summaryrefslogtreecommitdiff
path: root/test/net/fixtures/dhparams.pem
diff options
context:
space:
mode:
authorNobuyoshi Nakada <nobu@ruby-lang.org>2019-06-30 09:30:21 +0900
committerNobuyoshi Nakada <nobu@ruby-lang.org>2019-06-30 11:41:10 +0900
commit41012f2e2b71fddc9acf8a50d887707c44ad8f88 (patch)
tree08c7de279b3f11ce1e6e6da731721050060f319c /test/net/fixtures/dhparams.pem
parent78a8888c3eb6377218e8d3ec94a162c2c20eef82 (diff)
Add parentheses to suppress warnings
Diffstat (limited to 'test/net/fixtures/dhparams.pem')
0 files changed, 0 insertions, 0 deletions
rs/action.yml82
-rwxr-xr-x.github/actions/compilers/entrypoint.sh30
-rw-r--r--.github/actions/launchable/setup/action.yml96
-rw-r--r--.github/actions/make-snapshot/action.yml77
-rw-r--r--.github/actions/setup/baseruby/action.yml73
-rw-r--r--.github/actions/setup/directories/action.yml44
-rw-r--r--.github/actions/setup/macos/action.yml2
-rw-r--r--.github/actions/setup/ubuntu/action.yml35
-rw-r--r--.github/actions/slack/action.yml16
-rw-r--r--.github/auto_request_review.yml15
-rw-r--r--.github/codeql/codeql-config.yml22
-rw-r--r--.github/dependabot.yml29
-rw-r--r--.github/labeler.yml1
-rw-r--r--.github/workflows/annocheck.yml7
-rw-r--r--.github/workflows/auto_request_review.yml2
-rw-r--r--.github/workflows/auto_review_pr.yml41
-rw-r--r--.github/workflows/baseruby.yml8
-rw-r--r--.github/workflows/bundled_gems.yml100
-rw-r--r--.github/workflows/check_dependencies.yml8
-rw-r--r--.github/workflows/check_misc.yml93
-rw-r--r--.github/workflows/check_sast.yml133
-rw-r--r--.github/workflows/codeql-analysis.yml121
-rw-r--r--.github/workflows/compilers.yml268
-rw-r--r--.github/workflows/crosscompile.yml123
-rw-r--r--.github/workflows/cygwin.yml18
-rw-r--r--.github/workflows/default_gems.yml96
-rw-r--r--.github/workflows/default_gems_list.yml99
-rw-r--r--.github/workflows/dependabot_automerge.yml4
-rw-r--r--.github/workflows/labeler.yml5
-rw-r--r--.github/workflows/macos.yml51
-rw-r--r--.github/workflows/mingw.yml59
-rw-r--r--.github/workflows/modgc.yml25
-rw-r--r--.github/workflows/parse_y.yml7
-rw-r--r--.github/workflows/post_push.yml97
-rw-r--r--.github/workflows/pr-playground.yml6
-rw-r--r--.github/workflows/publish.yml110
-rw-r--r--.github/workflows/release.yml106
-rw-r--r--.github/workflows/rust-warnings.yml19
-rw-r--r--.github/workflows/scorecards.yml8
-rw-r--r--.github/workflows/spec_guards.yml11
-rw-r--r--.github/workflows/sync_default_gems.yml80
-rw-r--r--.github/workflows/tarball-macos.yml101
-rw-r--r--.github/workflows/tarball-non-development.yml87
-rw-r--r--.github/workflows/tarball-test-schedule.yml26
-rw-r--r--.github/workflows/tarball-test.yml104
-rw-r--r--.github/workflows/tarball-ubuntu.yml151
-rw-r--r--.github/workflows/tarball-windows.yml163
-rw-r--r--.github/workflows/ubuntu.yml172
-rw-r--r--.github/workflows/wasm.yml74
-rw-r--r--.github/workflows/windows.yml85
-rw-r--r--.github/workflows/wsl.yml7
-rw-r--r--.github/workflows/yjit-macos.yml35
-rw-r--r--.github/workflows/yjit-ubuntu.yml53
-rw-r--r--.github/workflows/zjit-macos.yml191
-rw-r--r--.github/workflows/zjit-ubuntu.yml216
-rw-r--r--.github/zizmor.yml33
-rw-r--r--.gitignore15
-rw-r--r--.rdoc_options16
-rw-r--r--COPYING2
-rw-r--r--COPYING.ja2
-rw-r--r--Cargo.lock729
-rw-r--r--Cargo.toml27
-rw-r--r--LEGAL266
-rw-r--r--NEWS.md438
-rw-r--r--README.EXT1
-rw-r--r--README.EXT.ja1
-rw-r--r--README.ja.md2
-rw-r--r--README.md2
-rw-r--r--addr2line.c5
-rw-r--r--array.c359
-rw-r--r--array.rb53
-rw-r--r--ast.c33
-rw-r--r--benchmark/dir_pwd.yml2
-rw-r--r--benchmark/file_basename.yml6
-rw-r--r--benchmark/file_dirname.yml6
-rw-r--r--benchmark/file_expand_path.yml4
-rw-r--r--benchmark/file_extname.yml6
-rw-r--r--benchmark/file_join.yml7
-rw-r--r--benchmark/float_predicate.yml12
-rw-r--r--benchmark/int_to_s.yml25
-rw-r--r--benchmark/integer_predicate.yml9
-rw-r--r--benchmark/object_class.yml40
-rw-r--r--benchmark/pathname.yml15
-rw-r--r--benchmark/set.yml4
-rw-r--r--benchmark/string_codepoints.yml9
-rw-r--r--benchmark/string_coderange_scan.yml10
-rw-r--r--benchmark/string_concat.yml4
-rw-r--r--benchmark/string_gsub.yml11
-rw-r--r--benchmark/string_inspect.yml13
-rw-r--r--benchmark/string_memsearch.yml75
-rw-r--r--benchmark/string_scrub.yml48
-rw-r--r--benchmark/time_now.yml1
-rw-r--r--benchmark/vm_ivar_get.yml67
-rw-r--r--benchmark/vm_ivar_set_on_instance.yml63
-rw-r--r--benchmark/vm_regexp.yml6
-rw-r--r--bignum.c178
-rwxr-xr-xbootstraptest/runner.rb33
-rw-r--r--bootstraptest/test_flow.rb4
-rw-r--r--bootstraptest/test_insns.rb7
-rw-r--r--bootstraptest/test_io.rb2
-rw-r--r--bootstraptest/test_method.rb13
-rw-r--r--bootstraptest/test_ractor.rb596
-rw-r--r--bootstraptest/test_syntax.rb8
-rw-r--r--bootstraptest/test_yjit.rb188
-rw-r--r--box.c1299
-rw-r--r--builtin.c84
-rw-r--r--builtin.h2
-rw-r--r--class.c856
-rw-r--r--common.mk261
-rw-r--r--compar.c60
-rw-r--r--compile.c728
-rw-r--r--complex.c309
-rw-r--r--concurrent_set.c292
-rw-r--r--configure.ac289
-rw-r--r--cont.c612
-rw-r--r--coroutine/ppc64le/Context.S7
-rw-r--r--cygwin/GNUmakefile.in11
-rw-r--r--darray.h23
-rw-r--r--debug.c33
-rw-r--r--debug_counter.h5
-rw-r--r--defs/gmake.mk139
-rw-r--r--defs/id.def3
-rw-r--r--defs/jit.mk61
-rw-r--r--defs/opt_insn_unif.def8
-rw-r--r--depend3262
-rw-r--r--dir.c278
-rw-r--r--dir.rb18
-rw-r--r--dln.c29
-rw-r--r--doc/.document16
-rw-r--r--doc/NEWS/NEWS-4.0.0.md802
-rw-r--r--doc/_regexp.rdoc93
-rw-r--r--doc/_timezones.rdoc2
-rw-r--r--doc/character_selectors.rdoc97
-rw-r--r--doc/command_injection.rdoc37
-rw-r--r--doc/command_line/environment.md174
-rw-r--r--doc/contributing/bug_triaging.rdoc (renamed from doc/bug_triaging.rdoc)0
-rw-r--r--doc/contributing/building_ruby.md8
-rw-r--r--doc/contributing/concurrency_guide.md154
-rw-r--r--doc/contributing/documentation_guide.md128
-rw-r--r--doc/contributing/dtrace_probes.rdoc (renamed from doc/dtrace_probes.rdoc)0
-rw-r--r--doc/contributing/glossary.md11
-rw-r--r--doc/contributing/making_changes_to_stdlibs.md2
-rw-r--r--doc/contributing/memory_view.md (renamed from doc/memory_view.md)0
-rw-r--r--doc/contributing/vm_stack_and_frames.md163
-rw-r--r--doc/csv/arguments/io.rdoc5
-rw-r--r--doc/csv/options/common/col_sep.rdoc57
-rw-r--r--doc/csv/options/common/quote_char.rdoc42
-rw-r--r--doc/csv/options/common/row_sep.rdoc91
-rw-r--r--doc/csv/options/generating/force_quotes.rdoc17
-rw-r--r--doc/csv/options/generating/quote_empty.rdoc12
-rw-r--r--doc/csv/options/generating/write_converters.rdoc25
-rw-r--r--doc/csv/options/generating/write_empty_value.rdoc15
-rw-r--r--doc/csv/options/generating/write_headers.rdoc29
-rw-r--r--doc/csv/options/generating/write_nil_value.rdoc14
-rw-r--r--doc/csv/options/parsing/converters.rdoc46
-rw-r--r--doc/csv/options/parsing/empty_value.rdoc13
-rw-r--r--doc/csv/options/parsing/field_size_limit.rdoc39
-rw-r--r--doc/csv/options/parsing/header_converters.rdoc43
-rw-r--r--doc/csv/options/parsing/headers.rdoc63
-rw-r--r--doc/csv/options/parsing/liberal_parsing.rdoc38
-rw-r--r--doc/csv/options/parsing/nil_value.rdoc12
-rw-r--r--doc/csv/options/parsing/return_headers.rdoc22
-rw-r--r--doc/csv/options/parsing/skip_blanks.rdoc31
-rw-r--r--doc/csv/options/parsing/skip_lines.rdoc37
-rw-r--r--doc/csv/options/parsing/strip.rdoc15
-rw-r--r--doc/csv/options/parsing/unconverted_fields.rdoc27
-rw-r--r--doc/csv/recipes/filtering.rdoc158
-rw-r--r--doc/csv/recipes/generating.rdoc246
-rw-r--r--doc/csv/recipes/parsing.rdoc545
-rw-r--r--doc/csv/recipes/recipes.rdoc6
-rw-r--r--doc/date/calendars.rdoc62
-rw-r--r--doc/distribution.md48
-rw-r--r--doc/distribution/distribution.md48
-rw-r--r--doc/distribution/windows.md304
-rw-r--r--doc/encodings.rdoc482
-rw-r--r--doc/examples/files.rdoc8
-rw-r--r--doc/exceptions.md521
-rw-r--r--doc/extension.ja.rdoc6
-rw-r--r--doc/extension.rdoc135
-rw-r--r--doc/file/filename_globbing.md299
-rw-r--r--doc/file/filename_matching.md353
-rw-r--r--doc/file/timestamps.md83
-rw-r--r--doc/float.rb128
-rw-r--r--doc/format_specifications.rdoc350
-rw-r--r--doc/forwardable.rd.ja80
-rw-r--r--doc/globals.md572
-rw-r--r--doc/jit/yjit.md547
-rw-r--r--doc/jit/zjit.md461
-rw-r--r--doc/language/box.md357
-rw-r--r--doc/language/bsearch.rdoc (renamed from doc/bsearch.rdoc)0
-rw-r--r--doc/language/calendars.rdoc62
-rw-r--r--doc/language/case_mapping.rdoc (renamed from doc/case_mapping.rdoc)0
-rw-r--r--doc/language/character_selectors.rdoc100
-rw-r--r--doc/language/dig_methods.rdoc (renamed from doc/dig_methods.rdoc)0
-rw-r--r--doc/language/encodings.rdoc482
-rw-r--r--doc/language/exceptions.md521
-rw-r--r--doc/language/fiber.md (renamed from doc/fiber.md)0
-rw-r--r--doc/language/format_specifications.rdoc354
-rw-r--r--doc/language/globals.md611
-rw-r--r--doc/language/hash_inclusion.rdoc (renamed from doc/hash_inclusion.rdoc)0
-rw-r--r--doc/language/implicit_conversion.rdoc (renamed from doc/implicit_conversion.rdoc)0
-rw-r--r--doc/language/marshal.rdoc (renamed from doc/marshal.rdoc)0
-rw-r--r--doc/language/option_dump.md265
-rw-r--r--doc/language/options.md744
-rw-r--r--doc/language/packed_data.md886
-rw-r--r--doc/language/ractor.md797
-rw-r--r--doc/language/regexp/methods.rdoc (renamed from doc/regexp/methods.rdoc)0
-rw-r--r--doc/language/regexp/unicode_properties.rdoc718
-rw-r--r--doc/language/signals.rdoc106
-rw-r--r--doc/language/strftime_formatting.rdoc525
-rw-r--r--doc/maintainers.md205
-rw-r--r--doc/matchdata/begin.rdoc12
-rw-r--r--doc/matchdata/bytebegin.rdoc12
-rw-r--r--doc/matchdata/byteend.rdoc12
-rw-r--r--doc/matchdata/end.rdoc12
-rw-r--r--doc/matchdata/offset.rdoc12
-rw-r--r--doc/namespace.md418
-rw-r--r--doc/packed_data.rdoc706
-rw-r--r--doc/ractor.md772
-rw-r--r--doc/regexp/unicode_properties.rdoc705
-rw-r--r--doc/reline/face.md111
-rw-r--r--doc/ruby/option_dump.md265
-rw-r--r--doc/ruby/options.md695
-rw-r--r--doc/security/command_injection.rdoc15
-rw-r--r--doc/security/security.rdoc (renamed from doc/security.rdoc)0
-rw-r--r--doc/signals.rdoc106
-rw-r--r--doc/standard_library.md10
-rw-r--r--doc/strftime_formatting.rdoc527
-rw-r--r--doc/string.rb158
-rw-r--r--doc/string/aref.rdoc96
-rw-r--r--doc/string/aset.rdoc179
-rw-r--r--doc/string/bytes.rdoc5
-rw-r--r--doc/string/bytesize.rdoc3
-rw-r--r--doc/string/bytesplice.rdoc5
-rw-r--r--doc/string/capitalize.rdoc26
-rw-r--r--doc/string/center.rdoc1
-rw-r--r--doc/string/chars.rdoc3
-rw-r--r--doc/string/chomp.rdoc1
-rw-r--r--doc/string/chop.rdoc2
-rw-r--r--doc/string/chr.rdoc1
-rw-r--r--doc/string/codepoints.rdoc3
-rw-r--r--doc/string/concat.rdoc1
-rw-r--r--doc/string/count.rdoc4
-rw-r--r--doc/string/delete.rdoc4
-rw-r--r--doc/string/delete_prefix.rdoc1
-rw-r--r--doc/string/delete_suffix.rdoc1
-rw-r--r--doc/string/downcase.rdoc20
-rw-r--r--doc/string/dump.rdoc129
-rw-r--r--doc/string/each_byte.rdoc3
-rw-r--r--doc/string/each_char.rdoc5
-rw-r--r--doc/string/each_codepoint.rdoc5
-rw-r--r--doc/string/each_grapheme_cluster.rdoc6
-rw-r--r--doc/string/end_with_p.rdoc1
-rw-r--r--doc/string/getbyte.rdoc5
-rw-r--r--doc/string/grapheme_clusters.rdoc2
-rw-r--r--doc/string/index.rdoc6
-rw-r--r--doc/string/insert.rdoc1
-rw-r--r--doc/string/inspect.rdoc38
-rw-r--r--doc/string/intern.rdoc8
-rw-r--r--doc/string/length.rdoc7
-rw-r--r--doc/string/ljust.rdoc15
-rw-r--r--doc/string/ord.rdoc3
-rw-r--r--doc/string/partition.rdoc51
-rw-r--r--doc/string/rindex.rdoc51
-rw-r--r--doc/string/rjust.rdoc9
-rw-r--r--doc/string/rpartition.rdoc55
-rw-r--r--doc/string/scan.rdoc35
-rw-r--r--doc/string/scrub.rdoc27
-rw-r--r--doc/string/split.rdoc132
-rw-r--r--doc/string/squeeze.rdoc33
-rw-r--r--doc/string/start_with_p.rdoc12
-rw-r--r--doc/string/sub.rdoc33
-rw-r--r--doc/string/succ.rdoc52
-rw-r--r--doc/string/sum.rdoc5
-rw-r--r--doc/string/swapcase.rdoc31
-rw-r--r--doc/string/unicode_normalize.rdoc28
-rw-r--r--doc/string/upcase.rdoc27
-rw-r--r--doc/string/upto.rdoc38
-rw-r--r--doc/string/valid_encoding_p.rdoc8
-rw-r--r--doc/stringio/each_byte.rdoc31
-rw-r--r--doc/stringio/each_char.rdoc31
-rw-r--r--doc/stringio/each_codepoint.rdoc33
-rw-r--r--doc/stringio/each_line.md189
-rw-r--r--doc/stringio/getbyte.rdoc24
-rw-r--r--doc/stringio/getc.rdoc30
-rw-r--r--doc/stringio/gets.rdoc99
-rw-r--r--doc/stringio/pread.rdoc65
-rw-r--r--doc/stringio/putc.rdoc82
-rw-r--r--doc/stringio/read.rdoc83
-rw-r--r--doc/stringio/size.rdoc4
-rw-r--r--doc/stringio/stringio.md702
-rw-r--r--doc/strscan/.document1
-rw-r--r--doc/strscan/link_refs.txt2
-rw-r--r--doc/strscan/methods/get_byte.md3
-rw-r--r--doc/strscan/methods/get_charpos.md3
-rw-r--r--doc/strscan/methods/get_pos.md3
-rw-r--r--doc/strscan/methods/getch.md3
-rw-r--r--doc/strscan/methods/scan.md3
-rw-r--r--doc/strscan/methods/scan_until.md3
-rw-r--r--doc/strscan/methods/set_pos.md4
-rw-r--r--doc/strscan/methods/skip.md3
-rw-r--r--doc/strscan/methods/skip_until.md9
-rw-r--r--doc/strscan/methods/terminate.md3
-rw-r--r--doc/strscan/strscan.md6
-rw-r--r--doc/syntax.rdoc3
-rw-r--r--doc/syntax/assignment.rdoc4
-rw-r--r--doc/syntax/calling_methods.rdoc7
-rw-r--r--doc/syntax/comments.rdoc2
-rw-r--r--doc/syntax/layout.rdoc118
-rw-r--r--doc/syntax/literals.rdoc11
-rw-r--r--doc/syntax/methods.rdoc1
-rw-r--r--doc/syntax/pattern_matching.rdoc2
-rw-r--r--doc/syntax/refinements.rdoc69
-rw-r--r--doc/windows.md303
-rw-r--r--doc/yarv_frame_layout.md77
-rw-r--r--doc/yarvarch.en7
-rw-r--r--doc/yarvarch.ja454
-rw-r--r--doc/yjit/yjit.md544
-rw-r--r--doc/zjit.md133
-rw-r--r--enc/Makefile.in5
-rw-r--r--enc/ascii.c4
-rw-r--r--enc/big5.c12
-rw-r--r--enc/cp949.c4
-rw-r--r--enc/depend6
-rw-r--r--enc/emacs_mule.c4
-rw-r--r--enc/euc_jp.c4
-rw-r--r--enc/euc_kr.c8
-rw-r--r--enc/euc_tw.c4
-rw-r--r--enc/gb18030.c4
-rw-r--r--enc/gbk.c4
-rw-r--r--enc/iso_8859_1.c6
-rw-r--r--enc/iso_8859_10.c6
-rw-r--r--enc/iso_8859_11.c4
-rw-r--r--enc/iso_8859_13.c6
-rw-r--r--enc/iso_8859_14.c6
-rw-r--r--enc/iso_8859_15.c6
-rw-r--r--enc/iso_8859_16.c6
-rw-r--r--enc/iso_8859_2.c6
-rw-r--r--enc/iso_8859_3.c6
-rw-r--r--enc/iso_8859_4.c6
-rw-r--r--enc/iso_8859_5.c6
-rw-r--r--enc/iso_8859_6.c4
-rw-r--r--enc/iso_8859_7.c6
-rw-r--r--enc/iso_8859_8.c4
-rw-r--r--enc/iso_8859_9.c6
-rw-r--r--enc/koi8_r.c4
-rw-r--r--enc/koi8_u.c4
-rwxr-xr-xenc/make_encmake.rb9
-rw-r--r--enc/shift_jis.c4
-rw-r--r--enc/unicode.c10
-rw-r--r--enc/unicode/16.0.0/casefold.h7804
-rw-r--r--enc/unicode/16.0.0/name2ctype.h48543
-rw-r--r--enc/unicode/17.0.0/casefold.h8013
-rw-r--r--enc/unicode/17.0.0/name2ctype.h49725
-rw-r--r--enc/us_ascii.c4
-rw-r--r--enc/utf_16be.c4
-rw-r--r--enc/utf_16le.c4
-rw-r--r--enc/utf_32be.c4
-rw-r--r--enc/utf_32le.c4
-rw-r--r--enc/utf_8.c4
-rw-r--r--enc/windows_1250.c6
-rw-r--r--enc/windows_1251.c6
-rw-r--r--enc/windows_1252.c6
-rw-r--r--enc/windows_1253.c6
-rw-r--r--enc/windows_1254.c6
-rw-r--r--enc/windows_1257.c6
-rw-r--r--enc/windows_31j.c4
-rw-r--r--encoding.c200
-rw-r--r--enum.c55
-rw-r--r--enumerator.c363
-rw-r--r--error.c152
-rw-r--r--eval.c86
-rw-r--r--eval_intern.h39
-rw-r--r--eval_jump.c2
-rw-r--r--ext/-test-/asan/asan.c24
-rw-r--r--ext/-test-/asan/depend162
-rw-r--r--ext/-test-/asan/extconf.rb2
-rw-r--r--ext/-test-/bignum/depend12
-rw-r--r--ext/-test-/box/yay1/extconf.rb1
-rw-r--r--ext/-test-/box/yay1/yay1.c (renamed from ext/-test-/namespace/yay1/yay1.c)0
-rw-r--r--ext/-test-/box/yay1/yay1.def (renamed from ext/-test-/namespace/yay1/yay1.def)0
-rw-r--r--ext/-test-/box/yay1/yay1.h (renamed from ext/-test-/namespace/yay1/yay1.h)0
-rw-r--r--ext/-test-/box/yay2/extconf.rb1
-rw-r--r--ext/-test-/box/yay2/yay2.c (renamed from ext/-test-/namespace/yay2/yay2.c)0
-rw-r--r--ext/-test-/box/yay2/yay2.def (renamed from ext/-test-/namespace/yay2/yay2.def)0
-rw-r--r--ext/-test-/box/yay2/yay2.h (renamed from ext/-test-/namespace/yay2/yay2.h)0
-rw-r--r--ext/-test-/cxxanyargs/cxxanyargs.cpp26
-rw-r--r--ext/-test-/fatal/invalid.c6
-rw-r--r--ext/-test-/integer/depend3
-rw-r--r--ext/-test-/namespace/yay1/extconf.rb1
-rw-r--r--ext/-test-/namespace/yay2/extconf.rb1
-rw-r--r--ext/-test-/postponed_job/postponed_job.c80
-rw-r--r--ext/-test-/rational/depend3
-rw-r--r--ext/-test-/sanitizers/depend162
-rw-r--r--ext/-test-/sanitizers/extconf.rb2
-rw-r--r--ext/-test-/sanitizers/sanitizers.c36
-rw-r--r--ext/-test-/scheduler/extconf.rb2
-rw-r--r--ext/-test-/scheduler/scheduler.c92
-rw-r--r--ext/-test-/st/foreach/foreach.c12
-rw-r--r--ext/-test-/stack/depend1
-rw-r--r--ext/-test-/stack/stack.c4
-rw-r--r--ext/-test-/string/cstr.c3
-rw-r--r--ext/-test-/string/depend3
-rw-r--r--ext/-test-/string/fstring.c6
-rw-r--r--ext/-test-/time/leap_second.c15
-rw-r--r--ext/-test-/tracepoint/gc_hook.c26
-rw-r--r--ext/-test-/tracepoint/tracepoint.c10
-rw-r--r--ext/.document21
-rw-r--r--ext/Setup13
-rw-r--r--ext/Setup.atheos21
-rw-r--r--ext/Setup.nt22
-rw-r--r--ext/cgi/escape/escape.c2
-rw-r--r--ext/coverage/coverage.c295
-rw-r--r--ext/coverage/depend2
-rw-r--r--ext/coverage/lib/coverage.rb5
-rw-r--r--ext/date/date_core.c383
-rw-r--r--ext/date/date_strptime.c6
-rw-r--r--ext/date/lib/date.rb2
-rw-r--r--ext/digest/digest.c2
-rw-r--r--ext/digest/lib/digest/version.rb3
-rw-r--r--ext/digest/sha1/sha1.c6
-rw-r--r--ext/erb/escape/escape.c28
-rw-r--r--ext/etc/etc.c4
-rw-r--r--ext/etc/etc.gemspec2
-rwxr-xr-xext/extmk.rb19
-rw-r--r--ext/fcntl/fcntl.c48
-rw-r--r--ext/io/console/console.c96
-rw-r--r--ext/io/wait/extconf.rb19
-rw-r--r--ext/io/wait/io-wait.gemspec24
-rw-r--r--ext/io/wait/wait.c418
-rw-r--r--ext/json/fbuffer/fbuffer.h126
-rw-r--r--ext/json/generator/depend1
-rw-r--r--ext/json/generator/extconf.rb5
-rw-r--r--ext/json/generator/generator.c910
-rw-r--r--ext/json/json.h134
-rw-r--r--ext/json/lib/json.rb59
-rw-r--r--ext/json/lib/json/common.rb132
-rw-r--r--ext/json/lib/json/ext/generator/state.rb25
-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/depend2
-rw-r--r--ext/json/parser/extconf.rb8
-rw-r--r--ext/json/parser/parser.c1832
-rw-r--r--ext/json/simd/simd.h64
-rw-r--r--ext/json/vendor/fpconv.c25
-rw-r--r--ext/json/vendor/ryu.h819
-rw-r--r--ext/monitor/depend162
-rw-r--r--ext/monitor/extconf.rb2
-rw-r--r--ext/monitor/lib/monitor.rb289
-rw-r--r--ext/monitor/monitor.c255
-rw-r--r--ext/objspace/depend9
-rw-r--r--ext/objspace/object_tracing.c99
-rw-r--r--ext/objspace/objspace.c312
-rw-r--r--ext/objspace/objspace_dump.c73
-rw-r--r--ext/openssl/History.md178
-rw-r--r--ext/openssl/extconf.rb15
-rw-r--r--ext/openssl/lib/openssl.rb9
-rw-r--r--ext/openssl/lib/openssl/asn1.rb188
-rw-r--r--ext/openssl/lib/openssl/digest.rb26
-rw-r--r--ext/openssl/lib/openssl/pkey.rb84
-rw-r--r--ext/openssl/lib/openssl/ssl.rb49
-rw-r--r--ext/openssl/lib/openssl/version.rb3
-rw-r--r--ext/openssl/lib/openssl/x509.rb9
-rw-r--r--ext/openssl/openssl.gemspec2
-rw-r--r--ext/openssl/openssl_missing.h23
-rw-r--r--ext/openssl/ossl.c477
-rw-r--r--ext/openssl/ossl.h24
-rw-r--r--ext/openssl/ossl_asn1.c1045
-rw-r--r--ext/openssl/ossl_asn1.h16
-rw-r--r--ext/openssl/ossl_bio.c12
-rw-r--r--ext/openssl/ossl_bn.c569
-rw-r--r--ext/openssl/ossl_cipher.c418
-rw-r--r--ext/openssl/ossl_cipher.h11
-rw-r--r--ext/openssl/ossl_config.c7
-rw-r--r--ext/openssl/ossl_digest.c116
-rw-r--r--ext/openssl/ossl_digest.h10
-rw-r--r--ext/openssl/ossl_engine.c79
-rw-r--r--ext/openssl/ossl_hmac.c57
-rw-r--r--ext/openssl/ossl_kdf.c199
-rw-r--r--ext/openssl/ossl_ns_spki.c66
-rw-r--r--ext/openssl/ossl_ocsp.c328
-rw-r--r--ext/openssl/ossl_pkcs12.c46
-rw-r--r--ext/openssl/ossl_pkcs7.c184
-rw-r--r--ext/openssl/ossl_pkey.c185
-rw-r--r--ext/openssl/ossl_pkey.h197
-rw-r--r--ext/openssl/ossl_pkey_dh.c67
-rw-r--r--ext/openssl/ossl_pkey_dsa.c37
-rw-r--r--ext/openssl/ossl_pkey_ec.c269
-rw-r--r--ext/openssl/ossl_pkey_rsa.c120
-rw-r--r--ext/openssl/ossl_provider.c5
-rw-r--r--ext/openssl/ossl_rand.c19
-rw-r--r--ext/openssl/ossl_ssl.c511
-rw-r--r--ext/openssl/ossl_ssl.h16
-rw-r--r--ext/openssl/ossl_ssl_session.c189
-rw-r--r--ext/openssl/ossl_ts.c214
-rw-r--r--ext/openssl/ossl_x509.c7
-rw-r--r--ext/openssl/ossl_x509.h12
-rw-r--r--ext/openssl/ossl_x509attr.c95
-rw-r--r--ext/openssl/ossl_x509cert.c158
-rw-r--r--ext/openssl/ossl_x509crl.c141
-rw-r--r--ext/openssl/ossl_x509ext.c112
-rw-r--r--ext/openssl/ossl_x509name.c146
-rw-r--r--ext/openssl/ossl_x509req.c116
-rw-r--r--ext/openssl/ossl_x509revoked.c59
-rw-r--r--ext/openssl/ossl_x509store.c80
-rw-r--r--ext/psych/extconf.rb7
-rw-r--r--ext/psych/lib/psych.rb13
-rw-r--r--ext/psych/lib/psych/core_ext.rb6
-rw-r--r--ext/psych/lib/psych/nodes/node.rb4
-rw-r--r--ext/psych/lib/psych/scalar_scanner.rb5
-rw-r--r--ext/psych/lib/psych/versions.rb4
-rw-r--r--ext/psych/lib/psych/visitors/to_ruby.rb10
-rw-r--r--ext/psych/psych_parser.c17
-rw-r--r--ext/psych/psych_to_ruby.c14
-rw-r--r--ext/pty/extconf.rb2
-rw-r--r--ext/pty/pty.c29
-rw-r--r--ext/ripper/depend9
-rw-r--r--ext/ripper/lib/ripper/lexer.rb2
-rw-r--r--ext/socket/ancdata.c69
-rw-r--r--ext/socket/depend45
-rw-r--r--ext/socket/extconf.rb1
-rw-r--r--ext/socket/getaddrinfo.c7
-rw-r--r--ext/socket/getnameinfo.c18
-rw-r--r--ext/socket/init.c8
-rw-r--r--ext/socket/ipsocket.c105
-rw-r--r--ext/socket/lib/socket.rb73
-rw-r--r--ext/socket/raddrinfo.c83
-rw-r--r--ext/socket/rubysocket.h9
-rw-r--r--ext/socket/socket.c8
-rw-r--r--ext/socket/tcpsocket.c4
-rw-r--r--ext/socket/udpsocket.c6
-rw-r--r--ext/socket/unixsocket.c3
-rw-r--r--ext/stringio/stringio.c355
-rw-r--r--ext/strscan/extconf.rb4
-rw-r--r--ext/strscan/lib/strscan.rb20
-rw-r--r--ext/strscan/lib/strscan/strscan.rb44
-rw-r--r--ext/strscan/strscan.c355
-rw-r--r--ext/strscan/strscan.gemspec12
-rw-r--r--ext/win32/lib/win32/registry.rb925
-rw-r--r--ext/win32/lib/win32/resolv.rb135
-rw-r--r--ext/win32/resolv/extconf.rb1
-rw-r--r--ext/win32/resolv/resolv.c214
-rw-r--r--ext/win32/win32-registry.gemspec32
-rw-r--r--ext/zlib/zlib.c51
-rw-r--r--ext/zlib/zlib.gemspec2
-rw-r--r--file.c1076
-rw-r--r--gc.c1591
-rw-r--r--gc.rb50
-rw-r--r--gc/default/default.c1568
-rw-r--r--gc/gc.h60
-rw-r--r--gc/gc_impl.h15
-rw-r--r--gc/mmtk/Cargo.lock13
-rw-r--r--gc/mmtk/Cargo.toml4
-rw-r--r--gc/mmtk/cbindgen.toml5
-rw-r--r--gc/mmtk/extconf.rb4
-rw-r--r--gc/mmtk/mmtk.c554
-rw-r--r--gc/mmtk/mmtk.h37
-rw-r--r--gc/mmtk/src/abi.rs21
-rw-r--r--gc/mmtk/src/api.rs199
-rw-r--r--gc/mmtk/src/binding.rs8
-rw-r--r--gc/mmtk/src/collection.rs51
-rw-r--r--gc/mmtk/src/heap/cpu_heap_trigger.rs370
-rw-r--r--gc/mmtk/src/heap/mod.rs9
-rw-r--r--gc/mmtk/src/heap/ruby_heap_trigger.rs105
-rw-r--r--gc/mmtk/src/lib.rs21
-rw-r--r--gc/mmtk/src/object_model.rs51
-rw-r--r--gc/mmtk/src/pinning_registry.rs187
-rw-r--r--gc/mmtk/src/scanning.rs43
-rw-r--r--gc/mmtk/src/utils.rs7
-rw-r--r--gc/mmtk/src/weak_proc.rs224
-rw-r--r--gc/wbcheck/extconf.rb3
-rw-r--r--gc/wbcheck/wbcheck.c1936
-rw-r--r--gem_prelude.rb1
-rw-r--r--gems/bundled_gems44
-rw-r--r--hash.c268
-rw-r--r--hash.rb2
-rw-r--r--id_table.c91
-rw-r--r--id_table.h19
-rw-r--r--imemo.c325
-rw-r--r--include/ruby/atomic.h44
-rw-r--r--include/ruby/backward.h6
-rw-r--r--include/ruby/backward/cxxanyargs.hpp29
-rw-r--r--include/ruby/debug.h55
-rw-r--r--include/ruby/fiber/scheduler.h22
-rw-r--r--include/ruby/internal/arithmetic/intptr_t.h12
-rw-r--r--include/ruby/internal/attr/deprecated.h9
-rw-r--r--include/ruby/internal/attr/forceinline.h2
-rw-r--r--include/ruby/internal/attr/format.h4
-rw-r--r--include/ruby/internal/attr/noexcept.h2
-rw-r--r--include/ruby/internal/attr/nonstring.h2
-rw-r--r--include/ruby/internal/attr/restrict.h2
-rw-r--r--include/ruby/internal/compiler_is/msvc.h13
-rw-r--r--include/ruby/internal/config.h2
-rw-r--r--include/ruby/internal/core/rarray.h2
-rw-r--r--include/ruby/internal/core/rbasic.h3
-rw-r--r--include/ruby/internal/core/rdata.h300
-rw-r--r--include/ruby/internal/core/rmatch.h55
-rw-r--r--include/ruby/internal/core/robject.h25
-rw-r--r--include/ruby/internal/core/rstring.h57
-rw-r--r--include/ruby/internal/core/rstruct.h12
-rw-r--r--include/ruby/internal/core/rtypeddata.h298
-rw-r--r--include/ruby/internal/ctype.h4
-rw-r--r--include/ruby/internal/encoding/string.h29
-rw-r--r--include/ruby/internal/error.h7
-rw-r--r--include/ruby/internal/eval.h15
-rw-r--r--include/ruby/internal/fl_type.h189
-rw-r--r--include/ruby/internal/gc.h165
-rw-r--r--include/ruby/internal/globals.h3
-rw-r--r--include/ruby/internal/intern/bignum.h45
-rw-r--r--include/ruby/internal/intern/complex.h4
-rw-r--r--include/ruby/internal/intern/cont.h9
-rw-r--r--include/ruby/internal/intern/enumerator.h12
-rw-r--r--include/ruby/internal/intern/file.h16
-rw-r--r--include/ruby/internal/intern/object.h3
-rw-r--r--include/ruby/internal/intern/proc.h12
-rw-r--r--include/ruby/internal/intern/select.h2
-rw-r--r--include/ruby/internal/intern/string.h21
-rw-r--r--include/ruby/internal/intern/variable.h1
-rw-r--r--include/ruby/internal/intern/vm.h7
-rw-r--r--include/ruby/internal/iterator.h45
-rw-r--r--include/ruby/internal/memory.h76
-rw-r--r--include/ruby/internal/newobj.h38
-rw-r--r--include/ruby/internal/scan_args.h6
-rw-r--r--include/ruby/internal/static_assert.h2
-rw-r--r--include/ruby/internal/symbol.h43
-rw-r--r--include/ruby/internal/value_type.h22
-rw-r--r--include/ruby/internal/warning_push.h2
-rw-r--r--include/ruby/internal/xmalloc.h151
-rw-r--r--include/ruby/onigmo.h14
-rw-r--r--include/ruby/ractor.h16
-rw-r--r--include/ruby/random.h3
-rw-r--r--include/ruby/st.h5
-rw-r--r--include/ruby/version.h4
-rw-r--r--include/ruby/win32.h57
-rw-r--r--inits.c3
-rw-r--r--insns.def167
-rw-r--r--internal/array.h3
-rw-r--r--internal/basic_operators.h1
-rw-r--r--internal/bignum.h41
-rw-r--r--internal/bits.h31
-rw-r--r--internal/box.h96
-rw-r--r--internal/class.h310
-rw-r--r--internal/compar.h1
-rw-r--r--internal/cont.h1
-rw-r--r--internal/error.h12
-rw-r--r--internal/eval.h2
-rw-r--r--internal/file.h2
-rw-r--r--internal/gc.h94
-rw-r--r--internal/hash.h18
-rw-r--r--internal/imemo.h141
-rw-r--r--internal/inits.h7
-rw-r--r--internal/io.h3
-rw-r--r--internal/load.h2
-rw-r--r--internal/namespace.h86
-rw-r--r--internal/numeric.h54
-rw-r--r--internal/object.h11
-rw-r--r--internal/range.h6
-rw-r--r--internal/rational.h23
-rw-r--r--internal/re.h48
-rw-r--r--internal/set_table.h6
-rw-r--r--internal/st.h11
-rw-r--r--internal/string.h36
-rw-r--r--internal/struct.h38
-rw-r--r--internal/thread.h6
-rw-r--r--internal/time.h7
-rw-r--r--internal/variable.h15
-rw-r--r--internal/vm.h8
-rw-r--r--io.c461
-rw-r--r--io_buffer.c363
-rw-r--r--iseq.c512
-rw-r--r--iseq.h21
-rw-r--r--jit.c394
-rw-r--r--jit/Cargo.toml6
-rw-r--r--jit/src/lib.rs38
-rw-r--r--jit_hook.rb9
-rw-r--r--kernel.rb3
-rw-r--r--lib/English.gemspec2
-rw-r--r--lib/English.rb50
-rw-r--r--lib/bundled_gems.rb68
-rw-r--r--lib/bundler.rb47
-rw-r--r--lib/bundler/bundler.gemspec6
-rw-r--r--lib/bundler/capistrano.rb20
-rw-r--r--lib/bundler/cli.rb229
-rw-r--r--lib/bundler/cli/add.rb17
-rw-r--r--lib/bundler/cli/cache.rb12
-rw-r--r--lib/bundler/cli/common.rb29
-rw-r--r--lib/bundler/cli/config.rb14
-rw-r--r--lib/bundler/cli/console.rb5
-rw-r--r--lib/bundler/cli/exec.rb33
-rw-r--r--lib/bundler/cli/gem.rb77
-rw-r--r--lib/bundler/cli/inject.rb60
-rw-r--r--lib/bundler/cli/install.rb98
-rw-r--r--lib/bundler/cli/issue.rb4
-rw-r--r--lib/bundler/cli/lock.rb10
-rw-r--r--lib/bundler/cli/outdated.rb44
-rw-r--r--lib/bundler/cli/plugin.rb6
-rw-r--r--lib/bundler/cli/pristine.rb6
-rw-r--r--lib/bundler/cli/show.rb2
-rw-r--r--lib/bundler/cli/update.rb8
-rw-r--r--lib/bundler/cli/viz.rb31
-rw-r--r--lib/bundler/compact_index_client.rb1
-rw-r--r--lib/bundler/compact_index_client/parser.rb5
-rw-r--r--lib/bundler/current_ruby.rb18
-rw-r--r--lib/bundler/definition.rb298
-rw-r--r--lib/bundler/deployment.rb65
-rw-r--r--lib/bundler/digest.rb2
-rw-r--r--lib/bundler/dsl.rb132
-rw-r--r--lib/bundler/endpoint_specification.rb12
-rw-r--r--lib/bundler/env.rb25
-rw-r--r--lib/bundler/environment_preserver.rb1
-rw-r--r--lib/bundler/errors.rb45
-rw-r--r--lib/bundler/feature_flag.rb33
-rw-r--r--lib/bundler/fetcher/compact_index.rb2
-rw-r--r--lib/bundler/fetcher/dependency.rb8
-rw-r--r--lib/bundler/fetcher/downloader.rb1
-rw-r--r--lib/bundler/fetcher/gem_remote_fetcher.rb6
-rw-r--r--lib/bundler/friendly_errors.rb4
-rw-r--r--lib/bundler/graph.rb152
-rw-r--r--lib/bundler/index.rb7
-rw-r--r--lib/bundler/injector.rb9
-rw-r--r--lib/bundler/inline.rb58
-rw-r--r--lib/bundler/installer.rb26
-rw-r--r--lib/bundler/installer/gem_installer.rb25
-rw-r--r--lib/bundler/installer/parallel_installer.rb110
-rw-r--r--lib/bundler/lazy_specification.rb65
-rw-r--r--lib/bundler/lockfile_generator.rb19
-rw-r--r--lib/bundler/lockfile_parser.rb42
-rw-r--r--lib/bundler/man/bundle-add.114
-rw-r--r--lib/bundler/man/bundle-add.1.ronn14
-rw-r--r--lib/bundler/man/bundle-binstubs.19
-rw-r--r--lib/bundler/man/bundle-binstubs.1.ronn10
-rw-r--r--lib/bundler/man/bundle-cache.116
-rw-r--r--lib/bundler/man/bundle-cache.1.ronn15
-rw-r--r--lib/bundler/man/bundle-check.17
-rw-r--r--lib/bundler/man/bundle-check.1.ronn5
-rw-r--r--lib/bundler/man/bundle-clean.12
-rw-r--r--lib/bundler/man/bundle-config.1323
-rw-r--r--lib/bundler/man/bundle-config.1.ronn144
-rw-r--r--lib/bundler/man/bundle-console.12
-rw-r--r--lib/bundler/man/bundle-doctor.12
-rw-r--r--lib/bundler/man/bundle-env.12
-rw-r--r--lib/bundler/man/bundle-exec.17
-rw-r--r--lib/bundler/man/bundle-exec.1.ronn6
-rw-r--r--lib/bundler/man/bundle-fund.12
-rw-r--r--lib/bundler/man/bundle-gem.19
-rw-r--r--lib/bundler/man/bundle-gem.1.ronn7
-rw-r--r--lib/bundler/man/bundle-help.12
-rw-r--r--lib/bundler/man/bundle-info.12
-rw-r--r--lib/bundler/man/bundle-init.12
-rw-r--r--lib/bundler/man/bundle-inject.131
-rw-r--r--lib/bundler/man/bundle-inject.1.ronn32
-rw-r--r--lib/bundler/man/bundle-install.172
-rw-r--r--lib/bundler/man/bundle-install.1.ronn134
-rw-r--r--lib/bundler/man/bundle-issue.12
-rw-r--r--lib/bundler/man/bundle-licenses.12
-rw-r--r--lib/bundler/man/bundle-list.12
-rw-r--r--lib/bundler/man/bundle-lock.12
-rw-r--r--lib/bundler/man/bundle-open.12
-rw-r--r--lib/bundler/man/bundle-outdated.131
-rw-r--r--lib/bundler/man/bundle-outdated.1.ronn31
-rw-r--r--lib/bundler/man/bundle-platform.12
-rw-r--r--lib/bundler/man/bundle-plugin.111
-rw-r--r--lib/bundler/man/bundle-plugin.1.ronn8
-rw-r--r--lib/bundler/man/bundle-pristine.12
-rw-r--r--lib/bundler/man/bundle-remove.110
-rw-r--r--lib/bundler/man/bundle-remove.1.ronn9
-rw-r--r--lib/bundler/man/bundle-show.17
-rw-r--r--lib/bundler/man/bundle-show.1.ronn4
-rw-r--r--lib/bundler/man/bundle-update.17
-rw-r--r--lib/bundler/man/bundle-update.1.ronn8
-rw-r--r--lib/bundler/man/bundle-version.12
-rw-r--r--lib/bundler/man/bundle-viz.130
-rw-r--r--lib/bundler/man/bundle-viz.1.ronn36
-rw-r--r--lib/bundler/man/bundle.111
-rw-r--r--lib/bundler/man/bundle.1.ronn9
-rw-r--r--lib/bundler/man/gemfile.577
-rw-r--r--lib/bundler/man/gemfile.5.ronn81
-rw-r--r--lib/bundler/man/index.txt2
-rw-r--r--lib/bundler/match_metadata.rb20
-rw-r--r--lib/bundler/match_remote_metadata.rb27
-rw-r--r--lib/bundler/materialization.rb2
-rw-r--r--lib/bundler/override.rb69
-rw-r--r--lib/bundler/plugin.rb11
-rw-r--r--lib/bundler/plugin/api/source.rb8
-rw-r--r--lib/bundler/plugin/events.rb68
-rw-r--r--lib/bundler/plugin/index.rb52
-rw-r--r--lib/bundler/plugin/installer.rb13
-rw-r--r--lib/bundler/plugin/source_list.rb2
-rw-r--r--lib/bundler/remote_specification.rb2
-rw-r--r--lib/bundler/resolver.rb127
-rw-r--r--lib/bundler/resolver/base.rb3
-rw-r--r--lib/bundler/resolver/strategy.rb9
-rw-r--r--lib/bundler/retry.rb34
-rw-r--r--lib/bundler/ruby_dsl.rb29
-rw-r--r--lib/bundler/ruby_version.rb6
-rw-r--r--lib/bundler/rubygems_ext.rb22
-rw-r--r--lib/bundler/rubygems_gem_installer.rb38
-rw-r--r--lib/bundler/rubygems_integration.rb8
-rw-r--r--lib/bundler/runtime.rb15
-rw-r--r--lib/bundler/self_manager.rb3
-rw-r--r--lib/bundler/settings.rb44
-rw-r--r--lib/bundler/settings/validator.rb7
-rw-r--r--lib/bundler/shared_helpers.rb35
-rw-r--r--lib/bundler/similarity_detector.rb63
-rw-r--r--lib/bundler/source.rb4
-rw-r--r--lib/bundler/source/gemspec.rb4
-rw-r--r--lib/bundler/source/git.rb14
-rw-r--r--lib/bundler/source/git/git_proxy.rb87
-rw-r--r--lib/bundler/source/metadata.rb4
-rw-r--r--lib/bundler/source/path.rb11
-rw-r--r--lib/bundler/source/path/installer.rb2
-rw-r--r--lib/bundler/source/rubygems.rb170
-rw-r--r--lib/bundler/source/rubygems/remote.rb14
-rw-r--r--lib/bundler/source/rubygems_aggregate.rb5
-rw-r--r--lib/bundler/source_list.rb57
-rw-r--r--lib/bundler/source_map.rb15
-rw-r--r--lib/bundler/spec_set.rb41
-rw-r--r--lib/bundler/stub_specification.rb1
-rw-r--r--lib/bundler/templates/newgem/CODE_OF_CONDUCT.md.tt136
-rw-r--r--lib/bundler/templates/newgem/Cargo.toml.tt6
-rw-r--r--lib/bundler/templates/newgem/Gemfile.tt8
-rw-r--r--lib/bundler/templates/newgem/Rakefile.tt5
-rw-r--r--lib/bundler/templates/newgem/circleci/config.yml.tt12
-rw-r--r--lib/bundler/templates/newgem/ext/newgem/Cargo.toml.tt9
-rw-r--r--lib/bundler/templates/newgem/ext/newgem/build.rs.tt5
-rw-r--r--lib/bundler/templates/newgem/ext/newgem/extconf-go.rb.tt11
-rw-r--r--lib/bundler/templates/newgem/ext/newgem/go.mod.tt5
-rw-r--r--lib/bundler/templates/newgem/ext/newgem/newgem-go.c.tt2
-rw-r--r--lib/bundler/templates/newgem/ext/newgem/newgem.go.tt31
-rw-r--r--lib/bundler/templates/newgem/ext/newgem/src/lib.rs.tt15
-rw-r--r--lib/bundler/templates/newgem/github/workflows/build-gems.yml.tt69
-rw-r--r--lib/bundler/templates/newgem/github/workflows/main.yml.tt11
-rw-r--r--lib/bundler/templates/newgem/gitlab-ci.yml.tt9
-rw-r--r--lib/bundler/templates/newgem/lib/newgem.rb.tt2
-rw-r--r--lib/bundler/templates/newgem/newgem.gemspec.tt21
-rw-r--r--lib/bundler/templates/newgem/spec/newgem_spec.rb.tt8
-rw-r--r--lib/bundler/templates/newgem/test/minitest/test_newgem.rb.tt6
-rw-r--r--lib/bundler/ui/shell.rb16
-rw-r--r--lib/bundler/vendor/connection_pool/lib/connection_pool.rb59
-rw-r--r--lib/bundler/vendor/connection_pool/lib/connection_pool/timed_stack.rb65
-rw-r--r--lib/bundler/vendor/connection_pool/lib/connection_pool/version.rb2
-rw-r--r--lib/bundler/vendor/fileutils/lib/fileutils.rb109
-rw-r--r--lib/bundler/vendor/net-http-persistent/lib/net/http/persistent.rb7
-rw-r--r--lib/bundler/vendor/thor/lib/thor.rb2
-rw-r--r--lib/bundler/vendor/thor/lib/thor/runner.rb2
-rw-r--r--lib/bundler/vendor/uri/lib/uri/common.rb72
-rw-r--r--lib/bundler/vendor/uri/lib/uri/file.rb2
-rw-r--r--lib/bundler/vendor/uri/lib/uri/generic.rb55
-rw-r--r--lib/bundler/vendor/uri/lib/uri/http.rb12
-rw-r--r--lib/bundler/vendor/uri/lib/uri/rfc2396_parser.rb17
-rw-r--r--lib/bundler/vendor/uri/lib/uri/version.rb4
-rw-r--r--lib/bundler/version.rb2
-rw-r--r--lib/bundler/vlad.rb15
-rw-r--r--lib/bundler/worker.rb14
-rw-r--r--lib/cgi.rb6
-rw-r--r--lib/cgi/escape.rb28
-rw-r--r--lib/cgi/util.rb2
-rw-r--r--lib/delegate.rb67
-rw-r--r--lib/did_you_mean.rb4
-rw-r--r--lib/erb.rb1273
-rw-r--r--lib/erb/compiler.rb3
-rw-r--r--lib/erb/erb.gemspec5
-rw-r--r--lib/erb/util.rb31
-rw-r--r--lib/erb/version.rb3
-rw-r--r--lib/error_highlight/base.rb198
-rw-r--r--lib/error_highlight/core_ext.rb35
-rw-r--r--lib/error_highlight/error_highlight.gemspec2
-rw-r--r--lib/error_highlight/formatter.rb4
-rw-r--r--lib/error_highlight/version.rb2
-rw-r--r--lib/fileutils.rb2
-rw-r--r--lib/find.rb83
-rw-r--r--lib/forwardable.rb51
-rw-r--r--lib/forwardable/forwardable.gemspec2
-rw-r--r--lib/forwardable/impl.rb17
-rw-r--r--lib/ipaddr.gemspec2
-rw-r--r--lib/ipaddr.rb46
-rw-r--r--lib/mkmf.rb42
-rw-r--r--lib/monitor.rb216
-rw-r--r--lib/net/http.rb95
-rw-r--r--lib/net/http/exceptions.rb3
-rw-r--r--lib/net/http/generic_request.rb11
-rw-r--r--lib/net/http/header.rb12
-rw-r--r--lib/net/http/net-http.gemspec9
-rw-r--r--lib/net/http/requests.rb64
-rw-r--r--lib/net/http/response.rb3
-rw-r--r--lib/net/http/responses.rb68
-rw-r--r--lib/net/net-protocol.gemspec5
-rw-r--r--lib/net/protocol.rb15
-rw-r--r--lib/open-uri.rb25
-rw-r--r--lib/open3/version.rb1
-rw-r--r--lib/optparse.rb74
-rw-r--r--lib/optparse/optparse.gemspec2
-rw-r--r--lib/pathname.rb105
-rw-r--r--lib/pp.rb70
-rw-r--r--lib/prettyprint.rb19
-rw-r--r--lib/prism.rb92
-rw-r--r--lib/prism/desugar_compiler.rb139
-rw-r--r--lib/prism/ffi.rb175
-rw-r--r--lib/prism/lex_compat.rb468
-rw-r--r--lib/prism/node_ext.rb345
-rw-r--r--lib/prism/node_find.rb185
-rw-r--r--lib/prism/pack.rb230
-rw-r--r--lib/prism/parse_result.rb514
-rw-r--r--lib/prism/parse_result/comments.rb43
-rw-r--r--lib/prism/parse_result/errors.rb8
-rw-r--r--lib/prism/parse_result/newlines.rb59
-rw-r--r--lib/prism/pattern.rb83
-rw-r--r--lib/prism/polyfill/scan_byte.rb2
-rw-r--r--lib/prism/polyfill/warn.rb38
-rw-r--r--lib/prism/prism.gemspec188
-rw-r--r--lib/prism/relocation.rb186
-rw-r--r--lib/prism/string_query.rb17
-rw-r--r--lib/prism/translation.rb10
-rw-r--r--lib/prism/translation/parser.rb17
-rw-r--r--lib/prism/translation/parser/builder.rb12
-rw-r--r--lib/prism/translation/parser/compiler.rb69
-rw-r--r--lib/prism/translation/parser/lexer.rb13
-rw-r--r--lib/prism/translation/parser33.rb13
-rw-r--r--lib/prism/translation/parser34.rb13
-rw-r--r--lib/prism/translation/parser35.rb13
-rw-r--r--lib/prism/translation/parser_current.rb10
-rw-r--r--lib/prism/translation/parser_versions.rb36
-rw-r--r--lib/prism/translation/ripper.rb1238
-rw-r--r--lib/prism/translation/ripper/filter.rb53
-rw-r--r--lib/prism/translation/ripper/lexer.rb133
-rw-r--r--lib/prism/translation/ripper/sexp.rb12
-rw-r--r--lib/prism/translation/ripper/shim.rb2
-rw-r--r--lib/prism/translation/ruby_parser.rb381
-rw-r--r--lib/resolv.gemspec5
-rw-r--r--lib/resolv.rb145
-rw-r--r--lib/rubygems.rb91
-rw-r--r--lib/rubygems/basic_specification.rb9
-rw-r--r--lib/rubygems/bundler_version_finder.rb80
-rw-r--r--lib/rubygems/command_manager.rb1
-rw-r--r--lib/rubygems/commands/build_command.rb7
-rw-r--r--lib/rubygems/commands/cert_command.rb2
-rw-r--r--lib/rubygems/commands/environment_command.rb1
-rw-r--r--lib/rubygems/commands/exec_command.rb3
-rw-r--r--lib/rubygems/commands/fetch_command.rb2
-rw-r--r--lib/rubygems/commands/help_command.rb4
-rw-r--r--lib/rubygems/commands/install_command.rb11
-rw-r--r--lib/rubygems/commands/owner_command.rb5
-rw-r--r--lib/rubygems/commands/pristine_command.rb9
-rw-r--r--lib/rubygems/commands/push_command.rb86
-rw-r--r--lib/rubygems/commands/query_command.rb43
-rw-r--r--lib/rubygems/commands/rebuild_command.rb1
-rw-r--r--lib/rubygems/commands/setup_command.rb10
-rw-r--r--lib/rubygems/commands/sources_command.rb167
-rw-r--r--lib/rubygems/commands/specification_command.rb8
-rw-r--r--lib/rubygems/commands/uninstall_command.rb2
-rw-r--r--lib/rubygems/config_file.rb52
-rw-r--r--lib/rubygems/defaults.rb11
-rw-r--r--lib/rubygems/dependency_installer.rb83
-rw-r--r--lib/rubygems/dependency_list.rb1
-rw-r--r--lib/rubygems/deprecate.rb138
-rw-r--r--lib/rubygems/doctor.rb2
-rw-r--r--lib/rubygems/exceptions.rb70
-rw-r--r--lib/rubygems/ext/builder.rb29
-rw-r--r--lib/rubygems/ext/cargo_builder.rb11
-rw-r--r--lib/rubygems/ext/cmake_builder.rb105
-rw-r--r--lib/rubygems/ext/configure_builder.rb4
-rw-r--r--lib/rubygems/ext/ext_conf_builder.rb4
-rw-r--r--lib/rubygems/ext/rake_builder.rb2
-rw-r--r--lib/rubygems/gem_runner.rb1
-rw-r--r--lib/rubygems/gemcutter_utilities.rb7
-rw-r--r--lib/rubygems/install_default_message.rb13
-rw-r--r--lib/rubygems/install_update_options.rb24
-rw-r--r--lib/rubygems/installer.rb124
-rw-r--r--lib/rubygems/name_tuple.rb6
-rw-r--r--lib/rubygems/package.rb93
-rw-r--r--lib/rubygems/package/tar_header.rb8
-rw-r--r--lib/rubygems/package/tar_reader.rb2
-rw-r--r--lib/rubygems/platform.rb42
-rw-r--r--lib/rubygems/psych_tree.rb2
-rw-r--r--lib/rubygems/remote_fetcher.rb27
-rw-r--r--lib/rubygems/request.rb1
-rw-r--r--lib/rubygems/request/connection_pools.rb7
-rw-r--r--lib/rubygems/request/http_pool.rb15
-rw-r--r--lib/rubygems/request_set.rb71
-rw-r--r--lib/rubygems/request_set/lockfile.rb4
-rw-r--r--lib/rubygems/request_set/lockfile/parser.rb344
-rw-r--r--lib/rubygems/request_set/lockfile/tokenizer.rb122
-rw-r--r--lib/rubygems/resolver.rb528
-rw-r--r--lib/rubygems/resolver/api_set.rb10
-rw-r--r--lib/rubygems/resolver/api_set/gem_parser.rb2
-rw-r--r--lib/rubygems/resolver/api_specification.rb6
-rw-r--r--lib/rubygems/resolver/conflict.rb146
-rw-r--r--lib/rubygems/resolver/incompatibility.rb10
-rw-r--r--lib/rubygems/resolver/installer_set.rb2
-rw-r--r--lib/rubygems/resolver/stats.rb46
-rw-r--r--lib/rubygems/resolver/strategy.rb44
-rw-r--r--lib/rubygems/safe_marshal.rb1
-rw-r--r--lib/rubygems/safe_yaml.rb16
-rw-r--r--lib/rubygems/security/policy.rb2
-rw-r--r--lib/rubygems/security/signer.rb2
-rw-r--r--lib/rubygems/source.rb4
-rw-r--r--lib/rubygems/source/local.rb6
-rw-r--r--lib/rubygems/source_list.rb36
-rw-r--r--lib/rubygems/specification.rb166
-rw-r--r--lib/rubygems/specification_policy.rb83
-rw-r--r--lib/rubygems/specification_record.rb15
-rw-r--r--lib/rubygems/stub_specification.rb1
-rw-r--r--lib/rubygems/text.rb11
-rw-r--r--lib/rubygems/uninstaller.rb23
-rw-r--r--lib/rubygems/user_interaction.rb3
-rw-r--r--lib/rubygems/util.rb22
-rw-r--r--lib/rubygems/util/atomic_file_writer.rb76
-rw-r--r--lib/rubygems/util/licenses.rb33
-rw-r--r--lib/rubygems/util/list.rb40
-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/lib/net/http.rb109
-rw-r--r--lib/rubygems/vendor/net-http/lib/net/http/exceptions.rb3
-rw-r--r--lib/rubygems/vendor/net-http/lib/net/http/generic_request.rb45
-rw-r--r--lib/rubygems/vendor/net-http/lib/net/http/header.rb12
-rw-r--r--lib/rubygems/vendor/net-http/lib/net/http/requests.rb16
-rw-r--r--lib/rubygems/vendor/net-http/lib/net/http/response.rb3
-rw-r--r--lib/rubygems/vendor/net-http/lib/net/http/responses.rb72
-rw-r--r--lib/rubygems/vendor/optparse/lib/optparse.rb123
-rw-r--r--lib/rubygems/vendor/pub_grub/lib/pub_grub.rb53
-rw-r--r--lib/rubygems/vendor/pub_grub/lib/pub_grub/assignment.rb20
-rw-r--r--lib/rubygems/vendor/pub_grub/lib/pub_grub/basic_package_source.rb169
-rw-r--r--lib/rubygems/vendor/pub_grub/lib/pub_grub/failure_writer.rb182
-rw-r--r--lib/rubygems/vendor/pub_grub/lib/pub_grub/incompatibility.rb150
-rw-r--r--lib/rubygems/vendor/pub_grub/lib/pub_grub/package.rb43
-rw-r--r--lib/rubygems/vendor/pub_grub/lib/pub_grub/partial_solution.rb121
-rw-r--r--lib/rubygems/vendor/pub_grub/lib/pub_grub/rubygems.rb45
-rw-r--r--lib/rubygems/vendor/pub_grub/lib/pub_grub/solve_failure.rb19
-rw-r--r--lib/rubygems/vendor/pub_grub/lib/pub_grub/static_package_source.rb61
-rw-r--r--lib/rubygems/vendor/pub_grub/lib/pub_grub/strategy.rb42
-rw-r--r--lib/rubygems/vendor/pub_grub/lib/pub_grub/term.rb105
-rw-r--r--lib/rubygems/vendor/pub_grub/lib/pub_grub/version.rb3
-rw-r--r--lib/rubygems/vendor/pub_grub/lib/pub_grub/version_constraint.rb129
-rw-r--r--lib/rubygems/vendor/pub_grub/lib/pub_grub/version_range.rb423
-rw-r--r--lib/rubygems/vendor/pub_grub/lib/pub_grub/version_solver.rb236
-rw-r--r--lib/rubygems/vendor/pub_grub/lib/pub_grub/version_union.rb178
-rw-r--r--lib/rubygems/vendor/resolv/lib/resolv.rb46
-rw-r--r--lib/rubygems/vendor/timeout/lib/timeout.rb5
-rw-r--r--lib/rubygems/vendor/uri/lib/uri/common.rb72
-rw-r--r--lib/rubygems/vendor/uri/lib/uri/file.rb2
-rw-r--r--lib/rubygems/vendor/uri/lib/uri/generic.rb55
-rw-r--r--lib/rubygems/vendor/uri/lib/uri/http.rb12
-rw-r--r--lib/rubygems/vendor/uri/lib/uri/rfc2396_parser.rb17
-rw-r--r--lib/rubygems/vendor/uri/lib/uri/version.rb4
-rw-r--r--lib/rubygems/vendored_molinillo.rb3
-rw-r--r--lib/rubygems/vendored_pub_grub.rb3
-rw-r--r--lib/rubygems/version.rb355
-rw-r--r--lib/rubygems/win_platform.rb30
-rw-r--r--lib/rubygems/yaml_serializer.rb889
-rw-r--r--lib/set/subclass_compatible.rb347
-rw-r--r--lib/singleton.rb11
-rw-r--r--lib/syntax_suggest/api.rb47
-rw-r--r--lib/syntax_suggest/clean_document.rb105
-rw-r--r--lib/syntax_suggest/code_line.rb134
-rw-r--r--lib/syntax_suggest/core_ext.rb127
-rw-r--r--lib/syntax_suggest/explain_syntax.rb18
-rw-r--r--lib/syntax_suggest/left_right_lex_count.rb168
-rw-r--r--lib/syntax_suggest/left_right_token_count.rb162
-rw-r--r--lib/syntax_suggest/lex_all.rb74
-rw-r--r--lib/syntax_suggest/lex_value.rb70
-rw-r--r--lib/syntax_suggest/ripper_errors.rb39
-rw-r--r--lib/syntax_suggest/syntax_suggest.gemspec2
-rw-r--r--lib/syntax_suggest/token.rb49
-rw-r--r--lib/syntax_suggest/version.rb2
-rw-r--r--lib/syntax_suggest/visitor.rb80
-rw-r--r--lib/tempfile.rb6
-rw-r--r--lib/time.gemspec1
-rw-r--r--lib/time.rb15
-rw-r--r--lib/timeout.rb267
-rw-r--r--lib/tsort.gemspec35
-rw-r--r--lib/tsort.rb457
-rw-r--r--lib/unicode_normalize/normalize.rb31
-rw-r--r--lib/unicode_normalize/tables.rb49
-rw-r--r--lib/uri/common.rb15
-rw-r--r--lib/uri/generic.rb33
-rw-r--r--lib/uri/mailto.rb6
-rw-r--r--lib/uri/version.rb4
-rw-r--r--lib/weakref.rb1
-rw-r--r--lib/yaml.rb1
-rwxr-xr-xlibexec/erb50
-rw-r--r--load.c602
-rw-r--r--man/erb.14
-rw-r--r--man/goruby.14
-rw-r--r--man/ruby.123
-rw-r--r--marshal.c109
-rw-r--r--math.c2
-rw-r--r--memory_view.c5
-rw-r--r--method.h21
-rw-r--r--mini_builtin.c31
-rw-r--r--misc/.vscode/settings.json4
-rwxr-xr-xmisc/jit_perf.py116
-rw-r--r--misc/lldb_rb/utils.py24
-rwxr-xr-xmisc/yjit_perf.py116
-rw-r--r--missing/dtoa.c211
-rw-r--r--namespace.c1129
-rw-r--r--node_dump.c5
-rw-r--r--numeric.c708
-rw-r--r--numeric.rb17
-rw-r--r--object.c482
-rw-r--r--pack.c134
-rw-r--r--pack.rb24
-rw-r--r--parse.y1090
-rw-r--r--parser_bits.h133
-rw-r--r--parser_st.c6
-rw-r--r--parser_st.h5
-rw-r--r--pathname.c1711
-rw-r--r--pathname_builtin.rb1799
-rw-r--r--prelude.rb16
-rw-r--r--prism/api_pack.c276
-rw-r--r--prism/arena.c117
-rw-r--r--prism/arena.h37
-rw-r--r--prism/buffer.c374
-rw-r--r--prism/buffer.h52
-rw-r--r--prism/char.c274
-rw-r--r--prism/comments.h43
-rw-r--r--prism/compiler/accel.h19
-rw-r--r--prism/compiler/align.h36
-rw-r--r--prism/compiler/exported.h24
-rw-r--r--prism/compiler/fallthrough.h22
-rw-r--r--prism/compiler/filesystem.h32
-rw-r--r--prism/compiler/flex_array.h19
-rw-r--r--prism/compiler/force_inline.h21
-rw-r--r--prism/compiler/format.h25
-rw-r--r--prism/compiler/inline.h17
-rw-r--r--prism/compiler/nodiscard.h22
-rw-r--r--prism/compiler/nonnull.h18
-rw-r--r--prism/compiler/unused.h18
-rw-r--r--prism/config.yml505
-rw-r--r--prism/constant_pool.c360
-rw-r--r--prism/constant_pool.h81
-rw-r--r--prism/defines.h260
-rw-r--r--prism/diagnostic.h93
-rw-r--r--prism/encoding.c248
-rw-r--r--prism/encoding.h283
-rw-r--r--prism/excludes.h29
-rw-r--r--prism/extension.c756
-rw-r--r--prism/extension.h4
-rw-r--r--prism/generate-srcs.mk.rb17
-rw-r--r--prism/integer.c681
-rw-r--r--prism/integer.h41
-rw-r--r--prism/internal/allocator.h68
-rw-r--r--prism/internal/allocator_debug.h88
-rw-r--r--prism/internal/arena.h108
-rw-r--r--prism/internal/bit.h42
-rw-r--r--prism/internal/buffer.h91
-rw-r--r--prism/internal/char.h139
-rw-r--r--prism/internal/comments.h20
-rw-r--r--prism/internal/constant_pool.h117
-rw-r--r--prism/internal/encoding.h242
-rw-r--r--prism/internal/integer.h68
-rw-r--r--prism/internal/isinf.h16
-rw-r--r--prism/internal/line_offset_list.h34
-rw-r--r--prism/internal/list.h62
-rw-r--r--prism/internal/magic_comments.h23
-rw-r--r--prism/internal/memchr.h15
-rw-r--r--prism/internal/node.h32
-rw-r--r--prism/internal/options.h212
-rw-r--r--prism/internal/parser.h958
-rw-r--r--prism/internal/regexp.h41
-rw-r--r--prism/internal/serialize.h34
-rw-r--r--prism/internal/source.h72
-rw-r--r--prism/internal/static_literals.h98
-rw-r--r--prism/internal/stringy.h30
-rw-r--r--prism/internal/strncasecmp.h18
-rw-r--r--prism/internal/strpbrk.h33
-rw-r--r--prism/internal/tokens.h11
-rw-r--r--prism/json.h32
-rw-r--r--prism/line_offset_list.c100
-rw-r--r--prism/line_offset_list.h61
-rw-r--r--prism/list.c24
-rw-r--r--prism/magic_comments.h35
-rw-r--r--prism/memchr.c37
-rw-r--r--prism/node.h71
-rw-r--r--prism/options.c204
-rw-r--r--prism/options.h361
-rw-r--r--prism/pack.c509
-rw-r--r--prism/pack.h163
-rw-r--r--prism/parser.c302
-rw-r--r--prism/parser.h1155
-rw-r--r--prism/prettyprint.h15
-rw-r--r--prism/prism.c12973
-rw-r--r--prism/prism.h358
-rw-r--r--prism/regexp.c1015
-rw-r--r--prism/regexp.h43
-rw-r--r--prism/serialize.h96
-rw-r--r--prism/source.c491
-rw-r--r--prism/source.h148
-rw-r--r--prism/srcs.mk70
-rw-r--r--prism/srcs.mk.in18
-rw-r--r--prism/static_literals.c70
-rw-r--r--prism/static_literals.h121
-rw-r--r--prism/stream.h28
-rw-r--r--prism/string_query.c166
-rw-r--r--prism/string_query.h63
-rw-r--r--prism/stringy.c91
-rw-r--r--prism/stringy.h72
-rw-r--r--prism/strncasecmp.c37
-rw-r--r--prism/strpbrk.c439
-rw-r--r--prism/templates/ext/prism/api_node.c.erb92
-rw-r--r--prism/templates/include/prism/ast.h.erb116
-rw-r--r--prism/templates/include/prism/diagnostic.h.erb130
-rw-r--r--prism/templates/include/prism/internal/diagnostic.h.erb60
-rw-r--r--prism/templates/lib/prism/compiler.rb.erb23
-rw-r--r--prism/templates/lib/prism/dispatcher.rb.erb38
-rw-r--r--prism/templates/lib/prism/dot_visitor.rb.erb48
-rw-r--r--prism/templates/lib/prism/dsl.rb.erb47
-rw-r--r--prism/templates/lib/prism/inspect_visitor.rb.erb36
-rw-r--r--prism/templates/lib/prism/mutation_compiler.rb.erb7
-rw-r--r--prism/templates/lib/prism/node.rb.erb413
-rw-r--r--prism/templates/lib/prism/reflection.rb.erb13
-rw-r--r--prism/templates/lib/prism/serialize.rb.erb298
-rw-r--r--prism/templates/lib/prism/visitor.rb.erb22
-rw-r--r--prism/templates/src/diagnostic.c.erb151
-rw-r--r--prism/templates/src/json.c.erb130
-rw-r--r--prism/templates/src/node.c.erb281
-rw-r--r--prism/templates/src/prettyprint.c.erb37
-rw-r--r--prism/templates/src/serialize.c.erb222
-rw-r--r--prism/templates/src/token_type.c.erb369
-rw-r--r--prism/templates/src/tokens.c.erb367
-rwxr-xr-xprism/templates/template.rb206
-rw-r--r--prism/util/pm_buffer.c357
-rw-r--r--prism/util/pm_buffer.h228
-rw-r--r--prism/util/pm_char.c318
-rw-r--r--prism/util/pm_char.h204
-rw-r--r--prism/util/pm_constant_pool.c342
-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.c383
-rw-r--r--prism/util/pm_string.h190
-rw-r--r--prism/util/pm_strncasecmp.c36
-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.h13
-rw-r--r--prism_compile.c1837
-rw-r--r--prism_compile.h115
-rw-r--r--prism_xallocator.h6
-rw-r--r--proc.c553
-rw-r--r--process.c31
-rw-r--r--ractor.c528
-rw-r--r--ractor.rb269
-rw-r--r--ractor_core.h40
-rw-r--r--ractor_sync.c66
-rw-r--r--random.c164
-rw-r--r--range.c60
-rw-r--r--rational.c219
-rw-r--r--re.c659
-rw-r--r--regcomp.c285
-rw-r--r--regenc.c19
-rw-r--r--regenc.h4
-rw-r--r--regerror.c20
-rw-r--r--regexec.c456
-rw-r--r--regint.h22
-rw-r--r--regparse.c15
-rw-r--r--regparse.h2
-rw-r--r--ruby.c193
-rw-r--r--ruby.rs (renamed from jit.rs)0
-rw-r--r--ruby_atomic.h47
-rw-r--r--ruby_parser.c2
-rw-r--r--rubyparser.h26
-rw-r--r--sample/openssl/c_rehash.rb2
-rw-r--r--sample/uumerge.rb2
-rw-r--r--scheduler.c156
-rw-r--r--set.c316
-rw-r--r--shape.c656
-rw-r--r--shape.h457
-rw-r--r--signal.c80
-rwxr-xr-xspec/bin/rspec1
-rw-r--r--spec/bundled_gems_spec.rb49
-rw-r--r--spec/bundler/bundler/bundler_spec.rb6
-rw-r--r--spec/bundler/bundler/cli_common_spec.rb22
-rw-r--r--spec/bundler/bundler/cli_spec.rb43
-rw-r--r--spec/bundler/bundler/compact_index_client/parser_spec.rb16
-rw-r--r--spec/bundler/bundler/current_ruby_spec.rb35
-rw-r--r--spec/bundler/bundler/definition_spec.rb81
-rw-r--r--spec/bundler/bundler/dsl_spec.rb211
-rw-r--r--spec/bundler/bundler/endpoint_specification_spec.rb40
-rw-r--r--spec/bundler/bundler/env_spec.rb19
-rw-r--r--spec/bundler/bundler/errors_spec.rb91
-rw-r--r--spec/bundler/bundler/fetcher/dependency_spec.rb14
-rw-r--r--spec/bundler/bundler/fetcher/downloader_spec.rb32
-rw-r--r--spec/bundler/bundler/fetcher/gem_remote_fetcher_spec.rb60
-rw-r--r--spec/bundler/bundler/friendly_errors_spec.rb8
-rw-r--r--spec/bundler/bundler/gem_helper_spec.rb11
-rw-r--r--spec/bundler/bundler/installer/parallel_installer_spec.rb79
-rw-r--r--spec/bundler/bundler/installer/spec_installation_spec.rb79
-rw-r--r--spec/bundler/bundler/lockfile_parser_spec.rb210
-rw-r--r--spec/bundler/bundler/override_spec.rb175
-rw-r--r--spec/bundler/bundler/plugin/events_spec.rb12
-rw-r--r--spec/bundler/bundler/plugin/index_spec.rb79
-rw-r--r--spec/bundler/bundler/plugin/installer_spec.rb7
-rw-r--r--spec/bundler/bundler/plugin_spec.rb24
-rw-r--r--spec/bundler/bundler/resolver/cooldown_spec.rb148
-rw-r--r--spec/bundler/bundler/retry_spec.rb111
-rw-r--r--spec/bundler/bundler/ruby_dsl_spec.rb37
-rw-r--r--spec/bundler/bundler/ruby_version_spec.rb22
-rw-r--r--spec/bundler/bundler/rubygems_ext_spec.rb39
-rw-r--r--spec/bundler/bundler/settings_spec.rb34
-rw-r--r--spec/bundler/bundler/shared_helpers_spec.rb32
-rw-r--r--spec/bundler/bundler/source/git/git_proxy_spec.rb57
-rw-r--r--spec/bundler/bundler/source/rubygems/remote_spec.rb35
-rw-r--r--spec/bundler/bundler/source/rubygems_spec.rb57
-rw-r--r--spec/bundler/bundler/source_list_spec.rb42
-rw-r--r--spec/bundler/bundler/spec_set_spec.rb89
-rw-r--r--spec/bundler/bundler/stub_specification_spec.rb8
-rw-r--r--spec/bundler/bundler/ui/shell_spec.rb28
-rw-r--r--spec/bundler/bundler/uri_normalizer_spec.rb25
-rw-r--r--spec/bundler/bundler/worker_spec.rb20
-rw-r--r--spec/bundler/cache/cache_path_spec.rb2
-rw-r--r--spec/bundler/cache/gems_spec.rb20
-rw-r--r--spec/bundler/cache/git_spec.rb61
-rw-r--r--spec/bundler/cache/path_spec.rb54
-rw-r--r--spec/bundler/commands/add_spec.rb112
-rw-r--r--spec/bundler/commands/binstubs_spec.rb34
-rw-r--r--spec/bundler/commands/cache_spec.rb187
-rw-r--r--spec/bundler/commands/check_spec.rb75
-rw-r--r--spec/bundler/commands/clean_spec.rb192
-rw-r--r--spec/bundler/commands/config_spec.rb62
-rw-r--r--spec/bundler/commands/console_spec.rb6
-rw-r--r--spec/bundler/commands/doctor_spec.rb4
-rw-r--r--spec/bundler/commands/exec_spec.rb116
-rw-r--r--spec/bundler/commands/fund_spec.rb2
-rw-r--r--spec/bundler/commands/info_spec.rb4
-rw-r--r--spec/bundler/commands/init_spec.rb2
-rw-r--r--spec/bundler/commands/inject_spec.rb113
-rw-r--r--spec/bundler/commands/install_spec.rb398
-rw-r--r--spec/bundler/commands/licenses_spec.rb2
-rw-r--r--spec/bundler/commands/lock_spec.rb337
-rw-r--r--spec/bundler/commands/newgem_spec.rb459
-rw-r--r--spec/bundler/commands/open_spec.rb8
-rw-r--r--spec/bundler/commands/outdated_spec.rb140
-rw-r--r--spec/bundler/commands/platform_spec.rb112
-rw-r--r--spec/bundler/commands/post_bundle_message_spec.rb67
-rw-r--r--spec/bundler/commands/pristine_spec.rb66
-rw-r--r--spec/bundler/commands/remove_spec.rb15
-rw-r--r--spec/bundler/commands/show_spec.rb29
-rw-r--r--spec/bundler/commands/ssl_spec.rb9
-rw-r--r--spec/bundler/commands/update_spec.rb144
-rw-r--r--spec/bundler/commands/version_spec.rb28
-rw-r--r--spec/bundler/commands/viz_spec.rb144
-rw-r--r--spec/bundler/install/allow_offline_install_spec.rb8
-rw-r--r--spec/bundler/install/binstubs_spec.rb2
-rw-r--r--spec/bundler/install/bundler_spec.rb10
-rw-r--r--spec/bundler/install/cooldown_spec.rb433
-rw-r--r--spec/bundler/install/deploy_spec.rb133
-rw-r--r--spec/bundler/install/failure_spec.rb34
-rw-r--r--spec/bundler/install/gemfile/eval_gemfile_spec.rb2
-rw-r--r--spec/bundler/install/gemfile/force_ruby_platform_spec.rb2
-rw-r--r--spec/bundler/install/gemfile/gemspec_spec.rb33
-rw-r--r--spec/bundler/install/gemfile/git_spec.rb30
-rw-r--r--spec/bundler/install/gemfile/groups_spec.rb106
-rw-r--r--spec/bundler/install/gemfile/install_if_spec.rb2
-rw-r--r--spec/bundler/install/gemfile/lockfile_spec.rb2
-rw-r--r--spec/bundler/install/gemfile/override_spec.rb401
-rw-r--r--spec/bundler/install/gemfile/path_spec.rb80
-rw-r--r--spec/bundler/install/gemfile/platform_spec.rb26
-rw-r--r--spec/bundler/install/gemfile/ruby_spec.rb4
-rw-r--r--spec/bundler/install/gemfile/sources_spec.rb1155
-rw-r--r--spec/bundler/install/gemfile/specific_platform_spec.rb201
-rw-r--r--spec/bundler/install/gemfile_spec.rb31
-rw-r--r--spec/bundler/install/gems/compact_index_spec.rb131
-rw-r--r--spec/bundler/install/gems/dependency_api_fallback_spec.rb2
-rw-r--r--spec/bundler/install/gems/dependency_api_spec.rb136
-rw-r--r--spec/bundler/install/gems/flex_spec.rb10
-rw-r--r--spec/bundler/install/gems/fund_spec.rb2
-rw-r--r--spec/bundler/install/gems/gemfile_source_header_spec.rb2
-rw-r--r--spec/bundler/install/gems/mirror_probe_spec.rb12
-rw-r--r--spec/bundler/install/gems/mirror_spec.rb4
-rw-r--r--spec/bundler/install/gems/native_extensions_spec.rb18
-rw-r--r--spec/bundler/install/gems/no_build_extension_spec.rb54
-rw-r--r--spec/bundler/install/gems/no_install_plugin_spec.rb53
-rw-r--r--spec/bundler/install/gems/post_install_spec.rb4
-rw-r--r--spec/bundler/install/gems/resolving_spec.rb22
-rw-r--r--spec/bundler/install/gems/standalone_spec.rb85
-rw-r--r--spec/bundler/install/gemspecs_spec.rb6
-rw-r--r--spec/bundler/install/git_spec.rb86
-rw-r--r--spec/bundler/install/global_cache_spec.rb19
-rw-r--r--spec/bundler/install/path_spec.rb58
-rw-r--r--spec/bundler/install/process_lock_spec.rb56
-rw-r--r--spec/bundler/install/yanked_spec.rb8
-rw-r--r--spec/bundler/lock/git_spec.rb43
-rw-r--r--spec/bundler/lock/lockfile_spec.rb206
-rw-r--r--spec/bundler/other/cli_dispatch_spec.rb2
-rw-r--r--spec/bundler/other/cli_man_pages_spec.rb18
-rw-r--r--spec/bundler/other/major_deprecation_spec.rb453
-rw-r--r--spec/bundler/plugins/command_spec.rb34
-rw-r--r--spec/bundler/plugins/hook_spec.rb123
-rw-r--r--spec/bundler/plugins/install_spec.rb48
-rw-r--r--spec/bundler/plugins/source/example_spec.rb16
-rw-r--r--spec/bundler/quality_es_spec.rb4
-rw-r--r--spec/bundler/quality_spec.rb14
-rw-r--r--spec/bundler/realworld/edgecases_spec.rb2
-rw-r--r--spec/bundler/realworld/fixtures/tapioca/Gemfile.lock4
-rw-r--r--spec/bundler/realworld/fixtures/warbler/Gemfile2
-rw-r--r--spec/bundler/realworld/fixtures/warbler/Gemfile.lock30
-rw-r--r--spec/bundler/runtime/env_helpers_spec.rb84
-rw-r--r--spec/bundler/runtime/executable_spec.rb40
-rw-r--r--spec/bundler/runtime/gem_tasks_spec.rb2
-rw-r--r--spec/bundler/runtime/inline_spec.rb58
-rw-r--r--spec/bundler/runtime/load_spec.rb2
-rw-r--r--spec/bundler/runtime/platform_spec.rb20
-rw-r--r--spec/bundler/runtime/self_management_spec.rb30
-rw-r--r--spec/bundler/runtime/setup_spec.rb97
-rw-r--r--spec/bundler/spec_helper.rb66
-rw-r--r--spec/bundler/support/artifice/compact_index_cooldown.rb6
-rw-r--r--spec/bundler/support/artifice/compact_index_etag_match.rb2
-rw-r--r--spec/bundler/support/artifice/helpers/compact_index.rb10
-rw-r--r--spec/bundler/support/artifice/helpers/compact_index_cooldown.rb13
-rw-r--r--spec/bundler/support/artifice/vcr.rb2
-rw-r--r--spec/bundler/support/builders.rb155
-rw-r--r--spec/bundler/support/checksums.rb21
-rw-r--r--spec/bundler/support/command_execution.rb2
-rw-r--r--spec/bundler/support/filters.rb6
-rw-r--r--spec/bundler/support/helpers.rb163
-rw-r--r--spec/bundler/support/matchers.rb2
-rw-r--r--spec/bundler/support/path.rb37
-rw-r--r--spec/bundler/support/rubygems_ext.rb55
-rw-r--r--spec/bundler/support/shards.rb200
-rw-r--r--spec/bundler/support/switch_rubygems.rb1
-rw-r--r--spec/bundler/support/the_bundle.rb8
-rw-r--r--spec/bundler/update/gemfile_spec.rb2
-rw-r--r--spec/bundler/update/git_spec.rb4
-rw-r--r--spec/default.mspec33
-rw-r--r--spec/mspec/Gemfile2
-rw-r--r--spec/mspec/Gemfile.lock4
-rw-r--r--spec/mspec/lib/mspec/commands/mspec-ci.rb1
-rw-r--r--spec/mspec/lib/mspec/commands/mspec-tag.rb1
-rw-r--r--spec/mspec/lib/mspec/matchers/base.rb18
-rw-r--r--spec/mspec/lib/mspec/matchers/be_an_instance_of.rb1
-rw-r--r--spec/mspec/lib/mspec/matchers/be_ancestor_of.rb1
-rw-r--r--spec/mspec/lib/mspec/matchers/be_empty.rb1
-rw-r--r--spec/mspec/lib/mspec/matchers/be_false.rb1
-rw-r--r--spec/mspec/lib/mspec/matchers/be_kind_of.rb1
-rw-r--r--spec/mspec/lib/mspec/matchers/be_nan.rb1
-rw-r--r--spec/mspec/lib/mspec/matchers/be_nil.rb1
-rw-r--r--spec/mspec/lib/mspec/matchers/be_true.rb1
-rw-r--r--spec/mspec/lib/mspec/matchers/eql.rb1
-rw-r--r--spec/mspec/lib/mspec/matchers/equal.rb1
-rw-r--r--spec/mspec/lib/mspec/matchers/have_class_variable.rb1
-rw-r--r--spec/mspec/lib/mspec/matchers/have_constant.rb1
-rw-r--r--spec/mspec/lib/mspec/matchers/have_instance_method.rb1
-rw-r--r--spec/mspec/lib/mspec/matchers/have_instance_variable.rb1
-rw-r--r--spec/mspec/lib/mspec/matchers/have_method.rb1
-rw-r--r--spec/mspec/lib/mspec/matchers/have_private_instance_method.rb1
-rw-r--r--spec/mspec/lib/mspec/matchers/have_private_method.rb1
-rw-r--r--spec/mspec/lib/mspec/matchers/have_protected_instance_method.rb1
-rw-r--r--spec/mspec/lib/mspec/matchers/have_public_instance_method.rb1
-rw-r--r--spec/mspec/lib/mspec/matchers/have_singleton_method.rb1
-rw-r--r--spec/mspec/lib/mspec/matchers/include.rb1
-rw-r--r--spec/mspec/lib/mspec/matchers/infinity.rb2
-rw-r--r--spec/mspec/lib/mspec/matchers/raise_error.rb64
-rw-r--r--spec/mspec/lib/mspec/matchers/respond_to.rb1
-rw-r--r--spec/mspec/lib/mspec/runner/formatters/base.rb2
-rw-r--r--spec/mspec/lib/mspec/runner/mspec.rb1
-rw-r--r--spec/mspec/lib/mspec/utils/name_map.rb13
-rw-r--r--spec/mspec/spec/commands/mspec_ci_spec.rb5
-rw-r--r--spec/mspec/spec/commands/mspec_run_spec.rb5
-rw-r--r--spec/mspec/spec/fixtures/should.rb4
-rw-r--r--spec/mspec/spec/matchers/raise_error_spec.rb77
-rw-r--r--spec/mspec/spec/spec_helper.rb5
-rw-r--r--spec/mspec/spec/utils/fixtures/this_file_raises.rb1
-rw-r--r--spec/mspec/spec/utils/fixtures/this_file_raises2.rb1
-rw-r--r--spec/mspec/spec/utils/name_map_spec.rb12
-rwxr-xr-xspec/mspec/tool/remove_old_guards.rb9
-rw-r--r--spec/mspec/tool/sync/sync-rubyspec.rb30
-rwxr-xr-xspec/mspec/tool/tag_from_output.rb2
-rw-r--r--spec/ruby/.rubocop.yml5
-rw-r--r--spec/ruby/.rubocop_todo.yml35
-rw-r--r--spec/ruby/CONTRIBUTING.md51
-rw-r--r--spec/ruby/README.md7
-rwxr-xr-xspec/ruby/bin/rubocop2
-rwxr-xr-xspec/ruby/command_line/dash_0_spec.rb2
-rw-r--r--spec/ruby/command_line/dash_r_spec.rb11
-rw-r--r--spec/ruby/command_line/dash_upper_i_spec.rb10
-rw-r--r--spec/ruby/command_line/dash_upper_s_spec.rb40
-rw-r--r--spec/ruby/command_line/dash_v_spec.rb2
-rw-r--r--spec/ruby/command_line/dash_x_spec.rb2
-rw-r--r--spec/ruby/command_line/error_message_spec.rb5
-rw-r--r--spec/ruby/command_line/feature_spec.rb10
-rw-r--r--spec/ruby/command_line/fixtures/bin/bad_embedded_ruby.txt2
-rw-r--r--spec/ruby/command_line/fixtures/bin/embedded_ruby.txt2
-rw-r--r--spec/ruby/command_line/frozen_strings_spec.rb36
-rw-r--r--spec/ruby/command_line/rubylib_spec.rb16
-rw-r--r--spec/ruby/command_line/rubyopt_spec.rb4
-rw-r--r--spec/ruby/command_line/syntax_error_spec.rb10
-rw-r--r--spec/ruby/core/argf/argf_spec.rb4
-rw-r--r--spec/ruby/core/argf/argv_spec.rb2
-rw-r--r--spec/ruby/core/argf/binmode_spec.rb2
-rw-r--r--spec/ruby/core/argf/close_spec.rb8
-rw-r--r--spec/ruby/core/argf/closed_spec.rb2
-rw-r--r--spec/ruby/core/argf/each_byte_spec.rb58
-rw-r--r--spec/ruby/core/argf/each_char_spec.rb58
-rw-r--r--spec/ruby/core/argf/each_codepoint_spec.rb58
-rw-r--r--spec/ruby/core/argf/each_line_spec.rb62
-rw-r--r--spec/ruby/core/argf/each_spec.rb5
-rw-r--r--spec/ruby/core/argf/eof_spec.rb28
-rw-r--r--spec/ruby/core/argf/filename_spec.rb28
-rw-r--r--spec/ruby/core/argf/fileno_spec.rb24
-rw-r--r--spec/ruby/core/argf/inspect_spec.rb7
-rw-r--r--spec/ruby/core/argf/path_spec.rb5
-rw-r--r--spec/ruby/core/argf/pos_spec.rb31
-rw-r--r--spec/ruby/core/argf/read_nonblock_spec.rb2
-rw-r--r--spec/ruby/core/argf/readchar_spec.rb2
-rw-r--r--spec/ruby/core/argf/readline_spec.rb2
-rw-r--r--spec/ruby/core/argf/readlines_spec.rb22
-rw-r--r--spec/ruby/core/argf/readpartial_spec.rb6
-rw-r--r--spec/ruby/core/argf/rewind_spec.rb2
-rw-r--r--spec/ruby/core/argf/seek_spec.rb2
-rw-r--r--spec/ruby/core/argf/shared/each_byte.rb58
-rw-r--r--spec/ruby/core/argf/shared/each_char.rb58
-rw-r--r--spec/ruby/core/argf/shared/each_codepoint.rb58
-rw-r--r--spec/ruby/core/argf/shared/each_line.rb62
-rw-r--r--spec/ruby/core/argf/shared/eof.rb24
-rw-r--r--spec/ruby/core/argf/shared/filename.rb28
-rw-r--r--spec/ruby/core/argf/shared/fileno.rb24
-rw-r--r--spec/ruby/core/argf/shared/pos.rb31
-rw-r--r--spec/ruby/core/argf/shared/readlines.rb22
-rw-r--r--spec/ruby/core/argf/skip_spec.rb2
-rw-r--r--spec/ruby/core/argf/tell_spec.rb5
-rw-r--r--spec/ruby/core/argf/to_a_spec.rb5
-rw-r--r--spec/ruby/core/argf/to_i_spec.rb5
-rw-r--r--spec/ruby/core/argf/to_io_spec.rb2
-rw-r--r--spec/ruby/core/array/allocate_spec.rb4
-rw-r--r--spec/ruby/core/array/append_spec.rb11
-rw-r--r--spec/ruby/core/array/assoc_spec.rb30
-rw-r--r--spec/ruby/core/array/at_spec.rb4
-rw-r--r--spec/ruby/core/array/bsearch_index_spec.rb28
-rw-r--r--spec/ruby/core/array/bsearch_spec.rb26
-rw-r--r--spec/ruby/core/array/clear_spec.rb8
-rw-r--r--spec/ruby/core/array/clone_spec.rb8
-rw-r--r--spec/ruby/core/array/collect_spec.rb10
-rw-r--r--spec/ruby/core/array/combination_spec.rb6
-rw-r--r--spec/ruby/core/array/compact_spec.rb14
-rw-r--r--spec/ruby/core/array/comparison_spec.rb2
-rw-r--r--spec/ruby/core/array/concat_spec.rb10
-rw-r--r--spec/ruby/core/array/constructor_spec.rb4
-rw-r--r--spec/ruby/core/array/cycle_spec.rb20
-rw-r--r--spec/ruby/core/array/deconstruct_spec.rb2
-rw-r--r--spec/ruby/core/array/delete_at_spec.rb2
-rw-r--r--spec/ruby/core/array/delete_if_spec.rb16
-rw-r--r--spec/ruby/core/array/delete_spec.rb2
-rw-r--r--spec/ruby/core/array/difference_spec.rb4
-rw-r--r--spec/ruby/core/array/dig_spec.rb8
-rw-r--r--spec/ruby/core/array/drop_spec.rb8
-rw-r--r--spec/ruby/core/array/drop_while_spec.rb2
-rw-r--r--spec/ruby/core/array/dup_spec.rb12
-rw-r--r--spec/ruby/core/array/each_index_spec.rb2
-rw-r--r--spec/ruby/core/array/each_spec.rb2
-rw-r--r--spec/ruby/core/array/element_reference_spec.rb861
-rw-r--r--spec/ruby/core/array/element_set_spec.rb48
-rw-r--r--spec/ruby/core/array/eql_spec.rb4
-rw-r--r--spec/ruby/core/array/equal_value_spec.rb10
-rw-r--r--spec/ruby/core/array/fetch_spec.rb10
-rw-r--r--spec/ruby/core/array/fetch_values_spec.rb6
-rw-r--r--spec/ruby/core/array/fill_spec.rb50
-rw-r--r--spec/ruby/core/array/filter_spec.rb11
-rw-r--r--spec/ruby/core/array/find_index_spec.rb40
-rw-r--r--spec/ruby/core/array/first_spec.rb24
-rw-r--r--spec/ruby/core/array/flatten_spec.rb36
-rw-r--r--spec/ruby/core/array/hash_spec.rb8
-rw-r--r--spec/ruby/core/array/index_spec.rb5
-rw-r--r--spec/ruby/core/array/initialize_spec.rb32
-rw-r--r--spec/ruby/core/array/insert_spec.rb14
-rw-r--r--spec/ruby/core/array/inspect_spec.rb105
-rw-r--r--spec/ruby/core/array/join_spec.rb102
-rw-r--r--spec/ruby/core/array/keep_if_spec.rb2
-rw-r--r--spec/ruby/core/array/last_spec.rb22
-rw-r--r--spec/ruby/core/array/length_spec.rb6
-rw-r--r--spec/ruby/core/array/map_spec.rb138
-rw-r--r--spec/ruby/core/array/max_spec.rb8
-rw-r--r--spec/ruby/core/array/min_spec.rb10
-rw-r--r--spec/ruby/core/array/multiply_spec.rb22
-rw-r--r--spec/ruby/core/array/new_spec.rb28
-rw-r--r--spec/ruby/core/array/pack/a_spec.rb4
-rw-r--r--spec/ruby/core/array/pack/b_spec.rb4
-rw-r--r--spec/ruby/core/array/pack/buffer_spec.rb6
-rw-r--r--spec/ruby/core/array/pack/c_spec.rb18
-rw-r--r--spec/ruby/core/array/pack/h_spec.rb4
-rw-r--r--spec/ruby/core/array/pack/m_spec.rb12
-rw-r--r--spec/ruby/core/array/pack/percent_spec.rb2
-rw-r--r--spec/ruby/core/array/pack/r_spec.rb89
-rw-r--r--spec/ruby/core/array/pack/shared/basic.rb47
-rw-r--r--spec/ruby/core/array/pack/shared/encodings.rb4
-rw-r--r--spec/ruby/core/array/pack/shared/float.rb88
-rw-r--r--spec/ruby/core/array/pack/shared/integer.rb114
-rw-r--r--spec/ruby/core/array/pack/shared/numeric_basic.rb16
-rw-r--r--spec/ruby/core/array/pack/shared/string.rb6
-rw-r--r--spec/ruby/core/array/pack/shared/unicode.rb26
-rw-r--r--spec/ruby/core/array/pack/u_spec.rb10
-rw-r--r--spec/ruby/core/array/pack/w_spec.rb20
-rw-r--r--spec/ruby/core/array/pack/x_spec.rb4
-rw-r--r--spec/ruby/core/array/pack/z_spec.rb2
-rw-r--r--spec/ruby/core/array/partition_spec.rb6
-rw-r--r--spec/ruby/core/array/permutation_spec.rb10
-rw-r--r--spec/ruby/core/array/plus_spec.rb12
-rw-r--r--spec/ruby/core/array/pop_spec.rb24
-rw-r--r--spec/ruby/core/array/prepend_spec.rb6
-rw-r--r--spec/ruby/core/array/product_spec.rb14
-rw-r--r--spec/ruby/core/array/push_spec.rb33
-rw-r--r--spec/ruby/core/array/rassoc_spec.rb22
-rw-r--r--spec/ruby/core/array/reject_spec.rb16
-rw-r--r--spec/ruby/core/array/repeated_combination_spec.rb8
-rw-r--r--spec/ruby/core/array/repeated_permutation_spec.rb4
-rw-r--r--spec/ruby/core/array/replace_spec.rb60
-rw-r--r--spec/ruby/core/array/reverse_each_spec.rb2
-rw-r--r--spec/ruby/core/array/reverse_spec.rb6
-rw-r--r--spec/ruby/core/array/rindex_spec.rb4
-rw-r--r--spec/ruby/core/array/rotate_spec.rb42
-rw-r--r--spec/ruby/core/array/sample_spec.rb32
-rw-r--r--spec/ruby/core/array/select_spec.rb35
-rw-r--r--spec/ruby/core/array/shared/clone.rb8
-rw-r--r--spec/ruby/core/array/shared/collect.rb141
-rw-r--r--spec/ruby/core/array/shared/difference.rb8
-rw-r--r--spec/ruby/core/array/shared/enumeratorize.rb2
-rw-r--r--spec/ruby/core/array/shared/eql.rb66
-rw-r--r--spec/ruby/core/array/shared/index.rb41
-rw-r--r--spec/ruby/core/array/shared/inspect.rb107
-rw-r--r--spec/ruby/core/array/shared/intersection.rb6
-rw-r--r--spec/ruby/core/array/shared/join.rb97
-rw-r--r--spec/ruby/core/array/shared/keep_if.rb16
-rw-r--r--spec/ruby/core/array/shared/length.rb11
-rw-r--r--spec/ruby/core/array/shared/push.rb33
-rw-r--r--spec/ruby/core/array/shared/replace.rb60
-rw-r--r--spec/ruby/core/array/shared/select.rb35
-rw-r--r--spec/ruby/core/array/shared/slice.rb857
-rw-r--r--spec/ruby/core/array/shared/union.rb6
-rw-r--r--spec/ruby/core/array/shared/unshift.rb64
-rw-r--r--spec/ruby/core/array/shift_spec.rb20
-rw-r--r--spec/ruby/core/array/shuffle_spec.rb28
-rw-r--r--spec/ruby/core/array/size_spec.rb11
-rw-r--r--spec/ruby/core/array/slice_spec.rb23
-rw-r--r--spec/ruby/core/array/sort_by_spec.rb16
-rw-r--r--spec/ruby/core/array/sort_spec.rb40
-rw-r--r--spec/ruby/core/array/sum_spec.rb16
-rw-r--r--spec/ruby/core/array/take_spec.rb4
-rw-r--r--spec/ruby/core/array/take_while_spec.rb2
-rw-r--r--spec/ruby/core/array/to_a_spec.rb4
-rw-r--r--spec/ruby/core/array/to_ary_spec.rb4
-rw-r--r--spec/ruby/core/array/to_h_spec.rb16
-rw-r--r--spec/ruby/core/array/to_s_spec.rb7
-rw-r--r--spec/ruby/core/array/transpose_spec.rb10
-rw-r--r--spec/ruby/core/array/try_convert_spec.rb16
-rw-r--r--spec/ruby/core/array/union_spec.rb2
-rw-r--r--spec/ruby/core/array/uniq_spec.rb12
-rw-r--r--spec/ruby/core/array/unshift_spec.rb64
-rw-r--r--spec/ruby/core/array/values_at_spec.rb2
-rw-r--r--spec/ruby/core/array/zip_spec.rb8
-rw-r--r--spec/ruby/core/basicobject/__send___spec.rb2
-rw-r--r--spec/ruby/core/basicobject/basicobject_spec.rb20
-rw-r--r--spec/ruby/core/basicobject/equal_spec.rb51
-rw-r--r--spec/ruby/core/basicobject/equal_value_spec.rb46
-rw-r--r--spec/ruby/core/basicobject/initialize_spec.rb4
-rw-r--r--spec/ruby/core/basicobject/instance_eval_spec.rb60
-rw-r--r--spec/ruby/core/basicobject/instance_exec_spec.rb30
-rw-r--r--spec/ruby/core/basicobject/method_missing_spec.rb2
-rw-r--r--spec/ruby/core/basicobject/not_equal_spec.rb16
-rw-r--r--spec/ruby/core/basicobject/not_spec.rb4
-rw-r--r--spec/ruby/core/basicobject/singleton_method_added_spec.rb12
-rw-r--r--spec/ruby/core/basicobject/singleton_method_removed_spec.rb2
-rw-r--r--spec/ruby/core/basicobject/singleton_method_undefined_spec.rb2
-rw-r--r--spec/ruby/core/binding/dup_spec.rb2
-rw-r--r--spec/ruby/core/binding/eval_spec.rb16
-rw-r--r--spec/ruby/core/binding/local_variable_get_spec.rb10
-rw-r--r--spec/ruby/core/binding/local_variable_set_spec.rb8
-rw-r--r--spec/ruby/core/binding/local_variables_spec.rb2
-rw-r--r--spec/ruby/core/builtin_constants/builtin_constants_spec.rb88
-rw-r--r--spec/ruby/core/class/allocate_spec.rb6
-rw-r--r--spec/ruby/core/class/attached_object_spec.rb8
-rw-r--r--spec/ruby/core/class/dup_spec.rb4
-rw-r--r--spec/ruby/core/class/inherited_spec.rb4
-rw-r--r--spec/ruby/core/class/initialize_spec.rb10
-rw-r--r--spec/ruby/core/class/new_spec.rb22
-rw-r--r--spec/ruby/core/class/subclasses_spec.rb4
-rw-r--r--spec/ruby/core/class/superclass_spec.rb2
-rw-r--r--spec/ruby/core/comparable/clamp_spec.rb179
-rw-r--r--spec/ruby/core/comparable/equal_value_spec.rb10
-rw-r--r--spec/ruby/core/comparable/fixtures/classes.rb1
-rw-r--r--spec/ruby/core/comparable/gt_spec.rb2
-rw-r--r--spec/ruby/core/comparable/gte_spec.rb2
-rw-r--r--spec/ruby/core/comparable/lt_spec.rb6
-rw-r--r--spec/ruby/core/comparable/lte_spec.rb2
-rw-r--r--spec/ruby/core/complex/abs_spec.rb10
-rw-r--r--spec/ruby/core/complex/angle_spec.rb5
-rw-r--r--spec/ruby/core/complex/arg_spec.rb9
-rw-r--r--spec/ruby/core/complex/coerce_spec.rb32
-rw-r--r--spec/ruby/core/complex/comparison_spec.rb12
-rw-r--r--spec/ruby/core/complex/conj_spec.rb5
-rw-r--r--spec/ruby/core/complex/conjugate_spec.rb8
-rw-r--r--spec/ruby/core/complex/constants_spec.rb2
-rw-r--r--spec/ruby/core/complex/divide_spec.rb82
-rw-r--r--spec/ruby/core/complex/eql_spec.rb12
-rw-r--r--spec/ruby/core/complex/equal_value_spec.rb8
-rw-r--r--spec/ruby/core/complex/exponent_spec.rb4
-rw-r--r--spec/ruby/core/complex/fdiv_spec.rb42
-rw-r--r--spec/ruby/core/complex/imag_spec.rb5
-rw-r--r--spec/ruby/core/complex/imaginary_spec.rb8
-rw-r--r--spec/ruby/core/complex/integer_spec.rb4
-rw-r--r--spec/ruby/core/complex/magnitude_spec.rb5
-rw-r--r--spec/ruby/core/complex/marshal_dump_spec.rb2
-rw-r--r--spec/ruby/core/complex/negative_spec.rb4
-rw-r--r--spec/ruby/core/complex/phase_spec.rb5
-rw-r--r--spec/ruby/core/complex/polar_spec.rb12
-rw-r--r--spec/ruby/core/complex/positive_spec.rb4
-rw-r--r--spec/ruby/core/complex/quo_spec.rb5
-rw-r--r--spec/ruby/core/complex/rationalize_spec.rb8
-rw-r--r--spec/ruby/core/complex/real_spec.rb8
-rw-r--r--spec/ruby/core/complex/rect_spec.rb9
-rw-r--r--spec/ruby/core/complex/rectangular_spec.rb110
-rw-r--r--spec/ruby/core/complex/shared/abs.rb10
-rw-r--r--spec/ruby/core/complex/shared/arg.rb9
-rw-r--r--spec/ruby/core/complex/shared/conjugate.rb8
-rw-r--r--spec/ruby/core/complex/shared/divide.rb82
-rw-r--r--spec/ruby/core/complex/shared/image.rb8
-rw-r--r--spec/ruby/core/complex/shared/rect.rb94
-rw-r--r--spec/ruby/core/complex/to_c_spec.rb2
-rw-r--r--spec/ruby/core/complex/to_f_spec.rb4
-rw-r--r--spec/ruby/core/complex/to_i_spec.rb4
-rw-r--r--spec/ruby/core/complex/to_r_spec.rb4
-rw-r--r--spec/ruby/core/conditionvariable/broadcast_spec.rb2
-rw-r--r--spec/ruby/core/conditionvariable/marshal_dump_spec.rb2
-rw-r--r--spec/ruby/core/conditionvariable/signal_spec.rb2
-rw-r--r--spec/ruby/core/conditionvariable/wait_spec.rb2
-rw-r--r--spec/ruby/core/data/deconstruct_keys_spec.rb96
-rw-r--r--spec/ruby/core/data/fixtures/classes.rb13
-rw-r--r--spec/ruby/core/data/hash_spec.rb2
-rw-r--r--spec/ruby/core/data/initialize_spec.rb98
-rw-r--r--spec/ruby/core/data/inspect_spec.rb6
-rw-r--r--spec/ruby/core/data/shared/inspect.rb62
-rw-r--r--spec/ruby/core/data/to_h_spec.rb8
-rw-r--r--spec/ruby/core/data/to_s_spec.rb61
-rw-r--r--spec/ruby/core/data/with_spec.rb14
-rw-r--r--spec/ruby/core/dir/chdir_spec.rb150
-rw-r--r--spec/ruby/core/dir/children_spec.rb18
-rw-r--r--spec/ruby/core/dir/chroot_spec.rb6
-rw-r--r--spec/ruby/core/dir/close_spec.rb10
-rw-r--r--spec/ruby/core/dir/delete_spec.rb53
-rw-r--r--spec/ruby/core/dir/each_child_spec.rb6
-rw-r--r--spec/ruby/core/dir/each_spec.rb4
-rw-r--r--spec/ruby/core/dir/empty_spec.rb8
-rw-r--r--spec/ruby/core/dir/entries_spec.rb10
-rw-r--r--spec/ruby/core/dir/exist_spec.rb57
-rw-r--r--spec/ruby/core/dir/fchdir_spec.rb108
-rw-r--r--spec/ruby/core/dir/fileno_spec.rb4
-rw-r--r--spec/ruby/core/dir/fixtures/common.rb39
-rw-r--r--spec/ruby/core/dir/for_fd_spec.rb110
-rw-r--r--spec/ruby/core/dir/foreach_spec.rb6
-rw-r--r--spec/ruby/core/dir/getwd_spec.rb12
-rw-r--r--spec/ruby/core/dir/glob_spec.rb2
-rw-r--r--spec/ruby/core/dir/home_spec.rb2
-rw-r--r--spec/ruby/core/dir/inspect_spec.rb4
-rw-r--r--spec/ruby/core/dir/mkdir_spec.rb10
-rw-r--r--spec/ruby/core/dir/open_spec.rb73
-rw-r--r--spec/ruby/core/dir/path_spec.rb12
-rw-r--r--spec/ruby/core/dir/pos_spec.rb29
-rw-r--r--spec/ruby/core/dir/pwd_spec.rb45
-rw-r--r--spec/ruby/core/dir/read_spec.rb4
-rw-r--r--spec/ruby/core/dir/rmdir_spec.rb12
-rw-r--r--spec/ruby/core/dir/scan_spec.rb224
-rw-r--r--spec/ruby/core/dir/shared/chroot.rb4
-rw-r--r--spec/ruby/core/dir/shared/closed.rb2
-rw-r--r--spec/ruby/core/dir/shared/delete.rb53
-rw-r--r--spec/ruby/core/dir/shared/exist.rb57
-rw-r--r--spec/ruby/core/dir/shared/glob.rb12
-rw-r--r--spec/ruby/core/dir/shared/open.rb73
-rw-r--r--spec/ruby/core/dir/shared/path.rb30
-rw-r--r--spec/ruby/core/dir/shared/pos.rb27
-rw-r--r--spec/ruby/core/dir/shared/pwd.rb45
-rw-r--r--spec/ruby/core/dir/tell_spec.rb13
-rw-r--r--spec/ruby/core/dir/to_path_spec.rb26
-rw-r--r--spec/ruby/core/dir/unlink_spec.rb12
-rw-r--r--spec/ruby/core/encoding/aliases_spec.rb10
-rw-r--r--spec/ruby/core/encoding/ascii_compatible_spec.rb15
-rw-r--r--spec/ruby/core/encoding/compatible_spec.rb50
-rw-r--r--spec/ruby/core/encoding/converter/asciicompat_encoding_spec.rb16
-rw-r--r--spec/ruby/core/encoding/converter/constants_spec.rb52
-rw-r--r--spec/ruby/core/encoding/converter/convert_spec.rb7
-rw-r--r--spec/ruby/core/encoding/converter/finish_spec.rb2
-rw-r--r--spec/ruby/core/encoding/converter/last_error_spec.rb32
-rw-r--r--spec/ruby/core/encoding/converter/new_spec.rb10
-rw-r--r--spec/ruby/core/encoding/converter/primitive_convert_spec.rb26
-rw-r--r--spec/ruby/core/encoding/converter/primitive_errinfo_spec.rb4
-rw-r--r--spec/ruby/core/encoding/converter/putback_spec.rb2
-rw-r--r--spec/ruby/core/encoding/converter/replacement_spec.rb8
-rw-r--r--spec/ruby/core/encoding/converter/search_convpath_spec.rb2
-rw-r--r--spec/ruby/core/encoding/default_external_spec.rb6
-rw-r--r--spec/ruby/core/encoding/default_internal_spec.rb12
-rw-r--r--spec/ruby/core/encoding/dummy_spec.rb21
-rw-r--r--spec/ruby/core/encoding/find_spec.rb8
-rw-r--r--spec/ruby/core/encoding/inspect_spec.rb2
-rw-r--r--spec/ruby/core/encoding/invalid_byte_sequence_error/destination_encoding_name_spec.rb4
-rw-r--r--spec/ruby/core/encoding/invalid_byte_sequence_error/destination_encoding_spec.rb4
-rw-r--r--spec/ruby/core/encoding/invalid_byte_sequence_error/error_bytes_spec.rb4
-rw-r--r--spec/ruby/core/encoding/invalid_byte_sequence_error/incomplete_input_spec.rb6
-rw-r--r--spec/ruby/core/encoding/invalid_byte_sequence_error/readagain_bytes_spec.rb4
-rw-r--r--spec/ruby/core/encoding/invalid_byte_sequence_error/source_encoding_name_spec.rb2
-rw-r--r--spec/ruby/core/encoding/invalid_byte_sequence_error/source_encoding_spec.rb4
-rw-r--r--spec/ruby/core/encoding/list_spec.rb10
-rw-r--r--spec/ruby/core/encoding/locale_charmap_spec.rb76
-rw-r--r--spec/ruby/core/encoding/name_list_spec.rb8
-rw-r--r--spec/ruby/core/encoding/name_spec.rb13
-rw-r--r--spec/ruby/core/encoding/names_spec.rb6
-rw-r--r--spec/ruby/core/encoding/replicate_spec.rb84
-rw-r--r--spec/ruby/core/encoding/shared/name.rb15
-rw-r--r--spec/ruby/core/encoding/to_s_spec.rb5
-rw-r--r--spec/ruby/core/encoding/undefined_conversion_error/destination_encoding_name_spec.rb2
-rw-r--r--spec/ruby/core/encoding/undefined_conversion_error/destination_encoding_spec.rb2
-rw-r--r--spec/ruby/core/encoding/undefined_conversion_error/error_char_spec.rb4
-rw-r--r--spec/ruby/core/encoding/undefined_conversion_error/source_encoding_name_spec.rb2
-rw-r--r--spec/ruby/core/encoding/undefined_conversion_error/source_encoding_spec.rb4
-rw-r--r--spec/ruby/core/enumerable/all_spec.rb20
-rw-r--r--spec/ruby/core/enumerable/any_spec.rb20
-rw-r--r--spec/ruby/core/enumerable/chain_spec.rb2
-rw-r--r--spec/ruby/core/enumerable/chunk_spec.rb8
-rw-r--r--spec/ruby/core/enumerable/chunk_while_spec.rb4
-rw-r--r--spec/ruby/core/enumerable/collect_concat_spec.rb6
-rw-r--r--spec/ruby/core/enumerable/collect_spec.rb6
-rw-r--r--spec/ruby/core/enumerable/cycle_spec.rb10
-rw-r--r--spec/ruby/core/enumerable/detect_spec.rb6
-rw-r--r--spec/ruby/core/enumerable/drop_spec.rb10
-rw-r--r--spec/ruby/core/enumerable/drop_while_spec.rb4
-rw-r--r--spec/ruby/core/enumerable/each_cons_spec.rb18
-rw-r--r--spec/ruby/core/enumerable/each_entry_spec.rb8
-rw-r--r--spec/ruby/core/enumerable/each_slice_spec.rb20
-rw-r--r--spec/ruby/core/enumerable/each_with_index_spec.rb6
-rw-r--r--spec/ruby/core/enumerable/each_with_object_spec.rb8
-rw-r--r--spec/ruby/core/enumerable/entries_spec.rb6
-rw-r--r--spec/ruby/core/enumerable/filter_map_spec.rb2
-rw-r--r--spec/ruby/core/enumerable/filter_spec.rb6
-rw-r--r--spec/ruby/core/enumerable/find_all_spec.rb6
-rw-r--r--spec/ruby/core/enumerable/find_index_spec.rb2
-rw-r--r--spec/ruby/core/enumerable/find_spec.rb75
-rw-r--r--spec/ruby/core/enumerable/first_spec.rb2
-rw-r--r--spec/ruby/core/enumerable/flat_map_spec.rb53
-rw-r--r--spec/ruby/core/enumerable/grep_spec.rb2
-rw-r--r--spec/ruby/core/enumerable/grep_v_spec.rb4
-rw-r--r--spec/ruby/core/enumerable/group_by_spec.rb8
-rw-r--r--spec/ruby/core/enumerable/include_spec.rb33
-rw-r--r--spec/ruby/core/enumerable/inject_spec.rb141
-rw-r--r--spec/ruby/core/enumerable/lazy_spec.rb2
-rw-r--r--spec/ruby/core/enumerable/map_spec.rb106
-rw-r--r--spec/ruby/core/enumerable/max_by_spec.rb8
-rw-r--r--spec/ruby/core/enumerable/max_spec.rb8
-rw-r--r--spec/ruby/core/enumerable/member_spec.rb6
-rw-r--r--spec/ruby/core/enumerable/min_by_spec.rb8
-rw-r--r--spec/ruby/core/enumerable/min_spec.rb10
-rw-r--r--spec/ruby/core/enumerable/minmax_by_spec.rb6
-rw-r--r--spec/ruby/core/enumerable/none_spec.rb28
-rw-r--r--spec/ruby/core/enumerable/one_spec.rb32
-rw-r--r--spec/ruby/core/enumerable/partition_spec.rb2
-rw-r--r--spec/ruby/core/enumerable/reduce_spec.rb6
-rw-r--r--spec/ruby/core/enumerable/reject_spec.rb2
-rw-r--r--spec/ruby/core/enumerable/reverse_each_spec.rb2
-rw-r--r--spec/ruby/core/enumerable/select_spec.rb30
-rw-r--r--spec/ruby/core/enumerable/shared/collect.rb107
-rw-r--r--spec/ruby/core/enumerable/shared/collect_concat.rb54
-rw-r--r--spec/ruby/core/enumerable/shared/entries.rb16
-rw-r--r--spec/ruby/core/enumerable/shared/find.rb77
-rw-r--r--spec/ruby/core/enumerable/shared/find_all.rb31
-rw-r--r--spec/ruby/core/enumerable/shared/include.rb34
-rw-r--r--spec/ruby/core/enumerable/shared/inject.rb142
-rw-r--r--spec/ruby/core/enumerable/shared/take.rb8
-rw-r--r--spec/ruby/core/enumerable/shared/value_packing.rb26
-rw-r--r--spec/ruby/core/enumerable/slice_after_spec.rb10
-rw-r--r--spec/ruby/core/enumerable/slice_before_spec.rb10
-rw-r--r--spec/ruby/core/enumerable/slice_when_spec.rb4
-rw-r--r--spec/ruby/core/enumerable/sort_by_spec.rb2
-rw-r--r--spec/ruby/core/enumerable/sort_spec.rb6
-rw-r--r--spec/ruby/core/enumerable/take_spec.rb10
-rw-r--r--spec/ruby/core/enumerable/take_while_spec.rb4
-rw-r--r--spec/ruby/core/enumerable/tally_spec.rb12
-rw-r--r--spec/ruby/core/enumerable/to_a_spec.rb16
-rw-r--r--spec/ruby/core/enumerable/to_h_spec.rb12
-rw-r--r--spec/ruby/core/enumerable/to_set_spec.rb16
-rw-r--r--spec/ruby/core/enumerable/zip_spec.rb6
-rw-r--r--spec/ruby/core/enumerator/arithmetic_sequence/each_spec.rb2
-rw-r--r--spec/ruby/core/enumerator/arithmetic_sequence/hash_spec.rb2
-rw-r--r--spec/ruby/core/enumerator/arithmetic_sequence/new_spec.rb4
-rw-r--r--spec/ruby/core/enumerator/chain/initialize_spec.rb10
-rw-r--r--spec/ruby/core/enumerator/chain/rewind_spec.rb6
-rw-r--r--spec/ruby/core/enumerator/each_spec.rb44
-rw-r--r--spec/ruby/core/enumerator/each_with_index_spec.rb4
-rw-r--r--spec/ruby/core/enumerator/each_with_object_spec.rb40
-rw-r--r--spec/ruby/core/enumerator/enum_for_spec.rb6
-rw-r--r--spec/ruby/core/enumerator/feed_spec.rb6
-rw-r--r--spec/ruby/core/enumerator/generator/each_spec.rb40
-rw-r--r--spec/ruby/core/enumerator/generator/initialize_spec.rb26
-rw-r--r--spec/ruby/core/enumerator/initialize_spec.rb14
-rw-r--r--spec/ruby/core/enumerator/lazy/chunk_spec.rb6
-rw-r--r--spec/ruby/core/enumerator/lazy/chunk_while_spec.rb2
-rw-r--r--spec/ruby/core/enumerator/lazy/collect_concat_spec.rb8
-rw-r--r--spec/ruby/core/enumerator/lazy/collect_spec.rb8
-rw-r--r--spec/ruby/core/enumerator/lazy/compact_spec.rb2
-rw-r--r--spec/ruby/core/enumerator/lazy/drop_spec.rb4
-rw-r--r--spec/ruby/core/enumerator/lazy/drop_while_spec.rb6
-rw-r--r--spec/ruby/core/enumerator/lazy/enum_for_spec.rb8
-rw-r--r--spec/ruby/core/enumerator/lazy/filter_spec.rb6
-rw-r--r--spec/ruby/core/enumerator/lazy/find_all_spec.rb8
-rw-r--r--spec/ruby/core/enumerator/lazy/flat_map_spec.rb76
-rw-r--r--spec/ruby/core/enumerator/lazy/grep_spec.rb8
-rw-r--r--spec/ruby/core/enumerator/lazy/grep_v_spec.rb8
-rw-r--r--spec/ruby/core/enumerator/lazy/initialize_spec.rb14
-rw-r--r--spec/ruby/core/enumerator/lazy/lazy_spec.rb8
-rw-r--r--spec/ruby/core/enumerator/lazy/map_spec.rb60
-rw-r--r--spec/ruby/core/enumerator/lazy/reject_spec.rb8
-rw-r--r--spec/ruby/core/enumerator/lazy/select_spec.rb64
-rw-r--r--spec/ruby/core/enumerator/lazy/shared/collect.rb62
-rw-r--r--spec/ruby/core/enumerator/lazy/shared/collect_concat.rb78
-rw-r--r--spec/ruby/core/enumerator/lazy/shared/select.rb66
-rw-r--r--spec/ruby/core/enumerator/lazy/shared/to_enum.rb55
-rw-r--r--spec/ruby/core/enumerator/lazy/slice_after_spec.rb2
-rw-r--r--spec/ruby/core/enumerator/lazy/slice_before_spec.rb2
-rw-r--r--spec/ruby/core/enumerator/lazy/slice_when_spec.rb2
-rw-r--r--spec/ruby/core/enumerator/lazy/take_spec.rb12
-rw-r--r--spec/ruby/core/enumerator/lazy/take_while_spec.rb6
-rw-r--r--spec/ruby/core/enumerator/lazy/to_enum_spec.rb54
-rw-r--r--spec/ruby/core/enumerator/lazy/uniq_spec.rb4
-rw-r--r--spec/ruby/core/enumerator/lazy/with_index_spec.rb2
-rw-r--r--spec/ruby/core/enumerator/lazy/zip_spec.rb8
-rw-r--r--spec/ruby/core/enumerator/new_spec.rb61
-rw-r--r--spec/ruby/core/enumerator/next_spec.rb8
-rw-r--r--spec/ruby/core/enumerator/next_values_spec.rb2
-rw-r--r--spec/ruby/core/enumerator/peek_spec.rb2
-rw-r--r--spec/ruby/core/enumerator/peek_values_spec.rb2
-rw-r--r--spec/ruby/core/enumerator/plus_spec.rb2
-rw-r--r--spec/ruby/core/enumerator/produce_spec.rb44
-rw-r--r--spec/ruby/core/enumerator/product/each_spec.rb16
-rw-r--r--spec/ruby/core/enumerator/product/initialize_copy_spec.rb10
-rw-r--r--spec/ruby/core/enumerator/product/initialize_spec.rb10
-rw-r--r--spec/ruby/core/enumerator/product/size_spec.rb10
-rw-r--r--spec/ruby/core/enumerator/product_spec.rb6
-rw-r--r--spec/ruby/core/enumerator/shared/each.rb46
-rw-r--r--spec/ruby/core/enumerator/shared/enum_for.rb57
-rw-r--r--spec/ruby/core/enumerator/shared/with_index.rb4
-rw-r--r--spec/ruby/core/enumerator/shared/with_object.rb42
-rw-r--r--spec/ruby/core/enumerator/size_spec.rb2
-rw-r--r--spec/ruby/core/enumerator/to_enum_spec.rb6
-rw-r--r--spec/ruby/core/enumerator/with_index_spec.rb8
-rw-r--r--spec/ruby/core/enumerator/with_object_spec.rb5
-rw-r--r--spec/ruby/core/enumerator/yielder/append_spec.rb35
-rw-r--r--spec/ruby/core/enumerator/yielder/initialize_spec.rb18
-rw-r--r--spec/ruby/core/enumerator/yielder/to_proc_spec.rb16
-rw-r--r--spec/ruby/core/enumerator/yielder/yield_spec.rb33
-rw-r--r--spec/ruby/core/env/assoc_spec.rb2
-rw-r--r--spec/ruby/core/env/clear_spec.rb2
-rw-r--r--spec/ruby/core/env/clone_spec.rb6
-rw-r--r--spec/ruby/core/env/delete_if_spec.rb10
-rw-r--r--spec/ruby/core/env/delete_spec.rb2
-rw-r--r--spec/ruby/core/env/dup_spec.rb2
-rw-r--r--spec/ruby/core/env/each_key_spec.rb8
-rw-r--r--spec/ruby/core/env/each_pair_spec.rb61
-rw-r--r--spec/ruby/core/env/each_spec.rb5
-rw-r--r--spec/ruby/core/env/each_value_spec.rb8
-rw-r--r--spec/ruby/core/env/element_reference_spec.rb4
-rw-r--r--spec/ruby/core/env/element_set_spec.rb60
-rw-r--r--spec/ruby/core/env/fetch_spec.rb4
-rw-r--r--spec/ruby/core/env/fetch_values_spec.rb51
-rw-r--r--spec/ruby/core/env/filter_spec.rb12
-rw-r--r--spec/ruby/core/env/has_key_spec.rb5
-rw-r--r--spec/ruby/core/env/has_value_spec.rb5
-rw-r--r--spec/ruby/core/env/include_spec.rb30
-rw-r--r--spec/ruby/core/env/keep_if_spec.rb10
-rw-r--r--spec/ruby/core/env/key_spec.rb9
-rw-r--r--spec/ruby/core/env/length_spec.rb5
-rw-r--r--spec/ruby/core/env/member_spec.rb5
-rw-r--r--spec/ruby/core/env/merge_spec.rb104
-rw-r--r--spec/ruby/core/env/rassoc_spec.rb2
-rw-r--r--spec/ruby/core/env/reject_spec.rb14
-rw-r--r--spec/ruby/core/env/replace_spec.rb16
-rw-r--r--spec/ruby/core/env/select_spec.rb61
-rw-r--r--spec/ruby/core/env/shared/each.rb65
-rw-r--r--spec/ruby/core/env/shared/include.rb30
-rw-r--r--spec/ruby/core/env/shared/length.rb13
-rw-r--r--spec/ruby/core/env/shared/select.rb61
-rw-r--r--spec/ruby/core/env/shared/store.rb60
-rw-r--r--spec/ruby/core/env/shared/to_hash.rb4
-rw-r--r--spec/ruby/core/env/shared/update.rb104
-rw-r--r--spec/ruby/core/env/shared/value.rb29
-rw-r--r--spec/ruby/core/env/shift_spec.rb8
-rw-r--r--spec/ruby/core/env/size_spec.rb13
-rw-r--r--spec/ruby/core/env/slice_spec.rb2
-rw-r--r--spec/ruby/core/env/store_spec.rb5
-rw-r--r--spec/ruby/core/env/to_h_spec.rb8
-rw-r--r--spec/ruby/core/env/update_spec.rb5
-rw-r--r--spec/ruby/core/env/value_spec.rb29
-rw-r--r--spec/ruby/core/env/values_at_spec.rb2
-rw-r--r--spec/ruby/core/exception/backtrace_locations_spec.rb6
-rw-r--r--spec/ruby/core/exception/backtrace_spec.rb10
-rw-r--r--spec/ruby/core/exception/cause_spec.rb54
-rw-r--r--spec/ruby/core/exception/dup_spec.rb14
-rw-r--r--spec/ruby/core/exception/equal_value_spec.rb4
-rw-r--r--spec/ruby/core/exception/errno_spec.rb10
-rw-r--r--spec/ruby/core/exception/exception_spec.rb4
-rw-r--r--spec/ruby/core/exception/exit_value_spec.rb2
-rw-r--r--spec/ruby/core/exception/frozen_error_spec.rb14
-rw-r--r--spec/ruby/core/exception/full_message_spec.rb24
-rw-r--r--spec/ruby/core/exception/io_error_spec.rb16
-rw-r--r--spec/ruby/core/exception/name_spec.rb12
-rw-r--r--spec/ruby/core/exception/no_method_error_spec.rb269
-rw-r--r--spec/ruby/core/exception/reason_spec.rb2
-rw-r--r--spec/ruby/core/exception/receiver_spec.rb16
-rw-r--r--spec/ruby/core/exception/result_spec.rb4
-rw-r--r--spec/ruby/core/exception/shared/new.rb4
-rw-r--r--spec/ruby/core/exception/shared/set_backtrace.rb10
-rw-r--r--spec/ruby/core/exception/signal_exception_spec.rb10
-rw-r--r--spec/ruby/core/exception/signm_spec.rb2
-rw-r--r--spec/ruby/core/exception/signo_spec.rb2
-rw-r--r--spec/ruby/core/exception/standard_error_spec.rb2
-rw-r--r--spec/ruby/core/exception/status_spec.rb2
-rw-r--r--spec/ruby/core/exception/success_spec.rb4
-rw-r--r--spec/ruby/core/exception/syntax_error_spec.rb4
-rw-r--r--spec/ruby/core/exception/system_call_error_spec.rb30
-rw-r--r--spec/ruby/core/false/dup_spec.rb2
-rw-r--r--spec/ruby/core/false/falseclass_spec.rb4
-rw-r--r--spec/ruby/core/false/inspect_spec.rb4
-rw-r--r--spec/ruby/core/false/singleton_method_spec.rb16
-rw-r--r--spec/ruby/core/false/to_s_spec.rb2
-rw-r--r--spec/ruby/core/false/xor_spec.rb8
-rw-r--r--spec/ruby/core/fiber/alive_spec.rb20
-rw-r--r--spec/ruby/core/fiber/current_spec.rb14
-rw-r--r--spec/ruby/core/fiber/fixtures/scheduler.rb35
-rw-r--r--spec/ruby/core/fiber/kill_spec.rb120
-rw-r--r--spec/ruby/core/fiber/new_spec.rb8
-rw-r--r--spec/ruby/core/fiber/raise_spec.rb46
-rw-r--r--spec/ruby/core/fiber/resume_spec.rb4
-rw-r--r--spec/ruby/core/fiber/scheduler_spec.rb5
-rw-r--r--spec/ruby/core/fiber/set_scheduler_spec.rb55
-rw-r--r--spec/ruby/core/fiber/shared/resume.rb14
-rw-r--r--spec/ruby/core/fiber/storage_spec.rb54
-rw-r--r--spec/ruby/core/fiber/transfer_spec.rb6
-rw-r--r--spec/ruby/core/fiber/yield_spec.rb4
-rw-r--r--spec/ruby/core/file/absolute_path_spec.rb24
-rw-r--r--spec/ruby/core/file/atime_spec.rb6
-rw-r--r--spec/ruby/core/file/basename_spec.rb36
-rw-r--r--spec/ruby/core/file/birthtime_spec.rb6
-rw-r--r--spec/ruby/core/file/chmod_spec.rb12
-rw-r--r--spec/ruby/core/file/chown_spec.rb2
-rw-r--r--spec/ruby/core/file/constants/constants_spec.rb6
-rw-r--r--spec/ruby/core/file/ctime_spec.rb6
-rw-r--r--spec/ruby/core/file/delete_spec.rb61
-rw-r--r--spec/ruby/core/file/dirname_spec.rb45
-rw-r--r--spec/ruby/core/file/expand_path_spec.rb20
-rw-r--r--spec/ruby/core/file/extname_spec.rb12
-rw-r--r--spec/ruby/core/file/fnmatch_spec.rb298
-rw-r--r--spec/ruby/core/file/ftype_spec.rb8
-rw-r--r--spec/ruby/core/file/inspect_spec.rb2
-rw-r--r--spec/ruby/core/file/join_spec.rb14
-rw-r--r--spec/ruby/core/file/link_spec.rb12
-rw-r--r--spec/ruby/core/file/mkfifo_spec.rb4
-rw-r--r--spec/ruby/core/file/mtime_spec.rb6
-rw-r--r--spec/ruby/core/file/new_spec.rb54
-rw-r--r--spec/ruby/core/file/open_spec.rb128
-rw-r--r--spec/ruby/core/file/path_spec.rb46
-rw-r--r--spec/ruby/core/file/readlink_spec.rb6
-rw-r--r--spec/ruby/core/file/realdirpath_spec.rb6
-rw-r--r--spec/ruby/core/file/realpath_spec.rb6
-rw-r--r--spec/ruby/core/file/rename_spec.rb8
-rw-r--r--spec/ruby/core/file/shared/fnmatch.rb294
-rw-r--r--spec/ruby/core/file/shared/open.rb2
-rw-r--r--spec/ruby/core/file/shared/path.rb82
-rw-r--r--spec/ruby/core/file/shared/read.rb4
-rw-r--r--spec/ruby/core/file/shared/stat.rb6
-rw-r--r--spec/ruby/core/file/shared/unlink.rb61
-rw-r--r--spec/ruby/core/file/size_spec.rb6
-rw-r--r--spec/ruby/core/file/socket_spec.rb32
-rw-r--r--spec/ruby/core/file/split_spec.rb6
-rw-r--r--spec/ruby/core/file/stat/atime_spec.rb2
-rw-r--r--spec/ruby/core/file/stat/birthtime_spec.rb4
-rw-r--r--spec/ruby/core/file/stat/blocks_spec.rb2
-rw-r--r--spec/ruby/core/file/stat/ctime_spec.rb2
-rw-r--r--spec/ruby/core/file/stat/dev_major_spec.rb4
-rw-r--r--spec/ruby/core/file/stat/dev_minor_spec.rb4
-rw-r--r--spec/ruby/core/file/stat/dev_spec.rb2
-rw-r--r--spec/ruby/core/file/stat/ftype_spec.rb2
-rw-r--r--spec/ruby/core/file/stat/ino_spec.rb4
-rw-r--r--spec/ruby/core/file/stat/mtime_spec.rb2
-rw-r--r--spec/ruby/core/file/stat/new_spec.rb4
-rw-r--r--spec/ruby/core/file/stat/rdev_major_spec.rb4
-rw-r--r--spec/ruby/core/file/stat/rdev_minor_spec.rb4
-rw-r--r--spec/ruby/core/file/stat/rdev_spec.rb2
-rw-r--r--spec/ruby/core/file/stat_spec.rb12
-rw-r--r--spec/ruby/core/file/sticky_spec.rb2
-rw-r--r--spec/ruby/core/file/symlink_spec.rb12
-rw-r--r--spec/ruby/core/file/to_path_spec.rb82
-rw-r--r--spec/ruby/core/file/truncate_spec.rb24
-rw-r--r--spec/ruby/core/file/umask_spec.rb8
-rw-r--r--spec/ruby/core/file/unlink_spec.rb5
-rw-r--r--spec/ruby/core/file/world_readable_spec.rb2
-rw-r--r--spec/ruby/core/file/world_writable_spec.rb2
-rw-r--r--spec/ruby/core/file/zero_spec.rb6
-rw-r--r--spec/ruby/core/filetest/empty_spec.rb7
-rw-r--r--spec/ruby/core/filetest/grpowned_spec.rb2
-rw-r--r--spec/ruby/core/filetest/socket_spec.rb4
-rw-r--r--spec/ruby/core/filetest/zero_spec.rb6
-rw-r--r--spec/ruby/core/float/angle_spec.rb5
-rw-r--r--spec/ruby/core/float/arg_spec.rb36
-rw-r--r--spec/ruby/core/float/case_compare_spec.rb5
-rw-r--r--spec/ruby/core/float/ceil_spec.rb28
-rw-r--r--spec/ruby/core/float/comparison_spec.rb10
-rw-r--r--spec/ruby/core/float/constants_spec.rb2
-rw-r--r--spec/ruby/core/float/denominator_spec.rb2
-rw-r--r--spec/ruby/core/float/divide_spec.rb20
-rw-r--r--spec/ruby/core/float/divmod_spec.rb22
-rw-r--r--spec/ruby/core/float/dup_spec.rb2
-rw-r--r--spec/ruby/core/float/eql_spec.rb8
-rw-r--r--spec/ruby/core/float/equal_value_spec.rb38
-rw-r--r--spec/ruby/core/float/fdiv_spec.rb59
-rw-r--r--spec/ruby/core/float/float_spec.rb4
-rw-r--r--spec/ruby/core/float/floor_spec.rb28
-rw-r--r--spec/ruby/core/float/gt_spec.rb4
-rw-r--r--spec/ruby/core/float/gte_spec.rb4
-rw-r--r--spec/ruby/core/float/inspect_spec.rb5
-rw-r--r--spec/ruby/core/float/lt_spec.rb4
-rw-r--r--spec/ruby/core/float/lte_spec.rb4
-rw-r--r--spec/ruby/core/float/magnitude_spec.rb10
-rw-r--r--spec/ruby/core/float/modulo_spec.rb52
-rw-r--r--spec/ruby/core/float/multiply_spec.rb4
-rw-r--r--spec/ruby/core/float/negative_spec.rb10
-rw-r--r--spec/ruby/core/float/next_float_spec.rb2
-rw-r--r--spec/ruby/core/float/numerator_spec.rb4
-rw-r--r--spec/ruby/core/float/phase_spec.rb5
-rw-r--r--spec/ruby/core/float/positive_spec.rb10
-rw-r--r--spec/ruby/core/float/prev_float_spec.rb2
-rw-r--r--spec/ruby/core/float/quo_spec.rb5
-rw-r--r--spec/ruby/core/float/rationalize_spec.rb8
-rw-r--r--spec/ruby/core/float/round_spec.rb223
-rw-r--r--spec/ruby/core/float/shared/abs.rb2
-rw-r--r--spec/ruby/core/float/shared/arg.rb36
-rw-r--r--spec/ruby/core/float/shared/arithmetic_exception_in_coerce.rb2
-rw-r--r--spec/ruby/core/float/shared/comparison_exception_in_coerce.rb2
-rw-r--r--spec/ruby/core/float/shared/equal.rb38
-rw-r--r--spec/ruby/core/float/shared/modulo.rb48
-rw-r--r--spec/ruby/core/float/shared/quo.rb59
-rw-r--r--spec/ruby/core/float/shared/to_i.rb14
-rw-r--r--spec/ruby/core/float/shared/to_s.rb308
-rw-r--r--spec/ruby/core/float/to_int_spec.rb5
-rw-r--r--spec/ruby/core/float/to_s_spec.rb308
-rw-r--r--spec/ruby/core/float/truncate_spec.rb10
-rw-r--r--spec/ruby/core/float/uplus_spec.rb2
-rw-r--r--spec/ruby/core/gc/config_spec.rb97
-rw-r--r--spec/ruby/core/gc/count_spec.rb2
-rw-r--r--spec/ruby/core/gc/profiler/enabled_spec.rb4
-rw-r--r--spec/ruby/core/gc/profiler/result_spec.rb2
-rw-r--r--spec/ruby/core/gc/profiler/total_time_spec.rb2
-rw-r--r--spec/ruby/core/gc/stat_spec.rb28
-rw-r--r--spec/ruby/core/gc/stress_spec.rb8
-rw-r--r--spec/ruby/core/gc/total_time_spec.rb2
-rw-r--r--spec/ruby/core/hash/allocate_spec.rb2
-rw-r--r--spec/ruby/core/hash/assoc_spec.rb8
-rw-r--r--spec/ruby/core/hash/clear_spec.rb6
-rw-r--r--spec/ruby/core/hash/clone_spec.rb2
-rw-r--r--spec/ruby/core/hash/compact_spec.rb46
-rw-r--r--spec/ruby/core/hash/compare_by_identity_spec.rb28
-rw-r--r--spec/ruby/core/hash/constructor_spec.rb57
-rw-r--r--spec/ruby/core/hash/deconstruct_keys_spec.rb4
-rw-r--r--spec/ruby/core/hash/default_proc_spec.rb20
-rw-r--r--spec/ruby/core/hash/default_spec.rb4
-rw-r--r--spec/ruby/core/hash/delete_if_spec.rb8
-rw-r--r--spec/ruby/core/hash/delete_spec.rb4
-rw-r--r--spec/ruby/core/hash/dig_spec.rb18
-rw-r--r--spec/ruby/core/hash/each_key_spec.rb2
-rw-r--r--spec/ruby/core/hash/each_pair_spec.rb106
-rw-r--r--spec/ruby/core/hash/each_spec.rb10
-rw-r--r--spec/ruby/core/hash/each_value_spec.rb2
-rw-r--r--spec/ruby/core/hash/element_reference_spec.rb2
-rw-r--r--spec/ruby/core/hash/element_set_spec.rb118
-rw-r--r--spec/ruby/core/hash/equal_value_spec.rb2
-rw-r--r--spec/ruby/core/hash/except_spec.rb30
-rw-r--r--spec/ruby/core/hash/fetch_spec.rb6
-rw-r--r--spec/ruby/core/hash/filter_spec.rb9
-rw-r--r--spec/ruby/core/hash/flatten_spec.rb4
-rw-r--r--spec/ruby/core/hash/gt_spec.rb2
-rw-r--r--spec/ruby/core/hash/gte_spec.rb2
-rw-r--r--spec/ruby/core/hash/has_key_spec.rb6
-rw-r--r--spec/ruby/core/hash/has_value_spec.rb6
-rw-r--r--spec/ruby/core/hash/include_spec.rb39
-rw-r--r--spec/ruby/core/hash/initialize_spec.rb12
-rw-r--r--spec/ruby/core/hash/inspect_spec.rb122
-rw-r--r--spec/ruby/core/hash/invert_spec.rb21
-rw-r--r--spec/ruby/core/hash/keep_if_spec.rb10
-rw-r--r--spec/ruby/core/hash/key_spec.rb30
-rw-r--r--spec/ruby/core/hash/keys_spec.rb4
-rw-r--r--spec/ruby/core/hash/length_spec.rb6
-rw-r--r--spec/ruby/core/hash/lt_spec.rb2
-rw-r--r--spec/ruby/core/hash/lte_spec.rb2
-rw-r--r--spec/ruby/core/hash/member_spec.rb6
-rw-r--r--spec/ruby/core/hash/merge_spec.rb110
-rw-r--r--spec/ruby/core/hash/new_spec.rb23
-rw-r--r--spec/ruby/core/hash/rassoc_spec.rb10
-rw-r--r--spec/ruby/core/hash/rehash_spec.rb6
-rw-r--r--spec/ruby/core/hash/reject_spec.rb31
-rw-r--r--spec/ruby/core/hash/replace_spec.rb59
-rw-r--r--spec/ruby/core/hash/ruby2_keywords_hash_spec.rb16
-rw-r--r--spec/ruby/core/hash/select_spec.rb108
-rw-r--r--spec/ruby/core/hash/shared/comparison.rb10
-rw-r--r--spec/ruby/core/hash/shared/each.rb105
-rw-r--r--spec/ruby/core/hash/shared/eql.rb88
-rw-r--r--spec/ruby/core/hash/shared/greater_than.rb6
-rw-r--r--spec/ruby/core/hash/shared/index.rb37
-rw-r--r--spec/ruby/core/hash/shared/iteration.rb6
-rw-r--r--spec/ruby/core/hash/shared/key.rb38
-rw-r--r--spec/ruby/core/hash/shared/length.rb12
-rw-r--r--spec/ruby/core/hash/shared/less_than.rb6
-rw-r--r--spec/ruby/core/hash/shared/select.rb91
-rw-r--r--spec/ruby/core/hash/shared/store.rb115
-rw-r--r--spec/ruby/core/hash/shared/to_s.rb93
-rw-r--r--spec/ruby/core/hash/shared/update.rb76
-rw-r--r--spec/ruby/core/hash/shared/value.rb14
-rw-r--r--spec/ruby/core/hash/shared/values_at.rb9
-rw-r--r--spec/ruby/core/hash/shift_spec.rb6
-rw-r--r--spec/ruby/core/hash/size_spec.rb13
-rw-r--r--spec/ruby/core/hash/slice_spec.rb25
-rw-r--r--spec/ruby/core/hash/store_spec.rb6
-rw-r--r--spec/ruby/core/hash/to_a_spec.rb4
-rw-r--r--spec/ruby/core/hash/to_h_spec.rb40
-rw-r--r--spec/ruby/core/hash/to_hash_spec.rb4
-rw-r--r--spec/ruby/core/hash/to_proc_spec.rb16
-rw-r--r--spec/ruby/core/hash/to_s_spec.rb6
-rw-r--r--spec/ruby/core/hash/transform_keys_spec.rb41
-rw-r--r--spec/ruby/core/hash/transform_values_spec.rb39
-rw-r--r--spec/ruby/core/hash/try_convert_spec.rb16
-rw-r--r--spec/ruby/core/hash/update_spec.rb6
-rw-r--r--spec/ruby/core/hash/value_spec.rb15
-rw-r--r--spec/ruby/core/hash/values_at_spec.rb10
-rw-r--r--spec/ruby/core/hash/values_spec.rb2
-rw-r--r--spec/ruby/core/integer/abs_spec.rb18
-rw-r--r--spec/ruby/core/integer/allbits_spec.rb6
-rw-r--r--spec/ruby/core/integer/anybits_spec.rb6
-rw-r--r--spec/ruby/core/integer/bit_and_spec.rb8
-rw-r--r--spec/ruby/core/integer/bit_or_spec.rb10
-rw-r--r--spec/ruby/core/integer/bit_xor_spec.rb10
-rw-r--r--spec/ruby/core/integer/case_compare_spec.rb5
-rw-r--r--spec/ruby/core/integer/ceil_spec.rb11
-rw-r--r--spec/ruby/core/integer/ceildiv_spec.rb22
-rw-r--r--spec/ruby/core/integer/chr_spec.rb62
-rw-r--r--spec/ruby/core/integer/coerce_spec.rb28
-rw-r--r--spec/ruby/core/integer/comparison_spec.rb14
-rw-r--r--spec/ruby/core/integer/digits_spec.rb6
-rw-r--r--spec/ruby/core/integer/div_spec.rb40
-rw-r--r--spec/ruby/core/integer/divide_spec.rb16
-rw-r--r--spec/ruby/core/integer/divmod_spec.rb34
-rw-r--r--spec/ruby/core/integer/downto_spec.rb8
-rw-r--r--spec/ruby/core/integer/dup_spec.rb4
-rw-r--r--spec/ruby/core/integer/element_reference_spec.rb14
-rw-r--r--spec/ruby/core/integer/eql_spec.rb25
-rw-r--r--spec/ruby/core/integer/equal_value_spec.rb63
-rw-r--r--spec/ruby/core/integer/even_spec.rb26
-rw-r--r--spec/ruby/core/integer/fdiv_spec.rb8
-rw-r--r--spec/ruby/core/integer/fixtures/classes.rb10
-rw-r--r--spec/ruby/core/integer/gcd_spec.rb16
-rw-r--r--spec/ruby/core/integer/gcdlcm_spec.rb16
-rw-r--r--spec/ruby/core/integer/gt_spec.rb13
-rw-r--r--spec/ruby/core/integer/gte_spec.rb13
-rw-r--r--spec/ruby/core/integer/inspect_spec.rb7
-rw-r--r--spec/ruby/core/integer/integer_spec.rb4
-rw-r--r--spec/ruby/core/integer/lcm_spec.rb16
-rw-r--r--spec/ruby/core/integer/left_shift_spec.rb28
-rw-r--r--spec/ruby/core/integer/lt_spec.rb13
-rw-r--r--spec/ruby/core/integer/lte_spec.rb13
-rw-r--r--spec/ruby/core/integer/magnitude_spec.rb5
-rw-r--r--spec/ruby/core/integer/minus_spec.rb12
-rw-r--r--spec/ruby/core/integer/modulo_spec.rb118
-rw-r--r--spec/ruby/core/integer/multiply_spec.rb12
-rw-r--r--spec/ruby/core/integer/next_spec.rb5
-rw-r--r--spec/ruby/core/integer/nobits_spec.rb6
-rw-r--r--spec/ruby/core/integer/odd_spec.rb26
-rw-r--r--spec/ruby/core/integer/ord_spec.rb16
-rw-r--r--spec/ruby/core/integer/plus_spec.rb12
-rw-r--r--spec/ruby/core/integer/pow_spec.rb22
-rw-r--r--spec/ruby/core/integer/pred_spec.rb10
-rw-r--r--spec/ruby/core/integer/rationalize_spec.rb6
-rw-r--r--spec/ruby/core/integer/remainder_spec.rb14
-rw-r--r--spec/ruby/core/integer/right_shift_spec.rb28
-rw-r--r--spec/ruby/core/integer/round_spec.rb62
-rw-r--r--spec/ruby/core/integer/shared/abs.rb18
-rw-r--r--spec/ruby/core/integer/shared/arithmetic_coerce.rb2
-rw-r--r--spec/ruby/core/integer/shared/comparison_coerce.rb2
-rw-r--r--spec/ruby/core/integer/shared/equal.rb58
-rw-r--r--spec/ruby/core/integer/shared/exponent.rb100
-rw-r--r--spec/ruby/core/integer/shared/integer_ceil_precision.rb25
-rw-r--r--spec/ruby/core/integer/shared/integer_floor_precision.rb9
-rw-r--r--spec/ruby/core/integer/shared/integer_rounding.rb6
-rw-r--r--spec/ruby/core/integer/shared/modulo.rb74
-rw-r--r--spec/ruby/core/integer/shared/next.rb25
-rw-r--r--spec/ruby/core/integer/shared/to_i.rb8
-rw-r--r--spec/ruby/core/integer/sqrt_spec.rb6
-rw-r--r--spec/ruby/core/integer/succ_spec.rb25
-rw-r--r--spec/ruby/core/integer/to_f_spec.rb6
-rw-r--r--spec/ruby/core/integer/to_r_spec.rb8
-rw-r--r--spec/ruby/core/integer/to_s_spec.rb24
-rw-r--r--spec/ruby/core/integer/truncate_spec.rb12
-rw-r--r--spec/ruby/core/integer/try_convert_spec.rb14
-rw-r--r--spec/ruby/core/integer/upto_spec.rb8
-rw-r--r--spec/ruby/core/io/advise_spec.rb28
-rw-r--r--spec/ruby/core/io/autoclose_spec.rb4
-rw-r--r--spec/ruby/core/io/binmode_spec.rb10
-rw-r--r--spec/ruby/core/io/binread_spec.rb6
-rw-r--r--spec/ruby/core/io/buffer/and_spec.rb62
-rw-r--r--spec/ruby/core/io/buffer/bit_count_spec.rb64
-rw-r--r--spec/ruby/core/io/buffer/empty_spec.rb27
-rw-r--r--spec/ruby/core/io/buffer/external_spec.rb23
-rw-r--r--spec/ruby/core/io/buffer/for_spec.rb95
-rw-r--r--spec/ruby/core/io/buffer/free_spec.rb102
-rw-r--r--spec/ruby/core/io/buffer/initialize_spec.rb119
-rw-r--r--spec/ruby/core/io/buffer/internal_spec.rb23
-rw-r--r--spec/ruby/core/io/buffer/locked_spec.rb75
-rw-r--r--spec/ruby/core/io/buffer/map_spec.rb347
-rw-r--r--spec/ruby/core/io/buffer/mapped_spec.rb23
-rw-r--r--spec/ruby/core/io/buffer/not_spec.rb37
-rw-r--r--spec/ruby/core/io/buffer/null_spec.rb27
-rw-r--r--spec/ruby/core/io/buffer/or_spec.rb62
-rw-r--r--spec/ruby/core/io/buffer/private_spec.rb23
-rw-r--r--spec/ruby/core/io/buffer/readonly_spec.rb28
-rw-r--r--spec/ruby/core/io/buffer/resize_spec.rb151
-rw-r--r--spec/ruby/core/io/buffer/shared/null_and_empty.rb57
-rw-r--r--spec/ruby/core/io/buffer/shared_spec.rb33
-rw-r--r--spec/ruby/core/io/buffer/string_spec.rb62
-rw-r--r--spec/ruby/core/io/buffer/transfer_spec.rb117
-rw-r--r--spec/ruby/core/io/buffer/valid_spec.rb99
-rw-r--r--spec/ruby/core/io/buffer/xor_spec.rb62
-rw-r--r--spec/ruby/core/io/close_on_exec_spec.rb4
-rw-r--r--spec/ruby/core/io/close_read_spec.rb10
-rw-r--r--spec/ruby/core/io/close_spec.rb12
-rw-r--r--spec/ruby/core/io/close_write_spec.rb10
-rw-r--r--spec/ruby/core/io/closed_spec.rb4
-rw-r--r--spec/ruby/core/io/copy_stream_spec.rb24
-rw-r--r--spec/ruby/core/io/dup_spec.rb6
-rw-r--r--spec/ruby/core/io/each_byte_spec.rb6
-rw-r--r--spec/ruby/core/io/each_char_spec.rb71
-rw-r--r--spec/ruby/core/io/each_codepoint_spec.rb55
-rw-r--r--spec/ruby/core/io/each_line_spec.rb246
-rw-r--r--spec/ruby/core/io/each_spec.rb10
-rw-r--r--spec/ruby/core/io/eof_spec.rb12
-rw-r--r--spec/ruby/core/io/external_encoding_spec.rb46
-rw-r--r--spec/ruby/core/io/fcntl_spec.rb2
-rw-r--r--spec/ruby/core/io/fileno_spec.rb2
-rw-r--r--spec/ruby/core/io/flush_spec.rb6
-rw-r--r--spec/ruby/core/io/foreach_spec.rb64
-rw-r--r--spec/ruby/core/io/fsync_spec.rb2
-rw-r--r--spec/ruby/core/io/getbyte_spec.rb4
-rw-r--r--spec/ruby/core/io/getc_spec.rb6
-rw-r--r--spec/ruby/core/io/gets_spec.rb38
-rw-r--r--spec/ruby/core/io/initialize_spec.rb12
-rw-r--r--spec/ruby/core/io/inspect_spec.rb4
-rw-r--r--spec/ruby/core/io/internal_encoding_spec.rb28
-rw-r--r--spec/ruby/core/io/ioctl_spec.rb6
-rw-r--r--spec/ruby/core/io/isatty_spec.rb5
-rw-r--r--spec/ruby/core/io/lineno_spec.rb18
-rw-r--r--spec/ruby/core/io/open_spec.rb8
-rw-r--r--spec/ruby/core/io/output_spec.rb2
-rw-r--r--spec/ruby/core/io/pid_spec.rb4
-rw-r--r--spec/ruby/core/io/pipe_spec.rb32
-rw-r--r--spec/ruby/core/io/popen_spec.rb18
-rw-r--r--spec/ruby/core/io/pos_spec.rb32
-rw-r--r--spec/ruby/core/io/pread_spec.rb216
-rw-r--r--spec/ruby/core/io/print_spec.rb4
-rw-r--r--spec/ruby/core/io/printf_spec.rb2
-rw-r--r--spec/ruby/core/io/puts_spec.rb2
-rw-r--r--spec/ruby/core/io/pwrite_spec.rb104
-rw-r--r--spec/ruby/core/io/read_nonblock_spec.rb22
-rw-r--r--spec/ruby/core/io/read_spec.rb182
-rw-r--r--spec/ruby/core/io/readbyte_spec.rb2
-rw-r--r--spec/ruby/core/io/readchar_spec.rb10
-rw-r--r--spec/ruby/core/io/readline_spec.rb10
-rw-r--r--spec/ruby/core/io/readlines_spec.rb76
-rw-r--r--spec/ruby/core/io/readpartial_spec.rb19
-rw-r--r--spec/ruby/core/io/reopen_spec.rb26
-rw-r--r--spec/ruby/core/io/rewind_spec.rb2
-rw-r--r--spec/ruby/core/io/seek_spec.rb2
-rw-r--r--spec/ruby/core/io/select_spec.rb62
-rw-r--r--spec/ruby/core/io/set_encoding_by_bom_spec.rb10
-rw-r--r--spec/ruby/core/io/set_encoding_spec.rb42
-rw-r--r--spec/ruby/core/io/shared/binwrite.rb4
-rw-r--r--spec/ruby/core/io/shared/chars.rb73
-rw-r--r--spec/ruby/core/io/shared/codepoints.rb54
-rw-r--r--spec/ruby/core/io/shared/each.rb251
-rw-r--r--spec/ruby/core/io/shared/new.rb79
-rw-r--r--spec/ruby/core/io/shared/pos.rb40
-rw-r--r--spec/ruby/core/io/shared/readlines.rb30
-rw-r--r--spec/ruby/core/io/shared/tty.rb24
-rw-r--r--spec/ruby/core/io/shared/write.rb8
-rw-r--r--spec/ruby/core/io/stat_spec.rb6
-rw-r--r--spec/ruby/core/io/sync_spec.rb4
-rw-r--r--spec/ruby/core/io/sysopen_spec.rb16
-rw-r--r--spec/ruby/core/io/sysread_spec.rb14
-rw-r--r--spec/ruby/core/io/sysseek_spec.rb4
-rw-r--r--spec/ruby/core/io/tell_spec.rb6
-rw-r--r--spec/ruby/core/io/to_i_spec.rb9
-rw-r--r--spec/ruby/core/io/to_io_spec.rb4
-rw-r--r--spec/ruby/core/io/to_path_spec.rb7
-rw-r--r--spec/ruby/core/io/try_convert_spec.rb12
-rw-r--r--spec/ruby/core/io/tty_spec.rb23
-rw-r--r--spec/ruby/core/io/ungetbyte_spec.rb12
-rw-r--r--spec/ruby/core/io/ungetc_spec.rb14
-rw-r--r--spec/ruby/core/io/write_nonblock_spec.rb8
-rw-r--r--spec/ruby/core/io/write_spec.rb21
-rw-r--r--spec/ruby/core/kernel/Array_spec.rb6
-rw-r--r--spec/ruby/core/kernel/Complex_spec.rb60
-rw-r--r--spec/ruby/core/kernel/Float_spec.rb136
-rw-r--r--spec/ruby/core/kernel/Hash_spec.rb6
-rw-r--r--spec/ruby/core/kernel/Integer_spec.rb254
-rw-r--r--spec/ruby/core/kernel/Rational_spec.rb118
-rw-r--r--spec/ruby/core/kernel/String_spec.rb14
-rw-r--r--spec/ruby/core/kernel/abort_spec.rb2
-rw-r--r--spec/ruby/core/kernel/at_exit_spec.rb4
-rw-r--r--spec/ruby/core/kernel/autoload_relative_spec.rb114
-rw-r--r--spec/ruby/core/kernel/autoload_spec.rb19
-rw-r--r--spec/ruby/core/kernel/backtick_spec.rb14
-rw-r--r--spec/ruby/core/kernel/binding_spec.rb4
-rw-r--r--spec/ruby/core/kernel/block_given_spec.rb2
-rw-r--r--spec/ruby/core/kernel/caller_locations_spec.rb11
-rw-r--r--spec/ruby/core/kernel/caller_spec.rb24
-rw-r--r--spec/ruby/core/kernel/case_compare_spec.rb14
-rw-r--r--spec/ruby/core/kernel/catch_spec.rb10
-rw-r--r--spec/ruby/core/kernel/chomp_spec.rb2
-rw-r--r--spec/ruby/core/kernel/chop_spec.rb2
-rw-r--r--spec/ruby/core/kernel/class_spec.rb20
-rw-r--r--spec/ruby/core/kernel/clone_spec.rb22
-rw-r--r--spec/ruby/core/kernel/comparison_spec.rb6
-rw-r--r--spec/ruby/core/kernel/define_singleton_method_spec.rb20
-rw-r--r--spec/ruby/core/kernel/dup_spec.rb14
-rw-r--r--spec/ruby/core/kernel/enum_for_spec.rb4
-rw-r--r--spec/ruby/core/kernel/eql_spec.rb2
-rw-r--r--spec/ruby/core/kernel/eval_spec.rb80
-rw-r--r--spec/ruby/core/kernel/exec_spec.rb2
-rw-r--r--spec/ruby/core/kernel/exit_spec.rb4
-rw-r--r--spec/ruby/core/kernel/extend_spec.rb8
-rw-r--r--spec/ruby/core/kernel/fail_spec.rb39
-rw-r--r--spec/ruby/core/kernel/fixtures/autoload_relative_b.rb7
-rw-r--r--spec/ruby/core/kernel/fixtures/autoload_relative_d.rb5
-rw-r--r--spec/ruby/core/kernel/fixtures/classes.rb19
-rw-r--r--spec/ruby/core/kernel/fork_spec.rb2
-rw-r--r--spec/ruby/core/kernel/format_spec.rb42
-rw-r--r--spec/ruby/core/kernel/freeze_spec.rb28
-rw-r--r--spec/ruby/core/kernel/frozen_spec.rb22
-rw-r--r--spec/ruby/core/kernel/gets_spec.rb2
-rw-r--r--spec/ruby/core/kernel/global_variables_spec.rb6
-rw-r--r--spec/ruby/core/kernel/gsub_spec.rb8
-rw-r--r--spec/ruby/core/kernel/initialize_clone_spec.rb2
-rw-r--r--spec/ruby/core/kernel/initialize_copy_spec.rb12
-rw-r--r--spec/ruby/core/kernel/initialize_dup_spec.rb2
-rw-r--r--spec/ruby/core/kernel/inspect_spec.rb48
-rw-r--r--spec/ruby/core/kernel/instance_of_spec.rb6
-rw-r--r--spec/ruby/core/kernel/instance_variable_defined_spec.rb12
-rw-r--r--spec/ruby/core/kernel/instance_variable_get_spec.rb28
-rw-r--r--spec/ruby/core/kernel/instance_variable_set_spec.rb28
-rw-r--r--spec/ruby/core/kernel/instance_variables_spec.rb2
-rw-r--r--spec/ruby/core/kernel/is_a_spec.rb54
-rw-r--r--spec/ruby/core/kernel/itself_spec.rb2
-rw-r--r--spec/ruby/core/kernel/kind_of_spec.rb5
-rw-r--r--spec/ruby/core/kernel/lambda_spec.rb82
-rw-r--r--spec/ruby/core/kernel/load_spec.rb2
-rw-r--r--spec/ruby/core/kernel/local_variables_spec.rb11
-rw-r--r--spec/ruby/core/kernel/loop_spec.rb6
-rw-r--r--spec/ruby/core/kernel/method_spec.rb22
-rw-r--r--spec/ruby/core/kernel/methods_spec.rb34
-rw-r--r--spec/ruby/core/kernel/not_match_spec.rb2
-rw-r--r--spec/ruby/core/kernel/open_spec.rb98
-rw-r--r--spec/ruby/core/kernel/p_spec.rb2
-rw-r--r--spec/ruby/core/kernel/print_spec.rb2
-rw-r--r--spec/ruby/core/kernel/printf_spec.rb2
-rw-r--r--spec/ruby/core/kernel/private_methods_spec.rb10
-rw-r--r--spec/ruby/core/kernel/proc_spec.rb14
-rw-r--r--spec/ruby/core/kernel/protected_methods_spec.rb10
-rw-r--r--spec/ruby/core/kernel/public_method_spec.rb6
-rw-r--r--spec/ruby/core/kernel/public_methods_spec.rb19
-rw-r--r--spec/ruby/core/kernel/public_send_spec.rb16
-rw-r--r--spec/ruby/core/kernel/putc_spec.rb2
-rw-r--r--spec/ruby/core/kernel/puts_spec.rb2
-rw-r--r--spec/ruby/core/kernel/raise_spec.rb108
-rw-r--r--spec/ruby/core/kernel/rand_spec.rb94
-rw-r--r--spec/ruby/core/kernel/readline_spec.rb2
-rw-r--r--spec/ruby/core/kernel/readlines_spec.rb2
-rw-r--r--spec/ruby/core/kernel/remove_instance_variable_spec.rb20
-rw-r--r--spec/ruby/core/kernel/require_relative_spec.rb140
-rw-r--r--spec/ruby/core/kernel/require_spec.rb44
-rw-r--r--spec/ruby/core/kernel/respond_to_missing_spec.rb20
-rw-r--r--spec/ruby/core/kernel/respond_to_spec.rb33
-rw-r--r--spec/ruby/core/kernel/select_spec.rb2
-rw-r--r--spec/ruby/core/kernel/set_trace_func_spec.rb2
-rw-r--r--spec/ruby/core/kernel/shared/dup_clone.rb8
-rw-r--r--spec/ruby/core/kernel/shared/kind_of.rb55
-rw-r--r--spec/ruby/core/kernel/shared/lambda.rb2
-rw-r--r--spec/ruby/core/kernel/shared/load.rb54
-rw-r--r--spec/ruby/core/kernel/shared/method.rb12
-rw-r--r--spec/ruby/core/kernel/shared/require.rb224
-rw-r--r--spec/ruby/core/kernel/shared/sprintf.rb124
-rw-r--r--spec/ruby/core/kernel/shared/sprintf_encoding.rb12
-rw-r--r--spec/ruby/core/kernel/shared/then.rb12
-rw-r--r--spec/ruby/core/kernel/singleton_class_spec.rb14
-rw-r--r--spec/ruby/core/kernel/singleton_method_spec.rb52
-rw-r--r--spec/ruby/core/kernel/singleton_methods_spec.rb65
-rw-r--r--spec/ruby/core/kernel/sleep_spec.rb65
-rw-r--r--spec/ruby/core/kernel/spawn_spec.rb2
-rw-r--r--spec/ruby/core/kernel/sprintf_spec.rb36
-rw-r--r--spec/ruby/core/kernel/srand_spec.rb8
-rw-r--r--spec/ruby/core/kernel/sub_spec.rb4
-rw-r--r--spec/ruby/core/kernel/syscall_spec.rb2
-rw-r--r--spec/ruby/core/kernel/system_spec.rb18
-rw-r--r--spec/ruby/core/kernel/tap_spec.rb4
-rw-r--r--spec/ruby/core/kernel/test_spec.rb12
-rw-r--r--spec/ruby/core/kernel/then_spec.rb10
-rw-r--r--spec/ruby/core/kernel/throw_spec.rb14
-rw-r--r--spec/ruby/core/kernel/to_enum_spec.rb56
-rw-r--r--spec/ruby/core/kernel/trace_var_spec.rb4
-rw-r--r--spec/ruby/core/kernel/trap_spec.rb2
-rw-r--r--spec/ruby/core/kernel/untrace_var_spec.rb2
-rw-r--r--spec/ruby/core/kernel/warn_spec.rb24
-rw-r--r--spec/ruby/core/main/define_method_spec.rb6
-rw-r--r--spec/ruby/core/main/include_spec.rb4
-rw-r--r--spec/ruby/core/main/private_spec.rb14
-rw-r--r--spec/ruby/core/main/public_spec.rb14
-rw-r--r--spec/ruby/core/main/ruby2_keywords_spec.rb2
-rw-r--r--spec/ruby/core/main/using_spec.rb14
-rw-r--r--spec/ruby/core/marshal/dump_spec.rb92
-rw-r--r--spec/ruby/core/marshal/float_spec.rb2
-rw-r--r--spec/ruby/core/marshal/load_spec.rb1289
-rw-r--r--spec/ruby/core/marshal/restore_spec.rb5
-rw-r--r--spec/ruby/core/marshal/shared/load.rb1270
-rw-r--r--spec/ruby/core/matchdata/allocate_spec.rb2
-rw-r--r--spec/ruby/core/matchdata/begin_spec.rb10
-rw-r--r--spec/ruby/core/matchdata/bytebegin_spec.rb132
-rw-r--r--spec/ruby/core/matchdata/byteend_spec.rb104
-rw-r--r--spec/ruby/core/matchdata/byteoffset_spec.rb10
-rw-r--r--spec/ruby/core/matchdata/captures_spec.rb11
-rw-r--r--spec/ruby/core/matchdata/deconstruct_keys_spec.rb27
-rw-r--r--spec/ruby/core/matchdata/deconstruct_spec.rb5
-rw-r--r--spec/ruby/core/matchdata/element_reference_spec.rb6
-rw-r--r--spec/ruby/core/matchdata/end_spec.rb2
-rw-r--r--spec/ruby/core/matchdata/eql_spec.rb5
-rw-r--r--spec/ruby/core/matchdata/equal_value_spec.rb24
-rw-r--r--spec/ruby/core/matchdata/inspect_spec.rb2
-rw-r--r--spec/ruby/core/matchdata/integer_at_spec.rb38
-rw-r--r--spec/ruby/core/matchdata/length_spec.rb5
-rw-r--r--spec/ruby/core/matchdata/named_captures_spec.rb16
-rw-r--r--spec/ruby/core/matchdata/names_spec.rb4
-rw-r--r--spec/ruby/core/matchdata/offset_spec.rb106
-rw-r--r--spec/ruby/core/matchdata/post_match_spec.rb6
-rw-r--r--spec/ruby/core/matchdata/pre_match_spec.rb6
-rw-r--r--spec/ruby/core/matchdata/regexp_spec.rb2
-rw-r--r--spec/ruby/core/matchdata/shared/captures.rb13
-rw-r--r--spec/ruby/core/matchdata/shared/eql.rb26
-rw-r--r--spec/ruby/core/matchdata/shared/length.rb5
-rw-r--r--spec/ruby/core/matchdata/size_spec.rb5
-rw-r--r--spec/ruby/core/matchdata/string_spec.rb2
-rw-r--r--spec/ruby/core/matchdata/to_a_spec.rb2
-rw-r--r--spec/ruby/core/matchdata/to_s_spec.rb2
-rw-r--r--spec/ruby/core/matchdata/values_at_spec.rb4
-rw-r--r--spec/ruby/core/math/acos_spec.rb14
-rw-r--r--spec/ruby/core/math/acosh_spec.rb14
-rw-r--r--spec/ruby/core/math/asin_spec.rb12
-rw-r--r--spec/ruby/core/math/asinh_spec.rb8
-rw-r--r--spec/ruby/core/math/atan2_spec.rb14
-rw-r--r--spec/ruby/core/math/atan_spec.rb8
-rw-r--r--spec/ruby/core/math/cbrt_spec.rb6
-rw-r--r--spec/ruby/core/math/cos_spec.rb12
-rw-r--r--spec/ruby/core/math/cosh_spec.rb8
-rw-r--r--spec/ruby/core/math/erf_spec.rb8
-rw-r--r--spec/ruby/core/math/erfc_spec.rb8
-rw-r--r--spec/ruby/core/math/exp_spec.rb8
-rw-r--r--spec/ruby/core/math/expm1_spec.rb37
-rw-r--r--spec/ruby/core/math/frexp_spec.rb6
-rw-r--r--spec/ruby/core/math/gamma_spec.rb6
-rw-r--r--spec/ruby/core/math/hypot_spec.rb12
-rw-r--r--spec/ruby/core/math/ldexp_spec.rb14
-rw-r--r--spec/ruby/core/math/lgamma_spec.rb13
-rw-r--r--spec/ruby/core/math/log10_spec.rb14
-rw-r--r--spec/ruby/core/math/log1p_spec.rb49
-rw-r--r--spec/ruby/core/math/log2_spec.rb10
-rw-r--r--spec/ruby/core/math/log_spec.rb16
-rw-r--r--spec/ruby/core/math/shared/atanh.rb12
-rw-r--r--spec/ruby/core/math/sin_spec.rb8
-rw-r--r--spec/ruby/core/math/sinh_spec.rb8
-rw-r--r--spec/ruby/core/math/sqrt_spec.rb10
-rw-r--r--spec/ruby/core/math/tan_spec.rb8
-rw-r--r--spec/ruby/core/math/tanh_spec.rb8
-rw-r--r--spec/ruby/core/method/call_spec.rb51
-rw-r--r--spec/ruby/core/method/case_compare_spec.rb6
-rw-r--r--spec/ruby/core/method/curry_spec.rb18
-rw-r--r--spec/ruby/core/method/element_reference_spec.rb6
-rw-r--r--spec/ruby/core/method/eql_spec.rb5
-rw-r--r--spec/ruby/core/method/equal_value_spec.rb92
-rw-r--r--spec/ruby/core/method/fixtures/classes.rb1
-rw-r--r--spec/ruby/core/method/inspect_spec.rb5
-rw-r--r--spec/ruby/core/method/original_name_spec.rb37
-rw-r--r--spec/ruby/core/method/parameters_spec.rb15
-rw-r--r--spec/ruby/core/method/receiver_spec.rb8
-rw-r--r--spec/ruby/core/method/shared/aliased_inspect.rb31
-rw-r--r--spec/ruby/core/method/shared/call.rb51
-rw-r--r--spec/ruby/core/method/shared/dup.rb2
-rw-r--r--spec/ruby/core/method/shared/eql.rb94
-rw-r--r--spec/ruby/core/method/shared/to_s.rb4
-rw-r--r--spec/ruby/core/method/source_location_spec.rb28
-rw-r--r--spec/ruby/core/method/to_s_spec.rb2
-rw-r--r--spec/ruby/core/method/unbind_spec.rb2
-rw-r--r--spec/ruby/core/module/alias_method_spec.rb48
-rw-r--r--spec/ruby/core/module/ancestors_spec.rb20
-rw-r--r--spec/ruby/core/module/append_features_spec.rb14
-rw-r--r--spec/ruby/core/module/attr_accessor_spec.rb16
-rw-r--r--spec/ruby/core/module/attr_reader_spec.rb10
-rw-r--r--spec/ruby/core/module/attr_spec.rb14
-rw-r--r--spec/ruby/core/module/attr_writer_spec.rb12
-rw-r--r--spec/ruby/core/module/autoload_relative_spec.rb128
-rw-r--r--spec/ruby/core/module/autoload_spec.rb141
-rw-r--r--spec/ruby/core/module/class_eval_spec.rb6
-rw-r--r--spec/ruby/core/module/class_exec_spec.rb6
-rw-r--r--spec/ruby/core/module/class_variable_defined_spec.rb12
-rw-r--r--spec/ruby/core/module/class_variable_get_spec.rb16
-rw-r--r--spec/ruby/core/module/class_variable_set_spec.rb12
-rw-r--r--spec/ruby/core/module/class_variables_spec.rb8
-rw-r--r--spec/ruby/core/module/const_added_spec.rb4
-rw-r--r--spec/ruby/core/module/const_defined_spec.rb62
-rw-r--r--spec/ruby/core/module/const_get_spec.rb46
-rw-r--r--spec/ruby/core/module/const_missing_spec.rb2
-rw-r--r--spec/ruby/core/module/const_set_spec.rb24
-rw-r--r--spec/ruby/core/module/const_source_location_spec.rb34
-rw-r--r--spec/ruby/core/module/constants_spec.rb7
-rw-r--r--spec/ruby/core/module/define_method_spec.rb114
-rw-r--r--spec/ruby/core/module/deprecate_constant_spec.rb8
-rw-r--r--spec/ruby/core/module/extend_object_spec.rb10
-rw-r--r--spec/ruby/core/module/extended_spec.rb2
-rw-r--r--spec/ruby/core/module/fixtures/autoload_relative_a.rb9
-rw-r--r--spec/ruby/core/module/fixtures/classes.rb2
-rw-r--r--spec/ruby/core/module/gt_spec.rb10
-rw-r--r--spec/ruby/core/module/gte_spec.rb2
-rw-r--r--spec/ruby/core/module/include_spec.rb36
-rw-r--r--spec/ruby/core/module/included_modules_spec.rb8
-rw-r--r--spec/ruby/core/module/included_spec.rb2
-rw-r--r--spec/ruby/core/module/inspect_spec.rb7
-rw-r--r--spec/ruby/core/module/instance_method_spec.rb32
-rw-r--r--spec/ruby/core/module/instance_methods_spec.rb30
-rw-r--r--spec/ruby/core/module/lt_spec.rb10
-rw-r--r--spec/ruby/core/module/lte_spec.rb2
-rw-r--r--spec/ruby/core/module/method_added_spec.rb4
-rw-r--r--spec/ruby/core/module/method_defined_spec.rb6
-rw-r--r--spec/ruby/core/module/method_removed_spec.rb2
-rw-r--r--spec/ruby/core/module/method_undefined_spec.rb2
-rw-r--r--spec/ruby/core/module/module_eval_spec.rb172
-rw-r--r--spec/ruby/core/module/module_exec_spec.rb35
-rw-r--r--spec/ruby/core/module/module_function_spec.rb22
-rw-r--r--spec/ruby/core/module/name_spec.rb13
-rw-r--r--spec/ruby/core/module/new_spec.rb2
-rw-r--r--spec/ruby/core/module/prepend_features_spec.rb8
-rw-r--r--spec/ruby/core/module/prepend_spec.rb34
-rw-r--r--spec/ruby/core/module/prepended_spec.rb2
-rw-r--r--spec/ruby/core/module/private_class_method_spec.rb22
-rw-r--r--spec/ruby/core/module/private_constant_spec.rb8
-rw-r--r--spec/ruby/core/module/private_instance_methods_spec.rb18
-rw-r--r--spec/ruby/core/module/private_method_defined_spec.rb10
-rw-r--r--spec/ruby/core/module/private_spec.rb18
-rw-r--r--spec/ruby/core/module/protected_instance_methods_spec.rb12
-rw-r--r--spec/ruby/core/module/protected_method_defined_spec.rb10
-rw-r--r--spec/ruby/core/module/protected_spec.rb16
-rw-r--r--spec/ruby/core/module/public_class_method_spec.rb14
-rw-r--r--spec/ruby/core/module/public_constant_spec.rb2
-rw-r--r--spec/ruby/core/module/public_instance_method_spec.rb20
-rw-r--r--spec/ruby/core/module/public_instance_methods_spec.rb14
-rw-r--r--spec/ruby/core/module/public_method_defined_spec.rb10
-rw-r--r--spec/ruby/core/module/public_spec.rb14
-rw-r--r--spec/ruby/core/module/refine_spec.rb31
-rw-r--r--spec/ruby/core/module/remove_class_variable_spec.rb12
-rw-r--r--spec/ruby/core/module/remove_const_spec.rb30
-rw-r--r--spec/ruby/core/module/remove_method_spec.rb16
-rw-r--r--spec/ruby/core/module/ruby2_keywords_spec.rb6
-rw-r--r--spec/ruby/core/module/set_temporary_name_spec.rb217
-rw-r--r--spec/ruby/core/module/shared/class_eval.rb174
-rw-r--r--spec/ruby/core/module/shared/class_exec.rb29
-rw-r--r--spec/ruby/core/module/shared/set_visibility.rb36
-rw-r--r--spec/ruby/core/module/undef_method_spec.rb32
-rw-r--r--spec/ruby/core/module/undefined_instance_methods_spec.rb7
-rw-r--r--spec/ruby/core/module/using_spec.rb12
-rw-r--r--spec/ruby/core/mutex/lock_spec.rb66
-rw-r--r--spec/ruby/core/mutex/locked_spec.rb8
-rw-r--r--spec/ruby/core/mutex/owned_spec.rb6
-rw-r--r--spec/ruby/core/mutex/sleep_spec.rb28
-rw-r--r--spec/ruby/core/mutex/synchronize_spec.rb8
-rw-r--r--spec/ruby/core/mutex/try_lock_spec.rb8
-rw-r--r--spec/ruby/core/mutex/unlock_spec.rb6
-rw-r--r--spec/ruby/core/nil/dup_spec.rb2
-rw-r--r--spec/ruby/core/nil/match_spec.rb14
-rw-r--r--spec/ruby/core/nil/nilclass_spec.rb4
-rw-r--r--spec/ruby/core/nil/rationalize_spec.rb4
-rw-r--r--spec/ruby/core/nil/singleton_method_spec.rb16
-rw-r--r--spec/ruby/core/nil/to_c_spec.rb2
-rw-r--r--spec/ruby/core/nil/to_s_spec.rb2
-rw-r--r--spec/ruby/core/nil/xor_spec.rb8
-rw-r--r--spec/ruby/core/numeric/abs2_spec.rb4
-rw-r--r--spec/ruby/core/numeric/abs_spec.rb17
-rw-r--r--spec/ruby/core/numeric/angle_spec.rb5
-rw-r--r--spec/ruby/core/numeric/arg_spec.rb36
-rw-r--r--spec/ruby/core/numeric/clone_spec.rb10
-rw-r--r--spec/ruby/core/numeric/coerce_spec.rb12
-rw-r--r--spec/ruby/core/numeric/comparison_spec.rb8
-rw-r--r--spec/ruby/core/numeric/conj_spec.rb5
-rw-r--r--spec/ruby/core/numeric/conjugate_spec.rb18
-rw-r--r--spec/ruby/core/numeric/div_spec.rb6
-rw-r--r--spec/ruby/core/numeric/dup_spec.rb4
-rw-r--r--spec/ruby/core/numeric/eql_spec.rb12
-rw-r--r--spec/ruby/core/numeric/fdiv_spec.rb4
-rw-r--r--spec/ruby/core/numeric/finite_spec.rb2
-rw-r--r--spec/ruby/core/numeric/i_spec.rb2
-rw-r--r--spec/ruby/core/numeric/imag_spec.rb5
-rw-r--r--spec/ruby/core/numeric/imaginary_spec.rb24
-rw-r--r--spec/ruby/core/numeric/magnitude_spec.rb5
-rw-r--r--spec/ruby/core/numeric/modulo_spec.rb19
-rw-r--r--spec/ruby/core/numeric/negative_spec.rb12
-rw-r--r--spec/ruby/core/numeric/phase_spec.rb5
-rw-r--r--spec/ruby/core/numeric/polar_spec.rb6
-rw-r--r--spec/ruby/core/numeric/positive_spec.rb12
-rw-r--r--spec/ruby/core/numeric/quo_spec.rb24
-rw-r--r--spec/ruby/core/numeric/real_spec.rb4
-rw-r--r--spec/ruby/core/numeric/rect_spec.rb5
-rw-r--r--spec/ruby/core/numeric/rectangular_spec.rb46
-rw-r--r--spec/ruby/core/numeric/remainder_spec.rb10
-rw-r--r--spec/ruby/core/numeric/shared/abs.rb19
-rw-r--r--spec/ruby/core/numeric/shared/arg.rb38
-rw-r--r--spec/ruby/core/numeric/shared/conj.rb20
-rw-r--r--spec/ruby/core/numeric/shared/imag.rb26
-rw-r--r--spec/ruby/core/numeric/shared/rect.rb48
-rw-r--r--spec/ruby/core/numeric/shared/step.rb90
-rw-r--r--spec/ruby/core/numeric/singleton_method_added_spec.rb8
-rw-r--r--spec/ruby/core/numeric/step_spec.rb12
-rw-r--r--spec/ruby/core/numeric/to_c_spec.rb4
-rw-r--r--spec/ruby/core/objectspace/_id2ref_spec.rb6
-rw-r--r--spec/ruby/core/objectspace/define_finalizer_spec.rb22
-rw-r--r--spec/ruby/core/objectspace/each_object_spec.rb46
-rw-r--r--spec/ruby/core/objectspace/garbage_collect_spec.rb4
-rw-r--r--spec/ruby/core/objectspace/undefine_finalizer_spec.rb2
-rw-r--r--spec/ruby/core/objectspace/weakkeymap/clear_spec.rb34
-rw-r--r--spec/ruby/core/objectspace/weakkeymap/delete_spec.rb78
-rw-r--r--spec/ruby/core/objectspace/weakkeymap/element_reference_spec.rb202
-rw-r--r--spec/ruby/core/objectspace/weakkeymap/element_set_spec.rb124
-rw-r--r--spec/ruby/core/objectspace/weakkeymap/getkey_spec.rb38
-rw-r--r--spec/ruby/core/objectspace/weakkeymap/inspect_spec.rb30
-rw-r--r--spec/ruby/core/objectspace/weakkeymap/key_spec.rb68
-rw-r--r--spec/ruby/core/objectspace/weakmap/delete_spec.rb42
-rw-r--r--spec/ruby/core/objectspace/weakmap/each_pair_spec.rb11
-rw-r--r--spec/ruby/core/objectspace/weakmap/each_spec.rb2
-rw-r--r--spec/ruby/core/objectspace/weakmap/each_value_spec.rb2
-rw-r--r--spec/ruby/core/objectspace/weakmap/include_spec.rb30
-rw-r--r--spec/ruby/core/objectspace/weakmap/key_spec.rb6
-rw-r--r--spec/ruby/core/objectspace/weakmap/length_spec.rb6
-rw-r--r--spec/ruby/core/objectspace/weakmap/member_spec.rb6
-rw-r--r--spec/ruby/core/objectspace/weakmap/shared/each.rb2
-rw-r--r--spec/ruby/core/objectspace/weakmap/shared/include.rb30
-rw-r--r--spec/ruby/core/objectspace/weakmap/shared/size.rb14
-rw-r--r--spec/ruby/core/objectspace/weakmap/size_spec.rb14
-rw-r--r--spec/ruby/core/proc/allocate_spec.rb2
-rw-r--r--spec/ruby/core/proc/binding_spec.rb2
-rw-r--r--spec/ruby/core/proc/block_pass_spec.rb4
-rw-r--r--spec/ruby/core/proc/call_spec.rb142
-rw-r--r--spec/ruby/core/proc/case_compare_spec.rb15
-rw-r--r--spec/ruby/core/proc/clone_spec.rb20
-rw-r--r--spec/ruby/core/proc/curry_spec.rb62
-rw-r--r--spec/ruby/core/proc/dup_spec.rb18
-rw-r--r--spec/ruby/core/proc/element_reference_spec.rb24
-rw-r--r--spec/ruby/core/proc/eql_spec.rb5
-rw-r--r--spec/ruby/core/proc/equal_value_spec.rb81
-rw-r--r--spec/ruby/core/proc/fixtures/proc_aref.rb10
-rw-r--r--spec/ruby/core/proc/fixtures/proc_aref_frozen.rb10
-rw-r--r--spec/ruby/core/proc/fixtures/proc_call.rb10
-rw-r--r--spec/ruby/core/proc/fixtures/proc_call_frozen.rb10
-rw-r--r--spec/ruby/core/proc/hash_spec.rb6
-rw-r--r--spec/ruby/core/proc/inspect_spec.rb5
-rw-r--r--spec/ruby/core/proc/lambda_spec.rb45
-rw-r--r--spec/ruby/core/proc/new_spec.rb28
-rw-r--r--spec/ruby/core/proc/parameters_spec.rb26
-rw-r--r--spec/ruby/core/proc/ruby2_keywords_spec.rb4
-rw-r--r--spec/ruby/core/proc/shared/call.rb99
-rw-r--r--spec/ruby/core/proc/shared/call_arguments.rb29
-rw-r--r--spec/ruby/core/proc/shared/compose.rb4
-rw-r--r--spec/ruby/core/proc/shared/dup.rb2
-rw-r--r--spec/ruby/core/proc/shared/equal.rb83
-rw-r--r--spec/ruby/core/proc/shared/to_s.rb60
-rw-r--r--spec/ruby/core/proc/source_location_spec.rb75
-rw-r--r--spec/ruby/core/proc/to_proc_spec.rb2
-rw-r--r--spec/ruby/core/proc/to_s_spec.rb60
-rw-r--r--spec/ruby/core/proc/yield_spec.rb15
-rw-r--r--spec/ruby/core/process/_fork_spec.rb4
-rw-r--r--spec/ruby/core/process/argv0_spec.rb8
-rw-r--r--spec/ruby/core/process/clock_gettime_spec.rb62
-rw-r--r--spec/ruby/core/process/constants_spec.rb46
-rw-r--r--spec/ruby/core/process/daemon_spec.rb17
-rw-r--r--spec/ruby/core/process/detach_spec.rb119
-rw-r--r--spec/ruby/core/process/egid_spec.rb8
-rw-r--r--spec/ruby/core/process/euid_spec.rb8
-rw-r--r--spec/ruby/core/process/exec_spec.rb20
-rw-r--r--spec/ruby/core/process/getpriority_spec.rb8
-rw-r--r--spec/ruby/core/process/getrlimit_spec.rb14
-rw-r--r--spec/ruby/core/process/groups_spec.rb4
-rw-r--r--spec/ruby/core/process/initgroups_spec.rb2
-rw-r--r--spec/ruby/core/process/kill_spec.rb8
-rw-r--r--spec/ruby/core/process/last_status_spec.rb2
-rw-r--r--spec/ruby/core/process/maxgroups_spec.rb2
-rw-r--r--spec/ruby/core/process/pid_spec.rb2
-rw-r--r--spec/ruby/core/process/set_proctitle_spec.rb2
-rw-r--r--spec/ruby/core/process/setpgid_spec.rb2
-rw-r--r--spec/ruby/core/process/setpgrp_spec.rb2
-rw-r--r--spec/ruby/core/process/setrlimit_spec.rb88
-rw-r--r--spec/ruby/core/process/spawn_spec.rb108
-rw-r--r--spec/ruby/core/process/status/bit_and_spec.rb6
-rw-r--r--spec/ruby/core/process/status/exited_spec.rb6
-rw-r--r--spec/ruby/core/process/status/right_shift_spec.rb6
-rw-r--r--spec/ruby/core/process/status/signaled_spec.rb6
-rw-r--r--spec/ruby/core/process/status/success_spec.rb8
-rw-r--r--spec/ruby/core/process/status/termsig_spec.rb4
-rw-r--r--spec/ruby/core/process/status/to_i_spec.rb4
-rw-r--r--spec/ruby/core/process/status/wait_spec.rb52
-rw-r--r--spec/ruby/core/process/times_spec.rb2
-rw-r--r--spec/ruby/core/process/uid_spec.rb6
-rw-r--r--spec/ruby/core/process/wait2_spec.rb29
-rw-r--r--spec/ruby/core/process/wait_spec.rb51
-rw-r--r--spec/ruby/core/process/waitall_spec.rb30
-rw-r--r--spec/ruby/core/process/waitpid2_spec.rb4
-rw-r--r--spec/ruby/core/process/waitpid_spec.rb11
-rw-r--r--spec/ruby/core/process/warmup_spec.rb10
-rw-r--r--spec/ruby/core/queue/deq_spec.rb10
-rw-r--r--spec/ruby/core/queue/enq_spec.rb5
-rw-r--r--spec/ruby/core/queue/initialize_spec.rb10
-rw-r--r--spec/ruby/core/queue/length_spec.rb5
-rw-r--r--spec/ruby/core/queue/push_spec.rb5
-rw-r--r--spec/ruby/core/queue/shift_spec.rb10
-rw-r--r--spec/ruby/core/random/new_seed_spec.rb2
-rw-r--r--spec/ruby/core/random/new_spec.rb8
-rw-r--r--spec/ruby/core/random/rand_spec.rb34
-rw-r--r--spec/ruby/core/random/seed_spec.rb2
-rw-r--r--spec/ruby/core/random/shared/bytes.rb2
-rw-r--r--spec/ruby/core/random/shared/rand.rb4
-rw-r--r--spec/ruby/core/random/urandom_spec.rb4
-rw-r--r--spec/ruby/core/range/bsearch_spec.rb104
-rw-r--r--spec/ruby/core/range/case_compare_spec.rb6
-rw-r--r--spec/ruby/core/range/cover_spec.rb2
-rw-r--r--spec/ruby/core/range/each_spec.rb10
-rw-r--r--spec/ruby/core/range/entries_spec.rb7
-rw-r--r--spec/ruby/core/range/eql_spec.rb2
-rw-r--r--spec/ruby/core/range/first_spec.rb10
-rw-r--r--spec/ruby/core/range/hash_spec.rb8
-rw-r--r--spec/ruby/core/range/include_spec.rb92
-rw-r--r--spec/ruby/core/range/initialize_spec.rb20
-rw-r--r--spec/ruby/core/range/last_spec.rb10
-rw-r--r--spec/ruby/core/range/max_spec.rb36
-rw-r--r--spec/ruby/core/range/member_spec.rb9
-rw-r--r--spec/ruby/core/range/min_spec.rb26
-rw-r--r--spec/ruby/core/range/minmax_spec.rb14
-rw-r--r--spec/ruby/core/range/new_spec.rb8
-rw-r--r--spec/ruby/core/range/overlap_spec.rb168
-rw-r--r--spec/ruby/core/range/reverse_each_spec.rb172
-rw-r--r--spec/ruby/core/range/shared/cover.rb142
-rw-r--r--spec/ruby/core/range/shared/cover_and_include.rb30
-rw-r--r--spec/ruby/core/range/shared/include.rb91
-rw-r--r--spec/ruby/core/range/size_spec.rb34
-rw-r--r--spec/ruby/core/range/step_spec.rb190
-rw-r--r--spec/ruby/core/range/to_a_spec.rb6
-rw-r--r--spec/ruby/core/range/to_set_spec.rb54
-rw-r--r--spec/ruby/core/rational/abs_spec.rb9
-rw-r--r--spec/ruby/core/rational/ceil_spec.rb49
-rw-r--r--spec/ruby/core/rational/comparison_spec.rb44
-rw-r--r--spec/ruby/core/rational/denominator_spec.rb4
-rw-r--r--spec/ruby/core/rational/div_spec.rb14
-rw-r--r--spec/ruby/core/rational/divide_spec.rb34
-rw-r--r--spec/ruby/core/rational/divmod_spec.rb24
-rw-r--r--spec/ruby/core/rational/equal_value_spec.rb26
-rw-r--r--spec/ruby/core/rational/exponent_spec.rb80
-rw-r--r--spec/ruby/core/rational/floor_spec.rb50
-rw-r--r--spec/ruby/core/rational/integer_spec.rb4
-rw-r--r--spec/ruby/core/rational/magnitude_spec.rb7
-rw-r--r--spec/ruby/core/rational/marshal_dump_spec.rb2
-rw-r--r--spec/ruby/core/rational/minus_spec.rb14
-rw-r--r--spec/ruby/core/rational/modulo_spec.rb10
-rw-r--r--spec/ruby/core/rational/multiply_spec.rb26
-rw-r--r--spec/ruby/core/rational/numerator_spec.rb4
-rw-r--r--spec/ruby/core/rational/plus_spec.rb14
-rw-r--r--spec/ruby/core/rational/quo_spec.rb22
-rw-r--r--spec/ruby/core/rational/rational_spec.rb2
-rw-r--r--spec/ruby/core/rational/rationalize_spec.rb4
-rw-r--r--spec/ruby/core/rational/round_spec.rb24
-rw-r--r--spec/ruby/core/rational/shared/abs.rb11
-rw-r--r--spec/ruby/core/rational/shared/arithmetic_exception_in_coerce.rb2
-rw-r--r--spec/ruby/core/rational/to_f_spec.rb8
-rw-r--r--spec/ruby/core/rational/to_i_spec.rb6
-rw-r--r--spec/ruby/core/rational/to_r_spec.rb8
-rw-r--r--spec/ruby/core/rational/truncate_spec.rb20
-rw-r--r--spec/ruby/core/rational/zero_spec.rb6
-rw-r--r--spec/ruby/core/refinement/append_features_spec.rb4
-rw-r--r--spec/ruby/core/refinement/extend_object_spec.rb4
-rw-r--r--spec/ruby/core/refinement/import_methods_spec.rb36
-rw-r--r--spec/ruby/core/refinement/include_spec.rb2
-rw-r--r--spec/ruby/core/refinement/prepend_features_spec.rb4
-rw-r--r--spec/ruby/core/refinement/prepend_spec.rb2
-rw-r--r--spec/ruby/core/refinement/refined_class_spec.rb7
-rw-r--r--spec/ruby/core/refinement/shared/target.rb13
-rw-r--r--spec/ruby/core/refinement/target_spec.rb13
-rw-r--r--spec/ruby/core/regexp/case_compare_spec.rb14
-rw-r--r--spec/ruby/core/regexp/compile_spec.rb2
-rw-r--r--spec/ruby/core/regexp/encoding_spec.rb2
-rw-r--r--spec/ruby/core/regexp/eql_spec.rb5
-rw-r--r--spec/ruby/core/regexp/equal_value_spec.rb31
-rw-r--r--spec/ruby/core/regexp/escape_spec.rb5
-rw-r--r--spec/ruby/core/regexp/fixed_encoding_spec.rb16
-rw-r--r--spec/ruby/core/regexp/initialize_spec.rb22
-rw-r--r--spec/ruby/core/regexp/last_match_spec.rb6
-rw-r--r--spec/ruby/core/regexp/linear_time_spec.rb53
-rw-r--r--spec/ruby/core/regexp/match_spec.rb38
-rw-r--r--spec/ruby/core/regexp/named_captures_spec.rb4
-rw-r--r--spec/ruby/core/regexp/names_spec.rb4
-rw-r--r--spec/ruby/core/regexp/new_spec.rb2
-rw-r--r--spec/ruby/core/regexp/options_spec.rb6
-rw-r--r--spec/ruby/core/regexp/quote_spec.rb41
-rw-r--r--spec/ruby/core/regexp/shared/equal_value.rb31
-rw-r--r--spec/ruby/core/regexp/shared/new.rb291
-rw-r--r--spec/ruby/core/regexp/shared/quote.rb41
-rw-r--r--spec/ruby/core/regexp/source_spec.rb4
-rw-r--r--spec/ruby/core/regexp/timeout_spec.rb4
-rw-r--r--spec/ruby/core/regexp/try_convert_spec.rb4
-rw-r--r--spec/ruby/core/regexp/union_spec.rb28
-rw-r--r--spec/ruby/core/set/add_spec.rb22
-rw-r--r--spec/ruby/core/set/append_spec.rb5
-rw-r--r--spec/ruby/core/set/case_compare_spec.rb8
-rw-r--r--spec/ruby/core/set/case_equality_spec.rb6
-rw-r--r--spec/ruby/core/set/classify_spec.rb2
-rw-r--r--spec/ruby/core/set/clear_spec.rb4
-rw-r--r--spec/ruby/core/set/collect_spec.rb5
-rw-r--r--spec/ruby/core/set/compare_by_identity_spec.rb20
-rw-r--r--spec/ruby/core/set/comparison_spec.rb4
-rw-r--r--spec/ruby/core/set/constructor_spec.rb10
-rw-r--r--spec/ruby/core/set/delete_if_spec.rb18
-rw-r--r--spec/ruby/core/set/delete_spec.rb12
-rw-r--r--spec/ruby/core/set/difference_spec.rb5
-rw-r--r--spec/ruby/core/set/disjoint_spec.rb4
-rw-r--r--spec/ruby/core/set/divide_spec.rb12
-rw-r--r--spec/ruby/core/set/each_spec.rb4
-rw-r--r--spec/ruby/core/set/empty_spec.rb6
-rw-r--r--spec/ruby/core/set/eql_spec.rb24
-rw-r--r--spec/ruby/core/set/equal_value_spec.rb2
-rw-r--r--spec/ruby/core/set/exclusion_spec.rb4
-rw-r--r--spec/ruby/core/set/filter_spec.rb5
-rw-r--r--spec/ruby/core/set/flatten_merge_spec.rb6
-rw-r--r--spec/ruby/core/set/flatten_spec.rb22
-rw-r--r--spec/ruby/core/set/gt_spec.rb7
-rw-r--r--spec/ruby/core/set/gte_spec.rb7
-rw-r--r--spec/ruby/core/set/hash_spec.rb2
-rw-r--r--spec/ruby/core/set/include_spec.rb29
-rw-r--r--spec/ruby/core/set/initialize_spec.rb64
-rw-r--r--spec/ruby/core/set/inspect_spec.rb5
-rw-r--r--spec/ruby/core/set/intersect_spec.rb4
-rw-r--r--spec/ruby/core/set/intersection_spec.rb19
-rw-r--r--spec/ruby/core/set/join_spec.rb2
-rw-r--r--spec/ruby/core/set/keep_if_spec.rb18
-rw-r--r--spec/ruby/core/set/length_spec.rb5
-rw-r--r--spec/ruby/core/set/lt_spec.rb7
-rw-r--r--spec/ruby/core/set/lte_spec.rb7
-rw-r--r--spec/ruby/core/set/map_spec.rb20
-rw-r--r--spec/ruby/core/set/member_spec.rb5
-rw-r--r--spec/ruby/core/set/merge_spec.rb20
-rw-r--r--spec/ruby/core/set/minus_spec.rb15
-rw-r--r--spec/ruby/core/set/plus_spec.rb5
-rw-r--r--spec/ruby/core/set/pretty_print_cycle_spec.rb7
-rw-r--r--spec/ruby/core/set/proper_subset_spec.rb44
-rw-r--r--spec/ruby/core/set/proper_superset_spec.rb38
-rw-r--r--spec/ruby/core/set/reject_spec.rb20
-rw-r--r--spec/ruby/core/set/replace_spec.rb2
-rw-r--r--spec/ruby/core/set/select_spec.rb39
-rw-r--r--spec/ruby/core/set/shared/add.rb14
-rw-r--r--spec/ruby/core/set/shared/collect.rb20
-rw-r--r--spec/ruby/core/set/shared/difference.rb15
-rw-r--r--spec/ruby/core/set/shared/include.rb29
-rw-r--r--spec/ruby/core/set/shared/inspect.rb45
-rw-r--r--spec/ruby/core/set/shared/intersection.rb15
-rw-r--r--spec/ruby/core/set/shared/length.rb6
-rw-r--r--spec/ruby/core/set/shared/select.rb41
-rw-r--r--spec/ruby/core/set/shared/union.rb15
-rw-r--r--spec/ruby/core/set/size_spec.rb6
-rw-r--r--spec/ruby/core/set/sortedset/sortedset_spec.rb4
-rw-r--r--spec/ruby/core/set/subset_spec.rb44
-rw-r--r--spec/ruby/core/set/superset_spec.rb38
-rw-r--r--spec/ruby/core/set/to_s_spec.rb46
-rw-r--r--spec/ruby/core/set/union_spec.rb19
-rw-r--r--spec/ruby/core/signal/signame_spec.rb4
-rw-r--r--spec/ruby/core/signal/trap_spec.rb40
-rw-r--r--spec/ruby/core/sizedqueue/deq_spec.rb10
-rw-r--r--spec/ruby/core/sizedqueue/enq_spec.rb15
-rw-r--r--spec/ruby/core/sizedqueue/length_spec.rb5
-rw-r--r--spec/ruby/core/sizedqueue/push_spec.rb15
-rw-r--r--spec/ruby/core/sizedqueue/shift_spec.rb10
-rw-r--r--spec/ruby/core/string/allocate_spec.rb2
-rw-r--r--spec/ruby/core/string/append_as_bytes_spec.rb8
-rw-r--r--spec/ruby/core/string/append_spec.rb4
-rw-r--r--spec/ruby/core/string/ascii_only_spec.rb30
-rw-r--r--spec/ruby/core/string/b_spec.rb2
-rw-r--r--spec/ruby/core/string/byteindex_spec.rb4
-rw-r--r--spec/ruby/core/string/byterindex_spec.rb4
-rw-r--r--spec/ruby/core/string/bytes_spec.rb6
-rw-r--r--spec/ruby/core/string/bytesplice_spec.rb352
-rw-r--r--spec/ruby/core/string/capitalize_spec.rb28
-rw-r--r--spec/ruby/core/string/case_compare_spec.rb7
-rw-r--r--spec/ruby/core/string/casecmp_spec.rb10
-rw-r--r--spec/ruby/core/string/center_spec.rb34
-rw-r--r--spec/ruby/core/string/chilled_string_spec.rb12
-rw-r--r--spec/ruby/core/string/chomp_spec.rb40
-rw-r--r--spec/ruby/core/string/chop_spec.rb12
-rw-r--r--spec/ruby/core/string/chr_spec.rb4
-rw-r--r--spec/ruby/core/string/clear_spec.rb6
-rw-r--r--spec/ruby/core/string/clone_spec.rb4
-rw-r--r--spec/ruby/core/string/codepoints_spec.rb5
-rw-r--r--spec/ruby/core/string/comparison_spec.rb4
-rw-r--r--spec/ruby/core/string/concat_spec.rb2
-rw-r--r--spec/ruby/core/string/count_spec.rb12
-rw-r--r--spec/ruby/core/string/crypt_spec.rb30
-rw-r--r--spec/ruby/core/string/dedup_spec.rb5
-rw-r--r--spec/ruby/core/string/delete_prefix_spec.rb16
-rw-r--r--spec/ruby/core/string/delete_spec.rb22
-rw-r--r--spec/ruby/core/string/delete_suffix_spec.rb16
-rw-r--r--spec/ruby/core/string/downcase_spec.rb26
-rw-r--r--spec/ruby/core/string/dump_spec.rb2
-rw-r--r--spec/ruby/core/string/dup_spec.rb6
-rw-r--r--spec/ruby/core/string/each_byte_spec.rb4
-rw-r--r--spec/ruby/core/string/each_codepoint_spec.rb34
-rw-r--r--spec/ruby/core/string/element_set_spec.rb86
-rw-r--r--spec/ruby/core/string/encode_spec.rb36
-rw-r--r--spec/ruby/core/string/encoding_spec.rb12
-rw-r--r--spec/ruby/core/string/eql_spec.rb8
-rw-r--r--spec/ruby/core/string/equal_value_spec.rb26
-rw-r--r--spec/ruby/core/string/force_encoding_spec.rb10
-rw-r--r--spec/ruby/core/string/freeze_spec.rb4
-rw-r--r--spec/ruby/core/string/getbyte_spec.rb12
-rw-r--r--spec/ruby/core/string/gsub_spec.rb54
-rw-r--r--spec/ruby/core/string/include_spec.rb8
-rw-r--r--spec/ruby/core/string/index_spec.rb41
-rw-r--r--spec/ruby/core/string/initialize_spec.rb4
-rw-r--r--spec/ruby/core/string/insert_spec.rb16
-rw-r--r--spec/ruby/core/string/inspect_spec.rb2
-rw-r--r--spec/ruby/core/string/intern_spec.rb6
-rw-r--r--spec/ruby/core/string/length_spec.rb53
-rw-r--r--spec/ruby/core/string/ljust_spec.rb32
-rw-r--r--spec/ruby/core/string/lstrip_spec.rb16
-rw-r--r--spec/ruby/core/string/match_spec.rb34
-rw-r--r--spec/ruby/core/string/modulo_spec.rb144
-rw-r--r--spec/ruby/core/string/new_spec.rb10
-rw-r--r--spec/ruby/core/string/next_spec.rb10
-rw-r--r--spec/ruby/core/string/ord_spec.rb6
-rw-r--r--spec/ruby/core/string/partition_spec.rb4
-rw-r--r--spec/ruby/core/string/plus_spec.rb18
-rw-r--r--spec/ruby/core/string/prepend_spec.rb12
-rw-r--r--spec/ruby/core/string/reverse_spec.rb18
-rw-r--r--spec/ruby/core/string/rindex_spec.rb16
-rw-r--r--spec/ruby/core/string/rjust_spec.rb32
-rw-r--r--spec/ruby/core/string/rpartition_spec.rb4
-rw-r--r--spec/ruby/core/string/rstrip_spec.rb16
-rw-r--r--spec/ruby/core/string/scan_spec.rb10
-rw-r--r--spec/ruby/core/string/scrub_spec.rb18
-rw-r--r--spec/ruby/core/string/setbyte_spec.rb16
-rw-r--r--spec/ruby/core/string/shared/byte_index_common.rb20
-rw-r--r--spec/ruby/core/string/shared/chars.rb26
-rw-r--r--spec/ruby/core/string/shared/codepoints.rb19
-rw-r--r--spec/ruby/core/string/shared/concat.rb36
-rw-r--r--spec/ruby/core/string/shared/dedup.rb51
-rw-r--r--spec/ruby/core/string/shared/each_char_without_block.rb2
-rw-r--r--spec/ruby/core/string/shared/each_codepoint_without_block.rb33
-rw-r--r--spec/ruby/core/string/shared/each_line.rb58
-rw-r--r--spec/ruby/core/string/shared/each_line_without_block.rb2
-rw-r--r--spec/ruby/core/string/shared/encode.rb50
-rw-r--r--spec/ruby/core/string/shared/eql.rb16
-rw-r--r--spec/ruby/core/string/shared/equal_value.rb29
-rw-r--r--spec/ruby/core/string/shared/grapheme_clusters.rb11
-rw-r--r--spec/ruby/core/string/shared/length.rb55
-rw-r--r--spec/ruby/core/string/shared/partition.rb6
-rw-r--r--spec/ruby/core/string/shared/replace.rb14
-rw-r--r--spec/ruby/core/string/shared/slice.rb86
-rw-r--r--spec/ruby/core/string/shared/strip.rb6
-rw-r--r--spec/ruby/core/string/shared/succ.rb87
-rw-r--r--spec/ruby/core/string/shared/to_s.rb13
-rw-r--r--spec/ruby/core/string/shared/to_sym.rb72
-rw-r--r--spec/ruby/core/string/size_spec.rb6
-rw-r--r--spec/ruby/core/string/slice_spec.rb93
-rw-r--r--spec/ruby/core/string/split_spec.rb56
-rw-r--r--spec/ruby/core/string/squeeze_spec.rb22
-rw-r--r--spec/ruby/core/string/start_with_spec.rb15
-rw-r--r--spec/ruby/core/string/strip_spec.rb8
-rw-r--r--spec/ruby/core/string/sub_spec.rb42
-rw-r--r--spec/ruby/core/string/succ_spec.rb85
-rw-r--r--spec/ruby/core/string/swapcase_spec.rb28
-rw-r--r--spec/ruby/core/string/to_c_spec.rb2
-rw-r--r--spec/ruby/core/string/to_f_spec.rb20
-rw-r--r--spec/ruby/core/string/to_i_spec.rb18
-rw-r--r--spec/ruby/core/string/to_r_spec.rb2
-rw-r--r--spec/ruby/core/string/to_s_spec.rb13
-rw-r--r--spec/ruby/core/string/to_str_spec.rb6
-rw-r--r--spec/ruby/core/string/to_sym_spec.rb73
-rw-r--r--spec/ruby/core/string/tr_s_spec.rb20
-rw-r--r--spec/ruby/core/string/tr_spec.rb24
-rw-r--r--spec/ruby/core/string/try_convert_spec.rb16
-rw-r--r--spec/ruby/core/string/uminus_spec.rb51
-rw-r--r--spec/ruby/core/string/undump_spec.rb36
-rw-r--r--spec/ruby/core/string/unicode_normalize_spec.rb8
-rw-r--r--spec/ruby/core/string/unicode_normalized_spec.rb20
-rw-r--r--spec/ruby/core/string/unpack/at_spec.rb2
-rw-r--r--spec/ruby/core/string/unpack/b_spec.rb36
-rw-r--r--spec/ruby/core/string/unpack/c_spec.rb18
-rw-r--r--spec/ruby/core/string/unpack/carret_spec.rb43
-rw-r--r--spec/ruby/core/string/unpack/h_spec.rb36
-rw-r--r--spec/ruby/core/string/unpack/m_spec.rb2
-rw-r--r--spec/ruby/core/string/unpack/p_spec.rb4
-rw-r--r--spec/ruby/core/string/unpack/percent_spec.rb2
-rw-r--r--spec/ruby/core/string/unpack/r_spec.rb85
-rw-r--r--spec/ruby/core/string/unpack/shared/basic.rb19
-rw-r--r--spec/ruby/core/string/unpack/shared/float.rb82
-rw-r--r--spec/ruby/core/string/unpack/shared/integer.rb110
-rw-r--r--spec/ruby/core/string/unpack/shared/unicode.rb18
-rw-r--r--spec/ruby/core/string/unpack/u_spec.rb4
-rw-r--r--spec/ruby/core/string/unpack/w_spec.rb18
-rw-r--r--spec/ruby/core/string/unpack/x_spec.rb6
-rw-r--r--spec/ruby/core/string/unpack1_spec.rb33
-rw-r--r--spec/ruby/core/string/unpack_spec.rb24
-rw-r--r--spec/ruby/core/string/upcase_spec.rb28
-rw-r--r--spec/ruby/core/string/uplus_spec.rb44
-rw-r--r--spec/ruby/core/string/upto_spec.rb10
-rw-r--r--spec/ruby/core/string/valid_encoding_spec.rb194
-rw-r--r--spec/ruby/core/struct/deconstruct_keys_spec.rb14
-rw-r--r--spec/ruby/core/struct/deconstruct_spec.rb7
-rw-r--r--spec/ruby/core/struct/dig_spec.rb4
-rw-r--r--spec/ruby/core/struct/each_pair_spec.rb4
-rw-r--r--spec/ruby/core/struct/each_spec.rb2
-rw-r--r--spec/ruby/core/struct/element_reference_spec.rb14
-rw-r--r--spec/ruby/core/struct/element_set_spec.rb10
-rw-r--r--spec/ruby/core/struct/eql_spec.rb2
-rw-r--r--spec/ruby/core/struct/filter_spec.rb10
-rw-r--r--spec/ruby/core/struct/fixtures/classes.rb1
-rw-r--r--spec/ruby/core/struct/hash_spec.rb4
-rw-r--r--spec/ruby/core/struct/initialize_spec.rb25
-rw-r--r--spec/ruby/core/struct/inspect_spec.rb5
-rw-r--r--spec/ruby/core/struct/instance_variable_get_spec.rb2
-rw-r--r--spec/ruby/core/struct/keyword_init_spec.rb16
-rw-r--r--spec/ruby/core/struct/length_spec.rb8
-rw-r--r--spec/ruby/core/struct/new_spec.rb76
-rw-r--r--spec/ruby/core/struct/select_spec.rb25
-rw-r--r--spec/ruby/core/struct/shared/inspect.rb40
-rw-r--r--spec/ruby/core/struct/shared/select.rb26
-rw-r--r--spec/ruby/core/struct/size_spec.rb5
-rw-r--r--spec/ruby/core/struct/struct_spec.rb4
-rw-r--r--spec/ruby/core/struct/to_h_spec.rb8
-rw-r--r--spec/ruby/core/struct/to_s_spec.rb39
-rw-r--r--spec/ruby/core/struct/values_at_spec.rb8
-rw-r--r--spec/ruby/core/struct/values_spec.rb7
-rw-r--r--spec/ruby/core/symbol/all_symbols_spec.rb8
-rw-r--r--spec/ruby/core/symbol/capitalize_spec.rb2
-rw-r--r--spec/ruby/core/symbol/case_compare_spec.rb8
-rw-r--r--spec/ruby/core/symbol/casecmp_spec.rb6
-rw-r--r--spec/ruby/core/symbol/comparison_spec.rb6
-rw-r--r--spec/ruby/core/symbol/downcase_spec.rb2
-rw-r--r--spec/ruby/core/symbol/dup_spec.rb2
-rw-r--r--spec/ruby/core/symbol/element_reference_spec.rb261
-rw-r--r--spec/ruby/core/symbol/empty_spec.rb4
-rw-r--r--spec/ruby/core/symbol/id2name_spec.rb5
-rw-r--r--spec/ruby/core/symbol/inspect_spec.rb34
-rw-r--r--spec/ruby/core/symbol/intern_spec.rb8
-rw-r--r--spec/ruby/core/symbol/length_spec.rb21
-rw-r--r--spec/ruby/core/symbol/match_spec.rb18
-rw-r--r--spec/ruby/core/symbol/next_spec.rb5
-rw-r--r--spec/ruby/core/symbol/shared/id2name.rb16
-rw-r--r--spec/ruby/core/symbol/shared/length.rb23
-rw-r--r--spec/ruby/core/symbol/shared/slice.rb262
-rw-r--r--spec/ruby/core/symbol/shared/succ.rb18
-rw-r--r--spec/ruby/core/symbol/size_spec.rb5
-rw-r--r--spec/ruby/core/symbol/slice_spec.rb5
-rw-r--r--spec/ruby/core/symbol/succ_spec.rb16
-rw-r--r--spec/ruby/core/symbol/swapcase_spec.rb2
-rw-r--r--spec/ruby/core/symbol/symbol_spec.rb4
-rw-r--r--spec/ruby/core/symbol/to_proc_spec.rb12
-rw-r--r--spec/ruby/core/symbol/to_s_spec.rb30
-rw-r--r--spec/ruby/core/symbol/to_sym_spec.rb2
-rw-r--r--spec/ruby/core/symbol/upcase_spec.rb2
-rw-r--r--spec/ruby/core/thread/abort_on_exception_spec.rb8
-rw-r--r--spec/ruby/core/thread/allocate_spec.rb2
-rw-r--r--spec/ruby/core/thread/backtrace/location/absolute_path_spec.rb2
-rw-r--r--spec/ruby/core/thread/backtrace/location/fixtures/classes.rb104
-rw-r--r--spec/ruby/core/thread/backtrace/location/inspect_spec.rb2
-rw-r--r--spec/ruby/core/thread/backtrace/location/label_spec.rb194
-rw-r--r--spec/ruby/core/thread/backtrace/location/to_s_spec.rb2
-rw-r--r--spec/ruby/core/thread/backtrace_locations_spec.rb12
-rw-r--r--spec/ruby/core/thread/backtrace_spec.rb4
-rw-r--r--spec/ruby/core/thread/current_spec.rb10
-rw-r--r--spec/ruby/core/thread/each_caller_location_spec.rb8
-rw-r--r--spec/ruby/core/thread/element_reference_spec.rb4
-rw-r--r--spec/ruby/core/thread/element_set_spec.rb8
-rw-r--r--spec/ruby/core/thread/exit_spec.rb9
-rw-r--r--spec/ruby/core/thread/fetch_spec.rb6
-rw-r--r--spec/ruby/core/thread/fixtures/classes.rb3
-rw-r--r--spec/ruby/core/thread/fork_spec.rb6
-rw-r--r--spec/ruby/core/thread/handle_interrupt_spec.rb6
-rw-r--r--spec/ruby/core/thread/initialize_spec.rb2
-rw-r--r--spec/ruby/core/thread/inspect_spec.rb5
-rw-r--r--spec/ruby/core/thread/join_spec.rb20
-rw-r--r--spec/ruby/core/thread/key_spec.rb16
-rw-r--r--spec/ruby/core/thread/keys_spec.rb12
-rw-r--r--spec/ruby/core/thread/kill_spec.rb215
-rw-r--r--spec/ruby/core/thread/list_spec.rb12
-rw-r--r--spec/ruby/core/thread/name_spec.rb2
-rw-r--r--spec/ruby/core/thread/native_thread_id_spec.rb10
-rw-r--r--spec/ruby/core/thread/new_spec.rb4
-rw-r--r--spec/ruby/core/thread/pending_interrupt_spec.rb2
-rw-r--r--spec/ruby/core/thread/priority_spec.rb8
-rw-r--r--spec/ruby/core/thread/raise_spec.rb64
-rw-r--r--spec/ruby/core/thread/report_on_exception_spec.rb12
-rw-r--r--spec/ruby/core/thread/shared/exit.rb219
-rw-r--r--spec/ruby/core/thread/shared/start.rb41
-rw-r--r--spec/ruby/core/thread/shared/to_s.rb53
-rw-r--r--spec/ruby/core/thread/shared/wakeup.rb2
-rw-r--r--spec/ruby/core/thread/start_spec.rb42
-rw-r--r--spec/ruby/core/thread/terminate_spec.rb6
-rw-r--r--spec/ruby/core/thread/thread_variable_get_spec.rb12
-rw-r--r--spec/ruby/core/thread/thread_variable_set_spec.rb10
-rw-r--r--spec/ruby/core/thread/thread_variable_spec.rb22
-rw-r--r--spec/ruby/core/thread/thread_variables_spec.rb3
-rw-r--r--spec/ruby/core/thread/to_s_spec.rb52
-rw-r--r--spec/ruby/core/thread/value_spec.rb2
-rw-r--r--spec/ruby/core/threadgroup/default_spec.rb2
-rw-r--r--spec/ruby/core/threadgroup/enclose_spec.rb2
-rw-r--r--spec/ruby/core/threadgroup/enclosed_spec.rb4
-rw-r--r--spec/ruby/core/threadgroup/list_spec.rb4
-rw-r--r--spec/ruby/core/time/_dump_spec.rb4
-rw-r--r--spec/ruby/core/time/_load_spec.rb2
-rw-r--r--spec/ruby/core/time/asctime_spec.rb6
-rw-r--r--spec/ruby/core/time/at_spec.rb54
-rw-r--r--spec/ruby/core/time/ceil_spec.rb4
-rw-r--r--spec/ruby/core/time/comparison_spec.rb2
-rw-r--r--spec/ruby/core/time/ctime_spec.rb5
-rw-r--r--spec/ruby/core/time/day_spec.rb15
-rw-r--r--spec/ruby/core/time/deconstruct_keys_spec.rb10
-rw-r--r--spec/ruby/core/time/dst_spec.rb8
-rw-r--r--spec/ruby/core/time/dup_spec.rb14
-rw-r--r--spec/ruby/core/time/eql_spec.rb16
-rw-r--r--spec/ruby/core/time/floor_spec.rb4
-rw-r--r--spec/ruby/core/time/getgm_spec.rb5
-rw-r--r--spec/ruby/core/time/getlocal_spec.rb54
-rw-r--r--spec/ruby/core/time/getutc_spec.rb9
-rw-r--r--spec/ruby/core/time/gm_spec.rb9
-rw-r--r--spec/ruby/core/time/gmt_offset_spec.rb5
-rw-r--r--spec/ruby/core/time/gmt_spec.rb5
-rw-r--r--spec/ruby/core/time/gmtime_spec.rb5
-rw-r--r--spec/ruby/core/time/gmtoff_spec.rb5
-rw-r--r--spec/ruby/core/time/hash_spec.rb2
-rw-r--r--spec/ruby/core/time/isdst_spec.rb5
-rw-r--r--spec/ruby/core/time/iso8601_spec.rb31
-rw-r--r--spec/ruby/core/time/localtime_spec.rb42
-rw-r--r--spec/ruby/core/time/mday_spec.rb5
-rw-r--r--spec/ruby/core/time/minus_spec.rb14
-rw-r--r--spec/ruby/core/time/mktime_spec.rb10
-rw-r--r--spec/ruby/core/time/mon_spec.rb5
-rw-r--r--spec/ruby/core/time/month_spec.rb15
-rw-r--r--spec/ruby/core/time/new_spec.rb200
-rw-r--r--spec/ruby/core/time/now_spec.rb40
-rw-r--r--spec/ruby/core/time/plus_spec.rb16
-rw-r--r--spec/ruby/core/time/round_spec.rb4
-rw-r--r--spec/ruby/core/time/shared/asctime.rb6
-rw-r--r--spec/ruby/core/time/shared/day.rb15
-rw-r--r--spec/ruby/core/time/shared/getgm.rb9
-rw-r--r--spec/ruby/core/time/shared/gm.rb70
-rw-r--r--spec/ruby/core/time/shared/gmt_offset.rb59
-rw-r--r--spec/ruby/core/time/shared/gmtime.rb40
-rw-r--r--spec/ruby/core/time/shared/inspect.rb2
-rw-r--r--spec/ruby/core/time/shared/isdst.rb8
-rw-r--r--spec/ruby/core/time/shared/month.rb15
-rw-r--r--spec/ruby/core/time/shared/now.rb4
-rw-r--r--spec/ruby/core/time/shared/time_params.rb34
-rw-r--r--spec/ruby/core/time/shared/to_i.rb16
-rw-r--r--spec/ruby/core/time/shared/xmlschema.rb31
-rw-r--r--spec/ruby/core/time/strftime_spec.rb2
-rw-r--r--spec/ruby/core/time/subsec_spec.rb12
-rw-r--r--spec/ruby/core/time/to_i_spec.rb16
-rw-r--r--spec/ruby/core/time/to_r_spec.rb4
-rw-r--r--spec/ruby/core/time/tv_nsec_spec.rb4
-rw-r--r--spec/ruby/core/time/tv_sec_spec.rb5
-rw-r--r--spec/ruby/core/time/tv_usec_spec.rb4
-rw-r--r--spec/ruby/core/time/utc_offset_spec.rb59
-rw-r--r--spec/ruby/core/time/utc_spec.rb117
-rw-r--r--spec/ruby/core/time/xmlschema_spec.rb7
-rw-r--r--spec/ruby/core/time/zone_spec.rb4
-rw-r--r--spec/ruby/core/tracepoint/allow_reentry_spec.rb2
-rw-r--r--spec/ruby/core/tracepoint/binding_spec.rb2
-rw-r--r--spec/ruby/core/tracepoint/defined_class_spec.rb10
-rw-r--r--spec/ruby/core/tracepoint/enable_spec.rb28
-rw-r--r--spec/ruby/core/tracepoint/event_spec.rb6
-rw-r--r--spec/ruby/core/tracepoint/lineno_spec.rb2
-rw-r--r--spec/ruby/core/tracepoint/method_id_spec.rb2
-rw-r--r--spec/ruby/core/tracepoint/new_spec.rb22
-rw-r--r--spec/ruby/core/tracepoint/path_spec.rb31
-rw-r--r--spec/ruby/core/tracepoint/raised_exception_spec.rb28
-rw-r--r--spec/ruby/core/tracepoint/self_spec.rb4
-rw-r--r--spec/ruby/core/true/dup_spec.rb2
-rw-r--r--spec/ruby/core/true/inspect_spec.rb4
-rw-r--r--spec/ruby/core/true/singleton_method_spec.rb16
-rw-r--r--spec/ruby/core/true/to_s_spec.rb2
-rw-r--r--spec/ruby/core/true/trueclass_spec.rb4
-rw-r--r--spec/ruby/core/unboundmethod/bind_call_spec.rb4
-rw-r--r--spec/ruby/core/unboundmethod/bind_spec.rb16
-rw-r--r--spec/ruby/core/unboundmethod/eql_spec.rb4
-rw-r--r--spec/ruby/core/unboundmethod/equal_value_spec.rb39
-rw-r--r--spec/ruby/core/unboundmethod/fixtures/classes.rb17
-rw-r--r--spec/ruby/core/unboundmethod/inspect_spec.rb6
-rw-r--r--spec/ruby/core/unboundmethod/original_name_spec.rb37
-rw-r--r--spec/ruby/core/unboundmethod/shared/dup.rb2
-rw-r--r--spec/ruby/core/unboundmethod/shared/to_s.rb33
-rw-r--r--spec/ruby/core/unboundmethod/source_location_spec.rb22
-rw-r--r--spec/ruby/core/unboundmethod/to_s_spec.rb33
-rw-r--r--spec/ruby/core/warning/categories_spec.rb12
-rw-r--r--spec/ruby/core/warning/element_reference_spec.rb16
-rw-r--r--spec/ruby/core/warning/element_set_spec.rb24
-rw-r--r--spec/ruby/core/warning/warn_spec.rb30
-rw-r--r--spec/ruby/default.mspec5
-rw-r--r--spec/ruby/language/BEGIN_spec.rb2
-rw-r--r--spec/ruby/language/alias_spec.rb14
-rw-r--r--spec/ruby/language/and_spec.rb16
-rw-r--r--spec/ruby/language/array_spec.rb18
-rw-r--r--spec/ruby/language/assignments_spec.rb66
-rw-r--r--spec/ruby/language/block_spec.rb152
-rw-r--r--spec/ruby/language/break_spec.rb20
-rw-r--r--spec/ruby/language/case_spec.rb51
-rw-r--r--spec/ruby/language/class_spec.rb103
-rw-r--r--spec/ruby/language/class_variable_spec.rb22
-rw-r--r--spec/ruby/language/constants_spec.rb84
-rw-r--r--spec/ruby/language/def_spec.rb154
-rw-r--r--spec/ruby/language/defined_spec.rb226
-rw-r--r--spec/ruby/language/delegation_spec.rb60
-rw-r--r--spec/ruby/language/encoding_spec.rb4
-rw-r--r--spec/ruby/language/ensure_spec.rb32
-rw-r--r--spec/ruby/language/file_spec.rb14
-rw-r--r--spec/ruby/language/fixtures/defined.rb27
-rw-r--r--spec/ruby/language/fixtures/delegation.rb4
-rw-r--r--spec/ruby/language/fixtures/freeze_magic_comment_across_files.rb3
-rw-r--r--spec/ruby/language/fixtures/freeze_magic_comment_across_files_diff_enc.rb3
-rw-r--r--spec/ruby/language/fixtures/freeze_magic_comment_across_files_no_comment.rb3
-rw-r--r--spec/ruby/language/fixtures/freeze_magic_comment_one_literal.rb4
-rw-r--r--spec/ruby/language/fixtures/freeze_magic_comment_required.rb2
-rw-r--r--spec/ruby/language/fixtures/freeze_magic_comment_required_diff_enc.rb2
-rw-r--r--spec/ruby/language/fixtures/freeze_magic_comment_required_no_comment.rb2
-rw-r--r--spec/ruby/language/fixtures/module.rb9
-rw-r--r--spec/ruby/language/fixtures/send.rb10
-rw-r--r--spec/ruby/language/fixtures/super.rb2
-rw-r--r--spec/ruby/language/for_spec.rb157
-rw-r--r--spec/ruby/language/hash_spec.rb53
-rw-r--r--spec/ruby/language/heredoc_spec.rb4
-rw-r--r--spec/ruby/language/if_spec.rb2
-rw-r--r--spec/ruby/language/it_parameter_spec.rb108
-rw-r--r--spec/ruby/language/keyword_arguments_spec.rb42
-rw-r--r--spec/ruby/language/lambda_spec.rb140
-rw-r--r--spec/ruby/language/line_spec.rb2
-rw-r--r--spec/ruby/language/loop_spec.rb2
-rw-r--r--spec/ruby/language/magic_comment_spec.rb3
-rw-r--r--spec/ruby/language/match_spec.rb8
-rw-r--r--spec/ruby/language/metaclass_spec.rb22
-rw-r--r--spec/ruby/language/method_spec.rb304
-rw-r--r--spec/ruby/language/module_spec.rb56
-rw-r--r--spec/ruby/language/next_spec.rb4
-rw-r--r--spec/ruby/language/not_spec.rb32
-rw-r--r--spec/ruby/language/numbered_parameters_spec.rb32
-rw-r--r--spec/ruby/language/numbers_spec.rb6
-rw-r--r--spec/ruby/language/optional_assignments_spec.rb10
-rw-r--r--spec/ruby/language/or_spec.rb32
-rw-r--r--spec/ruby/language/pattern_matching_spec.rb30
-rw-r--r--spec/ruby/language/precedence_spec.rb16
-rw-r--r--spec/ruby/language/predefined_spec.rb229
-rw-r--r--spec/ruby/language/private_spec.rb20
-rw-r--r--spec/ruby/language/proc_spec.rb44
-rw-r--r--spec/ruby/language/redo_spec.rb2
-rw-r--r--spec/ruby/language/regexp/anchors_spec.rb58
-rw-r--r--spec/ruby/language/regexp/back-references_spec.rb54
-rw-r--r--spec/ruby/language/regexp/character_classes_spec.rb226
-rw-r--r--spec/ruby/language/regexp/encoding_spec.rb18
-rw-r--r--spec/ruby/language/regexp/escapes_spec.rb10
-rw-r--r--spec/ruby/language/regexp/grouping_spec.rb6
-rw-r--r--spec/ruby/language/regexp/interpolation_spec.rb6
-rw-r--r--spec/ruby/language/regexp/modifiers_spec.rb40
-rw-r--r--spec/ruby/language/regexp/repetition_spec.rb2
-rw-r--r--spec/ruby/language/regexp_spec.rb26
-rw-r--r--spec/ruby/language/rescue_spec.rb44
-rw-r--r--spec/ruby/language/reserved_keywords.rb149
-rw-r--r--spec/ruby/language/retry_spec.rb8
-rw-r--r--spec/ruby/language/return_spec.rb14
-rw-r--r--spec/ruby/language/safe_navigator_spec.rb8
-rw-r--r--spec/ruby/language/send_spec.rb69
-rw-r--r--spec/ruby/language/shared/__FILE__.rb4
-rw-r--r--spec/ruby/language/shared/__LINE__.rb2
-rw-r--r--spec/ruby/language/singleton_class_spec.rb86
-rw-r--r--spec/ruby/language/source_encoding_spec.rb4
-rw-r--r--spec/ruby/language/string_spec.rb10
-rw-r--r--spec/ruby/language/super_spec.rb22
-rw-r--r--spec/ruby/language/symbol_spec.rb22
-rw-r--r--spec/ruby/language/throw_spec.rb10
-rw-r--r--spec/ruby/language/undef_spec.rb14
-rw-r--r--spec/ruby/language/variables_spec.rb44
-rw-r--r--spec/ruby/language/while_spec.rb16
-rw-r--r--spec/ruby/language/yield_spec.rb32
-rw-r--r--spec/ruby/library/English/English_spec.rb64
-rw-r--r--spec/ruby/library/English/alias_spec.rb6
-rw-r--r--spec/ruby/library/base64/strict_decode64_spec.rb8
-rw-r--r--spec/ruby/library/bigdecimal/BigDecimal_spec.rb76
-rw-r--r--spec/ruby/library/bigdecimal/add_spec.rb16
-rw-r--r--spec/ruby/library/bigdecimal/case_compare_spec.rb6
-rw-r--r--spec/ruby/library/bigdecimal/ceil_spec.rb6
-rw-r--r--spec/ruby/library/bigdecimal/clone_spec.rb8
-rw-r--r--spec/ruby/library/bigdecimal/constants_spec.rb6
-rw-r--r--spec/ruby/library/bigdecimal/core_spec.rb17
-rw-r--r--spec/ruby/library/bigdecimal/div_spec.rb28
-rw-r--r--spec/ruby/library/bigdecimal/divmod_spec.rb88
-rw-r--r--spec/ruby/library/bigdecimal/dup_spec.rb12
-rw-r--r--spec/ruby/library/bigdecimal/eql_spec.rb6
-rw-r--r--spec/ruby/library/bigdecimal/equal_value_spec.rb60
-rw-r--r--spec/ruby/library/bigdecimal/fix_spec.rb2
-rw-r--r--spec/ruby/library/bigdecimal/floor_spec.rb6
-rw-r--r--spec/ruby/library/bigdecimal/gt_spec.rb12
-rw-r--r--spec/ruby/library/bigdecimal/gte_spec.rb12
-rw-r--r--spec/ruby/library/bigdecimal/lt_spec.rb12
-rw-r--r--spec/ruby/library/bigdecimal/lte_spec.rb12
-rw-r--r--spec/ruby/library/bigdecimal/mode_spec.rb10
-rw-r--r--spec/ruby/library/bigdecimal/modulo_spec.rb15
-rw-r--r--spec/ruby/library/bigdecimal/mult_spec.rb8
-rw-r--r--spec/ruby/library/bigdecimal/nonzero_spec.rb10
-rw-r--r--spec/ruby/library/bigdecimal/precs_spec.rb55
-rw-r--r--spec/ruby/library/bigdecimal/remainder_spec.rb29
-rw-r--r--spec/ruby/library/bigdecimal/round_spec.rb14
-rw-r--r--spec/ruby/library/bigdecimal/shared/clone.rb13
-rw-r--r--spec/ruby/library/bigdecimal/shared/eql.rb61
-rw-r--r--spec/ruby/library/bigdecimal/shared/modulo.rb26
-rw-r--r--spec/ruby/library/bigdecimal/shared/power.rb4
-rw-r--r--spec/ruby/library/bigdecimal/shared/to_int.rb16
-rw-r--r--spec/ruby/library/bigdecimal/sqrt_spec.rb18
-rw-r--r--spec/ruby/library/bigdecimal/sub_spec.rb8
-rw-r--r--spec/ruby/library/bigdecimal/to_f_spec.rb6
-rw-r--r--spec/ruby/library/bigdecimal/to_i_spec.rb14
-rw-r--r--spec/ruby/library/bigdecimal/to_int_spec.rb6
-rw-r--r--spec/ruby/library/bigdecimal/to_r_spec.rb14
-rw-r--r--spec/ruby/library/bigdecimal/to_s_spec.rb12
-rw-r--r--spec/ruby/library/bigdecimal/truncate_spec.rb6
-rw-r--r--spec/ruby/library/bigdecimal/util_spec.rb2
-rw-r--r--spec/ruby/library/cgi/cookie/domain_spec.rb4
-rw-r--r--spec/ruby/library/cgi/cookie/expires_spec.rb4
-rw-r--r--spec/ruby/library/cgi/cookie/initialize_spec.rb16
-rw-r--r--spec/ruby/library/cgi/cookie/name_spec.rb2
-rw-r--r--spec/ruby/library/cgi/cookie/parse_spec.rb2
-rw-r--r--spec/ruby/library/cgi/cookie/path_spec.rb2
-rw-r--r--spec/ruby/library/cgi/cookie/secure_spec.rb22
-rw-r--r--spec/ruby/library/cgi/cookie/to_s_spec.rb2
-rw-r--r--spec/ruby/library/cgi/cookie/value_spec.rb4
-rw-r--r--spec/ruby/library/cgi/escapeElement_spec.rb4
-rw-r--r--spec/ruby/library/cgi/escapeURIComponent_spec.rb59
-rw-r--r--spec/ruby/library/cgi/htmlextension/a_spec.rb2
-rw-r--r--spec/ruby/library/cgi/htmlextension/base_spec.rb2
-rw-r--r--spec/ruby/library/cgi/htmlextension/blockquote_spec.rb2
-rw-r--r--spec/ruby/library/cgi/htmlextension/br_spec.rb2
-rw-r--r--spec/ruby/library/cgi/htmlextension/caption_spec.rb2
-rw-r--r--spec/ruby/library/cgi/htmlextension/checkbox_group_spec.rb2
-rw-r--r--spec/ruby/library/cgi/htmlextension/checkbox_spec.rb2
-rw-r--r--spec/ruby/library/cgi/htmlextension/doctype_spec.rb2
-rw-r--r--spec/ruby/library/cgi/htmlextension/file_field_spec.rb2
-rw-r--r--spec/ruby/library/cgi/htmlextension/form_spec.rb2
-rw-r--r--spec/ruby/library/cgi/htmlextension/frame_spec.rb2
-rw-r--r--spec/ruby/library/cgi/htmlextension/frameset_spec.rb2
-rw-r--r--spec/ruby/library/cgi/htmlextension/hidden_spec.rb2
-rw-r--r--spec/ruby/library/cgi/htmlextension/html_spec.rb2
-rw-r--r--spec/ruby/library/cgi/htmlextension/image_button_spec.rb2
-rw-r--r--spec/ruby/library/cgi/htmlextension/img_spec.rb2
-rw-r--r--spec/ruby/library/cgi/htmlextension/multipart_form_spec.rb4
-rw-r--r--spec/ruby/library/cgi/htmlextension/password_field_spec.rb2
-rw-r--r--spec/ruby/library/cgi/htmlextension/popup_menu_spec.rb2
-rw-r--r--spec/ruby/library/cgi/htmlextension/radio_button_spec.rb2
-rw-r--r--spec/ruby/library/cgi/htmlextension/radio_group_spec.rb2
-rw-r--r--spec/ruby/library/cgi/htmlextension/reset_spec.rb2
-rw-r--r--spec/ruby/library/cgi/htmlextension/scrolling_list_spec.rb2
-rw-r--r--spec/ruby/library/cgi/htmlextension/submit_spec.rb2
-rw-r--r--spec/ruby/library/cgi/htmlextension/text_field_spec.rb2
-rw-r--r--spec/ruby/library/cgi/htmlextension/textarea_spec.rb2
-rw-r--r--spec/ruby/library/cgi/http_header_spec.rb2
-rw-r--r--spec/ruby/library/cgi/initialize_spec.rb68
-rw-r--r--spec/ruby/library/cgi/out_spec.rb4
-rw-r--r--spec/ruby/library/cgi/parse_spec.rb2
-rw-r--r--spec/ruby/library/cgi/pretty_spec.rb2
-rw-r--r--spec/ruby/library/cgi/print_spec.rb2
-rw-r--r--spec/ruby/library/cgi/queryextension/accept_charset_spec.rb2
-rw-r--r--spec/ruby/library/cgi/queryextension/accept_encoding_spec.rb2
-rw-r--r--spec/ruby/library/cgi/queryextension/accept_language_spec.rb2
-rw-r--r--spec/ruby/library/cgi/queryextension/accept_spec.rb2
-rw-r--r--spec/ruby/library/cgi/queryextension/auth_type_spec.rb2
-rw-r--r--spec/ruby/library/cgi/queryextension/cache_control_spec.rb2
-rw-r--r--spec/ruby/library/cgi/queryextension/content_length_spec.rb6
-rw-r--r--spec/ruby/library/cgi/queryextension/content_type_spec.rb2
-rw-r--r--spec/ruby/library/cgi/queryextension/cookies_spec.rb2
-rw-r--r--spec/ruby/library/cgi/queryextension/element_reference_spec.rb4
-rw-r--r--spec/ruby/library/cgi/queryextension/from_spec.rb2
-rw-r--r--spec/ruby/library/cgi/queryextension/gateway_interface_spec.rb2
-rw-r--r--spec/ruby/library/cgi/queryextension/has_key_spec.rb2
-rw-r--r--spec/ruby/library/cgi/queryextension/host_spec.rb2
-rw-r--r--spec/ruby/library/cgi/queryextension/include_spec.rb2
-rw-r--r--spec/ruby/library/cgi/queryextension/key_spec.rb2
-rw-r--r--spec/ruby/library/cgi/queryextension/keys_spec.rb2
-rw-r--r--spec/ruby/library/cgi/queryextension/multipart_spec.rb4
-rw-r--r--spec/ruby/library/cgi/queryextension/negotiate_spec.rb2
-rw-r--r--spec/ruby/library/cgi/queryextension/params_spec.rb2
-rw-r--r--spec/ruby/library/cgi/queryextension/path_info_spec.rb2
-rw-r--r--spec/ruby/library/cgi/queryextension/path_translated_spec.rb2
-rw-r--r--spec/ruby/library/cgi/queryextension/pragma_spec.rb2
-rw-r--r--spec/ruby/library/cgi/queryextension/query_string_spec.rb2
-rw-r--r--spec/ruby/library/cgi/queryextension/raw_cookie2_spec.rb2
-rw-r--r--spec/ruby/library/cgi/queryextension/raw_cookie_spec.rb2
-rw-r--r--spec/ruby/library/cgi/queryextension/referer_spec.rb2
-rw-r--r--spec/ruby/library/cgi/queryextension/remote_addr_spec.rb2
-rw-r--r--spec/ruby/library/cgi/queryextension/remote_host_spec.rb2
-rw-r--r--spec/ruby/library/cgi/queryextension/remote_ident_spec.rb2
-rw-r--r--spec/ruby/library/cgi/queryextension/remote_user_spec.rb2
-rw-r--r--spec/ruby/library/cgi/queryextension/request_method_spec.rb2
-rw-r--r--spec/ruby/library/cgi/queryextension/script_name_spec.rb2
-rw-r--r--spec/ruby/library/cgi/queryextension/server_name_spec.rb2
-rw-r--r--spec/ruby/library/cgi/queryextension/server_port_spec.rb6
-rw-r--r--spec/ruby/library/cgi/queryextension/server_protocol_spec.rb2
-rw-r--r--spec/ruby/library/cgi/queryextension/server_software_spec.rb2
-rw-r--r--spec/ruby/library/cgi/queryextension/shared/has_key.rb6
-rw-r--r--spec/ruby/library/cgi/queryextension/user_agent_spec.rb2
-rw-r--r--spec/ruby/library/cgi/rfc1123_date_spec.rb2
-rw-r--r--spec/ruby/library/cgi/shared/http_header.rb10
-rw-r--r--spec/ruby/library/cgi/unescapeElement_spec.rb4
-rw-r--r--spec/ruby/library/cgi/unescapeURIComponent_spec.rb128
-rw-r--r--spec/ruby/library/cgi/unescape_spec.rb4
-rw-r--r--spec/ruby/library/coverage/result_spec.rb4
-rw-r--r--spec/ruby/library/coverage/start_spec.rb6
-rw-r--r--spec/ruby/library/coverage/supported_spec.rb6
-rw-r--r--spec/ruby/library/csv/generate_spec.rb2
-rw-r--r--spec/ruby/library/csv/parse_spec.rb4
-rw-r--r--spec/ruby/library/csv/readlines_spec.rb2
-rw-r--r--spec/ruby/library/date/add_month_spec.rb8
-rw-r--r--spec/ruby/library/date/add_spec.rb8
-rw-r--r--spec/ruby/library/date/asctime_spec.rb5
-rw-r--r--spec/ruby/library/date/commercial_spec.rb46
-rw-r--r--spec/ruby/library/date/constants_spec.rb4
-rw-r--r--spec/ruby/library/date/ctime_spec.rb4
-rw-r--r--spec/ruby/library/date/deconstruct_keys_spec.rb10
-rw-r--r--spec/ruby/library/date/eql_spec.rb4
-rw-r--r--spec/ruby/library/date/friday_spec.rb4
-rw-r--r--spec/ruby/library/date/gregorian_leap_spec.rb10
-rw-r--r--spec/ruby/library/date/gregorian_spec.rb6
-rw-r--r--spec/ruby/library/date/iso8601_spec.rb8
-rw-r--r--spec/ruby/library/date/jd_spec.rb15
-rw-r--r--spec/ruby/library/date/julian_leap_spec.rb10
-rw-r--r--spec/ruby/library/date/julian_spec.rb4
-rw-r--r--spec/ruby/library/date/mday_spec.rb4
-rw-r--r--spec/ruby/library/date/minus_month_spec.rb8
-rw-r--r--spec/ruby/library/date/minus_spec.rb6
-rw-r--r--spec/ruby/library/date/mon_spec.rb5
-rw-r--r--spec/ruby/library/date/monday_spec.rb2
-rw-r--r--spec/ruby/library/date/month_spec.rb6
-rw-r--r--spec/ruby/library/date/ordinal_spec.rb14
-rw-r--r--spec/ruby/library/date/parse_spec.rb6
-rw-r--r--spec/ruby/library/date/plus_spec.rb2
-rw-r--r--spec/ruby/library/date/saturday_spec.rb2
-rw-r--r--spec/ruby/library/date/shared/civil.rb16
-rw-r--r--spec/ruby/library/date/shared/commercial.rb39
-rw-r--r--spec/ruby/library/date/shared/jd.rb14
-rw-r--r--spec/ruby/library/date/shared/month.rb6
-rw-r--r--spec/ruby/library/date/shared/ordinal.rb22
-rw-r--r--spec/ruby/library/date/shared/valid_civil.rb36
-rw-r--r--spec/ruby/library/date/shared/valid_commercial.rb34
-rw-r--r--spec/ruby/library/date/shared/valid_jd.rb20
-rw-r--r--spec/ruby/library/date/shared/valid_ordinal.rb26
-rw-r--r--spec/ruby/library/date/succ_spec.rb4
-rw-r--r--spec/ruby/library/date/sunday_spec.rb2
-rw-r--r--spec/ruby/library/date/thursday_spec.rb2
-rw-r--r--spec/ruby/library/date/today_spec.rb2
-rw-r--r--spec/ruby/library/date/tuesday_spec.rb2
-rw-r--r--spec/ruby/library/date/valid_civil_spec.rb9
-rw-r--r--spec/ruby/library/date/valid_commercial_spec.rb33
-rw-r--r--spec/ruby/library/date/valid_date_spec.rb35
-rw-r--r--spec/ruby/library/date/valid_jd_spec.rb18
-rw-r--r--spec/ruby/library/date/valid_ordinal_spec.rb26
-rw-r--r--spec/ruby/library/date/wednesday_spec.rb2
-rw-r--r--spec/ruby/library/datetime/deconstruct_keys_spec.rb10
-rw-r--r--spec/ruby/library/datetime/hour_spec.rb13
-rw-r--r--spec/ruby/library/datetime/iso8601_spec.rb4
-rw-r--r--spec/ruby/library/datetime/min_spec.rb8
-rw-r--r--spec/ruby/library/datetime/minute_spec.rb40
-rw-r--r--spec/ruby/library/datetime/new_spec.rb2
-rw-r--r--spec/ruby/library/datetime/now_spec.rb2
-rw-r--r--spec/ruby/library/datetime/parse_spec.rb12
-rw-r--r--spec/ruby/library/datetime/rfc2822_spec.rb2
-rw-r--r--spec/ruby/library/datetime/sec_spec.rb8
-rw-r--r--spec/ruby/library/datetime/second_fraction_spec.rb4
-rw-r--r--spec/ruby/library/datetime/second_spec.rb43
-rw-r--r--spec/ruby/library/datetime/shared/min.rb40
-rw-r--r--spec/ruby/library/datetime/shared/sec.rb45
-rw-r--r--spec/ruby/library/datetime/to_date_spec.rb2
-rw-r--r--spec/ruby/library/datetime/to_s_spec.rb2
-rw-r--r--spec/ruby/library/datetime/to_time_spec.rb2
-rw-r--r--spec/ruby/library/delegate/delegate_class/instance_method_spec.rb14
-rw-r--r--spec/ruby/library/delegate/delegate_class/instance_methods_spec.rb12
-rw-r--r--spec/ruby/library/delegate/delegate_class/private_instance_methods_spec.rb12
-rw-r--r--spec/ruby/library/delegate/delegate_class/protected_instance_methods_spec.rb12
-rw-r--r--spec/ruby/library/delegate/delegate_class/public_instance_methods_spec.rb10
-rw-r--r--spec/ruby/library/delegate/delegator/eql_spec.rb8
-rw-r--r--spec/ruby/library/delegate/delegator/equal_spec.rb6
-rw-r--r--spec/ruby/library/delegate/delegator/equal_value_spec.rb6
-rw-r--r--spec/ruby/library/delegate/delegator/frozen_spec.rb14
-rw-r--r--spec/ruby/library/delegate/delegator/marshal_spec.rb2
-rw-r--r--spec/ruby/library/delegate/delegator/method_spec.rb18
-rw-r--r--spec/ruby/library/delegate/delegator/methods_spec.rb14
-rw-r--r--spec/ruby/library/delegate/delegator/not_equal_spec.rb6
-rw-r--r--spec/ruby/library/delegate/delegator/private_methods_spec.rb8
-rw-r--r--spec/ruby/library/delegate/delegator/protected_methods_spec.rb4
-rw-r--r--spec/ruby/library/delegate/delegator/public_methods_spec.rb4
-rw-r--r--spec/ruby/library/delegate/delegator/send_spec.rb8
-rw-r--r--spec/ruby/library/delegate/delegator/tap_spec.rb2
-rw-r--r--spec/ruby/library/digest/bubblebabble_spec.rb6
-rw-r--r--spec/ruby/library/digest/hexencode_spec.rb4
-rw-r--r--spec/ruby/library/digest/instance/append_spec.rb8
-rw-r--r--spec/ruby/library/digest/instance/shared/update.rb8
-rw-r--r--spec/ruby/library/digest/instance/update_spec.rb5
-rw-r--r--spec/ruby/library/digest/md5/append_spec.rb7
-rw-r--r--spec/ruby/library/digest/md5/file_spec.rb8
-rw-r--r--spec/ruby/library/digest/md5/length_spec.rb8
-rw-r--r--spec/ruby/library/digest/md5/shared/length.rb8
-rw-r--r--spec/ruby/library/digest/md5/shared/update.rb7
-rw-r--r--spec/ruby/library/digest/md5/size_spec.rb5
-rw-r--r--spec/ruby/library/digest/md5/update_spec.rb7
-rw-r--r--spec/ruby/library/digest/sha1/file_spec.rb8
-rw-r--r--spec/ruby/library/digest/sha256/append_spec.rb7
-rw-r--r--spec/ruby/library/digest/sha256/file_spec.rb8
-rw-r--r--spec/ruby/library/digest/sha256/length_spec.rb8
-rw-r--r--spec/ruby/library/digest/sha256/shared/length.rb8
-rw-r--r--spec/ruby/library/digest/sha256/shared/update.rb7
-rw-r--r--spec/ruby/library/digest/sha256/size_spec.rb5
-rw-r--r--spec/ruby/library/digest/sha256/update_spec.rb7
-rw-r--r--spec/ruby/library/digest/sha384/append_spec.rb7
-rw-r--r--spec/ruby/library/digest/sha384/file_spec.rb8
-rw-r--r--spec/ruby/library/digest/sha384/length_spec.rb8
-rw-r--r--spec/ruby/library/digest/sha384/shared/length.rb8
-rw-r--r--spec/ruby/library/digest/sha384/shared/update.rb7
-rw-r--r--spec/ruby/library/digest/sha384/size_spec.rb7
-rw-r--r--spec/ruby/library/digest/sha384/update_spec.rb7
-rw-r--r--spec/ruby/library/digest/sha512/append_spec.rb7
-rw-r--r--spec/ruby/library/digest/sha512/file_spec.rb8
-rw-r--r--spec/ruby/library/digest/sha512/length_spec.rb8
-rw-r--r--spec/ruby/library/digest/sha512/shared/length.rb8
-rw-r--r--spec/ruby/library/digest/sha512/shared/update.rb7
-rw-r--r--spec/ruby/library/digest/sha512/size_spec.rb7
-rw-r--r--spec/ruby/library/digest/sha512/update_spec.rb7
-rw-r--r--spec/ruby/library/erb/filename_spec.rb4
-rw-r--r--spec/ruby/library/erb/new_spec.rb28
-rw-r--r--spec/ruby/library/erb/result_spec.rb4
-rw-r--r--spec/ruby/library/erb/run_spec.rb4
-rw-r--r--spec/ruby/library/etc/confstr_spec.rb4
-rw-r--r--spec/ruby/library/etc/getgrgid_spec.rb8
-rw-r--r--spec/ruby/library/etc/getgrnam_spec.rb2
-rw-r--r--spec/ruby/library/etc/getlogin_spec.rb4
-rw-r--r--spec/ruby/library/etc/getpwnam_spec.rb2
-rw-r--r--spec/ruby/library/etc/getpwuid_spec.rb2
-rw-r--r--spec/ruby/library/etc/group_spec.rb4
-rw-r--r--spec/ruby/library/etc/nprocessors_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.rb2
-rw-r--r--spec/ruby/library/expect/expect_spec.rb4
-rw-r--r--spec/ruby/library/fiddle/handle/initialize_spec.rb2
-rw-r--r--spec/ruby/library/find/find_spec.rb2
-rw-r--r--spec/ruby/library/getoptlong/each_option_spec.rb18
-rw-r--r--spec/ruby/library/getoptlong/each_spec.rb5
-rw-r--r--spec/ruby/library/getoptlong/error_message_spec.rb2
-rw-r--r--spec/ruby/library/getoptlong/get_option_spec.rb5
-rw-r--r--spec/ruby/library/getoptlong/get_spec.rb62
-rw-r--r--spec/ruby/library/getoptlong/ordering_spec.rb4
-rw-r--r--spec/ruby/library/getoptlong/set_options_spec.rb14
-rw-r--r--spec/ruby/library/getoptlong/shared/each.rb18
-rw-r--r--spec/ruby/library/getoptlong/shared/get.rb62
-rw-r--r--spec/ruby/library/io-wait/wait_spec.rb12
-rw-r--r--spec/ruby/library/ipaddr/new_spec.rb8
-rw-r--r--spec/ruby/library/ipaddr/operator_spec.rb16
-rw-r--r--spec/ruby/library/ipaddr/reverse_spec.rb4
-rw-r--r--spec/ruby/library/logger/device/new_spec.rb8
-rw-r--r--spec/ruby/library/logger/logger/add_spec.rb6
-rw-r--r--spec/ruby/library/logger/logger/datetime_format_spec.rb2
-rw-r--r--spec/ruby/library/logger/logger/new_spec.rb10
-rw-r--r--spec/ruby/library/logger/logger/unknown_spec.rb2
-rw-r--r--spec/ruby/library/matrix/I_spec.rb6
-rw-r--r--spec/ruby/library/matrix/antisymmetric_spec.rb8
-rw-r--r--spec/ruby/library/matrix/build_spec.rb20
-rw-r--r--spec/ruby/library/matrix/clone_spec.rb8
-rw-r--r--spec/ruby/library/matrix/coerce_spec.rb2
-rw-r--r--spec/ruby/library/matrix/collect_spec.rb6
-rw-r--r--spec/ruby/library/matrix/column_spec.rb6
-rw-r--r--spec/ruby/library/matrix/column_vector_spec.rb6
-rw-r--r--spec/ruby/library/matrix/column_vectors_spec.rb4
-rw-r--r--spec/ruby/library/matrix/columns_spec.rb4
-rw-r--r--spec/ruby/library/matrix/conj_spec.rb6
-rw-r--r--spec/ruby/library/matrix/conjugate_spec.rb18
-rw-r--r--spec/ruby/library/matrix/constructor_spec.rb20
-rw-r--r--spec/ruby/library/matrix/det_spec.rb5
-rw-r--r--spec/ruby/library/matrix/determinant_spec.rb36
-rw-r--r--spec/ruby/library/matrix/diagonal_spec.rb16
-rw-r--r--spec/ruby/library/matrix/divide_spec.rb16
-rw-r--r--spec/ruby/library/matrix/each_spec.rb10
-rw-r--r--spec/ruby/library/matrix/each_with_index_spec.rb10
-rw-r--r--spec/ruby/library/matrix/eigenvalue_decomposition/initialize_spec.rb6
-rw-r--r--spec/ruby/library/matrix/element_reference_spec.rb4
-rw-r--r--spec/ruby/library/matrix/empty_spec.rb22
-rw-r--r--spec/ruby/library/matrix/eql_spec.rb2
-rw-r--r--spec/ruby/library/matrix/exponent_spec.rb10
-rw-r--r--spec/ruby/library/matrix/find_index_spec.rb16
-rw-r--r--spec/ruby/library/matrix/hash_spec.rb2
-rw-r--r--spec/ruby/library/matrix/hermitian_spec.rb12
-rw-r--r--spec/ruby/library/matrix/identity_spec.rb18
-rw-r--r--spec/ruby/library/matrix/imag_spec.rb6
-rw-r--r--spec/ruby/library/matrix/imaginary_spec.rb19
-rw-r--r--spec/ruby/library/matrix/inv_spec.rb7
-rw-r--r--spec/ruby/library/matrix/inverse_spec.rb36
-rw-r--r--spec/ruby/library/matrix/lower_triangular_spec.rb22
-rw-r--r--spec/ruby/library/matrix/lup_decomposition/determinant_spec.rb2
-rw-r--r--spec/ruby/library/matrix/lup_decomposition/initialize_spec.rb4
-rw-r--r--spec/ruby/library/matrix/lup_decomposition/l_spec.rb2
-rw-r--r--spec/ruby/library/matrix/lup_decomposition/p_spec.rb2
-rw-r--r--spec/ruby/library/matrix/lup_decomposition/solve_spec.rb6
-rw-r--r--spec/ruby/library/matrix/lup_decomposition/to_a_spec.rb4
-rw-r--r--spec/ruby/library/matrix/lup_decomposition/u_spec.rb2
-rw-r--r--spec/ruby/library/matrix/map_spec.rb24
-rw-r--r--spec/ruby/library/matrix/minor_spec.rb2
-rw-r--r--spec/ruby/library/matrix/minus_spec.rb20
-rw-r--r--spec/ruby/library/matrix/multiply_spec.rb14
-rw-r--r--spec/ruby/library/matrix/new_spec.rb2
-rw-r--r--spec/ruby/library/matrix/normal_spec.rb2
-rw-r--r--spec/ruby/library/matrix/orthogonal_spec.rb2
-rw-r--r--spec/ruby/library/matrix/permutation_spec.rb14
-rw-r--r--spec/ruby/library/matrix/plus_spec.rb20
-rw-r--r--spec/ruby/library/matrix/real_spec.rb12
-rw-r--r--spec/ruby/library/matrix/rect_spec.rb6
-rw-r--r--spec/ruby/library/matrix/rectangular_spec.rb17
-rw-r--r--spec/ruby/library/matrix/regular_spec.rb12
-rw-r--r--spec/ruby/library/matrix/round_spec.rb2
-rw-r--r--spec/ruby/library/matrix/row_spec.rb6
-rw-r--r--spec/ruby/library/matrix/row_vector_spec.rb4
-rw-r--r--spec/ruby/library/matrix/row_vectors_spec.rb4
-rw-r--r--spec/ruby/library/matrix/rows_spec.rb8
-rw-r--r--spec/ruby/library/matrix/scalar_spec.rb4
-rw-r--r--spec/ruby/library/matrix/shared/collect.rb26
-rw-r--r--spec/ruby/library/matrix/shared/conjugate.rb20
-rw-r--r--spec/ruby/library/matrix/shared/determinant.rb38
-rw-r--r--spec/ruby/library/matrix/shared/equal_value.rb20
-rw-r--r--spec/ruby/library/matrix/shared/identity.rb19
-rw-r--r--spec/ruby/library/matrix/shared/imaginary.rb20
-rw-r--r--spec/ruby/library/matrix/shared/inverse.rb38
-rw-r--r--spec/ruby/library/matrix/shared/rectangular.rb18
-rw-r--r--spec/ruby/library/matrix/shared/trace.rb12
-rw-r--r--spec/ruby/library/matrix/shared/transpose.rb19
-rw-r--r--spec/ruby/library/matrix/singular_spec.rb12
-rw-r--r--spec/ruby/library/matrix/square_spec.rb16
-rw-r--r--spec/ruby/library/matrix/symmetric_spec.rb8
-rw-r--r--spec/ruby/library/matrix/t_spec.rb8
-rw-r--r--spec/ruby/library/matrix/tr_spec.rb5
-rw-r--r--spec/ruby/library/matrix/trace_spec.rb9
-rw-r--r--spec/ruby/library/matrix/transpose_spec.rb17
-rw-r--r--spec/ruby/library/matrix/unit_spec.rb6
-rw-r--r--spec/ruby/library/matrix/unitary_spec.rb2
-rw-r--r--spec/ruby/library/matrix/upper_triangular_spec.rb22
-rw-r--r--spec/ruby/library/matrix/vector/cross_product_spec.rb2
-rw-r--r--spec/ruby/library/matrix/vector/each2_spec.rb12
-rw-r--r--spec/ruby/library/matrix/vector/eql_spec.rb4
-rw-r--r--spec/ruby/library/matrix/vector/inner_product_spec.rb2
-rw-r--r--spec/ruby/library/matrix/vector/normalize_spec.rb4
-rw-r--r--spec/ruby/library/matrix/zero_spec.rb4
-rw-r--r--spec/ruby/library/monitor/exit_spec.rb2
-rw-r--r--spec/ruby/library/monitor/mon_initialize_spec.rb2
-rw-r--r--spec/ruby/library/monitor/synchronize_spec.rb4
-rw-r--r--spec/ruby/library/net-ftp/FTPError_spec.rb11
-rw-r--r--spec/ruby/library/net-ftp/FTPPermError_spec.rb17
-rw-r--r--spec/ruby/library/net-ftp/FTPProtoError_spec.rb17
-rw-r--r--spec/ruby/library/net-ftp/FTPReplyError_spec.rb17
-rw-r--r--spec/ruby/library/net-ftp/FTPTempError_spec.rb17
-rw-r--r--spec/ruby/library/net-ftp/abort_spec.rb97
-rw-r--r--spec/ruby/library/net-ftp/acct_spec.rb111
-rw-r--r--spec/ruby/library/net-ftp/binary_spec.rb33
-rw-r--r--spec/ruby/library/net-ftp/chdir_spec.rb145
-rw-r--r--spec/ruby/library/net-ftp/close_spec.rb47
-rw-r--r--spec/ruby/library/net-ftp/closed_spec.rb31
-rw-r--r--spec/ruby/library/net-ftp/connect_spec.rb81
-rw-r--r--spec/ruby/library/net-ftp/debug_mode_spec.rb33
-rw-r--r--spec/ruby/library/net-ftp/default_passive_spec.rb11
-rw-r--r--spec/ruby/library/net-ftp/delete_spec.rb113
-rw-r--r--spec/ruby/library/net-ftp/dir_spec.rb13
-rw-r--r--spec/ruby/library/net-ftp/fixtures/server.rb436
-rw-r--r--spec/ruby/library/net-ftp/get_spec.rb31
-rw-r--r--spec/ruby/library/net-ftp/getbinaryfile_spec.rb13
-rw-r--r--spec/ruby/library/net-ftp/getdir_spec.rb11
-rw-r--r--spec/ruby/library/net-ftp/gettextfile_spec.rb13
-rw-r--r--spec/ruby/library/net-ftp/help_spec.rb103
-rw-r--r--spec/ruby/library/net-ftp/initialize_spec.rb557
-rw-r--r--spec/ruby/library/net-ftp/last_response_code_spec.rb13
-rw-r--r--spec/ruby/library/net-ftp/last_response_spec.rb39
-rw-r--r--spec/ruby/library/net-ftp/lastresp_spec.rb13
-rw-r--r--spec/ruby/library/net-ftp/list_spec.rb13
-rw-r--r--spec/ruby/library/net-ftp/login_spec.rb379
-rw-r--r--spec/ruby/library/net-ftp/ls_spec.rb13
-rw-r--r--spec/ruby/library/net-ftp/mdtm_spec.rb59
-rw-r--r--spec/ruby/library/net-ftp/mkdir_spec.rb97
-rw-r--r--spec/ruby/library/net-ftp/mtime_spec.rb73
-rw-r--r--spec/ruby/library/net-ftp/nlst_spec.rb141
-rw-r--r--spec/ruby/library/net-ftp/noop_spec.rb59
-rw-r--r--spec/ruby/library/net-ftp/open_spec.rb73
-rw-r--r--spec/ruby/library/net-ftp/passive_spec.rb39
-rw-r--r--spec/ruby/library/net-ftp/put_spec.rb31
-rw-r--r--spec/ruby/library/net-ftp/putbinaryfile_spec.rb13
-rw-r--r--spec/ruby/library/net-ftp/puttextfile_spec.rb13
-rw-r--r--spec/ruby/library/net-ftp/pwd_spec.rb101
-rw-r--r--spec/ruby/library/net-ftp/quit_spec.rb51
-rw-r--r--spec/ruby/library/net-ftp/rename_spec.rb159
-rw-r--r--spec/ruby/library/net-ftp/resume_spec.rb33
-rw-r--r--spec/ruby/library/net-ftp/retrbinary_spec.rb47
-rw-r--r--spec/ruby/library/net-ftp/retrlines_spec.rb55
-rw-r--r--spec/ruby/library/net-ftp/return_code_spec.rb35
-rw-r--r--spec/ruby/library/net-ftp/rmdir_spec.rb111
-rw-r--r--spec/ruby/library/net-ftp/sendcmd_spec.rb103
-rw-r--r--spec/ruby/library/net-ftp/set_socket_spec.rb13
-rw-r--r--spec/ruby/library/net-ftp/shared/getbinaryfile.rb226
-rw-r--r--spec/ruby/library/net-ftp/shared/gettextfile.rb162
-rw-r--r--spec/ruby/library/net-ftp/shared/last_response_code.rb40
-rw-r--r--spec/ruby/library/net-ftp/shared/list.rb176
-rw-r--r--spec/ruby/library/net-ftp/shared/putbinaryfile.rb258
-rw-r--r--spec/ruby/library/net-ftp/shared/puttextfile.rb214
-rw-r--r--spec/ruby/library/net-ftp/shared/pwd.rb4
-rw-r--r--spec/ruby/library/net-ftp/site_spec.rb101
-rw-r--r--spec/ruby/library/net-ftp/size_spec.rb91
-rw-r--r--spec/ruby/library/net-ftp/spec_helper.rb8
-rw-r--r--spec/ruby/library/net-ftp/status_spec.rb105
-rw-r--r--spec/ruby/library/net-ftp/storbinary_spec.rb73
-rw-r--r--spec/ruby/library/net-ftp/storlines_spec.rb65
-rw-r--r--spec/ruby/library/net-ftp/system_spec.rb91
-rw-r--r--spec/ruby/library/net-ftp/voidcmd_spec.rb103
-rw-r--r--spec/ruby/library/net-ftp/welcome_spec.rb39
-rw-r--r--spec/ruby/library/net-http/HTTPServerException_spec.rb4
-rw-r--r--spec/ruby/library/net-http/http/Proxy_spec.rb6
-rw-r--r--spec/ruby/library/net-http/http/active_spec.rb6
-rw-r--r--spec/ruby/library/net-http/http/copy_spec.rb2
-rw-r--r--spec/ruby/library/net-http/http/default_port_spec.rb2
-rw-r--r--spec/ruby/library/net-http/http/delete_spec.rb2
-rw-r--r--spec/ruby/library/net-http/http/finish_spec.rb4
-rw-r--r--spec/ruby/library/net-http/http/get2_spec.rb6
-rw-r--r--spec/ruby/library/net-http/http/get_spec.rb2
-rw-r--r--spec/ruby/library/net-http/http/head2_spec.rb6
-rw-r--r--spec/ruby/library/net-http/http/head_spec.rb4
-rw-r--r--spec/ruby/library/net-http/http/http_default_port_spec.rb2
-rw-r--r--spec/ruby/library/net-http/http/https_default_port_spec.rb2
-rw-r--r--spec/ruby/library/net-http/http/initialize_spec.rb10
-rw-r--r--spec/ruby/library/net-http/http/inspect_spec.rb2
-rw-r--r--spec/ruby/library/net-http/http/is_version_1_1_spec.rb5
-rw-r--r--spec/ruby/library/net-http/http/is_version_1_2_spec.rb5
-rw-r--r--spec/ruby/library/net-http/http/lock_spec.rb2
-rw-r--r--spec/ruby/library/net-http/http/mkcol_spec.rb2
-rw-r--r--spec/ruby/library/net-http/http/move_spec.rb2
-rw-r--r--spec/ruby/library/net-http/http/new_spec.rb40
-rw-r--r--spec/ruby/library/net-http/http/newobj_spec.rb12
-rw-r--r--spec/ruby/library/net-http/http/open_timeout_spec.rb8
-rw-r--r--spec/ruby/library/net-http/http/options_spec.rb2
-rw-r--r--spec/ruby/library/net-http/http/port_spec.rb2
-rw-r--r--spec/ruby/library/net-http/http/post2_spec.rb6
-rw-r--r--spec/ruby/library/net-http/http/post_spec.rb10
-rw-r--r--spec/ruby/library/net-http/http/propfind_spec.rb2
-rw-r--r--spec/ruby/library/net-http/http/proppatch_spec.rb2
-rw-r--r--spec/ruby/library/net-http/http/proxy_address_spec.rb4
-rw-r--r--spec/ruby/library/net-http/http/proxy_class_spec.rb4
-rw-r--r--spec/ruby/library/net-http/http/proxy_pass_spec.rb8
-rw-r--r--spec/ruby/library/net-http/http/proxy_port_spec.rb12
-rw-r--r--spec/ruby/library/net-http/http/proxy_user_spec.rb8
-rw-r--r--spec/ruby/library/net-http/http/put2_spec.rb6
-rw-r--r--spec/ruby/library/net-http/http/put_spec.rb2
-rw-r--r--spec/ruby/library/net-http/http/read_timeout_spec.rb8
-rw-r--r--spec/ruby/library/net-http/http/request_get_spec.rb41
-rw-r--r--spec/ruby/library/net-http/http/request_head_spec.rb41
-rw-r--r--spec/ruby/library/net-http/http/request_post_spec.rb41
-rw-r--r--spec/ruby/library/net-http/http/request_put_spec.rb41
-rw-r--r--spec/ruby/library/net-http/http/request_spec.rb8
-rw-r--r--spec/ruby/library/net-http/http/request_types_spec.rb56
-rw-r--r--spec/ruby/library/net-http/http/send_request_spec.rb8
-rw-r--r--spec/ruby/library/net-http/http/set_debug_output_spec.rb2
-rw-r--r--spec/ruby/library/net-http/http/shared/request_get.rb41
-rw-r--r--spec/ruby/library/net-http/http/shared/request_head.rb41
-rw-r--r--spec/ruby/library/net-http/http/shared/request_post.rb41
-rw-r--r--spec/ruby/library/net-http/http/shared/request_put.rb41
-rw-r--r--spec/ruby/library/net-http/http/shared/started.rb26
-rw-r--r--spec/ruby/library/net-http/http/shared/version_1_1.rb6
-rw-r--r--spec/ruby/library/net-http/http/shared/version_1_2.rb6
-rw-r--r--spec/ruby/library/net-http/http/start_spec.rb26
-rw-r--r--spec/ruby/library/net-http/http/started_spec.rb26
-rw-r--r--spec/ruby/library/net-http/http/trace_spec.rb2
-rw-r--r--spec/ruby/library/net-http/http/unlock_spec.rb2
-rw-r--r--spec/ruby/library/net-http/http/use_ssl_spec.rb2
-rw-r--r--spec/ruby/library/net-http/http/version_1_1_spec.rb6
-rw-r--r--spec/ruby/library/net-http/http/version_1_2_spec.rb12
-rw-r--r--spec/ruby/library/net-http/httpgenericrequest/body_exist_spec.rb4
-rw-r--r--spec/ruby/library/net-http/httpgenericrequest/body_spec.rb4
-rw-r--r--spec/ruby/library/net-http/httpgenericrequest/body_stream_spec.rb8
-rw-r--r--spec/ruby/library/net-http/httpgenericrequest/exec_spec.rb6
-rw-r--r--spec/ruby/library/net-http/httpgenericrequest/request_body_permitted_spec.rb4
-rw-r--r--spec/ruby/library/net-http/httpgenericrequest/response_body_permitted_spec.rb4
-rw-r--r--spec/ruby/library/net-http/httpgenericrequest/set_body_internal_spec.rb4
-rw-r--r--spec/ruby/library/net-http/httpheader/canonical_each_spec.rb7
-rw-r--r--spec/ruby/library/net-http/httpheader/chunked_spec.rb8
-rw-r--r--spec/ruby/library/net-http/httpheader/content_length_spec.rb12
-rw-r--r--spec/ruby/library/net-http/httpheader/content_range_spec.rb8
-rw-r--r--spec/ruby/library/net-http/httpheader/content_type_spec.rb8
-rw-r--r--spec/ruby/library/net-http/httpheader/delete_spec.rb8
-rw-r--r--spec/ruby/library/net-http/httpheader/each_capitalized_name_spec.rb2
-rw-r--r--spec/ruby/library/net-http/httpheader/each_capitalized_spec.rb31
-rw-r--r--spec/ruby/library/net-http/httpheader/each_header_spec.rb31
-rw-r--r--spec/ruby/library/net-http/httpheader/each_key_spec.rb31
-rw-r--r--spec/ruby/library/net-http/httpheader/each_name_spec.rb6
-rw-r--r--spec/ruby/library/net-http/httpheader/each_spec.rb7
-rw-r--r--spec/ruby/library/net-http/httpheader/each_value_spec.rb2
-rw-r--r--spec/ruby/library/net-http/httpheader/element_reference_spec.rb4
-rw-r--r--spec/ruby/library/net-http/httpheader/element_set_spec.rb6
-rw-r--r--spec/ruby/library/net-http/httpheader/fetch_spec.rb2
-rw-r--r--spec/ruby/library/net-http/httpheader/form_data_spec.rb6
-rw-r--r--spec/ruby/library/net-http/httpheader/get_fields_spec.rb4
-rw-r--r--spec/ruby/library/net-http/httpheader/key_spec.rb8
-rw-r--r--spec/ruby/library/net-http/httpheader/length_spec.rb7
-rw-r--r--spec/ruby/library/net-http/httpheader/main_type_spec.rb2
-rw-r--r--spec/ruby/library/net-http/httpheader/range_length_spec.rb12
-rw-r--r--spec/ruby/library/net-http/httpheader/range_spec.rb16
-rw-r--r--spec/ruby/library/net-http/httpheader/set_content_type_spec.rb18
-rw-r--r--spec/ruby/library/net-http/httpheader/set_form_data_spec.rb27
-rw-r--r--spec/ruby/library/net-http/httpheader/set_range_spec.rb89
-rw-r--r--spec/ruby/library/net-http/httpheader/shared/each_capitalized.rb31
-rw-r--r--spec/ruby/library/net-http/httpheader/shared/each_header.rb31
-rw-r--r--spec/ruby/library/net-http/httpheader/shared/each_name.rb31
-rw-r--r--spec/ruby/library/net-http/httpheader/shared/set_content_type.rb18
-rw-r--r--spec/ruby/library/net-http/httpheader/shared/set_form_data.rb27
-rw-r--r--spec/ruby/library/net-http/httpheader/shared/set_range.rb89
-rw-r--r--spec/ruby/library/net-http/httpheader/shared/size.rb18
-rw-r--r--spec/ruby/library/net-http/httpheader/size_spec.rb18
-rw-r--r--spec/ruby/library/net-http/httpheader/sub_type_spec.rb6
-rw-r--r--spec/ruby/library/net-http/httpheader/to_hash_spec.rb2
-rw-r--r--spec/ruby/library/net-http/httprequest/initialize_spec.rb4
-rw-r--r--spec/ruby/library/net-http/httpresponse/body_spec.rb19
-rw-r--r--spec/ruby/library/net-http/httpresponse/entity_spec.rb6
-rw-r--r--spec/ruby/library/net-http/httpresponse/error_spec.rb12
-rw-r--r--spec/ruby/library/net-http/httpresponse/header_spec.rb2
-rw-r--r--spec/ruby/library/net-http/httpresponse/read_body_spec.rb14
-rw-r--r--spec/ruby/library/net-http/httpresponse/read_header_spec.rb2
-rw-r--r--spec/ruby/library/net-http/httpresponse/read_new_spec.rb2
-rw-r--r--spec/ruby/library/net-http/httpresponse/reading_body_spec.rb14
-rw-r--r--spec/ruby/library/net-http/httpresponse/response_spec.rb2
-rw-r--r--spec/ruby/library/net-http/httpresponse/shared/body.rb20
-rw-r--r--spec/ruby/library/net-http/httpresponse/value_spec.rb12
-rw-r--r--spec/ruby/library/objectspace/dump_all_spec.rb4
-rw-r--r--spec/ruby/library/objectspace/dump_spec.rb22
-rw-r--r--spec/ruby/library/objectspace/memsize_of_all_spec.rb4
-rw-r--r--spec/ruby/library/objectspace/memsize_of_spec.rb2
-rw-r--r--spec/ruby/library/objectspace/reachable_objects_from_spec.rb12
-rw-r--r--spec/ruby/library/objectspace/trace_object_allocations_spec.rb2
-rw-r--r--spec/ruby/library/observer/notify_observers_spec.rb2
-rw-r--r--spec/ruby/library/open3/popen3_spec.rb8
-rw-r--r--spec/ruby/library/openssl/cipher_spec.rb2
-rw-r--r--spec/ruby/library/openssl/digest/initialize_spec.rb16
-rw-r--r--spec/ruby/library/openssl/digest/shared/update.rb8
-rw-r--r--spec/ruby/library/openssl/fixed_length_secure_compare_spec.rb12
-rw-r--r--spec/ruby/library/openssl/kdf/pbkdf2_hmac_spec.rb42
-rw-r--r--spec/ruby/library/openssl/kdf/scrypt_spec.rb42
-rw-r--r--spec/ruby/library/openssl/random/shared/random_bytes.rb4
-rw-r--r--spec/ruby/library/openssl/secure_compare_spec.rb12
-rw-r--r--spec/ruby/library/openssl/x509/name/parse_spec.rb4
-rw-r--r--spec/ruby/library/openstruct/delete_field_spec.rb6
-rw-r--r--spec/ruby/library/openstruct/equal_value_spec.rb24
-rw-r--r--spec/ruby/library/openstruct/frozen_spec.rb12
-rw-r--r--spec/ruby/library/openstruct/initialize_spec.rb2
-rw-r--r--spec/ruby/library/openstruct/inspect_spec.rb6
-rw-r--r--spec/ruby/library/openstruct/marshal_load_spec.rb2
-rw-r--r--spec/ruby/library/openstruct/method_missing_spec.rb6
-rw-r--r--spec/ruby/library/openstruct/new_spec.rb4
-rw-r--r--spec/ruby/library/openstruct/shared/inspect.rb20
-rw-r--r--spec/ruby/library/openstruct/to_h_spec.rb10
-rw-r--r--spec/ruby/library/openstruct/to_s_spec.rb20
-rw-r--r--spec/ruby/library/pathname/birthtime_spec.rb4
-rw-r--r--spec/ruby/library/pathname/case_compare_spec.rb8
-rw-r--r--spec/ruby/library/pathname/divide_spec.rb6
-rw-r--r--spec/ruby/library/pathname/empty_spec.rb8
-rw-r--r--spec/ruby/library/pathname/glob_spec.rb4
-rw-r--r--spec/ruby/library/pathname/inspect_spec.rb2
-rw-r--r--spec/ruby/library/pathname/new_spec.rb12
-rw-r--r--spec/ruby/library/pathname/pathname_spec.rb4
-rw-r--r--spec/ruby/library/pathname/plus_spec.rb7
-rw-r--r--spec/ruby/library/pathname/realdirpath_spec.rb2
-rw-r--r--spec/ruby/library/pathname/realpath_spec.rb2
-rw-r--r--spec/ruby/library/pathname/relative_path_from_spec.rb4
-rw-r--r--spec/ruby/library/pathname/shared/plus.rb8
-rw-r--r--spec/ruby/library/prime/each_spec.rb22
-rw-r--r--spec/ruby/library/prime/instance_spec.rb8
-rw-r--r--spec/ruby/library/prime/integer/prime_division_spec.rb2
-rw-r--r--spec/ruby/library/prime/integer/prime_spec.rb14
-rw-r--r--spec/ruby/library/prime/next_spec.rb8
-rw-r--r--spec/ruby/library/prime/prime_division_spec.rb4
-rw-r--r--spec/ruby/library/prime/prime_spec.rb14
-rw-r--r--spec/ruby/library/prime/shared/next.rb8
-rw-r--r--spec/ruby/library/prime/succ_spec.rb6
-rw-r--r--spec/ruby/library/random/formatter/alphanumeric_spec.rb22
-rw-r--r--spec/ruby/library/rbconfig/rbconfig_spec.rb8
-rw-r--r--spec/ruby/library/rbconfig/sizeof/limits_spec.rb6
-rw-r--r--spec/ruby/library/rbconfig/sizeof/sizeof_spec.rb6
-rw-r--r--spec/ruby/library/rbconfig/unicode_emoji_version_spec.rb6
-rw-r--r--spec/ruby/library/rbconfig/unicode_version_spec.rb6
-rw-r--r--spec/ruby/library/readline/basic_quote_characters_spec.rb2
-rw-r--r--spec/ruby/library/readline/basic_word_break_characters_spec.rb2
-rw-r--r--spec/ruby/library/readline/completer_quote_characters_spec.rb2
-rw-r--r--spec/ruby/library/readline/completer_word_break_characters_spec.rb2
-rw-r--r--spec/ruby/library/readline/completion_append_character_spec.rb2
-rw-r--r--spec/ruby/library/readline/completion_case_fold_spec.rb2
-rw-r--r--spec/ruby/library/readline/completion_proc_spec.rb4
-rw-r--r--spec/ruby/library/readline/constants_spec.rb4
-rw-r--r--spec/ruby/library/readline/emacs_editing_mode_spec.rb2
-rw-r--r--spec/ruby/library/readline/filename_quote_characters_spec.rb2
-rw-r--r--spec/ruby/library/readline/history/append_spec.rb2
-rw-r--r--spec/ruby/library/readline/history/delete_at_spec.rb4
-rw-r--r--spec/ruby/library/readline/history/element_reference_spec.rb12
-rw-r--r--spec/ruby/library/readline/history/element_set_spec.rb4
-rw-r--r--spec/ruby/library/readline/history/empty_spec.rb6
-rw-r--r--spec/ruby/library/readline/history/history_spec.rb2
-rw-r--r--spec/ruby/library/readline/history/pop_spec.rb2
-rw-r--r--spec/ruby/library/readline/history/push_spec.rb2
-rw-r--r--spec/ruby/library/readline/history/shift_spec.rb2
-rw-r--r--spec/ruby/library/readline/vi_editing_mode_spec.rb2
-rw-r--r--spec/ruby/library/resolv/get_address_spec.rb2
-rw-r--r--spec/ruby/library/resolv/get_name_spec.rb2
-rw-r--r--spec/ruby/library/ripper/lex_spec.rb6
-rw-r--r--spec/ruby/library/rubygems/gem/load_path_insert_index_spec.rb2
-rw-r--r--spec/ruby/library/securerandom/base64_spec.rb10
-rw-r--r--spec/ruby/library/securerandom/hex_spec.rb14
-rw-r--r--spec/ruby/library/securerandom/random_bytes_spec.rb12
-rw-r--r--spec/ruby/library/securerandom/random_number_spec.rb20
-rw-r--r--spec/ruby/library/shellwords/shellwords_spec.rb4
-rw-r--r--spec/ruby/library/singleton/allocate_spec.rb2
-rw-r--r--spec/ruby/library/singleton/clone_spec.rb2
-rw-r--r--spec/ruby/library/singleton/dup_spec.rb2
-rw-r--r--spec/ruby/library/singleton/instance_spec.rb12
-rw-r--r--spec/ruby/library/singleton/load_spec.rb13
-rw-r--r--spec/ruby/library/singleton/new_spec.rb2
-rw-r--r--spec/ruby/library/socket/addrinfo/afamily_spec.rb16
-rw-r--r--spec/ruby/library/socket/addrinfo/bind_spec.rb8
-rw-r--r--spec/ruby/library/socket/addrinfo/canonname_spec.rb4
-rw-r--r--spec/ruby/library/socket/addrinfo/connect_from_spec.rb12
-rw-r--r--spec/ruby/library/socket/addrinfo/connect_spec.rb6
-rw-r--r--spec/ruby/library/socket/addrinfo/connect_to_spec.rb12
-rw-r--r--spec/ruby/library/socket/addrinfo/family_addrinfo_spec.rb62
-rw-r--r--spec/ruby/library/socket/addrinfo/foreach_spec.rb2
-rw-r--r--spec/ruby/library/socket/addrinfo/getaddrinfo_spec.rb10
-rw-r--r--spec/ruby/library/socket/addrinfo/getnameinfo_spec.rb20
-rw-r--r--spec/ruby/library/socket/addrinfo/initialize_spec.rb82
-rw-r--r--spec/ruby/library/socket/addrinfo/inspect_sockaddr_spec.rb18
-rw-r--r--spec/ruby/library/socket/addrinfo/inspect_spec.rb26
-rw-r--r--spec/ruby/library/socket/addrinfo/ip_address_spec.rb14
-rw-r--r--spec/ruby/library/socket/addrinfo/ip_port_spec.rb14
-rw-r--r--spec/ruby/library/socket/addrinfo/ip_spec.rb20
-rw-r--r--spec/ruby/library/socket/addrinfo/ip_unpack_spec.rb14
-rw-r--r--spec/ruby/library/socket/addrinfo/ipv4_loopback_spec.rb20
-rw-r--r--spec/ruby/library/socket/addrinfo/ipv4_multicast_spec.rb14
-rw-r--r--spec/ruby/library/socket/addrinfo/ipv4_private_spec.rb18
-rw-r--r--spec/ruby/library/socket/addrinfo/ipv4_spec.rb18
-rw-r--r--spec/ruby/library/socket/addrinfo/ipv6_loopback_spec.rb22
-rw-r--r--spec/ruby/library/socket/addrinfo/ipv6_multicast_spec.rb18
-rw-r--r--spec/ruby/library/socket/addrinfo/ipv6_spec.rb18
-rw-r--r--spec/ruby/library/socket/addrinfo/ipv6_to_ipv4_spec.rb20
-rw-r--r--spec/ruby/library/socket/addrinfo/listen_spec.rb4
-rw-r--r--spec/ruby/library/socket/addrinfo/marshal_dump_spec.rb52
-rw-r--r--spec/ruby/library/socket/addrinfo/marshal_load_spec.rb20
-rw-r--r--spec/ruby/library/socket/addrinfo/pfamily_spec.rb16
-rw-r--r--spec/ruby/library/socket/addrinfo/protocol_spec.rb14
-rw-r--r--spec/ruby/library/socket/addrinfo/shared/to_sockaddr.rb49
-rw-r--r--spec/ruby/library/socket/addrinfo/socktype_spec.rb14
-rw-r--r--spec/ruby/library/socket/addrinfo/tcp_spec.rb2
-rw-r--r--spec/ruby/library/socket/addrinfo/to_s_spec.rb5
-rw-r--r--spec/ruby/library/socket/addrinfo/to_sockaddr_spec.rb47
-rw-r--r--spec/ruby/library/socket/addrinfo/udp_spec.rb2
-rw-r--r--spec/ruby/library/socket/addrinfo/unix_path_spec.rb46
-rw-r--r--spec/ruby/library/socket/addrinfo/unix_spec.rb52
-rw-r--r--spec/ruby/library/socket/ancillarydata/cmsg_is_spec.rb2
-rw-r--r--spec/ruby/library/socket/ancillarydata/initialize_spec.rb34
-rw-r--r--spec/ruby/library/socket/ancillarydata/int_spec.rb4
-rw-r--r--spec/ruby/library/socket/ancillarydata/ip_pktinfo_spec.rb16
-rw-r--r--spec/ruby/library/socket/ancillarydata/ipv6_pktinfo_addr_spec.rb2
-rw-r--r--spec/ruby/library/socket/ancillarydata/ipv6_pktinfo_spec.rb10
-rw-r--r--spec/ruby/library/socket/ancillarydata/unix_rights_spec.rb8
-rw-r--r--spec/ruby/library/socket/basicsocket/close_read_spec.rb12
-rw-r--r--spec/ruby/library/socket/basicsocket/close_write_spec.rb12
-rw-r--r--spec/ruby/library/socket/basicsocket/connect_address_spec.rb86
-rw-r--r--spec/ruby/library/socket/basicsocket/do_not_reverse_lookup_spec.rb2
-rw-r--r--spec/ruby/library/socket/basicsocket/for_fd_spec.rb6
-rw-r--r--spec/ruby/library/socket/basicsocket/getpeereid_spec.rb4
-rw-r--r--spec/ruby/library/socket/basicsocket/getpeername_spec.rb2
-rw-r--r--spec/ruby/library/socket/basicsocket/getsockname_spec.rb4
-rw-r--r--spec/ruby/library/socket/basicsocket/getsockopt_spec.rb12
-rw-r--r--spec/ruby/library/socket/basicsocket/recv_nonblock_spec.rb80
-rw-r--r--spec/ruby/library/socket/basicsocket/recv_spec.rb49
-rw-r--r--spec/ruby/library/socket/basicsocket/recvmsg_nonblock_spec.rb95
-rw-r--r--spec/ruby/library/socket/basicsocket/recvmsg_spec.rb64
-rw-r--r--spec/ruby/library/socket/basicsocket/send_spec.rb14
-rw-r--r--spec/ruby/library/socket/basicsocket/sendmsg_nonblock_spec.rb6
-rw-r--r--spec/ruby/library/socket/basicsocket/sendmsg_spec.rb2
-rw-r--r--spec/ruby/library/socket/basicsocket/setsockopt_spec.rb58
-rw-r--r--spec/ruby/library/socket/basicsocket/shutdown_spec.rb44
-rw-r--r--spec/ruby/library/socket/constants/constants_spec.rb26
-rw-r--r--spec/ruby/library/socket/ipsocket/addr_spec.rb8
-rw-r--r--spec/ruby/library/socket/ipsocket/getaddress_spec.rb2
-rw-r--r--spec/ruby/library/socket/ipsocket/inspect_spec.rb24
-rw-r--r--spec/ruby/library/socket/ipsocket/peeraddr_spec.rb4
-rw-r--r--spec/ruby/library/socket/ipsocket/recvfrom_spec.rb44
-rw-r--r--spec/ruby/library/socket/option/bool_spec.rb4
-rw-r--r--spec/ruby/library/socket/option/initialize_spec.rb18
-rw-r--r--spec/ruby/library/socket/option/int_spec.rb6
-rw-r--r--spec/ruby/library/socket/option/linger_spec.rb18
-rw-r--r--spec/ruby/library/socket/option/new_spec.rb6
-rw-r--r--spec/ruby/library/socket/shared/address.rb92
-rw-r--r--spec/ruby/library/socket/shared/pack_sockaddr.rb94
-rw-r--r--spec/ruby/library/socket/shared/socketpair.rb138
-rw-r--r--spec/ruby/library/socket/socket/accept_loop_spec.rb8
-rw-r--r--spec/ruby/library/socket/socket/accept_nonblock_spec.rb24
-rw-r--r--spec/ruby/library/socket/socket/accept_spec.rb12
-rw-r--r--spec/ruby/library/socket/socket/bind_spec.rb28
-rw-r--r--spec/ruby/library/socket/socket/connect_nonblock_spec.rb10
-rw-r--r--spec/ruby/library/socket/socket/connect_spec.rb4
-rw-r--r--spec/ruby/library/socket/socket/getaddrinfo_spec.rb68
-rw-r--r--spec/ruby/library/socket/socket/gethostbyaddr_spec.rb30
-rw-r--r--spec/ruby/library/socket/socket/gethostbyname_spec.rb10
-rw-r--r--spec/ruby/library/socket/socket/getifaddrs_spec.rb40
-rw-r--r--spec/ruby/library/socket/socket/getnameinfo_spec.rb16
-rw-r--r--spec/ruby/library/socket/socket/getservbyname_spec.rb2
-rw-r--r--spec/ruby/library/socket/socket/getservbyport_spec.rb2
-rw-r--r--spec/ruby/library/socket/socket/initialize_spec.rb16
-rw-r--r--spec/ruby/library/socket/socket/ip_address_list_spec.rb10
-rw-r--r--spec/ruby/library/socket/socket/listen_spec.rb6
-rw-r--r--spec/ruby/library/socket/socket/local_address_spec.rb2
-rw-r--r--spec/ruby/library/socket/socket/pack_sockaddr_in_spec.rb6
-rw-r--r--spec/ruby/library/socket/socket/pack_sockaddr_un_spec.rb8
-rw-r--r--spec/ruby/library/socket/socket/pair_spec.rb138
-rw-r--r--spec/ruby/library/socket/socket/recvfrom_nonblock_spec.rb73
-rw-r--r--spec/ruby/library/socket/socket/recvfrom_spec.rb48
-rw-r--r--spec/ruby/library/socket/socket/remote_address_spec.rb2
-rw-r--r--spec/ruby/library/socket/socket/sockaddr_in_spec.rb48
-rw-r--r--spec/ruby/library/socket/socket/sockaddr_un_spec.rb46
-rw-r--r--spec/ruby/library/socket/socket/socketpair_spec.rb6
-rw-r--r--spec/ruby/library/socket/socket/sysaccept_spec.rb10
-rw-r--r--spec/ruby/library/socket/socket/tcp_server_loop_spec.rb4
-rw-r--r--spec/ruby/library/socket/socket/tcp_server_sockets_spec.rb8
-rw-r--r--spec/ruby/library/socket/socket/tcp_spec.rb30
-rw-r--r--spec/ruby/library/socket/socket/udp_server_loop_on_spec.rb2
-rw-r--r--spec/ruby/library/socket/socket/udp_server_loop_spec.rb2
-rw-r--r--spec/ruby/library/socket/socket/udp_server_recv_spec.rb2
-rw-r--r--spec/ruby/library/socket/socket/udp_server_sockets_spec.rb8
-rw-r--r--spec/ruby/library/socket/socket/unix_server_loop_spec.rb76
-rw-r--r--spec/ruby/library/socket/socket/unix_server_socket_spec.rb56
-rw-r--r--spec/ruby/library/socket/socket/unix_spec.rb56
-rw-r--r--spec/ruby/library/socket/socket/unpack_sockaddr_in_spec.rb16
-rw-r--r--spec/ruby/library/socket/socket/unpack_sockaddr_un_spec.rb34
-rw-r--r--spec/ruby/library/socket/spec_helper.rb21
-rw-r--r--spec/ruby/library/socket/tcpserver/accept_nonblock_spec.rb12
-rw-r--r--spec/ruby/library/socket/tcpserver/accept_spec.rb8
-rw-r--r--spec/ruby/library/socket/tcpserver/gets_spec.rb2
-rw-r--r--spec/ruby/library/socket/tcpserver/initialize_spec.rb12
-rw-r--r--spec/ruby/library/socket/tcpserver/listen_spec.rb2
-rw-r--r--spec/ruby/library/socket/tcpserver/new_spec.rb28
-rw-r--r--spec/ruby/library/socket/tcpserver/sysaccept_spec.rb4
-rw-r--r--spec/ruby/library/socket/tcpsocket/gethostbyname_spec.rb14
-rw-r--r--spec/ruby/library/socket/tcpsocket/initialize_spec.rb10
-rw-r--r--spec/ruby/library/socket/tcpsocket/local_address_spec.rb2
-rw-r--r--spec/ruby/library/socket/tcpsocket/remote_address_spec.rb2
-rw-r--r--spec/ruby/library/socket/tcpsocket/shared/new.rb63
-rw-r--r--spec/ruby/library/socket/udpsocket/bind_spec.rb4
-rw-r--r--spec/ruby/library/socket/udpsocket/initialize_spec.rb14
-rw-r--r--spec/ruby/library/socket/udpsocket/inspect_spec.rb17
-rw-r--r--spec/ruby/library/socket/udpsocket/local_address_spec.rb2
-rw-r--r--spec/ruby/library/socket/udpsocket/new_spec.rb12
-rw-r--r--spec/ruby/library/socket/udpsocket/open_spec.rb2
-rw-r--r--spec/ruby/library/socket/udpsocket/recvfrom_nonblock_spec.rb8
-rw-r--r--spec/ruby/library/socket/udpsocket/remote_address_spec.rb2
-rw-r--r--spec/ruby/library/socket/udpsocket/send_spec.rb12
-rw-r--r--spec/ruby/library/socket/udpsocket/write_spec.rb2
-rw-r--r--spec/ruby/library/socket/unixserver/accept_nonblock_spec.rb114
-rw-r--r--spec/ruby/library/socket/unixserver/accept_spec.rb166
-rw-r--r--spec/ruby/library/socket/unixserver/for_fd_spec.rb28
-rw-r--r--spec/ruby/library/socket/unixserver/initialize_spec.rb36
-rw-r--r--spec/ruby/library/socket/unixserver/listen_spec.rb24
-rw-r--r--spec/ruby/library/socket/unixserver/new_spec.rb14
-rw-r--r--spec/ruby/library/socket/unixserver/open_spec.rb30
-rw-r--r--spec/ruby/library/socket/unixserver/sysaccept_spec.rb64
-rw-r--r--spec/ruby/library/socket/unixsocket/addr_spec.rb48
-rw-r--r--spec/ruby/library/socket/unixsocket/initialize_spec.rb62
-rw-r--r--spec/ruby/library/socket/unixsocket/inspect_spec.rb20
-rw-r--r--spec/ruby/library/socket/unixsocket/local_address_spec.rb132
-rw-r--r--spec/ruby/library/socket/unixsocket/new_spec.rb14
-rw-r--r--spec/ruby/library/socket/unixsocket/open_spec.rb34
-rw-r--r--spec/ruby/library/socket/unixsocket/pair_spec.rb59
-rw-r--r--spec/ruby/library/socket/unixsocket/partially_closable_spec.rb30
-rw-r--r--spec/ruby/library/socket/unixsocket/path_spec.rb34
-rw-r--r--spec/ruby/library/socket/unixsocket/peeraddr_spec.rb38
-rw-r--r--spec/ruby/library/socket/unixsocket/recv_io_spec.rb10
-rw-r--r--spec/ruby/library/socket/unixsocket/recvfrom_spec.rb152
-rw-r--r--spec/ruby/library/socket/unixsocket/remote_address_spec.rb60
-rw-r--r--spec/ruby/library/socket/unixsocket/send_io_spec.rb4
-rw-r--r--spec/ruby/library/socket/unixsocket/shared/pair.rb29
-rw-r--r--spec/ruby/library/socket/unixsocket/socketpair_spec.rb19
-rw-r--r--spec/ruby/library/stringio/append_spec.rb10
-rw-r--r--spec/ruby/library/stringio/binmode_spec.rb2
-rw-r--r--spec/ruby/library/stringio/close_read_spec.rb6
-rw-r--r--spec/ruby/library/stringio/close_spec.rb8
-rw-r--r--spec/ruby/library/stringio/close_write_spec.rb6
-rw-r--r--spec/ruby/library/stringio/closed_read_spec.rb4
-rw-r--r--spec/ruby/library/stringio/closed_spec.rb6
-rw-r--r--spec/ruby/library/stringio/closed_write_spec.rb4
-rw-r--r--spec/ruby/library/stringio/each_byte_spec.rb46
-rw-r--r--spec/ruby/library/stringio/each_char_spec.rb33
-rw-r--r--spec/ruby/library/stringio/each_codepoint_spec.rb46
-rw-r--r--spec/ruby/library/stringio/each_line_spec.rb199
-rw-r--r--spec/ruby/library/stringio/each_spec.rb33
-rw-r--r--spec/ruby/library/stringio/eof_spec.rb30
-rw-r--r--spec/ruby/library/stringio/fcntl_spec.rb2
-rw-r--r--spec/ruby/library/stringio/fileno_spec.rb2
-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.rb16
-rw-r--r--spec/ruby/library/stringio/initialize_spec.rb140
-rw-r--r--spec/ruby/library/stringio/inspect_spec.rb2
-rw-r--r--spec/ruby/library/stringio/isatty_spec.rb7
-rw-r--r--spec/ruby/library/stringio/length_spec.rb7
-rw-r--r--spec/ruby/library/stringio/lineno_spec.rb8
-rw-r--r--spec/ruby/library/stringio/open_spec.rb120
-rw-r--r--spec/ruby/library/stringio/path_spec.rb2
-rw-r--r--spec/ruby/library/stringio/pid_spec.rb2
-rw-r--r--spec/ruby/library/stringio/pos_spec.rb14
-rw-r--r--spec/ruby/library/stringio/print_spec.rb14
-rw-r--r--spec/ruby/library/stringio/printf_spec.rb14
-rw-r--r--spec/ruby/library/stringio/putc_spec.rb8
-rw-r--r--spec/ruby/library/stringio/puts_spec.rb8
-rw-r--r--spec/ruby/library/stringio/read_nonblock_spec.rb2
-rw-r--r--spec/ruby/library/stringio/read_spec.rb4
-rw-r--r--spec/ruby/library/stringio/readline_spec.rb8
-rw-r--r--spec/ruby/library/stringio/readlines_spec.rb14
-rw-r--r--spec/ruby/library/stringio/readpartial_spec.rb44
-rw-r--r--spec/ruby/library/stringio/reopen_spec.rb74
-rw-r--r--spec/ruby/library/stringio/rewind_spec.rb2
-rw-r--r--spec/ruby/library/stringio/seek_spec.rb24
-rw-r--r--spec/ruby/library/stringio/set_encoding_by_bom_spec.rb6
-rw-r--r--spec/ruby/library/stringio/shared/codepoints.rb45
-rw-r--r--spec/ruby/library/stringio/shared/each.rb209
-rw-r--r--spec/ruby/library/stringio/shared/each_byte.rb48
-rw-r--r--spec/ruby/library/stringio/shared/each_char.rb36
-rw-r--r--spec/ruby/library/stringio/shared/eof.rb24
-rw-r--r--spec/ruby/library/stringio/shared/getc.rb20
-rw-r--r--spec/ruby/library/stringio/shared/gets.rb34
-rw-r--r--spec/ruby/library/stringio/shared/isatty.rb5
-rw-r--r--spec/ruby/library/stringio/shared/length.rb5
-rw-r--r--spec/ruby/library/stringio/shared/read.rb26
-rw-r--r--spec/ruby/library/stringio/shared/readchar.rb6
-rw-r--r--spec/ruby/library/stringio/shared/sysread.rb2
-rw-r--r--spec/ruby/library/stringio/shared/tell.rb12
-rw-r--r--spec/ruby/library/stringio/shared/write.rb8
-rw-r--r--spec/ruby/library/stringio/size_spec.rb7
-rw-r--r--spec/ruby/library/stringio/string_spec.rb12
-rw-r--r--spec/ruby/library/stringio/stringio_spec.rb2
-rw-r--r--spec/ruby/library/stringio/sync_spec.rb4
-rw-r--r--spec/ruby/library/stringio/sysread_spec.rb2
-rw-r--r--spec/ruby/library/stringio/tell_spec.rb7
-rw-r--r--spec/ruby/library/stringio/truncate_spec.rb16
-rw-r--r--spec/ruby/library/stringio/tty_spec.rb7
-rw-r--r--spec/ruby/library/stringio/ungetc_spec.rb14
-rw-r--r--spec/ruby/library/stringscanner/append_spec.rb28
-rw-r--r--spec/ruby/library/stringscanner/beginning_of_line_spec.rb25
-rw-r--r--spec/ruby/library/stringscanner/bol_spec.rb5
-rw-r--r--spec/ruby/library/stringscanner/check_spec.rb16
-rw-r--r--spec/ruby/library/stringscanner/check_until_spec.rb20
-rw-r--r--spec/ruby/library/stringscanner/clear_spec.rb18
-rw-r--r--spec/ruby/library/stringscanner/concat_spec.rb9
-rw-r--r--spec/ruby/library/stringscanner/dup_spec.rb4
-rw-r--r--spec/ruby/library/stringscanner/element_reference_spec.rb16
-rw-r--r--spec/ruby/library/stringscanner/empty_spec.rb18
-rw-r--r--spec/ruby/library/stringscanner/eos_spec.rb17
-rw-r--r--spec/ruby/library/stringscanner/exist_spec.rb18
-rw-r--r--spec/ruby/library/stringscanner/get_byte_spec.rb81
-rw-r--r--spec/ruby/library/stringscanner/getbyte_spec.rb21
-rw-r--r--spec/ruby/library/stringscanner/getch_spec.rb19
-rw-r--r--spec/ruby/library/stringscanner/initialize_spec.rb6
-rw-r--r--spec/ruby/library/stringscanner/inspect_spec.rb2
-rw-r--r--spec/ruby/library/stringscanner/match_spec.rb2
-rw-r--r--spec/ruby/library/stringscanner/matched_spec.rb4
-rw-r--r--spec/ruby/library/stringscanner/named_captures_spec.rb8
-rw-r--r--spec/ruby/library/stringscanner/peek_spec.rb39
-rw-r--r--spec/ruby/library/stringscanner/peep_spec.rb18
-rw-r--r--spec/ruby/library/stringscanner/pointer_spec.rb9
-rw-r--r--spec/ruby/library/stringscanner/pos_spec.rb57
-rw-r--r--spec/ruby/library/stringscanner/rest_size_spec.rb27
-rw-r--r--spec/ruby/library/stringscanner/rest_spec.rb6
-rw-r--r--spec/ruby/library/stringscanner/restsize_spec.rb18
-rw-r--r--spec/ruby/library/stringscanner/scan_byte_spec.rb10
-rw-r--r--spec/ruby/library/stringscanner/scan_full_spec.rb2
-rw-r--r--spec/ruby/library/stringscanner/scan_integer_spec.rb18
-rw-r--r--spec/ruby/library/stringscanner/scan_spec.rb22
-rw-r--r--spec/ruby/library/stringscanner/scan_until_spec.rb20
-rw-r--r--spec/ruby/library/stringscanner/search_full_spec.rb16
-rw-r--r--spec/ruby/library/stringscanner/shared/bol.rb25
-rw-r--r--spec/ruby/library/stringscanner/shared/concat.rb30
-rw-r--r--spec/ruby/library/stringscanner/shared/eos.rb17
-rw-r--r--spec/ruby/library/stringscanner/shared/extract_range.rb4
-rw-r--r--spec/ruby/library/stringscanner/shared/extract_range_matched.rb4
-rw-r--r--spec/ruby/library/stringscanner/shared/get_byte.rb87
-rw-r--r--spec/ruby/library/stringscanner/shared/peek.rb39
-rw-r--r--spec/ruby/library/stringscanner/shared/pos.rb59
-rw-r--r--spec/ruby/library/stringscanner/shared/rest_size.rb18
-rw-r--r--spec/ruby/library/stringscanner/shared/terminate.rb8
-rw-r--r--spec/ruby/library/stringscanner/skip_spec.rb2
-rw-r--r--spec/ruby/library/stringscanner/skip_until_spec.rb20
-rw-r--r--spec/ruby/library/stringscanner/string_spec.rb2
-rw-r--r--spec/ruby/library/stringscanner/terminate_spec.rb8
-rw-r--r--spec/ruby/library/stringscanner/unscan_spec.rb6
-rw-r--r--spec/ruby/library/stringscanner/values_at_spec.rb4
-rw-r--r--spec/ruby/library/syslog/close_spec.rb16
-rw-r--r--spec/ruby/library/syslog/constants_spec.rb2
-rw-r--r--spec/ruby/library/syslog/facility_spec.rb6
-rw-r--r--spec/ruby/library/syslog/ident_spec.rb4
-rw-r--r--spec/ruby/library/syslog/inspect_spec.rb4
-rw-r--r--spec/ruby/library/syslog/log_spec.rb8
-rw-r--r--spec/ruby/library/syslog/mask_spec.rb14
-rw-r--r--spec/ruby/library/syslog/open_spec.rb48
-rw-r--r--spec/ruby/library/syslog/opened_spec.rb16
-rw-r--r--spec/ruby/library/syslog/options_spec.rb6
-rw-r--r--spec/ruby/library/syslog/reopen_spec.rb5
-rw-r--r--spec/ruby/library/syslog/shared/log.rb4
-rw-r--r--spec/ruby/library/syslog/shared/reopen.rb40
-rw-r--r--spec/ruby/library/tempfile/_close_spec.rb4
-rw-r--r--spec/ruby/library/tempfile/callback_spec.rb6
-rw-r--r--spec/ruby/library/tempfile/close_spec.rb6
-rw-r--r--spec/ruby/library/tempfile/create_spec.rb176
-rw-r--r--spec/ruby/library/tempfile/delete_spec.rb12
-rw-r--r--spec/ruby/library/tempfile/initialize_spec.rb2
-rw-r--r--spec/ruby/library/tempfile/length_spec.rb5
-rw-r--r--spec/ruby/library/tempfile/open_spec.rb18
-rw-r--r--spec/ruby/library/tempfile/path_spec.rb2
-rw-r--r--spec/ruby/library/tempfile/shared/length.rb21
-rw-r--r--spec/ruby/library/tempfile/shared/unlink.rb12
-rw-r--r--spec/ruby/library/tempfile/size_spec.rb21
-rw-r--r--spec/ruby/library/tempfile/unlink_spec.rb5
-rw-r--r--spec/ruby/library/thread/queue_spec.rb4
-rw-r--r--spec/ruby/library/thread/sizedqueue_spec.rb4
-rw-r--r--spec/ruby/library/time/iso8601_spec.rb5
-rw-r--r--spec/ruby/library/time/rfc2822_spec.rb65
-rw-r--r--spec/ruby/library/time/rfc822_spec.rb5
-rw-r--r--spec/ruby/library/time/shared/rfc2822.rb65
-rw-r--r--spec/ruby/library/time/shared/xmlschema.rb53
-rw-r--r--spec/ruby/library/time/to_time_spec.rb4
-rw-r--r--spec/ruby/library/time/xmlschema_spec.rb53
-rw-r--r--spec/ruby/library/timeout/error_spec.rb2
-rw-r--r--spec/ruby/library/timeout/timeout_spec.rb10
-rw-r--r--spec/ruby/library/tmpdir/dir/mktmpdir_spec.rb18
-rw-r--r--spec/ruby/library/tmpdir/dir/tmpdir_spec.rb4
-rw-r--r--spec/ruby/library/uri/join_spec.rb2
-rw-r--r--spec/ruby/library/uri/mailto/build_spec.rb2
-rw-r--r--spec/ruby/library/uri/parse_spec.rb24
-rw-r--r--spec/ruby/library/uri/parser/extract_spec.rb87
-rw-r--r--spec/ruby/library/uri/parser/join_spec.rb59
-rw-r--r--spec/ruby/library/uri/parser/parse_spec.rb210
-rw-r--r--spec/ruby/library/uri/plus_spec.rb170
-rw-r--r--spec/ruby/library/uri/select_spec.rb6
-rw-r--r--spec/ruby/library/uri/set_component_spec.rb60
-rw-r--r--spec/ruby/library/uri/shared/eql.rb6
-rw-r--r--spec/ruby/library/uri/shared/extract.rb83
-rw-r--r--spec/ruby/library/uri/shared/join.rb56
-rw-r--r--spec/ruby/library/uri/shared/parse.rb206
-rw-r--r--spec/ruby/library/uri/uri_spec.rb4
-rw-r--r--spec/ruby/library/weakref/__getobj___spec.rb4
-rw-r--r--spec/ruby/library/weakref/allocate_spec.rb2
-rw-r--r--spec/ruby/library/weakref/send_spec.rb4
-rw-r--r--spec/ruby/library/weakref/weakref_alive_spec.rb4
-rw-r--r--spec/ruby/library/win32ole/win32ole/_invoke_spec.rb6
-rw-r--r--spec/ruby/library/win32ole/win32ole/connect_spec.rb4
-rw-r--r--spec/ruby/library/win32ole/win32ole/const_load_spec.rb8
-rw-r--r--spec/ruby/library/win32ole/win32ole/locale_spec.rb2
-rw-r--r--spec/ruby/library/win32ole/win32ole/new_spec.rb8
-rw-r--r--spec/ruby/library/win32ole/win32ole/ole_func_methods_spec.rb6
-rw-r--r--spec/ruby/library/win32ole/win32ole/ole_get_methods_spec.rb2
-rw-r--r--spec/ruby/library/win32ole/win32ole/ole_methods_spec.rb6
-rw-r--r--spec/ruby/library/win32ole/win32ole/ole_obj_help_spec.rb4
-rw-r--r--spec/ruby/library/win32ole/win32ole/ole_put_methods_spec.rb6
-rw-r--r--spec/ruby/library/win32ole/win32ole/shared/ole_method.rb4
-rw-r--r--spec/ruby/library/win32ole/win32ole/shared/setproperty.rb2
-rw-r--r--spec/ruby/library/win32ole/win32ole_event/new_spec.rb8
-rw-r--r--spec/ruby/library/win32ole/win32ole_method/dispid_spec.rb2
-rw-r--r--spec/ruby/library/win32ole/win32ole_method/event_interface_spec.rb4
-rw-r--r--spec/ruby/library/win32ole/win32ole_method/event_spec.rb4
-rw-r--r--spec/ruby/library/win32ole/win32ole_method/helpcontext_spec.rb2
-rw-r--r--spec/ruby/library/win32ole/win32ole_method/helpfile_spec.rb2
-rw-r--r--spec/ruby/library/win32ole/win32ole_method/helpstring_spec.rb2
-rw-r--r--spec/ruby/library/win32ole/win32ole_method/invkind_spec.rb2
-rw-r--r--spec/ruby/library/win32ole/win32ole_method/invoke_kind_spec.rb2
-rw-r--r--spec/ruby/library/win32ole/win32ole_method/new_spec.rb14
-rw-r--r--spec/ruby/library/win32ole/win32ole_method/offset_vtbl_spec.rb2
-rw-r--r--spec/ruby/library/win32ole/win32ole_method/params_spec.rb8
-rw-r--r--spec/ruby/library/win32ole/win32ole_method/return_type_detail_spec.rb4
-rw-r--r--spec/ruby/library/win32ole/win32ole_method/return_type_spec.rb2
-rw-r--r--spec/ruby/library/win32ole/win32ole_method/return_vtype_spec.rb2
-rw-r--r--spec/ruby/library/win32ole/win32ole_method/shared/name.rb2
-rw-r--r--spec/ruby/library/win32ole/win32ole_method/size_opt_params_spec.rb2
-rw-r--r--spec/ruby/library/win32ole/win32ole_method/size_params_spec.rb2
-rw-r--r--spec/ruby/library/win32ole/win32ole_method/visible_spec.rb4
-rw-r--r--spec/ruby/library/win32ole/win32ole_param/default_spec.rb4
-rw-r--r--spec/ruby/library/win32ole/win32ole_param/input_spec.rb2
-rw-r--r--spec/ruby/library/win32ole/win32ole_param/ole_type_detail_spec.rb2
-rw-r--r--spec/ruby/library/win32ole/win32ole_param/ole_type_spec.rb2
-rw-r--r--spec/ruby/library/win32ole/win32ole_param/optional_spec.rb4
-rw-r--r--spec/ruby/library/win32ole/win32ole_param/retval_spec.rb4
-rw-r--r--spec/ruby/library/win32ole/win32ole_param/shared/name.rb2
-rw-r--r--spec/ruby/library/win32ole/win32ole_type/helpcontext_spec.rb2
-rw-r--r--spec/ruby/library/win32ole/win32ole_type/helpfile_spec.rb2
-rw-r--r--spec/ruby/library/win32ole/win32ole_type/major_version_spec.rb2
-rw-r--r--spec/ruby/library/win32ole/win32ole_type/minor_version_spec.rb2
-rw-r--r--spec/ruby/library/win32ole/win32ole_type/new_spec.rb16
-rw-r--r--spec/ruby/library/win32ole/win32ole_type/ole_classes_spec.rb2
-rw-r--r--spec/ruby/library/win32ole/win32ole_type/ole_methods_spec.rb2
-rw-r--r--spec/ruby/library/win32ole/win32ole_type/progids_spec.rb4
-rw-r--r--spec/ruby/library/win32ole/win32ole_type/shared/name.rb2
-rw-r--r--spec/ruby/library/win32ole/win32ole_type/src_type_spec.rb2
-rw-r--r--spec/ruby/library/win32ole/win32ole_type/typekind_spec.rb2
-rw-r--r--spec/ruby/library/win32ole/win32ole_type/typelibs_spec.rb4
-rw-r--r--spec/ruby/library/win32ole/win32ole_type/visible_spec.rb2
-rw-r--r--spec/ruby/library/win32ole/win32ole_variable/ole_type_detail_spec.rb4
-rw-r--r--spec/ruby/library/win32ole/win32ole_variable/ole_type_spec.rb2
-rw-r--r--spec/ruby/library/win32ole/win32ole_variable/shared/name.rb2
-rw-r--r--spec/ruby/library/win32ole/win32ole_variable/value_spec.rb2
-rw-r--r--spec/ruby/library/win32ole/win32ole_variable/variable_kind_spec.rb2
-rw-r--r--spec/ruby/library/win32ole/win32ole_variable/varkind_spec.rb2
-rw-r--r--spec/ruby/library/win32ole/win32ole_variable/visible_spec.rb2
-rw-r--r--spec/ruby/library/yaml/load_stream_spec.rb20
-rw-r--r--spec/ruby/library/yaml/parse_file_spec.rb2
-rw-r--r--spec/ruby/library/yaml/parse_spec.rb2
-rw-r--r--spec/ruby/library/yaml/shared/each_document.rb19
-rw-r--r--spec/ruby/library/yaml/shared/load.rb6
-rw-r--r--spec/ruby/library/yaml/to_yaml_spec.rb18
-rw-r--r--spec/ruby/library/zlib/adler32_spec.rb2
-rw-r--r--spec/ruby/library/zlib/crc32_spec.rb2
-rw-r--r--spec/ruby/library/zlib/gzipfile/close_spec.rb6
-rw-r--r--spec/ruby/library/zlib/gzipfile/comment_spec.rb3
-rw-r--r--spec/ruby/library/zlib/gzipfile/orig_name_spec.rb3
-rw-r--r--spec/ruby/library/zlib/gzipreader/each_line_spec.rb7
-rw-r--r--spec/ruby/library/zlib/gzipreader/each_spec.rb47
-rw-r--r--spec/ruby/library/zlib/gzipreader/eof_spec.rb29
-rw-r--r--spec/ruby/library/zlib/gzipreader/getc_spec.rb2
-rw-r--r--spec/ruby/library/zlib/gzipreader/gets_spec.rb2
-rw-r--r--spec/ruby/library/zlib/gzipreader/read_spec.rb6
-rw-r--r--spec/ruby/library/zlib/gzipreader/shared/each.rb49
-rw-r--r--spec/ruby/library/zlib/gzipreader/tell_spec.rb9
-rw-r--r--spec/ruby/library/zlib/gzipreader/ungetbyte_spec.rb4
-rw-r--r--spec/ruby/library/zlib/gzipreader/ungetc_spec.rb12
-rw-r--r--spec/ruby/library/zlib/gzipwriter/append_spec.rb2
-rw-r--r--spec/ruby/library/zlib/gzipwriter/mtime_spec.rb3
-rw-r--r--spec/ruby/library/zlib/inflate/append_spec.rb2
-rw-r--r--spec/ruby/library/zlib/inflate/finish_spec.rb2
-rw-r--r--spec/ruby/library/zlib/inflate/inflate_spec.rb4
-rw-r--r--spec/ruby/library/zlib/zlib_version_spec.rb2
-rw-r--r--spec/ruby/optional/capi/array_spec.rb86
-rw-r--r--spec/ruby/optional/capi/bignum_spec.rb16
-rw-r--r--spec/ruby/optional/capi/binding_spec.rb2
-rw-r--r--spec/ruby/optional/capi/class_spec.rb118
-rw-r--r--spec/ruby/optional/capi/constants_spec.rb2
-rw-r--r--spec/ruby/optional/capi/data_spec.rb2
-rw-r--r--spec/ruby/optional/capi/debug_spec.rb10
-rw-r--r--spec/ruby/optional/capi/encoding_spec.rb129
-rw-r--r--spec/ruby/optional/capi/exception_spec.rb32
-rw-r--r--spec/ruby/optional/capi/ext/array_spec.c8
-rw-r--r--spec/ruby/optional/capi/ext/digest_spec.c2
-rw-r--r--spec/ruby/optional/capi/ext/encoding_spec.c11
-rw-r--r--spec/ruby/optional/capi/ext/gc_spec.c29
-rw-r--r--spec/ruby/optional/capi/ext/io_spec.c24
-rw-r--r--spec/ruby/optional/capi/ext/kernel_spec.c15
-rw-r--r--spec/ruby/optional/capi/ext/rubyspec.h12
-rw-r--r--spec/ruby/optional/capi/ext/set_spec.c3
-rw-r--r--spec/ruby/optional/capi/ext/string_spec.c51
-rw-r--r--spec/ruby/optional/capi/ext/struct_spec.c9
-rw-r--r--spec/ruby/optional/capi/ext/thread_spec.c4
-rw-r--r--spec/ruby/optional/capi/ext/typed_data_spec.c9
-rw-r--r--spec/ruby/optional/capi/ext/util_spec.c4
-rw-r--r--spec/ruby/optional/capi/fiber_spec.rb12
-rw-r--r--spec/ruby/optional/capi/file_spec.rb8
-rw-r--r--spec/ruby/optional/capi/fixnum_spec.rb20
-rw-r--r--spec/ruby/optional/capi/float_spec.rb4
-rw-r--r--spec/ruby/optional/capi/gc_spec.rb40
-rw-r--r--spec/ruby/optional/capi/globals_spec.rb31
-rw-r--r--spec/ruby/optional/capi/hash_spec.rb42
-rw-r--r--spec/ruby/optional/capi/io_spec.rb376
-rw-r--r--spec/ruby/optional/capi/kernel_spec.rb126
-rw-r--r--spec/ruby/optional/capi/module_spec.rb58
-rw-r--r--spec/ruby/optional/capi/mutex_spec.rb34
-rw-r--r--spec/ruby/optional/capi/numeric_spec.rb56
-rw-r--r--spec/ruby/optional/capi/object_spec.rb152
-rw-r--r--spec/ruby/optional/capi/proc_spec.rb24
-rw-r--r--spec/ruby/optional/capi/range_spec.rb36
-rw-r--r--spec/ruby/optional/capi/regexp_spec.rb4
-rw-r--r--spec/ruby/optional/capi/set_spec.rb14
-rw-r--r--spec/ruby/optional/capi/spec_helper.rb42
-rw-r--r--spec/ruby/optional/capi/string_spec.rb304
-rw-r--r--spec/ruby/optional/capi/struct_spec.rb152
-rw-r--r--spec/ruby/optional/capi/thread_spec.rb24
-rw-r--r--spec/ruby/optional/capi/time_spec.rb108
-rw-r--r--spec/ruby/optional/capi/tracepoint_spec.rb2
-rw-r--r--spec/ruby/optional/capi/typed_data_spec.rb24
-rw-r--r--spec/ruby/optional/capi/util_spec.rb23
-rw-r--r--spec/ruby/optional/thread_safety/fixtures/classes.rb39
-rw-r--r--spec/ruby/optional/thread_safety/hash_spec.rb210
-rw-r--r--spec/ruby/security/cve_2010_1330_spec.rb2
-rw-r--r--spec/ruby/security/cve_2018_8778_spec.rb2
-rw-r--r--spec/ruby/security/cve_2018_8779_spec.rb4
-rw-r--r--spec/ruby/security/cve_2018_8780_spec.rb12
-rw-r--r--spec/ruby/security/cve_2019_8322_spec.rb33
-rw-r--r--spec/ruby/security/cve_2020_10663_spec.rb4
-rw-r--r--spec/ruby/shared/basicobject/method_missing.rb18
-rw-r--r--spec/ruby/shared/basicobject/send.rb18
-rw-r--r--spec/ruby/shared/enumerable/minmax.rb6
-rw-r--r--spec/ruby/shared/file/directory.rb18
-rw-r--r--spec/ruby/shared/file/executable.rb8
-rw-r--r--spec/ruby/shared/file/executable_real.rb8
-rw-r--r--spec/ruby/shared/file/exist.rb6
-rw-r--r--spec/ruby/shared/file/file.rb8
-rw-r--r--spec/ruby/shared/file/grpowned.rb6
-rw-r--r--spec/ruby/shared/file/identical.rb18
-rw-r--r--spec/ruby/shared/file/size.rb2
-rw-r--r--spec/ruby/shared/file/socket.rb32
-rw-r--r--spec/ruby/shared/file/world_readable.rb10
-rw-r--r--spec/ruby/shared/file/world_writable.rb10
-rw-r--r--spec/ruby/shared/file/writable_real.rb8
-rw-r--r--spec/ruby/shared/file/zero.rb10
-rw-r--r--spec/ruby/shared/hash/key_error.rb8
-rw-r--r--spec/ruby/shared/io/putc.rb8
-rw-r--r--spec/ruby/shared/kernel/at_exit.rb5
-rw-r--r--spec/ruby/shared/kernel/complex.rb2
-rw-r--r--spec/ruby/shared/kernel/equal.rb4
-rw-r--r--spec/ruby/shared/kernel/object_id.rb2
-rw-r--r--spec/ruby/shared/kernel/raise.rb171
-rw-r--r--spec/ruby/shared/process/abort.rb12
-rw-r--r--spec/ruby/shared/process/exit.rb22
-rw-r--r--spec/ruby/shared/process/fork.rb33
-rw-r--r--spec/ruby/shared/queue/clear.rb4
-rw-r--r--spec/ruby/shared/queue/close.rb4
-rw-r--r--spec/ruby/shared/queue/closed.rb4
-rw-r--r--spec/ruby/shared/queue/deque.rb16
-rw-r--r--spec/ruby/shared/queue/empty.rb4
-rw-r--r--spec/ruby/shared/queue/enque.rb2
-rw-r--r--spec/ruby/shared/queue/freeze.rb18
-rw-r--r--spec/ruby/shared/sizedqueue/enque.rb14
-rw-r--r--spec/ruby/shared/sizedqueue/max.rb10
-rw-r--r--spec/ruby/shared/sizedqueue/new.rb10
-rw-r--r--spec/ruby/shared/string/end_with.rb8
-rw-r--r--spec/ruby/shared/string/start_with.rb28
-rw-r--r--spec/ruby/shared/string/times.rb22
-rw-r--r--spec/ruby/shared/types/rb_num2dbl_fails.rb6
-rw-r--r--spec/syntax_suggest/integration/ruby_command_line_spec.rb4
-rw-r--r--spec/syntax_suggest/integration/syntax_suggest_spec.rb33
-rw-r--r--spec/syntax_suggest/spec_helper.rb10
-rw-r--r--spec/syntax_suggest/unit/api_spec.rb10
-rw-r--r--spec/syntax_suggest/unit/clean_document_spec.rb2
-rw-r--r--spec/syntax_suggest/unit/code_block_spec.rb2
-rw-r--r--spec/syntax_suggest/unit/code_line_spec.rb15
-rw-r--r--spec/syntax_suggest/unit/core_ext_spec.rb2
-rw-r--r--spec/syntax_suggest/unit/explain_syntax_spec.rb32
-rw-r--r--spec/syntax_suggest/unit/lex_all_spec.rb26
-rw-r--r--spec/syntax_suggest/unit/visitor_spec.rb119
-rw-r--r--sprintf.c10
-rw-r--r--st.c259
-rw-r--r--string.c1804
-rw-r--r--struct.c256
-rw-r--r--symbol.c207
-rw-r--r--template/Makefile.in29
-rw-r--r--template/configure-ext.mk.tmpl41
-rw-r--r--template/fake.rb.in1
-rw-r--r--template/id.c.tmpl2
-rw-r--r--template/unicode_norm_gen.tmpl17
-rw-r--r--test/-ext-/box/test_load_ext.rb97
-rw-r--r--test/-ext-/bug_reporter/test_bug_reporter.rb6
-rw-r--r--test/-ext-/namespace/test_load_ext.rb97
-rw-r--r--test/-ext-/postponed_job/test_postponed_job.rb35
-rw-r--r--test/-ext-/scheduler/test_interrupt_with_scheduler.rb54
-rw-r--r--test/-ext-/stack/test_stack_overflow.rb6
-rw-r--r--test/-ext-/string/test_capacity.rb11
-rw-r--r--test/-ext-/string/test_interned_str.rb5
-rw-r--r--test/-ext-/string/test_set_len.rb2
-rw-r--r--test/-ext-/test_abi.rb4
-rw-r--r--test/-ext-/thread/test_lock_native_thread.rb4
-rw-r--r--test/-ext-/tracepoint/test_tracepoint.rb2
-rw-r--r--test/.excludes-mmtk/TestObjSpace.rb1
-rw-r--r--test/.excludes-zjit/ErrorHighlightTest.rb1
-rw-r--r--test/.excludes-zjit/TestBugReporter.rb1
-rw-r--r--test/.excludes-zjit/TestERBCore.rb1
-rw-r--r--test/.excludes-zjit/TestERBCoreWOStrScan.rb1
-rw-r--r--test/.excludes-zjit/TestObjSpace.rb2
-rw-r--r--test/.excludes-zjit/TestParse.rb2
-rw-r--r--test/.excludes-zjit/TestProc.rb1
-rw-r--r--test/.excludes-zjit/TestRegexp.rb1
-rw-r--r--test/.excludes-zjit/TestResolvDNS.rb1
-rw-r--r--test/.excludes-zjit/TestRubyOptimization.rb1
-rw-r--r--test/.excludes-zjit/TestRubyOptions.rb10
-rw-r--r--test/.excludes-zjit/TestSetTraceFunc.rb1
-rw-r--r--test/.excludes-zjit/TestThread.rb2
-rw-r--r--test/.excludes-zjit/TestTimeout.rb3
-rw-r--r--test/.excludes-zjit/TestTracepointObj.rb1
-rw-r--r--test/.excludes/JSONGenericObjectTest.rb4
-rw-r--r--test/.excludes/TestPatternMatching.rb1
-rw-r--r--test/.excludes/TestThread.rb2
-rw-r--r--test/cgi/test_cgi_escape.rb4
-rw-r--r--test/coverage/test_coverage.rb64
-rw-r--r--test/date/test_date_conv.rb20
-rw-r--r--test/date/test_date_parse.rb26
-rw-r--r--test/date/test_date_strptime.rb15
-rw-r--r--test/erb/test_erb.rb117
-rw-r--r--test/error_highlight/test_error_highlight.rb309
-rw-r--r--test/fiber/scheduler.rb138
-rw-r--r--test/fiber/test_scheduler.rb157
-rw-r--r--test/fiber/test_thread.rb6
-rw-r--r--test/io/wait/test_io_wait.rb34
-rw-r--r--test/io/wait/test_io_wait_uncommon.rb15
-rw-r--r--test/json/fixtures/fail15.json (renamed from test/json/fixtures/pass15.json)0
-rw-r--r--test/json/fixtures/fail16.json (renamed from test/json/fixtures/pass16.json)0
-rw-r--r--test/json/fixtures/fail17.json (renamed from test/json/fixtures/pass17.json)0
-rw-r--r--test/json/fixtures/fail26.json (renamed from test/json/fixtures/pass26.json)0
-rw-r--r--test/json/fixtures/pass1.json2
-rwxr-xr-xtest/json/json_coder_test.rb107
-rw-r--r--test/json/json_common_interface_test.rb102
-rw-r--r--test/json/json_encoding_test.rb24
-rw-r--r--test/json/json_ext_parser_test.rb2
-rw-r--r--test/json/json_fixtures_test.rb2
-rwxr-xr-xtest/json/json_generator_test.rb456
-rw-r--r--test/json/json_generic_object_test.rb24
-rw-r--r--test/json/json_parser_test.rb135
-rw-r--r--test/json/json_ryu_fallback_test.rb191
-rw-r--r--test/json/ractor_test.rb60
-rw-r--r--test/json/test_helper.rb25
-rw-r--r--test/lib/jit_support.rb6
-rw-r--r--test/mkmf/test_egrep_cpp.rb14
-rw-r--r--test/monitor/test_monitor.rb2
-rw-r--r--test/net/http/test_http.rb25
-rw-r--r--test/net/http/test_http_request.rb34
-rw-r--r--test/net/http/test_https.rb84
-rw-r--r--test/net/http/test_https_proxy.rb16
-rw-r--r--test/net/http/utils.rb3
-rw-r--r--test/objspace/test_objspace.rb129
-rw-r--r--test/objspace/test_ractor.rb30
-rw-r--r--test/open-uri/test_open-uri.rb2
-rw-r--r--test/openssl/fixtures/pkey/dsa1024.pem12
-rw-r--r--test/openssl/fixtures/pkey/dsa256.pem8
-rw-r--r--test/openssl/fixtures/pkey/dsa512.pem8
-rw-r--r--test/openssl/fixtures/pkey/rsa1024.pem15
-rw-r--r--test/openssl/test_asn1.rb82
-rw-r--r--test/openssl/test_cipher.rb103
-rw-r--r--test/openssl/test_digest.rb80
-rw-r--r--test/openssl/test_fips.rb2
-rw-r--r--test/openssl/test_hmac.rb34
-rw-r--r--test/openssl/test_kdf.rb135
-rw-r--r--test/openssl/test_ns_spki.rb4
-rw-r--r--test/openssl/test_ocsp.rb43
-rw-r--r--test/openssl/test_ossl.rb27
-rw-r--r--test/openssl/test_pkcs12.rb38
-rw-r--r--test/openssl/test_pkcs7.rb4
-rw-r--r--test/openssl/test_pkey.rb126
-rw-r--r--test/openssl/test_pkey_dh.rb81
-rw-r--r--test/openssl/test_pkey_dsa.rb114
-rw-r--r--test/openssl/test_pkey_ec.rb62
-rw-r--r--test/openssl/test_pkey_rsa.rb305
-rw-r--r--test/openssl/test_provider.rb1
-rw-r--r--test/openssl/test_ssl.rb160
-rw-r--r--test/openssl/test_ts.rb39
-rw-r--r--test/openssl/test_x509cert.rb176
-rw-r--r--test/openssl/test_x509crl.rb78
-rw-r--r--test/openssl/test_x509name.rb16
-rw-r--r--test/openssl/test_x509req.rb94
-rw-r--r--test/openssl/utils.rb27
-rw-r--r--test/pathname/test_pathname.rb69
-rw-r--r--test/pathname/test_ractor.rb5
-rw-r--r--test/prism/api/freeze_test.rb5
-rw-r--r--test/prism/api/parse_stream_test.rb51
-rw-r--r--test/prism/api/parse_test.rb18
-rw-r--r--test/prism/bom_test.rb3
-rw-r--r--test/prism/encoding/encodings_test.rb18
-rw-r--r--test/prism/encoding/regular_expression_encoding_test.rb34
-rw-r--r--test/prism/errors/3.3-3.3/circular_parameters.txt12
-rw-r--r--test/prism/errors/3.3-3.4/leading_logical.txt34
-rw-r--r--test/prism/errors/3.3-3.4/private_endless_method.txt (renamed from test/prism/errors/private_endless_method.txt)0
-rw-r--r--test/prism/errors/3.3-4.0/do_not_allow_trailing_commas_in_method_parameters.txt (renamed from test/prism/errors/do_not_allow_trailing_commas_in_method_parameters.txt)0
-rw-r--r--test/prism/errors/3.3-4.0/noblock.txt6
-rw-r--r--test/prism/errors/3.3-4.0/singleton_method_with_void_value.txt3
-rw-r--r--test/prism/errors/3.4-4.0/void_value.txt18
-rw-r--r--test/prism/errors/3.4/block_args_in_array_assignment.txt (renamed from test/prism/errors/block_args_in_array_assignment.txt)0
-rw-r--r--test/prism/errors/3.4/dont_allow_return_inside_sclass_body.txt (renamed from test/prism/errors/dont_allow_return_inside_sclass_body.txt)0
-rw-r--r--test/prism/errors/3.4/it_with_ordinary_parameter.txt (renamed from test/prism/errors/it_with_ordinary_parameter.txt)0
-rw-r--r--test/prism/errors/3.4/keyword_args_in_array_assignment.txt (renamed from test/prism/errors/keyword_args_in_array_assignment.txt)0
-rw-r--r--test/prism/errors/4.1/do_not_allow_trailing_commas_after_terminating_arguments.txt6
-rw-r--r--test/prism/errors/4.1/end_block_exit.txt10
-rw-r--r--test/prism/errors/4.1/multiple_blocks.txt12
-rw-r--r--test/prism/errors/4.1/singleton_method_with_void_value.txt4
-rw-r--r--test/prism/errors/4.1/void_value.txt44
-rw-r--r--test/prism/errors/block_args_with_endless_def.txt5
-rw-r--r--test/prism/errors/block_beginning_with_brace_and_ending_with_end.txt2
-rw-r--r--test/prism/errors/block_pass_return_value.txt33
-rw-r--r--test/prism/errors/command_call_in.txt1
-rw-r--r--test/prism/errors/command_call_in_2.txt4
-rw-r--r--test/prism/errors/command_call_in_3.txt4
-rw-r--r--test/prism/errors/command_call_in_4.txt4
-rw-r--r--test/prism/errors/command_call_in_5.txt4
-rw-r--r--test/prism/errors/command_call_in_6.txt4
-rw-r--r--test/prism/errors/command_call_in_7.txt4
-rw-r--r--test/prism/errors/command_call_value_and.txt3
-rw-r--r--test/prism/errors/command_call_value_or.txt3
-rw-r--r--test/prism/errors/command_calls.txt7
-rw-r--r--test/prism/errors/command_calls_2.txt2
-rw-r--r--test/prism/errors/command_calls_24.txt2
-rw-r--r--test/prism/errors/command_calls_25.txt2
-rw-r--r--test/prism/errors/command_calls_32.txt19
-rw-r--r--test/prism/errors/command_calls_33.txt6
-rw-r--r--test/prism/errors/command_calls_34.txt31
-rw-r--r--test/prism/errors/command_calls_35.txt50
-rw-r--r--test/prism/errors/def_endless_do.txt6
-rw-r--r--test/prism/errors/def_with_optional_splat.txt6
-rw-r--r--test/prism/errors/destroy_call_operator_write_arguments.txt11
-rw-r--r--test/prism/errors/do_not_allow_forward_arguments_in_blocks.txt12
-rw-r--r--test/prism/errors/do_not_allow_forward_arguments_in_lambda_literals.txt12
-rw-r--r--test/prism/errors/endless_method_command_call.txt3
-rw-r--r--test/prism/errors/endless_method_command_call_parameters.txt27
-rw-r--r--test/prism/errors/heredoc_percent_q_newline_delimiter.txt11
-rw-r--r--test/prism/errors/heredoc_unterminated.txt2
-rw-r--r--test/prism/errors/infix_after_label.txt2
-rw-r--r--test/prism/errors/interpolated_symbol_pattern_hash_key.txt3
-rw-r--r--test/prism/errors/label_in_interpolated_string.txt14
-rw-r--r--test/prism/errors/match_predicate_after_rescue_with_dot_method_call.txt1
-rw-r--r--test/prism/errors/match_predicate_after_rescue_with_opreator.txt1
-rw-r--r--test/prism/errors/match_required_after_rescue_with_dot_method_call.txt1
-rw-r--r--test/prism/errors/match_required_after_rescue_with_opreator.txt1
-rw-r--r--test/prism/errors/modifier_conditional_in_predicate.txt12
-rw-r--r--test/prism/errors/not_without_parens_assignment.txt4
-rw-r--r--test/prism/errors/not_without_parens_call.txt7
-rw-r--r--test/prism/errors/not_without_parens_command.txt4
-rw-r--r--test/prism/errors/not_without_parens_command_call.txt4
-rw-r--r--test/prism/errors/not_without_parens_return.txt4
-rw-r--r--test/prism/errors/pattern-capture-in-alt-array.txt4
-rw-r--r--test/prism/errors/pattern-capture-in-alt-hash.txt3
-rw-r--r--test/prism/errors/pattern-capture-in-alt-name.txt3
-rw-r--r--test/prism/errors/pattern-capture-in-alt-top.txt4
-rw-r--r--test/prism/errors/pattern_string_key.txt8
-rw-r--r--test/prism/errors/rescue_pattern.txt4
-rw-r--r--test/prism/errors/shadow_args_in_lambda.txt2
-rw-r--r--test/prism/errors/singleton_method_for_literals.txt2
-rw-r--r--test/prism/errors/unterminated_begin.txt4
-rw-r--r--test/prism/errors/unterminated_begin_upcase.txt4
-rw-r--r--test/prism/errors/unterminated_block.txt2
-rw-r--r--test/prism/errors/unterminated_block_do_end.txt4
-rw-r--r--test/prism/errors/unterminated_class.txt4
-rw-r--r--test/prism/errors/unterminated_def.txt5
-rw-r--r--test/prism/errors/unterminated_end_upcase.txt4
-rw-r--r--test/prism/errors/unterminated_for.txt5
-rw-r--r--test/prism/errors/unterminated_heredoc_and_embexpr.txt11
-rw-r--r--test/prism/errors/unterminated_heredoc_and_embexpr_2.txt9
-rw-r--r--test/prism/errors/unterminated_if.txt5
-rw-r--r--test/prism/errors/unterminated_if_else.txt5
-rw-r--r--test/prism/errors/unterminated_lambda_brace.txt4
-rw-r--r--test/prism/errors/unterminated_module.txt4
-rw-r--r--test/prism/errors/unterminated_pattern_bracket.txt7
-rw-r--r--test/prism/errors/unterminated_pattern_paren.txt7
-rw-r--r--test/prism/errors/unterminated_until.txt5
-rw-r--r--test/prism/errors/void_value_expression_in_begin_statement.txt2
-rw-r--r--test/prism/errors/while_endless_method.txt2
-rw-r--r--test/prism/errors_test.rb110
-rw-r--r--test/prism/fixtures/3.3-3.3/block_args_in_array_assignment.txt1
-rw-r--r--test/prism/fixtures/3.3-3.3/it.txt (renamed from test/prism/fixtures/it.txt)0
-rw-r--r--test/prism/fixtures/3.3-3.3/it_indirect_writes.txt (renamed from test/prism/fixtures/it_indirect_writes.txt)0
-rw-r--r--test/prism/fixtures/3.3-3.3/it_read_and_assignment.txt (renamed from test/prism/fixtures/it_read_and_assignment.txt)0
-rw-r--r--test/prism/fixtures/3.3-3.3/it_with_ordinary_parameter.txt1
-rw-r--r--test/prism/fixtures/3.3-3.3/keyword_args_in_array_assignment.txt1
-rw-r--r--test/prism/fixtures/3.3-3.3/return_in_sclass.txt1
-rw-r--r--test/prism/fixtures/3.3-4.0/end_block_exit.txt11
-rw-r--r--test/prism/fixtures/3.3-4.0/void_value.txt29
-rw-r--r--test/prism/fixtures/3.4/circular_parameters.txt4
-rw-r--r--test/prism/fixtures/3.4/it.txt5
-rw-r--r--test/prism/fixtures/3.4/it_indirect_writes.txt23
-rw-r--r--test/prism/fixtures/3.4/it_read_and_assignment.txt1
-rw-r--r--test/prism/fixtures/4.0/endless_methods_command_call.txt11
-rw-r--r--test/prism/fixtures/4.0/leading_logical.txt16
-rw-r--r--test/prism/fixtures/4.1/noblock.txt4
-rw-r--r--test/prism/fixtures/4.1/trailing_comma_after_method_arguments.txt15
-rw-r--r--test/prism/fixtures/4.1/void_value.txt7
-rw-r--r--test/prism/fixtures/__END__.txt3
-rw-r--r--test/prism/fixtures/and_or_with_suffix.txt17
-rw-r--r--test/prism/fixtures/blocks.txt8
-rw-r--r--test/prism/fixtures/bom_leading_space.txt1
-rw-r--r--test/prism/fixtures/bom_spaces.txt1
-rw-r--r--test/prism/fixtures/break.txt4
-rw-r--r--test/prism/fixtures/case_in_in.txt4
-rw-r--r--test/prism/fixtures/character_literal.txt2
-rw-r--r--test/prism/fixtures/command_method_call_2.txt1
-rw-r--r--test/prism/fixtures/command_method_call_3.txt19
-rw-r--r--test/prism/fixtures/endless_method_as_default_arg.txt11
-rw-r--r--test/prism/fixtures/endless_methods.txt4
-rw-r--r--test/prism/fixtures/escaped_newline_with_trailing_content.txt2
-rw-r--r--test/prism/fixtures/heredoc_dedent_line_continuation.txt5
-rw-r--r--test/prism/fixtures/heredoc_percent_q_newline_delimiter.txt22
-rw-r--r--test/prism/fixtures/next.txt4
-rw-r--r--test/prism/fixtures/non_void_value.txt31
-rw-r--r--test/prism/fixtures/return.txt3
-rw-r--r--test/prism/fixtures/string_concatination_frozen_false.txt5
-rw-r--r--test/prism/fixtures/string_concatination_frozen_true.txt5
-rw-r--r--test/prism/fixtures/unary_method_calls.txt8
-rw-r--r--test/prism/fixtures/write_command_operator.txt3
-rw-r--r--test/prism/fixtures_test.rb10
-rw-r--r--test/prism/lex_test.rb117
-rw-r--r--test/prism/locals_test.rb20
-rw-r--r--test/prism/magic_comment_test.rb5
-rw-r--r--test/prism/newline_offsets_test.rb27
-rw-r--r--test/prism/newline_test.rb3
-rw-r--r--test/prism/ractor_test.rb2
-rw-r--r--test/prism/result/breadth_first_search_test.rb11
-rw-r--r--test/prism/result/continuable_test.rb124
-rw-r--r--test/prism/result/error_recovery_test.rb237
-rw-r--r--test/prism/result/numeric_value_test.rb11
-rw-r--r--test/prism/result/overlap_test.rb9
-rw-r--r--test/prism/result/source_location_test.rb16
-rw-r--r--test/prism/result/static_literals_test.rb5
-rw-r--r--test/prism/result/warnings_test.rb19
-rw-r--r--test/prism/ruby/find_fixtures.rb69
-rw-r--r--test/prism/ruby/find_test.rb242
-rw-r--r--test/prism/ruby/location_test.rb49
-rw-r--r--test/prism/ruby/parameters_signature_test.rb15
-rw-r--r--test/prism/ruby/parser_test.rb50
-rw-r--r--test/prism/ruby/ripper_test.rb275
-rw-r--r--test/prism/ruby/ruby_parser_test.rb18
-rw-r--r--test/prism/ruby/source_test.rb51
-rw-r--r--test/prism/snippets_test.rb12
-rw-r--r--test/prism/test_helper.rb58
-rw-r--r--test/psych/test_data.rb26
-rw-r--r--test/psych/test_parser.rb42
-rw-r--r--test/psych/test_scalar_scanner.rb5
-rw-r--r--test/psych/visitors/test_to_ruby.rb6
-rw-r--r--test/resolv/test_dns.rb127
-rw-r--r--test/resolv/test_resource.rb74
-rw-r--r--test/resolv/test_win32_config.rb26
-rw-r--r--test/ripper/assert_parse_files.rb1
-rw-r--r--test/ripper/test_lexer.rb52
-rw-r--r--test/ripper/test_parser_events.rb7
-rw-r--r--test/ruby/box/a.1_1_0.rb17
-rw-r--r--test/ruby/box/a.1_2_0.rb17
-rw-r--r--test/ruby/box/a.rb15
-rw-r--r--test/ruby/box/autoloading.rb8
-rw-r--r--test/ruby/box/blank.rb (renamed from test/ruby/namespace/blank.rb)0
-rw-r--r--test/ruby/box/blank1.rb (renamed from test/ruby/namespace/blank1.rb)0
-rw-r--r--test/ruby/box/blank2.rb (renamed from test/ruby/namespace/blank2.rb)0
-rw-r--r--test/ruby/box/box.rb10
-rw-r--r--test/ruby/box/call_proc.rb (renamed from test/ruby/namespace/call_proc.rb)0
-rw-r--r--test/ruby/box/call_toplevel.rb (renamed from test/ruby/namespace/call_toplevel.rb)0
-rw-r--r--test/ruby/box/consts.rb148
-rw-r--r--test/ruby/box/define_toplevel.rb (renamed from test/ruby/namespace/define_toplevel.rb)0
-rw-r--r--test/ruby/box/global_vars.rb37
-rw-r--r--test/ruby/box/instance_variables.rb (renamed from test/ruby/namespace/instance_variables.rb)0
-rw-r--r--test/ruby/box/line_splitter.rb (renamed from test/ruby/namespace/line_splitter.rb)0
-rw-r--r--test/ruby/box/load_path.rb (renamed from test/ruby/namespace/load_path.rb)0
-rw-r--r--test/ruby/box/open_class_with_include.rb (renamed from test/ruby/namespace/open_class_with_include.rb)0
-rw-r--r--test/ruby/box/proc_callee.rb (renamed from test/ruby/namespace/proc_callee.rb)0
-rw-r--r--test/ruby/box/proc_caller.rb (renamed from test/ruby/namespace/proc_caller.rb)0
-rw-r--r--test/ruby/box/procs.rb64
-rw-r--r--test/ruby/box/raise.rb (renamed from test/ruby/namespace/raise.rb)0
-rw-r--r--test/ruby/box/returns_proc.rb (renamed from test/ruby/namespace/returns_proc.rb)0
-rw-r--r--test/ruby/box/singleton_methods.rb (renamed from test/ruby/namespace/singleton_methods.rb)0
-rw-r--r--test/ruby/box/string_ext.rb (renamed from test/ruby/namespace/string_ext.rb)0
-rw-r--r--test/ruby/box/string_ext_caller.rb (renamed from test/ruby/namespace/string_ext_caller.rb)0
-rw-r--r--test/ruby/box/string_ext_calling.rb (renamed from test/ruby/namespace/string_ext_calling.rb)0
-rw-r--r--test/ruby/box/string_ext_eval_caller.rb (renamed from test/ruby/namespace/string_ext_eval_caller.rb)0
-rw-r--r--test/ruby/box/top_level.rb (renamed from test/ruby/namespace/top_level.rb)0
-rw-r--r--test/ruby/enc/test_emoji_breaks.rb2
-rw-r--r--test/ruby/namespace/a.1_1_0.rb17
-rw-r--r--test/ruby/namespace/a.1_2_0.rb17
-rw-r--r--test/ruby/namespace/a.rb15
-rw-r--r--test/ruby/namespace/autoloading.rb8
-rw-r--r--test/ruby/namespace/consts.rb147
-rw-r--r--test/ruby/namespace/current.rb13
-rw-r--r--test/ruby/namespace/global_vars.rb37
-rw-r--r--test/ruby/namespace/ns.rb10
-rw-r--r--test/ruby/namespace/procs.rb64
-rw-r--r--test/ruby/sentence.rb2
-rw-r--r--test/ruby/test_allocation.rb57
-rw-r--r--test/ruby/test_array.rb48
-rw-r--r--test/ruby/test_ast.rb94
-rw-r--r--test/ruby/test_autoload.rb107
-rw-r--r--test/ruby/test_backtrace.rb10
-rw-r--r--test/ruby/test_beginendblock.rb3
-rw-r--r--test/ruby/test_bignum.rb3
-rw-r--r--test/ruby/test_box.rb1219
-rw-r--r--test/ruby/test_call.rb48
-rw-r--r--test/ruby/test_class.rb140
-rw-r--r--test/ruby/test_compile_prism.rb23
-rw-r--r--test/ruby/test_data.rb29
-rw-r--r--test/ruby/test_defined.rb28
-rw-r--r--test/ruby/test_encoding.rb4
-rw-r--r--test/ruby/test_enum.rb10
-rw-r--r--test/ruby/test_enumerator.rb28
-rw-r--r--test/ruby/test_env.rb35
-rw-r--r--test/ruby/test_exception.rb29
-rw-r--r--test/ruby/test_fiber.rb41
-rw-r--r--test/ruby/test_file_exhaustive.rb44
-rw-r--r--test/ruby/test_float.rb39
-rw-r--r--test/ruby/test_frozen.rb16
-rw-r--r--test/ruby/test_gc.rb132
-rw-r--r--test/ruby/test_gc_compact.rb58
-rw-r--r--test/ruby/test_hash.rb6
-rw-r--r--test/ruby/test_integer.rb2
-rw-r--r--test/ruby/test_io.rb80
-rw-r--r--test/ruby/test_io_buffer.rb387
-rw-r--r--test/ruby/test_io_m17n.rb41
-rw-r--r--test/ruby/test_iseq.rb74
-rw-r--r--test/ruby/test_lambda.rb14
-rw-r--r--test/ruby/test_lazy_enumerator.rb21
-rw-r--r--test/ruby/test_literal.rb5
-rw-r--r--test/ruby/test_marshal.rb69
-rw-r--r--test/ruby/test_math.rb12
-rw-r--r--test/ruby/test_metaclass.rb2
-rw-r--r--test/ruby/test_method.rb34
-rw-r--r--test/ruby/test_module.rb102
-rw-r--r--test/ruby/test_namespace.rb618
-rw-r--r--test/ruby/test_nomethod_error.rb30
-rw-r--r--test/ruby/test_numeric.rb12
-rw-r--r--test/ruby/test_object.rb191
-rw-r--r--test/ruby/test_object_id.rb12
-rw-r--r--test/ruby/test_optimization.rb21
-rw-r--r--test/ruby/test_pack.rb167
-rw-r--r--test/ruby/test_parse.rb19
-rw-r--r--test/ruby/test_pattern_matching.rb42
-rw-r--r--test/ruby/test_proc.rb221
-rw-r--r--test/ruby/test_process.rb31
-rw-r--r--test/ruby/test_ractor.rb215
-rw-r--r--test/ruby/test_range.rb7
-rw-r--r--test/ruby/test_rational.rb38
-rw-r--r--test/ruby/test_refinement.rb950
-rw-r--r--test/ruby/test_regexp.rb114
-rw-r--r--test/ruby/test_require.rb48
-rw-r--r--test/ruby/test_rubyoptions.rb100
-rw-r--r--test/ruby/test_set.rb137
-rw-r--r--test/ruby/test_settracefunc.rb212
-rw-r--r--test/ruby/test_shapes.rb232
-rw-r--r--test/ruby/test_signal.rb22
-rw-r--r--test/ruby/test_sleep.rb18
-rw-r--r--test/ruby/test_string.rb309
-rw-r--r--test/ruby/test_struct.rb12
-rw-r--r--test/ruby/test_super.rb29
-rw-r--r--test/ruby/test_symbol.rb5
-rw-r--r--test/ruby/test_syntax.rb278
-rw-r--r--test/ruby/test_thread.rb109
-rw-r--r--test/ruby/test_thread_cv.rb4
-rw-r--r--test/ruby/test_thread_queue.rb8
-rw-r--r--test/ruby/test_time.rb7
-rw-r--r--test/ruby/test_time_tz.rb1
-rw-r--r--test/ruby/test_transcode.rb14
-rw-r--r--test/ruby/test_variable.rb128
-rw-r--r--test/ruby/test_vm_dump.rb3
-rw-r--r--test/ruby/test_weakmap.rb34
-rw-r--r--test/ruby/test_yield.rb2
-rw-r--r--test/ruby/test_yjit.rb156
-rw-r--r--test/ruby/test_zjit.rb2011
-rw-r--r--test/rubygems/coverage_setup.rb9
-rw-r--r--test/rubygems/helper.rb122
-rw-r--r--test/rubygems/installer_test_case.rb17
-rw-r--r--test/rubygems/package/tar_test_case.rb38
-rw-r--r--test/rubygems/test_bundled_ca.rb2
-rw-r--r--test/rubygems/test_gem.rb73
-rw-r--r--test/rubygems/test_gem_bundler_version_finder.rb157
-rw-r--r--test/rubygems/test_gem_command_manager.rb43
-rw-r--r--test/rubygems/test_gem_commands_build_command.rb10
-rw-r--r--test/rubygems/test_gem_commands_cert_command.rb22
-rw-r--r--test/rubygems/test_gem_commands_environment_command.rb4
-rw-r--r--test/rubygems/test_gem_commands_exec_command.rb29
-rw-r--r--test/rubygems/test_gem_commands_fetch_command.rb2
-rw-r--r--test/rubygems/test_gem_commands_help_command.rb2
-rw-r--r--test/rubygems/test_gem_commands_info_command.rb2
-rw-r--r--test/rubygems/test_gem_commands_install_command.rb46
-rw-r--r--test/rubygems/test_gem_commands_open_command.rb2
-rw-r--r--test/rubygems/test_gem_commands_owner_command.rb14
-rw-r--r--test/rubygems/test_gem_commands_pristine_command.rb8
-rw-r--r--test/rubygems/test_gem_commands_push_command.rb154
-rw-r--r--test/rubygems/test_gem_commands_query_command.rb830
-rw-r--r--test/rubygems/test_gem_commands_setup_command.rb4
-rw-r--r--test/rubygems/test_gem_commands_sources_command.rb685
-rw-r--r--test/rubygems/test_gem_commands_uninstall_command.rb2
-rw-r--r--test/rubygems/test_gem_commands_update_command.rb32
-rw-r--r--test/rubygems/test_gem_commands_which_command.rb2
-rw-r--r--test/rubygems/test_gem_commands_yank_command.rb1
-rw-r--r--test/rubygems/test_gem_config_file.rb56
-rw-r--r--test/rubygems/test_gem_dependency_installer.rb142
-rw-r--r--test/rubygems/test_gem_dependency_resolution_error.rb23
-rw-r--r--test/rubygems/test_gem_ext_builder.rb69
-rw-r--r--test/rubygems/test_gem_ext_cargo_builder/custom_name/ext/custom_name_lib/Cargo.lock51
-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.lock51
-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_link_flag_converter.rb2
-rw-r--r--test/rubygems/test_gem_ext_cmake_builder.rb97
-rw-r--r--test/rubygems/test_gem_ext_rake_builder.rb2
-rw-r--r--test/rubygems/test_gem_gem_runner.rb11
-rw-r--r--test/rubygems/test_gem_gemcutter_utilities.rb4
-rw-r--r--test/rubygems/test_gem_impossible_dependencies_error.rb60
-rw-r--r--test/rubygems/test_gem_install_update_options.rb12
-rw-r--r--test/rubygems/test_gem_installer.rb379
-rw-r--r--test/rubygems/test_gem_name_tuple.rb37
-rw-r--r--test/rubygems/test_gem_package.rb187
-rw-r--r--test/rubygems/test_gem_package_old.rb2
-rw-r--r--test/rubygems/test_gem_package_tar_header_ractor.rb61
-rw-r--r--test/rubygems/test_gem_path_support.rb8
-rw-r--r--test/rubygems/test_gem_platform.rb122
-rw-r--r--test/rubygems/test_gem_remote_fetcher.rb237
-rw-r--r--test/rubygems/test_gem_request.rb2
-rw-r--r--test/rubygems/test_gem_request_connection_pools.rb12
-rw-r--r--test/rubygems/test_gem_request_set.rb132
-rw-r--r--test/rubygems/test_gem_request_set_lockfile_parser.rb544
-rw-r--r--test/rubygems/test_gem_request_set_lockfile_tokenizer.rb307
-rw-r--r--test/rubygems/test_gem_requirement.rb22
-rw-r--r--test/rubygems/test_gem_resolver.rb496
-rw-r--r--test/rubygems/test_gem_resolver_conflict.rb80
-rw-r--r--test/rubygems/test_gem_resolver_git_specification.rb38
-rw-r--r--test/rubygems/test_gem_resolver_strategy.rb163
-rw-r--r--test/rubygems/test_gem_safe_marshal.rb2
-rw-r--r--test/rubygems/test_gem_safe_yaml.rb1302
-rw-r--r--test/rubygems/test_gem_security_trust_dir.rb6
-rw-r--r--test/rubygems/test_gem_source_git.rb2
-rw-r--r--test/rubygems/test_gem_source_list.rb127
-rw-r--r--test/rubygems/test_gem_source_local.rb24
-rw-r--r--test/rubygems/test_gem_specification.rb227
-rw-r--r--test/rubygems/test_gem_stub_specification.rb26
-rw-r--r--test/rubygems/test_gem_text.rb17
-rw-r--r--test/rubygems/test_gem_uri.rb2
-rw-r--r--test/rubygems/test_gem_util.rb11
-rw-r--r--test/rubygems/test_gem_util_atomic_file_writer.rb12
-rw-r--r--test/rubygems/test_gem_version.rb92
-rw-r--r--test/rubygems/test_project_sanity.rb3
-rw-r--r--test/rubygems/test_require.rb19
-rw-r--r--test/rubygems/test_rubygems.rb1
-rw-r--r--test/socket/test_ancdata.rb18
-rw-r--r--test/socket/test_nonblock.rb4
-rw-r--r--test/socket/test_socket.rb97
-rw-r--r--test/socket/test_tcp.rb4
-rw-r--r--test/socket/test_unix.rb20
-rw-r--r--test/stringio/test_stringio.rb119
-rw-r--r--test/strscan/test_stringscanner.rb73
-rw-r--r--test/test_bundled_gems.rb38
-rw-r--r--test/test_delegate.rb51
-rw-r--r--test/test_extlibs.rb2
-rw-r--r--test/test_ipaddr.rb60
-rw-r--r--test/test_pp.rb58
-rw-r--r--test/test_prettyprint.rb71
-rw-r--r--test/test_timeout.rb264
-rw-r--r--test/test_tsort.rb115
-rw-r--r--test/test_unicode_normalize.rb28
-rw-r--r--test/uri/test_common.rb3
-rw-r--r--test/uri/test_generic.rb15
-rw-r--r--test/uri/test_mailto.rb26
-rw-r--r--test/win32/test_registry.rb256
-rw-r--r--test/zlib/test_zlib.rb85
-rw-r--r--thread.c182
-rw-r--r--thread_none.c10
-rw-r--r--thread_pthread.c298
-rw-r--r--thread_pthread.h21
-rw-r--r--thread_pthread_mn.c166
-rw-r--r--thread_sync.c1425
-rw-r--r--thread_sync.rb649
-rw-r--r--thread_win32.c18
-rw-r--r--time.c21
-rw-r--r--timev.rb18
-rwxr-xr-xtool/auto-style.rb152
-rwxr-xr-xtool/auto_review_pr.rb172
-rw-r--r--tool/bundler/dev_gems.rb5
-rw-r--r--tool/bundler/dev_gems.rb.lock127
-rw-r--r--tool/bundler/rubocop_gems.rb4
-rw-r--r--tool/bundler/rubocop_gems.rb.lock170
-rw-r--r--tool/bundler/standard_gems.rb4
-rw-r--r--tool/bundler/standard_gems.rb.lock190
-rw-r--r--tool/bundler/test_gems.rb5
-rw-r--r--tool/bundler/test_gems.rb.lock94
-rw-r--r--tool/bundler/vendor_gems.rb14
-rw-r--r--tool/bundler/vendor_gems.rb.lock60
-rwxr-xr-xtool/commit-email.rb372
-rw-r--r--tool/downloader.rb2
-rw-r--r--tool/dump_ast.c77
-rwxr-xr-xtool/dump_ast.mkmf.rb37
-rwxr-xr-xtool/enc-unicode.rb3
-rwxr-xr-xtool/fetch-bundled_gems.rb19
-rwxr-xr-xtool/format-release51
-rwxr-xr-xtool/ifchange4
-rwxr-xr-xtool/leaked-globals2
-rw-r--r--tool/lib/_tmpdir.rb115
-rw-r--r--tool/lib/bundled_gem.rb49
-rw-r--r--tool/lib/colorize.rb72
-rw-r--r--tool/lib/core_assertions.rb84
-rw-r--r--tool/lib/envutil.rb21
-rw-r--r--tool/lib/leakchecker.rb36
-rw-r--r--tool/lib/memory_status.rb100
-rw-r--r--tool/lib/output.rb13
-rw-r--r--tool/lib/test/jobserver.rb47
-rw-r--r--tool/lib/test/unit.rb24
-rw-r--r--tool/lib/test/unit/assertions.rb10
-rw-r--r--tool/lib/vcs.rb75
-rw-r--r--tool/lrama/NEWS.md445
-rwxr-xr-xtool/lrama/exe/lrama2
-rw-r--r--tool/lrama/lib/lrama.rb10
-rw-r--r--tool/lrama/lib/lrama/bitmap.rb23
-rw-r--r--tool/lrama/lib/lrama/command.rb138
-rw-r--r--tool/lrama/lib/lrama/context.rb46
-rw-r--r--tool/lrama/lib/lrama/counterexamples.rb304
-rw-r--r--tool/lrama/lib/lrama/counterexamples/derivation.rb18
-rw-r--r--tool/lrama/lib/lrama/counterexamples/example.rb69
-rw-r--r--tool/lrama/lib/lrama/counterexamples/node.rb30
-rw-r--r--tool/lrama/lib/lrama/counterexamples/path.rb26
-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.rb25
-rw-r--r--tool/lrama/lib/lrama/counterexamples/transition_path.rb19
-rw-r--r--tool/lrama/lib/lrama/counterexamples/triple.rb36
-rw-r--r--tool/lrama/lib/lrama/diagnostics.rb36
-rw-r--r--tool/lrama/lib/lrama/diagram.rb77
-rw-r--r--tool/lrama/lib/lrama/digraph.rb35
-rw-r--r--tool/lrama/lib/lrama/erb.rb29
-rw-r--r--tool/lrama/lib/lrama/grammar.rb266
-rw-r--r--tool/lrama/lib/lrama/grammar/auxiliary.rb7
-rw-r--r--tool/lrama/lib/lrama/grammar/binding.rb63
-rw-r--r--tool/lrama/lib/lrama/grammar/code.rb17
-rw-r--r--tool/lrama/lib/lrama/grammar/code/destructor_code.rb11
-rw-r--r--tool/lrama/lib/lrama/grammar/code/initial_action_code.rb3
-rw-r--r--tool/lrama/lib/lrama/grammar/code/no_reference_code.rb3
-rw-r--r--tool/lrama/lib/lrama/grammar/code/printer_code.rb11
-rw-r--r--tool/lrama/lib/lrama/grammar/code/rule_action.rb50
-rw-r--r--tool/lrama/lib/lrama/grammar/counter.rb10
-rw-r--r--tool/lrama/lib/lrama/grammar/destructor.rb15
-rw-r--r--tool/lrama/lib/lrama/grammar/error_token.rb15
-rw-r--r--tool/lrama/lib/lrama/grammar/inline.rb3
-rw-r--r--tool/lrama/lib/lrama/grammar/inline/resolver.rb80
-rw-r--r--tool/lrama/lib/lrama/grammar/parameterized.rb5
-rw-r--r--tool/lrama/lib/lrama/grammar/parameterized/resolver.rb73
-rw-r--r--tool/lrama/lib/lrama/grammar/parameterized/rhs.rb45
-rw-r--r--tool/lrama/lib/lrama/grammar/parameterized/rule.rb36
-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.rb13
-rw-r--r--tool/lrama/lib/lrama/grammar/precedence.rb44
-rw-r--r--tool/lrama/lib/lrama/grammar/printer.rb9
-rw-r--r--tool/lrama/lib/lrama/grammar/reference.rb13
-rw-r--r--tool/lrama/lib/lrama/grammar/rule.rb66
-rw-r--r--tool/lrama/lib/lrama/grammar/rule_builder.rb153
-rw-r--r--tool/lrama/lib/lrama/grammar/stdlib.y116
-rw-r--r--tool/lrama/lib/lrama/grammar/symbol.rb82
-rw-r--r--tool/lrama/lib/lrama/grammar/symbols/resolver.rb67
-rw-r--r--tool/lrama/lib/lrama/grammar/type.rb14
-rw-r--r--tool/lrama/lib/lrama/grammar/union.rb13
-rw-r--r--tool/lrama/lib/lrama/grammar_validator.rb37
-rw-r--r--tool/lrama/lib/lrama/lexer.rb74
-rw-r--r--tool/lrama/lib/lrama/lexer/location.rb33
-rw-r--r--tool/lrama/lib/lrama/lexer/token.rb62
-rw-r--r--tool/lrama/lib/lrama/lexer/token/base.rb73
-rw-r--r--tool/lrama/lib/lrama/lexer/token/char.rb17
-rw-r--r--tool/lrama/lib/lrama/lexer/token/empty.rb14
-rw-r--r--tool/lrama/lib/lrama/lexer/token/ident.rb4
-rw-r--r--tool/lrama/lib/lrama/lexer/token/instantiate_rule.rb8
-rw-r--r--tool/lrama/lib/lrama/lexer/token/int.rb14
-rw-r--r--tool/lrama/lib/lrama/lexer/token/str.rb11
-rw-r--r--tool/lrama/lib/lrama/lexer/token/tag.rb4
-rw-r--r--tool/lrama/lib/lrama/lexer/token/token.rb11
-rw-r--r--tool/lrama/lib/lrama/lexer/token/user_code.rb100
-rw-r--r--tool/lrama/lib/lrama/logger.rb14
-rw-r--r--tool/lrama/lib/lrama/option_parser.rb72
-rw-r--r--tool/lrama/lib/lrama/options.rb32
-rw-r--r--tool/lrama/lib/lrama/output.rb17
-rw-r--r--tool/lrama/lib/lrama/parser.rb1591
-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/reporter.rb39
-rw-r--r--tool/lrama/lib/lrama/reporter/conflicts.rb44
-rw-r--r--tool/lrama/lib/lrama/reporter/grammar.rb39
-rw-r--r--tool/lrama/lib/lrama/reporter/precedences.rb54
-rw-r--r--tool/lrama/lib/lrama/reporter/profile.rb4
-rw-r--r--tool/lrama/lib/lrama/reporter/profile/call_stack.rb45
-rw-r--r--tool/lrama/lib/lrama/reporter/profile/memory.rb44
-rw-r--r--tool/lrama/lib/lrama/reporter/rules.rb43
-rw-r--r--tool/lrama/lib/lrama/reporter/states.rb387
-rw-r--r--tool/lrama/lib/lrama/reporter/terms.rb44
-rw-r--r--tool/lrama/lib/lrama/state.rb501
-rw-r--r--tool/lrama/lib/lrama/state/action.rb5
-rw-r--r--tool/lrama/lib/lrama/state/action/goto.rb33
-rw-r--r--tool/lrama/lib/lrama/state/action/reduce.rb71
-rw-r--r--tool/lrama/lib/lrama/state/action/shift.rb39
-rw-r--r--tool/lrama/lib/lrama/state/inadequacy_annotation.rb140
-rw-r--r--tool/lrama/lib/lrama/state/item.rb120
-rw-r--r--tool/lrama/lib/lrama/state/reduce.rb37
-rw-r--r--tool/lrama/lib/lrama/state/reduce_reduce_conflict.rb15
-rw-r--r--tool/lrama/lib/lrama/state/resolved_conflict.rb42
-rw-r--r--tool/lrama/lib/lrama/state/shift.rb15
-rw-r--r--tool/lrama/lib/lrama/state/shift_reduce_conflict.rb15
-rw-r--r--tool/lrama/lib/lrama/states.rb622
-rw-r--r--tool/lrama/lib/lrama/states/item.rb91
-rw-r--r--tool/lrama/lib/lrama/states_reporter.rb362
-rw-r--r--tool/lrama/lib/lrama/trace_reporter.rb45
-rw-r--r--tool/lrama/lib/lrama/tracer.rb51
-rw-r--r--tool/lrama/lib/lrama/tracer/actions.rb22
-rw-r--r--tool/lrama/lib/lrama/tracer/closure.rb30
-rw-r--r--tool/lrama/lib/lrama/tracer/duration.rb38
-rw-r--r--tool/lrama/lib/lrama/tracer/only_explicit_rules.rb24
-rw-r--r--tool/lrama/lib/lrama/tracer/rules.rb23
-rw-r--r--tool/lrama/lib/lrama/tracer/state.rb33
-rw-r--r--tool/lrama/lib/lrama/version.rb3
-rw-r--r--tool/lrama/lib/lrama/warnings.rb33
-rw-r--r--tool/lrama/lib/lrama/warnings/conflicts.rb27
-rw-r--r--tool/lrama/lib/lrama/warnings/implicit_empty.rb29
-rw-r--r--tool/lrama/lib/lrama/warnings/name_conflicts.rb63
-rw-r--r--tool/lrama/lib/lrama/warnings/redefined_rules.rb23
-rw-r--r--tool/lrama/lib/lrama/warnings/required.rb23
-rw-r--r--tool/lrama/lib/lrama/warnings/useless_precedence.rb25
-rw-r--r--tool/lrama/template/bison/_yacc.h8
-rw-r--r--tool/lrama/template/diagram/diagram.html102
-rw-r--r--tool/m4/ruby_append_option.m42
-rw-r--r--tool/m4/ruby_defint.m43
-rwxr-xr-xtool/make-snapshot41
-rwxr-xr-xtool/merger.rb21
-rwxr-xr-xtool/missing-baseruby.bat9
-rw-r--r--tool/mk_builtin_loader.rb388
-rwxr-xr-xtool/mkconfig.rb1
-rw-r--r--tool/notes-github-pr.rb138
-rw-r--r--tool/notify-slack-commits.rb87
-rwxr-xr-xtool/outdate-bundled-gems.rb23
-rw-r--r--tool/prereq.status8
-rwxr-xr-xtool/rbinstall.rb105
-rw-r--r--tool/rbs_skip_tests44
-rw-r--r--tool/rbs_skip_tests_windows7
-rwxr-xr-xtool/rdoc-srcdir5
-rwxr-xr-xtool/redmine-backporter.rb2
-rwxr-xr-xtool/releng/gen-mail.rb2
-rwxr-xr-xtool/releng/update-www-meta.rb25
-rwxr-xr-xtool/ruby-version.rb52
-rw-r--r--tool/ruby_vm/models/bare_instruction.rb236
-rw-r--r--tool/ruby_vm/models/bare_instructions.rb244
-rw-r--r--tool/ruby_vm/models/instructions.rb19
-rw-r--r--tool/ruby_vm/models/instructions_unification.rb42
-rw-r--r--tool/ruby_vm/models/instructions_unifications.rb42
-rw-r--r--tool/ruby_vm/models/operands_unification.rb141
-rw-r--r--tool/ruby_vm/models/operands_unifications.rb141
-rw-r--r--tool/ruby_vm/models/trace_instruction.rb70
-rw-r--r--tool/ruby_vm/models/trace_instructions.rb74
-rw-r--r--tool/ruby_vm/models/zjit_instruction.rb56
-rw-r--r--tool/ruby_vm/models/zjit_instructions.rb58
-rw-r--r--tool/ruby_vm/views/_insn_leaf_info.erb18
-rw-r--r--tool/ruby_vm/views/_insn_sp_pc_dependency.erb27
-rw-r--r--tool/ruby_vm/views/_leaf_helpers.erb6
-rw-r--r--tool/ruby_vm/views/_zjit_helpers.erb4
-rw-r--r--tool/ruby_vm/views/insns_info.inc.erb1
-rw-r--r--tool/ruby_vm/views/optinsn.inc.erb4
-rw-r--r--tool/ruby_vm/views/vm.inc.erb10
-rwxr-xr-xtool/sync_default_gems.rb1124
-rw-r--r--tool/test-bundled-gems.rb219
-rw-r--r--tool/test/init.rb12
-rw-r--r--tool/test/test_commit_email.rb102
-rwxr-xr-xtool/test/test_sync_default_gems.rb110
-rw-r--r--tool/test/testunit/test_assertion.rb25
-rw-r--r--tool/test/testunit/test_minitest_unit.rb9
-rw-r--r--tool/test/testunit/test_parallel.rb6
-rwxr-xr-xtool/update-NEWS-gemlist.rb28
-rwxr-xr-xtool/update-NEWS-github-release.rb395
-rwxr-xr-xtool/update-bundled_gems.rb54
-rwxr-xr-xtool/update-deps3
-rwxr-xr-xtool/zjit_bisect.rb43
-rwxr-xr-xtool/zjit_diff.rb272
-rw-r--r--tool/zjit_iongraph.html551
-rwxr-xr-xtool/zjit_iongraph.rb38
-rw-r--r--trace_point.rb8
-rw-r--r--transcode.c121
-rw-r--r--universal_parser.c2
-rw-r--r--util.c36
-rw-r--r--variable.c1447
-rw-r--r--vcpkg.json2
-rw-r--r--version.c23
-rw-r--r--vm.c803
-rw-r--r--vm_args.c70
-rw-r--r--vm_backtrace.c147
-rw-r--r--vm_callinfo.h121
-rw-r--r--vm_core.h302
-rw-r--r--vm_debug.h8
-rw-r--r--vm_dump.c350
-rw-r--r--vm_eval.c285
-rw-r--r--vm_exec.c2
-rw-r--r--vm_exec.h27
-rw-r--r--vm_insnhelper.c949
-rw-r--r--vm_insnhelper.h15
-rw-r--r--vm_method.c401
-rw-r--r--vm_sync.c25
-rw-r--r--vm_sync.h7
-rw-r--r--vm_trace.c487
-rw-r--r--weakmap.c512
-rw-r--r--win32/Makefile.sub255
-rw-r--r--[-rwxr-xr-x]win32/configure.bat479
-rw-r--r--win32/enc-setup.mak4
-rw-r--r--win32/file.c4
-rwxr-xr-xwin32/ifchange.bat117
-rwxr-xr-xwin32/install-buildtools.cmd28
-rwxr-xr-xwin32/install-msys-packages.cmd29
-rwxr-xr-xwin32/lastrev.bat30
-rwxr-xr-xwin32/makedirs.bat2
-rwxr-xr-xwin32/mkexports.rb10
-rwxr-xr-xwin32/rm.bat70
-rwxr-xr-xwin32/rmdirs.bat8
-rwxr-xr-xwin32/rtname.cmd71
-rw-r--r--win32/setup.mak100
-rw-r--r--win32/shellsplit.cmd114
-rw-r--r--win32/test_shellsplit.cmd28
-rwxr-xr-xwin32/vssetup.cmd83
-rw-r--r--win32/win32.c358
-rw-r--r--yjit.c378
-rw-r--r--yjit.h2
-rw-r--r--yjit.rb9
-rw-r--r--yjit/Cargo.lock22
-rw-r--r--yjit/Cargo.toml8
-rw-r--r--yjit/bindgen/src/main.rs151
-rw-r--r--yjit/src/asm/mod.rs4
-rw-r--r--yjit/src/backend/arm64/mod.rs17
-rw-r--r--yjit/src/backend/ir.rs16
-rw-r--r--yjit/src/backend/tests.rs4
-rw-r--r--yjit/src/codegen.rs608
-rw-r--r--yjit/src/core.rs133
-rw-r--r--yjit/src/cruby.rs34
-rw-r--r--yjit/src/cruby_bindings.inc.rs588
-rw-r--r--yjit/src/invariants.rs10
-rw-r--r--yjit/src/stats.rs74
-rw-r--r--yjit/src/utils.rs15
-rw-r--r--yjit/src/virtualmem.rs13
-rw-r--r--yjit/src/yjit.rs18
-rw-r--r--yjit/yjit.mk44
-rw-r--r--zjit.c330
-rw-r--r--zjit.h89
-rw-r--r--zjit.rb243
-rw-r--r--zjit/.gitignore1
-rw-r--r--zjit/Cargo.lock552
-rw-r--r--zjit/Cargo.toml12
-rw-r--r--zjit/bindgen/src/main.rs203
-rw-r--r--zjit/build.rs12
-rw-r--r--zjit/src/asm/arm64/arg/sf.rs2
-rw-r--r--zjit/src/asm/arm64/inst/atomic.rs2
-rw-r--r--zjit/src/asm/arm64/inst/branch.rs2
-rw-r--r--zjit/src/asm/arm64/inst/load_literal.rs4
-rw-r--r--zjit/src/asm/arm64/inst/load_register.rs2
-rw-r--r--zjit/src/asm/arm64/inst/load_store.rs8
-rw-r--r--zjit/src/asm/arm64/inst/load_store_exclusive.rs2
-rw-r--r--zjit/src/asm/arm64/inst/mod.rs2
-rw-r--r--zjit/src/asm/arm64/inst/mov.rs6
-rw-r--r--zjit/src/asm/arm64/inst/reg_pair.rs2
-rw-r--r--zjit/src/asm/arm64/inst/test_bit.rs2
-rw-r--r--zjit/src/asm/arm64/inst/udf.rs52
-rw-r--r--zjit/src/asm/arm64/mod.rs436
-rw-r--r--zjit/src/asm/arm64/opnd.rs89
-rw-r--r--zjit/src/asm/mod.rs123
-rw-r--r--zjit/src/asm/x86_64/mod.rs194
-rw-r--r--zjit/src/asm/x86_64/tests.rs997
-rw-r--r--zjit/src/assertions.rs21
-rw-r--r--zjit/src/backend/arm64/mod.rs1808
-rw-r--r--zjit/src/backend/lir.rs4093
-rw-r--r--zjit/src/backend/mod.rs6
-rw-r--r--zjit/src/backend/parcopy.rs368
-rw-r--r--zjit/src/backend/tests.rs122
-rw-r--r--zjit/src/backend/x86_64/mod.rs1843
-rw-r--r--zjit/src/bitset.rs133
-rw-r--r--zjit/src/cast.rs14
-rw-r--r--zjit/src/codegen.rs3421
-rw-r--r--zjit/src/codegen_tests.rs5814
-rw-r--r--zjit/src/cruby.rs585
-rw-r--r--zjit/src/cruby_bindings.inc.rs1744
-rw-r--r--zjit/src/cruby_methods.rs893
-rw-r--r--zjit/src/disasm.rs31
-rw-r--r--zjit/src/distribution.rs32
-rw-r--r--zjit/src/gc.rs232
-rw-r--r--zjit/src/hir.rs12473
-rw-r--r--zjit/src/hir/opt_tests.rs17408
-rw-r--r--zjit/src/hir/tests.rs6433
-rw-r--r--zjit/src/hir_effect/gen_hir_effect.rb126
-rw-r--r--zjit/src/hir_effect/hir_effect.inc.rs63
-rw-r--r--zjit/src/hir_effect/mod.rs420
-rw-r--r--zjit/src/hir_type/gen_hir_type.rb123
-rw-r--r--zjit/src/hir_type/hir_type.inc.rs183
-rw-r--r--zjit/src/hir_type/mod.rs477
-rw-r--r--zjit/src/invariants.rs388
-rw-r--r--zjit/src/jit_frame.rs314
-rw-r--r--zjit/src/json.rs700
-rw-r--r--zjit/src/lib.rs22
-rw-r--r--zjit/src/options.rs420
-rw-r--r--zjit/src/payload.rs144
-rw-r--r--zjit/src/profile.rs384
-rw-r--r--zjit/src/state.rs429
-rw-r--r--zjit/src/stats.rs1194
-rw-r--r--zjit/src/ttycolors.rs31
-rw-r--r--zjit/src/virtualmem.rs82
-rw-r--r--zjit/zjit.mk76
5420 files changed, 284929 insertions, 187109 deletions
diff --git a/.document b/.document
index 82ca602bfb..753d6f9892 100644
--- a/.document
+++ b/.document
@@ -42,6 +42,9 @@ lib
# and some of the ext/ directory (which has its own .document file)
ext
+# For `prism`, ruby code is in lib and c in the prism folder
+prism
+
# rdoc files
NEWS.md
diff --git a/.gdbinit b/.gdbinit
index f204b3a235..4457f6f12b 100644
--- a/.gdbinit
+++ b/.gdbinit
@@ -185,12 +185,14 @@ define rp
print (struct RBasic *)($arg0)
else
if ($flags & RUBY_T_MASK) == RUBY_T_DATA
- if ((struct RTypedData *)($arg0))->type & 1
- printf "%sT_DATA%s(%s): ", $color_type, $color_end, ((const rb_data_type_t *)(((struct RTypedData *)($arg0))->type & ~1))->wrap_struct_name
- print (struct RTypedData *)($arg0)
+ set $data = (struct RTypedData *)($arg0)
+ set $type = (const rb_data_type_t *)($data->type & ~1)
+ printf "%sT_DATA%s(%s): ", $color_type, $color_end, $type->wrap_struct_name
+ print *$type
+ if ($data->type & 1)
+ print (void *)&$data->data
else
- printf "%sT_DATA%s: ", $color_type, $color_end
- print (struct RData *)($arg0)
+ print $data
end
else
if ($flags & RUBY_T_MASK) == RUBY_T_MATCH
@@ -972,7 +974,7 @@ end
define print_lineno
set $cfp = $arg0
- set $iseq = $cfp->iseq
+ set $iseq = rb_get_cfp_iseq($cfp)
set $pos = $cfp->pc - $iseq->body->iseq_encoded
if $pos != 0
set $pos = $pos - 1
@@ -1053,7 +1055,7 @@ define print_id
else
set $serial = (rb_id_serial_t)$id
end
- if $serial && $serial <= ruby_global_symbols.last_id
+ if $serial && $serial < ruby_global_symbols.next_id
set $idx = $serial / ID_ENTRY_UNIT
set $ids = (struct RArray *)ruby_global_symbols.ids
set $flags = $ids->basic.flags
@@ -1076,7 +1078,7 @@ define print_id
set $aryptr = $ary->as.heap.ptr
set $arylen = $ary->as.heap.len
end
- set $result = $aryptr[($serial % ID_ENTRY_UNIT) * ID_ENTRY_SIZE + $t]
+ set $result = $aryptr[($serial % ID_ENTRY_UNIT) + $t]
if $result != RUBY_Qnil
print_string $result
else
@@ -1110,16 +1112,17 @@ define rb_ps_thread
set $cfp = $ps_thread_th->ec->cfp
set $cfpend = (rb_control_frame_t *)($ps_thread_th->ec->vm_stack + $ps_thread_th->ec->vm_stack_size)-1
while $cfp < $cfpend
- if $cfp->iseq
- if !((VALUE)$cfp->iseq & RUBY_IMMEDIATE_MASK) && (((imemo_ifunc << RUBY_FL_USHIFT) | RUBY_T_IMEMO)==$cfp->iseq->flags & ((RUBY_IMEMO_MASK << RUBY_FL_USHIFT) | RUBY_T_MASK))
+ if $cfp->_iseq
+ set $iseq = rb_get_cfp_iseq($cfp)
+ if !((VALUE)$iseq & RUBY_IMMEDIATE_MASK) && (((imemo_ifunc << RUBY_FL_USHIFT) | RUBY_T_IMEMO)==$iseq->flags & ((RUBY_IMEMO_MASK << RUBY_FL_USHIFT) | RUBY_T_MASK))
printf "%d:ifunc ", $cfpend-$cfp
set print symbol-filename on
- output/a $cfp->iseq.body
+ output/a $iseq.body
set print symbol-filename off
printf "\n"
else
if $cfp->pc
- set $location = $cfp->iseq->body->location
+ set $location = $iseq->body->location
printf "%d:", $cfpend-$cfp
print_pathobj $location.pathobj
printf ":"
diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs
index 5fb9ba5f7d..d752612085 100644
--- a/.git-blame-ignore-revs
+++ b/.git-blame-ignore-revs
@@ -10,6 +10,11 @@ e63a2115f64433b21cb5dd67c5bf8b30f87ef293
712ac99e4d0384a941c80a9f48f62943ba7d97c0
d1474affa8e105bece209cc9d594bb0a989859e1
2da92388b948821269b18d6b178a680f17e41750
+5062c0c621d887367af8a054e5e5d83d7ec57dd3
+
+# Indentation
+0e4bad888e605d424b9222ae0ca43f85c1634e5e
+61aa46c41648c6d1e9b0daa1a292de551fde78df
# Enable Style/StringLiterals cop for RubyGems/Bundler
d7ffd3fea402239b16833cc434404a7af82d44f3
@@ -36,3 +41,14 @@ a0f7de814ae5c299d6ce99bed5fb308a05d50ba0
d4e24021d39e1f80f0055b55d91f8d5f22e15084
7a56c316418980b8a41fcbdc94067b2bda2ad112
e90282be7ba1bc8e3119f6e1a2c80356ceb3f80a
+26a9e0b4e31f7b5a9cbd755e0a15823a8fa51bae
+2f53985da9ee593fe524d408256835667938c7d7
+bf01f6ae89a95d8f5572e050facfe311c8c28aaf
+7480cd8d37fd71a41ce12b759090051c7e14fb5a
+
+# Win32: EOL code of batch files
+23f9a0d655c4d405bb2397a147a1523436205486
+b839989fd22fef85e2af19de1bc83aa72a5b22bd
+
+# ZJIT cargo-insta snapshot raw string literals
+b78e0a6ddf7df8a7568ea71284f593423c739551
diff --git a/.gitattributes b/.gitattributes
index 6ac6e6fcc3..f98c091e3f 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -7,3 +7,8 @@ tool/update-deps diff=ruby
tool/make-snapshot diff=ruby
tool/format-release diff=ruby
tool/leaked-globals diff=ruby
+
+# To strip CR from the batch files, set the `diff.dos.textconv` filter
+# like as `git config diff.dos.textconv $'sed \'s/\r$//\''`.
+*.bat diff=dos
+*.cmd diff=dos
diff --git a/.github/actions/capiext/action.yml b/.github/actions/capiext/action.yml
new file mode 100644
index 0000000000..ed69c8ac5e
--- /dev/null
+++ b/.github/actions/capiext/action.yml
@@ -0,0 +1,86 @@
+name: rubyspec C-API extensions
+
+inputs:
+ builddir:
+ required: false
+ default: '.'
+ make:
+ required: false
+ default: 'make -s'
+
+outputs:
+ key:
+ value: >-
+ ${{
+ !steps.restore.outputs.cache-hit &&
+ github.ref == 'refs/heads/master' &&
+ steps.config.outputs.key
+ }}
+
+runs:
+ using: composite
+
+ steps:
+ - id: config
+ shell: bash
+ run: |
+ eval $(grep -e '^arch *=' -e '^ruby_version *=' -e '^DLEXT *=' Makefile |
+ sed 's/ *= */=/')
+ case "${ruby_version}" in
+ *+*) key=capiexts-${arch}-${ruby_version}-${{ hashFiles('src/spec/ruby/optional/capi/ext/*.[ch]') }};;
+ *) key=;;
+ esac
+ echo version=$ruby_version >> $GITHUB_OUTPUT
+ echo key="$key" >> $GITHUB_OUTPUT
+ echo DLEXT=$DLEXT >> $GITHUB_OUTPUT
+ working-directory: ${{ inputs.builddir }}
+
+ - name: Restore previous CAPI extensions
+ uses: actions/cache/restore@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4
+ id: cache
+ with:
+ path: ${{ inputs.builddir }}/spec/ruby/optional/capi/ext/
+ key: ${{ steps.config.outputs.key }}
+ if: ${{ steps.config.outputs.key }}
+
+ - name: Run test-spec with previous CAPI extension binaries
+ id: check
+ shell: bash
+ run: | # zizmor: ignore[template-injection]
+ touch spec/ruby/optional/capi/ext/*.$DLEXT
+ [ ! -f spec/ruby/optional/capi/ext/\*.$DLEXT ]
+ ${{ inputs.make }} SPECOPTS=optional/capi test-spec
+ env:
+ DLEXT: ${{ steps.config.outputs.DLEXT }}
+ working-directory: ${{ inputs.builddir }}
+ if: ${{ steps.cache.outputs.cache-hit }}
+
+ - name: Strip CAPI extensions
+ id: strip
+ shell: bash
+ run: |
+ rm -f spec/ruby/optional/capi/ext/*.c
+ [ "$DLEXT" = bundle ] || # separated to .dSYM directories
+ strip spec/ruby/optional/capi/ext/*.$DLEXT
+ env:
+ DLEXT: ${{ steps.config.outputs.DLEXT }}
+ working-directory: ${{ inputs.builddir }}
+ if: >-
+ ${{true
+ && ! steps.cache.outputs.cache-hit
+ && github.ref_name == 'master'
+ }}
+
+ - name: Save CAPI extensions
+ uses: actions/cache/save@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4
+ with:
+ path: ${{ inputs.builddir }}/spec/ruby/optional/capi/ext/
+ key: ${{ steps.config.outputs.key }}
+ if: ${{ steps.strip.outcome == 'success' }}
+
+ - shell: bash
+ run: |
+ echo "::error::Change from ${prev} detected; bump up ABI version"
+ env:
+ prev: ${{ steps.config.outputs.version }}
+ if: ${{ always() && steps.check.outcome == 'failure' }}
diff --git a/.github/actions/compilers/action.yml b/.github/actions/compilers/action.yml
index 30ccd25a12..c700bbfe9e 100644
--- a/.github/actions/compilers/action.yml
+++ b/.github/actions/compilers/action.yml
@@ -5,7 +5,7 @@ description: >-
inputs:
tag:
required: false
- default: clang-18
+ default: clang-20
description: >-
container image tag to use in this run.
@@ -60,11 +60,17 @@ inputs:
description: >-
Whether to run `make check`
- mspecopt:
+ test_all:
required: false
default: ''
description: >-
- Additional options for mspec.
+ Whether to run `make test-all` with options for test-all.
+
+ test_spec:
+ required: false
+ default: ''
+ description: >-
+ Whether to run `make test-spec` with options for mspec.
static_exts:
required: false
@@ -75,7 +81,9 @@ runs:
using: composite
steps:
- shell: bash
- run: docker pull --quiet 'ghcr.io/ruby/ruby-ci-image:${{ inputs.tag }}'
+ run: docker pull --quiet "ghcr.io/ruby/ruby-ci-image:${INPUT_TAG}"
+ env:
+ INPUT_TAG: ${{ inputs.tag }}
- name: Enable Launchable conditionally
id: enable-launchable
@@ -93,27 +101,28 @@ runs:
docker run
--rm
--user=root
- --volume '${{ github.workspace }}:/github/workspace:ro'
+ --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 }}'
- --env LAUNCHABLE_ORGANIZATION='${{ github.repository_owner }}'
- --env LAUNCHABLE_WORKSPACE='${{ github.event.repository.name }}'
- --env LAUNCHABLE_ENABLED='${{ steps.enable-launchable.outputs.enable-launchable || false }}'
- --env GITHUB_PR_HEAD_SHA='${{ github.event.pull_request.head.sha || github.sha }}'
- --env GITHUB_PULL_REQUEST_URL='${{ github.event.pull_request.html_url }}'
- --env GITHUB_REF='${{ github.ref }}'
+ --env INPUT_WITH_GCC
+ --env INPUT_CFLAGS
+ --env INPUT_CXXFLAGS
+ --env INPUT_OPTFLAGS
+ --env INPUT_CPPFLAGS
+ --env INPUT_APPEND_CONFIGURE
+ --env INPUT_CHECK
+ --env INPUT_TEST_ALL
+ --env INPUT_TEST_SPEC
+ --env INPUT_ENABLE_SHARED
+ --env INPUT_STATIC_EXTS
+ --env LAUNCHABLE_ORGANIZATION
+ --env LAUNCHABLE_WORKSPACE
+ --env LAUNCHABLE_ENABLED
+ --env GITHUB_PR_HEAD_SHA
+ --env GITHUB_PULL_REQUEST_URL
+ --env GITHUB_REF
--env GITHUB_ACTIONS
--env GITHUB_RUN_ID
--env GITHUB_REPOSITORY
@@ -123,4 +132,33 @@ runs:
--env GITHUB_SHA
--env GITHUB_HEAD_REF
--env GITHUB_SERVER_URL
- 'ghcr.io/ruby/ruby-ci-image:${{ inputs.tag }}'
+ "ghcr.io/ruby/ruby-ci-image:${INPUT_TAG}"
+ env:
+ INPUT_TAG: ${{ inputs.tag }}
+ INPUT_WITH_GCC: ${{ inputs.with_gcc || inputs.tag }}
+ INPUT_CFLAGS: ${{ inputs.CFLAGS }}
+ INPUT_CXXFLAGS: ${{ inputs.CXXFLAGS }}
+ INPUT_OPTFLAGS: ${{ inputs.OPTFLAGS }}
+ INPUT_CPPFLAGS: ${{ inputs.cppflags }}
+ INPUT_APPEND_CONFIGURE: ${{ inputs.append_configure }}
+ INPUT_CHECK: ${{ inputs.check }}
+ INPUT_TEST_ALL: ${{ inputs.test_all }}
+ INPUT_TEST_SPEC: ${{ inputs.test_spec }}
+ INPUT_ENABLE_SHARED: ${{ inputs.enable_shared }}
+ INPUT_STATIC_EXTS: ${{ inputs.static_exts }}
+ LAUNCHABLE_ORGANIZATION: ${{ github.repository_owner }}
+ LAUNCHABLE_WORKSPACE: ${{ github.event.repository.name }}
+ LAUNCHABLE_ENABLED: ${{ steps.enable-launchable.outputs.enable-launchable || false }}
+ GITHUB_PR_HEAD_SHA: ${{ github.event.pull_request.head.sha || github.sha }}
+ GITHUB_PULL_REQUEST_URL: ${{ github.event.pull_request.html_url }}
+ GITHUB_REF: ${{ github.ref }}
+
+ # Clean up non-default docker images to save disk space.
+ # The default image (clang-20) is reused across multiple steps
+ # within the same job, so we keep it to avoid redundant pulls.
+ - name: clean up docker image
+ shell: bash
+ run: docker rmi "ghcr.io/ruby/ruby-ci-image:${INPUT_TAG}" || true
+ if: ${{ always() && inputs.tag != 'clang-20' }}
+ env:
+ INPUT_TAG: ${{ inputs.tag }}
diff --git a/.github/actions/compilers/entrypoint.sh b/.github/actions/compilers/entrypoint.sh
index 17f749d69e..b554151091 100755
--- a/.github/actions/compilers/entrypoint.sh
+++ b/.github/actions/compilers/entrypoint.sh
@@ -26,7 +26,7 @@ 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)))"
+export GNUMAKEFLAGS="-j$((1 + $(nproc)))"
case "x${INPUT_ENABLE_SHARED}" in
x | xno | xfalse )
@@ -47,6 +47,7 @@ grouped ${srcdir}/configure \
--enable-debug-env \
--disable-install-doc \
--with-ext=-test-/cxxanyargs,+ \
+ --without-git \
${enable_shared} \
${INPUT_APPEND_CONFIGURE} \
CFLAGS="${INPUT_CFLAGS}" \
@@ -70,25 +71,20 @@ if [[ -n "${INPUT_STATIC_EXTS}" ]]; then
echo "::endgroup::"
fi
-btests=''
-tests=''
-spec_opts=''
+if [ -n "$INPUT_TEST_ALL" ]; then
+ tests=" -- $INPUT_TEST_ALL"
+else
+ tests=" -- ruby -ext-"
+fi
pushd ${builddir}
grouped make showflags
grouped make all
-grouped make test BTESTS="${btests}"
-
-[[ -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" SPECOPTS="${spec_opts}"
+
+# Run only `make test` by default. Run other tests if specified.
+grouped make test
+if [[ -n "$INPUT_CHECK" ]]; then grouped make test-tool; fi
+if [[ -n "$INPUT_CHECK" || -n "$INPUT_TEST_ALL" ]]; then grouped make test-all TESTS="$tests"; fi
+if [[ -n "$INPUT_CHECK" || -n "$INPUT_TEST_SPEC" ]]; then grouped env CHECK_LEAKS=true make test-spec MSPECOPT="$INPUT_TEST_SPEC"; fi
diff --git a/.github/actions/launchable/setup/action.yml b/.github/actions/launchable/setup/action.yml
index 54f1abd97a..305878492c 100644
--- a/.github/actions/launchable/setup/action.yml
+++ b/.github/actions/launchable/setup/action.yml
@@ -55,6 +55,12 @@ inputs:
description: >-
Whether this workflow is executed on YJIT.
+ is-zjit:
+ required: false
+ default: 'false'
+ description: >-
+ Whether this workflow is executed on ZJIT.
+
outputs:
stdout_report_path:
value: ${{ steps.global.outputs.stdout_report_path }}
@@ -89,17 +95,41 @@ runs:
# 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
+ uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0
with:
python-version: "3.x"
- if: steps.enable-launchable.outputs.enable-launchable
+ if: >-
+ ${{ steps.enable-launchable.outputs.enable-launchable
+ && !endsWith(inputs.os, 'ppc64le') && !endsWith(inputs.os, 's390x') }}
- name: Set up Java
- uses: actions/setup-java@7a445ee88d4e23b52c33fdc7601e40278616c7f8 # v4.0.0
+ uses: actions/setup-java@c1e323688fd81a25caa38c78aa6df2d33d3e20d9 # v4.8.0
with:
distribution: 'temurin'
java-version: '17'
- if: steps.enable-launchable.outputs.enable-launchable
+ if: >-
+ ${{ steps.enable-launchable.outputs.enable-launchable
+ && !endsWith(inputs.os, 'ppc64le') && !endsWith(inputs.os, 's390x') }}
+
+ - name: Set up Java ppc64le
+ uses: actions/setup-java@c1e323688fd81a25caa38c78aa6df2d33d3e20d9 # v4.8.0
+ with:
+ distribution: 'semeru'
+ architecture: 'ppc64le'
+ java-version: '17'
+ if: >-
+ ${{ steps.enable-launchable.outputs.enable-launchable
+ && endsWith(inputs.os, 'ppc64le') }}
+
+ - name: Set up Java s390x
+ uses: actions/setup-java@c1e323688fd81a25caa38c78aa6df2d33d3e20d9 # v4.8.0
+ with:
+ distribution: 'semeru'
+ architecture: 's390x'
+ java-version: '17'
+ if: >-
+ ${{ steps.enable-launchable.outputs.enable-launchable
+ && endsWith(inputs.os, 's390x') }}
- name: Set global vars
id: global
@@ -120,20 +150,26 @@ runs:
- name: Set environment variables for Launchable
shell: bash
- run: |
+ run: | # zizmor: ignore[github-env]
: # 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
+ echo "GITHUB_PULL_REQUEST_URL=${INPUT_PR_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=${{ github.event.repository.name }}" >> $GITHUB_ENV
+ echo "LAUNCHABLE_ORGANIZATION=${INPUT_REPOSITORY_OWNER}" >> $GITHUB_ENV
+ echo "LAUNCHABLE_WORKSPACE=${INPUT_REPOSITORY_NAME}" >> $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
+ echo "GITHUB_PR_HEAD_SHA=${INPUT_PR_HEAD_SHA}" >> $GITHUB_ENV
+ echo "LAUNCHABLE_TOKEN=${INPUT_LAUNCHABLE_TOKEN}" >> $GITHUB_ENV
: # To prevent a slowdown in CI, disable request retries when the Launchable server is unstable.
echo "LAUNCHABLE_SKIP_TIMEOUT_RETRY=1" >> $GITHUB_ENV
echo "LAUNCHABLE_COMMIT_TIMEOUT=1" >> $GITHUB_ENV
+ env:
+ INPUT_PR_HTML_URL: ${{ github.event.pull_request.html_url }}
+ INPUT_REPOSITORY_OWNER: ${{ github.repository_owner }}
+ INPUT_REPOSITORY_NAME: ${{ github.event.repository.name }}
+ INPUT_PR_HEAD_SHA: ${{ github.event.pull_request.head.sha || github.sha }}
+ INPUT_LAUNCHABLE_TOKEN: ${{ inputs.launchable-token }}
if: steps.enable-launchable.outputs.enable-launchable
- name: Set up path
@@ -141,33 +177,44 @@ runs:
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')
+ run: echo "$(python -msite --user-base)/bin" >> $GITHUB_PATH # zizmor: ignore[github-env]
+ if: >-
+ ${{
+ steps.enable-launchable.outputs.enable-launchable
+ && (startsWith(inputs.os, 'macos')
+ || endsWith(inputs.os, 'ppc64le')
+ || endsWith(inputs.os, 's390x'))
+ }}
- name: Set up Launchable
id: setup-launchable
shell: bash
working-directory: ${{ inputs.srcdir }}
- run: |
+ run: | # zizmor: ignore[github-env]
set -x
pip install --user launchable
: # The build name cannot include a slash, so we replace the string here.
- github_ref="${{ github.ref }}"
+ github_ref="${INPUT_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.
build_name="${github_ref}_${GITHUB_PR_HEAD_SHA}"
- test_opts="${{ inputs.test-opts }}"
+ test_opts="${INPUT_TEST_OPTS}"
test_opts="${test_opts// /}"
test_opts="${test_opts//=/:}"
test_all_test_suite='test-all'
btest_test_suite='btest'
test_spec_test_suite='test-spec'
- if [ "${{ inputs.is-yjit }}" = "true" ]; then
+ if [ "${INPUT_IS_YJIT}" = "true" ]; then
test_all_test_suite="yjit-${test_all_test_suite}"
btest_test_suite="yjit-${btest_test_suite}"
test_spec_test_suite="yjit-${test_spec_test_suite}"
fi
+ if [ "${INPUT_IS_ZJIT}" = "true" ]; then
+ test_all_test_suite="zjit-${test_all_test_suite}"
+ btest_test_suite="zjit-${btest_test_suite}"
+ test_spec_test_suite="zjit-${test_spec_test_suite}"
+ fi
# launchable_setup target var -- refers ${target} prefixed variables
launchable_setup() {
local target=$1 session
@@ -176,10 +223,10 @@ runs:
session=$(launchable record session \
--build "${build_name}" \
--observation \
- --flavor os="${{ inputs.os }}" \
- --flavor test_task="${{ inputs.test-task }}" \
+ --flavor os="${INPUT_OS}" \
+ --flavor test_task="${INPUT_TEST_TASK}" \
--flavor test_opts="${test_opts}" \
- --flavor workflow="${{ github.workflow }}" \
+ --flavor workflow="${INPUT_WORKFLOW}" \
--test-suite ${suite} \
)
echo "${target}_session=${session}" >> $GITHUB_OUTPUT
@@ -200,6 +247,13 @@ runs:
echo launchable_setup_dir=$(pwd) >> $GITHUB_OUTPUT
if: steps.enable-launchable.outputs.enable-launchable
env:
+ INPUT_GITHUB_REF: ${{ github.ref }}
+ INPUT_TEST_OPTS: ${{ inputs.test-opts }}
+ INPUT_IS_YJIT: ${{ inputs.is-yjit }}
+ INPUT_IS_ZJIT: ${{ inputs.is-zjit }}
+ INPUT_OS: ${{ inputs.os }}
+ INPUT_TEST_TASK: ${{ inputs.test-task }}
+ INPUT_WORKFLOW: ${{ github.workflow }}
test_all_enabled: ${{ steps.global.outputs.test_all_enabled }}
btest_enabled: ${{ steps.global.outputs.btest_enabled }}
test_spec_enabled: ${{ steps.global.outputs.test_spec_enabled }}
@@ -216,7 +270,7 @@ runs:
test_spec_report_dir: ${{ steps.global.outputs.test_spec_report_dir }}
- name: Clean up test results in Launchable
- uses: gacts/run-and-post-run@674528335da98a7afc80915ff2b4b860a0b3553a # v1.4.0
+ uses: gacts/run-and-post-run@81b6ce503cde93862cec047c54652e45c5dca991 # v1.4.3
with:
shell: bash
working-directory: ${{ inputs.builddir }}
@@ -233,7 +287,7 @@ runs:
test_spec_report_dir: ${{ steps.global.outputs.test_spec_report_dir }}
- name: Record test results in Launchable
- uses: gacts/run-and-post-run@674528335da98a7afc80915ff2b4b860a0b3553a # v1.4.0
+ uses: gacts/run-and-post-run@81b6ce503cde93862cec047c54652e45c5dca991 # v1.4.3
with:
shell: bash
working-directory: ${{ inputs.builddir }}
diff --git a/.github/actions/make-snapshot/action.yml b/.github/actions/make-snapshot/action.yml
new file mode 100644
index 0000000000..4552f0e067
--- /dev/null
+++ b/.github/actions/make-snapshot/action.yml
@@ -0,0 +1,77 @@
+name: 'make-snapshot'
+description: 'Make snapshot tarballs'
+inputs:
+ archname:
+ description: 'archname passed to tool/make-snapshot (e.g. snapshot-master)'
+ required: true
+ version:
+ description: 'Target Version'
+ required: false
+ shallow-since:
+ description: 'git fetch --shallow-since'
+ required: true
+ default: '2018-12-25 00:00:00'
+ fetch-branch:
+ description: 'fetch branch'
+ required: false
+ srcdir:
+ description: 'srcdir for tool/make-snapshot. Empty = clone ruby/ruby into ./ruby.'
+ required: false
+ default: ''
+ upload-artifact:
+ description: 'Upload Packages and Info as workflow artifacts. Pass "false" when callers run in a matrix that would collide on artifact names.'
+ required: false
+ default: 'true'
+
+runs:
+ using: "composite"
+ steps:
+ - name: Install libraries
+ run: |
+ set -x
+ sudo apt-get update -q || :
+ sudo apt-get install --no-install-recommends -q -y build-essential git bison autoconf ruby p7zip-full curl
+ shell: bash
+ - name: Checkout ruby/ruby for tool/make-snapshot
+ if: inputs.srcdir == ''
+ run: git clone --single-branch --depth=1 https://github.com/ruby/ruby ruby
+ shell: bash
+ - name: Fetch branches and notes (clone mode)
+ if: inputs.srcdir == ''
+ env:
+ SHALLOW_SINCE: ${{ inputs.shallow-since }}
+ FETCH_BRANCH: ${{ inputs.fetch-branch }}
+ run: |
+ set -x
+ cd ruby
+ git fetch --shallow-since="$SHALLOW_SINCE"
+ [ -n "$FETCH_BRANCH" ] && git fetch origin "+$FETCH_BRANCH:$FETCH_BRANCH"
+ git fetch origin '+refs/notes/commits:refs/notes/commits'
+ git fetch origin '+refs/notes/log-fix:refs/notes/log-fix'
+ shell: bash
+ - name: Fetch notes (local srcdir mode)
+ if: inputs.srcdir != ''
+ working-directory: ${{ inputs.srcdir }}
+ run: |
+ git fetch origin '+refs/notes/commits:refs/notes/commits' || :
+ git fetch origin '+refs/notes/log-fix:refs/notes/log-fix' || :
+ shell: bash
+ - name: Make snapshot
+ env:
+ ARCHNAME: ${{ inputs.archname }}
+ SRCDIR: ${{ inputs.srcdir }}
+ VERSION: ${{ inputs.version }}
+ run: |
+ [ -z "$SRCDIR" ] && SRCDIR=ruby
+ ruby "$SRCDIR/tool/make-snapshot" "-archname=$ARCHNAME" -srcdir="$SRCDIR" -packages=gzip,xz,zip pkg $VERSION
+ shell: bash
+ - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
+ with:
+ name: Packages
+ path: pkg
+ if: ${{ inputs.upload-artifact == 'true' }}
+ - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
+ with:
+ name: Info
+ path: pkg/info
+ if: ${{ inputs.upload-artifact == 'true' }}
diff --git a/.github/actions/setup/baseruby/action.yml b/.github/actions/setup/baseruby/action.yml
new file mode 100644
index 0000000000..76fe068897
--- /dev/null
+++ b/.github/actions/setup/baseruby/action.yml
@@ -0,0 +1,73 @@
+name: Setup directories etc.
+description: >-
+ Build baseruby for cross-compiling
+
+inputs:
+ srcdir:
+ required: true
+ default: ${{ github.workspace }}
+ description: >-
+ Directory of source codes.
+
+ builddir:
+ required: false
+ default: ${{ github.workspace }}/baseruby
+ description: >-
+ Where baseruby will be built.
+
+ installdir:
+ required: false
+ default: install
+ description: >-
+ The path where the baseruby will be installed to.
+ This is relative from the workspace.
+
+outputs:
+ ruby:
+ value: ${{ steps.build.outputs.installdir }}/bin/ruby
+ description: >-
+ The path of the executable baseruby.
+ dump_ast:
+ value: ${{ steps.build.outputs.installdir }}/bin/dump_ast
+ description: >-
+ The path of the executable dump_ast.
+
+runs:
+ using: composite
+
+ steps:
+ - name: Build baseruby
+ shell: bash
+ id: build
+ run: |
+ case "$installdir" in /*) ;; *) installdir="$PWD/$installdir";; esac
+ mkdir "$builddir"
+ ln -sr "$srcdir" "$builddir/.src"
+ pushd "$builddir"
+ .src/configure "--prefix=${installdir}" --disable-install-doc
+ CONFIGURE_ARGS=--with-out-ext=-test- make install
+ install dump_ast "${installdir}/bin"
+ {
+ echo "${installdir}/bin/dump_ast"
+ echo "${installdir}/.installed.list"
+ echo "${installdir}/"
+ } >> .installed.list
+ cp .installed.list "${installdir}/"
+ make distclean
+ rm .src
+ popd
+ rmdir "$builddir"
+ {
+ echo "installdir=${installdir}"
+ } | tee -a "$GITHUB_OUTPUT"
+ env:
+ srcdir: ${{ inputs.srcdir }}
+ builddir: ${{ inputs.builddir }}
+ installdir: ${{ inputs.installdir }}
+
+ - name: clean
+ uses: gacts/run-and-post-run@598d7a875d5620e0457490555b5e18e46082aa47 # v1.4.4
+ with:
+ working-directory: ${{ inputs.srcdir }}
+ post: |
+ ruby tool/rbuninstall.rb "${{ steps.build.outputs.installdir }}/.installed.list" > /dev/null
diff --git a/.github/actions/setup/directories/action.yml b/.github/actions/setup/directories/action.yml
index 728e082189..15dc097b6e 100644
--- a/.github/actions/setup/directories/action.yml
+++ b/.github/actions/setup/directories/action.yml
@@ -19,6 +19,13 @@ inputs:
Where binaries and other generated contents go. This will be
created if absent.
+ make-command:
+ required: false
+ type: string
+ default: 'make'
+ description: >-
+ The command of `make`.
+
makeup:
required: false
type: boolean
@@ -67,8 +74,11 @@ runs:
# their bash manually installed.
- shell: bash
run: |
- mkdir -p ${{ inputs.srcdir }}
- mkdir -p ${{ inputs.builddir }}
+ mkdir -p "${INPUT_SRCDIR}"
+ mkdir -p "${INPUT_BUILDDIR}"
+ env:
+ INPUT_SRCDIR: ${{ inputs.srcdir }}
+ INPUT_BUILDDIR: ${{ inputs.builddir }}
# Did you know that actions/checkout works without git(1)? We are
# checking that here.
@@ -88,12 +98,13 @@ runs:
git config --global init.defaultBranch garbage
- if: inputs.checkout
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
+ uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
path: ${{ inputs.srcdir }}
fetch-depth: ${{ inputs.fetch-depth }}
+ persist-credentials: false
- - uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4
+ - uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
with:
path: ${{ inputs.srcdir }}/.downloaded-cache
key: ${{ runner.os }}-${{ runner.arch }}-downloaded-cache
@@ -106,16 +117,16 @@ runs:
# This is for MinGW.
- if: runner.os == 'Windows'
shell: bash
- run: echo "GNUMAKEFLAGS=-j$((2 * NUMBER_OF_PROCESSORS))" >> $GITHUB_ENV
+ run: echo "GNUMAKEFLAGS=-j$((2 * NUMBER_OF_PROCESSORS))" >> $GITHUB_ENV # zizmor: ignore[github-env]
- if: runner.os == 'Linux'
shell: bash
- run: echo "GNUMAKEFLAGS=-sj$((1 + $(nproc --all)))" >> "$GITHUB_ENV"
+ run: echo "GNUMAKEFLAGS=-sj$((1 + $(nproc)))" >> "$GITHUB_ENV" # zizmor: ignore[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"
+ run: echo "MAKEFLAGS=-j$((1 + $(sysctl -n hw.activecpu)))" >> "$GITHUB_ENV" # zizmor: ignore[github-env]
- if: inputs.makeup
shell: bash
@@ -134,6 +145,7 @@ runs:
run: |
rm -f config.status .rbconfig.time \
Makefile GNUmakefile uncommon.mk enc.mk noarch-fake.rb
+ rm -f prism/.time prism/util/.time
- if: steps.which.outputs.sudo
shell: bash
@@ -163,19 +175,25 @@ runs:
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
+ echo clean="cd ${INPUT_BUILDDIR} && rm $*" >> $GITHUB_OUTPUT
+ env:
+ INPUT_BUILDDIR: ${{ inputs.builddir }}
- 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
+ echo distclean="cd ${INPUT_BUILDDIR} && ${INPUT_MAKE_COMMAND} distclean" >> $GITHUB_OUTPUT
+ echo remained-files="find ${INPUT_BUILDDIR} -ls" >> $GITHUB_OUTPUT
+ [ "${INPUT_BUILDDIR}" = "${INPUT_SRCDIR}" ] ||
+ echo final="rmdir ${INPUT_BUILDDIR}" >> $GITHUB_OUTPUT
+ env:
+ INPUT_BUILDDIR: ${{ inputs.builddir }}
+ INPUT_SRCDIR: ${{ inputs.srcdir }}
+ INPUT_MAKE_COMMAND: ${{ inputs.make-command }}
- name: clean
- uses: gacts/run-and-post-run@d803f6920adc9a47eeac4cb6c93dbc2e2890c684 # v1.4.2
+ uses: gacts/run-and-post-run@598d7a875d5620e0457490555b5e18e46082aa47 # v1.4.4
with:
working-directory:
post: |
diff --git a/.github/actions/setup/macos/action.yml b/.github/actions/setup/macos/action.yml
index d0072ff828..9cd37a9b12 100644
--- a/.github/actions/setup/macos/action.yml
+++ b/.github/actions/setup/macos/action.yml
@@ -17,7 +17,7 @@ runs:
- name: Set ENV
shell: bash
- run: |
+ run: | # zizmor: ignore[github-env]
dir_config() {
local args=() lib var="$1"; shift
for lib in "$@"; do
diff --git a/.github/actions/setup/ubuntu/action.yml b/.github/actions/setup/ubuntu/action.yml
index a9e5b41951..5209ccc03f 100644
--- a/.github/actions/setup/ubuntu/action.yml
+++ b/.github/actions/setup/ubuntu/action.yml
@@ -24,18 +24,38 @@ runs:
using: composite
steps:
+ - id: uname
+ name: uname
+ shell: bash
+ env:
+ arch: ${{ inputs.arch }}
+ run: |
+ setarch="${arch:+setarch $arch --}"
+ # normalize `uname`
+ if uname=$(${setarch} uname -m 2> /dev/null); then
+ # `setarch` works, `$arch` is a valid architecture name.
+ echo "setarch=${setarch}" >> "$GITHUB_OUTPUT"
+ else
+ # if `setarch` failed, take the given `arch` as-is.
+ uname="${arch}"
+ setarch=""
+ fi
+ echo "uname=$uname" >> "$GITHUB_OUTPUT"
+ echo "dpkg=${uname/686/386}" >> "$GITHUB_OUTPUT"
+
- name: set SETARCH
shell: bash
- run: echo "SETARCH=${setarch}" >> "$GITHUB_ENV"
+ run: echo "SETARCH=${setarch}" >> "$GITHUB_ENV" # zizmor: ignore[github-env]
env:
- setarch: ${{ inputs.arch && format('setarch {0} --', inputs.arch) }}
+ setarch: ${{ steps.uname.outputs.setarch }} # validated
- - id: uname
- name: uname
+ - name: dpkg setup
shell: bash
- run: |
- echo uname=`${SETARCH} uname -m` >> "$GITHUB_OUTPUT"
- echo dpkg=`${SETARCH} uname -m | sed s/686/386/` >> "$GITHUB_OUTPUT"
+ run: sudo dpkg --add-architecture "${dpkg}"
+ # `dpkg` is valid, also `uname`.
+ if: ${{ inputs.arch }}
+ env:
+ dpkg: ${{ steps.uname.outputs.dpkg }}
- name: apt-get
shell: bash
@@ -43,7 +63,6 @@ runs:
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/:/-} \
diff --git a/.github/actions/slack/action.yml b/.github/actions/slack/action.yml
index 98171efc5e..6f89bef11a 100644
--- a/.github/actions/slack/action.yml
+++ b/.github/actions/slack/action.yml
@@ -18,13 +18,24 @@ inputs:
Human-readable description of the run, something like "DEBUG=1".
This need not be unique among runs.
+ event_name:
+ required: false
+ default: 'push'
+ description: >-
+ Target event to trigger notification. Notify only push by default.
+
+ extra_channel_id:
+ required: false
+ description: >-
+ Slack channel ID to notify besides #alerts and #alerts-emoji.
+
outputs: {} # Nothing?
runs:
using: composite
steps:
- - uses: ruby/action-slack@54175162371f1f7c8eb94d7c8644ee2479fcd375 # v3.2.2
+ - uses: ruby/action-slack@d260b61aa817726d5bedd22dd6cc305787fa4cdd # v4.0.0
with:
payload: |
{
@@ -33,7 +44,8 @@ runs:
"url": "https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}",
"commit": "${{ github.sha }}",
"branch": "${{ github.ref_name }}"
+ ${{ inputs.extra_channel_id && format(', "extra_channel_id": "{0}"', inputs.extra_channel_id) }}
}
env:
SLACK_WEBHOOK_URL: ${{ inputs.SLACK_WEBHOOK_URL }}
- if: ${{github.event_name == 'push' && startsWith(github.repository, 'ruby/')}}
+ if: ${{ github.event_name == inputs.event_name && startsWith(github.repository, 'ruby/') }}
diff --git a/.github/auto_request_review.yml b/.github/auto_request_review.yml
index 264e6ef177..9e20cb7459 100644
--- a/.github/auto_request_review.yml
+++ b/.github/auto_request_review.yml
@@ -2,19 +2,20 @@ files:
'yjit*': [team:jit]
'yjit/**/*': [team:jit]
'yjit/src/cruby_bindings.inc.rs': []
- 'doc/yjit/*': [team:jit]
'bootstraptest/test_yjit*': [team:jit]
'test/ruby/test_yjit*': [team:jit]
'zjit*': [team:jit]
'zjit/**/*': [team:jit]
'zjit/src/cruby_bindings.inc.rs': []
- 'doc/zjit*': [team:jit]
'test/ruby/test_zjit*': [team:jit]
- 'test/.excludes-zjit/*': [team:jit]
'defs/jit.mk': [team:jit]
+ 'tool/zjit_bisect.rb': [team:jit]
+ 'doc/jit/*': [team:jit]
+ # Skip files updated by dependabot. It's noisy in notifications, and they're auto-merged anyway.
+ 'yjit/Cargo.lock': []
+ 'zjit/Cargo.lock': []
+ '.github/workflows/yjit-*.yml': []
+ '.github/workflows/zjit-*.yml': []
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
- # files are modified as well. To be enabled after fixing the behavior.
- #last_files_match_only: true
+ 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..f5d33545c1
--- /dev/null
+++ b/.github/codeql/codeql-config.yml
@@ -0,0 +1,22 @@
+paths-ignore:
+ - benchmark
+ - sample
+ - spec/ruby/command_line/fixtures
+ - spec/ruby/core/enumerable/shared/inject.rb
+ - spec/ruby/core/exception/fixtures
+ - spec/ruby/core/proc/parameters_spec.rb
+ - spec/ruby/core/proc/ruby2_keywords_spec.rb
+ - spec/ruby/core/range/reverse_each_spec.rb
+ - spec/ruby/language/fixtures
+ - spec/ruby/language/lambda_spec.rb
+ - spec/ruby/language/method_spec.rb
+ - spec/ruby/language/string_spec.rb
+ - test/error_highlight/test_error_highlight.rb
+ - test/prism/result/named_capture_test.rb
+ - test/ruby/test_call.rb
+ - test/ruby/test_signal.rb
+ - test/ruby/test_super.rb
+ - test/ruby/test_syntax.rb
+ - test/ruby/test_unicode_escape.rb
+ - test/rubygems/specifications/foo-0.0.1-x86-mswin32.gemspec
+ - trace_point.rb
diff --git a/.github/dependabot.yml b/.github/dependabot.yml
index 2c2982d1d4..57da742e5c 100644
--- a/.github/dependabot.yml
+++ b/.github/dependabot.yml
@@ -1,21 +1,28 @@
version: 2
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'
+ directories:
+ - '/'
+ - '/.github/actions/slack'
+ - '/.github/actions/setup/directories'
schedule:
interval: 'daily'
+ groups:
+ github-actions:
+ patterns:
+ - "*"
- package-ecosystem: 'cargo'
- directory: '/yjit'
+ directories:
+ - '/yjit'
+ - '/zjit'
+ exclude-paths:
+ - 'gc/mmtk/**'
schedule:
- interval: 'daily'
+ interval: 'monthly'
+ groups:
+ jit:
+ patterns:
+ - "*"
- package-ecosystem: 'vcpkg'
directory: '/'
schedule:
diff --git a/.github/labeler.yml b/.github/labeler.yml
index e81aed8e98..f39fcec386 100644
--- a/.github/labeler.yml
+++ b/.github/labeler.yml
@@ -4,3 +4,4 @@ Documentation:
Backport:
- base-branch: 'ruby_3_\d'
+- base-branch: 'ruby_4_\d'
diff --git a/.github/workflows/annocheck.yml b/.github/workflows/annocheck.yml
index 304d216d68..5991165d43 100644
--- a/.github/workflows/annocheck.yml
+++ b/.github/workflows/annocheck.yml
@@ -41,7 +41,7 @@ jobs:
|| contains(github.event.head_commit.message, '[DOC]')
|| contains(github.event.pull_request.title, '[DOC]')
|| contains(github.event.pull_request.labels.*.name, 'Documentation')
- || (github.event_name == 'push' && github.event.pull_request.user.login == 'dependabot[bot]')
+ || (github.event.pull_request.user.login == 'dependabot[bot]')
)}}
env:
@@ -61,10 +61,11 @@ jobs:
- run: id
working-directory:
- - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
+ - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
sparse-checkout-cone-mode: false
sparse-checkout: /.github
+ persist-credentials: false
- uses: ./.github/actions/setup/directories
with:
@@ -72,7 +73,7 @@ jobs:
builddir: build
makeup: true
- - uses: ruby/setup-ruby@a9bfc2ecf3dd40734a9418f89a7e9d484c32b990 # v1.248.0
+ - uses: ruby/setup-ruby@afeafc3d1ab54a631816aba4c914a0081c12ff2f # v1.310.0
with:
ruby-version: '3.1'
bundler: none
diff --git a/.github/workflows/auto_request_review.yml b/.github/workflows/auto_request_review.yml
index 207315a084..80f2517eb5 100644
--- a/.github/workflows/auto_request_review.yml
+++ b/.github/workflows/auto_request_review.yml
@@ -14,7 +14,7 @@ jobs:
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
+ uses: necojackarc/auto-request-review@035f049cb68460341ab744f19aa9f31aae685e36 # master
with:
# scope: public_repo
token: ${{ secrets.MATZBOT_AUTO_REQUEST_REVIEW_TOKEN }}
diff --git a/.github/workflows/auto_review_pr.yml b/.github/workflows/auto_review_pr.yml
new file mode 100644
index 0000000000..bb84a51573
--- /dev/null
+++ b/.github/workflows/auto_review_pr.yml
@@ -0,0 +1,41 @@
+name: Auto Review PR
+on:
+ pull_request_target:
+ types: [opened, ready_for_review, reopened]
+ branches: [master]
+ workflow_dispatch:
+ inputs:
+ pr_number:
+ description: 'PR number to review'
+ required: true
+ type: number
+
+permissions:
+ contents: read
+
+jobs:
+ auto-review-pr:
+ name: Auto Review PR
+ runs-on: ubuntu-latest
+ if: ${{ github.repository == 'ruby/ruby' && (github.base_ref == 'master' || github.event_name == 'workflow_dispatch') }}
+
+ permissions:
+ pull-requests: write
+ contents: read
+
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
+ with:
+ persist-credentials: false
+
+ - uses: ruby/setup-ruby@afeafc3d1ab54a631816aba4c914a0081c12ff2f # v1.310.0
+ with:
+ ruby-version: '3.4'
+ bundler: none
+
+ - name: Auto Review PR
+ run: ruby tool/auto_review_pr.rb "$GITHUB_PR_NUMBER"
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ GITHUB_PR_NUMBER: ${{ github.event.pull_request.number || github.event.inputs.pr_number }}
diff --git a/.github/workflows/baseruby.yml b/.github/workflows/baseruby.yml
index ffaec18b83..9e7720f659 100644
--- a/.github/workflows/baseruby.yml
+++ b/.github/workflows/baseruby.yml
@@ -37,7 +37,7 @@ jobs:
|| contains(github.event.head_commit.message, '[DOC]')
|| contains(github.event.pull_request.title, '[DOC]')
|| contains(github.event.pull_request.labels.*.name, 'Documentation')
- || (github.event_name == 'push' && github.event.pull_request.user.login == 'dependabot[bot]')
+ || (github.event.pull_request.user.login == 'dependabot[bot]')
)}}
strategy:
@@ -48,12 +48,14 @@ jobs:
- ruby-3.3
steps:
- - uses: ruby/setup-ruby@a9bfc2ecf3dd40734a9418f89a7e9d484c32b990 # v1.248.0
+ - uses: ruby/setup-ruby@afeafc3d1ab54a631816aba4c914a0081c12ff2f # v1.310.0
with:
ruby-version: ${{ matrix.ruby }}
bundler: none
- - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
+ - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
+ with:
+ persist-credentials: false
- uses: ./.github/actions/setup/ubuntu
diff --git a/.github/workflows/bundled_gems.yml b/.github/workflows/bundled_gems.yml
index 27ad55307b..d329ee9b4b 100644
--- a/.github/workflows/bundled_gems.yml
+++ b/.github/workflows/bundled_gems.yml
@@ -1,5 +1,8 @@
name: bundled_gems
+env:
+ UPDATE_ENABLED: true
+
on:
push:
branches: ['master']
@@ -31,10 +34,14 @@ jobs:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
+ - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
token: ${{ (github.repository == 'ruby/ruby' && !startsWith(github.event_name, 'pull')) && secrets.MATZBOT_AUTO_UPDATE_TOKEN || secrets.GITHUB_TOKEN }}
+ - uses: ruby/setup-ruby@afeafc3d1ab54a631816aba4c914a0081c12ff2f # v1.310.0
+ with:
+ ruby-version: 4.0
+
- uses: ./.github/actions/setup/directories
with:
# Skip overwriting MATZBOT_AUTO_UPDATE_TOKEN
@@ -49,24 +56,20 @@ jobs:
mkdir -p .downloaded-cache
for data in bundled_gems.json default_gems.json; do
ln -s .downloaded-cache/$data .
- curl -O -R -z ./$data https://stdgems.org/$data
+ curl --retry 5 --retry-connrefused --retry-delay 2 --retry-max-time 60 -O -R -z ./$data https://stdgems.org/$data
done
- 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
+ if: ${{ env.UPDATE_ENABLED == 'true' }}
- name: Maintain updated gems list in NEWS
run: |
ruby tool/update-NEWS-gemlist.rb bundled
+ ruby tool/update-NEWS-github-release.rb --update
+ if: ${{ env.UPDATE_ENABLED == 'true' }}
- name: Check diffs
id: diff
@@ -77,11 +80,71 @@ jobs:
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
+ - name: Commit
+ id: commit
+ run: |
+ git pull --ff-only origin ${GITHUB_REF#refs/heads/}
+ message="Update bundled gems list"
+ if [ -z "${gems}" ]; then
+ git commit --message="[DOC] ${message} at ${GITHUB_SHA:0:30}"
+ else
+ git commit --message="${message} as of ${TODAY}"
+ fi
+ 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: ${{ steps.diff.outputs.update }}
+
+ - name: Development revision of bundled gems
+ run: |
+ #!ruby
+ file = "gems/bundled_gems"
+
+ SECONDS_IN_DAY = 86400
+ today = Time.new("#{ENV['TODAY']}Z")
+ if !(december = today.month == 12)
+ days = 30
+ elsif (days = 26 - today.day).positive?
+ days += 4
+ else
+ puts "::info:: just after released"
+ exit
+ end
+
+ since = "#{today.year-1}-12-26"
+ ref = ENV['GITHUB_REF']
+ puts "::group::\e[94mfetching \e[1m#{file}\e[22m since \e[1m#{since}\e[22m from \e[1m#{ref}\e[m"
+ system(*%W[git fetch --shallow-since=#{since} --no-tags origin #{ref}], exception: true)
+ puts "::endgroup::"
+
+ puts "\e[94mchecking development version bundled gems older than \e[1m#{days}\e[22m days\e[m"
+ limit = today.to_i - days * SECONDS_IN_DAY
+ old = 0
+ IO.popen(%W"git blame --line-porcelain -- #{file}") do |blame|
+ while head = blame.gets("\n\t") and s = blame.gets
+ next unless (gem = s.split(/\s+|#.*/)).size > 3
+ time = head[/^committer-time \K\d+/].to_i
+ next if (d = limit - time) <= 0
+ d /= SECONDS_IN_DAY
+ line = head[/\A\h+ \d+ \K\d+/].to_i
+ level = if d < days; 'warning'; else old += 1; 'error'; end
+ d += days
+ puts "::#{level} file=#{file},line=#{line},title=Older than #{d} days::#{gem[0]} #{gem[3]}"
+ end
+ end
+ abort "::error title=Too long-standing gems::The release comes soon." if december and old.nonzero?
+ shell: ruby {0}
+ env:
+ file: ${{ steps.logs.outputs.file }}
+ days: ${{ steps.logs.outputs.days }}
+
- name: Install libraries
uses: ./.github/actions/setup/ubuntu
if: ${{ steps.diff.outputs.gems }}
@@ -107,27 +170,14 @@ jobs:
TEST_BUNDLED_GEMS_ALLOW_FAILURES: ''
if: ${{ steps.diff.outputs.gems }}
- - name: Commit
+ - name: Push
run: |
- git pull --ff-only origin ${GITHUB_REF#refs/heads/}
- message="Update bundled gems list"
- if [ -z "${gems}" ]; then
- git commit --message="[DOC] ${message} at ${GITHUB_SHA:0:30}"
- else
- git commit --message="${message} as of ${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
+ steps.commit.outcome == 'success'
}}
- uses: ./.github/actions/slack
diff --git a/.github/workflows/check_dependencies.yml b/.github/workflows/check_dependencies.yml
index db93e90efb..a120dde7e5 100644
--- a/.github/workflows/check_dependencies.yml
+++ b/.github/workflows/check_dependencies.yml
@@ -30,7 +30,9 @@ jobs:
runs-on: ${{ matrix.os }}
steps:
- - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
+ - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
+ with:
+ persist-credentials: false
- uses: ./.github/actions/setup/ubuntu
if: ${{ contains(matrix.os, 'ubuntu') }}
@@ -40,7 +42,7 @@ jobs:
- uses: ./.github/actions/setup/directories
- - uses: ruby/setup-ruby@a9bfc2ecf3dd40734a9418f89a7e9d484c32b990 # v1.248.0
+ - uses: ruby/setup-ruby@afeafc3d1ab54a631816aba4c914a0081c12ff2f # v1.310.0
with:
ruby-version: '3.1'
bundler: none
@@ -50,7 +52,7 @@ jobs:
- run: make fix-depends
- - run: git diff --no-ext-diff --ignore-submodules --exit-code
+ - run: git diff --color --no-ext-diff --ignore-submodules --exit-code
- uses: ./.github/actions/slack
with:
diff --git a/.github/workflows/check_misc.yml b/.github/workflows/check_misc.yml
index 54f8df66a2..cb1642b9e2 100644
--- a/.github/workflows/check_misc.yml
+++ b/.github/workflows/check_misc.yml
@@ -18,9 +18,14 @@ jobs:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
+ - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
token: ${{ (github.repository == 'ruby/ruby' && !startsWith(github.event_name, 'pull')) && secrets.MATZBOT_AUTO_UPDATE_TOKEN || secrets.GITHUB_TOKEN }}
+ persist-credentials: false
+
+ - uses: ruby/setup-ruby@afeafc3d1ab54a631816aba4c914a0081c12ff2f # v1.310.0
+ with:
+ ruby-version: head
- uses: ./.github/actions/setup/directories
with:
@@ -28,23 +33,34 @@ jobs:
# Skip overwriting MATZBOT_AUTO_UPDATE_TOKEN
checkout: '' # false (ref: https://github.com/actions/runner/issues/2238)
- # Run this step first to make sure auto-style commits are pushed
- - name: ${{ github.ref == 'refs/heads/master' && 'Auto-correct' || 'Check for' }} code styles
+ - name: Re-generate Makefiles
+ run: |
+ # config.status needs to run as a shell script
+ { echo ':&&exit'; cat tool/prereq.status; } > config.status
+ : # same as actions/setup/directories/action.yml
+ for mk in Makefile GNUmakefile; do
+ sed -f tool/prereq.status template/$mk.in > $mk
+ done
+
+ - name: Check for code styles
run: |
set -x
- ruby tool/auto-style.rb "$GITHUB_OLD_SHA" "$GITHUB_NEW_SHA" "$PUSH_REF"
+ ruby tool/auto-style.rb "$GITHUB_OLD_SHA" "$GITHUB_NEW_SHA"
env:
- EMAIL: svn-admin@ruby-lang.org
- GIT_AUTHOR_NAME: git
- GIT_COMMITTER_NAME: git
GITHUB_OLD_SHA: ${{ github.event.pull_request.base.sha }}
GITHUB_NEW_SHA: ${{ github.event.pull_request.merge_commit_sha }}
- PUSH_REF: ${{ github.ref == 'refs/heads/master' && github.ref || '' }}
+ # Skip 'push' events because post_push.yml fixes them on push
if: ${{ github.repository == 'ruby/ruby' && startsWith(github.event_name, 'pull') }}
- - name: Check if C-sources are US-ASCII
+ - name: Check if date in man pages is up-to-date
run: |
- grep -r -n --include='*.[chyS]' --include='*.asm' $'[^\t-~]' -- . && exit 1 || :
+ git fetch origin --depth=1 "${GITHUB_OLD_SHA}"
+ git diff --exit-code --name-only "${GITHUB_OLD_SHA}" HEAD -- man ||
+ make V=1 GIT=git BASERUBY=ruby update-man-date
+ git diff --color --no-ext-diff --ignore-submodules --exit-code -- man
+ env:
+ GITHUB_OLD_SHA: ${{ github.event.pull_request.base.sha }}
+ if: ${{ startsWith(github.event_name, 'pull') }}
- name: Check for bash specific substitution in configure.ac
run: |
@@ -61,29 +77,38 @@ jobs:
exit $fail
working-directory: include
+ - id: now
+ run: |
+ date +"mon=%-m"%n"day=%-d" >> $GITHUB_OUTPUT
+ env:
+ TZ: Asia/Tokyo
+
+ - id: deprecation
+ run: |
+ eval $(sed -n 's/^#define RUBY_API_VERSION_\(MAJOR\|MINOR\) /\1=/p' include/ruby/version.h)
+ if git --no-pager grep --color -o 'rb_warn_deprecated_to_remove_at('$MAJOR'\.'$MINOR',.*' -- '*.c' >&2; then
+ false
+ else
+ true
+ fi
+ continue-on-error: ${{ steps.now.outputs.mon < 12 }}
+
- name: Check if to generate documents
id: rdoc
run: |
- ref=$(sed 's/#.*//;/^rdoc /!d' gems/bundled_gems | awk '{print $4}')
- echo ref=$ref >> $GITHUB_OUTPUT
- # Generate only when document commit/PR
- if: >-
- ${{false
- || contains(github.event.head_commit.message, '[ruby/rdoc]')
- || contains(github.event.head_commit.message, '[DOC]')
- || contains(github.event.pull_request.title, '[DOC]')
- || contains(github.event.pull_request.labels.*.name, 'Documentation')
- }}
+ set -- $(sed 's/#.*//;/^rdoc /!d' gems/bundled_gems)
+ { echo version=$2; echo ref=$4; } >> $GITHUB_OUTPUT
- name: Checkout rdoc
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
+ uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
repository: ruby/rdoc
ref: ${{ steps.rdoc.outputs.ref }}
- path: .bundle/gems/rdoc-0
+ path: .bundle/gems/rdoc-${{ steps.rdoc.outputs.version }}
+ persist-credentials: false
if: ${{ steps.rdoc.outputs.ref != '' }}
- - name: Generate rdoc
+ - name: Generate rdoc scripts
run: |
set -x
gempath=$(ruby -e 'print Gem.user_dir, "/bin"')
@@ -92,21 +117,29 @@ jobs:
bundle config --local path vendor/bundle
bundle install --jobs 4
bundle exec rake generate
- working-directory: .bundle/gems/rdoc-0
+ working-directory: .bundle/gems/rdoc-${{ steps.rdoc.outputs.version }}
if: ${{ steps.rdoc.outputs.ref != '' }}
+ - name: Core docs coverage
+ run: |
+ make XRUBY=ruby RDOC_DEPENDS= RBCONFIG=update-rbconfig rdoc-coverage
+
- name: Generate docs
id: docs
run: |
- $RDOC -C -x ^ext -x ^lib .
- $RDOC --op html .
+ make XRUBY=ruby RDOC_DEPENDS= RBCONFIG=update-rbconfig HTMLOUT=html html
echo htmlout=ruby-html-${GITHUB_SHA:0:10} >> $GITHUB_OUTPUT
- env:
- RDOC: ruby -W0 --disable-gems tool/rdoc-srcdir -q
- if: ${{ steps.rdoc.outcome == 'success' }}
+ # Generate only when document commit/PR
+ if: >-
+ ${{false
+ || contains(github.event.head_commit.message, '[ruby/rdoc]')
+ || contains(github.event.head_commit.message, '[DOC]')
+ || contains(github.event.pull_request.title, '[DOC]')
+ || contains(github.event.pull_request.labels.*.name, 'Documentation')
+ }}
- name: Upload docs
- uses: actions/upload-artifact@v4
+ uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
path: html
name: ${{ steps.docs.outputs.htmlout }}
diff --git a/.github/workflows/check_sast.yml b/.github/workflows/check_sast.yml
new file mode 100644
index 0000000000..c8db1103ed
--- /dev/null
+++ b/.github/workflows/check_sast.yml
@@ -0,0 +1,133 @@
+name: 'Check SAST tool'
+
+on:
+ push:
+ branches: ['master']
+ paths-ignore:
+ - 'doc/**'
+ - '**/man/*'
+ - '**.md'
+ - '**.rdoc'
+ - '**/.document'
+ - '.*.yml'
+ pull_request:
+ paths-ignore:
+ - 'doc/**'
+ - '**/man/*'
+ - '**.md'
+ - '**.rdoc'
+ - '**/.document'
+ - '.*.yml'
+ schedule:
+ - cron: '0 12 * * *'
+ workflow_dispatch:
+
+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
+ contents: read
+
+jobs:
+ zizmor:
+ name: zizmor
+
+ runs-on: ubuntu-latest
+
+ permissions:
+ contents: read
+ security-events: write
+
+ steps:
+ - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
+ with:
+ persist-credentials: false
+
+ - name: Run zizmor
+ uses: zizmorcore/zizmor-action@5f14fd08f7cf1cb1609c1e344975f152c7ee938d # v0.5.6
+ continue-on-error: true
+
+ analyze:
+ name: Analyze
+ runs-on: ubuntu-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/upload-sarif to send a status report
+ # 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.pull_request.title, '[DOC]')
+ || contains(github.event.pull_request.labels.*.name, 'Documentation')
+ || (github.event.pull_request.user.login == 'dependabot[bot]')
+ )}}
+
+ strategy:
+ fail-fast: false
+ matrix:
+ include:
+ - language: cpp
+ - language: ruby
+
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
+ with:
+ persist-credentials: false
+
+ - name: Initialize CodeQL
+ uses: github/codeql-action/init@8aad20d150bbac5944a9f9d289da16a4b0d87c1e # v4.36.2
+ with:
+ languages: ${{ matrix.language }}
+ build-mode: none
+ config-file: .github/codeql/codeql-config.yml
+
+ - name: Perform CodeQL Analysis
+ uses: github/codeql-action/analyze@8aad20d150bbac5944a9f9d289da16a4b0d87c1e # v4.36.2
+ with:
+ category: '/language:${{ matrix.language }}'
+ upload: False
+ output: sarif-results
+
+ - name: filter-sarif
+ uses: advanced-security/filter-sarif@2da736ff05ef065cb2894ac6892e47b5eac2c3c0 # v1.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
+ -spec/ruby/core/regexp/timeout_spec.rb:rb/redos
+ -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: filter-sarif
+ uses: advanced-security/filter-sarif@2da736ff05ef065cb2894ac6892e47b5eac2c3c0 # v1.1
+ with:
+ patterns: |
+ +**/*.c
+ +**/*.h
+ input: sarif-results/${{ matrix.language }}.sarif
+ output: sarif-results/${{ matrix.language }}.sarif
+ if: ${{ matrix.language == 'cpp' }}
+ continue-on-error: true
+
+ - name: Upload SARIF
+ uses: github/codeql-action/upload-sarif@8aad20d150bbac5944a9f9d289da16a4b0d87c1e # v4.36.2
+ with:
+ sarif_file: sarif-results/${{ matrix.language }}.sarif
+ continue-on-error: true
diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml
deleted file mode 100644
index 6968be5e02..0000000000
--- a/.github/workflows/codeql-analysis.yml
+++ /dev/null
@@ -1,121 +0,0 @@
-name: 'CodeQL'
-
-on:
- push:
- branches: ['master']
- paths-ignore:
- - 'doc/**'
- - '**/man/*'
- - '**.md'
- - '**.rdoc'
- - '**/.document'
- - '.*.yml'
- pull_request:
- paths-ignore:
- - 'doc/**'
- - '**/man/*'
- - '**.md'
- - '**.rdoc'
- - '**/.document'
- - '.*.yml'
- schedule:
- - cron: '0 12 * * *'
- workflow_dispatch:
-
-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
- contents: read
-
-jobs:
- analyze:
- name: Analyze
- runs-on: ubuntu-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
- # 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.pull_request.title, '[DOC]')
- || contains(github.event.pull_request.labels.*.name, 'Documentation')
- || (github.event_name == 'push' && github.event.pull_request.user.login == 'dependabot[bot]')
- )}}
-
- env:
- enable_install_doc: no
-
- strategy:
- fail-fast: false
- matrix:
- include:
- - language: cpp
- - language: ruby
-
- steps:
- - name: Checkout repository
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
-
- - 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
-
- - uses: ./.github/actions/setup/directories
-
- - 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
-
- - name: Initialize CodeQL
- uses: github/codeql-action/init@df409f7d9260372bd5f19e5b04e83cb3c43714ae # v3.27.9
- with:
- languages: ${{ matrix.language }}
- trap-caching: false
- debug: true
-
- - name: Autobuild
- uses: github/codeql-action/autobuild@df409f7d9260372bd5f19e5b04e83cb3c43714ae # v3.27.9
-
- - name: Perform CodeQL Analysis
- uses: github/codeql-action/analyze@df409f7d9260372bd5f19e5b04e83cb3c43714ae # v3.27.9
- with:
- category: '/language:${{ matrix.language }}'
- upload: False
- output: sarif-results
-
- - 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: Upload SARIF
- uses: github/codeql-action/upload-sarif@df409f7d9260372bd5f19e5b04e83cb3c43714ae # v3.27.9
- with:
- sarif_file: sarif-results/${{ matrix.language }}.sarif
- continue-on-error: true
diff --git a/.github/workflows/compilers.yml b/.github/workflows/compilers.yml
index 3bad088613..f747b7fd03 100644
--- a/.github/workflows/compilers.yml
+++ b/.github/workflows/compilers.yml
@@ -37,7 +37,7 @@ jobs:
|| contains(github.event.head_commit.message, '[DOC]')
|| contains(github.event.pull_request.title, '[DOC]')
|| contains(github.event.pull_request.labels.*.name, 'Documentation')
- || (github.event_name == 'push' && github.event.pull_request.user.login == 'dependabot[bot]')
+ || (github.event.pull_request.user.login == 'dependabot[bot]')
)}}
steps:
- run: true
@@ -49,20 +49,21 @@ jobs:
needs: compile-if
if: ${{ needs.compile-if.result == 'success' }}
timeout-minutes: 60
- services: { docuum: { image: 'stephanmisc/docuum', options: '--init', volumes: [ '/root', '/var/run/docker.sock:/var/run/docker.sock' ] } }
+
steps:
- - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- with: { sparse-checkout-cone-mode: false, sparse-checkout: /.github }
+ - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
+ with: { sparse-checkout-cone-mode: false, sparse-checkout: /.github, persist-credentials: false }
# Set fetch-depth: 10 so that Launchable can receive commits information.
- { uses: './.github/actions/setup/directories', with: { srcdir: 'src', builddir: 'build', makeup: true, fetch-depth: 10 } }
- - name: 'clang 18 LTO'
+ - name: 'clang 22 LTO'
uses: './.github/actions/compilers'
with:
- tag: clang-18
- with_gcc: 'clang-18 -flto=auto'
+ tag: clang-22
+ with_gcc: 'clang-22 -flto=auto'
optflags: '-O2'
enable_shared: false
- - { uses: './.github/actions/compilers', name: '-O0', with: { optflags: '-O0 -march=x86-64 -mtune=generic' } }
+ timeout-minutes: 30
+ - { uses: './.github/actions/compilers', name: '-O0', with: { optflags: '-O0 -march=x86-64 -mtune=generic' }, timeout-minutes: 5 }
# - { uses: './.github/actions/compilers', name: '-O3', with: { optflags: '-O3 -march=x86-64 -mtune=generic', check: true } }
compile2:
@@ -71,10 +72,10 @@ jobs:
needs: compile-if
if: ${{ needs.compile-if.result == 'success' }}
timeout-minutes: 60
- services: { docuum: { image: 'stephanmisc/docuum', options: '--init', volumes: [ '/root', '/var/run/docker.sock:/var/run/docker.sock' ] } }
+
steps:
- - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- with: { sparse-checkout-cone-mode: false, sparse-checkout: /.github }
+ - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
+ with: { sparse-checkout-cone-mode: false, sparse-checkout: /.github, persist-credentials: false }
- { uses: './.github/actions/setup/directories', with: { srcdir: 'src', builddir: 'build', makeup: true, fetch-depth: 10 } }
- name: 'GCC 15 LTO'
uses: './.github/actions/compilers'
@@ -83,16 +84,15 @@ jobs:
with_gcc: 'gcc-15 -flto=auto -ffat-lto-objects -Werror=lto-type-mismatch'
optflags: '-O2'
enable_shared: false
- - { uses: './.github/actions/compilers', name: 'ext/Setup', with: { static_exts: 'etc json/* */escape' } }
- - { uses: './.github/actions/compilers', name: 'GCC 15', with: { tag: 'gcc-15' } }
- - { uses: './.github/actions/compilers', name: 'GCC 14', with: { tag: 'gcc-14' } }
- - { 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' } }
+ timeout-minutes: 10
+ - { uses: './.github/actions/compilers', name: 'ext/Setup', with: { static_exts: 'etc json/* */escape' }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'GCC 15', with: { tag: 'gcc-15' }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'GCC 14', with: { tag: 'gcc-14' }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'GCC 13', with: { tag: 'gcc-13' }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'GCC 12', with: { tag: 'gcc-12' }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'GCC 11', with: { tag: 'gcc-11' }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'GCC 10', with: { tag: 'gcc-10' }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'GCC 9', with: { tag: 'gcc-9' }, timeout-minutes: 5 }
compile3:
name: 'omnibus compilations, #3'
@@ -100,20 +100,18 @@ jobs:
needs: compile-if
if: ${{ needs.compile-if.result == 'success' }}
timeout-minutes: 60
- services: { docuum: { image: 'stephanmisc/docuum', options: '--init', volumes: [ '/root', '/var/run/docker.sock:/var/run/docker.sock' ] } }
+
steps:
- - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- with: { sparse-checkout-cone-mode: false, sparse-checkout: /.github }
+ - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
+ with: { sparse-checkout-cone-mode: false, sparse-checkout: /.github, persist-credentials: false }
- { uses: './.github/actions/setup/directories', with: { srcdir: 'src', builddir: 'build', makeup: true, fetch-depth: 10 } }
- - { uses: './.github/actions/compilers', name: 'clang 22', with: { tag: 'clang-22' } }
- - { uses: './.github/actions/compilers', name: 'clang 21', with: { tag: 'clang-21' } }
- - { 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 20', with: { tag: 'clang-20' }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'clang 19', with: { tag: 'clang-19' }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'clang 18', with: { tag: 'clang-18' }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'clang 17', with: { tag: 'clang-17' }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'clang 16', with: { tag: 'clang-16' }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'clang 15', with: { tag: 'clang-15' }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'clang 14', with: { tag: 'clang-14' }, timeout-minutes: 5 }
compile4:
name: 'omnibus compilations, #4'
@@ -121,20 +119,20 @@ jobs:
needs: compile-if
if: ${{ needs.compile-if.result == 'success' }}
timeout-minutes: 60
- services: { docuum: { image: 'stephanmisc/docuum', options: '--init', volumes: [ '/root', '/var/run/docker.sock:/var/run/docker.sock' ] } }
+
steps:
- - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- with: { sparse-checkout-cone-mode: false, sparse-checkout: /.github }
+ - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
+ with: { sparse-checkout-cone-mode: false, sparse-checkout: /.github, persist-credentials: false }
- { uses: './.github/actions/setup/directories', with: { srcdir: 'src', builddir: 'build', makeup: true, fetch-depth: 10 } }
- - { uses: './.github/actions/compilers', name: 'clang 13', with: { tag: 'clang-13' } }
- - { uses: './.github/actions/compilers', name: 'clang 12', with: { tag: 'clang-12' } }
- - { 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: 'clang 13', with: { tag: 'clang-13' }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'clang 12', with: { tag: 'clang-12' }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'clang 11', with: { tag: 'clang-11' }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'clang 10', with: { tag: 'clang-10' }, timeout-minutes: 5 }
+ # llvm-objcopy<=9 doesn't have --wildcard. It compiles, but leaves Rust symbols in libyjit.o and fail `make test-leaked-globals`.
+ - { uses: './.github/actions/compilers', name: 'clang 9', with: { tag: 'clang-9', append_configure: '--disable-yjit --disable-zjit' }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'clang 8', with: { tag: 'clang-8', append_configure: '--disable-yjit --disable-zjit' }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'clang 7', with: { tag: 'clang-7', append_configure: '--disable-yjit --disable-zjit' }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'clang 6', with: { tag: 'clang-6.0', append_configure: '--disable-yjit --disable-zjit' }, timeout-minutes: 5 }
compile5:
name: 'omnibus compilations, #5'
@@ -142,10 +140,10 @@ jobs:
needs: compile-if
if: ${{ needs.compile-if.result == 'success' }}
timeout-minutes: 60
- services: { docuum: { image: 'stephanmisc/docuum', options: '--init', volumes: [ '/root', '/var/run/docker.sock:/var/run/docker.sock' ] } }
+
steps:
- - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- with: { sparse-checkout-cone-mode: false, sparse-checkout: /.github }
+ - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
+ with: { sparse-checkout-cone-mode: false, sparse-checkout: /.github, persist-credentials: false }
- { uses: './.github/actions/setup/directories', with: { srcdir: 'src', builddir: 'build', makeup: true, fetch-depth: 10 } }
# -Wno-strict-prototypes is necessary with current clang-15 since
# older autoconf generate functions without prototype and -pedantic
@@ -153,14 +151,14 @@ jobs:
# 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: 'C99', with: { CFLAGS: '-std=c99 -Werror=pedantic -pedantic-errors -Wno-strict-prototypes' }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'C11', with: { CFLAGS: '-std=c11 -Werror=pedantic -pedantic-errors -Wno-strict-prototypes' }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'C17', with: { CFLAGS: '-std=c17 -Werror=pedantic -pedantic-errors -Wno-strict-prototypes' }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'C23', with: { CFLAGS: '-std=c2x -Werror=pedantic -pedantic-errors -Wno-strict-prototypes' }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'C++98', with: { CXXFLAGS: '-std=c++98 -Werror=pedantic -pedantic-errors -Wno-c++11-long-long' }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'C++11', with: { CXXFLAGS: '-std=c++11 -Werror=pedantic -pedantic-errors -Wno-c++11-long-long' }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'C++14', with: { CXXFLAGS: '-std=c++14 -Werror=pedantic -pedantic-errors -Wno-c++11-long-long' }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'C++17', with: { CXXFLAGS: '-std=c++17 -Werror=pedantic -pedantic-errors -Wno-c++11-long-long' }, timeout-minutes: 5 }
compile6:
name: 'omnibus compilations, #6'
@@ -168,19 +166,19 @@ jobs:
needs: compile-if
if: ${{ needs.compile-if.result == 'success' }}
timeout-minutes: 60
- services: { docuum: { image: 'stephanmisc/docuum', options: '--init', volumes: [ '/root', '/var/run/docker.sock:/var/run/docker.sock' ] } }
+
steps:
- - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- with: { sparse-checkout-cone-mode: false, sparse-checkout: /.github }
+ - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
+ with: { sparse-checkout-cone-mode: false, sparse-checkout: /.github, persist-credentials: false }
- { uses: './.github/actions/setup/directories', with: { srcdir: 'src', builddir: 'build', makeup: true, fetch-depth: 10 } }
- - { 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' } }
- - { 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' } }
+ - { uses: './.github/actions/compilers', name: 'C++20', with: { CXXFLAGS: '-std=c++20 -Werror=pedantic -pedantic-errors -Wno-c++11-long-long' }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'C++23', with: { CXXFLAGS: '-std=c++23 -Werror=pedantic -pedantic-errors -Wno-c++11-long-long' }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'C++26', with: { CXXFLAGS: '-std=c++26 -Werror=pedantic -pedantic-errors -Wno-c++11-long-long' }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'gmp', with: { append_configure: '--with-gmp', test_all: 'ruby/test_bignum.rb', test_spec: "/github/workspace/src/spec/ruby/core/integer" }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'jemalloc', with: { append_configure: '--with-jemalloc' }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'valgrind', with: { append_configure: '--with-valgrind' }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'coroutine=ucontext', with: { append_configure: '--with-coroutine=ucontext' }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'coroutine=pthread', with: { append_configure: '--with-coroutine=pthread' }, timeout-minutes: 5 }
compile7:
name: 'omnibus compilations, #7'
@@ -188,21 +186,19 @@ jobs:
needs: compile-if
if: ${{ needs.compile-if.result == 'success' }}
timeout-minutes: 60
- services: { docuum: { image: 'stephanmisc/docuum', options: '--init', volumes: [ '/root', '/var/run/docker.sock:/var/run/docker.sock' ] } }
+
steps:
- - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- with: { sparse-checkout-cone-mode: false, sparse-checkout: /.github }
+ - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
+ with: { sparse-checkout-cone-mode: false, sparse-checkout: /.github, persist-credentials: false }
- { uses: './.github/actions/setup/directories', with: { srcdir: 'src', builddir: 'build', makeup: true, fetch-depth: 10 } }
- - { uses: './.github/actions/compilers', name: 'disable-jit', with: { append_configure: '--disable-yjit --disable-zjit' } }
- - { uses: './.github/actions/compilers', name: 'disable-yjit', with: { append_configure: '--disable-yjit' } }
- - { uses: './.github/actions/compilers', name: 'disable-zjit', with: { append_configure: '--disable-zjit' } }
- - { 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' } }
+ - { uses: './.github/actions/compilers', name: 'disable-jit', with: { append_configure: '--disable-yjit --disable-zjit' }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'disable-yjit', with: { append_configure: '--disable-yjit' }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'disable-zjit', with: { append_configure: '--disable-zjit' }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'disable-dln', with: { append_configure: '--disable-dln' }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'enable-mkmf-verbose', with: { append_configure: '--enable-mkmf-verbose' }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'disable-rubygems', with: { append_configure: '--disable-rubygems' }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'RUBY_DEVEL', with: { append_configure: '--enable-devel' }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'OPT_THREADED_CODE=0', with: { cppflags: '-DOPT_THREADED_CODE=0' }, timeout-minutes: 5 }
compile8:
name: 'omnibus compilations, #8'
@@ -210,19 +206,18 @@ jobs:
needs: compile-if
if: ${{ needs.compile-if.result == 'success' }}
timeout-minutes: 60
- services: { docuum: { image: 'stephanmisc/docuum', options: '--init', volumes: [ '/root', '/var/run/docker.sock:/var/run/docker.sock' ] } }
+
steps:
- - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- with: { sparse-checkout-cone-mode: false, sparse-checkout: /.github }
+ - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
+ with: { sparse-checkout-cone-mode: false, sparse-checkout: /.github, persist-credentials: false }
- { uses: './.github/actions/setup/directories', with: { srcdir: 'src', builddir: 'build', makeup: true, fetch-depth: 10 } }
- - { 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: 'NDEBUG', with: { cppflags: '-DNDEBUG' }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'RUBY_DEBUG', with: { cppflags: '-DRUBY_DEBUG' }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'ARRAY_DEBUG', with: { cppflags: '-DARRAY_DEBUG' }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'CCAN_LIST_DEBUG', with: { cppflags: '-DCCAN_LIST_DEBUG' }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'CPDEBUG=-1', with: { cppflags: '-DCPDEBUG=-1' }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'ENC_DEBUG', with: { cppflags: '-DENC_DEBUG' }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'GC_DEBUG', with: { cppflags: '-DGC_DEBUG' }, timeout-minutes: 5 }
compile9:
name: 'omnibus compilations, #9'
@@ -230,19 +225,19 @@ jobs:
needs: compile-if
if: ${{ needs.compile-if.result == 'success' }}
timeout-minutes: 60
- services: { docuum: { image: 'stephanmisc/docuum', options: '--init', volumes: [ '/root', '/var/run/docker.sock:/var/run/docker.sock' ] } }
+
steps:
- - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- with: { sparse-checkout-cone-mode: false, sparse-checkout: /.github }
+ - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
+ with: { sparse-checkout-cone-mode: false, sparse-checkout: /.github, persist-credentials: false }
- { uses: './.github/actions/setup/directories', with: { srcdir: 'src', builddir: 'build', makeup: true, fetch-depth: 10 } }
- - { uses: './.github/actions/compilers', name: 'HASH_DEBUG', with: { cppflags: '-DHASH_DEBUG' } }
- - { uses: './.github/actions/compilers', name: 'ID_TABLE_DEBUG', with: { cppflags: '-DID_TABLE_DEBUG' } }
- - { 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: 'HASH_DEBUG', with: { cppflags: '-DHASH_DEBUG' }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'ID_TABLE_DEBUG', with: { cppflags: '-DID_TABLE_DEBUG' }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'RGENGC_DEBUG=-1', with: { cppflags: '-DRGENGC_DEBUG=-1' }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'SYMBOL_DEBUG', with: { cppflags: '-DSYMBOL_DEBUG' }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'RGENGC_CHECK_MODE', with: { cppflags: '-DRGENGC_CHECK_MODE' }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'VM_CHECK_MODE', with: { cppflags: '-DVM_CHECK_MODE' }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'USE_EMBED_CI=0', with: { cppflags: '-DUSE_EMBED_CI=0' }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'USE_FLONUM=0', with: { cppflags: '-DUSE_FLONUM=0', append_configure: '--disable-yjit --disable-zjit' }, timeout-minutes: 5 }
compileX:
name: 'omnibus compilations, #10'
@@ -250,19 +245,20 @@ jobs:
needs: compile-if
if: ${{ needs.compile-if.result == 'success' }}
timeout-minutes: 60
- services: { docuum: { image: 'stephanmisc/docuum', options: '--init', volumes: [ '/root', '/var/run/docker.sock:/var/run/docker.sock' ] } }
+
steps:
- - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- with: { sparse-checkout-cone-mode: false, sparse-checkout: /.github }
+ - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
+ with: { sparse-checkout-cone-mode: false, sparse-checkout: /.github, persist-credentials: false }
- { uses: './.github/actions/setup/directories', with: { srcdir: 'src', builddir: 'build', makeup: true, fetch-depth: 10 } }
- - { 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' } }
- - { 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: 'USE_LAZY_LOAD', with: { cppflags: '-DUSE_LAZY_LOAD' }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'USE_RUBY_DEBUG_LOG=1', with: { cppflags: '-DUSE_RUBY_DEBUG_LOG=1' }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'USE_DEBUG_COUNTER', with: { cppflags: '-DUSE_DEBUG_COUNTER=1' }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'SHARABLE_MIDDLE_SUBSTRING', with: { cppflags: '-DSHARABLE_MIDDLE_SUBSTRING=1' }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'DEBUG_FIND_TIME_NUMGUESS', with: { cppflags: '-DDEBUG_FIND_TIME_NUMGUESS' }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'DEBUG_INTEGER_PACK', with: { cppflags: '-DDEBUG_INTEGER_PACK' }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'OPT_THREADED_CODE=1', with: { cppflags: '-DOPT_THREADED_CODE=1' }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'OPT_THREADED_CODE=2', with: { cppflags: '-DOPT_THREADED_CODE=2' }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'clang 21', with: { tag: 'clang-21' }, timeout-minutes: 5 }
compileB:
name: 'omnibus compilations, #11'
@@ -270,19 +266,18 @@ jobs:
needs: compile-if
if: ${{ needs.compile-if.result == 'success' }}
timeout-minutes: 60
- services: { docuum: { image: 'stephanmisc/docuum', options: '--init', volumes: [ '/root', '/var/run/docker.sock:/var/run/docker.sock' ] } }
+
steps:
- - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- with: { sparse-checkout-cone-mode: false, sparse-checkout: /.github }
+ - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
+ with: { sparse-checkout-cone-mode: false, sparse-checkout: /.github, persist-credentials: false }
- { uses: './.github/actions/setup/directories', with: { srcdir: 'src', builddir: 'build', makeup: true, fetch-depth: 10 } }
- - { 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' } }
- - { 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_OBJ_INFO', with: { cppflags: '-DRGENGC_OBJ_INFO' } }
- - { uses: './.github/actions/compilers', name: 'RGENGC_PROFILE', with: { cppflags: '-DRGENGC_PROFILE' } }
+ - { uses: './.github/actions/compilers', name: 'GC_DEBUG_STRESS_TO_CLASS', with: { cppflags: '-DGC_DEBUG_STRESS_TO_CLASS' }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'GC_ENABLE_LAZY_SWEEP=0', with: { cppflags: '-DGC_ENABLE_LAZY_SWEEP=0' }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'GC_PROFILE_DETAIL_MEMORY', with: { cppflags: '-DGC_PROFILE_DETAIL_MEMORY' }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'GC_PROFILE_MORE_DETAIL', with: { cppflags: '-DGC_PROFILE_MORE_DETAIL' }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'MALLOC_ALLOCATED_SIZE_CHECK', with: { cppflags: '-DMALLOC_ALLOCATED_SIZE_CHECK' }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'RGENGC_ESTIMATE_OLDMALLOC', with: { cppflags: '-DRGENGC_ESTIMATE_OLDMALLOC' }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'RGENGC_PROFILE', with: { cppflags: '-DRGENGC_PROFILE' }, timeout-minutes: 5 }
compileC:
name: 'omnibus compilations, #12'
@@ -290,18 +285,19 @@ jobs:
needs: compile-if
if: ${{ needs.compile-if.result == 'success' }}
timeout-minutes: 60
- services: { docuum: { image: 'stephanmisc/docuum', options: '--init', volumes: [ '/root', '/var/run/docker.sock:/var/run/docker.sock' ] } }
+
steps:
- - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- with: { sparse-checkout-cone-mode: false, sparse-checkout: /.github }
+ - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
+ with: { sparse-checkout-cone-mode: false, sparse-checkout: /.github, persist-credentials: false }
- { uses: './.github/actions/setup/directories', with: { srcdir: 'src', builddir: 'build', makeup: true, fetch-depth: 10 } }
- - { 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' } }
- - { uses: './.github/actions/compilers', name: 'enable-yjit', with: { append_configure: '--enable-yjit' } }
- - { uses: './.github/actions/compilers', name: 'enable-{y,z}jit', with: { append_configure: '--enable-yjit --enable-zjit' } }
- - { uses: './.github/actions/compilers', name: 'enable-{y,z}jit=dev', with: { append_configure: '--enable-yjit=dev --enable-zjit' } }
- - { uses: './.github/actions/compilers', name: 'YJIT_FORCE_ENABLE', with: { cppflags: '-DYJIT_FORCE_ENABLE' } }
- - { uses: './.github/actions/compilers', name: 'UNIVERSAL_PARSER', with: { cppflags: '-DUNIVERSAL_PARSER' } }
+ - { uses: './.github/actions/compilers', name: 'VM_DEBUG_BP_CHECK', with: { cppflags: '-DVM_DEBUG_BP_CHECK' }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'VM_DEBUG_VERIFY_METHOD_CACHE', with: { cppflags: '-DVM_DEBUG_VERIFY_METHOD_CACHE' }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'YJIT_FORCE_ENABLE', with: { cppflags: '-DYJIT_FORCE_ENABLE' }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'UNIVERSAL_PARSER', with: { cppflags: '-DUNIVERSAL_PARSER' }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'clang 23', with: { tag: 'clang-23' }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'clang 22', with: { tag: 'clang-22' }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'GCC 8', with: { tag: 'gcc-8' }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'GCC 7', with: { tag: 'gcc-7' }, timeout-minutes: 5 }
compilemax:
name: 'omnibus compilations, result'
@@ -321,8 +317,8 @@ jobs:
- 'compileB'
- 'compileC'
steps:
- - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- with: { sparse-checkout-cone-mode: false, sparse-checkout: /.github }
+ - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
+ with: { sparse-checkout-cone-mode: false, sparse-checkout: /.github, persist-credentials: false }
- uses: ./.github/actions/slack
with:
label: 'omnibus'
diff --git a/.github/workflows/crosscompile.yml b/.github/workflows/crosscompile.yml
new file mode 100644
index 0000000000..3ed6429a1e
--- /dev/null
+++ b/.github/workflows/crosscompile.yml
@@ -0,0 +1,123 @@
+name: Cross compile
+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
+ 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:
+ name: make (${{ matrix.host }} host on ${{ matrix.build }})
+ strategy:
+ matrix:
+ include:
+ - host: aarch64-linux-gnu
+ arch: arm64
+ build: x86_64-linux-gnu
+ runs-on: ubuntu-24.04
+ file_arch: ARM aarch64
+ - host: x86_64-linux-gnu
+ arch: amd64
+ build: aarch64-linux-gnu
+ runs-on: ubuntu-24.04-arm
+ file_arch: x86-64
+ fail-fast: false
+
+ env:
+ GITPULLOPTIONS: --no-tags origin ${{ github.ref }}
+
+ runs-on: ${{ matrix.runs-on }}
+
+ if: >-
+ ${{!(false
+ || contains(github.event.head_commit.message, '[DOC]')
+ || contains(github.event.pull_request.title, '[DOC]')
+ || contains(github.event.pull_request.labels.*.name, 'Documentation')
+ || (github.event.pull_request.user.login == 'dependabot[bot]')
+ )}}
+
+ steps:
+ - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
+ with:
+ sparse-checkout-cone-mode: false
+ sparse-checkout: /.github
+ persist-credentials: false
+
+ - uses: ./.github/actions/setup/directories
+ with:
+ srcdir: src
+ builddir: build
+ makeup: true
+
+ - name: Setup cross-compilation toolchain sources
+ run: |
+ native_arch=$(dpkg --print-architecture)
+ # Restrict existing sources to native arch
+ sudo sed -i '/^Architectures:/d' /etc/apt/sources.list.d/ubuntu.sources
+ sudo sed -i "/^Types:/a Architectures: ${native_arch}" /etc/apt/sources.list.d/ubuntu.sources
+ # Add cross-arch sources
+ if [ "${{ matrix.arch }}" = "arm64" ]; then
+ cross_uri="http://ports.ubuntu.com/"
+ else
+ cross_uri="http://archive.ubuntu.com/ubuntu/"
+ fi
+ printf '%s\n' \
+ "Types: deb" \
+ "URIs: ${cross_uri}" \
+ "Suites: noble noble-updates noble-security" \
+ "Components: main universe" \
+ "Architectures: ${{ matrix.arch }}" \
+ | sudo tee /etc/apt/sources.list.d/cross-${{ matrix.arch }}.sources
+
+ - uses: ./.github/actions/setup/ubuntu
+ with:
+ arch: ${{ matrix.arch }}
+
+ - uses: ./.github/actions/setup/baseruby
+ id: baseruby
+ with:
+ srcdir: src
+
+ - name: Run configure
+ run: >-
+ ../src/configure -C --disable-install-doc
+ --prefix=/usr
+ --build=${{ matrix.build }}
+ --host=${{ matrix.host }}
+ --with-baseruby="$baseruby"
+ env:
+ baseruby: ${{ steps.baseruby.outputs.ruby }}
+
+ - run: make
+
+ - run: make install DESTDIR=$PWD/install
+
+ - name: Verify cross-compiled binary
+ run: |
+ file install/usr/bin/ruby
+ file install/usr/bin/ruby | grep -q '${{ matrix.file_arch }}'
+
+ - uses: ./.github/actions/slack
+ with:
+ label: cross ${{ matrix.host }}
+ 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/cygwin.yml b/.github/workflows/cygwin.yml
index d23261ddee..f1a6f79587 100644
--- a/.github/workflows/cygwin.yml
+++ b/.github/workflows/cygwin.yml
@@ -34,18 +34,22 @@ jobs:
|| contains(github.event.head_commit.message, '[DOC]')
|| contains(github.event.pull_request.title, '[DOC]')
|| contains(github.event.pull_request.labels.*.name, 'Documentation')
- || (github.event_name == 'push' && github.event.pull_request.user.login == 'dependabot[bot]')
+ || (github.event.pull_request.user.login == 'dependabot[bot]')
)}}
steps:
- run: git config --global core.autocrlf input
- - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
+ - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
+ with:
+ persist-credentials: false
- name: Setup Cygwin
- uses: cygwin/cygwin-install-action@master
+ uses: cygwin/cygwin-install-action@711d29f3da23c9f4a1798e369a6f01198c13b11a # v6.1
with:
- packages: ruby gcc-core make autoconf libtool libssl-devel libyaml-devel libffi-devel zlib-devel
+ packages: ruby gcc-core make autoconf libtool libssl-devel libyaml-devel libffi-devel zlib-devel rubygems
+ site: |
+ https://cygwin.osuosl.org/
- name: configure
run: |
@@ -63,3 +67,9 @@ jobs:
timeout-minutes: 30
run: make -j4 V=1
shell: C:\cygwin\bin\bash.EXE --noprofile --norc -e -o igncr -o pipefail {0}
+
+ - uses: ./.github/actions/slack
+ with:
+ label: Cygwin
+ SLACK_WEBHOOK_URL: ${{ secrets.SIMPLER_ALERTS_URL }} # ruby-lang slack: ruby/simpler-alerts-bot
+ if: ${{ failure() }}
diff --git a/.github/workflows/default_gems.yml b/.github/workflows/default_gems.yml
deleted file mode 100644
index cd15e34229..0000000000
--- a/.github/workflows/default_gems.yml
+++ /dev/null
@@ -1,96 +0,0 @@
-name: Update default gems list
-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:
- update_default_gems:
- name: Update default gems list
-
- permissions:
- contents: write # for Git to git push
-
- runs-on: ubuntu-latest
-
- if: ${{ github.repository == 'ruby/ruby' }}
-
- steps:
- - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- with:
- token: ${{ (github.repository == 'ruby/ruby' && !startsWith(github.event_name, 'pull')) && secrets.MATZBOT_AUTO_UPDATE_TOKEN || secrets.GITHUB_TOKEN }}
-
- - id: gems
- run: true
- if: ${{ github.ref == 'refs/heads/master' }}
-
- - uses: ./.github/actions/setup/directories
- with:
- makeup: true
- # Skip overwriting MATZBOT_AUTO_UPDATE_TOKEN
- checkout: '' # false (ref: https://github.com/actions/runner/issues/2238)
- if: ${{ steps.gems.outcome == 'success' }}
-
- - 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/default_gems_list.yml b/.github/workflows/default_gems_list.yml
new file mode 100644
index 0000000000..68f2d18dd6
--- /dev/null
+++ b/.github/workflows/default_gems_list.yml
@@ -0,0 +1,99 @@
+name: Update default gems list
+on: [push, pull_request, merge_group]
+
+env:
+ UPDATE_NEWS_ENABLED: true
+
+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:
+ update_default_gems_list:
+ name: Update default gems list
+
+ permissions:
+ contents: write # for Git to git push
+
+ runs-on: ubuntu-latest
+
+ if: ${{ github.repository == 'ruby/ruby' }}
+
+ steps:
+ - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
+ with:
+ token: ${{ (github.repository == 'ruby/ruby' && !startsWith(github.event_name, 'pull')) && secrets.MATZBOT_AUTO_UPDATE_TOKEN || secrets.GITHUB_TOKEN }}
+
+ - id: gems
+ run: true
+ if: ${{ github.ref == 'refs/heads/master' }}
+
+ - uses: ./.github/actions/setup/directories
+ with:
+ makeup: true
+ # Skip overwriting MATZBOT_AUTO_UPDATE_TOKEN
+ checkout: '' # false (ref: https://github.com/actions/runner/issues/2238)
+ if: ${{ steps.gems.outcome == 'success' }}
+
+ - name: Download previous gems list
+ run: |
+ data=default_gems.json
+ mkdir -p .downloaded-cache
+ ln -s .downloaded-cache/$data .
+ curl --retry 5 --retry-connrefused --retry-delay 2 --retry-max-time 60 -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' && env.UPDATE_NEWS_ENABLED == 'true' }}
+
+ - 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/dependabot_automerge.yml b/.github/workflows/dependabot_automerge.yml
index 3a2ba704ae..2e4dc8d7a2 100644
--- a/.github/workflows/dependabot_automerge.yml
+++ b/.github/workflows/dependabot_automerge.yml
@@ -13,11 +13,11 @@ jobs:
if: github.event.pull_request.user.login == 'dependabot[bot]' && github.repository == 'ruby/ruby'
steps:
- name: Dependabot metadata
- uses: dependabot/fetch-metadata@08eff52bf64351f401fb50d4972fa95b9f2c2d1b # v2.4.0
+ uses: dependabot/fetch-metadata@25dd0e34f4fe68f24cc83900b1fe3fe149efef98 # v3.1.0
id: metadata
- name: Wait for status checks
- uses: lewagon/wait-on-check-action@0dceb95e7c4cad8cc7422aee3885998f5cab9c79 # v1.4.0
+ uses: lewagon/wait-on-check-action@9312864dfbc9fd208e9c0417843430751c042800 # v1.7.0
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
ref: ${{ github.event.pull_request.head.sha || github.sha }}
diff --git a/.github/workflows/labeler.yml b/.github/workflows/labeler.yml
index e57cd86e2b..d0a8024b05 100644
--- a/.github/workflows/labeler.yml
+++ b/.github/workflows/labeler.yml
@@ -2,6 +2,9 @@ name: "Pull Request Labeler"
on:
- pull_request_target
+permissions:
+ contents: read
+
jobs:
labeler:
permissions:
@@ -9,4 +12,4 @@ jobs:
pull-requests: write
runs-on: ubuntu-latest
steps:
- - uses: actions/labeler@v5
+ - uses: actions/labeler@f27b608878404679385c85cfa523b85ccb86e213 # v6.1.0
diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml
index aab238ea47..4f1807121f 100644
--- a/.github/workflows/macos.yml
+++ b/.github/workflows/macos.yml
@@ -26,27 +26,29 @@ jobs:
matrix:
include:
- test_task: check
- os: macos-14
+ os: macos-26
- test_task: check
- os: macos-14
+ os: macos-15
configure_args: '--with-gcc=gcc-14'
- test_task: check
- os: macos-14
+ os: macos-26
configure_args: '--with-jemalloc --with-opt-dir=$(brew --prefix jemalloc)'
- test_task: check
- os: macos-14
+ os: macos-26
configure_args: '--with-gmp'
- test_task: test-all
test_opts: --repeat-count=2
- os: macos-14
+ os: macos-26
- test_task: test-bundler-parallel
- os: macos-14
+ os: macos-26
- test_task: test-bundled-gems
- os: macos-14
+ os: macos-26
- test_task: check
os: macos-15
- test_task: check
- os: macos-13
+ os: macos-15-intel
+ - test_task: check
+ os: macos-14
fail-fast: false
env:
@@ -59,14 +61,15 @@ jobs:
|| contains(github.event.head_commit.message, '[DOC]')
|| contains(github.event.pull_request.title, '[DOC]')
|| contains(github.event.pull_request.labels.*.name, 'Documentation')
- || (github.event_name == 'push' && github.event.pull_request.user.login == 'dependabot[bot]')
+ || (github.event.pull_request.user.login == 'dependabot[bot]')
)}}
steps:
- - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
+ - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
sparse-checkout-cone-mode: false
sparse-checkout: /.github
+ persist-credentials: false
- name: Install libraries
uses: ./.github/actions/setup/macos
@@ -141,7 +144,7 @@ jobs:
ulimit -c unlimited
make -s ${{ matrix.test_task }} ${TESTS:+TESTS="$TESTS"}
- timeout-minutes: 60
+ timeout-minutes: 90
env:
RUBY_TESTOPTS: '-q --tty=no'
TEST_BUNDLED_GEMS_ALLOW_FAILURES: ''
@@ -159,32 +162,24 @@ jobs:
if: ${{ matrix.test_task == 'check' && matrix.skipped_tests }}
continue-on-error: ${{ matrix.continue-on-skipped_tests || false }}
+ - name: CAPI extensions
+ uses: ./.github/actions/capiext
+ with:
+ builddir: build
+ env:
+ RUBY_TESTOPTS: '-v --tty=no'
+ if: ${{ contains(matrix.extra_checks, 'capi') }}
+
- uses: ./.github/actions/slack
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
- 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
+ runs-on: ubuntu-latest
needs: [make]
steps:
- run: exit 1
diff --git a/.github/workflows/mingw.yml b/.github/workflows/mingw.yml
index 773bb77503..9a47e70f8c 100644
--- a/.github/workflows/mingw.yml
+++ b/.github/workflows/mingw.yml
@@ -30,16 +30,32 @@ permissions:
#
jobs:
make:
- runs-on: windows-2022
+ runs-on: windows-${{ matrix.os }}
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'
+ MSYS2_ARCH: >-
+ ${{ case(
+ contains(matrix.msystem, 'arm64'), 'aarch64',
+ contains(matrix.msystem, '64'), 'x86_64',
+ 'i686'
+ ) }}
+ MINGW_PACKAGE_PREFIX: >-
+ mingw-w${{
+ case(endsWith(matrix.msystem, '64'), '64', '32')
+ }}-${{ case(
+ startsWith(matrix.msystem, 'clang'), 'clang',
+ startsWith(matrix.msystem, 'ucrt'), 'ucrt',
+ 'mingw'
+ ) }}-${{ case(
+ contains(matrix.msystem, 'arm64'), 'aarch64',
+ endsWith(matrix.msystem, '64'), 'x86_64',
+ 'i686'
+ ) }}
+ CFLAGS: '-mtune=generic -O3 -pipe'
+ CXXFLAGS: '-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 }}
@@ -50,8 +66,12 @@ jobs:
# 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'
+ os: 2022
test_task: 'check'
test-all-opts: '--name=!/TestObjSpace#test_reachable_objects_during_iteration/'
+ - msystem: 'CLANGARM64'
+ os: 11-arm
+ test_task: 'check'
fail-fast: false
if: >-
@@ -59,32 +79,33 @@ jobs:
|| contains(github.event.head_commit.message, '[DOC]')
|| contains(github.event.pull_request.title, '[DOC]')
|| contains(github.event.pull_request.labels.*.name, 'Documentation')
- || (github.event_name == 'push' && github.event.pull_request.user.login == 'dependabot[bot]')
+ || (github.event.pull_request.user.login == 'dependabot[bot]' && !startsWith(github.head_ref, 'dependabot/vcpkg'))
)}}
steps:
- - uses: msys2/setup-msys2@40677d36a502eb2cf0fb808cc9dec31bf6152638 # v2.28.0
+ - uses: msys2/setup-msys2@e9898307ac31d1a803454791be09ab9973336e1c # v2.31.1
id: msys2
with:
- msystem: UCRT64
+ msystem: ${{ matrix.msystem }}
update: true
install: >-
git
make
ruby
autoconf
- mingw-w64-ucrt-x86_64-gcc
- mingw-w64-ucrt-x86_64-ragel
- mingw-w64-ucrt-x86_64-openssl
- mingw-w64-ucrt-x86_64-libyaml
- mingw-w64-ucrt-x86_64-libffi
+ ${{ env.MINGW_PACKAGE_PREFIX }}-gcc
+ ${{ env.MINGW_PACKAGE_PREFIX }}-ragel
+ ${{ env.MINGW_PACKAGE_PREFIX }}-openssl
+ ${{ env.MINGW_PACKAGE_PREFIX }}-libyaml
+ ${{ env.MINGW_PACKAGE_PREFIX }}-libffi
- name: Set up env
id: setup-env
working-directory:
run: |
$msys2 = ${env:MSYS2_LOCATION}
- echo $msys2\usr\bin $msys2\ucrt64\bin |
+ $msystem = ${env:MSYSTEM}.ToLower()
+ echo $msys2\usr\bin $msys2\$msystem\bin |
Tee-Object ${env:GITHUB_PATH} -Append -Encoding utf-8
# Use the fast device for the temporary directory.
@@ -96,6 +117,7 @@ jobs:
shell: pwsh # cmd.exe does not strip spaces before `|`.
env:
MSYS2_LOCATION: ${{ steps.msys2.outputs.msys2-location }}
+ MSYSTEM: ${{ matrix.msystem }}
- name: Remove Strawberry Perl pkg-config
working-directory:
@@ -140,16 +162,17 @@ jobs:
I libssl-3-x64.dll
group Packages
- pacman -Qs mingw-w64-ucrt-x86_64-* | /bin/sed -n "s,local/mingw-w64-ucrt-x86_64-,,p"
+ pacman -Qs $MINGW_PACKAGE_PREFIX-* | /bin/sed -n "s,local/$MINGW_PACKAGE_PREFIX-,,p"
endgroup
[ ${#failed[@]} -eq 0 ]
shell: sh
- - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
+ - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
sparse-checkout-cone-mode: false
sparse-checkout: /.github
+ persist-credentials: false
- uses: ./.github/actions/setup/directories
with:
@@ -164,6 +187,8 @@ jobs:
../src/configure --disable-install-doc --prefix=/.
--build=$CHOST --host=$CHOST --target=$CHOST
shell: sh
+ env:
+ CHOST: ${{ env.MSYS2_ARCH }}-w64-mingw32
- name: make all
timeout-minutes: 30
@@ -185,7 +210,7 @@ jobs:
- name: test
timeout-minutes: 30
- run: make test
+ run: make test test-tool
env:
GNUMAKEFLAGS: ''
RUBY_TESTOPTS: '-v --tty=no'
diff --git a/.github/workflows/modgc.yml b/.github/workflows/modgc.yml
index 63c2d75d77..218127aad7 100644
--- a/.github/workflows/modgc.yml
+++ b/.github/workflows/modgc.yml
@@ -28,7 +28,7 @@ jobs:
- name: default
- name: mmtk
mmtk_build: release
- os: [macos-latest, ubuntu-latest]
+ os: [macos-26, ubuntu-latest]
include:
- test_task: check
fail-fast: false
@@ -44,14 +44,15 @@ jobs:
|| contains(github.event.head_commit.message, '[DOC]')
|| contains(github.event.pull_request.title, '[DOC]')
|| contains(github.event.pull_request.labels.*.name, 'Documentation')
- || (github.event_name == 'push' && github.event.pull_request.user.login == 'dependabot[bot]')
+ || (github.event.pull_request.user.login == 'dependabot[bot]')
)}}
steps:
- - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
+ - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
sparse-checkout-cone-mode: false
sparse-checkout: /.github
+ persist-credentials: false
- name: Install libraries (macOS)
uses: ./.github/actions/setup/macos
@@ -61,7 +62,7 @@ jobs:
uses: ./.github/actions/setup/ubuntu
if: ${{ contains(matrix.os, 'ubuntu') }}
- - uses: ruby/setup-ruby@a9bfc2ecf3dd40734a9418f89a7e9d484c32b990 # v1.248.0
+ - uses: ruby/setup-ruby@afeafc3d1ab54a631816aba4c914a0081c12ff2f # v1.310.0
with:
ruby-version: '3.1'
bundler: none
@@ -100,18 +101,20 @@ jobs:
- name: Run configure
env:
arch: ${{ matrix.arch }}
- run: >-
- $SETARCH ../src/configure -C --disable-install-doc --with-modular-gc=${{ env.MODULAR_GC_DIR }}
+ run: |
+ ${SETARCH} ../src/configure -C --disable-install-doc --with-modular-gc="${MODULAR_GC_DIR}" \
${arch:+--target=$arch-$OSTYPE --host=$arch-$OSTYPE}
- - uses: actions-rust-lang/setup-rust-toolchain@v1
+ - uses: actions-rust-lang/setup-rust-toolchain@46268bd060767258de96ed93c1251119784f2ab6 # v1.16.1
+ with:
+ cache-bin: false
- name: Set MMTk environment variables
run: |
echo 'EXCLUDES=../src/test/.excludes-mmtk' >> $GITHUB_ENV
echo 'MSPECOPT=-B../src/spec/mmtk.mspec' >> $GITHUB_ENV
if: ${{ matrix.gc.name == 'mmtk' }}
- - run: $SETARCH make
+ - run: ${SETARCH} make
- name: Build Modular GC
run: |
@@ -119,7 +122,7 @@ jobs:
make install-modular-gc MODULAR_GC=${{ matrix.gc.name }} MMTK_BUILD=${{ matrix.gc.mmtk_build }}
make distclean-modular-gc MODULAR_GC=${{ matrix.gc.name }}
- - run: $SETARCH make hello
+ - run: ${SETARCH} make hello
- name: Set test options for skipped tests
run: |
@@ -145,7 +148,7 @@ jobs:
test -n "${LAUNCHABLE_STDOUT}" && exec 1> >(tee "${LAUNCHABLE_STDOUT}")
test -n "${LAUNCHABLE_STDERR}" && exec 2> >(tee "${LAUNCHABLE_STDERR}")
- $SETARCH make -s ${{ matrix.test_task }} \
+ ${SETARCH} make -s ${{ matrix.test_task }} \
${TESTS:+TESTS="$TESTS"} \
${{ !contains(matrix.test_task, 'bundle') && 'RUBYOPT=-w' || '' }}
timeout-minutes: ${{ matrix.gc.timeout || 40 }}
@@ -158,7 +161,7 @@ jobs:
- name: make skipped tests
run: |
- $SETARCH make -s test-all TESTS="${TESTS//-n!\//-n/}"
+ ${SETARCH} make -s test-all TESTS="${TESTS//-n!\//-n/}"
env:
GNUMAKEFLAGS: ''
RUBY_TESTOPTS: '-v --tty=no'
diff --git a/.github/workflows/parse_y.yml b/.github/workflows/parse_y.yml
index 5acf6ae4cb..7c26e87e57 100644
--- a/.github/workflows/parse_y.yml
+++ b/.github/workflows/parse_y.yml
@@ -47,18 +47,19 @@ jobs:
|| contains(github.event.head_commit.message, '[DOC]')
|| contains(github.event.pull_request.title, '[DOC]')
|| contains(github.event.pull_request.labels.*.name, 'Documentation')
- || (github.event_name == 'push' && github.event.pull_request.user.login == 'dependabot[bot]')
+ || (github.event.pull_request.user.login == 'dependabot[bot]')
)}}
steps:
- - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
+ - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
sparse-checkout-cone-mode: false
sparse-checkout: /.github
+ persist-credentials: false
- uses: ./.github/actions/setup/ubuntu
- - uses: ruby/setup-ruby@a9bfc2ecf3dd40734a9418f89a7e9d484c32b990 # v1.248.0
+ - uses: ruby/setup-ruby@afeafc3d1ab54a631816aba4c914a0081c12ff2f # v1.310.0
with:
ruby-version: '3.1'
bundler: none
diff --git a/.github/workflows/post_push.yml b/.github/workflows/post_push.yml
new file mode 100644
index 0000000000..e351c8c286
--- /dev/null
+++ b/.github/workflows/post_push.yml
@@ -0,0 +1,97 @@
+name: Post-push
+on:
+ push:
+ branches:
+ - master
+ - 'ruby_*_*'
+
+permissions:
+ contents: read
+
+jobs:
+ hooks:
+ name: Post-push hooks
+ runs-on: ubuntu-latest
+ if: ${{ github.repository == 'ruby/ruby' }}
+ steps:
+ - name: Sync git.ruby-lang.org
+ id: sync-git
+ continue-on-error: true
+ run: |
+ mkdir -p ~/.ssh
+ (umask 066; printenv RUBY_GIT_SYNC_PRIVATE_KEY > ~/.ssh/id_ed25519)
+ ssh-keyscan -t ed25519 git.ruby-lang.org >> ~/.ssh/known_hosts
+ ssh -i ~/.ssh/id_ed25519 git-sync@git.ruby-lang.org "sudo -u git /home/git/git.ruby-lang.org/bin/update-ruby.sh $GITHUB_REF"
+ env:
+ GITHUB_REF: ${{ github.ref }}
+ RUBY_GIT_SYNC_PRIVATE_KEY: ${{ secrets.RUBY_GIT_SYNC_PRIVATE_KEY }}
+ if: ${{ github.ref == 'refs/heads/master' || startsWith(github.ref, 'refs/heads/ruby_') }}
+
+ - name: Fetch changesets on bugs.ruby-lang.org
+ run: |
+ curl "https://bugs.ruby-lang.org/sys/fetch_changesets?key=${REDMINE_SYS_API_KEY}" -s --fail-with-body -w '* status: %{http_code}\n'
+ env:
+ REDMINE_SYS_API_KEY: ${{ secrets.REDMINE_SYS_API_KEY }}
+ if: ${{ github.ref == 'refs/heads/master' || startsWith(github.ref, 'refs/heads/ruby_') }}
+
+ - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
+ with:
+ fetch-depth: 500 # for notify-slack-commits
+ token: ${{ secrets.MATZBOT_AUTO_UPDATE_TOKEN }}
+
+ - name: Notify commit to Slack
+ run: ruby tool/notify-slack-commits.rb "$GITHUB_OLD_SHA" "$GITHUB_NEW_SHA" refs/heads/master
+ env:
+ GITHUB_OLD_SHA: ${{ github.event.before }}
+ GITHUB_NEW_SHA: ${{ github.event.after }}
+ SLACK_WEBHOOK_URL_ALERTS: ${{ secrets.SLACK_WEBHOOK_URL_ALERTS }}
+ SLACK_WEBHOOK_URL_COMMITS: ${{ secrets.SLACK_WEBHOOK_URL_COMMITS }}
+ SLACK_WEBHOOK_URL_RUBY_JP: ${{ secrets.SLACK_WEBHOOK_URL_RUBY_JP }}
+ if: ${{ github.ref == 'refs/heads/master' }}
+
+ - name: Notify commit to ruby-cvs
+ run: |
+ SENDMAIL="ssh -i ${HOME}/.ssh/id_ed25519 git-sync@git.ruby-lang.org /usr/sbin/sendmail" \
+ ruby tool/commit-email.rb . ruby-cvs@g.ruby-lang.org \
+ "$GITHUB_OLD_SHA" "$GITHUB_NEW_SHA" "$GITHUB_REF" \
+ --viewer-uri "https://github.com/ruby/ruby/commit/" \
+ --error-to cvs-admin@ruby-lang.org
+ env:
+ GITHUB_OLD_SHA: ${{ github.event.before }}
+ GITHUB_NEW_SHA: ${{ github.event.after }}
+ GITHUB_REF: ${{ github.ref }}
+ if: ${{ github.ref == 'refs/heads/master' || startsWith(github.ref, 'refs/heads/ruby_') }}
+
+ - name: Auto-correct code styles
+ run: |
+ set -x
+ ruby tool/auto-style.rb "$GITHUB_OLD_SHA" "$GITHUB_NEW_SHA" refs/heads/master
+ env:
+ GITHUB_OLD_SHA: ${{ github.event.before }}
+ GITHUB_NEW_SHA: ${{ github.event.after }}
+ GIT_AUTHOR_NAME: git
+ GIT_COMMITTER_NAME: git
+ EMAIL: svn-admin@ruby-lang.org
+ if: ${{ github.ref == 'refs/heads/master' }}
+
+ - name: Push PR notes to GitHub
+ id: pr-notes
+ continue-on-error: true
+ run: ruby tool/notes-github-pr.rb "$(pwd)/.git" "$GITHUB_OLD_SHA" "$GITHUB_NEW_SHA" refs/heads/master
+ env:
+ GITHUB_OLD_SHA: ${{ github.event.before }}
+ GITHUB_NEW_SHA: ${{ github.event.after }}
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ GIT_AUTHOR_NAME: git
+ GIT_COMMITTER_NAME: git
+ EMAIL: svn-admin@ruby-lang.org
+ if: ${{ github.ref == 'refs/heads/master' }}
+
+ - name: Check for failures
+ run: exit 1
+ if: ${{ steps.sync-git.outcome == 'failure' || steps.pr-notes.outcome == 'failure' }}
+
+ - 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/pr-playground.yml b/.github/workflows/pr-playground.yml
index cc06006142..dc4f075a38 100644
--- a/.github/workflows/pr-playground.yml
+++ b/.github/workflows/pr-playground.yml
@@ -6,6 +6,10 @@ on:
workflows: ["WebAssembly"]
types: [completed]
+permissions:
+ contents: read
+ actions: read
+
jobs:
post-summary:
name: Post Playground link
@@ -25,7 +29,7 @@ jobs:
&& github.event.workflow_run.event == 'pull_request')
}}
steps:
- - uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
+ - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml
index 5d4474d978..5d4a31d287 100644
--- a/.github/workflows/publish.yml
+++ b/.github/workflows/publish.yml
@@ -1,18 +1,114 @@
-name: Start release workflow
+name: Publish Ruby packages
+
on:
- push:
- tags:
- - '*'
+ repository_dispatch:
+ types:
+ - release
+ workflow_dispatch:
+ inputs:
+ version:
+ description: 'Version of the Ruby package to release'
+ required: true
+ default: '4.0.0'
+
+permissions:
+ contents: read
jobs:
- notify:
+ release:
runs-on: ubuntu-latest
steps:
- - name: Build release package
+ - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
+ with:
+ persist-credentials: false
+
+ - uses: ruby/setup-ruby@afeafc3d1ab54a631816aba4c914a0081c12ff2f # v1.310.0
+ with:
+ ruby-version: 3.3.4
+
+ - name: Store Ruby version
+ env:
+ RUBY_VERSION: ${{ github.event.client_payload.version || github.event.inputs.version }}
+ run: |
+ echo "RUBY_VERSION=${RUBY_VERSION}" >> $GITHUB_ENV
+
+ - name: Store ABI version
+ run: echo "ABI_VERSION=$(echo ${RUBY_VERSION} | cut -d '.' -f 1-2)" >> $GITHUB_ENV
+
+ - name: Copy draft package `/tmp` to `/pub` directory
+ run: tool/release.sh ${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/${ABI_VERSION}/ruby-${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/${ABI_VERSION}/ruby-${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/${ABI_VERSION}/ruby-${RUBY_VERSION}.zip
+
+ - name: Create a release on GitHub
+ run: |
+ RELEASE_TAG=$(ruby tool/ruby-version.rb tag "${RUBY_VERSION}")
+ echo $RELEASE_TAG
+ PREVIOUS_RELEASE_TAG=$(ruby tool/ruby-version.rb previous-tag "${RUBY_VERSION}")
+ echo $PREVIOUS_RELEASE_TAG
+ tool/gen-github-release.rb $PREVIOUS_RELEASE_TAG $RELEASE_TAG --no-dry-run
+ env:
+ GITHUB_TOKEN: ${{ secrets.MATZBOT_AUTO_UPDATE_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": "${{ github.ref }}"}'
+ -d '{"event_type": "update_index"}'
+
+ - 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\": \"${RUBY_VERSION}\"}}"
+
+ - 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\": \"${RUBY_VERSION}\"}}"
+
+ - name: Store the latest LTS version of OpenSSL
+ run: |
+ echo "OPENSSL_VERSION=`curl -s https://api.github.com/repos/openssl/openssl/releases | jq -r '.[].tag_name | select(startswith("openssl-3.0"))' | sort -Vr | head -n1 | cut -d'-' -f2`" >> $GITHUB_ENV
+
+ - 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\": \"${RUBY_VERSION}\", \"openssl_version\": \"${OPENSSL_VERSION}\"}}"
+
+ - 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/release.yml b/.github/workflows/release.yml
index 284e336a29..a35bcff99a 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -1,107 +1,21 @@
-name: Publish Ruby packages
-
+name: Start release workflow
on:
- repository_dispatch:
- types:
- - release
- workflow_dispatch:
- inputs:
- version:
- description: 'Version of the Ruby package to release'
- required: true
- default: '3.3.4'
+ push:
+ tags:
+ - '*'
+
+permissions:
+ contents: read
jobs:
- release:
+ notify:
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_AUTO_UPDATE_TOKEN }}
-
- - name: Update versions index
+ - name: Build release package
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: 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 }}"}}'
-
- - 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: Store the latest LTS version of OpenSSL
- run: |
- echo "OPENSSL_VERSION=`curl -s https://api.github.com/repos/openssl/openssl/releases | jq -r '.[].tag_name | select(startswith("openssl-3.0"))' | sort -Vr | head -n1 | cut -d'-' -f2`" >> $GITHUB_ENV
-
- - 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": "${{ env.OPENSSL_VERSION }}"}}'
-
- - 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"}'
+ -d "{\"event_type\": \"$GITHUB_REF\"}"
diff --git a/.github/workflows/rust-warnings.yml b/.github/workflows/rust-warnings.yml
index 8fd78ea04b..7ea7d0c950 100644
--- a/.github/workflows/rust-warnings.yml
+++ b/.github/workflows/rust-warnings.yml
@@ -21,7 +21,7 @@ permissions:
contents: read
jobs:
- make:
+ rust-warnings:
env:
GITPULLOPTIONS: --no-tags origin ${{ github.ref }}
@@ -32,11 +32,13 @@ jobs:
|| contains(github.event.head_commit.message, '[DOC]')
|| contains(github.event.pull_request.title, '[DOC]')
|| contains(github.event.pull_request.labels.*.name, 'Documentation')
- || (github.event_name == 'push' && github.event.pull_request.user.login == 'dependabot[bot]')
+ || (github.event.pull_request.user.login == 'dependabot[bot]' && !startsWith(github.head_ref, 'dependabot/cargo'))
)}}
steps:
- - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
+ - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
+ with:
+ persist-credentials: false
- name: Install Rust
run: rustup default beta
@@ -46,6 +48,15 @@ jobs:
run: |
set -eu
cargo check --quiet --all-features --message-format=json \
- | jq -r 'select(.message.level == "warning" or .message.level == "error") | .message.rendered' \
+ | jq -r 'select(.message.level | IN("warning", "error")) | .message.rendered' \
+ | tee messages.txt
+ (exit "${PIPESTATUS[0]}") && ! grep --quiet '[^[:space:]]' messages.txt
+
+ - name: "📜 `rustdoc` warnings"
+ shell: bash
+ run: |
+ set -eu
+ cargo doc --document-private-items --all --no-deps --message-format=json \
+ | jq -r 'select(.message.level | IN("warning", "error")) | .message.rendered' \
| tee messages.txt
(exit "${PIPESTATUS[0]}") && ! grep --quiet '[^[:space:]]' messages.txt
diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml
index 8cc7e00c47..6dc4a7c6ad 100644
--- a/.github/workflows/scorecards.yml
+++ b/.github/workflows/scorecards.yml
@@ -34,12 +34,12 @@ jobs:
steps:
- name: "Checkout code"
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
+ uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
persist-credentials: false
- name: "Run analysis"
- uses: ossf/scorecard-action@05b42c624433fc40578a4040d5cf5e36ddca8cde # v2.4.2
+ uses: ossf/scorecard-action@4eaacf0543bb3f2c246792bd56e8cdeffafb205a # v2.4.3
with:
results_file: results.sarif
results_format: sarif
@@ -64,7 +64,7 @@ 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@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
+ uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: SARIF file
path: results.sarif
@@ -73,6 +73,6 @@ jobs:
# Upload the results to GitHub's code scanning dashboard (optional).
# Commenting out will disable upload of results to your repo's Code Scanning dashboard
- name: "Upload to code-scanning"
- uses: github/codeql-action/upload-sarif@v3
+ uses: github/codeql-action/upload-sarif@8aad20d150bbac5944a9f9d289da16a4b0d87c1e # v4.36.2
with:
sarif_file: results.sarif
diff --git a/.github/workflows/spec_guards.yml b/.github/workflows/spec_guards.yml
index e952053891..39714b13a4 100644
--- a/.github/workflows/spec_guards.yml
+++ b/.github/workflows/spec_guards.yml
@@ -31,7 +31,7 @@ jobs:
|| contains(github.event.head_commit.message, '[DOC]')
|| contains(github.event.pull_request.title, '[DOC]')
|| contains(github.event.pull_request.labels.*.name, 'Documentation')
- || (github.event_name == 'push' && github.event.pull_request.user.login == 'dependabot[bot]')
+ || (github.event.pull_request.user.login == 'dependabot[bot]')
)}}
strategy:
@@ -39,14 +39,17 @@ 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.2
- ruby-3.3
- ruby-3.4
+ - ruby-4.0
+ fail-fast: false
steps:
- - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
+ - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
+ with:
+ persist-credentials: false
- - uses: ruby/setup-ruby@a9bfc2ecf3dd40734a9418f89a7e9d484c32b990 # v1.248.0
+ - uses: ruby/setup-ruby@afeafc3d1ab54a631816aba4c914a0081c12ff2f # v1.310.0
with:
ruby-version: ${{ matrix.ruby }}
bundler: none
diff --git a/.github/workflows/sync_default_gems.yml b/.github/workflows/sync_default_gems.yml
new file mode 100644
index 0000000000..3aaae5864f
--- /dev/null
+++ b/.github/workflows/sync_default_gems.yml
@@ -0,0 +1,80 @@
+name: Sync default gems
+
+env:
+ DEFAULT_GEM_SYNC_ENABLED: true
+
+on:
+ workflow_dispatch:
+ inputs:
+ gem:
+ required: true
+ description: 'Name of the gem to be synchronized'
+ type: string
+ before:
+ required: true
+ description: 'Gem commit SHA before sync'
+ type: string
+ after:
+ required: true
+ description: 'Gem commit SHA after sync'
+ type: string
+
+permissions:
+ contents: read
+
+jobs:
+ sync_default_gems:
+ name: Sync default gem ${{ github.event.inputs.gem }}
+
+ permissions:
+ contents: write # for Git to git push
+
+ runs-on: ubuntu-latest
+
+ if: ${{ github.repository == 'ruby/ruby' }}
+
+ steps:
+ - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
+ name: Check out ruby/ruby
+ with:
+ token: ${{ github.repository == 'ruby/ruby' && secrets.MATZBOT_AUTO_UPDATE_TOKEN || secrets.GITHUB_TOKEN }}
+
+ - uses: ruby/setup-ruby@afeafc3d1ab54a631816aba4c914a0081c12ff2f # v1.310.0
+ with:
+ ruby-version: '3.4'
+ bundler: none
+
+ - name: Run tool/sync_default_gems.rb
+ id: sync
+ run: |
+ ruby_before=$(git rev-parse HEAD)
+ set -x
+ ruby tool/sync_default_gems.rb "${gem_name}" "${gem_before}..${gem_after}"
+ if [[ "$(git rev-parse HEAD)" != "$ruby_before" ]]; then
+ echo update=true >> $GITHUB_OUTPUT
+ fi
+ env:
+ gem_name: ${{ github.event.inputs.gem }}
+ gem_before: ${{ github.event.inputs.before }}
+ gem_after: ${{ github.event.inputs.after }}
+ EMAIL: svn-admin@ruby-lang.org
+ GIT_AUTHOR_NAME: git
+ GIT_COMMITTER_NAME: git
+
+ - name: Push
+ run: |
+ git pull --rebase origin ${GITHUB_REF#refs/heads/}
+ git push origin ${GITHUB_REF#refs/heads/}
+ if: ${{ steps.sync.outputs.update && env.DEFAULT_GEM_SYNC_ENABLED == 'true' }}
+ env:
+ EMAIL: svn-admin@ruby-lang.org
+ GIT_AUTHOR_NAME: git
+ GIT_COMMITTER_NAME: git
+
+ - uses: ./.github/actions/slack
+ with:
+ SLACK_WEBHOOK_URL: ${{ secrets.SIMPLER_ALERTS_URL }} # ruby-lang slack: ruby/simpler-alerts-bot
+ label: "${{ github.event.inputs.gem }} (<https://github.com/${{ github.event.inputs.gem == 'rubygems' && 'rubygems' || 'ruby' }}/${{ github.event.inputs.gem }}/compare/${{ github.event.inputs.before }}...${{ github.event.inputs.after }}|diff>)"
+ event_name: workflow_dispatch
+ extra_channel_id: C05FPKAU743 # alerts-sync
+ if: ${{ failure() }}
diff --git a/.github/workflows/tarball-macos.yml b/.github/workflows/tarball-macos.yml
new file mode 100644
index 0000000000..0d02cf6ae1
--- /dev/null
+++ b/.github/workflows/tarball-macos.yml
@@ -0,0 +1,101 @@
+name: tarball-macos (reusable)
+
+on:
+ workflow_call:
+ inputs:
+ archname:
+ description: 'archname (e.g. snapshot-master, snapshot-ruby_3_3)'
+ required: true
+ type: string
+ notify-release-channel:
+ description: 'Also send failure notifications to SNAPSHOT_SLACK_WEBHOOK_URL (schedule/release builds).'
+ required: false
+ type: boolean
+ default: false
+ secrets:
+ SIMPLER_ALERTS_URL:
+ required: false
+ SNAPSHOT_SLACK_WEBHOOK_URL:
+ required: false
+
+permissions:
+ contents: read
+
+jobs:
+ macos:
+ strategy:
+ matrix:
+ test_task: [check, test-bundled-gems, test-bundler-parallel]
+ os: [macos-26, macos-15, macos-14]
+ include:
+ - os: macos-15-intel
+ test_task: check
+ fail-fast: false
+ runs-on: ${{ matrix.os }}
+ env:
+ ARCHNAME: ${{ inputs.archname }}
+ steps:
+ - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
+ with:
+ name: Packages
+ path: pkg
+ - name: Extract
+ run: tar xf pkg/*.tar.xz
+ - name: Install libraries
+ run: |
+ with_retry () {
+ "$@" || { sleep 5 && "$@"; } || { sleep 60 && "$@"; }
+ }
+ set -x
+ with_retry brew install gmp libffi openssl zlib autoconf automake libtool libyaml
+ - name: Set ENV
+ run: |
+ echo "JOBS=-j$((1 + $(sysctl -n hw.activecpu)))" >> $GITHUB_ENV
+ - name: configure
+ run: cd "$ARCHNAME/" && ./configure --with-openssl-dir=$(brew --prefix openssl) --with-libyaml-dir=$(brew --prefix libyaml)
+ - name: make
+ run: cd "$ARCHNAME/" && make $JOBS
+ - name: Tests
+ run: cd "$ARCHNAME/" && make $JOBS -s ${{ matrix.test_task }}
+ env:
+ RUBY_TESTOPTS: "-q --tty=no"
+ RUBY_DEBUG_TEST_NO_REMOTE: "1"
+ # leaked-globals since 2.7
+ - name: Leaked Globals
+ run: cd "$ARCHNAME/" && make -s leaked-globals
+ if: matrix.test_task == 'check'
+ - name: make install without root privilege
+ run: cd "$ARCHNAME/" && make $JOBS install DESTDIR="/tmp/destdir"
+ if: matrix.test_task == 'check'
+ - name: make install
+ run: cd "$ARCHNAME/" && sudo make $JOBS install
+ if: matrix.test_task == 'check'
+ - name: Verify installed binaries
+ run: |
+ /usr/local/bin/ruby -v
+ /usr/local/bin/gem -v
+ /usr/local/bin/bundle -v
+ if: matrix.test_task == 'check'
+ - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
+ with:
+ sparse-checkout: .github/actions/slack
+ sparse-checkout-cone-mode: false
+ persist-credentials: false
+ if: ${{ failure() }}
+ - uses: ./.github/actions/slack
+ with:
+ label: "${{ matrix.os }} / ${{ matrix.test_task }}"
+ SLACK_WEBHOOK_URL: ${{ secrets.SIMPLER_ALERTS_URL }} # ruby-lang slack: ruby/simpler-alerts-bot
+ if: ${{ failure() }}
+ - uses: ruby/action-slack@d260b61aa817726d5bedd22dd6cc305787fa4cdd # v4.0.0
+ with:
+ payload: |
+ {
+ "attachments": [{
+ "text": "${{ job.status }}: ${{ matrix.os }} / ${{ matrix.test_task }} <https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}|${{ inputs.archname }}>",
+ "color": "danger"
+ }]
+ }
+ env:
+ SLACK_WEBHOOK_URL: ${{ secrets.SNAPSHOT_SLACK_WEBHOOK_URL }}
+ if: failure() && inputs.notify-release-channel
diff --git a/.github/workflows/tarball-non-development.yml b/.github/workflows/tarball-non-development.yml
new file mode 100644
index 0000000000..db6230b301
--- /dev/null
+++ b/.github/workflows/tarball-non-development.yml
@@ -0,0 +1,87 @@
+name: tarball-non-development (reusable)
+
+on:
+ workflow_call: {}
+
+permissions:
+ contents: read
+
+jobs:
+ non_development:
+ strategy:
+ fail-fast: false
+ matrix:
+ include:
+ - { variant: default, remove_ruby: false, configure_extra: '' }
+ - { variant: no-ruby, remove_ruby: true, configure_extra: '' }
+ - { variant: baseruby-no, remove_ruby: false, configure_extra: '--with-baseruby=no' }
+ runs-on: ubuntu-24.04
+ env:
+ ruby_prefix: /tmp/ruby-snapshot
+ steps:
+ - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
+ with:
+ name: Packages
+ path: pkg
+ - name: Extract
+ run: tar xf pkg/*.tar.xz
+ - name: Substitute patchlevel
+ run: |
+ set -x
+ cd snapshot-*/
+ sed -i.orig 's/^\( *# *define *RUBY_PATCHLEVEL\) *-.*/\1 0/' version.h
+ diff -u version.h.orig version.h || :
+ rm -f version.h.orig
+ - 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 zlib1g-dev libffi-dev libgmp-dev bison- autoconf-
+ - name: Remove host ruby
+ if: matrix.remove_ruby
+ run: |
+ set -x
+ sudo apt-get purge -y -q 'ruby*' || :
+ sudo rm -rf /opt/hostedtoolcache/Ruby
+ ! command -v ruby
+ - name: Set ENV
+ run: |
+ echo "JOBS=-j$((1 + $(nproc --all)))" >> $GITHUB_ENV
+ - name: configure
+ run: cd snapshot-*/ && ./configure --prefix="${ruby_prefix}" ${{ matrix.configure_extra }}
+ - name: make
+ run: cd snapshot-*/ && make $JOBS
+ - name: Leaked Globals
+ run: cd snapshot-*/ && make -s leaked-globals
+ - name: make install
+ run: cd snapshot-*/ && make $JOBS install
+ - name: Set PATH
+ run: echo "PATH=${ruby_prefix}/bin:$PATH" >> $GITHUB_ENV
+ - name: Check patchlevel
+ id: check-patchlevel
+ run: |
+ exec "${ruby_prefix}/bin/ruby" -vx "$0"
+ #!ruby
+ puts "RUBY_PATCHLEVEL=#{RUBY_PATCHLEVEL.inspect}"
+ abort unless RUBY_PATCHLEVEL >= 0
+ working-directory: ${{ env.ruby_prefix }}
+ continue-on-error: true
+ - name: Check LOADPATH
+ id: check-loadpath
+ run: |
+ exec ${ruby_prefix}/bin/ruby -vx "$0"
+ #!ruby
+ paths = $:.grep(/\+/)
+ pp paths
+ abort unless paths.empty?
+ working-directory: ${{ env.ruby_prefix }}
+ continue-on-error: true
+ - name: Check pathnames
+ id: check-pathnames
+ run: |
+ ! find -name '*+*' | grep +
+ working-directory: ${{ env.ruby_prefix }}
+ continue-on-error: true
+ - name: result
+ run: false
+ if: ${{ contains(steps.*.outcome, 'failure') }}
diff --git a/.github/workflows/tarball-test-schedule.yml b/.github/workflows/tarball-test-schedule.yml
new file mode 100644
index 0000000000..6684b09edb
--- /dev/null
+++ b/.github/workflows/tarball-test-schedule.yml
@@ -0,0 +1,26 @@
+name: tarball-test-schedule
+on:
+ schedule:
+ - cron: '30 18 * * *' # Daily at 18:30 UTC
+ workflow_dispatch:
+
+permissions: {}
+
+jobs:
+ dispatch:
+ if: ${{ github.event_name != 'schedule' || github.repository == 'ruby/ruby' }}
+ runs-on: ubuntu-latest
+ strategy:
+ fail-fast: false
+ matrix:
+ branch:
+ - master
+ - ruby_4_0
+ - ruby_3_4
+ - ruby_3_3
+ steps:
+ - name: Trigger tarball-test on ${{ matrix.branch }}
+ run: gh workflow run tarball-test.yml --ref "$BRANCH" --repo "$GITHUB_REPOSITORY" -f notify-release-channel=true
+ env:
+ BRANCH: ${{ matrix.branch }}
+ GH_TOKEN: ${{ secrets.MATZBOT_GITHUB_ACTION_TOKEN }}
diff --git a/.github/workflows/tarball-test.yml b/.github/workflows/tarball-test.yml
new file mode 100644
index 0000000000..f75d76761a
--- /dev/null
+++ b/.github/workflows/tarball-test.yml
@@ -0,0 +1,104 @@
+name: tarball-test
+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:
+ workflow_dispatch:
+ inputs:
+ notify-release-channel:
+ description: 'Also send failure notifications to SNAPSHOT_SLACK_WEBHOOK_URL (set by tarball-test-schedule).'
+ type: boolean
+ default: false
+
+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:
+ tarball:
+ runs-on: ubuntu-latest
+ # Cherry-pick to maintenance branches by changing only env.BRANCH below;
+ # archname / branch-label / Materialize all derive from it.
+ env:
+ BRANCH: master
+ outputs:
+ branch: ${{ env.BRANCH }}
+ skip: ${{ steps.skipping.outputs.skip }}
+ steps:
+ - id: skipping
+ run: echo 'skip=true' >> $GITHUB_OUTPUT
+ if: >-
+ ${{(false
+ || contains(github.event.head_commit.message, '[DOC]')
+ || contains(github.event.pull_request.title, '[DOC]')
+ || contains(github.event.pull_request.labels.*.name, 'Documentation')
+ || (github.event.pull_request.user.login == 'dependabot[bot]')
+ )}}
+ - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
+ with:
+ fetch-depth: 1 # actions/checkout fetches all heads/tags unless > 0
+ persist-credentials: false
+ # tool/make-snapshot derives the branch name from HEAD and looks up
+ # the upstream during ChangeLog generation. Detached checkouts
+ # (pull_request, merge_group) lack a local branch with tracking, so
+ # pin one to HEAD and connect it to the matching origin ref.
+ - name: Materialize local branch
+ run: |
+ git fetch --no-tags --depth=1 origin "+refs/heads/$BASE:refs/remotes/origin/$BASE"
+ git checkout -B "$BRANCH" HEAD
+ git branch --set-upstream-to="origin/$BASE" "$BRANCH"
+ env:
+ BASE: ${{ github.base_ref || env.BRANCH }}
+ - uses: ./.github/actions/make-snapshot
+ with:
+ archname: snapshot-${{ env.BRANCH }}
+ srcdir: '.'
+
+ ubuntu:
+ needs: tarball
+ if: ${{ ! needs.tarball.outputs.skip }}
+ uses: ./.github/workflows/tarball-ubuntu.yml
+ with:
+ archname: snapshot-${{ needs.tarball.outputs.branch }}
+ notify-release-channel: ${{ github.event_name == 'workflow_dispatch' && inputs.notify-release-channel || false }}
+ secrets:
+ SIMPLER_ALERTS_URL: ${{ secrets.SIMPLER_ALERTS_URL }}
+ SNAPSHOT_SLACK_WEBHOOK_URL: ${{ secrets.SNAPSHOT_SLACK_WEBHOOK_URL }}
+
+ macos:
+ needs: tarball
+ if: ${{ ! needs.tarball.outputs.skip }}
+ uses: ./.github/workflows/tarball-macos.yml
+ with:
+ archname: snapshot-${{ needs.tarball.outputs.branch }}
+ notify-release-channel: ${{ github.event_name == 'workflow_dispatch' && inputs.notify-release-channel || false }}
+ secrets:
+ SIMPLER_ALERTS_URL: ${{ secrets.SIMPLER_ALERTS_URL }}
+ SNAPSHOT_SLACK_WEBHOOK_URL: ${{ secrets.SNAPSHOT_SLACK_WEBHOOK_URL }}
+
+ windows:
+ needs: tarball
+ if: ${{ ! needs.tarball.outputs.skip }}
+ uses: ./.github/workflows/tarball-windows.yml
+ with:
+ archname: snapshot-${{ needs.tarball.outputs.branch }}
+ notify-release-channel: ${{ github.event_name == 'workflow_dispatch' && inputs.notify-release-channel || false }}
+ secrets:
+ SIMPLER_ALERTS_URL: ${{ secrets.SIMPLER_ALERTS_URL }}
+ SNAPSHOT_SLACK_WEBHOOK_URL: ${{ secrets.SNAPSHOT_SLACK_WEBHOOK_URL }}
+
+ non_development:
+ needs: tarball
+ uses: ./.github/workflows/tarball-non-development.yml
diff --git a/.github/workflows/tarball-ubuntu.yml b/.github/workflows/tarball-ubuntu.yml
new file mode 100644
index 0000000000..0482db3c7f
--- /dev/null
+++ b/.github/workflows/tarball-ubuntu.yml
@@ -0,0 +1,151 @@
+name: tarball-ubuntu (reusable)
+
+on:
+ workflow_call:
+ inputs:
+ archname:
+ description: 'archname (e.g. snapshot-master, snapshot-ruby_3_3)'
+ required: true
+ type: string
+ notify-release-channel:
+ description: 'Also send failure notifications to SNAPSHOT_SLACK_WEBHOOK_URL (schedule/release builds).'
+ required: false
+ type: boolean
+ default: false
+ secrets:
+ SIMPLER_ALERTS_URL:
+ required: false
+ SNAPSHOT_SLACK_WEBHOOK_URL:
+ required: false
+
+permissions:
+ contents: read
+
+jobs:
+ ubuntu:
+ strategy:
+ matrix:
+ test_task: [check, test-bundler-parallel, test-bundled-gems]
+ os: [ubuntu-24.04, ubuntu-22.04]
+ fail-fast: false
+ runs-on: ${{ matrix.os }}
+ env:
+ ARCHNAME: ${{ inputs.archname }}
+ steps:
+ - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
+ with:
+ name: Packages
+ path: pkg
+ - name: Extract
+ run: tar xf pkg/*.tar.xz
+ - 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 zlib1g-dev libffi-dev libgmp-dev bison- autoconf-
+ - uses: ruby/setup-ruby@afeafc3d1ab54a631816aba4c914a0081c12ff2f # v1.310.0
+ with:
+ ruby-version: '3.2'
+ # test-bundled-gems requires executable host ruby
+ if: matrix.test_task == 'test-bundled-gems'
+ - name: Fixed world writable dirs
+ run: |
+ mkdir -p $HOME/.local/share
+ mkdir -p $HOME/.cache/gem/specs
+ mkdir -p $HOME/.bundle/cache
+ mkdir -p $HOME/.ssh
+ chmod a-w $HOME/.bundle
+ # chmod a-w $HOME
+ # allow to write $HOME and check stats of HOME around tests (see below)
+ chmod -v a-w $HOME/.config
+ sudo chmod -R a-w /usr/share
+ sudo bash -c 'IFS=:; for d in '"$PATH"'; do chmod -v a-w $d; done' || :
+ - name: Set ENV
+ run: |
+ echo "JOBS=-j$((1 + $(nproc --all)))" >> $GITHUB_ENV
+ - name: configure
+ run: cd "$ARCHNAME/" && ./configure
+ - name: make
+ run: cd "$ARCHNAME/" && make $JOBS
+ - name: Save stats of HOME
+ run: |
+ set -euxo pipefail
+ cat >"$ARCHNAME/save-stats.rb" <<'EOF'
+ require 'pathname'
+ require 'digest'
+ out = []
+ [
+ Dir.home,
+ ].each do |dir|
+ Dir.each_child(dir) do |name|
+ pn = File.join(dir, name)
+ st = File.stat(pn)
+ if st.file?
+ content = Digest::SHA1.file(pn).hexdigest
+ elsif st.directory? && st.nlink <= 10
+ content = Dir.children(pn).sort
+ end
+ out << [pn, "%o"%st.mode, st.nlink, st.uid, st.gid, st.size, content].to_s
+ rescue
+ out << [pn, $!.inspect].to_s
+ end
+ end
+ File.open(ARGV.shift, "w") do |io|
+ io.puts out.sort
+ end
+ EOF
+ make -C "$ARCHNAME" TESTRUN_SCRIPT=save-stats.rb RUNOPT=/tmp/stat-before-tests.txt runruby
+ - name: Tests
+ run: cd "$ARCHNAME/" && make $JOBS -s ${{ matrix.test_task }}
+ env:
+ RUBY_TESTOPTS: "-q --tty=no"
+ # test_sync_default_gems triggers gpg, whose agent processes leave
+ # $HOME/.gnupg around even when GNUPGHOME points elsewhere.
+ - name: Forcibly remove ~/.gnupg
+ run: rm -rf $HOME/.gnupg
+ - name: Diff stats of HOME
+ run: |
+ make -C "$ARCHNAME" TESTRUN_SCRIPT=save-stats.rb RUNOPT=/tmp/stat-after-tests.txt runruby
+ rm -f "$ARCHNAME/save-stats.rb"
+ diff -u /tmp/stat-before-tests.txt /tmp/stat-after-tests.txt
+ # leaked-globals since 2.7
+ - name: Leaked Globals
+ run: cd "$ARCHNAME/" && make -s leaked-globals
+ if: matrix.test_task == 'check'
+ - name: make install without root privilege
+ run: cd "$ARCHNAME/" && make $JOBS install DESTDIR="/tmp/destdir"
+ if: matrix.test_task == 'check'
+ - name: make install
+ run: cd "$ARCHNAME/" && sudo make $JOBS install
+ if: matrix.test_task == 'check'
+ - name: Verify installed binaries
+ run: |
+ /usr/local/bin/ruby -v
+ /usr/local/bin/gem -v
+ /usr/local/bin/bundle -v
+ if: matrix.test_task == 'check'
+ - name: Show .local
+ run: find $HOME/.local -ls
+ - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
+ with:
+ sparse-checkout: .github/actions/slack
+ sparse-checkout-cone-mode: false
+ persist-credentials: false
+ if: ${{ failure() }}
+ - uses: ./.github/actions/slack
+ with:
+ label: "${{ matrix.os }} / ${{ matrix.test_task }}"
+ SLACK_WEBHOOK_URL: ${{ secrets.SIMPLER_ALERTS_URL }} # ruby-lang slack: ruby/simpler-alerts-bot
+ if: ${{ failure() }}
+ - uses: ruby/action-slack@d260b61aa817726d5bedd22dd6cc305787fa4cdd # v4.0.0
+ with:
+ payload: |
+ {
+ "attachments": [{
+ "text": "${{ job.status }}: ${{ matrix.os }} / ${{ matrix.test_task }} <https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}|${{ inputs.archname }}>",
+ "color": "danger"
+ }]
+ }
+ env:
+ SLACK_WEBHOOK_URL: ${{ secrets.SNAPSHOT_SLACK_WEBHOOK_URL }}
+ if: failure() && inputs.notify-release-channel
diff --git a/.github/workflows/tarball-windows.yml b/.github/workflows/tarball-windows.yml
new file mode 100644
index 0000000000..a66cdf729d
--- /dev/null
+++ b/.github/workflows/tarball-windows.yml
@@ -0,0 +1,163 @@
+name: tarball-windows (reusable)
+
+on:
+ workflow_call:
+ inputs:
+ archname:
+ description: 'archname (e.g. snapshot-master)'
+ required: true
+ type: string
+ notify-release-channel:
+ description: 'Also send failure notifications to SNAPSHOT_SLACK_WEBHOOK_URL (schedule/release builds).'
+ required: false
+ type: boolean
+ default: false
+ secrets:
+ SIMPLER_ALERTS_URL:
+ required: false
+ SNAPSHOT_SLACK_WEBHOOK_URL:
+ required: false
+
+permissions:
+ contents: read
+
+jobs:
+ windows:
+ strategy:
+ matrix:
+ include:
+ - os: '2022'
+ test_task: check
+ - os: '2025-vs2026'
+ test_task: check
+ fail-fast: false
+ runs-on: windows-${{ matrix.os }}
+ defaults:
+ run:
+ shell: cmd
+ working-directory: build
+ name: Windows ${{ matrix.os }} (${{ matrix.test_task }})
+ env:
+ GITPULLOPTIONS: --no-tags origin ${{github.ref}}
+ PATCH: C:\msys64\usr\bin\patch.exe
+ OS_VER: windows-${{ matrix.os }}
+ # see https://github.com/ruby/ruby/commit/9ff4399decef0036897d3cfb9ac2c710dea913ca
+ OPENSSL_MODULES: C:\vcpkg\installed\x64-windows\bin
+ steps:
+ - run: md build
+ working-directory:
+
+ - uses: ruby/setup-ruby@afeafc3d1ab54a631816aba4c914a0081c12ff2f # v1.310.0
+ with:
+ ruby-version: '3.2'
+ bundler: none
+ windows-toolchain: none
+
+ - uses: msys2/setup-msys2@e9898307ac31d1a803454791be09ab9973336e1c # v2.31.1
+ id: setup-msys2
+ with:
+ update: true
+ install: >-
+ 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@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
+ with:
+ path: C:\vcpkg\installed
+ key: ${{ runner.os }}-vcpkg-installed-${{ env.OS_VER }}-${{ github.sha }}
+ restore-keys: |
+ ${{ runner.os }}-vcpkg-installed-${{ env.OS_VER }}-
+ ${{ runner.os }}-vcpkg-installed-
+ - name: Install libraries with vcpkg
+ run: |
+ vcpkg --triplet x64-windows install gmp libffi libyaml openssl zlib
+
+ - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
+ with:
+ name: Packages
+ path: pkg
+ - name: Extract
+ run: 7z x pkg/*.zip
+ working-directory:
+
+ - uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
+ with:
+ path: snapshot-*/.downloaded-cache
+ key: downloaded-cache
+
+ - name: setup env
+ # %TEMP% is inconsistent with %TMP% and test-all expects they are consistent.
+ # https://github.com/actions/virtual-environments/issues/712#issuecomment-613004302
+ env:
+ ARCHNAME: ${{ inputs.archname }}
+ run: |
+ set > old.env
+ call ..\%ARCHNAME%\win32\vssetup.cmd
+ set TMP=%USERPROFILE%\AppData\Local\Temp
+ set TEMP=%USERPROFILE%\AppData\Local\Temp
+ set /a TEST_JOBS=(15 * %NUMBER_OF_PROCESSORS% / 10) > nul
+ set > new.env
+
+ - name: update env
+ shell: pwsh
+ run: |
+ $old = (Get-Content old.env); $new = (Get-Content new.env)
+ del *.env
+ Compare-Object $old $new |
+ Where-Object { $_.SideIndicator -eq '=>' } |
+ Select-Object -ExpandProperty InputObject |
+ Add-Content -Path $env:GITHUB_ENV
+ - name: link libraries
+ run: |
+ for %%I in (C:\vcpkg\installed\x64-windows\bin\*.dll) do (
+ mklink %%~nxI %%I
+ )
+ - name: Configure
+ env:
+ ARCHNAME: ${{ inputs.archname }}
+ run: >-
+ ../%ARCHNAME%/win32/configure.bat --disable-install-doc
+ --with-opt-dir=C:/vcpkg/installed/x64-windows
+ - run: nmake incs
+ - run: nmake extract-extlibs
+ - run: nmake
+ env:
+ YACC: win_bison
+
+ - name: ruby -v
+ run: .\ruby -v
+
+ - run: nmake test
+ timeout-minutes: 5
+
+ - run: nmake ${{ matrix.test_task }}
+ env:
+ RUBY_TESTOPTS: -j${{env.TEST_JOBS}}
+ timeout-minutes: 70
+ continue-on-error: ${{ matrix.continue-on-error || false }}
+
+ - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
+ with:
+ sparse-checkout: .github/actions/slack
+ sparse-checkout-cone-mode: false
+ persist-credentials: false
+ if: ${{ failure() }}
+ - uses: ./.github/actions/slack
+ with:
+ label: "${{ env.OS_VER }} / ${{ matrix.test_task }}"
+ SLACK_WEBHOOK_URL: ${{ secrets.SIMPLER_ALERTS_URL }} # ruby-lang slack: ruby/simpler-alerts-bot
+ if: ${{ failure() }}
+ - uses: ruby/action-slack@d260b61aa817726d5bedd22dd6cc305787fa4cdd # v4.0.0
+ with:
+ payload: |
+ {
+ "attachments": [{
+ "text": "${{ job.status }}: ${{ env.OS_VER }} / ${{ matrix.test_task }} <https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}|${{ inputs.archname }}>",
+ "color": "danger"
+ }]
+ }
+ env:
+ SLACK_WEBHOOK_URL: ${{ secrets.SNAPSHOT_SLACK_WEBHOOK_URL }}
+ if: failure() && inputs.notify-release-channel
diff --git a/.github/workflows/ubuntu.yml b/.github/workflows/ubuntu.yml
index 8955ea91d4..c887ae3811 100644
--- a/.github/workflows/ubuntu.yml
+++ b/.github/workflows/ubuntu.yml
@@ -24,22 +24,7 @@ jobs:
make:
strategy:
matrix:
- test_task: [check]
- configure: ['']
- arch: ['']
- os:
- - ubuntu-24.04
- - ubuntu-24.04-arm
- # FIXME Comment out ppc64le due to failing tests on GitHub Actions
- # ppc64le
- # https://bugs.ruby-lang.org/issues/21534
- # - ubuntu-24.04-ppc64le
- - ubuntu-24.04-s390x
- # The ppc64le/s390x runners work only in the registered repositories.
- # They don't work in forked repositories.
- # https://github.com/IBM/actionspz/blob/main/docs/FAQ.md#what-about-forked-repos
- upstream:
- - ${{ github.repository == 'ruby/ruby' }}
+ # We enumerate every job in matrix.include to save build time
include:
- test_task: check
configure: 'cppflags=-DVM_CHECK_MODE'
@@ -52,14 +37,15 @@ jobs:
- test_task: test-bundler-parallel
timeout: 50
- test_task: test-bundled-gems
- exclude:
- - os: ubuntu-24.04-ppc64le
- upstream: false
- - os: ubuntu-24.04-s390x
- upstream: false
+ - test_task: check
+ os: ubuntu-24.04
+ extra_checks: [capi]
+ # ubuntu-24.04-arm jobs don't start on ruby/ruby as of 2025-10-29
+ #- test_task: check
+ # os: ubuntu-24.04-arm
fail-fast: false
- env:
+ env: &make-env
GITPULLOPTIONS: --no-tags origin ${{ github.ref }}
RUBY_DEBUG: ci
@@ -70,42 +56,27 @@ jobs:
|| contains(github.event.head_commit.message, '[DOC]')
|| contains(github.event.pull_request.title, '[DOC]')
|| contains(github.event.pull_request.labels.*.name, 'Documentation')
- || (github.event_name == 'push' && github.event.pull_request.user.login == 'dependabot[bot]')
+ || (github.event.pull_request.user.login == 'dependabot[bot]')
)}}
- steps:
- - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
+ steps: &make-steps
+ - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
sparse-checkout-cone-mode: false
sparse-checkout: /.github
+ persist-credentials: false
- uses: ./.github/actions/setup/ubuntu
with:
arch: ${{ matrix.arch }}
- - uses: ruby/setup-ruby@a9bfc2ecf3dd40734a9418f89a7e9d484c32b990 # v1.248.0
+ - uses: ruby/setup-ruby@afeafc3d1ab54a631816aba4c914a0081c12ff2f # v1.310.0
with:
ruby-version: '3.1'
bundler: none
- if: ${{ !endsWith(matrix.os, 'arm') && !endsWith(matrix.os, 'ppc64le') && !endsWith(matrix.os, 's390x') }}
-
- # Avoid possible test failures with the zlib applying the following patch
- # on s390x CPU architecture.
- # https://github.com/madler/zlib/pull/410
- - name: Disable DFLTCC
- run: echo "DFLTCC=0" >> $GITHUB_ENV
- working-directory:
- if: ${{ endsWith(matrix.os, 's390x') }}
-
- # A temporary workaround: Set HOME env to pass the step
- # ./.github/actions/setup/directories.
- # https://github.com/IBM/actionspz/issues/30
- - name: Set HOME env
- run: |
- echo "HOME: #{HOME}"
- echo "HOME=$(ls -d ~)" >> $GITHUB_ENV
- working-directory:
- if: ${{ endsWith(matrix.os, 'ppc64le') || endsWith(matrix.os, 's390x') }}
+ if: >-
+ ${{ !endsWith(matrix.os, 'arm')
+ && !endsWith(matrix.os, 'ppc64le') && !endsWith(matrix.os, 's390x') }}
- uses: ./.github/actions/setup/directories
with:
@@ -122,7 +93,7 @@ jobs:
arch: ${{ matrix.arch }}
configure: ${{ matrix.configure }}
run: >-
- $SETARCH ../src/configure -C --disable-install-doc ${configure:-cppflags=-DRUBY_DEBUG}
+ $SETARCH ../src/configure -C --disable-install-doc ${configure:- --enable-debug-env cppflags=-DRUBY_DEBUG}
${arch:+--target=$arch-$OSTYPE --host=$arch-$OSTYPE}
- run: $SETARCH make prepare-gems
@@ -155,16 +126,12 @@ jobs:
continue-on-error: true
timeout-minutes: 3
- # A temporary workaround: Skip user ground id test
- # There is a mismatch between the group IDs of "id -g" and C function
- # getpwuid(uid_t uid) pw_gid.
- # https://github.com/IBM/actionspz/issues/31
- - name: Skip user group id test
- run: |
- sed -i.orig '/^ it "returns user group id" do/a\ skip' \
- ../src/spec/ruby/library/etc/struct_passwd_spec.rb
- diff -u ../src/spec/ruby/library/etc/struct_passwd_spec.rb{.orig,} || :
- if: ${{ endsWith(matrix.os, 'ppc64le') || endsWith(matrix.os, 's390x') }}
+ # Avoid possible test failures with the zlib applying the following patch
+ # on s390x CPU architecture.
+ # https://github.com/madler/zlib/pull/410
+ - name: Disable DFLTCC
+ run: echo "DFLTCC=0" >> $GITHUB_ENV
+ if: ${{ endsWith(matrix.os, 's390x') }}
- name: make ${{ matrix.test_task }}
run: |
@@ -196,9 +163,100 @@ jobs:
DESTDIR=${RUNNER_TEMP-${TMPDIR-/tmp}}/installed
$SETARCH make test-pc "DESTDIR=$DESTDIR"
+ - name: CAPI extensions
+ uses: ./.github/actions/capiext
+ with:
+ builddir: build
+ make: '$SETARCH make'
+ env:
+ RUBY_TESTOPTS: '-v --tty=no'
+ if: ${{ contains(matrix.extra_checks, 'capi') }}
+
+ - uses: ./.github/actions/slack
+ with:
+ label: ${{ matrix.test_task }} ${{ matrix.configure }}${{ matrix.arch }}${{ matrix.os }}
+ SLACK_WEBHOOK_URL: ${{ secrets.SIMPLER_ALERTS_URL }} # ruby-lang slack: ruby/simpler-alerts-bot
+ if: ${{ failure() }}
+
+ make-ibm:
+ strategy:
+ matrix:
+ include:
+ - test_task: check
+ os: ubuntu-24.04-ppc64le
+ - test_task: check
+ os: ubuntu-24.04-s390x
+ fail-fast: false
+
+ env: *make-env
+
+ runs-on: ${{ matrix.os }}
+
+ if: >-
+ ${{github.repository == 'ruby/ruby'
+ && !(false
+ || contains(github.event.head_commit.message, '[DOC]')
+ || contains(github.event.pull_request.title, '[DOC]')
+ || contains(github.event.pull_request.labels.*.name, 'Documentation')
+ || (github.event.pull_request.user.login == 'dependabot[bot]')
+ )}}
+
+ steps: *make-steps
+
+ # Separated from `make` job to avoid making it a required status check
+ ruby-bench:
+ strategy:
+ matrix:
+ include:
+ # Using the same setup as ZJIT jobs
+ - bench_opts: '--warmup=1 --bench=1 --excludes=shipit'
+
+ runs-on: ubuntu-24.04
+
+ if: >-
+ ${{!(false
+ || contains(github.event.head_commit.message, '[DOC]')
+ || contains(github.event.pull_request.title, '[DOC]')
+ || contains(github.event.pull_request.labels.*.name, 'Documentation')
+ || (github.event.pull_request.user.login == 'dependabot[bot]')
+ )}}
+
+ steps:
+ - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
+ with:
+ persist-credentials: false
+
+ - 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"
+
+ - run: make install
+
+ - name: Checkout ruby-bench
+ uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
+ with:
+ repository: ruby/ruby-bench
+ persist-credentials: false
+ path: ruby-bench
+
+ # If you want to skip failing benchmark, consider using `--excludes`.
+ # e.g. `bench_opts: '--warmup=1 --bench=1 --excludes=railsbench,lobsters'`
+ - name: Run ruby-bench
+ run: ruby run_benchmarks.rb -e "ruby::../build/install/bin/ruby" ${{ matrix.bench_opts }}
+ working-directory: ruby-bench
+ env:
+ BUNDLER_VERSION: 0
+
- uses: ./.github/actions/slack
with:
- label: ${{ matrix.test_task }} ${{ matrix.configure }}${{ matrix.arch }}
+ label: ruby-bench ${{ matrix.bench_opts }} ${{ matrix.ruby_opts }}
SLACK_WEBHOOK_URL: ${{ secrets.SIMPLER_ALERTS_URL }} # ruby-lang slack: ruby/simpler-alerts-bot
if: ${{ failure() }}
diff --git a/.github/workflows/wasm.yml b/.github/workflows/wasm.yml
index 1d1e4bc5a2..f0263de5ef 100644
--- a/.github/workflows/wasm.yml
+++ b/.github/workflows/wasm.yml
@@ -55,14 +55,20 @@ jobs:
|| contains(github.event.head_commit.message, '[DOC]')
|| contains(github.event.pull_request.title, '[DOC]')
|| contains(github.event.pull_request.labels.*.name, 'Documentation')
- || (github.event_name == 'push' && github.event.pull_request.user.login == 'dependabot[bot]')
+ || (github.event.pull_request.user.login == 'dependabot[bot]')
)}}
steps:
- - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
+ - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
sparse-checkout-cone-mode: false
sparse-checkout: /.github
+ persist-credentials: false
+
+ - uses: ruby/setup-ruby@afeafc3d1ab54a631816aba4c914a0081c12ff2f # v1.310.0
+ with:
+ ruby-version: '3.1'
+ bundler: none
- uses: ./.github/actions/setup/directories
with:
@@ -98,19 +104,10 @@ jobs:
run: |
echo "WASI_SDK_PATH=/opt/wasi-sdk" >> $GITHUB_ENV
- - uses: ruby/setup-ruby@a9bfc2ecf3dd40734a9418f89a7e9d484c32b990 # v1.248.0
+ - uses: ./.github/actions/setup/baseruby
+ id: baseruby
with:
- ruby-version: '3.1'
- bundler: none
-
- - name: Build baseruby
- run: |
- set -ex
- mkdir ../baseruby
- pushd ../baseruby
- ../src/configure --prefix=$PWD/install
- make
- make install
+ srcdir: src
- name: Download config.guess with wasi version
run: |
@@ -119,19 +116,38 @@ jobs:
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 \
- " \
- optflags="${{ matrix.entry.optflags }}" \
- debugflags="${{ matrix.entry.debugflags }}" \
- wasmoptflags="${{ matrix.entry.wasmoptflags }} ${{ matrix.entry.debugflags }}"
+ run: >-
+ ../src/configure
+ --host wasm32-unknown-wasi
+ --with-baseruby="${{ steps.baseruby.outputs.ruby }}"
+ --with-dump-ast="${{ steps.baseruby.outputs.dump_ast }}"
+ --with-static-linked-ext
+ --with-ext=${EXTS// /,}
+ LDFLAGS="
+ -Xlinker --stack-first
+ -Xlinker -z -Xlinker stack-size=16777216
+ "
+ optflags="${{ matrix.entry.optflags }}"
+ debugflags="${{ matrix.entry.debugflags }}"
+ wasmoptflags="${{ matrix.entry.wasmoptflags }} ${{ matrix.entry.debugflags }}"
+ env:
+ EXTS:
+ cgi/escape
+ continuation
+ coverage
+ date
+ digest
+ digest/*
+ erb/escape
+ etc
+ fcntl
+ json
+ json/*
+ objspace
+ rbconfig/sizeof
+ ripper
+ stringio
+ strscan
# miniruby may not be built when cross-compling
- run: make mini ruby
@@ -140,7 +156,7 @@ jobs:
- run: tar cfz ../install.tar.gz -C ../install .
- name: Upload artifacts
- uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
+ uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: ruby-wasm-install
path: ${{ github.workspace }}/install.tar.gz
@@ -168,7 +184,7 @@ jobs:
- 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@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
+ - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
if: ${{ github.event_name == 'pull_request' }}
with:
name: github-pr-info
diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml
index 3e85f7a1c5..03e75ad445 100644
--- a/.github/workflows/windows.yml
+++ b/.github/workflows/windows.yml
@@ -26,17 +26,16 @@ jobs:
matrix:
include:
- os: 2022
- vc: 2022
test_task: check
- - os: 2025
- vc: 2022
+ - os: 2022
+ test_task: test-bundled-gems
+ - os: 2025-vs2026
test_task: check
+ - os: 2025-vs2026
+ test_task: test-bundled-gems
- os: 11-arm
test_task: 'btest test-basic test-tool' # check and test-spec are broken yet.
target: arm64
- - os: 2025
- vc: 2022
- test_task: test-bundled-gems
fail-fast: false
runs-on: windows-${{ matrix.os }}
@@ -46,10 +45,10 @@ jobs:
|| contains(github.event.head_commit.message, '[DOC]')
|| contains(github.event.pull_request.title, '[DOC]')
|| contains(github.event.pull_request.labels.*.name, 'Documentation')
- || (github.event_name == 'push' && github.event.pull_request.user.login == 'dependabot[bot]')
+ || (github.event.pull_request.user.login == 'dependabot[bot]' && !startsWith(github.head_ref, 'dependabot/vcpkg'))
)}}
- name: Windows ${{ matrix.os }}/Visual C++ ${{ matrix.vc }} (${{ matrix.test_task }})
+ name: Windows ${{ matrix.os }} (${{ matrix.test_task }})
env:
GITPULLOPTIONS: --no-tags origin ${{ github.ref }}
@@ -59,15 +58,16 @@ jobs:
- run: md build
working-directory:
- - uses: ruby/setup-ruby@a9bfc2ecf3dd40734a9418f89a7e9d484c32b990 # v1.248.0
+ - uses: ruby/setup-ruby@afeafc3d1ab54a631816aba4c914a0081c12ff2f # v1.310.0
with:
# windows-11-arm has only 3.4.1, 3.4.2, 3.4.3, head
ruby-version: ${{ !endsWith(matrix.os, 'arm') && '3.1' || '3.4' }}
bundler: none
windows-toolchain: none
- - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
+ - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
+ persist-credentials: false
sparse-checkout-cone-mode: false
sparse-checkout: /.github
@@ -75,42 +75,52 @@ jobs:
with:
srcdir: src
builddir: build
+ make-command: nmake
+ clean: true
- name: Install tools with scoop
run: |
+ if ((vcpkg.exe help install) -match "manifest") { exit }
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
iwr -useb get.scoop.sh | iex
Join-Path (Resolve-Path ~).Path "scoop\shims" >> $Env:GITHUB_PATH
- scoop install vcpkg uutils-coreutils cmake@3.31.6
+ scoop install vcpkg
shell: pwsh
- name: Restore vcpkg artifact
id: restore-vcpkg
- uses: actions/cache/restore@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4
+ uses: actions/cache/restore@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
with:
path: src\vcpkg_installed
key: windows-${{ matrix.os }}-vcpkg-${{ hashFiles('src/vcpkg.json') }}
- name: Install libraries with vcpkg
+ id: build-vcpkg
run: |
- vcpkg install --vcpkg-root=%USERPROFILE%\scoop\apps\vcpkg\current
+ git -C "%VCPKG_INSTALLATION_ROOT%" pull --quiet
+ vcpkg install
working-directory: src
if: ${{ ! steps.restore-vcpkg.outputs.cache-hit }}
- name: Save vcpkg artifact
- uses: actions/cache/save@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4
+ uses: actions/cache/save@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
with:
path: src\vcpkg_installed
key: windows-${{ matrix.os }}-vcpkg-${{ hashFiles('src/vcpkg.json') }}
- if: ${{ ! steps.restore-vcpkg.outputs.cache-hit && (github.ref_name == 'master' || startsWith(github.ref_name, 'ruby_')) }}
+ if: >-
+ steps.build-vcpkg.outcome == 'success' &&
+ ( github.ref_name == 'master'
+ || startsWith(github.ref_name, 'ruby_')
+ || ( github.event.pull_request.user.login == 'dependabot[bot]'
+ && startsWith(github.head_ref || github.ref_name, 'dependabot/vcpkg'))
+ )
- 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
run: |
- ::- Set up VC ${{ matrix.vc }}
- set | uutils sort > old.env
+ set > old.env
call ..\src\win32\vssetup.cmd ^
-arch=${{ matrix.target || 'amd64' }} ^
${{ matrix.vcvars && '-vcvars_ver=' || '' }}${{ matrix.vcvars }}
@@ -120,9 +130,17 @@ jobs:
set MAKEFLAGS=l
set /a TEST_JOBS=(15 * %NUMBER_OF_PROCESSORS% / 10) > nul
set RUBY_OPT_DIR=%GITHUB_WORKSPACE:\=/%/src/vcpkg_installed/%VCPKG_DEFAULT_TRIPLET%
- set | uutils sort > new.env
- uutils comm -13 old.env new.env >> %GITHUB_ENV%
+ set > new.env
+
+ - name: update env
+ shell: pwsh
+ run: |
+ $old = (Get-Content old.env); $new = (Get-Content new.env)
del *.env
+ Compare-Object $old $new |
+ Where-Object { $_.SideIndicator -eq '=>' } |
+ Select-Object -ExpandProperty InputObject |
+ Add-Content -Path $env:GITHUB_ENV
- name: baseruby version
run: ruby -v
@@ -154,30 +172,9 @@ jobs:
# windows-11-arm runner cannot run `ruby tool/file2lastrev.rb --revision.h --output=revision.h`
- name: make revision.h
run: |
- if not exist revision.h (
- for /f "tokens=1-3" %%I in ('git log -1 "--date=format-local:%%F %%T" "--format=%%H %%cd" @') do (
- set rev=%%I
- set dt=%%J
- set tm=%%K
- )
- call set yy=%%dt:~0,4%%
- call set /a mm=100%%dt:~5,2%% %%%% 100
- call set /a dd=100%%dt:~8,2%% %%%% 100
- call set branch=%%GITHUB_REF:refs/heads/=%%
- (
- call echo #define RUBY_REVISION "%%rev:~,10%%"
- call echo #define RUBY_FULL_REVISION "%%rev%%"
- call echo #define RUBY_BRANCH_NAME "%%branch%%"
- call echo #define RUBY_RELEASE_DATETIME "%%dt%%T%%tm%%"
- call echo #define RUBY_RELEASE_YEAR %%yy%%
- call echo #define RUBY_RELEASE_MONTH %%mm%%
- call echo #define RUBY_RELEASE_DAY %%dd%%
- ) > revision.h
- copy /y NUL .revision.time
- )
+ win32\lastrev.bat | win32\ifchange.bat --timestamp=.revision.time revision.h -
type revision.h
- env:
- TZ: UTC
+ working-directory: src
- run: nmake
@@ -200,14 +197,14 @@ jobs:
- uses: ./.github/actions/slack
with:
- label: Windows ${{ matrix.os }} / VC ${{ matrix.vc }} / ${{ matrix.test_task || 'check' }}
+ label: Windows ${{ matrix.os }} / ${{ matrix.test_task || 'check' }}
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
+ runs-on: windows-2025-vs2026
needs: [make]
steps:
- run: exit 1
diff --git a/.github/workflows/wsl.yml b/.github/workflows/wsl.yml
index 640f18ce42..470b68fe66 100644
--- a/.github/workflows/wsl.yml
+++ b/.github/workflows/wsl.yml
@@ -14,16 +14,19 @@ on:
# 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:
+permissions:
+ contents: read
+
jobs:
wsl:
- runs-on: windows-2025
+ runs-on: windows-2025-vs2026
if: >-
${{!(false
|| contains(github.event.head_commit.message, '[DOC]')
|| contains(github.event.pull_request.title, '[DOC]')
|| contains(github.event.pull_request.labels.*.name, 'Documentation')
- || (github.event_name == 'push' && github.event.pull_request.user.login == 'dependabot[bot]')
+ || (github.event.pull_request.user.login == 'dependabot[bot]')
)}}
steps:
diff --git a/.github/workflows/yjit-macos.yml b/.github/workflows/yjit-macos.yml
index 72ef599a39..e11de6bc51 100644
--- a/.github/workflows/yjit-macos.yml
+++ b/.github/workflows/yjit-macos.yml
@@ -1,4 +1,4 @@
-name: YJIT macOS Arm64
+name: YJIT macOS
on:
push:
branches:
@@ -30,18 +30,20 @@ jobs:
cargo:
name: cargo test
- runs-on: macos-14
+ runs-on: macos-26
if: >-
${{!(false
|| contains(github.event.head_commit.message, '[DOC]')
|| contains(github.event.pull_request.title, '[DOC]')
|| contains(github.event.pull_request.labels.*.name, 'Documentation')
- || (github.event_name == 'push' && github.event.pull_request.user.login == 'dependabot[bot]')
+ || (github.event.pull_request.user.login == 'dependabot[bot]' && !startsWith(github.head_ref, 'dependabot/cargo'))
)}}
steps:
- - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
+ - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
+ with:
+ persist-credentials: false
- run: RUST_BACKTRACE=1 cargo test
working-directory: yjit
@@ -72,21 +74,22 @@ jobs:
RUN_OPTS: ${{ matrix.yjit_opts }}
SPECOPTS: ${{ matrix.specopts }}
- runs-on: macos-14
+ runs-on: macos-26
if: >-
${{!(false
|| contains(github.event.head_commit.message, '[DOC]')
|| contains(github.event.pull_request.title, '[DOC]')
|| contains(github.event.pull_request.labels.*.name, 'Documentation')
- || (github.event_name == 'push' && github.event.pull_request.user.login == 'dependabot[bot]')
+ || (github.event.pull_request.user.login == 'dependabot[bot]' && !startsWith(github.head_ref, 'dependabot/cargo'))
)}}
steps:
- - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
+ - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
sparse-checkout-cone-mode: false
sparse-checkout: /.github
+ persist-credentials: false
- name: Install libraries
uses: ./.github/actions/setup/macos
@@ -115,8 +118,10 @@ jobs:
ruby -ne 'raise "Disassembly seems broken in dev build (output has too few lines)" unless $_.to_i > 10'
if: ${{ contains(matrix.configure, 'jit=dev') }}
- - name: Enable YJIT through ENV
- run: echo "RUBY_YJIT_ENABLE=1" >> $GITHUB_ENV
+ - name: Set ENV for YJIT
+ run: |
+ echo "RUBY_YJIT_ENABLE=1" >> $GITHUB_ENV
+ echo "RUBY_CRASH_REPORT=$(pwd)/rb_crash_%p.txt" >> $GITHUB_ENV
- name: Set test options for skipped tests
run: |
@@ -129,7 +134,7 @@ jobs:
id: launchable
uses: ./.github/actions/launchable/setup
with:
- os: macos-14
+ os: macos-26
test-opts: ${{ matrix.configure }}
launchable-token: ${{ secrets.LAUNCHABLE_TOKEN }}
builddir: build
@@ -143,6 +148,7 @@ jobs:
test -n "${LAUNCHABLE_STDOUT}" && exec 1> >(tee "${LAUNCHABLE_STDOUT}")
test -n "${LAUNCHABLE_STDERR}" && exec 2> >(tee "${LAUNCHABLE_STDERR}")
+ set -x
make -s ${{ matrix.test_task }} ${TESTS:+TESTS="$TESTS"} \
RUN_OPTS="$RUN_OPTS" \
SPECOPTS="$SPECOPTS"
@@ -166,6 +172,13 @@ jobs:
if: ${{ matrix.test_task == 'check' && matrix.skipped_tests }}
continue-on-error: ${{ matrix.continue-on-skipped_tests || false }}
+ - name: Dump crash logs
+ if: ${{ failure() }}
+ continue-on-error: true
+ run: |
+ tail --verbose --lines=+1 rb_crash_*.txt
+ exit 1
+
- uses: ./.github/actions/slack
with:
label: ${{ matrix.test_task }} ${{ matrix.configure }} ${{ matrix.yjit_opts }}
@@ -175,7 +188,7 @@ jobs:
result:
if: ${{ always() }}
name: ${{ github.workflow }} result
- runs-on: macos-14
+ runs-on: ubuntu-latest
needs: [make]
steps:
- name: ${{ github.workflow }} jobs have failed
diff --git a/.github/workflows/yjit-ubuntu.yml b/.github/workflows/yjit-ubuntu.yml
index 3b3b75faac..ab816940f4 100644
--- a/.github/workflows/yjit-ubuntu.yml
+++ b/.github/workflows/yjit-ubuntu.yml
@@ -32,11 +32,13 @@ jobs:
|| contains(github.event.head_commit.message, '[DOC]')
|| contains(github.event.pull_request.title, '[DOC]')
|| contains(github.event.pull_request.labels.*.name, 'Documentation')
- || (github.event_name == 'push' && github.event.pull_request.user.login == 'dependabot[bot]')
+ || (github.event.pull_request.user.login == 'dependabot[bot]' && !startsWith(github.head_ref, 'dependabot/cargo'))
)}}
steps:
- - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
+ - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
+ with:
+ persist-credentials: false
# For now we can't run cargo test --offline because it complains about the
# capstone dependency, even though the dependency is optional
@@ -64,11 +66,13 @@ jobs:
|| contains(github.event.head_commit.message, '[DOC]')
|| contains(github.event.pull_request.title, '[DOC]')
|| contains(github.event.pull_request.labels.*.name, 'Documentation')
- || (github.event_name == 'push' && github.event.pull_request.user.login == 'dependabot[bot]')
+ || (github.event.pull_request.user.login == 'dependabot[bot]' && !startsWith(github.head_ref, 'dependabot/cargo'))
)}}
steps:
- - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
+ - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
+ with:
+ persist-credentials: false
# Check that we don't have linting errors in release mode, too
- run: cargo clippy --all-targets --all-features
@@ -81,7 +85,8 @@ jobs:
include:
- test_task: 'yjit-bindgen'
hint: 'To fix: use patch in logs'
- configure: '--with-gcc=clang-14 --enable-yjit=dev'
+ # Build with YJIT+ZJIT for output that works in the most number of configurations
+ configure: '--with-gcc=clang-14 --enable-yjit=dev --enable-zjit'
libclang_path: '/usr/lib/llvm-14/lib/libclang.so.1'
- test_task: 'check'
@@ -101,18 +106,12 @@ jobs:
- test_task: 'test-bundled-gems'
configure: '--enable-yjit=dev'
- - test_task: 'yjit-bench'
- configure: '--enable-yjit=dev'
- yjit_bench_opts: '--yjit-stats'
- continue-on-test_task: true
-
env:
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-22.04
@@ -122,18 +121,19 @@ jobs:
|| contains(github.event.head_commit.message, '[DOC]')
|| contains(github.event.pull_request.title, '[DOC]')
|| contains(github.event.pull_request.labels.*.name, 'Documentation')
- || (github.event_name == 'push' && github.event.pull_request.user.login == 'dependabot[bot]')
+ || (github.event.pull_request.user.login == 'dependabot[bot]' && !startsWith(github.head_ref, 'dependabot/cargo'))
)}}
steps:
- - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
+ - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
sparse-checkout-cone-mode: false
sparse-checkout: /.github
+ persist-credentials: false
- uses: ./.github/actions/setup/ubuntu
- - uses: ruby/setup-ruby@a9bfc2ecf3dd40734a9418f89a7e9d484c32b990 # v1.248.0
+ - uses: ruby/setup-ruby@afeafc3d1ab54a631816aba4c914a0081c12ff2f # v1.310.0
with:
ruby-version: '3.1'
bundler: none
@@ -151,6 +151,12 @@ jobs:
if: ${{ matrix.rust_version }}
run: rustup install ${{ matrix.rust_version }} --profile minimal
+ - name: Remove cargo
+ # Since this tests a `rustc` build for release, remove `cargo` to ensure
+ # that only `rustc` is used.
+ if: ${{ contains(matrix.configure, 'rustc') }}
+ run: sudo rm $(which -a cargo | uniq)
+
- name: Run configure
run: ../src/configure -C --disable-install-doc --prefix=$(pwd)/install ${{ matrix.configure }}
@@ -168,8 +174,10 @@ jobs:
ruby -ne 'raise "Disassembly seems broken in dev build (output has too few lines)" unless $_.to_i > 10'
if: ${{ contains(matrix.configure, 'jit=dev') }}
- - name: Enable YJIT through ENV
- run: echo "RUBY_YJIT_ENABLE=1" >> $GITHUB_ENV
+ - name: Set ENV for YJIT
+ run: |
+ echo "RUBY_YJIT_ENABLE=1" >> $GITHUB_ENV
+ echo "RUBY_CRASH_REPORT=$(pwd)/rb_crash_%p.txt" >> $GITHUB_ENV
# Check that the binary was built with YJIT
- name: Check YJIT enabled
@@ -193,6 +201,7 @@ jobs:
test -n "${LAUNCHABLE_STDOUT}" && exec 1> >(tee "${LAUNCHABLE_STDOUT}")
test -n "${LAUNCHABLE_STDERR}" && exec 2> >(tee "${LAUNCHABLE_STDERR}")
+ set -x
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"
@@ -208,12 +217,12 @@ jobs:
LAUNCHABLE_STDERR: ${{ steps.launchable.outputs.stderr_report_path }}
continue-on-error: ${{ matrix.continue-on-test_task || false }}
- - 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') }}
+ - name: Dump crash logs
+ if: ${{ failure() }}
+ continue-on-error: true
+ run: |
+ tail --verbose --lines=+1 rb_crash_*.txt
+ exit 1
- uses: ./.github/actions/slack
with:
diff --git a/.github/workflows/zjit-macos.yml b/.github/workflows/zjit-macos.yml
index 41ff382382..707e50e36b 100644
--- a/.github/workflows/zjit-macos.yml
+++ b/.github/workflows/zjit-macos.yml
@@ -1,4 +1,4 @@
-name: ZJIT macOS Arm64
+name: ZJIT macOS
on:
push:
branches:
@@ -32,41 +32,48 @@ jobs:
fail-fast: false
matrix:
include:
- - test_task: 'zjit-check'
+ - test_task: 'check'
+ run_opts: '--zjit-call-threshold=1'
+ specopts: '-T --zjit-call-threshold=1'
+ configure: '--enable-zjit=dev'
+
+ - test_task: 'check'
+ run_opts: '--zjit-disable-hir-opt --zjit-call-threshold=1'
+ specopts: '-T --zjit-disable-hir-opt -T --zjit-call-threshold=1'
+ configure: '--enable-zjit=dev'
+
+ - test_task: 'zjit-check' # zjit-test + quick feedback of test_zjit.rb
configure: '--enable-yjit=dev --enable-zjit'
rust_version: "1.85.0"
- - test_task: 'ruby' # build test for combo build
+ - test_task: 'ruby'
+ hint: 'combo build test'
configure: '--enable-yjit --enable-zjit'
- - test_task: 'zjit-test-all'
- configure: '--enable-zjit=dev'
- testopts: '--seed=11831'
-
- - test_task: 'btest'
- configure: '--enable-zjit=dev'
-
env:
GITPULLOPTIONS: --no-tags origin ${{ github.ref }}
- RUN_OPTS: ${{ matrix.zjit_opts }}
+ RUN_OPTS: ${{ matrix.run_opts }}
SPECOPTS: ${{ matrix.specopts }}
TESTOPTS: ${{ matrix.testopts }}
+ RUST_BACKTRACE: 1
+ ZJIT_RB_BUG: 1
- runs-on: macos-14
+ runs-on: macos-26
if: >-
${{!(false
|| contains(github.event.head_commit.message, '[DOC]')
|| contains(github.event.pull_request.title, '[DOC]')
|| contains(github.event.pull_request.labels.*.name, 'Documentation')
- || (github.event_name == 'push' && github.event.pull_request.user.login == 'dependabot[bot]')
+ || (github.event.pull_request.user.login == 'dependabot[bot]' && !startsWith(github.head_ref, 'dependabot/cargo'))
)}}
steps:
- - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
+ - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
sparse-checkout-cone-mode: false
sparse-checkout: /.github
+ persist-credentials: false
- name: Install libraries
uses: ./.github/actions/setup/macos
@@ -86,7 +93,7 @@ jobs:
rustup install ${{ matrix.rust_version }} --profile minimal
rustup default ${{ matrix.rust_version }}
- - uses: taiki-e/install-action@v2
+ - uses: taiki-e/install-action@4bc351f7f2614e48088386e2a0ad917ca3a7e4ba # v2.81.5
with:
tool: nextest@0.9
if: ${{ matrix.test_task == 'zjit-check' }}
@@ -94,9 +101,6 @@ jobs:
- 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: Verify that --zjit-dump-disasm works
@@ -106,71 +110,130 @@ jobs:
ruby -ne 'raise "Disassembly seems broken in dev build (output has too few lines)" unless $_.to_i > 10'
if: ${{ contains(matrix.configure, 'jit=dev') }}
- - name: btest
+ - name: Set ENV for ZJIT
run: |
- RUST_BACKTRACE=1 ruby --disable=gems ../src/bootstraptest/runner.rb --ruby="./miniruby -I../src/lib -I. -I.ext/common --zjit-call-threshold=1" \
- ../src/bootstraptest/test_attr.rb \
- ../src/bootstraptest/test_autoload.rb \
- ../src/bootstraptest/test_block.rb \
- ../src/bootstraptest/test_class.rb \
- ../src/bootstraptest/test_constant_cache.rb \
- ../src/bootstraptest/test_env.rb \
- ../src/bootstraptest/test_eval.rb \
- ../src/bootstraptest/test_exception.rb \
- ../src/bootstraptest/test_fiber.rb \
- ../src/bootstraptest/test_finalizer.rb \
- ../src/bootstraptest/test_flip.rb \
- ../src/bootstraptest/test_flow.rb \
- ../src/bootstraptest/test_fork.rb \
- ../src/bootstraptest/test_gc.rb \
- ../src/bootstraptest/test_insns.rb \
- ../src/bootstraptest/test_io.rb \
- ../src/bootstraptest/test_jump.rb \
- ../src/bootstraptest/test_literal.rb \
- ../src/bootstraptest/test_literal_suffix.rb \
- ../src/bootstraptest/test_load.rb \
- ../src/bootstraptest/test_marshal.rb \
- ../src/bootstraptest/test_massign.rb \
- ../src/bootstraptest/test_method.rb \
- ../src/bootstraptest/test_objectspace.rb \
- ../src/bootstraptest/test_proc.rb \
- ../src/bootstraptest/test_ractor.rb \
- ../src/bootstraptest/test_string.rb \
- ../src/bootstraptest/test_struct.rb \
- ../src/bootstraptest/test_syntax.rb \
- ../src/bootstraptest/test_thread.rb \
- ../src/bootstraptest/test_yjit_30k_ifelse.rb \
- ../src/bootstraptest/test_yjit_30k_methods.rb \
- ../src/bootstraptest/test_yjit_rust_port.rb
- # ../src/bootstraptest/test_yjit.rb \
- if: ${{ matrix.test_task == 'btest' }}
+ echo "RUBY_CRASH_REPORT=$(pwd)/rb_crash_%p.txt" >> $GITHUB_ENV
+
+ - name: Set up Launchable
+ id: launchable
+ uses: ./.github/actions/launchable/setup
+ with:
+ os: macos-26
+ test-opts: ${{ matrix.configure }}
+ launchable-token: ${{ secrets.LAUNCHABLE_TOKEN }}
+ builddir: build
+ srcdir: src
+ is-zjit: true
+ continue-on-error: true
+ timeout-minutes: 3
- name: make ${{ matrix.test_task }}
- run: >-
- make -s ${{ matrix.test_task }} ${TESTS:+TESTS="$TESTS"}
- RUN_OPTS="$RUN_OPTS"
- SPECOPTS="$SPECOPTS"
- TESTOPTS="$TESTOPTS"
+ run: |
+ test -n "${LAUNCHABLE_STDOUT}" && exec 1> >(tee "${LAUNCHABLE_STDOUT}")
+ test -n "${LAUNCHABLE_STDERR}" && exec 2> >(tee "${LAUNCHABLE_STDERR}")
+
+ set -x
+ make -s ${{ matrix.test_task }} ${TESTS:+TESTS="$TESTS"} \
+ RUN_OPTS="$RUN_OPTS" \
+ SPECOPTS="$SPECOPTS" \
+ TESTOPTS="$TESTOPTS"
timeout-minutes: 60
env:
RUBY_TESTOPTS: '-q --tty=no'
+ EXCLUDES: '../src/test/.excludes-zjit'
TEST_BUNDLED_GEMS_ALLOW_FAILURES: ''
- SYNTAX_SUGGEST_TIMEOUT: '5'
+ SYNTAX_SUGGEST_TIMEOUT: '30'
PRECHECK_BUNDLED_GEMS: 'no'
- TESTS: ${{ matrix.tests }}
+ LAUNCHABLE_STDOUT: ${{ steps.launchable.outputs.stdout_report_path }}
+ LAUNCHABLE_STDERR: ${{ steps.launchable.outputs.stderr_report_path }}
continue-on-error: ${{ matrix.continue-on-test_task || false }}
- if: ${{ matrix.test_task != 'btest' }}
+
+ - name: Dump crash logs
+ if: ${{ failure() }}
+ continue-on-error: true
+ run: |
+ tail --verbose --lines=+1 rb_crash_*.txt
+ exit 1
+
+ - uses: ./.github/actions/slack
+ with:
+ label: ${{ matrix.test_task }} ${{ matrix.configure }}
+ 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
+ runs-on: ubuntu-latest
needs: [make]
steps:
- run: exit 1
working-directory:
if: ${{ contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled') }}
+ # Separated from `make` job to avoid making it a required status check for now
+ ruby-bench:
+ strategy:
+ matrix:
+ include:
+ # Test --call-threshold=2 with 2 iterations in total
+ - ruby_opts: '--zjit-call-threshold=2'
+ bench_opts: '--warmup=1 --bench=1 --excludes=shipit'
+ configure: '--enable-zjit=dev_nodebug' # --enable-zjit=dev is too slow
+
+ runs-on: macos-26
+
+ if: >-
+ ${{!(false
+ || contains(github.event.head_commit.message, '[DOC]')
+ || contains(github.event.pull_request.title, '[DOC]')
+ || contains(github.event.pull_request.labels.*.name, 'Documentation')
+ || (github.event.pull_request.user.login == 'dependabot[bot]' && !startsWith(github.head_ref, 'dependabot/cargo'))
+ )}}
+
+ steps:
+ - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
+ with:
+ persist-credentials: false
+
+ - uses: ./.github/actions/setup/macos
+
+ - 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" ${{ matrix.configure }}
+
+ - run: make install
+
+ # setup/directories set MAKEFLAGS=-j4 for macOS, which randomly fails sqlite3.gem builds
+ - name: Unset MAKEFLAGS
+ run: echo "MAKEFLAGS=" >> "$GITHUB_ENV"
+
+ - name: Checkout ruby-bench
+ uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
+ with:
+ persist-credentials: false
+ repository: ruby/ruby-bench
+ path: ruby-bench
+
+ # If you want to skip failing benchmark, consider using `--excludes`.
+ # e.g. `bench_opts: '--warmup=1 --bench=1 --excludes=railsbench,lobsters'`
+ - name: Run ruby-bench
+ run: ruby run_benchmarks.rb -e "zjit::../build/install/bin/ruby ${{ matrix.ruby_opts }}" ${{ matrix.bench_opts }}
+ working-directory: ruby-bench
+ env:
+ BUNDLER_VERSION: 0
+
+ - uses: ./.github/actions/slack
+ with:
+ label: ruby-bench ${{ matrix.bench_opts }} ${{ matrix.ruby_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/zjit-ubuntu.yml b/.github/workflows/zjit-ubuntu.yml
index 4b0e0dbd5c..1c3e3f6531 100644
--- a/.github/workflows/zjit-ubuntu.yml
+++ b/.github/workflows/zjit-ubuntu.yml
@@ -27,66 +27,103 @@ permissions:
contents: read
jobs:
+ lint:
+ name: cargo clippy
+
+ runs-on: ubuntu-22.04
+
+ if: >-
+ ${{!(false
+ || contains(github.event.head_commit.message, '[DOC]')
+ || contains(github.event.pull_request.title, '[DOC]')
+ || contains(github.event.pull_request.labels.*.name, 'Documentation')
+ || (github.event.pull_request.user.login == 'dependabot[bot]' && !startsWith(github.head_ref, 'dependabot/cargo'))
+ )}}
+
+ steps:
+ - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
+ with:
+ persist-credentials: false
+
+ - run: cargo clippy --all-targets --all-features
+ working-directory: zjit
+
make:
strategy:
fail-fast: false
matrix:
include:
- - test_task: 'zjit-bindgen'
- hint: 'To fix: use patch in logs'
- configure: '--enable-zjit=dev --with-gcc=clang-14'
- libclang_path: '/usr/lib/llvm-14/lib/libclang.so.1'
+ - test_task: 'check'
+ run_opts: '--zjit-call-threshold=1'
+ specopts: '-T --zjit-call-threshold=1'
+ configure: '--enable-zjit=dev'
- - test_task: 'zjit-check'
+ - test_task: 'check'
+ run_opts: '--zjit-disable-hir-opt --zjit-call-threshold=1'
+ specopts: '-T --zjit-disable-hir-opt -T --zjit-call-threshold=1'
+ configure: '--enable-zjit=dev'
+
+ # The optimizer benefits from at least 1 iteration of profiling. Also, many
+ # regression tests in bootstraptest/test_yjit.rb assume call-threshold=2.
+ - test_task: 'btest'
+ run_opts: '--zjit-call-threshold=2'
+ configure: '--enable-zjit=dev'
+
+ - test_task: 'zjit-check' # zjit-test + quick feedback of test_zjit.rb
configure: '--enable-yjit --enable-zjit=dev'
rust_version: '1.85.0'
- - test_task: 'zjit-test-all'
- configure: '--enable-zjit=dev'
- testopts: '--seed=18140'
+ - test_task: 'zjit-bindgen'
+ hint: 'To fix: use patch in logs'
+ # Build with YJIT+ZJIT for output that works in the most number of configurations
+ configure: '--enable-zjit=dev --enable-yjit --with-gcc=clang-16'
+ clang_path: '/usr/bin/clang-16'
+ runs-on: 'ubuntu-24.04' # for clang-16
- - test_task: 'btest'
+ - test_task: 'test-bundled-gems'
configure: '--enable-zjit=dev'
+ run_opts: '--zjit-call-threshold=1'
env:
GITPULLOPTIONS: --no-tags origin ${{ github.ref }}
- RUN_OPTS: ${{ matrix.zjit_opts }}
+ RUN_OPTS: ${{ matrix.run_opts }}
YJIT_BENCH_OPTS: ${{ matrix.yjit_bench_opts }}
SPECOPTS: ${{ matrix.specopts }}
TESTOPTS: ${{ matrix.testopts }}
RUBY_DEBUG: ci
BUNDLE_JOBS: 8 # for yjit-bench
RUST_BACKTRACE: 1
+ ZJIT_RB_BUG: 1
- runs-on: ubuntu-22.04
+ runs-on: ${{ matrix.runs-on || 'ubuntu-22.04' }}
if: >-
${{!(false
|| contains(github.event.head_commit.message, '[DOC]')
|| contains(github.event.pull_request.title, '[DOC]')
|| contains(github.event.pull_request.labels.*.name, 'Documentation')
- || (github.event_name == 'push' && github.event.pull_request.user.login == 'dependabot[bot]')
+ || (github.event.pull_request.user.login == 'dependabot[bot]' && !startsWith(github.head_ref, 'dependabot/cargo'))
)}}
steps:
- - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
+ - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
sparse-checkout-cone-mode: false
sparse-checkout: /.github
+ persist-credentials: false
- uses: ./.github/actions/setup/ubuntu
- - uses: ruby/setup-ruby@a9bfc2ecf3dd40734a9418f89a7e9d484c32b990 # v1.248.0
+ - uses: ruby/setup-ruby@afeafc3d1ab54a631816aba4c914a0081c12ff2f # v1.310.0
with:
ruby-version: '3.1'
bundler: none
- - uses: taiki-e/install-action@v2
+ - uses: taiki-e/install-action@4bc351f7f2614e48088386e2a0ad917ca3a7e4ba # v2.81.5
with:
tool: nextest@0.9
if: ${{ matrix.test_task == 'zjit-check' }}
-
- uses: ./.github/actions/setup/directories
with:
srcdir: src
@@ -128,62 +165,58 @@ jobs:
run: ./miniruby --zjit -v | grep "+ZJIT"
if: ${{ matrix.configure != '--disable-zjit' }}
- - name: btest
+ - name: Set ENV for ZJIT
run: |
- RUST_BACKTRACE=1 ruby --disable=gems ../src/bootstraptest/runner.rb --ruby="./miniruby -I../src/lib -I. -I.ext/common --zjit-call-threshold=1" \
- ../src/bootstraptest/test_attr.rb \
- ../src/bootstraptest/test_autoload.rb \
- ../src/bootstraptest/test_block.rb \
- ../src/bootstraptest/test_class.rb \
- ../src/bootstraptest/test_constant_cache.rb \
- ../src/bootstraptest/test_env.rb \
- ../src/bootstraptest/test_env.rb \
- ../src/bootstraptest/test_exception.rb \
- ../src/bootstraptest/test_fiber.rb \
- ../src/bootstraptest/test_finalizer.rb \
- ../src/bootstraptest/test_flip.rb \
- ../src/bootstraptest/test_flow.rb \
- ../src/bootstraptest/test_fork.rb \
- ../src/bootstraptest/test_gc.rb \
- ../src/bootstraptest/test_insns.rb \
- ../src/bootstraptest/test_io.rb \
- ../src/bootstraptest/test_jump.rb \
- ../src/bootstraptest/test_literal.rb \
- ../src/bootstraptest/test_literal_suffix.rb \
- ../src/bootstraptest/test_load.rb \
- ../src/bootstraptest/test_marshal.rb \
- ../src/bootstraptest/test_massign.rb \
- ../src/bootstraptest/test_method.rb \
- ../src/bootstraptest/test_objectspace.rb \
- ../src/bootstraptest/test_proc.rb \
- ../src/bootstraptest/test_ractor.rb \
- ../src/bootstraptest/test_string.rb \
- ../src/bootstraptest/test_struct.rb \
- ../src/bootstraptest/test_syntax.rb \
- ../src/bootstraptest/test_thread.rb \
- ../src/bootstraptest/test_yjit_30k_ifelse.rb \
- ../src/bootstraptest/test_yjit_30k_methods.rb \
- ../src/bootstraptest/test_yjit_rust_port.rb
- # ../src/bootstraptest/test_yjit.rb \
- if: ${{ matrix.test_task == 'btest' }}
+ echo "RUBY_CRASH_REPORT=$(pwd)/rb_crash_%p.txt" >> $GITHUB_ENV
+
+ - name: Set up Launchable
+ id: launchable
+ uses: ./.github/actions/launchable/setup
+ with:
+ os: ${{ matrix.runs-on || 'ubuntu-22.04' }}
+ test-opts: ${{ matrix.configure }}
+ launchable-token: ${{ secrets.LAUNCHABLE_TOKEN }}
+ builddir: build
+ srcdir: src
+ is-zjit: true
+ continue-on-error: true
+ timeout-minutes: 3
- name: make ${{ matrix.test_task }}
- run: >-
- make -s ${{ matrix.test_task }} ${TESTS:+TESTS="$TESTS"}
- RUN_OPTS="$RUN_OPTS" MSPECOPT=--debug SPECOPTS="$SPECOPTS"
- TESTOPTS="$TESTOPTS"
- ZJIT_BINDGEN_DIFF_OPTS="$ZJIT_BINDGEN_DIFF_OPTS"
+ run: |
+ test -n "${LAUNCHABLE_STDOUT}" && exec 1> >(tee "${LAUNCHABLE_STDOUT}")
+ test -n "${LAUNCHABLE_STDERR}" && exec 2> >(tee "${LAUNCHABLE_STDERR}")
+
+ set -x
+ make -s ${{ matrix.test_task }} ${TESTS:+TESTS="$TESTS"} \
+ RUN_OPTS="$RUN_OPTS" MSPECOPT=--debug SPECOPTS="$SPECOPTS" \
+ TESTOPTS="$TESTOPTS" \
+ ZJIT_BINDGEN_DIFF_OPTS="$ZJIT_BINDGEN_DIFF_OPTS"
timeout-minutes: 90
env:
RUBY_TESTOPTS: '-q --tty=no'
+ EXCLUDES: '../src/test/.excludes-zjit'
TEST_BUNDLED_GEMS_ALLOW_FAILURES: ''
PRECHECK_BUNDLED_GEMS: 'no'
- SYNTAX_SUGGEST_TIMEOUT: '5'
+ SYNTAX_SUGGEST_TIMEOUT: '30'
ZJIT_BINDGEN_DIFF_OPTS: '--exit-code'
- LIBCLANG_PATH: ${{ matrix.libclang_path }}
- TESTS: ${{ matrix.tests }}
+ CLANG_PATH: ${{ matrix.clang_path }}
+ LAUNCHABLE_STDOUT: ${{ steps.launchable.outputs.stdout_report_path }}
+ LAUNCHABLE_STDERR: ${{ steps.launchable.outputs.stderr_report_path }}
continue-on-error: ${{ matrix.continue-on-test_task || false }}
- if: ${{ matrix.test_task != 'btest' }}
+
+ - name: Dump crash logs
+ if: ${{ failure() }}
+ continue-on-error: true
+ run: |
+ tail --verbose --lines=+1 rb_crash_*.txt
+ exit 1
+
+ - uses: ./.github/actions/slack
+ with:
+ label: ${{ matrix.test_task }} ${{ matrix.configure }}
+ SLACK_WEBHOOK_URL: ${{ secrets.SIMPLER_ALERTS_URL }} # ruby-lang slack: ruby/simpler-alerts-bot
+ if: ${{ failure() }}
result:
if: ${{ always() }}
@@ -196,6 +229,65 @@ jobs:
working-directory:
if: ${{ contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled') }}
+ # Separated from `make` job to avoid making it a required status check for now
+ ruby-bench:
+ strategy:
+ matrix:
+ include:
+ # Test --call-threshold=2 with 2 iterations in total
+ - ruby_opts: '--zjit-call-threshold=2'
+ bench_opts: '--warmup=1 --bench=1 --excludes=shipit'
+ configure: '--enable-zjit=dev_nodebug' # --enable-zjit=dev is too slow
+
+ runs-on: ubuntu-24.04
+
+ if: >-
+ ${{!(false
+ || contains(github.event.head_commit.message, '[DOC]')
+ || contains(github.event.pull_request.title, '[DOC]')
+ || contains(github.event.pull_request.labels.*.name, 'Documentation')
+ || (github.event.pull_request.user.login == 'dependabot[bot]' && !startsWith(github.head_ref, 'dependabot/cargo'))
+ )}}
+
+ steps:
+ - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
+ with:
+ persist-credentials: false
+
+ - 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" ${{ matrix.configure }}
+
+ - run: make install
+
+ - name: Checkout ruby-bench
+ uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
+ with:
+ repository: ruby/ruby-bench
+ persist-credentials: false
+ path: ruby-bench
+
+ # If you want to skip failing benchmark, consider using `--excludes`.
+ # e.g. `bench_opts: '--warmup=1 --bench=1 --excludes=railsbench,lobsters'`
+ - name: Run ruby-bench
+ run: ruby run_benchmarks.rb -e "zjit::../build/install/bin/ruby ${{ matrix.ruby_opts }}" ${{ matrix.bench_opts }}
+ working-directory: ruby-bench
+ env:
+ BUNDLER_VERSION: 0
+
+ - uses: ./.github/actions/slack
+ with:
+ label: ruby-bench ${{ matrix.bench_opts }} ${{ matrix.ruby_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/zizmor.yml b/.github/zizmor.yml
new file mode 100644
index 0000000000..2a8cad1d5c
--- /dev/null
+++ b/.github/zizmor.yml
@@ -0,0 +1,33 @@
+# Ignore existing findings (baseline)
+# Composite action findings are suppressed inline with # zizmor: ignore
+rules:
+ artipacked:
+ # These jobs push back to the repo and need persisted credentials.
+ ignore:
+ - bundled_gems.yml
+ - default_gems_list.yml
+ - post_push.yml
+ - sync_default_gems.yml
+ dangerous-triggers:
+ ignore:
+ - auto_request_review.yml
+ - auto_review_pr.yml
+ - labeler.yml
+ - pr-playground.yml
+ dependabot-cooldown:
+ ignore:
+ - dependabot.yml
+ misfeature:
+ ignore:
+ - mingw.yml
+ - tarball-windows.yml
+ - windows.yml
+ unpinned-images:
+ ignore:
+ - compilers.yml
+ secrets-outside-env:
+ # All committers with write access are trusted; no need for environment-scoped secrets.
+ disable: true
+ unpinned-uses:
+ ignore:
+ - wsl.yml
diff --git a/.gitignore b/.gitignore
index 6cf5fb5f32..7ead3a81f5 100644
--- a/.gitignore
+++ b/.gitignore
@@ -97,6 +97,7 @@ lcov*.info
/enc.mk
/encdb.h
/exts.mk
+/gc/*/exts.mk
/goruby
/id.[ch]
/largefile.h
@@ -264,17 +265,27 @@ lcov*.info
/lib/prism/reflection.rb
/lib/prism/serialize.rb
/lib/prism/visitor.rb
+/prism/internal/diagnostic.h
/prism/api_node.c
/prism/ast.h
/prism/diagnostic.c
-/prism/diagnostic.h
+/prism/json.c
/prism/node.c
/prism/prettyprint.c
/prism/serialize.c
-/prism/token_type.c
+/prism/tokens.c
/prism/srcs.mk
+/dump_ast
+
+# prism (old file)
+/prism/token_type.c
# tool/update-NEWS-gemlist.rb
/bundled_gems.json
/default_gems.json
/gems/default_gems
+
+# AI agents
+/.claude
+/AGENTS.md
+/CLAUDE.md
diff --git a/.rdoc_options b/.rdoc_options
index b8b511efe6..5172911e16 100644
--- a/.rdoc_options
+++ b/.rdoc_options
@@ -1,7 +1,5 @@
---
page_dir: doc
-charset: UTF-8
-encoding: UTF-8
main_page: index.md
title: Documentation for Ruby development version
visibility: :private
@@ -10,8 +8,10 @@ rdoc_include:
exclude:
- \.gemspec\z
+- lib/set/subclass_compatible.rb
autolink_excluded_words:
+- Box
- Class
- Method
- Module
@@ -23,3 +23,15 @@ autolink_excluded_words:
- YJIT
canonical_root: https://docs.ruby-lang.org/en/master
+
+footer_content:
+ Ruby:
+ Documentation: index.html
+ Official Website: https://www.ruby-lang.org/
+ Playground: https://ruby.github.io/play-ruby/
+ Resources:
+ GitHub: https://github.com/ruby/ruby
+ Issue Tracker: https://bugs.ruby-lang.org/projects/ruby-master/issues
+ RubyGems: https://rubygems.org/
+ Community:
+ X: https://x.com/rubylangorg
diff --git a/COPYING b/COPYING
index 48e5a96de7..428ce03ed7 100644
--- a/COPYING
+++ b/COPYING
@@ -1,3 +1,5 @@
+{日本語}[rdoc-ref:COPYING.ja]
+
Ruby is copyrighted free software by Yukihiro Matsumoto <matz@netlab.jp>.
You can redistribute it and/or modify it under either the terms of the
2-clause BSDL (see the file BSDL), or the conditions below:
diff --git a/COPYING.ja b/COPYING.ja
index 230376bc60..5de2dbcc8f 100644
--- a/COPYING.ja
+++ b/COPYING.ja
@@ -1,3 +1,5 @@
+{English}[rdoc-ref:COPYING]
+
本プログラムã¯ãƒ•リーソフトウェアã§ã™ï¼Ž2-clause BSDL
ã¾ãŸã¯ä»¥ä¸‹ã«ç¤ºã™æ¡ä»¶ã§æœ¬ãƒ—ログラムをå†é…布ã§ãã¾ã™
2-clause BSDLã«ã¤ã„ã¦ã¯BSDLファイルをå‚ç…§ã—ã¦ä¸‹ã•ã„.
diff --git a/Cargo.lock b/Cargo.lock
index 65131406d3..2108276e72 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -3,52 +3,327 @@
version = 3
[[package]]
+name = "anyhow"
+version = "1.0.100"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61"
+
+[[package]]
+name = "autocfg"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
+
+[[package]]
+name = "bitflags"
+version = "1.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
+
+[[package]]
+name = "bitflags"
+version = "2.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af"
+
+[[package]]
name = "capstone"
-version = "0.13.0"
+version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "015ef5d5ca1743e3f94af9509ba6bd2886523cfee46e48d15c2ef5216fd4ac9a"
+checksum = "f442ae0f2f3f1b923334b4a5386c95c69c1cfa072bafa23d6fae6d9682eb1dd4"
dependencies = [
"capstone-sys",
- "libc",
+ "static_assertions",
]
[[package]]
name = "capstone-sys"
-version = "0.17.0"
+version = "0.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2267cb8d16a1e4197863ec4284ffd1aec26fe7e57c58af46b02590a0235809a0"
+checksum = "a4e8087cab6731295f5a2a2bd82989ba4f41d3a428aab2e7c98d8f4db38aac05"
dependencies = [
"cc",
- "libc",
]
[[package]]
name = "cc"
-version = "1.2.18"
+version = "1.0.94"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "17f6e324229dc011159fcc089755d1e2e216a90d43a7dea6853ca740b84f35e7"
+
+[[package]]
+name = "cfg-if"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
+
+[[package]]
+name = "chacha20"
+version = "0.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6f8d983286843e49675a4b7a2d174efe136dc93a18d69130dd18198a6c167601"
+dependencies = [
+ "cfg-if",
+ "cpufeatures",
+ "rand_core",
+]
+
+[[package]]
+name = "console"
+version = "0.16.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d64e8af5551369d19cf50138de61f1c42074ab970f74e99be916646777f8fc87"
+dependencies = [
+ "encode_unicode",
+ "libc",
+ "windows-sys 0.61.2",
+]
+
+[[package]]
+name = "cpufeatures"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8b2a41393f66f16b0823bb79094d54ac5fbd34ab292ddafb9a0456ac9f87d201"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "encode_unicode"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0"
+
+[[package]]
+name = "equivalent"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
+
+[[package]]
+name = "errno"
+version = "0.3.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "525046617d8376e3db1deffb079e91cef90a89fc3ca5c185bbf8c9ecdd15cd5c"
+checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb"
dependencies = [
- "shlex",
+ "libc",
+ "windows-sys 0.52.0",
]
[[package]]
-name = "dissimilar"
-version = "1.0.10"
+name = "fastrand"
+version = "1.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8975ffdaa0ef3661bfe02dbdcc06c9f829dfafe6a3c474de366a8d5e44276921"
+checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be"
+dependencies = [
+ "instant",
+]
[[package]]
-name = "expect-test"
-version = "1.5.1"
+name = "foldhash"
+version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "63af43ff4431e848fb47472a920f14fa71c24de13255a5692e93d4e90302acb0"
+checksum = "a0d2fde1f7b3d48b8395d5f2de76c18a528bd6a9cdde438df747bfcba3e05d6f"
+
+[[package]]
+name = "getrandom"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0de51e6874e94e7bf76d726fc5d13ba782deca734ff60d5bb2fb2607c7406555"
dependencies = [
- "dissimilar",
+ "cfg-if",
+ "libc",
+ "r-efi",
+ "rand_core",
+ "wasip2",
+ "wasip3",
+]
+
+[[package]]
+name = "hashbrown"
+version = "0.15.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1"
+dependencies = [
+ "foldhash",
+]
+
+[[package]]
+name = "hashbrown"
+version = "0.16.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100"
+
+[[package]]
+name = "heck"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
+
+[[package]]
+name = "hermit-abi"
+version = "0.3.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024"
+
+[[package]]
+name = "id-arena"
+version = "2.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954"
+
+[[package]]
+name = "indexmap"
+version = "2.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017"
+dependencies = [
+ "equivalent",
+ "hashbrown 0.16.1",
+ "serde",
+ "serde_core",
+]
+
+[[package]]
+name = "insta"
+version = "1.47.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7b4a6248eb93a4401ed2f37dfe8ea592d3cf05b7cf4f8efa867b6895af7e094e"
+dependencies = [
+ "console",
"once_cell",
+ "similar",
+ "tempfile",
+]
+
+[[package]]
+name = "instant"
+version = "0.1.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222"
+dependencies = [
+ "cfg-if",
]
[[package]]
+name = "io-lifetimes"
+version = "1.0.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2"
+dependencies = [
+ "hermit-abi",
+ "libc",
+ "windows-sys 0.48.0",
+]
+
+[[package]]
+name = "itoa"
+version = "1.0.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
+
+[[package]]
name = "jit"
+version = "0.1.0"
+
+[[package]]
+name = "leb128fmt"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2"
+
+[[package]]
+name = "libc"
+version = "0.2.163"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1fdaeca4cf44ed4ac623e86ef41f056e848dbeab7ec043ecb7326ba300b36fd0"
+
+[[package]]
+name = "linux-raw-sys"
+version = "0.3.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519"
+
+[[package]]
+name = "log"
+version = "0.4.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "518ef76f2f87365916b142844c16d8fefd85039bc5699050210a7778ee1cd1de"
+
+[[package]]
+name = "memchr"
+version = "2.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "76fc44e2588d5b436dbc3c6cf62aef290f90dab6235744a93dfe1cc18f451e2c"
+
+[[package]]
+name = "once_cell"
+version = "1.21.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50"
+
+[[package]]
+name = "prettyplease"
+version = "0.2.37"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b"
+dependencies = [
+ "proc-macro2",
+ "syn",
+]
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.101"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de"
+dependencies = [
+ "unicode-ident",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.40"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "r-efi"
+version = "6.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf"
+
+[[package]]
+name = "rand"
+version = "0.10.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d2e8e8bcc7961af1fdac401278c6a831614941f6164ee3bf4ce61b7edb162207"
+dependencies = [
+ "chacha20",
+ "getrandom",
+ "rand_core",
+]
+
+[[package]]
+name = "rand_core"
+version = "0.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0c8d0fd677905edcbeedbf2edb6494d676f0e98d54d5cf9bda0b061cb8fb8aba"
+
+[[package]]
+name = "redox_syscall"
+version = "0.3.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29"
+dependencies = [
+ "bitflags 1.3.2",
+]
+
+[[package]]
+name = "ruby"
version = "0.0.0"
dependencies = [
"yjit",
@@ -56,28 +331,427 @@ dependencies = [
]
[[package]]
-name = "libc"
-version = "0.2.171"
+name = "rustix"
+version = "0.37.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6"
+checksum = "519165d378b97752ca44bbe15047d5d3409e875f39327546b42ac81d7e18c1b6"
+dependencies = [
+ "bitflags 1.3.2",
+ "errno",
+ "io-lifetimes",
+ "libc",
+ "linux-raw-sys",
+ "windows-sys 0.48.0",
+]
[[package]]
-name = "once_cell"
-version = "1.21.3"
+name = "ryu"
+version = "1.0.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f"
+
+[[package]]
+name = "semver"
+version = "1.0.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
+checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0"
+
+[[package]]
+name = "serde"
+version = "1.0.228"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e"
+dependencies = [
+ "serde_core",
+]
[[package]]
-name = "shlex"
-version = "1.3.0"
+name = "serde_core"
+version = "1.0.228"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
+checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad"
+dependencies = [
+ "serde_derive",
+]
+
+[[package]]
+name = "serde_derive"
+version = "1.0.228"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "serde_json"
+version = "1.0.143"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d401abef1d108fbd9cbaebc3e46611f4b1021f714a0597a71f41ee463f5f4a5a"
+dependencies = [
+ "itoa",
+ "memchr",
+ "ryu",
+ "serde",
+]
+
+[[package]]
+name = "similar"
+version = "2.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "32fea41aca09ee824cc9724996433064c89f7777e60762749a4170a14abbfa21"
+
+[[package]]
+name = "static_assertions"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
+
+[[package]]
+name = "syn"
+version = "2.0.117"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
+[[package]]
+name = "tempfile"
+version = "3.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "31c0432476357e58790aaa47a8efb0c5138f137343f3b5f23bd36a27e3b0a6d6"
+dependencies = [
+ "autocfg",
+ "cfg-if",
+ "fastrand",
+ "redox_syscall",
+ "rustix",
+ "windows-sys 0.48.0",
+]
+
+[[package]]
+name = "unicode-ident"
+version = "1.0.22"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5"
+
+[[package]]
+name = "unicode-xid"
+version = "0.2.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853"
+
+[[package]]
+name = "wasip2"
+version = "1.0.1+wasi-0.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7"
+dependencies = [
+ "wit-bindgen 0.46.0",
+]
+
+[[package]]
+name = "wasip3"
+version = "0.4.0+wasi-0.3.0-rc-2026-01-06"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5"
+dependencies = [
+ "wit-bindgen 0.51.0",
+]
+
+[[package]]
+name = "wasm-encoder"
+version = "0.244.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319"
+dependencies = [
+ "leb128fmt",
+ "wasmparser",
+]
+
+[[package]]
+name = "wasm-metadata"
+version = "0.244.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909"
+dependencies = [
+ "anyhow",
+ "indexmap",
+ "wasm-encoder",
+ "wasmparser",
+]
+
+[[package]]
+name = "wasmparser"
+version = "0.244.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe"
+dependencies = [
+ "bitflags 2.11.0",
+ "hashbrown 0.15.5",
+ "indexmap",
+ "semver",
+]
+
+[[package]]
+name = "windows-link"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
+
+[[package]]
+name = "windows-sys"
+version = "0.48.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
+dependencies = [
+ "windows-targets 0.48.5",
+]
+
+[[package]]
+name = "windows-sys"
+version = "0.52.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
+dependencies = [
+ "windows-targets 0.52.6",
+]
+
+[[package]]
+name = "windows-sys"
+version = "0.61.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc"
+dependencies = [
+ "windows-link",
+]
+
+[[package]]
+name = "windows-targets"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
+dependencies = [
+ "windows_aarch64_gnullvm 0.48.5",
+ "windows_aarch64_msvc 0.48.5",
+ "windows_i686_gnu 0.48.5",
+ "windows_i686_msvc 0.48.5",
+ "windows_x86_64_gnu 0.48.5",
+ "windows_x86_64_gnullvm 0.48.5",
+ "windows_x86_64_msvc 0.48.5",
+]
+
+[[package]]
+name = "windows-targets"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
+dependencies = [
+ "windows_aarch64_gnullvm 0.52.6",
+ "windows_aarch64_msvc 0.52.6",
+ "windows_i686_gnu 0.52.6",
+ "windows_i686_gnullvm",
+ "windows_i686_msvc 0.52.6",
+ "windows_x86_64_gnu 0.52.6",
+ "windows_x86_64_gnullvm 0.52.6",
+ "windows_x86_64_msvc 0.52.6",
+]
+
+[[package]]
+name = "windows_aarch64_gnullvm"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
+
+[[package]]
+name = "windows_aarch64_gnullvm"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
+
+[[package]]
+name = "windows_aarch64_msvc"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
+
+[[package]]
+name = "windows_aarch64_msvc"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
+
+[[package]]
+name = "windows_i686_gnu"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
+
+[[package]]
+name = "windows_i686_gnu"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
+
+[[package]]
+name = "windows_i686_gnullvm"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
+
+[[package]]
+name = "windows_i686_msvc"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
+
+[[package]]
+name = "windows_i686_msvc"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
+
+[[package]]
+name = "windows_x86_64_gnu"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
+
+[[package]]
+name = "windows_x86_64_gnu"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
+
+[[package]]
+name = "windows_x86_64_gnullvm"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
+
+[[package]]
+name = "windows_x86_64_gnullvm"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
+
+[[package]]
+name = "windows_x86_64_msvc"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
+
+[[package]]
+name = "windows_x86_64_msvc"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
+
+[[package]]
+name = "wit-bindgen"
+version = "0.46.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59"
+
+[[package]]
+name = "wit-bindgen"
+version = "0.51.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5"
+dependencies = [
+ "wit-bindgen-rust-macro",
+]
+
+[[package]]
+name = "wit-bindgen-core"
+version = "0.51.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc"
+dependencies = [
+ "anyhow",
+ "heck",
+ "wit-parser",
+]
+
+[[package]]
+name = "wit-bindgen-rust"
+version = "0.51.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21"
+dependencies = [
+ "anyhow",
+ "heck",
+ "indexmap",
+ "prettyplease",
+ "syn",
+ "wasm-metadata",
+ "wit-bindgen-core",
+ "wit-component",
+]
+
+[[package]]
+name = "wit-bindgen-rust-macro"
+version = "0.51.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17a"
+dependencies = [
+ "anyhow",
+ "prettyplease",
+ "proc-macro2",
+ "quote",
+ "syn",
+ "wit-bindgen-core",
+ "wit-bindgen-rust",
+]
+
+[[package]]
+name = "wit-component"
+version = "0.244.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2"
+dependencies = [
+ "anyhow",
+ "bitflags 2.11.0",
+ "indexmap",
+ "log",
+ "serde",
+ "serde_derive",
+ "serde_json",
+ "wasm-encoder",
+ "wasm-metadata",
+ "wasmparser",
+ "wit-parser",
+]
+
+[[package]]
+name = "wit-parser"
+version = "0.244.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736"
+dependencies = [
+ "anyhow",
+ "id-arena",
+ "indexmap",
+ "log",
+ "semver",
+ "serde",
+ "serde_derive",
+ "serde_json",
+ "unicode-xid",
+ "wasmparser",
+]
[[package]]
name = "yjit"
version = "0.1.0"
dependencies = [
"capstone",
+ "jit",
]
[[package]]
@@ -85,5 +759,8 @@ name = "zjit"
version = "0.0.1"
dependencies = [
"capstone",
- "expect-test",
+ "insta",
+ "jit",
+ "rand",
+ "yjit",
]
diff --git a/Cargo.toml b/Cargo.toml
index 3f373fdace..33010e65fb 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,12 +1,21 @@
-# Using Cargo's workspace feature to build all the Rust code in
-# into a single package.
-# TODO(alan) notes about rust version requirements. Undecided yet.
+# This is the root Cargo [workspace](https://doc.rust-lang.org/cargo/reference/workspaces.html)
+# and the root package for all the rust code that are statically linked into ruby. Rust tooling
+# limitations means all Rust code need to share a single archive library (staticlib) at the
+# integration point with non-rust code. (See rustlang/rust#44322 and #104707 for a taste of
+# the linking challenges.)
+#
+# Do not add required dependencies. This is a policy that helps downstream consumers and give
+# us tight control over what we ship. All of the optional dependencies are used exclusively
+# during development.
+#
+# Release builds avoid Cargo entirely because offline builds can fail even when none of the
+# optional dependencies are built (rust-lang/cargo#10352).
[workspace]
-members = ["zjit", "yjit"]
+members = ["zjit", "yjit", "jit"]
[package]
-name = "jit"
+name = "ruby"
version = "0.0.0"
edition = "2024"
rust-version = "1.85.0"
@@ -18,7 +27,7 @@ zjit = { path = "zjit", optional = true }
[lib]
crate-type = ["staticlib"]
-path = "jit.rs"
+path = "ruby.rs"
[features]
disasm = ["yjit?/disasm", "zjit?/disasm"]
@@ -27,11 +36,15 @@ yjit = [ "dep:yjit" ]
zjit = [ "dep:zjit" ]
[profile.dev]
-opt-level = 0
+opt-level = 1 # On 0, functions use so much stack space that we get stray `SystemStackError`s
debug = true
debug-assertions = true
overflow-checks = true
+[profile.test]
+inherits = "dev"
+opt-level = 0
+
[profile.dev_nodebug]
inherits = "dev"
diff --git a/LEGAL b/LEGAL
index a05cd6eaa3..2777aa2c14 100644
--- a/LEGAL
+++ b/LEGAL
@@ -704,32 +704,7 @@ mentioned below.
[ext/json/vendor/fpconv.c]
- This file is under the Boost Software License.
-
- >>>
- Boost Software License - Version 1.0 - August 17th, 2003
-
- Permission is hereby granted, free of charge, to any person or organization
- obtaining a copy of the software and accompanying documentation covered by
- this license (the "Software") to use, reproduce, display, distribute,
- execute, and transmit the Software, and to prepare derivative works of the
- Software, and to permit third-parties to whom the Software is furnished to
- do so, all subject to the following:
-
- The copyright notices in the Software and this entire statement, including
- the above license grant, this restriction and the following disclaimer,
- must be included in all copies of the Software, in whole or in part, and
- all derivative works of the Software, unless such copies or derivative
- works are solely in the form of machine-executable object code generated by
- a source language processor.
-
- 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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
- SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
- FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
- ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- DEALINGS IN THE SOFTWARE.
+ This file is under the {Boost Software License}[rdoc-ref:@Boost+Software+License+1.0].
[ext/json/vendor/jeaiii-ltoa.h]
@@ -738,7 +713,11 @@ mentioned below.
Copyright (c) 2022 James Edward Anhalt III - https://github.com/jeaiii/itoa
{MIT License}[rdoc-ref:@MIT+License]
-
+
+[ext/json/vendor/ryu.h]
+ This file is adapted from the Ryu algorithm by Ulf Adams https://github.com/ulfjack/ryu.
+ It is dual-licensed under {Apache License 2.0}[rdoc-ref:@Apache+License+2.0] OR
+ {Boost Software License 1.0}[rdoc-ref:@Boost+Software+License+1.0].
[ext/psych]
[test/psych]
@@ -1086,3 +1065,236 @@ mentioned below.
From ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change
paragraph 3 above is now null and void.
+
+== Boost Software License 1.0
+
+>>>
+ Boost Software License - Version 1.0 - August 17th, 2003
+
+ Permission is hereby granted, free of charge, to any person or organization
+ obtaining a copy of the software and accompanying documentation covered by
+ this license (the "Software") to use, reproduce, display, distribute,
+ execute, and transmit the Software, and to prepare derivative works of the
+ Software, and to permit third-parties to whom the Software is furnished to
+ do so, all subject to the following:
+
+ The copyright notices in the Software and this entire statement, including
+ the above license grant, this restriction and the following disclaimer,
+ must be included in all copies of the Software, in whole or in part, and
+ all derivative works of the Software, unless such copies or derivative
+ works are solely in the form of machine-executable object code generated by
+ a source language processor.
+
+ 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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+ SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+ FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ DEALINGS IN THE SOFTWARE.
+
+== Apache License 2.0
+
+>>>
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ a. You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ b. You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ c. You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ d. If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ >>>
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/NEWS.md b/NEWS.md
index b3d04feacf..9ff290ad75 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -1,277 +1,269 @@
-# NEWS for Ruby 3.5.0
+# NEWS for Ruby 4.1.0
This document is a list of user-visible feature changes
-since the **3.4.0** release, except for bug fixes.
+since the **4.0.0** release, except for bug fixes.
Note that each entry is kept to a minimum, see links for details.
## Language changes
-* `*nil` no longer calls `nil.to_a`, similar to how `**nil` does
- not call `nil.to_hash`. [[Feature #21047]]
+* `Module#clone` and `Module#dup` no longer rewrite the lexical scope of
+ copied methods. Constants and class variables resolve through the
+ original class, consistent with inheritance and mixins.
+ [[Feature #21981]]
## Core classes updates
Note: We're only listing outstanding class updates.
-* Kernel
-
- * `Kernel#inspect` now checks for the existence of a `#instance_variables_to_inspect` method,
- allowing control over which instance variables are displayed in the `#inspect` string:
-
- ```ruby
- class DatabaseConfig
- def initialize(host, user, password)
- @host = host
- @user = user
- @password = password
- end
-
- private def instance_variables_to_inspect = [:@host, :@user]
- end
-
- conf = DatabaseConfig.new("localhost", "root", "hunter2")
- conf.inspect #=> #<DatabaseConfig:0x0000000104def350 @host="localhost", @user="root">
- ```
-
- [[Feature #21219]]
-
-* Binding
-
- * `Binding#local_variables` does no longer include numbered parameters.
- Also, `Binding#local_variable_get` and `Binding#local_variable_set` reject
- to handle numbered parameters. [[Bug #21049]]
-
-* IO
+* Array
- * `IO.select` accepts +Float::INFINITY+ as a timeout argument.
- [[Feature #20610]]
+ * `Array#pack` accepts a new format `R` and `r` for unpacking unsigned
+ and signed LEB128 encoded integers. [[Feature #21785]]
+ * `Array#pack` accepts a new format `^` that returns the current offset.
+ Useful when combined with variable width formats like LEB128. [[Feature #21796]]
-* Math
+* ENV
- * `Math.log1p` and `Math.expm1` are added. [[Feature #21527]]
+ * `ENV.fetch_values` is added. It returns an array of values for the
+ given names, raising `KeyError` for missing names unless a block is
+ given. [[Feature #21781]]
-* Socket
-
- * `Socket.tcp` & `TCPSocket.new` accepts `open_timeout` as a keyword argument to specify
- the timeout for the initial connection. [[Feature #21347]]
-
-* Ractor
-
- * `Ractor::Port` class was added for a new synchronization mechanism
- to communicate between Ractors. [[Feature #21262]]
-
- ```ruby
- port1 = Ractor::Port.new
- port2 = Ractor::Port.new
- Ractor.new port1, port2 do |port1, port2|
- port1 << 1
- port2 << 11
- port1 << 2
- port2 << 12
- end
- 2.times{ p port1.receive } #=> 1, 2
- 2.times{ p port2.receive } #=> 11, 12
- ```
-
- `Ractor::Port` provides the following methods:
-
- * `Ractor::Port#receive`
- * `Ractor::Port#send` (or `Ractor::Port#<<`)
- * `Ractor::Port#close`
- * `Ractor::Port#closed?`
-
- As result, `Ractor.yield` and `Ractor#take` were removed.
+* Kernel
- * `Ractor#join` and `Ractor#value` were added to wait for the
- termination of a Ractor. These are similar to `Thread#join`
- and `Thread#value`.
+ * `Kernel#autoload_relative` and `Module#autoload_relative` are added.
+ These methods work like `autoload`, but resolve the file path relative
+ to the file where the method is called, similar to `require_relative`.
+ This makes it easier to autoload constants from files in the same
+ directory without hardcoding absolute paths or manipulating `$LOAD_PATH`.
+ [[Feature #15330]]
- * `Ractor#monitor` and `Ractor#unmonitor` were added as low-level
- interfaces used internally to implement `Ractor#join`.
+* MatchData
- * `Ractor.select` now only accepts Ractors and Ports. If Ractors are given,
- it returns when a Ractor terminates.
+ * `MatchData#integer_at` is added. It converts the matched substring to
+ integer and return the result. [[Feature #21932]]
- * `Ractor#default_port` was added. Each `Ractor` has a default port,
- which is used by `Ractor.send`, `Ractor.receive`.
+* Regexp
- * `Ractor#close_incoming` and `Ractor#close_outgoing` were removed.
+ * All instances of `Regexp` are now frozen, not just literals.
+ Subclasses of `Regexp` are not frozen for compatibility.
+ [[Feature #8948]]
* Set
- * Set is now a core class, instead of an autoloaded stdlib class.
- [[Feature #21216]]
-
-* String
-
- * Update Unicode to Version 16.0.0 and Emoji Version 16.0.
- [[Feature #19908]][[Feature #20724]] (also applies to Regexp)
-
-* Thread
-
- * Introduce support for `Thread#raise(cause:)` argument similar to
- `Kernel#raise`. [[Feature #21360]]
-
-* Fiber
-
- * Introduce support for `Fiber#raise(cause:)` argument similar to
- `Kernel#raise`. [[Feature #21360]]
-
-* Fiber::Scheduler
-
- * Introduce `Fiber::Scheduler#fiber_interrupt` to interrupt a fiber with a
- given exception. The initial use case is to interrupt a fiber that is
- waiting on a blocking IO operation when the IO operation is closed.
- [[Feature #21166]]
-
-* Pathname
-
- * Pathname has been promoted from a default gem to a core class of Ruby.
- [[Feature #17473]]
+ * A deprecated behavior, `Set#to_set`, `Range#to_set`, and
+ `Enumerable#to_set` accepting arguments, was removed. [[Feature #21390]]
## Stdlib updates
-The following bundled gems are promoted from default gems.
+### The following bundled gems are added.
-* ostruct 0.6.3
-* pstore 0.2.0
-* benchmark 0.4.1
-* logger 1.7.0
-* rdoc 6.14.2
-* win32ole 1.9.2
-* irb 1.15.2
-* reline 0.6.2
-* readline 0.0.4
-* fiddle 1.1.8
We only list stdlib changes that are notable feature changes.
Other changes are listed in the following sections. We also listed release
-history from the previous bundled version that is Ruby 3.3.0 if it has GitHub
+history from the previous bundled version that is Ruby 3.4.0 if it has GitHub
releases.
-The following default gem is added.
-
-* win32-registry 0.1.0
-
-The following default gems are updated.
-
-* RubyGems 3.8.0.dev
-* bundler 2.8.0.dev
-* erb 5.0.2
-* etc 1.4.6
-* io-console 0.8.1
-* io-nonblock 0.3.2
-* io-wait 0.3.2
-* json 2.13.2
-* optparse 0.7.0.dev.2
-* prism 1.4.0
-* psych 5.2.6
-* resolv 0.6.2
-* stringio 3.1.8.dev
-* strscan 3.1.6.dev
-* uri 1.0.3
-* weakref 0.1.4
-
-The following bundled gems are added.
-
-
-The following bundled gems are updated.
-
-* minitest 5.25.5
-* rake 13.3.0
-* test-unit 3.7.0
-* rexml 3.4.1
-* net-imap 0.5.9
-* net-smtp 0.5.1
-* matrix 0.4.3
-* prime 0.1.4
-* rbs 3.9.4
-* debug 1.11.0
-* base64 0.3.0
-* bigdecimal 3.2.2
-* drb 2.2.3
-* syslog 0.3.0
-* csv 3.3.5
-* repl_type_completor 0.1.11
+### The following bundled gems are promoted from default gems.
+
+* tsort 0.2.0
+* win32-registry 0.1.2
+
+### The following default gem is added.
+
+### The following default gems are updated.
+
+* RubyGems 4.1.0.dev
+ * 4.0.3 to [v4.0.4][RubyGems-v4.0.4], [v4.0.5][RubyGems-v4.0.5], [v4.0.6][RubyGems-v4.0.6], [v4.0.7][RubyGems-v4.0.7], [v4.0.8][RubyGems-v4.0.8], [v4.0.9][RubyGems-v4.0.9], [v4.0.10][RubyGems-v4.0.10], [v4.0.11][RubyGems-v4.0.11], [v4.0.12][RubyGems-v4.0.12], [v4.0.13][RubyGems-v4.0.13]
+* bundler 4.1.0.dev
+ * 4.0.3 to [v4.0.4][bundler-v4.0.4], [v4.0.5][bundler-v4.0.5], [v4.0.6][bundler-v4.0.6], [v4.0.7][bundler-v4.0.7], [v4.0.8][bundler-v4.0.8], [v4.0.9][bundler-v4.0.9], [v4.0.10][bundler-v4.0.10], [v4.0.11][bundler-v4.0.11], [v4.0.12][bundler-v4.0.12], [v4.0.13][bundler-v4.0.13]
+* erb 6.0.4
+ * 6.0.1 to [v6.0.1.1][erb-v6.0.1.1], [v6.0.2][erb-v6.0.2], [v6.0.3][erb-v6.0.3], [v6.0.4][erb-v6.0.4]
+* ipaddr 1.2.9
+ * 1.2.8 to [v1.2.9][ipaddr-v1.2.9]
+* json 2.19.8
+ * 2.18.0 to [v2.18.1][json-v2.18.1], [v2.19.0][json-v2.19.0], [v2.19.1][json-v2.19.1], [v2.19.2][json-v2.19.2], [v2.19.3][json-v2.19.3], [v2.19.4][json-v2.19.4], [v2.19.5][json-v2.19.5], [v2.19.6][json-v2.19.6], [v2.19.7][json-v2.19.7]
+* openssl 4.0.2
+ * 4.0.0 to [v4.0.1][openssl-v4.0.1], [v4.0.2][openssl-v4.0.2]
+* prism 1.9.0
+ * 1.7.0 to [v1.8.0][prism-v1.8.0], [v1.8.1][prism-v1.8.1], [v1.9.0][prism-v1.9.0]
+* psych 5.4.0
+* resolv 0.7.1
+ * 0.7.0 to [v0.7.1][resolv-v0.7.1]
+* stringio 3.2.1.dev
+* strscan 3.1.9.dev
+ * 3.1.6 to [v3.1.7][strscan-v3.1.7], [v3.1.8][strscan-v3.1.8]
+* syntax_suggest 3.0.0
+* timeout 0.6.1
+ * 0.6.0 to [v0.6.1][timeout-v0.6.1]
+* zlib 3.2.3
+ * 3.2.2 to [v3.2.3][zlib-v3.2.3]
+
+### The following bundled gems are updated.
+
+* minitest 6.0.6
+* rake 13.4.2
+ * 13.3.1 to [v13.4.0][rake-v13.4.0], [v13.4.1][rake-v13.4.1], [v13.4.2][rake-v13.4.2]
+* test-unit 3.7.8
+ * 3.7.5 to [3.7.6][test-unit-3.7.6], [3.7.7][test-unit-3.7.7], [3.7.8][test-unit-3.7.8]
+* net-imap 0.6.4
+ * 0.6.2 to [v0.6.3][net-imap-v0.6.3], [v0.6.4][net-imap-v0.6.4]
+* rbs 4.0.2
+ * 3.10.0 to [v3.10.1][rbs-v3.10.1], [v3.10.2][rbs-v3.10.2], [v3.10.3][rbs-v3.10.3], [v3.10.4][rbs-v3.10.4], [v4.0.0.dev.5][rbs-v4.0.0.dev.5], [v4.0.0][rbs-v4.0.0], [v4.0.2][rbs-v4.0.2]
+* typeprof 0.32.0
+* mutex_m 0.3.0
+* bigdecimal 4.1.2
+ * 4.0.1 to [v4.1.0][bigdecimal-v4.1.0], [v4.1.1][bigdecimal-v4.1.1], [v4.1.2][bigdecimal-v4.1.2]
+* resolv-replace 0.2.0
+ * 0.1.1 to [v0.2.0][resolv-replace-v0.2.0]
+* syslog 0.4.0
+ * 0.3.0 to [v0.4.0][syslog-v0.4.0]
+* repl_type_completor 0.1.15
+ * 0.1.12 to [v0.1.13][repl_type_completor-v0.1.13], [v0.1.14][repl_type_completor-v0.1.14], [v0.1.15][repl_type_completor-v0.1.15]
+* pstore 0.2.1
+ * 0.2.0 to [v0.2.1][pstore-v0.2.1]
+* rdoc 7.2.0
+ * 7.0.3 to [v7.0.4][rdoc-v7.0.4], [v7.1.0][rdoc-v7.1.0], [v7.2.0][rdoc-v7.2.0]
+* win32ole 1.9.3
+ * 1.9.2 to [v1.9.3][win32ole-v1.9.3]
+* irb 1.18.0
+ * 1.16.0 to [v1.17.0][irb-v1.17.0], [v1.18.0][irb-v1.18.0]
+
+### RubyGems and Bundler
+
+Ruby 4.0 bundled RubyGems and Bundler version 4. see the following links for details.
## Supported platforms
## Compatibility issues
-* The following methods were removed from Ractor due because of `Ractor::Port`:
+## Stdlib compatibility issues
- * `Ractor.yield`
- * `Ractor#take`
- * `Ractor#close_incoming`
- * `Ractor#close_outgoging`
+## C API updates
- [[Feature #21262]]
+### Embedded TypedData
-## Stdlib compatibility issues
+* The `RUBY_TYPED_EMBEDDABLE` flag is now public and documented and can be used by C extensions.
+ It allows allocating C structs directly into Ruby object slots, which reduces pointer chasing,
+ and in some case memory usage.
+ See the C extension documentation for details. [[Feature #21853]]
-* CGI library is removed from the default gems. Now we only provide `cgi/escape` for
- the following methods:
+* Added new C23 inspired allocator functions, that takes the previous memory size.
+ This allow the Ruby GC to better keep track of memory usage, improving its heuristics.
+ It also improves the performance of system allocators that support C23 `free_sized`.
- * `CGI.escape` and `CGI.unescape`
- * `CGI.escapeHTML` and `CGI.unescapeHTML`
- * `CGI.escapeURIComponent` and `CGI.unescapeURIComponent`
- * `CGI.escapeElement` and `CGI.unescapeElement`
+ However, it is important to note that passing an incorrect size to these function is undefined
+ behavior and may result in crashes or memory leaks.
- [[Feature #21258]]
+ - `ruby_xfree_sized(void *ptr, size_t size)`
+ - `ruby_xrealloc_sized(void *ptr, size_t newsiz, size_t oldsiz)`
+ - `ruby_xrealloc2_sized(void *ptr, size_t newelems, size_t newsiz, size_t oldelems)`
-* With the move of `Set` from stdlib to core class, `set/sorted_set.rb` has
- been removed, and `SortedSet` is no longer an autoloaded constant. Please
- install the `sorted_set` gem and `require 'sorted_set'` to use `SortedSet`.
- [[Feature #21287]]
+ [[Feature #21861]]
-## C API updates
+### Removed APIs
-* IO
+The following APIs, which have been deprecated for many years, are removed.
+[[Feature #21768]]
- * `rb_thread_fd_close` is deprecated and now a no-op. If you need to expose
- file descriptors from C extensions to Ruby code, create an `IO` instance
- using `RUBY_IO_MODE_EXTERNAL` and use `rb_io_close(io)` to close it (this
- also interrupts and waits for all pending operations on the `IO`
- instance). Directly closing file descriptors does not interrupt pending
- operations, and may lead to undefined behaviour. In other words, if two
- `IO` objects share the same file descriptor, closing one does not affect
- the other. [[Feature #18455]]
+* old postponed job functions,
+* untyped data object type/functions,
+* old APIs to allocate a data object,
+* taintedness/trustedness enums/macros,
+* `rb_gc_force_recycle` function,
+* `rb_iterate` function,
+* and some functions and constants for internal use.
## Implementation improvements
+### Ractor
+
+A lot of work has gone into making Ractors more stable, performant, and usable. These improvements bring Ractor implementation closer to leaving experimental status.
+
## JIT
-* YJIT
- * YJIT stats
- * `ratio_in_yjit` no longer works in the default build.
- Use `--enable-yjit=stats` on `configure` to enable it on `--yjit-stats`.
- * Add `invalidate_everything` to default stats, which is
- incremented when every code is invalidated by TracePoint.
- * Add `mem_size:` and `call_threshold:` options to `RubyVM::YJIT.enable`.
-* ZJIT
- * Add an experimental method-based JIT compiler.
- Use `--enable-zjit` on `configure` to enable the `--zjit` support.
- * As of Ruby 3.5.0-preview2, ZJIT is not yet ready for speeding up most benchmarks.
- Please refrain from evaluating ZJIT just yet. Stay tuned for the Ruby 3.5 release.
-* RJIT
- * `--rjit` is removed. We will move the implementation of the third-party JIT API
- to the [ruby/rjit](https://github.com/ruby/rjit) repository.
-
-[Feature #17473]: https://bugs.ruby-lang.org/issues/17473
-[Feature #18455]: https://bugs.ruby-lang.org/issues/18455
-[Feature #19908]: https://bugs.ruby-lang.org/issues/19908
-[Feature #20610]: https://bugs.ruby-lang.org/issues/20610
-[Feature #20724]: https://bugs.ruby-lang.org/issues/20724
-[Feature #21047]: https://bugs.ruby-lang.org/issues/21047
-[Bug #21049]: https://bugs.ruby-lang.org/issues/21049
-[Feature #21166]: https://bugs.ruby-lang.org/issues/21166
-[Feature #21216]: https://bugs.ruby-lang.org/issues/21216
-[Feature #21219]: https://bugs.ruby-lang.org/issues/21219
-[Feature #21258]: https://bugs.ruby-lang.org/issues/21258
-[Feature #21262]: https://bugs.ruby-lang.org/issues/21262
-[Feature #21287]: https://bugs.ruby-lang.org/issues/21287
-[Feature #21347]: https://bugs.ruby-lang.org/issues/21347
-[Feature #21360]: https://bugs.ruby-lang.org/issues/21360
-[Feature #21527]: https://bugs.ruby-lang.org/issues/21527
+[Feature #8948]: https://bugs.ruby-lang.org/issues/8948
+[Feature #15330]: https://bugs.ruby-lang.org/issues/15330
+[Feature #21390]: https://bugs.ruby-lang.org/issues/21390
+[Feature #21768]: https://bugs.ruby-lang.org/issues/21768
+[Feature #21785]: https://bugs.ruby-lang.org/issues/21785
+[Feature #21796]: https://bugs.ruby-lang.org/issues/21796
+[Feature #21853]: https://bugs.ruby-lang.org/issues/21853
+[Feature #21861]: https://bugs.ruby-lang.org/issues/21861
+[Feature #21932]: https://bugs.ruby-lang.org/issues/21932
+[Feature #21981]: https://bugs.ruby-lang.org/issues/21981
+[RubyGems-v4.0.4]: https://github.com/rubygems/rubygems/releases/tag/v4.0.4
+[RubyGems-v4.0.5]: https://github.com/rubygems/rubygems/releases/tag/v4.0.5
+[RubyGems-v4.0.6]: https://github.com/rubygems/rubygems/releases/tag/v4.0.6
+[RubyGems-v4.0.7]: https://github.com/rubygems/rubygems/releases/tag/v4.0.7
+[RubyGems-v4.0.8]: https://github.com/rubygems/rubygems/releases/tag/v4.0.8
+[RubyGems-v4.0.9]: https://github.com/rubygems/rubygems/releases/tag/v4.0.9
+[RubyGems-v4.0.10]: https://github.com/rubygems/rubygems/releases/tag/v4.0.10
+[RubyGems-v4.0.11]: https://github.com/rubygems/rubygems/releases/tag/v4.0.11
+[RubyGems-v4.0.12]: https://github.com/rubygems/rubygems/releases/tag/v4.0.12
+[RubyGems-v4.0.13]: https://github.com/rubygems/rubygems/releases/tag/v4.0.13
+[bundler-v4.0.4]: https://github.com/rubygems/rubygems/releases/tag/bundler-v4.0.4
+[bundler-v4.0.5]: https://github.com/rubygems/rubygems/releases/tag/bundler-v4.0.5
+[bundler-v4.0.6]: https://github.com/rubygems/rubygems/releases/tag/bundler-v4.0.6
+[bundler-v4.0.7]: https://github.com/rubygems/rubygems/releases/tag/bundler-v4.0.7
+[bundler-v4.0.8]: https://github.com/rubygems/rubygems/releases/tag/bundler-v4.0.8
+[bundler-v4.0.9]: https://github.com/rubygems/rubygems/releases/tag/bundler-v4.0.9
+[bundler-v4.0.10]: https://github.com/rubygems/rubygems/releases/tag/bundler-v4.0.10
+[bundler-v4.0.11]: https://github.com/rubygems/rubygems/releases/tag/bundler-v4.0.11
+[bundler-v4.0.12]: https://github.com/rubygems/rubygems/releases/tag/bundler-v4.0.12
+[bundler-v4.0.13]: https://github.com/rubygems/rubygems/releases/tag/bundler-v4.0.13
+[erb-v6.0.1.1]: https://github.com/ruby/erb/releases/tag/v6.0.1.1
+[erb-v6.0.2]: https://github.com/ruby/erb/releases/tag/v6.0.2
+[erb-v6.0.3]: https://github.com/ruby/erb/releases/tag/v6.0.3
+[erb-v6.0.4]: https://github.com/ruby/erb/releases/tag/v6.0.4
+[ipaddr-v1.2.9]: https://github.com/ruby/ipaddr/releases/tag/v1.2.9
+[json-v2.18.1]: https://github.com/ruby/json/releases/tag/v2.18.1
+[json-v2.19.0]: https://github.com/ruby/json/releases/tag/v2.19.0
+[json-v2.19.1]: https://github.com/ruby/json/releases/tag/v2.19.1
+[json-v2.19.2]: https://github.com/ruby/json/releases/tag/v2.19.2
+[json-v2.19.3]: https://github.com/ruby/json/releases/tag/v2.19.3
+[json-v2.19.4]: https://github.com/ruby/json/releases/tag/v2.19.4
+[json-v2.19.5]: https://github.com/ruby/json/releases/tag/v2.19.5
+[json-v2.19.6]: https://github.com/ruby/json/releases/tag/v2.19.6
+[json-v2.19.7]: https://github.com/ruby/json/releases/tag/v2.19.7
+[openssl-v4.0.1]: https://github.com/ruby/openssl/releases/tag/v4.0.1
+[openssl-v4.0.2]: https://github.com/ruby/openssl/releases/tag/v4.0.2
+[prism-v1.8.0]: https://github.com/ruby/prism/releases/tag/v1.8.0
+[prism-v1.8.1]: https://github.com/ruby/prism/releases/tag/v1.8.1
+[prism-v1.9.0]: https://github.com/ruby/prism/releases/tag/v1.9.0
+[resolv-v0.7.1]: https://github.com/ruby/resolv/releases/tag/v0.7.1
+[strscan-v3.1.7]: https://github.com/ruby/strscan/releases/tag/v3.1.7
+[strscan-v3.1.8]: https://github.com/ruby/strscan/releases/tag/v3.1.8
+[timeout-v0.6.1]: https://github.com/ruby/timeout/releases/tag/v0.6.1
+[zlib-v3.2.3]: https://github.com/ruby/zlib/releases/tag/v3.2.3
+[rake-v13.4.0]: https://github.com/ruby/rake/releases/tag/v13.4.0
+[rake-v13.4.1]: https://github.com/ruby/rake/releases/tag/v13.4.1
+[rake-v13.4.2]: https://github.com/ruby/rake/releases/tag/v13.4.2
+[test-unit-3.7.6]: https://github.com/test-unit/test-unit/releases/tag/3.7.6
+[test-unit-3.7.7]: https://github.com/test-unit/test-unit/releases/tag/3.7.7
+[test-unit-3.7.8]: https://github.com/test-unit/test-unit/releases/tag/3.7.8
+[net-imap-v0.6.3]: https://github.com/ruby/net-imap/releases/tag/v0.6.3
+[net-imap-v0.6.4]: https://github.com/ruby/net-imap/releases/tag/v0.6.4
+[rbs-v3.10.1]: https://github.com/ruby/rbs/releases/tag/v3.10.1
+[rbs-v3.10.2]: https://github.com/ruby/rbs/releases/tag/v3.10.2
+[rbs-v3.10.3]: https://github.com/ruby/rbs/releases/tag/v3.10.3
+[rbs-v3.10.4]: https://github.com/ruby/rbs/releases/tag/v3.10.4
+[rbs-v4.0.0.dev.5]: https://github.com/ruby/rbs/releases/tag/v4.0.0.dev.5
+[rbs-v4.0.0]: https://github.com/ruby/rbs/releases/tag/v4.0.0
+[rbs-v4.0.2]: https://github.com/ruby/rbs/releases/tag/v4.0.2
+[bigdecimal-v4.1.0]: https://github.com/ruby/bigdecimal/releases/tag/v4.1.0
+[bigdecimal-v4.1.1]: https://github.com/ruby/bigdecimal/releases/tag/v4.1.1
+[bigdecimal-v4.1.2]: https://github.com/ruby/bigdecimal/releases/tag/v4.1.2
+[resolv-replace-v0.2.0]: https://github.com/ruby/resolv-replace/releases/tag/v0.2.0
+[syslog-v0.4.0]: https://github.com/ruby/syslog/releases/tag/v0.4.0
+[repl_type_completor-v0.1.13]: https://github.com/ruby/repl_type_completor/releases/tag/v0.1.13
+[repl_type_completor-v0.1.14]: https://github.com/ruby/repl_type_completor/releases/tag/v0.1.14
+[repl_type_completor-v0.1.15]: https://github.com/ruby/repl_type_completor/releases/tag/v0.1.15
+[pstore-v0.2.1]: https://github.com/ruby/pstore/releases/tag/v0.2.1
+[rdoc-v7.0.4]: https://github.com/ruby/rdoc/releases/tag/v7.0.4
+[rdoc-v7.1.0]: https://github.com/ruby/rdoc/releases/tag/v7.1.0
+[rdoc-v7.2.0]: https://github.com/ruby/rdoc/releases/tag/v7.2.0
+[win32ole-v1.9.3]: https://github.com/ruby/win32ole/releases/tag/v1.9.3
+[irb-v1.17.0]: https://github.com/ruby/irb/releases/tag/v1.17.0
+[irb-v1.18.0]: https://github.com/ruby/irb/releases/tag/v1.18.0
diff --git a/README.EXT b/README.EXT
deleted file mode 100644
index 48b8d964c4..0000000000
--- a/README.EXT
+++ /dev/null
@@ -1 +0,0 @@
-Moved to doc/extension.rdoc
diff --git a/README.EXT.ja b/README.EXT.ja
deleted file mode 100644
index f884ecbb0e..0000000000
--- a/README.EXT.ja
+++ /dev/null
@@ -1 +0,0 @@
-doc/extension.ja.rdocã«ç§»å‹•ã—ã¾ã—ãŸ
diff --git a/README.ja.md b/README.ja.md
index 278285dc83..9bbc3a83a5 100644
--- a/README.ja.md
+++ b/README.ja.md
@@ -4,6 +4,8 @@
[![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)
+[English](rdoc-ref:README.md)
+
# Rubyã¨ã¯
Rubyã¯ã‚·ãƒ³ãƒ—ルã‹ã¤å¼·åŠ›ãªã‚ªãƒ–ジェクト指å‘スクリプト言語ã§ã™ï¼Ž Rubyã¯ç´”粋ãªã‚ªãƒ–ジェクト指å‘言語ã¨ã—ã¦è¨­è¨ˆã•れã¦ã„ã‚‹ã®ã§ï¼Œ
diff --git a/README.md b/README.md
index 5ed312cca8..02435b419e 100644
--- a/README.md
+++ b/README.md
@@ -3,6 +3,8 @@
[![Actions Status: Windows](https://github.com/ruby/ruby/workflows/Windows/badge.svg)](https://github.com/ruby/ruby/actions?query=workflow%3A"Windows")
[![Travis Status](https://app.travis-ci.com/ruby/ruby.svg?branch=master)](https://app.travis-ci.com/ruby/ruby)
+[日本語](rdoc-ref:README.ja.md)
+
# What is Ruby?
Ruby is an interpreted object-oriented programming language often
diff --git a/addr2line.c b/addr2line.c
index 745364cc0f..19a6a425c1 100644
--- a/addr2line.c
+++ b/addr2line.c
@@ -637,12 +637,13 @@ follow_debuglink_build_id(const char *build_id, size_t build_id_size, int num_tr
obj_info_t **objp, line_info_t *lines, int offset, FILE *errout)
{
static const char global_debug_dir[] = "/usr/lib/debug/.build-id/";
+ static const char debug_suffix[] = ".debug";
const size_t global_debug_dir_len = sizeof(global_debug_dir) - 1;
char *p;
obj_info_t *o1 = *objp, *o2;
size_t i;
- if (PATH_MAX < global_debug_dir_len + 1 + build_id_size * 2 + 6) return;
+ if (PATH_MAX < global_debug_dir_len + build_id_size * 2 + sizeof(debug_suffix)) return;
memcpy(binary_filename, global_debug_dir, global_debug_dir_len);
p = binary_filename + global_debug_dir_len;
@@ -653,7 +654,7 @@ follow_debuglink_build_id(const char *build_id, size_t build_id_size, int num_tr
*p++ = tbl[n % 16];
if (i == 0) *p++ = '/';
}
- strcpy(p, ".debug");
+ memcpy(p, debug_suffix, sizeof(debug_suffix));
append_obj(objp);
o2 = *objp;
diff --git a/array.c b/array.c
index 9f13b1bf51..db4c2c4802 100644
--- a/array.c
+++ b/array.c
@@ -29,6 +29,8 @@
#include "ruby/st.h"
#include "ruby/thread.h"
#include "ruby/util.h"
+#include "ruby/ractor.h"
+#include "shape.h"
#include "vm_core.h"
#include "builtin.h"
@@ -107,10 +109,12 @@ should_be_T_ARRAY(VALUE ary)
} while (0)
#define FL_UNSET_SHARED(ary) FL_UNSET((ary), RARRAY_SHARED_FLAG)
+#define ARY_SET_PTR_FORCE(ary, p) \
+ (RARRAY(ary)->as.heap.ptr = (p))
#define ARY_SET_PTR(ary, p) do { \
RUBY_ASSERT(!ARY_EMBED_P(ary)); \
RUBY_ASSERT(!OBJ_FROZEN(ary)); \
- RARRAY(ary)->as.heap.ptr = (p); \
+ ARY_SET_PTR_FORCE(ary, p); \
} while (0)
#define ARY_SET_EMBED_LEN(ary, n) do { \
long tmp_n = (n); \
@@ -148,11 +152,13 @@ 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_FORCE(ary, n) \
+ RARRAY(ary)->as.heap.aux.capa = (n);
#define ARY_SET_CAPA(ary, n) do { \
RUBY_ASSERT(!ARY_EMBED_P(ary)); \
RUBY_ASSERT(!ARY_SHARED_P(ary)); \
RUBY_ASSERT(!OBJ_FROZEN(ary)); \
- RARRAY(ary)->as.heap.aux.capa = (n); \
+ ARY_SET_CAPA_FORCE(ary, n); \
} while (0)
#define ARY_SHARED_ROOT_OCCUPIED(ary) (!OBJ_FROZEN(ary) && ARY_SHARED_ROOT_REFCNT(ary) == 1)
@@ -189,7 +195,9 @@ ary_embed_capa(VALUE ary)
static size_t
ary_embed_size(long capa)
{
- return offsetof(struct RArray, as.ary) + (sizeof(VALUE) * capa);
+ size_t size = offsetof(struct RArray, as.ary) + (sizeof(VALUE) * capa);
+ if (size < sizeof(struct RArray)) size = sizeof(struct RArray);
+ return size;
}
static bool
@@ -354,7 +362,7 @@ ary_heap_alloc_buffer(size_t capa)
static void
ary_heap_free_ptr(VALUE ary, const VALUE *ptr, long size)
{
- ruby_sized_xfree((void *)ptr, size);
+ ruby_xfree_sized((void *)ptr, size);
}
static void
@@ -380,13 +388,14 @@ rb_ary_make_embedded(VALUE ary)
if (!ARY_EMBED_P(ary)) {
const VALUE *buf = ARY_HEAP_PTR(ary);
long len = ARY_HEAP_LEN(ary);
+ long capa = ARY_HEAP_CAPA(ary);
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));
+ ary_heap_free_ptr(ary, buf, capa * sizeof(VALUE));
}
}
@@ -421,7 +430,7 @@ ary_resize_capa(VALUE ary, long capacity)
if (len > capacity) len = capacity;
MEMCPY((VALUE *)RARRAY(ary)->as.ary, ptr, VALUE, len);
- ary_heap_free_ptr(ary, ptr, old_capa);
+ ary_heap_free_ptr(ary, ptr, old_capa * sizeof(VALUE));
FL_SET_EMBED(ary);
ARY_SET_LEN(ary, len);
@@ -560,8 +569,8 @@ rb_ary_cancel_sharing(VALUE ary)
VALUE *ptr = ary_heap_alloc_buffer(len);
MEMCPY(ptr, ARY_HEAP_PTR(ary), VALUE, len);
rb_ary_unshare(ary);
- ARY_SET_CAPA(ary, len);
- ARY_SET_PTR(ary, ptr);
+ ARY_SET_CAPA_FORCE(ary, len);
+ ARY_SET_PTR_FORCE(ary, ptr);
}
rb_gc_writebarrier_remember(ary);
@@ -679,22 +688,22 @@ 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,
- T_ARRAY | RARRAY_EMBED_FLAG | (RGENGC_WB_PROTECTED_ARRAY ? FL_WB_PROTECTED : 0),
- size, 0);
- /* Created array is:
- * FL_SET_EMBED((VALUE)ary);
- * ARY_SET_EMBED_LEN((VALUE)ary, 0);
- */
- return (VALUE)ary;
+ /* Created array is:
+ * FL_SET_EMBED((VALUE)ary);
+ * ARY_SET_EMBED_LEN((VALUE)ary, 0);
+ */
+ return rb_newobj_of(klass, T_ARRAY | RARRAY_EMBED_FLAG, size);
}
static VALUE
ary_alloc_heap(VALUE klass)
{
- NEWOBJ_OF(ary, struct RArray, klass,
- T_ARRAY | (RGENGC_WB_PROTECTED_ARRAY ? FL_WB_PROTECTED : 0),
- sizeof(struct RArray), 0);
+ NEWOBJ_OF(ary, struct RArray, klass, T_ARRAY, sizeof(struct RArray));
+
+ ary->as.heap.len = 0;
+ ary->as.heap.aux.capa = 0;
+ ary->as.heap.ptr = NULL;
+
return (VALUE)ary;
}
@@ -792,23 +801,21 @@ 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);
- /* Created array is:
- * FL_SET_EMBED((VALUE)ary);
- * ARY_SET_EMBED_LEN((VALUE)ary, 0);
- */
- return (VALUE)ary;
+ /* Created array is:
+ * FL_SET_EMBED((VALUE)ary);
+ * ARY_SET_EMBED_LEN((VALUE)ary, 0);
+ */
+ return rb_ec_newobj_of(ec, klass, T_ARRAY | RARRAY_EMBED_FLAG, size);
}
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);
- return (VALUE)ary;
+ VALUE ary = rb_ec_newobj_of(ec, klass, T_ARRAY, sizeof(struct RArray));
+ RARRAY(ary)->as.heap.len = 0;
+ RARRAY(ary)->as.heap.aux.capa = 0;
+ RARRAY(ary)->as.heap.ptr = NULL;
+ return ary;
}
static VALUE
@@ -903,6 +910,7 @@ init_fake_ary_flags(void)
struct RArray fake_ary = {0};
fake_ary.basic.flags = T_ARRAY;
VALUE ary = (VALUE)&fake_ary;
+ RBASIC_SET_SHAPE_ID(ary, ROOT_SHAPE_ID | SHAPE_ID_LAYOUT_OTHER);
rb_ary_freeze(ary);
return fake_ary.basic.flags;
}
@@ -1439,10 +1447,12 @@ rb_ary_pop(VALUE ary)
{
ary_resize_capa(ary, n * 2);
}
- --n;
- ARY_SET_LEN(ary, n);
+
+ VALUE obj = RARRAY_AREF(ary, n - 1);
+
+ ARY_SET_LEN(ary, n - 1);
ary_verify(ary);
- return RARRAY_AREF(ary, n);
+ return obj;
}
/*
@@ -1770,14 +1780,10 @@ 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[offset] -> object or nil
+ * self[offset, size] -> 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
*
* Returns elements from +self+; does not modify +self+.
*
@@ -1785,27 +1791,27 @@ static VALUE rb_ary_aref2(VALUE ary, VALUE b, VALUE e);
*
* a = [:foo, 'bar', 2]
*
- * # Single argument index: returns one element.
+ * # Single argument offset: 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.
+ * # Arguments offset and size: returns an array.
* a[1, 2] # => ["bar", 2]
- * a[-2, 2] # => ["bar", 2] # Negative start counts backwards from end.
+ * a[-2, 2] # => ["bar", 2] # Negative offset 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 +offset+ is given, returns the element at offset +offset+:
*
* 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 +offset+ is negative, counts backwards from the end of +self+:
*
* a = [:foo, 'bar', 2]
* a[-1] # => 2
@@ -1813,29 +1819,29 @@ 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 +offset+ and +size+ are given,
+ * returns a new array of size +size+ containing successive elements beginning at offset +offset+:
*
* a = [:foo, 'bar', 2]
* a[0, 2] # => [:foo, "bar"]
* a[1, 2] # => ["bar", 2]
*
- * If <tt>start + length</tt> is greater than <tt>self.length</tt>,
- * returns all elements from offset +start+ to the end:
+ * If <tt>offset + size</tt> is greater than <tt>self.size</tt>,
+ * returns all elements from offset +offset+ to the end:
*
* a = [:foo, 'bar', 2]
* a[0, 4] # => [:foo, "bar", 2]
* a[1, 3] # => ["bar", 2]
* a[2, 2] # => [2]
*
- * If <tt>start == self.size</tt> and <tt>length >= 0</tt>,
+ * If <tt>offset == self.size</tt> and <tt>size >= 0</tt>,
* returns a new empty array.
*
- * If +length+ is negative, returns +nil+.
+ * If +size+ is negative, returns +nil+.
*
* When a single Range argument +range+ is given,
- * treats <tt>range.min</tt> as +start+ above
- * and <tt>range.size</tt> as +length+ above:
+ * treats <tt>range.min</tt> as +offset+ above
+ * and <tt>range.size</tt> as +size+ above:
*
* a = [:foo, 'bar', 2]
* a[0..1] # => [:foo, "bar"]
@@ -2070,6 +2076,95 @@ rb_ary_fetch(int argc, VALUE *argv, VALUE ary)
}
/*
+ * call-seq:
+ * find(if_none_proc = nil) {|element| ... } -> object or nil
+ * find(if_none_proc = nil) -> enumerator
+ *
+ * Returns the first element for which the block returns a truthy value.
+ *
+ * With a block given, calls the block with successive elements of the array;
+ * returns the first element for which the block returns a truthy value:
+ *
+ * [1, 3, 5].find {|element| element > 2} # => 3
+ *
+ * If no such element is found, calls +if_none_proc+ and returns its return value.
+ *
+ * [1, 3, 5].find(proc {-1}) {|element| element > 12} # => -1
+ *
+ * With no block given, returns an Enumerator.
+ *
+ */
+
+static VALUE
+rb_ary_find(int argc, VALUE *argv, VALUE ary)
+{
+ VALUE if_none;
+ long idx;
+
+ RETURN_ENUMERATOR(ary, argc, argv);
+ if_none = rb_check_arity(argc, 0, 1) ? argv[0] : Qnil;
+
+ for (idx = 0; idx < RARRAY_LEN(ary); idx++) {
+ VALUE elem = RARRAY_AREF(ary, idx);
+ if (RTEST(rb_yield(elem))) {
+ return elem;
+ }
+ }
+
+ if (!NIL_P(if_none)) {
+ return rb_funcallv(if_none, idCall, 0, 0);
+ }
+ return Qnil;
+}
+
+/*
+ * call-seq:
+ * rfind(if_none_proc = nil) {|element| ... } -> object or nil
+ * rfind(if_none_proc = nil) -> enumerator
+ *
+ * Returns the last element for which the block returns a truthy value.
+ *
+ * With a block given, calls the block with successive elements of the array in
+ * reverse order; returns the first element for which the block returns a truthy
+ * value:
+ *
+ * [1, 2, 3, 4, 5, 6].rfind {|element| element < 5} # => 4
+ *
+ * If no such element is found, calls +if_none_proc+ and returns its return value.
+ *
+ * [1, 2, 3, 4].rfind(proc {0}) {|element| element < -2} # => 0
+ *
+ * With no block given, returns an Enumerator.
+ *
+ */
+
+static VALUE
+rb_ary_rfind(int argc, VALUE *argv, VALUE ary)
+{
+ VALUE if_none;
+ long len, idx;
+
+ RETURN_ENUMERATOR(ary, argc, argv);
+ if_none = rb_check_arity(argc, 0, 1) ? argv[0] : Qnil;
+
+ idx = RARRAY_LEN(ary);
+ while (idx--) {
+ VALUE elem = RARRAY_AREF(ary, idx);
+ if (RTEST(rb_yield(elem))) {
+ return elem;
+ }
+
+ len = RARRAY_LEN(ary);
+ idx = (idx >= len) ? len : idx;
+ }
+
+ if (!NIL_P(if_none)) {
+ return rb_funcallv(if_none, idCall, 0, 0);
+ }
+ return Qnil;
+}
+
+/*
* call-seq:
* find_index(object) -> integer or nil
* find_index {|element| ... } -> integer or nil
@@ -2322,7 +2417,7 @@ rb_ary_resize(VALUE ary, long len)
MEMCPY((VALUE *)ARY_EMBED_PTR(ary), ptr, VALUE, len); /* WB: no new reference */
ARY_SET_EMBED_LEN(ary, len);
- if (is_malloc_ptr) ruby_sized_xfree((void *)ptr, ptr_capa);
+ if (is_malloc_ptr) ruby_xfree_sized((void *)ptr, ptr_capa);
}
else {
if (olen > len + ARY_DEFAULT_SIZE) {
@@ -2589,18 +2684,39 @@ 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)
+// These array primitives enable tight compatibility with the C implementation
+// in terms of what method calls happen. They can use unchecked utilities such as
+// FIX2LONG since unlike userland Ruby code, these methods cannot be traced with
+// TracePoint (or ruby/debug.h APIs) and have their local variables changed from
+// underneath them.
+
+// Return true if the index is at or past the end of the array.
+VALUE
+rb_jit_ary_at_end(rb_execution_context_t *ec, VALUE self, VALUE index)
{
- long i = NUM2LONG(*index);
- if (i >= RARRAY_LEN(self)) {
- return Qfalse;
- }
- *value = RARRAY_AREF(self, i);
- *index = LONG2NUM(i + 1);
- return Qtrue;
+ return FIX2LONG(index) >= RARRAY_LEN(self) ? Qtrue : Qfalse;
+}
+
+// Return the element at the given fixnum index.
+VALUE
+rb_jit_ary_at(rb_execution_context_t *ec, VALUE self, VALUE index)
+{
+ return RARRAY_AREF(self, FIX2LONG(index));
+}
+
+// Increment a fixnum by 1.
+VALUE
+rb_jit_fixnum_inc(rb_execution_context_t *ec, VALUE self, VALUE num)
+{
+ return LONG2FIX(FIX2LONG(num) + 1);
+}
+
+// Push a value onto an array and return the value.
+VALUE
+rb_jit_ary_push(rb_execution_context_t *ec, VALUE self, VALUE ary, VALUE val)
+{
+ rb_ary_push(ary, val);
+ return val;
}
/*
@@ -2898,23 +3014,28 @@ rb_ary_join(VALUE ary, VALUE sep)
StringValue(sep);
len += RSTRING_LEN(sep) * (RARRAY_LEN(ary) - 1);
}
- for (i=0; i<RARRAY_LEN(ary); i++) {
+ long len_memo = RARRAY_LEN(ary);
+ for (i=0; i < len_memo; i++) {
val = RARRAY_AREF(ary, i);
- tmp = rb_check_string_type(val);
-
- if (NIL_P(tmp) || tmp != val) {
- int first;
- long n = RARRAY_LEN(ary);
- if (i > n) i = n;
- result = rb_str_buf_new(len + (n-i)*10);
- rb_enc_associate(result, rb_usascii_encoding());
- i = ary_join_0(ary, sep, i, result);
- first = i == 0;
- ary_join_1(ary, ary, sep, i, result, &first);
- return result;
+ if (RB_UNLIKELY(!RB_TYPE_P(val, T_STRING))) {
+ tmp = rb_check_string_type(val);
+ if (NIL_P(tmp) || tmp != val) {
+ int first;
+ long n = RARRAY_LEN(ary);
+ if (i > n) i = n;
+ result = rb_str_buf_new(len + (n-i)*10);
+ rb_enc_associate(result, rb_usascii_encoding());
+ i = ary_join_0(ary, sep, i, result);
+ first = i == 0;
+ ary_join_1(ary, ary, sep, i, result, &first);
+ return result;
+ }
+ len += RSTRING_LEN(tmp);
+ len_memo = RARRAY_LEN(ary);
+ }
+ else {
+ len += RSTRING_LEN(val);
}
-
- len += RSTRING_LEN(tmp);
}
result = rb_str_new(0, len);
@@ -3053,7 +3174,7 @@ rb_ary_to_a(VALUE ary)
* forms each sub-array into a key-value pair in the new hash:
*
* a = [['foo', 'zero'], ['bar', 'one'], ['baz', 'two']]
- * a.to_h # => {"foo"=>"zero", "bar"=>"one", "baz"=>"two"}
+ * a.to_h # => {"foo" => "zero", "bar" => "one", "baz" => "two"}
* [].to_h # => {}
*
* With a block given, the block must return a 2-element array;
@@ -3062,7 +3183,7 @@ rb_ary_to_a(VALUE ary)
*
* a = ['foo', :bar, 1, [2, 3], {baz: 4}]
* a.to_h {|element| [element, element.class] }
- * # => {"foo"=>String, :bar=>Symbol, 1=>Integer, [2, 3]=>Array, {:baz=>4}=>Hash}
+ * # => {"foo" => String, bar: Symbol, 1 => Integer, [2, 3] => Array, {baz: 4} => Hash}
*
* Related: see {Methods for Converting}[rdoc-ref:Array@Methods+for+Converting].
*/
@@ -3502,7 +3623,7 @@ static VALUE rb_ary_bsearch_index(VALUE ary);
* Returns 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].
+ * See {Binary Searching}[rdoc-ref:language/bsearch.rdoc].
*
* Related: see {Methods for Fetching}[rdoc-ref:Array@Methods+for+Fetching].
*/
@@ -3526,7 +3647,7 @@ rb_ary_bsearch(VALUE ary)
* 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].
+ * See {Binary Searching}[rdoc-ref:language/bsearch.rdoc].
*
* Related: see {Methods for Fetching}[rdoc-ref:Array@Methods+for+Fetching].
*/
@@ -4557,7 +4678,7 @@ take_items(VALUE obj, long n)
* [:c3, :b3, :a3]]
*
* For an *object* in *other_arrays* that is not actually an array,
- * forms the the "other array" as <tt>object.to_ary</tt>, if defined,
+ * forms the "other array" as <tt>object.to_ary</tt>, if defined,
* or as <tt>object.each.to_a</tt> otherwise.
*
* Related: see {Methods for Converting}[rdoc-ref:Array@Methods+for+Converting].
@@ -4717,6 +4838,8 @@ rb_ary_replace(VALUE copy, VALUE orig)
ARY_SET_PTR(copy, ARY_HEAP_PTR(orig));
ARY_SET_LEN(copy, ARY_HEAP_LEN(orig));
rb_ary_set_shared(copy, shared_root);
+
+ RUBY_ASSERT(RB_OBJ_SHAREABLE_P(copy) ? RB_OBJ_SHAREABLE_P(shared_root) : 1);
}
ary_verify(copy);
return copy;
@@ -5768,7 +5891,7 @@ rb_ary_union_hash(VALUE hash, VALUE ary2)
*
* Returns the union of +self+ and +other_array+;
* duplicates are removed; order is preserved;
- * items are compared using <tt>eql?</tt>:
+ * items are compared using <tt>eql?</tt> and <tt>hash</tt>:
*
* [0, 1] | [2, 3] # => [0, 1, 2, 3]
* [0, 1, 1] | [2, 2, 3] # => [0, 1, 2, 3]
@@ -5802,7 +5925,7 @@ rb_ary_or(VALUE ary1, VALUE ary2)
*
* Returns a new array that is the union of the elements of +self+
* and all given arrays +other_arrays+;
- * items are compared using <tt>eql?</tt>:
+ * items are compared using <tt>eql?</tt> and <tt>hash</tt>:
*
* [0, 1, 2, 3].union([4, 5], [6, 7]) # => [0, 1, 2, 3, 4, 5, 6, 7]
*
@@ -6302,7 +6425,7 @@ push_value(st_data_t key, st_data_t val, st_data_t ary)
* returns +self+ if any elements removed, +nil+ otherwise.
*
* With no block given, identifies and removes elements using method <tt>eql?</tt>
- * to compare elements:
+ * and <tt>hash</tt> to compare elements:
*
* a = [0, 0, 1, 1, 2, 2]
* a.uniq! # => [0, 1, 2]
@@ -6310,7 +6433,7 @@ push_value(st_data_t key, st_data_t val, st_data_t ary)
*
* With a block given, calls the block for each element;
* identifies and omits "duplicate" elements using method <tt>eql?</tt>
- * to compare <i>block return values</i>;
+ * and <tt>hash</tt> to compare <i>block return values</i>;
* that is, an element is a duplicate if its block return value
* is the same as that of a previous element:
*
@@ -6359,14 +6482,14 @@ rb_ary_uniq_bang(VALUE ary)
* the first occurrence always being retained.
*
* With no block given, identifies and omits duplicate elements using method <tt>eql?</tt>
- * to compare elements:
+ * and <tt>hash</tt> to compare elements:
*
* a = [0, 0, 1, 1, 2, 2]
* a.uniq # => [0, 1, 2]
*
* With a block given, calls the block for each element;
* identifies and omits "duplicate" elements using method <tt>eql?</tt>
- * to compare <i>block return values</i>;
+ * and <tt>hash</tt> to compare <i>block return values</i>;
* that is, an element is a duplicate if its block return value
* is the same as that of a previous element:
*
@@ -6413,7 +6536,7 @@ rb_ary_uniq(VALUE ary)
* see also {Methods for Deleting}[rdoc-ref:Array@Methods+for+Deleting].
*/
-static VALUE
+VALUE
rb_ary_compact_bang(VALUE ary)
{
VALUE *p, *t, *end;
@@ -6620,16 +6743,16 @@ flatten(VALUE ary, int level)
* 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.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, {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}>]
*
* 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}>]
+ * 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].
@@ -6676,17 +6799,17 @@ rb_ary_flatten_bang(int argc, VALUE *argv, VALUE ary)
* 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}>]
+ * 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}>]
+ * 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].
@@ -8132,7 +8255,11 @@ 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)) {
+ bool init_is_float = RB_FLOAT_TYPE_P(v);
+ if (init_is_float) {
+ v = LONG2FIX(0);
+ }
+ else if (!RB_INTEGER_TYPE_P(v) && !RB_TYPE_P(v, T_RATIONAL)) {
i = 0;
goto init_is_a_value;
}
@@ -8160,12 +8287,13 @@ rb_ary_sum(int argc, VALUE *argv, VALUE ary)
goto not_exact;
}
v = finish_exact_sum(n, r, v, argc!=0);
+ if (init_is_float) v = rb_float_plus(argv[0], v);
return v;
not_exact:
v = finish_exact_sum(n, r, v, i!=0);
- if (RB_FLOAT_TYPE_P(e)) {
+ if (init_is_float ? (--i, e = argv[0], true) : RB_FLOAT_TYPE_P(e)) {
/*
* Kahan-Babuska balancing compensated summation algorithm
* See https://link.springer.com/article/10.1007/s00607-005-0139-x
@@ -8312,12 +8440,12 @@ rb_ary_deconstruct(VALUE ary)
*
* [1, 'one', :one, [2, 'two', :two]]
*
- * - A {%w or %W string-array Literal}[rdoc-ref:syntax/literals.rdoc@25w+and+-25W-3A+String-Array+Literals]:
+ * - A {%w or %W string-array Literal}[rdoc-ref:syntax/literals.rdoc@w-and-w-String-Array-Literals]:
*
* %w[foo bar baz] # => ["foo", "bar", "baz"]
* %w[1 % *] # => ["1", "%", "*"]
*
- * - A {%i or %I symbol-array Literal}[rdoc-ref:syntax/literals.rdoc@25i+and+-25I-3A+Symbol-Array+Literals]:
+ * - A {%i or %I symbol-array Literal}[rdoc-ref:syntax/literals.rdoc@i+and-I-Symbol-Array+Literals]:
*
* %i[foo bar baz] # => [:foo, :bar, :baz]
* %i[1 % *] # => [:"1", :%, :*]
@@ -8579,8 +8707,8 @@ rb_ary_deconstruct(VALUE ary)
*
* 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],
+ * - Inherits from {class Object}[rdoc-ref:Object@Whats-Here].
+ * - Includes {module Enumerable}[rdoc-ref:Enumerable@Whats-Here],
* which provides dozens of additional methods.
*
* Here, class \Array provides methods that are useful for:
@@ -8790,6 +8918,9 @@ Init_Array(void)
rb_define_method(rb_cArray, "length", rb_ary_length, 0);
rb_define_method(rb_cArray, "size", rb_ary_length, 0);
rb_define_method(rb_cArray, "empty?", rb_ary_empty_p, 0);
+ rb_define_method(rb_cArray, "find", rb_ary_find, -1);
+ rb_define_method(rb_cArray, "detect", rb_ary_find, -1);
+ rb_define_method(rb_cArray, "rfind", rb_ary_rfind, -1);
rb_define_method(rb_cArray, "find_index", rb_ary_index, -1);
rb_define_method(rb_cArray, "index", rb_ary_index, -1);
rb_define_method(rb_cArray, "rindex", rb_ary_rindex, -1);
@@ -8871,7 +9002,7 @@ Init_Array(void)
rb_define_method(rb_cArray, "deconstruct", rb_ary_deconstruct, 0);
- rb_cArray_empty_frozen = rb_ary_freeze(rb_ary_new());
+ rb_cArray_empty_frozen = RB_OBJ_SET_SHAREABLE(rb_ary_freeze(rb_ary_new()));
rb_vm_register_global_object(rb_cArray_empty_frozen);
}
diff --git a/array.rb b/array.rb
index 03663dbb0b..7ee4e09a4c 100644
--- a/array.rb
+++ b/array.rb
@@ -217,15 +217,15 @@ class Array
undef :each
def each # :nodoc:
- Primitive.attr! :inline_block, :c_trace
+ Primitive.attr! :inline_block, :c_trace, :without_interrupts
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
+ i = 0
+ until Primitive.rb_jit_ary_at_end(i)
+ yield Primitive.rb_jit_ary_at(i)
+ i = Primitive.rb_jit_fixnum_inc(i)
end
self
end
@@ -235,17 +235,18 @@ class Array
undef :map
def map # :nodoc:
- Primitive.attr! :inline_block, :c_trace
+ Primitive.attr! :inline_block, :c_trace, :without_interrupts
unless defined?(yield)
return Primitive.cexpr! 'SIZED_ENUMERATOR(self, 0, 0, ary_enum_length)'
end
- _i = 0
- value = nil
+ i = 0
result = Primitive.ary_sized_alloc
- while Primitive.cexpr!(%q{ ary_fetch_next(self, LOCAL_PTR(_i), LOCAL_PTR(value)) })
- result << yield(value)
+ until Primitive.rb_jit_ary_at_end(i)
+ value = yield(Primitive.rb_jit_ary_at(i))
+ Primitive.rb_jit_ary_push(result, value)
+ i = Primitive.rb_jit_fixnum_inc(i)
end
result
end
@@ -260,17 +261,20 @@ class Array
undef :select
def select # :nodoc:
- Primitive.attr! :inline_block, :c_trace
+ Primitive.attr! :inline_block, :c_trace, :without_interrupts
unless defined?(yield)
return Primitive.cexpr! 'SIZED_ENUMERATOR(self, 0, 0, ary_enum_length)'
end
- _i = 0
- value = nil
+ i = 0
result = Primitive.ary_sized_alloc
- while Primitive.cexpr!(%q{ ary_fetch_next(self, LOCAL_PTR(_i), LOCAL_PTR(value)) })
- result << value if yield value
+ until Primitive.rb_jit_ary_at_end(i)
+ value = Primitive.rb_jit_ary_at(i)
+ if yield value
+ Primitive.rb_jit_ary_push(result, value)
+ end
+ i = Primitive.rb_jit_fixnum_inc(i)
end
result
end
@@ -280,5 +284,24 @@ class Array
alias filter select
end
end
+
+ if Primitive.rb_builtin_basic_definition_p(:find)
+ undef :find
+
+ def find(if_none_proc = nil) # :nodoc:
+ Primitive.attr! :inline_block, :c_trace, :without_interrupts
+
+ unless defined?(yield)
+ return Primitive.cexpr! 'SIZED_ENUMERATOR(self, 0, 0, ary_enum_length)'
+ end
+ i = 0
+ until Primitive.rb_jit_ary_at_end(i)
+ value = Primitive.rb_jit_ary_at(i)
+ return value if yield(value)
+ i = Primitive.rb_jit_fixnum_inc(i)
+ end
+ if_none_proc&.call
+ end
+ end
end
end
diff --git a/ast.c b/ast.c
index 04b9543854..1ddc2b5791 100644
--- a/ast.c
+++ b/ast.c
@@ -32,9 +32,13 @@ 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);
+ size_t size = sizeof(struct ASTNodeData);
+ if (data->ast_value) {
+ rb_ast_t *ast = rb_ruby_ast_data_get(data->ast_value);
+ size += rb_ast_memsize(ast);
+ }
- return sizeof(struct ASTNodeData) + rb_ast_memsize(ast);
+ return size;
}
static const rb_data_type_t rb_node_type = {
@@ -400,6 +404,19 @@ rest_arg(VALUE ast_value, const NODE *rest_arg)
return NODE_NAMED_REST_P(rest_arg) ? NEW_CHILD(ast_value, rest_arg) : no_name_rest();
}
+static ID
+node_colon_name(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 VALUE
node_children(VALUE ast_value, const NODE *node)
{
@@ -493,7 +510,7 @@ node_children(VALUE ast_value, const NODE *node)
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));
}
- 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_value, RNODE_CDECL(node)->nd_else), ID2SYM(node_colon_name(RNODE_CDECL(node)->nd_else)), NEW_CHILD(ast_value, RNODE_CDECL(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),
@@ -681,7 +698,7 @@ node_children(VALUE ast_value, const NODE *node)
: 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)),
- var_name(ainfo->block_arg));
+ (ainfo->no_blockarg ? Qfalse : var_name(ainfo->block_arg)));
}
case NODE_SCOPE:
{
@@ -918,6 +935,14 @@ node_locations(VALUE ast_value, const NODE *node)
return rb_ary_new_from_args(2,
location_new(nd_code_loc(node)),
location_new(&RNODE_RETURN(node)->keyword_loc));
+
+ case NODE_SCLASS:
+ return rb_ary_new_from_args(4,
+ location_new(nd_code_loc(node)),
+ location_new(&RNODE_SCLASS(node)->class_keyword_loc),
+ location_new(&RNODE_SCLASS(node)->operator_loc),
+ location_new(&RNODE_SCLASS(node)->end_keyword_loc));
+
case NODE_SPLAT:
return rb_ary_new_from_args(2,
location_new(nd_code_loc(node)),
diff --git a/benchmark/dir_pwd.yml b/benchmark/dir_pwd.yml
new file mode 100644
index 0000000000..c435d3ac5e
--- /dev/null
+++ b/benchmark/dir_pwd.yml
@@ -0,0 +1,2 @@
+benchmark:
+ pwd: Dir.pwd
diff --git a/benchmark/file_basename.yml b/benchmark/file_basename.yml
new file mode 100644
index 0000000000..fbd78785aa
--- /dev/null
+++ b/benchmark/file_basename.yml
@@ -0,0 +1,6 @@
+prelude: |
+ # frozen_string_literal: true
+benchmark:
+ long: File.basename("/Users/george/src/github.com/ruby/ruby/benchmark/file_dirname.yml")
+ long_name: File.basename("Users_george_src_github.com_ruby_ruby_benchmark_file_dirname.yml")
+ withext: File.basename("/Users/george/src/github.com/ruby/ruby/benchmark/file_dirname.yml", ".yml")
diff --git a/benchmark/file_dirname.yml b/benchmark/file_dirname.yml
new file mode 100644
index 0000000000..43a81c9371
--- /dev/null
+++ b/benchmark/file_dirname.yml
@@ -0,0 +1,6 @@
+prelude: |
+ # frozen_string_literal: true
+benchmark:
+ long: File.dirname("/Users/george/src/github.com/ruby/ruby/benchmark/file_dirname.yml")
+ short: File.dirname("foo/bar")
+ n_4: File.dirname("/Users/george/src/github.com/ruby/ruby/benchmark/file_dirname.yml", 4)
diff --git a/benchmark/file_expand_path.yml b/benchmark/file_expand_path.yml
new file mode 100644
index 0000000000..9e503ab003
--- /dev/null
+++ b/benchmark/file_expand_path.yml
@@ -0,0 +1,4 @@
+prelude: |
+ # frozen_string_literal: true
+benchmark:
+ expand_path: File.expand_path("../../foo.txt", __FILE__)
diff --git a/benchmark/file_extname.yml b/benchmark/file_extname.yml
new file mode 100644
index 0000000000..fb16e55840
--- /dev/null
+++ b/benchmark/file_extname.yml
@@ -0,0 +1,6 @@
+prelude: |
+ # frozen_string_literal: true
+benchmark:
+ long: File.extname("/Users/george/src/github.com/ruby/ruby/benchmark/file_dirname.yml")
+ long_name: File.extname("Users_george_src_github.com_ruby_ruby_benchmark_file_dirname.yml")
+ short: File.extname("foo/bar")
diff --git a/benchmark/file_join.yml b/benchmark/file_join.yml
new file mode 100644
index 0000000000..845257cf1e
--- /dev/null
+++ b/benchmark/file_join.yml
@@ -0,0 +1,7 @@
+prelude: |
+ # frozen_string_literal: true
+benchmark:
+ two_strings: File.join(__FILE__, "path")
+ many_strings: File.join(__FILE__, "path", "a", "b", "c", "d")
+ array: File.join([__FILE__, "path", "a", "b", "c", "d"])
+ mixed: File.join(__FILE__, "path", "a", "b", ["c", "d"])
diff --git a/benchmark/float_predicate.yml b/benchmark/float_predicate.yml
new file mode 100644
index 0000000000..b946937666
--- /dev/null
+++ b/benchmark/float_predicate.yml
@@ -0,0 +1,12 @@
+prelude: |
+ floats = [1.0, -1.0, 0.0, Float::NAN, Float::INFINITY, -Float::INFINITY]
+
+benchmark:
+ float_nan?: floats.each { |f| f.nan? }
+ float_finite?: floats.each { |f| f.finite? }
+ float_infinite?: floats.each { |f| f.infinite? }
+ float_zero?: floats.each { |f| f.zero? }
+ float_positive?: floats.each { |f| f.positive? }
+ float_negative?: floats.each { |f| f.negative? }
+
+loop_count: 1000000
diff --git a/benchmark/int_to_s.yml b/benchmark/int_to_s.yml
new file mode 100644
index 0000000000..000dae9612
--- /dev/null
+++ b/benchmark/int_to_s.yml
@@ -0,0 +1,25 @@
+prelude: |
+ # frozen_string_literal: true
+ N1 = 5
+ N2 = 42
+ N3 = 400
+ N5 = 12345
+ N10 = 1_234_567_890
+ N19 = 4_611_686_018_427_387_903
+ NEG = -1_234_567_890
+ BIG20 = 10 ** 19 + 12_345_678_901_234_567
+ BIG40 = 10 ** 39 + 123_456_789_012_345
+ BIG100 = 10 ** 99 + 42
+benchmark:
+ fix_1digit: "N1.to_s"
+ fix_2digit: "N2.to_s"
+ fix_3digit: "N3.to_s"
+ fix_5digit: "N5.to_s"
+ fix_10digit: "N10.to_s"
+ fix_19digit: "N19.to_s"
+ fix_negative: "NEG.to_s"
+ big_20digit: "BIG20.to_s"
+ big_40digit: "BIG40.to_s"
+ big_100digit: "BIG100.to_s"
+ interp_id: '"id=#{N10}"'
+ interp_mixed: '"a=#{N2},b=#{N5},c=#{N10}"'
diff --git a/benchmark/integer_predicate.yml b/benchmark/integer_predicate.yml
new file mode 100644
index 0000000000..7c05ff2587
--- /dev/null
+++ b/benchmark/integer_predicate.yml
@@ -0,0 +1,9 @@
+prelude: |
+ nums = (0..9).to_a
+
+benchmark:
+ integer_zero?: nums.each { |n| n.zero? }
+ integer_even?: nums.each { |n| n.even? }
+ integer_odd?: nums.each { |n| n.odd? }
+
+loop_count: 1000000
diff --git a/benchmark/object_class.yml b/benchmark/object_class.yml
new file mode 100644
index 0000000000..1e5409d1e2
--- /dev/null
+++ b/benchmark/object_class.yml
@@ -0,0 +1,40 @@
+prelude: |
+ def get_class(obj)
+ i = 10_000
+ while i > 0
+ i -= 1
+ # 100 times per loop
+ obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class;
+ obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class;
+ obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class;
+ obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class;
+ obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class;
+ obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class;
+ obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class;
+ obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class;
+ obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class;
+ obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class;
+ obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class;
+ end
+ end
+
+ class Obj
+ end
+ obj = Obj.new
+
+ singleton = Obj.new
+ def singleton.bar
+ end
+
+ extended = Obj.new
+ 2.times do
+ extended.extend Module.new
+ end
+
+ immediate = 1.4
+benchmark:
+ obj: get_class(obj)
+ extended: get_class(extended)
+ singleton: get_class(singleton)
+ immediate: get_class(immediate)
+loop_count: 1000
diff --git a/benchmark/pathname.yml b/benchmark/pathname.yml
new file mode 100644
index 0000000000..bcf3011eab
--- /dev/null
+++ b/benchmark/pathname.yml
@@ -0,0 +1,15 @@
+prelude: |
+ abs = Pathname("/a")
+ rel = Pathname("a")
+ p1 = Pathname.new('foo/././././bar')
+ p2 = Pathname.new('foo/bar/./../..')
+ p3 = Pathname.new('foo/bar/zot')
+benchmark:
+ p1+p2: p1+p2
+ abs.root?: abs.root?
+ rel.root?: rel.root?
+ abs.absolute?: abs.absolute?
+ rel.absolute?: rel.absolute?
+ p1.cleanpath: p1.cleanpath
+ p2.cleanpath: p2.cleanpath
+ relative_path_from: p3.relative_path_from('foo/bar/qux/quax')
diff --git a/benchmark/set.yml b/benchmark/set.yml
index 43217036e2..061509cb1f 100644
--- a/benchmark/set.yml
+++ b/benchmark/set.yml
@@ -259,7 +259,3 @@ benchmark:
to_set_10: s1.to_set
to_set_100: s2.to_set
to_set_1000: s3.to_set
- to_set_arg_0: s0.to_set set_subclass
- to_set_arg_10: s1.to_set set_subclass
- to_set_arg_100: s2.to_set set_subclass
- to_set_arg_1000: s3.to_set set_subclass
diff --git a/benchmark/string_codepoints.yml b/benchmark/string_codepoints.yml
new file mode 100644
index 0000000000..6a07db7ce1
--- /dev/null
+++ b/benchmark/string_codepoints.yml
@@ -0,0 +1,9 @@
+prelude: |
+ mixed_ascii64 = ("a" * 63 + "\u{100}") * 2048
+ mixed_ascii256 = ("a" * 255 + "\u{100}") * 512
+ utf8_2byte = "\u{100}" * 65536
+
+benchmark:
+ codepoints_mixed_ascii64: mixed_ascii64.codepoints
+ codepoints_mixed_ascii256: mixed_ascii256.codepoints
+ codepoints_utf8_2byte: utf8_2byte.codepoints
diff --git a/benchmark/string_coderange_scan.yml b/benchmark/string_coderange_scan.yml
new file mode 100644
index 0000000000..d47bbd2b30
--- /dev/null
+++ b/benchmark/string_coderange_scan.yml
@@ -0,0 +1,10 @@
+prelude: |
+ def unknown(s) = s.b.force_encoding("UTF-8")
+ multibyte = unknown("\u{00e9}" * 16384) # best case: every byte non-ASCII
+ alternating = unknown("\u{00e9}a" * 10922) # worst case: non-ASCII then ASCII
+ ascii = unknown("a" * 32768) # baseline
+
+benchmark:
+ coderange_multibyte: multibyte.dup.valid_encoding?
+ coderange_alternating: alternating.dup.valid_encoding?
+ coderange_ascii: ascii.dup.valid_encoding?
diff --git a/benchmark/string_concat.yml b/benchmark/string_concat.yml
index f11f95ee9a..c07fd21013 100644
--- a/benchmark/string_concat.yml
+++ b/benchmark/string_concat.yml
@@ -1,8 +1,8 @@
prelude: |
CHUNK = "a" * 64
UCHUNK = "é" * 32
- SHORT = "a" * (GC::INTERNAL_CONSTANTS[:BASE_SLOT_SIZE] / 2)
- LONG = "a" * (GC::INTERNAL_CONSTANTS[:BASE_SLOT_SIZE] * 2)
+ SHORT = "a" * (GC.stat_heap(0, :slot_size) / 2)
+ LONG = "a" * (GC.stat_heap(0, :slot_size) * 2)
GC.disable # GC causes a lot of variance
benchmark:
binary_concat_7bit: |
diff --git a/benchmark/string_gsub.yml b/benchmark/string_gsub.yml
index 0f964337dd..c26e1a6498 100644
--- a/benchmark/string_gsub.yml
+++ b/benchmark/string_gsub.yml
@@ -20,8 +20,19 @@ prelude: |
}
ESCAPE_PATTERN = Regexp.union(ESCAPED_CHARS.keys)
+ NO_MATCH_SHARED_STRING = ("a" * 100_000).freeze
benchmark:
+ gsub_no_match_shared: |
+ str = NO_MATCH_SHARED_STRING.dup
+ str.gsub!("z", "x")
+ str
+
+ sub_no_match_shared: |
+ str = NO_MATCH_SHARED_STRING.dup
+ str.sub!("z", "x")
+ str
+
escape: |
str = STR.dup
str.gsub!(ESCAPE_PATTERN, ESCAPED_CHARS)
diff --git a/benchmark/string_inspect.yml b/benchmark/string_inspect.yml
new file mode 100644
index 0000000000..62a884e19d
--- /dev/null
+++ b/benchmark/string_inspect.yml
@@ -0,0 +1,13 @@
+prelude: |
+ ascii = "Hello, World! This is a benchmark test string." * 100
+ utf8 = "ã“ã‚“ã«ã¡ã¯ä¸–界。ã“れã¯ãƒ™ãƒ³ãƒãƒžãƒ¼ã‚¯ç”¨ã®ãƒ†ã‚¹ãƒˆæ–‡å­—列ã§ã™ã€‚" * 100
+ mixed = ("Hello World! " + "テスト" + " is great! ") * 100
+ binary = ("\xE3\x81\x82" * 100).b
+ escapy = "\n\t\"\\\#" * 100
+
+benchmark:
+ inspect_ascii: ascii.inspect
+ inspect_utf8: utf8.inspect
+ inspect_mixed: mixed.inspect
+ inspect_binary: binary.inspect
+ inspect_escapy: escapy.inspect
diff --git a/benchmark/string_memsearch.yml b/benchmark/string_memsearch.yml
new file mode 100644
index 0000000000..cde363289a
--- /dev/null
+++ b/benchmark/string_memsearch.yml
@@ -0,0 +1,75 @@
+prelude: |
+ # Haystacks of various sizes
+ small_hay = "a" * 256
+ medium_hay = "a" * 4096
+ large_hay = "a" * 65536
+
+ # Short needles (2-8 bytes) that exercise rb_memsearch_ss
+ needle_2 = "xy"
+ needle_4 = "xyzw"
+ needle_8 = "xyzwabcd"
+
+ # Needle whose first byte is absent from the haystack (memchr fast-path)
+ # vs needle whose first byte is common (rolling hash comparison)
+ first_byte_absent = "x" + "a" * 3
+ first_byte_common = "a" + "x" * 3
+
+ # Haystack with match at the end
+ hay_match_end = "a" * 4095 + "xy"
+
+ # Haystack with match at the start
+ hay_match_start = "xy" + "a" * 4094
+
+ # Mixed content haystack (more realistic)
+ mixed_hay = (("abcdefghij" * 100) + "z") * 10
+
+benchmark:
+ # === First byte absent from haystack (biggest win for rolling hash) ===
+ index_first_byte_absent_small: |
+ small_hay.index(first_byte_absent)
+ index_first_byte_absent_medium: |
+ medium_hay.index(first_byte_absent)
+ index_first_byte_absent_large: |
+ large_hay.index(first_byte_absent)
+
+ # === First byte common in haystack (stresses comparison loop) ===
+ index_first_byte_common_small: |
+ small_hay.index(first_byte_common)
+ index_first_byte_common_medium: |
+ medium_hay.index(first_byte_common)
+ index_first_byte_common_large: |
+ large_hay.index(first_byte_common)
+
+ # === Needle length variations (all absent) ===
+ index_needle_2_absent: |
+ medium_hay.index(needle_2)
+ index_needle_4_absent: |
+ medium_hay.index(needle_4)
+ index_needle_8_absent: |
+ medium_hay.index(needle_8)
+
+ # === Match at end of haystack ===
+ index_match_at_end: |
+ hay_match_end.index(needle_2)
+
+ # === Match at start of haystack ===
+ index_match_at_start: |
+ hay_match_start.index(needle_2)
+
+ # === include? (same code path) ===
+ include_first_byte_absent: |
+ medium_hay.include?(first_byte_absent)
+ include_first_byte_common: |
+ medium_hay.include?(first_byte_common)
+
+ # === byteindex ===
+ byteindex_first_byte_absent: |
+ medium_hay.byteindex(first_byte_absent)
+ byteindex_first_byte_common: |
+ medium_hay.byteindex(first_byte_common)
+
+ # === Mixed/realistic haystack ===
+ index_mixed_absent: |
+ mixed_hay.index(needle_4)
+ index_mixed_present: |
+ mixed_hay.index("ijab")
diff --git a/benchmark/string_scrub.yml b/benchmark/string_scrub.yml
new file mode 100644
index 0000000000..4b5faaad8e
--- /dev/null
+++ b/benchmark/string_scrub.yml
@@ -0,0 +1,48 @@
+prelude: |
+
+ STRING_SIZE = 1024
+ def duplicate_to_length(str, target_length)
+ return "" if target_length <= 0
+ return str[0, target_length] if str.length >= target_length
+
+ (str * ((target_length / str.length) + 1))[0, target_length]
+ end
+ base = "Hello \u{1f600} world! \u{00e9}\u{00f1}"
+ padding = duplicate_to_length(base, STRING_SIZE)
+
+ valid_utf8 = (padding.b + "OK".b).force_encoding("UTF-8")
+ valid_utf8.valid_encoding?
+ unknown_but_valid_utf8 = valid_utf8.dup.b.force_encoding("UTF-8")
+ invalid_utf8 = (padding.b + "\x80\xFF".b).force_encoding("UTF-8")
+ invalid_utf8.valid_encoding?
+ unknown_but_invalid_utf8 = (padding.b + "\x80\xFF".b).force_encoding("UTF-8")
+
+ worst_case_utf8 = duplicate_to_length("\u{1f600}\u{00e9}\u{00f1}", STRING_SIZE).b.force_encoding("UTF-8")
+
+ unknown_but_valid_utf8_worst_case = worst_case_utf8.dup.b.force_encoding("UTF-8")
+ unknown_but_invalid_utf8_worst_case = (worst_case_utf8.b + "\x80\xFF".b).force_encoding("UTF-8")
+
+benchmark:
+ scrub_known_valid: |
+ string = valid_utf8.dup
+ string.scrub!
+
+ scrub_known_invalid: |
+ string = invalid_utf8.dup
+ string.scrub!
+
+ scrub_unknown_but_valid_coderange: |
+ string = unknown_but_valid_utf8.dup
+ string.scrub!
+
+ scrub_unknown_and_invalid_coderange: |
+ string = unknown_but_invalid_utf8.dup
+ string.scrub!
+
+ scrub_unknown_but_valid_coderange_worst_case: |
+ string = unknown_but_valid_utf8_worst_case.dup
+ string.scrub!
+
+ scrub_unknown_and_invalid_coderange_worst_case: |
+ string = unknown_but_invalid_utf8_worst_case.dup
+ string.scrub! \ No newline at end of file
diff --git a/benchmark/time_now.yml b/benchmark/time_now.yml
index f6d6a31489..9336877cd4 100644
--- a/benchmark/time_now.yml
+++ b/benchmark/time_now.yml
@@ -1,3 +1,4 @@
benchmark:
- 'Time.now'
- 'Time.now(in: "+09:00")'
+ - 'Time.now.year'
diff --git a/benchmark/vm_ivar_get.yml b/benchmark/vm_ivar_get.yml
index 9174af6965..1e0dad665f 100644
--- a/benchmark/vm_ivar_get.yml
+++ b/benchmark/vm_ivar_get.yml
@@ -1,17 +1,75 @@
prelude: |
class Example
def initialize
+ @levar = 1
@v0 = 1
@v1 = 2
@v3 = 3
+ end
+
+ def get_value_loop
+ sum = 0
+
+ i = 0
+ while i < 100_000
+ # 10 times to de-emphasize loop overhead
+ sum += @levar
+ sum += @levar
+ sum += @levar
+ sum += @levar
+ sum += @levar
+ sum += @levar
+ sum += @levar
+ sum += @levar
+ sum += @levar
+ sum += @levar
+ i += 1
+ end
+
+ return sum
+ end
+
+ @levar = 1
+ @v0 = 1
+ @v1 = 2
+ @v3 = 3
+
+ def self.get_value_loop
+ sum = 0
+
+ i = 0
+ while i < 100_000
+ # 10 times to de-emphasize loop overhead
+ sum += @levar
+ sum += @levar
+ sum += @levar
+ sum += @levar
+ sum += @levar
+ sum += @levar
+ sum += @levar
+ sum += @levar
+ sum += @levar
+ sum += @levar
+ i += 1
+ end
+
+ return sum
+ end
+ end
+
+ class GenExample < Time
+ def initialize
@levar = 1
+ @v0 = 1
+ @v1 = 2
+ @v3 = 3
end
def get_value_loop
sum = 0
i = 0
- while i < 1000000
+ while i < 100_000
# 10 times to de-emphasize loop overhead
sum += @levar
sum += @levar
@@ -31,7 +89,12 @@ prelude: |
end
obj = Example.new
+ gen = GenExample.new
benchmark:
- vm_ivar_get: |
+ vm_ivar_get_on_obj: |
obj.get_value_loop
+ vm_ivar_get_on_class: |
+ Example.get_value_loop
+ vm_ivar_get_on_generic: |
+ gen.get_value_loop
loop_count: 100
diff --git a/benchmark/vm_ivar_set_on_instance.yml b/benchmark/vm_ivar_set_on_instance.yml
index 91857b7742..6ce53a86ec 100644
--- a/benchmark/vm_ivar_set_on_instance.yml
+++ b/benchmark/vm_ivar_set_on_instance.yml
@@ -1,16 +1,44 @@
prelude: |
class TheClass
def initialize
+ @levar = 1
@v0 = 1
@v1 = 2
@v3 = 3
+ end
+
+ def set_value_loop
+ # 100k
+ i = 0
+ while i < 100_000
+ # 10 times to de-emphasize loop overhead
+ @levar = i
+ @levar = i
+ @levar = i
+ @levar = i
+ @levar = i
+ @levar = i
+ @levar = i
+ @levar = i
+ @levar = i
+ @levar = i
+ i += 1
+ end
+ end
+ end
+
+ class Generic < Time
+ def initialize
@levar = 1
+ @v0 = 1
+ @v1 = 2
+ @v3 = 3
end
def set_value_loop
- # 1M
+ # 100k
i = 0
- while i < 1000000
+ while i < 100_000
# 10 times to de-emphasize loop overhead
@levar = i
@levar = i
@@ -28,8 +56,39 @@ prelude: |
end
obj = TheClass.new
+ gen_obj = Generic.new
+
+ class SomeClass
+ @levar = 1
+ @v0 = 1
+ @v1 = 2
+ @v3 = 3
+
+ def self.set_value_loop
+ # 100k
+ i = 0
+ while i < 100_000
+ # 10 times to de-emphasize loop overhead
+ @levar = i
+ @levar = i
+ @levar = i
+ @levar = i
+ @levar = i
+ @levar = i
+ @levar = i
+ @levar = i
+ @levar = i
+ @levar = i
+ i += 1
+ end
+ end
+ end
benchmark:
vm_ivar_set_on_instance: |
obj.set_value_loop
+ vm_ivar_set_on_generic: |
+ gen_obj.set_value_loop
+ vm_ivar_set_on_class: |
+ SomeClass.set_value_loop
loop_count: 100
diff --git a/benchmark/vm_regexp.yml b/benchmark/vm_regexp.yml
index 2aa3d94dbd..80541332b1 100644
--- a/benchmark/vm_regexp.yml
+++ b/benchmark/vm_regexp.yml
@@ -3,6 +3,12 @@ prelude: |
benchmark:
vm_regexp: |
/hoge/ =~ str
+ vm_regexp_alternating: |
+ /hoge/ =~ str
+ /huge/ =~ str
vm_regexp_invert: |
str =~ /hoge/
+ vm_regexp_invert_alternating: |
+ str =~ /hoge/
+ str =~ /huge/
loop_count: 6000000
diff --git a/bignum.c b/bignum.c
index 2e135caf20..28924b4eb9 100644
--- a/bignum.c
+++ b/bignum.c
@@ -64,6 +64,21 @@ static const bool debug_integer_pack = (
const char ruby_digitmap[] = "0123456789abcdefghijklmnopqrstuvwxyz";
+/* Two-digit decimal lookup table. Offset 2*n holds the ASCII pair for
+ * n in the range 0..99. Used by both rb_fix2str in numeric.c and
+ * big2str_2bdigits below to emit two base-10 digits per iteration. */
+const char ruby_decimal_digit_pairs[201] =
+ "00010203040506070809"
+ "10111213141516171819"
+ "20212223242526272829"
+ "30313233343536373839"
+ "40414243444546474849"
+ "50515253545556575859"
+ "60616263646566676869"
+ "70717273747576777879"
+ "80818283848586878889"
+ "90919293949596979899";
+
#ifndef SIZEOF_BDIGIT_DBL
# if SIZEOF_INT*2 <= SIZEOF_LONG_LONG
# define SIZEOF_BDIGIT_DBL SIZEOF_LONG_LONG
@@ -79,7 +94,6 @@ STATIC_ASSERT(sizeof_bdigit_and_dbl, SIZEOF_BDIGIT*2 <= SIZEOF_BDIGIT_DBL);
STATIC_ASSERT(bdigit_signedness, 0 < (BDIGIT)-1);
STATIC_ASSERT(bdigit_dbl_signedness, 0 < (BDIGIT_DBL)-1);
STATIC_ASSERT(bdigit_dbl_signed_signedness, 0 > (BDIGIT_DBL_SIGNED)-1);
-STATIC_ASSERT(rbignum_embed_len_max, BIGNUM_EMBED_LEN_MAX <= (BIGNUM_EMBED_LEN_MASK >> BIGNUM_EMBED_LEN_SHIFT));
#if SIZEOF_BDIGIT < SIZEOF_LONG
STATIC_ASSERT(sizeof_long_and_sizeof_bdigit, SIZEOF_LONG % SIZEOF_BDIGIT == 0);
@@ -2944,11 +2958,6 @@ bary_divmod(BDIGIT *qds, size_t qn, BDIGIT *rds, size_t rn, const BDIGIT *xds, s
}
}
-
-#ifndef BIGNUM_DEBUG
-# define BIGNUM_DEBUG (0+RUBY_DEBUG)
-#endif
-
static int
bigzero_p(VALUE x)
{
@@ -2965,7 +2974,7 @@ int
rb_cmpint(VALUE val, VALUE a, VALUE b)
{
if (NIL_P(val)) {
- rb_cmperr(a, b);
+ rb_cmperr_reason(a, b, "comparator returned nil");
}
if (FIXNUM_P(val)) {
long l = FIX2LONG(val);
@@ -2990,36 +2999,68 @@ rb_cmpint(VALUE val, VALUE a, VALUE b)
((l) << BIGNUM_EMBED_LEN_SHIFT)) : \
(void)(RBIGNUM(b)->as.heap.len = (l)))
+static size_t
+big_embed_capa(VALUE big)
+{
+ size_t size = rb_gc_obj_slot_size(big) - offsetof(struct RBignum, as.ary);
+ RUBY_ASSERT(size % sizeof(BDIGIT) == 0);
+ size_t capa = size / sizeof(BDIGIT);
+ RUBY_ASSERT(capa <= BIGNUM_EMBED_LEN_MAX);
+ return capa;
+}
+
+static size_t
+big_embed_size(size_t capa)
+{
+ size_t size = offsetof(struct RBignum, as.ary) + (sizeof(BDIGIT) * capa);
+ if (size < sizeof(struct RBignum)) {
+ size = sizeof(struct RBignum);
+ }
+ return size;
+}
+
+static bool
+big_embeddable_p(size_t capa)
+{
+ if (capa > BIGNUM_EMBED_LEN_MAX) {
+ return false;
+ }
+ return rb_gc_size_allocatable_p(big_embed_size(capa));
+}
+
static void
rb_big_realloc(VALUE big, size_t len)
{
BDIGIT *ds;
+ size_t embed_capa = big_embed_capa(big);
+
if (BIGNUM_EMBED_P(big)) {
- if (BIGNUM_EMBED_LEN_MAX < len) {
+ if (embed_capa < len) {
ds = ALLOC_N(BDIGIT, len);
- MEMCPY(ds, RBIGNUM(big)->as.ary, BDIGIT, BIGNUM_EMBED_LEN_MAX);
+ MEMCPY(ds, RBIGNUM(big)->as.ary, BDIGIT, embed_capa);
RBIGNUM(big)->as.heap.len = BIGNUM_LEN(big);
RBIGNUM(big)->as.heap.digits = ds;
FL_UNSET_RAW(big, BIGNUM_EMBED_FLAG);
}
}
else {
- if (len <= BIGNUM_EMBED_LEN_MAX) {
+ if (len <= embed_capa) {
ds = RBIGNUM(big)->as.heap.digits;
+ size_t old_len = RBIGNUM(big)->as.heap.len;
FL_SET_RAW(big, BIGNUM_EMBED_FLAG);
BIGNUM_SET_LEN(big, len);
- (void)VALGRIND_MAKE_MEM_UNDEFINED((void*)RBIGNUM(big)->as.ary, sizeof(RBIGNUM(big)->as.ary));
+ (void)VALGRIND_MAKE_MEM_UNDEFINED((void*)RBIGNUM(big)->as.ary, embed_capa * sizeof(BDIGIT));
if (ds) {
MEMCPY(RBIGNUM(big)->as.ary, ds, BDIGIT, len);
- xfree(ds);
+ SIZED_FREE_N(ds, old_len);
}
}
else {
if (BIGNUM_LEN(big) == 0) {
RBIGNUM(big)->as.heap.digits = ALLOC_N(BDIGIT, len);
}
- else {
- REALLOC_N(RBIGNUM(big)->as.heap.digits, BDIGIT, len);
+ else if (BIGNUM_LEN(big) != len) {
+ SIZED_REALLOC_N(RBIGNUM(big)->as.heap.digits, BDIGIT, len, BIGNUM_LEN(big));
}
}
}
@@ -3035,16 +3076,21 @@ 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);
- VALUE bigv = (VALUE)big;
- BIGNUM_SET_SIGN(bigv, sign);
- if (len <= BIGNUM_EMBED_LEN_MAX) {
- FL_SET_RAW(bigv, BIGNUM_EMBED_FLAG);
+ VALUE bigv;
+
+ if (big_embeddable_p(len)) {
+ size_t size = big_embed_size(len);
+ RUBY_ASSERT(rb_gc_size_allocatable_p(size));
+ NEWOBJ_OF(big, struct RBignum, klass, T_BIGNUM | BIGNUM_EMBED_FLAG, size);
+ bigv = (VALUE)big;
+ BIGNUM_SET_SIGN(bigv, sign);
BIGNUM_SET_LEN(bigv, len);
- (void)VALGRIND_MAKE_MEM_UNDEFINED((void*)big->as.ary, sizeof(big->as.ary));
+ (void)VALGRIND_MAKE_MEM_UNDEFINED((void*)big->as.ary, len * sizeof(BDIGIT));
}
else {
+ NEWOBJ_OF(big, struct RBignum, klass, T_BIGNUM, sizeof(struct RBignum));
+ bigv = (VALUE)big;
+ BIGNUM_SET_SIGN(bigv, sign);
big->as.heap.digits = ALLOC_N(BDIGIT, len);
big->as.heap.len = len;
}
@@ -3055,7 +3101,9 @@ bignew_1(VALUE klass, size_t len, int sign)
VALUE
rb_big_new(size_t len, int sign)
{
- return bignew(len, sign != 0);
+ VALUE obj = bignew(len, sign != 0);
+ memset(BIGNUM_DIGITS(obj), 0, len * sizeof(BDIGIT));
+ return obj;
}
VALUE
@@ -4475,7 +4523,7 @@ rb_str2big_gmp(VALUE arg, int base, int badcheck)
#if HAVE_LONG_LONG
-static VALUE
+VALUE
rb_ull2big(unsigned LONG_LONG n)
{
long i;
@@ -4497,7 +4545,7 @@ rb_ull2big(unsigned LONG_LONG n)
return big;
}
-static VALUE
+VALUE
rb_ll2big(LONG_LONG n)
{
long neg = 0;
@@ -4535,7 +4583,7 @@ rb_ll2inum(LONG_LONG n)
#endif /* HAVE_LONG_LONG */
#ifdef HAVE_INT128_T
-static VALUE
+VALUE
rb_uint128t2big(uint128_t n)
{
long i;
@@ -4778,11 +4826,34 @@ big2str_2bdigits(struct big2str_struct *b2s, BDIGIT *xds, size_t xn, size_t tail
return;
p = buf;
j = sizeof(buf);
- do {
- BDIGIT_DBL idx = num % b2s->base;
- num /= b2s->base;
- p[--j] = ruby_digitmap[idx];
- } while (num);
+ if (b2s->base == 10) {
+ /* Emit two decimal digits per iteration from ruby_decimal_digit_pairs.
+ * See the comment on the table in bignum.c near ruby_digitmap. */
+ while (num >= 100) {
+ BDIGIT_DBL idx = (num % 100) * 2;
+ num /= 100;
+ j -= 2;
+ p[j] = ruby_decimal_digit_pairs[idx];
+ p[j + 1] = ruby_decimal_digit_pairs[idx + 1];
+ }
+ if (num >= 10) {
+ BDIGIT_DBL idx = num * 2;
+ j -= 2;
+ p[j] = ruby_decimal_digit_pairs[idx];
+ p[j + 1] = ruby_decimal_digit_pairs[idx + 1];
+ }
+ else {
+ /* num is 1..9 here (0 was handled above) */
+ p[--j] = (char)('0' + num);
+ }
+ }
+ else {
+ do {
+ BDIGIT_DBL idx = num % b2s->base;
+ num /= b2s->base;
+ p[--j] = ruby_digitmap[idx];
+ } while (num);
+ }
len = sizeof(buf) - j;
big2str_alloc(b2s, len + taillen);
MEMCPY(b2s->ptr, buf + j, char, len);
@@ -4790,11 +4861,39 @@ big2str_2bdigits(struct big2str_struct *b2s, BDIGIT *xds, size_t xn, size_t tail
else {
p = b2s->ptr;
j = b2s->hbase2_numdigits;
- do {
- BDIGIT_DBL idx = num % b2s->base;
- num /= b2s->base;
- p[--j] = ruby_digitmap[idx];
- } while (j);
+ if (b2s->base == 10) {
+ /* Non-beginning chunks must emit EXACTLY hbase2_numdigits,
+ * zero-padded on the left. Consume num in 2-digit groups,
+ * handle the odd trailing digit, then memset remaining
+ * positions with '0'. */
+ while (num >= 100) {
+ BDIGIT_DBL idx = (num % 100) * 2;
+ num /= 100;
+ j -= 2;
+ p[j] = ruby_decimal_digit_pairs[idx];
+ p[j + 1] = ruby_decimal_digit_pairs[idx + 1];
+ }
+ if (num >= 10) {
+ BDIGIT_DBL idx = num * 2;
+ j -= 2;
+ p[j] = ruby_decimal_digit_pairs[idx];
+ p[j + 1] = ruby_decimal_digit_pairs[idx + 1];
+ }
+ else if (num > 0) {
+ p[--j] = (char)('0' + num);
+ }
+ if (j > 0) {
+ memset(p, '0', j);
+ j = 0;
+ }
+ }
+ else {
+ do {
+ BDIGIT_DBL idx = num % b2s->base;
+ num /= b2s->base;
+ p[--j] = ruby_digitmap[idx];
+ } while (j);
+ }
len = b2s->hbase2_numdigits;
}
b2s->ptr += len;
@@ -7030,7 +7129,7 @@ int_pow_tmp3(VALUE x, VALUE y, VALUE m, int nega_flg)
zn = mn;
z = bignew(zn, 1);
bary_powm_gmp(BDIGITS(z), zn, BDIGITS(x), xn, BDIGITS(y), yn, BDIGITS(m), mn);
- if (nega_flg & BIGNUM_POSITIVE_P(z)) {
+ if (nega_flg && BIGNUM_POSITIVE_P(z) && !BIGZEROP(z)) {
z = rb_big_minus(z, m);
}
RB_GC_GUARD(x);
@@ -7058,7 +7157,7 @@ int_pow_tmp3(VALUE x, VALUE y, VALUE m, int nega_flg)
x = rb_int_modulo(x, m);
}
- if (nega_flg && rb_int_positive_p(tmp)) {
+ if (nega_flg && rb_int_positive_p(tmp) && !rb_int_zero_p(tmp)) {
tmp = rb_int_minus(tmp, m);
}
return tmp;
@@ -7170,6 +7269,11 @@ rb_int_powm(int const argc, VALUE * const argv, VALUE const num)
rb_raise(rb_eTypeError, "Integer#pow() 2nd argument not allowed unless all arguments are integers");
}
+ if (rb_int_zero_p(a) && !rb_int_zero_p(b)) {
+ /* shortcut; 0**x => 0 except for x == 0 */
+ return INT2FIX(0);
+ }
+
if (rb_int_negative_p(m)) {
m = rb_int_uminus(m);
nega_flg = 1;
diff --git a/bootstraptest/runner.rb b/bootstraptest/runner.rb
index a8e67f3496..04de0c93b9 100755
--- a/bootstraptest/runner.rb
+++ b/bootstraptest/runner.rb
@@ -16,6 +16,7 @@ rescue LoadError
$:.unshift File.join(File.dirname(__FILE__), '../lib')
retry
end
+require_relative '../tool/lib/test/jobserver'
if !Dir.respond_to?(:mktmpdir)
# copied from lib/tmpdir.rb
@@ -110,35 +111,7 @@ BT = Class.new(bt) do
def wn=(wn)
unless wn == 1
- if /(?:\A|\s)--jobserver-(?:auth|fds)=(?:(\d+),(\d+)|fifo:((?:\\.|\S)+))/ =~ ENV.delete("MAKEFLAGS")
- begin
- if fifo = $3
- fifo.gsub!(/\\(?=.)/, '')
- r = File.open(fifo, IO::RDONLY|IO::NONBLOCK|IO::BINARY)
- w = File.open(fifo, IO::WRONLY|IO::NONBLOCK|IO::BINARY)
- else
- r = IO.for_fd($1.to_i(10), "rb", autoclose: false)
- w = IO.for_fd($2.to_i(10), "wb", autoclose: false)
- end
- rescue
- r.close if r
- else
- r.close_on_exec = true
- w.close_on_exec = true
- tokens = r.read_nonblock(wn > 0 ? wn : 1024, exception: false)
- r.close
- if String === tokens
- tokens.freeze
- auth = w
- w = nil
- at_exit {auth << tokens; auth.close}
- wn = tokens.size + 1
- else
- w.close
- wn = 1
- end
- end
- end
+ wn = Test::JobServer.max_jobs(wn > 0 ? wn : 1024, ENV.delete("MAKEFLAGS")) || wn
if wn <= 0
require 'etc'
wn = [Etc.nprocessors / 2, 1].max
@@ -298,7 +271,7 @@ End
if defined?(RUBY_DESCRIPTION)
puts "Driver is #{RUBY_DESCRIPTION}"
elsif defined?(RUBY_PATCHLEVEL)
- puts "Driver is ruby #{RUBY_VERSION} (#{RUBY_RELEASE_DATE}#{RUBY_PLATFORM}) [#{RUBY_PLATFORM}]"
+ puts "Driver is ruby #{RUBY_VERSION} (#{RUBY_RELEASE_DATE}#{RUBY_PATCHLEVEL}) [#{RUBY_PLATFORM}]"
else
puts "Driver is ruby #{RUBY_VERSION} (#{RUBY_RELEASE_DATE}) [#{RUBY_PLATFORM}]"
end
diff --git a/bootstraptest/test_flow.rb b/bootstraptest/test_flow.rb
index 15528a4213..7a95def1e6 100644
--- a/bootstraptest/test_flow.rb
+++ b/bootstraptest/test_flow.rb
@@ -376,7 +376,7 @@ assert_equal %q{[1, 4, 7, 5, 8, 9]}, %q{$a = []; begin; ; $a << 1
; $a << 3
end; $a << 4
def m2; $a << 5
- m1(:a, :b, (return 1; :c)); $a << 6
+ m1(:a, :b, (return 1 if true; :c)); $a << 6
end; $a << 7
m2; $a << 8
; $a << 9
@@ -399,7 +399,7 @@ assert_equal %q{[1, 3, 11, 4, 5, 6, 7, 12, 13]}, %q{$a = []; begin; ; $a << 1
m2(begin; $a << 5
2; $a << 6
ensure; $a << 7
- return 3; $a << 8
+ return 3 if true; $a << 8
end); $a << 9
4; $a << 10
end; $a << 11
diff --git a/bootstraptest/test_insns.rb b/bootstraptest/test_insns.rb
index 8a6efae089..1f70c8075c 100644
--- a/bootstraptest/test_insns.rb
+++ b/bootstraptest/test_insns.rb
@@ -86,7 +86,7 @@ tests = [
[ 'putobject', %q{ /(?<x>x)/ =~ "x"; x == "x" }, ],
[ 'putspecialobject', %q{ {//=>true}[//] }, ],
- [ 'putstring', %q{ "true" }, ],
+ [ 'dupstring', %q{ "true" }, ],
[ 'tostring / concatstrings', %q{ "#{true}" }, ],
[ 'toregexp', %q{ /#{true}/ =~ "true" && $~ }, ],
[ 'intern', %q{ :"#{true}" }, ],
@@ -426,11 +426,6 @@ tests = [
x&.x[true] ||= true # here
},
- [ 'opt_aref_with', %q{ { 'true' => true }['true'] }, ],
- [ 'opt_aref_with', %q{ Struct.new(:nil).new['nil'].nil? }, ],
- [ 'opt_aset_with', %q{ {}['true'] = true }, ],
- [ 'opt_aset_with', %q{ Struct.new(:true).new['true'] = true }, ],
-
[ 'opt_length', %q{ 'true' .length == 4 }, ],
[ 'opt_length', %q{ :true .length == 4 }, ],
[ 'opt_length', %q{ [ 'true' ] .length == 1 }, ],
diff --git a/bootstraptest/test_io.rb b/bootstraptest/test_io.rb
index 4e5d6d59c9..4081769a8c 100644
--- a/bootstraptest/test_io.rb
+++ b/bootstraptest/test_io.rb
@@ -85,7 +85,7 @@ assert_normal_exit %q{
ARGF.set_encoding "foo"
}
-/freebsd/ =~ RUBY_PLATFORM or
+/(freebsd|mswin)/ =~ RUBY_PLATFORM or
10.times do
assert_normal_exit %q{
at_exit { p :foo }
diff --git a/bootstraptest/test_method.rb b/bootstraptest/test_method.rb
index 997675200e..e894f6f601 100644
--- a/bootstraptest/test_method.rb
+++ b/bootstraptest/test_method.rb
@@ -1427,3 +1427,16 @@ assert_equal 'ok', <<~RUBY
test
RUBY
+
+assert_equal '[1, 2, 3]', %q{
+ def target(*args) = args
+ def x = [1]
+ def forwarder(...) = target(*x, 2, ...)
+ forwarder(3).inspect
+}, '[Bug #21832] post-splat args before forwarding'
+
+assert_equal '[nil, nil]', %q{
+ def self_reading(a = a, kw:) = a
+ def through_binding(a = binding.local_variable_get(:a), kw:) = a
+ [self_reading(kw: 1), through_binding(kw: 1)]
+}, 'nil initialization of optional parameters'
diff --git a/bootstraptest/test_ractor.rb b/bootstraptest/test_ractor.rb
index 4a58ece8ac..4fe90703fc 100644
--- a/bootstraptest/test_ractor.rb
+++ b/bootstraptest/test_ractor.rb
@@ -145,28 +145,107 @@ assert_equal '[:ok, :ok, :ok]', %q{
}.map(&:value)
}
-# Ractor.make_shareable issue for locals in proc [Bug #18023]
+assert_equal "42", %q{
+ a = 42
+ Ractor.shareable_lambda{ a }.call
+}
+
+# Ractor.shareable_proc issue for locals in proc [Bug #18023]
assert_equal '[:a, :b, :c, :d, :e]', %q{
v1, v2, v3, v4, v5 = :a, :b, :c, :d, :e
- closure = Ractor.current.instance_eval{ Proc.new { [v1, v2, v3, v4, v5] } }
+ closure = Proc.new { [v1, v2, v3, v4, v5] }
+ Ractor.shareable_proc(&closure).call
+}
+
+# Ractor.shareable_proc makes a copy of given Proc
+assert_equal '[true, true]', %q{
+ pr1 = Proc.new do
+ self
+ end
+ pr2 = Ractor.shareable_proc(&pr1)
+
+ [pr1.call == self, pr2.call == nil]
+}
+
+# Ractor.shareable_proc keeps the original Proc intact
+assert_equal '[SyntaxError, [Object, 43, 43], Binding]', %q{
+ a = 42
+ pr1 = Proc.new do
+ [self.class, eval("a"), binding.local_variable_get(:a)]
+ end
+ a += 1
+ pr2 = Ractor.shareable_proc(&pr1)
+
+ r = []
+ begin
+ pr2.call
+ rescue SyntaxError
+ r << SyntaxError
+ end
+
+ r << pr1.call << pr1.binding.class
+}
+
+# Ractor.make_shareable mutates the original Proc
+# This is the current behavior, it's currently considered safe enough
+# because in most cases it would raise anyway due to not-shared self or not-shared captured variable value
+assert_equal '[[42, 42], Binding, true, SyntaxError, "Can\'t create Binding from isolated Proc"]', %q{
+ a = 42
+ pr1 = nil.instance_exec do
+ Proc.new do
+ [eval("a"), binding.local_variable_get(:a)]
+ end
+ end
+
+ r = [pr1.call, pr1.binding.class]
+
+ pr2 = Ractor.make_shareable(pr1)
+ r << pr1.equal?(pr2)
+
+ begin
+ pr1.call
+ rescue SyntaxError
+ r << SyntaxError
+ end
+
+ begin
+ r << pr1.binding
+ rescue ArgumentError
+ r << $!.message
+ end
- Ractor.make_shareable(closure).call
+ r
}
-# Ractor.make_shareable issue for locals in proc [Bug #18023]
-assert_equal '[:a, :b, :c, :d, :e, :f, :g]', %q{
- a = :a
- closure = Ractor.current.instance_eval do
- -> {
- b, c, d = :b, :c, :d
- -> {
- e, f, g = :e, :f, :g
- -> { [a, b, c, d, e, f, g] }
- }.call
- }.call
+# Ractor::IsolationError cases
+assert_equal '3', %q{
+ ok = 0
+
+ begin
+ a = 1
+ Ractor.shareable_proc{a}
+ a = 2
+ rescue Ractor::IsolationError => e
+ ok += 1
end
- Ractor.make_shareable(closure).call
+ begin
+ cond = false
+ b = 1
+ b = 2 if cond
+ Ractor.shareable_proc{b}
+ rescue Ractor::IsolationError => e
+ ok += 1
+ end
+
+ begin
+ 1.times{|i|
+ i = 2
+ Ractor.shareable_proc{i}
+ }
+ rescue Ractor::IsolationError => e
+ ok += 1
+ end
}
###
@@ -237,7 +316,7 @@ assert_equal 30.times.map { 'ok' }.to_s, %q{
} unless (ENV.key?('TRAVIS') && ENV['TRAVIS_CPU_ARCH'] == 'arm64') # https://bugs.ruby-lang.org/issues/17878
# Exception for empty select
-assert_match /specify at least one ractor/, %q{
+assert_match /specify at least one Ractor::Port or Ractor/, %q{
begin
Ractor.select
rescue ArgumentError => e
@@ -415,7 +494,7 @@ assert_equal '{ok: 3}', %q{
end
3.times.map{Ractor.receive}.tally
-} unless yjit_enabled? || zjit_enabled? # YJIT: `[BUG] Bus Error at 0x000000010b7002d0` in jit_exec(), ZJIT hangs
+} unless yjit_enabled? # YJIT: `[BUG] Bus Error at 0x000000010b7002d0` in jit_exec()
# unshareable object are copied
assert_equal 'false', %q{
@@ -428,14 +507,14 @@ assert_equal 'false', %q{
}
# To copy the object, now Marshal#dump is used
-assert_equal "allocator undefined for Thread", %q{
+assert_match /can't clone unshareable instance of Thread/, %q{
obj = Thread.new{}
begin
r = Ractor.new obj do |msg|
msg
end
- rescue TypeError => e
- e.message #=> no _dump_data is defined for class Thread
+ rescue Ractor::Error => e
+ e.message
else
'ng'
end
@@ -724,7 +803,7 @@ assert_equal 'true', %q{
}
# given block Proc will be isolated, so can not access outer variables.
-assert_equal 'ArgumentError', %q{
+assert_equal 'Ractor::IsolationError', %q{
begin
a = true
r = Ractor.new do
@@ -735,8 +814,39 @@ assert_equal 'ArgumentError', %q{
end
}
+# eval with outer locals in a Ractor raises SyntaxError
+# [Bug #21522]
+assert_equal 'SyntaxError', %q{
+ outer = 42
+ r = Ractor.new do
+ eval("outer")
+ end
+ begin
+ r.value
+ rescue Ractor::RemoteError => e
+ e.cause.class
+ end
+}
+
+# eval of an undefined name in a Ractor raises NameError
+assert_equal 'NameError', %q{
+ r = Ractor.new do
+ eval("totally_undefined_name")
+ end
+ begin
+ r.value
+ rescue Ractor::RemoteError => e
+ e.cause.class
+ end
+}
+
+# eval of a local defined inside the Ractor works
+assert_equal '99', %q{
+ Ractor.new { inner = 99; eval("inner").to_s }.value
+}
+
# 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 (@iv from C)", <<~'RUBY', frozen_string_literal: false
class C
@iv = 'str'
end
@@ -911,8 +1021,8 @@ assert_equal '1234', %q{
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{
+# Reading non-shareable cvar from non-main Ractor is not allowed
+assert_equal 'can not read non-shareable class variable @@cv from non-main Ractors (C)', %q{
class C
@@cv = 'str'
end
@@ -930,8 +1040,8 @@ assert_equal 'can not access class variables from non-main Ractors', %q{
end
}
-# also cached 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{
+# also cached non-shareable cvar read from non-main Ractor is not allowed
+assert_equal 'can not read non-shareable class variable @@cv from non-main Ractors (C)', %q{
class C
@@cv = 'str'
def self.cv
@@ -952,6 +1062,95 @@ assert_equal 'can not access class variables from non-main Ractors', %q{
end
}
+# Reading shareable cvar from non-main Ractor is allowed
+assert_equal 'shareable', %q{
+ class C
+ @@cv = 'shareable'.freeze
+ def self.cv
+ @@cv
+ end
+ end
+
+ Ractor.new { C.cv }.value
+}
+
+# Reading shareable cvar (integer) from non-main Ractor is allowed
+assert_equal '42', %q{
+ class C
+ @@cv = 42
+ def self.cv
+ @@cv
+ end
+ end
+
+ Ractor.new { C.cv }.value.to_s
+}
+
+# Reading shareable cvar via module include from non-main Ractor is allowed
+assert_equal 'hello', %q{
+ module M
+ @@cv = 'hello'.freeze
+ def self.cv
+ @@cv
+ end
+ end
+
+ class C
+ include M
+ def self.cv
+ @@cv
+ end
+ end
+
+ Ractor.new { C.cv }.value
+}
+
+# Writing cvar from non-main Ractor is not allowed
+assert_equal 'can not set class variables from non-main Ractors (@@cv from C)', %q{
+ class C
+ @@cv = 'str'
+ def self.cv=(v)
+ @@cv = v
+ end
+ end
+
+ r = Ractor.new do
+ C.cv = 'new'
+ end
+
+ begin
+ r.join
+ rescue Ractor::RemoteError => e
+ e.cause.message
+ end
+}
+
+# Reading cvar that was made shareable after initial assignment
+assert_equal 'made shareable', %q{
+ class C
+ @@cv = +'made shareable'
+ Ractor.make_shareable(@@cv)
+ def self.cv
+ @@cv
+ end
+ end
+
+ Ractor.new { C.cv }.value
+}
+
+# cvar_defined? works from non-main Ractor
+assert_equal 'true', %q{
+ class C
+ @@cv = 42
+ def self.cv?
+ defined?(@@cv)
+ end
+ end
+
+ r = Ractor.new { C.cv? ? 'true' : 'false' }
+ r.value
+}
+
# 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
class C
@@ -967,7 +1166,7 @@ assert_equal 'can not access non-shareable objects in constant C::CONST by non-m
end
RUBY
-# Constant cache should care about non-sharable constants
+# Constant cache should care about non-shareable constants
assert_equal "can not access non-shareable objects in constant Object::STR by non-main Ractor.", <<~'RUBY', frozen_string_literal: false
STR = "hello"
def str; STR; end
@@ -979,6 +1178,20 @@ assert_equal "can not access non-shareable objects in constant Object::STR by no
end
RUBY
+# The correct constant path shall be reported
+assert_equal "can not access non-shareable objects in constant Object::STR by non-main Ractor.", <<~'RUBY', frozen_string_literal: false
+ STR = "hello"
+ module M
+ def self.str; STR; end
+ end
+
+ begin
+ Ractor.new{ M.str }.join
+ 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
class C
@@ -1056,6 +1269,24 @@ assert_equal 'ok', <<~'RUBY', frozen_string_literal: false
end.value
RUBY
+# Inserting into the id2ref table should be Ractor-safe
+assert_equal 'ok', <<~'RUBY'
+ # Force all calls to Kernel#object_id to insert into the id2ref table
+ obj = Object.new
+ ObjectSpace._id2ref(obj.object_id) rescue nil
+
+ 10.times.map do
+ Ractor.new do
+ 10_000.times do
+ a = Object.new
+ a.object_id
+ end
+ end
+ end.map(&:value)
+
+ :ok
+RUBY
+
# Ractor.make_shareable(obj)
assert_equal 'true', <<~'RUBY', frozen_string_literal: false
class C
@@ -1137,41 +1368,42 @@ assert_equal 'true', %q{
[a.frozen?, a[0].frozen?] == [true, false]
}
-# Ractor.make_shareable(a_proc) makes a proc shareable.
-assert_equal 'true', %q{
- a = [1, [2, 3], {a: "4"}]
+# Ractor.make_shareable(a_proc) requires a shareable receiver
+assert_equal '[:ok, "Proc\'s self is not shareable:"]', %q{
+ pr1 = nil.instance_exec { Proc.new{} }
+ pr2 = Proc.new{}
- pr = Ractor.current.instance_eval do
- Proc.new do
- a
+ [pr1, pr2].map do |pr|
+ begin
+ Ractor.make_shareable(pr)
+ rescue Ractor::Error => e
+ e.message[/^.+?:/]
+ else
+ :ok
end
end
-
- Ractor.make_shareable(a) # referred value should be shareable
- Ractor.make_shareable(pr)
- Ractor.shareable?(pr)
}
-# Ractor.make_shareable(a_proc) makes inner structure shareable and freezes it
-assert_equal 'true,true,true,true', %q{
- class Proc
- attr_reader :obj
- def initialize
- @obj = Object.new
- end
+# Ractor.make_shareable(Method/UnboundMethod)
+assert_equal 'true', %q{
+ # raise because receiver is unshareable
+ begin
+ _m0 = Ractor.make_shareable(self.method(:__id__))
+ rescue => e
+ raise e unless e.message =~ /can not make shareable object/
+ else
+ raise "no error"
end
- pr = Ractor.current.instance_eval do
- Proc.new {}
- end
+ # Method with shareable receiver
+ M1 = Ractor.make_shareable(Object.method(:__id__))
- results = []
- Ractor.make_shareable(pr)
- results << Ractor.shareable?(pr)
- results << pr.frozen?
- results << Ractor.shareable?(pr.obj)
- results << pr.obj.frozen?
- results.map(&:to_s).join(',')
+ # UnboundMethod
+ M2 = Ractor.make_shareable(Object.instance_method(:__id__))
+
+ Ractor.new do
+ Object.__id__ == M1.call && M1.call == M2.bind_call(Object)
+ end.value
}
# Ractor.shareable?(recursive_objects)
@@ -1202,50 +1434,16 @@ assert_equal '[C, M]', %q{
Ractor.make_shareable(ary = [C, M])
}
-# Ractor.make_shareable with curried proc checks isolation of original proc
-assert_equal 'isolation error', %q{
- a = Object.new
- orig = proc { a }
- curried = orig.curry
-
- begin
- Ractor.make_shareable(curried)
- rescue Ractor::IsolationError
- 'isolation error'
- else
- 'no error'
- end
-}
-
# define_method() can invoke different Ractor's proc if the proc is shareable.
assert_equal '1', %q{
class C
a = 1
- define_method "foo", Ractor.make_shareable(Proc.new{ a })
- a = 2
+ define_method "foo", Ractor.shareable_proc{ a }
end
Ractor.new{ C.new.foo }.value
}
-# Ractor.make_shareable(a_proc) makes a proc shareable.
-assert_equal 'can not make a Proc shareable because it accesses outer variables (a).', %q{
- a = b = nil
- pr = Ractor.current.instance_eval do
- Proc.new do
- c = b # assign to a is okay because c is block local variable
- # reading b is okay
- a = b # assign to a is not allowed #=> Ractor::Error
- end
- end
-
- begin
- Ractor.make_shareable(pr)
- rescue => e
- e.message
- end
-}
-
# Ractor.make_shareable(obj, copy: true) makes copied shareable object.
assert_equal '[false, false, true, true]', %q{
r = []
@@ -1302,7 +1500,7 @@ assert_equal '[:ok, :ok]', %q{
s = 'str'
trap(:INT){p s}
}.join
- rescue => Ractor::RemoteError
+ rescue Ractor::RemoteError
a << :ok
end
}
@@ -1400,6 +1598,9 @@ assert_equal "ok", %Q{
unless a[i].equal?(b[i])
raise [a[i], b[i]].inspect
end
+ unless a[i] == i.to_s
+ raise [i, a[i], b[i]].inspect
+ end
end
:ok
}
@@ -1420,18 +1621,17 @@ assert_equal "#{n}#{n}", %Q{
}.map{|r| r.value}.join
}
-# NameError
-assert_equal "ok", %q{
+# Now NoMethodError is copyable
+assert_equal "NoMethodError", %q{
obj = "".freeze # NameError refers the receiver indirectly
begin
obj.bar
rescue => err
end
- begin
- Ractor.new{} << err
- rescue TypeError
- 'ok'
- end
+
+ r = Ractor.new{ Ractor.receive }
+ r << err
+ r.value.class
}
assert_equal "ok", %q{
@@ -1471,42 +1671,6 @@ assert_equal "ok", %q{
"ok"
} if !yjit_enabled? && ENV['GITHUB_WORKFLOW'] != 'ModGC' # flaky
-assert_equal "ok", %q{
- def foo(*); ->{ super }; end
- begin
- Ractor.make_shareable(foo)
- rescue Ractor::IsolationError
- "ok"
- end
-}
-
-assert_equal "ok", %q{
- def foo(**); ->{ super }; end
- begin
- Ractor.make_shareable(foo)
- rescue Ractor::IsolationError
- "ok"
- end
-}
-
-assert_equal "ok", %q{
- def foo(...); ->{ super }; end
- begin
- Ractor.make_shareable(foo)
- rescue Ractor::IsolationError
- "ok"
- end
-}
-
-assert_equal "ok", %q{
- def foo((x), (y)); ->{ super }; end
- begin
- Ractor.make_shareable(foo([], []))
- rescue Ractor::IsolationError
- "ok"
- end
-}
-
# check method cache invalidation
assert_equal "ok", %q{
module M
@@ -1601,7 +1765,7 @@ assert_equal 'true', %q{
}
# check experimental warning
-assert_match /\Atest_ractor\.rb:1:\s+warning:\s+Ractor is experimental/, %q{
+assert_match /\Atest_ractor\.rb:1:\s+warning:\s+Ractor API is experimental/, %q{
Warning[:experimental] = $VERBOSE = true
STDERR.reopen(STDOUT)
eval("Ractor.new{}.value", nil, "test_ractor.rb", 1)
@@ -1999,7 +2163,7 @@ assert_equal 'ok', %q{
# move object with complex generic ivars
assert_equal 'ok', %q{
- # Make Array too_complex
+ # Make Array complex
30.times { |i| [].instance_variable_set(:"@complex#{i}", 1) }
ractor = Ractor.new { Ractor.receive }
@@ -2011,9 +2175,22 @@ assert_equal 'ok', %q{
roundtripped_obj.instance_variable_get(:@array1) == [1] ? :ok : roundtripped_obj
}
+# move object with generic ivars and existing id2ref table
+# [Bug #21664]
+assert_equal 'ok', %q{
+ obj = [1]
+ obj.instance_variable_set("@field", :ok)
+ ObjectSpace._id2ref(obj.object_id) # build id2ref table
+
+ ractor = Ractor.new { Ractor.receive }
+ ractor.send(obj, move: true)
+ obj = ractor.value
+ obj.instance_variable_get("@field")
+}
+
# copy object with complex generic ivars
assert_equal 'ok', %q{
- # Make Array too_complex
+ # Make Array complex
30.times { |i| [].instance_variable_set(:"@complex#{i}", 1) }
ractor = Ractor.new { Ractor.receive }
@@ -2327,22 +2504,6 @@ assert_equal '[["Only the successor ractor can take a value", 9], ["ok", 2]]', %
}.tally.sort
}
-# Ractor#take will warn for compatibility.
-# This method will be removed after 2025/09/01
-assert_equal "2", %q{
- raise "remove Ractor#take and this test" if Time.now > Time.new(2025, 9, 2)
- $VERBOSE = true
- r = Ractor.new{42}
- $msg = []
- def Warning.warn(msg)
- $msg << msg
- end
- r.take
- r.take
- raise unless $msg.all?{/Ractor#take/ =~ it}
- $msg.size
-}
-
# Cause lots of inline CC misses.
assert_equal 'ok', <<~'RUBY'
class A; def test; 1 + 1; end; end
@@ -2372,3 +2533,134 @@ assert_equal 'ok', <<~'RUBY'
ractors.each(&:join)
:ok
RUBY
+
+# This test checks that we do not trigger a GC when we have malloc with Ractor
+# locks. We cannot trigger a GC with Ractor locks because GC requires VM lock
+# and Ractor barrier. If another Ractor is waiting on this Ractor lock, then it
+# will deadlock because the other Ractor will never join the barrier.
+#
+# Creating Ractor::Port requires locking the Ractor and inserting into an
+# st_table, which can call malloc.
+assert_equal 'ok', <<~'RUBY'
+ r = Ractor.new do
+ loop do
+ Ractor::Port.new
+ end
+ end
+
+ 10.times do
+ 10_000.times do
+ r.send(nil)
+ end
+ sleep(0.01)
+ end
+ :ok
+RUBY
+
+assert_equal 'ok', <<~'RUBY'
+ begin
+ 100.times do |i|
+ Ractor.new(i) do |j|
+ 1000.times do |i|
+ "#{j}-#{i}"
+ end
+ Ractor.receive
+ end
+ pid = fork { }
+ _, status = Process.waitpid2 pid
+ raise unless status.success?
+ end
+
+ :ok
+ rescue NotImplementedError
+ :ok
+ end
+RUBY
+
+assert_equal 'ok', <<~'RUBY'
+ begin
+ 100.times do |i|
+ Ractor.new(i) do |j|
+ 1000.times do |i|
+ "#{j}-#{i}"
+ end
+ end
+ pid = fork do
+ GC.verify_internal_consistency
+ end
+ _, status = Process.waitpid2 pid
+ raise unless status.success?
+ end
+
+ :ok
+ rescue NotImplementedError
+ :ok
+ end
+RUBY
+
+# When creating bmethods in Ractors, they should only be usable from their
+# defining ractor, even if it is GC'd
+assert_equal 'ok', <<~'RUBY'
+
+begin
+ CLASSES = 1000.times.map { Class.new }.freeze
+
+ # This would be better to run in parallel, but there's a bug with lambda
+ # creation and YJIT causing crashes in dev mode
+ ractors = CLASSES.map do |klass|
+ Ractor.new(klass) do |klass|
+ Ractor.receive
+ klass.define_method(:foo) {}
+ end
+ end
+
+ ractors.each do |ractor|
+ ractor << nil
+ ractor.join
+ end
+
+ ractors.clear
+ GC.start
+
+ any = 1000.times.map do
+ Ractor.new do
+ CLASSES.any? do |klass|
+ begin
+ klass.new.foo
+ true
+ rescue RuntimeError
+ false
+ end
+ end
+ end
+ end.map(&:value).none? && :ok
+rescue ThreadError => e
+ # ignore limited memory machine
+ if /can\'t create Thread/ =~ e.message
+ :ok
+ else
+ raise
+ end
+end
+RUBY
+
+# Concurrent super calls with keyword arguments must not race on the
+# callinfo kwarg reference count. [Bug #22075]
+assert_equal 'ok', %q{
+ class Base
+ def foo(a:, b:, c:) = a
+ end
+
+ class Sub < Base
+ def foo(a:, b:, c:) = super(a: a, b: b, c: c)
+ end
+
+ 4.times.map do
+ Ractor.new do
+ obj = Sub.new
+ 100_000.times { obj.foo(a: 1, b: 2, c: 3) }
+ end
+ end.each(&:join)
+
+ :ok
+}
diff --git a/bootstraptest/test_syntax.rb b/bootstraptest/test_syntax.rb
index fbc9c6f62e..29bf93cb8f 100644
--- a/bootstraptest/test_syntax.rb
+++ b/bootstraptest/test_syntax.rb
@@ -571,7 +571,7 @@ assert_equal 'ok', %q{
assert_equal 'ok', %q{
1.times{
- p(1, (next; 2))
+ p(1, (next if true; 2))
}; :ok
}
assert_equal '3', %q{
@@ -585,7 +585,7 @@ assert_equal '3', %q{
i = 0
1 + (while true
break 2 if (i+=1) > 1
- p(1, (next; 2))
+ p(1, (next if true; 2))
end)
}
# redo
@@ -594,7 +594,7 @@ assert_equal 'ok', %q{
1.times{
break if i>1
i+=1
- p(1, (redo; 2))
+ p(1, (redo if true; 2))
}; :ok
}
assert_equal '3', %q{
@@ -608,7 +608,7 @@ assert_equal '3', %q{
i = 0
1 + (while true
break 2 if (i+=1) > 1
- p(1, (redo; 2))
+ p(1, (redo if true; 2))
end)
}
assert_equal '1', %q{
diff --git a/bootstraptest/test_yjit.rb b/bootstraptest/test_yjit.rb
index f76af3633d..e9ce905e2c 100644
--- a/bootstraptest/test_yjit.rb
+++ b/bootstraptest/test_yjit.rb
@@ -1330,7 +1330,7 @@ assert_equal '[42, :default]', %q{
]
}
-# Test default value block for Hash with opt_aref_with
+# Test default value block for Hash
assert_equal "false", <<~RUBY, frozen_string_literal: false
def index_with_string(h)
h["foo"]
@@ -2483,6 +2483,32 @@ assert_equal '[0, 2]', %q{
B.new.foo
}
+# invokesuper in a weird block
+assert_equal '["block->A#itself", "block->singleton#itself"]', %q{
+ # This test runs the same block as first as a block and then as a method,
+ # testing the routine that finds the currently running method, which is
+ # relevant for `super`.
+ class BlockIseqDuality
+ prepend(Module.new do
+ def itself
+ nested = -> { "block->" + super() }
+ @singleton_itself.define_singleton_method(:itself, &nested)
+ nested
+ end
+ end)
+
+ attr_reader :singleton_itself
+ def initialize = (@singleton_itself = "singleton#itself")
+
+ def itself = "A#itself"
+ end
+
+ tester = BlockIseqDuality.new
+ super_lambda = tester.itself
+ super_lambda.call # warmup
+ [super_lambda.call, tester.singleton_itself.itself]
+}
+
# invokesuper zsuper in a bmethod
assert_equal 'ok', %q{
class Foo
@@ -2680,6 +2706,22 @@ assert_equal '[1, 2]', %q{
expandarray_redefined_nilclass
}
+assert_equal 'not_array', %q{
+ def expandarray_not_array(obj)
+ a, = obj
+ a
+ end
+
+ obj = Object.new
+ def obj.method_missing(m, *args, &block)
+ return [:not_array] if m == :to_ary
+ super
+ end
+
+ expandarray_not_array(obj)
+ expandarray_not_array(obj)
+}
+
assert_equal '[1, 2, nil]', %q{
def expandarray_rhs_too_small
a, b, c = [1, 2]
@@ -4081,6 +4123,26 @@ assert_equal '1', %q{
bar { }
}
+# unshareable bmethod call through Method#to_proc#call
+assert_equal '1000', %q{
+ define_method(:bmethod) do
+ self
+ end
+
+ Ractor.new do
+ errors = 0
+ 1000.times do
+ p = method(:bmethod).to_proc
+ begin
+ p.call
+ rescue RuntimeError
+ errors += 1
+ end
+ end
+ errors
+ end.value
+}
+
# test for return stub lifetime issue
assert_equal '1', %q{
def foo(n)
@@ -4853,6 +4915,16 @@ assert_equal '[:ok, :ok, :ok, :ok, :ok]', %q{
tests
}
+# regression test for splat with &proc{} when the target has rest (Bug #21266)
+assert_equal '[]', %q{
+ def foo(args) = bar(*args, &proc { _1 })
+ def bar(_, _, _, _, *rest) = yield rest
+
+ GC.stress = true
+ foo([1,2,3,4])
+ foo([1,2,3,4])
+}
+
# regression test for invalidating an empty block
assert_equal '0', %q{
def foo = (* = 1).pred
@@ -5369,3 +5441,117 @@ assert_equal 'false', %{
RESULT.any?
}
+
+# throw and String#dup with GC stress
+assert_equal 'foo', %{
+ GC.stress = true
+
+ def foo
+ 1.times { return "foo".dup }
+ end
+
+ 10.times.map { foo.dup }.last
+}
+
+# regression test for [Bug #21772]
+# local variable type tracking desync
+assert_normal_exit %q{
+ def some_method = 0
+
+ def test_body(key)
+ some_method
+ key = key.to_s # setting of local relevant
+
+ key == "symbol"
+ end
+
+ def jit_caller = test_body("session_id")
+
+ jit_caller # first iteration, non-escaped environment
+ alias some_method binding # induce environment escape
+ test_body(:symbol)
+}
+
+# regression test for missing check in identity method inlining
+assert_normal_exit %q{
+ # Use dead code (if false) to create a local
+ # without initialization instructions.
+ def foo(a)
+ if false
+ x = nil
+ end
+ x
+ end
+ def test = foo(1)
+ test
+ test
+}
+
+# regression test for tracing invalidation with on-stack compiled methods
+# Exercises the on_stack_iseqs path in rb_yjit_tracing_invalidate_all
+# where delayed deallocation must not create aliasing &mut references
+# to IseqPayload (use-after-free of version_map backing storage).
+assert_normal_exit %q{
+ def deep = 42
+ def mid = deep
+ def outer = mid
+
+ # Compile all three methods with YJIT
+ 10.times { outer }
+
+ # Enable tracing from within a call chain so that outer/mid/deep
+ # are on the stack when rb_yjit_tracing_invalidate_all runs.
+ # This triggers the on_stack_iseqs (delayed deallocation) path.
+ def deep
+ TracePoint.new(:line) {}.enable
+ 42
+ end
+
+ outer
+
+ # After invalidation, verify YJIT can recompile and run correctly
+ def deep = 42
+ 10.times { outer }
+}
+
+# regression test for tracing invalidation with on-stack fibers
+# Suspended fibers have iseqs on their stack that must survive invalidation.
+assert_equal '42', %q{
+ def compiled_method
+ Fiber.yield
+ 42
+ end
+
+ # Compile the method
+ 10.times { compiled_method rescue nil }
+
+ fiber = Fiber.new { compiled_method }
+ fiber.resume # suspends inside compiled_method — it's now on the fiber's stack
+
+ # Enable tracing while compiled_method is on the fiber's stack.
+ # This triggers rb_yjit_tracing_invalidate_all with on-stack iseqs.
+ TracePoint.new(:call) {}.enable
+
+ # Resume the fiber — compiled_method's iseq must still be valid
+ fiber.resume.to_s
+}
+
+# regression test for register mapping of methods with over 256 locals
+# [Bug #22074]
+assert_equal "ok", %q{
+ source = +"def many_locals\n"
+ source << " total = 0\n"
+
+ 128.times do |i|
+ source << " y#{i} = 1\n"
+ source << " x#{i} = Object.new\n"
+ end
+
+ source << " total += 1\n"
+ source << " raise total.inspect unless total == 1\n"
+ source << "end\n"
+
+ eval(source)
+ many_locals
+ "ok"
+}
diff --git a/box.c b/box.c
new file mode 100644
index 0000000000..0ca7838be9
--- /dev/null
+++ b/box.c
@@ -0,0 +1,1299 @@
+/* indent-tabs-mode: nil */
+
+#include "eval_intern.h"
+#include "internal.h"
+#include "internal/box.h"
+#include "internal/class.h"
+#include "internal/eval.h"
+#include "internal/error.h"
+#include "internal/file.h"
+#include "internal/gc.h"
+#include "internal/hash.h"
+#include "internal/io.h"
+#include "internal/load.h"
+#include "internal/st.h"
+#include "internal/variable.h"
+#include "iseq.h"
+#include "ruby/internal/globals.h"
+#include "ruby/util.h"
+#include "vm_core.h"
+#include "darray.h"
+#include "zjit.h"
+
+#include "builtin.h"
+
+#include <stdio.h>
+
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+#ifdef HAVE_SYS_SENDFILE_H
+# include <sys/sendfile.h>
+#endif
+#ifdef HAVE_COPYFILE_H
+#include <copyfile.h>
+#endif
+
+VALUE rb_cBox = 0;
+VALUE rb_cBoxEntry = 0;
+VALUE rb_mBoxLoader = 0;
+
+static rb_box_t master_box[1]; /* Initialize in initialize_master_box() */
+static rb_box_t *root_box;
+static rb_box_t *main_box;
+
+static rb_box_gem_flags_t box_gem_flags[1];
+
+static char *tmp_dir;
+static bool tmp_dir_has_dirsep;
+
+#define BOX_TMP_PREFIX "_ruby_box_"
+
+#ifndef MAXPATHLEN
+# define MAXPATHLEN 1024
+#endif
+
+#if defined(_WIN32)
+# define DIRSEP "\\"
+#else
+# define DIRSEP "/"
+#endif
+
+bool ruby_box_enabled = false; // extern
+bool ruby_box_init_done = false; // extern
+bool ruby_box_crashed = false; // extern, changed only in vm.c
+
+VALUE rb_resolve_feature_path(VALUE klass, VALUE fname);
+static VALUE rb_box_inspect(VALUE obj);
+static void cleanup_all_local_extensions(VALUE libmap);
+
+void
+rb_box_set_gem_flags(rb_box_gem_flags_t *flags)
+{
+
+ box_gem_flags->gem = flags->gem;
+ box_gem_flags->error_highlight = flags->error_highlight;
+ box_gem_flags->did_you_mean = flags->did_you_mean;
+ box_gem_flags->syntax_suggest = flags->syntax_suggest;
+}
+
+void
+rb_box_init_done(void)
+{
+ ruby_box_init_done = true;
+}
+
+const rb_box_t *
+rb_master_box(void)
+{
+ return master_box;
+}
+
+const rb_box_t *
+rb_root_box(void)
+{
+ if (!root_box) // The root box isn't initialized yet - The Ruby runtime is in setup.
+ return master_box;
+ return root_box;
+}
+
+const rb_box_t *
+rb_main_box(void)
+{
+ return main_box;
+}
+
+const rb_box_t *
+rb_current_box(void)
+{
+ /*
+ * If RUBY_BOX is not set, the master box is the only available one.
+ *
+ * While the root/main boxes are not initialized, the master box is
+ * the only valid box.
+ * This early return is to avoid accessing EC before its setup.
+ */
+ if (!root_box)
+ return master_box;
+ if (!main_box)
+ return root_box;
+
+ return rb_vm_current_box(GET_EC());
+}
+
+const rb_box_t *
+rb_loading_box(void)
+{
+ if (!root_box)
+ return master_box;
+ if (!main_box)
+ return root_box;
+
+ return rb_vm_loading_box(GET_EC());
+}
+
+const rb_box_t *
+rb_current_box_in_crash_report(void)
+{
+ if (ruby_box_crashed)
+ return NULL;
+ return rb_current_box();
+}
+
+static long box_id_counter = 0;
+
+static long
+box_generate_id(void)
+{
+ long id;
+ RB_VM_LOCKING() {
+ id = ++box_id_counter;
+ }
+ return id;
+}
+
+static VALUE
+box_main_to_s(VALUE obj)
+{
+ return rb_str_new2("main");
+}
+
+static void
+box_entry_initialize(rb_box_t *box)
+{
+ const rb_box_t *master = rb_master_box();
+
+ // These will be updated immediately
+ box->box_object = 0;
+ box->box_id = 0;
+
+ box->top_self = rb_obj_alloc(rb_cObject);
+ rb_define_singleton_method(box->top_self, "to_s", box_main_to_s, 0);
+ rb_define_alias(rb_singleton_class(box->top_self), "inspect", "to_s");
+ box->load_path = rb_ary_dup(master->load_path);
+ box->expanded_load_path = rb_ary_dup(master->expanded_load_path);
+ box->load_path_snapshot = rb_ary_new();
+ box->load_path_check_cache = 0;
+ box->loaded_features = rb_ary_dup(master->loaded_features);
+ box->loaded_features_snapshot = rb_ary_new();
+ box->loaded_features_index = st_init_numtable();
+ box->loaded_features_realpaths = rb_hash_dup(master->loaded_features_realpaths);
+ box->loaded_features_realpath_map = rb_hash_dup(master->loaded_features_realpath_map);
+ box->loading_table = st_init_strtable();
+ box->ruby_dln_libmap = rb_hash_new_with_size(0);
+ box->gvar_tbl = rb_hash_new_with_size(0);
+ box->classext_cow_classes = st_init_numtable();
+
+ box->is_user = true;
+ box->is_optional = true;
+}
+
+void
+rb_box_gc_update_references(void *ptr)
+{
+ rb_box_t *box = (rb_box_t *)ptr;
+ if (!box) return;
+
+ if (box->box_object)
+ box->box_object = rb_gc_location(box->box_object);
+ if (box->top_self)
+ box->top_self = rb_gc_location(box->top_self);
+ box->load_path = rb_gc_location(box->load_path);
+ box->expanded_load_path = rb_gc_location(box->expanded_load_path);
+ box->load_path_snapshot = rb_gc_location(box->load_path_snapshot);
+ if (box->load_path_check_cache) {
+ box->load_path_check_cache = rb_gc_location(box->load_path_check_cache);
+ }
+ box->loaded_features = rb_gc_location(box->loaded_features);
+ box->loaded_features_snapshot = rb_gc_location(box->loaded_features_snapshot);
+ box->loaded_features_realpaths = rb_gc_location(box->loaded_features_realpaths);
+ box->loaded_features_realpath_map = rb_gc_location(box->loaded_features_realpath_map);
+ box->ruby_dln_libmap = rb_gc_location(box->ruby_dln_libmap);
+ box->gvar_tbl = rb_gc_location(box->gvar_tbl);
+}
+
+void
+rb_box_entry_mark(void *ptr)
+{
+ const rb_box_t *box = (rb_box_t *)ptr;
+ if (!box) return;
+
+ rb_gc_mark(box->box_object);
+ rb_gc_mark(box->top_self);
+ rb_gc_mark(box->load_path);
+ rb_gc_mark(box->expanded_load_path);
+ rb_gc_mark(box->load_path_snapshot);
+ rb_gc_mark(box->load_path_check_cache);
+ rb_gc_mark(box->loaded_features);
+ rb_gc_mark(box->loaded_features_snapshot);
+ rb_gc_mark(box->loaded_features_realpaths);
+ rb_gc_mark(box->loaded_features_realpath_map);
+ if (box->loading_table) {
+ rb_mark_tbl(box->loading_table);
+ }
+ rb_gc_mark(box->ruby_dln_libmap);
+ rb_gc_mark(box->gvar_tbl);
+ if (box->classext_cow_classes) {
+ rb_mark_set(box->classext_cow_classes);
+ }
+}
+
+static int
+free_loading_table_entry(st_data_t key, st_data_t value, st_data_t arg)
+{
+ xfree((char *)key);
+ return ST_DELETE;
+}
+
+static int
+free_loaded_feature_index_i(st_data_t key, st_data_t value, st_data_t arg)
+{
+ if (!FIXNUM_P(value)) {
+ rb_darray_free_sized((void *)value, long);
+ }
+ return ST_CONTINUE;
+}
+
+static void
+free_box_st_tables(void *ptr)
+{
+ rb_box_t *box = (rb_box_t *)ptr;
+ if (box->loading_table) {
+ st_foreach(box->loading_table, free_loading_table_entry, 0);
+ st_free_table(box->loading_table);
+ box->loading_table = 0;
+ }
+
+ if (box->loaded_features_index) {
+ st_foreach(box->loaded_features_index, free_loaded_feature_index_i, 0);
+ st_free_table(box->loaded_features_index);
+ }
+}
+
+static int
+free_classext_for_box(st_data_t key, st_data_t _value, st_data_t box_arg)
+{
+ rb_classext_t *ext;
+ VALUE obj = (VALUE)key;
+ const rb_box_t *box = (const rb_box_t *)box_arg;
+
+ if (RB_TYPE_P(obj, T_CLASS) || RB_TYPE_P(obj, T_MODULE)) {
+ ext = rb_class_unlink_classext(obj, box);
+ rb_class_classext_free(obj, ext, false);
+ }
+ else if (RB_TYPE_P(obj, T_ICLASS)) {
+ ext = rb_class_unlink_classext(obj, box);
+ rb_iclass_classext_free(obj, ext, false);
+ }
+ else {
+ rb_bug("Invalid type of object in classext_cow_classes: %s", rb_type_str(BUILTIN_TYPE(obj)));
+ }
+ return ST_CONTINUE;
+}
+
+static void
+box_entry_free(void *ptr)
+{
+ const rb_box_t *box = (const rb_box_t *)ptr;
+
+ if (box->classext_cow_classes) {
+ st_foreach(box->classext_cow_classes, free_classext_for_box, (st_data_t)box);
+ }
+
+ cleanup_all_local_extensions(box->ruby_dln_libmap);
+
+ free_box_st_tables(ptr);
+ SIZED_FREE(box);
+}
+
+static size_t
+box_entry_memsize(const void *ptr)
+{
+ size_t size = sizeof(rb_box_t);
+ const rb_box_t *box = (const rb_box_t *)ptr;
+ if (box->loaded_features_index) {
+ size += rb_st_memsize(box->loaded_features_index);
+ }
+ if (box->loading_table) {
+ size += rb_st_memsize(box->loading_table);
+ }
+ return size;
+}
+
+static const rb_data_type_t rb_box_data_type = {
+ "Ruby::Box::Entry",
+ {
+ rb_box_entry_mark,
+ box_entry_free,
+ box_entry_memsize,
+ rb_box_gc_update_references,
+ },
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY // TODO: enable RUBY_TYPED_WB_PROTECTED when inserting write barriers
+};
+
+static const rb_data_type_t rb_master_box_data_type = {
+ "Ruby::Box::Master",
+ {
+ rb_box_entry_mark,
+ free_box_st_tables,
+ box_entry_memsize,
+ rb_box_gc_update_references,
+ },
+ &rb_box_data_type, 0, RUBY_TYPED_FREE_IMMEDIATELY // TODO: enable RUBY_TYPED_WB_PROTECTED when inserting write barriers
+};
+
+VALUE
+rb_box_entry_alloc(VALUE klass)
+{
+ rb_box_t *entry;
+ VALUE obj = TypedData_Make_Struct(klass, rb_box_t, &rb_box_data_type, entry);
+ box_entry_initialize(entry);
+ return obj;
+}
+
+static rb_box_t *
+get_box_struct_internal(VALUE entry)
+{
+ rb_box_t *sval;
+ TypedData_Get_Struct(entry, rb_box_t, &rb_box_data_type, sval);
+ return sval;
+}
+
+rb_box_t *
+rb_get_box_t(VALUE box)
+{
+ VALUE entry;
+ ID id_box_entry;
+
+ VM_ASSERT(box);
+
+ if (NIL_P(box))
+ return (rb_box_t *)rb_root_box();
+
+ VM_ASSERT(BOX_OBJ_P(box));
+
+ CONST_ID(id_box_entry, "__box_entry__");
+ entry = rb_attr_get(box, id_box_entry);
+ return get_box_struct_internal(entry);
+}
+
+VALUE
+rb_get_box_object(rb_box_t *box)
+{
+ VM_ASSERT(box && box->box_object);
+ return box->box_object;
+}
+
+/*
+ * call-seq:
+ * Ruby::Box.new -> new_box
+ *
+ * Returns a new Ruby::Box object.
+ */
+static VALUE
+box_initialize(VALUE box_value)
+{
+ rb_box_t *box;
+ rb_classext_t *object_classext;
+ VALUE entry;
+ ID id_box_entry;
+ CONST_ID(id_box_entry, "__box_entry__");
+
+ if (!rb_box_available()) {
+ rb_raise(rb_eRuntimeError, "Ruby Box is disabled. Set RUBY_BOX=1 environment variable to use Ruby::Box.");
+ }
+
+ entry = rb_class_new_instance_pass_kw(0, NULL, rb_cBoxEntry);
+ box = get_box_struct_internal(entry);
+
+ box->box_object = box_value;
+ box->box_id = box_generate_id();
+ rb_define_singleton_method(box->load_path, "resolve_feature_path", rb_resolve_feature_path, 1);
+
+ // Set the Ruby::Box object unique/consistent from any boxes to have just single
+ // constant table from any view of every (including main) box.
+ // If a code in the box adds a constant, the constant will be visible even from root/main.
+ RCLASS_SET_PRIME_CLASSEXT_WRITABLE(box_value, true);
+
+ // Get a clean constant table of Object even by writable one
+ // because ns was just created, so it has not touched any constants yet.
+ object_classext = RCLASS_EXT_WRITABLE_IN_BOX(rb_cObject, box);
+ RCLASS_SET_CONST_TBL(box_value, RCLASSEXT_CONST_TBL(object_classext), true);
+
+ rb_ivar_set(box_value, id_box_entry, entry);
+
+ if (ruby_box_init_done) {
+ if (box_gem_flags->gem) {
+ rb_vm_call_cfunc_in_box(Qnil, rb_define_gem_modules, (VALUE)box_gem_flags, Qnil,
+ rb_str_new_cstr("before_prelude.user.dummy"), (const rb_box_t *)box);
+ rb_load_gem_prelude((VALUE)box);
+ }
+ }
+
+ // Invalidate ZJIT code that assumes only the root box is active
+ rb_zjit_invalidate_root_box();
+
+ return box_value;
+}
+
+/*
+ * call-seq:
+ * Ruby::Box.enabled? -> true or false
+ *
+ * Returns +true+ if Ruby::Box is enabled.
+ */
+static VALUE
+rb_box_s_getenabled(VALUE recv)
+{
+ return RBOOL(rb_box_available());
+}
+
+/*
+ * call-seq:
+ * Ruby::Box.current -> box, nil or false
+ *
+ * Returns the current box.
+ * Returns +nil+ if Ruby Box is not enabled.
+ */
+static VALUE
+rb_box_s_current(VALUE recv)
+{
+ const rb_box_t *box;
+
+ if (!rb_box_available())
+ return Qnil;
+
+ box = rb_vm_current_box(GET_EC());
+ VM_ASSERT(box && box->box_object);
+ return box->box_object;
+}
+
+/*
+ * call-seq:
+ * load_path -> array
+ *
+ * Returns box local load path.
+ */
+static VALUE
+rb_box_load_path(VALUE box)
+{
+ VM_ASSERT(BOX_OBJ_P(box));
+ return rb_get_box_t(box)->load_path;
+}
+
+#ifdef _WIN32
+UINT rb_w32_system_tmpdir(WCHAR *path, UINT len);
+#endif
+
+/* Copied from mjit.c Ruby 3.0.3 */
+static char *
+system_default_tmpdir(void)
+{
+ // c.f. ext/etc/etc.c:etc_systmpdir()
+#ifdef _WIN32
+ WCHAR tmppath[_MAX_PATH];
+ UINT len = rb_w32_system_tmpdir(tmppath, numberof(tmppath));
+ if (len) {
+ int blen = WideCharToMultiByte(CP_UTF8, 0, tmppath, len, NULL, 0, NULL, NULL);
+ char *tmpdir = xmalloc(blen + 1);
+ WideCharToMultiByte(CP_UTF8, 0, tmppath, len, tmpdir, blen, NULL, NULL);
+ tmpdir[blen] = '\0';
+ return tmpdir;
+ }
+#elif 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 _WIN32
+# 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;
+#endif
+ 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
+}
+
+/* end of copy */
+
+static int
+sprint_ext_filename(char *str, size_t size, long box_id, const char *prefix, const char *basename)
+{
+ if (tmp_dir_has_dirsep) {
+ return snprintf(str, size, "%s%sp%"PRI_PIDT_PREFIX"u_%ld_%s", tmp_dir, prefix, getpid(), box_id, basename);
+ }
+ return snprintf(str, size, "%s%s%sp%"PRI_PIDT_PREFIX"u_%ld_%s", tmp_dir, DIRSEP, prefix, getpid(), box_id, basename);
+}
+
+enum copy_error_type {
+ COPY_ERROR_NONE,
+ COPY_ERROR_SRC_OPEN,
+ COPY_ERROR_DST_OPEN,
+ COPY_ERROR_SRC_READ,
+ COPY_ERROR_DST_WRITE,
+ COPY_ERROR_SRC_STAT,
+ COPY_ERROR_DST_CHMOD,
+ COPY_ERROR_SYSERR
+};
+
+static const char *
+copy_ext_file_error(char *message, size_t size, int copy_retvalue)
+{
+#ifdef _WIN32
+ int error = GetLastError();
+ char *p = message;
+ size_t len = snprintf(message, size, "%d: ", error);
+
+#define format_message(sublang) FormatMessage(\
+ FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, \
+ NULL, error, MAKELANGID(LANG_NEUTRAL, (sublang)), \
+ message + len, size - len, NULL)
+ if (format_message(SUBLANG_ENGLISH_US) == 0)
+ format_message(SUBLANG_DEFAULT);
+ for (p = message + len; *p; p++) {
+ if (*p == '\n' || *p == '\r')
+ *p = ' ';
+ }
+#else
+ switch (copy_retvalue) {
+ case COPY_ERROR_SRC_OPEN:
+ strlcpy(message, "can't open the extension path", size);
+ break;
+ case COPY_ERROR_DST_OPEN:
+ strlcpy(message, "can't open the file to write", size);
+ break;
+ case COPY_ERROR_SRC_READ:
+ strlcpy(message, "failed to read the extension path", size);
+ break;
+ case COPY_ERROR_DST_WRITE:
+ strlcpy(message, "failed to write the extension path", size);
+ break;
+ case COPY_ERROR_SRC_STAT:
+ strlcpy(message, "failed to stat the extension path to copy permissions", size);
+ break;
+ case COPY_ERROR_DST_CHMOD:
+ strlcpy(message, "failed to set permissions to the copied extension path", size);
+ break;
+ case COPY_ERROR_SYSERR:
+ strlcpy(message, strerror(errno), size);
+ break;
+ case COPY_ERROR_NONE: /* shouldn't be called */
+ default:
+ rb_bug("unknown return value of copy_ext_file: %d", copy_retvalue);
+ }
+#endif
+ return message;
+}
+
+#ifndef _WIN32
+static enum copy_error_type
+copy_stream(int src_fd, int dst_fd)
+{
+ char buffer[1024];
+ ssize_t rsize;
+
+ while ((rsize = read(src_fd, buffer, sizeof(buffer))) != 0) {
+ if (rsize < 0) return COPY_ERROR_SRC_READ;
+ for (size_t written = 0; written < (size_t)rsize;) {
+ ssize_t wsize = write(dst_fd, buffer+written, rsize-written);
+ if (wsize < 0) return COPY_ERROR_DST_WRITE;
+ written += (size_t)wsize;
+ }
+ }
+ return COPY_ERROR_NONE;
+}
+#endif
+
+static enum copy_error_type
+copy_ext_file(const char *src_path, const char *dst_path)
+{
+#if defined(_WIN32)
+ WCHAR *w_src = rb_w32_mbstr_to_wstr(CP_UTF8, src_path, -1, NULL);
+ WCHAR *w_dst = rb_w32_mbstr_to_wstr(CP_UTF8, dst_path, -1, NULL);
+ if (!w_src || !w_dst) {
+ free(w_src);
+ free(w_dst);
+ rb_memerror();
+ }
+
+ enum copy_error_type rvalue = CopyFileW(w_src, w_dst, TRUE) ?
+ COPY_ERROR_NONE : COPY_ERROR_SYSERR;
+ free(w_src);
+ free(w_dst);
+ return rvalue;
+#else
+# ifdef O_BINARY
+ const int bin = O_BINARY;
+# else
+ const int bin = 0;
+# endif
+# ifdef O_CLOEXEC
+ const int cloexec = O_CLOEXEC;
+# else
+ const int cloexec = 0;
+# endif
+ const int src_fd = open(src_path, O_RDONLY|cloexec|bin);
+ if (src_fd < 0) return COPY_ERROR_SRC_OPEN;
+ if (!cloexec) rb_maygvl_fd_fix_cloexec(src_fd);
+
+ struct stat src_st;
+ if (fstat(src_fd, &src_st)) {
+ close(src_fd);
+ return COPY_ERROR_SRC_STAT;
+ }
+
+ const int dst_fd = open(dst_path, O_WRONLY|O_CREAT|O_EXCL|cloexec|bin, S_IRWXU);
+ if (dst_fd < 0) {
+ close(src_fd);
+ return COPY_ERROR_DST_OPEN;
+ }
+ if (!cloexec) rb_maygvl_fd_fix_cloexec(dst_fd);
+
+ enum copy_error_type ret = COPY_ERROR_NONE;
+
+ if (fchmod(dst_fd, src_st.st_mode & 0777)) {
+ ret = COPY_ERROR_DST_CHMOD;
+ goto done;
+ }
+
+ const size_t count_max = (SIZE_MAX >> 1) + 1;
+ (void)count_max;
+
+# ifdef HAVE_COPY_FILE_RANGE
+ for (;;) {
+ ssize_t written = copy_file_range(src_fd, NULL, dst_fd, NULL, count_max, 0);
+ if (written == 0) goto done;
+ if (written < 0) break;
+ }
+# endif
+# ifdef HAVE_FCOPYFILE
+ if (fcopyfile(src_fd, dst_fd, NULL, COPYFILE_DATA) == 0) {
+ goto done;
+ }
+# endif
+# ifdef USE_SENDFILE
+ for (;;) {
+ ssize_t written = sendfile(src_fd, dst_fd, NULL count_max);
+ if (written == 0) goto done;
+ if (written < 0) break;
+ }
+# endif
+ ret = copy_stream(src_fd, dst_fd);
+
+ done:
+ close(src_fd);
+ if (dst_fd >= 0) close(dst_fd);
+ if (ret != COPY_ERROR_NONE) unlink(dst_path);
+ return ret;
+#endif
+}
+
+#if defined __CYGWIN__ || defined DOSISH
+#define isdirsep(x) ((x) == '/' || (x) == '\\')
+#else
+#define isdirsep(x) ((x) == '/')
+#endif
+
+#define IS_SOEXT(e) (strcmp((e), ".so") == 0 || strcmp((e), ".o") == 0)
+#define IS_DLEXT(e) (strcmp((e), DLEXT) == 0)
+
+static void
+fname_without_suffix(const char *fname, char *rvalue, size_t rsize)
+{
+ size_t len = strlen(fname);
+ const char *pos;
+ for (pos = fname + len; pos > fname; pos--) {
+ if (IS_SOEXT(pos) || IS_DLEXT(pos)) {
+ len = pos - fname;
+ break;
+ }
+ if (fname + len - pos > DLEXT_MAXLEN) break;
+ }
+ if (len > rsize - 1) len = rsize - 1;
+ memcpy(rvalue, fname, len);
+ rvalue[len] = '\0';
+}
+
+static void
+escaped_basename(const char *path, const char *fname, char *rvalue, size_t rsize)
+{
+ char *pos;
+ const char *leaf = path, *found;
+ // `leaf + 1` looks uncomfortable (when leaf == path), but fname must not be the top-dir itself
+ while ((found = strstr(leaf + 1, fname)) != NULL) {
+ leaf = found; // find the last occurrence for the path like /etc/my-crazy-lib-dir/etc.so
+ }
+ strlcpy(rvalue, leaf, rsize);
+ for (pos = rvalue; *pos; pos++) {
+ if (isdirsep(*pos)) {
+ *pos = '+';
+ }
+ }
+}
+
+static void
+box_ext_cleanup_mark(void *p)
+{
+ rb_gc_mark((VALUE)p);
+}
+
+static void
+box_ext_cleanup_free(void *p)
+{
+ VALUE path = (VALUE)p;
+ unlink(RSTRING_PTR(path));
+}
+
+static const rb_data_type_t box_ext_cleanup_type = {
+ "box_ext_cleanup",
+ {box_ext_cleanup_mark, box_ext_cleanup_free},
+ .flags = RUBY_TYPED_FREE_IMMEDIATELY,
+};
+
+void
+rb_box_cleanup_local_extension(VALUE cleanup)
+{
+ void *p = DATA_PTR(cleanup);
+ DATA_PTR(cleanup) = NULL;
+#ifndef _WIN32
+ if (p) box_ext_cleanup_free(p);
+#endif
+ (void)p;
+}
+
+static int
+cleanup_local_extension_i(VALUE key, VALUE value, VALUE arg)
+{
+#if defined(_WIN32)
+ HMODULE h = (HMODULE)NUM2PTR(value);
+ WCHAR module_path[MAXPATHLEN];
+ DWORD len = GetModuleFileNameW(h, module_path, numberof(module_path));
+
+ FreeLibrary(h);
+ if (len > 0 && len < numberof(module_path)) DeleteFileW(module_path);
+#endif
+ return ST_DELETE;
+}
+
+static void
+cleanup_all_local_extensions(VALUE libmap)
+{
+ rb_hash_foreach(libmap, cleanup_local_extension_i, 0);
+}
+
+VALUE
+rb_box_local_extension(VALUE box_value, VALUE fname, VALUE path, VALUE *cleanup)
+{
+ char ext_path[MAXPATHLEN], fname2[MAXPATHLEN], basename[MAXPATHLEN];
+ int wrote;
+ const char *src_path = RSTRING_PTR(path), *fname_ptr = RSTRING_PTR(fname);
+ rb_box_t *box = rb_get_box_t(box_value);
+
+ fname_without_suffix(fname_ptr, fname2, sizeof(fname2));
+ escaped_basename(src_path, fname2, basename, sizeof(basename));
+
+ wrote = sprint_ext_filename(ext_path, sizeof(ext_path), box->box_id, BOX_TMP_PREFIX, basename);
+ if (wrote >= (int)sizeof(ext_path)) {
+ rb_bug("Extension file path in the box was too long");
+ }
+ VALUE new_path = rb_str_new_cstr(ext_path);
+ *cleanup = TypedData_Wrap_Struct(0, &box_ext_cleanup_type, NULL);
+ enum copy_error_type copy_error = copy_ext_file(src_path, ext_path);
+ if (copy_error) {
+ char message[1024];
+ copy_ext_file_error(message, sizeof(message), copy_error);
+ rb_raise(rb_eLoadError, "can't prepare the extension file for Ruby Box (%s from %"PRIsVALUE"): %s", ext_path, path, message);
+ }
+ DATA_PTR(*cleanup) = (void *)new_path;
+ return new_path;
+}
+
+static VALUE
+rb_box_load(int argc, VALUE *argv, VALUE box)
+{
+ VALUE fname, wrap;
+ rb_scan_args(argc, argv, "11", &fname, &wrap);
+
+ rb_vm_frame_flag_set_box_require(GET_EC());
+
+ return rb_load_entrypoint(fname, wrap);
+}
+
+static VALUE
+rb_box_require(VALUE box, VALUE fname)
+{
+ rb_vm_frame_flag_set_box_require(GET_EC());
+
+ return rb_require_string(fname);
+}
+
+static VALUE
+rb_box_require_relative(VALUE box, VALUE fname)
+{
+ rb_vm_frame_flag_set_box_require(GET_EC());
+
+ return rb_require_relative_entrypoint(fname);
+}
+
+static void
+initialize_master_box(void)
+{
+ rb_vm_t *vm = GET_VM();
+ rb_box_t *master = (rb_box_t *)rb_master_box();
+
+ master->load_path = rb_ary_new();
+ master->expanded_load_path = rb_ary_hidden_new(0);
+ master->load_path_snapshot = rb_ary_hidden_new(0);
+ master->load_path_check_cache = 0;
+ rb_define_singleton_method(master->load_path, "resolve_feature_path", rb_resolve_feature_path, 1);
+
+ master->loaded_features = rb_ary_new();
+ master->loaded_features_snapshot = rb_ary_hidden_new(0);
+ master->loaded_features_index = st_init_numtable();
+ master->loaded_features_realpaths = rb_hash_new();
+ rb_obj_hide(master->loaded_features_realpaths);
+ master->loaded_features_realpath_map = rb_hash_new();
+ rb_obj_hide(master->loaded_features_realpath_map);
+
+ master->ruby_dln_libmap = rb_hash_new_with_size(0);
+ master->gvar_tbl = rb_hash_new_with_size(0);
+ master->classext_cow_classes = NULL; // classext CoW never happen on the master box
+
+ vm->master_box = master;
+
+ if (rb_box_available()) {
+ VALUE master_box, entry;
+ ID id_box_entry;
+ CONST_ID(id_box_entry, "__box_entry__");
+
+ master_box = rb_obj_alloc(rb_cBox);
+ RCLASS_SET_PRIME_CLASSEXT_WRITABLE(master_box, true);
+ RCLASS_SET_CONST_TBL(master_box, RCLASSEXT_CONST_TBL(RCLASS_EXT_PRIME(rb_cObject)), true);
+
+ master->box_id = box_generate_id();
+ master->box_object = master_box;
+
+ entry = TypedData_Wrap_Struct(rb_cBoxEntry, &rb_master_box_data_type, master);
+ rb_ivar_set(master_box, id_box_entry, entry);
+
+ rb_gc_register_mark_object(master_box);
+ rb_gc_register_mark_object(entry);
+ }
+ else {
+ master->box_id = 1;
+ master->box_object = Qnil;
+ }
+}
+
+static VALUE
+rb_box_eval(VALUE box_value, VALUE str)
+{
+ const rb_iseq_t *iseq;
+ const rb_box_t *box;
+
+ StringValue(str);
+
+ iseq = rb_iseq_compile_iseq(str, rb_str_new_cstr("eval"));
+ VM_ASSERT(iseq);
+
+ box = (const rb_box_t *)rb_get_box_t(box_value);
+
+ return rb_iseq_eval(iseq, box);
+}
+
+static int box_experimental_warned = 0;
+
+RUBY_EXTERN const char ruby_api_version_name[];
+
+static VALUE
+box_value_initialize(bool root, bool user, bool optional)
+{
+ rb_box_t *box;
+ VALUE box_value = rb_class_new_instance(0, NULL, rb_cBox);
+
+ VM_ASSERT(BOX_OBJ_P(box_value));
+
+ box = rb_get_box_t(box_value);
+ box->box_object = box_value;
+ box->is_root = root;
+ box->is_user = user;
+ box->is_optional = optional;
+ return box_value;
+}
+
+void
+rb_initialize_mandatory_boxes(void)
+{
+ VALUE root_box_value, main_box_value;
+ rb_vm_t *vm = GET_VM();
+
+ VM_ASSERT(rb_box_available());
+
+ if (!box_experimental_warned) {
+ rb_category_warn(RB_WARN_CATEGORY_EXPERIMENTAL,
+ "Ruby::Box is experimental, and the behavior may change in the future!\n"
+ "See https://docs.ruby-lang.org/en/%s/Ruby/Box.html for known issues, etc.",
+ ruby_api_version_name);
+ box_experimental_warned = 1;
+ }
+
+ root_box_value = box_value_initialize(true, false, false);
+ main_box_value = box_value_initialize(false, true, false);
+
+ rb_const_set(rb_cBox, rb_intern("ROOT"), root_box_value);
+ rb_const_set(rb_cBox, rb_intern("MAIN"), main_box_value);
+
+ vm->root_box = root_box = rb_get_box_t(root_box_value);
+ vm->main_box = main_box = rb_get_box_t(main_box_value);
+
+ // create the writable classext of ::Object explicitly to finalize the set of visible top-level constants
+ RCLASS_EXT_WRITABLE_IN_BOX(rb_cObject, root_box);
+ RCLASS_EXT_WRITABLE_IN_BOX(rb_cObject, main_box);
+}
+
+static VALUE
+rb_box_inspect(VALUE obj)
+{
+ rb_box_t *box;
+ VALUE r;
+ if (obj == Qfalse) {
+ r = rb_str_new_cstr("#<Ruby::Box:master>");
+ return r;
+ }
+ box = rb_get_box_t(obj);
+ r = rb_str_new_cstr("#<Ruby::Box:");
+ rb_str_concat(r, rb_funcall(LONG2NUM(box->box_id), rb_intern("to_s"), 0));
+ if (BOX_MASTER_P(box)) {
+ rb_str_cat_cstr(r, ",master");
+ }
+ if (BOX_ROOT_P(box)) {
+ rb_str_cat_cstr(r, ",root");
+ }
+ if (BOX_USER_P(box)) {
+ rb_str_cat_cstr(r, ",user");
+ }
+ if (BOX_MAIN_P(box)) {
+ rb_str_cat_cstr(r, ",main");
+ }
+ else if (BOX_OPTIONAL_P(box)) {
+ rb_str_cat_cstr(r, ",optional");
+ }
+ rb_str_cat_cstr(r, ">");
+ return r;
+}
+
+static VALUE
+rb_box_loading_func(int argc, VALUE *argv, VALUE _self)
+{
+ rb_vm_frame_flag_set_box_require(GET_EC());
+ return rb_call_super(argc, argv);
+}
+
+static void
+box_define_loader_method(const char *name)
+{
+ rb_define_private_method(rb_mBoxLoader, name, rb_box_loading_func, -1);
+ rb_define_singleton_method(rb_mBoxLoader, name, rb_box_loading_func, -1);
+}
+
+void
+Init_master_box(void)
+{
+ master_box->loading_table = st_init_strtable();
+}
+
+void
+Init_enable_box(void)
+{
+ const char *env = getenv("RUBY_BOX");
+ if (env && strlen(env) == 1 && env[0] == '1') {
+ ruby_box_enabled = true;
+ }
+ else {
+ ruby_box_init_done = true;
+ }
+}
+
+/* :nodoc: */
+static VALUE
+rb_box_s_master(VALUE recv)
+{
+ return master_box->box_object;
+}
+
+/* :nodoc: */
+static VALUE
+rb_box_s_root(VALUE recv)
+{
+ return root_box->box_object;
+}
+
+/* :nodoc: */
+static VALUE
+rb_box_s_main(VALUE recv)
+{
+ return main_box->box_object;
+}
+
+/* :nodoc: */
+static VALUE
+rb_box_master_p(VALUE box_value)
+{
+ const rb_box_t *box = (const rb_box_t *)rb_get_box_t(box_value);
+ return RBOOL(BOX_MASTER_P(box));
+}
+
+/* :nodoc: */
+static VALUE
+rb_box_root_p(VALUE box_value)
+{
+ const rb_box_t *box = (const rb_box_t *)rb_get_box_t(box_value);
+ return RBOOL(BOX_ROOT_P(box));
+}
+
+/* :nodoc: */
+static VALUE
+rb_box_main_p(VALUE box_value)
+{
+ const rb_box_t *box = (const rb_box_t *)rb_get_box_t(box_value);
+ return RBOOL(BOX_MAIN_P(box));
+}
+
+#if RUBY_DEBUG
+
+static const char *
+classname(VALUE klass)
+{
+ VALUE p;
+ if (!klass) {
+ return "Qfalse";
+ }
+ p = RCLASSEXT_CLASSPATH(RCLASS_EXT_PRIME(klass));
+ if (RTEST(p))
+ return RSTRING_PTR(p);
+ if (RB_TYPE_P(klass, T_CLASS) || RB_TYPE_P(klass, T_MODULE) || RB_TYPE_P(klass, T_ICLASS))
+ return "AnyClassValue";
+ return "NonClassValue";
+}
+
+static enum rb_id_table_iterator_result
+dump_classext_methods_i(ID mid, VALUE _val, void *data)
+{
+ VALUE ary = (VALUE)data;
+ rb_ary_push(ary, rb_id2str(mid));
+ return ID_TABLE_CONTINUE;
+}
+
+static enum rb_id_table_iterator_result
+dump_classext_constants_i(ID mid, VALUE _val, void *data)
+{
+ VALUE ary = (VALUE)data;
+ rb_ary_push(ary, rb_id2str(mid));
+ return ID_TABLE_CONTINUE;
+}
+
+static void
+dump_classext_i(rb_classext_t *ext, bool is_prime, VALUE _recv, void *data)
+{
+ char buf[4096];
+ struct rb_id_table *tbl;
+ VALUE ary, res = (VALUE)data;
+
+ snprintf(buf, 4096, "Ruby::Box %ld:%s classext %p\n",
+ RCLASSEXT_BOX(ext)->box_id, is_prime ? " prime" : "", (void *)ext);
+ rb_str_cat_cstr(res, buf);
+
+ snprintf(buf, 2048, " Super: %s\n", classname(RCLASSEXT_SUPER(ext)));
+ rb_str_cat_cstr(res, buf);
+
+ tbl = RCLASSEXT_M_TBL(ext);
+ if (tbl) {
+ ary = rb_ary_new_capa((long)rb_id_table_size(tbl));
+ rb_id_table_foreach(RCLASSEXT_M_TBL(ext), dump_classext_methods_i, (void *)ary);
+ rb_ary_sort_bang(ary);
+ snprintf(buf, 4096, " Methods(%ld): ", RARRAY_LEN(ary));
+ rb_str_cat_cstr(res, buf);
+ rb_str_concat(res, rb_ary_join(ary, rb_str_new_cstr(",")));
+ rb_str_cat_cstr(res, "\n");
+ }
+ else {
+ rb_str_cat_cstr(res, " Methods(0): .\n");
+ }
+
+ tbl = RCLASSEXT_CONST_TBL(ext);
+ if (tbl) {
+ ary = rb_ary_new_capa((long)rb_id_table_size(tbl));
+ rb_id_table_foreach(tbl, dump_classext_constants_i, (void *)ary);
+ rb_ary_sort_bang(ary);
+ snprintf(buf, 4096, " Constants(%ld): ", RARRAY_LEN(ary));
+ rb_str_cat_cstr(res, buf);
+ rb_str_concat(res, rb_ary_join(ary, rb_str_new_cstr(",")));
+ rb_str_cat_cstr(res, "\n");
+ }
+ else {
+ rb_str_cat_cstr(res, " Constants(0): .\n");
+ }
+}
+
+/* :nodoc: */
+static VALUE
+rb_f_dump_classext(VALUE recv, VALUE klass)
+{
+ /*
+ * The desired output String value is:
+ * Class: 0x88800932 (String) [singleton]
+ * Prime classext box(2,main), readable(t), writable(f)
+ * Non-prime classexts: 3
+ * Box 2: prime classext 0x88800933
+ * Super: Object
+ * Methods(43): aaaaa, bbbb, cccc, dddd, eeeee, ffff, gggg, hhhhh, ...
+ * Constants(12): FOO, Bar, ...
+ * Box 5: classext 0x88800934
+ * Super: Object
+ * Methods(43): aaaaa, bbbb, cccc, dddd, eeeee, ffff, gggg, hhhhh, ...
+ * Constants(12): FOO, Bar, ...
+ */
+ char buf[2048];
+ VALUE res;
+ const rb_classext_t *ext;
+ const rb_box_t *box;
+ st_table *classext_tbl;
+
+ if (!(RB_TYPE_P(klass, T_CLASS) || RB_TYPE_P(klass, T_MODULE))) {
+ snprintf(buf, 2048, "Non-class/module value: %p (%s)\n", (void *)klass, rb_type_str(BUILTIN_TYPE(klass)));
+ return rb_str_new_cstr(buf);
+ }
+
+ if (RB_TYPE_P(klass, T_CLASS)) {
+ snprintf(buf, 2048, "Class: %p (%s)%s\n",
+ (void *)klass, classname(klass), RCLASS_SINGLETON_P(klass) ? " [singleton]" : "");
+ }
+ else {
+ snprintf(buf, 2048, "Module: %p (%s)\n", (void *)klass, classname(klass));
+ }
+ res = rb_str_new_cstr(buf);
+
+ ext = RCLASS_EXT_PRIME(klass);
+ box = RCLASSEXT_BOX(ext);
+ snprintf(buf, 2048, "Prime classext box(%ld,%s), readable(%s), writable(%s)\n",
+ box->box_id,
+ BOX_MASTER_P(box) ? "master" : (BOX_ROOT_P(box) ? "root" : (BOX_MAIN_P(box) ? "main" : "optional")),
+ RCLASS_PRIME_CLASSEXT_READABLE_P(klass) ? "t" : "f",
+ RCLASS_PRIME_CLASSEXT_WRITABLE_P(klass) ? "t" : "f");
+ rb_str_cat_cstr(res, buf);
+
+ classext_tbl = RCLASS_CLASSEXT_TBL(klass);
+ if (!classext_tbl) {
+ rb_str_cat_cstr(res, "Non-prime classexts: 0\n");
+ }
+ else {
+ snprintf(buf, 2048, "Non-prime classexts: %zu\n", st_table_size(classext_tbl));
+ rb_str_cat_cstr(res, buf);
+ }
+
+ rb_class_classext_foreach(klass, dump_classext_i, (void *)res);
+
+ return res;
+}
+
+#endif /* RUBY_DEBUG */
+
+/*
+ * Document-class: Ruby::Box
+ *
+ * :markup: markdown
+ * :include: doc/language/box.md
+ */
+void
+Init_Box(void)
+{
+ tmp_dir = system_tmpdir();
+ tmp_dir_has_dirsep = (strcmp(tmp_dir + (strlen(tmp_dir) - strlen(DIRSEP)), DIRSEP) == 0);
+
+ VALUE mRuby = rb_define_module("Ruby");
+
+ rb_cBox = rb_define_class_under(mRuby, "Box", rb_cModule);
+ rb_define_method(rb_cBox, "initialize", box_initialize, 0);
+
+ /* :nodoc: */
+ rb_cBoxEntry = rb_define_class_under(rb_cBox, "Entry", rb_cObject);
+ rb_define_alloc_func(rb_cBoxEntry, rb_box_entry_alloc);
+
+ initialize_master_box();
+
+ /* :nodoc: */
+ rb_mBoxLoader = rb_define_module_under(rb_cBox, "Loader");
+ box_define_loader_method("require");
+ box_define_loader_method("require_relative");
+ box_define_loader_method("load");
+
+ if (rb_box_available()) {
+ rb_include_module(rb_cObject, rb_mBoxLoader);
+
+ rb_define_singleton_method(rb_cBox, "master", rb_box_s_master, 0);
+ rb_define_singleton_method(rb_cBox, "root", rb_box_s_root, 0);
+ rb_define_singleton_method(rb_cBox, "main", rb_box_s_main, 0);
+ rb_define_method(rb_cBox, "master?", rb_box_master_p, 0);
+ rb_define_method(rb_cBox, "root?", rb_box_root_p, 0);
+ rb_define_method(rb_cBox, "main?", rb_box_main_p, 0);
+
+#if RUBY_DEBUG
+ rb_define_global_function("dump_classext", rb_f_dump_classext, 1);
+#endif
+ }
+
+ rb_define_singleton_method(rb_cBox, "enabled?", rb_box_s_getenabled, 0);
+ rb_define_singleton_method(rb_cBox, "current", rb_box_s_current, 0);
+
+ rb_define_method(rb_cBox, "load_path", rb_box_load_path, 0);
+ rb_define_method(rb_cBox, "load", rb_box_load, -1);
+ rb_define_method(rb_cBox, "require", rb_box_require, 1);
+ rb_define_method(rb_cBox, "require_relative", rb_box_require_relative, 1);
+ rb_define_method(rb_cBox, "eval", rb_box_eval, 1);
+
+ rb_define_method(rb_cBox, "inspect", rb_box_inspect, 0);
+}
diff --git a/builtin.c b/builtin.c
index 3400c4976e..03c9d03bc3 100644
--- a/builtin.c
+++ b/builtin.c
@@ -1,4 +1,5 @@
#include "internal.h"
+#include "internal/box.h"
#include "vm_core.h"
#include "iseq.h"
#include "builtin.h"
@@ -22,18 +23,41 @@ bin4feature(const struct builtin_binary *bb, const char *feature, size_t *psize)
static const unsigned char*
builtin_lookup(const char *feature, size_t *psize)
{
- static int index = 0;
- const unsigned char *bin = bin4feature(&builtin_binary[index++], feature, psize);
+ static size_t index = 0;
+ const unsigned char *bin = NULL;
+
+ /*
+ * Fast path:
+ * builtin_binary is usually arranged in the same order
+ * as features are looked up in miniruby, so try the next entry first.
+ */
+ if (builtin_binary[index].feature) {
+ bin = bin4feature(&builtin_binary[index], feature, psize);
+ index++;
+ }
+ if (bin) {
+ return bin;
+ }
- // usually, `builtin_binary` order is loading order at miniruby.
- for (const struct builtin_binary *bb = &builtin_binary[0]; bb->feature &&! bin; bb++) {
- bin = bin4feature(bb++, feature, psize);
+ /*
+ * Fallback:
+ * In case the lookup order does not match the array order,
+ * scan the entire table to find the feature.
+ */
+ for (const struct builtin_binary *bb = &builtin_binary[0];
+ bb->feature;
+ bb++) {
+ bin = bin4feature(bb, feature, psize);
+ if (bin) {
+ break;
+ }
}
+
return bin;
}
static void
-load_with_builtin_functions(const char *feature_name, const struct rb_builtin_function *table)
+load_with_builtin_functions(const char *feature_name, const struct rb_builtin_function *table, const rb_box_t *target_box)
{
// search binary
size_t size;
@@ -50,23 +74,41 @@ load_with_builtin_functions(const char *feature_name, const struct rb_builtin_fu
ASSUME(iseq); // otherwise an exception should have raised
vm->builtin_function_table = NULL;
- rb_namespace_enable_builtin();
-
// exec
- if (rb_namespace_available() && rb_mNamespaceRefiner) {
- rb_iseq_eval_with_refinement(rb_iseq_check(iseq), rb_mNamespaceRefiner);
- }
- else {
- rb_iseq_eval(rb_iseq_check(iseq));
+ rb_iseq_eval(rb_iseq_check(iseq), target_box);
+}
+
+void
+rb_load_with_builtin_functions(const char *feature_name, const struct rb_builtin_function *table)
+{
+ load_with_builtin_functions(feature_name, table, rb_root_box());
+}
+
+VALUE
+rb_define_gem_modules(VALUE flags_value, VALUE _)
+{
+ rb_box_gem_flags_t *flags = (rb_box_gem_flags_t *)flags_value;
+
+ if (flags->gem) {
+ rb_define_module("Gem");
+ if (flags->error_highlight) {
+ rb_define_module("ErrorHighlight");
+ }
+ if (flags->did_you_mean) {
+ rb_define_module("DidYouMean");
+ }
+ if (flags->syntax_suggest) {
+ rb_define_module("SyntaxSuggest");
+ }
}
- rb_namespace_disable_builtin();
+ return Qnil;
}
void
-rb_load_with_builtin_functions(const char *feature_name, const struct rb_builtin_function *table)
+rb_load_gem_prelude(VALUE box)
{
- load_with_builtin_functions(feature_name, table);
+ load_with_builtin_functions("gem_prelude", NULL, (const rb_box_t *)box);
}
#endif
@@ -86,5 +128,13 @@ Init_builtin(void)
void
Init_builtin_features(void)
{
- load_with_builtin_functions("gem_prelude", NULL);
+
+#ifdef BUILTIN_BINARY_SIZE
+
+ rb_load_gem_prelude((VALUE)rb_root_box());
+
+ rb_load_gem_prelude((VALUE)rb_main_box());
+
+#endif
+
}
diff --git a/builtin.h b/builtin.h
index fd1c4c307f..ffd2aad88e 100644
--- a/builtin.h
+++ b/builtin.h
@@ -21,6 +21,8 @@ struct rb_builtin_function {
}
void rb_load_with_builtin_functions(const char *feature_name, const struct rb_builtin_function *table);
+VALUE rb_define_gem_modules(VALUE, VALUE);
+void rb_load_gem_prelude(VALUE box);
#ifndef rb_execution_context_t
typedef struct rb_execution_context_struct rb_execution_context_t;
diff --git a/class.c b/class.c
index 24f61fd023..02078cc9bc 100644
--- a/class.c
+++ b/class.c
@@ -21,16 +21,18 @@
#include "debug_counter.h"
#include "id_table.h"
#include "internal.h"
+#include "internal/box.h"
#include "internal/class.h"
#include "internal/eval.h"
#include "internal/hash.h"
-#include "internal/namespace.h"
#include "internal/object.h"
#include "internal/string.h"
#include "internal/variable.h"
#include "ruby/st.h"
#include "vm_core.h"
+#include "ruby/ractor.h"
#include "yjit.h"
+#include "zjit.h"
/* Flags of T_CLASS
*
@@ -39,22 +41,22 @@
* 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_PRIME_CLASSEXT_PRIME_WRITABLE
- * This class's prime classext is the only classext and writable from any namespaces.
- * If unset, the prime classext is writable only from the root namespace.
+ * 2: RCLASS_PRIME_CLASSEXT_WRITABLE
+ * This class's prime classext is the only classext and writable from any boxes.
+ * If unset, the prime classext is writable only from the root box.
* 3: RCLASS_IS_INITIALIZED
* Class has been initialized.
- * 4: RCLASS_NAMESPACEABLE
- * Is a builtin class that may be namespaced. It larger than a normal class.
+ * 4: RCLASS_BOXABLE
+ * Is a builtin class that may be boxed. It larger than a normal class.
*/
/* Flags of T_ICLASS
*
- * 2: RCLASS_PRIME_CLASSEXT_PRIME_WRITABLE
- * This module's prime classext is the only classext and writable from any namespaces.
- * If unset, the prime classext is writable only from the root namespace.
- * 4: RCLASS_NAMESPACEABLE
- * Is a builtin class that may be namespaced. It larger than a normal class.
+ * 2: RCLASS_PRIME_CLASSEXT_WRITABLE
+ * This module's prime classext is the only classext and writable from any boxes.
+ * If unset, the prime classext is writable only from the root box.
+ * 4: RCLASS_BOXABLE
+ * Is a builtin class that may be boxed. It larger than a normal class.
*/
/* Flags of T_MODULE
@@ -62,35 +64,140 @@
* 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_IS_REFINEMENT
- * Module is used for refinements.
- * 2: RCLASS_PRIME_CLASSEXT_PRIME_WRITABLE
- * This module's prime classext is the only classext and writable from any namespaces.
- * If unset, the prime classext is writable only from the root namespace.
+ * 1: <reserved>
+ * Ensures that RUBY_FL_SINGLETON is never set on a T_MODULE. See `rb_class_real`.
+ * 2: RCLASS_PRIME_CLASSEXT_WRITABLE
+ * This module's prime classext is the only classext and writable from any boxes.
+ * If unset, the prime classext is writable only from the root box.
* 3: RCLASS_IS_INITIALIZED
* Module has been initialized.
- * 4: RCLASS_NAMESPACEABLE
- * Is a builtin class that may be namespaced. It larger than a normal class.
+ * 4: RCLASS_BOXABLE
+ * Is a builtin class that may be boxed. It larger than a normal class.
+ * 5: RMODULE_IS_REFINEMENT
+ * Module is used for refinements.
*/
#define METACLASS_OF(k) RBASIC(k)->klass
#define SET_METACLASS_OF(k, cls) RBASIC_SET_CLASS(k, cls)
-RUBY_EXTERN rb_serial_t ruby_vm_global_cvar_state;
+rb_classext_t *
+rb_class_unlink_classext(VALUE klass, const rb_box_t *box)
+{
+ st_data_t ext;
+ st_data_t key = (st_data_t)box->box_object;
+ st_delete(box->classext_cow_classes, &klass, 0);
+ st_delete(RCLASS_CLASSEXT_TBL(klass), &key, &ext);
+ return (rb_classext_t *)ext;
+}
-struct duplicate_id_tbl_data {
+void
+rb_class_classext_free(VALUE klass, rb_classext_t *ext, bool is_prime)
+{
struct rb_id_table *tbl;
- VALUE klass;
+
+ rb_id_table_free(RCLASSEXT_M_TBL(ext));
+
+ if (!RCLASSEXT_SHARED_CONST_TBL(ext) && (tbl = RCLASSEXT_CONST_TBL(ext)) != NULL) {
+ rb_free_const_table(tbl);
+ }
+
+ if (RCLASSEXT_SUPERCLASSES_WITH_SELF(ext)) {
+ RUBY_ASSERT(is_prime); // superclasses should only be used on prime
+ size_t depth = RCLASSEXT_SUPERCLASS_DEPTH(ext);
+ if (depth != RCLASS_MAX_SUPERCLASS_DEPTH) {
+ depth++;
+ }
+ SIZED_FREE_N(RCLASSEXT_SUPERCLASSES(ext), depth);
+ }
+
+ if (!is_prime) { // the prime classext will be freed with RClass
+ SIZED_FREE(ext);
+ }
+}
+
+void
+rb_iclass_classext_free(VALUE klass, rb_classext_t *ext, bool is_prime)
+{
+ if (RCLASSEXT_ICLASS_IS_ORIGIN(ext) && !RCLASSEXT_ICLASS_ORIGIN_SHARED_MTBL(ext)) {
+ /* Method table is not shared for origin iclasses of classes */
+ rb_id_table_free(RCLASSEXT_M_TBL(ext));
+ }
+
+ if (RCLASSEXT_CALLABLE_M_TBL(ext) != NULL) {
+ rb_id_table_free(RCLASSEXT_CALLABLE_M_TBL(ext));
+ }
+
+ if (!is_prime) { // the prime classext will be freed with RClass
+ SIZED_FREE(ext);
+ }
+}
+
+static void
+iclass_free_orphan_classext(VALUE klass, rb_classext_t *ext)
+{
+ if (RCLASSEXT_ICLASS_IS_ORIGIN(ext) && !RCLASSEXT_ICLASS_ORIGIN_SHARED_MTBL(ext)) {
+ /* Method table is not shared for origin iclasses of classes */
+ rb_id_table_free(RCLASSEXT_M_TBL(ext));
+ }
+
+ if (RCLASSEXT_CALLABLE_M_TBL(ext) != NULL) {
+ rb_id_table_free(RCLASSEXT_CALLABLE_M_TBL(ext));
+ }
+
+ SIZED_FREE(ext);
+}
+
+struct rb_class_set_box_classext_args {
+ VALUE obj;
+ rb_classext_t *ext;
};
-static enum rb_id_table_iterator_result
-duplicate_classext_id_table_i(ID key, VALUE value, void *data)
+static int
+set_box_classext_update(st_data_t *key_ptr, st_data_t *val_ptr, st_data_t a, int existing)
{
- struct rb_id_table *tbl = (struct rb_id_table *)data;
- rb_id_table_insert(tbl, key, value);
- return ID_TABLE_CONTINUE;
+ struct rb_class_set_box_classext_args *args = (struct rb_class_set_box_classext_args *)a;
+
+ if (existing) {
+ if (LIKELY(BUILTIN_TYPE(args->obj) == T_ICLASS)) {
+ iclass_free_orphan_classext(args->obj, (rb_classext_t *)*val_ptr);
+ }
+ else {
+ rb_bug("Updating existing classext for non-iclass never happen");
+ }
+ }
+
+ *val_ptr = (st_data_t)args->ext;
+
+ return ST_CONTINUE;
}
+void
+rb_class_set_box_classext(VALUE obj, const rb_box_t *box, rb_classext_t *ext)
+{
+ struct rb_class_set_box_classext_args args = {
+ .obj = obj,
+ .ext = ext,
+ };
+
+ VM_ASSERT(BOX_MUTABLE_P(box));
+
+ st_update(RCLASS_CLASSEXT_TBL(obj), (st_data_t)box->box_object, set_box_classext_update, (st_data_t)&args);
+
+ // The classext references are now visible via the classext table,
+ // so we must issue the write barrier before any further allocations
+ // (e.g. st_insert below) that could trigger GC.
+ rb_gc_writebarrier_remember(obj);
+
+ st_insert(box->classext_cow_classes, (st_data_t)obj, 0);
+}
+
+RUBY_EXTERN rb_serial_t ruby_vm_global_cvar_state;
+
+struct duplicate_id_tbl_data {
+ struct rb_id_table *tbl;
+ VALUE klass;
+};
+
static enum rb_id_table_iterator_result
duplicate_classext_m_tbl_i(ID key, VALUE value, void *data)
{
@@ -119,22 +226,6 @@ duplicate_classext_m_tbl(struct rb_id_table *orig, VALUE klass, bool init_missin
return tbl;
}
-static struct rb_id_table *
-duplicate_classext_id_table(struct rb_id_table *orig, bool init_missing)
-{
- struct rb_id_table *tbl;
-
- if (!orig) {
- if (init_missing)
- return rb_id_table_create(0);
- else
- return NULL;
- }
- tbl = rb_id_table_create(rb_id_table_size(orig));
- rb_id_table_foreach(orig, duplicate_classext_id_table_i, tbl);
- return tbl;
-}
-
static rb_const_entry_t *
duplicate_classext_const_entry(rb_const_entry_t *src, VALUE klass)
{
@@ -179,73 +270,13 @@ duplicate_classext_const_tbl(struct rb_id_table *src, VALUE klass)
return dst;
}
-static VALUE
-namespace_subclasses_tbl_key(const rb_namespace_t *ns)
-{
- if (!ns){
- return 0;
- }
- return (VALUE)ns->ns_id;
-}
-
-static void
-duplicate_classext_subclasses(rb_classext_t *orig, rb_classext_t *copy)
-{
- rb_subclass_anchor_t *anchor, *orig_anchor;
- rb_subclass_entry_t *head, *cur, *cdr, *entry, *first = NULL;
- rb_ns_subclasses_t *ns_subclasses;
- struct st_table *tbl;
-
- if (RCLASSEXT_SUBCLASSES(orig)) {
- orig_anchor = RCLASSEXT_SUBCLASSES(orig);
- ns_subclasses = orig_anchor->ns_subclasses;
- tbl = ((rb_ns_subclasses_t *)ns_subclasses)->tbl;
-
- anchor = ZALLOC(rb_subclass_anchor_t);
- anchor->ns_subclasses = rb_ns_subclasses_ref_inc(ns_subclasses);
-
- head = ZALLOC(rb_subclass_entry_t);
- anchor->head = head;
-
- RCLASSEXT_SUBCLASSES(copy) = anchor;
-
- cur = head;
- entry = orig_anchor->head;
- RUBY_ASSERT(!entry->klass);
- // The head entry has NULL klass always. See rb_class_foreach_subclass().
- entry = entry->next;
- while (entry) {
- if (rb_objspace_garbage_object_p(entry->klass)) {
- entry = entry->next;
- continue;
- }
- cdr = ZALLOC(rb_subclass_entry_t);
- cdr->klass = entry->klass;
- cdr->prev = cur;
- cur->next = cdr;
- if (!first) {
- VALUE ns_id = namespace_subclasses_tbl_key(RCLASSEXT_NS(copy));
- first = cdr;
- st_insert(tbl, ns_id, (st_data_t)first);
- }
- cur = cdr;
- entry = entry->next;
- }
- }
-
- if (RCLASSEXT_NS_SUPER_SUBCLASSES(orig))
- RCLASSEXT_NS_SUPER_SUBCLASSES(copy) = rb_ns_subclasses_ref_inc(RCLASSEXT_NS_SUPER_SUBCLASSES(orig));
- if (RCLASSEXT_NS_MODULE_SUBCLASSES(orig))
- RCLASSEXT_NS_MODULE_SUBCLASSES(copy) = rb_ns_subclasses_ref_inc(RCLASSEXT_NS_MODULE_SUBCLASSES(orig));
-}
-
static void
-class_duplicate_iclass_classext(VALUE iclass, rb_classext_t *mod_ext, const rb_namespace_t *ns)
+class_duplicate_iclass_classext(VALUE iclass, rb_classext_t *mod_ext, const rb_box_t *box)
{
RUBY_ASSERT(RB_TYPE_P(iclass, T_ICLASS));
rb_classext_t *src = RCLASS_EXT_PRIME(iclass);
- rb_classext_t *ext = RCLASS_EXT_TABLE_LOOKUP_INTERNAL(iclass, ns);
+ rb_classext_t *ext = RCLASS_EXT_TABLE_LOOKUP_INTERNAL(iclass, box);
int first_set = 0;
if (ext) {
@@ -255,7 +286,7 @@ class_duplicate_iclass_classext(VALUE iclass, rb_classext_t *mod_ext, const rb_n
ext = ZALLOC(rb_classext_t);
- RCLASSEXT_NS(ext) = ns;
+ RCLASSEXT_BOX(ext) = box;
RCLASSEXT_SUPER(ext) = RCLASSEXT_SUPER(src);
@@ -274,8 +305,7 @@ class_duplicate_iclass_classext(VALUE iclass, rb_classext_t *mod_ext, const rb_n
// RCLASSEXT_CALLABLE_M_TBL(ext) = NULL;
// RCLASSEXT_CC_TBL(ext) = NULL;
- // subclasses, namespace_super_subclasses_tbl, namespace_module_subclasses_tbl
- duplicate_classext_subclasses(src, ext);
+ // Subclasses/back-pointers are only in the prime classext.
RCLASSEXT_SET_ORIGIN(ext, iclass, RCLASSEXT_ORIGIN(src));
RCLASSEXT_ICLASS_IS_ORIGIN(ext) = RCLASSEXT_ICLASS_IS_ORIGIN(src);
@@ -283,25 +313,29 @@ class_duplicate_iclass_classext(VALUE iclass, rb_classext_t *mod_ext, const rb_n
RCLASSEXT_SET_INCLUDER(ext, iclass, RCLASSEXT_INCLUDER(src));
- first_set = RCLASS_SET_NAMESPACE_CLASSEXT(iclass, ns, ext);
+ VM_ASSERT(FL_TEST_RAW(iclass, RCLASS_BOXABLE));
+
+ first_set = RCLASS_SET_BOX_CLASSEXT(iclass, box, ext);
if (first_set) {
RCLASS_SET_PRIME_CLASSEXT_WRITABLE(iclass, false);
}
}
rb_classext_t *
-rb_class_duplicate_classext(rb_classext_t *orig, VALUE klass, const rb_namespace_t *ns)
+rb_class_duplicate_classext(rb_classext_t *orig, VALUE klass, const rb_box_t *box)
{
VM_ASSERT(RB_TYPE_P(klass, T_CLASS) || RB_TYPE_P(klass, T_MODULE) || RB_TYPE_P(klass, T_ICLASS));
rb_classext_t *ext = ZALLOC(rb_classext_t);
bool dup_iclass = RB_TYPE_P(klass, T_MODULE) ? true : false;
- RCLASSEXT_NS(ext) = ns;
+ RCLASSEXT_BOX(ext) = box;
RCLASSEXT_SUPER(ext) = RCLASSEXT_SUPER(orig);
RCLASSEXT_M_TBL(ext) = duplicate_classext_m_tbl(RCLASSEXT_M_TBL(orig), klass, dup_iclass);
+ RCLASSEXT_ICLASS_IS_ORIGIN(ext) = true;
+ RCLASSEXT_ICLASS_ORIGIN_SHARED_MTBL(ext) = false;
if (orig->fields_obj) {
RB_OBJ_WRITE(klass, &ext->fields_obj, rb_imemo_fields_clone(orig->fields_obj));
@@ -320,19 +354,25 @@ rb_class_duplicate_classext(rb_classext_t *orig, VALUE klass, const rb_namespace
* so initially, it can be NULL and let it be created lazily.
* RCLASSEXT_CALLABLE_M_TBL(ext) = NULL;
*
- * cc_tbl is for method inline cache, and method calls from different namespaces never occur on
+ * cc_tbl is for method inline cache, and method calls from different boxes never occur on
* the same code, so the copied classext should have a different cc_tbl from the prime one.
* RCLASSEXT_CC_TBL(copy) = NULL
*/
- RCLASSEXT_CVC_TBL(ext) = duplicate_classext_id_table(RCLASSEXT_CVC_TBL(orig), dup_iclass);
+ VALUE cvc_table = RCLASSEXT_CVC_TBL(orig);
+ if (cvc_table) {
+ cvc_table = rb_marked_id_table_dup(cvc_table);
+ }
+ else if (dup_iclass) {
+ cvc_table = rb_marked_id_table_new(2);
+ }
+ RB_OBJ_WRITE(klass, &RCLASSEXT_CVC_TBL(ext), cvc_table);
- // subclasses, subclasses_index
- duplicate_classext_subclasses(orig, ext);
+ // Subclasses/back-pointers are only in the prime classext.
RCLASSEXT_SET_ORIGIN(ext, klass, RCLASSEXT_ORIGIN(orig));
/*
- * Members not copied to namespace classext values
+ * Members not copied to box's classext values
* * refined_class
* * as.class.allocator / as.singleton_class.attached_object
* * includer
@@ -340,30 +380,37 @@ rb_class_duplicate_classext(rb_classext_t *orig, VALUE klass, const rb_namespace
* * variation count
*/
RCLASSEXT_PERMANENT_CLASSPATH(ext) = RCLASSEXT_PERMANENT_CLASSPATH(orig);
- RCLASSEXT_CLONED(ext) = RCLASSEXT_CLONED(orig);
RCLASSEXT_CLASSPATH(ext) = RCLASSEXT_CLASSPATH(orig);
/* For the usual T_CLASS/T_MODULE, iclass flags are always false */
if (dup_iclass) {
- VALUE iclass;
/*
* ICLASS has the same m_tbl/const_tbl/cvc_tbl with the included module.
* So the module's classext is copied, its tables should be also referred
- * by the ICLASS's classext for the namespace.
+ * by the ICLASS's classext for the box.
+ *
+ * Subclasses are only in the prime classext, so read from orig.
*/
- rb_subclass_anchor_t *anchor = RCLASSEXT_SUBCLASSES(ext);
- rb_subclass_entry_t *subclass_entry = anchor->head;
- while (subclass_entry) {
- if (subclass_entry->klass && RB_TYPE_P(subclass_entry->klass, T_ICLASS)) {
- iclass = subclass_entry->klass;
- if (RBASIC_CLASS(iclass) == klass) {
- // Is the subclass an ICLASS including this module into another class
- // If so we need to re-associate it under our namespace with the new ext
- class_duplicate_iclass_classext(iclass, ext, ns);
+ VALUE subs_v = RCLASSEXT_SUBCLASSES(orig);
+ if (subs_v) {
+ struct rb_subclasses *subs = (struct rb_subclasses *)subs_v;
+ VALUE *entries = rb_imemo_subclasses_entries(subs_v);
+ for (uint32_t i = 0; i < subs->count; i++) {
+ VALUE iclass = entries[i];
+ if (!iclass) continue;
+
+ /* every node in the subclass list should be an ICLASS built from this module */
+ VM_ASSERT(RB_TYPE_P(iclass, T_ICLASS));
+ VM_ASSERT(RBASIC_CLASS(iclass) == klass);
+
+ if (FL_TEST_RAW(iclass, RCLASS_BOXABLE)) {
+ // Non-boxable ICLASSes (included by classes in main/user boxes) can't
+ // hold per-box classexts, and their includer classes also can't, so
+ // method lookup through them always uses the prime classext.
+ class_duplicate_iclass_classext(iclass, ext, box);
}
}
- subclass_entry = subclass_entry->next;
}
}
@@ -423,40 +470,45 @@ rb_class_variation_count(VALUE klass)
}
static void
-push_subclass_entry_to_list(VALUE super, VALUE klass, bool is_module)
+push_subclass_entry_to_list(VALUE super, VALUE klass)
{
- rb_subclass_entry_t *entry, *head;
- rb_subclass_anchor_t *anchor;
- rb_ns_subclasses_t *ns_subclasses;
- struct st_table *tbl;
- const rb_namespace_t *ns = rb_current_namespace();
-
- entry = ZALLOC(rb_subclass_entry_t);
- entry->klass = klass;
+ RUBY_ASSERT(
+ (RB_TYPE_P(super, T_MODULE) && RB_TYPE_P(klass, T_ICLASS)) ||
+ (RB_TYPE_P(super, T_CLASS) && RB_TYPE_P(klass, T_CLASS)) ||
+ (RB_TYPE_P(klass, T_ICLASS) && !NIL_P(RCLASS_REFINED_CLASS(klass)))
+ );
RB_VM_LOCKING() {
- anchor = RCLASS_WRITABLE_SUBCLASSES(super);
- VM_ASSERT(anchor);
- ns_subclasses = (rb_ns_subclasses_t *)anchor->ns_subclasses;
- VM_ASSERT(ns_subclasses);
- tbl = ns_subclasses->tbl;
- VM_ASSERT(tbl);
-
- head = anchor->head;
- if (head->next) {
- head->next->prev = entry;
- entry->next = head->next;
+ VALUE subs_v = RCLASS_SUBCLASSES(super);
+ struct rb_subclasses *subs = (struct rb_subclasses *)subs_v;
+
+ if (!subs || subs->count == subs->capacity) {
+ VALUE *old_entries = subs ? rb_imemo_subclasses_entries(subs_v) : NULL;
+ uint32_t live = 0;
+ for (uint32_t i = 0; subs && i < subs->count; i++) {
+ if (old_entries[i]) live++;
+ }
+
+ uint32_t cap = subs ? subs->capacity : 2;
+ if (live * 2 >= cap) cap *= 2;
+
+ VALUE new_v = rb_imemo_subclasses_new(cap);
+ struct rb_subclasses *new_subs = (struct rb_subclasses *)new_v;
+ VALUE *new_entries = rb_imemo_subclasses_entries(new_v);
+ for (uint32_t i = 0; subs && i < subs->count; i++) {
+ VALUE entry = old_entries[i];
+ if (entry) {
+ new_entries[new_subs->count++] = entry;
+ RB_OBJ_WRITTEN(new_v, Qundef, entry);
+ }
+ }
+ RCLASS_SET_SUBCLASSES(super, new_v);
+ subs_v = new_v;
+ subs = new_subs;
}
- head->next = entry;
- entry->prev = head;
- st_insert(tbl, namespace_subclasses_tbl_key(ns), (st_data_t)entry);
- }
- if (is_module) {
- RCLASS_WRITE_NS_MODULE_SUBCLASSES(klass, anchor->ns_subclasses);
- }
- else {
- RCLASS_WRITE_NS_SUPER_SUBCLASSES(klass, anchor->ns_subclasses);
+ rb_imemo_subclasses_entries(subs_v)[subs->count++] = klass;
+ RB_OBJ_WRITTEN(subs_v, Qundef, klass);
}
}
@@ -464,7 +516,9 @@ void
rb_class_subclass_add(VALUE super, VALUE klass)
{
if (super && !UNDEF_P(super)) {
- push_subclass_entry_to_list(super, klass, false);
+ RUBY_ASSERT(RB_TYPE_P(super, T_CLASS) || RB_TYPE_P(super, T_MODULE));
+ RUBY_ASSERT(RB_TYPE_P(klass, T_CLASS) || RB_TYPE_P(klass, T_ICLASS));
+ push_subclass_entry_to_list(super, klass);
}
}
@@ -472,164 +526,33 @@ static void
rb_module_add_to_subclasses_list(VALUE module, VALUE iclass)
{
if (module && !UNDEF_P(module)) {
- push_subclass_entry_to_list(module, iclass, true);
+ RUBY_ASSERT(RB_TYPE_P(module, T_MODULE));
+ RUBY_ASSERT(RB_TYPE_P(iclass, T_ICLASS));
+ push_subclass_entry_to_list(module, iclass);
}
}
void
-rb_class_remove_subclass_head(VALUE klass) // TODO: check this is still used and required
-{
- rb_classext_t *ext = RCLASS_EXT_WRITABLE(klass);
- rb_class_classext_free_subclasses(ext, klass);
-}
-
-static struct rb_subclass_entry *
-class_get_subclasses_for_ns(struct st_table *tbl, VALUE ns_id)
-{
- st_data_t value;
- if (st_lookup(tbl, (st_data_t)ns_id, &value)) {
- return (struct rb_subclass_entry *)value;
- }
- return NULL;
-}
-
-static void
-remove_class_from_subclasses(struct st_table *tbl, VALUE ns_id, VALUE klass)
+rb_class_foreach_subclass(VALUE klass, void (*f)(VALUE, VALUE), VALUE arg)
{
- rb_subclass_entry_t *entry = class_get_subclasses_for_ns(tbl, ns_id);
- bool first_entry = true;
- while (entry) {
- if (entry->klass == klass) {
- rb_subclass_entry_t *prev = entry->prev, *next = entry->next;
+ VALUE subs_v = RCLASS_SUBCLASSES(klass);
+ if (!subs_v) return;
- if (prev) {
- prev->next = next;
- }
- if (next) {
- next->prev = prev;
- }
-
- xfree(entry);
-
- if (first_entry) {
- if (next) {
- st_insert(tbl, ns_id, (st_data_t)next);
- }
- else {
- // no subclass entries in this ns
- st_delete(tbl, &ns_id, NULL);
- }
- }
- break;
+ struct rb_subclasses *subs = (struct rb_subclasses *)subs_v;
+ VALUE *entries = rb_imemo_subclasses_entries(subs_v);
+ for (uint32_t i = 0; i < subs->count; i++) {
+ VALUE curklass = entries[i];
+ if (curklass) {
+ f(curklass, arg);
}
- else if (first_entry) {
- first_entry = false;
- }
- entry = entry->next;
- }
-}
-
-void
-rb_class_remove_from_super_subclasses(VALUE klass)
-{
- rb_classext_t *ext = RCLASS_EXT_WRITABLE(klass);
- rb_ns_subclasses_t *ns_subclasses = RCLASSEXT_NS_SUPER_SUBCLASSES(ext);
-
- if (!ns_subclasses) return;
- remove_class_from_subclasses(ns_subclasses->tbl, namespace_subclasses_tbl_key(RCLASSEXT_NS(ext)), klass);
- rb_ns_subclasses_ref_dec(ns_subclasses);
- RCLASSEXT_NS_SUPER_SUBCLASSES(ext) = 0;
-}
-
-void
-rb_class_remove_from_module_subclasses(VALUE klass)
-{
- rb_classext_t *ext = RCLASS_EXT_WRITABLE(klass);
- rb_ns_subclasses_t *ns_subclasses = RCLASSEXT_NS_MODULE_SUBCLASSES(ext);
-
- if (!ns_subclasses) return;
- remove_class_from_subclasses(ns_subclasses->tbl, namespace_subclasses_tbl_key(RCLASSEXT_NS(ext)), klass);
- rb_ns_subclasses_ref_dec(ns_subclasses);
- RCLASSEXT_NS_MODULE_SUBCLASSES(ext) = 0;
-}
-
-void
-rb_class_classext_free_subclasses(rb_classext_t *ext, VALUE klass)
-{
- rb_subclass_anchor_t *anchor = RCLASSEXT_SUBCLASSES(ext);
- struct st_table *tbl = anchor->ns_subclasses->tbl;
- VALUE ns_id = namespace_subclasses_tbl_key(RCLASSEXT_NS(ext));
- rb_subclass_entry_t *next, *entry = anchor->head;
-
- while (entry) {
- next = entry->next;
- xfree(entry);
- entry = next;
- }
- VM_ASSERT(
- rb_ns_subclasses_ref_count(anchor->ns_subclasses) > 0,
- "ns_subclasses refcount (%p) %ld", anchor->ns_subclasses, rb_ns_subclasses_ref_count(anchor->ns_subclasses));
- st_delete(tbl, &ns_id, NULL);
- rb_ns_subclasses_ref_dec(anchor->ns_subclasses);
- xfree(anchor);
-
- if (RCLASSEXT_NS_SUPER_SUBCLASSES(ext)) {
- rb_ns_subclasses_t *ns_sub = RCLASSEXT_NS_SUPER_SUBCLASSES(ext);
- remove_class_from_subclasses(ns_sub->tbl, ns_id, klass);
- rb_ns_subclasses_ref_dec(ns_sub);
- }
- if (RCLASSEXT_NS_MODULE_SUBCLASSES(ext)) {
- rb_ns_subclasses_t *ns_sub = RCLASSEXT_NS_MODULE_SUBCLASSES(ext);
- remove_class_from_subclasses(ns_sub->tbl, ns_id, klass);
- rb_ns_subclasses_ref_dec(ns_sub);
- }
-}
-
-void
-rb_class_foreach_subclass(VALUE klass, void (*f)(VALUE, VALUE), VALUE arg)
-{
- rb_subclass_entry_t *tmp;
- rb_subclass_entry_t *cur = RCLASS_SUBCLASSES_FIRST(klass);
- /* do not be tempted to simplify this loop into a for loop, the order of
- operations is important here if `f` modifies the linked list */
- while (cur) {
- VALUE curklass = cur->klass;
- tmp = cur->next;
- // do not trigger GC during f, otherwise the cur will become
- // a dangling pointer if the subclass is collected
- f(curklass, arg);
- cur = tmp;
}
}
static void
-class_detach_subclasses(VALUE klass, VALUE arg)
-{
- rb_class_remove_from_super_subclasses(klass);
-}
-
-void
-rb_class_detach_subclasses(VALUE klass)
-{
- rb_class_foreach_subclass(klass, class_detach_subclasses, Qnil);
-}
-
-static void
-class_detach_module_subclasses(VALUE klass, VALUE arg)
-{
- rb_class_remove_from_module_subclasses(klass);
-}
-
-void
-rb_class_detach_module_subclasses(VALUE klass)
-{
- rb_class_foreach_subclass(klass, class_detach_module_subclasses, Qnil);
-}
-
-static void
class_switch_superclass(VALUE super, VALUE klass)
{
- class_detach_subclasses(klass, Qnil);
+ // No need to remove from old super's subclasses list — the GC
+ // will nullify the weak reference when appropriate.
rb_class_subclass_add(super, klass);
}
@@ -644,41 +567,35 @@ class_switch_superclass(VALUE super, VALUE klass)
* @note this function is not Class#allocate.
*/
static VALUE
-class_alloc0(enum ruby_value_type type, VALUE klass, bool namespaceable)
+class_alloc0(enum ruby_value_type type, VALUE klass, bool boxable)
{
- rb_ns_subclasses_t *ns_subclasses;
- rb_subclass_anchor_t *anchor;
- const rb_namespace_t *ns = rb_definition_namespace();
+ const rb_box_t *box = rb_current_box();
- if (!ruby_namespace_init_done) {
- namespaceable = true;
+ if (!ruby_box_init_done) {
+ boxable = true;
}
size_t alloc_size = sizeof(struct RClass_and_rb_classext_t);
- if (namespaceable) {
- alloc_size = sizeof(struct RClass_namespaceable);
- }
-
- // class_alloc is supposed to return a new object that is not promoted yet.
- // So, we need to avoid GC after NEWOBJ_OF.
- // To achieve that, we allocate subclass lists before NEWOBJ_OF.
- //
- // TODO: Note that this could cause memory leak.
- // If NEWOBJ_OF fails with out of memory, these buffers will leak.
- ns_subclasses = ZALLOC(rb_ns_subclasses_t);
- ns_subclasses->refcount = 1;
- ns_subclasses->tbl = st_init_numtable();
- anchor = ZALLOC(rb_subclass_anchor_t);
- anchor->ns_subclasses = ns_subclasses;
- anchor->head = ZALLOC(rb_subclass_entry_t);
+ if (boxable) {
+ alloc_size = sizeof(struct RClass_boxable);
+ }
RUBY_ASSERT(type == T_CLASS || type == T_ICLASS || type == T_MODULE);
- VALUE flags = type;
- if (RGENGC_WB_PROTECTED_CLASS) flags |= FL_WB_PROTECTED;
- if (namespaceable) flags |= RCLASS_NAMESPACEABLE;
+ VALUE flags = type | FL_SHAREABLE;
+ if (boxable) flags |= RCLASS_BOXABLE;
+
+ shape_id_t shape_id = ROOT_SHAPE_ID;
+ if (boxable) {
+ shape_id |= SHAPE_ID_LAYOUT_OTHER;
+ }
+ else {
+ shape_id |= SHAPE_ID_LAYOUT_RCLASS;
+ }
+
+ struct RClass *obj = (struct RClass *)rb_newobj(GET_EC(), klass, flags, shape_id, true, alloc_size);
- NEWOBJ_OF(obj, struct RClass, klass, flags, alloc_size, 0);
+ obj->object_id = 0;
memset(RCLASS_EXT_PRIME(obj), 0, sizeof(rb_classext_t));
@@ -689,30 +606,46 @@ class_alloc0(enum ruby_value_type type, VALUE klass, bool namespaceable)
RCLASS_SET_SUPER((VALUE)obj, 0);
*/
- RCLASS_PRIME_NS((VALUE)obj) = ns;
- // Classes/Modules defined in user namespaces are
- // writable directly because it exists only in a namespace.
- RCLASS_SET_PRIME_CLASSEXT_WRITABLE((VALUE)obj, !namespaceable || NAMESPACE_USER_P(ns));
+ if (boxable) {
+ ((struct RClass_boxable *)obj)->box_classext_tbl = NULL;
+ }
+
+ RCLASS_PRIME_BOX((VALUE)obj) = box;
+ // Classes/Modules defined in user boxes are
+ // writable directly because it exists only in a box.
+ RCLASS_SET_PRIME_CLASSEXT_WRITABLE((VALUE)obj, !boxable || BOX_USER_P(box));
RCLASS_SET_ORIGIN((VALUE)obj, (VALUE)obj);
RCLASS_SET_REFINED_CLASS((VALUE)obj, Qnil);
- RCLASS_SET_SUBCLASSES((VALUE)obj, anchor);
-
return (VALUE)obj;
}
static VALUE
class_alloc(enum ruby_value_type type, VALUE klass)
{
- return class_alloc0(type, klass, false);
+ bool boxable = rb_box_available() && BOX_MASTER_P(rb_current_box());
+ return class_alloc0(type, klass, boxable);
}
static VALUE
class_associate_super(VALUE klass, VALUE super, bool init)
{
if (super && !UNDEF_P(super)) {
- class_switch_superclass(super, klass);
+ // Only maintain subclass lists for T_CLASS→T_CLASS relationships.
+ // Include/prepend inserts ICLASSes into the super chain, but T_CLASS
+ // subclass lists should track only the immutable T_CLASS→T_CLASS link.
+ if (RB_TYPE_P(klass, T_CLASS) && RB_TYPE_P(super, T_CLASS)) {
+ if (RCLASS_SINGLETON_P(klass)) {
+ // Instead of adding singleton classes to the subclass list,
+ // just set a flag so that method cache invalidation takes the
+ // tree path.
+ FL_SET_RAW(super, RCLASS_HAS_SUBCLASSES);
+ }
+ else {
+ class_switch_superclass(super, klass);
+ }
+ }
}
if (init) {
RCLASS_SET_SUPER(klass, super);
@@ -744,9 +677,9 @@ class_clear_method_table(VALUE c)
}
static VALUE
-class_boot_namespaceable(VALUE super, bool namespaceable)
+class_boot_boxable(VALUE super, bool boxable)
{
- VALUE klass = class_alloc0(T_CLASS, rb_cClass, namespaceable);
+ VALUE klass = class_alloc0(T_CLASS, rb_cClass, boxable);
// initialize method table prior to class_associate_super()
// because class_associate_super() may cause GC and promote klass
@@ -754,6 +687,7 @@ class_boot_namespaceable(VALUE super, bool namespaceable)
class_associate_super(klass, super, true);
if (super && !UNDEF_P(super)) {
+ RCLASS_SET_ALLOCATOR(klass, RCLASS_ALLOCATOR(super));
rb_class_set_initialized(klass);
}
@@ -772,7 +706,7 @@ class_boot_namespaceable(VALUE super, bool namespaceable)
VALUE
rb_class_boot(VALUE super)
{
- return class_boot_namespaceable(super, false);
+ return class_boot_boxable(super, false);
}
static VALUE *
@@ -858,11 +792,8 @@ rb_class_new(VALUE super)
rb_check_inheritable(super);
VALUE klass = rb_class_boot(super);
- if (super != rb_cObject && super != rb_cBasicObject) {
- RCLASS_SET_MAX_IV_COUNT(klass, RCLASS_MAX_IV_COUNT(super));
- }
-
- RUBY_ASSERT(getenv("RUBY_NAMESPACE") || RCLASS_PRIME_CLASSEXT_WRITABLE_P(klass));
+ RCLASS_SET_MAX_IV_COUNT(klass, RCLASS_MAX_IV_COUNT(super));
+ RUBY_ASSERT(getenv("RUBY_BOX") || RCLASS_PRIME_CLASSEXT_WRITABLE_P(klass));
return klass;
}
@@ -874,27 +805,20 @@ rb_class_s_alloc(VALUE klass)
}
static void
-clone_method(VALUE old_klass, VALUE new_klass, ID mid, const rb_method_entry_t *me)
+clone_method(VALUE new_klass, ID mid, const rb_method_entry_t *me)
{
- if (me->def->type == VM_METHOD_TYPE_ISEQ) {
- rb_cref_t *new_cref = rb_vm_rewrite_cref(me->def->body.iseq.cref, old_klass, new_klass);
- rb_add_method_iseq(new_klass, mid, me->def->body.iseq.iseqptr, new_cref, METHOD_ENTRY_VISI(me));
- }
- else {
- rb_method_entry_set(new_klass, mid, me, METHOD_ENTRY_VISI(me));
- }
+ rb_method_entry_set(new_klass, mid, me, METHOD_ENTRY_VISI(me));
}
struct clone_method_arg {
VALUE new_klass;
- VALUE old_klass;
};
static enum rb_id_table_iterator_result
clone_method_i(ID key, VALUE value, void *data)
{
const struct clone_method_arg *arg = (struct clone_method_arg *)data;
- clone_method(arg->old_klass, arg->new_klass, key, (const rb_method_entry_t *)value);
+ clone_method(arg->new_klass, key, (const rb_method_entry_t *)value);
return ID_TABLE_CONTINUE;
}
@@ -937,9 +861,15 @@ class_init_copy_check(VALUE clone, VALUE orig)
struct cvc_table_copy_ctx {
VALUE clone;
- struct rb_id_table * new_table;
+ VALUE new_table;
};
+static struct rb_cvar_class_tbl_entry *
+cvc_table_entry_alloc(void)
+{
+ return (struct rb_cvar_class_tbl_entry *)SHAREABLE_IMEMO_NEW(struct rb_cvar_class_tbl_entry, imemo_cvar_entry, 0);
+}
+
static enum rb_id_table_iterator_result
cvc_table_copy(ID id, VALUE val, void *data)
{
@@ -949,13 +879,11 @@ cvc_table_copy(ID id, VALUE val, void *data)
struct rb_cvar_class_tbl_entry *ent;
- ent = ALLOC(struct rb_cvar_class_tbl_entry);
- ent->class_value = ctx->clone;
- ent->cref = orig_entry->cref;
+ ent = cvc_table_entry_alloc();
+ RB_OBJ_WRITE((VALUE)ent, &ent->class_value, ctx->clone);
+ RB_OBJ_WRITE(ctx->clone, &ent->cref, orig_entry->cref);
ent->global_cvar_state = orig_entry->global_cvar_state;
- rb_id_table_insert(ctx->new_table, id, (VALUE)ent);
-
- RB_OBJ_WRITTEN(ctx->clone, Qundef, ent->cref);
+ rb_marked_id_table_insert(ctx->new_table, id, (VALUE)ent);
return ID_TABLE_CONTINUE;
}
@@ -968,13 +896,13 @@ copy_tables(VALUE clone, VALUE orig)
RCLASS_WRITE_CONST_TBL(clone, 0, false);
}
if (RCLASS_CVC_TBL(orig)) {
- struct rb_id_table *rb_cvc_tbl = RCLASS_CVC_TBL(orig);
- struct rb_id_table *rb_cvc_tbl_dup = rb_id_table_create(rb_id_table_size(rb_cvc_tbl));
+ VALUE rb_cvc_tbl = RCLASS_CVC_TBL(orig);
+ VALUE rb_cvc_tbl_dup = rb_marked_id_table_new(rb_marked_id_table_size(rb_cvc_tbl));
struct cvc_table_copy_ctx ctx;
ctx.clone = clone;
ctx.new_table = rb_cvc_tbl_dup;
- rb_id_table_foreach(rb_cvc_tbl, cvc_table_copy, &ctx);
+ rb_marked_id_table_foreach(rb_cvc_tbl, cvc_table_copy, &ctx);
RCLASS_WRITE_CVC_TBL(clone, rb_cvc_tbl_dup);
}
rb_id_table_free(RCLASS_M_TBL(clone));
@@ -990,6 +918,7 @@ copy_tables(VALUE clone, VALUE orig)
arg.klass = clone;
rb_id_table_foreach(orig_tbl, clone_const_i, &arg);
RCLASS_WRITE_CONST_TBL(clone, const_tbl, false);
+ rb_gc_writebarrier_remember(clone);
}
}
@@ -1035,12 +964,6 @@ rb_mod_init_copy(VALUE clone, VALUE orig)
rb_class_set_initialized(clone);
- /* cloned flag is refer at constant inline cache
- * see vm_get_const_key_cref() in vm_insnhelper.c
- */
- RCLASS_SET_CLONED(clone, true);
- RCLASS_SET_CLONED(orig, true);
-
if (!RCLASS_SINGLETON_P(CLASS_OF(clone))) {
RBASIC_SET_CLASS(clone, rb_singleton_class_clone(orig));
rb_singleton_class_attached(METACLASS_OF(clone), (VALUE)clone);
@@ -1051,7 +974,6 @@ rb_mod_init_copy(VALUE clone, VALUE orig)
copy_tables(clone, orig);
if (RCLASS_M_TBL(orig)) {
struct clone_method_arg arg;
- arg.old_klass = orig;
arg.new_klass = clone;
class_initialize_method_table(clone);
rb_id_table_foreach(RCLASS_M_TBL(orig), clone_method_i, &arg);
@@ -1113,7 +1035,6 @@ rb_mod_init_copy(VALUE clone, VALUE orig)
copy_tables(clone_origin, orig_origin);
if (RCLASS_M_TBL(orig_origin)) {
struct clone_method_arg arg;
- arg.old_klass = orig;
arg.new_klass = clone;
class_initialize_method_table(clone_origin);
rb_id_table_foreach(RCLASS_M_TBL(orig_origin), clone_method_i, &arg);
@@ -1175,7 +1096,7 @@ rb_singleton_class_clone_and_attach(VALUE obj, VALUE attach)
if (RCLASS_CONST_TBL(klass)) {
struct clone_const_arg arg;
struct rb_id_table *table;
- arg.tbl = table = rb_id_table_create(0);
+ arg.tbl = table = rb_id_table_create(rb_id_table_size(RCLASS_CONST_TBL(klass)));
arg.klass = clone;
rb_id_table_foreach(RCLASS_CONST_TBL(klass), clone_const_i, &arg);
RCLASS_SET_CONST_TBL(clone, table, false);
@@ -1185,7 +1106,6 @@ rb_singleton_class_clone_and_attach(VALUE obj, VALUE attach)
}
{
struct clone_method_arg arg;
- arg.old_klass = klass;
arg.new_klass = clone;
rb_id_table_foreach(RCLASS_M_TBL(klass), clone_method_i, &arg);
}
@@ -1259,7 +1179,7 @@ static inline VALUE
make_metaclass(VALUE klass)
{
VALUE super;
- VALUE metaclass = class_boot_namespaceable(Qundef, FL_TEST_RAW(klass, RCLASS_NAMESPACEABLE));
+ VALUE metaclass = class_boot_boxable(Qundef, FL_TEST_RAW(klass, RCLASS_BOXABLE));
FL_SET(metaclass, FL_SINGLETON);
rb_singleton_class_attached(metaclass, klass);
@@ -1295,12 +1215,18 @@ static inline VALUE
make_singleton_class(VALUE obj)
{
VALUE orig_class = METACLASS_OF(obj);
- VALUE klass = class_boot_namespaceable(orig_class, FL_TEST_RAW(orig_class, RCLASS_NAMESPACEABLE));
-
+ VALUE klass = class_alloc0(T_CLASS, rb_cClass, FL_TEST_RAW(orig_class, RCLASS_BOXABLE));
FL_SET(klass, FL_SINGLETON);
+ class_initialize_method_table(klass);
+ class_associate_super(klass, orig_class, true);
+ if (orig_class && !UNDEF_P(orig_class)) {
+ rb_class_set_initialized(klass);
+ }
+
RBASIC_SET_CLASS(obj, klass);
rb_singleton_class_attached(klass, obj);
rb_yjit_invalidate_no_singleton_class(orig_class);
+ rb_zjit_invalidate_no_singleton_class(orig_class);
SET_METACLASS_OF(klass, METACLASS_OF(rb_class_real(orig_class)));
return klass;
@@ -1395,8 +1321,12 @@ void
Init_class_hierarchy(void)
{
rb_cBasicObject = boot_defclass("BasicObject", 0);
+ RCLASS_SET_ALLOCATOR(rb_cBasicObject, rb_class_allocate_instance);
+ FL_SET_RAW(rb_cBasicObject, RCLASS_ALLOCATOR_DEFINED);
+ RCLASS_SET_EXPECT_NO_IVAR(rb_cBasicObject);
+
rb_cObject = boot_defclass("Object", rb_cBasicObject);
- rb_vm_register_global_object(rb_cObject);
+ RCLASS_SET_EXPECT_NO_IVAR(rb_cObject);
/* resolve class name ASAP for order-independence */
rb_set_class_path_string(rb_cObject, rb_cObject, rb_fstring_lit("Object"));
@@ -1476,13 +1406,8 @@ VALUE
rb_define_class(const char *name, VALUE super)
{
VALUE klass;
- ID id;
- const rb_namespace_t *ns = rb_current_namespace();
+ ID id = rb_intern(name);
- id = rb_intern(name);
- if (NAMESPACE_OPTIONAL_P(ns)) {
- return rb_define_class_id_under(ns->ns_object, id, super);
- }
if (rb_const_defined(rb_cObject, id)) {
klass = rb_const_get(rb_cObject, id);
if (!RB_TYPE_P(klass, T_CLASS)) {
@@ -1594,13 +1519,8 @@ VALUE
rb_define_module(const char *name)
{
VALUE module;
- ID id;
- const rb_namespace_t *ns = rb_current_namespace();
+ ID id = rb_intern(name);
- id = rb_intern(name);
- if (NAMESPACE_OPTIONAL_P(ns)) {
- return rb_define_module_id_under(ns->ns_object, id);
- }
if (rb_const_defined(rb_cObject, id)) {
module = rb_const_get(rb_cObject, id);
if (!RB_TYPE_P(module, T_MODULE)) {
@@ -1701,29 +1621,34 @@ rb_include_module(VALUE klass, VALUE module)
rb_raise(rb_eArgError, "cyclic include detected");
if (RB_TYPE_P(klass, T_MODULE)) {
- rb_subclass_entry_t *iclass = RCLASS_SUBCLASSES_FIRST(klass);
- 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. */
- if (!rb_objspace_garbage_object_p(check_class)) {
- while (check_class) {
- RUBY_ASSERT(!rb_objspace_garbage_object_p(check_class));
-
- if (RB_TYPE_P(check_class, T_ICLASS) &&
- (METACLASS_OF(check_class) == module)) {
- do_include = 0;
+ VALUE subs_v = RCLASS_SUBCLASSES(klass);
+ if (subs_v) {
+ struct rb_subclasses *subs = (struct rb_subclasses *)subs_v;
+ VALUE *entries = rb_imemo_subclasses_entries(subs_v);
+ for (uint32_t i = 0; i < subs->count; i++) {
+ VALUE check_class = entries[i];
+ if (!check_class) continue;
+
+ int do_include = 1;
+ /* During lazy sweeping, the entry could be a dead object that
+ * has not yet been swept. */
+ if (!rb_objspace_garbage_object_p(check_class)) {
+ VALUE walk = check_class;
+ while (walk) {
+ RUBY_ASSERT(!rb_objspace_garbage_object_p(walk));
+
+ if (RB_TYPE_P(walk, T_ICLASS) &&
+ (METACLASS_OF(walk) == module)) {
+ do_include = 0;
+ }
+ walk = RCLASS_SUPER(walk);
}
- check_class = RCLASS_SUPER(check_class);
- }
- if (do_include) {
- include_modules_at(iclass->klass, RCLASS_ORIGIN(iclass->klass), module, TRUE);
+ if (do_include) {
+ include_modules_at(check_class, RCLASS_ORIGIN(check_class), module, TRUE);
+ }
}
}
-
- iclass = iclass->next;
}
}
}
@@ -1956,29 +1881,32 @@ rb_prepend_module(VALUE klass, VALUE module)
rb_vm_check_redefinition_by_prepend(klass);
}
if (RB_TYPE_P(klass, T_MODULE)) {
- rb_subclass_entry_t *iclass = RCLASS_SUBCLASSES_FIRST(klass);
+ VALUE subs_v = RCLASS_SUBCLASSES(klass);
VALUE klass_origin = RCLASS_ORIGIN(klass);
struct rb_id_table *klass_m_tbl = RCLASS_M_TBL(klass);
struct rb_id_table *klass_origin_m_tbl = RCLASS_M_TBL(klass_origin);
- while (iclass) {
- /* During lazy sweeping, iclass->klass could be a dead object that
- * has not yet been swept. */
- if (!rb_objspace_garbage_object_p(iclass->klass)) {
- const VALUE subclass = iclass->klass;
- if (klass_had_no_origin && klass_origin_m_tbl == RCLASS_M_TBL(subclass)) {
- // backfill an origin iclass to handle refinements and future prepends
- rb_id_table_foreach(RCLASS_M_TBL(subclass), clear_module_cache_i, (void *)subclass);
- RCLASS_WRITE_M_TBL(subclass, klass_m_tbl);
- VALUE origin = rb_include_class_new(klass_origin, RCLASS_SUPER(subclass));
- rb_class_set_super(subclass, origin);
- RCLASS_SET_INCLUDER(origin, RCLASS_INCLUDER(subclass));
- RCLASS_WRITE_ORIGIN(subclass, origin);
- RICLASS_SET_ORIGIN_SHARED_MTBL(origin);
+ if (subs_v) {
+ struct rb_subclasses *subs = (struct rb_subclasses *)subs_v;
+ VALUE *entries = rb_imemo_subclasses_entries(subs_v);
+ for (uint32_t i = 0; i < subs->count; i++) {
+ const VALUE subclass = entries[i];
+ if (!subclass) continue;
+ /* During lazy sweeping, the entry could be a dead object that
+ * has not yet been swept. */
+ if (!rb_objspace_garbage_object_p(subclass)) {
+ if (klass_had_no_origin && klass_origin_m_tbl == RCLASS_M_TBL(subclass)) {
+ // backfill an origin iclass to handle refinements and future prepends
+ rb_id_table_foreach(RCLASS_M_TBL(subclass), clear_module_cache_i, (void *)subclass);
+ RCLASS_WRITE_M_TBL(subclass, klass_m_tbl);
+ VALUE origin = rb_include_class_new(klass_origin, RCLASS_SUPER(subclass));
+ rb_class_set_super(subclass, origin);
+ RCLASS_SET_INCLUDER(origin, RCLASS_INCLUDER(subclass));
+ RCLASS_WRITE_ORIGIN(subclass, origin);
+ RICLASS_SET_ORIGIN_SHARED_MTBL(origin);
+ }
+ include_modules_at(subclass, subclass, module, FALSE);
}
- include_modules_at(subclass, subclass, module, FALSE);
}
-
- iclass = iclass->next;
}
}
}
@@ -2108,19 +2036,17 @@ 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 (RB_TYPE_P(klass, T_ICLASS)) return; // skip refinement ICLASSes
+
+ if (!RCLASS_SINGLETON_P(klass)) {
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);
}
data->count++;
- if (!data->immediate_only) {
- rb_class_foreach_subclass(klass, class_descendants_recursive, v);
- }
- }
- else {
- rb_class_foreach_subclass(klass, class_descendants_recursive, v);
+ if (data->immediate_only) return;
}
+ rb_class_foreach_subclass(klass, class_descendants_recursive, v);
}
static VALUE
@@ -2593,7 +2519,7 @@ 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) && RCLASS_SINGLETON_P(obj)) {
rb_singleton_class(obj);
}
klass = CLASS_OF(obj);
@@ -2719,7 +2645,7 @@ rb_special_singleton_class(VALUE obj)
* consistency of the metaclass hierarchy.
*/
static VALUE
-singleton_class_of(VALUE obj)
+singleton_class_of(VALUE obj, bool ensure_eigenclass)
{
VALUE klass;
@@ -2747,28 +2673,43 @@ singleton_class_of(VALUE obj)
}
}
- klass = METACLASS_OF(obj);
- if (!(RCLASS_SINGLETON_P(klass) &&
- RCLASS_ATTACHED_OBJECT(klass) == obj)) {
- klass = rb_make_metaclass(obj, klass);
+ bool needs_lock = rb_multi_ractor_p() && rb_ractor_shareable_p(obj);
+ unsigned int lev;
+ if (needs_lock) {
+ RB_VM_LOCK_ENTER_LEV(&lev);
+ }
+ {
+ klass = METACLASS_OF(obj);
+ if (!(RCLASS_SINGLETON_P(klass) &&
+ RCLASS_ATTACHED_OBJECT(klass) == obj)) {
+ klass = rb_make_metaclass(obj, klass);
+ }
+ RB_FL_SET_RAW(klass, RB_OBJ_FROZEN_RAW(obj));
+ if (ensure_eigenclass && RB_TYPE_P(obj, T_CLASS)) {
+ /* ensures an exposed class belongs to its own eigenclass */
+ (void)ENSURE_EIGENCLASS(klass);
+ }
+ }
+ if (needs_lock) {
+ RB_VM_LOCK_LEAVE_LEV(&lev);
}
-
- RB_FL_SET_RAW(klass, RB_OBJ_FROZEN_RAW(obj));
return klass;
}
void
-rb_freeze_singleton_class(VALUE x)
-{
- /* should not propagate to meta-meta-class, and so on */
- if (!RCLASS_SINGLETON_P(x)) {
- VALUE klass = RBASIC_CLASS(x);
- if (klass && // no class when hidden from ObjectSpace
- FL_TEST_RAW(klass, FL_SINGLETON) &&
- !OBJ_FROZEN_RAW(klass)) {
- OBJ_FREEZE(klass);
- }
+rb_freeze_singleton_class(VALUE attached_object)
+{
+ VALUE klass;
+
+ /* Freeze singleton classes of singleton class, as singleton class is frozen, and so on */
+ /* In each iteration, check the current object's class pointer is the singleton class of the object. */
+ while ((klass = RBASIC_CLASS(attached_object)) &&
+ FL_TEST_RAW(klass, FL_SINGLETON) &&
+ !OBJ_FROZEN_RAW(klass) &&
+ (RCLASS_ATTACHED_OBJECT(klass) == attached_object)) {
+ attached_object = klass;
+ OBJ_FREEZE(attached_object);
}
}
@@ -2796,12 +2737,7 @@ rb_singleton_class_get(VALUE obj)
VALUE
rb_singleton_class(VALUE obj)
{
- VALUE klass = singleton_class_of(obj);
-
- /* ensures an exposed class belongs to its own eigenclass */
- if (RB_TYPE_P(obj, T_CLASS)) (void)ENSURE_EIGENCLASS(klass);
-
- return klass;
+ return singleton_class_of(obj, true);
}
/*!
@@ -2819,7 +2755,7 @@ rb_singleton_class(VALUE obj)
void
rb_define_singleton_method(VALUE obj, const char *name, VALUE (*func)(ANYARGS), int argc)
{
- rb_define_method(singleton_class_of(obj), name, func, argc);
+ rb_define_method(singleton_class_of(obj, false), name, func, argc);
}
#ifdef rb_define_module_function
diff --git a/common.mk b/common.mk
index 2a2f3b7ff3..916484a6fe 100644
--- a/common.mk
+++ b/common.mk
@@ -21,7 +21,7 @@ gnumake_recursive =
sequential = $(gnumake:yes=-sequential)
enable_shared = $(ENABLE_SHARED:no=)
-UNICODE_VERSION = 16.0.0
+UNICODE_VERSION = 17.0.0
UNICODE_EMOJI_VERSION_0 = $(UNICODE_VERSION)///
UNICODE_EMOJI_VERSION_1 = $(UNICODE_EMOJI_VERSION_0:.0///=)
UNICODE_EMOJI_VERSION = $(UNICODE_EMOJI_VERSION_1:///=)
@@ -44,6 +44,10 @@ RUBYLIB = $(PATH_SEPARATOR)
RUBYOPT = -
RUN_OPTS = --disable-gems
+GIT_IN_SRC = $(GIT) -C $(srcdir)
+GIT_LOG = $(GIT_IN_SRC) log --no-show-signature
+GIT_LOG_FORMAT = $(GIT_LOG) "--pretty=format:"
+
# GITPULLOPTIONS = --no-tags
PRISM_SRCDIR = $(srcdir)/prism
@@ -65,13 +69,18 @@ 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"
+yes_cross_compiling = $(CROSS_COMPILING:no=)
+X_$(CROSS_COMPILING:yes=)BASERUBY = $(BASERUBY)
+X_$(CROSS_COMPILING:no=)BASERUBY = $(XRUBY)
+RDOC = $(X_BASERUBY) --enable-gems "$(tooldir)/rdoc-srcdir"
RDOCOUT = $(EXTOUT)/rdoc
HTMLOUT = $(EXTOUT)/html
CAPIOUT = doc/capi
INSTALL_DOC_OPTS = --rdoc-output="$(RDOCOUT)" --html-output="$(HTMLOUT)"
RDOC_GEN_OPTS = --no-force-update \
+ --exclude '^lib/rubygems/core_ext/kernel_require\.rb$$' \
$(empty)
+RDOC_SERVER_PORT = 4000
INITOBJS = dmyext.$(OBJEXT) dmyenc.$(OBJEXT)
NORMALMAINOBJ = main.$(OBJEXT)
@@ -85,36 +94,49 @@ MAKE_ENC = -f $(ENC_MK) V="$(V)" UNICODE_HDR_DIR="$(UNICODE_HDR_DIR)" \
PRISM_BUILD_DIR = prism
-PRISM_FILES = prism/api_node.$(OBJEXT) \
- prism/api_pack.$(OBJEXT) \
+LIBPRISM_OBJS = \
+ prism/arena.$(OBJEXT) \
+ prism/buffer.$(OBJEXT) \
+ prism/char.$(OBJEXT) \
+ prism/constant_pool.$(OBJEXT) \
prism/diagnostic.$(OBJEXT) \
prism/encoding.$(OBJEXT) \
- prism/extension.$(OBJEXT) \
+ prism/integer.$(OBJEXT) \
+ prism/json.$(OBJEXT) \
+ prism/line_offset_list.$(OBJEXT) \
+ prism/list.$(OBJEXT) \
+ prism/memchr.$(OBJEXT) \
prism/node.$(OBJEXT) \
prism/options.$(OBJEXT) \
- prism/pack.$(OBJEXT) \
+ prism/parser.$(OBJEXT) \
prism/prettyprint.$(OBJEXT) \
+ prism/prism.$(OBJEXT) \
prism/regexp.$(OBJEXT) \
prism/serialize.$(OBJEXT) \
+ prism/source.$(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/string_query.$(OBJEXT) \
+ prism/stringy.$(OBJEXT) \
+ prism/strncasecmp.$(OBJEXT) \
+ prism/strpbrk.$(OBJEXT) \
+ prism/tokens.$(OBJEXT)
+
+EXTPRISM_OBJS = prism/api_node.$(OBJEXT) \
+ prism/extension.$(OBJEXT) \
prism_init.$(OBJEXT)
+PRISM_OBJS = $(LIBPRISM_OBJS) $(EXTPRISM_OBJS)
+
+# Prism objects depend on generated headers that are created from templates.
+# This must be declared here to ensure parallel builds don't compile prism
+# sources before the generated headers exist.
+$(LIBPRISM_OBJS): $(srcdir)/prism/ast.h $(srcdir)/prism/internal/diagnostic.h
+
COMMONOBJS = \
array.$(OBJEXT) \
ast.$(OBJEXT) \
bignum.$(OBJEXT) \
+ box.$(OBJEXT) \
class.$(OBJEXT) \
compar.$(OBJEXT) \
compile.$(OBJEXT) \
@@ -142,7 +164,6 @@ COMMONOBJS = \
marshal.$(OBJEXT) \
math.$(OBJEXT) \
memory_view.$(OBJEXT) \
- namespace.$(OBJEXT) \
node.$(OBJEXT) \
node_dump.$(OBJEXT) \
numeric.$(OBJEXT) \
@@ -188,7 +209,7 @@ COMMONOBJS = \
vm_sync.$(OBJEXT) \
vm_trace.$(OBJEXT) \
weakmap.$(OBJEXT) \
- $(PRISM_FILES) \
+ $(PRISM_OBJS) \
$(YJIT_OBJ) \
$(ZJIT_OBJ) \
$(JIT_OBJ) \
@@ -199,7 +220,7 @@ COMMONOBJS = \
$(BUILTIN_TRANSOBJS) \
$(MISSING)
-$(PRISM_FILES): $(PRISM_BUILD_DIR)/.time $(PRISM_BUILD_DIR)/util/.time
+$(PRISM_OBJS): $(PRISM_BUILD_DIR)/.time $(PRISM_BUILD_DIR)/util/.time
$(PRISM_BUILD_DIR)/.time $(PRISM_BUILD_DIR)/util/.time:
$(Q) $(MAKEDIRS) $(@D)
@@ -264,22 +285,16 @@ MAKE_LINK = $(MINIRUBY) -rfileutils -e "include FileUtils::Verbose" \
# For release builds
YJIT_RUSTC_ARGS = --crate-name=yjit \
- --crate-type=staticlib \
+ $(JIT_RUST_FLAGS) \
+ $(RUSTC_FLAGS) \
--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'
ZJIT_RUSTC_ARGS = --crate-name=zjit \
- --crate-type=staticlib \
+ $(JIT_RUST_FLAGS) \
+ $(RUSTC_FLAGS) \
--edition=2024 \
- -g \
- -C lto=thin \
- -C opt-level=3 \
- -C overflow-checks=on \
'--out-dir=$(CARGO_TARGET_DIR)/release/' \
'$(top_srcdir)/zjit/src/lib.rs'
@@ -332,12 +347,14 @@ $(EXTS_MK): ext/configure-ext.mk $(srcdir)/template/exts.mk.tmpl \
$(srcdir)/template/exts.mk.tmpl --gnumake=$(gnumake) --configure-exts=ext/configure-ext.mk
ext/configure-ext.mk: $(PREP) all-incs $(MKFILES) $(RBCONFIG) $(LIBRUBY) \
- $(srcdir)/template/configure-ext.mk.tmpl
+ $(srcdir)/template/configure-ext.mk.tmpl update-default-gemspecs \
+ $(HAVE_BASERUBY:yes=extract-gems)
$(ECHO) generating makefiles $@
$(Q)$(MAKEDIRS) $(@D)
$(Q)$(MINIRUBY) $(tooldir)/generic_erb.rb -o $@ -c \
$(srcdir)/template/$(@F).tmpl --srcdir="$(srcdir)" \
- --miniruby="$(MINIRUBY)" --script-args='$(SCRIPT_ARGS)'
+ --miniruby="$(MINIRUBY)" --script-args='$(SCRIPT_ARGS)' \
+ $(yes_cross_compiling:yes=--without-ext=-test-)
configure-ext: $(EXTS_MK)
@@ -610,23 +627,33 @@ post-install-dbg::
srcs-doc: prepare-gems
-rdoc: PHONY main srcs-doc
+RDOC_DEPENDS = main srcs-doc
+rdoc: PHONY $(RDOC_DEPENDS) $(RBCONFIG) update-default-gemspecs
@echo Generating RDoc documentation
$(Q) $(RDOC) --ri --op "$(RDOCOUT)" $(RDOC_GEN_OPTS) $(RDOCFLAGS) .
-html: PHONY main srcs-doc
+html: PHONY $(RDOC_DEPENDS) $(RBCONFIG) update-default-gemspecs
@echo Generating RDoc HTML files
$(Q) $(RDOC) --op "$(HTMLOUT)" $(RDOC_GEN_OPTS) $(RDOCFLAGS) .
-rdoc-coverage: PHONY main srcs-doc
+html-server: PHONY $(RDOC_DEPENDS) $(RBCONFIG)
+ @echo Starting RDoc server with live reload
+ $(Q) $(RDOC) --server=$(RDOC_SERVER_PORT) $(RDOC_GEN_OPTS) $(RDOCFLAGS) .
+
+RDOC_COVERAGE_EXCLUDES = -x ^ext/json -x ^ext/openssl -x ^ext/psych \
+ -x ^lib/bundler -x ^lib/rubygems \
+ -x ^lib/did_you_mean -x ^lib/error_highlight -x ^lib/syntax_suggest
+
+rdoc-coverage: PHONY $(RDOC_DEPENDS) $(RBCONFIG)
@echo Generating RDoc coverage report
- $(Q) $(RDOC) --quiet -C $(RDOCFLAGS) .
+ $(Q) $(RDOC) --quiet -C $(RDOCFLAGS) $(RDOC_COVERAGE_EXCLUDES) .
-undocumented: PHONY main srcs-doc
- $(Q) $(RDOC) --quiet -C $(RDOCFLAGS) . | \
+undocumented: PHONY $(RDOC_DEPENDS) $(RBCONFIG)
+ $(Q) $(RDOC) --quiet -C $(RDOCFLAGS) $(RDOC_COVERAGE_EXCLUDES) . | \
sed -n \
-e '/^ *# in file /{' -e 's///;N;s/\n/: /p' -e '}' \
- -e 's/^ *\(.*[^ ]\) *# in file \(.*\)/\2: \1/p' | sort
+ -e 's/^ *\(.*[^ ]\) *# in file \(.*\)/\2: \1/p' | \
+ sort -t: -k1,1 -k2n,2
RDOCBENCHOUT=/tmp/rdocbench
@@ -655,6 +682,8 @@ install-prereq: $(CLEAR_INSTALLED_LIST) yes-fake sudo-precheck PHONY
clear-installed-list: PHONY
@> $(INSTALLED_LIST) set MAKE="$(MAKE)"
+noarch_config_h = tmp/include/noarch/ruby/config.h
+
clean: clean-ext clean-enc clean-golf clean-docs clean-extout clean-modular-gc clean-local clean-platform clean-spec
clean-local:: clean-runnable
$(Q)$(RM) $(ALLOBJS) $(LIBRUBY_A) $(LIBRUBY_SO) $(LIBRUBY) $(LIBRUBY_ALIASES)
@@ -663,6 +692,8 @@ clean-local:: clean-runnable
$(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.rbbin
$(Q)$(RM) $(PRISM_BUILD_DIR)/.time $(PRISM_BUILD_DIR)/*/.time yjit_exit_locations.dump
+ $(Q)$(RM) $(noarch_config_h)
+ -$(Q)$(RMALL) dump_ast$(BUILD_EXEEXT)*
-$(Q)$(RMALL) target
-$(Q) $(RMDIR) enc/jis enc/trans enc $(COROUTINE_H:/Context.h=) coroutine target \
$(PRISM_BUILD_DIR)/*/ $(PRISM_BUILD_DIR) tmp \
@@ -695,7 +726,8 @@ distclean-local:: clean-local
$(Q)$(RM) config.cache config.status config.status.lineno
$(Q)$(RM) *~ *.bak *.stackdump core *.core gmon.out $(PREP)
-$(Q)$(RMALL) $(srcdir)/autom4te.cache
-distclean-ext:: PHONY
+distclean-local:: distclean-srcs-local
+distclean-ext:: distclean-srcs-ext
distclean-golf: clean-golf
distclean-rdoc: clean-rdoc
distclean-html: clean-html
@@ -710,6 +742,7 @@ realclean:: realclean-ext realclean-local realclean-enc realclean-golf realclean
realclean-local:: distclean-local realclean-srcs-local
clean-srcs:: clean-srcs-local clean-srcs-ext
+distclean-srcs:: distclean-srcs-local distclean-srcs-ext
realclean-srcs:: realclean-srcs-local realclean-srcs-ext
clean-srcs-local::
@@ -717,7 +750,9 @@ clean-srcs-local::
$(Q)$(RM) id.c id.h probes.dmyh probes.h
$(Q)$(RM) encdb.h transdb.h verconf.h ruby-runner.h
-realclean-srcs-local:: clean-srcs-local
+distclean-srcs-local:: clean-srcs-local
+
+realclean-srcs-local:: distclean-srcs-local
$(Q)$(CHDIR) $(srcdir) && $(RM) \
parse.c parse.h lex.c enc/trans/newline.c $(PRELUDES) revision.h \
id.c id.h probes.dmyh configure aclocal.m4 tool/config.guess tool/config.sub \
@@ -725,7 +760,8 @@ realclean-srcs-local:: clean-srcs-local
|| $(NULLCMD)
clean-srcs-ext::
-realclean-srcs-ext:: clean-srcs-ext
+distclean-srcs-ext:: clean-srcs-ext
+realclean-srcs-ext:: distclean-srcs-ext
realclean-ext:: PHONY
realclean-golf: distclean-golf
@@ -753,7 +789,7 @@ timestamp/distclean:: ext/distclean .bundle/distclean
timestamp/realclean:: ext/realclean .bundle/realclean
timestamp/clean timestamp/distclean timestamp/realclean::
- $(Q)$(RM) $(TIMESTAMPDIR)/.*.time $(TIMESTAMPDIR)/$(arch)/.time
+ $(Q)$(RM) $(TIMESTAMPDIR)/*.time $(TIMESTAMPDIR)/.*.time $(TIMESTAMPDIR)/$(arch)/.time
$(Q)$(RMDIRS) $(TIMESTAMPDIR)/$(arch) $(TIMESTAMPDIR) 2> $(NULL) || $(NULLCMD)
clean-ext::
@@ -785,13 +821,17 @@ clean-capi distclean-capi realclean-capi:
clean-platform distclean-platform realclean-platform:
$(Q) $(RM) $(PLATFORM_D)
- -$(Q) $(RMDIR) $(PLATFORM_DIR) 2> $(NULL) || $(NULLCMD)
+ -$(Q) $(RMDIR) $(PLATFORM_DIR) $(TIMESTAMPDIR) 2> $(NULL) || $(NULLCMD)
RUBYSPEC_CAPIEXT = spec/ruby/optional/capi/ext
RUBYSPEC_CAPIEXT_SRCDIR = $(srcdir)/$(RUBYSPEC_CAPIEXT)
-RUBYSPEC_CAPIEXT_DEPS = $(RUBYSPEC_CAPIEXT_SRCDIR)/rubyspec.h $(RUBY_H_INCLUDES) $(LIBRUBY)
+RUBYSPEC_CAPIEXT_DEPS = $(RUBYSPEC_CAPIEXT_SRCDIR)/rubyspec.h $(RUBY_H_INCLUDES) {$(VPATH)}internal/abi.h $(LIBRUBY)
+RUBYSPEC_CAPIEXT_BUILD = $(enable_shared:yes=rubyspec-capiext)
-rubyspec-capiext: build-ext $(DOT_WAIT)
+yes-rubyspec-capiext: build-ext
+ $(ACTIONS_GROUP)
+rubyspec-capiext: build-ext $(DOT_WAIT) yes-rubyspec-capiext $(DOT_WAIT)
+ $(ACTIONS_ENDGROUP)
# make-dependent rules should be included after this and built after build-ext.
clean-spec: PHONY
@@ -826,6 +866,12 @@ $(arch:noarch=ignore)-fake.rb: $(srcdir)/template/fake.rb.in $(tooldir)/generic_
i=- srcdir="$(srcdir)" BASERUBY="$(BASERUBY)" \
LIBPATHENV="$(LIBPATHENV)" PRELOADENV="$(PRELOADENV)" LIBRUBY_SO="$(LIBRUBY_SO)"
+# dummy file for generating sources; $(arch_hdrdir)/ruby/config.h with prereq.status.
+$(noarch_config_h):
+ $(ECHO) generating dummy config.h
+ $(Q) $(MAKEDIRS) $(@D)
+ $(Q) $(TOUCH) $@
+
noarch-fake.rb: # prerequisite of yes-fake
$(Q) exit > $@
@@ -881,7 +927,7 @@ no-test-testframework: PHONY
test-tool: $(TEST_RUNNABLE)-test-tool
yes-test-tool: prog PHONY
$(ACTIONS_GROUP)
- $(gnumake_recursive)$(Q)$(exec) $(RUNRUBY) "$(TOOL_TESTSDIR)/runner.rb" --ruby="$(RUNRUBY)" $(TESTOPTS)
+ $(gnumake_recursive)$(Q)$(exec) $(RUNRUBY) "$(TOOL_TESTSDIR)/runner.rb" --ruby="$(RUNRUBY)" $(TESTOPTS) $(TESTS)
$(ACTIONS_ENDGROUP)
no-test-tool: PHONY
@@ -892,7 +938,7 @@ 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
+yes-test-all-precheck: programs $(DOT_WAIT) test-precheck yes-fake
PRECHECK_TEST_ALL = yes-test-all-precheck
@@ -929,24 +975,20 @@ rbconfig.rb: $(RBCONFIG)
$(HAVE_BASERUBY:no=)$(RBCONFIG)$(HAVE_BASERUBY:no=): $(PREP)
$(RBCONFIG): $(tooldir)/mkconfig.rb config.status $(srcdir)/version.h $(srcdir)/common.mk
- $(Q)$(BOOTSTRAPRUBY) -n \
- -e 'BEGIN{version=ARGV.shift;mis=ARGV.dup}' \
- -e 'END{abort "UNICODE version mismatch: #{mis}" unless mis.empty?}' \
- -e '(mis.delete(ARGF.path); ARGF.close) if /ONIG_UNICODE_VERSION_STRING +"#{Regexp.quote(version)}"/o' \
- $(UNICODE_VERSION) $(UNICODE_DATA_HEADERS)
+
+$(RBCONFIG):
$(Q)$(BOOTSTRAPRUBY) $(tooldir)/mkconfig.rb \
-arch=$(arch) -version=$(RUBY_PROGRAM_VERSION) \
-install_name=$(RUBY_INSTALL_NAME) \
-so_name=$(RUBY_SO_NAME) \
-unicode_version=$(UNICODE_VERSION) \
-unicode_emoji_version=$(UNICODE_EMOJI_VERSION) \
- > rbconfig.tmp
- $(IFCHANGE) "--timestamp=$@" rbconfig.rb rbconfig.tmp
+ | $(IFCHANGE) "--timestamp=$@" rbconfig.rb -
test-rubyspec: test-spec
yes-test-rubyspec: yes-test-spec
-yes-test-spec-precheck: yes-test-all-precheck yes-fake
+yes-test-spec-precheck: yes-test-all-precheck $(RUBYSPEC_CAPIEXT_BUILD)
test-spec: $(TEST_RUNNABLE)-test-spec
yes-test-spec: yes-test-spec-precheck
@@ -996,8 +1038,11 @@ $(ENC_MK): $(srcdir)/enc/make_encmake.rb $(srcdir)/enc/Makefile.in $(srcdir)/enc
.PHONY: test install install-nodoc install-doc dist
.PHONY: loadpath golf capi rdoc install-prereq clear-installed-list
.PHONY: clean clean-ext clean-local clean-enc clean-golf clean-rdoc clean-html clean-extout
+.PHONY: clean-srcs clean-srcs-local clean-srcs-ext
.PHONY: distclean distclean-ext distclean-local distclean-enc distclean-golf distclean-extout
+.PHONY: distclean-srcs distclean-srcs-local distclean-srcs-ext
.PHONY: realclean realclean-ext realclean-local realclean-enc realclean-golf realclean-extout
+.PHONY: realclean-srcs realclean-srcs-local realclean-srcs-ext
.PHONY: exam check test test-short test-all btest btest-ruby test-basic test-knownbug
.PHONY: run runruby parse benchmark gdb gdb-ruby
.PHONY: update-mspec update-rubyspec test-rubyspec test-spec
@@ -1113,7 +1158,7 @@ $(NEWLINE_C): $(srcdir)/enc/trans/newline.trans $(tooldir)/transcode-tblgen.rb
$(Q) $(BASERUBY) "$(tooldir)/transcode-tblgen.rb" -vo $@ $(srcdir)/enc/trans/newline.trans
enc/trans/newline.$(OBJEXT): $(NEWLINE_C)
-verconf.h: $(srcdir)/template/verconf.h.tmpl $(tooldir)/generic_erb.rb $(RBCONFIG)
+verconf.h: $(srcdir)/template/verconf.h.tmpl $(tooldir)/generic_erb.rb rbconfig.rb
$(ECHO) creating $@
$(Q) $(BOOTSTRAPRUBY) "$(tooldir)/generic_erb.rb" -o $@ $(srcdir)/template/verconf.h.tmpl
@@ -1133,7 +1178,7 @@ $(srcs_vpath)insns_info.inc: $(tooldir)/ruby_vm/views/insns_info.inc.erb $(inc_c
$(tooldir)/ruby_vm/views/_insn_type_chars.erb $(tooldir)/ruby_vm/views/_insn_name_info.erb \
$(tooldir)/ruby_vm/views/_insn_len_info.erb $(tooldir)/ruby_vm/views/_insn_operand_info.erb \
$(tooldir)/ruby_vm/views/_attributes.erb $(tooldir)/ruby_vm/views/_comptime_insn_stack_increase.erb \
- $(tooldir)/ruby_vm/views/_zjit_helpers.erb
+ $(tooldir)/ruby_vm/views/_zjit_helpers.erb $(tooldir)/ruby_vm/views/_insn_leaf_info.erb
$(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 \
@@ -1278,9 +1323,9 @@ preludes: {$(VPATH)}miniprelude.c
$(ECHO) making $@
$(Q) $(MINIRUBY) $(tooldir)/mk_rbbin.rb $(SRC_FILE) > $(OS_DEST_FILE)
-{$(srcdir)}.rb.rbinc:
+{$(srcdir)}.rb.$(HAVE_BASERUBY:yes=)rbinc:
$(ECHO) making $@
- $(Q) $(BASERUBY) $(tooldir)/mk_builtin_loader.rb $(SRC_FILE)
+ $(Q) $(BASERUBY) $(tooldir)/mk_builtin_loader.rb $(DUMP_AST) $(SRC_FILE)
$(BUILTIN_BINARY:yes=built)in_binary.rbbin: $(PREP) $(BUILTIN_RB_SRCS) $(srcdir)/template/builtin_binary.rbbin.tmpl
$(Q) $(MINIRUBY) $(tooldir)/generic_erb.rb -o $@ \
@@ -1290,7 +1335,22 @@ $(BUILTIN_BINARY:yes=built)in_binary.rbbin: $(PREP) $(BUILTIN_RB_SRCS) $(srcdir)
$(BUILTIN_BINARY:no=builtin)_binary.rbbin:
$(Q) echo> $@ // empty $(@F)
-$(BUILTIN_RB_INCS): $(top_srcdir)/tool/mk_builtin_loader.rb
+$(BUILTIN_RB_INCS): $(tooldir)/mk_builtin_loader.rb $(DUMP_AST_TARGET)
+
+dump_ast$(BUILD_EXEEXT): $(tooldir)/dump_ast.c $(LIBPRISM_OBJS)
+ $(ECHO) compiling $@
+ $(Q) $(CC) $(CFLAGS) $(OUTFLAG)$@ $(INCFLAGS) $(tooldir)/dump_ast.c $(LIBPRISM_OBJS)
+
+build-tool/Makefile: $(tooldir)/dump_ast.mkmf.rb prism-srcs prism-incs
+ +$(BASERUBY) -s $(tooldir)/dump_ast.mkmf.rb "-INCFLAGS=$(INCFLAGS)" "-make=$(MAKE)" build-tool $(tooldir)/dump_ast.c dump_ast.$(OBJEXT) $(LIBPRISM_OBJS)
+
+build-tool/dump_ast$(BUILD_EXEEXT): build-tool/Makefile
+ cd build-tool && MAKEFLAGS= MFLAGS= && unset MAKEFLAGS MFLAGS && $(MAKE)
+
+clean-local:: clean-build-tool
+clean-build-tool:
+ - cd build-tool && $(MAKE) clean 2> $(NULL) || $(NULLCMD)
+ - $(RMDIR) build-tool
$(srcdir)/revision.h$(no_baseruby:no=~disabled~): $(REVISION_H)
@@ -1310,6 +1370,7 @@ $(common_mk__artifact_): $(srcdir)/common.mk $(common_mk_includes)
ripper_srcs: $(RIPPER_SRCS)
$(RIPPER_SRCS): $(srcdir)/parse.y $(srcdir)/defs/id.def
+$(RIPPER_SRCS): $(srcdir)/ext/ripper/depend $(srcdir)/ext/ripper/extconf.rb
$(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
$(ECHO) generating $@
@@ -1429,7 +1490,7 @@ dist:
up:: update-remote
up$(DOT_WAIT)::
- -$(Q)$(MAKE) $(mflags) Q=$(Q) REVISION_FORCE=PHONY ALWAYS_UPDATE_UNICODE= after-update
+ -$(Q)$(MAKE) $(mflags) Q=$(Q) REVISION_FORCE=PHONY ALWAYS_UPDATE_UNICODE= MINIRUBY=$(BASERUBY) after-update
yes::
no::
@@ -1438,6 +1499,7 @@ after-update:: common-srcs
after-update:: $(REVISION_H)
after-update:: extract-extlibs
after-update:: extract-gems
+after-update:: update-default-gemspecs
update-src::
$(Q) $(RM) $(REVISION_H) revision.h "$(srcdir)/$(REVISION_H)" "$(srcdir)/revision.h"
@@ -1512,35 +1574,21 @@ update-bundled_gems: PHONY
$(tooldir)/update-bundled_gems.rb \
"$(srcdir)/gems/bundled_gems" | \
$(IFCHANGE) "$(srcdir)/gems/bundled_gems" -
- $(GIT) -C "$(srcdir)" diff --no-ext-diff --ignore-submodules --exit-code || \
- $(GIT) -C "$(srcdir)" commit -m "Update bundled_gems" gems/bundled_gems
+ $(GIT_IN_SRC) diff --no-ext-diff --ignore-submodules --exit-code || \
+ $(GIT_IN_SRC) commit -m "Update bundled_gems" gems/bundled_gems
PRECHECK_BUNDLED_GEMS = yes
test-bundled-gems-precheck: $(TEST_RUNNABLE)-test-bundled-gems-precheck
yes-test-bundled-gems-precheck: $(PRECHECK_BUNDLED_GEMS:yes=main)
no-test-bundled-gems-precheck:
-update-default-gemspecs: $(TEST_RUNNABLE)-update-default-gemspecs
-no-update-default-gemspecs:
-yes-update-default-gemspecs: $(PRECHECK_BUNDLED_GEMS:yes=main)
+yes-update-default-gemspecs no-update-default-gemspecs: update-default-gemspecs
+update-default-gemspecs: $(PREP) $(RBCONFIG)
@$(MAKEDIRS) $(srcdir)/.bundle/specifications
- @$(XRUBY) -W0 -C "$(srcdir)" -rrubygems \
- -e "destdir = ARGV.shift" \
- -e "ARGV.each do |basedir|" \
- -e "Dir.glob(basedir+'/**/*.gemspec') do |g|" \
- -e "dir, base = File.split(g)" \
- -e "spec = Dir.chdir(dir) {Gem::Specification.load(base)} ||" \
- -e "Gem::Specification.load(g)" \
- -e "unless spec" \
- -e "puts %[Ignoring #{g}]" \
- -e "next" \
- -e "end" \
- -e "spec.files.clear" \
- -e "spec.extensions.clear" \
- -e "File.binwrite(File.join(destdir, spec.full_name+'.gemspec'), spec.to_ruby)" \
- -e "end" \
- -e "end" \
- -- .bundle/specifications lib ext
+ $(Q)$(MINIRUBY) -W0 -C "$(srcdir)" -I tool/lib -roptparse -routput -rbundled_gem \
+ -e "(out = Output.new).def_options(ARGV.options)" \
+ -e "BundledGem.update_default_gemspecs(ARGV.parse!, out, quiet: $(V).zero?)" \
+ -- -c -o .bundle/specifications lib ext
install-for-test-bundled-gems: $(TEST_RUNNABLE)-install-for-test-bundled-gems
no-install-for-test-bundled-gems: no-update-default-gemspecs
@@ -1548,12 +1596,15 @@ yes-install-for-test-bundled-gems: yes-update-default-gemspecs
$(XRUBY) -C "$(srcdir)" -r./tool/lib/gem_env.rb bin/gem \
install --no-document --conservative \
"hoe" "json-schema:5.1.0" "test-unit-rr" "simplecov" "simplecov-html" "simplecov-json" "rspec" "zeitwerk" \
- "sinatra" "rack" "tilt" "mustermann" "base64" "compact_index" "rack-test" "logger" "kpeg" "tracer"
+ "sinatra" "rack" "tilt" "mustermann" "base64" "compact_index" "rack-test" "logger" "kpeg" "tracer" "minitest-mock"
test-bundled-gems-fetch: yes-test-bundled-gems-fetch
yes-test-bundled-gems-fetch: clone-bundled-gems-src
-clone-bundled-gems-src: PHONY
+clone-bundled-gems-src: PHONY $(TIMESTAMPDIR)/bundled-gems-src.time
+$(TIMESTAMPDIR)/bundled-gems-src.time: $(srcdir)/gems/bundled_gems
+ $(Q) $(MAKEDIRS) $(@D)
$(Q) $(BASERUBY) -C $(srcdir) tool/fetch-bundled_gems.rb BUNDLED_GEMS="$(BUNDLED_GEMS)" gems/src gems/bundled_gems
+ $(Q) $(TOUCH) $@
no-test-bundled-gems-fetch:
test-bundled-gems-prepare: $(TEST_RUNNABLE)-test-bundled-gems-prepare
@@ -1587,7 +1638,7 @@ yes-test-bundled-gems-run: $(PREPARE_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)
+yes-test-bundled-gems-spec: yes-test-all-precheck $(PREPARE_BUNDLED_GEMS)
$(ACTIONS_GROUP)
$(gnumake_recursive)$(Q) \
$(RUNRUBY) -r./$(arch)-fake -r$(tooldir)/lib/_tmpdir \
@@ -1601,6 +1652,11 @@ test-syntax-suggest:
check: $(DOT_WAIT) $(PREPARE_SYNTAX_SUGGEST) test-syntax-suggest
+RAKER = $(XRUBY) -I$(srcdir)/gems/lib$(PATH_SEPARATOR)$(srcdir)/.bundle/lib \
+ -rrubygems $(srcdir)/.bundle/bin/rake
+rake:
+ $(RAKER) $(RAKE_OPTS) $(RAKE)
+
test-bundler-precheck: $(TEST_RUNNABLE)-test-bundler-precheck
no-test-bundler-precheck:
yes-test-bundler-precheck: main $(arch)-fake.rb
@@ -1619,9 +1675,12 @@ BUNDLER_SPECS =
PREPARE_BUNDLER = $(TEST_RUNNABLE)-test-bundler-prepare
test-bundler: $(TEST_RUNNABLE)-test-bundler
yes-test-bundler: $(PREPARE_BUNDLER)
- $(gnumake_recursive)$(XRUBY) \
+ $(gnumake_recursive)$(XRUBY) --enable-gems \
-r./$(arch)-fake \
- -C $(srcdir) -Ispec/bundler -Ispec/lib spec/bin/rspec \
+ -r$(tooldir)/lib/_tmpdir \
+ -I$(srcdir)/spec/bundler -I$(srcdir)/spec/lib \
+ -e "Dir.chdir(ARGV.shift); load('spec/bin/rspec')" \
+ -s -- -no-report-tmpdir -- "$(srcdir)" \
-r spec_helper $(RSPECOPTS) spec/bundler/$(BUNDLER_SPECS)
no-test-bundler:
@@ -1630,11 +1689,13 @@ test-bundler-parallel: $(TEST_RUNNABLE)-test-bundler-parallel
yes-test-bundler-parallel: $(PREPARE_BUNDLER)
$(gnumake_recursive)$(XRUBY) \
-r./$(arch)-fake \
+ -r$(tooldir)/lib/_tmpdir \
-I$(srcdir)/spec/bundler \
-e "ruby = ENV['RUBY']" \
-e "ARGV[-1] = File.expand_path(ARGV[-1])" \
-e "ENV['RSPEC_EXECUTABLE'] = ruby + ARGV.shift" \
-e "load ARGV.shift" \
+ -s -- -no-report-tmpdir -- \
" -C $(srcdir) -Ispec/bundler -Ispec/lib .bundle/bin/rspec -r spec_helper" \
$(srcdir)/spec/bin/parallel_rspec $(RSPECOPTS) \
$(PARALLELRSPECOPTS) $(srcdir)/spec/bundler/$(BUNDLER_SPECS)
@@ -1708,7 +1769,7 @@ UNICODE_UCD_EMOJI_DOWNLOAD = \
UNICODE_EMOJI_DOWNLOAD = \
$(UNICODE_DOWNLOADER) \
-d $(UNICODE_SRC_EMOJI_DATA_DIR) \
- -p emoji/$(UNICODE_EMOJI_VERSION)
+ -p $(UNICODE_VERSION)/emoji
update-unicode-files:
$(ECHO) Downloading Unicode $(UNICODE_VERSION) data and property files...
@@ -1750,8 +1811,8 @@ $(UNICODE_EMOJI_FILES):
$(Q) $(MAKEDIRS) "$(UNICODE_SRC_EMOJI_DATA_DIR)"
$(Q) $(UNICODE_EMOJI_DOWNLOAD) $@
-$(srcdir)/lib/unicode_normalize/tables.rb: \
- $(UNICODE_SRC_DATA_DIR)/$(HAVE_BASERUBY:yes=.unicode-tables.time)
+$(srcdir)/lib/unicode_normalize/$(HAVE_BASERUBY:yes=tables.rb): \
+ $(UNICODE_SRC_DATA_DIR)/.unicode-tables.time
$(UNICODE_SRC_DATA_DIR)/$(ALWAYS_UPDATE_UNICODE:yes=.unicode-tables.time): \
$(UNICODE_FILES) $(UNICODE_PROPERTY_FILES) \
@@ -1802,11 +1863,11 @@ $(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): \
+srcs-doc: $(srcdir)/doc/language/regexp/unicode_properties.rdoc
+$(srcdir)/doc/language/regexp/$(ALWAYS_UPDATE_UNICODE:yes=unicode_properties.rdoc): \
$(UNICODE_HDR_DIR)/name2ctype.h $(UNICODE_PROPERTY_FILES)
-$(srcdir)/doc/regexp/unicode_properties.rdoc:
+$(srcdir)/doc/language/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 || \
@@ -1872,9 +1933,9 @@ sudo-precheck: PHONY
@$(SUDO) echo > $(NULL)
update-man-date: PHONY
- -$(Q) $(BASERUBY) -I"$(tooldir)/lib" -rvcs -i -p \
+ $(Q) $(BASERUBY) -I"$(tooldir)/lib" -rvcs -i -p \
-e 'BEGIN{@vcs=VCS.detect(ARGV.shift)}' \
- -e '$$_.sub!(/^(\.Dd ).*/){$$1+@vcs.modified(ARGF.path).strftime("%B %d, %Y")}' \
+ -e '$$_.sub!(/^(\.Dd ).*/){$$1+@vcs.author_date(@vcs.relative_to(ARGF.path)).strftime("%B %d, %Y")}' \
"$(srcdir)" "$(srcdir)"/man/*.1
.PHONY: ChangeLog
@@ -1897,8 +1958,8 @@ nightly: yesterday $(DOT_WAIT) install
yesterday: rewindable
rewindable:
- $(GIT) -C $(srcdir) status --porcelain
- $(GIT) -C $(srcdir) diff --quiet
+ $(GIT_IN_SRC) status --porcelain
+ $(GIT_IN_SRC) diff --quiet
HELP_EXTRA_TASKS = ""
diff --git a/compar.c b/compar.c
index f5da6178cf..1ab2520f1e 100644
--- a/compar.c
+++ b/compar.c
@@ -24,8 +24,8 @@ rb_cmp(VALUE x, VALUE y)
return rb_funcallv(x, idCmp, 1, &y);
}
-void
-rb_cmperr(VALUE x, VALUE y)
+static VALUE
+cmperr_subject(VALUE y)
{
VALUE classname;
@@ -35,10 +35,25 @@ rb_cmperr(VALUE x, VALUE y)
else {
classname = rb_obj_class(y);
}
+ return classname;
+}
+
+void
+rb_cmperr(VALUE x, VALUE y)
+{
+ VALUE classname = cmperr_subject(y);
rb_raise(rb_eArgError, "comparison of %"PRIsVALUE" with %"PRIsVALUE" failed",
rb_obj_class(x), classname);
}
+void
+rb_cmperr_reason(VALUE x, VALUE y, const char *reason)
+{
+ VALUE classname = cmperr_subject(y);
+ rb_raise(rb_eArgError, "comparison of %"PRIsVALUE" with %"PRIsVALUE" failed: %s",
+ rb_obj_class(x), classname, reason);
+}
+
static VALUE
invcmp_recursive(VALUE x, VALUE y, int recursive)
{
@@ -95,10 +110,13 @@ cmpint(VALUE x, VALUE y)
/*
* call-seq:
- * obj > other -> true or false
+ * self > other -> true or false
*
- * Compares two objects based on the receiver's <code><=></code>
- * method, returning true if it returns a value greater than 0.
+ * Returns whether +self+ is "greater than" +other+;
+ * equivalent to <tt>(self <=> other) > 0</tt>:
+ *
+ * 'foo' > 'foo' # => false
+ * 'food' > 'foo' # => true
*/
static VALUE
@@ -109,10 +127,15 @@ cmp_gt(VALUE x, VALUE y)
/*
* call-seq:
- * obj >= other -> true or false
+ * self >= other -> true or false
+ *
+ * Returns whether +self+ is "greater than or equal to" +other+;
+ * equivalent to <tt>(self <=> other) >= 0</tt>:
+ *
+ * 'food' >= 'foo' # => true
+ * 'foo' >= 'foo' # => true
+ * 'foo' >= 'food' # => false
*
- * Compares two objects based on the receiver's <code><=></code>
- * method, returning true if it returns a value greater than or equal to 0.
*/
static VALUE
@@ -123,10 +146,14 @@ cmp_ge(VALUE x, VALUE y)
/*
* call-seq:
- * obj < other -> true or false
+ * self < other -> true or false
+ *
+ * Returns whether +self+ is "less than" +other+;
+ * equivalent to <tt>(self <=> other) < 0</tt>:
+ *
+ * 'foo' < 'foo' # => false
+ * 'foo' < 'food' # => true
*
- * Compares two objects based on the receiver's <code><=></code>
- * method, returning true if it returns a value less than 0.
*/
static VALUE
@@ -137,10 +164,15 @@ cmp_lt(VALUE x, VALUE y)
/*
* call-seq:
- * obj <= other -> true or false
+ * self <= other -> true or false
+ *
+ * Returns whether +self+ is "less than or equal to" +other+;
+ * equivalent to <tt>(self <=> other) <= 0</tt>:
+ *
+ * 'foo' <= 'foo' # => true
+ * 'foo' <= 'food' # => true
+ * 'food' <= 'foo' # => false
*
- * Compares two objects based on the receiver's <code><=></code>
- * method, returning true if it returns a value less than or equal to 0.
*/
static VALUE
diff --git a/compile.c b/compile.c
index bda18c1c42..65ced44f9c 100644
--- a/compile.c
+++ b/compile.c
@@ -494,6 +494,7 @@ static int iseq_set_arguments(rb_iseq_t *iseq, LINK_ANCHOR *const anchor, const
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 iseq_set_parameters_lvar_state(const 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_hash(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int method_call_keywords, int popped);
@@ -609,8 +610,6 @@ 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)
{
@@ -837,9 +836,9 @@ get_string_value(const NODE *node)
{
switch (nd_type(node)) {
case NODE_STR:
- return rb_node_str_string_val(node);
+ return RB_OBJ_SET_SHAREABLE(rb_node_str_string_val(node));
case NODE_FILE:
- return rb_node_file_path_val(node);
+ return RB_OBJ_SET_SHAREABLE(rb_node_file_path_val(node));
default:
rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
}
@@ -876,6 +875,7 @@ rb_iseq_compile_node(rb_iseq_t *iseq, const NODE *node)
/* 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_parameters_lvar_state(iseq);
switch (ISEQ_BODY(iseq)->type) {
case ISEQ_TYPE_BLOCK:
@@ -1029,75 +1029,44 @@ rb_iseq_original_iseq(const rb_iseq_t *iseq) /* cold path */
/* definition of data structure for compiler */
/*********************************************/
-/*
- * On 32-bit SPARC, GCC by default generates SPARC V7 code that may require
- * 8-byte word alignment. On the other hand, Oracle Solaris Studio seems to
- * generate SPARCV8PLUS code with unaligned memory access instructions.
- * That is why the STRICT_ALIGNMENT is defined only with GCC.
- */
-#if defined(__sparc) && SIZEOF_VOIDP == 4 && defined(__GNUC__)
- #define STRICT_ALIGNMENT
+#if defined(HAVE_TRUE_LONG_LONG) && SIZEOF_LONG_LONG > SIZEOF_VALUE
+# define ALIGNMENT_SIZE SIZEOF_LONG_LONG
+#else
+# define ALIGNMENT_SIZE SIZEOF_VALUE
#endif
+#define PADDING_SIZE_MAX ((size_t)((ALIGNMENT_SIZE) - 1))
-/*
- * Some OpenBSD platforms (including sparc64) require strict alignment.
- */
-#if defined(__OpenBSD__)
- #include <sys/endian.h>
- #ifdef __STRICT_ALIGNMENT
- #define STRICT_ALIGNMENT
- #endif
-#endif
+#define ALIGNMENT_SIZE_OF(type) alignment_size_assert(RUBY_ALIGNOF(type), #type)
-#ifdef STRICT_ALIGNMENT
- #if defined(HAVE_TRUE_LONG_LONG) && SIZEOF_LONG_LONG > SIZEOF_VALUE
- #define ALIGNMENT_SIZE SIZEOF_LONG_LONG
- #else
- #define ALIGNMENT_SIZE SIZEOF_VALUE
- #endif
- #define PADDING_SIZE_MAX ((size_t)((ALIGNMENT_SIZE) - 1))
- #define ALIGNMENT_SIZE_MASK PADDING_SIZE_MAX
- /* Note: ALIGNMENT_SIZE == (2 ** N) is expected. */
-#else
- #define PADDING_SIZE_MAX 0
-#endif /* STRICT_ALIGNMENT */
+static inline size_t
+alignment_size_assert(size_t align, const char *type)
+{
+ RUBY_ASSERT((align & (align - 1)) == 0,
+ "ALIGNMENT_SIZE_OF(%s):%zd == (2 ** N) is expected", type, align);
+ return align;
+}
-#ifdef STRICT_ALIGNMENT
/* calculate padding size for aligned memory access */
-static size_t
-calc_padding(void *ptr, size_t size)
+static inline size_t
+calc_padding(void *ptr, size_t align)
{
size_t mis;
size_t padding = 0;
- mis = (size_t)ptr & ALIGNMENT_SIZE_MASK;
+ mis = (size_t)ptr & (align - 1);
if (mis > 0) {
- padding = ALIGNMENT_SIZE - mis;
+ padding = align - mis;
}
-/*
- * On 32-bit sparc or equivalents, when a single VALUE is requested
- * and padding == sizeof(VALUE), it is clear that no padding is needed.
- */
-#if ALIGNMENT_SIZE > SIZEOF_VALUE
- if (size == sizeof(VALUE) && padding == sizeof(VALUE)) {
- padding = 0;
- }
-#endif
return padding;
}
-#endif /* STRICT_ALIGNMENT */
static void *
-compile_data_alloc_with_arena(struct iseq_compile_data_storage **arena, size_t size)
+compile_data_alloc_with_arena(struct iseq_compile_data_storage **arena, size_t size, size_t align)
{
void *ptr = 0;
struct iseq_compile_data_storage *storage = *arena;
-#ifdef STRICT_ALIGNMENT
- size_t padding = calc_padding((void *)&storage->buff[storage->pos], size);
-#else
- const size_t padding = 0; /* expected to be optimized by compiler */
-#endif /* STRICT_ALIGNMENT */
+ size_t padding = calc_padding((void *)&storage->buff[storage->pos], align);
if (size >= INT_MAX - padding) rb_memerror();
if (storage->pos + size + padding > storage->size) {
@@ -1113,14 +1082,10 @@ compile_data_alloc_with_arena(struct iseq_compile_data_storage **arena, size_t s
storage->next = 0;
storage->pos = 0;
storage->size = alloc_size;
-#ifdef STRICT_ALIGNMENT
- padding = calc_padding((void *)&storage->buff[storage->pos], size);
-#endif /* STRICT_ALIGNMENT */
+ padding = calc_padding((void *)&storage->buff[storage->pos], align);
}
-#ifdef STRICT_ALIGNMENT
storage->pos += (int)padding;
-#endif /* STRICT_ALIGNMENT */
ptr = (void *)&storage->buff[storage->pos];
storage->pos += (int)size;
@@ -1128,51 +1093,60 @@ compile_data_alloc_with_arena(struct iseq_compile_data_storage **arena, size_t s
}
static void *
-compile_data_alloc(rb_iseq_t *iseq, size_t size)
+compile_data_alloc(rb_iseq_t *iseq, size_t size, size_t align)
{
struct iseq_compile_data_storage ** arena = &ISEQ_COMPILE_DATA(iseq)->node.storage_current;
- return compile_data_alloc_with_arena(arena, size);
+ return compile_data_alloc_with_arena(arena, size, align);
}
+#define compile_data_alloc_type(iseq, type) \
+ (type *)compile_data_alloc(iseq, sizeof(type), ALIGNMENT_SIZE_OF(type))
+
static inline void *
-compile_data_alloc2(rb_iseq_t *iseq, size_t x, size_t y)
+compile_data_alloc2(rb_iseq_t *iseq, size_t elsize, size_t num, size_t align)
{
- size_t size = rb_size_mul_or_raise(x, y, rb_eRuntimeError);
- return compile_data_alloc(iseq, size);
+ size_t size = rb_size_mul_or_raise(elsize, num, rb_eRuntimeError);
+ return compile_data_alloc(iseq, size, align);
}
+#define compile_data_alloc2_type(iseq, type, num) \
+ (type *)compile_data_alloc2(iseq, sizeof(type), num, ALIGNMENT_SIZE_OF(type))
+
static inline void *
-compile_data_calloc2(rb_iseq_t *iseq, size_t x, size_t y)
+compile_data_calloc2(rb_iseq_t *iseq, size_t elsize, size_t num, size_t align)
{
- size_t size = rb_size_mul_or_raise(x, y, rb_eRuntimeError);
- void *p = compile_data_alloc(iseq, size);
+ size_t size = rb_size_mul_or_raise(elsize, num, rb_eRuntimeError);
+ void *p = compile_data_alloc(iseq, size, align);
memset(p, 0, size);
return p;
}
+#define compile_data_calloc2_type(iseq, type, num) \
+ (type *)compile_data_calloc2(iseq, sizeof(type), num, ALIGNMENT_SIZE_OF(type))
+
static INSN *
compile_data_alloc_insn(rb_iseq_t *iseq)
{
struct iseq_compile_data_storage ** arena = &ISEQ_COMPILE_DATA(iseq)->insn.storage_current;
- return (INSN *)compile_data_alloc_with_arena(arena, sizeof(INSN));
+ return (INSN *)compile_data_alloc_with_arena(arena, sizeof(INSN), ALIGNMENT_SIZE_OF(INSN));
}
static LABEL *
compile_data_alloc_label(rb_iseq_t *iseq)
{
- return (LABEL *)compile_data_alloc(iseq, sizeof(LABEL));
+ return compile_data_alloc_type(iseq, LABEL);
}
static ADJUST *
compile_data_alloc_adjust(rb_iseq_t *iseq)
{
- return (ADJUST *)compile_data_alloc(iseq, sizeof(ADJUST));
+ return compile_data_alloc_type(iseq, ADJUST);
}
static TRACE *
compile_data_alloc_trace(rb_iseq_t *iseq)
{
- return (TRACE *)compile_data_alloc(iseq, sizeof(TRACE));
+ return compile_data_alloc_type(iseq, TRACE);
}
/*
@@ -1398,6 +1372,9 @@ static void
iseq_insn_each_object_write_barrier(VALUE * obj, VALUE iseq)
{
RB_OBJ_WRITTEN(iseq, Qundef, *obj);
+ RUBY_ASSERT(SPECIAL_CONST_P(*obj) ||
+ RBASIC_CLASS(*obj) == 0 || // hidden
+ RB_OBJ_SHAREABLE_P(*obj));
}
static INSN *
@@ -1430,7 +1407,7 @@ new_insn_body(rb_iseq_t *iseq, int line_no, int node_id, enum ruby_vminsn_type i
if (argc > 0) {
int i;
va_start(argv, argc);
- operands = compile_data_alloc2(iseq, sizeof(VALUE), argc);
+ operands = compile_data_alloc2_type(iseq, VALUE, argc);
for (i = 0; i < argc; i++) {
VALUE v = va_arg(argv, VALUE);
operands[i] = v;
@@ -1448,7 +1425,7 @@ insn_replace_with_operands(rb_iseq_t *iseq, INSN *iobj, enum ruby_vminsn_type in
if (argc > 0) {
int i;
va_start(argv, argc);
- operands = compile_data_alloc2(iseq, sizeof(VALUE), argc);
+ operands = compile_data_alloc2_type(iseq, VALUE, argc);
for (i = 0; i < argc; i++) {
VALUE v = va_arg(argv, VALUE);
operands[i] = v;
@@ -1488,7 +1465,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)
{
- VALUE *operands = compile_data_calloc2(iseq, sizeof(VALUE), 2);
+ VALUE *operands = compile_data_calloc2_type(iseq, VALUE, 2);
VALUE ci = (VALUE)new_callinfo(iseq, id, FIX2INT(argc), FIX2INT(flag), keywords, blockiseq != NULL);
operands[0] = ci;
operands[1] = (VALUE)blockiseq;
@@ -1689,7 +1666,7 @@ iseq_setup(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
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) {
- xfree(ISEQ_BODY(iseq)->catch_table);
+ ruby_xfree_sized(ISEQ_BODY(iseq)->catch_table, iseq_catch_table_bytes(ISEQ_BODY(iseq)->catch_table->size));
ISEQ_BODY(iseq)->catch_table = NULL;
}
@@ -1715,6 +1692,7 @@ iseq_set_exception_local_table(rb_iseq_t *iseq)
{
ISEQ_BODY(iseq)->local_table_size = numberof(rb_iseq_shared_exc_local_tbl);
ISEQ_BODY(iseq)->local_table = rb_iseq_shared_exc_local_tbl;
+ ISEQ_BODY(iseq)->lvar_states = NULL; // $! is read-only, so don't need lvar_states
return COMPILE_OK;
}
@@ -1862,6 +1840,46 @@ iseq_lvar_id(const rb_iseq_t *iseq, int idx, int level)
}
static void
+update_lvar_state(const rb_iseq_t *iseq, int level, int idx)
+{
+ for (int i=0; i<level; i++) {
+ iseq = ISEQ_BODY(iseq)->parent_iseq;
+ }
+
+ enum lvar_state *states = ISEQ_BODY(iseq)->lvar_states;
+ int table_idx = ISEQ_BODY(iseq)->local_table_size - idx;
+ switch (states[table_idx]) {
+ case lvar_uninitialized:
+ states[table_idx] = lvar_initialized;
+ break;
+ case lvar_initialized:
+ states[table_idx] = lvar_reassigned;
+ break;
+ case lvar_reassigned:
+ /* nothing */
+ break;
+ default:
+ rb_bug("unreachable");
+ }
+}
+
+static int
+iseq_set_parameters_lvar_state(const rb_iseq_t *iseq)
+{
+ for (unsigned int i=0; i<ISEQ_BODY(iseq)->param.size; i++) {
+ ISEQ_BODY(iseq)->lvar_states[i] = lvar_initialized;
+ }
+
+ int lead_num = ISEQ_BODY(iseq)->param.lead_num;
+ int opt_num = ISEQ_BODY(iseq)->param.opt_num;
+ for (int i=0; i<opt_num; i++) {
+ ISEQ_BODY(iseq)->lvar_states[lead_num + i] = lvar_uninitialized;
+ }
+
+ return COMPILE_OK;
+}
+
+static void
iseq_add_getlocal(rb_iseq_t *iseq, LINK_ANCHOR *const seq, const NODE *const line_node, int idx, int level)
{
if (iseq_local_block_param_p(iseq, idx, level)) {
@@ -1882,6 +1900,7 @@ iseq_add_setlocal(rb_iseq_t *iseq, LINK_ANCHOR *const seq, const NODE *const lin
else {
ADD_INSN2(seq, line_node, setlocal, INT2FIX((idx) + VM_ENV_DATA_SIZE - 1), INT2FIX(level));
}
+ update_lvar_state(iseq, level, idx);
if (level > 0) access_outer_variables(iseq, level, iseq_lvar_id(iseq, idx, level), Qtrue);
}
@@ -2019,6 +2038,7 @@ iseq_set_arguments_keywords(rb_iseq_t *iseq, LINK_ANCHOR *const optargs,
for (i = 0; i < RARRAY_LEN(default_values); i++) {
VALUE dv = RARRAY_AREF(default_values, i);
if (dv == complex_mark) dv = Qundef;
+ if (!SPECIAL_CONST_P(dv)) rb_ractor_make_shareable(dv);
RB_OBJ_WRITE(iseq, &dvs[i], dv);
}
@@ -2038,7 +2058,7 @@ iseq_set_use_block(rb_iseq_t *iseq)
if (!rb_warning_category_enabled_p(RB_WARN_CATEGORY_STRICT_UNUSED_BLOCK)) {
st_data_t key = (st_data_t)rb_intern_str(body->location.label); // String -> ID
- set_insert(vm->unused_block_warning_table, key);
+ set_insert(&vm->unused_block_warning_table, key);
}
}
}
@@ -2050,7 +2070,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;
+ const struct rb_args_info *const args = &RNODE_ARGS(node_args)->nd_ainfo;
ID rest_id = 0;
int last_comma = 0;
ID block_id = 0;
@@ -2058,7 +2078,6 @@ iseq_set_arguments(rb_iseq_t *iseq, LINK_ANCHOR *const optargs, const NODE *cons
EXPECT_NODE("iseq_set_arguments", node_args, NODE_ARGS, COMPILE_NG);
- body->param.flags.ruby2_keywords = args->ruby2_keywords;
body->param.lead_num = arg_size = (int)args->pre_args_num;
if (body->param.lead_num > 0) body->param.flags.has_lead = TRUE;
debugs(" - argc: %d\n", body->param.lead_num);
@@ -2148,7 +2167,10 @@ iseq_set_arguments(rb_iseq_t *iseq, LINK_ANCHOR *const optargs, const NODE *cons
body->param.flags.accepts_no_kwarg = TRUE;
}
- if (block_id) {
+ if (args->no_blockarg) {
+ body->param.flags.accepts_no_block = TRUE;
+ }
+ else if (block_id) {
body->param.block_start = arg_size++;
body->param.flags.has_block = TRUE;
iseq_set_use_block(iseq);
@@ -2212,6 +2234,14 @@ iseq_set_local_table(rb_iseq_t *iseq, const rb_ast_id_table_t *tbl, const NODE *
ID *ids = ALLOC_N(ID, size);
MEMCPY(ids, tbl->ids + offset, ID, size);
ISEQ_BODY(iseq)->local_table = ids;
+
+ enum lvar_state *states = ALLOC_N(enum lvar_state, size);
+ // fprintf(stderr, "iseq:%p states:%p size:%d\n", iseq, states, (int)size);
+ for (unsigned int i=0; i<size; i++) {
+ states[i] = lvar_uninitialized;
+ // fprintf(stderr, "id:%s\n", rb_id2name(ISEQ_BODY(iseq)->local_table[i]));
+ }
+ ISEQ_BODY(iseq)->lvar_states = states;
}
ISEQ_BODY(iseq)->local_table_size = size;
@@ -2300,6 +2330,33 @@ static const struct st_hash_type cdhash_type = {
rb_iseq_cdhash_hash,
};
+static VALUE
+cdhash_new(size_t size)
+{
+ VALUE cdhash = rb_imemo_cdhash_new(size, &cdhash_type);
+ RB_OBJ_SET_SHAREABLE(cdhash);
+ return cdhash;
+}
+
+static void
+cdhash_aset(VALUE cdhash, VALUE key, VALUE val)
+{
+ st_table *tbl = rb_imemo_cdhash_tbl(cdhash);
+ st_insert(tbl, key, val);
+ RB_OBJ_WRITTEN(cdhash, Qundef, key);
+}
+
+static void
+cdhash_aset_if_missing(VALUE cdhash, VALUE key, VALUE val)
+{
+ st_table *tbl = rb_imemo_cdhash_tbl(cdhash);
+ VALUE dontcare;
+ if (!st_lookup(tbl, key, &dontcare)) {
+ st_insert(tbl, key, val);
+ RB_OBJ_WRITTEN(cdhash, Qundef, key);
+ }
+}
+
struct cdhash_set_label_struct {
VALUE hash;
int pos;
@@ -2307,15 +2364,20 @@ struct cdhash_set_label_struct {
};
static int
-cdhash_set_label_i(VALUE key, VALUE val, VALUE ptr)
+cdhash_set_label_check_i(st_data_t key, st_data_t value, st_data_t argp, int error)
+{
+ return ST_REPLACE;
+}
+
+static int
+cdhash_set_label_replace_i(st_data_t *key, st_data_t *value, st_data_t ptr, int existing)
{
struct cdhash_set_label_struct *data = (struct cdhash_set_label_struct *)ptr;
- LABEL *lobj = (LABEL *)(val & ~1);
- rb_hash_aset(data->hash, key, INT2FIX(lobj->position - (data->pos+data->len)));
+ LABEL *lobj = (LABEL *)(*value & ~1);
+ *value = lobj->position - (data->pos+data->len);
return ST_CONTINUE;
}
-
static inline VALUE
get_ivar_ic_value(rb_iseq_t *iseq,ID id)
{
@@ -2345,8 +2407,8 @@ get_cvar_ic_value(rb_iseq_t *iseq,ID id)
dump_disasm_list_with_cursor(FIRST_ELEMENT(anchor), list, dest)
#define BADINSN_ERROR \
- (xfree(generated_iseq), \
- xfree(insns_info), \
+ (SIZED_FREE_N(generated_iseq, generated_iseq_size), \
+ SIZED_FREE_N(insns_info, insns_info_size), \
BADINSN_DUMP(anchor, list, NULL), \
COMPILE_ERROR)
@@ -2612,8 +2674,13 @@ iseq_set_sequence(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
}
/* make instruction sequence */
+ const int generated_iseq_size = code_index;
generated_iseq = ALLOC_N(VALUE, code_index);
+
+ const int insns_info_size = insn_num;
insns_info = ALLOC_N(struct iseq_insn_info_entry, insn_num);
+
+ const int positions_size = 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));
@@ -2640,12 +2707,13 @@ iseq_set_sequence(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
bool needs_bitmap = false;
- if (ISEQ_MBITS_BUFLEN(code_index) == 1) {
+ const size_t mark_offset_bits_size = ISEQ_MBITS_BUFLEN(code_index);
+ if (mark_offset_bits_size == 1) {
mark_offset_bits = &ISEQ_COMPILE_DATA(iseq)->mark_bits.single;
ISEQ_COMPILE_DATA(iseq)->is_single_mark_bit = true;
}
else {
- mark_offset_bits = ZALLOC_N(iseq_bits_t, ISEQ_MBITS_BUFLEN(code_index));
+ mark_offset_bits = ZALLOC_N(iseq_bits_t, mark_offset_bits_size);
ISEQ_COMPILE_DATA(iseq)->mark_bits.list = mark_offset_bits;
ISEQ_COMPILE_DATA(iseq)->is_single_mark_bit = false;
}
@@ -2693,10 +2761,8 @@ iseq_set_sequence(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
data.hash = map;
data.pos = code_index;
data.len = len;
- rb_hash_foreach(map, cdhash_set_label_i, (VALUE)&data);
+ st_foreach_with_replace(rb_imemo_cdhash_tbl(map), cdhash_set_label_check_i, cdhash_set_label_replace_i, (VALUE)&data);
- rb_hash_rehash(map);
- freeze_hide_obj(map);
generated_iseq[code_index + 1 + j] = map;
ISEQ_MBITS_SET(mark_offset_bits, code_index + 1 + j);
RB_OBJ_WRITTEN(iseq, Qundef, map);
@@ -2745,12 +2811,12 @@ iseq_set_sequence(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
if (insn == BIN(setinstancevariable)) {
cache->iv_set_name = SYM2ID(operands[j - 1]);
+ cache->value = IVAR_CACHE_INIT;
}
else {
cache->iv_set_name = 0;
+ cache->value = rb_getivar_cache_pack(ROOT_SHAPE_ID, ATTR_INDEX_NOT_SET);
}
-
- vm_ic_attr_index_initialize(cache, INVALID_SHAPE_ID);
}
case TS_ISE: /* inline storage entry: `once` insn */
case TS_ICVARC: /* inline cvar cache */
@@ -2837,11 +2903,11 @@ iseq_set_sequence(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
}
else if (diff < 0) {
int label_no = adjust->label ? adjust->label->label_no : -1;
- xfree(generated_iseq);
- xfree(insns_info);
- xfree(positions);
+ SIZED_FREE_N(generated_iseq, generated_iseq_size);
+ SIZED_FREE_N(insns_info, insns_info_size);
+ SIZED_FREE_N(positions, positions_size);
if (ISEQ_MBITS_BUFLEN(code_size) > 1) {
- xfree(mark_offset_bits);
+ SIZED_FREE_N(mark_offset_bits, ISEQ_MBITS_BUFLEN(code_index));
}
debug_list(anchor, list);
COMPILE_ERROR(iseq, adjust->line_no,
@@ -2873,7 +2939,7 @@ iseq_set_sequence(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
else {
body->mark_bits.list = NULL;
ISEQ_COMPILE_DATA(iseq)->mark_bits.list = NULL;
- ruby_xfree(mark_offset_bits);
+ SIZED_FREE_N(mark_offset_bits, mark_offset_bits_size);
}
}
@@ -2881,9 +2947,9 @@ iseq_set_sequence(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
body->insns_info.body = insns_info;
body->insns_info.positions = positions;
- REALLOC_N(insns_info, struct iseq_insn_info_entry, insns_info_index);
+ SIZED_REALLOC_N(insns_info, struct iseq_insn_info_entry, insns_info_index, insns_info_size);
body->insns_info.body = insns_info;
- REALLOC_N(positions, unsigned int, insns_info_index);
+ SIZED_REALLOC_N(positions, unsigned int, insns_info_index, positions_size);
body->insns_info.positions = positions;
body->insns_info.size = insns_info_index;
@@ -3159,7 +3225,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, dupstring) || IS_INSN_ID(insn, dupchilledstring)) {
*op = OPERAND_AT(insn, 0);
return 1;
}
@@ -3171,6 +3237,25 @@ is_frozen_putstring(INSN *insn, VALUE *op)
}
static int
+insn_has_label_before(LINK_ELEMENT *elem)
+{
+ LINK_ELEMENT *prev = elem->prev;
+ while (prev) {
+ if (prev->type == ISEQ_ELEMENT_LABEL) {
+ LABEL *label = (LABEL *)prev;
+ if (label->refcnt > 0) {
+ return 1;
+ }
+ }
+ else if (prev->type == ISEQ_ELEMENT_INSN) {
+ break;
+ }
+ prev = prev->prev;
+ }
+ return 0;
+}
+
+static int
optimize_checktype(rb_iseq_t *iseq, INSN *iobj)
{
/*
@@ -3200,8 +3285,8 @@ optimize_checktype(rb_iseq_t *iseq, INSN *iobj)
VALUE type;
switch (INSN_OF(iobj)) {
- case BIN(putstring):
- case BIN(putchilledstring):
+ case BIN(dupstring):
+ case BIN(dupchilledstring):
type = INT2FIX(T_STRING);
break;
case BIN(putnil):
@@ -3399,8 +3484,8 @@ iseq_peephole_optimize(rb_iseq_t *iseq, LINK_ELEMENT *list, const int do_tailcal
}
/*
- * putstring "beg"
- * putstring "end"
+ * dupstring "beg"
+ * dupstring "end"
* newrange excl
*
* ==>
@@ -3415,9 +3500,10 @@ iseq_peephole_optimize(rb_iseq_t *iseq, LINK_ELEMENT *list, const int do_tailcal
if ((end = (INSN *)get_prev_insn(range)) != 0 &&
is_frozen_putstring(end, &str_end) &&
(beg = (INSN *)get_prev_insn(end)) != 0 &&
- is_frozen_putstring(beg, &str_beg)) {
+ is_frozen_putstring(beg, &str_beg) &&
+ !(insn_has_label_before(&beg->link) || insn_has_label_before(&end->link))) {
int excl = FIX2INT(OPERAND_AT(range, 0));
- VALUE lit_range = rb_range_new(str_beg, str_end, excl);
+ VALUE lit_range = RB_OBJ_SET_SHAREABLE(rb_range_new(str_beg, str_end, excl));
ELEM_REMOVE(&beg->link);
ELEM_REMOVE(&end->link);
@@ -3484,6 +3570,7 @@ iseq_peephole_optimize(rb_iseq_t *iseq, LINK_ELEMENT *list, const int do_tailcal
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);
+ RB_OBJ_SET_SHAREABLE(hash);
insn_replace_with_operands(iseq, iobj, BIN(opt_hash_freeze), 2, hash, (VALUE)ci);
ELEM_REMOVE(next);
@@ -3613,16 +3700,16 @@ iseq_peephole_optimize(rb_iseq_t *iseq, LINK_ELEMENT *list, const int do_tailcal
* =>
* jump L1
*
- * putstring ".."
+ * dupstring ".."
* if L1
* =>
* jump L1
*
- * putstring ".."
+ * dupstring ".."
* dup
* if L1
* =>
- * putstring ".."
+ * dupstring ".."
* jump L1
*
*/
@@ -3637,7 +3724,7 @@ iseq_peephole_optimize(rb_iseq_t *iseq, LINK_ELEMENT *list, const int do_tailcal
OPERAND_AT(pobj, 0) == Qfalse :
FALSE);
}
- else if (IS_INSN_ID(pobj, putstring) ||
+ else if (IS_INSN_ID(pobj, dupstring) ||
IS_INSN_ID(pobj, duparray) ||
IS_INSN_ID(pobj, newarray)) {
cond = IS_INSN_ID(iobj, branchif);
@@ -3675,7 +3762,7 @@ iseq_peephole_optimize(rb_iseq_t *iseq, LINK_ELEMENT *list, const int do_tailcal
if (IS_INSN_ID(iobj, pop)) {
/*
- * putself / putnil / putobject obj / putstring "..."
+ * putself / putnil / putobject obj / dupstring "..."
* pop
* =>
* # do nothing
@@ -3684,8 +3771,8 @@ iseq_peephole_optimize(rb_iseq_t *iseq, LINK_ELEMENT *list, const int do_tailcal
if (IS_INSN(prev)) {
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(putself) || previ == BIN(dupstring) ||
+ previ == BIN(dupchilledstring) ||
previ == BIN(dup) ||
previ == BIN(getlocal) ||
previ == BIN(getblockparam) ||
@@ -3827,10 +3914,10 @@ 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, dupstring) || IS_INSN_ID(iobj, dupchilledstring) ||
(IS_INSN_ID(iobj, putobject) && RB_TYPE_P(OPERAND_AT(iobj, 0), T_STRING))) {
/*
- * putstring ""
+ * dupstring ""
* concatstrings N
* =>
* concatstrings N-1
@@ -3857,6 +3944,9 @@ iseq_peephole_optimize(rb_iseq_t *iseq, LINK_ELEMENT *list, const int do_tailcal
rb_set_errinfo(errinfo);
COMPILE_ERROR(iseq, line, "%" PRIsVALUE, message);
}
+ else {
+ RB_OBJ_SET_SHAREABLE(re);
+ }
RB_OBJ_WRITE(iseq, &OPERAND_AT(iobj, 0), re);
ELEM_REMOVE(iobj->link.next);
}
@@ -3898,8 +3988,6 @@ iseq_peephole_optimize(rb_iseq_t *iseq, LINK_ELEMENT *list, const int do_tailcal
if (do_tailcallopt &&
(IS_INSN_ID(iobj, send) ||
- IS_INSN_ID(iobj, opt_aref_with) ||
- IS_INSN_ID(iobj, opt_aset_with) ||
IS_INSN_ID(iobj, invokesuper))) {
/*
* send ...
@@ -4100,7 +4188,7 @@ iseq_peephole_optimize(rb_iseq_t *iseq, LINK_ELEMENT *list, const int do_tailcal
unsigned int flags = vm_ci_flag(ci);
if ((flags & set_flags) == set_flags && !(flags & unset_flags)) {
((INSN*)niobj)->insn_id = BIN(putobject);
- RB_OBJ_WRITE(iseq, &OPERAND_AT(niobj, 0), rb_hash_freeze(rb_hash_resurrect(OPERAND_AT(niobj, 0))));
+ RB_OBJ_WRITE(iseq, &OPERAND_AT(niobj, 0), RB_OBJ_SET_SHAREABLE(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));
@@ -4164,7 +4252,7 @@ iseq_specialized_instruction(rb_iseq_t *iseq, INSN *iobj)
}
}
}
- else if ((IS_INSN_ID(niobj, putstring) || IS_INSN_ID(niobj, putchilledstring) ||
+ else if ((IS_INSN_ID(niobj, dupstring) || IS_INSN_ID(niobj, dupchilledstring) ||
(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);
@@ -4177,9 +4265,9 @@ iseq_specialized_instruction(rb_iseq_t *iseq, INSN *iobj)
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) ||
+ // newarray n, dupchilledstring "E", getlocal b, send :pack with {buffer: b}
+ // -> dupchilledstring "E", getlocal b, opt_newarray_send n+2, :pack, :buffer
+ else if ((IS_INSN_ID(niobj, dupstring) || IS_INSN_ID(niobj, dupchilledstring) ||
(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))) {
@@ -4202,7 +4290,7 @@ iseq_specialized_instruction(rb_iseq_t *iseq, INSN *iobj)
// Break the "else if" chain since some prior checks abort after sub-ifs.
// We already found "newarray". To match `[...].include?(arg)` we look for
// the instruction(s) representing the argument followed by a "send".
- if ((IS_INSN_ID(niobj, putstring) || IS_INSN_ID(niobj, putchilledstring) ||
+ if ((IS_INSN_ID(niobj, dupstring) || IS_INSN_ID(niobj, dupchilledstring) ||
IS_INSN_ID(niobj, putobject) ||
IS_INSN_ID(niobj, putself) ||
IS_INSN_ID(niobj, getlocal) ||
@@ -4351,6 +4439,7 @@ iseq_optimize(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
ISEQ_COMPILE_DATA(iseq)->option->tailcall_optimization;
const int do_si = ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction;
const int do_ou = ISEQ_COMPILE_DATA(iseq)->option->operands_unification;
+ const int do_without_ints = ISEQ_BODY(iseq)->builtin_attrs & BUILTIN_ATTR_WITHOUT_INTERRUPTS;
int rescue_level = 0;
int tailcallopt = do_tailcallopt;
@@ -4383,6 +4472,22 @@ iseq_optimize(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
insn_operands_unification((INSN *)list);
}
+ if (do_without_ints) {
+ INSN *item = (INSN *)list;
+ if (IS_INSN_ID(item, jump)) {
+ item->insn_id = BIN(jump_without_ints);
+ }
+ else if (IS_INSN_ID(item, branchif)) {
+ item->insn_id = BIN(branchif_without_ints);
+ }
+ else if (IS_INSN_ID(item, branchunless)) {
+ item->insn_id = BIN(branchunless_without_ints);
+ }
+ else if (IS_INSN_ID(item, branchnil)) {
+ item->insn_id = BIN(branchnil_without_ints);
+ }
+ }
+
if (do_block_optimization) {
INSN * item = (INSN *)list;
// Give up if there is a throw
@@ -4450,7 +4555,7 @@ new_unified_insn(rb_iseq_t *iseq,
}
if (argc > 0) {
- ptr = operands = compile_data_alloc2(iseq, sizeof(VALUE), argc);
+ ptr = operands = compile_data_alloc2_type(iseq, VALUE, argc);
}
/* copy operands */
@@ -4654,7 +4759,8 @@ 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);
- ADD_INSN1(ret, node, putstring, lit);
+ ADD_INSN1(ret, node, dupstring, lit);
+ RB_OBJ_SET_SHAREABLE(lit);
RB_OBJ_WRITTEN(iseq, Qundef, lit);
}
else {
@@ -4674,6 +4780,7 @@ compile_dregx(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, i
if (!popped) {
VALUE src = rb_node_dregx_string_val(node);
VALUE match = rb_reg_compile(src, cflag, NULL, 0);
+ RB_OBJ_SET_SHAREABLE(match);
ADD_INSN1(ret, node, putobject, match);
RB_OBJ_WRITTEN(iseq, Qundef, match);
}
@@ -4766,6 +4873,7 @@ compile_branch_condition(rb_iseq_t *iseq, LINK_ANCHOR *ret, const NODE *cond,
CHECK(ok = compile_logical(iseq, ret, RNODE_AND(cond)->nd_1st, NULL, else_label));
cond = RNODE_AND(cond)->nd_2nd;
if (ok == COMPILE_SINGLE) {
+ ADD_INSNL(ret, cond, jump, else_label);
INIT_ANCHOR(ignore);
ret = ignore;
then_label = NEW_LABEL(nd_line(cond));
@@ -4775,6 +4883,7 @@ compile_branch_condition(rb_iseq_t *iseq, LINK_ANCHOR *ret, const NODE *cond,
CHECK(ok = compile_logical(iseq, ret, RNODE_OR(cond)->nd_1st, then_label, NULL));
cond = RNODE_OR(cond)->nd_2nd;
if (ok == COMPILE_SINGLE) {
+ ADD_INSNL(ret, cond, jump, then_label);
INIT_ANCHOR(ignore);
ret = ignore;
else_label = NEW_LABEL(nd_line(cond));
@@ -5018,13 +5127,21 @@ static_literal_value(const NODE *node, rb_iseq_t *iseq)
{
switch (nd_type(node)) {
case NODE_INTEGER:
- return rb_node_integer_literal_val(node);
+ {
+ VALUE lit = rb_node_integer_literal_val(node);
+ if (!SPECIAL_CONST_P(lit)) RB_OBJ_SET_SHAREABLE(lit);
+ return lit;
+ }
case NODE_FLOAT:
- return rb_node_float_literal_val(node);
+ {
+ VALUE lit = rb_node_float_literal_val(node);
+ if (!SPECIAL_CONST_P(lit)) RB_OBJ_SET_SHAREABLE(lit);
+ return lit;
+ }
case NODE_RATIONAL:
- return rb_node_rational_literal_val(node);
+ return rb_ractor_make_shareable(rb_node_rational_literal_val(node));
case NODE_IMAGINARY:
- return rb_node_imaginary_literal_val(node);
+ return rb_ractor_make_shareable(rb_node_imaginary_literal_val(node));
case NODE_NIL:
return Qnil;
case NODE_TRUE:
@@ -5034,7 +5151,7 @@ static_literal_value(const NODE *node, rb_iseq_t *iseq)
case NODE_SYM:
return rb_node_sym_string_val(node);
case NODE_REGX:
- return rb_node_regx_string_val(node);
+ return RB_OBJ_SET_SHAREABLE(rb_node_regx_string_val(node));
case NODE_LINE:
return rb_node_line_lineno_val(node);
case NODE_ENCODING:
@@ -5043,7 +5160,9 @@ static_literal_value(const NODE *node, rb_iseq_t *iseq)
case NODE_STR:
if (ISEQ_COMPILE_DATA(iseq)->option->debug_frozen_string_literal || RTEST(ruby_debug)) {
VALUE lit = get_string_value(node);
- return rb_str_with_debug_created_info(lit, rb_iseq_path(iseq), (int)nd_line(node));
+ VALUE str = rb_str_with_debug_created_info(lit, rb_iseq_path(iseq), (int)nd_line(node));
+ RB_OBJ_SET_SHAREABLE(str);
+ return str;
}
else {
return get_string_value(node);
@@ -5141,7 +5260,7 @@ compile_array(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int pop
/* 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));
- OBJ_FREEZE(ary);
+ RB_OBJ_SET_FROZEN_SHAREABLE(ary);
/* Emit optimized code */
FLUSH_CHUNK;
@@ -5153,6 +5272,7 @@ compile_array(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int pop
ADD_INSN1(ret, line_node, putobject, ary);
ADD_INSN(ret, line_node, concattoarray);
}
+ RB_OBJ_SET_SHAREABLE(ary);
RB_OBJ_WRITTEN(iseq, Qundef, ary);
}
}
@@ -5279,13 +5399,15 @@ compile_hash(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int meth
for (; count; count--, node = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next) {
VALUE elem[2];
elem[0] = static_literal_value(RNODE_LIST(node)->nd_head, iseq);
+ if (!RB_SPECIAL_CONST_P(elem[0])) RB_OBJ_SET_FROZEN_SHAREABLE(elem[0]);
elem[1] = static_literal_value(RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_head, iseq);
+ if (!RB_SPECIAL_CONST_P(elem[1])) RB_OBJ_SET_FROZEN_SHAREABLE(elem[1]);
rb_ary_cat(ary, elem, 2);
}
- VALUE hash = rb_hash_new_with_size(RARRAY_LEN(ary) / 2);
+ VALUE hash = rb_hash_alloc_fixed_size(Qfalse, RARRAY_LEN(ary) / 2);
rb_hash_bulk_insert(RARRAY_LEN(ary), RARRAY_CONST_PTR(ary), hash);
- hash = rb_obj_hide(hash);
- OBJ_FREEZE(hash);
+ RB_GC_GUARD(ary);
+ hash = RB_OBJ_SET_FROZEN_SHAREABLE(hash);
/* Emit optimized code */
FLUSH_CHUNK();
@@ -5434,8 +5556,8 @@ when_vals(rb_iseq_t *iseq, LINK_ANCHOR *const cond_seq, const NODE *vals,
if (UNDEF_P(lit)) {
only_special_literals = 0;
}
- else if (NIL_P(rb_hash_lookup(literals, lit))) {
- rb_hash_aset(literals, lit, (VALUE)(l1) | 1);
+ else {
+ cdhash_aset_if_missing(literals, lit, (VALUE)(l1));
}
if (nd_type_p(val, NODE_STR) || nd_type_p(val, NODE_FILE)) {
@@ -5952,10 +6074,12 @@ collect_const_segments(rb_iseq_t *iseq, const NODE *node)
switch (nd_type(node)) {
case NODE_CONST:
rb_ary_unshift(arr, ID2SYM(RNODE_CONST(node)->nd_vid));
+ RB_OBJ_SET_SHAREABLE(arr);
return arr;
case NODE_COLON3:
rb_ary_unshift(arr, ID2SYM(RNODE_COLON3(node)->nd_mid));
rb_ary_unshift(arr, ID2SYM(idNULL));
+ RB_OBJ_SET_SHAREABLE(arr);
return arr;
case NODE_COLON2:
rb_ary_unshift(arr, ID2SYM(RNODE_COLON2(node)->nd_mid));
@@ -5998,6 +6122,23 @@ compile_const_prefix(rb_iseq_t *iseq, const NODE *const node,
}
static int
+cpath_const_p(const NODE *node)
+{
+ switch (nd_type(node)) {
+ case NODE_CONST:
+ case NODE_COLON3:
+ return TRUE;
+ case NODE_COLON2:
+ if (RNODE_COLON2(node)->nd_head) {
+ return cpath_const_p(RNODE_COLON2(node)->nd_head);
+ }
+ return TRUE;
+ default:
+ return FALSE;
+ }
+}
+
+static int
compile_cpath(LINK_ANCHOR *const ret, rb_iseq_t *iseq, const NODE *cpath)
{
if (nd_type_p(cpath, NODE_COLON3)) {
@@ -6006,9 +6147,13 @@ compile_cpath(LINK_ANCHOR *const ret, rb_iseq_t *iseq, const NODE *cpath)
return VM_DEFINECLASS_FLAG_SCOPED;
}
else if (nd_type_p(cpath, NODE_COLON2) && RNODE_COLON2(cpath)->nd_head) {
- /* Bar::Foo */
+ /* Bar::Foo or expr::Foo */
NO_CHECK(COMPILE(ret, "nd_else->nd_head", RNODE_COLON2(cpath)->nd_head));
- return VM_DEFINECLASS_FLAG_SCOPED;
+ int flags = VM_DEFINECLASS_FLAG_SCOPED;
+ if (!cpath_const_p(RNODE_COLON2(cpath)->nd_head)) {
+ flags |= VM_DEFINECLASS_FLAG_DYNAMIC_CREF;
+ }
+ return flags;
}
else {
/* class at cbase Foo */
@@ -6365,7 +6510,7 @@ add_ensure_range(rb_iseq_t *iseq, struct ensure_range *erange,
LABEL *lstart, LABEL *lend)
{
struct ensure_range *ne =
- compile_data_alloc(iseq, sizeof(struct ensure_range));
+ compile_data_alloc_type(iseq, struct ensure_range);
while (erange->next != 0) {
erange = erange->next;
@@ -6954,7 +7099,7 @@ compile_case(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_nod
DECL_ANCHOR(body_seq);
DECL_ANCHOR(cond_seq);
int only_special_literals = 1;
- VALUE literals = rb_hash_new();
+ VALUE literals = cdhash_new(0);
int line;
enum node_type type;
const NODE *line_node;
@@ -6965,8 +7110,6 @@ compile_case(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_nod
INIT_ANCHOR(body_seq);
INIT_ANCHOR(cond_seq);
- RHASH_TBL_RAW(literals)->type = &cdhash_type;
-
CHECK(COMPILE(head, "case base", RNODE_CASE(node)->nd_head));
branches = decl_branch_base(iseq, PTR2NUM(node), nd_code_loc(node), "case");
@@ -7587,6 +7730,7 @@ iseq_compile_pattern_each(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *c
ADD_INSN(ret, line_node, putnil);
}
else {
+ RB_OBJ_SET_FROZEN_SHAREABLE(keys);
ADD_INSN1(ret, line_node, duparray, keys);
RB_OBJ_WRITTEN(iseq, Qundef, rb_obj_hide(keys));
}
@@ -7624,7 +7768,8 @@ iseq_compile_pattern_each(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *c
ADD_INSN(ret, line_node, dup);
ADD_INSNL(ret, line_node, branchif, match_succeeded);
- ADD_INSN1(ret, line_node, putobject, rb_str_freeze(rb_sprintf("key not found: %+"PRIsVALUE, key))); // (4)
+ VALUE str = rb_str_freeze(rb_sprintf("key not found: %+"PRIsVALUE, key));
+ ADD_INSN1(ret, line_node, putobject, RB_OBJ_SET_SHAREABLE(str)); // (4)
ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 2 /* (3), (4) */));
ADD_INSN1(ret, line_node, putobject, Qtrue); // (5)
ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 3 /* (3), (4), (5) */));
@@ -8965,25 +9110,6 @@ compile_call_precheck_freeze(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE
}
return TRUE;
}
- /* 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)) &&
- ISEQ_COMPILE_DATA(iseq)->current_block == NULL &&
- !frozen_string_literal_p(iseq) &&
- 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)));
- ADD_INSN2(ret, line_node, opt_aref_with, str,
- new_callinfo(iseq, idAREF, 1, 0, NULL, FALSE));
- RB_OBJ_WRITTEN(iseq, Qundef, str);
- if (popped) {
- ADD_INSN(ret, line_node, pop);
- }
- return TRUE;
- }
return FALSE;
}
@@ -9141,6 +9267,9 @@ compile_builtin_attr(rb_iseq_t *iseq, const NODE *node)
// Let the iseq act like a C method in backtraces
ISEQ_BODY(iseq)->builtin_attrs |= BUILTIN_ATTR_C_TRACE;
}
+ else if (strcmp(RSTRING_PTR(string), "without_interrupts") == 0) {
+ ISEQ_BODY(iseq)->builtin_attrs |= BUILTIN_ATTR_WITHOUT_INTERRUPTS;
+ }
else {
goto unknown_arg;
}
@@ -9242,6 +9371,7 @@ compile_builtin_mandatory_only_method(rb_iseq_t *iseq, const NODE *node, const N
rb_node_init(RNODE(&scope_node), NODE_SCOPE);
scope_node.nd_tbl = tbl;
scope_node.nd_body = mandatory_node(iseq, node);
+ scope_node.nd_parent = NULL;
scope_node.nd_args = &args_node;
VALUE ast_value = rb_ruby_ast_new(RNODE(&scope_node));
@@ -10111,9 +10241,13 @@ 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_INSN2(val, node, getspecial, INT2FIX(0),
- INT2FIX(0));
+ {
+ VALUE re = rb_node_regx_string_val(node);
+ RB_OBJ_SET_FROZEN_SHAREABLE(re);
+ ADD_INSN1(recv, node, putobject, re);
+ ADD_INSN2(val, node, getspecial, INT2FIX(0),
+ INT2FIX(0));
+ }
break;
case NODE_MATCH2:
CHECK(COMPILE(recv, "receiver", RNODE_MATCH2(node)->nd_recv));
@@ -10190,6 +10324,7 @@ compile_colon3(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node,
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));
+ RB_OBJ_SET_FROZEN_SHAREABLE(segments);
ADD_INSN1(ret, node, opt_getconstant_path, segments);
RB_OBJ_WRITTEN(iseq, Qundef, segments);
}
@@ -10217,6 +10352,7 @@ compile_dots(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, in
VALUE bv = optimized_range_item(b);
VALUE ev = optimized_range_item(e);
VALUE val = rb_range_new(bv, ev, excl);
+ rb_ractor_make_shareable(rb_obj_freeze(val));
ADD_INSN1(ret, node, putobject, val);
RB_OBJ_WRITTEN(iseq, Qundef, val);
}
@@ -10311,31 +10447,6 @@ compile_attrasgn(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node
LABEL *else_label = NULL;
VALUE branches = Qfalse;
- /* optimization shortcut
- * obj["literal"] = value -> opt_aset_with(obj, "literal", value)
- */
- if (!ISEQ_COMPILE_DATA(iseq)->in_masgn &&
- 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)) &&
- ISEQ_COMPILE_DATA(iseq)->current_block == NULL &&
- !frozen_string_literal_p(iseq) &&
- 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));
- if (!popped) {
- ADD_INSN(ret, node, swap);
- ADD_INSN1(ret, node, topn, INT2FIX(1));
- }
- ADD_INSN2(ret, node, opt_aset_with, str,
- new_callinfo(iseq, idASET, 2, 0, NULL, FALSE));
- RB_OBJ_WRITTEN(iseq, Qundef, str);
- ADD_INSN(ret, node, pop);
- return COMPILE_OK;
- }
-
INIT_ANCHOR(recv);
INIT_ANCHOR(args);
argc = setup_args(iseq, args, RNODE_ATTRASGN(node)->nd_args, &flag, NULL);
@@ -10678,8 +10789,10 @@ compile_shareable_literal_constant(rb_iseq_t *iseq, LINK_ANCHOR *ret, enum rb_pa
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));
+ long len = RNODE_LIST(RNODE_HASH(node)->nd_head)->as.nd_alen;
+ RBIMPL_ASSERT_OR_ASSUME(len >= 0);
+ RBIMPL_ASSERT_OR_ASSUME(RB_POSFIXABLE(len));
+ ADD_INSN1(anchor, node, newhash, LONG2FIX(len));
}
*value_p = Qundef;
*shareable_literal_p = 0;
@@ -10693,8 +10806,10 @@ compile_shareable_literal_constant(rb_iseq_t *iseq, LINK_ANCHOR *ret, enum rb_pa
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));
+ long len = RNODE_LIST(RNODE_HASH(node)->nd_head)->as.nd_alen;
+ RBIMPL_ASSERT_OR_ASSUME(len >= 0);
+ RBIMPL_ASSERT_OR_ASSUME(RB_POSFIXABLE(len));
+ ADD_INSN1(anchor, node, newhash, LONG2FIX(len));
}
CHECK(compile_make_shareable_node(iseq, ret, anchor, node, false));
*value_p = Qundef;
@@ -10868,10 +10983,7 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const no
}
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;
}
@@ -11053,6 +11165,7 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const no
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));
+ RB_OBJ_SET_FROZEN_SHAREABLE(segments);
ADD_INSN1(ret, node, opt_getconstant_path, segments);
RB_OBJ_WRITTEN(iseq, Qundef, segments);
}
@@ -11118,6 +11231,7 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const no
}
case NODE_INTEGER:{
VALUE lit = rb_node_integer_literal_val(node);
+ if (!SPECIAL_CONST_P(lit)) RB_OBJ_SET_SHAREABLE(lit);
debugp_param("integer", lit);
if (!popped) {
ADD_INSN1(ret, node, putobject, lit);
@@ -11127,6 +11241,7 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const no
}
case NODE_FLOAT:{
VALUE lit = rb_node_float_literal_val(node);
+ if (!SPECIAL_CONST_P(lit)) RB_OBJ_SET_SHAREABLE(lit);
debugp_param("float", lit);
if (!popped) {
ADD_INSN1(ret, node, putobject, lit);
@@ -11136,6 +11251,7 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const no
}
case NODE_RATIONAL:{
VALUE lit = rb_node_rational_literal_val(node);
+ rb_ractor_make_shareable(lit);
debugp_param("rational", lit);
if (!popped) {
ADD_INSN1(ret, node, putobject, lit);
@@ -11145,6 +11261,7 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const no
}
case NODE_IMAGINARY:{
VALUE lit = rb_node_imaginary_literal_val(node);
+ rb_ractor_make_shareable(lit);
debugp_param("imaginary", lit);
if (!popped) {
ADD_INSN1(ret, node, putobject, lit);
@@ -11161,13 +11278,14 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const no
if ((option->debug_frozen_string_literal || RTEST(ruby_debug)) &&
option->frozen_string_literal != ISEQ_FROZEN_STRING_LITERAL_DISABLED) {
lit = rb_str_with_debug_created_info(lit, rb_iseq_path(iseq), line);
+ RB_OBJ_SET_SHAREABLE(lit);
}
switch (option->frozen_string_literal) {
case ISEQ_FROZEN_STRING_LITERAL_UNSET:
- ADD_INSN1(ret, node, putchilledstring, lit);
+ ADD_INSN1(ret, node, dupchilledstring, lit);
break;
case ISEQ_FROZEN_STRING_LITERAL_DISABLED:
- ADD_INSN1(ret, node, putstring, lit);
+ ADD_INSN1(ret, node, dupstring, lit);
break;
case ISEQ_FROZEN_STRING_LITERAL_ENABLED:
ADD_INSN1(ret, node, putobject, lit);
@@ -11215,6 +11333,7 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const no
case NODE_REGX:{
if (!popped) {
VALUE lit = rb_node_regx_string_val(node);
+ RB_OBJ_SET_SHAREABLE(lit);
ADD_INSN1(ret, node, putobject, lit);
RB_OBJ_WRITTEN(iseq, Qundef, lit);
}
@@ -11407,9 +11526,20 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const no
CHECK(COMPILE(ret, "sclass#recv", RNODE_SCLASS(node)->nd_recv));
ADD_INSN (ret, node, putnil);
CONST_ID(singletonclass, "singletonclass");
+
+ /* `class << self` in a class body and `class << Foo` (constant
+ receiver) are stable. All other forms are potentially dynamic. */
+ int sclass_flags = VM_DEFINECLASS_TYPE_SINGLETON_CLASS;
+ const NODE *recv = RNODE_SCLASS(node)->nd_recv;
+ if (!(nd_type_p(recv, NODE_SELF) &&
+ ISEQ_BODY(iseq)->type == ISEQ_TYPE_CLASS) &&
+ !cpath_const_p(recv)) {
+ sclass_flags |= VM_DEFINECLASS_FLAG_DYNAMIC_CREF;
+ }
+
ADD_INSN3(ret, node, defineclass,
ID2SYM(singletonclass), singleton_class,
- INT2FIX(VM_DEFINECLASS_TYPE_SINGLETON_CLASS));
+ INT2FIX(sclass_flags));
RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)singleton_class);
if (popped) {
@@ -11632,7 +11762,7 @@ insn_data_to_s_detail(INSN *iobj)
{
const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(iobj, j);
rb_str_cat2(str, "<calldata:");
- if (vm_ci_mid(ci)) rb_str_catf(str, "%"PRIsVALUE, rb_id2str(vm_ci_mid(ci)));
+ if (vm_ci_mid(ci)) rb_str_append(str, rb_id2str(vm_ci_mid(ci)));
rb_str_catf(str, ", %d>", vm_ci_argc(ci));
break;
}
@@ -11986,7 +12116,7 @@ iseq_build_from_ary_body(rb_iseq_t *iseq, LINK_ANCHOR *const anchor,
}
if (argc > 0) {
- argv = compile_data_calloc2(iseq, sizeof(VALUE), argc);
+ argv = compile_data_calloc2_type(iseq, VALUE, argc);
// add element before operand setup to make GC root
ADD_ELEM(anchor,
@@ -12066,18 +12196,18 @@ iseq_build_from_ary_body(rb_iseq_t *iseq, LINK_ANCHOR *const anchor,
case TS_CDHASH:
{
int i;
- VALUE map = rb_hash_new_with_size(RARRAY_LEN(op)/2);
+ VALUE map = cdhash_new(RARRAY_LEN(op) / 2);
- RHASH_TBL_RAW(map)->type = &cdhash_type;
op = rb_to_array_type(op);
for (i=0; i<RARRAY_LEN(op); i+=2) {
VALUE key = RARRAY_AREF(op, i);
VALUE sym = RARRAY_AREF(op, i+1);
LABEL *label =
register_label(iseq, labels_table, sym);
- rb_hash_aset(map, key, (VALUE)label | 1);
+ cdhash_aset(map, key, (VALUE)label);
}
RB_GC_GUARD(op);
+ RB_OBJ_SET_SHAREABLE(map); // allow mutation while compiling
argv[j] = map;
RB_OBJ_WRITTEN(iseq, Qundef, map);
}
@@ -12212,23 +12342,18 @@ rb_iseq_mark_and_move_insn_storage(struct iseq_compile_data_storage *storage)
{
INSN *iobj = 0;
size_t size = sizeof(INSN);
+ size_t align = ALIGNMENT_SIZE_OF(INSN);
unsigned int pos = 0;
while (storage) {
-#ifdef STRICT_ALIGNMENT
- size_t padding = calc_padding((void *)&storage->buff[pos], size);
-#else
- const size_t padding = 0; /* expected to be optimized by compiler */
-#endif /* STRICT_ALIGNMENT */
+ size_t padding = calc_padding((void *)&storage->buff[pos], align);
size_t offset = pos + size + padding;
if (offset > storage->size || offset > storage->pos) {
pos = 0;
storage = storage->next;
}
else {
-#ifdef STRICT_ALIGNMENT
pos += (int)padding;
-#endif /* STRICT_ALIGNMENT */
iobj = (INSN *)&storage->buff[pos];
@@ -12424,7 +12549,7 @@ typedef uint32_t ibf_offset_t;
#define IBF_MAJOR_VERSION ISEQ_MAJOR_VERSION
#ifdef RUBY_DEVEL
-#define IBF_DEVEL_VERSION 4
+#define IBF_DEVEL_VERSION 5
#define IBF_MINOR_VERSION (ISEQ_MINOR_VERSION * 10000 + IBF_DEVEL_VERSION)
#else
#define IBF_MINOR_VERSION ISEQ_MINOR_VERSION
@@ -12827,7 +12952,8 @@ ibf_load_builtin(const struct ibf_load *load, ibf_offset_t *offset)
const struct rb_builtin_function *table = GET_VM()->builtin_function_table;
if (table == NULL) rb_raise(rb_eArgError, "builtin function table is not provided");
if (strncmp(table[i].name, name, len) != 0) {
- rb_raise(rb_eArgError, "builtin function index (%d) mismatch (expect %s but %s)", i, name, table[i].name);
+ rb_raise(rb_eArgError, "builtin function index (%d) mismatch (expect %.*s but %s)",
+ i, len, name, table[i].name);
}
// fprintf(stderr, "load-builtin: name:%s(%d)\n", table[i].name, table[i].argc);
@@ -12913,21 +13039,23 @@ ibf_load_code(const struct ibf_load *load, rb_iseq_t *iseq, ibf_offset_t bytecod
VALUE iseqv = (VALUE)iseq;
unsigned int code_index;
ibf_offset_t reading_pos = bytecode_offset;
- VALUE *code = ALLOC_N(VALUE, iseq_size);
+ VALUE *code = ZALLOC_N(VALUE, iseq_size);
struct rb_iseq_constant_body *load_body = ISEQ_BODY(iseq);
struct rb_call_data *cd_entries = load_body->call_data;
int ic_index = 0;
- iseq_bits_t * mark_offset_bits;
-
- iseq_bits_t tmp[1] = {0};
+ load_body->iseq_encoded = code;
+ load_body->iseq_size = iseq_size;
+ iseq_bits_t * mark_offset_bits;
if (ISEQ_MBITS_BUFLEN(iseq_size) == 1) {
- mark_offset_bits = tmp;
+ load_body->mark_bits.single = 0;
+ mark_offset_bits = &load_body->mark_bits.single;
}
else {
- mark_offset_bits = ZALLOC_N(iseq_bits_t, ISEQ_MBITS_BUFLEN(iseq_size));
+ load_body->mark_bits.list = ZALLOC_N(iseq_bits_t, ISEQ_MBITS_BUFLEN(iseq_size));
+ mark_offset_bits = load_body->mark_bits.list;
}
bool needs_bitmap = false;
@@ -12959,10 +13087,6 @@ ibf_load_code(const struct ibf_load *load, rb_iseq_t *iseq, ibf_offset_t bytecod
{
VALUE op = ibf_load_small_value(load, &reading_pos);
VALUE v = ibf_load_object(load, op);
- v = rb_hash_dup(v); // hash dumped as frozen
- RHASH_TBL_RAW(v)->type = &cdhash_type;
- rb_hash_rehash(v); // hash function changed
- freeze_hide_obj(v);
// Overwrite the existing hash in the object list. This
// is to keep the object alive during load time.
@@ -13013,12 +13137,12 @@ ibf_load_code(const struct ibf_load *load, rb_iseq_t *iseq, ibf_offset_t bytecod
if (insn == BIN(setinstancevariable)) {
ID iv_name = (ID)code[code_index - 1];
cache->iv_set_name = iv_name;
+ cache->value = IVAR_CACHE_INIT;
}
else {
cache->iv_set_name = 0;
+ cache->value = rb_getivar_cache_pack(ROOT_SHAPE_ID, ATTR_INDEX_NOT_SET);
}
-
- vm_ic_attr_index_initialize(cache, INVALID_SHAPE_ID);
}
}
@@ -13050,20 +13174,9 @@ ibf_load_code(const struct ibf_load *load, rb_iseq_t *iseq, ibf_offset_t bytecod
}
}
- load_body->iseq_encoded = code;
- load_body->iseq_size = code_index;
-
- if (ISEQ_MBITS_BUFLEN(load_body->iseq_size) == 1) {
- load_body->mark_bits.single = mark_offset_bits[0];
- }
- else {
- if (needs_bitmap) {
- load_body->mark_bits.list = mark_offset_bits;
- }
- else {
- load_body->mark_bits.list = 0;
- ruby_xfree(mark_offset_bits);
- }
+ if (!needs_bitmap) {
+ SIZED_FREE_N(load_body->mark_bits.list, ISEQ_MBITS_BUFLEN(iseq_size));
+ load_body->mark_bits.list = NULL;
}
RUBY_ASSERT(code_index == iseq_size);
@@ -13235,7 +13348,7 @@ ibf_dump_local_table(struct ibf_dump *dump, const rb_iseq_t *iseq)
return ibf_dump_write(dump, table, sizeof(ID) * size);
}
-static ID *
+static const ID *
ibf_load_local_table(const struct ibf_load *load, ibf_offset_t local_table_offset, int size)
{
if (size > 0) {
@@ -13245,7 +13358,14 @@ ibf_load_local_table(const struct ibf_load *load, ibf_offset_t local_table_offse
for (i=0; i<size; i++) {
table[i] = ibf_load_id(load, table[i]);
}
- return table;
+
+ if (size == 1 && table[0] == idERROR_INFO) {
+ ruby_xfree_sized(table, sizeof(ID) * size);
+ return rb_iseq_shared_exc_local_tbl;
+ }
+ else {
+ return table;
+ }
}
else {
return NULL;
@@ -13253,6 +13373,28 @@ ibf_load_local_table(const struct ibf_load *load, ibf_offset_t local_table_offse
}
static ibf_offset_t
+ibf_dump_lvar_states(struct ibf_dump *dump, const rb_iseq_t *iseq)
+{
+ const struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
+ const int size = body->local_table_size;
+ IBF_W_ALIGN(enum lvar_state);
+ return ibf_dump_write(dump, body->lvar_states, sizeof(enum lvar_state) * (body->lvar_states ? size : 0));
+}
+
+static enum lvar_state *
+ibf_load_lvar_states(const struct ibf_load *load, ibf_offset_t lvar_states_offset, int size, const ID *local_table)
+{
+ if (local_table == rb_iseq_shared_exc_local_tbl ||
+ size <= 0) {
+ return NULL;
+ }
+ else {
+ enum lvar_state *states = IBF_R(lvar_states_offset, enum lvar_state, size);
+ return states;
+ }
+}
+
+static ibf_offset_t
ibf_dump_catch_table(struct ibf_dump *dump, const rb_iseq_t *iseq)
{
const struct iseq_catch_table *table = ISEQ_BODY(iseq)->catch_table;
@@ -13522,9 +13664,10 @@ ibf_dump_iseq_each(struct ibf_dump *dump, const rb_iseq_t *iseq)
positions = rb_iseq_insns_info_decode_positions(ISEQ_BODY(iseq));
const ibf_offset_t insns_info_positions_offset = ibf_dump_insns_info_positions(dump, positions, body->insns_info.size);
- ruby_xfree(positions);
+ SIZED_FREE_N(positions, ISEQ_BODY(iseq)->insns_info.size);
const ibf_offset_t local_table_offset = ibf_dump_local_table(dump, iseq);
+ const ibf_offset_t lvar_states_offset = ibf_dump_lvar_states(dump, iseq);
const unsigned int catch_table_size = body->catch_table ? body->catch_table->size : 0;
const ibf_offset_t catch_table_offset = ibf_dump_catch_table(dump, iseq);
const int parent_iseq_index = ibf_dump_iseq(dump, ISEQ_BODY(iseq)->parent_iseq);
@@ -13557,7 +13700,8 @@ ibf_dump_iseq_each(struct ibf_dump *dump, const rb_iseq_t *iseq)
(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.forwardable << 13) |
+ (body->param.flags.accepts_no_block << 14);
#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
# define IBF_BODY_OFFSET(x) (x)
@@ -13592,6 +13736,7 @@ ibf_dump_iseq_each(struct ibf_dump *dump, const rb_iseq_t *iseq)
ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(insns_info_positions_offset));
ibf_dump_write_small_value(dump, body->insns_info.size);
ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(local_table_offset));
+ ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(lvar_states_offset));
ibf_dump_write_small_value(dump, catch_table_size);
ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(catch_table_offset));
ibf_dump_write_small_value(dump, parent_iseq_index);
@@ -13703,6 +13848,7 @@ ibf_load_iseq_each(struct ibf_load *load, rb_iseq_t *iseq, ibf_offset_t offset)
const ibf_offset_t insns_info_positions_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
const unsigned int insns_info_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
const ibf_offset_t local_table_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
+ const ibf_offset_t lvar_states_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
const unsigned int catch_table_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
const ibf_offset_t catch_table_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
const int parent_iseq_index = (int)ibf_load_small_value(load, &reading_pos);
@@ -13775,6 +13921,7 @@ ibf_load_iseq_each(struct ibf_load *load, rb_iseq_t *iseq, ibf_offset_t offset)
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.flags.accepts_no_block = (param_flags >> 14) & 1;
load_body->param.size = param_size;
load_body->param.lead_num = param_lead_num;
load_body->param.opt_num = param_opt_num;
@@ -13819,6 +13966,7 @@ ibf_load_iseq_each(struct ibf_load *load, rb_iseq_t *iseq, ibf_offset_t offset)
load_body->insns_info.body = ibf_load_insns_info_body(load, insns_info_body_offset, insns_info_size);
load_body->insns_info.positions = ibf_load_insns_info_positions(load, insns_info_positions_offset, insns_info_size);
load_body->local_table = ibf_load_local_table(load, local_table_offset, local_table_size);
+ load_body->lvar_states = ibf_load_lvar_states(load, lvar_states_offset, local_table_size, load_body->local_table);
ibf_load_catch_table(load, catch_table_offset, catch_table_size, iseq);
const rb_iseq_t *parent_iseq = ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)parent_iseq_index);
@@ -13901,8 +14049,6 @@ ibf_dump_iseq_list(struct ibf_dump *dump, struct ibf_header *header)
header->iseq_list_size = (unsigned int)size;
}
-#define IBF_OBJECT_INTERNAL FL_PROMOTED0
-
/*
* Binary format
* - ibf_object_header
@@ -13962,7 +14108,11 @@ struct ibf_object_symbol {
#define IBF_ALIGNED_OFFSET(align, offset) /* offset > 0 */ \
((((offset) - 1) / (align) + 1) * (align))
-#define IBF_OBJBODY(type, offset) (const type *)\
+/* No cast, since it's UB to create an unaligned pointer.
+ * Leave as void* for use with memcpy in those cases.
+ * We align the offset, but the buffer pointer is only VALUE aligned,
+ * so the returned pointer may be unaligned for `type` .*/
+#define IBF_OBJBODY(type, offset) \
ibf_load_check_offset(load, IBF_ALIGNED_OFFSET(RUBY_ALIGNOF(type), offset))
static const void *
@@ -14057,8 +14207,12 @@ ibf_dump_object_float(struct ibf_dump *dump, VALUE obj)
static VALUE
ibf_load_object_float(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
{
- const double *dblp = IBF_OBJBODY(double, offset);
- return DBL2NUM(*dblp);
+ double d;
+ /* Avoid unaligned VFP load on ARMv7; IBF payload may be unaligned (C99 6.3.2.3 p7). */
+ memcpy(&d, IBF_OBJBODY(double, offset), sizeof(d));
+ VALUE f = DBL2NUM(d);
+ if (!FLONUM_P(f)) RB_OBJ_SET_SHAREABLE(f);
+ return f;
}
static void
@@ -14129,7 +14283,7 @@ ibf_load_object_regexp(const struct ibf_load *load, const struct ibf_object_head
VALUE reg = rb_reg_compile(srcstr, (int)regexp.option, NULL, 0);
if (header->internal) rb_obj_hide(reg);
- if (header->frozen) rb_obj_freeze(reg);
+ if (header->frozen) RB_OBJ_SET_SHAREABLE(rb_obj_freeze(reg));
return reg;
}
@@ -14160,7 +14314,10 @@ 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_ary_freeze(ary);
+ rb_ractor_make_shareable(ary); // TODO: check elements
+ }
return ary;
}
@@ -14191,7 +14348,7 @@ static VALUE
ibf_load_object_hash(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
{
long len = (long)ibf_load_small_value(load, &offset);
- VALUE obj = rb_hash_new_with_size(len);
+ VALUE obj = header->frozen ? rb_hash_alloc_fixed_size(rb_cHash, len) : rb_hash_new_with_size(len);
int i;
for (i = 0; i < len; i++) {
@@ -14202,10 +14359,59 @@ ibf_load_object_hash(const struct ibf_load *load, const struct ibf_object_header
VALUE val = ibf_load_object(load, val_index);
rb_hash_aset(obj, key, val);
}
- rb_hash_rehash(obj);
if (header->internal) rb_obj_hide(obj);
- if (header->frozen) rb_obj_freeze(obj);
+ if (header->frozen) {
+ RB_OBJ_SET_FROZEN_SHAREABLE(obj);
+ }
+
+ return obj;
+}
+
+static int
+ibf_dump_cdhash_i(st_data_t key, st_data_t val, st_data_t ptr)
+{
+ struct ibf_dump *dump = (struct ibf_dump *)ptr;
+
+ VALUE key_index = ibf_dump_object(dump, (VALUE)key);
+
+ ibf_dump_write_small_value(dump, key_index);
+ ibf_dump_write_small_value(dump, val);
+ return ST_CONTINUE;
+}
+
+static void
+ibf_dump_object_imemo(struct ibf_dump *dump, VALUE obj)
+{
+ switch (imemo_type(obj)) {
+ case imemo_cdhash: {
+ st_table *tbl = rb_imemo_cdhash_tbl(obj);
+
+ long len = tbl->num_entries;
+ ibf_dump_write_small_value(dump, (VALUE)len);
+ if (len > 0) st_foreach(tbl, ibf_dump_cdhash_i, (VALUE)dump);
+ break;
+ }
+ default:
+ ibf_dump_object_unsupported(dump, obj);
+ break;
+ }
+}
+
+static VALUE
+ibf_load_object_imemo(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
+{
+ long len = (long)ibf_load_small_value(load, &offset);
+ VALUE obj = cdhash_new(len);
+
+ int i;
+ for (i = 0; i < len; i++) {
+ VALUE key_index = ibf_load_small_value(load, &offset);
+ VALUE val = ibf_load_small_value(load, &offset);
+
+ VALUE key = ibf_load_object(load, key_index);
+ cdhash_aset(obj, key, val);
+ }
return obj;
}
@@ -14241,7 +14447,7 @@ ibf_load_object_struct(const struct ibf_load *load, const struct ibf_object_head
VALUE end = ibf_load_object(load, range->end);
VALUE obj = rb_range_new(beg, end, range->excl);
if (header->internal) rb_obj_hide(obj);
- if (header->frozen) rb_obj_freeze(obj);
+ if (header->frozen) RB_OBJ_SET_FROZEN_SHAREABLE(obj);
return obj;
}
@@ -14269,7 +14475,7 @@ ibf_load_object_bignum(const struct ibf_load *load, const struct ibf_object_head
big_unpack_flags |
(sign == 0 ? INTEGER_PACK_NEGATIVE : 0));
if (header->internal) rb_obj_hide(obj);
- if (header->frozen) rb_obj_freeze(obj);
+ if (header->frozen) RB_OBJ_SET_FROZEN_SHAREABLE(obj);
return obj;
}
@@ -14330,7 +14536,7 @@ ibf_load_object_complex_rational(const struct ibf_load *load, const struct ibf_o
rb_complex_new(a, b) : rb_rational_new(a, b);
if (header->internal) rb_obj_hide(obj);
- if (header->frozen) rb_obj_freeze(obj);
+ if (header->frozen) rb_ractor_make_shareable(rb_obj_freeze(obj));
return obj;
}
@@ -14386,7 +14592,7 @@ static const ibf_dump_object_function dump_object_functions[RUBY_T_MASK+1] = {
ibf_dump_object_unsupported, /* 0x17 */
ibf_dump_object_unsupported, /* 0x18 */
ibf_dump_object_unsupported, /* 0x19 */
- ibf_dump_object_unsupported, /* T_IMEMO 0x1a */
+ ibf_dump_object_imemo, /* T_IMEMO 0x1a */
ibf_dump_object_unsupported, /* T_NODE 0x1b */
ibf_dump_object_unsupported, /* T_ICLASS 0x1c */
ibf_dump_object_unsupported, /* T_ZOMBIE 0x1d */
@@ -14479,7 +14685,7 @@ static const ibf_load_object_function load_object_functions[RUBY_T_MASK+1] = {
ibf_load_object_unsupported, /* 0x17 */
ibf_load_object_unsupported, /* 0x18 */
ibf_load_object_unsupported, /* 0x19 */
- ibf_load_object_unsupported, /* T_IMEMO 0x1a */
+ ibf_load_object_imemo, /* T_IMEMO 0x1a */
ibf_load_object_unsupported, /* T_NODE 0x1b */
ibf_load_object_unsupported, /* T_ICLASS 0x1c */
ibf_load_object_unsupported, /* T_ZOMBIE 0x1d */
@@ -14835,7 +15041,7 @@ static void
ibf_loader_free(void *ptr)
{
struct ibf_load *load = (struct ibf_load *)ptr;
- ruby_xfree(load);
+ SIZED_FREE(load);
}
static size_t
diff --git a/complex.c b/complex.c
index d6daee307c..8c661f2019 100644
--- a/complex.c
+++ b/complex.c
@@ -20,6 +20,7 @@
#include "internal/array.h"
#include "internal/class.h"
#include "internal/complex.h"
+#include "internal/error.h"
#include "internal/math.h"
#include "internal/numeric.h"
#include "internal/object.h"
@@ -51,20 +52,6 @@ static ID id_abs, id_arg,
#define id_quo idQuo
#define id_fdiv idFdiv
-#define fun1(n) \
-inline static VALUE \
-f_##n(VALUE x)\
-{\
- return rb_funcall(x, id_##n, 0);\
-}
-
-#define fun2(n) \
-inline static VALUE \
-f_##n(VALUE x, VALUE y)\
-{\
- return rb_funcall(x, id_##n, 1, y);\
-}
-
#define PRESERVE_SIGNEDZERO
inline static VALUE
@@ -275,8 +262,6 @@ f_to_f(VALUE x)
return rb_funcall(x, id_to_f, 0);
}
-fun1(to_r)
-
inline static int
f_eqeq_p(VALUE x, VALUE y)
{
@@ -287,8 +272,18 @@ f_eqeq_p(VALUE x, VALUE y)
return (int)rb_equal(x, y);
}
-fun2(expt)
-fun2(fdiv)
+static VALUE
+f_fdiv(VALUE x, VALUE y)
+{
+ if (RB_INTEGER_TYPE_P(x))
+ return rb_int_fdiv(x, y);
+ if (RB_FLOAT_TYPE_P(x))
+ return rb_float_div(x, y);
+ if (RB_TYPE_P(x, T_RATIONAL))
+ return rb_rational_fdiv(x, y);
+
+ return rb_funcallv(x, id_fdiv, 1, &y);
+}
static VALUE
f_quo(VALUE x, VALUE y)
@@ -317,24 +312,6 @@ f_negative_p(VALUE x)
#define f_positive_p(x) (!f_negative_p(x))
-inline static bool
-f_zero_p(VALUE x)
-{
- if (RB_FLOAT_TYPE_P(x)) {
- return FLOAT_ZERO_P(x);
- }
- else if (RB_INTEGER_TYPE_P(x)) {
- return FIXNUM_ZERO_P(x);
- }
- else if (RB_TYPE_P(x, T_RATIONAL)) {
- const VALUE num = RRATIONAL(x)->num;
- return FIXNUM_ZERO_P(num);
- }
- return rb_equal(x, ZERO) != 0;
-}
-
-#define f_nonzero_p(x) (!f_zero_p(x))
-
static inline bool
always_finite_type_p(VALUE x)
{
@@ -392,8 +369,7 @@ 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, sizeof(struct RComplex));
RCOMPLEX_SET_REAL(obj, real);
RCOMPLEX_SET_IMAG(obj, imag);
@@ -799,9 +775,9 @@ rb_complex_imag(VALUE self)
/*
* call-seq:
- * -complex -> new_complex
+ * -self -> complex
*
- * Returns the negation of +self+, which is the negation of each of its parts:
+ * Returns +self+, negated, which is the negation of each of its parts:
*
* -Complex.rect(1, 2) # => (-1-2i)
* -Complex.rect(-1, -2) # => (1+2i)
@@ -816,17 +792,26 @@ rb_complex_uminus(VALUE self)
}
/*
- * call-seq:
- * complex + numeric -> new_complex
+ * call-seq:
+ * self + other -> numeric
+ *
+ * Returns the sum of +self+ and +other+:
*
- * Returns the sum of +self+ and +numeric+:
+ * Complex(1, 2) + 0 # => (1+2i)
+ * Complex(1, 2) + 1 # => (2+2i)
+ * Complex(1, 2) + -1 # => (0+2i)
*
- * 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)
+ * Complex(1, 2) + 1.0 # => (2.0+2i)
*
+ * Complex(1, 2) + Complex(2, 1) # => (3+3i)
+ * Complex(1, 2) + Complex(2.0, 1.0) # => (3.0+3.0i)
+ *
+ * Complex(1, 2) + Rational(1, 1) # => ((2/1)+2i)
+ * Complex(1, 2) + Rational(1, 2) # => ((3/2)+2i)
+ *
+ * For a computation involving Floats, the result may be inexact (see Float#+):
+ *
+ * Complex(1, 2) + 3.14 # => (4.140000000000001+2i)
*/
VALUE
rb_complex_plus(VALUE self, VALUE other)
@@ -852,9 +837,9 @@ rb_complex_plus(VALUE self, VALUE other)
/*
* call-seq:
- * complex - numeric -> new_complex
+ * self - other -> complex
*
- * Returns the difference of +self+ and +numeric+:
+ * Returns the difference of +self+ and +other+:
*
* Complex.rect(2, 3) - Complex.rect(2, 3) # => (0+0i)
* Complex.rect(900) - Complex.rect(1) # => (899+0i)
@@ -913,15 +898,16 @@ comp_mul(VALUE areal, VALUE aimag, VALUE breal, VALUE bimag, VALUE *real, VALUE
/*
* call-seq:
- * complex * numeric -> new_complex
+ * self * other -> numeric
*
- * Returns the product of +self+ and +numeric+:
+ * Returns the numeric product of +self+ and +other+:
*
+ * Complex.rect(9, 8) * 4 # => (36+32i)
+ * Complex.rect(20, 9) * 9.8 # => (196.0+88.2i)
* 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)
+ * Complex.rect(9, 8) * Rational(2, 3) # => ((6/1)+(16/3)*i)
*
*/
VALUE
@@ -989,9 +975,9 @@ f_divide(VALUE self, VALUE other,
/*
* call-seq:
- * complex / numeric -> new_complex
+ * self / other -> complex
*
- * Returns the quotient of +self+ and +numeric+:
+ * Returns the quotient of +self+ and +other+:
*
* Complex.rect(2, 3) / Complex.rect(2, 3) # => (1+0i)
* Complex.rect(900) / Complex.rect(1) # => (900+0i)
@@ -1112,9 +1098,9 @@ complex_pow_for_special_angle(VALUE self, VALUE other)
/*
* call-seq:
- * complex ** numeric -> new_complex
+ * self ** exponent -> complex
*
- * Returns +self+ raised to power +numeric+:
+ * Returns +self+ raised to the power +exponent+:
*
* Complex.rect(0, 1) ** 2 # => (-1+0i)
* Complex.rect(-8) ** Rational(1, 3) # => (1.0000000000000002+1.7320508075688772i)
@@ -1205,21 +1191,20 @@ rb_complex_pow(VALUE self, VALUE other)
if (RB_BIGNUM_TYPE_P(other))
rb_warn("in a**b, b may be too big");
- r = f_abs(self);
- theta = f_arg(self);
+ r = rb_num_pow(f_abs(self), other);
+ theta = f_mul(f_arg(self), other);
- return f_complex_polar(CLASS_OF(self), f_expt(r, other),
- f_mul(theta, other));
+ return f_complex_polar(CLASS_OF(self), r, theta);
}
return rb_num_coerce_bin(self, other, id_expt);
}
/*
* call-seq:
- * complex == object -> true or false
+ * self == other -> true or false
*
- * Returns +true+ if <tt>self.real == object.real</tt>
- * and <tt>self.imag == object.imag</tt>:
+ * Returns whether both <tt>self.real == other.real</tt>
+ * and <tt>self.imag == other.imag</tt>:
*
* Complex.rect(2, 3) == Complex.rect(2.0, 3.0) # => true
*
@@ -1250,14 +1235,16 @@ nucomp_real_p(VALUE self)
/*
* call-seq:
- * complex <=> object -> -1, 0, 1, or nil
+ * self <=> other -> -1, 0, 1, or nil
+ *
+ * Compares +self+ and +other+.
*
* Returns:
*
- * - <tt>self.real <=> object.real</tt> if both of the following are true:
+ * - <tt>self.real <=> other.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.
+ * - <tt>other.imag == 0</tt> (always true if +other+ is numeric but not complex).
*
* - +nil+ otherwise.
*
@@ -1270,6 +1257,8 @@ nucomp_real_p(VALUE self)
* Complex.rect(1) <=> Complex.rect(1, 1) # => nil # object.imag not zero.
* Complex.rect(1) <=> 'Foo' # => nil # object.imag not defined.
*
+ * \Class \Complex includes module Comparable,
+ * each of whose methods uses Complex#<=> for comparison.
*/
static VALUE
nucomp_cmp(VALUE self, VALUE other)
@@ -1765,12 +1754,6 @@ rb_complex_new_polar(VALUE x, VALUE y)
}
VALUE
-rb_complex_polar(VALUE x, VALUE y)
-{
- return rb_complex_new_polar(x, y);
-}
-
-VALUE
rb_Complex(VALUE x, VALUE y)
{
VALUE a[2];
@@ -1795,7 +1778,7 @@ rb_dbl_complex_new(double real, double imag)
* Complex.rect(1, Rational(0, 1)).to_i # => 1
*
* Raises RangeError if <tt>self.imag</tt> is not exactly zero
- * (either <tt>Integer(0)</tt> or <tt>Rational(0, _n_)</tt>).
+ * (either <tt>Integer(0)</tt> or <tt>Rational(0, n)</tt>).
*/
static VALUE
nucomp_to_i(VALUE self)
@@ -1819,7 +1802,7 @@ nucomp_to_i(VALUE self)
* 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>).
+ * (either <tt>Integer(0)</tt> or <tt>Rational(0, n)</tt>).
*/
static VALUE
nucomp_to_f(VALUE self)
@@ -1844,7 +1827,7 @@ nucomp_to_f(VALUE self)
* Complex.rect(1, 0.0).to_r # => (1/1)
*
* Raises RangeError if <tt>self.imag</tt> is not exactly zero
- * (either <tt>Integer(0)</tt> or <tt>Rational(0, _n_)</tt>)
+ * (either <tt>Integer(0)</tt> or <tt>Rational(0, n)</tt>)
* and <tt>self.imag.to_r</tt> is not exactly zero.
*
* Related: Complex#rationalize.
@@ -1864,7 +1847,7 @@ nucomp_to_r(VALUE self)
self);
}
}
- return f_to_r(dat->real);
+ return rb_funcallv(dat->real, id_to_r, 0, 0);
}
/*
@@ -2229,28 +2212,156 @@ 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)
+ * Returns a Complex object:
+ * parses the leading substring of +self+
+ * to extract two numeric values that become the coordinates of the complex object.
+ *
+ * The substring is interpreted as containing
+ * either rectangular coordinates (real and imaginary parts)
+ * or polar coordinates (magnitude and angle parts),
+ * depending on an included or implied "separator" character:
+ *
+ * - <tt>'+'</tt>, <tt>'-'</tt>, or no separator: rectangular coordinates.
+ * - <tt>'@'</tt>: polar coordinates.
+ *
+ * <b>In Brief</b>
+ *
+ * In these examples, we use method Complex#rect to display rectangular coordinates,
+ * and method Complex#polar to display polar coordinates.
+ *
+ * # Rectangular coordinates.
+ *
+ * # Real-only: no separator; imaginary part is zero.
+ * '9'.to_c.rect # => [9, 0] # Integer.
+ * '-9'.to_c.rect # => [-9, 0] # Integer (negative).
+ * '2.5'.to_c.rect # => [2.5, 0] # Float.
+ * '1.23e-14'.to_c.rect # => [1.23e-14, 0] # Float with exponent.
+ * '2.5/1'.to_c.rect # => [(5/2), 0] # Rational.
+ *
+ * # Some things are ignored.
+ * 'foo1'.to_c.rect # => [0, 0] # Unparsed entire substring.
+ * '1foo'.to_c.rect # => [1, 0] # Unparsed trailing substring.
+ * ' 1 '.to_c.rect # => [1, 0] # Leading and trailing whitespace.
+ * *
+ * # Imaginary only: trailing 'i' required; real part is zero.
+ * '9i'.to_c.rect # => [0, 9]
+ * '-9i'.to_c.rect # => [0, -9]
+ * '2.5i'.to_c.rect # => [0, 2.5]
+ * '1.23e-14i'.to_c.rect # => [0, 1.23e-14]
+ * '2.5/1i'.to_c.rect # => [0, (5/2)]
+ *
+ * # Real and imaginary; '+' or '-' separator; trailing 'i' required.
+ * '2+3i'.to_c.rect # => [2, 3]
+ * '-2-3i'.to_c.rect # => [-2, -3]
+ * '2.5+3i'.to_c.rect # => [2.5, 3]
+ * '2.5+3/2i'.to_c.rect # => [2.5, (3/2)]
+ *
+ * # Polar coordinates; '@' separator; magnitude required.
+ * '1.0@0'.to_c.polar # => [1.0, 0.0]
+ * '1.0@'.to_c.polar # => [1.0, 0.0]
+ * "1.0@#{Math::PI}".to_c.polar # => [1.0, 3.141592653589793]
+ * "1.0@#{Math::PI/2}".to_c.polar # => [1.0, 1.5707963267948966]
+ *
+ * <b>Parsed Values</b>
+ *
+ * The parsing may be thought of as searching for numeric literals
+ * embedded in the substring.
+ *
+ * This section shows how the method parses numeric values from leading substrings.
+ * The examples show real-only or imaginary-only parsing;
+ * the parsing is the same for each part.
+ *
+ * '1foo'.to_c # => (1+0i) # Ignores trailing unparsed characters.
+ * ' 1 '.to_c # => (1+0i) # Ignores leading and trailing whitespace.
+ * 'x1'.to_c # => (0+0i) # Finds no leading numeric.
+ *
+ * # Integer literal embedded in the substring.
+ * '1'.to_c # => (1+0i)
+ * '-1'.to_c # => (-1+0i)
+ * '1i'.to_c # => (0+1i)
+ *
+ * # Integer literals that don't work.
+ * '0b100'.to_c # => (0+0i) # Not parsed as binary.
+ * '0o100'.to_c # => (0+0i) # Not parsed as octal.
+ * '0d100'.to_c # => (0+0i) # Not parsed as decimal.
+ * '0x100'.to_c # => (0+0i) # Not parsed as hexadecimal.
+ * '010'.to_c # => (10+0i) # Not parsed as octal.
+ *
+ * # Float literals:
+ * '3.14'.to_c # => (3.14+0i)
+ * '3.14i'.to_c # => (0+3.14i)
+ * '1.23e4'.to_c # => (12300.0+0i)
+ * '1.23e+4'.to_c # => (12300.0+0i)
+ * '1.23e-4'.to_c # => (0.000123+0i)
+ *
+ * # Rational literals:
+ * '1/2'.to_c # => ((1/2)+0i)
+ * '-1/2'.to_c # => ((-1/2)+0i)
+ * '1/2r'.to_c # => ((1/2)+0i)
+ * '-1/2r'.to_c # => ((-1/2)+0i)
+ *
+ * <b>Rectangular Coordinates</b>
+ *
+ * With separator <tt>'+'</tt> or <tt>'-'</tt>,
+ * or with no separator,
+ * interprets the values as rectangular coordinates: real and imaginary.
+ *
+ * With no separator, assigns a single value to either the real or the imaginary part:
+ *
+ * ''.to_c # => (0+0i) # Defaults to zero.
+ * '1'.to_c # => (1+0i) # Real (no trailing 'i').
+ * '1i'.to_c # => (0+1i) # Imaginary (trailing 'i').
+ * 'i'.to_c # => (0+1i) # Special case (imaginary 1).
+ *
+ * With separator <tt>'+'</tt>, both parts positive (or zero):
+ *
+ * # Without trailing 'i'.
+ * '+'.to_c # => (0+0i) # No values: defaults to zero.
+ * '+1'.to_c # => (1+0i) # Value after '+': real only.
+ * '1+'.to_c # => (1+0i) # Value before '+': real only.
+ * '2+1'.to_c # => (2+0i) # Values before and after '+': real and imaginary.
+ * # With trailing 'i'.
+ * '+1i'.to_c # => (0+1i) # Value after '+': imaginary only.
+ * '2+i'.to_c # => (2+1i) # Value before '+': real and imaginary 1.
+ * '2+1i'.to_c # => (2+1i) # Values before and after '+': real and imaginary.
+ *
+ * With separator <tt>'-'</tt>, negative imaginary part:
+ *
+ * # Without trailing 'i'.
+ * '-'.to_c # => (0+0i) # No values: defaults to zero.
+ * '-1'.to_c # => (-1+0i) # Value after '-': negative real, zero imaginary.
+ * '1-'.to_c # => (1+0i) # Value before '-': positive real, zero imaginary.
+ * '2-1'.to_c # => (2+0i) # Values before and after '-': positive real, zero imaginary.
+ * # With trailing 'i'.
+ * '-1i'.to_c # => (0-1i) # Value after '-': negative real, zero imaginary.
+ * '2-i'.to_c # => (2-1i) # Value before '-': positive real, negative imaginary.
+ * '2-1i'.to_c # => (2-1i) # Values before and after '-': positive real, negative imaginary.
+ *
+ * Note that the suffixed character <tt>'i'</tt>
+ * may instead be one of <tt>'I'</tt>, <tt>'j'</tt>, or <tt>'J'</tt>,
+ * with the same effect.
+ *
+ * <b>Polar Coordinates</b>
+ *
+ * With separator <tt>'@'</tt>)
+ * interprets the values as polar coordinates: magnitude and angle.
+ *
+ * '2@'.to_c.polar # => [2, 0.0] # Value before '@': magnitude only.
+ * # Values before and after '@': magnitude and angle.
+ * '2@1'.to_c.polar # => [2.0, 1.0]
* "1.0@#{Math::PI/2}".to_c # => (0.0+1i)
* "1.0@#{Math::PI}".to_c # => (-1+0.0i)
+ * # Magnitude not given: defaults to zero.
+ * '@'.to_c.polar # => [0, 0.0]
+ * '@1'.to_c.polar # => [0, 0.0]
*
- * Returns \Complex zero if the string cannot be converted:
+ * '1.0@0'.to_c # => (1+0.0i)
*
- * 'ruby'.to_c # => (0+0i)
+ * Note that in all cases, the suffixed character <tt>'i'</tt>
+ * may instead be one of <tt>'I'</tt>, <tt>'j'</tt>, <tt>'J'</tt>,
+ * with the same effect.
*
- * See Kernel#Complex.
+ * See {Converting to Non-String}[rdoc-ref:String@Converting+to+Non--5CString].
*/
static VALUE
string_to_c(VALUE self)
@@ -2275,7 +2386,7 @@ nucomp_convert(VALUE klass, VALUE a1, VALUE a2, int raise)
{
if (NIL_P(a1) || NIL_P(a2)) {
if (!raise) return Qnil;
- rb_raise(rb_eTypeError, "can't convert nil into Complex");
+ rb_cant_convert(Qnil, "Complex");
}
if (RB_TYPE_P(a1, T_STRING)) {
@@ -2509,9 +2620,9 @@ float_arg(VALUE self)
* 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].
+ * from classes {Numeric}[rdoc-ref:Numeric@Whats-Here]
+ * and {Object}[rdoc-ref:Object@Whats-Here].
+ * - Includes (indirectly) module {Comparable}[rdoc-ref:Comparable@Whats-Here].
*
* Here, class \Complex has methods for:
*
diff --git a/concurrent_set.c b/concurrent_set.c
index ffbd028a2c..42a5bfe8da 100644
--- a/concurrent_set.c
+++ b/concurrent_set.c
@@ -1,10 +1,12 @@
#include "internal.h"
#include "internal/gc.h"
#include "internal/concurrent_set.h"
-#include "ruby_atomic.h"
#include "ruby/atomic.h"
#include "vm_sync.h"
+#define CONCURRENT_SET_CONTINUATION_BIT ((VALUE)1 << (sizeof(VALUE) * CHAR_BIT - 1))
+#define CONCURRENT_SET_HASH_MASK (~CONCURRENT_SET_CONTINUATION_BIT)
+
enum concurrent_set_special_values {
CONCURRENT_SET_EMPTY,
CONCURRENT_SET_DELETED,
@@ -26,10 +28,40 @@ struct concurrent_set {
};
static void
+concurrent_set_mark_continuation(struct concurrent_set_entry *entry, VALUE curr_hash_and_flags)
+{
+ if (curr_hash_and_flags & CONCURRENT_SET_CONTINUATION_BIT) return;
+
+ RUBY_ASSERT((curr_hash_and_flags & CONCURRENT_SET_HASH_MASK) != 0);
+
+ VALUE new_hash = curr_hash_and_flags | CONCURRENT_SET_CONTINUATION_BIT;
+ VALUE prev_hash = rbimpl_atomic_value_cas(&entry->hash, curr_hash_and_flags, new_hash, RBIMPL_ATOMIC_RELEASE, RBIMPL_ATOMIC_RELAXED);
+
+ // At the moment we only expect to be racing concurrently against another
+ // thread also setting the continuation bit.
+ // In the future if deletion is concurrent this will need adjusting
+ RUBY_ASSERT(prev_hash == curr_hash_and_flags || prev_hash == new_hash);
+ (void)prev_hash;
+}
+
+static VALUE
+concurrent_set_hash(const struct concurrent_set *set, VALUE key)
+{
+ VALUE hash = set->funcs->hash(key);
+ hash &= CONCURRENT_SET_HASH_MASK;
+ if (hash == 0) {
+ hash ^= CONCURRENT_SET_HASH_MASK;
+ }
+ RUBY_ASSERT(hash != 0);
+ RUBY_ASSERT(!(hash & CONCURRENT_SET_CONTINUATION_BIT));
+ return hash;
+}
+
+static void
concurrent_set_free(void *ptr)
{
struct concurrent_set *set = ptr;
- xfree(set->entries);
+ SIZED_FREE_N(set->entries, set->capacity);
}
static size_t
@@ -40,14 +72,26 @@ concurrent_set_size(const void *ptr)
(set->capacity * sizeof(struct concurrent_set_entry));
}
+/* Hack: Though it would be trivial, we're intentionally avoiding WB-protecting
+ * this object. This prevents the object from aging and ensures it can always be
+ * collected in a minor GC.
+ * Longer term this deserves a better way to reclaim memory promptly.
+ */
+static void
+concurrent_set_mark(void *ptr)
+{
+ (void)ptr;
+}
+
static const rb_data_type_t concurrent_set_type = {
.wrap_struct_name = "VM/concurrent_set",
.function = {
- .dmark = NULL,
+ .dmark = concurrent_set_mark,
.dfree = concurrent_set_free,
.dsize = concurrent_set_size,
},
- .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_EMBEDDABLE
+ /* Hack: NOT WB_PROTECTED on purpose (see above) */
+ .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_EMBEDDABLE
};
VALUE
@@ -97,7 +141,7 @@ static void
concurrent_set_try_resize_without_locking(VALUE old_set_obj, VALUE *set_obj_ptr)
{
// Check if another thread has already resized.
- if (RUBY_ATOMIC_VALUE_LOAD(*set_obj_ptr) != old_set_obj) {
+ if (rbimpl_atomic_value_load(set_obj_ptr, RBIMPL_ATOMIC_ACQUIRE) != old_set_obj) {
return;
}
@@ -105,8 +149,9 @@ concurrent_set_try_resize_without_locking(VALUE old_set_obj, VALUE *set_obj_ptr)
// This may overcount by up to the number of threads concurrently attempting to insert
// GC may also happen between now and the set being rebuilt
- int expected_size = RUBY_ATOMIC_LOAD(old_set->size) - old_set->deleted_entries;
+ int expected_size = rbimpl_atomic_load(&old_set->size, RBIMPL_ATOMIC_RELAXED) - old_set->deleted_entries;
+ // NOTE: new capacity must make sense with load factor, don't change one without checking the other.
struct concurrent_set_entry *old_entries = old_set->entries;
int old_capacity = old_set->capacity;
int new_capacity = old_capacity * 2;
@@ -117,25 +162,21 @@ concurrent_set_try_resize_without_locking(VALUE old_set_obj, VALUE *set_obj_ptr)
new_capacity = old_capacity;
}
- // May cause GC and therefore deletes, so must hapen first.
+ // May cause GC and therefore deletes, so must happen first.
VALUE new_set_obj = rb_concurrent_set_new(old_set->funcs, new_capacity);
struct concurrent_set *new_set = RTYPEDDATA_GET_DATA(new_set_obj);
for (int i = 0; i < old_capacity; i++) {
- struct concurrent_set_entry *entry = &old_entries[i];
- VALUE key = RUBY_ATOMIC_VALUE_EXCHANGE(entry->key, CONCURRENT_SET_MOVED);
+ struct concurrent_set_entry *old_entry = &old_entries[i];
+ VALUE key = rbimpl_atomic_value_exchange(&old_entry->key, CONCURRENT_SET_MOVED, RBIMPL_ATOMIC_ACQUIRE);
RUBY_ASSERT(key != CONCURRENT_SET_MOVED);
if (key < CONCURRENT_SET_SPECIAL_VALUE_COUNT) continue;
if (!RB_SPECIAL_CONST_P(key) && rb_objspace_garbage_object_p(key)) continue;
- VALUE hash = RUBY_ATOMIC_VALUE_LOAD(entry->hash);
- if (hash == 0) {
- // Either in-progress insert or extremely unlikely 0 hash.
- // Re-calculate the hash.
- hash = old_set->funcs->hash(key);
- }
- RUBY_ASSERT(hash == old_set->funcs->hash(key));
+ VALUE hash = rbimpl_atomic_value_load(&old_entry->hash, RBIMPL_ATOMIC_RELAXED) & CONCURRENT_SET_HASH_MASK;
+ RUBY_ASSERT(hash != 0);
+ RUBY_ASSERT(hash == concurrent_set_hash(old_set, key));
// Insert key into new_set.
struct concurrent_set_probe probe;
@@ -144,25 +185,24 @@ concurrent_set_try_resize_without_locking(VALUE old_set_obj, VALUE *set_obj_ptr)
while (true) {
struct concurrent_set_entry *entry = &new_set->entries[idx];
- if (entry->key == CONCURRENT_SET_EMPTY) {
- new_set->size++;
+ if (entry->hash == CONCURRENT_SET_EMPTY) {
+ RUBY_ASSERT(entry->key == CONCURRENT_SET_EMPTY);
+ new_set->size++;
RUBY_ASSERT(new_set->size <= new_set->capacity / 2);
- RUBY_ASSERT(entry->hash == 0);
entry->key = key;
entry->hash = hash;
break;
}
- else {
- RUBY_ASSERT(entry->key >= CONCURRENT_SET_SPECIAL_VALUE_COUNT);
- }
+ RUBY_ASSERT(entry->key >= CONCURRENT_SET_SPECIAL_VALUE_COUNT);
+ entry->hash |= CONCURRENT_SET_CONTINUATION_BIT;
idx = concurrent_set_probe_next(&probe);
}
}
- RUBY_ATOMIC_VALUE_SET(*set_obj_ptr, new_set_obj);
+ rbimpl_atomic_value_store(set_obj_ptr, new_set_obj, RBIMPL_ATOMIC_RELEASE);
RB_GC_GUARD(old_set_obj);
}
@@ -182,29 +222,48 @@ rb_concurrent_set_find(VALUE *set_obj_ptr, VALUE key)
VALUE set_obj;
VALUE hash = 0;
+ struct concurrent_set *set;
+ struct concurrent_set_probe probe;
+ int idx;
retry:
- set_obj = RUBY_ATOMIC_VALUE_LOAD(*set_obj_ptr);
+ set_obj = rbimpl_atomic_value_load(set_obj_ptr, RBIMPL_ATOMIC_ACQUIRE);
RUBY_ASSERT(set_obj);
- struct concurrent_set *set = RTYPEDDATA_GET_DATA(set_obj);
+ set = RTYPEDDATA_GET_DATA(set_obj);
if (hash == 0) {
// We don't need to recompute the hash on every retry because it should
// never change.
- hash = set->funcs->hash(key);
+ hash = concurrent_set_hash(set, key);
}
- RUBY_ASSERT(hash == set->funcs->hash(key));
+ RUBY_ASSERT(hash == concurrent_set_hash(set, key));
- struct concurrent_set_probe probe;
- int idx = concurrent_set_probe_start(&probe, set, hash);
+ idx = concurrent_set_probe_start(&probe, set, hash);
while (true) {
struct concurrent_set_entry *entry = &set->entries[idx];
- VALUE curr_key = RUBY_ATOMIC_VALUE_LOAD(entry->key);
+ VALUE curr_hash_and_flags = rbimpl_atomic_value_load(&entry->hash, RBIMPL_ATOMIC_ACQUIRE);
+ VALUE curr_hash = curr_hash_and_flags & CONCURRENT_SET_HASH_MASK;
+ bool continuation = curr_hash_and_flags & CONCURRENT_SET_CONTINUATION_BIT;
+
+ if (curr_hash_and_flags == CONCURRENT_SET_EMPTY) {
+ return 0;
+ }
+
+ if (curr_hash != hash) {
+ if (!continuation) {
+ return 0;
+ }
+ idx = concurrent_set_probe_next(&probe);
+ continue;
+ }
+
+ VALUE curr_key = rbimpl_atomic_value_load(&entry->key, RBIMPL_ATOMIC_ACQUIRE);
switch (curr_key) {
case CONCURRENT_SET_EMPTY:
- return 0;
+ // In-progress insert: hash written but key not yet
+ break;
case CONCURRENT_SET_DELETED:
break;
case CONCURRENT_SET_MOVED:
@@ -213,13 +272,9 @@ rb_concurrent_set_find(VALUE *set_obj_ptr, VALUE key)
goto retry;
default: {
- VALUE curr_hash = RUBY_ATOMIC_VALUE_LOAD(entry->hash);
- if (curr_hash != 0 && curr_hash != hash) break;
-
if (UNLIKELY(!RB_SPECIAL_CONST_P(curr_key) && rb_objspace_garbage_object_p(curr_key))) {
// This is a weakref set, so after marking but before sweeping is complete we may find a matching garbage object.
- // Skip it and mark it as deleted.
- RUBY_ATOMIC_VALUE_CAS(entry->key, curr_key, CONCURRENT_SET_DELETED);
+ // Skip it and let the GC pass clean it up
break;
}
@@ -229,6 +284,10 @@ rb_concurrent_set_find(VALUE *set_obj_ptr, VALUE key)
return curr_key;
}
+ if (!continuation) {
+ return 0;
+ }
+
break;
}
}
@@ -242,56 +301,84 @@ rb_concurrent_set_find_or_insert(VALUE *set_obj_ptr, VALUE key, void *data)
{
RUBY_ASSERT(key >= CONCURRENT_SET_SPECIAL_VALUE_COUNT);
- bool inserting = false;
- VALUE set_obj;
- VALUE hash = 0;
+ // First attempt to find
+ {
+ VALUE result = rb_concurrent_set_find(set_obj_ptr, key);
+ if (result) return result;
+ }
- retry:
- set_obj = RUBY_ATOMIC_VALUE_LOAD(*set_obj_ptr);
+ // First time we need to call create, and store the hash
+ VALUE set_obj = rbimpl_atomic_value_load(set_obj_ptr, RBIMPL_ATOMIC_ACQUIRE);
RUBY_ASSERT(set_obj);
- struct concurrent_set *set = RTYPEDDATA_GET_DATA(set_obj);
- if (hash == 0) {
- // We don't need to recompute the hash on every retry because it should
- // never change.
- hash = set->funcs->hash(key);
- }
- RUBY_ASSERT(hash == set->funcs->hash(key));
+ struct concurrent_set *set = RTYPEDDATA_GET_DATA(set_obj);
+ key = set->funcs->create(key, data);
+ VALUE hash = concurrent_set_hash(set, key);
struct concurrent_set_probe probe;
- int idx = concurrent_set_probe_start(&probe, set, hash);
+ int idx;
+
+ goto start_search;
+
+retry:
+ // On retries we only need to load the hash object
+ set_obj = rbimpl_atomic_value_load(set_obj_ptr, RBIMPL_ATOMIC_ACQUIRE);
+ RUBY_ASSERT(set_obj);
+ set = RTYPEDDATA_GET_DATA(set_obj);
+
+ RUBY_ASSERT(hash == concurrent_set_hash(set, key));
+
+start_search:
+ idx = concurrent_set_probe_start(&probe, set, hash);
while (true) {
struct concurrent_set_entry *entry = &set->entries[idx];
- VALUE curr_key = RUBY_ATOMIC_VALUE_LOAD(entry->key);
+ VALUE curr_hash_and_flags = rbimpl_atomic_value_load(&entry->hash, RBIMPL_ATOMIC_ACQUIRE);
+ VALUE curr_hash = curr_hash_and_flags & CONCURRENT_SET_HASH_MASK;
+ bool continuation = curr_hash_and_flags & CONCURRENT_SET_CONTINUATION_BIT;
+
+ if (curr_hash_and_flags == CONCURRENT_SET_EMPTY) {
+ // Reserve this slot for our hash value
+ curr_hash_and_flags = rbimpl_atomic_value_cas(&entry->hash, CONCURRENT_SET_EMPTY, hash, RBIMPL_ATOMIC_RELEASE, RBIMPL_ATOMIC_RELAXED);
+ if (curr_hash_and_flags != CONCURRENT_SET_EMPTY) {
+ // Lost race, retry same slot to check winner's hash
+ continue;
+ }
+
+ // CAS succeeded, so these are the values stored
+ curr_hash_and_flags = hash;
+ curr_hash = hash;
+
+ // Fall through to try to claim key
+ }
+
+ if (curr_hash != hash) {
+ goto probe_next;
+ }
+
+ VALUE curr_key = rbimpl_atomic_value_load(&entry->key, RBIMPL_ATOMIC_ACQUIRE);
switch (curr_key) {
case CONCURRENT_SET_EMPTY: {
- // Not in set
- if (!inserting) {
- key = set->funcs->create(key, data);
- RUBY_ASSERT(hash == set->funcs->hash(key));
- inserting = true;
- }
+ rb_atomic_t prev_size = rbimpl_atomic_fetch_add(&set->size, 1, RBIMPL_ATOMIC_RELAXED);
- rb_atomic_t prev_size = RUBY_ATOMIC_FETCH_ADD(set->size, 1);
+ // Load_factor reached at 75% full. ex: prev_size: 32, capacity: 64, load_factor: 50%.
+ bool load_factor_reached = (uint64_t)(prev_size * 4) >= (uint64_t)(set->capacity * 3);
- if (UNLIKELY(prev_size > set->capacity / 2)) {
+ if (UNLIKELY(load_factor_reached)) {
concurrent_set_try_resize(set_obj, set_obj_ptr);
-
goto retry;
}
- curr_key = RUBY_ATOMIC_VALUE_CAS(entry->key, CONCURRENT_SET_EMPTY, key);
- if (curr_key == CONCURRENT_SET_EMPTY) {
- RUBY_ATOMIC_VALUE_SET(entry->hash, hash);
-
+ VALUE prev_key = rbimpl_atomic_value_cas(&entry->key, CONCURRENT_SET_EMPTY, key, RBIMPL_ATOMIC_RELEASE, RBIMPL_ATOMIC_RELAXED);
+ if (prev_key == CONCURRENT_SET_EMPTY) {
+ RUBY_ASSERT(rb_concurrent_set_find(set_obj_ptr, key) == key);
RB_GC_GUARD(set_obj);
return key;
}
else {
// Entry was not inserted.
- RUBY_ATOMIC_DEC(set->size);
+ rbimpl_atomic_sub(&set->size, 1, RBIMPL_ATOMIC_RELAXED);
// Another thread won the race, try again at the same location.
continue;
@@ -302,57 +389,78 @@ rb_concurrent_set_find_or_insert(VALUE *set_obj_ptr, VALUE key, void *data)
case CONCURRENT_SET_MOVED:
// Wait
RB_VM_LOCKING();
-
goto retry;
- default: {
- VALUE curr_hash = RUBY_ATOMIC_VALUE_LOAD(entry->hash);
- if (curr_hash != 0 && curr_hash != hash) break;
-
+ default:
+ // We're never GC during our search
+ // If the continuation bit wasn't set at the start of our search,
+ // any concurrent find with the same hash value would also look at
+ // this location and try to swap curr_key
if (UNLIKELY(!RB_SPECIAL_CONST_P(curr_key) && rb_objspace_garbage_object_p(curr_key))) {
- // This is a weakref set, so after marking but before sweeping is complete we may find a matching garbage object.
- // Skip it and mark it as deleted.
- RUBY_ATOMIC_VALUE_CAS(entry->key, curr_key, CONCURRENT_SET_DELETED);
- break;
+ if (continuation) {
+ goto probe_next;
+ }
+ {
+ VALUE prev = rbimpl_atomic_value_cas(&entry->key, curr_key, CONCURRENT_SET_EMPTY, RBIMPL_ATOMIC_RELEASE, RBIMPL_ATOMIC_RELAXED);
+ if (prev == curr_key) {
+ rbimpl_atomic_sub(&set->size, 1, RBIMPL_ATOMIC_RELAXED);
+ }
+ }
+ continue;
}
if (set->funcs->cmp(key, curr_key)) {
- // We've found a match.
+ // We've found a live match.
RB_GC_GUARD(set_obj);
- if (inserting) {
- // We created key using set->funcs->create, but we didn't end
- // up inserting it into the set. Free it here to prevent memory
- // leaks.
- if (set->funcs->free) set->funcs->free(key);
- }
+ // We created key using set->funcs->create, but we didn't end
+ // up inserting it into the set. Free it here to prevent memory
+ // leaks.
+ if (set->funcs->free) set->funcs->free(key);
return curr_key;
}
-
break;
- }
}
+ probe_next:
+ RUBY_ASSERT(curr_hash_and_flags != CONCURRENT_SET_EMPTY);
+ concurrent_set_mark_continuation(entry, curr_hash_and_flags);
idx = concurrent_set_probe_next(&probe);
}
}
+static void
+concurrent_set_delete_entry_locked(struct concurrent_set *set, struct concurrent_set_entry *entry)
+{
+ ASSERT_vm_locking_with_barrier();
+
+ if (entry->hash & CONCURRENT_SET_CONTINUATION_BIT) {
+ entry->hash = CONCURRENT_SET_CONTINUATION_BIT;
+ entry->key = CONCURRENT_SET_DELETED;
+ set->deleted_entries++;
+ }
+ else {
+ entry->hash = CONCURRENT_SET_EMPTY;
+ entry->key = CONCURRENT_SET_EMPTY;
+ set->size--;
+ }
+}
+
VALUE
rb_concurrent_set_delete_by_identity(VALUE set_obj, VALUE key)
{
- // Assume locking and barrier (which there is no assert for).
- ASSERT_vm_locking();
+ ASSERT_vm_locking_with_barrier();
struct concurrent_set *set = RTYPEDDATA_GET_DATA(set_obj);
- VALUE hash = set->funcs->hash(key);
+ VALUE hash = concurrent_set_hash(set, key);
struct concurrent_set_probe probe;
int idx = concurrent_set_probe_start(&probe, set, hash);
while (true) {
struct concurrent_set_entry *entry = &set->entries[idx];
- VALUE curr_key = RUBY_ATOMIC_VALUE_LOAD(entry->key);
+ VALUE curr_key = entry->key;
switch (curr_key) {
case CONCURRENT_SET_EMPTY:
@@ -365,8 +473,8 @@ rb_concurrent_set_delete_by_identity(VALUE set_obj, VALUE key)
break;
default:
if (key == curr_key) {
- entry->key = CONCURRENT_SET_DELETED;
- set->deleted_entries++;
+ RUBY_ASSERT((entry->hash & CONCURRENT_SET_HASH_MASK) == hash);
+ concurrent_set_delete_entry_locked(set, entry);
return curr_key;
}
break;
@@ -379,14 +487,13 @@ rb_concurrent_set_delete_by_identity(VALUE set_obj, VALUE key)
void
rb_concurrent_set_foreach_with_replace(VALUE set_obj, int (*callback)(VALUE *key, void *data), void *data)
{
- // Assume locking and barrier (which there is no assert for).
- ASSERT_vm_locking();
+ ASSERT_vm_locking_with_barrier();
struct concurrent_set *set = RTYPEDDATA_GET_DATA(set_obj);
for (unsigned int i = 0; i < set->capacity; i++) {
struct concurrent_set_entry *entry = &set->entries[i];
- VALUE key = set->entries[i].key;
+ VALUE key = entry->key;
switch (key) {
case CONCURRENT_SET_EMPTY:
@@ -401,8 +508,7 @@ rb_concurrent_set_foreach_with_replace(VALUE set_obj, int (*callback)(VALUE *key
case ST_STOP:
return;
case ST_DELETE:
- set->entries[i].key = CONCURRENT_SET_DELETED;
- set->deleted_entries++;
+ concurrent_set_delete_entry_locked(set, entry);
break;
}
break;
diff --git a/configure.ac b/configure.ac
index 82f144a8bb..2de91209d6 100644
--- a/configure.ac
+++ b/configure.ac
@@ -69,6 +69,7 @@ dnl 93(bright yellow) is copied from .github/workflows/mingw.yml
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
+AC_ARG_VAR([rustc_flags], [additional RUSTC_FLAGS])dnl
[begin]_group "environment section" && {
HAVE_BASERUBY=yes
@@ -82,9 +83,17 @@ AC_ARG_WITH(baseruby,
],
[
AC_PATH_PROG([BASERUBY], [ruby], [false])
+ HAVE_BASERUBY=
])
-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], [
+ # --without-baseruby
+], [error=`RUBYOPT=- $BASERUBY --disable=gems "${tooldir}/missing-baseruby.bat" --verbose 2>&1`], [
+ HAVE_BASERUBY=yes
+], [test "$HAVE_BASERUBY" = ""], [ # no --with-baseruby option
+ AC_MSG_WARN($error) # just warn and continue
+ HAVE_BASERUBY=no
+], [ # the ruby given by --with-baseruby is too old
+ AC_MSG_ERROR($error) # bail out
])
AS_IF([test "${HAVE_BASERUBY:=no}" != no], [
AS_CASE(["$build_os"], [mingw*], [
@@ -101,16 +110,44 @@ AS_IF([test "$HAVE_BASERUBY" = no], [
])
AC_SUBST(BASERUBY)
AC_SUBST(HAVE_BASERUBY)
+AS_IF([test "$cross_compiling" = yes],
+ [X_BUILD_EXEEXT=`$BASERUBY -rrbconfig -e ['puts RbConfig::CONFIG["EXEEXT"]']`],
+ [X_BUILD_EXEEXT='$(EXEEXT)']
+)
+AC_SUBST(X_BUILD_EXEEXT)
+
+AC_ARG_WITH(dump-ast,
+ AS_HELP_STRING([--with-dump-ast=DUMP_AST], [use DUMP_AST as dump_ast; for cross-compiling with a host-built dump_ast]),
+ [DUMP_AST=$withval DUMP_AST_TARGET='$(empty)'],
+ [AS_IF([test "$cross_compiling" = yes], [
+ DUMP_AST='build-tool/dump_ast$(BUILD_EXEEXT)'
+ ], [
+ DUMP_AST='./dump_ast$(BUILD_EXEEXT)'
+ ])
+ DUMP_AST_TARGET='$(DUMP_AST)'])
+dnl Without baseruby, .rbinc files cannot be regenerated, so clear the
+dnl dependency on dump_ast to avoid rebuilding pre-generated .rbinc files.
+AS_IF([test "$HAVE_BASERUBY" = no], [DUMP_AST_TARGET='$(empty)'])
+AC_SUBST(X_DUMP_AST, "${DUMP_AST}")
+AC_SUBST(X_DUMP_AST_TARGET, "${DUMP_AST_TARGET}")
: ${GIT=git}
HAVE_GIT=yes
AC_ARG_WITH(git,
AS_HELP_STRING([--without-git], [never use git]),
[AS_CASE([$withval],
- [no], [GIT=never-use HAVE_GIT=no],
+ [no], [HAVE_GIT=no],
[yes], [],
[GIT=$withval])])
-AS_IF([test x"$HAVE_GIT" = xyes], [command -v "$GIT" > /dev/null || HAVE_GIT=no])
+{
+ test x"$HAVE_GIT" = xyes &&
+ command -v "$GIT" > /dev/null &&
+ # `git -C`: 1.8.5
+ # `git log --no-show-signature`: 2.10.0
+ AS_CASE([`$GIT -C . --version 2> /dev/null | sed 's/.* //'`],
+ [0.*|1.*|2.@<:@0-9@:>@.*], [false],
+ [true])
+} || HAVE_GIT=no GIT=never-use
AC_SUBST(GIT)
AC_SUBST(HAVE_GIT)
@@ -251,6 +288,11 @@ AS_CASE(["/${rb_CC} "],
RUBY_CHECK_PROG_FOR_CC([OBJDUMP], [clang], [${llvm_prefix}objdump])
RUBY_CHECK_PROG_FOR_CC([RANLIB], [clang], [${llvm_prefix}ranlib])
RUBY_CHECK_PROG_FOR_CC([STRIP], [clang], [${llvm_prefix}strip])
+
+ # These -Wno-* flags silence clang-specific diagnostics that don't exist
+ # in GCC. GCC silently accepts unknown -Wno-* flags but later emits noisy
+ # "unrecognized command-line option" notes whenever another warning fires.
+ clang_warnflags="-Wno-constant-logical-operand -Wno-parentheses-equality -Wno-self-assign"
])
AS_UNSET(rb_CC)
AS_UNSET(rb_dummy)
@@ -264,6 +306,8 @@ AS_CASE(["${build_os}"],
])
AS_CASE(["${target_os}"],
[cygwin*|msys*|mingw*|darwin*], [
+ ac_ct_OBJCOPY=":"
+ ac_cv_prog_OBJCOPY=":"
ac_cv_prog_ac_ct_OBJCOPY=":"
])
@@ -286,6 +330,8 @@ AC_CHECK_TOOLS([OBJCOPY], [gobjcopy objcopy], [:])
AC_CHECK_TOOLS([OBJDUMP], [gobjdump objdump])
AC_CHECK_TOOLS([STRIP], [gstrip strip], [:])
+FIRSTMAKEFILE=""
+
# 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"])
@@ -460,6 +506,8 @@ AS_CASE(["$target_os"],
# so wrap clang to insert our fake wasm-opt, which does nothing, in PATH.
CC_WRAPPER=`cd -P "${tooldir}" && pwd`/wasm-clangw
CC="$CC_WRAPPER $CC"
+
+ FIRSTMAKEFILE=GNUmakefile:wasm/GNUmakefile.in
])
cc_version=
@@ -501,6 +549,8 @@ AS_CASE(["$target_os"],
target_cpu=`echo $target_cpu | sed s/i.86/i386/`
AS_CASE(["$target"], [-*], [ target="$target_cpu${target}"])
AS_CASE(["$target_alias"], [-*], [ target_alias="$target_cpu${target_alias}"])
+ # cygwin/GNUmakefile.in is not exclusively for cygwin.
+ FIRSTMAKEFILE=GNUmakefile:cygwin/GNUmakefile.in
AS_CASE(["$target_os"],
[mingw*], [
test "$rb_cv_msvcrt" = "" && unset rb_cv_msvcrt
@@ -521,7 +571,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,6 +652,22 @@ AS_IF([test -f conf$$.dir/src/cdcmd], [
rm -fr conf$$.dir
AC_MSG_RESULT([$CHDIR])
AC_SUBST(CHDIR)
+
+AS_CASE(["$FIRSTMAKEFILE"], [*GNUmakefile:*], [gnumake=yes], [
+ AC_MSG_CHECKING([if ${MAKE-make} is GNU make])
+ mkdir conftest.dir
+ echo "all:; @echo yes" > conftest.dir/GNUmakefile
+ echo "all:; @echo no" > conftest.dir/Makefile
+ gnumake=`(cd conftest.dir; ${MAKE-make})`
+ rm -fr conftest.dir
+ AS_CASE(["$gnumake"],
+ [*yes*], [
+ FIRSTMAKEFILE=GNUmakefile:template/GNUmakefile.in
+ gnumake=yes],
+ [
+ gnumake=no])
+ AC_MSG_RESULT($gnumake)
+])
}
[begin]_group "compiler section" && {
@@ -675,7 +740,7 @@ AS_IF([test "$fdeclspec" = yes], [
RUBY_APPEND_OPTIONS(cflags, -fdeclspec)
RUBY_APPEND_OPTIONS(orig_cflags, -fdeclspec)
])
-RUBY_TRY_CXXFLAGS(-fdeclspec, [fdeclspec=yes], [fdeclspec=no])
+RUBY_TRY_CXXFLAGS(-fdeclspec, [fdeclspec=yes], [fdeclspec=no], [@%:@include <cstdio>])
AS_IF([test "$fdeclspec" = yes], [
RUBY_APPEND_OPTIONS(CXXFLAGS, -fdeclspec)
])
@@ -703,6 +768,12 @@ AS_CASE(["$GCC:${warnflags+set}:${extra_warnflags:+set}:"],
AS_CASE([ $CFLAGS ], [*" -save-temps="*|*" -save-temps "*], [], [
extra_warnflags="$extra_warnflags -Werror=misleading-indentation"
])
+ AS_CASE([$target_os], [mingw*], [
+ # 64bit Windows is IL32P64; shorten-64-to-32 causes tons of warnigs
+ extra_warnflags="$extra_warnflags -Wno-shorten-64-to-32"
+ ], [
+ extra_warnflags="$extra_warnflags -Werror=shorten-64-to-32"
+ ])
# ICC doesn't support -Werror=
AS_IF([test $icc_version -gt 0], [
@@ -716,19 +787,15 @@ AS_CASE(["$GCC:${warnflags+set}:${extra_warnflags:+set}:"],
-Werror=implicit-function-declaration \
-Werror=implicit-int \
-Werror=pointer-arith \
- -Werror=shorten-64-to-32 \
-Werror=write-strings \
-Werror=old-style-definition \
-Wimplicit-fallthrough=0 \
-Wmissing-noreturn \
-Wno-cast-function-type \
- -Wno-constant-logical-operand \
-Wno-long-long \
-Wno-missing-field-initializers \
-Wno-overlength-strings \
-Wno-packed-bitfield-compat \
- -Wno-parentheses-equality \
- -Wno-self-assign \
-Wno-tautological-compare \
-Wno-unused-parameter \
-Wno-unused-value \
@@ -736,6 +803,7 @@ AS_CASE(["$GCC:${warnflags+set}:${extra_warnflags:+set}:"],
-Wsuggest-attribute=noreturn \
-Wunused-variable \
-diag-disable=175,188,1684,2259,2312 \
+ $clang_warnflags \
$extra_warnflags \
; do
AS_IF([test "$particular_werror_flags" != yes], [
@@ -1228,6 +1296,11 @@ main()
ac_cv_header_sys_time_h=no
ac_cv_header_sys_times_h=no
ac_cv_header_sys_socket_h=no
+ ac_cv_func_chown=yes
+ ac_cv_func_getegid=yes
+ ac_cv_func_geteuid=yes
+ ac_cv_func_getgid=yes
+ ac_cv_func_getuid=yes
ac_cv_func_execv=yes
ac_cv_func_lstat=yes
ac_cv_func_times=yes
@@ -1240,6 +1313,8 @@ main()
ac_cv_func_readlink=yes
ac_cv_func_shutdown=yes
ac_cv_func_symlink=yes
+ ac_cv_func_clock_getres=yes
+ ac_cv_func_clock_gettime=yes
ac_cv_lib_crypt_crypt=no
ac_cv_func_getpgrp_void=no
ac_cv_func_memcmp_working=yes
@@ -1256,8 +1331,8 @@ main()
AS_IF([test "$target_cpu" = x64], [
ac_cv_func___builtin_setjmp=yes
ac_cv_func_round=no
+ ac_cv_func_tgamma=no
])
- ac_cv_func_tgamma=no
AC_CHECK_TYPE([NET_LUID], [], [],
[@%:@include <winsock2.h>
@%:@include <windows.h>
@@ -1729,18 +1804,26 @@ AS_IF([test "$GCC" = yes], [
[rb_cv_gcc_atomic_builtins=no])])
AS_IF([test "$rb_cv_gcc_atomic_builtins" = yes], [
AC_DEFINE(HAVE_GCC_ATOMIC_BUILTINS)
- AC_CACHE_CHECK([for 64bit __atomic builtins], [rb_cv_gcc_atomic_builtins_64], [
- AC_LINK_IFELSE([AC_LANG_PROGRAM([[@%:@include <stdint.h>
- uint64_t atomic_var;]],
- [[
- __atomic_load_n(&atomic_var, __ATOMIC_RELAXED);
- __atomic_store_n(&atomic_var, 0, __ATOMIC_RELAXED);
- ]])],
- [rb_cv_gcc_atomic_builtins_64=yes],
- [rb_cv_gcc_atomic_builtins_64=no])])
- AS_IF([test "$rb_cv_gcc_atomic_builtins_64" = yes], [
- AC_DEFINE(HAVE_GCC_ATOMIC_BUILTINS_64)
- ])
+ for lib in "" atomic; do
+ AS_IF([test "$lib" != ""], [
+ AC_CHECK_LIB([atomic], [__atomic_fetch_add_8])
+ unset rb_cv_gcc_atomic_builtins_64
+ ])
+ AC_CACHE_CHECK([for 64bit __atomic builtins${lib:+ with -l$lib}],
+ [rb_cv_gcc_atomic_builtins_64], [
+ AC_LINK_IFELSE([AC_LANG_PROGRAM([[@%:@include <stdint.h>
+ uint64_t atomic_var;]],
+ [[
+ __atomic_load_n(&atomic_var, __ATOMIC_RELAXED);
+ __atomic_store_n(&atomic_var, 0, __ATOMIC_RELAXED);
+ ]])],
+ [rb_cv_gcc_atomic_builtins_64=yes],
+ [rb_cv_gcc_atomic_builtins_64=no])])
+ AS_IF([test "$rb_cv_gcc_atomic_builtins_64" = yes], [
+ AC_DEFINE(HAVE_GCC_ATOMIC_BUILTINS_64)
+ break
+ ])
+ done
])
AC_CACHE_CHECK([for __sync builtins], [rb_cv_gcc_sync_builtins], [
@@ -1804,10 +1887,6 @@ RUBY_DECL_ATTRIBUTE([__nonnull__(n)], [RUBY_FUNC_NONNULL(n,x)], [rb_cv_func_nonn
RUBY_APPEND_OPTION(XCFLAGS, -DRUBY_EXPORT)
-AC_ARG_ENABLE(mathn,
- AS_HELP_STRING([--enable-mathn], [enable canonicalization for mathn]),
- [AC_MSG_ERROR([mathn support has been dropped])])
-
AC_CACHE_CHECK(for function name string predefined identifier,
rb_cv_function_name_string,
[AS_CASE(["$target_os"],[openbsd*],[
@@ -2435,9 +2514,7 @@ AC_CACHE_CHECK(for negative time_t for gmtime(3), rb_cv_negative_time_t,
#include <time.h>
void
-check(tm, y, m, d, h, s)
- struct tm *tm;
- int y, m, d, h, s;
+check(struct tm *tm, int y, int m, int d, int h, int s)
{
if (!tm ||
tm->tm_year != y ||
@@ -2521,8 +2598,7 @@ AS_IF([test "$ac_cv_func_sigprocmask" = yes && test "$ac_cv_func_sigaction" = ye
#include <signal.h>
void
-sig_handler(dummy)
- int dummy;
+sig_handler(int dummy)
{
}
@@ -3465,7 +3541,7 @@ AS_IF([test x"$cross_compiling" = xyes], [
# darwin target requires miniruby for linking ext bundles
PREP="$PREP"' miniruby$(EXEEXT)'
])
- RUNRUBY_COMMAND='$(MINIRUBY) -I`cd $(srcdir)/lib; pwd`'
+ RUNRUBY_COMMAND='$(MINIRUBY) -I`$(CHDIR) $(srcdir)/lib; pwd`'
RUNRUBY='$(RUNRUBY_COMMAND)'
XRUBY='$(MINIRUBY)'
TEST_RUNNABLE=no
@@ -3491,7 +3567,6 @@ AC_SUBST(RUNRUBY)
AC_SUBST(XRUBY)
AC_SUBST(EXTOUT, [${EXTOUT=.ext}])
-FIRSTMAKEFILE=""
LIBRUBY_A='lib$(RUBY_SO_NAME)-static.a'
LIBRUBY='$(LIBRUBY_A)'
LIBRUBYARG_STATIC='-l$(RUBY_SO_NAME)-static'
@@ -3508,7 +3583,8 @@ AS_CASE(["$target_os"],
AC_ARG_ENABLE(multiarch,
AS_HELP_STRING([--enable-multiarch], [enable multiarch compatible directories]),
- [multiarch=], [unset multiarch])
+ [AS_CASE([$enableval], [no], [unset multiarch], [multiarch=])],
+ [unset multiarch])
AS_IF([test ${multiarch+set}], [
AC_DEFINE(ENABLE_MULTIARCH)
])
@@ -3658,6 +3734,7 @@ AS_CASE("$enable_shared", [yes], [
LIBRUBY_DLDFLAGS="$LIBRUBY_DLDFLAGS "'-current_version $(RUBY_PROGRAM_VERSION)'
AS_IF([test "$visibility_option" = ld], [
LIBRUBY_DLDFLAGS="$LIBRUBY_DLDFLAGS "'-Wl,-unexported_symbol,_Init_*'
+ LIBRUBY_DLDFLAGS="$LIBRUBY_DLDFLAGS "'-Wl,-unexported_symbol,_InitVM_*'
LIBRUBY_DLDFLAGS="$LIBRUBY_DLDFLAGS "'-Wl,-unexported_symbol,_ruby_static_id_*'
LIBRUBY_DLDFLAGS="$LIBRUBY_DLDFLAGS "'-Wl,-unexported_symbol,*_threadptr_*'
])
@@ -3855,11 +3932,11 @@ AC_SUBST(INSTALL_STATIC_LIBRARY)
[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/ZJIT (rustc >= 1.58.0)
+dnl check if rustc is recent enough to build YJIT (rustc >= 1.58.0)
JIT_RUSTC_OK=no
+JIT_TARGET_ARCH=
AS_IF([test "$RUSTC" != "no"],
- AC_MSG_CHECKING([whether ${RUSTC} works for YJIT/ZJIT])
- JIT_TARGET_ARCH=
+ AC_MSG_CHECKING([whether ${RUSTC} works for YJIT])
AS_CASE(["$target_cpu"],
[arm64|aarch64], [JIT_TARGET_ARCH=aarch64],
[x86_64], [JIT_TARGET_ARCH=x86_64],
@@ -3893,33 +3970,43 @@ AS_IF([test "$cross_compiling" = no],
)
)
-dnl build ZJIT in release mode if rustc >= 1.58.0 is present and we are on a supported platform
-AC_ARG_ENABLE(zjit,
- AS_HELP_STRING([--enable-zjit],
- [enable in-process JIT compiler that requires Rust build tools. enabled by default on supported platforms if rustc 1.58.0+ is available]),
- [ZJIT_SUPPORT=$enableval],
- [AS_CASE(["$JIT_TARGET_OK:$JIT_RUSTC_OK:$YJIT_SUPPORT"],
- [yes:yes:no], [
- ZJIT_SUPPORT=yes
- ],
- [ZJIT_SUPPORT=no]
- )]
-)
-
dnl build YJIT in release mode if rustc >= 1.58.0 is present and we are on a supported platform
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(["$JIT_TARGET_OK:$JIT_RUSTC_OK:$ZJIT_SUPPORT"],
- [yes:yes:no], [
+ [AS_CASE(["$JIT_TARGET_OK:$JIT_RUSTC_OK"],
+ [yes:yes], [
YJIT_SUPPORT=yes
],
[YJIT_SUPPORT=no]
)]
)
-CARGO=
+dnl build ZJIT in release mode if rustc >= 1.85.0 is present and we are on a supported platform
+ZJIT_SUPPORT=no
+AC_ARG_ENABLE(zjit,
+ AS_HELP_STRING([--enable-zjit],
+ [enable experimental JIT compiler that requires Rust build tools. enabled by default on supported platforms if rustc 1.85.0+ is available]),
+ [ZJIT_SUPPORT=$enableval],
+ [AS_CASE(["$JIT_TARGET_OK"],
+ [yes], [
+ rb_zjit_build_possible=no
+ AC_MSG_CHECKING([prerequisites for ZJIT])dnl only checked when --enable-zjit is not specified
+ # Fails in case rustc target doesn't match ruby target. Can happen on Rosetta, for example.
+ # 1.85.0 is the first stable version that supports the 2024 edition.
+ AS_IF([test "$RUSTC" != "no" && echo "#[cfg(target_arch = \"$JIT_TARGET_ARCH\")] fn main() {}" |
+ $RUSTC - --edition=2024 --emit asm=/dev/null 2>/dev/null],
+ AS_IF([test "$gnumake" = "yes"], [
+ rb_zjit_build_possible=yes
+ ])
+ )
+ AC_MSG_RESULT($rb_zjit_build_possible)
+ ZJIT_SUPPORT=$rb_zjit_build_possible
+ ]
+ )]
+)
+
CARGO_BUILD_ARGS=
YJIT_LIBS=
JIT_CARGO_SUPPORT=no
@@ -3970,7 +4057,7 @@ AS_CASE(["${ZJIT_SUPPORT}"],
[yes], [
],
[dev], [
- rb_cargo_features="$rb_cargo_features,disasm"
+ rb_cargo_features="$rb_cargo_features,disasm,runtime_checks"
JIT_CARGO_SUPPORT=dev
AC_DEFINE(RUBY_DEBUG, 1)
],
@@ -3996,11 +4083,26 @@ AS_CASE(["${ZJIT_SUPPORT}"],
AC_DEFINE(USE_ZJIT, 0)
])
-# if YJIT+ZJIT release build, or any build that requires Cargo
-AS_IF([test x"$JIT_CARGO_SUPPORT" != "xno" -o \( x"$YJIT_SUPPORT" != "xno" -a x"$ZJIT_SUPPORT" != "xno" \)], [
+RUSTC_FLAGS='-g -C lto=thin -C opt-level=3 -C overflow-checks=on'
+AS_IF([test -n "${rustc_flags}"], [
+ RUSTC_FLAGS="${RUSTC_FLAGS} ${rustc_flags}"
+])
+
+JIT_RUST_FLAGS='--crate-type=staticlib --cfg feature=\"stats_allocator\"'
+RLIB_DIR=
+AS_CASE(["$JIT_CARGO_SUPPORT:$YJIT_SUPPORT:$ZJIT_SUPPORT"],
+[no:yes:yes], [ # release build of YJIT+ZJIT
+ YJIT_LIBS=
+ ZJIT_LIBS=
+ JIT_RUST_FLAGS="--crate-type=rlib"
+ RLIB_DIR="target/release"
+ RUST_LIB="target/release/libruby.a"
+],
+[no:*], [],
+[ # JIT_CARGO_SUPPORT not "no" -- cargo required.
AC_CHECK_TOOL(CARGO, [cargo], [no])
AS_IF([test x"$CARGO" = "xno"],
- AC_MSG_ERROR([cargo is required. Installation instructions available at https://www.rust-lang.org/tools/install]))
+ AC_MSG_ERROR([this build configuration requires cargo. Installation instructions available at https://www.rust-lang.org/tools/install]))
YJIT_LIBS=
ZJIT_LIBS=
@@ -4023,9 +4125,9 @@ AS_IF([test x"$JIT_CARGO_SUPPORT" != "xno" -o \( x"$YJIT_SUPPORT" != "xno" -a x"
])
CARGO_BUILD_ARGS="--profile ${JIT_CARGO_SUPPORT} --features ${rb_cargo_features}"
AS_IF([test "${JIT_CARGO_SUPPORT}" = "dev"], [
- RUST_LIB="target/debug/libjit.a"
+ RUST_LIB="target/debug/libruby.a"
], [
- RUST_LIB="target/${JIT_CARGO_SUPPORT}/libjit.a"
+ RUST_LIB="target/${JIT_CARGO_SUPPORT}/libruby.a"
])
])
@@ -4042,6 +4144,8 @@ AS_IF([test -n "$RUST_LIB"], [
dnl These variables end up in ::RbConfig::CONFIG
AC_SUBST(RUSTC)dnl Rust compiler command
+AC_SUBST(JIT_RUST_FLAGS)dnl the common rustc flags for JIT crates such as zjit
+AC_SUBST(RUSTC_FLAGS)dnl user-configurable rustc compiler flags
AC_SUBST(CARGO)dnl Cargo command for Rust builds
AC_SUBST(CARGO_BUILD_ARGS)dnl for selecting Rust build profiles
AC_SUBST(YJIT_SUPPORT)dnl what flavor of YJIT the Ruby build includes
@@ -4052,6 +4156,7 @@ AC_SUBST(ZJIT_LIBS)dnl path to the .a library of ZJIT
AC_SUBST(ZJIT_OBJ)dnl for optionally building the C parts of ZJIT
AC_SUBST(JIT_OBJ)dnl for optionally building C glue code for Rust FFI
AC_SUBST(RUST_LIB)dnl path to the rust .a library that contains either or both JITs
+AC_SUBST(RLIB_DIR)dnl subpath of build directory for .rlib files
AC_SUBST(JIT_CARGO_SUPPORT)dnl "no" or the cargo profile of the rust code
}
@@ -4166,7 +4271,6 @@ enum {
PLATFORM_DIR=win32
])
LIBRUBY_ALIASES=''
- FIRSTMAKEFILE=GNUmakefile:cygwin/GNUmakefile.in
AS_IF([test x"$enable_shared" = xyes], [
LIBRUBY='lib$(RUBY_SO_NAME).dll.a'
], [
@@ -4176,7 +4280,6 @@ enum {
])
],
[wasi*], [
- FIRSTMAKEFILE=GNUmakefile:wasm/GNUmakefile.in
AC_LIBOBJ([wasm/missing])
AC_LIBOBJ([wasm/runtime])
AC_LIBOBJ([wasm/fiber])
@@ -4193,21 +4296,6 @@ AC_ARG_ENABLE(debug-env,
AS_HELP_STRING([--enable-debug-env], [enable RUBY_DEBUG environment variable]),
[AC_SUBST(ENABLE_DEBUG_ENV, yes)])
-AS_CASE(["$FIRSTMAKEFILE"], [*GNUmakefile:*], [gnumake=yes], [
- AC_MSG_CHECKING([if ${MAKE-make} is GNU make])
- mkdir conftest.dir
- echo "all:; @echo yes" > conftest.dir/GNUmakefile
- echo "all:; @echo no" > conftest.dir/Makefile
- gnumake=`(cd conftest.dir; ${MAKE-make})`
- rm -fr conftest.dir
- AS_CASE(["$gnumake"],
- [*yes*], [
- FIRSTMAKEFILE=GNUmakefile:template/GNUmakefile.in
- gnumake=yes],
- [
- gnumake=no])
- AC_MSG_RESULT($gnumake)
-])
AS_IF([test "$gnumake" = yes], [ NULLCMD=: ], [
AC_MSG_CHECKING([for safe null command for ${MAKE-make}])
mkdir conftest.dir
@@ -4275,8 +4363,7 @@ AS_IF([test -n "${LIBS}"], [
MAINFLAGS=`echo " $MAINLIBS " | sed "s|$libspat"'||;s/^ *//;s/ *$//'`
])
LIBRUBYARG_STATIC="${LIBRUBYARG_STATIC} \$(MAINLIBS)"
-CPPFLAGS="$CPPFLAGS "'$(DEFS)'
-test -z "$CPPFLAGS" || CPPFLAGS="$CPPFLAGS "; CPPFLAGS="$CPPFLAGS"'${cppflags}'
+CPPFLAGS="$CPPFLAGS "'$(DEFS) ${cppflags}'
AS_IF([test -n "${cflags+set}"], [
cflagspat=`eval echo '"'"${cflags}"'"' | sed 's/[[][|.*]]/\\&/g;s/^ */ /;s/^ *$/ /'`
CFLAGS=`echo " $CFLAGS " | sed "s|$cflagspat"'|${cflags}|;s/^ *//;s/ *$//'`
@@ -4291,6 +4378,24 @@ AS_IF([test "${ARCH_FLAG}"], [
CXXFLAGS=`echo "$CXXFLAGS" | sed "s| *$archflagpat"'||'`
LDFLAGS=`echo "$LDFLAGS" | sed "s| *$archflagpat"'||'`
])
+AS_CASE([" $rb_cv_warnflags "], [*" -Wshorten-64-to-32 "*|*" -Werror=shorten-64-to-32 "*], [
+ voidp_ll=
+ AS_CASE([$ac_cv_sizeof_voidp],
+ [SIZEOF_LONG_LONG], [voidp_ll=true],
+ [@<:@0-9@:>@*], [
+ AS_IF([test $ac_cv_sizeof_voidp -gt $ac_cv_sizeof_long], [voidp_ll=true])
+ ])
+ AS_IF([test "$voidp_ll"], [
+ # Disable the shorten-64-to-32 warning for now, because it currently
+ # generates a lot of warnings on platforms where `sizeof(void*)` is
+ # larger than `sizeof(long)`.
+ #
+ # TODO: Replace `long` with `ptrdiff_t` or something in the all sources.
+ rb_cv_warnflags=`echo "$rb_cv_warnflags" |
+ sed -e 's/ -W\(shorten-64-to-32 \)/ -Wno-\1/' \
+ -e 's/ -Werror=\(shorten-64-to-32 \)/ -Wno-\1/'`
+ ])
+])
rb_cv_warnflags=`echo "$rb_cv_warnflags" | sed 's/^ *//;s/ *$//'`
warnflags="$rb_cv_warnflags"
AC_SUBST(cppflags)dnl
@@ -4333,7 +4438,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/.*://'`
@@ -4597,6 +4701,9 @@ m4_foreach(parser, [available_parsers],
[AC_MSG_ERROR([Unknown parser: $with_parser])]
)
+# Use the ruby allocator for prism. See prism/defines.h
+RUBY_APPEND_OPTIONS(XCFLAGS, -DPRISM_XALLOCATOR)
+
arch_hdrdir="${EXTOUT}/include/${arch}/ruby"
AS_MKDIR_P("${arch_hdrdir}")
config_h="${arch_hdrdir}/config.h"
@@ -4699,21 +4806,7 @@ AC_CONFIG_FILES(Makefile:template/Makefile.in, [
echo; echo '$(srcdir)/$(CONFIGURE):RUBY_M4_INCLUDED \
$(empty)'
- } > $tmpmk && AS_IF([! grep '^ruby:' $tmpmk > /dev/null], [
- AS_IF([test "${gnumake}" = yes], [
- tmpgmk=confgmk$$.tmp
- {
- echo "include $tmpmk"
- echo "-include uncommon.mk"
- } > $tmpgmk
- ], [
- tmpgmk=$tmpmk
- ]) &&
- test -z "`${MAKE-make} -f $tmpgmk info-program | grep '^PROGRAM=ruby$'`" &&
- echo 'ruby: $(PROGRAM);' >> $tmpmk
- rm -f uncommon.mk # remove stale uncommon.mk, it should be updated by GNUmakefile
- test "$tmpmk" = "$tmpgmk" || rm -f "$tmpgmk"
- ]) && mv -f $tmpmk Makefile],
+ } > $tmpmk && mv -f $tmpmk Makefile],
[EXEEXT='$EXEEXT' MAKE='${MAKE-make}' gnumake='$gnumake' GIT='$GIT' YJIT_SUPPORT='$YJIT_SUPPORT'])
AC_ARG_WITH([ruby-pc],
@@ -4728,6 +4821,11 @@ AC_ARG_WITH(destdir,
[DESTDIR="$withval"])
AC_SUBST(DESTDIR)
+AS_IF([test "x$load_relative:$DESTDIR" = xyes:], [
+ AS_IF([test "x$prefix" = xNONE], [DESTDIR="$ac_default_prefix"], [DESTDIR="$prefix"])
+ prefix=/.
+])
+
AC_OUTPUT
}
@@ -4781,6 +4879,7 @@ config_summary "strip command" "$STRIP"
config_summary "install doc" "$DOCTARGETS"
config_summary "YJIT support" "$YJIT_SUPPORT"
config_summary "ZJIT support" "$ZJIT_SUPPORT"
+config_summary "RUSTC_FLAGS" "$RUSTC_FLAGS"
config_summary "man page type" "$MANTYPE"
config_summary "search path" "$search_path"
config_summary "static-linked-ext" ${EXTSTATIC:+"yes"}
diff --git a/cont.c b/cont.c
index 0d7245ed9c..6bb61e5ee8 100644
--- a/cont.c
+++ b/cont.c
@@ -41,14 +41,20 @@ extern int madvise(caddr_t, size_t, int);
#include "vm_sync.h"
#include "id_table.h"
#include "ractor_core.h"
+#include "zjit.h"
-static const int DEBUG = 0;
+enum {
+ DEBUG = 0,
+ DEBUG_EXPAND = 0,
+ DEBUG_ACQUIRE = 0,
+};
#define RB_PAGE_SIZE (pagesize)
#define RB_PAGE_MASK (~(RB_PAGE_SIZE - 1))
static long pagesize;
-static const rb_data_type_t cont_data_type, fiber_data_type;
+static const rb_data_type_t rb_cont_data_type;
+static const rb_data_type_t rb_fiber_data_type;
static VALUE rb_cContinuation;
static VALUE rb_cFiber;
static VALUE rb_eFiberError;
@@ -61,11 +67,11 @@ static VALUE rb_cFiberPool;
// Defined in `coroutine/$arch/Context.h`:
#ifdef COROUTINE_LIMITED_ADDRESS_SPACE
#define FIBER_POOL_ALLOCATION_FREE
-#define FIBER_POOL_INITIAL_SIZE 8
-#define FIBER_POOL_ALLOCATION_MAXIMUM_SIZE 32
+#define FIBER_POOL_MINIMUM_COUNT 8
+#define FIBER_POOL_MAXIMUM_ALLOCATIONS 32
#else
-#define FIBER_POOL_INITIAL_SIZE 32
-#define FIBER_POOL_ALLOCATION_MAXIMUM_SIZE 1024
+#define FIBER_POOL_MINIMUM_COUNT 32
+#define FIBER_POOL_MAXIMUM_ALLOCATIONS 1024
#endif
#ifdef RB_EXPERIMENTAL_FIBER_POOL
#define FIBER_POOL_ALLOCATION_FREE
@@ -78,6 +84,7 @@ enum context_type {
struct cont_saved_vm_stack {
VALUE *ptr;
+ size_t size;
#ifdef CAPTURE_JUST_VALID_VM_STACK
size_t slen; /* length of stack (head of ec->vm_stack) */
size_t clen; /* length of control frames (tail of ec->vm_stack) */
@@ -187,7 +194,11 @@ struct fiber_pool {
size_t count;
// The initial number of stacks to allocate.
- size_t initial_count;
+ size_t minimum_count;
+
+ // If positive, total stacks in this pool cannot exceed this (shared pool only:
+ // set via RUBY_SHARED_FIBER_POOL_MAXIMUM_COUNT). Expansion fails with errno EAGAIN.
+ size_t maximum_count;
// Whether to madvise(free) the stack or not.
// If this value is set to 1, the stack will be madvise(free)ed
@@ -280,7 +291,7 @@ rb_free_shared_fiber_pool(void)
struct fiber_pool_allocation *allocations = shared_fiber_pool.allocations;
while (allocations) {
struct fiber_pool_allocation *next = allocations->next;
- xfree(allocations);
+ SIZED_FREE(allocations);
allocations = next;
}
}
@@ -468,11 +479,12 @@ fiber_pool_allocate_memory(size_t * count, size_t stride)
// the system would allow (e.g. overcommit * physical memory + swap), we
// divide count by two and try again. This condition should only be
// encountered in edge cases, but we handle it here gracefully.
- while (*count > 1) {
+ while (*count) {
#if defined(_WIN32)
void * base = VirtualAlloc(0, (*count)*stride, MEM_COMMIT, PAGE_READWRITE);
if (!base) {
+ errno = rb_w32_map_errno(GetLastError());
*count = (*count) >> 1;
}
else {
@@ -504,93 +516,122 @@ fiber_pool_allocate_memory(size_t * count, size_t stride)
}
// Given an existing fiber pool, expand it by the specified number of stacks.
+//
// @param count the maximum number of stacks to allocate.
-// @return the allocated fiber pool.
+// @return the new allocation on success, or NULL on failure with errno set.
+// @raise NoMemoryError if the struct or memory allocation fails.
+//
+// Call from fiber_pool_stack_acquire_expand with VM lock held, or from
+// fiber_pool_initialize before the pool is shared across threads.
// @sa fiber_pool_allocation_free
static struct fiber_pool_allocation *
fiber_pool_expand(struct fiber_pool * fiber_pool, size_t count)
{
- struct fiber_pool_allocation * allocation;
- RB_VM_LOCK_ENTER();
- {
- STACK_GROW_DIR_DETECTION;
+ if (count == 0) {
+ errno = EAGAIN;
+ return NULL;
+ }
- size_t size = fiber_pool->size;
- size_t stride = size + RB_PAGE_SIZE;
+ STACK_GROW_DIR_DETECTION;
- // Allocate the memory required for the stacks:
- void * base = fiber_pool_allocate_memory(&count, stride);
+ size_t size = fiber_pool->size;
+ size_t stride = size + RB_PAGE_SIZE;
- if (base == NULL) {
- rb_raise(rb_eFiberError, "can't alloc machine stack to fiber (%"PRIuSIZE" x %"PRIuSIZE" bytes): %s", count, size, ERRNOMSG);
+ // If the maximum number of stacks is set, and we have reached it, return NULL.
+ if (fiber_pool->maximum_count > 0) {
+ if (fiber_pool->count >= fiber_pool->maximum_count) {
+ errno = EAGAIN;
+ return NULL;
+ }
+ size_t remaining = fiber_pool->maximum_count - fiber_pool->count;
+ if (count > remaining) {
+ count = remaining;
}
+ }
- struct fiber_pool_vacancy * vacancies = fiber_pool->vacancies;
- allocation = RB_ALLOC(struct fiber_pool_allocation);
+ // Allocate metadata before mmap: ruby_xmalloc (RB_ALLOC) raises on failure and
+ // must not run after base is mapped, or the region would leak.
+ struct fiber_pool_allocation * allocation = RB_ALLOC(struct fiber_pool_allocation);
- // Initialize fiber pool allocation:
- allocation->base = base;
- allocation->size = size;
- allocation->stride = stride;
- allocation->count = count;
+ // Allocate the memory required for the stacks:
+ void * base = fiber_pool_allocate_memory(&count, stride);
+
+ if (base == NULL) {
+ if (!errno) errno = ENOMEM;
+ ruby_xfree(allocation);
+ return NULL;
+ }
+
+ struct fiber_pool_vacancy * vacancies = fiber_pool->vacancies;
+
+ // Initialize fiber pool allocation:
+ allocation->base = base;
+ allocation->size = size;
+ allocation->stride = stride;
+ allocation->count = count;
#ifdef FIBER_POOL_ALLOCATION_FREE
- allocation->used = 0;
+ allocation->used = 0;
#endif
- allocation->pool = fiber_pool;
+ allocation->pool = fiber_pool;
- if (DEBUG) {
- fprintf(stderr, "fiber_pool_expand(%"PRIuSIZE"): %p, %"PRIuSIZE"/%"PRIuSIZE" x [%"PRIuSIZE":%"PRIuSIZE"]\n",
- count, (void*)fiber_pool, fiber_pool->used, fiber_pool->count, size, fiber_pool->vm_stack_size);
- }
+ if (DEBUG_EXPAND) {
+ fprintf(stderr, "fiber_pool_expand(%"PRIuSIZE"): %p, %"PRIuSIZE"/%"PRIuSIZE" x [%"PRIuSIZE":%"PRIuSIZE"]\n",
+ count, (void*)fiber_pool, fiber_pool->used, fiber_pool->count, size, fiber_pool->vm_stack_size);
+ }
- // Iterate over all stacks, initializing the vacancy list:
- for (size_t i = 0; i < count; i += 1) {
- void * base = (char*)allocation->base + (stride * i);
- void * page = (char*)base + STACK_DIR_UPPER(size, 0);
+ // Iterate over all stacks, initializing the vacancy list:
+ for (size_t i = 0; i < count; i += 1) {
+ void * base = (char*)allocation->base + (stride * i);
+ void * page = (char*)base + STACK_DIR_UPPER(size, 0);
#if defined(_WIN32)
- DWORD old_protect;
-
- if (!VirtualProtect(page, RB_PAGE_SIZE, PAGE_READWRITE | PAGE_GUARD, &old_protect)) {
- VirtualFree(allocation->base, 0, MEM_RELEASE);
- rb_raise(rb_eFiberError, "can't set a guard page: %s", ERRNOMSG);
- }
+ DWORD old_protect;
+
+ if (!VirtualProtect(page, RB_PAGE_SIZE, PAGE_READWRITE | PAGE_GUARD, &old_protect)) {
+ int error = rb_w32_map_errno(GetLastError());
+ VirtualFree(allocation->base, 0, MEM_RELEASE);
+ ruby_xfree(allocation);
+ errno = error;
+ return NULL;
+ }
#elif defined(__wasi__)
- // wasi-libc's mprotect emulation doesn't support PROT_NONE.
- (void)page;
+ // wasi-libc's mprotect emulation doesn't support PROT_NONE.
+ (void)page;
#else
- if (mprotect(page, RB_PAGE_SIZE, PROT_NONE) < 0) {
- munmap(allocation->base, count*stride);
- rb_raise(rb_eFiberError, "can't set a guard page: %s", ERRNOMSG);
- }
+ if (mprotect(page, RB_PAGE_SIZE, PROT_NONE) < 0) {
+ int error = errno;
+ if (!error) error = ENOMEM;
+ munmap(allocation->base, count*stride);
+ ruby_xfree(allocation);
+ errno = error;
+ return NULL;
+ }
#endif
- vacancies = fiber_pool_vacancy_initialize(
- fiber_pool, vacancies,
- (char*)base + STACK_DIR_UPPER(0, RB_PAGE_SIZE),
- size
- );
+ vacancies = fiber_pool_vacancy_initialize(
+ fiber_pool, vacancies,
+ (char*)base + STACK_DIR_UPPER(0, RB_PAGE_SIZE),
+ size
+ );
#ifdef FIBER_POOL_ALLOCATION_FREE
- vacancies->stack.allocation = allocation;
+ vacancies->stack.allocation = allocation;
#endif
- }
+ }
- // Insert the allocation into the head of the pool:
- allocation->next = fiber_pool->allocations;
+ // Insert the allocation into the head of the pool:
+ allocation->next = fiber_pool->allocations;
#ifdef FIBER_POOL_ALLOCATION_FREE
- if (allocation->next) {
- allocation->next->previous = allocation;
- }
+ if (allocation->next) {
+ allocation->next->previous = allocation;
+ }
- allocation->previous = NULL;
+ allocation->previous = NULL;
#endif
- fiber_pool->allocations = allocation;
- fiber_pool->vacancies = vacancies;
- fiber_pool->count += count;
- }
- RB_VM_LOCK_LEAVE();
+ fiber_pool->allocations = allocation;
+ fiber_pool->vacancies = vacancies;
+ fiber_pool->count += count;
return allocation;
}
@@ -598,7 +639,7 @@ fiber_pool_expand(struct fiber_pool * fiber_pool, size_t count)
// Initialize the specified fiber pool with the given number of stacks.
// @param vm_stack_size The size of the vm stack to allocate.
static void
-fiber_pool_initialize(struct fiber_pool * fiber_pool, size_t size, size_t count, size_t vm_stack_size)
+fiber_pool_initialize(struct fiber_pool * fiber_pool, size_t size, size_t minimum_count, size_t maximum_count, size_t vm_stack_size)
{
VM_ASSERT(vm_stack_size < size);
@@ -606,13 +647,17 @@ fiber_pool_initialize(struct fiber_pool * fiber_pool, size_t size, size_t count,
fiber_pool->vacancies = NULL;
fiber_pool->size = ((size / RB_PAGE_SIZE) + 1) * RB_PAGE_SIZE;
fiber_pool->count = 0;
- fiber_pool->initial_count = count;
+ fiber_pool->minimum_count = minimum_count;
+ fiber_pool->maximum_count = maximum_count;
fiber_pool->free_stacks = 1;
fiber_pool->used = 0;
-
fiber_pool->vm_stack_size = vm_stack_size;
- fiber_pool_expand(fiber_pool, count);
+ if (fiber_pool->minimum_count > 0) {
+ if (RB_UNLIKELY(!fiber_pool_expand(fiber_pool, fiber_pool->minimum_count))) {
+ rb_raise(rb_eFiberError, "can't allocate initial fiber stacks (%"PRIuSIZE" x %"PRIuSIZE" bytes): %s", fiber_pool->minimum_count, fiber_pool->size, strerror(errno));
+ }
+ }
}
#ifdef FIBER_POOL_ALLOCATION_FREE
@@ -656,35 +701,101 @@ fiber_pool_allocation_free(struct fiber_pool_allocation * allocation)
allocation->pool->count -= allocation->count;
- ruby_xfree(allocation);
+ SIZED_FREE(allocation);
}
#endif
+// Number of stacks to request when expanding the pool (clamped to min/max).
+static size_t
+fiber_pool_stack_expand_count(const struct fiber_pool *pool)
+{
+ const size_t maximum_allocations = FIBER_POOL_MAXIMUM_ALLOCATIONS;
+ const size_t minimum_count = FIBER_POOL_MINIMUM_COUNT;
+
+ // We are going try and double the number of stacks in the pool:
+ size_t count = pool->count;
+ if (count > maximum_allocations) count = maximum_allocations;
+ if (count < minimum_count) count = minimum_count;
+
+ // If we have a maximum count, we need to clamp the number of stacks to the maximum:
+ if (pool->maximum_count > 0) {
+ if (pool->count >= pool->maximum_count) {
+ // No expansion is possible:
+ return 0;
+ }
+
+ // Otherwise, compute the number of stacks we can allocate to bring us to the maximum:
+ size_t remaining = pool->maximum_count - pool->count;
+ if (count > remaining) {
+ count = remaining;
+ }
+ }
+
+ return count;
+}
+
+// When the vacancy list is empty, grow the pool (and run GC only if mmap fails). Caller holds the VM lock.
+// Returns NULL if expansion failed after GC + retry; errno is set. Otherwise returns a vacancy.
+static struct fiber_pool_vacancy *
+fiber_pool_stack_acquire_expand(struct fiber_pool *fiber_pool)
+{
+ size_t count = fiber_pool_stack_expand_count(fiber_pool);
+
+ if (DEBUG_ACQUIRE) fprintf(stderr, "fiber_pool_stack_acquire: expanding fiber pool by %"PRIuSIZE" stacks\n", count);
+
+ struct fiber_pool_vacancy *vacancy = NULL;
+
+ if (RB_LIKELY(fiber_pool_expand(fiber_pool, count))) {
+ return fiber_pool_vacancy_pop(fiber_pool);
+ }
+ else {
+ if (DEBUG_ACQUIRE) fprintf(stderr, "fiber_pool_stack_acquire: expand failed (%s), collecting garbage\n", strerror(errno));
+
+ rb_gc();
+
+ // After running GC, the vacancy list may have some stacks:
+ vacancy = fiber_pool_vacancy_pop(fiber_pool);
+ if (RB_LIKELY(vacancy)) {
+ return vacancy;
+ }
+
+ // Recompute count as gc may have freed up some allocations:
+ count = fiber_pool_stack_expand_count(fiber_pool);
+
+ // Try to expand the fiber pool again:
+ if (RB_LIKELY(fiber_pool_expand(fiber_pool, count))) {
+ return fiber_pool_vacancy_pop(fiber_pool);
+ }
+ else {
+ // Okay, we really failed to acquire a stack. Give up and return NULL with errno set:
+ return NULL;
+ }
+ }
+}
+
// Acquire a stack from the given fiber pool. If none are available, allocate more.
static struct fiber_pool_stack
fiber_pool_stack_acquire(struct fiber_pool * fiber_pool)
{
- struct fiber_pool_vacancy * vacancy ;
- RB_VM_LOCK_ENTER();
+ struct fiber_pool_vacancy * vacancy;
+
+ unsigned int lev;
+ RB_VM_LOCK_ENTER_LEV(&lev);
{
+ // Fast path: try to acquire a stack from the vacancy list:
vacancy = fiber_pool_vacancy_pop(fiber_pool);
if (DEBUG) fprintf(stderr, "fiber_pool_stack_acquire: %p used=%"PRIuSIZE"\n", (void*)fiber_pool->vacancies, fiber_pool->used);
- if (!vacancy) {
- const size_t maximum = FIBER_POOL_ALLOCATION_MAXIMUM_SIZE;
- const size_t minimum = fiber_pool->initial_count;
-
- size_t count = fiber_pool->count;
- if (count > maximum) count = maximum;
- if (count < minimum) count = minimum;
-
- fiber_pool_expand(fiber_pool, count);
+ // Slow path: If the pool has no vacancies, expand first. Only run GC when expansion fails (e.g. mmap), so we can reclaim stacks from dead fibers before retrying:
+ if (RB_UNLIKELY(!vacancy)) {
+ vacancy = fiber_pool_stack_acquire_expand(fiber_pool);
- // The free list should now contain some stacks:
- VM_ASSERT(fiber_pool->vacancies);
-
- vacancy = fiber_pool_vacancy_pop(fiber_pool);
+ // If expansion failed, raise an error:
+ if (RB_UNLIKELY(!vacancy)) {
+ RB_VM_LOCK_LEAVE_LEV(&lev);
+ rb_raise(rb_eFiberError, "can't allocate fiber stack: %s", strerror(errno));
+ }
}
VM_ASSERT(vacancy);
@@ -703,7 +814,7 @@ fiber_pool_stack_acquire(struct fiber_pool * fiber_pool)
fiber_pool_stack_reset(&vacancy->stack);
}
- RB_VM_LOCK_LEAVE();
+ RB_VM_LOCK_LEAVE_LEV(&lev);
return vacancy->stack;
}
@@ -774,44 +885,40 @@ static void
fiber_pool_stack_release(struct fiber_pool_stack * stack)
{
struct fiber_pool * pool = stack->pool;
- RB_VM_LOCK_ENTER();
- {
- struct fiber_pool_vacancy * vacancy = fiber_pool_vacancy_pointer(stack->base, stack->size);
+ struct fiber_pool_vacancy * vacancy = fiber_pool_vacancy_pointer(stack->base, stack->size);
- if (DEBUG) fprintf(stderr, "fiber_pool_stack_release: %p used=%"PRIuSIZE"\n", stack->base, stack->pool->used);
+ if (DEBUG) fprintf(stderr, "fiber_pool_stack_release: %p used=%"PRIuSIZE"\n", stack->base, stack->pool->used);
- // Copy the stack details into the vacancy area:
- vacancy->stack = *stack;
- // After this point, be careful about updating/using state in stack, since it's copied to the vacancy area.
+ // Copy the stack details into the vacancy area:
+ vacancy->stack = *stack;
+ // After this point, be careful about updating/using state in stack, since it's copied to the vacancy area.
- // Reset the stack pointers and reserve space for the vacancy data:
- fiber_pool_vacancy_reset(vacancy);
+ // Reset the stack pointers and reserve space for the vacancy data:
+ fiber_pool_vacancy_reset(vacancy);
- // Push the vacancy into the vancancies list:
- pool->vacancies = fiber_pool_vacancy_push(vacancy, pool->vacancies);
- pool->used -= 1;
+ // Push the vacancy into the vancancies list:
+ pool->vacancies = fiber_pool_vacancy_push(vacancy, pool->vacancies);
+ pool->used -= 1;
#ifdef FIBER_POOL_ALLOCATION_FREE
- struct fiber_pool_allocation * allocation = stack->allocation;
+ struct fiber_pool_allocation * allocation = stack->allocation;
- allocation->used -= 1;
+ allocation->used -= 1;
- // Release address space and/or dirty memory:
- if (allocation->used == 0) {
- fiber_pool_allocation_free(allocation);
- }
- else if (stack->pool->free_stacks) {
- fiber_pool_stack_free(&vacancy->stack);
- }
+ // Release address space and/or dirty memory:
+ if (allocation->used == 0) {
+ fiber_pool_allocation_free(allocation);
+ }
+ else if (stack->pool->free_stacks) {
+ fiber_pool_stack_free(&vacancy->stack);
+ }
#else
- // This is entirely optional, but clears the dirty flag from the stack
- // memory, so it won't get swapped to disk when there is memory pressure:
- if (stack->pool->free_stacks) {
- fiber_pool_stack_free(&vacancy->stack);
- }
-#endif
+ // This is entirely optional, but clears the dirty flag from the stack
+ // memory, so it won't get swapped to disk when there is memory pressure:
+ if (stack->pool->free_stacks) {
+ fiber_pool_stack_free(&vacancy->stack);
}
- RB_VM_LOCK_LEAVE();
+#endif
}
static inline void
@@ -924,6 +1031,17 @@ fiber_stack_release(rb_fiber_t * fiber)
rb_ec_clear_vm_stack(ec);
}
+static void
+fiber_stack_release_locked(rb_fiber_t *fiber)
+{
+ if (!ruby_vm_during_cleanup) {
+ // We can't try to acquire the VM lock here because MMTK calls free in its own native thread which has no ec.
+ // This assertion will fail on MMTK but we currently don't have CI for debug releases of MMTK, so we can assert for now.
+ ASSERT_vm_locking_with_barrier();
+ }
+ fiber_stack_release(fiber);
+}
+
static const char *
fiber_status_name(enum fiber_status s)
{
@@ -945,7 +1063,9 @@ fiber_verify(const rb_fiber_t *fiber)
switch (fiber->status) {
case FIBER_RESUMED:
- VM_ASSERT(fiber->cont.saved_ec.vm_stack != NULL);
+ if (fiber->cont.saved_ec.thread_ptr->self == 0) {
+ VM_ASSERT(fiber->cont.saved_ec.vm_stack != NULL);
+ }
break;
case FIBER_SUSPENDED:
VM_ASSERT(fiber->cont.saved_ec.vm_stack != NULL);
@@ -975,7 +1095,7 @@ cont_ptr(VALUE obj)
{
rb_context_t *cont;
- TypedData_Get_Struct(obj, rb_context_t, &cont_data_type, cont);
+ TypedData_Get_Struct(obj, rb_context_t, &rb_cont_data_type, cont);
return cont;
}
@@ -985,7 +1105,7 @@ fiber_ptr(VALUE obj)
{
rb_fiber_t *fiber;
- TypedData_Get_Struct(obj, rb_fiber_t, &fiber_data_type, fiber);
+ TypedData_Get_Struct(obj, rb_fiber_t, &rb_fiber_data_type, fiber);
if (!fiber) rb_raise(rb_eFiberError, "uninitialized fiber");
return fiber;
@@ -1078,21 +1198,26 @@ cont_free(void *ptr)
RUBY_FREE_ENTER("cont");
if (cont->type == CONTINUATION_CONTEXT) {
- ruby_xfree(cont->saved_ec.vm_stack);
- RUBY_FREE_UNLESS_NULL(cont->machine.stack);
+ SIZED_FREE_N(cont->saved_ec.vm_stack, cont->saved_ec.vm_stack_size);
+ SIZED_FREE_N(cont->machine.stack, cont->machine.stack_size);
}
else {
rb_fiber_t *fiber = (rb_fiber_t*)cont;
coroutine_destroy(&fiber->context);
- fiber_stack_release(fiber);
+ fiber_stack_release_locked(fiber);
}
- RUBY_FREE_UNLESS_NULL(cont->saved_vm_stack.ptr);
+ SIZED_FREE_N(cont->saved_vm_stack.ptr, cont->saved_vm_stack.size);
VM_ASSERT(cont->jit_cont != NULL);
jit_cont_free(cont->jit_cont);
/* free rb_cont_t or rb_fiber_t */
- ruby_xfree(ptr);
+ if (cont->type == CONTINUATION_CONTEXT) {
+ SIZED_FREE(cont);
+ }
+ else {
+ SIZED_FREE((rb_fiber_t *)cont);
+ }
RUBY_FREE_LEAVE("cont");
}
@@ -1133,12 +1258,7 @@ rb_fiber_update_self(rb_fiber_t *fiber)
void
rb_fiber_mark_self(const rb_fiber_t *fiber)
{
- if (fiber->cont.self) {
- rb_gc_mark_movable(fiber->cont.self);
- }
- else {
- rb_execution_context_mark(&fiber->cont.saved_ec);
- }
+ rb_gc_mark_movable(fiber->cont.self);
}
static void
@@ -1204,12 +1324,13 @@ fiber_memsize(const void *ptr)
VALUE
rb_obj_is_fiber(VALUE obj)
{
- return RBOOL(rb_typeddata_is_kind_of(obj, &fiber_data_type));
+ return RBOOL(rb_typeddata_is_kind_of(obj, &rb_fiber_data_type));
}
static void
cont_save_machine_stack(rb_thread_t *th, rb_context_t *cont)
{
+ const size_t old_stack_size = cont->machine.stack_size;
size_t size;
SET_MACHINE_STACK_END(&th->ec->machine.stack_end);
@@ -1224,10 +1345,10 @@ cont_save_machine_stack(rb_thread_t *th, rb_context_t *cont)
}
if (cont->machine.stack) {
- REALLOC_N(cont->machine.stack, VALUE, size);
+ SIZED_REALLOC_N(cont->machine.stack, VALUE, cont->machine.stack_size, old_stack_size);
}
else {
- cont->machine.stack = ALLOC_N(VALUE, size);
+ cont->machine.stack = ALLOC_N(VALUE, cont->machine.stack_size);
}
FLUSH_REGISTER_WINDOWS;
@@ -1235,9 +1356,23 @@ cont_save_machine_stack(rb_thread_t *th, rb_context_t *cont)
MEMCPY(cont->machine.stack, cont->machine.stack_src, VALUE, size);
}
-static const rb_data_type_t cont_data_type = {
+static void
+cont_handle_weak_references(void *ptr)
+{
+ rb_context_t *cont = ptr;
+
+ if (!cont) return;
+
+ if (!rb_gc_handle_weak_references_alive_p(cont->saved_ec.gen_fields_cache.obj) ||
+ !rb_gc_handle_weak_references_alive_p(cont->saved_ec.gen_fields_cache.fields_obj)) {
+ cont->saved_ec.gen_fields_cache.obj = Qundef;
+ cont->saved_ec.gen_fields_cache.fields_obj = Qundef;
+ }
+}
+
+static const rb_data_type_t rb_cont_data_type = {
"continuation",
- {cont_mark, cont_free, cont_memsize, cont_compact},
+ {cont_mark, cont_free, cont_memsize, cont_compact, cont_handle_weak_references},
0, 0, RUBY_TYPED_FREE_IMMEDIATELY
};
@@ -1268,7 +1403,7 @@ jit_cont_new(rb_execution_context_t *ec)
// We need to use calloc instead of something like ZALLOC to avoid triggering GC here.
// When this function is called from rb_thread_alloc through rb_threadptr_root_fiber_setup,
// the thread is still being prepared and marking it causes SEGV.
- cont = calloc(1, sizeof(struct rb_jit_cont));
+ cont = ruby_mimcalloc(1, sizeof(struct rb_jit_cont));
if (cont == NULL)
rb_memerror();
cont->ec = ec;
@@ -1307,7 +1442,7 @@ jit_cont_free(struct rb_jit_cont *cont)
}
rb_native_mutex_unlock(&jit_cont_lock);
- free(cont);
+ ruby_mimfree(cont);
}
// Call a given callback against all on-stack ISEQs.
@@ -1321,8 +1456,11 @@ rb_jit_cont_each_iseq(rb_iseq_callback callback, void *data)
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);
+ if (CFP_PC(cfp) && CFP_ISEQ(cfp)) {
+ const rb_iseq_t *iseq = CFP_ISEQ(cfp);
+ if (iseq && imemo_type((VALUE)iseq) == imemo_iseq) {
+ callback(iseq, data);
+ }
}
cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
}
@@ -1358,7 +1496,7 @@ rb_jit_cont_finish(void)
struct rb_jit_cont *cont, *next;
for (cont = first_jit_cont; cont != NULL; cont = next) {
next = cont->next;
- free(cont); // Don't use xfree because it's allocated by calloc.
+ ruby_mimfree(cont); // Don't use xfree because it's allocated by mimcalloc.
}
rb_native_mutex_destroy(&jit_cont_lock);
}
@@ -1397,7 +1535,8 @@ cont_new(VALUE klass)
rb_thread_t *th = GET_THREAD();
THREAD_MUST_BE_RUNNING(th);
- contval = TypedData_Make_Struct(klass, rb_context_t, &cont_data_type, cont);
+ contval = TypedData_Make_Struct(klass, rb_context_t, &rb_cont_data_type, cont);
+ rb_gc_declare_weak_references(contval);
cont->self = contval;
cont_init(cont, th);
return cont;
@@ -1441,8 +1580,8 @@ show_vm_pcs(const rb_control_frame_t *cfp,
int i=0;
while (cfp != end_of_cfp) {
int pc = 0;
- if (cfp->iseq) {
- pc = cfp->pc - ISEQ_BODY(cfp->iseq)->iseq_encoded;
+ if (CFP_ISEQ(cfp)) {
+ pc = cfp->pc - ISEQ_BODY(CFP_ISEQ(cfp))->iseq_encoded;
}
fprintf(stderr, "%2d pc: %d\n", i++, pc);
cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
@@ -1466,6 +1605,7 @@ cont_capture(volatile int *volatile stat)
#ifdef CAPTURE_JUST_VALID_VM_STACK
cont->saved_vm_stack.slen = ec->cfp->sp - ec->vm_stack;
cont->saved_vm_stack.clen = ec->vm_stack + ec->vm_stack_size - (VALUE*)ec->cfp;
+ cont->saved_vm_stack.size = cont->saved_vm_stack.slen + cont->saved_vm_stack.clen;
cont->saved_vm_stack.ptr = ALLOC_N(VALUE, cont->saved_vm_stack.slen + cont->saved_vm_stack.clen);
MEMCPY(cont->saved_vm_stack.ptr,
ec->vm_stack,
@@ -1475,6 +1615,7 @@ cont_capture(volatile int *volatile stat)
VALUE,
cont->saved_vm_stack.clen);
#else
+ cont->saved_vm_stack.size = ec->vm_stack_size;
cont->saved_vm_stack.ptr = ALLOC_N(VALUE, ec->vm_stack_size);
MEMCPY(cont->saved_vm_stack.ptr, ec->vm_stack, VALUE, ec->vm_stack_size);
#endif
@@ -1976,16 +2117,38 @@ rb_cont_call(int argc, VALUE *argv, VALUE contval)
*
*/
-static const rb_data_type_t fiber_data_type = {
+static void
+fiber_handle_weak_references(void *ptr)
+{
+ rb_fiber_t *fiber = ptr;
+
+ if (!fiber) return;
+
+ if (!rb_gc_handle_weak_references_alive_p(fiber->cont.saved_ec.gen_fields_cache.obj) ||
+ !rb_gc_handle_weak_references_alive_p(fiber->cont.saved_ec.gen_fields_cache.fields_obj)) {
+ fiber->cont.saved_ec.gen_fields_cache.obj = Qundef;
+ fiber->cont.saved_ec.gen_fields_cache.fields_obj = Qundef;
+ }
+}
+
+static const rb_data_type_t rb_fiber_data_type = {
"fiber",
- {fiber_mark, fiber_free, fiber_memsize, fiber_compact,},
+ {fiber_mark, fiber_free, fiber_memsize, fiber_compact, fiber_handle_weak_references},
0, 0, RUBY_TYPED_FREE_IMMEDIATELY
};
static VALUE
fiber_alloc(VALUE klass)
{
- return TypedData_Wrap_Struct(klass, &fiber_data_type, 0);
+ VALUE obj = TypedData_Wrap_Struct(klass, &rb_fiber_data_type, 0);
+ rb_gc_declare_weak_references(obj);
+ return obj;
+}
+
+static rb_serial_t
+next_ec_serial(rb_ractor_t *cr)
+{
+ return cr->next_ec_serial++;
}
static rb_fiber_t*
@@ -2007,6 +2170,7 @@ fiber_t_alloc(VALUE fiber_value, unsigned int blocking)
cont_init(&fiber->cont, th);
fiber->cont.saved_ec.fiber_ptr = fiber;
+ fiber->cont.saved_ec.serial = next_ec_serial(th->ractor);
rb_ec_clear_vm_stack(&fiber->cont.saved_ec);
fiber->prev = NULL;
@@ -2020,32 +2184,10 @@ fiber_t_alloc(VALUE fiber_value, unsigned int blocking)
return fiber;
}
-static rb_fiber_t *
-root_fiber_alloc(rb_thread_t *th)
-{
- VALUE fiber_value = fiber_alloc(rb_cFiber);
- rb_fiber_t *fiber = th->ec->fiber_ptr;
-
- VM_ASSERT(DATA_PTR(fiber_value) == NULL);
- VM_ASSERT(fiber->cont.type == FIBER_CONTEXT);
- VM_ASSERT(FIBER_RESUMED_P(fiber));
-
- th->root_fiber = fiber;
- DATA_PTR(fiber_value) = fiber;
- fiber->cont.self = fiber_value;
-
- coroutine_initialize_main(&fiber->context);
-
- return fiber;
-}
-
static inline rb_fiber_t*
fiber_current(void)
{
rb_execution_context_t *ec = GET_EC();
- if (ec->fiber_ptr->cont.self == 0) {
- root_fiber_alloc(rb_ec_thread_ptr(ec));
- }
return ec->fiber_ptr;
}
@@ -2178,7 +2320,7 @@ rb_fiber_storage_set(VALUE self, VALUE value)
* Returns the value of the fiber storage variable identified by +key+.
*
* The +key+ must be a symbol, and the value is set by Fiber#[]= or
- * Fiber#store.
+ * Fiber#storage.
*
* See also Fiber::[]=.
*/
@@ -2547,21 +2689,36 @@ 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 = ZALLOC(rb_fiber_t);
if (!fiber) {
rb_bug("%s", strerror(errno)); /* ... is it possible to call rb_bug here? */
}
+
fiber->cont.type = FIBER_CONTEXT;
fiber->cont.saved_ec.fiber_ptr = fiber;
+ fiber->cont.saved_ec.serial = next_ec_serial(th->ractor);
fiber->cont.saved_ec.thread_ptr = th;
fiber->blocking = 1;
fiber->killed = 0;
fiber_status_set(fiber, FIBER_RESUMED); /* skip CREATED */
+
+ coroutine_initialize_main(&fiber->context);
+
th->ec = &fiber->cont.saved_ec;
+
cont_init_jit_cont(&fiber->cont);
}
void
+rb_root_fiber_obj_setup(rb_thread_t *th)
+{
+ rb_fiber_t *fiber = th->ec->fiber_ptr;
+ VALUE fiber_value = fiber_alloc(rb_cFiber);
+ DATA_PTR(fiber_value) = fiber;
+ fiber->cont.self = fiber_value;
+}
+
+void
rb_threadptr_root_fiber_release(rb_thread_t *th)
{
if (th->root_fiber) {
@@ -2631,15 +2788,7 @@ rb_fiber_current(void)
static inline void
fiber_store(rb_fiber_t *next_fiber, rb_thread_t *th)
{
- rb_fiber_t *fiber;
-
- if (th->ec->fiber_ptr != NULL) {
- fiber = th->ec->fiber_ptr;
- }
- else {
- /* create root fiber */
- fiber = root_fiber_alloc(th);
- }
+ rb_fiber_t *fiber = th->ec->fiber_ptr;
if (FIBER_CREATED_P(next_fiber)) {
fiber_prepare_stack(next_fiber);
@@ -2675,7 +2824,9 @@ fiber_switch(rb_fiber_t *fiber, int argc, const VALUE *argv, int kw_splat, rb_fi
rb_thread_t *th = GET_THREAD();
/* make sure the root_fiber object is available */
- if (th->root_fiber == NULL) root_fiber_alloc(th);
+ if (th->root_fiber == NULL) {
+ th->root_fiber = th->ec->fiber_ptr;
+ }
if (th->ec->fiber_ptr == fiber) {
/* ignore fiber context switch
@@ -2740,8 +2891,10 @@ fiber_switch(rb_fiber_t *fiber, int argc, const VALUE *argv, int kw_splat, rb_fi
// We cannot free the stack until the pthread is joined:
#ifndef COROUTINE_PTHREAD_CONTEXT
- if (resuming_fiber && FIBER_TERMINATED_P(fiber)) {
- fiber_stack_release(fiber);
+ if (FIBER_TERMINATED_P(fiber)) {
+ RB_VM_LOCKING() {
+ fiber_stack_release(fiber);
+ }
}
#endif
@@ -2881,6 +3034,7 @@ void
rb_fiber_close(rb_fiber_t *fiber)
{
fiber_status_set(fiber, FIBER_TERMINATED);
+ rb_ec_close(&fiber->cont.saved_ec);
}
static void
@@ -3228,28 +3382,37 @@ rb_fiber_raise(VALUE fiber, int argc, VALUE *argv)
/*
* call-seq:
- * fiber.raise -> obj
- * fiber.raise(string) -> obj
- * fiber.raise(exception [, string [, array]]) -> obj
+ * raise(exception, message = exception.to_s, backtrace = nil, cause: $!)
+ * raise(message = nil, cause: $!)
*
* Raises an exception in the fiber at the point at which the last
- * +Fiber.yield+ was called. If the fiber has not been started or has
+ * +Fiber.yield+ was called.
+ *
+ * f = Fiber.new {
+ * puts "Before the yield"
+ * Fiber.yield 1 # -- exception will be raised here
+ * puts "After the yield"
+ * }
+ *
+ * p f.resume
+ * f.raise "Gotcha"
+ *
+ * Output
+ *
+ * Before the first yield
+ * 1
+ * t.rb:8:in 'Fiber.yield': Gotcha (RuntimeError)
+ * from t.rb:8:in 'block in <main>'
+ *
+ * If the fiber has not been started or has
* already run to completion, raises +FiberError+. If the fiber is
* yielding, it is resumed. If it is transferring, it is transferred into.
* But if it is resuming, raises +FiberError+.
*
- * With no arguments, raises a +RuntimeError+. With a single +String+
- * argument, raises a +RuntimeError+ with the string as a message. Otherwise,
- * the first parameter should be the name of an +Exception+ class (or an
- * object that returns an +Exception+ object when sent an +exception+
- * message). The optional second parameter sets the message associated with
- * 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.
+ * See Kernel#raise for more information on arguments.
+ *
*/
static VALUE
rb_fiber_m_raise(int argc, VALUE *argv, VALUE self)
@@ -3344,6 +3507,8 @@ rb_fiber_atfork(rb_thread_t *th)
th->root_fiber = th->ec->fiber_ptr;
}
th->root_fiber->prev = 0;
+ th->root_fiber->blocking = 1;
+ th->blocking = 1;
}
}
#endif
@@ -3356,7 +3521,7 @@ fiber_pool_free(void *ptr)
RUBY_FREE_ENTER("fiber_pool");
fiber_pool_allocation_free(fiber_pool->allocations);
- ruby_xfree(fiber_pool);
+ SIZED_FREE(fiber_pool);
RUBY_FREE_LEAVE("fiber_pool");
}
@@ -3410,7 +3575,7 @@ rb_fiber_pool_initialize(int argc, VALUE* argv, VALUE self)
TypedData_Get_Struct(self, struct fiber_pool, &FiberPoolDataType, fiber_pool);
- fiber_pool_initialize(fiber_pool, NUM2SIZET(size), NUM2SIZET(count), NUM2SIZET(vm_stack_size));
+ fiber_pool_initialize(fiber_pool, NUM2SIZET(size), NUM2SIZET(count), 0, NUM2SIZET(vm_stack_size));
return self;
}
@@ -3429,6 +3594,46 @@ rb_fiber_pool_initialize(int argc, VALUE* argv, VALUE self)
* fiber.resume #=> FiberError: dead fiber called
*/
+static size_t
+shared_fiber_pool_minimum_count(void)
+{
+ size_t minimum_count = FIBER_POOL_MINIMUM_COUNT;
+
+ const char *minimum_count_env = getenv("RUBY_SHARED_FIBER_POOL_MINIMUM_COUNT");
+ if (minimum_count_env && minimum_count_env[0]) {
+ char *end;
+ unsigned long value = strtoul(minimum_count_env, &end, 10);
+ if (end != minimum_count_env && *end == '\0') {
+ minimum_count = (size_t)value;
+ }
+ else {
+ rb_warn("invalid RUBY_SHARED_FIBER_POOL_MINIMUM_COUNT=%s (expected a non-negative integer)", minimum_count_env);
+ }
+ }
+
+ return minimum_count;
+}
+
+static size_t
+shared_fiber_pool_maximum_count(void)
+{
+ size_t maximum_count = 0;
+
+ const char *maximum_count_env = getenv("RUBY_SHARED_FIBER_POOL_MAXIMUM_COUNT");
+ if (maximum_count_env && maximum_count_env[0]) {
+ char *end;
+ unsigned long value = strtoul(maximum_count_env, &end, 10);
+ if (end != maximum_count_env && *end == '\0') {
+ maximum_count = (size_t)value;
+ }
+ else {
+ rb_warn("invalid RUBY_SHARED_FIBER_POOL_MAXIMUM_COUNT=%s (expected a non-negative integer)", maximum_count_env);
+ }
+ }
+
+ return maximum_count;
+}
+
void
Init_Cont(void)
{
@@ -3446,7 +3651,11 @@ Init_Cont(void)
#endif
SET_MACHINE_STACK_END(&th->ec->machine.stack_end);
- fiber_pool_initialize(&shared_fiber_pool, stack_size, FIBER_POOL_INITIAL_SIZE, vm_stack_size);
+ rb_eFiberError = rb_define_class("FiberError", rb_eStandardError);
+
+ size_t minimum_count = shared_fiber_pool_minimum_count();
+ size_t maximum_count = shared_fiber_pool_maximum_count();
+ fiber_pool_initialize(&shared_fiber_pool, stack_size, minimum_count, maximum_count, vm_stack_size);
fiber_initialize_keywords[0] = rb_intern_const("blocking");
fiber_initialize_keywords[1] = rb_intern_const("pool");
@@ -3468,7 +3677,6 @@ Init_Cont(void)
rb_cFiber = rb_define_class("Fiber", rb_cObject);
rb_define_alloc_func(rb_cFiber, fiber_alloc);
- rb_eFiberError = rb_define_class("FiberError", rb_eStandardError);
rb_define_singleton_method(rb_cFiber, "yield", rb_fiber_s_yield, -1);
rb_define_singleton_method(rb_cFiber, "current", rb_fiber_s_current, 0);
rb_define_singleton_method(rb_cFiber, "blocking", rb_fiber_blocking, 0);
@@ -3496,6 +3704,10 @@ Init_Cont(void)
rb_define_singleton_method(rb_cFiber, "schedule", rb_fiber_s_schedule, -1);
+ rb_thread_t *current_thread = rb_current_thread();
+ RUBY_ASSERT(CLASS_OF(current_thread->ec->fiber_ptr->cont.self) == 0);
+ *(VALUE *)&((struct RBasic *)current_thread->ec->fiber_ptr->cont.self)->klass = rb_cFiber;
+
#ifdef RB_EXPERIMENTAL_FIBER_POOL
/*
* Document-class: Fiber::Pool
diff --git a/coroutine/ppc64le/Context.S b/coroutine/ppc64le/Context.S
index f7bcae2c3a..819264c245 100644
--- a/coroutine/ppc64le/Context.S
+++ b/coroutine/ppc64le/Context.S
@@ -1,11 +1,18 @@
#define TOKEN_PASTE(x,y) x##y
+.abiversion 2
.text
.align 2
.globl PREFIXED_SYMBOL(coroutine_transfer)
.type PREFIXED_SYMBOL(coroutine_transfer), @function
PREFIXED_SYMBOL(coroutine_transfer):
+ # Global entry: set up TOC pointer (r2) from r12.
+ # Required by ELFv2 ABI when this function is reached via the PLT.
+ addis 2, 12, .TOC. - PREFIXED_SYMBOL(coroutine_transfer)@ha
+ addi 2, 2, .TOC. - PREFIXED_SYMBOL(coroutine_transfer)@l
+ .localentry PREFIXED_SYMBOL(coroutine_transfer), .-PREFIXED_SYMBOL(coroutine_transfer)
+
# Make space on the stack for caller registers
addi 1,1,-160
diff --git a/cygwin/GNUmakefile.in b/cygwin/GNUmakefile.in
index 8e83d73040..109baa747d 100644
--- a/cygwin/GNUmakefile.in
+++ b/cygwin/GNUmakefile.in
@@ -6,14 +6,9 @@ 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@
diff --git a/darray.h b/darray.h
index c9035b74b6..d6521be19f 100644
--- a/darray.h
+++ b/darray.h
@@ -4,6 +4,7 @@
#include <stdint.h>
#include <stddef.h>
#include <stdlib.h>
+#include "ruby/ruby.h"
// Type for a dynamic array. Use to declare a dynamic array.
// It is a pointer so it fits in st_table nicely. Designed
@@ -133,6 +134,9 @@ rb_darray_size(const void *ary)
return meta ? meta->size : 0;
}
+/* Estimate of the amount of memory used by this darray.
+ * Useful for TypedData objects. */
+#define rb_darray_memsize(ary) (sizeof(*(ary)) + (rb_darray_size(ary) * sizeof((ary)->data[0])))
static inline void
rb_darray_pop(void *ary, size_t count)
@@ -158,6 +162,16 @@ rb_darray_free(void *ary)
}
static inline void
+rb_darray_free_sized0(void *ary, size_t element_size)
+{
+ const rb_darray_meta_t *meta = ary;
+ if (meta) {
+ ruby_xfree_sized(ary, sizeof(*meta) + (element_size * meta->capa));
+ }
+}
+#define rb_darray_free_sized(ary, T) rb_darray_free_sized0((ary), sizeof(T))
+
+static inline void
rb_darray_free_without_gc(void *ary)
{
free(ary);
@@ -187,13 +201,16 @@ rb_darray_calloc_mul_add_without_gc(size_t x, size_t y, size_t z)
return ptr;
}
+void *ruby_xrealloc_sized(void *ptr, size_t new_size, size_t old_size);
+
/* Internal function. Like rb_xrealloc_mul_add. */
static inline void *
-rb_darray_realloc_mul_add(void *orig_ptr, size_t x, size_t y, size_t z)
+rb_darray_realloc_mul_add(void *orig_ptr, size_t capa, size_t element_size, size_t header_size)
{
- size_t size = rbimpl_size_add_or_raise(rbimpl_size_mul_or_raise(x, y), z);
+ size_t size = rbimpl_size_add_or_raise(rbimpl_size_mul_or_raise(capa, element_size), header_size);
+ size_t old_size = (rb_darray_capa(orig_ptr) * element_size) + header_size; // We know it won't overflow
- void *ptr = xrealloc(orig_ptr, size);
+ void *ptr = ruby_xrealloc_sized(orig_ptr, size, old_size);
RUBY_ASSERT(ptr != NULL);
return ptr;
diff --git a/debug.c b/debug.c
index 4717a0bc9c..730f860e7a 100644
--- a/debug.c
+++ b/debug.c
@@ -57,6 +57,7 @@ const union {
enum ruby_rstring_flags rstring_flags;
enum ruby_rarray_flags rarray_flags;
enum ruby_rarray_consts rarray_consts;
+ enum rbimpl_typeddata_flags rtypeddata_consts;
enum {
RUBY_FMODE_READABLE = FMODE_READABLE,
RUBY_FMODE_WRITABLE = FMODE_WRITABLE,
@@ -168,9 +169,7 @@ ruby_debug_breakpoint(void)
}
#if defined _WIN32
-# if RUBY_MSVCRT_VERSION >= 80
extern int ruby_w32_rtc_error;
-# endif
#endif
#if defined _WIN32 || defined __CYGWIN__
#include <windows.h>
@@ -233,9 +232,7 @@ ruby_env_debug_option(const char *str, int len, void *arg)
SET_WHEN("ci", ruby_on_ci, 1);
SET_WHEN_UINT("rgengc", &ruby_rgengc_debug, 1, ruby_rgengc_debug = 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),
@@ -371,7 +368,7 @@ setup_debug_log_filter(void)
if (len >= MAX_DEBUG_LOG_FILTER_LEN) {
fprintf(stderr, "too long: %s (max:%d)\n", str, MAX_DEBUG_LOG_FILTER_LEN - 1);
- exit(1);
+ exit(EXIT_FAILURE);
}
// body
@@ -399,7 +396,7 @@ setup_debug_log(void)
debug_log.mem = (char *)malloc(MAX_DEBUG_LOG * MAX_DEBUG_LOG_MESSAGE_LEN);
if (debug_log.mem == NULL) {
fprintf(stderr, "setup_debug_log failed (can't allocate memory)\n");
- exit(1);
+ exit(EXIT_FAILURE);
}
ruby_debug_log_mode |= ruby_debug_log_memory;
}
@@ -427,7 +424,7 @@ setup_debug_log(void)
break;
default:
fprintf(stderr, "can not parse RUBY_DEBUG_LOG filename: %s\n", log_config);
- exit(1);
+ exit(EXIT_FAILURE);
}
}
else {
@@ -436,13 +433,13 @@ setup_debug_log(void)
if (j >= DEBUG_LOG_MAX_PATH) {
fprintf(stderr, "RUBY_DEBUG_LOG=%s is too long\n", log_config);
- exit(1);
+ exit(EXIT_FAILURE);
}
}
if ((debug_log.output = fopen(debug_log.output_file, "w")) == NULL) {
fprintf(stderr, "can not open %s for RUBY_DEBUG_LOG\n", log_config);
- exit(1);
+ exit(EXIT_FAILURE);
}
setvbuf(debug_log.output, NULL, _IONBF, 0);
}
@@ -712,4 +709,22 @@ ruby_debug_log_dump(const char *fname, unsigned int n)
fclose(fp);
}
}
+
+#else
+
+#undef ruby_debug_log
+void
+ruby_debug_log(const char *file, int line, const char *func_name, const char *fmt, ...)
+{
+ va_list args;
+
+ fprintf(stderr, "[%s:%d] %s: ", file, line, func_name);
+
+ va_start(args, fmt);
+ vfprintf(stderr, fmt, args);
+ va_end(args);
+
+ fprintf(stderr, "\n");
+}
+
#endif // #if USE_RUBY_DEBUG_LOG
diff --git a/debug_counter.h b/debug_counter.h
index c8d8ed8f11..721ff9d1b8 100644
--- a/debug_counter.h
+++ b/debug_counter.h
@@ -240,7 +240,7 @@ RB_DEBUG_COUNTER(obj_wb_unprotect)
RB_DEBUG_COUNTER(obj_obj_embed)
RB_DEBUG_COUNTER(obj_obj_ptr)
-RB_DEBUG_COUNTER(obj_obj_too_complex)
+RB_DEBUG_COUNTER(obj_obj_complex)
RB_DEBUG_COUNTER(obj_str_ptr)
RB_DEBUG_COUNTER(obj_str_embed)
@@ -305,6 +305,7 @@ RB_DEBUG_COUNTER(obj_imemo_ment)
RB_DEBUG_COUNTER(obj_imemo_iseq)
RB_DEBUG_COUNTER(obj_imemo_env)
RB_DEBUG_COUNTER(obj_imemo_tmpbuf)
+RB_DEBUG_COUNTER(obj_imemo_cvar_entry)
RB_DEBUG_COUNTER(obj_imemo_cref)
RB_DEBUG_COUNTER(obj_imemo_svar)
RB_DEBUG_COUNTER(obj_imemo_throw_data)
@@ -314,6 +315,8 @@ RB_DEBUG_COUNTER(obj_imemo_callinfo)
RB_DEBUG_COUNTER(obj_imemo_callcache)
RB_DEBUG_COUNTER(obj_imemo_constcache)
RB_DEBUG_COUNTER(obj_imemo_fields)
+RB_DEBUG_COUNTER(obj_imemo_subclasses)
+RB_DEBUG_COUNTER(obj_imemo_cdhash)
RB_DEBUG_COUNTER(opt_new_hit)
RB_DEBUG_COUNTER(opt_new_miss)
diff --git a/defs/gmake.mk b/defs/gmake.mk
index bd4b8b8e39..0320f9b7d5 100644
--- a/defs/gmake.mk
+++ b/defs/gmake.mk
@@ -2,6 +2,7 @@
reconfig config.status: export MAKE:=$(MAKE)
export BASERUBY:=$(BASERUBY)
+export GIT
override gnumake_recursive := $(if $(findstring n,$(firstword $(MFLAGS))),,+)
override mflags := $(filter-out -j%,$(MFLAGS))
MSPECOPT += $(if $(filter -j%,$(MFLAGS)),-j)
@@ -161,6 +162,10 @@ endif
config.status: $(wildcard config.cache)
+ifneq (ruby,$(PROGRAM))
+ruby: $(PROGRAM);
+endif
+
STUBPROGRAM = rubystub$(EXEEXT)
IGNOREDPATTERNS = %~ .% %.orig %.rej \#%\#
SCRIPTBINDIR := $(if $(EXEEXT),,exec/)
@@ -216,8 +221,8 @@ post-commit: $(if $(DOT_WAIT),,do-commit)
GITHUB_RUBY_URL = https://github.com/ruby/ruby
PR =
-COMMIT_GPG_SIGN = $(shell $(GIT) -C "$(srcdir)" config commit.gpgsign)
-REMOTE_GITHUB_URL = $(shell $(GIT) -C "$(srcdir)" config remote.github.url)
+COMMIT_GPG_SIGN = $(shell $(GIT_IN_SRC) config commit.gpgsign)
+REMOTE_GITHUB_URL = $(shell $(GIT_IN_SRC) config remote.github.url)
COMMITS_NOTES = commits
.PHONY: fetch-github
@@ -232,19 +237,19 @@ define fetch-github
$(eval REMOTE_GITHUB_URL := $(REMOTE_GITHUB_URL))
$(if $(REMOTE_GITHUB_URL),,
echo adding $(GITHUB_RUBY_URL) as remote github
- $(GIT) -C "$(srcdir)" remote add github $(GITHUB_RUBY_URL)
- $(GIT) -C "$(srcdir)" config --add remote.github.fetch +refs/notes/$(COMMITS_NOTES):refs/notes/$(COMMITS_NOTES)
+ $(GIT_IN_SRC) remote add github $(GITHUB_RUBY_URL)
+ $(GIT_IN_SRC) config --add remote.github.fetch +refs/notes/$(COMMITS_NOTES):refs/notes/$(COMMITS_NOTES)
$(eval REMOTE_GITHUB_URL := $(GITHUB_RUBY_URL))
)
- $(if $(shell $(GIT) -C "$(srcdir)" rev-parse "github/pull/$(1)/head" -- 2> /dev/null),
- $(GIT) -C "$(srcdir)" branch -f "gh-$(1)" "github/pull/$(1)/head",
- $(GIT) -C "$(srcdir)" fetch -f github "pull/$(1)/head:gh-$(1)"
+ $(if $(shell $(GIT_IN_SRC) rev-parse "github/pull/$(1)/head" -- 2> /dev/null),
+ $(GIT_IN_SRC) branch -f "gh-$(1)" "github/pull/$(1)/head",
+ $(GIT_IN_SRC) fetch -f github "pull/$(1)/head:gh-$(1)"
)
endef
.PHONY: checkout-github
checkout-github: fetch-github
- $(GIT) -C "$(srcdir)" checkout "gh-$(PR)"
+ $(GIT_IN_SRC) checkout "gh-$(PR)"
.PHONY: update-github
update-github: fetch-github
@@ -257,25 +262,25 @@ update-github: fetch-github
$(eval PR_BRANCH := $(word 2,$(PULL_REQUEST_FORK_BRANCH)))
$(eval GITHUB_UPDATE_WORKTREE := $(shell mktemp -d "$(srcdir)/gh-$(PR)-XXXXXX"))
- $(GIT) -C "$(srcdir)" worktree add $(notdir $(GITHUB_UPDATE_WORKTREE)) "gh-$(PR)"
+ $(GIT_IN_SRC) worktree add $(notdir $(GITHUB_UPDATE_WORKTREE)) "gh-$(PR)"
$(GIT) -C "$(GITHUB_UPDATE_WORKTREE)" merge master --no-edit
@$(BASERUBY) -e 'print "Are you sure to push this to PR=$(PR)? [Y/n]: "; exit(gets.chomp != "n")'
- $(GIT) -C "$(srcdir)" remote add fork-$(PR) git@github.com:$(FORK_REPO).git
+ $(GIT_IN_SRC) remote add fork-$(PR) git@github.com:$(FORK_REPO).git
$(GIT) -C "$(GITHUB_UPDATE_WORKTREE)" push fork-$(PR) gh-$(PR):$(PR_BRANCH)
- $(GIT) -C "$(srcdir)" remote rm fork-$(PR)
- $(GIT) -C "$(srcdir)" worktree remove $(notdir $(GITHUB_UPDATE_WORKTREE))
- $(GIT) -C "$(srcdir)" branch -D gh-$(PR)
+ $(GIT_IN_SRC) remote rm fork-$(PR)
+ $(GIT_IN_SRC) worktree remove $(notdir $(GITHUB_UPDATE_WORKTREE))
+ $(GIT_IN_SRC) branch -D gh-$(PR)
.PHONY: pull-github
pull-github: fetch-github
$(call pull-github,$(PR))
define pull-github
- $(eval GITHUB_MERGE_BASE := $(shell $(GIT) -C "$(srcdir)" log -1 --format=format:%H))
- $(eval GITHUB_MERGE_BRANCH := $(shell $(GIT) -C "$(srcdir)" symbolic-ref --short HEAD))
+ $(eval GITHUB_MERGE_BASE := $(shell $(GIT_IN_SRC) rev-parse HEAD)
+ $(eval GITHUB_MERGE_BRANCH := $(shell $(GIT_IN_SRC) symbolic-ref --short HEAD))
$(eval GITHUB_MERGE_WORKTREE := $(shell mktemp -d "$(srcdir)/gh-$(1)-XXXXXX"))
- $(GIT) -C "$(srcdir)" worktree prune
- $(GIT) -C "$(srcdir)" worktree add $(notdir $(GITHUB_MERGE_WORKTREE)) "gh-$(1)"
+ $(GIT_IN_SRC) worktree prune
+ $(GIT_IN_SRC) worktree add $(notdir $(GITHUB_MERGE_WORKTREE)) "gh-$(1)"
$(GIT) -C "$(GITHUB_MERGE_WORKTREE)" rebase $(GITHUB_MERGE_BRANCH)
$(eval COMMIT_GPG_SIGN := $(COMMIT_GPG_SIGN))
$(if $(filter true,$(COMMIT_GPG_SIGN)), \
@@ -290,7 +295,7 @@ fetch-github-%:
.PHONY: checkout-github-%
checkout-github-%: fetch-github-%
- $(GIT) -C "$(srcdir)" checkout "gh-$*"
+ $(GIT_IN_SRC) checkout "gh-$*"
.PHONY: pr-% pull-github-%
pr-% pull-github-%: fetch-github-%
@@ -406,6 +411,7 @@ $(srcdir)/.bundle/gems:
ifneq ($(DOT_WAIT),)
up:: $(DOT_WAIT) after-update
+after-update:: MINIRUBY = $(BASERUBY)
endif
ifneq ($(filter update-bundled_gems refresh-gems,$(MAKECMDGOALS)),)
@@ -429,7 +435,7 @@ ifneq ($(DOT_WAIT),)
endif
ifeq ($(HAVE_GIT),yes)
-REVISION_LATEST := $(shell $(CHDIR) $(srcdir) && $(GIT) log -1 --format=%H 2>/dev/null)
+REVISION_LATEST := $(shell $(GIT_IN_SRC) rev-parse HEAD 2>/dev/null)
else
REVISION_LATEST := update
endif
@@ -448,8 +454,10 @@ include $(top_srcdir)/defs/jit.mk
# Query on the generated rdoc
#
# $ make rdoc:Integer#+
-rdoc\:%: PHONY
- $(Q)$(RUNRUBY) $(srcdir)/libexec/ri --no-standard-docs --doc-dir=$(RDOCOUT) $(patsubst rdoc:%,%,$@)
+rdoc\:%: PHONY programs $(RDOCOUT) update-default-gemspecs
+ $(Q)$(RUNRUBY) $(RUNOPT0) -I$(tooldir)/lib -rbundled_gem \
+ -e "load BundledGem.command('rdoc', 'ri')" -- \
+ --no-standard-docs --doc-dir=$(RDOCOUT) $(patsubst rdoc:%,%,$@)
test_%.rb test/%: programs PHONY
$(Q)$(exec) $(RUNRUBY) "$(TESTSDIR)/runner.rb" --ruby="$(RUNRUBY)" $(TEST_EXCLUDES) $(TESTOPTS) -- $(patsubst test/%,%,$@)
@@ -491,7 +499,7 @@ endif
update-deps:
$(eval update_deps := $(shell date +update-deps-%Y%m%d))
$(eval deps_dir := $(shell mktemp -d)/$(update_deps))
- $(eval GIT_DIR := $(shell $(GIT) -C $(srcdir) rev-parse --absolute-git-dir))
+ $(eval GIT_DIR := $(shell $(GIT_IN_SRC) rev-parse --absolute-git-dir))
$(GIT) --git-dir=$(GIT_DIR) worktree add $(deps_dir)
cp $(tooldir)/config.guess $(tooldir)/config.sub $(deps_dir)/tool
[ -f config.status ] && cp config.status $(deps_dir)
@@ -511,8 +519,8 @@ fix-depends check-depends: all hello
# order-only-prerequisites doesn't work for $(RUBYSPEC_CAPIEXT)
# because the same named directory exists in the source tree.
$(RUBYSPEC_CAPIEXT)/%.$(DLEXT): $(srcdir)/$(RUBYSPEC_CAPIEXT)/%.c $(RUBYSPEC_CAPIEXT_DEPS) \
- | build-ext
- $(ECHO) building $@
+ | build-ext yes-rubyspec-capiext
+ $(no_silence:no=$(ECHO) building $@)
$(Q) $(MAKEDIRS) $(@D)
$(Q) $(DLDSHARED) -L. $(XDLDFLAGS) $(XLDFLAGS) $(LDFLAGS) $(INCFLAGS) $(CPPFLAGS) $(OUTFLAG)$@ $< $(LIBRUBYARG)
ifneq ($(POSTLINK),)
@@ -520,43 +528,86 @@ ifneq ($(POSTLINK),)
endif
$(Q) $(RMALL) $@.*
-RUBYSPEC_CAPIEXT_SO := $(patsubst %.c,$(RUBYSPEC_CAPIEXT)/%.$(DLEXT),$(notdir $(wildcard $(srcdir)/$(RUBYSPEC_CAPIEXT)/*.c)))
-rubyspec-capiext: $(RUBYSPEC_CAPIEXT_SO)
- @ $(NULLCMD)
+RUBYSPEC_CAPIEXT_EXTS := $(patsubst %.c,$(RUBYSPEC_CAPIEXT)/%.$(DLEXT),$(notdir $(wildcard $(srcdir)/$(RUBYSPEC_CAPIEXT)/*.c)))
+rubyspec-capiext: $(RUBYSPEC_CAPIEXT_EXTS)
-ifeq ($(ENABLE_SHARED),yes)
-exts: rubyspec-capiext
-endif
-
-spec/%/ spec/%_spec.rb: programs exts PHONY
+spec/%/ spec/%_spec.rb: programs exts $(RUBYSPEC_CAPIEXT_BUILD) 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))
+# `make matz`: bump up the MINOR;
+# Copying NEWS.md to doc/NEWS/, and empty the details in NEWS.md.
+#
+# `make matz NEW=x.y`: bump up to x.y.0;
+# Just update the version in the title of NEWS.md.
+
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"
+matz-commit: OLD := $(MAJOR).$(MINOR).0
+ifdef NEW
+matz-commit: MAJOR := $(word 1,$(subst ., ,$(NEW)))
+matz-commit: MINOR := $(word 2,$(subst ., ,$(NEW)))
+matz-commit: $(DOT_WAIT) bump_news
+bump_news$(DOT_WAIT): up
+bump_headers$(DOT_WAIT): bump_news
+else
+matz-commit: MINOR := $(shell expr $(MINOR) + 1)
+matz-commit: $(DOT_WAIT) reset_news
+flush_news$(DOT_WAIT): up
+bump_headers$(DOT_WAIT): reset_news
+endif
+
+matz: $(DOT_WAIT) matz-commit
+matz-commit: bump_headers
+matz-commit: override NEW := $(MAJOR).$(MINOR).0
+matz-commit: files := include/ruby/version.h include/ruby/internal/abi.h
+matz-commit: message := Development of $(NEW) started.
+
+flush_news:
+ $(GIT_IN_SRC) mv -f NEWS.md doc/NEWS/NEWS-$(OLD).md
+ $(GIT_IN_SRC) commit -m "[DOC] Flush NEWS.md"
+
+.PHONY: flush_news reset_news bump_news bump_headers
+
+bump_headers:
sed -i~ \
+ -e "s/^\(#define RUBY_API_VERSION_MAJOR\) .*/\1 $(MAJOR)/" \
-e "s/^\(#define RUBY_API_VERSION_MINOR\) .*/\1 $(MINOR)/" \
-e "s/^\(#define RUBY_ABI_VERSION\) .*/\1 0/" \
$(files:%=$(srcdir)/%)
- $(GIT) -C $(srcdir) add $(files)
+
+reset_news: flush_news
$(BASERUBY) -C $(srcdir) -p -00 \
- -e 'BEGIN {old, new = ARGV.shift(2); STDOUT.reopen("NEWS.md")}' \
+ -e 'BEGIN {old, new = ARGV.shift(2); STDOUT.reopen(ARGV.shift)}' \
-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)"
+ $(OLD) $(NEW) NEWS.md doc/NEWS/NEWS-$(OLD).md
+
+bump_news:
+ $(BASERUBY) -C $(srcdir) -p -i \
+ -e 'BEGIN {new = ARGV.shift; print gets("").sub(/Ruby \K[0-9.]+/, new)}' \
+ $(NEW) NEWS.md
+
+matz: matz-commit matz-push
+
+matz-commit:
+ $(GIT_IN_SRC) add NEWS.md $(files)
+ $(GIT_IN_SRC) commit -m "$(message)"
+
+GIT_REMOTE_ORIGIN = origin
+
+matz-push: matz-commit
+ $(eval origin_url := $(shell $(GIT_IN_SRC) remote get-url $(GIT_REMOTE_ORIGIN)))
+ $(if $(origin_url),,@false)
+ $(eval last_commit := $(shell $(GIT_IN_SRC) log -n1 --format=%H --author=matz HEAD~..HEAD))
+ $(if $(last_commit),,$(ECHO) No matz commits 1>&2; false)
+ $(if $(filter 12-25 12-26,$(shell date +%m-%d)),,$(ECHO) Not the release date 1>&2; false)
+ $(ECHO) $$'\e[31m'Pushing to $$'\e[7m'$(GIT_REMOTE_ORIGIN)$$'\e[27m'" ($(origin_url))"$$'\e[m'
+ $(GIT_IN_SRC) push $(GIT_REMOTE_ORIGIN)
tags:
$(MAKE) GIT="$(GIT)" -C "$(srcdir)" -f defs/tags.mk
diff --git a/defs/id.def b/defs/id.def
index 0c32b0d1d4..344b072e76 100644
--- a/defs/id.def
+++ b/defs/id.def
@@ -28,6 +28,7 @@ firstline, predefined = __LINE__+1, %[\
send
__send__
__recursive_key__
+ clone
initialize
initialize_copy
initialize_clone
@@ -78,6 +79,8 @@ firstline, predefined = __LINE__+1, %[\
_7 NUMPARAM_7
_8 NUMPARAM_8
_9 NUMPARAM_9
+ <it> ItImplicit
+ it It
"/*NULL*/" NULL
empty?
diff --git a/defs/jit.mk b/defs/jit.mk
index 28d8f2da3a..2c1e819684 100644
--- a/defs/jit.mk
+++ b/defs/jit.mk
@@ -1,10 +1,9 @@
# Make recipes that deal with the rust code of YJIT and ZJIT.
-
-# Because of Cargo cache, if the actual binary is not changed from the
-# previous build, the mtime is preserved as the cached file.
-# This means the target is not updated actually, and it will need to
-# rebuild at the next build.
-RUST_LIB_TOUCH = touch $@
+#
+# $(gnumake_recursive) adds the '+' prefix to pass down GNU make's
+# jobserver resources to cargo/rustc as rust-lang.org recommends.
+# Without it, certain make version trigger a warning. It does not
+# add the prefix when `make --dry-run` so dry runs are indeed dry.
ifneq ($(JIT_CARGO_SUPPORT),no)
@@ -13,11 +12,17 @@ CARGO_VERBOSE_0 = -q
CARGO_VERBOSE_1 =
CARGO_VERBOSE = $(CARGO_VERBOSE_$(V))
+# Because of Cargo cache, if the actual binary is not changed from the
+# previous build, the mtime is preserved as the cached file.
+# This means the target is not updated actually, and it will need to
+# rebuild at the next build.
+RUST_LIB_TOUCH = touch $@
+
# NOTE: MACOSX_DEPLOYMENT_TARGET to match `rustc --print deployment-target` to avoid the warning below.
# ld: warning: object file (target/debug/libjit.a(<libcapstone object>)) was built for
# newer macOS version (15.2) than being linked (15.0)
# This limits us to an older set of macOS API in the rust code, but we don't use any.
-$(RUST_LIB): $(srcdir)/jit.rs
+$(RUST_LIB): $(srcdir)/ruby.rs target/.rustc-version
$(Q)if [ '$(ZJIT_SUPPORT)' != no -a '$(YJIT_SUPPORT)' != no ]; then \
echo 'building YJIT and ZJIT ($(JIT_CARGO_SUPPORT:yes=release) mode)'; \
elif [ '$(ZJIT_SUPPORT)' != no ]; then \
@@ -25,12 +30,39 @@ $(RUST_LIB): $(srcdir)/jit.rs
elif [ '$(YJIT_SUPPORT)' != no ]; then \
echo 'building YJIT ($(JIT_CARGO_SUPPORT) mode)'; \
fi
- +$(Q)CARGO_TARGET_DIR='$(CARGO_TARGET_DIR)' \
+ $(gnumake_recursive)$(Q)CARGO_TARGET_DIR='$(CARGO_TARGET_DIR)' \
CARGO_TERM_PROGRESS_WHEN='never' \
MACOSX_DEPLOYMENT_TARGET=11.0 \
$(CARGO) $(CARGO_VERBOSE) build --manifest-path '$(top_srcdir)/Cargo.toml' $(CARGO_BUILD_ARGS)
$(RUST_LIB_TOUCH)
-endif
+else ifneq ($(strip $(RLIB_DIR)),) # combo build
+
+$(RUST_LIB): $(srcdir)/ruby.rs target/.rustc-version
+ $(ECHO) 'building $(@F)'
+ $(gnumake_recursive)$(Q) $(RUSTC) --edition=2024 \
+ $(RUSTC_FLAGS) \
+ '-L$(@D)' \
+ --extern=yjit \
+ --extern=zjit \
+ --crate-type=staticlib \
+ --cfg 'feature="yjit"' \
+ --cfg 'feature="zjit"' \
+ '--out-dir=$(@D)' \
+ '$(top_srcdir)/ruby.rs'
+
+# Absolute path to avoid VPATH ambiguity
+JIT_RLIB = $(TOP_BUILD_DIR)/$(RLIB_DIR)/libjit.rlib
+$(YJIT_RLIB): $(JIT_RLIB)
+$(ZJIT_RLIB): $(JIT_RLIB)
+$(JIT_RLIB): target/.rustc-version
+ $(ECHO) 'building $(@F)'
+ $(gnumake_recursive)$(Q) $(RUSTC) --crate-name=jit \
+ --edition=2024 \
+ $(JIT_RUST_FLAGS) \
+ $(RUSTC_FLAGS) \
+ '--out-dir=$(@D)' \
+ '$(top_srcdir)/jit/src/lib.rs'
+endif # ifneq ($(JIT_CARGO_SUPPORT),no)
RUST_LIB_SYMBOLS = $(RUST_LIB:.a=).symbols
$(RUST_LIBOBJ): $(RUST_LIB)
@@ -45,6 +77,17 @@ endif
rust-libobj: $(RUST_LIBOBJ)
rust-lib: $(RUST_LIB)
+rustc-version-check: target/.rustc-version
+
+target/.rustc-version: PHONY
+ $(eval prev_version := $(if $(wildcard $@),$(shell cat $@)))
+ $(eval curr_version := $(shell $(RUSTC) -V | cut -d' ' -f2))
+ $(eval clean := $(filter-out $(prev_version),$(curr_version)))
+ $(if $(clean),$(ECHO) Cleaning $(@D) for rustc $(curr_version))
+ $(if $(clean),$(Q)$(RMALL) $(@D))
+ $(if $(clean),$(Q)$(MAKEDIRS) $(@D))
+ $(if $(clean),$(Q)echo $(curr_version) > $@)
+
# For Darwin only: a list of symbols that we want the glommed Rust static lib to export.
# Unfortunately, using wildcard like '_rb_*' with -exported-symbol does not work, at least
# not on version 820.1. Assume llvm-nm, so XCode 8.0 (from 2016) or newer.
diff --git a/defs/opt_insn_unif.def b/defs/opt_insn_unif.def
index 31ae2eb6a1..5ce67538f1 100644
--- a/defs/opt_insn_unif.def
+++ b/defs/opt_insn_unif.def
@@ -6,12 +6,12 @@
__END__
putobject putobject
-putobject putstring
+putobject dupstring
putobject setlocal
-putstring putstring
-putstring putobject
-putstring setlocal
+dupstring dupstring
+dupstring putobject
+dupstring setlocal
# putnil end
diff --git a/depend b/depend
index 7fdf369158..a2e8312298 100644
--- a/depend
+++ b/depend
@@ -63,6 +63,7 @@ array.$(OBJEXT): $(top_srcdir)/internal/array.h
array.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
array.$(OBJEXT): $(top_srcdir)/internal/bignum.h
array.$(OBJEXT): $(top_srcdir)/internal/bits.h
+array.$(OBJEXT): $(top_srcdir)/internal/box.h
array.$(OBJEXT): $(top_srcdir)/internal/class.h
array.$(OBJEXT): $(top_srcdir)/internal/compar.h
array.$(OBJEXT): $(top_srcdir)/internal/compilers.h
@@ -71,7 +72,6 @@ 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/namespace.h
array.$(OBJEXT): $(top_srcdir)/internal/numeric.h
array.$(OBJEXT): $(top_srcdir)/internal/object.h
array.$(OBJEXT): $(top_srcdir)/internal/proc.h
@@ -80,6 +80,7 @@ array.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
array.$(OBJEXT): $(top_srcdir)/internal/serial.h
array.$(OBJEXT): $(top_srcdir)/internal/set_table.h
array.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
+array.$(OBJEXT): $(top_srcdir)/internal/struct.h
array.$(OBJEXT): $(top_srcdir)/internal/variable.h
array.$(OBJEXT): $(top_srcdir)/internal/vm.h
array.$(OBJEXT): $(top_srcdir)/internal/warnings.h
@@ -263,6 +264,7 @@ array.$(OBJEXT): {$(VPATH)}onigmo.h
array.$(OBJEXT): {$(VPATH)}oniguruma.h
array.$(OBJEXT): {$(VPATH)}probes.dmyh
array.$(OBJEXT): {$(VPATH)}probes.h
+array.$(OBJEXT): {$(VPATH)}ractor.h
array.$(OBJEXT): {$(VPATH)}ruby_assert.h
array.$(OBJEXT): {$(VPATH)}ruby_atomic.h
array.$(OBJEXT): {$(VPATH)}rubyparser.h
@@ -285,12 +287,13 @@ 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/box.h
+ast.$(OBJEXT): $(top_srcdir)/internal/compar.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/namespace.h
ast.$(OBJEXT): $(top_srcdir)/internal/numeric.h
ast.$(OBJEXT): $(top_srcdir)/internal/parse.h
ast.$(OBJEXT): $(top_srcdir)/internal/rational.h
@@ -299,32 +302,45 @@ ast.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
ast.$(OBJEXT): $(top_srcdir)/internal/serial.h
ast.$(OBJEXT): $(top_srcdir)/internal/set_table.h
ast.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
+ast.$(OBJEXT): $(top_srcdir)/internal/struct.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/arena.h
ast.$(OBJEXT): $(top_srcdir)/prism/ast.h
-ast.$(OBJEXT): $(top_srcdir)/prism/defines.h
+ast.$(OBJEXT): $(top_srcdir)/prism/buffer.h
+ast.$(OBJEXT): $(top_srcdir)/prism/comments.h
+ast.$(OBJEXT): $(top_srcdir)/prism/compiler/align.h
+ast.$(OBJEXT): $(top_srcdir)/prism/compiler/exported.h
+ast.$(OBJEXT): $(top_srcdir)/prism/compiler/filesystem.h
+ast.$(OBJEXT): $(top_srcdir)/prism/compiler/nodiscard.h
+ast.$(OBJEXT): $(top_srcdir)/prism/compiler/nonnull.h
+ast.$(OBJEXT): $(top_srcdir)/prism/constant_pool.h
ast.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h
-ast.$(OBJEXT): $(top_srcdir)/prism/encoding.h
+ast.$(OBJEXT): $(top_srcdir)/prism/excludes.h
+ast.$(OBJEXT): $(top_srcdir)/prism/integer.h
+ast.$(OBJEXT): $(top_srcdir)/prism/internal/char.h
+ast.$(OBJEXT): $(top_srcdir)/prism/internal/encoding.h
+ast.$(OBJEXT): $(top_srcdir)/prism/internal/list.h
+ast.$(OBJEXT): $(top_srcdir)/prism/internal/memchr.h
+ast.$(OBJEXT): $(top_srcdir)/prism/internal/regexp.h
+ast.$(OBJEXT): $(top_srcdir)/prism/internal/static_literals.h
+ast.$(OBJEXT): $(top_srcdir)/prism/internal/strncasecmp.h
+ast.$(OBJEXT): $(top_srcdir)/prism/internal/strpbrk.h
+ast.$(OBJEXT): $(top_srcdir)/prism/json.h
+ast.$(OBJEXT): $(top_srcdir)/prism/line_offset_list.h
+ast.$(OBJEXT): $(top_srcdir)/prism/magic_comments.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): $(top_srcdir)/prism/serialize.h
+ast.$(OBJEXT): $(top_srcdir)/prism/source.h
+ast.$(OBJEXT): $(top_srcdir)/prism/stream.h
+ast.$(OBJEXT): $(top_srcdir)/prism/string_query.h
+ast.$(OBJEXT): $(top_srcdir)/prism/stringy.h
ast.$(OBJEXT): $(top_srcdir)/prism/version.h
ast.$(OBJEXT): {$(VPATH)}assert.h
ast.$(OBJEXT): {$(VPATH)}ast.c
@@ -505,6 +521,7 @@ ast.$(OBJEXT): {$(VPATH)}node.h
ast.$(OBJEXT): {$(VPATH)}onigmo.h
ast.$(OBJEXT): {$(VPATH)}oniguruma.h
ast.$(OBJEXT): {$(VPATH)}prism_compile.h
+ast.$(OBJEXT): {$(VPATH)}prism_xallocator.h
ast.$(OBJEXT): {$(VPATH)}ruby_assert.h
ast.$(OBJEXT): {$(VPATH)}ruby_atomic.h
ast.$(OBJEXT): {$(VPATH)}rubyparser.h
@@ -525,19 +542,21 @@ 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/box.h
bignum.$(OBJEXT): $(top_srcdir)/internal/class.h
+bignum.$(OBJEXT): $(top_srcdir)/internal/compar.h
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/namespace.h
bignum.$(OBJEXT): $(top_srcdir)/internal/numeric.h
bignum.$(OBJEXT): $(top_srcdir)/internal/object.h
bignum.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
bignum.$(OBJEXT): $(top_srcdir)/internal/serial.h
bignum.$(OBJEXT): $(top_srcdir)/internal/set_table.h
bignum.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
+bignum.$(OBJEXT): $(top_srcdir)/internal/struct.h
bignum.$(OBJEXT): $(top_srcdir)/internal/variable.h
bignum.$(OBJEXT): $(top_srcdir)/internal/vm.h
bignum.$(OBJEXT): $(top_srcdir)/internal/warnings.h
@@ -728,6 +747,270 @@ bignum.$(OBJEXT): {$(VPATH)}thread_native.h
bignum.$(OBJEXT): {$(VPATH)}util.h
bignum.$(OBJEXT): {$(VPATH)}vm_core.h
bignum.$(OBJEXT): {$(VPATH)}vm_opts.h
+box.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
+box.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
+box.$(OBJEXT): $(CCAN_DIR)/list/list.h
+box.$(OBJEXT): $(CCAN_DIR)/str/str.h
+box.$(OBJEXT): $(hdrdir)/ruby/ruby.h
+box.$(OBJEXT): $(top_srcdir)/internal/array.h
+box.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
+box.$(OBJEXT): $(top_srcdir)/internal/box.h
+box.$(OBJEXT): $(top_srcdir)/internal/class.h
+box.$(OBJEXT): $(top_srcdir)/internal/compilers.h
+box.$(OBJEXT): $(top_srcdir)/internal/error.h
+box.$(OBJEXT): $(top_srcdir)/internal/eval.h
+box.$(OBJEXT): $(top_srcdir)/internal/file.h
+box.$(OBJEXT): $(top_srcdir)/internal/gc.h
+box.$(OBJEXT): $(top_srcdir)/internal/hash.h
+box.$(OBJEXT): $(top_srcdir)/internal/imemo.h
+box.$(OBJEXT): $(top_srcdir)/internal/io.h
+box.$(OBJEXT): $(top_srcdir)/internal/load.h
+box.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
+box.$(OBJEXT): $(top_srcdir)/internal/serial.h
+box.$(OBJEXT): $(top_srcdir)/internal/set_table.h
+box.$(OBJEXT): $(top_srcdir)/internal/st.h
+box.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
+box.$(OBJEXT): $(top_srcdir)/internal/string.h
+box.$(OBJEXT): $(top_srcdir)/internal/struct.h
+box.$(OBJEXT): $(top_srcdir)/internal/variable.h
+box.$(OBJEXT): $(top_srcdir)/internal/vm.h
+box.$(OBJEXT): $(top_srcdir)/internal/warnings.h
+box.$(OBJEXT): $(top_srcdir)/prism/arena.h
+box.$(OBJEXT): $(top_srcdir)/prism/ast.h
+box.$(OBJEXT): $(top_srcdir)/prism/buffer.h
+box.$(OBJEXT): $(top_srcdir)/prism/comments.h
+box.$(OBJEXT): $(top_srcdir)/prism/compiler/align.h
+box.$(OBJEXT): $(top_srcdir)/prism/compiler/exported.h
+box.$(OBJEXT): $(top_srcdir)/prism/compiler/filesystem.h
+box.$(OBJEXT): $(top_srcdir)/prism/compiler/nodiscard.h
+box.$(OBJEXT): $(top_srcdir)/prism/compiler/nonnull.h
+box.$(OBJEXT): $(top_srcdir)/prism/constant_pool.h
+box.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h
+box.$(OBJEXT): $(top_srcdir)/prism/excludes.h
+box.$(OBJEXT): $(top_srcdir)/prism/integer.h
+box.$(OBJEXT): $(top_srcdir)/prism/internal/char.h
+box.$(OBJEXT): $(top_srcdir)/prism/internal/encoding.h
+box.$(OBJEXT): $(top_srcdir)/prism/internal/list.h
+box.$(OBJEXT): $(top_srcdir)/prism/internal/memchr.h
+box.$(OBJEXT): $(top_srcdir)/prism/internal/regexp.h
+box.$(OBJEXT): $(top_srcdir)/prism/internal/static_literals.h
+box.$(OBJEXT): $(top_srcdir)/prism/internal/strncasecmp.h
+box.$(OBJEXT): $(top_srcdir)/prism/internal/strpbrk.h
+box.$(OBJEXT): $(top_srcdir)/prism/json.h
+box.$(OBJEXT): $(top_srcdir)/prism/line_offset_list.h
+box.$(OBJEXT): $(top_srcdir)/prism/magic_comments.h
+box.$(OBJEXT): $(top_srcdir)/prism/node.h
+box.$(OBJEXT): $(top_srcdir)/prism/options.h
+box.$(OBJEXT): $(top_srcdir)/prism/parser.h
+box.$(OBJEXT): $(top_srcdir)/prism/prettyprint.h
+box.$(OBJEXT): $(top_srcdir)/prism/prism.h
+box.$(OBJEXT): $(top_srcdir)/prism/serialize.h
+box.$(OBJEXT): $(top_srcdir)/prism/source.h
+box.$(OBJEXT): $(top_srcdir)/prism/stream.h
+box.$(OBJEXT): $(top_srcdir)/prism/string_query.h
+box.$(OBJEXT): $(top_srcdir)/prism/stringy.h
+box.$(OBJEXT): $(top_srcdir)/prism/version.h
+box.$(OBJEXT): {$(VPATH)}assert.h
+box.$(OBJEXT): {$(VPATH)}atomic.h
+box.$(OBJEXT): {$(VPATH)}backward/2/assume.h
+box.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
+box.$(OBJEXT): {$(VPATH)}backward/2/bool.h
+box.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
+box.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
+box.$(OBJEXT): {$(VPATH)}backward/2/limits.h
+box.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
+box.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
+box.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
+box.$(OBJEXT): {$(VPATH)}box.c
+box.$(OBJEXT): {$(VPATH)}builtin.h
+box.$(OBJEXT): {$(VPATH)}config.h
+box.$(OBJEXT): {$(VPATH)}constant.h
+box.$(OBJEXT): {$(VPATH)}darray.h
+box.$(OBJEXT): {$(VPATH)}debug_counter.h
+box.$(OBJEXT): {$(VPATH)}defines.h
+box.$(OBJEXT): {$(VPATH)}encindex.h
+box.$(OBJEXT): {$(VPATH)}encoding.h
+box.$(OBJEXT): {$(VPATH)}eval_intern.h
+box.$(OBJEXT): {$(VPATH)}id.h
+box.$(OBJEXT): {$(VPATH)}id_table.h
+box.$(OBJEXT): {$(VPATH)}intern.h
+box.$(OBJEXT): {$(VPATH)}internal.h
+box.$(OBJEXT): {$(VPATH)}internal/abi.h
+box.$(OBJEXT): {$(VPATH)}internal/anyargs.h
+box.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
+box.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
+box.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
+box.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
+box.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
+box.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
+box.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
+box.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
+box.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
+box.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
+box.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
+box.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
+box.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
+box.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
+box.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
+box.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
+box.$(OBJEXT): {$(VPATH)}internal/assume.h
+box.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
+box.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
+box.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
+box.$(OBJEXT): {$(VPATH)}internal/attr/const.h
+box.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
+box.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
+box.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
+box.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
+box.$(OBJEXT): {$(VPATH)}internal/attr/error.h
+box.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
+box.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
+box.$(OBJEXT): {$(VPATH)}internal/attr/format.h
+box.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
+box.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
+box.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
+box.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
+box.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
+box.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
+box.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
+box.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
+box.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
+box.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
+box.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
+box.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
+box.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
+box.$(OBJEXT): {$(VPATH)}internal/cast.h
+box.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+box.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+box.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+box.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+box.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+box.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+box.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+box.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+box.$(OBJEXT): {$(VPATH)}internal/config.h
+box.$(OBJEXT): {$(VPATH)}internal/constant_p.h
+box.$(OBJEXT): {$(VPATH)}internal/core.h
+box.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
+box.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
+box.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
+box.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
+box.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
+box.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
+box.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
+box.$(OBJEXT): {$(VPATH)}internal/core/robject.h
+box.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
+box.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
+box.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
+box.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
+box.$(OBJEXT): {$(VPATH)}internal/ctype.h
+box.$(OBJEXT): {$(VPATH)}internal/dllexport.h
+box.$(OBJEXT): {$(VPATH)}internal/dosish.h
+box.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
+box.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
+box.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
+box.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
+box.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
+box.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
+box.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
+box.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
+box.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
+box.$(OBJEXT): {$(VPATH)}internal/error.h
+box.$(OBJEXT): {$(VPATH)}internal/eval.h
+box.$(OBJEXT): {$(VPATH)}internal/event.h
+box.$(OBJEXT): {$(VPATH)}internal/fl_type.h
+box.$(OBJEXT): {$(VPATH)}internal/gc.h
+box.$(OBJEXT): {$(VPATH)}internal/glob.h
+box.$(OBJEXT): {$(VPATH)}internal/globals.h
+box.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
+box.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
+box.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
+box.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
+box.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
+box.$(OBJEXT): {$(VPATH)}internal/has/extension.h
+box.$(OBJEXT): {$(VPATH)}internal/has/feature.h
+box.$(OBJEXT): {$(VPATH)}internal/has/warning.h
+box.$(OBJEXT): {$(VPATH)}internal/intern/array.h
+box.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
+box.$(OBJEXT): {$(VPATH)}internal/intern/class.h
+box.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
+box.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
+box.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
+box.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
+box.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
+box.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
+box.$(OBJEXT): {$(VPATH)}internal/intern/error.h
+box.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
+box.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+box.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
+box.$(OBJEXT): {$(VPATH)}internal/intern/io.h
+box.$(OBJEXT): {$(VPATH)}internal/intern/load.h
+box.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
+box.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
+box.$(OBJEXT): {$(VPATH)}internal/intern/object.h
+box.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
+box.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
+box.$(OBJEXT): {$(VPATH)}internal/intern/process.h
+box.$(OBJEXT): {$(VPATH)}internal/intern/random.h
+box.$(OBJEXT): {$(VPATH)}internal/intern/range.h
+box.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
+box.$(OBJEXT): {$(VPATH)}internal/intern/re.h
+box.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
+box.$(OBJEXT): {$(VPATH)}internal/intern/select.h
+box.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
+box.$(OBJEXT): {$(VPATH)}internal/intern/set.h
+box.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
+box.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
+box.$(OBJEXT): {$(VPATH)}internal/intern/string.h
+box.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
+box.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
+box.$(OBJEXT): {$(VPATH)}internal/intern/time.h
+box.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
+box.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
+box.$(OBJEXT): {$(VPATH)}internal/interpreter.h
+box.$(OBJEXT): {$(VPATH)}internal/iterator.h
+box.$(OBJEXT): {$(VPATH)}internal/memory.h
+box.$(OBJEXT): {$(VPATH)}internal/method.h
+box.$(OBJEXT): {$(VPATH)}internal/module.h
+box.$(OBJEXT): {$(VPATH)}internal/newobj.h
+box.$(OBJEXT): {$(VPATH)}internal/scan_args.h
+box.$(OBJEXT): {$(VPATH)}internal/special_consts.h
+box.$(OBJEXT): {$(VPATH)}internal/static_assert.h
+box.$(OBJEXT): {$(VPATH)}internal/stdalign.h
+box.$(OBJEXT): {$(VPATH)}internal/stdbool.h
+box.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
+box.$(OBJEXT): {$(VPATH)}internal/symbol.h
+box.$(OBJEXT): {$(VPATH)}internal/value.h
+box.$(OBJEXT): {$(VPATH)}internal/value_type.h
+box.$(OBJEXT): {$(VPATH)}internal/variable.h
+box.$(OBJEXT): {$(VPATH)}internal/warning_push.h
+box.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
+box.$(OBJEXT): {$(VPATH)}io.h
+box.$(OBJEXT): {$(VPATH)}iseq.h
+box.$(OBJEXT): {$(VPATH)}method.h
+box.$(OBJEXT): {$(VPATH)}missing.h
+box.$(OBJEXT): {$(VPATH)}node.h
+box.$(OBJEXT): {$(VPATH)}onigmo.h
+box.$(OBJEXT): {$(VPATH)}oniguruma.h
+box.$(OBJEXT): {$(VPATH)}prism/ast.h
+box.$(OBJEXT): {$(VPATH)}prism/diagnostic.h
+box.$(OBJEXT): {$(VPATH)}prism/version.h
+box.$(OBJEXT): {$(VPATH)}prism_compile.h
+box.$(OBJEXT): {$(VPATH)}prism_xallocator.h
+box.$(OBJEXT): {$(VPATH)}ruby_assert.h
+box.$(OBJEXT): {$(VPATH)}ruby_atomic.h
+box.$(OBJEXT): {$(VPATH)}rubyparser.h
+box.$(OBJEXT): {$(VPATH)}shape.h
+box.$(OBJEXT): {$(VPATH)}st.h
+box.$(OBJEXT): {$(VPATH)}subst.h
+box.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
+box.$(OBJEXT): {$(VPATH)}thread_native.h
+box.$(OBJEXT): {$(VPATH)}util.h
+box.$(OBJEXT): {$(VPATH)}vm_core.h
+box.$(OBJEXT): {$(VPATH)}vm_debug.h
+box.$(OBJEXT): {$(VPATH)}vm_opts.h
+box.$(OBJEXT): {$(VPATH)}vm_sync.h
+box.$(OBJEXT): {$(VPATH)}zjit.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
@@ -735,39 +1018,52 @@ builtin.$(OBJEXT): $(CCAN_DIR)/str/str.h
builtin.$(OBJEXT): $(hdrdir)/ruby/ruby.h
builtin.$(OBJEXT): $(top_srcdir)/internal/array.h
builtin.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
+builtin.$(OBJEXT): $(top_srcdir)/internal/box.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/namespace.h
builtin.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
builtin.$(OBJEXT): $(top_srcdir)/internal/serial.h
builtin.$(OBJEXT): $(top_srcdir)/internal/set_table.h
builtin.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
+builtin.$(OBJEXT): $(top_srcdir)/internal/struct.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/arena.h
builtin.$(OBJEXT): $(top_srcdir)/prism/ast.h
-builtin.$(OBJEXT): $(top_srcdir)/prism/defines.h
+builtin.$(OBJEXT): $(top_srcdir)/prism/buffer.h
+builtin.$(OBJEXT): $(top_srcdir)/prism/comments.h
+builtin.$(OBJEXT): $(top_srcdir)/prism/compiler/align.h
+builtin.$(OBJEXT): $(top_srcdir)/prism/compiler/exported.h
+builtin.$(OBJEXT): $(top_srcdir)/prism/compiler/filesystem.h
+builtin.$(OBJEXT): $(top_srcdir)/prism/compiler/nodiscard.h
+builtin.$(OBJEXT): $(top_srcdir)/prism/compiler/nonnull.h
+builtin.$(OBJEXT): $(top_srcdir)/prism/constant_pool.h
builtin.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h
-builtin.$(OBJEXT): $(top_srcdir)/prism/encoding.h
+builtin.$(OBJEXT): $(top_srcdir)/prism/excludes.h
+builtin.$(OBJEXT): $(top_srcdir)/prism/integer.h
+builtin.$(OBJEXT): $(top_srcdir)/prism/internal/char.h
+builtin.$(OBJEXT): $(top_srcdir)/prism/internal/encoding.h
+builtin.$(OBJEXT): $(top_srcdir)/prism/internal/list.h
+builtin.$(OBJEXT): $(top_srcdir)/prism/internal/memchr.h
+builtin.$(OBJEXT): $(top_srcdir)/prism/internal/regexp.h
+builtin.$(OBJEXT): $(top_srcdir)/prism/internal/static_literals.h
+builtin.$(OBJEXT): $(top_srcdir)/prism/internal/strncasecmp.h
+builtin.$(OBJEXT): $(top_srcdir)/prism/internal/strpbrk.h
+builtin.$(OBJEXT): $(top_srcdir)/prism/json.h
+builtin.$(OBJEXT): $(top_srcdir)/prism/line_offset_list.h
+builtin.$(OBJEXT): $(top_srcdir)/prism/magic_comments.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): $(top_srcdir)/prism/serialize.h
+builtin.$(OBJEXT): $(top_srcdir)/prism/source.h
+builtin.$(OBJEXT): $(top_srcdir)/prism/stream.h
+builtin.$(OBJEXT): $(top_srcdir)/prism/string_query.h
+builtin.$(OBJEXT): $(top_srcdir)/prism/stringy.h
builtin.$(OBJEXT): $(top_srcdir)/prism/version.h
builtin.$(OBJEXT): {$(VPATH)}assert.h
builtin.$(OBJEXT): {$(VPATH)}atomic.h
@@ -948,6 +1244,7 @@ builtin.$(OBJEXT): {$(VPATH)}node.h
builtin.$(OBJEXT): {$(VPATH)}onigmo.h
builtin.$(OBJEXT): {$(VPATH)}oniguruma.h
builtin.$(OBJEXT): {$(VPATH)}prism_compile.h
+builtin.$(OBJEXT): {$(VPATH)}prism_xallocator.h
builtin.$(OBJEXT): {$(VPATH)}ruby_assert.h
builtin.$(OBJEXT): {$(VPATH)}ruby_atomic.h
builtin.$(OBJEXT): {$(VPATH)}rubyparser.h
@@ -965,19 +1262,20 @@ class.$(OBJEXT): $(CCAN_DIR)/str/str.h
class.$(OBJEXT): $(hdrdir)/ruby/ruby.h
class.$(OBJEXT): $(top_srcdir)/internal/array.h
class.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
+class.$(OBJEXT): $(top_srcdir)/internal/box.h
class.$(OBJEXT): $(top_srcdir)/internal/class.h
class.$(OBJEXT): $(top_srcdir)/internal/compilers.h
class.$(OBJEXT): $(top_srcdir)/internal/eval.h
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/namespace.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/set_table.h
class.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
class.$(OBJEXT): $(top_srcdir)/internal/string.h
+class.$(OBJEXT): $(top_srcdir)/internal/struct.h
class.$(OBJEXT): $(top_srcdir)/internal/variable.h
class.$(OBJEXT): $(top_srcdir)/internal/vm.h
class.$(OBJEXT): $(top_srcdir)/internal/warnings.h
@@ -997,6 +1295,7 @@ class.$(OBJEXT): {$(VPATH)}config.h
class.$(OBJEXT): {$(VPATH)}constant.h
class.$(OBJEXT): {$(VPATH)}debug_counter.h
class.$(OBJEXT): {$(VPATH)}defines.h
+class.$(OBJEXT): {$(VPATH)}encindex.h
class.$(OBJEXT): {$(VPATH)}encoding.h
class.$(OBJEXT): {$(VPATH)}id.h
class.$(OBJEXT): {$(VPATH)}id_table.h
@@ -1157,6 +1456,7 @@ class.$(OBJEXT): {$(VPATH)}missing.h
class.$(OBJEXT): {$(VPATH)}node.h
class.$(OBJEXT): {$(VPATH)}onigmo.h
class.$(OBJEXT): {$(VPATH)}oniguruma.h
+class.$(OBJEXT): {$(VPATH)}ractor.h
class.$(OBJEXT): {$(VPATH)}ruby_assert.h
class.$(OBJEXT): {$(VPATH)}ruby_atomic.h
class.$(OBJEXT): {$(VPATH)}rubyparser.h
@@ -1170,6 +1470,7 @@ class.$(OBJEXT): {$(VPATH)}vm_debug.h
class.$(OBJEXT): {$(VPATH)}vm_opts.h
class.$(OBJEXT): {$(VPATH)}vm_sync.h
class.$(OBJEXT): {$(VPATH)}yjit.h
+class.$(OBJEXT): {$(VPATH)}zjit.h
compar.$(OBJEXT): $(hdrdir)/ruby/ruby.h
compar.$(OBJEXT): $(hdrdir)/ruby/version.h
compar.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
@@ -1194,6 +1495,7 @@ compar.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
compar.$(OBJEXT): {$(VPATH)}compar.c
compar.$(OBJEXT): {$(VPATH)}config.h
compar.$(OBJEXT): {$(VPATH)}defines.h
+compar.$(OBJEXT): {$(VPATH)}encindex.h
compar.$(OBJEXT): {$(VPATH)}encoding.h
compar.$(OBJEXT): {$(VPATH)}id.h
compar.$(OBJEXT): {$(VPATH)}intern.h
@@ -1363,7 +1665,9 @@ compile.$(OBJEXT): $(top_srcdir)/internal/array.h
compile.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
compile.$(OBJEXT): $(top_srcdir)/internal/bignum.h
compile.$(OBJEXT): $(top_srcdir)/internal/bits.h
+compile.$(OBJEXT): $(top_srcdir)/internal/box.h
compile.$(OBJEXT): $(top_srcdir)/internal/class.h
+compile.$(OBJEXT): $(top_srcdir)/internal/compar.h
compile.$(OBJEXT): $(top_srcdir)/internal/compile.h
compile.$(OBJEXT): $(top_srcdir)/internal/compilers.h
compile.$(OBJEXT): $(top_srcdir)/internal/complex.h
@@ -1374,7 +1678,6 @@ 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/namespace.h
compile.$(OBJEXT): $(top_srcdir)/internal/numeric.h
compile.$(OBJEXT): $(top_srcdir)/internal/object.h
compile.$(OBJEXT): $(top_srcdir)/internal/parse.h
@@ -1386,33 +1689,46 @@ compile.$(OBJEXT): $(top_srcdir)/internal/serial.h
compile.$(OBJEXT): $(top_srcdir)/internal/set_table.h
compile.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
compile.$(OBJEXT): $(top_srcdir)/internal/string.h
+compile.$(OBJEXT): $(top_srcdir)/internal/struct.h
compile.$(OBJEXT): $(top_srcdir)/internal/symbol.h
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/arena.h
compile.$(OBJEXT): $(top_srcdir)/prism/ast.h
-compile.$(OBJEXT): $(top_srcdir)/prism/defines.h
+compile.$(OBJEXT): $(top_srcdir)/prism/buffer.h
+compile.$(OBJEXT): $(top_srcdir)/prism/comments.h
+compile.$(OBJEXT): $(top_srcdir)/prism/compiler/align.h
+compile.$(OBJEXT): $(top_srcdir)/prism/compiler/exported.h
+compile.$(OBJEXT): $(top_srcdir)/prism/compiler/filesystem.h
+compile.$(OBJEXT): $(top_srcdir)/prism/compiler/nodiscard.h
+compile.$(OBJEXT): $(top_srcdir)/prism/compiler/nonnull.h
+compile.$(OBJEXT): $(top_srcdir)/prism/constant_pool.h
compile.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h
-compile.$(OBJEXT): $(top_srcdir)/prism/encoding.h
+compile.$(OBJEXT): $(top_srcdir)/prism/excludes.h
+compile.$(OBJEXT): $(top_srcdir)/prism/integer.h
+compile.$(OBJEXT): $(top_srcdir)/prism/internal/char.h
+compile.$(OBJEXT): $(top_srcdir)/prism/internal/encoding.h
+compile.$(OBJEXT): $(top_srcdir)/prism/internal/list.h
+compile.$(OBJEXT): $(top_srcdir)/prism/internal/memchr.h
+compile.$(OBJEXT): $(top_srcdir)/prism/internal/regexp.h
+compile.$(OBJEXT): $(top_srcdir)/prism/internal/static_literals.h
+compile.$(OBJEXT): $(top_srcdir)/prism/internal/strncasecmp.h
+compile.$(OBJEXT): $(top_srcdir)/prism/internal/strpbrk.h
+compile.$(OBJEXT): $(top_srcdir)/prism/json.h
+compile.$(OBJEXT): $(top_srcdir)/prism/line_offset_list.h
+compile.$(OBJEXT): $(top_srcdir)/prism/magic_comments.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/serialize.h
+compile.$(OBJEXT): $(top_srcdir)/prism/source.h
+compile.$(OBJEXT): $(top_srcdir)/prism/stream.h
+compile.$(OBJEXT): $(top_srcdir)/prism/string_query.h
+compile.$(OBJEXT): $(top_srcdir)/prism/stringy.h
compile.$(OBJEXT): $(top_srcdir)/prism/version.h
compile.$(OBJEXT): $(top_srcdir)/prism_compile.c
compile.$(OBJEXT): {$(VPATH)}assert.h
@@ -1602,6 +1918,7 @@ compile.$(OBJEXT): {$(VPATH)}oniguruma.h
compile.$(OBJEXT): {$(VPATH)}optinsn.inc
compile.$(OBJEXT): {$(VPATH)}prism_compile.c
compile.$(OBJEXT): {$(VPATH)}prism_compile.h
+compile.$(OBJEXT): {$(VPATH)}prism_xallocator.h
compile.$(OBJEXT): {$(VPATH)}ractor.h
compile.$(OBJEXT): {$(VPATH)}re.h
compile.$(OBJEXT): {$(VPATH)}regex.h
@@ -1629,14 +1946,16 @@ complex.$(OBJEXT): $(top_srcdir)/internal/array.h
complex.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
complex.$(OBJEXT): $(top_srcdir)/internal/bignum.h
complex.$(OBJEXT): $(top_srcdir)/internal/bits.h
+complex.$(OBJEXT): $(top_srcdir)/internal/box.h
complex.$(OBJEXT): $(top_srcdir)/internal/class.h
+complex.$(OBJEXT): $(top_srcdir)/internal/compar.h
complex.$(OBJEXT): $(top_srcdir)/internal/compilers.h
complex.$(OBJEXT): $(top_srcdir)/internal/complex.h
+complex.$(OBJEXT): $(top_srcdir)/internal/error.h
complex.$(OBJEXT): $(top_srcdir)/internal/fixnum.h
complex.$(OBJEXT): $(top_srcdir)/internal/gc.h
complex.$(OBJEXT): $(top_srcdir)/internal/imemo.h
complex.$(OBJEXT): $(top_srcdir)/internal/math.h
-complex.$(OBJEXT): $(top_srcdir)/internal/namespace.h
complex.$(OBJEXT): $(top_srcdir)/internal/numeric.h
complex.$(OBJEXT): $(top_srcdir)/internal/object.h
complex.$(OBJEXT): $(top_srcdir)/internal/rational.h
@@ -1645,6 +1964,7 @@ complex.$(OBJEXT): $(top_srcdir)/internal/serial.h
complex.$(OBJEXT): $(top_srcdir)/internal/set_table.h
complex.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
complex.$(OBJEXT): $(top_srcdir)/internal/string.h
+complex.$(OBJEXT): $(top_srcdir)/internal/struct.h
complex.$(OBJEXT): $(top_srcdir)/internal/variable.h
complex.$(OBJEXT): $(top_srcdir)/internal/vm.h
complex.$(OBJEXT): $(top_srcdir)/internal/warnings.h
@@ -1664,6 +1984,7 @@ complex.$(OBJEXT): {$(VPATH)}config.h
complex.$(OBJEXT): {$(VPATH)}constant.h
complex.$(OBJEXT): {$(VPATH)}debug_counter.h
complex.$(OBJEXT): {$(VPATH)}defines.h
+complex.$(OBJEXT): {$(VPATH)}encindex.h
complex.$(OBJEXT): {$(VPATH)}encoding.h
complex.$(OBJEXT): {$(VPATH)}id.h
complex.$(OBJEXT): {$(VPATH)}id_table.h
@@ -1843,11 +2164,11 @@ concurrent_set.$(OBJEXT): $(CCAN_DIR)/str/str.h
concurrent_set.$(OBJEXT): $(hdrdir)/ruby/ruby.h
concurrent_set.$(OBJEXT): $(top_srcdir)/internal/array.h
concurrent_set.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
+concurrent_set.$(OBJEXT): $(top_srcdir)/internal/box.h
concurrent_set.$(OBJEXT): $(top_srcdir)/internal/compilers.h
concurrent_set.$(OBJEXT): $(top_srcdir)/internal/concurrent_set.h
concurrent_set.$(OBJEXT): $(top_srcdir)/internal/gc.h
concurrent_set.$(OBJEXT): $(top_srcdir)/internal/imemo.h
-concurrent_set.$(OBJEXT): $(top_srcdir)/internal/namespace.h
concurrent_set.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
concurrent_set.$(OBJEXT): $(top_srcdir)/internal/serial.h
concurrent_set.$(OBJEXT): $(top_srcdir)/internal/set_table.h
@@ -1869,6 +2190,7 @@ concurrent_set.$(OBJEXT): {$(VPATH)}concurrent_set.c
concurrent_set.$(OBJEXT): {$(VPATH)}config.h
concurrent_set.$(OBJEXT): {$(VPATH)}debug_counter.h
concurrent_set.$(OBJEXT): {$(VPATH)}defines.h
+concurrent_set.$(OBJEXT): {$(VPATH)}encindex.h
concurrent_set.$(OBJEXT): {$(VPATH)}encoding.h
concurrent_set.$(OBJEXT): {$(VPATH)}id.h
concurrent_set.$(OBJEXT): {$(VPATH)}id_table.h
@@ -2049,45 +2371,58 @@ 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/box.h
cont.$(OBJEXT): $(top_srcdir)/internal/compilers.h
cont.$(OBJEXT): $(top_srcdir)/internal/cont.h
cont.$(OBJEXT): $(top_srcdir)/internal/error.h
cont.$(OBJEXT): $(top_srcdir)/internal/eval.h
cont.$(OBJEXT): $(top_srcdir)/internal/gc.h
cont.$(OBJEXT): $(top_srcdir)/internal/imemo.h
-cont.$(OBJEXT): $(top_srcdir)/internal/namespace.h
cont.$(OBJEXT): $(top_srcdir)/internal/proc.h
cont.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
cont.$(OBJEXT): $(top_srcdir)/internal/serial.h
cont.$(OBJEXT): $(top_srcdir)/internal/set_table.h
cont.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
cont.$(OBJEXT): $(top_srcdir)/internal/string.h
+cont.$(OBJEXT): $(top_srcdir)/internal/struct.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/arena.h
cont.$(OBJEXT): $(top_srcdir)/prism/ast.h
-cont.$(OBJEXT): $(top_srcdir)/prism/defines.h
+cont.$(OBJEXT): $(top_srcdir)/prism/buffer.h
+cont.$(OBJEXT): $(top_srcdir)/prism/comments.h
+cont.$(OBJEXT): $(top_srcdir)/prism/compiler/align.h
+cont.$(OBJEXT): $(top_srcdir)/prism/compiler/exported.h
+cont.$(OBJEXT): $(top_srcdir)/prism/compiler/filesystem.h
+cont.$(OBJEXT): $(top_srcdir)/prism/compiler/nodiscard.h
+cont.$(OBJEXT): $(top_srcdir)/prism/compiler/nonnull.h
+cont.$(OBJEXT): $(top_srcdir)/prism/constant_pool.h
cont.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h
-cont.$(OBJEXT): $(top_srcdir)/prism/encoding.h
+cont.$(OBJEXT): $(top_srcdir)/prism/excludes.h
+cont.$(OBJEXT): $(top_srcdir)/prism/integer.h
+cont.$(OBJEXT): $(top_srcdir)/prism/internal/char.h
+cont.$(OBJEXT): $(top_srcdir)/prism/internal/encoding.h
+cont.$(OBJEXT): $(top_srcdir)/prism/internal/list.h
+cont.$(OBJEXT): $(top_srcdir)/prism/internal/memchr.h
+cont.$(OBJEXT): $(top_srcdir)/prism/internal/regexp.h
+cont.$(OBJEXT): $(top_srcdir)/prism/internal/static_literals.h
+cont.$(OBJEXT): $(top_srcdir)/prism/internal/strncasecmp.h
+cont.$(OBJEXT): $(top_srcdir)/prism/internal/strpbrk.h
+cont.$(OBJEXT): $(top_srcdir)/prism/json.h
+cont.$(OBJEXT): $(top_srcdir)/prism/line_offset_list.h
+cont.$(OBJEXT): $(top_srcdir)/prism/magic_comments.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): $(top_srcdir)/prism/serialize.h
+cont.$(OBJEXT): $(top_srcdir)/prism/source.h
+cont.$(OBJEXT): $(top_srcdir)/prism/stream.h
+cont.$(OBJEXT): $(top_srcdir)/prism/string_query.h
+cont.$(OBJEXT): $(top_srcdir)/prism/stringy.h
cont.$(OBJEXT): $(top_srcdir)/prism/version.h
cont.$(OBJEXT): {$(VPATH)}$(COROUTINE_H)
cont.$(OBJEXT): {$(VPATH)}assert.h
@@ -2106,6 +2441,7 @@ cont.$(OBJEXT): {$(VPATH)}constant.h
cont.$(OBJEXT): {$(VPATH)}cont.c
cont.$(OBJEXT): {$(VPATH)}debug_counter.h
cont.$(OBJEXT): {$(VPATH)}defines.h
+cont.$(OBJEXT): {$(VPATH)}encindex.h
cont.$(OBJEXT): {$(VPATH)}encoding.h
cont.$(OBJEXT): {$(VPATH)}eval_intern.h
cont.$(OBJEXT): {$(VPATH)}fiber/scheduler.h
@@ -2270,6 +2606,7 @@ cont.$(OBJEXT): {$(VPATH)}node.h
cont.$(OBJEXT): {$(VPATH)}onigmo.h
cont.$(OBJEXT): {$(VPATH)}oniguruma.h
cont.$(OBJEXT): {$(VPATH)}prism_compile.h
+cont.$(OBJEXT): {$(VPATH)}prism_xallocator.h
cont.$(OBJEXT): {$(VPATH)}ractor.h
cont.$(OBJEXT): {$(VPATH)}ractor_core.h
cont.$(OBJEXT): {$(VPATH)}ruby_assert.h
@@ -2285,6 +2622,7 @@ cont.$(OBJEXT): {$(VPATH)}vm_debug.h
cont.$(OBJEXT): {$(VPATH)}vm_opts.h
cont.$(OBJEXT): {$(VPATH)}vm_sync.h
cont.$(OBJEXT): {$(VPATH)}yjit.h
+cont.$(OBJEXT): {$(VPATH)}zjit.h
debug.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
debug.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
debug.$(OBJEXT): $(CCAN_DIR)/list/list.h
@@ -2292,16 +2630,17 @@ debug.$(OBJEXT): $(CCAN_DIR)/str/str.h
debug.$(OBJEXT): $(hdrdir)/ruby/ruby.h
debug.$(OBJEXT): $(top_srcdir)/internal/array.h
debug.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
+debug.$(OBJEXT): $(top_srcdir)/internal/box.h
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/namespace.h
debug.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
debug.$(OBJEXT): $(top_srcdir)/internal/serial.h
debug.$(OBJEXT): $(top_srcdir)/internal/set_table.h
debug.$(OBJEXT): $(top_srcdir)/internal/signal.h
debug.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
+debug.$(OBJEXT): $(top_srcdir)/internal/struct.h
debug.$(OBJEXT): $(top_srcdir)/internal/variable.h
debug.$(OBJEXT): $(top_srcdir)/internal/vm.h
debug.$(OBJEXT): $(top_srcdir)/internal/warnings.h
@@ -2501,6 +2840,7 @@ 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.$(OBJEXT): {$(VPATH)}zjit.h
debug_counter.$(OBJEXT): $(hdrdir)/ruby/ruby.h
debug_counter.$(OBJEXT): {$(VPATH)}assert.h
debug_counter.$(OBJEXT): {$(VPATH)}backward/2/assume.h
@@ -2670,6 +3010,7 @@ 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/box.h
dir.$(OBJEXT): $(top_srcdir)/internal/class.h
dir.$(OBJEXT): $(top_srcdir)/internal/compilers.h
dir.$(OBJEXT): $(top_srcdir)/internal/dir.h
@@ -2679,7 +3020,6 @@ 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/namespace.h
dir.$(OBJEXT): $(top_srcdir)/internal/object.h
dir.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
dir.$(OBJEXT): $(top_srcdir)/internal/serial.h
@@ -2881,8 +3221,8 @@ 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/box.h
dln.$(OBJEXT): $(top_srcdir)/internal/compilers.h
-dln.$(OBJEXT): $(top_srcdir)/internal/namespace.h
dln.$(OBJEXT): $(top_srcdir)/internal/warnings.h
dln.$(OBJEXT): {$(VPATH)}assert.h
dln.$(OBJEXT): {$(VPATH)}backward/2/assume.h
@@ -3363,6 +3703,42 @@ dmydln.$(OBJEXT): {$(VPATH)}st.h
dmydln.$(OBJEXT): {$(VPATH)}subst.h
dmyenc.$(OBJEXT): {$(VPATH)}dmyenc.c
dmyext.$(OBJEXT): {$(VPATH)}dmyext.c
+dump_ast-dump_ast.$(OBJEXT): $(top_srcdir)/prism/arena.h
+dump_ast-dump_ast.$(OBJEXT): $(top_srcdir)/prism/ast.h
+dump_ast-dump_ast.$(OBJEXT): $(top_srcdir)/prism/buffer.h
+dump_ast-dump_ast.$(OBJEXT): $(top_srcdir)/prism/comments.h
+dump_ast-dump_ast.$(OBJEXT): $(top_srcdir)/prism/compiler/align.h
+dump_ast-dump_ast.$(OBJEXT): $(top_srcdir)/prism/compiler/exported.h
+dump_ast-dump_ast.$(OBJEXT): $(top_srcdir)/prism/compiler/filesystem.h
+dump_ast-dump_ast.$(OBJEXT): $(top_srcdir)/prism/compiler/nodiscard.h
+dump_ast-dump_ast.$(OBJEXT): $(top_srcdir)/prism/compiler/nonnull.h
+dump_ast-dump_ast.$(OBJEXT): $(top_srcdir)/prism/constant_pool.h
+dump_ast-dump_ast.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h
+dump_ast-dump_ast.$(OBJEXT): $(top_srcdir)/prism/excludes.h
+dump_ast-dump_ast.$(OBJEXT): $(top_srcdir)/prism/integer.h
+dump_ast-dump_ast.$(OBJEXT): $(top_srcdir)/prism/internal/char.h
+dump_ast-dump_ast.$(OBJEXT): $(top_srcdir)/prism/internal/encoding.h
+dump_ast-dump_ast.$(OBJEXT): $(top_srcdir)/prism/internal/list.h
+dump_ast-dump_ast.$(OBJEXT): $(top_srcdir)/prism/internal/memchr.h
+dump_ast-dump_ast.$(OBJEXT): $(top_srcdir)/prism/internal/regexp.h
+dump_ast-dump_ast.$(OBJEXT): $(top_srcdir)/prism/internal/static_literals.h
+dump_ast-dump_ast.$(OBJEXT): $(top_srcdir)/prism/internal/strncasecmp.h
+dump_ast-dump_ast.$(OBJEXT): $(top_srcdir)/prism/internal/strpbrk.h
+dump_ast-dump_ast.$(OBJEXT): $(top_srcdir)/prism/json.h
+dump_ast-dump_ast.$(OBJEXT): $(top_srcdir)/prism/line_offset_list.h
+dump_ast-dump_ast.$(OBJEXT): $(top_srcdir)/prism/magic_comments.h
+dump_ast-dump_ast.$(OBJEXT): $(top_srcdir)/prism/node.h
+dump_ast-dump_ast.$(OBJEXT): $(top_srcdir)/prism/options.h
+dump_ast-dump_ast.$(OBJEXT): $(top_srcdir)/prism/parser.h
+dump_ast-dump_ast.$(OBJEXT): $(top_srcdir)/prism/prettyprint.h
+dump_ast-dump_ast.$(OBJEXT): $(top_srcdir)/prism/prism.h
+dump_ast-dump_ast.$(OBJEXT): $(top_srcdir)/prism/serialize.h
+dump_ast-dump_ast.$(OBJEXT): $(top_srcdir)/prism/source.h
+dump_ast-dump_ast.$(OBJEXT): $(top_srcdir)/prism/stream.h
+dump_ast-dump_ast.$(OBJEXT): $(top_srcdir)/prism/string_query.h
+dump_ast-dump_ast.$(OBJEXT): $(top_srcdir)/prism/stringy.h
+dump_ast-dump_ast.$(OBJEXT): $(top_srcdir)/prism/version.h
+dump_ast-dump_ast.$(OBJEXT): $(top_srcdir)/tool/dump_ast.c
enc/ascii.$(OBJEXT): $(hdrdir)/ruby/ruby.h
enc/ascii.$(OBJEXT): {$(VPATH)}assert.h
enc/ascii.$(OBJEXT): {$(VPATH)}backward/2/assume.h
@@ -4384,6 +4760,7 @@ encoding.$(OBJEXT): {$(VPATH)}missing.h
encoding.$(OBJEXT): {$(VPATH)}node.h
encoding.$(OBJEXT): {$(VPATH)}onigmo.h
encoding.$(OBJEXT): {$(VPATH)}oniguruma.h
+encoding.$(OBJEXT): {$(VPATH)}ractor.h
encoding.$(OBJEXT): {$(VPATH)}regenc.h
encoding.$(OBJEXT): {$(VPATH)}ruby_assert.h
encoding.$(OBJEXT): {$(VPATH)}ruby_atomic.h
@@ -4504,6 +4881,7 @@ enum.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
enum.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
enum.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
enum.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
+enum.$(OBJEXT): {$(VPATH)}internal/core/rmatch.h
enum.$(OBJEXT): {$(VPATH)}internal/core/robject.h
enum.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
enum.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
@@ -4594,6 +4972,8 @@ enum.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
enum.$(OBJEXT): {$(VPATH)}missing.h
enum.$(OBJEXT): {$(VPATH)}onigmo.h
enum.$(OBJEXT): {$(VPATH)}oniguruma.h
+enum.$(OBJEXT): {$(VPATH)}re.h
+enum.$(OBJEXT): {$(VPATH)}regex.h
enum.$(OBJEXT): {$(VPATH)}ruby_assert.h
enum.$(OBJEXT): {$(VPATH)}shape.h
enum.$(OBJEXT): {$(VPATH)}st.h
@@ -4610,7 +4990,9 @@ enumerator.$(OBJEXT): $(top_srcdir)/internal/array.h
enumerator.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
enumerator.$(OBJEXT): $(top_srcdir)/internal/bignum.h
enumerator.$(OBJEXT): $(top_srcdir)/internal/bits.h
+enumerator.$(OBJEXT): $(top_srcdir)/internal/box.h
enumerator.$(OBJEXT): $(top_srcdir)/internal/class.h
+enumerator.$(OBJEXT): $(top_srcdir)/internal/compar.h
enumerator.$(OBJEXT): $(top_srcdir)/internal/compilers.h
enumerator.$(OBJEXT): $(top_srcdir)/internal/enumerator.h
enumerator.$(OBJEXT): $(top_srcdir)/internal/error.h
@@ -4618,7 +5000,6 @@ enumerator.$(OBJEXT): $(top_srcdir)/internal/fixnum.h
enumerator.$(OBJEXT): $(top_srcdir)/internal/gc.h
enumerator.$(OBJEXT): $(top_srcdir)/internal/hash.h
enumerator.$(OBJEXT): $(top_srcdir)/internal/imemo.h
-enumerator.$(OBJEXT): $(top_srcdir)/internal/namespace.h
enumerator.$(OBJEXT): $(top_srcdir)/internal/numeric.h
enumerator.$(OBJEXT): $(top_srcdir)/internal/range.h
enumerator.$(OBJEXT): $(top_srcdir)/internal/rational.h
@@ -4646,6 +5027,7 @@ enumerator.$(OBJEXT): {$(VPATH)}config.h
enumerator.$(OBJEXT): {$(VPATH)}constant.h
enumerator.$(OBJEXT): {$(VPATH)}debug_counter.h
enumerator.$(OBJEXT): {$(VPATH)}defines.h
+enumerator.$(OBJEXT): {$(VPATH)}encindex.h
enumerator.$(OBJEXT): {$(VPATH)}encoding.h
enumerator.$(OBJEXT): {$(VPATH)}enumerator.c
enumerator.$(OBJEXT): {$(VPATH)}id.h
@@ -4827,6 +5209,7 @@ 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/box.h
error.$(OBJEXT): $(top_srcdir)/internal/class.h
error.$(OBJEXT): $(top_srcdir)/internal/compilers.h
error.$(OBJEXT): $(top_srcdir)/internal/error.h
@@ -4836,7 +5219,6 @@ error.$(OBJEXT): $(top_srcdir)/internal/hash.h
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/namespace.h
error.$(OBJEXT): $(top_srcdir)/internal/object.h
error.$(OBJEXT): $(top_srcdir)/internal/process.h
error.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
@@ -4844,6 +5226,7 @@ error.$(OBJEXT): $(top_srcdir)/internal/serial.h
error.$(OBJEXT): $(top_srcdir)/internal/set_table.h
error.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
error.$(OBJEXT): $(top_srcdir)/internal/string.h
+error.$(OBJEXT): $(top_srcdir)/internal/struct.h
error.$(OBJEXT): $(top_srcdir)/internal/symbol.h
error.$(OBJEXT): $(top_srcdir)/internal/thread.h
error.$(OBJEXT): $(top_srcdir)/internal/variable.h
@@ -4865,6 +5248,7 @@ error.$(OBJEXT): {$(VPATH)}config.h
error.$(OBJEXT): {$(VPATH)}constant.h
error.$(OBJEXT): {$(VPATH)}debug_counter.h
error.$(OBJEXT): {$(VPATH)}defines.h
+error.$(OBJEXT): {$(VPATH)}encindex.h
error.$(OBJEXT): {$(VPATH)}encoding.h
error.$(OBJEXT): {$(VPATH)}error.c
error.$(OBJEXT): {$(VPATH)}id.h
@@ -5043,6 +5427,7 @@ error.$(OBJEXT): {$(VPATH)}vm_opts.h
error.$(OBJEXT): {$(VPATH)}vm_sync.h
error.$(OBJEXT): {$(VPATH)}warning.rbinc
error.$(OBJEXT): {$(VPATH)}yjit.h
+error.$(OBJEXT): {$(VPATH)}zjit.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
@@ -5052,6 +5437,7 @@ 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/box.h
eval.$(OBJEXT): $(top_srcdir)/internal/class.h
eval.$(OBJEXT): $(top_srcdir)/internal/compilers.h
eval.$(OBJEXT): $(top_srcdir)/internal/cont.h
@@ -5062,39 +5448,51 @@ eval.$(OBJEXT): $(top_srcdir)/internal/hash.h
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/namespace.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/set_table.h
eval.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
eval.$(OBJEXT): $(top_srcdir)/internal/string.h
+eval.$(OBJEXT): $(top_srcdir)/internal/struct.h
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/arena.h
eval.$(OBJEXT): $(top_srcdir)/prism/ast.h
-eval.$(OBJEXT): $(top_srcdir)/prism/defines.h
+eval.$(OBJEXT): $(top_srcdir)/prism/buffer.h
+eval.$(OBJEXT): $(top_srcdir)/prism/comments.h
+eval.$(OBJEXT): $(top_srcdir)/prism/compiler/align.h
+eval.$(OBJEXT): $(top_srcdir)/prism/compiler/exported.h
+eval.$(OBJEXT): $(top_srcdir)/prism/compiler/filesystem.h
+eval.$(OBJEXT): $(top_srcdir)/prism/compiler/nodiscard.h
+eval.$(OBJEXT): $(top_srcdir)/prism/compiler/nonnull.h
+eval.$(OBJEXT): $(top_srcdir)/prism/constant_pool.h
eval.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h
-eval.$(OBJEXT): $(top_srcdir)/prism/encoding.h
+eval.$(OBJEXT): $(top_srcdir)/prism/excludes.h
+eval.$(OBJEXT): $(top_srcdir)/prism/integer.h
+eval.$(OBJEXT): $(top_srcdir)/prism/internal/char.h
+eval.$(OBJEXT): $(top_srcdir)/prism/internal/encoding.h
+eval.$(OBJEXT): $(top_srcdir)/prism/internal/list.h
+eval.$(OBJEXT): $(top_srcdir)/prism/internal/memchr.h
+eval.$(OBJEXT): $(top_srcdir)/prism/internal/regexp.h
+eval.$(OBJEXT): $(top_srcdir)/prism/internal/static_literals.h
+eval.$(OBJEXT): $(top_srcdir)/prism/internal/strncasecmp.h
+eval.$(OBJEXT): $(top_srcdir)/prism/internal/strpbrk.h
+eval.$(OBJEXT): $(top_srcdir)/prism/json.h
+eval.$(OBJEXT): $(top_srcdir)/prism/line_offset_list.h
+eval.$(OBJEXT): $(top_srcdir)/prism/magic_comments.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): $(top_srcdir)/prism/serialize.h
+eval.$(OBJEXT): $(top_srcdir)/prism/source.h
+eval.$(OBJEXT): $(top_srcdir)/prism/stream.h
+eval.$(OBJEXT): $(top_srcdir)/prism/string_query.h
+eval.$(OBJEXT): $(top_srcdir)/prism/stringy.h
eval.$(OBJEXT): $(top_srcdir)/prism/version.h
eval.$(OBJEXT): {$(VPATH)}assert.h
eval.$(OBJEXT): {$(VPATH)}atomic.h
@@ -5111,6 +5509,7 @@ eval.$(OBJEXT): {$(VPATH)}config.h
eval.$(OBJEXT): {$(VPATH)}constant.h
eval.$(OBJEXT): {$(VPATH)}debug_counter.h
eval.$(OBJEXT): {$(VPATH)}defines.h
+eval.$(OBJEXT): {$(VPATH)}encindex.h
eval.$(OBJEXT): {$(VPATH)}encoding.h
eval.$(OBJEXT): {$(VPATH)}eval.c
eval.$(OBJEXT): {$(VPATH)}eval_error.c
@@ -5279,6 +5678,7 @@ eval.$(OBJEXT): {$(VPATH)}node.h
eval.$(OBJEXT): {$(VPATH)}onigmo.h
eval.$(OBJEXT): {$(VPATH)}oniguruma.h
eval.$(OBJEXT): {$(VPATH)}prism_compile.h
+eval.$(OBJEXT): {$(VPATH)}prism_xallocator.h
eval.$(OBJEXT): {$(VPATH)}probes.dmyh
eval.$(OBJEXT): {$(VPATH)}probes.h
eval.$(OBJEXT): {$(VPATH)}probes_helper.h
@@ -5297,6 +5697,7 @@ eval.$(OBJEXT): {$(VPATH)}vm_core.h
eval.$(OBJEXT): {$(VPATH)}vm_debug.h
eval.$(OBJEXT): {$(VPATH)}vm_opts.h
eval.$(OBJEXT): {$(VPATH)}vm_sync.h
+eval.$(OBJEXT): {$(VPATH)}zjit.h
explicit_bzero.$(OBJEXT): {$(VPATH)}config.h
explicit_bzero.$(OBJEXT): {$(VPATH)}explicit_bzero.c
explicit_bzero.$(OBJEXT): {$(VPATH)}internal/attr/format.h
@@ -5322,6 +5723,7 @@ file.$(OBJEXT): $(top_srcdir)/internal/array.h
file.$(OBJEXT): $(top_srcdir)/internal/class.h
file.$(OBJEXT): $(top_srcdir)/internal/compilers.h
file.$(OBJEXT): $(top_srcdir)/internal/dir.h
+file.$(OBJEXT): $(top_srcdir)/internal/encoding.h
file.$(OBJEXT): $(top_srcdir)/internal/error.h
file.$(OBJEXT): $(top_srcdir)/internal/file.h
file.$(OBJEXT): $(top_srcdir)/internal/gc.h
@@ -5533,7 +5935,9 @@ 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/box.h
gc.$(OBJEXT): $(top_srcdir)/internal/class.h
+gc.$(OBJEXT): $(top_srcdir)/internal/compar.h
gc.$(OBJEXT): $(top_srcdir)/internal/compile.h
gc.$(OBJEXT): $(top_srcdir)/internal/compilers.h
gc.$(OBJEXT): $(top_srcdir)/internal/complex.h
@@ -5546,11 +5950,11 @@ gc.$(OBJEXT): $(top_srcdir)/internal/gc.h
gc.$(OBJEXT): $(top_srcdir)/internal/hash.h
gc.$(OBJEXT): $(top_srcdir)/internal/imemo.h
gc.$(OBJEXT): $(top_srcdir)/internal/io.h
-gc.$(OBJEXT): $(top_srcdir)/internal/namespace.h
gc.$(OBJEXT): $(top_srcdir)/internal/numeric.h
gc.$(OBJEXT): $(top_srcdir)/internal/object.h
gc.$(OBJEXT): $(top_srcdir)/internal/proc.h
gc.$(OBJEXT): $(top_srcdir)/internal/rational.h
+gc.$(OBJEXT): $(top_srcdir)/internal/re.h
gc.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
gc.$(OBJEXT): $(top_srcdir)/internal/serial.h
gc.$(OBJEXT): $(top_srcdir)/internal/set_table.h
@@ -5562,28 +5966,40 @@ 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/arena.h
gc.$(OBJEXT): $(top_srcdir)/prism/ast.h
-gc.$(OBJEXT): $(top_srcdir)/prism/defines.h
+gc.$(OBJEXT): $(top_srcdir)/prism/buffer.h
+gc.$(OBJEXT): $(top_srcdir)/prism/comments.h
+gc.$(OBJEXT): $(top_srcdir)/prism/compiler/align.h
+gc.$(OBJEXT): $(top_srcdir)/prism/compiler/exported.h
+gc.$(OBJEXT): $(top_srcdir)/prism/compiler/filesystem.h
+gc.$(OBJEXT): $(top_srcdir)/prism/compiler/nodiscard.h
+gc.$(OBJEXT): $(top_srcdir)/prism/compiler/nonnull.h
+gc.$(OBJEXT): $(top_srcdir)/prism/constant_pool.h
gc.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h
-gc.$(OBJEXT): $(top_srcdir)/prism/encoding.h
+gc.$(OBJEXT): $(top_srcdir)/prism/excludes.h
+gc.$(OBJEXT): $(top_srcdir)/prism/integer.h
+gc.$(OBJEXT): $(top_srcdir)/prism/internal/char.h
+gc.$(OBJEXT): $(top_srcdir)/prism/internal/encoding.h
+gc.$(OBJEXT): $(top_srcdir)/prism/internal/list.h
+gc.$(OBJEXT): $(top_srcdir)/prism/internal/memchr.h
+gc.$(OBJEXT): $(top_srcdir)/prism/internal/regexp.h
+gc.$(OBJEXT): $(top_srcdir)/prism/internal/static_literals.h
+gc.$(OBJEXT): $(top_srcdir)/prism/internal/strncasecmp.h
+gc.$(OBJEXT): $(top_srcdir)/prism/internal/strpbrk.h
+gc.$(OBJEXT): $(top_srcdir)/prism/json.h
+gc.$(OBJEXT): $(top_srcdir)/prism/line_offset_list.h
+gc.$(OBJEXT): $(top_srcdir)/prism/magic_comments.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): $(top_srcdir)/prism/serialize.h
+gc.$(OBJEXT): $(top_srcdir)/prism/source.h
+gc.$(OBJEXT): $(top_srcdir)/prism/stream.h
+gc.$(OBJEXT): $(top_srcdir)/prism/string_query.h
+gc.$(OBJEXT): $(top_srcdir)/prism/stringy.h
gc.$(OBJEXT): $(top_srcdir)/prism/version.h
gc.$(OBJEXT): {$(VPATH)}assert.h
gc.$(OBJEXT): {$(VPATH)}atomic.h
@@ -5603,6 +6019,7 @@ gc.$(OBJEXT): {$(VPATH)}darray.h
gc.$(OBJEXT): {$(VPATH)}debug.h
gc.$(OBJEXT): {$(VPATH)}debug_counter.h
gc.$(OBJEXT): {$(VPATH)}defines.h
+gc.$(OBJEXT): {$(VPATH)}encindex.h
gc.$(OBJEXT): {$(VPATH)}encoding.h
gc.$(OBJEXT): {$(VPATH)}eval_intern.h
gc.$(OBJEXT): {$(VPATH)}gc.c
@@ -5770,6 +6187,7 @@ gc.$(OBJEXT): {$(VPATH)}node.h
gc.$(OBJEXT): {$(VPATH)}onigmo.h
gc.$(OBJEXT): {$(VPATH)}oniguruma.h
gc.$(OBJEXT): {$(VPATH)}prism_compile.h
+gc.$(OBJEXT): {$(VPATH)}prism_xallocator.h
gc.$(OBJEXT): {$(VPATH)}probes.dmyh
gc.$(OBJEXT): {$(VPATH)}probes.h
gc.$(OBJEXT): {$(VPATH)}ractor.h
@@ -5797,6 +6215,7 @@ gc.$(OBJEXT): {$(VPATH)}vm_debug.h
gc.$(OBJEXT): {$(VPATH)}vm_opts.h
gc.$(OBJEXT): {$(VPATH)}vm_sync.h
gc.$(OBJEXT): {$(VPATH)}yjit.h
+gc.$(OBJEXT): {$(VPATH)}zjit.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
@@ -5807,12 +6226,12 @@ 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/box.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/namespace.h
goruby.$(OBJEXT): $(top_srcdir)/internal/numeric.h
goruby.$(OBJEXT): $(top_srcdir)/internal/parse.h
goruby.$(OBJEXT): $(top_srcdir)/internal/rational.h
@@ -5824,28 +6243,27 @@ 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/arena.h
goruby.$(OBJEXT): $(top_srcdir)/prism/ast.h
-goruby.$(OBJEXT): $(top_srcdir)/prism/defines.h
+goruby.$(OBJEXT): $(top_srcdir)/prism/buffer.h
+goruby.$(OBJEXT): $(top_srcdir)/prism/constant_pool.h
goruby.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h
-goruby.$(OBJEXT): $(top_srcdir)/prism/encoding.h
+goruby.$(OBJEXT): $(top_srcdir)/prism/integer.h
+goruby.$(OBJEXT): $(top_srcdir)/prism/internal/char.h
+goruby.$(OBJEXT): $(top_srcdir)/prism/internal/encoding.h
+goruby.$(OBJEXT): $(top_srcdir)/prism/internal/list.h
+goruby.$(OBJEXT): $(top_srcdir)/prism/internal/memchr.h
+goruby.$(OBJEXT): $(top_srcdir)/prism/internal/regexp.h
+goruby.$(OBJEXT): $(top_srcdir)/prism/internal/static_literals.h
+goruby.$(OBJEXT): $(top_srcdir)/prism/internal/strncasecmp.h
+goruby.$(OBJEXT): $(top_srcdir)/prism/internal/strpbrk.h
+goruby.$(OBJEXT): $(top_srcdir)/prism/line_offset_list.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): $(top_srcdir)/prism/stringy.h
goruby.$(OBJEXT): $(top_srcdir)/prism/version.h
goruby.$(OBJEXT): {$(VPATH)}assert.h
goruby.$(OBJEXT): {$(VPATH)}atomic.h
@@ -6048,6 +6466,7 @@ hash.$(OBJEXT): $(top_srcdir)/internal/array.h
hash.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
hash.$(OBJEXT): $(top_srcdir)/internal/bignum.h
hash.$(OBJEXT): $(top_srcdir)/internal/bits.h
+hash.$(OBJEXT): $(top_srcdir)/internal/box.h
hash.$(OBJEXT): $(top_srcdir)/internal/class.h
hash.$(OBJEXT): $(top_srcdir)/internal/compilers.h
hash.$(OBJEXT): $(top_srcdir)/internal/cont.h
@@ -6055,7 +6474,6 @@ hash.$(OBJEXT): $(top_srcdir)/internal/error.h
hash.$(OBJEXT): $(top_srcdir)/internal/gc.h
hash.$(OBJEXT): $(top_srcdir)/internal/hash.h
hash.$(OBJEXT): $(top_srcdir)/internal/imemo.h
-hash.$(OBJEXT): $(top_srcdir)/internal/namespace.h
hash.$(OBJEXT): $(top_srcdir)/internal/object.h
hash.$(OBJEXT): $(top_srcdir)/internal/proc.h
hash.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
@@ -6071,28 +6489,40 @@ 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/arena.h
hash.$(OBJEXT): $(top_srcdir)/prism/ast.h
-hash.$(OBJEXT): $(top_srcdir)/prism/defines.h
+hash.$(OBJEXT): $(top_srcdir)/prism/buffer.h
+hash.$(OBJEXT): $(top_srcdir)/prism/comments.h
+hash.$(OBJEXT): $(top_srcdir)/prism/compiler/align.h
+hash.$(OBJEXT): $(top_srcdir)/prism/compiler/exported.h
+hash.$(OBJEXT): $(top_srcdir)/prism/compiler/filesystem.h
+hash.$(OBJEXT): $(top_srcdir)/prism/compiler/nodiscard.h
+hash.$(OBJEXT): $(top_srcdir)/prism/compiler/nonnull.h
+hash.$(OBJEXT): $(top_srcdir)/prism/constant_pool.h
hash.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h
-hash.$(OBJEXT): $(top_srcdir)/prism/encoding.h
+hash.$(OBJEXT): $(top_srcdir)/prism/excludes.h
+hash.$(OBJEXT): $(top_srcdir)/prism/integer.h
+hash.$(OBJEXT): $(top_srcdir)/prism/internal/char.h
+hash.$(OBJEXT): $(top_srcdir)/prism/internal/encoding.h
+hash.$(OBJEXT): $(top_srcdir)/prism/internal/list.h
+hash.$(OBJEXT): $(top_srcdir)/prism/internal/memchr.h
+hash.$(OBJEXT): $(top_srcdir)/prism/internal/regexp.h
+hash.$(OBJEXT): $(top_srcdir)/prism/internal/static_literals.h
+hash.$(OBJEXT): $(top_srcdir)/prism/internal/strncasecmp.h
+hash.$(OBJEXT): $(top_srcdir)/prism/internal/strpbrk.h
+hash.$(OBJEXT): $(top_srcdir)/prism/json.h
+hash.$(OBJEXT): $(top_srcdir)/prism/line_offset_list.h
+hash.$(OBJEXT): $(top_srcdir)/prism/magic_comments.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): $(top_srcdir)/prism/serialize.h
+hash.$(OBJEXT): $(top_srcdir)/prism/source.h
+hash.$(OBJEXT): $(top_srcdir)/prism/stream.h
+hash.$(OBJEXT): $(top_srcdir)/prism/string_query.h
+hash.$(OBJEXT): $(top_srcdir)/prism/stringy.h
hash.$(OBJEXT): $(top_srcdir)/prism/version.h
hash.$(OBJEXT): {$(VPATH)}assert.h
hash.$(OBJEXT): {$(VPATH)}atomic.h
@@ -6110,6 +6540,7 @@ hash.$(OBJEXT): {$(VPATH)}config.h
hash.$(OBJEXT): {$(VPATH)}constant.h
hash.$(OBJEXT): {$(VPATH)}debug_counter.h
hash.$(OBJEXT): {$(VPATH)}defines.h
+hash.$(OBJEXT): {$(VPATH)}encindex.h
hash.$(OBJEXT): {$(VPATH)}encoding.h
hash.$(OBJEXT): {$(VPATH)}hash.c
hash.$(OBJEXT): {$(VPATH)}hash.rbinc
@@ -6275,6 +6706,7 @@ hash.$(OBJEXT): {$(VPATH)}node.h
hash.$(OBJEXT): {$(VPATH)}onigmo.h
hash.$(OBJEXT): {$(VPATH)}oniguruma.h
hash.$(OBJEXT): {$(VPATH)}prism_compile.h
+hash.$(OBJEXT): {$(VPATH)}prism_xallocator.h
hash.$(OBJEXT): {$(VPATH)}probes.dmyh
hash.$(OBJEXT): {$(VPATH)}probes.h
hash.$(OBJEXT): {$(VPATH)}ractor.h
@@ -6300,17 +6732,18 @@ 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/box.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/namespace.h
imemo.$(OBJEXT): $(top_srcdir)/internal/object.h
imemo.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
imemo.$(OBJEXT): $(top_srcdir)/internal/serial.h
imemo.$(OBJEXT): $(top_srcdir)/internal/set_table.h
imemo.$(OBJEXT): $(top_srcdir)/internal/st.h
imemo.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
+imemo.$(OBJEXT): $(top_srcdir)/internal/struct.h
imemo.$(OBJEXT): $(top_srcdir)/internal/variable.h
imemo.$(OBJEXT): $(top_srcdir)/internal/vm.h
imemo.$(OBJEXT): $(top_srcdir)/internal/warnings.h
@@ -6678,7 +7111,9 @@ io.$(OBJEXT): $(top_srcdir)/internal/array.h
io.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
io.$(OBJEXT): $(top_srcdir)/internal/bignum.h
io.$(OBJEXT): $(top_srcdir)/internal/bits.h
+io.$(OBJEXT): $(top_srcdir)/internal/box.h
io.$(OBJEXT): $(top_srcdir)/internal/class.h
+io.$(OBJEXT): $(top_srcdir)/internal/compar.h
io.$(OBJEXT): $(top_srcdir)/internal/compilers.h
io.$(OBJEXT): $(top_srcdir)/internal/encoding.h
io.$(OBJEXT): $(top_srcdir)/internal/error.h
@@ -6687,7 +7122,6 @@ io.$(OBJEXT): $(top_srcdir)/internal/gc.h
io.$(OBJEXT): $(top_srcdir)/internal/imemo.h
io.$(OBJEXT): $(top_srcdir)/internal/inits.h
io.$(OBJEXT): $(top_srcdir)/internal/io.h
-io.$(OBJEXT): $(top_srcdir)/internal/namespace.h
io.$(OBJEXT): $(top_srcdir)/internal/numeric.h
io.$(OBJEXT): $(top_srcdir)/internal/object.h
io.$(OBJEXT): $(top_srcdir)/internal/process.h
@@ -6696,6 +7130,7 @@ io.$(OBJEXT): $(top_srcdir)/internal/serial.h
io.$(OBJEXT): $(top_srcdir)/internal/set_table.h
io.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
io.$(OBJEXT): $(top_srcdir)/internal/string.h
+io.$(OBJEXT): $(top_srcdir)/internal/struct.h
io.$(OBJEXT): $(top_srcdir)/internal/thread.h
io.$(OBJEXT): $(top_srcdir)/internal/transcode.h
io.$(OBJEXT): $(top_srcdir)/internal/variable.h
@@ -6909,13 +7344,14 @@ io_buffer.$(OBJEXT): $(top_srcdir)/internal/array.h
io_buffer.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
io_buffer.$(OBJEXT): $(top_srcdir)/internal/bignum.h
io_buffer.$(OBJEXT): $(top_srcdir)/internal/bits.h
+io_buffer.$(OBJEXT): $(top_srcdir)/internal/box.h
+io_buffer.$(OBJEXT): $(top_srcdir)/internal/compar.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/gc.h
io_buffer.$(OBJEXT): $(top_srcdir)/internal/imemo.h
io_buffer.$(OBJEXT): $(top_srcdir)/internal/io.h
-io_buffer.$(OBJEXT): $(top_srcdir)/internal/namespace.h
io_buffer.$(OBJEXT): $(top_srcdir)/internal/numeric.h
io_buffer.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
io_buffer.$(OBJEXT): $(top_srcdir)/internal/serial.h
@@ -6938,6 +7374,7 @@ io_buffer.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
io_buffer.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
io_buffer.$(OBJEXT): {$(VPATH)}config.h
io_buffer.$(OBJEXT): {$(VPATH)}defines.h
+io_buffer.$(OBJEXT): {$(VPATH)}encindex.h
io_buffer.$(OBJEXT): {$(VPATH)}encoding.h
io_buffer.$(OBJEXT): {$(VPATH)}fiber/scheduler.h
io_buffer.$(OBJEXT): {$(VPATH)}id.h
@@ -7123,7 +7560,9 @@ 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/box.h
iseq.$(OBJEXT): $(top_srcdir)/internal/class.h
+iseq.$(OBJEXT): $(top_srcdir)/internal/compar.h
iseq.$(OBJEXT): $(top_srcdir)/internal/compile.h
iseq.$(OBJEXT): $(top_srcdir)/internal/compilers.h
iseq.$(OBJEXT): $(top_srcdir)/internal/complex.h
@@ -7134,7 +7573,6 @@ 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/namespace.h
iseq.$(OBJEXT): $(top_srcdir)/internal/numeric.h
iseq.$(OBJEXT): $(top_srcdir)/internal/parse.h
iseq.$(OBJEXT): $(top_srcdir)/internal/rational.h
@@ -7144,33 +7582,46 @@ iseq.$(OBJEXT): $(top_srcdir)/internal/serial.h
iseq.$(OBJEXT): $(top_srcdir)/internal/set_table.h
iseq.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
iseq.$(OBJEXT): $(top_srcdir)/internal/string.h
+iseq.$(OBJEXT): $(top_srcdir)/internal/struct.h
iseq.$(OBJEXT): $(top_srcdir)/internal/symbol.h
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/arena.h
iseq.$(OBJEXT): $(top_srcdir)/prism/ast.h
-iseq.$(OBJEXT): $(top_srcdir)/prism/defines.h
+iseq.$(OBJEXT): $(top_srcdir)/prism/buffer.h
+iseq.$(OBJEXT): $(top_srcdir)/prism/comments.h
+iseq.$(OBJEXT): $(top_srcdir)/prism/compiler/align.h
+iseq.$(OBJEXT): $(top_srcdir)/prism/compiler/exported.h
+iseq.$(OBJEXT): $(top_srcdir)/prism/compiler/filesystem.h
+iseq.$(OBJEXT): $(top_srcdir)/prism/compiler/nodiscard.h
+iseq.$(OBJEXT): $(top_srcdir)/prism/compiler/nonnull.h
+iseq.$(OBJEXT): $(top_srcdir)/prism/constant_pool.h
iseq.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h
-iseq.$(OBJEXT): $(top_srcdir)/prism/encoding.h
+iseq.$(OBJEXT): $(top_srcdir)/prism/excludes.h
+iseq.$(OBJEXT): $(top_srcdir)/prism/integer.h
+iseq.$(OBJEXT): $(top_srcdir)/prism/internal/char.h
+iseq.$(OBJEXT): $(top_srcdir)/prism/internal/encoding.h
+iseq.$(OBJEXT): $(top_srcdir)/prism/internal/list.h
+iseq.$(OBJEXT): $(top_srcdir)/prism/internal/memchr.h
+iseq.$(OBJEXT): $(top_srcdir)/prism/internal/regexp.h
+iseq.$(OBJEXT): $(top_srcdir)/prism/internal/static_literals.h
+iseq.$(OBJEXT): $(top_srcdir)/prism/internal/strncasecmp.h
+iseq.$(OBJEXT): $(top_srcdir)/prism/internal/strpbrk.h
+iseq.$(OBJEXT): $(top_srcdir)/prism/json.h
+iseq.$(OBJEXT): $(top_srcdir)/prism/line_offset_list.h
+iseq.$(OBJEXT): $(top_srcdir)/prism/magic_comments.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): $(top_srcdir)/prism/serialize.h
+iseq.$(OBJEXT): $(top_srcdir)/prism/source.h
+iseq.$(OBJEXT): $(top_srcdir)/prism/stream.h
+iseq.$(OBJEXT): $(top_srcdir)/prism/string_query.h
+iseq.$(OBJEXT): $(top_srcdir)/prism/stringy.h
iseq.$(OBJEXT): $(top_srcdir)/prism/version.h
iseq.$(OBJEXT): {$(VPATH)}assert.h
iseq.$(OBJEXT): {$(VPATH)}atomic.h
@@ -7188,6 +7639,7 @@ iseq.$(OBJEXT): {$(VPATH)}config.h
iseq.$(OBJEXT): {$(VPATH)}constant.h
iseq.$(OBJEXT): {$(VPATH)}debug_counter.h
iseq.$(OBJEXT): {$(VPATH)}defines.h
+iseq.$(OBJEXT): {$(VPATH)}encindex.h
iseq.$(OBJEXT): {$(VPATH)}encoding.h
iseq.$(OBJEXT): {$(VPATH)}eval_intern.h
iseq.$(OBJEXT): {$(VPATH)}id.h
@@ -7356,7 +7808,9 @@ iseq.$(OBJEXT): {$(VPATH)}node.h
iseq.$(OBJEXT): {$(VPATH)}onigmo.h
iseq.$(OBJEXT): {$(VPATH)}oniguruma.h
iseq.$(OBJEXT): {$(VPATH)}prism_compile.h
+iseq.$(OBJEXT): {$(VPATH)}prism_xallocator.h
iseq.$(OBJEXT): {$(VPATH)}ractor.h
+iseq.$(OBJEXT): {$(VPATH)}ractor_core.h
iseq.$(OBJEXT): {$(VPATH)}ruby_assert.h
iseq.$(OBJEXT): {$(VPATH)}ruby_atomic.h
iseq.$(OBJEXT): {$(VPATH)}rubyparser.h
@@ -7380,40 +7834,57 @@ jit.$(OBJEXT): $(CCAN_DIR)/str/str.h
jit.$(OBJEXT): $(hdrdir)/ruby/ruby.h
jit.$(OBJEXT): $(top_srcdir)/internal/array.h
jit.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
+jit.$(OBJEXT): $(top_srcdir)/internal/bits.h
+jit.$(OBJEXT): $(top_srcdir)/internal/box.h
jit.$(OBJEXT): $(top_srcdir)/internal/class.h
+jit.$(OBJEXT): $(top_srcdir)/internal/compile.h
jit.$(OBJEXT): $(top_srcdir)/internal/compilers.h
+jit.$(OBJEXT): $(top_srcdir)/internal/fixnum.h
jit.$(OBJEXT): $(top_srcdir)/internal/gc.h
jit.$(OBJEXT): $(top_srcdir)/internal/imemo.h
-jit.$(OBJEXT): $(top_srcdir)/internal/namespace.h
jit.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
jit.$(OBJEXT): $(top_srcdir)/internal/serial.h
jit.$(OBJEXT): $(top_srcdir)/internal/set_table.h
jit.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
+jit.$(OBJEXT): $(top_srcdir)/internal/string.h
+jit.$(OBJEXT): $(top_srcdir)/internal/struct.h
jit.$(OBJEXT): $(top_srcdir)/internal/variable.h
jit.$(OBJEXT): $(top_srcdir)/internal/vm.h
jit.$(OBJEXT): $(top_srcdir)/internal/warnings.h
+jit.$(OBJEXT): $(top_srcdir)/prism/arena.h
jit.$(OBJEXT): $(top_srcdir)/prism/ast.h
-jit.$(OBJEXT): $(top_srcdir)/prism/defines.h
+jit.$(OBJEXT): $(top_srcdir)/prism/buffer.h
+jit.$(OBJEXT): $(top_srcdir)/prism/comments.h
+jit.$(OBJEXT): $(top_srcdir)/prism/compiler/align.h
+jit.$(OBJEXT): $(top_srcdir)/prism/compiler/exported.h
+jit.$(OBJEXT): $(top_srcdir)/prism/compiler/filesystem.h
+jit.$(OBJEXT): $(top_srcdir)/prism/compiler/nodiscard.h
+jit.$(OBJEXT): $(top_srcdir)/prism/compiler/nonnull.h
+jit.$(OBJEXT): $(top_srcdir)/prism/constant_pool.h
jit.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h
-jit.$(OBJEXT): $(top_srcdir)/prism/encoding.h
+jit.$(OBJEXT): $(top_srcdir)/prism/excludes.h
+jit.$(OBJEXT): $(top_srcdir)/prism/integer.h
+jit.$(OBJEXT): $(top_srcdir)/prism/internal/char.h
+jit.$(OBJEXT): $(top_srcdir)/prism/internal/encoding.h
+jit.$(OBJEXT): $(top_srcdir)/prism/internal/list.h
+jit.$(OBJEXT): $(top_srcdir)/prism/internal/memchr.h
+jit.$(OBJEXT): $(top_srcdir)/prism/internal/regexp.h
+jit.$(OBJEXT): $(top_srcdir)/prism/internal/static_literals.h
+jit.$(OBJEXT): $(top_srcdir)/prism/internal/strncasecmp.h
+jit.$(OBJEXT): $(top_srcdir)/prism/internal/strpbrk.h
+jit.$(OBJEXT): $(top_srcdir)/prism/json.h
+jit.$(OBJEXT): $(top_srcdir)/prism/line_offset_list.h
+jit.$(OBJEXT): $(top_srcdir)/prism/magic_comments.h
jit.$(OBJEXT): $(top_srcdir)/prism/node.h
jit.$(OBJEXT): $(top_srcdir)/prism/options.h
-jit.$(OBJEXT): $(top_srcdir)/prism/pack.h
jit.$(OBJEXT): $(top_srcdir)/prism/parser.h
jit.$(OBJEXT): $(top_srcdir)/prism/prettyprint.h
jit.$(OBJEXT): $(top_srcdir)/prism/prism.h
-jit.$(OBJEXT): $(top_srcdir)/prism/regexp.h
-jit.$(OBJEXT): $(top_srcdir)/prism/static_literals.h
-jit.$(OBJEXT): $(top_srcdir)/prism/util/pm_buffer.h
-jit.$(OBJEXT): $(top_srcdir)/prism/util/pm_char.h
-jit.$(OBJEXT): $(top_srcdir)/prism/util/pm_constant_pool.h
-jit.$(OBJEXT): $(top_srcdir)/prism/util/pm_integer.h
-jit.$(OBJEXT): $(top_srcdir)/prism/util/pm_list.h
-jit.$(OBJEXT): $(top_srcdir)/prism/util/pm_memchr.h
-jit.$(OBJEXT): $(top_srcdir)/prism/util/pm_newline_list.h
-jit.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h
-jit.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.h
-jit.$(OBJEXT): $(top_srcdir)/prism/util/pm_strpbrk.h
+jit.$(OBJEXT): $(top_srcdir)/prism/serialize.h
+jit.$(OBJEXT): $(top_srcdir)/prism/source.h
+jit.$(OBJEXT): $(top_srcdir)/prism/stream.h
+jit.$(OBJEXT): $(top_srcdir)/prism/string_query.h
+jit.$(OBJEXT): $(top_srcdir)/prism/stringy.h
jit.$(OBJEXT): $(top_srcdir)/prism/version.h
jit.$(OBJEXT): {$(VPATH)}assert.h
jit.$(OBJEXT): {$(VPATH)}atomic.h
@@ -7431,6 +7902,7 @@ jit.$(OBJEXT): {$(VPATH)}config.h
jit.$(OBJEXT): {$(VPATH)}constant.h
jit.$(OBJEXT): {$(VPATH)}debug_counter.h
jit.$(OBJEXT): {$(VPATH)}defines.h
+jit.$(OBJEXT): {$(VPATH)}encindex.h
jit.$(OBJEXT): {$(VPATH)}encoding.h
jit.$(OBJEXT): {$(VPATH)}id.h
jit.$(OBJEXT): {$(VPATH)}id_table.h
@@ -7597,6 +8069,7 @@ jit.$(OBJEXT): {$(VPATH)}node.h
jit.$(OBJEXT): {$(VPATH)}onigmo.h
jit.$(OBJEXT): {$(VPATH)}oniguruma.h
jit.$(OBJEXT): {$(VPATH)}prism_compile.h
+jit.$(OBJEXT): {$(VPATH)}prism_xallocator.h
jit.$(OBJEXT): {$(VPATH)}ruby_assert.h
jit.$(OBJEXT): {$(VPATH)}ruby_atomic.h
jit.$(OBJEXT): {$(VPATH)}rubyparser.h
@@ -7610,6 +8083,7 @@ jit.$(OBJEXT): {$(VPATH)}vm_core.h
jit.$(OBJEXT): {$(VPATH)}vm_debug.h
jit.$(OBJEXT): {$(VPATH)}vm_opts.h
jit.$(OBJEXT): {$(VPATH)}vm_sync.h
+jit.$(OBJEXT): {$(VPATH)}zjit.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
@@ -7620,6 +8094,8 @@ 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/box.h
+load.$(OBJEXT): $(top_srcdir)/internal/compar.h
load.$(OBJEXT): $(top_srcdir)/internal/compilers.h
load.$(OBJEXT): $(top_srcdir)/internal/complex.h
load.$(OBJEXT): $(top_srcdir)/internal/dir.h
@@ -7631,7 +8107,6 @@ 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/namespace.h
load.$(OBJEXT): $(top_srcdir)/internal/numeric.h
load.$(OBJEXT): $(top_srcdir)/internal/parse.h
load.$(OBJEXT): $(top_srcdir)/internal/rational.h
@@ -7641,32 +8116,45 @@ load.$(OBJEXT): $(top_srcdir)/internal/serial.h
load.$(OBJEXT): $(top_srcdir)/internal/set_table.h
load.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
load.$(OBJEXT): $(top_srcdir)/internal/string.h
+load.$(OBJEXT): $(top_srcdir)/internal/struct.h
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/arena.h
load.$(OBJEXT): $(top_srcdir)/prism/ast.h
-load.$(OBJEXT): $(top_srcdir)/prism/defines.h
+load.$(OBJEXT): $(top_srcdir)/prism/buffer.h
+load.$(OBJEXT): $(top_srcdir)/prism/comments.h
+load.$(OBJEXT): $(top_srcdir)/prism/compiler/align.h
+load.$(OBJEXT): $(top_srcdir)/prism/compiler/exported.h
+load.$(OBJEXT): $(top_srcdir)/prism/compiler/filesystem.h
+load.$(OBJEXT): $(top_srcdir)/prism/compiler/nodiscard.h
+load.$(OBJEXT): $(top_srcdir)/prism/compiler/nonnull.h
+load.$(OBJEXT): $(top_srcdir)/prism/constant_pool.h
load.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h
-load.$(OBJEXT): $(top_srcdir)/prism/encoding.h
+load.$(OBJEXT): $(top_srcdir)/prism/excludes.h
+load.$(OBJEXT): $(top_srcdir)/prism/integer.h
+load.$(OBJEXT): $(top_srcdir)/prism/internal/char.h
+load.$(OBJEXT): $(top_srcdir)/prism/internal/encoding.h
+load.$(OBJEXT): $(top_srcdir)/prism/internal/list.h
+load.$(OBJEXT): $(top_srcdir)/prism/internal/memchr.h
+load.$(OBJEXT): $(top_srcdir)/prism/internal/regexp.h
+load.$(OBJEXT): $(top_srcdir)/prism/internal/static_literals.h
+load.$(OBJEXT): $(top_srcdir)/prism/internal/strncasecmp.h
+load.$(OBJEXT): $(top_srcdir)/prism/internal/strpbrk.h
+load.$(OBJEXT): $(top_srcdir)/prism/json.h
+load.$(OBJEXT): $(top_srcdir)/prism/line_offset_list.h
+load.$(OBJEXT): $(top_srcdir)/prism/magic_comments.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): $(top_srcdir)/prism/serialize.h
+load.$(OBJEXT): $(top_srcdir)/prism/source.h
+load.$(OBJEXT): $(top_srcdir)/prism/stream.h
+load.$(OBJEXT): $(top_srcdir)/prism/string_query.h
+load.$(OBJEXT): $(top_srcdir)/prism/stringy.h
load.$(OBJEXT): $(top_srcdir)/prism/version.h
load.$(OBJEXT): {$(VPATH)}assert.h
load.$(OBJEXT): {$(VPATH)}atomic.h
@@ -7684,6 +8172,7 @@ load.$(OBJEXT): {$(VPATH)}constant.h
load.$(OBJEXT): {$(VPATH)}darray.h
load.$(OBJEXT): {$(VPATH)}defines.h
load.$(OBJEXT): {$(VPATH)}dln.h
+load.$(OBJEXT): {$(VPATH)}encindex.h
load.$(OBJEXT): {$(VPATH)}encoding.h
load.$(OBJEXT): {$(VPATH)}eval_intern.h
load.$(OBJEXT): {$(VPATH)}id.h
@@ -7848,6 +8337,7 @@ load.$(OBJEXT): {$(VPATH)}node.h
load.$(OBJEXT): {$(VPATH)}onigmo.h
load.$(OBJEXT): {$(VPATH)}oniguruma.h
load.$(OBJEXT): {$(VPATH)}prism_compile.h
+load.$(OBJEXT): {$(VPATH)}prism_xallocator.h
load.$(OBJEXT): {$(VPATH)}probes.dmyh
load.$(OBJEXT): {$(VPATH)}probes.h
load.$(OBJEXT): {$(VPATH)}ractor.h
@@ -7864,6 +8354,7 @@ load.$(OBJEXT): {$(VPATH)}util.h
load.$(OBJEXT): {$(VPATH)}vm_core.h
load.$(OBJEXT): {$(VPATH)}vm_debug.h
load.$(OBJEXT): {$(VPATH)}vm_opts.h
+load.$(OBJEXT): {$(VPATH)}zjit.h
loadpath.$(OBJEXT): $(hdrdir)/ruby/ruby.h
loadpath.$(OBJEXT): $(hdrdir)/ruby/version.h
loadpath.$(OBJEXT): $(top_srcdir)/version.h
@@ -8372,7 +8863,9 @@ marshal.$(OBJEXT): $(top_srcdir)/internal/array.h
marshal.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
marshal.$(OBJEXT): $(top_srcdir)/internal/bignum.h
marshal.$(OBJEXT): $(top_srcdir)/internal/bits.h
+marshal.$(OBJEXT): $(top_srcdir)/internal/box.h
marshal.$(OBJEXT): $(top_srcdir)/internal/class.h
+marshal.$(OBJEXT): $(top_srcdir)/internal/compar.h
marshal.$(OBJEXT): $(top_srcdir)/internal/compilers.h
marshal.$(OBJEXT): $(top_srcdir)/internal/encoding.h
marshal.$(OBJEXT): $(top_srcdir)/internal/error.h
@@ -8380,9 +8873,9 @@ marshal.$(OBJEXT): $(top_srcdir)/internal/fixnum.h
marshal.$(OBJEXT): $(top_srcdir)/internal/gc.h
marshal.$(OBJEXT): $(top_srcdir)/internal/hash.h
marshal.$(OBJEXT): $(top_srcdir)/internal/imemo.h
-marshal.$(OBJEXT): $(top_srcdir)/internal/namespace.h
marshal.$(OBJEXT): $(top_srcdir)/internal/numeric.h
marshal.$(OBJEXT): $(top_srcdir)/internal/object.h
+marshal.$(OBJEXT): $(top_srcdir)/internal/re.h
marshal.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
marshal.$(OBJEXT): $(top_srcdir)/internal/serial.h
marshal.$(OBJEXT): $(top_srcdir)/internal/set_table.h
@@ -8480,6 +8973,7 @@ marshal.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
marshal.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
marshal.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
marshal.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
+marshal.$(OBJEXT): {$(VPATH)}internal/core/rmatch.h
marshal.$(OBJEXT): {$(VPATH)}internal/core/robject.h
marshal.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
marshal.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
@@ -8575,6 +9069,8 @@ marshal.$(OBJEXT): {$(VPATH)}missing.h
marshal.$(OBJEXT): {$(VPATH)}node.h
marshal.$(OBJEXT): {$(VPATH)}onigmo.h
marshal.$(OBJEXT): {$(VPATH)}oniguruma.h
+marshal.$(OBJEXT): {$(VPATH)}re.h
+marshal.$(OBJEXT): {$(VPATH)}regex.h
marshal.$(OBJEXT): {$(VPATH)}ruby_assert.h
marshal.$(OBJEXT): {$(VPATH)}ruby_atomic.h
marshal.$(OBJEXT): {$(VPATH)}rubyparser.h
@@ -8770,15 +9266,16 @@ 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/box.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/namespace.h
memory_view.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
memory_view.$(OBJEXT): $(top_srcdir)/internal/serial.h
memory_view.$(OBJEXT): $(top_srcdir)/internal/set_table.h
memory_view.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
+memory_view.$(OBJEXT): $(top_srcdir)/internal/struct.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
@@ -8981,13 +9478,14 @@ 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/box.h
+miniinit.$(OBJEXT): $(top_srcdir)/internal/compar.h
miniinit.$(OBJEXT): $(top_srcdir)/internal/compilers.h
miniinit.$(OBJEXT): $(top_srcdir)/internal/complex.h
miniinit.$(OBJEXT): $(top_srcdir)/internal/eval.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/namespace.h
miniinit.$(OBJEXT): $(top_srcdir)/internal/numeric.h
miniinit.$(OBJEXT): $(top_srcdir)/internal/parse.h
miniinit.$(OBJEXT): $(top_srcdir)/internal/rational.h
@@ -8996,31 +9494,44 @@ miniinit.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
miniinit.$(OBJEXT): $(top_srcdir)/internal/serial.h
miniinit.$(OBJEXT): $(top_srcdir)/internal/set_table.h
miniinit.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
+miniinit.$(OBJEXT): $(top_srcdir)/internal/struct.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/arena.h
miniinit.$(OBJEXT): $(top_srcdir)/prism/ast.h
-miniinit.$(OBJEXT): $(top_srcdir)/prism/defines.h
+miniinit.$(OBJEXT): $(top_srcdir)/prism/buffer.h
+miniinit.$(OBJEXT): $(top_srcdir)/prism/comments.h
+miniinit.$(OBJEXT): $(top_srcdir)/prism/compiler/align.h
+miniinit.$(OBJEXT): $(top_srcdir)/prism/compiler/exported.h
+miniinit.$(OBJEXT): $(top_srcdir)/prism/compiler/filesystem.h
+miniinit.$(OBJEXT): $(top_srcdir)/prism/compiler/nodiscard.h
+miniinit.$(OBJEXT): $(top_srcdir)/prism/compiler/nonnull.h
+miniinit.$(OBJEXT): $(top_srcdir)/prism/constant_pool.h
miniinit.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h
-miniinit.$(OBJEXT): $(top_srcdir)/prism/encoding.h
+miniinit.$(OBJEXT): $(top_srcdir)/prism/excludes.h
+miniinit.$(OBJEXT): $(top_srcdir)/prism/integer.h
+miniinit.$(OBJEXT): $(top_srcdir)/prism/internal/char.h
+miniinit.$(OBJEXT): $(top_srcdir)/prism/internal/encoding.h
+miniinit.$(OBJEXT): $(top_srcdir)/prism/internal/list.h
+miniinit.$(OBJEXT): $(top_srcdir)/prism/internal/memchr.h
+miniinit.$(OBJEXT): $(top_srcdir)/prism/internal/regexp.h
+miniinit.$(OBJEXT): $(top_srcdir)/prism/internal/static_literals.h
+miniinit.$(OBJEXT): $(top_srcdir)/prism/internal/strncasecmp.h
+miniinit.$(OBJEXT): $(top_srcdir)/prism/internal/strpbrk.h
+miniinit.$(OBJEXT): $(top_srcdir)/prism/json.h
+miniinit.$(OBJEXT): $(top_srcdir)/prism/line_offset_list.h
+miniinit.$(OBJEXT): $(top_srcdir)/prism/magic_comments.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): $(top_srcdir)/prism/serialize.h
+miniinit.$(OBJEXT): $(top_srcdir)/prism/source.h
+miniinit.$(OBJEXT): $(top_srcdir)/prism/stream.h
+miniinit.$(OBJEXT): $(top_srcdir)/prism/string_query.h
+miniinit.$(OBJEXT): $(top_srcdir)/prism/stringy.h
miniinit.$(OBJEXT): $(top_srcdir)/prism/version.h
miniinit.$(OBJEXT): {$(VPATH)}array.rb
miniinit.$(OBJEXT): {$(VPATH)}assert.h
@@ -9218,6 +9729,7 @@ miniinit.$(OBJEXT): {$(VPATH)}pack.rb
miniinit.$(OBJEXT): {$(VPATH)}pathname_builtin.rb
miniinit.$(OBJEXT): {$(VPATH)}prelude.rb
miniinit.$(OBJEXT): {$(VPATH)}prism_compile.h
+miniinit.$(OBJEXT): {$(VPATH)}prism_xallocator.h
miniinit.$(OBJEXT): {$(VPATH)}ractor.rb
miniinit.$(OBJEXT): {$(VPATH)}ruby_assert.h
miniinit.$(OBJEXT): {$(VPATH)}ruby_atomic.h
@@ -9236,221 +9748,6 @@ miniinit.$(OBJEXT): {$(VPATH)}vm_opts.h
miniinit.$(OBJEXT): {$(VPATH)}warning.rb
miniinit.$(OBJEXT): {$(VPATH)}yjit.rb
miniinit.$(OBJEXT): {$(VPATH)}zjit.rb
-namespace.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
-namespace.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
-namespace.$(OBJEXT): $(CCAN_DIR)/list/list.h
-namespace.$(OBJEXT): $(CCAN_DIR)/str/str.h
-namespace.$(OBJEXT): $(hdrdir)/ruby/ruby.h
-namespace.$(OBJEXT): $(top_srcdir)/internal/array.h
-namespace.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
-namespace.$(OBJEXT): $(top_srcdir)/internal/class.h
-namespace.$(OBJEXT): $(top_srcdir)/internal/compilers.h
-namespace.$(OBJEXT): $(top_srcdir)/internal/error.h
-namespace.$(OBJEXT): $(top_srcdir)/internal/eval.h
-namespace.$(OBJEXT): $(top_srcdir)/internal/file.h
-namespace.$(OBJEXT): $(top_srcdir)/internal/gc.h
-namespace.$(OBJEXT): $(top_srcdir)/internal/hash.h
-namespace.$(OBJEXT): $(top_srcdir)/internal/imemo.h
-namespace.$(OBJEXT): $(top_srcdir)/internal/load.h
-namespace.$(OBJEXT): $(top_srcdir)/internal/namespace.h
-namespace.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
-namespace.$(OBJEXT): $(top_srcdir)/internal/serial.h
-namespace.$(OBJEXT): $(top_srcdir)/internal/set_table.h
-namespace.$(OBJEXT): $(top_srcdir)/internal/st.h
-namespace.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
-namespace.$(OBJEXT): $(top_srcdir)/internal/string.h
-namespace.$(OBJEXT): $(top_srcdir)/internal/variable.h
-namespace.$(OBJEXT): $(top_srcdir)/internal/vm.h
-namespace.$(OBJEXT): $(top_srcdir)/internal/warnings.h
-namespace.$(OBJEXT): {$(VPATH)}assert.h
-namespace.$(OBJEXT): {$(VPATH)}atomic.h
-namespace.$(OBJEXT): {$(VPATH)}backward/2/assume.h
-namespace.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
-namespace.$(OBJEXT): {$(VPATH)}backward/2/bool.h
-namespace.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
-namespace.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
-namespace.$(OBJEXT): {$(VPATH)}backward/2/limits.h
-namespace.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
-namespace.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
-namespace.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
-namespace.$(OBJEXT): {$(VPATH)}config.h
-namespace.$(OBJEXT): {$(VPATH)}constant.h
-namespace.$(OBJEXT): {$(VPATH)}debug_counter.h
-namespace.$(OBJEXT): {$(VPATH)}defines.h
-namespace.$(OBJEXT): {$(VPATH)}encoding.h
-namespace.$(OBJEXT): {$(VPATH)}id.h
-namespace.$(OBJEXT): {$(VPATH)}id_table.h
-namespace.$(OBJEXT): {$(VPATH)}intern.h
-namespace.$(OBJEXT): {$(VPATH)}internal.h
-namespace.$(OBJEXT): {$(VPATH)}internal/abi.h
-namespace.$(OBJEXT): {$(VPATH)}internal/anyargs.h
-namespace.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
-namespace.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
-namespace.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
-namespace.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
-namespace.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
-namespace.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
-namespace.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
-namespace.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
-namespace.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
-namespace.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
-namespace.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
-namespace.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
-namespace.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
-namespace.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
-namespace.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
-namespace.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
-namespace.$(OBJEXT): {$(VPATH)}internal/assume.h
-namespace.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
-namespace.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
-namespace.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
-namespace.$(OBJEXT): {$(VPATH)}internal/attr/const.h
-namespace.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
-namespace.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
-namespace.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
-namespace.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
-namespace.$(OBJEXT): {$(VPATH)}internal/attr/error.h
-namespace.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
-namespace.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
-namespace.$(OBJEXT): {$(VPATH)}internal/attr/format.h
-namespace.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
-namespace.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
-namespace.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
-namespace.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
-namespace.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
-namespace.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
-namespace.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-namespace.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
-namespace.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
-namespace.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
-namespace.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
-namespace.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
-namespace.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
-namespace.$(OBJEXT): {$(VPATH)}internal/cast.h
-namespace.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
-namespace.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
-namespace.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
-namespace.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
-namespace.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
-namespace.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
-namespace.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
-namespace.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
-namespace.$(OBJEXT): {$(VPATH)}internal/config.h
-namespace.$(OBJEXT): {$(VPATH)}internal/constant_p.h
-namespace.$(OBJEXT): {$(VPATH)}internal/core.h
-namespace.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
-namespace.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
-namespace.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
-namespace.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
-namespace.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
-namespace.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
-namespace.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
-namespace.$(OBJEXT): {$(VPATH)}internal/core/robject.h
-namespace.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
-namespace.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
-namespace.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
-namespace.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
-namespace.$(OBJEXT): {$(VPATH)}internal/ctype.h
-namespace.$(OBJEXT): {$(VPATH)}internal/dllexport.h
-namespace.$(OBJEXT): {$(VPATH)}internal/dosish.h
-namespace.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
-namespace.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
-namespace.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
-namespace.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
-namespace.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
-namespace.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
-namespace.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
-namespace.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
-namespace.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
-namespace.$(OBJEXT): {$(VPATH)}internal/error.h
-namespace.$(OBJEXT): {$(VPATH)}internal/eval.h
-namespace.$(OBJEXT): {$(VPATH)}internal/event.h
-namespace.$(OBJEXT): {$(VPATH)}internal/fl_type.h
-namespace.$(OBJEXT): {$(VPATH)}internal/gc.h
-namespace.$(OBJEXT): {$(VPATH)}internal/glob.h
-namespace.$(OBJEXT): {$(VPATH)}internal/globals.h
-namespace.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
-namespace.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
-namespace.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
-namespace.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
-namespace.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
-namespace.$(OBJEXT): {$(VPATH)}internal/has/extension.h
-namespace.$(OBJEXT): {$(VPATH)}internal/has/feature.h
-namespace.$(OBJEXT): {$(VPATH)}internal/has/warning.h
-namespace.$(OBJEXT): {$(VPATH)}internal/intern/array.h
-namespace.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
-namespace.$(OBJEXT): {$(VPATH)}internal/intern/class.h
-namespace.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
-namespace.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
-namespace.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
-namespace.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
-namespace.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
-namespace.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
-namespace.$(OBJEXT): {$(VPATH)}internal/intern/error.h
-namespace.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
-namespace.$(OBJEXT): {$(VPATH)}internal/intern/file.h
-namespace.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
-namespace.$(OBJEXT): {$(VPATH)}internal/intern/io.h
-namespace.$(OBJEXT): {$(VPATH)}internal/intern/load.h
-namespace.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
-namespace.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
-namespace.$(OBJEXT): {$(VPATH)}internal/intern/object.h
-namespace.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
-namespace.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
-namespace.$(OBJEXT): {$(VPATH)}internal/intern/process.h
-namespace.$(OBJEXT): {$(VPATH)}internal/intern/random.h
-namespace.$(OBJEXT): {$(VPATH)}internal/intern/range.h
-namespace.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
-namespace.$(OBJEXT): {$(VPATH)}internal/intern/re.h
-namespace.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
-namespace.$(OBJEXT): {$(VPATH)}internal/intern/select.h
-namespace.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
-namespace.$(OBJEXT): {$(VPATH)}internal/intern/set.h
-namespace.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
-namespace.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
-namespace.$(OBJEXT): {$(VPATH)}internal/intern/string.h
-namespace.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
-namespace.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
-namespace.$(OBJEXT): {$(VPATH)}internal/intern/time.h
-namespace.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
-namespace.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
-namespace.$(OBJEXT): {$(VPATH)}internal/interpreter.h
-namespace.$(OBJEXT): {$(VPATH)}internal/iterator.h
-namespace.$(OBJEXT): {$(VPATH)}internal/memory.h
-namespace.$(OBJEXT): {$(VPATH)}internal/method.h
-namespace.$(OBJEXT): {$(VPATH)}internal/module.h
-namespace.$(OBJEXT): {$(VPATH)}internal/newobj.h
-namespace.$(OBJEXT): {$(VPATH)}internal/scan_args.h
-namespace.$(OBJEXT): {$(VPATH)}internal/special_consts.h
-namespace.$(OBJEXT): {$(VPATH)}internal/static_assert.h
-namespace.$(OBJEXT): {$(VPATH)}internal/stdalign.h
-namespace.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-namespace.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
-namespace.$(OBJEXT): {$(VPATH)}internal/symbol.h
-namespace.$(OBJEXT): {$(VPATH)}internal/value.h
-namespace.$(OBJEXT): {$(VPATH)}internal/value_type.h
-namespace.$(OBJEXT): {$(VPATH)}internal/variable.h
-namespace.$(OBJEXT): {$(VPATH)}internal/warning_push.h
-namespace.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
-namespace.$(OBJEXT): {$(VPATH)}method.h
-namespace.$(OBJEXT): {$(VPATH)}missing.h
-namespace.$(OBJEXT): {$(VPATH)}namespace.c
-namespace.$(OBJEXT): {$(VPATH)}node.h
-namespace.$(OBJEXT): {$(VPATH)}onigmo.h
-namespace.$(OBJEXT): {$(VPATH)}oniguruma.h
-namespace.$(OBJEXT): {$(VPATH)}ruby_assert.h
-namespace.$(OBJEXT): {$(VPATH)}ruby_atomic.h
-namespace.$(OBJEXT): {$(VPATH)}rubyparser.h
-namespace.$(OBJEXT): {$(VPATH)}shape.h
-namespace.$(OBJEXT): {$(VPATH)}st.h
-namespace.$(OBJEXT): {$(VPATH)}subst.h
-namespace.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
-namespace.$(OBJEXT): {$(VPATH)}thread_native.h
-namespace.$(OBJEXT): {$(VPATH)}util.h
-namespace.$(OBJEXT): {$(VPATH)}vm_core.h
-namespace.$(OBJEXT): {$(VPATH)}vm_debug.h
-namespace.$(OBJEXT): {$(VPATH)}vm_opts.h
-namespace.$(OBJEXT): {$(VPATH)}vm_sync.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
@@ -9458,15 +9755,16 @@ node.$(OBJEXT): $(CCAN_DIR)/str/str.h
node.$(OBJEXT): $(hdrdir)/ruby/ruby.h
node.$(OBJEXT): $(top_srcdir)/internal/array.h
node.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
+node.$(OBJEXT): $(top_srcdir)/internal/box.h
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/namespace.h
node.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
node.$(OBJEXT): $(top_srcdir)/internal/serial.h
node.$(OBJEXT): $(top_srcdir)/internal/set_table.h
node.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
+node.$(OBJEXT): $(top_srcdir)/internal/struct.h
node.$(OBJEXT): $(top_srcdir)/internal/variable.h
node.$(OBJEXT): $(top_srcdir)/internal/vm.h
node.$(OBJEXT): $(top_srcdir)/internal/warnings.h
@@ -9665,14 +9963,15 @@ 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/box.h
node_dump.$(OBJEXT): $(top_srcdir)/internal/class.h
+node_dump.$(OBJEXT): $(top_srcdir)/internal/compar.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/namespace.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
@@ -9681,6 +9980,7 @@ node_dump.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
node_dump.$(OBJEXT): $(top_srcdir)/internal/serial.h
node_dump.$(OBJEXT): $(top_srcdir)/internal/set_table.h
node_dump.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
+node_dump.$(OBJEXT): $(top_srcdir)/internal/struct.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
@@ -9881,15 +10181,17 @@ 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/box.h
numeric.$(OBJEXT): $(top_srcdir)/internal/class.h
+numeric.$(OBJEXT): $(top_srcdir)/internal/compar.h
numeric.$(OBJEXT): $(top_srcdir)/internal/compilers.h
numeric.$(OBJEXT): $(top_srcdir)/internal/complex.h
numeric.$(OBJEXT): $(top_srcdir)/internal/enumerator.h
+numeric.$(OBJEXT): $(top_srcdir)/internal/error.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/namespace.h
numeric.$(OBJEXT): $(top_srcdir)/internal/numeric.h
numeric.$(OBJEXT): $(top_srcdir)/internal/object.h
numeric.$(OBJEXT): $(top_srcdir)/internal/rational.h
@@ -9898,6 +10200,7 @@ numeric.$(OBJEXT): $(top_srcdir)/internal/serial.h
numeric.$(OBJEXT): $(top_srcdir)/internal/set_table.h
numeric.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
numeric.$(OBJEXT): $(top_srcdir)/internal/string.h
+numeric.$(OBJEXT): $(top_srcdir)/internal/struct.h
numeric.$(OBJEXT): $(top_srcdir)/internal/util.h
numeric.$(OBJEXT): $(top_srcdir)/internal/variable.h
numeric.$(OBJEXT): $(top_srcdir)/internal/vm.h
@@ -9917,6 +10220,7 @@ numeric.$(OBJEXT): {$(VPATH)}builtin.h
numeric.$(OBJEXT): {$(VPATH)}config.h
numeric.$(OBJEXT): {$(VPATH)}constant.h
numeric.$(OBJEXT): {$(VPATH)}defines.h
+numeric.$(OBJEXT): {$(VPATH)}encindex.h
numeric.$(OBJEXT): {$(VPATH)}encoding.h
numeric.$(OBJEXT): {$(VPATH)}id.h
numeric.$(OBJEXT): {$(VPATH)}id_table.h
@@ -10100,7 +10404,9 @@ object.$(OBJEXT): $(top_srcdir)/internal/array.h
object.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
object.$(OBJEXT): $(top_srcdir)/internal/bignum.h
object.$(OBJEXT): $(top_srcdir)/internal/bits.h
+object.$(OBJEXT): $(top_srcdir)/internal/box.h
object.$(OBJEXT): $(top_srcdir)/internal/class.h
+object.$(OBJEXT): $(top_srcdir)/internal/compar.h
object.$(OBJEXT): $(top_srcdir)/internal/compilers.h
object.$(OBJEXT): $(top_srcdir)/internal/error.h
object.$(OBJEXT): $(top_srcdir)/internal/eval.h
@@ -10108,7 +10414,6 @@ object.$(OBJEXT): $(top_srcdir)/internal/fixnum.h
object.$(OBJEXT): $(top_srcdir)/internal/gc.h
object.$(OBJEXT): $(top_srcdir)/internal/imemo.h
object.$(OBJEXT): $(top_srcdir)/internal/inits.h
-object.$(OBJEXT): $(top_srcdir)/internal/namespace.h
object.$(OBJEXT): $(top_srcdir)/internal/numeric.h
object.$(OBJEXT): $(top_srcdir)/internal/object.h
object.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
@@ -10138,6 +10443,7 @@ object.$(OBJEXT): {$(VPATH)}config.h
object.$(OBJEXT): {$(VPATH)}constant.h
object.$(OBJEXT): {$(VPATH)}debug_counter.h
object.$(OBJEXT): {$(VPATH)}defines.h
+object.$(OBJEXT): {$(VPATH)}encindex.h
object.$(OBJEXT): {$(VPATH)}encoding.h
object.$(OBJEXT): {$(VPATH)}id.h
object.$(OBJEXT): {$(VPATH)}id_table.h
@@ -10326,16 +10632,21 @@ 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/bignum.h
pack.$(OBJEXT): $(top_srcdir)/internal/bits.h
+pack.$(OBJEXT): $(top_srcdir)/internal/box.h
+pack.$(OBJEXT): $(top_srcdir)/internal/compar.h
pack.$(OBJEXT): $(top_srcdir)/internal/compilers.h
+pack.$(OBJEXT): $(top_srcdir)/internal/fixnum.h
pack.$(OBJEXT): $(top_srcdir)/internal/gc.h
pack.$(OBJEXT): $(top_srcdir)/internal/imemo.h
-pack.$(OBJEXT): $(top_srcdir)/internal/namespace.h
+pack.$(OBJEXT): $(top_srcdir)/internal/numeric.h
pack.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
pack.$(OBJEXT): $(top_srcdir)/internal/serial.h
pack.$(OBJEXT): $(top_srcdir)/internal/set_table.h
pack.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
pack.$(OBJEXT): $(top_srcdir)/internal/string.h
+pack.$(OBJEXT): $(top_srcdir)/internal/struct.h
pack.$(OBJEXT): $(top_srcdir)/internal/symbol.h
pack.$(OBJEXT): $(top_srcdir)/internal/variable.h
pack.$(OBJEXT): $(top_srcdir)/internal/vm.h
@@ -10355,6 +10666,7 @@ pack.$(OBJEXT): {$(VPATH)}builtin.h
pack.$(OBJEXT): {$(VPATH)}config.h
pack.$(OBJEXT): {$(VPATH)}constant.h
pack.$(OBJEXT): {$(VPATH)}defines.h
+pack.$(OBJEXT): {$(VPATH)}encindex.h
pack.$(OBJEXT): {$(VPATH)}encoding.h
pack.$(OBJEXT): {$(VPATH)}id.h
pack.$(OBJEXT): {$(VPATH)}id_table.h
@@ -10539,6 +10851,8 @@ 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/box.h
+parse.$(OBJEXT): $(top_srcdir)/internal/compar.h
parse.$(OBJEXT): $(top_srcdir)/internal/compile.h
parse.$(OBJEXT): $(top_srcdir)/internal/compilers.h
parse.$(OBJEXT): $(top_srcdir)/internal/complex.h
@@ -10549,7 +10863,6 @@ parse.$(OBJEXT): $(top_srcdir)/internal/gc.h
parse.$(OBJEXT): $(top_srcdir)/internal/hash.h
parse.$(OBJEXT): $(top_srcdir)/internal/imemo.h
parse.$(OBJEXT): $(top_srcdir)/internal/io.h
-parse.$(OBJEXT): $(top_srcdir)/internal/namespace.h
parse.$(OBJEXT): $(top_srcdir)/internal/numeric.h
parse.$(OBJEXT): $(top_srcdir)/internal/parse.h
parse.$(OBJEXT): $(top_srcdir)/internal/rational.h
@@ -10560,6 +10873,7 @@ parse.$(OBJEXT): $(top_srcdir)/internal/serial.h
parse.$(OBJEXT): $(top_srcdir)/internal/set_table.h
parse.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
parse.$(OBJEXT): $(top_srcdir)/internal/string.h
+parse.$(OBJEXT): $(top_srcdir)/internal/struct.h
parse.$(OBJEXT): $(top_srcdir)/internal/symbol.h
parse.$(OBJEXT): $(top_srcdir)/internal/thread.h
parse.$(OBJEXT): $(top_srcdir)/internal/variable.h
@@ -10580,6 +10894,7 @@ parse.$(OBJEXT): {$(VPATH)}config.h
parse.$(OBJEXT): {$(VPATH)}constant.h
parse.$(OBJEXT): {$(VPATH)}defines.h
parse.$(OBJEXT): {$(VPATH)}defs/keywords
+parse.$(OBJEXT): {$(VPATH)}encindex.h
parse.$(OBJEXT): {$(VPATH)}encoding.h
parse.$(OBJEXT): {$(VPATH)}id.h
parse.$(OBJEXT): {$(VPATH)}id_table.h
@@ -10648,6 +10963,7 @@ parse.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
parse.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
parse.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
parse.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
+parse.$(OBJEXT): {$(VPATH)}internal/core/rmatch.h
parse.$(OBJEXT): {$(VPATH)}internal/core/robject.h
parse.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
parse.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
@@ -10750,6 +11066,7 @@ parse.$(OBJEXT): {$(VPATH)}parser_st.h
parse.$(OBJEXT): {$(VPATH)}probes.dmyh
parse.$(OBJEXT): {$(VPATH)}probes.h
parse.$(OBJEXT): {$(VPATH)}ractor.h
+parse.$(OBJEXT): {$(VPATH)}re.h
parse.$(OBJEXT): {$(VPATH)}regenc.h
parse.$(OBJEXT): {$(VPATH)}regex.h
parse.$(OBJEXT): {$(VPATH)}ruby_assert.h
@@ -10830,6 +11147,11 @@ parser_st.$(OBJEXT): {$(VPATH)}st.c
pathname.$(OBJEXT): $(hdrdir)/ruby.h
pathname.$(OBJEXT): $(hdrdir)/ruby/ruby.h
pathname.$(OBJEXT): $(top_srcdir)/internal/compilers.h
+pathname.$(OBJEXT): $(top_srcdir)/internal/file.h
+pathname.$(OBJEXT): $(top_srcdir)/internal/serial.h
+pathname.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
+pathname.$(OBJEXT): $(top_srcdir)/internal/string.h
+pathname.$(OBJEXT): $(top_srcdir)/internal/vm.h
pathname.$(OBJEXT): $(top_srcdir)/internal/warnings.h
pathname.$(OBJEXT): {$(VPATH)}assert.h
pathname.$(OBJEXT): {$(VPATH)}backward.h
@@ -10845,8 +11167,10 @@ pathname.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
pathname.$(OBJEXT): {$(VPATH)}builtin.h
pathname.$(OBJEXT): {$(VPATH)}config.h
pathname.$(OBJEXT): {$(VPATH)}defines.h
+pathname.$(OBJEXT): {$(VPATH)}encindex.h
pathname.$(OBJEXT): {$(VPATH)}encoding.h
pathname.$(OBJEXT): {$(VPATH)}intern.h
+pathname.$(OBJEXT): {$(VPATH)}internal.h
pathname.$(OBJEXT): {$(VPATH)}internal/abi.h
pathname.$(OBJEXT): {$(VPATH)}internal/anyargs.h
pathname.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
@@ -11007,30 +11331,48 @@ pathname.$(OBJEXT): {$(VPATH)}st.h
pathname.$(OBJEXT): {$(VPATH)}subst.h
prism/api_node.$(OBJEXT): $(hdrdir)/ruby.h
prism/api_node.$(OBJEXT): $(hdrdir)/ruby/ruby.h
+prism/api_node.$(OBJEXT): $(hdrdir)/ruby/version.h
prism/api_node.$(OBJEXT): $(top_srcdir)/prism/api_node.c
+prism/api_node.$(OBJEXT): $(top_srcdir)/prism/arena.h
prism/api_node.$(OBJEXT): $(top_srcdir)/prism/ast.h
-prism/api_node.$(OBJEXT): $(top_srcdir)/prism/defines.h
+prism/api_node.$(OBJEXT): $(top_srcdir)/prism/buffer.h
+prism/api_node.$(OBJEXT): $(top_srcdir)/prism/comments.h
+prism/api_node.$(OBJEXT): $(top_srcdir)/prism/compiler/align.h
+prism/api_node.$(OBJEXT): $(top_srcdir)/prism/compiler/exported.h
+prism/api_node.$(OBJEXT): $(top_srcdir)/prism/compiler/filesystem.h
+prism/api_node.$(OBJEXT): $(top_srcdir)/prism/compiler/flex_array.h
+prism/api_node.$(OBJEXT): $(top_srcdir)/prism/compiler/force_inline.h
+prism/api_node.$(OBJEXT): $(top_srcdir)/prism/compiler/inline.h
+prism/api_node.$(OBJEXT): $(top_srcdir)/prism/compiler/nodiscard.h
+prism/api_node.$(OBJEXT): $(top_srcdir)/prism/compiler/nonnull.h
+prism/api_node.$(OBJEXT): $(top_srcdir)/prism/constant_pool.h
prism/api_node.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h
-prism/api_node.$(OBJEXT): $(top_srcdir)/prism/encoding.h
+prism/api_node.$(OBJEXT): $(top_srcdir)/prism/excludes.h
prism/api_node.$(OBJEXT): $(top_srcdir)/prism/extension.h
+prism/api_node.$(OBJEXT): $(top_srcdir)/prism/integer.h
+prism/api_node.$(OBJEXT): $(top_srcdir)/prism/internal/allocator.h
+prism/api_node.$(OBJEXT): $(top_srcdir)/prism/internal/arena.h
+prism/api_node.$(OBJEXT): $(top_srcdir)/prism/internal/char.h
+prism/api_node.$(OBJEXT): $(top_srcdir)/prism/internal/encoding.h
+prism/api_node.$(OBJEXT): $(top_srcdir)/prism/internal/list.h
+prism/api_node.$(OBJEXT): $(top_srcdir)/prism/internal/memchr.h
+prism/api_node.$(OBJEXT): $(top_srcdir)/prism/internal/regexp.h
+prism/api_node.$(OBJEXT): $(top_srcdir)/prism/internal/static_literals.h
+prism/api_node.$(OBJEXT): $(top_srcdir)/prism/internal/strncasecmp.h
+prism/api_node.$(OBJEXT): $(top_srcdir)/prism/internal/strpbrk.h
+prism/api_node.$(OBJEXT): $(top_srcdir)/prism/json.h
+prism/api_node.$(OBJEXT): $(top_srcdir)/prism/line_offset_list.h
+prism/api_node.$(OBJEXT): $(top_srcdir)/prism/magic_comments.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): $(top_srcdir)/prism/serialize.h
+prism/api_node.$(OBJEXT): $(top_srcdir)/prism/source.h
+prism/api_node.$(OBJEXT): $(top_srcdir)/prism/stream.h
+prism/api_node.$(OBJEXT): $(top_srcdir)/prism/string_query.h
+prism/api_node.$(OBJEXT): $(top_srcdir)/prism/stringy.h
prism/api_node.$(OBJEXT): $(top_srcdir)/prism/version.h
prism/api_node.$(OBJEXT): {$(VPATH)}assert.h
prism/api_node.$(OBJEXT): {$(VPATH)}backward/2/assume.h
@@ -11198,244 +11540,262 @@ 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_xallocator.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/ast.h
-prism/api_pack.$(OBJEXT): $(top_srcdir)/prism/defines.h
-prism/api_pack.$(OBJEXT): $(top_srcdir)/prism/diagnostic.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): $(top_srcdir)/prism/version.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/set.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)}st.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}subst.h
+prism/arena.$(OBJEXT): $(top_srcdir)/prism/arena.c
+prism/arena.$(OBJEXT): $(top_srcdir)/prism/arena.h
+prism/arena.$(OBJEXT): $(top_srcdir)/prism/compiler/exported.h
+prism/arena.$(OBJEXT): $(top_srcdir)/prism/compiler/flex_array.h
+prism/arena.$(OBJEXT): $(top_srcdir)/prism/compiler/force_inline.h
+prism/arena.$(OBJEXT): $(top_srcdir)/prism/compiler/inline.h
+prism/arena.$(OBJEXT): $(top_srcdir)/prism/compiler/nodiscard.h
+prism/arena.$(OBJEXT): $(top_srcdir)/prism/compiler/nonnull.h
+prism/arena.$(OBJEXT): $(top_srcdir)/prism/internal/allocator.h
+prism/arena.$(OBJEXT): $(top_srcdir)/prism/internal/arena.h
+prism/arena.$(OBJEXT): {$(VPATH)}config.h
+prism/arena.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
+prism/arena.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
+prism/arena.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
+prism/arena.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
+prism/arena.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
+prism/arena.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+prism/arena.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+prism/arena.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+prism/arena.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+prism/arena.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+prism/arena.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+prism/arena.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+prism/arena.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+prism/arena.$(OBJEXT): {$(VPATH)}internal/config.h
+prism/arena.$(OBJEXT): {$(VPATH)}internal/dllexport.h
+prism/arena.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
+prism/arena.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
+prism/arena.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
+prism/arena.$(OBJEXT): {$(VPATH)}internal/has/extension.h
+prism/arena.$(OBJEXT): {$(VPATH)}internal/has/feature.h
+prism/arena.$(OBJEXT): {$(VPATH)}internal/has/warning.h
+prism/arena.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
+prism/arena.$(OBJEXT): {$(VPATH)}prism_xallocator.h
+prism/buffer.$(OBJEXT): $(top_srcdir)/prism/arena.h
+prism/buffer.$(OBJEXT): $(top_srcdir)/prism/buffer.c
+prism/buffer.$(OBJEXT): $(top_srcdir)/prism/buffer.h
+prism/buffer.$(OBJEXT): $(top_srcdir)/prism/compiler/exported.h
+prism/buffer.$(OBJEXT): $(top_srcdir)/prism/compiler/force_inline.h
+prism/buffer.$(OBJEXT): $(top_srcdir)/prism/compiler/format.h
+prism/buffer.$(OBJEXT): $(top_srcdir)/prism/compiler/inline.h
+prism/buffer.$(OBJEXT): $(top_srcdir)/prism/compiler/nodiscard.h
+prism/buffer.$(OBJEXT): $(top_srcdir)/prism/compiler/nonnull.h
+prism/buffer.$(OBJEXT): $(top_srcdir)/prism/internal/allocator.h
+prism/buffer.$(OBJEXT): $(top_srcdir)/prism/internal/buffer.h
+prism/buffer.$(OBJEXT): $(top_srcdir)/prism/internal/char.h
+prism/buffer.$(OBJEXT): $(top_srcdir)/prism/line_offset_list.h
+prism/buffer.$(OBJEXT): {$(VPATH)}config.h
+prism/buffer.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
+prism/buffer.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
+prism/buffer.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
+prism/buffer.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
+prism/buffer.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
+prism/buffer.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+prism/buffer.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+prism/buffer.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+prism/buffer.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+prism/buffer.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+prism/buffer.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+prism/buffer.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+prism/buffer.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+prism/buffer.$(OBJEXT): {$(VPATH)}internal/config.h
+prism/buffer.$(OBJEXT): {$(VPATH)}internal/dllexport.h
+prism/buffer.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
+prism/buffer.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
+prism/buffer.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
+prism/buffer.$(OBJEXT): {$(VPATH)}internal/has/extension.h
+prism/buffer.$(OBJEXT): {$(VPATH)}internal/has/feature.h
+prism/buffer.$(OBJEXT): {$(VPATH)}internal/has/warning.h
+prism/buffer.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
+prism/buffer.$(OBJEXT): {$(VPATH)}prism_xallocator.h
+prism/char.$(OBJEXT): $(top_srcdir)/prism/arena.h
+prism/char.$(OBJEXT): $(top_srcdir)/prism/char.c
+prism/char.$(OBJEXT): $(top_srcdir)/prism/compiler/exported.h
+prism/char.$(OBJEXT): $(top_srcdir)/prism/compiler/force_inline.h
+prism/char.$(OBJEXT): $(top_srcdir)/prism/compiler/inline.h
+prism/char.$(OBJEXT): $(top_srcdir)/prism/compiler/nodiscard.h
+prism/char.$(OBJEXT): $(top_srcdir)/prism/compiler/nonnull.h
+prism/char.$(OBJEXT): $(top_srcdir)/prism/internal/char.h
+prism/char.$(OBJEXT): $(top_srcdir)/prism/internal/line_offset_list.h
+prism/char.$(OBJEXT): $(top_srcdir)/prism/line_offset_list.h
+prism/char.$(OBJEXT): {$(VPATH)}config.h
+prism/char.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
+prism/char.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
+prism/char.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
+prism/char.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
+prism/char.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
+prism/char.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+prism/char.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+prism/char.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+prism/char.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+prism/char.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+prism/char.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+prism/char.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+prism/char.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+prism/char.$(OBJEXT): {$(VPATH)}internal/config.h
+prism/char.$(OBJEXT): {$(VPATH)}internal/dllexport.h
+prism/char.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
+prism/char.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
+prism/char.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
+prism/char.$(OBJEXT): {$(VPATH)}internal/has/extension.h
+prism/char.$(OBJEXT): {$(VPATH)}internal/has/feature.h
+prism/char.$(OBJEXT): {$(VPATH)}internal/has/warning.h
+prism/char.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
+prism/char.$(OBJEXT): {$(VPATH)}prism_xallocator.h
+prism/constant_pool.$(OBJEXT): $(top_srcdir)/prism/arena.h
+prism/constant_pool.$(OBJEXT): $(top_srcdir)/prism/compiler/align.h
+prism/constant_pool.$(OBJEXT): $(top_srcdir)/prism/compiler/exported.h
+prism/constant_pool.$(OBJEXT): $(top_srcdir)/prism/compiler/flex_array.h
+prism/constant_pool.$(OBJEXT): $(top_srcdir)/prism/compiler/force_inline.h
+prism/constant_pool.$(OBJEXT): $(top_srcdir)/prism/compiler/inline.h
+prism/constant_pool.$(OBJEXT): $(top_srcdir)/prism/compiler/nodiscard.h
+prism/constant_pool.$(OBJEXT): $(top_srcdir)/prism/compiler/nonnull.h
+prism/constant_pool.$(OBJEXT): $(top_srcdir)/prism/constant_pool.c
+prism/constant_pool.$(OBJEXT): $(top_srcdir)/prism/constant_pool.h
+prism/constant_pool.$(OBJEXT): $(top_srcdir)/prism/internal/arena.h
+prism/constant_pool.$(OBJEXT): $(top_srcdir)/prism/internal/constant_pool.h
+prism/constant_pool.$(OBJEXT): {$(VPATH)}config.h
+prism/constant_pool.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
+prism/constant_pool.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
+prism/constant_pool.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
+prism/constant_pool.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
+prism/constant_pool.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
+prism/constant_pool.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+prism/constant_pool.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+prism/constant_pool.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+prism/constant_pool.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+prism/constant_pool.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+prism/constant_pool.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+prism/constant_pool.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+prism/constant_pool.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+prism/constant_pool.$(OBJEXT): {$(VPATH)}internal/config.h
+prism/constant_pool.$(OBJEXT): {$(VPATH)}internal/dllexport.h
+prism/constant_pool.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
+prism/constant_pool.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
+prism/constant_pool.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
+prism/constant_pool.$(OBJEXT): {$(VPATH)}internal/has/extension.h
+prism/constant_pool.$(OBJEXT): {$(VPATH)}internal/has/feature.h
+prism/constant_pool.$(OBJEXT): {$(VPATH)}internal/has/warning.h
+prism/constant_pool.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
+prism/constant_pool.$(OBJEXT): {$(VPATH)}prism_xallocator.h
+prism/diagnostic.$(OBJEXT): $(top_srcdir)/prism/arena.h
prism/diagnostic.$(OBJEXT): $(top_srcdir)/prism/ast.h
-prism/diagnostic.$(OBJEXT): $(top_srcdir)/prism/defines.h
+prism/diagnostic.$(OBJEXT): $(top_srcdir)/prism/buffer.h
+prism/diagnostic.$(OBJEXT): $(top_srcdir)/prism/compiler/align.h
+prism/diagnostic.$(OBJEXT): $(top_srcdir)/prism/compiler/exported.h
+prism/diagnostic.$(OBJEXT): $(top_srcdir)/prism/compiler/flex_array.h
+prism/diagnostic.$(OBJEXT): $(top_srcdir)/prism/compiler/force_inline.h
+prism/diagnostic.$(OBJEXT): $(top_srcdir)/prism/compiler/inline.h
+prism/diagnostic.$(OBJEXT): $(top_srcdir)/prism/compiler/nodiscard.h
+prism/diagnostic.$(OBJEXT): $(top_srcdir)/prism/compiler/nonnull.h
+prism/diagnostic.$(OBJEXT): $(top_srcdir)/prism/constant_pool.h
prism/diagnostic.$(OBJEXT): $(top_srcdir)/prism/diagnostic.c
prism/diagnostic.$(OBJEXT): $(top_srcdir)/prism/diagnostic.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/encoding.$(OBJEXT): $(top_srcdir)/prism/defines.h
+prism/diagnostic.$(OBJEXT): $(top_srcdir)/prism/integer.h
+prism/diagnostic.$(OBJEXT): $(top_srcdir)/prism/internal/allocator.h
+prism/diagnostic.$(OBJEXT): $(top_srcdir)/prism/internal/arena.h
+prism/diagnostic.$(OBJEXT): $(top_srcdir)/prism/internal/char.h
+prism/diagnostic.$(OBJEXT): $(top_srcdir)/prism/internal/diagnostic.h
+prism/diagnostic.$(OBJEXT): $(top_srcdir)/prism/internal/list.h
+prism/diagnostic.$(OBJEXT): $(top_srcdir)/prism/line_offset_list.h
+prism/diagnostic.$(OBJEXT): $(top_srcdir)/prism/stringy.h
+prism/diagnostic.$(OBJEXT): {$(VPATH)}config.h
+prism/diagnostic.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
+prism/diagnostic.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
+prism/diagnostic.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
+prism/diagnostic.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
+prism/diagnostic.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
+prism/diagnostic.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+prism/diagnostic.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+prism/diagnostic.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+prism/diagnostic.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+prism/diagnostic.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+prism/diagnostic.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+prism/diagnostic.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+prism/diagnostic.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+prism/diagnostic.$(OBJEXT): {$(VPATH)}internal/config.h
+prism/diagnostic.$(OBJEXT): {$(VPATH)}internal/dllexport.h
+prism/diagnostic.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
+prism/diagnostic.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
+prism/diagnostic.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
+prism/diagnostic.$(OBJEXT): {$(VPATH)}internal/has/extension.h
+prism/diagnostic.$(OBJEXT): {$(VPATH)}internal/has/feature.h
+prism/diagnostic.$(OBJEXT): {$(VPATH)}internal/has/warning.h
+prism/diagnostic.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
+prism/diagnostic.$(OBJEXT): {$(VPATH)}prism_xallocator.h
+prism/encoding.$(OBJEXT): $(top_srcdir)/prism/compiler/unused.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/encoding.$(OBJEXT): $(top_srcdir)/prism/internal/encoding.h
+prism/encoding.$(OBJEXT): $(top_srcdir)/prism/internal/strncasecmp.h
+prism/encoding.$(OBJEXT): {$(VPATH)}config.h
+prism/encoding.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
+prism/encoding.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
+prism/encoding.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
+prism/encoding.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
+prism/encoding.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
+prism/encoding.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+prism/encoding.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+prism/encoding.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+prism/encoding.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+prism/encoding.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+prism/encoding.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+prism/encoding.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+prism/encoding.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+prism/encoding.$(OBJEXT): {$(VPATH)}internal/config.h
+prism/encoding.$(OBJEXT): {$(VPATH)}internal/dllexport.h
+prism/encoding.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
+prism/encoding.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
+prism/encoding.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
+prism/encoding.$(OBJEXT): {$(VPATH)}internal/has/extension.h
+prism/encoding.$(OBJEXT): {$(VPATH)}internal/has/feature.h
+prism/encoding.$(OBJEXT): {$(VPATH)}internal/has/warning.h
+prism/encoding.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
+prism/encoding.$(OBJEXT): {$(VPATH)}prism_xallocator.h
prism/extension.$(OBJEXT): $(hdrdir)/ruby.h
prism/extension.$(OBJEXT): $(hdrdir)/ruby/ruby.h
+prism/extension.$(OBJEXT): $(hdrdir)/ruby/version.h
+prism/extension.$(OBJEXT): $(top_srcdir)/prism/arena.h
prism/extension.$(OBJEXT): $(top_srcdir)/prism/ast.h
-prism/extension.$(OBJEXT): $(top_srcdir)/prism/defines.h
+prism/extension.$(OBJEXT): $(top_srcdir)/prism/buffer.h
+prism/extension.$(OBJEXT): $(top_srcdir)/prism/comments.h
+prism/extension.$(OBJEXT): $(top_srcdir)/prism/compiler/align.h
+prism/extension.$(OBJEXT): $(top_srcdir)/prism/compiler/exported.h
+prism/extension.$(OBJEXT): $(top_srcdir)/prism/compiler/filesystem.h
+prism/extension.$(OBJEXT): $(top_srcdir)/prism/compiler/nodiscard.h
+prism/extension.$(OBJEXT): $(top_srcdir)/prism/compiler/nonnull.h
+prism/extension.$(OBJEXT): $(top_srcdir)/prism/constant_pool.h
prism/extension.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h
-prism/extension.$(OBJEXT): $(top_srcdir)/prism/encoding.h
+prism/extension.$(OBJEXT): $(top_srcdir)/prism/excludes.h
prism/extension.$(OBJEXT): $(top_srcdir)/prism/extension.c
prism/extension.$(OBJEXT): $(top_srcdir)/prism/extension.h
+prism/extension.$(OBJEXT): $(top_srcdir)/prism/integer.h
+prism/extension.$(OBJEXT): $(top_srcdir)/prism/internal/char.h
+prism/extension.$(OBJEXT): $(top_srcdir)/prism/internal/encoding.h
+prism/extension.$(OBJEXT): $(top_srcdir)/prism/internal/list.h
+prism/extension.$(OBJEXT): $(top_srcdir)/prism/internal/memchr.h
+prism/extension.$(OBJEXT): $(top_srcdir)/prism/internal/regexp.h
+prism/extension.$(OBJEXT): $(top_srcdir)/prism/internal/static_literals.h
+prism/extension.$(OBJEXT): $(top_srcdir)/prism/internal/strncasecmp.h
+prism/extension.$(OBJEXT): $(top_srcdir)/prism/internal/strpbrk.h
+prism/extension.$(OBJEXT): $(top_srcdir)/prism/json.h
+prism/extension.$(OBJEXT): $(top_srcdir)/prism/line_offset_list.h
+prism/extension.$(OBJEXT): $(top_srcdir)/prism/magic_comments.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): $(top_srcdir)/prism/serialize.h
+prism/extension.$(OBJEXT): $(top_srcdir)/prism/source.h
+prism/extension.$(OBJEXT): $(top_srcdir)/prism/stream.h
+prism/extension.$(OBJEXT): $(top_srcdir)/prism/string_query.h
+prism/extension.$(OBJEXT): $(top_srcdir)/prism/stringy.h
prism/extension.$(OBJEXT): $(top_srcdir)/prism/version.h
prism/extension.$(OBJEXT): {$(VPATH)}assert.h
prism/extension.$(OBJEXT): {$(VPATH)}backward/2/assume.h
@@ -11603,227 +11963,890 @@ 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_xallocator.h
prism/extension.$(OBJEXT): {$(VPATH)}st.h
prism/extension.$(OBJEXT): {$(VPATH)}subst.h
+prism/integer.$(OBJEXT): $(top_srcdir)/prism/arena.h
+prism/integer.$(OBJEXT): $(top_srcdir)/prism/buffer.h
+prism/integer.$(OBJEXT): $(top_srcdir)/prism/compiler/exported.h
+prism/integer.$(OBJEXT): $(top_srcdir)/prism/compiler/format.h
+prism/integer.$(OBJEXT): $(top_srcdir)/prism/compiler/nodiscard.h
+prism/integer.$(OBJEXT): $(top_srcdir)/prism/compiler/nonnull.h
+prism/integer.$(OBJEXT): $(top_srcdir)/prism/integer.c
+prism/integer.$(OBJEXT): $(top_srcdir)/prism/integer.h
+prism/integer.$(OBJEXT): $(top_srcdir)/prism/internal/allocator.h
+prism/integer.$(OBJEXT): $(top_srcdir)/prism/internal/buffer.h
+prism/integer.$(OBJEXT): $(top_srcdir)/prism/internal/char.h
+prism/integer.$(OBJEXT): $(top_srcdir)/prism/internal/integer.h
+prism/integer.$(OBJEXT): $(top_srcdir)/prism/line_offset_list.h
+prism/integer.$(OBJEXT): {$(VPATH)}config.h
+prism/integer.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
+prism/integer.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
+prism/integer.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
+prism/integer.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
+prism/integer.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
+prism/integer.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+prism/integer.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+prism/integer.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+prism/integer.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+prism/integer.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+prism/integer.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+prism/integer.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+prism/integer.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+prism/integer.$(OBJEXT): {$(VPATH)}internal/config.h
+prism/integer.$(OBJEXT): {$(VPATH)}internal/dllexport.h
+prism/integer.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
+prism/integer.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
+prism/integer.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
+prism/integer.$(OBJEXT): {$(VPATH)}internal/has/extension.h
+prism/integer.$(OBJEXT): {$(VPATH)}internal/has/feature.h
+prism/integer.$(OBJEXT): {$(VPATH)}internal/has/warning.h
+prism/integer.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
+prism/integer.$(OBJEXT): {$(VPATH)}prism_xallocator.h
+prism/json.$(OBJEXT): $(top_srcdir)/prism/arena.h
+prism/json.$(OBJEXT): $(top_srcdir)/prism/ast.h
+prism/json.$(OBJEXT): $(top_srcdir)/prism/buffer.h
+prism/json.$(OBJEXT): $(top_srcdir)/prism/comments.h
+prism/json.$(OBJEXT): $(top_srcdir)/prism/compiler/accel.h
+prism/json.$(OBJEXT): $(top_srcdir)/prism/compiler/align.h
+prism/json.$(OBJEXT): $(top_srcdir)/prism/compiler/exported.h
+prism/json.$(OBJEXT): $(top_srcdir)/prism/compiler/flex_array.h
+prism/json.$(OBJEXT): $(top_srcdir)/prism/compiler/force_inline.h
+prism/json.$(OBJEXT): $(top_srcdir)/prism/compiler/format.h
+prism/json.$(OBJEXT): $(top_srcdir)/prism/compiler/inline.h
+prism/json.$(OBJEXT): $(top_srcdir)/prism/compiler/nodiscard.h
+prism/json.$(OBJEXT): $(top_srcdir)/prism/compiler/nonnull.h
+prism/json.$(OBJEXT): $(top_srcdir)/prism/constant_pool.h
+prism/json.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h
+prism/json.$(OBJEXT): $(top_srcdir)/prism/excludes.h
+prism/json.$(OBJEXT): $(top_srcdir)/prism/integer.h
+prism/json.$(OBJEXT): $(top_srcdir)/prism/internal/arena.h
+prism/json.$(OBJEXT): $(top_srcdir)/prism/internal/buffer.h
+prism/json.$(OBJEXT): $(top_srcdir)/prism/internal/constant_pool.h
+prism/json.$(OBJEXT): $(top_srcdir)/prism/internal/encoding.h
+prism/json.$(OBJEXT): $(top_srcdir)/prism/internal/integer.h
+prism/json.$(OBJEXT): $(top_srcdir)/prism/internal/list.h
+prism/json.$(OBJEXT): $(top_srcdir)/prism/internal/options.h
+prism/json.$(OBJEXT): $(top_srcdir)/prism/internal/parser.h
+prism/json.$(OBJEXT): $(top_srcdir)/prism/internal/static_literals.h
+prism/json.$(OBJEXT): $(top_srcdir)/prism/internal/strpbrk.h
+prism/json.$(OBJEXT): $(top_srcdir)/prism/json.c
+prism/json.$(OBJEXT): $(top_srcdir)/prism/json.h
+prism/json.$(OBJEXT): $(top_srcdir)/prism/line_offset_list.h
+prism/json.$(OBJEXT): $(top_srcdir)/prism/magic_comments.h
+prism/json.$(OBJEXT): $(top_srcdir)/prism/options.h
+prism/json.$(OBJEXT): $(top_srcdir)/prism/parser.h
+prism/json.$(OBJEXT): $(top_srcdir)/prism/stringy.h
+prism/line_offset_list.$(OBJEXT): $(top_srcdir)/prism/arena.h
+prism/line_offset_list.$(OBJEXT): $(top_srcdir)/prism/compiler/align.h
+prism/line_offset_list.$(OBJEXT): $(top_srcdir)/prism/compiler/exported.h
+prism/line_offset_list.$(OBJEXT): $(top_srcdir)/prism/compiler/flex_array.h
+prism/line_offset_list.$(OBJEXT): $(top_srcdir)/prism/compiler/force_inline.h
+prism/line_offset_list.$(OBJEXT): $(top_srcdir)/prism/compiler/inline.h
+prism/line_offset_list.$(OBJEXT): $(top_srcdir)/prism/compiler/nodiscard.h
+prism/line_offset_list.$(OBJEXT): $(top_srcdir)/prism/compiler/nonnull.h
+prism/line_offset_list.$(OBJEXT): $(top_srcdir)/prism/internal/arena.h
+prism/line_offset_list.$(OBJEXT): $(top_srcdir)/prism/internal/line_offset_list.h
+prism/line_offset_list.$(OBJEXT): $(top_srcdir)/prism/line_offset_list.c
+prism/line_offset_list.$(OBJEXT): $(top_srcdir)/prism/line_offset_list.h
+prism/line_offset_list.$(OBJEXT): {$(VPATH)}config.h
+prism/line_offset_list.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
+prism/line_offset_list.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
+prism/line_offset_list.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
+prism/line_offset_list.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
+prism/line_offset_list.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
+prism/line_offset_list.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+prism/line_offset_list.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+prism/line_offset_list.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+prism/line_offset_list.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+prism/line_offset_list.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+prism/line_offset_list.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+prism/line_offset_list.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+prism/line_offset_list.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+prism/line_offset_list.$(OBJEXT): {$(VPATH)}internal/config.h
+prism/line_offset_list.$(OBJEXT): {$(VPATH)}internal/dllexport.h
+prism/line_offset_list.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
+prism/line_offset_list.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
+prism/line_offset_list.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
+prism/line_offset_list.$(OBJEXT): {$(VPATH)}internal/has/extension.h
+prism/line_offset_list.$(OBJEXT): {$(VPATH)}internal/has/feature.h
+prism/line_offset_list.$(OBJEXT): {$(VPATH)}internal/has/warning.h
+prism/line_offset_list.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
+prism/line_offset_list.$(OBJEXT): {$(VPATH)}prism_xallocator.h
+prism/list.$(OBJEXT): $(top_srcdir)/prism/internal/list.h
+prism/list.$(OBJEXT): $(top_srcdir)/prism/list.c
+prism/list.$(OBJEXT): {$(VPATH)}config.h
+prism/list.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
+prism/list.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
+prism/list.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
+prism/list.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
+prism/list.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
+prism/list.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+prism/list.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+prism/list.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+prism/list.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+prism/list.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+prism/list.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+prism/list.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+prism/list.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+prism/list.$(OBJEXT): {$(VPATH)}internal/config.h
+prism/list.$(OBJEXT): {$(VPATH)}internal/dllexport.h
+prism/list.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
+prism/list.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
+prism/list.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
+prism/list.$(OBJEXT): {$(VPATH)}internal/has/extension.h
+prism/list.$(OBJEXT): {$(VPATH)}internal/has/feature.h
+prism/list.$(OBJEXT): {$(VPATH)}internal/has/warning.h
+prism/list.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
+prism/list.$(OBJEXT): {$(VPATH)}prism_xallocator.h
+prism/memchr.$(OBJEXT): $(top_srcdir)/prism/ast.h
+prism/memchr.$(OBJEXT): $(top_srcdir)/prism/constant_pool.h
+prism/memchr.$(OBJEXT): $(top_srcdir)/prism/internal/encoding.h
+prism/memchr.$(OBJEXT): $(top_srcdir)/prism/internal/list.h
+prism/memchr.$(OBJEXT): $(top_srcdir)/prism/internal/memchr.h
+prism/memchr.$(OBJEXT): $(top_srcdir)/prism/internal/strncasecmp.h
+prism/memchr.$(OBJEXT): $(top_srcdir)/prism/line_offset_list.h
+prism/memchr.$(OBJEXT): $(top_srcdir)/prism/memchr.c
+prism/memchr.$(OBJEXT): $(top_srcdir)/prism/parser.h
+prism/memchr.$(OBJEXT): $(top_srcdir)/prism/stringy.h
+prism/memchr.$(OBJEXT): {$(VPATH)}config.h
+prism/memchr.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
+prism/memchr.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
+prism/memchr.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
+prism/memchr.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
+prism/memchr.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
+prism/memchr.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+prism/memchr.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+prism/memchr.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+prism/memchr.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+prism/memchr.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+prism/memchr.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+prism/memchr.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+prism/memchr.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+prism/memchr.$(OBJEXT): {$(VPATH)}internal/config.h
+prism/memchr.$(OBJEXT): {$(VPATH)}internal/dllexport.h
+prism/memchr.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
+prism/memchr.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
+prism/memchr.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
+prism/memchr.$(OBJEXT): {$(VPATH)}internal/has/extension.h
+prism/memchr.$(OBJEXT): {$(VPATH)}internal/has/feature.h
+prism/memchr.$(OBJEXT): {$(VPATH)}internal/has/warning.h
+prism/memchr.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
+prism/memchr.$(OBJEXT): {$(VPATH)}prism_xallocator.h
+prism/node.$(OBJEXT): $(top_srcdir)/prism/arena.h
prism/node.$(OBJEXT): $(top_srcdir)/prism/ast.h
-prism/node.$(OBJEXT): $(top_srcdir)/prism/defines.h
+prism/node.$(OBJEXT): $(top_srcdir)/prism/buffer.h
+prism/node.$(OBJEXT): $(top_srcdir)/prism/compiler/align.h
+prism/node.$(OBJEXT): $(top_srcdir)/prism/compiler/exported.h
+prism/node.$(OBJEXT): $(top_srcdir)/prism/compiler/flex_array.h
+prism/node.$(OBJEXT): $(top_srcdir)/prism/compiler/force_inline.h
+prism/node.$(OBJEXT): $(top_srcdir)/prism/compiler/inline.h
+prism/node.$(OBJEXT): $(top_srcdir)/prism/compiler/nodiscard.h
+prism/node.$(OBJEXT): $(top_srcdir)/prism/compiler/nonnull.h
+prism/node.$(OBJEXT): $(top_srcdir)/prism/constant_pool.h
prism/node.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h
-prism/node.$(OBJEXT): $(top_srcdir)/prism/encoding.h
+prism/node.$(OBJEXT): $(top_srcdir)/prism/integer.h
+prism/node.$(OBJEXT): $(top_srcdir)/prism/internal/arena.h
+prism/node.$(OBJEXT): $(top_srcdir)/prism/internal/char.h
+prism/node.$(OBJEXT): $(top_srcdir)/prism/internal/encoding.h
+prism/node.$(OBJEXT): $(top_srcdir)/prism/internal/list.h
+prism/node.$(OBJEXT): $(top_srcdir)/prism/internal/node.h
+prism/node.$(OBJEXT): $(top_srcdir)/prism/internal/regexp.h
+prism/node.$(OBJEXT): $(top_srcdir)/prism/internal/static_literals.h
+prism/node.$(OBJEXT): $(top_srcdir)/prism/internal/strncasecmp.h
+prism/node.$(OBJEXT): $(top_srcdir)/prism/internal/strpbrk.h
+prism/node.$(OBJEXT): $(top_srcdir)/prism/line_offset_list.h
prism/node.$(OBJEXT): $(top_srcdir)/prism/node.c
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/options.$(OBJEXT): $(top_srcdir)/prism/defines.h
+prism/node.$(OBJEXT): $(top_srcdir)/prism/stringy.h
+prism/node.$(OBJEXT): {$(VPATH)}config.h
+prism/node.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
+prism/node.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
+prism/node.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
+prism/node.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
+prism/node.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
+prism/node.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+prism/node.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+prism/node.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+prism/node.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+prism/node.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+prism/node.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+prism/node.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+prism/node.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+prism/node.$(OBJEXT): {$(VPATH)}internal/config.h
+prism/node.$(OBJEXT): {$(VPATH)}internal/dllexport.h
+prism/node.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
+prism/node.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
+prism/node.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
+prism/node.$(OBJEXT): {$(VPATH)}internal/has/extension.h
+prism/node.$(OBJEXT): {$(VPATH)}internal/has/feature.h
+prism/node.$(OBJEXT): {$(VPATH)}internal/has/warning.h
+prism/node.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
+prism/node.$(OBJEXT): {$(VPATH)}prism_xallocator.h
+prism/options.$(OBJEXT): $(top_srcdir)/prism/arena.h
+prism/options.$(OBJEXT): $(top_srcdir)/prism/compiler/exported.h
+prism/options.$(OBJEXT): $(top_srcdir)/prism/compiler/force_inline.h
+prism/options.$(OBJEXT): $(top_srcdir)/prism/compiler/inline.h
+prism/options.$(OBJEXT): $(top_srcdir)/prism/compiler/nodiscard.h
+prism/options.$(OBJEXT): $(top_srcdir)/prism/compiler/nonnull.h
+prism/options.$(OBJEXT): $(top_srcdir)/prism/internal/allocator.h
+prism/options.$(OBJEXT): $(top_srcdir)/prism/internal/char.h
+prism/options.$(OBJEXT): $(top_srcdir)/prism/internal/options.h
+prism/options.$(OBJEXT): $(top_srcdir)/prism/internal/stringy.h
+prism/options.$(OBJEXT): $(top_srcdir)/prism/line_offset_list.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/options.$(OBJEXT): $(top_srcdir)/prism/stringy.h
+prism/options.$(OBJEXT): {$(VPATH)}config.h
+prism/options.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
+prism/options.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
+prism/options.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
+prism/options.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
+prism/options.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
+prism/options.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+prism/options.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+prism/options.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+prism/options.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+prism/options.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+prism/options.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+prism/options.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+prism/options.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+prism/options.$(OBJEXT): {$(VPATH)}internal/config.h
+prism/options.$(OBJEXT): {$(VPATH)}internal/dllexport.h
+prism/options.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
+prism/options.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
+prism/options.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
+prism/options.$(OBJEXT): {$(VPATH)}internal/has/extension.h
+prism/options.$(OBJEXT): {$(VPATH)}internal/has/feature.h
+prism/options.$(OBJEXT): {$(VPATH)}internal/has/warning.h
+prism/options.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
+prism/options.$(OBJEXT): {$(VPATH)}prism_xallocator.h
+prism/parser.$(OBJEXT): $(top_srcdir)/prism/arena.h
+prism/parser.$(OBJEXT): $(top_srcdir)/prism/ast.h
+prism/parser.$(OBJEXT): $(top_srcdir)/prism/buffer.h
+prism/parser.$(OBJEXT): $(top_srcdir)/prism/comments.h
+prism/parser.$(OBJEXT): $(top_srcdir)/prism/compiler/accel.h
+prism/parser.$(OBJEXT): $(top_srcdir)/prism/compiler/align.h
+prism/parser.$(OBJEXT): $(top_srcdir)/prism/compiler/exported.h
+prism/parser.$(OBJEXT): $(top_srcdir)/prism/compiler/flex_array.h
+prism/parser.$(OBJEXT): $(top_srcdir)/prism/compiler/force_inline.h
+prism/parser.$(OBJEXT): $(top_srcdir)/prism/compiler/inline.h
+prism/parser.$(OBJEXT): $(top_srcdir)/prism/compiler/nodiscard.h
+prism/parser.$(OBJEXT): $(top_srcdir)/prism/compiler/nonnull.h
+prism/parser.$(OBJEXT): $(top_srcdir)/prism/constant_pool.h
+prism/parser.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h
+prism/parser.$(OBJEXT): $(top_srcdir)/prism/integer.h
+prism/parser.$(OBJEXT): $(top_srcdir)/prism/internal/allocator.h
+prism/parser.$(OBJEXT): $(top_srcdir)/prism/internal/arena.h
+prism/parser.$(OBJEXT): $(top_srcdir)/prism/internal/comments.h
+prism/parser.$(OBJEXT): $(top_srcdir)/prism/internal/constant_pool.h
+prism/parser.$(OBJEXT): $(top_srcdir)/prism/internal/diagnostic.h
+prism/parser.$(OBJEXT): $(top_srcdir)/prism/internal/encoding.h
+prism/parser.$(OBJEXT): $(top_srcdir)/prism/internal/list.h
+prism/parser.$(OBJEXT): $(top_srcdir)/prism/internal/magic_comments.h
+prism/parser.$(OBJEXT): $(top_srcdir)/prism/internal/options.h
+prism/parser.$(OBJEXT): $(top_srcdir)/prism/internal/parser.h
+prism/parser.$(OBJEXT): $(top_srcdir)/prism/internal/static_literals.h
+prism/parser.$(OBJEXT): $(top_srcdir)/prism/internal/strpbrk.h
+prism/parser.$(OBJEXT): $(top_srcdir)/prism/line_offset_list.h
+prism/parser.$(OBJEXT): $(top_srcdir)/prism/magic_comments.h
+prism/parser.$(OBJEXT): $(top_srcdir)/prism/options.h
+prism/parser.$(OBJEXT): $(top_srcdir)/prism/parser.c
+prism/parser.$(OBJEXT): $(top_srcdir)/prism/parser.h
+prism/parser.$(OBJEXT): $(top_srcdir)/prism/stringy.h
+prism/parser.$(OBJEXT): {$(VPATH)}config.h
+prism/parser.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
+prism/parser.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
+prism/parser.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
+prism/parser.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
+prism/parser.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
+prism/parser.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+prism/parser.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+prism/parser.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+prism/parser.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+prism/parser.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+prism/parser.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+prism/parser.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+prism/parser.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+prism/parser.$(OBJEXT): {$(VPATH)}internal/config.h
+prism/parser.$(OBJEXT): {$(VPATH)}internal/dllexport.h
+prism/parser.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
+prism/parser.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
+prism/parser.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
+prism/parser.$(OBJEXT): {$(VPATH)}internal/has/extension.h
+prism/parser.$(OBJEXT): {$(VPATH)}internal/has/feature.h
+prism/parser.$(OBJEXT): {$(VPATH)}internal/has/warning.h
+prism/parser.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
+prism/parser.$(OBJEXT): {$(VPATH)}prism_xallocator.h
+prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/arena.h
prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/ast.h
-prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/defines.h
-prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/encoding.h
+prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/buffer.h
+prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/comments.h
+prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/compiler/accel.h
+prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/compiler/align.h
+prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/compiler/exported.h
+prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/compiler/flex_array.h
+prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/compiler/force_inline.h
+prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/compiler/format.h
+prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/compiler/inline.h
+prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/compiler/nodiscard.h
+prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/compiler/nonnull.h
+prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/constant_pool.h
+prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h
+prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/excludes.h
+prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/integer.h
+prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/internal/arena.h
+prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/internal/buffer.h
+prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/internal/char.h
+prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/internal/constant_pool.h
+prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/internal/encoding.h
+prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/internal/integer.h
+prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/internal/list.h
+prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/internal/options.h
+prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/internal/parser.h
+prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/internal/static_literals.h
+prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/internal/strncasecmp.h
+prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/internal/strpbrk.h
+prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/line_offset_list.h
+prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/magic_comments.h
prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/options.h
prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/parser.h
prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/prettyprint.c
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): $(top_srcdir)/prism/stringy.h
+prism/prettyprint.$(OBJEXT): {$(VPATH)}config.h
+prism/prettyprint.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
+prism/prettyprint.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
+prism/prettyprint.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
+prism/prettyprint.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
+prism/prettyprint.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
+prism/prettyprint.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+prism/prettyprint.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+prism/prettyprint.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+prism/prettyprint.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+prism/prettyprint.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+prism/prettyprint.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+prism/prettyprint.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+prism/prettyprint.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+prism/prettyprint.$(OBJEXT): {$(VPATH)}internal/config.h
+prism/prettyprint.$(OBJEXT): {$(VPATH)}internal/dllexport.h
+prism/prettyprint.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
+prism/prettyprint.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
+prism/prettyprint.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
+prism/prettyprint.$(OBJEXT): {$(VPATH)}internal/has/extension.h
+prism/prettyprint.$(OBJEXT): {$(VPATH)}internal/has/feature.h
+prism/prettyprint.$(OBJEXT): {$(VPATH)}internal/has/warning.h
+prism/prettyprint.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
+prism/prettyprint.$(OBJEXT): {$(VPATH)}prism_xallocator.h
+prism/prism.$(OBJEXT): $(top_srcdir)/prism/arena.h
prism/prism.$(OBJEXT): $(top_srcdir)/prism/ast.h
-prism/prism.$(OBJEXT): $(top_srcdir)/prism/defines.h
+prism/prism.$(OBJEXT): $(top_srcdir)/prism/buffer.h
+prism/prism.$(OBJEXT): $(top_srcdir)/prism/comments.h
+prism/prism.$(OBJEXT): $(top_srcdir)/prism/compiler/accel.h
+prism/prism.$(OBJEXT): $(top_srcdir)/prism/compiler/align.h
+prism/prism.$(OBJEXT): $(top_srcdir)/prism/compiler/exported.h
+prism/prism.$(OBJEXT): $(top_srcdir)/prism/compiler/fallthrough.h
+prism/prism.$(OBJEXT): $(top_srcdir)/prism/compiler/filesystem.h
+prism/prism.$(OBJEXT): $(top_srcdir)/prism/compiler/flex_array.h
+prism/prism.$(OBJEXT): $(top_srcdir)/prism/compiler/force_inline.h
+prism/prism.$(OBJEXT): $(top_srcdir)/prism/compiler/format.h
+prism/prism.$(OBJEXT): $(top_srcdir)/prism/compiler/inline.h
+prism/prism.$(OBJEXT): $(top_srcdir)/prism/compiler/nodiscard.h
+prism/prism.$(OBJEXT): $(top_srcdir)/prism/compiler/nonnull.h
+prism/prism.$(OBJEXT): $(top_srcdir)/prism/compiler/unused.h
+prism/prism.$(OBJEXT): $(top_srcdir)/prism/constant_pool.h
prism/prism.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h
-prism/prism.$(OBJEXT): $(top_srcdir)/prism/encoding.h
+prism/prism.$(OBJEXT): $(top_srcdir)/prism/excludes.h
+prism/prism.$(OBJEXT): $(top_srcdir)/prism/integer.h
+prism/prism.$(OBJEXT): $(top_srcdir)/prism/internal/allocator.h
+prism/prism.$(OBJEXT): $(top_srcdir)/prism/internal/arena.h
+prism/prism.$(OBJEXT): $(top_srcdir)/prism/internal/bit.h
+prism/prism.$(OBJEXT): $(top_srcdir)/prism/internal/buffer.h
+prism/prism.$(OBJEXT): $(top_srcdir)/prism/internal/char.h
+prism/prism.$(OBJEXT): $(top_srcdir)/prism/internal/comments.h
+prism/prism.$(OBJEXT): $(top_srcdir)/prism/internal/constant_pool.h
+prism/prism.$(OBJEXT): $(top_srcdir)/prism/internal/diagnostic.h
+prism/prism.$(OBJEXT): $(top_srcdir)/prism/internal/encoding.h
+prism/prism.$(OBJEXT): $(top_srcdir)/prism/internal/integer.h
+prism/prism.$(OBJEXT): $(top_srcdir)/prism/internal/isinf.h
+prism/prism.$(OBJEXT): $(top_srcdir)/prism/internal/line_offset_list.h
+prism/prism.$(OBJEXT): $(top_srcdir)/prism/internal/list.h
+prism/prism.$(OBJEXT): $(top_srcdir)/prism/internal/magic_comments.h
+prism/prism.$(OBJEXT): $(top_srcdir)/prism/internal/memchr.h
+prism/prism.$(OBJEXT): $(top_srcdir)/prism/internal/node.h
+prism/prism.$(OBJEXT): $(top_srcdir)/prism/internal/options.h
+prism/prism.$(OBJEXT): $(top_srcdir)/prism/internal/parser.h
+prism/prism.$(OBJEXT): $(top_srcdir)/prism/internal/regexp.h
+prism/prism.$(OBJEXT): $(top_srcdir)/prism/internal/serialize.h
+prism/prism.$(OBJEXT): $(top_srcdir)/prism/internal/source.h
+prism/prism.$(OBJEXT): $(top_srcdir)/prism/internal/static_literals.h
+prism/prism.$(OBJEXT): $(top_srcdir)/prism/internal/stringy.h
+prism/prism.$(OBJEXT): $(top_srcdir)/prism/internal/strncasecmp.h
+prism/prism.$(OBJEXT): $(top_srcdir)/prism/internal/strpbrk.h
+prism/prism.$(OBJEXT): $(top_srcdir)/prism/internal/tokens.h
+prism/prism.$(OBJEXT): $(top_srcdir)/prism/line_offset_list.h
+prism/prism.$(OBJEXT): $(top_srcdir)/prism/magic_comments.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/serialize.h
+prism/prism.$(OBJEXT): $(top_srcdir)/prism/source.h
+prism/prism.$(OBJEXT): $(top_srcdir)/prism/stream.h
+prism/prism.$(OBJEXT): $(top_srcdir)/prism/stringy.h
prism/prism.$(OBJEXT): $(top_srcdir)/prism/version.h
+prism/prism.$(OBJEXT): {$(VPATH)}config.h
+prism/prism.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
+prism/prism.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
+prism/prism.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
+prism/prism.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
+prism/prism.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
+prism/prism.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+prism/prism.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+prism/prism.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+prism/prism.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+prism/prism.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+prism/prism.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+prism/prism.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+prism/prism.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+prism/prism.$(OBJEXT): {$(VPATH)}internal/config.h
+prism/prism.$(OBJEXT): {$(VPATH)}internal/dllexport.h
+prism/prism.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
+prism/prism.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
+prism/prism.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
+prism/prism.$(OBJEXT): {$(VPATH)}internal/has/extension.h
+prism/prism.$(OBJEXT): {$(VPATH)}internal/has/feature.h
+prism/prism.$(OBJEXT): {$(VPATH)}internal/has/warning.h
+prism/prism.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
+prism/prism.$(OBJEXT): {$(VPATH)}prism_xallocator.h
+prism/regexp.$(OBJEXT): $(top_srcdir)/prism/arena.h
prism/regexp.$(OBJEXT): $(top_srcdir)/prism/ast.h
-prism/regexp.$(OBJEXT): $(top_srcdir)/prism/defines.h
-prism/regexp.$(OBJEXT): $(top_srcdir)/prism/encoding.h
+prism/regexp.$(OBJEXT): $(top_srcdir)/prism/buffer.h
+prism/regexp.$(OBJEXT): $(top_srcdir)/prism/comments.h
+prism/regexp.$(OBJEXT): $(top_srcdir)/prism/compiler/accel.h
+prism/regexp.$(OBJEXT): $(top_srcdir)/prism/compiler/align.h
+prism/regexp.$(OBJEXT): $(top_srcdir)/prism/compiler/exported.h
+prism/regexp.$(OBJEXT): $(top_srcdir)/prism/compiler/fallthrough.h
+prism/regexp.$(OBJEXT): $(top_srcdir)/prism/compiler/flex_array.h
+prism/regexp.$(OBJEXT): $(top_srcdir)/prism/compiler/force_inline.h
+prism/regexp.$(OBJEXT): $(top_srcdir)/prism/compiler/format.h
+prism/regexp.$(OBJEXT): $(top_srcdir)/prism/compiler/inline.h
+prism/regexp.$(OBJEXT): $(top_srcdir)/prism/compiler/nodiscard.h
+prism/regexp.$(OBJEXT): $(top_srcdir)/prism/compiler/nonnull.h
+prism/regexp.$(OBJEXT): $(top_srcdir)/prism/constant_pool.h
+prism/regexp.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h
+prism/regexp.$(OBJEXT): $(top_srcdir)/prism/integer.h
+prism/regexp.$(OBJEXT): $(top_srcdir)/prism/internal/arena.h
+prism/regexp.$(OBJEXT): $(top_srcdir)/prism/internal/buffer.h
+prism/regexp.$(OBJEXT): $(top_srcdir)/prism/internal/char.h
+prism/regexp.$(OBJEXT): $(top_srcdir)/prism/internal/constant_pool.h
+prism/regexp.$(OBJEXT): $(top_srcdir)/prism/internal/diagnostic.h
+prism/regexp.$(OBJEXT): $(top_srcdir)/prism/internal/encoding.h
+prism/regexp.$(OBJEXT): $(top_srcdir)/prism/internal/list.h
+prism/regexp.$(OBJEXT): $(top_srcdir)/prism/internal/memchr.h
+prism/regexp.$(OBJEXT): $(top_srcdir)/prism/internal/options.h
+prism/regexp.$(OBJEXT): $(top_srcdir)/prism/internal/parser.h
+prism/regexp.$(OBJEXT): $(top_srcdir)/prism/internal/regexp.h
+prism/regexp.$(OBJEXT): $(top_srcdir)/prism/internal/static_literals.h
+prism/regexp.$(OBJEXT): $(top_srcdir)/prism/internal/stringy.h
+prism/regexp.$(OBJEXT): $(top_srcdir)/prism/internal/strncasecmp.h
+prism/regexp.$(OBJEXT): $(top_srcdir)/prism/internal/strpbrk.h
+prism/regexp.$(OBJEXT): $(top_srcdir)/prism/line_offset_list.h
+prism/regexp.$(OBJEXT): $(top_srcdir)/prism/magic_comments.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): $(top_srcdir)/prism/stringy.h
+prism/regexp.$(OBJEXT): {$(VPATH)}config.h
+prism/regexp.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
+prism/regexp.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
+prism/regexp.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
+prism/regexp.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
+prism/regexp.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
+prism/regexp.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+prism/regexp.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+prism/regexp.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+prism/regexp.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+prism/regexp.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+prism/regexp.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+prism/regexp.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+prism/regexp.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+prism/regexp.$(OBJEXT): {$(VPATH)}internal/config.h
+prism/regexp.$(OBJEXT): {$(VPATH)}internal/dllexport.h
+prism/regexp.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
+prism/regexp.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
+prism/regexp.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
+prism/regexp.$(OBJEXT): {$(VPATH)}internal/has/extension.h
+prism/regexp.$(OBJEXT): {$(VPATH)}internal/has/feature.h
+prism/regexp.$(OBJEXT): {$(VPATH)}internal/has/warning.h
+prism/regexp.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
+prism/regexp.$(OBJEXT): {$(VPATH)}prism_xallocator.h
+prism/serialize.$(OBJEXT): $(top_srcdir)/prism/arena.h
prism/serialize.$(OBJEXT): $(top_srcdir)/prism/ast.h
-prism/serialize.$(OBJEXT): $(top_srcdir)/prism/defines.h
+prism/serialize.$(OBJEXT): $(top_srcdir)/prism/buffer.h
+prism/serialize.$(OBJEXT): $(top_srcdir)/prism/comments.h
+prism/serialize.$(OBJEXT): $(top_srcdir)/prism/compiler/accel.h
+prism/serialize.$(OBJEXT): $(top_srcdir)/prism/compiler/align.h
+prism/serialize.$(OBJEXT): $(top_srcdir)/prism/compiler/exported.h
+prism/serialize.$(OBJEXT): $(top_srcdir)/prism/compiler/filesystem.h
+prism/serialize.$(OBJEXT): $(top_srcdir)/prism/compiler/flex_array.h
+prism/serialize.$(OBJEXT): $(top_srcdir)/prism/compiler/force_inline.h
+prism/serialize.$(OBJEXT): $(top_srcdir)/prism/compiler/format.h
+prism/serialize.$(OBJEXT): $(top_srcdir)/prism/compiler/inline.h
+prism/serialize.$(OBJEXT): $(top_srcdir)/prism/compiler/nodiscard.h
+prism/serialize.$(OBJEXT): $(top_srcdir)/prism/compiler/nonnull.h
+prism/serialize.$(OBJEXT): $(top_srcdir)/prism/constant_pool.h
prism/serialize.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h
-prism/serialize.$(OBJEXT): $(top_srcdir)/prism/encoding.h
+prism/serialize.$(OBJEXT): $(top_srcdir)/prism/excludes.h
+prism/serialize.$(OBJEXT): $(top_srcdir)/prism/integer.h
+prism/serialize.$(OBJEXT): $(top_srcdir)/prism/internal/arena.h
+prism/serialize.$(OBJEXT): $(top_srcdir)/prism/internal/buffer.h
+prism/serialize.$(OBJEXT): $(top_srcdir)/prism/internal/char.h
+prism/serialize.$(OBJEXT): $(top_srcdir)/prism/internal/comments.h
+prism/serialize.$(OBJEXT): $(top_srcdir)/prism/internal/constant_pool.h
+prism/serialize.$(OBJEXT): $(top_srcdir)/prism/internal/diagnostic.h
+prism/serialize.$(OBJEXT): $(top_srcdir)/prism/internal/encoding.h
+prism/serialize.$(OBJEXT): $(top_srcdir)/prism/internal/list.h
+prism/serialize.$(OBJEXT): $(top_srcdir)/prism/internal/magic_comments.h
+prism/serialize.$(OBJEXT): $(top_srcdir)/prism/internal/memchr.h
+prism/serialize.$(OBJEXT): $(top_srcdir)/prism/internal/options.h
+prism/serialize.$(OBJEXT): $(top_srcdir)/prism/internal/parser.h
+prism/serialize.$(OBJEXT): $(top_srcdir)/prism/internal/regexp.h
+prism/serialize.$(OBJEXT): $(top_srcdir)/prism/internal/static_literals.h
+prism/serialize.$(OBJEXT): $(top_srcdir)/prism/internal/strncasecmp.h
+prism/serialize.$(OBJEXT): $(top_srcdir)/prism/internal/strpbrk.h
+prism/serialize.$(OBJEXT): $(top_srcdir)/prism/json.h
+prism/serialize.$(OBJEXT): $(top_srcdir)/prism/line_offset_list.h
+prism/serialize.$(OBJEXT): $(top_srcdir)/prism/magic_comments.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/serialize.c
-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): $(top_srcdir)/prism/serialize.h
+prism/serialize.$(OBJEXT): $(top_srcdir)/prism/source.h
+prism/serialize.$(OBJEXT): $(top_srcdir)/prism/stream.h
+prism/serialize.$(OBJEXT): $(top_srcdir)/prism/string_query.h
+prism/serialize.$(OBJEXT): $(top_srcdir)/prism/stringy.h
prism/serialize.$(OBJEXT): $(top_srcdir)/prism/version.h
+prism/serialize.$(OBJEXT): {$(VPATH)}config.h
+prism/serialize.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
+prism/serialize.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
+prism/serialize.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
+prism/serialize.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
+prism/serialize.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
+prism/serialize.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+prism/serialize.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+prism/serialize.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+prism/serialize.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+prism/serialize.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+prism/serialize.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+prism/serialize.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+prism/serialize.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+prism/serialize.$(OBJEXT): {$(VPATH)}internal/config.h
+prism/serialize.$(OBJEXT): {$(VPATH)}internal/dllexport.h
+prism/serialize.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
+prism/serialize.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
+prism/serialize.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
+prism/serialize.$(OBJEXT): {$(VPATH)}internal/has/extension.h
+prism/serialize.$(OBJEXT): {$(VPATH)}internal/has/feature.h
+prism/serialize.$(OBJEXT): {$(VPATH)}internal/has/warning.h
+prism/serialize.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
+prism/serialize.$(OBJEXT): {$(VPATH)}prism_xallocator.h
+prism/source.$(OBJEXT): $(top_srcdir)/prism/buffer.h
+prism/source.$(OBJEXT): $(top_srcdir)/prism/compiler/exported.h
+prism/source.$(OBJEXT): $(top_srcdir)/prism/compiler/filesystem.h
+prism/source.$(OBJEXT): $(top_srcdir)/prism/compiler/format.h
+prism/source.$(OBJEXT): $(top_srcdir)/prism/compiler/nodiscard.h
+prism/source.$(OBJEXT): $(top_srcdir)/prism/compiler/nonnull.h
+prism/source.$(OBJEXT): $(top_srcdir)/prism/internal/allocator.h
+prism/source.$(OBJEXT): $(top_srcdir)/prism/internal/buffer.h
+prism/source.$(OBJEXT): $(top_srcdir)/prism/internal/source.h
+prism/source.$(OBJEXT): $(top_srcdir)/prism/source.c
+prism/source.$(OBJEXT): $(top_srcdir)/prism/source.h
+prism/source.$(OBJEXT): {$(VPATH)}config.h
+prism/source.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
+prism/source.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
+prism/source.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
+prism/source.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
+prism/source.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
+prism/source.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+prism/source.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+prism/source.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+prism/source.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+prism/source.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+prism/source.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+prism/source.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+prism/source.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+prism/source.$(OBJEXT): {$(VPATH)}internal/config.h
+prism/source.$(OBJEXT): {$(VPATH)}internal/dllexport.h
+prism/source.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
+prism/source.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
+prism/source.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
+prism/source.$(OBJEXT): {$(VPATH)}internal/has/extension.h
+prism/source.$(OBJEXT): {$(VPATH)}internal/has/feature.h
+prism/source.$(OBJEXT): {$(VPATH)}internal/has/warning.h
+prism/source.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
+prism/source.$(OBJEXT): {$(VPATH)}prism_xallocator.h
+prism/static_literals.$(OBJEXT): $(top_srcdir)/prism/arena.h
prism/static_literals.$(OBJEXT): $(top_srcdir)/prism/ast.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/buffer.h
+prism/static_literals.$(OBJEXT): $(top_srcdir)/prism/compiler/align.h
+prism/static_literals.$(OBJEXT): $(top_srcdir)/prism/compiler/exported.h
+prism/static_literals.$(OBJEXT): $(top_srcdir)/prism/compiler/format.h
+prism/static_literals.$(OBJEXT): $(top_srcdir)/prism/compiler/inline.h
+prism/static_literals.$(OBJEXT): $(top_srcdir)/prism/compiler/nodiscard.h
+prism/static_literals.$(OBJEXT): $(top_srcdir)/prism/compiler/nonnull.h
+prism/static_literals.$(OBJEXT): $(top_srcdir)/prism/compiler/unused.h
+prism/static_literals.$(OBJEXT): $(top_srcdir)/prism/constant_pool.h
+prism/static_literals.$(OBJEXT): $(top_srcdir)/prism/integer.h
+prism/static_literals.$(OBJEXT): $(top_srcdir)/prism/internal/allocator.h
+prism/static_literals.$(OBJEXT): $(top_srcdir)/prism/internal/buffer.h
+prism/static_literals.$(OBJEXT): $(top_srcdir)/prism/internal/char.h
+prism/static_literals.$(OBJEXT): $(top_srcdir)/prism/internal/encoding.h
+prism/static_literals.$(OBJEXT): $(top_srcdir)/prism/internal/integer.h
+prism/static_literals.$(OBJEXT): $(top_srcdir)/prism/internal/isinf.h
+prism/static_literals.$(OBJEXT): $(top_srcdir)/prism/internal/list.h
+prism/static_literals.$(OBJEXT): $(top_srcdir)/prism/internal/static_literals.h
+prism/static_literals.$(OBJEXT): $(top_srcdir)/prism/internal/stringy.h
+prism/static_literals.$(OBJEXT): $(top_srcdir)/prism/internal/strncasecmp.h
+prism/static_literals.$(OBJEXT): $(top_srcdir)/prism/line_offset_list.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/token_type.$(OBJEXT): $(top_srcdir)/prism/ast.h
-prism/token_type.$(OBJEXT): $(top_srcdir)/prism/defines.h
-prism/token_type.$(OBJEXT): $(top_srcdir)/prism/token_type.c
-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/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/ast.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_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/ast.h
-prism/util/pm_strpbrk.$(OBJEXT): $(top_srcdir)/prism/defines.h
-prism/util/pm_strpbrk.$(OBJEXT): $(top_srcdir)/prism/diagnostic.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/static_literals.$(OBJEXT): $(top_srcdir)/prism/stringy.h
+prism/static_literals.$(OBJEXT): {$(VPATH)}config.h
+prism/static_literals.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
+prism/static_literals.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
+prism/static_literals.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
+prism/static_literals.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
+prism/static_literals.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
+prism/static_literals.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+prism/static_literals.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+prism/static_literals.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+prism/static_literals.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+prism/static_literals.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+prism/static_literals.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+prism/static_literals.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+prism/static_literals.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+prism/static_literals.$(OBJEXT): {$(VPATH)}internal/config.h
+prism/static_literals.$(OBJEXT): {$(VPATH)}internal/dllexport.h
+prism/static_literals.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
+prism/static_literals.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
+prism/static_literals.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
+prism/static_literals.$(OBJEXT): {$(VPATH)}internal/has/extension.h
+prism/static_literals.$(OBJEXT): {$(VPATH)}internal/has/feature.h
+prism/static_literals.$(OBJEXT): {$(VPATH)}internal/has/warning.h
+prism/static_literals.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
+prism/static_literals.$(OBJEXT): {$(VPATH)}prism_xallocator.h
+prism/string_query.$(OBJEXT): $(top_srcdir)/prism/arena.h
+prism/string_query.$(OBJEXT): $(top_srcdir)/prism/compiler/exported.h
+prism/string_query.$(OBJEXT): $(top_srcdir)/prism/compiler/force_inline.h
+prism/string_query.$(OBJEXT): $(top_srcdir)/prism/compiler/inline.h
+prism/string_query.$(OBJEXT): $(top_srcdir)/prism/compiler/nodiscard.h
+prism/string_query.$(OBJEXT): $(top_srcdir)/prism/compiler/nonnull.h
+prism/string_query.$(OBJEXT): $(top_srcdir)/prism/internal/char.h
+prism/string_query.$(OBJEXT): $(top_srcdir)/prism/internal/encoding.h
+prism/string_query.$(OBJEXT): $(top_srcdir)/prism/line_offset_list.h
+prism/string_query.$(OBJEXT): $(top_srcdir)/prism/string_query.c
+prism/string_query.$(OBJEXT): $(top_srcdir)/prism/string_query.h
+prism/stringy.$(OBJEXT): $(top_srcdir)/prism/compiler/exported.h
+prism/stringy.$(OBJEXT): $(top_srcdir)/prism/compiler/nonnull.h
+prism/stringy.$(OBJEXT): $(top_srcdir)/prism/internal/allocator.h
+prism/stringy.$(OBJEXT): $(top_srcdir)/prism/internal/stringy.h
+prism/stringy.$(OBJEXT): $(top_srcdir)/prism/stringy.c
+prism/stringy.$(OBJEXT): $(top_srcdir)/prism/stringy.h
+prism/stringy.$(OBJEXT): {$(VPATH)}config.h
+prism/stringy.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
+prism/stringy.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
+prism/stringy.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
+prism/stringy.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
+prism/stringy.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
+prism/stringy.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+prism/stringy.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+prism/stringy.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+prism/stringy.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+prism/stringy.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+prism/stringy.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+prism/stringy.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+prism/stringy.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+prism/stringy.$(OBJEXT): {$(VPATH)}internal/config.h
+prism/stringy.$(OBJEXT): {$(VPATH)}internal/dllexport.h
+prism/stringy.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
+prism/stringy.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
+prism/stringy.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
+prism/stringy.$(OBJEXT): {$(VPATH)}internal/has/extension.h
+prism/stringy.$(OBJEXT): {$(VPATH)}internal/has/feature.h
+prism/stringy.$(OBJEXT): {$(VPATH)}internal/has/warning.h
+prism/stringy.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
+prism/stringy.$(OBJEXT): {$(VPATH)}prism_xallocator.h
+prism/strncasecmp.$(OBJEXT): $(top_srcdir)/prism/compiler/inline.h
+prism/strncasecmp.$(OBJEXT): $(top_srcdir)/prism/internal/strncasecmp.h
+prism/strncasecmp.$(OBJEXT): $(top_srcdir)/prism/strncasecmp.c
+prism/strncasecmp.$(OBJEXT): {$(VPATH)}config.h
+prism/strncasecmp.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
+prism/strncasecmp.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
+prism/strncasecmp.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
+prism/strncasecmp.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
+prism/strncasecmp.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
+prism/strncasecmp.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+prism/strncasecmp.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+prism/strncasecmp.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+prism/strncasecmp.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+prism/strncasecmp.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+prism/strncasecmp.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+prism/strncasecmp.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+prism/strncasecmp.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+prism/strncasecmp.$(OBJEXT): {$(VPATH)}internal/config.h
+prism/strncasecmp.$(OBJEXT): {$(VPATH)}internal/dllexport.h
+prism/strncasecmp.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
+prism/strncasecmp.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
+prism/strncasecmp.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
+prism/strncasecmp.$(OBJEXT): {$(VPATH)}internal/has/extension.h
+prism/strncasecmp.$(OBJEXT): {$(VPATH)}internal/has/feature.h
+prism/strncasecmp.$(OBJEXT): {$(VPATH)}internal/has/warning.h
+prism/strncasecmp.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
+prism/strncasecmp.$(OBJEXT): {$(VPATH)}prism_xallocator.h
+prism/strpbrk.$(OBJEXT): $(top_srcdir)/prism/arena.h
+prism/strpbrk.$(OBJEXT): $(top_srcdir)/prism/ast.h
+prism/strpbrk.$(OBJEXT): $(top_srcdir)/prism/buffer.h
+prism/strpbrk.$(OBJEXT): $(top_srcdir)/prism/comments.h
+prism/strpbrk.$(OBJEXT): $(top_srcdir)/prism/compiler/accel.h
+prism/strpbrk.$(OBJEXT): $(top_srcdir)/prism/compiler/align.h
+prism/strpbrk.$(OBJEXT): $(top_srcdir)/prism/compiler/exported.h
+prism/strpbrk.$(OBJEXT): $(top_srcdir)/prism/compiler/flex_array.h
+prism/strpbrk.$(OBJEXT): $(top_srcdir)/prism/compiler/force_inline.h
+prism/strpbrk.$(OBJEXT): $(top_srcdir)/prism/compiler/inline.h
+prism/strpbrk.$(OBJEXT): $(top_srcdir)/prism/compiler/nodiscard.h
+prism/strpbrk.$(OBJEXT): $(top_srcdir)/prism/compiler/nonnull.h
+prism/strpbrk.$(OBJEXT): $(top_srcdir)/prism/compiler/unused.h
+prism/strpbrk.$(OBJEXT): $(top_srcdir)/prism/constant_pool.h
+prism/strpbrk.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h
+prism/strpbrk.$(OBJEXT): $(top_srcdir)/prism/integer.h
+prism/strpbrk.$(OBJEXT): $(top_srcdir)/prism/internal/arena.h
+prism/strpbrk.$(OBJEXT): $(top_srcdir)/prism/internal/bit.h
+prism/strpbrk.$(OBJEXT): $(top_srcdir)/prism/internal/char.h
+prism/strpbrk.$(OBJEXT): $(top_srcdir)/prism/internal/constant_pool.h
+prism/strpbrk.$(OBJEXT): $(top_srcdir)/prism/internal/diagnostic.h
+prism/strpbrk.$(OBJEXT): $(top_srcdir)/prism/internal/encoding.h
+prism/strpbrk.$(OBJEXT): $(top_srcdir)/prism/internal/list.h
+prism/strpbrk.$(OBJEXT): $(top_srcdir)/prism/internal/options.h
+prism/strpbrk.$(OBJEXT): $(top_srcdir)/prism/internal/parser.h
+prism/strpbrk.$(OBJEXT): $(top_srcdir)/prism/internal/static_literals.h
+prism/strpbrk.$(OBJEXT): $(top_srcdir)/prism/internal/strncasecmp.h
+prism/strpbrk.$(OBJEXT): $(top_srcdir)/prism/internal/strpbrk.h
+prism/strpbrk.$(OBJEXT): $(top_srcdir)/prism/line_offset_list.h
+prism/strpbrk.$(OBJEXT): $(top_srcdir)/prism/magic_comments.h
+prism/strpbrk.$(OBJEXT): $(top_srcdir)/prism/options.h
+prism/strpbrk.$(OBJEXT): $(top_srcdir)/prism/parser.h
+prism/strpbrk.$(OBJEXT): $(top_srcdir)/prism/stringy.h
+prism/strpbrk.$(OBJEXT): $(top_srcdir)/prism/strpbrk.c
+prism/strpbrk.$(OBJEXT): {$(VPATH)}config.h
+prism/strpbrk.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
+prism/strpbrk.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
+prism/strpbrk.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
+prism/strpbrk.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
+prism/strpbrk.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
+prism/strpbrk.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+prism/strpbrk.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+prism/strpbrk.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+prism/strpbrk.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+prism/strpbrk.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+prism/strpbrk.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+prism/strpbrk.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+prism/strpbrk.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+prism/strpbrk.$(OBJEXT): {$(VPATH)}internal/config.h
+prism/strpbrk.$(OBJEXT): {$(VPATH)}internal/dllexport.h
+prism/strpbrk.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
+prism/strpbrk.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
+prism/strpbrk.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
+prism/strpbrk.$(OBJEXT): {$(VPATH)}internal/has/extension.h
+prism/strpbrk.$(OBJEXT): {$(VPATH)}internal/has/feature.h
+prism/strpbrk.$(OBJEXT): {$(VPATH)}internal/has/warning.h
+prism/strpbrk.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
+prism/strpbrk.$(OBJEXT): {$(VPATH)}prism_xallocator.h
+prism/tokens.$(OBJEXT): $(top_srcdir)/prism/arena.h
+prism/tokens.$(OBJEXT): $(top_srcdir)/prism/ast.h
+prism/tokens.$(OBJEXT): $(top_srcdir)/prism/buffer.h
+prism/tokens.$(OBJEXT): $(top_srcdir)/prism/compiler/align.h
+prism/tokens.$(OBJEXT): $(top_srcdir)/prism/compiler/exported.h
+prism/tokens.$(OBJEXT): $(top_srcdir)/prism/compiler/nodiscard.h
+prism/tokens.$(OBJEXT): $(top_srcdir)/prism/compiler/nonnull.h
+prism/tokens.$(OBJEXT): $(top_srcdir)/prism/constant_pool.h
+prism/tokens.$(OBJEXT): $(top_srcdir)/prism/integer.h
+prism/tokens.$(OBJEXT): $(top_srcdir)/prism/internal/char.h
+prism/tokens.$(OBJEXT): $(top_srcdir)/prism/line_offset_list.h
+prism/tokens.$(OBJEXT): $(top_srcdir)/prism/stringy.h
+prism/tokens.$(OBJEXT): $(top_srcdir)/prism/tokens.c
+prism/tokens.$(OBJEXT): {$(VPATH)}config.h
+prism/tokens.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
+prism/tokens.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
+prism/tokens.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
+prism/tokens.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
+prism/tokens.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
+prism/tokens.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+prism/tokens.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+prism/tokens.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+prism/tokens.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+prism/tokens.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+prism/tokens.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+prism/tokens.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+prism/tokens.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+prism/tokens.$(OBJEXT): {$(VPATH)}internal/config.h
+prism/tokens.$(OBJEXT): {$(VPATH)}internal/dllexport.h
+prism/tokens.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
+prism/tokens.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
+prism/tokens.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
+prism/tokens.$(OBJEXT): {$(VPATH)}internal/has/extension.h
+prism/tokens.$(OBJEXT): {$(VPATH)}internal/has/feature.h
+prism/tokens.$(OBJEXT): {$(VPATH)}internal/has/warning.h
+prism/tokens.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
+prism/tokens.$(OBJEXT): {$(VPATH)}prism_xallocator.h
prism_init.$(OBJEXT): $(hdrdir)/ruby.h
prism_init.$(OBJEXT): $(hdrdir)/ruby/ruby.h
+prism_init.$(OBJEXT): $(hdrdir)/ruby/version.h
+prism_init.$(OBJEXT): $(top_srcdir)/prism/arena.h
prism_init.$(OBJEXT): $(top_srcdir)/prism/ast.h
-prism_init.$(OBJEXT): $(top_srcdir)/prism/defines.h
+prism_init.$(OBJEXT): $(top_srcdir)/prism/buffer.h
+prism_init.$(OBJEXT): $(top_srcdir)/prism/comments.h
+prism_init.$(OBJEXT): $(top_srcdir)/prism/compiler/align.h
+prism_init.$(OBJEXT): $(top_srcdir)/prism/compiler/exported.h
+prism_init.$(OBJEXT): $(top_srcdir)/prism/compiler/filesystem.h
+prism_init.$(OBJEXT): $(top_srcdir)/prism/compiler/nodiscard.h
+prism_init.$(OBJEXT): $(top_srcdir)/prism/compiler/nonnull.h
+prism_init.$(OBJEXT): $(top_srcdir)/prism/constant_pool.h
prism_init.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h
-prism_init.$(OBJEXT): $(top_srcdir)/prism/encoding.h
+prism_init.$(OBJEXT): $(top_srcdir)/prism/excludes.h
prism_init.$(OBJEXT): $(top_srcdir)/prism/extension.h
+prism_init.$(OBJEXT): $(top_srcdir)/prism/integer.h
+prism_init.$(OBJEXT): $(top_srcdir)/prism/internal/char.h
+prism_init.$(OBJEXT): $(top_srcdir)/prism/internal/encoding.h
+prism_init.$(OBJEXT): $(top_srcdir)/prism/internal/list.h
+prism_init.$(OBJEXT): $(top_srcdir)/prism/internal/memchr.h
+prism_init.$(OBJEXT): $(top_srcdir)/prism/internal/regexp.h
+prism_init.$(OBJEXT): $(top_srcdir)/prism/internal/static_literals.h
+prism_init.$(OBJEXT): $(top_srcdir)/prism/internal/strncasecmp.h
+prism_init.$(OBJEXT): $(top_srcdir)/prism/internal/strpbrk.h
+prism_init.$(OBJEXT): $(top_srcdir)/prism/json.h
+prism_init.$(OBJEXT): $(top_srcdir)/prism/line_offset_list.h
+prism_init.$(OBJEXT): $(top_srcdir)/prism/magic_comments.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/serialize.h
+prism_init.$(OBJEXT): $(top_srcdir)/prism/source.h
+prism_init.$(OBJEXT): $(top_srcdir)/prism/stream.h
+prism_init.$(OBJEXT): $(top_srcdir)/prism/string_query.h
+prism_init.$(OBJEXT): $(top_srcdir)/prism/stringy.h
prism_init.$(OBJEXT): $(top_srcdir)/prism/version.h
prism_init.$(OBJEXT): $(top_srcdir)/prism_init.c
prism_init.$(OBJEXT): {$(VPATH)}assert.h
@@ -11993,6 +13016,7 @@ prism_init.$(OBJEXT): {$(VPATH)}missing.h
prism_init.$(OBJEXT): {$(VPATH)}onigmo.h
prism_init.$(OBJEXT): {$(VPATH)}oniguruma.h
prism_init.$(OBJEXT): {$(VPATH)}prism_init.c
+prism_init.$(OBJEXT): {$(VPATH)}prism_xallocator.h
prism_init.$(OBJEXT): {$(VPATH)}st.h
prism_init.$(OBJEXT): {$(VPATH)}subst.h
proc.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
@@ -12003,6 +13027,7 @@ 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/box.h
proc.$(OBJEXT): $(top_srcdir)/internal/class.h
proc.$(OBJEXT): $(top_srcdir)/internal/compilers.h
proc.$(OBJEXT): $(top_srcdir)/internal/error.h
@@ -12010,7 +13035,6 @@ 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/namespace.h
proc.$(OBJEXT): $(top_srcdir)/internal/object.h
proc.$(OBJEXT): $(top_srcdir)/internal/proc.h
proc.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
@@ -12018,32 +13042,45 @@ proc.$(OBJEXT): $(top_srcdir)/internal/serial.h
proc.$(OBJEXT): $(top_srcdir)/internal/set_table.h
proc.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
proc.$(OBJEXT): $(top_srcdir)/internal/string.h
+proc.$(OBJEXT): $(top_srcdir)/internal/struct.h
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/arena.h
proc.$(OBJEXT): $(top_srcdir)/prism/ast.h
-proc.$(OBJEXT): $(top_srcdir)/prism/defines.h
+proc.$(OBJEXT): $(top_srcdir)/prism/buffer.h
+proc.$(OBJEXT): $(top_srcdir)/prism/comments.h
+proc.$(OBJEXT): $(top_srcdir)/prism/compiler/align.h
+proc.$(OBJEXT): $(top_srcdir)/prism/compiler/exported.h
+proc.$(OBJEXT): $(top_srcdir)/prism/compiler/filesystem.h
+proc.$(OBJEXT): $(top_srcdir)/prism/compiler/nodiscard.h
+proc.$(OBJEXT): $(top_srcdir)/prism/compiler/nonnull.h
+proc.$(OBJEXT): $(top_srcdir)/prism/constant_pool.h
proc.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h
-proc.$(OBJEXT): $(top_srcdir)/prism/encoding.h
+proc.$(OBJEXT): $(top_srcdir)/prism/excludes.h
+proc.$(OBJEXT): $(top_srcdir)/prism/integer.h
+proc.$(OBJEXT): $(top_srcdir)/prism/internal/char.h
+proc.$(OBJEXT): $(top_srcdir)/prism/internal/encoding.h
+proc.$(OBJEXT): $(top_srcdir)/prism/internal/list.h
+proc.$(OBJEXT): $(top_srcdir)/prism/internal/memchr.h
+proc.$(OBJEXT): $(top_srcdir)/prism/internal/regexp.h
+proc.$(OBJEXT): $(top_srcdir)/prism/internal/static_literals.h
+proc.$(OBJEXT): $(top_srcdir)/prism/internal/strncasecmp.h
+proc.$(OBJEXT): $(top_srcdir)/prism/internal/strpbrk.h
+proc.$(OBJEXT): $(top_srcdir)/prism/json.h
+proc.$(OBJEXT): $(top_srcdir)/prism/line_offset_list.h
+proc.$(OBJEXT): $(top_srcdir)/prism/magic_comments.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): $(top_srcdir)/prism/serialize.h
+proc.$(OBJEXT): $(top_srcdir)/prism/source.h
+proc.$(OBJEXT): $(top_srcdir)/prism/stream.h
+proc.$(OBJEXT): $(top_srcdir)/prism/string_query.h
+proc.$(OBJEXT): $(top_srcdir)/prism/stringy.h
proc.$(OBJEXT): $(top_srcdir)/prism/version.h
proc.$(OBJEXT): {$(VPATH)}assert.h
proc.$(OBJEXT): {$(VPATH)}atomic.h
@@ -12060,6 +13097,7 @@ proc.$(OBJEXT): {$(VPATH)}config.h
proc.$(OBJEXT): {$(VPATH)}constant.h
proc.$(OBJEXT): {$(VPATH)}debug_counter.h
proc.$(OBJEXT): {$(VPATH)}defines.h
+proc.$(OBJEXT): {$(VPATH)}encindex.h
proc.$(OBJEXT): {$(VPATH)}encoding.h
proc.$(OBJEXT): {$(VPATH)}eval_intern.h
proc.$(OBJEXT): {$(VPATH)}id.h
@@ -12223,6 +13261,7 @@ proc.$(OBJEXT): {$(VPATH)}node.h
proc.$(OBJEXT): {$(VPATH)}onigmo.h
proc.$(OBJEXT): {$(VPATH)}oniguruma.h
proc.$(OBJEXT): {$(VPATH)}prism_compile.h
+proc.$(OBJEXT): {$(VPATH)}prism_xallocator.h
proc.$(OBJEXT): {$(VPATH)}proc.c
proc.$(OBJEXT): {$(VPATH)}ractor.h
proc.$(OBJEXT): {$(VPATH)}ractor_core.h
@@ -12239,6 +13278,7 @@ proc.$(OBJEXT): {$(VPATH)}vm_debug.h
proc.$(OBJEXT): {$(VPATH)}vm_opts.h
proc.$(OBJEXT): {$(VPATH)}vm_sync.h
proc.$(OBJEXT): {$(VPATH)}yjit.h
+proc.$(OBJEXT): {$(VPATH)}zjit.h
process.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
process.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
process.$(OBJEXT): $(CCAN_DIR)/list/list.h
@@ -12250,7 +13290,9 @@ process.$(OBJEXT): $(top_srcdir)/internal/array.h
process.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
process.$(OBJEXT): $(top_srcdir)/internal/bignum.h
process.$(OBJEXT): $(top_srcdir)/internal/bits.h
+process.$(OBJEXT): $(top_srcdir)/internal/box.h
process.$(OBJEXT): $(top_srcdir)/internal/class.h
+process.$(OBJEXT): $(top_srcdir)/internal/compar.h
process.$(OBJEXT): $(top_srcdir)/internal/compilers.h
process.$(OBJEXT): $(top_srcdir)/internal/dir.h
process.$(OBJEXT): $(top_srcdir)/internal/error.h
@@ -12260,7 +13302,6 @@ 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/namespace.h
process.$(OBJEXT): $(top_srcdir)/internal/numeric.h
process.$(OBJEXT): $(top_srcdir)/internal/object.h
process.$(OBJEXT): $(top_srcdir)/internal/process.h
@@ -12269,6 +13310,7 @@ process.$(OBJEXT): $(top_srcdir)/internal/serial.h
process.$(OBJEXT): $(top_srcdir)/internal/set_table.h
process.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
process.$(OBJEXT): $(top_srcdir)/internal/string.h
+process.$(OBJEXT): $(top_srcdir)/internal/struct.h
process.$(OBJEXT): $(top_srcdir)/internal/thread.h
process.$(OBJEXT): $(top_srcdir)/internal/time.h
process.$(OBJEXT): $(top_srcdir)/internal/variable.h
@@ -12290,6 +13332,7 @@ process.$(OBJEXT): {$(VPATH)}constant.h
process.$(OBJEXT): {$(VPATH)}debug_counter.h
process.$(OBJEXT): {$(VPATH)}defines.h
process.$(OBJEXT): {$(VPATH)}dln.h
+process.$(OBJEXT): {$(VPATH)}encindex.h
process.$(OBJEXT): {$(VPATH)}encoding.h
process.$(OBJEXT): {$(VPATH)}fiber/scheduler.h
process.$(OBJEXT): {$(VPATH)}hrtime.h
@@ -12481,6 +13524,8 @@ ractor.$(OBJEXT): $(top_srcdir)/internal/array.h
ractor.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
ractor.$(OBJEXT): $(top_srcdir)/internal/bignum.h
ractor.$(OBJEXT): $(top_srcdir)/internal/bits.h
+ractor.$(OBJEXT): $(top_srcdir)/internal/box.h
+ractor.$(OBJEXT): $(top_srcdir)/internal/compar.h
ractor.$(OBJEXT): $(top_srcdir)/internal/compilers.h
ractor.$(OBJEXT): $(top_srcdir)/internal/complex.h
ractor.$(OBJEXT): $(top_srcdir)/internal/error.h
@@ -12488,7 +13533,6 @@ ractor.$(OBJEXT): $(top_srcdir)/internal/fixnum.h
ractor.$(OBJEXT): $(top_srcdir)/internal/gc.h
ractor.$(OBJEXT): $(top_srcdir)/internal/hash.h
ractor.$(OBJEXT): $(top_srcdir)/internal/imemo.h
-ractor.$(OBJEXT): $(top_srcdir)/internal/namespace.h
ractor.$(OBJEXT): $(top_srcdir)/internal/numeric.h
ractor.$(OBJEXT): $(top_srcdir)/internal/object.h
ractor.$(OBJEXT): $(top_srcdir)/internal/ractor.h
@@ -12496,6 +13540,7 @@ 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/set_table.h
+ractor.$(OBJEXT): $(top_srcdir)/internal/st.h
ractor.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
ractor.$(OBJEXT): $(top_srcdir)/internal/string.h
ractor.$(OBJEXT): $(top_srcdir)/internal/struct.h
@@ -12519,6 +13564,7 @@ ractor.$(OBJEXT): {$(VPATH)}config.h
ractor.$(OBJEXT): {$(VPATH)}constant.h
ractor.$(OBJEXT): {$(VPATH)}debug_counter.h
ractor.$(OBJEXT): {$(VPATH)}defines.h
+ractor.$(OBJEXT): {$(VPATH)}encindex.h
ractor.$(OBJEXT): {$(VPATH)}encoding.h
ractor.$(OBJEXT): {$(VPATH)}eval_intern.h
ractor.$(OBJEXT): {$(VPATH)}id.h
@@ -12588,6 +13634,7 @@ ractor.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
ractor.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
ractor.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
ractor.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
+ractor.$(OBJEXT): {$(VPATH)}internal/core/rmatch.h
ractor.$(OBJEXT): {$(VPATH)}internal/core/robject.h
ractor.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
ractor.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
@@ -12685,6 +13732,8 @@ ractor.$(OBJEXT): {$(VPATH)}ractor.h
ractor.$(OBJEXT): {$(VPATH)}ractor.rbinc
ractor.$(OBJEXT): {$(VPATH)}ractor_core.h
ractor.$(OBJEXT): {$(VPATH)}ractor_sync.c
+ractor.$(OBJEXT): {$(VPATH)}re.h
+ractor.$(OBJEXT): {$(VPATH)}regex.h
ractor.$(OBJEXT): {$(VPATH)}ruby_assert.h
ractor.$(OBJEXT): {$(VPATH)}ruby_atomic.h
ractor.$(OBJEXT): {$(VPATH)}rubyparser.h
@@ -12710,17 +13759,19 @@ 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/box.h
+random.$(OBJEXT): $(top_srcdir)/internal/compar.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/namespace.h
random.$(OBJEXT): $(top_srcdir)/internal/numeric.h
random.$(OBJEXT): $(top_srcdir)/internal/random.h
random.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
random.$(OBJEXT): $(top_srcdir)/internal/serial.h
random.$(OBJEXT): $(top_srcdir)/internal/set_table.h
random.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
+random.$(OBJEXT): $(top_srcdir)/internal/struct.h
random.$(OBJEXT): $(top_srcdir)/internal/variable.h
random.$(OBJEXT): $(top_srcdir)/internal/vm.h
random.$(OBJEXT): $(top_srcdir)/internal/warnings.h
@@ -12948,6 +13999,7 @@ range.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
range.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
range.$(OBJEXT): {$(VPATH)}config.h
range.$(OBJEXT): {$(VPATH)}defines.h
+range.$(OBJEXT): {$(VPATH)}encindex.h
range.$(OBJEXT): {$(VPATH)}encoding.h
range.$(OBJEXT): {$(VPATH)}id.h
range.$(OBJEXT): {$(VPATH)}id_table.h
@@ -13119,13 +14171,15 @@ 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/box.h
rational.$(OBJEXT): $(top_srcdir)/internal/class.h
+rational.$(OBJEXT): $(top_srcdir)/internal/compar.h
rational.$(OBJEXT): $(top_srcdir)/internal/compilers.h
rational.$(OBJEXT): $(top_srcdir)/internal/complex.h
+rational.$(OBJEXT): $(top_srcdir)/internal/error.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/namespace.h
rational.$(OBJEXT): $(top_srcdir)/internal/numeric.h
rational.$(OBJEXT): $(top_srcdir)/internal/object.h
rational.$(OBJEXT): $(top_srcdir)/internal/rational.h
@@ -13133,6 +14187,7 @@ rational.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
rational.$(OBJEXT): $(top_srcdir)/internal/serial.h
rational.$(OBJEXT): $(top_srcdir)/internal/set_table.h
rational.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
+rational.$(OBJEXT): $(top_srcdir)/internal/string.h
rational.$(OBJEXT): $(top_srcdir)/internal/variable.h
rational.$(OBJEXT): $(top_srcdir)/internal/vm.h
rational.$(OBJEXT): $(top_srcdir)/internal/warnings.h
@@ -13150,6 +14205,7 @@ 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)}encindex.h
rational.$(OBJEXT): {$(VPATH)}encoding.h
rational.$(OBJEXT): {$(VPATH)}id.h
rational.$(OBJEXT): {$(VPATH)}id_table.h
@@ -13329,14 +14385,16 @@ 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/bignum.h
re.$(OBJEXT): $(top_srcdir)/internal/bits.h
+re.$(OBJEXT): $(top_srcdir)/internal/box.h
re.$(OBJEXT): $(top_srcdir)/internal/class.h
re.$(OBJEXT): $(top_srcdir)/internal/compilers.h
re.$(OBJEXT): $(top_srcdir)/internal/encoding.h
+re.$(OBJEXT): $(top_srcdir)/internal/error.h
re.$(OBJEXT): $(top_srcdir)/internal/gc.h
re.$(OBJEXT): $(top_srcdir)/internal/hash.h
re.$(OBJEXT): $(top_srcdir)/internal/imemo.h
-re.$(OBJEXT): $(top_srcdir)/internal/namespace.h
re.$(OBJEXT): $(top_srcdir)/internal/object.h
re.$(OBJEXT): $(top_srcdir)/internal/ractor.h
re.$(OBJEXT): $(top_srcdir)/internal/re.h
@@ -13345,6 +14403,7 @@ re.$(OBJEXT): $(top_srcdir)/internal/serial.h
re.$(OBJEXT): $(top_srcdir)/internal/set_table.h
re.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
re.$(OBJEXT): $(top_srcdir)/internal/string.h
+re.$(OBJEXT): $(top_srcdir)/internal/struct.h
re.$(OBJEXT): $(top_srcdir)/internal/time.h
re.$(OBJEXT): $(top_srcdir)/internal/variable.h
re.$(OBJEXT): $(top_srcdir)/internal/vm.h
@@ -14546,8 +15605,10 @@ 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/box.h
ruby.$(OBJEXT): $(top_srcdir)/internal/class.h
ruby.$(OBJEXT): $(top_srcdir)/internal/cmdlineopt.h
+ruby.$(OBJEXT): $(top_srcdir)/internal/compar.h
ruby.$(OBJEXT): $(top_srcdir)/internal/compilers.h
ruby.$(OBJEXT): $(top_srcdir)/internal/complex.h
ruby.$(OBJEXT): $(top_srcdir)/internal/cont.h
@@ -14561,7 +15622,6 @@ 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/namespace.h
ruby.$(OBJEXT): $(top_srcdir)/internal/numeric.h
ruby.$(OBJEXT): $(top_srcdir)/internal/object.h
ruby.$(OBJEXT): $(top_srcdir)/internal/parse.h
@@ -14572,32 +15632,45 @@ ruby.$(OBJEXT): $(top_srcdir)/internal/serial.h
ruby.$(OBJEXT): $(top_srcdir)/internal/set_table.h
ruby.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
ruby.$(OBJEXT): $(top_srcdir)/internal/string.h
+ruby.$(OBJEXT): $(top_srcdir)/internal/struct.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/arena.h
ruby.$(OBJEXT): $(top_srcdir)/prism/ast.h
-ruby.$(OBJEXT): $(top_srcdir)/prism/defines.h
+ruby.$(OBJEXT): $(top_srcdir)/prism/buffer.h
+ruby.$(OBJEXT): $(top_srcdir)/prism/comments.h
+ruby.$(OBJEXT): $(top_srcdir)/prism/compiler/align.h
+ruby.$(OBJEXT): $(top_srcdir)/prism/compiler/exported.h
+ruby.$(OBJEXT): $(top_srcdir)/prism/compiler/filesystem.h
+ruby.$(OBJEXT): $(top_srcdir)/prism/compiler/nodiscard.h
+ruby.$(OBJEXT): $(top_srcdir)/prism/compiler/nonnull.h
+ruby.$(OBJEXT): $(top_srcdir)/prism/constant_pool.h
ruby.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h
-ruby.$(OBJEXT): $(top_srcdir)/prism/encoding.h
+ruby.$(OBJEXT): $(top_srcdir)/prism/excludes.h
+ruby.$(OBJEXT): $(top_srcdir)/prism/integer.h
+ruby.$(OBJEXT): $(top_srcdir)/prism/internal/char.h
+ruby.$(OBJEXT): $(top_srcdir)/prism/internal/encoding.h
+ruby.$(OBJEXT): $(top_srcdir)/prism/internal/list.h
+ruby.$(OBJEXT): $(top_srcdir)/prism/internal/memchr.h
+ruby.$(OBJEXT): $(top_srcdir)/prism/internal/regexp.h
+ruby.$(OBJEXT): $(top_srcdir)/prism/internal/static_literals.h
+ruby.$(OBJEXT): $(top_srcdir)/prism/internal/strncasecmp.h
+ruby.$(OBJEXT): $(top_srcdir)/prism/internal/strpbrk.h
+ruby.$(OBJEXT): $(top_srcdir)/prism/json.h
+ruby.$(OBJEXT): $(top_srcdir)/prism/line_offset_list.h
+ruby.$(OBJEXT): $(top_srcdir)/prism/magic_comments.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): $(top_srcdir)/prism/serialize.h
+ruby.$(OBJEXT): $(top_srcdir)/prism/source.h
+ruby.$(OBJEXT): $(top_srcdir)/prism/stream.h
+ruby.$(OBJEXT): $(top_srcdir)/prism/string_query.h
+ruby.$(OBJEXT): $(top_srcdir)/prism/stringy.h
ruby.$(OBJEXT): $(top_srcdir)/prism/version.h
ruby.$(OBJEXT): {$(VPATH)}assert.h
ruby.$(OBJEXT): {$(VPATH)}atomic.h
@@ -14615,6 +15688,7 @@ ruby.$(OBJEXT): {$(VPATH)}constant.h
ruby.$(OBJEXT): {$(VPATH)}debug_counter.h
ruby.$(OBJEXT): {$(VPATH)}defines.h
ruby.$(OBJEXT): {$(VPATH)}dln.h
+ruby.$(OBJEXT): {$(VPATH)}encindex.h
ruby.$(OBJEXT): {$(VPATH)}encoding.h
ruby.$(OBJEXT): {$(VPATH)}eval_intern.h
ruby.$(OBJEXT): {$(VPATH)}id.h
@@ -14779,6 +15853,7 @@ ruby.$(OBJEXT): {$(VPATH)}node.h
ruby.$(OBJEXT): {$(VPATH)}onigmo.h
ruby.$(OBJEXT): {$(VPATH)}oniguruma.h
ruby.$(OBJEXT): {$(VPATH)}prism_compile.h
+ruby.$(OBJEXT): {$(VPATH)}prism_xallocator.h
ruby.$(OBJEXT): {$(VPATH)}ruby.c
ruby.$(OBJEXT): {$(VPATH)}ruby_assert.h
ruby.$(OBJEXT): {$(VPATH)}ruby_atomic.h
@@ -14793,10 +15868,13 @@ ruby.$(OBJEXT): {$(VPATH)}util.h
ruby.$(OBJEXT): {$(VPATH)}vm_core.h
ruby.$(OBJEXT): {$(VPATH)}vm_opts.h
ruby.$(OBJEXT): {$(VPATH)}yjit.h
+ruby.$(OBJEXT): {$(VPATH)}zjit.h
ruby_parser.$(OBJEXT): $(hdrdir)/ruby/ruby.h
ruby_parser.$(OBJEXT): $(top_srcdir)/internal/array.h
+ruby_parser.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
ruby_parser.$(OBJEXT): $(top_srcdir)/internal/bignum.h
ruby_parser.$(OBJEXT): $(top_srcdir)/internal/bits.h
+ruby_parser.$(OBJEXT): $(top_srcdir)/internal/compar.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
@@ -14823,6 +15901,7 @@ 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)}encindex.h
ruby_parser.$(OBJEXT): {$(VPATH)}encoding.h
ruby_parser.$(OBJEXT): {$(VPATH)}intern.h
ruby_parser.$(OBJEXT): {$(VPATH)}internal.h
@@ -14889,6 +15968,7 @@ 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/rmatch.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
@@ -14980,6 +16060,8 @@ 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)}re.h
+ruby_parser.$(OBJEXT): {$(VPATH)}regex.h
ruby_parser.$(OBJEXT): {$(VPATH)}ruby_assert.h
ruby_parser.$(OBJEXT): {$(VPATH)}ruby_parser.c
ruby_parser.$(OBJEXT): {$(VPATH)}rubyparser.h
@@ -14992,10 +16074,10 @@ scheduler.$(OBJEXT): $(CCAN_DIR)/str/str.h
scheduler.$(OBJEXT): $(hdrdir)/ruby/ruby.h
scheduler.$(OBJEXT): $(top_srcdir)/internal/array.h
scheduler.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
+scheduler.$(OBJEXT): $(top_srcdir)/internal/box.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/namespace.h
scheduler.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
scheduler.$(OBJEXT): $(top_srcdir)/internal/serial.h
scheduler.$(OBJEXT): $(top_srcdir)/internal/set_table.h
@@ -15019,6 +16101,7 @@ scheduler.$(OBJEXT): {$(VPATH)}config.h
scheduler.$(OBJEXT): {$(VPATH)}constant.h
scheduler.$(OBJEXT): {$(VPATH)}defines.h
scheduler.$(OBJEXT): {$(VPATH)}encoding.h
+scheduler.$(OBJEXT): {$(VPATH)}eval_intern.h
scheduler.$(OBJEXT): {$(VPATH)}fiber/scheduler.h
scheduler.$(OBJEXT): {$(VPATH)}id.h
scheduler.$(OBJEXT): {$(VPATH)}id_table.h
@@ -15193,6 +16276,7 @@ scheduler.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
scheduler.$(OBJEXT): {$(VPATH)}thread_native.h
scheduler.$(OBJEXT): {$(VPATH)}vm_core.h
scheduler.$(OBJEXT): {$(VPATH)}vm_opts.h
+scheduler.$(OBJEXT): {$(VPATH)}zjit.h
set.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
set.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
set.$(OBJEXT): $(CCAN_DIR)/list/list.h
@@ -15201,18 +16285,19 @@ set.$(OBJEXT): $(hdrdir)/ruby/ruby.h
set.$(OBJEXT): $(top_srcdir)/internal/array.h
set.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
set.$(OBJEXT): $(top_srcdir)/internal/bits.h
+set.$(OBJEXT): $(top_srcdir)/internal/box.h
set.$(OBJEXT): $(top_srcdir)/internal/compilers.h
set.$(OBJEXT): $(top_srcdir)/internal/error.h
set.$(OBJEXT): $(top_srcdir)/internal/gc.h
set.$(OBJEXT): $(top_srcdir)/internal/hash.h
set.$(OBJEXT): $(top_srcdir)/internal/imemo.h
-set.$(OBJEXT): $(top_srcdir)/internal/namespace.h
set.$(OBJEXT): $(top_srcdir)/internal/proc.h
set.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
set.$(OBJEXT): $(top_srcdir)/internal/serial.h
set.$(OBJEXT): $(top_srcdir)/internal/set_table.h
set.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
set.$(OBJEXT): $(top_srcdir)/internal/string.h
+set.$(OBJEXT): $(top_srcdir)/internal/struct.h
set.$(OBJEXT): $(top_srcdir)/internal/symbol.h
set.$(OBJEXT): $(top_srcdir)/internal/variable.h
set.$(OBJEXT): $(top_srcdir)/internal/vm.h
@@ -15231,6 +16316,7 @@ set.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
set.$(OBJEXT): {$(VPATH)}config.h
set.$(OBJEXT): {$(VPATH)}constant.h
set.$(OBJEXT): {$(VPATH)}defines.h
+set.$(OBJEXT): {$(VPATH)}encindex.h
set.$(OBJEXT): {$(VPATH)}encoding.h
set.$(OBJEXT): {$(VPATH)}id.h
set.$(OBJEXT): {$(VPATH)}id_table.h
@@ -15571,12 +16657,12 @@ 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/box.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/namespace.h
shape.$(OBJEXT): $(top_srcdir)/internal/object.h
shape.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
shape.$(OBJEXT): $(top_srcdir)/internal/serial.h
@@ -15603,6 +16689,7 @@ shape.$(OBJEXT): {$(VPATH)}config.h
shape.$(OBJEXT): {$(VPATH)}constant.h
shape.$(OBJEXT): {$(VPATH)}debug_counter.h
shape.$(OBJEXT): {$(VPATH)}defines.h
+shape.$(OBJEXT): {$(VPATH)}encindex.h
shape.$(OBJEXT): {$(VPATH)}encoding.h
shape.$(OBJEXT): {$(VPATH)}id.h
shape.$(OBJEXT): {$(VPATH)}id_table.h
@@ -15786,12 +16873,12 @@ 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/box.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
-signal.$(OBJEXT): $(top_srcdir)/internal/namespace.h
signal.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
signal.$(OBJEXT): $(top_srcdir)/internal/serial.h
signal.$(OBJEXT): $(top_srcdir)/internal/set_table.h
@@ -15817,6 +16904,7 @@ signal.$(OBJEXT): {$(VPATH)}config.h
signal.$(OBJEXT): {$(VPATH)}constant.h
signal.$(OBJEXT): {$(VPATH)}debug_counter.h
signal.$(OBJEXT): {$(VPATH)}defines.h
+signal.$(OBJEXT): {$(VPATH)}encindex.h
signal.$(OBJEXT): {$(VPATH)}encoding.h
signal.$(OBJEXT): {$(VPATH)}eval_intern.h
signal.$(OBJEXT): {$(VPATH)}id.h
@@ -15993,11 +17081,14 @@ signal.$(OBJEXT): {$(VPATH)}thread_native.h
signal.$(OBJEXT): {$(VPATH)}vm_core.h
signal.$(OBJEXT): {$(VPATH)}vm_debug.h
signal.$(OBJEXT): {$(VPATH)}vm_opts.h
+signal.$(OBJEXT): {$(VPATH)}zjit.h
sprintf.$(OBJEXT): $(hdrdir)/ruby/ruby.h
sprintf.$(OBJEXT): $(hdrdir)/ruby/version.h
+sprintf.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
sprintf.$(OBJEXT): $(top_srcdir)/internal/bignum.h
sprintf.$(OBJEXT): $(top_srcdir)/internal/bits.h
sprintf.$(OBJEXT): $(top_srcdir)/internal/class.h
+sprintf.$(OBJEXT): $(top_srcdir)/internal/compar.h
sprintf.$(OBJEXT): $(top_srcdir)/internal/compilers.h
sprintf.$(OBJEXT): $(top_srcdir)/internal/error.h
sprintf.$(OBJEXT): $(top_srcdir)/internal/fixnum.h
@@ -16026,6 +17117,7 @@ sprintf.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
sprintf.$(OBJEXT): {$(VPATH)}config.h
sprintf.$(OBJEXT): {$(VPATH)}constant.h
sprintf.$(OBJEXT): {$(VPATH)}defines.h
+sprintf.$(OBJEXT): {$(VPATH)}encindex.h
sprintf.$(OBJEXT): {$(VPATH)}encoding.h
sprintf.$(OBJEXT): {$(VPATH)}id.h
sprintf.$(OBJEXT): {$(VPATH)}id_table.h
@@ -16193,16 +17285,28 @@ sprintf.$(OBJEXT): {$(VPATH)}st.h
sprintf.$(OBJEXT): {$(VPATH)}subst.h
sprintf.$(OBJEXT): {$(VPATH)}util.h
sprintf.$(OBJEXT): {$(VPATH)}vsnprintf.c
+st.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
+st.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
+st.$(OBJEXT): $(CCAN_DIR)/list/list.h
+st.$(OBJEXT): $(CCAN_DIR)/str/str.h
st.$(OBJEXT): $(hdrdir)/ruby/ruby.h
+st.$(OBJEXT): $(top_srcdir)/internal/array.h
+st.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
st.$(OBJEXT): $(top_srcdir)/internal/bits.h
+st.$(OBJEXT): $(top_srcdir)/internal/box.h
st.$(OBJEXT): $(top_srcdir)/internal/compilers.h
+st.$(OBJEXT): $(top_srcdir)/internal/gc.h
st.$(OBJEXT): $(top_srcdir)/internal/hash.h
+st.$(OBJEXT): $(top_srcdir)/internal/imemo.h
st.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
+st.$(OBJEXT): $(top_srcdir)/internal/serial.h
st.$(OBJEXT): $(top_srcdir)/internal/set_table.h
st.$(OBJEXT): $(top_srcdir)/internal/st.h
st.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
+st.$(OBJEXT): $(top_srcdir)/internal/vm.h
st.$(OBJEXT): $(top_srcdir)/internal/warnings.h
st.$(OBJEXT): {$(VPATH)}assert.h
+st.$(OBJEXT): {$(VPATH)}atomic.h
st.$(OBJEXT): {$(VPATH)}backward/2/assume.h
st.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
st.$(OBJEXT): {$(VPATH)}backward/2/bool.h
@@ -16214,6 +17318,9 @@ st.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
st.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
st.$(OBJEXT): {$(VPATH)}config.h
st.$(OBJEXT): {$(VPATH)}defines.h
+st.$(OBJEXT): {$(VPATH)}encoding.h
+st.$(OBJEXT): {$(VPATH)}id.h
+st.$(OBJEXT): {$(VPATH)}id_table.h
st.$(OBJEXT): {$(VPATH)}intern.h
st.$(OBJEXT): {$(VPATH)}internal.h
st.$(OBJEXT): {$(VPATH)}internal/abi.h
@@ -16287,6 +17394,15 @@ st.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
st.$(OBJEXT): {$(VPATH)}internal/ctype.h
st.$(OBJEXT): {$(VPATH)}internal/dllexport.h
st.$(OBJEXT): {$(VPATH)}internal/dosish.h
+st.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
+st.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
+st.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
+st.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
+st.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
+st.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
+st.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
+st.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
+st.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
st.$(OBJEXT): {$(VPATH)}internal/error.h
st.$(OBJEXT): {$(VPATH)}internal/eval.h
st.$(OBJEXT): {$(VPATH)}internal/event.h
@@ -16358,11 +17474,21 @@ st.$(OBJEXT): {$(VPATH)}internal/value_type.h
st.$(OBJEXT): {$(VPATH)}internal/variable.h
st.$(OBJEXT): {$(VPATH)}internal/warning_push.h
st.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
+st.$(OBJEXT): {$(VPATH)}method.h
st.$(OBJEXT): {$(VPATH)}missing.h
+st.$(OBJEXT): {$(VPATH)}node.h
+st.$(OBJEXT): {$(VPATH)}onigmo.h
+st.$(OBJEXT): {$(VPATH)}oniguruma.h
st.$(OBJEXT): {$(VPATH)}ruby_assert.h
+st.$(OBJEXT): {$(VPATH)}ruby_atomic.h
+st.$(OBJEXT): {$(VPATH)}rubyparser.h
st.$(OBJEXT): {$(VPATH)}st.c
st.$(OBJEXT): {$(VPATH)}st.h
st.$(OBJEXT): {$(VPATH)}subst.h
+st.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
+st.$(OBJEXT): {$(VPATH)}thread_native.h
+st.$(OBJEXT): {$(VPATH)}vm_core.h
+st.$(OBJEXT): {$(VPATH)}vm_opts.h
strftime.$(OBJEXT): $(hdrdir)/ruby/ruby.h
strftime.$(OBJEXT): $(top_srcdir)/internal/compilers.h
strftime.$(OBJEXT): $(top_srcdir)/internal/encoding.h
@@ -16382,6 +17508,7 @@ strftime.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
strftime.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
strftime.$(OBJEXT): {$(VPATH)}config.h
strftime.$(OBJEXT): {$(VPATH)}defines.h
+strftime.$(OBJEXT): {$(VPATH)}encindex.h
strftime.$(OBJEXT): {$(VPATH)}encoding.h
strftime.$(OBJEXT): {$(VPATH)}intern.h
strftime.$(OBJEXT): {$(VPATH)}internal.h
@@ -16553,6 +17680,7 @@ string.$(OBJEXT): $(top_srcdir)/internal/array.h
string.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
string.$(OBJEXT): $(top_srcdir)/internal/bignum.h
string.$(OBJEXT): $(top_srcdir)/internal/bits.h
+string.$(OBJEXT): $(top_srcdir)/internal/box.h
string.$(OBJEXT): $(top_srcdir)/internal/class.h
string.$(OBJEXT): $(top_srcdir)/internal/compar.h
string.$(OBJEXT): $(top_srcdir)/internal/compilers.h
@@ -16563,7 +17691,6 @@ string.$(OBJEXT): $(top_srcdir)/internal/fixnum.h
string.$(OBJEXT): $(top_srcdir)/internal/gc.h
string.$(OBJEXT): $(top_srcdir)/internal/hash.h
string.$(OBJEXT): $(top_srcdir)/internal/imemo.h
-string.$(OBJEXT): $(top_srcdir)/internal/namespace.h
string.$(OBJEXT): $(top_srcdir)/internal/numeric.h
string.$(OBJEXT): $(top_srcdir)/internal/object.h
string.$(OBJEXT): $(top_srcdir)/internal/proc.h
@@ -16758,6 +17885,7 @@ string.$(OBJEXT): {$(VPATH)}onigmo.h
string.$(OBJEXT): {$(VPATH)}oniguruma.h
string.$(OBJEXT): {$(VPATH)}probes.dmyh
string.$(OBJEXT): {$(VPATH)}probes.h
+string.$(OBJEXT): {$(VPATH)}ractor.h
string.$(OBJEXT): {$(VPATH)}re.h
string.$(OBJEXT): {$(VPATH)}regex.h
string.$(OBJEXT): {$(VPATH)}ruby_assert.h
@@ -16814,13 +17942,13 @@ 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/box.h
struct.$(OBJEXT): $(top_srcdir)/internal/class.h
struct.$(OBJEXT): $(top_srcdir)/internal/compilers.h
struct.$(OBJEXT): $(top_srcdir)/internal/error.h
struct.$(OBJEXT): $(top_srcdir)/internal/gc.h
struct.$(OBJEXT): $(top_srcdir)/internal/hash.h
struct.$(OBJEXT): $(top_srcdir)/internal/imemo.h
-struct.$(OBJEXT): $(top_srcdir)/internal/namespace.h
struct.$(OBJEXT): $(top_srcdir)/internal/object.h
struct.$(OBJEXT): $(top_srcdir)/internal/proc.h
struct.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
@@ -16849,6 +17977,7 @@ struct.$(OBJEXT): {$(VPATH)}config.h
struct.$(OBJEXT): {$(VPATH)}constant.h
struct.$(OBJEXT): {$(VPATH)}debug_counter.h
struct.$(OBJEXT): {$(VPATH)}defines.h
+struct.$(OBJEXT): {$(VPATH)}encindex.h
struct.$(OBJEXT): {$(VPATH)}encoding.h
struct.$(OBJEXT): {$(VPATH)}id.h
struct.$(OBJEXT): {$(VPATH)}id_table.h
@@ -17030,6 +18159,7 @@ 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/box.h
symbol.$(OBJEXT): $(top_srcdir)/internal/class.h
symbol.$(OBJEXT): $(top_srcdir)/internal/compilers.h
symbol.$(OBJEXT): $(top_srcdir)/internal/concurrent_set.h
@@ -17037,7 +18167,6 @@ 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/namespace.h
symbol.$(OBJEXT): $(top_srcdir)/internal/object.h
symbol.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
symbol.$(OBJEXT): $(top_srcdir)/internal/serial.h
@@ -17062,8 +18191,10 @@ symbol.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
symbol.$(OBJEXT): {$(VPATH)}builtin.h
symbol.$(OBJEXT): {$(VPATH)}config.h
symbol.$(OBJEXT): {$(VPATH)}constant.h
+symbol.$(OBJEXT): {$(VPATH)}darray.h
symbol.$(OBJEXT): {$(VPATH)}debug_counter.h
symbol.$(OBJEXT): {$(VPATH)}defines.h
+symbol.$(OBJEXT): {$(VPATH)}encindex.h
symbol.$(OBJEXT): {$(VPATH)}encoding.h
symbol.$(OBJEXT): {$(VPATH)}id.c
symbol.$(OBJEXT): {$(VPATH)}id.h
@@ -17229,6 +18360,7 @@ symbol.$(OBJEXT): {$(VPATH)}onigmo.h
symbol.$(OBJEXT): {$(VPATH)}oniguruma.h
symbol.$(OBJEXT): {$(VPATH)}probes.dmyh
symbol.$(OBJEXT): {$(VPATH)}probes.h
+symbol.$(OBJEXT): {$(VPATH)}ractor.h
symbol.$(OBJEXT): {$(VPATH)}ruby_assert.h
symbol.$(OBJEXT): {$(VPATH)}ruby_atomic.h
symbol.$(OBJEXT): {$(VPATH)}rubyparser.h
@@ -17255,6 +18387,7 @@ 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
+thread.$(OBJEXT): $(top_srcdir)/internal/box.h
thread.$(OBJEXT): $(top_srcdir)/internal/class.h
thread.$(OBJEXT): $(top_srcdir)/internal/compilers.h
thread.$(OBJEXT): $(top_srcdir)/internal/cont.h
@@ -17264,7 +18397,6 @@ thread.$(OBJEXT): $(top_srcdir)/internal/gc.h
thread.$(OBJEXT): $(top_srcdir)/internal/hash.h
thread.$(OBJEXT): $(top_srcdir)/internal/imemo.h
thread.$(OBJEXT): $(top_srcdir)/internal/io.h
-thread.$(OBJEXT): $(top_srcdir)/internal/namespace.h
thread.$(OBJEXT): $(top_srcdir)/internal/object.h
thread.$(OBJEXT): $(top_srcdir)/internal/proc.h
thread.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
@@ -17273,33 +18405,46 @@ thread.$(OBJEXT): $(top_srcdir)/internal/set_table.h
thread.$(OBJEXT): $(top_srcdir)/internal/signal.h
thread.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
thread.$(OBJEXT): $(top_srcdir)/internal/string.h
+thread.$(OBJEXT): $(top_srcdir)/internal/struct.h
thread.$(OBJEXT): $(top_srcdir)/internal/thread.h
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/arena.h
thread.$(OBJEXT): $(top_srcdir)/prism/ast.h
-thread.$(OBJEXT): $(top_srcdir)/prism/defines.h
+thread.$(OBJEXT): $(top_srcdir)/prism/buffer.h
+thread.$(OBJEXT): $(top_srcdir)/prism/comments.h
+thread.$(OBJEXT): $(top_srcdir)/prism/compiler/align.h
+thread.$(OBJEXT): $(top_srcdir)/prism/compiler/exported.h
+thread.$(OBJEXT): $(top_srcdir)/prism/compiler/filesystem.h
+thread.$(OBJEXT): $(top_srcdir)/prism/compiler/nodiscard.h
+thread.$(OBJEXT): $(top_srcdir)/prism/compiler/nonnull.h
+thread.$(OBJEXT): $(top_srcdir)/prism/constant_pool.h
thread.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h
-thread.$(OBJEXT): $(top_srcdir)/prism/encoding.h
+thread.$(OBJEXT): $(top_srcdir)/prism/excludes.h
+thread.$(OBJEXT): $(top_srcdir)/prism/integer.h
+thread.$(OBJEXT): $(top_srcdir)/prism/internal/char.h
+thread.$(OBJEXT): $(top_srcdir)/prism/internal/encoding.h
+thread.$(OBJEXT): $(top_srcdir)/prism/internal/list.h
+thread.$(OBJEXT): $(top_srcdir)/prism/internal/memchr.h
+thread.$(OBJEXT): $(top_srcdir)/prism/internal/regexp.h
+thread.$(OBJEXT): $(top_srcdir)/prism/internal/static_literals.h
+thread.$(OBJEXT): $(top_srcdir)/prism/internal/strncasecmp.h
+thread.$(OBJEXT): $(top_srcdir)/prism/internal/strpbrk.h
+thread.$(OBJEXT): $(top_srcdir)/prism/json.h
+thread.$(OBJEXT): $(top_srcdir)/prism/line_offset_list.h
+thread.$(OBJEXT): $(top_srcdir)/prism/magic_comments.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): $(top_srcdir)/prism/serialize.h
+thread.$(OBJEXT): $(top_srcdir)/prism/source.h
+thread.$(OBJEXT): $(top_srcdir)/prism/stream.h
+thread.$(OBJEXT): $(top_srcdir)/prism/string_query.h
+thread.$(OBJEXT): $(top_srcdir)/prism/stringy.h
thread.$(OBJEXT): $(top_srcdir)/prism/version.h
thread.$(OBJEXT): {$(VPATH)}$(COROUTINE_H)
thread.$(OBJEXT): {$(VPATH)}assert.h
@@ -17319,6 +18464,7 @@ thread.$(OBJEXT): {$(VPATH)}constant.h
thread.$(OBJEXT): {$(VPATH)}debug.h
thread.$(OBJEXT): {$(VPATH)}debug_counter.h
thread.$(OBJEXT): {$(VPATH)}defines.h
+thread.$(OBJEXT): {$(VPATH)}encindex.h
thread.$(OBJEXT): {$(VPATH)}encoding.h
thread.$(OBJEXT): {$(VPATH)}eval_intern.h
thread.$(OBJEXT): {$(VPATH)}fiber/scheduler.h
@@ -17485,6 +18631,7 @@ thread.$(OBJEXT): {$(VPATH)}node.h
thread.$(OBJEXT): {$(VPATH)}onigmo.h
thread.$(OBJEXT): {$(VPATH)}oniguruma.h
thread.$(OBJEXT): {$(VPATH)}prism_compile.h
+thread.$(OBJEXT): {$(VPATH)}prism_xallocator.h
thread.$(OBJEXT): {$(VPATH)}ractor.h
thread.$(OBJEXT): {$(VPATH)}ractor_core.h
thread.$(OBJEXT): {$(VPATH)}ruby_assert.h
@@ -17506,6 +18653,7 @@ thread.$(OBJEXT): {$(VPATH)}vm_core.h
thread.$(OBJEXT): {$(VPATH)}vm_debug.h
thread.$(OBJEXT): {$(VPATH)}vm_opts.h
thread.$(OBJEXT): {$(VPATH)}vm_sync.h
+thread.$(OBJEXT): {$(VPATH)}zjit.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
@@ -17515,13 +18663,14 @@ time.$(OBJEXT): $(top_srcdir)/internal/array.h
time.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
time.$(OBJEXT): $(top_srcdir)/internal/bignum.h
time.$(OBJEXT): $(top_srcdir)/internal/bits.h
+time.$(OBJEXT): $(top_srcdir)/internal/box.h
time.$(OBJEXT): $(top_srcdir)/internal/compar.h
time.$(OBJEXT): $(top_srcdir)/internal/compilers.h
+time.$(OBJEXT): $(top_srcdir)/internal/error.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/namespace.h
time.$(OBJEXT): $(top_srcdir)/internal/numeric.h
time.$(OBJEXT): $(top_srcdir)/internal/rational.h
time.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
@@ -17529,6 +18678,7 @@ time.$(OBJEXT): $(top_srcdir)/internal/serial.h
time.$(OBJEXT): $(top_srcdir)/internal/set_table.h
time.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
time.$(OBJEXT): $(top_srcdir)/internal/string.h
+time.$(OBJEXT): $(top_srcdir)/internal/struct.h
time.$(OBJEXT): $(top_srcdir)/internal/time.h
time.$(OBJEXT): $(top_srcdir)/internal/variable.h
time.$(OBJEXT): $(top_srcdir)/internal/vm.h
@@ -17548,6 +18698,7 @@ time.$(OBJEXT): {$(VPATH)}builtin.h
time.$(OBJEXT): {$(VPATH)}config.h
time.$(OBJEXT): {$(VPATH)}constant.h
time.$(OBJEXT): {$(VPATH)}defines.h
+time.$(OBJEXT): {$(VPATH)}encindex.h
time.$(OBJEXT): {$(VPATH)}encoding.h
time.$(OBJEXT): {$(VPATH)}id.h
time.$(OBJEXT): {$(VPATH)}id_table.h
@@ -17722,21 +18873,32 @@ time.$(OBJEXT): {$(VPATH)}timev.rbinc
time.$(OBJEXT): {$(VPATH)}util.h
time.$(OBJEXT): {$(VPATH)}vm_core.h
time.$(OBJEXT): {$(VPATH)}vm_opts.h
+transcode.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
+transcode.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
+transcode.$(OBJEXT): $(CCAN_DIR)/list/list.h
+transcode.$(OBJEXT): $(CCAN_DIR)/str/str.h
transcode.$(OBJEXT): $(hdrdir)/ruby/ruby.h
transcode.$(OBJEXT): $(top_srcdir)/internal/array.h
+transcode.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
+transcode.$(OBJEXT): $(top_srcdir)/internal/box.h
transcode.$(OBJEXT): $(top_srcdir)/internal/class.h
transcode.$(OBJEXT): $(top_srcdir)/internal/compilers.h
transcode.$(OBJEXT): $(top_srcdir)/internal/encoding.h
transcode.$(OBJEXT): $(top_srcdir)/internal/gc.h
+transcode.$(OBJEXT): $(top_srcdir)/internal/imemo.h
transcode.$(OBJEXT): $(top_srcdir)/internal/inits.h
transcode.$(OBJEXT): $(top_srcdir)/internal/object.h
+transcode.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
transcode.$(OBJEXT): $(top_srcdir)/internal/serial.h
+transcode.$(OBJEXT): $(top_srcdir)/internal/set_table.h
transcode.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
transcode.$(OBJEXT): $(top_srcdir)/internal/string.h
transcode.$(OBJEXT): $(top_srcdir)/internal/transcode.h
transcode.$(OBJEXT): $(top_srcdir)/internal/variable.h
+transcode.$(OBJEXT): $(top_srcdir)/internal/vm.h
transcode.$(OBJEXT): $(top_srcdir)/internal/warnings.h
transcode.$(OBJEXT): {$(VPATH)}assert.h
+transcode.$(OBJEXT): {$(VPATH)}atomic.h
transcode.$(OBJEXT): {$(VPATH)}backward/2/assume.h
transcode.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
transcode.$(OBJEXT): {$(VPATH)}backward/2/bool.h
@@ -17750,6 +18912,7 @@ transcode.$(OBJEXT): {$(VPATH)}config.h
transcode.$(OBJEXT): {$(VPATH)}constant.h
transcode.$(OBJEXT): {$(VPATH)}debug_counter.h
transcode.$(OBJEXT): {$(VPATH)}defines.h
+transcode.$(OBJEXT): {$(VPATH)}encindex.h
transcode.$(OBJEXT): {$(VPATH)}encoding.h
transcode.$(OBJEXT): {$(VPATH)}id.h
transcode.$(OBJEXT): {$(VPATH)}id_table.h
@@ -17905,15 +19068,24 @@ transcode.$(OBJEXT): {$(VPATH)}internal/value_type.h
transcode.$(OBJEXT): {$(VPATH)}internal/variable.h
transcode.$(OBJEXT): {$(VPATH)}internal/warning_push.h
transcode.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
+transcode.$(OBJEXT): {$(VPATH)}method.h
transcode.$(OBJEXT): {$(VPATH)}missing.h
+transcode.$(OBJEXT): {$(VPATH)}node.h
transcode.$(OBJEXT): {$(VPATH)}onigmo.h
transcode.$(OBJEXT): {$(VPATH)}oniguruma.h
+transcode.$(OBJEXT): {$(VPATH)}ruby_assert.h
+transcode.$(OBJEXT): {$(VPATH)}ruby_atomic.h
+transcode.$(OBJEXT): {$(VPATH)}rubyparser.h
transcode.$(OBJEXT): {$(VPATH)}shape.h
transcode.$(OBJEXT): {$(VPATH)}st.h
transcode.$(OBJEXT): {$(VPATH)}subst.h
+transcode.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
+transcode.$(OBJEXT): {$(VPATH)}thread_native.h
transcode.$(OBJEXT): {$(VPATH)}transcode.c
transcode.$(OBJEXT): {$(VPATH)}transcode_data.h
+transcode.$(OBJEXT): {$(VPATH)}vm_core.h
transcode.$(OBJEXT): {$(VPATH)}vm_debug.h
+transcode.$(OBJEXT): {$(VPATH)}vm_opts.h
transcode.$(OBJEXT): {$(VPATH)}vm_sync.h
util.$(OBJEXT): $(hdrdir)/ruby/ruby.h
util.$(OBJEXT): $(top_srcdir)/internal/array.h
@@ -18095,6 +19267,7 @@ 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/box.h
variable.$(OBJEXT): $(top_srcdir)/internal/class.h
variable.$(OBJEXT): $(top_srcdir)/internal/compilers.h
variable.$(OBJEXT): $(top_srcdir)/internal/error.h
@@ -18102,7 +19275,6 @@ variable.$(OBJEXT): $(top_srcdir)/internal/eval.h
variable.$(OBJEXT): $(top_srcdir)/internal/gc.h
variable.$(OBJEXT): $(top_srcdir)/internal/hash.h
variable.$(OBJEXT): $(top_srcdir)/internal/imemo.h
-variable.$(OBJEXT): $(top_srcdir)/internal/namespace.h
variable.$(OBJEXT): $(top_srcdir)/internal/object.h
variable.$(OBJEXT): $(top_srcdir)/internal/re.h
variable.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
@@ -18131,6 +19303,7 @@ variable.$(OBJEXT): {$(VPATH)}config.h
variable.$(OBJEXT): {$(VPATH)}constant.h
variable.$(OBJEXT): {$(VPATH)}debug_counter.h
variable.$(OBJEXT): {$(VPATH)}defines.h
+variable.$(OBJEXT): {$(VPATH)}encindex.h
variable.$(OBJEXT): {$(VPATH)}encoding.h
variable.$(OBJEXT): {$(VPATH)}id.h
variable.$(OBJEXT): {$(VPATH)}id_table.h
@@ -18199,6 +19372,7 @@ variable.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
variable.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
variable.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
variable.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
+variable.$(OBJEXT): {$(VPATH)}internal/core/rmatch.h
variable.$(OBJEXT): {$(VPATH)}internal/core/robject.h
variable.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
variable.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
@@ -18293,6 +19467,8 @@ variable.$(OBJEXT): {$(VPATH)}onigmo.h
variable.$(OBJEXT): {$(VPATH)}oniguruma.h
variable.$(OBJEXT): {$(VPATH)}ractor.h
variable.$(OBJEXT): {$(VPATH)}ractor_core.h
+variable.$(OBJEXT): {$(VPATH)}re.h
+variable.$(OBJEXT): {$(VPATH)}regex.h
variable.$(OBJEXT): {$(VPATH)}ruby_assert.h
variable.$(OBJEXT): {$(VPATH)}ruby_atomic.h
variable.$(OBJEXT): {$(VPATH)}rubyparser.h
@@ -18318,11 +19494,11 @@ version.$(OBJEXT): $(hdrdir)/ruby/ruby.h
version.$(OBJEXT): $(hdrdir)/ruby/version.h
version.$(OBJEXT): $(top_srcdir)/internal/array.h
version.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
+version.$(OBJEXT): $(top_srcdir)/internal/box.h
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/namespace.h
version.$(OBJEXT): $(top_srcdir)/internal/parse.h
version.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
version.$(OBJEXT): $(top_srcdir)/internal/serial.h
@@ -18531,6 +19707,7 @@ vm.$(OBJEXT): $(top_srcdir)/internal/array.h
vm.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
vm.$(OBJEXT): $(top_srcdir)/internal/bignum.h
vm.$(OBJEXT): $(top_srcdir)/internal/bits.h
+vm.$(OBJEXT): $(top_srcdir)/internal/box.h
vm.$(OBJEXT): $(top_srcdir)/internal/class.h
vm.$(OBJEXT): $(top_srcdir)/internal/compar.h
vm.$(OBJEXT): $(top_srcdir)/internal/compile.h
@@ -18546,7 +19723,6 @@ 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/namespace.h
vm.$(OBJEXT): $(top_srcdir)/internal/numeric.h
vm.$(OBJEXT): $(top_srcdir)/internal/object.h
vm.$(OBJEXT): $(top_srcdir)/internal/parse.h
@@ -18558,6 +19734,7 @@ 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/set_table.h
+vm.$(OBJEXT): $(top_srcdir)/internal/st.h
vm.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
vm.$(OBJEXT): $(top_srcdir)/internal/string.h
vm.$(OBJEXT): $(top_srcdir)/internal/struct.h
@@ -18567,28 +19744,40 @@ 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/arena.h
vm.$(OBJEXT): $(top_srcdir)/prism/ast.h
-vm.$(OBJEXT): $(top_srcdir)/prism/defines.h
+vm.$(OBJEXT): $(top_srcdir)/prism/buffer.h
+vm.$(OBJEXT): $(top_srcdir)/prism/comments.h
+vm.$(OBJEXT): $(top_srcdir)/prism/compiler/align.h
+vm.$(OBJEXT): $(top_srcdir)/prism/compiler/exported.h
+vm.$(OBJEXT): $(top_srcdir)/prism/compiler/filesystem.h
+vm.$(OBJEXT): $(top_srcdir)/prism/compiler/nodiscard.h
+vm.$(OBJEXT): $(top_srcdir)/prism/compiler/nonnull.h
+vm.$(OBJEXT): $(top_srcdir)/prism/constant_pool.h
vm.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h
-vm.$(OBJEXT): $(top_srcdir)/prism/encoding.h
+vm.$(OBJEXT): $(top_srcdir)/prism/excludes.h
+vm.$(OBJEXT): $(top_srcdir)/prism/integer.h
+vm.$(OBJEXT): $(top_srcdir)/prism/internal/char.h
+vm.$(OBJEXT): $(top_srcdir)/prism/internal/encoding.h
+vm.$(OBJEXT): $(top_srcdir)/prism/internal/list.h
+vm.$(OBJEXT): $(top_srcdir)/prism/internal/memchr.h
+vm.$(OBJEXT): $(top_srcdir)/prism/internal/regexp.h
+vm.$(OBJEXT): $(top_srcdir)/prism/internal/static_literals.h
+vm.$(OBJEXT): $(top_srcdir)/prism/internal/strncasecmp.h
+vm.$(OBJEXT): $(top_srcdir)/prism/internal/strpbrk.h
+vm.$(OBJEXT): $(top_srcdir)/prism/json.h
+vm.$(OBJEXT): $(top_srcdir)/prism/line_offset_list.h
+vm.$(OBJEXT): $(top_srcdir)/prism/magic_comments.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): $(top_srcdir)/prism/serialize.h
+vm.$(OBJEXT): $(top_srcdir)/prism/source.h
+vm.$(OBJEXT): $(top_srcdir)/prism/stream.h
+vm.$(OBJEXT): $(top_srcdir)/prism/string_query.h
+vm.$(OBJEXT): $(top_srcdir)/prism/stringy.h
vm.$(OBJEXT): $(top_srcdir)/prism/version.h
vm.$(OBJEXT): {$(VPATH)}assert.h
vm.$(OBJEXT): {$(VPATH)}atomic.h
@@ -18607,6 +19796,7 @@ vm.$(OBJEXT): {$(VPATH)}constant.h
vm.$(OBJEXT): {$(VPATH)}debug_counter.h
vm.$(OBJEXT): {$(VPATH)}defines.h
vm.$(OBJEXT): {$(VPATH)}defs/opt_operand.def
+vm.$(OBJEXT): {$(VPATH)}encindex.h
vm.$(OBJEXT): {$(VPATH)}encoding.h
vm.$(OBJEXT): {$(VPATH)}eval_intern.h
vm.$(OBJEXT): {$(VPATH)}id.h
@@ -18679,6 +19869,7 @@ vm.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
vm.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
vm.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
vm.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
+vm.$(OBJEXT): {$(VPATH)}internal/core/rmatch.h
vm.$(OBJEXT): {$(VPATH)}internal/core/robject.h
vm.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
vm.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
@@ -18775,11 +19966,14 @@ vm.$(OBJEXT): {$(VPATH)}node.h
vm.$(OBJEXT): {$(VPATH)}onigmo.h
vm.$(OBJEXT): {$(VPATH)}oniguruma.h
vm.$(OBJEXT): {$(VPATH)}prism_compile.h
+vm.$(OBJEXT): {$(VPATH)}prism_xallocator.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)}re.h
+vm.$(OBJEXT): {$(VPATH)}regex.h
vm.$(OBJEXT): {$(VPATH)}ruby_assert.h
vm.$(OBJEXT): {$(VPATH)}ruby_atomic.h
vm.$(OBJEXT): {$(VPATH)}rubyparser.h
@@ -18817,42 +20011,56 @@ 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/box.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/namespace.h
+vm_backtrace.$(OBJEXT): $(top_srcdir)/internal/object.h
vm_backtrace.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
vm_backtrace.$(OBJEXT): $(top_srcdir)/internal/serial.h
vm_backtrace.$(OBJEXT): $(top_srcdir)/internal/set_table.h
vm_backtrace.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
vm_backtrace.$(OBJEXT): $(top_srcdir)/internal/string.h
+vm_backtrace.$(OBJEXT): $(top_srcdir)/internal/struct.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/arena.h
vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/ast.h
-vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/defines.h
+vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/buffer.h
+vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/comments.h
+vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/compiler/align.h
+vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/compiler/exported.h
+vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/compiler/filesystem.h
+vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/compiler/nodiscard.h
+vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/compiler/nonnull.h
+vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/constant_pool.h
vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h
-vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/encoding.h
+vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/excludes.h
+vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/integer.h
+vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/internal/char.h
+vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/internal/encoding.h
+vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/internal/list.h
+vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/internal/memchr.h
+vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/internal/regexp.h
+vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/internal/static_literals.h
+vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/internal/strncasecmp.h
+vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/internal/strpbrk.h
+vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/json.h
+vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/line_offset_list.h
+vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/magic_comments.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): $(top_srcdir)/prism/serialize.h
+vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/source.h
+vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/stream.h
+vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/string_query.h
+vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/stringy.h
vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/version.h
vm_backtrace.$(OBJEXT): {$(VPATH)}assert.h
vm_backtrace.$(OBJEXT): {$(VPATH)}atomic.h
@@ -18870,6 +20078,7 @@ 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)}encindex.h
vm_backtrace.$(OBJEXT): {$(VPATH)}encoding.h
vm_backtrace.$(OBJEXT): {$(VPATH)}eval_intern.h
vm_backtrace.$(OBJEXT): {$(VPATH)}id.h
@@ -19033,6 +20242,7 @@ vm_backtrace.$(OBJEXT): {$(VPATH)}node.h
vm_backtrace.$(OBJEXT): {$(VPATH)}onigmo.h
vm_backtrace.$(OBJEXT): {$(VPATH)}oniguruma.h
vm_backtrace.$(OBJEXT): {$(VPATH)}prism_compile.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}prism_xallocator.h
vm_backtrace.$(OBJEXT): {$(VPATH)}ruby_assert.h
vm_backtrace.$(OBJEXT): {$(VPATH)}ruby_atomic.h
vm_backtrace.$(OBJEXT): {$(VPATH)}rubyparser.h
@@ -19046,6 +20256,7 @@ 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_backtrace.$(OBJEXT): {$(VPATH)}zjit.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
@@ -19053,39 +20264,52 @@ vm_dump.$(OBJEXT): $(CCAN_DIR)/str/str.h
vm_dump.$(OBJEXT): $(hdrdir)/ruby/ruby.h
vm_dump.$(OBJEXT): $(top_srcdir)/internal/array.h
vm_dump.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
+vm_dump.$(OBJEXT): $(top_srcdir)/internal/box.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/namespace.h
vm_dump.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
vm_dump.$(OBJEXT): $(top_srcdir)/internal/serial.h
vm_dump.$(OBJEXT): $(top_srcdir)/internal/set_table.h
vm_dump.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
+vm_dump.$(OBJEXT): $(top_srcdir)/internal/struct.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/arena.h
vm_dump.$(OBJEXT): $(top_srcdir)/prism/ast.h
-vm_dump.$(OBJEXT): $(top_srcdir)/prism/defines.h
+vm_dump.$(OBJEXT): $(top_srcdir)/prism/buffer.h
+vm_dump.$(OBJEXT): $(top_srcdir)/prism/comments.h
+vm_dump.$(OBJEXT): $(top_srcdir)/prism/compiler/align.h
+vm_dump.$(OBJEXT): $(top_srcdir)/prism/compiler/exported.h
+vm_dump.$(OBJEXT): $(top_srcdir)/prism/compiler/filesystem.h
+vm_dump.$(OBJEXT): $(top_srcdir)/prism/compiler/nodiscard.h
+vm_dump.$(OBJEXT): $(top_srcdir)/prism/compiler/nonnull.h
+vm_dump.$(OBJEXT): $(top_srcdir)/prism/constant_pool.h
vm_dump.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h
-vm_dump.$(OBJEXT): $(top_srcdir)/prism/encoding.h
+vm_dump.$(OBJEXT): $(top_srcdir)/prism/excludes.h
+vm_dump.$(OBJEXT): $(top_srcdir)/prism/integer.h
+vm_dump.$(OBJEXT): $(top_srcdir)/prism/internal/char.h
+vm_dump.$(OBJEXT): $(top_srcdir)/prism/internal/encoding.h
+vm_dump.$(OBJEXT): $(top_srcdir)/prism/internal/list.h
+vm_dump.$(OBJEXT): $(top_srcdir)/prism/internal/memchr.h
+vm_dump.$(OBJEXT): $(top_srcdir)/prism/internal/regexp.h
+vm_dump.$(OBJEXT): $(top_srcdir)/prism/internal/static_literals.h
+vm_dump.$(OBJEXT): $(top_srcdir)/prism/internal/strncasecmp.h
+vm_dump.$(OBJEXT): $(top_srcdir)/prism/internal/strpbrk.h
+vm_dump.$(OBJEXT): $(top_srcdir)/prism/json.h
+vm_dump.$(OBJEXT): $(top_srcdir)/prism/line_offset_list.h
+vm_dump.$(OBJEXT): $(top_srcdir)/prism/magic_comments.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): $(top_srcdir)/prism/serialize.h
+vm_dump.$(OBJEXT): $(top_srcdir)/prism/source.h
+vm_dump.$(OBJEXT): $(top_srcdir)/prism/stream.h
+vm_dump.$(OBJEXT): $(top_srcdir)/prism/string_query.h
+vm_dump.$(OBJEXT): $(top_srcdir)/prism/stringy.h
vm_dump.$(OBJEXT): $(top_srcdir)/prism/version.h
vm_dump.$(OBJEXT): {$(VPATH)}addr2line.h
vm_dump.$(OBJEXT): {$(VPATH)}assert.h
@@ -19265,6 +20489,7 @@ vm_dump.$(OBJEXT): {$(VPATH)}node.h
vm_dump.$(OBJEXT): {$(VPATH)}onigmo.h
vm_dump.$(OBJEXT): {$(VPATH)}oniguruma.h
vm_dump.$(OBJEXT): {$(VPATH)}prism_compile.h
+vm_dump.$(OBJEXT): {$(VPATH)}prism_xallocator.h
vm_dump.$(OBJEXT): {$(VPATH)}procstat_vm.c
vm_dump.$(OBJEXT): {$(VPATH)}ractor.h
vm_dump.$(OBJEXT): {$(VPATH)}ractor_core.h
@@ -19280,6 +20505,7 @@ vm_dump.$(OBJEXT): {$(VPATH)}vm_core.h
vm_dump.$(OBJEXT): {$(VPATH)}vm_debug.h
vm_dump.$(OBJEXT): {$(VPATH)}vm_dump.c
vm_dump.$(OBJEXT): {$(VPATH)}vm_opts.h
+vm_dump.$(OBJEXT): {$(VPATH)}zjit.h
vm_sync.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
vm_sync.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
vm_sync.$(OBJEXT): $(CCAN_DIR)/list/list.h
@@ -19287,10 +20513,10 @@ vm_sync.$(OBJEXT): $(CCAN_DIR)/str/str.h
vm_sync.$(OBJEXT): $(hdrdir)/ruby/ruby.h
vm_sync.$(OBJEXT): $(top_srcdir)/internal/array.h
vm_sync.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
+vm_sync.$(OBJEXT): $(top_srcdir)/internal/box.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/namespace.h
vm_sync.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
vm_sync.$(OBJEXT): $(top_srcdir)/internal/serial.h
vm_sync.$(OBJEXT): $(top_srcdir)/internal/set_table.h
@@ -19498,43 +20724,56 @@ 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/box.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/namespace.h
vm_trace.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
vm_trace.$(OBJEXT): $(top_srcdir)/internal/serial.h
vm_trace.$(OBJEXT): $(top_srcdir)/internal/set_table.h
vm_trace.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
+vm_trace.$(OBJEXT): $(top_srcdir)/internal/struct.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/arena.h
vm_trace.$(OBJEXT): $(top_srcdir)/prism/ast.h
-vm_trace.$(OBJEXT): $(top_srcdir)/prism/defines.h
+vm_trace.$(OBJEXT): $(top_srcdir)/prism/buffer.h
+vm_trace.$(OBJEXT): $(top_srcdir)/prism/comments.h
+vm_trace.$(OBJEXT): $(top_srcdir)/prism/compiler/align.h
+vm_trace.$(OBJEXT): $(top_srcdir)/prism/compiler/exported.h
+vm_trace.$(OBJEXT): $(top_srcdir)/prism/compiler/filesystem.h
+vm_trace.$(OBJEXT): $(top_srcdir)/prism/compiler/nodiscard.h
+vm_trace.$(OBJEXT): $(top_srcdir)/prism/compiler/nonnull.h
+vm_trace.$(OBJEXT): $(top_srcdir)/prism/constant_pool.h
vm_trace.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h
-vm_trace.$(OBJEXT): $(top_srcdir)/prism/encoding.h
+vm_trace.$(OBJEXT): $(top_srcdir)/prism/excludes.h
+vm_trace.$(OBJEXT): $(top_srcdir)/prism/integer.h
+vm_trace.$(OBJEXT): $(top_srcdir)/prism/internal/char.h
+vm_trace.$(OBJEXT): $(top_srcdir)/prism/internal/encoding.h
+vm_trace.$(OBJEXT): $(top_srcdir)/prism/internal/list.h
+vm_trace.$(OBJEXT): $(top_srcdir)/prism/internal/memchr.h
+vm_trace.$(OBJEXT): $(top_srcdir)/prism/internal/regexp.h
+vm_trace.$(OBJEXT): $(top_srcdir)/prism/internal/static_literals.h
+vm_trace.$(OBJEXT): $(top_srcdir)/prism/internal/strncasecmp.h
+vm_trace.$(OBJEXT): $(top_srcdir)/prism/internal/strpbrk.h
+vm_trace.$(OBJEXT): $(top_srcdir)/prism/json.h
+vm_trace.$(OBJEXT): $(top_srcdir)/prism/line_offset_list.h
+vm_trace.$(OBJEXT): $(top_srcdir)/prism/magic_comments.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): $(top_srcdir)/prism/serialize.h
+vm_trace.$(OBJEXT): $(top_srcdir)/prism/source.h
+vm_trace.$(OBJEXT): $(top_srcdir)/prism/stream.h
+vm_trace.$(OBJEXT): $(top_srcdir)/prism/string_query.h
+vm_trace.$(OBJEXT): $(top_srcdir)/prism/stringy.h
vm_trace.$(OBJEXT): $(top_srcdir)/prism/version.h
vm_trace.$(OBJEXT): {$(VPATH)}assert.h
vm_trace.$(OBJEXT): {$(VPATH)}atomic.h
@@ -19716,7 +20955,9 @@ vm_trace.$(OBJEXT): {$(VPATH)}node.h
vm_trace.$(OBJEXT): {$(VPATH)}onigmo.h
vm_trace.$(OBJEXT): {$(VPATH)}oniguruma.h
vm_trace.$(OBJEXT): {$(VPATH)}prism_compile.h
+vm_trace.$(OBJEXT): {$(VPATH)}prism_xallocator.h
vm_trace.$(OBJEXT): {$(VPATH)}ractor.h
+vm_trace.$(OBJEXT): {$(VPATH)}ractor_core.h
vm_trace.$(OBJEXT): {$(VPATH)}ruby_assert.h
vm_trace.$(OBJEXT): {$(VPATH)}ruby_atomic.h
vm_trace.$(OBJEXT): {$(VPATH)}rubyparser.h
@@ -19732,6 +20973,7 @@ 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
+vm_trace.$(OBJEXT): {$(VPATH)}zjit.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
@@ -19739,11 +20981,11 @@ 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/box.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/namespace.h
weakmap.$(OBJEXT): $(top_srcdir)/internal/proc.h
weakmap.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
weakmap.$(OBJEXT): $(top_srcdir)/internal/serial.h
@@ -19943,7 +21185,9 @@ 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/box.h
yjit.$(OBJEXT): $(top_srcdir)/internal/class.h
+yjit.$(OBJEXT): $(top_srcdir)/internal/compar.h
yjit.$(OBJEXT): $(top_srcdir)/internal/compile.h
yjit.$(OBJEXT): $(top_srcdir)/internal/compilers.h
yjit.$(OBJEXT): $(top_srcdir)/internal/cont.h
@@ -19951,38 +21195,50 @@ 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/namespace.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/set_table.h
yjit.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
yjit.$(OBJEXT): $(top_srcdir)/internal/string.h
+yjit.$(OBJEXT): $(top_srcdir)/internal/struct.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/arena.h
yjit.$(OBJEXT): $(top_srcdir)/prism/ast.h
-yjit.$(OBJEXT): $(top_srcdir)/prism/defines.h
+yjit.$(OBJEXT): $(top_srcdir)/prism/buffer.h
+yjit.$(OBJEXT): $(top_srcdir)/prism/comments.h
+yjit.$(OBJEXT): $(top_srcdir)/prism/compiler/align.h
+yjit.$(OBJEXT): $(top_srcdir)/prism/compiler/exported.h
+yjit.$(OBJEXT): $(top_srcdir)/prism/compiler/filesystem.h
+yjit.$(OBJEXT): $(top_srcdir)/prism/compiler/nodiscard.h
+yjit.$(OBJEXT): $(top_srcdir)/prism/compiler/nonnull.h
+yjit.$(OBJEXT): $(top_srcdir)/prism/constant_pool.h
yjit.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h
-yjit.$(OBJEXT): $(top_srcdir)/prism/encoding.h
+yjit.$(OBJEXT): $(top_srcdir)/prism/excludes.h
+yjit.$(OBJEXT): $(top_srcdir)/prism/integer.h
+yjit.$(OBJEXT): $(top_srcdir)/prism/internal/char.h
+yjit.$(OBJEXT): $(top_srcdir)/prism/internal/encoding.h
+yjit.$(OBJEXT): $(top_srcdir)/prism/internal/list.h
+yjit.$(OBJEXT): $(top_srcdir)/prism/internal/memchr.h
+yjit.$(OBJEXT): $(top_srcdir)/prism/internal/regexp.h
+yjit.$(OBJEXT): $(top_srcdir)/prism/internal/static_literals.h
+yjit.$(OBJEXT): $(top_srcdir)/prism/internal/strncasecmp.h
+yjit.$(OBJEXT): $(top_srcdir)/prism/internal/strpbrk.h
+yjit.$(OBJEXT): $(top_srcdir)/prism/json.h
+yjit.$(OBJEXT): $(top_srcdir)/prism/line_offset_list.h
+yjit.$(OBJEXT): $(top_srcdir)/prism/magic_comments.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): $(top_srcdir)/prism/serialize.h
+yjit.$(OBJEXT): $(top_srcdir)/prism/source.h
+yjit.$(OBJEXT): $(top_srcdir)/prism/stream.h
+yjit.$(OBJEXT): $(top_srcdir)/prism/string_query.h
+yjit.$(OBJEXT): $(top_srcdir)/prism/stringy.h
yjit.$(OBJEXT): $(top_srcdir)/prism/version.h
yjit.$(OBJEXT): {$(VPATH)}assert.h
yjit.$(OBJEXT): {$(VPATH)}atomic.h
@@ -20001,6 +21257,7 @@ yjit.$(OBJEXT): {$(VPATH)}constant.h
yjit.$(OBJEXT): {$(VPATH)}debug.h
yjit.$(OBJEXT): {$(VPATH)}debug_counter.h
yjit.$(OBJEXT): {$(VPATH)}defines.h
+yjit.$(OBJEXT): {$(VPATH)}encindex.h
yjit.$(OBJEXT): {$(VPATH)}encoding.h
yjit.$(OBJEXT): {$(VPATH)}id.h
yjit.$(OBJEXT): {$(VPATH)}id_table.h
@@ -20167,6 +21424,7 @@ yjit.$(OBJEXT): {$(VPATH)}node.h
yjit.$(OBJEXT): {$(VPATH)}onigmo.h
yjit.$(OBJEXT): {$(VPATH)}oniguruma.h
yjit.$(OBJEXT): {$(VPATH)}prism_compile.h
+yjit.$(OBJEXT): {$(VPATH)}prism_xallocator.h
yjit.$(OBJEXT): {$(VPATH)}probes.dmyh
yjit.$(OBJEXT): {$(VPATH)}probes.h
yjit.$(OBJEXT): {$(VPATH)}probes_helper.h
@@ -20197,7 +21455,9 @@ zjit.$(OBJEXT): $(top_srcdir)/internal/array.h
zjit.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
zjit.$(OBJEXT): $(top_srcdir)/internal/bignum.h
zjit.$(OBJEXT): $(top_srcdir)/internal/bits.h
+zjit.$(OBJEXT): $(top_srcdir)/internal/box.h
zjit.$(OBJEXT): $(top_srcdir)/internal/class.h
+zjit.$(OBJEXT): $(top_srcdir)/internal/compar.h
zjit.$(OBJEXT): $(top_srcdir)/internal/compile.h
zjit.$(OBJEXT): $(top_srcdir)/internal/compilers.h
zjit.$(OBJEXT): $(top_srcdir)/internal/cont.h
@@ -20208,33 +21468,47 @@ zjit.$(OBJEXT): $(top_srcdir)/internal/imemo.h
zjit.$(OBJEXT): $(top_srcdir)/internal/numeric.h
zjit.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
zjit.$(OBJEXT): $(top_srcdir)/internal/serial.h
+zjit.$(OBJEXT): $(top_srcdir)/internal/set_table.h
zjit.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
zjit.$(OBJEXT): $(top_srcdir)/internal/string.h
+zjit.$(OBJEXT): $(top_srcdir)/internal/struct.h
zjit.$(OBJEXT): $(top_srcdir)/internal/variable.h
zjit.$(OBJEXT): $(top_srcdir)/internal/vm.h
zjit.$(OBJEXT): $(top_srcdir)/internal/warnings.h
+zjit.$(OBJEXT): $(top_srcdir)/prism/arena.h
zjit.$(OBJEXT): $(top_srcdir)/prism/ast.h
-zjit.$(OBJEXT): $(top_srcdir)/prism/defines.h
+zjit.$(OBJEXT): $(top_srcdir)/prism/buffer.h
+zjit.$(OBJEXT): $(top_srcdir)/prism/comments.h
+zjit.$(OBJEXT): $(top_srcdir)/prism/compiler/align.h
+zjit.$(OBJEXT): $(top_srcdir)/prism/compiler/exported.h
+zjit.$(OBJEXT): $(top_srcdir)/prism/compiler/filesystem.h
+zjit.$(OBJEXT): $(top_srcdir)/prism/compiler/nodiscard.h
+zjit.$(OBJEXT): $(top_srcdir)/prism/compiler/nonnull.h
+zjit.$(OBJEXT): $(top_srcdir)/prism/constant_pool.h
zjit.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h
-zjit.$(OBJEXT): $(top_srcdir)/prism/encoding.h
+zjit.$(OBJEXT): $(top_srcdir)/prism/excludes.h
+zjit.$(OBJEXT): $(top_srcdir)/prism/integer.h
+zjit.$(OBJEXT): $(top_srcdir)/prism/internal/char.h
+zjit.$(OBJEXT): $(top_srcdir)/prism/internal/encoding.h
+zjit.$(OBJEXT): $(top_srcdir)/prism/internal/list.h
+zjit.$(OBJEXT): $(top_srcdir)/prism/internal/memchr.h
+zjit.$(OBJEXT): $(top_srcdir)/prism/internal/regexp.h
+zjit.$(OBJEXT): $(top_srcdir)/prism/internal/static_literals.h
+zjit.$(OBJEXT): $(top_srcdir)/prism/internal/strncasecmp.h
+zjit.$(OBJEXT): $(top_srcdir)/prism/internal/strpbrk.h
+zjit.$(OBJEXT): $(top_srcdir)/prism/json.h
+zjit.$(OBJEXT): $(top_srcdir)/prism/line_offset_list.h
+zjit.$(OBJEXT): $(top_srcdir)/prism/magic_comments.h
zjit.$(OBJEXT): $(top_srcdir)/prism/node.h
zjit.$(OBJEXT): $(top_srcdir)/prism/options.h
-zjit.$(OBJEXT): $(top_srcdir)/prism/pack.h
zjit.$(OBJEXT): $(top_srcdir)/prism/parser.h
zjit.$(OBJEXT): $(top_srcdir)/prism/prettyprint.h
zjit.$(OBJEXT): $(top_srcdir)/prism/prism.h
-zjit.$(OBJEXT): $(top_srcdir)/prism/regexp.h
-zjit.$(OBJEXT): $(top_srcdir)/prism/static_literals.h
-zjit.$(OBJEXT): $(top_srcdir)/prism/util/pm_buffer.h
-zjit.$(OBJEXT): $(top_srcdir)/prism/util/pm_char.h
-zjit.$(OBJEXT): $(top_srcdir)/prism/util/pm_constant_pool.h
-zjit.$(OBJEXT): $(top_srcdir)/prism/util/pm_integer.h
-zjit.$(OBJEXT): $(top_srcdir)/prism/util/pm_list.h
-zjit.$(OBJEXT): $(top_srcdir)/prism/util/pm_memchr.h
-zjit.$(OBJEXT): $(top_srcdir)/prism/util/pm_newline_list.h
-zjit.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h
-zjit.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.h
-zjit.$(OBJEXT): $(top_srcdir)/prism/util/pm_strpbrk.h
+zjit.$(OBJEXT): $(top_srcdir)/prism/serialize.h
+zjit.$(OBJEXT): $(top_srcdir)/prism/source.h
+zjit.$(OBJEXT): $(top_srcdir)/prism/stream.h
+zjit.$(OBJEXT): $(top_srcdir)/prism/string_query.h
+zjit.$(OBJEXT): $(top_srcdir)/prism/stringy.h
zjit.$(OBJEXT): $(top_srcdir)/prism/version.h
zjit.$(OBJEXT): {$(VPATH)}assert.h
zjit.$(OBJEXT): {$(VPATH)}atomic.h
@@ -20253,6 +21527,7 @@ zjit.$(OBJEXT): {$(VPATH)}constant.h
zjit.$(OBJEXT): {$(VPATH)}debug.h
zjit.$(OBJEXT): {$(VPATH)}debug_counter.h
zjit.$(OBJEXT): {$(VPATH)}defines.h
+zjit.$(OBJEXT): {$(VPATH)}encindex.h
zjit.$(OBJEXT): {$(VPATH)}encoding.h
zjit.$(OBJEXT): {$(VPATH)}id.h
zjit.$(OBJEXT): {$(VPATH)}id_table.h
@@ -20384,6 +21659,7 @@ zjit.$(OBJEXT): {$(VPATH)}internal/intern/re.h
zjit.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
zjit.$(OBJEXT): {$(VPATH)}internal/intern/select.h
zjit.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
+zjit.$(OBJEXT): {$(VPATH)}internal/intern/set.h
zjit.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
zjit.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
zjit.$(OBJEXT): {$(VPATH)}internal/intern/string.h
@@ -20418,6 +21694,7 @@ zjit.$(OBJEXT): {$(VPATH)}node.h
zjit.$(OBJEXT): {$(VPATH)}onigmo.h
zjit.$(OBJEXT): {$(VPATH)}oniguruma.h
zjit.$(OBJEXT): {$(VPATH)}prism_compile.h
+zjit.$(OBJEXT): {$(VPATH)}prism_xallocator.h
zjit.$(OBJEXT): {$(VPATH)}probes.dmyh
zjit.$(OBJEXT): {$(VPATH)}probes.h
zjit.$(OBJEXT): {$(VPATH)}probes_helper.h
@@ -20435,6 +21712,7 @@ zjit.$(OBJEXT): {$(VPATH)}vm_debug.h
zjit.$(OBJEXT): {$(VPATH)}vm_insnhelper.h
zjit.$(OBJEXT): {$(VPATH)}vm_opts.h
zjit.$(OBJEXT): {$(VPATH)}vm_sync.h
+zjit.$(OBJEXT): {$(VPATH)}yjit.h
zjit.$(OBJEXT): {$(VPATH)}zjit.c
zjit.$(OBJEXT): {$(VPATH)}zjit.h
zjit.$(OBJEXT): {$(VPATH)}zjit.rbinc
diff --git a/dir.c b/dir.c
index b934f2795c..9f2d36b633 100644
--- a/dir.c
+++ b/dir.c
@@ -504,6 +504,20 @@ fnmatch(
}
VALUE rb_cDir;
+static VALUE sym_directory, sym_link, sym_file, sym_unknown;
+
+#if defined(DT_BLK) || defined(S_IFBLK)
+static VALUE sym_block_device;
+#endif
+#if defined(DT_CHR) || defined(S_IFCHR)
+static VALUE sym_character_device;
+#endif
+#if defined(DT_FIFO) || defined(S_IFIFO)
+static VALUE sym_fifo;
+#endif
+#if defined(DT_SOCK) || defined(S_IFSOCK)
+static VALUE sym_socket;
+#endif
struct dir_data {
DIR *dir;
@@ -905,14 +919,109 @@ dir_read(VALUE dir)
}
}
-static VALUE dir_each_entry(VALUE, VALUE (*)(VALUE, VALUE), VALUE, int);
+struct dir_entry_args {
+ struct dir_data *dirp;
+ struct dirent *dp;
+};
+
+static VALUE dir_each_entry(VALUE, VALUE (*)(VALUE, VALUE, struct dir_entry_args *), VALUE, int);
static VALUE
-dir_yield(VALUE arg, VALUE path)
+dir_yield(VALUE arg, VALUE path, struct dir_entry_args *_unused)
{
return rb_yield(path);
}
+static int do_lstat(int fd, const char *path, struct stat *pst, int flags, rb_encoding *enc);
+
+static VALUE
+dir_yield_with_type(VALUE arg, VALUE path, struct dir_entry_args *dir_entry)
+{
+ VALUE type;
+ switch (dir_entry->dp->d_type) {
+#ifdef DT_BLK
+ case DT_BLK:
+ type = sym_block_device;
+ break;
+#endif
+#ifdef DT_CHR
+ case DT_CHR:
+ type = sym_character_device;
+ break;
+#endif
+ case DT_DIR:
+ type = sym_directory;
+ break;
+#ifdef DT_FIFO
+ case DT_FIFO:
+ type = sym_fifo;
+ break;
+#endif
+ case DT_LNK:
+ type = sym_link;
+ break;
+ case DT_REG:
+ type = sym_file;
+ break;
+#ifdef DT_SOCK
+ case DT_SOCK:
+ type = sym_socket;
+ break;
+#endif
+ default:
+ type = sym_unknown;
+ break;
+ }
+
+#ifdef HAVE_DIRFD
+ if (RUBY_DEBUG || RB_UNLIKELY(type == sym_unknown)) {
+ struct stat st;
+ if (do_lstat(dirfd(dir_entry->dirp->dir), dir_entry->dp->d_name, &st, 0, rb_filesystem_encoding()) == 0) {
+ switch (st.st_mode & S_IFMT) {
+ case S_IFDIR:
+ type = sym_directory;
+ break;
+ case S_IFLNK:
+ type = sym_link;
+ break;
+ case S_IFREG:
+ type = sym_file;
+ break;
+#ifdef S_IFSOCK
+ case S_IFSOCK:
+ type = sym_socket;
+ break;
+#endif
+#ifdef S_IFIFO
+ case S_IFIFO:
+ type = sym_fifo;
+ break;
+#endif
+#ifdef S_IFBLK
+ case S_IFBLK:
+ type = sym_block_device;
+ break;
+#endif
+#ifdef S_IFCHR
+ case S_IFCHR:
+ type = sym_character_device;
+ break;
+#endif
+ default:
+ break;
+ }
+ }
+ }
+#endif // HAVE_DIRFD
+
+ if (NIL_P(arg)) {
+ return rb_yield_values(2, path, type);
+ }
+ else {
+ return rb_ary_push(arg, rb_assoc_new(path, type));
+ }
+}
+
/*
* call-seq:
* each {|entry_name| ... } -> self
@@ -940,7 +1049,7 @@ dir_each(VALUE dir)
}
static VALUE
-dir_each_entry(VALUE dir, VALUE (*each)(VALUE, VALUE), VALUE arg, int children_only)
+dir_each_entry(VALUE dir, VALUE (*each)(VALUE, VALUE, struct dir_entry_args *), VALUE arg, int children_only)
{
struct dir_data *dirp;
struct dirent *dp;
@@ -966,7 +1075,11 @@ dir_each_entry(VALUE dir, VALUE (*each)(VALUE, VALUE), VALUE arg, int children_o
else
#endif
path = rb_external_str_new_with_enc(name, namlen, dirp->enc);
- (*each)(arg, path);
+ struct dir_entry_args each_args = {
+ .dirp = dirp,
+ .dp = dp,
+ };
+ (*each)(arg, path, &each_args);
}
return dir;
}
@@ -1472,24 +1585,55 @@ dir_chdir(VALUE dir)
#endif
}
+static VALUE last_cwd;
+
#ifndef _WIN32
+static VALUE
+getcwd_to_str(VALUE arg)
+{
+ const char *path = (const char *)arg;
+#ifdef __APPLE__
+ return rb_str_normalize_ospath(path, strlen(path));
+#else
+ return rb_str_new2(path);
+#endif
+}
+
+static VALUE
+getcwd_xfree(VALUE arg)
+{
+ xfree((void *)arg);
+ return Qnil;
+}
+
+static VALUE
+rb_dir_getwd_ospath_slowpath(void)
+{
+ char *path = ruby_getcwd();
+ return rb_ensure(getcwd_to_str, (VALUE)path, getcwd_xfree, (VALUE)path);
+}
+
VALUE
rb_dir_getwd_ospath(void)
{
- char *path;
- VALUE cwd;
- VALUE path_guard;
+ char buf[PATH_MAX];
+ char *path = getcwd(buf, PATH_MAX);
+ if (!path) {
+ return rb_dir_getwd_ospath_slowpath();
+ }
+
+ VALUE cached_cwd = RUBY_ATOMIC_VALUE_LOAD(last_cwd);
- path_guard = rb_imemo_tmpbuf_auto_free_pointer();
- path = ruby_getcwd();
- rb_imemo_tmpbuf_set_ptr(path_guard, path);
+ if (!cached_cwd || strcmp(RSTRING_PTR(cached_cwd), path) != 0) {
#ifdef __APPLE__
- cwd = rb_str_normalize_ospath(path, strlen(path));
+ cached_cwd = rb_str_normalize_ospath(path, strlen(path));
#else
- cwd = rb_str_new2(path);
+ cached_cwd = rb_str_new2(path);
#endif
- rb_free_tmp_buffer(&path_guard);
- return cwd;
+ rb_str_freeze(cached_cwd);
+ RUBY_ATOMIC_VALUE_SET(last_cwd, cached_cwd);
+ }
+ return cached_cwd;
}
#endif
@@ -1498,7 +1642,7 @@ rb_dir_getwd(void)
{
rb_encoding *fs = rb_filesystem_encoding();
int fsenc = rb_enc_to_index(fs);
- VALUE cwd = rb_dir_getwd_ospath();
+ VALUE cwd = rb_str_new_shared(rb_dir_getwd_ospath());
switch (fsenc) {
case ENCINDEX_US_ASCII:
@@ -1804,7 +1948,7 @@ nogvl_stat(void *args)
/* System call with warning */
static int
-do_stat(int fd, size_t baselen, const char *path, struct stat *pst, int flags, rb_encoding *enc)
+do_stat(int fd, const char *path, struct stat *pst, int flags, rb_encoding *enc)
{
#if USE_OPENDIR_AT
struct fstatat_args args;
@@ -1836,7 +1980,7 @@ nogvl_lstat(void *args)
#endif
static int
-do_lstat(int fd, size_t baselen, const char *path, struct stat *pst, int flags, rb_encoding *enc)
+do_lstat(int fd, const char *path, struct stat *pst, int flags, rb_encoding *enc)
{
#if USE_OPENDIR_AT
struct fstatat_args args;
@@ -2659,8 +2803,10 @@ glob_opendir(ruby_glob_entries_t *ent, DIR *dirp, int flags, rb_encoding *enc)
}
if (count >= capacity) {
capacity += 256;
- if (!(newp = GLOB_REALLOC_N(ent->sort.entries, capacity)))
+ if (!(newp = GLOB_REALLOC_N(ent->sort.entries, capacity))) {
+ GLOB_FREE(rdp);
goto nomem;
+ }
ent->sort.entries = newp;
}
ent->sort.entries[count++] = rdp;
@@ -2779,7 +2925,7 @@ glob_helper(
if (*path) {
if (match_all && pathtype == path_unknown) {
- if (do_lstat(fd, baselen, path, &st, flags, enc) == 0) {
+ if (do_lstat(fd, path, &st, flags, enc) == 0) {
pathtype = IFTODT(st.st_mode);
}
else {
@@ -2787,7 +2933,7 @@ glob_helper(
}
}
if (match_dir && (pathtype == path_unknown || pathtype == path_symlink)) {
- if (do_stat(fd, baselen, path, &st, flags, enc) == 0) {
+ if (do_stat(fd, path, &st, flags, enc) == 0) {
pathtype = IFTODT(st.st_mode);
}
else {
@@ -2915,7 +3061,7 @@ glob_helper(
if (recursive && dotfile < ((flags & FNM_DOTMATCH) ? 2 : 1) &&
new_pathtype == path_unknown) {
/* RECURSIVE never match dot files unless FNM_DOTMATCH is set */
- if (do_lstat(fd, baselen, buf, &st, flags, enc) == 0)
+ if (do_lstat(fd, buf, &st, flags, enc) == 0)
new_pathtype = IFTODT(st.st_mode);
else
new_pathtype = path_noent;
@@ -3471,10 +3617,16 @@ dir_foreach(int argc, VALUE *argv, VALUE io)
}
static VALUE
+dir_entry_ary_push(VALUE ary, VALUE entry, struct dir_entry_args *_unused)
+{
+ return rb_ary_push(ary, entry);
+}
+
+static VALUE
dir_collect(VALUE dir)
{
VALUE ary = rb_ary_new();
- dir_each_entry(dir, rb_ary_push, ary, FALSE);
+ dir_each_entry(dir, dir_entry_ary_push, ary, FALSE);
return ary;
}
@@ -3569,12 +3721,37 @@ static VALUE
dir_collect_children(VALUE dir)
{
VALUE ary = rb_ary_new();
- dir_each_entry(dir, rb_ary_push, ary, TRUE);
+ dir_each_entry(dir, dir_entry_ary_push, ary, TRUE);
return ary;
}
/*
* call-seq:
+ * children -> array
+ *
+ * Returns an array of the entry names in +self+ along with their type
+ * except for <tt>'.'</tt> and <tt>'..'</tt>:
+ *
+ * dir = Dir.new('/example')
+ * dir.scan # => [["config.h", :file], ["lib", :directory], ["main.rb", :file]]
+ *
+ */
+static VALUE
+dir_scan_children(VALUE dir)
+{
+ if (rb_block_given_p()) {
+ dir_each_entry(dir, dir_yield_with_type, Qnil, TRUE);
+ return Qnil;
+ }
+ else {
+ VALUE ary = rb_ary_new();
+ dir_each_entry(dir, dir_yield_with_type, ary, TRUE);
+ return ary;
+ }
+}
+
+/*
+ * call-seq:
* Dir.children(dirpath) -> array
* Dir.children(dirpath, encoding: 'UTF-8') -> array
*
@@ -3601,6 +3778,40 @@ dir_s_children(int argc, VALUE *argv, VALUE io)
return rb_ensure(dir_collect_children, dir, dir_close, dir);
}
+/*
+ * call-seq:
+ * Dir.scan(dirpath) {|entry_name, entry_type| ... } -> nil
+ * Dir.scan(dirpath, encoding: 'UTF-8') {|entry_name, entry_type| ... } -> nil
+ * Dir.scan(dirpath) -> [[entry_name, entry_type], ...]
+ * Dir.scan(dirpath, encoding: 'UTF-8') -> [[entry_name, entry_type], ...]
+ *
+ * Yields or returns an array of the entry names in the directory at +dirpath+
+ * associated with their type, except for <tt>'.'</tt> and <tt>'..'</tt>;
+ * sets the given encoding onto each returned entry name.
+ *
+ * The type symbol is one of:
+ * ``<code>:file</code>'', ``<code>:directory</code>'',
+ * ``<code>:characterSpecial</code>'', ``<code>:blockSpecial</code>'',
+ * ``<code>:fifo</code>'', ``<code>:link</code>'',
+ * or ``<code>:socket</code>'':
+ *
+ * Dir.children('/example') # => [["config.h", :file], ["lib", :directory], ["main.rb", :file]]
+ * Dir.children('/example').first.first.encoding
+ * # => #<Encoding:UTF-8>
+ * Dir.children('/example', encoding: 'US-ASCII').first.encoding
+ * # => #<Encoding:US-ASCII>
+ *
+ * See {String Encoding}[rdoc-ref:encodings.rdoc@String+Encoding].
+ *
+ * Raises an exception if the directory does not exist.
+ */
+static VALUE
+dir_s_scan(int argc, VALUE *argv, VALUE klass)
+{
+ VALUE dir = dir_open_dir(argc, argv);
+ return rb_ensure(dir_scan_children, dir, dir_close, dir);
+}
+
static int
fnmatch_brace(const char *pattern, VALUE val, void *enc)
{
@@ -3804,8 +4015,27 @@ rb_dir_s_empty_p(VALUE obj, VALUE dirname)
void
Init_Dir(void)
{
+ sym_directory = ID2SYM(rb_intern("directory"));
+ sym_link = ID2SYM(rb_intern("link"));
+ sym_file = ID2SYM(rb_intern("file"));
+ sym_unknown = ID2SYM(rb_intern("unknown"));
+
+#if defined(DT_BLK) || defined(S_IFBLK)
+ sym_block_device = ID2SYM(rb_intern("blockSpecial"));
+#endif
+#if defined(DT_CHR) || defined(S_IFCHR)
+ sym_character_device = ID2SYM(rb_intern("characterSpecial"));
+#endif
+#if defined(DT_FIFO) || defined(S_IFIFO)
+ sym_fifo = ID2SYM(rb_intern("fifo"));
+#endif
+#if defined(DT_SOCK) || defined(S_IFSOCK)
+ sym_socket = ID2SYM(rb_intern("socket"));
+#endif
+
rb_gc_register_address(&chdir_lock.path);
rb_gc_register_address(&chdir_lock.thread);
+ rb_gc_register_address(&last_cwd);
rb_cDir = rb_define_class("Dir", rb_cObject);
@@ -3817,6 +4047,7 @@ Init_Dir(void)
rb_define_singleton_method(rb_cDir, "entries", dir_entries, -1);
rb_define_singleton_method(rb_cDir, "each_child", dir_s_each_child, -1);
rb_define_singleton_method(rb_cDir, "children", dir_s_children, -1);
+ rb_define_singleton_method(rb_cDir, "scan", dir_s_scan, -1);
rb_define_method(rb_cDir,"fileno", dir_fileno, 0);
rb_define_method(rb_cDir,"path", dir_path, 0);
@@ -3826,6 +4057,7 @@ Init_Dir(void)
rb_define_method(rb_cDir,"each", dir_each, 0);
rb_define_method(rb_cDir,"each_child", dir_each_child_m, 0);
rb_define_method(rb_cDir,"children", dir_collect_children, 0);
+ rb_define_method(rb_cDir,"scan", dir_scan_children, 0);
rb_define_method(rb_cDir,"rewind", dir_rewind, 0);
rb_define_method(rb_cDir,"tell", dir_tell, 0);
rb_define_method(rb_cDir,"seek", dir_seek, 1);
diff --git a/dir.rb b/dir.rb
index a05bd18630..9b83f68822 100644
--- a/dir.rb
+++ b/dir.rb
@@ -31,7 +31,7 @@
# 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].
+# - It includes {module Enumerable}[rdoc-ref:Enumerable@Whats+Here].
#
# == \Dir As Stream-Like
#
@@ -85,8 +85,8 @@
#
# First, what's elsewhere. Class \Dir:
#
-# - Inherits from {class Object}[rdoc-ref:Object@What-27s+Here].
-# - Includes {module Enumerable}[rdoc-ref:Enumerable@What-27s+Here],
+# - Inherits from {class Object}[rdoc-ref:Object@Whats+Here].
+# - Includes {module Enumerable}[rdoc-ref:Enumerable@Whats+Here],
# which provides dozens of additional methods.
#
# Here, class \Dir provides methods that are useful for:
@@ -178,7 +178,7 @@ class Dir
# 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('.', encoding: Encoding::US_ASCII).read.encoding # => #<Encoding:US-ASCII>
#
def self.open(name, encoding: nil, &block)
dir = Primitive.dir_s_open(name, encoding)
@@ -206,7 +206,7 @@ class Dir
# 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>
+ # Dir.new('.', encoding: Encoding::US_ASCI).read.encoding # => #<Encoding:US-ASCII>
#
def initialize(name, encoding: nil)
Primitive.dir_initialize(name, encoding)
@@ -319,14 +319,14 @@ class Dir
#
# Dir.glob('io.?') # => ["io.c"]
#
- # - <tt>'[_set_]'</tt>: Matches any one character in the string _set_;
+ # - <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>:
+ # - <tt>'{abc,xyz}'</tt>:
# Matches either string _abc_ or string _xyz_;
# behaves like {Regexp alternation}[rdoc-ref:Regexp@Alternation]:
#
@@ -388,10 +388,10 @@ class Dir
#
# - File::FNM_EXTGLOB:
# enables the pattern extension
- # <tt>'{_a_,_b_}'</tt>, which matches pattern _a_ and pattern _b_;
+ # <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>):
+ # (e.g., <tt>'(?:a|b)'</tt>):
#
# pattern = '{LEGAL,BSDL}'
# Dir.glob(pattern) # => ["LEGAL", "BSDL"]
diff --git a/dln.c b/dln.c
index 5f6b1f0564..d3b03e3e87 100644
--- a/dln.c
+++ b/dln.c
@@ -25,8 +25,8 @@ static void dln_loaderror(const char *format, ...);
#endif
#include "dln.h"
#include "internal.h"
+#include "internal/box.h"
#include "internal/compilers.h"
-#include "internal/namespace.h"
#ifdef HAVE_STDLIB_H
# include <stdlib.h>
@@ -77,6 +77,10 @@ void *xrealloc();
# include <unistd.h>
#endif
+#ifndef UNREACHABLE_RETURN
+# define UNREACHABLE_RETURN(x) return (x)
+#endif
+
#ifndef dln_loaderror
static void
dln_loaderror(const char *format, ...)
@@ -348,6 +352,7 @@ dln_open(const char *file)
void *handle;
#if defined(_WIN32)
+# define DLN_DEFINED
char message[1024];
/* Convert the file path to wide char */
@@ -374,6 +379,7 @@ dln_open(const char *file)
# endif
#elif defined(USE_DLN_DLOPEN)
+# define DLN_DEFINED
# ifndef RTLD_LAZY
# define RTLD_LAZY 1
@@ -389,7 +395,7 @@ dln_open(const char *file)
# endif
/* Load file */
- int mode = rb_namespace_available() ? RTLD_LAZY|RTLD_LOCAL : RTLD_LAZY|RTLD_GLOBAL;
+ int mode = rb_box_available() ? RTLD_LAZY|RTLD_LOCAL : RTLD_LAZY|RTLD_GLOBAL;
handle = dlopen(file, mode);
if (handle == NULL) {
error = dln_strerror();
@@ -505,7 +511,7 @@ abi_check_enabled_p(void)
static void *
dln_load_and_init(const char *file, const char *init_fct_name)
{
-#if defined(_WIN32) || defined(USE_DLN_DLOPEN)
+#if defined(DLN_DEFINED)
void *handle = dln_open(file);
#ifdef RUBY_DLN_CHECK_ABI
@@ -523,6 +529,7 @@ dln_load_and_init(const char *file, const char *init_fct_name)
return handle;
#elif defined(_AIX)
+# define DLN_DEFINED
{
void (*init_fct)(void);
@@ -539,33 +546,25 @@ dln_load_and_init(const char *file, const char *init_fct_name)
}
#else
dln_notimplement();
+ UNREACHABLE_RETURN(0);
#endif
-
- return 0; /* dummy return */
}
void *
dln_load(const char *file)
{
-#if defined(_WIN32) || defined(USE_DLN_DLOPEN)
- char *init_fct_name;
- init_funcname(&init_fct_name, file);
- return dln_load_and_init(file, init_fct_name);
-#else
- dln_notimplement();
- return 0;
-#endif
+ return dln_load_feature(file, file);
}
void *
dln_load_feature(const char *file, const char *fname)
{
-#if defined(_WIN32) || defined(USE_DLN_DLOPEN)
+#if defined(DLN_DEFINED)
char *init_fct_name;
init_funcname(&init_fct_name, fname);
return dln_load_and_init(file, init_fct_name);
#else
dln_notimplement();
- return 0;
+ UNREACHABLE_RETURN(0);
#endif
}
diff --git a/doc/.document b/doc/.document
index 6e6caa8333..337289a662 100644
--- a/doc/.document
+++ b/doc/.document
@@ -1,12 +1,14 @@
-*.md
-*.rb
+[^_]*.md
+[^_]*.rb
[^_]*.rdoc
contributing
+distribution
NEWS
syntax
optparse
-date
-rdoc
-regexp
-yjit
-ruby
+jit
+security
+language
+strscan
+file
+
diff --git a/doc/NEWS/NEWS-4.0.0.md b/doc/NEWS/NEWS-4.0.0.md
new file mode 100644
index 0000000000..5d932fbf5d
--- /dev/null
+++ b/doc/NEWS/NEWS-4.0.0.md
@@ -0,0 +1,802 @@
+# NEWS for Ruby 4.0.0
+
+This document is a list of user-visible feature changes
+since the **3.4.0** release, except for bug fixes.
+
+Note that each entry is kept to a minimum, see links for details.
+
+## Language changes
+
+* `*nil` no longer calls `nil.to_a`, similar to how `**nil` does
+ not call `nil.to_hash`. [[Feature #21047]]
+
+* Logical binary operators (`||`, `&&`, `and` and `or`) at the
+ beginning of a line continue the previous line, like fluent dot.
+ The following code examples are equal:
+
+ ```ruby
+ if condition1
+ && condition2
+ ...
+ end
+ ```
+
+ Previously:
+
+ ```ruby
+ if condition1 && condition2
+ ...
+ end
+ ```
+
+ ```ruby
+ if condition1 &&
+ condition2
+ ...
+ end
+ ```
+
+ [[Feature #20925]]
+
+## Core classes updates
+
+Note: We're only listing outstanding class updates.
+
+* Array
+
+ * `Array#rfind` has been added as a more efficient alternative to `array.reverse_each.find` [[Feature #21678]]
+ * `Array#find` has been added as a more efficient override of `Enumerable#find` [[Feature #21678]]
+* Binding
+
+ * `Binding#local_variables` does no longer include numbered parameters.
+ Also, `Binding#local_variable_get`, `Binding#local_variable_set`, and
+ `Binding#local_variable_defined?` reject to handle numbered parameters.
+ [[Bug #21049]]
+
+ * `Binding#implicit_parameters`, `Binding#implicit_parameter_get`, and
+ `Binding#implicit_parameter_defined?` have been added to access
+ numbered parameters and "it" parameter. [[Bug #21049]]
+
+* Enumerator
+
+ * `Enumerator.produce` now accepts an optional `size` keyword argument
+ to specify the size of the enumerator. It can be an integer,
+ `Float::INFINITY`, a callable object (such as a lambda), or `nil` to
+ indicate unknown size. When not specified, the size defaults to
+ `Float::INFINITY`.
+
+ ```ruby
+ # Infinite enumerator
+ enum = Enumerator.produce(1, size: Float::INFINITY, &:succ)
+ enum.size # => Float::INFINITY
+
+ # Finite enumerator with known/computable size
+ abs_dir = File.expand_path("./baz") # => "/foo/bar/baz"
+ traverser = Enumerator.produce(abs_dir, size: -> { abs_dir.count("/") + 1 }) {
+ raise StopIteration if it == "/"
+ File.dirname(it)
+ }
+ traverser.size # => 4
+ ```
+
+ [[Feature #21701]]
+
+* ErrorHighlight
+
+ * When an ArgumentError is raised, it now displays code snippets for
+ both the method call (caller) and the method definition (callee).
+ [[Feature #21543]]
+
+ ```
+ test.rb:1:in 'Object#add': wrong number of arguments (given 1, expected 2) (ArgumentError)
+
+ caller: test.rb:3
+ | add(1)
+ ^^^
+ callee: test.rb:1
+ | def add(x, y) = x + y
+ ^^^
+ from test.rb:3:in '<main>'
+ ```
+
+* Fiber
+
+ * Introduce support for `Fiber#raise(cause:)` argument similar to
+ `Kernel#raise`. [[Feature #21360]]
+
+* Fiber::Scheduler
+
+ * Introduce `Fiber::Scheduler#fiber_interrupt` to interrupt a fiber with a
+ given exception. The initial use case is to interrupt a fiber that is
+ waiting on a blocking IO operation when the IO operation is closed.
+ [[Feature #21166]]
+
+ * Introduce `Fiber::Scheduler#yield` to allow the fiber scheduler to
+ continue processing when signal exceptions are disabled.
+ [[Bug #21633]]
+
+ * Reintroduce the `Fiber::Scheduler#io_close` hook for asynchronous `IO#close`.
+
+ * Invoke `Fiber::Scheduler#io_write` when flushing the IO write buffer.
+ [[Bug #21789]]
+
+* File
+
+ * `File::Stat#birthtime` is now available on Linux via the statx
+ system call when supported by the kernel and filesystem.
+ [[Feature #21205]]
+
+* IO
+
+ * `IO.select` accepts `Float::INFINITY` as a timeout argument.
+ [[Feature #20610]]
+
+ * A deprecated behavior, process creation by `IO` class methods
+ with a leading `|`, was removed. [[Feature #19630]]
+
+* Kernel
+
+ * `Kernel#inspect` now checks for the existence of a `#instance_variables_to_inspect` method,
+ allowing control over which instance variables are displayed in the `#inspect` string:
+
+ ```ruby
+ class DatabaseConfig
+ def initialize(host, user, password)
+ @host = host
+ @user = user
+ @password = password
+ end
+
+ private def instance_variables_to_inspect = [:@host, :@user]
+ end
+
+ conf = DatabaseConfig.new("localhost", "root", "hunter2")
+ conf.inspect #=> #<DatabaseConfig:0x0000000104def350 @host="localhost", @user="root">
+ ```
+
+ [[Feature #21219]]
+
+ * A deprecated behavior, process creation by `Kernel#open` with a
+ leading `|`, was removed. [[Feature #19630]]
+
+* Math
+
+ * `Math.log1p` and `Math.expm1` are added. [[Feature #21527]]
+
+* Pathname
+
+ * Pathname has been promoted from a default gem to a core class of Ruby.
+ [[Feature #17473]]
+
+* Proc
+
+ * `Proc#parameters` now shows anonymous optional parameters as `[:opt]`
+ instead of `[:opt, nil]`, making the output consistent with when the
+ anonymous parameter is required. [[Bug #20974]]
+
+* Ractor
+
+ * `Ractor::Port` class was added for a new synchronization mechanism
+ to communicate between Ractors. [[Feature #21262]]
+
+ ```ruby
+ port1 = Ractor::Port.new
+ port2 = Ractor::Port.new
+ Ractor.new port1, port2 do |port1, port2|
+ port1 << 1
+ port2 << 11
+ port1 << 2
+ port2 << 12
+ end
+ 2.times{ p port1.receive } #=> 1, 2
+ 2.times{ p port2.receive } #=> 11, 12
+ ```
+
+ `Ractor::Port` provides the following methods:
+
+ * `Ractor::Port#receive`
+ * `Ractor::Port#send` (or `Ractor::Port#<<`)
+ * `Ractor::Port#close`
+ * `Ractor::Port#closed?`
+
+ As a result, `Ractor.yield` and `Ractor#take` were removed.
+
+ * `Ractor#join` and `Ractor#value` were added to wait for the
+ termination of a Ractor. These are similar to `Thread#join`
+ and `Thread#value`.
+
+ * `Ractor#monitor` and `Ractor#unmonitor` were added as low-level
+ interfaces used internally to implement `Ractor#join`.
+
+ * `Ractor.select` now only accepts Ractors and Ports. If Ractors are given,
+ it returns when a Ractor terminates.
+
+ * `Ractor#default_port` was added. Each `Ractor` has a default port,
+ which is used by `Ractor.send`, `Ractor.receive`.
+
+ * `Ractor#close_incoming` and `Ractor#close_outgoing` were removed.
+
+ * `Ractor.shareable_proc` and `Ractor.shareable_lambda` are introduced
+ to make shareable Proc or lambda.
+ [[Feature #21550]], [[Feature #21557]]
+
+* Range
+
+ * `Range#to_set` now performs size checks to prevent issues with
+ endless ranges. [[Bug #21654]]
+
+ * `Range#overlap?` now correctly handles infinite (unbounded) ranges.
+ [[Bug #21185]]
+
+ * `Range#max` behavior on beginless integer ranges has been fixed.
+ [[Bug #21174]] [[Bug #21175]]
+
+* Ruby
+
+ * A new toplevel module `Ruby` has been defined, which contains
+ Ruby-related constants. This module was reserved in Ruby 3.4
+ and is now officially defined. [[Feature #20884]]
+
+* Ruby::Box
+
+ * A new (experimental) feature to provide separation about definitions.
+ For the detail of "Ruby Box", see [doc/language/box.md](doc/language/box.md).
+ [[Feature #21311]] [[Misc #21385]]
+
+* Set
+
+ * `Set` is now a core class, instead of an autoloaded stdlib class.
+ [[Feature #21216]]
+
+ * `Set#inspect` now uses a simpler display, similar to literal arrays.
+ (e.g., `Set[1, 2, 3]` instead of `#<Set: {1, 2, 3}>`). [[Feature #21389]]
+
+ * Passing arguments to `Set#to_set` and `Enumerable#to_set` is now deprecated.
+ [[Feature #21390]]
+
+* Socket
+
+ * `Socket.tcp` & `TCPSocket.new` accepts an `open_timeout` keyword argument to specify
+ the timeout for the initial connection. [[Feature #21347]]
+ * When a user-specified timeout occurred in `TCPSocket.new`, either `Errno::ETIMEDOUT`
+ or `IO::TimeoutError` could previously be raised depending on the situation.
+ This behavior has been unified so that `IO::TimeoutError` is now consistently raised.
+ (Please note that, in `Socket.tcp`, there are still cases where `Errno::ETIMEDOUT`
+ may be raised in similar situations, and that in both cases `Errno::ETIMEDOUT` may be
+ raised when the timeout occurs at the OS level.)
+
+* String
+
+ * Update Unicode to Version 17.0.0 and Emoji Version 17.0.
+ [[Feature #19908]][[Feature #20724]][[Feature #21275]] (also applies to Regexp)
+
+ * `String#strip`, `strip!`, `lstrip`, `lstrip!`, `rstrip`, and `rstrip!`
+ are extended to accept `*selectors` arguments. [[Feature #21552]]
+
+* Thread
+
+ * Introduce support for `Thread#raise(cause:)` argument similar to
+ `Kernel#raise`. [[Feature #21360]]
+
+## Stdlib updates
+
+We only list stdlib changes that are notable feature changes.
+
+Other changes are listed in the following sections. We also listed release
+history from the previous bundled version that is Ruby 3.4.0 if it has GitHub
+releases.
+
+The following bundled gems are promoted from default gems.
+
+* ostruct 0.6.3
+ * 0.6.1 to [v0.6.2][ostruct-v0.6.2], [v0.6.3][ostruct-v0.6.3]
+* pstore 0.2.0
+ * 0.1.4 to [v0.2.0][pstore-v0.2.0]
+* benchmark 0.5.0
+ * 0.4.0 to [v0.4.1][benchmark-v0.4.1], [v0.5.0][benchmark-v0.5.0]
+* logger 1.7.0
+ * 1.6.4 to [v1.6.5][logger-v1.6.5], [v1.6.6][logger-v1.6.6], [v1.7.0][logger-v1.7.0]
+* rdoc 7.0.3
+ * 6.14.0 to [v6.14.1][rdoc-v6.14.1], [v6.14.2][rdoc-v6.14.2], [v6.15.0][rdoc-v6.15.0], [v6.15.1][rdoc-v6.15.1], [v6.16.0][rdoc-v6.16.0], [v6.16.1][rdoc-v6.16.1], [v6.17.0][rdoc-v6.17.0], [v7.0.0][rdoc-v7.0.0], [v7.0.1][rdoc-v7.0.1], [v7.0.2][rdoc-v7.0.2], [v7.0.3][rdoc-v7.0.3]
+* win32ole 1.9.2
+ * 1.9.1 to [v1.9.2][win32ole-v1.9.2]
+* irb 1.16.0
+ * 1.14.3 to [v1.15.0][irb-v1.15.0], [v1.15.1][irb-v1.15.1], [v1.15.2][irb-v1.15.2], [v1.15.3][irb-v1.15.3], [v1.16.0][irb-v1.16.0]
+* reline 0.6.3
+ * 0.6.0 to [v0.6.1][reline-v0.6.1], [v0.6.2][reline-v0.6.2], [v0.6.3][reline-v0.6.3]
+* readline 0.0.4
+* fiddle 1.1.8
+ * 1.1.6 to [v1.1.7][fiddle-v1.1.7], [v1.1.8][fiddle-v1.1.8]
+
+The following default gem is added.
+
+* win32-registry 0.1.2
+
+The following default gems are updated.
+
+* RubyGems 4.0.3
+* bundler 4.0.3
+* date 3.5.1
+ * 3.4.1 to [v3.5.0][date-v3.5.0], [v3.5.1][date-v3.5.1]
+* delegate 0.6.1
+ * 0.4.0 to [v0.5.0][delegate-v0.5.0], [v0.6.0][delegate-v0.6.0], [v0.6.1][delegate-v0.6.1]
+* digest 3.2.1
+ * 3.2.0 to [v3.2.1][digest-v3.2.1]
+* english 0.8.1
+ * 0.8.0 to [v0.8.1][english-v0.8.1]
+* erb 6.0.1
+ * 4.0.4 to [v5.1.2][erb-v5.1.2], [v5.1.3][erb-v5.1.3], [v6.0.0][erb-v6.0.0], [v6.0.1][erb-v6.0.1]
+* error_highlight 0.7.1
+* etc 1.4.6
+* fcntl 1.3.0
+ * 1.2.0 to [v1.3.0][fcntl-v1.3.0]
+* fileutils 1.8.0
+ * 1.7.3 to [v1.8.0][fileutils-v1.8.0]
+* forwardable 1.4.0
+ * 1.3.3 to [v1.4.0][forwardable-v1.4.0]
+* io-console 0.8.2
+ * 0.8.1 to [v0.8.2][io-console-v0.8.2]
+* io-nonblock 0.3.2
+* io-wait 0.4.0
+ * 0.3.2 to [v0.3.3][io-wait-v0.3.3], [v0.3.5.test1][io-wait-v0.3.5.test1], [v0.3.5][io-wait-v0.3.5], [v0.3.6][io-wait-v0.3.6], [v0.4.0][io-wait-v0.4.0]
+* ipaddr 1.2.8
+* json 2.18.0
+ * 2.9.1 to [v2.10.0][json-v2.10.0], [v2.10.1][json-v2.10.1], [v2.10.2][json-v2.10.2], [v2.11.0][json-v2.11.0], [v2.11.1][json-v2.11.1], [v2.11.2][json-v2.11.2], [v2.11.3][json-v2.11.3], [v2.12.0][json-v2.12.0], [v2.12.1][json-v2.12.1], [v2.12.2][json-v2.12.2], [v2.13.0][json-v2.13.0], [v2.13.1][json-v2.13.1], [v2.13.2][json-v2.13.2], [v2.14.0][json-v2.14.0], [v2.14.1][json-v2.14.1], [v2.15.0][json-v2.15.0], [v2.15.1][json-v2.15.1], [v2.15.2][json-v2.15.2], [v2.16.0][json-v2.16.0], [v2.17.0][json-v2.17.0], [v2.17.1][json-v2.17.1], [v2.18.0][json-v2.18.0]
+* net-http 0.9.1
+ * 0.6.0 to [v0.7.0][net-http-v0.7.0], [v0.8.0][net-http-v0.8.0], [v0.9.0][net-http-v0.9.0], [v0.9.1][net-http-v0.9.1]
+* openssl 4.0.0
+ * 3.3.1 to [v3.3.2][openssl-v3.3.2], [v4.0.0][openssl-v4.0.0]
+* optparse 0.8.1
+ * 0.6.0 to [v0.7.0][optparse-v0.7.0], [v0.8.0][optparse-v0.8.0], [v0.8.1][optparse-v0.8.1]
+* pp 0.6.3
+ * 0.6.2 to [v0.6.3][pp-v0.6.3]
+* prism 1.7.0
+ * 1.5.2 to [v1.6.0][prism-v1.6.0], [v1.7.0][prism-v1.7.0]
+* psych 5.3.1
+ * 5.2.2 to [v5.2.3][psych-v5.2.3], [v5.2.4][psych-v5.2.4], [v5.2.5][psych-v5.2.5], [v5.2.6][psych-v5.2.6], [v5.3.0][psych-v5.3.0], [v5.3.1][psych-v5.3.1]
+* resolv 0.7.0
+ * 0.6.2 to [v0.6.3][resolv-v0.6.3], [v0.7.0][resolv-v0.7.0]
+* stringio 3.2.0
+ * 3.1.2 to [v3.1.3][stringio-v3.1.3], [v3.1.4][stringio-v3.1.4], [v3.1.5][stringio-v3.1.5], [v3.1.6][stringio-v3.1.6], [v3.1.7][stringio-v3.1.7], [v3.1.8][stringio-v3.1.8], [v3.1.9][stringio-v3.1.9], [v3.2.0][stringio-v3.2.0]
+* strscan 3.1.6
+ * 3.1.2 to [v3.1.3][strscan-v3.1.3], [v3.1.4][strscan-v3.1.4], [v3.1.5][strscan-v3.1.5], [v3.1.6][strscan-v3.1.6]
+* time 0.4.2
+ * 0.4.1 to [v0.4.2][time-v0.4.2]
+* timeout 0.6.0
+ * 0.4.3 to [v0.4.4][timeout-v0.4.4], [v0.5.0][timeout-v0.5.0], [v0.6.0][timeout-v0.6.0]
+* uri 1.1.1
+ * 1.0.4 to [v1.1.0][uri-v1.1.0], [v1.1.1][uri-v1.1.1]
+* weakref 0.1.4
+ * 0.1.3 to [v0.1.4][weakref-v0.1.4]
+* zlib 3.2.2
+ * 3.2.1 to [v3.2.2][zlib-v3.2.2]
+
+The following bundled gems are updated.
+
+* minitest 6.0.0
+* power_assert 3.0.1
+ * 2.0.5 to [v3.0.0][power_assert-v3.0.0], [v3.0.1][power_assert-v3.0.1]
+* rake 13.3.1
+ * 13.2.1 to [v13.3.0][rake-v13.3.0], [v13.3.1][rake-v13.3.1]
+* test-unit 3.7.5
+ * 3.6.7 to [3.6.8][test-unit-3.6.8], [3.6.9][test-unit-3.6.9], [3.7.0][test-unit-3.7.0], [3.7.1][test-unit-3.7.1], [3.7.2][test-unit-3.7.2], [3.7.3][test-unit-3.7.3], [3.7.4][test-unit-3.7.4], [3.7.5][test-unit-3.7.5]
+* rexml 3.4.4
+* rss 0.3.2
+ * 0.3.1 to [0.3.2][rss-0.3.2]
+* net-ftp 0.3.9
+ * 0.3.8 to [v0.3.9][net-ftp-v0.3.9]
+* net-imap 0.6.2
+ * 0.5.8 to [v0.5.9][net-imap-v0.5.9], [v0.5.10][net-imap-v0.5.10], [v0.5.11][net-imap-v0.5.11], [v0.5.12][net-imap-v0.5.12], [v0.5.13][net-imap-v0.5.13], [v0.6.0][net-imap-v0.6.0], [v0.6.1][net-imap-v0.6.1], [v0.6.2][net-imap-v0.6.2]
+* net-smtp 0.5.1
+ * 0.5.0 to [v0.5.1][net-smtp-v0.5.1]
+* matrix 0.4.3
+ * 0.4.2 to [v0.4.3][matrix-v0.4.3]
+* prime 0.1.4
+ * 0.1.3 to [v0.1.4][prime-v0.1.4]
+* rbs 3.10.0
+ * 3.8.0 to [v3.8.1][rbs-v3.8.1], [v3.9.0.dev.1][rbs-v3.9.0.dev.1], [v3.9.0.pre.1][rbs-v3.9.0.pre.1], [v3.9.0.pre.2][rbs-v3.9.0.pre.2], [v3.9.0][rbs-v3.9.0], [v3.9.1][rbs-v3.9.1], [v3.9.2][rbs-v3.9.2], [v3.9.3][rbs-v3.9.3], [v3.9.4][rbs-v3.9.4], [v3.9.5][rbs-v3.9.5], [v3.10.0.pre.1][rbs-v3.10.0.pre.1], [v3.10.0.pre.2][rbs-v3.10.0.pre.2], [v3.10.0][rbs-v3.10.0]
+* typeprof 0.31.1
+* debug 1.11.1
+ * 1.11.0 to [v1.11.1][debug-v1.11.1]
+* base64 0.3.0
+ * 0.2.0 to [v0.3.0][base64-v0.3.0]
+* bigdecimal 4.0.1
+ * 3.1.8 to [v3.2.0][bigdecimal-v3.2.0], [v3.2.1][bigdecimal-v3.2.1], [v3.2.2][bigdecimal-v3.2.2], [v3.2.3][bigdecimal-v3.2.3], [v3.3.0][bigdecimal-v3.3.0], [v3.3.1][bigdecimal-v3.3.1], [v4.0.0][bigdecimal-v4.0.0], [v4.0.1][bigdecimal-v4.0.1]
+* drb 2.2.3
+ * 2.2.1 to [v2.2.3][drb-v2.2.3]
+* syslog 0.3.0
+ * 0.2.0 to [v0.3.0][syslog-v0.3.0]
+* csv 3.3.5
+ * 3.3.2 to [v3.3.3][csv-v3.3.3], [v3.3.4][csv-v3.3.4], [v3.3.5][csv-v3.3.5]
+* repl_type_completor 0.1.12
+
+### RubyGems and Bundler
+
+Ruby 4.0 bundled RubyGems and Bundler version 4. see the following links for details.
+
+* [Upgrading to RubyGems/Bundler 4 - RubyGems Blog](https://blog.rubygems.org/2025/12/03/upgrade-to-rubygems-bundler-4.html)
+* [4.0.0 Released - RubyGems Blog](https://blog.rubygems.org/2025/12/03/4.0.0-released.html)
+* [4.0.1 Released - RubyGems Blog](https://blog.rubygems.org/2025/12/09/4.0.1-released.html)
+* [4.0.2 Released - RubyGems Blog](https://blog.rubygems.org/2025/12/17/4.0.2-released.html)
+* [4.0.3 Released - RubyGems Blog](https://blog.rubygems.org/2025/12/23/4.0.3-released.html)
+
+## Supported platforms
+
+* Windows
+
+ * Dropped support for MSVC versions older than 14.0 (_MSC_VER 1900).
+ This means Visual Studio 2015 or later is now required.
+
+## Compatibility issues
+
+* The following methods were removed from Ractor due to the addition of `Ractor::Port`:
+
+ * `Ractor.yield`
+ * `Ractor#take`
+ * `Ractor#close_incoming`
+ * `Ractor#close_outgoing`
+
+ [[Feature #21262]]
+
+* `ObjectSpace._id2ref` is deprecated. [[Feature #15408]]
+
+* `Process::Status#&` and `Process::Status#>>` have been removed.
+ They were deprecated in Ruby 3.3. [[Bug #19868]]
+
+* `rb_path_check` has been removed. This function was used for
+ `$SAFE` path checking which was removed in Ruby 2.7,
+ and was already deprecated.
+ [[Feature #20971]]
+
+* A backtrace for `ArgumentError` of "wrong number of arguments" now
+ include the receiver's class or module name (e.g., in `Foo#bar`
+ instead of in `bar`). [[Bug #21698]]
+
+* Backtraces no longer display `internal` frames.
+ These methods now appear as if it is in the Ruby source file,
+ consistent with other C-implemented methods. [[Bug #20968]]
+
+ Before:
+ ```
+ ruby -e '[1].fetch_values(42)'
+ <internal:array>:211:in 'Array#fetch': index 42 outside of array bounds: -1...1 (IndexError)
+ from <internal:array>:211:in 'block in Array#fetch_values'
+ from <internal:array>:211:in 'Array#map!'
+ from <internal:array>:211:in 'Array#fetch_values'
+ from -e:1:in '<main>'
+ ```
+
+ After:
+ ```
+ $ ruby -e '[1].fetch_values(42)'
+ -e:1:in 'Array#fetch_values': index 42 outside of array bounds: -1...1 (IndexError)
+ from -e:1:in '<main>'
+ ```
+
+## Stdlib compatibility issues
+
+* CGI library is removed from the default gems. Now we only provide `cgi/escape` for
+ the following methods:
+
+ * `CGI.escape` and `CGI.unescape`
+ * `CGI.escapeHTML` and `CGI.unescapeHTML`
+ * `CGI.escapeURIComponent` and `CGI.unescapeURIComponent`
+ * `CGI.escapeElement` and `CGI.unescapeElement`
+
+ [[Feature #21258]]
+
+* With the move of `Set` from stdlib to core class, `set/sorted_set.rb` has
+ been removed, and `SortedSet` is no longer an autoloaded constant. Please
+ install the `sorted_set` gem and `require 'sorted_set'` to use `SortedSet`.
+ [[Feature #21287]]
+
+* Net::HTTP
+
+ * The default behavior of automatically setting the `Content-Type` header
+ to `application/x-www-form-urlencoded` for requests with a body
+ (e.g., `POST`, `PUT`) when the header was not explicitly set has been
+ removed. If your application relied on this automatic default, your
+ requests will now be sent without a Content-Type header, potentially
+ breaking compatibility with certain servers.
+ [[GH-net-http #205]]
+
+## C API updates
+
+* IO
+
+ * `rb_thread_fd_close` is deprecated and now a no-op. If you need to expose
+ file descriptors from C extensions to Ruby code, create an `IO` instance
+ using `RUBY_IO_MODE_EXTERNAL` and use `rb_io_close(io)` to close it (this
+ also interrupts and waits for all pending operations on the `IO`
+ instance). Directly closing file descriptors does not interrupt pending
+ operations, and may lead to undefined behaviour. In other words, if two
+ `IO` objects share the same file descriptor, closing one does not affect
+ the other. [[Feature #18455]]
+
+* GVL
+
+ * `rb_thread_call_with_gvl` now works with or without the GVL.
+ This allows gems to avoid checking `ruby_thread_has_gvl_p`.
+ Please still be diligent about the GVL. [[Feature #20750]]
+
+* Set
+
+ * A C API for `Set` has been added. The following methods are supported:
+ [[Feature #21459]]
+
+ * `rb_set_foreach`
+ * `rb_set_new`
+ * `rb_set_new_capa`
+ * `rb_set_lookup`
+ * `rb_set_add`
+ * `rb_set_clear`
+ * `rb_set_delete`
+ * `rb_set_size`
+
+## Implementation improvements
+
+* `Class#new` (ex. `Object.new`) is faster in all cases, but especially when passing keyword arguments. This has also been integrated into YJIT and ZJIT. [[Feature #21254]]
+* GC heaps of different size pools now grow independently, reducing memory usage when only some pools contain long-lived objects
+* GC sweeping is faster on pages of large objects
+* "Generic ivar" objects (String, Array, `TypedData`, etc.) now use a new internal "fields" object for faster instance variable access
+* The GC avoids maintaining an internal `id2ref` table until it is first used, making `object_id` allocation and GC sweeping faster
+* `object_id` and `hash` are faster on Class and Module objects
+* Larger bignum Integers can remain embedded using variable width allocation
+* `Random`, `Enumerator::Product`, `Enumerator::Chain`, `Addrinfo`,
+ `StringScanner`, and some internal objects are now write-barrier protected,
+ which reduces GC overhead.
+
+### Ractor
+
+A lot of work has gone into making Ractors more stable, performant, and usable. These improvements bring Ractor implementation closer to leaving experimental status.
+
+* Performance improvements
+ * Frozen strings and the symbol table internally use a lock-free hash set [[Feature #21268]]
+ * Method cache lookups avoid locking in most cases
+ * Class (and generic ivar) instance variable access is faster and avoids locking
+ * CPU cache contention is avoided in object allocation by using a per-ractor counter
+ * CPU cache contention is avoided in xmalloc/xfree by using a thread-local counter
+ * `object_id` avoids locking in most cases
+* Bug fixes and stability
+ * Fixed possible deadlocks when combining Ractors and Threads
+ * Fixed issues with require and autoload in a Ractor
+ * Fixed encoding/transcoding issues across Ractors
+ * Fixed race conditions in GC operations and method invalidation
+ * Fixed issues with processes forking after starting a Ractor
+ * GC allocation counts are now accurate under Ractors
+ * Fixed TracePoints not working after GC [[Bug #19112]]
+
+## JIT
+
+* ZJIT
+ * Introduce an [experimental method-based JIT compiler](https://docs.ruby-lang.org/en/master/jit/zjit_md.html).
+ Where available, ZJIT can be enabled at runtime with the `--zjit` option or by calling `RubyVM::ZJIT.enable`.
+ When building Ruby, Rust 1.85.0 or later is required to include ZJIT support.
+ * As of Ruby 4.0.0, ZJIT is faster than the interpreter, but not yet as fast as YJIT.
+ We encourage experimentation with ZJIT, but advise against deploying it in production for now.
+ * Our goal is to make ZJIT faster than YJIT and production-ready in Ruby 4.1.
+* YJIT
+ * `RubyVM::YJIT.runtime_stats`
+ * `ratio_in_yjit` no longer works in the default build.
+ Use `--enable-yjit=stats` on `configure` to enable it on `--yjit-stats`.
+ * Add `invalidate_everything` to default stats, which is
+ incremented when every code is invalidated by TracePoint.
+ * Add `mem_size:` and `call_threshold:` options to `RubyVM::YJIT.enable`.
+* RJIT
+ * `--rjit` is removed. We will move the implementation of the third-party JIT API
+ to the [ruby/rjit](https://github.com/ruby/rjit) repository.
+
+[Feature #15408]: https://bugs.ruby-lang.org/issues/15408
+[Feature #17473]: https://bugs.ruby-lang.org/issues/17473
+[Feature #18455]: https://bugs.ruby-lang.org/issues/18455
+[Bug #19112]: https://bugs.ruby-lang.org/issues/19112
+[Feature #19630]: https://bugs.ruby-lang.org/issues/19630
+[Bug #19868]: https://bugs.ruby-lang.org/issues/19868
+[Feature #19908]: https://bugs.ruby-lang.org/issues/19908
+[Feature #20610]: https://bugs.ruby-lang.org/issues/20610
+[Feature #20724]: https://bugs.ruby-lang.org/issues/20724
+[Feature #20750]: https://bugs.ruby-lang.org/issues/20750
+[Feature #20884]: https://bugs.ruby-lang.org/issues/20884
+[Feature #20925]: https://bugs.ruby-lang.org/issues/20925
+[Bug #20968]: https://bugs.ruby-lang.org/issues/20968
+[Feature #20971]: https://bugs.ruby-lang.org/issues/20971
+[Bug #20974]: https://bugs.ruby-lang.org/issues/20974
+[Feature #21047]: https://bugs.ruby-lang.org/issues/21047
+[Bug #21049]: https://bugs.ruby-lang.org/issues/21049
+[Feature #21166]: https://bugs.ruby-lang.org/issues/21166
+[Bug #21174]: https://bugs.ruby-lang.org/issues/21174
+[Bug #21175]: https://bugs.ruby-lang.org/issues/21175
+[Bug #21185]: https://bugs.ruby-lang.org/issues/21185
+[Feature #21205]: https://bugs.ruby-lang.org/issues/21205
+[Feature #21216]: https://bugs.ruby-lang.org/issues/21216
+[Feature #21219]: https://bugs.ruby-lang.org/issues/21219
+[Feature #21254]: https://bugs.ruby-lang.org/issues/21254
+[Feature #21258]: https://bugs.ruby-lang.org/issues/21258
+[Feature #21268]: https://bugs.ruby-lang.org/issues/21268
+[Feature #21262]: https://bugs.ruby-lang.org/issues/21262
+[Feature #21275]: https://bugs.ruby-lang.org/issues/21275
+[Feature #21287]: https://bugs.ruby-lang.org/issues/21287
+[Feature #21311]: https://bugs.ruby-lang.org/issues/21311
+[Feature #21347]: https://bugs.ruby-lang.org/issues/21347
+[Feature #21360]: https://bugs.ruby-lang.org/issues/21360
+[Misc #21385]: https://bugs.ruby-lang.org/issues/21385
+[Feature #21389]: https://bugs.ruby-lang.org/issues/21389
+[Feature #21390]: https://bugs.ruby-lang.org/issues/21390
+[Feature #21459]: https://bugs.ruby-lang.org/issues/21459
+[Feature #21527]: https://bugs.ruby-lang.org/issues/21527
+[Feature #21543]: https://bugs.ruby-lang.org/issues/21543
+[Feature #21550]: https://bugs.ruby-lang.org/issues/21550
+[Feature #21552]: https://bugs.ruby-lang.org/issues/21552
+[Feature #21557]: https://bugs.ruby-lang.org/issues/21557
+[Bug #21633]: https://bugs.ruby-lang.org/issues/21633
+[Bug #21654]: https://bugs.ruby-lang.org/issues/21654
+[Feature #21678]: https://bugs.ruby-lang.org/issues/21678
+[Bug #21698]: https://bugs.ruby-lang.org/issues/21698
+[Feature #21701]: https://bugs.ruby-lang.org/issues/21701
+[Bug #21789]: https://bugs.ruby-lang.org/issues/21789
+[GH-net-http #205]: https://github.com/ruby/net-http/issues/205
+[ostruct-v0.6.2]: https://github.com/ruby/ostruct/releases/tag/v0.6.2
+[ostruct-v0.6.3]: https://github.com/ruby/ostruct/releases/tag/v0.6.3
+[pstore-v0.2.0]: https://github.com/ruby/pstore/releases/tag/v0.2.0
+[benchmark-v0.4.1]: https://github.com/ruby/benchmark/releases/tag/v0.4.1
+[benchmark-v0.5.0]: https://github.com/ruby/benchmark/releases/tag/v0.5.0
+[logger-v1.6.5]: https://github.com/ruby/logger/releases/tag/v1.6.5
+[logger-v1.6.6]: https://github.com/ruby/logger/releases/tag/v1.6.6
+[logger-v1.7.0]: https://github.com/ruby/logger/releases/tag/v1.7.0
+[rdoc-v6.14.1]: https://github.com/ruby/rdoc/releases/tag/v6.14.1
+[rdoc-v6.14.2]: https://github.com/ruby/rdoc/releases/tag/v6.14.2
+[rdoc-v6.15.0]: https://github.com/ruby/rdoc/releases/tag/v6.15.0
+[rdoc-v6.15.1]: https://github.com/ruby/rdoc/releases/tag/v6.15.1
+[rdoc-v6.16.0]: https://github.com/ruby/rdoc/releases/tag/v6.16.0
+[rdoc-v6.16.1]: https://github.com/ruby/rdoc/releases/tag/v6.16.1
+[rdoc-v6.17.0]: https://github.com/ruby/rdoc/releases/tag/v6.17.0
+[rdoc-v7.0.0]: https://github.com/ruby/rdoc/releases/tag/v7.0.0
+[rdoc-v7.0.1]: https://github.com/ruby/rdoc/releases/tag/v7.0.1
+[rdoc-v7.0.2]: https://github.com/ruby/rdoc/releases/tag/v7.0.2
+[rdoc-v7.0.3]: https://github.com/ruby/rdoc/releases/tag/v7.0.3
+[win32ole-v1.9.2]: https://github.com/ruby/win32ole/releases/tag/v1.9.2
+[irb-v1.15.0]: https://github.com/ruby/irb/releases/tag/v1.15.0
+[irb-v1.15.1]: https://github.com/ruby/irb/releases/tag/v1.15.1
+[irb-v1.15.2]: https://github.com/ruby/irb/releases/tag/v1.15.2
+[irb-v1.15.3]: https://github.com/ruby/irb/releases/tag/v1.15.3
+[irb-v1.16.0]: https://github.com/ruby/irb/releases/tag/v1.16.0
+[reline-v0.6.1]: https://github.com/ruby/reline/releases/tag/v0.6.1
+[reline-v0.6.2]: https://github.com/ruby/reline/releases/tag/v0.6.2
+[reline-v0.6.3]: https://github.com/ruby/reline/releases/tag/v0.6.3
+[fiddle-v1.1.7]: https://github.com/ruby/fiddle/releases/tag/v1.1.7
+[fiddle-v1.1.8]: https://github.com/ruby/fiddle/releases/tag/v1.1.8
+[date-v3.5.0]: https://github.com/ruby/date/releases/tag/v3.5.0
+[date-v3.5.1]: https://github.com/ruby/date/releases/tag/v3.5.1
+[delegate-v0.5.0]: https://github.com/ruby/delegate/releases/tag/v0.5.0
+[delegate-v0.6.0]: https://github.com/ruby/delegate/releases/tag/v0.6.0
+[delegate-v0.6.1]: https://github.com/ruby/delegate/releases/tag/v0.6.1
+[digest-v3.2.1]: https://github.com/ruby/digest/releases/tag/v3.2.1
+[english-v0.8.1]: https://github.com/ruby/english/releases/tag/v0.8.1
+[erb-v5.1.2]: https://github.com/ruby/erb/releases/tag/v5.1.2
+[erb-v5.1.3]: https://github.com/ruby/erb/releases/tag/v5.1.3
+[erb-v6.0.0]: https://github.com/ruby/erb/releases/tag/v6.0.0
+[erb-v6.0.1]: https://github.com/ruby/erb/releases/tag/v6.0.1
+[fcntl-v1.3.0]: https://github.com/ruby/fcntl/releases/tag/v1.3.0
+[fileutils-v1.8.0]: https://github.com/ruby/fileutils/releases/tag/v1.8.0
+[forwardable-v1.4.0]: https://github.com/ruby/forwardable/releases/tag/v1.4.0
+[io-console-v0.8.2]: https://github.com/ruby/io-console/releases/tag/v0.8.2
+[io-wait-v0.3.3]: https://github.com/ruby/io-wait/releases/tag/v0.3.3
+[io-wait-v0.3.5.test1]: https://github.com/ruby/io-wait/releases/tag/v0.3.5.test1
+[io-wait-v0.3.5]: https://github.com/ruby/io-wait/releases/tag/v0.3.5
+[io-wait-v0.3.6]: https://github.com/ruby/io-wait/releases/tag/v0.3.6
+[io-wait-v0.4.0]: https://github.com/ruby/io-wait/releases/tag/v0.4.0
+[json-v2.10.0]: https://github.com/ruby/json/releases/tag/v2.10.0
+[json-v2.10.1]: https://github.com/ruby/json/releases/tag/v2.10.1
+[json-v2.10.2]: https://github.com/ruby/json/releases/tag/v2.10.2
+[json-v2.11.0]: https://github.com/ruby/json/releases/tag/v2.11.0
+[json-v2.11.1]: https://github.com/ruby/json/releases/tag/v2.11.1
+[json-v2.11.2]: https://github.com/ruby/json/releases/tag/v2.11.2
+[json-v2.11.3]: https://github.com/ruby/json/releases/tag/v2.11.3
+[json-v2.12.0]: https://github.com/ruby/json/releases/tag/v2.12.0
+[json-v2.12.1]: https://github.com/ruby/json/releases/tag/v2.12.1
+[json-v2.12.2]: https://github.com/ruby/json/releases/tag/v2.12.2
+[json-v2.13.0]: https://github.com/ruby/json/releases/tag/v2.13.0
+[json-v2.13.1]: https://github.com/ruby/json/releases/tag/v2.13.1
+[json-v2.13.2]: https://github.com/ruby/json/releases/tag/v2.13.2
+[json-v2.14.0]: https://github.com/ruby/json/releases/tag/v2.14.0
+[json-v2.14.1]: https://github.com/ruby/json/releases/tag/v2.14.1
+[json-v2.15.0]: https://github.com/ruby/json/releases/tag/v2.15.0
+[json-v2.15.1]: https://github.com/ruby/json/releases/tag/v2.15.1
+[json-v2.15.2]: https://github.com/ruby/json/releases/tag/v2.15.2
+[json-v2.16.0]: https://github.com/ruby/json/releases/tag/v2.16.0
+[json-v2.17.0]: https://github.com/ruby/json/releases/tag/v2.17.0
+[json-v2.17.1]: https://github.com/ruby/json/releases/tag/v2.17.1
+[json-v2.18.0]: https://github.com/ruby/json/releases/tag/v2.18.0
+[net-http-v0.7.0]: https://github.com/ruby/net-http/releases/tag/v0.7.0
+[net-http-v0.8.0]: https://github.com/ruby/net-http/releases/tag/v0.8.0
+[net-http-v0.9.0]: https://github.com/ruby/net-http/releases/tag/v0.9.0
+[net-http-v0.9.1]: https://github.com/ruby/net-http/releases/tag/v0.9.1
+[openssl-v3.3.2]: https://github.com/ruby/openssl/releases/tag/v3.3.2
+[openssl-v4.0.0]: https://github.com/ruby/openssl/releases/tag/v4.0.0
+[optparse-v0.7.0]: https://github.com/ruby/optparse/releases/tag/v0.7.0
+[optparse-v0.8.0]: https://github.com/ruby/optparse/releases/tag/v0.8.0
+[optparse-v0.8.1]: https://github.com/ruby/optparse/releases/tag/v0.8.1
+[pp-v0.6.3]: https://github.com/ruby/pp/releases/tag/v0.6.3
+[prism-v1.6.0]: https://github.com/ruby/prism/releases/tag/v1.6.0
+[prism-v1.7.0]: https://github.com/ruby/prism/releases/tag/v1.7.0
+[psych-v5.2.3]: https://github.com/ruby/psych/releases/tag/v5.2.3
+[psych-v5.2.4]: https://github.com/ruby/psych/releases/tag/v5.2.4
+[psych-v5.2.5]: https://github.com/ruby/psych/releases/tag/v5.2.5
+[psych-v5.2.6]: https://github.com/ruby/psych/releases/tag/v5.2.6
+[psych-v5.3.0]: https://github.com/ruby/psych/releases/tag/v5.3.0
+[psych-v5.3.1]: https://github.com/ruby/psych/releases/tag/v5.3.1
+[resolv-v0.6.3]: https://github.com/ruby/resolv/releases/tag/v0.6.3
+[resolv-v0.7.0]: https://github.com/ruby/resolv/releases/tag/v0.7.0
+[stringio-v3.1.3]: https://github.com/ruby/stringio/releases/tag/v3.1.3
+[stringio-v3.1.4]: https://github.com/ruby/stringio/releases/tag/v3.1.4
+[stringio-v3.1.5]: https://github.com/ruby/stringio/releases/tag/v3.1.5
+[stringio-v3.1.6]: https://github.com/ruby/stringio/releases/tag/v3.1.6
+[stringio-v3.1.7]: https://github.com/ruby/stringio/releases/tag/v3.1.7
+[stringio-v3.1.8]: https://github.com/ruby/stringio/releases/tag/v3.1.8
+[stringio-v3.1.9]: https://github.com/ruby/stringio/releases/tag/v3.1.9
+[stringio-v3.2.0]: https://github.com/ruby/stringio/releases/tag/v3.2.0
+[strscan-v3.1.3]: https://github.com/ruby/strscan/releases/tag/v3.1.3
+[strscan-v3.1.4]: https://github.com/ruby/strscan/releases/tag/v3.1.4
+[strscan-v3.1.5]: https://github.com/ruby/strscan/releases/tag/v3.1.5
+[strscan-v3.1.6]: https://github.com/ruby/strscan/releases/tag/v3.1.6
+[time-v0.4.2]: https://github.com/ruby/time/releases/tag/v0.4.2
+[timeout-v0.4.4]: https://github.com/ruby/timeout/releases/tag/v0.4.4
+[timeout-v0.5.0]: https://github.com/ruby/timeout/releases/tag/v0.5.0
+[timeout-v0.6.0]: https://github.com/ruby/timeout/releases/tag/v0.6.0
+[uri-v1.1.0]: https://github.com/ruby/uri/releases/tag/v1.1.0
+[uri-v1.1.1]: https://github.com/ruby/uri/releases/tag/v1.1.1
+[weakref-v0.1.4]: https://github.com/ruby/weakref/releases/tag/v0.1.4
+[zlib-v3.2.2]: https://github.com/ruby/zlib/releases/tag/v3.2.2
+[power_assert-v3.0.0]: https://github.com/ruby/power_assert/releases/tag/v3.0.0
+[power_assert-v3.0.1]: https://github.com/ruby/power_assert/releases/tag/v3.0.1
+[rake-v13.3.0]: https://github.com/ruby/rake/releases/tag/v13.3.0
+[rake-v13.3.1]: https://github.com/ruby/rake/releases/tag/v13.3.1
+[test-unit-3.6.8]: https://github.com/test-unit/test-unit/releases/tag/3.6.8
+[test-unit-3.6.9]: https://github.com/test-unit/test-unit/releases/tag/3.6.9
+[test-unit-3.7.0]: https://github.com/test-unit/test-unit/releases/tag/3.7.0
+[test-unit-3.7.1]: https://github.com/test-unit/test-unit/releases/tag/3.7.1
+[test-unit-3.7.2]: https://github.com/test-unit/test-unit/releases/tag/3.7.2
+[test-unit-3.7.3]: https://github.com/test-unit/test-unit/releases/tag/3.7.3
+[test-unit-3.7.4]: https://github.com/test-unit/test-unit/releases/tag/3.7.4
+[test-unit-3.7.5]: https://github.com/test-unit/test-unit/releases/tag/3.7.5
+[rss-0.3.2]: https://github.com/ruby/rss/releases/tag/0.3.2
+[net-ftp-v0.3.9]: https://github.com/ruby/net-ftp/releases/tag/v0.3.9
+[net-imap-v0.5.9]: https://github.com/ruby/net-imap/releases/tag/v0.5.9
+[net-imap-v0.5.10]: https://github.com/ruby/net-imap/releases/tag/v0.5.10
+[net-imap-v0.5.11]: https://github.com/ruby/net-imap/releases/tag/v0.5.11
+[net-imap-v0.5.12]: https://github.com/ruby/net-imap/releases/tag/v0.5.12
+[net-imap-v0.5.13]: https://github.com/ruby/net-imap/releases/tag/v0.5.13
+[net-imap-v0.6.0]: https://github.com/ruby/net-imap/releases/tag/v0.6.0
+[net-imap-v0.6.1]: https://github.com/ruby/net-imap/releases/tag/v0.6.1
+[net-imap-v0.6.2]: https://github.com/ruby/net-imap/releases/tag/v0.6.2
+[net-smtp-v0.5.1]: https://github.com/ruby/net-smtp/releases/tag/v0.5.1
+[matrix-v0.4.3]: https://github.com/ruby/matrix/releases/tag/v0.4.3
+[prime-v0.1.4]: https://github.com/ruby/prime/releases/tag/v0.1.4
+[rbs-v3.8.1]: https://github.com/ruby/rbs/releases/tag/v3.8.1
+[rbs-v3.9.0.dev.1]: https://github.com/ruby/rbs/releases/tag/v3.9.0.dev.1
+[rbs-v3.9.0.pre.1]: https://github.com/ruby/rbs/releases/tag/v3.9.0.pre.1
+[rbs-v3.9.0.pre.2]: https://github.com/ruby/rbs/releases/tag/v3.9.0.pre.2
+[rbs-v3.9.0]: https://github.com/ruby/rbs/releases/tag/v3.9.0
+[rbs-v3.9.1]: https://github.com/ruby/rbs/releases/tag/v3.9.1
+[rbs-v3.9.2]: https://github.com/ruby/rbs/releases/tag/v3.9.2
+[rbs-v3.9.3]: https://github.com/ruby/rbs/releases/tag/v3.9.3
+[rbs-v3.9.4]: https://github.com/ruby/rbs/releases/tag/v3.9.4
+[rbs-v3.9.5]: https://github.com/ruby/rbs/releases/tag/v3.9.5
+[rbs-v3.10.0.pre.1]: https://github.com/ruby/rbs/releases/tag/v3.10.0.pre.1
+[rbs-v3.10.0.pre.2]: https://github.com/ruby/rbs/releases/tag/v3.10.0.pre.2
+[rbs-v3.10.0]: https://github.com/ruby/rbs/releases/tag/v3.10.0
+[debug-v1.11.1]: https://github.com/ruby/debug/releases/tag/v1.11.1
+[base64-v0.3.0]: https://github.com/ruby/base64/releases/tag/v0.3.0
+[bigdecimal-v3.2.0]: https://github.com/ruby/bigdecimal/releases/tag/v3.2.0
+[bigdecimal-v3.2.1]: https://github.com/ruby/bigdecimal/releases/tag/v3.2.1
+[bigdecimal-v3.2.2]: https://github.com/ruby/bigdecimal/releases/tag/v3.2.2
+[bigdecimal-v3.2.3]: https://github.com/ruby/bigdecimal/releases/tag/v3.2.3
+[bigdecimal-v3.3.0]: https://github.com/ruby/bigdecimal/releases/tag/v3.3.0
+[bigdecimal-v3.3.1]: https://github.com/ruby/bigdecimal/releases/tag/v3.3.1
+[bigdecimal-v4.0.0]: https://github.com/ruby/bigdecimal/releases/tag/v4.0.0
+[bigdecimal-v4.0.1]: https://github.com/ruby/bigdecimal/releases/tag/v4.0.1
+[drb-v2.2.3]: https://github.com/ruby/drb/releases/tag/v2.2.3
+[syslog-v0.3.0]: https://github.com/ruby/syslog/releases/tag/v0.3.0
+[csv-v3.3.3]: https://github.com/ruby/csv/releases/tag/v3.3.3
+[csv-v3.3.4]: https://github.com/ruby/csv/releases/tag/v3.3.4
+[csv-v3.3.5]: https://github.com/ruby/csv/releases/tag/v3.3.5
diff --git a/doc/_regexp.rdoc b/doc/_regexp.rdoc
index c9f3742241..4ad6118ddd 100644
--- a/doc/_regexp.rdoc
+++ b/doc/_regexp.rdoc
@@ -26,20 +26,20 @@ A regexp may be used:
re.match('good') # => nil
See sections {Method match}[rdoc-ref:Regexp@Method+match]
- and {Operator =~}[rdoc-ref:Regexp@Operator+-3D~].
+ and {Operator =~}[rdoc-ref:Regexp@Operator-].
- 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].
+ See section {Method match?}[rdoc-ref:Regexp@Method+match].
- 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].
+ See {Regexp Methods}[rdoc-ref:language/regexp/methods.rdoc].
== \Regexp Objects
@@ -64,7 +64,7 @@ A regular expression may be created with:
/foo/ # => /foo/
- A <tt>%r</tt> regexp literal
- (see {%r: Regexp Literals}[rdoc-ref:syntax/literals.rdoc@25r-3A+Regexp+Literals]):
+ (see {%r: Regexp Literals}[rdoc-ref:syntax/literals.rdoc@r-regexp+literals]):
# Same delimiter character at beginning and end;
# useful for avoiding escaping characters
@@ -113,7 +113,7 @@ none sets {global variables}[rdoc-ref:Regexp@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~].
+- <tt>#=~</tt>: see {Operator =~}[rdoc-ref:Regexp@Operator-].
The affected global variables are:
@@ -414,21 +414,21 @@ Each of these anchors matches a boundary:
Lookahead anchors:
-- <tt>(?=_pat_)</tt>: Positive lookahead assertion:
+- <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:
+- <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:
+- <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:
+- <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.
@@ -561,9 +561,9 @@ Quantifier matching may be greedy, lazy, or possessive:
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].
+ {Choosing Minimal or Maximal Repetition}[https://www.oreilly.com/library/view/regular-expressions-cookbook/9780596802837/ch02s13.html].
- 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].
+ {Eliminate Needless Backtracking}[https://www.oreilly.com/library/view/regular-expressions-cookbook/9780596802837/ch02s14.html].
=== Groups and Captures
@@ -574,7 +574,7 @@ A simple regexp has (at most) one match:
re.match('1943-02-04').size # => 1
re.match('foo') # => nil
-Adding one or more pairs of parentheses, <tt>(_subexpression_)</tt>,
+Adding one or more pairs of parentheses, <tt>(subexpression)</tt>,
defines _groups_, which may result in multiple matched substrings,
called _captures_:
@@ -647,8 +647,8 @@ 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_.
+ - 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,
@@ -661,7 +661,7 @@ A regexp may contain any number of groups:
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>,
+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")
@@ -676,7 +676,7 @@ 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>:
+A named group may be backreferenced as <tt>\k<name></tt>:
/(?<vowel>[aeiou]).\k<vowel>.\k<vowel>/.match('ototomy')
# => #<MatchData "ototo" vowel:"o">
@@ -713,7 +713,7 @@ 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>
+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;
@@ -732,10 +732,10 @@ 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>)
+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>):
+via the number n (<tt>\\gn</tt>) or name (<tt>\g<name></tt>):
/\A(?<paren>\(\g<paren>*\))*\z/.match('(())')
# ^1
@@ -764,16 +764,16 @@ The pattern:
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].
+See {Subexpression calls}[https://learnbyexample.github.io/Ruby_Regexp/groupings-and-backreferences.html#subexpression-calls].
==== Conditionals
-The conditional construct takes the form <tt>(?(_cond_)_yes_|_no_)</tt>, where:
+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.
+- If not needed, <tt>|no</tt> may be omitted.
Examples:
@@ -802,7 +802,7 @@ The absence operator is a special group that matches anything which does _not_ m
==== Unicode Properties
-The <tt>/\p{_property_name_}/</tt> construct (with lowercase +p+)
+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:
@@ -821,7 +821,7 @@ 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]
+See {Unicode Properties}[rdoc-ref:language/regexp/unicode_properties.rdoc]
for regexps based on the numerous properties.
Some commonly-used properties correspond to POSIX bracket expressions:
@@ -930,7 +930,7 @@ Punctuation:
- +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].
+- {Cn, Unassigned}[http://zuga.net/articles/unicode/category/unassigned/].
- {Co, Private_Use}[https://www.compart.com/en/unicode/category/Co].
- {Cs, Surrogate}[https://www.compart.com/en/unicode/category/Cs].
@@ -1033,23 +1033,23 @@ See also {Extended Mode}[rdoc-ref:Regexp@Extended+Mode].
Each of these modifiers sets a mode for the regexp:
-- +i+: <tt>/_pattern_/i</tt> sets
+- +i+: <tt>/pattern/i</tt> sets
{Case-Insensitive Mode}[rdoc-ref:Regexp@Case-Insensitive+Mode].
-- +m+: <tt>/_pattern_/m</tt> sets
+- +m+: <tt>/pattern/m</tt> sets
{Multiline Mode}[rdoc-ref:Regexp@Multiline+Mode].
-- +x+: <tt>/_pattern_/x</tt> sets
+- +x+: <tt>/pattern/x</tt> sets
{Extended Mode}[rdoc-ref:Regexp@Extended+Mode].
-- +o+: <tt>/_pattern_/o</tt> sets
+- +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
+- <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:
@@ -1128,6 +1128,13 @@ Regexp in extended mode:
re = /#{pattern}/x
re.match('MCMXLIII') # => #<MatchData "MCMXLIII" 1:"CM" 2:"XL" 3:"III">
+Comments in regexp literals cannot include unescaped terminator
+characters:
+
+ /
+ foo # the following slash \/ must be escaped
+ /x
+
=== Interpolation Mode
Modifier +o+ means that the first time a literal regexp with interpolations
@@ -1166,22 +1173,22 @@ 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,
+- <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
+- <tt>/pat/u</tt>: UTF-8
/foo/u.encoding # => #<Encoding:UTF-8>
-- <tt>/_pat_/e</tt>: EUC-JP
+- <tt>/pat/e</tt>: EUC-JP
/foo/e.encoding # => #<Encoding:EUC-JP>
-- <tt>/_pat_/s</tt>: Windows-31J
+- <tt>/pat/s</tt>: Windows-31J
/foo/s.encoding # => #<Encoding:Windows-31J>
@@ -1251,7 +1258,7 @@ the potential vulnerability arising from this is the {regular expression denial-
\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.
+in relation to the input size, and a ReDoS attack is not possible.
This optimization is applied if the pattern meets these criteria:
@@ -1272,13 +1279,13 @@ because the optimization uses memoization (which may invoke large memory consump
== References
-Read (online PDF books):
+Read:
-- {Mastering Regular Expressions}[https://ia902508.us.archive.org/10/items/allitebooks-02/Mastering%20Regular%20Expressions%2C%203rd%20Edition.pdf]
+- <i>Mastering Regular Expressions</i>
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]
+- <i>Regular Expressions Cookbook</i>
by Jan Goyvaerts & Steven Levithan.
-Explore, test (interactive online editor):
+Explore, test:
-- {Rubular}[https://rubular.com/].
+- {Rubular}[https://rubular.com/]: interactive online editor.
diff --git a/doc/_timezones.rdoc b/doc/_timezones.rdoc
index a2ac46584f..945654c163 100644
--- a/doc/_timezones.rdoc
+++ b/doc/_timezones.rdoc
@@ -11,7 +11,7 @@ Certain +Time+ methods accept arguments that specify timezones:
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].
+- {Hours/minutes offset}[rdoc-ref:Time@HoursMinutes+Offsets].
- {Single-letter offset}[rdoc-ref:Time@Single-Letter+Offsets].
- {Integer offset}[rdoc-ref:Time@Integer+Offsets].
- {Timezone object}[rdoc-ref:Time@Timezone+Objects].
diff --git a/doc/character_selectors.rdoc b/doc/character_selectors.rdoc
deleted file mode 100644
index 47cf242be7..0000000000
--- a/doc/character_selectors.rdoc
+++ /dev/null
@@ -1,97 +0,0 @@
-= Character Selectors
-
-== 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:
-
-- String#tr(selector, replacements): returns a new string.
-- String#tr!(selector, replacements): returns +self+ or +nil+.
-- String#tr_s(selector, replacements): returns a new string.
-- String#tr_s!(selector, replacements): returns +self+ or +nil+.
-- String#count(*selectors): returns the count of the specified characters.
-- String#delete(*selectors): returns a new string.
-- String#delete!(*selectors): returns +self+ or +nil+.
-- String#squeeze(*selectors): returns a new string.
-- String#squeeze!(*selectors): returns +self+ or +nil+.
-
-A character selector identifies zero or more characters in +self+
-that are to be operands for the method.
-
-In this section, we illustrate using method String#delete(selector),
-which deletes the selected characters.
-
-In the simplest case, the characters selected are exactly those
-contained in the selector itself:
-
- 'abracadabra'.delete('a') # => "brcdbr"
- 'abracadabra'.delete('ab') # => "rcdr"
- 'abracadabra'.delete('abc') # => "rdr"
- '0123456789'.delete('258') # => "0134679"
- '!@#$%&*()_+'.delete('+&#') # => "!@$%*()_"
- 'теÑÑ‚'.delete('Ñ‚') # => "еÑ"
- 'ã“ã‚“ã«ã¡ã¯'.delete('ã«') # => "ã“ã‚“ã¡ã¯"
-
-Note that order and repetitions do not matter:
-
- 'abracadabra'.delete('dcab') # => "rr"
- 'abracadabra'.delete('aaaa') # => "brcdbr"
-
-In a character selector, these three characters get special treatment:
-
-- A leading caret (<tt>'^'</tt>) functions as a "not" operator
- for the characters to its right:
-
- 'abracadabra'.delete('^bc') # => "bcb"
- '0123456789'.delete('^852') # => "258"
-
-- A hyphen (<tt>'-'</tt>) between two other characters
- defines a range of characters instead of a plain string of characters:
-
- 'abracadabra'.delete('a-d') # => "rr"
- '0123456789'.delete('4-7') # => "012389"
- '!@#$%&*()_+'.delete(' -/') # => "@^_"
-
- # May contain more than one range.
- 'abracadabra'.delete('a-cq-t') # => "d"
-
- # Ranges may be mixed with plain characters.
- '0123456789'.delete('67-950-23') # => "4"
-
- # Ranges may be mixed with negations.
- 'abracadabra'.delete('^a-c') # => "abacaaba"
-
-- A backslash (<tt>'\'</tt>) acts as an escape for a caret, a hyphen,
- or another backslash:
-
- 'abracadabra^'.delete('\^bc') # => "araadara"
- 'abracadabra-'.delete('a\-d') # => "brcbr"
- "hello\r\nworld".delete("\r") # => "hello\nworld"
- "hello\r\nworld".delete("\\r") # => "hello\r\nwold"
- "hello\r\nworld".delete("\\\r") # => "hello\nworld"
-
-== Multiple Character Selectors
-
-These instance methods accept multiple character selectors:
-
-- String#count(*selectors): returns the count of the specified characters.
-- String#delete(*selectors): returns a new string.
-- String#delete!(*selectors): returns +self+ or +nil+.
-- String#squeeze(*selectors): returns a new string.
-- String#squeeze!(*selectors): returns +self+ or +nil+.
-
-In effect, the given selectors are formed into a single selector
-consisting of only those characters common to _all_ of the given selectors.
-
-All forms of selectors may be used, including negations, ranges, and escapes.
-
-Each of these pairs of method calls is equivalent:
-
- s.delete('abcde', 'dcbfg')
- s.delete('bcd')
-
- s.delete('^abc', '^def')
- s.delete('^abcdef')
-
- s.delete('a-e', 'c-g')
- s.delete('cde')
diff --git a/doc/command_injection.rdoc b/doc/command_injection.rdoc
deleted file mode 100644
index ee33d4a04e..0000000000
--- a/doc/command_injection.rdoc
+++ /dev/null
@@ -1,37 +0,0 @@
-= Command Injection
-
-Some Ruby core methods accept string data
-that includes text to be executed as a system command.
-
-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.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+:
-
-- File.read(path).
-- File.write(path).
-- File.binread(path).
-- File.binwrite(path).
-- File.readlines(path).
-- File.foreach(path).
diff --git a/doc/command_line/environment.md b/doc/command_line/environment.md
deleted file mode 100644
index 8f6d595f6c..0000000000
--- a/doc/command_line/environment.md
+++ /dev/null
@@ -1,174 +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:
-
-```console
-$ 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:
-
-```console
-$ 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:
-
-```console
-$ 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:
-
-```console
-$ 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:
-
-```console
-$ 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`:
-
-```console
-$ 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):
-
-```console
-$ 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:
-
-```ruby
-Warning[:experimental] # => true
-Warning[:deprecated] # => false
-Warning[:performance] # => false
-```
-
-They may also be set:
-
-```ruby
-Warning[:experimental] = false
-Warning[:deprecated] = true
-Warning[:performance] = true
-```
-
-You can suppress a category by prefixing `no-` to the category name:
-
-```console
-$ ruby -W:no-experimental -e 'p IO::Buffer.new'
-#<IO::Buffer>
-```
-
diff --git a/doc/bug_triaging.rdoc b/doc/contributing/bug_triaging.rdoc
index 83fe88cabe..83fe88cabe 100644
--- a/doc/bug_triaging.rdoc
+++ b/doc/contributing/bug_triaging.rdoc
diff --git a/doc/contributing/building_ruby.md b/doc/contributing/building_ruby.md
index eac83fc00e..a283a2f3db 100644
--- a/doc/contributing/building_ruby.md
+++ b/doc/contributing/building_ruby.md
@@ -17,11 +17,11 @@
* [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
+ * ruby - 3.1 or later
* We can upgrade this version to system ruby version of the latest
Ubuntu LTS.
* git - 2.32 or later
- * Anterior versions may work; 2.32 or later will prevent build
+ * Earlier versions may work; 2.32 or later will prevent build
errors in case your system `.gitconfig` uses `$HOME` paths.
2. Install optional, recommended dependencies:
@@ -151,7 +151,7 @@ ruby
├── build # Created in step 2 and populated in step 4
│ ├── GNUmakefile # Generated by `../configure`
│ ├── Makefile # Generated by `../configure`
-│ ├── object.o # Compiled object file, built my `make`
+│ ├── object.o # Compiled object file, built by `make`
│ └── ... other compiled `.o` object files
│
│ # Other interesting files:
@@ -184,7 +184,7 @@ cause build failures.
## Building on Windows
The documentation for building on Windows can be found in [the separated
-file](../windows.md).
+file](../distribution/windows.md).
## More details
diff --git a/doc/contributing/concurrency_guide.md b/doc/contributing/concurrency_guide.md
new file mode 100644
index 0000000000..1fb58f7203
--- /dev/null
+++ b/doc/contributing/concurrency_guide.md
@@ -0,0 +1,154 @@
+# Concurrency Guide
+
+This is a guide to thinking about concurrency in the cruby source code, whether that's contributing to Ruby
+by writing C or by contributing to one of the JITs. This does not touch on native extensions, only the core
+language. It will go over:
+
+* What needs synchronizing?
+* How to use the VM lock, and what you can and can't do when you've acquired this lock.
+* What you can and can't do when you've acquired other native locks.
+* The difference between the VM lock and the GVL.
+* What a VM barrier is and when to use it.
+* The lock ordering of some important locks.
+* How ruby interrupt handling works.
+* The timer thread and what it's responsible for.
+
+## What needs synchronizing?
+
+Before ractors, only one ruby thread could run at once. That didn't mean you could forget about concurrency issues, though. The timer thread
+is a native thread that interacts with other ruby threads and changes some VM internals, so if these changes can be done in parallel by both the timer
+thread and a ruby thread, they need to be synchronized.
+
+When you add ractors to the mix, it gets more complicated. However, ractors allow you to forget about synchronization for non-shareable objects because
+they aren't used across ractors. Only one ruby thread can touch the object at once. For shareable objects, they are deeply frozen so there isn't any
+mutation on the objects themselves. However, something like reading/writing constants across ractors does need to be synchronized. In this case, ruby threads need to
+see a consistent view of the VM. If publishing the update takes 2 steps or even two separate instructions, like in this case, synchronization is required.
+
+Most synchronization is to protect VM internals. These internals include structures for the thread scheduler on each ractor, the global ractor scheduler, the
+coordination between ruby threads and ractors, global tables (for `fstrings`, encodings, symbols and global vars), etc. Anything that can be mutated by a ractor
+that can also be read or mutated by another ractor at the same time requires proper synchronization.
+
+## The VM Lock
+
+There's only one VM lock and it is for critical sections that can only be entered by one ractor at a time.
+Without ractors, the VM lock is useless. It does not stop all ractors from running, as ractors can run
+without trying to acquire this lock. If you're updating global (shared) data between ractors and aren't using
+atomics, you need to use a lock and this is a convenient one to use. Unlike other locks, you can allocate ruby-managed
+memory with it held. When you take the VM lock, there are things you can and can't do during your critical section:
+
+You can (as long as no other locks are also held before the VM lock):
+
+* Create ruby objects, call `ruby_xmalloc`, etc.
+
+You can't:
+
+* Context switch to another ruby thread or ractor. This is important, as many things can cause ruby-level context switches including:
+
+ * Calling any ruby method through, for example, `rb_funcall`. If you execute ruby code, a context switch could happen.
+ This also applies to ruby methods defined in C, as they can be redefined in Ruby. Things that call ruby methods such as
+ `rb_obj_respond_to` are also disallowed.
+
+ * Calling `rb_raise`. This will call `initialize` on the new exception object. With the VM lock
+ held, nothing you call should be able to raise an exception. `NoMemoryError` is allowed, however.
+
+ * Calling `rb_nogvl` or a ruby-level mechanism that can context switch like `rb_mutex_lock`.
+
+ * Enter any blocking operation managed by ruby. This will context switch to another ruby thread using `rb_nogvl` or
+ something equivalent. A blocking operation is one that blocks the thread's progress, such as `sleep` or `IO#read`.
+
+Internally, the VM lock is the `vm->ractor.sync.lock`.
+
+You need to be on a ruby thread to take the VM lock. You also can't take it inside any functions that could be called during sweeping, as MMTK sweeps
+on another thread and you need a valid `ec` to grab the lock. For this same reason (among others), you can't take it from the timer thread either.
+
+## Other Locks
+
+All native locks that aren't the VM lock share a more strict set of rules for what's allowed during the critical section. By native locks, we mean
+anything that uses `rb_native_mutex_lock`. Some important locks include the `interrupt_lock`, the ractor scheduling lock (protects global scheduling data structures),
+the thread scheduling lock (local to each ractor, protects per-ractor scheduling data structures) and the ractor lock (local to each ractor, protects ractor data structures).
+
+When you acquire one of these locks,
+
+You can:
+
+* Allocate memory though non-ruby allocation such as raw `malloc` or the standard library. But be careful, some functions like `strdup` use
+ruby allocation through the use of macros!
+
+* Use `ccan` lists, as they don't allocate.
+
+* Do the usual things like set variables or struct fields, manipulate linked lists, signal condition variables etc.
+
+You can't:
+
+* Allocate ruby-managed memory. This includes creating ruby objects or using `ruby_xmalloc` or `st_insert`. The reason this
+is disallowed is if that allocation causes a GC, then all other ruby threads must join a VM barrier as soon as possible
+(when they next check interrupts or acquire the VM lock). This is so that no other ractors are running during GC. If a ruby thread
+is waiting (blocked) on this same native lock, it can't join the barrier and a deadlock occurs because the barrier will never finish.
+
+* Raise exceptions. You also can't use `EC_JUMP_TAG` if it jumps out of the critical section.
+
+* Context switch. See the `VM Lock` section for more info.
+
+## Difference Between VM Lock and GVL
+
+The VM Lock is a particular lock in the source code. There is only one VM Lock. The GVL, on the other hand, is more of a combination of locks.
+It is "acquired" when a ruby thread is about to run or is running. Since many ruby threads can run at the same time if they're in different ractors,
+there are many GVLs (1 per `SNT` + 1 for the main ractor). It can no longer be thought of as a "Global VM Lock" like it once was before ractors.
+
+## VM Barriers
+
+Sometimes, taking the VM Lock isn't enough and you need a guarantee that all ractors have stopped. This happens when running `GC`, for instance.
+To get a barrier, you take the VM Lock and call `rb_vm_barrier()`. For the duration that the VM lock is held, no other ractors will be running. It's not used
+often as taking a barrier slows ractor performance down considerably, but it's useful to know about and is sometimes the only solution.
+
+## Lock Orderings
+
+It's a good idea to not hold more than 2 locks at once on the same thread. Locking multiple locks can introduce deadlocks, so do it with care. When locking
+multiple locks at once, follow an ordering that is consistent across the program, otherwise you can introduce deadlocks. Here are the orderings of some important locks:
+
+* VM lock before ractor_sched_lock
+* thread_sched_lock before ractor_sched_lock
+* interrupt_lock before timer_th.waiting_lock
+* timer_th.waiting_lock before ractor_sched_lock
+
+These orderings are subject to change, so check the source if you're not sure. On top of this:
+
+* During each `ubf` (unblock) function, the VM lock can be taken around it in some circumstances. This happens during VM shutdown, for example.
+See the "Interrupt Handling" section for more details.
+
+## Ruby Interrupt Handling
+
+When the VM runs ruby code, ruby's threads intermittently check ruby-level interrupts. These software interrupts
+are for various things in ruby and they can be set by other ruby threads or the timer thread.
+
+* Ruby threads check when they should give up their timeslice. The native thread switches to another ruby thread when their time is up.
+* The timer thread sends a "trap" interrupt to the main thread if any ruby-level signal handlers are pending.
+* Ruby threads can have other ruby threads run tasks for them by sending them an interrupt. For instance, ractors send
+the main thread an interrupt when they need to `require` a file so that it's done on the main thread. They wait for the
+main thread's result.
+* During VM shutdown, a "terminate" interrupt is sent to all ractor main threads top stop them asap.
+* When calling `Thread#raise`, the caller sends an interrupt to that thread telling it which exception to raise.
+* Unlocking a mutex sends the next waiter (if any) an interrupt telling it to grab the lock.
+* Signalling or broadcasting on a condition variable tells the waiter(s) to wake up.
+
+This isn't a complete list.
+
+When sending an interrupt to a ruby thread, the ruby thread can be blocked. For example, it could be in the middle of a `TCPSocket#read` call. If so,
+the receiving thread's `ubf` (unblock function) gets called from the thread (ruby thread or timer thread) that sent the interrupt.
+Each ruby thread has a `ubf` that is set when it enters a blocking operation and is unset after returning from it. By default, this `ubf` function sends a
+`SIGVTALRM` to the receiving thread to try to unblock it from the kernel so it can check its interrupts. There are other `ubfs` that
+aren't associated with a syscall, such as when calling `Ractor#join` or `sleep`. All `ubfs` are called with the `interrupt_lock` held,
+so take that into account when using locks inside `ubfs`.
+
+Remember, `ubfs` can be called from the timer thread so you cannot assume an `ec` inside them. The `ec` (execution context) is only set on ruby threads.
+
+## The Timer Thread
+
+The timer thread has a few functions. They are:
+
+* Send interrupts to ruby threads that have run for their whole timeslice.
+* Wake up M:N ruby threads (threads in non-main ractors) blocked on IO or after a specified timeout. This
+uses `kqueue` or `epoll`, depending on the OS, to receive IO events on behalf of the threads.
+* Continue calling the `SIGVTARLM` signal if a thread is still blocked on a syscall after the first `ubf` call.
+* Signal native threads (`SNT`) waiting on a ractor if there are ractors waiting in the global run queue.
+* Create more `SNT`s if some are blocked, like on IO or on `Ractor#join`.
diff --git a/doc/contributing/documentation_guide.md b/doc/contributing/documentation_guide.md
index 8a73543e6c..7c73ad1c50 100644
--- a/doc/contributing/documentation_guide.md
+++ b/doc/contributing/documentation_guide.md
@@ -6,8 +6,8 @@ in the Ruby core and in the Ruby standard library.
## Generating documentation
-Most Ruby documentation lives in the source files and is written in
-[RDoc format](https://ruby.github.io/rdoc/RDoc/MarkupReference.html).
+Most Ruby documentation lives in the source files, and is written in RDoc format
+(described in the [RDoc Markup Reference]).
Some pages live under the `doc` folder and can be written in either
`.rdoc` or `.md` format, determined by the file extension.
@@ -20,12 +20,19 @@ build directory:
make html
```
+Or, to start a live-reloading server that automatically refreshes
+the browser when you edit source files:
+
+```sh
+make html-server
+```
+
+Then visit http://localhost:4000 in your browser.
+To use a different port: `make html-server RDOC_SERVER_PORT=8080`.
+
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
@@ -43,14 +50,12 @@ 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].
-- Refer to authoritative and relevant sources using
- [links](https://ruby.github.io/rdoc/RDoc/MarkupReference.html#class-RDoc::MarkupReference-label-Links).
+- Organize material with [headings].
+- Refer to authoritative and relevant sources using [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].
+ - Excessive comma-separated phrases; consider a [list][lists].
- Idioms and culture-specific references.
- Overuse of headings.
- Using US-ASCII-incompatible characters in C source files;
@@ -105,16 +110,16 @@ involving new files `doc/*.rdoc`:
*/
```
-### \RDoc
+### RDoc
Ruby is documented using RDoc.
-For information on \RDoc syntax and features, see the
-[RDoc Markup Reference](https://ruby.github.io/rdoc/RDoc/MarkupReference.html).
+For information on RDoc syntax and features,
+see the [RDoc Markup Reference].
### Output from `irb`
For code examples, consider using interactive Ruby,
-[irb](https://ruby-doc.org/stdlib/libdoc/irb/rdoc/IRB.html).
+[irb].
For a code example that includes `irb` output,
consider aligning `# => ...` in successive lines.
@@ -133,16 +138,15 @@ Organize a long discussion for a class or module with [headings].
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](https://ruby.github.io/rdoc/RDoc/MarkupReference.html#class-RDoc::MarkupReference-label-Bold)
-as pseudo-headings.
+within the documentation for a method or constant,
+use [bold text] as pseudo-headings.
### Blank Lines
A blank line begins a new paragraph.
-A [code block](https://ruby.github.io/rdoc/RDoc/MarkupReference.html#class-RDoc::MarkupReference-label-Code+Blocks)
-or [list] should be preceded by and followed by a blank line.
+A [code block][code blocks]
+or [list][lists] should be preceded by and followed by a blank line.
This is unnecessary for the HTML output, but helps in the `ri` output.
### \Method Names
@@ -185,7 +189,7 @@ renders as:
> - File.new
> - File#read.
-In general, \RDoc's auto-linking should not be suppressed.
+In general, RDoc's auto-linking should not be suppressed.
For example, we should write just plain _Float_ (which is auto-linked):
```rdoc
@@ -265,16 +269,16 @@ and _never_ when referring to the class itself.
When writing an explicit link, follow these guidelines.
-#### +rdoc-ref+ Scheme
+#### `rdoc-ref` Scheme
-Use the +rdoc-ref+ scheme for:
+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].
+See section "`rdoc-ref` Scheme" in [links].
#### URL-Based Link
@@ -291,13 +295,37 @@ 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.
+#### Fragments
+
+In general, a link that includes a [fragment][fragment]
+must cite the exact identifier on the target page;
+otherwise, the browser finds no suitable identifier,
+and does not scroll to the desired part of the page.
+
+However, certain pages on `github.com` and `github.io`
+support "fuzzy" identifier matching, so that URL
+https://github.com/rdp/ruby_tutorials_core/wiki/Ruby-Talk-FAQ#-why-are-rubys-floats-imprecise,
+(whose fragment is `-why-are-rubys-floats-imprecise`)
+scrolls to heading "Why are ruby’s floats imprecise?"
+even though the identifier there actually is the longer
+`#user-content--why-are-rubys-floats-imprecise`.
+
+Ruby documentation should avoid using these shortened fragments, for two reasons:
+
+- The GitHub pages that do this implement it using Javascript;
+ if the user's browser has Javascript disabled
+ (which some employers actually require),
+ the shortened fragment is ineffective and the desired scrolling does not occur.
+- A program that checks links in Ruby documentation will find no suitable identifier,
+ and therefore will report the fragment as not found.
+
### Variable Names
The name of a variable (as specified in its call-seq) should be marked up as
[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+).
+(i.e., one defined and used only in the discussion, such as `n`).
### HTML Tags
@@ -312,13 +340,12 @@ In particular, avoid building tables with HTML tags
Alternatives:
-- A {verbatim text block}[https://ruby.github.io/rdoc/RDoc/MarkupReference.html#class-RDoc::MarkupReference-label-Verbatim+Text+Blocks],
+- A [verbatim text block][verbatim text blocks],
using spaces and punctuation to format the text;
- note that {text markup}[https://ruby.github.io/rdoc/RDoc/MarkupReference.html#class-RDoc::MarkupReference-label-Text+Markup]
- will not be honored:
+ note that [text markup][text markup] will not be honored:
- Example {source}[https://github.com/ruby/ruby/blob/34d802f32f00df1ac0220b62f72605827c16bad8/file.c#L6570-L6596].
- - Corresponding {output}[rdoc-ref:File@Read-2FWrite+Mode].
+ - Corresponding {output}[rdoc-ref:File@ReadWrite+Mode].
- (Markdown format only): A {Github Flavored Markdown (GFM) table}[https://github.github.com/gfm/#tables-extension-],
using special formatting for the text:
@@ -326,6 +353,16 @@ Alternatives:
- 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].
+### Languages in Examples
+
+For symbols and strings in documentation examples:
+
+- Prefer \English in \English documentation: <tt>'Hello'</tt>.
+- Prefer Japanese in Japanese documentation: <tt>'ã“ã‚“ã«ã¡ã¯'</tt>.
+- If a second language is needed (as, for example, characters with different byte-sizes),
+ prefer Japanese in \English documentation and \English in Japanese documentation.
+- Use other languages examples only as necessary: see String#capitalize.
+
## Documenting Classes and Modules
The general structure of the class or module documentation should be:
@@ -364,9 +401,9 @@ Guidelines:
and a short description.
- If the method has aliases, mention them in parentheses before the colon
(and do not list the aliases separately).
- - Check the rendered documentation to determine whether \RDoc has recognized
+ - Check the rendered documentation to determine whether RDoc has recognized
the method and linked to it; if not, manually insert a
- [link](https://ruby.github.io/rdoc/RDoc/MarkupReference.html#class-RDoc::MarkupReference-label-Links).
+ [link][links].
- If there are numerous entries, consider grouping them into subsections with headings.
- If there are more than a few such subsections,
@@ -388,11 +425,11 @@ The general structure of the method documentation should be:
### Calling Sequence (for methods written in C)
-For methods written in Ruby, \RDoc documents the calling sequence automatically.
+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:`](https://ruby.github.io/rdoc/RDoc/MarkupReference.html#class-RDoc::MarkupReference-label-Directives+for+Method+Documentation).
+For methods written in C, RDoc cannot determine what arguments
+the method accepts, so those need to be documented using RDoc directive
+[`call-seq:`][call-seq]
For a singleton method, use the form:
@@ -481,10 +518,10 @@ Return types:
- If the method can return multiple different types,
separate the types with "or" and, if necessary, commas.
-- If the method can return multiple types, use +object+.
-- If the method returns the receiver, use +self+.
+- If the method can return multiple types, use `object`.
+- If the method returns the receiver, use `self`.
- If the method returns an object of the same class,
- prefix `new_` if and only if the object is not +self+;
+ prefix `new_` if and only if the object is not `self`;
example: `new_array`.
Aliases:
@@ -567,7 +604,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](https://ruby.github.io/rdoc/RDoc/MarkupReference.html#class-RDoc::MarkupReference-label-Labeled+Lists).
+[labeled list][lists].
### Corner Cases and Exceptions
@@ -608,6 +645,15 @@ For methods that accept multiple argument types, in some cases it can
be useful to document the different argument types separately. It's
best to use a separate paragraph for each case you are discussing.
-[headings]: https://ruby.github.io/rdoc/RDoc/MarkupReference.html#class-RDoc::MarkupReference-label-Headings
-[list]: https://ruby.github.io/rdoc/RDoc/MarkupReference.html#class-RDoc::MarkupReference-label-Lists
-[monofont]: https://ruby.github.io/rdoc/RDoc/MarkupReference.html#class-RDoc::MarkupReference-label-Monofont
+[bold text]: https://ruby.github.io/rdoc/doc/markup_reference/rdoc_rdoc.html#bold
+[call-seq]: https://ruby.github.io/rdoc/doc/markup_reference/rdoc_rdoc.html#directive-for-specifying-rdoc-source-format
+[code blocks]: https://ruby.github.io/rdoc/doc/markup_reference/rdoc_rdoc.html#code-blocks
+[fragment]: https://developer.mozilla.org/en-US/docs/Web/URI/Reference/Fragment
+[headings]: https://ruby.github.io/rdoc/doc/markup_reference/rdoc_rdoc.html#headings
+[irb]: https://ruby.github.io/irb/index.html
+[links]: https://ruby.github.io/rdoc/doc/markup_reference/rdoc_rdoc.html#links
+[lists]: https://ruby.github.io/rdoc/doc/markup_reference/rdoc_rdoc.html#lists
+[monofont]: https://ruby.github.io/rdoc/doc/markup_reference/rdoc_rdoc.html#monofont
+[RDoc Markup Reference]: https://ruby.github.io/rdoc/doc/markup_reference/rdoc_rdoc.html
+[text markup]: https://ruby.github.io/rdoc/doc/markup_reference/rdoc_rdoc.html#text-markup
+[verbatim text blocks]: https://ruby.github.io/rdoc/doc/markup_reference/rdoc_rdoc.html#verbatim-text-blocks
diff --git a/doc/dtrace_probes.rdoc b/doc/contributing/dtrace_probes.rdoc
index 1b20597ab4..1b20597ab4 100644
--- a/doc/dtrace_probes.rdoc
+++ b/doc/contributing/dtrace_probes.rdoc
diff --git a/doc/contributing/glossary.md b/doc/contributing/glossary.md
index 6f9c335028..3ec9796147 100644
--- a/doc/contributing/glossary.md
+++ b/doc/contributing/glossary.md
@@ -4,15 +4,17 @@ Just a list of acronyms I've run across in the Ruby source code and their meanin
| Term | Definition |
| --- | -----------|
+| `bmethod` | Method defined by `define_method() {}` (a Block that runs as a Method). |
| `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 |
| CFG | Control Flow Graph. Representation of the program where all control-flow and data dependencies have been made explicit by unrolling the stack and local variables. |
| `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`. |
+| `ci` | Call Information. Refers to an `rb_callinfo` struct. Contains call information about the call site, including number of parameters to be passed, whether they are keyword arguments or not, etc. Used in conjunction with the `cc` and `cd`. |
+| `cme` | Callable Method Entry. Refers to the `rb_callable_method_entry_t` struct, the internal representation of a Ruby method that has `defined_class` and `owner` set and is ready for dispatch. |
| `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 |
+| CRuby | Reference 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` |
@@ -33,10 +35,13 @@ Just a list of acronyms I've run across in the Ruby source code and their meanin
| `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 |
+| `snt` | Shared Native Thread. OS thread on which many ruby threads can run. Ruby threads from different ractors can even run on the same SNT. Ruby threads can switch SNTs when they context switch. SNTs are used in the M:N threading model. By default, non-main ractors use this model.
+| `dnt` | Dedicated Native Thread. OS thread on which only one ruby thread can run. The ruby thread always runs on that same OS thread. DNTs are used in the 1:1 threading model. By default, the main ractor uses this model.
| `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|
+| ST table | ST table is the main C implementation of a hash (smaller Ruby hashes may be backed by AR tables). |
| `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)
+| 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 |
diff --git a/doc/contributing/making_changes_to_stdlibs.md b/doc/contributing/making_changes_to_stdlibs.md
index 2156a61e39..2ceb2e6075 100644
--- a/doc/contributing/making_changes_to_stdlibs.md
+++ b/doc/contributing/making_changes_to_stdlibs.md
@@ -4,7 +4,7 @@ Everything in the [lib](https://github.com/ruby/ruby/tree/master/lib) directory
If you'd like to make contributions to standard libraries, do so in the standalone repositories, and the
changes will be automatically mirrored into the Ruby repository.
-For example, CSV lives in [a separate repository](https://github.com/ruby/csv) and is mirrored into [Ruby](https://github.com/ruby/ruby/tree/master/lib/csv).
+For example, ERB lives in [a separate repository](https://github.com/ruby/erb) and is mirrored into [Ruby](https://github.com/ruby/ruby/tree/master/lib/erb).
## Maintainers
diff --git a/doc/memory_view.md b/doc/contributing/memory_view.md
index 0b1369163d..0b1369163d 100644
--- a/doc/memory_view.md
+++ b/doc/contributing/memory_view.md
diff --git a/doc/contributing/vm_stack_and_frames.md b/doc/contributing/vm_stack_and_frames.md
new file mode 100644
index 0000000000..c7dc59db16
--- /dev/null
+++ b/doc/contributing/vm_stack_and_frames.md
@@ -0,0 +1,163 @@
+# Ruby VM Stack and Frame Layout
+
+This document explains the Ruby VM stack architecture, including how the value
+stack (SP) and control frames (CFP) share a single contiguous memory region,
+and how individual frames are structured.
+
+## VM Stack Architecture
+
+The Ruby VM uses a single contiguous stack (`ec->vm_stack`) with two different
+regions growing toward each other. Understanding this requires distinguishing
+the overall architecture (how CFPs and values share one stack) from individual
+frame internals (how values are organized for one single frame).
+
+```text
+High addresses (ec->vm_stack + ec->vm_stack_size)
+ ↓
+ [CFP region starts here] ↠RUBY_VM_END_CONTROL_FRAME(ec)
+ [CFP - 1] New frame pushed here (grows downward)
+ [CFP - 2] Another frame
+ ...
+
+ (Unused space - stack overflow when they meet)
+
+ ... Value stack grows UP toward higher addresses
+ [SP + n] Values pushed here
+ [ec->cfp->sp] Current executing frame's stack pointer
+ ↑
+Low addresses (ec->vm_stack)
+```
+
+The "unused space" represents free space available for new frames and values. When this gap closes (CFP meets SP), stack overflow occurs.
+
+### Stack Growth Directions
+
+**Control Frames (CFP):**
+
+- Start at `ec->vm_stack + ec->vm_stack_size` (high addresses)
+- Grow **downward** toward lower addresses as frames are pushed
+- Each new frame is allocated at `cfp - 1` (lower address)
+- The `rb_control_frame_t` structure itself moves downward
+
+**Value Stack (SP):**
+
+- Starts at `ec->vm_stack` (low addresses)
+- Grows **upward** toward higher addresses as values are pushed
+- Each frame's `cfp->sp` points to the top of its value stack
+
+### Stack Overflow
+
+When recursive calls push too many frames, CFP grows downward until it collides
+with SP growing upward. The VM detects this with `CHECK_VM_STACK_OVERFLOW0`,
+which computes `const rb_control_frame_struct *bound = (void *)&sp[margin];`
+and raises if `cfp <= &bound[1]`.
+
+## Understanding Individual Frame Value Stacks
+
+Each frame has its own portion of the overall VM stack, called its "VM value stack"
+or simply "value stack". This space is pre-allocated when the frame is created,
+with size determined by:
+
+- `local_size` - space for local variables
+- `stack_max` - maximum depth for temporary values during execution
+
+The frame's value stack grows upward from its base (where self/arguments/locals
+live) toward `cfp->sp` (the current top of temporary values).
+
+## Visualizing How Frames Fit in the VM Stack
+
+The left side shows the overall VM stack with CFP metadata separated from frame
+values. The right side zooms into one frame's value region, revealing its internal
+structure.
+
+```text
+Overall VM Stack (ec->vm_stack): Zooming into Frame 2's value stack:
+
+High addr (vm_stack + vm_stack_size) High addr (cfp->sp)
+ ↓ ┌
+ [CFP 1 metadata] │ [Temporaries]
+ [CFP 2 metadata] ─────────┠│ [Env: Flags/Block/CME] ↠cfp->ep
+ [CFP 3 metadata] │ │ [Locals]
+ ──────────────── │ ┌─┤ [Arguments]
+ (unused space) │ │ │ [self]
+ ──────────────── │ │ └
+ [Frame 3 values] │ │ Low addr (frame base)
+ [Frame 2 values] <────────┴───────┘
+ [Frame 1 values]
+ ↑
+Low addr (vm_stack)
+```
+
+## Examining a Single Frame's Value Stack
+
+Now let's walk through a concrete Ruby program to see how a single frame's
+value stack is structured internally:
+
+```ruby
+def foo(x, y)
+ z = x.casecmp(y)
+end
+
+foo(:one, :two)
+```
+
+First, after arguments are evaluated and right before the `send` to `foo`:
+
+```text
+ ┌────────────â”
+ putself │ :two │
+ putobject :one 0x2 ├────────────┤
+ putobject :two │ :one │
+► send <:foo, argc:2> 0x1 ├────────────┤
+ leave │ self │
+ 0x0 └────────────┘
+```
+
+The `put*` instructions have pushed 3 items onto the stack. It's now time to
+add a new control frame for `foo`. The following is the shape of the stack
+after one instruction in `foo`:
+
+```text
+ cfp->sp=0x8 at this point.
+ 0x8 ┌────────────â”◄──Stack space for temporaries
+ │ :one │ live above the environment.
+ 0x7 ├────────────┤
+ getlocal x@0 │ < flags > │ foo's rb_control_frame_t
+► getlocal y@1 0x6 ├────────────┤◄──has cfp->ep=0x6
+ send <:casecmp, argc:1> │ <no block> │
+ dup 0x5 ├────────────┤ The flags, block, and CME triple
+ setlocal z@2 │ <CME: foo> │ (VM_ENV_DATA_SIZE) form an
+ leave 0x4 ├────────────┤ environment. They can be used to
+ │ z (nil) │ figure out what local variables
+ 0x3 ├────────────┤ are below them.
+ │ :two │
+ 0x2 ├────────────┤ Notice how the arguments, now
+ │ :one │ locals, never moved. This layout
+ 0x1 ├────────────┤ allows for argument transfer
+ │ self │ without copying.
+ 0x0 └────────────┘
+```
+
+Given that locals have lower address than `cfp->ep`, it makes sense then that
+`getlocal` in `insns.def` has `val = *(vm_get_ep(GET_EP(), level) - idx);`.
+When accessing variables in the immediate scope, where `level=0`, it's
+essentially `val = cfp->ep[-idx];`.
+
+Note that this EP-relative index has a different basis than the index that comes
+after "@" in disassembly listings. The "@" index is relative to the 0th local
+(`x` in this case).
+
+### Q&A
+
+Q: It seems that the receiver is always at an offset relative to EP,
+ like locals. Couldn't we use EP to access it instead of using `cfp->self`?
+
+A: Not all calls put the `self` in the callee on the stack. Two
+ examples are `Proc#call`, where the receiver is the Proc object, but `self`
+ inside the callee is `Proc#receiver`, and `yield`, where the receiver isn't
+ pushed onto the stack before the arguments.
+
+Q: Why have `cfp->ep` when it seems that everything is below `cfp->sp`?
+
+A: In the example, `cfp->ep` points to the stack, but it can also point to the
+ GC heap. Blocks can capture and evacuate their environment to the heap.
diff --git a/doc/csv/arguments/io.rdoc b/doc/csv/arguments/io.rdoc
deleted file mode 100644
index f5fe1d1975..0000000000
--- a/doc/csv/arguments/io.rdoc
+++ /dev/null
@@ -1,5 +0,0 @@
-* Argument +io+ should be an IO object that is:
- * Open for reading; on return, the IO object will be closed.
- * Positioned at the beginning.
- To position at the end, for appending, use method CSV.generate.
- For any other positioning, pass a preset \StringIO object instead.
diff --git a/doc/csv/options/common/col_sep.rdoc b/doc/csv/options/common/col_sep.rdoc
deleted file mode 100644
index 3f23c6d2d3..0000000000
--- a/doc/csv/options/common/col_sep.rdoc
+++ /dev/null
@@ -1,57 +0,0 @@
-====== Option +col_sep+
-
-Specifies the \String field separator to be used
-for both parsing and generating.
-The \String will be transcoded into the data's \Encoding before use.
-
-Default value:
- CSV::DEFAULT_OPTIONS.fetch(:col_sep) # => "," (comma)
-
-Using the default (comma):
- str = CSV.generate do |csv|
- csv << [:foo, 0]
- csv << [:bar, 1]
- csv << [:baz, 2]
- end
- str # => "foo,0\nbar,1\nbaz,2\n"
- ary = CSV.parse(str)
- ary # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
-
-Using +:+ (colon):
- col_sep = ':'
- str = CSV.generate(col_sep: col_sep) do |csv|
- csv << [:foo, 0]
- csv << [:bar, 1]
- csv << [:baz, 2]
- end
- str # => "foo:0\nbar:1\nbaz:2\n"
- ary = CSV.parse(str, col_sep: col_sep)
- ary # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
-
-Using +::+ (two colons):
- col_sep = '::'
- str = CSV.generate(col_sep: col_sep) do |csv|
- csv << [:foo, 0]
- csv << [:bar, 1]
- csv << [:baz, 2]
- end
- str # => "foo::0\nbar::1\nbaz::2\n"
- ary = CSV.parse(str, col_sep: col_sep)
- ary # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
-
-Using <tt>''</tt> (empty string):
- col_sep = ''
- str = CSV.generate(col_sep: col_sep) do |csv|
- csv << [:foo, 0]
- csv << [:bar, 1]
- csv << [:baz, 2]
- end
- str # => "foo0\nbar1\nbaz2\n"
-
----
-
-Raises an exception if parsing with the empty \String:
- col_sep = ''
- # Raises ArgumentError (:col_sep must be 1 or more characters: "")
- CSV.parse("foo0\nbar1\nbaz2\n", col_sep: col_sep)
-
diff --git a/doc/csv/options/common/quote_char.rdoc b/doc/csv/options/common/quote_char.rdoc
deleted file mode 100644
index 67fd3af68b..0000000000
--- a/doc/csv/options/common/quote_char.rdoc
+++ /dev/null
@@ -1,42 +0,0 @@
-====== Option +quote_char+
-
-Specifies the character (\String of length 1) used used to quote fields
-in both parsing and generating.
-This String will be transcoded into the data's \Encoding before use.
-
-Default value:
- CSV::DEFAULT_OPTIONS.fetch(:quote_char) # => "\"" (double quote)
-
-This is useful for an application that incorrectly uses <tt>'</tt> (single-quote)
-to quote fields, instead of the correct <tt>"</tt> (double-quote).
-
-Using the default (double quote):
- str = CSV.generate do |csv|
- csv << ['foo', 0]
- csv << ["'bar'", 1]
- csv << ['"baz"', 2]
- end
- str # => "foo,0\n'bar',1\n\"\"\"baz\"\"\",2\n"
- ary = CSV.parse(str)
- ary # => [["foo", "0"], ["'bar'", "1"], ["\"baz\"", "2"]]
-
-Using <tt>'</tt> (single-quote):
- quote_char = "'"
- str = CSV.generate(quote_char: quote_char) do |csv|
- csv << ['foo', 0]
- csv << ["'bar'", 1]
- csv << ['"baz"', 2]
- end
- str # => "foo,0\n'''bar''',1\n\"baz\",2\n"
- ary = CSV.parse(str, quote_char: quote_char)
- ary # => [["foo", "0"], ["'bar'", "1"], ["\"baz\"", "2"]]
-
----
-
-Raises an exception if the \String length is greater than 1:
- # Raises ArgumentError (:quote_char has to be nil or a single character String)
- CSV.new('', quote_char: 'xx')
-
-Raises an exception if the value is not a \String:
- # Raises ArgumentError (:quote_char has to be nil or a single character String)
- CSV.new('', quote_char: :foo)
diff --git a/doc/csv/options/common/row_sep.rdoc b/doc/csv/options/common/row_sep.rdoc
deleted file mode 100644
index eae15b4a84..0000000000
--- a/doc/csv/options/common/row_sep.rdoc
+++ /dev/null
@@ -1,91 +0,0 @@
-====== Option +row_sep+
-
-Specifies the row separator, a \String or the \Symbol <tt>:auto</tt> (see below),
-to be used for both parsing and generating.
-
-Default value:
- CSV::DEFAULT_OPTIONS.fetch(:row_sep) # => :auto
-
----
-
-When +row_sep+ is a \String, that \String becomes the row separator.
-The String will be transcoded into the data's Encoding before use.
-
-Using <tt>"\n"</tt>:
- row_sep = "\n"
- str = CSV.generate(row_sep: row_sep) do |csv|
- csv << [:foo, 0]
- csv << [:bar, 1]
- csv << [:baz, 2]
- end
- str # => "foo,0\nbar,1\nbaz,2\n"
- ary = CSV.parse(str)
- ary # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
-
-Using <tt>|</tt> (pipe):
- row_sep = '|'
- str = CSV.generate(row_sep: row_sep) do |csv|
- csv << [:foo, 0]
- csv << [:bar, 1]
- csv << [:baz, 2]
- end
- str # => "foo,0|bar,1|baz,2|"
- ary = CSV.parse(str, row_sep: row_sep)
- ary # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
-
-Using <tt>--</tt> (two hyphens):
- row_sep = '--'
- str = CSV.generate(row_sep: row_sep) do |csv|
- csv << [:foo, 0]
- csv << [:bar, 1]
- csv << [:baz, 2]
- end
- str # => "foo,0--bar,1--baz,2--"
- ary = CSV.parse(str, row_sep: row_sep)
- ary # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
-
-Using <tt>''</tt> (empty string):
- row_sep = ''
- str = CSV.generate(row_sep: row_sep) do |csv|
- csv << [:foo, 0]
- csv << [:bar, 1]
- csv << [:baz, 2]
- end
- str # => "foo,0bar,1baz,2"
- ary = CSV.parse(str, row_sep: row_sep)
- ary # => [["foo", "0bar", "1baz", "2"]]
-
----
-
-When +row_sep+ is the \Symbol +:auto+ (the default),
-generating uses <tt>"\n"</tt> as the row separator:
- str = CSV.generate do |csv|
- csv << [:foo, 0]
- csv << [:bar, 1]
- csv << [:baz, 2]
- end
- str # => "foo,0\nbar,1\nbaz,2\n"
-
-Parsing, on the other hand, invokes auto-discovery of the row separator.
-
-Auto-discovery reads ahead in the data looking for the next <tt>\r\n</tt>, +\n+, or +\r+ sequence.
-The sequence will be selected even if it occurs in a quoted field,
-assuming that you would have the same line endings there.
-
-Example:
- str = CSV.generate do |csv|
- csv << [:foo, 0]
- csv << [:bar, 1]
- csv << [:baz, 2]
- end
- str # => "foo,0\nbar,1\nbaz,2\n"
- ary = CSV.parse(str)
- ary # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
-
-The default <tt>$INPUT_RECORD_SEPARATOR</tt> (<tt>$/</tt>) is used
-if any of the following is true:
-* None of those sequences is found.
-* Data is +ARGF+, +STDIN+, +STDOUT+, or +STDERR+.
-* 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.
diff --git a/doc/csv/options/generating/force_quotes.rdoc b/doc/csv/options/generating/force_quotes.rdoc
deleted file mode 100644
index 11afd1a16c..0000000000
--- a/doc/csv/options/generating/force_quotes.rdoc
+++ /dev/null
@@ -1,17 +0,0 @@
-====== Option +force_quotes+
-
-Specifies the boolean that determines whether each output field is to be double-quoted.
-
-Default value:
- CSV::DEFAULT_OPTIONS.fetch(:force_quotes) # => false
-
-For examples in this section:
- ary = ['foo', 0, nil]
-
-Using the default, +false+:
- str = CSV.generate_line(ary)
- str # => "foo,0,\n"
-
-Using +true+:
- str = CSV.generate_line(ary, force_quotes: true)
- str # => "\"foo\",\"0\",\"\"\n"
diff --git a/doc/csv/options/generating/quote_empty.rdoc b/doc/csv/options/generating/quote_empty.rdoc
deleted file mode 100644
index 4c5645c662..0000000000
--- a/doc/csv/options/generating/quote_empty.rdoc
+++ /dev/null
@@ -1,12 +0,0 @@
-====== Option +quote_empty+
-
-Specifies the boolean that determines whether an empty value is to be double-quoted.
-
-Default value:
- CSV::DEFAULT_OPTIONS.fetch(:quote_empty) # => true
-
-With the default +true+:
- CSV.generate_line(['"', ""]) # => "\"\"\"\",\"\"\n"
-
-With +false+:
- CSV.generate_line(['"', ""], quote_empty: false) # => "\"\"\"\",\n"
diff --git a/doc/csv/options/generating/write_converters.rdoc b/doc/csv/options/generating/write_converters.rdoc
deleted file mode 100644
index d1a9cc748f..0000000000
--- a/doc/csv/options/generating/write_converters.rdoc
+++ /dev/null
@@ -1,25 +0,0 @@
-====== Option +write_converters+
-
-Specifies converters to be used in generating fields.
-See {Write Converters}[#class-CSV-label-Write+Converters]
-
-Default value:
- CSV::DEFAULT_OPTIONS.fetch(:write_converters) # => nil
-
-With no write converter:
- str = CSV.generate_line(["\na\n", "\tb\t", " c "])
- str # => "\"\na\n\",\tb\t, c \n"
-
-With a write converter:
- strip_converter = proc {|field| field.strip }
- str = CSV.generate_line(["\na\n", "\tb\t", " c "], write_converters: strip_converter)
- str # => "a,b,c\n"
-
-With two write converters (called in order):
- upcase_converter = proc {|field| field.upcase }
- downcase_converter = proc {|field| field.downcase }
- write_converters = [upcase_converter, downcase_converter]
- str = CSV.generate_line(['a', 'b', 'c'], write_converters: write_converters)
- str # => "a,b,c\n"
-
-See also {Write Converters}[#class-CSV-label-Write+Converters]
diff --git a/doc/csv/options/generating/write_empty_value.rdoc b/doc/csv/options/generating/write_empty_value.rdoc
deleted file mode 100644
index 67be5662cb..0000000000
--- a/doc/csv/options/generating/write_empty_value.rdoc
+++ /dev/null
@@ -1,15 +0,0 @@
-====== Option +write_empty_value+
-
-Specifies the object that is to be substituted for each field
-that has an empty \String.
-
-Default value:
- CSV::DEFAULT_OPTIONS.fetch(:write_empty_value) # => ""
-
-Without the option:
- str = CSV.generate_line(['a', '', 'c', ''])
- str # => "a,\"\",c,\"\"\n"
-
-With the option:
- str = CSV.generate_line(['a', '', 'c', ''], write_empty_value: "x")
- str # => "a,x,c,x\n"
diff --git a/doc/csv/options/generating/write_headers.rdoc b/doc/csv/options/generating/write_headers.rdoc
deleted file mode 100644
index c56aa48adb..0000000000
--- a/doc/csv/options/generating/write_headers.rdoc
+++ /dev/null
@@ -1,29 +0,0 @@
-====== Option +write_headers+
-
-Specifies the boolean that determines whether a header row is included in the output;
-ignored if there are no headers.
-
-Default value:
- CSV::DEFAULT_OPTIONS.fetch(:write_headers) # => nil
-
-Without +write_headers+:
- file_path = 't.csv'
- CSV.open(file_path,'w',
- :headers => ['Name','Value']
- ) do |csv|
- csv << ['foo', '0']
- end
- CSV.open(file_path) do |csv|
- csv.shift
- end # => ["foo", "0"]
-
-With +write_headers+":
- CSV.open(file_path,'w',
- :write_headers => true,
- :headers => ['Name','Value']
- ) do |csv|
- csv << ['foo', '0']
- end
- CSV.open(file_path) do |csv|
- csv.shift
- end # => ["Name", "Value"]
diff --git a/doc/csv/options/generating/write_nil_value.rdoc b/doc/csv/options/generating/write_nil_value.rdoc
deleted file mode 100644
index 65d33ff54e..0000000000
--- a/doc/csv/options/generating/write_nil_value.rdoc
+++ /dev/null
@@ -1,14 +0,0 @@
-====== Option +write_nil_value+
-
-Specifies the object that is to be substituted for each +nil+-valued field.
-
-Default value:
- CSV::DEFAULT_OPTIONS.fetch(:write_nil_value) # => nil
-
-Without the option:
- str = CSV.generate_line(['a', nil, 'c', nil])
- str # => "a,,c,\n"
-
-With the option:
- str = CSV.generate_line(['a', nil, 'c', nil], write_nil_value: "x")
- str # => "a,x,c,x\n"
diff --git a/doc/csv/options/parsing/converters.rdoc b/doc/csv/options/parsing/converters.rdoc
deleted file mode 100644
index 211fa48de6..0000000000
--- a/doc/csv/options/parsing/converters.rdoc
+++ /dev/null
@@ -1,46 +0,0 @@
-====== Option +converters+
-
-Specifies converters to be used in parsing fields.
-See {Field Converters}[#class-CSV-label-Field+Converters]
-
-Default value:
- CSV::DEFAULT_OPTIONS.fetch(:converters) # => nil
-
-The value may be a field converter name
-(see {Stored Converters}[#class-CSV-label-Stored+Converters]):
- str = '1,2,3'
- # Without a converter
- array = CSV.parse_line(str)
- array # => ["1", "2", "3"]
- # With built-in converter :integer
- array = CSV.parse_line(str, converters: :integer)
- array # => [1, 2, 3]
-
-The value may be a converter list
-(see {Converter Lists}[#class-CSV-label-Converter+Lists]):
- str = '1,3.14159'
- # Without converters
- array = CSV.parse_line(str)
- array # => ["1", "3.14159"]
- # With built-in converters
- array = CSV.parse_line(str, converters: [:integer, :float])
- array # => [1, 3.14159]
-
-The value may be a \Proc custom converter:
-(see {Custom Field Converters}[#class-CSV-label-Custom+Field+Converters]):
- str = ' foo , bar , baz '
- # Without a converter
- array = CSV.parse_line(str)
- array # => [" foo ", " bar ", " baz "]
- # With a custom converter
- array = CSV.parse_line(str, converters: proc {|field| field.strip })
- array # => ["foo", "bar", "baz"]
-
-See also {Custom Field Converters}[#class-CSV-label-Custom+Field+Converters]
-
----
-
-Raises an exception if the converter is not a converter name or a \Proc:
- str = 'foo,0'
- # Raises NoMethodError (undefined method `arity' for nil:NilClass)
- CSV.parse(str, converters: :foo)
diff --git a/doc/csv/options/parsing/empty_value.rdoc b/doc/csv/options/parsing/empty_value.rdoc
deleted file mode 100644
index 7d3bcc078c..0000000000
--- a/doc/csv/options/parsing/empty_value.rdoc
+++ /dev/null
@@ -1,13 +0,0 @@
-====== Option +empty_value+
-
-Specifies the object that is to be substituted
-for each field that has an empty \String.
-
-Default value:
- CSV::DEFAULT_OPTIONS.fetch(:empty_value) # => "" (empty string)
-
-With the default, <tt>""</tt>:
- CSV.parse_line('a,"",b,"",c') # => ["a", "", "b", "", "c"]
-
-With a different object:
- CSV.parse_line('a,"",b,"",c', empty_value: 'x') # => ["a", "x", "b", "x", "c"]
diff --git a/doc/csv/options/parsing/field_size_limit.rdoc b/doc/csv/options/parsing/field_size_limit.rdoc
deleted file mode 100644
index 797c5776fc..0000000000
--- a/doc/csv/options/parsing/field_size_limit.rdoc
+++ /dev/null
@@ -1,39 +0,0 @@
-====== Option +field_size_limit+
-
-Specifies the \Integer field size limit.
-
-Default value:
- CSV::DEFAULT_OPTIONS.fetch(:field_size_limit) # => nil
-
-This is a maximum size CSV will read ahead looking for the closing quote for a field.
-(In truth, it reads to the first line ending beyond this size.)
-If a quote cannot be found within the limit CSV will raise a MalformedCSVError,
-assuming the data is faulty.
-You can use this limit to prevent what are effectively DoS attacks on the parser.
-However, this limit can cause a legitimate parse to fail;
-therefore the default value is +nil+ (no limit).
-
-For the examples in this section:
- str = <<~EOT
- "a","b"
- "
- 2345
- ",""
- EOT
- str # => "\"a\",\"b\"\n\"\n2345\n\",\"\"\n"
-
-Using the default +nil+:
- ary = CSV.parse(str)
- ary # => [["a", "b"], ["\n2345\n", ""]]
-
-Using <tt>50</tt>:
- field_size_limit = 50
- ary = CSV.parse(str, field_size_limit: field_size_limit)
- ary # => [["a", "b"], ["\n2345\n", ""]]
-
----
-
-Raises an exception if a field is too long:
- big_str = "123456789\n" * 1024
- # Raises CSV::MalformedCSVError (Field size exceeded in line 1.)
- CSV.parse('valid,fields,"' + big_str + '"', field_size_limit: 2048)
diff --git a/doc/csv/options/parsing/header_converters.rdoc b/doc/csv/options/parsing/header_converters.rdoc
deleted file mode 100644
index 309180805f..0000000000
--- a/doc/csv/options/parsing/header_converters.rdoc
+++ /dev/null
@@ -1,43 +0,0 @@
-====== Option +header_converters+
-
-Specifies converters to be used in parsing headers.
-See {Header Converters}[#class-CSV-label-Header+Converters]
-
-Default value:
- CSV::DEFAULT_OPTIONS.fetch(:header_converters) # => nil
-
-Identical in functionality to option {converters}[#class-CSV-label-Option+converters]
-except that:
-- The converters apply only to the header row.
-- The built-in header converters are +:downcase+ and +:symbol+.
-
-This section assumes prior execution of:
- str = <<-EOT
- Name,Value
- foo,0
- bar,1
- baz,2
- EOT
- # With no header converter
- table = CSV.parse(str, headers: true)
- table.headers # => ["Name", "Value"]
-
-The value may be a header converter name
-(see {Stored Converters}[#class-CSV-label-Stored+Converters]):
- table = CSV.parse(str, headers: true, header_converters: :downcase)
- table.headers # => ["name", "value"]
-
-The value may be a converter list
-(see {Converter Lists}[#class-CSV-label-Converter+Lists]):
- header_converters = [:downcase, :symbol]
- table = CSV.parse(str, headers: true, header_converters: header_converters)
- table.headers # => [:name, :value]
-
-The value may be a \Proc custom converter
-(see {Custom Header Converters}[#class-CSV-label-Custom+Header+Converters]):
- upcase_converter = proc {|field| field.upcase }
- table = CSV.parse(str, headers: true, header_converters: upcase_converter)
- table.headers # => ["NAME", "VALUE"]
-
-See also {Custom Header Converters}[#class-CSV-label-Custom+Header+Converters]
-
diff --git a/doc/csv/options/parsing/headers.rdoc b/doc/csv/options/parsing/headers.rdoc
deleted file mode 100644
index 0ea151f24b..0000000000
--- a/doc/csv/options/parsing/headers.rdoc
+++ /dev/null
@@ -1,63 +0,0 @@
-====== Option +headers+
-
-Specifies a boolean, \Symbol, \Array, or \String to be used
-to define column headers.
-
-Default value:
- CSV::DEFAULT_OPTIONS.fetch(:headers) # => false
-
----
-
-Without +headers+:
- str = <<-EOT
- Name,Count
- foo,0
- bar,1
- bax,2
- EOT
- csv = CSV.new(str)
- csv # => #<CSV io_type:StringIO encoding:UTF-8 lineno:0 col_sep:"," row_sep:"\n" quote_char:"\"">
- csv.headers # => nil
- csv.shift # => ["Name", "Count"]
-
----
-
-If set to +true+ or the \Symbol +:first_row+,
-the first row of the data is treated as a row of headers:
- str = <<-EOT
- Name,Count
- foo,0
- bar,1
- bax,2
- EOT
- csv = CSV.new(str, headers: true)
- csv # => #<CSV io_type:StringIO encoding:UTF-8 lineno:2 col_sep:"," row_sep:"\n" quote_char:"\"" headers:["Name", "Count"]>
- csv.headers # => ["Name", "Count"]
- csv.shift # => #<CSV::Row "Name":"bar" "Count":"1">
-
----
-
-If set to an \Array, the \Array elements are treated as headers:
- str = <<-EOT
- foo,0
- bar,1
- bax,2
- EOT
- csv = CSV.new(str, headers: ['Name', 'Count'])
- csv
- csv.headers # => ["Name", "Count"]
- csv.shift # => #<CSV::Row "Name":"bar" "Count":"1">
-
----
-
-If set to a \String +str+, method <tt>CSV::parse_line(str, options)</tt> is called
-with the current +options+, and the returned \Array is treated as headers:
- str = <<-EOT
- foo,0
- bar,1
- bax,2
- EOT
- csv = CSV.new(str, headers: 'Name,Count')
- csv
- csv.headers # => ["Name", "Count"]
- csv.shift # => #<CSV::Row "Name":"bar" "Count":"1">
diff --git a/doc/csv/options/parsing/liberal_parsing.rdoc b/doc/csv/options/parsing/liberal_parsing.rdoc
deleted file mode 100644
index 603de28613..0000000000
--- a/doc/csv/options/parsing/liberal_parsing.rdoc
+++ /dev/null
@@ -1,38 +0,0 @@
-====== Option +liberal_parsing+
-
-Specifies the boolean or hash 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:
- str = 'is,this "three, or four",fields'
-
-Without +liberal_parsing+:
- # Raises CSV::MalformedCSVError (Illegal quoting in str 1.)
- CSV.parse_line(str)
-
-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/options/parsing/nil_value.rdoc b/doc/csv/options/parsing/nil_value.rdoc
deleted file mode 100644
index 412e8795e8..0000000000
--- a/doc/csv/options/parsing/nil_value.rdoc
+++ /dev/null
@@ -1,12 +0,0 @@
-====== Option +nil_value+
-
-Specifies the object that is to be substituted for each null (no-text) field.
-
-Default value:
- CSV::DEFAULT_OPTIONS.fetch(:nil_value) # => nil
-
-With the default, +nil+:
- CSV.parse_line('a,,b,,c') # => ["a", nil, "b", nil, "c"]
-
-With a different object:
- CSV.parse_line('a,,b,,c', nil_value: 0) # => ["a", 0, "b", 0, "c"]
diff --git a/doc/csv/options/parsing/return_headers.rdoc b/doc/csv/options/parsing/return_headers.rdoc
deleted file mode 100644
index 45d2e3f3de..0000000000
--- a/doc/csv/options/parsing/return_headers.rdoc
+++ /dev/null
@@ -1,22 +0,0 @@
-====== Option +return_headers+
-
-Specifies the boolean that determines whether method #shift
-returns or ignores the header row.
-
-Default value:
- CSV::DEFAULT_OPTIONS.fetch(:return_headers) # => false
-
-Examples:
- str = <<-EOT
- Name,Count
- foo,0
- bar,1
- bax,2
- EOT
- # Without return_headers first row is str.
- csv = CSV.new(str, headers: true)
- csv.shift # => #<CSV::Row "Name":"foo" "Count":"0">
- # With return_headers first row is headers.
- csv = CSV.new(str, headers: true, return_headers: true)
- csv.shift # => #<CSV::Row "Name":"Name" "Count":"Count">
-
diff --git a/doc/csv/options/parsing/skip_blanks.rdoc b/doc/csv/options/parsing/skip_blanks.rdoc
deleted file mode 100644
index 2c8f7b7bb8..0000000000
--- a/doc/csv/options/parsing/skip_blanks.rdoc
+++ /dev/null
@@ -1,31 +0,0 @@
-====== Option +skip_blanks+
-
-Specifies a boolean that determines whether blank lines in the input will be ignored;
-a line that contains a column separator is not considered to be blank.
-
-Default value:
- CSV::DEFAULT_OPTIONS.fetch(:skip_blanks) # => false
-
-See also option {skiplines}[#class-CSV-label-Option+skip_lines].
-
-For examples in this section:
- str = <<-EOT
- foo,0
-
- bar,1
- baz,2
-
- ,
- EOT
-
-Using the default, +false+:
- ary = CSV.parse(str)
- ary # => [["foo", "0"], [], ["bar", "1"], ["baz", "2"], [], [nil, nil]]
-
-Using +true+:
- ary = CSV.parse(str, skip_blanks: true)
- ary # => [["foo", "0"], ["bar", "1"], ["baz", "2"], [nil, nil]]
-
-Using a truthy value:
- ary = CSV.parse(str, skip_blanks: :foo)
- ary # => [["foo", "0"], ["bar", "1"], ["baz", "2"], [nil, nil]]
diff --git a/doc/csv/options/parsing/skip_lines.rdoc b/doc/csv/options/parsing/skip_lines.rdoc
deleted file mode 100644
index 1481c40a5f..0000000000
--- a/doc/csv/options/parsing/skip_lines.rdoc
+++ /dev/null
@@ -1,37 +0,0 @@
-====== Option +skip_lines+
-
-Specifies an object to use in identifying comment lines in the input that are to be ignored:
-* If a \Regexp, ignores lines that match it.
-* If a \String, converts it to a \Regexp, ignores lines that match it.
-* If +nil+, no lines are considered to be comments.
-
-Default value:
- CSV::DEFAULT_OPTIONS.fetch(:skip_lines) # => nil
-
-For examples in this section:
- str = <<-EOT
- # Comment
- foo,0
- bar,1
- baz,2
- # Another comment
- EOT
- str # => "# Comment\nfoo,0\nbar,1\nbaz,2\n# Another comment\n"
-
-Using the default, +nil+:
- ary = CSV.parse(str)
- ary # => [["# Comment"], ["foo", "0"], ["bar", "1"], ["baz", "2"], ["# Another comment"]]
-
-Using a \Regexp:
- ary = CSV.parse(str, skip_lines: /^#/)
- ary # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
-
-Using a \String:
- ary = CSV.parse(str, skip_lines: '#')
- ary # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
-
----
-
-Raises an exception if given an object that is not a \Regexp, a \String, or +nil+:
- # Raises ArgumentError (:skip_lines has to respond to #match: 0)
- CSV.parse(str, skip_lines: 0)
diff --git a/doc/csv/options/parsing/strip.rdoc b/doc/csv/options/parsing/strip.rdoc
deleted file mode 100644
index 56ae4310c3..0000000000
--- a/doc/csv/options/parsing/strip.rdoc
+++ /dev/null
@@ -1,15 +0,0 @@
-====== Option +strip+
-
-Specifies the boolean value that determines whether
-whitespace is stripped from each input field.
-
-Default value:
- CSV::DEFAULT_OPTIONS.fetch(:strip) # => false
-
-With default value +false+:
- ary = CSV.parse_line(' a , b ')
- ary # => [" a ", " b "]
-
-With value +true+:
- ary = CSV.parse_line(' a , b ', strip: true)
- ary # => ["a", "b"]
diff --git a/doc/csv/options/parsing/unconverted_fields.rdoc b/doc/csv/options/parsing/unconverted_fields.rdoc
deleted file mode 100644
index 3e7f839d49..0000000000
--- a/doc/csv/options/parsing/unconverted_fields.rdoc
+++ /dev/null
@@ -1,27 +0,0 @@
-====== Option +unconverted_fields+
-
-Specifies the boolean that determines whether unconverted field values are to be available.
-
-Default value:
- CSV::DEFAULT_OPTIONS.fetch(:unconverted_fields) # => nil
-
-The unconverted field values are those found in the source data,
-prior to any conversions performed via option +converters+.
-
-When option +unconverted_fields+ is +true+,
-each returned row (\Array or \CSV::Row) has an added method,
-+unconverted_fields+, that returns the unconverted field values:
- str = <<-EOT
- foo,0
- bar,1
- baz,2
- EOT
- # Without unconverted_fields
- csv = CSV.parse(str, converters: :integer)
- csv # => [["foo", 0], ["bar", 1], ["baz", 2]]
- csv.first.respond_to?(:unconverted_fields) # => false
- # With unconverted_fields
- csv = CSV.parse(str, converters: :integer, unconverted_fields: true)
- csv # => [["foo", 0], ["bar", 1], ["baz", 2]]
- csv.first.respond_to?(:unconverted_fields) # => true
- csv.first.unconverted_fields # => ["foo", "0"]
diff --git a/doc/csv/recipes/filtering.rdoc b/doc/csv/recipes/filtering.rdoc
deleted file mode 100644
index 1552bf0fb8..0000000000
--- a/doc/csv/recipes/filtering.rdoc
+++ /dev/null
@@ -1,158 +0,0 @@
-== 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:
- require 'csv'
-
-=== Contents
-
-- {Source and Output Formats}[#label-Source+and+Output+Formats]
- - {Filtering String to String}[#label-Filtering+String+to+String]
- - {Recipe: Filter String to String with Headers}[#label-Recipe-3A+Filter+String+to+String+with+Headers]
- - {Recipe: Filter String to String Without Headers}[#label-Recipe-3A+Filter+String+to+String+Without+Headers]
- - {Filtering String to IO Stream}[#label-Filtering+String+to+IO+Stream]
- - {Recipe: Filter String to IO Stream with Headers}[#label-Recipe-3A+Filter+String+to+IO+Stream+with+Headers]
- - {Recipe: Filter String to IO Stream Without Headers}[#label-Recipe-3A+Filter+String+to+IO+Stream+Without+Headers]
- - {Filtering IO Stream to String}[#label-Filtering+IO+Stream+to+String]
- - {Recipe: Filter IO Stream to String with Headers}[#label-Recipe-3A+Filter+IO+Stream+to+String+with+Headers]
- - {Recipe: Filter IO Stream to String Without Headers}[#label-Recipe-3A+Filter+IO+Stream+to+String+Without+Headers]
- - {Filtering IO Stream to IO Stream}[#label-Filtering+IO+Stream+to+IO+Stream]
- - {Recipe: Filter IO Stream to IO Stream with Headers}[#label-Recipe-3A+Filter+IO+Stream+to+IO+Stream+with+Headers]
- - {Recipe: Filter IO Stream to IO Stream Without Headers}[#label-Recipe-3A+Filter+IO+Stream+to+IO+Stream+Without+Headers]
-
-=== Source and Output Formats
-
-You can use a Unix-style "filter" for \CSV data.
-The filter reads source \CSV data and writes output \CSV data as modified by the filter.
-The input and output \CSV data may be any mixture of \Strings and \IO streams.
-
-==== Filtering \String to \String
-
-You can filter one \String to another, with or without headers.
-
-===== Recipe: Filter \String to \String with Headers
-
-Use class method CSV.filter with option +headers+ to filter a \String to another \String:
- in_string = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
- out_string = ''
- CSV.filter(in_string, out_string, headers: true) do |row|
- row[0] = row[0].upcase
- row[1] *= 4
- end
- out_string # => "Name,Value\nFOO,0000\nBAR,1111\nBAZ,2222\n"
-
-===== Recipe: Filter \String to \String Without Headers
-
-Use class method CSV.filter without option +headers+ to filter a \String to another \String:
- 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"
-
-==== Filtering \String to \IO Stream
-
-You can filter a \String to an \IO stream, with or without headers.
-
-===== Recipe: Filter \String to \IO Stream with Headers
-
-Use class method CSV.filter with option +headers+ to filter a \String to an \IO stream:
- in_string = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
- path = 't.csv'
- File.open(path, 'w') do |out_io|
- CSV.filter(in_string, out_io, headers: true) do |row|
- row[0] = row[0].upcase
- row[1] *= 4
- end
- end
- p File.read(path) # => "Name,Value\nFOO,0000\nBAR,1111\nBAZ,2222\n"
-
-===== Recipe: Filter \String to \IO Stream Without Headers
-
-Use class method CSV.filter without option +headers+ to filter a \String to an \IO stream:
- in_string = "foo,0\nbar,1\nbaz,2\n"
- path = 't.csv'
- File.open(path, 'w') do |out_io|
- CSV.filter(in_string, out_io) do |row|
- row[0] = row[0].upcase
- row[1] *= 4
- end
- end
- p File.read(path) # => "FOO,0000\nBAR,1111\nBAZ,2222\n"
-
-==== Filtering \IO Stream to \String
-
-You can filter an \IO stream to a \String, with or without headers.
-
-===== Recipe: Filter \IO Stream to \String with Headers
-
-Use class method CSV.filter with option +headers+ to filter an \IO stream to a \String:
- in_string = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
- path = 't.csv'
- File.write(path, in_string)
- out_string = ''
- File.open(path, headers: true) do |in_io|
- CSV.filter(in_io, out_string, headers: true) do |row|
- row[0] = row[0].upcase
- row[1] *= 4
- end
- end
- out_string # => "Name,Value\nFOO,0000\nBAR,1111\nBAZ,2222\n"
-
-===== Recipe: Filter \IO Stream to \String Without Headers
-
-Use class method CSV.filter without option +headers+ to filter an \IO stream to a \String:
- in_string = "foo,0\nbar,1\nbaz,2\n"
- path = 't.csv'
- File.write(path, in_string)
- out_string = ''
- File.open(path) do |in_io|
- CSV.filter(in_io, out_string) do |row|
- row[0] = row[0].upcase
- row[1] *= 4
- end
- end
- out_string # => "FOO,0000\nBAR,1111\nBAZ,2222\n"
-
-==== Filtering \IO Stream to \IO Stream
-
-You can filter an \IO stream to another \IO stream, with or without headers.
-
-===== Recipe: Filter \IO Stream to \IO Stream with Headers
-
-Use class method CSV.filter with option +headers+ to filter an \IO stream to another \IO stream:
- in_path = 't.csv'
- in_string = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
- File.write(in_path, in_string)
- out_path = 'u.csv'
- File.open(in_path) do |in_io|
- File.open(out_path, 'w') do |out_io|
- CSV.filter(in_io, out_io, headers: true) do |row|
- row[0] = row[0].upcase
- row[1] *= 4
- end
- end
- end
- p File.read(out_path) # => "Name,Value\nFOO,0000\nBAR,1111\nBAZ,2222\n"
-
-===== Recipe: Filter \IO Stream to \IO Stream Without Headers
-
-Use class method CSV.filter without option +headers+ to filter an \IO stream to another \IO stream:
- in_path = 't.csv'
- in_string = "foo,0\nbar,1\nbaz,2\n"
- File.write(in_path, in_string)
- out_path = 'u.csv'
- File.open(in_path) do |in_io|
- File.open(out_path, 'w') do |out_io|
- CSV.filter(in_io, out_io) do |row|
- row[0] = row[0].upcase
- row[1] *= 4
- end
- end
- end
- p File.read(out_path) # => "FOO,0000\nBAR,1111\nBAZ,2222\n"
diff --git a/doc/csv/recipes/generating.rdoc b/doc/csv/recipes/generating.rdoc
deleted file mode 100644
index e61838d31a..0000000000
--- a/doc/csv/recipes/generating.rdoc
+++ /dev/null
@@ -1,246 +0,0 @@
-== 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:
- require 'csv'
-
-=== Contents
-
-- {Output Formats}[#label-Output+Formats]
- - {Generating to a String}[#label-Generating+to+a+String]
- - {Recipe: Generate to String with Headers}[#label-Recipe-3A+Generate+to+String+with+Headers]
- - {Recipe: Generate to String Without Headers}[#label-Recipe-3A+Generate+to+String+Without+Headers]
- - {Generating to a File}[#label-Generating+to+a+File]
- - {Recipe: Generate to File with Headers}[#label-Recipe-3A+Generate+to+File+with+Headers]
- - {Recipe: Generate to File Without Headers}[#label-Recipe-3A+Generate+to+File+Without+Headers]
- - {Generating to IO an Stream}[#label-Generating+to+an+IO+Stream]
- - {Recipe: Generate to IO Stream with Headers}[#label-Recipe-3A+Generate+to+IO+Stream+with+Headers]
- - {Recipe: Generate to IO Stream Without Headers}[#label-Recipe-3A+Generate+to+IO+Stream+Without+Headers]
-- {Converting Fields}[#label-Converting+Fields]
- - {Recipe: Filter Generated Field Strings}[#label-Recipe-3A+Filter+Generated+Field+Strings]
- - {Recipe: Specify Multiple Write Converters}[#label-Recipe-3A+Specify+Multiple+Write+Converters]
-- {RFC 4180 Compliance}[#label-RFC+4180+Compliance]
- - {Row Separator}[#label-Row+Separator]
- - {Recipe: Generate Compliant Row Separator}[#label-Recipe-3A+Generate+Compliant+Row+Separator]
- - {Recipe: Generate Non-Compliant Row Separator}[#label-Recipe-3A+Generate+Non-Compliant+Row+Separator]
- - {Column Separator}[#label-Column+Separator]
- - {Recipe: Generate Compliant Column Separator}[#label-Recipe-3A+Generate+Compliant+Column+Separator]
- - {Recipe: Generate Non-Compliant Column Separator}[#label-Recipe-3A+Generate+Non-Compliant+Column+Separator]
- - {Quote Character}[#label-Quote+Character]
- - {Recipe: Generate Compliant Quote Character}[#label-Recipe-3A+Generate+Compliant+Quote+Character]
- - {Recipe: Generate Non-Compliant Quote Character}[#label-Recipe-3A+Generate+Non-Compliant+Quote+Character]
-
-=== Output Formats
-
-You can generate \CSV output to a \String, to a \File (via its path), or to an \IO stream.
-
-==== Generating to a \String
-
-You can generate \CSV output to a \String, with or without headers.
-
-===== Recipe: Generate to \String with Headers
-
-Use class method CSV.generate with option +headers+ to generate to a \String.
-
-This example uses method CSV#<< to append the rows
-that are to be generated:
- output_string = CSV.generate('', headers: ['Name', 'Value'], write_headers: true) do |csv|
- csv << ['Foo', 0]
- csv << ['Bar', 1]
- csv << ['Baz', 2]
- end
- output_string # => "Name,Value\nFoo,0\nBar,1\nBaz,2\n"
-
-===== Recipe: Generate to \String Without Headers
-
-Use class method CSV.generate without option +headers+ to generate to 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"
-
-==== Generating to a \File
-
-You can generate /CSV data to a \File, with or without headers.
-
-===== Recipe: Generate to \File with Headers
-
-Use class method CSV.open with option +headers+ generate to a \File.
-
-This example uses method CSV#<< to append the rows
-that are to be generated:
- path = 't.csv'
- CSV.open(path, 'w', headers: ['Name', 'Value'], write_headers: true) do |csv|
- csv << ['Foo', 0]
- csv << ['Bar', 1]
- csv << ['Baz', 2]
- end
- p File.read(path) # => "Name,Value\nFoo,0\nBar,1\nBaz,2\n"
-
-===== Recipe: Generate to \File Without Headers
-
-Use class method CSV.open without option +headers+ to generate to a \File.
-
-This example uses method CSV#<< to append the rows
-that are to be generated:
- path = 't.csv'
- CSV.open(path, 'w') do |csv|
- csv << ['Foo', 0]
- csv << ['Bar', 1]
- csv << ['Baz', 2]
- end
- p File.read(path) # => "Foo,0\nBar,1\nBaz,2\n"
-
-==== Generating to an \IO Stream
-
-You can generate \CSV data to an \IO stream, with or without headers.
-
-==== Recipe: Generate to \IO Stream with Headers
-
-Use class method CSV.new with option +headers+ to generate \CSV data to an \IO stream:
- path = 't.csv'
- File.open(path, 'w') do |file|
- csv = CSV.new(file, headers: ['Name', 'Value'], write_headers: true)
- csv << ['Foo', 0]
- csv << ['Bar', 1]
- csv << ['Baz', 2]
- end
- p File.read(path) # => "Name,Value\nFoo,0\nBar,1\nBaz,2\n"
-
-===== Recipe: Generate to \IO Stream Without Headers
-
-Use class method CSV.new without option +headers+ to generate \CSV data to an \IO stream:
- path = 't.csv'
- File.open(path, 'w') do |file|
- csv = CSV.new(file)
- csv << ['Foo', 0]
- csv << ['Bar', 1]
- csv << ['Baz', 2]
- end
- p File.read(path) # => "Foo,0\nBar,1\nBaz,2\n"
-
-=== Converting Fields
-
-You can use _write_ _converters_ to convert fields when generating \CSV.
-
-==== Recipe: Filter Generated Field Strings
-
-Use option <tt>:write_converters</tt> and a custom converter to convert field values when generating \CSV.
-
-This example defines and uses a custom write converter to strip whitespace from generated fields:
- strip_converter = proc {|field| field.respond_to?(:strip) ? field.strip : field }
- output_string = CSV.generate(write_converters: strip_converter) do |csv|
- csv << [' foo ', 0]
- csv << [' bar ', 1]
- csv << [' baz ', 2]
- end
- output_string # => "foo,0\nbar,1\nbaz,2\n"
-
-==== Recipe: Specify Multiple Write Converters
-
-Use option <tt>:write_converters</tt> and multiple custom converters
-to convert field values when generating \CSV.
-
-This example defines and uses two custom write converters to strip and upcase generated fields:
- strip_converter = proc {|field| field.respond_to?(:strip) ? field.strip : field }
- upcase_converter = proc {|field| field.respond_to?(:upcase) ? field.upcase : field }
- converters = [strip_converter, upcase_converter]
- output_string = CSV.generate(write_converters: converters) do |csv|
- csv << [' foo ', 0]
- csv << [' bar ', 1]
- csv << [' baz ', 2]
- end
- output_string # => "FOO,0\nBAR,1\nBAZ,2\n"
-
-=== RFC 4180 Compliance
-
-By default, \CSV generates data that is compliant with
-{RFC 4180}[https://www.rfc-editor.org/rfc/rfc4180]
-with respect to:
-- Column separator.
-- Quote character.
-
-==== Row Separator
-
-RFC 4180 specifies the row separator CRLF (Ruby <tt>"\r\n"</tt>).
-
-===== Recipe: Generate Compliant Row Separator
-
-For strict compliance, use option +:row_sep+ to specify row separator <tt>"\r\n"</tt>:
- output_string = CSV.generate('', row_sep: "\r\n") do |csv|
- csv << ['Foo', 0]
- csv << ['Bar', 1]
- csv << ['Baz', 2]
- end
- output_string # => "Foo,0\r\nBar,1\r\nBaz,2\r\n"
-
-===== Recipe: Generate Non-Compliant Row Separator
-
-For data with non-compliant row separators, use option +:row_sep+ with a different value:
-This example source uses semicolon (<tt>";'</tt>) as its row separator:
- output_string = CSV.generate('', row_sep: ";") do |csv|
- csv << ['Foo', 0]
- csv << ['Bar', 1]
- csv << ['Baz', 2]
- end
- output_string # => "Foo,0;Bar,1;Baz,2;"
-
-==== Column Separator
-
-RFC 4180 specifies column separator COMMA (Ruby <tt>","</tt>).
-
-===== Recipe: Generate Compliant Column Separator
-
-Because the \CSV default comma separator is <tt>","</tt>,
-you need not specify option +:col_sep+ for compliant data:
- 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"
-
-===== Recipe: Generate Non-Compliant Column Separator
-
-For data with non-compliant column separators, use option +:col_sep+.
-This example source uses TAB (<tt>"\t"</tt>) as its column separator:
- output_string = CSV.generate('', col_sep: "\t") do |csv|
- csv << ['Foo', 0]
- csv << ['Bar', 1]
- csv << ['Baz', 2]
- end
- output_string # => "Foo\t0\nBar\t1\nBaz\t2\n"
-
-==== Quote Character
-
-RFC 4180 specifies quote character DQUOTE (Ruby <tt>"\""</tt>).
-
-===== Recipe: Generate Compliant Quote Character
-
-Because the \CSV default quote character is <tt>"\""</tt>,
-you need not specify option +:quote_char+ for compliant data:
- output_string = CSV.generate('', force_quotes: true) do |csv|
- csv << ['Foo', 0]
- csv << ['Bar', 1]
- csv << ['Baz', 2]
- end
- output_string # => "\"Foo\",\"0\"\n\"Bar\",\"1\"\n\"Baz\",\"2\"\n"
-
-===== Recipe: Generate Non-Compliant Quote Character
-
-For data with non-compliant quote characters, use option +:quote_char+.
-This example source uses SQUOTE (<tt>"'"</tt>) as its quote character:
- output_string = CSV.generate('', quote_char: "'", force_quotes: true) do |csv|
- csv << ['Foo', 0]
- csv << ['Bar', 1]
- csv << ['Baz', 2]
- end
- output_string # => "'Foo','0'\n'Bar','1'\n'Baz','2'\n"
diff --git a/doc/csv/recipes/parsing.rdoc b/doc/csv/recipes/parsing.rdoc
deleted file mode 100644
index 1b7071e33f..0000000000
--- a/doc/csv/recipes/parsing.rdoc
+++ /dev/null
@@ -1,545 +0,0 @@
-== 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:
- require 'csv'
-
-=== Contents
-
-- {Source Formats}[#label-Source+Formats]
- - {Parsing from a String}[#label-Parsing+from+a+String]
- - {Recipe: Parse from String with Headers}[#label-Recipe-3A+Parse+from+String+with+Headers]
- - {Recipe: Parse from String Without Headers}[#label-Recipe-3A+Parse+from+String+Without+Headers]
- - {Parsing from a File}[#label-Parsing+from+a+File]
- - {Recipe: Parse from File with Headers}[#label-Recipe-3A+Parse+from+File+with+Headers]
- - {Recipe: Parse from File Without Headers}[#label-Recipe-3A+Parse+from+File+Without+Headers]
- - {Parsing from an IO Stream}[#label-Parsing+from+an+IO+Stream]
- - {Recipe: Parse from IO Stream with Headers}[#label-Recipe-3A+Parse+from+IO+Stream+with+Headers]
- - {Recipe: Parse from IO Stream Without Headers}[#label-Recipe-3A+Parse+from+IO+Stream+Without+Headers]
-- {RFC 4180 Compliance}[#label-RFC+4180+Compliance]
- - {Row Separator}[#label-Row+Separator]
- - {Recipe: Handle Compliant Row Separator}[#label-Recipe-3A+Handle+Compliant+Row+Separator]
- - {Recipe: Handle Non-Compliant Row Separator}[#label-Recipe-3A+Handle+Non-Compliant+Row+Separator]
- - {Column Separator}[#label-Column+Separator]
- - {Recipe: Handle Compliant Column Separator}[#label-Recipe-3A+Handle+Compliant+Column+Separator]
- - {Recipe: Handle Non-Compliant Column Separator}[#label-Recipe-3A+Handle+Non-Compliant+Column+Separator]
- - {Quote Character}[#label-Quote+Character]
- - {Recipe: Handle Compliant Quote Character}[#label-Recipe-3A+Handle+Compliant+Quote+Character]
- - {Recipe: Handle Non-Compliant Quote Character}[#label-Recipe-3A+Handle+Non-Compliant+Quote+Character]
- - {Recipe: Allow Liberal Parsing}[#label-Recipe-3A+Allow+Liberal+Parsing]
-- {Special Handling}[#label-Special+Handling]
- - {Special Line Handling}[#label-Special+Line+Handling]
- - {Recipe: Ignore Blank Lines}[#label-Recipe-3A+Ignore+Blank+Lines]
- - {Recipe: Ignore Selected Lines}[#label-Recipe-3A+Ignore+Selected+Lines]
- - {Special Field Handling}[#label-Special+Field+Handling]
- - {Recipe: Strip Fields}[#label-Recipe-3A+Strip+Fields]
- - {Recipe: Handle Null Fields}[#label-Recipe-3A+Handle+Null+Fields]
- - {Recipe: Handle Empty Fields}[#label-Recipe-3A+Handle+Empty+Fields]
-- {Converting Fields}[#label-Converting+Fields]
- - {Converting Fields to Objects}[#label-Converting+Fields+to+Objects]
- - {Recipe: Convert Fields to Integers}[#label-Recipe-3A+Convert+Fields+to+Integers]
- - {Recipe: Convert Fields to Floats}[#label-Recipe-3A+Convert+Fields+to+Floats]
- - {Recipe: Convert Fields to Numerics}[#label-Recipe-3A+Convert+Fields+to+Numerics]
- - {Recipe: Convert Fields to Dates}[#label-Recipe-3A+Convert+Fields+to+Dates]
- - {Recipe: Convert Fields to DateTimes}[#label-Recipe-3A+Convert+Fields+to+DateTimes]
- - {Recipe: Convert Assorted Fields to Objects}[#label-Recipe-3A+Convert+Assorted+Fields+to+Objects]
- - {Recipe: Convert Fields to Other Objects}[#label-Recipe-3A+Convert+Fields+to+Other+Objects]
- - {Recipe: Filter Field Strings}[#label-Recipe-3A+Filter+Field+Strings]
- - {Recipe: Register Field Converters}[#label-Recipe-3A+Register+Field+Converters]
- - {Using Multiple Field Converters}[#label-Using+Multiple+Field+Converters]
- - {Recipe: Specify Multiple Field Converters in Option :converters}[#label-Recipe-3A+Specify+Multiple+Field+Converters+in+Option+-3Aconverters]
- - {Recipe: Specify Multiple Field Converters in a Custom Converter List}[#label-Recipe-3A+Specify+Multiple+Field+Converters+in+a+Custom+Converter+List]
-- {Converting Headers}[#label-Converting+Headers]
- - {Recipe: Convert Headers to Lowercase}[#label-Recipe-3A+Convert+Headers+to+Lowercase]
- - {Recipe: Convert Headers to Symbols}[#label-Recipe-3A+Convert+Headers+to+Symbols]
- - {Recipe: Filter Header Strings}[#label-Recipe-3A+Filter+Header+Strings]
- - {Recipe: Register Header Converters}[#label-Recipe-3A+Register+Header+Converters]
- - {Using Multiple Header Converters}[#label-Using+Multiple+Header+Converters]
- - {Recipe: Specify Multiple Header Converters in Option :header_converters}[#label-Recipe-3A+Specify+Multiple+Header+Converters+in+Option+-3Aheader_converters]
- - {Recipe: Specify Multiple Header Converters in a Custom Header Converter List}[#label-Recipe-3A+Specify+Multiple+Header+Converters+in+a+Custom+Header+Converter+List]
-- {Diagnostics}[#label-Diagnostics]
- - {Recipe: Capture Unconverted Fields}[#label-Recipe-3A+Capture+Unconverted+Fields]
- - {Recipe: Capture Field Info}[#label-Recipe-3A+Capture+Field+Info]
-
-=== Source Formats
-
-You can parse \CSV data from a \String, from a \File (via its path), or from an \IO stream.
-
-==== Parsing from a \String
-
-You can parse \CSV data from a \String, with or without headers.
-
-===== Recipe: Parse from \String with Headers
-
-Use class method CSV.parse with option +headers+ to read a source \String all at once
-(may have memory resource implications):
- string = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
- CSV.parse(string, headers: true) # => #<CSV::Table mode:col_or_row row_count:4>
-
-Use instance method CSV#each with option +headers+ to read a source \String one row at a time:
- CSV.new(string, headers: true).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">
-
-===== Recipe: Parse from \String Without Headers
-
-Use class method CSV.parse without option +headers+ to read a source \String all at once
-(may have memory resource implications):
- string = "foo,0\nbar,1\nbaz,2\n"
- CSV.parse(string) # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
-
-Use instance method CSV#each without option +headers+ to read a source \String one row at a time:
- CSV.new(string).each do |row|
- p row
- end
-Output:
- ["foo", "0"]
- ["bar", "1"]
- ["baz", "2"]
-
-==== Parsing from a \File
-
-You can parse \CSV data from a \File, with or without headers.
-
-===== Recipe: Parse from \File with Headers
-
-Use instance method CSV#read with option +headers+ to read a file all at once:
- 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>
-
-Use class method CSV.foreach with option +headers+ to read one row at a time:
- CSV.foreach(path, headers: true) do |row|
- p row
- end
-Output:
- #<CSV::Row "Name":"foo" "Value":"0">
- #<CSV::Row "Name":"bar" "Value":"1">
- #<CSV::Row "Name":"baz" "Value":"2">
-
-===== Recipe: Parse from \File Without Headers
-
-Use class method CSV.read without option +headers+ to read a file all at once:
- string = "foo,0\nbar,1\nbaz,2\n"
- path = 't.csv'
- File.write(path, string)
- CSV.read(path) # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
-
-Use class method CSV.foreach without option +headers+ to read one row at a time:
- CSV.foreach(path) do |row|
- p row
- end
-Output:
- ["foo", "0"]
- ["bar", "1"]
- ["baz", "2"]
-
-==== Parsing from an \IO Stream
-
-You can parse \CSV data from an \IO stream, with or without headers.
-
-===== Recipe: Parse from \IO Stream with Headers
-
-Use class method CSV.parse with option +headers+ to read an \IO stream all at once:
- string = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
- path = 't.csv'
- File.write(path, string)
- File.open(path) do |file|
- CSV.parse(file, headers: true)
- end # => #<CSV::Table mode:col_or_row row_count:4>
-
-Use class method CSV.foreach with option +headers+ to read one row at a time:
- File.open(path) do |file|
- CSV.foreach(file, headers: true) do |row|
- p row
- end
- end
-Output:
- #<CSV::Row "Name":"foo" "Value":"0">
- #<CSV::Row "Name":"bar" "Value":"1">
- #<CSV::Row "Name":"baz" "Value":"2">
-
-===== Recipe: Parse from \IO Stream Without Headers
-
-Use class method CSV.parse without option +headers+ to read an \IO stream all at once:
- string = "foo,0\nbar,1\nbaz,2\n"
- path = 't.csv'
- File.write(path, string)
- File.open(path) do |file|
- CSV.parse(file)
- end # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
-
-Use class method CSV.foreach without option +headers+ to read one row at a time:
- File.open(path) do |file|
- CSV.foreach(file) do |row|
- p row
- end
- end
-Output:
- ["foo", "0"]
- ["bar", "1"]
- ["baz", "2"]
-
-=== RFC 4180 Compliance
-
-By default, \CSV parses data that is compliant with
-{RFC 4180}[https://www.rfc-editor.org/rfc/rfc4180]
-with respect to:
-- Row separator.
-- Column separator.
-- Quote character.
-
-==== Row Separator
-
-RFC 4180 specifies the row separator CRLF (Ruby <tt>"\r\n"</tt>).
-
-Although the \CSV default row separator is <tt>"\n"</tt>,
-the parser also by default handles row separator <tt>"\r"</tt> and the RFC-compliant <tt>"\r\n"</tt>.
-
-===== Recipe: Handle Compliant Row Separator
-
-For strict compliance, use option +:row_sep+ to specify row separator <tt>"\r\n"</tt>,
-which allows the compliant row separator:
- source = "foo,1\r\nbar,1\r\nbaz,2\r\n"
- CSV.parse(source, row_sep: "\r\n") # => [["foo", "1"], ["bar", "1"], ["baz", "2"]]
-But rejects other row separators:
- source = "foo,1\nbar,1\nbaz,2\n"
- CSV.parse(source, row_sep: "\r\n") # Raised MalformedCSVError
- source = "foo,1\rbar,1\rbaz,2\r"
- CSV.parse(source, row_sep: "\r\n") # Raised MalformedCSVError
- source = "foo,1\n\rbar,1\n\rbaz,2\n\r"
- CSV.parse(source, row_sep: "\r\n") # Raised MalformedCSVError
-
-===== Recipe: Handle Non-Compliant Row Separator
-
-For data with non-compliant row separators, use option +:row_sep+.
-This example source uses semicolon (<tt>";"</tt>) as its row separator:
- source = "foo,1;bar,1;baz,2;"
- CSV.parse(source, row_sep: ';') # => [["foo", "1"], ["bar", "1"], ["baz", "2"]]
-
-==== Column Separator
-
-RFC 4180 specifies column separator COMMA (Ruby <tt>","</tt>).
-
-===== Recipe: Handle Compliant Column Separator
-
-Because the \CSV default comma separator is ',',
-you need not specify option +:col_sep+ for compliant data:
- source = "foo,1\nbar,1\nbaz,2\n"
- CSV.parse(source) # => [["foo", "1"], ["bar", "1"], ["baz", "2"]]
-
-===== Recipe: Handle Non-Compliant Column Separator
-
-For data with non-compliant column separators, use option +:col_sep+.
-This example source uses TAB (<tt>"\t"</tt>) as its column separator:
- source = "foo,1\tbar,1\tbaz,2"
- CSV.parse(source, col_sep: "\t") # => [["foo", "1"], ["bar", "1"], ["baz", "2"]]
-
-==== Quote Character
-
-RFC 4180 specifies quote character DQUOTE (Ruby <tt>"\""</tt>).
-
-===== Recipe: Handle Compliant Quote Character
-
-Because the \CSV default quote character is <tt>"\""</tt>,
-you need not specify option +:quote_char+ for compliant data:
- source = "\"foo\",\"1\"\n\"bar\",\"1\"\n\"baz\",\"2\"\n"
- CSV.parse(source) # => [["foo", "1"], ["bar", "1"], ["baz", "2"]]
-
-===== Recipe: Handle Non-Compliant Quote Character
-
-For data with non-compliant quote characters, use option +:quote_char+.
-This example source uses SQUOTE (<tt>"'"</tt>) as its quote character:
- source = "'foo','1'\n'bar','1'\n'baz','2'\n"
- CSV.parse(source, quote_char: "'") # => [["foo", "1"], ["bar", "1"], ["baz", "2"]]
-
-==== Recipe: Allow Liberal Parsing
-
-Use option +:liberal_parsing+ to specify that \CSV should
-attempt to parse input not conformant with RFC 4180, such as double quotes in unquoted fields:
- source = 'is,this "three, or four",fields'
- CSV.parse(source) # Raises MalformedCSVError
- CSV.parse(source, liberal_parsing: true) # => [["is", "this \"three", " or four\"", "fields"]]
-
-=== Special Handling
-
-You can use parsing options to specify special handling for certain lines and fields.
-
-==== Special Line Handling
-
-Use parsing options to specify special handling for blank lines, or for other selected lines.
-
-===== Recipe: Ignore Blank Lines
-
-Use option +:skip_blanks+ to ignore blank lines:
- source = <<-EOT
- foo,0
-
- bar,1
- baz,2
-
- ,
- EOT
- parsed = CSV.parse(source, skip_blanks: true)
- parsed # => [["foo", "0"], ["bar", "1"], ["baz", "2"], [nil, nil]]
-
-===== Recipe: Ignore Selected Lines
-
-Use option +:skip_lines+ to ignore selected lines.
- source = <<-EOT
- # Comment
- foo,0
- bar,1
- baz,2
- # Another comment
- EOT
- parsed = CSV.parse(source, skip_lines: /^#/)
- parsed # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
-
-==== Special Field Handling
-
-Use parsing options to specify special handling for certain field values.
-
-===== Recipe: Strip Fields
-
-Use option +:strip+ to strip parsed field values:
- CSV.parse_line(' a , b ', strip: true) # => ["a", "b"]
-
-===== Recipe: Handle Null Fields
-
-Use option +:nil_value+ to specify a value that will replace each field
-that is null (no text):
- CSV.parse_line('a,,b,,c', nil_value: 0) # => ["a", 0, "b", 0, "c"]
-
-===== Recipe: Handle Empty Fields
-
-Use option +:empty_value+ to specify a value that will replace each field
-that is empty (\String of length 0);
- CSV.parse_line('a,"",b,"",c', empty_value: 'x') # => ["a", "x", "b", "x", "c"]
-
-=== Converting Fields
-
-You can use field converters to change parsed \String fields into other objects,
-or to otherwise modify the \String fields.
-
-==== Converting Fields to Objects
-
-Use field converters to change parsed \String objects into other, more specific, objects.
-
-There are built-in field converters for converting to objects of certain classes:
-- \Float
-- \Integer
-- \Date
-- \DateTime
-
-Other built-in field converters include:
-- +:numeric+: converts to \Integer and \Float.
-- +:all+: converts to \DateTime, \Integer, \Float.
-
-You can also define field converters to convert to objects of other classes.
-
-===== Recipe: Convert Fields to Integers
-
-Convert fields to \Integer objects using built-in converter +:integer+:
- source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
- parsed = CSV.parse(source, headers: true, converters: :integer)
- parsed.map {|row| row['Value'].class} # => [Integer, Integer, Integer]
-
-===== Recipe: Convert Fields to Floats
-
-Convert fields to \Float objects using built-in converter +:float+:
- source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
- parsed = CSV.parse(source, headers: true, converters: :float)
- parsed.map {|row| row['Value'].class} # => [Float, Float, Float]
-
-===== Recipe: Convert Fields to Numerics
-
-Convert fields to \Integer and \Float objects using built-in converter +:numeric+:
- source = "Name,Value\nfoo,0\nbar,1.1\nbaz,2.2\n"
- parsed = CSV.parse(source, headers: true, converters: :numeric)
- parsed.map {|row| row['Value'].class} # => [Integer, Float, Float]
-
-===== Recipe: Convert Fields to Dates
-
-Convert fields to \Date objects using built-in converter +:date+:
- source = "Name,Date\nfoo,2001-02-03\nbar,2001-02-04\nbaz,2001-02-03\n"
- parsed = CSV.parse(source, headers: true, converters: :date)
- parsed.map {|row| row['Date'].class} # => [Date, Date, Date]
-
-===== Recipe: Convert Fields to DateTimes
-
-Convert fields to \DateTime objects using built-in converter +:date_time+:
- source = "Name,DateTime\nfoo,2001-02-03\nbar,2001-02-04\nbaz,2020-05-07T14:59:00-05:00\n"
- parsed = CSV.parse(source, headers: true, converters: :date_time)
- parsed.map {|row| row['DateTime'].class} # => [DateTime, DateTime, DateTime]
-
-===== Recipe: Convert Assorted Fields to Objects
-
-Convert assorted fields to objects using built-in converter +:all+:
- source = "Type,Value\nInteger,0\nFloat,1.0\nDateTime,2001-02-04\n"
- parsed = CSV.parse(source, headers: true, converters: :all)
- parsed.map {|row| row['Value'].class} # => [Integer, Float, DateTime]
-
-===== Recipe: Convert Fields to Other Objects
-
-Define a custom field converter to convert \String fields into other objects.
-This example defines and uses a custom field converter
-that converts each column-1 value to a \Rational object:
- rational_converter = proc do |field, field_context|
- field_context.index == 1 ? field.to_r : field
- end
- source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
- parsed = CSV.parse(source, headers: true, converters: rational_converter)
- parsed.map {|row| row['Value'].class} # => [Rational, Rational, Rational]
-
-==== Recipe: Filter Field Strings
-
-Define a custom field converter to modify \String fields.
-This example defines and uses a custom field converter
-that strips whitespace from each field value:
- strip_converter = proc {|field| field.strip }
- source = "Name,Value\n foo , 0 \n bar , 1 \n baz , 2 \n"
- parsed = CSV.parse(source, headers: true, converters: strip_converter)
- parsed['Name'] # => ["foo", "bar", "baz"]
- parsed['Value'] # => ["0", "1", "2"]
-
-==== Recipe: Register Field Converters
-
-Register a custom field converter, assigning it a name;
-then refer to the converter by its name:
- rational_converter = proc do |field, field_context|
- field_context.index == 1 ? field.to_r : field
- end
- CSV::Converters[:rational] = rational_converter
- source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
- parsed = CSV.parse(source, headers: true, converters: :rational)
- parsed['Value'] # => [(0/1), (1/1), (2/1)]
-
-==== Using Multiple Field Converters
-
-You can use multiple field converters in either of these ways:
-- Specify converters in option +:converters+.
-- Specify converters in a custom converter list.
-
-===== Recipe: Specify Multiple Field Converters in Option +:converters+
-
-Apply multiple field converters by specifying them in option +:converters+:
- source = "Name,Value\nfoo,0\nbar,1.0\nbaz,2.0\n"
- parsed = CSV.parse(source, headers: true, converters: [:integer, :float])
- parsed['Value'] # => [0, 1.0, 2.0]
-
-===== Recipe: Specify Multiple Field Converters in a Custom Converter List
-
-Apply multiple field converters by defining and registering a custom converter list:
- strip_converter = proc {|field| field.strip }
- CSV::Converters[:strip] = strip_converter
- CSV::Converters[:my_converters] = [:integer, :float, :strip]
- source = "Name,Value\n foo , 0 \n bar , 1.0 \n baz , 2.0 \n"
- parsed = CSV.parse(source, headers: true, converters: :my_converters)
- parsed['Name'] # => ["foo", "bar", "baz"]
- parsed['Value'] # => [0, 1.0, 2.0]
-
-=== Converting Headers
-
-You can use header converters to modify parsed \String headers.
-
-Built-in header converters include:
-- +:symbol+: converts \String header to \Symbol.
-- +:downcase+: converts \String header to lowercase.
-
-You can also define header converters to otherwise modify header \Strings.
-
-==== Recipe: Convert Headers to Lowercase
-
-Convert headers to lowercase using built-in converter +:downcase+:
- source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
- parsed = CSV.parse(source, headers: true, header_converters: :downcase)
- parsed.headers # => ["name", "value"]
-
-==== Recipe: Convert Headers to Symbols
-
-Convert headers to downcased Symbols using built-in converter +:symbol+:
- source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
- parsed = CSV.parse(source, headers: true, header_converters: :symbol)
- parsed.headers # => [:name, :value]
- parsed.headers.map {|header| header.class} # => [Symbol, Symbol]
-
-==== Recipe: Filter Header Strings
-
-Define a custom header converter to modify \String fields.
-This example defines and uses a custom header converter
-that capitalizes each header \String:
- capitalize_converter = proc {|header| header.capitalize }
- source = "NAME,VALUE\nfoo,0\nbar,1\nbaz,2\n"
- parsed = CSV.parse(source, headers: true, header_converters: capitalize_converter)
- parsed.headers # => ["Name", "Value"]
-
-==== Recipe: Register Header Converters
-
-Register a custom header converter, assigning it a name;
-then refer to the converter by its name:
- capitalize_converter = proc {|header| header.capitalize }
- CSV::HeaderConverters[:capitalize] = capitalize_converter
- source = "NAME,VALUE\nfoo,0\nbar,1\nbaz,2\n"
- parsed = CSV.parse(source, headers: true, header_converters: :capitalize)
- parsed.headers # => ["Name", "Value"]
-
-==== Using Multiple Header Converters
-
-You can use multiple header converters in either of these ways:
-- Specify header converters in option +:header_converters+.
-- Specify header converters in a custom header converter list.
-
-===== Recipe: Specify Multiple Header Converters in Option :header_converters
-
-Apply multiple header converters by specifying them in option +:header_converters+:
- source = "Name,Value\nfoo,0\nbar,1.0\nbaz,2.0\n"
- parsed = CSV.parse(source, headers: true, header_converters: [:downcase, :symbol])
- parsed.headers # => [:name, :value]
-
-===== Recipe: Specify Multiple Header Converters in a Custom Header Converter List
-
-Apply multiple header converters by defining and registering a custom header converter list:
- CSV::HeaderConverters[:my_header_converters] = [:symbol, :downcase]
- source = "NAME,VALUE\nfoo,0\nbar,1.0\nbaz,2.0\n"
- parsed = CSV.parse(source, headers: true, header_converters: :my_header_converters)
- parsed.headers # => [:name, :value]
-
-=== Diagnostics
-
-==== Recipe: Capture Unconverted Fields
-
-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.each {|row| p row.unconverted_fields }
-Output:
- ["Name", "Value"]
- ["foo", "0"]
- ["bar", "1"]
- ["baz", "2"]
-
-==== Recipe: Capture Field Info
-
-To capture field info in a custom converter, accept two block arguments.
-The first is the field value; the second is a +CSV::FieldInfo+ object:
- strip_converter = proc {|field, field_info| p field_info; field.strip }
- source = " foo , 0 \n bar , 1 \n baz , 2 \n"
- parsed = CSV.parse(source, converters: strip_converter)
- parsed # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
-Output:
- #<struct CSV::FieldInfo index=0, line=1, header=nil>
- #<struct CSV::FieldInfo index=1, line=1, header=nil>
- #<struct CSV::FieldInfo index=0, line=2, header=nil>
- #<struct CSV::FieldInfo index=1, line=2, header=nil>
- #<struct CSV::FieldInfo index=0, line=3, header=nil>
- #<struct CSV::FieldInfo index=1, line=3, header=nil>
diff --git a/doc/csv/recipes/recipes.rdoc b/doc/csv/recipes/recipes.rdoc
deleted file mode 100644
index 9bf7885b1e..0000000000
--- a/doc/csv/recipes/recipes.rdoc
+++ /dev/null
@@ -1,6 +0,0 @@
-== Recipes for \CSV
-
-The recipes are specific code examples for specific tasks. 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/date/calendars.rdoc b/doc/date/calendars.rdoc
deleted file mode 100644
index 4e6fd8334b..0000000000
--- a/doc/date/calendars.rdoc
+++ /dev/null
@@ -1,62 +0,0 @@
-== Julian and Gregorian Calendars
-
-The difference between the
-{Julian calendar}[https://en.wikipedia.org/wiki/Julian_calendar]
-and the
-{Gregorian calendar}[https://en.wikipedia.org/wiki/Gregorian_calendar]
-may matter to your program if it uses dates before the switchovers.
-
-- October 15, 1582.
-- September 14, 1752.
-
-A date will be different in the two calendars, in general.
-
-=== Different switchover dates
-
-The reasons for the difference are religious/political histories.
-
-- On October 15, 1582, several countries changed
- from the Julian calendar to the Gregorian calendar;
- these included Italy, Poland, Portugal, and Spain.
- Other countries in the Western world retained the Julian calendar.
-- On September 14, 1752, most of the British empire
- changed from the Julian calendar to the Gregorian calendar.
-
-When your code uses a date before these switchover dates,
-it will matter whether it considers the switchover date
-to be the earlier date or the later date (or neither).
-
-See also {a concrete example here}[rdoc-ref:DateTime@When+should+you+use+DateTime+and+when+should+you+use+Time-3F].
-
-=== Argument +start+
-
-Certain methods in class \Date handle differences in the
-{Julian and Gregorian calendars}[rdoc-ref:date/calendars.rdoc@Julian+and+Gregorian+Calendars]
-by accepting an optional argument +start+, whose value may be:
-
-- Date::ITALY (the default): the created date is Julian
- if before October 15, 1582, Gregorian otherwise:
-
- d = Date.new(1582, 10, 15)
- d.prev_day.julian? # => true
- d.julian? # => false
- d.gregorian? # => true
-
-- Date::ENGLAND: the created date is Julian if before September 14, 1752,
- Gregorian otherwise:
-
- d = Date.new(1752, 9, 14, Date::ENGLAND)
- d.prev_day.julian? # => true
- d.julian? # => false
- d.gregorian? # => true
-
-- Date::JULIAN: the created date is Julian regardless of its value:
-
- d = Date.new(1582, 10, 15, Date::JULIAN)
- d.julian? # => true
-
-- Date::GREGORIAN: the created date is Gregorian regardless of its value:
-
- d = Date.new(1752, 9, 14, Date::GREGORIAN)
- d.prev_day.gregorian? # => true
-
diff --git a/doc/distribution.md b/doc/distribution.md
deleted file mode 100644
index 164e1b7109..0000000000
--- a/doc/distribution.md
+++ /dev/null
@@ -1,48 +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 cryptographically 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:
-
-```console
-$ ./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/distribution/distribution.md b/doc/distribution/distribution.md
new file mode 100644
index 0000000000..e0e4ad354b
--- /dev/null
+++ b/doc/distribution/distribution.md
@@ -0,0 +1,48 @@
+# 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 cryptographically 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:
+
+```console
+$ ./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/distribution/windows.md b/doc/distribution/windows.md
new file mode 100644
index 0000000000..26a727d7ad
--- /dev/null
+++ b/doc/distribution/windows.md
@@ -0,0 +1,304 @@
+# 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:
+
+```batch
+ridk install
+ridk enable ucrt64
+
+pacman -S --needed %MINGW_PACKAGE_PREFIX%-openssl %MINGW_PACKAGE_PREFIX%-libyaml %MINGW_PACKAGE_PREFIX%-libffi
+
+mkdir c:\work\ruby
+cd /d c:\work\ruby
+
+git clone https://github.com/ruby/ruby src
+
+sh ./src/autogen.sh
+
+mkdir build
+cd build
+sh ../src/configure -C --disable-install-doc
+make
+```
+
+or in MSYS2 `bash` like:
+
+```bash
+ridk install
+ridk enable ucrt64
+bash
+
+pacman -S --needed $MINGW_PACKAGE_PREFIX-openssl $MINGW_PACKAGE_PREFIX-libyaml $MINGW_PACKAGE_PREFIX-libffi
+
+mkdir /c/work/ruby
+cd /c/work/ruby
+
+git clone https://github.com/ruby/ruby src
+
+./src/autogen.sh
+cd build
+../src/configure -C --disable-install-doc
+make
+```
+
+If you have other MSYS2 environment via other package manager like `scoop`, you need to specify `$MINGW_PACKAGE_PREFIX` is `mingw-w64-ucrt-x86_64`.
+And you need to add `--with-opt-dir` option to `configure` command like:
+
+```batch
+sh ../../ruby/configure -C --disable-install-doc --with-opt-dir=C:\Users\username\scoop\apps\msys2\current\ucrt64
+```
+
+[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.
+
+ The minimum requirement is here:
+ * VC++/MSVC on VS 2017/2019/2022 version build tools.
+ * Windows 10/11 SDK
+
+ You can install Visual Studio Build Tools with `winget`.
+ `win32\install-buildtools.cmd` is a batch file to install the
+ minimum requirements excluding the IDE etc.
+
+3. Please set environment variable `INCLUDE`, `LIB`, `PATH` to run
+ required commands properly from the command line. These are set
+ properly by `vsdevcmd.bat` or `vcvarall*.bat` usually. You can run
+ the following command to set them in your command line.
+
+ To native build:
+
+ ```
+ cmd /k win32\vssetup.cmd
+ ```
+
+ To cross build arm64 binary:
+
+ ```
+ cmd /k win32\vssetup.cmd -arch=arm64
+ ```
+
+ To cross build x64 binary:
+
+ ```
+ cmd /k win32\vssetup.cmd -arch=x64
+ ```
+
+ This batch file is a wrapper of `vsdevcmd.bat` and options are
+ passed to it as-is. `win32\vssetup.cmd -help` for other command
+ line options.
+
+ **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`
+ * `ruby` 3.1 or later
+
+ You can use [scoop](https://scoop.sh/) to install them like:
+
+ ```batch
+ scoop install git ruby
+ ```
+
+ The windows version of `git` configured with `autocrlf` is `true`. The Ruby
+ test suite may fail with `autocrlf` set to `true`. You can set it to `false`
+ like:
+
+ ```batch
+ git config --global core.autocrlf false
+ ```
+
+5. You need to install required libraries using [vcpkg](https://vcpkg.io/) on
+ directory of ruby repository like:
+
+ ```batch
+ 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` .
+
+2. If you want to append to the executable and DLL file names,
+ specify `--program-prefix` and `--program-suffix`, like
+ `win32\configure.bat --program-suffix=-$(MAJOR)$(MINOR)`.
+
+ Also, the `--install-name` and `--so-name` options specify the
+ exact base names of the executable and DLL files, respectively,
+ like `win32\configure.bat --install-name=$(RUBY_BASE_NAME)-$(MAJOR)$(MINOR)`.
+
+ By default, the name for the executable without a console window
+ is generated from the _RUBY_INSTALL_NAME_ specified as above by
+ replacing `ruby` with `rubyw`. If you want to make it different
+ more, modify _RUBYW_INSTALL_NAME_ directly in the Makefile.
+
+3. You need specify vcpkg directory to use `--with-opt-dir`
+ option like `win32\configure.bat --with-opt-dir=C:/vcpkg_installed/x64-windows`
+
+4. Run `nmake up` if you are building from GIT source.
+
+5. Run `nmake`
+
+6. Run `nmake prepare-vcpkg` with administrator privilege 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
+ ```
+
+ ```batch
+ 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
+ ```
+
+ ```batch
+ 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
+ ```
+
+ ```batch
+ 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
+ ```
+
+ ```batch
+ 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:
+
+```batch
+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/encodings.rdoc b/doc/encodings.rdoc
deleted file mode 100644
index bd87c38e9e..0000000000
--- a/doc/encodings.rdoc
+++ /dev/null
@@ -1,482 +0,0 @@
-= Encodings
-
-== The Basics
-
-A {character encoding}[https://en.wikipedia.org/wiki/Character_encoding],
-often shortened to _encoding_, is a mapping between:
-
-- A sequence of 8-bit bytes (each byte in the range <tt>0..255</tt>).
-- Characters in a specific character set.
-
-Some character sets contain only 1-byte characters;
-{US-ASCII}[https://en.wikipedia.org/wiki/ASCII], for example, has 256 1-byte characters.
-This string, encoded in US-ASCII, has six characters that are stored as six bytes:
-
- s = 'Hello!'.encode(Encoding::US_ASCII) # => "Hello!"
- s.encoding # => #<Encoding:US-ASCII>
- s.bytes # => [72, 101, 108, 108, 111, 33]
-
-Other encodings may involve multi-byte characters.
-{UTF-8}[https://en.wikipedia.org/wiki/UTF-8], for example,
-encodes more than one million characters, encoding each in one to four bytes.
-The lowest-valued of these characters correspond to ASCII characters,
-and so are 1-byte characters:
-
- s = 'Hello!' # => "Hello!"
- s.bytes # => [72, 101, 108, 108, 111, 33]
-
-Other characters, such as the Euro symbol, are multi-byte:
-
- s = "\u20ac" # => "€"
- s.bytes # => [226, 130, 172]
-
-== The \Encoding Class
-
-=== \Encoding Objects
-
-Ruby encodings are defined by constants in class \Encoding.
-There can be only one instance of \Encoding for each of these constants.
-Method Encoding.list returns an array of \Encoding objects (one for each constant):
-
- Encoding.list.size # => 103
- Encoding.list.first.class # => Encoding
- Encoding.list.take(3)
- # => [#<Encoding:ASCII-8BIT>, #<Encoding:UTF-8>, #<Encoding:US-ASCII>]
-
-=== Names and Aliases
-
-Method Encoding#name returns the name of an \Encoding:
-
- Encoding::ASCII_8BIT.name # => "ASCII-8BIT"
- Encoding::WINDOWS_31J.name # => "Windows-31J"
-
-An \Encoding object has zero or more aliases;
-method Encoding#names returns an array containing the name and all aliases:
-
- Encoding::ASCII_8BIT.names
- # => ["ASCII-8BIT", "BINARY"]
- Encoding::WINDOWS_31J.names
- #=> ["Windows-31J", "CP932", "csWindows31J", "SJIS", "PCK"]
-
-Method Encoding.aliases returns a hash of all alias/name pairs:
-
- Encoding.aliases.size # => 71
- Encoding.aliases.take(3)
- # => [["BINARY", "ASCII-8BIT"], ["CP437", "IBM437"], ["CP720", "IBM720"]]
-
-Method Encoding.name_list returns an array of all the encoding names and aliases:
-
- Encoding.name_list.size # => 175
- Encoding.name_list.take(3)
- # => ["ASCII-8BIT", "UTF-8", "US-ASCII"]
-
-Method +name_list+ returns more entries than method +list+
-because it includes both the names and their aliases.
-
-Method Encoding.find returns the \Encoding for a given name or alias, if it exists:
-
- Encoding.find("US-ASCII") # => #<Encoding:US-ASCII>
- Encoding.find("US-ASCII").class # => Encoding
-
-=== Default Encodings
-
-Method Encoding.find, above, also returns a default \Encoding
-for each of these special names:
-
-- +external+: the default external \Encoding:
-
- Encoding.find("external") # => #<Encoding:UTF-8>
-
-- +internal+: the default internal \Encoding (may be +nil+):
-
- Encoding.find("internal") # => nil
-
-- +locale+: the default \Encoding for a string from the environment:
-
- Encoding.find("locale") # => #<Encoding:UTF-8> # Linux
- Encoding.find("locale") # => #<Encoding:IBM437> # Windows
-
-- +filesystem+: the default \Encoding for a string from the filesystem:
-
- Encoding.find("filesystem") # => #<Encoding:UTF-8>
-
-Method Encoding.default_external returns the default external \Encoding:
-
- Encoding.default_external # => #<Encoding:UTF-8>
-
-Method Encoding.default_external= sets that value:
-
- Encoding.default_external = Encoding::US_ASCII # => #<Encoding:US-ASCII>
- Encoding.default_external # => #<Encoding:US-ASCII>
-
-Method Encoding.default_internal returns the default internal \Encoding:
-
- Encoding.default_internal # => nil
-
-Method Encoding.default_internal= sets the default internal \Encoding:
-
- Encoding.default_internal = Encoding::US_ASCII # => #<Encoding:US-ASCII>
- Encoding.default_internal # => #<Encoding:US-ASCII>
-
-=== Compatible Encodings
-
-Method Encoding.compatible? returns whether two given objects are encoding-compatible
-(that is, whether they can be concatenated);
-returns the \Encoding of the concatenated string, or +nil+ if incompatible:
-
- rus = "\u{442 435 441 442}"
- eng = 'text'
- Encoding.compatible?(rus, eng) # => #<Encoding:UTF-8>
-
- s0 = "\xa1\xa1".force_encoding(Encoding::ISO_8859_1) # => "\xA1\xA1"
- s1 = "\xa1\xa1".force_encoding(Encoding::EUCJP) # => "\x{A1A1}"
- Encoding.compatible?(s0, s1) # => nil
-
-== \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].
-
- 's'.encoding # => #<Encoding:UTF-8>
-
-The default encoding for a string created with method String.new is:
-
-- For no argument, ASCII-8BIT.
-- 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].
-
-In either case, any encoding may be specified:
-
- s = String.new(encoding: Encoding::UTF_8) # => ""
- s.encoding # => #<Encoding:UTF-8>
- s = String.new('foo', encoding: Encoding::BINARY) # => "foo"
- s.encoding # => #<Encoding:BINARY (ASCII-8BIT)>
-
-The encoding for a string may be changed:
-
- s = "R\xC3\xA9sum\xC3\xA9" # => "Résumé"
- s.encoding # => #<Encoding:UTF-8>
- s.force_encoding(Encoding::ISO_8859_1) # => "R\xC3\xA9sum\xC3\xA9"
- s.encoding # => #<Encoding:ISO-8859-1>
-
-Changing the assigned encoding does not alter the content of the string;
-it changes only the way the content is to be interpreted:
-
- s # => "R\xC3\xA9sum\xC3\xA9"
- s.force_encoding(Encoding::UTF_8) # => "Résumé"
-
-The actual content of a string may also be altered;
-see {Transcoding a String}[#label-Transcoding+a+String].
-
-Here are a couple of useful query methods:
-
- s = "abc".force_encoding(Encoding::UTF_8) # => "abc"
- s.ascii_only? # => true
- s = "abc\u{6666}".force_encoding(Encoding::UTF_8) # => "abc晦"
- s.ascii_only? # => false
-
- s = "\xc2\xa1".force_encoding(Encoding::UTF_8) # => "¡"
- s.valid_encoding? # => true
- s = "\xc2".force_encoding(Encoding::UTF_8) # => "\xC2"
- s.valid_encoding? # => false
-
-== \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.
-
-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].
-
-== Filesystem \Encoding
-
-The filesystem encoding is the default \Encoding for a string from the filesystem:
-
- Encoding.find("filesystem") # => #<Encoding:UTF-8>
-
-== 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
-
-Certain stream objects can have two encodings; these objects include instances of:
-
-- IO.
-- File.
-- ARGF.
-- StringIO.
-
-The two encodings are:
-
-- An _external_ _encoding_, which identifies the encoding of the stream.
-- An _internal_ _encoding_, which (if not +nil+) specifies the encoding
- to be used for the string constructed from the stream.
-
-=== External \Encoding
-
-The external encoding, which is an \Encoding object, specifies how bytes read
-from the stream are to be interpreted as characters.
-
-The default external encoding is:
-
-- UTF-8 for a text stream.
-- ASCII-8BIT for a binary stream.
-
-The default external encoding is returned by method Encoding.default_external,
-and may be set by:
-
-- Ruby command-line options <tt>--external_encoding</tt> or <tt>-E</tt>.
-
-You can also set the default external encoding using method Encoding.default_external=,
-but doing so may cause problems; strings created before and after the change
-may have a different encodings.
-
-For an \IO or \File object, the external encoding may be set by:
-
-- Open options +external_encoding+ or +encoding+, when the object is created;
- see {Open Options}[rdoc-ref:IO@Open+Options].
-
-For an \IO, \File, \ARGF, or \StringIO object, the external encoding may be set by:
-
-- Methods +set_encoding+ or (except for \ARGF) +set_encoding_by_bom+.
-
-=== Internal \Encoding
-
-The internal encoding, which is an \Encoding object or +nil+,
-specifies how characters read from the stream
-are to be converted to characters in the internal encoding;
-those characters become a string whose encoding is set to the internal encoding.
-
-The default internal encoding is +nil+ (no conversion).
-It is returned by method Encoding.default_internal,
-and may be set by:
-
-- Ruby command-line options <tt>--internal_encoding</tt> or <tt>-E</tt>.
-
-You can also set the default internal encoding using method Encoding.default_internal=,
-but doing so may cause problems; strings created before and after the change
-may have a different encodings.
-
-For an \IO or \File object, the internal encoding may be set by:
-
-- Open options +internal_encoding+ or +encoding+, when the object is created;
- see {Open Options}[rdoc-ref:IO@Open+Options].
-
-For an \IO, \File, \ARGF, or \StringIO object, the internal encoding may be set by:
-
-- Method +set_encoding+.
-
-== Script \Encoding
-
-A Ruby script has a script encoding, which may be retrieved by:
-
- __ENCODING__ # => #<Encoding:UTF-8>
-
-The default script encoding is UTF-8;
-a Ruby source file may set its script encoding with a magic comment
-on the first line of the file (or second line, if there is a shebang on the first).
-The comment must contain the word +coding+ or +encoding+,
-followed by a colon, space and the Encoding name or alias:
-
- # encoding: ISO-8859-1
- __ENCODING__ #=> #<Encoding:ISO-8859-1>
-
-== Transcoding
-
-_Transcoding_ is the process of changing a sequence of characters
-from one encoding to another.
-
-As far as possible, the characters remain the same,
-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
-
-Each of these methods transcodes a string:
-
-- String#encode: Transcodes +self+ into a new string
- according to given encodings and options.
-- String#encode!: Like String#encode, but transcodes +self+ in place.
-- String#scrub: Transcodes +self+ into a new string
- by replacing invalid byte sequences with a given or default replacement string.
-- String#scrub!: Like String#scrub, but transcodes +self+ in place.
-- String#unicode_normalize: Transcodes +self+ into a new string
- according to Unicode normalization.
-- String#unicode_normalize!: Like String#unicode_normalize,
- but transcodes +self+ in place.
-
-== Transcoding a Stream
-
-Each of these methods may transcode a stream;
-whether it does so depends on the external and internal encodings:
-
-- IO.foreach: Yields each line of given stream to the block.
-- IO.new: Creates and returns a new \IO object for the given integer file descriptor.
-- IO.open: Creates a new \IO object.
-- IO.pipe: Creates a connected pair of reader and writer \IO objects.
-- IO.popen: Creates an \IO object to interact with a subprocess.
-- IO.read: Returns a string with all or a subset of bytes from the given stream.
-- IO.readlines: Returns an array of strings, which are the lines from the given stream.
-- IO.write: Writes a given string to the given stream.
-
-This example writes a string to a file, encoding it as ISO-8859-1,
-then reads the file into a new string, encoding it as UTF-8:
-
- s = "R\u00E9sum\u00E9"
- path = 't.tmp'
- ext_enc = Encoding::ISO_8859_1
- int_enc = Encoding::UTF_8
-
- File.write(path, s, external_encoding: ext_enc)
- raw_text = File.binread(path)
-
- transcoded_text = File.read(path, external_encoding: ext_enc, internal_encoding: int_enc)
-
- p raw_text
- p transcoded_text
-
-Output:
-
- "R\xE9sum\xE9"
- "Résumé"
-
-== \Encoding Options
-
-A number of methods in the Ruby core accept keyword arguments as encoding options.
-
-Some of the options specify or utilize a _replacement_ _string_, to be used
-in certain transcoding operations.
-A replacement string may be in any encoding that can be converted
-to the encoding of the destination string.
-
-These keyword-value pairs specify encoding options:
-
-- For an invalid byte sequence:
-
- - <tt>:invalid: nil</tt> (default): Raise exception.
- - <tt>:invalid: :replace</tt>: Replace each invalid byte sequence
- with the replacement string.
-
- Examples:
-
- s = "\x80foo\x80"
- s.encode(Encoding::ISO_8859_3) # Raises Encoding::InvalidByteSequenceError.
- s.encode(Encoding::ISO_8859_3, invalid: :replace) # => "?foo?"
-
-- For an undefined character:
-
- - <tt>:undef: nil</tt> (default): Raise exception.
- - <tt>:undef: :replace</tt>: Replace each undefined character
- with the replacement string.
-
- Examples:
-
- s = "\x80foo\x80"
- "\x80".encode(Encoding::UTF_8, Encoding::BINARY) # Raises Encoding::UndefinedConversionError.
- s.encode(Encoding::UTF_8, Encoding::BINARY, undef: :replace) # => "�foo�"
-
-
-- Replacement string:
-
- - <tt>:replace: nil</tt> (default): Set replacement string to default value:
- <tt>"\uFFFD"</tt> ("�") for a Unicode encoding, <tt>'?'</tt> otherwise.
- - <tt>:replace: _some_string_</tt>: Set replacement string to the given +some_string+;
- overrides +:fallback+.
-
- Examples:
-
- s = "\xA5foo\xA5"
- options = {:undef => :replace, :replace => 'xyzzy'}
- s.encode(Encoding::UTF_8, Encoding::ISO_8859_3, **options) # => "xyzzyfooxyzzy"
-
-- Replacement fallback:
-
- One of these may be specified:
-
- - <tt>:fallback: nil</tt> (default): No replacement fallback.
- - <tt>:fallback: _hash_like_object_</tt>: Set replacement fallback to the given
- +hash_like_object+; the replacement string is <tt>_hash_like_object_[X]</tt>.
- - <tt>:fallback: _method_</tt>: Set replacement fallback to the given
- +method+; the replacement string is <tt>_method_(X)</tt>.
- - <tt>:fallback: _proc_</tt>: Set replacement fallback to the given
- +proc+; the replacement string is <tt>_proc_[X]</tt>.
-
- Examples:
-
- s = "\u3042foo\u3043"
-
- hash = {"\u3042" => 'xyzzy'}
- hash.default = 'XYZZY'
- s.encode(Encoding::US_ASCII, fallback: hash) # => "xyzzyfooXYZZY"
-
- def (fallback = "U+%.4X").escape(x)
- self % x.unpack("U")
- end
- "\u{3042}".encode(Encoding::US_ASCII, fallback: fallback.method(:escape)) # => "U+3042"
-
- proc = Proc.new {|x| x == "\u3042" ? 'xyzzy' : 'XYZZY' }
- s.encode('ASCII', fallback: proc) # => "XYZZYfooXYZZY"
-
-- XML entities:
-
- One of these may be specified:
-
- - <tt>:xml: nil</tt> (default): No handling for XML entities.
- - <tt>:xml: :text</tt>: Treat source text as XML;
- replace each undefined character
- with its upper-case hexadecimal numeric character reference,
- except that:
-
- - <tt>&</tt> is replaced with <tt>&amp;</tt>.
- - <tt><</tt> is replaced with <tt>&lt;</tt>.
- - <tt>></tt> is replaced with <tt>&gt;</tt>.
-
- - <tt>:xml: :attr</tt>: Treat source text as XML attribute value;
- replace each undefined character
- with its upper-case hexadecimal numeric character reference,
- except that:
-
- - The replacement string <tt>r</tt> is double-quoted (<tt>"r"</tt>).
- - Each embedded double-quote is replaced with <tt>&quot;</tt>.
- - <tt>&</tt> is replaced with <tt>&amp;</tt>.
- - <tt><</tt> is replaced with <tt>&lt;</tt>.
- - <tt>></tt> is replaced with <tt>&gt;</tt>.
-
- Examples:
-
- s = 'foo"<&>"bar' + "\u3042"
- s.encode(Encoding::US_ASCII, xml: :text) # => "foo\"&lt;&amp;&gt;\"bar&#x3042;"
- s.encode(Encoding::US_ASCII, xml: :attr) # => "\"foo&quot;&lt;&amp;&gt;&quot;bar&#x3042;\""
-
-
-- Newlines:
-
- One of these may be specified:
-
- - <tt>:cr_newline: true</tt>: Replace each line-feed character (<tt>"\n"</tt>)
- with a carriage-return character (<tt>"\r"</tt>).
- - <tt>:crlf_newline: true</tt>: Replace each line-feed character (<tt>"\n"</tt>)
- with a carriage-return/line-feed string (<tt>"\r\n"</tt>).
- - <tt>:universal_newline: true</tt>: Replace each carriage-return
- character (<tt>"\r"</tt>) and each carriage-return/line-feed string
- (<tt>"\r\n"</tt>) with a line-feed character (<tt>"\n"</tt>).
-
- Examples:
-
- s = "\n \r \r\n" # => "\n \r \r\n"
- s.encode(Encoding::US_ASCII, cr_newline: true) # => "\r \r \r\r"
- s.encode(Encoding::US_ASCII, crlf_newline: true) # => "\r\n \r \r\r\n"
- s.encode(Encoding::US_ASCII, universal_newline: true) # => "\n \n \n"
diff --git a/doc/examples/files.rdoc b/doc/examples/files.rdoc
index f736132770..cb400c81be 100644
--- a/doc/examples/files.rdoc
+++ b/doc/examples/files.rdoc
@@ -7,8 +7,8 @@ text = <<~EOT
Fifth line
EOT
-# Russian text.
-russian = "\u{442 435 441 442}" # => "теÑÑ‚"
+# Japanese text.
+japanese = 'ã“ã‚“ã«ã¡ã¯'
# Binary data.
data = "\u9990\u9991\u9992\u9993\u9994"
@@ -16,8 +16,8 @@ data = "\u9990\u9991\u9992\u9993\u9994"
# Text file.
File.write('t.txt', text)
-# File with Russian text.
-File.write('t.rus', russian)
+# File with Japanese text.
+File.write('t.ja', japanese)
# File with binary data.
f = File.new('t.dat', 'wb:UTF-16')
diff --git a/doc/exceptions.md b/doc/exceptions.md
deleted file mode 100644
index 2c47455911..0000000000
--- a/doc/exceptions.md
+++ /dev/null
@@ -1,521 +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:
-
-```rb
-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):
-
-```console
-$ 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:
-
-```rb
-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).
-
-```rb
-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:
-
-```rb
-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):
-
-```rb
-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:
-
-```rb
-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:
-
-```rb
-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;
-they're:
-
-- `$!`: contains the rescued exception.
-- `$@`: contains its backtrace.
-
-Example:
-
-```rb
-begin
- 1 / 0
-rescue
- p $!
- p $@
-end
-```
-
-Output:
-
-```
-#<ZeroDivisionError: divided by 0>
-["t.rb:2:in 'Integer#/'", "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:
-
-```rb
-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.
-
-```rb
-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.
-
-```rb
-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:
-
- ```rb
- 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:
-
- ```rb
- 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:
-
-```rb
-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 'Integer#/': 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):
-
-```rb
-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).
-
-```rb
-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.
-
-By default, Ruby sets the backtrace of the exception to the location where it
-was raised.
-
-The developer might adjust this by either providing +backtrace+ argument
-to Kernel#raise, or using Exception#set_backtrace.
-
-Note that:
-
-- by default, both +backtrace+ and +backtrace_locations+ represent the same backtrace;
-- if the developer sets the backtrace by one of the above methods to an array of
- Thread::Backtrace::Location, they still represent the same backtrace;
-- if the developer sets the backtrace to a string or an array of strings:
- - by Kernel#raise: +backtrace_locations+ become +nil+;
- - by Exception#set_backtrace: +backtrace_locations+ preserve the original
- value;
-- if the developer sets the backtrace to +nil+ by Exception#set_backtrace,
- +backtrace_locations+ preserve the original value; but if the exception is then
- reraised, both +backtrace+ and +backtrace_locations+ become the location of reraise.
diff --git a/doc/extension.ja.rdoc b/doc/extension.ja.rdoc
index 2f7856f3d4..a943f7a109 100644
--- a/doc/extension.ja.rdoc
+++ b/doc/extension.ja.rdoc
@@ -1,5 +1,7 @@
# extension.ja.rdoc - -*- RDoc -*- created at: Mon Aug 7 16:45:54 JST 1995
+{English}[rdoc-ref:extension.rdoc]
+
= Rubyã®æ‹¡å¼µãƒ©ã‚¤ãƒ–ラリã®ä½œã‚Šæ–¹
Rubyã®æ‹¡å¼µãƒ©ã‚¤ãƒ–ラリã®ä½œã‚Šæ–¹ã‚’説明ã—ã¾ã™ï¼Ž
@@ -335,11 +337,11 @@ rb_ary_aref(int argc, const VALUE *argv, VALUE ary) ::
rb_ary_entry(VALUE ary, long offset) ::
- \ary[offset]
+ ary\[offset]
rb_ary_store(VALUE ary, long offset, VALUE obj) ::
- \ary[offset] = obj
+ ary\[offset] = obj
rb_ary_subseq(VALUE ary, long beg, long len) ::
diff --git a/doc/extension.rdoc b/doc/extension.rdoc
index ba59d107ab..9fc507706e 100644
--- a/doc/extension.rdoc
+++ b/doc/extension.rdoc
@@ -1,5 +1,7 @@
# extension.rdoc - -*- RDoc -*- created at: Mon Aug 7 16:45:54 JST 1995
+{日本語}[rdoc-ref:extension.ja.rdoc]
+
= Creating extension libraries for Ruby
This document explains how to make extension libraries for Ruby.
@@ -315,11 +317,11 @@ rb_ary_aref(int argc, const VALUE *argv, VALUE ary) ::
rb_ary_entry(VALUE ary, long offset) ::
- \ary[offset]
+ ary\[offset]
rb_ary_store(VALUE ary, long offset, VALUE obj) ::
- \ary[offset] = obj
+ ary\[offset] = obj
rb_ary_subseq(VALUE ary, long beg, long len) ::
@@ -759,6 +761,50 @@ RUBY_TYPED_FROZEN_SHAREABLE ::
If this flag is not set, the object can not become a shareable
object by Ractor.make_shareable() method.
+RUBY_TYPED_EMBEDDABLE ::
+
+ This flag indicates that Ruby may store the C struct inside the object
+ slot, rather than allocate it separately with +malloc+.
+ However, it is not a guarantee. Ruby may decide not to embed the object.
+ For instance if it's too large to fit into one of the available slot sizes.
+
+ Embedding the C struct inside the object slot reduces pointer chasing,
+ malloc overhead, and improves sweep performance.
+ In some cases, it can also reduce the memory footprint of the object.
+
+ To be embeddable, types must abide by some restrictions:
+
+ * Pointers to the C struct, or into the C struct, MUST NOT be stored,
+ as they become invalid when GC compaction occurs.
+ It is however valid to pass and use such pointers for as long as the Ruby
+ object remains on the stack.
+
+ In a sense, this is similar to the restrictions of a stack allocated struct.
+
+ The +RB_GC_GUARD+ macro must be used to ensure the object is not moved by
+ compaction and not freed, unless the object is passed directly as an
+ argument from Ruby to C, i.e. as a parameter of a function used with
+ +rb_define_method+ and similar.
+
+ * The +DATA_PTR+ and +RTYPEDDATA_DATA+ macro can't be used.
+ Only +RTYPEDDATA_GET_DATA+` or +TypedData_Get_Struct+ macros can be used
+ with embeddable objects.
+ Accessing `RDATA(obj)->data` or `RTYPEDDATA(obj)->data` is invalid too.
+
+ * The +dfree+ function MUST NOT free the C struct itself.
+ Setting +dfree+ to +RUBY_DEFAULT_FREE+ is fine.
+ To support older Ruby versions without this feature, you can
+ conditionally free the C struct if +RUBY_TYPED_EMBEDDABLE+ isn't defined.
+
+ * The type must have the +RUBY_TYPED_FREE_IMMEDIATELY+ flag set.
+
+ If the embedded C struct is of variable size, +rb_data_typed_object_zalloc+
+ can be used instead of +TypedData_Make_Struct+.
+
+ See {Embedded TypedData}[rdoc-ref:@Appendix+G.+Embedded+TypedData] for a
+ commented example of how to use +RUBY_TYPED_EMBEDDABLE+.
+
+
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.
@@ -2047,7 +2093,7 @@ the <code>*_kw</code> functions introduced in Ruby 2.7.
#define rb_proc_call_with_block_kw(p, c, v, b, kw) rb_proc_call_with_block(p, c, v, b)
#define rb_method_call_kw(c, v, m, kw) rb_method_call(c, v, m)
#define rb_method_call_with_block_kw(c, v, m, b, kw) rb_method_call_with_block(c, v, m, b)
- #define rb_eval_cmd_kwd(c, a, kw) rb_eval_cmd(c, a, 0)
+ #define rb_eval_cmd_kw(c, a, kw) rb_eval_cmd(c, a, 0)
#endif
== Appendix C. Functions available for use in extconf.rb
@@ -2283,6 +2329,89 @@ To make a "Ractor-safe" C extension, we need to check the following points:
making of a Ractor-safe extension. This document will be extended as they are
discovered.
+== Appendix G. Embedded TypedData
+
+Here is an example of how to use +RUBY_TYPED_EMBEDDABLE+::
+
+ struct my_data {
+ struct timespec created_at;
+ size_t buffer_capa;
+ char *buffer;
+ };
+
+ static void
+ my_data_free(void *ptr)
+ {
+ struct my_data *data = (struct my_data *)ptr;
+
+ // Deliberately don't free `ptr` if it is embeddable.
+ // Only auxiliary memory need to be freed.
+ ruby_xfree(data->buffer);
+ }
+
+ static size_t
+ my_data_size(const void *ptr)
+ {
+ const struct my_data *data = (const struct my_data *)ptr;
+ // We don't need to account for `sizeof(struct my_struct)` because it is embedded inside the Ruby object.
+ // Only auxiliary memory need to be reported.
+ return data->buffer_capa;
+ }
+
+ static const rb_data_type_t my_type = {
+ .wrap_struct_name = "my_type",
+ .function = {
+ .dfree = my_data_free,
+ .dsize = my_data_size,
+ }
+ .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_EMBEDDABLE,
+ };
+
+ static VALUE
+ my_data_alloc(VALUE klass)
+ {
+ struct my_data *data;
+ VALUE obj = TypedData_Make_Struct(klass, struct my_data, &my_type, data);
+
+ // Is it fine to pass pointers into the embedded struct, for as long as
+ // the called function won't use it after the Ruby object have left the stack.
+ clock_gettime(CLOCK_REALTIME, &data->created_at);
+ data->buffer_capa = 1024;
+ data->buffer = ZALLOC_N(char, data->buffer_capa);
+
+ return obj
+ }
+
+ static VALUE
+ my_data_m_parse(VALUE klass)
+ {
+ struct my_data *data;
+ VALUE my_data_obj = my_data_alloc(klass);
+ TypedData_Get_Struct(obj, struct my_data, &my_type, data);
+
+ // `my_data_obj` was allocated from C, `RB_GC_GUARD` must be used to
+ // ensure the compiler will keep its reference on the stack.
+ RB_GC_GUARD(my_data_obj)
+ }
+
+ static VALUE
+ my_data_read(VALUE self)
+ {
+ struct my_data *data;
+ TypedData_Get_Struct(obj, struct my_data, &my_type, data);
+
+ // `self` is received from `rb_define_method` so `RB_GC_GUARD` isn't necessary.
+ return rb_str_new(data->buffer, data->buffer_capa)
+ }
+
+ void
+ Init_my_data(void)
+ {
+ VALUE cMyData = rb_define_class("MyData");
+ rb_define_method(cMyData, "read", my_data_read, 0);
+ rb_define_singleton_method(cMyData, "parse", my_data_m_parse, 0);
+ }
+
--
Local variables:
fill-column: 70
diff --git a/doc/file/filename_globbing.md b/doc/file/filename_globbing.md
new file mode 100644
index 0000000000..ce4549bffe
--- /dev/null
+++ b/doc/file/filename_globbing.md
@@ -0,0 +1,299 @@
+# Filename Globbing
+
+Filename globbing is a pattern-matching feature implemented in certain Ruby methods:
+
+- Dir.glob.
+- [`Dir[]`](https://docs.ruby-lang.org/en/master/Dir.html#method-c-5B-5D).
+- Pathname.glob.
+- Pathname#glob.
+
+Each `glob` method finds filesystem entries (files and directories)
+that match certain patterns.
+
+These methods are quite different
+from [filename-matching](rdoc-ref:filename_matching.md) methods,
+which match patterns against string paths, and do not access the filesystem.
+
+## Patterns
+
+These are the basic elements of filename-globbing patterns;
+see the sections below for details:
+
+| Pattern | Meaning | Examples |
+|:------------------------:|------------------------------------------|------------------------------|
+| Simple string. | Matches itself. | `'LEGAL'` |
+| `'*'` | Matches any sequence of characters. | `'*.txt'` |
+| `'?'` | Matches any single character. | `'?.txt'` |
+| `'[abc]'`,<br>`'[^abc]'` | Matches a single character from a set. | `'x[abc]y'`,<br>`'x[^abc]y'` |
+| `'[a-z]`',<br>`'[^a-z]'` | Matches a single character from a range. | `'x[0-9]y'`,<br>`'x[^0-9]y'` |
+| `'{ , }'` | Matches alternatives. | `'{abc,def}'` |
+| `'**'` | Matches directories recursively. | `'**/test.rb'` |
+| `'\'` | Escapes the next character. | `'\\*'`, `'\?'` |
+
+## Patterns
+
+### Simple \String
+
+A "simple string" is one that does not contain special filename-globbing patterns;
+see the table above.
+
+A simple string matches itself:
+
+```ruby
+Dir.glob('LEGAL') # => ["LEGAL"]
+Dir.glob('LEGA') # => [] # Must be exact.
+Dir.glob('legal') # => [] # Case-sensitive.
+```
+
+Note that case-sensitivity may _not_ be modified by flags.
+
+By default, the Windows short name pattern is disabled:
+
+```ruby
+Dir.glob('PROGRAM~1') # => []
+```
+
+It may be enabled by flag [`File::FNM_SHORTNAME`](#constant-filefnmshortname).
+
+
+### Any Sequence of Characters (`'*'`)
+
+The asterisk pattern (`'*'`) matches any sequence of characters:
+
+```ruby
+Dir.glob('*').take(3) # => ["BSDL", "CONTRIBUTING.md", "COPYING"]
+Dir.glob('\*') # => [] # Escaped.
+```
+
+By default, the asterisk pattern does not match a leading period (as in a dot-file):
+
+```ruby
+Dir.glob('*').select {|entry| entry.start_with?('.') } # => []
+```
+
+That matching may be enabled by flag [`File::FNM_DOTMATCH`](#constant-filefnmdotmatch).
+
+The asterisk pattern does not match across file separators:
+
+```ruby
+Dir.glob('*.rb').select {|entry| entry.include?('/') } # => []
+```
+
+Therefore flag File::FNM_PATHNAME does not affect the pattern.
+
+### Single Character (`'?'`)
+
+The question-mark pattern (`'?'`) matches any single character:
+
+```ruby
+Dir.glob('???') # => ["GPL", "bin", "doc", "enc", "ext", "jit", "lib", "man"]
+Dir.glob('??') # => ["gc"] # Only one entry with a 2-character name.
+Dir.glob('?') # => [] # No entries with a 1-character name.
+Dir.glob('\?') # => [] # No entries containing character '?'.
+```
+
+By default, the question-mark pattern does not match a leading period (as in a dot-file):
+
+```ruby
+Dir.glob(".???") # => [".git"]
+Dir.glob("????").select {|entry| entry.start_with?('.') } # => []
+```
+
+That matching may be enabled by flag [`File::FNM_DOTMATCH`](#constant-filefnmdotmatch).
+
+### Single Character from a Set (`'[abc]'`, `'[^abc]'`)
+
+Characters enclosed in square brackets define a set of characters,
+any of which matches a single character:
+
+```ruby
+Dir.glob('[efgh][abcd]') # => ["gc"]
+Dir.glob('\[efgh][abcd]') # => [] # Escaped.
+```
+
+The character set may be negated:
+
+```ruby
+Dir.glob('[^abcd][^efgh]') # => ["gc"]
+```
+
+### Single Character from a \Range (`'[a-c]'`, `'[^a-c]'`)
+
+A range of characters enclosed in square brackets defines a set of characters,
+any of which matches a single character:
+
+```ruby
+Dir.glob('[k-m][h-j][a-c]') # => ["lib"]
+Dir.glob('\[k-m][h-j][a-c]') # => [] # Escaped.
+```
+
+The range may be negated:
+
+```ruby
+Dir.glob('[^k-m][h-j][a-c]') # => []
+Dir.glob('[^a-c][^k-m][^h-j]') # => ["GPL", "doc", "enc", "ext", "jit", "lib", "man"]
+```
+
+### Alternatives (`'{ , }'`)
+
+The alternatives pattern consists of comma-separated strings
+enclosed in curly braces:
+
+```ruby
+Dir.glob('{k,L,R}*') # => ["kernel.rb", "LEGAL", "README.ja.md", "README.md"]
+Dir.glob('{R,L,k}*') # => ["README.ja.md", "README.md", "LEGAL", "kernel.rb"]
+# Whitespace matters:
+Dir.glob('{k ,L,R}*') # => ["LEGAL", "README.ja.md", "README.md"]
+```
+
+### Recursive Directory Matching (`'**'`)
+
+The double-asterisk pattern (`'**'`) matches directories recursively:
+
+```ruby
+# Find all entries everywhere ending with '.ja'.
+Dir.glob('**/*.ja')
+# => ["COPYING.ja", "doc/pty/README.expect.ja", "doc/pty/README.ja"]
+
+# Find all entries everywhere ending with '.rb'.
+Dir.glob('**/*.rb').size # => 7574
+Dir.glob('**/*.rb').take(3)
+# => ["KNOWNBUGS.rb", "array.rb", "ast.rb"]
+
+# Find all entries in directory 'lib' ending with `.rb'.
+Dir.glob('lib/**/*.rb').size # => 626
+Dir.glob('lib/**/*.rb').take(3)
+# # =>
+# ["lib/English.rb",
+# "lib/bundled_gems.rb",
+# "lib/bundler/build_metadata.rb"]
+
+# Find all entries in directory 'test/ruby' ending with '.rb'.
+Dir.glob('test/ruby/**/*.rb').size # => 200
+Dir.glob('test/ruby/**/*.rb').take(3)
+# # =>
+# ["test/ruby/allpairs.rb",
+# "test/ruby/beginmainend.rb",
+# "test/ruby/box/a.1_1_0.rb"]
+
+# Escaped.
+Dir.glob('\**/*.rb') # => []
+```
+
+
+### Escape (`'\'`)
+
+The backslash character (`'\'`) may be used to escape any of the characters
+that filename globbing treats as special:
+
+```ruby
+Dir.glob('\*') # => []
+Dir.glob('\?') # => []
+Dir.glob('\[efgh][abcd]') # => []
+Dir.glob('\[k-m][h-j][a-c]') # => []
+Dir.glob('\**/*.rb') # => []
+```
+
+## Keyword Arguments
+
+| Keyword | Value | Default | Meaning |
+|-------------------|--------------------------|:-------:|-----------------------------------------|
+| [`base`](#base) | \String path. | `'.'` | Root for searching. |
+| [`flags`](#flags) | Logical OR of constants. | `0` | Modify globbing behavior. |
+| [`sort`](#sort) | `true` or `false` | `true` | Whether returned array is to be sorted. |
+
+### `base`
+
+Optional keyword argument `base` (defaults to `'.'`)
+specifies where in the filesystem the searching is to begin:
+
+```ruby
+Dir.glob('*').size # => 241
+Dir.glob('*').take(3)
+# => ["BSDL", "CONTRIBUTING.md", "COPYING"]
+
+Dir.glob('*', base: 'lib').size # => 72
+Dir.glob('*', base: 'lib').take(3)
+# => ["English.gemspec", "English.rb", "bundled_gems.rb"]
+
+Dir.glob('*', base: 'lib/net').size # => 5
+Dir.glob('*', base: 'lib/net').take(3)
+# => ["http", "http.rb", "https.rb"]
+```
+
+### `flags`
+
+Optional keyword argument `flags` (defaults to `0`) may be the bitwise OR
+of the constants `File::FNM*`:
+
+```ruby
+Dir.glob('*', flags: File::FNM_DOTMATCH | File::FNM_NOESCAPE)
+```
+
+These are the constants for filename-globbing patterns;
+see the sections below for details:
+
+
+| Constant | Meaning |
+|-----------------------------------------------------|--------------------------------------------|
+| [`File::FNM_DOTMATCH`](#constant-filefnmdotmatch) | Make pattern `'*'` match a leading period. |
+| [`File::FNM_NOESCAPE`](#constant-filefnmnoescape) | Disable escaping. |
+| [`File::FNM_SHORTNAME`](#constant-filefnmshortname) | Enable short-name matching (Windows only). |
+
+These constants do not affect filename globbing:
+
+- File::FNM_CASEFOLD.
+- File::FNM_EXTGLOB.
+- File::FNM_PATHNAME.
+- File::FNM_SYSCASE.
+
+#### Constant File::FNM_DOTMATCH
+
+By default, filename globbing does not allow patterns `'*'` and `'?'` to match a dotfile name
+(i.e, an entry name beginning with a dot);
+use constant [`File::FNM_DOTMATCH`](#constant-filefnmdotmatch)
+to enable the match:
+
+```ruby
+Dir.glob('*').size # => 241
+Dir.glob('*', flags: File::FNM_DOTMATCH).size # => 256
+Dir.glob('*', flags: File::FNM_DOTMATCH).take(3) # => [".", ".dir-locals.el", ".document"]
+```
+
+#### Constant File::FNM_NOESCAPE
+
+By default filename globbing has escaping enabled;
+use constant [`File::FNM_NOESCAPE`](#constant-filefnmnoescape)
+to disable it:
+
+```ruby
+Dir.glob('*').size # => 241
+Dir.glob('\*').size # => 0
+```
+
+#### Constant File::FNM_SHORTNAME
+
+By default, Windows shortname matching is disabled;
+use constant [`File::FNM_SHORTNAME`](#constant-filefnmshortname)
+to enable it (on Windows only).
+
+Using that constant allows patterns to match short names
+in filename globbing on Windows,
+which can be useful for compatibility with legacy applications
+that rely on these short names;
+see [8.3 filename](https://en.wikipedia.org/wiki/8.3_filename).
+This feature helps ensure that file operations work correctly
+even when dealing with files that have long names.
+
+### `sort`
+
+Optional keyword argument `sort` (defaults to `'true'`)
+specifies whether the returned array is to be sorted:
+
+```ruby
+Dir.glob('*').take(3)
+# => ["BSDL", "CONTRIBUTING.md", "COPYING"]
+Dir.glob('*', sort: false).take(3)
+# => ["gc.rb", "yjit.rb", "iseq.h"]
+```
+
diff --git a/doc/file/filename_matching.md b/doc/file/filename_matching.md
new file mode 100644
index 0000000000..cf5b60bac2
--- /dev/null
+++ b/doc/file/filename_matching.md
@@ -0,0 +1,353 @@
+# Filename Matching
+
+Filename matching is a pattern-matching feature implemented in certain Ruby methods:
+
+- File.fnmatch.
+- Pathname#fnmatch.
+
+Each `fnmatch` method matches a pattern against a string _path_;
+these methods operate only on strings, and do not access the file system.
+
+These methods are quite different
+from [filename-globbing](rdoc-ref:filename_globbing.md) methods,
+which match patterns against string paths found in the actual file system.
+
+## Patterns
+
+These are the basic elements of filename matching patterns;
+see the sections below for details:
+
+| Pattern | Meaning | Examples |
+|:------------------------:|--------------------------------------------|------------------------------|
+| Simple string. | Matches itself. | `'Rakefile'`, `'LEGAL'` |
+| `'*'` | Matches any sequence of characters. | `'*.txt'` |
+| `'?'` | Matches any single character. | `'?.txt'` |
+| `'[abc]'`,<br>`'[^abc]'` | Matches a single character from a set. | `'x[abc]y'`,<br>`'x[^abc]y'` |
+| `'[a-z]`',<br>`'[^a-z]'` | Matches a single character from a range. | `'x[0-9]y'`,<br>`'x[^0-9]y'` |
+| `'\'` | Escapes the next character. | `'\\*'`, `'\?'` |
+
+There are two other patterns that are disabled by default:
+
+- Directory-like substring (`'**'`);
+ see [`File::FNM_PATHNAME`](#constant-filefnmpathname) below.
+- Alternatives (`'{ , }'`);
+ see [`File::FNM_EXTGLOB`](#constant-filefnmextglob) below.
+
+### Simple \String
+
+A "simple string" is one that does not contain special filename-matching patterns;
+see the table above.
+
+A simple string matches itself:
+
+```ruby
+File.fnmatch('xyzzy', 'xyzzy') # => true
+File.fnmatch('one_two_three', 'one_two_three') # => true
+File.fnmatch('123', '123') # => true
+File.fnmatch('Form 27B/6', 'Form 27B/6') # => true
+File.fnmatch('bcd', 'abcde') # => false # Must be exact.
+```
+
+By default, the matching is case-sensitive:
+
+```ruby
+File.fnmatch('abc', 'ABC') # => false
+```
+
+Case-sensitivity may be modified by flags:
+
+- [`File::FNM_CASEFOLD`](#constant-filefnmcasefold).
+- [`File::FNM_SYSCASE`](#constant-filefnmsyscase).
+
+By default, the alternatives pattern is disabled:
+
+```rutby
+File.fnmatch('R{ub,foo}y', 'Ruby') # => false
+```
+
+It may be enabled by flag [`File::FNM_EXTGLOB`](#constant-filefnmextglob).
+
+By default, the Windows short name pattern is disabled:
+
+```ruby
+File.fnmatch('PROGRAM~1', 'Program Files') # => false
+```
+
+It may be enabled by flag [`File::FNM_SHORTNAME`](#constant-filefnmshortname).
+
+### Any Sequence of Characters (`'*'`)
+
+The asterisk pattern (`'*'`) matches any sequence of characters:
+
+```ruby
+File.fnmatch('*', 'foo') # => true
+File.fnmatch('*', '') # => true
+File.fnmatch('*', '*') # => true
+File.fnmatch('\*', 'foo') # => false # Escaped.
+```
+
+By default, the asterisk pattern does not match a leading period (as in a dot-file):
+
+```ruby
+File.fnmatch('*', '.document') # => false
+```
+
+That matching may be enabled by flag [`File::FNM_DOTMATCH`](#constant-filefnmdotmatch).
+
+By default, the asterisk pattern matches across file separators:
+
+```ruby
+File.fnmatch('*.rb', 'lib/test.rb') # => true
+```
+
+That matching may be disabled by flag [`File::FNM_PATHNAME`](#constant-filefnmpathname).
+
+### Single Character (`'?'`)
+
+The question-mark pattern (`'?'`) matches any single character:
+
+```ruby
+File.fnmatch('?', 'f') # => true
+File.fnmatch("foo-?.txt", "foo-1.txt") # => true
+File.fnmatch('?', 'foo') # => false
+File.fnmatch('?', '') # => false
+File.fnmatch('\?', 'f') # => false # Escaped.
+```
+
+By default, pattern `'?'` matches the file separator:
+
+```ruby
+File.fnmatch('foo?boo', 'foo/boo') # => true
+```
+
+That matching may be disabled by flag [`File::FNM_PATHNAME`](#constant-filefnmpathname).
+
+### Single Character from a Set (`'[abc]'`, `'[^abc]'`)
+
+Characters enclosed in square brackets define a set of characters,
+any of which matches a single character:
+
+```ruby
+File.fnmatch('[ruby]', 'r') # => true
+File.fnmatch('[ruby]', 'u') # => true
+File.fnmatch('[ruby]', 'y') # => true
+File.fnmatch('[ruby]', 'ruby') # => false
+File.fnmatch('\[ruby]', 'r') # => false # Escaped.
+```
+
+The character set may be negated:
+
+```ruby
+File.fnmatch('[^ruby]', 'r') # => false
+File.fnmatch('[^ruby]', 'u') # => false
+```
+
+### Single Character from a \Range (`'[a-c]'`, `'[^a-c]'`)
+
+A range of characters enclosed in square brackets defines a set of characters,
+any of which matches a single character:
+
+```ruby
+File.fnmatch('[a-c]', 'b') # => true
+File.fnmatch('[a-c]', 'd') # => false
+File.fnmatch('[a-c]', 'abc') # => false
+File.fnmatch('R[t-v][a-c]y', 'Ruby') # => true # Multiple ranges allowed.
+File.fnmatch('\[a-c]', 'b') # => false # Escaped.
+```
+
+The range may be negated:
+
+```ruby
+File.fnmatch('[^a-c]', 'b') # => false
+File.fnmatch('[^a-c]', 'd') # => true
+```
+
+### Escape (`'\'`)
+
+The backslash character (`'\'`) may be used to escape any of the characters
+that filename matching treats as special:
+
+```ruby
+File.fnmatch('[a-c]', 'b') # => true
+File.fnmatch('\[a-c]', 'b') # => false
+File.fnmatch('[a-c\]', 'b') # => false
+File.fnmatch('[a\-c]', 'b') # => false
+
+File.fnmatch('{a,b}', 'b', File::FNM_EXTGLOB) # => true
+File.fnmatch('\{a,b}', 'b', File::FNM_EXTGLOB) # => false
+File.fnmatch('{a\,b}', 'b', File::FNM_EXTGLOB) # => false
+File.fnmatch('{a,b\}', 'b', File::FNM_EXTGLOB) # => false
+```
+
+Use a double-backslash to represent an ordinary backslash:
+
+```ruby
+File.fnmatch('\\\\', '\\') # => true
+```
+
+By default escape pattern `'\'` is enabled;
+it may be disabled by flag [`File::FNM_NOESCAPE`](#constant-filefnmnoescape).
+
+## Flags
+
+Optional argument `flags` (defaults to `0`) may be the bitwise OR
+of the constants `File::FNM*`.
+
+These are the constants for filename-matching patterns;
+see the sections below for details:
+
+| Constant | Meaning |
+|-----------------------------------------------------|-------------------------------------------------------------|
+| [`File::FNM_CASEFOLD`](#constant-filefnmcasefold) | Make the pattern case-insensitive. |
+| [`File::FNM_DOTMATCH`](#constant-filefnmdotmatch) | Make pattern `*` match a leading period.. |
+| [`File::FNM_EXTGLOB`](#constant-filefnmextglob) | Enable alternatives in pattern. |
+| [`File::FNM_NOESCAPE`](#constant-filefnmnoescape) | Disable escaping. |
+| [`File::FNM_PATHNAME`](#constant-filefnmpathname) | Make patterns `'*'` and `'?'` not match the file separator. |
+| [`File::FNM_SHORTNAME`](#constant-filefnmshortname) | Enable short-name matching (Windows only). |
+| [`File::FNM_SYSCASE`](#constant-filefnmsyscase) | Make the pattern use OS's case sensitivity. |
+
+
+### Constant File::FNM_CASEFOLD
+
+By default, filename matching is case-sensitive;
+use constant [`File::FNM_CASEFOLD`](#constant-filefnmcasefold)
+to make the matching case-insensitive:
+
+```ruby
+File.fnmatch('abc', 'ABC') # => false
+File.fnmatch('abc', 'ABC', File::FNM_CASEFOLD) # => true
+```
+
+### Constant File::FNM_DOTMATCH
+
+By default, filename matching does not allow pattern `'*'` to match a dotfile name
+(i.e, a filename beginning with a dot);
+use constant [`File::FNM_DOTMATCH`](#constant-filefnmdotmatch)
+to enable the match:
+
+```ruby
+File.fnmatch('*', '.document') # => false
+File.fnmatch('*', '.document', File::FNM_DOTMATCH) # => true
+```
+### Constant File::FNM_EXTGLOB
+
+By default, filename matching has the alternative notation disabled;
+use constant [`File::FNM_EXTGLOB`](#constant-filefnmextglob)
+to enable it:
+
+```ruby
+File.fnmatch('R{ub,foo}y', 'Ruby') # => false
+File.fnmatch('R{ub,foo}y', 'Ruby', File::FNM_EXTGLOB) # => true
+```
+
+The alternatives pattern consists of zero or more unquoted strings,
+separated by commas, and enclosed in curly braces:
+
+```ruby
+File.fnmatch('R{ub,foo,bar}y', 'Ruby') # => false # Not enabled.
+File.fnmatch('R{ub,foo,bar}y', 'Ruby', File::FNM_EXTGLOB) # => true
+# Whitespace matters.
+File.fnmatch('R{ub ,foo,bar}y', 'Ruby', File::FNM_EXTGLOB) # => false
+File.fnmatch('R{ ub,foo,bar}y', 'Ruby', File::FNM_EXTGLOB) # => false
+# Special characters remain in force:
+File.fnmatch('{*,?}', 'hello', File::FNM_EXTGLOB) # => true
+File.fnmatch('{*ello,?}', 'hello', File::FNM_EXTGLOB) # => true
+File.fnmatch('{*ELLO,?}', 'hello', File::FNM_EXTGLOB) # => false
+File.fnmatch('{*ELLO,?????}', 'hello', File::FNM_EXTGLOB) # => true
+# With the flag not given.
+File.fnmatch('R{ub,foo,bar}y', 'Ruby') # => false
+```
+
+### Constant File::FNM_NOESCAPE
+
+By default filename matching has escaping enabled;
+use constant [`File::FNM_NOESCAPE`](#constant-filefnmnoescape)
+to disable it:
+
+```ruby
+File.fnmatch('\*\?\*\*', '*?**') # => true
+File.fnmatch('\*\?\*\*', '*?**', File::FNM_NOESCAPE) # => false
+```
+
+### Constant File::FNM_PATHNAME
+
+Flag [`File::FNM_PATHNAME`](#constant-filefnmpathname) affects
+patterns `'**'`, `'*'`, and `'?'`.
+
+By default, the double-asterisk pattern (`'**'`) is equivalent to pattern `'*'`,
+and matches any sequence of directory-like substrings:
+
+```ruby
+File.fnmatch('**', 'a/b/c') # => true
+File.fnmatch('*', 'a/b/c') # => true
+```
+
+When flag [`File::FNM_PATHNAME`](#constant-filefnmpathname) is given,
+the pattern matches only one component of a file path:
+
+```ruby
+File.fnmatch('**', 'a/b/c') # => true # Matches 'a/b/c'.
+File.fnmatch('**', 'a/b/c', File::FNM_PATHNAME) # => false # Matches only 'a'.
+File.fnmatch('**', 'a/b/c', File::FNM_PATHNAME) # => false # Matches only 'a/b'.
+File.fnmatch('**/*', 'a/b/c', File::FNM_PATHNAME) # => true # Matches 'a/b', then 'c'.
+```
+
+By default, filename matching enables pattern `'*'` to match
+at or across the file separator (`File::SEPARATOR`);
+use constant [`File::FNM_PATHNAME`](#constant-filefnmpathname)
+to disable such matching:
+
+```ruby
+File::SEPARATOR # => "/"
+File.fnmatch('*.rb', 'lib/test.rb') # => true
+File.fnmatch('*.rb', 'lib/test.rb', File::FNM_PATHNAME) # => false
+```
+
+By default, filename matching enables pattern `'?'` to match
+at or across the file separator (`File::SEPARATOR`);
+use constant [`File::FNM_PATHNAME`](#constant-filefnmpathname)
+to disable such matching:
+
+```ruby
+File.fnmatch('foo?boo', 'foo/boo') # => true
+File.fnmatch('foo?boo', 'foo/boo', File::FNM_PATHNAME) # => false
+```
+
+### Constant File::FNM_SHORTNAME
+
+By default, Windows shortname matching is disabled;
+use constant [`File::FNM_SHORTNAME`](#constant-filefnmshortname)
+to enable it (on Windows only).
+
+Using that constant allows patterns to match short names
+in filename matching on Windows,
+which can be useful for compatibility with legacy applications
+that rely on these short names;
+see [8.3 filename](https://en.wikipedia.org/wiki/8.3_filename).
+This feature helps ensure that file operations work correctly
+even when dealing with files that have long names.
+
+```ruby
+File::FNM_SHORTNAME.zero? # => false # On Windows, not zero; may be enabled.
+File::FNM_SHORTNAME.zero? # => true # Elsewhere, always zero; may not be enabled.
+
+File.fnmatch('PROGRAM~1', 'Program Files') # => false
+# This will be true if and only if on Windows and short name 'PROGRAM~1' exists.
+File.fnmatch('PROGRAM~1', 'Program Files', File::FNM_SHORTNAME) # => true
+```
+
+### Constant File::FNM_SYSCASE
+
+By default, filename matching uses Ruby's own case-sensitivity rules;
+use constant [`File::FNM_SYSCASE`](#constant-filefnmsyscase)
+to use the case-sensitivity rules of the underlying file system:
+
+```ruby
+File::FNM_SYSCASE.zero? # => false # On Windows, not zero; may be enabled.
+File::FNM_SYSCASE.zero? # => true # Elsewhere, always zero; may not be enabled.
+
+File.fnmatch('abc', 'ABC') # => false # Ruby; case-sensitive.
+File.fnmatch('abc', 'ABC', File::FNM_SYSCASE) # => true # Windows; case-insensitive.
+File.fnmatch('abc', 'ABC', File::FNM_SYSCASE) # => false # Linus; case-sensitive.
+```
+
diff --git a/doc/file/timestamps.md b/doc/file/timestamps.md
new file mode 100644
index 0000000000..c8ad616567
--- /dev/null
+++ b/doc/file/timestamps.md
@@ -0,0 +1,83 @@
+# \File System Timestamps
+
+A file system entry (the name of a file or directory)
+has several times (called timestamps) associated with it.
+
+The Ruby methods that return these timestamps (each as a Time object)
+are actually returning "whatever the OS says,"
+and so their behaviors may vary among OS platforms.
+If a platform does not support a particular timestamp,
+the corresponding Ruby methods raise NotImplementedError.
+
+These timestamps are:
+
+| Name | Meaning | Changes |
+|:--------------------------------:|----------------------------------------|-----------------------|
+| [`birthtime`](#birth-time) | Create time. | Never. |
+| [`mtime`](#modification-time) | Modification time. | When written. |
+| [`atime`](#access-time) | Access time. | When read or written. |
+| [`ctime`](#metadata-change-time) | Metadata-change time (or create time). | See below. |
+
+## Birth \Time
+
+The birth time for an entry is the time the entry was created.
+The birth time does not change, although if the entry is deleted and re-created,
+the birth time will be different.
+
+Each of these methods returns the birth time for an entry as a Time object:
+
+- File::birthtime.
+- File#birthtime.
+- File::Stat#birthtime.
+- Pathname#birthtime.
+
+On Windows, each of these methods also returns the birth time:
+
+- File::ctime.
+- File#ctime.
+- File::Stat#ctime.
+- Pathname#ctime.
+
+## Modification \Time
+
+The modification time for an entry is the time the entry was last modified.
+The modification time is updated when the entry is written,
+though some file systems may delay the update.
+
+Each of these methods returns the modification time for an entry as a Time object:
+
+- File::mtime.
+- File#mtime.
+- File::Stat#mtime.
+- Pathname#mtime.
+
+## Access \Time
+
+The access time for an entry is the time the entry last read.
+The access time is updated when the entry is read,
+though some file systems may delay the update.
+
+Each of these methods returns the access time for an entry as a Time object:
+
+- File::atime.
+- File#atime.
+- File::Stat#atime.
+- Pathname#atime.
+
+## Metadata-Change \Time
+
+The metadata-change time for an entry is the time the entry last read.
+The metadata-change time is updated when the entry's metadata is changed;
+changing access mode or permissions may update the metadata-change time,
+though some file systems may delay the update.
+
+On non-Windows systems,
+each of these methods returns the metadata-change time for an entry:
+
+- File::ctime.
+- File#ctime.
+- File::Stat#ctime.
+- Pathname#ctime.
+
+On Windows, each `ctime` method returns the birth time,
+not the metadata-change time.
diff --git a/doc/float.rb b/doc/float.rb
new file mode 100644
index 0000000000..93b57ebc4c
--- /dev/null
+++ b/doc/float.rb
@@ -0,0 +1,128 @@
+# A \Float object stores a real number
+# using the native architecture's double-precision floating-point representation.
+#
+# == \Float Imprecisions
+#
+# Some real numbers can be represented precisely as \Float objects:
+#
+# 37.5 # => 37.5
+# 98.75 # => 98.75
+# 12.3125 # => 12.3125
+#
+# Others cannot; among these are the transcendental numbers, including:
+#
+# - Pi, <i>Ï€</i>: in mathematics, a number of infinite precision:
+# 3.1415926535897932384626433... (to 25 places);
+# in Ruby, it is of limited precision (in this case, to 16 decimal places):
+#
+# Math::PI # => 3.141592653589793
+#
+# - Euler's number, <i>e</i>: in mathematics, a number of infinite precision:
+# 2.7182818284590452353602874... (to 25 places);
+# in Ruby, it is of limited precision (in this case, to 15 decimal places):
+#
+# Math::E # => 2.718281828459045
+#
+# Some floating-point computations in Ruby give precise results:
+#
+# 1.0/2 # => 0.5
+# 100.0/8 # => 12.5
+#
+# Others do not:
+#
+# - In mathematics, 2/3 as a decimal number is an infinitely-repeating decimal:
+# 0.666... (forever);
+# in Ruby, +2.0/3+ is of limited precision (in this case, to 16 decimal places):
+#
+# 2.0/3 # => 0.6666666666666666
+#
+# - In mathematics, the square root of 2 is an irrational number of infinite precision:
+# 1.4142135623730950488016887... (to 25 decimal places);
+# in Ruby, it is of limited precision (in this case, to 16 decimal places):
+#
+# Math.sqrt(2.0) # => 1.4142135623730951
+#
+# - Even a simple computation can introduce imprecision:
+#
+# x = 0.1 + 0.2 # => 0.30000000000000004
+# y = 0.3 # => 0.3
+# x == y # => false
+#
+# See:
+#
+# - https://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html
+# - https://github.com/rdp/ruby_tutorials_core/wiki/Ruby-Talk-FAQ#user-content--why-are-rubys-floats-imprecise
+# - https://en.wikipedia.org/wiki/Floating_point#Accuracy_problems
+#
+# Note that precise storage and computation of rational numbers
+# is possible using Rational objects.
+#
+# == Creating a \Float
+#
+# You can create a \Float object explicitly with:
+#
+# - A {floating-point literal}[rdoc-ref:syntax/literals.rdoc@Float+Literals].
+#
+# You can convert certain objects to Floats with:
+#
+# - Method #Float.
+#
+# == What's Here
+#
+# First, what's elsewhere. Class \Float:
+#
+# - Inherits from
+# {class Numeric}[rdoc-ref:Numeric@Whats+Here]
+# and {class Object}[rdoc-ref:Object@Whats+Here].
+# - Includes {module Comparable}[rdoc-ref:Comparable@Whats+Here].
+#
+# Here, class \Float provides methods for:
+#
+# - {Querying}[rdoc-ref:Float@Querying]
+# - {Comparing}[rdoc-ref:Float@Comparing]
+# - {Converting}[rdoc-ref:Float@Converting]
+#
+# === Querying
+#
+# - #finite?: Returns whether +self+ is finite.
+# - #hash: Returns the integer hash code for +self+.
+# - #infinite?: Returns whether +self+ is infinite.
+# - #nan?: Returns whether +self+ is a NaN (not-a-number).
+#
+# === Comparing
+#
+# - #<: Returns whether +self+ is less than the given value.
+# - #<=: Returns whether +self+ is less than or equal to the given value.
+# - #<=>: Returns a number indicating whether +self+ is less than, equal
+# to, or greater than the given value.
+# - #== (aliased as #=== and #eql?): Returns whether +self+ is equal to
+# the given value.
+# - #>: Returns whether +self+ is greater than the given value.
+# - #>=: Returns whether +self+ is greater than or equal to the given value.
+#
+# === Converting
+#
+# - #% (aliased as #modulo): Returns +self+ modulo the given value.
+# - #*: Returns the product of +self+ and the given value.
+# - #**: Returns the value of +self+ raised to the power of the given value.
+# - #+: Returns the sum of +self+ and the given value.
+# - #-: Returns the difference of +self+ and the given value.
+# - #/: 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+
+# - #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.
+# - #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.
+# - #quo: Returns the quotient from dividing +self+ by the given value.
+# - #round: Returns +self+ rounded to the nearest value, to a given precision.
+# - #to_i (aliased as #to_int): Returns +self+ truncated to an Integer.
+# - #to_s (aliased as #inspect): Returns a string containing the place-value
+# representation of +self+ in the given radix.
+# - #truncate: Returns +self+ truncated to a given precision.
+#
+
+ class Float; end
diff --git a/doc/format_specifications.rdoc b/doc/format_specifications.rdoc
deleted file mode 100644
index bdfdc24953..0000000000
--- a/doc/format_specifications.rdoc
+++ /dev/null
@@ -1,350 +0,0 @@
-= Format Specifications
-
-Several Ruby core classes have instance method +printf+ or +sprintf+:
-
-- ARGF#printf
-- IO#printf
-- Kernel#printf
-- Kernel#sprintf
-
-Each of these methods takes:
-
-- Argument +format_string+, which has zero or more
- embedded _format_ _specifications_ (see below).
-- Arguments <tt>*arguments</tt>, which are zero or more objects to be formatted.
-
-Each of these methods prints or returns the string
-resulting from replacing each
-format specification embedded in +format_string+ with a string form
-of the corresponding argument among +arguments+.
-
-A simple example:
-
- sprintf('Name: %s; value: %d', 'Foo', 0) # => "Name: Foo; value: 0"
-
-A format specification has the form:
-
- %[flags][width][.precision]type
-
-It consists of:
-
-- A leading percent character.
-- Zero or more _flags_ (each is a character).
-- An optional _width_ _specifier_ (an integer).
-- An optional _precision_ _specifier_ (a period followed by a non-negative integer).
-- A _type_ _specifier_ (a character).
-
-Except for the leading percent character,
-the only required part is the type specifier, so we begin with that.
-
-== Type Specifiers
-
-This section provides a brief explanation of each type specifier.
-The links lead to the details and examples.
-
-=== \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].
-- +d+, +i+, or +u+ (all are identical):
- Format +argument+ as a decimal integer.
- See {Specifier d}[rdoc-ref:format_specifications.rdoc@Specifier+d].
-- +o+: Format +argument+ as an octal integer.
- See {Specifier o}[rdoc-ref:format_specifications.rdoc@Specifier+o].
-- +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
-
-- +a+ or +A+: Format +argument+ as hexadecimal floating-point number.
- See {Specifiers a and A}[rdoc-ref:format_specifications.rdoc@Specifiers+a+and+A].
-- +e+ or +E+: Format +argument+ in scientific notation.
- See {Specifiers e and E}[rdoc-ref:format_specifications.rdoc@Specifiers+e+and+E].
-- +f+: Format +argument+ as a decimal floating-point number.
- See {Specifier f}[rdoc-ref:format_specifications.rdoc@Specifier+f].
-- +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
-
-- +c+: Format +argument+ as a character.
- See {Specifier c}[rdoc-ref:format_specifications.rdoc@Specifier+c].
-- +p+: Format +argument+ as a string via <tt>argument.inspect</tt>.
- See {Specifier p}[rdoc-ref:format_specifications.rdoc@Specifier+p].
-- +s+: Format +argument+ as a string via <tt>argument.to_s</tt>.
- See {Specifier s}[rdoc-ref:format_specifications.rdoc@Specifier+s].
-- <tt>%</tt>: Format +argument+ (<tt>'%'</tt>) as a single percent character.
- See {Specifier %}[rdoc-ref:format_specifications.rdoc@Specifier+-25].
-
-== Flags
-
-The effect of a flag may vary greatly among type specifiers.
-These remarks are general in nature.
-See {type-specific details}[rdoc-ref:format_specifications.rdoc@Type+Specifier+Details+and+Examples].
-
-Multiple flags may be given with single type specifier;
-order does not matter.
-
-=== <tt>' '</tt> Flag
-
-Insert a space before a non-negative number:
-
- sprintf('%d', 10) # => "10"
- sprintf('% d', 10) # => " 10"
-
-Insert a minus sign for negative value:
-
- sprintf('%d', -10) # => "-10"
- sprintf('% d', -10) # => "-10"
-
-=== <tt>'#'</tt> Flag
-
-Use an alternate format; varies among types:
-
- sprintf('%x', 100) # => "64"
- sprintf('%#x', 100) # => "0x64"
-
-=== <tt>'+'</tt> Flag
-
-Add a leading plus sign for a non-negative number:
-
- sprintf('%x', 100) # => "64"
- sprintf('%+x', 100) # => "+64"
-
-=== <tt>'-'</tt> Flag
-
-Left justify the value in its field:
-
- sprintf('%6d', 100) # => " 100"
- sprintf('%-6d', 100) # => "100 "
-
-=== <tt>'0'</tt> Flag
-
-Left-pad with zeros instead of spaces:
-
- sprintf('%6d', 100) # => " 100"
- sprintf('%06d', 100) # => "000100"
-
-=== <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
-
-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
-
-In general, a width specifier determines the minimum width (in characters)
-of the formatted field:
-
- sprintf('%10d', 100) # => " 100"
-
- # Left-justify if negative.
- sprintf('%-10d', 100) # => "100 "
-
- # Ignore if too small.
- sprintf('%1d', 100) # => "100"
-
-== Precision Specifier
-
-A precision specifier is a decimal point followed by zero or more
-decimal digits.
-
-For integer type specifiers, the precision specifies the minimum number of
-digits to be written. If the precision is shorter than the integer, the result is
-padded with leading zeros. There is no modification or truncation of the result
-if the integer is longer than the precision:
-
- sprintf('%.3d', 1) # => "001"
- sprintf('%.3d', 1000) # => "1000"
-
- # If the precision is 0 and the value is 0, nothing is written
- sprintf('%.d', 0) # => ""
- sprintf('%.0d', 0) # => ""
-
-For the +a+/+A+, +e+/+E+, +f+/+F+ specifiers, the precision specifies
-the number of digits after the decimal point to be written:
-
- sprintf('%.2f', 3.14159) # => "3.14"
- sprintf('%.10f', 3.14159) # => "3.1415900000"
-
- # With no precision specifier, defaults to 6-digit precision.
- sprintf('%f', 3.14159) # => "3.141590"
-
-For the +g+/+G+ specifiers, the precision specifies
-the number of significant digits to be written:
-
- sprintf('%.2g', 123.45) # => "1.2e+02"
- sprintf('%.3g', 123.45) # => "123"
- sprintf('%.10g', 123.45) # => "123.45"
-
- # With no precision specifier, defaults to 6 significant digits.
- sprintf('%g', 123.456789) # => "123.457"
-
-For the +s+, +p+ specifiers, the precision specifies
-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
-
-=== Specifiers +a+ and +A+
-
-Format +argument+ as hexadecimal floating-point number:
-
- sprintf('%a', 3.14159) # => "0x1.921f9f01b866ep+1"
- sprintf('%a', -3.14159) # => "-0x1.921f9f01b866ep+1"
- sprintf('%a', 4096) # => "0x1p+12"
- sprintf('%a', -4096) # => "-0x1p+12"
-
- # Capital 'A' means that alphabetical characters are printed in upper case.
- sprintf('%A', 4096) # => "0X1P+12"
- sprintf('%A', -4096) # => "-0X1P+12"
-
-=== Specifiers +b+ and +B+
-
-The two specifiers +b+ and +B+ behave identically
-except when flag <tt>'#'</tt>+ is used.
-
-Format +argument+ as a binary integer:
-
- sprintf('%b', 1) # => "1"
- sprintf('%b', 4) # => "100"
-
- # Prefix '..' for negative value.
- sprintf('%b', -4) # => "..100"
-
- # Alternate format.
- sprintf('%#b', 4) # => "0b100"
- sprintf('%#B', 4) # => "0B100"
-
-=== 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+
-
-Format +argument+ as a decimal integer:
-
- sprintf('%d', 100) # => "100"
- sprintf('%d', -100) # => "-100"
-
-Flag <tt>'#'</tt> does not apply.
-
-=== Specifiers +e+ and +E+
-
-Format +argument+ in
-{scientific notation}[https://en.wikipedia.org/wiki/Scientific_notation]:
-
- sprintf('%e', 3.14159) # => "3.141590e+00"
- sprintf('%E', -3.14159) # => "-3.141590E+00"
-
-=== Specifier +f+
-
-Format +argument+ as a floating-point number:
-
- sprintf('%f', 3.14159) # => "3.141590"
- sprintf('%f', -3.14159) # => "-3.141590"
-
-Flag <tt>'#'</tt> does not apply.
-
-=== 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.
-Otherwise format +argument+ using floating-point form (+f+ specifier):
-
- sprintf('%g', 100) # => "100"
- sprintf('%g', 100.0) # => "100"
- sprintf('%g', 3.14159) # => "3.14159"
- sprintf('%g', 100000000000) # => "1e+11"
- sprintf('%g', 0.000000000001) # => "1e-12"
-
- # Capital 'G' means use capital 'E'.
- sprintf('%G', 100000000000) # => "1E+11"
- sprintf('%G', 0.000000000001) # => "1E-12"
-
- # Alternate format.
- sprintf('%#g', 100000000000) # => "1.00000e+11"
- sprintf('%#g', 0.000000000001) # => "1.00000e-12"
- sprintf('%#G', 100000000000) # => "1.00000E+11"
- sprintf('%#G', 0.000000000001) # => "1.00000E-12"
-
-=== Specifier +o+
-
-Format +argument+ as an octal integer.
-If +argument+ is negative, it will be formatted as a two's complement
-prefixed with +..7+:
-
- sprintf('%o', 16) # => "20"
-
- # Prefix '..7' for negative value.
- sprintf('%o', -16) # => "..760"
-
- # Prefix zero for alternate format if positive.
- sprintf('%#o', 16) # => "020"
- sprintf('%#o', -16) # => "..760"
-
-=== 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+
-
-Format +argument+ as a string via <tt>argument.to_s</tt>:
-
- t = Time.now
- sprintf('%s', t) # => "2022-05-01 13:42:07 -0500"
-
-Flag <tt>'#'</tt> does not apply.
-
-=== Specifiers +x+ and +X+
-
-Format +argument+ as a hexadecimal integer.
-If +argument+ is negative, it will be formatted as a two's complement
-prefixed with +..f+:
-
- sprintf('%x', 100) # => "64"
-
- # Prefix '..f' for negative value.
- sprintf('%x', -100) # => "..f9c"
-
- # Use alternate format.
- sprintf('%#x', 100) # => "0x64"
-
- # Alternate format for negative value.
- sprintf('%#x', -100) # => "0x..f9c"
-
-=== Specifier <tt>%</tt>
-
-Format +argument+ (<tt>'%'</tt>) as a single percent character:
-
- sprintf('%d %%', 100) # => "100 %"
-
-Flags do not apply.
-
-== Reference by Name
-
-For more complex formatting, Ruby supports a reference by name.
-%<name>s style uses format style, but %{name} style doesn't.
-
-Examples:
-
- sprintf("%<foo>d : %<bar>f", { :foo => 1, :bar => 2 }) # => 1 : 2.000000
- sprintf("%{foo}f", { :foo => 1 }) # => "1f"
diff --git a/doc/forwardable.rd.ja b/doc/forwardable.rd.ja
deleted file mode 100644
index 53e8202513..0000000000
--- a/doc/forwardable.rd.ja
+++ /dev/null
@@ -1,80 +0,0 @@
- -- forwardable.rb
- $Release Version: 1.1 $
- $Revision$
-
-=begin
-= Forwardable
-
-クラスã«å¯¾ã—メソッドã®å§”譲機能を定義ã—ã¾ã™.
-
-== ä½¿ã„æ–¹
-
-クラスã«å¯¾ã—ã¦extendã—ã¦ä½¿ã„ã¾ã™.
-
- class Foo
- extend Forwardable
-
- def_delegators("@out", "printf", "print")
- def_delegators(:@in, :gets)
- def_delegator(:@contents, :[], "content_at")
- end
- f = Foo.new
- f.printf ...
- f.gets
- f.content_at(1)
-
-== メソッド
-
---- Forwardable#def_instance_delegators(accessor, *methods)
-
- ((|methods|))ã§æ¸¡ã•れãŸãƒ¡ã‚½ãƒƒãƒ‰ã®ãƒªã‚¹ãƒˆã‚’((|accessorã«|))委譲ã™ã‚‹
- よã†ã«ã—ã¾ã™.
-
---- Forwardable#def_instance_delegator(accessor, method, ali = method)
-
- ((||method|))ã§æ¸¡ã•れãŸãƒ¡ã‚½ãƒƒãƒ‰ã‚’((|accessor|))ã«å§”è­²ã™ã‚‹ã‚ˆã†ã«ã—
- ã¾ã™. ((|ali|))ãŒå¼•æ•°ã¨ã—ã¦æ¸¡ã•れãŸã¨ãã¯, メソッド((|ali|))ãŒå‘¼ã°
- れãŸã¨ãã«ã¯, ((|accessor|))ã«å¯¾ã—((|method|))を呼ã³å‡ºã—ã¾ã™.
-
---- Forwardable#def_delegators(accessor, *methods)
-
- ((|Forwardable#def_instance_delegators|))ã®åˆ¥åã§ã™.
-
---- Forwardable#def_delegator(accessor, method, ali = method)
-
- ((|Forwardable#def_instance_delegator|))ã®åˆ¥åã§ã™.
-
-= SingleForwardable
-
-オブジェクトã«å¯¾ã—, メソッドã®å§”譲機能を定義ã—ã¾ã™.
-
-== ä½¿ã„æ–¹
-
-オブジェクトã«å¯¾ã—ã¦((|extend|))ã—ã¦ä½¿ã„ã¾ã™.
-
- g = Goo.new
- g.extend SingleForwardable
- g.def_delegator("@out", :puts)
- g.puts ...
-
-== メソッド
-
---- SingleForwardable#def_singleton_delegators(accessor, *methods)
-
- ((|methods|))ã§æ¸¡ã•れãŸãƒ¡ã‚½ãƒƒãƒ‰ã®ãƒªã‚¹ãƒˆã‚’((|accessor|))ã«å§”è­²ã™ã‚‹
- よã†ã«ã—ã¾ã™.
-
---- SingleForwardable#def_singleton_delegator(accessor, method, ali = method)
-
- ((|method|))ã§æ¸¡ã•れãŸãƒ¡ã‚½ãƒƒãƒ‰ã‚’((|accessor|))ã«å§”è­²ã™ã‚‹ã‚ˆã†ã«ã—ã¾
- ã™. ((|ali|))ãŒå¼•æ•°ã¨ã—ã¦æ¸¡ã•れãŸã¨ãã¯, メソッド((|ali|))ãŒå‘¼ã°ã‚Œ
- ãŸã¨ãã«ã¯, ((|accessor|))ã«å¯¾ã—((|method|))を呼ã³å‡ºã—ã¾ã™.
-
---- SingleForwardable#def_delegators(accessor, *methods)
-
- ((|SingleForwardable#def_singleton_delegators|))ã®åˆ¥åã§ã™.
-
---- SingleForwardable#def_delegator(accessor, method, ali = method)
-
- ((|SingleForwardable#def_singleton_delegator|))ã®åˆ¥åã§ã™.
-=end
diff --git a/doc/globals.md b/doc/globals.md
deleted file mode 100644
index b9315f5ff9..0000000000
--- a/doc/globals.md
+++ /dev/null
@@ -1,572 +0,0 @@
-# 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:
-
-```ruby
-require 'English'
-```
-
-## Summary
-
-### Exceptions
-
-| Variable | English | Contains |
-|-------------|-------------------|----------------------------------------------------|
-| `$!` | `$ERROR_INFO` | Exception object; set by Kernel#raise. |
-| `$@` | `$ERROR_POSITION` | Array of backtrace positions; set by Kernel#raise. |
-
-### Pattern Matching
-
-| Variable | English | Contains |
-|---------------|---------------------|--------------------------------------------------|
-| `$~` | `$LAST_MATCH_INFO` | MatchData object; set by matcher method. |
-| `$&` | `$MATCH` | Matched substring; set by matcher method. |
-| `` $` `` | `$PRE_MATCH` | Substring left of match; set by matcher method. |
-| `$'` | `$POST_MATCH` | Substring right of match; set by matcher method. |
-| `$+` | `$LAST_PAREN_MATCH` | Last group matched; set by matcher method. |
-| `$1` | | First group matched; set by matcher method. |
-| `$2` | | Second group matched; set by matcher method. |
-| <tt>$_n_</tt> | | <i>n</i>th group matched; set by matcher method. |
-
-### Separators
-
-| Variable | English | Contains |
-|----------|----------------------------|--------------------------------------------|
-| `$/` | `$INPUT_RECORD_SEPARATOR` | Input record separator; initially newline. |
-| `$\` | `$OUTPUT_RECORD_SEPARATOR` | Output record separator; initially `nil`. |
-
-### Streams
-
-| Variable | English | Contains |
-|-----------|-----------------------------|-----------------------------------------------|
-| `$stdin` | | Standard input stream; initially `STDIN`. |
-| `$stdout` | | Standard input stream; initially `STDIOUT`. |
-| `$stderr` | | Standard input stream; initially `STDERR`. |
-| `$<` | `$DEFAULT_INPUT` | Default standard input; `ARGF` or `$stdin`. |
-| `$>` | `$DEFAULT_OUTPUT` | Default standard output; initially `$stdout`. |
-| `$.` | `$INPUT_LINE_NUMBER`, `$NR` | Input position of most recently read stream. |
-| `$_` | `$LAST_READ_LINE` | String from most recently read stream. |
-
-### Processes
-
-| Variable | English | Contains |
-|---------------------------|-----------------------|--------------------------------------------------------|
-| `$0` | | Initially, the name of the executing program. |
-| `$*` | `$ARGV` | Points to the `ARGV` array. |
-| `$$` | `$PROCESS_ID`, `$PID` | Process ID of the current process. |
-| `$?` | `$CHILD_STATUS` | Process::Status of most recently exited child process. |
-| `$LOAD_PATH`, `$:`, `$-I` | | Array of paths to be searched. |
-| `$LOADED_FEATURES`, `$"` | | Array of paths to loaded files. |
-
-### Debugging
-
-| Variable | English | Contains |
-|-------------|---------|--------------------------------------------------------|
-| `$FILENAME` | | The value returned by method ARGF.filename. |
-| `$DEBUG` | | Initially, whether option `-d` or `--debug` was given. |
-| `$VERBOSE` | | Initially, whether option `-V` or `-W` was given. |
-
-### Other Variables
-
-| Variable | English | Contains |
-|----------|---------|------------------------------------------------|
-| `$-a` | | Whether option `-a` was given. |
-| `$-i` | | Extension given with command-line option `-i`. |
-| `$-l` | | Whether option `-l` was given. |
-| `$-p` | | Whether option `-p` was given. |
-
-## Exceptions
-
-### `$!` (\Exception)
-
-Contains the Exception object set by Kernel#raise:
-
-```ruby
-begin
- raise RuntimeError.new('Boo!')
-rescue RuntimeError
- p $!
-end
-```
-
-Output:
-
-```
-#<RuntimeError: Boo!>
-```
-
-English - `$ERROR_INFO`
-
-### `$@` (Backtrace)
-
-Same as `$!.backtrace`;
-returns an array of backtrace positions:
-
-```ruby
-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 - `$ERROR_POSITION`.
-
-## 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].
-
-### `$~` (\MatchData)
-
-MatchData object created from the match;
-thread-local and frame-local.
-
-English - `$LAST_MATCH_INFO`.
-
-### `$&` (Matched Substring)
-
-The matched string.
-
-English - `$MATCH`.
-
-### `` $` `` (Pre-Match Substring)
-The string to the left of the match.
-
-English - `$PREMATCH`.
-
-### `$'` (Post-Match Substring)
-
-The string to the right of the match.
-
-English - `$POSTMATCH`.
-
-### `$+` (Last Matched Group)
-
-The last group matched.
-
-English - `$LAST_PAREN_MATCH`.
-
-### `$1`, `$2`, \Etc. (Matched Group)
-
-For <tt>$_n_</tt> the <i>n</i>th group of the match.
-
-No \English.
-
-## Separators
-
-### `$/` (Input Record Separator)
-
-An input record separator, initially newline.
-
-English - `$INPUT_RECORD_SEPARATOR`, `$RS`.
-
-Aliased as `$-0`.
-
-### `$\` (Output Record Separator)
-
-An output record separator, initially `nil`.
-
-English - `$OUTPUT_RECORD_SEPARATOR`, `$ORS`.
-
-## Streams
-
-### `$stdin` (Standard Input)
-
-The current standard input stream; initially:
-
-```ruby
-$stdin # => #<IO:<STDIN>>
-```
-
-### `$stdout` (Standard Output)
-
-The current standard output stream; initially:
-
-```ruby
-$stdout # => #<IO:<STDOUT>>
-```
-
-### `$stderr` (Standard Error)
-
-The current standard error stream; initially:
-
-```ruby
-$stderr # => #<IO:<STDERR>>
-```
-
-### `$<` (\ARGF or $stdin)
-
-Points to stream ARGF if not empty, else to stream $stdin; read-only.
-
-English - `$DEFAULT_INPUT`.
-
-### `$>` (Default Standard Output)
-
-An output stream, initially `$stdout`.
-
-English - `$DEFAULT_OUTPUT`
-
-### `$.` (Input Position)
-
-The input position (line number) in the most recently read stream.
-
-English - `$INPUT_LINE_NUMBER`, `$NR`
-
-### `$_` (Last Read Line)
-
-The line (string) from the most recently read stream.
-
-English - `$LAST_READ_LINE`.
-
-## Processes
-
-### `$0`
-
-Initially, contains the name of the script being executed;
-may be reassigned.
-
-### `$*` (\ARGV)
-
-Points to ARGV.
-
-English - `$ARGV`.
-
-### `$$` (Process ID)
-
-The process ID of the current process. Same as Process.pid.
-
-English - `$PROCESS_ID`, `$PID`.
-
-### `$?` (Child Status)
-
-Initially `nil`, otherwise the Process::Status object
-created for the most-recently exited child process;
-thread-local.
-
-English - `$CHILD_STATUS`.
-
-### `$LOAD_PATH` (Load Path)
-
-Contains the array of paths to be searched
-by Kernel#load and Kernel#require.
-
-Singleton method `$LOAD_PATH.resolve_feature_path(feature)`
-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:
-
-```ruby
-$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 `$:` and `$-I`.
-
-### `$LOADED_FEATURES`
-
-Contains an array of the paths to the loaded files:
-
-```ruby
-$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 `$"`.
-
-## Debugging
-
-### `$FILENAME`
-
-The value returned by method ARGF.filename.
-
-### `$DEBUG`
-
-Initially `true` if command-line option `-d` or `--debug` is given,
-otherwise initially `false`;
-may be set to either value in the running program.
-
-When `true`, prints each raised exception to `$stderr`.
-
-Aliased as `$-d`.
-
-### `$VERBOSE`
-
-Initially `true` if command-line option `-v` or `-w` 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 `$-v` and `$-w`.
-
-## Other Variables
-
-### `$-a`
-
-Whether command-line option `-a` was given; read-only.
-
-### `$-i`
-
-Contains the extension given with command-line option `-i`,
-or `nil` if none.
-
-An alias of ARGF.inplace_mode.
-
-### `$-l`
-
-Whether command-line option `-l` was set; read-only.
-
-### `$-p`
-
-Whether command-line option `-p` was given; read-only.
-
-## Deprecated
-
-### `$=`
-
-### `$,`
-
-### `$;`
-
-# Pre-Defined Global Constants
-
-## Summary
-
-### Streams
-
-| Constant | Contains |
-|----------|-------------------------|
-| `STDIN` | Standard input stream. |
-| `STDOUT` | Standard output stream. |
-| `STDERR` | Standard error stream. |
-
-### Environment
-
-| Constant | Contains |
-|-----------------------|-------------------------------------------------------------------------------|
-| `ENV` | Hash of current environment variable names and values. |
-| `ARGF` | String concatenation of files given on the command line, or `$stdin` if none. |
-| `ARGV` | Array of the given command-line arguments. |
-| `TOPLEVEL_BINDING` | Binding of the top level scope. |
-| `RUBY_VERSION` | String Ruby version. |
-| `RUBY_RELEASE_DATE` | String Ruby release date. |
-| `RUBY_PLATFORM` | String Ruby platform. |
-| `RUBY_PATCH_LEVEL` | String Ruby patch level. |
-| `RUBY_REVISION` | String Ruby revision. |
-| `RUBY_COPYRIGHT` | String Ruby copyright. |
-| `RUBY_ENGINE` | String Ruby engine. |
-| `RUBY_ENGINE_VERSION` | String Ruby engine version. |
-| `RUBY_DESCRIPTION` | String Ruby description. |
-
-### Embedded Data
-
-| Constant | Contains |
-|----------|--------------------------------------------------------------------|
-| `DATA` | File containing embedded data (lines following `__END__`, if any). |
-
-## Streams
-
-### `STDIN`
-
-The standard input stream (the default value for `$stdin`):
-
-```ruby
-STDIN # => #<IO:<STDIN>>
-```
-
-### `STDOUT`
-
-The standard output stream (the default value for `$stdout`):
-
-```ruby
-STDOUT # => #<IO:<STDOUT>>
-```
-
-### `STDERR`
-
-The standard error stream (the default value for `$stderr`):
-
-```ruby
-STDERR # => #<IO:<STDERR>>
-```
-
-## Environment
-
-### `ENV`
-
-A hash of the contains current environment variables names and values:
-
-```ruby
-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
-`$stdin` if no files were given, `"-"` is given, or after
-all files have been read.
-
-### `ARGV`
-
-An array of the given command-line arguments.
-
-### `TOPLEVEL_BINDING`
-
-The Binding of the top level scope:
-
-```ruby
-TOPLEVEL_BINDING # => #<Binding:0x00007f58da0da7c0>
-```
-
-### `RUBY_VERSION`
-
-The Ruby version:
-
-```ruby
-RUBY_VERSION # => "3.2.2"
-```
-
-### `RUBY_RELEASE_DATE`
-
-The release date string:
-
-```ruby
-RUBY_RELEASE_DATE # => "2023-03-30"
-```
-
-### `RUBY_PLATFORM`
-
-The platform identifier:
-
-```ruby
-RUBY_PLATFORM # => "x86_64-linux"
-```
-
-### `RUBY_PATCHLEVEL`
-
-The integer patch level for this Ruby:
-
-```ruby
-RUBY_PATCHLEVEL # => 53
-```
-
-For a development build the patch level will be -1.
-
-### `RUBY_REVISION`
-
-The git commit hash for this Ruby:
-
-```ruby
-RUBY_REVISION # => "e51014f9c05aa65cbf203442d37fef7c12390015"
-```
-
-### `RUBY_COPYRIGHT`
-
-The copyright string:
-
-```ruby
-RUBY_COPYRIGHT
-# => "ruby - Copyright (C) 1993-2023 Yukihiro Matsumoto"
-```
-
-### `RUBY_ENGINE`
-
-The name of the Ruby implementation:
-
-```ruby
-RUBY_ENGINE # => "ruby"
-```
-
-### `RUBY_ENGINE_VERSION`
-
-The version of the Ruby implementation:
-
-```ruby
-RUBY_ENGINE_VERSION # => "3.2.2"
-```
-
-### `RUBY_DESCRIPTION`
-
-The description of the Ruby implementation:
-
-```ruby
-RUBY_DESCRIPTION
-# => "ruby 3.2.2 (2023-03-30 revision e51014f9c0) [x86_64-linux]"
-```
-
-## Embedded \Data
-
-### `DATA`
-
-Defined if and only if the program has this line:
-
-```ruby
-__END__
-```
-
-When defined, `DATA` is a File object
-containing the lines following the `__END__`,
-positioned at the first of those lines:
-
-```ruby
-p DATA
-DATA.each_line { |line| p line }
-__END__
-Foo
-Bar
-Baz
-```
-
-Output:
-
-```
-#<File:t.rb>
-"Foo\n"
-"Bar\n"
-"Baz\n"
-```
diff --git a/doc/jit/yjit.md b/doc/jit/yjit.md
new file mode 100644
index 0000000000..d91877c30e
--- /dev/null
+++ b/doc/jit/yjit.md
@@ -0,0 +1,547 @@
+<p align="center">
+ <a href="https://yjit.org/" target="_blank" rel="noopener noreferrer">
+ <img src="https://user-images.githubusercontent.com/224488/131155756-aa8fb528-a813-4dfd-99ac-8785c3d5eed7.png" width="400">
+ </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.
+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:ruby@shopify.com">share your success stories with us!</a>
+</b></p>
+
+If you wish to learn more about the approach taken, here are some conference talks and publications:
+
+- MPLR 2023 talk: [Evaluating YJIT’s Performance in a Production Context: A Pragmatic Approach](https://www.youtube.com/watch?v=pVRmPZcNUhc)
+- 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)
+- ECOOP 2016 paper: [Interprocedural Type Specialization of JavaScript Programs Without Type Analysis](https://drops.dagstuhl.de/opus/volltexte/2016/6101/pdf/LIPIcs-ECOOP-2016-7.pdf)
+- 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:
+
+```BibTeX
+@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},
+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}
+}
+```
+
+## 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).
+
+## Installation
+
+### Requirements
+
+You will need to install:
+
+ - All the usual build tools for Ruby. See [Building Ruby](../contributing/building_ruby.md)
+ - The Rust compiler `rustc`
+ - The Rust version must be [>= 1.58.0](../../yjit/Cargo.toml).
+ - Optionally, only if you wish to build in dev/debug mode, Rust's `cargo`
+
+If you don't intend on making code changes to YJIT itself, we recommend
+obtaining `rustc` through your OS's package manager since that
+likely reuses the same vendor which provides the C toolchain.
+
+If you will be changing YJIT's Rust code, we suggest using the
+[first-party installation method][rust-install] for Rust. Rust also provides
+first class [support][editor-tools] for many source code editors.
+
+[rust-install]: https://www.rust-lang.org/tools/install
+[editor-tools]: https://www.rust-lang.org/tools
+
+### Building YJIT
+
+Start by cloning the `ruby/ruby` repository:
+
+```sh
+git clone https://github.com/ruby/ruby yjit
+cd yjit
+```
+
+The YJIT `ruby` binary can be built with either GCC or Clang.
+It can be built either in dev (debug) mode or in release mode.
+For maximum performance, compile YJIT in release mode with GCC.
+See [Building Ruby](rdoc-ref:contributing/building_ruby.md@building-ruby).
+
+```sh
+# Configure in release mode for maximum performance, build and install
+./autogen.sh
+./configure --enable-yjit --prefix=$HOME/.rubies/ruby-yjit --disable-install-doc
+make -j && make install
+```
+
+or
+
+```sh
+# Configure in lower-performance dev (debug) mode for development, build and install
+./autogen.sh
+./configure --enable-yjit=dev --prefix=$HOME/.rubies/ruby-yjit --disable-install-doc
+make -j && make install
+```
+
+Dev mode includes extended YJIT statistics, but can be slow. For only statistics you can configure in stats mode:
+
+```sh
+# Configure in extended-stats mode without slow runtime checks, build and install
+./autogen.sh
+./configure --enable-yjit=stats --prefix=$HOME/.rubies/ruby-yjit --disable-install-doc
+make -j && make install
+```
+
+On macOS, you may need to specify where to find some libraries:
+
+```sh
+# Install dependencies
+brew install openssl libyaml
+
+# Configure in dev (debug) mode for development, build and install
+./autogen.sh
+./configure --enable-yjit=dev --prefix=$HOME/.rubies/ruby-yjit --disable-install-doc --with-opt-dir="$(brew --prefix openssl):$(brew --prefix readline):$(brew --prefix libyaml)"
+make -j && make install
+```
+
+Typically configure will choose the default C compiler. To specify the C compiler, use
+
+```sh
+# Choosing a specific c compiler
+export CC=/path/to/my/chosen/c/compiler
+```
+
+before running `./configure`.
+
+You can test that YJIT works correctly by running:
+
+```sh
+# Quick tests found in /bootstraptest
+make btest
+
+# Complete set of tests
+make -j test-all
+```
+
+## Usage
+
+### Examples
+
+Once YJIT is built, you can either use `./miniruby` from within your build directory, or switch to the YJIT version of `ruby`
+by using the `chruby` tool:
+
+```sh
+chruby ruby-yjit
+ruby myscript.rb
+```
+
+You can dump statistics about compilation and execution by running YJIT with the `--yjit-stats` command-line option:
+
+```sh
+./miniruby --yjit-stats myscript.rb
+```
+
+You can see what YJIT has compiled by running YJIT with the `--yjit-log` command-line option:
+
+```sh
+./miniruby --yjit-log myscript.rb
+```
+
+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>
+
+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-mem-size=N`: soft limit on YJIT memory usage in MiB (default: 128). Tries to limit `code_region_size + yjit_alloc_size`
+- `--yjit-exec-mem-size=N`: hard limit on executable memory block in MiB. Limits `code_region_size`
+- `--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-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-log[=file|dir]`: log all compilation events to the specified file or directory. If no name is supplied, the last 1024 log entries will be printed to stderr when the application exits.
+- `--yjit-log=quiet`: gather a circular buffer of recent YJIT compilations. The compilation log entries are accessible through `RubyVM::YJIT.log` and old entries will be discarded if the buffer is not drained quickly. (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`
+
+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.
+
+## 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-mem-size
+
+The `--yjit-mem-size` value can be used to set the maximum amount of memory that YJIT
+is allowed to use. This corresponds to the total of `RubyVM::YJIT.runtime_stats[:code_region_size]`
+and `RubyVM::YJIT.runtime_stats[:yjit_alloc_size]`
+Increasing the `--yjit-mem-size` value 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 percentage of total YARV instructions
+executed by YJIT as opposed to the CRuby interpreter.
+Ideally, `ratio_in_yjit` should be as large as 99%, and increasing `--yjit-mem-size` often
+helps improving `ratio_in_yjit`.
+
+### Running workers as long as possible
+
+It's helpful to call the same code as many times as possible before a process restarts.
+If a process is killed too frequently, the time taken for compiling methods may outweigh
+the speedup obtained by compiling them.
+
+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
+
+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.
+
+### Decreasing --yjit-mem-size
+
+YJIT uses memory for compiled code and metadata. You can change the maximum amount of memory
+that YJIT can use by specifying a different `--yjit-mem-size` command-line option. The default value
+is currently `128`.
+When changing this value, 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.
+
+## Code Optimization Tips
+
+This section contains tips on writing Ruby code that will run as fast as possible on YJIT. Some of this advice is based on current limitations of YJIT, while other advice is broadly applicable. It probably won't be practical to apply these tips everywhere in your codebase. You should ideally start by profiling your application using a tool such as [stackprof](https://github.com/tmm1/stackprof) so that you can determine which methods make up most of the execution time. You can then refactor the specific methods that make up the largest fractions of the execution time. We do not recommend modifying your entire codebase based on the current limitations of YJIT.
+
+- Avoid using `OpenStruct`
+- Avoid redefining basic integer operations (i.e. +, -, <, >, etc.)
+- 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
+
+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`.
+
+```rb
+$ RUBYOPT="--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,
+ :send_callsite_not_simple=>7267,
+ :send_kw_splat=>7,
+ :send_ivar_set_method=>72,
+...
+```
+
+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 main-line machine code
+* `:outlined_code_size` - size in bytes of relatively uncommonly executed machine 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.)
+
+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.
+
+The printed text after a `--yjit-stats` run includes other information that may be named differently than the information in `RubyVM::YJIT.runtime_stats`.
+
+## Contributing
+
+We welcome open source contributions. 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
+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.
+
+### 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
+- `yjit/src/asm/*`: in-memory assembler we use to generate machine code
+- `yjit/src/codegen.rs`: logic for translating Ruby bytecode to machine code
+- `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
+
+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
+
+### Generating C bindings with bindgen
+
+In order to expose C functions to the Rust codebase, you will need to generate C bindings:
+
+```sh
+CC=clang ./configure --enable-yjit=dev
+make -j yjit-bindgen
+```
+
+This uses the bindgen tools to generate/update `yjit/src/cruby_bindings.inc.rs` based on the
+bindings listed in `yjit/bindgen/src/main.rs`. Avoid manually editing this file
+as it could be automatically regenerated at a later time. If you need to manually add C bindings,
+add them to `yjit/cruby.rs` instead.
+
+### Coding & Debugging Protips
+
+There are multiple test suites:
+
+- `make btest` (see `/bootstraptest`)
+- `make test-all`
+- `make test-spec`
+- `make check` runs all of the above
+- `make yjit-check` runs quick checks to see that YJIT is working correctly
+
+The tests can be run in parallel like this:
+
+```sh
+make -j test-all RUN_OPTS="--yjit-call-threshold=1"
+```
+
+Or single-threaded like this, to more easily identify which specific test is failing:
+
+```sh
+make test-all TESTOPTS=--verbose RUN_OPTS="--yjit-call-threshold=1"
+```
+
+To run a single test file with `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
+make btest BTESTS=bootstraptest/test_ractor.rb RUN_OPTS="--yjit-call-threshold=1"
+```
+
+There are shortcuts to run/debug your own test/repro in `test.rb`:
+
+```sh
+make run # runs ./miniruby test.rb
+make lldb # launches ./miniruby test.rb in lldb
+```
+
+You can use the Intel syntax for disassembly in LLDB, keeping it consistent with YJIT's disassembly:
+
+```sh
+echo "settings set target.x86-disassembly-flavor intel" >> ~/.lldbinit
+```
+
+## Running x86 YJIT on Apple's Rosetta
+
+For development purposes, it is possible to run x86 YJIT on an Apple M1 via Rosetta. You can find basic
+instructions below, but there are a few caveats listed further down.
+
+First, install Rosetta:
+
+```console
+$ softwareupdate --install-rosetta
+```
+
+Now any command can be run with Rosetta via the `arch` command line tool.
+
+Then you can start your shell in an x86 environment:
+
+```console
+$ arch -x86_64 zsh
+```
+
+You can double check your current architecture via the `arch` command:
+
+```console
+$ arch -x86_64 zsh
+$ arch
+i386
+```
+
+You may need to set the default target for `rustc` to x86-64, e.g.
+
+```console
+$ rustup default stable-x86_64-apple-darwin
+```
+
+While in your i386 shell, install Cargo and Homebrew, then hack away!
+
+### Rosetta Caveats
+
+1. You must install a version of Homebrew for each architecture
+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/jit_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/jit_perf.py
+```
diff --git a/doc/jit/zjit.md b/doc/jit/zjit.md
new file mode 100644
index 0000000000..ebe5cc4f9b
--- /dev/null
+++ b/doc/jit/zjit.md
@@ -0,0 +1,461 @@
+<p align="center">
+ <img src="https://github.com/user-attachments/assets/27abfe03-3e96-4220-b6f1-278bb0c87684" width="400">
+</p>
+
+# ZJIT: ADVANCED RUBY JIT PROTOTYPE
+
+ZJIT is a method-based just-in-time (JIT) compiler for Ruby. It uses profile
+information from the interpreter to guide optimization in the compiler.
+
+ZJIT 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.
+
+## Current Limitations
+
+ZJIT may not be suitable for certain applications. It currently only supports macOS, Linux and BSD on x86-64 and arm64/aarch64 CPUs. ZJIT 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 [ZJIT's command-line options](rdoc-ref:@Command-Line+Options).
+
+## Contributing
+
+We welcome open source contributions. Feel free to open new issues to report
+bugs or just to ask questions. Suggestions on how to make this document more
+helpful for new contributors are most welcome.
+
+Bug fixes and bug reports are very valuable to us. If you find a bug in ZJIT,
+it's very possible that nobody has reported it before, or that we don't have
+a good reproduction for it, so please open a ticket on [the official Ruby bug
+tracker][rubybugs] (or, if you don't want to make an account, [on
+Shopify/ruby][shopifyruby]) 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 ZJIT 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.
+
+[rubybugs]: https://bugs.ruby-lang.org/projects/ruby-master
+[shopifyruby]: https://github.com/Shopify/ruby/issues
+
+If you would like to contribute a large patch to ZJIT, we suggest [chatting on
+Zulip][zulip] for a casual chat and then opening an issue on the [Shopify/ruby
+repository][shopifyruby] so that we can have a technical 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
+ZJIT.
+
+[zulip]: https://zjit.zulipchat.com/
+
+## Build Instructions
+
+Refer to [Building Ruby](rdoc-ref:contributing/building_ruby.md) for general build prerequisites.
+Additionally, ZJIT requires Rust 1.85.0 or later. Release builds need only `rustc`. Development
+builds require `cargo` and may download dependencies. GNU Make is required.
+
+### For normal use
+
+To build ZJIT on macOS:
+
+```bash
+./autogen.sh
+
+./configure \
+ --enable-zjit \
+ --prefix="$HOME"/.rubies/ruby-zjit \
+ --disable-install-doc \
+ --with-opt-dir="$(brew --prefix openssl):$(brew --prefix readline):$(brew --prefix libyaml)"
+
+make -j miniruby
+```
+
+To build ZJIT on Linux:
+
+```bash
+./autogen.sh
+
+./configure \
+ --enable-zjit \
+ --prefix="$HOME"/.rubies/ruby-zjit \
+ --disable-install-doc
+
+make -j miniruby
+```
+
+### For development
+
+To build ZJIT on macOS:
+
+```bash
+./autogen.sh
+
+./configure \
+ --enable-zjit=dev \
+ --prefix="$HOME"/.rubies/ruby-zjit \
+ --disable-install-doc \
+ --with-opt-dir="$(brew --prefix openssl):$(brew --prefix readline):$(brew --prefix libyaml)"
+
+make -j miniruby
+```
+
+To build ZJIT on Linux:
+
+```bash
+./autogen.sh
+
+./configure \
+ --enable-zjit=dev \
+ --prefix="$HOME"/.rubies/ruby-zjit \
+ --disable-install-doc
+
+make -j miniruby
+```
+
+Note that `--enable-zjit=dev` does a lot of IR validation, which will help to catch errors early but mean compilation and warmup are significantly slower.
+
+The valid values for `--enable-zjit` are, from fastest to slowest:
+* `--enable-zjit`: enable ZJIT in release mode for maximum performance
+* `--enable-zjit=stats`: enable ZJIT in extended-stats mode
+* `--enable-zjit=dev_nodebug`: enable ZJIT in development mode but without slow runtime checks
+* `--enable-zjit=dev`: enable ZJIT in debug mode for development, also enables `RUBY_DEBUG`
+
+### Regenerate bindings
+
+When modifying `zjit/bindgen/src/main.rs` you need to regenerate bindings in `zjit/src/cruby_bindings.inc.rs` with:
+
+```bash
+make zjit-bindgen
+```
+
+## Documentation
+
+### Command-Line Options
+
+See `ruby --help` for ZJIT-specific command-line options:
+
+```
+$ ruby --help
+...
+ZJIT options:
+ --zjit-mem-size=num
+ Max amount of memory that ZJIT can use in MiB (default: 128).
+ --zjit-call-threshold=num
+ Number of calls to trigger JIT (default: 30).
+ --zjit-num-profiles=num
+ Number of profiled calls before JIT (default: 5).
+ --zjit-stats[=quiet]
+ Enable collecting ZJIT statistics (=quiet to suppress output).
+ --zjit-disable Disable ZJIT for lazily enabling it with RubyVM::ZJIT.enable.
+ --zjit-perf Dump ISEQ symbols into /tmp/perf-{}.map for Linux perf.
+ --zjit-log-compiled-iseqs=path
+ Log compiled ISEQs to the file. The file will be truncated.
+ --zjit-trace-exits[=counter]
+ Record source on side-exit. `Counter` picks specific counter.
+ --zjit-trace-exits-sample-rate=num
+ Frequency at which to record side exits. Must be `usize`.
+$
+```
+
+### Source level documentation
+
+You can generate and open the source level documentation in your browser using:
+
+```bash
+cargo doc --document-private-items -p zjit --open
+```
+
+### Graph of the Type System
+
+You can generate a graph of the ZJIT type hierarchy using:
+
+```bash
+ruby zjit/src/hir_type/gen_hir_type.rb > zjit/src/hir_type/hir_type.inc.rs
+dot -O -Tpdf zjit_types.dot
+open zjit_types.dot.pdf
+```
+
+## Testing
+
+Note that tests link against CRuby, so directly calling `cargo test`, or `cargo nextest` should not build. All tests are instead accessed through `make`.
+
+### Setup
+
+First, ensure you have `cargo` installed. If you do not already have it, you can use [rustup.rs](https://rustup.rs/).
+
+Also install cargo-binstall with:
+
+```bash
+cargo install cargo-binstall
+```
+
+Make sure to add `--enable-zjit=dev` when you run `configure`, then install the following tools:
+
+```bash
+cargo binstall --secure cargo-nextest
+cargo binstall --secure cargo-insta
+```
+
+`cargo-insta` is used for updating snapshots. `cargo-nextest` runs each test in its own process, which is valuable since CRuby only supports booting once per process, and most APIs are not thread safe.
+
+### Running unit tests
+
+For testing functionality within ZJIT, use:
+
+```bash
+make zjit-test
+```
+
+You can also run a single test case by specifying the function name:
+
+```bash
+make zjit-test ZJIT_TESTS=test_putobject
+```
+
+#### Snapshot Testing
+
+ZJIT uses [insta](https://insta.rs/) for snapshot testing within unit tests. When tests fail due to snapshot mismatches, pending snapshots are created. The test command will notify you if there are pending snapshots:
+
+```
+Pending snapshots found. Accept with: make zjit-test-update
+```
+
+To update/accept all the snapshot changes:
+
+```bash
+make zjit-test-update
+```
+
+You can also review snapshot changes interactively one by one:
+
+```bash
+cd zjit && cargo insta review
+```
+
+Test changes will be reviewed alongside code changes.
+
+### Running integration tests
+
+This command runs Ruby execution tests.
+
+```bash
+make test-all TESTS="test/ruby/test_zjit.rb"
+```
+
+You can also run a single test case by matching the method name:
+
+```bash
+make test-all TESTS="test/ruby/test_zjit.rb -n TestZJIT#test_putobject"
+```
+
+### Running all tests
+
+Runs both `make zjit-test` and `test/ruby/test_zjit.rb`:
+
+```bash
+make zjit-check
+```
+
+## Statistics Collection
+
+ZJIT provides detailed statistics about JIT compilation and execution behavior.
+
+### Basic Stats
+
+Run with basic statistics printed on exit:
+
+```bash
+./miniruby --zjit-stats script.rb
+```
+
+Collect stats without printing (access via `RubyVM::ZJIT.stats` in Ruby):
+
+```bash
+./miniruby --zjit-stats=quiet script.rb
+```
+
+### Accessing Stats in Ruby
+
+```ruby
+# Check if stats are enabled
+if RubyVM::ZJIT.stats_enabled?
+ stats = RubyVM::ZJIT.stats
+ puts "Compiled ISEQs: #{stats[:compiled_iseq_count]}"
+ puts "Failed ISEQs: #{stats[:failed_iseq_count]}"
+
+ # You can also reset stats during execution
+ RubyVM::ZJIT.reset_stats!
+end
+```
+
+### Performance Ratio
+
+The `ratio_in_zjit` stat shows the percentage of Ruby instructions executed in JIT code vs interpreter.
+This metric only appears when ZJIT is built with `--enable-zjit=stats` [or more](#build-instructions) (which enables `rb_vm_insn_count` tracking) and represents a key performance indicator for ZJIT effectiveness.
+
+### Tracing side exits
+
+`--zjit-trace-exits` records a backtrace every time compiled code takes a
+side exit. The output is a [Fuchsia Trace Format](https://fuchsia.dev/fuchsia-src/reference/tracing/trace-format)
+(`.fxt`) file written to `/tmp/perfetto-{pid}.fxt`, which can be opened
+directly in [Perfetto UI](https://ui.perfetto.dev/) or queried with the
+[Perfetto trace processor](https://perfetto.dev/docs/quickstart/trace-analysis).
+
+```bash
+$ ./miniruby --zjit-trace-exits -e '
+def poly(x)
+ x.to_s
+end
+
+30.times { poly(1) }
+30.times { poly("hello") }
+30.times { poly(:sym) }
+'
+ZJIT: writing trace exits to /tmp/perfetto-123456.fxt
+```
+
+To find the hottest side-exit locations, open the `.fxt` file in
+[Perfetto UI](https://ui.perfetto.dev/) and run an SQL query via the
+"Query (SQL)" tab in the bottom panel. Alternatively, download
+`trace_processor_shell` to query from the command line:
+
+```bash
+curl -Lo /tmp/trace_processor_shell https://get.perfetto.dev/trace_processor
+chmod +x /tmp/trace_processor_shell
+
+/tmp/trace_processor_shell /tmp/perfetto-123456.fxt -Q "
+SELECT reason, backtrace, count(*) AS exits FROM (
+ SELECT
+ s.id,
+ s.name AS reason,
+ group_concat(a.display_value, ' <- ') AS backtrace
+ FROM slice s
+ JOIN args a USING(arg_set_id)
+ WHERE s.category = 'side_exit'
+ GROUP BY s.id
+)
+GROUP BY reason, backtrace
+ORDER BY exits DESC
+LIMIT 30
+"
+```
+
+Example output:
+
+```
+"reason","backtrace","exits"
+"GuardType(Fixnum)","Object#poly (-e) <- block in <main> (-e) <- Integer#times (<internal:numeric>) <- <main> (-e)",60
+```
+
+You can also trace a specific counter with `--zjit-trace-exits=<counter_name>`
+(e.g. `--zjit-trace-exits=exit_compile_error`), or downsample with
+`--zjit-trace-exits-sample-rate=N` to record every N-th exit.
+Enabling `--zjit-trace-exits-sample-rate=N` will automatically enable
+`--zjit-trace-exits`.
+
+### Viewing HIR as text
+
+The compiled ZJIT HIR can be viewed as text using the `--zjit-dump-hir` option. However, HIR will only be generated if the call threshold is reached (default 30). By setting the threshold to 1 you can easily view the HIR for code snippets such as `1 + 1`:
+
+```bash
+./miniruby --zjit --zjit-dump-hir --zjit-call-threshold=1 -e "1 + 1"
+```
+
+Note that this disables profiling. To inject interpreter profiles into ZJIT, consider running your sample code 30 times:
+
+```bash
+./miniruby --zjit --zjit-dump-hir -e "30.times { 1 + 1 }"
+```
+
+### Viewing HIR in Iongraph
+
+Using `--zjit-dump-hir-iongraph` will dump all compiled functions into a directory named `/tmp/zjit-iongraph-{PROCESS_PID}`. Each file will be named `func_{ZJIT_FUNC_NAME}.json`. In order to use them in the Iongraph viewer, you'll need to use `jq` to collate them to a single file. An example invocation of `jq` is shown below for reference.
+
+`jq --slurp --null-input '.functions=inputs | .version=1' /tmp/zjit-iongraph-{PROCESS_PID}/func*.json > ~/Downloads/ion.json`
+
+From there, you can use https://mozilla-spidermonkey.github.io/iongraph/ to view your trace.
+
+### Printing ZJIT Errors
+
+`--zjit-debug` prints ZJIT compilation errors and other diagnostics:
+
+```bash
+./miniruby --zjit-debug script.rb
+```
+
+As you might guess from the name, this option is intended mostly for ZJIT developers.
+
+## Useful dev commands
+
+To view YARV output for code snippets:
+
+```bash
+./miniruby --dump=insns -e0
+```
+
+To run code snippets with ZJIT:
+
+```bash
+./miniruby --zjit -e0
+```
+
+You can also try https://www.rubyexplorer.xyz/ to view Ruby YARV disasm output with syntax highlighting
+in a way that can be easily shared with other team members.
+
+## Understanding Ruby Stacks
+
+Ruby execution involves three distinct stacks and understanding them will help you understand ZJIT's implementation:
+
+### 1. Native Stack
+
+- **Purpose**: Return addresses and saved registers. ZJIT also uses it for some C functions' argument arrays
+- **Management**: OS-managed, one per native thread
+- **Growth**: Downward from high addresses
+- **Constants**: `NATIVE_STACK_PTR`, `NATIVE_BASE_PTR`
+
+### 2. Ruby VM Stack
+
+The Ruby VM uses a single contiguous memory region (`ec->vm_stack`) containing two sub-stacks that grow toward each other. When they meet, stack overflow occurs.
+
+See [doc/contributing/vm_stack_and_frames.md](rdoc-ref:contributing/vm_stack_and_frames.md) for detailed architecture and frame layout.
+
+**Control Frame Stack:**
+
+- **Stores**: Frame metadata (`rb_control_frame_t` structures)
+- **Growth**: Downward from `vm_stack + size` (high addresses)
+- **Constants**: `CFP`
+
+**Value Stack:**
+
+- **Stores**: YARV bytecode operands (self, arguments, locals, temporaries)
+- **Growth**: Upward from `vm_stack` (low addresses)
+- **Constants**: `SP`
+
+## ZJIT Glossary
+
+This glossary contains terms that are helpful for understanding ZJIT.
+
+Please note that some terms may appear in CRuby internals too but with different meanings.
+
+| Term | Definition |
+| ----------------- | ------------------------------------------------------------------------------------------------------------------------------- |
+| HIR | High-level Intermediate Representation. High-level (Ruby semantics) graph representation in static single-assignment (SSA) form |
+| LIR | Low-level Intermediate Representation. Low-level IR used in the backend for assembly generation |
+| SSA | Static Single Assignment. A form where each variable is assigned exactly once |
+| `opnd` | Operand. An operand to an IR instruction (can be register, memory, immediate, etc.) |
+| `dst` | Destination. The output operand of an instruction where the result is stored |
+| VReg | Virtual Register. A virtual register that gets lowered to physical register or memory |
+| `insn_id` | Instruction ID. An index of an instruction in a function |
+| `block_id` | The index of a basic block, which effectively acts like a pointer |
+| `branch` | Control flow edge between basic blocks in the compiled code |
+| `cb` | Code Block. Memory region for generated machine code |
+| `entry` | The starting address of compiled code for an ISEQ |
+| Patch Point | Location in generated code that can be modified later in case assumptions get invalidated |
+| Frame State | Captured state of the Ruby stack frame at a specific point for deoptimization |
+| Guard | A run-time check that ensures assumptions are still valid |
+| `invariant` | An assumption that JIT code relies on, requiring invalidation if broken |
+| Deopt | Deoptimization. Process of falling back from JIT code to interpreter |
+| Side Exit | Exit from JIT code back to interpreter |
+| Type Lattice | Hierarchy of types used for type inference and optimization |
+| Constant Folding | Optimization that evaluates constant expressions at compile time |
+| RSP | x86-64 stack pointer register used for native stack operations |
+| Register Spilling | Process of moving register values to memory when running out of physical registers |
diff --git a/doc/language/box.md b/doc/language/box.md
new file mode 100644
index 0000000000..92514b3ec9
--- /dev/null
+++ b/doc/language/box.md
@@ -0,0 +1,357 @@
+# Ruby Box - Ruby's in-process separation of Classes and Modules
+
+Ruby Box is designed to provide separated spaces in a Ruby process, to isolate application code, libraries and monkey patches.
+
+## Known issues
+
+* Experimental warning is shown when ruby starts with `RUBY_BOX=1` (specify `-W:no-experimental` option to hide it)
+* Installing native extensions may fail under `RUBY_BOX=1` because of stack level too deep in extconf.rb
+* `require 'active_support/core_ext'` may fail under `RUBY_BOX=1`
+* Defined methods in a box may not be referred by built-in methods written in Ruby
+
+## TODOs
+
+* Add the loaded box on iseq to check if another box tries running the iseq (add a field only when VM_CHECK_MODE?)
+* Assign its own TOPLEVEL_BINDING in boxes
+* Fix calling `warn` in boxes to refer `$VERBOSE` and `Warning.warn` in the box
+* Make an internal data container class `Ruby::Box::Entry` invisible
+* More test cases about `$LOAD_PATH` and `$LOADED_FEATURES`
+
+## How to use
+
+### Enabling Ruby Box
+
+First, an environment variable should be set at the ruby process bootup: `RUBY_BOX=1`.
+The only valid value is `1` to enable Ruby Box. Other values (or unset `RUBY_BOX`) means disabling Ruby Box. And setting the value after Ruby program starts doesn't work.
+
+### Using Ruby Box
+
+`Ruby::Box` class is the entrypoint of Ruby Box.
+
+```ruby
+box = Ruby::Box.new
+box.require('something') # or require_relative, load
+```
+
+The required file (either .rb or .so/.dll/.bundle) is loaded in the box (`box` here). The required/loaded files from `something` will be loaded in the box recursively.
+
+```ruby
+# something.rb
+
+X = 1
+
+class Something
+ def self.x = X
+ def x = ::X
+end
+```
+
+Classes/modules, those methods and constants defined in the box can be accessed via `box` object.
+
+```ruby
+X = 2
+p X # 2
+p ::X # 2
+p box::Something.x # 1
+p box::X # 1
+```
+
+Instance methods defined in the box also run with definitions in the box.
+
+```ruby
+s = box::Something.new
+
+p s.x # 1
+```
+
+## Specifications
+
+### Ruby Box types
+
+There are three box types:
+
+* Master box
+* Root box
+* User boxes
+
+Ruby bootstrap runs in the root box, and a
+
+There is the root box, just a single box in a Ruby process. All builtin classes/modules are defined and run in the root box. (See "Builtin classes and modules".)
+
+User boxes are to run user-written programs and libraries loaded from user programs. The user's main program (specified by the `ruby` command line argument) is executed in the "main" box, which is a user box automatically created at the end of Ruby's bootstrap. The files specified with `-r` command line option will be required in the main box.
+
+Calling `Ruby::Box.new` creates an "optional" box (a user, non-main box), technically equal to the main box.
+
+Ruby also has the master box. The master box is the "master copy" of all boxes. Boxes will be created as a copy of the master box. The master box is only for the source of box copies, and no code runs in the master box.
+
+
+```
+[master]
+ |
+ |----[root]
+ |
+ |----[main]
+ |
+ |----[user box 1]
+ |
+ |----[user box 2]
+ ...
+```
+
+### Ruby Box class and instances
+
+`Ruby::Box` is a class, as a subclass of `Module`. `Ruby::Box` instances are a kind of `Module`.
+
+### Classes and modules defined in boxes
+
+The classes and modules, newly defined in a box `box`, are accessible via `box`. For example, if a class `A` is defined in `box`, it is accessible as `box::A` from outside of the box.
+
+In the box `box`, `A` can be referred to as `A` (and `::A`).
+
+### Built-in classes and modules reopened in boxes
+
+In boxes, builtin classes/modules are visible and can be reopened. Those classes/modules can be reopened using `class` or `module` clauses, and class/module definitions can be changed.
+
+The changed definitions are visible only in the box. In other boxes, builtin classes/modules and those instances work without changed definitions.
+
+```ruby
+# in foo.rb
+class String
+ BLANK_PATTERN = /\A\s*\z/
+ def blank?
+ self.match?(BLANK_PATTERN)
+ end
+end
+
+module Foo
+ def self.foo = "foo"
+
+ def self.foo_is_blank?
+ foo.blank?
+ end
+end
+
+Foo.foo.blank? #=> false
+"foo".blank? #=> false
+
+# in main.rb
+box = Ruby::Box.new
+box.require_relative('foo')
+
+box::Foo.foo_is_blank? #=> false (#blank? called in box)
+
+"foo".blank? # NoMethodError
+String::BLANK_PATTERN # NameError
+```
+
+The main box and `box` above are different boxes, so monkey patches in main are also invisible in `box`.
+
+### Builtin classes and modules
+
+In the box context, "builtin" classes and modules are classes and modules:
+
+* Accessible without any `require` calls in user scripts
+* Defined before any user program start running
+
+Hereafter, "builtin classes and modules" will be referred to as just "builtin classes".
+
+Builtin classes and modules are loaded in all boxes, and run in the root box.
+
+### Exceptional non-built-in classes/modules
+
+There are some exceptional classes/modules that are enabled in default, but aren't built-in classes. Those classes/modules are:
+
+* `RubyGems`
+* `ErrorHighlight`
+* `DidYouMean`
+* `SyntaxSuggest`
+
+Those classes/modules (part of default gems) are loaded in each boxes independently. If a user box's code calls RubyGems, it calls the RubyGems inside the box itself, instead of the root box's one.
+
+### Builtin classes referred via box objects
+
+Builtin classes in a box `box` can be referred from other boxes. For example, `box::String` is a valid reference, and `String` and `box::String` are identical (`String == box::String`, `String.object_id == box::String.object_id`).
+
+`box::String`-like reference returns just a `String` in the current box, so its definition is `String` in the box, not in `box`.
+
+```ruby
+# foo.rb
+class String
+ def self.foo = "foo"
+end
+
+# main.rb
+box = Ruby::Box.new
+box.require_relative('foo')
+
+box::String.foo # NoMethodError
+```
+
+### Class instance variables, class variables, constants
+
+Builtin classes can have different sets of class instance variables, class variables and constants between boxes.
+
+```ruby
+# foo.rb
+class Array
+ @v = "foo"
+ @@v = "_foo_"
+ V = "FOO"
+end
+
+Array.instance_variable_get(:@v) #=> "foo"
+Array.class_variable_get(:@@v) #=> "_foo_"
+Array.const_get(:V) #=> "FOO"
+
+# main.rb
+box = Ruby::Box.new
+box.require_relative('foo')
+
+Array.instance_variable_get(:@v) #=> nil
+Array.class_variable_get(:@@v) # NameError
+Array.const_get(:V) # NameError
+```
+
+### Global variables
+
+In boxes, changes on global variables are also isolated in the boxes. Changes on global variables in a box are visible/applied only in the box.
+
+```ruby
+# foo.rb
+$foo = "foo"
+$VERBOSE = nil
+
+puts "This appears: '#{$foo}'"
+
+# main.rb
+p $foo #=> nil
+p $VERBOSE #=> false
+
+box = Ruby::Box.new
+box.require_relative('foo') # "This appears: 'foo'"
+
+p $foo #=> nil
+p $VERBOSE #=> false
+```
+
+### Top level constants
+
+Usually, top level constants are defined as constants of `Object`. In boxes, top level constants are constants of `Object` in the box. And the box object `box`'s constants are strictly equal to constants of `Object`.
+
+```ruby
+# foo.rb
+FOO = 100
+
+FOO #=> 100
+Object::FOO #=> 100
+
+# main.rb
+box = Ruby::Box.new
+box.require_relative('foo')
+
+box::FOO #=> 100
+
+FOO # NameError
+Object::FOO # NameError
+```
+
+### Top level methods
+
+Top level methods are private instance methods of `Object`, in each box.
+
+```ruby
+# foo.rb
+def yay = "foo"
+
+class Foo
+ def self.say = yay
+end
+
+Foo.say #=> "foo"
+yay #=> "foo"
+
+# main.rb
+box = Ruby::Box.new
+box.require_relative('foo')
+
+box::Foo.say #=> "foo"
+
+yay # NoMethodError
+```
+
+There is no way to expose top level methods in boxes to others.
+(See "Expose top level methods as a method of the box object" in "Discussions" section below)
+
+### Ruby Box scopes
+
+Ruby Box works in file scope. One `.rb` file runs in a single box.
+
+Once a file is loaded in a box `box`, all methods/procs defined/created in the file run in `box`.
+
+### Utility methods
+
+Several methods are available for trying/testing Ruby Box.
+
+* `Ruby::Box.current` returns the current box
+* `Ruby::Box.enabled?` returns true/false to represent `RUBY_BOX=1` is specified or not
+* `Ruby::Box.root` returns the root box
+* `Ruby::Box.main` returns the main box
+* `Ruby::Box#eval` evaluates a Ruby code (String) in the receiver box, just like calling `#load` with a file
+
+## Implementation details
+
+#### ISeq inline method/constant cache
+
+As described above in "Ruby Box scopes", an ".rb" file runs in a box. So method/constant resolution will be done in a box consistently.
+
+That means ISeq inline caches work well even with boxes. Otherwise, it's a bug.
+
+#### Method call global cache (gccct)
+
+`rb_funcall()` C function refers to the global cc cache table (gccct), and the cache key is calculated with the current box.
+
+So, `rb_funcall()` calls have a performance penalty when Ruby Box is enabled.
+
+#### Current box and loading box
+
+The current box is the box that the executing code is in. `Ruby::Box.current` returns the current box object.
+
+The loading box is an internally managed box to determine the box to load newly required/loaded files. For example, `box` is the loading box when `box.require("foo")` is called.
+
+## Discussions
+
+#### More builtin methods written in Ruby
+
+If Ruby Box is enabled by default, builtin methods can be written in Ruby because it can't be overridden by users' monkey patches. Builtin Ruby methods can be JIT-ed, and it could bring performance reward.
+
+#### Monkey patching methods called by builtin methods
+
+Builtin methods sometimes call other builtin methods. For example, `Hash#map` calls `Hash#each` to retrieve entries to be mapped. Without Ruby Box, Ruby users can overwrite `Hash#each` and expect the behavior change of `Hash#map` as a result.
+
+But with boxes, `Hash#map` runs in the root box. Ruby users can define `Hash#each` only in user boxes, so users cannot change `Hash#map`'s behavior in this case. To achieve it, users should override both`Hash#map` and `Hash#each` (or only `Hash#map`).
+
+It is a breaking change.
+
+Users can define methods using `Ruby::Box.root.eval(...)`, but it's clearly not ideal API.
+
+#### Assigning values to global variables used by builtin methods
+
+Similar to monkey patching methods, global variables assigned in a box is separated from the root box. Methods defined in the root box referring a global variable can't find the re-assigned one.
+
+#### Context of `$LOAD_PATH` and `$LOADED_FEATURES`
+
+Global variables `$LOAD_PATH` and `$LOADED_FEATURES` control `require` method behaviors. So those variables are determined by the loading box instead of the current box.
+
+This could potentially conflict with the user's expectations. We should find the solution.
+
+#### Expose top level methods as a method of the box object
+
+Currently, top level methods in boxes are not accessible from outside of the box. But there might be a use case to call other box's top level methods.
+
+#### Separate `cc_tbl` and `callable_m_tbl`, `cvc_tbl` for less classext CoW
+
+The fields of `rb_classext_t` contains several cache(-like) data, `cc_tbl`(callcache table), `callable_m_tbl`(table of resolved complemented methods) and `cvc_tbl`(class variable cache table).
+
+The classext CoW is triggered when the contents of `rb_classext_t` are changed, including `cc_tbl`, `callable_m_tbl`, and `cvc_tbl`. But those three tables are changed by just calling methods or referring class variables. So, currently, classext CoW is triggered much more times than the original expectation.
+
+If we can move those three tables outside of `rb_classext_t`, the number of copied `rb_classext_t` will be much less than the current implementation.
diff --git a/doc/bsearch.rdoc b/doc/language/bsearch.rdoc
index 90705853d7..90705853d7 100644
--- a/doc/bsearch.rdoc
+++ b/doc/language/bsearch.rdoc
diff --git a/doc/language/calendars.rdoc b/doc/language/calendars.rdoc
new file mode 100644
index 0000000000..a2540f1c43
--- /dev/null
+++ b/doc/language/calendars.rdoc
@@ -0,0 +1,62 @@
+== Julian and Gregorian Calendars
+
+The difference between the
+{Julian calendar}[https://en.wikipedia.org/wiki/Julian_calendar]
+and the
+{Gregorian calendar}[https://en.wikipedia.org/wiki/Gregorian_calendar]
+may matter to your program if it uses dates before the switchovers.
+
+- October 15, 1582.
+- September 14, 1752.
+
+A date will be different in the two calendars, in general.
+
+=== Different switchover dates
+
+The reasons for the difference are religious/political histories.
+
+- On October 15, 1582, several countries changed
+ from the Julian calendar to the Gregorian calendar;
+ these included Italy, Poland, Portugal, and Spain.
+ Other countries in the Western world retained the Julian calendar.
+- On September 14, 1752, most of the British empire
+ changed from the Julian calendar to the Gregorian calendar.
+
+When your code uses a date before these switchover dates,
+it will matter whether it considers the switchover date
+to be the earlier date or the later date (or neither).
+
+See also {a concrete example here}[rdoc-ref:DateTime@When+should+you+use+DateTime+and+when+should+you+use+Time-3F].
+
+=== Argument +start+
+
+Certain methods in class \Date handle differences in the
+{Julian and Gregorian calendars}[rdoc-ref:@Julian+and+Gregorian+Calendars]
+by accepting an optional argument +start+, whose value may be:
+
+- Date::ITALY (the default): the created date is Julian
+ if before October 15, 1582, Gregorian otherwise:
+
+ d = Date.new(1582, 10, 15)
+ d.prev_day.julian? # => true
+ d.julian? # => false
+ d.gregorian? # => true
+
+- Date::ENGLAND: the created date is Julian if before September 14, 1752,
+ Gregorian otherwise:
+
+ d = Date.new(1752, 9, 14, Date::ENGLAND)
+ d.prev_day.julian? # => true
+ d.julian? # => false
+ d.gregorian? # => true
+
+- Date::JULIAN: the created date is Julian regardless of its value:
+
+ d = Date.new(1582, 10, 15, Date::JULIAN)
+ d.julian? # => true
+
+- Date::GREGORIAN: the created date is Gregorian regardless of its value:
+
+ d = Date.new(1752, 9, 14, Date::GREGORIAN)
+ d.prev_day.gregorian? # => true
+
diff --git a/doc/case_mapping.rdoc b/doc/language/case_mapping.rdoc
index d40155db03..d40155db03 100644
--- a/doc/case_mapping.rdoc
+++ b/doc/language/case_mapping.rdoc
diff --git a/doc/language/character_selectors.rdoc b/doc/language/character_selectors.rdoc
new file mode 100644
index 0000000000..8bfc9b719b
--- /dev/null
+++ b/doc/language/character_selectors.rdoc
@@ -0,0 +1,100 @@
+= Character Selectors
+
+== 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:
+
+- String#tr(selector, replacements): returns a new string.
+- String#tr!(selector, replacements): returns +self+ or +nil+.
+- String#tr_s(selector, replacements): returns a new string.
+- String#tr_s!(selector, replacements): returns +self+ or +nil+.
+- String#count(*selectors): returns the count of the specified characters.
+- String#delete(*selectors): returns a new string.
+- String#delete!(*selectors): returns +self+ or +nil+.
+- String#squeeze(*selectors): returns a new string.
+- String#squeeze!(*selectors): returns +self+ or +nil+.
+- String#strip(*selectors): returns a new string.
+- String#strip!(*selectors): returns +self+ or +nil+.
+
+A character selector identifies zero or more characters in +self+
+that are to be operands for the method.
+
+In this section, we illustrate using method String#delete(selector),
+which deletes the selected characters.
+
+In the simplest case, the characters selected are exactly those
+contained in the selector itself:
+
+ 'abracadabra'.delete('a') # => "brcdbr"
+ 'abracadabra'.delete('ab') # => "rcdr"
+ 'abracadabra'.delete('abc') # => "rdr"
+ '0123456789'.delete('258') # => "0134679"
+ '!@#$%&*()_+'.delete('+&#') # => "!@$%*()_"
+ 'ã“ã‚“ã«ã¡ã¯'.delete('ã«') # => "ã“ã‚“ã¡ã¯"
+
+Note that order and repetitions do not matter:
+
+ 'abracadabra'.delete('dcab') # => "rr"
+ 'abracadabra'.delete('aaaa') # => "brcdbr"
+
+In a character selector, these three characters get special treatment:
+
+- A leading caret (<tt>'^'</tt>) functions as a "not" operator
+ for the characters to its right:
+
+ 'abracadabra'.delete('^bc') # => "bcb"
+ '0123456789'.delete('^852') # => "258"
+
+- A hyphen (<tt>'-'</tt>) between two other characters
+ defines a range of characters instead of a plain string of characters:
+
+ 'abracadabra'.delete('a-d') # => "rr"
+ '0123456789'.delete('4-7') # => "012389"
+ '!@#$%&*()_+'.delete(' -/') # => "@^_"
+
+ # May contain more than one range.
+ 'abracadabra'.delete('a-cq-t') # => "d"
+
+ # Ranges may be mixed with plain characters.
+ '0123456789'.delete('67-950-23') # => "4"
+
+ # Ranges may be mixed with negations.
+ 'abracadabra'.delete('^a-c') # => "abacaaba"
+
+- A backslash (<tt>'\'</tt>) acts as an escape for a caret, a hyphen,
+ or another backslash:
+
+ 'abracadabra^'.delete('\^bc') # => "araadara"
+ 'abracadabra-'.delete('a\-d') # => "brcbr"
+ "hello\r\nworld".delete("\r") # => "hello\nworld"
+ "hello\r\nworld".delete("\\r") # => "hello\r\nwold"
+ "hello\r\nworld".delete("\\\r") # => "hello\nworld"
+
+== Multiple Character Selectors
+
+These instance methods accept multiple character selectors:
+
+- String#count(*selectors): returns the count of the specified characters.
+- String#delete(*selectors): returns a new string.
+- String#delete!(*selectors): returns +self+ or +nil+.
+- String#squeeze(*selectors): returns a new string.
+- String#squeeze!(*selectors): returns +self+ or +nil+.
+- String#strip(*selectors): returns a new string.
+- String#strip!(*selectors): returns +self+ or +nil+.
+
+In effect, the given selectors are formed into a single selector
+consisting of only those characters common to _all_ of the given selectors.
+
+All forms of selectors may be used, including negations, ranges, and escapes.
+
+Each of these pairs of method calls is equivalent:
+
+ s.delete('abcde', 'dcbfg')
+ s.delete('bcd')
+
+ s.delete('^abc', '^def')
+ s.delete('^abcdef')
+
+ s.delete('a-e', 'c-g')
+ s.delete('cde')
diff --git a/doc/dig_methods.rdoc b/doc/language/dig_methods.rdoc
index 366275d451..366275d451 100644
--- a/doc/dig_methods.rdoc
+++ b/doc/language/dig_methods.rdoc
diff --git a/doc/language/encodings.rdoc b/doc/language/encodings.rdoc
new file mode 100644
index 0000000000..683842d3fb
--- /dev/null
+++ b/doc/language/encodings.rdoc
@@ -0,0 +1,482 @@
+= Encodings
+
+== The Basics
+
+A {character encoding}[https://en.wikipedia.org/wiki/Character_encoding],
+often shortened to _encoding_, is a mapping between:
+
+- A sequence of 8-bit bytes (each byte in the range <tt>0..255</tt>).
+- Characters in a specific character set.
+
+Some character sets contain only 1-byte characters;
+{US-ASCII}[https://en.wikipedia.org/wiki/ASCII], for example, has 256 1-byte characters.
+This string, encoded in US-ASCII, has six characters that are stored as six bytes:
+
+ s = 'Hello!'.encode(Encoding::US_ASCII) # => "Hello!"
+ s.encoding # => #<Encoding:US-ASCII>
+ s.bytes # => [72, 101, 108, 108, 111, 33]
+
+Other encodings may involve multi-byte characters.
+{UTF-8}[https://en.wikipedia.org/wiki/UTF-8], for example,
+encodes more than one million characters, encoding each in one to four bytes.
+The lowest-valued of these characters correspond to ASCII characters,
+and so are 1-byte characters:
+
+ s = 'Hello!' # => "Hello!"
+ s.bytes # => [72, 101, 108, 108, 111, 33]
+
+Other characters, such as the Euro symbol, are multi-byte:
+
+ s = "\u20ac" # => "€"
+ s.bytes # => [226, 130, 172]
+
+== The \Encoding Class
+
+=== \Encoding Objects
+
+Ruby encodings are defined by constants in class \Encoding.
+There can be only one instance of \Encoding for each of these constants.
+Method Encoding.list returns an array of \Encoding objects (one for each constant):
+
+ Encoding.list.size # => 103
+ Encoding.list.first.class # => Encoding
+ Encoding.list.take(3)
+ # => [#<Encoding:ASCII-8BIT>, #<Encoding:UTF-8>, #<Encoding:US-ASCII>]
+
+=== Names and Aliases
+
+Method Encoding#name returns the name of an \Encoding:
+
+ Encoding::ASCII_8BIT.name # => "ASCII-8BIT"
+ Encoding::WINDOWS_31J.name # => "Windows-31J"
+
+An \Encoding object has zero or more aliases;
+method Encoding#names returns an array containing the name and all aliases:
+
+ Encoding::ASCII_8BIT.names
+ # => ["ASCII-8BIT", "BINARY"]
+ Encoding::WINDOWS_31J.names
+ #=> ["Windows-31J", "CP932", "csWindows31J", "SJIS", "PCK"]
+
+Method Encoding.aliases returns a hash of all alias/name pairs:
+
+ Encoding.aliases.size # => 71
+ Encoding.aliases.take(3)
+ # => [["BINARY", "ASCII-8BIT"], ["CP437", "IBM437"], ["CP720", "IBM720"]]
+
+Method Encoding.name_list returns an array of all the encoding names and aliases:
+
+ Encoding.name_list.size # => 175
+ Encoding.name_list.take(3)
+ # => ["ASCII-8BIT", "UTF-8", "US-ASCII"]
+
+Method +name_list+ returns more entries than method +list+
+because it includes both the names and their aliases.
+
+Method Encoding.find returns the \Encoding for a given name or alias, if it exists:
+
+ Encoding.find("US-ASCII") # => #<Encoding:US-ASCII>
+ Encoding.find("US-ASCII").class # => Encoding
+
+=== Default Encodings
+
+Method Encoding.find, above, also returns a default \Encoding
+for each of these special names:
+
+- +external+: the default external \Encoding:
+
+ Encoding.find("external") # => #<Encoding:UTF-8>
+
+- +internal+: the default internal \Encoding (may be +nil+):
+
+ Encoding.find("internal") # => nil
+
+- +locale+: the default \Encoding for a string from the environment:
+
+ Encoding.find("locale") # => #<Encoding:UTF-8> # Linux
+ Encoding.find("locale") # => #<Encoding:IBM437> # Windows
+
+- +filesystem+: the default \Encoding for a string from the filesystem:
+
+ Encoding.find("filesystem") # => #<Encoding:UTF-8>
+
+Method Encoding.default_external returns the default external \Encoding:
+
+ Encoding.default_external # => #<Encoding:UTF-8>
+
+Method Encoding.default_external= sets that value:
+
+ Encoding.default_external = Encoding::US_ASCII # => #<Encoding:US-ASCII>
+ Encoding.default_external # => #<Encoding:US-ASCII>
+
+Method Encoding.default_internal returns the default internal \Encoding:
+
+ Encoding.default_internal # => nil
+
+Method Encoding.default_internal= sets the default internal \Encoding:
+
+ Encoding.default_internal = Encoding::US_ASCII # => #<Encoding:US-ASCII>
+ Encoding.default_internal # => #<Encoding:US-ASCII>
+
+=== Compatible Encodings
+
+Method Encoding.compatible? returns whether two given objects are encoding-compatible
+(that is, whether they can be concatenated);
+returns the \Encoding of the concatenated string, or +nil+ if incompatible:
+
+ rus = "\u{442 435 441 442}"
+ eng = 'text'
+ Encoding.compatible?(rus, eng) # => #<Encoding:UTF-8>
+
+ s0 = "\xa1\xa1".force_encoding(Encoding::ISO_8859_1) # => "\xA1\xA1"
+ s1 = "\xa1\xa1".force_encoding(Encoding::EUCJP) # => "\x{A1A1}"
+ Encoding.compatible?(s0, s1) # => nil
+
+== \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:@Script+Encoding].
+
+ 's'.encoding # => #<Encoding:UTF-8>
+
+The default encoding for a string created with method String.new is:
+
+- For no argument, ASCII-8BIT.
+- For a \String object argument, the encoding of that string.
+- For a string literal, the script encoding;
+ see {Script Encoding}[rdoc-ref:@Script+Encoding].
+
+In either case, any encoding may be specified:
+
+ s = String.new(encoding: Encoding::UTF_8) # => ""
+ s.encoding # => #<Encoding:UTF-8>
+ s = String.new('foo', encoding: Encoding::BINARY) # => "foo"
+ s.encoding # => #<Encoding:BINARY (ASCII-8BIT)>
+
+The encoding for a string may be changed:
+
+ s = "R\xC3\xA9sum\xC3\xA9" # => "Résumé"
+ s.encoding # => #<Encoding:UTF-8>
+ s.force_encoding(Encoding::ISO_8859_1) # => "R\xC3\xA9sum\xC3\xA9"
+ s.encoding # => #<Encoding:ISO-8859-1>
+
+Changing the assigned encoding does not alter the content of the string;
+it changes only the way the content is to be interpreted:
+
+ s # => "R\xC3\xA9sum\xC3\xA9"
+ s.force_encoding(Encoding::UTF_8) # => "Résumé"
+
+The actual content of a string may also be altered;
+see {Transcoding a String}[#label-Transcoding+a+String].
+
+Here are a couple of useful query methods:
+
+ s = "abc".force_encoding(Encoding::UTF_8) # => "abc"
+ s.ascii_only? # => true
+ s = "abc\u{6666}".force_encoding(Encoding::UTF_8) # => "abc晦"
+ s.ascii_only? # => false
+
+ s = "\xc2\xa1".force_encoding(Encoding::UTF_8) # => "¡"
+ s.valid_encoding? # => true
+ s = "\xc2".force_encoding(Encoding::UTF_8) # => "\xC2"
+ s.valid_encoding? # => false
+
+== \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.
+
+The default encoding for these, however, is:
+
+- US-ASCII, if all characters are US-ASCII.
+- The script encoding, otherwise;
+ see (Script Encoding)[rdoc-ref:@Script+Encoding].
+
+== Filesystem \Encoding
+
+The filesystem encoding is the default \Encoding for a string from the filesystem:
+
+ Encoding.find("filesystem") # => #<Encoding:UTF-8>
+
+== 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
+
+Certain stream objects can have two encodings; these objects include instances of:
+
+- IO.
+- File.
+- ARGF.
+- StringIO.
+
+The two encodings are:
+
+- An _external_ _encoding_, which identifies the encoding of the stream.
+- An _internal_ _encoding_, which (if not +nil+) specifies the encoding
+ to be used for the string constructed from the stream.
+
+=== External \Encoding
+
+The external encoding, which is an \Encoding object, specifies how bytes read
+from the stream are to be interpreted as characters.
+
+The default external encoding is:
+
+- UTF-8 for a text stream.
+- ASCII-8BIT for a binary stream.
+
+The default external encoding is returned by method Encoding.default_external,
+and may be set by:
+
+- Ruby command-line options <tt>--external_encoding</tt> or <tt>-E</tt>.
+
+You can also set the default external encoding using method Encoding.default_external=,
+but doing so may cause problems; strings created before and after the change
+may have a different encodings.
+
+For an \IO or \File object, the external encoding may be set by:
+
+- Open options +external_encoding+ or +encoding+, when the object is created;
+ see {Open Options}[rdoc-ref:IO@Open+Options].
+
+For an \IO, \File, \ARGF, or \StringIO object, the external encoding may be set by:
+
+- Methods +set_encoding+ or (except for \ARGF) +set_encoding_by_bom+.
+
+=== Internal \Encoding
+
+The internal encoding, which is an \Encoding object or +nil+,
+specifies how characters read from the stream
+are to be converted to characters in the internal encoding;
+those characters become a string whose encoding is set to the internal encoding.
+
+The default internal encoding is +nil+ (no conversion).
+It is returned by method Encoding.default_internal,
+and may be set by:
+
+- Ruby command-line options <tt>--internal_encoding</tt> or <tt>-E</tt>.
+
+You can also set the default internal encoding using method Encoding.default_internal=,
+but doing so may cause problems; strings created before and after the change
+may have a different encodings.
+
+For an \IO or \File object, the internal encoding may be set by:
+
+- Open options +internal_encoding+ or +encoding+, when the object is created;
+ see {Open Options}[rdoc-ref:IO@Open+Options].
+
+For an \IO, \File, \ARGF, or \StringIO object, the internal encoding may be set by:
+
+- Method +set_encoding+.
+
+== Script \Encoding
+
+A Ruby script has a script encoding, which may be retrieved by:
+
+ __ENCODING__ # => #<Encoding:UTF-8>
+
+The default script encoding is UTF-8;
+a Ruby source file may set its script encoding with a magic comment
+on the first line of the file (or second line, if there is a shebang on the first).
+The comment must contain the word +coding+ or +encoding+,
+followed by a colon, space and the Encoding name or alias:
+
+ # encoding: ISO-8859-1
+ __ENCODING__ #=> #<Encoding:ISO-8859-1>
+
+== Transcoding
+
+_Transcoding_ is the process of changing a sequence of characters
+from one encoding to another.
+
+As far as possible, the characters remain the same,
+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
+
+Each of these methods transcodes a string:
+
+- String#encode: Transcodes +self+ into a new string
+ according to given encodings and options.
+- String#encode!: Like String#encode, but transcodes +self+ in place.
+- String#scrub: Transcodes +self+ into a new string
+ by replacing invalid byte sequences with a given or default replacement string.
+- String#scrub!: Like String#scrub, but transcodes +self+ in place.
+- String#unicode_normalize: Transcodes +self+ into a new string
+ according to Unicode normalization.
+- String#unicode_normalize!: Like String#unicode_normalize,
+ but transcodes +self+ in place.
+
+== Transcoding a Stream
+
+Each of these methods may transcode a stream;
+whether it does so depends on the external and internal encodings:
+
+- IO.foreach: Yields each line of given stream to the block.
+- IO.new: Creates and returns a new \IO object for the given integer file descriptor.
+- IO.open: Creates a new \IO object.
+- IO.pipe: Creates a connected pair of reader and writer \IO objects.
+- IO.popen: Creates an \IO object to interact with a subprocess.
+- IO.read: Returns a string with all or a subset of bytes from the given stream.
+- IO.readlines: Returns an array of strings, which are the lines from the given stream.
+- IO.write: Writes a given string to the given stream.
+
+This example writes a string to a file, encoding it as ISO-8859-1,
+then reads the file into a new string, encoding it as UTF-8:
+
+ s = "R\u00E9sum\u00E9"
+ path = 't.tmp'
+ ext_enc = Encoding::ISO_8859_1
+ int_enc = Encoding::UTF_8
+
+ File.write(path, s, external_encoding: ext_enc)
+ raw_text = File.binread(path)
+
+ transcoded_text = File.read(path, external_encoding: ext_enc, internal_encoding: int_enc)
+
+ p raw_text
+ p transcoded_text
+
+Output:
+
+ "R\xE9sum\xE9"
+ "Résumé"
+
+== \Encoding Options
+
+A number of methods in the Ruby core accept keyword arguments as encoding options.
+
+Some of the options specify or utilize a _replacement_ _string_, to be used
+in certain transcoding operations.
+A replacement string may be in any encoding that can be converted
+to the encoding of the destination string.
+
+These keyword-value pairs specify encoding options:
+
+- For an invalid byte sequence:
+
+ - <tt>:invalid: nil</tt> (default): Raise exception.
+ - <tt>:invalid: :replace</tt>: Replace each invalid byte sequence
+ with the replacement string.
+
+ Examples:
+
+ s = "\x80foo\x80"
+ s.encode(Encoding::ISO_8859_3) # Raises Encoding::InvalidByteSequenceError.
+ s.encode(Encoding::ISO_8859_3, invalid: :replace) # => "?foo?"
+
+- For an undefined character:
+
+ - <tt>:undef: nil</tt> (default): Raise exception.
+ - <tt>:undef: :replace</tt>: Replace each undefined character
+ with the replacement string.
+
+ Examples:
+
+ s = "\x80foo\x80"
+ "\x80".encode(Encoding::UTF_8, Encoding::BINARY) # Raises Encoding::UndefinedConversionError.
+ s.encode(Encoding::UTF_8, Encoding::BINARY, undef: :replace) # => "�foo�"
+
+
+- Replacement string:
+
+ - <tt>:replace: nil</tt> (default): Set replacement string to default value:
+ <tt>"\uFFFD"</tt> ("�") for a Unicode encoding, <tt>'?'</tt> otherwise.
+ - <tt>:replace: some_string</tt>: Set replacement string to the given +some_string+;
+ overrides +:fallback+.
+
+ Examples:
+
+ s = "\xA5foo\xA5"
+ options = {:undef => :replace, :replace => 'xyzzy'}
+ s.encode(Encoding::UTF_8, Encoding::ISO_8859_3, **options) # => "xyzzyfooxyzzy"
+
+- Replacement fallback:
+
+ One of these may be specified:
+
+ - <tt>:fallback: nil</tt> (default): No replacement fallback.
+ - <tt>:fallback: hash_like_object</tt>: Set replacement fallback to the given
+ +hash_like_object+; the replacement string is <tt>hash_like_object[X]</tt>.
+ - <tt>:fallback: method</tt>: Set replacement fallback to the given
+ +method+; the replacement string is <tt>method(X)</tt>.
+ - <tt>:fallback: proc</tt>: Set replacement fallback to the given
+ +proc+; the replacement string is <tt>proc[X]</tt>.
+
+ Examples:
+
+ s = "\u3042foo\u3043"
+
+ hash = {"\u3042" => 'xyzzy'}
+ hash.default = 'XYZZY'
+ s.encode(Encoding::US_ASCII, fallback: hash) # => "xyzzyfooXYZZY"
+
+ def (fallback = "U+%.4X").escape(x)
+ self % x.unpack("U")
+ end
+ "\u{3042}".encode(Encoding::US_ASCII, fallback: fallback.method(:escape)) # => "U+3042"
+
+ proc = Proc.new {|x| x == "\u3042" ? 'xyzzy' : 'XYZZY' }
+ s.encode('ASCII', fallback: proc) # => "XYZZYfooXYZZY"
+
+- XML entities:
+
+ One of these may be specified:
+
+ - <tt>:xml: nil</tt> (default): No handling for XML entities.
+ - <tt>:xml: :text</tt>: Treat source text as XML;
+ replace each undefined character
+ with its upper-case hexadecimal numeric character reference,
+ except that:
+
+ - <tt>&</tt> is replaced with <tt>&amp;</tt>.
+ - <tt><</tt> is replaced with <tt>&lt;</tt>.
+ - <tt>></tt> is replaced with <tt>&gt;</tt>.
+
+ - <tt>:xml: :attr</tt>: Treat source text as XML attribute value;
+ replace each undefined character
+ with its upper-case hexadecimal numeric character reference,
+ except that:
+
+ - The replacement string <tt>r</tt> is double-quoted (<tt>"r"</tt>).
+ - Each embedded double-quote is replaced with <tt>&quot;</tt>.
+ - <tt>&</tt> is replaced with <tt>&amp;</tt>.
+ - <tt><</tt> is replaced with <tt>&lt;</tt>.
+ - <tt>></tt> is replaced with <tt>&gt;</tt>.
+
+ Examples:
+
+ s = 'foo"<&>"bar' + "\u3042"
+ s.encode(Encoding::US_ASCII, xml: :text) # => "foo\"&lt;&amp;&gt;\"bar&#x3042;"
+ s.encode(Encoding::US_ASCII, xml: :attr) # => "\"foo&quot;&lt;&amp;&gt;&quot;bar&#x3042;\""
+
+
+- Newlines:
+
+ One of these may be specified:
+
+ - <tt>:cr_newline: true</tt>: Replace each line-feed character (<tt>"\n"</tt>)
+ with a carriage-return character (<tt>"\r"</tt>).
+ - <tt>:crlf_newline: true</tt>: Replace each line-feed character (<tt>"\n"</tt>)
+ with a carriage-return/line-feed string (<tt>"\r\n"</tt>).
+ - <tt>:universal_newline: true</tt>: Replace each carriage-return
+ character (<tt>"\r"</tt>) and each carriage-return/line-feed string
+ (<tt>"\r\n"</tt>) with a line-feed character (<tt>"\n"</tt>).
+
+ Examples:
+
+ s = "\n \r \r\n" # => "\n \r \r\n"
+ s.encode(Encoding::US_ASCII, cr_newline: true) # => "\r \r \r\r"
+ s.encode(Encoding::US_ASCII, crlf_newline: true) # => "\r\n \r \r\r\n"
+ s.encode(Encoding::US_ASCII, universal_newline: true) # => "\n \n \n"
diff --git a/doc/language/exceptions.md b/doc/language/exceptions.md
new file mode 100644
index 0000000000..5f8f0ece69
--- /dev/null
+++ b/doc/language/exceptions.md
@@ -0,0 +1,521 @@
+# 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:
+
+```rb
+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):
+
+```console
+$ 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:
+
+```rb
+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).
+
+```rb
+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:
+
+```rb
+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):
+
+```rb
+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:
+
+```rb
+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:
+
+```rb
+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;
+they're:
+
+- `$!`: contains the rescued exception.
+- `$@`: contains its backtrace.
+
+Example:
+
+```rb
+begin
+ 1 / 0
+rescue
+ p $!
+ p $@
+end
+```
+
+Output:
+
+```
+#<ZeroDivisionError: divided by 0>
+["t.rb:2:in 'Integer#/'", "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:
+
+```rb
+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.
+
+```rb
+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.
+
+```rb
+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:
+
+ ```rb
+ 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:
+
+ ```rb
+ 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:
+
+```rb
+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 'Integer#/': 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):
+
+```rb
+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).
+
+```rb
+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.
+
+By default, Ruby sets the backtrace of the exception to the location where it
+was raised.
+
+The developer might adjust this by either providing `backtrace` argument
+to Kernel#raise, or using Exception#set_backtrace.
+
+Note that:
+
+- by default, both `backtrace` and `backtrace_locations` represent the same backtrace;
+- if the developer sets the backtrace by one of the above methods to an array of
+ Thread::Backtrace::Location, they still represent the same backtrace;
+- if the developer sets the backtrace to a string or an array of strings:
+ - by Kernel#raise: `backtrace_locations` become `nil`;
+ - by Exception#set_backtrace: `backtrace_locations` preserve the original
+ value;
+- if the developer sets the backtrace to `nil` by Exception#set_backtrace,
+ `backtrace_locations` preserve the original value; but if the exception is then
+ reraised, both `backtrace` and `backtrace_locations` become the location of reraise.
diff --git a/doc/fiber.md b/doc/language/fiber.md
index d9011cce2f..d9011cce2f 100644
--- a/doc/fiber.md
+++ b/doc/language/fiber.md
diff --git a/doc/language/format_specifications.rdoc b/doc/language/format_specifications.rdoc
new file mode 100644
index 0000000000..763470aa02
--- /dev/null
+++ b/doc/language/format_specifications.rdoc
@@ -0,0 +1,354 @@
+= Format Specifications
+
+Several Ruby core classes have instance method +printf+ or +sprintf+:
+
+- ARGF#printf
+- IO#printf
+- Kernel#printf
+- Kernel#sprintf
+
+Each of these methods takes:
+
+- Argument +format_string+, which has zero or more
+ embedded _format_ _specifications_ (see below).
+- Arguments <tt>*arguments</tt>, which are zero or more objects to be formatted.
+
+Each of these methods prints or returns the string
+resulting from replacing each
+format specification embedded in +format_string+ with a string form
+of the corresponding argument among +arguments+.
+
+A simple example:
+
+ sprintf('Name: %s; value: %d', 'Foo', 0) # => "Name: Foo; value: 0"
+
+A format specification has the form:
+
+ %[flags][width][.precision]type
+
+It consists of:
+
+- A leading percent character.
+- Zero or more _flags_ (each is a character).
+- An optional _width_ _specifier_ (an integer, or <tt>*</tt>).
+- An optional _precision_ _specifier_ (a period followed by a non-negative
+ integer, or <tt>*</tt>).
+- A _type_ _specifier_ (a character).
+
+Except for the leading percent character,
+the only required part is the type specifier, so we begin with that.
+
+== Type Specifiers
+
+This section provides a brief explanation of each type specifier.
+The links lead to the details and examples.
+
+=== \Integer Type Specifiers
+
+- +b+ or +B+: Format +argument+ as a binary integer.
+ See {Specifiers b and B}[rdoc-ref:@Specifiers+b+and+B].
+- +d+, +i+, or +u+ (all are identical):
+ Format +argument+ as a decimal integer.
+ See {Specifier d}[rdoc-ref:@Specifier+d].
+- +o+: Format +argument+ as an octal integer.
+ See {Specifier o}[rdoc-ref:@Specifier+o].
+- +x+ or +X+: Format +argument+ as a hexadecimal integer.
+ See {Specifiers x and X}[rdoc-ref:@Specifiers+x+and+X].
+
+=== Floating-Point Type Specifiers
+
+- +a+ or +A+: Format +argument+ as hexadecimal floating-point number.
+ See {Specifiers a and A}[rdoc-ref:@Specifiers+a+and+A].
+- +e+ or +E+: Format +argument+ in scientific notation.
+ See {Specifiers e and E}[rdoc-ref:@Specifiers+e+and+E].
+- +f+: Format +argument+ as a decimal floating-point number.
+ See {Specifier f}[rdoc-ref:@Specifier+f].
+- +g+ or +G+: Format +argument+ in a "general" format.
+ See {Specifiers g and G}[rdoc-ref:@Specifiers+g+and+G].
+
+=== Other Type Specifiers
+
+- +c+: Format +argument+ as a character.
+ See {Specifier c}[rdoc-ref:@Specifier+c].
+- +p+: Format +argument+ as a string via <tt>argument.inspect</tt>.
+ See {Specifier p}[rdoc-ref:@Specifier+p].
+- +s+: Format +argument+ as a string via <tt>argument.to_s</tt>.
+ See {Specifier s}[rdoc-ref:@Specifier+s].
+- <tt>%</tt>: Format +argument+ (<tt>'%'</tt>) as a single percent character.
+ See {Specifier %}[rdoc-ref:@Specifier+-25].
+
+== Flags
+
+The effect of a flag may vary greatly among type specifiers.
+These remarks are general in nature.
+See {type-specific details}[rdoc-ref:@Type+Specifier+Details+and+Examples].
+
+Multiple flags may be given with single type specifier;
+order does not matter.
+
+=== <tt>' '</tt> Flag
+
+Insert a space before a non-negative number:
+
+ sprintf('%d', 10) # => "10"
+ sprintf('% d', 10) # => " 10"
+
+Insert a minus sign for negative value:
+
+ sprintf('%d', -10) # => "-10"
+ sprintf('% d', -10) # => "-10"
+
+=== <tt>'#'</tt> Flag
+
+Use an alternate format; varies among types:
+
+ sprintf('%x', 100) # => "64"
+ sprintf('%#x', 100) # => "0x64"
+
+=== <tt>'+'</tt> Flag
+
+Add a leading plus sign for a non-negative number:
+
+ sprintf('%x', 100) # => "64"
+ sprintf('%+x', 100) # => "+64"
+
+=== <tt>'-'</tt> Flag
+
+Left justify the value in its field:
+
+ sprintf('%6d', 100) # => " 100"
+ sprintf('%-6d', 100) # => "100 "
+
+=== <tt>'0'</tt> Flag
+
+Left-pad with zeros instead of spaces:
+
+ sprintf('%6d', 100) # => " 100"
+ sprintf('%06d', 100) # => "000100"
+
+=== <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
+
+In general, a width specifier determines the minimum width (in characters)
+of the formatted field:
+
+ sprintf('%10d', 100) # => " 100"
+
+ # Left-justify if negative.
+ sprintf('%-10d', 100) # => "100 "
+
+ # Ignore if too small.
+ sprintf('%1d', 100) # => "100"
+
+If the width specifier is <tt>'*'</tt> instead of an integer, the actual minimum
+width is taken from the argument list:
+
+ sprintf('%*d', 20, 14) # => " 14"
+
+== Precision Specifier
+
+A precision specifier is a decimal point followed by zero or more
+decimal digits.
+
+For integer type specifiers, the precision specifies the minimum number of
+digits to be written. If the precision is shorter than the integer, the result is
+padded with leading zeros. There is no modification or truncation of the result
+if the integer is longer than the precision:
+
+ sprintf('%.3d', 1) # => "001"
+ sprintf('%.3d', 1000) # => "1000"
+
+ # If the precision is 0 and the value is 0, nothing is written
+ sprintf('%.d', 0) # => ""
+ sprintf('%.0d', 0) # => ""
+
+For the +a+/+A+, +e+/+E+, +f+ specifiers, the precision specifies
+the number of digits after the decimal point to be written:
+
+ sprintf('%.2f', 3.14159) # => "3.14"
+ sprintf('%.10f', 3.14159) # => "3.1415900000"
+
+ # With no precision specifier, defaults to 6-digit precision.
+ sprintf('%f', 3.14159) # => "3.141590"
+
+For the +g+/+G+ specifiers, the precision specifies
+the number of significant digits to be written:
+
+ sprintf('%.2g', 123.45) # => "1.2e+02"
+ sprintf('%.3g', 123.45) # => "123"
+ sprintf('%.10g', 123.45) # => "123.45"
+
+ # With no precision specifier, defaults to 6 significant digits.
+ sprintf('%g', 123.456789) # => "123.457"
+
+For the +s+, +p+ specifiers, the precision specifies
+the number of characters to write:
+
+ sprintf('%s', Time.now) # => "2022-05-04 11:59:16 -0400"
+ sprintf('%.10s', Time.now) # => "2022-05-04"
+
+If the precision specifier is <tt>'*'</tt> instead of a non-negative integer,
+the actual precision is taken from the argument list:
+
+ sprintf('%.*d', 20, 1) # => "00000000000000000001"
+
+== Type Specifier Details and Examples
+
+=== Specifiers +a+ and +A+
+
+Format +argument+ as hexadecimal floating-point number:
+
+ sprintf('%a', 3.14159) # => "0x1.921f9f01b866ep+1"
+ sprintf('%a', -3.14159) # => "-0x1.921f9f01b866ep+1"
+ sprintf('%a', 4096) # => "0x1p+12"
+ sprintf('%a', -4096) # => "-0x1p+12"
+
+ # Capital 'A' means that alphabetical characters are printed in upper case.
+ sprintf('%A', 4096) # => "0X1P+12"
+ sprintf('%A', -4096) # => "-0X1P+12"
+
+=== Specifiers +b+ and +B+
+
+The two specifiers +b+ and +B+ behave identically
+except when flag <tt>'#'</tt>+ is used.
+
+Format +argument+ as a binary integer:
+
+ sprintf('%b', 1) # => "1"
+ sprintf('%b', 4) # => "100"
+
+ # Prefix '..' for negative value.
+ sprintf('%b', -4) # => "..100"
+
+ # Alternate format.
+ sprintf('%#b', 4) # => "0b100"
+ sprintf('%#B', 4) # => "0B100"
+
+=== 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+
+
+Format +argument+ as a decimal integer:
+
+ sprintf('%d', 100) # => "100"
+ sprintf('%d', -100) # => "-100"
+
+Flag <tt>'#'</tt> does not apply.
+
+=== Specifiers +e+ and +E+
+
+Format +argument+ in
+{scientific notation}[https://en.wikipedia.org/wiki/Scientific_notation]:
+
+ sprintf('%e', 3.14159) # => "3.141590e+00"
+ sprintf('%E', -3.14159) # => "-3.141590E+00"
+
+=== Specifier +f+
+
+Format +argument+ as a floating-point number:
+
+ sprintf('%f', 3.14159) # => "3.141590"
+ sprintf('%f', -3.14159) # => "-3.141590"
+
+Flag <tt>'#'</tt> does not apply.
+
+=== 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.
+Otherwise format +argument+ using floating-point form (+f+ specifier):
+
+ sprintf('%g', 100) # => "100"
+ sprintf('%g', 100.0) # => "100"
+ sprintf('%g', 3.14159) # => "3.14159"
+ sprintf('%g', 100000000000) # => "1e+11"
+ sprintf('%g', 0.000000000001) # => "1e-12"
+
+ # Capital 'G' means use capital 'E'.
+ sprintf('%G', 100000000000) # => "1E+11"
+ sprintf('%G', 0.000000000001) # => "1E-12"
+
+ # Alternate format.
+ sprintf('%#g', 100000000000) # => "1.00000e+11"
+ sprintf('%#g', 0.000000000001) # => "1.00000e-12"
+ sprintf('%#G', 100000000000) # => "1.00000E+11"
+ sprintf('%#G', 0.000000000001) # => "1.00000E-12"
+
+=== Specifier +o+
+
+Format +argument+ as an octal integer.
+If +argument+ is negative, it will be formatted as a two's complement
+prefixed with +..7+:
+
+ sprintf('%o', 16) # => "20"
+
+ # Prefix '..7' for negative value.
+ sprintf('%o', -16) # => "..760"
+
+ # Prefix zero for alternate format if positive.
+ sprintf('%#o', 16) # => "020"
+ sprintf('%#o', -16) # => "..760"
+
+=== 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+
+
+Format +argument+ as a string via <tt>argument.to_s</tt>:
+
+ t = Time.now
+ sprintf('%s', t) # => "2022-05-01 13:42:07 -0500"
+
+Flag <tt>'#'</tt> does not apply.
+
+=== Specifiers +x+ and +X+
+
+Format +argument+ as a hexadecimal integer.
+If +argument+ is negative, it will be formatted as a two's complement
+prefixed with +..f+:
+
+ sprintf('%x', 100) # => "64"
+
+ # Prefix '..f' for negative value.
+ sprintf('%x', -100) # => "..f9c"
+
+ # Use alternate format.
+ sprintf('%#x', 100) # => "0x64"
+
+ # Alternate format for negative value.
+ sprintf('%#x', -100) # => "0x..f9c"
+
+=== Specifier <tt>%</tt>
+
+Format +argument+ (<tt>'%'</tt>) as a single percent character:
+
+ sprintf('%d %%', 100) # => "100 %"
+
+Flags do not apply.
+
+== Reference by Name
+
+For more complex formatting, Ruby supports a reference by name.
+%<name>s style uses format style, but %{name} style doesn't.
+
+Examples:
+
+ sprintf("%<foo>d : %<bar>f", { :foo => 1, :bar => 2 }) # => 1 : 2.000000
+ sprintf("%{foo}f", { :foo => 1 }) # => "1f"
diff --git a/doc/language/globals.md b/doc/language/globals.md
new file mode 100644
index 0000000000..0f6b632a08
--- /dev/null
+++ b/doc/language/globals.md
@@ -0,0 +1,611 @@
+# 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:
+
+```ruby
+require 'English'
+```
+
+## In Brief
+
+### Exceptions
+
+| Variable | \English | Contains | Initially | Read-Only | Reset By |
+|:--------:|:-----------------:|----------------------------------------|:---------:|:---------:|--------------|
+| `$!` | `$ERROR_INFO` | \Exception object or `nil` | `nil` | Yes | Kernel#raise |
+| `$@` | `$ERROR_POSITION` | \Array of backtrace positions or `nil` | `nil` | Yes | Kernel#raise |
+
+### Matched \Data
+
+| Variable | \English | Contains | Initially | Read-Only | Reset By |
+|:---------:|:-------------------:|-----------------------------------|:---------:|:---------:|-----------------|
+| `$~` | `$LAST_MATCH_INFO` | \MatchData object or `nil` | `nil` | No | Matcher methods |
+| `$&` | `$MATCH` | Matched substring or `nil` | `nil` | No | Matcher methods |
+| `` $` `` | `$PRE_MATCH` | Substring left of match or `nil` | `nil` | No | Matcher methods |
+| `$'` | `$POST_MATCH` | Substring right of match or `nil` | `nil` | No | Matcher methods |
+| `$+` | `$LAST_PAREN_MATCH` | Last group matched or `nil` | `nil` | No | Matcher methods |
+| `$1` | | First group matched or `nil` | `nil` | Yes | Matcher methods |
+| `$2` | | Second group matched or `nil` | `nil` | Yes | Matcher methods |
+| `$n` | | <i>n</i>th group matched or `nil` | `nil` | Yes | Matcher methods |
+
+### Separators
+
+| Variable | \English | Contains | Initially | Read-Only | Reset By |
+|:-----------:|:---------------------------:|-------------------------|:---------:|:---------:|----------|
+| `$/`, `$-0` | `$INPUT_RECORD_SEPARATOR` | Input record separator | Newline | No | |
+| `$\` | `$OUTPUT_RECORD_SEPARATOR` | Output record separator | `nil` | No | |
+
+### Streams
+
+| Variable | \English | Contains | Initially | Read-Only | Reset By |
+|:---------:|:----------------------------:|---------------------------------------------|:---------:|:---------:|----------------------|
+| `$stdin` | | Standard input stream | `STDIN` | No | |
+| `$stdout` | | Standard output stream | `STDOUT` | No | |
+| `$stderr` | | Standard error stream | `STDERR` | No | |
+| `$<` | `$DEFAULT_INPUT` | Default standard input | `ARGF` | Yes | |
+| `$>` | `$DEFAULT_OUTPUT` | Default standard output | `STDOUT` | No | |
+| `$.` | `$INPUT_LINE_NUMBER`, `$NR` | Input position of most recently read stream | 0 | No | Certain read methods |
+| `$_` | `$LAST_READ_LINE` | String from most recently read stream | `nil` | No | Certain read methods |
+
+### Processes
+
+| Variable | \English | Contains | Initially | Read-Only | Reset By |
+|:-------------------------:|:----------------------:|---------------------------------|:-------------:|:---------:|----------|
+| `$0`, `$PROGRAM_NAME` | | Program name | Program name | No | |
+| `$*` | `$ARGV` | \ARGV array | `ARGV` | Yes | |
+| `$$` | `$PROCESS_ID`, `$PID` | Process id | Process PID | Yes | |
+| `$?` | `$CHILD_STATUS` | Status of recently exited child | `nil` | Yes | |
+| `$LOAD_PATH`, `$:`, `$-I` | | \Array of search paths | Ruby defaults | Yes | |
+| `$LOADED_FEATURES`, `$"` | | \Array of load paths | Ruby defaults | Yes | |
+
+### Debugging
+
+| Variable | \English | Contains | Initially | Read-Only | Reset By |
+|:-----------:|:--------:|--------------------------------------------|:----------------------------:|:---------:|----------|
+| `$FILENAME` | | Value returned by method `ARGF.filename` | Command-line argument or '-' | Yes | |
+| `$DEBUG` | | Whether option `-d` or `--debug` was given | Command-line option | No | |
+| `$VERBOSE` | | Whether option `-V` or `-W` was given | Command-line option | No | |
+
+### Other Variables
+
+| Variable | \English | Contains | Initially | Read-Only | Reset By |
+|:-----------:|:--------:|-----------------------------------------------|:---------:|:---------:|----------|
+| `$-F`, `$;` | | Separator given with command-line option `-F` | | | |
+| `$-a` | | Whether option `-a` was given | | Yes | |
+| `$-i` | | Extension given with command-line option `-i` | | No | |
+| `$-l` | | Whether option `-l` was given | | Yes | |
+| `$-p` | | Whether option `-p` was given | | Yes | |
+| `$F` | | \Array of `$_` split by `$-F` | | | |
+
+## Exceptions
+
+### `$!` (\Exception)
+
+Contains the Exception object set by Kernel#raise:
+
+```ruby
+begin
+ raise RuntimeError.new('Boo!')
+rescue RuntimeError
+ p $!
+end
+```
+
+Output:
+
+```
+#<RuntimeError: Boo!>
+```
+
+English - `$ERROR_INFO`
+
+### `$@` (Backtrace)
+
+Same as `$!.backtrace`;
+returns an array of backtrace positions:
+
+```ruby
+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 - `$ERROR_POSITION`.
+
+## Matched \Data
+
+These global variables store information about the most recent
+successful match in the current scope.
+
+For details and examples,
+see [Regexp Global Variables].
+
+### `$~` (\MatchData)
+
+MatchData object created from the match;
+thread-local and frame-local.
+
+English - `$LAST_MATCH_INFO`.
+
+### `$&` (Matched Substring)
+
+The matched string.
+
+English - `$MATCH`.
+
+### `` $` `` (Pre-Match Substring)
+The string to the left of the match.
+
+English - `$PREMATCH`.
+
+### `$'` (Post-Match Substring)
+
+The string to the right of the match.
+
+English - `$POSTMATCH`.
+
+### `$+` (Last Matched Group)
+
+The last group matched.
+
+English - `$LAST_PAREN_MATCH`.
+
+### `$1`, `$2`, \Etc. (Matched Group)
+
+For <tt>$n</tt> the <i>n</i>th group of the match.
+
+No \English.
+
+## Separators
+
+### `$/` (Input Record Separator)
+
+An input record separator, initially newline.
+Set by the [command-line option `-0`].
+
+Setting to non-nil value by other than the command-line option is
+deprecated.
+
+English - `$INPUT_RECORD_SEPARATOR`, `$RS`.
+
+Aliased as `$-0`.
+
+### `$\` (Output Record Separator)
+
+An output record separator, initially `nil`.
+
+Copied from `$/` when the [command-line option `-l`] is
+given.
+
+Setting to non-nil value by other than the command-line option is
+deprecated.
+
+English - `$OUTPUT_RECORD_SEPARATOR`, `$ORS`.
+
+## Streams
+
+### `$stdin` (Standard Input)
+
+The current standard input stream; initially:
+
+```ruby
+$stdin # => #<IO:<STDIN>>
+```
+
+### `$stdout` (Standard Output)
+
+The current standard output stream; initially:
+
+```ruby
+$stdout # => #<IO:<STDOUT>>
+```
+
+### `$stderr` (Standard Error)
+
+The current standard error stream; initially:
+
+```ruby
+$stderr # => #<IO:<STDERR>>
+```
+
+### `$<` (\ARGF or $stdin)
+
+Points to stream ARGF if not empty, else to stream $stdin; read-only.
+
+English - `$DEFAULT_INPUT`.
+
+### `$>` (Default Standard Output)
+
+An output stream, initially `$stdout`.
+
+English - `$DEFAULT_OUTPUT`
+
+### `$.` (Input Position)
+
+The input position (line number) in the most recently read stream.
+
+English - `$INPUT_LINE_NUMBER`, `$NR`
+
+### `$_` (Last Read Line)
+
+The line (string) from the most recently read stream.
+
+English - `$LAST_READ_LINE`.
+
+## Processes
+
+### `$0`
+
+Initially, contains the name of the script being executed;
+may be reassigned.
+
+### `$*` (\ARGV)
+
+Points to ARGV.
+
+English - `$ARGV`.
+
+### `$$` (Process ID)
+
+The process ID of the current process. Same as Process.pid.
+
+English - `$PROCESS_ID`, `$PID`.
+
+### `$?` (Child Status)
+
+Initially `nil`, otherwise the Process::Status object
+created for the most-recently exited child process;
+thread-local.
+
+English - `$CHILD_STATUS`.
+
+### `$LOAD_PATH` (Load Path)
+
+Contains the array of paths to be searched
+by Kernel#load and Kernel#require.
+
+Singleton method `$LOAD_PATH.resolve_feature_path(feature)`
+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:
+
+```ruby
+$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 `$:` and `$-I`.
+
+### `$LOADED_FEATURES`
+
+Contains an array of the paths to the loaded files:
+
+```ruby
+$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 `$"`.
+
+## Debugging
+
+### `$FILENAME`
+
+The value returned by method ARGF.filename.
+
+### `$DEBUG`
+
+Initially `true` if [command-line option `-d`] or
+[`--debug`][command-line option `-d`] is given, otherwise initially `false`;
+may be set to either value in the running program.
+
+When `true`, prints each raised exception to `$stderr`.
+
+Aliased as `$-d`.
+
+### `$VERBOSE`
+
+Initially `true` if [command-line option `-v`] or
+[command-line option `-w`] 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 `$-v` and `$-w`.
+
+## Other Variables
+
+### `$-F`
+
+The default field separator in String#split; must be a String or a
+Regexp, and can be set with [command-line option `-F`].
+
+Setting to non-nil value by other than the command-line option is
+deprecated.
+
+Aliased as `$;`.
+
+### `$-a`
+
+Whether [command-line option `-a`] was given; read-only.
+
+### `$-i`
+
+Contains the extension given with [command-line option `-i`],
+or `nil` if none.
+
+An alias of ARGF.inplace_mode.
+
+### `$-l`
+
+Whether [command-line option `-l`] was set; read-only.
+
+### `$-p`
+
+Whether [command-line option `-p`] was given; read-only.
+
+### `$F`
+
+If the [command-line option `-a`] is given, the array
+obtained by splitting `$_` by `$-F` is assigned at the start of each
+`-l`/`-p` loop.
+
+## Deprecated
+
+### `$=`
+
+### `$,`
+
+# Pre-Defined Global Constants
+
+## Summary
+
+### Streams
+
+| Constant | Contains |
+|:--------:|-------------------------|
+| `STDIN` | Standard input stream. |
+| `STDOUT` | Standard output stream. |
+| `STDERR` | Standard error stream. |
+
+### Environment
+
+| Constant | Contains |
+|-----------------------|-------------------------------------------------------------------------------|
+| `ENV` | Hash of current environment variable names and values. |
+| `ARGF` | String concatenation of files given on the command line, or `$stdin` if none. |
+| `ARGV` | Array of the given command-line arguments. |
+| `TOPLEVEL_BINDING` | Binding of the top level scope. |
+| `RUBY_VERSION` | String Ruby version. |
+| `RUBY_RELEASE_DATE` | String Ruby release date. |
+| `RUBY_PLATFORM` | String Ruby platform. |
+| `RUBY_PATCH_LEVEL` | String Ruby patch level. |
+| `RUBY_REVISION` | String Ruby revision. |
+| `RUBY_COPYRIGHT` | String Ruby copyright. |
+| `RUBY_ENGINE` | String Ruby engine. |
+| `RUBY_ENGINE_VERSION` | String Ruby engine version. |
+| `RUBY_DESCRIPTION` | String Ruby description. |
+
+### Embedded \Data
+
+| Constant | Contains |
+|:---------------------:|-------------------------------------------------------------------------------|
+| `DATA` | File containing embedded data (lines following `__END__`, if any). |
+
+## Streams
+
+### `STDIN`
+
+The standard input stream (the default value for `$stdin`):
+
+```ruby
+STDIN # => #<IO:<STDIN>>
+```
+
+### `STDOUT`
+
+The standard output stream (the default value for `$stdout`):
+
+```ruby
+STDOUT # => #<IO:<STDOUT>>
+```
+
+### `STDERR`
+
+The standard error stream (the default value for `$stderr`):
+
+```ruby
+STDERR # => #<IO:<STDERR>>
+```
+
+## Environment
+
+### `ENV`
+
+A hash of the contains current environment variables names and values:
+
+```ruby
+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
+`$stdin` if no files were given, `"-"` is given, or after
+all files have been read.
+
+### `ARGV`
+
+An array of the given command-line arguments.
+
+### `TOPLEVEL_BINDING`
+
+The Binding of the top level scope:
+
+```ruby
+TOPLEVEL_BINDING # => #<Binding:0x00007f58da0da7c0>
+```
+
+### `RUBY_VERSION`
+
+The Ruby version:
+
+```ruby
+RUBY_VERSION # => "3.2.2"
+```
+
+### `RUBY_RELEASE_DATE`
+
+The release date string:
+
+```ruby
+RUBY_RELEASE_DATE # => "2023-03-30"
+```
+
+### `RUBY_PLATFORM`
+
+The platform identifier:
+
+```ruby
+RUBY_PLATFORM # => "x86_64-linux"
+```
+
+### `RUBY_PATCHLEVEL`
+
+The integer patch level for this Ruby:
+
+```ruby
+RUBY_PATCHLEVEL # => 53
+```
+
+For a development build the patch level will be -1.
+
+### `RUBY_REVISION`
+
+The git commit hash for this Ruby:
+
+```ruby
+RUBY_REVISION # => "e51014f9c05aa65cbf203442d37fef7c12390015"
+```
+
+### `RUBY_COPYRIGHT`
+
+The copyright string:
+
+```ruby
+RUBY_COPYRIGHT
+# => "ruby - Copyright (C) 1993-2023 Yukihiro Matsumoto"
+```
+
+### `RUBY_ENGINE`
+
+The name of the Ruby implementation:
+
+```ruby
+RUBY_ENGINE # => "ruby"
+```
+
+### `RUBY_ENGINE_VERSION`
+
+The version of the Ruby implementation:
+
+```ruby
+RUBY_ENGINE_VERSION # => "3.2.2"
+```
+
+### `RUBY_DESCRIPTION`
+
+The description of the Ruby implementation:
+
+```ruby
+RUBY_DESCRIPTION
+# => "ruby 3.2.2 (2023-03-30 revision e51014f9c0) [x86_64-linux]"
+```
+
+## Embedded \Data
+
+### `DATA`
+
+Defined if and only if the program has this line:
+
+```ruby
+__END__
+```
+
+When defined, `DATA` is a File object
+containing the lines following the `__END__`,
+positioned at the first of those lines:
+
+```ruby
+p DATA
+DATA.each_line { |line| p line }
+__END__
+Foo
+Bar
+Baz
+```
+
+Output:
+
+```
+#<File:t.rb>
+"Foo\n"
+"Bar\n"
+"Baz\n"
+```
+
+[command-line option `-0`]: rdoc-ref:language/options.md@-0-set--input-record-separator
+[command-line option `-F`]: rdoc-ref:language/options.md@-f-set-input-field-separator
+[command-line option `-a`]: rdoc-ref:language/options.md@-a-split-input-lines-into-fields
+[command-line option `-d`]: rdoc-ref:language/options.md@-d-set-debug-to-true
+[command-line option `-i`]: rdoc-ref:language/options.md@-i-set-argf-in-place-mode
+[command-line option `-l`]: rdoc-ref:language/options.md@-l-set-output-record-separator-chop-lines
+[command-line option `-p`]: rdoc-ref:language/options.md@-p--n-with-printing
+[command-line option `-v`]: rdoc-ref:language/options.md@-v-print-version-set-verbose
+[command-line option `-w`]: rdoc-ref:language/options.md@-w-synonym-for--w1
+
+[Regexp Global Variables]: rdoc-ref:Regexp@Global+Variables
+
diff --git a/doc/hash_inclusion.rdoc b/doc/language/hash_inclusion.rdoc
index 05c2b0932a..05c2b0932a 100644
--- a/doc/hash_inclusion.rdoc
+++ b/doc/language/hash_inclusion.rdoc
diff --git a/doc/implicit_conversion.rdoc b/doc/language/implicit_conversion.rdoc
index e244096125..e244096125 100644
--- a/doc/implicit_conversion.rdoc
+++ b/doc/language/implicit_conversion.rdoc
diff --git a/doc/marshal.rdoc b/doc/language/marshal.rdoc
index 740064ade6..740064ade6 100644
--- a/doc/marshal.rdoc
+++ b/doc/language/marshal.rdoc
diff --git a/doc/language/option_dump.md b/doc/language/option_dump.md
new file mode 100644
index 0000000000..328c6b52af
--- /dev/null
+++ b/doc/language/option_dump.md
@@ -0,0 +1,265 @@
+# Option `--dump`
+
+For other argument values,
+see {Option `--dump`}[rdoc-ref:options.md@--dump+Dump+Items].
+
+For the examples here, we use this program:
+
+```console
+$ 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 dupstring "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):
+
+ ```console
+ $ 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)
+ ```
+
+- `yydebug`: Debugging information from yacc parser generator:
+
+ ```
+ $ 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: )
+ ```
+
+Additional flags can follow dump items.
+
+- `+comment`: Add comments to AST.
+- `+error-tolerant`: Parse in error-tolerant mode.
+- `-optimize`: Disable optimizations for instruction sequences.
diff --git a/doc/language/options.md b/doc/language/options.md
new file mode 100644
index 0000000000..1329b7ca63
--- /dev/null
+++ b/doc/language/options.md
@@ -0,0 +1,744 @@
+# 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:
+
+```console
+$ ruby -e 'puts "Hello, World."'
+```
+
+Some examples here assume that file `desiderata.txt` exists:
+
+```console
+$ 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:
+
+```console
+$ 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`][-a]:
+ Split input lines into fields.
+- [Option `-F`][-F]:
+ Set input field separator.
+- [Option `-l`][-l]:
+ Set output record separator; chop lines.
+- [Option `-n`][-n]:
+ Run program in `gets` loop.
+- [Option `-p`][-p]:
+ `-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`:
+
+```console
+$ 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`][-0]:
+ Set `$/` (input record separator).
+- [Option `-F`][-F]:
+ Set input field separator.
+- [Option `-l`][-l]:
+ Set output record separator; chop lines.
+- [Option `-n`][-n]:
+ Run program in `gets` loop.
+- [Option `-p`][-p]:
+ `-n`, with printing.
+
+### `-c`: Check Syntax
+
+Option `-c` specifies that the specified Ruby program
+should be checked for syntax, but not actually executed:
+
+```console
+$ 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:
+
+```console
+$ basename `pwd`
+ruby
+$ ruby -C lib -e 'puts File.basename(Dir.pwd)'
+lib
+$ basename `pwd`
+ruby
+```
+
+This option is accumulative; relative paths are solved from the
+previous working directory.
+
+```console
+$ ruby -C / -C usr -e 'puts Dir.pwd'
+/usr
+```
+
+If the argument is not an existing directory, a fatal error will
+occur:
+
+```console
+$ ruby -C /nonexistent
+ruby: Can't chdir to /nonexistent (fatal)
+$ ruby -C /dev/null
+ruby: Can't chdir to /dev/null (fatal)
+```
+
+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`:
+
+```console
+$ ruby -e 'p $DEBUG'
+false
+$ ruby -d -e 'p $DEBUG'
+true
+```
+
+[Option `--debug`][--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:
+
+```console
+$ 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:
+
+```console
+# 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`][--external-encoding]:
+ Set default external encoding.
+- [Option `--internal-encoding`][--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:
+
+```console
+$ 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:
+
+```console
+$ 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`][-0]:
+ Set `$/` (input record separator).
+- [Option `-a`][-a]:
+ Split input lines into fields.
+- [Option `-l`][-l]:
+ Set output record separator; chop lines.
+- [Option `-n`][-n]:
+ Run program in `gets` loop.
+- [Option `-p`][-p]:
+ `-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=:
+
+```console
+$ 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:
+
+```console
+$ 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
+```
+
+This option and [option `-C`][-C] will
+be applied in the order in the command line; expansion of `-I` options
+are affected by preceeding `-C` options.
+
+```console
+$ ruby -C / -Ilib -C usr -Ilib -e 'puts $:[0, 2]'
+/lib
+/usr/lib
+```
+
+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):
+
+```console
+$ 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):
+
+```console
+$ 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`][-0]:
+ Set `$/` (input record separator).
+- [Option `-a`][-a]:
+ Split input lines into fields.
+- [Option `-F`][-F]:
+ Set input field separator.
+- [Option `-n`][-n]:
+ Run program in `gets` loop.
+- [Option `-p`][-p]:
+ `-n`, with printing.
+
+### `-n`: Run Program in `gets` Loop
+
+Option `-n` runs your program in a `Kernel#gets` loop:
+
+```ruby
+while gets
+ # Your Ruby code.
+end
+```
+
+Note that `gets` reads the next line and sets global variable `$_`
+to the last read line:
+
+```console
+$ 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`][-0]:
+ Set `$/` (input record separator).
+- [Option `-a`][-a]:
+ Split input lines into fields.
+- [Option `-F`][-F]:
+ Set input field separator.
+- [Option `-l`][-l]:
+ Set output record separator; chop lines.
+- [Option `-p`][-p]:
+ `-n`, with printing.
+
+### `-p`: `-n`, with Printing
+
+Option `-p` is like option `-n`, but also prints each line:
+
+```console
+$ 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`][-0]:
+ Set `$/` (input record separator).
+- [Option `-a`][-a]:
+ Split input lines into fields.
+- [Option `-F`][-F]:
+ Set input field separator.
+- [Option `-l`][-l]:
+ Set output record separator; chop lines.
+- [Option `-n`][-n]:
+ 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:
+
+```console
+$ ruby -e 'p defined?(JSON); p defined?(CSV)'
+nil
+nil
+$ ruby -r csv -r json -e 'p defined?(JSON); p defined?(CSV)'
+"constant"
+"constant"
+```
+
+The library is loaded with the `Kernel#require` method, after the
+other options such as [`-C`][-C], [`-I`][-I], and "custom options" by
+[`-s`][-s], are applied:
+
+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.
+- If there is no script name in the command line (using {option
+ -e}[rdoc-ref:@-e+Execute+Given+Ruby+Code] or implicit reading from
+ `$stdin`), the custom options must be separated from the other
+ interpreter options with a `--`.
+- 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:
+
+```console
+$ 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"]
+```
+
+### `-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:
+
+```console
+$ 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`:
+
+```console
+$ 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):
+
+```console
+$ 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:
+
+```rb
+Warning[:experimental] # => true
+Warning[:deprecated] # => false
+Warning[:performance] # => false
+```
+
+They may also be set:
+
+```rb
+Warning[:experimental] = false
+Warning[:deprecated] = true
+Warning[:performance] = true
+```
+
+You can suppress a category by prefixing `no-` to the category name:
+
+```console
+$ 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:
+
+```console
+$ 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:
+
+```console
+$ 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:
+
+```console
+$ ruby --copyright
+ruby - Copyright (C) 1993-2024 Yukihiro Matsumoto
+```
+
+### `--debug`: Alias for `-d`
+
+Option `--debug` is an alias for
+[option `-d`][-d].
+
+### `--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`][--enable].
+
+### `--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`][--copyright].
+- `--dump=help`:
+ Same as [option `--help`][--help].
+- `--dump=syntax`:
+ Same as [option `-c`][-c].
+- `--dump=usage`:
+ Same as [option `-h`][-h].
+- `--dump=version`:
+ Same as [option `--version`][--version].
+
+For other argument values and examples,
+see {Option `--dump`}[rdoc-ref:option_dump.md].
+
+### `--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`][--disable].
+
+### `--encoding`: Alias for `-E`.
+
+Option `--encoding` is an alias for
+[option `-E`][-E].
+
+### `--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].
+
+```console
+$ 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].
+
+```console
+$ ruby -e 'puts Encoding::default_internal.nil?'
+true
+$ ruby --internal-encoding=cesu-8 -e 'puts Encoding::default_internal'
+CESU-8
+```
+
+### `--jit`
+
+Option `--jit` is an alias for option `--yjit`, which enables YJIT;
+see additional YJIT options in the [YJIT documentation](rdoc-ref:jit/yjit.md).
+
+### `--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.
+
+[-0]: rdoc-ref:@-0+Set++Input+Record+Separator
+[-C]: rdoc-ref:@-C+Set+Working+Directory
+[-E]: rdoc-ref:@-E+Set+Default+Encodings
+[-F]: rdoc-ref:@-F+Set+Input+Field+Separator
+[-I]: rdoc-ref:@-I+Add+to+LOADPATH
+[-a]: rdoc-ref:@-a+Split+Input+Lines+into+Fields
+[-c]: rdoc-ref:@-c+Check+Syntax
+[-d]: rdoc-ref:@-d+Set+DEBUG+to+true
+[-e]: rdoc-ref:@-e+Execute+Given+Ruby+Code
+[-h]: rdoc-ref:@-h+Print+Short+Help+Message
+[-l]: rdoc-ref:@-l+Set+Output+Record+Separator+Chop+Lines
+[-n]: rdoc-ref:@-n+Run+Program+in+gets+Loop
+[-p]: rdoc-ref:@-p+-n+with+Printing
+[-s]: rdoc-ref:@-s+Define+Global+Variable
+[--copyright]: rdoc-ref:@--copyright+Print+Ruby+Copyright
+[--debug]: rdoc-ref:@--debug+Alias+for+-d
+[--disable]: rdoc-ref:@--disable+Disable+Features
+[--enable]: rdoc-ref:@--enable+Enable+Features
+[--external-encoding]: rdoc-ref:@--external+encoding+Set+Default+External+Encoding
+[--internal-encoding]: rdoc-ref:@--internal+encoding+Set+Default+Internal+Encoding
+[--help]: rdoc-ref:@--help+Print+Help+Message
+[--version]: rdoc-ref:@--version+Print+Ruby+Version
+[Encoding: Names and Aliases]: rdoc-ref:encodings.rdoc@Names+and+Aliases
diff --git a/doc/language/packed_data.md b/doc/language/packed_data.md
new file mode 100644
index 0000000000..1b133367d6
--- /dev/null
+++ b/doc/language/packed_data.md
@@ -0,0 +1,886 @@
+# Packed \Data
+
+## Quick Reference
+
+These tables summarize the directives for packing and unpacking.
+
+### For Integers
+
+| Directive | Meaning |
+|-----------------------|-----------------------------------------------------------------------------------------------------|
+| `C` | 8-bit unsigned (`unsigned char`) |
+| `S` | 16-bit unsigned, native endian (`uint16_t`) |
+| `L` | 32-bit unsigned, native endian (`uint32_t`) |
+| `Q` | 64-bit unsigned, native endian (`uint64_t`) |
+| `J` | pointer width unsigned, native endian (`uintptr_t`) |
+| | |
+| `c` | 8-bit signed (`signed char`) |
+| `s` | 16-bit signed, native endian (`int16_t`) |
+| `l` | 32-bit signed, native endian (`int32_t`) |
+| `q` | 64-bit signed, native endian (`int64_t`) |
+| `j` | pointer width signed, native endian (`intptr_t`) |
+| | |
+| `S_` `S!` | `unsigned short`, native endian |
+| `I` `I_` `I!` | `unsigned int`, native endian |
+| `L_` `L!` | `unsigned long`, native endian |
+| `Q_` `Q!` | `unsigned long long`, native endian; (raises ArgumentError if the platform has no `long long` type) |
+| `J!` | `uintptr_t`, native endian (same with `J`) |
+| | |
+| `s_` `s!` | `signed short`, native endian |
+| `i` `i_` `i!` | `signed int`, native endian |
+| `l_` `l!` | `signed long`, native endian |
+| `q_` `q!` | `signed long long`, native endian; (raises ArgumentError if the platform has no `long long` type) |
+| `j!` | `intptr_t`, native endian (same with `j`) |
+| | |
+| `S>` `s>` `S!>` `s!>` | each the same as the directive without `>`, but big endian; `S>` is the same as `n` |
+| `L>` `l>` `L!>` `l!>` | `L>` is the same as `N` |
+| `I!>` `i!>` | |
+| `Q>` `q>` `Q!>` `q!>` | |
+| `J>` `j>` `J!>` `j!>` | |
+| | |
+| `S<` `s<` `S!<` `s!<` | each the same as the directive without `<`, but little endian; `S<` is the same as `v` |
+| `L<` `l<` `L!<` `l!<` | `L<` is the same as `V` |
+| `I!<` `i!<` | |
+| `Q<` `q<` `Q!<` `q!<` | |
+| `J<` `j<` `J!<` `j!<` | |
+| | |
+| `n` | 16-bit unsigned, network (big-endian) byte order |
+| `N` | 32-bit unsigned, network (big-endian) byte order |
+| `v` | 16-bit unsigned, VAX (little-endian) byte order |
+| `V` | 32-bit unsigned, VAX (little-endian) byte order |
+| | |
+| `U` | UTF-8 character |
+| `w` | BER-compressed integer |
+| `R` | LEB128 encoded unsigned integer |
+| `r` | LEB128 encoded signed integer |
+
+### For Floats
+
+| Directive | Meaning |
+|-----------|---------------------------------------------------|
+| `D` `d` | double-precision, native format |
+| `F` `f` | single-precision, native format |
+| `E` | double-precision, little-endian byte order |
+| `e` | single-precision, little-endian byte order |
+| `G` | double-precision, network (big-endian) byte order |
+| `g` | single-precision, network (big-endian) byte order |
+
+### For Strings
+
+| Directive | Meaning |
+|-----------|------------------------------------------------------------------------------------------------|
+| `A` | arbitrary binary string (remove trailing nulls and ASCII spaces) |
+| `a` | arbitrary binary string |
+| `Z` | null-terminated string |
+| `B` | bit string (MSB first) |
+| `b` | bit string (LSB first) |
+| `H` | hex string (high nibble first) |
+| `h` | hex string (low nibble first) |
+| `u` | UU-encoded string |
+| `M` | quoted-printable, MIME encoding (see RFC2045) |
+| `m` | base64 encoded string (RFC 2045) (default) (base64 encoded string (RFC 4648) if followed by 0) |
+| `P` | pointer to a structure (fixed-length string) |
+| `p` | pointer to a null-terminated string |
+
+### Additional Directives for Packing
+
+| Directive | Meaning |
+|-----------|----------------------------|
+| `@` | moves to absolute position |
+| `X` | back up a byte |
+| `x` | null byte |
+
+### Additional Directives for Unpacking
+
+| Directive | Meaning |
+|-----------|-------------------------------------------------|
+| `@` | skip to the offset given by the length argument |
+| `X` | skip backward one byte |
+| `x` | skip forward one byte |
+| `^` | return the current offset |
+
+## Packing and Unpacking
+
+Certain Ruby core methods deal with packing and unpacking data:
+
+- Method Array#pack:
+ Formats each element in array `self` into a binary string;
+ returns that string.
+- Method String#unpack:
+ Extracts data from string `self`,
+ forming objects that become the elements of a new array;
+ returns that array.
+- Method String#unpack1:
+ Does the same, but unpacks and returns only the first extracted object.
+
+Each of these methods accepts a string `template`,
+consisting of zero or more _directive_ characters,
+each followed by zero or more _modifier_ characters.
+
+Examples (directive `'C'` specifies '`unsigned character`'):
+
+```ruby
+[65].pack('C') # => "A" # One element, one directive.
+[65, 66].pack('CC') # => "AB" # Two elements, two directives.
+[65, 66].pack('C') # => "A" # Extra element is ignored.
+[65].pack('') # => "" # No directives.
+[65].pack('CC') # Extra directive raises ArgumentError.
+```
+
+```ruby
+'A'.unpack('C') # => [65] # One character, one directive.
+'AB'.unpack('CC') # => [65, 66] # Two characters, two directives.
+'AB'.unpack('C') # => [65] # Extra character is ignored.
+'A'.unpack('CC') # => [65, nil] # Extra directive generates nil.
+'AB'.unpack('') # => [] # No directives.
+```
+
+The string `template` may contain any mixture of valid directives
+(directive `'c'` specifies 'signed character'):
+
+```ruby
+[65, -1].pack('cC') # => "A\xFF"
+"A\xFF".unpack('cC') # => [65, 255]
+```
+
+The string `template` may contain whitespace (which is ignored)
+and comments, each of which begins with character `'#'`
+and continues up to and including the next following newline:
+
+```ruby
+[0,1].pack(" C #foo \n C ") # => "\x00\x01"
+"\0\1".unpack(" C #foo \n C ") # => [0, 1]
+```
+
+Any directive may be followed by either of these modifiers:
+
+- `'*'` - The directive is to be applied as many times as needed:
+
+ ```ruby
+ [65, 66].pack('C*') # => "AB"
+ 'AB'.unpack('C*') # => [65, 66]
+ ```
+
+- \Integer `count` - The directive is to be applied `count` times:
+
+ ```ruby
+ [65, 66].pack('C2') # => "AB"
+ [65, 66].pack('C3') # Raises ArgumentError.
+ 'AB'.unpack('C2') # => [65, 66]
+ 'AB'.unpack('C3') # => [65, 66, nil]
+ ```
+
+ Note: Directives in `%w[A a Z m]` use `count` differently;
+ see [\String Directives][rdoc-ref:@String+Directives].
+
+If elements don't fit the provided directive, only least significant bits are encoded:
+
+```ruby
+[257].pack("C").unpack("C") # => [1]
+```
+
+## Packing Method
+
+Method Array#pack accepts optional keyword argument
+`buffer` that specifies the target string (instead of a new string):
+
+```ruby
+[65, 66].pack('C*', buffer: 'foo') # => "fooAB"
+```
+
+The method can accept a block:
+
+```ruby
+# Packed string is passed to the block.
+[65, 66].pack('C*') {|s| p s } # => "AB"
+```
+
+## Unpacking Methods
+
+Methods String#unpack and String#unpack1 each accept
+an optional keyword argument `offset` that specifies an offset
+into the string:
+
+```ruby
+'ABC'.unpack('C*', offset: 1) # => [66, 67]
+'ABC'.unpack1('C*', offset: 1) # => 66
+```
+
+Both methods can accept a block:
+
+```ruby
+# Each unpacked object is passed to the block.
+ret = []
+"ABCD".unpack("C*") {|c| ret << c }
+ret # => [65, 66, 67, 68]
+```
+
+```ruby
+# The single unpacked object is passed to the block.
+'AB'.unpack1('C*') {|ele| p ele } # => 65
+```
+
+## \Integer Directives
+
+Each integer directive specifies the packing or unpacking
+for one element in the input or output array.
+
+### 8-Bit \Integer Directives
+
+- `'c'` - 8-bit signed integer
+ (like C `signed char`):
+
+ ```ruby
+ [0, 1, 255].pack('c*') # => "\x00\x01\xFF"
+ s = [0, 1, -1].pack('c*') # => "\x00\x01\xFF"
+ s.unpack('c*') # => [0, 1, -1]
+ ```
+
+- `'C'` - 8-bit unsigned integer
+ (like C `unsigned char`):
+
+ ```ruby
+ [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
+
+- `'s'` - 16-bit signed integer, native-endian
+ (like C `int16_t`):
+
+ ```ruby
+ [513, -514].pack('s*') # => "\x01\x02\xFE\xFD"
+ s = [513, 65022].pack('s*') # => "\x01\x02\xFE\xFD"
+ s.unpack('s*') # => [513, -514]
+ ```
+
+- `'S'` - 16-bit unsigned integer, native-endian
+ (like C `uint16_t`):
+
+ ```ruby
+ [513, -514].pack('S*') # => "\x01\x02\xFE\xFD"
+ s = [513, 65022].pack('S*') # => "\x01\x02\xFE\xFD"
+ s.unpack('S*') # => [513, 65022]
+ ```
+
+- `'n'` - 16-bit network integer, big-endian:
+
+ ```ruby
+ s = [0, 1, -1, 32767, -32768, 65535].pack('n*')
+ # => "\x00\x00\x00\x01\xFF\xFF\x7F\xFF\x80\x00\xFF\xFF"
+ s.unpack('n*')
+ # => [0, 1, 65535, 32767, 32768, 65535]
+ ```
+
+- `'v'` - 16-bit VAX integer, little-endian:
+
+ ```ruby
+ s = [0, 1, -1, 32767, -32768, 65535].pack('v*')
+ # => "\x00\x00\x01\x00\xFF\xFF\xFF\x7F\x00\x80\xFF\xFF"
+ s.unpack('v*')
+ # => [0, 1, 65535, 32767, 32768, 65535]
+ ```
+
+### 32-Bit \Integer Directives
+
+- `'l'` - 32-bit signed integer, native-endian
+ (like C `int32_t`):
+
+ ```ruby
+ s = [67305985, -50462977].pack('l*')
+ # => "\x01\x02\x03\x04\xFF\xFE\xFD\xFC"
+ s.unpack('l*')
+ # => [67305985, -50462977]
+ ```
+
+- `'L'` - 32-bit unsigned integer, native-endian
+ (like C `uint32_t`):
+
+ ```ruby
+ s = [67305985, 4244504319].pack('L*')
+ # => "\x01\x02\x03\x04\xFF\xFE\xFD\xFC"
+ s.unpack('L*')
+ # => [67305985, 4244504319]
+ ```
+
+- `'N'` - 32-bit network integer, big-endian:
+
+ ```ruby
+ s = [0,1,-1].pack('N*')
+ # => "\x00\x00\x00\x00\x00\x00\x00\x01\xFF\xFF\xFF\xFF"
+ s.unpack('N*')
+ # => [0, 1, 4294967295]
+ ```
+
+- `'V'` - 32-bit VAX integer, little-endian:
+
+ ```ruby
+ s = [0,1,-1].pack('V*')
+ # => "\x00\x00\x00\x00\x01\x00\x00\x00\xFF\xFF\xFF\xFF"
+ s.unpack('v*')
+ # => [0, 0, 1, 0, 65535, 65535]
+ ```
+
+### 64-Bit \Integer Directives
+
+- `'q'` - 64-bit signed integer, native-endian
+ (like C `int64_t`):
+
+ ```ruby
+ s = [578437695752307201, -506097522914230529].pack('q*')
+ # => "\x01\x02\x03\x04\x05\x06\a\b\xFF\xFE\xFD\xFC\xFB\xFA\xF9\xF8"
+ s.unpack('q*')
+ # => [578437695752307201, -506097522914230529]
+ ```
+
+- `'Q'` - 64-bit unsigned integer, native-endian
+ (like C `uint64_t`):
+
+ ```ruby
+ s = [578437695752307201, 17940646550795321087].pack('Q*')
+ # => "\x01\x02\x03\x04\x05\x06\a\b\xFF\xFE\xFD\xFC\xFB\xFA\xF9\xF8"
+ s.unpack('Q*')
+ # => [578437695752307201, 17940646550795321087]
+ ```
+
+### Platform-Dependent \Integer Directives
+
+- `'i'` - Platform-dependent width signed integer,
+ native-endian (like C `int`):
+
+ ```ruby
+ s = [67305985, -50462977].pack('i*')
+ # => "\x01\x02\x03\x04\xFF\xFE\xFD\xFC"
+ s.unpack('i*')
+ # => [67305985, -50462977]
+ ```
+
+- `'I'` - Platform-dependent width unsigned integer,
+ native-endian (like C `unsigned int`):
+
+ ```ruby
+ s = [67305985, -50462977].pack('I*')
+ # => "\x01\x02\x03\x04\xFF\xFE\xFD\xFC"
+ s.unpack('I*')
+ # => [67305985, 4244504319]
+ ```
+
+- `'j'` - Pointer-width signed integer, native-endian
+ (like C `intptr_t`):
+
+ ```ruby
+ 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]
+ ```
+
+- `'J'` - Pointer-width unsigned integer, native-endian
+ (like C `uintptr_t`):
+
+ ```ruby
+ 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
+
+- `'U'` - UTF-8 character:
+
+ ```ruby
+ s = [4194304].pack('U*')
+ # => "\xF8\x90\x80\x80\x80"
+ s.unpack('U*')
+ # => [4194304]
+ ```
+
+- `'r'` - Signed LEB128-encoded integer
+ (see [Signed LEB128](https://en.wikipedia.org/wiki/LEB128#Signed_LEB128))
+
+ ```ruby
+ s = [1, 127, -128, 16383, -16384].pack("r*")
+ # => "\x01\xFF\x00\x80\x7F\xFF\xFF\x00\x80\x80\x7F"
+ s.unpack('r*')
+ # => [1, 127, -128, 16383, -16384]
+ ```
+
+- `'R'` - Unsigned LEB128-encoded integer
+ (see [Unsigned LEB128](https://en.wikipedia.org/wiki/LEB128#Unsigned_LEB128))
+
+ ```ruby
+ s = [1, 127, 128, 16383, 16384].pack("R*")
+ # => "\x01\x7F\x80\x01\xFF\x7F\x80\x80\x01"
+ s.unpack('R*')
+ # => [1, 127, 128, 16383, 16384]
+ ```
+
+- `'w'` - BER-encoded integer
+ (see [BER encoding](https://en.wikipedia.org/wiki/X.690#BER_encoding)):
+
+ ```ruby
+ s = [1073741823].pack('w*')
+ # => "\x83\xFF\xFF\xFF\x7F"
+ s.unpack('w*')
+ # => [1073741823]
+ ```
+
+### Modifiers for \Integer Directives
+
+For the following directives, `'!'` or `'_'` modifiers may be
+suffixed as underlying platform’s native size.
+
+- `'i'`, `'I'` - C `int`, always native size.
+- `'s'`, `'S'` - C `short`.
+- `'l'`, `'L'` - C `long`.
+- `'q'`, `'Q'` - C `long long`, if available.
+- `'j'`, `'J'` - C `intptr_t`, 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:
+
+- `'>'` - Big-endian.
+- `'<'` - Little-endian.
+
+## \Float Directives
+
+Each float directive specifies the packing or unpacking
+for one element in the input or output array.
+
+### Single-Precision \Float Directives
+
+- `'F'` or `'f'` - Native format:
+
+ ```ruby
+ s = [3.0].pack('F') # => "\x00\x00@@"
+ s.unpack('F') # => [3.0]
+ ```
+
+- `'e'` - Little-endian:
+
+ ```ruby
+ s = [3.0].pack('e') # => "\x00\x00@@"
+ s.unpack('e') # => [3.0]
+ ```
+
+- `'g'` - Big-endian:
+
+ ```ruby
+ s = [3.0].pack('g') # => "@@\x00\x00"
+ s.unpack('g') # => [3.0]
+ ```
+
+### Double-Precision \Float Directives
+
+- `'D'` or `'d'` - Native format:
+
+ ```ruby
+ s = [3.0].pack('D') # => "\x00\x00\x00\x00\x00\x00\b@"
+ s.unpack('D') # => [3.0]
+ ```
+
+- `'E'` - Little-endian:
+
+ ```ruby
+ s = [3.0].pack('E') # => "\x00\x00\x00\x00\x00\x00\b@"
+ s.unpack('E') # => [3.0]
+ ```
+
+- `'G'` - Big-endian:
+
+ ```ruby
+ s = [3.0].pack('G') # => "@\b\x00\x00\x00\x00\x00\x00"
+ s.unpack('G') # => [3.0]
+ ```
+
+A float directive may be infinity or not-a-number:
+
+```ruby
+inf = 1.0/0.0 # => Infinity
+[inf].pack('f') # => "\x00\x00\x80\x7F"
+"\x00\x00\x80\x7F".unpack('f') # => [Infinity]
+
+nan = inf/inf # => NaN
+[nan].pack('f') # => "\x00\x00\xC0\x7F"
+"\x00\x00\xC0\x7F".unpack('f') # => [NaN]
+```
+
+## \String Directives
+
+Each string directive specifies the packing or unpacking
+for one byte in the input or output string.
+
+### Binary \String Directives
+
+- `'A'` - Arbitrary binary string (space padded; count is width);
+ `nil` is treated as the empty string:
+
+ ```ruby
+ ['foo'].pack('A') # => "f"
+ ['foo'].pack('A*') # => "foo"
+ ['foo'].pack('A2') # => "fo"
+ ['foo'].pack('A4') # => "foo "
+ [nil].pack('A') # => " "
+ [nil].pack('A*') # => ""
+ [nil].pack('A2') # => " "
+ [nil].pack('A4') # => " "
+ ```
+
+ ```ruby
+ "foo\0".unpack('A') # => ["f"]
+ "foo\0".unpack('A4') # => ["foo"]
+ "foo\0bar".unpack('A10') # => ["foo\x00bar"] # Reads past "\0".
+ "foo ".unpack('A') # => ["f"]
+ "foo ".unpack('A4') # => ["foo"]
+ "foo".unpack('A4') # => ["foo"]
+ ```
+
+ ```ruby
+ japanese = 'ã“ã‚“ã«ã¡ã¯'
+ japanese.size # => 5
+ japanese.bytesize # => 15
+ [japanese].pack('A') # => "\xE3"
+ [japanese].pack('A*') # => "\xE3\x81\x93\xE3\x82\x93\xE3\x81\xAB\xE3\x81\xA1\xE3\x81\xAF"
+ japanese.unpack('A') # => ["\xE3"]
+ japanese.unpack('A2') # => ["\xE3\x81"]
+ japanese.unpack('A4') # => ["\xE3\x81\x93\xE3"]
+ japanese.unpack('A*') # => ["\xE3\x81\x93\xE3\x82\x93\xE3\x81\xAB\xE3\x81\xA1\xE3\x81\xAF"]
+ ```
+
+- `'a'` - Arbitrary binary string (null padded; count is width):
+
+ ```ruby
+ ["foo"].pack('a') # => "f"
+ ["foo"].pack('a*') # => "foo"
+ ["foo"].pack('a2') # => "fo"
+ ["foo\0"].pack('a4') # => "foo\x00"
+ [nil].pack('a') # => "\x00"
+ [nil].pack('a*') # => ""
+ [nil].pack('a2') # => "\x00\x00"
+ [nil].pack('a4') # => "\x00\x00\x00\x00"
+ ```
+
+ ```ruby
+ "foo\0".unpack('a') # => ["f"]
+ "foo\0".unpack('a4') # => ["foo\x00"]
+ "foo ".unpack('a4') # => ["foo "]
+ "foo".unpack('a4') # => ["foo"]
+ "foo\0bar".unpack('a4') # => ["foo\x00"] # Reads past "\0".
+ ```
+
+- `'Z'` - Same as `'a'`,
+ except that null is added or ignored with `'*'`:
+
+ ```ruby
+ ["foo"].pack('Z*') # => "foo\x00"
+ [nil].pack('Z*') # => "\x00"
+ ```
+
+ ```ruby
+ "foo\0".unpack('Z*') # => ["foo"]
+ "foo".unpack('Z*') # => ["foo"]
+ "foo\0bar".unpack('Z*') # => ["foo"] # Does not read past "\0".
+ ```
+
+### Bit \String Directives
+
+- `'B'` - Bit string (high byte first):
+
+ ```ruby
+ ['11111111' + '00000000'].pack('B*') # => "\xFF\x00"
+ ['10000000' + '01000000'].pack('B*') # => "\x80@"
+ ```
+
+ ```ruby
+ ['1'].pack('B0') # => ""
+ ['1'].pack('B1') # => "\x80"
+ ['1'].pack('B2') # => "\x80\x00"
+ ['1'].pack('B3') # => "\x80\x00"
+ ['1'].pack('B4') # => "\x80\x00\x00"
+ ['1'].pack('B5') # => "\x80\x00\x00"
+ ['1'].pack('B6') # => "\x80\x00\x00\x00"
+ ```
+
+ ```ruby
+ "\xff\x00".unpack("B*") # => ["1111111100000000"]
+ "\x01\x02".unpack("B*") # => ["0000000100000010"]
+ ```
+
+ ```ruby
+ "".unpack("B0") # => [""]
+ "\x80".unpack("B1") # => ["1"]
+ "\x80".unpack("B2") # => ["10"]
+ "\x80".unpack("B3") # => ["100"]
+ ```
+
+- `'b'` - Bit string (low byte first):
+
+ ```ruby
+ ['11111111' + '00000000'].pack('b*') # => "\xFF\x00"
+ ['10000000' + '01000000'].pack('b*') # => "\x01\x02"
+ ```
+
+ ```ruby
+ ['1'].pack('b0') # => ""
+ ['1'].pack('b1') # => "\x01"
+ ['1'].pack('b2') # => "\x01\x00"
+ ['1'].pack('b3') # => "\x01\x00"
+ ['1'].pack('b4') # => "\x01\x00\x00"
+ ['1'].pack('b5') # => "\x01\x00\x00"
+ ['1'].pack('b6') # => "\x01\x00\x00\x00"
+ ```
+
+ ```ruby
+ "\xff\x00".unpack("b*") # => ["1111111100000000"]
+ "\x01\x02".unpack("b*") # => ["1000000001000000"]
+ ```
+
+ ```ruby
+ "".unpack("b0") # => [""]
+ "\x01".unpack("b1") # => ["1"]
+ "\x01".unpack("b2") # => ["10"]
+ "\x01".unpack("b3") # => ["100"]
+ ```
+
+### Hex \String Directives
+
+- `'H'` - Hex string (high nibble first):
+
+ ```ruby
+ ['10ef'].pack('H*') # => "\x10\xEF"
+ ['10ef'].pack('H0') # => ""
+ ['10ef'].pack('H3') # => "\x10\xE0"
+ ['10ef'].pack('H5') # => "\x10\xEF\x00"
+ ```
+
+ ```ruby
+ ['fff'].pack('H3') # => "\xFF\xF0"
+ ['fff'].pack('H4') # => "\xFF\xF0"
+ ['fff'].pack('H5') # => "\xFF\xF0\x00"
+ ['fff'].pack('H6') # => "\xFF\xF0\x00"
+ ['fff'].pack('H7') # => "\xFF\xF0\x00\x00"
+ ['fff'].pack('H8') # => "\xFF\xF0\x00\x00"
+ ```
+
+ ```ruby
+ "\x10\xef".unpack('H*') # => ["10ef"]
+ "\x10\xef".unpack('H0') # => [""]
+ "\x10\xef".unpack('H1') # => ["1"]
+ "\x10\xef".unpack('H2') # => ["10"]
+ "\x10\xef".unpack('H3') # => ["10e"]
+ "\x10\xef".unpack('H4') # => ["10ef"]
+ "\x10\xef".unpack('H5') # => ["10ef"]
+ ```
+
+- `'h'` - Hex string (low nibble first):
+
+ ```ruby
+ ['10ef'].pack('h*') # => "\x01\xFE"
+ ['10ef'].pack('h0') # => ""
+ ['10ef'].pack('h3') # => "\x01\x0E"
+ ['10ef'].pack('h5') # => "\x01\xFE\x00"
+ ```
+
+ ```ruby
+ ['fff'].pack('h3') # => "\xFF\x0F"
+ ['fff'].pack('h4') # => "\xFF\x0F"
+ ['fff'].pack('h5') # => "\xFF\x0F\x00"
+ ['fff'].pack('h6') # => "\xFF\x0F\x00"
+ ['fff'].pack('h7') # => "\xFF\x0F\x00\x00"
+ ['fff'].pack('h8') # => "\xFF\x0F\x00\x00"
+ ```
+
+ ```ruby
+ "\x01\xfe".unpack('h*') # => ["10ef"]
+ "\x01\xfe".unpack('h0') # => [""]
+ "\x01\xfe".unpack('h1') # => ["1"]
+ "\x01\xfe".unpack('h2') # => ["10"]
+ "\x01\xfe".unpack('h3') # => ["10e"]
+ "\x01\xfe".unpack('h4') # => ["10ef"]
+ "\x01\xfe".unpack('h5') # => ["10ef"]
+ ```
+
+### Pointer \String Directives
+
+- `'P'` - Pointer to a structure (fixed-length string):
+
+ ```ruby
+ s = ['abc'].pack('P') # => "\xE0O\x7F\xE5\xA1\x01\x00\x00"
+ s.unpack('P*') # => ["abc"]
+ ".".unpack("P") # => []
+ ("\0" * 8).unpack("P") # => [nil]
+ [nil].pack("P") # => "\x00\x00\x00\x00\x00\x00\x00\x00"
+ ```
+
+- `'p'` - Pointer to a null-terminated string:
+
+ ```ruby
+ s = ['abc'].pack('p') # => "(\xE4u\xE5\xA1\x01\x00\x00"
+ s.unpack('p*') # => ["abc"]
+ ".".unpack("p") # => []
+ ("\0" * 8).unpack("p") # => [nil]
+ [nil].pack("p") # => "\x00\x00\x00\x00\x00\x00\x00\x00"
+ ```
+
+### Other \String Directives
+
+- `'M'` - Quoted printable, MIME encoding;
+ text mode, but input must use LF and output LF;
+ (see [RFC 2045](https://www.ietf.org/rfc/rfc2045.txt)):
+
+ ```ruby
+ ["a b c\td \ne"].pack('M') # => "a b c\td =\n\ne=\n"
+ ["\0"].pack('M') # => "=00=\n"
+ ```
+
+ ```ruby
+ ["a"*1023].pack('M') == ("a"*73+"=\n")*14+"a=\n" # => true
+ ("a"*73+"=\na=\n").unpack('M') == ["a"*74] # => true
+ (("a"*73+"=\n")*14+"a=\n").unpack('M') == ["a"*1023] # => true
+ ```
+
+ ```ruby
+ "a b c\td =\n\ne=\n".unpack('M') # => ["a b c\td \ne"]
+ "=00=\n".unpack('M') # => ["\x00"]
+ ```
+
+ ```ruby
+ "pre=31=32=33after".unpack('M') # => ["pre123after"]
+ "pre=\nafter".unpack('M') # => ["preafter"]
+ "pre=\r\nafter".unpack('M') # => ["preafter"]
+ "pre=".unpack('M') # => ["pre="]
+ "pre=\r".unpack('M') # => ["pre=\r"]
+ "pre=hoge".unpack('M') # => ["pre=hoge"]
+ "pre==31after".unpack('M') # => ["pre==31after"]
+ "pre===31after".unpack('M') # => ["pre===31after"]
+ ```
+
+- `'m'` - Base64 encoded string;
+ count specifies input bytes between each newline,
+ rounded down to nearest multiple of 3;
+ if count is zero, no newlines are added;
+ (see [RFC 4648](https://www.ietf.org/rfc/rfc4648.txt)):
+
+ ```ruby
+ [""].pack('m') # => ""
+ ["\0"].pack('m') # => "AA==\n"
+ ["\0\0"].pack('m') # => "AAA=\n"
+ ["\0\0\0"].pack('m') # => "AAAA\n"
+ ["\377"].pack('m') # => "/w==\n"
+ ["\377\377"].pack('m') # => "//8=\n"
+ ["\377\377\377"].pack('m') # => "////\n"
+ ```
+
+ ```ruby
+ "".unpack('m') # => [""]
+ "AA==\n".unpack('m') # => ["\x00"]
+ "AAA=\n".unpack('m') # => ["\x00\x00"]
+ "AAAA\n".unpack('m') # => ["\x00\x00\x00"]
+ "/w==\n".unpack('m') # => ["\xFF"]
+ "//8=\n".unpack('m') # => ["\xFF\xFF"]
+ "////\n".unpack('m') # => ["\xFF\xFF\xFF"]
+ "A\n".unpack('m') # => [""]
+ "AA\n".unpack('m') # => ["\x00"]
+ "AA=\n".unpack('m') # => ["\x00"]
+ "AAA\n".unpack('m') # => ["\x00\x00"]
+ ```
+
+ ```ruby
+ [""].pack('m0') # => ""
+ ["\0"].pack('m0') # => "AA=="
+ ["\0\0"].pack('m0') # => "AAA="
+ ["\0\0\0"].pack('m0') # => "AAAA"
+ ["\377"].pack('m0') # => "/w=="
+ ["\377\377"].pack('m0') # => "//8="
+ ["\377\377\377"].pack('m0') # => "////"
+ ```
+
+ ```ruby
+ "".unpack('m0') # => [""]
+ "AA==".unpack('m0') # => ["\x00"]
+ "AAA=".unpack('m0') # => ["\x00\x00"]
+ "AAAA".unpack('m0') # => ["\x00\x00\x00"]
+ "/w==".unpack('m0') # => ["\xFF"]
+ "//8=".unpack('m0') # => ["\xFF\xFF"]
+ "////".unpack('m0') # => ["\xFF\xFF\xFF"]
+ ```
+
+- `'u'` - UU-encoded string:
+
+ ```ruby
+ [""].pack("u") # => ""
+ ["a"].pack("u") # => "!80``\n"
+ ["aaa"].pack("u") # => "#86%A\n"
+ ```
+
+ ```ruby
+ "".unpack("u") # => [""]
+ "#86)C\n".unpack("u") # => ["abc"]
+ ```
+
+## Offset Directives
+
+- `'@'` - Begin packing at the given byte offset;
+ for packing, null fill or shrink if necessary:
+
+ ```ruby
+ [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 unpacking, cannot to move to outside the string:
+
+ ```ruby
+ "\x01\x00\x00\x02".unpack("C@3C") # => [1, 2]
+ "\x00".unpack("@1C") # => [nil]
+ "\x00".unpack("@2C") # Raises ArgumentError.
+ ```
+
+- `'X'` - For packing, shrink for the given byte offset:
+
+ ```ruby
+ [0, 1, 2].pack("CCXC") # => "\x00\x02"
+ [0, 1, 2].pack("CCX2C") # => "\x02"
+ ```
+
+ For unpacking; rewind unpacking position for the given byte offset:
+
+ ```ruby
+ "\x00\x02".unpack("CCXC") # => [0, 2, 2]
+ ```
+
+ Cannot to move to outside the string:
+
+ ```ruby
+ [0, 1, 2].pack("CCX3C") # Raises ArgumentError.
+ "\x00\x02".unpack("CX3C") # Raises ArgumentError.
+ ```
+
+- `'x'` - Begin packing at after the given byte offset;
+ for packing, null fill if necessary:
+
+ ```ruby
+ [].pack("x0") # => ""
+ [].pack("x") # => "\x00"
+ [].pack("x8") # => "\x00\x00\x00\x00\x00\x00\x00\x00"
+ ```
+
+ For unpacking, cannot to move to outside the string:
+
+ ```ruby
+ "\x00\x00\x02".unpack("CxC") # => [0, 2]
+ "\x00\x00\x02".unpack("x3C") # => [nil]
+ "\x00\x00\x02".unpack("x4C") # Raises ArgumentError
+ ```
+
+- `'^'` - Only for unpacking; the current position:
+
+ ```ruby
+ "foo\0\0\0".unpack("Z*^") # => ["foo", 4]
+ ```
diff --git a/doc/language/ractor.md b/doc/language/ractor.md
new file mode 100644
index 0000000000..1592656217
--- /dev/null
+++ b/doc/language/ractor.md
@@ -0,0 +1,797 @@
+# Ractor - Ruby's Actor-like concurrency abstraction
+
+Ractors are designed to provide parallel execution of Ruby code without thread-safety concerns.
+
+## Summary
+
+### Multiple Ractors in a ruby process
+
+You can create multiple Ractors which can run ruby code in parallel with each other.
+
+* `Ractor.new{ expr }` creates a new Ractor and `expr` can run in parallel with other ractors on a multi-core computer.
+* Ruby processes start with one ractor (called the *main ractor*).
+* If the main ractor terminates, all other ractors receive termination requests, similar to how threads behave.
+* Each Ractor contains one or more `Thread`s.
+ * Threads within the same ractor share a ractor-wide global lock (GVL in MRI terminology), so they can't run in parallel with each other (without releasing the GVL explicitly in C extensions). Threads in different ractors can run in parallel.
+ * The overhead of creating a ractor is slightly above the overhead of creating a thread.
+
+### Limited sharing between Ractors
+
+Ractors don't share all objects, unlike threads which can access any object other than objects stored in another thread's thread-locals.
+
+* Most objects are *unshareable objects*. Unshareable objects can only be used by the ractor that instantiated them, so you don't need to worry about thread-safety issues resulting from using the object concurrently across ractors.
+* Some objects are *shareable objects*. Here is an incomplete list to give you an idea:
+ * `i = 123`: All `Integer`s are shareable.
+ * `s = "str".freeze`: Frozen strings are shareable if they have no instance variables that refer to unshareable objects.
+ * `a = [1, [2], 3].freeze`: `a` is not a shareable object because `a` refers to the unshareable object `[2]` (this Array is not frozen).
+ * `h = {c: Object}.freeze`: `h` is shareable because `Symbol`s and `Class`es are shareable, and the Hash is frozen.
+ * Class/Module objects are always shareable, even if they refer to unshareable objects.
+ * Special shareable objects
+ * Ractor objects themselves are shareable.
+ * And more...
+
+### Communication between Ractors with `Ractor::Port`
+
+Ractors communicate with each other and synchronize their execution by exchanging messages. The `Ractor::Port` class provides this communication mechanism.
+
+```ruby
+port = Ractor::Port.new
+
+Ractor.new port do |port|
+ # Other ractors can send to the port
+ port << 42
+end
+
+port.receive # get a message from the port. Only the ractor that created the Port can receive from it.
+#=> 42
+```
+
+All Ractors have a default port, which `Ractor#send`, `Ractor.receive` (etc) will use.
+
+### Copy & Move semantics when sending objects
+
+To send unshareable objects to another ractor, objects are either copied or moved.
+
+* Copy: deep-copies the object to the other ractor. All unshareable objects will be `Kernel#clone`ed.
+* Move: moves membership to another ractor.
+ * The sending ractor can not access the moved object after it moves.
+ * There is a guarantee that only one ractor can access an unshareable object at once.
+
+### Thread-safety
+
+Ractors help to write thread-safe, concurrent programs. They allow sharing of data only through explicit message passing for
+unshareable objects. Shareable objects are guaranteed to work correctly across ractors, even if the ractors are running in parallel.
+This guarantee, however, only applies across ractors. You still need to use `Mutex`es and other thread-safety tools within a ractor if
+you're using multiple ruby `Thread`s.
+
+ * Most objects are unshareable. You can't create data-races across ractors due to the inability to use these objects across ractors.
+ * Shareable objects are protected by locks (or otherwise don't need to be) so they can be used by more than one ractor at once.
+
+## Creation and termination
+
+### `Ractor.new`
+
+* `Ractor.new { expr }` creates a Ractor.
+
+```ruby
+# Ractor.new with a block creates a new Ractor
+r = Ractor.new do
+ # This block can run in parallel with other ractors
+end
+
+# You can name a Ractor with a `name:` argument.
+r = Ractor.new name: 'my-first-ractor' do
+end
+
+r.name #=> 'my-first-ractor'
+```
+
+### Block isolation
+
+The Ractor executes `expr` in the given block.
+The given block will be isolated from its outer scope. To prevent sharing objects between ractors, outer variables, `self` and other information is isolated from the block.
+
+This isolation occurs at Ractor creation time (when `Ractor.new` is called). If the given block is not able to be isolated because of outer variables or `self`, an error will be raised.
+
+```ruby
+begin
+ a = true
+ r = Ractor.new do
+ a #=> Ractor::IsolationError because this block accesses outer variable `a`.
+ end
+ r.join # wait for ractor to finish
+rescue Ractor::IsolationError
+end
+```
+
+* The `self` of the given block is the `Ractor` object itself.
+
+```ruby
+r = Ractor.new do
+ p self.class #=> Ractor
+ self.object_id
+end
+r.value == self.object_id #=> false
+```
+
+Arguments passed to `Ractor.new()` become block parameters for the given block. However, Ruby does not pass the objects themselves, but sends them as messages (see below for details).
+
+```ruby
+r = Ractor.new 'ok' do |msg|
+ msg #=> 'ok'
+end
+r.value #=> 'ok'
+```
+
+```ruby
+# similar to the last example
+r = Ractor.new do
+ msg = Ractor.receive
+ msg
+end
+r.send 'ok'
+r.value #=> 'ok'
+```
+
+### The execution result of the given block
+
+The return value of the given block becomes an outgoing message (see below for details).
+
+```ruby
+r = Ractor.new do
+ 'ok'
+end
+r.value #=> `ok`
+```
+
+An error in the given block will be propagated to the consumer of the outgoing message.
+
+```ruby
+r = Ractor.new do
+ raise 'ok' # exception will be transferred to the consumer
+end
+
+begin
+ r.value
+rescue Ractor::RemoteError => e
+ e.cause.class #=> RuntimeError
+ e.cause.message #=> 'ok'
+ e.ractor #=> r
+end
+```
+
+## Communication between Ractors
+
+Communication between ractors is achieved by sending and receiving messages. There are two ways to communicate:
+
+* (1) Sending and receiving messages via `Ractor::Port`
+* (2) Using shareable container objects. For example, the Ractor::TVar gem ([ko1/ractor-tvar](https://github.com/ko1/ractor-tvar))
+
+Users can control program execution timing with (1), but should not control with (2) (only perform critical sections).
+
+For sending and receiving messages, these are the fundamental APIs:
+
+* send/receive via `Ractor::Port`.
+ * `Ractor::Port#send(obj)` (`Ractor::Port#<<(obj)` is an alias) sends a message to the port. Ports are connected to an infinite size incoming queue so sending will never block the caller.
+ * `Ractor::Port#receive` dequeues a message from its own incoming queue. If the incoming queue is empty, `Ractor::Port#receive` will block the execution of the current Thread until a message is sent.
+ * `Ractor#send` and `Ractor.receive` use ports (their default port) internally, so are conceptually similar to the above.
+* You can close a `Ractor::Port` by `Ractor::Port#close`. A port can only be closed by the ractor that created it.
+ * If a port is closed, you can't `send` to it. Doing so raises an exception.
+ * When a ractor is terminated, the ractor's ports are automatically closed.
+* You can wait for a ractor's termination and receive its return value with `Ractor#value`. This is similar to `Thread#value`.
+
+There are 3 ways to send an object as a message:
+
+1) Send a reference: sending a shareable object sends only a reference to the object (fast).
+
+2) Copy an object: sending an unshareable object through copying it deeply (can be slow). Note that you can not send an object this way 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 across ractors with a membership change. The sending Ractor can not access the moved object after moving it, otherwise an exception will be raised. Implementation note: `T_DATA` objects are not supported.
+
+You can choose between "Copy" and "Move" by the `move:` keyword, `Ractor#send(obj, move: true/false)`. The default is `false` ("Copy"). However, if the object is shareable it will automatically use `move`.
+
+### Wait for multiple Ractors with `Ractor.select`
+
+You can wait for messages on multiple ports at once.
+The return value of `Ractor.select()` is `[port, msg]` where `port` is a ready port and `msg` is the received message.
+
+To make it convenient, `Ractor.select` can also accept ractors. In this case, it waits for their termination.
+The return value of `Ractor.select()` is `[r, msg]` where `r` is a terminated Ractor and `msg` is the value of the ractor's block.
+
+Wait for a single ractor (same as `Ractor#value`):
+
+```ruby
+r1 = Ractor.new{'r1'}
+
+r, obj = Ractor.select(r1)
+r == r1 and obj == 'r1' #=> true
+```
+
+Wait for two ractors:
+
+```ruby
+r1 = Ractor.new{'r1'}
+r2 = Ractor.new{'r2'}
+rs = [r1, r2]
+values = []
+
+while rs.any?
+ r, obj = Ractor.select(*rs)
+ rs.delete(r)
+ values << obj
+end
+
+values.sort == ['r1', 'r2'] #=> true
+```
+
+NOTE: Using `Ractor.select()` on a very large number of ractors has the same issue as `select(2)` currently.
+
+### Closing ports
+
+* `Ractor::Port#close` closes the port (similar to `Queue#close`).
+ * `port.send(obj)` will raise an exception when the port is closed.
+ * When the queue connected to the port is empty and port is closed, `Ractor::Port#receive` raises an exception. If the queue is not empty, it dequeues an object without exceptions.
+* When a Ractor terminates, the ports are closed automatically.
+
+Example (try to get a result from closed ractor):
+
+```ruby
+r = Ractor.new do
+ 'finish'
+end
+r.join # success (wait for the termination)
+r.value # success (will return 'finish')
+
+# The ractor's termination value has already been given to another ractor
+Ractor.new r do |r|
+ r.value #=> Ractor::Error
+end.join
+```
+
+Example (try to send to closed port):
+
+```ruby
+r = Ractor.new do
+end
+
+r.join # wait for termination, closes default port
+
+begin
+ r.send(1)
+rescue Ractor::ClosedError
+ 'ok'
+end
+```
+
+### Send a message by copying
+
+`Ractor::Port#send(obj)` copies `obj` deeply if `obj` is an unshareable object.
+
+```ruby
+obj = 'str'.dup
+r = Ractor.new obj do |msg|
+ # return received msg's object_id
+ msg.object_id
+end
+
+obj.object_id == r.value #=> false
+```
+
+Some objects do not support copying, and raise an exception.
+
+```ruby
+obj = Thread.new{}
+begin
+ Ractor.new obj do |msg|
+ msg
+ end
+rescue TypeError => e
+ e.message #=> #<TypeError: allocator undefined for Thread>
+end
+```
+
+### Send a message by moving
+
+`Ractor::Port#send(obj, move: true)` moves `obj` to the destination Ractor.
+If the source ractor uses the moved object (for example, calls a method like `obj.foo()`), it will raise an error.
+
+```ruby
+r = Ractor.new do
+ obj = Ractor.receive
+ obj << ' world'
+end
+
+str = 'hello'.dup
+r.send str, move: true
+# str is now moved, and accessing str from this ractor is prohibited
+modified = r.value #=> 'hello world'
+
+
+begin
+ # Error because it uses moved str.
+ str << ' exception' # raise Ractor::MovedError
+rescue Ractor::MovedError
+ modified #=> 'hello world'
+end
+```
+
+Some objects do not support moving, and an exception will be raised.
+
+```ruby
+r = Ractor.new do
+ Ractor.receive
+end
+
+r.send(Thread.new{}, move: true) #=> allocator undefined for Thread (TypeError)
+```
+
+Once an object has been moved, the source object's class is changed to `Ractor::MovedObject`.
+
+### Shareable objects
+
+The following is an inexhaustive list of shareable objects:
+
+* `Integer`, `Float`, `Complex`, `Rational`
+* `Symbol`, frozen `String` objects that don't refer to unshareables, `true`, `false`, `nil`
+* `Regexp` objects, if they have no instance variables or their instance variables refer only to shareables
+* `Class` and `Module` objects
+* `Ractor` and other special objects which deal with synchronization
+
+To make objects shareable, `Ractor.make_shareable(obj)` is provided. It tries to make the object shareable by freezing `obj` and recursively traversing its references to freeze them all. This method accepts the `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. `Ractor.make_shareable(copy: false)` has no effect on an already shareable object. If the object cannot be made shareable, a `Ractor::Error` exception will be raised.
+
+## Language changes to limit sharing between Ractors
+
+To isolate unshareable objects across ractors, we introduced additional language semantics for multi-ractor Ruby programs.
+
+Note that when not using ractors, these additional semantics are not needed (100% compatible with Ruby 2).
+
+### Global variables
+
+Only the main Ractor can access global variables.
+
+```ruby
+$gv = 1
+r = Ractor.new do
+ $gv
+end
+
+begin
+ r.join
+rescue Ractor::RemoteError => e
+ e.cause.message #=> 'can not access global variables from non-main Ractors'
+end
+```
+
+Note that some special global variables, such as `$stdin`, `$stdout` and `$stderr` are local to each ractor. See [[Bug #17268]](https://bugs.ruby-lang.org/issues/17268) for more details.
+
+### Instance variables of shareable objects
+
+Instance variables of classes/modules can be accessed from non-main ractors only if their values are shareable objects.
+
+```ruby
+class C
+ @iv = 1
+end
+
+p Ractor.new do
+ class C
+ @iv
+ end
+end.value #=> 1
+```
+
+Otherwise, only the main Ractor can access instance variables of shareable objects.
+
+```ruby
+class C
+ @iv = [] # unshareable object
+end
+
+Ractor.new do
+ class C
+ begin
+ p @iv
+ rescue Ractor::IsolationError
+ p $!.message
+ #=> "can not get unshareable values from instance variables of classes/modules from non-main Ractors"
+ end
+
+ begin
+ @iv = 42
+ rescue Ractor::IsolationError
+ p $!.message
+ #=> "can not set instance variables of classes/modules by non-main Ractors"
+ end
+ end
+end.join
+```
+
+```ruby
+shared = Ractor.new{}
+shared.instance_variable_set(:@iv, 'str')
+
+r = Ractor.new shared do |shared|
+ p shared.instance_variable_get(:@iv)
+end
+
+begin
+ r.join
+rescue Ractor::RemoteError => e
+ e.cause.message #=> can not access instance variables of shareable objects from non-main Ractors (Ractor::IsolationError)
+end
+```
+
+### Class variables
+
+Only the main Ractor can access class variables.
+
+```ruby
+class C
+ @@cv = 'str'
+end
+
+r = Ractor.new do
+ class C
+ p @@cv
+ end
+end
+
+
+begin
+ r.join
+rescue => e
+ e.class #=> Ractor::IsolationError
+end
+```
+
+### Constants
+
+Only the main Ractor can read constants which refer to an unshareable object.
+
+```ruby
+class C
+ CONST = 'str'.dup
+end
+r = Ractor.new do
+ C::CONST
+end
+begin
+ r.join
+rescue => e
+ e.class #=> Ractor::IsolationError
+end
+```
+
+Only the main Ractor can define constants which refer to an unshareable object.
+
+```ruby
+class C
+end
+r = Ractor.new do
+ C::CONST = 'str'.dup
+end
+begin
+ r.join
+rescue => e
+ e.class #=> Ractor::IsolationError
+end
+```
+
+When creating/updating a library to support ractors, constants should only refer to shareable objects if they are to be used by non-main ractors.
+
+```ruby
+TABLE = {a: 'ko1', b: 'ko2', c: 'ko3'}
+```
+
+In this case, `TABLE` refers to an unshareable Hash object. In order for other ractors to use `TABLE`, we need to make it shareable. We can use `Ractor.make_shareable()` like so:
+
+```ruby
+TABLE = Ractor.make_shareable( {a: 'ko1', b: 'ko2', c: 'ko3'} )
+```
+
+To make it easy, Ruby 3.0 introduced a new `shareable_constant_value` file directive.
+
+```ruby
+# shareable_constant_value: literal
+
+TABLE = {a: 'ko1', b: 'ko2', c: 'ko3'}
+#=> Same as: TABLE = Ractor.make_shareable( {a: 'ko1', b: 'ko2', c: 'ko3'} )
+```
+
+The `shareable_constant_value` directive accepts the following modes (descriptions use the example: `CONST = expr`):
+
+* 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)}`.
+* experimental_everything: replaced to `CONST = Ractor.make_shareable(expr)`.
+* experimental_copy: replaced to `CONST = Ractor.make_shareable(expr, copy: true)`.
+
+Except for the `none` mode (default), it is guaranteed that these constants refer only to shareable objects.
+
+See [syntax/comments.rdoc](../syntax/comments.rdoc) for more details.
+
+### Shareable procs
+
+Procs and lambdas are unshareable objects, even when they are frozen. To create an unshareable Proc, you must use `Ractor.shareable_proc { expr }`. Much like during Ractor creation, the proc's block is isolated from its outer environment, so it cannot access variables from the outside scope. `self` is also changed within the Proc to be `nil` by default, although a `self:` keyword can be provided if you want to customize the value to a different shareable object.
+
+```ruby
+p = Ractor.shareable_proc { p self }
+p.call #=> nil
+```
+
+```ruby
+begin
+ a = 1
+ pr = Ractor.shareable_proc { p a }
+ pr.call # never gets here
+rescue Ractor::IsolationError
+end
+```
+
+In order to dynamically define a method with `Module#define_method` that can be used from different ractors, you must define it with a shareable proc. Alternatively, you can use `Module#class_eval` or `Module#module_eval` with a String. Even though the shareable proc's `self` is initially bound to `nil`, `define_method` will bind `self` to the correct value in the method.
+
+```ruby
+class A
+ define_method :testing, &Ractor.shareable_proc do
+ p self
+ end
+end
+Ractor.new do
+ a = A.new
+ a.testing #=> #<A:0x0000000101acfe10>
+end.join
+```
+
+This isolation must be done to prevent the method from accessing and assigning captured outer variables across ractors.
+
+### Ractor-local storage
+
+You can store any object (even unshareables) in ractor-local storage.
+
+```ruby
+r = Ractor.new do
+ values = []
+ Ractor[:threads] = []
+ 3.times do |i|
+ Ractor[:threads] << Thread.new do
+ values << [Ractor.receive, i+1] # Ractor.receive blocks the current thread in the current ractor until it receives a message
+ end
+ end
+ Ractor[:threads].each(&:join)
+ values
+end
+
+r << 1
+r << 2
+r << 3
+r.value #=> [[1,1],[2,2],[3,3]] (the order can change with each run)
+```
+
+## Examples
+
+### Traditional Ring example in Actor-model
+
+```ruby
+RN = 1_000
+CR = Ractor.current
+
+r = Ractor.new do
+ p Ractor.receive
+ CR << :fin
+end
+
+RN.times{
+ r = Ractor.new r do |next_r|
+ next_r << Ractor.receive
+ end
+}
+
+p :setup_ok
+r << 1
+p Ractor.receive
+```
+
+### Fork-join
+
+```ruby
+def fib n
+ if n < 2
+ 1
+ else
+ fib(n-2) + fib(n-1)
+ end
+end
+
+RN = 10
+rs = (1..RN).map do |i|
+ Ractor.new i do |i|
+ [i, fib(i)]
+ end
+end
+
+until rs.empty?
+ r, v = Ractor.select(*rs)
+ rs.delete r
+ p answer: v
+end
+```
+
+### Worker pool
+
+(1) One ractor has a pool
+
+```ruby
+require 'prime'
+
+N = 1000
+RN = 10
+
+# make RN workers
+workers = (1..RN).map do
+ Ractor.new do |; result_port|
+ loop do
+ n, result_port = Ractor.receive
+ result_port << [n, n.prime?, Ractor.current]
+ end
+ end
+end
+
+result_port = Ractor::Port.new
+results = []
+
+(1..N).each do |i|
+ if workers.empty?
+ # receive a result
+ n, result, w = result_port.receive
+ results << [n, result]
+ else
+ w = workers.pop
+ end
+
+ # send a task to the idle worker ractor
+ w << [i, result_port]
+end
+
+# receive a result
+while results.size != N
+ n, result, _w = result_port.receive
+ results << [n, result]
+end
+
+pp results.sort_by{|n, result| n}
+```
+
+### Pipeline
+
+```ruby
+# pipeline with send/receive
+
+r3 = Ractor.new Ractor.current do |cr|
+ cr.send Ractor.receive + 'r3'
+end
+
+r2 = Ractor.new r3 do |r3|
+ r3.send Ractor.receive + 'r2'
+end
+
+r1 = Ractor.new r2 do |r2|
+ r2.send Ractor.receive + 'r1'
+end
+
+r1 << 'r0'
+p Ractor.receive #=> "r0r1r2r3"
+```
+
+### Supervise
+
+```ruby
+# ring example again
+
+r = Ractor.current
+(1..10).map{|i|
+ r = Ractor.new r, i do |r, i|
+ r.send Ractor.receive + "r#{i}"
+ end
+}
+
+r.send "r0"
+p Ractor.receive #=> "r0r10r9r8r7r6r5r4r3r2r1"
+```
+
+```ruby
+# ring example with an error
+
+r = Ractor.current
+rs = (1..10).map{|i|
+ r = Ractor.new r, i do |r, i|
+ loop do
+ msg = Ractor.receive
+ raise if /e/ =~ msg
+ r.send msg + "r#{i}"
+ end
+ end
+}
+
+r.send "r0"
+p Ractor.receive #=> "r0r10r9r8r7r6r5r4r3r2r1"
+r.send "r0"
+p Ractor.select(*rs, Ractor.current) #=> [:receive, "r0r10r9r8r7r6r5r4r3r2r1"]
+r.send "e0"
+p Ractor.select(*rs, Ractor.current)
+#=>
+# <Thread:0x000056262de28bd8 run> terminated with exception (report_on_exception is true):
+# Traceback (most recent call last):
+# 2: from /home/ko1/src/ruby/trunk/test.rb:7:in `block (2 levels) in <main>'
+# 1: from /home/ko1/src/ruby/trunk/test.rb:7:in `loop'
+# /home/ko1/src/ruby/trunk/test.rb:9:in `block (3 levels) in <main>': unhandled exception
+# Traceback (most recent call last):
+# 2: from /home/ko1/src/ruby/trunk/test.rb:7:in `block (2 levels) in <main>'
+# 1: from /home/ko1/src/ruby/trunk/test.rb:7:in `loop'
+# /home/ko1/src/ruby/trunk/test.rb:9:in `block (3 levels) in <main>': unhandled exception
+# 1: from /home/ko1/src/ruby/trunk/test.rb:21:in `<main>'
+# <internal:ractor>:69:in `select': thrown by remote Ractor. (Ractor::RemoteError)
+```
+
+```ruby
+# resend non-error message
+
+r = Ractor.current
+rs = (1..10).map{|i|
+ r = Ractor.new r, i do |r, i|
+ loop do
+ msg = Ractor.receive
+ raise if /e/ =~ msg
+ r.send msg + "r#{i}"
+ end
+ end
+}
+
+r.send "r0"
+p Ractor.receive #=> "r0r10r9r8r7r6r5r4r3r2r1"
+r.send "r0"
+p Ractor.select(*rs, Ractor.current)
+[:receive, "r0r10r9r8r7r6r5r4r3r2r1"]
+msg = 'e0'
+begin
+ r.send msg
+ p Ractor.select(*rs, Ractor.current)
+rescue Ractor::RemoteError
+ msg = 'r0'
+ retry
+end
+
+#=> <internal:ractor>:100:in `send': The incoming-port is already closed (Ractor::ClosedError)
+# because r == r[-1] is terminated.
+```
+
+```ruby
+# ring example with supervisor and re-start
+
+def make_ractor r, i
+ Ractor.new r, i do |r, i|
+ loop do
+ msg = Ractor.receive
+ raise if /e/ =~ msg
+ r.send msg + "r#{i}"
+ end
+ end
+end
+
+r = Ractor.current
+rs = (1..10).map{|i|
+ r = make_ractor(r, i)
+}
+
+msg = 'e0' # error causing message
+begin
+ r.send msg
+ p Ractor.select(*rs, Ractor.current)
+rescue Ractor::RemoteError
+ r = rs[-1] = make_ractor(rs[-2], rs.size-1)
+ msg = 'x0'
+ retry
+end
+
+#=> [:receive, "x0r9r9r8r7r6r5r4r3r2r1"]
+```
diff --git a/doc/regexp/methods.rdoc b/doc/language/regexp/methods.rdoc
index 356156ac9a..356156ac9a 100644
--- a/doc/regexp/methods.rdoc
+++ b/doc/language/regexp/methods.rdoc
diff --git a/doc/language/regexp/unicode_properties.rdoc b/doc/language/regexp/unicode_properties.rdoc
new file mode 100644
index 0000000000..94080f7199
--- /dev/null
+++ b/doc/language/regexp/unicode_properties.rdoc
@@ -0,0 +1,718 @@
+== \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{IDS_Unary_Operator}</tt>, <tt>\p{IDSU}</tt>
+- <tt>\p{ID_Compat_Math_Continue}</tt>
+- <tt>\p{ID_Compat_Math_Start}</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{Modifier_Combining_Mark}</tt>, <tt>\p{MCM}</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{InCB_Consonant}</tt>
+- <tt>\p{InCB_Extend}</tt>
+- <tt>\p{InCB_Linker}</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{Beria_Erfe}</tt>, <tt>\p{Berf}</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{Garay}</tt>, <tt>\p{Gara}</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{Gurung_Khema}</tt>, <tt>\p{Gukh}</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{Kirat_Rai}</tt>, <tt>\p{Krai}</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{Ol_Onal}</tt>, <tt>\p{Onao}</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{Sidetic}</tt>, <tt>\p{Sidt}</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{Sunuwar}</tt>, <tt>\p{Sunu}</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{Tai_Yo}</tt>, <tt>\p{Tayo}</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{Todhri}</tt>, <tt>\p{Todr}</tt>
+- <tt>\p{Tolong_Siki}</tt>, <tt>\p{Tols}</tt>
+- <tt>\p{Toto}</tt>
+- <tt>\p{Tulu_Tigalari}</tt>, <tt>\p{Tutg}</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_Beria_Erfe}</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_CJK_Unified_Ideographs_Extension_I}</tt>
+- <tt>\p{In_CJK_Unified_Ideographs_Extension_J}</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_Egyptian_Hieroglyphs_Extended_A}</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_Garay}</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_Gurung_Khema}</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_Kirat_Rai}</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_Supplement}</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_Myanmar_Extended_C}</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_Ol_Onal}</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_Sharada_Supplement}</tt>
+- <tt>\p{In_Shavian}</tt>
+- <tt>\p{In_Shorthand_Format_Controls}</tt>
+- <tt>\p{In_Siddham}</tt>
+- <tt>\p{In_Sidetic}</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_Sunuwar}</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_Symbols_for_Legacy_Computing_Supplement}</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_Tai_Yo}</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_Components_Supplement}</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_Todhri}</tt>
+- <tt>\p{In_Tolong_Siki}</tt>
+- <tt>\p{In_Toto}</tt>
+- <tt>\p{In_Transport_and_Map_Symbols}</tt>
+- <tt>\p{In_Tulu_Tigalari}</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_15_1}</tt>
+- <tt>\p{Age_16_0}</tt>
+- <tt>\p{Age_17_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/language/signals.rdoc b/doc/language/signals.rdoc
new file mode 100644
index 0000000000..a82dab81c6
--- /dev/null
+++ b/doc/language/signals.rdoc
@@ -0,0 +1,106 @@
+= Caveats for implementing Signal.trap callbacks
+
+As with implementing signal handlers in C or most other languages,
+all code passed to Signal.trap must be reentrant. If you are not
+familiar with reentrancy, you need to read up on it at
+{Wikipedia}[https://en.wikipedia.org/wiki/Reentrancy_(computing)] or
+elsewhere before reading the rest of this document.
+
+Most importantly, "thread-safety" does not guarantee reentrancy;
+and methods such as Mutex#lock and Mutex#synchronize which are
+commonly used for thread-safety even prevent reentrancy.
+
+== An implementation detail of the Ruby VM
+
+The Ruby VM defers Signal.trap callbacks from running until it is safe
+for its internal data structures, but it does not know when it is safe
+for data structures in YOUR code. Ruby implements deferred signal
+handling by registering short C functions with only
+{async-signal-safe functions}[http://man7.org/linux/man-pages/man7/signal-safety.7.html] as
+signal handlers. These short C functions only do enough to tell the VM to
+run callbacks registered via Signal.trap later in the main Ruby Thread.
+
+== Unsafe methods to call in Signal.trap blocks
+
+When in doubt, consider anything not listed as safe below as being
+unsafe.
+
+* Mutex#lock, Mutex#synchronize and any code using them are explicitly
+ unsafe. This includes Monitor in the standard library which uses
+ Mutex to provide reentrancy.
+
+* Dir.chdir with block
+
+* any IO write operations when IO#sync is false;
+ including IO#write, IO#write_nonblock, IO#puts.
+ Pipes and sockets default to `IO#sync = true', so it is safe to
+ write to them unless IO#sync was disabled.
+
+* File#flock, as the underlying flock(2) call is not specified by POSIX
+
+== Commonly safe operations inside Signal.trap blocks
+
+* Assignment and retrieval of local, instance, and class variables
+
+* Most object allocations and initializations of common types
+ including Array, Hash, String, Struct, Time.
+
+* Common Array, Hash, String, Struct operations which do not execute a block
+ are generally safe; but beware if iteration is occurring elsewhere.
+
+* Hash#[], Hash#[]= (unless Hash.new was given an unsafe block)
+
+* Thread::Queue#push and Thread::SizedQueue#push (since Ruby 2.1)
+
+* Creating a new Thread via Thread.new/Thread.start can used to get
+ around the unusability of Mutexes inside a signal handler
+
+* Signal.trap is safe to use inside blocks passed to Signal.trap
+
+* arithmetic on Integer and Float (`+', `-', '%', '*', '/')
+
+ Additionally, signal handlers do not run between two successive
+ local variable accesses, so shortcuts such as `+=' and `-=' will
+ not trigger a data race when used on Integer and Float classes in
+ signal handlers.
+
+== System call wrapper methods which are safe inside Signal.trap
+
+Since Ruby has wrappers around many
+{async-signal-safe C functions}[http://man7.org/linux/man-pages/man7/signal-safety.7.html]
+the corresponding wrappers for many IO, File, Dir, and Socket methods
+are safe.
+
+(Incomplete list)
+
+* Dir.chdir (without block arg)
+* Dir.mkdir
+* Dir.open
+* File#truncate
+* File.link
+* File.open
+* File.readlink
+* File.rename
+* File.stat
+* File.symlink
+* File.truncate
+* File.unlink
+* File.utime
+* IO#close
+* IO#dup
+* IO#fsync
+* IO#read
+* IO#read_nonblock
+* IO#stat
+* IO#sysread
+* IO#syswrite
+* IO.select
+* IO.pipe
+* Process.clock_gettime
+* Process.exit!
+* Process.fork
+* Process.kill
+* Process.pid
+* Process.ppid
+* Process.waitpid
+...
diff --git a/doc/language/strftime_formatting.rdoc b/doc/language/strftime_formatting.rdoc
new file mode 100644
index 0000000000..2bfa6b975e
--- /dev/null
+++ b/doc/language/strftime_formatting.rdoc
@@ -0,0 +1,525 @@
+= 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:
+
+- Date#strftime.
+- DateTime#strftime.
+- Time#strftime.
+
+Each of these methods takes optional argument +format+,
+which has zero or more embedded _format_ _specifications_ (see below).
+
+Each of these methods returns the string resulting from replacing each
+format specification embedded in +format+ with a string form
+of one or more parts of the date or time.
+
+A simple example:
+
+ Time.now.strftime('%H:%M:%S') # => "14:02:07"
+
+A format specification has the form:
+
+ %[flags][width]conversion
+
+It consists of:
+
+- A leading percent character.
+- Zero or more _flags_ (each is a character).
+- An optional _width_ _specifier_ (an integer).
+- A _conversion_ _specifier_ (a character).
+
+Except for the leading percent character,
+the only required part is the conversion specifier, so we begin with that.
+
+== Conversion Specifiers
+
+=== \Date (Year, Month, Day)
+
+- <tt>%Y</tt> - Year including century, zero-padded:
+
+ Time.now.strftime('%Y') # => "2022"
+ Time.new(-1000).strftime('%Y') # => "-1000" # Before common era.
+ Time.new(10000).strftime('%Y') # => "10000" # Far future.
+ Time.new(10).strftime('%Y') # => "0010" # Zero-padded by default.
+
+- <tt>%y</tt> - Year without century, in range (0.99), zero-padded:
+
+ Time.now.strftime('%y') # => "22"
+ Time.new(1).strftime('%y') # => "01" # Zero-padded by default.
+
+- <tt>%C</tt> - Century, zero-padded:
+
+ Time.now.strftime('%C') # => "20"
+ Time.new(-1000).strftime('%C') # => "-10" # Before common era.
+ Time.new(10000).strftime('%C') # => "100" # Far future.
+ Time.new(100).strftime('%C') # => "01" # Zero-padded by default.
+
+- <tt>%m</tt> - Month of the year, in range (1..12), zero-padded:
+
+ Time.new(2022, 1).strftime('%m') # => "01" # Zero-padded by default.
+ Time.new(2022, 12).strftime('%m') # => "12"
+
+- <tt>%B</tt> - Full month name, capitalized:
+
+ Time.new(2022, 1).strftime('%B') # => "January"
+ Time.new(2022, 12).strftime('%B') # => "December"
+
+- <tt>%b</tt> - Abbreviated month name, capitalized:
+
+ Time.new(2022, 1).strftime('%b') # => "Jan"
+ Time.new(2022, 12).strftime('%h') # => "Dec"
+
+- <tt>%h</tt> - Same as <tt>%b</tt>.
+
+- <tt>%d</tt> - Day of the month, in range (1..31), zero-padded:
+
+ Time.new(2002, 1, 1).strftime('%d') # => "01"
+ Time.new(2002, 1, 31).strftime('%d') # => "31"
+
+- <tt>%e</tt> - Day of the month, in range (1..31), blank-padded:
+
+ Time.new(2002, 1, 1).strftime('%e') # => " 1"
+ Time.new(2002, 1, 31).strftime('%e') # => "31"
+
+- <tt>%j</tt> - Day of the year, in range (1..366), zero-padded:
+
+ Time.new(2002, 1, 1).strftime('%j') # => "001"
+ Time.new(2002, 12, 31).strftime('%j') # => "365"
+
+=== \Time (Hour, Minute, Second, Subsecond)
+
+- <tt>%H</tt> - Hour of the day, in range (0..23), zero-padded:
+
+ Time.new(2022, 1, 1, 1).strftime('%H') # => "01"
+ Time.new(2022, 1, 1, 13).strftime('%H') # => "13"
+
+- <tt>%k</tt> - Hour of the day, in range (0..23), blank-padded:
+
+ Time.new(2022, 1, 1, 1).strftime('%k') # => " 1"
+ Time.new(2022, 1, 1, 13).strftime('%k') # => "13"
+
+- <tt>%I</tt> - Hour of the day, in range (1..12), zero-padded:
+
+ Time.new(2022, 1, 1, 1).strftime('%I') # => "01"
+ Time.new(2022, 1, 1, 13).strftime('%I') # => "01"
+
+- <tt>%l</tt> - Hour of the day, in range (1..12), blank-padded:
+
+ Time.new(2022, 1, 1, 1).strftime('%l') # => " 1"
+ Time.new(2022, 1, 1, 13).strftime('%l') # => " 1"
+
+- <tt>%P</tt> - Meridian indicator, lowercase:
+
+ Time.new(2022, 1, 1, 1).strftime('%P') # => "am"
+ Time.new(2022, 1, 1, 13).strftime('%P') # => "pm"
+
+- <tt>%p</tt> - Meridian indicator, uppercase:
+
+ Time.new(2022, 1, 1, 1).strftime('%p') # => "AM"
+ Time.new(2022, 1, 1, 13).strftime('%p') # => "PM"
+
+- <tt>%M</tt> - Minute of the hour, in range (0..59), zero-padded:
+
+ Time.new(2022, 1, 1, 1, 0, 0).strftime('%M') # => "00"
+
+- <tt>%S</tt> - Second of the minute in range (0..59), zero-padded:
+
+ Time.new(2022, 1, 1, 1, 0, 0, 0).strftime('%S') # => "00"
+
+- <tt>%L</tt> - Millisecond of the second, in range (0..999), zero-padded:
+
+ Time.new(2022, 1, 1, 1, 0, 0, 0).strftime('%L') # => "000"
+
+- <tt>%N</tt> - Fractional seconds, default width is 9 digits (nanoseconds):
+
+ t = Time.now # => 2022-06-29 07:10:20.3230914 -0500
+ t.strftime('%N') # => "323091400" # Default.
+
+ Use {width specifiers}[rdoc-ref:@Width+Specifiers]
+ to adjust units:
+
+ t.strftime('%3N') # => "323" # Milliseconds.
+ t.strftime('%6N') # => "323091" # Microseconds.
+ t.strftime('%9N') # => "323091400" # Nanoseconds.
+ t.strftime('%12N') # => "323091400000" # Picoseconds.
+ t.strftime('%15N') # => "323091400000000" # Femptoseconds.
+ t.strftime('%18N') # => "323091400000000000" # Attoseconds.
+ t.strftime('%21N') # => "323091400000000000000" # Zeptoseconds.
+ t.strftime('%24N') # => "323091400000000000000000" # Yoctoseconds.
+
+- <tt>%s</tt> - Number of seconds since the epoch:
+
+ Time.now.strftime('%s') # => "1656505136"
+
+=== Timezone
+
+- <tt>%z</tt> - Timezone as hour and minute offset from UTC:
+
+ Time.now.strftime('%z') # => "-0500"
+
+- <tt>%Z</tt> - Timezone name (platform-dependent):
+
+ Time.now.strftime('%Z') # => "Central Daylight Time"
+
+=== Weekday
+
+- <tt>%A</tt> - Full weekday name:
+
+ Time.now.strftime('%A') # => "Wednesday"
+
+- <tt>%a</tt> - Abbreviated weekday name:
+
+ Time.now.strftime('%a') # => "Wed"
+
+- <tt>%u</tt> - Day of the week, in range (1..7), Monday is 1:
+
+ t = Time.new(2022, 6, 26) # => 2022-06-26 00:00:00 -0500
+ t.strftime('%a') # => "Sun"
+ t.strftime('%u') # => "7"
+
+- <tt>%w</tt> - Day of the week, in range (0..6), Sunday is 0:
+
+ t = Time.new(2022, 6, 26) # => 2022-06-26 00:00:00 -0500
+ t.strftime('%a') # => "Sun"
+ t.strftime('%w') # => "0"
+
+=== Week Number
+
+- <tt>%U</tt> - Week number of the year, in range (0..53), zero-padded,
+ where each week begins on a Sunday:
+
+ t = Time.new(2022, 6, 26) # => 2022-06-26 00:00:00 -0500
+ t.strftime('%a') # => "Sun"
+ t.strftime('%U') # => "26"
+
+- <tt>%W</tt> - Week number of the year, in range (0..53), zero-padded,
+ where each week begins on a Monday:
+
+ t = Time.new(2022, 6, 26) # => 2022-06-26 00:00:00 -0500
+ t.strftime('%a') # => "Sun"
+ t.strftime('%W') # => "25"
+
+=== Week Dates
+
+See {ISO 8601 week dates}[https://en.wikipedia.org/wiki/ISO_8601#Week_dates].
+
+ t0 = Time.new(2023, 1, 1) # => 2023-01-01 00:00:00 -0600
+ t1 = Time.new(2024, 1, 1) # => 2024-01-01 00:00:00 -0600
+
+- <tt>%G</tt> - Week-based year:
+
+ t0.strftime('%G') # => "2022"
+ t1.strftime('%G') # => "2024"
+
+- <tt>%g</tt> - Week-based year without century, in range (0..99), zero-padded:
+
+ t0.strftime('%g') # => "22"
+ t1.strftime('%g') # => "24"
+
+- <tt>%V</tt> - Week number of the week-based year, in range (1..53),
+ zero-padded:
+
+ t0.strftime('%V') # => "52"
+ t1.strftime('%V') # => "01"
+
+=== Literals
+
+- <tt>%n</tt> - Newline character "\n":
+
+ Time.now.strftime('%n') # => "\n"
+
+- <tt>%t</tt> - Tab character "\t":
+
+ Time.now.strftime('%t') # => "\t"
+
+- <tt>%%</tt> - Percent character '%':
+
+ Time.now.strftime('%%') # => "%"
+
+=== Shorthand Conversion Specifiers
+
+Each shorthand specifier here is shown with its corresponding
+longhand specifier.
+
+- <tt>%c</tt> - \Date and time:
+
+ Time.now.strftime('%c') # => "Wed Jun 29 08:01:41 2022"
+ Time.now.strftime('%a %b %e %T %Y') # => "Wed Jun 29 08:02:07 2022"
+
+- <tt>%D</tt> - \Date:
+
+ Time.now.strftime('%D') # => "06/29/22"
+ Time.now.strftime('%m/%d/%y') # => "06/29/22"
+
+- <tt>%F</tt> - ISO 8601 date:
+
+ Time.now.strftime('%F') # => "2022-06-29"
+ Time.now.strftime('%Y-%m-%d') # => "2022-06-29"
+
+- <tt>%v</tt> - VMS date:
+
+ Time.now.strftime('%v') # => "29-JUN-2022"
+ Time.now.strftime('%e-%^b-%4Y') # => "29-JUN-2022"
+
+- <tt>%x</tt> - Same as <tt>%D</tt>.
+
+- <tt>%X</tt> - Same as <tt>%T</tt>.
+
+- <tt>%r</tt> - 12-hour time:
+
+ Time.new(2022, 1, 1, 1).strftime('%r') # => "01:00:00 AM"
+ Time.new(2022, 1, 1, 1).strftime('%I:%M:%S %p') # => "01:00:00 AM"
+ Time.new(2022, 1, 1, 13).strftime('%r') # => "01:00:00 PM"
+ Time.new(2022, 1, 1, 13).strftime('%I:%M:%S %p') # => "01:00:00 PM"
+
+- <tt>%R</tt> - 24-hour time:
+
+ Time.new(2022, 1, 1, 1).strftime('%R') # => "01:00"
+ Time.new(2022, 1, 1, 1).strftime('%H:%M') # => "01:00"
+ Time.new(2022, 1, 1, 13).strftime('%R') # => "13:00"
+ Time.new(2022, 1, 1, 13).strftime('%H:%M') # => "13:00"
+
+- <tt>%T</tt> - 24-hour time:
+
+ Time.new(2022, 1, 1, 1).strftime('%T') # => "01:00:00"
+ Time.new(2022, 1, 1, 1).strftime('%H:%M:%S') # => "01:00:00"
+ Time.new(2022, 1, 1, 13).strftime('%T') # => "13:00:00"
+ Time.new(2022, 1, 1, 13).strftime('%H:%M:%S') # => "13:00:00"
+
+- <tt>%+</tt> (not supported in Time#strftime) - \Date and time:
+
+ DateTime.now.strftime('%+')
+ # => "Wed Jun 29 08:31:53 -05:00 2022"
+ DateTime.now.strftime('%a %b %e %H:%M:%S %Z %Y')
+ # => "Wed Jun 29 08:32:18 -05:00 2022"
+
+== Flags
+
+Flags may affect certain formatting specifications.
+
+Multiple flags may be given with a single conversion specified;
+order does not matter.
+
+=== Padding Flags
+
+- <tt>0</tt> - Pad with zeroes:
+
+ Time.new(10).strftime('%0Y') # => "0010"
+
+- <tt>_</tt> - Pad with blanks:
+
+ Time.new(10).strftime('%_Y') # => " 10"
+
+- <tt>-</tt> - Don't pad:
+
+ Time.new(10).strftime('%-Y') # => "10"
+
+=== Casing Flags
+
+- <tt>^</tt> - Upcase result:
+
+ Time.new(2022, 1).strftime('%B') # => "January" # No casing flag.
+ Time.new(2022, 1).strftime('%^B') # => "JANUARY"
+
+- <tt>#</tt> - Swapcase result:
+
+ Time.now.strftime('%p') # => "AM"
+ Time.now.strftime('%^p') # => "AM"
+ Time.now.strftime('%#p') # => "am"
+
+=== Timezone Flags
+
+- <tt>:</tt> - Put timezone as colon-separated hours and minutes:
+
+ Time.now.strftime('%:z') # => "-05:00"
+
+- <tt>::</tt> - Put timezone as colon-separated hours, minutes, and seconds:
+
+ Time.now.strftime('%::z') # => "-05:00:00"
+
+== Width Specifiers
+
+The integer width specifier gives a minimum width for the returned string:
+
+ Time.new(2002).strftime('%Y') # => "2002" # No width specifier.
+ Time.new(2002).strftime('%10Y') # => "0000002002"
+ Time.new(2002, 12).strftime('%B') # => "December" # No width specifier.
+ Time.new(2002, 12).strftime('%10B') # => " December"
+ Time.new(2002, 12).strftime('%3B') # => "December" # Ignored if too small.
+
+= Specialized Format Strings
+
+Here are a few specialized format strings,
+each based on an external standard.
+
+== HTTP Format
+
+The HTTP date format is based on
+{RFC 2616}[https://www.rfc-editor.org/rfc/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>
+ # Return HTTP-formatted string.
+ httpdate = d.httpdate # => "Sat, 03 Feb 2001 00:00:00 GMT"
+ # Return new date parsed from HTTP-formatted string.
+ Date.httpdate(httpdate) # => #<Date: 2001-02-03>
+ # Return hash parsed from HTTP-formatted string.
+ Date._httpdate(httpdate)
+ # => {:wday=>6, :mday=>3, :mon=>2, :year=>2001, :hour=>0, :min=>0, :sec=>0, :zone=>"GMT", :offset=>0}
+
+== RFC 3339 Format
+
+The RFC 3339 date format is based on
+{RFC 3339}[https://www.rfc-editor.org/rfc/rfc3339]:
+
+ d = Date.new(2001, 2, 3) # => #<Date: 2001-02-03>
+ # Return 3339-formatted string.
+ rfc3339 = d.rfc3339 # => "2001-02-03T00:00:00+00:00"
+ # Return new date parsed from 3339-formatted string.
+ Date.rfc3339(rfc3339) # => #<Date: 2001-02-03>
+ # Return hash parsed from 3339-formatted string.
+ Date._rfc3339(rfc3339)
+ # => {:year=>2001, :mon=>2, :mday=>3, :hour=>0, :min=>0, :sec=>0, :zone=>"+00:00", :offset=>0}
+
+== RFC 2822 Format
+
+The RFC 2822 date format is based on
+{RFC 2822}[https://www.rfc-editor.org/rfc/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>
+ # Return 2822-formatted string.
+ rfc2822 = d.rfc2822 # => "Sat, 3 Feb 2001 00:00:00 +0000"
+ # Return new date parsed from 2822-formatted string.
+ Date.rfc2822(rfc2822) # => #<Date: 2001-02-03>
+ # Return hash parsed from 2822-formatted string.
+ 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
+
+The JIS X 0301 format includes the
+{Japanese era name}[https://en.wikipedia.org/wiki/Japanese_era_name],
+and treats dates in the format <tt>'%Y-%m-%d'</tt>
+with the first letter of the romanized era name prefixed:
+
+ d = Date.new(2001, 2, 3) # => #<Date: 2001-02-03>
+ # Return 0301-formatted string.
+ jisx0301 = d.jisx0301 # => "H13.02.03"
+ # Return new date parsed from 0301-formatted string.
+ Date.jisx0301(jisx0301) # => #<Date: 2001-02-03>
+ # Return hash parsed from 0301-formatted string.
+ Date._jisx0301(jisx0301) # => {:year=>2001, :mon=>2, :mday=>3}
+
+== ISO 8601 Format Specifications
+
+This section shows format specifications that are compatible with
+{ISO 8601}[https://en.wikipedia.org/wiki/ISO_8601].
+Details for various formats may be seen at the links.
+
+Examples in this section assume:
+
+ t = Time.now # => 2022-06-29 16:49:25.465246 -0500
+
+=== Dates
+
+See {ISO 8601 dates}[https://en.wikipedia.org/wiki/ISO_8601#Dates].
+
+- {Years}[https://en.wikipedia.org/wiki/ISO_8601#Years]:
+
+ - Basic year (+YYYY+):
+
+ t.strftime('%Y') # => "2022"
+
+ - Expanded year (<tt>±YYYYY</tt>):
+
+ t.strftime('+%5Y') # => "+02022"
+ t.strftime('-%5Y') # => "-02022"
+
+- {Calendar dates}[https://en.wikipedia.org/wiki/ISO_8601#Calendar_dates]:
+
+ - Basic date (+YYYYMMDD+):
+
+ t.strftime('%Y%m%d') # => "20220629"
+
+ - Extended date (<tt>YYYY-MM-DD</tt>):
+
+ t.strftime('%Y-%m-%d') # => "2022-06-29"
+
+ - Reduced extended date (<tt>YYYY-MM</tt>):
+
+ t.strftime('%Y-%m') # => "2022-06"
+
+- {Week dates}[https://en.wikipedia.org/wiki/ISO_8601#Week_dates]:
+
+ - Basic date (+YYYYWww+ or +YYYYWwwD+):
+
+ t.strftime('%Y%Ww') # => "202226w"
+ t.strftime('%Y%Ww%u') # => "202226w3"
+
+ - Extended date (<tt>YYYY-Www</tt> or <tt>YYYY-Www-D<tt>):
+
+ t.strftime('%Y-%Ww') # => "2022-26w"
+ t.strftime('%Y-%Ww-%u') # => "2022-26w-3"
+
+- {Ordinal dates}[https://en.wikipedia.org/wiki/ISO_8601#Ordinal_dates]:
+
+ - Basic date (+YYYYDDD+):
+
+ t.strftime('%Y%j') # => "2022180"
+
+ - Extended date (<tt>YYYY-DDD</tt>):
+
+ t.strftime('%Y-%j') # => "2022-180"
+
+=== Times
+
+See {ISO 8601 times}[https://en.wikipedia.org/wiki/ISO_8601#Times].
+
+- Times:
+
+ - Basic time (+Thhmmss.sss+, +Thhmmss+, +Thhmm+, or +Thh+):
+
+ t.strftime('T%H%M%S.%L') # => "T164925.465"
+ t.strftime('T%H%M%S') # => "T164925"
+ t.strftime('T%H%M') # => "T1649"
+ t.strftime('T%H') # => "T16"
+
+ - Extended time (+Thh:mm:ss.sss+, +Thh:mm:ss+, or +Thh:mm+):
+
+ t.strftime('T%H:%M:%S.%L') # => "T16:49:25.465"
+ t.strftime('T%H:%M:%S') # => "T16:49:25"
+ t.strftime('T%H:%M') # => "T16:49"
+
+- {Time zone designators}[https://en.wikipedia.org/wiki/ISO_8601#Time_zone_designators]:
+
+ - Timezone (+time+ represents a valid time,
+ +hh+ represents a valid 2-digit hour,
+ and +mm+ represents a valid 2-digit minute):
+
+ - Basic timezone (<tt>time±hhmm</tt>, <tt>time±hh</tt>, or +timeZ+):
+
+ t.strftime('T%H%M%S%z') # => "T164925-0500"
+ t.strftime('T%H%M%S%z').slice(0..-3) # => "T164925-05"
+ t.strftime('T%H%M%SZ') # => "T164925Z"
+
+ - Extended timezone (<tt>time±hh:mm</tt>):
+
+ t.strftime('T%H:%M:%S%z') # => "T16:49:25-0500"
+
+ - See also:
+
+ - {Local time (unqualified)}[https://en.wikipedia.org/wiki/ISO_8601#Local_time_(unqualified)].
+ - {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
+
+See {ISO 8601 Combined date and time representations}[https://en.wikipedia.org/wiki/ISO_8601#Combined_date_and_time_representations].
+
+An ISO 8601 combined date and time representation may be any
+ISO 8601 date and any ISO 8601 time,
+separated by the letter +T+.
+
+For the relevant +strftime+ formats, see {Dates}[rdoc-ref:@Dates] and {Times}[rdoc-ref:@Times] above.
diff --git a/doc/maintainers.md b/doc/maintainers.md
index 7d217a1665..e87ccaca05 100644
--- a/doc/maintainers.md
+++ b/doc/maintainers.md
@@ -28,6 +28,10 @@ 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.
+No maintainer means that there is no specific maintainer for the part now.
+The member of ruby core team can fix issues at anytime. But major changes need
+consensus on ruby-core/ruby-dev.
+
### Language core features including security
* Yukihiro Matsumoto ([matz])
@@ -40,25 +44,30 @@ have commit right, others don't.
* Yukihiro Matsumoto ([matz])
-## Standard Library Maintainers
-
-### Libraries
+### Standard Library Maintainers
#### lib/mkmf.rb
-* *unmaintained*
+* *No maintainer*
+
+#### pathname_builtin.rb, lib/pathname.rb
+
+* Tanaka Akira ([akr])
#### lib/rubygems.rb, lib/rubygems/*
-* Eric Hodel ([drbrain])
* Hiroshi SHIBATA ([hsbt])
-* https://github.com/rubygems/rubygems
+* https://github.com/ruby/rubygems
#### lib/unicode_normalize.rb, lib/unicode_normalize/*
* Martin J. Dürst ([duerst])
-### Extensions
+### Standard Library(Extensions) Maintainers
+
+#### set.c
+
+* Akinori MUSHA ([knu])
#### ext/continuation
@@ -78,15 +87,19 @@ have commit right, others don't.
#### ext/objspace
-* *unmaintained*
+* *No maintainer*
+
+#### ext/pathname
+
+* Tanaka Akira ([akr])
#### ext/pty
-* *unmaintained*
+* *No maintainer*
#### ext/ripper
-* *unmaintained*
+* *No maintainer*
#### ext/socket
@@ -97,29 +110,27 @@ have commit right, others don't.
* NAKAMURA Usaku ([unak])
-## Default gems Maintainers
-
-### Libraries
+### Default gems(Libraries) Maintainers
#### lib/bundler.rb, lib/bundler/*
* Hiroshi SHIBATA ([hsbt])
-* https://github.com/rubygems/rubygems
+* https://github.com/ruby/rubygems
* https://rubygems.org/gems/bundler
#### lib/cgi/escape.rb
-* *unmaintained*
+* *No maintainer*
#### lib/English.rb
-* *unmaintained*
+* *No maintainer*
* https://github.com/ruby/English
* https://rubygems.org/gems/English
#### lib/delegate.rb
-* *unmaintained*
+* *No maintainer*
* https://github.com/ruby/delegate
* https://rubygems.org/gems/delegate
@@ -150,7 +161,7 @@ have commit right, others don't.
#### lib/fileutils.rb
-* *unmaintained*
+* *No maintainer*
* https://github.com/ruby/fileutils
* https://rubygems.org/gems/fileutils
@@ -176,6 +187,7 @@ have commit right, others don't.
* Nobuyuki Nakada ([nobu])
* https://github.com/ruby/optparse
+* https://rubygems.org/gems/optparse
#### lib/net/http.rb, lib/net/https.rb
@@ -185,13 +197,13 @@ have commit right, others don't.
#### lib/net/protocol.rb
-* *unmaintained*
+* *No maintainer*
* https://github.com/ruby/net-protocol
* https://rubygems.org/gems/net-protocol
#### lib/open3.rb
-* *unmaintained*
+* *No maintainer*
* https://github.com/ruby/open3
* https://rubygems.org/gems/open3
@@ -199,6 +211,7 @@ have commit right, others don't.
* Tanaka Akira ([akr])
* https://github.com/ruby/open-uri
+* https://rubygems.org/gems/open-uri
#### lib/pp.rb
@@ -217,6 +230,7 @@ have commit right, others don't.
* Kevin Newton ([kddnewton])
* Eileen Uchitelle ([eileencodes])
* Aaron Patterson ([tenderlove])
+* Earlopain ([earlopain])
* https://github.com/ruby/prism
* https://rubygems.org/gems/prism
@@ -246,7 +260,7 @@ have commit right, others don't.
#### lib/tempfile.rb
-* *unmaintained*
+* *No maintainer*
* https://github.com/ruby/tempfile
* https://rubygems.org/gems/tempfile
@@ -262,24 +276,12 @@ have commit right, others don't.
* 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*
+* *No maintainer*
* 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])
@@ -301,11 +303,11 @@ have commit right, others don't.
#### lib/weakref.rb
-* *unmaintained*
+* *No maintainer*
* https://github.com/ruby/weakref
* https://rubygems.org/gems/weakref
-### Extensions
+### Default gems(Extensions) Maintainers
#### ext/cgi
@@ -313,19 +315,19 @@ have commit right, others don't.
#### ext/date
-* *unmaintained*
+* *No maintainer*
* https://github.com/ruby/date
* https://rubygems.org/gems/date
#### ext/etc
-* *unmaintained*
+* *No maintainer*
* https://github.com/ruby/etc
* https://rubygems.org/gems/etc
#### ext/fcntl
-* *unmaintained*
+* *No maintainer*
* https://github.com/ruby/fcntl
* https://rubygems.org/gems/fcntl
@@ -361,12 +363,6 @@ have commit right, others don't.
* 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])
@@ -392,159 +388,248 @@ have commit right, others don't.
* https://github.com/ruby/zlib
* https://rubygems.org/gems/zlib
-## Bundled gems upstream repositories
+## Bundled gems upstream repositories and maintainers
+
+The maintanance policy of bundled gems is different from Module Maintainers above.
+Please check the policies for each repository.
+
+The ruby core team tries to maintain the repositories with no maintainers.
+It may needs to make consensus on ruby-core/ruby-dev before making major changes.
### minitest
+* Ryan Davis ([zenspider])
* https://github.com/minitest/minitest
+* https://rubygems.org/gems/minitest
### power_assert
+* Tsujimoto Kenta ([k-tsj])
* https://github.com/ruby/power_assert
+* https://rubygems.org/gems/power_assert
### rake
+* Hiroshi SHIBATA ([hsbt])
* https://github.com/ruby/rake
+* https://rubygems.org/gems/rake
### test-unit
+* Kouhei Sutou ([kou])
* https://github.com/test-unit/test-unit
+* https://rubygems.org/gems/test-unit
### rexml
+* Kouhei Sutou ([kou])
* https://github.com/ruby/rexml
+* https://rubygems.org/gems/rexml
### rss
+* Kouhei Sutou ([kou])
* https://github.com/ruby/rss
-
-### net-ftp
-
-* https://github.com/ruby/net-ftp
+* https://rubygems.org/gems/rss
### net-imap
+* Nicholas A. Evans ([nevans])
* https://github.com/ruby/net-imap
-
-### net-pop
-
-* https://github.com/ruby/net-pop
+* https://rubygems.org/gems/net-imap
### net-smtp
+* TOMITA Masahiro ([tmtm])
* https://github.com/ruby/net-smtp
+* https://rubygems.org/gems/net-smtp
### matrix
+* Marc-André Lafortune ([marcandre])
* https://github.com/ruby/matrix
+* https://rubygems.org/gems/matrix
### prime
* https://github.com/ruby/prime
+* https://rubygems.org/gems/prime
### rbs
+* Soutaro Matsumoto ([soutaro])
* https://github.com/ruby/rbs
+* https://rubygems.org/gems/rbs
### typeprof
+* Yusuke Endoh ([mame])
* https://github.com/ruby/typeprof
+* https://rubygems.org/gems/typeprof
### debug
+* Koichi Sasada ([ko1])
* https://github.com/ruby/debug
+* https://rubygems.org/gems/debug
### racc
+* Yuichi Kaneko ([yui-knk])
* https://github.com/ruby/racc
+* https://rubygems.org/gems/racc
#### mutex_m
* https://github.com/ruby/mutex_m
+* https://rubygems.org/gems/mutex_m
#### getoptlong
* https://github.com/ruby/getoptlong
+* https://rubygems.org/gems/getoptlong
#### base64
+* Yusuke Endoh ([mame])
* https://github.com/ruby/base64
+* https://rubygems.org/gems/base64
#### bigdecimal
+* Kenta Murata ([mrkn])
* https://github.com/ruby/bigdecimal
+* https://rubygems.org/gems/bigdecimal
#### observer
* https://github.com/ruby/observer
+* https://rubygems.org/gems/observer
#### abbrev
+* Akinori MUSHA ([knu])
* https://github.com/ruby/abbrev
+* https://rubygems.org/gems/abbrev
#### resolv-replace
+* Akira TANAKA ([akr])
* https://github.com/ruby/resolv-replace
+* https://rubygems.org/gems/resolv-replace
#### rinda
+* Masatoshi SEKI ([seki])
* https://github.com/ruby/rinda
+* https://rubygems.org/gems/rinda
#### drb
+* Masatoshi SEKI ([seki])
* https://github.com/ruby/drb
+* https://rubygems.org/gems/drb
#### nkf
+* Naruse Yusuke ([nurse])
* https://github.com/ruby/nkf
+* https://rubygems.org/gems/nkf
#### syslog
+* Akinori Musha ([knu])
* https://github.com/ruby/syslog
+* https://rubygems.org/gems/syslog
#### csv
+* Kouhei Sutou ([kou])
* https://github.com/ruby/csv
+* https://rubygems.org/gems/csv
#### ostruct
+* Marc-André Lafortune ([marcandre])
* https://github.com/ruby/ostruct
+* https://rubygems.org/gems/ostruct
#### pstore
* https://github.com/ruby/pstore
+* https://rubygems.org/gems/pstore
#### benchmark
+* Benoit Daloze ([eregon])
* https://github.com/ruby/benchmark
+* https://rubygems.org/gems/benchmark
#### logger
+* Naotoshi Seo ([sonots])
* https://github.com/ruby/logger
+* https://rubygems.org/gems/logger
#### rdoc
+* Stan Lo ([st0012])
+* Nobuyoshi Nakada ([nobu])
* https://github.com/ruby/rdoc
+* https://rubygems.org/gems/rdoc
#### win32ole
+* Masaki Suketa ([suketa])
* https://github.com/ruby/win32ole
+* https://rubygems.org/gems/win32ole
#### irb
+* Tomoya Ishida ([tompng])
+* Stan Lo ([st0012])
+* Mari Imaizumi ([ima1zumi])
+* HASUMI Hitoshi ([hasumikin])
* https://github.com/ruby/irb
+* https://rubygems.org/gems/irb
#### reline
+* Tomoya Ishida ([tompng])
+* Stan Lo ([st0012])
+* Mari Imaizumi ([ima1zumi])
+* HASUMI Hitoshi ([hasumikin])
* https://github.com/ruby/reline
+* https://rubygems.org/gems/reline
#### readline
* https://github.com/ruby/readline
+* https://rubygems.org/gems/readline
#### fiddle
+* Kouhei Sutou ([kou])
* https://github.com/ruby/fiddle
+* https://rubygems.org/gems/fiddle
+
+#### repl_type_completor
+
+* Tomoya Ishida ([tompng])
+* https://github.com/ruby/repl_type_completor
+* https://rubygems.org/gems/repl_type_completor
+
+#### tsort
+
+* Tanaka Akira ([akr])
+* https://github.com/ruby/tsort
+* https://rubygems.org/gems/tsort
+
+#### win32-registry
+
+* Nakamura Usaku ([unak])
+* https://github.com/ruby/win32-registry
+* https://rubygems.org/gems/win32-registry
## Platform Maintainers
@@ -582,7 +667,7 @@ have commit right, others don't.
### cygwin, ...
-* none. (Maintainer WANTED)
+* **No maintainer**
### WebAssembly/WASI
@@ -593,8 +678,10 @@ have commit right, others don't.
[colby-swandale]: https://github.com/colby-swandale
[drbrain]: https://github.com/drbrain
[duerst]: https://github.com/duerst
+[earlopain]: https://github.com/earlopain
[eban]: https://github.com/eban
[eileencodes]: https://github.com/eileencodes
+[eregon]: https://github.com/eregon
[hasumikin]: https://github.com/hasumikin
[hsbt]: https://github.com/hsbt
[ima1zumi]: https://github.com/ima1zumi
@@ -625,3 +712,11 @@ have commit right, others don't.
[tompng]: https://github.com/tompng
[unak]: https://github.com/unak
[yuki24]: https://github.com/yuki24
+[zenspider]: https://github.com/zenspider
+[k-tsj]: https://github.com/k-tsj
+[nevans]: https://github.com/nevans
+[tmtm]: https://github.com/tmtm
+[soutaro]: https://github.com/soutaro
+[yui-knk]: https://github.com/yui-knk
+[hasumikin]: https://github.com/hasumikin
+[suketa]: https://github.com/suketa
diff --git a/doc/matchdata/begin.rdoc b/doc/matchdata/begin.rdoc
index 8046dd9d55..6100617e19 100644
--- a/doc/matchdata/begin.rdoc
+++ b/doc/matchdata/begin.rdoc
@@ -10,12 +10,12 @@ returns the offset of the beginning of the <tt>n</tt>th match:
m[3] # => "113"
m.begin(3) # => 3
- m = /(Ñ‚)(е)(Ñ)/.match('теÑÑ‚')
- # => #<MatchData "теÑ" 1:"Ñ‚" 2:"е" 3:"Ñ">
- m[0] # => "теÑ"
- m.begin(0) # => 0
- m[3] # => "Ñ"
- m.begin(3) # => 2
+ m = /(ã‚“)(ã«)(ã¡)/.match('ã“ã‚“ã«ã¡ã¯')
+ # => #<MatchData "ã‚“ã«ã¡" 1:"ã‚“" 2:"ã«" 3:"ã¡">
+ m[0] # => "ã‚“ã«ã¡"
+ m.begin(0) # => 1
+ m[3] # => "ã¡"
+ m.begin(3) # => 3
When string or symbol argument +name+ is given,
returns the offset of the beginning for the named match:
diff --git a/doc/matchdata/bytebegin.rdoc b/doc/matchdata/bytebegin.rdoc
index 5b40a7ef73..54e417a7fc 100644
--- a/doc/matchdata/bytebegin.rdoc
+++ b/doc/matchdata/bytebegin.rdoc
@@ -10,12 +10,12 @@ returns the offset of the beginning of the <tt>n</tt>th match:
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
+ m = /(ã‚“)(ã«)(ã¡)/.match('ã“ã‚“ã«ã¡ã¯')
+ # => #<MatchData "ã‚“ã«ã¡" 1:"ã‚“" 2:"ã«" 3:"ã¡">
+ m[0] # => "ã‚“ã«ã¡"
+ m.bytebegin(0) # => 3
+ m[3] # => "ã¡"
+ m.bytebegin(3) # => 9
When string or symbol argument +name+ is given,
returns the offset of the beginning for the named match:
diff --git a/doc/matchdata/byteend.rdoc b/doc/matchdata/byteend.rdoc
index eb57664022..0a03f76208 100644
--- a/doc/matchdata/byteend.rdoc
+++ b/doc/matchdata/byteend.rdoc
@@ -10,12 +10,12 @@ returns the offset of the end of the <tt>n</tt>th match:
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
+ m = /(ã‚“)(ã«)(ã¡)/.match('ã“ã‚“ã«ã¡ã¯')
+ # => #<MatchData "ã‚“ã«ã¡" 1:"ã‚“" 2:"ã«" 3:"ã¡">
+ m[0] # => "ã‚“ã«ã¡"
+ m.byteend(0) # => 12
+ m[3] # => "ã¡"
+ m.byteend(3) # => 12
When string or symbol argument +name+ is given,
returns the offset of the end for the named match:
diff --git a/doc/matchdata/end.rdoc b/doc/matchdata/end.rdoc
index 0209b2d2fc..c43a5428f3 100644
--- a/doc/matchdata/end.rdoc
+++ b/doc/matchdata/end.rdoc
@@ -10,12 +10,12 @@ returns the offset of the end of the <tt>n</tt>th match:
m[3] # => "113"
m.end(3) # => 6
- m = /(Ñ‚)(е)(Ñ)/.match('теÑÑ‚')
- # => #<MatchData "теÑ" 1:"Ñ‚" 2:"е" 3:"Ñ">
- m[0] # => "теÑ"
- m.end(0) # => 3
- m[3] # => "Ñ"
- m.end(3) # => 3
+ m = /(ã‚“)(ã«)(ã¡)/.match('ã“ã‚“ã«ã¡ã¯')
+ # => #<MatchData "ã‚“ã«ã¡" 1:"ã‚“" 2:"ã«" 3:"ã¡">
+ m[0] # => "ã‚“ã«ã¡"
+ m.end(0) # => 4
+ m[3] # => "ã¡"
+ m.end(3) # => 4
When string or symbol argument +name+ is given,
returns the offset of the end for the named match:
diff --git a/doc/matchdata/offset.rdoc b/doc/matchdata/offset.rdoc
index 0985316d76..4194ef7ef9 100644
--- a/doc/matchdata/offset.rdoc
+++ b/doc/matchdata/offset.rdoc
@@ -11,12 +11,12 @@ returns the starting and ending offsets of the <tt>n</tt>th match:
m[3] # => "113"
m.offset(3) # => [3, 6]
- m = /(Ñ‚)(е)(Ñ)/.match('теÑÑ‚')
- # => #<MatchData "теÑ" 1:"Ñ‚" 2:"е" 3:"Ñ">
- m[0] # => "теÑ"
- m.offset(0) # => [0, 3]
- m[3] # => "Ñ"
- m.offset(3) # => [2, 3]
+ m = /(ã‚“)(ã«)(ã¡)/.match('ã“ã‚“ã«ã¡ã¯')
+ # => #<MatchData "ã‚“ã«ã¡" 1:"ã‚“" 2:"ã«" 3:"ã¡">
+ m[0] # => "ã‚“ã«ã¡"
+ m.offset(0) # => [1, 4]
+ m[3] # => "ã¡"
+ m.offset(3) # => [3, 4]
When string or symbol argument +name+ is given,
returns the starting and ending offsets for the named match:
diff --git a/doc/namespace.md b/doc/namespace.md
deleted file mode 100644
index eee6b94072..0000000000
--- a/doc/namespace.md
+++ /dev/null
@@ -1,418 +0,0 @@
-# Namespace - Ruby's in-process separation of Classes and Modules
-
-Namespace is designed to provide separated spaces in a Ruby process, to isolate applications and libraries.
-
-## Known issues
-
-* Experimental warning is shown when ruby starts with `RUBY_NAMESPACE=1` (specify `-W:no-experimental` option to hide it)
-* `bundle install` may fail
-* `require 'active_support'` may fail
-* A wrong current namespace detection happens sometimes in the root namespace
-
-## TODOs
-
-* Identify the CI failure cause and restore temporarily skipped tests (mmtk, test/ruby/test_allocation on i686)
-* Reconstruct current/loading namespace management based on control frames
-* Add the loaded namespace on iseq to check if another namespace tries running the iseq (add a field only when VM_CHECK_MODE?)
-* Delete per-namespace extension files (.so) lazily or process exit
-* Collect rb_classext_t entries for a namespace when the namespace is collected
-* Allocate an rb_namespace_t entry as the root namespace at first, then construct the contents and wrap it as rb_cNamespace instance later (to eliminate root/builtin two namespaces situation)
-* Assign its own TOPLEVEL_BINDING in namespaces
-* Fix `warn` in namespaces to refer `$VERBOSE` in the namespace
-* Make an internal data container `Namespace::Entry` invisible
-* More test cases about `$LOAD_PATH` and `$LOADED_FEATURES`
-* Return classpath and nesting without the namespace prefix in the namespace itself [#21316](https://bugs.ruby-lang.org/issues/21316), [#21318](https://bugs.ruby-lang.org/issues/21318)
-
-## How to use
-
-### Enabling namespace
-
-First, an environment variable should be set at the ruby process bootup: `RUBY_NAMESPACE=1`.
-The only valid value is `1` to enable namespace. Other values (or unset `RUBY_NAMESPACE`) means disabling namespace. And setting the value after Ruby program starts doesn't work.
-
-### Using namespace
-
-`Namespace` class is the entrypoint of namespaces.
-
-```ruby
-ns = Namespace.new
-ns.require('something') # or require_relative, load
-```
-
-The required file (either .rb or .so/.dll/.bundle) is loaded in the namespace (`ns` here). The required/loaded files from `something` will be loaded in the namespace recursively.
-
-```ruby
-# something.rb
-
-X = 1
-
-class Something
- def self.x = X
- def x = ::X
-end
-```
-
-Classes/modules, those methods and constants defined in the namespace can be accessed via `ns` object.
-
-```ruby
-p ns::Something.x # 1
-
-X = 2
-p X # 2
-p ::X # 2
-p ns::Something.x # 1
-p ns::X # 1
-```
-
-Instance methods defined in the namespace also run with definitions in the namespace.
-
-```ruby
-s = ns::Something.new
-
-p s.x # 1
-```
-
-## Specifications
-
-### Namespace types
-
-There are two namespace types:
-
-* Root namespace
-* User namespace
-
-There is the root namespace, just a single namespace in a Ruby process. Ruby bootstrap runs in the root namespace, and all builtin classes/modules are defined in the root namespace. (See "Builtin classes and modules".)
-
-User namespaces are to run user-written programs and libraries loaded from user programs. The user's main program (specified by the `ruby` command line argument) is executed in the "main" namespace, which is a user namespace automatically created at the end of Ruby's bootstrap, copied from the root namespace.
-
-When `Namespace.new` is called, an "optional" namespace (a user, non-main namespace) is created, copied from the root namespace. All user namespaces are flat, copied from the root namespace.
-
-### Namespace class and instances
-
-`Namespace` is a top level class, as a subclass of `Module`, and `Namespace` instances are a kind of `Module`.
-
-### Classes and modules defined in namespace
-
-The classes and modules, newly defined in a namespace `ns`, are defined under `ns`. For example, if a class `A` is defined in `ns`, it is actually defined as `ns::A`.
-
-In the namespace `ns`, `ns::A` can be referred to as `A` (and `::A`). From outside of `ns`, it can be referred to as `ns::A`.
-
-The main namespace is exceptional. Top level classes and modules defined in the main namespace are just top level classes and modules.
-
-### Classes and modules reopened in namespace
-
-In namespaces, builtin classes/modules are visible and can be reopened. Those classes/modules can be reopened using `class` or `module` clauses, and class/module definitions can be changed.
-
-The changed definitions are visible only in the namespace. In other namespaces, builtin classes/modules and those instances work without changed definitions.
-
-```ruby
-# in foo.rb
-class String
- BLANK_PATTERN = /\A\s*\z/
- def blank?
- self =~ BLANK_PATTERN
- end
-end
-
-module Foo
- def self.foo = "foo"
-
- def self.foo_is_blank?
- foo.blank?
- end
-end
-
-Foo.foo.blank? #=> false
-"foo".blank? #=> false
-
-# in main.rb
-ns = Namespace.new
-ns.require('foo')
-
-Foo.foo_is_blank? #=> false (#blank? called in ns)
-
-Foo.foo.blank? # NoMethodError
-"foo".blank? # NoMethodError
-String::BLANK_PATTERN # NameError
-```
-
-The main namespace and `ns` are different namespaces, so monkey patches in main are also invisible in `ns`.
-
-### Builtin classes and modules
-
-In the namespace context, "builtin" classes and modules are classes and modules:
-
-* Accessible without any `require` calls in user scripts
-* Defined before any user program start running
-* Including classes/modules loaded by `prelude.rb` (including RubyGems `Gem`, for example)
-
-Hereafter, "builtin classes and modules" will be referred to as just "builtin classes".
-
-### Builtin classes referred via namespace objects
-
-Builtin classes in a namespace `ns` can be referred from other namespace. For example, `ns::String` is a valid reference, and `String` and `ns::String` are identical (`String == ns::String`, `String.object_id == ns::String.object_id`).
-
-`ns::String`-like reference returns just a `String` in the current namespace, so its definition is `String` in the namespace, not in `ns`.
-
-```ruby
-# foo.rb
-class String
- def self.foo = "foo"
-end
-
-# main.rb
-ns = Namespace.new
-ns.require('foo')
-
-ns::String.foo # NoMethodError
-```
-
-### Class instance variables, class variables, constants
-
-Builtin classes can have different sets of class instance variables, class variables and constants between namespaces.
-
-```ruby
-# foo.rb
-class Array
- @v = "foo"
- @@v = "_foo_"
- V = "FOO"
-end
-
-Array.instance_variable_get(:@v) #=> "foo"
-Array.class_variable_get(:@@v) #=> "_foo_"
-Array.const_get(:V) #=> "FOO"
-
-# main.rb
-ns = Namespace.new
-ns.require('foo')
-
-Array.instance_variable_get(:@v) #=> nil
-Array.class_variable_get(:@@v) # NameError
-Array.const_get(:V) # NameError
-```
-
-### Global variables
-
-In namespaces, changes on global variables are also isolated in the namespace. Changes on global variables in a namespace are visible/applied only in the namespace.
-
-```ruby
-# foo.rb
-$foo = "foo"
-$VERBOSE = nil
-
-puts "This appears: '#{$foo}'"
-
-# main.rb
-p $foo #=> nil
-p $VERBOSE #=> false
-
-ns = Namespace.new
-ns.require('foo') # "This appears: 'foo'"
-
-p $foo #=> nil
-p $VERBOSE #=> false
-```
-
-### Top level constants
-
-Usually, top level constants are defined as constants of `Object`. In namespaces, top level constants are constants of `Object` in the namespace. And the namespace object `ns`'s constants are strictly equal to constants of `Object`.
-
-```ruby
-# foo.rb
-FOO = 100
-
-FOO #=> 100
-Object::FOO #=> 100
-
-# main.rb
-ns = Namespace.new
-ns.require('foo')
-
-ns::FOO #=> 100
-
-FOO # NameError
-Object::FOO # NameError
-```
-
-### Top level methods
-
-Top level methods are private instance methods of `Object`, in each namespace.
-
-```ruby
-# foo.rb
-def yay = "foo"
-
-class Foo
- def self.say = yay
-end
-
-Foo.say #=> "foo"
-yay #=> "foo"
-
-# main.rb
-ns = Namespace.new
-ns.require('foo')
-
-ns.Foo.say #=> "foo"
-
-yay # NoMethodError
-```
-
-There is no way to expose top level methods in namespaces to another namespace.
-(See "Expose top level methods as a method of the namespace object" in "Discussions" section below)
-
-### Namespace scopes
-
-Namespace works in file scope. One `.rb` file runs in a single namespace.
-
-Once a file is loaded in a namespace `ns`, all methods/procs defined/created in the file run in `ns`.
-
-## Implementation details
-
-#### Object Shapes
-
-Once builtin classes are copied and modified in namespaces, its instance variable management fallbacks from Object Shapes to a traditional iv table (st_table) because RClass stores the shape in its `flags`, not in `rb_classext_t`.
-
-#### Size of RClass and rb_classext_t
-
-Namespace requires to move some fields from RClass to `rb_classext_t`, then the size of RClass and `rb_classext_t` is now larger than `4 * RVALUE_SIZE`. It's against the expectation of [Variable Width Allocation](https://rubykaigi.org/2021-takeout/presentations/peterzhu2118.html).
-
-Now the `STATIC_ASSERT` to check the size is commented-out. (See "Minimize the size of RClass and rb_classext_t" in "Discussion" section below)
-
-#### ISeq inline method/constant cache
-
-As described above in "Namespace scopes", an ".rb" file runs in a namespace. So method/constant resolution will be done in a namespace consistently.
-
-That means ISeq inline caches work well even with namespaces. Otherwise, it's a bug.
-
-#### Method call global cache (gccct)
-
-`rb_funcall()` C function refers to the global cc cache table (gccct), and the cache key is calculated with the current namespace.
-
-So, `rb_funcall()` calls have a performance penalty when namespace is enabled.
-
-#### Current namespace and loading namespace
-
-The current namespace is the namespace that the executing code is in. `Namespace.current` returns the current namespace object.
-
-The loading namespace is an internally managed namespace to determine the namespace to load newly required/loaded files. For example, `ns` is the loading namespace when `ns.require("foo")` is called.
-
-## Discussions
-
-#### Namespace#inspect
-
-Currently, `Namespace#inspect` returns values like `"#<Namespace:0x00000001083a5660>"`. This results in the very redundant and poorly visible classpath outside the namespace.
-
-```ruby
-# foo.rb
-class C; end
-
-# main.rb
-ns = Namespace.new
-ns.require('foo')
-
-p ns::C # "#<Namespace:0x00000001083a5660>::C"
-```
-
-And currently, if a namespace is assigned to a constant `NS1`, the classpath output will be `NS1::C`. But the namespace object can be brought to another namespace and the constant `NS1` in the namespace is something different. So the constant-based classpath for namespace is not safe basically.
-
-So we should find a better format to show namespaces. Options are:
-
-* `NS1::C` (only when this namespace is created and assigned to NS1 in the current namespace)
-* `#<Namespace:user:1083a5660>::C` (with namespace type and without preceding 0)
-* or something else
-
-#### Namespace#eval
-
-Testing namespace features needs to create files to be loaded in namespaces. It's not easy nor casual.
-
-If `Namespace` class has an instance method `#eval` to evaluate code in the namespace, it can be helpful.
-
-#### More builtin methods written in Ruby
-
-If namespace is enabled by default, builtin methods can be written in Ruby because it can't be overridden by users' monkey patches. Builtin Ruby methods can be JIT-ed, and it could bring performance reward.
-
-#### Monkey patching methods called by builtin methods
-
-Builtin methods sometimes call other builtin methods. For example, `Hash#map` calls `Hash#each` to retrieve entries to be mapped. Without namespace, Ruby users can overwrite `Hash#each` and expect the behavior change of `Hash#map` as a result.
-
-But with namespaces, `Hash#map` runs in the root namespace. Ruby users can define `Hash#each` only in user namespaces, so users cannot change `Hash#map`'s behavior in this case. To achieve it, users should override both`Hash#map` and `Hash#each` (or only `Hash#map`).
-
-It is a breaking change.
-
-It's an option to change the behavior of methods in the root namespace to refer to definitions in user namespaces. But if we do so, that means we can't proceed with "More builtin methods written in Ruby".
-
-#### Context of \$LOAD\_PATH and \$LOADED\_FEATURES
-
-Global variables `$LOAD_PATH` and `$LOADED_FEATURES` control `require` method behaviors. So those namespaces are determined by the loading namespace instead of the current namespace.
-
-This could potentially conflict with the user's expectations. We should find the solution.
-
-#### Expose top level methods as a method of the namespace object
-
-Currently, top level methods in namespaces are not accessible from outside of the namespace. But there might be a use case to call other namespace's top level methods.
-
-#### Split root and builtin namespace
-
-NOTE: "builtin" namespace is a different one from the "builtin" namespace in the current implementation
-
-Currently, the single "root" namespace is the source of classext CoW. And also, the "root" namespace can load additional files after starting main script evaluation by calling methods which contain lines like `require "openssl"`.
-
-That means, user namespaces can have different sets of definitions according to when it is created.
-
-```
-[root]
- |
- |----[main]
- |
- |(require "openssl" called in root)
- |
- |----[ns1] having OpenSSL
- |
- |(remove_const called for OpenSSL in root)
- |
- |----[ns2] without OpenSSL
-```
-
-This could cause unexpected behavior differences between user namespaces. It should NOT be a problem because user scripts which refer to `OpenSSL` should call `require "openssl"` by themselves.
-But in the worst case, a script (without `require "openssl"`) runs well in `ns1`, but doesn't run in `ns2`. This situation looks like a "random failure" to users.
-
-An option possible to prevent this situation is to have "root" and "builtin" namespaces.
-
-* root
- * The namespace for the Ruby process bootstrap, then the source of CoW
- * After starting the main namespace, no code runs in this namespace
-* builtin
- * The namespace copied from the root namespace at the same time with "main"
- * Methods and procs defined in the "root" namespace run in this namespace
- * Classes and modules required will be loaded in this namespace
-
-This design realizes a consistent source of namespace CoW.
-
-#### Separate cc_tbl and callable_m_tbl, cvc_tbl for less classext CoW
-
-The fields of `rb_classext_t` contains several cache(-like) data, `cc_tbl`(callcache table), `callable_m_tbl`(table of resolved complemented methods) and `cvc_tbl`(class variable cache table).
-
-The classext CoW is triggered when the contents of `rb_classext_t` are changed, including `cc_tbl`, `callable_m_tbl`, and `cvc_tbl`. But those three tables are changed by just calling methods or referring class variables. So, currently, classext CoW is triggered much more times than the original expectation.
-
-If we can move those three tables outside of `rb_classext_t`, the number of copied `rb_classext_t` will be much less than the current implementation.
-
-#### Object Shapes per namespace
-
-Now the classext CoW requires RClass and `rb_classext_t` to fallback its instance variable management from Object Shapes to the traditional `st_table`. It may have a performance penalty.
-
-If we can apply Object Shapes on `rb_classext_t` instead of `RClass`, per-namespace classext can have its own shapes, and it may be able to avoid the performance penalty.
-
-#### Minimize the size of RClass and rb_classext_t
-
-As described in "Size of RClass and rb_classext_t" section above, the size of RClass and `rb_classext_t` is currently larger than `4 * RVALUE_SIZE` (`20 * VALUE_SIZE`). Now the size is `23 * VALUE_SIZE + 7 bits`.
-
-The fields possibly removed from `rb_classext_t` are:
-
-* `cc_tbl`, `callable_m_tbl`, `cvc_tbl` (See the section "Separate cc_tbl and callable_m_tbl, cvc_tbl for less classext CoW" above)
-* `ns_super_subclasses`, `module_super_subclasses`
- * `RCLASSEXT_SUBCLASSES(RCLASS_EXT_PRIME(RCLASSEXT_SUPER(klass)))->ns_subclasses` can replace it
- * These fields are used only in GC, how's the actual performance benefit?
-
-If we can move or remove those fields, the size satisfies the assertion (`<= 4 * RVALUE_SIZE`).
diff --git a/doc/packed_data.rdoc b/doc/packed_data.rdoc
deleted file mode 100644
index b33eed58e7..0000000000
--- a/doc/packed_data.rdoc
+++ /dev/null
@@ -1,706 +0,0 @@
-= Packed \Data
-
-== Quick Reference
-
-These tables summarize the directives for packing and unpacking.
-
-=== For Integers
-
- Directive | Meaning
- --------------|---------------------------------------------------------------
- C | 8-bit unsigned (unsigned char)
- S | 16-bit unsigned, native endian (uint16_t)
- L | 32-bit unsigned, native endian (uint32_t)
- Q | 64-bit unsigned, native endian (uint64_t)
- J | pointer width unsigned, native endian (uintptr_t)
-
- c | 8-bit signed (signed char)
- s | 16-bit signed, native endian (int16_t)
- l | 32-bit signed, native endian (int32_t)
- q | 64-bit signed, native endian (int64_t)
- j | pointer width signed, native endian (intptr_t)
-
- S_ S! | unsigned short, native endian
- I I_ I! | unsigned int, native endian
- L_ L! | unsigned long, native endian
- Q_ Q! | unsigned long long, native endian
- | (raises ArgumentError if the platform has no long long type)
- J! | uintptr_t, native endian (same with J)
-
- s_ s! | signed short, native endian
- i i_ i! | signed int, native endian
- l_ l! | signed long, native endian
- q_ q! | signed long long, native endian
- | (raises ArgumentError if the platform has no long long type)
- j! | intptr_t, native endian (same with j)
-
- S> s> S!> s!> | each the same as the directive without >, but big endian
- L> l> L!> l!> | S> is the same as n
- I!> i!> | L> is the same as N
- Q> q> Q!> q!> |
- J> j> J!> j!> |
-
- S< s< S!< s!< | each the same as the directive without <, but little endian
- L< l< L!< l!< | S< is the same as v
- I!< i!< | L< is the same as V
- Q< q< Q!< q!< |
- J< j< J!< j!< |
-
- n | 16-bit unsigned, network (big-endian) byte order
- N | 32-bit unsigned, network (big-endian) byte order
- v | 16-bit unsigned, VAX (little-endian) byte order
- V | 32-bit unsigned, VAX (little-endian) byte order
-
- U | UTF-8 character
- w | BER-compressed integer
-
-=== For Floats
-
- Directive | Meaning
- ----------|--------------------------------------------------
- D d | double-precision, native format
- F f | single-precision, native format
- E | double-precision, little-endian byte order
- e | single-precision, little-endian byte order
- G | double-precision, network (big-endian) byte order
- g | single-precision, network (big-endian) byte order
-
-=== For Strings
-
- Directive | Meaning
- ----------|-----------------------------------------------------------------
- A | arbitrary binary string (remove trailing nulls and ASCII spaces)
- a | arbitrary binary string
- Z | null-terminated string
- B | bit string (MSB first)
- b | bit string (LSB first)
- H | hex string (high nibble first)
- h | hex string (low nibble first)
- u | UU-encoded string
- M | quoted-printable, MIME encoding (see RFC2045)
- m | base64 encoded string (RFC 2045) (default)
- | (base64 encoded string (RFC 4648) if followed by 0)
- P | pointer to a structure (fixed-length string)
- p | pointer to a null-terminated string
-
-=== Additional Directives for Packing
-
- Directive | Meaning
- ----------|----------------------------------------------------------------
- @ | moves to absolute position
- X | back up a byte
- x | null byte
-
-=== Additional Directives for Unpacking
-
- Directive | Meaning
- ----------|----------------------------------------------------------------
- @ | skip to the offset given by the length argument
- X | skip backward one byte
- x | skip forward one byte
-
-== Packing and Unpacking
-
-Certain Ruby core methods deal with packing and unpacking data:
-
-- Method Array#pack:
- Formats each element in array +self+ into a binary string;
- returns that string.
-- Method String#unpack:
- Extracts data from string +self+,
- forming objects that become the elements of a new array;
- returns that array.
-- Method String#unpack1:
- Does the same, but unpacks and returns only the first extracted object.
-
-Each of these methods accepts a string +template+,
-consisting of zero or more _directive_ characters,
-each followed by zero or more _modifier_ characters.
-
-Examples (directive <tt>'C'</tt> specifies 'unsigned character'):
-
- [65].pack('C') # => "A" # One element, one directive.
- [65, 66].pack('CC') # => "AB" # Two elements, two directives.
- [65, 66].pack('C') # => "A" # Extra element is ignored.
- [65].pack('') # => "" # No directives.
- [65].pack('CC') # Extra directive raises ArgumentError.
-
- 'A'.unpack('C') # => [65] # One character, one directive.
- 'AB'.unpack('CC') # => [65, 66] # Two characters, two directives.
- 'AB'.unpack('C') # => [65] # Extra character is ignored.
- 'A'.unpack('CC') # => [65, nil] # Extra directive generates nil.
- 'AB'.unpack('') # => [] # No directives.
-
-The string +template+ may contain any mixture of valid directives
-(directive <tt>'c'</tt> specifies 'signed character'):
-
- [65, -1].pack('cC') # => "A\xFF"
- "A\xFF".unpack('cC') # => [65, 255]
-
-The string +template+ may contain whitespace (which is ignored)
-and comments, each of which begins with character <tt>'#'</tt>
-and continues up to and including the next following newline:
-
- [0,1].pack(" C #foo \n C ") # => "\x00\x01"
- "\0\1".unpack(" C #foo \n C ") # => [0, 1]
-
-Any directive may be followed by either of these modifiers:
-
-- <tt>'*'</tt> - The directive is to be applied as many times as needed:
-
- [65, 66].pack('C*') # => "AB"
- 'AB'.unpack('C*') # => [65, 66]
-
-- Integer +count+ - The directive is to be applied +count+ times:
-
- [65, 66].pack('C2') # => "AB"
- [65, 66].pack('C3') # Raises ArgumentError.
- 'AB'.unpack('C2') # => [65, 66]
- 'AB'.unpack('C3') # => [65, 66, nil]
-
- Note: Directives in <tt>%w[A a Z m]</tt> use +count+ differently;
- see {String Directives}[rdoc-ref:packed_data.rdoc@String+Directives].
-
-If elements don't fit the provided directive, only least significant bits are encoded:
-
- [257].pack("C").unpack("C") # => [1]
-
-== Packing Method
-
-Method Array#pack accepts optional keyword argument
-+buffer+ that specifies the target string (instead of a new string):
-
- [65, 66].pack('C*', buffer: 'foo') # => "fooAB"
-
-The method can accept a block:
-
- # Packed string is passed to the block.
- [65, 66].pack('C*') {|s| p s } # => "AB"
-
-== Unpacking Methods
-
-Methods String#unpack and String#unpack1 each accept
-an optional keyword argument +offset+ that specifies an offset
-into the string:
-
- 'ABC'.unpack('C*', offset: 1) # => [66, 67]
- 'ABC'.unpack1('C*', offset: 1) # => 66
-
-Both methods can accept a block:
-
- # Each unpacked object is passed to the block.
- ret = []
- "ABCD".unpack("C*") {|c| ret << c }
- ret # => [65, 66, 67, 68]
-
- # The single unpacked object is passed to the block.
- 'AB'.unpack1('C*') {|ele| p ele } # => 65
-
-== \Integer Directives
-
-Each integer directive specifies the packing or unpacking
-for one element in the input or output array.
-
-=== 8-Bit \Integer Directives
-
-- <tt>'c'</tt> - 8-bit signed integer
- (like C <tt>signed char</tt>):
-
- [0, 1, 255].pack('c*') # => "\x00\x01\xFF"
- s = [0, 1, -1].pack('c*') # => "\x00\x01\xFF"
- s.unpack('c*') # => [0, 1, -1]
-
-- <tt>'C'</tt> - 8-bit unsigned 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
-
-- <tt>'s'</tt> - 16-bit signed integer, native-endian
- (like C <tt>int16_t</tt>):
-
- [513, -514].pack('s*') # => "\x01\x02\xFE\xFD"
- s = [513, 65022].pack('s*') # => "\x01\x02\xFE\xFD"
- s.unpack('s*') # => [513, -514]
-
-- <tt>'S'</tt> - 16-bit unsigned integer, native-endian
- (like C <tt>uint16_t</tt>):
-
- [513, -514].pack('S*') # => "\x01\x02\xFE\xFD"
- s = [513, 65022].pack('S*') # => "\x01\x02\xFE\xFD"
- s.unpack('S*') # => [513, 65022]
-
-- <tt>'n'</tt> - 16-bit network integer, big-endian:
-
- s = [0, 1, -1, 32767, -32768, 65535].pack('n*')
- # => "\x00\x00\x00\x01\xFF\xFF\x7F\xFF\x80\x00\xFF\xFF"
- s.unpack('n*')
- # => [0, 1, 65535, 32767, 32768, 65535]
-
-- <tt>'v'</tt> - 16-bit VAX integer, little-endian:
-
- s = [0, 1, -1, 32767, -32768, 65535].pack('v*')
- # => "\x00\x00\x01\x00\xFF\xFF\xFF\x7F\x00\x80\xFF\xFF"
- s.unpack('v*')
- # => [0, 1, 65535, 32767, 32768, 65535]
-
-=== 32-Bit \Integer Directives
-
-- <tt>'l'</tt> - 32-bit signed integer, native-endian
- (like C <tt>int32_t</tt>):
-
- s = [67305985, -50462977].pack('l*')
- # => "\x01\x02\x03\x04\xFF\xFE\xFD\xFC"
- s.unpack('l*')
- # => [67305985, -50462977]
-
-- <tt>'L'</tt> - 32-bit unsigned integer, native-endian
- (like C <tt>uint32_t</tt>):
-
- s = [67305985, 4244504319].pack('L*')
- # => "\x01\x02\x03\x04\xFF\xFE\xFD\xFC"
- s.unpack('L*')
- # => [67305985, 4244504319]
-
-- <tt>'N'</tt> - 32-bit network integer, big-endian:
-
- s = [0,1,-1].pack('N*')
- # => "\x00\x00\x00\x00\x00\x00\x00\x01\xFF\xFF\xFF\xFF"
- s.unpack('N*')
- # => [0, 1, 4294967295]
-
-- <tt>'V'</tt> - 32-bit VAX integer, little-endian:
-
- s = [0,1,-1].pack('V*')
- # => "\x00\x00\x00\x00\x01\x00\x00\x00\xFF\xFF\xFF\xFF"
- s.unpack('v*')
- # => [0, 0, 1, 0, 65535, 65535]
-
-=== 64-Bit \Integer Directives
-
-- <tt>'q'</tt> - 64-bit signed integer, native-endian
- (like C <tt>int64_t</tt>):
-
- s = [578437695752307201, -506097522914230529].pack('q*')
- # => "\x01\x02\x03\x04\x05\x06\a\b\xFF\xFE\xFD\xFC\xFB\xFA\xF9\xF8"
- s.unpack('q*')
- # => [578437695752307201, -506097522914230529]
-
-- <tt>'Q'</tt> - 64-bit unsigned integer, native-endian
- (like C <tt>uint64_t</tt>):
-
- s = [578437695752307201, 17940646550795321087].pack('Q*')
- # => "\x01\x02\x03\x04\x05\x06\a\b\xFF\xFE\xFD\xFC\xFB\xFA\xF9\xF8"
- s.unpack('Q*')
- # => [578437695752307201, 17940646550795321087]
-
-=== Platform-Dependent \Integer Directives
-
-- <tt>'i'</tt> - Platform-dependent width signed integer,
- native-endian (like C <tt>int</tt>):
-
- s = [67305985, -50462977].pack('i*')
- # => "\x01\x02\x03\x04\xFF\xFE\xFD\xFC"
- s.unpack('i*')
- # => [67305985, -50462977]
-
-- <tt>'I'</tt> - Platform-dependent width unsigned integer,
- native-endian (like C <tt>unsigned int</tt>):
-
- s = [67305985, -50462977].pack('I*')
- # => "\x01\x02\x03\x04\xFF\xFE\xFD\xFC"
- s.unpack('I*')
- # => [67305985, 4244504319]
-
-- <tt>'j'</tt> - 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>):
-
- 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
-
-- <tt>'U'</tt> - UTF-8 character:
-
- s = [4194304].pack('U*')
- # => "\xF8\x90\x80\x80\x80"
- s.unpack('U*')
- # => [4194304]
-
-- <tt>'w'</tt> - BER-encoded integer
- (see {BER encoding}[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:
-
-- <tt>'>'</tt> - Big-endian.
-- <tt>'<'</tt> - Little-endian.
-
-== \Float Directives
-
-Each float directive specifies the packing or unpacking
-for one element in the input or output array.
-
-=== Single-Precision \Float Directives
-
-- <tt>'F'</tt> or <tt>'f'</tt> - Native format:
-
- s = [3.0].pack('F') # => "\x00\x00@@"
- s.unpack('F') # => [3.0]
-
-- <tt>'e'</tt> - Little-endian:
-
- s = [3.0].pack('e') # => "\x00\x00@@"
- s.unpack('e') # => [3.0]
-
-- <tt>'g'</tt> - Big-endian:
-
- s = [3.0].pack('g') # => "@@\x00\x00"
- s.unpack('g') # => [3.0]
-
-=== Double-Precision \Float Directives
-
-- <tt>'D'</tt> or <tt>'d'</tt> - Native format:
-
- s = [3.0].pack('D') # => "\x00\x00\x00\x00\x00\x00\b@"
- s.unpack('D') # => [3.0]
-
-- <tt>'E'</tt> - Little-endian:
-
- s = [3.0].pack('E') # => "\x00\x00\x00\x00\x00\x00\b@"
- s.unpack('E') # => [3.0]
-
-- <tt>'G'</tt> - Big-endian:
-
- s = [3.0].pack('G') # => "@\b\x00\x00\x00\x00\x00\x00"
- s.unpack('G') # => [3.0]
-
-A float directive may be infinity or not-a-number:
-
- inf = 1.0/0.0 # => Infinity
- [inf].pack('f') # => "\x00\x00\x80\x7F"
- "\x00\x00\x80\x7F".unpack('f') # => [Infinity]
-
- nan = inf/inf # => NaN
- [nan].pack('f') # => "\x00\x00\xC0\x7F"
- "\x00\x00\xC0\x7F".unpack('f') # => [NaN]
-
-== \String Directives
-
-Each string directive specifies the packing or unpacking
-for one byte in the input or output string.
-
-=== Binary \String Directives
-
-- <tt>'A'</tt> - Arbitrary binary string (space padded; count is width);
- +nil+ is treated as the empty string:
-
- ['foo'].pack('A') # => "f"
- ['foo'].pack('A*') # => "foo"
- ['foo'].pack('A2') # => "fo"
- ['foo'].pack('A4') # => "foo "
- [nil].pack('A') # => " "
- [nil].pack('A*') # => ""
- [nil].pack('A2') # => " "
- [nil].pack('A4') # => " "
-
- "foo\0".unpack('A') # => ["f"]
- "foo\0".unpack('A4') # => ["foo"]
- "foo\0bar".unpack('A10') # => ["foo\x00bar"] # Reads past "\0".
- "foo ".unpack('A') # => ["f"]
- "foo ".unpack('A4') # => ["foo"]
- "foo".unpack('A4') # => ["foo"]
-
- russian = "\u{442 435 441 442}" # => "теÑÑ‚"
- russian.size # => 4
- russian.bytesize # => 8
- [russian].pack('A') # => "\xD1"
- [russian].pack('A*') # => "\xD1\x82\xD0\xB5\xD1\x81\xD1\x82"
- russian.unpack('A') # => ["\xD1"]
- russian.unpack('A2') # => ["\xD1\x82"]
- russian.unpack('A4') # => ["\xD1\x82\xD0\xB5"]
- russian.unpack('A*') # => ["\xD1\x82\xD0\xB5\xD1\x81\xD1\x82"]
-
-- <tt>'a'</tt> - Arbitrary binary string (null padded; count is width):
-
- ["foo"].pack('a') # => "f"
- ["foo"].pack('a*') # => "foo"
- ["foo"].pack('a2') # => "fo"
- ["foo\0"].pack('a4') # => "foo\x00"
- [nil].pack('a') # => "\x00"
- [nil].pack('a*') # => ""
- [nil].pack('a2') # => "\x00\x00"
- [nil].pack('a4') # => "\x00\x00\x00\x00"
-
- "foo\0".unpack('a') # => ["f"]
- "foo\0".unpack('a4') # => ["foo\x00"]
- "foo ".unpack('a4') # => ["foo "]
- "foo".unpack('a4') # => ["foo"]
- "foo\0bar".unpack('a4') # => ["foo\x00"] # Reads past "\0".
-
-- <tt>'Z'</tt> - Same as <tt>'a'</tt>,
- except that null is added or ignored with <tt>'*'</tt>:
-
- ["foo"].pack('Z*') # => "foo\x00"
- [nil].pack('Z*') # => "\x00"
-
- "foo\0".unpack('Z*') # => ["foo"]
- "foo".unpack('Z*') # => ["foo"]
- "foo\0bar".unpack('Z*') # => ["foo"] # Does not read past "\0".
-
-=== Bit \String Directives
-
-- <tt>'B'</tt> - Bit string (high byte first):
-
- ['11111111' + '00000000'].pack('B*') # => "\xFF\x00"
- ['10000000' + '01000000'].pack('B*') # => "\x80@"
-
- ['1'].pack('B0') # => ""
- ['1'].pack('B1') # => "\x80"
- ['1'].pack('B2') # => "\x80\x00"
- ['1'].pack('B3') # => "\x80\x00"
- ['1'].pack('B4') # => "\x80\x00\x00"
- ['1'].pack('B5') # => "\x80\x00\x00"
- ['1'].pack('B6') # => "\x80\x00\x00\x00"
-
- "\xff\x00".unpack("B*") # => ["1111111100000000"]
- "\x01\x02".unpack("B*") # => ["0000000100000010"]
-
- "".unpack("B0") # => [""]
- "\x80".unpack("B1") # => ["1"]
- "\x80".unpack("B2") # => ["10"]
- "\x80".unpack("B3") # => ["100"]
-
-- <tt>'b'</tt> - Bit string (low byte first):
-
- ['11111111' + '00000000'].pack('b*') # => "\xFF\x00"
- ['10000000' + '01000000'].pack('b*') # => "\x01\x02"
-
- ['1'].pack('b0') # => ""
- ['1'].pack('b1') # => "\x01"
- ['1'].pack('b2') # => "\x01\x00"
- ['1'].pack('b3') # => "\x01\x00"
- ['1'].pack('b4') # => "\x01\x00\x00"
- ['1'].pack('b5') # => "\x01\x00\x00"
- ['1'].pack('b6') # => "\x01\x00\x00\x00"
-
- "\xff\x00".unpack("b*") # => ["1111111100000000"]
- "\x01\x02".unpack("b*") # => ["1000000001000000"]
-
- "".unpack("b0") # => [""]
- "\x01".unpack("b1") # => ["1"]
- "\x01".unpack("b2") # => ["10"]
- "\x01".unpack("b3") # => ["100"]
-
-=== Hex \String Directives
-
-- <tt>'H'</tt> - Hex string (high nibble first):
-
- ['10ef'].pack('H*') # => "\x10\xEF"
- ['10ef'].pack('H0') # => ""
- ['10ef'].pack('H3') # => "\x10\xE0"
- ['10ef'].pack('H5') # => "\x10\xEF\x00"
-
- ['fff'].pack('H3') # => "\xFF\xF0"
- ['fff'].pack('H4') # => "\xFF\xF0"
- ['fff'].pack('H5') # => "\xFF\xF0\x00"
- ['fff'].pack('H6') # => "\xFF\xF0\x00"
- ['fff'].pack('H7') # => "\xFF\xF0\x00\x00"
- ['fff'].pack('H8') # => "\xFF\xF0\x00\x00"
-
- "\x10\xef".unpack('H*') # => ["10ef"]
- "\x10\xef".unpack('H0') # => [""]
- "\x10\xef".unpack('H1') # => ["1"]
- "\x10\xef".unpack('H2') # => ["10"]
- "\x10\xef".unpack('H3') # => ["10e"]
- "\x10\xef".unpack('H4') # => ["10ef"]
- "\x10\xef".unpack('H5') # => ["10ef"]
-
-- <tt>'h'</tt> - Hex string (low nibble first):
-
- ['10ef'].pack('h*') # => "\x01\xFE"
- ['10ef'].pack('h0') # => ""
- ['10ef'].pack('h3') # => "\x01\x0E"
- ['10ef'].pack('h5') # => "\x01\xFE\x00"
-
- ['fff'].pack('h3') # => "\xFF\x0F"
- ['fff'].pack('h4') # => "\xFF\x0F"
- ['fff'].pack('h5') # => "\xFF\x0F\x00"
- ['fff'].pack('h6') # => "\xFF\x0F\x00"
- ['fff'].pack('h7') # => "\xFF\x0F\x00\x00"
- ['fff'].pack('h8') # => "\xFF\x0F\x00\x00"
-
- "\x01\xfe".unpack('h*') # => ["10ef"]
- "\x01\xfe".unpack('h0') # => [""]
- "\x01\xfe".unpack('h1') # => ["1"]
- "\x01\xfe".unpack('h2') # => ["10"]
- "\x01\xfe".unpack('h3') # => ["10e"]
- "\x01\xfe".unpack('h4') # => ["10ef"]
- "\x01\xfe".unpack('h5') # => ["10ef"]
-
-=== Pointer \String Directives
-
-- <tt>'P'</tt> - Pointer to a structure (fixed-length string):
-
- s = ['abc'].pack('P') # => "\xE0O\x7F\xE5\xA1\x01\x00\x00"
- s.unpack('P*') # => ["abc"]
- ".".unpack("P") # => []
- ("\0" * 8).unpack("P") # => [nil]
- [nil].pack("P") # => "\x00\x00\x00\x00\x00\x00\x00\x00"
-
-- <tt>'p'</tt> - Pointer to a null-terminated string:
-
- s = ['abc'].pack('p') # => "(\xE4u\xE5\xA1\x01\x00\x00"
- s.unpack('p*') # => ["abc"]
- ".".unpack("p") # => []
- ("\0" * 8).unpack("p") # => [nil]
- [nil].pack("p") # => "\x00\x00\x00\x00\x00\x00\x00\x00"
-
-=== Other \String Directives
-
-- <tt>'M'</tt> - Quoted printable, MIME encoding;
- text mode, but input must use LF and output LF;
- (see {RFC 2045}[https://www.ietf.org/rfc/rfc2045.txt]):
-
- ["a b c\td \ne"].pack('M') # => "a b c\td =\n\ne=\n"
- ["\0"].pack('M') # => "=00=\n"
-
- ["a"*1023].pack('M') == ("a"*73+"=\n")*14+"a=\n" # => true
- ("a"*73+"=\na=\n").unpack('M') == ["a"*74] # => true
- (("a"*73+"=\n")*14+"a=\n").unpack('M') == ["a"*1023] # => true
-
- "a b c\td =\n\ne=\n".unpack('M') # => ["a b c\td \ne"]
- "=00=\n".unpack('M') # => ["\x00"]
-
- "pre=31=32=33after".unpack('M') # => ["pre123after"]
- "pre=\nafter".unpack('M') # => ["preafter"]
- "pre=\r\nafter".unpack('M') # => ["preafter"]
- "pre=".unpack('M') # => ["pre="]
- "pre=\r".unpack('M') # => ["pre=\r"]
- "pre=hoge".unpack('M') # => ["pre=hoge"]
- "pre==31after".unpack('M') # => ["pre==31after"]
- "pre===31after".unpack('M') # => ["pre===31after"]
-
-- <tt>'m'</tt> - Base64 encoded string;
- count specifies input bytes between each newline,
- rounded down to nearest multiple of 3;
- if count is zero, no newlines are added;
- (see {RFC 4648}[https://www.ietf.org/rfc/rfc4648.txt]):
-
- [""].pack('m') # => ""
- ["\0"].pack('m') # => "AA==\n"
- ["\0\0"].pack('m') # => "AAA=\n"
- ["\0\0\0"].pack('m') # => "AAAA\n"
- ["\377"].pack('m') # => "/w==\n"
- ["\377\377"].pack('m') # => "//8=\n"
- ["\377\377\377"].pack('m') # => "////\n"
-
- "".unpack('m') # => [""]
- "AA==\n".unpack('m') # => ["\x00"]
- "AAA=\n".unpack('m') # => ["\x00\x00"]
- "AAAA\n".unpack('m') # => ["\x00\x00\x00"]
- "/w==\n".unpack('m') # => ["\xFF"]
- "//8=\n".unpack('m') # => ["\xFF\xFF"]
- "////\n".unpack('m') # => ["\xFF\xFF\xFF"]
- "A\n".unpack('m') # => [""]
- "AA\n".unpack('m') # => ["\x00"]
- "AA=\n".unpack('m') # => ["\x00"]
- "AAA\n".unpack('m') # => ["\x00\x00"]
-
- [""].pack('m0') # => ""
- ["\0"].pack('m0') # => "AA=="
- ["\0\0"].pack('m0') # => "AAA="
- ["\0\0\0"].pack('m0') # => "AAAA"
- ["\377"].pack('m0') # => "/w=="
- ["\377\377"].pack('m0') # => "//8="
- ["\377\377\377"].pack('m0') # => "////"
-
- "".unpack('m0') # => [""]
- "AA==".unpack('m0') # => ["\x00"]
- "AAA=".unpack('m0') # => ["\x00\x00"]
- "AAAA".unpack('m0') # => ["\x00\x00\x00"]
- "/w==".unpack('m0') # => ["\xFF"]
- "//8=".unpack('m0') # => ["\xFF\xFF"]
- "////".unpack('m0') # => ["\xFF\xFF\xFF"]
-
-- <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"]
-
-== 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 unpacking, cannot to move to outside the string:
-
- "\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:
-
- [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:
-
- [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:
-
- [].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/ractor.md b/doc/ractor.md
deleted file mode 100644
index 224e36934b..0000000000
--- a/doc/ractor.md
+++ /dev/null
@@ -1,772 +0,0 @@
-# Ractor - Ruby's Actor-like concurrent abstraction
-
-Ractor is designed to provide a parallel execution feature of Ruby without thread-safety concerns.
-
-## Summary
-
-### Multiple Ractors in an interpreter process
-
-You can make multiple Ractors and they run in parallel.
-
-* `Ractor.new{ expr }` creates a new Ractor and `expr` is run in parallel on a parallel computer.
-* Interpreter invokes with the first Ractor (called *main Ractor*).
-* If the main Ractor terminates, all other Ractors receive termination requests, similar to how threads behave. (if main thread (first invoked Thread), Ruby interpreter sends all running threads to terminate execution).
-* Each Ractor contains one or more Threads.
- * Threads within the same Ractor share a Ractor-wide global lock like GIL (GVL in MRI terminology), so they can't run in parallel (without releasing GVL explicitly in C-level). Threads in different ractors run in parallel.
- * The overhead of creating a Ractor is similar to overhead of one Thread creation.
-
-### Limited sharing between multiple ractors
-
-Ractors don't share everything, unlike threads.
-
-* Most objects are *Unshareable objects*, so you don't need to care about thread-safety problems which are caused by sharing.
-* Some objects are *Shareable objects*.
- * Immutable objects: frozen objects which don't refer to unshareable-objects.
- * `i = 123`: `i` is an immutable object.
- * `s = "str".freeze`: `s` is an immutable object.
- * `a = [1, [2], 3].freeze`: `a` is not an immutable object because `a` refers unshareable-object `[2]` (which is not frozen).
- * `h = {c: Object}.freeze`: `h` is an immutable object because `h` refers Symbol `:c` and shareable `Object` class object which is not frozen.
- * Class/Module objects
- * Special shareable objects
- * Ractor object itself.
- * And more...
-
-### Communication between Ractors with `Ractor::Port`
-
-Ractors communicate with each other and synchronize the execution by message exchanging between Ractors. `Ractor::Port` is provided for this communication.
-
-```ruby
-port = Ractor::Port.new
-
-Ractor.new port do |port|
- # Other ractors can send to the port
- port << 42
-end
-
-port.receive # get a message to the port. Only the creator Ractor can receive from the port
-#=> 42
-```
-
-Ractors have its own default port and `Ractor#send`, `Ractor.receive` will use it.
-
-### Copy & Move semantics to send messages
-
-To send unshareable objects as messages, objects are copied or moved.
-
-* Copy: use deep-copy.
-* Move: move membership.
- * Sender can not access the moved object after moving the object.
- * Guarantee that at least only 1 Ractor can access the object.
-
-### Thread-safety
-
-Ractor helps to write a thread-safe concurrent program, but we can make thread-unsafe programs with Ractors.
-
-* GOOD: Sharing limitation
- * Most objects are unshareable, so we can't make data-racy and race-conditional programs.
- * Shareable objects are protected by an interpreter or locking mechanism.
-* BAD: Class/Module can violate this assumption
- * To make it compatible with old behavior, classes and modules can introduce data-race and so on.
- * Ruby programmers should take care if they modify class/module objects on multi Ractor programs.
-* BAD: Ractor can't solve all thread-safety problems
- * There are several blocking operations (waiting send) so you can make a program which has dead-lock and live-lock issues.
- * Some kind of shareable objects can introduce transactions (STM, for example). However, misusing transactions will generate inconsistent state.
-
-Without Ractor, we need to trace all state-mutations to debug thread-safety issues.
-With Ractor, you can concentrate on suspicious code which are shared with Ractors.
-
-## Creation and termination
-
-### `Ractor.new`
-
-* `Ractor.new{ expr }` generates another Ractor.
-
-```ruby
-# Ractor.new with a block creates new Ractor
-r = Ractor.new do
- # This block will be run in parallel with other ractors
-end
-
-# You can name a Ractor with `name:` argument.
-r = Ractor.new name: 'test-name' do
-end
-
-# and Ractor#name returns its name.
-r.name #=> 'test-name'
-```
-
-### Given block isolation
-
-The Ractor executes given `expr` in a given block.
-Given block will be isolated from outer scope by the `Proc#isolate` method (not exposed yet for Ruby users). To prevent sharing unshareable objects between ractors, block outer-variables, `self` and other information are isolated.
-
-`Proc#isolate` is called at Ractor creation time (when `Ractor.new` is called). If given Proc object is not able to isolate because of outer variables and so on, an error will be raised.
-
-```ruby
-begin
- a = true
- r = Ractor.new do
- a #=> ArgumentError because this block accesses `a`.
- end
- r.join # see later
-rescue ArgumentError
-end
-```
-
-* The `self` of the given block is the `Ractor` object itself.
-
-```ruby
-r = Ractor.new do
- p self.class #=> Ractor
- self.object_id
-end
-r.value == self.object_id #=> false
-```
-
-Passed arguments to `Ractor.new()` becomes block parameters for the given block. However, an interpreter does not pass the parameter object references, but send them as messages (see below for details).
-
-```ruby
-r = Ractor.new 'ok' do |msg|
- msg #=> 'ok'
-end
-r.value #=> 'ok'
-```
-
-```ruby
-# almost similar to the last example
-r = Ractor.new do
- msg = Ractor.receive
- msg
-end
-r.send 'ok'
-r.value #=> 'ok'
-```
-
-### An execution result of given block
-
-Return value of the given block becomes an outgoing message (see below for details).
-
-```ruby
-r = Ractor.new do
- 'ok'
-end
-r.value #=> `ok`
-```
-
-Error in the given block will be propagated to the receiver of an outgoing message.
-
-```ruby
-r = Ractor.new do
- raise 'ok' # exception will be transferred to the receiver
-end
-
-begin
- r.value
-rescue Ractor::RemoteError => e
- e.cause.class #=> RuntimeError
- e.cause.message #=> 'ok'
- e.ractor #=> r
-end
-```
-
-## Communication between Ractors
-
-Communication between Ractors is achieved by sending and receiving messages. There are two ways to communicate with each other.
-
-* (1) Message sending/receiving via `Ractor::Port`
-* (2) Using shareable container objects
- * Ractor::TVar gem ([ko1/ractor-tvar](https://github.com/ko1/ractor-tvar))
- * more?
-
-Users can control program execution timing with (1), but should not control with (2) (only manage as critical section).
-
-For message sending and receiving, there are two types of APIs: push type and pull type.
-
-* (1) send/receive via `Ractor::Port`.
- * `Ractor::Port#send(obj)` (`Ractor::Port#<<(obj)` is an alias) send a message to the port. Ports are connected to the infinite size incoming queue so `Ractor::Port#send` will never block.
- * `Ractor::Port#receive` dequeue a message from its own incoming queue. If the incoming queue is empty, `Ractor::Port#receive` calling will block the execution of a thread.
-* `Ractor.select()` can wait for the success of `Ractor::Port#receive`.
-* You can close `Ractor::Port` by `Ractor::Port#close` only by the creator Ractor of the port.
- * If the port is closed, you can't `send` to the port. If `Ractor::Port#receive` is blocked for the closed port, then it will raise an exception.
- * 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.
- * 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)).
-
-### Wait for multiple Ractors with `Ractor.select`
-
-You can wait multiple Ractor port's receiving.
-The return value of `Ractor.select()` is `[port, msg]` where `port` is a ready port and `msg` is received message.
-
-To make convenient, `Ractor.select` can also accept Ractors to wait the termination of Ractors.
-The return value of `Ractor.select()` is `[r, msg]` where `r` is a terminated Ractor and `msg` is the value of Ractor's block.
-
-Wait for a single ractor (same as `Ractor#value`):
-
-```ruby
-r1 = Ractor.new{'r1'}
-
-r, obj = Ractor.select(r1)
-r == r1 and obj == 'r1' #=> true
-```
-
-Waiting for two ractors:
-
-```ruby
-r1 = Ractor.new{'r1'}
-r2 = Ractor.new{'r2'}
-rs = [r1, r2]
-as = []
-
-# Wait for r1 or r2's Ractor.yield
-r, obj = Ractor.select(*rs)
-rs.delete(r)
-as << obj
-
-# Second try (rs only contain not-closed ractors)
-r, obj = Ractor.select(*rs)
-rs.delete(r)
-as << obj
-as.sort == ['r1', 'r2'] #=> true
-```
-
-TODO: Current `Ractor.select()` has the same issue of `select(2)`, so this interface should be refined.
-
-TODO: `select` syntax of go-language uses round-robin technique to make fair scheduling. Now `Ractor.select()` doesn't use it.
-
-### Closing Ractor's ports
-
-* `Ractor::Port#close` close the ports (similar to `Queue#close`).
- * `port.send(obj)` where `port` is closed, will raise an exception.
- * When the queue connected to the port is empty and port is closed, `Ractor::Port#receive` raises an exception. If the queue is not empty, it dequeues an object without exceptions.
-* When a Ractor terminates, the ports are closed automatically.
-
-Example (try to get a result from closed Ractor):
-
-```ruby
-r = Ractor.new do
- 'finish'
-end
-r.join # success (wait for the termination)
-r.value # success (will return 'finish')
-
-# the first Ractor which success the `Ractor#value` can get the result
-Ractor.new r do |r|
- r.value #=> Ractor::Error
-end
-```
-
-Example (try to send to closed (terminated) Ractor):
-
-```ruby
-r = Ractor.new do
-end
-
-r.join # wait terminate
-
-begin
- r.send(1)
-rescue Ractor::ClosedError
- 'ok'
-else
- 'ng'
-end
-```
-
-### Send a message by copying
-
-`Ractor::Port#send(obj)` copy `obj` deeply if `obj` is an unshareable object.
-
-```ruby
-obj = 'str'.dup
-r = Ractor.new obj do |msg|
- # return received msg's object_id
- msg.object_id
-end
-
-obj.object_id == r.value #=> false
-```
-
-Some objects are not supported to copy the value, and raise an exception.
-
-```ruby
-obj = Thread.new{}
-begin
- Ractor.new obj do |msg|
- msg
- end
-rescue TypeError => e
- e.message #=> #<TypeError: allocator undefined for Thread>
-else
- 'ng' # unreachable here
-end
-```
-
-### Send a message by moving
-
-`Ractor::Port#send(obj, move: true)` moves `obj` to the destination Ractor.
-If the source Ractor touches the moved object (for example, call the method like `obj.foo()`), it will be an error.
-
-```ruby
-# move with Ractor#send
-r = Ractor.new do
- obj = Ractor.receive
- obj << ' world'
-end
-
-str = 'hello'
-r.send str, move: true
-modified = r.value #=> 'hello world'
-
-# str is moved, and accessing str from this Ractor is prohibited
-
-begin
- # Error because it touches moved str.
- str << ' exception' # raise Ractor::MovedError
-rescue Ractor::MovedError
- modified #=> 'hello world'
-else
- raise 'unreachable'
-end
-```
-
-Some objects are not supported to move, and an exception will be raised.
-
-```ruby
-r = Ractor.new do
- Ractor.receive
-end
-
-r.send(Thread.new{}, move: true) #=> allocator undefined for Thread (TypeError)
-```
-
-To achieve the access prohibition for moved objects, _class replacement_ technique is used to implement it.
-
-### Shareable objects
-
-The following objects are shareable.
-
-* Immutable objects
- * Small integers, some symbols, `true`, `false`, `nil` (a.k.a. `SPECIAL_CONST_P()` objects in internal)
- * Frozen native objects
- * Numeric objects: `Float`, `Complex`, `Rational`, big integers (`T_BIGNUM` in internal)
- * All Symbols.
- * Frozen `String` and `Regexp` objects (their instance variables should refer only shareable objects)
-* Class, Module objects (`T_CLASS`, `T_MODULE` and `T_ICLASS` in internal)
-* `Ractor` and other special objects which care about synchronization.
-
-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 shareable 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.
-
-## Language changes to isolate unshareable objects between Ractors
-
-To isolate unshareable objects between Ractors, we introduced additional language semantics on multi-Ractor Ruby programs.
-
-Note that without using Ractors, these additional semantics is not needed (100% compatible with Ruby 2).
-
-### Global variables
-
-Only the main Ractor (a Ractor created at starting of interpreter) can access global variables.
-
-```ruby
-$gv = 1
-r = Ractor.new do
- $gv
-end
-
-begin
- r.join
-rescue Ractor::RemoteError => e
- e.cause.message #=> 'can not access global variables from non-main Ractors'
-end
-```
-
-Note that some special global variables, such as `$stdin`, `$stdout` and `$stderr` are Ractor-local. See [[Bug #17268]](https://bugs.ruby-lang.org/issues/17268) for more details.
-
-### Instance variables of shareable objects
-
-Instance variables of classes/modules can be get from non-main Ractors if the referring values are shareable objects.
-
-```ruby
-class C
- @iv = 1
-end
-
-p Ractor.new do
- class C
- @iv
- end
-end.value #=> 1
-```
-
-Otherwise, only the main Ractor can access instance variables of shareable objects.
-
-```ruby
-class C
- @iv = [] # unshareable object
-end
-
-Ractor.new do
- class C
- begin
- p @iv
- rescue Ractor::IsolationError
- p $!.message
- #=> "can not get unshareable values from instance variables of classes/modules from non-main Ractors"
- end
-
- begin
- @iv = 42
- rescue Ractor::IsolationError
- p $!.message
- #=> "can not set instance variables of classes/modules by non-main Ractors"
- end
- end
-end.join
-```
-
-
-
-```ruby
-shared = Ractor.new{}
-shared.instance_variable_set(:@iv, 'str')
-
-r = Ractor.new shared do |shared|
- p shared.instance_variable_get(:@iv)
-end
-
-begin
- r.join
-rescue Ractor::RemoteError => e
- e.cause.message #=> can not access instance variables of shareable objects from non-main Ractors (Ractor::IsolationError)
-end
-```
-
-Note that instance variables for class/module objects are also prohibited on Ractors.
-
-### Class variables
-
-Only the main Ractor can access class variables.
-
-```ruby
-class C
- @@cv = 'str'
-end
-
-r = Ractor.new do
- class C
- p @@cv
- end
-end
-
-
-begin
- r.join
-rescue => e
- e.class #=> Ractor::IsolationError
-end
-```
-
-### Constants
-
-Only the main Ractor can read constants which refer to the unshareable object.
-
-```ruby
-class C
- CONST = 'str'
-end
-r = Ractor.new do
- C::CONST
-end
-begin
- r.join
-rescue => e
- e.class #=> Ractor::IsolationError
-end
-```
-
-Only the main Ractor can define constants which refer to the unshareable object.
-
-```ruby
-class C
-end
-r = Ractor.new do
- C::CONST = 'str'
-end
-begin
- r.join
-rescue => e
- e.class #=> Ractor::IsolationError
-end
-```
-
-To make multi-ractor supported library, the constants should only refer shareable objects.
-
-```ruby
-TABLE = {a: 'ko1', b: 'ko2', c: 'ko3'}
-```
-
-In this case, `TABLE` references an unshareable Hash object. So that other ractors can not refer `TABLE` constant. To make it shareable, we can use `Ractor.make_shareable()` like that.
-
-```ruby
-TABLE = Ractor.make_shareable( {a: 'ko1', b: 'ko2', c: 'ko3'} )
-```
-
-To make it easy, Ruby 3.0 introduced new `shareable_constant_value` Directive.
-
-```ruby
-# shareable_constant_value: literal
-
-TABLE = {a: 'ko1', b: 'ko2', c: 'ko3'}
-#=> Same as: TABLE = Ractor.make_shareable( {a: 'ko1', b: 'ko2', c: 'ko3'} )
-```
-
-`shareable_constant_value` directive accepts the following modes (descriptions use the example: `CONST = expr`):
-
-* 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)}`.
-* experimental_everything: replaced to `CONST = Ractor.make_shareable(expr)`.
-* experimental_copy: replaced to `CONST = Ractor.make_shareable(expr, copy: true)`.
-
-Except the `none` mode (default), it is guaranteed that the assigned constants refer to only shareable objects.
-
-See [doc/syntax/comments.rdoc](syntax/comments.rdoc) for more details.
-
-## Implementation note
-
-* Each Ractor has its own thread, it means each Ractor has at least 1 native thread.
-* Each Ractor has its own ID (`rb_ractor_t::pub::id`).
- * On debug mode, all unshareable objects are labeled with current Ractor's id, and it is checked to detect unshareable object leak (access an object from different Ractor) in VM.
-
-## Examples
-
-### Traditional Ring example in Actor-model
-
-```ruby
-RN = 1_000
-CR = Ractor.current
-
-r = Ractor.new do
- p Ractor.receive
- CR << :fin
-end
-
-RN.times{
- r = Ractor.new r do |next_r|
- next_r << Ractor.receive
- end
-}
-
-p :setup_ok
-r << 1
-p Ractor.receive
-```
-
-### Fork-join
-
-```ruby
-def fib n
- if n < 2
- 1
- else
- fib(n-2) + fib(n-1)
- end
-end
-
-RN = 10
-rs = (1..RN).map do |i|
- Ractor.new i do |i|
- [i, fib(i)]
- end
-end
-
-until rs.empty?
- r, v = Ractor.select(*rs)
- rs.delete r
- p answer: v
-end
-```
-
-### Worker pool
-
-(1) One ractor has a pool
-
-```ruby
-require 'prime'
-
-N = 1000
-RN = 10
-
-# make RN workers
-workers = (1..RN).map do
- Ractor.new do |; result_port|
- loop do
- n, result_port = Ractor.receive
- result_port << [n, n.prime?, Ractor.current]
- end
- end
-end
-
-result_port = Ractor::Port.new
-results = []
-
-(1..N).each do |i|
- if workers.empty?
- # receive a result
- n, result, w = result_port.receive
- results << [n, result]
- else
- w = workers.pop
- end
-
- # send a task to the idle worker ractor
- w << [i, result_port]
-end
-
-# receive a result
-while results.size != N
- n, result, _w = result_port.receive
- results << [n, result]
-end
-
-pp results.sort_by{|n, result| n}
-```
-
-### Pipeline
-
-```ruby
-# pipeline with send/receive
-
-r3 = Ractor.new Ractor.current do |cr|
- cr.send Ractor.receive + 'r3'
-end
-
-r2 = Ractor.new r3 do |r3|
- r3.send Ractor.receive + 'r2'
-end
-
-r1 = Ractor.new r2 do |r2|
- r2.send Ractor.receive + 'r1'
-end
-
-r1 << 'r0'
-p Ractor.receive #=> "r0r1r2r3"
-```
-
-### Supervise
-
-```ruby
-# ring example again
-
-r = Ractor.current
-(1..10).map{|i|
- r = Ractor.new r, i do |r, i|
- r.send Ractor.receive + "r#{i}"
- end
-}
-
-r.send "r0"
-p Ractor.receive #=> "r0r10r9r8r7r6r5r4r3r2r1"
-```
-
-```ruby
-# ring example with an error
-
-r = Ractor.current
-rs = (1..10).map{|i|
- r = Ractor.new r, i do |r, i|
- loop do
- msg = Ractor.receive
- raise if /e/ =~ msg
- r.send msg + "r#{i}"
- end
- end
-}
-
-r.send "r0"
-p Ractor.receive #=> "r0r10r9r8r7r6r5r4r3r2r1"
-r.send "r0"
-p Ractor.select(*rs, Ractor.current) #=> [:receive, "r0r10r9r8r7r6r5r4r3r2r1"]
-r.send "e0"
-p Ractor.select(*rs, Ractor.current)
-#=>
-# <Thread:0x000056262de28bd8 run> terminated with exception (report_on_exception is true):
-# Traceback (most recent call last):
-# 2: from /home/ko1/src/ruby/trunk/test.rb:7:in `block (2 levels) in <main>'
-# 1: from /home/ko1/src/ruby/trunk/test.rb:7:in `loop'
-# /home/ko1/src/ruby/trunk/test.rb:9:in `block (3 levels) in <main>': unhandled exception
-# Traceback (most recent call last):
-# 2: from /home/ko1/src/ruby/trunk/test.rb:7:in `block (2 levels) in <main>'
-# 1: from /home/ko1/src/ruby/trunk/test.rb:7:in `loop'
-# /home/ko1/src/ruby/trunk/test.rb:9:in `block (3 levels) in <main>': unhandled exception
-# 1: from /home/ko1/src/ruby/trunk/test.rb:21:in `<main>'
-# <internal:ractor>:69:in `select': thrown by remote Ractor. (Ractor::RemoteError)
-```
-
-```ruby
-# resend non-error message
-
-r = Ractor.current
-rs = (1..10).map{|i|
- r = Ractor.new r, i do |r, i|
- loop do
- msg = Ractor.receive
- raise if /e/ =~ msg
- r.send msg + "r#{i}"
- end
- end
-}
-
-r.send "r0"
-p Ractor.receive #=> "r0r10r9r8r7r6r5r4r3r2r1"
-r.send "r0"
-p Ractor.select(*rs, Ractor.current)
-[:receive, "r0r10r9r8r7r6r5r4r3r2r1"]
-msg = 'e0'
-begin
- r.send msg
- p Ractor.select(*rs, Ractor.current)
-rescue Ractor::RemoteError
- msg = 'r0'
- retry
-end
-
-#=> <internal:ractor>:100:in `send': The incoming-port is already closed (Ractor::ClosedError)
-# because r == r[-1] is terminated.
-```
-
-```ruby
-# ring example with supervisor and re-start
-
-def make_ractor r, i
- Ractor.new r, i do |r, i|
- loop do
- msg = Ractor.receive
- raise if /e/ =~ msg
- r.send msg + "r#{i}"
- end
- end
-end
-
-r = Ractor.current
-rs = (1..10).map{|i|
- r = make_ractor(r, i)
-}
-
-msg = 'e0' # error causing message
-begin
- r.send msg
- p Ractor.select(*rs, Ractor.current)
-rescue Ractor::RemoteError
- r = rs[-1] = make_ractor(rs[-2], rs.size-1)
- msg = 'x0'
- retry
-end
-
-#=> [:receive, "x0r9r9r8r7r6r5r4r3r2r1"]
-```
diff --git a/doc/regexp/unicode_properties.rdoc b/doc/regexp/unicode_properties.rdoc
deleted file mode 100644
index f1f1f9d6a9..0000000000
--- a/doc/regexp/unicode_properties.rdoc
+++ /dev/null
@@ -1,705 +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{IDS_Unary_Operator}</tt>, <tt>\p{IDSU}</tt>
-- <tt>\p{ID_Compat_Math_Continue}</tt>
-- <tt>\p{ID_Compat_Math_Start}</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{Modifier_Combining_Mark}</tt>, <tt>\p{MCM}</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{InCB_Consonant}</tt>
-- <tt>\p{InCB_Extend}</tt>
-- <tt>\p{InCB_Linker}</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{Garay}</tt>, <tt>\p{Gara}</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{Gurung_Khema}</tt>, <tt>\p{Gukh}</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{Kirat_Rai}</tt>, <tt>\p{Krai}</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{Ol_Onal}</tt>, <tt>\p{Onao}</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{Sunuwar}</tt>, <tt>\p{Sunu}</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{Todhri}</tt>, <tt>\p{Todr}</tt>
-- <tt>\p{Toto}</tt>
-- <tt>\p{Tulu_Tigalari}</tt>, <tt>\p{Tutg}</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_CJK_Unified_Ideographs_Extension_I}</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_Egyptian_Hieroglyphs_Extended_A}</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_Garay}</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_Gurung_Khema}</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_Kirat_Rai}</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_Myanmar_Extended_C}</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_Ol_Onal}</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_Sunuwar}</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_Symbols_for_Legacy_Computing_Supplement}</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_Todhri}</tt>
-- <tt>\p{In_Toto}</tt>
-- <tt>\p{In_Transport_and_Map_Symbols}</tt>
-- <tt>\p{In_Tulu_Tigalari}</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_15_1}</tt>
-- <tt>\p{Age_16_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/ruby/option_dump.md b/doc/ruby/option_dump.md
deleted file mode 100644
index a156484bf6..0000000000
--- a/doc/ruby/option_dump.md
+++ /dev/null
@@ -1,265 +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:
-
-```console
-$ 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):
-
- ```console
- $ 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)
- ```
-
-- `yydebug`: Debugging information from yacc parser generator:
-
- ```
- $ 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: )
- ```
-
-Additional flags can follow dump items.
-
-- `+comment`: Add comments to AST.
-- `+error-tolerant`: Parse in error-tolerant mode.
-- `-optimize`: Disable optimizations for instruction sequences.
diff --git a/doc/ruby/options.md b/doc/ruby/options.md
deleted file mode 100644
index 943b5f967b..0000000000
--- a/doc/ruby/options.md
+++ /dev/null
@@ -1,695 +0,0 @@
-<!---
- CAUTION
-
- This page on docs.ruby-lang.org is displayed in Ruby's help message (-h and --help).
- Please make sure you update the link when renaming or moving this file.
---->
-
-# 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:
-
-```console
-$ ruby -e 'puts "Hello, World."'
-```
-
-Some examples here assume that file `desiderata.txt` exists:
-
-```console
-$ 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:
-
-```console
-$ 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`:
-
-```console
-$ 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:
-
-```console
-$ 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:
-
-```console
-$ 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`:
-
-```console
-$ 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:
-
-```console
-$ 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:
-
-```console
-# 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:
-
-```console
-$ 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:
-
-```console
-$ 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=:
-
-```console
-$ 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:
-
-```console
-$ 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):
-
-```console
-$ 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):
-
-```console
-$ 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:
-
-```ruby
-while gets
- # Your Ruby code.
-end
-```
-
-Note that `gets` reads the next line and sets global variable `$_`
-to the last read line:
-
-```console
-$ 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:
-
-```console
-$ 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:
-
-```console
-$ 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:
-
-```console
-$ 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:
-
-```console
-$ 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`:
-
-```console
-$ 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):
-
-```console
-$ 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:
-
-```rb
-Warning[:experimental] # => true
-Warning[:deprecated] # => false
-Warning[:performance] # => false
-```
-
-They may also be set:
-
-```rb
-Warning[:experimental] = false
-Warning[:deprecated] = true
-Warning[:performance] = true
-```
-
-You can suppress a category by prefixing `no-` to the category name:
-
-```console
-$ 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:
-
-```console
-$ 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:
-
-```console
-$ 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:
-
-```console
-$ 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].
-
-```console
-$ 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].
-
-```console
-$ ruby -e 'puts Encoding::default_internal.nil?'
-true
-$ ruby --internal-encoding=cesu-8 -e 'puts Encoding::default_internal'
-CESU-8
-```
-
-### `--jit`
-
-Option `--jit` is an alias for option `--yjit`, which enables YJIT;
-see additional YJIT options in the [YJIT documentation](rdoc-ref:yjit/yjit.md).
-
-### `--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.
-
diff --git a/doc/security/command_injection.rdoc b/doc/security/command_injection.rdoc
new file mode 100644
index 0000000000..d46e42f7be
--- /dev/null
+++ b/doc/security/command_injection.rdoc
@@ -0,0 +1,15 @@
+= Command Injection
+
+Some Ruby core methods accept string data
+that includes text to be executed as a system command.
+
+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>).
diff --git a/doc/security.rdoc b/doc/security/security.rdoc
index af9970d336..af9970d336 100644
--- a/doc/security.rdoc
+++ b/doc/security/security.rdoc
diff --git a/doc/signals.rdoc b/doc/signals.rdoc
deleted file mode 100644
index 403eb66549..0000000000
--- a/doc/signals.rdoc
+++ /dev/null
@@ -1,106 +0,0 @@
-= Caveats for implementing Signal.trap callbacks
-
-As with implementing signal handlers in C or most other languages,
-all code passed to Signal.trap must be reentrant. If you are not
-familiar with reentrancy, you need to read up on it at
-{Wikipedia}[https://en.wikipedia.org/wiki/Reentrancy_(computing)] or
-elsewhere before reading the rest of this document.
-
-Most importantly, "thread-safety" does not guarantee reentrancy;
-and methods such as Mutex#lock and Mutex#synchronize which are
-commonly used for thread-safety even prevent reentrancy.
-
-== An implementation detail of the Ruby VM
-
-The Ruby VM defers Signal.trap callbacks from running until it is safe
-for its internal data structures, but it does not know when it is safe
-for data structures in YOUR code. Ruby implements deferred signal
-handling by registering short C functions with only
-{async-signal-safe functions}[http://man7.org/linux/man-pages/man7/signal-safety.7.html] as
-signal handlers. These short C functions only do enough tell the VM to
-run callbacks registered via Signal.trap later in the main Ruby Thread.
-
-== Unsafe methods to call in Signal.trap blocks
-
-When in doubt, consider anything not listed as safe below as being
-unsafe.
-
-* Mutex#lock, Mutex#synchronize and any code using them are explicitly
- unsafe. This includes Monitor in the standard library which uses
- Mutex to provide reentrancy.
-
-* Dir.chdir with block
-
-* any IO write operations when IO#sync is false;
- including IO#write, IO#write_nonblock, IO#puts.
- Pipes and sockets default to `IO#sync = true', so it is safe to
- write to them unless IO#sync was disabled.
-
-* File#flock, as the underlying flock(2) call is not specified by POSIX
-
-== Commonly safe operations inside Signal.trap blocks
-
-* Assignment and retrieval of local, instance, and class variables
-
-* Most object allocations and initializations of common types
- including Array, Hash, String, Struct, Time.
-
-* Common Array, Hash, String, Struct operations which do not execute a block
- are generally safe; but beware if iteration is occurring elsewhere.
-
-* Hash#[], Hash#[]= (unless Hash.new was given an unsafe block)
-
-* Thread::Queue#push and Thread::SizedQueue#push (since Ruby 2.1)
-
-* Creating a new Thread via Thread.new/Thread.start can used to get
- around the unusability of Mutexes inside a signal handler
-
-* Signal.trap is safe to use inside blocks passed to Signal.trap
-
-* arithmetic on Integer and Float (`+', `-', '%', '*', '/')
-
- Additionally, signal handlers do not run between two successive
- local variable accesses, so shortcuts such as `+=' and `-=' will
- not trigger a data race when used on Integer and Float classes in
- signal handlers.
-
-== System call wrapper methods which are safe inside Signal.trap
-
-Since Ruby has wrappers around many
-{async-signal-safe C functions}[http://man7.org/linux/man-pages/man7/signal-safety.7.html]
-the corresponding wrappers for many IO, File, Dir, and Socket methods
-are safe.
-
-(Incomplete list)
-
-* Dir.chdir (without block arg)
-* Dir.mkdir
-* Dir.open
-* File#truncate
-* File.link
-* File.open
-* File.readlink
-* File.rename
-* File.stat
-* File.symlink
-* File.truncate
-* File.unlink
-* File.utime
-* IO#close
-* IO#dup
-* IO#fsync
-* IO#read
-* IO#read_nonblock
-* IO#stat
-* IO#sysread
-* IO#syswrite
-* IO.select
-* IO.pipe
-* Process.clock_gettime
-* Process.exit!
-* Process.fork
-* Process.kill
-* Process.pid
-* Process.ppid
-* Process.waitpid
-...
diff --git a/doc/standard_library.md b/doc/standard_library.md
index 0c48ac0cdd..782db10c37 100644
--- a/doc/standard_library.md
+++ b/doc/standard_library.md
@@ -11,6 +11,7 @@ of each.
- `MakeMakefile`: A module used to generate a Makefile for C extensions
- `RbConfig`: Information about your Ruby configuration and build
- `Gem`: A package management framework for Ruby
+- `Pathname`: Representation of the name of a file or directory on the filesystem. Pathname is a core class, but only methods that depend on other libraries are provided as a library.
## Extensions
@@ -58,7 +59,6 @@ of each.
- Time ([GitHub][time]): Extends the Time class with methods for parsing and conversion
- Timeout ([GitHub][timeout]): Auto-terminate potentially long-running operations in Ruby
- TmpDir ([GitHub][tmpdir]): Extends the Dir class to manage the OS temporary file path
-- TSort ([GitHub][tsort]): Topological sorting using Tarjan's algorithm
- UN ([GitHub][un]): Utilities to replace common UNIX commands
- URI ([GitHub][uri]): A Ruby module providing support for Uniform Resource Identifiers
- YAML ([GitHub][yaml]): The Ruby client library for the Psych YAML implementation
@@ -75,7 +75,6 @@ of each.
- IO#wait ([GitHub][io-wait]): Provides the feature for waiting until IO is readable or writable without blocking.
- JSON ([GitHub][json]): Implements JavaScript Object Notation for Ruby
- OpenSSL ([GitHub][openssl]): Provides SSL, TLS, and general-purpose cryptography for Ruby
-- Pathname ([GitHub][pathname]): Representation of the name of a file or directory on the filesystem
- Psych ([GitHub][psych]): A YAML parser and emitter for Ruby
- StringIO ([GitHub][stringio]): Pseudo-I/O on String objects
- StringScanner ([GitHub][strscan]): Provides lexical scanning operations on a String
@@ -96,9 +95,7 @@ of each.
- [test-unit]: A compatibility layer for MiniTest
- [rexml][rexml-doc] ([GitHub][rexml]): An XML toolkit for Ruby
- [rss]: A family of libraries supporting various XML-based "feeds"
-- [net-ftp]: Support for the File Transfer Protocol
- [net-imap]: Ruby client API for the Internet Message Access Protocol
-- [net-pop]: Ruby client library for POP3
- [net-smtp]: Simple Mail Transfer Protocol client library for Ruby
- [matrix]: Represents a mathematical matrix
- [prime]: Prime numbers and factorization library
@@ -126,6 +123,8 @@ of each.
- [reline][reline-doc] ([GitHub][reline]): GNU Readline and Editline in a pure Ruby implementation
- [readline]: Wrapper for the Readline extension and Reline
- [fiddle]: A libffi wrapper for Ruby
+- [tsort]: Topological sorting using Tarjan's algorithm
+- [win32-registry]: Registry accessor library for the Windows platform.
## Tools
@@ -164,10 +163,8 @@ of each.
[matrix]: https://github.com/ruby/matrix
[minitest]: https://github.com/seattlerb/minitest
[mutex_m]: https://github.com/ruby/mutex_m
-[net-ftp]: https://github.com/ruby/net-ftp
[net-http]: https://github.com/ruby/net-http
[net-imap]: https://github.com/ruby/net-imap
-[net-pop]: https://github.com/ruby/net-pop
[net-smtp]: https://github.com/ruby/net-smtp
[nkf]: https://github.com/ruby/nkf
[observer]: https://github.com/ruby/observer
@@ -212,6 +209,7 @@ of each.
[uri]: https://github.com/ruby/uri
[weakref]: https://github.com/ruby/weakref
[win32ole]: https://github.com/ruby/win32ole
+[win32-registry]: https://github.com/ruby/win32-registry
[yaml]: https://github.com/ruby/yaml
[zlib]: https://github.com/ruby/zlib
diff --git a/doc/strftime_formatting.rdoc b/doc/strftime_formatting.rdoc
deleted file mode 100644
index 5c7b33155d..0000000000
--- a/doc/strftime_formatting.rdoc
+++ /dev/null
@@ -1,527 +0,0 @@
-= 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:
-
-- Date#strftime.
-- DateTime#strftime.
-- Time#strftime.
-
-Each of these methods takes optional argument +format+,
-which has zero or more embedded _format_ _specifications_ (see below).
-
-Each of these methods returns the string resulting from replacing each
-format specification embedded in +format+ with a string form
-of one or more parts of the date or time.
-
-A simple example:
-
- Time.now.strftime('%H:%M:%S') # => "14:02:07"
-
-A format specification has the form:
-
- %[flags][width]conversion
-
-It consists of:
-
-- A leading percent character.
-- Zero or more _flags_ (each is a character).
-- An optional _width_ _specifier_ (an integer).
-- A _conversion_ _specifier_ (a character).
-
-Except for the leading percent character,
-the only required part is the conversion specifier, so we begin with that.
-
-== Conversion Specifiers
-
-=== \Date (Year, Month, Day)
-
-- <tt>%Y</tt> - Year including century, zero-padded:
-
- Time.now.strftime('%Y') # => "2022"
- Time.new(-1000).strftime('%Y') # => "-1000" # Before common era.
- Time.new(10000).strftime('%Y') # => "10000" # Far future.
- Time.new(10).strftime('%Y') # => "0010" # Zero-padded by default.
-
-- <tt>%y</tt> - Year without century, in range (0.99), zero-padded:
-
- Time.now.strftime('%y') # => "22"
- Time.new(1).strftime('%y') # => "01" # Zero-padded by default.
-
-- <tt>%C</tt> - Century, zero-padded:
-
- Time.now.strftime('%C') # => "20"
- Time.new(-1000).strftime('%C') # => "-10" # Before common era.
- Time.new(10000).strftime('%C') # => "100" # Far future.
- Time.new(100).strftime('%C') # => "01" # Zero-padded by default.
-
-- <tt>%m</tt> - Month of the year, in range (1..12), zero-padded:
-
- Time.new(2022, 1).strftime('%m') # => "01" # Zero-padded by default.
- Time.new(2022, 12).strftime('%m') # => "12"
-
-- <tt>%B</tt> - Full month name, capitalized:
-
- Time.new(2022, 1).strftime('%B') # => "January"
- Time.new(2022, 12).strftime('%B') # => "December"
-
-- <tt>%b</tt> - Abbreviated month name, capitalized:
-
- Time.new(2022, 1).strftime('%b') # => "Jan"
- Time.new(2022, 12).strftime('%h') # => "Dec"
-
-- <tt>%h</tt> - Same as <tt>%b</tt>.
-
-- <tt>%d</tt> - Day of the month, in range (1..31), zero-padded:
-
- Time.new(2002, 1, 1).strftime('%d') # => "01"
- Time.new(2002, 1, 31).strftime('%d') # => "31"
-
-- <tt>%e</tt> - Day of the month, in range (1..31), blank-padded:
-
- Time.new(2002, 1, 1).strftime('%e') # => " 1"
- Time.new(2002, 1, 31).strftime('%e') # => "31"
-
-- <tt>%j</tt> - Day of the year, in range (1..366), zero-padded:
-
- Time.new(2002, 1, 1).strftime('%j') # => "001"
- Time.new(2002, 12, 31).strftime('%j') # => "365"
-
-=== \Time (Hour, Minute, Second, Subsecond)
-
-- <tt>%H</tt> - Hour of the day, in range (0..23), zero-padded:
-
- Time.new(2022, 1, 1, 1).strftime('%H') # => "01"
- Time.new(2022, 1, 1, 13).strftime('%H') # => "13"
-
-- <tt>%k</tt> - Hour of the day, in range (0..23), blank-padded:
-
- Time.new(2022, 1, 1, 1).strftime('%k') # => " 1"
- Time.new(2022, 1, 1, 13).strftime('%k') # => "13"
-
-- <tt>%I</tt> - Hour of the day, in range (1..12), zero-padded:
-
- Time.new(2022, 1, 1, 1).strftime('%I') # => "01"
- Time.new(2022, 1, 1, 13).strftime('%I') # => "01"
-
-- <tt>%l</tt> - Hour of the day, in range (1..12), blank-padded:
-
- Time.new(2022, 1, 1, 1).strftime('%l') # => " 1"
- Time.new(2022, 1, 1, 13).strftime('%l') # => " 1"
-
-- <tt>%P</tt> - Meridian indicator, lowercase:
-
- Time.new(2022, 1, 1, 1).strftime('%P') # => "am"
- Time.new(2022, 1, 1, 13).strftime('%P') # => "pm"
-
-- <tt>%p</tt> - Meridian indicator, uppercase:
-
- Time.new(2022, 1, 1, 1).strftime('%p') # => "AM"
- Time.new(2022, 1, 1, 13).strftime('%p') # => "PM"
-
-- <tt>%M</tt> - Minute of the hour, in range (0..59), zero-padded:
-
- Time.new(2022, 1, 1, 1, 0, 0).strftime('%M') # => "00"
-
-- <tt>%S</tt> - Second of the minute in range (0..59), zero-padded:
-
- Time.new(2022, 1, 1, 1, 0, 0, 0).strftime('%S') # => "00"
-
-- <tt>%L</tt> - Millisecond of the second, in range (0..999), zero-padded:
-
- Time.new(2022, 1, 1, 1, 0, 0, 0).strftime('%L') # => "000"
-
-- <tt>%N</tt> - Fractional seconds, default width is 9 digits (nanoseconds):
-
- t = Time.now # => 2022-06-29 07:10:20.3230914 -0500
- t.strftime('%N') # => "323091400" # Default.
-
- Use {width specifiers}[rdoc-ref:strftime_formatting.rdoc@Width+Specifiers]
- to adjust units:
-
- t.strftime('%3N') # => "323" # Milliseconds.
- t.strftime('%6N') # => "323091" # Microseconds.
- t.strftime('%9N') # => "323091400" # Nanoseconds.
- t.strftime('%12N') # => "323091400000" # Picoseconds.
- t.strftime('%15N') # => "323091400000000" # Femptoseconds.
- t.strftime('%18N') # => "323091400000000000" # Attoseconds.
- t.strftime('%21N') # => "323091400000000000000" # Zeptoseconds.
- t.strftime('%24N') # => "323091400000000000000000" # Yoctoseconds.
-
-- <tt>%s</tt> - Number of seconds since the epoch:
-
- Time.now.strftime('%s') # => "1656505136"
-
-=== Timezone
-
-- <tt>%z</tt> - Timezone as hour and minute offset from UTC:
-
- Time.now.strftime('%z') # => "-0500"
-
-- <tt>%Z</tt> - Timezone name (platform-dependent):
-
- Time.now.strftime('%Z') # => "Central Daylight Time"
-
-=== Weekday
-
-- <tt>%A</tt> - Full weekday name:
-
- Time.now.strftime('%A') # => "Wednesday"
-
-- <tt>%a</tt> - Abbreviated weekday name:
-
- Time.now.strftime('%a') # => "Wed"
-
-- <tt>%u</tt> - Day of the week, in range (1..7), Monday is 1:
-
- t = Time.new(2022, 6, 26) # => 2022-06-26 00:00:00 -0500
- t.strftime('%a') # => "Sun"
- t.strftime('%u') # => "7"
-
-- <tt>%w</tt> - Day of the week, in range (0..6), Sunday is 0:
-
- t = Time.new(2022, 6, 26) # => 2022-06-26 00:00:00 -0500
- t.strftime('%a') # => "Sun"
- t.strftime('%w') # => "0"
-
-=== Week Number
-
-- <tt>%U</tt> - Week number of the year, in range (0..53), zero-padded,
- where each week begins on a Sunday:
-
- t = Time.new(2022, 6, 26) # => 2022-06-26 00:00:00 -0500
- t.strftime('%a') # => "Sun"
- t.strftime('%U') # => "26"
-
-- <tt>%W</tt> - Week number of the year, in range (0..53), zero-padded,
- where each week begins on a Monday:
-
- t = Time.new(2022, 6, 26) # => 2022-06-26 00:00:00 -0500
- t.strftime('%a') # => "Sun"
- t.strftime('%W') # => "25"
-
-=== Week Dates
-
-See {ISO 8601 week dates}[https://en.wikipedia.org/wiki/ISO_8601#Week_dates].
-
- t0 = Time.new(2023, 1, 1) # => 2023-01-01 00:00:00 -0600
- t1 = Time.new(2024, 1, 1) # => 2024-01-01 00:00:00 -0600
-
-- <tt>%G</tt> - Week-based year:
-
- t0.strftime('%G') # => "2022"
- t1.strftime('%G') # => "2024"
-
-- <tt>%g</tt> - Week-based year without century, in range (0..99), zero-padded:
-
- t0.strftime('%g') # => "22"
- t1.strftime('%g') # => "24"
-
-- <tt>%V</tt> - Week number of the week-based year, in range (1..53),
- zero-padded:
-
- t0.strftime('%V') # => "52"
- t1.strftime('%V') # => "01"
-
-=== Literals
-
-- <tt>%n</tt> - Newline character "\n":
-
- Time.now.strftime('%n') # => "\n"
-
-- <tt>%t</tt> - Tab character "\t":
-
- Time.now.strftime('%t') # => "\t"
-
-- <tt>%%</tt> - Percent character '%':
-
- Time.now.strftime('%%') # => "%"
-
-=== Shorthand Conversion Specifiers
-
-Each shorthand specifier here is shown with its corresponding
-longhand specifier.
-
-- <tt>%c</tt> - \Date and time:
-
- Time.now.strftime('%c') # => "Wed Jun 29 08:01:41 2022"
- Time.now.strftime('%a %b %e %T %Y') # => "Wed Jun 29 08:02:07 2022"
-
-- <tt>%D</tt> - \Date:
-
- Time.now.strftime('%D') # => "06/29/22"
- Time.now.strftime('%m/%d/%y') # => "06/29/22"
-
-- <tt>%F</tt> - ISO 8601 date:
-
- Time.now.strftime('%F') # => "2022-06-29"
- Time.now.strftime('%Y-%m-%d') # => "2022-06-29"
-
-- <tt>%v</tt> - VMS date:
-
- Time.now.strftime('%v') # => "29-JUN-2022"
- Time.now.strftime('%e-%^b-%4Y') # => "29-JUN-2022"
-
-- <tt>%x</tt> - Same as <tt>%D</tt>.
-
-- <tt>%X</tt> - Same as <tt>%T</tt>.
-
-- <tt>%r</tt> - 12-hour time:
-
- Time.new(2022, 1, 1, 1).strftime('%r') # => "01:00:00 AM"
- Time.new(2022, 1, 1, 1).strftime('%I:%M:%S %p') # => "01:00:00 AM"
- Time.new(2022, 1, 1, 13).strftime('%r') # => "01:00:00 PM"
- Time.new(2022, 1, 1, 13).strftime('%I:%M:%S %p') # => "01:00:00 PM"
-
-- <tt>%R</tt> - 24-hour time:
-
- Time.new(2022, 1, 1, 1).strftime('%R') # => "01:00"
- Time.new(2022, 1, 1, 1).strftime('%H:%M') # => "01:00"
- Time.new(2022, 1, 1, 13).strftime('%R') # => "13:00"
- Time.new(2022, 1, 1, 13).strftime('%H:%M') # => "13:00"
-
-- <tt>%T</tt> - 24-hour time:
-
- Time.new(2022, 1, 1, 1).strftime('%T') # => "01:00:00"
- Time.new(2022, 1, 1, 1).strftime('%H:%M:%S') # => "01:00:00"
- Time.new(2022, 1, 1, 13).strftime('%T') # => "13:00:00"
- Time.new(2022, 1, 1, 13).strftime('%H:%M:%S') # => "13:00:00"
-
-- <tt>%+</tt> (not supported in Time#strftime) - \Date and time:
-
- DateTime.now.strftime('%+')
- # => "Wed Jun 29 08:31:53 -05:00 2022"
- DateTime.now.strftime('%a %b %e %H:%M:%S %Z %Y')
- # => "Wed Jun 29 08:32:18 -05:00 2022"
-
-== Flags
-
-Flags may affect certain formatting specifications.
-
-Multiple flags may be given with a single conversion specified;
-order does not matter.
-
-=== Padding Flags
-
-- <tt>0</tt> - Pad with zeroes:
-
- Time.new(10).strftime('%0Y') # => "0010"
-
-- <tt>_</tt> - Pad with blanks:
-
- Time.new(10).strftime('%_Y') # => " 10"
-
-- <tt>-</tt> - Don't pad:
-
- Time.new(10).strftime('%-Y') # => "10"
-
-=== Casing Flags
-
-- <tt>^</tt> - Upcase result:
-
- Time.new(2022, 1).strftime('%B') # => "January" # No casing flag.
- Time.new(2022, 1).strftime('%^B') # => "JANUARY"
-
-- <tt>#</tt> - Swapcase result:
-
- Time.now.strftime('%p') # => "AM"
- Time.now.strftime('%^p') # => "AM"
- Time.now.strftime('%#p') # => "am"
-
-=== Timezone Flags
-
-- <tt>:</tt> - Put timezone as colon-separated hours and minutes:
-
- Time.now.strftime('%:z') # => "-05:00"
-
-- <tt>::</tt> - Put timezone as colon-separated hours, minutes, and seconds:
-
- Time.now.strftime('%::z') # => "-05:00:00"
-
-== Width Specifiers
-
-The integer width specifier gives a minimum width for the returned string:
-
- Time.new(2002).strftime('%Y') # => "2002" # No width specifier.
- Time.new(2002).strftime('%10Y') # => "0000002002"
- Time.new(2002, 12).strftime('%B') # => "December" # No width specifier.
- Time.new(2002, 12).strftime('%10B') # => " December"
- Time.new(2002, 12).strftime('%3B') # => "December" # Ignored if too small.
-
-= Specialized Format Strings
-
-Here are a few specialized format strings,
-each based on an external standard.
-
-== HTTP Format
-
-The HTTP date format is based on
-{RFC 2616}[https://www.rfc-editor.org/rfc/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>
- # Return HTTP-formatted string.
- httpdate = d.httpdate # => "Sat, 03 Feb 2001 00:00:00 GMT"
- # Return new date parsed from HTTP-formatted string.
- Date.httpdate(httpdate) # => #<Date: 2001-02-03>
- # Return hash parsed from HTTP-formatted string.
- Date._httpdate(httpdate)
- # => {:wday=>6, :mday=>3, :mon=>2, :year=>2001, :hour=>0, :min=>0, :sec=>0, :zone=>"GMT", :offset=>0}
-
-== RFC 3339 Format
-
-The RFC 3339 date format is based on
-{RFC 3339}[https://www.rfc-editor.org/rfc/rfc3339]:
-
- d = Date.new(2001, 2, 3) # => #<Date: 2001-02-03>
- # Return 3339-formatted string.
- rfc3339 = d.rfc3339 # => "2001-02-03T00:00:00+00:00"
- # Return new date parsed from 3339-formatted string.
- Date.rfc3339(rfc3339) # => #<Date: 2001-02-03>
- # Return hash parsed from 3339-formatted string.
- Date._rfc3339(rfc3339)
- # => {:year=>2001, :mon=>2, :mday=>3, :hour=>0, :min=>0, :sec=>0, :zone=>"+00:00", :offset=>0}
-
-== RFC 2822 Format
-
-The RFC 2822 date format is based on
-{RFC 2822}[https://www.rfc-editor.org/rfc/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>
- # Return 2822-formatted string.
- rfc2822 = d.rfc2822 # => "Sat, 3 Feb 2001 00:00:00 +0000"
- # Return new date parsed from 2822-formatted string.
- Date.rfc2822(rfc2822) # => #<Date: 2001-02-03>
- # Return hash parsed from 2822-formatted string.
- 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
-
-The JIS X 0301 format includes the
-{Japanese era name}[https://en.wikipedia.org/wiki/Japanese_era_name],
-and treats dates in the format <tt>'%Y-%m-%d'</tt>
-with the first letter of the romanized era name prefixed:
-
- d = Date.new(2001, 2, 3) # => #<Date: 2001-02-03>
- # Return 0301-formatted string.
- jisx0301 = d.jisx0301 # => "H13.02.03"
- # Return new date parsed from 0301-formatted string.
- Date.jisx0301(jisx0301) # => #<Date: 2001-02-03>
- # Return hash parsed from 0301-formatted string.
- Date._jisx0301(jisx0301) # => {:year=>2001, :mon=>2, :mday=>3}
-
-== ISO 8601 Format Specifications
-
-This section shows format specifications that are compatible with
-{ISO 8601}[https://en.wikipedia.org/wiki/ISO_8601].
-Details for various formats may be seen at the links.
-
-Examples in this section assume:
-
- t = Time.now # => 2022-06-29 16:49:25.465246 -0500
-
-=== Dates
-
-See {ISO 8601 dates}[https://en.wikipedia.org/wiki/ISO_8601#Dates].
-
-- {Years}[https://en.wikipedia.org/wiki/ISO_8601#Years]:
-
- - Basic year (+YYYY+):
-
- t.strftime('%Y') # => "2022"
-
- - Expanded year (<tt>±YYYYY</tt>):
-
- t.strftime('+%5Y') # => "+02022"
- t.strftime('-%5Y') # => "-02022"
-
-- {Calendar dates}[https://en.wikipedia.org/wiki/ISO_8601#Calendar_dates]:
-
- - Basic date (+YYYYMMDD+):
-
- t.strftime('%Y%m%d') # => "20220629"
-
- - Extended date (<tt>YYYY-MM-DD</tt>):
-
- t.strftime('%Y-%m-%d') # => "2022-06-29"
-
- - Reduced extended date (<tt>YYYY-MM</tt>):
-
- t.strftime('%Y-%m') # => "2022-06"
-
-- {Week dates}[https://en.wikipedia.org/wiki/ISO_8601#Week_dates]:
-
- - Basic date (+YYYYWww+ or +YYYYWwwD+):
-
- t.strftime('%Y%Ww') # => "202226w"
- t.strftime('%Y%Ww%u') # => "202226w3"
-
- - Extended date (<tt>YYYY-Www</tt> or <tt>YYYY-Www-D<tt>):
-
- t.strftime('%Y-%Ww') # => "2022-26w"
- t.strftime('%Y-%Ww-%u') # => "2022-26w-3"
-
-- {Ordinal dates}[https://en.wikipedia.org/wiki/ISO_8601#Ordinal_dates]:
-
- - Basic date (+YYYYDDD+):
-
- t.strftime('%Y%j') # => "2022180"
-
- - Extended date (<tt>YYYY-DDD</tt>):
-
- t.strftime('%Y-%j') # => "2022-180"
-
-=== Times
-
-See {ISO 8601 times}[https://en.wikipedia.org/wiki/ISO_8601#Times].
-
-- Times:
-
- - Basic time (+Thhmmss.sss+, +Thhmmss+, +Thhmm+, or +Thh+):
-
- t.strftime('T%H%M%S.%L') # => "T164925.465"
- t.strftime('T%H%M%S') # => "T164925"
- t.strftime('T%H%M') # => "T1649"
- t.strftime('T%H') # => "T16"
-
- - Extended time (+Thh:mm:ss.sss+, +Thh:mm:ss+, or +Thh:mm+):
-
- t.strftime('T%H:%M:%S.%L') # => "T16:49:25.465"
- t.strftime('T%H:%M:%S') # => "T16:49:25"
- t.strftime('T%H:%M') # => "T16:49"
-
-- {Time zone designators}[https://en.wikipedia.org/wiki/ISO_8601#Time_zone_designators]:
-
- - Timezone (+time+ represents a valid time,
- +hh+ represents a valid 2-digit hour,
- and +mm+ represents a valid 2-digit minute):
-
- - Basic timezone (<tt>time±hhmm</tt>, <tt>time±hh</tt>, or +timeZ+):
-
- t.strftime('T%H%M%S%z') # => "T164925-0500"
- t.strftime('T%H%M%S%z').slice(0..-3) # => "T164925-05"
- t.strftime('T%H%M%SZ') # => "T164925Z"
-
- - Extended timezone (<tt>time±hh:mm</tt>):
-
- t.strftime('T%H:%M:%S%z') # => "T16:49:25-0500"
-
- - See also:
-
- - {Local time (unqualified)}[https://en.wikipedia.org/wiki/ISO_8601#Local_time_(unqualified)].
- - {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
-
-See {ISO 8601 Combined date and time representations}[https://en.wikipedia.org/wiki/ISO_8601#Combined_date_and_time_representations].
-
-An ISO 8601 combined date and time representation may be any
-ISO 8601 date and any ISO 8601 time,
-separated by the letter +T+.
-
-For the relevant +strftime+ formats, see
-{Dates}[rdoc-ref:strftime_formatting.rdoc@Dates]
-and {Times}[rdoc-ref:strftime_formatting.rdoc@Times] above.
diff --git a/doc/string.rb b/doc/string.rb
index 9ed97d49f6..4dac94e93a 100644
--- a/doc/string.rb
+++ b/doc/string.rb
@@ -159,156 +159,17 @@
# - #rstrip, #rstrip!: Strip trailing whitespace.
# - #strip, #strip!: Strip leading and trailing whitespace.
#
-# == +String+ Slices
-#
-# A _slice_ of a string is a substring selected by certain criteria.
-#
-# These instance methods utilize slicing:
-#
-# - String#[] (aliased as String#slice): Returns a slice copied from +self+.
-# - String#[]=: Mutates +self+ with the slice replaced.
-# - String#slice!: Mutates +self+ with the slice removed and returns the removed slice.
-#
-# Each of the above methods takes arguments that determine the slice
-# to be copied or replaced.
-#
-# The arguments have several forms.
-# For a string +string+, the forms are:
-#
-# - <tt>string[index]</tt>
-# - <tt>string[start, length]</tt>
-# - <tt>string[range]</tt>
-# - <tt>string[regexp, capture = 0]</tt>
-# - <tt>string[substring]</tt>
-#
-# <b><tt>string[index]</tt></b>
-#
-# When a non-negative integer argument +index+ is given,
-# the slice is the 1-character substring found in +self+ at character offset +index+:
-#
-# 'bar'[0] # => "b"
-# 'bar'[2] # => "r"
-# 'bar'[20] # => nil
-# 'теÑÑ‚'[2] # => "Ñ"
-# 'ã“ã‚“ã«ã¡ã¯'[4] # => "ã¯"
-#
-# When a negative integer +index+ is given,
-# the slice begins at the offset given by counting backward from the end of +self+:
-#
-# 'bar'[-3] # => "b"
-# 'bar'[-1] # => "r"
-# 'bar'[-20] # => nil
-#
-# <b><tt>string[start, length]</tt></b>
-#
-# When non-negative integer arguments +start+ and +length+ are given,
-# the slice begins at character offset +start+, if it exists,
-# and continues for +length+ characters, if available:
-#
-# 'foo'[0, 2] # => "fo"
-# 'теÑÑ‚'[1, 2] # => "еÑ"
-# 'ã“ã‚“ã«ã¡ã¯'[2, 2] # => "ã«ã¡"
-# # Zero length.
-# 'foo'[2, 0] # => ""
-# # Length not entirely available.
-# 'foo'[1, 200] # => "oo"
-# # Start out of range.
-# 'foo'[4, 2] # => nil
-#
-# Special case: if +start+ equals the length of +self+,
-# the slice is a new empty string:
-#
-# 'foo'[3, 2] # => ""
-# 'foo'[3, 200] # => ""
-#
-# When a negative +start+ and non-negative +length+ are given,
-# the slice begins by counting backward from the end of +self+,
-# and continues for +length+ characters, if available:
-#
-# 'foo'[-2, 2] # => "oo"
-# 'foo'[-2, 200] # => "oo"
-# # Start out of range.
-# 'foo'[-4, 2] # => nil
-#
-# When a negative +length+ is given, there is no slice:
-#
-# 'foo'[1, -1] # => nil
-# 'foo'[-2, -1] # => nil
-#
-# <b><tt>string[range]</tt></b>
-#
-# When a Range argument +range+ is given,
-# it creates a substring of +string+ using the indices in +range+.
-# The slice is then determined as above:
-#
-# 'foo'[0..1] # => "fo"
-# 'foo'[0, 2] # => "fo"
-#
-# 'foo'[2...2] # => ""
-# 'foo'[2, 0] # => ""
-#
-# 'foo'[1..200] # => "oo"
-# 'foo'[1, 200] # => "oo"
-#
-# 'foo'[4..5] # => nil
-# 'foo'[4, 2] # => nil
-#
-# 'foo'[-4..-3] # => nil
-# 'foo'[-4, 2] # => nil
-#
-# 'foo'[3..4] # => ""
-# 'foo'[3, 2] # => ""
-#
-# 'foo'[-2..-1] # => "oo"
-# 'foo'[-2, 2] # => "oo"
-#
-# 'foo'[-2..197] # => "oo"
-# 'foo'[-2, 200] # => "oo"
-#
-# <b><tt>string[regexp, capture = 0]</tt></b>
-#
-# When the Regexp argument +regexp+ is given,
-# and the +capture+ argument is <tt>0</tt>,
-# the slice is the first matching substring found in +self+:
-#
-# 'foo'[/o/] # => "o"
-# 'foo'[/x/] # => nil
-# s = 'hello there'
-# s[/[aeiou](.)\1/] # => "ell"
-# s[/[aeiou](.)\1/, 0] # => "ell"
-#
-# If the argument +capture+ is provided and not <tt>0</tt>,
-# it should be either a capture group index (integer)
-# or a capture group name (String or Symbol);
-# the slice is the specified capture (see Regexp@Groups and Captures):
-#
-# s = 'hello there'
-# s[/[aeiou](.)\1/, 1] # => "l"
-# s[/(?<vowel>[aeiou])(?<non_vowel>[^aeiou])/, "non_vowel"] # => "l"
-# s[/(?<vowel>[aeiou])(?<non_vowel>[^aeiou])/, :vowel] # => "e"
-#
-# If an invalid capture group index is given, there is no slice.
-# If an invalid capture group name is given, +IndexError+ is raised.
-#
-# <b><tt>string[substring]</tt></b>
-#
-# When the single +String+ argument +substring+ is given,
-# it returns the substring from +self+ if found, otherwise +nil+:
-#
-# 'foo'['oo'] # => "oo"
-# 'foo'['xx'] # => nil
-#
# == What's Here
#
# First, what's elsewhere. Class +String+:
#
-# - Inherits from the {Object class}[rdoc-ref:Object@What-27s+Here].
-# - Includes the {Comparable module}[rdoc-ref:Comparable@What-27s+Here].
+# - Inherits from the {Object class}[rdoc-ref:Object@Whats+Here].
+# - Includes the {Comparable module}[rdoc-ref:Comparable@Whats+Here].
#
# Here, class +String+ provides methods that are useful for:
#
# - {Creating a \String}[rdoc-ref:String@Creating+a+String].
-# - {Freezing/Unfreezing a \String}[rdoc-ref:String@Freezing-2FUnfreezing].
+# - {Freezing/Unfreezing a \String}[rdoc-ref:String@FreezingUnfreezing].
# - {Querying a \String}[rdoc-ref:String@Querying].
# - {Comparing Strings}[rdoc-ref:String@Comparing].
# - {Modifying a \String}[rdoc-ref:String@Modifying].
@@ -333,10 +194,10 @@
#
# _Counts_
#
-# - #length (aliased as #size): Returns the count of characters (not bytes).
-# - #empty?: Returns whether the length of +self+ is zero.
# - #bytesize: Returns the count of bytes.
# - #count: Returns the count of substrings matching given strings.
+# - #empty?: Returns whether the length of +self+ is zero.
+# - #length (aliased as #size): Returns the count of characters (not bytes).
#
# _Substrings_
#
@@ -387,6 +248,7 @@
# - #<<: Returns +self+ concatenated with a given string or integer.
# - #append_as_bytes: Returns +self+ concatenated with strings without performing any
# encoding validation or conversion.
+# - #prepend: Prefixes to +self+ the concatenation of given other strings.
#
# _Substitution_
#
@@ -396,7 +258,7 @@
# - #gsub!: Replaces each substring that matches a given pattern with a given replacement string;
# returns +self+ if any changes, +nil+ otherwise.
# - #succ! (aliased as #next!): Returns +self+ modified to become its own successor.
-# - #initialize_copy (aliased as #replace): Returns +self+ with its entire content replaced by a given string.
+# - #replace: Returns +self+ with its entire content replaced by a given string.
# - #reverse!: Returns +self+ with its characters in reverse order.
# - #setbyte: Sets the byte at a given integer offset to a given value; returns the argument.
# - #tr!: Replaces specified characters in +self+ with specified replacement characters;
@@ -447,7 +309,6 @@
# - #+: Returns the concatenation of +self+ and a given other string.
# - #center: Returns a copy of +self+, centered by specified padding.
# - #concat: Returns the concatenation of +self+ with given other strings.
-# - #prepend: Returns the concatenation of a given other string with +self+.
# - #ljust: Returns a copy of +self+ of a given length, right-padded with a given other string.
# - #rjust: Returns a copy of +self+ of a given length, left-padded with a given other string.
#
@@ -461,8 +322,7 @@
# _Substitution_
#
# - #dump: Returns a printable version of +self+, enclosed in double-quotes.
-# - #undump: Returns a copy of +self+ with all <tt>\xNN</tt> notations replaced by <tt>\uNNNN</tt> notations
-# and all escaped characters unescaped.
+# - #undump: Inverse of #dump; returns a copy of +self+ with changes of the kinds made by #dump "undone."
# - #sub: Returns a copy of +self+ with the first substring matching a given pattern
# replaced with a given replacement string.
# - #gsub: Returns a copy of +self+ with each substring that matches a given pattern
@@ -538,8 +398,10 @@
# - #hex: Returns the integer value of the leading characters, interpreted as hexadecimal digits.
# - #oct: Returns the integer value of the leading characters, interpreted as octal digits.
# - #ord: Returns the integer ordinal of the first character in +self+.
+# - #to_c: Returns the complex value of leading characters, interpreted as a complex number.
# - #to_i: Returns the integer value of leading characters, interpreted as an integer.
# - #to_f: Returns the floating-point value of leading characters, interpreted as a floating-point number.
+# - #to_r: Returns the rational value of leading characters, interpreted as a rational.
#
# <em>Strings and Symbols</em>
#
diff --git a/doc/string/aref.rdoc b/doc/string/aref.rdoc
new file mode 100644
index 0000000000..a9ab8857bc
--- /dev/null
+++ b/doc/string/aref.rdoc
@@ -0,0 +1,96 @@
+Returns the substring of +self+ specified by the arguments.
+
+<b>Form <tt>self[offset]</tt></b>
+
+With non-negative integer argument +offset+ given,
+returns the 1-character substring found in self at character offset +offset+:
+
+ 'hello'[0] # => "h"
+ 'hello'[4] # => "o"
+ 'hello'[5] # => nil
+ 'ã“ã‚“ã«ã¡ã¯'[4] # => "ã¯"
+
+With negative integer argument +offset+ given,
+counts backward from the end of +self+:
+
+ 'hello'[-1] # => "o"
+ 'hello'[-5] # => "h"
+ 'hello'[-6] # => nil
+
+<b>Form <tt>self[offset, size]</tt></b>
+
+With integer arguments +offset+ and +size+ given,
+returns a substring of size +size+ characters (as available)
+beginning at character offset specified by +offset+.
+
+If argument +offset+ is non-negative,
+the offset is +offset+:
+
+ 'hello'[0, 1] # => "h"
+ 'hello'[0, 5] # => "hello"
+ 'hello'[0, 6] # => "hello"
+ 'hello'[2, 3] # => "llo"
+ 'hello'[2, 0] # => ""
+ 'hello'[2, -1] # => nil
+
+If argument +offset+ is negative,
+counts backward from the end of +self+:
+
+ 'hello'[-1, 1] # => "o"
+ 'hello'[-5, 5] # => "hello"
+ 'hello'[-1, 0] # => ""
+ 'hello'[-6, 5] # => nil
+
+Special case: if +offset+ equals the size of +self+,
+returns a new empty string:
+
+ 'hello'[5, 3] # => ""
+
+<b>Form <tt>self[range]</tt></b>
+
+With Range argument +range+ given,
+forms substring <tt>self[range.start, range.size]</tt>:
+
+ 'hello'[0..2] # => "hel"
+ 'hello'[0, 3] # => "hel"
+
+ 'hello'[0...2] # => "he"
+ 'hello'[0, 2] # => "he"
+
+ 'hello'[0, 0] # => ""
+ 'hello'[0...0] # => ""
+
+<b>Form <tt>self[regexp, capture = 0]</tt></b>
+
+With Regexp argument +regexp+ given and +capture+ as zero,
+searches for a matching substring in +self+;
+updates {Regexp-related global variables}[rdoc-ref:Regexp@Global+Variables]:
+
+ 'hello'[/ell/] # => "ell"
+ 'hello'[/l+/] # => "ll"
+ 'hello'[//] # => ""
+ 'hello'[/nosuch/] # => nil
+
+With +capture+ as a positive integer +n+,
+returns the +n+th matched group:
+
+ 'hello'[/(h)(e)(l+)(o)/] # => "hello"
+ 'hello'[/(h)(e)(l+)(o)/, 1] # => "h"
+ $1 # => "h"
+ 'hello'[/(h)(e)(l+)(o)/, 2] # => "e"
+ $2 # => "e"
+ 'hello'[/(h)(e)(l+)(o)/, 3] # => "ll"
+ 'hello'[/(h)(e)(l+)(o)/, 4] # => "o"
+ 'hello'[/(h)(e)(l+)(o)/, 5] # => nil
+
+<b>Form <tt>self[substring]</tt></b>
+
+With string argument +substring+ given,
+returns the matching substring of +self+, if found:
+
+ 'hello'['ell'] # => "ell"
+ 'hello'[''] # => ""
+ 'hello'['nosuch'] # => nil
+ 'ã“ã‚“ã«ã¡ã¯'['ã‚“ã«ã¡'] # => "ã‚“ã«ã¡"
+
+Related: see {Converting to New String}[rdoc-ref:String@Converting+to+New+String].
diff --git a/doc/string/aset.rdoc b/doc/string/aset.rdoc
new file mode 100644
index 0000000000..98c58b59cc
--- /dev/null
+++ b/doc/string/aset.rdoc
@@ -0,0 +1,179 @@
+Returns +self+ with all, a substring, or none of its contents replaced;
+returns the argument +other_string+.
+
+<b>Form <tt>self[index] = other_string</tt></b>
+
+With non-negative integer argument +index+ given,
+searches for the 1-character substring found in self at character offset index:
+
+ s = 'hello'
+ s[0] = 'foo' # => "foo"
+ s # => "fooello"
+
+ s = 'hello'
+ s[4] = 'foo' # => "foo"
+ s # => "hellfoo"
+
+ s = 'hello'
+ s[5] = 'foo' # => "foo"
+ s # => "hellofoo"
+
+ s = 'hello'
+ s[6] = 'foo' # Raises IndexError: index 6 out of string.
+
+With negative integer argument +index+ given,
+counts backward from the end of +self+:
+
+ s = 'hello'
+ s[-1] = 'foo' # => "foo"
+ s # => "hellfoo"
+
+ s = 'hello'
+ s[-5] = 'foo' # => "foo"
+ s # => "fooello"
+
+ s = 'hello'
+ s[-6] = 'foo' # Raises IndexError: index -6 out of string.
+
+<b>Form <tt>self[start, length] = other_string</tt></b>
+
+With integer arguments +start+ and +length+ given,
+searches for a substring of size +length+ characters (as available)
+beginning at character offset specified by +start+.
+
+If argument +start+ is non-negative,
+the offset is +start+:
+
+ s = 'hello'
+ s[0, 1] = 'foo' # => "foo"
+ s # => "fooello"
+
+ s = 'hello'
+ s[0, 5] = 'foo' # => "foo"
+ s # => "foo"
+
+ s = 'hello'
+ s[0, 9] = 'foo' # => "foo"
+ s # => "foo"
+
+ s = 'hello'
+ s[2, 0] = 'foo' # => "foo"
+ s # => "hefoollo"
+
+ s = 'hello'
+ s[2, -1] = 'foo' # Raises IndexError: negative length -1.
+
+If argument +start+ is negative,
+counts backward from the end of +self+:
+
+ s = 'hello'
+ s[-1, 1] = 'foo' # => "foo"
+ s # => "hellfoo"
+
+ s = 'hello'
+ s[-1, 9] = 'foo' # => "foo"
+ s # => "hellfoo"
+
+ s = 'hello'
+ s[-5, 2] = 'foo' # => "foo"
+ s # => "foollo"
+
+ s = 'hello'
+ s[-3, 0] = 'foo' # => "foo"
+ s # => "hefoollo"
+
+ s = 'hello'
+ s[-6, 2] = 'foo' # Raises IndexError: index -6 out of string.
+
+Special case: if +start+ equals the length of +self+,
+the argument is appended to +self+:
+
+ s = 'hello'
+ s[5, 3] = 'foo' # => "foo"
+ s # => "hellofoo"
+
+<b>Form <tt>self[range] = other_string</tt></b>
+
+With Range argument +range+ given,
+equivalent to <tt>self[range.start, range.size] = other_string</tt>:
+
+ s0 = 'hello'
+ s1 = 'hello'
+ s0[0..2] = 'foo' # => "foo"
+ s1[0, 3] = 'foo' # => "foo"
+ s0 # => "foolo"
+ s1 # => "foolo"
+
+ s = 'hello'
+ s[0...2] = 'foo' # => "foo"
+ s # => "foollo"
+
+ s = 'hello'
+ s[0...0] = 'foo' # => "foo"
+ s # => "foohello"
+
+ s = 'hello'
+ s[9..10] = 'foo' # Raises RangeError: 9..10 out of range
+
+<b>Form <tt>self[regexp, capture = 0] = other_string</tt></b>
+
+With Regexp argument +regexp+ given and +capture+ as zero,
+searches for a matching substring in +self+;
+updates {Regexp-related global variables}[rdoc-ref:Regexp@Global+Variables]:
+
+ s = 'hello'
+ s[/l/] = 'L' # => "L"
+ [$`, $&, $'] # => ["he", "l", "lo"]
+ s[/eLlo/] = 'owdy' # => "owdy"
+ [$`, $&, $'] # => ["h", "eLlo", ""]
+ s[/eLlo/] = 'owdy' # Raises IndexError: regexp not matched.
+ [$`, $&, $'] # => [nil, nil, nil]
+
+With +capture+ as a positive integer +n+,
+searches for the +n+th matched group:
+
+ s = 'hello'
+ s[/(h)(e)(l+)(o)/] = 'foo' # => "foo"
+ [$`, $&, $'] # => ["", "hello", ""]
+
+ s = 'hello'
+ s[/(h)(e)(l+)(o)/, 1] = 'foo' # => "foo"
+ s # => "fooello"
+ [$`, $&, $'] # => ["", "hello", ""]
+
+ s = 'hello'
+ s[/(h)(e)(l+)(o)/, 2] = 'foo' # => "foo"
+ s # => "hfoollo"
+ [$`, $&, $'] # => ["", "hello", ""]
+
+ s = 'hello'
+ s[/(h)(e)(l+)(o)/, 4] = 'foo' # => "foo"
+ s # => "hellfoo"
+ [$`, $&, $'] # => ["", "hello", ""]
+
+ s = 'hello'
+ # => "hello"
+ s[/(h)(e)(l+)(o)/, 5] = 'foo # Raises IndexError: index 5 out of regexp.
+
+ s = 'hello'
+ s[/nosuch/] = 'foo' # Raises IndexError: regexp not matched.
+
+<b>Form <tt>self[substring] = other_string</tt></b>
+
+With string argument +substring+ given:
+
+ s = 'hello'
+ s['l'] = 'foo' # => "foo"
+ s # => "hefoolo"
+
+ s = 'hello'
+ s['ll'] = 'foo' # => "foo"
+ s # => "hefooo"
+
+ s = 'ã“ã‚“ã«ã¡ã¯'
+ s['ã‚“ã«ã¡'] = 'foo' # => "foo"
+ s # => "ã“fooã¯"
+
+ s['nosuch'] = 'foo' # Raises IndexError: string not matched.
+
+Related: see {Modifying}[rdoc-ref:String@Modifying].
diff --git a/doc/string/bytes.rdoc b/doc/string/bytes.rdoc
index f4b071f630..16fa8e0bb0 100644
--- a/doc/string/bytes.rdoc
+++ b/doc/string/bytes.rdoc
@@ -1,8 +1,7 @@
Returns an array of the bytes in +self+:
- 'hello'.bytes # => [104, 101, 108, 108, 111]
- 'теÑÑ‚'.bytes # => [209, 130, 208, 181, 209, 129, 209, 130]
+ 'hello'.bytes # => [104, 101, 108, 108, 111]
'ã“ã‚“ã«ã¡ã¯'.bytes
# => [227, 129, 147, 227, 130, 147, 227, 129, 171, 227, 129, 161, 227, 129, 175]
-Related: see {Converting to Non-String}[rdoc-ref:String@Converting+to+Non--5CString].
+Related: see {Converting to Non-String}[rdoc-ref:String@Converting+to+Non-String].
diff --git a/doc/string/bytesize.rdoc b/doc/string/bytesize.rdoc
index 5166dd7dc6..8d12a0d454 100644
--- a/doc/string/bytesize.rdoc
+++ b/doc/string/bytesize.rdoc
@@ -5,9 +5,6 @@ Note that the byte count may be different from the character count (returned by
s = 'foo'
s.bytesize # => 3
s.size # => 3
- s = 'теÑÑ‚'
- s.bytesize # => 8
- s.size # => 4
s = 'ã“ã‚“ã«ã¡ã¯'
s.bytesize # => 15
s.size # => 5
diff --git a/doc/string/bytesplice.rdoc b/doc/string/bytesplice.rdoc
index 5689ef4a2b..790f9eb9a0 100644
--- a/doc/string/bytesplice.rdoc
+++ b/doc/string/bytesplice.rdoc
@@ -20,7 +20,7 @@ And either count may be zero (i.e., specifying an empty string):
'0123456789'.bytesplice(0, 0, 'abc') # => "abc0123456789" # Empty target.
In the second form, just as in the first,
-arugments +offset+ and +length+ determine the target bytes;
+arguments +offset+ and +length+ determine the target bytes;
argument +str+ _contains_ the source bytes,
and the additional arguments +str_offset+ and +str_length+
determine the actual source bytes:
@@ -42,7 +42,7 @@ and the source bytes are all of the given +str+:
'0123456789'.bytesplice(0...0, 'abc') # => "abc0123456789" # Empty target.
In the fourth form, just as in the third,
-arugment +range+ determines the target bytes;
+argument +range+ determines the target bytes;
argument +str+ _contains_ the source bytes,
and the additional argument +str_range+
determines the actual source bytes:
@@ -63,4 +63,3 @@ and so has character boundaries at offsets 0, 3, 6, 9, 12, and 15.
'ã“ã‚“ã«ã¡ã¯'.bytesplice(0, 3, 'abc') # => "abcã‚“ã«ã¡ã¯"
'ã“ã‚“ã«ã¡ã¯'.bytesplice(1, 3, 'abc') # Raises IndexError.
'ã“ã‚“ã«ã¡ã¯'.bytesplice(0, 2, 'abc') # Raises IndexError.
-
diff --git a/doc/string/capitalize.rdoc b/doc/string/capitalize.rdoc
new file mode 100644
index 0000000000..3a1a2dcb8b
--- /dev/null
+++ b/doc/string/capitalize.rdoc
@@ -0,0 +1,26 @@
+Returns a string containing the characters in +self+,
+each with possibly changed case:
+
+- The first character made uppercase.
+- All other characters are made lowercase.
+
+Examples:
+
+ 'hello'.capitalize # => "Hello"
+ 'HELLO'.capitalize # => "Hello"
+ 'straße'.capitalize # => "Straße" # Lowercase 'ß' not changed.
+ 'STRAẞE'.capitalize # => "Straße" # Uppercase 'ẞ' downcased to 'ß'.
+
+Some characters (and some character sets) do not have upcase and downcase versions;
+see {Case Mapping}[rdoc-ref:case_mapping.rdoc]:
+
+ s = '1, 2, 3, ...'
+ s.capitalize == s # => true
+ s = 'ã“ã‚“ã«ã¡ã¯'
+ s.capitalize == s # => true
+
+The casing is affected by the given +mapping+,
+which may be +:ascii+, +:fold+, or +:turkic+;
+see {Case Mappings}[rdoc-ref:case_mapping.rdoc@Case+Mappings].
+
+Related: see {Converting to New String}[rdoc-ref:String@Converting+to+New+String].
diff --git a/doc/string/center.rdoc b/doc/string/center.rdoc
index 343f6ba263..b86c8b5916 100644
--- a/doc/string/center.rdoc
+++ b/doc/string/center.rdoc
@@ -9,7 +9,6 @@ centered and padded on one or both ends with +pad_string+:
'hello'.center(20, '-|') # => "-|-|-|-hello-|-|-|-|" # Some padding repeated.
'hello'.center(10, 'abcdefg') # => "abhelloabc" # Some padding not used.
' hello '.center(13) # => " hello "
- 'теÑÑ‚'.center(10) # => " теÑÑ‚ "
'ã“ã‚“ã«ã¡ã¯'.center(10) # => " ã“ã‚“ã«ã¡ã¯ " # Multi-byte characters.
If +size+ is less than or equal to the size of +self+, returns an unpadded copy of +self+:
diff --git a/doc/string/chars.rdoc b/doc/string/chars.rdoc
index 094384271b..47fb01b43a 100644
--- a/doc/string/chars.rdoc
+++ b/doc/string/chars.rdoc
@@ -1,8 +1,7 @@
Returns an array of the characters in +self+:
'hello'.chars # => ["h", "e", "l", "l", "o"]
- 'теÑÑ‚'.chars # => ["Ñ‚", "е", "Ñ", "Ñ‚"]
'ã“ã‚“ã«ã¡ã¯'.chars # => ["ã“", "ã‚“", "ã«", "ã¡", "ã¯"]
''.chars # => []
-Related: see {Converting to Non-String}[rdoc-ref:String@Converting+to+Non--5CString].
+Related: see {Converting to Non-String}[rdoc-ref:String@Converting+to+Non-String].
diff --git a/doc/string/chomp.rdoc b/doc/string/chomp.rdoc
index 6ec7664f6b..4efff5c291 100644
--- a/doc/string/chomp.rdoc
+++ b/doc/string/chomp.rdoc
@@ -9,7 +9,6 @@ if they are <tt>"\r"</tt>, <tt>"\n"</tt>, or <tt>"\r\n"</tt>
"abc\n".chomp # => "abc"
"abc\r\n".chomp # => "abc"
"abc\n\r".chomp # => "abc\n"
- "теÑÑ‚\r\n".chomp # => "теÑÑ‚"
"ã“ã‚“ã«ã¡ã¯\r\n".chomp # => "ã“ã‚“ã«ã¡ã¯"
When +line_sep+ is <tt>''</tt> (an empty string),
diff --git a/doc/string/chop.rdoc b/doc/string/chop.rdoc
index 2c48e91129..d818ba467a 100644
--- a/doc/string/chop.rdoc
+++ b/doc/string/chop.rdoc
@@ -3,13 +3,11 @@ Returns a new string copied from +self+, with trailing characters possibly remov
Removes <tt>"\r\n"</tt> if those are the last two characters.
"abc\r\n".chop # => "abc"
- "теÑÑ‚\r\n".chop # => "теÑÑ‚"
"ã“ã‚“ã«ã¡ã¯\r\n".chop # => "ã“ã‚“ã«ã¡ã¯"
Otherwise removes the last character if it exists.
'abcd'.chop # => "abc"
- 'теÑÑ‚'.chop # => "теÑ"
'ã“ã‚“ã«ã¡ã¯'.chop # => "ã“ã‚“ã«ã¡"
''.chop # => ""
diff --git a/doc/string/chr.rdoc b/doc/string/chr.rdoc
index 1ada3854cb..153d5d71c3 100644
--- a/doc/string/chr.rdoc
+++ b/doc/string/chr.rdoc
@@ -1,7 +1,6 @@
Returns a string containing the first character of +self+:
'hello'.chr # => "h"
- 'теÑÑ‚'.chr # => "Ñ‚"
'ã“ã‚“ã«ã¡ã¯'.chr # => "ã“"
''.chr # => ""
diff --git a/doc/string/codepoints.rdoc b/doc/string/codepoints.rdoc
index d9586d2e0b..0ad866389e 100644
--- a/doc/string/codepoints.rdoc
+++ b/doc/string/codepoints.rdoc
@@ -2,8 +2,7 @@ Returns an array of the codepoints in +self+;
each codepoint is the integer value for a character:
'hello'.codepoints # => [104, 101, 108, 108, 111]
- 'теÑÑ‚'.codepoints # => [1090, 1077, 1089, 1090]
'ã“ã‚“ã«ã¡ã¯'.codepoints # => [12371, 12435, 12395, 12385, 12399]
''.codepoints # => []
-Related: see {Converting to Non-String}[rdoc-ref:String@Converting+to+Non--5CString].
+Related: see {Converting to Non-String}[rdoc-ref:String@Converting+to+Non-String].
diff --git a/doc/string/concat.rdoc b/doc/string/concat.rdoc
index 2ba0c714af..92ba664b8c 100644
--- a/doc/string/concat.rdoc
+++ b/doc/string/concat.rdoc
@@ -6,7 +6,6 @@ For each given object +object+ that is an integer,
the value is considered a codepoint and converted to a character before concatenation:
'foo'.concat(32, 'bar', 32, 'baz') # => "foo bar baz" # Embeds spaces.
- 'те'.concat(1089, 1090) # => "теÑÑ‚"
'ã“ã‚“'.concat(12395, 12385, 12399) # => "ã“ã‚“ã«ã¡ã¯"
Related: see {Converting to New String}[rdoc-ref:String@Converting+to+New+String].
diff --git a/doc/string/count.rdoc b/doc/string/count.rdoc
index 092c672d7d..7a3b9f1e21 100644
--- a/doc/string/count.rdoc
+++ b/doc/string/count.rdoc
@@ -9,10 +9,6 @@ returns the count of instances of that character:
s.count('x') # => 0
s.count('') # => 0
- s = 'теÑÑ‚'
- s.count('Ñ‚') # => 2
- s.count('е') # => 1
-
s = 'よã‚ã—ããŠé¡˜ã„ã—ã¾ã™'
s.count('よ') # => 1
s.count('ã—') # => 2
diff --git a/doc/string/delete.rdoc b/doc/string/delete.rdoc
index e8ff4c0ae4..1827f177e6 100644
--- a/doc/string/delete.rdoc
+++ b/doc/string/delete.rdoc
@@ -10,10 +10,6 @@ removes all instances of that character:
s.delete('x') # => "abracadabra"
s.delete('') # => "abracadabra"
- s = 'теÑÑ‚'
- s.delete('Ñ‚') # => "еÑ"
- s.delete('е') # => "Ñ‚ÑÑ‚"
-
s = 'よã‚ã—ããŠé¡˜ã„ã—ã¾ã™'
s.delete('よ') # => "ã‚ã—ããŠé¡˜ã„ã—ã¾ã™"
s.delete('ã—') # => "よã‚ããŠé¡˜ã„ã¾ã™"
diff --git a/doc/string/delete_prefix.rdoc b/doc/string/delete_prefix.rdoc
index 1135f3d19d..6255e300e3 100644
--- a/doc/string/delete_prefix.rdoc
+++ b/doc/string/delete_prefix.rdoc
@@ -4,7 +4,6 @@ Returns a copy of +self+ with leading substring +prefix+ removed:
'oof'.delete_prefix('oo') # => "f"
'oof'.delete_prefix('oof') # => ""
'oof'.delete_prefix('x') # => "oof"
- 'теÑÑ‚'.delete_prefix('те') # => "ÑÑ‚"
'ã“ã‚“ã«ã¡ã¯'.delete_prefix('ã“ã‚“') # => "ã«ã¡ã¯"
Related: see {Converting to New String}[rdoc-ref:String@Converting+to+New+String].
diff --git a/doc/string/delete_suffix.rdoc b/doc/string/delete_suffix.rdoc
index 2fb70ce012..a4d9a80f85 100644
--- a/doc/string/delete_suffix.rdoc
+++ b/doc/string/delete_suffix.rdoc
@@ -5,7 +5,6 @@ Returns a copy of +self+ with trailing substring <tt>suffix</tt> removed:
'foo'.delete_suffix('foo') # => ""
'foo'.delete_suffix('f') # => "foo"
'foo'.delete_suffix('x') # => "foo"
- 'теÑÑ‚'.delete_suffix('ÑÑ‚') # => "те"
'ã“ã‚“ã«ã¡ã¯'.delete_suffix('ã¡ã¯') # => "ã“ã‚“ã«"
Related: see {Converting to New String}[rdoc-ref:String@Converting+to+New+String].
diff --git a/doc/string/downcase.rdoc b/doc/string/downcase.rdoc
index 0fb67daaeb..d5fffa037b 100644
--- a/doc/string/downcase.rdoc
+++ b/doc/string/downcase.rdoc
@@ -1,12 +1,20 @@
Returns a new string containing the downcased characters in +self+:
- 'Hello, World!'.downcase # => "hello, world!"
- 'ТЕСТ'.downcase # => "теÑÑ‚"
- 'よã‚ã—ããŠé¡˜ã„ã—ã¾ã™'.downcase # => "よã‚ã—ããŠé¡˜ã„ã—ã¾ã™"
+ 'HELLO'.downcase # => "hello"
+ 'STRAẞE'.downcase # => "straße"
+ 'ПРИВЕТ'.downcase # => "привет"
+ 'RubyGems.org'.downcase # => "rubygems.org"
-Some characters do not have upcased and downcased versions.
+Some characters (and some character sets) do not have upcase and downcase versions;
+see {Case Mapping}[rdoc-ref:case_mapping.rdoc]:
-The casing may be affected by the given +mapping+;
-see {Case Mapping}[rdoc-ref:case_mapping.rdoc].
+ s = '1, 2, 3, ...'
+ s.downcase == s # => true
+ s = 'ã“ã‚“ã«ã¡ã¯'
+ s.downcase == s # => true
+
+The casing is affected by the given +mapping+,
+which may be +:ascii+, +:fold+, or +:turkic+;
+see {Case Mappings}[rdoc-ref:case_mapping.rdoc@Case+Mappings].
Related: see {Converting to New String}[rdoc-ref:String@Converting+to+New+String].
diff --git a/doc/string/dump.rdoc b/doc/string/dump.rdoc
index a5ab0bb42f..7b688c28a6 100644
--- a/doc/string/dump.rdoc
+++ b/doc/string/dump.rdoc
@@ -1,52 +1,89 @@
-Returns a printable version of +self+, enclosed in double-quotes:
+For an ordinary string, this method, +String#dump+,
+returns a printable ASCII-only version of +self+, enclosed in double-quotes.
- 'hello'.dump # => "\"hello\""
+For a dumped string, method String#undump is the inverse of +String#dump+;
+it returns a "restored" version of +self+,
+where all the dumping changes have been undone.
-Certain special characters are rendered with escapes:
+In the simplest case, the dumped string contains the original string,
+enclosed in double-quotes;
+this example is done in +irb+ (interactive Ruby), which uses method `inspect` to render the results:
- '"'.dump # => "\"\\\"\""
- '\\'.dump # => "\"\\\\\""
+ s = 'hello' # => "hello"
+ s.dump # => "\"hello\""
+ s.dump.undump # => "hello"
-Non-printing characters are rendered with escapes:
+Keep in mind that in the second line above:
+
+- The outer double-quotes are put on by +inspect+,
+ and _are_ _not_ part of the output of #dump.
+- The inner double-quotes _are_ part of the output of +dump+,
+ and are escaped by +inspect+ because they are within the outer double-quotes.
+
+To avoid confusion, we'll use this helper method to omit the outer double-quotes:
+
+ def dump(s)
+ print "String: ", s, "\n"
+ print "Dumped: ", s.dump, "\n"
+ print "Undumped: ", s.dump.undump, "\n"
+ end
+
+So that for string <tt>'hello'</tt>, we'll see:
+
+ String: hello
+ Dumped: "hello"
+ Undumped: hello
+
+In a dump, certain special characters are escaped:
+
+ String: "
+ Dumped: "\""
+ Undumped: "
+
+ String: \
+ Dumped: "\\"
+ Undumped: \
+
+In a dump, unprintable characters are replaced by printable ones;
+the unprintable characters are the whitespace characters (other than space itself);
+here we see the ordinals for those characters, together with explanatory text:
+
+ h = {
+ 7 => 'Alert (BEL)',
+ 8 => 'Backspace (BS)',
+ 9 => 'Horizontal tab (HT)',
+ 10 => 'Linefeed (LF)',
+ 11 => 'Vertical tab (VT)',
+ 12 => 'Formfeed (FF)',
+ 13 => 'Carriage return (CR)'
+ }
+
+In this example, the dumped output is printed by method #inspect,
+and so contains both outer double-quotes and escaped inner double-quotes:
s = ''
- s << 7 # Alarm (bell).
- s << 8 # Back space.
- s << 9 # Horizontal tab.
- s << 10 # Line feed.
- s << 11 # Vertical tab.
- s << 12 # Form feed.
- s << 13 # Carriage return.
- s # => "\a\b\t\n\v\f\r"
- s.dump # => "\"\\a\\b\\t\\n\\v\\f\\r\""
-
-If +self+ is encoded in UTF-8 and contains Unicode characters, renders Unicode
-characters in Unicode escape sequence:
-
- 'теÑÑ‚'.dump # => "\"\\u0442\\u0435\\u0441\\u0442\""
- 'ã“ã‚“ã«ã¡ã¯'.dump # => "\"\\u3053\\u3093\\u306B\\u3061\\u306F\""
-
-If the encoding of +self+ is not ASCII-compatible (i.e., +self.encoding.ascii_compatible?+
-returns +false+), renders all ASCII-compatible bytes as ASCII characters and all
-other bytes as hexadecimal. Appends <tt>.dup.force_encoding(\"encoding\")</tt>, where
-<tt><encoding></tt> is +self.encoding.name+:
-
- s = 'hello'
- s.encoding # => #<Encoding:UTF-8>
- s.dump # => "\"hello\""
- s.encode('utf-16').dump # => "\"\\xFE\\xFF\\x00h\\x00e\\x00l\\x00l\\x00o\".dup.force_encoding(\"UTF-16\")"
- s.encode('utf-16le').dump # => "\"h\\x00e\\x00l\\x00l\\x00o\\x00\".dup.force_encoding(\"UTF-16LE\")"
-
- s = 'теÑÑ‚'
- s.encoding # => #<Encoding:UTF-8>
- s.dump # => "\"\\u0442\\u0435\\u0441\\u0442\""
- s.encode('utf-16').dump # => "\"\\xFE\\xFF\\x04B\\x045\\x04A\\x04B\".dup.force_encoding(\"UTF-16\")"
- s.encode('utf-16le').dump # => "\"B\\x045\\x04A\\x04B\\x04\".dup.force_encoding(\"UTF-16LE\")"
-
- s = 'ã“ã‚“ã«ã¡ã¯'
- s.encoding # => #<Encoding:UTF-8>
- s.dump # => "\"\\u3053\\u3093\\u306B\\u3061\\u306F\""
- s.encode('utf-16').dump # => "\"\\xFE\\xFF0S0\\x930k0a0o\".dup.force_encoding(\"UTF-16\")"
- s.encode('utf-16le').dump # => "\"S0\\x930k0a0o0\".dup.force_encoding(\"UTF-16LE\")"
-
-Related: see {Converting to New String}[rdoc-ref:String@Converting+to+New+String].
+ h.keys.each {|i| s << i } # => [7, 8, 9, 10, 11, 12, 13]
+ s # => "\a\b\t\n\v\f\r"
+ s.dump # => "\"\\a\\b\\t\\n\\v\\f\\r\""
+
+If +self+ is encoded in UTF-8 and contains Unicode characters,
+each Unicode character is dumped as a Unicode escape sequence:
+
+ String: ã“ã‚“ã«ã¡ã¯
+ Dumped: "\u3053\u3093\u306B\u3061\u306F"
+ Undumped: ã“ã‚“ã«ã¡ã¯
+
+If the encoding of +self+ is not ASCII-compatible
+(i.e., if <tt>self.encoding.ascii_compatible?</tt> returns +false+),
+each ASCII-compatible byte is dumped as an ASCII character,
+and all other bytes are dumped as hexadecimal;
+also appends <tt>.dup.force_encoding(\"encoding\")</tt>,
+where <tt><encoding></tt> is <tt>self.encoding.name</tt>:
+
+ String: hello
+ Dumped: "\xFE\xFF\x00h\x00e\x00l\x00l\x00o".dup.force_encoding("UTF-16")
+ Undumped: hello
+
+ String: ã“ã‚“ã«ã¡ã¯
+ Dumped: "\xFE\xFF0S0\x930k0a0o".dup.force_encoding("UTF-16")
+ Undumped: ã“ã‚“ã«ã¡ã¯
diff --git a/doc/string/each_byte.rdoc b/doc/string/each_byte.rdoc
index 1f1069863b..642d71e84b 100644
--- a/doc/string/each_byte.rdoc
+++ b/doc/string/each_byte.rdoc
@@ -5,9 +5,6 @@ returns +self+:
'hello'.each_byte {|byte| a.push(byte) } # Five 1-byte characters.
a # => [104, 101, 108, 108, 111]
a = []
- 'теÑÑ‚'.each_byte {|byte| a.push(byte) } # Four 2-byte characters.
- a # => [209, 130, 208, 181, 209, 129, 209, 130]
- a = []
'ã“ã‚“ã«ã¡ã¯'.each_byte {|byte| a.push(byte) } # Five 3-byte characters.
a # => [227, 129, 147, 227, 130, 147, 227, 129, 171, 227, 129, 161, 227, 129, 175]
diff --git a/doc/string/each_char.rdoc b/doc/string/each_char.rdoc
index 5aa85b28ad..2dd56711d3 100644
--- a/doc/string/each_char.rdoc
+++ b/doc/string/each_char.rdoc
@@ -7,11 +7,6 @@ returns +self+:
end
a # => ["h", "e", "l", "l", "o"]
a = []
- 'теÑÑ‚'.each_char do |char|
- a.push(char)
- end
- a # => ["Ñ‚", "е", "Ñ", "Ñ‚"]
- a = []
'ã“ã‚“ã«ã¡ã¯'.each_char do |char|
a.push(char)
end
diff --git a/doc/string/each_codepoint.rdoc b/doc/string/each_codepoint.rdoc
index 0e687082d3..8e4e7545e6 100644
--- a/doc/string/each_codepoint.rdoc
+++ b/doc/string/each_codepoint.rdoc
@@ -8,11 +8,6 @@ returns +self+:
end
a # => [104, 101, 108, 108, 111]
a = []
- 'теÑÑ‚'.each_codepoint do |codepoint|
- a.push(codepoint)
- end
- a # => [1090, 1077, 1089, 1090]
- a = []
'ã“ã‚“ã«ã¡ã¯'.each_codepoint do |codepoint|
a.push(codepoint)
end
diff --git a/doc/string/each_grapheme_cluster.rdoc b/doc/string/each_grapheme_cluster.rdoc
index 8bc6f78aaa..384cd6967d 100644
--- a/doc/string/each_grapheme_cluster.rdoc
+++ b/doc/string/each_grapheme_cluster.rdoc
@@ -9,12 +9,6 @@ returns +self+:
a # => ["h", "e", "l", "l", "o"]
a = []
- 'теÑÑ‚'.each_grapheme_cluster do |grapheme_cluster|
- a.push(grapheme_cluster)
- end
- a # => ["Ñ‚", "е", "Ñ", "Ñ‚"]
-
- a = []
'ã“ã‚“ã«ã¡ã¯'.each_grapheme_cluster do |grapheme_cluster|
a.push(grapheme_cluster)
end
diff --git a/doc/string/end_with_p.rdoc b/doc/string/end_with_p.rdoc
index fcd9242122..9a95d74fde 100644
--- a/doc/string/end_with_p.rdoc
+++ b/doc/string/end_with_p.rdoc
@@ -4,7 +4,6 @@ Returns whether +self+ ends with any of the given +strings+:
'foo'.end_with?('bar', 'oo') # => true
'foo'.end_with?('bar', 'baz') # => false
'foo'.end_with?('') # => true
- 'теÑÑ‚'.end_with?('Ñ‚') # => true
'ã“ã‚“ã«ã¡ã¯'.end_with?('ã¯') # => true
Related: see {Querying}[rdoc-ref:String@Querying].
diff --git a/doc/string/getbyte.rdoc b/doc/string/getbyte.rdoc
index ba1c06fd27..974e21c473 100644
--- a/doc/string/getbyte.rdoc
+++ b/doc/string/getbyte.rdoc
@@ -16,11 +16,8 @@ Returns +nil+ if +index+ is out of range:
More examples:
- s = 'теÑÑ‚'
- s.bytes # => [209, 130, 208, 181, 209, 129, 209, 130]
- s.getbyte(2) # => 208
s = 'ã“ã‚“ã«ã¡ã¯'
s.bytes # => [227, 129, 147, 227, 130, 147, 227, 129, 171, 227, 129, 161, 227, 129, 175]
s.getbyte(2) # => 147
-Related: see {Converting to Non-String}[rdoc-ref:String@Converting+to+Non--5CString].
+Related: see {Converting to Non-String}[rdoc-ref:String@Converting+to+Non-String].
diff --git a/doc/string/grapheme_clusters.rdoc b/doc/string/grapheme_clusters.rdoc
index 07ea1e318b..ee8b45700e 100644
--- a/doc/string/grapheme_clusters.rdoc
+++ b/doc/string/grapheme_clusters.rdoc
@@ -16,4 +16,4 @@ Details:
s.chars # => ["a", "̈"] # Two characters.
s.chars.map {|char| char.ord } # => [97, 776] # Their values.
-Related: see {Converting to Non-String}[rdoc-ref:String@Converting+to+Non--5CString].
+Related: see {Converting to Non-String}[rdoc-ref:String@Converting+to+Non-String].
diff --git a/doc/string/index.rdoc b/doc/string/index.rdoc
index cc34bc68e6..c3cff24dac 100644
--- a/doc/string/index.rdoc
+++ b/doc/string/index.rdoc
@@ -8,10 +8,9 @@ returns the index of the first matching substring in +self+:
'foo'.index('o') # => 1
'foo'.index('oo') # => 1
'foo'.index('ooo') # => nil
- 'теÑÑ‚'.index('Ñ') # => 2 # Characters, not bytes.
'ã“ã‚“ã«ã¡ã¯'.index('ã¡') # => 3
-When +pattern is a Regexp, returns the index of the first match in +self+:
+When +pattern+ is a Regexp, returns the index of the first match in +self+:
'foo'.index(/o./) # => 1
'foo'.index(/.o/) # => 0
@@ -24,9 +23,6 @@ the returned index is relative to the beginning of +self+:
'bar'.index('r', 2) # => 2
'bar'.index('r', 3) # => nil
'bar'.index(/[r-z]/, 0) # => 2
- 'теÑÑ‚'.index('Ñ', 1) # => 2
- 'теÑÑ‚'.index('Ñ', 2) # => 2
- 'теÑÑ‚'.index('Ñ', 3) # => nil # Offset in characters, not bytes.
'ã“ã‚“ã«ã¡ã¯'.index('ã¡', 2) # => 3
With negative integer argument +offset+, selects the search position by counting backward
diff --git a/doc/string/insert.rdoc b/doc/string/insert.rdoc
index d8252d5ec5..73205f2069 100644
--- a/doc/string/insert.rdoc
+++ b/doc/string/insert.rdoc
@@ -5,7 +5,6 @@ If the given +index+ is non-negative, inserts +other_string+ at offset +index+:
'foo'.insert(0, 'bar') # => "barfoo"
'foo'.insert(1, 'bar') # => "fbaroo"
'foo'.insert(3, 'bar') # => "foobar"
- 'теÑÑ‚'.insert(2, 'bar') # => "теbarÑÑ‚" # Characters, not bytes.
'ã“ã‚“ã«ã¡ã¯'.insert(2, 'bar') # => "ã“ã‚“barã«ã¡ã¯"
If the +index+ is negative, counts backward from the end of +self+
diff --git a/doc/string/inspect.rdoc b/doc/string/inspect.rdoc
new file mode 100644
index 0000000000..398a5a74c5
--- /dev/null
+++ b/doc/string/inspect.rdoc
@@ -0,0 +1,38 @@
+Returns a printable version of +self+, enclosed in double-quotes.
+
+Most printable characters are rendered simply as themselves:
+
+ 'abc'.inspect # => "\"abc\""
+ '012'.inspect # => "\"012\""
+ ''.inspect # => "\"\""
+ "\u000012".inspect # => "\"\\u000012\""
+ 'ã“ã‚“ã«ã¡ã¯'.inspect # => "\"ã“ã‚“ã«ã¡ã¯\""
+
+But printable characters double-quote (<tt>'"'</tt>) and backslash and (<tt>'\\'</tt>) are escaped:
+
+ '"'.inspect # => "\"\\\"\""
+ '\\'.inspect # => "\"\\\\\""
+
+Unprintable characters are the {ASCII characters}[https://en.wikipedia.org/wiki/ASCII]
+whose values are in range <tt>0..31</tt>,
+along with the character whose value is +127+.
+
+Most of these characters are rendered thus:
+
+ 0.chr.inspect # => "\"\\x00\""
+ 1.chr.inspect # => "\"\\x01\""
+ 2.chr.inspect # => "\"\\x02\""
+ # ...
+
+A few, however, have special renderings:
+
+ 7.chr.inspect # => "\"\\a\"" # BEL
+ 8.chr.inspect # => "\"\\b\"" # BS
+ 9.chr.inspect # => "\"\\t\"" # TAB
+ 10.chr.inspect # => "\"\\n\"" # LF
+ 11.chr.inspect # => "\"\\v\"" # VT
+ 12.chr.inspect # => "\"\\f\"" # FF
+ 13.chr.inspect # => "\"\\r\"" # CR
+ 27.chr.inspect # => "\"\\e\"" # ESC
+
+Related: see {Converting to Non-String}[rdoc-ref:String@Converting+to+Non-String].
diff --git a/doc/string/intern.rdoc b/doc/string/intern.rdoc
new file mode 100644
index 0000000000..c82302b906
--- /dev/null
+++ b/doc/string/intern.rdoc
@@ -0,0 +1,8 @@
+Returns the Symbol object derived from +self+,
+creating it if it did not already exist:
+
+ 'foo'.intern # => :foo
+ 'ã“ã‚“ã«ã¡ã¯'.intern # => :ã“ã‚“ã«ã¡ã¯
+
+Related: see {Converting to Non-String}[rdoc-ref:String@Converting+to+Non-String].
+
diff --git a/doc/string/length.rdoc b/doc/string/length.rdoc
index 544bca269f..eb68edb10c 100644
--- a/doc/string/length.rdoc
+++ b/doc/string/length.rdoc
@@ -1,12 +1,11 @@
Returns the count of characters (not bytes) in +self+:
'foo'.length # => 3
- 'теÑÑ‚'.length # => 4
- 'ã“ã‚“ã«ã¡ã¯'.length # => 5
+ 'ã“ã‚“ã«ã¡ã¯'.length # => 5
Contrast with String#bytesize:
'foo'.bytesize # => 3
- 'теÑÑ‚'.bytesize # => 8
- 'ã“ã‚“ã«ã¡ã¯'.bytesize # => 15
+ 'ã“ã‚“ã«ã¡ã¯'.bytesize # => 15
+Related: see {Querying}[rdoc-ref:String@Querying].
diff --git a/doc/string/ljust.rdoc b/doc/string/ljust.rdoc
index 8e23c1fc8f..a8ca62ee76 100644
--- a/doc/string/ljust.rdoc
+++ b/doc/string/ljust.rdoc
@@ -1,16 +1,13 @@
-Returns a left-justified copy of +self+.
-
-If integer argument +size+ is greater than the size (in characters) of +self+,
-returns a new string of length +size+ that is a copy of +self+,
-left justified and padded on the right with +pad_string+:
+Returns a copy of +self+, left-justified and, if necessary, right-padded with the +pad_string+:
'hello'.ljust(10) # => "hello "
' hello'.ljust(10) # => " hello "
'hello'.ljust(10, 'ab') # => "helloababa"
- 'теÑÑ‚'.ljust(10) # => "теÑÑ‚ "
- 'ã“ã‚“ã«ã¡ã¯'.ljust(10) # => "ã“ã‚“ã«ã¡ã¯ "
+ 'ã“ã‚“ã«ã¡ã¯'.ljust(10) # => "ã“ã‚“ã«ã¡ã¯ "
-If +size+ is not greater than the size of +self+, returns a copy of +self+:
+If <tt>width <= self.length</tt>, returns a copy of +self+:
'hello'.ljust(5) # => "hello"
- 'hello'.ljust(1) # => "hello"
+ 'hello'.ljust(1) # => "hello" # Does not truncate to width.
+
+Related: see {Converting to New String}[rdoc-ref:String@Converting+to+New+String].
diff --git a/doc/string/ord.rdoc b/doc/string/ord.rdoc
index d586363d44..8c460d3ba4 100644
--- a/doc/string/ord.rdoc
+++ b/doc/string/ord.rdoc
@@ -2,5 +2,6 @@ Returns the integer ordinal of the first character of +self+:
'h'.ord # => 104
'hello'.ord # => 104
- 'теÑÑ‚'.ord # => 1090
'ã“ã‚“ã«ã¡ã¯'.ord # => 12371
+
+Related: see {Converting to Non-String}[rdoc-ref:String@Converting+to+Non-String].
diff --git a/doc/string/partition.rdoc b/doc/string/partition.rdoc
index ebe575e8eb..b2e620a9fc 100644
--- a/doc/string/partition.rdoc
+++ b/doc/string/partition.rdoc
@@ -1,24 +1,43 @@
Returns a 3-element array of substrings of +self+.
-Matches a pattern against +self+, scanning from the beginning.
-The pattern is:
+If +pattern+ is matched, returns the array:
-- +string_or_regexp+ itself, if it is a Regexp.
-- <tt>Regexp.quote(string_or_regexp)</tt>, if +string_or_regexp+ is a string.
+ [pre_match, first_match, post_match]
-If the pattern is matched, returns pre-match, first-match, post-match:
+where:
- 'hello'.partition('l') # => ["he", "l", "lo"]
- 'hello'.partition('ll') # => ["he", "ll", "o"]
- 'hello'.partition('h') # => ["", "h", "ello"]
- 'hello'.partition('o') # => ["hell", "o", ""]
- 'hello'.partition(/l+/) #=> ["he", "ll", "o"]
- 'hello'.partition('') # => ["", "", "hello"]
- 'теÑÑ‚'.partition('Ñ‚') # => ["", "Ñ‚", "еÑÑ‚"]
- 'ã“ã‚“ã«ã¡ã¯'.partition('ã«') # => ["ã“ã‚“", "ã«", "ã¡ã¯"]
+- +first_match+ is the first-found matching substring.
+- +pre_match+ and +post_match+ are the preceding and following substrings.
-If the pattern is not matched, returns a copy of +self+ and two empty strings:
+If +pattern+ is not matched, returns the array:
- 'hello'.partition('x') # => ["hello", "", ""]
+ [self.dup, "", ""]
-Related: String#rpartition, String#split.
+Note that in the examples below, a returned string <tt>'hello'</tt>
+is a copy of +self+, not +self+.
+
+If +pattern+ is a Regexp, performs the equivalent of <tt>self.match(pattern)</tt>
+(also setting {matched-data variables}[rdoc-ref:language/globals.md@Matched+Data]):
+
+ 'hello'.partition(/h/) # => ["", "h", "ello"]
+ 'hello'.partition(/l/) # => ["he", "l", "lo"]
+ 'hello'.partition(/l+/) # => ["he", "ll", "o"]
+ 'hello'.partition(/o/) # => ["hell", "o", ""]
+ 'hello'.partition(/^/) # => ["", "", "hello"]
+ 'hello'.partition(//) # => ["", "", "hello"]
+ 'hello'.partition(/$/) # => ["hello", "", ""]
+ 'hello'.partition(/x/) # => ["hello", "", ""]
+
+If +pattern+ is not a Regexp, converts it to a string (if it is not already one),
+then performs the equivalent of <tt>self.index(pattern)</tt>
+(and does _not_ set {matched-data global variables}[rdoc-ref:language/globals.md@Matched+Data]):
+
+ 'hello'.partition('h') # => ["", "h", "ello"]
+ 'hello'.partition('l') # => ["he", "l", "lo"]
+ 'hello'.partition('ll') # => ["he", "ll", "o"]
+ 'hello'.partition('o') # => ["hell", "o", ""]
+ 'hello'.partition('') # => ["", "", "hello"]
+ 'hello'.partition('x') # => ["hello", "", ""]
+ 'ã“ã‚“ã«ã¡ã¯'.partition('ã«') # => ["ã“ã‚“", "ã«", "ã¡ã¯"]
+
+Related: see {Converting to Non-String}[rdoc-ref:String@Converting+to+Non-String].
diff --git a/doc/string/rindex.rdoc b/doc/string/rindex.rdoc
new file mode 100644
index 0000000000..2b81c3716d
--- /dev/null
+++ b/doc/string/rindex.rdoc
@@ -0,0 +1,51 @@
+Returns the integer position of the _last_ substring that matches the given argument +pattern+,
+or +nil+ if none found.
+
+When +pattern+ is a string, returns the index of the last matching substring in self:
+
+ 'foo'.rindex('f') # => 0
+ 'foo'.rindex('o') # => 2
+ 'foo'.rindex('oo' # => 1
+ 'foo'.rindex('ooo') # => nil
+ 'ã“ã‚“ã«ã¡ã¯'.rindex('ã¡') # => 3
+
+When +pattern+ is a Regexp, returns the index of the last match in self:
+
+ 'foo'.rindex(/f/) # => 0
+ 'foo'.rindex(/o/) # => 2
+ 'foo'.rindex(/oo/) # => 1
+ 'foo'.rindex(/ooo/) # => nil
+
+When +offset+ is non-negative, it specifies the maximum starting position in the
+string to end the search:
+
+ 'foo'.rindex('o', 0) # => nil
+ 'foo'.rindex('o', 1) # => 1
+ 'foo'.rindex('o', 2) # => 2
+ 'foo'.rindex('o', 3) # => 2
+
+With negative integer argument +offset+,
+selects the search position by counting backward from the end of +self+:
+
+ 'foo'.rindex('o', -1) # => 2
+ 'foo'.rindex('o', -2) # => 1
+ 'foo'.rindex('o', -3) # => nil
+ 'foo'.rindex('o', -4) # => nil
+
+The last match means starting at the possible last position, not
+the last of longest matches:
+
+ 'foo'.rindex(/o+/) # => 2
+ $~ # => #<MatchData "o">
+
+To get the last longest match, combine with negative lookbehind:
+
+ 'foo'.rindex(/(?<!o)o+/) # => 1
+ $~ # => #<MatchData "oo">
+
+Or String#index with negative lookforward.
+
+ 'foo'.index(/o+(?!.*o)/) # => 1
+ $~ # => #<MatchData "oo">
+
+Related: see {Querying}[rdoc-ref:String@Querying].
diff --git a/doc/string/rjust.rdoc b/doc/string/rjust.rdoc
index 24e7bf3159..acd3f198d4 100644
--- a/doc/string/rjust.rdoc
+++ b/doc/string/rjust.rdoc
@@ -1,16 +1,17 @@
Returns a right-justified copy of +self+.
-If integer argument +size+ is greater than the size (in characters) of +self+,
-returns a new string of length +size+ that is a copy of +self+,
+If integer argument +width+ is greater than the size (in characters) of +self+,
+returns a new string of length +width+ that is a copy of +self+,
right justified and padded on the left with +pad_string+:
'hello'.rjust(10) # => " hello"
'hello '.rjust(10) # => " hello "
'hello'.rjust(10, 'ab') # => "ababahello"
- 'теÑÑ‚'.rjust(10) # => " теÑÑ‚"
'ã“ã‚“ã«ã¡ã¯'.rjust(10) # => " ã“ã‚“ã«ã¡ã¯"
-If +size+ is not greater than the size of +self+, returns a copy of +self+:
+If <tt>width <= self.size</tt>, returns a copy of +self+:
'hello'.rjust(5, 'ab') # => "hello"
'hello'.rjust(1, 'ab') # => "hello"
+
+Related: see {Converting to New String}[rdoc-ref:String@Converting+to+New+String].
diff --git a/doc/string/rpartition.rdoc b/doc/string/rpartition.rdoc
index d24106fb9f..add95b1f40 100644
--- a/doc/string/rpartition.rdoc
+++ b/doc/string/rpartition.rdoc
@@ -1,24 +1,47 @@
Returns a 3-element array of substrings of +self+.
-Matches a pattern against +self+, scanning backwards from the end.
-The pattern is:
+Searches +self+ for a match of +pattern+, seeking the _last_ match.
-- +string_or_regexp+ itself, if it is a Regexp.
-- <tt>Regexp.quote(string_or_regexp)</tt>, if +string_or_regexp+ is a string.
+If +pattern+ is not matched, returns the array:
-If the pattern is matched, returns pre-match, last-match, post-match:
+ ["", "", self.dup]
- 'hello'.rpartition('l') # => ["hel", "l", "o"]
- 'hello'.rpartition('ll') # => ["he", "ll", "o"]
- 'hello'.rpartition('h') # => ["", "h", "ello"]
- 'hello'.rpartition('o') # => ["hell", "o", ""]
- 'hello'.rpartition(/l+/) # => ["hel", "l", "o"]
- 'hello'.rpartition('') # => ["hello", "", ""]
- 'теÑÑ‚'.rpartition('Ñ‚') # => ["теÑ", "Ñ‚", ""]
- 'ã“ã‚“ã«ã¡ã¯'.rpartition('ã«') # => ["ã“ã‚“", "ã«", "ã¡ã¯"]
+If +pattern+ is matched, returns the array:
-If the pattern is not matched, returns two empty strings and a copy of +self+:
+ [pre_match, last_match, post_match]
- 'hello'.rpartition('x') # => ["", "", "hello"]
+where:
-Related: String#partition, String#split.
+- +last_match+ is the last-found matching substring.
+- +pre_match+ and +post_match+ are the preceding and following substrings.
+
+The pattern used is:
+
+- +pattern+ itself, if it is a Regexp.
+- <tt>Regexp.quote(pattern)</tt>, if +pattern+ is a string.
+
+Note that in the examples below, a returned string <tt>'hello'</tt> is a copy of +self+, not +self+.
+
+If +pattern+ is a Regexp, searches for the last matching substring
+(also setting {matched-data global variables}[rdoc-ref:language/globals.md@Matched+Data]):
+
+ 'hello'.rpartition(/l/) # => ["hel", "l", "o"]
+ 'hello'.rpartition(/ll/) # => ["he", "ll", "o"]
+ 'hello'.rpartition(/h/) # => ["", "h", "ello"]
+ 'hello'.rpartition(/o/) # => ["hell", "o", ""]
+ 'hello'.rpartition(//) # => ["hello", "", ""]
+ 'hello'.rpartition(/x/) # => ["", "", "hello"]
+ 'ã“ã‚“ã«ã¡ã¯'.rpartition(/ã«/) # => ["ã“ã‚“", "ã«", "ã¡ã¯"]
+
+If +pattern+ is not a Regexp, converts it to a string (if it is not already one),
+then searches for the last matching substring
+(and does _not_ set {matched-data global variables}[rdoc-ref:language/globals.md@Matched+Data]):
+
+ 'hello'.rpartition('l') # => ["hel", "l", "o"]
+ 'hello'.rpartition('ll') # => ["he", "ll", "o"]
+ 'hello'.rpartition('h') # => ["", "h", "ello"]
+ 'hello'.rpartition('o') # => ["hell", "o", ""]
+ 'hello'.rpartition('') # => ["hello", "", ""]
+ 'ã“ã‚“ã«ã¡ã¯'.rpartition('ã«') # => ["ã“ã‚“", "ã«", "ã¡ã¯"]
+
+Related: see {Converting to Non-String}[rdoc-ref:String@Converting+to+Non-String].
diff --git a/doc/string/scan.rdoc b/doc/string/scan.rdoc
new file mode 100644
index 0000000000..d39b5b6dfa
--- /dev/null
+++ b/doc/string/scan.rdoc
@@ -0,0 +1,35 @@
+Matches a pattern against +self+:
+
+- If +pattern+ is a Regexp, the pattern used is +pattern+ itself.
+- If +pattern+ is a string, the pattern used is <tt>Regexp.quote(pattern)</tt>.
+
+Generates a collection of matching results
+and updates {regexp-related global variables}[rdoc-ref:Regexp@Global+Variables]:
+
+- If the pattern contains no groups, each result is a matched substring.
+- If the pattern contains groups, each result is an array
+ containing a matched substring for each group.
+
+With no block given, returns an array of the results:
+
+ 'cruel world'.scan(/\w+/) # => ["cruel", "world"]
+ 'cruel world'.scan(/.../) # => ["cru", "el ", "wor"]
+ 'cruel world'.scan(/(...)/) # => [["cru"], ["el "], ["wor"]]
+ 'cruel world'.scan(/(..)(..)/) # => [["cr", "ue"], ["l ", "wo"]]
+ 'ã“ã‚“ã«ã¡ã¯'.scan(/../) # => ["ã“ã‚“", "ã«ã¡"]
+ 'abracadabra'.scan('ab') # => ["ab", "ab"]
+ 'abracadabra'.scan('nosuch') # => []
+
+With a block given, calls the block with each result; returns +self+:
+
+ 'cruel world'.scan(/\w+/) {|w| p w }
+ # => "cruel"
+ # => "world"
+ 'cruel world'.scan(/(.)(.)/) {|x, y| p [x, y] }
+ # => ["c", "r"]
+ # => ["u", "e"]
+ # => ["l", " "]
+ # => ["w", "o"]
+ # => ["r", "l"]
+
+Related: see {Converting to Non-String}[rdoc-ref:String@Converting+to+Non-String].
diff --git a/doc/string/scrub.rdoc b/doc/string/scrub.rdoc
index 1a5b1c79d0..314b28c465 100644
--- a/doc/string/scrub.rdoc
+++ b/doc/string/scrub.rdoc
@@ -1,25 +1,22 @@
Returns a copy of +self+ with each invalid byte sequence replaced
by the given +replacement_string+.
-With no block given and no argument, replaces each invalid sequence
-with the default replacement string
-(<tt>"�"</tt> for a Unicode encoding, <tt>'?'</tt> otherwise):
+With no block given, replaces each invalid sequence
+with the given +default_replacement_string+
+(by default, <tt>"�"</tt> for a Unicode encoding, <tt>'?'</tt> otherwise):
- s = "foo\x81\x81bar"
- s.scrub # => "foo��bar"
+ "foo\x81\x81bar".scrub # => "foo��bar"
+ "foo\x81\x81bar".force_encoding('US-ASCII').scrub # => "foo??bar"
+ "foo\x81\x81bar".scrub('xyzzy') # => "fooxyzzyxyzzybar"
-With no block given and argument +replacement_string+ given,
-replaces each invalid sequence with that string:
+With a block given, calls the block with each invalid sequence,
+and replaces that sequence with the return value of the block:
- "foo\x81\x81bar".scrub('xyzzy') # => "fooxyzzyxyzzybar"
+ "foo\x81\x81bar".scrub {|sequence| p sequence; 'XYZZY' } # => "fooXYZZYXYZZYbar"
-With a block given, replaces each invalid sequence with the value
-of the block:
-
- "foo\x81\x81bar".scrub {|bytes| p bytes; 'XYZZY' }
- # => "fooXYZZYXYZZYbar"
-
-Output:
+Output :
"\x81"
"\x81"
+
+Related: see {Converting to New String}[rdoc-ref:String@Converting+to+New+String].
diff --git a/doc/string/split.rdoc b/doc/string/split.rdoc
index 131c14b83f..8679149003 100644
--- a/doc/string/split.rdoc
+++ b/doc/string/split.rdoc
@@ -1,99 +1,101 @@
-Returns an array of substrings of +self+
-that are the result of splitting +self+
+Creates an array of substrings by splitting +self+
at each occurrence of the given field separator +field_sep+.
-When +field_sep+ is <tt>$;</tt>:
+With no arguments given,
+splits using the field separator <tt>$;</tt>,
+whose default value is +nil+.
-- If <tt>$;</tt> is +nil+ (its default value),
- the split occurs just as if +field_sep+ were given as a space character
- (see below).
+With no block given, returns the array of substrings:
-- If <tt>$;</tt> is a string,
- the split occurs just as if +field_sep+ were given as that string
- (see below).
+ 'abracadabra'.split('a') # => ["", "br", "c", "d", "br"]
-When +field_sep+ is <tt>' '</tt> and +limit+ is +0+ (its default value),
-the split occurs at each sequence of whitespace:
+When +field_sep+ is +nil+ or <tt>' '</tt> (a single space),
+splits at each sequence of whitespace:
- 'abc def ghi'.split(' ') # => ["abc", "def", "ghi"]
- "abc \n\tdef\t\n ghi".split(' ') # => ["abc", "def", "ghi"]
- 'abc def ghi'.split(' ') # => ["abc", "def", "ghi"]
+ 'foo bar baz'.split(nil) # => ["foo", "bar", "baz"]
+ 'foo bar baz'.split(' ') # => ["foo", "bar", "baz"]
+ "foo \n\tbar\t\n baz".split(' ') # => ["foo", "bar", "baz"]
+ 'foo bar baz'.split(' ') # => ["foo", "bar", "baz"]
''.split(' ') # => []
-When +field_sep+ is a string different from <tt>' '</tt>
-and +limit+ is +0+,
-the split occurs at each occurrence of +field_sep+;
-trailing empty substrings are not returned:
+When +field_sep+ is an empty string,
+splits at every character:
- 'abracadabra'.split('ab') # => ["", "racad", "ra"]
- 'aaabcdaaa'.split('a') # => ["", "", "", "bcd"]
- ''.split('a') # => []
- '3.14159'.split('1') # => ["3.", "4", "59"]
- '!@#$%^$&*($)_+'.split('$') # => ["!@#", "%^", "&*(", ")_+"]
- 'теÑÑ‚'.split('Ñ‚') # => ["", "еÑ"]
- 'ã“ã‚“ã«ã¡ã¯'.split('ã«') # => ["ã“ã‚“", "ã¡ã¯"]
+ 'abracadabra'.split('') # => ["a", "b", "r", "a", "c", "a", "d", "a", "b", "r", "a"]
+ ''.split('') # => []
+ 'ã“ã‚“ã«ã¡ã¯'.split('') # => ["ã“", "ã‚“", "ã«", "ã¡", "ã¯"]
-When +field_sep+ is a Regexp and +limit+ is +0+,
-the split occurs at each occurrence of a match;
-trailing empty substrings are not returned:
+When +field_sep+ is a non-empty string and different from <tt>' '</tt> (a single space),
+uses that string as the separator:
+
+ 'abracadabra'.split('a') # => ["", "br", "c", "d", "br"]
+ 'abracadabra'.split('ab') # => ["", "racad", "ra"]
+ ''.split('a') # => []
+ 'ã“ã‚“ã«ã¡ã¯'.split('ã«') # => ["ã“ã‚“", "ã¡ã¯"]
+
+When +field_sep+ is a Regexp,
+splits at each occurrence of a matching substring:
'abracadabra'.split(/ab/) # => ["", "racad", "ra"]
- 'aaabcdaaa'.split(/a/) # => ["", "", "", "bcd"]
- 'aaabcdaaa'.split(//) # => ["a", "a", "a", "b", "c", "d", "a", "a", "a"]
'1 + 1 == 2'.split(/\W+/) # => ["1", "1", "2"]
+ 'abracadabra'.split(//) # => ["a", "b", "r", "a", "c", "a", "d", "a", "b", "r", "a"]
-If the \Regexp contains groups, their matches are also included
+If the \Regexp contains groups, their matches are included
in the returned array:
'1:2:3'.split(/(:)()()/, 2) # => ["1", ":", "", "", "2:3"]
-As seen above, if +limit+ is +0+,
-trailing empty substrings are not returned:
+Argument +limit+ sets a limit on the size of the returned array;
+it also determines whether trailing empty strings are included in the returned array.
- 'aaabcdaaa'.split('a') # => ["", "", "", "bcd"]
+When +limit+ is zero,
+there is no limit on the size of the array,
+but trailing empty strings are omitted:
-If +limit+ is positive integer +n+, no more than <tt>n - 1-</tt>
-splits occur, so that at most +n+ substrings are returned,
-and trailing empty substrings are included:
+ 'abracadabra'.split('', 0) # => ["a", "b", "r", "a", "c", "a", "d", "a", "b", "r", "a"]
+ 'abracadabra'.split('a', 0) # => ["", "br", "c", "d", "br"] # Empty string after last 'a' omitted.
- 'aaabcdaaa'.split('a', 1) # => ["aaabcdaaa"]
- 'aaabcdaaa'.split('a', 2) # => ["", "aabcdaaa"]
- 'aaabcdaaa'.split('a', 5) # => ["", "", "", "bcd", "aa"]
- 'aaabcdaaa'.split('a', 7) # => ["", "", "", "bcd", "", "", ""]
- 'aaabcdaaa'.split('a', 8) # => ["", "", "", "bcd", "", "", ""]
+When +limit+ is a positive integer,
+there is a limit on the size of the array (no more than <tt>n - 1</tt> splits occur),
+and trailing empty strings are included:
-Note that if +field_sep+ is a \Regexp containing groups,
-their matches are in the returned array, but do not count toward the limit.
+ 'abracadabra'.split('', 3) # => ["a", "b", "racadabra"]
+ 'abracadabra'.split('a', 3) # => ["", "br", "cadabra"]
+ 'abracadabra'.split('', 30) # => ["a", "b", "r", "a", "c", "a", "d", "a", "b", "r", "a", ""]
+ 'abracadabra'.split('a', 30) # => ["", "br", "c", "d", "br", ""]
+ 'abracadabra'.split('', 1) # => ["abracadabra"]
+ 'abracadabra'.split('a', 1) # => ["abracadabra"]
-If +limit+ is negative, it behaves the same as if +limit+ was zero,
-meaning that there is no limit,
-and trailing empty substrings are included:
+When +limit+ is negative,
+there is no limit on the size of the array,
+and trailing empty strings are omitted:
- 'aaabcdaaa'.split('a', -1) # => ["", "", "", "bcd", "", "", ""]
+ 'abracadabra'.split('', -1) # => ["a", "b", "r", "a", "c", "a", "d", "a", "b", "r", "a", ""]
+ 'abracadabra'.split('a', -1) # => ["", "br", "c", "d", "br", ""]
If a block is given, it is called with each substring and returns +self+:
- 'abc def ghi'.split(' ') {|substring| p substring }
+ 'foo bar baz'.split(' ') {|substring| p substring }
+
+Output :
+
+ "foo"
+ "bar"
+ "baz"
-Output:
+Note that the above example is functionally equivalent to:
- "abc"
- "def"
- "ghi"
- => "abc def ghi"
+ 'foo bar baz'.split(' ').each {|substring| p substring }
-Note that the above example is functionally the same as calling +#each+ after
-+#split+ and giving the same block. However, the above example has better
-performance because it avoids the creation of an intermediate array. Also,
-note the different return values.
+Output :
- 'abc def ghi'.split(' ').each {|substring| p substring }
+ "foo"
+ "bar"
+ "baz"
-Output:
+But the latter:
- "abc"
- "def"
- "ghi"
- => ["abc", "def", "ghi"]
+- Has poorer performance because it creates an intermediate array.
+- Returns an array (instead of +self+).
-Related: String#partition, String#rpartition.
+Related: see {Converting to Non-String}[rdoc-ref:String@Converting+to+Non-String].
diff --git a/doc/string/squeeze.rdoc b/doc/string/squeeze.rdoc
new file mode 100644
index 0000000000..1a38c08b32
--- /dev/null
+++ b/doc/string/squeeze.rdoc
@@ -0,0 +1,33 @@
+Returns a copy of +self+ with each tuple (doubling, tripling, etc.) of specified characters
+"squeezed" down to a single character.
+
+The tuples to be squeezed are specified by arguments +selectors+,
+each of which is a string;
+see {Character Selectors}[rdoc-ref:character_selectors.rdoc@Character+Selectors].
+
+A single argument may be a single character:
+
+ 'Noooooo!'.squeeze('o') # => "No!"
+ 'foo bar baz'.squeeze(' ') # => "foo bar baz"
+ 'Mississippi'.squeeze('s') # => "Misisippi"
+ 'Mississippi'.squeeze('p') # => "Mississipi"
+ 'Mississippi'.squeeze('x') # => "Mississippi" # Unused selector character is ignored.
+ 'беÑÑонница'.squeeze('Ñ') # => "беÑонница"
+ 'беÑÑонница'.squeeze('н') # => "беÑÑоница"
+
+A single argument may be a string of characters:
+
+ 'Mississippi'.squeeze('sp') # => "Misisipi"
+ 'Mississippi'.squeeze('ps') # => "Misisipi" # Order doesn't matter.
+ 'Mississippi'.squeeze('nonsense') # => "Misisippi" # Unused selector characters are ignored.
+
+A single argument may be a range of characters:
+
+ 'Mississippi'.squeeze('a-p') # => "Mississipi"
+ 'Mississippi'.squeeze('q-z') # => "Misisippi"
+ 'Mississippi'.squeeze('a-z') # => "Misisipi"
+
+Multiple arguments are allowed;
+see {Multiple Character Selectors}[rdoc-ref:character_selectors.rdoc@Multiple+Character+Selectors].
+
+Related: see {Converting to New String}[rdoc-ref:String@Converting+to+New+String].
diff --git a/doc/string/start_with_p.rdoc b/doc/string/start_with_p.rdoc
index 5d1f9f9543..f78edc7fa3 100644
--- a/doc/string/start_with_p.rdoc
+++ b/doc/string/start_with_p.rdoc
@@ -1,10 +1,9 @@
-Returns whether +self+ starts with any of the given +string_or_regexp+.
+Returns whether +self+ starts with any of the given +patterns+.
-Matches patterns against the beginning of +self+.
-For each given +string_or_regexp+, the pattern is:
+For each argument, the pattern used is:
-- +string_or_regexp+ itself, if it is a Regexp.
-- <tt>Regexp.quote(string_or_regexp)</tt>, if +string_or_regexp+ is a string.
+- The pattern itself, if it is a Regexp.
+- <tt>Regexp.quote(pattern)</tt>, if it is a string.
Returns +true+ if any pattern matches the beginning, +false+ otherwise:
@@ -12,7 +11,6 @@ Returns +true+ if any pattern matches the beginning, +false+ otherwise:
'hello'.start_with?(/H/i) # => true
'hello'.start_with?('heaven', 'hell') # => true
'hello'.start_with?('heaven', 'paradise') # => false
- 'теÑÑ‚'.start_with?('Ñ‚') # => true
'ã“ã‚“ã«ã¡ã¯'.start_with?('ã“') # => true
-Related: String#end_with?.
+Related: see {Querying}[rdoc-ref:String@Querying].
diff --git a/doc/string/sub.rdoc b/doc/string/sub.rdoc
new file mode 100644
index 0000000000..ff051ea177
--- /dev/null
+++ b/doc/string/sub.rdoc
@@ -0,0 +1,33 @@
+Returns a copy of self, possibly with a substring replaced.
+
+Argument +pattern+ may be a string or a Regexp;
+argument +replacement+ may be a string or a Hash.
+
+Varying types for the argument values makes this method very versatile.
+
+Below are some simple examples; for many more examples,
+see {Substitution Methods}[rdoc-ref:String@Substitution+Methods].
+
+With arguments +pattern+ and string +replacement+ given,
+replaces the first matching substring with the given replacement string:
+
+ s = 'abracadabra' # => "abracadabra"
+ s.sub('bra', 'xyzzy') # => "axyzzycadabra"
+ s.sub(/bra/, 'xyzzy') # => "axyzzycadabra"
+ s.sub('nope', 'xyzzy') # => "abracadabra"
+
+With arguments +pattern+ and hash +replacement+ given,
+replaces the first matching substring with a value from the given replacement hash, or removes it:
+
+ h = {'a' => 'A', 'b' => 'B', 'c' => 'C'}
+ s.sub('b', h) # => "aBracadabra"
+ s.sub(/b/, h) # => "aBracadabra"
+ s.sub(/d/, h) # => "abracaabra" # 'd' removed.
+
+With argument +pattern+ and a block given,
+calls the block with each matching substring;
+replaces that substring with the block’s return value:
+
+ s.sub('b') {|match| match.upcase } # => "aBracadabra"
+
+Related: see {Converting to New String}[rdoc-ref:String@Converting+to+New+String].
diff --git a/doc/string/succ.rdoc b/doc/string/succ.rdoc
new file mode 100644
index 0000000000..1b4b936a8e
--- /dev/null
+++ b/doc/string/succ.rdoc
@@ -0,0 +1,52 @@
+Returns the successor to +self+. The successor is calculated by
+incrementing characters.
+
+The first character to be incremented is the rightmost alphanumeric:
+or, if no alphanumerics, the rightmost character:
+
+ 'THX1138'.succ # => "THX1139"
+ '<<koala>>'.succ # => "<<koalb>>"
+ '***'.succ # => '**+'
+ 'ã“ã‚“ã«ã¡ã¯'.succ # => "ã“ã‚“ã«ã¡ã°"
+
+The successor to a digit is another digit, "carrying" to the next-left
+character for a "rollover" from 9 to 0, and prepending another digit
+if necessary:
+
+ '00'.succ # => "01"
+ '09'.succ # => "10"
+ '99'.succ # => "100"
+
+The successor to a letter is another letter of the same case,
+carrying to the next-left character for a rollover,
+and prepending another same-case letter if necessary:
+
+ 'aa'.succ # => "ab"
+ 'az'.succ # => "ba"
+ 'zz'.succ # => "aaa"
+ 'AA'.succ # => "AB"
+ 'AZ'.succ # => "BA"
+ 'ZZ'.succ # => "AAA"
+
+The successor to a non-alphanumeric character is the next character
+in the underlying character set's collating sequence,
+carrying to the next-left character for a rollover,
+and prepending another character if necessary:
+
+ s = 0.chr * 3 # => "\x00\x00\x00"
+ s.succ # => "\x00\x00\x01"
+ s = 255.chr * 3 # => "\xFF\xFF\xFF"
+ s.succ # => "\x01\x00\x00\x00"
+
+Carrying can occur between and among mixtures of alphanumeric characters:
+
+ s = 'zz99zz99' # => "zz99zz99"
+ s.succ # => "aaa00aa00"
+ s = '99zz99zz' # => "99zz99zz"
+ s.succ # => "100aa00aa"
+
+The successor to an empty +String+ is a new empty +String+:
+
+ ''.succ # => ""
+
+Related: see {Converting to New String}[rdoc-ref:String@Converting+to+New+String].
diff --git a/doc/string/sum.rdoc b/doc/string/sum.rdoc
index 5de24e6402..22045e5f4d 100644
--- a/doc/string/sum.rdoc
+++ b/doc/string/sum.rdoc
@@ -1,11 +1,12 @@
-Returns a basic +n+-bit checksum of the characters in +self+;
+Returns a basic +n+-bit {checksum}[https://en.wikipedia.org/wiki/Checksum] of the characters in +self+;
the checksum is the sum of the binary value of each byte in +self+,
modulo <tt>2**n - 1</tt>:
'hello'.sum # => 532
'hello'.sum(4) # => 4
'hello'.sum(64) # => 532
- 'теÑÑ‚'.sum # => 1405
'ã“ã‚“ã«ã¡ã¯'.sum # => 2582
This is not a particularly strong checksum.
+
+Related: see {Querying}[rdoc-ref:String@Querying].
diff --git a/doc/string/swapcase.rdoc b/doc/string/swapcase.rdoc
new file mode 100644
index 0000000000..4353c8528a
--- /dev/null
+++ b/doc/string/swapcase.rdoc
@@ -0,0 +1,31 @@
+Returns a string containing the characters in +self+, with cases reversed:
+
+- Each uppercase character is downcased.
+- Each lowercase character is upcased.
+
+Examples:
+
+ 'Hello'.swapcase # => "hELLO"
+ 'Straße'.swapcase # => "sTRASSE"
+ 'RubyGems.org'.swapcase # => "rUBYgEMS.ORG"
+
+The sizes of +self+ and the upcased result may differ:
+
+ s = 'Straße'
+ s.size # => 6
+ s.swapcase # => "sTRASSE"
+ s.swapcase.size # => 7
+
+Some characters (and some character sets) do not have upcase and downcase versions;
+see {Case Mapping}[rdoc-ref:case_mapping.rdoc]:
+
+ s = '1, 2, 3, ...'
+ s.swapcase == s # => true
+ s = 'ã“ã‚“ã«ã¡ã¯'
+ s.swapcase == s # => true
+
+The casing is affected by the given +mapping+,
+which may be +:ascii+, +:fold+, or +:turkic+;
+see {Case Mappings}[rdoc-ref:case_mapping.rdoc@Case+Mappings].
+
+Related: see {Converting to New String}[rdoc-ref:String@Converting+to+New+String].
diff --git a/doc/string/unicode_normalize.rdoc b/doc/string/unicode_normalize.rdoc
new file mode 100644
index 0000000000..5f733c0fb8
--- /dev/null
+++ b/doc/string/unicode_normalize.rdoc
@@ -0,0 +1,28 @@
+Returns a copy of +self+ with
+{Unicode normalization}[https://unicode.org/reports/tr15] applied.
+
+Argument +form+ must be one of the following symbols
+(see {Unicode normalization forms}[https://unicode.org/reports/tr15/#Norm_Forms]):
+
+- +:nfc+: Canonical decomposition, followed by canonical composition.
+- +:nfd+: Canonical decomposition.
+- +:nfkc+: Compatibility decomposition, followed by canonical composition.
+- +:nfkd+: Compatibility decomposition.
+
+The encoding of +self+ must be one of:
+
+- <tt>Encoding::UTF_8</tt>.
+- <tt>Encoding::UTF_16BE</tt>.
+- <tt>Encoding::UTF_16LE</tt>.
+- <tt>Encoding::UTF_32BE</tt>.
+- <tt>Encoding::UTF_32LE</tt>.
+- <tt>Encoding::GB18030</tt>.
+- <tt>Encoding::UCS_2BE</tt>.
+- <tt>Encoding::UCS_4BE</tt>.
+
+Examples:
+
+ "a\u0300".unicode_normalize # => "à" # Lowercase 'a' with grave accens.
+ "a\u0300".unicode_normalize(:nfd) # => "à" # Same.
+
+Related: see {Converting to New String}[rdoc-ref:String@Converting+to+New+String].
diff --git a/doc/string/upcase.rdoc b/doc/string/upcase.rdoc
new file mode 100644
index 0000000000..ad859e8973
--- /dev/null
+++ b/doc/string/upcase.rdoc
@@ -0,0 +1,27 @@
+Returns a new string containing the upcased characters in +self+:
+
+ 'hello'.upcase # => "HELLO"
+ 'straße'.upcase # => "STRASSE"
+ 'привет'.upcase # => "ПРИВЕТ"
+ 'RubyGems.org'.upcase # => "RUBYGEMS.ORG"
+
+The sizes of +self+ and the upcased result may differ:
+
+ s = 'Straße'
+ s.size # => 6
+ s.upcase # => "STRASSE"
+ s.upcase.size # => 7
+
+Some characters (and some character sets) do not have upcase and downcase versions;
+see {Case Mapping}[rdoc-ref:case_mapping.rdoc]:
+
+ s = '1, 2, 3, ...'
+ s.upcase == s # => true
+ s = 'ã“ã‚“ã«ã¡ã¯'
+ s.upcase == s # => true
+
+The casing is affected by the given +mapping+,
+which may be +:ascii+, +:fold+, or +:turkic+;
+see {Case Mappings}[rdoc-ref:case_mapping.rdoc@Case+Mappings].
+
+Related: see {Converting to New String}[rdoc-ref:String@Converting+to+New+String].
diff --git a/doc/string/upto.rdoc b/doc/string/upto.rdoc
new file mode 100644
index 0000000000..f860fe84fe
--- /dev/null
+++ b/doc/string/upto.rdoc
@@ -0,0 +1,38 @@
+With a block given, calls the block with each +String+ value
+returned by successive calls to String#succ;
+the first value is +self+, the next is <tt>self.succ</tt>, and so on;
+the sequence terminates when value +other_string+ is reached;
+returns +self+:
+
+ a = []
+ 'a'.upto('f') {|c| a.push(c) }
+ a # => ["a", "b", "c", "d", "e", "f"]
+
+ a = []
+ 'Ж'.upto('П') {|c| a.push(c) }
+ a # => ["Ж", "З", "И", "Й", "К", "Л", "М", "Ð", "О", "П"]
+
+ a = []
+ 'よ'.upto('ã‚') {|c| a.push(c) }
+ a # => ["よ", "ら", "り", "ã‚‹", "れ", "ã‚"]
+
+ a = []
+ 'a8'.upto('b6') {|c| a.push(c) }
+ a # => ["a8", "a9", "b0", "b1", "b2", "b3", "b4", "b5", "b6"]
+
+If argument +exclusive+ is given as a truthy object, the last value is omitted:
+
+ a = []
+ 'a'.upto('f', true) {|c| a.push(c) }
+ a # => ["a", "b", "c", "d", "e"]
+
+If +other_string+ would not be reached, does not call the block:
+
+ '25'.upto('5') {|s| fail s }
+ 'aa'.upto('a') {|s| fail s }
+
+With no block given, returns a new Enumerator:
+
+ 'a8'.upto('b6') # => #<Enumerator: "a8":upto("b6")>
+
+Related: see {Iterating}[rdoc-ref:String@Iterating].
diff --git a/doc/string/valid_encoding_p.rdoc b/doc/string/valid_encoding_p.rdoc
new file mode 100644
index 0000000000..e1db55174a
--- /dev/null
+++ b/doc/string/valid_encoding_p.rdoc
@@ -0,0 +1,8 @@
+Returns whether +self+ is encoded correctly:
+
+ s = 'Straße'
+ s.valid_encoding? # => true
+ s.encoding # => #<Encoding:UTF-8>
+ s.force_encoding(Encoding::ASCII).valid_encoding? # => false
+
+Related: see {Querying}[rdoc-ref:String@Querying].
diff --git a/doc/stringio/each_byte.rdoc b/doc/stringio/each_byte.rdoc
new file mode 100644
index 0000000000..708432b69e
--- /dev/null
+++ b/doc/stringio/each_byte.rdoc
@@ -0,0 +1,31 @@
+With a block given, calls the block with each remaining byte in the stream;
+positions the stream at end-of-file;
+returns +self+:
+
+ bytes = []
+ strio = StringIO.new('hello') # Five 1-byte characters.
+ strio.each_byte {|byte| bytes.push(byte) }
+ strio.eof? # => true
+ bytes # => [104, 101, 108, 108, 111]
+
+ bytes = []
+ strio = StringIO.new('ã“ã‚“ã«ã¡ã¯') # Five 3-byte characters.
+ strio.each_byte {|byte| bytes.push(byte) }
+ bytes # => [227, 129, 147, 227, 130, 147, 227, 129, 171, 227, 129, 161, 227, 129, 175]
+
+The position in the stream matters:
+
+ bytes = []
+ strio = StringIO.new('ã“ã‚“ã«ã¡ã¯')
+ strio.getc # => "ã“"
+ strio.pos # => 3 # 3-byte character was read.
+ strio.each_byte {|byte| bytes.push(byte) }
+ bytes # => [227, 130, 147, 227, 129, 171, 227, 129, 161, 227, 129, 175]
+
+If at end-of-file, does not call the block:
+
+ strio.eof? # => true
+ strio.each_byte {|byte| fail 'Boo!' }
+ strio.eof? # => true
+
+With no block given, returns a new {Enumerator}[rdoc-ref:Enumerator].
diff --git a/doc/stringio/each_char.rdoc b/doc/stringio/each_char.rdoc
new file mode 100644
index 0000000000..bec5ecac3f
--- /dev/null
+++ b/doc/stringio/each_char.rdoc
@@ -0,0 +1,31 @@
+With a block given, calls the block with each remaining character in the stream;
+positions the stream at end-of-file;
+returns +self+:
+
+ chars = []
+ strio = StringIO.new('hello')
+ strio.each_char {|char| chars.push(char) }
+ strio.eof? # => true
+ chars # => ["h", "e", "l", "l", "o"]
+
+ chars = []
+ strio = StringIO.new('ã“ã‚“ã«ã¡ã¯')
+ strio.each_char {|char| chars.push(char) }
+ chars # => ["ã“", "ã‚“", "ã«", "ã¡", "ã¯"]
+
+Stream position matters:
+
+ chars = []
+ strio = StringIO.new('ã“ã‚“ã«ã¡ã¯')
+ strio.getc # => "ã“"
+ strio.pos # => 3 # 3-byte character was read.
+ strio.each_char {|char| chars.push(char) }
+ chars # => ["ã‚“", "ã«", "ã¡", "ã¯"]
+
+When at end-of-stream does not call the block:
+
+ strio.eof? # => true
+ strio.each_char {|char| fail 'Boo!' }
+ strio.eof? # => true
+
+With no block given, returns a new {Enumerator}[rdoc-ref:Enumerator].
diff --git a/doc/stringio/each_codepoint.rdoc b/doc/stringio/each_codepoint.rdoc
new file mode 100644
index 0000000000..0d10831142
--- /dev/null
+++ b/doc/stringio/each_codepoint.rdoc
@@ -0,0 +1,33 @@
+With a block given, calls the block with each successive codepoint from self;
+sets the position to end-of-stream;
+returns +self+.
+
+Each codepoint is the integer value for a character; returns self:
+
+ codepoints = []
+ strio = StringIO.new('hello')
+ strio.each_codepoint {|codepoint| codepoints.push(codepoint) }
+ strio.eof? # => true
+ codepoints # => [104, 101, 108, 108, 111]
+
+ codepoints = []
+ strio = StringIO.new('ã“ã‚“ã«ã¡ã¯')
+ strio.each_codepoint {|codepoint| codepoints.push(codepoint) }
+ codepoints # => [12371, 12435, 12395, 12385, 12399]
+
+Position in the stream matters:
+
+ codepoints = []
+ strio = StringIO.new('ã“ã‚“ã«ã¡ã¯')
+ strio.getc # => "ã“"
+ strio.pos # => 3
+ strio.each_codepoint {|codepoint| codepoints.push(codepoint) }
+ codepoints # => [12435, 12395, 12385, 12399]
+
+When at end-of-stream, the block is not called:
+
+ strio.eof? # => true
+ strio.each_codepoint {|codepoint| fail 'Boo!' }
+ strio.eof? # => true
+
+With no block given, returns a new {Enumerator}[rdoc-ref:Enumerator].
diff --git a/doc/stringio/each_line.md b/doc/stringio/each_line.md
new file mode 100644
index 0000000000..e29640a12a
--- /dev/null
+++ b/doc/stringio/each_line.md
@@ -0,0 +1,189 @@
+With a block given calls the block with each remaining line (see "Position" below) in the stream;
+returns `self`.
+
+Leaves stream position at end-of-stream.
+
+**No Arguments**
+
+With no arguments given,
+reads lines using the default record separator
+(global variable `$/`, whose initial value is `"\n"`).
+
+```ruby
+strio = StringIO.new(TEXT)
+strio.each_line {|line| p line }
+strio.eof? # => true
+```
+
+Output:
+
+```
+"First line\n"
+"Second line\n"
+"\n"
+"Fourth line\n"
+"Fifth line\n"
+```
+
+**Argument `sep`**
+
+With only string argument `sep` given,
+reads lines using that string as the record separator:
+
+```ruby
+strio = StringIO.new(TEXT)
+strio.each_line(' ') {|line| p line }
+```
+
+Output:
+
+```
+"First "
+"line\nSecond "
+"line\n\nFourth "
+"line\nFifth "
+"line\n"
+```
+
+**Argument `limit`**
+
+With only integer argument `limit` given,
+reads lines using the default record separator;
+also limits the size (in characters) of each line to the given limit:
+
+```ruby
+strio = StringIO.new(TEXT)
+strio.each_line(10) {|line| p line }
+```
+
+Output:
+
+```
+"First line"
+"\n"
+"Second lin"
+"e\n"
+"\n"
+"Fourth lin"
+"e\n"
+"Fifth line"
+"\n"
+```
+
+**Arguments `sep` and `limit`**
+
+With arguments `sep` and `limit` both given,
+honors both:
+
+```ruby
+strio = StringIO.new(TEXT)
+strio.each_line(' ', 10) {|line| p line }
+```
+
+Output:
+
+```
+"First "
+"line\nSecon"
+"d "
+"line\n\nFour"
+"th "
+"line\nFifth"
+" "
+"line\n"
+```
+
+**Position**
+
+As stated above, method `each` _remaining_ line in the stream.
+
+In the examples above each `strio` object starts with its position at beginning-of-stream;
+but in other cases the position may be anywhere (see StringIO#pos):
+
+```ruby
+strio = StringIO.new(TEXT)
+strio.pos = 30 # Set stream position to character 30.
+strio.each_line {|line| p line }
+```
+
+Output:
+
+```
+" line\n"
+"Fifth line\n"
+```
+
+In all the examples above, the stream position is at the beginning of a character;
+in other cases, that need not be so:
+
+```ruby
+s = 'ã“ã‚“ã«ã¡ã¯' # Five 3-byte characters.
+strio = StringIO.new(s)
+strio.pos = 3 # At beginning of second character.
+strio.each_line {|line| p line }
+strio.pos = 4 # At second byte of second character.
+strio.each_line {|line| p line }
+strio.pos = 5 # At third byte of second character.
+strio.each_line {|line| p line }
+```
+
+Output:
+
+```
+"ã‚“ã«ã¡ã¯"
+"\x82\x93ã«ã¡ã¯"
+"\x93ã«ã¡ã¯"
+```
+
+**Special Record Separators**
+
+Like some methods in class `IO`, StringIO.each honors two special record separators;
+see {Special Line Separators}[https://docs.ruby-lang.org/en/master/IO.html#class-IO-label-Special+Line+Separator+Values].
+
+```ruby
+strio = StringIO.new(TEXT)
+strio.each_line('') {|line| p line } # Read as paragraphs (separated by blank lines).
+```
+
+Output:
+
+```
+"First line\nSecond line\n\n"
+"Fourth line\nFifth line\n"
+```
+
+```ruby
+strio = StringIO.new(TEXT)
+strio.each_line(nil) {|line| p line } # "Slurp"; read it all.
+```
+
+Output:
+
+```
+"First line\nSecond line\n\nFourth line\nFifth line\n"
+```
+
+**Keyword Argument `chomp`**
+
+With keyword argument `chomp` given as `true` (the default is `false`),
+removes trailing newline (if any) from each line:
+
+```ruby
+strio = StringIO.new(TEXT)
+strio.each_line(chomp: true) {|line| p line }
+```
+
+Output:
+
+```
+"First line"
+"Second line"
+""
+"Fourth line"
+"Fifth line"
+```
+
+With no block given, returns a new {Enumerator}[https://docs.ruby-lang.org/en/master/Enumerator.html].
+
+
+Related: StringIO.each_byte, StringIO.each_char, StringIO.each_codepoint.
diff --git a/doc/stringio/getbyte.rdoc b/doc/stringio/getbyte.rdoc
new file mode 100644
index 0000000000..148455abf4
--- /dev/null
+++ b/doc/stringio/getbyte.rdoc
@@ -0,0 +1,24 @@
+Reads and returns the next integer byte (not character) from the stream:
+
+ s = 'foo'
+ s.bytes # => [102, 111, 111]
+ strio = StringIO.new(s)
+ strio.getbyte # => 102
+ strio.getbyte # => 111
+ strio.getbyte # => 111
+
+Returns +nil+ if at end-of-stream:
+
+ strio.eof? # => true
+ strio.getbyte # => nil
+
+Returns a byte, not a character:
+
+ s = 'ã“ã‚“ã«ã¡ã¯'
+ s.bytes
+ # => [227, 129, 147, 227, 130, 147, 227, 129, 171, 227, 129, 161, 227, 129, 175]
+ strio = StringIO.new(s)
+ strio.getbyte # => 227
+ strio.getbyte # => 129
+
+Related: #each_byte, #ungetbyte, #getc.
diff --git a/doc/stringio/getc.rdoc b/doc/stringio/getc.rdoc
new file mode 100644
index 0000000000..58ce47c337
--- /dev/null
+++ b/doc/stringio/getc.rdoc
@@ -0,0 +1,30 @@
+Reads and returns the next character (or byte; see below) from the stream:
+
+ strio = StringIO.new('foo')
+ strio.getc # => "f"
+ strio.getc # => "o"
+ strio.getc # => "o"
+
+Returns +nil+ if at end-of-stream:
+
+ strio.eof? # => true
+ strio.getc # => nil
+
+Returns characters, not bytes:
+
+ strio = StringIO.new('ã“ã‚“ã«ã¡ã¯')
+ strio.getc # => "ã“"
+ strio.getc # => "ã‚“"
+
+In each of the examples above, the stream is positioned at the beginning of a character;
+in other cases that need not be true:
+
+ strio = StringIO.new('ã“ã‚“ã«ã¡ã¯') # Five 3-byte characters.
+ strio.pos = 3 # => 3 # At beginning of second character; returns character.
+ strio.getc # => "ã‚“"
+ strio.pos = 4 # => 4 # At second byte of second character; returns byte.
+ strio.getc # => "\x82"
+ strio.pos = 5 # => 5 # At third byte of second character; returns byte.
+ strio.getc # => "\x93"
+
+Related: #getbyte, #putc, #ungetc.
diff --git a/doc/stringio/gets.rdoc b/doc/stringio/gets.rdoc
new file mode 100644
index 0000000000..4152152a25
--- /dev/null
+++ b/doc/stringio/gets.rdoc
@@ -0,0 +1,99 @@
+Reads and returns a line from the stream;
+returns +nil+ if at end-of-stream.
+
+Side effects:
+
+- Increments stream position by the number of bytes read.
+- Assigns the return value to global variable <tt>$_</tt>.
+
+With no arguments given, reads a line using the default record separator
+(global variable <tt>$/</tt>,* whose initial value is <tt>"\n"</tt>):
+
+ strio = StringIO.new(TEXT)
+ strio.pos # => 0
+ strio.gets # => "First line\n"
+ strio.pos # => 11
+ $_ # => "First line\n"
+ strio.gets # => "Second line\n"
+ strio.read # => "\nFourth line\nFifth line\n"
+ strio.eof? # => true
+ strio.gets # => nil
+
+ strio = StringIO.new('ã“ã‚“ã«ã¡ã¯') # Five 3-byte characters.
+ strio.pos # => 0
+ strio.gets # => "ã“ã‚“ã«ã¡ã¯"
+ strio.pos # => 15
+
+<b>Argument +sep+</b>
+
+With only string argument +sep+ given, reads a line using that string as the record separator:
+
+ strio = StringIO.new(TEXT)
+ strio.gets(' ') # => "First "
+ strio.gets(' ') # => "line\nSecond "
+ strio.gets(' ') # => "line\n\nFourth "
+
+<b>Argument +limit+</b>
+
+With only integer argument +limit+ given,
+reads a line using the default record separator;
+limits the size (in characters) of each line to the given limit:
+
+ strio = StringIO.new(TEXT)
+ strio.gets(10) # => "First line"
+ strio.gets(10) # => "\n"
+ strio.gets(10) # => "Second lin"
+ strio.gets(10) # => "e\n"
+
+<b>Arguments +sep+ and +limit+</b>
+
+With arguments +sep+ and +limit+ both given, honors both:
+
+ strio = StringIO.new(TEXT)
+ strio.gets(' ', 10) # => "First "
+ strio.gets(' ', 10) # => "line\nSecon"
+ strio.gets(' ', 10) # => "d "
+
+<b>Position</b>
+
+As stated above, method +gets+ reads and returns the next line in the stream.
+
+In the examples above each +strio+ object starts with its position at beginning-of-stream;
+but in other cases the position may be anywhere:
+
+ strio = StringIO.new(TEXT)
+ strio.pos = 12
+ strio.gets # => "econd line\n"
+
+The position need not be at a character boundary:
+
+ strio = StringIO.new('ã“ã‚“ã«ã¡ã¯') # Five 3-byte characters.
+ strio.pos = 3 # At beginning of second character.
+ strio.gets # => "ã‚“ã«ã¡ã¯"
+ strio.pos = 4 # Within second character.
+ strio.gets # => "\x82\x93ã«ã¡ã¯"
+
+<b>Special Record Separators</b>
+
+Like some methods in class IO, method +gets+ honors two special record separators;
+see {Special Line Separators}[https://docs.ruby-lang.org/en/master/IO.html#class-IO-label-Special+Line+Separator+Values]:
+
+ strio = StringIO.new(TEXT)
+ strio.gets('') # Read "paragraph" (up to empty line).
+ # => "First line\nSecond line\n\n"
+
+ strio = StringIO.new(TEXT)
+ strio.gets(nil) # "Slurp": read all.
+ # => "First line\nSecond line\n\nFourth line\nFifth line\n"
+
+<b>Keyword Argument +chomp+</b>
+
+With keyword argument +chomp+ given as +true+ (the default is +false+),
+removes the trailing newline (if any) from the returned line:
+
+ strio = StringIO.new(TEXT)
+ strio.gets # => "First line\n"
+ strio.gets(chomp: true) # => "Second line"
+
+Related: #each_line, #readlines,
+{Kernel#puts}[rdoc-ref:Kernel#puts].
diff --git a/doc/stringio/pread.rdoc b/doc/stringio/pread.rdoc
new file mode 100644
index 0000000000..2dcbc18ad8
--- /dev/null
+++ b/doc/stringio/pread.rdoc
@@ -0,0 +1,65 @@
+**Note**: \Method +pread+ is different from other reading methods
+in that it does not modify +self+ in any way;
+thus, multiple threads may read safely from the same stream.
+
+Reads up to +maxlen+ bytes from the stream,
+beginning at 0-based byte offset +offset+;
+returns a string containing the read bytes.
+
+The returned string:
+
+- Contains +maxlen+ bytes from the stream, if available;
+ otherwise contains all available bytes.
+- Has encoding +Encoding::ASCII_8BIT+.
+
+With only arguments +maxlen+ and +offset+ given,
+returns a new string:
+
+ english = 'Hello' # Five 1-byte characters.
+ strio = StringIO.new(english)
+ strio.pread(3, 0) # => "Hel"
+ strio.pread(3, 2) # => "llo"
+ strio.pread(0, 0) # => ""
+ strio.pread(50, 0) # => "Hello"
+ strio.pread(50, 2) # => "llo"
+ strio.pread(50, 4) # => "o"
+ strio.pread(0, 0).encoding
+ # => #<Encoding:BINARY (ASCII-8BIT)>
+
+ russian = 'Привет' # Six 2-byte characters.
+ strio = StringIO.new(russian)
+ strio.pread(50, 0) # All 12 bytes.
+ # => "\xD0\x9F\xD1\x80\xD0\xB8\xD0\xB2\xD0\xB5\xD1\x82"
+ strio.pread(3, 0) # => "\xD0\x9F\xD1"
+ strio.pread(3, 3) # => "\x80\xD0\xB8"
+ strio.pread(0, 0).encoding
+ # => #<Encoding:BINARY (ASCII-8BIT)>
+
+ japanese = 'ã“ã‚“ã«ã¡ã¯' # Five 3-byte characters.
+ strio = StringIO.new(japanese)
+ strio.pread(50, 0) # All 15 bytes.
+ # => "\xE3\x81\x93\xE3\x82\x93\xE3\x81\xAB\xE3\x81\xA1\xE3\x81\xAF"
+ strio.pread(6, 0) # => "\xE3\x81\x93\xE3\x82\x93"
+ strio.pread(1, 2) # => "\x93"
+ strio.pread(0, 0).encoding
+ # => #<Encoding:BINARY (ASCII-8BIT)>
+
+Raises an exception if +offset+ is out-of-range:
+
+ strio = StringIO.new(english)
+ strio.pread(5, 50) # Raises EOFError: end of file reached
+
+With string argument +out_string+ given:
+
+- Reads as above.
+- Overwrites the content of +out_string+ with the read bytes.
+
+Examples:
+
+ out_string = 'Will be overwritten'
+ out_string.encoding # => #<Encoding:UTF-8>
+ result = StringIO.new(english).pread(50, 0, out_string)
+ result.__id__ == out_string.__id__ # => true
+ out_string # => "Hello"
+ out_string.encoding # => #<Encoding:BINARY (ASCII-8BIT)>
+
diff --git a/doc/stringio/putc.rdoc b/doc/stringio/putc.rdoc
new file mode 100644
index 0000000000..4636ffa0db
--- /dev/null
+++ b/doc/stringio/putc.rdoc
@@ -0,0 +1,82 @@
+Replaces one or more bytes at position +pos+
+with bytes of the given argument;
+advances the position by the count of bytes written;
+returns the argument.
+
+\StringIO object for 1-byte characters.
+
+ strio = StringIO.new('foo')
+ strio.pos # => 0
+
+With 1-byte argument, replaces one byte:
+
+ strio.putc('b')
+ strio.string # => "boo"
+ strio.pos # => 1
+ strio.putc('a') # => "a"
+ strio.string # => "bao"
+ strio.pos # => 2
+ strio.putc('r') # => "r"
+ strio.string # => "bar"
+ strio.pos # => 3
+ strio.putc('n') # => "n"
+ strio.string # => "barn"
+ strio.pos # => 4
+
+Fills with null characters if necessary:
+
+ strio.pos = 6
+ strio.putc('x') # => "x"
+ strio.string # => "barn\u0000\u0000x"
+ strio.pos # => 7
+
+With integer argument, replaces one byte with the low-order byte of the integer:
+
+ strio = StringIO.new('foo')
+ strio.putc(70)
+ strio.string # => "Foo"
+ strio.putc(79)
+ strio.string # => "FOo"
+ strio.putc(79 + 1024)
+ strio.string # => "FOO"
+
+\StringIO object for Multi-byte characters:
+
+ greek = 'αβγδε' # Five 2-byte characters.
+ strio = StringIO.new(greek)
+ strio.string# => "αβγδε"
+ strio.string.b # => "\xCE\xB1\xCE\xB2\xCE\xB3\xCE\xB4\xCE\xB5"
+ strio.string.bytesize # => 10
+ strio.string.chars # => ["α", "β", "γ", "δ", "ε"]
+ strio.string.size # => 5
+
+With 1-byte argument, replaces one byte of the string:
+
+ strio.putc(' ') # 1-byte ascii space.
+ strio.pos # => 1
+ strio.string # => " \xB1βγδε"
+ strio.string.b # => " \xB1\xCE\xB2\xCE\xB3\xCE\xB4\xCE\xB5"
+ strio.string.bytesize # => 10
+ strio.string.chars # => [" ", "\xB1", "β", "γ", "δ", "ε"]
+ strio.string.size # => 6
+
+ strio.putc(' ')
+ strio.pos # => 2
+ strio.string # => " βγδε"
+ strio.string.b # => " \xCE\xB2\xCE\xB3\xCE\xB4\xCE\xB5"
+ strio.string.bytesize # => 10
+ strio.string.chars # => [" ", " ", "β", "γ", "δ", "ε"]
+ strio.string.size # => 6
+
+With 2-byte argument, replaces two bytes of the string:
+
+ strio.rewind
+ strio.putc('α')
+ strio.pos # => 2
+ strio.string # => "αβγδε"
+ strio.string.b # => "\xCE\xB1\xCE\xB2\xCE\xB3\xCE\xB4\xCE\xB5"
+ strio.string.bytesize # => 10
+ strio.string.chars # => ["α", "β", "γ", "δ", "ε"]
+ strio.string.size # => 5
+
+Related: #getc, #ungetc.
diff --git a/doc/stringio/read.rdoc b/doc/stringio/read.rdoc
new file mode 100644
index 0000000000..46b9fa349f
--- /dev/null
+++ b/doc/stringio/read.rdoc
@@ -0,0 +1,83 @@
+Reads and returns a string containing bytes read from the stream,
+beginning at the current position;
+advances the position by the count of bytes read.
+
+With no arguments given,
+reads all remaining bytes in the stream;
+returns a new string containing bytes read:
+
+ strio = StringIO.new('Hello') # Five 1-byte characters.
+ strio.read # => "Hello"
+ strio.pos # => 5
+ strio.read # => ""
+ StringIO.new('').read # => ""
+
+With non-negative argument +maxlen+ given,
+reads +maxlen+ bytes as available;
+returns a new string containing the bytes read, or +nil+ if none:
+
+ strio.rewind
+ strio.read(3) # => "Hel"
+ strio.read(3) # => "lo"
+ strio.read(3) # => nil
+
+ russian = 'Привет' # Six 2-byte characters.
+ russian.b
+ # => "\xD0\x9F\xD1\x80\xD0\xB8\xD0\xB2\xD0\xB5\xD1\x82"
+ strio = StringIO.new(russian)
+ strio.read(6) # => "\xD0\x9F\xD1\x80\xD0\xB8"
+ strio.read(6) # => "\xD0\xB2\xD0\xB5\xD1\x82"
+ strio.read(6) # => nil
+
+ japanese = 'ã“ã‚“ã«ã¡ã¯'
+ japanese.b
+ # => "\xE3\x81\x93\xE3\x82\x93\xE3\x81\xAB\xE3\x81\xA1\xE3\x81\xAF"
+ strio = StringIO.new(japanese)
+ strio.read(9) # => "\xE3\x81\x93\xE3\x82\x93\xE3\x81\xAB"
+ strio.read(9) # => "\xE3\x81\xA1\xE3\x81\xAF"
+ strio.read(9) # => nil
+
+With argument +max_len+ as +nil+ and string argument +out_string+ given,
+reads the remaining bytes in the stream;
+clears +out_string+ and writes the bytes into it;
+returns +out_string+:
+
+ out_string = 'Will be overwritten'
+ strio = StringIO.new('Hello')
+ strio.read(nil, out_string) # => "Hello"
+ strio.read(nil, out_string) # => ""
+
+With non-negative argument +maxlen+ and string argument +out_string+ given,
+reads the +maxlen bytes from the stream, as availble;
+clears +out_string+ and writes the bytes into it;
+returns +out_string+ if any bytes were read, or +nil+ if none:
+
+ out_string = 'Will be overwritten'
+ strio = StringIO.new('Hello')
+ strio.read(3, out_string) # => "Hel"
+ strio.read(3, out_string) # => "lo"
+ strio.read(3, out_string) # => nil
+
+ out_string = 'Will be overwritten'
+ strio = StringIO.new(russian)
+ strio.read(6, out_string) # => "При"
+ strio.read(6, out_string) # => "вет"
+ strio.read(6, out_string) # => nil
+ strio.rewind
+ russian.b
+ # => "\xD0\x9F\xD1\x80\xD0\xB8\xD0\xB2\xD0\xB5\xD1\x82"
+ strio.read(3) # => "\xD0\x9F\xD1"
+ strio.read(3) # => "\x80\xD0\xB8"
+
+ out_string = 'Will be overwritten'
+ strio = StringIO.new(japanese)
+ strio.read(9, out_string) # => "ã“ã‚“ã«"
+ strio.read(9, out_string) # => "ã¡ã¯"
+ strio.read(9, out_string) # => nil
+ strio.rewind
+ japanese.b
+ # => "\xE3\x81\x93\xE3\x82\x93\xE3\x81\xAB\xE3\x81\xA1\xE3\x81\xAF"
+ strio.read(4) # => "\xE3\x81\x93\xE3"
+ strio.read(4) # => "\x82\x93\xE3\x81"
+
+Related: #gets, #readlines.
diff --git a/doc/stringio/size.rdoc b/doc/stringio/size.rdoc
new file mode 100644
index 0000000000..253c612c43
--- /dev/null
+++ b/doc/stringio/size.rdoc
@@ -0,0 +1,4 @@
+Returns the number of bytes in the string in +self+:
+
+ StringIO.new('hello').size # => 5 # Five 1-byte characters.
+ StringIO.new('ã“ã‚“ã«ã¡ã¯').size # => 15 # Five 3-byte characters.
diff --git a/doc/stringio/stringio.md b/doc/stringio/stringio.md
new file mode 100644
index 0000000000..f81f79cfea
--- /dev/null
+++ b/doc/stringio/stringio.md
@@ -0,0 +1,702 @@
+\Class \StringIO supports accessing a string as a stream,
+similar in some ways to [class IO][io class].
+
+You can create a \StringIO instance using:
+
+- StringIO.new: returns a new \StringIO object containing the given string.
+- StringIO.open: passes a new \StringIO object to the given block.
+
+Like an \IO stream, a \StringIO stream has certain properties:
+
+- **Read/write mode**: whether the stream may be read, written, appended to, etc.;
+ see [Read/Write Mode][read/write mode].
+- **Data mode**: text-only or binary;
+ see [Data Mode][data mode].
+- **Encodings**: internal and external encodings;
+ see [Encodings][encodings].
+- **Position**: where in the stream the next read or write is to occur;
+ see [Position][position].
+- **Line number**: a special, line-oriented, "position" (different from the position mentioned above);
+ see [Line Number][line number].
+- **Open/closed**: whether the stream is open or closed, for reading or writing.
+ see [Open/Closed Streams][open/closed streams].
+- **BOM**: byte mark order;
+ see [Byte Order Mark][bom (byte order mark)].
+
+## About the Examples
+
+Examples on this page assume that \StringIO has been required:
+
+```ruby
+require 'stringio'
+```
+
+And that this constant has been defined:
+
+```ruby
+TEXT = <<EOT
+First line
+Second line
+
+Fourth line
+Fifth line
+EOT
+```
+
+## Stream Properties
+
+### Read/Write Mode
+
+#### Summary
+
+| Mode | Initial Clear? | Read | Write |
+|:--------------------------:|:--------------:|:--------:|:--------:|
+| <tt>'r'</tt>: read-only | No | Anywhere | Error |
+| <tt>'w'</tt>: write-only | Yes | Error | Anywhere |
+| <tt>'a'</tt>: append-only | No | Error | End only |
+| <tt>'r+'</tt>: read/write | No | Anywhere | Anywhere |
+| <tt>'w+'</tt>: read-write | Yes | Anywhere | Anywhere |
+| <tt>'a+'</tt>: read/append | No | Anywhere | End only |
+
+Each section below describes a read/write mode.
+
+Any of the modes may be given as a string or as file constants;
+example:
+
+```ruby
+strio = StringIO.new('foo', 'a')
+strio = StringIO.new('foo', File::WRONLY | File::APPEND)
+```
+
+#### `'r'`: Read-Only
+
+Mode specified as one of:
+
+- String: `'r'`.
+- Constant: `File::RDONLY`.
+
+Initial state:
+
+```ruby
+strio = StringIO.new('foobarbaz', 'r')
+strio.pos # => 0 # Beginning-of-stream.
+strio.string # => "foobarbaz" # Not cleared.
+```
+
+May be read anywhere:
+
+```ruby
+strio.gets(3) # => "foo"
+strio.gets(3) # => "bar"
+strio.pos = 9
+strio.gets(3) # => nil
+```
+
+May not be written:
+
+```ruby
+strio.write('foo') # Raises IOError: not opened for writing
+```
+
+#### `'w'`: Write-Only
+
+Mode specified as one of:
+
+- String: `'w'`.
+- Constant: `File::WRONLY`.
+
+Initial state:
+
+```ruby
+strio = StringIO.new('foo', 'w')
+strio.pos # => 0 # Beginning of stream.
+strio.string # => "" # Initially cleared.
+```
+
+May be written anywhere (even past end-of-stream):
+
+```ruby
+strio.write('foobar')
+strio.string # => "foobar"
+strio.rewind
+strio.write('FOO')
+strio.string # => "FOObar"
+strio.pos = 3
+strio.write('BAR')
+strio.string # => "FOOBAR"
+strio.pos = 9
+strio.write('baz')
+strio.string # => "FOOBAR\u0000\u0000\u0000baz" # Null-padded.
+```
+
+May not be read:
+
+```ruby
+strio.read # Raises IOError: not opened for reading
+```
+
+#### `'a'`: Append-Only
+
+Mode specified as one of:
+
+- String: `'a'`.
+- Constant: `File::WRONLY | File::APPEND`.
+
+Initial state:
+
+```ruby
+strio = StringIO.new('foo', 'a')
+strio.pos # => 0 # Beginning-of-stream.
+strio.string # => "foo" # Not cleared.
+```
+
+May be written only at the end; position does not affect writing:
+
+```ruby
+strio.write('bar')
+strio.string # => "foobar"
+strio.write('baz')
+strio.string # => "foobarbaz"
+strio.pos = 400
+strio.write('bat')
+strio.string # => "foobarbazbat"
+```
+
+May not be read:
+
+```ruby
+strio.gets # Raises IOError: not opened for reading
+```
+
+#### `'r+'`: Read/Write
+
+Mode specified as one of:
+
+- String: `'r+'`.
+- Constant: `File::RDRW`.
+
+Initial state:
+
+```ruby
+strio = StringIO.new('foobar', 'r+')
+strio.pos # => 0 # Beginning-of-stream.
+strio.string # => "foobar" # Not cleared.
+```
+
+May be written anywhere (even past end-of-stream):
+
+```ruby
+strio.write('FOO')
+strio.string # => "FOObar"
+strio.write('BAR')
+strio.string # => "FOOBAR"
+strio.write('BAZ')
+strio.string # => "FOOBARBAZ"
+strio.pos = 12
+strio.write('BAT')
+strio.string # => "FOOBARBAZ\u0000\u0000\u0000BAT" # Null padded.
+```
+
+May be read anywhere:
+
+```ruby
+strio.pos = 0
+strio.gets(3) # => "FOO"
+strio.pos = 6
+strio.gets(3) # => "BAZ"
+strio.pos = 400
+strio.gets(3) # => nil
+```
+
+#### `'w+'`: Read/Write (Initially Clear)
+
+Mode specified as one of:
+
+- String: `'w+'`.
+- Constant: `File::RDWR | File::TRUNC`.
+
+Initial state:
+
+```ruby
+strio = StringIO.new('foo', 'w+')
+strio.pos # => 0 # Beginning-of-stream.
+strio.string # => "" # Truncated.
+```
+
+May be written anywhere (even past end-of-stream):
+
+```ruby
+strio.write('foobar')
+strio.string # => "foobar"
+strio.rewind
+strio.write('FOO')
+strio.string # => "FOObar"
+strio.write('BAR')
+strio.string # => "FOOBAR"
+strio.write('BAZ')
+strio.string # => "FOOBARBAZ"
+strio.pos = 12
+strio.write('BAT')
+strio.string # => "FOOBARBAZ\u0000\u0000\u0000BAT" # Null-padded.
+```
+
+May be read anywhere:
+
+```ruby
+strio.rewind
+strio.gets(3) # => "FOO"
+strio.gets(3) # => "BAR"
+strio.pos = 12
+strio.gets(3) # => "BAT"
+strio.pos = 400
+strio.gets(3) # => nil
+```
+
+#### `'a+'`: Read/Append
+
+Mode specified as one of:
+
+- String: `'a+'`.
+- Constant: `File::RDWR | File::APPEND`.
+
+Initial state:
+
+```ruby
+strio = StringIO.new('foo', 'a+')
+strio.pos # => 0 # Beginning-of-stream.
+strio.string # => "foo" # Not cleared.
+```
+
+May be written only at the end; #rewind; position does not affect writing:
+
+```ruby
+strio.write('bar')
+strio.string # => "foobar"
+strio.write('baz')
+strio.string # => "foobarbaz"
+strio.pos = 400
+strio.write('bat')
+strio.string # => "foobarbazbat"
+```
+
+May be read anywhere:
+
+```ruby
+strio.rewind
+strio.gets(3) # => "foo"
+strio.gets(3) # => "bar"
+strio.pos = 9
+strio.gets(3) # => "bat"
+strio.pos = 400
+strio.gets(3) # => nil
+```
+
+### Data Mode
+
+To specify whether the stream is to be treated as text or as binary data,
+either of the following may be suffixed to any of the string read/write modes above:
+
+- `'t'`: Text;
+ initializes the encoding as Encoding::UTF_8.
+- `'b'`: Binary;
+ initializes the encoding as Encoding::ASCII_8BIT.
+
+If neither is given, the stream defaults to text data.
+
+Examples:
+
+```ruby
+strio = StringIO.new('foo', 'rt')
+strio.external_encoding # => #<Encoding:UTF-8>
+data = "\u9990\u9991\u9992\u9993\u9994"
+strio = StringIO.new(data, 'rb')
+strio.external_encoding # => #<Encoding:BINARY (ASCII-8BIT)>
+```
+
+When the data mode is specified, the read/write mode may not be omitted:
+
+```ruby
+StringIO.new(data, 'b') # Raises ArgumentError: invalid access mode b
+```
+
+A text stream may be changed to binary by calling instance method #binmode;
+a binary stream may not be changed to text.
+
+### Encodings
+
+A stream has an encoding; see [Encodings][encodings document].
+
+The initial encoding for a new or re-opened stream depends on its [data mode][data mode]:
+
+- Text: `Encoding::UTF_8`.
+- Binary: `Encoding::ASCII_8BIT`.
+
+These instance methods are relevant:
+
+- #external_encoding: returns the current encoding of the stream as an `Encoding` object.
+- #internal_encoding: returns +nil+; a stream does not have an internal encoding.
+- #set_encoding: sets the encoding for the stream.
+- #set_encoding_by_bom: sets the encoding for the stream to the stream's BOM (byte order mark).
+
+Examples:
+
+```ruby
+strio = StringIO.new('foo', 'rt') # Text mode.
+strio.external_encoding # => #<Encoding:UTF-8>
+data = "\u9990\u9991\u9992\u9993\u9994"
+strio = StringIO.new(data, 'rb') # Binary mode.
+strio.external_encoding # => #<Encoding:BINARY (ASCII-8BIT)>
+strio = StringIO.new('foo')
+strio.external_encoding # => #<Encoding:UTF-8>
+strio.set_encoding('US-ASCII')
+strio.external_encoding # => #<Encoding:US-ASCII>
+```
+
+### Position
+
+A stream has a _position_, and integer offset (in bytes) into the stream.
+The initial position of a stream is zero.
+
+#### Getting and Setting the Position
+
+Each of these methods initializes (to zero) the position of a new or re-opened stream:
+
+- ::new: returns a new stream.
+- ::open: passes a new stream to the block.
+- #reopen: re-initializes the stream.
+
+Each of these methods queries, gets, or sets the position, without otherwise changing the stream:
+
+- #eof?: returns whether the position is at end-of-stream.
+- #pos: returns the position.
+- #pos=: sets the position.
+- #rewind: sets the position to zero.
+- #seek: sets the position.
+
+Examples:
+
+```ruby
+strio = StringIO.new('foobar')
+strio.pos # => 0
+strio.pos = 3
+strio.pos # => 3
+strio.eof? # => false
+strio.rewind
+strio.pos # => 0
+strio.seek(0, IO::SEEK_END)
+strio.pos # => 6
+strio.eof? # => true
+```
+
+#### Position Before and After Reading
+
+Except for #pread, a stream reading method (see [Basic Reading][basic reading])
+begins reading at the current position.
+
+Except for #pread, a read method advances the position past the read substring.
+
+Examples:
+
+```ruby
+strio = StringIO.new(TEXT)
+strio.string # => "First line\nSecond line\n\nFourth line\nFifth line\n"
+strio.pos # => 0
+strio.getc # => "F"
+strio.pos # => 1
+strio.gets # => "irst line\n"
+strio.pos # => 11
+strio.pos = 24
+strio.gets # => "Fourth line\n"
+strio.pos # => 36
+
+strio = StringIO.new('ã“ã‚“ã«ã¡ã¯') # Five 3-byte characters.
+strio.pos = 0 # At first byte of first character.
+strio.read # => "ã“ã‚“ã«ã¡ã¯"
+strio.pos = 1 # At second byte of first character.
+strio.read # => "\x81\x93ã‚“ã«ã¡ã¯"
+strio.pos = 2 # At third byte of first character.
+strio.read # => "\x93ã‚“ã«ã¡ã¯"
+strio.pos = 3 # At first byte of second character.
+strio.read # => "ã‚“ã«ã¡ã¯"
+
+strio = StringIO.new(TEXT)
+strio.pos = 15
+a = []
+strio.each_line {|line| a.push(line) }
+a # => ["nd line\n", "\n", "Fourth line\n", "Fifth line\n"]
+strio.pos # => 47 ## End-of-stream.
+```
+
+#### Position Before and After Writing
+
+Each of these methods begins writing at the current position,
+and advances the position to the end of the written substring:
+
+- #putc: writes the given character.
+- #write: writes the given objects as strings.
+- [Kernel#puts][kernel#puts]: writes given objects as strings, each followed by newline.
+
+Examples:
+
+```ruby
+strio = StringIO.new('foo')
+strio.pos # => 0
+strio.putc('b')
+strio.string # => "boo"
+strio.pos # => 1
+strio.write('r')
+strio.string # => "bro"
+strio.pos # => 2
+strio.puts('ew')
+strio.string # => "brew\n"
+strio.pos # => 5
+strio.pos = 8
+strio.write('foo')
+strio.string # => "brew\n\u0000\u0000\u0000foo"
+strio.pos # => 11
+```
+
+Each of these methods writes _before_ the current position, and decrements the position
+so that the written data is next to be read:
+
+- #ungetbyte: unshifts the given byte.
+- #ungetc: unshifts the given character.
+
+Examples:
+
+```ruby
+strio = StringIO.new('foo')
+strio.pos = 2
+strio.ungetc('x')
+strio.pos # => 1
+strio.string # => "fxo"
+strio.ungetc('x')
+strio.pos # => 0
+strio.string # => "xxo"
+```
+
+This method does not affect the position:
+
+- #truncate: truncates the stream's string to the given size.
+
+Examples:
+
+```ruby
+strio = StringIO.new('foobar')
+strio.pos # => 0
+strio.truncate(3)
+strio.string # => "foo"
+strio.pos # => 0
+strio.pos = 500
+strio.truncate(0)
+strio.string # => ""
+strio.pos # => 500
+```
+
+### Line Number
+
+A stream has a line number, which initially is zero:
+
+- Method #lineno returns the line number.
+- Method #lineno= sets the line number.
+
+The line number can be affected by reading (but never by writing);
+in general, the line number is incremented each time the record separator (default: `"\n"`) is read.
+
+Examples:
+
+```ruby
+strio = StringIO.new(TEXT)
+strio.string # => "First line\nSecond line\n\nFourth line\nFifth line\n"
+strio.lineno # => 0
+strio.gets # => "First line\n"
+strio.lineno # => 1
+strio.getc # => "S"
+strio.lineno # => 1
+strio.gets # => "econd line\n"
+strio.lineno # => 2
+strio.gets # => "\n"
+strio.lineno # => 3
+strio.gets # => "Fourth line\n"
+strio.lineno # => 4
+```
+
+Setting the position does not affect the line number:
+
+```ruby
+strio.pos = 0
+strio.lineno # => 4
+strio.gets # => "First line\n"
+strio.pos # => 11
+strio.lineno # => 5
+```
+
+And setting the line number does not affect the position:
+
+```ruby
+strio.lineno = 10
+strio.pos # => 11
+strio.gets # => "Second line\n"
+strio.lineno # => 11
+strio.pos # => 23
+```
+
+### Open/Closed Streams
+
+A new stream is open for either reading or writing, and may be open for both;
+see [Read/Write Mode][read/write mode].
+
+Each of these methods initializes the read/write mode for a new or re-opened stream:
+
+- ::new: returns a new stream.
+- ::open: passes a new stream to the block.
+- #reopen: re-initializes the stream.
+
+Other relevant methods:
+
+- #close: closes the stream for both reading and writing.
+- #close_read: closes the stream for reading.
+- #close_write: closes the stream for writing.
+- #closed?: returns whether the stream is closed for both reading and writing.
+- #closed_read?: returns whether the stream is closed for reading.
+- #closed_write?: returns whether the stream is closed for writing.
+
+### BOM (Byte Order Mark)
+
+The string provided for ::new, ::open, or #reopen
+may contain an optional [BOM][bom] (byte order mark) at the beginning of the string;
+the BOM can affect the stream's encoding.
+
+The BOM (if provided):
+
+- Is stored as part of the stream's string.
+- Does _not_ immediately affect the encoding.
+- Is _initially_ considered part of the stream.
+
+```ruby
+utf8_bom = "\xEF\xBB\xBF"
+string = utf8_bom + 'foo'
+string.bytes # => [239, 187, 191, 102, 111, 111]
+strio.string.bytes.take(3) # => [239, 187, 191] # The BOM.
+strio = StringIO.new(string, 'rb')
+strio.string.bytes # => [239, 187, 191, 102, 111, 111] # BOM is part of the stored string.
+strio.external_encoding # => #<Encoding:BINARY (ASCII-8BIT)> # Default for a binary stream.
+strio.gets # => "\xEF\xBB\xBFfoo" # BOM is part of the stream.
+```
+
+You can call instance method #set_encoding_by_bom to "activate" the stored BOM;
+after doing so the BOM:
+
+- Is _still_ stored as part of the stream's string.
+- _Determines_ (and may have changed) the stream's encoding.
+- Is _no longer_ considered part of the stream.
+
+```ruby
+strio.set_encoding_by_bom
+strio.string.bytes # => [239, 187, 191, 102, 111, 111] # BOM is still part of the stored string.
+strio.external_encoding # => #<Encoding:UTF-8> # The new encoding.
+strio.rewind # => 0
+strio.gets # => "foo" # BOM is not part of the stream.
+```
+
+## Basic Stream \IO
+
+### Basic Reading
+
+You can read from the stream using these instance methods:
+
+- #getbyte: reads and returns the next byte.
+- #getc: reads and returns the next character.
+- #gets: reads and returns all or part of the next line.
+- #read: reads and returns all or part of the remaining data in the stream.
+- #readlines: reads the remaining data the stream and returns an array of its lines.
+- [Kernel#readline][kernel#readline]: like #gets, but raises an exception if at end-of-stream.
+
+You can iterate over the stream using these instance methods:
+
+- #each_byte: reads each remaining byte, passing it to the block.
+- #each_char: reads each remaining character, passing it to the block.
+- #each_codepoint: reads each remaining codepoint, passing it to the block.
+- #each_line: reads all or part of each remaining line, passing the read string to the block
+
+This instance method is useful in a multi-threaded application:
+
+- #pread: reads and returns all or part of the stream.
+
+### Basic Writing
+
+You can write to the stream, advancing the position, using these instance methods:
+
+- #putc: writes a given character.
+- #write: writes the given objects as strings.
+- [Kernel#puts][kernel#puts] writes given objects as strings, each followed by newline.
+
+You can "unshift" to the stream using these instance methods;
+each writes _before_ the current position, and decrements the position
+so that the written data is next to be read.
+
+- #ungetbyte: unshifts the given byte.
+- #ungetc: unshifts the given character.
+
+One more writing method:
+
+- #truncate: truncates the stream's string to the given size.
+
+## Line \IO
+
+Reading:
+
+- #gets: reads and returns the next line.
+- [Kernel#readline][kernel#readline]: like #gets, but raises an exception if at end-of-stream.
+- #readlines: reads the remaining data the stream and returns an array of its lines.
+- #each_line: reads each remaining line, passing it to the block
+
+Writing:
+
+- [Kernel#puts][kernel#puts]: writes given objects, each followed by newline.
+
+## Character \IO
+
+Reading:
+
+- #each_char: reads each remaining character, passing it to the block.
+- #getc: reads and returns the next character.
+
+Writing:
+
+- #putc: writes the given character.
+- #ungetc.: unshifts the given character.
+
+## Byte \IO
+
+Reading:
+
+- #each_byte: reads each remaining byte, passing it to the block.
+- #getbyte: reads and returns the next byte.
+
+Writing:
+
+- #ungetbyte: unshifts the given byte.
+
+## Codepoint \IO
+
+Reading:
+
+- #each_codepoint: reads each remaining codepoint, passing it to the block.
+
+[bom]: https://en.wikipedia.org/wiki/Byte_order_mark
+[encodings document]: https://docs.ruby-lang.org/en/master/language/encodings_rdoc.html
+[io class]: https://docs.ruby-lang.org/en/master/IO.html
+[kernel#puts]: https://docs.ruby-lang.org/en/master/Kernel.html#method-i-puts
+[kernel#readline]: https://docs.ruby-lang.org/en/master/Kernel.html#method-i-readline
+
+[basic reading]: rdoc-ref:StringIO@Basic+Reading
+[basic writing]: rdoc-ref:StringIO@Basic+Writing
+[bom (byte order mark)]: rdoc-ref:StringIO@BOM+Byte+Order+Mark
+[data mode]: rdoc-ref:StringIO@Data+Mode
+[encodings]: rdoc-ref:StringIO@Encodings
+[end-of-stream]: rdoc-ref:StringIO@End-of-Stream
+[line number]: rdoc-ref:StringIO@Line+Number
+[open/closed streams]: rdoc-ref:StringIO@OpenClosed+Streams
+[position]: rdoc-ref:StringIO@Position
+[read/write mode]: rdoc-ref:StringIO@ReadWrite+Mode
diff --git a/doc/strscan/.document b/doc/strscan/.document
new file mode 100644
index 0000000000..b8085a8474
--- /dev/null
+++ b/doc/strscan/.document
@@ -0,0 +1 @@
+helper_methods.md
diff --git a/doc/strscan/link_refs.txt b/doc/strscan/link_refs.txt
index 19f6f7ce5c..04c4419982 100644
--- a/doc/strscan/link_refs.txt
+++ b/doc/strscan/link_refs.txt
@@ -1,5 +1,5 @@
[1]: rdoc-ref:StringScanner@Stored+String
-[2]: rdoc-ref:StringScanner@Byte+Position+-28Position-29
+[2]: rdoc-ref:StringScanner@Byte+Position+Position
[3]: rdoc-ref:StringScanner@Target+Substring
[4]: rdoc-ref:StringScanner@Setting+the+Target+Substring
[5]: rdoc-ref:StringScanner@Traversing+the+Target+Substring
diff --git a/doc/strscan/methods/get_byte.md b/doc/strscan/methods/get_byte.md
index 3208d77158..775226638e 100644
--- a/doc/strscan/methods/get_byte.md
+++ b/doc/strscan/methods/get_byte.md
@@ -1,6 +1,3 @@
-call-seq:
- get_byte -> byte_as_character or nil
-
Returns the next byte, if available:
- If the [position][2]
diff --git a/doc/strscan/methods/get_charpos.md b/doc/strscan/methods/get_charpos.md
index 954fcf5b44..4de07897dc 100644
--- a/doc/strscan/methods/get_charpos.md
+++ b/doc/strscan/methods/get_charpos.md
@@ -1,6 +1,3 @@
-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:
diff --git a/doc/strscan/methods/get_pos.md b/doc/strscan/methods/get_pos.md
index 81bbb2345e..56b1636812 100644
--- a/doc/strscan/methods/get_pos.md
+++ b/doc/strscan/methods/get_pos.md
@@ -1,6 +1,3 @@
-call-seq:
- pos -> byte_position
-
Returns the integer [byte position][2],
which may be different from the [character position][7]:
diff --git a/doc/strscan/methods/getch.md b/doc/strscan/methods/getch.md
index 3dd70e4c5b..ede1d2b071 100644
--- a/doc/strscan/methods/getch.md
+++ b/doc/strscan/methods/getch.md
@@ -1,6 +1,3 @@
-call-seq:
- getch -> character or nil
-
Returns the next (possibly multibyte) character,
if available:
diff --git a/doc/strscan/methods/scan.md b/doc/strscan/methods/scan.md
index 22ddd368b6..805c797913 100644
--- a/doc/strscan/methods/scan.md
+++ b/doc/strscan/methods/scan.md
@@ -1,6 +1,3 @@
-call-seq:
- scan(pattern) -> substring or nil
-
Attempts to [match][17] the given `pattern`
at the beginning of the [target substring][3].
diff --git a/doc/strscan/methods/scan_until.md b/doc/strscan/methods/scan_until.md
index 9a8c7c02f6..5fb2912a1b 100644
--- a/doc/strscan/methods/scan_until.md
+++ b/doc/strscan/methods/scan_until.md
@@ -1,6 +1,3 @@
-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].
diff --git a/doc/strscan/methods/set_pos.md b/doc/strscan/methods/set_pos.md
index 3b7abe65e3..6a43edeb41 100644
--- a/doc/strscan/methods/set_pos.md
+++ b/doc/strscan/methods/set_pos.md
@@ -1,7 +1,3 @@
-call-seq:
- pos = n -> n
- pointer = n -> n
-
Sets the [byte position][2] and the [character position][11];
returns `n`.
diff --git a/doc/strscan/methods/skip.md b/doc/strscan/methods/skip.md
index 10a329e0e4..7e924b624b 100644
--- a/doc/strscan/methods/skip.md
+++ b/doc/strscan/methods/skip.md
@@ -1,6 +1,3 @@
-call-seq:
- skip(pattern) match_size or nil
-
Attempts to [match][17] the given `pattern`
at the beginning of the [target substring][3];
diff --git a/doc/strscan/methods/skip_until.md b/doc/strscan/methods/skip_until.md
index b7dacf6da1..a0ffab0b84 100644
--- a/doc/strscan/methods/skip_until.md
+++ b/doc/strscan/methods/skip_until.md
@@ -1,13 +1,11 @@
-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.
+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 size of the matched substring.
```rb
@@ -42,6 +40,7 @@ If the match attempt fails:
- Clears match values.
- Returns `nil`.
+- Does not update positions.
```rb
scanner.skip_until(/nope/) # => nil
diff --git a/doc/strscan/methods/terminate.md b/doc/strscan/methods/terminate.md
index b03b37d2a2..27f7d41cb1 100644
--- a/doc/strscan/methods/terminate.md
+++ b/doc/strscan/methods/terminate.md
@@ -1,6 +1,3 @@
-call-seq:
- terminate -> self
-
Sets the scanner to end-of-string;
returns +self+:
diff --git a/doc/strscan/strscan.md b/doc/strscan/strscan.md
index 1211a687c2..bbdeccd75e 100644
--- a/doc/strscan/strscan.md
+++ b/doc/strscan/strscan.md
@@ -37,7 +37,7 @@ Some examples here assume that certain helper methods are defined:
- `match_values_cleared?(scanner)`:
Returns whether the scanner's [match values][9] are cleared.
-See examples [here][ext/strscan/helper_methods_md.html].
+See examples at [helper methods](doc/strscan/helper_methods.md).
## The `StringScanner` \Object
@@ -204,7 +204,7 @@ put_situation(scanner)
## Target Substring
-The target substring is the the part of the [stored string][1]
+The target substring is 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:
@@ -417,7 +417,7 @@ 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+. |
+| #\[\](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>. |
diff --git a/doc/syntax.rdoc b/doc/syntax.rdoc
index cb427b6f0f..a48c83ff15 100644
--- a/doc/syntax.rdoc
+++ b/doc/syntax.rdoc
@@ -2,6 +2,9 @@
The Ruby syntax is large and is split up into the following sections:
+{Code Layout}[rdoc-ref:syntax/layout.rdoc] ::
+ Breaking code in lines
+
Literals[rdoc-ref:syntax/literals.rdoc] ::
Numbers, Strings, Arrays, Hashes, etc.
diff --git a/doc/syntax/assignment.rdoc b/doc/syntax/assignment.rdoc
index 68d4ae97be..3988f82e5f 100644
--- a/doc/syntax/assignment.rdoc
+++ b/doc/syntax/assignment.rdoc
@@ -9,7 +9,7 @@ Assignment creates a local variable if the variable was not previously
referenced.
An assignment expression result is always the assigned value, including
-{assignment methods}[rdoc-ref:syntax/assignment.rdoc@Assignment+Methods].
+{assignment methods}[rdoc-ref:@Assignment+Methods].
== Local Variable Names
@@ -279,7 +279,7 @@ An uninitialized global variable has a value of +nil+.
Ruby has some special globals that behave differently depending on context
such as the regular expression match variables or that have a side-effect when
-assigned to. See the {global variables documentation}[rdoc-ref:globals.md]
+assigned to. See the {global variables documentation}[rdoc-ref:language/globals.md]
for details.
== Assignment Methods
diff --git a/doc/syntax/calling_methods.rdoc b/doc/syntax/calling_methods.rdoc
index bf5916e99a..a24c5fbf1f 100644
--- a/doc/syntax/calling_methods.rdoc
+++ b/doc/syntax/calling_methods.rdoc
@@ -355,9 +355,8 @@ as one argument:
# Prints the object itself:
# #<Name:0x00007f9d07bca650 @name="Jane Doe">
-This allows to handle one or many arguments polymorphically. Note also that +nil+
-has NilClass#to_a defined to return an empty array, so conditional unpacking is
-possible:
+This allows to handle one or many arguments polymorphically. Note also that <tt>*nil</tt>
+is unpacked to an empty list of arguments, so conditional unpacking is possible:
my_method(*(some_arguments if some_condition?))
@@ -426,7 +425,7 @@ as keyword arguments:
name = Name.new('Jane Doe')
p(**name)
- # Prints: {name: "Jane", last: "Doe"}
+ # Prints: {first: "Jane", last: "Doe"}
Unlike <code>*</code> operator, <code>**</code> raises an error when used on an
object that doesn't respond to <code>#to_hash</code>. The one exception is
diff --git a/doc/syntax/comments.rdoc b/doc/syntax/comments.rdoc
index 00d19d588a..cb6829a984 100644
--- a/doc/syntax/comments.rdoc
+++ b/doc/syntax/comments.rdoc
@@ -170,7 +170,7 @@ In this mode, all values assigned to constants are made shareable.
# shareable_constant_value: experimental_everything
FOO = Set[1, 2, {foo: []}]
- # same as FOO = Ractor.make_sharable(...)
+ # same as FOO = Ractor.make_shareable(...)
# OR same as `FOO = Set[1, 2, {foo: [].freeze}.freeze].freeze`
var = [{foo: []}]
diff --git a/doc/syntax/layout.rdoc b/doc/syntax/layout.rdoc
new file mode 100644
index 0000000000..31e51d9ff1
--- /dev/null
+++ b/doc/syntax/layout.rdoc
@@ -0,0 +1,118 @@
+= Code Layout
+
+Expressions in Ruby are separated by line breaks:
+
+ x = 1
+ y = 2
+ z = x + y
+
+Line breaks are also used as logical separators of the headers of some control structures from their bodies:
+
+ if z > 3 # line break ends the condition and starts the body
+ puts "more"
+ end
+
+ while x < 3 # line break ends the condition and starts the body
+ x += 1
+ end
+
+<tt>;</tt> can be used as an expressions separator instead of a line break:
+
+ x = 1; y = 2; z = x + y
+ if z > 3; puts "more"; end
+
+Traditionally, expressions separated by <tt>;</tt> are used only in short scripts and experiments.
+
+In some control structures, there is an optional keyword that can be used instead of a line break to separate their elements:
+
+ # if, elsif, until and case ... when: 'then' is an optional separator:
+
+ if z > 3 then puts "more" end
+
+ case x
+ when Numeric then "number"
+ when String then "string"
+ else "object"
+ end
+
+ # while and until: 'do' is an optional separator
+ while x < 3 do x +=1 end
+
+Also, line breaks can be skipped in some places where it doesn't create any ambiguity. Note in the example above: no line break needed before +end+, just as no line break needed after +else+.
+
+== Breaking expressions in lines
+
+One expression might be split into several lines when each line can be unambiguously identified as "incomplete" without the next one.
+
+These works:
+
+ x = # incomplete without something after =
+ 1 + # incomplete without something after +
+ 2
+
+ File.read "test.txt", # incomplete without something after ,
+ enconding: "utf-8"
+
+These would not:
+
+ # unintended interpretation:
+ x = 1 # already complete expression
+ + 2 # interpreted as a separate +2
+
+ # syntax error:
+ File.read "test.txt" # already complete expression
+ , encoding: "utf-8" # attempt to parse as a new expression, SyntaxError
+
+The exceptions to the rule are lines starting with <tt>.</tt> ("leading dot" style of method calls) or logical operators <tt>&&</tt>/<tt>||</tt> and <tt>and</tt>/<tt>or</tt>:
+
+ # OK, interpreted as a chain of calls
+ File.read('test.txt')
+ .strip("\n")
+ .split("\t")
+ .sort
+
+ # OK, interpreted as a chain of logical operators:
+ File.empty?('test.txt')
+ || File.size('test.txt') < 10
+ || File.read('test.txt').strip.empty?
+
+If the expressions is broken into multiple lines in any of the ways described above, comments between separate lines are allowed:
+
+ sum = base_salary +
+ # see "yearly bonuses section"
+ yearly_bonus(year) +
+ # per-employee coefficient is described
+ # in another module
+ personal_coeff(employee)
+
+ # We want to short-circuit on empty files
+ File.empty?('test.txt')
+ # Or almost empty ones
+ || File.size('test.txt') < 10
+ # Otherwise we check if it is full of spaces
+ || File.read('test.txt').strip.empty?
+
+Finally, the code can explicitly tell Ruby that the expression is continued on the next line with <tt>\\</tt>:
+
+ # Unusual, but works
+ File.read "test.txt" \
+ , encoding: "utf-8"
+
+ # More regular usage (joins the strings on parsing instead
+ # of concatenating them in runtime, as + would do):
+ TEXT = "One pretty long line" \
+ "one more long line" \
+ "one other line of the text"
+
+The <tt>\\</tt> works as a parse time line break escape, so with it, comments can not be inserted between the lines:
+
+ TEXT = "line 1" \
+ # here would be line 2:
+ "line 2"
+
+ # This is interpreted as if there was no line break where \ is,
+ # i.e. the same as
+ TEXT = "line 1" # here would be line 2:
+ "line 2"
+
+ puts TEXT #=> "line 1"
diff --git a/doc/syntax/literals.rdoc b/doc/syntax/literals.rdoc
index 46bb7673f3..c876558d4e 100644
--- a/doc/syntax/literals.rdoc
+++ b/doc/syntax/literals.rdoc
@@ -3,7 +3,7 @@
Literals create objects you can use in your program. Literals include:
* {Boolean and Nil Literals}[#label-Boolean+and+Nil+Literals]
-* {Number Literals}[#label-Number+Literals]
+* {Numeric Literals}[#label-Numeric+Literals]
* {Integer Literals}[#label-Integer+Literals]
* {Float Literals}[#label-Float+Literals]
@@ -36,7 +36,7 @@ Literals create objects you can use in your program. Literals include:
+true+ is a true value. All objects except +nil+ and +false+ evaluate to a
true value in conditional expressions.
-== Number Literals
+== \Numeric Literals
=== \Integer Literals
@@ -547,6 +547,13 @@ with <tt>%w</tt> (non-interpolable) or <tt>%W</tt> (interpolable):
# (not nested array).
%w[foo[bar baz]qux] # => ["foo[bar", "baz]qux"]
+The interpolated string is treated as a single word even if it contains
+whitespace.
+
+ s = "bar baz"
+ %W[foo #{s} zot] #=> ["foo", "bar baz", "zot"]
+ %W[foo #{"bar baz zot"} qux] # => ["foo", "bar baz zot", "qux"]
+
The following characters are considered as white spaces to separate words:
* space, ASCII 20h (SPC)
diff --git a/doc/syntax/methods.rdoc b/doc/syntax/methods.rdoc
index 8dafa6bb0c..14810a188f 100644
--- a/doc/syntax/methods.rdoc
+++ b/doc/syntax/methods.rdoc
@@ -100,6 +100,7 @@ operators.
<code>/</code> :: divide
<code>%</code> :: modulus division, String#%
<code>&</code> :: AND
+<code>|</code> :: OR
<code>^</code> :: XOR (exclusive OR)
<code>>></code> :: right-shift
<code><<</code> :: left-shift, append
diff --git a/doc/syntax/pattern_matching.rdoc b/doc/syntax/pattern_matching.rdoc
index c43919ba14..06aae26d49 100644
--- a/doc/syntax/pattern_matching.rdoc
+++ b/doc/syntax/pattern_matching.rdoc
@@ -253,11 +253,11 @@ The "rest" part of a pattern also can be bound to a variable:
case {a: 1, b: 2}
in {a: } | Array
+ # ^ SyntaxError (variable capture in alternative pattern)
"matched: #{a}"
else
"not matched"
end
- # SyntaxError (illegal variable in alternative pattern (a))
Variables that start with <code>_</code> are the only exclusions from this rule:
diff --git a/doc/syntax/refinements.rdoc b/doc/syntax/refinements.rdoc
index 17d5e67c21..80595eb445 100644
--- a/doc/syntax/refinements.rdoc
+++ b/doc/syntax/refinements.rdoc
@@ -210,43 +210,58 @@ all refinements from the same module are active when a refined method
== Method Lookup
-When looking up a method for an instance of class +C+ Ruby checks:
+Method lookup in Ruby is based on the ancestor chain. You can see the
+ancestor chain for any object in Ruby by doing:
-* If refinements are active for +C+, in the reverse order they were activated:
- * The prepended modules from the refinement for +C+
- * The refinement for +C+
- * The included modules from the refinement for +C+
-* The prepended modules of +C+
-* +C+
-* The included modules of +C+
+ object.singleton_class.ancestors
+ # or, if the object does not support a singleton class:
+ object.class.ancestors
-If no method was found at any point this repeats with the superclass of +C+.
+The ancestor chain is constructed as follows:
-Note that methods in a subclass have priority over refinements in a
-superclass. For example, if the method <code>/</code> is defined in a
-refinement for Numeric <code>1 / 2</code> invokes the original Integer#/
-because Integer is a subclass of Numeric and is searched before the refinements
-for the superclass Numeric. Since the method <code>/</code> is also present
-in child +Integer+, the method lookup does not move up to the superclass.
+* Subclasses are before superclasses in the ancestor chain
+* Prepended modules are before the class they prepend in the ancestor
+ chain, in reverse order in which they were prepended.
+* Included modules are after the class they are included in in the
+ ancestor chain, in reverse order in which they were included.
+
+When looking up a method for an object, Ruby goes through each ancestor:
+
+* If the class/module has been refined, Ruby will consider the refinements
+ activated at the point the method was called, in reverse order of
+ activation.
+* Otherwise, Ruby will check the methods of the class/module itself.
+
+If no method was found at either point this repeats with the next
+ancestor.
-However, if a method +foo+ is defined on Numeric in a refinement, <code>1.foo</code>
+Note that methods in a earlier ancestor have priority over refinements in a
+later ancestor. For example, if the method <code>/</code> is defined in a
+refinement for Numeric <code>1 / 2</code> invokes the original Integer#/
+because Integer is a comes before Numeric in the ancestor chain. However,
+if a method +foo+ is defined on Numeric in a refinement, <code>1.foo</code>
invokes that method since +foo+ does not exist on Integer.
== +super+
-When +super+ is invoked method lookup checks:
+When +super+ is invoked, method lookup starts:
+
+* If the method is in a refinement, at the refined class or module
+* Otherwise, at the next ancestor
+
+Method lookup then proceeds as described in the Method Lookup section
+above.
-* The included modules of the current class. Note that the current class may
- be a refinement.
-* If the current class is a refinement, the method lookup proceeds as in the
- Method Lookup section above.
-* If the current class has a direct superclass, the method proceeds as in the
- Method Lookup section above using the superclass.
+Refinements activated at the call site of a refinement method do not
+affect +super+ inside that method. Only refinements activated at the
+point +super+ was called affect method lookup for that +super+ call.
+You cannot use refinements to insert into the middle of a method
+lookup chain, only to insert at the start of a method lookup chain,
+unless you control the +super+ call sites.
-Note that +super+ in a method of a refinement invokes the method in the
-refined class even if there is another refinement which has been activated in
-the same context. This is only true for +super+ in a method of a refinement, it
-does not apply to +super+ in a method in a module that is included in a refinement.
+Note that if you refine a module, the refinement method can call +super+
+to call the method in the module, but the method in the module cannot
+call +super+ to continue the method lookup process to further ancestors.
== Methods Introspection
diff --git a/doc/windows.md b/doc/windows.md
deleted file mode 100644
index 4ea03d0507..0000000000
--- a/doc/windows.md
+++ /dev/null
@@ -1,303 +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:
-
-```batch
-ridk install
-ridk enable ucrt64
-
-pacman -S --needed %MINGW_PACKAGE_PREFIX%-openssl %MINGW_PACKAGE_PREFIX%-libyaml %MINGW_PACKAGE_PREFIX%-libffi
-
-mkdir c:\work\ruby
-cd /d c:\work\ruby
-
-git clone https://github.com/ruby/ruby src
-
-sh ./src/autogen.sh
-
-mkdir build
-cd build
-sh ../src/configure -C --disable-install-doc
-make
-```
-
-or in MSYS2 `bash` like:
-
-```bash
-ridk install
-ridk enable ucrt64
-bash
-
-pacman -S --needed $MINGW_PACKAGE_PREFIX-openssl $MINGW_PACKAGE_PREFIX-libyaml $MINGW_PACKAGE_PREFIX-libffi
-
-mkdir /c/work/ruby
-cd /c/work/ruby
-
-git clone https://github.com/ruby/ruby src
-
-./src/autogen.sh
-cd build
-../src/configure -C --disable-install-doc
-make
-```
-
-If you have other MSYS2 environment via other package manager like `scoop`, you need to specify `$MINGW_PACKAGE_PREFIX` is `mingw-w64-ucrt-x86_64`.
-And you need to add `--with-opt-dir` option to `configure` command like:
-
-```batch
-sh ../../ruby/configure -C --disable-install-doc --with-opt-dir=C:\Users\username\scoop\apps\msys2\current\ucrt64
-```
-
-[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.
-
- The minimum requirement is here:
- * VC++/MSVC on VS 2017/2019/2022 version build tools.
- * Windows 10/11 SDK
-
- You can install Visual Studio Build Tools with `winget`.
- `win32\install-buildtools.cmd` is a batch file to install the
- minimum requirements excluding the IDE etc.
-
-3. Please set environment variable `INCLUDE`, `LIB`, `PATH` to run
- required commands properly from the command line. These are set
- properly by `vsdevcmd.bat` or `vcvarall*.bat` usually. You can run
- the following command to set them in your command line.
-
- To native build:
-
- ```
- cmd /k win32\vssetup.cmd
- ```
-
- To cross build arm64 binary:
-
- ```
- cmd /k win32\vssetup.cmd -arch=arm64
- ```
-
- To cross build x64 binary:
-
- ```
- cmd /k win32\vssetup.cmd -arch=x64
- ```
-
- This batch file is a wrapper of `vsdevcmd.bat` and options are
- passed to it as-is. `win32\vssetup.cmd -help` for other command
- line options.
-
- **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`
- * `ruby` 3.0 or later
-
- You can use [scoop](https://scoop.sh/) to install them like:
-
- ```batch
- scoop install git ruby
- ```
-
- The windows version of `git` configured with `autocrlf` is `true`. The Ruby
- test suite may fail with `autocrlf` set to `true`. You can set it to `false`
- like:
-
- ```batch
- git config --global core.autocrlf false
- ```
-
-5. You need to install required libraries using [vcpkg](https://vcpkg.io/) on
- directory of ruby repository like:
-
- ```batch
- 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` .
-
-2. If you want to append to the executable and DLL file names,
- specify `--program-prefix` and `--program-suffix`, like
- `win32\configure.bat --program-suffix=-$(MAJOR)$(MINOR)`.
-
- Also, the `--install-name` and `--so-name` options specify the
- exact base names of the executable and DLL files, respectively,
- like `win32\configure.bat --install-name=$(RUBY_BASE_NAME)-$(MAJOR)$(MINOR)`.
-
- By default, the name for the executable without a console window
- is generated from the _RUBY_INSTALL_NAME_ specified as above by
- replacing `ruby` with `rubyw`. If you want to make it different
- more, modify _RUBYW_INSTALL_NAME_ directly in the Makefile.
-
-3. You need specify vcpkg directory to use `--with-opt-dir`
- option like `win32\configure.bat --with-opt-dir=C:/vcpkg_installed/x64-windows`
-
-4. Run `nmake up` if you are building from GIT source.
-
-5. Run `nmake`
-
-6. Run `nmake prepare-vcpkg` with administrator privilege 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
- ```
-
- ```batch
- 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
- ```
-
- ```batch
- 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
- ```
-
- ```batch
- 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
- ```
-
- ```batch
- 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:
-
-```batch
-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/yarv_frame_layout.md b/doc/yarv_frame_layout.md
deleted file mode 100644
index ea8ad013cf..0000000000
--- a/doc/yarv_frame_layout.md
+++ /dev/null
@@ -1,77 +0,0 @@
-# YARV Frame Layout
-
-This document is an introduction to what happens on the VM stack as the VM
-services calls. The code holds the ultimate truth for this subject, so beware
-that this document can become stale.
-
-We'll walk through the following program, with explanation at selected points
-in execution and abridged disassembly listings:
-
-```ruby
-def foo(x, y)
- z = x.casecmp(y)
-end
-
-foo(:one, :two)
-```
-
-First, after arguments are evaluated and right before the `send` to `foo`:
-
-```
- ┌────────────â”
- putself │ :two │
- putobject :one 0x2 ├────────────┤
- putobject :two │ :one │
-► send <:foo, argc:2> 0x1 ├────────────┤
- leave │ self │
- 0x0 └────────────┘
-```
-
-The `put*` instructions have pushed 3 items onto the stack. It's now time to
-add a new control frame for `foo`. The following is the shape of the stack
-after one instruction in `foo`:
-
-```
- cfp->sp=0x8 at this point.
- 0x8 ┌────────────â”◄──Stack space for temporaries
- │ :one │ live above the environment.
- 0x7 ├────────────┤
- getlocal x@0 │ < flags > │ foo's rb_control_frame_t
-► getlocal y@1 0x6 ├────────────┤◄──has cfp->ep=0x6
- send <:casecmp, argc:1> │ <no block> │
- dup 0x5 ├────────────┤ The flags, block, and CME triple
- setlocal z@2 │ <CME: foo> │ (VM_ENV_DATA_SIZE) form an
- leave 0x4 ├────────────┤ environment. They can be used to
- │ z (nil) │ figure out what local variables
- 0x3 ├────────────┤ are below them.
- │ :two │
- 0x2 ├────────────┤ Notice how the arguments, now
- │ :one │ locals, never moved. This layout
- 0x1 ├────────────┤ allows for argument transfer
- │ self │ without copying.
- 0x0 └────────────┘
-```
-
-Given that locals have lower address than `cfp->ep`, it makes sense then that
-`getlocal` in `insns.def` has `val = *(vm_get_ep(GET_EP(), level) - idx);`.
-When accessing variables in the immediate scope, where `level=0`, it's
-essentially `val = cfp->ep[-idx];`.
-
-Note that this EP-relative index has a different basis the index that comes
-after "@" in disassembly listings. The "@" index is relative to the 0th local
-(`x` in this case).
-
-## Q&A
-
-Q: It seems that the receiver is always at an offset relative to EP,
- like locals. Couldn't we use EP to access it instead of using `cfp->self`?
-
-A: Not all calls put the `self` in the callee on the stack. Two
- examples are `Proc#call`, where the receiver is the Proc object, but `self`
- inside the callee is `Proc#receiver`, and `yield`, where the receiver isn't
- pushed onto the stack before the arguments.
-
-Q: Why have `cfp->ep` when it seems that everything is below `cfp->sp`?
-
-A: In the example, `cfp->ep` points to the stack, but it can also point to the
- GC heap. Blocks can capture and evacuate their environment to the heap.
diff --git a/doc/yarvarch.en b/doc/yarvarch.en
deleted file mode 100644
index 7a76e25b7e..0000000000
--- a/doc/yarvarch.en
+++ /dev/null
@@ -1,7 +0,0 @@
-#title YARV: Yet another RubyVM - Software Architecture
-
-maybe writing.
-
-* YARV instruction set
-
-<%= d %>
diff --git a/doc/yarvarch.ja b/doc/yarvarch.ja
deleted file mode 100644
index 2739ec6b14..0000000000
--- a/doc/yarvarch.ja
+++ /dev/null
@@ -1,454 +0,0 @@
-#title YARVアーキテクãƒãƒ£
-#set author 日本 Ruby ã®ä¼š ã•ã•ã ã“ã†ã„ã¡
-
-
-- 2005-03-03(Thu) 00:31:12 +0900 ã„ã‚ã„ã‚ã¨æ›¸ãç›´ã—
-
-----
-
-* ã“れã¯ï¼Ÿ
-
-[[YARV: Yet Another RubyVM|http://www.atdot.net/yarv]] 㮠設計メモã§ã™ã€‚
-
-
-YARV ã¯ã€Ruby プログラムã®ãŸã‚ã®æ¬¡ã®æ©Ÿèƒ½ã‚’æä¾›ã—ã¾ã™ã€‚
-
-- Compiler
-- VM Generator
-- VM (Virtual Machine)
-- Assembler
-- Dis-Assembler
-- (experimental) JIT Compiler
-- (experimental) AOT Compiler
-
-
-ç¾åœ¨ã® YARV 㯠Ruby ã‚¤ãƒ³ã‚¿ãƒ—ãƒªã‚¿ã®æ‹¡å¼µãƒ©ã‚¤ãƒ–ラリã¨ã—ã¦å®Ÿè£…ã—ã¦ã„ã¾ã™ã€‚ã“
-れã«ã‚ˆã‚Šã€Ruby インタプリタã®å¿…è¦ãªæ©Ÿèƒ½ï¼ˆãƒ‘ーサã€ã‚ªãƒ–ジェクト管ç†ã€æ—¢å­˜
-ã®æ‹¡å¼µãƒ©ã‚¤ãƒ–ラリ)ãªã©ãŒã»ã¼ãã®ã¾ã¾åˆ©ç”¨ã§ãã¾ã™ã€‚
-
-ãŸã ã—ã€ã„ãã¤ã‹ã®ãƒ‘ッãƒã‚’ Ruby インタプリタã«å½“ã¦ãªã‘れã°ãªã‚Šã¾ã›ã‚“。
-
-今後ã¯ã€Ruby 本体ã®ã‚¤ãƒ³ã‚¿ãƒ—リタ部分(eval.cï¼‰ã‚’ç½®ãæ›ãˆã‚‹ã“ã¨ã‚’目指ã—ã¦
-開発を継続ã™ã‚‹äºˆå®šã§ã™ã€‚
-
-
-* Compiler (compile.h, compile.c)
-
-コンパイラã¯ã€Ruby インタプリタã®ãƒ‘ーサã«ã‚ˆã£ã¦ç”Ÿæˆã•ã‚ŒãŸæ§‹æ–‡æœ¨ï¼ˆRNode
-データã«ã‚ˆã‚‹æœ¨ï¼‰ã‚’ YARV 命令列ã«å¤‰æ›ã—ã¾ã™ã€‚YARV 命令ã«ã¤ã„ã¦ã¯å¾Œè¿°ã—ã¾
-ã™ã€‚
-
-ã¨ãã«é›£ã—ã„ã“ã¨ã¯ã—ã¦ã„ã¾ã›ã‚“ãŒã€ã‚¹ã‚³ãƒ¼ãƒ—ãªã©ã®é–‹å§‹æ™‚ã«ãƒ­ãƒ¼ã‚«ãƒ«å¤‰æ•°ã®åˆ
-期化ãªã©ã‚’行ã„ã€ã‚ã¨ã¯æ§‹æ–‡æœ¨ã‚’辿り変æ›ã—ã¦ã„ãã¾ã™ã€‚
-
-変æ›ä¸­ã¯ Ruby ã® Array オブジェクト㫠YARV 命令オブジェクトã€ãŠã‚ˆã³ã‚ªãƒš
-ランドを格ç´ã—ã¦ã„ãã€æœ€å¾Œã«å®Ÿè¡Œã§ãã‚‹å½¢ã«å¤‰æ›ã—ã¾ã™ã€‚コンパイラã§ã¯ã€ã‚³
-ンパイル中ã«ç”Ÿæˆã™ã‚‹ãƒ¡ãƒ¢ãƒªé ˜åŸŸã®ç®¡ç†ãŒå•題ã«ãªã‚‹ã“ã¨ãŒã‚りã¾ã™ãŒã€YARV
-ã®å ´åˆã€Ruby インタプリタãŒã™ã¹ã¦é¢å€’ã‚’ã¿ã¦ãれるã®ã§ã“ã®éƒ¨åˆ†ã¯éžå¸¸ã«æ¥½
-ã«ä½œã‚‹ã“ã¨ãŒã§ãã¾ã—ãŸï¼ˆã‚¬ãƒ¼ãƒ™ãƒ¼ã‚¸ã‚³ãƒ¬ã‚¯ã‚¿ã«ã‚ˆã£ã¦è‡ªå‹•çš„ã«ãƒ¡ãƒ¢ãƒªç®¡ç†ã‚’ã—
-ã¦ãれるãŸã‚)。
-
-YARV 命令ã¯ã€å‘½ä»¤ã‚’示ã™è­˜åˆ¥å­ã€ã‚ªãƒšãƒ©ãƒ³ãƒ‰ãªã©ã€ã™ã¹ã¦ 1 word (マシンã§
-表ç¾ã§ãる自然ãªå€¤ã€‚C 言語ã§ã¯ãƒã‚¤ãƒ³ã‚¿ã®ã‚µã‚¤ã‚ºã€‚Ruby インタプリタ用語ã§
-㯠VALUE ã®ã‚µã‚¤ã‚ºï¼‰ã§è¡¨ç¾ã•れã¾ã™ã€‚ãã®ãŸã‚ã€YARV 命令ã¯ã„ã‚ゆる「ãƒã‚¤ãƒˆ
-コードã€ã§ã¯ã‚りã¾ã›ã‚“。ãã®ãŸã‚ã€YARV ã®èª¬æ˜Žãªã©ã§ã¯ã€Œå‘½ä»¤åˆ—ã€ã¨ã„ã†ç”¨
-語を使ã£ã¦ã„ã¾ã™ã€‚
-
-1 word ã§ã‚ã‚‹ãŸã‚ã€ãƒ¡ãƒ¢ãƒªã®åˆ©ç”¨åŠ¹çŽ‡ã¯å¤šå°‘悪ããªã‚Šã¾ã™ãŒã€ã‚¢ã‚¯ã‚»ã‚¹é€Ÿåº¦ãª
-ã©ã‚’考慮ã™ã‚‹ã¨ã€æœ¬æ–¹å¼ãŒä¸€ç•ªã„ã„ã¨è€ƒãˆã¦ãŠã‚Šã¾ã™ã€‚ãŸã¨ãˆã°ã‚ªãƒšãƒ©ãƒ³ãƒ‰ã‚’コ
-ãƒ³ã‚¹ã‚¿ãƒ³ãƒˆãƒ—ãƒ¼ãƒ«ã«æ ¼ç´ã—ã€ã‚¤ãƒ³ãƒ‡ãƒƒã‚¯ã‚¹ã®ã¿ã‚’オペランドã§ç¤ºã™ã“ã¨ã‚‚å¯èƒ½ã§
-ã™ãŒã€é–“接アクセスã«ãªã£ã¦ã—ã¾ã†ã®ã§æ€§èƒ½ã«å½±éŸ¿ãŒå‡ºã‚‹ãŸã‚ã€å´ä¸‹ã—ã¾ã—ãŸã€‚
-
-
-* VM Generator (rb/insns2vm.rb, insns.def)
-
-rb/insns2vm.rb ã¨ã„ã†ã‚¹ã‚¯ãƒªãƒ—トã¯ã€insns.def ã¨ã„ã†ãƒ•ァイルを読ã¿è¾¼ã¿ã€
-VM ã®ãŸã‚ã«å¿…è¦ãªãƒ•ァイルを生æˆã—ã¾ã™ã€‚具体的ã«ã¯ã€å‘½ä»¤ã‚’実行ã™ã‚‹éƒ¨åˆ†ã‚’
-生æˆã—ã¾ã™ãŒã€ã»ã‹ã«ã‚‚コンパイルã«å¿…è¦ãªæƒ…å ±ã€æœ€é©åŒ–ã«å¿…è¦ãªæƒ…å ±ã€ã‚„アセ
-ンブラã€é€†ã‚¢ã‚»ãƒ³ãƒ–ラã«å¿…è¦ãªæƒ…報を示ã™ãƒ•ァイルも生æˆã—ã¾ã™ã€‚
-
-
-** 命令記述
-
-insns.def ã«ã¯ã€å„命令ãŒã©ã®ã‚ˆã†ãªå‘½ä»¤ã§ã‚ã‚‹ã‹ã‚’記述ã—ã¾ã™ã€‚具体的ã«ã¯æ¬¡
-ã®æƒ…報を記述ã—ã¾ã™ã€‚
-
-- 命令ã®åå‰
-- ãã®å‘½ä»¤ã®ã‚«ãƒ†ã‚´ãƒªã€ã‚³ãƒ¡ãƒ³ãƒˆï¼ˆè‹±èªžã€æ—¥æœ¬èªžï¼‰
-- オペランドã®åå‰
-- ãã®å‘½ä»¤å®Ÿè¡Œå‰ã«ã‚¹ã‚¿ãƒƒã‚¯ã‹ã‚‰ãƒãƒƒãƒ—ã™ã‚‹å€¤
-- ãã®å‘½ä»¤å®Ÿè¡Œå¾Œã«ã‚¹ã‚¿ãƒƒã‚¯ã«ãƒ—ッシュã™ã‚‹å€¤
-- ãã®å‘½ä»¤ã®ãƒ­ã‚¸ãƒƒã‚¯ï¼ˆC 言語ã§è¨˜è¿°ï¼‰
-
-ãŸã¨ãˆã°ã€ã‚¹ã‚¿ãƒƒã‚¯ã« self ã‚’ãŠã putself ã¨ã„ã†å‘½ä»¤ã¯æ¬¡ã®ã‚ˆã†ã«è¨˜è¿°ã—ã¾
-ã™ã€‚
-
-#code
-/**
- @c put
- @e put self.
- @j self ã‚’ç½®ã。
- */
-DEFINE_INSN
-putself
-()
-()
-(VALUE val)
-{
- val = GET_SELF();
-}
-#end
-
-ã“ã®å ´åˆã€ã‚ªãƒšãƒ©ãƒ³ãƒ‰ã¨ã€ã‚¹ã‚¿ãƒƒã‚¯ã‹ã‚‰ãƒãƒƒãƒ—ã™ã‚‹å€¤ã¯ç„¡ã„ã“ã¨ã«ãªã‚Šã¾ã™ã€‚命
-令終了後ã€self をスタックトップã«ç½®ããŸã„ã‚ã‘ã§ã™ãŒã€ãれ㯠val ã¨ã„ã†ã€
-スタックã«ãƒ—ッシュã™ã‚‹å€¤ã¨ã—ã¦å®£è¨€ã—ã¦ãŠã„ãŸå¤‰æ•°ã«ä»£å…¥ã—ã¦ãŠãã“ã¨ã§ã€ã“
-れを変æ›ã™ã‚‹ã¨ã‚¹ã‚¿ãƒƒã‚¯ãƒˆãƒƒãƒ—ã«ç½®ã C プログラムãŒç”Ÿæˆã•れã¾ã™ã€‚
-
-ç´°ã‹ã„フォーマット㯠insns.def ã®å†’é ­ã‚’å‚ç…§ã—ã¦ãã ã•ã„。ãã‚“ãªã«é›£ã—ã
-ãªã„ã¨æ€ã„ã¾ã™ã€‚
-
-insnhelper.h ã¨ã„ã†ãƒ•ァイルã«ã€å‘½ä»¤ãƒ­ã‚¸ãƒƒã‚¯ã‚’記述ã™ã‚‹ãŸã‚ã«å¿…è¦ãªãƒžã‚¯ãƒ­
-ãŒå®šç¾©ã•れã¦ã„ã¾ã™ã€‚ã¾ãŸã€VM ã®å†…部構造ã«é–¢ã™ã‚‹å®šç¾©ã¯ vm.h ã¨ã„ã†ãƒ•ァイ
-ルã«ã‚りã¾ã™ã€‚
-
-
-* VM (Virtual Machine, vm.h, vm.c)
-
-VM ã¯ã€å®Ÿéš›ã«ã‚³ãƒ³ãƒ‘イルã—ãŸçµæžœç”Ÿæˆã•れる YARV 命令列を実行ã—ã¾ã™ã€‚ã¾ã•
-ã«ã€ã“ã®éƒ¨åˆ†ãŒ YARV ã®ã‚­ãƒ¢ã«ãªã‚Šã€å°†æ¥çš„ã«ã¯ eval.c ã‚’ã“ã® VM ã§ç½®ãæ›ãˆ
-ãŸã„ã¨è€ƒãˆã¦ã„ã¾ã™ã€‚
-
-ç¾åœ¨ã® Ruby インタプリタã§å®Ÿè¡Œã§ãã‚‹ã™ã¹ã¦ã®ã“ã¨ãŒã€ã“ã® VM ã§å®Ÿç¾ã§ãã‚‹
-よã†ã«ä½œã£ã¦ã„ã¾ã™ï¼ˆç¾æ®µéšŽã§ã¯ã¾ã å®Œå…¨ã§ã¯ã‚りã¾ã›ã‚“ãŒã€ãã†ãªã‚‹ã¹ãã§ã™ï¼‰ã€‚
-
-VM ã¯ã€å˜ç´”ãªã‚¹ã‚¿ãƒƒã‚¯ãƒžã‚·ãƒ³ã¨ã—ã¦å®Ÿè£…ã—ã¦ã„ã¾ã™ã€‚スレッドã²ã¨ã¤ã«ã‚¹ã‚¿ãƒƒ
-クã²ã¨ã¤ã‚’ä¿æŒã—ã¾ã™ã€‚スタックã®é ˜åŸŸã¯ãƒ’ープã‹ã‚‰å–å¾—ã™ã‚‹ã®ã§ã€æŸ”軟ãªé ˜åŸŸ
-設定ãŒå¯èƒ½ã§ã™ã€‚
-
-
-** レジスタ
-
-VM 㯠5 ã¤ã®ä»®æƒ³çš„ãªãƒ¬ã‚¸ã‚¹ã‚¿ã«ã‚ˆã£ã¦åˆ¶å¾¡ã•れã¾ã™ã€‚
-
-- PC (Program Counter)
-- SP (Stack Pointer)
-- CFP (Control Frame Pointer)
-- LFP (Local Frame Pointer)
-- DFP (Dynamic Frame Pointer)
-
-PC ã¯ç¾åœ¨å®Ÿè¡Œä¸­ã®å‘½ä»¤åˆ—ã®ä½ç½®ã‚’示ã—ã¾ã™ã€‚SP ã¯ã‚¹ã‚¿ãƒƒã‚¯ãƒˆãƒƒãƒ—ã®ä½ç½®ã‚’示ã—
-ã¾ã™ã€‚CFPã€LFPã€DFP ã¯ãれãžã‚Œãƒ•ãƒ¬ãƒ¼ãƒ ã®æƒ…報を示ã—ã¾ã™ã€‚詳細ã¯å¾Œè¿°ã—ã¾ã™ã€‚
-
-
-** スタックフレーム
-
-obsolete (update soon)
-
-
-** フレームデザインã«ã¤ã„ã¦ã®è£œè¶³
-
-Lisp ã®å‡¦ç†ç³»ãªã©ã‚’ã‹ã‚“ãŒãˆã‚‹ã¨ã€ã‚ã–ã‚ã–ブロックローカルフレームã¨ãƒ¡ã‚½
-ッドローカルフレームã®ã‚ˆã†ãªã‚‚ã®ã‚’用æ„ã™ã‚‹ã®ã¯å¥‡ç•°ã«è¦‹ãˆã‚‹ã‹ã‚‚ã—れã¾ã›ã‚“。
-ã‚るフレームをã€å…¥ã‚Œå­æ§‹é€ ã«ã—ã¦ã€ãƒ­ãƒ¼ã‚«ãƒ«å¤‰æ•°ã®ã‚¢ã‚¯ã‚»ã‚¹ã¯ãã®å…¥ã‚Œå­ã‚’外
-å´ã«è¾¿ã‚Œã°å¿…ãšãŸã©ã‚Šç€ãã“ã¨ãŒã§ãã‚‹ã‹ã‚‰ã§ã™ï¼ˆã¤ã¾ã‚Šã€lfp ã¯å¿…è¦ãªã„)。
-
-ã—ã‹ã—ã€Ruby ã§ã¯ã„ãã¤ã‹çжæ³ãŒé•ã„ã¾ã™ã€‚ã¾ãšã€ãƒ¡ã‚½ãƒƒãƒ‰ãƒ­ãƒ¼ã‚«ãƒ«ãªæƒ…å ±ãŒ
-ã‚ã‚‹ã“ã¨ã€å…·ä½“çš„ã«ã¯ãƒ–ロックã¨self(callee ã‹ã‚‰ã¿ã‚‹ã¨ receiver)ã§ã™ã€‚ã“
-ã®æƒ…報をãれãžã‚Œã®ãƒ•レームã«ã‚‚ãŸã›ã‚‹ã®ã¯ç„¡é§„ã§ã™ã€‚
-
-ã¾ãŸã€Ruby2.0 ã‹ã‚‰ã¯ãƒ–ロックローカル変数ã¯ãªããªã‚Šã¾ã™ï¼ˆãƒ–ロックローカル
-å¼•æ•°ã¯æ®‹ã‚‹ã®ã§ã€æ§‹é€ è‡ªä½“ã¯ã‚ã¾ã‚Šå¤‰ã‚りã¾ã›ã‚“)。ãã®ãŸã‚ã€ãƒ¡ã‚½ãƒƒãƒ‰ãƒ­ãƒ¼ã‚«
-ル変数ã¸ã®ã‚¢ã‚¯ã‚»ã‚¹ãŒé »ç™ºã™ã‚‹ã“ã¨ãŒäºˆæƒ³ã•れã¾ã™ã€‚
-
-ã“ã®ã¨ãã€ãƒ¡ã‚½ãƒƒãƒ‰ãƒ­ãƒ¼ã‚«ãƒ«å¤‰æ•°ã¸ã®ã‚¢ã‚¯ã‚»ã‚¹ã®ãŸã³ã«ãƒ•レーム(スコープ)ã®
-リストをãŸã©ã‚‹ã®ã¯ç„¡é§„ã§ã‚ã‚‹ã¨åˆ¤æ–­ã—ã€æ˜Žç¤ºçš„ã«ãƒ¡ã‚½ãƒƒãƒ‰ãƒ­ãƒ¼ã‚«ãƒ«ã‚¹ã‚³ãƒ¼ãƒ—ã¨
-ブロックフレームを分離ã—ã€ãƒ–ロックフレームã‹ã‚‰ã¯ãƒ¡ã‚½ãƒƒãƒ‰ãƒ­ãƒ¼ã‚«ãƒ«ãƒ•レーム
-㌠lfpレジスタã«ã‚ˆã£ã¦å®¹æ˜“ã«ã‚¢ã‚¯ã‚»ã‚¹ã§ãるよã†ã«ã—ã¾ã—ãŸã€‚
-
-
-** メソッド呼ã³å‡ºã—ã«ã¤ã„ã¦
-
-メソッド呼ã³å‡ºã—ã¯ã€YARV 命令列ã§è¨˜è¿°ã•れãŸãƒ¡ã‚½ãƒƒãƒ‰ã‹ã€C ã§è¨˜è¿°ã•れãŸãƒ¡
-ソッドã‹ã«ã‚ˆã£ã¦ãƒ‡ã‚£ã‚¹ãƒ‘ãƒƒãƒæ‰‹æ³•ãŒå¤‰ã‚りã¾ã™ã€‚
-
-YARV 命令列ã§ã‚ã£ãŸå ´åˆã€ä¸Šè¿°ã—ãŸã‚¹ã‚¿ãƒƒã‚¯ãƒ•レームを作æˆã—ã¦å‘½ä»¤ã‚’継続ã—
-ã¾ã™ã€‚ã¨ãã« VM ã®é–¢æ•°ã‚’å†å¸°å‘¼ã³å‡ºã™ã™ã‚‹ã“ã¨ã¯è¡Œãªã„ã¾ã›ã‚“。
-
-C ã§è¨˜è¿°ã•れãŸãƒ¡ã‚½ãƒƒãƒ‰ã ã£ãŸå ´åˆã€å˜ç´”ã«ãã®é–¢æ•°ã‚’呼ã³å‡ºã—ã¾ã™ï¼ˆãŸã ã—ã€
-ãƒãƒƒã‚¯ãƒˆãƒ¬ãƒ¼ã‚¹ã‚’æ­£ã—ã生æˆã™ã‚‹ãŸã‚ã«ãƒ¡ã‚½ãƒƒãƒ‰å‘¼ã³å‡ºã—ã®æƒ…報を付加ã—ã¦ã‹ã‚‰
-行ãªã„ã¾ã™ï¼‰ã€‚
-
-ã“ã®ãŸã‚ã€VM 用スタックを別途用æ„ã—ãŸã‚‚ã®ã®ã€ãƒ—ログラムã«ã‚ˆã£ã¦ã¯ãƒžã‚·ãƒ³
-スタックを使ã„切ã£ã¦ã—ã¾ã†å¯èƒ½æ€§ãŒã‚りã¾ã™ï¼ˆC -> Ruby -> C -> ... ã¨ã„ã†
-呼ã³å‡ºã—ãŒç¶šã„ãŸå ´åˆï¼‰ã€‚ã“れã¯ã€ç¾åœ¨ã§ã¯é¿ã‘られãªã„仕様ã¨ãªã£ã¦ã„ã¾ã™ã€‚
-
-
-** 例外
-
-例外ã¯ã€Java ã® JVM ã¨åŒæ§˜ã«ä¾‹å¤–テーブルを用æ„ã™ã‚‹ã“ã¨ã§å®Ÿç¾ã—ã¾ã™ã€‚例外
-ãŒç™ºç”Ÿã—ãŸã‚‰ã€å½“該フレームをã€ä¾‹å¤–テーブルを検査ã—ã¾ã™ã€‚ãã“ã§ã€ä¾‹å¤–ãŒç™º
-生ã—ãŸã¨ãã® PC ã®å€¤ã«åˆè‡´ã™ã‚‹ã‚¨ãƒ³ãƒˆãƒªãŒã‚ã£ãŸå ´åˆã€ãã®ã‚¨ãƒ³ãƒˆãƒªã«å¾“ã£ã¦
-動作ã—ã¾ã™ã€‚ã‚‚ã—エントリãŒè¦‹ã¤ã‹ã‚‰ãªã‹ã£ãŸå ´åˆã€ã‚¹ã‚¿ãƒƒã‚¯ã‚’æ’’ãæˆ»ã—ã¦ã¾ãŸ
-åŒæ§˜ã«ãã®ã‚¹ã‚³ãƒ¼ãƒ—ã®ä¾‹å¤–テーブルを検査ã—ã¾ã™ã€‚
-
-ã¾ãŸã€breakã€return(ブロック中)ã€retry ãªã©ã‚‚åŒæ§˜ã®ä»•組ã¿ã§å®Ÿç¾ã—ã¾ã™ã€‚
-
-*** 例外テーブル
-
-例外テーブルエントリã¯å…·ä½“çš„ã«ã¯æ¬¡ã®æƒ…å ±ãŒæ ¼ç´ã•れã¦ã„ã¾ã™ã€‚
-
-- 対象ã¨ã™ã‚‹ PC ã®ç¯„囲
-- 対象ã¨ã™ã‚‹ä¾‹å¤–ã®ç¨®é¡ž
-- ã‚‚ã—対象ã¨ãªã£ãŸã¨ãã«ã‚¸ãƒ£ãƒ³ãƒ—ã™ã‚‹å…ˆï¼ˆç¨®é¡žã«ã‚ˆã‚‹ï¼‰
-- ã‚‚ã—対象ã¨ãªã£ãŸã¨ãã«èµ·å‹•ã™ã‚‹ãƒ–ロック㮠iseq
-
-
-*** rescue
-
-rescue 節ã¯ãƒ–ロックã¨ã—ã¦å®Ÿç¾ã—ã¦ã„ã¾ã™ã€‚$! ã®å€¤ã‚’唯一ã®å¼•æ•°ã¨ã—ã¦æŒã¡ã¾
-ã™ã€‚
-
-#code
-begin
-rescue A
-rescue B
-rescue C
-end
-#end
-
-ã¯ã€æ¬¡ã®ã‚ˆã†ãª Ruby スクリプトã«å¤‰æ›ã•れã¾ã™ã€‚
-
-#code
-{|err|
- case err
- when A === err
- when B === err
- when C === err
- else
- raise # yarv ã®å‘½ä»¤ã§ã¯ throw
- end
-}
-#end
-
-
-*** ensure
-
-正常系(例外ãŒç™ºç”Ÿã—ãªã‹ã£ãŸå ´åˆï¼‰ã¨ç•°å¸¸ç³»ï¼ˆä¾‹å¤–ãŒç™ºç”Ÿã—ãŸã¨ããªã©ï¼‰ã®2
-種類ã®å‘½ä»¤åˆ—ãŒç”Ÿæˆã•れã¾ã™ã€‚正常系ã§ã¯ã€ãŸã ã®é€£ç¶šã—ãŸã‚³ãƒ¼ãƒ‰é ˜åŸŸã¨ã—ã¦ã‚³
-ンパイルã•れã¾ã™ã€‚ã¾ãŸã€ç•°å¸¸ç³»ã§ã¯ãƒ–ロックã¨ã—ã¦å®Ÿè£…ã—ã¾ã™ã€‚最後ã¯å¿…ãš
-throw 命令ã§ç· ã‚ã‚‹ã“ã¨ã«ãªã‚Šã¾ã™ã€‚
-
-
-*** break, return(ブロック中)ã€retry
-
-break æ–‡ã€ãƒ–ロック中㮠return æ–‡ã€retry 文㯠throw 命令ã¨ã—ã¦ã‚³ãƒ³ãƒ‘イル
-ã•れã¾ã™ã€‚ã©ã“ã¾ã§æˆ»ã‚‹ã‹ã¯ã€break をフックã™ã‚‹ä¾‹å¤–テーブルã®ã‚¨ãƒ³ãƒˆãƒªãŒåˆ¤
-æ–­ã—ã¾ã™ã€‚
-
-
-** å®šæ•°ã®æ¤œç´¢
-
-定数ã¨ã„ã†åå‰ãªã®ã«ã€Ruby ã§ã¯ã‚³ãƒ³ãƒ‘ã‚¤ãƒ«æ™‚ã«æ±ºå®šã—ã¾ã›ã‚“。ã¨ã„ã†ã‹ã€ã„
-ã¤ã¾ã§ã‚‚å†å®šç¾©å¯èƒ½ã«ãªã£ã¦ã„ã¾ã™ã€‚
-
-定数アクセスã®ãŸã‚ã®Rubyè¨˜è¿°ã¯æ¬¡ã®ã‚ˆã†ã«ãªã‚Šã¾ã™ã€‚
-
-#code
-Ruby表ç¾:
-expr::ID::...::ID
-#end
-
-ã“れã¯ã€yarv命令セットã§ã¯æ¬¡ã®ã‚ˆã†ã«ãªã‚Šã¾ã™ã€‚
-
-#code
-(expr)
-getconstant ID
-...
-getconstant ID
-#end
-
-
-*** 定数検索パス
-
-ã‚‚ã— expr ㌠nil ã ã£ãŸå ´åˆã€å®šæ•°æ¤œç´¢ãƒ‘スã«å¾“ã£ã¦å®šæ•°ã‚’検索ã—ã¾ã™ã€‚ã“ã®
-挙動ã¯ä»Šå¾Œ Ruby 2.0 ã«å‘ã‘ã¦å¤‰æ›´ã•れる場åˆãŒã‚りã¾ã™ã€‚
-
-+ クラスã€ãƒ¢ã‚¸ãƒ¥ãƒ¼ãƒ«ã®å‹•çš„ãƒã‚¹ãƒˆé–¢ä¿‚(プログラムã®å­—é¢ä¸Šï¼‰ã‚’ルートã¾ã§è¾¿ã‚‹
-+ 継承関係をルート(Object)ã¾ã§è¾¿ã‚‹
-
-ã“ã®ãŸã‚ã€ã‚¯ãƒ©ã‚¹ã€ãƒ¢ã‚¸ãƒ¥ãƒ¼ãƒ«ã®å‹•çš„ãƒã‚¹ãƒˆé–¢ä¿‚ã‚’ä¿å­˜ã—ãªã‘れã°ãªã‚Šã¾ã›ã‚“。
-ã“ã®ãŸã‚ã«ã€thread_object ã«ã¯ klass_nest_stack ã¨ã„ã†ã‚‚ã®ã‚’用æ„ã—ã¾ã—ãŸã€‚
-ã“れã¯ã€ç¾åœ¨ã®ãƒã‚¹ãƒˆã®æƒ…報をä¿å­˜ã—ã¾ã™ã€‚
-
-メソッド定義時ã€ãã®ç¾åœ¨ã®ãƒã‚¹ãƒˆæƒ…報をメソッド定義時ã«ï¼ˆdupã—ã¦ï¼‰åŠ ãˆã‚‹
-ã“ã¨ã§ã€ãã®ãƒ¡ã‚½ãƒƒãƒ‰ã®å®Ÿè¡Œæ™‚ã€ãã®ãƒã‚¹ãƒˆæƒ…報をå‚ç…§ã™ã‚‹ã“ã¨ãŒå¯èƒ½ã«ãªã‚Šã¾
-ã™ã€‚
-
-トップレベルã§ã¯ã€ãã®æƒ…å ±ã¯ãªã„ã“ã¨ã«ãªã‚Šã¾ã™ã€‚
-
-クラス/モジュール定義文実行時ã¯ã€ç¾åœ¨ã®æƒ…å ±ãã®ã‚‚ã®ã‚’å‚ç…§ã™ã‚‹ã“ã¨ã«ãªã‚Š
-ã¾ã™ã€‚ã“れã¯ã€ã‚¯ãƒ©ã‚¹ã‚¹ã‚³ãƒ¼ãƒ—çªå…¥æ™‚ã€ãã®æƒ…報をクラス定義文ã«ã‚³ãƒ”ーã—ã¾ã™
-(ã™ã§ã«ã‚³ãƒ”ーã•れã¦ã„れã°ã€ã“れを行ã„ã¾ã›ã‚“)。
-
-ã“れã«ã‚ˆã‚Šã€å‹•çš„ãªãƒã‚¹ãƒˆæƒ…å ±ã‚’çµ±ä¸€çš„ã«æ‰±ã†ã“ã¨ãŒã§ãã¾ã™ã€‚
-
-
-** 最é©åŒ–手法
-
-YARV ã§ã¯é«˜é€ŸåŒ–を目的ã¨ã—ã¦ã„ã‚‹ã®ã§ã€ã•ã¾ã–ã¾ãªæœ€é©åŒ–手法を利用ã—ã¦ã„ã¾
-ã™ã€‚詳細ã¯å‰²æ„›ã—ã¾ã™ãŒã€ä»¥ä¸‹ã«è¿°ã¹ã‚‹æœ€é©åŒ–ãªã©ã‚’行ãªã£ã¦ãŠã‚Šã¾ã™ã€‚
-
-
-*** threaded code
-
-GCC ã® C 言語拡張ã§ã‚る値ã¨ã—ã¦ã®ãƒ©ãƒ™ãƒ«ã‚’利用ã—㦠direct threaded code
-を実ç¾ã—ã¦ã„ã¾ã™ã€‚
-
-
-*** Peephole optimization
-
-ã„ãã¤ã‹ã®ç°¡å˜ãªæœ€é©åŒ–ã‚’ã—ã¦ã„ã¾ã™ã€‚
-
-
-*** inline method cache
-
-命令列ã®ä¸­ã«ãƒ¡ã‚½ãƒƒãƒ‰æ¤œç´¢çµæžœã‚’埋ã‚è¾¼ã¿ã¾ã™ã€‚
-
-
-*** inline constant cache
-
-命令列ã®ä¸­ã«å®šæ•°æ¤œç´¢çµæžœã‚’埋ã‚è¾¼ã¿ã¾ã™ã€‚
-
-
-*** ブロック㨠Proc オブジェクトã®åˆ†é›¢
-
-ブロック付ãメソッド呼ã³å‡ºã—ãŒè¡Œãªã‚れãŸã¨ãã«ã¯ã™ãã«ã¯ãƒ–ロックを Proc
-オブジェクトã¨ã—ã¦ç”Ÿæˆã—ã¾ã›ã‚“。ã“れã«ã‚ˆã‚Šã€å¿…è¦ãªã„ Proc オブジェクトã®
-生æˆã‚’抑ãˆã¦ã„ã¾ã™ã€‚
-
-Proc メソッドã¯ã€å®Ÿéš›ã«å¿…è¦ã«ãªã£ãŸæ™‚点ã§ä½œã‚‰ã‚Œã€ãã®ã¨ãã«ç’°å¢ƒï¼ˆã‚¹ã‚³ãƒ¼
-プ上ã«ç¢ºä¿ã•れãŸå¤‰æ•°ãªã©ï¼‰ã‚’ヒープã«ä¿å­˜ã—ã¾ã™ã€‚
-
-
-*** 特化命令
-
-Fixnum åŒå£«ã®åŠ ç®—ãªã©ã‚’正直ã«é–¢æ•°å‘¼ã³å‡ºã—ã«ã‚ˆã£ã¦è¡Œãªã†ã¨ã€ã‚³ã‚¹ãƒˆãŒã‹ã‹
-ã‚‹ã®ã§ã€ã“れらã®ãƒ—ãƒªãƒŸãƒ†ã‚£ãƒ–ãªæ“作を行ãªã†ãŸã‚ã®ãƒ¡ã‚½ãƒƒãƒ‰å‘¼ã³å‡ºã—ã¯å°‚用命
-令を用æ„ã—ã¾ã—ãŸã€‚
-
-
-*** 命令èžåˆ
-
-複数ã®å‘½ä»¤ã‚’ 1 命令ã«å¤‰æ›ã—ã¾ã™ã€‚èžåˆå‘½ä»¤ã¯ opt_insn_unif.def ã®è¨˜è¿°ã«ã‚ˆ
-り自動的ã«ç”Ÿæˆã•れã¾ã™ã€‚
-
-
-*** オペランドèžåˆ
-
-複数ã®ã‚ªãƒšãƒ©ãƒ³ãƒ‰ã‚’å«ã‚ãŸå‘½ä»¤ã‚’生æˆã—ã¾ã™ã€‚èžåˆå‘½ä»¤ã¯ opt_operand.def ã®
-記述ã«ã‚ˆã£ã¦è‡ªå‹•çš„ã«ç”Ÿæˆã•れã¾ã™ã€‚
-
-
-*** stack caching
-
-スタックトップを仮想レジスタã«ä¿æŒã™ã‚‹ã‚ˆã†ã«ã—ã¾ã™ã€‚ç¾åœ¨ã¯ 2 個ã®ä»®æƒ³ãƒ¬
-ジスタを想定ã—ã€5状態ã®ã‚¹ã‚¿ãƒƒã‚¯ã‚­ãƒ£ãƒƒã‚·ãƒ³ã‚°ã‚’行ãªã„ã¾ã™ã€‚スタックキャッ
-シングã™ã‚‹å‘½ä»¤ã¯è‡ªå‹•çš„ã«ç”Ÿæˆã•れã¾ã™ã€‚
-
-
-*** JIT Compile
-
-機械語を切り貼りã—ã¾ã™ã€‚éžå¸¸ã«å®Ÿé¨“çš„ãªã‚³ãƒ¼ãƒ‰ã‚‚ã®ã—ã‹ä½œã£ã¦ãŠã‚Šã¾ã›ã‚“。ã»
-ã¨ã‚“ã©ã®ãƒ—ログラムã¯å‹•ãã¾ã›ã‚“。
-
-
-*** AOT Compile
-
-YARV 命令列を C 言語ã«å¤‰æ›ã—ã¾ã™ã€‚ã¾ã ååˆ†ãªæœ€é©åŒ–を行ãªãˆã¦ãŠã‚Šã¾ã›ã‚“ãŒã€
-ãれãªã‚Šã«å‹•ãã¾ã™ã€‚rb/aotc.rb ãŒã‚³ãƒ³ãƒ‘イラã§ã™ã€‚
-
-
-* Assembler (rb/yasm.rb)
-
-YARV 命令列ã®ã‚¢ã‚»ãƒ³ãƒ–ラを用æ„ã—ã¾ã—ãŸã€‚ä½¿ã„æ–¹ã¯ rb/yasm.rb ã‚’å‚ç…§ã—ã¦ã
-ã ã•ã„(ã¾ã ã€ä¾‹ç¤ºã—ã¦ã‚ã‚‹ç”Ÿæˆæ‰‹æ³•ã®ã™ã¹ã¦ã‚’サãƒãƒ¼ãƒˆã—ã¦ã„ã‚‹ã‚ã‘ã§ã¯ã‚り
-ã¾ã›ã‚“)。
-
-
-* Dis-Assembler (disasm.c)
-
-YARV 命令列を示ã™ã‚ªãƒ–ジェクト YARVCore::InstructionSequence ã«ã¯ disasm
-メソッドãŒã‚りã¾ã™ã€‚ã“れã¯ã€å‘½ä»¤åˆ—を逆アセンブルã—ãŸæ–‡å­—列を返ã—ã¾ã™ã€‚
-
-
-* YARV 命令セット
-
-<%= d %>
-
-* ãã®ä»–
-
-** テスト
-
-test/test_* ãŒãƒ†ã‚¹ãƒˆã‚±ãƒ¼ã‚¹ã§ã™ã€‚一応ã€ãƒŸã‚¹ãªãå‹•ãã¯ãšã§ã™ã€‚逆ã«ã„ã†ã¨ã€
-ã“ã®ãƒ†ã‚¹ãƒˆã«è¨˜è¿°ã•れã¦ã„る例ã§ã¯ãã¡ã‚“ã¨å‹•作ã™ã‚‹ã¨ã„ã†ã“ã¨ã§ã™ã€‚
-
-
-** ベンãƒãƒžãƒ¼ã‚¯
-
-benchmark/bm_* ã«ãƒ™ãƒ³ãƒãƒžãƒ¼ã‚¯ãƒ—ログラムãŒãŠã„ã¦ã‚りã¾ã™ã€‚
-
-
-** 今後ã®äºˆå®š
-
-ã¾ã ã¾ã ã‚„らãªã‘れã°ã„ã‘ãªã„ã“ã¨ã€æœªå®Ÿè£…部分ãŒãŸãã•ã‚“ã‚りã¾ã™ã‚“ã§ã‚„ã£ã¦
-ã„ã‹ãªã‘れã°ãªã‚Šã¾ã›ã‚“。一番大ããªç›®æ¨™ã¯ eval.c ã‚’ç½®ãæ›ãˆã‚‹ã“ã¨ã§ã—ょã†
-ã‹ã€‚
-
-
-*** Verifier
-
-YARV 命令列ã¯ã€ãƒŸã‚¹ãŒã‚ã£ã¦ã‚‚å‹•ã‹ã—ã¦ã—ã¾ã†ãŸã‚å±é™ºã§ã‚ã‚‹å¯èƒ½æ€§ãŒã‚りã¾
-ã™ã€‚ãã®ãŸã‚ã€ã‚¹ã‚¿ãƒƒã‚¯ã®åˆ©ç”¨çŠ¶æ…‹ã‚’ãã¡ã‚“ã¨äº‹å‰ã«æ¤œè¨¼ã™ã‚‹ã‚ˆã†ãªãƒ™ãƒªãƒ•ァイ
-アを用æ„ã—ãªã‘れã°ãªã‚‰ãªã„ã¨è€ƒãˆã¦ã„ã¾ã™ã€‚
-
-
-*** Compiled File ã®æ§‹æƒ³
-
-Ruby プログラムをã“ã®å‘½ä»¤ã‚»ãƒƒãƒˆã«ã‚·ãƒªã‚¢ãƒ©ã‚¤ã‚ºã—ãŸãƒ‡ãƒ¼ã‚¿æ§‹é€ ã‚’ファイルã«
-出力ã§ãるよã†ã«ã—ãŸã„ã¨è€ƒãˆã¦ã„ã¾ã™ã€‚ã“れを利用ã—ã¦ä¸€åº¦ã‚³ãƒ³ãƒ‘イルã—ãŸå‘½
-令列をファイルã«ä¿å­˜ã—ã¦ãŠã‘ã°ã€æ¬¡å›žãƒ­ãƒ¼ãƒ‰æ™‚ã«ã¯ã‚³ãƒ³ãƒ‘ã‚¤ãƒ«ã®æ‰‹é–“ã€ã‚³ã‚¹ãƒˆ
-ã‚’çœãã“ã¨ãŒã§ãã¾ã™ã€‚
-
-
-**** 全体構æˆ
-
-次ã®ã‚ˆã†ãªãƒ•ァイル構æˆã‚’考ãˆã¦ã„ã¾ã™ãŒã€ã¾ã æœªå®šã§ã™ã€‚
-
-#code
-u4 : 4 byte unsigned storage
-u2 : 2 byte unsigned storage
-u1 : 1 byte unsigned storage
-
-every storages are little endian :-)
-
-CompiledFile{
- u4 magic;
-
- u2 major;
- u2 minor;
-
- u4 character_code;
-
- u4 constants_pool_count;
- ConstantEntry constants_pool[constants_pool_count];
-
- u4 block_count;
- blockEntry blocks[block_count];
-
- u4 method_count;
- MethodEntry methods[method_count];
-}
-#end
-
-Java classfile ã®ãƒ‘クリ。
-
diff --git a/doc/yjit/yjit.md b/doc/yjit/yjit.md
deleted file mode 100644
index 0024c780b9..0000000000
--- a/doc/yjit/yjit.md
+++ /dev/null
@@ -1,544 +0,0 @@
-<p align="center">
- <a href="https://yjit.org/" target="_blank" rel="noopener noreferrer">
- <img src="https://user-images.githubusercontent.com/224488/131155756-aa8fb528-a813-4dfd-99ac-8785c3d5eed7.png" width="400">
- </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.
-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>
-
-If you wish to learn more about the approach taken, here are some conference talks and publications:
-
-- MPLR 2023 talk: [Evaluating YJIT’s Performance in a Production Context: A Pragmatic Approach](https://www.youtube.com/watch?v=pVRmPZcNUhc)
-- 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)
-- ECOOP 2016 paper: [Interprocedural Type Specialization of JavaScript Programs Without Type Analysis](https://drops.dagstuhl.de/opus/volltexte/2016/6101/pdf/LIPIcs-ECOOP-2016-7.pdf)
-- 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:
-
-```BibTeX
-@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},
-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}
-}
-```
-
-## 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).
-
-## Installation
-
-### Requirements
-
-You will need to install:
-
- - All the usual build tools for Ruby. See [Building Ruby](../contributing/building_ruby.md)
- - The Rust compiler `rustc`
- - The Rust version must be [>= 1.58.0](../../yjit/Cargo.toml).
- - Optionally, only if you wish to build in dev/debug mode, Rust's `cargo`
-
-If you don't intend on making code changes to YJIT itself, we recommend
-obtaining `rustc` through your OS's package manager since that
-likely reuses the same vendor which provides the C toolchain.
-
-If you will be changing YJIT's Rust code, we suggest using the
-[first-party installation method][rust-install] for Rust. Rust also provides
-first class [support][editor-tools] for many source code editors.
-
-[rust-install]: https://www.rust-lang.org/tools/install
-[editor-tools]: https://www.rust-lang.org/tools
-
-### Building YJIT
-
-Start by cloning the `ruby/ruby` repository:
-
-```sh
-git clone https://github.com/ruby/ruby yjit
-cd yjit
-```
-
-The YJIT `ruby` binary can be built with either GCC or Clang. It can be built either in dev (debug) mode or in release mode. For maximum performance, compile YJIT in release mode with GCC. More detailed build instructions are provided in the [Ruby README](https://github.com/ruby/ruby#how-to-build).
-
-```sh
-# Configure in release mode for maximum performance, build and install
-./autogen.sh
-./configure --enable-yjit --prefix=$HOME/.rubies/ruby-yjit --disable-install-doc
-make -j && make install
-```
-
-or
-
-```sh
-# Configure in lower-performance dev (debug) mode for development, build and install
-./autogen.sh
-./configure --enable-yjit=dev --prefix=$HOME/.rubies/ruby-yjit --disable-install-doc
-make -j && make install
-```
-
-Dev mode includes extended YJIT statistics, but can be slow. For only statistics you can configure in stats mode:
-
-```sh
-# Configure in extended-stats mode without slow runtime checks, build and install
-./autogen.sh
-./configure --enable-yjit=stats --prefix=$HOME/.rubies/ruby-yjit --disable-install-doc
-make -j && make install
-```
-
-On macOS, you may need to specify where to find some libraries:
-
-```sh
-# Install dependencies
-brew install openssl libyaml
-
-# Configure in dev (debug) mode for development, build and install
-./autogen.sh
-./configure --enable-yjit=dev --prefix=$HOME/.rubies/ruby-yjit --disable-install-doc --with-opt-dir="$(brew --prefix openssl):$(brew --prefix readline):$(brew --prefix libyaml)"
-make -j && make install
-```
-
-Typically configure will choose the default C compiler. To specify the C compiler, use
-
-```sh
-# Choosing a specific c compiler
-export CC=/path/to/my/chosen/c/compiler
-```
-
-before running `./configure`.
-
-You can test that YJIT works correctly by running:
-
-```sh
-# Quick tests found in /bootstraptest
-make btest
-
-# Complete set of tests
-make -j test-all
-```
-
-## Usage
-
-### Examples
-
-Once YJIT is built, you can either use `./miniruby` from within your build directory, or switch to the YJIT version of `ruby`
-by using the `chruby` tool:
-
-```sh
-chruby ruby-yjit
-ruby myscript.rb
-```
-
-You can dump statistics about compilation and execution by running YJIT with the `--yjit-stats` command-line option:
-
-```sh
-./miniruby --yjit-stats myscript.rb
-```
-
-You can see what YJIT has compiled by running YJIT with the `--yjit-log` command-line option:
-
-```sh
-./miniruby --yjit-log myscript.rb
-```
-
-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>
-
-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-mem-size=N`: soft limit on YJIT memory usage in MiB (default: 128). Tries to limit `code_region_size + yjit_alloc_size`
-- `--yjit-exec-mem-size=N`: hard limit on executable memory block in MiB. Limits `code_region_size`
-- `--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-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-log[=file|dir]`: log all compilation events to the specified file or directory. If no name is supplied, the last 1024 log entries will be printed to stderr when the application exits.
-- `--yjit-log=quiet`: gather a circular buffer of recent YJIT compilations. The compilation log entries are accessible through `RubyVM::YJIT.log` and old entries will be discarded if the buffer is not drained quickly. (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`
-
-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.
-
-## 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-mem-size
-
-The `--yjit-mem-size` value can be used to set the maximum amount of memory that YJIT
-is allowed to use. This corresponds to the total of `RubyVM::YJIT.runtime_stats[:code_region_size]`
-and `RubyVM::YJIT.runtime_stats[:yjit_alloc_size]`
-Increasing the `--yjit-mem-size` value 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 percentage of total YARV instructions
-executed by YJIT as opposed to the CRuby interpreter.
-Ideally, `ratio_in_yjit` should be as large as 99%, and increasing `--yjit-mem-size` often
-helps improving `ratio_in_yjit`.
-
-### Running workers as long as possible
-
-It's helpful to call the same code as many times as possible before a process restarts.
-If a process is killed too frequently, the time taken for compiling methods may outweigh
-the speedup obtained by compiling them.
-
-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
-
-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.
-
-### Decreasing --yjit-mem-size
-
-YJIT uses memory for compiled code and metadata. You can change the maximum amount of memory
-that YJIT can use by specifying a different `--yjit-mem-size` command-line option. The default value
-is currently `128`.
-When changing this value, 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.
-
-## Code Optimization Tips
-
-This section contains tips on writing Ruby code that will run as fast as possible on YJIT. Some of this advice is based on current limitations of YJIT, while other advice is broadly applicable. It probably won't be practical to apply these tips everywhere in your codebase. You should ideally start by profiling your application using a tool such as [stackprof](https://github.com/tmm1/stackprof) so that you can determine which methods make up most of the execution time. You can then refactor the specific methods that make up the largest fractions of the execution time. We do not recommend modifying your entire codebase based on the current limitations of YJIT.
-
-- Avoid using `OpenStruct`
-- Avoid redefining basic integer operations (i.e. +, -, <, >, etc.)
-- 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
-
-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`.
-
-```rb
-$ RUBYOPT="--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,
- :send_callsite_not_simple=>7267,
- :send_kw_splat=>7,
- :send_ivar_set_method=>72,
-...
-```
-
-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
-
-Counters starting with "exit_" show reasons for YJIT code taking a side exit (return to the interpreter.)
-
-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.
-
-The printed text after a `--yjit-stats` run includes other information that may be named differently than the information in `RubyVM::YJIT.runtime_stats`.
-
-## Contributing
-
-We welcome open source contributions. 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
-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.
-
-### 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
-- `yjit/src/asm/*`: in-memory assembler we use to generate machine code
-- `yjit/src/codegen.rs`: logic for translating Ruby bytecode to machine code
-- `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
-
-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
-
-### Generating C bindings with bindgen
-
-In order to expose C functions to the Rust codebase, you will need to generate C bindings:
-
-```sh
-CC=clang ./configure --enable-yjit=dev
-make -j yjit-bindgen
-```
-
-This uses the bindgen tools to generate/update `yjit/src/cruby_bindings.inc.rs` based on the
-bindings listed in `yjit/bindgen/src/main.rs`. Avoid manually editing this file
-as it could be automatically regenerated at a later time. If you need to manually add C bindings,
-add them to `yjit/cruby.rs` instead.
-
-### Coding & Debugging Protips
-
-There are multiple 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:
-
-```sh
-make -j test-all RUN_OPTS="--yjit-call-threshold=1"
-```
-
-Or single-threaded like this, to more easily identify which specific test is failing:
-
-```sh
-make test-all TESTOPTS=--verbose RUN_OPTS="--yjit-call-threshold=1"
-```
-
-To run a single test file with `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
-make btest BTESTS=bootstraptest/test_ractor.rb RUN_OPTS="--yjit-call-threshold=1"
-```
-
-There are shortcuts to run/debug your own test/repro in `test.rb`:
-
-```sh
-make run # runs ./miniruby test.rb
-make lldb # launches ./miniruby test.rb in lldb
-```
-
-You can use the Intel syntax for disassembly in LLDB, keeping it consistent with YJIT's disassembly:
-
-```sh
-echo "settings set target.x86-disassembly-flavor intel" >> ~/.lldbinit
-```
-
-## Running x86 YJIT on Apple's Rosetta
-
-For development purposes, it is possible to run x86 YJIT on an Apple M1 via Rosetta. You can find basic
-instructions below, but there are a few caveats listed further down.
-
-First, install Rosetta:
-
-```console
-$ softwareupdate --install-rosetta
-```
-
-Now any command can be run with Rosetta via the `arch` command line tool.
-
-Then you can start your shell in an x86 environment:
-
-```console
-$ arch -x86_64 zsh
-```
-
-You can double check your current architecture via the `arch` command:
-
-```console
-$ arch -x86_64 zsh
-$ arch
-i386
-```
-
-You may need to set the default target for `rustc` to x86-64, e.g.
-
-```console
-$ rustup default stable-x86_64-apple-darwin
-```
-
-While in your i386 shell, install Cargo and Homebrew, then hack away!
-
-### Rosetta Caveats
-
-1. You must install a version of Homebrew for each architecture
-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/zjit.md b/doc/zjit.md
deleted file mode 100644
index 90f890bfa0..0000000000
--- a/doc/zjit.md
+++ /dev/null
@@ -1,133 +0,0 @@
-# ZJIT: ADVANCED RUBY JIT PROTOTYPE
-
-## Build Instructions
-
-To build ZJIT on macOS:
-```
-./autogen.sh
-./configure --enable-zjit=dev --prefix=$HOME/.rubies/ruby-zjit --disable-install-doc --with-opt-dir="$(brew --prefix openssl):$(brew --prefix readline):$(brew --prefix libyaml)"
-make -j miniruby
-```
-
-## Useful dev commands
-
-To view YARV output for code snippets:
-```
-./miniruby --dump=insns -e0
-```
-
-To run code snippets with ZJIT:
-```
-./miniruby --zjit -e0
-```
-
-You can also try https://www.rubyexplorer.xyz/ to view Ruby YARV disasm output with syntax highlighting
-in a way that can be easily shared with other team members.
-
-## Testing
-
-Make sure you have a `--enable-zjit=dev` build, and run `brew install cargo-nextest` first.
-
-### make zjit-check
-
-This command runs all ZJIT tests: `make zjit-test` and `test/ruby/test_zjit.rb`.
-
-```
-make zjit-check
-```
-
-### make zjit-test
-
-This command runs Rust unit tests.
-
-```
-make zjit-test
-```
-
-You can also run a single test case by specifying the function name:
-
-```
-make zjit-test ZJIT_TESTS=test_putobject
-```
-
-If you expect that your changes cause tests to fail and they do, you can have
-`expect-test` fix the expected value for you by putting `UPDATE_EXPECT=1`
-before your test command, like so:
-
-```
-UPDATE_EXPECT=1 make zjit-test ZJIT_TESTS=test_putobject
-```
-
-Test changes will be reviewed alongside code changes.
-
-<details>
-
-<summary>Setting up zjit-test</summary>
-
-ZJIT uses `cargo-nextest` for Rust unit tests instead of `cargo test`.
-`cargo-nextest` runs each test in its own process, which is valuable since
-CRuby only supports booting once per process, and most APIs are not thread
-safe. Use `brew install cargo-nextest` to install it on macOS, otherwise, refer
-to <https://nexte.st/docs/installation/pre-built-binaries/> for installation
-instructions.
-
-Since it uses Cargo, you'll also need a `configure --enable-zjit=dev ...` build
-for `make zjit-test`. Since the tests need to link against CRuby, directly
-calling `cargo test`, or `cargo nextest` likely won't build. Make sure to
-use `make`.
-
-</details>
-
-### make zjit-test-all
-
-```
-make zjit-test-all
-```
-
-This command runs all Ruby tests under `/test/ruby/` with ZJIT enabled.
-
-Certain tests are excluded under `/test/.excludes-zjit`.
-
-### test/ruby/test\_zjit.rb
-
-This command runs Ruby execution tests.
-
-```
-make test-all TESTS="test/ruby/test_zjit.rb"
-```
-
-You can also run a single test case by matching the method name:
-
-```
-make test-all TESTS="test/ruby/test_zjit.rb -n TestZJIT#test_putobject"
-```
-
-## ZJIT Glossary
-
-This glossary contains terms that are helpful for understanding ZJIT.
-
-Please note that some terms may appear in CRuby internals too but with different meanings.
-
-| Term | Definition |
-| --- | -----------|
-| HIR | High-level Intermediate Representation. High-level (Ruby semantics) graph representation in static single-assignment (SSA) form |
-| LIR | Low-level Intermediate Representation. Low-level IR used in the backend for assembly generation |
-| SSA | Static Single Assignment. A form where each variable is assigned exactly once |
-| `opnd` | Operand. An operand to an IR instruction (can be register, memory, immediate, etc.) |
-| `dst` | Destination. The output operand of an instruction where the result is stored |
-| VReg | Virtual Register. A virtual register that gets lowered to physical register or memory |
-| `insn_id` | Instruction ID. An index of an instruction in a function |
-| `block_id` | The index of a basic block, which effectively acts like a pointer |
-| `branch` | Control flow edge between basic blocks in the compiled code |
-| `cb` | Code Block. Memory region for generated machine code |
-| `entry` | The starting address of compiled code for an ISEQ |
-| Patch Point | Location in generated code that can be modified later in case assumptions get invalidated |
-| Frame State | Captured state of the Ruby stack frame at a specific point for deoptimization |
-| Guard | A run-time check that ensures assumptions are still valid |
-| `invariant` | An assumption that JIT code relies on, requiring invalidation if broken |
-| Deopt | Deoptimization. Process of falling back from JIT code to interpreter |
-| Side Exit | Exit from JIT code back to interpreter |
-| Type Lattice | Hierarchy of types used for type inference and optimization |
-| Constant Folding | Optimization that evaluates constant expressions at compile time |
-| RSP | x86-64 stack pointer register used for native stack operations |
-| Register Spilling | Process of moving register values to memory when running out of physical registers |
diff --git a/enc/Makefile.in b/enc/Makefile.in
index ce93fdd22d..2a3c45169f 100644
--- a/enc/Makefile.in
+++ b/enc/Makefile.in
@@ -24,13 +24,14 @@ OBJEXT = @OBJEXT@
LIBEXT = @LIBEXT@
EXEEXT = @EXEEXT@
TIMESTAMPDIR = $(EXTOUT)/.timestamp
-ENC_TRANS_D = $(TIMESTAMPDIR)/.enc-trans.time
-ENC_TRANS_SO_D = $(TIMESTAMPDIR)/.enc-trans.so.time
+ENC_TRANS_D = $(TIMESTAMPDIR)/enc-trans.time
+ENC_TRANS_SO_D = $(TIMESTAMPDIR)/enc-trans-$(arch).time
BUILTIN_ENCS = enc/ascii.c enc/us_ascii.c\
enc/unicode.c enc/utf_8.c
BUILTIN_TRANSES = enc/trans/newline.trans
+BUILTIN_TRANS_CSRCS = $(BUILTIN_TRANSES:.trans=.c)
RUBY_SO_NAME = @RUBY_SO_NAME@
LIBRUBY = @LIBRUBY@
diff --git a/enc/ascii.c b/enc/ascii.c
index ae7db97f25..4ba93f4feb 100644
--- a/enc/ascii.c
+++ b/enc/ascii.c
@@ -54,7 +54,11 @@ OnigEncodingDefine(ascii, ASCII) = {
onigenc_not_support_get_ctype_code_range,
onigenc_single_byte_left_adjust_char_head,
onigenc_always_true_is_allowed_reverse_match,
+#ifdef USE_CASE_MAP_API
onigenc_single_byte_ascii_only_case_map,
+#else
+ NULL,
+#endif
ENCINDEX_ASCII_8BIT,
ONIGENC_FLAG_NONE,
};
diff --git a/enc/big5.c b/enc/big5.c
index ab4fb69819..e141ebdbe3 100644
--- a/enc/big5.c
+++ b/enc/big5.c
@@ -300,7 +300,11 @@ OnigEncodingDefine(big5, BIG5) = {
onigenc_not_support_get_ctype_code_range,
big5_left_adjust_char_head,
big5_is_allowed_reverse_match,
+#ifdef USE_CASE_MAP_API
onigenc_ascii_only_case_map,
+#else
+ NULL,
+#endif
0,
ONIGENC_FLAG_NONE,
};
@@ -335,7 +339,11 @@ OnigEncodingDefine(big5_hkscs, BIG5_HKSCS) = {
onigenc_not_support_get_ctype_code_range,
big5_left_adjust_char_head,
big5_is_allowed_reverse_match,
+#ifdef USE_CASE_MAP_API
onigenc_ascii_only_case_map,
+#else
+ NULL,
+#endif
0,
ONIGENC_FLAG_NONE,
};
@@ -370,7 +378,11 @@ OnigEncodingDefine(big5_uao, BIG5_UAO) = {
onigenc_not_support_get_ctype_code_range,
big5_left_adjust_char_head,
big5_is_allowed_reverse_match,
+#ifdef USE_CASE_MAP_API
onigenc_ascii_only_case_map,
+#else
+ NULL,
+#endif
0,
ONIGENC_FLAG_NONE,
};
diff --git a/enc/cp949.c b/enc/cp949.c
index 1600d0cd5b..77e961a7cd 100644
--- a/enc/cp949.c
+++ b/enc/cp949.c
@@ -211,7 +211,11 @@ OnigEncodingDefine(cp949, CP949) = {
onigenc_not_support_get_ctype_code_range,
cp949_left_adjust_char_head,
cp949_is_allowed_reverse_match,
+#ifdef USE_CASE_MAP_API
onigenc_ascii_only_case_map,
+#else
+ NULL,
+#endif
0,
ONIGENC_FLAG_NONE,
};
diff --git a/enc/depend b/enc/depend
index a458b63887..4bf97dc880 100644
--- a/enc/depend
+++ b/enc/depend
@@ -157,15 +157,15 @@ clean:
% end
% unless inplace
$(Q)$(RM) enc/unicode/*/casefold.h enc/unicode/*/name2ctype.h
- $(Q)$(RM) enc/jis/props.h
- -$(Q)$(RMDIR) enc/unicode<%=ignore_error%>
+ $(Q)$(RM) enc/trans/newline.c enc/jis/props.h
+ -$(Q)$(RMDIR) enc/trnas enc/unicode<%=ignore_error%>
% end
% workdirs.reverse_each do|d|
-$(Q)$(RMDIR) <%=pathrep[d]%><%=ignore_error%>
% end
clean-srcs:
- $(Q)$(RM) <%=pathrep['$(TRANSCSRCS)']%>
+ $(Q)$(RM) <%=pathrep['$(TRANSCSRCS)']%> <%=pathrep['$(BUILTIN_TRANS_CSRCS)']%>
-$(Q)$(RMDIR) <%=pathrep['enc/trans']%><%=ignore_error%>
$(Q)$(RM) enc/unicode/*/casefold.h enc/unicode/*/name2ctype.h
$(Q)$(RM) enc/jis/props.h
diff --git a/enc/emacs_mule.c b/enc/emacs_mule.c
index f92eb183cf..abd986a187 100644
--- a/enc/emacs_mule.c
+++ b/enc/emacs_mule.c
@@ -334,7 +334,11 @@ OnigEncodingDefine(emacs_mule, Emacs_Mule) = {
onigenc_not_support_get_ctype_code_range,
left_adjust_char_head,
onigenc_always_true_is_allowed_reverse_match,
+#ifdef USE_CASE_MAP_API
onigenc_ascii_only_case_map,
+#else
+ NULL,
+#endif
0,
ONIGENC_FLAG_NONE,
};
diff --git a/enc/euc_jp.c b/enc/euc_jp.c
index d283bf4ebb..678d011668 100644
--- a/enc/euc_jp.c
+++ b/enc/euc_jp.c
@@ -576,7 +576,11 @@ OnigEncodingDefine(euc_jp, EUC_JP) = {
get_ctype_code_range,
left_adjust_char_head,
is_allowed_reverse_match,
+#ifdef USE_CASE_MAP_API
onigenc_ascii_only_case_map,
+#else
+ NULL,
+#endif
0,
ONIGENC_FLAG_NONE,
};
diff --git a/enc/euc_kr.c b/enc/euc_kr.c
index 21d6ab4e1c..4079a0ece0 100644
--- a/enc/euc_kr.c
+++ b/enc/euc_kr.c
@@ -188,7 +188,11 @@ OnigEncodingDefine(euc_kr, EUC_KR) = {
onigenc_not_support_get_ctype_code_range,
euckr_left_adjust_char_head,
euckr_is_allowed_reverse_match,
+#ifdef USE_CASE_MAP_API
onigenc_ascii_only_case_map,
+#else
+ NULL,
+#endif
0,
ONIGENC_FLAG_NONE,
};
@@ -213,7 +217,11 @@ OnigEncodingDefine(euc_cn, EUC_CN) = {
onigenc_not_support_get_ctype_code_range,
euckr_left_adjust_char_head,
euckr_is_allowed_reverse_match,
+#ifdef USE_CASE_MAP_API
onigenc_ascii_only_case_map,
+#else
+ NULL,
+#endif
0,
ONIGENC_FLAG_NONE,
};
diff --git a/enc/euc_tw.c b/enc/euc_tw.c
index 1c5659cb1d..722e29a9da 100644
--- a/enc/euc_tw.c
+++ b/enc/euc_tw.c
@@ -221,7 +221,11 @@ OnigEncodingDefine(euc_tw, EUC_TW) = {
onigenc_not_support_get_ctype_code_range,
euctw_left_adjust_char_head,
euctw_is_allowed_reverse_match,
+#ifdef USE_CASE_MAP_API
onigenc_ascii_only_case_map,
+#else
+ NULL,
+#endif
0,
ONIGENC_FLAG_NONE,
};
diff --git a/enc/gb18030.c b/enc/gb18030.c
index 63d2e633ec..316737db11 100644
--- a/enc/gb18030.c
+++ b/enc/gb18030.c
@@ -597,7 +597,11 @@ OnigEncodingDefine(gb18030, GB18030) = {
onigenc_not_support_get_ctype_code_range,
gb18030_left_adjust_char_head,
gb18030_is_allowed_reverse_match,
+#ifdef USE_CASE_MAP_API
onigenc_ascii_only_case_map,
+#else
+ NULL,
+#endif
0,
ONIGENC_FLAG_NONE,
};
diff --git a/enc/gbk.c b/enc/gbk.c
index 31032553bf..3df4e4b6d6 100644
--- a/enc/gbk.c
+++ b/enc/gbk.c
@@ -211,7 +211,11 @@ OnigEncodingDefine(gbk, GBK) = {
onigenc_not_support_get_ctype_code_range,
gbk_left_adjust_char_head,
gbk_is_allowed_reverse_match,
+#ifdef USE_CASE_MAP_API
onigenc_ascii_only_case_map,
+#else
+ NULL,
+#endif
0,
ONIGENC_FLAG_NONE,
};
diff --git a/enc/iso_8859_1.c b/enc/iso_8859_1.c
index 7af0888c3e..78ea1fba60 100644
--- a/enc/iso_8859_1.c
+++ b/enc/iso_8859_1.c
@@ -255,6 +255,7 @@ is_code_ctype(OnigCodePoint code, unsigned int ctype, OnigEncoding enc ARG_UNUSE
return FALSE;
}
+#ifdef USE_CASE_MAP_API
static int
case_map(OnigCaseFoldType* flagP, const OnigUChar** pp,
const OnigUChar* end, OnigUChar* to, OnigUChar* to_end,
@@ -297,6 +298,7 @@ case_map(OnigCaseFoldType* flagP, const OnigUChar** pp,
*flagP = flags;
return (int )(to - to_start);
}
+#endif
OnigEncodingDefine(iso_8859_1, ISO_8859_1) = {
onigenc_single_byte_mbc_enc_len,
@@ -315,7 +317,11 @@ OnigEncodingDefine(iso_8859_1, ISO_8859_1) = {
onigenc_not_support_get_ctype_code_range,
onigenc_single_byte_left_adjust_char_head,
onigenc_always_true_is_allowed_reverse_match,
+#ifdef USE_CASE_MAP_API
case_map,
+#else
+ NULL,
+#endif
0,
ONIGENC_FLAG_NONE,
};
diff --git a/enc/iso_8859_10.c b/enc/iso_8859_10.c
index cae4be2db0..bf1c884cb2 100644
--- a/enc/iso_8859_10.c
+++ b/enc/iso_8859_10.c
@@ -224,6 +224,7 @@ get_case_fold_codes_by_str(OnigCaseFoldType flag,
flag, p, end, items);
}
+#ifdef USE_CASE_MAP_API
static int
case_map(OnigCaseFoldType* flagP, const OnigUChar** pp,
const OnigUChar* end, OnigUChar* to, OnigUChar* to_end,
@@ -269,6 +270,7 @@ case_map(OnigCaseFoldType* flagP, const OnigUChar** pp,
*flagP = flags;
return (int )(to - to_start);
}
+#endif
OnigEncodingDefine(iso_8859_10, ISO_8859_10) = {
onigenc_single_byte_mbc_enc_len,
@@ -287,7 +289,11 @@ OnigEncodingDefine(iso_8859_10, ISO_8859_10) = {
onigenc_not_support_get_ctype_code_range,
onigenc_single_byte_left_adjust_char_head,
onigenc_always_true_is_allowed_reverse_match,
+#ifdef USE_CASE_MAP_API
case_map,
+#else
+ NULL,
+#endif
0,
ONIGENC_FLAG_NONE,
};
diff --git a/enc/iso_8859_11.c b/enc/iso_8859_11.c
index b9c6119fd9..403ae6499e 100644
--- a/enc/iso_8859_11.c
+++ b/enc/iso_8859_11.c
@@ -93,7 +93,11 @@ OnigEncodingDefine(iso_8859_11, ISO_8859_11) = {
onigenc_not_support_get_ctype_code_range,
onigenc_single_byte_left_adjust_char_head,
onigenc_always_true_is_allowed_reverse_match,
+#ifdef USE_CASE_MAP_API
onigenc_single_byte_ascii_only_case_map,
+#else
+ NULL,
+#endif
0,
ONIGENC_FLAG_NONE,
};
diff --git a/enc/iso_8859_13.c b/enc/iso_8859_13.c
index fe1ddd7065..8c6e758b80 100644
--- a/enc/iso_8859_13.c
+++ b/enc/iso_8859_13.c
@@ -217,6 +217,7 @@ get_case_fold_codes_by_str(OnigCaseFoldType flag,
flag, p, end, items);
}
+#ifdef USE_CASE_MAP_API
static int
case_map(OnigCaseFoldType* flagP, const OnigUChar** pp,
const OnigUChar* end, OnigUChar* to, OnigUChar* to_end,
@@ -264,6 +265,7 @@ case_map(OnigCaseFoldType* flagP, const OnigUChar** pp,
*flagP = flags;
return (int )(to - to_start);
}
+#endif
OnigEncodingDefine(iso_8859_13, ISO_8859_13) = {
onigenc_single_byte_mbc_enc_len,
@@ -282,7 +284,11 @@ OnigEncodingDefine(iso_8859_13, ISO_8859_13) = {
onigenc_not_support_get_ctype_code_range,
onigenc_single_byte_left_adjust_char_head,
onigenc_always_true_is_allowed_reverse_match,
+#ifdef USE_CASE_MAP_API
case_map,
+#else
+ NULL,
+#endif
0,
ONIGENC_FLAG_NONE,
};
diff --git a/enc/iso_8859_14.c b/enc/iso_8859_14.c
index 647514a016..21dffea76f 100644
--- a/enc/iso_8859_14.c
+++ b/enc/iso_8859_14.c
@@ -226,6 +226,7 @@ get_case_fold_codes_by_str(OnigCaseFoldType flag,
flag, p, end, items);
}
+#ifdef USE_CASE_MAP_API
static int
case_map(OnigCaseFoldType* flagP, const OnigUChar** pp,
const OnigUChar* end, OnigUChar* to, OnigUChar* to_end,
@@ -280,6 +281,7 @@ case_map(OnigCaseFoldType* flagP, const OnigUChar** pp,
*flagP = flags;
return (int )(to - to_start);
}
+#endif
OnigEncodingDefine(iso_8859_14, ISO_8859_14) = {
onigenc_single_byte_mbc_enc_len,
@@ -298,7 +300,11 @@ OnigEncodingDefine(iso_8859_14, ISO_8859_14) = {
onigenc_not_support_get_ctype_code_range,
onigenc_single_byte_left_adjust_char_head,
onigenc_always_true_is_allowed_reverse_match,
+#ifdef USE_CASE_MAP_API
case_map,
+#else
+ NULL,
+#endif
0,
ONIGENC_FLAG_NONE,
};
diff --git a/enc/iso_8859_15.c b/enc/iso_8859_15.c
index 377a3afc7b..dd6c29a643 100644
--- a/enc/iso_8859_15.c
+++ b/enc/iso_8859_15.c
@@ -220,6 +220,7 @@ get_case_fold_codes_by_str(OnigCaseFoldType flag,
flag, p, end, items);
}
+#ifdef USE_CASE_MAP_API
static int
case_map(OnigCaseFoldType* flagP, const OnigUChar** pp,
const OnigUChar* end, OnigUChar* to, OnigUChar* to_end,
@@ -271,6 +272,7 @@ case_map(OnigCaseFoldType* flagP, const OnigUChar** pp,
*flagP = flags;
return (int )(to - to_start);
}
+#endif
OnigEncodingDefine(iso_8859_15, ISO_8859_15) = {
onigenc_single_byte_mbc_enc_len,
@@ -289,7 +291,11 @@ OnigEncodingDefine(iso_8859_15, ISO_8859_15) = {
onigenc_not_support_get_ctype_code_range,
onigenc_single_byte_left_adjust_char_head,
onigenc_always_true_is_allowed_reverse_match,
+#ifdef USE_CASE_MAP_API
case_map,
+#else
+ NULL,
+#endif
0,
ONIGENC_FLAG_NONE,
};
diff --git a/enc/iso_8859_16.c b/enc/iso_8859_16.c
index 135630eb73..aa7ce99fba 100644
--- a/enc/iso_8859_16.c
+++ b/enc/iso_8859_16.c
@@ -222,6 +222,7 @@ get_case_fold_codes_by_str(OnigCaseFoldType flag,
flag, p, end, items);
}
+#ifdef USE_CASE_MAP_API
static int
case_map(OnigCaseFoldType* flagP, const OnigUChar** pp,
const OnigUChar* end, OnigUChar* to, OnigUChar* to_end,
@@ -275,6 +276,7 @@ case_map(OnigCaseFoldType* flagP, const OnigUChar** pp,
*flagP = flags;
return (int )(to - to_start);
}
+#endif
OnigEncodingDefine(iso_8859_16, ISO_8859_16) = {
onigenc_single_byte_mbc_enc_len,
@@ -293,7 +295,11 @@ OnigEncodingDefine(iso_8859_16, ISO_8859_16) = {
onigenc_not_support_get_ctype_code_range,
onigenc_single_byte_left_adjust_char_head,
onigenc_always_true_is_allowed_reverse_match,
+#ifdef USE_CASE_MAP_API
case_map,
+#else
+ NULL,
+#endif
0,
ONIGENC_FLAG_NONE,
};
diff --git a/enc/iso_8859_2.c b/enc/iso_8859_2.c
index 3a05c6320d..859073fd14 100644
--- a/enc/iso_8859_2.c
+++ b/enc/iso_8859_2.c
@@ -220,6 +220,7 @@ is_code_ctype(OnigCodePoint code, unsigned int ctype, OnigEncoding enc ARG_UNUSE
return FALSE;
}
+#ifdef USE_CASE_MAP_API
static int
case_map(OnigCaseFoldType* flagP, const OnigUChar** pp,
const OnigUChar* end, OnigUChar* to, OnigUChar* to_end,
@@ -266,6 +267,7 @@ case_map(OnigCaseFoldType* flagP, const OnigUChar** pp,
*flagP = flags;
return (int )(to - to_start);
}
+#endif
OnigEncodingDefine(iso_8859_2, ISO_8859_2) = {
onigenc_single_byte_mbc_enc_len,
@@ -284,7 +286,11 @@ OnigEncodingDefine(iso_8859_2, ISO_8859_2) = {
onigenc_not_support_get_ctype_code_range,
onigenc_single_byte_left_adjust_char_head,
onigenc_always_true_is_allowed_reverse_match,
+#ifdef USE_CASE_MAP_API
case_map,
+#else
+ NULL,
+#endif
0,
ONIGENC_FLAG_NONE,
};
diff --git a/enc/iso_8859_3.c b/enc/iso_8859_3.c
index 2a343eac63..d8199d5125 100644
--- a/enc/iso_8859_3.c
+++ b/enc/iso_8859_3.c
@@ -220,6 +220,7 @@ get_case_fold_codes_by_str(OnigCaseFoldType flag,
flag, p, end, items);
}
+#ifdef USE_CASE_MAP_API
#define DOTLESS_i (0xB9)
#define I_WITH_DOT_ABOVE (0xA9)
static int
@@ -276,6 +277,7 @@ case_map(OnigCaseFoldType* flagP, const OnigUChar** pp,
*flagP = flags;
return (int )(to - to_start);
}
+#endif
OnigEncodingDefine(iso_8859_3, ISO_8859_3) = {
onigenc_single_byte_mbc_enc_len,
@@ -294,7 +296,11 @@ OnigEncodingDefine(iso_8859_3, ISO_8859_3) = {
onigenc_not_support_get_ctype_code_range,
onigenc_single_byte_left_adjust_char_head,
onigenc_always_true_is_allowed_reverse_match,
+#ifdef USE_CASE_MAP_API
case_map,
+#else
+ NULL,
+#endif
0,
ONIGENC_FLAG_NONE,
};
diff --git a/enc/iso_8859_4.c b/enc/iso_8859_4.c
index e2134e8c0b..5f01f01575 100644
--- a/enc/iso_8859_4.c
+++ b/enc/iso_8859_4.c
@@ -223,6 +223,7 @@ get_case_fold_codes_by_str(OnigCaseFoldType flag,
flag, p, end, items);
}
+#ifdef USE_CASE_MAP_API
static int
case_map(OnigCaseFoldType* flagP, const OnigUChar** pp,
const OnigUChar* end, OnigUChar* to, OnigUChar* to_end,
@@ -272,6 +273,7 @@ case_map(OnigCaseFoldType* flagP, const OnigUChar** pp,
*flagP = flags;
return (int )(to - to_start);
}
+#endif
OnigEncodingDefine(iso_8859_4, ISO_8859_4) = {
onigenc_single_byte_mbc_enc_len,
@@ -290,7 +292,11 @@ OnigEncodingDefine(iso_8859_4, ISO_8859_4) = {
onigenc_not_support_get_ctype_code_range,
onigenc_single_byte_left_adjust_char_head,
onigenc_always_true_is_allowed_reverse_match,
+#ifdef USE_CASE_MAP_API
case_map,
+#else
+ NULL,
+#endif
0,
ONIGENC_FLAG_NONE,
};
diff --git a/enc/iso_8859_5.c b/enc/iso_8859_5.c
index 6fafc35823..8223fc0ec7 100644
--- a/enc/iso_8859_5.c
+++ b/enc/iso_8859_5.c
@@ -209,6 +209,7 @@ get_case_fold_codes_by_str(OnigCaseFoldType flag,
flag, p, end, items);
}
+#ifdef USE_CASE_MAP_API
static int
case_map(OnigCaseFoldType* flagP, const OnigUChar** pp,
const OnigUChar* end, OnigUChar* to, OnigUChar* to_end,
@@ -240,6 +241,7 @@ case_map(OnigCaseFoldType* flagP, const OnigUChar** pp,
*flagP = flags;
return (int )(to - to_start);
}
+#endif
OnigEncodingDefine(iso_8859_5, ISO_8859_5) = {
onigenc_single_byte_mbc_enc_len,
@@ -258,7 +260,11 @@ OnigEncodingDefine(iso_8859_5, ISO_8859_5) = {
onigenc_not_support_get_ctype_code_range,
onigenc_single_byte_left_adjust_char_head,
onigenc_always_true_is_allowed_reverse_match,
+#ifdef USE_CASE_MAP_API
case_map,
+#else
+ NULL,
+#endif
0,
ONIGENC_FLAG_NONE,
};
diff --git a/enc/iso_8859_6.c b/enc/iso_8859_6.c
index cdb74054d1..78543ea307 100644
--- a/enc/iso_8859_6.c
+++ b/enc/iso_8859_6.c
@@ -93,7 +93,11 @@ OnigEncodingDefine(iso_8859_6, ISO_8859_6) = {
onigenc_not_support_get_ctype_code_range,
onigenc_single_byte_left_adjust_char_head,
onigenc_always_true_is_allowed_reverse_match,
+#ifdef USE_CASE_MAP_API
onigenc_single_byte_ascii_only_case_map,
+#else
+ NULL,
+#endif
0,
ONIGENC_FLAG_NONE,
};
diff --git a/enc/iso_8859_7.c b/enc/iso_8859_7.c
index ac973f74ba..e84f5c3460 100644
--- a/enc/iso_8859_7.c
+++ b/enc/iso_8859_7.c
@@ -205,6 +205,7 @@ get_case_fold_codes_by_str(OnigCaseFoldType flag,
flag, p, end, items);
}
+#ifdef USE_CASE_MAP_API
static int
case_map(OnigCaseFoldType* flagP, const OnigUChar** pp,
const OnigUChar* end, OnigUChar* to, OnigUChar* to_end,
@@ -259,6 +260,7 @@ case_map(OnigCaseFoldType* flagP, const OnigUChar** pp,
*flagP = flags;
return (int )(to - to_start);
}
+#endif
OnigEncodingDefine(iso_8859_7, ISO_8859_7) = {
onigenc_single_byte_mbc_enc_len,
@@ -277,7 +279,11 @@ OnigEncodingDefine(iso_8859_7, ISO_8859_7) = {
onigenc_not_support_get_ctype_code_range,
onigenc_single_byte_left_adjust_char_head,
onigenc_always_true_is_allowed_reverse_match,
+#ifdef USE_CASE_MAP_API
case_map,
+#else
+ NULL,
+#endif
0,
ONIGENC_FLAG_NONE,
};
diff --git a/enc/iso_8859_8.c b/enc/iso_8859_8.c
index e256855f21..b757a283de 100644
--- a/enc/iso_8859_8.c
+++ b/enc/iso_8859_8.c
@@ -93,7 +93,11 @@ OnigEncodingDefine(iso_8859_8, ISO_8859_8) = {
onigenc_not_support_get_ctype_code_range,
onigenc_single_byte_left_adjust_char_head,
onigenc_always_true_is_allowed_reverse_match,
+#ifdef USE_CASE_MAP_API
onigenc_single_byte_ascii_only_case_map,
+#else
+ NULL,
+#endif
0,
ONIGENC_FLAG_NONE,
};
diff --git a/enc/iso_8859_9.c b/enc/iso_8859_9.c
index 004eec310f..f15953963b 100644
--- a/enc/iso_8859_9.c
+++ b/enc/iso_8859_9.c
@@ -213,6 +213,7 @@ get_case_fold_codes_by_str(OnigCaseFoldType flag,
flag, p, end, items);
}
+#ifdef USE_CASE_MAP_API
#define DOTLESS_i (0xFD)
#define I_WITH_DOT_ABOVE (0xDD)
static int
@@ -265,6 +266,7 @@ case_map(OnigCaseFoldType* flagP, const OnigUChar** pp,
*flagP = flags;
return (int )(to - to_start);
}
+#endif
OnigEncodingDefine(iso_8859_9, ISO_8859_9) = {
onigenc_single_byte_mbc_enc_len,
@@ -283,7 +285,11 @@ OnigEncodingDefine(iso_8859_9, ISO_8859_9) = {
onigenc_not_support_get_ctype_code_range,
onigenc_single_byte_left_adjust_char_head,
onigenc_always_true_is_allowed_reverse_match,
+#ifdef USE_CASE_MAP_API
case_map,
+#else
+ NULL,
+#endif
0,
ONIGENC_FLAG_NONE,
};
diff --git a/enc/koi8_r.c b/enc/koi8_r.c
index a520975774..39f2482465 100644
--- a/enc/koi8_r.c
+++ b/enc/koi8_r.c
@@ -214,7 +214,11 @@ OnigEncodingDefine(koi8_r, KOI8_R) = {
onigenc_not_support_get_ctype_code_range,
onigenc_single_byte_left_adjust_char_head,
onigenc_always_true_is_allowed_reverse_match,
+#ifdef USE_CASE_MAP_API
onigenc_single_byte_ascii_only_case_map,
+#else
+ NULL,
+#endif
0,
ONIGENC_FLAG_NONE,
};
diff --git a/enc/koi8_u.c b/enc/koi8_u.c
index 50bb78bd04..8cd890dd16 100644
--- a/enc/koi8_u.c
+++ b/enc/koi8_u.c
@@ -218,7 +218,11 @@ OnigEncodingDefine(koi8_u, KOI8_U) = {
onigenc_not_support_get_ctype_code_range,
onigenc_single_byte_left_adjust_char_head,
onigenc_always_true_is_allowed_reverse_match,
+#ifdef USE_CASE_MAP_API
onigenc_single_byte_ascii_only_case_map,
+#else
+ NULL,
+#endif
0,
ONIGENC_FLAG_NONE,
};
diff --git a/enc/make_encmake.rb b/enc/make_encmake.rb
index 96d1944bcb..e5ed4eb4b5 100755
--- a/enc/make_encmake.rb
+++ b/enc/make_encmake.rb
@@ -1,8 +1,11 @@
#! ./miniruby
dir = File.expand_path("../..", __FILE__)
-$:.unshift(dir)
-$:.unshift(".")
+# The source lib directory provides the standard library for miniruby.
+# Don't add it when running with baseruby to avoid loading both
+# baseruby's cgi/escape.so and source cgi/escape.rb via erb.
+$:.unshift("#{dir}/lib") unless defined?(CROSS_COMPILING)
+$:.unshift(Dir.pwd, "#{dir}/tool/lib")
if $".grep(/mkmf/).empty?
$" << "mkmf.rb"
load File.expand_path("lib/mkmf.rb", dir)
@@ -147,6 +150,6 @@ if MODULE_TYPE == :static
Dir.mkdir 'enc'
rescue Errno::EEXIST
end
- require 'tool/lib/output'
+ require 'output'
Output.new(path: "enc/encinit.c", ifchange: true).write(tmp)
end
diff --git a/enc/shift_jis.c b/enc/shift_jis.c
index f1355d2d95..48f648868a 100644
--- a/enc/shift_jis.c
+++ b/enc/shift_jis.c
@@ -47,7 +47,11 @@ OnigEncodingDefine(shift_jis, Shift_JIS) = {
get_ctype_code_range,
left_adjust_char_head,
is_allowed_reverse_match,
+#ifdef USE_CASE_MAP_API
onigenc_ascii_only_case_map,
+#else
+ NULL,
+#endif
0,
ONIGENC_FLAG_NONE,
};
diff --git a/enc/unicode.c b/enc/unicode.c
index cbfc6cdf58..5bc806863e 100644
--- a/enc/unicode.c
+++ b/enc/unicode.c
@@ -655,6 +655,7 @@ onigenc_unicode_get_case_fold_codes_by_str(OnigEncoding enc,
return n;
}
+#ifdef USE_CASE_MAP_API
/* length in bytes for three characters in UTF-32; e.g. needed for ffi (U+FB03) */
#define CASE_MAPPING_SLACK 12
#define MODIFIED (flags |= ONIGENC_CASE_MODIFIED)
@@ -682,15 +683,13 @@ onigenc_unicode_case_map(OnigCaseFoldType* flagP,
*pp += codepoint_length;
if (code <= 'z') { /* ASCII comes first */
- if (code >= 'a' && code <= 'z') {
+ if (code >= 'a' /*&& code <= 'z'*/) {
if (flags & ONIGENC_CASE_UPCASE) {
MODIFIED;
if (flags & ONIGENC_CASE_FOLD_TURKISH_AZERI && code == 'i')
code = I_WITH_DOT_ABOVE;
- else {
- code -= 'a';
- code += 'A';
- }
+ else
+ code -= 'a' - 'A';
}
}
else if (code >= 'A' && code <= 'Z') {
@@ -800,6 +799,7 @@ SpecialsCopy:
*flagP = flags;
return (int )(to - to_start);
}
+#endif
const char onigenc_unicode_version_string[] =
#ifdef ONIG_UNICODE_VERSION_STRING
diff --git a/enc/unicode/16.0.0/casefold.h b/enc/unicode/16.0.0/casefold.h
deleted file mode 100644
index f14c0777d7..0000000000
--- a/enc/unicode/16.0.0/casefold.h
+++ /dev/null
@@ -1,7804 +0,0 @@
-/* DO NOT EDIT THIS FILE. */
-/* Generated by enc-case-folding.rb */
-
-#if defined ONIG_UNICODE_VERSION_STRING && !( \
- ONIG_UNICODE_VERSION_MAJOR == 16 && \
- ONIG_UNICODE_VERSION_MINOR == 0 && \
- ONIG_UNICODE_VERSION_TEENY == 0 && \
- 1)
-# error ONIG_UNICODE_VERSION_STRING mismatch
-#endif
-#define ONIG_UNICODE_VERSION_STRING "16.0.0"
-#define ONIG_UNICODE_VERSION_MAJOR 16
-#define ONIG_UNICODE_VERSION_MINOR 0
-#define ONIG_UNICODE_VERSION_TEENY 0
-
-static const CaseFold_11_Type CaseFold_11_Table[] = {
-#define CaseFold (*(CaseFold_11_Type (*)[1555])(CaseFold_11_Table+0))
- {0x0041, {1|F|D, {0x0061}}},
- {0x0042, {1|F|D, {0x0062}}},
- {0x0043, {1|F|D, {0x0063}}},
- {0x0044, {1|F|D, {0x0064}}},
- {0x0045, {1|F|D, {0x0065}}},
- {0x0046, {1|F|D, {0x0066}}},
- {0x0047, {1|F|D, {0x0067}}},
- {0x0048, {1|F|D, {0x0068}}},
- {0x004a, {1|F|D, {0x006a}}},
- {0x004b, {1|F|D, {0x006b}}},
- {0x004c, {1|F|D, {0x006c}}},
- {0x004d, {1|F|D, {0x006d}}},
- {0x004e, {1|F|D, {0x006e}}},
- {0x004f, {1|F|D, {0x006f}}},
- {0x0050, {1|F|D, {0x0070}}},
- {0x0051, {1|F|D, {0x0071}}},
- {0x0052, {1|F|D, {0x0072}}},
- {0x0053, {1|F|D, {0x0073}}},
- {0x0054, {1|F|D, {0x0074}}},
- {0x0055, {1|F|D, {0x0075}}},
- {0x0056, {1|F|D, {0x0076}}},
- {0x0057, {1|F|D, {0x0077}}},
- {0x0058, {1|F|D, {0x0078}}},
- {0x0059, {1|F|D, {0x0079}}},
- {0x005a, {1|F|D, {0x007a}}},
- {0x00b5, {1|F|SU|I(0), {0x03bc}}},
- {0x00c0, {1|F|D, {0x00e0}}},
- {0x00c1, {1|F|D, {0x00e1}}},
- {0x00c2, {1|F|D, {0x00e2}}},
- {0x00c3, {1|F|D, {0x00e3}}},
- {0x00c4, {1|F|D, {0x00e4}}},
- {0x00c5, {1|F|D, {0x00e5}}},
- {0x00c6, {1|F|D, {0x00e6}}},
- {0x00c7, {1|F|D, {0x00e7}}},
- {0x00c8, {1|F|D, {0x00e8}}},
- {0x00c9, {1|F|D, {0x00e9}}},
- {0x00ca, {1|F|D, {0x00ea}}},
- {0x00cb, {1|F|D, {0x00eb}}},
- {0x00cc, {1|F|D, {0x00ec}}},
- {0x00cd, {1|F|D, {0x00ed}}},
- {0x00ce, {1|F|D, {0x00ee}}},
- {0x00cf, {1|F|D, {0x00ef}}},
- {0x00d0, {1|F|D, {0x00f0}}},
- {0x00d1, {1|F|D, {0x00f1}}},
- {0x00d2, {1|F|D, {0x00f2}}},
- {0x00d3, {1|F|D, {0x00f3}}},
- {0x00d4, {1|F|D, {0x00f4}}},
- {0x00d5, {1|F|D, {0x00f5}}},
- {0x00d6, {1|F|D, {0x00f6}}},
- {0x00d8, {1|F|D, {0x00f8}}},
- {0x00d9, {1|F|D, {0x00f9}}},
- {0x00da, {1|F|D, {0x00fa}}},
- {0x00db, {1|F|D, {0x00fb}}},
- {0x00dc, {1|F|D, {0x00fc}}},
- {0x00dd, {1|F|D, {0x00fd}}},
- {0x00de, {1|F|D, {0x00fe}}},
- {0x00df, {2|F|ST|SU|I(1), {0x0073, 0x0073}}},
- {0x0100, {1|F|D, {0x0101}}},
- {0x0102, {1|F|D, {0x0103}}},
- {0x0104, {1|F|D, {0x0105}}},
- {0x0106, {1|F|D, {0x0107}}},
- {0x0108, {1|F|D, {0x0109}}},
- {0x010a, {1|F|D, {0x010b}}},
- {0x010c, {1|F|D, {0x010d}}},
- {0x010e, {1|F|D, {0x010f}}},
- {0x0110, {1|F|D, {0x0111}}},
- {0x0112, {1|F|D, {0x0113}}},
- {0x0114, {1|F|D, {0x0115}}},
- {0x0116, {1|F|D, {0x0117}}},
- {0x0118, {1|F|D, {0x0119}}},
- {0x011a, {1|F|D, {0x011b}}},
- {0x011c, {1|F|D, {0x011d}}},
- {0x011e, {1|F|D, {0x011f}}},
- {0x0120, {1|F|D, {0x0121}}},
- {0x0122, {1|F|D, {0x0123}}},
- {0x0124, {1|F|D, {0x0125}}},
- {0x0126, {1|F|D, {0x0127}}},
- {0x0128, {1|F|D, {0x0129}}},
- {0x012a, {1|F|D, {0x012b}}},
- {0x012c, {1|F|D, {0x012d}}},
- {0x012e, {1|F|D, {0x012f}}},
- {0x0132, {1|F|D, {0x0133}}},
- {0x0134, {1|F|D, {0x0135}}},
- {0x0136, {1|F|D, {0x0137}}},
- {0x0139, {1|F|D, {0x013a}}},
- {0x013b, {1|F|D, {0x013c}}},
- {0x013d, {1|F|D, {0x013e}}},
- {0x013f, {1|F|D, {0x0140}}},
- {0x0141, {1|F|D, {0x0142}}},
- {0x0143, {1|F|D, {0x0144}}},
- {0x0145, {1|F|D, {0x0146}}},
- {0x0147, {1|F|D, {0x0148}}},
- {0x0149, {2|F|SU|I(5), {0x02bc, 0x006e}}},
- {0x014a, {1|F|D, {0x014b}}},
- {0x014c, {1|F|D, {0x014d}}},
- {0x014e, {1|F|D, {0x014f}}},
- {0x0150, {1|F|D, {0x0151}}},
- {0x0152, {1|F|D, {0x0153}}},
- {0x0154, {1|F|D, {0x0155}}},
- {0x0156, {1|F|D, {0x0157}}},
- {0x0158, {1|F|D, {0x0159}}},
- {0x015a, {1|F|D, {0x015b}}},
- {0x015c, {1|F|D, {0x015d}}},
- {0x015e, {1|F|D, {0x015f}}},
- {0x0160, {1|F|D, {0x0161}}},
- {0x0162, {1|F|D, {0x0163}}},
- {0x0164, {1|F|D, {0x0165}}},
- {0x0166, {1|F|D, {0x0167}}},
- {0x0168, {1|F|D, {0x0169}}},
- {0x016a, {1|F|D, {0x016b}}},
- {0x016c, {1|F|D, {0x016d}}},
- {0x016e, {1|F|D, {0x016f}}},
- {0x0170, {1|F|D, {0x0171}}},
- {0x0172, {1|F|D, {0x0173}}},
- {0x0174, {1|F|D, {0x0175}}},
- {0x0176, {1|F|D, {0x0177}}},
- {0x0178, {1|F|D, {0x00ff}}},
- {0x0179, {1|F|D, {0x017a}}},
- {0x017b, {1|F|D, {0x017c}}},
- {0x017d, {1|F|D, {0x017e}}},
- {0x017f, {1|F|SU|I(7), {0x0073}}},
- {0x0181, {1|F|D, {0x0253}}},
- {0x0182, {1|F|D, {0x0183}}},
- {0x0184, {1|F|D, {0x0185}}},
- {0x0186, {1|F|D, {0x0254}}},
- {0x0187, {1|F|D, {0x0188}}},
- {0x0189, {1|F|D, {0x0256}}},
- {0x018a, {1|F|D, {0x0257}}},
- {0x018b, {1|F|D, {0x018c}}},
- {0x018e, {1|F|D, {0x01dd}}},
- {0x018f, {1|F|D, {0x0259}}},
- {0x0190, {1|F|D, {0x025b}}},
- {0x0191, {1|F|D, {0x0192}}},
- {0x0193, {1|F|D, {0x0260}}},
- {0x0194, {1|F|D, {0x0263}}},
- {0x0196, {1|F|D, {0x0269}}},
- {0x0197, {1|F|D, {0x0268}}},
- {0x0198, {1|F|D, {0x0199}}},
- {0x019c, {1|F|D, {0x026f}}},
- {0x019d, {1|F|D, {0x0272}}},
- {0x019f, {1|F|D, {0x0275}}},
- {0x01a0, {1|F|D, {0x01a1}}},
- {0x01a2, {1|F|D, {0x01a3}}},
- {0x01a4, {1|F|D, {0x01a5}}},
- {0x01a6, {1|F|D, {0x0280}}},
- {0x01a7, {1|F|D, {0x01a8}}},
- {0x01a9, {1|F|D, {0x0283}}},
- {0x01ac, {1|F|D, {0x01ad}}},
- {0x01ae, {1|F|D, {0x0288}}},
- {0x01af, {1|F|D, {0x01b0}}},
- {0x01b1, {1|F|D, {0x028a}}},
- {0x01b2, {1|F|D, {0x028b}}},
- {0x01b3, {1|F|D, {0x01b4}}},
- {0x01b5, {1|F|D, {0x01b6}}},
- {0x01b7, {1|F|D, {0x0292}}},
- {0x01b8, {1|F|D, {0x01b9}}},
- {0x01bc, {1|F|D, {0x01bd}}},
- {0x01c4, {1|F|D|ST|I(8), {0x01c6}}},
- {0x01c5, {1|F|D|IT|SU|I(9), {0x01c6}}},
- {0x01c7, {1|F|D|ST|I(12), {0x01c9}}},
- {0x01c8, {1|F|D|IT|SU|I(13), {0x01c9}}},
- {0x01ca, {1|F|D|ST|I(16), {0x01cc}}},
- {0x01cb, {1|F|D|IT|SU|I(17), {0x01cc}}},
- {0x01cd, {1|F|D, {0x01ce}}},
- {0x01cf, {1|F|D, {0x01d0}}},
- {0x01d1, {1|F|D, {0x01d2}}},
- {0x01d3, {1|F|D, {0x01d4}}},
- {0x01d5, {1|F|D, {0x01d6}}},
- {0x01d7, {1|F|D, {0x01d8}}},
- {0x01d9, {1|F|D, {0x01da}}},
- {0x01db, {1|F|D, {0x01dc}}},
- {0x01de, {1|F|D, {0x01df}}},
- {0x01e0, {1|F|D, {0x01e1}}},
- {0x01e2, {1|F|D, {0x01e3}}},
- {0x01e4, {1|F|D, {0x01e5}}},
- {0x01e6, {1|F|D, {0x01e7}}},
- {0x01e8, {1|F|D, {0x01e9}}},
- {0x01ea, {1|F|D, {0x01eb}}},
- {0x01ec, {1|F|D, {0x01ed}}},
- {0x01ee, {1|F|D, {0x01ef}}},
- {0x01f0, {2|F|SU|I(20), {0x006a, 0x030c}}},
- {0x01f1, {1|F|D|ST|I(22), {0x01f3}}},
- {0x01f2, {1|F|D|IT|SU|I(23), {0x01f3}}},
- {0x01f4, {1|F|D, {0x01f5}}},
- {0x01f6, {1|F|D, {0x0195}}},
- {0x01f7, {1|F|D, {0x01bf}}},
- {0x01f8, {1|F|D, {0x01f9}}},
- {0x01fa, {1|F|D, {0x01fb}}},
- {0x01fc, {1|F|D, {0x01fd}}},
- {0x01fe, {1|F|D, {0x01ff}}},
- {0x0200, {1|F|D, {0x0201}}},
- {0x0202, {1|F|D, {0x0203}}},
- {0x0204, {1|F|D, {0x0205}}},
- {0x0206, {1|F|D, {0x0207}}},
- {0x0208, {1|F|D, {0x0209}}},
- {0x020a, {1|F|D, {0x020b}}},
- {0x020c, {1|F|D, {0x020d}}},
- {0x020e, {1|F|D, {0x020f}}},
- {0x0210, {1|F|D, {0x0211}}},
- {0x0212, {1|F|D, {0x0213}}},
- {0x0214, {1|F|D, {0x0215}}},
- {0x0216, {1|F|D, {0x0217}}},
- {0x0218, {1|F|D, {0x0219}}},
- {0x021a, {1|F|D, {0x021b}}},
- {0x021c, {1|F|D, {0x021d}}},
- {0x021e, {1|F|D, {0x021f}}},
- {0x0220, {1|F|D, {0x019e}}},
- {0x0222, {1|F|D, {0x0223}}},
- {0x0224, {1|F|D, {0x0225}}},
- {0x0226, {1|F|D, {0x0227}}},
- {0x0228, {1|F|D, {0x0229}}},
- {0x022a, {1|F|D, {0x022b}}},
- {0x022c, {1|F|D, {0x022d}}},
- {0x022e, {1|F|D, {0x022f}}},
- {0x0230, {1|F|D, {0x0231}}},
- {0x0232, {1|F|D, {0x0233}}},
- {0x023a, {1|F|D, {0x2c65}}},
- {0x023b, {1|F|D, {0x023c}}},
- {0x023d, {1|F|D, {0x019a}}},
- {0x023e, {1|F|D, {0x2c66}}},
- {0x0241, {1|F|D, {0x0242}}},
- {0x0243, {1|F|D, {0x0180}}},
- {0x0244, {1|F|D, {0x0289}}},
- {0x0245, {1|F|D, {0x028c}}},
- {0x0246, {1|F|D, {0x0247}}},
- {0x0248, {1|F|D, {0x0249}}},
- {0x024a, {1|F|D, {0x024b}}},
- {0x024c, {1|F|D, {0x024d}}},
- {0x024e, {1|F|D, {0x024f}}},
- {0x0345, {1|F|SU|I(26), {0x03b9}}},
- {0x0370, {1|F|D, {0x0371}}},
- {0x0372, {1|F|D, {0x0373}}},
- {0x0376, {1|F|D, {0x0377}}},
- {0x037f, {1|F|D, {0x03f3}}},
- {0x0386, {1|F|D, {0x03ac}}},
- {0x0388, {1|F|D, {0x03ad}}},
- {0x0389, {1|F|D, {0x03ae}}},
- {0x038a, {1|F|D, {0x03af}}},
- {0x038c, {1|F|D, {0x03cc}}},
- {0x038e, {1|F|D, {0x03cd}}},
- {0x038f, {1|F|D, {0x03ce}}},
- {0x0390, {3|F|SU|I(27), {0x03b9, 0x0308, 0x0301}}},
- {0x0391, {1|F|D, {0x03b1}}},
- {0x0392, {1|F|D, {0x03b2}}},
- {0x0393, {1|F|D, {0x03b3}}},
- {0x0394, {1|F|D, {0x03b4}}},
- {0x0395, {1|F|D, {0x03b5}}},
- {0x0396, {1|F|D, {0x03b6}}},
- {0x0397, {1|F|D, {0x03b7}}},
- {0x0398, {1|F|D, {0x03b8}}},
- {0x0399, {1|F|D, {0x03b9}}},
- {0x039a, {1|F|D, {0x03ba}}},
- {0x039b, {1|F|D, {0x03bb}}},
- {0x039c, {1|F|D, {0x03bc}}},
- {0x039d, {1|F|D, {0x03bd}}},
- {0x039e, {1|F|D, {0x03be}}},
- {0x039f, {1|F|D, {0x03bf}}},
- {0x03a0, {1|F|D, {0x03c0}}},
- {0x03a1, {1|F|D, {0x03c1}}},
- {0x03a3, {1|F|D, {0x03c3}}},
- {0x03a4, {1|F|D, {0x03c4}}},
- {0x03a5, {1|F|D, {0x03c5}}},
- {0x03a6, {1|F|D, {0x03c6}}},
- {0x03a7, {1|F|D, {0x03c7}}},
- {0x03a8, {1|F|D, {0x03c8}}},
- {0x03a9, {1|F|D, {0x03c9}}},
- {0x03aa, {1|F|D, {0x03ca}}},
- {0x03ab, {1|F|D, {0x03cb}}},
- {0x03b0, {3|F|SU|I(30), {0x03c5, 0x0308, 0x0301}}},
- {0x03c2, {1|F|SU|I(33), {0x03c3}}},
- {0x03cf, {1|F|D, {0x03d7}}},
- {0x03d0, {1|F|SU|I(34), {0x03b2}}},
- {0x03d1, {1|F|SU|I(35), {0x03b8}}},
- {0x03d5, {1|F|SU|I(36), {0x03c6}}},
- {0x03d6, {1|F|SU|I(37), {0x03c0}}},
- {0x03d8, {1|F|D, {0x03d9}}},
- {0x03da, {1|F|D, {0x03db}}},
- {0x03dc, {1|F|D, {0x03dd}}},
- {0x03de, {1|F|D, {0x03df}}},
- {0x03e0, {1|F|D, {0x03e1}}},
- {0x03e2, {1|F|D, {0x03e3}}},
- {0x03e4, {1|F|D, {0x03e5}}},
- {0x03e6, {1|F|D, {0x03e7}}},
- {0x03e8, {1|F|D, {0x03e9}}},
- {0x03ea, {1|F|D, {0x03eb}}},
- {0x03ec, {1|F|D, {0x03ed}}},
- {0x03ee, {1|F|D, {0x03ef}}},
- {0x03f0, {1|F|SU|I(38), {0x03ba}}},
- {0x03f1, {1|F|SU|I(39), {0x03c1}}},
- {0x03f4, {1|F|D, {0x03b8}}},
- {0x03f5, {1|F|SU|I(40), {0x03b5}}},
- {0x03f7, {1|F|D, {0x03f8}}},
- {0x03f9, {1|F|D, {0x03f2}}},
- {0x03fa, {1|F|D, {0x03fb}}},
- {0x03fd, {1|F|D, {0x037b}}},
- {0x03fe, {1|F|D, {0x037c}}},
- {0x03ff, {1|F|D, {0x037d}}},
- {0x0400, {1|F|D, {0x0450}}},
- {0x0401, {1|F|D, {0x0451}}},
- {0x0402, {1|F|D, {0x0452}}},
- {0x0403, {1|F|D, {0x0453}}},
- {0x0404, {1|F|D, {0x0454}}},
- {0x0405, {1|F|D, {0x0455}}},
- {0x0406, {1|F|D, {0x0456}}},
- {0x0407, {1|F|D, {0x0457}}},
- {0x0408, {1|F|D, {0x0458}}},
- {0x0409, {1|F|D, {0x0459}}},
- {0x040a, {1|F|D, {0x045a}}},
- {0x040b, {1|F|D, {0x045b}}},
- {0x040c, {1|F|D, {0x045c}}},
- {0x040d, {1|F|D, {0x045d}}},
- {0x040e, {1|F|D, {0x045e}}},
- {0x040f, {1|F|D, {0x045f}}},
- {0x0410, {1|F|D, {0x0430}}},
- {0x0411, {1|F|D, {0x0431}}},
- {0x0412, {1|F|D, {0x0432}}},
- {0x0413, {1|F|D, {0x0433}}},
- {0x0414, {1|F|D, {0x0434}}},
- {0x0415, {1|F|D, {0x0435}}},
- {0x0416, {1|F|D, {0x0436}}},
- {0x0417, {1|F|D, {0x0437}}},
- {0x0418, {1|F|D, {0x0438}}},
- {0x0419, {1|F|D, {0x0439}}},
- {0x041a, {1|F|D, {0x043a}}},
- {0x041b, {1|F|D, {0x043b}}},
- {0x041c, {1|F|D, {0x043c}}},
- {0x041d, {1|F|D, {0x043d}}},
- {0x041e, {1|F|D, {0x043e}}},
- {0x041f, {1|F|D, {0x043f}}},
- {0x0420, {1|F|D, {0x0440}}},
- {0x0421, {1|F|D, {0x0441}}},
- {0x0422, {1|F|D, {0x0442}}},
- {0x0423, {1|F|D, {0x0443}}},
- {0x0424, {1|F|D, {0x0444}}},
- {0x0425, {1|F|D, {0x0445}}},
- {0x0426, {1|F|D, {0x0446}}},
- {0x0427, {1|F|D, {0x0447}}},
- {0x0428, {1|F|D, {0x0448}}},
- {0x0429, {1|F|D, {0x0449}}},
- {0x042a, {1|F|D, {0x044a}}},
- {0x042b, {1|F|D, {0x044b}}},
- {0x042c, {1|F|D, {0x044c}}},
- {0x042d, {1|F|D, {0x044d}}},
- {0x042e, {1|F|D, {0x044e}}},
- {0x042f, {1|F|D, {0x044f}}},
- {0x0460, {1|F|D, {0x0461}}},
- {0x0462, {1|F|D, {0x0463}}},
- {0x0464, {1|F|D, {0x0465}}},
- {0x0466, {1|F|D, {0x0467}}},
- {0x0468, {1|F|D, {0x0469}}},
- {0x046a, {1|F|D, {0x046b}}},
- {0x046c, {1|F|D, {0x046d}}},
- {0x046e, {1|F|D, {0x046f}}},
- {0x0470, {1|F|D, {0x0471}}},
- {0x0472, {1|F|D, {0x0473}}},
- {0x0474, {1|F|D, {0x0475}}},
- {0x0476, {1|F|D, {0x0477}}},
- {0x0478, {1|F|D, {0x0479}}},
- {0x047a, {1|F|D, {0x047b}}},
- {0x047c, {1|F|D, {0x047d}}},
- {0x047e, {1|F|D, {0x047f}}},
- {0x0480, {1|F|D, {0x0481}}},
- {0x048a, {1|F|D, {0x048b}}},
- {0x048c, {1|F|D, {0x048d}}},
- {0x048e, {1|F|D, {0x048f}}},
- {0x0490, {1|F|D, {0x0491}}},
- {0x0492, {1|F|D, {0x0493}}},
- {0x0494, {1|F|D, {0x0495}}},
- {0x0496, {1|F|D, {0x0497}}},
- {0x0498, {1|F|D, {0x0499}}},
- {0x049a, {1|F|D, {0x049b}}},
- {0x049c, {1|F|D, {0x049d}}},
- {0x049e, {1|F|D, {0x049f}}},
- {0x04a0, {1|F|D, {0x04a1}}},
- {0x04a2, {1|F|D, {0x04a3}}},
- {0x04a4, {1|F|D, {0x04a5}}},
- {0x04a6, {1|F|D, {0x04a7}}},
- {0x04a8, {1|F|D, {0x04a9}}},
- {0x04aa, {1|F|D, {0x04ab}}},
- {0x04ac, {1|F|D, {0x04ad}}},
- {0x04ae, {1|F|D, {0x04af}}},
- {0x04b0, {1|F|D, {0x04b1}}},
- {0x04b2, {1|F|D, {0x04b3}}},
- {0x04b4, {1|F|D, {0x04b5}}},
- {0x04b6, {1|F|D, {0x04b7}}},
- {0x04b8, {1|F|D, {0x04b9}}},
- {0x04ba, {1|F|D, {0x04bb}}},
- {0x04bc, {1|F|D, {0x04bd}}},
- {0x04be, {1|F|D, {0x04bf}}},
- {0x04c0, {1|F|D, {0x04cf}}},
- {0x04c1, {1|F|D, {0x04c2}}},
- {0x04c3, {1|F|D, {0x04c4}}},
- {0x04c5, {1|F|D, {0x04c6}}},
- {0x04c7, {1|F|D, {0x04c8}}},
- {0x04c9, {1|F|D, {0x04ca}}},
- {0x04cb, {1|F|D, {0x04cc}}},
- {0x04cd, {1|F|D, {0x04ce}}},
- {0x04d0, {1|F|D, {0x04d1}}},
- {0x04d2, {1|F|D, {0x04d3}}},
- {0x04d4, {1|F|D, {0x04d5}}},
- {0x04d6, {1|F|D, {0x04d7}}},
- {0x04d8, {1|F|D, {0x04d9}}},
- {0x04da, {1|F|D, {0x04db}}},
- {0x04dc, {1|F|D, {0x04dd}}},
- {0x04de, {1|F|D, {0x04df}}},
- {0x04e0, {1|F|D, {0x04e1}}},
- {0x04e2, {1|F|D, {0x04e3}}},
- {0x04e4, {1|F|D, {0x04e5}}},
- {0x04e6, {1|F|D, {0x04e7}}},
- {0x04e8, {1|F|D, {0x04e9}}},
- {0x04ea, {1|F|D, {0x04eb}}},
- {0x04ec, {1|F|D, {0x04ed}}},
- {0x04ee, {1|F|D, {0x04ef}}},
- {0x04f0, {1|F|D, {0x04f1}}},
- {0x04f2, {1|F|D, {0x04f3}}},
- {0x04f4, {1|F|D, {0x04f5}}},
- {0x04f6, {1|F|D, {0x04f7}}},
- {0x04f8, {1|F|D, {0x04f9}}},
- {0x04fa, {1|F|D, {0x04fb}}},
- {0x04fc, {1|F|D, {0x04fd}}},
- {0x04fe, {1|F|D, {0x04ff}}},
- {0x0500, {1|F|D, {0x0501}}},
- {0x0502, {1|F|D, {0x0503}}},
- {0x0504, {1|F|D, {0x0505}}},
- {0x0506, {1|F|D, {0x0507}}},
- {0x0508, {1|F|D, {0x0509}}},
- {0x050a, {1|F|D, {0x050b}}},
- {0x050c, {1|F|D, {0x050d}}},
- {0x050e, {1|F|D, {0x050f}}},
- {0x0510, {1|F|D, {0x0511}}},
- {0x0512, {1|F|D, {0x0513}}},
- {0x0514, {1|F|D, {0x0515}}},
- {0x0516, {1|F|D, {0x0517}}},
- {0x0518, {1|F|D, {0x0519}}},
- {0x051a, {1|F|D, {0x051b}}},
- {0x051c, {1|F|D, {0x051d}}},
- {0x051e, {1|F|D, {0x051f}}},
- {0x0520, {1|F|D, {0x0521}}},
- {0x0522, {1|F|D, {0x0523}}},
- {0x0524, {1|F|D, {0x0525}}},
- {0x0526, {1|F|D, {0x0527}}},
- {0x0528, {1|F|D, {0x0529}}},
- {0x052a, {1|F|D, {0x052b}}},
- {0x052c, {1|F|D, {0x052d}}},
- {0x052e, {1|F|D, {0x052f}}},
- {0x0531, {1|F|D, {0x0561}}},
- {0x0532, {1|F|D, {0x0562}}},
- {0x0533, {1|F|D, {0x0563}}},
- {0x0534, {1|F|D, {0x0564}}},
- {0x0535, {1|F|D, {0x0565}}},
- {0x0536, {1|F|D, {0x0566}}},
- {0x0537, {1|F|D, {0x0567}}},
- {0x0538, {1|F|D, {0x0568}}},
- {0x0539, {1|F|D, {0x0569}}},
- {0x053a, {1|F|D, {0x056a}}},
- {0x053b, {1|F|D, {0x056b}}},
- {0x053c, {1|F|D, {0x056c}}},
- {0x053d, {1|F|D, {0x056d}}},
- {0x053e, {1|F|D, {0x056e}}},
- {0x053f, {1|F|D, {0x056f}}},
- {0x0540, {1|F|D, {0x0570}}},
- {0x0541, {1|F|D, {0x0571}}},
- {0x0542, {1|F|D, {0x0572}}},
- {0x0543, {1|F|D, {0x0573}}},
- {0x0544, {1|F|D, {0x0574}}},
- {0x0545, {1|F|D, {0x0575}}},
- {0x0546, {1|F|D, {0x0576}}},
- {0x0547, {1|F|D, {0x0577}}},
- {0x0548, {1|F|D, {0x0578}}},
- {0x0549, {1|F|D, {0x0579}}},
- {0x054a, {1|F|D, {0x057a}}},
- {0x054b, {1|F|D, {0x057b}}},
- {0x054c, {1|F|D, {0x057c}}},
- {0x054d, {1|F|D, {0x057d}}},
- {0x054e, {1|F|D, {0x057e}}},
- {0x054f, {1|F|D, {0x057f}}},
- {0x0550, {1|F|D, {0x0580}}},
- {0x0551, {1|F|D, {0x0581}}},
- {0x0552, {1|F|D, {0x0582}}},
- {0x0553, {1|F|D, {0x0583}}},
- {0x0554, {1|F|D, {0x0584}}},
- {0x0555, {1|F|D, {0x0585}}},
- {0x0556, {1|F|D, {0x0586}}},
- {0x0587, {2|F|ST|SU|I(41), {0x0565, 0x0582}}},
- {0x10a0, {1|F|D, {0x2d00}}},
- {0x10a1, {1|F|D, {0x2d01}}},
- {0x10a2, {1|F|D, {0x2d02}}},
- {0x10a3, {1|F|D, {0x2d03}}},
- {0x10a4, {1|F|D, {0x2d04}}},
- {0x10a5, {1|F|D, {0x2d05}}},
- {0x10a6, {1|F|D, {0x2d06}}},
- {0x10a7, {1|F|D, {0x2d07}}},
- {0x10a8, {1|F|D, {0x2d08}}},
- {0x10a9, {1|F|D, {0x2d09}}},
- {0x10aa, {1|F|D, {0x2d0a}}},
- {0x10ab, {1|F|D, {0x2d0b}}},
- {0x10ac, {1|F|D, {0x2d0c}}},
- {0x10ad, {1|F|D, {0x2d0d}}},
- {0x10ae, {1|F|D, {0x2d0e}}},
- {0x10af, {1|F|D, {0x2d0f}}},
- {0x10b0, {1|F|D, {0x2d10}}},
- {0x10b1, {1|F|D, {0x2d11}}},
- {0x10b2, {1|F|D, {0x2d12}}},
- {0x10b3, {1|F|D, {0x2d13}}},
- {0x10b4, {1|F|D, {0x2d14}}},
- {0x10b5, {1|F|D, {0x2d15}}},
- {0x10b6, {1|F|D, {0x2d16}}},
- {0x10b7, {1|F|D, {0x2d17}}},
- {0x10b8, {1|F|D, {0x2d18}}},
- {0x10b9, {1|F|D, {0x2d19}}},
- {0x10ba, {1|F|D, {0x2d1a}}},
- {0x10bb, {1|F|D, {0x2d1b}}},
- {0x10bc, {1|F|D, {0x2d1c}}},
- {0x10bd, {1|F|D, {0x2d1d}}},
- {0x10be, {1|F|D, {0x2d1e}}},
- {0x10bf, {1|F|D, {0x2d1f}}},
- {0x10c0, {1|F|D, {0x2d20}}},
- {0x10c1, {1|F|D, {0x2d21}}},
- {0x10c2, {1|F|D, {0x2d22}}},
- {0x10c3, {1|F|D, {0x2d23}}},
- {0x10c4, {1|F|D, {0x2d24}}},
- {0x10c5, {1|F|D, {0x2d25}}},
- {0x10c7, {1|F|D, {0x2d27}}},
- {0x10cd, {1|F|D, {0x2d2d}}},
- {0x13f8, {1|F|U, {0x13f0}}},
- {0x13f9, {1|F|U, {0x13f1}}},
- {0x13fa, {1|F|U, {0x13f2}}},
- {0x13fb, {1|F|U, {0x13f3}}},
- {0x13fc, {1|F|U, {0x13f4}}},
- {0x13fd, {1|F|U, {0x13f5}}},
- {0x1c80, {1|F|SU|I(45), {0x0432}}},
- {0x1c81, {1|F|SU|I(46), {0x0434}}},
- {0x1c82, {1|F|SU|I(47), {0x043e}}},
- {0x1c83, {1|F|SU|I(48), {0x0441}}},
- {0x1c84, {1|F|SU|I(49), {0x0442}}},
- {0x1c85, {1|F|SU|I(50), {0x0442}}},
- {0x1c86, {1|F|SU|I(51), {0x044a}}},
- {0x1c87, {1|F|SU|I(52), {0x0463}}},
- {0x1c88, {1|F|SU|I(53), {0xa64b}}},
- {0x1c89, {1|F|D, {0x1c8a}}},
- {0x1c90, {1|F|D, {0x10d0}}},
- {0x1c91, {1|F|D, {0x10d1}}},
- {0x1c92, {1|F|D, {0x10d2}}},
- {0x1c93, {1|F|D, {0x10d3}}},
- {0x1c94, {1|F|D, {0x10d4}}},
- {0x1c95, {1|F|D, {0x10d5}}},
- {0x1c96, {1|F|D, {0x10d6}}},
- {0x1c97, {1|F|D, {0x10d7}}},
- {0x1c98, {1|F|D, {0x10d8}}},
- {0x1c99, {1|F|D, {0x10d9}}},
- {0x1c9a, {1|F|D, {0x10da}}},
- {0x1c9b, {1|F|D, {0x10db}}},
- {0x1c9c, {1|F|D, {0x10dc}}},
- {0x1c9d, {1|F|D, {0x10dd}}},
- {0x1c9e, {1|F|D, {0x10de}}},
- {0x1c9f, {1|F|D, {0x10df}}},
- {0x1ca0, {1|F|D, {0x10e0}}},
- {0x1ca1, {1|F|D, {0x10e1}}},
- {0x1ca2, {1|F|D, {0x10e2}}},
- {0x1ca3, {1|F|D, {0x10e3}}},
- {0x1ca4, {1|F|D, {0x10e4}}},
- {0x1ca5, {1|F|D, {0x10e5}}},
- {0x1ca6, {1|F|D, {0x10e6}}},
- {0x1ca7, {1|F|D, {0x10e7}}},
- {0x1ca8, {1|F|D, {0x10e8}}},
- {0x1ca9, {1|F|D, {0x10e9}}},
- {0x1caa, {1|F|D, {0x10ea}}},
- {0x1cab, {1|F|D, {0x10eb}}},
- {0x1cac, {1|F|D, {0x10ec}}},
- {0x1cad, {1|F|D, {0x10ed}}},
- {0x1cae, {1|F|D, {0x10ee}}},
- {0x1caf, {1|F|D, {0x10ef}}},
- {0x1cb0, {1|F|D, {0x10f0}}},
- {0x1cb1, {1|F|D, {0x10f1}}},
- {0x1cb2, {1|F|D, {0x10f2}}},
- {0x1cb3, {1|F|D, {0x10f3}}},
- {0x1cb4, {1|F|D, {0x10f4}}},
- {0x1cb5, {1|F|D, {0x10f5}}},
- {0x1cb6, {1|F|D, {0x10f6}}},
- {0x1cb7, {1|F|D, {0x10f7}}},
- {0x1cb8, {1|F|D, {0x10f8}}},
- {0x1cb9, {1|F|D, {0x10f9}}},
- {0x1cba, {1|F|D, {0x10fa}}},
- {0x1cbd, {1|F|D, {0x10fd}}},
- {0x1cbe, {1|F|D, {0x10fe}}},
- {0x1cbf, {1|F|D, {0x10ff}}},
- {0x1e00, {1|F|D, {0x1e01}}},
- {0x1e02, {1|F|D, {0x1e03}}},
- {0x1e04, {1|F|D, {0x1e05}}},
- {0x1e06, {1|F|D, {0x1e07}}},
- {0x1e08, {1|F|D, {0x1e09}}},
- {0x1e0a, {1|F|D, {0x1e0b}}},
- {0x1e0c, {1|F|D, {0x1e0d}}},
- {0x1e0e, {1|F|D, {0x1e0f}}},
- {0x1e10, {1|F|D, {0x1e11}}},
- {0x1e12, {1|F|D, {0x1e13}}},
- {0x1e14, {1|F|D, {0x1e15}}},
- {0x1e16, {1|F|D, {0x1e17}}},
- {0x1e18, {1|F|D, {0x1e19}}},
- {0x1e1a, {1|F|D, {0x1e1b}}},
- {0x1e1c, {1|F|D, {0x1e1d}}},
- {0x1e1e, {1|F|D, {0x1e1f}}},
- {0x1e20, {1|F|D, {0x1e21}}},
- {0x1e22, {1|F|D, {0x1e23}}},
- {0x1e24, {1|F|D, {0x1e25}}},
- {0x1e26, {1|F|D, {0x1e27}}},
- {0x1e28, {1|F|D, {0x1e29}}},
- {0x1e2a, {1|F|D, {0x1e2b}}},
- {0x1e2c, {1|F|D, {0x1e2d}}},
- {0x1e2e, {1|F|D, {0x1e2f}}},
- {0x1e30, {1|F|D, {0x1e31}}},
- {0x1e32, {1|F|D, {0x1e33}}},
- {0x1e34, {1|F|D, {0x1e35}}},
- {0x1e36, {1|F|D, {0x1e37}}},
- {0x1e38, {1|F|D, {0x1e39}}},
- {0x1e3a, {1|F|D, {0x1e3b}}},
- {0x1e3c, {1|F|D, {0x1e3d}}},
- {0x1e3e, {1|F|D, {0x1e3f}}},
- {0x1e40, {1|F|D, {0x1e41}}},
- {0x1e42, {1|F|D, {0x1e43}}},
- {0x1e44, {1|F|D, {0x1e45}}},
- {0x1e46, {1|F|D, {0x1e47}}},
- {0x1e48, {1|F|D, {0x1e49}}},
- {0x1e4a, {1|F|D, {0x1e4b}}},
- {0x1e4c, {1|F|D, {0x1e4d}}},
- {0x1e4e, {1|F|D, {0x1e4f}}},
- {0x1e50, {1|F|D, {0x1e51}}},
- {0x1e52, {1|F|D, {0x1e53}}},
- {0x1e54, {1|F|D, {0x1e55}}},
- {0x1e56, {1|F|D, {0x1e57}}},
- {0x1e58, {1|F|D, {0x1e59}}},
- {0x1e5a, {1|F|D, {0x1e5b}}},
- {0x1e5c, {1|F|D, {0x1e5d}}},
- {0x1e5e, {1|F|D, {0x1e5f}}},
- {0x1e60, {1|F|D, {0x1e61}}},
- {0x1e62, {1|F|D, {0x1e63}}},
- {0x1e64, {1|F|D, {0x1e65}}},
- {0x1e66, {1|F|D, {0x1e67}}},
- {0x1e68, {1|F|D, {0x1e69}}},
- {0x1e6a, {1|F|D, {0x1e6b}}},
- {0x1e6c, {1|F|D, {0x1e6d}}},
- {0x1e6e, {1|F|D, {0x1e6f}}},
- {0x1e70, {1|F|D, {0x1e71}}},
- {0x1e72, {1|F|D, {0x1e73}}},
- {0x1e74, {1|F|D, {0x1e75}}},
- {0x1e76, {1|F|D, {0x1e77}}},
- {0x1e78, {1|F|D, {0x1e79}}},
- {0x1e7a, {1|F|D, {0x1e7b}}},
- {0x1e7c, {1|F|D, {0x1e7d}}},
- {0x1e7e, {1|F|D, {0x1e7f}}},
- {0x1e80, {1|F|D, {0x1e81}}},
- {0x1e82, {1|F|D, {0x1e83}}},
- {0x1e84, {1|F|D, {0x1e85}}},
- {0x1e86, {1|F|D, {0x1e87}}},
- {0x1e88, {1|F|D, {0x1e89}}},
- {0x1e8a, {1|F|D, {0x1e8b}}},
- {0x1e8c, {1|F|D, {0x1e8d}}},
- {0x1e8e, {1|F|D, {0x1e8f}}},
- {0x1e90, {1|F|D, {0x1e91}}},
- {0x1e92, {1|F|D, {0x1e93}}},
- {0x1e94, {1|F|D, {0x1e95}}},
- {0x1e96, {2|F|SU|I(54), {0x0068, 0x0331}}},
- {0x1e97, {2|F|SU|I(56), {0x0074, 0x0308}}},
- {0x1e98, {2|F|SU|I(58), {0x0077, 0x030a}}},
- {0x1e99, {2|F|SU|I(60), {0x0079, 0x030a}}},
- {0x1e9a, {2|F|SU|I(62), {0x0061, 0x02be}}},
- {0x1e9b, {1|F|SU|I(64), {0x1e61}}},
- {0x1e9e, {2|F|SL|I(65), {0x0073, 0x0073}}},
- {0x1ea0, {1|F|D, {0x1ea1}}},
- {0x1ea2, {1|F|D, {0x1ea3}}},
- {0x1ea4, {1|F|D, {0x1ea5}}},
- {0x1ea6, {1|F|D, {0x1ea7}}},
- {0x1ea8, {1|F|D, {0x1ea9}}},
- {0x1eaa, {1|F|D, {0x1eab}}},
- {0x1eac, {1|F|D, {0x1ead}}},
- {0x1eae, {1|F|D, {0x1eaf}}},
- {0x1eb0, {1|F|D, {0x1eb1}}},
- {0x1eb2, {1|F|D, {0x1eb3}}},
- {0x1eb4, {1|F|D, {0x1eb5}}},
- {0x1eb6, {1|F|D, {0x1eb7}}},
- {0x1eb8, {1|F|D, {0x1eb9}}},
- {0x1eba, {1|F|D, {0x1ebb}}},
- {0x1ebc, {1|F|D, {0x1ebd}}},
- {0x1ebe, {1|F|D, {0x1ebf}}},
- {0x1ec0, {1|F|D, {0x1ec1}}},
- {0x1ec2, {1|F|D, {0x1ec3}}},
- {0x1ec4, {1|F|D, {0x1ec5}}},
- {0x1ec6, {1|F|D, {0x1ec7}}},
- {0x1ec8, {1|F|D, {0x1ec9}}},
- {0x1eca, {1|F|D, {0x1ecb}}},
- {0x1ecc, {1|F|D, {0x1ecd}}},
- {0x1ece, {1|F|D, {0x1ecf}}},
- {0x1ed0, {1|F|D, {0x1ed1}}},
- {0x1ed2, {1|F|D, {0x1ed3}}},
- {0x1ed4, {1|F|D, {0x1ed5}}},
- {0x1ed6, {1|F|D, {0x1ed7}}},
- {0x1ed8, {1|F|D, {0x1ed9}}},
- {0x1eda, {1|F|D, {0x1edb}}},
- {0x1edc, {1|F|D, {0x1edd}}},
- {0x1ede, {1|F|D, {0x1edf}}},
- {0x1ee0, {1|F|D, {0x1ee1}}},
- {0x1ee2, {1|F|D, {0x1ee3}}},
- {0x1ee4, {1|F|D, {0x1ee5}}},
- {0x1ee6, {1|F|D, {0x1ee7}}},
- {0x1ee8, {1|F|D, {0x1ee9}}},
- {0x1eea, {1|F|D, {0x1eeb}}},
- {0x1eec, {1|F|D, {0x1eed}}},
- {0x1eee, {1|F|D, {0x1eef}}},
- {0x1ef0, {1|F|D, {0x1ef1}}},
- {0x1ef2, {1|F|D, {0x1ef3}}},
- {0x1ef4, {1|F|D, {0x1ef5}}},
- {0x1ef6, {1|F|D, {0x1ef7}}},
- {0x1ef8, {1|F|D, {0x1ef9}}},
- {0x1efa, {1|F|D, {0x1efb}}},
- {0x1efc, {1|F|D, {0x1efd}}},
- {0x1efe, {1|F|D, {0x1eff}}},
- {0x1f08, {1|F|D, {0x1f00}}},
- {0x1f09, {1|F|D, {0x1f01}}},
- {0x1f0a, {1|F|D, {0x1f02}}},
- {0x1f0b, {1|F|D, {0x1f03}}},
- {0x1f0c, {1|F|D, {0x1f04}}},
- {0x1f0d, {1|F|D, {0x1f05}}},
- {0x1f0e, {1|F|D, {0x1f06}}},
- {0x1f0f, {1|F|D, {0x1f07}}},
- {0x1f18, {1|F|D, {0x1f10}}},
- {0x1f19, {1|F|D, {0x1f11}}},
- {0x1f1a, {1|F|D, {0x1f12}}},
- {0x1f1b, {1|F|D, {0x1f13}}},
- {0x1f1c, {1|F|D, {0x1f14}}},
- {0x1f1d, {1|F|D, {0x1f15}}},
- {0x1f28, {1|F|D, {0x1f20}}},
- {0x1f29, {1|F|D, {0x1f21}}},
- {0x1f2a, {1|F|D, {0x1f22}}},
- {0x1f2b, {1|F|D, {0x1f23}}},
- {0x1f2c, {1|F|D, {0x1f24}}},
- {0x1f2d, {1|F|D, {0x1f25}}},
- {0x1f2e, {1|F|D, {0x1f26}}},
- {0x1f2f, {1|F|D, {0x1f27}}},
- {0x1f38, {1|F|D, {0x1f30}}},
- {0x1f39, {1|F|D, {0x1f31}}},
- {0x1f3a, {1|F|D, {0x1f32}}},
- {0x1f3b, {1|F|D, {0x1f33}}},
- {0x1f3c, {1|F|D, {0x1f34}}},
- {0x1f3d, {1|F|D, {0x1f35}}},
- {0x1f3e, {1|F|D, {0x1f36}}},
- {0x1f3f, {1|F|D, {0x1f37}}},
- {0x1f48, {1|F|D, {0x1f40}}},
- {0x1f49, {1|F|D, {0x1f41}}},
- {0x1f4a, {1|F|D, {0x1f42}}},
- {0x1f4b, {1|F|D, {0x1f43}}},
- {0x1f4c, {1|F|D, {0x1f44}}},
- {0x1f4d, {1|F|D, {0x1f45}}},
- {0x1f50, {2|F|SU|I(66), {0x03c5, 0x0313}}},
- {0x1f52, {3|F|SU|I(68), {0x03c5, 0x0313, 0x0300}}},
- {0x1f54, {3|F|SU|I(71), {0x03c5, 0x0313, 0x0301}}},
- {0x1f56, {3|F|SU|I(74), {0x03c5, 0x0313, 0x0342}}},
- {0x1f59, {1|F|D, {0x1f51}}},
- {0x1f5b, {1|F|D, {0x1f53}}},
- {0x1f5d, {1|F|D, {0x1f55}}},
- {0x1f5f, {1|F|D, {0x1f57}}},
- {0x1f68, {1|F|D, {0x1f60}}},
- {0x1f69, {1|F|D, {0x1f61}}},
- {0x1f6a, {1|F|D, {0x1f62}}},
- {0x1f6b, {1|F|D, {0x1f63}}},
- {0x1f6c, {1|F|D, {0x1f64}}},
- {0x1f6d, {1|F|D, {0x1f65}}},
- {0x1f6e, {1|F|D, {0x1f66}}},
- {0x1f6f, {1|F|D, {0x1f67}}},
- {0x1f80, {2|F|ST|SU|I(77), {0x1f00, 0x03b9}}},
- {0x1f81, {2|F|ST|SU|I(80), {0x1f01, 0x03b9}}},
- {0x1f82, {2|F|ST|SU|I(83), {0x1f02, 0x03b9}}},
- {0x1f83, {2|F|ST|SU|I(86), {0x1f03, 0x03b9}}},
- {0x1f84, {2|F|ST|SU|I(89), {0x1f04, 0x03b9}}},
- {0x1f85, {2|F|ST|SU|I(92), {0x1f05, 0x03b9}}},
- {0x1f86, {2|F|ST|SU|I(95), {0x1f06, 0x03b9}}},
- {0x1f87, {2|F|ST|SU|I(98), {0x1f07, 0x03b9}}},
- {0x1f88, {2|F|IT|SL|SU|I(101), {0x1f00, 0x03b9}}},
- {0x1f89, {2|F|IT|SL|SU|I(106), {0x1f01, 0x03b9}}},
- {0x1f8a, {2|F|IT|SL|SU|I(111), {0x1f02, 0x03b9}}},
- {0x1f8b, {2|F|IT|SL|SU|I(116), {0x1f03, 0x03b9}}},
- {0x1f8c, {2|F|IT|SL|SU|I(121), {0x1f04, 0x03b9}}},
- {0x1f8d, {2|F|IT|SL|SU|I(126), {0x1f05, 0x03b9}}},
- {0x1f8e, {2|F|IT|SL|SU|I(131), {0x1f06, 0x03b9}}},
- {0x1f8f, {2|F|IT|SL|SU|I(136), {0x1f07, 0x03b9}}},
- {0x1f90, {2|F|ST|SU|I(141), {0x1f20, 0x03b9}}},
- {0x1f91, {2|F|ST|SU|I(144), {0x1f21, 0x03b9}}},
- {0x1f92, {2|F|ST|SU|I(147), {0x1f22, 0x03b9}}},
- {0x1f93, {2|F|ST|SU|I(150), {0x1f23, 0x03b9}}},
- {0x1f94, {2|F|ST|SU|I(153), {0x1f24, 0x03b9}}},
- {0x1f95, {2|F|ST|SU|I(156), {0x1f25, 0x03b9}}},
- {0x1f96, {2|F|ST|SU|I(159), {0x1f26, 0x03b9}}},
- {0x1f97, {2|F|ST|SU|I(162), {0x1f27, 0x03b9}}},
- {0x1f98, {2|F|IT|SL|SU|I(165), {0x1f20, 0x03b9}}},
- {0x1f99, {2|F|IT|SL|SU|I(170), {0x1f21, 0x03b9}}},
- {0x1f9a, {2|F|IT|SL|SU|I(175), {0x1f22, 0x03b9}}},
- {0x1f9b, {2|F|IT|SL|SU|I(180), {0x1f23, 0x03b9}}},
- {0x1f9c, {2|F|IT|SL|SU|I(185), {0x1f24, 0x03b9}}},
- {0x1f9d, {2|F|IT|SL|SU|I(190), {0x1f25, 0x03b9}}},
- {0x1f9e, {2|F|IT|SL|SU|I(195), {0x1f26, 0x03b9}}},
- {0x1f9f, {2|F|IT|SL|SU|I(200), {0x1f27, 0x03b9}}},
- {0x1fa0, {2|F|ST|SU|I(205), {0x1f60, 0x03b9}}},
- {0x1fa1, {2|F|ST|SU|I(208), {0x1f61, 0x03b9}}},
- {0x1fa2, {2|F|ST|SU|I(211), {0x1f62, 0x03b9}}},
- {0x1fa3, {2|F|ST|SU|I(214), {0x1f63, 0x03b9}}},
- {0x1fa4, {2|F|ST|SU|I(217), {0x1f64, 0x03b9}}},
- {0x1fa5, {2|F|ST|SU|I(220), {0x1f65, 0x03b9}}},
- {0x1fa6, {2|F|ST|SU|I(223), {0x1f66, 0x03b9}}},
- {0x1fa7, {2|F|ST|SU|I(226), {0x1f67, 0x03b9}}},
- {0x1fa8, {2|F|IT|SL|SU|I(229), {0x1f60, 0x03b9}}},
- {0x1fa9, {2|F|IT|SL|SU|I(234), {0x1f61, 0x03b9}}},
- {0x1faa, {2|F|IT|SL|SU|I(239), {0x1f62, 0x03b9}}},
- {0x1fab, {2|F|IT|SL|SU|I(244), {0x1f63, 0x03b9}}},
- {0x1fac, {2|F|IT|SL|SU|I(249), {0x1f64, 0x03b9}}},
- {0x1fad, {2|F|IT|SL|SU|I(254), {0x1f65, 0x03b9}}},
- {0x1fae, {2|F|IT|SL|SU|I(259), {0x1f66, 0x03b9}}},
- {0x1faf, {2|F|IT|SL|SU|I(264), {0x1f67, 0x03b9}}},
- {0x1fb2, {2|F|ST|SU|I(269), {0x1f70, 0x03b9}}},
- {0x1fb3, {2|F|ST|SU|I(273), {0x03b1, 0x03b9}}},
- {0x1fb4, {2|F|ST|SU|I(276), {0x03ac, 0x03b9}}},
- {0x1fb6, {2|F|SU|I(280), {0x03b1, 0x0342}}},
- {0x1fb7, {3|F|ST|SU|I(282), {0x03b1, 0x0342, 0x03b9}}},
- {0x1fb8, {1|F|D, {0x1fb0}}},
- {0x1fb9, {1|F|D, {0x1fb1}}},
- {0x1fba, {1|F|D, {0x1f70}}},
- {0x1fbb, {1|F|D, {0x1f71}}},
- {0x1fbc, {2|F|IT|SL|SU|I(288), {0x03b1, 0x03b9}}},
- {0x1fbe, {1|F|SU|I(293), {0x03b9}}},
- {0x1fc2, {2|F|ST|SU|I(294), {0x1f74, 0x03b9}}},
- {0x1fc3, {2|F|ST|SU|I(298), {0x03b7, 0x03b9}}},
- {0x1fc4, {2|F|ST|SU|I(301), {0x03ae, 0x03b9}}},
- {0x1fc6, {2|F|SU|I(305), {0x03b7, 0x0342}}},
- {0x1fc7, {3|F|ST|SU|I(307), {0x03b7, 0x0342, 0x03b9}}},
- {0x1fc8, {1|F|D, {0x1f72}}},
- {0x1fc9, {1|F|D, {0x1f73}}},
- {0x1fca, {1|F|D, {0x1f74}}},
- {0x1fcb, {1|F|D, {0x1f75}}},
- {0x1fcc, {2|F|IT|SL|SU|I(313), {0x03b7, 0x03b9}}},
- {0x1fd2, {3|F|SU|I(318), {0x03b9, 0x0308, 0x0300}}},
- {0x1fd3, {3|F|SU|I(321), {0x03b9, 0x0308, 0x0301}}},
- {0x1fd6, {2|F|SU|I(324), {0x03b9, 0x0342}}},
- {0x1fd7, {3|F|SU|I(326), {0x03b9, 0x0308, 0x0342}}},
- {0x1fd8, {1|F|D, {0x1fd0}}},
- {0x1fd9, {1|F|D, {0x1fd1}}},
- {0x1fda, {1|F|D, {0x1f76}}},
- {0x1fdb, {1|F|D, {0x1f77}}},
- {0x1fe2, {3|F|SU|I(329), {0x03c5, 0x0308, 0x0300}}},
- {0x1fe3, {3|F|SU|I(332), {0x03c5, 0x0308, 0x0301}}},
- {0x1fe4, {2|F|SU|I(335), {0x03c1, 0x0313}}},
- {0x1fe6, {2|F|SU|I(337), {0x03c5, 0x0342}}},
- {0x1fe7, {3|F|SU|I(339), {0x03c5, 0x0308, 0x0342}}},
- {0x1fe8, {1|F|D, {0x1fe0}}},
- {0x1fe9, {1|F|D, {0x1fe1}}},
- {0x1fea, {1|F|D, {0x1f7a}}},
- {0x1feb, {1|F|D, {0x1f7b}}},
- {0x1fec, {1|F|D, {0x1fe5}}},
- {0x1ff2, {2|F|ST|SU|I(342), {0x1f7c, 0x03b9}}},
- {0x1ff3, {2|F|ST|SU|I(346), {0x03c9, 0x03b9}}},
- {0x1ff4, {2|F|ST|SU|I(349), {0x03ce, 0x03b9}}},
- {0x1ff6, {2|F|SU|I(353), {0x03c9, 0x0342}}},
- {0x1ff7, {3|F|ST|SU|I(355), {0x03c9, 0x0342, 0x03b9}}},
- {0x1ff8, {1|F|D, {0x1f78}}},
- {0x1ff9, {1|F|D, {0x1f79}}},
- {0x1ffa, {1|F|D, {0x1f7c}}},
- {0x1ffb, {1|F|D, {0x1f7d}}},
- {0x1ffc, {2|F|IT|SL|SU|I(361), {0x03c9, 0x03b9}}},
- {0x2126, {1|F|D, {0x03c9}}},
- {0x212a, {1|F|D, {0x006b}}},
- {0x212b, {1|F|D, {0x00e5}}},
- {0x2132, {1|F|D, {0x214e}}},
- {0x2160, {1|F|D, {0x2170}}},
- {0x2161, {1|F|D, {0x2171}}},
- {0x2162, {1|F|D, {0x2172}}},
- {0x2163, {1|F|D, {0x2173}}},
- {0x2164, {1|F|D, {0x2174}}},
- {0x2165, {1|F|D, {0x2175}}},
- {0x2166, {1|F|D, {0x2176}}},
- {0x2167, {1|F|D, {0x2177}}},
- {0x2168, {1|F|D, {0x2178}}},
- {0x2169, {1|F|D, {0x2179}}},
- {0x216a, {1|F|D, {0x217a}}},
- {0x216b, {1|F|D, {0x217b}}},
- {0x216c, {1|F|D, {0x217c}}},
- {0x216d, {1|F|D, {0x217d}}},
- {0x216e, {1|F|D, {0x217e}}},
- {0x216f, {1|F|D, {0x217f}}},
- {0x2183, {1|F|D, {0x2184}}},
- {0x24b6, {1|F|D, {0x24d0}}},
- {0x24b7, {1|F|D, {0x24d1}}},
- {0x24b8, {1|F|D, {0x24d2}}},
- {0x24b9, {1|F|D, {0x24d3}}},
- {0x24ba, {1|F|D, {0x24d4}}},
- {0x24bb, {1|F|D, {0x24d5}}},
- {0x24bc, {1|F|D, {0x24d6}}},
- {0x24bd, {1|F|D, {0x24d7}}},
- {0x24be, {1|F|D, {0x24d8}}},
- {0x24bf, {1|F|D, {0x24d9}}},
- {0x24c0, {1|F|D, {0x24da}}},
- {0x24c1, {1|F|D, {0x24db}}},
- {0x24c2, {1|F|D, {0x24dc}}},
- {0x24c3, {1|F|D, {0x24dd}}},
- {0x24c4, {1|F|D, {0x24de}}},
- {0x24c5, {1|F|D, {0x24df}}},
- {0x24c6, {1|F|D, {0x24e0}}},
- {0x24c7, {1|F|D, {0x24e1}}},
- {0x24c8, {1|F|D, {0x24e2}}},
- {0x24c9, {1|F|D, {0x24e3}}},
- {0x24ca, {1|F|D, {0x24e4}}},
- {0x24cb, {1|F|D, {0x24e5}}},
- {0x24cc, {1|F|D, {0x24e6}}},
- {0x24cd, {1|F|D, {0x24e7}}},
- {0x24ce, {1|F|D, {0x24e8}}},
- {0x24cf, {1|F|D, {0x24e9}}},
- {0x2c00, {1|F|D, {0x2c30}}},
- {0x2c01, {1|F|D, {0x2c31}}},
- {0x2c02, {1|F|D, {0x2c32}}},
- {0x2c03, {1|F|D, {0x2c33}}},
- {0x2c04, {1|F|D, {0x2c34}}},
- {0x2c05, {1|F|D, {0x2c35}}},
- {0x2c06, {1|F|D, {0x2c36}}},
- {0x2c07, {1|F|D, {0x2c37}}},
- {0x2c08, {1|F|D, {0x2c38}}},
- {0x2c09, {1|F|D, {0x2c39}}},
- {0x2c0a, {1|F|D, {0x2c3a}}},
- {0x2c0b, {1|F|D, {0x2c3b}}},
- {0x2c0c, {1|F|D, {0x2c3c}}},
- {0x2c0d, {1|F|D, {0x2c3d}}},
- {0x2c0e, {1|F|D, {0x2c3e}}},
- {0x2c0f, {1|F|D, {0x2c3f}}},
- {0x2c10, {1|F|D, {0x2c40}}},
- {0x2c11, {1|F|D, {0x2c41}}},
- {0x2c12, {1|F|D, {0x2c42}}},
- {0x2c13, {1|F|D, {0x2c43}}},
- {0x2c14, {1|F|D, {0x2c44}}},
- {0x2c15, {1|F|D, {0x2c45}}},
- {0x2c16, {1|F|D, {0x2c46}}},
- {0x2c17, {1|F|D, {0x2c47}}},
- {0x2c18, {1|F|D, {0x2c48}}},
- {0x2c19, {1|F|D, {0x2c49}}},
- {0x2c1a, {1|F|D, {0x2c4a}}},
- {0x2c1b, {1|F|D, {0x2c4b}}},
- {0x2c1c, {1|F|D, {0x2c4c}}},
- {0x2c1d, {1|F|D, {0x2c4d}}},
- {0x2c1e, {1|F|D, {0x2c4e}}},
- {0x2c1f, {1|F|D, {0x2c4f}}},
- {0x2c20, {1|F|D, {0x2c50}}},
- {0x2c21, {1|F|D, {0x2c51}}},
- {0x2c22, {1|F|D, {0x2c52}}},
- {0x2c23, {1|F|D, {0x2c53}}},
- {0x2c24, {1|F|D, {0x2c54}}},
- {0x2c25, {1|F|D, {0x2c55}}},
- {0x2c26, {1|F|D, {0x2c56}}},
- {0x2c27, {1|F|D, {0x2c57}}},
- {0x2c28, {1|F|D, {0x2c58}}},
- {0x2c29, {1|F|D, {0x2c59}}},
- {0x2c2a, {1|F|D, {0x2c5a}}},
- {0x2c2b, {1|F|D, {0x2c5b}}},
- {0x2c2c, {1|F|D, {0x2c5c}}},
- {0x2c2d, {1|F|D, {0x2c5d}}},
- {0x2c2e, {1|F|D, {0x2c5e}}},
- {0x2c2f, {1|F|D, {0x2c5f}}},
- {0x2c60, {1|F|D, {0x2c61}}},
- {0x2c62, {1|F|D, {0x026b}}},
- {0x2c63, {1|F|D, {0x1d7d}}},
- {0x2c64, {1|F|D, {0x027d}}},
- {0x2c67, {1|F|D, {0x2c68}}},
- {0x2c69, {1|F|D, {0x2c6a}}},
- {0x2c6b, {1|F|D, {0x2c6c}}},
- {0x2c6d, {1|F|D, {0x0251}}},
- {0x2c6e, {1|F|D, {0x0271}}},
- {0x2c6f, {1|F|D, {0x0250}}},
- {0x2c70, {1|F|D, {0x0252}}},
- {0x2c72, {1|F|D, {0x2c73}}},
- {0x2c75, {1|F|D, {0x2c76}}},
- {0x2c7e, {1|F|D, {0x023f}}},
- {0x2c7f, {1|F|D, {0x0240}}},
- {0x2c80, {1|F|D, {0x2c81}}},
- {0x2c82, {1|F|D, {0x2c83}}},
- {0x2c84, {1|F|D, {0x2c85}}},
- {0x2c86, {1|F|D, {0x2c87}}},
- {0x2c88, {1|F|D, {0x2c89}}},
- {0x2c8a, {1|F|D, {0x2c8b}}},
- {0x2c8c, {1|F|D, {0x2c8d}}},
- {0x2c8e, {1|F|D, {0x2c8f}}},
- {0x2c90, {1|F|D, {0x2c91}}},
- {0x2c92, {1|F|D, {0x2c93}}},
- {0x2c94, {1|F|D, {0x2c95}}},
- {0x2c96, {1|F|D, {0x2c97}}},
- {0x2c98, {1|F|D, {0x2c99}}},
- {0x2c9a, {1|F|D, {0x2c9b}}},
- {0x2c9c, {1|F|D, {0x2c9d}}},
- {0x2c9e, {1|F|D, {0x2c9f}}},
- {0x2ca0, {1|F|D, {0x2ca1}}},
- {0x2ca2, {1|F|D, {0x2ca3}}},
- {0x2ca4, {1|F|D, {0x2ca5}}},
- {0x2ca6, {1|F|D, {0x2ca7}}},
- {0x2ca8, {1|F|D, {0x2ca9}}},
- {0x2caa, {1|F|D, {0x2cab}}},
- {0x2cac, {1|F|D, {0x2cad}}},
- {0x2cae, {1|F|D, {0x2caf}}},
- {0x2cb0, {1|F|D, {0x2cb1}}},
- {0x2cb2, {1|F|D, {0x2cb3}}},
- {0x2cb4, {1|F|D, {0x2cb5}}},
- {0x2cb6, {1|F|D, {0x2cb7}}},
- {0x2cb8, {1|F|D, {0x2cb9}}},
- {0x2cba, {1|F|D, {0x2cbb}}},
- {0x2cbc, {1|F|D, {0x2cbd}}},
- {0x2cbe, {1|F|D, {0x2cbf}}},
- {0x2cc0, {1|F|D, {0x2cc1}}},
- {0x2cc2, {1|F|D, {0x2cc3}}},
- {0x2cc4, {1|F|D, {0x2cc5}}},
- {0x2cc6, {1|F|D, {0x2cc7}}},
- {0x2cc8, {1|F|D, {0x2cc9}}},
- {0x2cca, {1|F|D, {0x2ccb}}},
- {0x2ccc, {1|F|D, {0x2ccd}}},
- {0x2cce, {1|F|D, {0x2ccf}}},
- {0x2cd0, {1|F|D, {0x2cd1}}},
- {0x2cd2, {1|F|D, {0x2cd3}}},
- {0x2cd4, {1|F|D, {0x2cd5}}},
- {0x2cd6, {1|F|D, {0x2cd7}}},
- {0x2cd8, {1|F|D, {0x2cd9}}},
- {0x2cda, {1|F|D, {0x2cdb}}},
- {0x2cdc, {1|F|D, {0x2cdd}}},
- {0x2cde, {1|F|D, {0x2cdf}}},
- {0x2ce0, {1|F|D, {0x2ce1}}},
- {0x2ce2, {1|F|D, {0x2ce3}}},
- {0x2ceb, {1|F|D, {0x2cec}}},
- {0x2ced, {1|F|D, {0x2cee}}},
- {0x2cf2, {1|F|D, {0x2cf3}}},
- {0xa640, {1|F|D, {0xa641}}},
- {0xa642, {1|F|D, {0xa643}}},
- {0xa644, {1|F|D, {0xa645}}},
- {0xa646, {1|F|D, {0xa647}}},
- {0xa648, {1|F|D, {0xa649}}},
- {0xa64a, {1|F|D, {0xa64b}}},
- {0xa64c, {1|F|D, {0xa64d}}},
- {0xa64e, {1|F|D, {0xa64f}}},
- {0xa650, {1|F|D, {0xa651}}},
- {0xa652, {1|F|D, {0xa653}}},
- {0xa654, {1|F|D, {0xa655}}},
- {0xa656, {1|F|D, {0xa657}}},
- {0xa658, {1|F|D, {0xa659}}},
- {0xa65a, {1|F|D, {0xa65b}}},
- {0xa65c, {1|F|D, {0xa65d}}},
- {0xa65e, {1|F|D, {0xa65f}}},
- {0xa660, {1|F|D, {0xa661}}},
- {0xa662, {1|F|D, {0xa663}}},
- {0xa664, {1|F|D, {0xa665}}},
- {0xa666, {1|F|D, {0xa667}}},
- {0xa668, {1|F|D, {0xa669}}},
- {0xa66a, {1|F|D, {0xa66b}}},
- {0xa66c, {1|F|D, {0xa66d}}},
- {0xa680, {1|F|D, {0xa681}}},
- {0xa682, {1|F|D, {0xa683}}},
- {0xa684, {1|F|D, {0xa685}}},
- {0xa686, {1|F|D, {0xa687}}},
- {0xa688, {1|F|D, {0xa689}}},
- {0xa68a, {1|F|D, {0xa68b}}},
- {0xa68c, {1|F|D, {0xa68d}}},
- {0xa68e, {1|F|D, {0xa68f}}},
- {0xa690, {1|F|D, {0xa691}}},
- {0xa692, {1|F|D, {0xa693}}},
- {0xa694, {1|F|D, {0xa695}}},
- {0xa696, {1|F|D, {0xa697}}},
- {0xa698, {1|F|D, {0xa699}}},
- {0xa69a, {1|F|D, {0xa69b}}},
- {0xa722, {1|F|D, {0xa723}}},
- {0xa724, {1|F|D, {0xa725}}},
- {0xa726, {1|F|D, {0xa727}}},
- {0xa728, {1|F|D, {0xa729}}},
- {0xa72a, {1|F|D, {0xa72b}}},
- {0xa72c, {1|F|D, {0xa72d}}},
- {0xa72e, {1|F|D, {0xa72f}}},
- {0xa732, {1|F|D, {0xa733}}},
- {0xa734, {1|F|D, {0xa735}}},
- {0xa736, {1|F|D, {0xa737}}},
- {0xa738, {1|F|D, {0xa739}}},
- {0xa73a, {1|F|D, {0xa73b}}},
- {0xa73c, {1|F|D, {0xa73d}}},
- {0xa73e, {1|F|D, {0xa73f}}},
- {0xa740, {1|F|D, {0xa741}}},
- {0xa742, {1|F|D, {0xa743}}},
- {0xa744, {1|F|D, {0xa745}}},
- {0xa746, {1|F|D, {0xa747}}},
- {0xa748, {1|F|D, {0xa749}}},
- {0xa74a, {1|F|D, {0xa74b}}},
- {0xa74c, {1|F|D, {0xa74d}}},
- {0xa74e, {1|F|D, {0xa74f}}},
- {0xa750, {1|F|D, {0xa751}}},
- {0xa752, {1|F|D, {0xa753}}},
- {0xa754, {1|F|D, {0xa755}}},
- {0xa756, {1|F|D, {0xa757}}},
- {0xa758, {1|F|D, {0xa759}}},
- {0xa75a, {1|F|D, {0xa75b}}},
- {0xa75c, {1|F|D, {0xa75d}}},
- {0xa75e, {1|F|D, {0xa75f}}},
- {0xa760, {1|F|D, {0xa761}}},
- {0xa762, {1|F|D, {0xa763}}},
- {0xa764, {1|F|D, {0xa765}}},
- {0xa766, {1|F|D, {0xa767}}},
- {0xa768, {1|F|D, {0xa769}}},
- {0xa76a, {1|F|D, {0xa76b}}},
- {0xa76c, {1|F|D, {0xa76d}}},
- {0xa76e, {1|F|D, {0xa76f}}},
- {0xa779, {1|F|D, {0xa77a}}},
- {0xa77b, {1|F|D, {0xa77c}}},
- {0xa77d, {1|F|D, {0x1d79}}},
- {0xa77e, {1|F|D, {0xa77f}}},
- {0xa780, {1|F|D, {0xa781}}},
- {0xa782, {1|F|D, {0xa783}}},
- {0xa784, {1|F|D, {0xa785}}},
- {0xa786, {1|F|D, {0xa787}}},
- {0xa78b, {1|F|D, {0xa78c}}},
- {0xa78d, {1|F|D, {0x0265}}},
- {0xa790, {1|F|D, {0xa791}}},
- {0xa792, {1|F|D, {0xa793}}},
- {0xa796, {1|F|D, {0xa797}}},
- {0xa798, {1|F|D, {0xa799}}},
- {0xa79a, {1|F|D, {0xa79b}}},
- {0xa79c, {1|F|D, {0xa79d}}},
- {0xa79e, {1|F|D, {0xa79f}}},
- {0xa7a0, {1|F|D, {0xa7a1}}},
- {0xa7a2, {1|F|D, {0xa7a3}}},
- {0xa7a4, {1|F|D, {0xa7a5}}},
- {0xa7a6, {1|F|D, {0xa7a7}}},
- {0xa7a8, {1|F|D, {0xa7a9}}},
- {0xa7aa, {1|F|D, {0x0266}}},
- {0xa7ab, {1|F|D, {0x025c}}},
- {0xa7ac, {1|F|D, {0x0261}}},
- {0xa7ad, {1|F|D, {0x026c}}},
- {0xa7ae, {1|F|D, {0x026a}}},
- {0xa7b0, {1|F|D, {0x029e}}},
- {0xa7b1, {1|F|D, {0x0287}}},
- {0xa7b2, {1|F|D, {0x029d}}},
- {0xa7b3, {1|F|D, {0xab53}}},
- {0xa7b4, {1|F|D, {0xa7b5}}},
- {0xa7b6, {1|F|D, {0xa7b7}}},
- {0xa7b8, {1|F|D, {0xa7b9}}},
- {0xa7ba, {1|F|D, {0xa7bb}}},
- {0xa7bc, {1|F|D, {0xa7bd}}},
- {0xa7be, {1|F|D, {0xa7bf}}},
- {0xa7c0, {1|F|D, {0xa7c1}}},
- {0xa7c2, {1|F|D, {0xa7c3}}},
- {0xa7c4, {1|F|D, {0xa794}}},
- {0xa7c5, {1|F|D, {0x0282}}},
- {0xa7c6, {1|F|D, {0x1d8e}}},
- {0xa7c7, {1|F|D, {0xa7c8}}},
- {0xa7c9, {1|F|D, {0xa7ca}}},
- {0xa7cb, {1|F|D, {0x0264}}},
- {0xa7cc, {1|F|D, {0xa7cd}}},
- {0xa7d0, {1|F|D, {0xa7d1}}},
- {0xa7d6, {1|F|D, {0xa7d7}}},
- {0xa7d8, {1|F|D, {0xa7d9}}},
- {0xa7da, {1|F|D, {0xa7db}}},
- {0xa7dc, {1|F|D, {0x019b}}},
- {0xa7f5, {1|F|D, {0xa7f6}}},
- {0xab70, {1|F|U, {0x13a0}}},
- {0xab71, {1|F|U, {0x13a1}}},
- {0xab72, {1|F|U, {0x13a2}}},
- {0xab73, {1|F|U, {0x13a3}}},
- {0xab74, {1|F|U, {0x13a4}}},
- {0xab75, {1|F|U, {0x13a5}}},
- {0xab76, {1|F|U, {0x13a6}}},
- {0xab77, {1|F|U, {0x13a7}}},
- {0xab78, {1|F|U, {0x13a8}}},
- {0xab79, {1|F|U, {0x13a9}}},
- {0xab7a, {1|F|U, {0x13aa}}},
- {0xab7b, {1|F|U, {0x13ab}}},
- {0xab7c, {1|F|U, {0x13ac}}},
- {0xab7d, {1|F|U, {0x13ad}}},
- {0xab7e, {1|F|U, {0x13ae}}},
- {0xab7f, {1|F|U, {0x13af}}},
- {0xab80, {1|F|U, {0x13b0}}},
- {0xab81, {1|F|U, {0x13b1}}},
- {0xab82, {1|F|U, {0x13b2}}},
- {0xab83, {1|F|U, {0x13b3}}},
- {0xab84, {1|F|U, {0x13b4}}},
- {0xab85, {1|F|U, {0x13b5}}},
- {0xab86, {1|F|U, {0x13b6}}},
- {0xab87, {1|F|U, {0x13b7}}},
- {0xab88, {1|F|U, {0x13b8}}},
- {0xab89, {1|F|U, {0x13b9}}},
- {0xab8a, {1|F|U, {0x13ba}}},
- {0xab8b, {1|F|U, {0x13bb}}},
- {0xab8c, {1|F|U, {0x13bc}}},
- {0xab8d, {1|F|U, {0x13bd}}},
- {0xab8e, {1|F|U, {0x13be}}},
- {0xab8f, {1|F|U, {0x13bf}}},
- {0xab90, {1|F|U, {0x13c0}}},
- {0xab91, {1|F|U, {0x13c1}}},
- {0xab92, {1|F|U, {0x13c2}}},
- {0xab93, {1|F|U, {0x13c3}}},
- {0xab94, {1|F|U, {0x13c4}}},
- {0xab95, {1|F|U, {0x13c5}}},
- {0xab96, {1|F|U, {0x13c6}}},
- {0xab97, {1|F|U, {0x13c7}}},
- {0xab98, {1|F|U, {0x13c8}}},
- {0xab99, {1|F|U, {0x13c9}}},
- {0xab9a, {1|F|U, {0x13ca}}},
- {0xab9b, {1|F|U, {0x13cb}}},
- {0xab9c, {1|F|U, {0x13cc}}},
- {0xab9d, {1|F|U, {0x13cd}}},
- {0xab9e, {1|F|U, {0x13ce}}},
- {0xab9f, {1|F|U, {0x13cf}}},
- {0xaba0, {1|F|U, {0x13d0}}},
- {0xaba1, {1|F|U, {0x13d1}}},
- {0xaba2, {1|F|U, {0x13d2}}},
- {0xaba3, {1|F|U, {0x13d3}}},
- {0xaba4, {1|F|U, {0x13d4}}},
- {0xaba5, {1|F|U, {0x13d5}}},
- {0xaba6, {1|F|U, {0x13d6}}},
- {0xaba7, {1|F|U, {0x13d7}}},
- {0xaba8, {1|F|U, {0x13d8}}},
- {0xaba9, {1|F|U, {0x13d9}}},
- {0xabaa, {1|F|U, {0x13da}}},
- {0xabab, {1|F|U, {0x13db}}},
- {0xabac, {1|F|U, {0x13dc}}},
- {0xabad, {1|F|U, {0x13dd}}},
- {0xabae, {1|F|U, {0x13de}}},
- {0xabaf, {1|F|U, {0x13df}}},
- {0xabb0, {1|F|U, {0x13e0}}},
- {0xabb1, {1|F|U, {0x13e1}}},
- {0xabb2, {1|F|U, {0x13e2}}},
- {0xabb3, {1|F|U, {0x13e3}}},
- {0xabb4, {1|F|U, {0x13e4}}},
- {0xabb5, {1|F|U, {0x13e5}}},
- {0xabb6, {1|F|U, {0x13e6}}},
- {0xabb7, {1|F|U, {0x13e7}}},
- {0xabb8, {1|F|U, {0x13e8}}},
- {0xabb9, {1|F|U, {0x13e9}}},
- {0xabba, {1|F|U, {0x13ea}}},
- {0xabbb, {1|F|U, {0x13eb}}},
- {0xabbc, {1|F|U, {0x13ec}}},
- {0xabbd, {1|F|U, {0x13ed}}},
- {0xabbe, {1|F|U, {0x13ee}}},
- {0xabbf, {1|F|U, {0x13ef}}},
- {0xfb00, {2|F|ST|SU|I(366), {0x0066, 0x0066}}},
- {0xfb01, {2|F|ST|SU|I(370), {0x0066, 0x0069}}},
- {0xfb02, {2|F|ST|SU|I(374), {0x0066, 0x006c}}},
- {0xfb03, {3|F|ST|SU|I(378), {0x0066, 0x0066, 0x0069}}},
- {0xfb04, {3|F|ST|SU|I(384), {0x0066, 0x0066, 0x006c}}},
- {0xfb05, {2|F|ST|SU|I(390), {0x0073, 0x0074}}},
- {0xfb06, {2|F|ST|SU|I(394), {0x0073, 0x0074}}},
- {0xfb13, {2|F|ST|SU|I(398), {0x0574, 0x0576}}},
- {0xfb14, {2|F|ST|SU|I(402), {0x0574, 0x0565}}},
- {0xfb15, {2|F|ST|SU|I(406), {0x0574, 0x056b}}},
- {0xfb16, {2|F|ST|SU|I(410), {0x057e, 0x0576}}},
- {0xfb17, {2|F|ST|SU|I(414), {0x0574, 0x056d}}},
- {0xff21, {1|F|D, {0xff41}}},
- {0xff22, {1|F|D, {0xff42}}},
- {0xff23, {1|F|D, {0xff43}}},
- {0xff24, {1|F|D, {0xff44}}},
- {0xff25, {1|F|D, {0xff45}}},
- {0xff26, {1|F|D, {0xff46}}},
- {0xff27, {1|F|D, {0xff47}}},
- {0xff28, {1|F|D, {0xff48}}},
- {0xff29, {1|F|D, {0xff49}}},
- {0xff2a, {1|F|D, {0xff4a}}},
- {0xff2b, {1|F|D, {0xff4b}}},
- {0xff2c, {1|F|D, {0xff4c}}},
- {0xff2d, {1|F|D, {0xff4d}}},
- {0xff2e, {1|F|D, {0xff4e}}},
- {0xff2f, {1|F|D, {0xff4f}}},
- {0xff30, {1|F|D, {0xff50}}},
- {0xff31, {1|F|D, {0xff51}}},
- {0xff32, {1|F|D, {0xff52}}},
- {0xff33, {1|F|D, {0xff53}}},
- {0xff34, {1|F|D, {0xff54}}},
- {0xff35, {1|F|D, {0xff55}}},
- {0xff36, {1|F|D, {0xff56}}},
- {0xff37, {1|F|D, {0xff57}}},
- {0xff38, {1|F|D, {0xff58}}},
- {0xff39, {1|F|D, {0xff59}}},
- {0xff3a, {1|F|D, {0xff5a}}},
- {0x10400, {1|F|D, {0x10428}}},
- {0x10401, {1|F|D, {0x10429}}},
- {0x10402, {1|F|D, {0x1042a}}},
- {0x10403, {1|F|D, {0x1042b}}},
- {0x10404, {1|F|D, {0x1042c}}},
- {0x10405, {1|F|D, {0x1042d}}},
- {0x10406, {1|F|D, {0x1042e}}},
- {0x10407, {1|F|D, {0x1042f}}},
- {0x10408, {1|F|D, {0x10430}}},
- {0x10409, {1|F|D, {0x10431}}},
- {0x1040a, {1|F|D, {0x10432}}},
- {0x1040b, {1|F|D, {0x10433}}},
- {0x1040c, {1|F|D, {0x10434}}},
- {0x1040d, {1|F|D, {0x10435}}},
- {0x1040e, {1|F|D, {0x10436}}},
- {0x1040f, {1|F|D, {0x10437}}},
- {0x10410, {1|F|D, {0x10438}}},
- {0x10411, {1|F|D, {0x10439}}},
- {0x10412, {1|F|D, {0x1043a}}},
- {0x10413, {1|F|D, {0x1043b}}},
- {0x10414, {1|F|D, {0x1043c}}},
- {0x10415, {1|F|D, {0x1043d}}},
- {0x10416, {1|F|D, {0x1043e}}},
- {0x10417, {1|F|D, {0x1043f}}},
- {0x10418, {1|F|D, {0x10440}}},
- {0x10419, {1|F|D, {0x10441}}},
- {0x1041a, {1|F|D, {0x10442}}},
- {0x1041b, {1|F|D, {0x10443}}},
- {0x1041c, {1|F|D, {0x10444}}},
- {0x1041d, {1|F|D, {0x10445}}},
- {0x1041e, {1|F|D, {0x10446}}},
- {0x1041f, {1|F|D, {0x10447}}},
- {0x10420, {1|F|D, {0x10448}}},
- {0x10421, {1|F|D, {0x10449}}},
- {0x10422, {1|F|D, {0x1044a}}},
- {0x10423, {1|F|D, {0x1044b}}},
- {0x10424, {1|F|D, {0x1044c}}},
- {0x10425, {1|F|D, {0x1044d}}},
- {0x10426, {1|F|D, {0x1044e}}},
- {0x10427, {1|F|D, {0x1044f}}},
- {0x104b0, {1|F|D, {0x104d8}}},
- {0x104b1, {1|F|D, {0x104d9}}},
- {0x104b2, {1|F|D, {0x104da}}},
- {0x104b3, {1|F|D, {0x104db}}},
- {0x104b4, {1|F|D, {0x104dc}}},
- {0x104b5, {1|F|D, {0x104dd}}},
- {0x104b6, {1|F|D, {0x104de}}},
- {0x104b7, {1|F|D, {0x104df}}},
- {0x104b8, {1|F|D, {0x104e0}}},
- {0x104b9, {1|F|D, {0x104e1}}},
- {0x104ba, {1|F|D, {0x104e2}}},
- {0x104bb, {1|F|D, {0x104e3}}},
- {0x104bc, {1|F|D, {0x104e4}}},
- {0x104bd, {1|F|D, {0x104e5}}},
- {0x104be, {1|F|D, {0x104e6}}},
- {0x104bf, {1|F|D, {0x104e7}}},
- {0x104c0, {1|F|D, {0x104e8}}},
- {0x104c1, {1|F|D, {0x104e9}}},
- {0x104c2, {1|F|D, {0x104ea}}},
- {0x104c3, {1|F|D, {0x104eb}}},
- {0x104c4, {1|F|D, {0x104ec}}},
- {0x104c5, {1|F|D, {0x104ed}}},
- {0x104c6, {1|F|D, {0x104ee}}},
- {0x104c7, {1|F|D, {0x104ef}}},
- {0x104c8, {1|F|D, {0x104f0}}},
- {0x104c9, {1|F|D, {0x104f1}}},
- {0x104ca, {1|F|D, {0x104f2}}},
- {0x104cb, {1|F|D, {0x104f3}}},
- {0x104cc, {1|F|D, {0x104f4}}},
- {0x104cd, {1|F|D, {0x104f5}}},
- {0x104ce, {1|F|D, {0x104f6}}},
- {0x104cf, {1|F|D, {0x104f7}}},
- {0x104d0, {1|F|D, {0x104f8}}},
- {0x104d1, {1|F|D, {0x104f9}}},
- {0x104d2, {1|F|D, {0x104fa}}},
- {0x104d3, {1|F|D, {0x104fb}}},
- {0x10570, {1|F|D, {0x10597}}},
- {0x10571, {1|F|D, {0x10598}}},
- {0x10572, {1|F|D, {0x10599}}},
- {0x10573, {1|F|D, {0x1059a}}},
- {0x10574, {1|F|D, {0x1059b}}},
- {0x10575, {1|F|D, {0x1059c}}},
- {0x10576, {1|F|D, {0x1059d}}},
- {0x10577, {1|F|D, {0x1059e}}},
- {0x10578, {1|F|D, {0x1059f}}},
- {0x10579, {1|F|D, {0x105a0}}},
- {0x1057a, {1|F|D, {0x105a1}}},
- {0x1057c, {1|F|D, {0x105a3}}},
- {0x1057d, {1|F|D, {0x105a4}}},
- {0x1057e, {1|F|D, {0x105a5}}},
- {0x1057f, {1|F|D, {0x105a6}}},
- {0x10580, {1|F|D, {0x105a7}}},
- {0x10581, {1|F|D, {0x105a8}}},
- {0x10582, {1|F|D, {0x105a9}}},
- {0x10583, {1|F|D, {0x105aa}}},
- {0x10584, {1|F|D, {0x105ab}}},
- {0x10585, {1|F|D, {0x105ac}}},
- {0x10586, {1|F|D, {0x105ad}}},
- {0x10587, {1|F|D, {0x105ae}}},
- {0x10588, {1|F|D, {0x105af}}},
- {0x10589, {1|F|D, {0x105b0}}},
- {0x1058a, {1|F|D, {0x105b1}}},
- {0x1058c, {1|F|D, {0x105b3}}},
- {0x1058d, {1|F|D, {0x105b4}}},
- {0x1058e, {1|F|D, {0x105b5}}},
- {0x1058f, {1|F|D, {0x105b6}}},
- {0x10590, {1|F|D, {0x105b7}}},
- {0x10591, {1|F|D, {0x105b8}}},
- {0x10592, {1|F|D, {0x105b9}}},
- {0x10594, {1|F|D, {0x105bb}}},
- {0x10595, {1|F|D, {0x105bc}}},
- {0x10c80, {1|F|D, {0x10cc0}}},
- {0x10c81, {1|F|D, {0x10cc1}}},
- {0x10c82, {1|F|D, {0x10cc2}}},
- {0x10c83, {1|F|D, {0x10cc3}}},
- {0x10c84, {1|F|D, {0x10cc4}}},
- {0x10c85, {1|F|D, {0x10cc5}}},
- {0x10c86, {1|F|D, {0x10cc6}}},
- {0x10c87, {1|F|D, {0x10cc7}}},
- {0x10c88, {1|F|D, {0x10cc8}}},
- {0x10c89, {1|F|D, {0x10cc9}}},
- {0x10c8a, {1|F|D, {0x10cca}}},
- {0x10c8b, {1|F|D, {0x10ccb}}},
- {0x10c8c, {1|F|D, {0x10ccc}}},
- {0x10c8d, {1|F|D, {0x10ccd}}},
- {0x10c8e, {1|F|D, {0x10cce}}},
- {0x10c8f, {1|F|D, {0x10ccf}}},
- {0x10c90, {1|F|D, {0x10cd0}}},
- {0x10c91, {1|F|D, {0x10cd1}}},
- {0x10c92, {1|F|D, {0x10cd2}}},
- {0x10c93, {1|F|D, {0x10cd3}}},
- {0x10c94, {1|F|D, {0x10cd4}}},
- {0x10c95, {1|F|D, {0x10cd5}}},
- {0x10c96, {1|F|D, {0x10cd6}}},
- {0x10c97, {1|F|D, {0x10cd7}}},
- {0x10c98, {1|F|D, {0x10cd8}}},
- {0x10c99, {1|F|D, {0x10cd9}}},
- {0x10c9a, {1|F|D, {0x10cda}}},
- {0x10c9b, {1|F|D, {0x10cdb}}},
- {0x10c9c, {1|F|D, {0x10cdc}}},
- {0x10c9d, {1|F|D, {0x10cdd}}},
- {0x10c9e, {1|F|D, {0x10cde}}},
- {0x10c9f, {1|F|D, {0x10cdf}}},
- {0x10ca0, {1|F|D, {0x10ce0}}},
- {0x10ca1, {1|F|D, {0x10ce1}}},
- {0x10ca2, {1|F|D, {0x10ce2}}},
- {0x10ca3, {1|F|D, {0x10ce3}}},
- {0x10ca4, {1|F|D, {0x10ce4}}},
- {0x10ca5, {1|F|D, {0x10ce5}}},
- {0x10ca6, {1|F|D, {0x10ce6}}},
- {0x10ca7, {1|F|D, {0x10ce7}}},
- {0x10ca8, {1|F|D, {0x10ce8}}},
- {0x10ca9, {1|F|D, {0x10ce9}}},
- {0x10caa, {1|F|D, {0x10cea}}},
- {0x10cab, {1|F|D, {0x10ceb}}},
- {0x10cac, {1|F|D, {0x10cec}}},
- {0x10cad, {1|F|D, {0x10ced}}},
- {0x10cae, {1|F|D, {0x10cee}}},
- {0x10caf, {1|F|D, {0x10cef}}},
- {0x10cb0, {1|F|D, {0x10cf0}}},
- {0x10cb1, {1|F|D, {0x10cf1}}},
- {0x10cb2, {1|F|D, {0x10cf2}}},
- {0x10d50, {1|F|D, {0x10d70}}},
- {0x10d51, {1|F|D, {0x10d71}}},
- {0x10d52, {1|F|D, {0x10d72}}},
- {0x10d53, {1|F|D, {0x10d73}}},
- {0x10d54, {1|F|D, {0x10d74}}},
- {0x10d55, {1|F|D, {0x10d75}}},
- {0x10d56, {1|F|D, {0x10d76}}},
- {0x10d57, {1|F|D, {0x10d77}}},
- {0x10d58, {1|F|D, {0x10d78}}},
- {0x10d59, {1|F|D, {0x10d79}}},
- {0x10d5a, {1|F|D, {0x10d7a}}},
- {0x10d5b, {1|F|D, {0x10d7b}}},
- {0x10d5c, {1|F|D, {0x10d7c}}},
- {0x10d5d, {1|F|D, {0x10d7d}}},
- {0x10d5e, {1|F|D, {0x10d7e}}},
- {0x10d5f, {1|F|D, {0x10d7f}}},
- {0x10d60, {1|F|D, {0x10d80}}},
- {0x10d61, {1|F|D, {0x10d81}}},
- {0x10d62, {1|F|D, {0x10d82}}},
- {0x10d63, {1|F|D, {0x10d83}}},
- {0x10d64, {1|F|D, {0x10d84}}},
- {0x10d65, {1|F|D, {0x10d85}}},
- {0x118a0, {1|F|D, {0x118c0}}},
- {0x118a1, {1|F|D, {0x118c1}}},
- {0x118a2, {1|F|D, {0x118c2}}},
- {0x118a3, {1|F|D, {0x118c3}}},
- {0x118a4, {1|F|D, {0x118c4}}},
- {0x118a5, {1|F|D, {0x118c5}}},
- {0x118a6, {1|F|D, {0x118c6}}},
- {0x118a7, {1|F|D, {0x118c7}}},
- {0x118a8, {1|F|D, {0x118c8}}},
- {0x118a9, {1|F|D, {0x118c9}}},
- {0x118aa, {1|F|D, {0x118ca}}},
- {0x118ab, {1|F|D, {0x118cb}}},
- {0x118ac, {1|F|D, {0x118cc}}},
- {0x118ad, {1|F|D, {0x118cd}}},
- {0x118ae, {1|F|D, {0x118ce}}},
- {0x118af, {1|F|D, {0x118cf}}},
- {0x118b0, {1|F|D, {0x118d0}}},
- {0x118b1, {1|F|D, {0x118d1}}},
- {0x118b2, {1|F|D, {0x118d2}}},
- {0x118b3, {1|F|D, {0x118d3}}},
- {0x118b4, {1|F|D, {0x118d4}}},
- {0x118b5, {1|F|D, {0x118d5}}},
- {0x118b6, {1|F|D, {0x118d6}}},
- {0x118b7, {1|F|D, {0x118d7}}},
- {0x118b8, {1|F|D, {0x118d8}}},
- {0x118b9, {1|F|D, {0x118d9}}},
- {0x118ba, {1|F|D, {0x118da}}},
- {0x118bb, {1|F|D, {0x118db}}},
- {0x118bc, {1|F|D, {0x118dc}}},
- {0x118bd, {1|F|D, {0x118dd}}},
- {0x118be, {1|F|D, {0x118de}}},
- {0x118bf, {1|F|D, {0x118df}}},
- {0x16e40, {1|F|D, {0x16e60}}},
- {0x16e41, {1|F|D, {0x16e61}}},
- {0x16e42, {1|F|D, {0x16e62}}},
- {0x16e43, {1|F|D, {0x16e63}}},
- {0x16e44, {1|F|D, {0x16e64}}},
- {0x16e45, {1|F|D, {0x16e65}}},
- {0x16e46, {1|F|D, {0x16e66}}},
- {0x16e47, {1|F|D, {0x16e67}}},
- {0x16e48, {1|F|D, {0x16e68}}},
- {0x16e49, {1|F|D, {0x16e69}}},
- {0x16e4a, {1|F|D, {0x16e6a}}},
- {0x16e4b, {1|F|D, {0x16e6b}}},
- {0x16e4c, {1|F|D, {0x16e6c}}},
- {0x16e4d, {1|F|D, {0x16e6d}}},
- {0x16e4e, {1|F|D, {0x16e6e}}},
- {0x16e4f, {1|F|D, {0x16e6f}}},
- {0x16e50, {1|F|D, {0x16e70}}},
- {0x16e51, {1|F|D, {0x16e71}}},
- {0x16e52, {1|F|D, {0x16e72}}},
- {0x16e53, {1|F|D, {0x16e73}}},
- {0x16e54, {1|F|D, {0x16e74}}},
- {0x16e55, {1|F|D, {0x16e75}}},
- {0x16e56, {1|F|D, {0x16e76}}},
- {0x16e57, {1|F|D, {0x16e77}}},
- {0x16e58, {1|F|D, {0x16e78}}},
- {0x16e59, {1|F|D, {0x16e79}}},
- {0x16e5a, {1|F|D, {0x16e7a}}},
- {0x16e5b, {1|F|D, {0x16e7b}}},
- {0x16e5c, {1|F|D, {0x16e7c}}},
- {0x16e5d, {1|F|D, {0x16e7d}}},
- {0x16e5e, {1|F|D, {0x16e7e}}},
- {0x16e5f, {1|F|D, {0x16e7f}}},
- {0x1e900, {1|F|D, {0x1e922}}},
- {0x1e901, {1|F|D, {0x1e923}}},
- {0x1e902, {1|F|D, {0x1e924}}},
- {0x1e903, {1|F|D, {0x1e925}}},
- {0x1e904, {1|F|D, {0x1e926}}},
- {0x1e905, {1|F|D, {0x1e927}}},
- {0x1e906, {1|F|D, {0x1e928}}},
- {0x1e907, {1|F|D, {0x1e929}}},
- {0x1e908, {1|F|D, {0x1e92a}}},
- {0x1e909, {1|F|D, {0x1e92b}}},
- {0x1e90a, {1|F|D, {0x1e92c}}},
- {0x1e90b, {1|F|D, {0x1e92d}}},
- {0x1e90c, {1|F|D, {0x1e92e}}},
- {0x1e90d, {1|F|D, {0x1e92f}}},
- {0x1e90e, {1|F|D, {0x1e930}}},
- {0x1e90f, {1|F|D, {0x1e931}}},
- {0x1e910, {1|F|D, {0x1e932}}},
- {0x1e911, {1|F|D, {0x1e933}}},
- {0x1e912, {1|F|D, {0x1e934}}},
- {0x1e913, {1|F|D, {0x1e935}}},
- {0x1e914, {1|F|D, {0x1e936}}},
- {0x1e915, {1|F|D, {0x1e937}}},
- {0x1e916, {1|F|D, {0x1e938}}},
- {0x1e917, {1|F|D, {0x1e939}}},
- {0x1e918, {1|F|D, {0x1e93a}}},
- {0x1e919, {1|F|D, {0x1e93b}}},
- {0x1e91a, {1|F|D, {0x1e93c}}},
- {0x1e91b, {1|F|D, {0x1e93d}}},
- {0x1e91c, {1|F|D, {0x1e93e}}},
- {0x1e91d, {1|F|D, {0x1e93f}}},
- {0x1e91e, {1|F|D, {0x1e940}}},
- {0x1e91f, {1|F|D, {0x1e941}}},
- {0x1e920, {1|F|D, {0x1e942}}},
- {0x1e921, {1|F|D, {0x1e943}}},
-#define CaseFold_Locale (*(CaseFold_11_Type (*)[2])(CaseFold_11_Table+1555))
- {0x0049, {1|F|D, {0x0069}}},
- {0x0130, {2|F|D, {0x0069, 0x0307}}},
-};
-
-/* ANSI-C code produced by gperf version 3.1 */
-/* Command-line: gperf -7 -k1,2,3 -F,-1 -c -j1 -i1 -t -T -E -C -H onigenc_unicode_CaseFold_11_hash -N onigenc_unicode_CaseFold_11_lookup -n */
-
-/* maximum key range = 3358, duplicates = 0 */
-
-#ifdef __GNUC__
-__inline
-#else
-#ifdef __cplusplus
-inline
-#endif
-#endif
-/*ARGSUSED*/
-static unsigned int
-onigenc_unicode_CaseFold_11_hash(const OnigCodePoint code)
-{
- static const unsigned short asso_values[] =
- {
- 2, 271, 6, 43, 1, 1, 64, 14, 5, 396,
- 239, 791, 3364, 3364, 3364, 3364, 3364, 3364, 3364, 3364,
- 3364, 3364, 3364, 3364, 3364, 45, 553, 3364, 3364, 3364,
- 3364, 3364, 3364, 400, 3364, 3364, 3364, 3364, 3364, 11,
- 3364, 3364, 3364, 3364, 3364, 3364, 3364, 3364, 3364, 500,
- 3364, 3364, 3364, 3364, 3364, 3364, 3364, 163, 3364, 3364,
- 311, 310, 445, 3, 3364, 3364, 129, 15, 3364, 3364,
- 3364, 3364, 3364, 410, 3364, 3364, 400, 863, 428, 38,
- 2012, 226, 42, 182, 2175, 94, 1252, 7, 12, 24,
- 2080, 764, 1166, 684, 1635, 168, 1891, 308, 1977, 153,
- 1790, 108, 1520, 261, 1811, 426, 1766, 484, 1720, 506,
- 2127, 286, 1445, 411, 1715, 366, 1703, 352, 60, 667,
- 1428, 551, 1322, 611, 1650, 597, 631, 614, 1994, 691,
- 82, 876, 1670, 870, 1699, 707, 1301, 542, 1886, 816,
- 1751, 822, 1813, 1101, 1662, 1117, 3, 1003, 1187, 1134,
- 1275, 989, 1600, 933, 1567, 925, 1764, 1197, 1051, 843,
- 1847, 1034, 212, 1071, 1244, 1020, 85, 1143, 30, 942,
- 17, 1478, 308, 1394, 203, 1476, 26, 1347, 178, 1380,
- 24, 1629, 104, 1574, 123, 1553, 520, 1547, 122, 1608,
- 2, 135, 38, 1613, 55, 1826, 206, 1996, 281, 2105,
- 488, 1794, 348, 1917, 368, 1655, 235
- };
- return asso_values[bits_of(code, 2)+79] + asso_values[bits_of(code, 1)] + asso_values[bits_of(code, 0)];
-}
-
-static const CodePointList3 *
-onigenc_unicode_CaseFold_11_lookup(const OnigCodePoint code)
-{
- enum
- {
- MIN_CODE_VALUE = 0x41,
- MAX_CODE_VALUE = 0x1e921,
- TOTAL_KEYWORDS = 1557,
- MIN_WORD_LENGTH = 3,
- MAX_WORD_LENGTH = 3,
- MIN_HASH_VALUE = 6,
- MAX_HASH_VALUE = 3363
- };
-
- static const short wordlist[] =
- {
- -1, -1, -1, -1, -1, -1,
- /*0x0243*/ 221,
- /*0x0043*/ 2,
- /*0x1fc3*/ 828,
- -1,
- /*0x0208*/ 194,
- /*0x0143*/ 89,
- /*0x1f88*/ 776,
- /*0x10408*/ 1281,
- /*0x0408*/ 305,
- /*0x0108*/ 61,
- /*0x2c6f*/ 969,
- /*0x1f89*/ 777,
- /*0x10409*/ 1282,
- /*0x0409*/ 306,
- /*0xab88*/ 1179,
- /*0x2c08*/ 920,
- /*0x1fdb*/ 844,
- /*0x0388*/ 235,
- -1,
- /*0xab89*/ 1180,
- /*0x2c09*/ 921,
- /*0x020a*/ 195,
- /*0x0389*/ 236,
- /*0x1f8a*/ 778,
- /*0x1040a*/ 1283,
- /*0x040a*/ 307,
- /*0x010a*/ 62,
- /*0x2c88*/ 979,
- /*0x0059*/ 23,
- /*0x1fd9*/ 842,
- -1,
- /*0xab8a*/ 1181,
- /*0x2c0a*/ 922,
- -1,
- /*0x038a*/ 237,
- /*0x0200*/ 190,
- -1,
- /*0x1f80*/ 768,
- /*0x10400*/ 1273,
- /*0x0400*/ 297,
- /*0x0100*/ 57,
- /*0x1f83*/ 771,
- /*0x10403*/ 1276,
- /*0x0403*/ 300,
- /*0x2c8a*/ 980,
- /*0xab80*/ 1171,
- /*0x2c00*/ 912,
- /*0x10c88*/ 1392,
- /*0x03f1*/ 288,
- /*0xab83*/ 1174,
- /*0x2c03*/ 915,
- /*0x0189*/ 126,
- /*0x10c89*/ 1393,
- /*0x2183*/ 885,
- /*0x1ff3*/ 856,
- -1,
- /*0x01db*/ 170,
- /*0x1e908*/ 1529,
- /*0x2c80*/ 975,
- /*0x1fa7*/ 807,
- /*0x10427*/ 1312,
- /*0x0427*/ 336,
- /*0x1e909*/ 1530,
- /*0x018a*/ 127,
- /*0x10c8a*/ 1394,
- -1, -1,
- /*0xaba7*/ 1210,
- /*0x2c27*/ 951,
- /*0x01d9*/ 169,
- /*0x03a7*/ 263,
- -1, -1, -1,
- /*0x1e90a*/ 1531,
- -1,
- /*0xa780*/ 1107,
- /*0x01f1*/ 181,
- /*0x10c80*/ 1384,
- -1, -1,
- /*0x1fb3*/ 817,
- /*0x10c83*/ 1387,
- /*0x0057*/ 21,
- /*0x1fd7*/ 840,
- -1, -1, -1,
- /*0x1e900*/ 1521,
- /*0xabb3*/ 1222,
- -1,
- /*0x0206*/ 193,
- /*0x1e903*/ 1524,
- /*0x1f86*/ 774,
- /*0x10406*/ 1279,
- /*0x0406*/ 303,
- /*0x0106*/ 60,
- -1, -1,
- /*0x01a7*/ 145,
- /*0x10ca7*/ 1423,
- /*0xab86*/ 1177,
- /*0x2c06*/ 918,
- /*0x1fe7*/ 849,
- /*0x0386*/ 234,
- /*0x0216*/ 201,
- -1,
- /*0x1f96*/ 790,
- /*0x10416*/ 1295,
- /*0x0416*/ 319,
- /*0x0116*/ 68,
- -1,
- /*0x2c67*/ 964,
- -1,
- /*0x2c86*/ 978,
- /*0xab96*/ 1193,
- /*0x2c16*/ 934,
- -1,
- /*0x0396*/ 247,
- -1,
- /*0xa7b3*/ 1133,
- /*0x01b3*/ 152,
- /*0x1fe9*/ 851,
- -1,
- /*0x01d7*/ 168,
- -1, -1,
- /*0x216f*/ 884,
- /*0x2c96*/ 986,
- -1,
- /*0x2c6d*/ 967,
- /*0x2c69*/ 965,
- /*0xa786*/ 1110,
- /*0x0186*/ 124,
- /*0x10c86*/ 1390,
- /*0xfb00*/ 1235,
- /*0x0470*/ 353,
- /*0x0170*/ 112,
- -1,
- /*0xfb03*/ 1238,
- -1, -1,
- /*0x2ced*/ 1026,
- /*0x2c70*/ 970,
- /*0x1e906*/ 1527,
- /*0x03f0*/ 287,
- /*0xa796*/ 1115,
- /*0x0196*/ 135,
- /*0x10c96*/ 1406,
- /*0x2165*/ 874,
- /*0x0214*/ 200,
- /*0x2161*/ 870,
- /*0x1f94*/ 788,
- /*0x10414*/ 1293,
- /*0x0414*/ 317,
- /*0x0114*/ 67,
- -1, -1,
- /*0x1e916*/ 1543,
- -1,
- /*0xab94*/ 1191,
- /*0x2c14*/ 932,
- -1,
- /*0x0394*/ 245,
- -1,
- /*0x0210*/ 198,
- /*0x1c88*/ 538,
- /*0x1f90*/ 784,
- /*0x10410*/ 1289,
- /*0x0410*/ 313,
- /*0x0110*/ 65,
- /*0x1c89*/ 539,
- -1,
- /*0x2c94*/ 985,
- /*0x01f0*/ 180,
- /*0xab90*/ 1187,
- /*0x2c10*/ 928,
- /*0x1fe3*/ 846,
- /*0x0390*/ 241,
- /*0x0204*/ 192,
- -1,
- /*0x1f84*/ 772,
- /*0x10404*/ 1277,
- /*0x0404*/ 301,
- /*0x0104*/ 59,
- -1,
- /*0x2c63*/ 962,
- -1,
- /*0x2c90*/ 983,
- /*0xab84*/ 1175,
- /*0x2c04*/ 916,
- /*0xfb06*/ 1241,
- /*0x0194*/ 134,
- /*0x10c94*/ 1404,
- -1,
- /*0x0370*/ 230,
- -1,
- /*0x1c80*/ 530,
- -1, -1, -1,
- /*0x1c83*/ 533,
- /*0x2c84*/ 977,
- /*0x1e914*/ 1541,
- -1,
- /*0xfb16*/ 1245,
- /*0xa790*/ 1113,
- /*0x0190*/ 131,
- /*0x10c90*/ 1400,
- -1,
- /*0x0053*/ 17,
- /*0x1fd3*/ 838,
- -1, -1,
- /*0x2c75*/ 972,
- -1,
- /*0x03f5*/ 290,
- -1,
- /*0x1e910*/ 1537,
- /*0x1ca7*/ 563,
- /*0xa784*/ 1109,
- /*0x0184*/ 123,
- /*0x10c84*/ 1388,
- /*0x0202*/ 191,
- -1,
- /*0x1f82*/ 770,
- /*0x10402*/ 1275,
- /*0x0402*/ 299,
- /*0x0102*/ 58,
- /*0x2167*/ 876,
- -1, -1,
- /*0x1e904*/ 1525,
- /*0xab82*/ 1173,
- /*0x2c02*/ 914,
- -1, -1,
- /*0x017f*/ 120,
- /*0x0543*/ 463,
- -1, -1,
- /*0x1cb3*/ 575,
- /*0x0508*/ 425,
- /*0x2c7f*/ 974,
- /*0xa7f5*/ 1154,
- /*0x03ff*/ 296,
- /*0x2c82*/ 976,
- /*0x216d*/ 882,
- /*0x2169*/ 878,
- -1,
- /*0xfb14*/ 1243,
- /*0x01d3*/ 166,
- -1,
- /*0x1c86*/ 536,
- -1, -1, -1, -1,
- /*0x0218*/ 202,
- /*0x050a*/ 426,
- /*0x1f98*/ 792,
- /*0x10418*/ 1297,
- /*0x0418*/ 321,
- /*0x0118*/ 69,
- /*0xa782*/ 1108,
- /*0x0182*/ 122,
- /*0x10c82*/ 1386,
- /*0x1c96*/ 546,
- /*0xab98*/ 1195,
- /*0x2c18*/ 936,
- /*0x00c3*/ 29,
- /*0x0398*/ 249,
- /*0x10571*/ 1350,
- /*0x0500*/ 421,
- -1, -1,
- /*0x1e902*/ 1523,
- -1, -1,
- /*0xfb04*/ 1239,
- /*0x1ff7*/ 859,
- /*0x2c98*/ 987,
- -1,
- /*0x0220*/ 206,
- /*0x00db*/ 52,
- /*0x1fa0*/ 800,
- /*0x10420*/ 1305,
- /*0x0420*/ 329,
- /*0x0120*/ 73,
- /*0x10573*/ 1352,
- -1,
- /*0x03f7*/ 291,
- -1,
- /*0xaba0*/ 1203,
- /*0x2c20*/ 944,
- /*0x037f*/ 233,
- /*0x03a0*/ 257,
- /*0x00d9*/ 50,
- -1,
- /*0xa798*/ 1116,
- /*0x0198*/ 137,
- /*0x10c98*/ 1408,
- -1,
- /*0x2163*/ 872,
- -1,
- /*0x0212*/ 199,
- /*0x2ca0*/ 991,
- /*0x1f92*/ 786,
- /*0x10412*/ 1291,
- /*0x0412*/ 315,
- /*0x0112*/ 66,
- /*0x1e918*/ 1545,
- /*0x1c94*/ 544,
- /*0x1e88*/ 654,
- /*0x1e08*/ 590,
- /*0xab92*/ 1189,
- /*0x2c12*/ 930,
- /*0x0533*/ 447,
- /*0x0392*/ 243,
- -1,
- /*0x01f7*/ 185,
- -1, -1,
- /*0xfb02*/ 1237,
- /*0xa7a0*/ 1120,
- /*0x01a0*/ 141,
- /*0x10ca0*/ 1416,
- /*0x1c90*/ 540,
- /*0x2c92*/ 984,
- /*0x0506*/ 424,
- /*0x1e8a*/ 655,
- /*0x1e0a*/ 591,
- -1, -1, -1, -1,
- /*0x1e920*/ 1553,
- -1, -1, -1, -1,
- /*0x1c84*/ 534,
- -1,
- /*0x0516*/ 432,
- /*0x1e80*/ 650,
- /*0x1e00*/ 586,
- /*0xa792*/ 1114,
- /*0x1ffb*/ 863,
- /*0x10c92*/ 1402,
- /*0x0226*/ 209,
- /*0x017b*/ 118,
- /*0x1fa6*/ 806,
- /*0x10426*/ 1311,
- /*0x0426*/ 335,
- /*0x0126*/ 76,
- /*0x13fb*/ 527,
- -1, -1,
- /*0x1e912*/ 1539,
- /*0xaba6*/ 1209,
- /*0x2c26*/ 950,
- -1,
- /*0x03a6*/ 262,
- /*0x0224*/ 208,
- -1,
- /*0x1fa4*/ 804,
- /*0x10424*/ 1309,
- /*0x0424*/ 333,
- /*0x0124*/ 75,
- /*0x10570*/ 1349,
- /*0x017d*/ 119,
- -1,
- /*0x2ca6*/ 994,
- /*0xaba4*/ 1207,
- /*0x2c24*/ 948,
- /*0x13fd*/ 529,
- /*0x03a4*/ 260,
- -1,
- /*0x03fd*/ 294,
- -1, -1, -1, -1, -1, -1,
- /*0x1c82*/ 532,
- /*0x2ca4*/ 993,
- -1,
- /*0x0514*/ 431,
- -1,
- /*0xa7a6*/ 1123,
- /*0x01a6*/ 144,
- /*0x10ca6*/ 1422,
- -1,
- /*0x104c3*/ 1332,
- /*0x04c3*/ 391,
- -1, -1, -1,
- /*0x10c3*/ 519,
- /*0x1e86*/ 653,
- /*0x1e06*/ 589,
- -1,
- /*0x0510*/ 429,
- /*0xa7a4*/ 1122,
- /*0x01a4*/ 143,
- /*0x10ca4*/ 1420,
- -1,
- /*0x0222*/ 207,
- /*0x24c3*/ 899,
- /*0x1fa2*/ 802,
- /*0x10422*/ 1307,
- /*0x0422*/ 331,
- /*0x0122*/ 74,
- /*0x1e96*/ 661,
- /*0x1e16*/ 597,
- /*0x048a*/ 362,
- /*0x0504*/ 423,
- /*0xaba2*/ 1205,
- /*0x2c22*/ 946,
- /*0x1c98*/ 548,
- -1, -1,
- /*0x021a*/ 203,
- -1,
- /*0x1f9a*/ 794,
- /*0x1041a*/ 1299,
- /*0x041a*/ 323,
- /*0x011a*/ 70,
- -1,
- /*0x0480*/ 361,
- /*0x2ca2*/ 992,
- -1,
- /*0xab9a*/ 1197,
- /*0x2c1a*/ 938,
- -1,
- /*0x039a*/ 251,
- -1, -1, -1,
- /*0x10575*/ 1354,
- /*0x1ef0*/ 708,
- /*0x1e70*/ 642,
- /*0x1f6f*/ 767,
- -1,
- /*0x1ca0*/ 556,
- /*0x2c9a*/ 988,
- /*0x0553*/ 479,
- /*0x1f08*/ 716,
- /*0xa7a2*/ 1121,
- /*0x01a2*/ 142,
- /*0x10ca2*/ 1418,
- -1,
- /*0x1f09*/ 717,
- -1, -1,
- /*0x10a7*/ 491,
- -1,
- /*0x1f5b*/ 757,
- /*0x1e94*/ 660,
- /*0x1e14*/ 596,
- /*0x0502*/ 422,
- -1, -1,
- /*0xa79a*/ 1117,
- /*0x1f0a*/ 718,
- /*0x10c9a*/ 1410,
- /*0x1c92*/ 542,
- -1,
- /*0x1057f*/ 1363,
- /*0x00df*/ 56,
- /*0x1f59*/ 756,
- -1,
- /*0x104b3*/ 1316,
- /*0x1e90*/ 658,
- /*0x1e10*/ 594,
- /*0x1e91a*/ 1547,
- /*0x2126*/ 865,
- /*0x10b3*/ 503,
- /*0x00d3*/ 45,
- -1,
- /*0x021c*/ 204,
- -1,
- /*0x1f9c*/ 796,
- /*0x1041c*/ 1301,
- /*0x041c*/ 325,
- /*0x011c*/ 71,
- /*0x1ff9*/ 861,
- /*0x1e84*/ 652,
- /*0x1e04*/ 588,
- /*0x0179*/ 117,
- /*0xab9c*/ 1199,
- /*0x2c1c*/ 940,
- -1,
- /*0x039c*/ 253,
- /*0x13f9*/ 525,
- /*0x0518*/ 433,
- -1,
- /*0x03f9*/ 292,
- -1,
- /*0x0496*/ 368,
- -1, -1,
- /*0x021e*/ 205,
- /*0x2c9c*/ 989,
- /*0x1f9e*/ 798,
- /*0x1041e*/ 1303,
- /*0x041e*/ 327,
- /*0x011e*/ 72,
- -1, -1,
- /*0x1ca6*/ 562,
- -1,
- /*0xab9e*/ 1201,
- /*0x2c1e*/ 942,
- /*0x10577*/ 1356,
- /*0x039e*/ 255,
- -1, -1,
- /*0x1feb*/ 853,
- -1,
- /*0x0520*/ 437,
- /*0xa79c*/ 1118,
- /*0x019c*/ 138,
- /*0x10c9c*/ 1412,
- /*0x1ca4*/ 560,
- /*0x2c9e*/ 990,
- /*0x04f0*/ 413,
- /*0x2c6b*/ 966,
- -1, -1, -1,
- /*0x1e82*/ 651,
- /*0x1e02*/ 587,
- /*0x1e91c*/ 1549,
- -1, -1, -1, -1,
- /*0x023a*/ 216,
- /*0x2ceb*/ 1025,
- /*0x1fba*/ 823,
- -1,
- /*0x0512*/ 430,
- /*0xa79e*/ 1119,
- /*0x0494*/ 367,
- /*0x10c9e*/ 1414,
- -1,
- /*0x022a*/ 211,
- /*0xabba*/ 1229,
- /*0x1faa*/ 810,
- -1,
- /*0x042a*/ 339,
- /*0x012a*/ 78,
- -1,
- /*0x118a7*/ 1464,
- /*0x1e91e*/ 1551,
- -1,
- /*0xabaa*/ 1213,
- /*0x2c2a*/ 954,
- /*0x0490*/ 365,
- /*0x03aa*/ 266,
- /*0x2cba*/ 1004,
- /*0x1f6d*/ 765,
- /*0x1f69*/ 761,
- /*0x10d5b*/ 1446,
- -1,
- /*0x1e98*/ 663,
- /*0x1e18*/ 598,
- -1,
- /*0x1ca2*/ 558,
- /*0x2caa*/ 996,
- /*0x10d65*/ 1456,
- -1,
- /*0x10d61*/ 1452,
- /*0x00dd*/ 54,
- -1,
- /*0x118b3*/ 1476,
- /*0x10d59*/ 1444,
- -1,
- /*0xa7ba*/ 1137,
- -1, -1, -1, -1,
- /*0x1c9a*/ 550,
- -1,
- /*0x0526*/ 440,
- -1,
- /*0xa7aa*/ 1125,
- -1,
- /*0x10caa*/ 1426,
- /*0x1ea0*/ 668,
- /*0x1e20*/ 602,
- /*0x022e*/ 213,
- -1,
- /*0x1fae*/ 814,
- -1,
- /*0x042e*/ 343,
- /*0x012e*/ 80,
- -1,
- /*0x0524*/ 439,
- /*0x1057d*/ 1361,
- /*0x104d3*/ 1348,
- /*0xabae*/ 1217,
- /*0x2c2e*/ 958,
- -1, -1,
- /*0x022c*/ 212,
- -1,
- /*0x1fac*/ 812,
- /*0x0230*/ 214,
- /*0x042c*/ 341,
- /*0x012c*/ 79,
- /*0x1e92*/ 659,
- /*0x1e12*/ 595,
- /*0x0130*/ 1556,
- /*0x2cae*/ 998,
- /*0xabac*/ 1215,
- /*0x2c2c*/ 956,
- -1,
- /*0xabb0*/ 1219,
- -1, -1,
- /*0x03b0*/ 268,
- -1, -1, -1, -1, -1,
- /*0x1faf*/ 815,
- /*0x2cac*/ 997,
- /*0x042f*/ 344,
- /*0x10d57*/ 1442,
- /*0x2cb0*/ 999,
- /*0xa7ae*/ 1129,
- /*0x01ae*/ 148,
- /*0x10cae*/ 1430,
- /*0xabaf*/ 1218,
- /*0x2c2f*/ 959,
- -1, -1, -1,
- /*0x1c9c*/ 552,
- /*0x1f5f*/ 759,
- /*0x216b*/ 880,
- /*0x0522*/ 438,
- -1, -1,
- /*0xa7ac*/ 1127,
- /*0x01ac*/ 147,
- /*0x10cac*/ 1428,
- /*0xa7b0*/ 1130,
- /*0x0498*/ 369,
- /*0x10cb0*/ 1432,
- -1, -1, -1,
- /*0x1ea6*/ 671,
- /*0x1e26*/ 605,
- -1,
- /*0x051a*/ 434,
- -1, -1,
- /*0x0228*/ 210,
- /*0x1c9e*/ 554,
- /*0x1fa8*/ 808,
- -1,
- /*0x0428*/ 337,
- /*0x0128*/ 77,
- /*0x01af*/ 149,
- /*0x10caf*/ 1431,
- /*0x1ea4*/ 670,
- /*0x1e24*/ 604,
- /*0xaba8*/ 1211,
- /*0x2c28*/ 952,
- /*0x212a*/ 866,
- /*0x03a8*/ 264,
- /*0x04a0*/ 373,
- -1, -1,
- /*0x020e*/ 197,
- /*0x10a0*/ 484,
- /*0x1f8e*/ 782,
- /*0x1040e*/ 1287,
- /*0x040e*/ 311,
- /*0x010e*/ 64,
- /*0x2ca8*/ 995,
- /*0x0232*/ 215,
- -1,
- /*0x1fb2*/ 816,
- /*0xab8e*/ 1185,
- /*0x2c0e*/ 926,
- /*0x0132*/ 81,
- /*0x038e*/ 239,
- -1, -1, -1,
- /*0xabb2*/ 1221,
- -1,
- /*0x0492*/ 366,
- /*0x1cba*/ 582,
- /*0x1f18*/ 724,
- -1,
- /*0x2c8e*/ 982,
- /*0xa7a8*/ 1124,
- /*0x1fb8*/ 821,
- /*0x10ca8*/ 1424,
- -1, -1,
- /*0x1caa*/ 566,
- /*0x2cb2*/ 1000,
- -1, -1,
- /*0xabb8*/ 1227,
- -1, -1,
- /*0x1ea2*/ 669,
- /*0x1e22*/ 603,
- /*0x051c*/ 435,
- -1, -1,
- /*0x10579*/ 1358,
- /*0x018e*/ 129,
- /*0x10c8e*/ 1398,
- -1,
- /*0x10d63*/ 1454,
- /*0x2cb8*/ 1003,
- /*0xff27*/ 1253,
- /*0xa7b2*/ 1132,
- /*0x01b2*/ 151,
- /*0x10cb2*/ 1434,
- /*0x1e9a*/ 665,
- /*0x1e1a*/ 599,
- /*0x1e90e*/ 1535,
- -1, -1, -1, -1, -1, -1,
- /*0x051e*/ 436,
- -1, -1,
- /*0x04a6*/ 376,
- /*0xa7b8*/ 1136,
- /*0x01b8*/ 155,
- -1,
- /*0x10a6*/ 490,
- /*0x1f5d*/ 758,
- /*0xff33*/ 1265,
- /*0x10d5f*/ 1450,
- -1, -1, -1, -1,
- /*0x1cae*/ 570,
- -1,
- /*0x04a4*/ 375,
- -1,
- /*0x10d53*/ 1438,
- /*0x020c*/ 196,
- /*0x10a4*/ 488,
- /*0x1f8c*/ 780,
- /*0x1040c*/ 1285,
- /*0x040c*/ 309,
- /*0x010c*/ 63,
- -1, -1, -1,
- /*0x1cac*/ 568,
- /*0xab8c*/ 1183,
- /*0x2c0c*/ 924,
- /*0x1cb0*/ 572,
- /*0x038c*/ 238,
- -1,
- /*0xa77b*/ 1104,
- /*0x053a*/ 454,
- -1, -1,
- /*0xa726*/ 1067,
- /*0x118a0*/ 1457,
- -1, -1,
- /*0x2c8c*/ 981,
- -1,
- /*0x052a*/ 442,
- -1, -1, -1,
- /*0x1caf*/ 571,
- /*0x1e1c*/ 600,
- -1,
- /*0x10588*/ 1372,
- /*0xa724*/ 1066,
- -1,
- /*0xa77d*/ 1105,
- -1,
- /*0x10589*/ 1373,
- -1, -1, -1, -1,
- /*0x04a2*/ 374,
- /*0x10c8c*/ 1396,
- -1, -1,
- /*0x10a2*/ 486,
- -1, -1,
- /*0x1058a*/ 1374,
- -1,
- /*0x1e9e*/ 667,
- /*0x1e1e*/ 601,
- /*0x1e90c*/ 1533,
- /*0x1fbc*/ 825,
- /*0x2132*/ 868,
- -1,
- /*0x049a*/ 370,
- /*0x023e*/ 219,
- -1,
- /*0x1fbe*/ 826,
- -1,
- /*0xabbc*/ 1231,
- /*0x10580*/ 1364,
- -1,
- /*0x1ca8*/ 564,
- -1,
- /*0x10583*/ 1367,
- /*0xabbe*/ 1233,
- -1, -1,
- /*0x052e*/ 444,
- -1, -1, -1,
- /*0x2cbc*/ 1005,
- -1, -1,
- /*0xa722*/ 1065,
- -1,
- /*0x0050*/ 14,
- /*0x2cbe*/ 1006,
- -1, -1,
- /*0x0150*/ 96,
- /*0x052c*/ 443,
- /*0x118a6*/ 1463,
- /*0x1eba*/ 681,
- /*0x1e3a*/ 615,
- /*0x1cb2*/ 574,
- -1, -1,
- /*0x03d0*/ 271,
- /*0xa7bc*/ 1138,
- /*0x01bc*/ 156,
- /*0x10d5d*/ 1448,
- /*0x1eaa*/ 673,
- /*0x1e2a*/ 607,
- -1,
- /*0xa7be*/ 1139,
- /*0x118a4*/ 1461,
- -1,
- /*0x2cd0*/ 1015,
- -1, -1,
- /*0x1cb8*/ 580,
- /*0x1f1a*/ 726,
- -1,
- /*0x1fb6*/ 819,
- /*0xa688*/ 1055,
- -1,
- /*0x0136*/ 83,
- -1, -1,
- /*0x1fb4*/ 818,
- /*0x049c*/ 371,
- /*0xabb6*/ 1225,
- /*0x0134*/ 82,
- -1,
- /*0x10586*/ 1370,
- /*0xa7d0*/ 1149,
- -1,
- /*0xabb4*/ 1223,
- -1, -1, -1,
- /*0xa68a*/ 1056,
- -1, -1,
- /*0x2cb6*/ 1002,
- -1, -1, -1, -1, -1,
- /*0x2cb4*/ 1001,
- -1,
- /*0x049e*/ 372,
- -1, -1,
- /*0xa680*/ 1051,
- /*0x0528*/ 441,
- /*0x1eae*/ 675,
- /*0x1e2e*/ 609,
- -1,
- /*0x118a2*/ 1459,
- -1,
- /*0xa7b6*/ 1135,
- -1, -1, -1, -1, -1,
- /*0xa7b4*/ 1134,
- -1,
- /*0xa779*/ 1103,
- /*0x1eac*/ 674,
- /*0x1e2c*/ 608,
- /*0x050e*/ 428,
- /*0x1eb0*/ 676,
- /*0x1e30*/ 610,
- /*0x024c*/ 227,
- /*0x004c*/ 10,
- /*0x1fcc*/ 836,
- /*0x1f1c*/ 728,
- /*0x0532*/ 446,
- /*0x014c*/ 94,
- -1, -1,
- /*0x024a*/ 226,
- /*0x004a*/ 8,
- /*0x1fca*/ 834,
- /*0x104ba*/ 1323,
- /*0x04ba*/ 386,
- /*0x014a*/ 93,
- -1, -1,
- /*0x10ba*/ 510,
- /*0x10594*/ 1382,
- /*0x005a*/ 24,
- /*0x1fda*/ 843,
- /*0x0538*/ 452,
- /*0x04aa*/ 378,
- /*0x015a*/ 101,
- /*0x2ccc*/ 1013,
- -1,
- /*0x10aa*/ 494,
- /*0x24ba*/ 890,
- -1, -1, -1,
- /*0x03da*/ 276,
- /*0x2cca*/ 1012,
- /*0x10590*/ 1379,
- -1, -1,
- /*0xa686*/ 1054,
- -1, -1, -1,
- /*0x1f6b*/ 763,
- /*0x2cda*/ 1020,
- /*0xa7cc*/ 1148,
- -1, -1, -1, -1,
- /*0x10584*/ 1368,
- -1,
- /*0xa73a*/ 1076,
- /*0xa696*/ 1062,
- /*0x01ca*/ 161,
- /*0x1ea8*/ 672,
- /*0x1e28*/ 606,
- -1, -1, -1, -1,
- /*0xa72a*/ 1069,
- /*0xa7da*/ 1152,
- /*0x1cbe*/ 584,
- -1,
- /*0x1f3a*/ 740,
- -1, -1,
- /*0x0248*/ 225,
- /*0x0048*/ 7,
- /*0x1fc8*/ 832,
- /*0x04ae*/ 380,
- /*0x1e8e*/ 657,
- /*0x1e0e*/ 593,
- /*0x1f2a*/ 732,
- /*0x10ae*/ 498,
- -1, -1, -1,
- /*0x1eb2*/ 677,
- /*0x1e32*/ 611,
- /*0x050c*/ 427,
- /*0x0244*/ 222,
- /*0x0044*/ 3,
- /*0x1fc4*/ 829,
- /*0x04ac*/ 379,
- -1,
- /*0x104b0*/ 1313,
- /*0x04b0*/ 381,
- /*0x10ac*/ 496,
- -1,
- /*0x2cc8*/ 1011,
- /*0x10b0*/ 500,
- -1,
- /*0x10582*/ 1366,
- /*0x1eb8*/ 680,
- /*0x1e38*/ 614,
- -1,
- /*0xa694*/ 1061,
- -1,
- /*0x0056*/ 20,
- /*0x1fd6*/ 839,
- /*0xff26*/ 1252,
- -1,
- /*0x0156*/ 99,
- /*0x2cc4*/ 1009,
- -1,
- /*0xa72e*/ 1071,
- -1,
- /*0x10af*/ 499,
- /*0x01c8*/ 160,
- /*0x1cb6*/ 578,
- /*0x03d6*/ 274,
- /*0xa690*/ 1059,
- /*0x0052*/ 16,
- /*0x1fd2*/ 837,
- /*0xff24*/ 1250,
- /*0x1cb4*/ 576,
- /*0x0152*/ 97,
- /*0x118ba*/ 1483,
- /*0x1f2e*/ 736,
- /*0xa72c*/ 1070,
- /*0x2cd6*/ 1018,
- /*0xa7c4*/ 1142,
- /*0x01c4*/ 157,
- -1, -1,
- /*0xa684*/ 1053,
- /*0x118aa*/ 1467,
- -1, -1,
- /*0x004f*/ 13,
- -1,
- /*0x053c*/ 456,
- /*0x1f2c*/ 734,
- -1,
- /*0x2cd2*/ 1016,
- -1, -1,
- /*0x053e*/ 458,
- /*0xa7d6*/ 1150,
- /*0x04a8*/ 377,
- -1,
- /*0x03cf*/ 270,
- -1,
- /*0x10a8*/ 492,
- -1, -1, -1, -1, -1,
- /*0x0054*/ 18,
- /*0x1e8c*/ 656,
- /*0x1e0c*/ 592,
- /*0x1f2f*/ 737,
- /*0x0154*/ 98,
- -1, -1,
- /*0x048e*/ 364,
- -1,
- /*0x0550*/ 476,
- /*0xff22*/ 1248,
- -1, -1,
- /*0x104b2*/ 1315,
- /*0x04b2*/ 382,
- -1, -1, -1,
- /*0x10b2*/ 502,
- -1,
- /*0xa682*/ 1052,
- /*0x01cf*/ 164,
- /*0x2cd4*/ 1017,
- /*0x118ae*/ 1471,
- -1,
- /*0x10592*/ 1381,
- /*0xa728*/ 1068,
- -1, -1,
- /*0x104b8*/ 1321,
- /*0x04b8*/ 385,
- -1, -1, -1,
- /*0x10b8*/ 508,
- -1,
- /*0x0536*/ 450,
- /*0x118ac*/ 1469,
- -1,
- /*0x1f28*/ 730,
- /*0x118b0*/ 1473,
- /*0x00d0*/ 42,
- /*0x0534*/ 448,
- -1,
- /*0x24b8*/ 888,
- -1,
- /*0x0042*/ 1,
- /*0x1fc2*/ 827,
- -1, -1,
- /*0xa732*/ 1072,
- -1,
- /*0x2cc0*/ 1007,
- /*0x1ebc*/ 682,
- /*0x1e3c*/ 616,
- /*0xa698*/ 1063,
- /*0x1f0e*/ 722,
- /*0x118af*/ 1472,
- /*0x03c2*/ 269,
- /*0x1ebe*/ 683,
- /*0x1e3e*/ 617,
- -1,
- /*0x0246*/ 224,
- /*0x0046*/ 5,
- /*0x1fc6*/ 830,
- -1,
- /*0xa738*/ 1075,
- -1,
- /*0x2cc2*/ 1008,
- -1,
- /*0xa7c0*/ 1140,
- -1,
- /*0x0058*/ 22,
- /*0x1fd8*/ 841,
- -1, -1,
- /*0x0158*/ 100,
- -1, -1,
- /*0x1f38*/ 738,
- /*0x1ed0*/ 692,
- /*0x1e50*/ 626,
- -1, -1,
- /*0x03d8*/ 275,
- /*0x2cc6*/ 1010,
- /*0xa7c2*/ 1141,
- /*0x048c*/ 363,
- -1, -1, -1,
- /*0x054c*/ 472,
- -1,
- /*0x118a8*/ 1465,
- /*0x2cd8*/ 1019,
- /*0x16e43*/ 1492,
- /*0x1f8d*/ 781,
- /*0x1040d*/ 1286,
- /*0x040d*/ 310,
- /*0x054a*/ 470,
- -1, -1,
- /*0xa692*/ 1060,
- /*0xa7c6*/ 1144,
- /*0xab8d*/ 1184,
- /*0x2c0d*/ 925,
- -1,
- /*0x1eb6*/ 679,
- /*0x1e36*/ 613,
- /*0x16e5b*/ 1516,
- -1, -1,
- /*0xa7d8*/ 1151,
- /*0x1eb4*/ 678,
- /*0x1e34*/ 612,
- /*0x0245*/ 223,
- /*0x0045*/ 4,
- /*0x118b2*/ 1475,
- -1, -1,
- /*0x0145*/ 90,
- -1,
- /*0x16e59*/ 1514,
- /*0x00cc*/ 38,
- -1,
- /*0x024e*/ 228,
- /*0x004e*/ 12,
- -1, -1, -1,
- /*0x014e*/ 95,
- /*0x00ca*/ 36,
- -1,
- /*0x118b8*/ 1481,
- -1,
- /*0xa78d*/ 1112,
- /*0x1f0c*/ 720,
- /*0x10c8d*/ 1397,
- /*0x104bc*/ 1325,
- /*0x04bc*/ 387,
- /*0x00da*/ 51,
- /*0xff3a*/ 1272,
- -1,
- /*0x10bc*/ 512,
- /*0x104be*/ 1327,
- /*0x04be*/ 388,
- -1,
- /*0x1e90d*/ 1534,
- /*0x2cce*/ 1014,
- /*0x10be*/ 514,
- /*0xff2a*/ 1256,
- -1, -1,
- /*0x24bc*/ 892,
- -1,
- /*0x0548*/ 468,
- /*0xa7c5*/ 1143,
- /*0x01c5*/ 158,
- -1,
- /*0x24be*/ 894,
- -1, -1,
- /*0x1ecc*/ 690,
- /*0x1e4c*/ 624,
- -1,
- /*0x104d0*/ 1345,
- /*0x04d0*/ 397,
- -1, -1,
- /*0x0544*/ 464,
- /*0x1eca*/ 689,
- /*0x1e4a*/ 623,
- -1,
- /*0x0055*/ 19,
- /*0xa650*/ 1036,
- /*0xa73c*/ 1077,
- -1,
- /*0x16e57*/ 1512,
- /*0x0345*/ 229,
- /*0x1eda*/ 697,
- /*0x1e5a*/ 631,
- /*0xa73e*/ 1078,
- /*0x1f87*/ 775,
- /*0x10407*/ 1280,
- /*0x0407*/ 304,
- /*0x03d5*/ 273,
- /*0x0556*/ 482,
- /*0x00c8*/ 34,
- /*0x1f3c*/ 742,
- -1,
- /*0xab87*/ 1178,
- /*0x2c07*/ 919,
- /*0x104b6*/ 1319,
- /*0x04b6*/ 384,
- /*0x1f3e*/ 744,
- -1,
- /*0xff2e*/ 1260,
- /*0x10b6*/ 506,
- /*0x104b4*/ 1317,
- /*0x04b4*/ 383,
- /*0x0552*/ 478,
- /*0x00c4*/ 30,
- /*0xa750*/ 1087,
- /*0x10b4*/ 504,
- /*0x0047*/ 6,
- /*0x1fc7*/ 831,
- -1,
- /*0x24b6*/ 886,
- /*0x0147*/ 91,
- -1,
- /*0xff2c*/ 1258,
- -1, -1,
- /*0xff30*/ 1262,
- /*0x01d5*/ 167,
- /*0x1f50*/ 752,
- -1,
- /*0x054f*/ 475,
- /*0x00d6*/ 48,
- -1,
- /*0xa69a*/ 1064,
- /*0xab71*/ 1156,
- /*0x0187*/ 125,
- /*0x10c87*/ 1391,
- -1, -1,
- /*0x1ec8*/ 688,
- /*0x1e48*/ 622,
- -1,
- /*0xa736*/ 1074,
- /*0xff2f*/ 1261,
- /*0x1fb9*/ 822,
- /*0x00d2*/ 44,
- /*0x1e907*/ 1528,
- /*0x0139*/ 84,
- /*0xa734*/ 1073,
- -1,
- /*0x0554*/ 480,
- /*0xab73*/ 1158,
- /*0xabb9*/ 1228,
- /*0x1ec4*/ 686,
- /*0x1e44*/ 620,
- /*0x118bc*/ 1485,
- -1,
- /*0xa7c7*/ 1145,
- /*0x01c7*/ 159,
- -1,
- /*0x104cc*/ 1341,
- /*0x118be*/ 1487,
- /*0x00cf*/ 41,
- -1, -1,
- /*0x1fab*/ 811,
- -1,
- /*0x042b*/ 340,
- /*0x104ca*/ 1339,
- /*0xa64c*/ 1034,
- /*0x1ed6*/ 695,
- /*0x1e56*/ 629,
- -1,
- /*0xabab*/ 1214,
- /*0x2c2b*/ 955,
- /*0x24cc*/ 908,
- /*0x03ab*/ 267,
- /*0xa64a*/ 1033,
- /*0x04da*/ 402,
- /*0xff28*/ 1254,
- /*0x0540*/ 460,
- -1,
- /*0x00d4*/ 46,
- /*0x24ca*/ 906,
- /*0x1ed2*/ 693,
- /*0x1e52*/ 627,
- /*0xa65a*/ 1041,
- -1, -1, -1,
- /*0x1fe2*/ 845,
- -1,
- /*0x0462*/ 346,
- /*0x0162*/ 105,
- -1, -1,
- /*0x0542*/ 462,
- /*0xa74c*/ 1085,
- -1,
- /*0x2c62*/ 961,
- -1,
- /*0x03e2*/ 280,
- -1,
- /*0xff32*/ 1264,
- /*0xa7ab*/ 1126,
- /*0xa74a*/ 1084,
- /*0x10cab*/ 1427,
- -1,
- /*0x16e5f*/ 1520,
- /*0x118b6*/ 1479,
- /*0x1f4c*/ 750,
- /*0x2ce2*/ 1024,
- /*0x00c0*/ 26,
- /*0x0546*/ 466,
- /*0xa75a*/ 1092,
- /*0x118b4*/ 1477,
- -1,
- /*0x16e53*/ 1508,
- /*0x1f4a*/ 748,
- /*0xff38*/ 1270,
- -1,
- /*0x1ed4*/ 694,
- /*0x1e54*/ 628,
- /*0x1fe4*/ 847,
- /*0x104c8*/ 1337,
- /*0x0464*/ 347,
- /*0x0164*/ 106,
- -1,
- /*0x00c2*/ 28,
- -1,
- /*0x01e2*/ 173,
- /*0xab70*/ 1155,
- /*0x2c64*/ 963,
- /*0xa648*/ 1032,
- /*0x03e4*/ 281,
- /*0x10d50*/ 1435,
- -1, -1,
- /*0x104c4*/ 1333,
- /*0x24c8*/ 904,
- /*0x015e*/ 103,
- -1, -1,
- /*0x10c4*/ 520,
- -1,
- /*0x00c6*/ 32,
- -1,
- /*0xa644*/ 1030,
- /*0x03de*/ 278,
- -1, -1,
- /*0x1ec0*/ 684,
- /*0x1e40*/ 618,
- /*0x24c4*/ 900,
- /*0x00d8*/ 49,
- /*0x1c87*/ 537,
- /*0x04d6*/ 400,
- -1,
- /*0x2cde*/ 1022,
- -1, -1,
- /*0xa748*/ 1083,
- -1,
- /*0x01e4*/ 174,
- /*0xa656*/ 1039,
- -1,
- /*0x0545*/ 465,
- /*0x1ec2*/ 685,
- /*0x1e42*/ 619,
- /*0x104d2*/ 1347,
- /*0x04d2*/ 398,
- /*0x1fa9*/ 809,
- -1,
- /*0x0429*/ 338,
- /*0x1f48*/ 746,
- /*0xa744*/ 1081,
- /*0x054e*/ 474,
- /*0x01de*/ 171,
- /*0xa652*/ 1037,
- /*0xaba9*/ 1212,
- /*0x2c29*/ 953,
- -1,
- /*0x03a9*/ 265,
- -1,
- /*0x1ec6*/ 687,
- /*0x1e46*/ 621,
- /*0x104cf*/ 1344,
- -1,
- /*0x1fa1*/ 801,
- /*0x10421*/ 1306,
- /*0x0421*/ 330,
- /*0x212b*/ 867,
- /*0xa756*/ 1090,
- /*0x1ed8*/ 696,
- /*0x1e58*/ 630,
- -1,
- /*0xaba1*/ 1204,
- /*0x2c21*/ 945,
- /*0x00c5*/ 31,
- /*0x03a1*/ 258,
- -1,
- /*0x24cf*/ 911,
- /*0xab75*/ 1160,
- -1,
- /*0x1cb9*/ 581,
- /*0x1f56*/ 755,
- /*0xa752*/ 1088,
- /*0x04d4*/ 399,
- /*0x00ce*/ 40,
- -1, -1,
- /*0x01a9*/ 146,
- /*0x10ca9*/ 1425,
- /*0x16e5d*/ 1518,
- /*0x1058e*/ 1377,
- /*0xa654*/ 1038,
- /*0x2162*/ 871,
- -1, -1,
- /*0x1f52*/ 753,
- -1,
- /*0x0460*/ 345,
- /*0x0160*/ 104,
- /*0x0555*/ 481,
- /*0x015c*/ 102,
- /*0x1cab*/ 567,
- -1, -1,
- /*0x2c60*/ 960,
- /*0x10ca1*/ 1417,
- /*0x03e0*/ 279,
- /*0xab7f*/ 1170,
- /*0x03dc*/ 277,
- -1,
- /*0x10d5a*/ 1445,
- -1,
- /*0x104c0*/ 1329,
- /*0x04c0*/ 389,
- -1,
- /*0x1e921*/ 1554,
- /*0x2ce0*/ 1023,
- /*0x10c0*/ 516,
- /*0x2cdc*/ 1021,
- /*0xa754*/ 1089,
- -1,
- /*0xa640*/ 1028,
- -1,
- /*0x1ece*/ 691,
- /*0x1e4e*/ 625,
- /*0x2164*/ 873,
- -1,
- /*0x24c0*/ 896,
- /*0x104c2*/ 1331,
- -1,
- /*0x0547*/ 467,
- /*0x00d5*/ 47,
- /*0x1f54*/ 754,
- /*0x10c2*/ 518,
- -1,
- /*0x01e0*/ 172,
- /*0xa7dc*/ 1153,
- /*0xa642*/ 1029,
- -1,
- /*0x1f97*/ 791,
- /*0x10417*/ 1296,
- /*0x0417*/ 320,
- -1,
- /*0x24c2*/ 898,
- -1,
- /*0x104c6*/ 1335,
- -1,
- /*0xab97*/ 1194,
- /*0x2c17*/ 935,
- /*0xa740*/ 1079,
- /*0x0397*/ 248,
- -1, -1,
- /*0xab77*/ 1162,
- /*0xa646*/ 1031,
- /*0x04d8*/ 401,
- /*0x0539*/ 453,
- -1,
- /*0xff36*/ 1268,
- -1,
- /*0x24c6*/ 902,
- -1,
- /*0x00c7*/ 33,
- /*0xa658*/ 1040,
- /*0xff34*/ 1266,
- /*0xa742*/ 1080,
- /*0x1fec*/ 854,
- /*0xa68e*/ 1058,
- /*0x046c*/ 351,
- /*0x016c*/ 110,
- /*0x1058c*/ 1375,
- -1,
- /*0x1fea*/ 852,
- -1,
- /*0x046a*/ 350,
- /*0x016a*/ 109,
- -1,
- /*0x03ec*/ 285,
- -1,
- /*0x0197*/ 136,
- /*0x10c97*/ 1407,
- -1,
- /*0xa746*/ 1082,
- /*0x03ea*/ 284,
- -1,
- /*0x004b*/ 9,
- /*0x1fcb*/ 835,
- -1,
- /*0x10d56*/ 1441,
- -1,
- /*0x1e917*/ 1544,
- /*0xa758*/ 1091,
- -1,
- /*0x1fe8*/ 850,
- -1,
- /*0x0468*/ 349,
- /*0x0168*/ 108,
- -1,
- /*0x104c5*/ 1334,
- /*0x04c5*/ 392,
- -1, -1,
- /*0x10d52*/ 1437,
- /*0x10c5*/ 521,
- /*0x03e8*/ 283,
- -1,
- /*0x01ec*/ 178,
- /*0x1ca9*/ 565,
- /*0x104ce*/ 1343,
- -1, -1, -1,
- /*0x01ea*/ 177,
- /*0x24c5*/ 901,
- -1, -1, -1,
- /*0xa64e*/ 1035,
- /*0x0049*/ 1555,
- /*0x1fc9*/ 833,
- /*0xab7b*/ 1166,
- /*0x2160*/ 869,
- /*0x0149*/ 92,
- /*0x24ce*/ 910,
- /*0x1ca1*/ 557,
- /*0xa7cb*/ 1147,
- /*0x01cb*/ 162,
- /*0x1f0d*/ 721,
- -1,
- /*0x046e*/ 352,
- /*0x016e*/ 111,
- -1,
- /*0x1ff2*/ 855,
- /*0x01e8*/ 176,
- /*0x0472*/ 354,
- /*0x0172*/ 113,
- /*0x2c6e*/ 968,
- /*0xfb17*/ 1246,
- /*0x03ee*/ 286,
- /*0x10d54*/ 1439,
- /*0xab7d*/ 1168,
- /*0x2c72*/ 971,
- -1, -1, -1,
- /*0xa74e*/ 1086,
- -1,
- /*0xa68c*/ 1057,
- /*0x1fe6*/ 848,
- -1,
- /*0x0466*/ 348,
- /*0x0166*/ 107,
- -1,
- /*0x2cf2*/ 1027,
- /*0x1f8f*/ 783,
- /*0x1040f*/ 1288,
- /*0x040f*/ 312,
- -1,
- /*0xa7c9*/ 1146,
- /*0x03e6*/ 282,
- -1, -1,
- /*0xab8f*/ 1186,
- /*0x2c0f*/ 927,
- -1,
- /*0x038f*/ 240,
- -1,
- /*0x01ee*/ 179,
- -1,
- /*0x1fad*/ 813,
- -1,
- /*0x042d*/ 342,
- /*0x01f2*/ 182,
- /*0x1ee2*/ 701,
- /*0x1e62*/ 635,
- -1,
- /*0x047e*/ 360,
- /*0xabad*/ 1216,
- /*0x2c2d*/ 957,
- /*0x0241*/ 220,
- /*0x0041*/ 0,
- /*0x00de*/ 55,
- -1,
- /*0x2c7e*/ 973,
- /*0x0141*/ 88,
- /*0x03fe*/ 295,
- /*0x104c7*/ 1336,
- /*0x04c7*/ 393,
- /*0x01e6*/ 175,
- -1, -1,
- /*0x10c7*/ 522,
- /*0x216c*/ 881,
- /*0x0372*/ 231,
- /*0x018f*/ 130,
- /*0x10c8f*/ 1399,
- -1,
- /*0xabb5*/ 1224,
- /*0x216a*/ 879,
- /*0x1c97*/ 547,
- -1,
- /*0x24c7*/ 903,
- -1, -1, -1,
- /*0x1e90f*/ 1536,
- /*0x1ee4*/ 702,
- /*0x1e64*/ 636,
- /*0xa7ad*/ 1128,
- -1,
- /*0x10cad*/ 1429,
- /*0x10d58*/ 1443,
- /*0x104b9*/ 1322,
- -1,
- /*0x01fe*/ 189,
- -1, -1,
- /*0x10b9*/ 509,
- /*0x1fb7*/ 820,
- /*0x2168*/ 877,
- /*0x1ede*/ 699,
- /*0x1e5e*/ 633,
- /*0x1fa5*/ 805,
- /*0x10425*/ 1310,
- /*0x0425*/ 334,
- -1,
- /*0xabb7*/ 1226,
- /*0x24b9*/ 889,
- -1,
- /*0x01b5*/ 153,
- /*0xaba5*/ 1208,
- /*0x2c25*/ 949,
- -1,
- /*0x03a5*/ 261,
- /*0x1fa3*/ 803,
- /*0x10423*/ 1308,
- /*0x0423*/ 332,
- -1,
- /*0x10ab*/ 495,
- /*0x1f9d*/ 797,
- /*0x1041d*/ 1302,
- /*0x041d*/ 326,
- /*0xaba3*/ 1206,
- /*0x2c23*/ 947,
- -1,
- /*0x03a3*/ 259,
- -1,
- /*0xab9d*/ 1200,
- /*0x2c1d*/ 941,
- -1,
- /*0x039d*/ 254,
- -1, -1,
- /*0x216e*/ 883,
- -1, -1, -1, -1,
- /*0x01b7*/ 154,
- /*0x04e2*/ 406,
- /*0xab79*/ 1164,
- -1,
- /*0x1f39*/ 739,
- /*0x10ca5*/ 1421,
- -1,
- /*0x00dc*/ 53,
- -1,
- /*0xa662*/ 1045,
- /*0x023d*/ 218,
- -1, -1, -1, -1,
- /*0x013d*/ 86,
- /*0x2166*/ 875,
- /*0x10ca3*/ 1419,
- -1, -1,
- /*0xabbd*/ 1232,
- /*0x019d*/ 139,
- /*0x10c9d*/ 1413,
- -1,
- /*0x004d*/ 11,
- /*0x1f2b*/ 733,
- -1,
- /*0x1f9b*/ 795,
- /*0x1041b*/ 1300,
- /*0x041b*/ 324,
- -1, -1,
- /*0x1e91d*/ 1550,
- -1,
- /*0x04e4*/ 407,
- /*0xab9b*/ 1198,
- /*0x2c1b*/ 939,
- /*0xa762*/ 1096,
- /*0x039b*/ 252,
- -1, -1, -1,
- /*0xa664*/ 1046,
- -1,
- /*0x1ee0*/ 700,
- /*0x1e60*/ 634,
- /*0x1edc*/ 698,
- /*0x1e5c*/ 632,
- /*0x04de*/ 404,
- -1, -1,
- /*0x1f95*/ 789,
- /*0x10415*/ 1294,
- /*0x0415*/ 318,
- /*0x10d55*/ 1440,
- /*0x1ffa*/ 862,
- /*0xa65e*/ 1043,
- /*0x047a*/ 358,
- /*0x118b9*/ 1482,
- /*0xab95*/ 1192,
- /*0x2c15*/ 933,
- -1,
- /*0x0395*/ 246,
- /*0x13fa*/ 526,
- /*0x054b*/ 471,
- /*0x01cd*/ 163,
- /*0x03fa*/ 293,
- -1,
- /*0x10c9b*/ 1411,
- -1,
- /*0xa764*/ 1097,
- /*0x1cad*/ 569,
- /*0x1f99*/ 793,
- /*0x10419*/ 1298,
- /*0x0419*/ 322,
- -1, -1,
- /*0x013f*/ 87,
- /*0x1e91b*/ 1548,
- /*0x118ab*/ 1468,
- /*0xab99*/ 1196,
- /*0x2c19*/ 937,
- /*0xabbf*/ 1234,
- /*0x0399*/ 250,
- /*0xa75e*/ 1094,
- -1,
- /*0x10a9*/ 493,
- /*0x1ff4*/ 857,
- /*0x1e97*/ 662,
- /*0x0474*/ 355,
- /*0x0174*/ 114,
- /*0x1cb5*/ 577,
- /*0x10c95*/ 1405,
- -1, -1,
- /*0x01fa*/ 187,
- /*0x00cb*/ 37,
- /*0x0549*/ 469,
- /*0x03f4*/ 289,
- -1, -1, -1,
- /*0x1e915*/ 1542,
- /*0x10a1*/ 485,
- -1, -1, -1,
- /*0x0051*/ 15,
- -1,
- /*0x10572*/ 1351,
- -1, -1, -1,
- /*0x10c99*/ 1409,
- -1,
- /*0x1eec*/ 706,
- /*0x1e6c*/ 640,
- -1, -1,
- /*0x03d1*/ 272,
- /*0x1cb7*/ 579,
- /*0x1eea*/ 705,
- /*0x1e6a*/ 639,
- /*0x1e919*/ 1546,
- /*0x1ca5*/ 561,
- -1, -1,
- /*0x01f4*/ 183,
- -1,
- /*0x00c9*/ 35,
- /*0x04e0*/ 405,
- /*0x1f29*/ 731,
- /*0x04dc*/ 403,
- -1, -1, -1,
- /*0x1ca3*/ 559,
- -1,
- /*0xa660*/ 1044,
- -1,
- /*0xa65c*/ 1042,
- /*0x1c9d*/ 553,
- /*0x1ee8*/ 704,
- /*0x1e68*/ 638,
- -1,
- /*0x023b*/ 217,
- -1,
- /*0x1fbb*/ 824,
- /*0x01d1*/ 165,
- /*0xfb15*/ 1244,
- /*0x013b*/ 85,
- /*0x1057e*/ 1362,
- /*0x1f91*/ 785,
- /*0x10411*/ 1290,
- /*0x0411*/ 314,
- /*0xabbb*/ 1230,
- -1,
- /*0x10d62*/ 1453,
- -1,
- /*0x0541*/ 461,
- /*0xab91*/ 1188,
- /*0x2c11*/ 929,
- -1,
- /*0x0391*/ 242,
- -1, -1,
- /*0xa760*/ 1095,
- /*0x0535*/ 449,
- /*0xa75c*/ 1093,
- -1, -1, -1,
- /*0x1cbd*/ 583,
- -1, -1, -1,
- /*0x1eee*/ 707,
- /*0x1e6e*/ 641,
- /*0x1ffc*/ 864,
- -1,
- /*0x047c*/ 359,
- /*0x1ef2*/ 709,
- /*0x1e72*/ 643,
- -1, -1,
- /*0x118a9*/ 1466,
- /*0x13fc*/ 528,
- /*0x1c9b*/ 551,
- -1, -1,
- /*0x10d64*/ 1455,
- /*0x00c1*/ 27,
- /*0x0191*/ 132,
- /*0x10c91*/ 1401,
- -1, -1,
- /*0x0537*/ 451,
- /*0x1ee6*/ 703,
- /*0x1e66*/ 637,
- /*0x00b5*/ 25,
- -1,
- /*0x04ec*/ 411,
- /*0x118a1*/ 1458,
- /*0x1e911*/ 1538,
- /*0x10d5e*/ 1449,
- -1, -1,
- /*0x04ea*/ 410,
- -1,
- /*0xa66c*/ 1050,
- -1,
- /*0x1c95*/ 545,
- -1, -1,
- /*0x1058d*/ 1376,
- /*0xa66a*/ 1049,
- -1, -1,
- /*0x01fc*/ 188,
- -1,
- /*0x104cb*/ 1340,
- /*0x04cb*/ 395,
- -1,
- /*0x1efe*/ 715,
- /*0x1e7e*/ 649,
- -1, -1, -1,
- /*0x04e8*/ 409,
- -1, -1,
- /*0xff39*/ 1271,
- /*0x1c99*/ 549,
- -1,
- /*0x1cbf*/ 585,
- /*0x24cb*/ 907,
- /*0xa668*/ 1048,
- /*0xa76c*/ 1101,
- /*0x1f93*/ 787,
- /*0x10413*/ 1292,
- /*0x0413*/ 316,
- -1, -1,
- /*0xa76a*/ 1100,
- -1, -1,
- /*0xab93*/ 1190,
- /*0x2c13*/ 931,
- /*0x053d*/ 457,
- /*0x0393*/ 244,
- /*0x1f6c*/ 764,
- -1,
- /*0xff2b*/ 1257,
- /*0x104c9*/ 1338,
- /*0x04c9*/ 394,
- -1,
- /*0x1f6a*/ 762,
- /*0x1ff6*/ 858,
- -1,
- /*0x0476*/ 356,
- /*0x0176*/ 115,
- /*0x054d*/ 473,
- /*0x04ee*/ 412,
- /*0xabb1*/ 1220,
- /*0xa768*/ 1099,
- -1,
- /*0x16e50*/ 1505,
- /*0x04f2*/ 414,
- /*0x24c9*/ 905,
- -1,
- /*0x1f4b*/ 749,
- -1, -1,
- /*0x1f81*/ 769,
- /*0x10401*/ 1274,
- /*0x0401*/ 298,
- -1,
- /*0x1f68*/ 760,
- /*0x0193*/ 133,
- /*0x10c93*/ 1403,
- -1,
- /*0xab81*/ 1172,
- /*0x2c01*/ 913,
- /*0x04e6*/ 408,
- -1, -1,
- /*0x10d60*/ 1451,
- -1,
- /*0x10d5c*/ 1447,
- /*0x1e913*/ 1540,
- /*0x1057a*/ 1359,
- /*0xa666*/ 1047,
- -1,
- /*0x00cd*/ 39,
- /*0xa7b1*/ 1131,
- /*0x01b1*/ 150,
- /*0x10cb1*/ 1433,
- /*0x01f6*/ 184,
- /*0xa76e*/ 1102,
- -1,
- /*0x10587*/ 1371,
- /*0x0587*/ 483,
- -1,
- /*0x1f49*/ 747,
- -1, -1, -1, -1,
- /*0x10ad*/ 497,
- /*0x04fe*/ 420,
- /*0x053f*/ 459,
- /*0x1f6e*/ 766,
- /*0x1c91*/ 541,
- /*0x0181*/ 121,
- /*0x10c81*/ 1385,
- /*0x104c1*/ 1330,
- /*0x04c1*/ 390,
- -1,
- /*0x0376*/ 232,
- /*0xa766*/ 1098,
- /*0x10c1*/ 517,
- -1,
- /*0x10574*/ 1353,
- /*0x104b5*/ 1318,
- /*0x1e901*/ 1522,
- -1, -1, -1,
- /*0x10b5*/ 505,
- -1,
- /*0x24c1*/ 897,
- -1, -1, -1,
- /*0x1e9b*/ 666,
- -1,
- /*0xfb13*/ 1242,
- -1,
- /*0x1f0f*/ 723,
- -1, -1,
- /*0x1f8b*/ 779,
- /*0x1040b*/ 1284,
- /*0x040b*/ 308,
- /*0x0551*/ 477,
- /*0xa77e*/ 1106,
- -1, -1,
- /*0x16e4c*/ 1501,
- /*0xab8b*/ 1182,
- /*0x2c0b*/ 923,
- -1,
- /*0x104b7*/ 1320,
- /*0x1f2d*/ 735,
- -1, -1,
- /*0x16e4a*/ 1499,
- /*0x10b7*/ 507,
- /*0xff29*/ 1255,
- -1, -1,
- /*0x10a5*/ 489,
- /*0x1efa*/ 713,
- /*0x1e7a*/ 647,
- -1,
- /*0x16e5a*/ 1515,
- /*0x1ff8*/ 860,
- /*0x24b7*/ 887,
- /*0x0478*/ 357,
- /*0x0178*/ 116,
- -1,
- /*0xfb01*/ 1236,
- -1,
- /*0x10a3*/ 487,
- /*0x13f8*/ 524,
- /*0xff21*/ 1247,
- /*0x00d1*/ 43,
- -1, -1,
- /*0x1e99*/ 664,
- /*0xa78b*/ 1111,
- /*0x018b*/ 128,
- /*0x10c8b*/ 1395,
- /*0x053b*/ 455,
- -1, -1, -1, -1,
- /*0x1f9f*/ 799,
- /*0x1041f*/ 1304,
- /*0x041f*/ 328,
- -1,
- /*0x1e90b*/ 1532,
- -1,
- /*0x1ef4*/ 710,
- /*0x1e74*/ 644,
- /*0xab9f*/ 1202,
- /*0x2c1f*/ 943,
- /*0x1c93*/ 543,
- /*0x039f*/ 256,
- -1, -1, -1, -1,
- /*0x104bd*/ 1326,
- -1,
- /*0x01f8*/ 186,
- /*0x118ad*/ 1470,
- -1,
- /*0x10bd*/ 513,
- -1, -1,
- /*0x16e48*/ 1497,
- /*0x1057c*/ 1360,
- -1,
- /*0x1cb1*/ 573,
- -1,
- /*0x104cd*/ 1342,
- /*0x04cd*/ 396,
- /*0x24bd*/ 893,
- -1, -1,
- /*0x10cd*/ 523,
- /*0x1f1d*/ 729,
- -1, -1,
- /*0x16e44*/ 1493,
- /*0x118b5*/ 1478,
- /*0x019f*/ 140,
- /*0x10c9f*/ 1415,
- -1, -1,
- /*0x24cd*/ 909,
- /*0x1c81*/ 531,
- -1, -1,
- /*0x1f85*/ 773,
- /*0x10405*/ 1278,
- /*0x0405*/ 302,
- /*0x1e91f*/ 1552,
- -1, -1, -1,
- /*0x16e56*/ 1511,
- /*0xab85*/ 1176,
- /*0x2c05*/ 917,
- -1, -1,
- /*0x04fa*/ 418,
- -1, -1, -1, -1, -1,
- /*0x1f3d*/ 743,
- -1,
- /*0x118b7*/ 1480,
- /*0x16e52*/ 1507,
- -1, -1,
- /*0x118a5*/ 1462,
- -1, -1, -1, -1, -1,
- /*0x104bf*/ 1328,
- /*0x1f4d*/ 751,
- -1,
- /*0x1f1b*/ 727,
- -1,
- /*0x10bf*/ 515,
- /*0x118a3*/ 1460,
- -1,
- /*0x16e4f*/ 1504,
- -1, -1,
- /*0x10c85*/ 1389,
- -1, -1,
- /*0x04f4*/ 415,
- /*0x24bf*/ 895,
- -1, -1, -1,
- /*0x1efc*/ 714,
- /*0x1e7c*/ 648,
- /*0x1e905*/ 1526,
- -1, -1, -1,
- /*0x0531*/ 445,
- /*0x10576*/ 1355,
- -1,
- /*0x16e54*/ 1509,
- -1, -1, -1, -1, -1,
- /*0x104d1*/ 1346,
- -1, -1, -1, -1, -1, -1,
- -1,
- /*0x118bd*/ 1486,
- -1, -1, -1, -1, -1,
- /*0x1f19*/ 725,
- -1,
- /*0x1f3f*/ 745,
- -1, -1, -1, -1, -1, -1,
- -1,
- /*0x16e40*/ 1489,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1,
- /*0xfb05*/ 1240,
- -1, -1, -1, -1,
- /*0x104bb*/ 1324,
- /*0x16e42*/ 1491,
- -1, -1, -1,
- /*0x10bb*/ 511,
- -1, -1, -1,
- /*0x1c9f*/ 555,
- -1, -1, -1, -1, -1,
- /*0x24bb*/ 891,
- -1, -1,
- /*0x16e46*/ 1495,
- -1, -1, -1, -1, -1, -1,
- /*0x1ef6*/ 711,
- /*0x1e76*/ 645,
- /*0x16e58*/ 1513,
- -1, -1, -1,
- /*0x118bf*/ 1488,
- /*0x04fc*/ 419,
- -1, -1, -1, -1, -1, -1,
- -1, -1,
- /*0xff2d*/ 1259,
- -1, -1, -1, -1, -1, -1,
- -1, -1,
- /*0x1f3b*/ 741,
- -1, -1, -1, -1, -1, -1,
- /*0x1c85*/ 535,
- -1, -1, -1,
- /*0xff35*/ 1267,
- /*0x10578*/ 1357,
- -1, -1, -1, -1, -1, -1,
- -1, -1,
- /*0x16e45*/ 1494,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1,
- /*0x16e4e*/ 1503,
- -1, -1, -1, -1, -1, -1,
- -1, -1,
- /*0xff37*/ 1269,
- -1, -1, -1,
- /*0xff25*/ 1251,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1,
- /*0x118bb*/ 1484,
- -1,
- /*0xff23*/ 1249,
- -1,
- /*0x104b1*/ 1314,
- -1, -1,
- /*0x04f6*/ 416,
- -1,
- /*0x10b1*/ 501,
- -1, -1, -1, -1,
- /*0x10d51*/ 1436,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1,
- /*0x16e55*/ 1510,
- -1, -1, -1, -1, -1,
- /*0x1ef8*/ 712,
- /*0x1e78*/ 646,
- -1, -1, -1, -1, -1, -1,
- -1, -1,
- /*0x1058f*/ 1378,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1,
- /*0x16e47*/ 1496,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1,
- /*0x118b1*/ 1474,
- -1, -1, -1, -1, -1, -1,
- -1,
- /*0x04f8*/ 417,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1,
- /*0x1f0b*/ 719,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1,
- /*0x16e5e*/ 1519,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1,
- /*0x10595*/ 1383,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1,
- /*0x16e5c*/ 1517,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1,
- /*0xff31*/ 1263,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1,
- /*0x10591*/ 1380,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1,
- /*0x16e4b*/ 1500,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1,
- /*0x16e49*/ 1498,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- /*0x10581*/ 1365,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- /*0x16e41*/ 1490,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1,
- /*0xab72*/ 1157,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1,
- /*0xab7e*/ 1169,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1,
- /*0x16e4d*/ 1502,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1,
- /*0x10585*/ 1369,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1,
- /*0x16e51*/ 1506,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1,
- /*0xab7a*/ 1165,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1,
- /*0xab74*/ 1159,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- /*0xab7c*/ 1167,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- /*0xab76*/ 1161,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- /*0xab78*/ 1163
- };
-
- if (code <= MAX_CODE_VALUE && code >= MIN_CODE_VALUE)
- {
- register unsigned int key = onigenc_unicode_CaseFold_11_hash(code);
-
- if (key <= MAX_HASH_VALUE)
- {
- register short s = wordlist[key];
-
- if (s >= 0 && code1_equal(code, CaseFold_11_Table[s].from))
- return &CaseFold_11_Table[s].to;
- }
- }
- return 0;
-}
-
-static const CaseUnfold_11_Type CaseUnfold_11_Table[] = {
-#define CaseUnfold_11 (*(CaseUnfold_11_Type (*)[1422])(CaseUnfold_11_Table+0))
- {0x0061, {1|U, {0x0041}}},
- {0x0062, {1|U, {0x0042}}},
- {0x0063, {1|U, {0x0043}}},
- {0x0064, {1|U, {0x0044}}},
- {0x0065, {1|U, {0x0045}}},
- {0x0066, {1|U, {0x0046}}},
- {0x0067, {1|U, {0x0047}}},
- {0x0068, {1|U, {0x0048}}},
- {0x006a, {1|U, {0x004a}}},
- {0x006b, {2|U, {0x004b, 0x212a}}},
- {0x006c, {1|U, {0x004c}}},
- {0x006d, {1|U, {0x004d}}},
- {0x006e, {1|U, {0x004e}}},
- {0x006f, {1|U, {0x004f}}},
- {0x0070, {1|U, {0x0050}}},
- {0x0071, {1|U, {0x0051}}},
- {0x0072, {1|U, {0x0052}}},
- {0x0073, {2|U, {0x0053, 0x017f}}},
- {0x0074, {1|U, {0x0054}}},
- {0x0075, {1|U, {0x0055}}},
- {0x0076, {1|U, {0x0056}}},
- {0x0077, {1|U, {0x0057}}},
- {0x0078, {1|U, {0x0058}}},
- {0x0079, {1|U, {0x0059}}},
- {0x007a, {1|U, {0x005a}}},
- {0x00e0, {1|U, {0x00c0}}},
- {0x00e1, {1|U, {0x00c1}}},
- {0x00e2, {1|U, {0x00c2}}},
- {0x00e3, {1|U, {0x00c3}}},
- {0x00e4, {1|U, {0x00c4}}},
- {0x00e5, {2|U, {0x00c5, 0x212b}}},
- {0x00e6, {1|U, {0x00c6}}},
- {0x00e7, {1|U, {0x00c7}}},
- {0x00e8, {1|U, {0x00c8}}},
- {0x00e9, {1|U, {0x00c9}}},
- {0x00ea, {1|U, {0x00ca}}},
- {0x00eb, {1|U, {0x00cb}}},
- {0x00ec, {1|U, {0x00cc}}},
- {0x00ed, {1|U, {0x00cd}}},
- {0x00ee, {1|U, {0x00ce}}},
- {0x00ef, {1|U, {0x00cf}}},
- {0x00f0, {1|U, {0x00d0}}},
- {0x00f1, {1|U, {0x00d1}}},
- {0x00f2, {1|U, {0x00d2}}},
- {0x00f3, {1|U, {0x00d3}}},
- {0x00f4, {1|U, {0x00d4}}},
- {0x00f5, {1|U, {0x00d5}}},
- {0x00f6, {1|U, {0x00d6}}},
- {0x00f8, {1|U, {0x00d8}}},
- {0x00f9, {1|U, {0x00d9}}},
- {0x00fa, {1|U, {0x00da}}},
- {0x00fb, {1|U, {0x00db}}},
- {0x00fc, {1|U, {0x00dc}}},
- {0x00fd, {1|U, {0x00dd}}},
- {0x00fe, {1|U, {0x00de}}},
- {0x00ff, {1|U, {0x0178}}},
- {0x0101, {1|U, {0x0100}}},
- {0x0103, {1|U, {0x0102}}},
- {0x0105, {1|U, {0x0104}}},
- {0x0107, {1|U, {0x0106}}},
- {0x0109, {1|U, {0x0108}}},
- {0x010b, {1|U, {0x010a}}},
- {0x010d, {1|U, {0x010c}}},
- {0x010f, {1|U, {0x010e}}},
- {0x0111, {1|U, {0x0110}}},
- {0x0113, {1|U, {0x0112}}},
- {0x0115, {1|U, {0x0114}}},
- {0x0117, {1|U, {0x0116}}},
- {0x0119, {1|U, {0x0118}}},
- {0x011b, {1|U, {0x011a}}},
- {0x011d, {1|U, {0x011c}}},
- {0x011f, {1|U, {0x011e}}},
- {0x0121, {1|U, {0x0120}}},
- {0x0123, {1|U, {0x0122}}},
- {0x0125, {1|U, {0x0124}}},
- {0x0127, {1|U, {0x0126}}},
- {0x0129, {1|U, {0x0128}}},
- {0x012b, {1|U, {0x012a}}},
- {0x012d, {1|U, {0x012c}}},
- {0x012f, {1|U, {0x012e}}},
- {0x0133, {1|U, {0x0132}}},
- {0x0135, {1|U, {0x0134}}},
- {0x0137, {1|U, {0x0136}}},
- {0x013a, {1|U, {0x0139}}},
- {0x013c, {1|U, {0x013b}}},
- {0x013e, {1|U, {0x013d}}},
- {0x0140, {1|U, {0x013f}}},
- {0x0142, {1|U, {0x0141}}},
- {0x0144, {1|U, {0x0143}}},
- {0x0146, {1|U, {0x0145}}},
- {0x0148, {1|U, {0x0147}}},
- {0x014b, {1|U, {0x014a}}},
- {0x014d, {1|U, {0x014c}}},
- {0x014f, {1|U, {0x014e}}},
- {0x0151, {1|U, {0x0150}}},
- {0x0153, {1|U, {0x0152}}},
- {0x0155, {1|U, {0x0154}}},
- {0x0157, {1|U, {0x0156}}},
- {0x0159, {1|U, {0x0158}}},
- {0x015b, {1|U, {0x015a}}},
- {0x015d, {1|U, {0x015c}}},
- {0x015f, {1|U, {0x015e}}},
- {0x0161, {1|U, {0x0160}}},
- {0x0163, {1|U, {0x0162}}},
- {0x0165, {1|U, {0x0164}}},
- {0x0167, {1|U, {0x0166}}},
- {0x0169, {1|U, {0x0168}}},
- {0x016b, {1|U, {0x016a}}},
- {0x016d, {1|U, {0x016c}}},
- {0x016f, {1|U, {0x016e}}},
- {0x0171, {1|U, {0x0170}}},
- {0x0173, {1|U, {0x0172}}},
- {0x0175, {1|U, {0x0174}}},
- {0x0177, {1|U, {0x0176}}},
- {0x017a, {1|U, {0x0179}}},
- {0x017c, {1|U, {0x017b}}},
- {0x017e, {1|U, {0x017d}}},
- {0x0180, {1|U, {0x0243}}},
- {0x0183, {1|U, {0x0182}}},
- {0x0185, {1|U, {0x0184}}},
- {0x0188, {1|U, {0x0187}}},
- {0x018c, {1|U, {0x018b}}},
- {0x0192, {1|U, {0x0191}}},
- {0x0195, {1|U, {0x01f6}}},
- {0x0199, {1|U, {0x0198}}},
- {0x019a, {1|U, {0x023d}}},
- {0x019b, {1|U, {0xa7dc}}},
- {0x019e, {1|U, {0x0220}}},
- {0x01a1, {1|U, {0x01a0}}},
- {0x01a3, {1|U, {0x01a2}}},
- {0x01a5, {1|U, {0x01a4}}},
- {0x01a8, {1|U, {0x01a7}}},
- {0x01ad, {1|U, {0x01ac}}},
- {0x01b0, {1|U, {0x01af}}},
- {0x01b4, {1|U, {0x01b3}}},
- {0x01b6, {1|U, {0x01b5}}},
- {0x01b9, {1|U, {0x01b8}}},
- {0x01bd, {1|U, {0x01bc}}},
- {0x01bf, {1|U, {0x01f7}}},
- {0x01c6, {2|U|ST, {0x01c4, 0x01c5}}},
- {0x01c9, {2|U|ST, {0x01c7, 0x01c8}}},
- {0x01cc, {2|U|ST, {0x01ca, 0x01cb}}},
- {0x01ce, {1|U, {0x01cd}}},
- {0x01d0, {1|U, {0x01cf}}},
- {0x01d2, {1|U, {0x01d1}}},
- {0x01d4, {1|U, {0x01d3}}},
- {0x01d6, {1|U, {0x01d5}}},
- {0x01d8, {1|U, {0x01d7}}},
- {0x01da, {1|U, {0x01d9}}},
- {0x01dc, {1|U, {0x01db}}},
- {0x01dd, {1|U, {0x018e}}},
- {0x01df, {1|U, {0x01de}}},
- {0x01e1, {1|U, {0x01e0}}},
- {0x01e3, {1|U, {0x01e2}}},
- {0x01e5, {1|U, {0x01e4}}},
- {0x01e7, {1|U, {0x01e6}}},
- {0x01e9, {1|U, {0x01e8}}},
- {0x01eb, {1|U, {0x01ea}}},
- {0x01ed, {1|U, {0x01ec}}},
- {0x01ef, {1|U, {0x01ee}}},
- {0x01f3, {2|U|ST, {0x01f1, 0x01f2}}},
- {0x01f5, {1|U, {0x01f4}}},
- {0x01f9, {1|U, {0x01f8}}},
- {0x01fb, {1|U, {0x01fa}}},
- {0x01fd, {1|U, {0x01fc}}},
- {0x01ff, {1|U, {0x01fe}}},
- {0x0201, {1|U, {0x0200}}},
- {0x0203, {1|U, {0x0202}}},
- {0x0205, {1|U, {0x0204}}},
- {0x0207, {1|U, {0x0206}}},
- {0x0209, {1|U, {0x0208}}},
- {0x020b, {1|U, {0x020a}}},
- {0x020d, {1|U, {0x020c}}},
- {0x020f, {1|U, {0x020e}}},
- {0x0211, {1|U, {0x0210}}},
- {0x0213, {1|U, {0x0212}}},
- {0x0215, {1|U, {0x0214}}},
- {0x0217, {1|U, {0x0216}}},
- {0x0219, {1|U, {0x0218}}},
- {0x021b, {1|U, {0x021a}}},
- {0x021d, {1|U, {0x021c}}},
- {0x021f, {1|U, {0x021e}}},
- {0x0223, {1|U, {0x0222}}},
- {0x0225, {1|U, {0x0224}}},
- {0x0227, {1|U, {0x0226}}},
- {0x0229, {1|U, {0x0228}}},
- {0x022b, {1|U, {0x022a}}},
- {0x022d, {1|U, {0x022c}}},
- {0x022f, {1|U, {0x022e}}},
- {0x0231, {1|U, {0x0230}}},
- {0x0233, {1|U, {0x0232}}},
- {0x023c, {1|U, {0x023b}}},
- {0x023f, {1|U, {0x2c7e}}},
- {0x0240, {1|U, {0x2c7f}}},
- {0x0242, {1|U, {0x0241}}},
- {0x0247, {1|U, {0x0246}}},
- {0x0249, {1|U, {0x0248}}},
- {0x024b, {1|U, {0x024a}}},
- {0x024d, {1|U, {0x024c}}},
- {0x024f, {1|U, {0x024e}}},
- {0x0250, {1|U, {0x2c6f}}},
- {0x0251, {1|U, {0x2c6d}}},
- {0x0252, {1|U, {0x2c70}}},
- {0x0253, {1|U, {0x0181}}},
- {0x0254, {1|U, {0x0186}}},
- {0x0256, {1|U, {0x0189}}},
- {0x0257, {1|U, {0x018a}}},
- {0x0259, {1|U, {0x018f}}},
- {0x025b, {1|U, {0x0190}}},
- {0x025c, {1|U, {0xa7ab}}},
- {0x0260, {1|U, {0x0193}}},
- {0x0261, {1|U, {0xa7ac}}},
- {0x0263, {1|U, {0x0194}}},
- {0x0264, {1|U, {0xa7cb}}},
- {0x0265, {1|U, {0xa78d}}},
- {0x0266, {1|U, {0xa7aa}}},
- {0x0268, {1|U, {0x0197}}},
- {0x0269, {1|U, {0x0196}}},
- {0x026a, {1|U, {0xa7ae}}},
- {0x026b, {1|U, {0x2c62}}},
- {0x026c, {1|U, {0xa7ad}}},
- {0x026f, {1|U, {0x019c}}},
- {0x0271, {1|U, {0x2c6e}}},
- {0x0272, {1|U, {0x019d}}},
- {0x0275, {1|U, {0x019f}}},
- {0x027d, {1|U, {0x2c64}}},
- {0x0280, {1|U, {0x01a6}}},
- {0x0282, {1|U, {0xa7c5}}},
- {0x0283, {1|U, {0x01a9}}},
- {0x0287, {1|U, {0xa7b1}}},
- {0x0288, {1|U, {0x01ae}}},
- {0x0289, {1|U, {0x0244}}},
- {0x028a, {1|U, {0x01b1}}},
- {0x028b, {1|U, {0x01b2}}},
- {0x028c, {1|U, {0x0245}}},
- {0x0292, {1|U, {0x01b7}}},
- {0x029d, {1|U, {0xa7b2}}},
- {0x029e, {1|U, {0xa7b0}}},
- {0x0371, {1|U, {0x0370}}},
- {0x0373, {1|U, {0x0372}}},
- {0x0377, {1|U, {0x0376}}},
- {0x037b, {1|U, {0x03fd}}},
- {0x037c, {1|U, {0x03fe}}},
- {0x037d, {1|U, {0x03ff}}},
- {0x03ac, {1|U, {0x0386}}},
- {0x03ad, {1|U, {0x0388}}},
- {0x03ae, {1|U, {0x0389}}},
- {0x03af, {1|U, {0x038a}}},
- {0x03b1, {1|U, {0x0391}}},
- {0x03b2, {2|U, {0x0392, 0x03d0}}},
- {0x03b3, {1|U, {0x0393}}},
- {0x03b4, {1|U, {0x0394}}},
- {0x03b5, {2|U, {0x0395, 0x03f5}}},
- {0x03b6, {1|U, {0x0396}}},
- {0x03b7, {1|U, {0x0397}}},
- {0x03b8, {3|U, {0x0398, 0x03d1, 0x03f4}}},
- {0x03b9, {3|U, {0x0399, 0x0345, 0x1fbe}}},
- {0x03ba, {2|U, {0x039a, 0x03f0}}},
- {0x03bb, {1|U, {0x039b}}},
- {0x03bc, {2|U, {0x039c, 0x00b5}}},
- {0x03bd, {1|U, {0x039d}}},
- {0x03be, {1|U, {0x039e}}},
- {0x03bf, {1|U, {0x039f}}},
- {0x03c0, {2|U, {0x03a0, 0x03d6}}},
- {0x03c1, {2|U, {0x03a1, 0x03f1}}},
- {0x03c3, {2|U, {0x03a3, 0x03c2}}},
- {0x03c4, {1|U, {0x03a4}}},
- {0x03c5, {1|U, {0x03a5}}},
- {0x03c6, {2|U, {0x03a6, 0x03d5}}},
- {0x03c7, {1|U, {0x03a7}}},
- {0x03c8, {1|U, {0x03a8}}},
- {0x03c9, {2|U, {0x03a9, 0x2126}}},
- {0x03ca, {1|U, {0x03aa}}},
- {0x03cb, {1|U, {0x03ab}}},
- {0x03cc, {1|U, {0x038c}}},
- {0x03cd, {1|U, {0x038e}}},
- {0x03ce, {1|U, {0x038f}}},
- {0x03d7, {1|U, {0x03cf}}},
- {0x03d9, {1|U, {0x03d8}}},
- {0x03db, {1|U, {0x03da}}},
- {0x03dd, {1|U, {0x03dc}}},
- {0x03df, {1|U, {0x03de}}},
- {0x03e1, {1|U, {0x03e0}}},
- {0x03e3, {1|U, {0x03e2}}},
- {0x03e5, {1|U, {0x03e4}}},
- {0x03e7, {1|U, {0x03e6}}},
- {0x03e9, {1|U, {0x03e8}}},
- {0x03eb, {1|U, {0x03ea}}},
- {0x03ed, {1|U, {0x03ec}}},
- {0x03ef, {1|U, {0x03ee}}},
- {0x03f2, {1|U, {0x03f9}}},
- {0x03f3, {1|U, {0x037f}}},
- {0x03f8, {1|U, {0x03f7}}},
- {0x03fb, {1|U, {0x03fa}}},
- {0x0430, {1|U, {0x0410}}},
- {0x0431, {1|U, {0x0411}}},
- {0x0432, {2|U, {0x0412, 0x1c80}}},
- {0x0433, {1|U, {0x0413}}},
- {0x0434, {2|U, {0x0414, 0x1c81}}},
- {0x0435, {1|U, {0x0415}}},
- {0x0436, {1|U, {0x0416}}},
- {0x0437, {1|U, {0x0417}}},
- {0x0438, {1|U, {0x0418}}},
- {0x0439, {1|U, {0x0419}}},
- {0x043a, {1|U, {0x041a}}},
- {0x043b, {1|U, {0x041b}}},
- {0x043c, {1|U, {0x041c}}},
- {0x043d, {1|U, {0x041d}}},
- {0x043e, {2|U, {0x041e, 0x1c82}}},
- {0x043f, {1|U, {0x041f}}},
- {0x0440, {1|U, {0x0420}}},
- {0x0441, {2|U, {0x0421, 0x1c83}}},
- {0x0442, {3|U, {0x0422, 0x1c84, 0x1c85}}},
- {0x0443, {1|U, {0x0423}}},
- {0x0444, {1|U, {0x0424}}},
- {0x0445, {1|U, {0x0425}}},
- {0x0446, {1|U, {0x0426}}},
- {0x0447, {1|U, {0x0427}}},
- {0x0448, {1|U, {0x0428}}},
- {0x0449, {1|U, {0x0429}}},
- {0x044a, {2|U, {0x042a, 0x1c86}}},
- {0x044b, {1|U, {0x042b}}},
- {0x044c, {1|U, {0x042c}}},
- {0x044d, {1|U, {0x042d}}},
- {0x044e, {1|U, {0x042e}}},
- {0x044f, {1|U, {0x042f}}},
- {0x0450, {1|U, {0x0400}}},
- {0x0451, {1|U, {0x0401}}},
- {0x0452, {1|U, {0x0402}}},
- {0x0453, {1|U, {0x0403}}},
- {0x0454, {1|U, {0x0404}}},
- {0x0455, {1|U, {0x0405}}},
- {0x0456, {1|U, {0x0406}}},
- {0x0457, {1|U, {0x0407}}},
- {0x0458, {1|U, {0x0408}}},
- {0x0459, {1|U, {0x0409}}},
- {0x045a, {1|U, {0x040a}}},
- {0x045b, {1|U, {0x040b}}},
- {0x045c, {1|U, {0x040c}}},
- {0x045d, {1|U, {0x040d}}},
- {0x045e, {1|U, {0x040e}}},
- {0x045f, {1|U, {0x040f}}},
- {0x0461, {1|U, {0x0460}}},
- {0x0463, {2|U, {0x0462, 0x1c87}}},
- {0x0465, {1|U, {0x0464}}},
- {0x0467, {1|U, {0x0466}}},
- {0x0469, {1|U, {0x0468}}},
- {0x046b, {1|U, {0x046a}}},
- {0x046d, {1|U, {0x046c}}},
- {0x046f, {1|U, {0x046e}}},
- {0x0471, {1|U, {0x0470}}},
- {0x0473, {1|U, {0x0472}}},
- {0x0475, {1|U, {0x0474}}},
- {0x0477, {1|U, {0x0476}}},
- {0x0479, {1|U, {0x0478}}},
- {0x047b, {1|U, {0x047a}}},
- {0x047d, {1|U, {0x047c}}},
- {0x047f, {1|U, {0x047e}}},
- {0x0481, {1|U, {0x0480}}},
- {0x048b, {1|U, {0x048a}}},
- {0x048d, {1|U, {0x048c}}},
- {0x048f, {1|U, {0x048e}}},
- {0x0491, {1|U, {0x0490}}},
- {0x0493, {1|U, {0x0492}}},
- {0x0495, {1|U, {0x0494}}},
- {0x0497, {1|U, {0x0496}}},
- {0x0499, {1|U, {0x0498}}},
- {0x049b, {1|U, {0x049a}}},
- {0x049d, {1|U, {0x049c}}},
- {0x049f, {1|U, {0x049e}}},
- {0x04a1, {1|U, {0x04a0}}},
- {0x04a3, {1|U, {0x04a2}}},
- {0x04a5, {1|U, {0x04a4}}},
- {0x04a7, {1|U, {0x04a6}}},
- {0x04a9, {1|U, {0x04a8}}},
- {0x04ab, {1|U, {0x04aa}}},
- {0x04ad, {1|U, {0x04ac}}},
- {0x04af, {1|U, {0x04ae}}},
- {0x04b1, {1|U, {0x04b0}}},
- {0x04b3, {1|U, {0x04b2}}},
- {0x04b5, {1|U, {0x04b4}}},
- {0x04b7, {1|U, {0x04b6}}},
- {0x04b9, {1|U, {0x04b8}}},
- {0x04bb, {1|U, {0x04ba}}},
- {0x04bd, {1|U, {0x04bc}}},
- {0x04bf, {1|U, {0x04be}}},
- {0x04c2, {1|U, {0x04c1}}},
- {0x04c4, {1|U, {0x04c3}}},
- {0x04c6, {1|U, {0x04c5}}},
- {0x04c8, {1|U, {0x04c7}}},
- {0x04ca, {1|U, {0x04c9}}},
- {0x04cc, {1|U, {0x04cb}}},
- {0x04ce, {1|U, {0x04cd}}},
- {0x04cf, {1|U, {0x04c0}}},
- {0x04d1, {1|U, {0x04d0}}},
- {0x04d3, {1|U, {0x04d2}}},
- {0x04d5, {1|U, {0x04d4}}},
- {0x04d7, {1|U, {0x04d6}}},
- {0x04d9, {1|U, {0x04d8}}},
- {0x04db, {1|U, {0x04da}}},
- {0x04dd, {1|U, {0x04dc}}},
- {0x04df, {1|U, {0x04de}}},
- {0x04e1, {1|U, {0x04e0}}},
- {0x04e3, {1|U, {0x04e2}}},
- {0x04e5, {1|U, {0x04e4}}},
- {0x04e7, {1|U, {0x04e6}}},
- {0x04e9, {1|U, {0x04e8}}},
- {0x04eb, {1|U, {0x04ea}}},
- {0x04ed, {1|U, {0x04ec}}},
- {0x04ef, {1|U, {0x04ee}}},
- {0x04f1, {1|U, {0x04f0}}},
- {0x04f3, {1|U, {0x04f2}}},
- {0x04f5, {1|U, {0x04f4}}},
- {0x04f7, {1|U, {0x04f6}}},
- {0x04f9, {1|U, {0x04f8}}},
- {0x04fb, {1|U, {0x04fa}}},
- {0x04fd, {1|U, {0x04fc}}},
- {0x04ff, {1|U, {0x04fe}}},
- {0x0501, {1|U, {0x0500}}},
- {0x0503, {1|U, {0x0502}}},
- {0x0505, {1|U, {0x0504}}},
- {0x0507, {1|U, {0x0506}}},
- {0x0509, {1|U, {0x0508}}},
- {0x050b, {1|U, {0x050a}}},
- {0x050d, {1|U, {0x050c}}},
- {0x050f, {1|U, {0x050e}}},
- {0x0511, {1|U, {0x0510}}},
- {0x0513, {1|U, {0x0512}}},
- {0x0515, {1|U, {0x0514}}},
- {0x0517, {1|U, {0x0516}}},
- {0x0519, {1|U, {0x0518}}},
- {0x051b, {1|U, {0x051a}}},
- {0x051d, {1|U, {0x051c}}},
- {0x051f, {1|U, {0x051e}}},
- {0x0521, {1|U, {0x0520}}},
- {0x0523, {1|U, {0x0522}}},
- {0x0525, {1|U, {0x0524}}},
- {0x0527, {1|U, {0x0526}}},
- {0x0529, {1|U, {0x0528}}},
- {0x052b, {1|U, {0x052a}}},
- {0x052d, {1|U, {0x052c}}},
- {0x052f, {1|U, {0x052e}}},
- {0x0561, {1|U, {0x0531}}},
- {0x0562, {1|U, {0x0532}}},
- {0x0563, {1|U, {0x0533}}},
- {0x0564, {1|U, {0x0534}}},
- {0x0565, {1|U, {0x0535}}},
- {0x0566, {1|U, {0x0536}}},
- {0x0567, {1|U, {0x0537}}},
- {0x0568, {1|U, {0x0538}}},
- {0x0569, {1|U, {0x0539}}},
- {0x056a, {1|U, {0x053a}}},
- {0x056b, {1|U, {0x053b}}},
- {0x056c, {1|U, {0x053c}}},
- {0x056d, {1|U, {0x053d}}},
- {0x056e, {1|U, {0x053e}}},
- {0x056f, {1|U, {0x053f}}},
- {0x0570, {1|U, {0x0540}}},
- {0x0571, {1|U, {0x0541}}},
- {0x0572, {1|U, {0x0542}}},
- {0x0573, {1|U, {0x0543}}},
- {0x0574, {1|U, {0x0544}}},
- {0x0575, {1|U, {0x0545}}},
- {0x0576, {1|U, {0x0546}}},
- {0x0577, {1|U, {0x0547}}},
- {0x0578, {1|U, {0x0548}}},
- {0x0579, {1|U, {0x0549}}},
- {0x057a, {1|U, {0x054a}}},
- {0x057b, {1|U, {0x054b}}},
- {0x057c, {1|U, {0x054c}}},
- {0x057d, {1|U, {0x054d}}},
- {0x057e, {1|U, {0x054e}}},
- {0x057f, {1|U, {0x054f}}},
- {0x0580, {1|U, {0x0550}}},
- {0x0581, {1|U, {0x0551}}},
- {0x0582, {1|U, {0x0552}}},
- {0x0583, {1|U, {0x0553}}},
- {0x0584, {1|U, {0x0554}}},
- {0x0585, {1|U, {0x0555}}},
- {0x0586, {1|U, {0x0556}}},
- {0x10d0, {1|U|IT, {0x1c90}}},
- {0x10d1, {1|U|IT, {0x1c91}}},
- {0x10d2, {1|U|IT, {0x1c92}}},
- {0x10d3, {1|U|IT, {0x1c93}}},
- {0x10d4, {1|U|IT, {0x1c94}}},
- {0x10d5, {1|U|IT, {0x1c95}}},
- {0x10d6, {1|U|IT, {0x1c96}}},
- {0x10d7, {1|U|IT, {0x1c97}}},
- {0x10d8, {1|U|IT, {0x1c98}}},
- {0x10d9, {1|U|IT, {0x1c99}}},
- {0x10da, {1|U|IT, {0x1c9a}}},
- {0x10db, {1|U|IT, {0x1c9b}}},
- {0x10dc, {1|U|IT, {0x1c9c}}},
- {0x10dd, {1|U|IT, {0x1c9d}}},
- {0x10de, {1|U|IT, {0x1c9e}}},
- {0x10df, {1|U|IT, {0x1c9f}}},
- {0x10e0, {1|U|IT, {0x1ca0}}},
- {0x10e1, {1|U|IT, {0x1ca1}}},
- {0x10e2, {1|U|IT, {0x1ca2}}},
- {0x10e3, {1|U|IT, {0x1ca3}}},
- {0x10e4, {1|U|IT, {0x1ca4}}},
- {0x10e5, {1|U|IT, {0x1ca5}}},
- {0x10e6, {1|U|IT, {0x1ca6}}},
- {0x10e7, {1|U|IT, {0x1ca7}}},
- {0x10e8, {1|U|IT, {0x1ca8}}},
- {0x10e9, {1|U|IT, {0x1ca9}}},
- {0x10ea, {1|U|IT, {0x1caa}}},
- {0x10eb, {1|U|IT, {0x1cab}}},
- {0x10ec, {1|U|IT, {0x1cac}}},
- {0x10ed, {1|U|IT, {0x1cad}}},
- {0x10ee, {1|U|IT, {0x1cae}}},
- {0x10ef, {1|U|IT, {0x1caf}}},
- {0x10f0, {1|U|IT, {0x1cb0}}},
- {0x10f1, {1|U|IT, {0x1cb1}}},
- {0x10f2, {1|U|IT, {0x1cb2}}},
- {0x10f3, {1|U|IT, {0x1cb3}}},
- {0x10f4, {1|U|IT, {0x1cb4}}},
- {0x10f5, {1|U|IT, {0x1cb5}}},
- {0x10f6, {1|U|IT, {0x1cb6}}},
- {0x10f7, {1|U|IT, {0x1cb7}}},
- {0x10f8, {1|U|IT, {0x1cb8}}},
- {0x10f9, {1|U|IT, {0x1cb9}}},
- {0x10fa, {1|U|IT, {0x1cba}}},
- {0x10fd, {1|U|IT, {0x1cbd}}},
- {0x10fe, {1|U|IT, {0x1cbe}}},
- {0x10ff, {1|U|IT, {0x1cbf}}},
- {0x13a0, {1|D, {0xab70}}},
- {0x13a1, {1|D, {0xab71}}},
- {0x13a2, {1|D, {0xab72}}},
- {0x13a3, {1|D, {0xab73}}},
- {0x13a4, {1|D, {0xab74}}},
- {0x13a5, {1|D, {0xab75}}},
- {0x13a6, {1|D, {0xab76}}},
- {0x13a7, {1|D, {0xab77}}},
- {0x13a8, {1|D, {0xab78}}},
- {0x13a9, {1|D, {0xab79}}},
- {0x13aa, {1|D, {0xab7a}}},
- {0x13ab, {1|D, {0xab7b}}},
- {0x13ac, {1|D, {0xab7c}}},
- {0x13ad, {1|D, {0xab7d}}},
- {0x13ae, {1|D, {0xab7e}}},
- {0x13af, {1|D, {0xab7f}}},
- {0x13b0, {1|D, {0xab80}}},
- {0x13b1, {1|D, {0xab81}}},
- {0x13b2, {1|D, {0xab82}}},
- {0x13b3, {1|D, {0xab83}}},
- {0x13b4, {1|D, {0xab84}}},
- {0x13b5, {1|D, {0xab85}}},
- {0x13b6, {1|D, {0xab86}}},
- {0x13b7, {1|D, {0xab87}}},
- {0x13b8, {1|D, {0xab88}}},
- {0x13b9, {1|D, {0xab89}}},
- {0x13ba, {1|D, {0xab8a}}},
- {0x13bb, {1|D, {0xab8b}}},
- {0x13bc, {1|D, {0xab8c}}},
- {0x13bd, {1|D, {0xab8d}}},
- {0x13be, {1|D, {0xab8e}}},
- {0x13bf, {1|D, {0xab8f}}},
- {0x13c0, {1|D, {0xab90}}},
- {0x13c1, {1|D, {0xab91}}},
- {0x13c2, {1|D, {0xab92}}},
- {0x13c3, {1|D, {0xab93}}},
- {0x13c4, {1|D, {0xab94}}},
- {0x13c5, {1|D, {0xab95}}},
- {0x13c6, {1|D, {0xab96}}},
- {0x13c7, {1|D, {0xab97}}},
- {0x13c8, {1|D, {0xab98}}},
- {0x13c9, {1|D, {0xab99}}},
- {0x13ca, {1|D, {0xab9a}}},
- {0x13cb, {1|D, {0xab9b}}},
- {0x13cc, {1|D, {0xab9c}}},
- {0x13cd, {1|D, {0xab9d}}},
- {0x13ce, {1|D, {0xab9e}}},
- {0x13cf, {1|D, {0xab9f}}},
- {0x13d0, {1|D, {0xaba0}}},
- {0x13d1, {1|D, {0xaba1}}},
- {0x13d2, {1|D, {0xaba2}}},
- {0x13d3, {1|D, {0xaba3}}},
- {0x13d4, {1|D, {0xaba4}}},
- {0x13d5, {1|D, {0xaba5}}},
- {0x13d6, {1|D, {0xaba6}}},
- {0x13d7, {1|D, {0xaba7}}},
- {0x13d8, {1|D, {0xaba8}}},
- {0x13d9, {1|D, {0xaba9}}},
- {0x13da, {1|D, {0xabaa}}},
- {0x13db, {1|D, {0xabab}}},
- {0x13dc, {1|D, {0xabac}}},
- {0x13dd, {1|D, {0xabad}}},
- {0x13de, {1|D, {0xabae}}},
- {0x13df, {1|D, {0xabaf}}},
- {0x13e0, {1|D, {0xabb0}}},
- {0x13e1, {1|D, {0xabb1}}},
- {0x13e2, {1|D, {0xabb2}}},
- {0x13e3, {1|D, {0xabb3}}},
- {0x13e4, {1|D, {0xabb4}}},
- {0x13e5, {1|D, {0xabb5}}},
- {0x13e6, {1|D, {0xabb6}}},
- {0x13e7, {1|D, {0xabb7}}},
- {0x13e8, {1|D, {0xabb8}}},
- {0x13e9, {1|D, {0xabb9}}},
- {0x13ea, {1|D, {0xabba}}},
- {0x13eb, {1|D, {0xabbb}}},
- {0x13ec, {1|D, {0xabbc}}},
- {0x13ed, {1|D, {0xabbd}}},
- {0x13ee, {1|D, {0xabbe}}},
- {0x13ef, {1|D, {0xabbf}}},
- {0x13f0, {1|D, {0x13f8}}},
- {0x13f1, {1|D, {0x13f9}}},
- {0x13f2, {1|D, {0x13fa}}},
- {0x13f3, {1|D, {0x13fb}}},
- {0x13f4, {1|D, {0x13fc}}},
- {0x13f5, {1|D, {0x13fd}}},
- {0x1c8a, {1|U, {0x1c89}}},
- {0x1d79, {1|U, {0xa77d}}},
- {0x1d7d, {1|U, {0x2c63}}},
- {0x1d8e, {1|U, {0xa7c6}}},
- {0x1e01, {1|U, {0x1e00}}},
- {0x1e03, {1|U, {0x1e02}}},
- {0x1e05, {1|U, {0x1e04}}},
- {0x1e07, {1|U, {0x1e06}}},
- {0x1e09, {1|U, {0x1e08}}},
- {0x1e0b, {1|U, {0x1e0a}}},
- {0x1e0d, {1|U, {0x1e0c}}},
- {0x1e0f, {1|U, {0x1e0e}}},
- {0x1e11, {1|U, {0x1e10}}},
- {0x1e13, {1|U, {0x1e12}}},
- {0x1e15, {1|U, {0x1e14}}},
- {0x1e17, {1|U, {0x1e16}}},
- {0x1e19, {1|U, {0x1e18}}},
- {0x1e1b, {1|U, {0x1e1a}}},
- {0x1e1d, {1|U, {0x1e1c}}},
- {0x1e1f, {1|U, {0x1e1e}}},
- {0x1e21, {1|U, {0x1e20}}},
- {0x1e23, {1|U, {0x1e22}}},
- {0x1e25, {1|U, {0x1e24}}},
- {0x1e27, {1|U, {0x1e26}}},
- {0x1e29, {1|U, {0x1e28}}},
- {0x1e2b, {1|U, {0x1e2a}}},
- {0x1e2d, {1|U, {0x1e2c}}},
- {0x1e2f, {1|U, {0x1e2e}}},
- {0x1e31, {1|U, {0x1e30}}},
- {0x1e33, {1|U, {0x1e32}}},
- {0x1e35, {1|U, {0x1e34}}},
- {0x1e37, {1|U, {0x1e36}}},
- {0x1e39, {1|U, {0x1e38}}},
- {0x1e3b, {1|U, {0x1e3a}}},
- {0x1e3d, {1|U, {0x1e3c}}},
- {0x1e3f, {1|U, {0x1e3e}}},
- {0x1e41, {1|U, {0x1e40}}},
- {0x1e43, {1|U, {0x1e42}}},
- {0x1e45, {1|U, {0x1e44}}},
- {0x1e47, {1|U, {0x1e46}}},
- {0x1e49, {1|U, {0x1e48}}},
- {0x1e4b, {1|U, {0x1e4a}}},
- {0x1e4d, {1|U, {0x1e4c}}},
- {0x1e4f, {1|U, {0x1e4e}}},
- {0x1e51, {1|U, {0x1e50}}},
- {0x1e53, {1|U, {0x1e52}}},
- {0x1e55, {1|U, {0x1e54}}},
- {0x1e57, {1|U, {0x1e56}}},
- {0x1e59, {1|U, {0x1e58}}},
- {0x1e5b, {1|U, {0x1e5a}}},
- {0x1e5d, {1|U, {0x1e5c}}},
- {0x1e5f, {1|U, {0x1e5e}}},
- {0x1e61, {2|U, {0x1e60, 0x1e9b}}},
- {0x1e63, {1|U, {0x1e62}}},
- {0x1e65, {1|U, {0x1e64}}},
- {0x1e67, {1|U, {0x1e66}}},
- {0x1e69, {1|U, {0x1e68}}},
- {0x1e6b, {1|U, {0x1e6a}}},
- {0x1e6d, {1|U, {0x1e6c}}},
- {0x1e6f, {1|U, {0x1e6e}}},
- {0x1e71, {1|U, {0x1e70}}},
- {0x1e73, {1|U, {0x1e72}}},
- {0x1e75, {1|U, {0x1e74}}},
- {0x1e77, {1|U, {0x1e76}}},
- {0x1e79, {1|U, {0x1e78}}},
- {0x1e7b, {1|U, {0x1e7a}}},
- {0x1e7d, {1|U, {0x1e7c}}},
- {0x1e7f, {1|U, {0x1e7e}}},
- {0x1e81, {1|U, {0x1e80}}},
- {0x1e83, {1|U, {0x1e82}}},
- {0x1e85, {1|U, {0x1e84}}},
- {0x1e87, {1|U, {0x1e86}}},
- {0x1e89, {1|U, {0x1e88}}},
- {0x1e8b, {1|U, {0x1e8a}}},
- {0x1e8d, {1|U, {0x1e8c}}},
- {0x1e8f, {1|U, {0x1e8e}}},
- {0x1e91, {1|U, {0x1e90}}},
- {0x1e93, {1|U, {0x1e92}}},
- {0x1e95, {1|U, {0x1e94}}},
- {0x1ea1, {1|U, {0x1ea0}}},
- {0x1ea3, {1|U, {0x1ea2}}},
- {0x1ea5, {1|U, {0x1ea4}}},
- {0x1ea7, {1|U, {0x1ea6}}},
- {0x1ea9, {1|U, {0x1ea8}}},
- {0x1eab, {1|U, {0x1eaa}}},
- {0x1ead, {1|U, {0x1eac}}},
- {0x1eaf, {1|U, {0x1eae}}},
- {0x1eb1, {1|U, {0x1eb0}}},
- {0x1eb3, {1|U, {0x1eb2}}},
- {0x1eb5, {1|U, {0x1eb4}}},
- {0x1eb7, {1|U, {0x1eb6}}},
- {0x1eb9, {1|U, {0x1eb8}}},
- {0x1ebb, {1|U, {0x1eba}}},
- {0x1ebd, {1|U, {0x1ebc}}},
- {0x1ebf, {1|U, {0x1ebe}}},
- {0x1ec1, {1|U, {0x1ec0}}},
- {0x1ec3, {1|U, {0x1ec2}}},
- {0x1ec5, {1|U, {0x1ec4}}},
- {0x1ec7, {1|U, {0x1ec6}}},
- {0x1ec9, {1|U, {0x1ec8}}},
- {0x1ecb, {1|U, {0x1eca}}},
- {0x1ecd, {1|U, {0x1ecc}}},
- {0x1ecf, {1|U, {0x1ece}}},
- {0x1ed1, {1|U, {0x1ed0}}},
- {0x1ed3, {1|U, {0x1ed2}}},
- {0x1ed5, {1|U, {0x1ed4}}},
- {0x1ed7, {1|U, {0x1ed6}}},
- {0x1ed9, {1|U, {0x1ed8}}},
- {0x1edb, {1|U, {0x1eda}}},
- {0x1edd, {1|U, {0x1edc}}},
- {0x1edf, {1|U, {0x1ede}}},
- {0x1ee1, {1|U, {0x1ee0}}},
- {0x1ee3, {1|U, {0x1ee2}}},
- {0x1ee5, {1|U, {0x1ee4}}},
- {0x1ee7, {1|U, {0x1ee6}}},
- {0x1ee9, {1|U, {0x1ee8}}},
- {0x1eeb, {1|U, {0x1eea}}},
- {0x1eed, {1|U, {0x1eec}}},
- {0x1eef, {1|U, {0x1eee}}},
- {0x1ef1, {1|U, {0x1ef0}}},
- {0x1ef3, {1|U, {0x1ef2}}},
- {0x1ef5, {1|U, {0x1ef4}}},
- {0x1ef7, {1|U, {0x1ef6}}},
- {0x1ef9, {1|U, {0x1ef8}}},
- {0x1efb, {1|U, {0x1efa}}},
- {0x1efd, {1|U, {0x1efc}}},
- {0x1eff, {1|U, {0x1efe}}},
- {0x1f00, {1|U, {0x1f08}}},
- {0x1f01, {1|U, {0x1f09}}},
- {0x1f02, {1|U, {0x1f0a}}},
- {0x1f03, {1|U, {0x1f0b}}},
- {0x1f04, {1|U, {0x1f0c}}},
- {0x1f05, {1|U, {0x1f0d}}},
- {0x1f06, {1|U, {0x1f0e}}},
- {0x1f07, {1|U, {0x1f0f}}},
- {0x1f10, {1|U, {0x1f18}}},
- {0x1f11, {1|U, {0x1f19}}},
- {0x1f12, {1|U, {0x1f1a}}},
- {0x1f13, {1|U, {0x1f1b}}},
- {0x1f14, {1|U, {0x1f1c}}},
- {0x1f15, {1|U, {0x1f1d}}},
- {0x1f20, {1|U, {0x1f28}}},
- {0x1f21, {1|U, {0x1f29}}},
- {0x1f22, {1|U, {0x1f2a}}},
- {0x1f23, {1|U, {0x1f2b}}},
- {0x1f24, {1|U, {0x1f2c}}},
- {0x1f25, {1|U, {0x1f2d}}},
- {0x1f26, {1|U, {0x1f2e}}},
- {0x1f27, {1|U, {0x1f2f}}},
- {0x1f30, {1|U, {0x1f38}}},
- {0x1f31, {1|U, {0x1f39}}},
- {0x1f32, {1|U, {0x1f3a}}},
- {0x1f33, {1|U, {0x1f3b}}},
- {0x1f34, {1|U, {0x1f3c}}},
- {0x1f35, {1|U, {0x1f3d}}},
- {0x1f36, {1|U, {0x1f3e}}},
- {0x1f37, {1|U, {0x1f3f}}},
- {0x1f40, {1|U, {0x1f48}}},
- {0x1f41, {1|U, {0x1f49}}},
- {0x1f42, {1|U, {0x1f4a}}},
- {0x1f43, {1|U, {0x1f4b}}},
- {0x1f44, {1|U, {0x1f4c}}},
- {0x1f45, {1|U, {0x1f4d}}},
- {0x1f51, {1|U, {0x1f59}}},
- {0x1f53, {1|U, {0x1f5b}}},
- {0x1f55, {1|U, {0x1f5d}}},
- {0x1f57, {1|U, {0x1f5f}}},
- {0x1f60, {1|U, {0x1f68}}},
- {0x1f61, {1|U, {0x1f69}}},
- {0x1f62, {1|U, {0x1f6a}}},
- {0x1f63, {1|U, {0x1f6b}}},
- {0x1f64, {1|U, {0x1f6c}}},
- {0x1f65, {1|U, {0x1f6d}}},
- {0x1f66, {1|U, {0x1f6e}}},
- {0x1f67, {1|U, {0x1f6f}}},
- {0x1f70, {1|U, {0x1fba}}},
- {0x1f71, {1|U, {0x1fbb}}},
- {0x1f72, {1|U, {0x1fc8}}},
- {0x1f73, {1|U, {0x1fc9}}},
- {0x1f74, {1|U, {0x1fca}}},
- {0x1f75, {1|U, {0x1fcb}}},
- {0x1f76, {1|U, {0x1fda}}},
- {0x1f77, {1|U, {0x1fdb}}},
- {0x1f78, {1|U, {0x1ff8}}},
- {0x1f79, {1|U, {0x1ff9}}},
- {0x1f7a, {1|U, {0x1fea}}},
- {0x1f7b, {1|U, {0x1feb}}},
- {0x1f7c, {1|U, {0x1ffa}}},
- {0x1f7d, {1|U, {0x1ffb}}},
- {0x1fb0, {1|U, {0x1fb8}}},
- {0x1fb1, {1|U, {0x1fb9}}},
- {0x1fd0, {1|U, {0x1fd8}}},
- {0x1fd1, {1|U, {0x1fd9}}},
- {0x1fe0, {1|U, {0x1fe8}}},
- {0x1fe1, {1|U, {0x1fe9}}},
- {0x1fe5, {1|U, {0x1fec}}},
- {0x214e, {1|U, {0x2132}}},
- {0x2170, {1|U, {0x2160}}},
- {0x2171, {1|U, {0x2161}}},
- {0x2172, {1|U, {0x2162}}},
- {0x2173, {1|U, {0x2163}}},
- {0x2174, {1|U, {0x2164}}},
- {0x2175, {1|U, {0x2165}}},
- {0x2176, {1|U, {0x2166}}},
- {0x2177, {1|U, {0x2167}}},
- {0x2178, {1|U, {0x2168}}},
- {0x2179, {1|U, {0x2169}}},
- {0x217a, {1|U, {0x216a}}},
- {0x217b, {1|U, {0x216b}}},
- {0x217c, {1|U, {0x216c}}},
- {0x217d, {1|U, {0x216d}}},
- {0x217e, {1|U, {0x216e}}},
- {0x217f, {1|U, {0x216f}}},
- {0x2184, {1|U, {0x2183}}},
- {0x24d0, {1|U, {0x24b6}}},
- {0x24d1, {1|U, {0x24b7}}},
- {0x24d2, {1|U, {0x24b8}}},
- {0x24d3, {1|U, {0x24b9}}},
- {0x24d4, {1|U, {0x24ba}}},
- {0x24d5, {1|U, {0x24bb}}},
- {0x24d6, {1|U, {0x24bc}}},
- {0x24d7, {1|U, {0x24bd}}},
- {0x24d8, {1|U, {0x24be}}},
- {0x24d9, {1|U, {0x24bf}}},
- {0x24da, {1|U, {0x24c0}}},
- {0x24db, {1|U, {0x24c1}}},
- {0x24dc, {1|U, {0x24c2}}},
- {0x24dd, {1|U, {0x24c3}}},
- {0x24de, {1|U, {0x24c4}}},
- {0x24df, {1|U, {0x24c5}}},
- {0x24e0, {1|U, {0x24c6}}},
- {0x24e1, {1|U, {0x24c7}}},
- {0x24e2, {1|U, {0x24c8}}},
- {0x24e3, {1|U, {0x24c9}}},
- {0x24e4, {1|U, {0x24ca}}},
- {0x24e5, {1|U, {0x24cb}}},
- {0x24e6, {1|U, {0x24cc}}},
- {0x24e7, {1|U, {0x24cd}}},
- {0x24e8, {1|U, {0x24ce}}},
- {0x24e9, {1|U, {0x24cf}}},
- {0x2c30, {1|U, {0x2c00}}},
- {0x2c31, {1|U, {0x2c01}}},
- {0x2c32, {1|U, {0x2c02}}},
- {0x2c33, {1|U, {0x2c03}}},
- {0x2c34, {1|U, {0x2c04}}},
- {0x2c35, {1|U, {0x2c05}}},
- {0x2c36, {1|U, {0x2c06}}},
- {0x2c37, {1|U, {0x2c07}}},
- {0x2c38, {1|U, {0x2c08}}},
- {0x2c39, {1|U, {0x2c09}}},
- {0x2c3a, {1|U, {0x2c0a}}},
- {0x2c3b, {1|U, {0x2c0b}}},
- {0x2c3c, {1|U, {0x2c0c}}},
- {0x2c3d, {1|U, {0x2c0d}}},
- {0x2c3e, {1|U, {0x2c0e}}},
- {0x2c3f, {1|U, {0x2c0f}}},
- {0x2c40, {1|U, {0x2c10}}},
- {0x2c41, {1|U, {0x2c11}}},
- {0x2c42, {1|U, {0x2c12}}},
- {0x2c43, {1|U, {0x2c13}}},
- {0x2c44, {1|U, {0x2c14}}},
- {0x2c45, {1|U, {0x2c15}}},
- {0x2c46, {1|U, {0x2c16}}},
- {0x2c47, {1|U, {0x2c17}}},
- {0x2c48, {1|U, {0x2c18}}},
- {0x2c49, {1|U, {0x2c19}}},
- {0x2c4a, {1|U, {0x2c1a}}},
- {0x2c4b, {1|U, {0x2c1b}}},
- {0x2c4c, {1|U, {0x2c1c}}},
- {0x2c4d, {1|U, {0x2c1d}}},
- {0x2c4e, {1|U, {0x2c1e}}},
- {0x2c4f, {1|U, {0x2c1f}}},
- {0x2c50, {1|U, {0x2c20}}},
- {0x2c51, {1|U, {0x2c21}}},
- {0x2c52, {1|U, {0x2c22}}},
- {0x2c53, {1|U, {0x2c23}}},
- {0x2c54, {1|U, {0x2c24}}},
- {0x2c55, {1|U, {0x2c25}}},
- {0x2c56, {1|U, {0x2c26}}},
- {0x2c57, {1|U, {0x2c27}}},
- {0x2c58, {1|U, {0x2c28}}},
- {0x2c59, {1|U, {0x2c29}}},
- {0x2c5a, {1|U, {0x2c2a}}},
- {0x2c5b, {1|U, {0x2c2b}}},
- {0x2c5c, {1|U, {0x2c2c}}},
- {0x2c5d, {1|U, {0x2c2d}}},
- {0x2c5e, {1|U, {0x2c2e}}},
- {0x2c5f, {1|U, {0x2c2f}}},
- {0x2c61, {1|U, {0x2c60}}},
- {0x2c65, {1|U, {0x023a}}},
- {0x2c66, {1|U, {0x023e}}},
- {0x2c68, {1|U, {0x2c67}}},
- {0x2c6a, {1|U, {0x2c69}}},
- {0x2c6c, {1|U, {0x2c6b}}},
- {0x2c73, {1|U, {0x2c72}}},
- {0x2c76, {1|U, {0x2c75}}},
- {0x2c81, {1|U, {0x2c80}}},
- {0x2c83, {1|U, {0x2c82}}},
- {0x2c85, {1|U, {0x2c84}}},
- {0x2c87, {1|U, {0x2c86}}},
- {0x2c89, {1|U, {0x2c88}}},
- {0x2c8b, {1|U, {0x2c8a}}},
- {0x2c8d, {1|U, {0x2c8c}}},
- {0x2c8f, {1|U, {0x2c8e}}},
- {0x2c91, {1|U, {0x2c90}}},
- {0x2c93, {1|U, {0x2c92}}},
- {0x2c95, {1|U, {0x2c94}}},
- {0x2c97, {1|U, {0x2c96}}},
- {0x2c99, {1|U, {0x2c98}}},
- {0x2c9b, {1|U, {0x2c9a}}},
- {0x2c9d, {1|U, {0x2c9c}}},
- {0x2c9f, {1|U, {0x2c9e}}},
- {0x2ca1, {1|U, {0x2ca0}}},
- {0x2ca3, {1|U, {0x2ca2}}},
- {0x2ca5, {1|U, {0x2ca4}}},
- {0x2ca7, {1|U, {0x2ca6}}},
- {0x2ca9, {1|U, {0x2ca8}}},
- {0x2cab, {1|U, {0x2caa}}},
- {0x2cad, {1|U, {0x2cac}}},
- {0x2caf, {1|U, {0x2cae}}},
- {0x2cb1, {1|U, {0x2cb0}}},
- {0x2cb3, {1|U, {0x2cb2}}},
- {0x2cb5, {1|U, {0x2cb4}}},
- {0x2cb7, {1|U, {0x2cb6}}},
- {0x2cb9, {1|U, {0x2cb8}}},
- {0x2cbb, {1|U, {0x2cba}}},
- {0x2cbd, {1|U, {0x2cbc}}},
- {0x2cbf, {1|U, {0x2cbe}}},
- {0x2cc1, {1|U, {0x2cc0}}},
- {0x2cc3, {1|U, {0x2cc2}}},
- {0x2cc5, {1|U, {0x2cc4}}},
- {0x2cc7, {1|U, {0x2cc6}}},
- {0x2cc9, {1|U, {0x2cc8}}},
- {0x2ccb, {1|U, {0x2cca}}},
- {0x2ccd, {1|U, {0x2ccc}}},
- {0x2ccf, {1|U, {0x2cce}}},
- {0x2cd1, {1|U, {0x2cd0}}},
- {0x2cd3, {1|U, {0x2cd2}}},
- {0x2cd5, {1|U, {0x2cd4}}},
- {0x2cd7, {1|U, {0x2cd6}}},
- {0x2cd9, {1|U, {0x2cd8}}},
- {0x2cdb, {1|U, {0x2cda}}},
- {0x2cdd, {1|U, {0x2cdc}}},
- {0x2cdf, {1|U, {0x2cde}}},
- {0x2ce1, {1|U, {0x2ce0}}},
- {0x2ce3, {1|U, {0x2ce2}}},
- {0x2cec, {1|U, {0x2ceb}}},
- {0x2cee, {1|U, {0x2ced}}},
- {0x2cf3, {1|U, {0x2cf2}}},
- {0x2d00, {1|U, {0x10a0}}},
- {0x2d01, {1|U, {0x10a1}}},
- {0x2d02, {1|U, {0x10a2}}},
- {0x2d03, {1|U, {0x10a3}}},
- {0x2d04, {1|U, {0x10a4}}},
- {0x2d05, {1|U, {0x10a5}}},
- {0x2d06, {1|U, {0x10a6}}},
- {0x2d07, {1|U, {0x10a7}}},
- {0x2d08, {1|U, {0x10a8}}},
- {0x2d09, {1|U, {0x10a9}}},
- {0x2d0a, {1|U, {0x10aa}}},
- {0x2d0b, {1|U, {0x10ab}}},
- {0x2d0c, {1|U, {0x10ac}}},
- {0x2d0d, {1|U, {0x10ad}}},
- {0x2d0e, {1|U, {0x10ae}}},
- {0x2d0f, {1|U, {0x10af}}},
- {0x2d10, {1|U, {0x10b0}}},
- {0x2d11, {1|U, {0x10b1}}},
- {0x2d12, {1|U, {0x10b2}}},
- {0x2d13, {1|U, {0x10b3}}},
- {0x2d14, {1|U, {0x10b4}}},
- {0x2d15, {1|U, {0x10b5}}},
- {0x2d16, {1|U, {0x10b6}}},
- {0x2d17, {1|U, {0x10b7}}},
- {0x2d18, {1|U, {0x10b8}}},
- {0x2d19, {1|U, {0x10b9}}},
- {0x2d1a, {1|U, {0x10ba}}},
- {0x2d1b, {1|U, {0x10bb}}},
- {0x2d1c, {1|U, {0x10bc}}},
- {0x2d1d, {1|U, {0x10bd}}},
- {0x2d1e, {1|U, {0x10be}}},
- {0x2d1f, {1|U, {0x10bf}}},
- {0x2d20, {1|U, {0x10c0}}},
- {0x2d21, {1|U, {0x10c1}}},
- {0x2d22, {1|U, {0x10c2}}},
- {0x2d23, {1|U, {0x10c3}}},
- {0x2d24, {1|U, {0x10c4}}},
- {0x2d25, {1|U, {0x10c5}}},
- {0x2d27, {1|U, {0x10c7}}},
- {0x2d2d, {1|U, {0x10cd}}},
- {0xa641, {1|U, {0xa640}}},
- {0xa643, {1|U, {0xa642}}},
- {0xa645, {1|U, {0xa644}}},
- {0xa647, {1|U, {0xa646}}},
- {0xa649, {1|U, {0xa648}}},
- {0xa64b, {2|U, {0xa64a, 0x1c88}}},
- {0xa64d, {1|U, {0xa64c}}},
- {0xa64f, {1|U, {0xa64e}}},
- {0xa651, {1|U, {0xa650}}},
- {0xa653, {1|U, {0xa652}}},
- {0xa655, {1|U, {0xa654}}},
- {0xa657, {1|U, {0xa656}}},
- {0xa659, {1|U, {0xa658}}},
- {0xa65b, {1|U, {0xa65a}}},
- {0xa65d, {1|U, {0xa65c}}},
- {0xa65f, {1|U, {0xa65e}}},
- {0xa661, {1|U, {0xa660}}},
- {0xa663, {1|U, {0xa662}}},
- {0xa665, {1|U, {0xa664}}},
- {0xa667, {1|U, {0xa666}}},
- {0xa669, {1|U, {0xa668}}},
- {0xa66b, {1|U, {0xa66a}}},
- {0xa66d, {1|U, {0xa66c}}},
- {0xa681, {1|U, {0xa680}}},
- {0xa683, {1|U, {0xa682}}},
- {0xa685, {1|U, {0xa684}}},
- {0xa687, {1|U, {0xa686}}},
- {0xa689, {1|U, {0xa688}}},
- {0xa68b, {1|U, {0xa68a}}},
- {0xa68d, {1|U, {0xa68c}}},
- {0xa68f, {1|U, {0xa68e}}},
- {0xa691, {1|U, {0xa690}}},
- {0xa693, {1|U, {0xa692}}},
- {0xa695, {1|U, {0xa694}}},
- {0xa697, {1|U, {0xa696}}},
- {0xa699, {1|U, {0xa698}}},
- {0xa69b, {1|U, {0xa69a}}},
- {0xa723, {1|U, {0xa722}}},
- {0xa725, {1|U, {0xa724}}},
- {0xa727, {1|U, {0xa726}}},
- {0xa729, {1|U, {0xa728}}},
- {0xa72b, {1|U, {0xa72a}}},
- {0xa72d, {1|U, {0xa72c}}},
- {0xa72f, {1|U, {0xa72e}}},
- {0xa733, {1|U, {0xa732}}},
- {0xa735, {1|U, {0xa734}}},
- {0xa737, {1|U, {0xa736}}},
- {0xa739, {1|U, {0xa738}}},
- {0xa73b, {1|U, {0xa73a}}},
- {0xa73d, {1|U, {0xa73c}}},
- {0xa73f, {1|U, {0xa73e}}},
- {0xa741, {1|U, {0xa740}}},
- {0xa743, {1|U, {0xa742}}},
- {0xa745, {1|U, {0xa744}}},
- {0xa747, {1|U, {0xa746}}},
- {0xa749, {1|U, {0xa748}}},
- {0xa74b, {1|U, {0xa74a}}},
- {0xa74d, {1|U, {0xa74c}}},
- {0xa74f, {1|U, {0xa74e}}},
- {0xa751, {1|U, {0xa750}}},
- {0xa753, {1|U, {0xa752}}},
- {0xa755, {1|U, {0xa754}}},
- {0xa757, {1|U, {0xa756}}},
- {0xa759, {1|U, {0xa758}}},
- {0xa75b, {1|U, {0xa75a}}},
- {0xa75d, {1|U, {0xa75c}}},
- {0xa75f, {1|U, {0xa75e}}},
- {0xa761, {1|U, {0xa760}}},
- {0xa763, {1|U, {0xa762}}},
- {0xa765, {1|U, {0xa764}}},
- {0xa767, {1|U, {0xa766}}},
- {0xa769, {1|U, {0xa768}}},
- {0xa76b, {1|U, {0xa76a}}},
- {0xa76d, {1|U, {0xa76c}}},
- {0xa76f, {1|U, {0xa76e}}},
- {0xa77a, {1|U, {0xa779}}},
- {0xa77c, {1|U, {0xa77b}}},
- {0xa77f, {1|U, {0xa77e}}},
- {0xa781, {1|U, {0xa780}}},
- {0xa783, {1|U, {0xa782}}},
- {0xa785, {1|U, {0xa784}}},
- {0xa787, {1|U, {0xa786}}},
- {0xa78c, {1|U, {0xa78b}}},
- {0xa791, {1|U, {0xa790}}},
- {0xa793, {1|U, {0xa792}}},
- {0xa794, {1|U, {0xa7c4}}},
- {0xa797, {1|U, {0xa796}}},
- {0xa799, {1|U, {0xa798}}},
- {0xa79b, {1|U, {0xa79a}}},
- {0xa79d, {1|U, {0xa79c}}},
- {0xa79f, {1|U, {0xa79e}}},
- {0xa7a1, {1|U, {0xa7a0}}},
- {0xa7a3, {1|U, {0xa7a2}}},
- {0xa7a5, {1|U, {0xa7a4}}},
- {0xa7a7, {1|U, {0xa7a6}}},
- {0xa7a9, {1|U, {0xa7a8}}},
- {0xa7b5, {1|U, {0xa7b4}}},
- {0xa7b7, {1|U, {0xa7b6}}},
- {0xa7b9, {1|U, {0xa7b8}}},
- {0xa7bb, {1|U, {0xa7ba}}},
- {0xa7bd, {1|U, {0xa7bc}}},
- {0xa7bf, {1|U, {0xa7be}}},
- {0xa7c1, {1|U, {0xa7c0}}},
- {0xa7c3, {1|U, {0xa7c2}}},
- {0xa7c8, {1|U, {0xa7c7}}},
- {0xa7ca, {1|U, {0xa7c9}}},
- {0xa7cd, {1|U, {0xa7cc}}},
- {0xa7d1, {1|U, {0xa7d0}}},
- {0xa7d7, {1|U, {0xa7d6}}},
- {0xa7d9, {1|U, {0xa7d8}}},
- {0xa7db, {1|U, {0xa7da}}},
- {0xa7f6, {1|U, {0xa7f5}}},
- {0xab53, {1|U, {0xa7b3}}},
- {0xff41, {1|U, {0xff21}}},
- {0xff42, {1|U, {0xff22}}},
- {0xff43, {1|U, {0xff23}}},
- {0xff44, {1|U, {0xff24}}},
- {0xff45, {1|U, {0xff25}}},
- {0xff46, {1|U, {0xff26}}},
- {0xff47, {1|U, {0xff27}}},
- {0xff48, {1|U, {0xff28}}},
- {0xff49, {1|U, {0xff29}}},
- {0xff4a, {1|U, {0xff2a}}},
- {0xff4b, {1|U, {0xff2b}}},
- {0xff4c, {1|U, {0xff2c}}},
- {0xff4d, {1|U, {0xff2d}}},
- {0xff4e, {1|U, {0xff2e}}},
- {0xff4f, {1|U, {0xff2f}}},
- {0xff50, {1|U, {0xff30}}},
- {0xff51, {1|U, {0xff31}}},
- {0xff52, {1|U, {0xff32}}},
- {0xff53, {1|U, {0xff33}}},
- {0xff54, {1|U, {0xff34}}},
- {0xff55, {1|U, {0xff35}}},
- {0xff56, {1|U, {0xff36}}},
- {0xff57, {1|U, {0xff37}}},
- {0xff58, {1|U, {0xff38}}},
- {0xff59, {1|U, {0xff39}}},
- {0xff5a, {1|U, {0xff3a}}},
- {0x10428, {1|U, {0x10400}}},
- {0x10429, {1|U, {0x10401}}},
- {0x1042a, {1|U, {0x10402}}},
- {0x1042b, {1|U, {0x10403}}},
- {0x1042c, {1|U, {0x10404}}},
- {0x1042d, {1|U, {0x10405}}},
- {0x1042e, {1|U, {0x10406}}},
- {0x1042f, {1|U, {0x10407}}},
- {0x10430, {1|U, {0x10408}}},
- {0x10431, {1|U, {0x10409}}},
- {0x10432, {1|U, {0x1040a}}},
- {0x10433, {1|U, {0x1040b}}},
- {0x10434, {1|U, {0x1040c}}},
- {0x10435, {1|U, {0x1040d}}},
- {0x10436, {1|U, {0x1040e}}},
- {0x10437, {1|U, {0x1040f}}},
- {0x10438, {1|U, {0x10410}}},
- {0x10439, {1|U, {0x10411}}},
- {0x1043a, {1|U, {0x10412}}},
- {0x1043b, {1|U, {0x10413}}},
- {0x1043c, {1|U, {0x10414}}},
- {0x1043d, {1|U, {0x10415}}},
- {0x1043e, {1|U, {0x10416}}},
- {0x1043f, {1|U, {0x10417}}},
- {0x10440, {1|U, {0x10418}}},
- {0x10441, {1|U, {0x10419}}},
- {0x10442, {1|U, {0x1041a}}},
- {0x10443, {1|U, {0x1041b}}},
- {0x10444, {1|U, {0x1041c}}},
- {0x10445, {1|U, {0x1041d}}},
- {0x10446, {1|U, {0x1041e}}},
- {0x10447, {1|U, {0x1041f}}},
- {0x10448, {1|U, {0x10420}}},
- {0x10449, {1|U, {0x10421}}},
- {0x1044a, {1|U, {0x10422}}},
- {0x1044b, {1|U, {0x10423}}},
- {0x1044c, {1|U, {0x10424}}},
- {0x1044d, {1|U, {0x10425}}},
- {0x1044e, {1|U, {0x10426}}},
- {0x1044f, {1|U, {0x10427}}},
- {0x104d8, {1|U, {0x104b0}}},
- {0x104d9, {1|U, {0x104b1}}},
- {0x104da, {1|U, {0x104b2}}},
- {0x104db, {1|U, {0x104b3}}},
- {0x104dc, {1|U, {0x104b4}}},
- {0x104dd, {1|U, {0x104b5}}},
- {0x104de, {1|U, {0x104b6}}},
- {0x104df, {1|U, {0x104b7}}},
- {0x104e0, {1|U, {0x104b8}}},
- {0x104e1, {1|U, {0x104b9}}},
- {0x104e2, {1|U, {0x104ba}}},
- {0x104e3, {1|U, {0x104bb}}},
- {0x104e4, {1|U, {0x104bc}}},
- {0x104e5, {1|U, {0x104bd}}},
- {0x104e6, {1|U, {0x104be}}},
- {0x104e7, {1|U, {0x104bf}}},
- {0x104e8, {1|U, {0x104c0}}},
- {0x104e9, {1|U, {0x104c1}}},
- {0x104ea, {1|U, {0x104c2}}},
- {0x104eb, {1|U, {0x104c3}}},
- {0x104ec, {1|U, {0x104c4}}},
- {0x104ed, {1|U, {0x104c5}}},
- {0x104ee, {1|U, {0x104c6}}},
- {0x104ef, {1|U, {0x104c7}}},
- {0x104f0, {1|U, {0x104c8}}},
- {0x104f1, {1|U, {0x104c9}}},
- {0x104f2, {1|U, {0x104ca}}},
- {0x104f3, {1|U, {0x104cb}}},
- {0x104f4, {1|U, {0x104cc}}},
- {0x104f5, {1|U, {0x104cd}}},
- {0x104f6, {1|U, {0x104ce}}},
- {0x104f7, {1|U, {0x104cf}}},
- {0x104f8, {1|U, {0x104d0}}},
- {0x104f9, {1|U, {0x104d1}}},
- {0x104fa, {1|U, {0x104d2}}},
- {0x104fb, {1|U, {0x104d3}}},
- {0x10597, {1|U, {0x10570}}},
- {0x10598, {1|U, {0x10571}}},
- {0x10599, {1|U, {0x10572}}},
- {0x1059a, {1|U, {0x10573}}},
- {0x1059b, {1|U, {0x10574}}},
- {0x1059c, {1|U, {0x10575}}},
- {0x1059d, {1|U, {0x10576}}},
- {0x1059e, {1|U, {0x10577}}},
- {0x1059f, {1|U, {0x10578}}},
- {0x105a0, {1|U, {0x10579}}},
- {0x105a1, {1|U, {0x1057a}}},
- {0x105a3, {1|U, {0x1057c}}},
- {0x105a4, {1|U, {0x1057d}}},
- {0x105a5, {1|U, {0x1057e}}},
- {0x105a6, {1|U, {0x1057f}}},
- {0x105a7, {1|U, {0x10580}}},
- {0x105a8, {1|U, {0x10581}}},
- {0x105a9, {1|U, {0x10582}}},
- {0x105aa, {1|U, {0x10583}}},
- {0x105ab, {1|U, {0x10584}}},
- {0x105ac, {1|U, {0x10585}}},
- {0x105ad, {1|U, {0x10586}}},
- {0x105ae, {1|U, {0x10587}}},
- {0x105af, {1|U, {0x10588}}},
- {0x105b0, {1|U, {0x10589}}},
- {0x105b1, {1|U, {0x1058a}}},
- {0x105b3, {1|U, {0x1058c}}},
- {0x105b4, {1|U, {0x1058d}}},
- {0x105b5, {1|U, {0x1058e}}},
- {0x105b6, {1|U, {0x1058f}}},
- {0x105b7, {1|U, {0x10590}}},
- {0x105b8, {1|U, {0x10591}}},
- {0x105b9, {1|U, {0x10592}}},
- {0x105bb, {1|U, {0x10594}}},
- {0x105bc, {1|U, {0x10595}}},
- {0x10cc0, {1|U, {0x10c80}}},
- {0x10cc1, {1|U, {0x10c81}}},
- {0x10cc2, {1|U, {0x10c82}}},
- {0x10cc3, {1|U, {0x10c83}}},
- {0x10cc4, {1|U, {0x10c84}}},
- {0x10cc5, {1|U, {0x10c85}}},
- {0x10cc6, {1|U, {0x10c86}}},
- {0x10cc7, {1|U, {0x10c87}}},
- {0x10cc8, {1|U, {0x10c88}}},
- {0x10cc9, {1|U, {0x10c89}}},
- {0x10cca, {1|U, {0x10c8a}}},
- {0x10ccb, {1|U, {0x10c8b}}},
- {0x10ccc, {1|U, {0x10c8c}}},
- {0x10ccd, {1|U, {0x10c8d}}},
- {0x10cce, {1|U, {0x10c8e}}},
- {0x10ccf, {1|U, {0x10c8f}}},
- {0x10cd0, {1|U, {0x10c90}}},
- {0x10cd1, {1|U, {0x10c91}}},
- {0x10cd2, {1|U, {0x10c92}}},
- {0x10cd3, {1|U, {0x10c93}}},
- {0x10cd4, {1|U, {0x10c94}}},
- {0x10cd5, {1|U, {0x10c95}}},
- {0x10cd6, {1|U, {0x10c96}}},
- {0x10cd7, {1|U, {0x10c97}}},
- {0x10cd8, {1|U, {0x10c98}}},
- {0x10cd9, {1|U, {0x10c99}}},
- {0x10cda, {1|U, {0x10c9a}}},
- {0x10cdb, {1|U, {0x10c9b}}},
- {0x10cdc, {1|U, {0x10c9c}}},
- {0x10cdd, {1|U, {0x10c9d}}},
- {0x10cde, {1|U, {0x10c9e}}},
- {0x10cdf, {1|U, {0x10c9f}}},
- {0x10ce0, {1|U, {0x10ca0}}},
- {0x10ce1, {1|U, {0x10ca1}}},
- {0x10ce2, {1|U, {0x10ca2}}},
- {0x10ce3, {1|U, {0x10ca3}}},
- {0x10ce4, {1|U, {0x10ca4}}},
- {0x10ce5, {1|U, {0x10ca5}}},
- {0x10ce6, {1|U, {0x10ca6}}},
- {0x10ce7, {1|U, {0x10ca7}}},
- {0x10ce8, {1|U, {0x10ca8}}},
- {0x10ce9, {1|U, {0x10ca9}}},
- {0x10cea, {1|U, {0x10caa}}},
- {0x10ceb, {1|U, {0x10cab}}},
- {0x10cec, {1|U, {0x10cac}}},
- {0x10ced, {1|U, {0x10cad}}},
- {0x10cee, {1|U, {0x10cae}}},
- {0x10cef, {1|U, {0x10caf}}},
- {0x10cf0, {1|U, {0x10cb0}}},
- {0x10cf1, {1|U, {0x10cb1}}},
- {0x10cf2, {1|U, {0x10cb2}}},
- {0x10d70, {1|U, {0x10d50}}},
- {0x10d71, {1|U, {0x10d51}}},
- {0x10d72, {1|U, {0x10d52}}},
- {0x10d73, {1|U, {0x10d53}}},
- {0x10d74, {1|U, {0x10d54}}},
- {0x10d75, {1|U, {0x10d55}}},
- {0x10d76, {1|U, {0x10d56}}},
- {0x10d77, {1|U, {0x10d57}}},
- {0x10d78, {1|U, {0x10d58}}},
- {0x10d79, {1|U, {0x10d59}}},
- {0x10d7a, {1|U, {0x10d5a}}},
- {0x10d7b, {1|U, {0x10d5b}}},
- {0x10d7c, {1|U, {0x10d5c}}},
- {0x10d7d, {1|U, {0x10d5d}}},
- {0x10d7e, {1|U, {0x10d5e}}},
- {0x10d7f, {1|U, {0x10d5f}}},
- {0x10d80, {1|U, {0x10d60}}},
- {0x10d81, {1|U, {0x10d61}}},
- {0x10d82, {1|U, {0x10d62}}},
- {0x10d83, {1|U, {0x10d63}}},
- {0x10d84, {1|U, {0x10d64}}},
- {0x10d85, {1|U, {0x10d65}}},
- {0x118c0, {1|U, {0x118a0}}},
- {0x118c1, {1|U, {0x118a1}}},
- {0x118c2, {1|U, {0x118a2}}},
- {0x118c3, {1|U, {0x118a3}}},
- {0x118c4, {1|U, {0x118a4}}},
- {0x118c5, {1|U, {0x118a5}}},
- {0x118c6, {1|U, {0x118a6}}},
- {0x118c7, {1|U, {0x118a7}}},
- {0x118c8, {1|U, {0x118a8}}},
- {0x118c9, {1|U, {0x118a9}}},
- {0x118ca, {1|U, {0x118aa}}},
- {0x118cb, {1|U, {0x118ab}}},
- {0x118cc, {1|U, {0x118ac}}},
- {0x118cd, {1|U, {0x118ad}}},
- {0x118ce, {1|U, {0x118ae}}},
- {0x118cf, {1|U, {0x118af}}},
- {0x118d0, {1|U, {0x118b0}}},
- {0x118d1, {1|U, {0x118b1}}},
- {0x118d2, {1|U, {0x118b2}}},
- {0x118d3, {1|U, {0x118b3}}},
- {0x118d4, {1|U, {0x118b4}}},
- {0x118d5, {1|U, {0x118b5}}},
- {0x118d6, {1|U, {0x118b6}}},
- {0x118d7, {1|U, {0x118b7}}},
- {0x118d8, {1|U, {0x118b8}}},
- {0x118d9, {1|U, {0x118b9}}},
- {0x118da, {1|U, {0x118ba}}},
- {0x118db, {1|U, {0x118bb}}},
- {0x118dc, {1|U, {0x118bc}}},
- {0x118dd, {1|U, {0x118bd}}},
- {0x118de, {1|U, {0x118be}}},
- {0x118df, {1|U, {0x118bf}}},
- {0x16e60, {1|U, {0x16e40}}},
- {0x16e61, {1|U, {0x16e41}}},
- {0x16e62, {1|U, {0x16e42}}},
- {0x16e63, {1|U, {0x16e43}}},
- {0x16e64, {1|U, {0x16e44}}},
- {0x16e65, {1|U, {0x16e45}}},
- {0x16e66, {1|U, {0x16e46}}},
- {0x16e67, {1|U, {0x16e47}}},
- {0x16e68, {1|U, {0x16e48}}},
- {0x16e69, {1|U, {0x16e49}}},
- {0x16e6a, {1|U, {0x16e4a}}},
- {0x16e6b, {1|U, {0x16e4b}}},
- {0x16e6c, {1|U, {0x16e4c}}},
- {0x16e6d, {1|U, {0x16e4d}}},
- {0x16e6e, {1|U, {0x16e4e}}},
- {0x16e6f, {1|U, {0x16e4f}}},
- {0x16e70, {1|U, {0x16e50}}},
- {0x16e71, {1|U, {0x16e51}}},
- {0x16e72, {1|U, {0x16e52}}},
- {0x16e73, {1|U, {0x16e53}}},
- {0x16e74, {1|U, {0x16e54}}},
- {0x16e75, {1|U, {0x16e55}}},
- {0x16e76, {1|U, {0x16e56}}},
- {0x16e77, {1|U, {0x16e57}}},
- {0x16e78, {1|U, {0x16e58}}},
- {0x16e79, {1|U, {0x16e59}}},
- {0x16e7a, {1|U, {0x16e5a}}},
- {0x16e7b, {1|U, {0x16e5b}}},
- {0x16e7c, {1|U, {0x16e5c}}},
- {0x16e7d, {1|U, {0x16e5d}}},
- {0x16e7e, {1|U, {0x16e5e}}},
- {0x16e7f, {1|U, {0x16e5f}}},
- {0x1e922, {1|U, {0x1e900}}},
- {0x1e923, {1|U, {0x1e901}}},
- {0x1e924, {1|U, {0x1e902}}},
- {0x1e925, {1|U, {0x1e903}}},
- {0x1e926, {1|U, {0x1e904}}},
- {0x1e927, {1|U, {0x1e905}}},
- {0x1e928, {1|U, {0x1e906}}},
- {0x1e929, {1|U, {0x1e907}}},
- {0x1e92a, {1|U, {0x1e908}}},
- {0x1e92b, {1|U, {0x1e909}}},
- {0x1e92c, {1|U, {0x1e90a}}},
- {0x1e92d, {1|U, {0x1e90b}}},
- {0x1e92e, {1|U, {0x1e90c}}},
- {0x1e92f, {1|U, {0x1e90d}}},
- {0x1e930, {1|U, {0x1e90e}}},
- {0x1e931, {1|U, {0x1e90f}}},
- {0x1e932, {1|U, {0x1e910}}},
- {0x1e933, {1|U, {0x1e911}}},
- {0x1e934, {1|U, {0x1e912}}},
- {0x1e935, {1|U, {0x1e913}}},
- {0x1e936, {1|U, {0x1e914}}},
- {0x1e937, {1|U, {0x1e915}}},
- {0x1e938, {1|U, {0x1e916}}},
- {0x1e939, {1|U, {0x1e917}}},
- {0x1e93a, {1|U, {0x1e918}}},
- {0x1e93b, {1|U, {0x1e919}}},
- {0x1e93c, {1|U, {0x1e91a}}},
- {0x1e93d, {1|U, {0x1e91b}}},
- {0x1e93e, {1|U, {0x1e91c}}},
- {0x1e93f, {1|U, {0x1e91d}}},
- {0x1e940, {1|U, {0x1e91e}}},
- {0x1e941, {1|U, {0x1e91f}}},
- {0x1e942, {1|U, {0x1e920}}},
- {0x1e943, {1|U, {0x1e921}}},
-#define CaseUnfold_11_Locale (*(CaseUnfold_11_Type (*)[1])(CaseUnfold_11_Table+1422))
- {0x0069, {1|U, {0x0049}}},
-};
-
-/* ANSI-C code produced by gperf version 3.1 */
-/* Command-line: gperf -7 -k1,2,3 -F,-1 -c -j1 -i1 -t -T -E -C -H onigenc_unicode_CaseUnfold_11_hash -N onigenc_unicode_CaseUnfold_11_lookup -n */
-
-/* maximum key range = 2713, duplicates = 0 */
-
-#ifdef __GNUC__
-__inline
-#else
-#ifdef __cplusplus
-inline
-#endif
-#endif
-/*ARGSUSED*/
-static unsigned int
-onigenc_unicode_CaseUnfold_11_hash(const OnigCodePoint code)
-{
- static const unsigned short asso_values[] =
- {
- 1, 2716, 2, 1, 4, 640, 9, 260, 231, 142,
- 589, 20, 2, 3, 434, 372, 2716, 2716, 2716, 2716,
- 2716, 2716, 2716, 2716, 2716, 2716, 2716, 2716, 2716, 112,
- 404, 141, 2716, 2716, 2716, 2716, 2716, 120, 2716, 2716,
- 2716, 2716, 2716, 1, 2716, 2716, 2716, 2716, 2716, 2716,
- 2716, 2716, 2716, 395, 2716, 2716, 2716, 2716, 2716, 2716,
- 2716, 3, 11, 6, 7, 8, 244, 723, 34, 1143,
- 365, 1012, 56, 1546, 12, 1709, 9, 15, 14, 1796,
- 241, 917, 87, 227, 47, 1535, 267, 1468, 1, 1612,
- 49, 1184, 361, 10, 557, 1704, 51, 1814, 66, 1385,
- 338, 786, 740, 659, 125, 801, 354, 1134, 249, 1252,
- 327, 756, 193, 1116, 1511, 838, 1898, 703, 1796, 679,
- 1745, 629, 1856, 827, 1832, 995, 1531, 973, 1806, 811,
- 850, 511, 903, 500, 1517, 935, 1483, 876, 1461, 555,
- 1790, 541, 1703, 465, 1274, 531, 1340, 250, 1667, 342,
- 1660, 408, 1652, 194, 1622, 85, 1595, 70, 1578, 129,
- 1492, 100, 1489, 1, 1450, 25, 1432, 35, 1180, 55,
- 1415, 45, 459, 160, 1298, 317, 577, 220, 1224, 594,
- 965, 373, 1322, 670, 1062, 1243, 966, 1045, 1124, 1160,
- 1223, 1094, 1497, 1314
- };
- return asso_values[bits_of(code, 2)+66] + asso_values[bits_of(code, 1)+4] + asso_values[bits_of(code, 0)];
-}
-
-static const CodePointList3 *
-onigenc_unicode_CaseUnfold_11_lookup(const OnigCodePoint code)
-{
- enum
- {
- MIN_CODE_VALUE = 0x61,
- MAX_CODE_VALUE = 0x1e943,
- TOTAL_KEYWORDS = 1423,
- MIN_WORD_LENGTH = 3,
- MAX_WORD_LENGTH = 3,
- MIN_HASH_VALUE = 3,
- MAX_HASH_VALUE = 2715
- };
-
- static const short wordlist[] =
- {
- -1, -1, -1,
- /*0x13e1*/ 591,
- /*0x0461*/ 342,
- /*0x04e1*/ 402,
- /*0x0061*/ 0,
- -1,
- /*0x104e1*/ 1189,
- /*0x1e61*/ 664,
- /*0x1ee1*/ 723,
- /*0x0161*/ 102,
- /*0x2ce1*/ 956,
- /*0x1c8a*/ 612,
- /*0x049b*/ 367,
- -1, -1,
- /*0x24e1*/ 843,
- /*0x1e1b*/ 629,
- /*0x048b*/ 359,
- /*0x011b*/ 69,
- /*0x2c9b*/ 921,
- /*0x03e1*/ 282,
- /*0x1e0b*/ 621,
- /*0x1e8b*/ 685,
- /*0x010b*/ 61,
- /*0x2c8b*/ 913,
- /*0x13e3*/ 593,
- /*0x0463*/ 343,
- /*0x04e3*/ 403,
- /*0x0063*/ 2,
- -1,
- /*0x104e3*/ 1191,
- /*0x1e63*/ 665,
- /*0x1ee3*/ 724,
- /*0x0163*/ 103,
- /*0x2ce3*/ 957,
- /*0x13e5*/ 595,
- /*0x0465*/ 344,
- /*0x04e5*/ 404,
- /*0x0065*/ 4,
- /*0x24e3*/ 845,
- /*0x104e5*/ 1193,
- /*0x1e65*/ 666,
- /*0x1ee5*/ 725,
- /*0x0165*/ 104,
- /*0x03e3*/ 283,
- /*0x13e9*/ 599,
- /*0x0469*/ 346,
- /*0x04e9*/ 406,
- /*0x0069*/ 1422,
- /*0x24e5*/ 847,
- /*0x104e9*/ 1197,
- /*0x1e69*/ 668,
- /*0x1ee9*/ 727,
- /*0x0169*/ 106,
- /*0x03e5*/ 284,
- /*0x13e7*/ 597,
- /*0x0467*/ 345,
- /*0x04e7*/ 405,
- /*0x0067*/ 6,
- /*0x24e9*/ 851,
- /*0x104e7*/ 1195,
- /*0x1e67*/ 667,
- /*0x1ee7*/ 726,
- /*0x0167*/ 105,
- /*0x03e9*/ 286,
- -1,
- /*0x13a0*/ 526,
- -1, -1,
- /*0x24e7*/ 849,
- /*0x13db*/ 585,
- /*0x045b*/ 337,
- /*0x04db*/ 399,
- -1,
- /*0x03e7*/ 285,
- /*0x104db*/ 1183,
- /*0x1e5b*/ 661,
- /*0x1edb*/ 720,
- /*0x015b*/ 99,
- /*0x2cdb*/ 953,
- -1, -1, -1, -1,
- /*0x24db*/ 837,
- /*0x13d9*/ 583,
- /*0x0459*/ 335,
- /*0x04d9*/ 398,
- /*0xa761*/ 1068,
- /*0x03db*/ 279,
- /*0x104d9*/ 1181,
- /*0x1e59*/ 660,
- /*0x1ed9*/ 719,
- /*0x0159*/ 98,
- /*0x2cd9*/ 952,
- -1, -1, -1, -1,
- /*0x24d9*/ 835,
- /*0x13df*/ 589,
- /*0x045f*/ 341,
- /*0x04df*/ 401,
- -1,
- /*0x03d9*/ 278,
- /*0x104df*/ 1187,
- /*0x1e5f*/ 663,
- /*0x1edf*/ 722,
- /*0x015f*/ 101,
- /*0x2cdf*/ 955,
- -1, -1,
- /*0xa763*/ 1069,
- -1,
- /*0x24df*/ 841,
- /*0x10ce1*/ 1284,
- -1, -1, -1,
- /*0x03df*/ 281,
- /*0x10e1*/ 497,
- -1,
- /*0xa765*/ 1070,
- -1, -1,
- /*0x13a6*/ 532,
- -1, -1, -1,
- /*0x13dd*/ 587,
- /*0x045d*/ 339,
- /*0x04dd*/ 400,
- /*0xa769*/ 1072,
- -1,
- /*0x104dd*/ 1185,
- /*0x1e5d*/ 662,
- /*0x1edd*/ 721,
- /*0x015d*/ 100,
- /*0x2cdd*/ 954,
- /*0x10ce3*/ 1286,
- -1, -1,
- /*0xa767*/ 1071,
- /*0x24dd*/ 839,
- /*0x10e3*/ 499,
- -1, -1, -1,
- /*0x03dd*/ 280,
- /*0x10ce5*/ 1288,
- /*0x028a*/ 232,
- -1, -1,
- /*0x0288*/ 230,
- /*0x10e5*/ 501,
- /*0x028c*/ 234,
- /*0x028b*/ 233,
- /*0xa75b*/ 1065,
- -1,
- /*0x10ce9*/ 1292,
- /*0x13eb*/ 601,
- /*0x046b*/ 347,
- /*0x04eb*/ 407,
- /*0x006b*/ 9,
- /*0x10e9*/ 505,
- /*0x104eb*/ 1199,
- /*0x1e6b*/ 669,
- /*0x1eeb*/ 728,
- /*0x016b*/ 107,
- /*0x10ce7*/ 1290,
- -1, -1,
- /*0xa759*/ 1064,
- -1,
- /*0x10e7*/ 503,
- /*0x0282*/ 227,
- -1,
- /*0x10d82*/ 1320,
- -1,
- /*0x03eb*/ 287,
- -1, -1, -1, -1,
- /*0x10cdb*/ 1278,
- -1, -1,
- /*0xa75f*/ 1067,
- /*0x0292*/ 235,
- /*0x10db*/ 491,
- -1, -1,
- /*0x029e*/ 237,
- /*0x13ae*/ 540,
- /*0x13d7*/ 581,
- /*0x0457*/ 333,
- /*0x04d7*/ 397,
- /*0x1042e*/ 1146,
- -1,
- /*0x10cd9*/ 1276,
- /*0x1e57*/ 659,
- /*0x1ed7*/ 718,
- /*0x0157*/ 97,
- /*0x2cd7*/ 951,
- /*0x10d9*/ 489,
- -1, -1, -1,
- /*0x24d7*/ 833,
- -1, -1, -1,
- /*0x03ae*/ 246,
- /*0x03d7*/ 277,
- /*0x10cdf*/ 1282,
- -1,
- /*0xa75d*/ 1066,
- -1, -1,
- /*0x10df*/ 495,
- /*0x13ef*/ 605,
- /*0x046f*/ 349,
- /*0x04ef*/ 409,
- /*0x006f*/ 13,
- -1,
- /*0x104ef*/ 1203,
- /*0x1e6f*/ 671,
- /*0x1eef*/ 730,
- /*0x016f*/ 109,
- /*0x0491*/ 362,
- -1,
- /*0x0261*/ 211,
- -1,
- /*0x1e11*/ 624,
- /*0x1e91*/ 688,
- /*0x0111*/ 64,
- /*0x2c91*/ 916,
- /*0xa79b*/ 1089,
- -1,
- /*0x03ef*/ 289,
- /*0x021b*/ 179,
- /*0xa78c*/ 1083,
- /*0xa661*/ 1017,
- /*0x10cdd*/ 1280,
- /*0x1f61*/ 780,
- /*0x020b*/ 171,
- /*0x1d8e*/ 615,
- /*0xa76b*/ 1073,
- /*0x10dd*/ 493,
- /*0x13aa*/ 536,
- /*0x13d1*/ 575,
- /*0x0451*/ 327,
- /*0x04d1*/ 394,
- /*0x1042a*/ 1142,
- -1,
- /*0x0263*/ 212,
- /*0x1e51*/ 656,
- /*0x1ed1*/ 715,
- /*0x0151*/ 94,
- /*0x2cd1*/ 948,
- /*0x01e1*/ 152,
- -1, -1, -1,
- /*0x24d1*/ 827,
- /*0x0265*/ 214,
- /*0xa663*/ 1018,
- -1,
- /*0x1f63*/ 782,
- /*0x019b*/ 126,
- -1,
- /*0x0188*/ 120,
- -1,
- /*0x018c*/ 121,
- /*0x10ceb*/ 1294,
- /*0x0269*/ 217,
- /*0xa665*/ 1019,
- /*0x1f02*/ 741,
- /*0x1f65*/ 784,
- /*0x10eb*/ 507,
- -1,
- /*0xa757*/ 1063,
- -1, -1,
- /*0x01e3*/ 153,
- -1,
- /*0xa669*/ 1021,
- -1, -1, -1,
- /*0x1f12*/ 749,
- -1, -1, -1,
- /*0x01e5*/ 154,
- -1,
- /*0xa667*/ 1020,
- /*0xa7db*/ 1111,
- /*0x1f67*/ 786,
- /*0x1f06*/ 745,
- /*0x025b*/ 208,
- -1, -1, -1,
- /*0x01e9*/ 156,
- -1,
- /*0x0192*/ 122,
- /*0xa76f*/ 1075,
- /*0x10cd7*/ 1274,
- /*0x1f20*/ 753,
- /*0x019e*/ 127,
- /*0xa65b*/ 1014,
- /*0xa7d9*/ 1110,
- /*0x10d7*/ 487,
- /*0x01e7*/ 155,
- /*0x0259*/ 207,
- -1,
- /*0x13ed*/ 603,
- /*0x046d*/ 348,
- /*0x04ed*/ 408,
- /*0x006d*/ 11,
- -1,
- /*0x104ed*/ 1201,
- /*0x1e6d*/ 670,
- /*0x1eed*/ 729,
- /*0x016d*/ 108,
- /*0xa659*/ 1013,
- /*0x13ac*/ 538,
- -1, -1,
- /*0x1f10*/ 747,
- /*0x1042c*/ 1144,
- -1, -1,
- /*0x10cef*/ 1298,
- -1,
- /*0x03ed*/ 288,
- /*0xa751*/ 1060,
- /*0x13a2*/ 528,
- /*0x10ef*/ 511,
- -1,
- /*0xa65f*/ 1016,
- /*0x13d3*/ 577,
- /*0x0453*/ 329,
- /*0x04d3*/ 395,
- -1,
- /*0x03ac*/ 244,
- -1,
- /*0x1e53*/ 657,
- /*0x1ed3*/ 716,
- /*0x0153*/ 95,
- /*0x2cd3*/ 949,
- -1, -1,
- /*0x13a8*/ 534,
- -1,
- /*0x24d3*/ 829,
- -1,
- /*0x10428*/ 1140,
- /*0x01df*/ 151,
- -1,
- /*0x2c61*/ 900,
- -1, -1,
- /*0x10cd1*/ 1268,
- -1, -1, -1,
- /*0x1f26*/ 759,
- /*0x10d1*/ 481,
- /*0xa65d*/ 1015,
- -1, -1,
- /*0x13f3*/ 609,
- /*0x0473*/ 351,
- /*0x04f3*/ 411,
- /*0x0073*/ 17,
- -1,
- /*0x104f3*/ 1207,
- /*0x1e73*/ 673,
- /*0x1ef3*/ 732,
- /*0x0173*/ 111,
- /*0x2cf3*/ 960,
- -1,
- /*0x1059b*/ 1220,
- /*0x0280*/ 226,
- -1,
- /*0x10d80*/ 1318,
- /*0x01dd*/ 150,
- -1,
- /*0x026b*/ 219,
- /*0xab53*/ 1113,
- /*0x03f3*/ 291,
- -1, -1,
- /*0x2c65*/ 901,
- -1, -1, -1, -1, -1,
- /*0xa66b*/ 1022,
- -1, -1,
- /*0xa76d*/ 1074,
- /*0x0582*/ 475,
- -1, -1,
- /*0x13d5*/ 579,
- /*0x0455*/ 331,
- /*0x04d5*/ 396,
- -1, -1, -1,
- /*0x1e55*/ 658,
- /*0x1ed5*/ 717,
- /*0x0155*/ 96,
- /*0x2cd5*/ 950,
- -1,
- /*0x01eb*/ 157,
- -1,
- /*0xa7d7*/ 1109,
- /*0x24d5*/ 831,
- /*0x10598*/ 1217,
- /*0x0257*/ 206,
- /*0x1059e*/ 1223,
- -1,
- /*0x0586*/ 479,
- -1,
- /*0xa753*/ 1061,
- /*0x2c5b*/ 895,
- /*0x10ced*/ 1296,
- -1, -1,
- /*0x0561*/ 442,
- /*0xa657*/ 1012,
- /*0x10ed*/ 509,
- /*0x1f57*/ 778,
- -1, -1,
- /*0x105a0*/ 1225,
- -1, -1,
- /*0x051b*/ 431,
- -1,
- /*0x2c59*/ 893,
- -1, -1,
- /*0x050b*/ 423,
- -1,
- /*0x026f*/ 221,
- -1, -1, -1,
- /*0xa791*/ 1084,
- -1,
- /*0x10cd3*/ 1270,
- /*0x0211*/ 174,
- /*0x0563*/ 444,
- /*0x13ea*/ 600,
- /*0x2c5f*/ 899,
- /*0x10d3*/ 483,
- /*0x006a*/ 8,
- -1,
- /*0x104ea*/ 1198,
- /*0x13cd*/ 571,
- /*0x044d*/ 323,
- /*0x118db*/ 1351,
- /*0x0565*/ 446,
- /*0x1044d*/ 1177,
- /*0x1f11*/ 748,
- /*0x1e4d*/ 654,
- /*0x1ecd*/ 713,
- /*0x014d*/ 92,
- /*0x2ccd*/ 946,
- -1, -1,
- /*0xa7d1*/ 1108,
- /*0x0569*/ 450,
- /*0x01ef*/ 159,
- /*0x0251*/ 201,
- -1,
- /*0x118d9*/ 1349,
- -1,
- /*0x03cd*/ 275,
- -1, -1,
- /*0x1f00*/ 739,
- /*0x0567*/ 448,
- /*0x2c5d*/ 897,
- -1,
- /*0xa651*/ 1009,
- /*0x10f3*/ 515,
- /*0x1f51*/ 775,
- /*0xa794*/ 1086,
- /*0xa755*/ 1062,
- -1,
- /*0x118df*/ 1355,
- -1,
- /*0x105a6*/ 1230,
- /*0x13c3*/ 561,
- /*0x0443*/ 313,
- -1,
- /*0x0180*/ 117,
- /*0x10443*/ 1167,
- -1,
- /*0x1e43*/ 649,
- /*0x1ec3*/ 708,
- /*0x10d84*/ 1322,
- /*0x2cc3*/ 941,
- /*0x1f14*/ 751,
- /*0x13c1*/ 559,
- /*0x0441*/ 311,
- -1, -1,
- /*0x10441*/ 1165,
- -1,
- /*0x1e41*/ 648,
- /*0x1ec1*/ 707,
- /*0x03c3*/ 265,
- /*0x2cc1*/ 940,
- -1,
- /*0x10cd5*/ 1272,
- -1, -1, -1,
- /*0x118dd*/ 1353,
- /*0x10d5*/ 485,
- -1, -1,
- /*0x03c1*/ 264,
- /*0x13cf*/ 573,
- /*0x044f*/ 325,
- /*0x04cf*/ 393,
- -1,
- /*0x1044f*/ 1179,
- -1,
- /*0x1e4f*/ 655,
- /*0x1ecf*/ 714,
- /*0x014f*/ 93,
- /*0x2ccf*/ 947,
- /*0x13cb*/ 569,
- /*0x044b*/ 321,
- -1, -1,
- /*0x1044b*/ 1175,
- -1,
- /*0x1e4b*/ 653,
- /*0x1ecb*/ 712,
- /*0x014b*/ 91,
- /*0x2ccb*/ 945,
- -1,
- /*0xa74d*/ 1058,
- -1,
- /*0x2c57*/ 891,
- /*0x13c9*/ 567,
- /*0x0449*/ 319,
- /*0x2d16*/ 983,
- /*0xa66d*/ 1023,
- /*0x10449*/ 1173,
- /*0x03cb*/ 273,
- /*0x1e49*/ 652,
- /*0x1ec9*/ 711,
- -1,
- /*0x2cc9*/ 944,
- /*0x2d0a*/ 971,
- /*0x2d1b*/ 988,
- /*0x105ae*/ 1238,
- /*0x2d08*/ 969,
- -1,
- /*0x2d0c*/ 973,
- /*0x2d0b*/ 972,
- /*0x0253*/ 203,
- /*0x10cea*/ 1293,
- /*0x03c9*/ 271,
- -1,
- /*0x01ed*/ 158,
- /*0x13ee*/ 604,
- /*0x10ea*/ 506,
- /*0x10ccd*/ 1264,
- /*0x006e*/ 12,
- /*0x1f22*/ 755,
- /*0x104ee*/ 1202,
- /*0xa653*/ 1010,
- -1,
- /*0x1f53*/ 776,
- /*0x2cee*/ 959,
- /*0xa743*/ 1053,
- -1, -1,
- /*0x2d02*/ 963,
- /*0x118d7*/ 1347,
- -1,
- /*0x056b*/ 452,
- /*0x13f1*/ 607,
- /*0x0471*/ 350,
- /*0x04f1*/ 410,
- /*0x0071*/ 15,
- /*0xa741*/ 1052,
- /*0x104f1*/ 1205,
- /*0x1e71*/ 672,
- /*0x1ef1*/ 731,
- /*0x0171*/ 110,
- /*0x2d12*/ 979,
- -1,
- /*0x2d18*/ 985,
- -1,
- /*0x2d1e*/ 991,
- /*0x1f04*/ 743,
- -1,
- /*0x2c51*/ 885,
- -1,
- /*0x2d06*/ 967,
- /*0x01a8*/ 131,
- /*0x10cc3*/ 1254,
- /*0x0580*/ 473,
- /*0x1f73*/ 790,
- -1,
- /*0xa74f*/ 1059,
- -1,
- /*0x019a*/ 125,
- -1,
- /*0x2d20*/ 993,
- /*0x105aa*/ 1234,
- -1,
- /*0x10cc1*/ 1252,
- -1, -1,
- /*0xa74b*/ 1057,
- /*0x13b7*/ 549,
- /*0x0437*/ 301,
- /*0x04b7*/ 381,
- /*0x01f3*/ 160,
- /*0x10437*/ 1155,
- -1,
- /*0x1e37*/ 643,
- /*0x1eb7*/ 702,
- /*0x0137*/ 82,
- /*0x2cb7*/ 935,
- -1,
- /*0x00e1*/ 26,
- -1,
- /*0xa749*/ 1056,
- /*0x2d10*/ 977,
- -1,
- /*0x10ccf*/ 1266,
- -1,
- /*0x118d1*/ 1341,
- /*0x03b7*/ 254,
- /*0xa655*/ 1011,
- /*0x1e926*/ 1392,
- /*0x1f55*/ 777,
- -1,
- /*0x056f*/ 456,
- -1,
- /*0x10ccb*/ 1262,
- -1, -1, -1,
- /*0x13a5*/ 531,
- /*0x0511*/ 426,
- /*0x04a5*/ 372,
- -1, -1,
- /*0x00e3*/ 28,
- /*0x1e25*/ 634,
- /*0x1ea5*/ 693,
- /*0x0125*/ 74,
- /*0x2ca5*/ 926,
- /*0x10cc9*/ 1260,
- /*0x13f5*/ 611,
- /*0x0475*/ 352,
- /*0x04f5*/ 412,
- /*0x0075*/ 19,
- /*0x00e5*/ 30,
- /*0x104f5*/ 1209,
- /*0x1e75*/ 674,
- /*0x1ef5*/ 733,
- /*0x0175*/ 112,
- /*0x13b5*/ 547,
- /*0x0435*/ 299,
- /*0x04b5*/ 380,
- -1,
- /*0x10435*/ 1153,
- /*0x00e9*/ 34,
- /*0x1e35*/ 642,
- /*0x1eb5*/ 701,
- /*0x0135*/ 81,
- /*0x2cb5*/ 934,
- /*0x026a*/ 218,
- /*0x16e61*/ 1357,
- /*0x10cee*/ 1297,
- /*0xa7cd*/ 1107,
- -1,
- /*0x00e7*/ 32,
- /*0x024d*/ 198,
- /*0x10ee*/ 510,
- -1,
- /*0x03b5*/ 252,
- -1, -1,
- /*0x105ac*/ 1236,
- /*0x2c53*/ 887,
- /*0x13b3*/ 545,
- /*0x0433*/ 297,
- /*0x04b3*/ 379,
- /*0xa64d*/ 1007,
- /*0x10433*/ 1151,
- /*0x10cf1*/ 1300,
- /*0x1e33*/ 641,
- /*0x1eb3*/ 700,
- /*0x0133*/ 80,
- /*0x2cb3*/ 933,
- /*0x10f1*/ 513,
- /*0x16e63*/ 1359,
- -1,
- /*0xa737*/ 1047,
- -1,
- /*0x1e92e*/ 1400,
- -1, -1, -1,
- /*0x03b3*/ 250,
- /*0x1fe1*/ 806,
- /*0x16e65*/ 1361,
- /*0x0481*/ 358,
- -1,
- /*0xa7c3*/ 1104,
- /*0x105a8*/ 1232,
- /*0x1e01*/ 616,
- /*0x1e81*/ 680,
- /*0x0101*/ 56,
- /*0x2c81*/ 908,
- /*0x2c73*/ 906,
- /*0x16e69*/ 1365,
- /*0x1059a*/ 1219,
- /*0x0584*/ 477,
- /*0x2173*/ 812,
- /*0xa7c1*/ 1103,
- /*0x118d3*/ 1343,
- /*0x13a4*/ 530,
- /*0xa643*/ 1002,
- -1,
- /*0x1f43*/ 772,
- /*0x16e67*/ 1363,
- -1,
- /*0xa725*/ 1039,
- -1, -1, -1,
- /*0x056d*/ 454,
- -1,
- /*0xa641*/ 1001,
- -1,
- /*0x1f41*/ 770,
- -1,
- /*0x13ad*/ 539,
- /*0x1fe5*/ 807,
- /*0x04ad*/ 376,
- -1,
- /*0x1042d*/ 1145,
- /*0x024f*/ 199,
- /*0x1e2d*/ 638,
- /*0x1ead*/ 697,
- /*0x012d*/ 78,
- /*0x2cad*/ 930,
- /*0xa735*/ 1046,
- -1,
- /*0x2c55*/ 889,
- -1, -1,
- /*0x024b*/ 197,
- /*0xa64f*/ 1008,
- -1,
- /*0x1e92a*/ 1396,
- /*0x03ad*/ 245,
- -1, -1, -1,
- /*0x10d73*/ 1305,
- -1, -1,
- /*0xa64b*/ 1006,
- /*0x2d11*/ 978,
- -1,
- /*0x0249*/ 196,
- /*0x13a3*/ 529,
- -1,
- /*0x04a3*/ 371,
- /*0x10f5*/ 517,
- /*0xa733*/ 1045,
- -1,
- /*0x1e23*/ 633,
- /*0x1ea3*/ 692,
- /*0x0123*/ 73,
- /*0x2ca3*/ 925,
- /*0xa649*/ 1005,
- /*0x2d0e*/ 975,
- -1,
- /*0x00eb*/ 36,
- /*0x2d00*/ 961,
- /*0x13a7*/ 533,
- -1,
- /*0x04a7*/ 373,
- -1,
- /*0x118d5*/ 1345,
- /*0x0573*/ 460,
- /*0x1e27*/ 635,
- /*0x1ea7*/ 694,
- /*0x0127*/ 75,
- /*0x2ca7*/ 927,
- /*0x13bf*/ 557,
- /*0x043f*/ 309,
- /*0x04bf*/ 385,
- /*0x01c9*/ 140,
- /*0x1043f*/ 1163,
- -1,
- /*0x1e3f*/ 647,
- /*0x1ebf*/ 706,
- /*0x2c6a*/ 904,
- /*0x2cbf*/ 939,
- -1, -1,
- /*0x2d14*/ 981,
- /*0x0271*/ 222,
- /*0x2c4d*/ 881,
- -1,
- /*0x13b9*/ 551,
- /*0x0439*/ 303,
- /*0x04b9*/ 382,
- /*0x03bf*/ 262,
- /*0x10439*/ 1157,
- -1,
- /*0x1e39*/ 644,
- /*0x1eb9*/ 703,
- -1,
- /*0x2cb9*/ 936,
- /*0x1f71*/ 788,
- /*0x13b1*/ 543,
- /*0x0431*/ 295,
- /*0x04b1*/ 378,
- -1,
- /*0x10431*/ 1149,
- /*0xa72d*/ 1043,
- /*0x1e31*/ 640,
- /*0x1eb1*/ 699,
- /*0x03b9*/ 256,
- /*0x2cb1*/ 932,
- -1,
- /*0x16e6b*/ 1367,
- /*0x13c0*/ 558,
- /*0x0440*/ 310,
- /*0x1e92c*/ 1398,
- -1,
- /*0x10440*/ 1164,
- -1,
- /*0xa7b7*/ 1098,
- /*0x03b1*/ 248,
- /*0x0140*/ 86,
- /*0x00ef*/ 40,
- /*0x2c43*/ 871,
- -1,
- /*0x118cd*/ 1337,
- /*0x1e922*/ 1388,
- -1, -1,
- /*0x10d81*/ 1319,
- -1, -1,
- /*0x03c0*/ 263,
- -1,
- /*0x2c41*/ 869,
- /*0x1f37*/ 768,
- /*0xa723*/ 1038,
- -1, -1,
- /*0x13c7*/ 565,
- /*0x0447*/ 317,
- -1,
- /*0x1e928*/ 1394,
- /*0x10447*/ 1171,
- -1,
- /*0x1e47*/ 651,
- /*0x1ec7*/ 710,
- -1,
- /*0x2cc7*/ 943,
- /*0xa7a5*/ 1094,
- -1,
- /*0xa727*/ 1040,
- /*0x0225*/ 183,
- -1,
- /*0x2c4f*/ 883,
- /*0x056a*/ 451,
- -1,
- /*0x2d22*/ 995,
- /*0x03c7*/ 269,
- -1,
- /*0x118c3*/ 1327,
- /*0xa73f*/ 1051,
- -1,
- /*0x0275*/ 224,
- /*0x2c4b*/ 879,
- /*0x1f25*/ 758,
- /*0x13c2*/ 560,
- /*0x0442*/ 312,
- /*0x04c2*/ 386,
- /*0xa7b5*/ 1097,
- /*0x10442*/ 1166,
- /*0x118c1*/ 1325,
- /*0x16e6f*/ 1371,
- -1,
- /*0x0142*/ 87,
- -1,
- /*0x1f75*/ 792,
- /*0xa739*/ 1048,
- /*0x2c49*/ 877,
- -1,
- /*0x2d1a*/ 987,
- /*0x01a5*/ 130,
- /*0x048f*/ 361,
- -1,
- /*0x2d04*/ 965,
- /*0x1f35*/ 766,
- /*0x1e0f*/ 623,
- /*0x1e8f*/ 687,
- /*0x010f*/ 63,
- /*0x2c8f*/ 915,
- /*0xa69b*/ 1037,
- /*0x118cf*/ 1339,
- /*0x01f5*/ 161,
- -1,
- /*0x1059c*/ 1221,
- /*0xa68b*/ 1029,
- /*0x0233*/ 190,
- /*0xff59*/ 1138,
- /*0x13c5*/ 563,
- /*0x0445*/ 315,
- -1,
- /*0x118cb*/ 1335,
- /*0x10445*/ 1169,
- -1,
- /*0x1e45*/ 650,
- /*0x1ec5*/ 709,
- -1,
- /*0x2cc5*/ 942,
- -1,
- /*0x1f33*/ 764,
- -1, -1, -1,
- /*0xa781*/ 1079,
- -1,
- /*0x118c9*/ 1333,
- /*0x0201*/ 166,
- /*0x03c5*/ 267,
- -1,
- /*0x00ed*/ 38,
- -1,
- /*0x2171*/ 810,
- -1, -1,
- /*0x0373*/ 239,
- -1,
- /*0xa747*/ 1055,
- /*0x10cc0*/ 1251,
- /*0x13f2*/ 608,
- /*0x1f01*/ 740,
- -1,
- /*0x0072*/ 16,
- /*0x0078*/ 22,
- /*0x104f2*/ 1206,
- /*0x104f8*/ 1212,
- /*0x1fd1*/ 804,
- /*0x13bd*/ 555,
- /*0x043d*/ 307,
- /*0x04bd*/ 384,
- -1,
- /*0x1043d*/ 1161,
- -1,
- /*0x1e3d*/ 646,
- /*0x1ebd*/ 705,
- -1,
- /*0x2cbd*/ 938,
- /*0x1f24*/ 757,
- /*0x03f2*/ 290,
- /*0x03f8*/ 292,
- /*0x022d*/ 187,
- -1, -1,
- /*0x2c37*/ 859,
- /*0x10cc7*/ 1258,
- -1,
- /*0x03bd*/ 260,
- -1, -1,
- /*0x13bb*/ 553,
- /*0x043b*/ 305,
- /*0x04bb*/ 383,
- -1,
- /*0x1043b*/ 1159,
- /*0x10d71*/ 1303,
- /*0x1e3b*/ 645,
- /*0x1ebb*/ 704,
- /*0x105b7*/ 1246,
- /*0x2cbb*/ 937,
- -1,
- /*0x16e6d*/ 1369,
- -1, -1, -1,
- /*0x056e*/ 455,
- -1,
- /*0x00f3*/ 44,
- /*0xa7a3*/ 1093,
- /*0x03bb*/ 258,
- /*0x01ad*/ 132,
- /*0x0223*/ 182,
- /*0x10cc2*/ 1253,
- /*0x1e05*/ 618,
- /*0x1e85*/ 682,
- /*0x0105*/ 58,
- /*0x2c85*/ 910,
- /*0xa745*/ 1054,
- -1, -1,
- /*0x1e943*/ 1421,
- -1,
- /*0x0571*/ 458,
- /*0xa7a7*/ 1095,
- /*0x1f23*/ 756,
- -1,
- /*0x0227*/ 184,
- -1,
- /*0x105a5*/ 1229,
- /*0x2175*/ 814,
- -1,
- /*0x1e941*/ 1419,
- -1,
- /*0xa7bf*/ 1102,
- /*0x2c35*/ 857,
- -1,
- /*0x023f*/ 192,
- -1,
- /*0xff57*/ 1136,
- /*0x1f27*/ 760,
- /*0x01a3*/ 129,
- /*0x0479*/ 354,
- /*0x04f9*/ 414,
- /*0x0079*/ 23,
- /*0x10cc5*/ 1256,
- /*0x104f9*/ 1213,
- /*0x1e79*/ 676,
- /*0x1ef9*/ 735,
- /*0x105b5*/ 1244,
- /*0xa7b9*/ 1099,
- /*0x1d79*/ 613,
- -1, -1, -1, -1,
- /*0xa73d*/ 1050,
- -1,
- /*0x16e73*/ 1375,
- /*0x2c33*/ 855,
- -1,
- /*0x0076*/ 20,
- -1,
- /*0x104f6*/ 1210,
- /*0x0231*/ 189,
- -1,
- /*0x01bf*/ 138,
- -1, -1, -1, -1, -1,
- /*0x10d75*/ 1307,
- /*0x105b3*/ 1242,
- -1,
- /*0x10cf2*/ 1301,
- /*0x0240*/ 193,
- /*0x1f31*/ 762,
- /*0xa73b*/ 1049,
- -1,
- /*0x10f2*/ 514,
- /*0x10f8*/ 520,
- /*0x01b9*/ 136,
- -1, -1, -1, -1, -1,
- /*0x0525*/ 436,
- /*0x1f40*/ 769,
- /*0x0581*/ 474,
- /*0x047d*/ 356,
- /*0x04fd*/ 416,
- -1,
- /*0x00ea*/ 35,
- /*0xff51*/ 1130,
- /*0x1e7d*/ 678,
- /*0x1efd*/ 737,
- -1,
- /*0x0575*/ 462,
- /*0x1d7d*/ 614,
- -1,
- /*0x0247*/ 195,
- -1, -1, -1, -1, -1, -1,
- /*0x2d1c*/ 989,
- /*0x105a4*/ 1228,
- -1,
- /*0x13af*/ 541,
- /*0xa647*/ 1004,
- /*0x04af*/ 377,
- -1,
- /*0x1042f*/ 1147,
- -1,
- /*0x1e2f*/ 639,
- /*0x1eaf*/ 698,
- /*0x012f*/ 79,
- /*0x2caf*/ 931,
- -1,
- /*0x007a*/ 24,
- -1,
- /*0x104fa*/ 1214,
- /*0x105ad*/ 1237,
- -1,
- /*0x017a*/ 114,
- /*0x0242*/ 194,
- /*0x13a9*/ 535,
- /*0x03af*/ 247,
- /*0x04a9*/ 374,
- -1,
- /*0x10429*/ 1141,
- -1,
- /*0x1e29*/ 636,
- /*0x1ea9*/ 695,
- /*0x0129*/ 76,
- /*0x2ca9*/ 928,
- /*0xa691*/ 1032,
- -1,
- /*0x1f42*/ 771,
- /*0x020f*/ 173,
- /*0x16e6a*/ 1366,
- /*0x1e03*/ 617,
- /*0x1e83*/ 681,
- /*0x0103*/ 57,
- /*0x2c83*/ 909,
- -1,
- /*0x1e937*/ 1409,
- /*0x10d85*/ 1323,
- /*0x0501*/ 418,
- -1, -1, -1,
- /*0x105a3*/ 1227,
- /*0x047b*/ 355,
- /*0x04fb*/ 415,
- -1,
- /*0x10f9*/ 521,
- /*0x104fb*/ 1215,
- /*0x1e7b*/ 677,
- /*0x1efb*/ 736,
- -1, -1, -1,
- /*0x2c3f*/ 867,
- -1, -1, -1,
- /*0x105a7*/ 1231,
- /*0xa645*/ 1003,
- -1,
- /*0x1f45*/ 774,
- /*0x03fb*/ 293,
- /*0x13e6*/ 596,
- /*0x10f6*/ 518,
- /*0x0371*/ 238,
- /*0x0066*/ 5,
- /*0x1e925*/ 1391,
- /*0x104e6*/ 1194,
- /*0x0499*/ 366,
- /*0x2c39*/ 861,
- -1,
- /*0x052d*/ 440,
- /*0x1e19*/ 628,
- /*0xff53*/ 1132,
- /*0x0119*/ 68,
- /*0x2c99*/ 920,
- /*0x24e6*/ 848,
- /*0x0272*/ 223,
- -1, -1,
- /*0x2c31*/ 853,
- -1,
- /*0xa7bd*/ 1101,
- /*0x105b9*/ 1248,
- -1,
- /*0xa72f*/ 1044,
- /*0x1e935*/ 1407,
- -1, -1, -1,
- /*0x1f72*/ 789,
- /*0x1f78*/ 795,
- /*0x2c40*/ 868,
- /*0xa77a*/ 1076,
- /*0x105b1*/ 1241,
- /*0x10fd*/ 523,
- -1,
- /*0x2d25*/ 998,
- /*0x00ee*/ 39,
- -1, -1,
- /*0x0523*/ 435,
- -1,
- /*0xa729*/ 1041,
- /*0xa7bb*/ 1100,
- -1,
- /*0x13f0*/ 606,
- -1, -1,
- /*0x0070*/ 14,
- /*0x1e933*/ 1405,
- /*0x104f0*/ 1204,
- -1,
- /*0x017c*/ 115,
- /*0x01bd*/ 137,
- /*0x00f1*/ 42,
- /*0x0527*/ 437,
- -1,
- /*0x2c47*/ 875,
- -1, -1,
- /*0xa785*/ 1081,
- -1, -1,
- /*0x0205*/ 168,
- /*0x10fa*/ 522,
- /*0x0477*/ 353,
- /*0x04f7*/ 413,
- /*0x0077*/ 21,
- /*0x118c0*/ 1324,
- /*0x104f7*/ 1211,
- /*0x1e77*/ 675,
- /*0x1ef7*/ 734,
- /*0x0177*/ 113,
- /*0x13ab*/ 537,
- -1,
- /*0x04ab*/ 375,
- /*0x1f05*/ 744,
- /*0x1042b*/ 1143,
- /*0xff55*/ 1134,
- /*0x1e2b*/ 637,
- /*0x1eab*/ 696,
- /*0x012b*/ 77,
- /*0x2cab*/ 929,
- -1,
- /*0x2c42*/ 870,
- -1,
- /*0x1e924*/ 1390,
- /*0x16e6e*/ 1370,
- -1, -1, -1, -1,
- /*0x0185*/ 119,
- -1,
- /*0x118c7*/ 1331,
- /*0x13ce*/ 572,
- /*0x044e*/ 324,
- /*0x04ce*/ 392,
- -1,
- /*0x1044e*/ 1178,
- /*0x2d01*/ 962,
- -1,
- /*0x1e92d*/ 1399,
- -1,
- /*0x16e71*/ 1373,
- /*0x0283*/ 228,
- -1,
- /*0x10d83*/ 1321,
- -1,
- /*0x1f79*/ 796,
- /*0xa7f6*/ 1112,
- -1, -1, -1,
- /*0x03ce*/ 276,
- /*0x10ce6*/ 1289,
- /*0x2c45*/ 873,
- /*0x2d24*/ 997,
- -1,
- /*0x13ec*/ 602,
- /*0x10e6*/ 502,
- /*0x118c2*/ 1326,
- /*0x006c*/ 10,
- -1,
- /*0x104ec*/ 1200,
- /*0x01f9*/ 162,
- /*0x1f76*/ 793,
- -1,
- /*0x2cec*/ 958,
- -1,
- /*0x00f5*/ 46,
- /*0xa77c*/ 1077,
- /*0x1e923*/ 1389,
- /*0x2d2d*/ 1000,
- -1,
- /*0xff4d*/ 1126,
- /*0x047f*/ 357,
- /*0x04ff*/ 417,
- -1, -1, -1,
- /*0x1e7f*/ 679,
- /*0x1eff*/ 738,
- /*0x13f4*/ 610,
- -1,
- /*0x027d*/ 225,
- /*0x0074*/ 18,
- /*0x1e927*/ 1393,
- /*0x104f4*/ 1208,
- -1,
- /*0x2172*/ 811,
- /*0x2178*/ 817,
- -1,
- /*0x118c5*/ 1329,
- /*0x2c3d*/ 865,
- -1, -1,
- /*0x1e93f*/ 1417,
- /*0x1f7d*/ 800,
- /*0x10cf0*/ 1299,
- /*0xa72b*/ 1042,
- /*0x13d0*/ 574,
- /*0x0450*/ 326,
- /*0x2d23*/ 996,
- /*0x10f0*/ 512,
- -1, -1,
- /*0x022f*/ 188,
- -1, -1,
- /*0xff43*/ 1116,
- /*0x050f*/ 425,
- -1,
- /*0x1e939*/ 1411,
- /*0x01fd*/ 164,
- /*0x24d0*/ 826,
- /*0x2c3b*/ 863,
- -1,
- /*0x2d27*/ 999,
- -1,
- /*0x16e75*/ 1377,
- /*0xff41*/ 1114,
- /*0xa7a9*/ 1096,
- /*0x10f7*/ 519,
- /*0x1e931*/ 1403,
- /*0x0229*/ 185,
- -1, -1,
- /*0x1f7a*/ 797,
- -1,
- /*0x105bb*/ 1249,
- /*0xa783*/ 1080,
- /*0x10d72*/ 1304,
- /*0x10d78*/ 1310,
- /*0x0203*/ 167,
- -1,
- /*0x1e940*/ 1418,
- /*0x2184*/ 825,
- -1, -1, -1,
- /*0xff4f*/ 1128,
- -1, -1,
- /*0x0585*/ 478,
- -1,
- /*0x13a1*/ 527,
- /*0x1f03*/ 742,
- /*0x04a1*/ 370,
- /*0x10cce*/ 1265,
- -1,
- /*0xff4b*/ 1124,
- /*0x1e21*/ 632,
- /*0x1ea1*/ 691,
- /*0x0121*/ 72,
- /*0x2ca1*/ 924,
- -1, -1, -1,
- /*0x0572*/ 459,
- /*0x0578*/ 465,
- -1,
- /*0xa77f*/ 1078,
- /*0x0183*/ 118,
- /*0x1f7b*/ 798,
- /*0xff49*/ 1122,
- -1, -1, -1, -1,
- /*0x2179*/ 818,
- /*0x0266*/ 215,
- /*0xa799*/ 1088,
- /*0x10cec*/ 1295,
- -1,
- /*0x0219*/ 178,
- /*0x13e8*/ 598,
- -1,
- /*0x10ec*/ 508,
- /*0x0068*/ 7,
- /*0x01fb*/ 163,
- /*0x104e8*/ 1196,
- -1,
- /*0x2c76*/ 907,
- /*0x1f66*/ 785,
- -1, -1,
- /*0x2176*/ 815,
- -1,
- /*0x1e942*/ 1420,
- /*0x24e8*/ 850,
- -1, -1,
- /*0x13e4*/ 594,
- /*0x10ff*/ 525,
- -1,
- /*0x0064*/ 3,
- -1,
- /*0x104e4*/ 1192,
- -1, -1, -1,
- /*0x10f4*/ 516,
- -1,
- /*0x0199*/ 124,
- -1,
- /*0x0505*/ 420,
- /*0x24e4*/ 846,
- -1, -1, -1,
- /*0x13e2*/ 592,
- /*0x10d79*/ 1311,
- -1,
- /*0x0062*/ 1,
- /*0x10cd0*/ 1267,
- /*0x104e2*/ 1190,
- -1, -1,
- /*0x217d*/ 822,
- /*0x10d0*/ 480,
- -1,
- /*0x13c8*/ 566,
- /*0x0448*/ 318,
- /*0x04c8*/ 389,
- /*0x24e2*/ 844,
- /*0x10448*/ 1172,
- /*0x1f7c*/ 799,
- /*0x1f70*/ 787,
- /*0x10d76*/ 1308,
- /*0x0148*/ 90,
- /*0x0495*/ 364,
- -1, -1,
- /*0x2d0f*/ 976,
- /*0x1e15*/ 626,
- /*0x1e95*/ 690,
- /*0x0115*/ 66,
- /*0x2c95*/ 918,
- /*0x0579*/ 466,
- -1,
- /*0x03c8*/ 270,
- -1,
- /*0x022b*/ 186,
- /*0x13c6*/ 564,
- /*0x0446*/ 316,
- /*0x04c6*/ 388,
- /*0x1f77*/ 794,
- /*0x10446*/ 1170,
- /*0x217a*/ 819,
- /*0x13e0*/ 590,
- /*0x105af*/ 1239,
- /*0x0146*/ 89,
- /*0x13de*/ 588,
- /*0x045e*/ 340,
- /*0x104e0*/ 1188,
- /*0x0576*/ 463,
- -1,
- /*0x104de*/ 1186,
- /*0x1e93d*/ 1415,
- -1,
- /*0x10d7d*/ 1315,
- -1,
- /*0x03c6*/ 268,
- /*0x24e0*/ 842,
- -1,
- /*0x017e*/ 116,
- /*0x24de*/ 840,
- -1,
- /*0x105a9*/ 1233,
- -1, -1,
- /*0x13b0*/ 542,
- /*0x0430*/ 294,
- -1,
- /*0x0583*/ 476,
- /*0x10430*/ 1148,
- -1,
- /*0x13c4*/ 562,
- /*0x0444*/ 314,
- /*0x04c4*/ 387,
- /*0x1e93b*/ 1413,
- /*0x10444*/ 1168,
- -1, -1,
- /*0x217b*/ 820,
- /*0x0144*/ 88,
- -1,
- /*0x057d*/ 470,
- /*0x026c*/ 220,
- /*0x10ce8*/ 1291,
- /*0x10d7a*/ 1312,
- /*0x13bc*/ 554,
- /*0x043c*/ 306,
- /*0x01ce*/ 142,
- /*0x10e8*/ 504,
- /*0x1043c*/ 1160,
- /*0x03c4*/ 266,
- /*0x0493*/ 363,
- -1,
- /*0x013c*/ 84,
- /*0x2c66*/ 902,
- /*0x1e13*/ 625,
- /*0x1e93*/ 689,
- /*0x0113*/ 65,
- /*0x2c93*/ 917,
- -1,
- /*0x10ce4*/ 1287,
- -1, -1,
- /*0x052f*/ 441,
- /*0x03bc*/ 259,
- /*0x10e4*/ 500,
- /*0x1e07*/ 619,
- /*0x1e87*/ 683,
- /*0x0107*/ 59,
- /*0x2c87*/ 911,
- -1,
- /*0x057a*/ 467,
- /*0x10599*/ 1218,
- -1,
- /*0x1fb1*/ 802,
- -1, -1, -1,
- /*0x10ce2*/ 1285,
- /*0x1f74*/ 791,
- /*0x10d7b*/ 1313,
- /*0x0529*/ 438,
- /*0x2d05*/ 966,
- /*0x10e2*/ 498,
- /*0x0250*/ 200,
- -1, -1,
- /*0x01ff*/ 165,
- -1,
- /*0x10cc8*/ 1259,
- /*0x0503*/ 419,
- -1,
- /*0x13dc*/ 586,
- /*0x045c*/ 338,
- -1, -1, -1,
- /*0x104dc*/ 1184,
- -1, -1, -1,
- /*0x217c*/ 821,
- /*0x2170*/ 809,
- -1, -1, -1,
- /*0x24dc*/ 838,
- /*0x057b*/ 468,
- -1,
- /*0x13da*/ 584,
- /*0x045a*/ 336,
- /*0x10cc6*/ 1257,
- -1,
- /*0x01d0*/ 143,
- /*0x104da*/ 1182,
- -1, -1,
- /*0x10ce0*/ 1283,
- /*0x00f2*/ 43,
- /*0x00f8*/ 48,
- /*0x10cde*/ 1281,
- /*0x2177*/ 816,
- /*0x10e0*/ 496,
- /*0x24da*/ 836,
- -1,
- /*0x10de*/ 494,
- /*0xa7a1*/ 1092,
- /*0x0566*/ 447,
- /*0x0497*/ 365,
- -1,
- /*0x10fe*/ 524,
- /*0x0519*/ 430,
- /*0x1e17*/ 627,
- -1,
- /*0x0117*/ 67,
- /*0x2c97*/ 919,
- /*0x13d8*/ 582,
- /*0x0458*/ 334,
- -1, -1,
- /*0x105ab*/ 1235,
- /*0x104d8*/ 1180,
- /*0x1f21*/ 754,
- /*0x10d7c*/ 1314,
- /*0x10d70*/ 1302,
- /*0x10cc4*/ 1255,
- -1, -1,
- /*0x2c4e*/ 882,
- -1,
- /*0x24d8*/ 834,
- -1,
- /*0x214e*/ 808,
- -1,
- /*0xa681*/ 1024,
- /*0x1e92f*/ 1401,
- -1, -1,
- /*0x01a1*/ 128,
- /*0x0268*/ 216,
- -1, -1, -1,
- /*0x10d77*/ 1309,
- -1, -1,
- /*0x13d6*/ 580,
- /*0x0456*/ 332,
- /*0x16e72*/ 1374,
- /*0x16e78*/ 1380,
- /*0x057c*/ 469,
- /*0x0570*/ 457,
- /*0x2c6c*/ 905,
- /*0x1e929*/ 1395,
- /*0x13d4*/ 578,
- /*0x0454*/ 330,
- /*0x0264*/ 213,
- -1, -1, -1,
- /*0x24d6*/ 832,
- /*0x13d2*/ 576,
- /*0x0452*/ 328,
- -1, -1,
- /*0x118ce*/ 1338,
- -1, -1,
- /*0x24d4*/ 830,
- /*0x1f64*/ 783,
- /*0x0577*/ 464,
- -1,
- /*0x217f*/ 824,
- -1, -1,
- /*0x24d2*/ 828,
- /*0x037d*/ 243,
- -1,
- /*0x00f9*/ 49,
- /*0x052b*/ 439,
- /*0x2174*/ 813,
- /*0x0287*/ 229,
- /*0xa7c8*/ 1105,
- -1, -1, -1,
- /*0x10cdc*/ 1279,
- /*0x1f62*/ 781,
- -1, -1, -1,
- /*0x10dc*/ 492,
- /*0x0215*/ 176,
- /*0x2d03*/ 964,
- /*0x2c50*/ 884,
- /*0x00f6*/ 47,
- -1,
- /*0x13cc*/ 570,
- /*0x044c*/ 322,
- /*0x04cc*/ 391,
- /*0x049d*/ 368,
- /*0x1044c*/ 1176,
- -1,
- /*0x10cda*/ 1277,
- /*0x1e1d*/ 630,
- /*0x1f15*/ 752,
- /*0x011d*/ 70,
- /*0x2c9d*/ 922,
- /*0x10da*/ 490,
- /*0x1e09*/ 620,
- /*0x1e89*/ 684,
- /*0x0109*/ 60,
- /*0x2c89*/ 912,
- /*0x0260*/ 210,
- /*0x10d7f*/ 1317,
- -1,
- /*0x03cc*/ 274,
- -1, -1,
- /*0xff47*/ 1120,
- -1,
- /*0x0195*/ 123,
- /*0x10d74*/ 1306,
- -1, -1,
- /*0x056c*/ 453,
- /*0x1f60*/ 779,
- /*0x00fd*/ 53,
- /*0x16e79*/ 1381,
- -1,
- /*0x10cd8*/ 1275,
- /*0x118d0*/ 1340,
- -1, -1,
- /*0x2d19*/ 986,
- /*0x10d8*/ 488,
- /*0x01c6*/ 139,
- -1, -1,
- /*0x13b6*/ 548,
- /*0x0436*/ 300,
- /*0x057f*/ 472,
- /*0x037b*/ 241,
- /*0x10436*/ 1154,
- -1,
- /*0x16e76*/ 1378,
- /*0xff42*/ 1115,
- -1,
- /*0x1f30*/ 761,
- /*0x0574*/ 461,
- -1, -1, -1,
- /*0x105a1*/ 1226,
- /*0x1f44*/ 773,
- /*0x023c*/ 191,
- /*0xa793*/ 1085,
- /*0x00fa*/ 50,
- /*0x03b6*/ 253,
- /*0x0213*/ 175,
- /*0x10cd6*/ 1273,
- -1, -1, -1,
- /*0x01b0*/ 133,
- /*0x10d6*/ 486,
- -1,
- /*0xa787*/ 1082,
- /*0x10cd4*/ 1271,
- /*0x2c68*/ 903,
- /*0x0207*/ 169,
- /*0x1e92b*/ 1397,
- /*0x1f13*/ 750,
- /*0x10d4*/ 484,
- -1,
- /*0x10cd2*/ 1269,
- -1,
- /*0x16e7d*/ 1385,
- /*0xff45*/ 1118,
- -1,
- /*0x10d2*/ 482,
- -1, -1,
- /*0x1f07*/ 746,
- /*0x13ca*/ 568,
- /*0x044a*/ 320,
- /*0x04ca*/ 390,
- -1,
- /*0x1044a*/ 1174,
- -1,
- /*0x13b4*/ 546,
- /*0x0434*/ 298,
- /*0x048d*/ 360,
- /*0x00fb*/ 51,
- /*0x10434*/ 1152,
- -1,
- /*0x1e0d*/ 622,
- /*0x1e8d*/ 686,
- /*0x010d*/ 62,
- /*0x2c8d*/ 914,
- /*0x13be*/ 556,
- /*0x043e*/ 308,
- /*0x025c*/ 209,
- /*0x03ca*/ 272,
- /*0x1043e*/ 1162,
- /*0x037c*/ 242,
- -1,
- /*0x16e7a*/ 1382,
- /*0x013e*/ 85,
- /*0x03b4*/ 251,
- /*0x049f*/ 369,
- /*0x10ccc*/ 1263,
- /*0x0521*/ 434,
- /*0x00e6*/ 31,
- /*0x1e1f*/ 631,
- /*0x2c48*/ 876,
- /*0x011f*/ 71,
- /*0x2c9f*/ 923,
- -1,
- /*0x03be*/ 261,
- -1, -1, -1, -1, -1,
- /*0x0377*/ 240,
- /*0x13ba*/ 552,
- /*0x043a*/ 304,
- /*0xa68f*/ 1031,
- -1,
- /*0x1043a*/ 1158,
- /*0x01dc*/ 149,
- -1,
- /*0xa797*/ 1087,
- /*0x013a*/ 83,
- -1,
- /*0x0217*/ 177,
- /*0x2c46*/ 874,
- -1,
- /*0x029d*/ 236,
- -1, -1,
- /*0x0568*/ 449,
- /*0x16e7b*/ 1383,
- /*0x0289*/ 231,
- /*0x03ba*/ 257,
- /*0x2c5e*/ 898,
- -1,
- /*0x01da*/ 148,
- -1,
- /*0x13b8*/ 550,
- /*0x0438*/ 302,
- /*0x118c8*/ 1332,
- -1,
- /*0x10438*/ 1156,
- /*0x217e*/ 823,
- /*0x00fc*/ 52,
- /*0x00f0*/ 41,
- -1,
- /*0x0564*/ 445,
- -1, -1, -1,
- /*0x16e66*/ 1362,
- -1,
- /*0x2c30*/ 852,
- -1, -1, -1,
- /*0x03b8*/ 255,
- -1,
- /*0x2c44*/ 872,
- -1, -1,
- /*0x118c6*/ 1330,
- /*0x01d8*/ 147,
- /*0x0256*/ 205,
- /*0x0562*/ 443,
- -1,
- /*0x105b0*/ 1240,
- -1, -1, -1,
- /*0x118de*/ 1354,
- /*0x0254*/ 204,
- /*0x2c3c*/ 864,
- -1, -1, -1, -1, -1,
- /*0x0252*/ 202,
- /*0x13b2*/ 544,
- /*0x0432*/ 296,
- -1,
- /*0x0515*/ 428,
- /*0x10432*/ 1150,
- /*0x10d7e*/ 1316,
- /*0x10cca*/ 1261,
- /*0x105bc*/ 1250,
- -1, -1, -1, -1, -1,
- /*0x01d6*/ 146,
- /*0x16e7c*/ 1384,
- /*0x16e70*/ 1372,
- /*0x118c4*/ 1328,
- -1, -1,
- /*0x03b2*/ 249,
- -1,
- /*0x01d4*/ 145,
- -1, -1, -1, -1, -1, -1,
- /*0x01d2*/ 144,
- -1, -1,
- /*0xa685*/ 1026,
- /*0x057e*/ 471,
- /*0xa79d*/ 1090,
- /*0x16e77*/ 1379,
- -1,
- /*0x021d*/ 180,
- -1, -1,
- /*0x00ec*/ 37,
- /*0x2c5c*/ 896,
- /*0x0209*/ 170,
- -1,
- /*0x2d21*/ 994,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1,
- /*0x00ff*/ 55,
- -1,
- /*0x2c5a*/ 894,
- -1, -1, -1, -1, -1,
- /*0x00f4*/ 45,
- /*0x01cc*/ 141,
- -1, -1, -1, -1, -1,
- /*0x0513*/ 427,
- -1, -1, -1, -1, -1, -1,
- /*0x118dc*/ 1352,
- -1, -1, -1,
- /*0x0507*/ 421,
- -1, -1,
- /*0x2c58*/ 892,
- -1, -1, -1,
- /*0x10597*/ 1216,
- /*0x16e6c*/ 1368,
- /*0x1f36*/ 767,
- -1, -1, -1,
- /*0x118da*/ 1350,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1,
- /*0x16e7f*/ 1387,
- /*0x01b6*/ 135,
- -1, -1, -1, -1, -1, -1,
- /*0x16e74*/ 1376,
- /*0x2c56*/ 890,
- -1, -1, -1, -1,
- /*0xa7ca*/ 1106,
- -1,
- /*0x118d8*/ 1348,
- /*0x2c54*/ 888,
- -1, -1, -1,
- /*0x2d15*/ 982,
- -1,
- /*0x020d*/ 172,
- /*0x2c52*/ 886,
- -1, -1, -1, -1, -1, -1,
- -1, -1,
- /*0x1e930*/ 1402,
- -1, -1,
- /*0x1f34*/ 765,
- -1,
- /*0xa79f*/ 1091,
- -1, -1,
- /*0x021f*/ 181,
- /*0x0517*/ 429,
- -1, -1, -1,
- /*0x118d6*/ 1346,
- -1, -1, -1, -1,
- /*0x00e8*/ 33,
- /*0x01b4*/ 134,
- /*0x1e93c*/ 1414,
- /*0x118d4*/ 1344,
- -1, -1,
- /*0xa683*/ 1025,
- -1,
- /*0x1fd0*/ 803,
- /*0x2c4c*/ 880,
- /*0x118d2*/ 1342,
- -1, -1, -1, -1, -1, -1,
- /*0x00e4*/ 29,
- -1, -1, -1, -1, -1, -1,
- /*0x1059d*/ 1222,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1,
- /*0x00e2*/ 27,
- -1,
- /*0x2d13*/ 980,
- -1, -1, -1, -1, -1, -1,
- -1, -1,
- /*0x118cc*/ 1336,
- /*0xa699*/ 1036,
- /*0x2d07*/ 968,
- -1,
- /*0x16e68*/ 1364,
- /*0x2c36*/ 858,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1,
- /*0x105b6*/ 1245,
- -1,
- /*0x16e64*/ 1360,
- -1,
- /*0xff4e*/ 1127,
- -1, -1, -1, -1,
- /*0x00e0*/ 25,
- -1, -1, -1, -1, -1, -1,
- -1,
- /*0x00fe*/ 54,
- /*0x051d*/ 432,
- -1,
- /*0x16e62*/ 1358,
- -1,
- /*0x1f32*/ 763,
- /*0x0509*/ 422,
- -1, -1, -1, -1, -1, -1,
- -1,
- /*0x2c4a*/ 878,
- -1, -1, -1, -1, -1,
- /*0x2c34*/ 856,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1,
- /*0x2c3e*/ 866,
- -1,
- /*0x2d17*/ 984,
- -1,
- /*0x105b4*/ 1243,
- -1, -1, -1, -1, -1, -1,
- -1,
- /*0x16e60*/ 1356,
- -1, -1, -1, -1, -1, -1,
- -1,
- /*0x16e7e*/ 1386,
- /*0x118ca*/ 1334,
- /*0x1059f*/ 1224,
- /*0xff50*/ 1129,
- -1, -1,
- /*0x2c3a*/ 862,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- /*0x1fe0*/ 805,
- -1, -1, -1, -1,
- /*0x2c38*/ 860,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- /*0x050d*/ 424,
- /*0x105b8*/ 1247,
- -1, -1,
- /*0x1fb0*/ 801,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1,
- /*0x051f*/ 433,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1,
- /*0x2c32*/ 854,
- -1,
- /*0x2d1d*/ 990,
- -1, -1, -1, -1,
- /*0x2d09*/ 970,
- -1, -1, -1, -1,
- /*0x1e936*/ 1408,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1,
- /*0xff48*/ 1121,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1,
- /*0x1e934*/ 1406,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1,
- /*0x1e93e*/ 1416,
- /*0xff46*/ 1119,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1,
- /*0x2d0d*/ 974,
- -1, -1, -1, -1,
- /*0x1e93a*/ 1412,
- -1, -1, -1, -1, -1, -1,
- -1, -1,
- /*0xff44*/ 1117,
- -1, -1, -1,
- /*0x2d1f*/ 992,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1,
- /*0x1e938*/ 1410,
- -1, -1, -1,
- /*0xa695*/ 1034,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1,
- /*0x1e932*/ 1404,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1,
- /*0xff5a*/ 1139,
- -1, -1, -1, -1, -1, -1,
- -1,
- /*0xa693*/ 1033,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1,
- /*0xa687*/ 1027,
- -1, -1, -1, -1, -1, -1,
- -1,
- /*0xff58*/ 1137,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1,
- /*0xff56*/ 1135,
- -1, -1, -1, -1, -1, -1,
- -1,
- /*0xff54*/ 1133,
- -1, -1, -1, -1, -1, -1,
- /*0xff52*/ 1131,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- /*0xa697*/ 1035,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1,
- /*0xff4c*/ 1125,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1,
- /*0xa689*/ 1028,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- /*0xff4a*/ 1123,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1,
- /*0xa68d*/ 1030
- };
-
- if (code <= MAX_CODE_VALUE && code >= MIN_CODE_VALUE)
- {
- register unsigned int key = onigenc_unicode_CaseUnfold_11_hash(code);
-
- if (key <= MAX_HASH_VALUE)
- {
- register short s = wordlist[key];
-
- if (s >= 0 && code1_equal(code, CaseUnfold_11_Table[s].from))
- return &CaseUnfold_11_Table[s].to;
- }
- }
- return 0;
-}
-
-static const CaseUnfold_12_Type CaseUnfold_12_Table[] = {
-#define CaseUnfold_12 (*(CaseUnfold_12_Type (*)[58])(CaseUnfold_12_Table+0))
- {{0x0061, 0x02be}, {1, {0x1e9a}}},
- {{0x0066, 0x0066}, {1, {0xfb00}}},
- {{0x0066, 0x0069}, {1, {0xfb01}}},
- {{0x0066, 0x006c}, {1, {0xfb02}}},
- {{0x0068, 0x0331}, {1, {0x1e96}}},
- {{0x006a, 0x030c}, {1, {0x01f0}}},
- {{0x0073, 0x0073}, {2, {0x00df, 0x1e9e}}},
- {{0x0073, 0x0074}, {2, {0xfb05, 0xfb06}}},
- {{0x0074, 0x0308}, {1, {0x1e97}}},
- {{0x0077, 0x030a}, {1, {0x1e98}}},
- {{0x0079, 0x030a}, {1, {0x1e99}}},
- {{0x02bc, 0x006e}, {1, {0x0149}}},
- {{0x03ac, 0x03b9}, {1, {0x1fb4}}},
- {{0x03ae, 0x03b9}, {1, {0x1fc4}}},
- {{0x03b1, 0x0342}, {1, {0x1fb6}}},
- {{0x03b1, 0x03b9}, {2, {0x1fb3, 0x1fbc}}},
- {{0x03b7, 0x0342}, {1, {0x1fc6}}},
- {{0x03b7, 0x03b9}, {2, {0x1fc3, 0x1fcc}}},
- {{0x03b9, 0x0342}, {1, {0x1fd6}}},
- {{0x03c1, 0x0313}, {1, {0x1fe4}}},
- {{0x03c5, 0x0313}, {1, {0x1f50}}},
- {{0x03c5, 0x0342}, {1, {0x1fe6}}},
- {{0x03c9, 0x0342}, {1, {0x1ff6}}},
- {{0x03c9, 0x03b9}, {2, {0x1ff3, 0x1ffc}}},
- {{0x03ce, 0x03b9}, {1, {0x1ff4}}},
- {{0x0565, 0x0582}, {1, {0x0587}}},
- {{0x0574, 0x0565}, {1, {0xfb14}}},
- {{0x0574, 0x056b}, {1, {0xfb15}}},
- {{0x0574, 0x056d}, {1, {0xfb17}}},
- {{0x0574, 0x0576}, {1, {0xfb13}}},
- {{0x057e, 0x0576}, {1, {0xfb16}}},
- {{0x1f00, 0x03b9}, {2, {0x1f80, 0x1f88}}},
- {{0x1f01, 0x03b9}, {2, {0x1f81, 0x1f89}}},
- {{0x1f02, 0x03b9}, {2, {0x1f82, 0x1f8a}}},
- {{0x1f03, 0x03b9}, {2, {0x1f83, 0x1f8b}}},
- {{0x1f04, 0x03b9}, {2, {0x1f84, 0x1f8c}}},
- {{0x1f05, 0x03b9}, {2, {0x1f85, 0x1f8d}}},
- {{0x1f06, 0x03b9}, {2, {0x1f86, 0x1f8e}}},
- {{0x1f07, 0x03b9}, {2, {0x1f87, 0x1f8f}}},
- {{0x1f20, 0x03b9}, {2, {0x1f90, 0x1f98}}},
- {{0x1f21, 0x03b9}, {2, {0x1f91, 0x1f99}}},
- {{0x1f22, 0x03b9}, {2, {0x1f92, 0x1f9a}}},
- {{0x1f23, 0x03b9}, {2, {0x1f93, 0x1f9b}}},
- {{0x1f24, 0x03b9}, {2, {0x1f94, 0x1f9c}}},
- {{0x1f25, 0x03b9}, {2, {0x1f95, 0x1f9d}}},
- {{0x1f26, 0x03b9}, {2, {0x1f96, 0x1f9e}}},
- {{0x1f27, 0x03b9}, {2, {0x1f97, 0x1f9f}}},
- {{0x1f60, 0x03b9}, {2, {0x1fa0, 0x1fa8}}},
- {{0x1f61, 0x03b9}, {2, {0x1fa1, 0x1fa9}}},
- {{0x1f62, 0x03b9}, {2, {0x1fa2, 0x1faa}}},
- {{0x1f63, 0x03b9}, {2, {0x1fa3, 0x1fab}}},
- {{0x1f64, 0x03b9}, {2, {0x1fa4, 0x1fac}}},
- {{0x1f65, 0x03b9}, {2, {0x1fa5, 0x1fad}}},
- {{0x1f66, 0x03b9}, {2, {0x1fa6, 0x1fae}}},
- {{0x1f67, 0x03b9}, {2, {0x1fa7, 0x1faf}}},
- {{0x1f70, 0x03b9}, {1, {0x1fb2}}},
- {{0x1f74, 0x03b9}, {1, {0x1fc2}}},
- {{0x1f7c, 0x03b9}, {1, {0x1ff2}}},
-#define CaseUnfold_12_Locale (*(CaseUnfold_12_Type (*)[1])(CaseUnfold_12_Table+58))
- {{0x0069, 0x0307}, {1, {0x0130}}},
-};
-
-/* ANSI-C code produced by gperf version 3.1 */
-/* Command-line: gperf -7 -k1,2,3,4,5,6 -F,-1 -c -j1 -i1 -t -T -E -C -H onigenc_unicode_CaseUnfold_12_hash -N onigenc_unicode_CaseUnfold_12_lookup -n */
-
-/* maximum key range = 71, duplicates = 0 */
-
-#ifdef __GNUC__
-__inline
-#else
-#ifdef __cplusplus
-inline
-#endif
-#endif
-/*ARGSUSED*/
-static unsigned int
-onigenc_unicode_CaseUnfold_12_hash(const OnigCodePoint *codes)
-{
- static const unsigned char asso_values[] =
- {
- 3, 58, 54, 57, 56, 16, 8, 2, 43, 82,
- 3, 1, 23, 82, 82, 82, 82, 82, 82, 4,
- 82, 82, 82, 82, 82, 82, 82, 82, 82, 82,
- 82, 82, 52, 51, 50, 49, 48, 47, 46, 45,
- 82, 82, 82, 82, 43, 82, 42, 82, 82, 13,
- 82, 82, 82, 82, 82, 11, 82, 1, 82, 82,
- 14, 82, 1, 82, 82, 31, 3, 82, 82, 30,
- 82, 82, 82, 10, 82, 82, 82, 82, 37, 82,
- 82, 82, 82, 82, 82, 82, 82, 82, 82, 82,
- 82, 82, 82, 82, 82, 82, 37, 15, 36, 35,
- 34, 17, 1, 33, 12, 4, 23, 23, 26, 21,
- 13, 82, 27, 82, 82, 2, 5, 82, 11, 16,
- 82, 15, 82, 82, 23, 82, 8, 82
- };
- return asso_values[bits_at(codes, 5)] + asso_values[bits_at(codes, 4)] + asso_values[bits_at(codes, 3)] + asso_values[bits_at(codes, 2)] + asso_values[bits_at(codes, 1)] + asso_values[bits_at(codes, 0)];
-}
-
-static const CodePointList2 *
-onigenc_unicode_CaseUnfold_12_lookup(const OnigCodePoint *codes)
-{
- enum
- {
- MIN_CODE_VALUE = 0x61,
- MAX_CODE_VALUE = 0x1f7c,
- TOTAL_KEYWORDS = 59,
- MIN_WORD_LENGTH = 6,
- MAX_WORD_LENGTH = 6,
- MIN_HASH_VALUE = 11,
- MAX_HASH_VALUE = 81
- };
-
- static const short wordlist[] =
- {
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1,
- /*0x1f66,0x03b9*/ 53,
- /*0x1f07,0x03b9*/ 38,
- /*0x1f00,0x03b9*/ 31,
- /*0x0066,0x0066*/ 1,
- /*0x1f74,0x03b9*/ 56,
- /*0x0073,0x0073*/ 6,
- /*0x0066,0x0069*/ 2,
- /*0x1f06,0x03b9*/ 37,
- /*0x0073,0x0074*/ 7,
- /*0x03b9,0x0342*/ 18,
- /*0x03c9,0x03b9*/ 23,
- /*0x03b7,0x03b9*/ 17,
- /*0x0069,0x0307*/ 58,
- /*0x03b1,0x03b9*/ 15,
- /*0x1f61,0x03b9*/ 48,
- /*0x1f05,0x03b9*/ 36,
- /*0x1f65,0x03b9*/ 52,
- /*0x0574,0x0576*/ 29,
- /*0x03c9,0x0342*/ 22,
- /*0x03b7,0x0342*/ 16,
- /*0x057e,0x0576*/ 30,
- /*0x03b1,0x0342*/ 14,
- /*0x1f7c,0x03b9*/ 57,
- /*0x0574,0x0565*/ 26,
- /*0x0079,0x030a*/ 10,
- /*0x0077,0x030a*/ 9,
- /*0x1f70,0x03b9*/ 55,
- /*0x0574,0x056d*/ 28,
- /*0x0066,0x006c*/ 3,
- /*0x0574,0x056b*/ 27,
- /*0x0061,0x02be*/ 0,
- /*0x0068,0x0331*/ 4,
- /*0x1f67,0x03b9*/ 54,
- /*0x1f64,0x03b9*/ 51,
- /*0x1f63,0x03b9*/ 50,
- /*0x1f62,0x03b9*/ 49,
- /*0x1f60,0x03b9*/ 47,
- /*0x03ce,0x03b9*/ 24,
- /*0x03c5,0x0342*/ 21,
- /*0x03c5,0x0313*/ 20,
- /*0x03c1,0x0313*/ 19,
- /*0x02bc,0x006e*/ 11,
- /*0x03ae,0x03b9*/ 13,
- /*0x03ac,0x03b9*/ 12,
- /*0x1f27,0x03b9*/ 46,
- /*0x1f26,0x03b9*/ 45,
- /*0x1f25,0x03b9*/ 44,
- /*0x1f24,0x03b9*/ 43,
- /*0x1f23,0x03b9*/ 42,
- /*0x1f22,0x03b9*/ 41,
- /*0x1f21,0x03b9*/ 40,
- /*0x1f20,0x03b9*/ 39,
- /*0x006a,0x030c*/ 5,
- /*0x1f02,0x03b9*/ 33,
- /*0x0074,0x0308*/ 8,
- /*0x1f04,0x03b9*/ 35,
- /*0x1f03,0x03b9*/ 34,
- /*0x1f01,0x03b9*/ 32,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- /*0x0565,0x0582*/ 25
- };
-
- if (codes[0] <= MAX_CODE_VALUE && codes[0] >= MIN_CODE_VALUE &&
- codes[1] <= MAX_CODE_VALUE && codes[1] >= MIN_CODE_VALUE)
- {
- register unsigned int key = onigenc_unicode_CaseUnfold_12_hash(codes);
-
- if (key <= MAX_HASH_VALUE)
- {
- register short s = wordlist[key];
-
- if (s >= 0 && code2_equal(codes, CaseUnfold_12_Table[s].from))
- return &CaseUnfold_12_Table[s].to;
- }
- }
- return 0;
-}
-
-static const CaseUnfold_13_Type CaseUnfold_13_Table[] = {
-#define CaseUnfold_13 (*(CaseUnfold_13_Type (*)[14])(CaseUnfold_13_Table+0))
- {{0x0066, 0x0066, 0x0069}, {1, {0xfb03}}},
- {{0x0066, 0x0066, 0x006c}, {1, {0xfb04}}},
- {{0x03b1, 0x0342, 0x03b9}, {1, {0x1fb7}}},
- {{0x03b7, 0x0342, 0x03b9}, {1, {0x1fc7}}},
- {{0x03b9, 0x0308, 0x0300}, {1, {0x1fd2}}},
- {{0x03b9, 0x0308, 0x0301}, {2, {0x0390, 0x1fd3}}},
- {{0x03b9, 0x0308, 0x0342}, {1, {0x1fd7}}},
- {{0x03c5, 0x0308, 0x0300}, {1, {0x1fe2}}},
- {{0x03c5, 0x0308, 0x0301}, {2, {0x03b0, 0x1fe3}}},
- {{0x03c5, 0x0308, 0x0342}, {1, {0x1fe7}}},
- {{0x03c5, 0x0313, 0x0300}, {1, {0x1f52}}},
- {{0x03c5, 0x0313, 0x0301}, {1, {0x1f54}}},
- {{0x03c5, 0x0313, 0x0342}, {1, {0x1f56}}},
- {{0x03c9, 0x0342, 0x03b9}, {1, {0x1ff7}}},
-};
-
-/* ANSI-C code produced by gperf version 3.1 */
-/* Command-line: gperf -7 -k1,2,3,4,5,6,7,8,9 -F,-1 -c -j1 -i1 -t -T -E -C -H onigenc_unicode_CaseUnfold_13_hash -N onigenc_unicode_CaseUnfold_13_lookup -n */
-
-/* maximum key range = 20, duplicates = 0 */
-
-#ifdef __GNUC__
-__inline
-#else
-#ifdef __cplusplus
-inline
-#endif
-#endif
-/*ARGSUSED*/
-static unsigned int
-onigenc_unicode_CaseUnfold_13_hash(const OnigCodePoint *codes)
-{
- static const unsigned char asso_values[] =
- {
- 7, 4, 47, 47, 47, 47, 1, 1, 2, 47,
- 47, 47, 47, 47, 47, 47, 47, 47, 47, 1,
- 47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
- 47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
- 47, 47, 47, 47, 47, 47, 47, 47, 47, 11,
- 47, 47, 47, 47, 47, 10, 47, 2, 47, 47,
- 47, 47, 47, 47, 47, 47, 1, 47, 47, 1,
- 47, 47, 47, 9, 47, 47, 47, 47, 47, 47,
- 47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
- 47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
- 47, 47, 1, 47, 47, 2, 47, 47, 1, 47,
- 47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
- 47, 47, 47, 47, 47, 47, 47, 47
- };
- return asso_values[bits_at(codes, 8)] + asso_values[bits_at(codes, 7)] + asso_values[bits_at(codes, 6)] + asso_values[bits_at(codes, 5)] + asso_values[bits_at(codes, 4)] + asso_values[bits_at(codes, 3)] + asso_values[bits_at(codes, 2)] + asso_values[bits_at(codes, 1)] + asso_values[bits_at(codes, 0)];
-}
-
-static const CodePointList2 *
-onigenc_unicode_CaseUnfold_13_lookup(const OnigCodePoint *codes)
-{
- enum
- {
- MIN_CODE_VALUE = 0x66,
- MAX_CODE_VALUE = 0x3c9,
- TOTAL_KEYWORDS = 14,
- MIN_WORD_LENGTH = 9,
- MAX_WORD_LENGTH = 9,
- MIN_HASH_VALUE = 27,
- MAX_HASH_VALUE = 46
- };
-
- static const short wordlist[] =
- {
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1,
- /*0x03c5,0x0313,0x0342*/ 12,
- /*0x03c5,0x0308,0x0342*/ 9,
- /*0x03b9,0x0308,0x0342*/ 6,
- /*0x03c5,0x0313,0x0301*/ 11,
- /*0x03c5,0x0308,0x0301*/ 8,
- /*0x03b9,0x0308,0x0301*/ 5,
- /*0x03c5,0x0313,0x0300*/ 10,
- /*0x03c5,0x0308,0x0300*/ 7,
- /*0x03b9,0x0308,0x0300*/ 4,
- /*0x03c9,0x0342,0x03b9*/ 13,
- /*0x03b7,0x0342,0x03b9*/ 3,
- /*0x03b1,0x0342,0x03b9*/ 2,
- -1, -1, -1, -1, -1, -1,
- /*0x0066,0x0066,0x006c*/ 1,
- /*0x0066,0x0066,0x0069*/ 0
- };
-
- if (codes[0] <= MAX_CODE_VALUE && codes[0] >= MIN_CODE_VALUE &&
- codes[1] <= MAX_CODE_VALUE && codes[1] >= MIN_CODE_VALUE &&
- codes[2] <= MAX_CODE_VALUE && codes[2] >= MIN_CODE_VALUE)
- {
- register unsigned int key = onigenc_unicode_CaseUnfold_13_hash(codes);
-
- if (key <= MAX_HASH_VALUE)
- {
- register short s = wordlist[key];
-
- if (s >= 0 && code3_equal(codes, CaseUnfold_13_Table[s].from))
- return &CaseUnfold_13_Table[s].to;
- }
- }
- return 0;
-}
-
-static const OnigCodePoint CaseMappingSpecials[] = {
- L(1)|0x039C,
- L(2)|0x0053, 0x0073, L(2)|0x0053, 0x0053,
- L(2)|0x02BC, 0x004E,
- L(1)|0x0053,
- L(1)|0x01C5,
- L(2)|0x0064, 0x017D, L(1)|0x01C4,
- L(1)|0x01C8,
- L(2)|0x006C, 0x004A, L(1)|0x01C7,
- L(1)|0x01CB,
- L(2)|0x006E, 0x004A, L(1)|0x01CA,
- L(2)|0x004A, 0x030C,
- L(1)|0x01F2,
- L(2)|0x0064, 0x005A, L(1)|0x01F1,
- L(1)|0x0399,
- L(3)|0x0399, 0x0308, 0x0301,
- L(3)|0x03A5, 0x0308, 0x0301,
- L(1)|0x03A3,
- L(1)|0x0392,
- L(1)|0x0398,
- L(1)|0x03A6,
- L(1)|0x03A0,
- L(1)|0x039A,
- L(1)|0x03A1,
- L(1)|0x0395,
- L(2)|0x0535, 0x0582, L(2)|0x0535, 0x0552,
- L(1)|0x0412,
- L(1)|0x0414,
- L(1)|0x041E,
- L(1)|0x0421,
- L(1)|0x0422,
- L(1)|0x0422,
- L(1)|0x042A,
- L(1)|0x0462,
- L(1)|0xA64A,
- L(2)|0x0048, 0x0331,
- L(2)|0x0054, 0x0308,
- L(2)|0x0057, 0x030A,
- L(2)|0x0059, 0x030A,
- L(2)|0x0041, 0x02BE,
- L(1)|0x1E60,
- L(1)|0x00DF,
- L(2)|0x03A5, 0x0313,
- L(3)|0x03A5, 0x0313, 0x0300,
- L(3)|0x03A5, 0x0313, 0x0301,
- L(3)|0x03A5, 0x0313, 0x0342,
- L(1)|0x1F88, L(2)|0x1F08, 0x0399,
- L(1)|0x1F89, L(2)|0x1F09, 0x0399,
- L(1)|0x1F8A, L(2)|0x1F0A, 0x0399,
- L(1)|0x1F8B, L(2)|0x1F0B, 0x0399,
- L(1)|0x1F8C, L(2)|0x1F0C, 0x0399,
- L(1)|0x1F8D, L(2)|0x1F0D, 0x0399,
- L(1)|0x1F8E, L(2)|0x1F0E, 0x0399,
- L(1)|0x1F8F, L(2)|0x1F0F, 0x0399,
- L(2)|0x1F00, 0x0399, L(1)|0x1F80, L(2)|0x1F08, 0x0399,
- L(2)|0x1F01, 0x0399, L(1)|0x1F81, L(2)|0x1F09, 0x0399,
- L(2)|0x1F02, 0x0399, L(1)|0x1F82, L(2)|0x1F0A, 0x0399,
- L(2)|0x1F03, 0x0399, L(1)|0x1F83, L(2)|0x1F0B, 0x0399,
- L(2)|0x1F04, 0x0399, L(1)|0x1F84, L(2)|0x1F0C, 0x0399,
- L(2)|0x1F05, 0x0399, L(1)|0x1F85, L(2)|0x1F0D, 0x0399,
- L(2)|0x1F06, 0x0399, L(1)|0x1F86, L(2)|0x1F0E, 0x0399,
- L(2)|0x1F07, 0x0399, L(1)|0x1F87, L(2)|0x1F0F, 0x0399,
- L(1)|0x1F98, L(2)|0x1F28, 0x0399,
- L(1)|0x1F99, L(2)|0x1F29, 0x0399,
- L(1)|0x1F9A, L(2)|0x1F2A, 0x0399,
- L(1)|0x1F9B, L(2)|0x1F2B, 0x0399,
- L(1)|0x1F9C, L(2)|0x1F2C, 0x0399,
- L(1)|0x1F9D, L(2)|0x1F2D, 0x0399,
- L(1)|0x1F9E, L(2)|0x1F2E, 0x0399,
- L(1)|0x1F9F, L(2)|0x1F2F, 0x0399,
- L(2)|0x1F20, 0x0399, L(1)|0x1F90, L(2)|0x1F28, 0x0399,
- L(2)|0x1F21, 0x0399, L(1)|0x1F91, L(2)|0x1F29, 0x0399,
- L(2)|0x1F22, 0x0399, L(1)|0x1F92, L(2)|0x1F2A, 0x0399,
- L(2)|0x1F23, 0x0399, L(1)|0x1F93, L(2)|0x1F2B, 0x0399,
- L(2)|0x1F24, 0x0399, L(1)|0x1F94, L(2)|0x1F2C, 0x0399,
- L(2)|0x1F25, 0x0399, L(1)|0x1F95, L(2)|0x1F2D, 0x0399,
- L(2)|0x1F26, 0x0399, L(1)|0x1F96, L(2)|0x1F2E, 0x0399,
- L(2)|0x1F27, 0x0399, L(1)|0x1F97, L(2)|0x1F2F, 0x0399,
- L(1)|0x1FA8, L(2)|0x1F68, 0x0399,
- L(1)|0x1FA9, L(2)|0x1F69, 0x0399,
- L(1)|0x1FAA, L(2)|0x1F6A, 0x0399,
- L(1)|0x1FAB, L(2)|0x1F6B, 0x0399,
- L(1)|0x1FAC, L(2)|0x1F6C, 0x0399,
- L(1)|0x1FAD, L(2)|0x1F6D, 0x0399,
- L(1)|0x1FAE, L(2)|0x1F6E, 0x0399,
- L(1)|0x1FAF, L(2)|0x1F6F, 0x0399,
- L(2)|0x1F60, 0x0399, L(1)|0x1FA0, L(2)|0x1F68, 0x0399,
- L(2)|0x1F61, 0x0399, L(1)|0x1FA1, L(2)|0x1F69, 0x0399,
- L(2)|0x1F62, 0x0399, L(1)|0x1FA2, L(2)|0x1F6A, 0x0399,
- L(2)|0x1F63, 0x0399, L(1)|0x1FA3, L(2)|0x1F6B, 0x0399,
- L(2)|0x1F64, 0x0399, L(1)|0x1FA4, L(2)|0x1F6C, 0x0399,
- L(2)|0x1F65, 0x0399, L(1)|0x1FA5, L(2)|0x1F6D, 0x0399,
- L(2)|0x1F66, 0x0399, L(1)|0x1FA6, L(2)|0x1F6E, 0x0399,
- L(2)|0x1F67, 0x0399, L(1)|0x1FA7, L(2)|0x1F6F, 0x0399,
- L(2)|0x1FBA, 0x0345, L(2)|0x1FBA, 0x0399,
- L(1)|0x1FBC, L(2)|0x0391, 0x0399,
- L(2)|0x0386, 0x0345, L(2)|0x0386, 0x0399,
- L(2)|0x0391, 0x0342,
- L(3)|0x0391, 0x0342, 0x0345, L(3)|0x0391, 0x0342, 0x0399,
- L(2)|0x03B1, 0x0399, L(1)|0x1FB3, L(2)|0x0391, 0x0399,
- L(1)|0x0399,
- L(2)|0x1FCA, 0x0345, L(2)|0x1FCA, 0x0399,
- L(1)|0x1FCC, L(2)|0x0397, 0x0399,
- L(2)|0x0389, 0x0345, L(2)|0x0389, 0x0399,
- L(2)|0x0397, 0x0342,
- L(3)|0x0397, 0x0342, 0x0345, L(3)|0x0397, 0x0342, 0x0399,
- L(2)|0x03B7, 0x0399, L(1)|0x1FC3, L(2)|0x0397, 0x0399,
- L(3)|0x0399, 0x0308, 0x0300,
- L(3)|0x0399, 0x0308, 0x0301,
- L(2)|0x0399, 0x0342,
- L(3)|0x0399, 0x0308, 0x0342,
- L(3)|0x03A5, 0x0308, 0x0300,
- L(3)|0x03A5, 0x0308, 0x0301,
- L(2)|0x03A1, 0x0313,
- L(2)|0x03A5, 0x0342,
- L(3)|0x03A5, 0x0308, 0x0342,
- L(2)|0x1FFA, 0x0345, L(2)|0x1FFA, 0x0399,
- L(1)|0x1FFC, L(2)|0x03A9, 0x0399,
- L(2)|0x038F, 0x0345, L(2)|0x038F, 0x0399,
- L(2)|0x03A9, 0x0342,
- L(3)|0x03A9, 0x0342, 0x0345, L(3)|0x03A9, 0x0342, 0x0399,
- L(2)|0x03C9, 0x0399, L(1)|0x1FF3, L(2)|0x03A9, 0x0399,
- L(2)|0x0046, 0x0066, L(2)|0x0046, 0x0046,
- L(2)|0x0046, 0x0069, L(2)|0x0046, 0x0049,
- L(2)|0x0046, 0x006C, L(2)|0x0046, 0x004C,
- L(3)|0x0046, 0x0066, 0x0069, L(3)|0x0046, 0x0046, 0x0049,
- L(3)|0x0046, 0x0066, 0x006C, L(3)|0x0046, 0x0046, 0x004C,
- L(2)|0x0053, 0x0074, L(2)|0x0053, 0x0054,
- L(2)|0x0053, 0x0074, L(2)|0x0053, 0x0054,
- L(2)|0x0544, 0x0576, L(2)|0x0544, 0x0546,
- L(2)|0x0544, 0x0565, L(2)|0x0544, 0x0535,
- L(2)|0x0544, 0x056B, L(2)|0x0544, 0x053B,
- L(2)|0x054E, 0x0576, L(2)|0x054E, 0x0546,
- L(2)|0x0544, 0x056D, L(2)|0x0544, 0x053D,
-};
diff --git a/enc/unicode/16.0.0/name2ctype.h b/enc/unicode/16.0.0/name2ctype.h
deleted file mode 100644
index 42da74f318..0000000000
--- a/enc/unicode/16.0.0/name2ctype.h
+++ /dev/null
@@ -1,48543 +0,0 @@
-/* ANSI-C code produced by gperf version 3.1 */
-/* Command-line: gperf -7 -c -j1 -i1 -t -C -P -T -H uniname2ctype_hash -Q uniname2ctype_pool -N uniname2ctype_p */
-#ifndef USE_UNICODE_PROPERTIES
-/* Computed positions: -k'1,3' */
-#else /* USE_UNICODE_PROPERTIES */
-/* Computed positions: -k'1-3,5-6,12,16,$' */
-#endif /* USE_UNICODE_PROPERTIES */
-
-#if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \
- && ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \
- && (')' == 41) && ('*' == 42) && ('+' == 43) && (',' == 44) \
- && ('-' == 45) && ('.' == 46) && ('/' == 47) && ('0' == 48) \
- && ('1' == 49) && ('2' == 50) && ('3' == 51) && ('4' == 52) \
- && ('5' == 53) && ('6' == 54) && ('7' == 55) && ('8' == 56) \
- && ('9' == 57) && (':' == 58) && (';' == 59) && ('<' == 60) \
- && ('=' == 61) && ('>' == 62) && ('?' == 63) && ('A' == 65) \
- && ('B' == 66) && ('C' == 67) && ('D' == 68) && ('E' == 69) \
- && ('F' == 70) && ('G' == 71) && ('H' == 72) && ('I' == 73) \
- && ('J' == 74) && ('K' == 75) && ('L' == 76) && ('M' == 77) \
- && ('N' == 78) && ('O' == 79) && ('P' == 80) && ('Q' == 81) \
- && ('R' == 82) && ('S' == 83) && ('T' == 84) && ('U' == 85) \
- && ('V' == 86) && ('W' == 87) && ('X' == 88) && ('Y' == 89) \
- && ('Z' == 90) && ('[' == 91) && ('\\' == 92) && (']' == 93) \
- && ('^' == 94) && ('_' == 95) && ('a' == 97) && ('b' == 98) \
- && ('c' == 99) && ('d' == 100) && ('e' == 101) && ('f' == 102) \
- && ('g' == 103) && ('h' == 104) && ('i' == 105) && ('j' == 106) \
- && ('k' == 107) && ('l' == 108) && ('m' == 109) && ('n' == 110) \
- && ('o' == 111) && ('p' == 112) && ('q' == 113) && ('r' == 114) \
- && ('s' == 115) && ('t' == 116) && ('u' == 117) && ('v' == 118) \
- && ('w' == 119) && ('x' == 120) && ('y' == 121) && ('z' == 122) \
- && ('{' == 123) && ('|' == 124) && ('}' == 125) && ('~' == 126))
-/* The character set is not based on ISO-646. */
-#error "gperf generated tables don't work with this execution character set. Please report a bug to <bug-gperf@gnu.org>."
-#endif
-
-
-
-/* 'NEWLINE': [[:NEWLINE:]] */
-static const OnigCodePoint CR_NEWLINE[] = {
- 1,
- 0x000a, 0x000a,
-}; /* CR_NEWLINE */
-
-/* 'Alpha': [[:Alpha:]] */
-static const OnigCodePoint CR_Alpha[] = {
- 757,
- 0x0041, 0x005a,
- 0x0061, 0x007a,
- 0x00aa, 0x00aa,
- 0x00b5, 0x00b5,
- 0x00ba, 0x00ba,
- 0x00c0, 0x00d6,
- 0x00d8, 0x00f6,
- 0x00f8, 0x02c1,
- 0x02c6, 0x02d1,
- 0x02e0, 0x02e4,
- 0x02ec, 0x02ec,
- 0x02ee, 0x02ee,
- 0x0345, 0x0345,
- 0x0363, 0x0374,
- 0x0376, 0x0377,
- 0x037a, 0x037d,
- 0x037f, 0x037f,
- 0x0386, 0x0386,
- 0x0388, 0x038a,
- 0x038c, 0x038c,
- 0x038e, 0x03a1,
- 0x03a3, 0x03f5,
- 0x03f7, 0x0481,
- 0x048a, 0x052f,
- 0x0531, 0x0556,
- 0x0559, 0x0559,
- 0x0560, 0x0588,
- 0x05b0, 0x05bd,
- 0x05bf, 0x05bf,
- 0x05c1, 0x05c2,
- 0x05c4, 0x05c5,
- 0x05c7, 0x05c7,
- 0x05d0, 0x05ea,
- 0x05ef, 0x05f2,
- 0x0610, 0x061a,
- 0x0620, 0x0657,
- 0x0659, 0x065f,
- 0x066e, 0x06d3,
- 0x06d5, 0x06dc,
- 0x06e1, 0x06e8,
- 0x06ed, 0x06ef,
- 0x06fa, 0x06fc,
- 0x06ff, 0x06ff,
- 0x0710, 0x073f,
- 0x074d, 0x07b1,
- 0x07ca, 0x07ea,
- 0x07f4, 0x07f5,
- 0x07fa, 0x07fa,
- 0x0800, 0x0817,
- 0x081a, 0x082c,
- 0x0840, 0x0858,
- 0x0860, 0x086a,
- 0x0870, 0x0887,
- 0x0889, 0x088e,
- 0x0897, 0x0897,
- 0x08a0, 0x08c9,
- 0x08d4, 0x08df,
- 0x08e3, 0x08e9,
- 0x08f0, 0x093b,
- 0x093d, 0x094c,
- 0x094e, 0x0950,
- 0x0955, 0x0963,
- 0x0971, 0x0983,
- 0x0985, 0x098c,
- 0x098f, 0x0990,
- 0x0993, 0x09a8,
- 0x09aa, 0x09b0,
- 0x09b2, 0x09b2,
- 0x09b6, 0x09b9,
- 0x09bd, 0x09c4,
- 0x09c7, 0x09c8,
- 0x09cb, 0x09cc,
- 0x09ce, 0x09ce,
- 0x09d7, 0x09d7,
- 0x09dc, 0x09dd,
- 0x09df, 0x09e3,
- 0x09f0, 0x09f1,
- 0x09fc, 0x09fc,
- 0x0a01, 0x0a03,
- 0x0a05, 0x0a0a,
- 0x0a0f, 0x0a10,
- 0x0a13, 0x0a28,
- 0x0a2a, 0x0a30,
- 0x0a32, 0x0a33,
- 0x0a35, 0x0a36,
- 0x0a38, 0x0a39,
- 0x0a3e, 0x0a42,
- 0x0a47, 0x0a48,
- 0x0a4b, 0x0a4c,
- 0x0a51, 0x0a51,
- 0x0a59, 0x0a5c,
- 0x0a5e, 0x0a5e,
- 0x0a70, 0x0a75,
- 0x0a81, 0x0a83,
- 0x0a85, 0x0a8d,
- 0x0a8f, 0x0a91,
- 0x0a93, 0x0aa8,
- 0x0aaa, 0x0ab0,
- 0x0ab2, 0x0ab3,
- 0x0ab5, 0x0ab9,
- 0x0abd, 0x0ac5,
- 0x0ac7, 0x0ac9,
- 0x0acb, 0x0acc,
- 0x0ad0, 0x0ad0,
- 0x0ae0, 0x0ae3,
- 0x0af9, 0x0afc,
- 0x0b01, 0x0b03,
- 0x0b05, 0x0b0c,
- 0x0b0f, 0x0b10,
- 0x0b13, 0x0b28,
- 0x0b2a, 0x0b30,
- 0x0b32, 0x0b33,
- 0x0b35, 0x0b39,
- 0x0b3d, 0x0b44,
- 0x0b47, 0x0b48,
- 0x0b4b, 0x0b4c,
- 0x0b56, 0x0b57,
- 0x0b5c, 0x0b5d,
- 0x0b5f, 0x0b63,
- 0x0b71, 0x0b71,
- 0x0b82, 0x0b83,
- 0x0b85, 0x0b8a,
- 0x0b8e, 0x0b90,
- 0x0b92, 0x0b95,
- 0x0b99, 0x0b9a,
- 0x0b9c, 0x0b9c,
- 0x0b9e, 0x0b9f,
- 0x0ba3, 0x0ba4,
- 0x0ba8, 0x0baa,
- 0x0bae, 0x0bb9,
- 0x0bbe, 0x0bc2,
- 0x0bc6, 0x0bc8,
- 0x0bca, 0x0bcc,
- 0x0bd0, 0x0bd0,
- 0x0bd7, 0x0bd7,
- 0x0c00, 0x0c0c,
- 0x0c0e, 0x0c10,
- 0x0c12, 0x0c28,
- 0x0c2a, 0x0c39,
- 0x0c3d, 0x0c44,
- 0x0c46, 0x0c48,
- 0x0c4a, 0x0c4c,
- 0x0c55, 0x0c56,
- 0x0c58, 0x0c5a,
- 0x0c5d, 0x0c5d,
- 0x0c60, 0x0c63,
- 0x0c80, 0x0c83,
- 0x0c85, 0x0c8c,
- 0x0c8e, 0x0c90,
- 0x0c92, 0x0ca8,
- 0x0caa, 0x0cb3,
- 0x0cb5, 0x0cb9,
- 0x0cbd, 0x0cc4,
- 0x0cc6, 0x0cc8,
- 0x0cca, 0x0ccc,
- 0x0cd5, 0x0cd6,
- 0x0cdd, 0x0cde,
- 0x0ce0, 0x0ce3,
- 0x0cf1, 0x0cf3,
- 0x0d00, 0x0d0c,
- 0x0d0e, 0x0d10,
- 0x0d12, 0x0d3a,
- 0x0d3d, 0x0d44,
- 0x0d46, 0x0d48,
- 0x0d4a, 0x0d4c,
- 0x0d4e, 0x0d4e,
- 0x0d54, 0x0d57,
- 0x0d5f, 0x0d63,
- 0x0d7a, 0x0d7f,
- 0x0d81, 0x0d83,
- 0x0d85, 0x0d96,
- 0x0d9a, 0x0db1,
- 0x0db3, 0x0dbb,
- 0x0dbd, 0x0dbd,
- 0x0dc0, 0x0dc6,
- 0x0dcf, 0x0dd4,
- 0x0dd6, 0x0dd6,
- 0x0dd8, 0x0ddf,
- 0x0df2, 0x0df3,
- 0x0e01, 0x0e3a,
- 0x0e40, 0x0e46,
- 0x0e4d, 0x0e4d,
- 0x0e81, 0x0e82,
- 0x0e84, 0x0e84,
- 0x0e86, 0x0e8a,
- 0x0e8c, 0x0ea3,
- 0x0ea5, 0x0ea5,
- 0x0ea7, 0x0eb9,
- 0x0ebb, 0x0ebd,
- 0x0ec0, 0x0ec4,
- 0x0ec6, 0x0ec6,
- 0x0ecd, 0x0ecd,
- 0x0edc, 0x0edf,
- 0x0f00, 0x0f00,
- 0x0f40, 0x0f47,
- 0x0f49, 0x0f6c,
- 0x0f71, 0x0f83,
- 0x0f88, 0x0f97,
- 0x0f99, 0x0fbc,
- 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, 0x1c8a,
- 0x1c90, 0x1cba,
- 0x1cbd, 0x1cbf,
- 0x1ce9, 0x1cec,
- 0x1cee, 0x1cf3,
- 0x1cf5, 0x1cf6,
- 0x1cfa, 0x1cfa,
- 0x1d00, 0x1dbf,
- 0x1dd3, 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, 0xa7cd,
- 0xa7d0, 0xa7d1,
- 0xa7d3, 0xa7d3,
- 0xa7d5, 0xa7dc,
- 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,
- 0x105c0, 0x105f3,
- 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,
- 0x10d4a, 0x10d65,
- 0x10d69, 0x10d69,
- 0x10d6f, 0x10d85,
- 0x10e80, 0x10ea9,
- 0x10eab, 0x10eac,
- 0x10eb0, 0x10eb1,
- 0x10ec2, 0x10ec4,
- 0x10efc, 0x10efc,
- 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,
- 0x11380, 0x11389,
- 0x1138b, 0x1138b,
- 0x1138e, 0x1138e,
- 0x11390, 0x113b5,
- 0x113b7, 0x113c0,
- 0x113c2, 0x113c2,
- 0x113c5, 0x113c5,
- 0x113c7, 0x113ca,
- 0x113cc, 0x113cd,
- 0x113d1, 0x113d1,
- 0x113d3, 0x113d3,
- 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,
- 0x11bc0, 0x11be0,
- 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,
- 0x13460, 0x143fa,
- 0x14400, 0x14646,
- 0x16100, 0x1612e,
- 0x16800, 0x16a38,
- 0x16a40, 0x16a5e,
- 0x16a70, 0x16abe,
- 0x16ad0, 0x16aed,
- 0x16b00, 0x16b2f,
- 0x16b40, 0x16b43,
- 0x16b63, 0x16b77,
- 0x16b7d, 0x16b8f,
- 0x16d40, 0x16d6c,
- 0x16e40, 0x16e7f,
- 0x16f00, 0x16f4a,
- 0x16f4f, 0x16f87,
- 0x16f8f, 0x16f9f,
- 0x16fe0, 0x16fe1,
- 0x16fe3, 0x16fe3,
- 0x16ff0, 0x16ff1,
- 0x17000, 0x187f7,
- 0x18800, 0x18cd5,
- 0x18cff, 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,
- 0x1e5d0, 0x1e5ed,
- 0x1e5f0, 0x1e5f0,
- 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,
- 0x2ebf0, 0x2ee5d,
- 0x2f800, 0x2fa1d,
- 0x30000, 0x3134a,
- 0x31350, 0x323af,
-}; /* CR_Alpha */
-
-/* 'Blank': [[:Blank:]] */
-static const OnigCodePoint CR_Blank[] = {
- 8,
- 0x0009, 0x0009,
- 0x0020, 0x0020,
- 0x00a0, 0x00a0,
- 0x1680, 0x1680,
- 0x2000, 0x200a,
- 0x202f, 0x202f,
- 0x205f, 0x205f,
- 0x3000, 0x3000,
-}; /* CR_Blank */
-
-/* 'Cntrl': [[:Cntrl:]] */
-static const OnigCodePoint CR_Cntrl[] = {
- 2,
- 0x0000, 0x001f,
- 0x007f, 0x009f,
-}; /* CR_Cntrl */
-
-/* 'Digit': [[:Digit:]] */
-static const OnigCodePoint CR_Digit[] = {
- 71,
- 0x0030, 0x0039,
- 0x0660, 0x0669,
- 0x06f0, 0x06f9,
- 0x07c0, 0x07c9,
- 0x0966, 0x096f,
- 0x09e6, 0x09ef,
- 0x0a66, 0x0a6f,
- 0x0ae6, 0x0aef,
- 0x0b66, 0x0b6f,
- 0x0be6, 0x0bef,
- 0x0c66, 0x0c6f,
- 0x0ce6, 0x0cef,
- 0x0d66, 0x0d6f,
- 0x0de6, 0x0def,
- 0x0e50, 0x0e59,
- 0x0ed0, 0x0ed9,
- 0x0f20, 0x0f29,
- 0x1040, 0x1049,
- 0x1090, 0x1099,
- 0x17e0, 0x17e9,
- 0x1810, 0x1819,
- 0x1946, 0x194f,
- 0x19d0, 0x19d9,
- 0x1a80, 0x1a89,
- 0x1a90, 0x1a99,
- 0x1b50, 0x1b59,
- 0x1bb0, 0x1bb9,
- 0x1c40, 0x1c49,
- 0x1c50, 0x1c59,
- 0xa620, 0xa629,
- 0xa8d0, 0xa8d9,
- 0xa900, 0xa909,
- 0xa9d0, 0xa9d9,
- 0xa9f0, 0xa9f9,
- 0xaa50, 0xaa59,
- 0xabf0, 0xabf9,
- 0xff10, 0xff19,
- 0x104a0, 0x104a9,
- 0x10d30, 0x10d39,
- 0x10d40, 0x10d49,
- 0x11066, 0x1106f,
- 0x110f0, 0x110f9,
- 0x11136, 0x1113f,
- 0x111d0, 0x111d9,
- 0x112f0, 0x112f9,
- 0x11450, 0x11459,
- 0x114d0, 0x114d9,
- 0x11650, 0x11659,
- 0x116c0, 0x116c9,
- 0x116d0, 0x116e3,
- 0x11730, 0x11739,
- 0x118e0, 0x118e9,
- 0x11950, 0x11959,
- 0x11bf0, 0x11bf9,
- 0x11c50, 0x11c59,
- 0x11d50, 0x11d59,
- 0x11da0, 0x11da9,
- 0x11f50, 0x11f59,
- 0x16130, 0x16139,
- 0x16a60, 0x16a69,
- 0x16ac0, 0x16ac9,
- 0x16b50, 0x16b59,
- 0x16d70, 0x16d79,
- 0x1ccf0, 0x1ccf9,
- 0x1d7ce, 0x1d7ff,
- 0x1e140, 0x1e149,
- 0x1e2f0, 0x1e2f9,
- 0x1e4f0, 0x1e4f9,
- 0x1e5f1, 0x1e5fa,
- 0x1e950, 0x1e959,
- 0x1fbf0, 0x1fbf9,
-}; /* CR_Digit */
-
-/* 'Graph': [[:Graph:]] */
-static const OnigCodePoint CR_Graph[] = {
- 737,
- 0x0021, 0x007e,
- 0x00a1, 0x0377,
- 0x037a, 0x037f,
- 0x0384, 0x038a,
- 0x038c, 0x038c,
- 0x038e, 0x03a1,
- 0x03a3, 0x052f,
- 0x0531, 0x0556,
- 0x0559, 0x058a,
- 0x058d, 0x058f,
- 0x0591, 0x05c7,
- 0x05d0, 0x05ea,
- 0x05ef, 0x05f4,
- 0x0600, 0x070d,
- 0x070f, 0x074a,
- 0x074d, 0x07b1,
- 0x07c0, 0x07fa,
- 0x07fd, 0x082d,
- 0x0830, 0x083e,
- 0x0840, 0x085b,
- 0x085e, 0x085e,
- 0x0860, 0x086a,
- 0x0870, 0x088e,
- 0x0890, 0x0891,
- 0x0897, 0x0983,
- 0x0985, 0x098c,
- 0x098f, 0x0990,
- 0x0993, 0x09a8,
- 0x09aa, 0x09b0,
- 0x09b2, 0x09b2,
- 0x09b6, 0x09b9,
- 0x09bc, 0x09c4,
- 0x09c7, 0x09c8,
- 0x09cb, 0x09ce,
- 0x09d7, 0x09d7,
- 0x09dc, 0x09dd,
- 0x09df, 0x09e3,
- 0x09e6, 0x09fe,
- 0x0a01, 0x0a03,
- 0x0a05, 0x0a0a,
- 0x0a0f, 0x0a10,
- 0x0a13, 0x0a28,
- 0x0a2a, 0x0a30,
- 0x0a32, 0x0a33,
- 0x0a35, 0x0a36,
- 0x0a38, 0x0a39,
- 0x0a3c, 0x0a3c,
- 0x0a3e, 0x0a42,
- 0x0a47, 0x0a48,
- 0x0a4b, 0x0a4d,
- 0x0a51, 0x0a51,
- 0x0a59, 0x0a5c,
- 0x0a5e, 0x0a5e,
- 0x0a66, 0x0a76,
- 0x0a81, 0x0a83,
- 0x0a85, 0x0a8d,
- 0x0a8f, 0x0a91,
- 0x0a93, 0x0aa8,
- 0x0aaa, 0x0ab0,
- 0x0ab2, 0x0ab3,
- 0x0ab5, 0x0ab9,
- 0x0abc, 0x0ac5,
- 0x0ac7, 0x0ac9,
- 0x0acb, 0x0acd,
- 0x0ad0, 0x0ad0,
- 0x0ae0, 0x0ae3,
- 0x0ae6, 0x0af1,
- 0x0af9, 0x0aff,
- 0x0b01, 0x0b03,
- 0x0b05, 0x0b0c,
- 0x0b0f, 0x0b10,
- 0x0b13, 0x0b28,
- 0x0b2a, 0x0b30,
- 0x0b32, 0x0b33,
- 0x0b35, 0x0b39,
- 0x0b3c, 0x0b44,
- 0x0b47, 0x0b48,
- 0x0b4b, 0x0b4d,
- 0x0b55, 0x0b57,
- 0x0b5c, 0x0b5d,
- 0x0b5f, 0x0b63,
- 0x0b66, 0x0b77,
- 0x0b82, 0x0b83,
- 0x0b85, 0x0b8a,
- 0x0b8e, 0x0b90,
- 0x0b92, 0x0b95,
- 0x0b99, 0x0b9a,
- 0x0b9c, 0x0b9c,
- 0x0b9e, 0x0b9f,
- 0x0ba3, 0x0ba4,
- 0x0ba8, 0x0baa,
- 0x0bae, 0x0bb9,
- 0x0bbe, 0x0bc2,
- 0x0bc6, 0x0bc8,
- 0x0bca, 0x0bcd,
- 0x0bd0, 0x0bd0,
- 0x0bd7, 0x0bd7,
- 0x0be6, 0x0bfa,
- 0x0c00, 0x0c0c,
- 0x0c0e, 0x0c10,
- 0x0c12, 0x0c28,
- 0x0c2a, 0x0c39,
- 0x0c3c, 0x0c44,
- 0x0c46, 0x0c48,
- 0x0c4a, 0x0c4d,
- 0x0c55, 0x0c56,
- 0x0c58, 0x0c5a,
- 0x0c5d, 0x0c5d,
- 0x0c60, 0x0c63,
- 0x0c66, 0x0c6f,
- 0x0c77, 0x0c8c,
- 0x0c8e, 0x0c90,
- 0x0c92, 0x0ca8,
- 0x0caa, 0x0cb3,
- 0x0cb5, 0x0cb9,
- 0x0cbc, 0x0cc4,
- 0x0cc6, 0x0cc8,
- 0x0cca, 0x0ccd,
- 0x0cd5, 0x0cd6,
- 0x0cdd, 0x0cde,
- 0x0ce0, 0x0ce3,
- 0x0ce6, 0x0cef,
- 0x0cf1, 0x0cf3,
- 0x0d00, 0x0d0c,
- 0x0d0e, 0x0d10,
- 0x0d12, 0x0d44,
- 0x0d46, 0x0d48,
- 0x0d4a, 0x0d4f,
- 0x0d54, 0x0d63,
- 0x0d66, 0x0d7f,
- 0x0d81, 0x0d83,
- 0x0d85, 0x0d96,
- 0x0d9a, 0x0db1,
- 0x0db3, 0x0dbb,
- 0x0dbd, 0x0dbd,
- 0x0dc0, 0x0dc6,
- 0x0dca, 0x0dca,
- 0x0dcf, 0x0dd4,
- 0x0dd6, 0x0dd6,
- 0x0dd8, 0x0ddf,
- 0x0de6, 0x0def,
- 0x0df2, 0x0df4,
- 0x0e01, 0x0e3a,
- 0x0e3f, 0x0e5b,
- 0x0e81, 0x0e82,
- 0x0e84, 0x0e84,
- 0x0e86, 0x0e8a,
- 0x0e8c, 0x0ea3,
- 0x0ea5, 0x0ea5,
- 0x0ea7, 0x0ebd,
- 0x0ec0, 0x0ec4,
- 0x0ec6, 0x0ec6,
- 0x0ec8, 0x0ece,
- 0x0ed0, 0x0ed9,
- 0x0edc, 0x0edf,
- 0x0f00, 0x0f47,
- 0x0f49, 0x0f6c,
- 0x0f71, 0x0f97,
- 0x0f99, 0x0fbc,
- 0x0fbe, 0x0fcc,
- 0x0fce, 0x0fda,
- 0x1000, 0x10c5,
- 0x10c7, 0x10c7,
- 0x10cd, 0x10cd,
- 0x10d0, 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,
- 0x135d, 0x137c,
- 0x1380, 0x1399,
- 0x13a0, 0x13f5,
- 0x13f8, 0x13fd,
- 0x1400, 0x167f,
- 0x1681, 0x169c,
- 0x16a0, 0x16f8,
- 0x1700, 0x1715,
- 0x171f, 0x1736,
- 0x1740, 0x1753,
- 0x1760, 0x176c,
- 0x176e, 0x1770,
- 0x1772, 0x1773,
- 0x1780, 0x17dd,
- 0x17e0, 0x17e9,
- 0x17f0, 0x17f9,
- 0x1800, 0x1819,
- 0x1820, 0x1878,
- 0x1880, 0x18aa,
- 0x18b0, 0x18f5,
- 0x1900, 0x191e,
- 0x1920, 0x192b,
- 0x1930, 0x193b,
- 0x1940, 0x1940,
- 0x1944, 0x196d,
- 0x1970, 0x1974,
- 0x1980, 0x19ab,
- 0x19b0, 0x19c9,
- 0x19d0, 0x19da,
- 0x19de, 0x1a1b,
- 0x1a1e, 0x1a5e,
- 0x1a60, 0x1a7c,
- 0x1a7f, 0x1a89,
- 0x1a90, 0x1a99,
- 0x1aa0, 0x1aad,
- 0x1ab0, 0x1ace,
- 0x1b00, 0x1b4c,
- 0x1b4e, 0x1bf3,
- 0x1bfc, 0x1c37,
- 0x1c3b, 0x1c49,
- 0x1c4d, 0x1c8a,
- 0x1c90, 0x1cba,
- 0x1cbd, 0x1cc7,
- 0x1cd0, 0x1cfa,
- 0x1d00, 0x1f15,
- 0x1f18, 0x1f1d,
- 0x1f20, 0x1f45,
- 0x1f48, 0x1f4d,
- 0x1f50, 0x1f57,
- 0x1f59, 0x1f59,
- 0x1f5b, 0x1f5b,
- 0x1f5d, 0x1f5d,
- 0x1f5f, 0x1f7d,
- 0x1f80, 0x1fb4,
- 0x1fb6, 0x1fc4,
- 0x1fc6, 0x1fd3,
- 0x1fd6, 0x1fdb,
- 0x1fdd, 0x1fef,
- 0x1ff2, 0x1ff4,
- 0x1ff6, 0x1ffe,
- 0x200b, 0x2027,
- 0x202a, 0x202e,
- 0x2030, 0x205e,
- 0x2060, 0x2064,
- 0x2066, 0x2071,
- 0x2074, 0x208e,
- 0x2090, 0x209c,
- 0x20a0, 0x20c0,
- 0x20d0, 0x20f0,
- 0x2100, 0x218b,
- 0x2190, 0x2429,
- 0x2440, 0x244a,
- 0x2460, 0x2b73,
- 0x2b76, 0x2b95,
- 0x2b97, 0x2cf3,
- 0x2cf9, 0x2d25,
- 0x2d27, 0x2d27,
- 0x2d2d, 0x2d2d,
- 0x2d30, 0x2d67,
- 0x2d6f, 0x2d70,
- 0x2d7f, 0x2d96,
- 0x2da0, 0x2da6,
- 0x2da8, 0x2dae,
- 0x2db0, 0x2db6,
- 0x2db8, 0x2dbe,
- 0x2dc0, 0x2dc6,
- 0x2dc8, 0x2dce,
- 0x2dd0, 0x2dd6,
- 0x2dd8, 0x2dde,
- 0x2de0, 0x2e5d,
- 0x2e80, 0x2e99,
- 0x2e9b, 0x2ef3,
- 0x2f00, 0x2fd5,
- 0x2ff0, 0x2fff,
- 0x3001, 0x303f,
- 0x3041, 0x3096,
- 0x3099, 0x30ff,
- 0x3105, 0x312f,
- 0x3131, 0x318e,
- 0x3190, 0x31e5,
- 0x31ef, 0x321e,
- 0x3220, 0xa48c,
- 0xa490, 0xa4c6,
- 0xa4d0, 0xa62b,
- 0xa640, 0xa6f7,
- 0xa700, 0xa7cd,
- 0xa7d0, 0xa7d1,
- 0xa7d3, 0xa7d3,
- 0xa7d5, 0xa7dc,
- 0xa7f2, 0xa82c,
- 0xa830, 0xa839,
- 0xa840, 0xa877,
- 0xa880, 0xa8c5,
- 0xa8ce, 0xa8d9,
- 0xa8e0, 0xa953,
- 0xa95f, 0xa97c,
- 0xa980, 0xa9cd,
- 0xa9cf, 0xa9d9,
- 0xa9de, 0xa9fe,
- 0xaa00, 0xaa36,
- 0xaa40, 0xaa4d,
- 0xaa50, 0xaa59,
- 0xaa5c, 0xaac2,
- 0xaadb, 0xaaf6,
- 0xab01, 0xab06,
- 0xab09, 0xab0e,
- 0xab11, 0xab16,
- 0xab20, 0xab26,
- 0xab28, 0xab2e,
- 0xab30, 0xab6b,
- 0xab70, 0xabed,
- 0xabf0, 0xabf9,
- 0xac00, 0xd7a3,
- 0xd7b0, 0xd7c6,
- 0xd7cb, 0xd7fb,
- 0xe000, 0xfa6d,
- 0xfa70, 0xfad9,
- 0xfb00, 0xfb06,
- 0xfb13, 0xfb17,
- 0xfb1d, 0xfb36,
- 0xfb38, 0xfb3c,
- 0xfb3e, 0xfb3e,
- 0xfb40, 0xfb41,
- 0xfb43, 0xfb44,
- 0xfb46, 0xfbc2,
- 0xfbd3, 0xfd8f,
- 0xfd92, 0xfdc7,
- 0xfdcf, 0xfdcf,
- 0xfdf0, 0xfe19,
- 0xfe20, 0xfe52,
- 0xfe54, 0xfe66,
- 0xfe68, 0xfe6b,
- 0xfe70, 0xfe74,
- 0xfe76, 0xfefc,
- 0xfeff, 0xfeff,
- 0xff01, 0xffbe,
- 0xffc2, 0xffc7,
- 0xffca, 0xffcf,
- 0xffd2, 0xffd7,
- 0xffda, 0xffdc,
- 0xffe0, 0xffe6,
- 0xffe8, 0xffee,
- 0xfff9, 0xfffd,
- 0x10000, 0x1000b,
- 0x1000d, 0x10026,
- 0x10028, 0x1003a,
- 0x1003c, 0x1003d,
- 0x1003f, 0x1004d,
- 0x10050, 0x1005d,
- 0x10080, 0x100fa,
- 0x10100, 0x10102,
- 0x10107, 0x10133,
- 0x10137, 0x1018e,
- 0x10190, 0x1019c,
- 0x101a0, 0x101a0,
- 0x101d0, 0x101fd,
- 0x10280, 0x1029c,
- 0x102a0, 0x102d0,
- 0x102e0, 0x102fb,
- 0x10300, 0x10323,
- 0x1032d, 0x1034a,
- 0x10350, 0x1037a,
- 0x10380, 0x1039d,
- 0x1039f, 0x103c3,
- 0x103c8, 0x103d5,
- 0x10400, 0x1049d,
- 0x104a0, 0x104a9,
- 0x104b0, 0x104d3,
- 0x104d8, 0x104fb,
- 0x10500, 0x10527,
- 0x10530, 0x10563,
- 0x1056f, 0x1057a,
- 0x1057c, 0x1058a,
- 0x1058c, 0x10592,
- 0x10594, 0x10595,
- 0x10597, 0x105a1,
- 0x105a3, 0x105b1,
- 0x105b3, 0x105b9,
- 0x105bb, 0x105bc,
- 0x105c0, 0x105f3,
- 0x10600, 0x10736,
- 0x10740, 0x10755,
- 0x10760, 0x10767,
- 0x10780, 0x10785,
- 0x10787, 0x107b0,
- 0x107b2, 0x107ba,
- 0x10800, 0x10805,
- 0x10808, 0x10808,
- 0x1080a, 0x10835,
- 0x10837, 0x10838,
- 0x1083c, 0x1083c,
- 0x1083f, 0x10855,
- 0x10857, 0x1089e,
- 0x108a7, 0x108af,
- 0x108e0, 0x108f2,
- 0x108f4, 0x108f5,
- 0x108fb, 0x1091b,
- 0x1091f, 0x10939,
- 0x1093f, 0x1093f,
- 0x10980, 0x109b7,
- 0x109bc, 0x109cf,
- 0x109d2, 0x10a03,
- 0x10a05, 0x10a06,
- 0x10a0c, 0x10a13,
- 0x10a15, 0x10a17,
- 0x10a19, 0x10a35,
- 0x10a38, 0x10a3a,
- 0x10a3f, 0x10a48,
- 0x10a50, 0x10a58,
- 0x10a60, 0x10a9f,
- 0x10ac0, 0x10ae6,
- 0x10aeb, 0x10af6,
- 0x10b00, 0x10b35,
- 0x10b39, 0x10b55,
- 0x10b58, 0x10b72,
- 0x10b78, 0x10b91,
- 0x10b99, 0x10b9c,
- 0x10ba9, 0x10baf,
- 0x10c00, 0x10c48,
- 0x10c80, 0x10cb2,
- 0x10cc0, 0x10cf2,
- 0x10cfa, 0x10d27,
- 0x10d30, 0x10d39,
- 0x10d40, 0x10d65,
- 0x10d69, 0x10d85,
- 0x10d8e, 0x10d8f,
- 0x10e60, 0x10e7e,
- 0x10e80, 0x10ea9,
- 0x10eab, 0x10ead,
- 0x10eb0, 0x10eb1,
- 0x10ec2, 0x10ec4,
- 0x10efc, 0x10f27,
- 0x10f30, 0x10f59,
- 0x10f70, 0x10f89,
- 0x10fb0, 0x10fcb,
- 0x10fe0, 0x10ff6,
- 0x11000, 0x1104d,
- 0x11052, 0x11075,
- 0x1107f, 0x110c2,
- 0x110cd, 0x110cd,
- 0x110d0, 0x110e8,
- 0x110f0, 0x110f9,
- 0x11100, 0x11134,
- 0x11136, 0x11147,
- 0x11150, 0x11176,
- 0x11180, 0x111df,
- 0x111e1, 0x111f4,
- 0x11200, 0x11211,
- 0x11213, 0x11241,
- 0x11280, 0x11286,
- 0x11288, 0x11288,
- 0x1128a, 0x1128d,
- 0x1128f, 0x1129d,
- 0x1129f, 0x112a9,
- 0x112b0, 0x112ea,
- 0x112f0, 0x112f9,
- 0x11300, 0x11303,
- 0x11305, 0x1130c,
- 0x1130f, 0x11310,
- 0x11313, 0x11328,
- 0x1132a, 0x11330,
- 0x11332, 0x11333,
- 0x11335, 0x11339,
- 0x1133b, 0x11344,
- 0x11347, 0x11348,
- 0x1134b, 0x1134d,
- 0x11350, 0x11350,
- 0x11357, 0x11357,
- 0x1135d, 0x11363,
- 0x11366, 0x1136c,
- 0x11370, 0x11374,
- 0x11380, 0x11389,
- 0x1138b, 0x1138b,
- 0x1138e, 0x1138e,
- 0x11390, 0x113b5,
- 0x113b7, 0x113c0,
- 0x113c2, 0x113c2,
- 0x113c5, 0x113c5,
- 0x113c7, 0x113ca,
- 0x113cc, 0x113d5,
- 0x113d7, 0x113d8,
- 0x113e1, 0x113e2,
- 0x11400, 0x1145b,
- 0x1145d, 0x11461,
- 0x11480, 0x114c7,
- 0x114d0, 0x114d9,
- 0x11580, 0x115b5,
- 0x115b8, 0x115dd,
- 0x11600, 0x11644,
- 0x11650, 0x11659,
- 0x11660, 0x1166c,
- 0x11680, 0x116b9,
- 0x116c0, 0x116c9,
- 0x116d0, 0x116e3,
- 0x11700, 0x1171a,
- 0x1171d, 0x1172b,
- 0x11730, 0x11746,
- 0x11800, 0x1183b,
- 0x118a0, 0x118f2,
- 0x118ff, 0x11906,
- 0x11909, 0x11909,
- 0x1190c, 0x11913,
- 0x11915, 0x11916,
- 0x11918, 0x11935,
- 0x11937, 0x11938,
- 0x1193b, 0x11946,
- 0x11950, 0x11959,
- 0x119a0, 0x119a7,
- 0x119aa, 0x119d7,
- 0x119da, 0x119e4,
- 0x11a00, 0x11a47,
- 0x11a50, 0x11aa2,
- 0x11ab0, 0x11af8,
- 0x11b00, 0x11b09,
- 0x11bc0, 0x11be1,
- 0x11bf0, 0x11bf9,
- 0x11c00, 0x11c08,
- 0x11c0a, 0x11c36,
- 0x11c38, 0x11c45,
- 0x11c50, 0x11c6c,
- 0x11c70, 0x11c8f,
- 0x11c92, 0x11ca7,
- 0x11ca9, 0x11cb6,
- 0x11d00, 0x11d06,
- 0x11d08, 0x11d09,
- 0x11d0b, 0x11d36,
- 0x11d3a, 0x11d3a,
- 0x11d3c, 0x11d3d,
- 0x11d3f, 0x11d47,
- 0x11d50, 0x11d59,
- 0x11d60, 0x11d65,
- 0x11d67, 0x11d68,
- 0x11d6a, 0x11d8e,
- 0x11d90, 0x11d91,
- 0x11d93, 0x11d98,
- 0x11da0, 0x11da9,
- 0x11ee0, 0x11ef8,
- 0x11f00, 0x11f10,
- 0x11f12, 0x11f3a,
- 0x11f3e, 0x11f5a,
- 0x11fb0, 0x11fb0,
- 0x11fc0, 0x11ff1,
- 0x11fff, 0x12399,
- 0x12400, 0x1246e,
- 0x12470, 0x12474,
- 0x12480, 0x12543,
- 0x12f90, 0x12ff2,
- 0x13000, 0x13455,
- 0x13460, 0x143fa,
- 0x14400, 0x14646,
- 0x16100, 0x16139,
- 0x16800, 0x16a38,
- 0x16a40, 0x16a5e,
- 0x16a60, 0x16a69,
- 0x16a6e, 0x16abe,
- 0x16ac0, 0x16ac9,
- 0x16ad0, 0x16aed,
- 0x16af0, 0x16af5,
- 0x16b00, 0x16b45,
- 0x16b50, 0x16b59,
- 0x16b5b, 0x16b61,
- 0x16b63, 0x16b77,
- 0x16b7d, 0x16b8f,
- 0x16d40, 0x16d79,
- 0x16e40, 0x16e9a,
- 0x16f00, 0x16f4a,
- 0x16f4f, 0x16f87,
- 0x16f8f, 0x16f9f,
- 0x16fe0, 0x16fe4,
- 0x16ff0, 0x16ff1,
- 0x17000, 0x187f7,
- 0x18800, 0x18cd5,
- 0x18cff, 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,
- 0x1bc9c, 0x1bca3,
- 0x1cc00, 0x1ccf9,
- 0x1cd00, 0x1ceb3,
- 0x1cf00, 0x1cf2d,
- 0x1cf30, 0x1cf46,
- 0x1cf50, 0x1cfc3,
- 0x1d000, 0x1d0f5,
- 0x1d100, 0x1d126,
- 0x1d129, 0x1d1ea,
- 0x1d200, 0x1d245,
- 0x1d2c0, 0x1d2d3,
- 0x1d2e0, 0x1d2f3,
- 0x1d300, 0x1d356,
- 0x1d360, 0x1d378,
- 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, 0x1d7cb,
- 0x1d7ce, 0x1da8b,
- 0x1da9b, 0x1da9f,
- 0x1daa1, 0x1daaf,
- 0x1df00, 0x1df1e,
- 0x1df25, 0x1df2a,
- 0x1e000, 0x1e006,
- 0x1e008, 0x1e018,
- 0x1e01b, 0x1e021,
- 0x1e023, 0x1e024,
- 0x1e026, 0x1e02a,
- 0x1e030, 0x1e06d,
- 0x1e08f, 0x1e08f,
- 0x1e100, 0x1e12c,
- 0x1e130, 0x1e13d,
- 0x1e140, 0x1e149,
- 0x1e14e, 0x1e14f,
- 0x1e290, 0x1e2ae,
- 0x1e2c0, 0x1e2f9,
- 0x1e2ff, 0x1e2ff,
- 0x1e4d0, 0x1e4f9,
- 0x1e5d0, 0x1e5fa,
- 0x1e5ff, 0x1e5ff,
- 0x1e7e0, 0x1e7e6,
- 0x1e7e8, 0x1e7eb,
- 0x1e7ed, 0x1e7ee,
- 0x1e7f0, 0x1e7fe,
- 0x1e800, 0x1e8c4,
- 0x1e8c7, 0x1e8d6,
- 0x1e900, 0x1e94b,
- 0x1e950, 0x1e959,
- 0x1e95e, 0x1e95f,
- 0x1ec71, 0x1ecb4,
- 0x1ed01, 0x1ed3d,
- 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,
- 0x1eef0, 0x1eef1,
- 0x1f000, 0x1f02b,
- 0x1f030, 0x1f093,
- 0x1f0a0, 0x1f0ae,
- 0x1f0b1, 0x1f0bf,
- 0x1f0c1, 0x1f0cf,
- 0x1f0d1, 0x1f0f5,
- 0x1f100, 0x1f1ad,
- 0x1f1e6, 0x1f202,
- 0x1f210, 0x1f23b,
- 0x1f240, 0x1f248,
- 0x1f250, 0x1f251,
- 0x1f260, 0x1f265,
- 0x1f300, 0x1f6d7,
- 0x1f6dc, 0x1f6ec,
- 0x1f6f0, 0x1f6fc,
- 0x1f700, 0x1f776,
- 0x1f77b, 0x1f7d9,
- 0x1f7e0, 0x1f7eb,
- 0x1f7f0, 0x1f7f0,
- 0x1f800, 0x1f80b,
- 0x1f810, 0x1f847,
- 0x1f850, 0x1f859,
- 0x1f860, 0x1f887,
- 0x1f890, 0x1f8ad,
- 0x1f8b0, 0x1f8bb,
- 0x1f8c0, 0x1f8c1,
- 0x1f900, 0x1fa53,
- 0x1fa60, 0x1fa6d,
- 0x1fa70, 0x1fa7c,
- 0x1fa80, 0x1fa89,
- 0x1fa8f, 0x1fac6,
- 0x1face, 0x1fadc,
- 0x1fadf, 0x1fae9,
- 0x1faf0, 0x1faf8,
- 0x1fb00, 0x1fb92,
- 0x1fb94, 0x1fbf9,
- 0x20000, 0x2a6df,
- 0x2a700, 0x2b739,
- 0x2b740, 0x2b81d,
- 0x2b820, 0x2cea1,
- 0x2ceb0, 0x2ebe0,
- 0x2ebf0, 0x2ee5d,
- 0x2f800, 0x2fa1d,
- 0x30000, 0x3134a,
- 0x31350, 0x323af,
- 0xe0001, 0xe0001,
- 0xe0020, 0xe007f,
- 0xe0100, 0xe01ef,
- 0xf0000, 0xffffd,
- 0x100000, 0x10fffd,
-}; /* CR_Graph */
-
-/* 'Lower': [[:Lower:]] */
-static const OnigCodePoint CR_Lower[] = {
- 675,
- 0x0061, 0x007a,
- 0x00aa, 0x00aa,
- 0x00b5, 0x00b5,
- 0x00ba, 0x00ba,
- 0x00df, 0x00f6,
- 0x00f8, 0x00ff,
- 0x0101, 0x0101,
- 0x0103, 0x0103,
- 0x0105, 0x0105,
- 0x0107, 0x0107,
- 0x0109, 0x0109,
- 0x010b, 0x010b,
- 0x010d, 0x010d,
- 0x010f, 0x010f,
- 0x0111, 0x0111,
- 0x0113, 0x0113,
- 0x0115, 0x0115,
- 0x0117, 0x0117,
- 0x0119, 0x0119,
- 0x011b, 0x011b,
- 0x011d, 0x011d,
- 0x011f, 0x011f,
- 0x0121, 0x0121,
- 0x0123, 0x0123,
- 0x0125, 0x0125,
- 0x0127, 0x0127,
- 0x0129, 0x0129,
- 0x012b, 0x012b,
- 0x012d, 0x012d,
- 0x012f, 0x012f,
- 0x0131, 0x0131,
- 0x0133, 0x0133,
- 0x0135, 0x0135,
- 0x0137, 0x0138,
- 0x013a, 0x013a,
- 0x013c, 0x013c,
- 0x013e, 0x013e,
- 0x0140, 0x0140,
- 0x0142, 0x0142,
- 0x0144, 0x0144,
- 0x0146, 0x0146,
- 0x0148, 0x0149,
- 0x014b, 0x014b,
- 0x014d, 0x014d,
- 0x014f, 0x014f,
- 0x0151, 0x0151,
- 0x0153, 0x0153,
- 0x0155, 0x0155,
- 0x0157, 0x0157,
- 0x0159, 0x0159,
- 0x015b, 0x015b,
- 0x015d, 0x015d,
- 0x015f, 0x015f,
- 0x0161, 0x0161,
- 0x0163, 0x0163,
- 0x0165, 0x0165,
- 0x0167, 0x0167,
- 0x0169, 0x0169,
- 0x016b, 0x016b,
- 0x016d, 0x016d,
- 0x016f, 0x016f,
- 0x0171, 0x0171,
- 0x0173, 0x0173,
- 0x0175, 0x0175,
- 0x0177, 0x0177,
- 0x017a, 0x017a,
- 0x017c, 0x017c,
- 0x017e, 0x0180,
- 0x0183, 0x0183,
- 0x0185, 0x0185,
- 0x0188, 0x0188,
- 0x018c, 0x018d,
- 0x0192, 0x0192,
- 0x0195, 0x0195,
- 0x0199, 0x019b,
- 0x019e, 0x019e,
- 0x01a1, 0x01a1,
- 0x01a3, 0x01a3,
- 0x01a5, 0x01a5,
- 0x01a8, 0x01a8,
- 0x01aa, 0x01ab,
- 0x01ad, 0x01ad,
- 0x01b0, 0x01b0,
- 0x01b4, 0x01b4,
- 0x01b6, 0x01b6,
- 0x01b9, 0x01ba,
- 0x01bd, 0x01bf,
- 0x01c6, 0x01c6,
- 0x01c9, 0x01c9,
- 0x01cc, 0x01cc,
- 0x01ce, 0x01ce,
- 0x01d0, 0x01d0,
- 0x01d2, 0x01d2,
- 0x01d4, 0x01d4,
- 0x01d6, 0x01d6,
- 0x01d8, 0x01d8,
- 0x01da, 0x01da,
- 0x01dc, 0x01dd,
- 0x01df, 0x01df,
- 0x01e1, 0x01e1,
- 0x01e3, 0x01e3,
- 0x01e5, 0x01e5,
- 0x01e7, 0x01e7,
- 0x01e9, 0x01e9,
- 0x01eb, 0x01eb,
- 0x01ed, 0x01ed,
- 0x01ef, 0x01f0,
- 0x01f3, 0x01f3,
- 0x01f5, 0x01f5,
- 0x01f9, 0x01f9,
- 0x01fb, 0x01fb,
- 0x01fd, 0x01fd,
- 0x01ff, 0x01ff,
- 0x0201, 0x0201,
- 0x0203, 0x0203,
- 0x0205, 0x0205,
- 0x0207, 0x0207,
- 0x0209, 0x0209,
- 0x020b, 0x020b,
- 0x020d, 0x020d,
- 0x020f, 0x020f,
- 0x0211, 0x0211,
- 0x0213, 0x0213,
- 0x0215, 0x0215,
- 0x0217, 0x0217,
- 0x0219, 0x0219,
- 0x021b, 0x021b,
- 0x021d, 0x021d,
- 0x021f, 0x021f,
- 0x0221, 0x0221,
- 0x0223, 0x0223,
- 0x0225, 0x0225,
- 0x0227, 0x0227,
- 0x0229, 0x0229,
- 0x022b, 0x022b,
- 0x022d, 0x022d,
- 0x022f, 0x022f,
- 0x0231, 0x0231,
- 0x0233, 0x0239,
- 0x023c, 0x023c,
- 0x023f, 0x0240,
- 0x0242, 0x0242,
- 0x0247, 0x0247,
- 0x0249, 0x0249,
- 0x024b, 0x024b,
- 0x024d, 0x024d,
- 0x024f, 0x0293,
- 0x0295, 0x02b8,
- 0x02c0, 0x02c1,
- 0x02e0, 0x02e4,
- 0x0345, 0x0345,
- 0x0371, 0x0371,
- 0x0373, 0x0373,
- 0x0377, 0x0377,
- 0x037a, 0x037d,
- 0x0390, 0x0390,
- 0x03ac, 0x03ce,
- 0x03d0, 0x03d1,
- 0x03d5, 0x03d7,
- 0x03d9, 0x03d9,
- 0x03db, 0x03db,
- 0x03dd, 0x03dd,
- 0x03df, 0x03df,
- 0x03e1, 0x03e1,
- 0x03e3, 0x03e3,
- 0x03e5, 0x03e5,
- 0x03e7, 0x03e7,
- 0x03e9, 0x03e9,
- 0x03eb, 0x03eb,
- 0x03ed, 0x03ed,
- 0x03ef, 0x03f3,
- 0x03f5, 0x03f5,
- 0x03f8, 0x03f8,
- 0x03fb, 0x03fc,
- 0x0430, 0x045f,
- 0x0461, 0x0461,
- 0x0463, 0x0463,
- 0x0465, 0x0465,
- 0x0467, 0x0467,
- 0x0469, 0x0469,
- 0x046b, 0x046b,
- 0x046d, 0x046d,
- 0x046f, 0x046f,
- 0x0471, 0x0471,
- 0x0473, 0x0473,
- 0x0475, 0x0475,
- 0x0477, 0x0477,
- 0x0479, 0x0479,
- 0x047b, 0x047b,
- 0x047d, 0x047d,
- 0x047f, 0x047f,
- 0x0481, 0x0481,
- 0x048b, 0x048b,
- 0x048d, 0x048d,
- 0x048f, 0x048f,
- 0x0491, 0x0491,
- 0x0493, 0x0493,
- 0x0495, 0x0495,
- 0x0497, 0x0497,
- 0x0499, 0x0499,
- 0x049b, 0x049b,
- 0x049d, 0x049d,
- 0x049f, 0x049f,
- 0x04a1, 0x04a1,
- 0x04a3, 0x04a3,
- 0x04a5, 0x04a5,
- 0x04a7, 0x04a7,
- 0x04a9, 0x04a9,
- 0x04ab, 0x04ab,
- 0x04ad, 0x04ad,
- 0x04af, 0x04af,
- 0x04b1, 0x04b1,
- 0x04b3, 0x04b3,
- 0x04b5, 0x04b5,
- 0x04b7, 0x04b7,
- 0x04b9, 0x04b9,
- 0x04bb, 0x04bb,
- 0x04bd, 0x04bd,
- 0x04bf, 0x04bf,
- 0x04c2, 0x04c2,
- 0x04c4, 0x04c4,
- 0x04c6, 0x04c6,
- 0x04c8, 0x04c8,
- 0x04ca, 0x04ca,
- 0x04cc, 0x04cc,
- 0x04ce, 0x04cf,
- 0x04d1, 0x04d1,
- 0x04d3, 0x04d3,
- 0x04d5, 0x04d5,
- 0x04d7, 0x04d7,
- 0x04d9, 0x04d9,
- 0x04db, 0x04db,
- 0x04dd, 0x04dd,
- 0x04df, 0x04df,
- 0x04e1, 0x04e1,
- 0x04e3, 0x04e3,
- 0x04e5, 0x04e5,
- 0x04e7, 0x04e7,
- 0x04e9, 0x04e9,
- 0x04eb, 0x04eb,
- 0x04ed, 0x04ed,
- 0x04ef, 0x04ef,
- 0x04f1, 0x04f1,
- 0x04f3, 0x04f3,
- 0x04f5, 0x04f5,
- 0x04f7, 0x04f7,
- 0x04f9, 0x04f9,
- 0x04fb, 0x04fb,
- 0x04fd, 0x04fd,
- 0x04ff, 0x04ff,
- 0x0501, 0x0501,
- 0x0503, 0x0503,
- 0x0505, 0x0505,
- 0x0507, 0x0507,
- 0x0509, 0x0509,
- 0x050b, 0x050b,
- 0x050d, 0x050d,
- 0x050f, 0x050f,
- 0x0511, 0x0511,
- 0x0513, 0x0513,
- 0x0515, 0x0515,
- 0x0517, 0x0517,
- 0x0519, 0x0519,
- 0x051b, 0x051b,
- 0x051d, 0x051d,
- 0x051f, 0x051f,
- 0x0521, 0x0521,
- 0x0523, 0x0523,
- 0x0525, 0x0525,
- 0x0527, 0x0527,
- 0x0529, 0x0529,
- 0x052b, 0x052b,
- 0x052d, 0x052d,
- 0x052f, 0x052f,
- 0x0560, 0x0588,
- 0x10d0, 0x10fa,
- 0x10fc, 0x10ff,
- 0x13f8, 0x13fd,
- 0x1c80, 0x1c88,
- 0x1c8a, 0x1c8a,
- 0x1d00, 0x1dbf,
- 0x1e01, 0x1e01,
- 0x1e03, 0x1e03,
- 0x1e05, 0x1e05,
- 0x1e07, 0x1e07,
- 0x1e09, 0x1e09,
- 0x1e0b, 0x1e0b,
- 0x1e0d, 0x1e0d,
- 0x1e0f, 0x1e0f,
- 0x1e11, 0x1e11,
- 0x1e13, 0x1e13,
- 0x1e15, 0x1e15,
- 0x1e17, 0x1e17,
- 0x1e19, 0x1e19,
- 0x1e1b, 0x1e1b,
- 0x1e1d, 0x1e1d,
- 0x1e1f, 0x1e1f,
- 0x1e21, 0x1e21,
- 0x1e23, 0x1e23,
- 0x1e25, 0x1e25,
- 0x1e27, 0x1e27,
- 0x1e29, 0x1e29,
- 0x1e2b, 0x1e2b,
- 0x1e2d, 0x1e2d,
- 0x1e2f, 0x1e2f,
- 0x1e31, 0x1e31,
- 0x1e33, 0x1e33,
- 0x1e35, 0x1e35,
- 0x1e37, 0x1e37,
- 0x1e39, 0x1e39,
- 0x1e3b, 0x1e3b,
- 0x1e3d, 0x1e3d,
- 0x1e3f, 0x1e3f,
- 0x1e41, 0x1e41,
- 0x1e43, 0x1e43,
- 0x1e45, 0x1e45,
- 0x1e47, 0x1e47,
- 0x1e49, 0x1e49,
- 0x1e4b, 0x1e4b,
- 0x1e4d, 0x1e4d,
- 0x1e4f, 0x1e4f,
- 0x1e51, 0x1e51,
- 0x1e53, 0x1e53,
- 0x1e55, 0x1e55,
- 0x1e57, 0x1e57,
- 0x1e59, 0x1e59,
- 0x1e5b, 0x1e5b,
- 0x1e5d, 0x1e5d,
- 0x1e5f, 0x1e5f,
- 0x1e61, 0x1e61,
- 0x1e63, 0x1e63,
- 0x1e65, 0x1e65,
- 0x1e67, 0x1e67,
- 0x1e69, 0x1e69,
- 0x1e6b, 0x1e6b,
- 0x1e6d, 0x1e6d,
- 0x1e6f, 0x1e6f,
- 0x1e71, 0x1e71,
- 0x1e73, 0x1e73,
- 0x1e75, 0x1e75,
- 0x1e77, 0x1e77,
- 0x1e79, 0x1e79,
- 0x1e7b, 0x1e7b,
- 0x1e7d, 0x1e7d,
- 0x1e7f, 0x1e7f,
- 0x1e81, 0x1e81,
- 0x1e83, 0x1e83,
- 0x1e85, 0x1e85,
- 0x1e87, 0x1e87,
- 0x1e89, 0x1e89,
- 0x1e8b, 0x1e8b,
- 0x1e8d, 0x1e8d,
- 0x1e8f, 0x1e8f,
- 0x1e91, 0x1e91,
- 0x1e93, 0x1e93,
- 0x1e95, 0x1e9d,
- 0x1e9f, 0x1e9f,
- 0x1ea1, 0x1ea1,
- 0x1ea3, 0x1ea3,
- 0x1ea5, 0x1ea5,
- 0x1ea7, 0x1ea7,
- 0x1ea9, 0x1ea9,
- 0x1eab, 0x1eab,
- 0x1ead, 0x1ead,
- 0x1eaf, 0x1eaf,
- 0x1eb1, 0x1eb1,
- 0x1eb3, 0x1eb3,
- 0x1eb5, 0x1eb5,
- 0x1eb7, 0x1eb7,
- 0x1eb9, 0x1eb9,
- 0x1ebb, 0x1ebb,
- 0x1ebd, 0x1ebd,
- 0x1ebf, 0x1ebf,
- 0x1ec1, 0x1ec1,
- 0x1ec3, 0x1ec3,
- 0x1ec5, 0x1ec5,
- 0x1ec7, 0x1ec7,
- 0x1ec9, 0x1ec9,
- 0x1ecb, 0x1ecb,
- 0x1ecd, 0x1ecd,
- 0x1ecf, 0x1ecf,
- 0x1ed1, 0x1ed1,
- 0x1ed3, 0x1ed3,
- 0x1ed5, 0x1ed5,
- 0x1ed7, 0x1ed7,
- 0x1ed9, 0x1ed9,
- 0x1edb, 0x1edb,
- 0x1edd, 0x1edd,
- 0x1edf, 0x1edf,
- 0x1ee1, 0x1ee1,
- 0x1ee3, 0x1ee3,
- 0x1ee5, 0x1ee5,
- 0x1ee7, 0x1ee7,
- 0x1ee9, 0x1ee9,
- 0x1eeb, 0x1eeb,
- 0x1eed, 0x1eed,
- 0x1eef, 0x1eef,
- 0x1ef1, 0x1ef1,
- 0x1ef3, 0x1ef3,
- 0x1ef5, 0x1ef5,
- 0x1ef7, 0x1ef7,
- 0x1ef9, 0x1ef9,
- 0x1efb, 0x1efb,
- 0x1efd, 0x1efd,
- 0x1eff, 0x1f07,
- 0x1f10, 0x1f15,
- 0x1f20, 0x1f27,
- 0x1f30, 0x1f37,
- 0x1f40, 0x1f45,
- 0x1f50, 0x1f57,
- 0x1f60, 0x1f67,
- 0x1f70, 0x1f7d,
- 0x1f80, 0x1f87,
- 0x1f90, 0x1f97,
- 0x1fa0, 0x1fa7,
- 0x1fb0, 0x1fb4,
- 0x1fb6, 0x1fb7,
- 0x1fbe, 0x1fbe,
- 0x1fc2, 0x1fc4,
- 0x1fc6, 0x1fc7,
- 0x1fd0, 0x1fd3,
- 0x1fd6, 0x1fd7,
- 0x1fe0, 0x1fe7,
- 0x1ff2, 0x1ff4,
- 0x1ff6, 0x1ff7,
- 0x2071, 0x2071,
- 0x207f, 0x207f,
- 0x2090, 0x209c,
- 0x210a, 0x210a,
- 0x210e, 0x210f,
- 0x2113, 0x2113,
- 0x212f, 0x212f,
- 0x2134, 0x2134,
- 0x2139, 0x2139,
- 0x213c, 0x213d,
- 0x2146, 0x2149,
- 0x214e, 0x214e,
- 0x2170, 0x217f,
- 0x2184, 0x2184,
- 0x24d0, 0x24e9,
- 0x2c30, 0x2c5f,
- 0x2c61, 0x2c61,
- 0x2c65, 0x2c66,
- 0x2c68, 0x2c68,
- 0x2c6a, 0x2c6a,
- 0x2c6c, 0x2c6c,
- 0x2c71, 0x2c71,
- 0x2c73, 0x2c74,
- 0x2c76, 0x2c7d,
- 0x2c81, 0x2c81,
- 0x2c83, 0x2c83,
- 0x2c85, 0x2c85,
- 0x2c87, 0x2c87,
- 0x2c89, 0x2c89,
- 0x2c8b, 0x2c8b,
- 0x2c8d, 0x2c8d,
- 0x2c8f, 0x2c8f,
- 0x2c91, 0x2c91,
- 0x2c93, 0x2c93,
- 0x2c95, 0x2c95,
- 0x2c97, 0x2c97,
- 0x2c99, 0x2c99,
- 0x2c9b, 0x2c9b,
- 0x2c9d, 0x2c9d,
- 0x2c9f, 0x2c9f,
- 0x2ca1, 0x2ca1,
- 0x2ca3, 0x2ca3,
- 0x2ca5, 0x2ca5,
- 0x2ca7, 0x2ca7,
- 0x2ca9, 0x2ca9,
- 0x2cab, 0x2cab,
- 0x2cad, 0x2cad,
- 0x2caf, 0x2caf,
- 0x2cb1, 0x2cb1,
- 0x2cb3, 0x2cb3,
- 0x2cb5, 0x2cb5,
- 0x2cb7, 0x2cb7,
- 0x2cb9, 0x2cb9,
- 0x2cbb, 0x2cbb,
- 0x2cbd, 0x2cbd,
- 0x2cbf, 0x2cbf,
- 0x2cc1, 0x2cc1,
- 0x2cc3, 0x2cc3,
- 0x2cc5, 0x2cc5,
- 0x2cc7, 0x2cc7,
- 0x2cc9, 0x2cc9,
- 0x2ccb, 0x2ccb,
- 0x2ccd, 0x2ccd,
- 0x2ccf, 0x2ccf,
- 0x2cd1, 0x2cd1,
- 0x2cd3, 0x2cd3,
- 0x2cd5, 0x2cd5,
- 0x2cd7, 0x2cd7,
- 0x2cd9, 0x2cd9,
- 0x2cdb, 0x2cdb,
- 0x2cdd, 0x2cdd,
- 0x2cdf, 0x2cdf,
- 0x2ce1, 0x2ce1,
- 0x2ce3, 0x2ce4,
- 0x2cec, 0x2cec,
- 0x2cee, 0x2cee,
- 0x2cf3, 0x2cf3,
- 0x2d00, 0x2d25,
- 0x2d27, 0x2d27,
- 0x2d2d, 0x2d2d,
- 0xa641, 0xa641,
- 0xa643, 0xa643,
- 0xa645, 0xa645,
- 0xa647, 0xa647,
- 0xa649, 0xa649,
- 0xa64b, 0xa64b,
- 0xa64d, 0xa64d,
- 0xa64f, 0xa64f,
- 0xa651, 0xa651,
- 0xa653, 0xa653,
- 0xa655, 0xa655,
- 0xa657, 0xa657,
- 0xa659, 0xa659,
- 0xa65b, 0xa65b,
- 0xa65d, 0xa65d,
- 0xa65f, 0xa65f,
- 0xa661, 0xa661,
- 0xa663, 0xa663,
- 0xa665, 0xa665,
- 0xa667, 0xa667,
- 0xa669, 0xa669,
- 0xa66b, 0xa66b,
- 0xa66d, 0xa66d,
- 0xa681, 0xa681,
- 0xa683, 0xa683,
- 0xa685, 0xa685,
- 0xa687, 0xa687,
- 0xa689, 0xa689,
- 0xa68b, 0xa68b,
- 0xa68d, 0xa68d,
- 0xa68f, 0xa68f,
- 0xa691, 0xa691,
- 0xa693, 0xa693,
- 0xa695, 0xa695,
- 0xa697, 0xa697,
- 0xa699, 0xa699,
- 0xa69b, 0xa69d,
- 0xa723, 0xa723,
- 0xa725, 0xa725,
- 0xa727, 0xa727,
- 0xa729, 0xa729,
- 0xa72b, 0xa72b,
- 0xa72d, 0xa72d,
- 0xa72f, 0xa731,
- 0xa733, 0xa733,
- 0xa735, 0xa735,
- 0xa737, 0xa737,
- 0xa739, 0xa739,
- 0xa73b, 0xa73b,
- 0xa73d, 0xa73d,
- 0xa73f, 0xa73f,
- 0xa741, 0xa741,
- 0xa743, 0xa743,
- 0xa745, 0xa745,
- 0xa747, 0xa747,
- 0xa749, 0xa749,
- 0xa74b, 0xa74b,
- 0xa74d, 0xa74d,
- 0xa74f, 0xa74f,
- 0xa751, 0xa751,
- 0xa753, 0xa753,
- 0xa755, 0xa755,
- 0xa757, 0xa757,
- 0xa759, 0xa759,
- 0xa75b, 0xa75b,
- 0xa75d, 0xa75d,
- 0xa75f, 0xa75f,
- 0xa761, 0xa761,
- 0xa763, 0xa763,
- 0xa765, 0xa765,
- 0xa767, 0xa767,
- 0xa769, 0xa769,
- 0xa76b, 0xa76b,
- 0xa76d, 0xa76d,
- 0xa76f, 0xa778,
- 0xa77a, 0xa77a,
- 0xa77c, 0xa77c,
- 0xa77f, 0xa77f,
- 0xa781, 0xa781,
- 0xa783, 0xa783,
- 0xa785, 0xa785,
- 0xa787, 0xa787,
- 0xa78c, 0xa78c,
- 0xa78e, 0xa78e,
- 0xa791, 0xa791,
- 0xa793, 0xa795,
- 0xa797, 0xa797,
- 0xa799, 0xa799,
- 0xa79b, 0xa79b,
- 0xa79d, 0xa79d,
- 0xa79f, 0xa79f,
- 0xa7a1, 0xa7a1,
- 0xa7a3, 0xa7a3,
- 0xa7a5, 0xa7a5,
- 0xa7a7, 0xa7a7,
- 0xa7a9, 0xa7a9,
- 0xa7af, 0xa7af,
- 0xa7b5, 0xa7b5,
- 0xa7b7, 0xa7b7,
- 0xa7b9, 0xa7b9,
- 0xa7bb, 0xa7bb,
- 0xa7bd, 0xa7bd,
- 0xa7bf, 0xa7bf,
- 0xa7c1, 0xa7c1,
- 0xa7c3, 0xa7c3,
- 0xa7c8, 0xa7c8,
- 0xa7ca, 0xa7ca,
- 0xa7cd, 0xa7cd,
- 0xa7d1, 0xa7d1,
- 0xa7d3, 0xa7d3,
- 0xa7d5, 0xa7d5,
- 0xa7d7, 0xa7d7,
- 0xa7d9, 0xa7d9,
- 0xa7db, 0xa7db,
- 0xa7f2, 0xa7f4,
- 0xa7f6, 0xa7f6,
- 0xa7f8, 0xa7fa,
- 0xab30, 0xab5a,
- 0xab5c, 0xab69,
- 0xab70, 0xabbf,
- 0xfb00, 0xfb06,
- 0xfb13, 0xfb17,
- 0xff41, 0xff5a,
- 0x10428, 0x1044f,
- 0x104d8, 0x104fb,
- 0x10597, 0x105a1,
- 0x105a3, 0x105b1,
- 0x105b3, 0x105b9,
- 0x105bb, 0x105bc,
- 0x10780, 0x10780,
- 0x10783, 0x10785,
- 0x10787, 0x107b0,
- 0x107b2, 0x107ba,
- 0x10cc0, 0x10cf2,
- 0x10d70, 0x10d85,
- 0x118c0, 0x118df,
- 0x16e60, 0x16e7f,
- 0x1d41a, 0x1d433,
- 0x1d44e, 0x1d454,
- 0x1d456, 0x1d467,
- 0x1d482, 0x1d49b,
- 0x1d4b6, 0x1d4b9,
- 0x1d4bb, 0x1d4bb,
- 0x1d4bd, 0x1d4c3,
- 0x1d4c5, 0x1d4cf,
- 0x1d4ea, 0x1d503,
- 0x1d51e, 0x1d537,
- 0x1d552, 0x1d56b,
- 0x1d586, 0x1d59f,
- 0x1d5ba, 0x1d5d3,
- 0x1d5ee, 0x1d607,
- 0x1d622, 0x1d63b,
- 0x1d656, 0x1d66f,
- 0x1d68a, 0x1d6a5,
- 0x1d6c2, 0x1d6da,
- 0x1d6dc, 0x1d6e1,
- 0x1d6fc, 0x1d714,
- 0x1d716, 0x1d71b,
- 0x1d736, 0x1d74e,
- 0x1d750, 0x1d755,
- 0x1d770, 0x1d788,
- 0x1d78a, 0x1d78f,
- 0x1d7aa, 0x1d7c2,
- 0x1d7c4, 0x1d7c9,
- 0x1d7cb, 0x1d7cb,
- 0x1df00, 0x1df09,
- 0x1df0b, 0x1df1e,
- 0x1df25, 0x1df2a,
- 0x1e030, 0x1e06d,
- 0x1e922, 0x1e943,
-}; /* CR_Lower */
-
-/* 'Print': [[:Print:]] */
-static const OnigCodePoint CR_Print[] = {
- 733,
- 0x0020, 0x007e,
- 0x00a0, 0x0377,
- 0x037a, 0x037f,
- 0x0384, 0x038a,
- 0x038c, 0x038c,
- 0x038e, 0x03a1,
- 0x03a3, 0x052f,
- 0x0531, 0x0556,
- 0x0559, 0x058a,
- 0x058d, 0x058f,
- 0x0591, 0x05c7,
- 0x05d0, 0x05ea,
- 0x05ef, 0x05f4,
- 0x0600, 0x070d,
- 0x070f, 0x074a,
- 0x074d, 0x07b1,
- 0x07c0, 0x07fa,
- 0x07fd, 0x082d,
- 0x0830, 0x083e,
- 0x0840, 0x085b,
- 0x085e, 0x085e,
- 0x0860, 0x086a,
- 0x0870, 0x088e,
- 0x0890, 0x0891,
- 0x0897, 0x0983,
- 0x0985, 0x098c,
- 0x098f, 0x0990,
- 0x0993, 0x09a8,
- 0x09aa, 0x09b0,
- 0x09b2, 0x09b2,
- 0x09b6, 0x09b9,
- 0x09bc, 0x09c4,
- 0x09c7, 0x09c8,
- 0x09cb, 0x09ce,
- 0x09d7, 0x09d7,
- 0x09dc, 0x09dd,
- 0x09df, 0x09e3,
- 0x09e6, 0x09fe,
- 0x0a01, 0x0a03,
- 0x0a05, 0x0a0a,
- 0x0a0f, 0x0a10,
- 0x0a13, 0x0a28,
- 0x0a2a, 0x0a30,
- 0x0a32, 0x0a33,
- 0x0a35, 0x0a36,
- 0x0a38, 0x0a39,
- 0x0a3c, 0x0a3c,
- 0x0a3e, 0x0a42,
- 0x0a47, 0x0a48,
- 0x0a4b, 0x0a4d,
- 0x0a51, 0x0a51,
- 0x0a59, 0x0a5c,
- 0x0a5e, 0x0a5e,
- 0x0a66, 0x0a76,
- 0x0a81, 0x0a83,
- 0x0a85, 0x0a8d,
- 0x0a8f, 0x0a91,
- 0x0a93, 0x0aa8,
- 0x0aaa, 0x0ab0,
- 0x0ab2, 0x0ab3,
- 0x0ab5, 0x0ab9,
- 0x0abc, 0x0ac5,
- 0x0ac7, 0x0ac9,
- 0x0acb, 0x0acd,
- 0x0ad0, 0x0ad0,
- 0x0ae0, 0x0ae3,
- 0x0ae6, 0x0af1,
- 0x0af9, 0x0aff,
- 0x0b01, 0x0b03,
- 0x0b05, 0x0b0c,
- 0x0b0f, 0x0b10,
- 0x0b13, 0x0b28,
- 0x0b2a, 0x0b30,
- 0x0b32, 0x0b33,
- 0x0b35, 0x0b39,
- 0x0b3c, 0x0b44,
- 0x0b47, 0x0b48,
- 0x0b4b, 0x0b4d,
- 0x0b55, 0x0b57,
- 0x0b5c, 0x0b5d,
- 0x0b5f, 0x0b63,
- 0x0b66, 0x0b77,
- 0x0b82, 0x0b83,
- 0x0b85, 0x0b8a,
- 0x0b8e, 0x0b90,
- 0x0b92, 0x0b95,
- 0x0b99, 0x0b9a,
- 0x0b9c, 0x0b9c,
- 0x0b9e, 0x0b9f,
- 0x0ba3, 0x0ba4,
- 0x0ba8, 0x0baa,
- 0x0bae, 0x0bb9,
- 0x0bbe, 0x0bc2,
- 0x0bc6, 0x0bc8,
- 0x0bca, 0x0bcd,
- 0x0bd0, 0x0bd0,
- 0x0bd7, 0x0bd7,
- 0x0be6, 0x0bfa,
- 0x0c00, 0x0c0c,
- 0x0c0e, 0x0c10,
- 0x0c12, 0x0c28,
- 0x0c2a, 0x0c39,
- 0x0c3c, 0x0c44,
- 0x0c46, 0x0c48,
- 0x0c4a, 0x0c4d,
- 0x0c55, 0x0c56,
- 0x0c58, 0x0c5a,
- 0x0c5d, 0x0c5d,
- 0x0c60, 0x0c63,
- 0x0c66, 0x0c6f,
- 0x0c77, 0x0c8c,
- 0x0c8e, 0x0c90,
- 0x0c92, 0x0ca8,
- 0x0caa, 0x0cb3,
- 0x0cb5, 0x0cb9,
- 0x0cbc, 0x0cc4,
- 0x0cc6, 0x0cc8,
- 0x0cca, 0x0ccd,
- 0x0cd5, 0x0cd6,
- 0x0cdd, 0x0cde,
- 0x0ce0, 0x0ce3,
- 0x0ce6, 0x0cef,
- 0x0cf1, 0x0cf3,
- 0x0d00, 0x0d0c,
- 0x0d0e, 0x0d10,
- 0x0d12, 0x0d44,
- 0x0d46, 0x0d48,
- 0x0d4a, 0x0d4f,
- 0x0d54, 0x0d63,
- 0x0d66, 0x0d7f,
- 0x0d81, 0x0d83,
- 0x0d85, 0x0d96,
- 0x0d9a, 0x0db1,
- 0x0db3, 0x0dbb,
- 0x0dbd, 0x0dbd,
- 0x0dc0, 0x0dc6,
- 0x0dca, 0x0dca,
- 0x0dcf, 0x0dd4,
- 0x0dd6, 0x0dd6,
- 0x0dd8, 0x0ddf,
- 0x0de6, 0x0def,
- 0x0df2, 0x0df4,
- 0x0e01, 0x0e3a,
- 0x0e3f, 0x0e5b,
- 0x0e81, 0x0e82,
- 0x0e84, 0x0e84,
- 0x0e86, 0x0e8a,
- 0x0e8c, 0x0ea3,
- 0x0ea5, 0x0ea5,
- 0x0ea7, 0x0ebd,
- 0x0ec0, 0x0ec4,
- 0x0ec6, 0x0ec6,
- 0x0ec8, 0x0ece,
- 0x0ed0, 0x0ed9,
- 0x0edc, 0x0edf,
- 0x0f00, 0x0f47,
- 0x0f49, 0x0f6c,
- 0x0f71, 0x0f97,
- 0x0f99, 0x0fbc,
- 0x0fbe, 0x0fcc,
- 0x0fce, 0x0fda,
- 0x1000, 0x10c5,
- 0x10c7, 0x10c7,
- 0x10cd, 0x10cd,
- 0x10d0, 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,
- 0x135d, 0x137c,
- 0x1380, 0x1399,
- 0x13a0, 0x13f5,
- 0x13f8, 0x13fd,
- 0x1400, 0x169c,
- 0x16a0, 0x16f8,
- 0x1700, 0x1715,
- 0x171f, 0x1736,
- 0x1740, 0x1753,
- 0x1760, 0x176c,
- 0x176e, 0x1770,
- 0x1772, 0x1773,
- 0x1780, 0x17dd,
- 0x17e0, 0x17e9,
- 0x17f0, 0x17f9,
- 0x1800, 0x1819,
- 0x1820, 0x1878,
- 0x1880, 0x18aa,
- 0x18b0, 0x18f5,
- 0x1900, 0x191e,
- 0x1920, 0x192b,
- 0x1930, 0x193b,
- 0x1940, 0x1940,
- 0x1944, 0x196d,
- 0x1970, 0x1974,
- 0x1980, 0x19ab,
- 0x19b0, 0x19c9,
- 0x19d0, 0x19da,
- 0x19de, 0x1a1b,
- 0x1a1e, 0x1a5e,
- 0x1a60, 0x1a7c,
- 0x1a7f, 0x1a89,
- 0x1a90, 0x1a99,
- 0x1aa0, 0x1aad,
- 0x1ab0, 0x1ace,
- 0x1b00, 0x1b4c,
- 0x1b4e, 0x1bf3,
- 0x1bfc, 0x1c37,
- 0x1c3b, 0x1c49,
- 0x1c4d, 0x1c8a,
- 0x1c90, 0x1cba,
- 0x1cbd, 0x1cc7,
- 0x1cd0, 0x1cfa,
- 0x1d00, 0x1f15,
- 0x1f18, 0x1f1d,
- 0x1f20, 0x1f45,
- 0x1f48, 0x1f4d,
- 0x1f50, 0x1f57,
- 0x1f59, 0x1f59,
- 0x1f5b, 0x1f5b,
- 0x1f5d, 0x1f5d,
- 0x1f5f, 0x1f7d,
- 0x1f80, 0x1fb4,
- 0x1fb6, 0x1fc4,
- 0x1fc6, 0x1fd3,
- 0x1fd6, 0x1fdb,
- 0x1fdd, 0x1fef,
- 0x1ff2, 0x1ff4,
- 0x1ff6, 0x1ffe,
- 0x2000, 0x2027,
- 0x202a, 0x2064,
- 0x2066, 0x2071,
- 0x2074, 0x208e,
- 0x2090, 0x209c,
- 0x20a0, 0x20c0,
- 0x20d0, 0x20f0,
- 0x2100, 0x218b,
- 0x2190, 0x2429,
- 0x2440, 0x244a,
- 0x2460, 0x2b73,
- 0x2b76, 0x2b95,
- 0x2b97, 0x2cf3,
- 0x2cf9, 0x2d25,
- 0x2d27, 0x2d27,
- 0x2d2d, 0x2d2d,
- 0x2d30, 0x2d67,
- 0x2d6f, 0x2d70,
- 0x2d7f, 0x2d96,
- 0x2da0, 0x2da6,
- 0x2da8, 0x2dae,
- 0x2db0, 0x2db6,
- 0x2db8, 0x2dbe,
- 0x2dc0, 0x2dc6,
- 0x2dc8, 0x2dce,
- 0x2dd0, 0x2dd6,
- 0x2dd8, 0x2dde,
- 0x2de0, 0x2e5d,
- 0x2e80, 0x2e99,
- 0x2e9b, 0x2ef3,
- 0x2f00, 0x2fd5,
- 0x2ff0, 0x303f,
- 0x3041, 0x3096,
- 0x3099, 0x30ff,
- 0x3105, 0x312f,
- 0x3131, 0x318e,
- 0x3190, 0x31e5,
- 0x31ef, 0x321e,
- 0x3220, 0xa48c,
- 0xa490, 0xa4c6,
- 0xa4d0, 0xa62b,
- 0xa640, 0xa6f7,
- 0xa700, 0xa7cd,
- 0xa7d0, 0xa7d1,
- 0xa7d3, 0xa7d3,
- 0xa7d5, 0xa7dc,
- 0xa7f2, 0xa82c,
- 0xa830, 0xa839,
- 0xa840, 0xa877,
- 0xa880, 0xa8c5,
- 0xa8ce, 0xa8d9,
- 0xa8e0, 0xa953,
- 0xa95f, 0xa97c,
- 0xa980, 0xa9cd,
- 0xa9cf, 0xa9d9,
- 0xa9de, 0xa9fe,
- 0xaa00, 0xaa36,
- 0xaa40, 0xaa4d,
- 0xaa50, 0xaa59,
- 0xaa5c, 0xaac2,
- 0xaadb, 0xaaf6,
- 0xab01, 0xab06,
- 0xab09, 0xab0e,
- 0xab11, 0xab16,
- 0xab20, 0xab26,
- 0xab28, 0xab2e,
- 0xab30, 0xab6b,
- 0xab70, 0xabed,
- 0xabf0, 0xabf9,
- 0xac00, 0xd7a3,
- 0xd7b0, 0xd7c6,
- 0xd7cb, 0xd7fb,
- 0xe000, 0xfa6d,
- 0xfa70, 0xfad9,
- 0xfb00, 0xfb06,
- 0xfb13, 0xfb17,
- 0xfb1d, 0xfb36,
- 0xfb38, 0xfb3c,
- 0xfb3e, 0xfb3e,
- 0xfb40, 0xfb41,
- 0xfb43, 0xfb44,
- 0xfb46, 0xfbc2,
- 0xfbd3, 0xfd8f,
- 0xfd92, 0xfdc7,
- 0xfdcf, 0xfdcf,
- 0xfdf0, 0xfe19,
- 0xfe20, 0xfe52,
- 0xfe54, 0xfe66,
- 0xfe68, 0xfe6b,
- 0xfe70, 0xfe74,
- 0xfe76, 0xfefc,
- 0xfeff, 0xfeff,
- 0xff01, 0xffbe,
- 0xffc2, 0xffc7,
- 0xffca, 0xffcf,
- 0xffd2, 0xffd7,
- 0xffda, 0xffdc,
- 0xffe0, 0xffe6,
- 0xffe8, 0xffee,
- 0xfff9, 0xfffd,
- 0x10000, 0x1000b,
- 0x1000d, 0x10026,
- 0x10028, 0x1003a,
- 0x1003c, 0x1003d,
- 0x1003f, 0x1004d,
- 0x10050, 0x1005d,
- 0x10080, 0x100fa,
- 0x10100, 0x10102,
- 0x10107, 0x10133,
- 0x10137, 0x1018e,
- 0x10190, 0x1019c,
- 0x101a0, 0x101a0,
- 0x101d0, 0x101fd,
- 0x10280, 0x1029c,
- 0x102a0, 0x102d0,
- 0x102e0, 0x102fb,
- 0x10300, 0x10323,
- 0x1032d, 0x1034a,
- 0x10350, 0x1037a,
- 0x10380, 0x1039d,
- 0x1039f, 0x103c3,
- 0x103c8, 0x103d5,
- 0x10400, 0x1049d,
- 0x104a0, 0x104a9,
- 0x104b0, 0x104d3,
- 0x104d8, 0x104fb,
- 0x10500, 0x10527,
- 0x10530, 0x10563,
- 0x1056f, 0x1057a,
- 0x1057c, 0x1058a,
- 0x1058c, 0x10592,
- 0x10594, 0x10595,
- 0x10597, 0x105a1,
- 0x105a3, 0x105b1,
- 0x105b3, 0x105b9,
- 0x105bb, 0x105bc,
- 0x105c0, 0x105f3,
- 0x10600, 0x10736,
- 0x10740, 0x10755,
- 0x10760, 0x10767,
- 0x10780, 0x10785,
- 0x10787, 0x107b0,
- 0x107b2, 0x107ba,
- 0x10800, 0x10805,
- 0x10808, 0x10808,
- 0x1080a, 0x10835,
- 0x10837, 0x10838,
- 0x1083c, 0x1083c,
- 0x1083f, 0x10855,
- 0x10857, 0x1089e,
- 0x108a7, 0x108af,
- 0x108e0, 0x108f2,
- 0x108f4, 0x108f5,
- 0x108fb, 0x1091b,
- 0x1091f, 0x10939,
- 0x1093f, 0x1093f,
- 0x10980, 0x109b7,
- 0x109bc, 0x109cf,
- 0x109d2, 0x10a03,
- 0x10a05, 0x10a06,
- 0x10a0c, 0x10a13,
- 0x10a15, 0x10a17,
- 0x10a19, 0x10a35,
- 0x10a38, 0x10a3a,
- 0x10a3f, 0x10a48,
- 0x10a50, 0x10a58,
- 0x10a60, 0x10a9f,
- 0x10ac0, 0x10ae6,
- 0x10aeb, 0x10af6,
- 0x10b00, 0x10b35,
- 0x10b39, 0x10b55,
- 0x10b58, 0x10b72,
- 0x10b78, 0x10b91,
- 0x10b99, 0x10b9c,
- 0x10ba9, 0x10baf,
- 0x10c00, 0x10c48,
- 0x10c80, 0x10cb2,
- 0x10cc0, 0x10cf2,
- 0x10cfa, 0x10d27,
- 0x10d30, 0x10d39,
- 0x10d40, 0x10d65,
- 0x10d69, 0x10d85,
- 0x10d8e, 0x10d8f,
- 0x10e60, 0x10e7e,
- 0x10e80, 0x10ea9,
- 0x10eab, 0x10ead,
- 0x10eb0, 0x10eb1,
- 0x10ec2, 0x10ec4,
- 0x10efc, 0x10f27,
- 0x10f30, 0x10f59,
- 0x10f70, 0x10f89,
- 0x10fb0, 0x10fcb,
- 0x10fe0, 0x10ff6,
- 0x11000, 0x1104d,
- 0x11052, 0x11075,
- 0x1107f, 0x110c2,
- 0x110cd, 0x110cd,
- 0x110d0, 0x110e8,
- 0x110f0, 0x110f9,
- 0x11100, 0x11134,
- 0x11136, 0x11147,
- 0x11150, 0x11176,
- 0x11180, 0x111df,
- 0x111e1, 0x111f4,
- 0x11200, 0x11211,
- 0x11213, 0x11241,
- 0x11280, 0x11286,
- 0x11288, 0x11288,
- 0x1128a, 0x1128d,
- 0x1128f, 0x1129d,
- 0x1129f, 0x112a9,
- 0x112b0, 0x112ea,
- 0x112f0, 0x112f9,
- 0x11300, 0x11303,
- 0x11305, 0x1130c,
- 0x1130f, 0x11310,
- 0x11313, 0x11328,
- 0x1132a, 0x11330,
- 0x11332, 0x11333,
- 0x11335, 0x11339,
- 0x1133b, 0x11344,
- 0x11347, 0x11348,
- 0x1134b, 0x1134d,
- 0x11350, 0x11350,
- 0x11357, 0x11357,
- 0x1135d, 0x11363,
- 0x11366, 0x1136c,
- 0x11370, 0x11374,
- 0x11380, 0x11389,
- 0x1138b, 0x1138b,
- 0x1138e, 0x1138e,
- 0x11390, 0x113b5,
- 0x113b7, 0x113c0,
- 0x113c2, 0x113c2,
- 0x113c5, 0x113c5,
- 0x113c7, 0x113ca,
- 0x113cc, 0x113d5,
- 0x113d7, 0x113d8,
- 0x113e1, 0x113e2,
- 0x11400, 0x1145b,
- 0x1145d, 0x11461,
- 0x11480, 0x114c7,
- 0x114d0, 0x114d9,
- 0x11580, 0x115b5,
- 0x115b8, 0x115dd,
- 0x11600, 0x11644,
- 0x11650, 0x11659,
- 0x11660, 0x1166c,
- 0x11680, 0x116b9,
- 0x116c0, 0x116c9,
- 0x116d0, 0x116e3,
- 0x11700, 0x1171a,
- 0x1171d, 0x1172b,
- 0x11730, 0x11746,
- 0x11800, 0x1183b,
- 0x118a0, 0x118f2,
- 0x118ff, 0x11906,
- 0x11909, 0x11909,
- 0x1190c, 0x11913,
- 0x11915, 0x11916,
- 0x11918, 0x11935,
- 0x11937, 0x11938,
- 0x1193b, 0x11946,
- 0x11950, 0x11959,
- 0x119a0, 0x119a7,
- 0x119aa, 0x119d7,
- 0x119da, 0x119e4,
- 0x11a00, 0x11a47,
- 0x11a50, 0x11aa2,
- 0x11ab0, 0x11af8,
- 0x11b00, 0x11b09,
- 0x11bc0, 0x11be1,
- 0x11bf0, 0x11bf9,
- 0x11c00, 0x11c08,
- 0x11c0a, 0x11c36,
- 0x11c38, 0x11c45,
- 0x11c50, 0x11c6c,
- 0x11c70, 0x11c8f,
- 0x11c92, 0x11ca7,
- 0x11ca9, 0x11cb6,
- 0x11d00, 0x11d06,
- 0x11d08, 0x11d09,
- 0x11d0b, 0x11d36,
- 0x11d3a, 0x11d3a,
- 0x11d3c, 0x11d3d,
- 0x11d3f, 0x11d47,
- 0x11d50, 0x11d59,
- 0x11d60, 0x11d65,
- 0x11d67, 0x11d68,
- 0x11d6a, 0x11d8e,
- 0x11d90, 0x11d91,
- 0x11d93, 0x11d98,
- 0x11da0, 0x11da9,
- 0x11ee0, 0x11ef8,
- 0x11f00, 0x11f10,
- 0x11f12, 0x11f3a,
- 0x11f3e, 0x11f5a,
- 0x11fb0, 0x11fb0,
- 0x11fc0, 0x11ff1,
- 0x11fff, 0x12399,
- 0x12400, 0x1246e,
- 0x12470, 0x12474,
- 0x12480, 0x12543,
- 0x12f90, 0x12ff2,
- 0x13000, 0x13455,
- 0x13460, 0x143fa,
- 0x14400, 0x14646,
- 0x16100, 0x16139,
- 0x16800, 0x16a38,
- 0x16a40, 0x16a5e,
- 0x16a60, 0x16a69,
- 0x16a6e, 0x16abe,
- 0x16ac0, 0x16ac9,
- 0x16ad0, 0x16aed,
- 0x16af0, 0x16af5,
- 0x16b00, 0x16b45,
- 0x16b50, 0x16b59,
- 0x16b5b, 0x16b61,
- 0x16b63, 0x16b77,
- 0x16b7d, 0x16b8f,
- 0x16d40, 0x16d79,
- 0x16e40, 0x16e9a,
- 0x16f00, 0x16f4a,
- 0x16f4f, 0x16f87,
- 0x16f8f, 0x16f9f,
- 0x16fe0, 0x16fe4,
- 0x16ff0, 0x16ff1,
- 0x17000, 0x187f7,
- 0x18800, 0x18cd5,
- 0x18cff, 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,
- 0x1bc9c, 0x1bca3,
- 0x1cc00, 0x1ccf9,
- 0x1cd00, 0x1ceb3,
- 0x1cf00, 0x1cf2d,
- 0x1cf30, 0x1cf46,
- 0x1cf50, 0x1cfc3,
- 0x1d000, 0x1d0f5,
- 0x1d100, 0x1d126,
- 0x1d129, 0x1d1ea,
- 0x1d200, 0x1d245,
- 0x1d2c0, 0x1d2d3,
- 0x1d2e0, 0x1d2f3,
- 0x1d300, 0x1d356,
- 0x1d360, 0x1d378,
- 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, 0x1d7cb,
- 0x1d7ce, 0x1da8b,
- 0x1da9b, 0x1da9f,
- 0x1daa1, 0x1daaf,
- 0x1df00, 0x1df1e,
- 0x1df25, 0x1df2a,
- 0x1e000, 0x1e006,
- 0x1e008, 0x1e018,
- 0x1e01b, 0x1e021,
- 0x1e023, 0x1e024,
- 0x1e026, 0x1e02a,
- 0x1e030, 0x1e06d,
- 0x1e08f, 0x1e08f,
- 0x1e100, 0x1e12c,
- 0x1e130, 0x1e13d,
- 0x1e140, 0x1e149,
- 0x1e14e, 0x1e14f,
- 0x1e290, 0x1e2ae,
- 0x1e2c0, 0x1e2f9,
- 0x1e2ff, 0x1e2ff,
- 0x1e4d0, 0x1e4f9,
- 0x1e5d0, 0x1e5fa,
- 0x1e5ff, 0x1e5ff,
- 0x1e7e0, 0x1e7e6,
- 0x1e7e8, 0x1e7eb,
- 0x1e7ed, 0x1e7ee,
- 0x1e7f0, 0x1e7fe,
- 0x1e800, 0x1e8c4,
- 0x1e8c7, 0x1e8d6,
- 0x1e900, 0x1e94b,
- 0x1e950, 0x1e959,
- 0x1e95e, 0x1e95f,
- 0x1ec71, 0x1ecb4,
- 0x1ed01, 0x1ed3d,
- 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,
- 0x1eef0, 0x1eef1,
- 0x1f000, 0x1f02b,
- 0x1f030, 0x1f093,
- 0x1f0a0, 0x1f0ae,
- 0x1f0b1, 0x1f0bf,
- 0x1f0c1, 0x1f0cf,
- 0x1f0d1, 0x1f0f5,
- 0x1f100, 0x1f1ad,
- 0x1f1e6, 0x1f202,
- 0x1f210, 0x1f23b,
- 0x1f240, 0x1f248,
- 0x1f250, 0x1f251,
- 0x1f260, 0x1f265,
- 0x1f300, 0x1f6d7,
- 0x1f6dc, 0x1f6ec,
- 0x1f6f0, 0x1f6fc,
- 0x1f700, 0x1f776,
- 0x1f77b, 0x1f7d9,
- 0x1f7e0, 0x1f7eb,
- 0x1f7f0, 0x1f7f0,
- 0x1f800, 0x1f80b,
- 0x1f810, 0x1f847,
- 0x1f850, 0x1f859,
- 0x1f860, 0x1f887,
- 0x1f890, 0x1f8ad,
- 0x1f8b0, 0x1f8bb,
- 0x1f8c0, 0x1f8c1,
- 0x1f900, 0x1fa53,
- 0x1fa60, 0x1fa6d,
- 0x1fa70, 0x1fa7c,
- 0x1fa80, 0x1fa89,
- 0x1fa8f, 0x1fac6,
- 0x1face, 0x1fadc,
- 0x1fadf, 0x1fae9,
- 0x1faf0, 0x1faf8,
- 0x1fb00, 0x1fb92,
- 0x1fb94, 0x1fbf9,
- 0x20000, 0x2a6df,
- 0x2a700, 0x2b739,
- 0x2b740, 0x2b81d,
- 0x2b820, 0x2cea1,
- 0x2ceb0, 0x2ebe0,
- 0x2ebf0, 0x2ee5d,
- 0x2f800, 0x2fa1d,
- 0x30000, 0x3134a,
- 0x31350, 0x323af,
- 0xe0001, 0xe0001,
- 0xe0020, 0xe007f,
- 0xe0100, 0xe01ef,
- 0xf0000, 0xffffd,
- 0x100000, 0x10fffd,
-}; /* CR_Print */
-
-/* 'XPosixPunct': [[:Punct:]] */
-static const OnigCodePoint CR_XPosixPunct[] = {
- 193,
- 0x0021, 0x002f,
- 0x003a, 0x0040,
- 0x005b, 0x0060,
- 0x007b, 0x007e,
- 0x00a1, 0x00a1,
- 0x00a7, 0x00a7,
- 0x00ab, 0x00ab,
- 0x00b6, 0x00b7,
- 0x00bb, 0x00bb,
- 0x00bf, 0x00bf,
- 0x037e, 0x037e,
- 0x0387, 0x0387,
- 0x055a, 0x055f,
- 0x0589, 0x058a,
- 0x05be, 0x05be,
- 0x05c0, 0x05c0,
- 0x05c3, 0x05c3,
- 0x05c6, 0x05c6,
- 0x05f3, 0x05f4,
- 0x0609, 0x060a,
- 0x060c, 0x060d,
- 0x061b, 0x061b,
- 0x061d, 0x061f,
- 0x066a, 0x066d,
- 0x06d4, 0x06d4,
- 0x0700, 0x070d,
- 0x07f7, 0x07f9,
- 0x0830, 0x083e,
- 0x085e, 0x085e,
- 0x0964, 0x0965,
- 0x0970, 0x0970,
- 0x09fd, 0x09fd,
- 0x0a76, 0x0a76,
- 0x0af0, 0x0af0,
- 0x0c77, 0x0c77,
- 0x0c84, 0x0c84,
- 0x0df4, 0x0df4,
- 0x0e4f, 0x0e4f,
- 0x0e5a, 0x0e5b,
- 0x0f04, 0x0f12,
- 0x0f14, 0x0f14,
- 0x0f3a, 0x0f3d,
- 0x0f85, 0x0f85,
- 0x0fd0, 0x0fd4,
- 0x0fd9, 0x0fda,
- 0x104a, 0x104f,
- 0x10fb, 0x10fb,
- 0x1360, 0x1368,
- 0x1400, 0x1400,
- 0x166e, 0x166e,
- 0x169b, 0x169c,
- 0x16eb, 0x16ed,
- 0x1735, 0x1736,
- 0x17d4, 0x17d6,
- 0x17d8, 0x17da,
- 0x1800, 0x180a,
- 0x1944, 0x1945,
- 0x1a1e, 0x1a1f,
- 0x1aa0, 0x1aa6,
- 0x1aa8, 0x1aad,
- 0x1b4e, 0x1b4f,
- 0x1b5a, 0x1b60,
- 0x1b7d, 0x1b7f,
- 0x1bfc, 0x1bff,
- 0x1c3b, 0x1c3f,
- 0x1c7e, 0x1c7f,
- 0x1cc0, 0x1cc7,
- 0x1cd3, 0x1cd3,
- 0x2010, 0x2027,
- 0x2030, 0x2043,
- 0x2045, 0x2051,
- 0x2053, 0x205e,
- 0x207d, 0x207e,
- 0x208d, 0x208e,
- 0x2308, 0x230b,
- 0x2329, 0x232a,
- 0x2768, 0x2775,
- 0x27c5, 0x27c6,
- 0x27e6, 0x27ef,
- 0x2983, 0x2998,
- 0x29d8, 0x29db,
- 0x29fc, 0x29fd,
- 0x2cf9, 0x2cfc,
- 0x2cfe, 0x2cff,
- 0x2d70, 0x2d70,
- 0x2e00, 0x2e2e,
- 0x2e30, 0x2e4f,
- 0x2e52, 0x2e5d,
- 0x3001, 0x3003,
- 0x3008, 0x3011,
- 0x3014, 0x301f,
- 0x3030, 0x3030,
- 0x303d, 0x303d,
- 0x30a0, 0x30a0,
- 0x30fb, 0x30fb,
- 0xa4fe, 0xa4ff,
- 0xa60d, 0xa60f,
- 0xa673, 0xa673,
- 0xa67e, 0xa67e,
- 0xa6f2, 0xa6f7,
- 0xa874, 0xa877,
- 0xa8ce, 0xa8cf,
- 0xa8f8, 0xa8fa,
- 0xa8fc, 0xa8fc,
- 0xa92e, 0xa92f,
- 0xa95f, 0xa95f,
- 0xa9c1, 0xa9cd,
- 0xa9de, 0xa9df,
- 0xaa5c, 0xaa5f,
- 0xaade, 0xaadf,
- 0xaaf0, 0xaaf1,
- 0xabeb, 0xabeb,
- 0xfd3e, 0xfd3f,
- 0xfe10, 0xfe19,
- 0xfe30, 0xfe52,
- 0xfe54, 0xfe61,
- 0xfe63, 0xfe63,
- 0xfe68, 0xfe68,
- 0xfe6a, 0xfe6b,
- 0xff01, 0xff03,
- 0xff05, 0xff0a,
- 0xff0c, 0xff0f,
- 0xff1a, 0xff1b,
- 0xff1f, 0xff20,
- 0xff3b, 0xff3d,
- 0xff3f, 0xff3f,
- 0xff5b, 0xff5b,
- 0xff5d, 0xff5d,
- 0xff5f, 0xff65,
- 0x10100, 0x10102,
- 0x1039f, 0x1039f,
- 0x103d0, 0x103d0,
- 0x1056f, 0x1056f,
- 0x10857, 0x10857,
- 0x1091f, 0x1091f,
- 0x1093f, 0x1093f,
- 0x10a50, 0x10a58,
- 0x10a7f, 0x10a7f,
- 0x10af0, 0x10af6,
- 0x10b39, 0x10b3f,
- 0x10b99, 0x10b9c,
- 0x10d6e, 0x10d6e,
- 0x10ead, 0x10ead,
- 0x10f55, 0x10f59,
- 0x10f86, 0x10f89,
- 0x11047, 0x1104d,
- 0x110bb, 0x110bc,
- 0x110be, 0x110c1,
- 0x11140, 0x11143,
- 0x11174, 0x11175,
- 0x111c5, 0x111c8,
- 0x111cd, 0x111cd,
- 0x111db, 0x111db,
- 0x111dd, 0x111df,
- 0x11238, 0x1123d,
- 0x112a9, 0x112a9,
- 0x113d4, 0x113d5,
- 0x113d7, 0x113d8,
- 0x1144b, 0x1144f,
- 0x1145a, 0x1145b,
- 0x1145d, 0x1145d,
- 0x114c6, 0x114c6,
- 0x115c1, 0x115d7,
- 0x11641, 0x11643,
- 0x11660, 0x1166c,
- 0x116b9, 0x116b9,
- 0x1173c, 0x1173e,
- 0x1183b, 0x1183b,
- 0x11944, 0x11946,
- 0x119e2, 0x119e2,
- 0x11a3f, 0x11a46,
- 0x11a9a, 0x11a9c,
- 0x11a9e, 0x11aa2,
- 0x11b00, 0x11b09,
- 0x11be1, 0x11be1,
- 0x11c41, 0x11c45,
- 0x11c70, 0x11c71,
- 0x11ef7, 0x11ef8,
- 0x11f43, 0x11f4f,
- 0x11fff, 0x11fff,
- 0x12470, 0x12474,
- 0x12ff1, 0x12ff2,
- 0x16a6e, 0x16a6f,
- 0x16af5, 0x16af5,
- 0x16b37, 0x16b3b,
- 0x16b44, 0x16b44,
- 0x16d6d, 0x16d6f,
- 0x16e97, 0x16e9a,
- 0x16fe2, 0x16fe2,
- 0x1bc9f, 0x1bc9f,
- 0x1da87, 0x1da8b,
- 0x1e5ff, 0x1e5ff,
- 0x1e95e, 0x1e95f,
-}; /* CR_XPosixPunct */
-
-/* 'Space': [[:Space:]] */
-static const OnigCodePoint CR_Space[] = {
- 10,
- 0x0009, 0x000d,
- 0x0020, 0x0020,
- 0x0085, 0x0085,
- 0x00a0, 0x00a0,
- 0x1680, 0x1680,
- 0x2000, 0x200a,
- 0x2028, 0x2029,
- 0x202f, 0x202f,
- 0x205f, 0x205f,
- 0x3000, 0x3000,
-}; /* CR_Space */
-
-/* 'Upper': [[:Upper:]] */
-static const OnigCodePoint CR_Upper[] = {
- 656,
- 0x0041, 0x005a,
- 0x00c0, 0x00d6,
- 0x00d8, 0x00de,
- 0x0100, 0x0100,
- 0x0102, 0x0102,
- 0x0104, 0x0104,
- 0x0106, 0x0106,
- 0x0108, 0x0108,
- 0x010a, 0x010a,
- 0x010c, 0x010c,
- 0x010e, 0x010e,
- 0x0110, 0x0110,
- 0x0112, 0x0112,
- 0x0114, 0x0114,
- 0x0116, 0x0116,
- 0x0118, 0x0118,
- 0x011a, 0x011a,
- 0x011c, 0x011c,
- 0x011e, 0x011e,
- 0x0120, 0x0120,
- 0x0122, 0x0122,
- 0x0124, 0x0124,
- 0x0126, 0x0126,
- 0x0128, 0x0128,
- 0x012a, 0x012a,
- 0x012c, 0x012c,
- 0x012e, 0x012e,
- 0x0130, 0x0130,
- 0x0132, 0x0132,
- 0x0134, 0x0134,
- 0x0136, 0x0136,
- 0x0139, 0x0139,
- 0x013b, 0x013b,
- 0x013d, 0x013d,
- 0x013f, 0x013f,
- 0x0141, 0x0141,
- 0x0143, 0x0143,
- 0x0145, 0x0145,
- 0x0147, 0x0147,
- 0x014a, 0x014a,
- 0x014c, 0x014c,
- 0x014e, 0x014e,
- 0x0150, 0x0150,
- 0x0152, 0x0152,
- 0x0154, 0x0154,
- 0x0156, 0x0156,
- 0x0158, 0x0158,
- 0x015a, 0x015a,
- 0x015c, 0x015c,
- 0x015e, 0x015e,
- 0x0160, 0x0160,
- 0x0162, 0x0162,
- 0x0164, 0x0164,
- 0x0166, 0x0166,
- 0x0168, 0x0168,
- 0x016a, 0x016a,
- 0x016c, 0x016c,
- 0x016e, 0x016e,
- 0x0170, 0x0170,
- 0x0172, 0x0172,
- 0x0174, 0x0174,
- 0x0176, 0x0176,
- 0x0178, 0x0179,
- 0x017b, 0x017b,
- 0x017d, 0x017d,
- 0x0181, 0x0182,
- 0x0184, 0x0184,
- 0x0186, 0x0187,
- 0x0189, 0x018b,
- 0x018e, 0x0191,
- 0x0193, 0x0194,
- 0x0196, 0x0198,
- 0x019c, 0x019d,
- 0x019f, 0x01a0,
- 0x01a2, 0x01a2,
- 0x01a4, 0x01a4,
- 0x01a6, 0x01a7,
- 0x01a9, 0x01a9,
- 0x01ac, 0x01ac,
- 0x01ae, 0x01af,
- 0x01b1, 0x01b3,
- 0x01b5, 0x01b5,
- 0x01b7, 0x01b8,
- 0x01bc, 0x01bc,
- 0x01c4, 0x01c4,
- 0x01c7, 0x01c7,
- 0x01ca, 0x01ca,
- 0x01cd, 0x01cd,
- 0x01cf, 0x01cf,
- 0x01d1, 0x01d1,
- 0x01d3, 0x01d3,
- 0x01d5, 0x01d5,
- 0x01d7, 0x01d7,
- 0x01d9, 0x01d9,
- 0x01db, 0x01db,
- 0x01de, 0x01de,
- 0x01e0, 0x01e0,
- 0x01e2, 0x01e2,
- 0x01e4, 0x01e4,
- 0x01e6, 0x01e6,
- 0x01e8, 0x01e8,
- 0x01ea, 0x01ea,
- 0x01ec, 0x01ec,
- 0x01ee, 0x01ee,
- 0x01f1, 0x01f1,
- 0x01f4, 0x01f4,
- 0x01f6, 0x01f8,
- 0x01fa, 0x01fa,
- 0x01fc, 0x01fc,
- 0x01fe, 0x01fe,
- 0x0200, 0x0200,
- 0x0202, 0x0202,
- 0x0204, 0x0204,
- 0x0206, 0x0206,
- 0x0208, 0x0208,
- 0x020a, 0x020a,
- 0x020c, 0x020c,
- 0x020e, 0x020e,
- 0x0210, 0x0210,
- 0x0212, 0x0212,
- 0x0214, 0x0214,
- 0x0216, 0x0216,
- 0x0218, 0x0218,
- 0x021a, 0x021a,
- 0x021c, 0x021c,
- 0x021e, 0x021e,
- 0x0220, 0x0220,
- 0x0222, 0x0222,
- 0x0224, 0x0224,
- 0x0226, 0x0226,
- 0x0228, 0x0228,
- 0x022a, 0x022a,
- 0x022c, 0x022c,
- 0x022e, 0x022e,
- 0x0230, 0x0230,
- 0x0232, 0x0232,
- 0x023a, 0x023b,
- 0x023d, 0x023e,
- 0x0241, 0x0241,
- 0x0243, 0x0246,
- 0x0248, 0x0248,
- 0x024a, 0x024a,
- 0x024c, 0x024c,
- 0x024e, 0x024e,
- 0x0370, 0x0370,
- 0x0372, 0x0372,
- 0x0376, 0x0376,
- 0x037f, 0x037f,
- 0x0386, 0x0386,
- 0x0388, 0x038a,
- 0x038c, 0x038c,
- 0x038e, 0x038f,
- 0x0391, 0x03a1,
- 0x03a3, 0x03ab,
- 0x03cf, 0x03cf,
- 0x03d2, 0x03d4,
- 0x03d8, 0x03d8,
- 0x03da, 0x03da,
- 0x03dc, 0x03dc,
- 0x03de, 0x03de,
- 0x03e0, 0x03e0,
- 0x03e2, 0x03e2,
- 0x03e4, 0x03e4,
- 0x03e6, 0x03e6,
- 0x03e8, 0x03e8,
- 0x03ea, 0x03ea,
- 0x03ec, 0x03ec,
- 0x03ee, 0x03ee,
- 0x03f4, 0x03f4,
- 0x03f7, 0x03f7,
- 0x03f9, 0x03fa,
- 0x03fd, 0x042f,
- 0x0460, 0x0460,
- 0x0462, 0x0462,
- 0x0464, 0x0464,
- 0x0466, 0x0466,
- 0x0468, 0x0468,
- 0x046a, 0x046a,
- 0x046c, 0x046c,
- 0x046e, 0x046e,
- 0x0470, 0x0470,
- 0x0472, 0x0472,
- 0x0474, 0x0474,
- 0x0476, 0x0476,
- 0x0478, 0x0478,
- 0x047a, 0x047a,
- 0x047c, 0x047c,
- 0x047e, 0x047e,
- 0x0480, 0x0480,
- 0x048a, 0x048a,
- 0x048c, 0x048c,
- 0x048e, 0x048e,
- 0x0490, 0x0490,
- 0x0492, 0x0492,
- 0x0494, 0x0494,
- 0x0496, 0x0496,
- 0x0498, 0x0498,
- 0x049a, 0x049a,
- 0x049c, 0x049c,
- 0x049e, 0x049e,
- 0x04a0, 0x04a0,
- 0x04a2, 0x04a2,
- 0x04a4, 0x04a4,
- 0x04a6, 0x04a6,
- 0x04a8, 0x04a8,
- 0x04aa, 0x04aa,
- 0x04ac, 0x04ac,
- 0x04ae, 0x04ae,
- 0x04b0, 0x04b0,
- 0x04b2, 0x04b2,
- 0x04b4, 0x04b4,
- 0x04b6, 0x04b6,
- 0x04b8, 0x04b8,
- 0x04ba, 0x04ba,
- 0x04bc, 0x04bc,
- 0x04be, 0x04be,
- 0x04c0, 0x04c1,
- 0x04c3, 0x04c3,
- 0x04c5, 0x04c5,
- 0x04c7, 0x04c7,
- 0x04c9, 0x04c9,
- 0x04cb, 0x04cb,
- 0x04cd, 0x04cd,
- 0x04d0, 0x04d0,
- 0x04d2, 0x04d2,
- 0x04d4, 0x04d4,
- 0x04d6, 0x04d6,
- 0x04d8, 0x04d8,
- 0x04da, 0x04da,
- 0x04dc, 0x04dc,
- 0x04de, 0x04de,
- 0x04e0, 0x04e0,
- 0x04e2, 0x04e2,
- 0x04e4, 0x04e4,
- 0x04e6, 0x04e6,
- 0x04e8, 0x04e8,
- 0x04ea, 0x04ea,
- 0x04ec, 0x04ec,
- 0x04ee, 0x04ee,
- 0x04f0, 0x04f0,
- 0x04f2, 0x04f2,
- 0x04f4, 0x04f4,
- 0x04f6, 0x04f6,
- 0x04f8, 0x04f8,
- 0x04fa, 0x04fa,
- 0x04fc, 0x04fc,
- 0x04fe, 0x04fe,
- 0x0500, 0x0500,
- 0x0502, 0x0502,
- 0x0504, 0x0504,
- 0x0506, 0x0506,
- 0x0508, 0x0508,
- 0x050a, 0x050a,
- 0x050c, 0x050c,
- 0x050e, 0x050e,
- 0x0510, 0x0510,
- 0x0512, 0x0512,
- 0x0514, 0x0514,
- 0x0516, 0x0516,
- 0x0518, 0x0518,
- 0x051a, 0x051a,
- 0x051c, 0x051c,
- 0x051e, 0x051e,
- 0x0520, 0x0520,
- 0x0522, 0x0522,
- 0x0524, 0x0524,
- 0x0526, 0x0526,
- 0x0528, 0x0528,
- 0x052a, 0x052a,
- 0x052c, 0x052c,
- 0x052e, 0x052e,
- 0x0531, 0x0556,
- 0x10a0, 0x10c5,
- 0x10c7, 0x10c7,
- 0x10cd, 0x10cd,
- 0x13a0, 0x13f5,
- 0x1c89, 0x1c89,
- 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,
- 0x1fb8, 0x1fbb,
- 0x1fc8, 0x1fcb,
- 0x1fd8, 0x1fdb,
- 0x1fe8, 0x1fec,
- 0x1ff8, 0x1ffb,
- 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,
- 0xa7cb, 0xa7cc,
- 0xa7d0, 0xa7d0,
- 0xa7d6, 0xa7d6,
- 0xa7d8, 0xa7d8,
- 0xa7da, 0xa7da,
- 0xa7dc, 0xa7dc,
- 0xa7f5, 0xa7f5,
- 0xff21, 0xff3a,
- 0x10400, 0x10427,
- 0x104b0, 0x104d3,
- 0x10570, 0x1057a,
- 0x1057c, 0x1058a,
- 0x1058c, 0x10592,
- 0x10594, 0x10595,
- 0x10c80, 0x10cb2,
- 0x10d50, 0x10d65,
- 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,
-}; /* CR_Upper */
-
-/* 'XDigit': [[:XDigit:]] */
-static const OnigCodePoint CR_XDigit[] = {
- 3,
- 0x0030, 0x0039,
- 0x0041, 0x0046,
- 0x0061, 0x0066,
-}; /* CR_XDigit */
-
-/* 'Word': [[:Word:]] */
-static const OnigCodePoint CR_Word[] = {
- 796,
- 0x0030, 0x0039,
- 0x0041, 0x005a,
- 0x005f, 0x005f,
- 0x0061, 0x007a,
- 0x00aa, 0x00aa,
- 0x00b5, 0x00b5,
- 0x00ba, 0x00ba,
- 0x00c0, 0x00d6,
- 0x00d8, 0x00f6,
- 0x00f8, 0x02c1,
- 0x02c6, 0x02d1,
- 0x02e0, 0x02e4,
- 0x02ec, 0x02ec,
- 0x02ee, 0x02ee,
- 0x0300, 0x0374,
- 0x0376, 0x0377,
- 0x037a, 0x037d,
- 0x037f, 0x037f,
- 0x0386, 0x0386,
- 0x0388, 0x038a,
- 0x038c, 0x038c,
- 0x038e, 0x03a1,
- 0x03a3, 0x03f5,
- 0x03f7, 0x0481,
- 0x0483, 0x052f,
- 0x0531, 0x0556,
- 0x0559, 0x0559,
- 0x0560, 0x0588,
- 0x0591, 0x05bd,
- 0x05bf, 0x05bf,
- 0x05c1, 0x05c2,
- 0x05c4, 0x05c5,
- 0x05c7, 0x05c7,
- 0x05d0, 0x05ea,
- 0x05ef, 0x05f2,
- 0x0610, 0x061a,
- 0x0620, 0x0669,
- 0x066e, 0x06d3,
- 0x06d5, 0x06dc,
- 0x06df, 0x06e8,
- 0x06ea, 0x06fc,
- 0x06ff, 0x06ff,
- 0x0710, 0x074a,
- 0x074d, 0x07b1,
- 0x07c0, 0x07f5,
- 0x07fa, 0x07fa,
- 0x07fd, 0x07fd,
- 0x0800, 0x082d,
- 0x0840, 0x085b,
- 0x0860, 0x086a,
- 0x0870, 0x0887,
- 0x0889, 0x088e,
- 0x0897, 0x08e1,
- 0x08e3, 0x0963,
- 0x0966, 0x096f,
- 0x0971, 0x0983,
- 0x0985, 0x098c,
- 0x098f, 0x0990,
- 0x0993, 0x09a8,
- 0x09aa, 0x09b0,
- 0x09b2, 0x09b2,
- 0x09b6, 0x09b9,
- 0x09bc, 0x09c4,
- 0x09c7, 0x09c8,
- 0x09cb, 0x09ce,
- 0x09d7, 0x09d7,
- 0x09dc, 0x09dd,
- 0x09df, 0x09e3,
- 0x09e6, 0x09f1,
- 0x09fc, 0x09fc,
- 0x09fe, 0x09fe,
- 0x0a01, 0x0a03,
- 0x0a05, 0x0a0a,
- 0x0a0f, 0x0a10,
- 0x0a13, 0x0a28,
- 0x0a2a, 0x0a30,
- 0x0a32, 0x0a33,
- 0x0a35, 0x0a36,
- 0x0a38, 0x0a39,
- 0x0a3c, 0x0a3c,
- 0x0a3e, 0x0a42,
- 0x0a47, 0x0a48,
- 0x0a4b, 0x0a4d,
- 0x0a51, 0x0a51,
- 0x0a59, 0x0a5c,
- 0x0a5e, 0x0a5e,
- 0x0a66, 0x0a75,
- 0x0a81, 0x0a83,
- 0x0a85, 0x0a8d,
- 0x0a8f, 0x0a91,
- 0x0a93, 0x0aa8,
- 0x0aaa, 0x0ab0,
- 0x0ab2, 0x0ab3,
- 0x0ab5, 0x0ab9,
- 0x0abc, 0x0ac5,
- 0x0ac7, 0x0ac9,
- 0x0acb, 0x0acd,
- 0x0ad0, 0x0ad0,
- 0x0ae0, 0x0ae3,
- 0x0ae6, 0x0aef,
- 0x0af9, 0x0aff,
- 0x0b01, 0x0b03,
- 0x0b05, 0x0b0c,
- 0x0b0f, 0x0b10,
- 0x0b13, 0x0b28,
- 0x0b2a, 0x0b30,
- 0x0b32, 0x0b33,
- 0x0b35, 0x0b39,
- 0x0b3c, 0x0b44,
- 0x0b47, 0x0b48,
- 0x0b4b, 0x0b4d,
- 0x0b55, 0x0b57,
- 0x0b5c, 0x0b5d,
- 0x0b5f, 0x0b63,
- 0x0b66, 0x0b6f,
- 0x0b71, 0x0b71,
- 0x0b82, 0x0b83,
- 0x0b85, 0x0b8a,
- 0x0b8e, 0x0b90,
- 0x0b92, 0x0b95,
- 0x0b99, 0x0b9a,
- 0x0b9c, 0x0b9c,
- 0x0b9e, 0x0b9f,
- 0x0ba3, 0x0ba4,
- 0x0ba8, 0x0baa,
- 0x0bae, 0x0bb9,
- 0x0bbe, 0x0bc2,
- 0x0bc6, 0x0bc8,
- 0x0bca, 0x0bcd,
- 0x0bd0, 0x0bd0,
- 0x0bd7, 0x0bd7,
- 0x0be6, 0x0bef,
- 0x0c00, 0x0c0c,
- 0x0c0e, 0x0c10,
- 0x0c12, 0x0c28,
- 0x0c2a, 0x0c39,
- 0x0c3c, 0x0c44,
- 0x0c46, 0x0c48,
- 0x0c4a, 0x0c4d,
- 0x0c55, 0x0c56,
- 0x0c58, 0x0c5a,
- 0x0c5d, 0x0c5d,
- 0x0c60, 0x0c63,
- 0x0c66, 0x0c6f,
- 0x0c80, 0x0c83,
- 0x0c85, 0x0c8c,
- 0x0c8e, 0x0c90,
- 0x0c92, 0x0ca8,
- 0x0caa, 0x0cb3,
- 0x0cb5, 0x0cb9,
- 0x0cbc, 0x0cc4,
- 0x0cc6, 0x0cc8,
- 0x0cca, 0x0ccd,
- 0x0cd5, 0x0cd6,
- 0x0cdd, 0x0cde,
- 0x0ce0, 0x0ce3,
- 0x0ce6, 0x0cef,
- 0x0cf1, 0x0cf3,
- 0x0d00, 0x0d0c,
- 0x0d0e, 0x0d10,
- 0x0d12, 0x0d44,
- 0x0d46, 0x0d48,
- 0x0d4a, 0x0d4e,
- 0x0d54, 0x0d57,
- 0x0d5f, 0x0d63,
- 0x0d66, 0x0d6f,
- 0x0d7a, 0x0d7f,
- 0x0d81, 0x0d83,
- 0x0d85, 0x0d96,
- 0x0d9a, 0x0db1,
- 0x0db3, 0x0dbb,
- 0x0dbd, 0x0dbd,
- 0x0dc0, 0x0dc6,
- 0x0dca, 0x0dca,
- 0x0dcf, 0x0dd4,
- 0x0dd6, 0x0dd6,
- 0x0dd8, 0x0ddf,
- 0x0de6, 0x0def,
- 0x0df2, 0x0df3,
- 0x0e01, 0x0e3a,
- 0x0e40, 0x0e4e,
- 0x0e50, 0x0e59,
- 0x0e81, 0x0e82,
- 0x0e84, 0x0e84,
- 0x0e86, 0x0e8a,
- 0x0e8c, 0x0ea3,
- 0x0ea5, 0x0ea5,
- 0x0ea7, 0x0ebd,
- 0x0ec0, 0x0ec4,
- 0x0ec6, 0x0ec6,
- 0x0ec8, 0x0ece,
- 0x0ed0, 0x0ed9,
- 0x0edc, 0x0edf,
- 0x0f00, 0x0f00,
- 0x0f18, 0x0f19,
- 0x0f20, 0x0f29,
- 0x0f35, 0x0f35,
- 0x0f37, 0x0f37,
- 0x0f39, 0x0f39,
- 0x0f3e, 0x0f47,
- 0x0f49, 0x0f6c,
- 0x0f71, 0x0f84,
- 0x0f86, 0x0f97,
- 0x0f99, 0x0fbc,
- 0x0fc6, 0x0fc6,
- 0x1000, 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,
- 0x135d, 0x135f,
- 0x1380, 0x138f,
- 0x13a0, 0x13f5,
- 0x13f8, 0x13fd,
- 0x1401, 0x166c,
- 0x166f, 0x167f,
- 0x1681, 0x169a,
- 0x16a0, 0x16ea,
- 0x16ee, 0x16f8,
- 0x1700, 0x1715,
- 0x171f, 0x1734,
- 0x1740, 0x1753,
- 0x1760, 0x176c,
- 0x176e, 0x1770,
- 0x1772, 0x1773,
- 0x1780, 0x17d3,
- 0x17d7, 0x17d7,
- 0x17dc, 0x17dd,
- 0x17e0, 0x17e9,
- 0x180b, 0x180d,
- 0x180f, 0x1819,
- 0x1820, 0x1878,
- 0x1880, 0x18aa,
- 0x18b0, 0x18f5,
- 0x1900, 0x191e,
- 0x1920, 0x192b,
- 0x1930, 0x193b,
- 0x1946, 0x196d,
- 0x1970, 0x1974,
- 0x1980, 0x19ab,
- 0x19b0, 0x19c9,
- 0x19d0, 0x19d9,
- 0x1a00, 0x1a1b,
- 0x1a20, 0x1a5e,
- 0x1a60, 0x1a7c,
- 0x1a7f, 0x1a89,
- 0x1a90, 0x1a99,
- 0x1aa7, 0x1aa7,
- 0x1ab0, 0x1ace,
- 0x1b00, 0x1b4c,
- 0x1b50, 0x1b59,
- 0x1b6b, 0x1b73,
- 0x1b80, 0x1bf3,
- 0x1c00, 0x1c37,
- 0x1c40, 0x1c49,
- 0x1c4d, 0x1c7d,
- 0x1c80, 0x1c8a,
- 0x1c90, 0x1cba,
- 0x1cbd, 0x1cbf,
- 0x1cd0, 0x1cd2,
- 0x1cd4, 0x1cfa,
- 0x1d00, 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,
- 0x200c, 0x200d,
- 0x203f, 0x2040,
- 0x2054, 0x2054,
- 0x2071, 0x2071,
- 0x207f, 0x207f,
- 0x2090, 0x209c,
- 0x20d0, 0x20f0,
- 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, 0x2cf3,
- 0x2d00, 0x2d25,
- 0x2d27, 0x2d27,
- 0x2d2d, 0x2d2d,
- 0x2d30, 0x2d67,
- 0x2d6f, 0x2d6f,
- 0x2d7f, 0x2d96,
- 0x2da0, 0x2da6,
- 0x2da8, 0x2dae,
- 0x2db0, 0x2db6,
- 0x2db8, 0x2dbe,
- 0x2dc0, 0x2dc6,
- 0x2dc8, 0x2dce,
- 0x2dd0, 0x2dd6,
- 0x2dd8, 0x2dde,
- 0x2de0, 0x2dff,
- 0x2e2f, 0x2e2f,
- 0x3005, 0x3007,
- 0x3021, 0x302f,
- 0x3031, 0x3035,
- 0x3038, 0x303c,
- 0x3041, 0x3096,
- 0x3099, 0x309a,
- 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, 0xa672,
- 0xa674, 0xa67d,
- 0xa67f, 0xa6f1,
- 0xa717, 0xa71f,
- 0xa722, 0xa788,
- 0xa78b, 0xa7cd,
- 0xa7d0, 0xa7d1,
- 0xa7d3, 0xa7d3,
- 0xa7d5, 0xa7dc,
- 0xa7f2, 0xa827,
- 0xa82c, 0xa82c,
- 0xa840, 0xa873,
- 0xa880, 0xa8c5,
- 0xa8d0, 0xa8d9,
- 0xa8e0, 0xa8f7,
- 0xa8fb, 0xa8fb,
- 0xa8fd, 0xa92d,
- 0xa930, 0xa953,
- 0xa960, 0xa97c,
- 0xa980, 0xa9c0,
- 0xa9cf, 0xa9d9,
- 0xa9e0, 0xa9fe,
- 0xaa00, 0xaa36,
- 0xaa40, 0xaa4d,
- 0xaa50, 0xaa59,
- 0xaa60, 0xaa76,
- 0xaa7a, 0xaac2,
- 0xaadb, 0xaadd,
- 0xaae0, 0xaaef,
- 0xaaf2, 0xaaf6,
- 0xab01, 0xab06,
- 0xab09, 0xab0e,
- 0xab11, 0xab16,
- 0xab20, 0xab26,
- 0xab28, 0xab2e,
- 0xab30, 0xab5a,
- 0xab5c, 0xab69,
- 0xab70, 0xabea,
- 0xabec, 0xabed,
- 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,
- 0xfe00, 0xfe0f,
- 0xfe20, 0xfe2f,
- 0xfe33, 0xfe34,
- 0xfe4d, 0xfe4f,
- 0xfe70, 0xfe74,
- 0xfe76, 0xfefc,
- 0xff10, 0xff19,
- 0xff21, 0xff3a,
- 0xff3f, 0xff3f,
- 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,
- 0x101fd, 0x101fd,
- 0x10280, 0x1029c,
- 0x102a0, 0x102d0,
- 0x102e0, 0x102e0,
- 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,
- 0x105c0, 0x105f3,
- 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,
- 0x10a38, 0x10a3a,
- 0x10a3f, 0x10a3f,
- 0x10a60, 0x10a7c,
- 0x10a80, 0x10a9c,
- 0x10ac0, 0x10ac7,
- 0x10ac9, 0x10ae6,
- 0x10b00, 0x10b35,
- 0x10b40, 0x10b55,
- 0x10b60, 0x10b72,
- 0x10b80, 0x10b91,
- 0x10c00, 0x10c48,
- 0x10c80, 0x10cb2,
- 0x10cc0, 0x10cf2,
- 0x10d00, 0x10d27,
- 0x10d30, 0x10d39,
- 0x10d40, 0x10d65,
- 0x10d69, 0x10d6d,
- 0x10d6f, 0x10d85,
- 0x10e80, 0x10ea9,
- 0x10eab, 0x10eac,
- 0x10eb0, 0x10eb1,
- 0x10ec2, 0x10ec4,
- 0x10efc, 0x10f1c,
- 0x10f27, 0x10f27,
- 0x10f30, 0x10f50,
- 0x10f70, 0x10f85,
- 0x10fb0, 0x10fc4,
- 0x10fe0, 0x10ff6,
- 0x11000, 0x11046,
- 0x11066, 0x11075,
- 0x1107f, 0x110ba,
- 0x110c2, 0x110c2,
- 0x110d0, 0x110e8,
- 0x110f0, 0x110f9,
- 0x11100, 0x11134,
- 0x11136, 0x1113f,
- 0x11144, 0x11147,
- 0x11150, 0x11173,
- 0x11176, 0x11176,
- 0x11180, 0x111c4,
- 0x111c9, 0x111cc,
- 0x111ce, 0x111da,
- 0x111dc, 0x111dc,
- 0x11200, 0x11211,
- 0x11213, 0x11237,
- 0x1123e, 0x11241,
- 0x11280, 0x11286,
- 0x11288, 0x11288,
- 0x1128a, 0x1128d,
- 0x1128f, 0x1129d,
- 0x1129f, 0x112a8,
- 0x112b0, 0x112ea,
- 0x112f0, 0x112f9,
- 0x11300, 0x11303,
- 0x11305, 0x1130c,
- 0x1130f, 0x11310,
- 0x11313, 0x11328,
- 0x1132a, 0x11330,
- 0x11332, 0x11333,
- 0x11335, 0x11339,
- 0x1133b, 0x11344,
- 0x11347, 0x11348,
- 0x1134b, 0x1134d,
- 0x11350, 0x11350,
- 0x11357, 0x11357,
- 0x1135d, 0x11363,
- 0x11366, 0x1136c,
- 0x11370, 0x11374,
- 0x11380, 0x11389,
- 0x1138b, 0x1138b,
- 0x1138e, 0x1138e,
- 0x11390, 0x113b5,
- 0x113b7, 0x113c0,
- 0x113c2, 0x113c2,
- 0x113c5, 0x113c5,
- 0x113c7, 0x113ca,
- 0x113cc, 0x113d3,
- 0x113e1, 0x113e2,
- 0x11400, 0x1144a,
- 0x11450, 0x11459,
- 0x1145e, 0x11461,
- 0x11480, 0x114c5,
- 0x114c7, 0x114c7,
- 0x114d0, 0x114d9,
- 0x11580, 0x115b5,
- 0x115b8, 0x115c0,
- 0x115d8, 0x115dd,
- 0x11600, 0x11640,
- 0x11644, 0x11644,
- 0x11650, 0x11659,
- 0x11680, 0x116b8,
- 0x116c0, 0x116c9,
- 0x116d0, 0x116e3,
- 0x11700, 0x1171a,
- 0x1171d, 0x1172b,
- 0x11730, 0x11739,
- 0x11740, 0x11746,
- 0x11800, 0x1183a,
- 0x118a0, 0x118e9,
- 0x118ff, 0x11906,
- 0x11909, 0x11909,
- 0x1190c, 0x11913,
- 0x11915, 0x11916,
- 0x11918, 0x11935,
- 0x11937, 0x11938,
- 0x1193b, 0x11943,
- 0x11950, 0x11959,
- 0x119a0, 0x119a7,
- 0x119aa, 0x119d7,
- 0x119da, 0x119e1,
- 0x119e3, 0x119e4,
- 0x11a00, 0x11a3e,
- 0x11a47, 0x11a47,
- 0x11a50, 0x11a99,
- 0x11a9d, 0x11a9d,
- 0x11ab0, 0x11af8,
- 0x11bc0, 0x11be0,
- 0x11bf0, 0x11bf9,
- 0x11c00, 0x11c08,
- 0x11c0a, 0x11c36,
- 0x11c38, 0x11c40,
- 0x11c50, 0x11c59,
- 0x11c72, 0x11c8f,
- 0x11c92, 0x11ca7,
- 0x11ca9, 0x11cb6,
- 0x11d00, 0x11d06,
- 0x11d08, 0x11d09,
- 0x11d0b, 0x11d36,
- 0x11d3a, 0x11d3a,
- 0x11d3c, 0x11d3d,
- 0x11d3f, 0x11d47,
- 0x11d50, 0x11d59,
- 0x11d60, 0x11d65,
- 0x11d67, 0x11d68,
- 0x11d6a, 0x11d8e,
- 0x11d90, 0x11d91,
- 0x11d93, 0x11d98,
- 0x11da0, 0x11da9,
- 0x11ee0, 0x11ef6,
- 0x11f00, 0x11f10,
- 0x11f12, 0x11f3a,
- 0x11f3e, 0x11f42,
- 0x11f50, 0x11f5a,
- 0x11fb0, 0x11fb0,
- 0x12000, 0x12399,
- 0x12400, 0x1246e,
- 0x12480, 0x12543,
- 0x12f90, 0x12ff0,
- 0x13000, 0x1342f,
- 0x13440, 0x13455,
- 0x13460, 0x143fa,
- 0x14400, 0x14646,
- 0x16100, 0x16139,
- 0x16800, 0x16a38,
- 0x16a40, 0x16a5e,
- 0x16a60, 0x16a69,
- 0x16a70, 0x16abe,
- 0x16ac0, 0x16ac9,
- 0x16ad0, 0x16aed,
- 0x16af0, 0x16af4,
- 0x16b00, 0x16b36,
- 0x16b40, 0x16b43,
- 0x16b50, 0x16b59,
- 0x16b63, 0x16b77,
- 0x16b7d, 0x16b8f,
- 0x16d40, 0x16d6c,
- 0x16d70, 0x16d79,
- 0x16e40, 0x16e7f,
- 0x16f00, 0x16f4a,
- 0x16f4f, 0x16f87,
- 0x16f8f, 0x16f9f,
- 0x16fe0, 0x16fe1,
- 0x16fe3, 0x16fe4,
- 0x16ff0, 0x16ff1,
- 0x17000, 0x187f7,
- 0x18800, 0x18cd5,
- 0x18cff, 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,
- 0x1bc9d, 0x1bc9e,
- 0x1ccf0, 0x1ccf9,
- 0x1cf00, 0x1cf2d,
- 0x1cf30, 0x1cf46,
- 0x1d165, 0x1d169,
- 0x1d16d, 0x1d172,
- 0x1d17b, 0x1d182,
- 0x1d185, 0x1d18b,
- 0x1d1aa, 0x1d1ad,
- 0x1d242, 0x1d244,
- 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,
- 0x1da00, 0x1da36,
- 0x1da3b, 0x1da6c,
- 0x1da75, 0x1da75,
- 0x1da84, 0x1da84,
- 0x1da9b, 0x1da9f,
- 0x1daa1, 0x1daaf,
- 0x1df00, 0x1df1e,
- 0x1df25, 0x1df2a,
- 0x1e000, 0x1e006,
- 0x1e008, 0x1e018,
- 0x1e01b, 0x1e021,
- 0x1e023, 0x1e024,
- 0x1e026, 0x1e02a,
- 0x1e030, 0x1e06d,
- 0x1e08f, 0x1e08f,
- 0x1e100, 0x1e12c,
- 0x1e130, 0x1e13d,
- 0x1e140, 0x1e149,
- 0x1e14e, 0x1e14e,
- 0x1e290, 0x1e2ae,
- 0x1e2c0, 0x1e2f9,
- 0x1e4d0, 0x1e4f9,
- 0x1e5d0, 0x1e5fa,
- 0x1e7e0, 0x1e7e6,
- 0x1e7e8, 0x1e7eb,
- 0x1e7ed, 0x1e7ee,
- 0x1e7f0, 0x1e7fe,
- 0x1e800, 0x1e8c4,
- 0x1e8d0, 0x1e8d6,
- 0x1e900, 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,
- 0x2ebf0, 0x2ee5d,
- 0x2f800, 0x2fa1d,
- 0x30000, 0x3134a,
- 0x31350, 0x323af,
- 0xe0100, 0xe01ef,
-}; /* CR_Word */
-
-/* 'Alnum': [[:Alnum:]] */
-static const OnigCodePoint CR_Alnum[] = {
- 802,
- 0x0030, 0x0039,
- 0x0041, 0x005a,
- 0x0061, 0x007a,
- 0x00aa, 0x00aa,
- 0x00b5, 0x00b5,
- 0x00ba, 0x00ba,
- 0x00c0, 0x00d6,
- 0x00d8, 0x00f6,
- 0x00f8, 0x02c1,
- 0x02c6, 0x02d1,
- 0x02e0, 0x02e4,
- 0x02ec, 0x02ec,
- 0x02ee, 0x02ee,
- 0x0345, 0x0345,
- 0x0363, 0x0374,
- 0x0376, 0x0377,
- 0x037a, 0x037d,
- 0x037f, 0x037f,
- 0x0386, 0x0386,
- 0x0388, 0x038a,
- 0x038c, 0x038c,
- 0x038e, 0x03a1,
- 0x03a3, 0x03f5,
- 0x03f7, 0x0481,
- 0x048a, 0x052f,
- 0x0531, 0x0556,
- 0x0559, 0x0559,
- 0x0560, 0x0588,
- 0x05b0, 0x05bd,
- 0x05bf, 0x05bf,
- 0x05c1, 0x05c2,
- 0x05c4, 0x05c5,
- 0x05c7, 0x05c7,
- 0x05d0, 0x05ea,
- 0x05ef, 0x05f2,
- 0x0610, 0x061a,
- 0x0620, 0x0657,
- 0x0659, 0x0669,
- 0x066e, 0x06d3,
- 0x06d5, 0x06dc,
- 0x06e1, 0x06e8,
- 0x06ed, 0x06fc,
- 0x06ff, 0x06ff,
- 0x0710, 0x073f,
- 0x074d, 0x07b1,
- 0x07c0, 0x07ea,
- 0x07f4, 0x07f5,
- 0x07fa, 0x07fa,
- 0x0800, 0x0817,
- 0x081a, 0x082c,
- 0x0840, 0x0858,
- 0x0860, 0x086a,
- 0x0870, 0x0887,
- 0x0889, 0x088e,
- 0x0897, 0x0897,
- 0x08a0, 0x08c9,
- 0x08d4, 0x08df,
- 0x08e3, 0x08e9,
- 0x08f0, 0x093b,
- 0x093d, 0x094c,
- 0x094e, 0x0950,
- 0x0955, 0x0963,
- 0x0966, 0x096f,
- 0x0971, 0x0983,
- 0x0985, 0x098c,
- 0x098f, 0x0990,
- 0x0993, 0x09a8,
- 0x09aa, 0x09b0,
- 0x09b2, 0x09b2,
- 0x09b6, 0x09b9,
- 0x09bd, 0x09c4,
- 0x09c7, 0x09c8,
- 0x09cb, 0x09cc,
- 0x09ce, 0x09ce,
- 0x09d7, 0x09d7,
- 0x09dc, 0x09dd,
- 0x09df, 0x09e3,
- 0x09e6, 0x09f1,
- 0x09fc, 0x09fc,
- 0x0a01, 0x0a03,
- 0x0a05, 0x0a0a,
- 0x0a0f, 0x0a10,
- 0x0a13, 0x0a28,
- 0x0a2a, 0x0a30,
- 0x0a32, 0x0a33,
- 0x0a35, 0x0a36,
- 0x0a38, 0x0a39,
- 0x0a3e, 0x0a42,
- 0x0a47, 0x0a48,
- 0x0a4b, 0x0a4c,
- 0x0a51, 0x0a51,
- 0x0a59, 0x0a5c,
- 0x0a5e, 0x0a5e,
- 0x0a66, 0x0a75,
- 0x0a81, 0x0a83,
- 0x0a85, 0x0a8d,
- 0x0a8f, 0x0a91,
- 0x0a93, 0x0aa8,
- 0x0aaa, 0x0ab0,
- 0x0ab2, 0x0ab3,
- 0x0ab5, 0x0ab9,
- 0x0abd, 0x0ac5,
- 0x0ac7, 0x0ac9,
- 0x0acb, 0x0acc,
- 0x0ad0, 0x0ad0,
- 0x0ae0, 0x0ae3,
- 0x0ae6, 0x0aef,
- 0x0af9, 0x0afc,
- 0x0b01, 0x0b03,
- 0x0b05, 0x0b0c,
- 0x0b0f, 0x0b10,
- 0x0b13, 0x0b28,
- 0x0b2a, 0x0b30,
- 0x0b32, 0x0b33,
- 0x0b35, 0x0b39,
- 0x0b3d, 0x0b44,
- 0x0b47, 0x0b48,
- 0x0b4b, 0x0b4c,
- 0x0b56, 0x0b57,
- 0x0b5c, 0x0b5d,
- 0x0b5f, 0x0b63,
- 0x0b66, 0x0b6f,
- 0x0b71, 0x0b71,
- 0x0b82, 0x0b83,
- 0x0b85, 0x0b8a,
- 0x0b8e, 0x0b90,
- 0x0b92, 0x0b95,
- 0x0b99, 0x0b9a,
- 0x0b9c, 0x0b9c,
- 0x0b9e, 0x0b9f,
- 0x0ba3, 0x0ba4,
- 0x0ba8, 0x0baa,
- 0x0bae, 0x0bb9,
- 0x0bbe, 0x0bc2,
- 0x0bc6, 0x0bc8,
- 0x0bca, 0x0bcc,
- 0x0bd0, 0x0bd0,
- 0x0bd7, 0x0bd7,
- 0x0be6, 0x0bef,
- 0x0c00, 0x0c0c,
- 0x0c0e, 0x0c10,
- 0x0c12, 0x0c28,
- 0x0c2a, 0x0c39,
- 0x0c3d, 0x0c44,
- 0x0c46, 0x0c48,
- 0x0c4a, 0x0c4c,
- 0x0c55, 0x0c56,
- 0x0c58, 0x0c5a,
- 0x0c5d, 0x0c5d,
- 0x0c60, 0x0c63,
- 0x0c66, 0x0c6f,
- 0x0c80, 0x0c83,
- 0x0c85, 0x0c8c,
- 0x0c8e, 0x0c90,
- 0x0c92, 0x0ca8,
- 0x0caa, 0x0cb3,
- 0x0cb5, 0x0cb9,
- 0x0cbd, 0x0cc4,
- 0x0cc6, 0x0cc8,
- 0x0cca, 0x0ccc,
- 0x0cd5, 0x0cd6,
- 0x0cdd, 0x0cde,
- 0x0ce0, 0x0ce3,
- 0x0ce6, 0x0cef,
- 0x0cf1, 0x0cf3,
- 0x0d00, 0x0d0c,
- 0x0d0e, 0x0d10,
- 0x0d12, 0x0d3a,
- 0x0d3d, 0x0d44,
- 0x0d46, 0x0d48,
- 0x0d4a, 0x0d4c,
- 0x0d4e, 0x0d4e,
- 0x0d54, 0x0d57,
- 0x0d5f, 0x0d63,
- 0x0d66, 0x0d6f,
- 0x0d7a, 0x0d7f,
- 0x0d81, 0x0d83,
- 0x0d85, 0x0d96,
- 0x0d9a, 0x0db1,
- 0x0db3, 0x0dbb,
- 0x0dbd, 0x0dbd,
- 0x0dc0, 0x0dc6,
- 0x0dcf, 0x0dd4,
- 0x0dd6, 0x0dd6,
- 0x0dd8, 0x0ddf,
- 0x0de6, 0x0def,
- 0x0df2, 0x0df3,
- 0x0e01, 0x0e3a,
- 0x0e40, 0x0e46,
- 0x0e4d, 0x0e4d,
- 0x0e50, 0x0e59,
- 0x0e81, 0x0e82,
- 0x0e84, 0x0e84,
- 0x0e86, 0x0e8a,
- 0x0e8c, 0x0ea3,
- 0x0ea5, 0x0ea5,
- 0x0ea7, 0x0eb9,
- 0x0ebb, 0x0ebd,
- 0x0ec0, 0x0ec4,
- 0x0ec6, 0x0ec6,
- 0x0ecd, 0x0ecd,
- 0x0ed0, 0x0ed9,
- 0x0edc, 0x0edf,
- 0x0f00, 0x0f00,
- 0x0f20, 0x0f29,
- 0x0f40, 0x0f47,
- 0x0f49, 0x0f6c,
- 0x0f71, 0x0f83,
- 0x0f88, 0x0f97,
- 0x0f99, 0x0fbc,
- 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, 0x1c8a,
- 0x1c90, 0x1cba,
- 0x1cbd, 0x1cbf,
- 0x1ce9, 0x1cec,
- 0x1cee, 0x1cf3,
- 0x1cf5, 0x1cf6,
- 0x1cfa, 0x1cfa,
- 0x1d00, 0x1dbf,
- 0x1dd3, 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, 0xa7cd,
- 0xa7d0, 0xa7d1,
- 0xa7d3, 0xa7d3,
- 0xa7d5, 0xa7dc,
- 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,
- 0x105c0, 0x105f3,
- 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,
- 0x10d40, 0x10d65,
- 0x10d69, 0x10d69,
- 0x10d6f, 0x10d85,
- 0x10e80, 0x10ea9,
- 0x10eab, 0x10eac,
- 0x10eb0, 0x10eb1,
- 0x10ec2, 0x10ec4,
- 0x10efc, 0x10efc,
- 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,
- 0x11380, 0x11389,
- 0x1138b, 0x1138b,
- 0x1138e, 0x1138e,
- 0x11390, 0x113b5,
- 0x113b7, 0x113c0,
- 0x113c2, 0x113c2,
- 0x113c5, 0x113c5,
- 0x113c7, 0x113ca,
- 0x113cc, 0x113cd,
- 0x113d1, 0x113d1,
- 0x113d3, 0x113d3,
- 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,
- 0x116d0, 0x116e3,
- 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,
- 0x11bc0, 0x11be0,
- 0x11bf0, 0x11bf9,
- 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,
- 0x13460, 0x143fa,
- 0x14400, 0x14646,
- 0x16100, 0x1612e,
- 0x16130, 0x16139,
- 0x16800, 0x16a38,
- 0x16a40, 0x16a5e,
- 0x16a60, 0x16a69,
- 0x16a70, 0x16abe,
- 0x16ac0, 0x16ac9,
- 0x16ad0, 0x16aed,
- 0x16b00, 0x16b2f,
- 0x16b40, 0x16b43,
- 0x16b50, 0x16b59,
- 0x16b63, 0x16b77,
- 0x16b7d, 0x16b8f,
- 0x16d40, 0x16d6c,
- 0x16d70, 0x16d79,
- 0x16e40, 0x16e7f,
- 0x16f00, 0x16f4a,
- 0x16f4f, 0x16f87,
- 0x16f8f, 0x16f9f,
- 0x16fe0, 0x16fe1,
- 0x16fe3, 0x16fe3,
- 0x16ff0, 0x16ff1,
- 0x17000, 0x187f7,
- 0x18800, 0x18cd5,
- 0x18cff, 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,
- 0x1ccf0, 0x1ccf9,
- 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,
- 0x1e5d0, 0x1e5ed,
- 0x1e5f0, 0x1e5fa,
- 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,
- 0x2ebf0, 0x2ee5d,
- 0x2f800, 0x2fa1d,
- 0x30000, 0x3134a,
- 0x31350, 0x323af,
-}; /* CR_Alnum */
-
-/* 'ASCII': [[:ASCII:]] */
-static const OnigCodePoint CR_ASCII[] = {
- 1,
- 0x0000, 0x007f,
-}; /* CR_ASCII */
-
-/* 'Punct': [[:Punct:]] */
-static const OnigCodePoint CR_Punct[] = {
- 198,
- 0x0021, 0x0023,
- 0x0025, 0x002a,
- 0x002c, 0x002f,
- 0x003a, 0x003b,
- 0x003f, 0x0040,
- 0x005b, 0x005d,
- 0x005f, 0x005f,
- 0x007b, 0x007b,
- 0x007d, 0x007d,
- 0x00a1, 0x00a1,
- 0x00a7, 0x00a7,
- 0x00ab, 0x00ab,
- 0x00b6, 0x00b7,
- 0x00bb, 0x00bb,
- 0x00bf, 0x00bf,
- 0x037e, 0x037e,
- 0x0387, 0x0387,
- 0x055a, 0x055f,
- 0x0589, 0x058a,
- 0x05be, 0x05be,
- 0x05c0, 0x05c0,
- 0x05c3, 0x05c3,
- 0x05c6, 0x05c6,
- 0x05f3, 0x05f4,
- 0x0609, 0x060a,
- 0x060c, 0x060d,
- 0x061b, 0x061b,
- 0x061d, 0x061f,
- 0x066a, 0x066d,
- 0x06d4, 0x06d4,
- 0x0700, 0x070d,
- 0x07f7, 0x07f9,
- 0x0830, 0x083e,
- 0x085e, 0x085e,
- 0x0964, 0x0965,
- 0x0970, 0x0970,
- 0x09fd, 0x09fd,
- 0x0a76, 0x0a76,
- 0x0af0, 0x0af0,
- 0x0c77, 0x0c77,
- 0x0c84, 0x0c84,
- 0x0df4, 0x0df4,
- 0x0e4f, 0x0e4f,
- 0x0e5a, 0x0e5b,
- 0x0f04, 0x0f12,
- 0x0f14, 0x0f14,
- 0x0f3a, 0x0f3d,
- 0x0f85, 0x0f85,
- 0x0fd0, 0x0fd4,
- 0x0fd9, 0x0fda,
- 0x104a, 0x104f,
- 0x10fb, 0x10fb,
- 0x1360, 0x1368,
- 0x1400, 0x1400,
- 0x166e, 0x166e,
- 0x169b, 0x169c,
- 0x16eb, 0x16ed,
- 0x1735, 0x1736,
- 0x17d4, 0x17d6,
- 0x17d8, 0x17da,
- 0x1800, 0x180a,
- 0x1944, 0x1945,
- 0x1a1e, 0x1a1f,
- 0x1aa0, 0x1aa6,
- 0x1aa8, 0x1aad,
- 0x1b4e, 0x1b4f,
- 0x1b5a, 0x1b60,
- 0x1b7d, 0x1b7f,
- 0x1bfc, 0x1bff,
- 0x1c3b, 0x1c3f,
- 0x1c7e, 0x1c7f,
- 0x1cc0, 0x1cc7,
- 0x1cd3, 0x1cd3,
- 0x2010, 0x2027,
- 0x2030, 0x2043,
- 0x2045, 0x2051,
- 0x2053, 0x205e,
- 0x207d, 0x207e,
- 0x208d, 0x208e,
- 0x2308, 0x230b,
- 0x2329, 0x232a,
- 0x2768, 0x2775,
- 0x27c5, 0x27c6,
- 0x27e6, 0x27ef,
- 0x2983, 0x2998,
- 0x29d8, 0x29db,
- 0x29fc, 0x29fd,
- 0x2cf9, 0x2cfc,
- 0x2cfe, 0x2cff,
- 0x2d70, 0x2d70,
- 0x2e00, 0x2e2e,
- 0x2e30, 0x2e4f,
- 0x2e52, 0x2e5d,
- 0x3001, 0x3003,
- 0x3008, 0x3011,
- 0x3014, 0x301f,
- 0x3030, 0x3030,
- 0x303d, 0x303d,
- 0x30a0, 0x30a0,
- 0x30fb, 0x30fb,
- 0xa4fe, 0xa4ff,
- 0xa60d, 0xa60f,
- 0xa673, 0xa673,
- 0xa67e, 0xa67e,
- 0xa6f2, 0xa6f7,
- 0xa874, 0xa877,
- 0xa8ce, 0xa8cf,
- 0xa8f8, 0xa8fa,
- 0xa8fc, 0xa8fc,
- 0xa92e, 0xa92f,
- 0xa95f, 0xa95f,
- 0xa9c1, 0xa9cd,
- 0xa9de, 0xa9df,
- 0xaa5c, 0xaa5f,
- 0xaade, 0xaadf,
- 0xaaf0, 0xaaf1,
- 0xabeb, 0xabeb,
- 0xfd3e, 0xfd3f,
- 0xfe10, 0xfe19,
- 0xfe30, 0xfe52,
- 0xfe54, 0xfe61,
- 0xfe63, 0xfe63,
- 0xfe68, 0xfe68,
- 0xfe6a, 0xfe6b,
- 0xff01, 0xff03,
- 0xff05, 0xff0a,
- 0xff0c, 0xff0f,
- 0xff1a, 0xff1b,
- 0xff1f, 0xff20,
- 0xff3b, 0xff3d,
- 0xff3f, 0xff3f,
- 0xff5b, 0xff5b,
- 0xff5d, 0xff5d,
- 0xff5f, 0xff65,
- 0x10100, 0x10102,
- 0x1039f, 0x1039f,
- 0x103d0, 0x103d0,
- 0x1056f, 0x1056f,
- 0x10857, 0x10857,
- 0x1091f, 0x1091f,
- 0x1093f, 0x1093f,
- 0x10a50, 0x10a58,
- 0x10a7f, 0x10a7f,
- 0x10af0, 0x10af6,
- 0x10b39, 0x10b3f,
- 0x10b99, 0x10b9c,
- 0x10d6e, 0x10d6e,
- 0x10ead, 0x10ead,
- 0x10f55, 0x10f59,
- 0x10f86, 0x10f89,
- 0x11047, 0x1104d,
- 0x110bb, 0x110bc,
- 0x110be, 0x110c1,
- 0x11140, 0x11143,
- 0x11174, 0x11175,
- 0x111c5, 0x111c8,
- 0x111cd, 0x111cd,
- 0x111db, 0x111db,
- 0x111dd, 0x111df,
- 0x11238, 0x1123d,
- 0x112a9, 0x112a9,
- 0x113d4, 0x113d5,
- 0x113d7, 0x113d8,
- 0x1144b, 0x1144f,
- 0x1145a, 0x1145b,
- 0x1145d, 0x1145d,
- 0x114c6, 0x114c6,
- 0x115c1, 0x115d7,
- 0x11641, 0x11643,
- 0x11660, 0x1166c,
- 0x116b9, 0x116b9,
- 0x1173c, 0x1173e,
- 0x1183b, 0x1183b,
- 0x11944, 0x11946,
- 0x119e2, 0x119e2,
- 0x11a3f, 0x11a46,
- 0x11a9a, 0x11a9c,
- 0x11a9e, 0x11aa2,
- 0x11b00, 0x11b09,
- 0x11be1, 0x11be1,
- 0x11c41, 0x11c45,
- 0x11c70, 0x11c71,
- 0x11ef7, 0x11ef8,
- 0x11f43, 0x11f4f,
- 0x11fff, 0x11fff,
- 0x12470, 0x12474,
- 0x12ff1, 0x12ff2,
- 0x16a6e, 0x16a6f,
- 0x16af5, 0x16af5,
- 0x16b37, 0x16b3b,
- 0x16b44, 0x16b44,
- 0x16d6d, 0x16d6f,
- 0x16e97, 0x16e9a,
- 0x16fe2, 0x16fe2,
- 0x1bc9f, 0x1bc9f,
- 0x1da87, 0x1da8b,
- 0x1e5ff, 0x1e5ff,
- 0x1e95e, 0x1e95f,
-}; /* CR_Punct */
-
-#ifdef USE_UNICODE_PROPERTIES
-/* 'Any': - */
-static const OnigCodePoint CR_Any[] = {
- 1,
- 0x0000, 0x10ffff,
-}; /* CR_Any */
-
-/* 'Assigned': - */
-static const OnigCodePoint CR_Assigned[] = {
- 731,
- 0x0000, 0x0377,
- 0x037a, 0x037f,
- 0x0384, 0x038a,
- 0x038c, 0x038c,
- 0x038e, 0x03a1,
- 0x03a3, 0x052f,
- 0x0531, 0x0556,
- 0x0559, 0x058a,
- 0x058d, 0x058f,
- 0x0591, 0x05c7,
- 0x05d0, 0x05ea,
- 0x05ef, 0x05f4,
- 0x0600, 0x070d,
- 0x070f, 0x074a,
- 0x074d, 0x07b1,
- 0x07c0, 0x07fa,
- 0x07fd, 0x082d,
- 0x0830, 0x083e,
- 0x0840, 0x085b,
- 0x085e, 0x085e,
- 0x0860, 0x086a,
- 0x0870, 0x088e,
- 0x0890, 0x0891,
- 0x0897, 0x0983,
- 0x0985, 0x098c,
- 0x098f, 0x0990,
- 0x0993, 0x09a8,
- 0x09aa, 0x09b0,
- 0x09b2, 0x09b2,
- 0x09b6, 0x09b9,
- 0x09bc, 0x09c4,
- 0x09c7, 0x09c8,
- 0x09cb, 0x09ce,
- 0x09d7, 0x09d7,
- 0x09dc, 0x09dd,
- 0x09df, 0x09e3,
- 0x09e6, 0x09fe,
- 0x0a01, 0x0a03,
- 0x0a05, 0x0a0a,
- 0x0a0f, 0x0a10,
- 0x0a13, 0x0a28,
- 0x0a2a, 0x0a30,
- 0x0a32, 0x0a33,
- 0x0a35, 0x0a36,
- 0x0a38, 0x0a39,
- 0x0a3c, 0x0a3c,
- 0x0a3e, 0x0a42,
- 0x0a47, 0x0a48,
- 0x0a4b, 0x0a4d,
- 0x0a51, 0x0a51,
- 0x0a59, 0x0a5c,
- 0x0a5e, 0x0a5e,
- 0x0a66, 0x0a76,
- 0x0a81, 0x0a83,
- 0x0a85, 0x0a8d,
- 0x0a8f, 0x0a91,
- 0x0a93, 0x0aa8,
- 0x0aaa, 0x0ab0,
- 0x0ab2, 0x0ab3,
- 0x0ab5, 0x0ab9,
- 0x0abc, 0x0ac5,
- 0x0ac7, 0x0ac9,
- 0x0acb, 0x0acd,
- 0x0ad0, 0x0ad0,
- 0x0ae0, 0x0ae3,
- 0x0ae6, 0x0af1,
- 0x0af9, 0x0aff,
- 0x0b01, 0x0b03,
- 0x0b05, 0x0b0c,
- 0x0b0f, 0x0b10,
- 0x0b13, 0x0b28,
- 0x0b2a, 0x0b30,
- 0x0b32, 0x0b33,
- 0x0b35, 0x0b39,
- 0x0b3c, 0x0b44,
- 0x0b47, 0x0b48,
- 0x0b4b, 0x0b4d,
- 0x0b55, 0x0b57,
- 0x0b5c, 0x0b5d,
- 0x0b5f, 0x0b63,
- 0x0b66, 0x0b77,
- 0x0b82, 0x0b83,
- 0x0b85, 0x0b8a,
- 0x0b8e, 0x0b90,
- 0x0b92, 0x0b95,
- 0x0b99, 0x0b9a,
- 0x0b9c, 0x0b9c,
- 0x0b9e, 0x0b9f,
- 0x0ba3, 0x0ba4,
- 0x0ba8, 0x0baa,
- 0x0bae, 0x0bb9,
- 0x0bbe, 0x0bc2,
- 0x0bc6, 0x0bc8,
- 0x0bca, 0x0bcd,
- 0x0bd0, 0x0bd0,
- 0x0bd7, 0x0bd7,
- 0x0be6, 0x0bfa,
- 0x0c00, 0x0c0c,
- 0x0c0e, 0x0c10,
- 0x0c12, 0x0c28,
- 0x0c2a, 0x0c39,
- 0x0c3c, 0x0c44,
- 0x0c46, 0x0c48,
- 0x0c4a, 0x0c4d,
- 0x0c55, 0x0c56,
- 0x0c58, 0x0c5a,
- 0x0c5d, 0x0c5d,
- 0x0c60, 0x0c63,
- 0x0c66, 0x0c6f,
- 0x0c77, 0x0c8c,
- 0x0c8e, 0x0c90,
- 0x0c92, 0x0ca8,
- 0x0caa, 0x0cb3,
- 0x0cb5, 0x0cb9,
- 0x0cbc, 0x0cc4,
- 0x0cc6, 0x0cc8,
- 0x0cca, 0x0ccd,
- 0x0cd5, 0x0cd6,
- 0x0cdd, 0x0cde,
- 0x0ce0, 0x0ce3,
- 0x0ce6, 0x0cef,
- 0x0cf1, 0x0cf3,
- 0x0d00, 0x0d0c,
- 0x0d0e, 0x0d10,
- 0x0d12, 0x0d44,
- 0x0d46, 0x0d48,
- 0x0d4a, 0x0d4f,
- 0x0d54, 0x0d63,
- 0x0d66, 0x0d7f,
- 0x0d81, 0x0d83,
- 0x0d85, 0x0d96,
- 0x0d9a, 0x0db1,
- 0x0db3, 0x0dbb,
- 0x0dbd, 0x0dbd,
- 0x0dc0, 0x0dc6,
- 0x0dca, 0x0dca,
- 0x0dcf, 0x0dd4,
- 0x0dd6, 0x0dd6,
- 0x0dd8, 0x0ddf,
- 0x0de6, 0x0def,
- 0x0df2, 0x0df4,
- 0x0e01, 0x0e3a,
- 0x0e3f, 0x0e5b,
- 0x0e81, 0x0e82,
- 0x0e84, 0x0e84,
- 0x0e86, 0x0e8a,
- 0x0e8c, 0x0ea3,
- 0x0ea5, 0x0ea5,
- 0x0ea7, 0x0ebd,
- 0x0ec0, 0x0ec4,
- 0x0ec6, 0x0ec6,
- 0x0ec8, 0x0ece,
- 0x0ed0, 0x0ed9,
- 0x0edc, 0x0edf,
- 0x0f00, 0x0f47,
- 0x0f49, 0x0f6c,
- 0x0f71, 0x0f97,
- 0x0f99, 0x0fbc,
- 0x0fbe, 0x0fcc,
- 0x0fce, 0x0fda,
- 0x1000, 0x10c5,
- 0x10c7, 0x10c7,
- 0x10cd, 0x10cd,
- 0x10d0, 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,
- 0x135d, 0x137c,
- 0x1380, 0x1399,
- 0x13a0, 0x13f5,
- 0x13f8, 0x13fd,
- 0x1400, 0x169c,
- 0x16a0, 0x16f8,
- 0x1700, 0x1715,
- 0x171f, 0x1736,
- 0x1740, 0x1753,
- 0x1760, 0x176c,
- 0x176e, 0x1770,
- 0x1772, 0x1773,
- 0x1780, 0x17dd,
- 0x17e0, 0x17e9,
- 0x17f0, 0x17f9,
- 0x1800, 0x1819,
- 0x1820, 0x1878,
- 0x1880, 0x18aa,
- 0x18b0, 0x18f5,
- 0x1900, 0x191e,
- 0x1920, 0x192b,
- 0x1930, 0x193b,
- 0x1940, 0x1940,
- 0x1944, 0x196d,
- 0x1970, 0x1974,
- 0x1980, 0x19ab,
- 0x19b0, 0x19c9,
- 0x19d0, 0x19da,
- 0x19de, 0x1a1b,
- 0x1a1e, 0x1a5e,
- 0x1a60, 0x1a7c,
- 0x1a7f, 0x1a89,
- 0x1a90, 0x1a99,
- 0x1aa0, 0x1aad,
- 0x1ab0, 0x1ace,
- 0x1b00, 0x1b4c,
- 0x1b4e, 0x1bf3,
- 0x1bfc, 0x1c37,
- 0x1c3b, 0x1c49,
- 0x1c4d, 0x1c8a,
- 0x1c90, 0x1cba,
- 0x1cbd, 0x1cc7,
- 0x1cd0, 0x1cfa,
- 0x1d00, 0x1f15,
- 0x1f18, 0x1f1d,
- 0x1f20, 0x1f45,
- 0x1f48, 0x1f4d,
- 0x1f50, 0x1f57,
- 0x1f59, 0x1f59,
- 0x1f5b, 0x1f5b,
- 0x1f5d, 0x1f5d,
- 0x1f5f, 0x1f7d,
- 0x1f80, 0x1fb4,
- 0x1fb6, 0x1fc4,
- 0x1fc6, 0x1fd3,
- 0x1fd6, 0x1fdb,
- 0x1fdd, 0x1fef,
- 0x1ff2, 0x1ff4,
- 0x1ff6, 0x1ffe,
- 0x2000, 0x2064,
- 0x2066, 0x2071,
- 0x2074, 0x208e,
- 0x2090, 0x209c,
- 0x20a0, 0x20c0,
- 0x20d0, 0x20f0,
- 0x2100, 0x218b,
- 0x2190, 0x2429,
- 0x2440, 0x244a,
- 0x2460, 0x2b73,
- 0x2b76, 0x2b95,
- 0x2b97, 0x2cf3,
- 0x2cf9, 0x2d25,
- 0x2d27, 0x2d27,
- 0x2d2d, 0x2d2d,
- 0x2d30, 0x2d67,
- 0x2d6f, 0x2d70,
- 0x2d7f, 0x2d96,
- 0x2da0, 0x2da6,
- 0x2da8, 0x2dae,
- 0x2db0, 0x2db6,
- 0x2db8, 0x2dbe,
- 0x2dc0, 0x2dc6,
- 0x2dc8, 0x2dce,
- 0x2dd0, 0x2dd6,
- 0x2dd8, 0x2dde,
- 0x2de0, 0x2e5d,
- 0x2e80, 0x2e99,
- 0x2e9b, 0x2ef3,
- 0x2f00, 0x2fd5,
- 0x2ff0, 0x303f,
- 0x3041, 0x3096,
- 0x3099, 0x30ff,
- 0x3105, 0x312f,
- 0x3131, 0x318e,
- 0x3190, 0x31e5,
- 0x31ef, 0x321e,
- 0x3220, 0xa48c,
- 0xa490, 0xa4c6,
- 0xa4d0, 0xa62b,
- 0xa640, 0xa6f7,
- 0xa700, 0xa7cd,
- 0xa7d0, 0xa7d1,
- 0xa7d3, 0xa7d3,
- 0xa7d5, 0xa7dc,
- 0xa7f2, 0xa82c,
- 0xa830, 0xa839,
- 0xa840, 0xa877,
- 0xa880, 0xa8c5,
- 0xa8ce, 0xa8d9,
- 0xa8e0, 0xa953,
- 0xa95f, 0xa97c,
- 0xa980, 0xa9cd,
- 0xa9cf, 0xa9d9,
- 0xa9de, 0xa9fe,
- 0xaa00, 0xaa36,
- 0xaa40, 0xaa4d,
- 0xaa50, 0xaa59,
- 0xaa5c, 0xaac2,
- 0xaadb, 0xaaf6,
- 0xab01, 0xab06,
- 0xab09, 0xab0e,
- 0xab11, 0xab16,
- 0xab20, 0xab26,
- 0xab28, 0xab2e,
- 0xab30, 0xab6b,
- 0xab70, 0xabed,
- 0xabf0, 0xabf9,
- 0xac00, 0xd7a3,
- 0xd7b0, 0xd7c6,
- 0xd7cb, 0xd7fb,
- 0xd800, 0xfa6d,
- 0xfa70, 0xfad9,
- 0xfb00, 0xfb06,
- 0xfb13, 0xfb17,
- 0xfb1d, 0xfb36,
- 0xfb38, 0xfb3c,
- 0xfb3e, 0xfb3e,
- 0xfb40, 0xfb41,
- 0xfb43, 0xfb44,
- 0xfb46, 0xfbc2,
- 0xfbd3, 0xfd8f,
- 0xfd92, 0xfdc7,
- 0xfdcf, 0xfdcf,
- 0xfdf0, 0xfe19,
- 0xfe20, 0xfe52,
- 0xfe54, 0xfe66,
- 0xfe68, 0xfe6b,
- 0xfe70, 0xfe74,
- 0xfe76, 0xfefc,
- 0xfeff, 0xfeff,
- 0xff01, 0xffbe,
- 0xffc2, 0xffc7,
- 0xffca, 0xffcf,
- 0xffd2, 0xffd7,
- 0xffda, 0xffdc,
- 0xffe0, 0xffe6,
- 0xffe8, 0xffee,
- 0xfff9, 0xfffd,
- 0x10000, 0x1000b,
- 0x1000d, 0x10026,
- 0x10028, 0x1003a,
- 0x1003c, 0x1003d,
- 0x1003f, 0x1004d,
- 0x10050, 0x1005d,
- 0x10080, 0x100fa,
- 0x10100, 0x10102,
- 0x10107, 0x10133,
- 0x10137, 0x1018e,
- 0x10190, 0x1019c,
- 0x101a0, 0x101a0,
- 0x101d0, 0x101fd,
- 0x10280, 0x1029c,
- 0x102a0, 0x102d0,
- 0x102e0, 0x102fb,
- 0x10300, 0x10323,
- 0x1032d, 0x1034a,
- 0x10350, 0x1037a,
- 0x10380, 0x1039d,
- 0x1039f, 0x103c3,
- 0x103c8, 0x103d5,
- 0x10400, 0x1049d,
- 0x104a0, 0x104a9,
- 0x104b0, 0x104d3,
- 0x104d8, 0x104fb,
- 0x10500, 0x10527,
- 0x10530, 0x10563,
- 0x1056f, 0x1057a,
- 0x1057c, 0x1058a,
- 0x1058c, 0x10592,
- 0x10594, 0x10595,
- 0x10597, 0x105a1,
- 0x105a3, 0x105b1,
- 0x105b3, 0x105b9,
- 0x105bb, 0x105bc,
- 0x105c0, 0x105f3,
- 0x10600, 0x10736,
- 0x10740, 0x10755,
- 0x10760, 0x10767,
- 0x10780, 0x10785,
- 0x10787, 0x107b0,
- 0x107b2, 0x107ba,
- 0x10800, 0x10805,
- 0x10808, 0x10808,
- 0x1080a, 0x10835,
- 0x10837, 0x10838,
- 0x1083c, 0x1083c,
- 0x1083f, 0x10855,
- 0x10857, 0x1089e,
- 0x108a7, 0x108af,
- 0x108e0, 0x108f2,
- 0x108f4, 0x108f5,
- 0x108fb, 0x1091b,
- 0x1091f, 0x10939,
- 0x1093f, 0x1093f,
- 0x10980, 0x109b7,
- 0x109bc, 0x109cf,
- 0x109d2, 0x10a03,
- 0x10a05, 0x10a06,
- 0x10a0c, 0x10a13,
- 0x10a15, 0x10a17,
- 0x10a19, 0x10a35,
- 0x10a38, 0x10a3a,
- 0x10a3f, 0x10a48,
- 0x10a50, 0x10a58,
- 0x10a60, 0x10a9f,
- 0x10ac0, 0x10ae6,
- 0x10aeb, 0x10af6,
- 0x10b00, 0x10b35,
- 0x10b39, 0x10b55,
- 0x10b58, 0x10b72,
- 0x10b78, 0x10b91,
- 0x10b99, 0x10b9c,
- 0x10ba9, 0x10baf,
- 0x10c00, 0x10c48,
- 0x10c80, 0x10cb2,
- 0x10cc0, 0x10cf2,
- 0x10cfa, 0x10d27,
- 0x10d30, 0x10d39,
- 0x10d40, 0x10d65,
- 0x10d69, 0x10d85,
- 0x10d8e, 0x10d8f,
- 0x10e60, 0x10e7e,
- 0x10e80, 0x10ea9,
- 0x10eab, 0x10ead,
- 0x10eb0, 0x10eb1,
- 0x10ec2, 0x10ec4,
- 0x10efc, 0x10f27,
- 0x10f30, 0x10f59,
- 0x10f70, 0x10f89,
- 0x10fb0, 0x10fcb,
- 0x10fe0, 0x10ff6,
- 0x11000, 0x1104d,
- 0x11052, 0x11075,
- 0x1107f, 0x110c2,
- 0x110cd, 0x110cd,
- 0x110d0, 0x110e8,
- 0x110f0, 0x110f9,
- 0x11100, 0x11134,
- 0x11136, 0x11147,
- 0x11150, 0x11176,
- 0x11180, 0x111df,
- 0x111e1, 0x111f4,
- 0x11200, 0x11211,
- 0x11213, 0x11241,
- 0x11280, 0x11286,
- 0x11288, 0x11288,
- 0x1128a, 0x1128d,
- 0x1128f, 0x1129d,
- 0x1129f, 0x112a9,
- 0x112b0, 0x112ea,
- 0x112f0, 0x112f9,
- 0x11300, 0x11303,
- 0x11305, 0x1130c,
- 0x1130f, 0x11310,
- 0x11313, 0x11328,
- 0x1132a, 0x11330,
- 0x11332, 0x11333,
- 0x11335, 0x11339,
- 0x1133b, 0x11344,
- 0x11347, 0x11348,
- 0x1134b, 0x1134d,
- 0x11350, 0x11350,
- 0x11357, 0x11357,
- 0x1135d, 0x11363,
- 0x11366, 0x1136c,
- 0x11370, 0x11374,
- 0x11380, 0x11389,
- 0x1138b, 0x1138b,
- 0x1138e, 0x1138e,
- 0x11390, 0x113b5,
- 0x113b7, 0x113c0,
- 0x113c2, 0x113c2,
- 0x113c5, 0x113c5,
- 0x113c7, 0x113ca,
- 0x113cc, 0x113d5,
- 0x113d7, 0x113d8,
- 0x113e1, 0x113e2,
- 0x11400, 0x1145b,
- 0x1145d, 0x11461,
- 0x11480, 0x114c7,
- 0x114d0, 0x114d9,
- 0x11580, 0x115b5,
- 0x115b8, 0x115dd,
- 0x11600, 0x11644,
- 0x11650, 0x11659,
- 0x11660, 0x1166c,
- 0x11680, 0x116b9,
- 0x116c0, 0x116c9,
- 0x116d0, 0x116e3,
- 0x11700, 0x1171a,
- 0x1171d, 0x1172b,
- 0x11730, 0x11746,
- 0x11800, 0x1183b,
- 0x118a0, 0x118f2,
- 0x118ff, 0x11906,
- 0x11909, 0x11909,
- 0x1190c, 0x11913,
- 0x11915, 0x11916,
- 0x11918, 0x11935,
- 0x11937, 0x11938,
- 0x1193b, 0x11946,
- 0x11950, 0x11959,
- 0x119a0, 0x119a7,
- 0x119aa, 0x119d7,
- 0x119da, 0x119e4,
- 0x11a00, 0x11a47,
- 0x11a50, 0x11aa2,
- 0x11ab0, 0x11af8,
- 0x11b00, 0x11b09,
- 0x11bc0, 0x11be1,
- 0x11bf0, 0x11bf9,
- 0x11c00, 0x11c08,
- 0x11c0a, 0x11c36,
- 0x11c38, 0x11c45,
- 0x11c50, 0x11c6c,
- 0x11c70, 0x11c8f,
- 0x11c92, 0x11ca7,
- 0x11ca9, 0x11cb6,
- 0x11d00, 0x11d06,
- 0x11d08, 0x11d09,
- 0x11d0b, 0x11d36,
- 0x11d3a, 0x11d3a,
- 0x11d3c, 0x11d3d,
- 0x11d3f, 0x11d47,
- 0x11d50, 0x11d59,
- 0x11d60, 0x11d65,
- 0x11d67, 0x11d68,
- 0x11d6a, 0x11d8e,
- 0x11d90, 0x11d91,
- 0x11d93, 0x11d98,
- 0x11da0, 0x11da9,
- 0x11ee0, 0x11ef8,
- 0x11f00, 0x11f10,
- 0x11f12, 0x11f3a,
- 0x11f3e, 0x11f5a,
- 0x11fb0, 0x11fb0,
- 0x11fc0, 0x11ff1,
- 0x11fff, 0x12399,
- 0x12400, 0x1246e,
- 0x12470, 0x12474,
- 0x12480, 0x12543,
- 0x12f90, 0x12ff2,
- 0x13000, 0x13455,
- 0x13460, 0x143fa,
- 0x14400, 0x14646,
- 0x16100, 0x16139,
- 0x16800, 0x16a38,
- 0x16a40, 0x16a5e,
- 0x16a60, 0x16a69,
- 0x16a6e, 0x16abe,
- 0x16ac0, 0x16ac9,
- 0x16ad0, 0x16aed,
- 0x16af0, 0x16af5,
- 0x16b00, 0x16b45,
- 0x16b50, 0x16b59,
- 0x16b5b, 0x16b61,
- 0x16b63, 0x16b77,
- 0x16b7d, 0x16b8f,
- 0x16d40, 0x16d79,
- 0x16e40, 0x16e9a,
- 0x16f00, 0x16f4a,
- 0x16f4f, 0x16f87,
- 0x16f8f, 0x16f9f,
- 0x16fe0, 0x16fe4,
- 0x16ff0, 0x16ff1,
- 0x17000, 0x187f7,
- 0x18800, 0x18cd5,
- 0x18cff, 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,
- 0x1bc9c, 0x1bca3,
- 0x1cc00, 0x1ccf9,
- 0x1cd00, 0x1ceb3,
- 0x1cf00, 0x1cf2d,
- 0x1cf30, 0x1cf46,
- 0x1cf50, 0x1cfc3,
- 0x1d000, 0x1d0f5,
- 0x1d100, 0x1d126,
- 0x1d129, 0x1d1ea,
- 0x1d200, 0x1d245,
- 0x1d2c0, 0x1d2d3,
- 0x1d2e0, 0x1d2f3,
- 0x1d300, 0x1d356,
- 0x1d360, 0x1d378,
- 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, 0x1d7cb,
- 0x1d7ce, 0x1da8b,
- 0x1da9b, 0x1da9f,
- 0x1daa1, 0x1daaf,
- 0x1df00, 0x1df1e,
- 0x1df25, 0x1df2a,
- 0x1e000, 0x1e006,
- 0x1e008, 0x1e018,
- 0x1e01b, 0x1e021,
- 0x1e023, 0x1e024,
- 0x1e026, 0x1e02a,
- 0x1e030, 0x1e06d,
- 0x1e08f, 0x1e08f,
- 0x1e100, 0x1e12c,
- 0x1e130, 0x1e13d,
- 0x1e140, 0x1e149,
- 0x1e14e, 0x1e14f,
- 0x1e290, 0x1e2ae,
- 0x1e2c0, 0x1e2f9,
- 0x1e2ff, 0x1e2ff,
- 0x1e4d0, 0x1e4f9,
- 0x1e5d0, 0x1e5fa,
- 0x1e5ff, 0x1e5ff,
- 0x1e7e0, 0x1e7e6,
- 0x1e7e8, 0x1e7eb,
- 0x1e7ed, 0x1e7ee,
- 0x1e7f0, 0x1e7fe,
- 0x1e800, 0x1e8c4,
- 0x1e8c7, 0x1e8d6,
- 0x1e900, 0x1e94b,
- 0x1e950, 0x1e959,
- 0x1e95e, 0x1e95f,
- 0x1ec71, 0x1ecb4,
- 0x1ed01, 0x1ed3d,
- 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,
- 0x1eef0, 0x1eef1,
- 0x1f000, 0x1f02b,
- 0x1f030, 0x1f093,
- 0x1f0a0, 0x1f0ae,
- 0x1f0b1, 0x1f0bf,
- 0x1f0c1, 0x1f0cf,
- 0x1f0d1, 0x1f0f5,
- 0x1f100, 0x1f1ad,
- 0x1f1e6, 0x1f202,
- 0x1f210, 0x1f23b,
- 0x1f240, 0x1f248,
- 0x1f250, 0x1f251,
- 0x1f260, 0x1f265,
- 0x1f300, 0x1f6d7,
- 0x1f6dc, 0x1f6ec,
- 0x1f6f0, 0x1f6fc,
- 0x1f700, 0x1f776,
- 0x1f77b, 0x1f7d9,
- 0x1f7e0, 0x1f7eb,
- 0x1f7f0, 0x1f7f0,
- 0x1f800, 0x1f80b,
- 0x1f810, 0x1f847,
- 0x1f850, 0x1f859,
- 0x1f860, 0x1f887,
- 0x1f890, 0x1f8ad,
- 0x1f8b0, 0x1f8bb,
- 0x1f8c0, 0x1f8c1,
- 0x1f900, 0x1fa53,
- 0x1fa60, 0x1fa6d,
- 0x1fa70, 0x1fa7c,
- 0x1fa80, 0x1fa89,
- 0x1fa8f, 0x1fac6,
- 0x1face, 0x1fadc,
- 0x1fadf, 0x1fae9,
- 0x1faf0, 0x1faf8,
- 0x1fb00, 0x1fb92,
- 0x1fb94, 0x1fbf9,
- 0x20000, 0x2a6df,
- 0x2a700, 0x2b739,
- 0x2b740, 0x2b81d,
- 0x2b820, 0x2cea1,
- 0x2ceb0, 0x2ebe0,
- 0x2ebf0, 0x2ee5d,
- 0x2f800, 0x2fa1d,
- 0x30000, 0x3134a,
- 0x31350, 0x323af,
- 0xe0001, 0xe0001,
- 0xe0020, 0xe007f,
- 0xe0100, 0xe01ef,
- 0xf0000, 0xffffd,
- 0x100000, 0x10fffd,
-}; /* CR_Assigned */
-
-/* 'C': Major Category */
-static const OnigCodePoint CR_C[] = {
- 736,
- 0x0000, 0x001f,
- 0x007f, 0x009f,
- 0x00ad, 0x00ad,
- 0x0378, 0x0379,
- 0x0380, 0x0383,
- 0x038b, 0x038b,
- 0x038d, 0x038d,
- 0x03a2, 0x03a2,
- 0x0530, 0x0530,
- 0x0557, 0x0558,
- 0x058b, 0x058c,
- 0x0590, 0x0590,
- 0x05c8, 0x05cf,
- 0x05eb, 0x05ee,
- 0x05f5, 0x0605,
- 0x061c, 0x061c,
- 0x06dd, 0x06dd,
- 0x070e, 0x070f,
- 0x074b, 0x074c,
- 0x07b2, 0x07bf,
- 0x07fb, 0x07fc,
- 0x082e, 0x082f,
- 0x083f, 0x083f,
- 0x085c, 0x085d,
- 0x085f, 0x085f,
- 0x086b, 0x086f,
- 0x088f, 0x0896,
- 0x08e2, 0x08e2,
- 0x0984, 0x0984,
- 0x098d, 0x098e,
- 0x0991, 0x0992,
- 0x09a9, 0x09a9,
- 0x09b1, 0x09b1,
- 0x09b3, 0x09b5,
- 0x09ba, 0x09bb,
- 0x09c5, 0x09c6,
- 0x09c9, 0x09ca,
- 0x09cf, 0x09d6,
- 0x09d8, 0x09db,
- 0x09de, 0x09de,
- 0x09e4, 0x09e5,
- 0x09ff, 0x0a00,
- 0x0a04, 0x0a04,
- 0x0a0b, 0x0a0e,
- 0x0a11, 0x0a12,
- 0x0a29, 0x0a29,
- 0x0a31, 0x0a31,
- 0x0a34, 0x0a34,
- 0x0a37, 0x0a37,
- 0x0a3a, 0x0a3b,
- 0x0a3d, 0x0a3d,
- 0x0a43, 0x0a46,
- 0x0a49, 0x0a4a,
- 0x0a4e, 0x0a50,
- 0x0a52, 0x0a58,
- 0x0a5d, 0x0a5d,
- 0x0a5f, 0x0a65,
- 0x0a77, 0x0a80,
- 0x0a84, 0x0a84,
- 0x0a8e, 0x0a8e,
- 0x0a92, 0x0a92,
- 0x0aa9, 0x0aa9,
- 0x0ab1, 0x0ab1,
- 0x0ab4, 0x0ab4,
- 0x0aba, 0x0abb,
- 0x0ac6, 0x0ac6,
- 0x0aca, 0x0aca,
- 0x0ace, 0x0acf,
- 0x0ad1, 0x0adf,
- 0x0ae4, 0x0ae5,
- 0x0af2, 0x0af8,
- 0x0b00, 0x0b00,
- 0x0b04, 0x0b04,
- 0x0b0d, 0x0b0e,
- 0x0b11, 0x0b12,
- 0x0b29, 0x0b29,
- 0x0b31, 0x0b31,
- 0x0b34, 0x0b34,
- 0x0b3a, 0x0b3b,
- 0x0b45, 0x0b46,
- 0x0b49, 0x0b4a,
- 0x0b4e, 0x0b54,
- 0x0b58, 0x0b5b,
- 0x0b5e, 0x0b5e,
- 0x0b64, 0x0b65,
- 0x0b78, 0x0b81,
- 0x0b84, 0x0b84,
- 0x0b8b, 0x0b8d,
- 0x0b91, 0x0b91,
- 0x0b96, 0x0b98,
- 0x0b9b, 0x0b9b,
- 0x0b9d, 0x0b9d,
- 0x0ba0, 0x0ba2,
- 0x0ba5, 0x0ba7,
- 0x0bab, 0x0bad,
- 0x0bba, 0x0bbd,
- 0x0bc3, 0x0bc5,
- 0x0bc9, 0x0bc9,
- 0x0bce, 0x0bcf,
- 0x0bd1, 0x0bd6,
- 0x0bd8, 0x0be5,
- 0x0bfb, 0x0bff,
- 0x0c0d, 0x0c0d,
- 0x0c11, 0x0c11,
- 0x0c29, 0x0c29,
- 0x0c3a, 0x0c3b,
- 0x0c45, 0x0c45,
- 0x0c49, 0x0c49,
- 0x0c4e, 0x0c54,
- 0x0c57, 0x0c57,
- 0x0c5b, 0x0c5c,
- 0x0c5e, 0x0c5f,
- 0x0c64, 0x0c65,
- 0x0c70, 0x0c76,
- 0x0c8d, 0x0c8d,
- 0x0c91, 0x0c91,
- 0x0ca9, 0x0ca9,
- 0x0cb4, 0x0cb4,
- 0x0cba, 0x0cbb,
- 0x0cc5, 0x0cc5,
- 0x0cc9, 0x0cc9,
- 0x0cce, 0x0cd4,
- 0x0cd7, 0x0cdc,
- 0x0cdf, 0x0cdf,
- 0x0ce4, 0x0ce5,
- 0x0cf0, 0x0cf0,
- 0x0cf4, 0x0cff,
- 0x0d0d, 0x0d0d,
- 0x0d11, 0x0d11,
- 0x0d45, 0x0d45,
- 0x0d49, 0x0d49,
- 0x0d50, 0x0d53,
- 0x0d64, 0x0d65,
- 0x0d80, 0x0d80,
- 0x0d84, 0x0d84,
- 0x0d97, 0x0d99,
- 0x0db2, 0x0db2,
- 0x0dbc, 0x0dbc,
- 0x0dbe, 0x0dbf,
- 0x0dc7, 0x0dc9,
- 0x0dcb, 0x0dce,
- 0x0dd5, 0x0dd5,
- 0x0dd7, 0x0dd7,
- 0x0de0, 0x0de5,
- 0x0df0, 0x0df1,
- 0x0df5, 0x0e00,
- 0x0e3b, 0x0e3e,
- 0x0e5c, 0x0e80,
- 0x0e83, 0x0e83,
- 0x0e85, 0x0e85,
- 0x0e8b, 0x0e8b,
- 0x0ea4, 0x0ea4,
- 0x0ea6, 0x0ea6,
- 0x0ebe, 0x0ebf,
- 0x0ec5, 0x0ec5,
- 0x0ec7, 0x0ec7,
- 0x0ecf, 0x0ecf,
- 0x0eda, 0x0edb,
- 0x0ee0, 0x0eff,
- 0x0f48, 0x0f48,
- 0x0f6d, 0x0f70,
- 0x0f98, 0x0f98,
- 0x0fbd, 0x0fbd,
- 0x0fcd, 0x0fcd,
- 0x0fdb, 0x0fff,
- 0x10c6, 0x10c6,
- 0x10c8, 0x10cc,
- 0x10ce, 0x10cf,
- 0x1249, 0x1249,
- 0x124e, 0x124f,
- 0x1257, 0x1257,
- 0x1259, 0x1259,
- 0x125e, 0x125f,
- 0x1289, 0x1289,
- 0x128e, 0x128f,
- 0x12b1, 0x12b1,
- 0x12b6, 0x12b7,
- 0x12bf, 0x12bf,
- 0x12c1, 0x12c1,
- 0x12c6, 0x12c7,
- 0x12d7, 0x12d7,
- 0x1311, 0x1311,
- 0x1316, 0x1317,
- 0x135b, 0x135c,
- 0x137d, 0x137f,
- 0x139a, 0x139f,
- 0x13f6, 0x13f7,
- 0x13fe, 0x13ff,
- 0x169d, 0x169f,
- 0x16f9, 0x16ff,
- 0x1716, 0x171e,
- 0x1737, 0x173f,
- 0x1754, 0x175f,
- 0x176d, 0x176d,
- 0x1771, 0x1771,
- 0x1774, 0x177f,
- 0x17de, 0x17df,
- 0x17ea, 0x17ef,
- 0x17fa, 0x17ff,
- 0x180e, 0x180e,
- 0x181a, 0x181f,
- 0x1879, 0x187f,
- 0x18ab, 0x18af,
- 0x18f6, 0x18ff,
- 0x191f, 0x191f,
- 0x192c, 0x192f,
- 0x193c, 0x193f,
- 0x1941, 0x1943,
- 0x196e, 0x196f,
- 0x1975, 0x197f,
- 0x19ac, 0x19af,
- 0x19ca, 0x19cf,
- 0x19db, 0x19dd,
- 0x1a1c, 0x1a1d,
- 0x1a5f, 0x1a5f,
- 0x1a7d, 0x1a7e,
- 0x1a8a, 0x1a8f,
- 0x1a9a, 0x1a9f,
- 0x1aae, 0x1aaf,
- 0x1acf, 0x1aff,
- 0x1b4d, 0x1b4d,
- 0x1bf4, 0x1bfb,
- 0x1c38, 0x1c3a,
- 0x1c4a, 0x1c4c,
- 0x1c8b, 0x1c8f,
- 0x1cbb, 0x1cbc,
- 0x1cc8, 0x1ccf,
- 0x1cfb, 0x1cff,
- 0x1f16, 0x1f17,
- 0x1f1e, 0x1f1f,
- 0x1f46, 0x1f47,
- 0x1f4e, 0x1f4f,
- 0x1f58, 0x1f58,
- 0x1f5a, 0x1f5a,
- 0x1f5c, 0x1f5c,
- 0x1f5e, 0x1f5e,
- 0x1f7e, 0x1f7f,
- 0x1fb5, 0x1fb5,
- 0x1fc5, 0x1fc5,
- 0x1fd4, 0x1fd5,
- 0x1fdc, 0x1fdc,
- 0x1ff0, 0x1ff1,
- 0x1ff5, 0x1ff5,
- 0x1fff, 0x1fff,
- 0x200b, 0x200f,
- 0x202a, 0x202e,
- 0x2060, 0x206f,
- 0x2072, 0x2073,
- 0x208f, 0x208f,
- 0x209d, 0x209f,
- 0x20c1, 0x20cf,
- 0x20f1, 0x20ff,
- 0x218c, 0x218f,
- 0x242a, 0x243f,
- 0x244b, 0x245f,
- 0x2b74, 0x2b75,
- 0x2b96, 0x2b96,
- 0x2cf4, 0x2cf8,
- 0x2d26, 0x2d26,
- 0x2d28, 0x2d2c,
- 0x2d2e, 0x2d2f,
- 0x2d68, 0x2d6e,
- 0x2d71, 0x2d7e,
- 0x2d97, 0x2d9f,
- 0x2da7, 0x2da7,
- 0x2daf, 0x2daf,
- 0x2db7, 0x2db7,
- 0x2dbf, 0x2dbf,
- 0x2dc7, 0x2dc7,
- 0x2dcf, 0x2dcf,
- 0x2dd7, 0x2dd7,
- 0x2ddf, 0x2ddf,
- 0x2e5e, 0x2e7f,
- 0x2e9a, 0x2e9a,
- 0x2ef4, 0x2eff,
- 0x2fd6, 0x2fef,
- 0x3040, 0x3040,
- 0x3097, 0x3098,
- 0x3100, 0x3104,
- 0x3130, 0x3130,
- 0x318f, 0x318f,
- 0x31e6, 0x31ee,
- 0x321f, 0x321f,
- 0xa48d, 0xa48f,
- 0xa4c7, 0xa4cf,
- 0xa62c, 0xa63f,
- 0xa6f8, 0xa6ff,
- 0xa7ce, 0xa7cf,
- 0xa7d2, 0xa7d2,
- 0xa7d4, 0xa7d4,
- 0xa7dd, 0xa7f1,
- 0xa82d, 0xa82f,
- 0xa83a, 0xa83f,
- 0xa878, 0xa87f,
- 0xa8c6, 0xa8cd,
- 0xa8da, 0xa8df,
- 0xa954, 0xa95e,
- 0xa97d, 0xa97f,
- 0xa9ce, 0xa9ce,
- 0xa9da, 0xa9dd,
- 0xa9ff, 0xa9ff,
- 0xaa37, 0xaa3f,
- 0xaa4e, 0xaa4f,
- 0xaa5a, 0xaa5b,
- 0xaac3, 0xaada,
- 0xaaf7, 0xab00,
- 0xab07, 0xab08,
- 0xab0f, 0xab10,
- 0xab17, 0xab1f,
- 0xab27, 0xab27,
- 0xab2f, 0xab2f,
- 0xab6c, 0xab6f,
- 0xabee, 0xabef,
- 0xabfa, 0xabff,
- 0xd7a4, 0xd7af,
- 0xd7c7, 0xd7ca,
- 0xd7fc, 0xf8ff,
- 0xfa6e, 0xfa6f,
- 0xfada, 0xfaff,
- 0xfb07, 0xfb12,
- 0xfb18, 0xfb1c,
- 0xfb37, 0xfb37,
- 0xfb3d, 0xfb3d,
- 0xfb3f, 0xfb3f,
- 0xfb42, 0xfb42,
- 0xfb45, 0xfb45,
- 0xfbc3, 0xfbd2,
- 0xfd90, 0xfd91,
- 0xfdc8, 0xfdce,
- 0xfdd0, 0xfdef,
- 0xfe1a, 0xfe1f,
- 0xfe53, 0xfe53,
- 0xfe67, 0xfe67,
- 0xfe6c, 0xfe6f,
- 0xfe75, 0xfe75,
- 0xfefd, 0xff00,
- 0xffbf, 0xffc1,
- 0xffc8, 0xffc9,
- 0xffd0, 0xffd1,
- 0xffd8, 0xffd9,
- 0xffdd, 0xffdf,
- 0xffe7, 0xffe7,
- 0xffef, 0xfffb,
- 0xfffe, 0xffff,
- 0x1000c, 0x1000c,
- 0x10027, 0x10027,
- 0x1003b, 0x1003b,
- 0x1003e, 0x1003e,
- 0x1004e, 0x1004f,
- 0x1005e, 0x1007f,
- 0x100fb, 0x100ff,
- 0x10103, 0x10106,
- 0x10134, 0x10136,
- 0x1018f, 0x1018f,
- 0x1019d, 0x1019f,
- 0x101a1, 0x101cf,
- 0x101fe, 0x1027f,
- 0x1029d, 0x1029f,
- 0x102d1, 0x102df,
- 0x102fc, 0x102ff,
- 0x10324, 0x1032c,
- 0x1034b, 0x1034f,
- 0x1037b, 0x1037f,
- 0x1039e, 0x1039e,
- 0x103c4, 0x103c7,
- 0x103d6, 0x103ff,
- 0x1049e, 0x1049f,
- 0x104aa, 0x104af,
- 0x104d4, 0x104d7,
- 0x104fc, 0x104ff,
- 0x10528, 0x1052f,
- 0x10564, 0x1056e,
- 0x1057b, 0x1057b,
- 0x1058b, 0x1058b,
- 0x10593, 0x10593,
- 0x10596, 0x10596,
- 0x105a2, 0x105a2,
- 0x105b2, 0x105b2,
- 0x105ba, 0x105ba,
- 0x105bd, 0x105bf,
- 0x105f4, 0x105ff,
- 0x10737, 0x1073f,
- 0x10756, 0x1075f,
- 0x10768, 0x1077f,
- 0x10786, 0x10786,
- 0x107b1, 0x107b1,
- 0x107bb, 0x107ff,
- 0x10806, 0x10807,
- 0x10809, 0x10809,
- 0x10836, 0x10836,
- 0x10839, 0x1083b,
- 0x1083d, 0x1083e,
- 0x10856, 0x10856,
- 0x1089f, 0x108a6,
- 0x108b0, 0x108df,
- 0x108f3, 0x108f3,
- 0x108f6, 0x108fa,
- 0x1091c, 0x1091e,
- 0x1093a, 0x1093e,
- 0x10940, 0x1097f,
- 0x109b8, 0x109bb,
- 0x109d0, 0x109d1,
- 0x10a04, 0x10a04,
- 0x10a07, 0x10a0b,
- 0x10a14, 0x10a14,
- 0x10a18, 0x10a18,
- 0x10a36, 0x10a37,
- 0x10a3b, 0x10a3e,
- 0x10a49, 0x10a4f,
- 0x10a59, 0x10a5f,
- 0x10aa0, 0x10abf,
- 0x10ae7, 0x10aea,
- 0x10af7, 0x10aff,
- 0x10b36, 0x10b38,
- 0x10b56, 0x10b57,
- 0x10b73, 0x10b77,
- 0x10b92, 0x10b98,
- 0x10b9d, 0x10ba8,
- 0x10bb0, 0x10bff,
- 0x10c49, 0x10c7f,
- 0x10cb3, 0x10cbf,
- 0x10cf3, 0x10cf9,
- 0x10d28, 0x10d2f,
- 0x10d3a, 0x10d3f,
- 0x10d66, 0x10d68,
- 0x10d86, 0x10d8d,
- 0x10d90, 0x10e5f,
- 0x10e7f, 0x10e7f,
- 0x10eaa, 0x10eaa,
- 0x10eae, 0x10eaf,
- 0x10eb2, 0x10ec1,
- 0x10ec5, 0x10efb,
- 0x10f28, 0x10f2f,
- 0x10f5a, 0x10f6f,
- 0x10f8a, 0x10faf,
- 0x10fcc, 0x10fdf,
- 0x10ff7, 0x10fff,
- 0x1104e, 0x11051,
- 0x11076, 0x1107e,
- 0x110bd, 0x110bd,
- 0x110c3, 0x110cf,
- 0x110e9, 0x110ef,
- 0x110fa, 0x110ff,
- 0x11135, 0x11135,
- 0x11148, 0x1114f,
- 0x11177, 0x1117f,
- 0x111e0, 0x111e0,
- 0x111f5, 0x111ff,
- 0x11212, 0x11212,
- 0x11242, 0x1127f,
- 0x11287, 0x11287,
- 0x11289, 0x11289,
- 0x1128e, 0x1128e,
- 0x1129e, 0x1129e,
- 0x112aa, 0x112af,
- 0x112eb, 0x112ef,
- 0x112fa, 0x112ff,
- 0x11304, 0x11304,
- 0x1130d, 0x1130e,
- 0x11311, 0x11312,
- 0x11329, 0x11329,
- 0x11331, 0x11331,
- 0x11334, 0x11334,
- 0x1133a, 0x1133a,
- 0x11345, 0x11346,
- 0x11349, 0x1134a,
- 0x1134e, 0x1134f,
- 0x11351, 0x11356,
- 0x11358, 0x1135c,
- 0x11364, 0x11365,
- 0x1136d, 0x1136f,
- 0x11375, 0x1137f,
- 0x1138a, 0x1138a,
- 0x1138c, 0x1138d,
- 0x1138f, 0x1138f,
- 0x113b6, 0x113b6,
- 0x113c1, 0x113c1,
- 0x113c3, 0x113c4,
- 0x113c6, 0x113c6,
- 0x113cb, 0x113cb,
- 0x113d6, 0x113d6,
- 0x113d9, 0x113e0,
- 0x113e3, 0x113ff,
- 0x1145c, 0x1145c,
- 0x11462, 0x1147f,
- 0x114c8, 0x114cf,
- 0x114da, 0x1157f,
- 0x115b6, 0x115b7,
- 0x115de, 0x115ff,
- 0x11645, 0x1164f,
- 0x1165a, 0x1165f,
- 0x1166d, 0x1167f,
- 0x116ba, 0x116bf,
- 0x116ca, 0x116cf,
- 0x116e4, 0x116ff,
- 0x1171b, 0x1171c,
- 0x1172c, 0x1172f,
- 0x11747, 0x117ff,
- 0x1183c, 0x1189f,
- 0x118f3, 0x118fe,
- 0x11907, 0x11908,
- 0x1190a, 0x1190b,
- 0x11914, 0x11914,
- 0x11917, 0x11917,
- 0x11936, 0x11936,
- 0x11939, 0x1193a,
- 0x11947, 0x1194f,
- 0x1195a, 0x1199f,
- 0x119a8, 0x119a9,
- 0x119d8, 0x119d9,
- 0x119e5, 0x119ff,
- 0x11a48, 0x11a4f,
- 0x11aa3, 0x11aaf,
- 0x11af9, 0x11aff,
- 0x11b0a, 0x11bbf,
- 0x11be2, 0x11bef,
- 0x11bfa, 0x11bff,
- 0x11c09, 0x11c09,
- 0x11c37, 0x11c37,
- 0x11c46, 0x11c4f,
- 0x11c6d, 0x11c6f,
- 0x11c90, 0x11c91,
- 0x11ca8, 0x11ca8,
- 0x11cb7, 0x11cff,
- 0x11d07, 0x11d07,
- 0x11d0a, 0x11d0a,
- 0x11d37, 0x11d39,
- 0x11d3b, 0x11d3b,
- 0x11d3e, 0x11d3e,
- 0x11d48, 0x11d4f,
- 0x11d5a, 0x11d5f,
- 0x11d66, 0x11d66,
- 0x11d69, 0x11d69,
- 0x11d8f, 0x11d8f,
- 0x11d92, 0x11d92,
- 0x11d99, 0x11d9f,
- 0x11daa, 0x11edf,
- 0x11ef9, 0x11eff,
- 0x11f11, 0x11f11,
- 0x11f3b, 0x11f3d,
- 0x11f5b, 0x11faf,
- 0x11fb1, 0x11fbf,
- 0x11ff2, 0x11ffe,
- 0x1239a, 0x123ff,
- 0x1246f, 0x1246f,
- 0x12475, 0x1247f,
- 0x12544, 0x12f8f,
- 0x12ff3, 0x12fff,
- 0x13430, 0x1343f,
- 0x13456, 0x1345f,
- 0x143fb, 0x143ff,
- 0x14647, 0x160ff,
- 0x1613a, 0x167ff,
- 0x16a39, 0x16a3f,
- 0x16a5f, 0x16a5f,
- 0x16a6a, 0x16a6d,
- 0x16abf, 0x16abf,
- 0x16aca, 0x16acf,
- 0x16aee, 0x16aef,
- 0x16af6, 0x16aff,
- 0x16b46, 0x16b4f,
- 0x16b5a, 0x16b5a,
- 0x16b62, 0x16b62,
- 0x16b78, 0x16b7c,
- 0x16b90, 0x16d3f,
- 0x16d7a, 0x16e3f,
- 0x16e9b, 0x16eff,
- 0x16f4b, 0x16f4e,
- 0x16f88, 0x16f8e,
- 0x16fa0, 0x16fdf,
- 0x16fe5, 0x16fef,
- 0x16ff2, 0x16fff,
- 0x187f8, 0x187ff,
- 0x18cd6, 0x18cfe,
- 0x18d09, 0x1afef,
- 0x1aff4, 0x1aff4,
- 0x1affc, 0x1affc,
- 0x1afff, 0x1afff,
- 0x1b123, 0x1b131,
- 0x1b133, 0x1b14f,
- 0x1b153, 0x1b154,
- 0x1b156, 0x1b163,
- 0x1b168, 0x1b16f,
- 0x1b2fc, 0x1bbff,
- 0x1bc6b, 0x1bc6f,
- 0x1bc7d, 0x1bc7f,
- 0x1bc89, 0x1bc8f,
- 0x1bc9a, 0x1bc9b,
- 0x1bca0, 0x1cbff,
- 0x1ccfa, 0x1ccff,
- 0x1ceb4, 0x1ceff,
- 0x1cf2e, 0x1cf2f,
- 0x1cf47, 0x1cf4f,
- 0x1cfc4, 0x1cfff,
- 0x1d0f6, 0x1d0ff,
- 0x1d127, 0x1d128,
- 0x1d173, 0x1d17a,
- 0x1d1eb, 0x1d1ff,
- 0x1d246, 0x1d2bf,
- 0x1d2d4, 0x1d2df,
- 0x1d2f4, 0x1d2ff,
- 0x1d357, 0x1d35f,
- 0x1d379, 0x1d3ff,
- 0x1d455, 0x1d455,
- 0x1d49d, 0x1d49d,
- 0x1d4a0, 0x1d4a1,
- 0x1d4a3, 0x1d4a4,
- 0x1d4a7, 0x1d4a8,
- 0x1d4ad, 0x1d4ad,
- 0x1d4ba, 0x1d4ba,
- 0x1d4bc, 0x1d4bc,
- 0x1d4c4, 0x1d4c4,
- 0x1d506, 0x1d506,
- 0x1d50b, 0x1d50c,
- 0x1d515, 0x1d515,
- 0x1d51d, 0x1d51d,
- 0x1d53a, 0x1d53a,
- 0x1d53f, 0x1d53f,
- 0x1d545, 0x1d545,
- 0x1d547, 0x1d549,
- 0x1d551, 0x1d551,
- 0x1d6a6, 0x1d6a7,
- 0x1d7cc, 0x1d7cd,
- 0x1da8c, 0x1da9a,
- 0x1daa0, 0x1daa0,
- 0x1dab0, 0x1deff,
- 0x1df1f, 0x1df24,
- 0x1df2b, 0x1dfff,
- 0x1e007, 0x1e007,
- 0x1e019, 0x1e01a,
- 0x1e022, 0x1e022,
- 0x1e025, 0x1e025,
- 0x1e02b, 0x1e02f,
- 0x1e06e, 0x1e08e,
- 0x1e090, 0x1e0ff,
- 0x1e12d, 0x1e12f,
- 0x1e13e, 0x1e13f,
- 0x1e14a, 0x1e14d,
- 0x1e150, 0x1e28f,
- 0x1e2af, 0x1e2bf,
- 0x1e2fa, 0x1e2fe,
- 0x1e300, 0x1e4cf,
- 0x1e4fa, 0x1e5cf,
- 0x1e5fb, 0x1e5fe,
- 0x1e600, 0x1e7df,
- 0x1e7e7, 0x1e7e7,
- 0x1e7ec, 0x1e7ec,
- 0x1e7ef, 0x1e7ef,
- 0x1e7ff, 0x1e7ff,
- 0x1e8c5, 0x1e8c6,
- 0x1e8d7, 0x1e8ff,
- 0x1e94c, 0x1e94f,
- 0x1e95a, 0x1e95d,
- 0x1e960, 0x1ec70,
- 0x1ecb5, 0x1ed00,
- 0x1ed3e, 0x1edff,
- 0x1ee04, 0x1ee04,
- 0x1ee20, 0x1ee20,
- 0x1ee23, 0x1ee23,
- 0x1ee25, 0x1ee26,
- 0x1ee28, 0x1ee28,
- 0x1ee33, 0x1ee33,
- 0x1ee38, 0x1ee38,
- 0x1ee3a, 0x1ee3a,
- 0x1ee3c, 0x1ee41,
- 0x1ee43, 0x1ee46,
- 0x1ee48, 0x1ee48,
- 0x1ee4a, 0x1ee4a,
- 0x1ee4c, 0x1ee4c,
- 0x1ee50, 0x1ee50,
- 0x1ee53, 0x1ee53,
- 0x1ee55, 0x1ee56,
- 0x1ee58, 0x1ee58,
- 0x1ee5a, 0x1ee5a,
- 0x1ee5c, 0x1ee5c,
- 0x1ee5e, 0x1ee5e,
- 0x1ee60, 0x1ee60,
- 0x1ee63, 0x1ee63,
- 0x1ee65, 0x1ee66,
- 0x1ee6b, 0x1ee6b,
- 0x1ee73, 0x1ee73,
- 0x1ee78, 0x1ee78,
- 0x1ee7d, 0x1ee7d,
- 0x1ee7f, 0x1ee7f,
- 0x1ee8a, 0x1ee8a,
- 0x1ee9c, 0x1eea0,
- 0x1eea4, 0x1eea4,
- 0x1eeaa, 0x1eeaa,
- 0x1eebc, 0x1eeef,
- 0x1eef2, 0x1efff,
- 0x1f02c, 0x1f02f,
- 0x1f094, 0x1f09f,
- 0x1f0af, 0x1f0b0,
- 0x1f0c0, 0x1f0c0,
- 0x1f0d0, 0x1f0d0,
- 0x1f0f6, 0x1f0ff,
- 0x1f1ae, 0x1f1e5,
- 0x1f203, 0x1f20f,
- 0x1f23c, 0x1f23f,
- 0x1f249, 0x1f24f,
- 0x1f252, 0x1f25f,
- 0x1f266, 0x1f2ff,
- 0x1f6d8, 0x1f6db,
- 0x1f6ed, 0x1f6ef,
- 0x1f6fd, 0x1f6ff,
- 0x1f777, 0x1f77a,
- 0x1f7da, 0x1f7df,
- 0x1f7ec, 0x1f7ef,
- 0x1f7f1, 0x1f7ff,
- 0x1f80c, 0x1f80f,
- 0x1f848, 0x1f84f,
- 0x1f85a, 0x1f85f,
- 0x1f888, 0x1f88f,
- 0x1f8ae, 0x1f8af,
- 0x1f8bc, 0x1f8bf,
- 0x1f8c2, 0x1f8ff,
- 0x1fa54, 0x1fa5f,
- 0x1fa6e, 0x1fa6f,
- 0x1fa7d, 0x1fa7f,
- 0x1fa8a, 0x1fa8e,
- 0x1fac7, 0x1facd,
- 0x1fadd, 0x1fade,
- 0x1faea, 0x1faef,
- 0x1faf9, 0x1faff,
- 0x1fb93, 0x1fb93,
- 0x1fbfa, 0x1ffff,
- 0x2a6e0, 0x2a6ff,
- 0x2b73a, 0x2b73f,
- 0x2b81e, 0x2b81f,
- 0x2cea2, 0x2ceaf,
- 0x2ebe1, 0x2ebef,
- 0x2ee5e, 0x2f7ff,
- 0x2fa1e, 0x2ffff,
- 0x3134b, 0x3134f,
- 0x323b0, 0xe00ff,
- 0xe01f0, 0x10ffff,
-}; /* CR_C */
-
-/* 'Cc': General Category */
-#define CR_Cc CR_Cntrl
-
-/* 'Cf': General Category */
-static const OnigCodePoint CR_Cf[] = {
- 21,
- 0x00ad, 0x00ad,
- 0x0600, 0x0605,
- 0x061c, 0x061c,
- 0x06dd, 0x06dd,
- 0x070f, 0x070f,
- 0x0890, 0x0891,
- 0x08e2, 0x08e2,
- 0x180e, 0x180e,
- 0x200b, 0x200f,
- 0x202a, 0x202e,
- 0x2060, 0x2064,
- 0x2066, 0x206f,
- 0xfeff, 0xfeff,
- 0xfff9, 0xfffb,
- 0x110bd, 0x110bd,
- 0x110cd, 0x110cd,
- 0x13430, 0x1343f,
- 0x1bca0, 0x1bca3,
- 0x1d173, 0x1d17a,
- 0xe0001, 0xe0001,
- 0xe0020, 0xe007f,
-}; /* CR_Cf */
-
-/* 'Cn': General Category */
-static const OnigCodePoint CR_Cn[] = {
- 731,
- 0x0378, 0x0379,
- 0x0380, 0x0383,
- 0x038b, 0x038b,
- 0x038d, 0x038d,
- 0x03a2, 0x03a2,
- 0x0530, 0x0530,
- 0x0557, 0x0558,
- 0x058b, 0x058c,
- 0x0590, 0x0590,
- 0x05c8, 0x05cf,
- 0x05eb, 0x05ee,
- 0x05f5, 0x05ff,
- 0x070e, 0x070e,
- 0x074b, 0x074c,
- 0x07b2, 0x07bf,
- 0x07fb, 0x07fc,
- 0x082e, 0x082f,
- 0x083f, 0x083f,
- 0x085c, 0x085d,
- 0x085f, 0x085f,
- 0x086b, 0x086f,
- 0x088f, 0x088f,
- 0x0892, 0x0896,
- 0x0984, 0x0984,
- 0x098d, 0x098e,
- 0x0991, 0x0992,
- 0x09a9, 0x09a9,
- 0x09b1, 0x09b1,
- 0x09b3, 0x09b5,
- 0x09ba, 0x09bb,
- 0x09c5, 0x09c6,
- 0x09c9, 0x09ca,
- 0x09cf, 0x09d6,
- 0x09d8, 0x09db,
- 0x09de, 0x09de,
- 0x09e4, 0x09e5,
- 0x09ff, 0x0a00,
- 0x0a04, 0x0a04,
- 0x0a0b, 0x0a0e,
- 0x0a11, 0x0a12,
- 0x0a29, 0x0a29,
- 0x0a31, 0x0a31,
- 0x0a34, 0x0a34,
- 0x0a37, 0x0a37,
- 0x0a3a, 0x0a3b,
- 0x0a3d, 0x0a3d,
- 0x0a43, 0x0a46,
- 0x0a49, 0x0a4a,
- 0x0a4e, 0x0a50,
- 0x0a52, 0x0a58,
- 0x0a5d, 0x0a5d,
- 0x0a5f, 0x0a65,
- 0x0a77, 0x0a80,
- 0x0a84, 0x0a84,
- 0x0a8e, 0x0a8e,
- 0x0a92, 0x0a92,
- 0x0aa9, 0x0aa9,
- 0x0ab1, 0x0ab1,
- 0x0ab4, 0x0ab4,
- 0x0aba, 0x0abb,
- 0x0ac6, 0x0ac6,
- 0x0aca, 0x0aca,
- 0x0ace, 0x0acf,
- 0x0ad1, 0x0adf,
- 0x0ae4, 0x0ae5,
- 0x0af2, 0x0af8,
- 0x0b00, 0x0b00,
- 0x0b04, 0x0b04,
- 0x0b0d, 0x0b0e,
- 0x0b11, 0x0b12,
- 0x0b29, 0x0b29,
- 0x0b31, 0x0b31,
- 0x0b34, 0x0b34,
- 0x0b3a, 0x0b3b,
- 0x0b45, 0x0b46,
- 0x0b49, 0x0b4a,
- 0x0b4e, 0x0b54,
- 0x0b58, 0x0b5b,
- 0x0b5e, 0x0b5e,
- 0x0b64, 0x0b65,
- 0x0b78, 0x0b81,
- 0x0b84, 0x0b84,
- 0x0b8b, 0x0b8d,
- 0x0b91, 0x0b91,
- 0x0b96, 0x0b98,
- 0x0b9b, 0x0b9b,
- 0x0b9d, 0x0b9d,
- 0x0ba0, 0x0ba2,
- 0x0ba5, 0x0ba7,
- 0x0bab, 0x0bad,
- 0x0bba, 0x0bbd,
- 0x0bc3, 0x0bc5,
- 0x0bc9, 0x0bc9,
- 0x0bce, 0x0bcf,
- 0x0bd1, 0x0bd6,
- 0x0bd8, 0x0be5,
- 0x0bfb, 0x0bff,
- 0x0c0d, 0x0c0d,
- 0x0c11, 0x0c11,
- 0x0c29, 0x0c29,
- 0x0c3a, 0x0c3b,
- 0x0c45, 0x0c45,
- 0x0c49, 0x0c49,
- 0x0c4e, 0x0c54,
- 0x0c57, 0x0c57,
- 0x0c5b, 0x0c5c,
- 0x0c5e, 0x0c5f,
- 0x0c64, 0x0c65,
- 0x0c70, 0x0c76,
- 0x0c8d, 0x0c8d,
- 0x0c91, 0x0c91,
- 0x0ca9, 0x0ca9,
- 0x0cb4, 0x0cb4,
- 0x0cba, 0x0cbb,
- 0x0cc5, 0x0cc5,
- 0x0cc9, 0x0cc9,
- 0x0cce, 0x0cd4,
- 0x0cd7, 0x0cdc,
- 0x0cdf, 0x0cdf,
- 0x0ce4, 0x0ce5,
- 0x0cf0, 0x0cf0,
- 0x0cf4, 0x0cff,
- 0x0d0d, 0x0d0d,
- 0x0d11, 0x0d11,
- 0x0d45, 0x0d45,
- 0x0d49, 0x0d49,
- 0x0d50, 0x0d53,
- 0x0d64, 0x0d65,
- 0x0d80, 0x0d80,
- 0x0d84, 0x0d84,
- 0x0d97, 0x0d99,
- 0x0db2, 0x0db2,
- 0x0dbc, 0x0dbc,
- 0x0dbe, 0x0dbf,
- 0x0dc7, 0x0dc9,
- 0x0dcb, 0x0dce,
- 0x0dd5, 0x0dd5,
- 0x0dd7, 0x0dd7,
- 0x0de0, 0x0de5,
- 0x0df0, 0x0df1,
- 0x0df5, 0x0e00,
- 0x0e3b, 0x0e3e,
- 0x0e5c, 0x0e80,
- 0x0e83, 0x0e83,
- 0x0e85, 0x0e85,
- 0x0e8b, 0x0e8b,
- 0x0ea4, 0x0ea4,
- 0x0ea6, 0x0ea6,
- 0x0ebe, 0x0ebf,
- 0x0ec5, 0x0ec5,
- 0x0ec7, 0x0ec7,
- 0x0ecf, 0x0ecf,
- 0x0eda, 0x0edb,
- 0x0ee0, 0x0eff,
- 0x0f48, 0x0f48,
- 0x0f6d, 0x0f70,
- 0x0f98, 0x0f98,
- 0x0fbd, 0x0fbd,
- 0x0fcd, 0x0fcd,
- 0x0fdb, 0x0fff,
- 0x10c6, 0x10c6,
- 0x10c8, 0x10cc,
- 0x10ce, 0x10cf,
- 0x1249, 0x1249,
- 0x124e, 0x124f,
- 0x1257, 0x1257,
- 0x1259, 0x1259,
- 0x125e, 0x125f,
- 0x1289, 0x1289,
- 0x128e, 0x128f,
- 0x12b1, 0x12b1,
- 0x12b6, 0x12b7,
- 0x12bf, 0x12bf,
- 0x12c1, 0x12c1,
- 0x12c6, 0x12c7,
- 0x12d7, 0x12d7,
- 0x1311, 0x1311,
- 0x1316, 0x1317,
- 0x135b, 0x135c,
- 0x137d, 0x137f,
- 0x139a, 0x139f,
- 0x13f6, 0x13f7,
- 0x13fe, 0x13ff,
- 0x169d, 0x169f,
- 0x16f9, 0x16ff,
- 0x1716, 0x171e,
- 0x1737, 0x173f,
- 0x1754, 0x175f,
- 0x176d, 0x176d,
- 0x1771, 0x1771,
- 0x1774, 0x177f,
- 0x17de, 0x17df,
- 0x17ea, 0x17ef,
- 0x17fa, 0x17ff,
- 0x181a, 0x181f,
- 0x1879, 0x187f,
- 0x18ab, 0x18af,
- 0x18f6, 0x18ff,
- 0x191f, 0x191f,
- 0x192c, 0x192f,
- 0x193c, 0x193f,
- 0x1941, 0x1943,
- 0x196e, 0x196f,
- 0x1975, 0x197f,
- 0x19ac, 0x19af,
- 0x19ca, 0x19cf,
- 0x19db, 0x19dd,
- 0x1a1c, 0x1a1d,
- 0x1a5f, 0x1a5f,
- 0x1a7d, 0x1a7e,
- 0x1a8a, 0x1a8f,
- 0x1a9a, 0x1a9f,
- 0x1aae, 0x1aaf,
- 0x1acf, 0x1aff,
- 0x1b4d, 0x1b4d,
- 0x1bf4, 0x1bfb,
- 0x1c38, 0x1c3a,
- 0x1c4a, 0x1c4c,
- 0x1c8b, 0x1c8f,
- 0x1cbb, 0x1cbc,
- 0x1cc8, 0x1ccf,
- 0x1cfb, 0x1cff,
- 0x1f16, 0x1f17,
- 0x1f1e, 0x1f1f,
- 0x1f46, 0x1f47,
- 0x1f4e, 0x1f4f,
- 0x1f58, 0x1f58,
- 0x1f5a, 0x1f5a,
- 0x1f5c, 0x1f5c,
- 0x1f5e, 0x1f5e,
- 0x1f7e, 0x1f7f,
- 0x1fb5, 0x1fb5,
- 0x1fc5, 0x1fc5,
- 0x1fd4, 0x1fd5,
- 0x1fdc, 0x1fdc,
- 0x1ff0, 0x1ff1,
- 0x1ff5, 0x1ff5,
- 0x1fff, 0x1fff,
- 0x2065, 0x2065,
- 0x2072, 0x2073,
- 0x208f, 0x208f,
- 0x209d, 0x209f,
- 0x20c1, 0x20cf,
- 0x20f1, 0x20ff,
- 0x218c, 0x218f,
- 0x242a, 0x243f,
- 0x244b, 0x245f,
- 0x2b74, 0x2b75,
- 0x2b96, 0x2b96,
- 0x2cf4, 0x2cf8,
- 0x2d26, 0x2d26,
- 0x2d28, 0x2d2c,
- 0x2d2e, 0x2d2f,
- 0x2d68, 0x2d6e,
- 0x2d71, 0x2d7e,
- 0x2d97, 0x2d9f,
- 0x2da7, 0x2da7,
- 0x2daf, 0x2daf,
- 0x2db7, 0x2db7,
- 0x2dbf, 0x2dbf,
- 0x2dc7, 0x2dc7,
- 0x2dcf, 0x2dcf,
- 0x2dd7, 0x2dd7,
- 0x2ddf, 0x2ddf,
- 0x2e5e, 0x2e7f,
- 0x2e9a, 0x2e9a,
- 0x2ef4, 0x2eff,
- 0x2fd6, 0x2fef,
- 0x3040, 0x3040,
- 0x3097, 0x3098,
- 0x3100, 0x3104,
- 0x3130, 0x3130,
- 0x318f, 0x318f,
- 0x31e6, 0x31ee,
- 0x321f, 0x321f,
- 0xa48d, 0xa48f,
- 0xa4c7, 0xa4cf,
- 0xa62c, 0xa63f,
- 0xa6f8, 0xa6ff,
- 0xa7ce, 0xa7cf,
- 0xa7d2, 0xa7d2,
- 0xa7d4, 0xa7d4,
- 0xa7dd, 0xa7f1,
- 0xa82d, 0xa82f,
- 0xa83a, 0xa83f,
- 0xa878, 0xa87f,
- 0xa8c6, 0xa8cd,
- 0xa8da, 0xa8df,
- 0xa954, 0xa95e,
- 0xa97d, 0xa97f,
- 0xa9ce, 0xa9ce,
- 0xa9da, 0xa9dd,
- 0xa9ff, 0xa9ff,
- 0xaa37, 0xaa3f,
- 0xaa4e, 0xaa4f,
- 0xaa5a, 0xaa5b,
- 0xaac3, 0xaada,
- 0xaaf7, 0xab00,
- 0xab07, 0xab08,
- 0xab0f, 0xab10,
- 0xab17, 0xab1f,
- 0xab27, 0xab27,
- 0xab2f, 0xab2f,
- 0xab6c, 0xab6f,
- 0xabee, 0xabef,
- 0xabfa, 0xabff,
- 0xd7a4, 0xd7af,
- 0xd7c7, 0xd7ca,
- 0xd7fc, 0xd7ff,
- 0xfa6e, 0xfa6f,
- 0xfada, 0xfaff,
- 0xfb07, 0xfb12,
- 0xfb18, 0xfb1c,
- 0xfb37, 0xfb37,
- 0xfb3d, 0xfb3d,
- 0xfb3f, 0xfb3f,
- 0xfb42, 0xfb42,
- 0xfb45, 0xfb45,
- 0xfbc3, 0xfbd2,
- 0xfd90, 0xfd91,
- 0xfdc8, 0xfdce,
- 0xfdd0, 0xfdef,
- 0xfe1a, 0xfe1f,
- 0xfe53, 0xfe53,
- 0xfe67, 0xfe67,
- 0xfe6c, 0xfe6f,
- 0xfe75, 0xfe75,
- 0xfefd, 0xfefe,
- 0xff00, 0xff00,
- 0xffbf, 0xffc1,
- 0xffc8, 0xffc9,
- 0xffd0, 0xffd1,
- 0xffd8, 0xffd9,
- 0xffdd, 0xffdf,
- 0xffe7, 0xffe7,
- 0xffef, 0xfff8,
- 0xfffe, 0xffff,
- 0x1000c, 0x1000c,
- 0x10027, 0x10027,
- 0x1003b, 0x1003b,
- 0x1003e, 0x1003e,
- 0x1004e, 0x1004f,
- 0x1005e, 0x1007f,
- 0x100fb, 0x100ff,
- 0x10103, 0x10106,
- 0x10134, 0x10136,
- 0x1018f, 0x1018f,
- 0x1019d, 0x1019f,
- 0x101a1, 0x101cf,
- 0x101fe, 0x1027f,
- 0x1029d, 0x1029f,
- 0x102d1, 0x102df,
- 0x102fc, 0x102ff,
- 0x10324, 0x1032c,
- 0x1034b, 0x1034f,
- 0x1037b, 0x1037f,
- 0x1039e, 0x1039e,
- 0x103c4, 0x103c7,
- 0x103d6, 0x103ff,
- 0x1049e, 0x1049f,
- 0x104aa, 0x104af,
- 0x104d4, 0x104d7,
- 0x104fc, 0x104ff,
- 0x10528, 0x1052f,
- 0x10564, 0x1056e,
- 0x1057b, 0x1057b,
- 0x1058b, 0x1058b,
- 0x10593, 0x10593,
- 0x10596, 0x10596,
- 0x105a2, 0x105a2,
- 0x105b2, 0x105b2,
- 0x105ba, 0x105ba,
- 0x105bd, 0x105bf,
- 0x105f4, 0x105ff,
- 0x10737, 0x1073f,
- 0x10756, 0x1075f,
- 0x10768, 0x1077f,
- 0x10786, 0x10786,
- 0x107b1, 0x107b1,
- 0x107bb, 0x107ff,
- 0x10806, 0x10807,
- 0x10809, 0x10809,
- 0x10836, 0x10836,
- 0x10839, 0x1083b,
- 0x1083d, 0x1083e,
- 0x10856, 0x10856,
- 0x1089f, 0x108a6,
- 0x108b0, 0x108df,
- 0x108f3, 0x108f3,
- 0x108f6, 0x108fa,
- 0x1091c, 0x1091e,
- 0x1093a, 0x1093e,
- 0x10940, 0x1097f,
- 0x109b8, 0x109bb,
- 0x109d0, 0x109d1,
- 0x10a04, 0x10a04,
- 0x10a07, 0x10a0b,
- 0x10a14, 0x10a14,
- 0x10a18, 0x10a18,
- 0x10a36, 0x10a37,
- 0x10a3b, 0x10a3e,
- 0x10a49, 0x10a4f,
- 0x10a59, 0x10a5f,
- 0x10aa0, 0x10abf,
- 0x10ae7, 0x10aea,
- 0x10af7, 0x10aff,
- 0x10b36, 0x10b38,
- 0x10b56, 0x10b57,
- 0x10b73, 0x10b77,
- 0x10b92, 0x10b98,
- 0x10b9d, 0x10ba8,
- 0x10bb0, 0x10bff,
- 0x10c49, 0x10c7f,
- 0x10cb3, 0x10cbf,
- 0x10cf3, 0x10cf9,
- 0x10d28, 0x10d2f,
- 0x10d3a, 0x10d3f,
- 0x10d66, 0x10d68,
- 0x10d86, 0x10d8d,
- 0x10d90, 0x10e5f,
- 0x10e7f, 0x10e7f,
- 0x10eaa, 0x10eaa,
- 0x10eae, 0x10eaf,
- 0x10eb2, 0x10ec1,
- 0x10ec5, 0x10efb,
- 0x10f28, 0x10f2f,
- 0x10f5a, 0x10f6f,
- 0x10f8a, 0x10faf,
- 0x10fcc, 0x10fdf,
- 0x10ff7, 0x10fff,
- 0x1104e, 0x11051,
- 0x11076, 0x1107e,
- 0x110c3, 0x110cc,
- 0x110ce, 0x110cf,
- 0x110e9, 0x110ef,
- 0x110fa, 0x110ff,
- 0x11135, 0x11135,
- 0x11148, 0x1114f,
- 0x11177, 0x1117f,
- 0x111e0, 0x111e0,
- 0x111f5, 0x111ff,
- 0x11212, 0x11212,
- 0x11242, 0x1127f,
- 0x11287, 0x11287,
- 0x11289, 0x11289,
- 0x1128e, 0x1128e,
- 0x1129e, 0x1129e,
- 0x112aa, 0x112af,
- 0x112eb, 0x112ef,
- 0x112fa, 0x112ff,
- 0x11304, 0x11304,
- 0x1130d, 0x1130e,
- 0x11311, 0x11312,
- 0x11329, 0x11329,
- 0x11331, 0x11331,
- 0x11334, 0x11334,
- 0x1133a, 0x1133a,
- 0x11345, 0x11346,
- 0x11349, 0x1134a,
- 0x1134e, 0x1134f,
- 0x11351, 0x11356,
- 0x11358, 0x1135c,
- 0x11364, 0x11365,
- 0x1136d, 0x1136f,
- 0x11375, 0x1137f,
- 0x1138a, 0x1138a,
- 0x1138c, 0x1138d,
- 0x1138f, 0x1138f,
- 0x113b6, 0x113b6,
- 0x113c1, 0x113c1,
- 0x113c3, 0x113c4,
- 0x113c6, 0x113c6,
- 0x113cb, 0x113cb,
- 0x113d6, 0x113d6,
- 0x113d9, 0x113e0,
- 0x113e3, 0x113ff,
- 0x1145c, 0x1145c,
- 0x11462, 0x1147f,
- 0x114c8, 0x114cf,
- 0x114da, 0x1157f,
- 0x115b6, 0x115b7,
- 0x115de, 0x115ff,
- 0x11645, 0x1164f,
- 0x1165a, 0x1165f,
- 0x1166d, 0x1167f,
- 0x116ba, 0x116bf,
- 0x116ca, 0x116cf,
- 0x116e4, 0x116ff,
- 0x1171b, 0x1171c,
- 0x1172c, 0x1172f,
- 0x11747, 0x117ff,
- 0x1183c, 0x1189f,
- 0x118f3, 0x118fe,
- 0x11907, 0x11908,
- 0x1190a, 0x1190b,
- 0x11914, 0x11914,
- 0x11917, 0x11917,
- 0x11936, 0x11936,
- 0x11939, 0x1193a,
- 0x11947, 0x1194f,
- 0x1195a, 0x1199f,
- 0x119a8, 0x119a9,
- 0x119d8, 0x119d9,
- 0x119e5, 0x119ff,
- 0x11a48, 0x11a4f,
- 0x11aa3, 0x11aaf,
- 0x11af9, 0x11aff,
- 0x11b0a, 0x11bbf,
- 0x11be2, 0x11bef,
- 0x11bfa, 0x11bff,
- 0x11c09, 0x11c09,
- 0x11c37, 0x11c37,
- 0x11c46, 0x11c4f,
- 0x11c6d, 0x11c6f,
- 0x11c90, 0x11c91,
- 0x11ca8, 0x11ca8,
- 0x11cb7, 0x11cff,
- 0x11d07, 0x11d07,
- 0x11d0a, 0x11d0a,
- 0x11d37, 0x11d39,
- 0x11d3b, 0x11d3b,
- 0x11d3e, 0x11d3e,
- 0x11d48, 0x11d4f,
- 0x11d5a, 0x11d5f,
- 0x11d66, 0x11d66,
- 0x11d69, 0x11d69,
- 0x11d8f, 0x11d8f,
- 0x11d92, 0x11d92,
- 0x11d99, 0x11d9f,
- 0x11daa, 0x11edf,
- 0x11ef9, 0x11eff,
- 0x11f11, 0x11f11,
- 0x11f3b, 0x11f3d,
- 0x11f5b, 0x11faf,
- 0x11fb1, 0x11fbf,
- 0x11ff2, 0x11ffe,
- 0x1239a, 0x123ff,
- 0x1246f, 0x1246f,
- 0x12475, 0x1247f,
- 0x12544, 0x12f8f,
- 0x12ff3, 0x12fff,
- 0x13456, 0x1345f,
- 0x143fb, 0x143ff,
- 0x14647, 0x160ff,
- 0x1613a, 0x167ff,
- 0x16a39, 0x16a3f,
- 0x16a5f, 0x16a5f,
- 0x16a6a, 0x16a6d,
- 0x16abf, 0x16abf,
- 0x16aca, 0x16acf,
- 0x16aee, 0x16aef,
- 0x16af6, 0x16aff,
- 0x16b46, 0x16b4f,
- 0x16b5a, 0x16b5a,
- 0x16b62, 0x16b62,
- 0x16b78, 0x16b7c,
- 0x16b90, 0x16d3f,
- 0x16d7a, 0x16e3f,
- 0x16e9b, 0x16eff,
- 0x16f4b, 0x16f4e,
- 0x16f88, 0x16f8e,
- 0x16fa0, 0x16fdf,
- 0x16fe5, 0x16fef,
- 0x16ff2, 0x16fff,
- 0x187f8, 0x187ff,
- 0x18cd6, 0x18cfe,
- 0x18d09, 0x1afef,
- 0x1aff4, 0x1aff4,
- 0x1affc, 0x1affc,
- 0x1afff, 0x1afff,
- 0x1b123, 0x1b131,
- 0x1b133, 0x1b14f,
- 0x1b153, 0x1b154,
- 0x1b156, 0x1b163,
- 0x1b168, 0x1b16f,
- 0x1b2fc, 0x1bbff,
- 0x1bc6b, 0x1bc6f,
- 0x1bc7d, 0x1bc7f,
- 0x1bc89, 0x1bc8f,
- 0x1bc9a, 0x1bc9b,
- 0x1bca4, 0x1cbff,
- 0x1ccfa, 0x1ccff,
- 0x1ceb4, 0x1ceff,
- 0x1cf2e, 0x1cf2f,
- 0x1cf47, 0x1cf4f,
- 0x1cfc4, 0x1cfff,
- 0x1d0f6, 0x1d0ff,
- 0x1d127, 0x1d128,
- 0x1d1eb, 0x1d1ff,
- 0x1d246, 0x1d2bf,
- 0x1d2d4, 0x1d2df,
- 0x1d2f4, 0x1d2ff,
- 0x1d357, 0x1d35f,
- 0x1d379, 0x1d3ff,
- 0x1d455, 0x1d455,
- 0x1d49d, 0x1d49d,
- 0x1d4a0, 0x1d4a1,
- 0x1d4a3, 0x1d4a4,
- 0x1d4a7, 0x1d4a8,
- 0x1d4ad, 0x1d4ad,
- 0x1d4ba, 0x1d4ba,
- 0x1d4bc, 0x1d4bc,
- 0x1d4c4, 0x1d4c4,
- 0x1d506, 0x1d506,
- 0x1d50b, 0x1d50c,
- 0x1d515, 0x1d515,
- 0x1d51d, 0x1d51d,
- 0x1d53a, 0x1d53a,
- 0x1d53f, 0x1d53f,
- 0x1d545, 0x1d545,
- 0x1d547, 0x1d549,
- 0x1d551, 0x1d551,
- 0x1d6a6, 0x1d6a7,
- 0x1d7cc, 0x1d7cd,
- 0x1da8c, 0x1da9a,
- 0x1daa0, 0x1daa0,
- 0x1dab0, 0x1deff,
- 0x1df1f, 0x1df24,
- 0x1df2b, 0x1dfff,
- 0x1e007, 0x1e007,
- 0x1e019, 0x1e01a,
- 0x1e022, 0x1e022,
- 0x1e025, 0x1e025,
- 0x1e02b, 0x1e02f,
- 0x1e06e, 0x1e08e,
- 0x1e090, 0x1e0ff,
- 0x1e12d, 0x1e12f,
- 0x1e13e, 0x1e13f,
- 0x1e14a, 0x1e14d,
- 0x1e150, 0x1e28f,
- 0x1e2af, 0x1e2bf,
- 0x1e2fa, 0x1e2fe,
- 0x1e300, 0x1e4cf,
- 0x1e4fa, 0x1e5cf,
- 0x1e5fb, 0x1e5fe,
- 0x1e600, 0x1e7df,
- 0x1e7e7, 0x1e7e7,
- 0x1e7ec, 0x1e7ec,
- 0x1e7ef, 0x1e7ef,
- 0x1e7ff, 0x1e7ff,
- 0x1e8c5, 0x1e8c6,
- 0x1e8d7, 0x1e8ff,
- 0x1e94c, 0x1e94f,
- 0x1e95a, 0x1e95d,
- 0x1e960, 0x1ec70,
- 0x1ecb5, 0x1ed00,
- 0x1ed3e, 0x1edff,
- 0x1ee04, 0x1ee04,
- 0x1ee20, 0x1ee20,
- 0x1ee23, 0x1ee23,
- 0x1ee25, 0x1ee26,
- 0x1ee28, 0x1ee28,
- 0x1ee33, 0x1ee33,
- 0x1ee38, 0x1ee38,
- 0x1ee3a, 0x1ee3a,
- 0x1ee3c, 0x1ee41,
- 0x1ee43, 0x1ee46,
- 0x1ee48, 0x1ee48,
- 0x1ee4a, 0x1ee4a,
- 0x1ee4c, 0x1ee4c,
- 0x1ee50, 0x1ee50,
- 0x1ee53, 0x1ee53,
- 0x1ee55, 0x1ee56,
- 0x1ee58, 0x1ee58,
- 0x1ee5a, 0x1ee5a,
- 0x1ee5c, 0x1ee5c,
- 0x1ee5e, 0x1ee5e,
- 0x1ee60, 0x1ee60,
- 0x1ee63, 0x1ee63,
- 0x1ee65, 0x1ee66,
- 0x1ee6b, 0x1ee6b,
- 0x1ee73, 0x1ee73,
- 0x1ee78, 0x1ee78,
- 0x1ee7d, 0x1ee7d,
- 0x1ee7f, 0x1ee7f,
- 0x1ee8a, 0x1ee8a,
- 0x1ee9c, 0x1eea0,
- 0x1eea4, 0x1eea4,
- 0x1eeaa, 0x1eeaa,
- 0x1eebc, 0x1eeef,
- 0x1eef2, 0x1efff,
- 0x1f02c, 0x1f02f,
- 0x1f094, 0x1f09f,
- 0x1f0af, 0x1f0b0,
- 0x1f0c0, 0x1f0c0,
- 0x1f0d0, 0x1f0d0,
- 0x1f0f6, 0x1f0ff,
- 0x1f1ae, 0x1f1e5,
- 0x1f203, 0x1f20f,
- 0x1f23c, 0x1f23f,
- 0x1f249, 0x1f24f,
- 0x1f252, 0x1f25f,
- 0x1f266, 0x1f2ff,
- 0x1f6d8, 0x1f6db,
- 0x1f6ed, 0x1f6ef,
- 0x1f6fd, 0x1f6ff,
- 0x1f777, 0x1f77a,
- 0x1f7da, 0x1f7df,
- 0x1f7ec, 0x1f7ef,
- 0x1f7f1, 0x1f7ff,
- 0x1f80c, 0x1f80f,
- 0x1f848, 0x1f84f,
- 0x1f85a, 0x1f85f,
- 0x1f888, 0x1f88f,
- 0x1f8ae, 0x1f8af,
- 0x1f8bc, 0x1f8bf,
- 0x1f8c2, 0x1f8ff,
- 0x1fa54, 0x1fa5f,
- 0x1fa6e, 0x1fa6f,
- 0x1fa7d, 0x1fa7f,
- 0x1fa8a, 0x1fa8e,
- 0x1fac7, 0x1facd,
- 0x1fadd, 0x1fade,
- 0x1faea, 0x1faef,
- 0x1faf9, 0x1faff,
- 0x1fb93, 0x1fb93,
- 0x1fbfa, 0x1ffff,
- 0x2a6e0, 0x2a6ff,
- 0x2b73a, 0x2b73f,
- 0x2b81e, 0x2b81f,
- 0x2cea2, 0x2ceaf,
- 0x2ebe1, 0x2ebef,
- 0x2ee5e, 0x2f7ff,
- 0x2fa1e, 0x2ffff,
- 0x3134b, 0x3134f,
- 0x323b0, 0xe0000,
- 0xe0002, 0xe001f,
- 0xe0080, 0xe00ff,
- 0xe01f0, 0xeffff,
- 0xffffe, 0xfffff,
- 0x10fffe, 0x10ffff,
-}; /* CR_Cn */
-
-/* 'Co': General Category */
-static const OnigCodePoint CR_Co[] = {
- 3,
- 0xe000, 0xf8ff,
- 0xf0000, 0xffffd,
- 0x100000, 0x10fffd,
-}; /* CR_Co */
-
-/* 'Cs': General Category */
-static const OnigCodePoint CR_Cs[] = {
- 1,
- 0xd800, 0xdfff,
-}; /* CR_Cs */
-
-/* 'L': Major Category */
-static const OnigCodePoint CR_L[] = {
- 677,
- 0x0041, 0x005a,
- 0x0061, 0x007a,
- 0x00aa, 0x00aa,
- 0x00b5, 0x00b5,
- 0x00ba, 0x00ba,
- 0x00c0, 0x00d6,
- 0x00d8, 0x00f6,
- 0x00f8, 0x02c1,
- 0x02c6, 0x02d1,
- 0x02e0, 0x02e4,
- 0x02ec, 0x02ec,
- 0x02ee, 0x02ee,
- 0x0370, 0x0374,
- 0x0376, 0x0377,
- 0x037a, 0x037d,
- 0x037f, 0x037f,
- 0x0386, 0x0386,
- 0x0388, 0x038a,
- 0x038c, 0x038c,
- 0x038e, 0x03a1,
- 0x03a3, 0x03f5,
- 0x03f7, 0x0481,
- 0x048a, 0x052f,
- 0x0531, 0x0556,
- 0x0559, 0x0559,
- 0x0560, 0x0588,
- 0x05d0, 0x05ea,
- 0x05ef, 0x05f2,
- 0x0620, 0x064a,
- 0x066e, 0x066f,
- 0x0671, 0x06d3,
- 0x06d5, 0x06d5,
- 0x06e5, 0x06e6,
- 0x06ee, 0x06ef,
- 0x06fa, 0x06fc,
- 0x06ff, 0x06ff,
- 0x0710, 0x0710,
- 0x0712, 0x072f,
- 0x074d, 0x07a5,
- 0x07b1, 0x07b1,
- 0x07ca, 0x07ea,
- 0x07f4, 0x07f5,
- 0x07fa, 0x07fa,
- 0x0800, 0x0815,
- 0x081a, 0x081a,
- 0x0824, 0x0824,
- 0x0828, 0x0828,
- 0x0840, 0x0858,
- 0x0860, 0x086a,
- 0x0870, 0x0887,
- 0x0889, 0x088e,
- 0x08a0, 0x08c9,
- 0x0904, 0x0939,
- 0x093d, 0x093d,
- 0x0950, 0x0950,
- 0x0958, 0x0961,
- 0x0971, 0x0980,
- 0x0985, 0x098c,
- 0x098f, 0x0990,
- 0x0993, 0x09a8,
- 0x09aa, 0x09b0,
- 0x09b2, 0x09b2,
- 0x09b6, 0x09b9,
- 0x09bd, 0x09bd,
- 0x09ce, 0x09ce,
- 0x09dc, 0x09dd,
- 0x09df, 0x09e1,
- 0x09f0, 0x09f1,
- 0x09fc, 0x09fc,
- 0x0a05, 0x0a0a,
- 0x0a0f, 0x0a10,
- 0x0a13, 0x0a28,
- 0x0a2a, 0x0a30,
- 0x0a32, 0x0a33,
- 0x0a35, 0x0a36,
- 0x0a38, 0x0a39,
- 0x0a59, 0x0a5c,
- 0x0a5e, 0x0a5e,
- 0x0a72, 0x0a74,
- 0x0a85, 0x0a8d,
- 0x0a8f, 0x0a91,
- 0x0a93, 0x0aa8,
- 0x0aaa, 0x0ab0,
- 0x0ab2, 0x0ab3,
- 0x0ab5, 0x0ab9,
- 0x0abd, 0x0abd,
- 0x0ad0, 0x0ad0,
- 0x0ae0, 0x0ae1,
- 0x0af9, 0x0af9,
- 0x0b05, 0x0b0c,
- 0x0b0f, 0x0b10,
- 0x0b13, 0x0b28,
- 0x0b2a, 0x0b30,
- 0x0b32, 0x0b33,
- 0x0b35, 0x0b39,
- 0x0b3d, 0x0b3d,
- 0x0b5c, 0x0b5d,
- 0x0b5f, 0x0b61,
- 0x0b71, 0x0b71,
- 0x0b83, 0x0b83,
- 0x0b85, 0x0b8a,
- 0x0b8e, 0x0b90,
- 0x0b92, 0x0b95,
- 0x0b99, 0x0b9a,
- 0x0b9c, 0x0b9c,
- 0x0b9e, 0x0b9f,
- 0x0ba3, 0x0ba4,
- 0x0ba8, 0x0baa,
- 0x0bae, 0x0bb9,
- 0x0bd0, 0x0bd0,
- 0x0c05, 0x0c0c,
- 0x0c0e, 0x0c10,
- 0x0c12, 0x0c28,
- 0x0c2a, 0x0c39,
- 0x0c3d, 0x0c3d,
- 0x0c58, 0x0c5a,
- 0x0c5d, 0x0c5d,
- 0x0c60, 0x0c61,
- 0x0c80, 0x0c80,
- 0x0c85, 0x0c8c,
- 0x0c8e, 0x0c90,
- 0x0c92, 0x0ca8,
- 0x0caa, 0x0cb3,
- 0x0cb5, 0x0cb9,
- 0x0cbd, 0x0cbd,
- 0x0cdd, 0x0cde,
- 0x0ce0, 0x0ce1,
- 0x0cf1, 0x0cf2,
- 0x0d04, 0x0d0c,
- 0x0d0e, 0x0d10,
- 0x0d12, 0x0d3a,
- 0x0d3d, 0x0d3d,
- 0x0d4e, 0x0d4e,
- 0x0d54, 0x0d56,
- 0x0d5f, 0x0d61,
- 0x0d7a, 0x0d7f,
- 0x0d85, 0x0d96,
- 0x0d9a, 0x0db1,
- 0x0db3, 0x0dbb,
- 0x0dbd, 0x0dbd,
- 0x0dc0, 0x0dc6,
- 0x0e01, 0x0e30,
- 0x0e32, 0x0e33,
- 0x0e40, 0x0e46,
- 0x0e81, 0x0e82,
- 0x0e84, 0x0e84,
- 0x0e86, 0x0e8a,
- 0x0e8c, 0x0ea3,
- 0x0ea5, 0x0ea5,
- 0x0ea7, 0x0eb0,
- 0x0eb2, 0x0eb3,
- 0x0ebd, 0x0ebd,
- 0x0ec0, 0x0ec4,
- 0x0ec6, 0x0ec6,
- 0x0edc, 0x0edf,
- 0x0f00, 0x0f00,
- 0x0f40, 0x0f47,
- 0x0f49, 0x0f6c,
- 0x0f88, 0x0f8c,
- 0x1000, 0x102a,
- 0x103f, 0x103f,
- 0x1050, 0x1055,
- 0x105a, 0x105d,
- 0x1061, 0x1061,
- 0x1065, 0x1066,
- 0x106e, 0x1070,
- 0x1075, 0x1081,
- 0x108e, 0x108e,
- 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,
- 0x16f1, 0x16f8,
- 0x1700, 0x1711,
- 0x171f, 0x1731,
- 0x1740, 0x1751,
- 0x1760, 0x176c,
- 0x176e, 0x1770,
- 0x1780, 0x17b3,
- 0x17d7, 0x17d7,
- 0x17dc, 0x17dc,
- 0x1820, 0x1878,
- 0x1880, 0x1884,
- 0x1887, 0x18a8,
- 0x18aa, 0x18aa,
- 0x18b0, 0x18f5,
- 0x1900, 0x191e,
- 0x1950, 0x196d,
- 0x1970, 0x1974,
- 0x1980, 0x19ab,
- 0x19b0, 0x19c9,
- 0x1a00, 0x1a16,
- 0x1a20, 0x1a54,
- 0x1aa7, 0x1aa7,
- 0x1b05, 0x1b33,
- 0x1b45, 0x1b4c,
- 0x1b83, 0x1ba0,
- 0x1bae, 0x1baf,
- 0x1bba, 0x1be5,
- 0x1c00, 0x1c23,
- 0x1c4d, 0x1c4f,
- 0x1c5a, 0x1c7d,
- 0x1c80, 0x1c8a,
- 0x1c90, 0x1cba,
- 0x1cbd, 0x1cbf,
- 0x1ce9, 0x1cec,
- 0x1cee, 0x1cf3,
- 0x1cf5, 0x1cf6,
- 0x1cfa, 0x1cfa,
- 0x1d00, 0x1dbf,
- 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,
- 0x2183, 0x2184,
- 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,
- 0x2e2f, 0x2e2f,
- 0x3005, 0x3006,
- 0x3031, 0x3035,
- 0x303b, 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,
- 0xa67f, 0xa69d,
- 0xa6a0, 0xa6e5,
- 0xa717, 0xa71f,
- 0xa722, 0xa788,
- 0xa78b, 0xa7cd,
- 0xa7d0, 0xa7d1,
- 0xa7d3, 0xa7d3,
- 0xa7d5, 0xa7dc,
- 0xa7f2, 0xa801,
- 0xa803, 0xa805,
- 0xa807, 0xa80a,
- 0xa80c, 0xa822,
- 0xa840, 0xa873,
- 0xa882, 0xa8b3,
- 0xa8f2, 0xa8f7,
- 0xa8fb, 0xa8fb,
- 0xa8fd, 0xa8fe,
- 0xa90a, 0xa925,
- 0xa930, 0xa946,
- 0xa960, 0xa97c,
- 0xa984, 0xa9b2,
- 0xa9cf, 0xa9cf,
- 0xa9e0, 0xa9e4,
- 0xa9e6, 0xa9ef,
- 0xa9fa, 0xa9fe,
- 0xaa00, 0xaa28,
- 0xaa40, 0xaa42,
- 0xaa44, 0xaa4b,
- 0xaa60, 0xaa76,
- 0xaa7a, 0xaa7a,
- 0xaa7e, 0xaaaf,
- 0xaab1, 0xaab1,
- 0xaab5, 0xaab6,
- 0xaab9, 0xaabd,
- 0xaac0, 0xaac0,
- 0xaac2, 0xaac2,
- 0xaadb, 0xaadd,
- 0xaae0, 0xaaea,
- 0xaaf2, 0xaaf4,
- 0xab01, 0xab06,
- 0xab09, 0xab0e,
- 0xab11, 0xab16,
- 0xab20, 0xab26,
- 0xab28, 0xab2e,
- 0xab30, 0xab5a,
- 0xab5c, 0xab69,
- 0xab70, 0xabe2,
- 0xac00, 0xd7a3,
- 0xd7b0, 0xd7c6,
- 0xd7cb, 0xd7fb,
- 0xf900, 0xfa6d,
- 0xfa70, 0xfad9,
- 0xfb00, 0xfb06,
- 0xfb13, 0xfb17,
- 0xfb1d, 0xfb1d,
- 0xfb1f, 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,
- 0x10280, 0x1029c,
- 0x102a0, 0x102d0,
- 0x10300, 0x1031f,
- 0x1032d, 0x10340,
- 0x10342, 0x10349,
- 0x10350, 0x10375,
- 0x10380, 0x1039d,
- 0x103a0, 0x103c3,
- 0x103c8, 0x103cf,
- 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,
- 0x105c0, 0x105f3,
- 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, 0x10a00,
- 0x10a10, 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, 0x10d23,
- 0x10d4a, 0x10d65,
- 0x10d6f, 0x10d85,
- 0x10e80, 0x10ea9,
- 0x10eb0, 0x10eb1,
- 0x10ec2, 0x10ec4,
- 0x10f00, 0x10f1c,
- 0x10f27, 0x10f27,
- 0x10f30, 0x10f45,
- 0x10f70, 0x10f81,
- 0x10fb0, 0x10fc4,
- 0x10fe0, 0x10ff6,
- 0x11003, 0x11037,
- 0x11071, 0x11072,
- 0x11075, 0x11075,
- 0x11083, 0x110af,
- 0x110d0, 0x110e8,
- 0x11103, 0x11126,
- 0x11144, 0x11144,
- 0x11147, 0x11147,
- 0x11150, 0x11172,
- 0x11176, 0x11176,
- 0x11183, 0x111b2,
- 0x111c1, 0x111c4,
- 0x111da, 0x111da,
- 0x111dc, 0x111dc,
- 0x11200, 0x11211,
- 0x11213, 0x1122b,
- 0x1123f, 0x11240,
- 0x11280, 0x11286,
- 0x11288, 0x11288,
- 0x1128a, 0x1128d,
- 0x1128f, 0x1129d,
- 0x1129f, 0x112a8,
- 0x112b0, 0x112de,
- 0x11305, 0x1130c,
- 0x1130f, 0x11310,
- 0x11313, 0x11328,
- 0x1132a, 0x11330,
- 0x11332, 0x11333,
- 0x11335, 0x11339,
- 0x1133d, 0x1133d,
- 0x11350, 0x11350,
- 0x1135d, 0x11361,
- 0x11380, 0x11389,
- 0x1138b, 0x1138b,
- 0x1138e, 0x1138e,
- 0x11390, 0x113b5,
- 0x113b7, 0x113b7,
- 0x113d1, 0x113d1,
- 0x113d3, 0x113d3,
- 0x11400, 0x11434,
- 0x11447, 0x1144a,
- 0x1145f, 0x11461,
- 0x11480, 0x114af,
- 0x114c4, 0x114c5,
- 0x114c7, 0x114c7,
- 0x11580, 0x115ae,
- 0x115d8, 0x115db,
- 0x11600, 0x1162f,
- 0x11644, 0x11644,
- 0x11680, 0x116aa,
- 0x116b8, 0x116b8,
- 0x11700, 0x1171a,
- 0x11740, 0x11746,
- 0x11800, 0x1182b,
- 0x118a0, 0x118df,
- 0x118ff, 0x11906,
- 0x11909, 0x11909,
- 0x1190c, 0x11913,
- 0x11915, 0x11916,
- 0x11918, 0x1192f,
- 0x1193f, 0x1193f,
- 0x11941, 0x11941,
- 0x119a0, 0x119a7,
- 0x119aa, 0x119d0,
- 0x119e1, 0x119e1,
- 0x119e3, 0x119e3,
- 0x11a00, 0x11a00,
- 0x11a0b, 0x11a32,
- 0x11a3a, 0x11a3a,
- 0x11a50, 0x11a50,
- 0x11a5c, 0x11a89,
- 0x11a9d, 0x11a9d,
- 0x11ab0, 0x11af8,
- 0x11bc0, 0x11be0,
- 0x11c00, 0x11c08,
- 0x11c0a, 0x11c2e,
- 0x11c40, 0x11c40,
- 0x11c72, 0x11c8f,
- 0x11d00, 0x11d06,
- 0x11d08, 0x11d09,
- 0x11d0b, 0x11d30,
- 0x11d46, 0x11d46,
- 0x11d60, 0x11d65,
- 0x11d67, 0x11d68,
- 0x11d6a, 0x11d89,
- 0x11d98, 0x11d98,
- 0x11ee0, 0x11ef2,
- 0x11f02, 0x11f02,
- 0x11f04, 0x11f10,
- 0x11f12, 0x11f33,
- 0x11fb0, 0x11fb0,
- 0x12000, 0x12399,
- 0x12480, 0x12543,
- 0x12f90, 0x12ff0,
- 0x13000, 0x1342f,
- 0x13441, 0x13446,
- 0x13460, 0x143fa,
- 0x14400, 0x14646,
- 0x16100, 0x1611d,
- 0x16800, 0x16a38,
- 0x16a40, 0x16a5e,
- 0x16a70, 0x16abe,
- 0x16ad0, 0x16aed,
- 0x16b00, 0x16b2f,
- 0x16b40, 0x16b43,
- 0x16b63, 0x16b77,
- 0x16b7d, 0x16b8f,
- 0x16d40, 0x16d6c,
- 0x16e40, 0x16e7f,
- 0x16f00, 0x16f4a,
- 0x16f50, 0x16f50,
- 0x16f93, 0x16f9f,
- 0x16fe0, 0x16fe1,
- 0x16fe3, 0x16fe3,
- 0x17000, 0x187f7,
- 0x18800, 0x18cd5,
- 0x18cff, 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,
- 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,
- 0x1e030, 0x1e06d,
- 0x1e100, 0x1e12c,
- 0x1e137, 0x1e13d,
- 0x1e14e, 0x1e14e,
- 0x1e290, 0x1e2ad,
- 0x1e2c0, 0x1e2eb,
- 0x1e4d0, 0x1e4eb,
- 0x1e5d0, 0x1e5ed,
- 0x1e5f0, 0x1e5f0,
- 0x1e7e0, 0x1e7e6,
- 0x1e7e8, 0x1e7eb,
- 0x1e7ed, 0x1e7ee,
- 0x1e7f0, 0x1e7fe,
- 0x1e800, 0x1e8c4,
- 0x1e900, 0x1e943,
- 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,
- 0x20000, 0x2a6df,
- 0x2a700, 0x2b739,
- 0x2b740, 0x2b81d,
- 0x2b820, 0x2cea1,
- 0x2ceb0, 0x2ebe0,
- 0x2ebf0, 0x2ee5d,
- 0x2f800, 0x2fa1d,
- 0x30000, 0x3134a,
- 0x31350, 0x323af,
-}; /* CR_L */
-
-/* 'LC': General Category */
-static const OnigCodePoint CR_LC[] = {
- 145,
- 0x0041, 0x005a,
- 0x0061, 0x007a,
- 0x00b5, 0x00b5,
- 0x00c0, 0x00d6,
- 0x00d8, 0x00f6,
- 0x00f8, 0x01ba,
- 0x01bc, 0x01bf,
- 0x01c4, 0x0293,
- 0x0295, 0x02af,
- 0x0370, 0x0373,
- 0x0376, 0x0377,
- 0x037b, 0x037d,
- 0x037f, 0x037f,
- 0x0386, 0x0386,
- 0x0388, 0x038a,
- 0x038c, 0x038c,
- 0x038e, 0x03a1,
- 0x03a3, 0x03f5,
- 0x03f7, 0x0481,
- 0x048a, 0x052f,
- 0x0531, 0x0556,
- 0x0560, 0x0588,
- 0x10a0, 0x10c5,
- 0x10c7, 0x10c7,
- 0x10cd, 0x10cd,
- 0x10d0, 0x10fa,
- 0x10fd, 0x10ff,
- 0x13a0, 0x13f5,
- 0x13f8, 0x13fd,
- 0x1c80, 0x1c8a,
- 0x1c90, 0x1cba,
- 0x1cbd, 0x1cbf,
- 0x1d00, 0x1d2b,
- 0x1d6b, 0x1d77,
- 0x1d79, 0x1d9a,
- 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,
- 0x2102, 0x2102,
- 0x2107, 0x2107,
- 0x210a, 0x2113,
- 0x2115, 0x2115,
- 0x2119, 0x211d,
- 0x2124, 0x2124,
- 0x2126, 0x2126,
- 0x2128, 0x2128,
- 0x212a, 0x212d,
- 0x212f, 0x2134,
- 0x2139, 0x2139,
- 0x213c, 0x213f,
- 0x2145, 0x2149,
- 0x214e, 0x214e,
- 0x2183, 0x2184,
- 0x2c00, 0x2c7b,
- 0x2c7e, 0x2ce4,
- 0x2ceb, 0x2cee,
- 0x2cf2, 0x2cf3,
- 0x2d00, 0x2d25,
- 0x2d27, 0x2d27,
- 0x2d2d, 0x2d2d,
- 0xa640, 0xa66d,
- 0xa680, 0xa69b,
- 0xa722, 0xa76f,
- 0xa771, 0xa787,
- 0xa78b, 0xa78e,
- 0xa790, 0xa7cd,
- 0xa7d0, 0xa7d1,
- 0xa7d3, 0xa7d3,
- 0xa7d5, 0xa7dc,
- 0xa7f5, 0xa7f6,
- 0xa7fa, 0xa7fa,
- 0xab30, 0xab5a,
- 0xab60, 0xab68,
- 0xab70, 0xabbf,
- 0xfb00, 0xfb06,
- 0xfb13, 0xfb17,
- 0xff21, 0xff3a,
- 0xff41, 0xff5a,
- 0x10400, 0x1044f,
- 0x104b0, 0x104d3,
- 0x104d8, 0x104fb,
- 0x10570, 0x1057a,
- 0x1057c, 0x1058a,
- 0x1058c, 0x10592,
- 0x10594, 0x10595,
- 0x10597, 0x105a1,
- 0x105a3, 0x105b1,
- 0x105b3, 0x105b9,
- 0x105bb, 0x105bc,
- 0x10c80, 0x10cb2,
- 0x10cc0, 0x10cf2,
- 0x10d50, 0x10d65,
- 0x10d70, 0x10d85,
- 0x118a0, 0x118df,
- 0x16e40, 0x16e7f,
- 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, 0x1df09,
- 0x1df0b, 0x1df1e,
- 0x1df25, 0x1df2a,
- 0x1e900, 0x1e943,
-}; /* CR_LC */
-
-/* 'Ll': General Category */
-static const OnigCodePoint CR_Ll[] = {
- 662,
- 0x0061, 0x007a,
- 0x00b5, 0x00b5,
- 0x00df, 0x00f6,
- 0x00f8, 0x00ff,
- 0x0101, 0x0101,
- 0x0103, 0x0103,
- 0x0105, 0x0105,
- 0x0107, 0x0107,
- 0x0109, 0x0109,
- 0x010b, 0x010b,
- 0x010d, 0x010d,
- 0x010f, 0x010f,
- 0x0111, 0x0111,
- 0x0113, 0x0113,
- 0x0115, 0x0115,
- 0x0117, 0x0117,
- 0x0119, 0x0119,
- 0x011b, 0x011b,
- 0x011d, 0x011d,
- 0x011f, 0x011f,
- 0x0121, 0x0121,
- 0x0123, 0x0123,
- 0x0125, 0x0125,
- 0x0127, 0x0127,
- 0x0129, 0x0129,
- 0x012b, 0x012b,
- 0x012d, 0x012d,
- 0x012f, 0x012f,
- 0x0131, 0x0131,
- 0x0133, 0x0133,
- 0x0135, 0x0135,
- 0x0137, 0x0138,
- 0x013a, 0x013a,
- 0x013c, 0x013c,
- 0x013e, 0x013e,
- 0x0140, 0x0140,
- 0x0142, 0x0142,
- 0x0144, 0x0144,
- 0x0146, 0x0146,
- 0x0148, 0x0149,
- 0x014b, 0x014b,
- 0x014d, 0x014d,
- 0x014f, 0x014f,
- 0x0151, 0x0151,
- 0x0153, 0x0153,
- 0x0155, 0x0155,
- 0x0157, 0x0157,
- 0x0159, 0x0159,
- 0x015b, 0x015b,
- 0x015d, 0x015d,
- 0x015f, 0x015f,
- 0x0161, 0x0161,
- 0x0163, 0x0163,
- 0x0165, 0x0165,
- 0x0167, 0x0167,
- 0x0169, 0x0169,
- 0x016b, 0x016b,
- 0x016d, 0x016d,
- 0x016f, 0x016f,
- 0x0171, 0x0171,
- 0x0173, 0x0173,
- 0x0175, 0x0175,
- 0x0177, 0x0177,
- 0x017a, 0x017a,
- 0x017c, 0x017c,
- 0x017e, 0x0180,
- 0x0183, 0x0183,
- 0x0185, 0x0185,
- 0x0188, 0x0188,
- 0x018c, 0x018d,
- 0x0192, 0x0192,
- 0x0195, 0x0195,
- 0x0199, 0x019b,
- 0x019e, 0x019e,
- 0x01a1, 0x01a1,
- 0x01a3, 0x01a3,
- 0x01a5, 0x01a5,
- 0x01a8, 0x01a8,
- 0x01aa, 0x01ab,
- 0x01ad, 0x01ad,
- 0x01b0, 0x01b0,
- 0x01b4, 0x01b4,
- 0x01b6, 0x01b6,
- 0x01b9, 0x01ba,
- 0x01bd, 0x01bf,
- 0x01c6, 0x01c6,
- 0x01c9, 0x01c9,
- 0x01cc, 0x01cc,
- 0x01ce, 0x01ce,
- 0x01d0, 0x01d0,
- 0x01d2, 0x01d2,
- 0x01d4, 0x01d4,
- 0x01d6, 0x01d6,
- 0x01d8, 0x01d8,
- 0x01da, 0x01da,
- 0x01dc, 0x01dd,
- 0x01df, 0x01df,
- 0x01e1, 0x01e1,
- 0x01e3, 0x01e3,
- 0x01e5, 0x01e5,
- 0x01e7, 0x01e7,
- 0x01e9, 0x01e9,
- 0x01eb, 0x01eb,
- 0x01ed, 0x01ed,
- 0x01ef, 0x01f0,
- 0x01f3, 0x01f3,
- 0x01f5, 0x01f5,
- 0x01f9, 0x01f9,
- 0x01fb, 0x01fb,
- 0x01fd, 0x01fd,
- 0x01ff, 0x01ff,
- 0x0201, 0x0201,
- 0x0203, 0x0203,
- 0x0205, 0x0205,
- 0x0207, 0x0207,
- 0x0209, 0x0209,
- 0x020b, 0x020b,
- 0x020d, 0x020d,
- 0x020f, 0x020f,
- 0x0211, 0x0211,
- 0x0213, 0x0213,
- 0x0215, 0x0215,
- 0x0217, 0x0217,
- 0x0219, 0x0219,
- 0x021b, 0x021b,
- 0x021d, 0x021d,
- 0x021f, 0x021f,
- 0x0221, 0x0221,
- 0x0223, 0x0223,
- 0x0225, 0x0225,
- 0x0227, 0x0227,
- 0x0229, 0x0229,
- 0x022b, 0x022b,
- 0x022d, 0x022d,
- 0x022f, 0x022f,
- 0x0231, 0x0231,
- 0x0233, 0x0239,
- 0x023c, 0x023c,
- 0x023f, 0x0240,
- 0x0242, 0x0242,
- 0x0247, 0x0247,
- 0x0249, 0x0249,
- 0x024b, 0x024b,
- 0x024d, 0x024d,
- 0x024f, 0x0293,
- 0x0295, 0x02af,
- 0x0371, 0x0371,
- 0x0373, 0x0373,
- 0x0377, 0x0377,
- 0x037b, 0x037d,
- 0x0390, 0x0390,
- 0x03ac, 0x03ce,
- 0x03d0, 0x03d1,
- 0x03d5, 0x03d7,
- 0x03d9, 0x03d9,
- 0x03db, 0x03db,
- 0x03dd, 0x03dd,
- 0x03df, 0x03df,
- 0x03e1, 0x03e1,
- 0x03e3, 0x03e3,
- 0x03e5, 0x03e5,
- 0x03e7, 0x03e7,
- 0x03e9, 0x03e9,
- 0x03eb, 0x03eb,
- 0x03ed, 0x03ed,
- 0x03ef, 0x03f3,
- 0x03f5, 0x03f5,
- 0x03f8, 0x03f8,
- 0x03fb, 0x03fc,
- 0x0430, 0x045f,
- 0x0461, 0x0461,
- 0x0463, 0x0463,
- 0x0465, 0x0465,
- 0x0467, 0x0467,
- 0x0469, 0x0469,
- 0x046b, 0x046b,
- 0x046d, 0x046d,
- 0x046f, 0x046f,
- 0x0471, 0x0471,
- 0x0473, 0x0473,
- 0x0475, 0x0475,
- 0x0477, 0x0477,
- 0x0479, 0x0479,
- 0x047b, 0x047b,
- 0x047d, 0x047d,
- 0x047f, 0x047f,
- 0x0481, 0x0481,
- 0x048b, 0x048b,
- 0x048d, 0x048d,
- 0x048f, 0x048f,
- 0x0491, 0x0491,
- 0x0493, 0x0493,
- 0x0495, 0x0495,
- 0x0497, 0x0497,
- 0x0499, 0x0499,
- 0x049b, 0x049b,
- 0x049d, 0x049d,
- 0x049f, 0x049f,
- 0x04a1, 0x04a1,
- 0x04a3, 0x04a3,
- 0x04a5, 0x04a5,
- 0x04a7, 0x04a7,
- 0x04a9, 0x04a9,
- 0x04ab, 0x04ab,
- 0x04ad, 0x04ad,
- 0x04af, 0x04af,
- 0x04b1, 0x04b1,
- 0x04b3, 0x04b3,
- 0x04b5, 0x04b5,
- 0x04b7, 0x04b7,
- 0x04b9, 0x04b9,
- 0x04bb, 0x04bb,
- 0x04bd, 0x04bd,
- 0x04bf, 0x04bf,
- 0x04c2, 0x04c2,
- 0x04c4, 0x04c4,
- 0x04c6, 0x04c6,
- 0x04c8, 0x04c8,
- 0x04ca, 0x04ca,
- 0x04cc, 0x04cc,
- 0x04ce, 0x04cf,
- 0x04d1, 0x04d1,
- 0x04d3, 0x04d3,
- 0x04d5, 0x04d5,
- 0x04d7, 0x04d7,
- 0x04d9, 0x04d9,
- 0x04db, 0x04db,
- 0x04dd, 0x04dd,
- 0x04df, 0x04df,
- 0x04e1, 0x04e1,
- 0x04e3, 0x04e3,
- 0x04e5, 0x04e5,
- 0x04e7, 0x04e7,
- 0x04e9, 0x04e9,
- 0x04eb, 0x04eb,
- 0x04ed, 0x04ed,
- 0x04ef, 0x04ef,
- 0x04f1, 0x04f1,
- 0x04f3, 0x04f3,
- 0x04f5, 0x04f5,
- 0x04f7, 0x04f7,
- 0x04f9, 0x04f9,
- 0x04fb, 0x04fb,
- 0x04fd, 0x04fd,
- 0x04ff, 0x04ff,
- 0x0501, 0x0501,
- 0x0503, 0x0503,
- 0x0505, 0x0505,
- 0x0507, 0x0507,
- 0x0509, 0x0509,
- 0x050b, 0x050b,
- 0x050d, 0x050d,
- 0x050f, 0x050f,
- 0x0511, 0x0511,
- 0x0513, 0x0513,
- 0x0515, 0x0515,
- 0x0517, 0x0517,
- 0x0519, 0x0519,
- 0x051b, 0x051b,
- 0x051d, 0x051d,
- 0x051f, 0x051f,
- 0x0521, 0x0521,
- 0x0523, 0x0523,
- 0x0525, 0x0525,
- 0x0527, 0x0527,
- 0x0529, 0x0529,
- 0x052b, 0x052b,
- 0x052d, 0x052d,
- 0x052f, 0x052f,
- 0x0560, 0x0588,
- 0x10d0, 0x10fa,
- 0x10fd, 0x10ff,
- 0x13f8, 0x13fd,
- 0x1c80, 0x1c88,
- 0x1c8a, 0x1c8a,
- 0x1d00, 0x1d2b,
- 0x1d6b, 0x1d77,
- 0x1d79, 0x1d9a,
- 0x1e01, 0x1e01,
- 0x1e03, 0x1e03,
- 0x1e05, 0x1e05,
- 0x1e07, 0x1e07,
- 0x1e09, 0x1e09,
- 0x1e0b, 0x1e0b,
- 0x1e0d, 0x1e0d,
- 0x1e0f, 0x1e0f,
- 0x1e11, 0x1e11,
- 0x1e13, 0x1e13,
- 0x1e15, 0x1e15,
- 0x1e17, 0x1e17,
- 0x1e19, 0x1e19,
- 0x1e1b, 0x1e1b,
- 0x1e1d, 0x1e1d,
- 0x1e1f, 0x1e1f,
- 0x1e21, 0x1e21,
- 0x1e23, 0x1e23,
- 0x1e25, 0x1e25,
- 0x1e27, 0x1e27,
- 0x1e29, 0x1e29,
- 0x1e2b, 0x1e2b,
- 0x1e2d, 0x1e2d,
- 0x1e2f, 0x1e2f,
- 0x1e31, 0x1e31,
- 0x1e33, 0x1e33,
- 0x1e35, 0x1e35,
- 0x1e37, 0x1e37,
- 0x1e39, 0x1e39,
- 0x1e3b, 0x1e3b,
- 0x1e3d, 0x1e3d,
- 0x1e3f, 0x1e3f,
- 0x1e41, 0x1e41,
- 0x1e43, 0x1e43,
- 0x1e45, 0x1e45,
- 0x1e47, 0x1e47,
- 0x1e49, 0x1e49,
- 0x1e4b, 0x1e4b,
- 0x1e4d, 0x1e4d,
- 0x1e4f, 0x1e4f,
- 0x1e51, 0x1e51,
- 0x1e53, 0x1e53,
- 0x1e55, 0x1e55,
- 0x1e57, 0x1e57,
- 0x1e59, 0x1e59,
- 0x1e5b, 0x1e5b,
- 0x1e5d, 0x1e5d,
- 0x1e5f, 0x1e5f,
- 0x1e61, 0x1e61,
- 0x1e63, 0x1e63,
- 0x1e65, 0x1e65,
- 0x1e67, 0x1e67,
- 0x1e69, 0x1e69,
- 0x1e6b, 0x1e6b,
- 0x1e6d, 0x1e6d,
- 0x1e6f, 0x1e6f,
- 0x1e71, 0x1e71,
- 0x1e73, 0x1e73,
- 0x1e75, 0x1e75,
- 0x1e77, 0x1e77,
- 0x1e79, 0x1e79,
- 0x1e7b, 0x1e7b,
- 0x1e7d, 0x1e7d,
- 0x1e7f, 0x1e7f,
- 0x1e81, 0x1e81,
- 0x1e83, 0x1e83,
- 0x1e85, 0x1e85,
- 0x1e87, 0x1e87,
- 0x1e89, 0x1e89,
- 0x1e8b, 0x1e8b,
- 0x1e8d, 0x1e8d,
- 0x1e8f, 0x1e8f,
- 0x1e91, 0x1e91,
- 0x1e93, 0x1e93,
- 0x1e95, 0x1e9d,
- 0x1e9f, 0x1e9f,
- 0x1ea1, 0x1ea1,
- 0x1ea3, 0x1ea3,
- 0x1ea5, 0x1ea5,
- 0x1ea7, 0x1ea7,
- 0x1ea9, 0x1ea9,
- 0x1eab, 0x1eab,
- 0x1ead, 0x1ead,
- 0x1eaf, 0x1eaf,
- 0x1eb1, 0x1eb1,
- 0x1eb3, 0x1eb3,
- 0x1eb5, 0x1eb5,
- 0x1eb7, 0x1eb7,
- 0x1eb9, 0x1eb9,
- 0x1ebb, 0x1ebb,
- 0x1ebd, 0x1ebd,
- 0x1ebf, 0x1ebf,
- 0x1ec1, 0x1ec1,
- 0x1ec3, 0x1ec3,
- 0x1ec5, 0x1ec5,
- 0x1ec7, 0x1ec7,
- 0x1ec9, 0x1ec9,
- 0x1ecb, 0x1ecb,
- 0x1ecd, 0x1ecd,
- 0x1ecf, 0x1ecf,
- 0x1ed1, 0x1ed1,
- 0x1ed3, 0x1ed3,
- 0x1ed5, 0x1ed5,
- 0x1ed7, 0x1ed7,
- 0x1ed9, 0x1ed9,
- 0x1edb, 0x1edb,
- 0x1edd, 0x1edd,
- 0x1edf, 0x1edf,
- 0x1ee1, 0x1ee1,
- 0x1ee3, 0x1ee3,
- 0x1ee5, 0x1ee5,
- 0x1ee7, 0x1ee7,
- 0x1ee9, 0x1ee9,
- 0x1eeb, 0x1eeb,
- 0x1eed, 0x1eed,
- 0x1eef, 0x1eef,
- 0x1ef1, 0x1ef1,
- 0x1ef3, 0x1ef3,
- 0x1ef5, 0x1ef5,
- 0x1ef7, 0x1ef7,
- 0x1ef9, 0x1ef9,
- 0x1efb, 0x1efb,
- 0x1efd, 0x1efd,
- 0x1eff, 0x1f07,
- 0x1f10, 0x1f15,
- 0x1f20, 0x1f27,
- 0x1f30, 0x1f37,
- 0x1f40, 0x1f45,
- 0x1f50, 0x1f57,
- 0x1f60, 0x1f67,
- 0x1f70, 0x1f7d,
- 0x1f80, 0x1f87,
- 0x1f90, 0x1f97,
- 0x1fa0, 0x1fa7,
- 0x1fb0, 0x1fb4,
- 0x1fb6, 0x1fb7,
- 0x1fbe, 0x1fbe,
- 0x1fc2, 0x1fc4,
- 0x1fc6, 0x1fc7,
- 0x1fd0, 0x1fd3,
- 0x1fd6, 0x1fd7,
- 0x1fe0, 0x1fe7,
- 0x1ff2, 0x1ff4,
- 0x1ff6, 0x1ff7,
- 0x210a, 0x210a,
- 0x210e, 0x210f,
- 0x2113, 0x2113,
- 0x212f, 0x212f,
- 0x2134, 0x2134,
- 0x2139, 0x2139,
- 0x213c, 0x213d,
- 0x2146, 0x2149,
- 0x214e, 0x214e,
- 0x2184, 0x2184,
- 0x2c30, 0x2c5f,
- 0x2c61, 0x2c61,
- 0x2c65, 0x2c66,
- 0x2c68, 0x2c68,
- 0x2c6a, 0x2c6a,
- 0x2c6c, 0x2c6c,
- 0x2c71, 0x2c71,
- 0x2c73, 0x2c74,
- 0x2c76, 0x2c7b,
- 0x2c81, 0x2c81,
- 0x2c83, 0x2c83,
- 0x2c85, 0x2c85,
- 0x2c87, 0x2c87,
- 0x2c89, 0x2c89,
- 0x2c8b, 0x2c8b,
- 0x2c8d, 0x2c8d,
- 0x2c8f, 0x2c8f,
- 0x2c91, 0x2c91,
- 0x2c93, 0x2c93,
- 0x2c95, 0x2c95,
- 0x2c97, 0x2c97,
- 0x2c99, 0x2c99,
- 0x2c9b, 0x2c9b,
- 0x2c9d, 0x2c9d,
- 0x2c9f, 0x2c9f,
- 0x2ca1, 0x2ca1,
- 0x2ca3, 0x2ca3,
- 0x2ca5, 0x2ca5,
- 0x2ca7, 0x2ca7,
- 0x2ca9, 0x2ca9,
- 0x2cab, 0x2cab,
- 0x2cad, 0x2cad,
- 0x2caf, 0x2caf,
- 0x2cb1, 0x2cb1,
- 0x2cb3, 0x2cb3,
- 0x2cb5, 0x2cb5,
- 0x2cb7, 0x2cb7,
- 0x2cb9, 0x2cb9,
- 0x2cbb, 0x2cbb,
- 0x2cbd, 0x2cbd,
- 0x2cbf, 0x2cbf,
- 0x2cc1, 0x2cc1,
- 0x2cc3, 0x2cc3,
- 0x2cc5, 0x2cc5,
- 0x2cc7, 0x2cc7,
- 0x2cc9, 0x2cc9,
- 0x2ccb, 0x2ccb,
- 0x2ccd, 0x2ccd,
- 0x2ccf, 0x2ccf,
- 0x2cd1, 0x2cd1,
- 0x2cd3, 0x2cd3,
- 0x2cd5, 0x2cd5,
- 0x2cd7, 0x2cd7,
- 0x2cd9, 0x2cd9,
- 0x2cdb, 0x2cdb,
- 0x2cdd, 0x2cdd,
- 0x2cdf, 0x2cdf,
- 0x2ce1, 0x2ce1,
- 0x2ce3, 0x2ce4,
- 0x2cec, 0x2cec,
- 0x2cee, 0x2cee,
- 0x2cf3, 0x2cf3,
- 0x2d00, 0x2d25,
- 0x2d27, 0x2d27,
- 0x2d2d, 0x2d2d,
- 0xa641, 0xa641,
- 0xa643, 0xa643,
- 0xa645, 0xa645,
- 0xa647, 0xa647,
- 0xa649, 0xa649,
- 0xa64b, 0xa64b,
- 0xa64d, 0xa64d,
- 0xa64f, 0xa64f,
- 0xa651, 0xa651,
- 0xa653, 0xa653,
- 0xa655, 0xa655,
- 0xa657, 0xa657,
- 0xa659, 0xa659,
- 0xa65b, 0xa65b,
- 0xa65d, 0xa65d,
- 0xa65f, 0xa65f,
- 0xa661, 0xa661,
- 0xa663, 0xa663,
- 0xa665, 0xa665,
- 0xa667, 0xa667,
- 0xa669, 0xa669,
- 0xa66b, 0xa66b,
- 0xa66d, 0xa66d,
- 0xa681, 0xa681,
- 0xa683, 0xa683,
- 0xa685, 0xa685,
- 0xa687, 0xa687,
- 0xa689, 0xa689,
- 0xa68b, 0xa68b,
- 0xa68d, 0xa68d,
- 0xa68f, 0xa68f,
- 0xa691, 0xa691,
- 0xa693, 0xa693,
- 0xa695, 0xa695,
- 0xa697, 0xa697,
- 0xa699, 0xa699,
- 0xa69b, 0xa69b,
- 0xa723, 0xa723,
- 0xa725, 0xa725,
- 0xa727, 0xa727,
- 0xa729, 0xa729,
- 0xa72b, 0xa72b,
- 0xa72d, 0xa72d,
- 0xa72f, 0xa731,
- 0xa733, 0xa733,
- 0xa735, 0xa735,
- 0xa737, 0xa737,
- 0xa739, 0xa739,
- 0xa73b, 0xa73b,
- 0xa73d, 0xa73d,
- 0xa73f, 0xa73f,
- 0xa741, 0xa741,
- 0xa743, 0xa743,
- 0xa745, 0xa745,
- 0xa747, 0xa747,
- 0xa749, 0xa749,
- 0xa74b, 0xa74b,
- 0xa74d, 0xa74d,
- 0xa74f, 0xa74f,
- 0xa751, 0xa751,
- 0xa753, 0xa753,
- 0xa755, 0xa755,
- 0xa757, 0xa757,
- 0xa759, 0xa759,
- 0xa75b, 0xa75b,
- 0xa75d, 0xa75d,
- 0xa75f, 0xa75f,
- 0xa761, 0xa761,
- 0xa763, 0xa763,
- 0xa765, 0xa765,
- 0xa767, 0xa767,
- 0xa769, 0xa769,
- 0xa76b, 0xa76b,
- 0xa76d, 0xa76d,
- 0xa76f, 0xa76f,
- 0xa771, 0xa778,
- 0xa77a, 0xa77a,
- 0xa77c, 0xa77c,
- 0xa77f, 0xa77f,
- 0xa781, 0xa781,
- 0xa783, 0xa783,
- 0xa785, 0xa785,
- 0xa787, 0xa787,
- 0xa78c, 0xa78c,
- 0xa78e, 0xa78e,
- 0xa791, 0xa791,
- 0xa793, 0xa795,
- 0xa797, 0xa797,
- 0xa799, 0xa799,
- 0xa79b, 0xa79b,
- 0xa79d, 0xa79d,
- 0xa79f, 0xa79f,
- 0xa7a1, 0xa7a1,
- 0xa7a3, 0xa7a3,
- 0xa7a5, 0xa7a5,
- 0xa7a7, 0xa7a7,
- 0xa7a9, 0xa7a9,
- 0xa7af, 0xa7af,
- 0xa7b5, 0xa7b5,
- 0xa7b7, 0xa7b7,
- 0xa7b9, 0xa7b9,
- 0xa7bb, 0xa7bb,
- 0xa7bd, 0xa7bd,
- 0xa7bf, 0xa7bf,
- 0xa7c1, 0xa7c1,
- 0xa7c3, 0xa7c3,
- 0xa7c8, 0xa7c8,
- 0xa7ca, 0xa7ca,
- 0xa7cd, 0xa7cd,
- 0xa7d1, 0xa7d1,
- 0xa7d3, 0xa7d3,
- 0xa7d5, 0xa7d5,
- 0xa7d7, 0xa7d7,
- 0xa7d9, 0xa7d9,
- 0xa7db, 0xa7db,
- 0xa7f6, 0xa7f6,
- 0xa7fa, 0xa7fa,
- 0xab30, 0xab5a,
- 0xab60, 0xab68,
- 0xab70, 0xabbf,
- 0xfb00, 0xfb06,
- 0xfb13, 0xfb17,
- 0xff41, 0xff5a,
- 0x10428, 0x1044f,
- 0x104d8, 0x104fb,
- 0x10597, 0x105a1,
- 0x105a3, 0x105b1,
- 0x105b3, 0x105b9,
- 0x105bb, 0x105bc,
- 0x10cc0, 0x10cf2,
- 0x10d70, 0x10d85,
- 0x118c0, 0x118df,
- 0x16e60, 0x16e7f,
- 0x1d41a, 0x1d433,
- 0x1d44e, 0x1d454,
- 0x1d456, 0x1d467,
- 0x1d482, 0x1d49b,
- 0x1d4b6, 0x1d4b9,
- 0x1d4bb, 0x1d4bb,
- 0x1d4bd, 0x1d4c3,
- 0x1d4c5, 0x1d4cf,
- 0x1d4ea, 0x1d503,
- 0x1d51e, 0x1d537,
- 0x1d552, 0x1d56b,
- 0x1d586, 0x1d59f,
- 0x1d5ba, 0x1d5d3,
- 0x1d5ee, 0x1d607,
- 0x1d622, 0x1d63b,
- 0x1d656, 0x1d66f,
- 0x1d68a, 0x1d6a5,
- 0x1d6c2, 0x1d6da,
- 0x1d6dc, 0x1d6e1,
- 0x1d6fc, 0x1d714,
- 0x1d716, 0x1d71b,
- 0x1d736, 0x1d74e,
- 0x1d750, 0x1d755,
- 0x1d770, 0x1d788,
- 0x1d78a, 0x1d78f,
- 0x1d7aa, 0x1d7c2,
- 0x1d7c4, 0x1d7c9,
- 0x1d7cb, 0x1d7cb,
- 0x1df00, 0x1df09,
- 0x1df0b, 0x1df1e,
- 0x1df25, 0x1df2a,
- 0x1e922, 0x1e943,
-}; /* CR_Ll */
-
-/* 'Lm': General Category */
-static const OnigCodePoint CR_Lm[] = {
- 75,
- 0x02b0, 0x02c1,
- 0x02c6, 0x02d1,
- 0x02e0, 0x02e4,
- 0x02ec, 0x02ec,
- 0x02ee, 0x02ee,
- 0x0374, 0x0374,
- 0x037a, 0x037a,
- 0x0559, 0x0559,
- 0x0640, 0x0640,
- 0x06e5, 0x06e6,
- 0x07f4, 0x07f5,
- 0x07fa, 0x07fa,
- 0x081a, 0x081a,
- 0x0824, 0x0824,
- 0x0828, 0x0828,
- 0x08c9, 0x08c9,
- 0x0971, 0x0971,
- 0x0e46, 0x0e46,
- 0x0ec6, 0x0ec6,
- 0x10fc, 0x10fc,
- 0x17d7, 0x17d7,
- 0x1843, 0x1843,
- 0x1aa7, 0x1aa7,
- 0x1c78, 0x1c7d,
- 0x1d2c, 0x1d6a,
- 0x1d78, 0x1d78,
- 0x1d9b, 0x1dbf,
- 0x2071, 0x2071,
- 0x207f, 0x207f,
- 0x2090, 0x209c,
- 0x2c7c, 0x2c7d,
- 0x2d6f, 0x2d6f,
- 0x2e2f, 0x2e2f,
- 0x3005, 0x3005,
- 0x3031, 0x3035,
- 0x303b, 0x303b,
- 0x309d, 0x309e,
- 0x30fc, 0x30fe,
- 0xa015, 0xa015,
- 0xa4f8, 0xa4fd,
- 0xa60c, 0xa60c,
- 0xa67f, 0xa67f,
- 0xa69c, 0xa69d,
- 0xa717, 0xa71f,
- 0xa770, 0xa770,
- 0xa788, 0xa788,
- 0xa7f2, 0xa7f4,
- 0xa7f8, 0xa7f9,
- 0xa9cf, 0xa9cf,
- 0xa9e6, 0xa9e6,
- 0xaa70, 0xaa70,
- 0xaadd, 0xaadd,
- 0xaaf3, 0xaaf4,
- 0xab5c, 0xab5f,
- 0xab69, 0xab69,
- 0xff70, 0xff70,
- 0xff9e, 0xff9f,
- 0x10780, 0x10785,
- 0x10787, 0x107b0,
- 0x107b2, 0x107ba,
- 0x10d4e, 0x10d4e,
- 0x10d6f, 0x10d6f,
- 0x16b40, 0x16b43,
- 0x16d40, 0x16d42,
- 0x16d6b, 0x16d6c,
- 0x16f93, 0x16f9f,
- 0x16fe0, 0x16fe1,
- 0x16fe3, 0x16fe3,
- 0x1aff0, 0x1aff3,
- 0x1aff5, 0x1affb,
- 0x1affd, 0x1affe,
- 0x1e030, 0x1e06d,
- 0x1e137, 0x1e13d,
- 0x1e4eb, 0x1e4eb,
- 0x1e94b, 0x1e94b,
-}; /* CR_Lm */
-
-/* 'Lo': General Category */
-static const OnigCodePoint CR_Lo[] = {
- 528,
- 0x00aa, 0x00aa,
- 0x00ba, 0x00ba,
- 0x01bb, 0x01bb,
- 0x01c0, 0x01c3,
- 0x0294, 0x0294,
- 0x05d0, 0x05ea,
- 0x05ef, 0x05f2,
- 0x0620, 0x063f,
- 0x0641, 0x064a,
- 0x066e, 0x066f,
- 0x0671, 0x06d3,
- 0x06d5, 0x06d5,
- 0x06ee, 0x06ef,
- 0x06fa, 0x06fc,
- 0x06ff, 0x06ff,
- 0x0710, 0x0710,
- 0x0712, 0x072f,
- 0x074d, 0x07a5,
- 0x07b1, 0x07b1,
- 0x07ca, 0x07ea,
- 0x0800, 0x0815,
- 0x0840, 0x0858,
- 0x0860, 0x086a,
- 0x0870, 0x0887,
- 0x0889, 0x088e,
- 0x08a0, 0x08c8,
- 0x0904, 0x0939,
- 0x093d, 0x093d,
- 0x0950, 0x0950,
- 0x0958, 0x0961,
- 0x0972, 0x0980,
- 0x0985, 0x098c,
- 0x098f, 0x0990,
- 0x0993, 0x09a8,
- 0x09aa, 0x09b0,
- 0x09b2, 0x09b2,
- 0x09b6, 0x09b9,
- 0x09bd, 0x09bd,
- 0x09ce, 0x09ce,
- 0x09dc, 0x09dd,
- 0x09df, 0x09e1,
- 0x09f0, 0x09f1,
- 0x09fc, 0x09fc,
- 0x0a05, 0x0a0a,
- 0x0a0f, 0x0a10,
- 0x0a13, 0x0a28,
- 0x0a2a, 0x0a30,
- 0x0a32, 0x0a33,
- 0x0a35, 0x0a36,
- 0x0a38, 0x0a39,
- 0x0a59, 0x0a5c,
- 0x0a5e, 0x0a5e,
- 0x0a72, 0x0a74,
- 0x0a85, 0x0a8d,
- 0x0a8f, 0x0a91,
- 0x0a93, 0x0aa8,
- 0x0aaa, 0x0ab0,
- 0x0ab2, 0x0ab3,
- 0x0ab5, 0x0ab9,
- 0x0abd, 0x0abd,
- 0x0ad0, 0x0ad0,
- 0x0ae0, 0x0ae1,
- 0x0af9, 0x0af9,
- 0x0b05, 0x0b0c,
- 0x0b0f, 0x0b10,
- 0x0b13, 0x0b28,
- 0x0b2a, 0x0b30,
- 0x0b32, 0x0b33,
- 0x0b35, 0x0b39,
- 0x0b3d, 0x0b3d,
- 0x0b5c, 0x0b5d,
- 0x0b5f, 0x0b61,
- 0x0b71, 0x0b71,
- 0x0b83, 0x0b83,
- 0x0b85, 0x0b8a,
- 0x0b8e, 0x0b90,
- 0x0b92, 0x0b95,
- 0x0b99, 0x0b9a,
- 0x0b9c, 0x0b9c,
- 0x0b9e, 0x0b9f,
- 0x0ba3, 0x0ba4,
- 0x0ba8, 0x0baa,
- 0x0bae, 0x0bb9,
- 0x0bd0, 0x0bd0,
- 0x0c05, 0x0c0c,
- 0x0c0e, 0x0c10,
- 0x0c12, 0x0c28,
- 0x0c2a, 0x0c39,
- 0x0c3d, 0x0c3d,
- 0x0c58, 0x0c5a,
- 0x0c5d, 0x0c5d,
- 0x0c60, 0x0c61,
- 0x0c80, 0x0c80,
- 0x0c85, 0x0c8c,
- 0x0c8e, 0x0c90,
- 0x0c92, 0x0ca8,
- 0x0caa, 0x0cb3,
- 0x0cb5, 0x0cb9,
- 0x0cbd, 0x0cbd,
- 0x0cdd, 0x0cde,
- 0x0ce0, 0x0ce1,
- 0x0cf1, 0x0cf2,
- 0x0d04, 0x0d0c,
- 0x0d0e, 0x0d10,
- 0x0d12, 0x0d3a,
- 0x0d3d, 0x0d3d,
- 0x0d4e, 0x0d4e,
- 0x0d54, 0x0d56,
- 0x0d5f, 0x0d61,
- 0x0d7a, 0x0d7f,
- 0x0d85, 0x0d96,
- 0x0d9a, 0x0db1,
- 0x0db3, 0x0dbb,
- 0x0dbd, 0x0dbd,
- 0x0dc0, 0x0dc6,
- 0x0e01, 0x0e30,
- 0x0e32, 0x0e33,
- 0x0e40, 0x0e45,
- 0x0e81, 0x0e82,
- 0x0e84, 0x0e84,
- 0x0e86, 0x0e8a,
- 0x0e8c, 0x0ea3,
- 0x0ea5, 0x0ea5,
- 0x0ea7, 0x0eb0,
- 0x0eb2, 0x0eb3,
- 0x0ebd, 0x0ebd,
- 0x0ec0, 0x0ec4,
- 0x0edc, 0x0edf,
- 0x0f00, 0x0f00,
- 0x0f40, 0x0f47,
- 0x0f49, 0x0f6c,
- 0x0f88, 0x0f8c,
- 0x1000, 0x102a,
- 0x103f, 0x103f,
- 0x1050, 0x1055,
- 0x105a, 0x105d,
- 0x1061, 0x1061,
- 0x1065, 0x1066,
- 0x106e, 0x1070,
- 0x1075, 0x1081,
- 0x108e, 0x108e,
- 0x1100, 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,
- 0x1401, 0x166c,
- 0x166f, 0x167f,
- 0x1681, 0x169a,
- 0x16a0, 0x16ea,
- 0x16f1, 0x16f8,
- 0x1700, 0x1711,
- 0x171f, 0x1731,
- 0x1740, 0x1751,
- 0x1760, 0x176c,
- 0x176e, 0x1770,
- 0x1780, 0x17b3,
- 0x17dc, 0x17dc,
- 0x1820, 0x1842,
- 0x1844, 0x1878,
- 0x1880, 0x1884,
- 0x1887, 0x18a8,
- 0x18aa, 0x18aa,
- 0x18b0, 0x18f5,
- 0x1900, 0x191e,
- 0x1950, 0x196d,
- 0x1970, 0x1974,
- 0x1980, 0x19ab,
- 0x19b0, 0x19c9,
- 0x1a00, 0x1a16,
- 0x1a20, 0x1a54,
- 0x1b05, 0x1b33,
- 0x1b45, 0x1b4c,
- 0x1b83, 0x1ba0,
- 0x1bae, 0x1baf,
- 0x1bba, 0x1be5,
- 0x1c00, 0x1c23,
- 0x1c4d, 0x1c4f,
- 0x1c5a, 0x1c77,
- 0x1ce9, 0x1cec,
- 0x1cee, 0x1cf3,
- 0x1cf5, 0x1cf6,
- 0x1cfa, 0x1cfa,
- 0x2135, 0x2138,
- 0x2d30, 0x2d67,
- 0x2d80, 0x2d96,
- 0x2da0, 0x2da6,
- 0x2da8, 0x2dae,
- 0x2db0, 0x2db6,
- 0x2db8, 0x2dbe,
- 0x2dc0, 0x2dc6,
- 0x2dc8, 0x2dce,
- 0x2dd0, 0x2dd6,
- 0x2dd8, 0x2dde,
- 0x3006, 0x3006,
- 0x303c, 0x303c,
- 0x3041, 0x3096,
- 0x309f, 0x309f,
- 0x30a1, 0x30fa,
- 0x30ff, 0x30ff,
- 0x3105, 0x312f,
- 0x3131, 0x318e,
- 0x31a0, 0x31bf,
- 0x31f0, 0x31ff,
- 0x3400, 0x4dbf,
- 0x4e00, 0xa014,
- 0xa016, 0xa48c,
- 0xa4d0, 0xa4f7,
- 0xa500, 0xa60b,
- 0xa610, 0xa61f,
- 0xa62a, 0xa62b,
- 0xa66e, 0xa66e,
- 0xa6a0, 0xa6e5,
- 0xa78f, 0xa78f,
- 0xa7f7, 0xa7f7,
- 0xa7fb, 0xa801,
- 0xa803, 0xa805,
- 0xa807, 0xa80a,
- 0xa80c, 0xa822,
- 0xa840, 0xa873,
- 0xa882, 0xa8b3,
- 0xa8f2, 0xa8f7,
- 0xa8fb, 0xa8fb,
- 0xa8fd, 0xa8fe,
- 0xa90a, 0xa925,
- 0xa930, 0xa946,
- 0xa960, 0xa97c,
- 0xa984, 0xa9b2,
- 0xa9e0, 0xa9e4,
- 0xa9e7, 0xa9ef,
- 0xa9fa, 0xa9fe,
- 0xaa00, 0xaa28,
- 0xaa40, 0xaa42,
- 0xaa44, 0xaa4b,
- 0xaa60, 0xaa6f,
- 0xaa71, 0xaa76,
- 0xaa7a, 0xaa7a,
- 0xaa7e, 0xaaaf,
- 0xaab1, 0xaab1,
- 0xaab5, 0xaab6,
- 0xaab9, 0xaabd,
- 0xaac0, 0xaac0,
- 0xaac2, 0xaac2,
- 0xaadb, 0xaadc,
- 0xaae0, 0xaaea,
- 0xaaf2, 0xaaf2,
- 0xab01, 0xab06,
- 0xab09, 0xab0e,
- 0xab11, 0xab16,
- 0xab20, 0xab26,
- 0xab28, 0xab2e,
- 0xabc0, 0xabe2,
- 0xac00, 0xd7a3,
- 0xd7b0, 0xd7c6,
- 0xd7cb, 0xd7fb,
- 0xf900, 0xfa6d,
- 0xfa70, 0xfad9,
- 0xfb1d, 0xfb1d,
- 0xfb1f, 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,
- 0xff66, 0xff6f,
- 0xff71, 0xff9d,
- 0xffa0, 0xffbe,
- 0xffc2, 0xffc7,
- 0xffca, 0xffcf,
- 0xffd2, 0xffd7,
- 0xffda, 0xffdc,
- 0x10000, 0x1000b,
- 0x1000d, 0x10026,
- 0x10028, 0x1003a,
- 0x1003c, 0x1003d,
- 0x1003f, 0x1004d,
- 0x10050, 0x1005d,
- 0x10080, 0x100fa,
- 0x10280, 0x1029c,
- 0x102a0, 0x102d0,
- 0x10300, 0x1031f,
- 0x1032d, 0x10340,
- 0x10342, 0x10349,
- 0x10350, 0x10375,
- 0x10380, 0x1039d,
- 0x103a0, 0x103c3,
- 0x103c8, 0x103cf,
- 0x10450, 0x1049d,
- 0x10500, 0x10527,
- 0x10530, 0x10563,
- 0x105c0, 0x105f3,
- 0x10600, 0x10736,
- 0x10740, 0x10755,
- 0x10760, 0x10767,
- 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, 0x10a00,
- 0x10a10, 0x10a13,
- 0x10a15, 0x10a17,
- 0x10a19, 0x10a35,
- 0x10a60, 0x10a7c,
- 0x10a80, 0x10a9c,
- 0x10ac0, 0x10ac7,
- 0x10ac9, 0x10ae4,
- 0x10b00, 0x10b35,
- 0x10b40, 0x10b55,
- 0x10b60, 0x10b72,
- 0x10b80, 0x10b91,
- 0x10c00, 0x10c48,
- 0x10d00, 0x10d23,
- 0x10d4a, 0x10d4d,
- 0x10d4f, 0x10d4f,
- 0x10e80, 0x10ea9,
- 0x10eb0, 0x10eb1,
- 0x10ec2, 0x10ec4,
- 0x10f00, 0x10f1c,
- 0x10f27, 0x10f27,
- 0x10f30, 0x10f45,
- 0x10f70, 0x10f81,
- 0x10fb0, 0x10fc4,
- 0x10fe0, 0x10ff6,
- 0x11003, 0x11037,
- 0x11071, 0x11072,
- 0x11075, 0x11075,
- 0x11083, 0x110af,
- 0x110d0, 0x110e8,
- 0x11103, 0x11126,
- 0x11144, 0x11144,
- 0x11147, 0x11147,
- 0x11150, 0x11172,
- 0x11176, 0x11176,
- 0x11183, 0x111b2,
- 0x111c1, 0x111c4,
- 0x111da, 0x111da,
- 0x111dc, 0x111dc,
- 0x11200, 0x11211,
- 0x11213, 0x1122b,
- 0x1123f, 0x11240,
- 0x11280, 0x11286,
- 0x11288, 0x11288,
- 0x1128a, 0x1128d,
- 0x1128f, 0x1129d,
- 0x1129f, 0x112a8,
- 0x112b0, 0x112de,
- 0x11305, 0x1130c,
- 0x1130f, 0x11310,
- 0x11313, 0x11328,
- 0x1132a, 0x11330,
- 0x11332, 0x11333,
- 0x11335, 0x11339,
- 0x1133d, 0x1133d,
- 0x11350, 0x11350,
- 0x1135d, 0x11361,
- 0x11380, 0x11389,
- 0x1138b, 0x1138b,
- 0x1138e, 0x1138e,
- 0x11390, 0x113b5,
- 0x113b7, 0x113b7,
- 0x113d1, 0x113d1,
- 0x113d3, 0x113d3,
- 0x11400, 0x11434,
- 0x11447, 0x1144a,
- 0x1145f, 0x11461,
- 0x11480, 0x114af,
- 0x114c4, 0x114c5,
- 0x114c7, 0x114c7,
- 0x11580, 0x115ae,
- 0x115d8, 0x115db,
- 0x11600, 0x1162f,
- 0x11644, 0x11644,
- 0x11680, 0x116aa,
- 0x116b8, 0x116b8,
- 0x11700, 0x1171a,
- 0x11740, 0x11746,
- 0x11800, 0x1182b,
- 0x118ff, 0x11906,
- 0x11909, 0x11909,
- 0x1190c, 0x11913,
- 0x11915, 0x11916,
- 0x11918, 0x1192f,
- 0x1193f, 0x1193f,
- 0x11941, 0x11941,
- 0x119a0, 0x119a7,
- 0x119aa, 0x119d0,
- 0x119e1, 0x119e1,
- 0x119e3, 0x119e3,
- 0x11a00, 0x11a00,
- 0x11a0b, 0x11a32,
- 0x11a3a, 0x11a3a,
- 0x11a50, 0x11a50,
- 0x11a5c, 0x11a89,
- 0x11a9d, 0x11a9d,
- 0x11ab0, 0x11af8,
- 0x11bc0, 0x11be0,
- 0x11c00, 0x11c08,
- 0x11c0a, 0x11c2e,
- 0x11c40, 0x11c40,
- 0x11c72, 0x11c8f,
- 0x11d00, 0x11d06,
- 0x11d08, 0x11d09,
- 0x11d0b, 0x11d30,
- 0x11d46, 0x11d46,
- 0x11d60, 0x11d65,
- 0x11d67, 0x11d68,
- 0x11d6a, 0x11d89,
- 0x11d98, 0x11d98,
- 0x11ee0, 0x11ef2,
- 0x11f02, 0x11f02,
- 0x11f04, 0x11f10,
- 0x11f12, 0x11f33,
- 0x11fb0, 0x11fb0,
- 0x12000, 0x12399,
- 0x12480, 0x12543,
- 0x12f90, 0x12ff0,
- 0x13000, 0x1342f,
- 0x13441, 0x13446,
- 0x13460, 0x143fa,
- 0x14400, 0x14646,
- 0x16100, 0x1611d,
- 0x16800, 0x16a38,
- 0x16a40, 0x16a5e,
- 0x16a70, 0x16abe,
- 0x16ad0, 0x16aed,
- 0x16b00, 0x16b2f,
- 0x16b63, 0x16b77,
- 0x16b7d, 0x16b8f,
- 0x16d43, 0x16d6a,
- 0x16f00, 0x16f4a,
- 0x16f50, 0x16f50,
- 0x17000, 0x187f7,
- 0x18800, 0x18cd5,
- 0x18cff, 0x18d08,
- 0x1b000, 0x1b122,
- 0x1b132, 0x1b132,
- 0x1b150, 0x1b152,
- 0x1b155, 0x1b155,
- 0x1b164, 0x1b167,
- 0x1b170, 0x1b2fb,
- 0x1bc00, 0x1bc6a,
- 0x1bc70, 0x1bc7c,
- 0x1bc80, 0x1bc88,
- 0x1bc90, 0x1bc99,
- 0x1df0a, 0x1df0a,
- 0x1e100, 0x1e12c,
- 0x1e14e, 0x1e14e,
- 0x1e290, 0x1e2ad,
- 0x1e2c0, 0x1e2eb,
- 0x1e4d0, 0x1e4ea,
- 0x1e5d0, 0x1e5ed,
- 0x1e5f0, 0x1e5f0,
- 0x1e7e0, 0x1e7e6,
- 0x1e7e8, 0x1e7eb,
- 0x1e7ed, 0x1e7ee,
- 0x1e7f0, 0x1e7fe,
- 0x1e800, 0x1e8c4,
- 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,
- 0x20000, 0x2a6df,
- 0x2a700, 0x2b739,
- 0x2b740, 0x2b81d,
- 0x2b820, 0x2cea1,
- 0x2ceb0, 0x2ebe0,
- 0x2ebf0, 0x2ee5d,
- 0x2f800, 0x2fa1d,
- 0x30000, 0x3134a,
- 0x31350, 0x323af,
-}; /* CR_Lo */
-
-/* 'Lt': General Category */
-static const OnigCodePoint CR_Lt[] = {
- 10,
- 0x01c5, 0x01c5,
- 0x01c8, 0x01c8,
- 0x01cb, 0x01cb,
- 0x01f2, 0x01f2,
- 0x1f88, 0x1f8f,
- 0x1f98, 0x1f9f,
- 0x1fa8, 0x1faf,
- 0x1fbc, 0x1fbc,
- 0x1fcc, 0x1fcc,
- 0x1ffc, 0x1ffc,
-}; /* CR_Lt */
-
-/* 'Lu': General Category */
-static const OnigCodePoint CR_Lu[] = {
- 651,
- 0x0041, 0x005a,
- 0x00c0, 0x00d6,
- 0x00d8, 0x00de,
- 0x0100, 0x0100,
- 0x0102, 0x0102,
- 0x0104, 0x0104,
- 0x0106, 0x0106,
- 0x0108, 0x0108,
- 0x010a, 0x010a,
- 0x010c, 0x010c,
- 0x010e, 0x010e,
- 0x0110, 0x0110,
- 0x0112, 0x0112,
- 0x0114, 0x0114,
- 0x0116, 0x0116,
- 0x0118, 0x0118,
- 0x011a, 0x011a,
- 0x011c, 0x011c,
- 0x011e, 0x011e,
- 0x0120, 0x0120,
- 0x0122, 0x0122,
- 0x0124, 0x0124,
- 0x0126, 0x0126,
- 0x0128, 0x0128,
- 0x012a, 0x012a,
- 0x012c, 0x012c,
- 0x012e, 0x012e,
- 0x0130, 0x0130,
- 0x0132, 0x0132,
- 0x0134, 0x0134,
- 0x0136, 0x0136,
- 0x0139, 0x0139,
- 0x013b, 0x013b,
- 0x013d, 0x013d,
- 0x013f, 0x013f,
- 0x0141, 0x0141,
- 0x0143, 0x0143,
- 0x0145, 0x0145,
- 0x0147, 0x0147,
- 0x014a, 0x014a,
- 0x014c, 0x014c,
- 0x014e, 0x014e,
- 0x0150, 0x0150,
- 0x0152, 0x0152,
- 0x0154, 0x0154,
- 0x0156, 0x0156,
- 0x0158, 0x0158,
- 0x015a, 0x015a,
- 0x015c, 0x015c,
- 0x015e, 0x015e,
- 0x0160, 0x0160,
- 0x0162, 0x0162,
- 0x0164, 0x0164,
- 0x0166, 0x0166,
- 0x0168, 0x0168,
- 0x016a, 0x016a,
- 0x016c, 0x016c,
- 0x016e, 0x016e,
- 0x0170, 0x0170,
- 0x0172, 0x0172,
- 0x0174, 0x0174,
- 0x0176, 0x0176,
- 0x0178, 0x0179,
- 0x017b, 0x017b,
- 0x017d, 0x017d,
- 0x0181, 0x0182,
- 0x0184, 0x0184,
- 0x0186, 0x0187,
- 0x0189, 0x018b,
- 0x018e, 0x0191,
- 0x0193, 0x0194,
- 0x0196, 0x0198,
- 0x019c, 0x019d,
- 0x019f, 0x01a0,
- 0x01a2, 0x01a2,
- 0x01a4, 0x01a4,
- 0x01a6, 0x01a7,
- 0x01a9, 0x01a9,
- 0x01ac, 0x01ac,
- 0x01ae, 0x01af,
- 0x01b1, 0x01b3,
- 0x01b5, 0x01b5,
- 0x01b7, 0x01b8,
- 0x01bc, 0x01bc,
- 0x01c4, 0x01c4,
- 0x01c7, 0x01c7,
- 0x01ca, 0x01ca,
- 0x01cd, 0x01cd,
- 0x01cf, 0x01cf,
- 0x01d1, 0x01d1,
- 0x01d3, 0x01d3,
- 0x01d5, 0x01d5,
- 0x01d7, 0x01d7,
- 0x01d9, 0x01d9,
- 0x01db, 0x01db,
- 0x01de, 0x01de,
- 0x01e0, 0x01e0,
- 0x01e2, 0x01e2,
- 0x01e4, 0x01e4,
- 0x01e6, 0x01e6,
- 0x01e8, 0x01e8,
- 0x01ea, 0x01ea,
- 0x01ec, 0x01ec,
- 0x01ee, 0x01ee,
- 0x01f1, 0x01f1,
- 0x01f4, 0x01f4,
- 0x01f6, 0x01f8,
- 0x01fa, 0x01fa,
- 0x01fc, 0x01fc,
- 0x01fe, 0x01fe,
- 0x0200, 0x0200,
- 0x0202, 0x0202,
- 0x0204, 0x0204,
- 0x0206, 0x0206,
- 0x0208, 0x0208,
- 0x020a, 0x020a,
- 0x020c, 0x020c,
- 0x020e, 0x020e,
- 0x0210, 0x0210,
- 0x0212, 0x0212,
- 0x0214, 0x0214,
- 0x0216, 0x0216,
- 0x0218, 0x0218,
- 0x021a, 0x021a,
- 0x021c, 0x021c,
- 0x021e, 0x021e,
- 0x0220, 0x0220,
- 0x0222, 0x0222,
- 0x0224, 0x0224,
- 0x0226, 0x0226,
- 0x0228, 0x0228,
- 0x022a, 0x022a,
- 0x022c, 0x022c,
- 0x022e, 0x022e,
- 0x0230, 0x0230,
- 0x0232, 0x0232,
- 0x023a, 0x023b,
- 0x023d, 0x023e,
- 0x0241, 0x0241,
- 0x0243, 0x0246,
- 0x0248, 0x0248,
- 0x024a, 0x024a,
- 0x024c, 0x024c,
- 0x024e, 0x024e,
- 0x0370, 0x0370,
- 0x0372, 0x0372,
- 0x0376, 0x0376,
- 0x037f, 0x037f,
- 0x0386, 0x0386,
- 0x0388, 0x038a,
- 0x038c, 0x038c,
- 0x038e, 0x038f,
- 0x0391, 0x03a1,
- 0x03a3, 0x03ab,
- 0x03cf, 0x03cf,
- 0x03d2, 0x03d4,
- 0x03d8, 0x03d8,
- 0x03da, 0x03da,
- 0x03dc, 0x03dc,
- 0x03de, 0x03de,
- 0x03e0, 0x03e0,
- 0x03e2, 0x03e2,
- 0x03e4, 0x03e4,
- 0x03e6, 0x03e6,
- 0x03e8, 0x03e8,
- 0x03ea, 0x03ea,
- 0x03ec, 0x03ec,
- 0x03ee, 0x03ee,
- 0x03f4, 0x03f4,
- 0x03f7, 0x03f7,
- 0x03f9, 0x03fa,
- 0x03fd, 0x042f,
- 0x0460, 0x0460,
- 0x0462, 0x0462,
- 0x0464, 0x0464,
- 0x0466, 0x0466,
- 0x0468, 0x0468,
- 0x046a, 0x046a,
- 0x046c, 0x046c,
- 0x046e, 0x046e,
- 0x0470, 0x0470,
- 0x0472, 0x0472,
- 0x0474, 0x0474,
- 0x0476, 0x0476,
- 0x0478, 0x0478,
- 0x047a, 0x047a,
- 0x047c, 0x047c,
- 0x047e, 0x047e,
- 0x0480, 0x0480,
- 0x048a, 0x048a,
- 0x048c, 0x048c,
- 0x048e, 0x048e,
- 0x0490, 0x0490,
- 0x0492, 0x0492,
- 0x0494, 0x0494,
- 0x0496, 0x0496,
- 0x0498, 0x0498,
- 0x049a, 0x049a,
- 0x049c, 0x049c,
- 0x049e, 0x049e,
- 0x04a0, 0x04a0,
- 0x04a2, 0x04a2,
- 0x04a4, 0x04a4,
- 0x04a6, 0x04a6,
- 0x04a8, 0x04a8,
- 0x04aa, 0x04aa,
- 0x04ac, 0x04ac,
- 0x04ae, 0x04ae,
- 0x04b0, 0x04b0,
- 0x04b2, 0x04b2,
- 0x04b4, 0x04b4,
- 0x04b6, 0x04b6,
- 0x04b8, 0x04b8,
- 0x04ba, 0x04ba,
- 0x04bc, 0x04bc,
- 0x04be, 0x04be,
- 0x04c0, 0x04c1,
- 0x04c3, 0x04c3,
- 0x04c5, 0x04c5,
- 0x04c7, 0x04c7,
- 0x04c9, 0x04c9,
- 0x04cb, 0x04cb,
- 0x04cd, 0x04cd,
- 0x04d0, 0x04d0,
- 0x04d2, 0x04d2,
- 0x04d4, 0x04d4,
- 0x04d6, 0x04d6,
- 0x04d8, 0x04d8,
- 0x04da, 0x04da,
- 0x04dc, 0x04dc,
- 0x04de, 0x04de,
- 0x04e0, 0x04e0,
- 0x04e2, 0x04e2,
- 0x04e4, 0x04e4,
- 0x04e6, 0x04e6,
- 0x04e8, 0x04e8,
- 0x04ea, 0x04ea,
- 0x04ec, 0x04ec,
- 0x04ee, 0x04ee,
- 0x04f0, 0x04f0,
- 0x04f2, 0x04f2,
- 0x04f4, 0x04f4,
- 0x04f6, 0x04f6,
- 0x04f8, 0x04f8,
- 0x04fa, 0x04fa,
- 0x04fc, 0x04fc,
- 0x04fe, 0x04fe,
- 0x0500, 0x0500,
- 0x0502, 0x0502,
- 0x0504, 0x0504,
- 0x0506, 0x0506,
- 0x0508, 0x0508,
- 0x050a, 0x050a,
- 0x050c, 0x050c,
- 0x050e, 0x050e,
- 0x0510, 0x0510,
- 0x0512, 0x0512,
- 0x0514, 0x0514,
- 0x0516, 0x0516,
- 0x0518, 0x0518,
- 0x051a, 0x051a,
- 0x051c, 0x051c,
- 0x051e, 0x051e,
- 0x0520, 0x0520,
- 0x0522, 0x0522,
- 0x0524, 0x0524,
- 0x0526, 0x0526,
- 0x0528, 0x0528,
- 0x052a, 0x052a,
- 0x052c, 0x052c,
- 0x052e, 0x052e,
- 0x0531, 0x0556,
- 0x10a0, 0x10c5,
- 0x10c7, 0x10c7,
- 0x10cd, 0x10cd,
- 0x13a0, 0x13f5,
- 0x1c89, 0x1c89,
- 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,
- 0x1fb8, 0x1fbb,
- 0x1fc8, 0x1fcb,
- 0x1fd8, 0x1fdb,
- 0x1fe8, 0x1fec,
- 0x1ff8, 0x1ffb,
- 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,
- 0x2183, 0x2183,
- 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,
- 0xa7cb, 0xa7cc,
- 0xa7d0, 0xa7d0,
- 0xa7d6, 0xa7d6,
- 0xa7d8, 0xa7d8,
- 0xa7da, 0xa7da,
- 0xa7dc, 0xa7dc,
- 0xa7f5, 0xa7f5,
- 0xff21, 0xff3a,
- 0x10400, 0x10427,
- 0x104b0, 0x104d3,
- 0x10570, 0x1057a,
- 0x1057c, 0x1058a,
- 0x1058c, 0x10592,
- 0x10594, 0x10595,
- 0x10c80, 0x10cb2,
- 0x10d50, 0x10d65,
- 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,
-}; /* CR_Lu */
-
-/* 'M': Major Category */
-static const OnigCodePoint CR_M[] = {
- 321,
- 0x0300, 0x036f,
- 0x0483, 0x0489,
- 0x0591, 0x05bd,
- 0x05bf, 0x05bf,
- 0x05c1, 0x05c2,
- 0x05c4, 0x05c5,
- 0x05c7, 0x05c7,
- 0x0610, 0x061a,
- 0x064b, 0x065f,
- 0x0670, 0x0670,
- 0x06d6, 0x06dc,
- 0x06df, 0x06e4,
- 0x06e7, 0x06e8,
- 0x06ea, 0x06ed,
- 0x0711, 0x0711,
- 0x0730, 0x074a,
- 0x07a6, 0x07b0,
- 0x07eb, 0x07f3,
- 0x07fd, 0x07fd,
- 0x0816, 0x0819,
- 0x081b, 0x0823,
- 0x0825, 0x0827,
- 0x0829, 0x082d,
- 0x0859, 0x085b,
- 0x0897, 0x089f,
- 0x08ca, 0x08e1,
- 0x08e3, 0x0903,
- 0x093a, 0x093c,
- 0x093e, 0x094f,
- 0x0951, 0x0957,
- 0x0962, 0x0963,
- 0x0981, 0x0983,
- 0x09bc, 0x09bc,
- 0x09be, 0x09c4,
- 0x09c7, 0x09c8,
- 0x09cb, 0x09cd,
- 0x09d7, 0x09d7,
- 0x09e2, 0x09e3,
- 0x09fe, 0x09fe,
- 0x0a01, 0x0a03,
- 0x0a3c, 0x0a3c,
- 0x0a3e, 0x0a42,
- 0x0a47, 0x0a48,
- 0x0a4b, 0x0a4d,
- 0x0a51, 0x0a51,
- 0x0a70, 0x0a71,
- 0x0a75, 0x0a75,
- 0x0a81, 0x0a83,
- 0x0abc, 0x0abc,
- 0x0abe, 0x0ac5,
- 0x0ac7, 0x0ac9,
- 0x0acb, 0x0acd,
- 0x0ae2, 0x0ae3,
- 0x0afa, 0x0aff,
- 0x0b01, 0x0b03,
- 0x0b3c, 0x0b3c,
- 0x0b3e, 0x0b44,
- 0x0b47, 0x0b48,
- 0x0b4b, 0x0b4d,
- 0x0b55, 0x0b57,
- 0x0b62, 0x0b63,
- 0x0b82, 0x0b82,
- 0x0bbe, 0x0bc2,
- 0x0bc6, 0x0bc8,
- 0x0bca, 0x0bcd,
- 0x0bd7, 0x0bd7,
- 0x0c00, 0x0c04,
- 0x0c3c, 0x0c3c,
- 0x0c3e, 0x0c44,
- 0x0c46, 0x0c48,
- 0x0c4a, 0x0c4d,
- 0x0c55, 0x0c56,
- 0x0c62, 0x0c63,
- 0x0c81, 0x0c83,
- 0x0cbc, 0x0cbc,
- 0x0cbe, 0x0cc4,
- 0x0cc6, 0x0cc8,
- 0x0cca, 0x0ccd,
- 0x0cd5, 0x0cd6,
- 0x0ce2, 0x0ce3,
- 0x0cf3, 0x0cf3,
- 0x0d00, 0x0d03,
- 0x0d3b, 0x0d3c,
- 0x0d3e, 0x0d44,
- 0x0d46, 0x0d48,
- 0x0d4a, 0x0d4d,
- 0x0d57, 0x0d57,
- 0x0d62, 0x0d63,
- 0x0d81, 0x0d83,
- 0x0dca, 0x0dca,
- 0x0dcf, 0x0dd4,
- 0x0dd6, 0x0dd6,
- 0x0dd8, 0x0ddf,
- 0x0df2, 0x0df3,
- 0x0e31, 0x0e31,
- 0x0e34, 0x0e3a,
- 0x0e47, 0x0e4e,
- 0x0eb1, 0x0eb1,
- 0x0eb4, 0x0ebc,
- 0x0ec8, 0x0ece,
- 0x0f18, 0x0f19,
- 0x0f35, 0x0f35,
- 0x0f37, 0x0f37,
- 0x0f39, 0x0f39,
- 0x0f3e, 0x0f3f,
- 0x0f71, 0x0f84,
- 0x0f86, 0x0f87,
- 0x0f8d, 0x0f97,
- 0x0f99, 0x0fbc,
- 0x0fc6, 0x0fc6,
- 0x102b, 0x103e,
- 0x1056, 0x1059,
- 0x105e, 0x1060,
- 0x1062, 0x1064,
- 0x1067, 0x106d,
- 0x1071, 0x1074,
- 0x1082, 0x108d,
- 0x108f, 0x108f,
- 0x109a, 0x109d,
- 0x135d, 0x135f,
- 0x1712, 0x1715,
- 0x1732, 0x1734,
- 0x1752, 0x1753,
- 0x1772, 0x1773,
- 0x17b4, 0x17d3,
- 0x17dd, 0x17dd,
- 0x180b, 0x180d,
- 0x180f, 0x180f,
- 0x1885, 0x1886,
- 0x18a9, 0x18a9,
- 0x1920, 0x192b,
- 0x1930, 0x193b,
- 0x1a17, 0x1a1b,
- 0x1a55, 0x1a5e,
- 0x1a60, 0x1a7c,
- 0x1a7f, 0x1a7f,
- 0x1ab0, 0x1ace,
- 0x1b00, 0x1b04,
- 0x1b34, 0x1b44,
- 0x1b6b, 0x1b73,
- 0x1b80, 0x1b82,
- 0x1ba1, 0x1bad,
- 0x1be6, 0x1bf3,
- 0x1c24, 0x1c37,
- 0x1cd0, 0x1cd2,
- 0x1cd4, 0x1ce8,
- 0x1ced, 0x1ced,
- 0x1cf4, 0x1cf4,
- 0x1cf7, 0x1cf9,
- 0x1dc0, 0x1dff,
- 0x20d0, 0x20f0,
- 0x2cef, 0x2cf1,
- 0x2d7f, 0x2d7f,
- 0x2de0, 0x2dff,
- 0x302a, 0x302f,
- 0x3099, 0x309a,
- 0xa66f, 0xa672,
- 0xa674, 0xa67d,
- 0xa69e, 0xa69f,
- 0xa6f0, 0xa6f1,
- 0xa802, 0xa802,
- 0xa806, 0xa806,
- 0xa80b, 0xa80b,
- 0xa823, 0xa827,
- 0xa82c, 0xa82c,
- 0xa880, 0xa881,
- 0xa8b4, 0xa8c5,
- 0xa8e0, 0xa8f1,
- 0xa8ff, 0xa8ff,
- 0xa926, 0xa92d,
- 0xa947, 0xa953,
- 0xa980, 0xa983,
- 0xa9b3, 0xa9c0,
- 0xa9e5, 0xa9e5,
- 0xaa29, 0xaa36,
- 0xaa43, 0xaa43,
- 0xaa4c, 0xaa4d,
- 0xaa7b, 0xaa7d,
- 0xaab0, 0xaab0,
- 0xaab2, 0xaab4,
- 0xaab7, 0xaab8,
- 0xaabe, 0xaabf,
- 0xaac1, 0xaac1,
- 0xaaeb, 0xaaef,
- 0xaaf5, 0xaaf6,
- 0xabe3, 0xabea,
- 0xabec, 0xabed,
- 0xfb1e, 0xfb1e,
- 0xfe00, 0xfe0f,
- 0xfe20, 0xfe2f,
- 0x101fd, 0x101fd,
- 0x102e0, 0x102e0,
- 0x10376, 0x1037a,
- 0x10a01, 0x10a03,
- 0x10a05, 0x10a06,
- 0x10a0c, 0x10a0f,
- 0x10a38, 0x10a3a,
- 0x10a3f, 0x10a3f,
- 0x10ae5, 0x10ae6,
- 0x10d24, 0x10d27,
- 0x10d69, 0x10d6d,
- 0x10eab, 0x10eac,
- 0x10efc, 0x10eff,
- 0x10f46, 0x10f50,
- 0x10f82, 0x10f85,
- 0x11000, 0x11002,
- 0x11038, 0x11046,
- 0x11070, 0x11070,
- 0x11073, 0x11074,
- 0x1107f, 0x11082,
- 0x110b0, 0x110ba,
- 0x110c2, 0x110c2,
- 0x11100, 0x11102,
- 0x11127, 0x11134,
- 0x11145, 0x11146,
- 0x11173, 0x11173,
- 0x11180, 0x11182,
- 0x111b3, 0x111c0,
- 0x111c9, 0x111cc,
- 0x111ce, 0x111cf,
- 0x1122c, 0x11237,
- 0x1123e, 0x1123e,
- 0x11241, 0x11241,
- 0x112df, 0x112ea,
- 0x11300, 0x11303,
- 0x1133b, 0x1133c,
- 0x1133e, 0x11344,
- 0x11347, 0x11348,
- 0x1134b, 0x1134d,
- 0x11357, 0x11357,
- 0x11362, 0x11363,
- 0x11366, 0x1136c,
- 0x11370, 0x11374,
- 0x113b8, 0x113c0,
- 0x113c2, 0x113c2,
- 0x113c5, 0x113c5,
- 0x113c7, 0x113ca,
- 0x113cc, 0x113d0,
- 0x113d2, 0x113d2,
- 0x113e1, 0x113e2,
- 0x11435, 0x11446,
- 0x1145e, 0x1145e,
- 0x114b0, 0x114c3,
- 0x115af, 0x115b5,
- 0x115b8, 0x115c0,
- 0x115dc, 0x115dd,
- 0x11630, 0x11640,
- 0x116ab, 0x116b7,
- 0x1171d, 0x1172b,
- 0x1182c, 0x1183a,
- 0x11930, 0x11935,
- 0x11937, 0x11938,
- 0x1193b, 0x1193e,
- 0x11940, 0x11940,
- 0x11942, 0x11943,
- 0x119d1, 0x119d7,
- 0x119da, 0x119e0,
- 0x119e4, 0x119e4,
- 0x11a01, 0x11a0a,
- 0x11a33, 0x11a39,
- 0x11a3b, 0x11a3e,
- 0x11a47, 0x11a47,
- 0x11a51, 0x11a5b,
- 0x11a8a, 0x11a99,
- 0x11c2f, 0x11c36,
- 0x11c38, 0x11c3f,
- 0x11c92, 0x11ca7,
- 0x11ca9, 0x11cb6,
- 0x11d31, 0x11d36,
- 0x11d3a, 0x11d3a,
- 0x11d3c, 0x11d3d,
- 0x11d3f, 0x11d45,
- 0x11d47, 0x11d47,
- 0x11d8a, 0x11d8e,
- 0x11d90, 0x11d91,
- 0x11d93, 0x11d97,
- 0x11ef3, 0x11ef6,
- 0x11f00, 0x11f01,
- 0x11f03, 0x11f03,
- 0x11f34, 0x11f3a,
- 0x11f3e, 0x11f42,
- 0x11f5a, 0x11f5a,
- 0x13440, 0x13440,
- 0x13447, 0x13455,
- 0x1611e, 0x1612f,
- 0x16af0, 0x16af4,
- 0x16b30, 0x16b36,
- 0x16f4f, 0x16f4f,
- 0x16f51, 0x16f87,
- 0x16f8f, 0x16f92,
- 0x16fe4, 0x16fe4,
- 0x16ff0, 0x16ff1,
- 0x1bc9d, 0x1bc9e,
- 0x1cf00, 0x1cf2d,
- 0x1cf30, 0x1cf46,
- 0x1d165, 0x1d169,
- 0x1d16d, 0x1d172,
- 0x1d17b, 0x1d182,
- 0x1d185, 0x1d18b,
- 0x1d1aa, 0x1d1ad,
- 0x1d242, 0x1d244,
- 0x1da00, 0x1da36,
- 0x1da3b, 0x1da6c,
- 0x1da75, 0x1da75,
- 0x1da84, 0x1da84,
- 0x1da9b, 0x1da9f,
- 0x1daa1, 0x1daaf,
- 0x1e000, 0x1e006,
- 0x1e008, 0x1e018,
- 0x1e01b, 0x1e021,
- 0x1e023, 0x1e024,
- 0x1e026, 0x1e02a,
- 0x1e08f, 0x1e08f,
- 0x1e130, 0x1e136,
- 0x1e2ae, 0x1e2ae,
- 0x1e2ec, 0x1e2ef,
- 0x1e4ec, 0x1e4ef,
- 0x1e5ee, 0x1e5ef,
- 0x1e8d0, 0x1e8d6,
- 0x1e944, 0x1e94a,
- 0xe0100, 0xe01ef,
-}; /* CR_M */
-
-/* 'Mc': General Category */
-static const OnigCodePoint CR_Mc[] = {
- 190,
- 0x0903, 0x0903,
- 0x093b, 0x093b,
- 0x093e, 0x0940,
- 0x0949, 0x094c,
- 0x094e, 0x094f,
- 0x0982, 0x0983,
- 0x09be, 0x09c0,
- 0x09c7, 0x09c8,
- 0x09cb, 0x09cc,
- 0x09d7, 0x09d7,
- 0x0a03, 0x0a03,
- 0x0a3e, 0x0a40,
- 0x0a83, 0x0a83,
- 0x0abe, 0x0ac0,
- 0x0ac9, 0x0ac9,
- 0x0acb, 0x0acc,
- 0x0b02, 0x0b03,
- 0x0b3e, 0x0b3e,
- 0x0b40, 0x0b40,
- 0x0b47, 0x0b48,
- 0x0b4b, 0x0b4c,
- 0x0b57, 0x0b57,
- 0x0bbe, 0x0bbf,
- 0x0bc1, 0x0bc2,
- 0x0bc6, 0x0bc8,
- 0x0bca, 0x0bcc,
- 0x0bd7, 0x0bd7,
- 0x0c01, 0x0c03,
- 0x0c41, 0x0c44,
- 0x0c82, 0x0c83,
- 0x0cbe, 0x0cbe,
- 0x0cc0, 0x0cc4,
- 0x0cc7, 0x0cc8,
- 0x0cca, 0x0ccb,
- 0x0cd5, 0x0cd6,
- 0x0cf3, 0x0cf3,
- 0x0d02, 0x0d03,
- 0x0d3e, 0x0d40,
- 0x0d46, 0x0d48,
- 0x0d4a, 0x0d4c,
- 0x0d57, 0x0d57,
- 0x0d82, 0x0d83,
- 0x0dcf, 0x0dd1,
- 0x0dd8, 0x0ddf,
- 0x0df2, 0x0df3,
- 0x0f3e, 0x0f3f,
- 0x0f7f, 0x0f7f,
- 0x102b, 0x102c,
- 0x1031, 0x1031,
- 0x1038, 0x1038,
- 0x103b, 0x103c,
- 0x1056, 0x1057,
- 0x1062, 0x1064,
- 0x1067, 0x106d,
- 0x1083, 0x1084,
- 0x1087, 0x108c,
- 0x108f, 0x108f,
- 0x109a, 0x109c,
- 0x1715, 0x1715,
- 0x1734, 0x1734,
- 0x17b6, 0x17b6,
- 0x17be, 0x17c5,
- 0x17c7, 0x17c8,
- 0x1923, 0x1926,
- 0x1929, 0x192b,
- 0x1930, 0x1931,
- 0x1933, 0x1938,
- 0x1a19, 0x1a1a,
- 0x1a55, 0x1a55,
- 0x1a57, 0x1a57,
- 0x1a61, 0x1a61,
- 0x1a63, 0x1a64,
- 0x1a6d, 0x1a72,
- 0x1b04, 0x1b04,
- 0x1b35, 0x1b35,
- 0x1b3b, 0x1b3b,
- 0x1b3d, 0x1b41,
- 0x1b43, 0x1b44,
- 0x1b82, 0x1b82,
- 0x1ba1, 0x1ba1,
- 0x1ba6, 0x1ba7,
- 0x1baa, 0x1baa,
- 0x1be7, 0x1be7,
- 0x1bea, 0x1bec,
- 0x1bee, 0x1bee,
- 0x1bf2, 0x1bf3,
- 0x1c24, 0x1c2b,
- 0x1c34, 0x1c35,
- 0x1ce1, 0x1ce1,
- 0x1cf7, 0x1cf7,
- 0x302e, 0x302f,
- 0xa823, 0xa824,
- 0xa827, 0xa827,
- 0xa880, 0xa881,
- 0xa8b4, 0xa8c3,
- 0xa952, 0xa953,
- 0xa983, 0xa983,
- 0xa9b4, 0xa9b5,
- 0xa9ba, 0xa9bb,
- 0xa9be, 0xa9c0,
- 0xaa2f, 0xaa30,
- 0xaa33, 0xaa34,
- 0xaa4d, 0xaa4d,
- 0xaa7b, 0xaa7b,
- 0xaa7d, 0xaa7d,
- 0xaaeb, 0xaaeb,
- 0xaaee, 0xaaef,
- 0xaaf5, 0xaaf5,
- 0xabe3, 0xabe4,
- 0xabe6, 0xabe7,
- 0xabe9, 0xabea,
- 0xabec, 0xabec,
- 0x11000, 0x11000,
- 0x11002, 0x11002,
- 0x11082, 0x11082,
- 0x110b0, 0x110b2,
- 0x110b7, 0x110b8,
- 0x1112c, 0x1112c,
- 0x11145, 0x11146,
- 0x11182, 0x11182,
- 0x111b3, 0x111b5,
- 0x111bf, 0x111c0,
- 0x111ce, 0x111ce,
- 0x1122c, 0x1122e,
- 0x11232, 0x11233,
- 0x11235, 0x11235,
- 0x112e0, 0x112e2,
- 0x11302, 0x11303,
- 0x1133e, 0x1133f,
- 0x11341, 0x11344,
- 0x11347, 0x11348,
- 0x1134b, 0x1134d,
- 0x11357, 0x11357,
- 0x11362, 0x11363,
- 0x113b8, 0x113ba,
- 0x113c2, 0x113c2,
- 0x113c5, 0x113c5,
- 0x113c7, 0x113ca,
- 0x113cc, 0x113cd,
- 0x113cf, 0x113cf,
- 0x11435, 0x11437,
- 0x11440, 0x11441,
- 0x11445, 0x11445,
- 0x114b0, 0x114b2,
- 0x114b9, 0x114b9,
- 0x114bb, 0x114be,
- 0x114c1, 0x114c1,
- 0x115af, 0x115b1,
- 0x115b8, 0x115bb,
- 0x115be, 0x115be,
- 0x11630, 0x11632,
- 0x1163b, 0x1163c,
- 0x1163e, 0x1163e,
- 0x116ac, 0x116ac,
- 0x116ae, 0x116af,
- 0x116b6, 0x116b6,
- 0x1171e, 0x1171e,
- 0x11720, 0x11721,
- 0x11726, 0x11726,
- 0x1182c, 0x1182e,
- 0x11838, 0x11838,
- 0x11930, 0x11935,
- 0x11937, 0x11938,
- 0x1193d, 0x1193d,
- 0x11940, 0x11940,
- 0x11942, 0x11942,
- 0x119d1, 0x119d3,
- 0x119dc, 0x119df,
- 0x119e4, 0x119e4,
- 0x11a39, 0x11a39,
- 0x11a57, 0x11a58,
- 0x11a97, 0x11a97,
- 0x11c2f, 0x11c2f,
- 0x11c3e, 0x11c3e,
- 0x11ca9, 0x11ca9,
- 0x11cb1, 0x11cb1,
- 0x11cb4, 0x11cb4,
- 0x11d8a, 0x11d8e,
- 0x11d93, 0x11d94,
- 0x11d96, 0x11d96,
- 0x11ef5, 0x11ef6,
- 0x11f03, 0x11f03,
- 0x11f34, 0x11f35,
- 0x11f3e, 0x11f3f,
- 0x11f41, 0x11f41,
- 0x1612a, 0x1612c,
- 0x16f51, 0x16f87,
- 0x16ff0, 0x16ff1,
- 0x1d165, 0x1d166,
- 0x1d16d, 0x1d172,
-}; /* CR_Mc */
-
-/* 'Me': General Category */
-static const OnigCodePoint CR_Me[] = {
- 5,
- 0x0488, 0x0489,
- 0x1abe, 0x1abe,
- 0x20dd, 0x20e0,
- 0x20e2, 0x20e4,
- 0xa670, 0xa672,
-}; /* CR_Me */
-
-/* 'Mn': General Category */
-static const OnigCodePoint CR_Mn[] = {
- 357,
- 0x0300, 0x036f,
- 0x0483, 0x0487,
- 0x0591, 0x05bd,
- 0x05bf, 0x05bf,
- 0x05c1, 0x05c2,
- 0x05c4, 0x05c5,
- 0x05c7, 0x05c7,
- 0x0610, 0x061a,
- 0x064b, 0x065f,
- 0x0670, 0x0670,
- 0x06d6, 0x06dc,
- 0x06df, 0x06e4,
- 0x06e7, 0x06e8,
- 0x06ea, 0x06ed,
- 0x0711, 0x0711,
- 0x0730, 0x074a,
- 0x07a6, 0x07b0,
- 0x07eb, 0x07f3,
- 0x07fd, 0x07fd,
- 0x0816, 0x0819,
- 0x081b, 0x0823,
- 0x0825, 0x0827,
- 0x0829, 0x082d,
- 0x0859, 0x085b,
- 0x0897, 0x089f,
- 0x08ca, 0x08e1,
- 0x08e3, 0x0902,
- 0x093a, 0x093a,
- 0x093c, 0x093c,
- 0x0941, 0x0948,
- 0x094d, 0x094d,
- 0x0951, 0x0957,
- 0x0962, 0x0963,
- 0x0981, 0x0981,
- 0x09bc, 0x09bc,
- 0x09c1, 0x09c4,
- 0x09cd, 0x09cd,
- 0x09e2, 0x09e3,
- 0x09fe, 0x09fe,
- 0x0a01, 0x0a02,
- 0x0a3c, 0x0a3c,
- 0x0a41, 0x0a42,
- 0x0a47, 0x0a48,
- 0x0a4b, 0x0a4d,
- 0x0a51, 0x0a51,
- 0x0a70, 0x0a71,
- 0x0a75, 0x0a75,
- 0x0a81, 0x0a82,
- 0x0abc, 0x0abc,
- 0x0ac1, 0x0ac5,
- 0x0ac7, 0x0ac8,
- 0x0acd, 0x0acd,
- 0x0ae2, 0x0ae3,
- 0x0afa, 0x0aff,
- 0x0b01, 0x0b01,
- 0x0b3c, 0x0b3c,
- 0x0b3f, 0x0b3f,
- 0x0b41, 0x0b44,
- 0x0b4d, 0x0b4d,
- 0x0b55, 0x0b56,
- 0x0b62, 0x0b63,
- 0x0b82, 0x0b82,
- 0x0bc0, 0x0bc0,
- 0x0bcd, 0x0bcd,
- 0x0c00, 0x0c00,
- 0x0c04, 0x0c04,
- 0x0c3c, 0x0c3c,
- 0x0c3e, 0x0c40,
- 0x0c46, 0x0c48,
- 0x0c4a, 0x0c4d,
- 0x0c55, 0x0c56,
- 0x0c62, 0x0c63,
- 0x0c81, 0x0c81,
- 0x0cbc, 0x0cbc,
- 0x0cbf, 0x0cbf,
- 0x0cc6, 0x0cc6,
- 0x0ccc, 0x0ccd,
- 0x0ce2, 0x0ce3,
- 0x0d00, 0x0d01,
- 0x0d3b, 0x0d3c,
- 0x0d41, 0x0d44,
- 0x0d4d, 0x0d4d,
- 0x0d62, 0x0d63,
- 0x0d81, 0x0d81,
- 0x0dca, 0x0dca,
- 0x0dd2, 0x0dd4,
- 0x0dd6, 0x0dd6,
- 0x0e31, 0x0e31,
- 0x0e34, 0x0e3a,
- 0x0e47, 0x0e4e,
- 0x0eb1, 0x0eb1,
- 0x0eb4, 0x0ebc,
- 0x0ec8, 0x0ece,
- 0x0f18, 0x0f19,
- 0x0f35, 0x0f35,
- 0x0f37, 0x0f37,
- 0x0f39, 0x0f39,
- 0x0f71, 0x0f7e,
- 0x0f80, 0x0f84,
- 0x0f86, 0x0f87,
- 0x0f8d, 0x0f97,
- 0x0f99, 0x0fbc,
- 0x0fc6, 0x0fc6,
- 0x102d, 0x1030,
- 0x1032, 0x1037,
- 0x1039, 0x103a,
- 0x103d, 0x103e,
- 0x1058, 0x1059,
- 0x105e, 0x1060,
- 0x1071, 0x1074,
- 0x1082, 0x1082,
- 0x1085, 0x1086,
- 0x108d, 0x108d,
- 0x109d, 0x109d,
- 0x135d, 0x135f,
- 0x1712, 0x1714,
- 0x1732, 0x1733,
- 0x1752, 0x1753,
- 0x1772, 0x1773,
- 0x17b4, 0x17b5,
- 0x17b7, 0x17bd,
- 0x17c6, 0x17c6,
- 0x17c9, 0x17d3,
- 0x17dd, 0x17dd,
- 0x180b, 0x180d,
- 0x180f, 0x180f,
- 0x1885, 0x1886,
- 0x18a9, 0x18a9,
- 0x1920, 0x1922,
- 0x1927, 0x1928,
- 0x1932, 0x1932,
- 0x1939, 0x193b,
- 0x1a17, 0x1a18,
- 0x1a1b, 0x1a1b,
- 0x1a56, 0x1a56,
- 0x1a58, 0x1a5e,
- 0x1a60, 0x1a60,
- 0x1a62, 0x1a62,
- 0x1a65, 0x1a6c,
- 0x1a73, 0x1a7c,
- 0x1a7f, 0x1a7f,
- 0x1ab0, 0x1abd,
- 0x1abf, 0x1ace,
- 0x1b00, 0x1b03,
- 0x1b34, 0x1b34,
- 0x1b36, 0x1b3a,
- 0x1b3c, 0x1b3c,
- 0x1b42, 0x1b42,
- 0x1b6b, 0x1b73,
- 0x1b80, 0x1b81,
- 0x1ba2, 0x1ba5,
- 0x1ba8, 0x1ba9,
- 0x1bab, 0x1bad,
- 0x1be6, 0x1be6,
- 0x1be8, 0x1be9,
- 0x1bed, 0x1bed,
- 0x1bef, 0x1bf1,
- 0x1c2c, 0x1c33,
- 0x1c36, 0x1c37,
- 0x1cd0, 0x1cd2,
- 0x1cd4, 0x1ce0,
- 0x1ce2, 0x1ce8,
- 0x1ced, 0x1ced,
- 0x1cf4, 0x1cf4,
- 0x1cf8, 0x1cf9,
- 0x1dc0, 0x1dff,
- 0x20d0, 0x20dc,
- 0x20e1, 0x20e1,
- 0x20e5, 0x20f0,
- 0x2cef, 0x2cf1,
- 0x2d7f, 0x2d7f,
- 0x2de0, 0x2dff,
- 0x302a, 0x302d,
- 0x3099, 0x309a,
- 0xa66f, 0xa66f,
- 0xa674, 0xa67d,
- 0xa69e, 0xa69f,
- 0xa6f0, 0xa6f1,
- 0xa802, 0xa802,
- 0xa806, 0xa806,
- 0xa80b, 0xa80b,
- 0xa825, 0xa826,
- 0xa82c, 0xa82c,
- 0xa8c4, 0xa8c5,
- 0xa8e0, 0xa8f1,
- 0xa8ff, 0xa8ff,
- 0xa926, 0xa92d,
- 0xa947, 0xa951,
- 0xa980, 0xa982,
- 0xa9b3, 0xa9b3,
- 0xa9b6, 0xa9b9,
- 0xa9bc, 0xa9bd,
- 0xa9e5, 0xa9e5,
- 0xaa29, 0xaa2e,
- 0xaa31, 0xaa32,
- 0xaa35, 0xaa36,
- 0xaa43, 0xaa43,
- 0xaa4c, 0xaa4c,
- 0xaa7c, 0xaa7c,
- 0xaab0, 0xaab0,
- 0xaab2, 0xaab4,
- 0xaab7, 0xaab8,
- 0xaabe, 0xaabf,
- 0xaac1, 0xaac1,
- 0xaaec, 0xaaed,
- 0xaaf6, 0xaaf6,
- 0xabe5, 0xabe5,
- 0xabe8, 0xabe8,
- 0xabed, 0xabed,
- 0xfb1e, 0xfb1e,
- 0xfe00, 0xfe0f,
- 0xfe20, 0xfe2f,
- 0x101fd, 0x101fd,
- 0x102e0, 0x102e0,
- 0x10376, 0x1037a,
- 0x10a01, 0x10a03,
- 0x10a05, 0x10a06,
- 0x10a0c, 0x10a0f,
- 0x10a38, 0x10a3a,
- 0x10a3f, 0x10a3f,
- 0x10ae5, 0x10ae6,
- 0x10d24, 0x10d27,
- 0x10d69, 0x10d6d,
- 0x10eab, 0x10eac,
- 0x10efc, 0x10eff,
- 0x10f46, 0x10f50,
- 0x10f82, 0x10f85,
- 0x11001, 0x11001,
- 0x11038, 0x11046,
- 0x11070, 0x11070,
- 0x11073, 0x11074,
- 0x1107f, 0x11081,
- 0x110b3, 0x110b6,
- 0x110b9, 0x110ba,
- 0x110c2, 0x110c2,
- 0x11100, 0x11102,
- 0x11127, 0x1112b,
- 0x1112d, 0x11134,
- 0x11173, 0x11173,
- 0x11180, 0x11181,
- 0x111b6, 0x111be,
- 0x111c9, 0x111cc,
- 0x111cf, 0x111cf,
- 0x1122f, 0x11231,
- 0x11234, 0x11234,
- 0x11236, 0x11237,
- 0x1123e, 0x1123e,
- 0x11241, 0x11241,
- 0x112df, 0x112df,
- 0x112e3, 0x112ea,
- 0x11300, 0x11301,
- 0x1133b, 0x1133c,
- 0x11340, 0x11340,
- 0x11366, 0x1136c,
- 0x11370, 0x11374,
- 0x113bb, 0x113c0,
- 0x113ce, 0x113ce,
- 0x113d0, 0x113d0,
- 0x113d2, 0x113d2,
- 0x113e1, 0x113e2,
- 0x11438, 0x1143f,
- 0x11442, 0x11444,
- 0x11446, 0x11446,
- 0x1145e, 0x1145e,
- 0x114b3, 0x114b8,
- 0x114ba, 0x114ba,
- 0x114bf, 0x114c0,
- 0x114c2, 0x114c3,
- 0x115b2, 0x115b5,
- 0x115bc, 0x115bd,
- 0x115bf, 0x115c0,
- 0x115dc, 0x115dd,
- 0x11633, 0x1163a,
- 0x1163d, 0x1163d,
- 0x1163f, 0x11640,
- 0x116ab, 0x116ab,
- 0x116ad, 0x116ad,
- 0x116b0, 0x116b5,
- 0x116b7, 0x116b7,
- 0x1171d, 0x1171d,
- 0x1171f, 0x1171f,
- 0x11722, 0x11725,
- 0x11727, 0x1172b,
- 0x1182f, 0x11837,
- 0x11839, 0x1183a,
- 0x1193b, 0x1193c,
- 0x1193e, 0x1193e,
- 0x11943, 0x11943,
- 0x119d4, 0x119d7,
- 0x119da, 0x119db,
- 0x119e0, 0x119e0,
- 0x11a01, 0x11a0a,
- 0x11a33, 0x11a38,
- 0x11a3b, 0x11a3e,
- 0x11a47, 0x11a47,
- 0x11a51, 0x11a56,
- 0x11a59, 0x11a5b,
- 0x11a8a, 0x11a96,
- 0x11a98, 0x11a99,
- 0x11c30, 0x11c36,
- 0x11c38, 0x11c3d,
- 0x11c3f, 0x11c3f,
- 0x11c92, 0x11ca7,
- 0x11caa, 0x11cb0,
- 0x11cb2, 0x11cb3,
- 0x11cb5, 0x11cb6,
- 0x11d31, 0x11d36,
- 0x11d3a, 0x11d3a,
- 0x11d3c, 0x11d3d,
- 0x11d3f, 0x11d45,
- 0x11d47, 0x11d47,
- 0x11d90, 0x11d91,
- 0x11d95, 0x11d95,
- 0x11d97, 0x11d97,
- 0x11ef3, 0x11ef4,
- 0x11f00, 0x11f01,
- 0x11f36, 0x11f3a,
- 0x11f40, 0x11f40,
- 0x11f42, 0x11f42,
- 0x11f5a, 0x11f5a,
- 0x13440, 0x13440,
- 0x13447, 0x13455,
- 0x1611e, 0x16129,
- 0x1612d, 0x1612f,
- 0x16af0, 0x16af4,
- 0x16b30, 0x16b36,
- 0x16f4f, 0x16f4f,
- 0x16f8f, 0x16f92,
- 0x16fe4, 0x16fe4,
- 0x1bc9d, 0x1bc9e,
- 0x1cf00, 0x1cf2d,
- 0x1cf30, 0x1cf46,
- 0x1d167, 0x1d169,
- 0x1d17b, 0x1d182,
- 0x1d185, 0x1d18b,
- 0x1d1aa, 0x1d1ad,
- 0x1d242, 0x1d244,
- 0x1da00, 0x1da36,
- 0x1da3b, 0x1da6c,
- 0x1da75, 0x1da75,
- 0x1da84, 0x1da84,
- 0x1da9b, 0x1da9f,
- 0x1daa1, 0x1daaf,
- 0x1e000, 0x1e006,
- 0x1e008, 0x1e018,
- 0x1e01b, 0x1e021,
- 0x1e023, 0x1e024,
- 0x1e026, 0x1e02a,
- 0x1e08f, 0x1e08f,
- 0x1e130, 0x1e136,
- 0x1e2ae, 0x1e2ae,
- 0x1e2ec, 0x1e2ef,
- 0x1e4ec, 0x1e4ef,
- 0x1e5ee, 0x1e5ef,
- 0x1e8d0, 0x1e8d6,
- 0x1e944, 0x1e94a,
- 0xe0100, 0xe01ef,
-}; /* CR_Mn */
-
-/* 'N': Major Category */
-static const OnigCodePoint CR_N[] = {
- 144,
- 0x0030, 0x0039,
- 0x00b2, 0x00b3,
- 0x00b9, 0x00b9,
- 0x00bc, 0x00be,
- 0x0660, 0x0669,
- 0x06f0, 0x06f9,
- 0x07c0, 0x07c9,
- 0x0966, 0x096f,
- 0x09e6, 0x09ef,
- 0x09f4, 0x09f9,
- 0x0a66, 0x0a6f,
- 0x0ae6, 0x0aef,
- 0x0b66, 0x0b6f,
- 0x0b72, 0x0b77,
- 0x0be6, 0x0bf2,
- 0x0c66, 0x0c6f,
- 0x0c78, 0x0c7e,
- 0x0ce6, 0x0cef,
- 0x0d58, 0x0d5e,
- 0x0d66, 0x0d78,
- 0x0de6, 0x0def,
- 0x0e50, 0x0e59,
- 0x0ed0, 0x0ed9,
- 0x0f20, 0x0f33,
- 0x1040, 0x1049,
- 0x1090, 0x1099,
- 0x1369, 0x137c,
- 0x16ee, 0x16f0,
- 0x17e0, 0x17e9,
- 0x17f0, 0x17f9,
- 0x1810, 0x1819,
- 0x1946, 0x194f,
- 0x19d0, 0x19da,
- 0x1a80, 0x1a89,
- 0x1a90, 0x1a99,
- 0x1b50, 0x1b59,
- 0x1bb0, 0x1bb9,
- 0x1c40, 0x1c49,
- 0x1c50, 0x1c59,
- 0x2070, 0x2070,
- 0x2074, 0x2079,
- 0x2080, 0x2089,
- 0x2150, 0x2182,
- 0x2185, 0x2189,
- 0x2460, 0x249b,
- 0x24ea, 0x24ff,
- 0x2776, 0x2793,
- 0x2cfd, 0x2cfd,
- 0x3007, 0x3007,
- 0x3021, 0x3029,
- 0x3038, 0x303a,
- 0x3192, 0x3195,
- 0x3220, 0x3229,
- 0x3248, 0x324f,
- 0x3251, 0x325f,
- 0x3280, 0x3289,
- 0x32b1, 0x32bf,
- 0xa620, 0xa629,
- 0xa6e6, 0xa6ef,
- 0xa830, 0xa835,
- 0xa8d0, 0xa8d9,
- 0xa900, 0xa909,
- 0xa9d0, 0xa9d9,
- 0xa9f0, 0xa9f9,
- 0xaa50, 0xaa59,
- 0xabf0, 0xabf9,
- 0xff10, 0xff19,
- 0x10107, 0x10133,
- 0x10140, 0x10178,
- 0x1018a, 0x1018b,
- 0x102e1, 0x102fb,
- 0x10320, 0x10323,
- 0x10341, 0x10341,
- 0x1034a, 0x1034a,
- 0x103d1, 0x103d5,
- 0x104a0, 0x104a9,
- 0x10858, 0x1085f,
- 0x10879, 0x1087f,
- 0x108a7, 0x108af,
- 0x108fb, 0x108ff,
- 0x10916, 0x1091b,
- 0x109bc, 0x109bd,
- 0x109c0, 0x109cf,
- 0x109d2, 0x109ff,
- 0x10a40, 0x10a48,
- 0x10a7d, 0x10a7e,
- 0x10a9d, 0x10a9f,
- 0x10aeb, 0x10aef,
- 0x10b58, 0x10b5f,
- 0x10b78, 0x10b7f,
- 0x10ba9, 0x10baf,
- 0x10cfa, 0x10cff,
- 0x10d30, 0x10d39,
- 0x10d40, 0x10d49,
- 0x10e60, 0x10e7e,
- 0x10f1d, 0x10f26,
- 0x10f51, 0x10f54,
- 0x10fc5, 0x10fcb,
- 0x11052, 0x1106f,
- 0x110f0, 0x110f9,
- 0x11136, 0x1113f,
- 0x111d0, 0x111d9,
- 0x111e1, 0x111f4,
- 0x112f0, 0x112f9,
- 0x11450, 0x11459,
- 0x114d0, 0x114d9,
- 0x11650, 0x11659,
- 0x116c0, 0x116c9,
- 0x116d0, 0x116e3,
- 0x11730, 0x1173b,
- 0x118e0, 0x118f2,
- 0x11950, 0x11959,
- 0x11bf0, 0x11bf9,
- 0x11c50, 0x11c6c,
- 0x11d50, 0x11d59,
- 0x11da0, 0x11da9,
- 0x11f50, 0x11f59,
- 0x11fc0, 0x11fd4,
- 0x12400, 0x1246e,
- 0x16130, 0x16139,
- 0x16a60, 0x16a69,
- 0x16ac0, 0x16ac9,
- 0x16b50, 0x16b59,
- 0x16b5b, 0x16b61,
- 0x16d70, 0x16d79,
- 0x16e80, 0x16e96,
- 0x1ccf0, 0x1ccf9,
- 0x1d2c0, 0x1d2d3,
- 0x1d2e0, 0x1d2f3,
- 0x1d360, 0x1d378,
- 0x1d7ce, 0x1d7ff,
- 0x1e140, 0x1e149,
- 0x1e2f0, 0x1e2f9,
- 0x1e4f0, 0x1e4f9,
- 0x1e5f1, 0x1e5fa,
- 0x1e8c7, 0x1e8cf,
- 0x1e950, 0x1e959,
- 0x1ec71, 0x1ecab,
- 0x1ecad, 0x1ecaf,
- 0x1ecb1, 0x1ecb4,
- 0x1ed01, 0x1ed2d,
- 0x1ed2f, 0x1ed3d,
- 0x1f100, 0x1f10c,
- 0x1fbf0, 0x1fbf9,
-}; /* CR_N */
-
-/* 'Nd': General Category */
-#define CR_Nd CR_Digit
-
-/* 'Nl': General Category */
-static const OnigCodePoint CR_Nl[] = {
- 12,
- 0x16ee, 0x16f0,
- 0x2160, 0x2182,
- 0x2185, 0x2188,
- 0x3007, 0x3007,
- 0x3021, 0x3029,
- 0x3038, 0x303a,
- 0xa6e6, 0xa6ef,
- 0x10140, 0x10174,
- 0x10341, 0x10341,
- 0x1034a, 0x1034a,
- 0x103d1, 0x103d5,
- 0x12400, 0x1246e,
-}; /* CR_Nl */
-
-/* 'No': General Category */
-static const OnigCodePoint CR_No[] = {
- 72,
- 0x00b2, 0x00b3,
- 0x00b9, 0x00b9,
- 0x00bc, 0x00be,
- 0x09f4, 0x09f9,
- 0x0b72, 0x0b77,
- 0x0bf0, 0x0bf2,
- 0x0c78, 0x0c7e,
- 0x0d58, 0x0d5e,
- 0x0d70, 0x0d78,
- 0x0f2a, 0x0f33,
- 0x1369, 0x137c,
- 0x17f0, 0x17f9,
- 0x19da, 0x19da,
- 0x2070, 0x2070,
- 0x2074, 0x2079,
- 0x2080, 0x2089,
- 0x2150, 0x215f,
- 0x2189, 0x2189,
- 0x2460, 0x249b,
- 0x24ea, 0x24ff,
- 0x2776, 0x2793,
- 0x2cfd, 0x2cfd,
- 0x3192, 0x3195,
- 0x3220, 0x3229,
- 0x3248, 0x324f,
- 0x3251, 0x325f,
- 0x3280, 0x3289,
- 0x32b1, 0x32bf,
- 0xa830, 0xa835,
- 0x10107, 0x10133,
- 0x10175, 0x10178,
- 0x1018a, 0x1018b,
- 0x102e1, 0x102fb,
- 0x10320, 0x10323,
- 0x10858, 0x1085f,
- 0x10879, 0x1087f,
- 0x108a7, 0x108af,
- 0x108fb, 0x108ff,
- 0x10916, 0x1091b,
- 0x109bc, 0x109bd,
- 0x109c0, 0x109cf,
- 0x109d2, 0x109ff,
- 0x10a40, 0x10a48,
- 0x10a7d, 0x10a7e,
- 0x10a9d, 0x10a9f,
- 0x10aeb, 0x10aef,
- 0x10b58, 0x10b5f,
- 0x10b78, 0x10b7f,
- 0x10ba9, 0x10baf,
- 0x10cfa, 0x10cff,
- 0x10e60, 0x10e7e,
- 0x10f1d, 0x10f26,
- 0x10f51, 0x10f54,
- 0x10fc5, 0x10fcb,
- 0x11052, 0x11065,
- 0x111e1, 0x111f4,
- 0x1173a, 0x1173b,
- 0x118ea, 0x118f2,
- 0x11c5a, 0x11c6c,
- 0x11fc0, 0x11fd4,
- 0x16b5b, 0x16b61,
- 0x16e80, 0x16e96,
- 0x1d2c0, 0x1d2d3,
- 0x1d2e0, 0x1d2f3,
- 0x1d360, 0x1d378,
- 0x1e8c7, 0x1e8cf,
- 0x1ec71, 0x1ecab,
- 0x1ecad, 0x1ecaf,
- 0x1ecb1, 0x1ecb4,
- 0x1ed01, 0x1ed2d,
- 0x1ed2f, 0x1ed3d,
- 0x1f100, 0x1f10c,
-}; /* CR_No */
-
-/* 'P': Major Category */
-#define CR_P CR_Punct
-
-/* 'Pc': General Category */
-static const OnigCodePoint CR_Pc[] = {
- 6,
- 0x005f, 0x005f,
- 0x203f, 0x2040,
- 0x2054, 0x2054,
- 0xfe33, 0xfe34,
- 0xfe4d, 0xfe4f,
- 0xff3f, 0xff3f,
-}; /* CR_Pc */
-
-/* 'Pd': General Category */
-static const OnigCodePoint CR_Pd[] = {
- 20,
- 0x002d, 0x002d,
- 0x058a, 0x058a,
- 0x05be, 0x05be,
- 0x1400, 0x1400,
- 0x1806, 0x1806,
- 0x2010, 0x2015,
- 0x2e17, 0x2e17,
- 0x2e1a, 0x2e1a,
- 0x2e3a, 0x2e3b,
- 0x2e40, 0x2e40,
- 0x2e5d, 0x2e5d,
- 0x301c, 0x301c,
- 0x3030, 0x3030,
- 0x30a0, 0x30a0,
- 0xfe31, 0xfe32,
- 0xfe58, 0xfe58,
- 0xfe63, 0xfe63,
- 0xff0d, 0xff0d,
- 0x10d6e, 0x10d6e,
- 0x10ead, 0x10ead,
-}; /* CR_Pd */
-
-/* 'Pe': General Category */
-static const OnigCodePoint CR_Pe[] = {
- 76,
- 0x0029, 0x0029,
- 0x005d, 0x005d,
- 0x007d, 0x007d,
- 0x0f3b, 0x0f3b,
- 0x0f3d, 0x0f3d,
- 0x169c, 0x169c,
- 0x2046, 0x2046,
- 0x207e, 0x207e,
- 0x208e, 0x208e,
- 0x2309, 0x2309,
- 0x230b, 0x230b,
- 0x232a, 0x232a,
- 0x2769, 0x2769,
- 0x276b, 0x276b,
- 0x276d, 0x276d,
- 0x276f, 0x276f,
- 0x2771, 0x2771,
- 0x2773, 0x2773,
- 0x2775, 0x2775,
- 0x27c6, 0x27c6,
- 0x27e7, 0x27e7,
- 0x27e9, 0x27e9,
- 0x27eb, 0x27eb,
- 0x27ed, 0x27ed,
- 0x27ef, 0x27ef,
- 0x2984, 0x2984,
- 0x2986, 0x2986,
- 0x2988, 0x2988,
- 0x298a, 0x298a,
- 0x298c, 0x298c,
- 0x298e, 0x298e,
- 0x2990, 0x2990,
- 0x2992, 0x2992,
- 0x2994, 0x2994,
- 0x2996, 0x2996,
- 0x2998, 0x2998,
- 0x29d9, 0x29d9,
- 0x29db, 0x29db,
- 0x29fd, 0x29fd,
- 0x2e23, 0x2e23,
- 0x2e25, 0x2e25,
- 0x2e27, 0x2e27,
- 0x2e29, 0x2e29,
- 0x2e56, 0x2e56,
- 0x2e58, 0x2e58,
- 0x2e5a, 0x2e5a,
- 0x2e5c, 0x2e5c,
- 0x3009, 0x3009,
- 0x300b, 0x300b,
- 0x300d, 0x300d,
- 0x300f, 0x300f,
- 0x3011, 0x3011,
- 0x3015, 0x3015,
- 0x3017, 0x3017,
- 0x3019, 0x3019,
- 0x301b, 0x301b,
- 0x301e, 0x301f,
- 0xfd3e, 0xfd3e,
- 0xfe18, 0xfe18,
- 0xfe36, 0xfe36,
- 0xfe38, 0xfe38,
- 0xfe3a, 0xfe3a,
- 0xfe3c, 0xfe3c,
- 0xfe3e, 0xfe3e,
- 0xfe40, 0xfe40,
- 0xfe42, 0xfe42,
- 0xfe44, 0xfe44,
- 0xfe48, 0xfe48,
- 0xfe5a, 0xfe5a,
- 0xfe5c, 0xfe5c,
- 0xfe5e, 0xfe5e,
- 0xff09, 0xff09,
- 0xff3d, 0xff3d,
- 0xff5d, 0xff5d,
- 0xff60, 0xff60,
- 0xff63, 0xff63,
-}; /* CR_Pe */
-
-/* 'Pf': General Category */
-static const OnigCodePoint CR_Pf[] = {
- 10,
- 0x00bb, 0x00bb,
- 0x2019, 0x2019,
- 0x201d, 0x201d,
- 0x203a, 0x203a,
- 0x2e03, 0x2e03,
- 0x2e05, 0x2e05,
- 0x2e0a, 0x2e0a,
- 0x2e0d, 0x2e0d,
- 0x2e1d, 0x2e1d,
- 0x2e21, 0x2e21,
-}; /* CR_Pf */
-
-/* 'Pi': General Category */
-static const OnigCodePoint CR_Pi[] = {
- 11,
- 0x00ab, 0x00ab,
- 0x2018, 0x2018,
- 0x201b, 0x201c,
- 0x201f, 0x201f,
- 0x2039, 0x2039,
- 0x2e02, 0x2e02,
- 0x2e04, 0x2e04,
- 0x2e09, 0x2e09,
- 0x2e0c, 0x2e0c,
- 0x2e1c, 0x2e1c,
- 0x2e20, 0x2e20,
-}; /* CR_Pi */
-
-/* 'Po': General Category */
-static const OnigCodePoint CR_Po[] = {
- 193,
- 0x0021, 0x0023,
- 0x0025, 0x0027,
- 0x002a, 0x002a,
- 0x002c, 0x002c,
- 0x002e, 0x002f,
- 0x003a, 0x003b,
- 0x003f, 0x0040,
- 0x005c, 0x005c,
- 0x00a1, 0x00a1,
- 0x00a7, 0x00a7,
- 0x00b6, 0x00b7,
- 0x00bf, 0x00bf,
- 0x037e, 0x037e,
- 0x0387, 0x0387,
- 0x055a, 0x055f,
- 0x0589, 0x0589,
- 0x05c0, 0x05c0,
- 0x05c3, 0x05c3,
- 0x05c6, 0x05c6,
- 0x05f3, 0x05f4,
- 0x0609, 0x060a,
- 0x060c, 0x060d,
- 0x061b, 0x061b,
- 0x061d, 0x061f,
- 0x066a, 0x066d,
- 0x06d4, 0x06d4,
- 0x0700, 0x070d,
- 0x07f7, 0x07f9,
- 0x0830, 0x083e,
- 0x085e, 0x085e,
- 0x0964, 0x0965,
- 0x0970, 0x0970,
- 0x09fd, 0x09fd,
- 0x0a76, 0x0a76,
- 0x0af0, 0x0af0,
- 0x0c77, 0x0c77,
- 0x0c84, 0x0c84,
- 0x0df4, 0x0df4,
- 0x0e4f, 0x0e4f,
- 0x0e5a, 0x0e5b,
- 0x0f04, 0x0f12,
- 0x0f14, 0x0f14,
- 0x0f85, 0x0f85,
- 0x0fd0, 0x0fd4,
- 0x0fd9, 0x0fda,
- 0x104a, 0x104f,
- 0x10fb, 0x10fb,
- 0x1360, 0x1368,
- 0x166e, 0x166e,
- 0x16eb, 0x16ed,
- 0x1735, 0x1736,
- 0x17d4, 0x17d6,
- 0x17d8, 0x17da,
- 0x1800, 0x1805,
- 0x1807, 0x180a,
- 0x1944, 0x1945,
- 0x1a1e, 0x1a1f,
- 0x1aa0, 0x1aa6,
- 0x1aa8, 0x1aad,
- 0x1b4e, 0x1b4f,
- 0x1b5a, 0x1b60,
- 0x1b7d, 0x1b7f,
- 0x1bfc, 0x1bff,
- 0x1c3b, 0x1c3f,
- 0x1c7e, 0x1c7f,
- 0x1cc0, 0x1cc7,
- 0x1cd3, 0x1cd3,
- 0x2016, 0x2017,
- 0x2020, 0x2027,
- 0x2030, 0x2038,
- 0x203b, 0x203e,
- 0x2041, 0x2043,
- 0x2047, 0x2051,
- 0x2053, 0x2053,
- 0x2055, 0x205e,
- 0x2cf9, 0x2cfc,
- 0x2cfe, 0x2cff,
- 0x2d70, 0x2d70,
- 0x2e00, 0x2e01,
- 0x2e06, 0x2e08,
- 0x2e0b, 0x2e0b,
- 0x2e0e, 0x2e16,
- 0x2e18, 0x2e19,
- 0x2e1b, 0x2e1b,
- 0x2e1e, 0x2e1f,
- 0x2e2a, 0x2e2e,
- 0x2e30, 0x2e39,
- 0x2e3c, 0x2e3f,
- 0x2e41, 0x2e41,
- 0x2e43, 0x2e4f,
- 0x2e52, 0x2e54,
- 0x3001, 0x3003,
- 0x303d, 0x303d,
- 0x30fb, 0x30fb,
- 0xa4fe, 0xa4ff,
- 0xa60d, 0xa60f,
- 0xa673, 0xa673,
- 0xa67e, 0xa67e,
- 0xa6f2, 0xa6f7,
- 0xa874, 0xa877,
- 0xa8ce, 0xa8cf,
- 0xa8f8, 0xa8fa,
- 0xa8fc, 0xa8fc,
- 0xa92e, 0xa92f,
- 0xa95f, 0xa95f,
- 0xa9c1, 0xa9cd,
- 0xa9de, 0xa9df,
- 0xaa5c, 0xaa5f,
- 0xaade, 0xaadf,
- 0xaaf0, 0xaaf1,
- 0xabeb, 0xabeb,
- 0xfe10, 0xfe16,
- 0xfe19, 0xfe19,
- 0xfe30, 0xfe30,
- 0xfe45, 0xfe46,
- 0xfe49, 0xfe4c,
- 0xfe50, 0xfe52,
- 0xfe54, 0xfe57,
- 0xfe5f, 0xfe61,
- 0xfe68, 0xfe68,
- 0xfe6a, 0xfe6b,
- 0xff01, 0xff03,
- 0xff05, 0xff07,
- 0xff0a, 0xff0a,
- 0xff0c, 0xff0c,
- 0xff0e, 0xff0f,
- 0xff1a, 0xff1b,
- 0xff1f, 0xff20,
- 0xff3c, 0xff3c,
- 0xff61, 0xff61,
- 0xff64, 0xff65,
- 0x10100, 0x10102,
- 0x1039f, 0x1039f,
- 0x103d0, 0x103d0,
- 0x1056f, 0x1056f,
- 0x10857, 0x10857,
- 0x1091f, 0x1091f,
- 0x1093f, 0x1093f,
- 0x10a50, 0x10a58,
- 0x10a7f, 0x10a7f,
- 0x10af0, 0x10af6,
- 0x10b39, 0x10b3f,
- 0x10b99, 0x10b9c,
- 0x10f55, 0x10f59,
- 0x10f86, 0x10f89,
- 0x11047, 0x1104d,
- 0x110bb, 0x110bc,
- 0x110be, 0x110c1,
- 0x11140, 0x11143,
- 0x11174, 0x11175,
- 0x111c5, 0x111c8,
- 0x111cd, 0x111cd,
- 0x111db, 0x111db,
- 0x111dd, 0x111df,
- 0x11238, 0x1123d,
- 0x112a9, 0x112a9,
- 0x113d4, 0x113d5,
- 0x113d7, 0x113d8,
- 0x1144b, 0x1144f,
- 0x1145a, 0x1145b,
- 0x1145d, 0x1145d,
- 0x114c6, 0x114c6,
- 0x115c1, 0x115d7,
- 0x11641, 0x11643,
- 0x11660, 0x1166c,
- 0x116b9, 0x116b9,
- 0x1173c, 0x1173e,
- 0x1183b, 0x1183b,
- 0x11944, 0x11946,
- 0x119e2, 0x119e2,
- 0x11a3f, 0x11a46,
- 0x11a9a, 0x11a9c,
- 0x11a9e, 0x11aa2,
- 0x11b00, 0x11b09,
- 0x11be1, 0x11be1,
- 0x11c41, 0x11c45,
- 0x11c70, 0x11c71,
- 0x11ef7, 0x11ef8,
- 0x11f43, 0x11f4f,
- 0x11fff, 0x11fff,
- 0x12470, 0x12474,
- 0x12ff1, 0x12ff2,
- 0x16a6e, 0x16a6f,
- 0x16af5, 0x16af5,
- 0x16b37, 0x16b3b,
- 0x16b44, 0x16b44,
- 0x16d6d, 0x16d6f,
- 0x16e97, 0x16e9a,
- 0x16fe2, 0x16fe2,
- 0x1bc9f, 0x1bc9f,
- 0x1da87, 0x1da8b,
- 0x1e5ff, 0x1e5ff,
- 0x1e95e, 0x1e95f,
-}; /* CR_Po */
-
-/* 'Ps': General Category */
-static const OnigCodePoint CR_Ps[] = {
- 79,
- 0x0028, 0x0028,
- 0x005b, 0x005b,
- 0x007b, 0x007b,
- 0x0f3a, 0x0f3a,
- 0x0f3c, 0x0f3c,
- 0x169b, 0x169b,
- 0x201a, 0x201a,
- 0x201e, 0x201e,
- 0x2045, 0x2045,
- 0x207d, 0x207d,
- 0x208d, 0x208d,
- 0x2308, 0x2308,
- 0x230a, 0x230a,
- 0x2329, 0x2329,
- 0x2768, 0x2768,
- 0x276a, 0x276a,
- 0x276c, 0x276c,
- 0x276e, 0x276e,
- 0x2770, 0x2770,
- 0x2772, 0x2772,
- 0x2774, 0x2774,
- 0x27c5, 0x27c5,
- 0x27e6, 0x27e6,
- 0x27e8, 0x27e8,
- 0x27ea, 0x27ea,
- 0x27ec, 0x27ec,
- 0x27ee, 0x27ee,
- 0x2983, 0x2983,
- 0x2985, 0x2985,
- 0x2987, 0x2987,
- 0x2989, 0x2989,
- 0x298b, 0x298b,
- 0x298d, 0x298d,
- 0x298f, 0x298f,
- 0x2991, 0x2991,
- 0x2993, 0x2993,
- 0x2995, 0x2995,
- 0x2997, 0x2997,
- 0x29d8, 0x29d8,
- 0x29da, 0x29da,
- 0x29fc, 0x29fc,
- 0x2e22, 0x2e22,
- 0x2e24, 0x2e24,
- 0x2e26, 0x2e26,
- 0x2e28, 0x2e28,
- 0x2e42, 0x2e42,
- 0x2e55, 0x2e55,
- 0x2e57, 0x2e57,
- 0x2e59, 0x2e59,
- 0x2e5b, 0x2e5b,
- 0x3008, 0x3008,
- 0x300a, 0x300a,
- 0x300c, 0x300c,
- 0x300e, 0x300e,
- 0x3010, 0x3010,
- 0x3014, 0x3014,
- 0x3016, 0x3016,
- 0x3018, 0x3018,
- 0x301a, 0x301a,
- 0x301d, 0x301d,
- 0xfd3f, 0xfd3f,
- 0xfe17, 0xfe17,
- 0xfe35, 0xfe35,
- 0xfe37, 0xfe37,
- 0xfe39, 0xfe39,
- 0xfe3b, 0xfe3b,
- 0xfe3d, 0xfe3d,
- 0xfe3f, 0xfe3f,
- 0xfe41, 0xfe41,
- 0xfe43, 0xfe43,
- 0xfe47, 0xfe47,
- 0xfe59, 0xfe59,
- 0xfe5b, 0xfe5b,
- 0xfe5d, 0xfe5d,
- 0xff08, 0xff08,
- 0xff3b, 0xff3b,
- 0xff5b, 0xff5b,
- 0xff5f, 0xff5f,
- 0xff62, 0xff62,
-}; /* CR_Ps */
-
-/* 'S': Major Category */
-static const OnigCodePoint CR_S[] = {
- 236,
- 0x0024, 0x0024,
- 0x002b, 0x002b,
- 0x003c, 0x003e,
- 0x005e, 0x005e,
- 0x0060, 0x0060,
- 0x007c, 0x007c,
- 0x007e, 0x007e,
- 0x00a2, 0x00a6,
- 0x00a8, 0x00a9,
- 0x00ac, 0x00ac,
- 0x00ae, 0x00b1,
- 0x00b4, 0x00b4,
- 0x00b8, 0x00b8,
- 0x00d7, 0x00d7,
- 0x00f7, 0x00f7,
- 0x02c2, 0x02c5,
- 0x02d2, 0x02df,
- 0x02e5, 0x02eb,
- 0x02ed, 0x02ed,
- 0x02ef, 0x02ff,
- 0x0375, 0x0375,
- 0x0384, 0x0385,
- 0x03f6, 0x03f6,
- 0x0482, 0x0482,
- 0x058d, 0x058f,
- 0x0606, 0x0608,
- 0x060b, 0x060b,
- 0x060e, 0x060f,
- 0x06de, 0x06de,
- 0x06e9, 0x06e9,
- 0x06fd, 0x06fe,
- 0x07f6, 0x07f6,
- 0x07fe, 0x07ff,
- 0x0888, 0x0888,
- 0x09f2, 0x09f3,
- 0x09fa, 0x09fb,
- 0x0af1, 0x0af1,
- 0x0b70, 0x0b70,
- 0x0bf3, 0x0bfa,
- 0x0c7f, 0x0c7f,
- 0x0d4f, 0x0d4f,
- 0x0d79, 0x0d79,
- 0x0e3f, 0x0e3f,
- 0x0f01, 0x0f03,
- 0x0f13, 0x0f13,
- 0x0f15, 0x0f17,
- 0x0f1a, 0x0f1f,
- 0x0f34, 0x0f34,
- 0x0f36, 0x0f36,
- 0x0f38, 0x0f38,
- 0x0fbe, 0x0fc5,
- 0x0fc7, 0x0fcc,
- 0x0fce, 0x0fcf,
- 0x0fd5, 0x0fd8,
- 0x109e, 0x109f,
- 0x1390, 0x1399,
- 0x166d, 0x166d,
- 0x17db, 0x17db,
- 0x1940, 0x1940,
- 0x19de, 0x19ff,
- 0x1b61, 0x1b6a,
- 0x1b74, 0x1b7c,
- 0x1fbd, 0x1fbd,
- 0x1fbf, 0x1fc1,
- 0x1fcd, 0x1fcf,
- 0x1fdd, 0x1fdf,
- 0x1fed, 0x1fef,
- 0x1ffd, 0x1ffe,
- 0x2044, 0x2044,
- 0x2052, 0x2052,
- 0x207a, 0x207c,
- 0x208a, 0x208c,
- 0x20a0, 0x20c0,
- 0x2100, 0x2101,
- 0x2103, 0x2106,
- 0x2108, 0x2109,
- 0x2114, 0x2114,
- 0x2116, 0x2118,
- 0x211e, 0x2123,
- 0x2125, 0x2125,
- 0x2127, 0x2127,
- 0x2129, 0x2129,
- 0x212e, 0x212e,
- 0x213a, 0x213b,
- 0x2140, 0x2144,
- 0x214a, 0x214d,
- 0x214f, 0x214f,
- 0x218a, 0x218b,
- 0x2190, 0x2307,
- 0x230c, 0x2328,
- 0x232b, 0x2429,
- 0x2440, 0x244a,
- 0x249c, 0x24e9,
- 0x2500, 0x2767,
- 0x2794, 0x27c4,
- 0x27c7, 0x27e5,
- 0x27f0, 0x2982,
- 0x2999, 0x29d7,
- 0x29dc, 0x29fb,
- 0x29fe, 0x2b73,
- 0x2b76, 0x2b95,
- 0x2b97, 0x2bff,
- 0x2ce5, 0x2cea,
- 0x2e50, 0x2e51,
- 0x2e80, 0x2e99,
- 0x2e9b, 0x2ef3,
- 0x2f00, 0x2fd5,
- 0x2ff0, 0x2fff,
- 0x3004, 0x3004,
- 0x3012, 0x3013,
- 0x3020, 0x3020,
- 0x3036, 0x3037,
- 0x303e, 0x303f,
- 0x309b, 0x309c,
- 0x3190, 0x3191,
- 0x3196, 0x319f,
- 0x31c0, 0x31e5,
- 0x31ef, 0x31ef,
- 0x3200, 0x321e,
- 0x322a, 0x3247,
- 0x3250, 0x3250,
- 0x3260, 0x327f,
- 0x328a, 0x32b0,
- 0x32c0, 0x33ff,
- 0x4dc0, 0x4dff,
- 0xa490, 0xa4c6,
- 0xa700, 0xa716,
- 0xa720, 0xa721,
- 0xa789, 0xa78a,
- 0xa828, 0xa82b,
- 0xa836, 0xa839,
- 0xaa77, 0xaa79,
- 0xab5b, 0xab5b,
- 0xab6a, 0xab6b,
- 0xfb29, 0xfb29,
- 0xfbb2, 0xfbc2,
- 0xfd40, 0xfd4f,
- 0xfdcf, 0xfdcf,
- 0xfdfc, 0xfdff,
- 0xfe62, 0xfe62,
- 0xfe64, 0xfe66,
- 0xfe69, 0xfe69,
- 0xff04, 0xff04,
- 0xff0b, 0xff0b,
- 0xff1c, 0xff1e,
- 0xff3e, 0xff3e,
- 0xff40, 0xff40,
- 0xff5c, 0xff5c,
- 0xff5e, 0xff5e,
- 0xffe0, 0xffe6,
- 0xffe8, 0xffee,
- 0xfffc, 0xfffd,
- 0x10137, 0x1013f,
- 0x10179, 0x10189,
- 0x1018c, 0x1018e,
- 0x10190, 0x1019c,
- 0x101a0, 0x101a0,
- 0x101d0, 0x101fc,
- 0x10877, 0x10878,
- 0x10ac8, 0x10ac8,
- 0x10d8e, 0x10d8f,
- 0x1173f, 0x1173f,
- 0x11fd5, 0x11ff1,
- 0x16b3c, 0x16b3f,
- 0x16b45, 0x16b45,
- 0x1bc9c, 0x1bc9c,
- 0x1cc00, 0x1ccef,
- 0x1cd00, 0x1ceb3,
- 0x1cf50, 0x1cfc3,
- 0x1d000, 0x1d0f5,
- 0x1d100, 0x1d126,
- 0x1d129, 0x1d164,
- 0x1d16a, 0x1d16c,
- 0x1d183, 0x1d184,
- 0x1d18c, 0x1d1a9,
- 0x1d1ae, 0x1d1ea,
- 0x1d200, 0x1d241,
- 0x1d245, 0x1d245,
- 0x1d300, 0x1d356,
- 0x1d6c1, 0x1d6c1,
- 0x1d6db, 0x1d6db,
- 0x1d6fb, 0x1d6fb,
- 0x1d715, 0x1d715,
- 0x1d735, 0x1d735,
- 0x1d74f, 0x1d74f,
- 0x1d76f, 0x1d76f,
- 0x1d789, 0x1d789,
- 0x1d7a9, 0x1d7a9,
- 0x1d7c3, 0x1d7c3,
- 0x1d800, 0x1d9ff,
- 0x1da37, 0x1da3a,
- 0x1da6d, 0x1da74,
- 0x1da76, 0x1da83,
- 0x1da85, 0x1da86,
- 0x1e14f, 0x1e14f,
- 0x1e2ff, 0x1e2ff,
- 0x1ecac, 0x1ecac,
- 0x1ecb0, 0x1ecb0,
- 0x1ed2e, 0x1ed2e,
- 0x1eef0, 0x1eef1,
- 0x1f000, 0x1f02b,
- 0x1f030, 0x1f093,
- 0x1f0a0, 0x1f0ae,
- 0x1f0b1, 0x1f0bf,
- 0x1f0c1, 0x1f0cf,
- 0x1f0d1, 0x1f0f5,
- 0x1f10d, 0x1f1ad,
- 0x1f1e6, 0x1f202,
- 0x1f210, 0x1f23b,
- 0x1f240, 0x1f248,
- 0x1f250, 0x1f251,
- 0x1f260, 0x1f265,
- 0x1f300, 0x1f6d7,
- 0x1f6dc, 0x1f6ec,
- 0x1f6f0, 0x1f6fc,
- 0x1f700, 0x1f776,
- 0x1f77b, 0x1f7d9,
- 0x1f7e0, 0x1f7eb,
- 0x1f7f0, 0x1f7f0,
- 0x1f800, 0x1f80b,
- 0x1f810, 0x1f847,
- 0x1f850, 0x1f859,
- 0x1f860, 0x1f887,
- 0x1f890, 0x1f8ad,
- 0x1f8b0, 0x1f8bb,
- 0x1f8c0, 0x1f8c1,
- 0x1f900, 0x1fa53,
- 0x1fa60, 0x1fa6d,
- 0x1fa70, 0x1fa7c,
- 0x1fa80, 0x1fa89,
- 0x1fa8f, 0x1fac6,
- 0x1face, 0x1fadc,
- 0x1fadf, 0x1fae9,
- 0x1faf0, 0x1faf8,
- 0x1fb00, 0x1fb92,
- 0x1fb94, 0x1fbef,
-}; /* CR_S */
-
-/* 'Sc': General Category */
-static const OnigCodePoint CR_Sc[] = {
- 21,
- 0x0024, 0x0024,
- 0x00a2, 0x00a5,
- 0x058f, 0x058f,
- 0x060b, 0x060b,
- 0x07fe, 0x07ff,
- 0x09f2, 0x09f3,
- 0x09fb, 0x09fb,
- 0x0af1, 0x0af1,
- 0x0bf9, 0x0bf9,
- 0x0e3f, 0x0e3f,
- 0x17db, 0x17db,
- 0x20a0, 0x20c0,
- 0xa838, 0xa838,
- 0xfdfc, 0xfdfc,
- 0xfe69, 0xfe69,
- 0xff04, 0xff04,
- 0xffe0, 0xffe1,
- 0xffe5, 0xffe6,
- 0x11fdd, 0x11fe0,
- 0x1e2ff, 0x1e2ff,
- 0x1ecb0, 0x1ecb0,
-}; /* CR_Sc */
-
-/* 'Sk': General Category */
-static const OnigCodePoint CR_Sk[] = {
- 31,
- 0x005e, 0x005e,
- 0x0060, 0x0060,
- 0x00a8, 0x00a8,
- 0x00af, 0x00af,
- 0x00b4, 0x00b4,
- 0x00b8, 0x00b8,
- 0x02c2, 0x02c5,
- 0x02d2, 0x02df,
- 0x02e5, 0x02eb,
- 0x02ed, 0x02ed,
- 0x02ef, 0x02ff,
- 0x0375, 0x0375,
- 0x0384, 0x0385,
- 0x0888, 0x0888,
- 0x1fbd, 0x1fbd,
- 0x1fbf, 0x1fc1,
- 0x1fcd, 0x1fcf,
- 0x1fdd, 0x1fdf,
- 0x1fed, 0x1fef,
- 0x1ffd, 0x1ffe,
- 0x309b, 0x309c,
- 0xa700, 0xa716,
- 0xa720, 0xa721,
- 0xa789, 0xa78a,
- 0xab5b, 0xab5b,
- 0xab6a, 0xab6b,
- 0xfbb2, 0xfbc2,
- 0xff3e, 0xff3e,
- 0xff40, 0xff40,
- 0xffe3, 0xffe3,
- 0x1f3fb, 0x1f3ff,
-}; /* CR_Sk */
-
-/* 'Sm': General Category */
-static const OnigCodePoint CR_Sm[] = {
- 65,
- 0x002b, 0x002b,
- 0x003c, 0x003e,
- 0x007c, 0x007c,
- 0x007e, 0x007e,
- 0x00ac, 0x00ac,
- 0x00b1, 0x00b1,
- 0x00d7, 0x00d7,
- 0x00f7, 0x00f7,
- 0x03f6, 0x03f6,
- 0x0606, 0x0608,
- 0x2044, 0x2044,
- 0x2052, 0x2052,
- 0x207a, 0x207c,
- 0x208a, 0x208c,
- 0x2118, 0x2118,
- 0x2140, 0x2144,
- 0x214b, 0x214b,
- 0x2190, 0x2194,
- 0x219a, 0x219b,
- 0x21a0, 0x21a0,
- 0x21a3, 0x21a3,
- 0x21a6, 0x21a6,
- 0x21ae, 0x21ae,
- 0x21ce, 0x21cf,
- 0x21d2, 0x21d2,
- 0x21d4, 0x21d4,
- 0x21f4, 0x22ff,
- 0x2320, 0x2321,
- 0x237c, 0x237c,
- 0x239b, 0x23b3,
- 0x23dc, 0x23e1,
- 0x25b7, 0x25b7,
- 0x25c1, 0x25c1,
- 0x25f8, 0x25ff,
- 0x266f, 0x266f,
- 0x27c0, 0x27c4,
- 0x27c7, 0x27e5,
- 0x27f0, 0x27ff,
- 0x2900, 0x2982,
- 0x2999, 0x29d7,
- 0x29dc, 0x29fb,
- 0x29fe, 0x2aff,
- 0x2b30, 0x2b44,
- 0x2b47, 0x2b4c,
- 0xfb29, 0xfb29,
- 0xfe62, 0xfe62,
- 0xfe64, 0xfe66,
- 0xff0b, 0xff0b,
- 0xff1c, 0xff1e,
- 0xff5c, 0xff5c,
- 0xff5e, 0xff5e,
- 0xffe2, 0xffe2,
- 0xffe9, 0xffec,
- 0x10d8e, 0x10d8f,
- 0x1d6c1, 0x1d6c1,
- 0x1d6db, 0x1d6db,
- 0x1d6fb, 0x1d6fb,
- 0x1d715, 0x1d715,
- 0x1d735, 0x1d735,
- 0x1d74f, 0x1d74f,
- 0x1d76f, 0x1d76f,
- 0x1d789, 0x1d789,
- 0x1d7a9, 0x1d7a9,
- 0x1d7c3, 0x1d7c3,
- 0x1eef0, 0x1eef1,
-}; /* CR_Sm */
-
-/* 'So': General Category */
-static const OnigCodePoint CR_So[] = {
- 187,
- 0x00a6, 0x00a6,
- 0x00a9, 0x00a9,
- 0x00ae, 0x00ae,
- 0x00b0, 0x00b0,
- 0x0482, 0x0482,
- 0x058d, 0x058e,
- 0x060e, 0x060f,
- 0x06de, 0x06de,
- 0x06e9, 0x06e9,
- 0x06fd, 0x06fe,
- 0x07f6, 0x07f6,
- 0x09fa, 0x09fa,
- 0x0b70, 0x0b70,
- 0x0bf3, 0x0bf8,
- 0x0bfa, 0x0bfa,
- 0x0c7f, 0x0c7f,
- 0x0d4f, 0x0d4f,
- 0x0d79, 0x0d79,
- 0x0f01, 0x0f03,
- 0x0f13, 0x0f13,
- 0x0f15, 0x0f17,
- 0x0f1a, 0x0f1f,
- 0x0f34, 0x0f34,
- 0x0f36, 0x0f36,
- 0x0f38, 0x0f38,
- 0x0fbe, 0x0fc5,
- 0x0fc7, 0x0fcc,
- 0x0fce, 0x0fcf,
- 0x0fd5, 0x0fd8,
- 0x109e, 0x109f,
- 0x1390, 0x1399,
- 0x166d, 0x166d,
- 0x1940, 0x1940,
- 0x19de, 0x19ff,
- 0x1b61, 0x1b6a,
- 0x1b74, 0x1b7c,
- 0x2100, 0x2101,
- 0x2103, 0x2106,
- 0x2108, 0x2109,
- 0x2114, 0x2114,
- 0x2116, 0x2117,
- 0x211e, 0x2123,
- 0x2125, 0x2125,
- 0x2127, 0x2127,
- 0x2129, 0x2129,
- 0x212e, 0x212e,
- 0x213a, 0x213b,
- 0x214a, 0x214a,
- 0x214c, 0x214d,
- 0x214f, 0x214f,
- 0x218a, 0x218b,
- 0x2195, 0x2199,
- 0x219c, 0x219f,
- 0x21a1, 0x21a2,
- 0x21a4, 0x21a5,
- 0x21a7, 0x21ad,
- 0x21af, 0x21cd,
- 0x21d0, 0x21d1,
- 0x21d3, 0x21d3,
- 0x21d5, 0x21f3,
- 0x2300, 0x2307,
- 0x230c, 0x231f,
- 0x2322, 0x2328,
- 0x232b, 0x237b,
- 0x237d, 0x239a,
- 0x23b4, 0x23db,
- 0x23e2, 0x2429,
- 0x2440, 0x244a,
- 0x249c, 0x24e9,
- 0x2500, 0x25b6,
- 0x25b8, 0x25c0,
- 0x25c2, 0x25f7,
- 0x2600, 0x266e,
- 0x2670, 0x2767,
- 0x2794, 0x27bf,
- 0x2800, 0x28ff,
- 0x2b00, 0x2b2f,
- 0x2b45, 0x2b46,
- 0x2b4d, 0x2b73,
- 0x2b76, 0x2b95,
- 0x2b97, 0x2bff,
- 0x2ce5, 0x2cea,
- 0x2e50, 0x2e51,
- 0x2e80, 0x2e99,
- 0x2e9b, 0x2ef3,
- 0x2f00, 0x2fd5,
- 0x2ff0, 0x2fff,
- 0x3004, 0x3004,
- 0x3012, 0x3013,
- 0x3020, 0x3020,
- 0x3036, 0x3037,
- 0x303e, 0x303f,
- 0x3190, 0x3191,
- 0x3196, 0x319f,
- 0x31c0, 0x31e5,
- 0x31ef, 0x31ef,
- 0x3200, 0x321e,
- 0x322a, 0x3247,
- 0x3250, 0x3250,
- 0x3260, 0x327f,
- 0x328a, 0x32b0,
- 0x32c0, 0x33ff,
- 0x4dc0, 0x4dff,
- 0xa490, 0xa4c6,
- 0xa828, 0xa82b,
- 0xa836, 0xa837,
- 0xa839, 0xa839,
- 0xaa77, 0xaa79,
- 0xfd40, 0xfd4f,
- 0xfdcf, 0xfdcf,
- 0xfdfd, 0xfdff,
- 0xffe4, 0xffe4,
- 0xffe8, 0xffe8,
- 0xffed, 0xffee,
- 0xfffc, 0xfffd,
- 0x10137, 0x1013f,
- 0x10179, 0x10189,
- 0x1018c, 0x1018e,
- 0x10190, 0x1019c,
- 0x101a0, 0x101a0,
- 0x101d0, 0x101fc,
- 0x10877, 0x10878,
- 0x10ac8, 0x10ac8,
- 0x1173f, 0x1173f,
- 0x11fd5, 0x11fdc,
- 0x11fe1, 0x11ff1,
- 0x16b3c, 0x16b3f,
- 0x16b45, 0x16b45,
- 0x1bc9c, 0x1bc9c,
- 0x1cc00, 0x1ccef,
- 0x1cd00, 0x1ceb3,
- 0x1cf50, 0x1cfc3,
- 0x1d000, 0x1d0f5,
- 0x1d100, 0x1d126,
- 0x1d129, 0x1d164,
- 0x1d16a, 0x1d16c,
- 0x1d183, 0x1d184,
- 0x1d18c, 0x1d1a9,
- 0x1d1ae, 0x1d1ea,
- 0x1d200, 0x1d241,
- 0x1d245, 0x1d245,
- 0x1d300, 0x1d356,
- 0x1d800, 0x1d9ff,
- 0x1da37, 0x1da3a,
- 0x1da6d, 0x1da74,
- 0x1da76, 0x1da83,
- 0x1da85, 0x1da86,
- 0x1e14f, 0x1e14f,
- 0x1ecac, 0x1ecac,
- 0x1ed2e, 0x1ed2e,
- 0x1f000, 0x1f02b,
- 0x1f030, 0x1f093,
- 0x1f0a0, 0x1f0ae,
- 0x1f0b1, 0x1f0bf,
- 0x1f0c1, 0x1f0cf,
- 0x1f0d1, 0x1f0f5,
- 0x1f10d, 0x1f1ad,
- 0x1f1e6, 0x1f202,
- 0x1f210, 0x1f23b,
- 0x1f240, 0x1f248,
- 0x1f250, 0x1f251,
- 0x1f260, 0x1f265,
- 0x1f300, 0x1f3fa,
- 0x1f400, 0x1f6d7,
- 0x1f6dc, 0x1f6ec,
- 0x1f6f0, 0x1f6fc,
- 0x1f700, 0x1f776,
- 0x1f77b, 0x1f7d9,
- 0x1f7e0, 0x1f7eb,
- 0x1f7f0, 0x1f7f0,
- 0x1f800, 0x1f80b,
- 0x1f810, 0x1f847,
- 0x1f850, 0x1f859,
- 0x1f860, 0x1f887,
- 0x1f890, 0x1f8ad,
- 0x1f8b0, 0x1f8bb,
- 0x1f8c0, 0x1f8c1,
- 0x1f900, 0x1fa53,
- 0x1fa60, 0x1fa6d,
- 0x1fa70, 0x1fa7c,
- 0x1fa80, 0x1fa89,
- 0x1fa8f, 0x1fac6,
- 0x1face, 0x1fadc,
- 0x1fadf, 0x1fae9,
- 0x1faf0, 0x1faf8,
- 0x1fb00, 0x1fb92,
- 0x1fb94, 0x1fbef,
-}; /* CR_So */
-
-/* 'Z': Major Category */
-static const OnigCodePoint CR_Z[] = {
- 8,
- 0x0020, 0x0020,
- 0x00a0, 0x00a0,
- 0x1680, 0x1680,
- 0x2000, 0x200a,
- 0x2028, 0x2029,
- 0x202f, 0x202f,
- 0x205f, 0x205f,
- 0x3000, 0x3000,
-}; /* CR_Z */
-
-/* 'Zl': General Category */
-static const OnigCodePoint CR_Zl[] = {
- 1,
- 0x2028, 0x2028,
-}; /* CR_Zl */
-
-/* 'Zp': General Category */
-static const OnigCodePoint CR_Zp[] = {
- 1,
- 0x2029, 0x2029,
-}; /* CR_Zp */
-
-/* 'Zs': General Category */
-static const OnigCodePoint CR_Zs[] = {
- 7,
- 0x0020, 0x0020,
- 0x00a0, 0x00a0,
- 0x1680, 0x1680,
- 0x2000, 0x200a,
- 0x202f, 0x202f,
- 0x205f, 0x205f,
- 0x3000, 0x3000,
-}; /* CR_Zs */
-
-/* 'Math': Derived Property */
-static const OnigCodePoint CR_Math[] = {
- 139,
- 0x002b, 0x002b,
- 0x003c, 0x003e,
- 0x005e, 0x005e,
- 0x007c, 0x007c,
- 0x007e, 0x007e,
- 0x00ac, 0x00ac,
- 0x00b1, 0x00b1,
- 0x00d7, 0x00d7,
- 0x00f7, 0x00f7,
- 0x03d0, 0x03d2,
- 0x03d5, 0x03d5,
- 0x03f0, 0x03f1,
- 0x03f4, 0x03f6,
- 0x0606, 0x0608,
- 0x2016, 0x2016,
- 0x2032, 0x2034,
- 0x2040, 0x2040,
- 0x2044, 0x2044,
- 0x2052, 0x2052,
- 0x2061, 0x2064,
- 0x207a, 0x207e,
- 0x208a, 0x208e,
- 0x20d0, 0x20dc,
- 0x20e1, 0x20e1,
- 0x20e5, 0x20e6,
- 0x20eb, 0x20ef,
- 0x2102, 0x2102,
- 0x2107, 0x2107,
- 0x210a, 0x2113,
- 0x2115, 0x2115,
- 0x2118, 0x211d,
- 0x2124, 0x2124,
- 0x2128, 0x2129,
- 0x212c, 0x212d,
- 0x212f, 0x2131,
- 0x2133, 0x2138,
- 0x213c, 0x2149,
- 0x214b, 0x214b,
- 0x2190, 0x21a7,
- 0x21a9, 0x21ae,
- 0x21b0, 0x21b1,
- 0x21b6, 0x21b7,
- 0x21bc, 0x21db,
- 0x21dd, 0x21dd,
- 0x21e4, 0x21e5,
- 0x21f4, 0x22ff,
- 0x2308, 0x230b,
- 0x2320, 0x2321,
- 0x237c, 0x237c,
- 0x239b, 0x23b5,
- 0x23b7, 0x23b7,
- 0x23d0, 0x23d0,
- 0x23dc, 0x23e2,
- 0x25a0, 0x25a1,
- 0x25ae, 0x25b7,
- 0x25bc, 0x25c1,
- 0x25c6, 0x25c7,
- 0x25ca, 0x25cb,
- 0x25cf, 0x25d3,
- 0x25e2, 0x25e2,
- 0x25e4, 0x25e4,
- 0x25e7, 0x25ec,
- 0x25f8, 0x25ff,
- 0x2605, 0x2606,
- 0x2640, 0x2640,
- 0x2642, 0x2642,
- 0x2660, 0x2663,
- 0x266d, 0x266f,
- 0x27c0, 0x27ff,
- 0x2900, 0x2aff,
- 0x2b30, 0x2b44,
- 0x2b47, 0x2b4c,
- 0xfb29, 0xfb29,
- 0xfe61, 0xfe66,
- 0xfe68, 0xfe68,
- 0xff0b, 0xff0b,
- 0xff1c, 0xff1e,
- 0xff3c, 0xff3c,
- 0xff3e, 0xff3e,
- 0xff5c, 0xff5c,
- 0xff5e, 0xff5e,
- 0xffe2, 0xffe2,
- 0xffe9, 0xffec,
- 0x10d8e, 0x10d8f,
- 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, 0x1d7cb,
- 0x1d7ce, 0x1d7ff,
- 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,
- 0x1eef0, 0x1eef1,
-}; /* CR_Math */
-
-/* 'Alphabetic': Derived Property */
-#define CR_Alphabetic CR_Alpha
-
-/* 'Lowercase': Derived Property */
-#define CR_Lowercase CR_Lower
-
-/* 'Uppercase': Derived Property */
-#define CR_Uppercase CR_Upper
-
-/* 'Cased': Derived Property */
-static const OnigCodePoint CR_Cased[] = {
- 159,
- 0x0041, 0x005a,
- 0x0061, 0x007a,
- 0x00aa, 0x00aa,
- 0x00b5, 0x00b5,
- 0x00ba, 0x00ba,
- 0x00c0, 0x00d6,
- 0x00d8, 0x00f6,
- 0x00f8, 0x01ba,
- 0x01bc, 0x01bf,
- 0x01c4, 0x0293,
- 0x0295, 0x02b8,
- 0x02c0, 0x02c1,
- 0x02e0, 0x02e4,
- 0x0345, 0x0345,
- 0x0370, 0x0373,
- 0x0376, 0x0377,
- 0x037a, 0x037d,
- 0x037f, 0x037f,
- 0x0386, 0x0386,
- 0x0388, 0x038a,
- 0x038c, 0x038c,
- 0x038e, 0x03a1,
- 0x03a3, 0x03f5,
- 0x03f7, 0x0481,
- 0x048a, 0x052f,
- 0x0531, 0x0556,
- 0x0560, 0x0588,
- 0x10a0, 0x10c5,
- 0x10c7, 0x10c7,
- 0x10cd, 0x10cd,
- 0x10d0, 0x10fa,
- 0x10fc, 0x10ff,
- 0x13a0, 0x13f5,
- 0x13f8, 0x13fd,
- 0x1c80, 0x1c8a,
- 0x1c90, 0x1cba,
- 0x1cbd, 0x1cbf,
- 0x1d00, 0x1dbf,
- 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, 0x2134,
- 0x2139, 0x2139,
- 0x213c, 0x213f,
- 0x2145, 0x2149,
- 0x214e, 0x214e,
- 0x2160, 0x217f,
- 0x2183, 0x2184,
- 0x24b6, 0x24e9,
- 0x2c00, 0x2ce4,
- 0x2ceb, 0x2cee,
- 0x2cf2, 0x2cf3,
- 0x2d00, 0x2d25,
- 0x2d27, 0x2d27,
- 0x2d2d, 0x2d2d,
- 0xa640, 0xa66d,
- 0xa680, 0xa69d,
- 0xa722, 0xa787,
- 0xa78b, 0xa78e,
- 0xa790, 0xa7cd,
- 0xa7d0, 0xa7d1,
- 0xa7d3, 0xa7d3,
- 0xa7d5, 0xa7dc,
- 0xa7f2, 0xa7f6,
- 0xa7f8, 0xa7fa,
- 0xab30, 0xab5a,
- 0xab5c, 0xab69,
- 0xab70, 0xabbf,
- 0xfb00, 0xfb06,
- 0xfb13, 0xfb17,
- 0xff21, 0xff3a,
- 0xff41, 0xff5a,
- 0x10400, 0x1044f,
- 0x104b0, 0x104d3,
- 0x104d8, 0x104fb,
- 0x10570, 0x1057a,
- 0x1057c, 0x1058a,
- 0x1058c, 0x10592,
- 0x10594, 0x10595,
- 0x10597, 0x105a1,
- 0x105a3, 0x105b1,
- 0x105b3, 0x105b9,
- 0x105bb, 0x105bc,
- 0x10780, 0x10780,
- 0x10783, 0x10785,
- 0x10787, 0x107b0,
- 0x107b2, 0x107ba,
- 0x10c80, 0x10cb2,
- 0x10cc0, 0x10cf2,
- 0x10d50, 0x10d65,
- 0x10d70, 0x10d85,
- 0x118a0, 0x118df,
- 0x16e40, 0x16e7f,
- 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, 0x1df09,
- 0x1df0b, 0x1df1e,
- 0x1df25, 0x1df2a,
- 0x1e030, 0x1e06d,
- 0x1e900, 0x1e943,
- 0x1f130, 0x1f149,
- 0x1f150, 0x1f169,
- 0x1f170, 0x1f189,
-}; /* CR_Cased */
-
-/* 'Case_Ignorable': Derived Property */
-static const OnigCodePoint CR_Case_Ignorable[] = {
- 452,
- 0x0027, 0x0027,
- 0x002e, 0x002e,
- 0x003a, 0x003a,
- 0x005e, 0x005e,
- 0x0060, 0x0060,
- 0x00a8, 0x00a8,
- 0x00ad, 0x00ad,
- 0x00af, 0x00af,
- 0x00b4, 0x00b4,
- 0x00b7, 0x00b8,
- 0x02b0, 0x036f,
- 0x0374, 0x0375,
- 0x037a, 0x037a,
- 0x0384, 0x0385,
- 0x0387, 0x0387,
- 0x0483, 0x0489,
- 0x0559, 0x0559,
- 0x055f, 0x055f,
- 0x0591, 0x05bd,
- 0x05bf, 0x05bf,
- 0x05c1, 0x05c2,
- 0x05c4, 0x05c5,
- 0x05c7, 0x05c7,
- 0x05f4, 0x05f4,
- 0x0600, 0x0605,
- 0x0610, 0x061a,
- 0x061c, 0x061c,
- 0x0640, 0x0640,
- 0x064b, 0x065f,
- 0x0670, 0x0670,
- 0x06d6, 0x06dd,
- 0x06df, 0x06e8,
- 0x06ea, 0x06ed,
- 0x070f, 0x070f,
- 0x0711, 0x0711,
- 0x0730, 0x074a,
- 0x07a6, 0x07b0,
- 0x07eb, 0x07f5,
- 0x07fa, 0x07fa,
- 0x07fd, 0x07fd,
- 0x0816, 0x082d,
- 0x0859, 0x085b,
- 0x0888, 0x0888,
- 0x0890, 0x0891,
- 0x0897, 0x089f,
- 0x08c9, 0x0902,
- 0x093a, 0x093a,
- 0x093c, 0x093c,
- 0x0941, 0x0948,
- 0x094d, 0x094d,
- 0x0951, 0x0957,
- 0x0962, 0x0963,
- 0x0971, 0x0971,
- 0x0981, 0x0981,
- 0x09bc, 0x09bc,
- 0x09c1, 0x09c4,
- 0x09cd, 0x09cd,
- 0x09e2, 0x09e3,
- 0x09fe, 0x09fe,
- 0x0a01, 0x0a02,
- 0x0a3c, 0x0a3c,
- 0x0a41, 0x0a42,
- 0x0a47, 0x0a48,
- 0x0a4b, 0x0a4d,
- 0x0a51, 0x0a51,
- 0x0a70, 0x0a71,
- 0x0a75, 0x0a75,
- 0x0a81, 0x0a82,
- 0x0abc, 0x0abc,
- 0x0ac1, 0x0ac5,
- 0x0ac7, 0x0ac8,
- 0x0acd, 0x0acd,
- 0x0ae2, 0x0ae3,
- 0x0afa, 0x0aff,
- 0x0b01, 0x0b01,
- 0x0b3c, 0x0b3c,
- 0x0b3f, 0x0b3f,
- 0x0b41, 0x0b44,
- 0x0b4d, 0x0b4d,
- 0x0b55, 0x0b56,
- 0x0b62, 0x0b63,
- 0x0b82, 0x0b82,
- 0x0bc0, 0x0bc0,
- 0x0bcd, 0x0bcd,
- 0x0c00, 0x0c00,
- 0x0c04, 0x0c04,
- 0x0c3c, 0x0c3c,
- 0x0c3e, 0x0c40,
- 0x0c46, 0x0c48,
- 0x0c4a, 0x0c4d,
- 0x0c55, 0x0c56,
- 0x0c62, 0x0c63,
- 0x0c81, 0x0c81,
- 0x0cbc, 0x0cbc,
- 0x0cbf, 0x0cbf,
- 0x0cc6, 0x0cc6,
- 0x0ccc, 0x0ccd,
- 0x0ce2, 0x0ce3,
- 0x0d00, 0x0d01,
- 0x0d3b, 0x0d3c,
- 0x0d41, 0x0d44,
- 0x0d4d, 0x0d4d,
- 0x0d62, 0x0d63,
- 0x0d81, 0x0d81,
- 0x0dca, 0x0dca,
- 0x0dd2, 0x0dd4,
- 0x0dd6, 0x0dd6,
- 0x0e31, 0x0e31,
- 0x0e34, 0x0e3a,
- 0x0e46, 0x0e4e,
- 0x0eb1, 0x0eb1,
- 0x0eb4, 0x0ebc,
- 0x0ec6, 0x0ec6,
- 0x0ec8, 0x0ece,
- 0x0f18, 0x0f19,
- 0x0f35, 0x0f35,
- 0x0f37, 0x0f37,
- 0x0f39, 0x0f39,
- 0x0f71, 0x0f7e,
- 0x0f80, 0x0f84,
- 0x0f86, 0x0f87,
- 0x0f8d, 0x0f97,
- 0x0f99, 0x0fbc,
- 0x0fc6, 0x0fc6,
- 0x102d, 0x1030,
- 0x1032, 0x1037,
- 0x1039, 0x103a,
- 0x103d, 0x103e,
- 0x1058, 0x1059,
- 0x105e, 0x1060,
- 0x1071, 0x1074,
- 0x1082, 0x1082,
- 0x1085, 0x1086,
- 0x108d, 0x108d,
- 0x109d, 0x109d,
- 0x10fc, 0x10fc,
- 0x135d, 0x135f,
- 0x1712, 0x1714,
- 0x1732, 0x1733,
- 0x1752, 0x1753,
- 0x1772, 0x1773,
- 0x17b4, 0x17b5,
- 0x17b7, 0x17bd,
- 0x17c6, 0x17c6,
- 0x17c9, 0x17d3,
- 0x17d7, 0x17d7,
- 0x17dd, 0x17dd,
- 0x180b, 0x180f,
- 0x1843, 0x1843,
- 0x1885, 0x1886,
- 0x18a9, 0x18a9,
- 0x1920, 0x1922,
- 0x1927, 0x1928,
- 0x1932, 0x1932,
- 0x1939, 0x193b,
- 0x1a17, 0x1a18,
- 0x1a1b, 0x1a1b,
- 0x1a56, 0x1a56,
- 0x1a58, 0x1a5e,
- 0x1a60, 0x1a60,
- 0x1a62, 0x1a62,
- 0x1a65, 0x1a6c,
- 0x1a73, 0x1a7c,
- 0x1a7f, 0x1a7f,
- 0x1aa7, 0x1aa7,
- 0x1ab0, 0x1ace,
- 0x1b00, 0x1b03,
- 0x1b34, 0x1b34,
- 0x1b36, 0x1b3a,
- 0x1b3c, 0x1b3c,
- 0x1b42, 0x1b42,
- 0x1b6b, 0x1b73,
- 0x1b80, 0x1b81,
- 0x1ba2, 0x1ba5,
- 0x1ba8, 0x1ba9,
- 0x1bab, 0x1bad,
- 0x1be6, 0x1be6,
- 0x1be8, 0x1be9,
- 0x1bed, 0x1bed,
- 0x1bef, 0x1bf1,
- 0x1c2c, 0x1c33,
- 0x1c36, 0x1c37,
- 0x1c78, 0x1c7d,
- 0x1cd0, 0x1cd2,
- 0x1cd4, 0x1ce0,
- 0x1ce2, 0x1ce8,
- 0x1ced, 0x1ced,
- 0x1cf4, 0x1cf4,
- 0x1cf8, 0x1cf9,
- 0x1d2c, 0x1d6a,
- 0x1d78, 0x1d78,
- 0x1d9b, 0x1dff,
- 0x1fbd, 0x1fbd,
- 0x1fbf, 0x1fc1,
- 0x1fcd, 0x1fcf,
- 0x1fdd, 0x1fdf,
- 0x1fed, 0x1fef,
- 0x1ffd, 0x1ffe,
- 0x200b, 0x200f,
- 0x2018, 0x2019,
- 0x2024, 0x2024,
- 0x2027, 0x2027,
- 0x202a, 0x202e,
- 0x2060, 0x2064,
- 0x2066, 0x206f,
- 0x2071, 0x2071,
- 0x207f, 0x207f,
- 0x2090, 0x209c,
- 0x20d0, 0x20f0,
- 0x2c7c, 0x2c7d,
- 0x2cef, 0x2cf1,
- 0x2d6f, 0x2d6f,
- 0x2d7f, 0x2d7f,
- 0x2de0, 0x2dff,
- 0x2e2f, 0x2e2f,
- 0x3005, 0x3005,
- 0x302a, 0x302d,
- 0x3031, 0x3035,
- 0x303b, 0x303b,
- 0x3099, 0x309e,
- 0x30fc, 0x30fe,
- 0xa015, 0xa015,
- 0xa4f8, 0xa4fd,
- 0xa60c, 0xa60c,
- 0xa66f, 0xa672,
- 0xa674, 0xa67d,
- 0xa67f, 0xa67f,
- 0xa69c, 0xa69f,
- 0xa6f0, 0xa6f1,
- 0xa700, 0xa721,
- 0xa770, 0xa770,
- 0xa788, 0xa78a,
- 0xa7f2, 0xa7f4,
- 0xa7f8, 0xa7f9,
- 0xa802, 0xa802,
- 0xa806, 0xa806,
- 0xa80b, 0xa80b,
- 0xa825, 0xa826,
- 0xa82c, 0xa82c,
- 0xa8c4, 0xa8c5,
- 0xa8e0, 0xa8f1,
- 0xa8ff, 0xa8ff,
- 0xa926, 0xa92d,
- 0xa947, 0xa951,
- 0xa980, 0xa982,
- 0xa9b3, 0xa9b3,
- 0xa9b6, 0xa9b9,
- 0xa9bc, 0xa9bd,
- 0xa9cf, 0xa9cf,
- 0xa9e5, 0xa9e6,
- 0xaa29, 0xaa2e,
- 0xaa31, 0xaa32,
- 0xaa35, 0xaa36,
- 0xaa43, 0xaa43,
- 0xaa4c, 0xaa4c,
- 0xaa70, 0xaa70,
- 0xaa7c, 0xaa7c,
- 0xaab0, 0xaab0,
- 0xaab2, 0xaab4,
- 0xaab7, 0xaab8,
- 0xaabe, 0xaabf,
- 0xaac1, 0xaac1,
- 0xaadd, 0xaadd,
- 0xaaec, 0xaaed,
- 0xaaf3, 0xaaf4,
- 0xaaf6, 0xaaf6,
- 0xab5b, 0xab5f,
- 0xab69, 0xab6b,
- 0xabe5, 0xabe5,
- 0xabe8, 0xabe8,
- 0xabed, 0xabed,
- 0xfb1e, 0xfb1e,
- 0xfbb2, 0xfbc2,
- 0xfe00, 0xfe0f,
- 0xfe13, 0xfe13,
- 0xfe20, 0xfe2f,
- 0xfe52, 0xfe52,
- 0xfe55, 0xfe55,
- 0xfeff, 0xfeff,
- 0xff07, 0xff07,
- 0xff0e, 0xff0e,
- 0xff1a, 0xff1a,
- 0xff3e, 0xff3e,
- 0xff40, 0xff40,
- 0xff70, 0xff70,
- 0xff9e, 0xff9f,
- 0xffe3, 0xffe3,
- 0xfff9, 0xfffb,
- 0x101fd, 0x101fd,
- 0x102e0, 0x102e0,
- 0x10376, 0x1037a,
- 0x10780, 0x10785,
- 0x10787, 0x107b0,
- 0x107b2, 0x107ba,
- 0x10a01, 0x10a03,
- 0x10a05, 0x10a06,
- 0x10a0c, 0x10a0f,
- 0x10a38, 0x10a3a,
- 0x10a3f, 0x10a3f,
- 0x10ae5, 0x10ae6,
- 0x10d24, 0x10d27,
- 0x10d4e, 0x10d4e,
- 0x10d69, 0x10d6d,
- 0x10d6f, 0x10d6f,
- 0x10eab, 0x10eac,
- 0x10efc, 0x10eff,
- 0x10f46, 0x10f50,
- 0x10f82, 0x10f85,
- 0x11001, 0x11001,
- 0x11038, 0x11046,
- 0x11070, 0x11070,
- 0x11073, 0x11074,
- 0x1107f, 0x11081,
- 0x110b3, 0x110b6,
- 0x110b9, 0x110ba,
- 0x110bd, 0x110bd,
- 0x110c2, 0x110c2,
- 0x110cd, 0x110cd,
- 0x11100, 0x11102,
- 0x11127, 0x1112b,
- 0x1112d, 0x11134,
- 0x11173, 0x11173,
- 0x11180, 0x11181,
- 0x111b6, 0x111be,
- 0x111c9, 0x111cc,
- 0x111cf, 0x111cf,
- 0x1122f, 0x11231,
- 0x11234, 0x11234,
- 0x11236, 0x11237,
- 0x1123e, 0x1123e,
- 0x11241, 0x11241,
- 0x112df, 0x112df,
- 0x112e3, 0x112ea,
- 0x11300, 0x11301,
- 0x1133b, 0x1133c,
- 0x11340, 0x11340,
- 0x11366, 0x1136c,
- 0x11370, 0x11374,
- 0x113bb, 0x113c0,
- 0x113ce, 0x113ce,
- 0x113d0, 0x113d0,
- 0x113d2, 0x113d2,
- 0x113e1, 0x113e2,
- 0x11438, 0x1143f,
- 0x11442, 0x11444,
- 0x11446, 0x11446,
- 0x1145e, 0x1145e,
- 0x114b3, 0x114b8,
- 0x114ba, 0x114ba,
- 0x114bf, 0x114c0,
- 0x114c2, 0x114c3,
- 0x115b2, 0x115b5,
- 0x115bc, 0x115bd,
- 0x115bf, 0x115c0,
- 0x115dc, 0x115dd,
- 0x11633, 0x1163a,
- 0x1163d, 0x1163d,
- 0x1163f, 0x11640,
- 0x116ab, 0x116ab,
- 0x116ad, 0x116ad,
- 0x116b0, 0x116b5,
- 0x116b7, 0x116b7,
- 0x1171d, 0x1171d,
- 0x1171f, 0x1171f,
- 0x11722, 0x11725,
- 0x11727, 0x1172b,
- 0x1182f, 0x11837,
- 0x11839, 0x1183a,
- 0x1193b, 0x1193c,
- 0x1193e, 0x1193e,
- 0x11943, 0x11943,
- 0x119d4, 0x119d7,
- 0x119da, 0x119db,
- 0x119e0, 0x119e0,
- 0x11a01, 0x11a0a,
- 0x11a33, 0x11a38,
- 0x11a3b, 0x11a3e,
- 0x11a47, 0x11a47,
- 0x11a51, 0x11a56,
- 0x11a59, 0x11a5b,
- 0x11a8a, 0x11a96,
- 0x11a98, 0x11a99,
- 0x11c30, 0x11c36,
- 0x11c38, 0x11c3d,
- 0x11c3f, 0x11c3f,
- 0x11c92, 0x11ca7,
- 0x11caa, 0x11cb0,
- 0x11cb2, 0x11cb3,
- 0x11cb5, 0x11cb6,
- 0x11d31, 0x11d36,
- 0x11d3a, 0x11d3a,
- 0x11d3c, 0x11d3d,
- 0x11d3f, 0x11d45,
- 0x11d47, 0x11d47,
- 0x11d90, 0x11d91,
- 0x11d95, 0x11d95,
- 0x11d97, 0x11d97,
- 0x11ef3, 0x11ef4,
- 0x11f00, 0x11f01,
- 0x11f36, 0x11f3a,
- 0x11f40, 0x11f40,
- 0x11f42, 0x11f42,
- 0x11f5a, 0x11f5a,
- 0x13430, 0x13440,
- 0x13447, 0x13455,
- 0x1611e, 0x16129,
- 0x1612d, 0x1612f,
- 0x16af0, 0x16af4,
- 0x16b30, 0x16b36,
- 0x16b40, 0x16b43,
- 0x16d40, 0x16d42,
- 0x16d6b, 0x16d6c,
- 0x16f4f, 0x16f4f,
- 0x16f8f, 0x16f9f,
- 0x16fe0, 0x16fe1,
- 0x16fe3, 0x16fe4,
- 0x1aff0, 0x1aff3,
- 0x1aff5, 0x1affb,
- 0x1affd, 0x1affe,
- 0x1bc9d, 0x1bc9e,
- 0x1bca0, 0x1bca3,
- 0x1cf00, 0x1cf2d,
- 0x1cf30, 0x1cf46,
- 0x1d167, 0x1d169,
- 0x1d173, 0x1d182,
- 0x1d185, 0x1d18b,
- 0x1d1aa, 0x1d1ad,
- 0x1d242, 0x1d244,
- 0x1da00, 0x1da36,
- 0x1da3b, 0x1da6c,
- 0x1da75, 0x1da75,
- 0x1da84, 0x1da84,
- 0x1da9b, 0x1da9f,
- 0x1daa1, 0x1daaf,
- 0x1e000, 0x1e006,
- 0x1e008, 0x1e018,
- 0x1e01b, 0x1e021,
- 0x1e023, 0x1e024,
- 0x1e026, 0x1e02a,
- 0x1e030, 0x1e06d,
- 0x1e08f, 0x1e08f,
- 0x1e130, 0x1e13d,
- 0x1e2ae, 0x1e2ae,
- 0x1e2ec, 0x1e2ef,
- 0x1e4eb, 0x1e4ef,
- 0x1e5ee, 0x1e5ef,
- 0x1e8d0, 0x1e8d6,
- 0x1e944, 0x1e94b,
- 0x1f3fb, 0x1f3ff,
- 0xe0001, 0xe0001,
- 0xe0020, 0xe007f,
- 0xe0100, 0xe01ef,
-}; /* CR_Case_Ignorable */
-
-/* 'Changes_When_Lowercased': Derived Property */
-static const OnigCodePoint CR_Changes_When_Lowercased[] = {
- 614,
- 0x0041, 0x005a,
- 0x00c0, 0x00d6,
- 0x00d8, 0x00de,
- 0x0100, 0x0100,
- 0x0102, 0x0102,
- 0x0104, 0x0104,
- 0x0106, 0x0106,
- 0x0108, 0x0108,
- 0x010a, 0x010a,
- 0x010c, 0x010c,
- 0x010e, 0x010e,
- 0x0110, 0x0110,
- 0x0112, 0x0112,
- 0x0114, 0x0114,
- 0x0116, 0x0116,
- 0x0118, 0x0118,
- 0x011a, 0x011a,
- 0x011c, 0x011c,
- 0x011e, 0x011e,
- 0x0120, 0x0120,
- 0x0122, 0x0122,
- 0x0124, 0x0124,
- 0x0126, 0x0126,
- 0x0128, 0x0128,
- 0x012a, 0x012a,
- 0x012c, 0x012c,
- 0x012e, 0x012e,
- 0x0130, 0x0130,
- 0x0132, 0x0132,
- 0x0134, 0x0134,
- 0x0136, 0x0136,
- 0x0139, 0x0139,
- 0x013b, 0x013b,
- 0x013d, 0x013d,
- 0x013f, 0x013f,
- 0x0141, 0x0141,
- 0x0143, 0x0143,
- 0x0145, 0x0145,
- 0x0147, 0x0147,
- 0x014a, 0x014a,
- 0x014c, 0x014c,
- 0x014e, 0x014e,
- 0x0150, 0x0150,
- 0x0152, 0x0152,
- 0x0154, 0x0154,
- 0x0156, 0x0156,
- 0x0158, 0x0158,
- 0x015a, 0x015a,
- 0x015c, 0x015c,
- 0x015e, 0x015e,
- 0x0160, 0x0160,
- 0x0162, 0x0162,
- 0x0164, 0x0164,
- 0x0166, 0x0166,
- 0x0168, 0x0168,
- 0x016a, 0x016a,
- 0x016c, 0x016c,
- 0x016e, 0x016e,
- 0x0170, 0x0170,
- 0x0172, 0x0172,
- 0x0174, 0x0174,
- 0x0176, 0x0176,
- 0x0178, 0x0179,
- 0x017b, 0x017b,
- 0x017d, 0x017d,
- 0x0181, 0x0182,
- 0x0184, 0x0184,
- 0x0186, 0x0187,
- 0x0189, 0x018b,
- 0x018e, 0x0191,
- 0x0193, 0x0194,
- 0x0196, 0x0198,
- 0x019c, 0x019d,
- 0x019f, 0x01a0,
- 0x01a2, 0x01a2,
- 0x01a4, 0x01a4,
- 0x01a6, 0x01a7,
- 0x01a9, 0x01a9,
- 0x01ac, 0x01ac,
- 0x01ae, 0x01af,
- 0x01b1, 0x01b3,
- 0x01b5, 0x01b5,
- 0x01b7, 0x01b8,
- 0x01bc, 0x01bc,
- 0x01c4, 0x01c5,
- 0x01c7, 0x01c8,
- 0x01ca, 0x01cb,
- 0x01cd, 0x01cd,
- 0x01cf, 0x01cf,
- 0x01d1, 0x01d1,
- 0x01d3, 0x01d3,
- 0x01d5, 0x01d5,
- 0x01d7, 0x01d7,
- 0x01d9, 0x01d9,
- 0x01db, 0x01db,
- 0x01de, 0x01de,
- 0x01e0, 0x01e0,
- 0x01e2, 0x01e2,
- 0x01e4, 0x01e4,
- 0x01e6, 0x01e6,
- 0x01e8, 0x01e8,
- 0x01ea, 0x01ea,
- 0x01ec, 0x01ec,
- 0x01ee, 0x01ee,
- 0x01f1, 0x01f2,
- 0x01f4, 0x01f4,
- 0x01f6, 0x01f8,
- 0x01fa, 0x01fa,
- 0x01fc, 0x01fc,
- 0x01fe, 0x01fe,
- 0x0200, 0x0200,
- 0x0202, 0x0202,
- 0x0204, 0x0204,
- 0x0206, 0x0206,
- 0x0208, 0x0208,
- 0x020a, 0x020a,
- 0x020c, 0x020c,
- 0x020e, 0x020e,
- 0x0210, 0x0210,
- 0x0212, 0x0212,
- 0x0214, 0x0214,
- 0x0216, 0x0216,
- 0x0218, 0x0218,
- 0x021a, 0x021a,
- 0x021c, 0x021c,
- 0x021e, 0x021e,
- 0x0220, 0x0220,
- 0x0222, 0x0222,
- 0x0224, 0x0224,
- 0x0226, 0x0226,
- 0x0228, 0x0228,
- 0x022a, 0x022a,
- 0x022c, 0x022c,
- 0x022e, 0x022e,
- 0x0230, 0x0230,
- 0x0232, 0x0232,
- 0x023a, 0x023b,
- 0x023d, 0x023e,
- 0x0241, 0x0241,
- 0x0243, 0x0246,
- 0x0248, 0x0248,
- 0x024a, 0x024a,
- 0x024c, 0x024c,
- 0x024e, 0x024e,
- 0x0370, 0x0370,
- 0x0372, 0x0372,
- 0x0376, 0x0376,
- 0x037f, 0x037f,
- 0x0386, 0x0386,
- 0x0388, 0x038a,
- 0x038c, 0x038c,
- 0x038e, 0x038f,
- 0x0391, 0x03a1,
- 0x03a3, 0x03ab,
- 0x03cf, 0x03cf,
- 0x03d8, 0x03d8,
- 0x03da, 0x03da,
- 0x03dc, 0x03dc,
- 0x03de, 0x03de,
- 0x03e0, 0x03e0,
- 0x03e2, 0x03e2,
- 0x03e4, 0x03e4,
- 0x03e6, 0x03e6,
- 0x03e8, 0x03e8,
- 0x03ea, 0x03ea,
- 0x03ec, 0x03ec,
- 0x03ee, 0x03ee,
- 0x03f4, 0x03f4,
- 0x03f7, 0x03f7,
- 0x03f9, 0x03fa,
- 0x03fd, 0x042f,
- 0x0460, 0x0460,
- 0x0462, 0x0462,
- 0x0464, 0x0464,
- 0x0466, 0x0466,
- 0x0468, 0x0468,
- 0x046a, 0x046a,
- 0x046c, 0x046c,
- 0x046e, 0x046e,
- 0x0470, 0x0470,
- 0x0472, 0x0472,
- 0x0474, 0x0474,
- 0x0476, 0x0476,
- 0x0478, 0x0478,
- 0x047a, 0x047a,
- 0x047c, 0x047c,
- 0x047e, 0x047e,
- 0x0480, 0x0480,
- 0x048a, 0x048a,
- 0x048c, 0x048c,
- 0x048e, 0x048e,
- 0x0490, 0x0490,
- 0x0492, 0x0492,
- 0x0494, 0x0494,
- 0x0496, 0x0496,
- 0x0498, 0x0498,
- 0x049a, 0x049a,
- 0x049c, 0x049c,
- 0x049e, 0x049e,
- 0x04a0, 0x04a0,
- 0x04a2, 0x04a2,
- 0x04a4, 0x04a4,
- 0x04a6, 0x04a6,
- 0x04a8, 0x04a8,
- 0x04aa, 0x04aa,
- 0x04ac, 0x04ac,
- 0x04ae, 0x04ae,
- 0x04b0, 0x04b0,
- 0x04b2, 0x04b2,
- 0x04b4, 0x04b4,
- 0x04b6, 0x04b6,
- 0x04b8, 0x04b8,
- 0x04ba, 0x04ba,
- 0x04bc, 0x04bc,
- 0x04be, 0x04be,
- 0x04c0, 0x04c1,
- 0x04c3, 0x04c3,
- 0x04c5, 0x04c5,
- 0x04c7, 0x04c7,
- 0x04c9, 0x04c9,
- 0x04cb, 0x04cb,
- 0x04cd, 0x04cd,
- 0x04d0, 0x04d0,
- 0x04d2, 0x04d2,
- 0x04d4, 0x04d4,
- 0x04d6, 0x04d6,
- 0x04d8, 0x04d8,
- 0x04da, 0x04da,
- 0x04dc, 0x04dc,
- 0x04de, 0x04de,
- 0x04e0, 0x04e0,
- 0x04e2, 0x04e2,
- 0x04e4, 0x04e4,
- 0x04e6, 0x04e6,
- 0x04e8, 0x04e8,
- 0x04ea, 0x04ea,
- 0x04ec, 0x04ec,
- 0x04ee, 0x04ee,
- 0x04f0, 0x04f0,
- 0x04f2, 0x04f2,
- 0x04f4, 0x04f4,
- 0x04f6, 0x04f6,
- 0x04f8, 0x04f8,
- 0x04fa, 0x04fa,
- 0x04fc, 0x04fc,
- 0x04fe, 0x04fe,
- 0x0500, 0x0500,
- 0x0502, 0x0502,
- 0x0504, 0x0504,
- 0x0506, 0x0506,
- 0x0508, 0x0508,
- 0x050a, 0x050a,
- 0x050c, 0x050c,
- 0x050e, 0x050e,
- 0x0510, 0x0510,
- 0x0512, 0x0512,
- 0x0514, 0x0514,
- 0x0516, 0x0516,
- 0x0518, 0x0518,
- 0x051a, 0x051a,
- 0x051c, 0x051c,
- 0x051e, 0x051e,
- 0x0520, 0x0520,
- 0x0522, 0x0522,
- 0x0524, 0x0524,
- 0x0526, 0x0526,
- 0x0528, 0x0528,
- 0x052a, 0x052a,
- 0x052c, 0x052c,
- 0x052e, 0x052e,
- 0x0531, 0x0556,
- 0x10a0, 0x10c5,
- 0x10c7, 0x10c7,
- 0x10cd, 0x10cd,
- 0x13a0, 0x13f5,
- 0x1c89, 0x1c89,
- 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,
- 0x2126, 0x2126,
- 0x212a, 0x212b,
- 0x2132, 0x2132,
- 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,
- 0xa7cb, 0xa7cc,
- 0xa7d0, 0xa7d0,
- 0xa7d6, 0xa7d6,
- 0xa7d8, 0xa7d8,
- 0xa7da, 0xa7da,
- 0xa7dc, 0xa7dc,
- 0xa7f5, 0xa7f5,
- 0xff21, 0xff3a,
- 0x10400, 0x10427,
- 0x104b0, 0x104d3,
- 0x10570, 0x1057a,
- 0x1057c, 0x1058a,
- 0x1058c, 0x10592,
- 0x10594, 0x10595,
- 0x10c80, 0x10cb2,
- 0x10d50, 0x10d65,
- 0x118a0, 0x118bf,
- 0x16e40, 0x16e5f,
- 0x1e900, 0x1e921,
-}; /* CR_Changes_When_Lowercased */
-
-/* 'Changes_When_Uppercased': Derived Property */
-static const OnigCodePoint CR_Changes_When_Uppercased[] = {
- 630,
- 0x0061, 0x007a,
- 0x00b5, 0x00b5,
- 0x00df, 0x00f6,
- 0x00f8, 0x00ff,
- 0x0101, 0x0101,
- 0x0103, 0x0103,
- 0x0105, 0x0105,
- 0x0107, 0x0107,
- 0x0109, 0x0109,
- 0x010b, 0x010b,
- 0x010d, 0x010d,
- 0x010f, 0x010f,
- 0x0111, 0x0111,
- 0x0113, 0x0113,
- 0x0115, 0x0115,
- 0x0117, 0x0117,
- 0x0119, 0x0119,
- 0x011b, 0x011b,
- 0x011d, 0x011d,
- 0x011f, 0x011f,
- 0x0121, 0x0121,
- 0x0123, 0x0123,
- 0x0125, 0x0125,
- 0x0127, 0x0127,
- 0x0129, 0x0129,
- 0x012b, 0x012b,
- 0x012d, 0x012d,
- 0x012f, 0x012f,
- 0x0131, 0x0131,
- 0x0133, 0x0133,
- 0x0135, 0x0135,
- 0x0137, 0x0137,
- 0x013a, 0x013a,
- 0x013c, 0x013c,
- 0x013e, 0x013e,
- 0x0140, 0x0140,
- 0x0142, 0x0142,
- 0x0144, 0x0144,
- 0x0146, 0x0146,
- 0x0148, 0x0149,
- 0x014b, 0x014b,
- 0x014d, 0x014d,
- 0x014f, 0x014f,
- 0x0151, 0x0151,
- 0x0153, 0x0153,
- 0x0155, 0x0155,
- 0x0157, 0x0157,
- 0x0159, 0x0159,
- 0x015b, 0x015b,
- 0x015d, 0x015d,
- 0x015f, 0x015f,
- 0x0161, 0x0161,
- 0x0163, 0x0163,
- 0x0165, 0x0165,
- 0x0167, 0x0167,
- 0x0169, 0x0169,
- 0x016b, 0x016b,
- 0x016d, 0x016d,
- 0x016f, 0x016f,
- 0x0171, 0x0171,
- 0x0173, 0x0173,
- 0x0175, 0x0175,
- 0x0177, 0x0177,
- 0x017a, 0x017a,
- 0x017c, 0x017c,
- 0x017e, 0x0180,
- 0x0183, 0x0183,
- 0x0185, 0x0185,
- 0x0188, 0x0188,
- 0x018c, 0x018c,
- 0x0192, 0x0192,
- 0x0195, 0x0195,
- 0x0199, 0x019b,
- 0x019e, 0x019e,
- 0x01a1, 0x01a1,
- 0x01a3, 0x01a3,
- 0x01a5, 0x01a5,
- 0x01a8, 0x01a8,
- 0x01ad, 0x01ad,
- 0x01b0, 0x01b0,
- 0x01b4, 0x01b4,
- 0x01b6, 0x01b6,
- 0x01b9, 0x01b9,
- 0x01bd, 0x01bd,
- 0x01bf, 0x01bf,
- 0x01c5, 0x01c6,
- 0x01c8, 0x01c9,
- 0x01cb, 0x01cc,
- 0x01ce, 0x01ce,
- 0x01d0, 0x01d0,
- 0x01d2, 0x01d2,
- 0x01d4, 0x01d4,
- 0x01d6, 0x01d6,
- 0x01d8, 0x01d8,
- 0x01da, 0x01da,
- 0x01dc, 0x01dd,
- 0x01df, 0x01df,
- 0x01e1, 0x01e1,
- 0x01e3, 0x01e3,
- 0x01e5, 0x01e5,
- 0x01e7, 0x01e7,
- 0x01e9, 0x01e9,
- 0x01eb, 0x01eb,
- 0x01ed, 0x01ed,
- 0x01ef, 0x01f0,
- 0x01f2, 0x01f3,
- 0x01f5, 0x01f5,
- 0x01f9, 0x01f9,
- 0x01fb, 0x01fb,
- 0x01fd, 0x01fd,
- 0x01ff, 0x01ff,
- 0x0201, 0x0201,
- 0x0203, 0x0203,
- 0x0205, 0x0205,
- 0x0207, 0x0207,
- 0x0209, 0x0209,
- 0x020b, 0x020b,
- 0x020d, 0x020d,
- 0x020f, 0x020f,
- 0x0211, 0x0211,
- 0x0213, 0x0213,
- 0x0215, 0x0215,
- 0x0217, 0x0217,
- 0x0219, 0x0219,
- 0x021b, 0x021b,
- 0x021d, 0x021d,
- 0x021f, 0x021f,
- 0x0223, 0x0223,
- 0x0225, 0x0225,
- 0x0227, 0x0227,
- 0x0229, 0x0229,
- 0x022b, 0x022b,
- 0x022d, 0x022d,
- 0x022f, 0x022f,
- 0x0231, 0x0231,
- 0x0233, 0x0233,
- 0x023c, 0x023c,
- 0x023f, 0x0240,
- 0x0242, 0x0242,
- 0x0247, 0x0247,
- 0x0249, 0x0249,
- 0x024b, 0x024b,
- 0x024d, 0x024d,
- 0x024f, 0x0254,
- 0x0256, 0x0257,
- 0x0259, 0x0259,
- 0x025b, 0x025c,
- 0x0260, 0x0261,
- 0x0263, 0x0266,
- 0x0268, 0x026c,
- 0x026f, 0x026f,
- 0x0271, 0x0272,
- 0x0275, 0x0275,
- 0x027d, 0x027d,
- 0x0280, 0x0280,
- 0x0282, 0x0283,
- 0x0287, 0x028c,
- 0x0292, 0x0292,
- 0x029d, 0x029e,
- 0x0345, 0x0345,
- 0x0371, 0x0371,
- 0x0373, 0x0373,
- 0x0377, 0x0377,
- 0x037b, 0x037d,
- 0x0390, 0x0390,
- 0x03ac, 0x03ce,
- 0x03d0, 0x03d1,
- 0x03d5, 0x03d7,
- 0x03d9, 0x03d9,
- 0x03db, 0x03db,
- 0x03dd, 0x03dd,
- 0x03df, 0x03df,
- 0x03e1, 0x03e1,
- 0x03e3, 0x03e3,
- 0x03e5, 0x03e5,
- 0x03e7, 0x03e7,
- 0x03e9, 0x03e9,
- 0x03eb, 0x03eb,
- 0x03ed, 0x03ed,
- 0x03ef, 0x03f3,
- 0x03f5, 0x03f5,
- 0x03f8, 0x03f8,
- 0x03fb, 0x03fb,
- 0x0430, 0x045f,
- 0x0461, 0x0461,
- 0x0463, 0x0463,
- 0x0465, 0x0465,
- 0x0467, 0x0467,
- 0x0469, 0x0469,
- 0x046b, 0x046b,
- 0x046d, 0x046d,
- 0x046f, 0x046f,
- 0x0471, 0x0471,
- 0x0473, 0x0473,
- 0x0475, 0x0475,
- 0x0477, 0x0477,
- 0x0479, 0x0479,
- 0x047b, 0x047b,
- 0x047d, 0x047d,
- 0x047f, 0x047f,
- 0x0481, 0x0481,
- 0x048b, 0x048b,
- 0x048d, 0x048d,
- 0x048f, 0x048f,
- 0x0491, 0x0491,
- 0x0493, 0x0493,
- 0x0495, 0x0495,
- 0x0497, 0x0497,
- 0x0499, 0x0499,
- 0x049b, 0x049b,
- 0x049d, 0x049d,
- 0x049f, 0x049f,
- 0x04a1, 0x04a1,
- 0x04a3, 0x04a3,
- 0x04a5, 0x04a5,
- 0x04a7, 0x04a7,
- 0x04a9, 0x04a9,
- 0x04ab, 0x04ab,
- 0x04ad, 0x04ad,
- 0x04af, 0x04af,
- 0x04b1, 0x04b1,
- 0x04b3, 0x04b3,
- 0x04b5, 0x04b5,
- 0x04b7, 0x04b7,
- 0x04b9, 0x04b9,
- 0x04bb, 0x04bb,
- 0x04bd, 0x04bd,
- 0x04bf, 0x04bf,
- 0x04c2, 0x04c2,
- 0x04c4, 0x04c4,
- 0x04c6, 0x04c6,
- 0x04c8, 0x04c8,
- 0x04ca, 0x04ca,
- 0x04cc, 0x04cc,
- 0x04ce, 0x04cf,
- 0x04d1, 0x04d1,
- 0x04d3, 0x04d3,
- 0x04d5, 0x04d5,
- 0x04d7, 0x04d7,
- 0x04d9, 0x04d9,
- 0x04db, 0x04db,
- 0x04dd, 0x04dd,
- 0x04df, 0x04df,
- 0x04e1, 0x04e1,
- 0x04e3, 0x04e3,
- 0x04e5, 0x04e5,
- 0x04e7, 0x04e7,
- 0x04e9, 0x04e9,
- 0x04eb, 0x04eb,
- 0x04ed, 0x04ed,
- 0x04ef, 0x04ef,
- 0x04f1, 0x04f1,
- 0x04f3, 0x04f3,
- 0x04f5, 0x04f5,
- 0x04f7, 0x04f7,
- 0x04f9, 0x04f9,
- 0x04fb, 0x04fb,
- 0x04fd, 0x04fd,
- 0x04ff, 0x04ff,
- 0x0501, 0x0501,
- 0x0503, 0x0503,
- 0x0505, 0x0505,
- 0x0507, 0x0507,
- 0x0509, 0x0509,
- 0x050b, 0x050b,
- 0x050d, 0x050d,
- 0x050f, 0x050f,
- 0x0511, 0x0511,
- 0x0513, 0x0513,
- 0x0515, 0x0515,
- 0x0517, 0x0517,
- 0x0519, 0x0519,
- 0x051b, 0x051b,
- 0x051d, 0x051d,
- 0x051f, 0x051f,
- 0x0521, 0x0521,
- 0x0523, 0x0523,
- 0x0525, 0x0525,
- 0x0527, 0x0527,
- 0x0529, 0x0529,
- 0x052b, 0x052b,
- 0x052d, 0x052d,
- 0x052f, 0x052f,
- 0x0561, 0x0587,
- 0x10d0, 0x10fa,
- 0x10fd, 0x10ff,
- 0x13f8, 0x13fd,
- 0x1c80, 0x1c88,
- 0x1c8a, 0x1c8a,
- 0x1d79, 0x1d79,
- 0x1d7d, 0x1d7d,
- 0x1d8e, 0x1d8e,
- 0x1e01, 0x1e01,
- 0x1e03, 0x1e03,
- 0x1e05, 0x1e05,
- 0x1e07, 0x1e07,
- 0x1e09, 0x1e09,
- 0x1e0b, 0x1e0b,
- 0x1e0d, 0x1e0d,
- 0x1e0f, 0x1e0f,
- 0x1e11, 0x1e11,
- 0x1e13, 0x1e13,
- 0x1e15, 0x1e15,
- 0x1e17, 0x1e17,
- 0x1e19, 0x1e19,
- 0x1e1b, 0x1e1b,
- 0x1e1d, 0x1e1d,
- 0x1e1f, 0x1e1f,
- 0x1e21, 0x1e21,
- 0x1e23, 0x1e23,
- 0x1e25, 0x1e25,
- 0x1e27, 0x1e27,
- 0x1e29, 0x1e29,
- 0x1e2b, 0x1e2b,
- 0x1e2d, 0x1e2d,
- 0x1e2f, 0x1e2f,
- 0x1e31, 0x1e31,
- 0x1e33, 0x1e33,
- 0x1e35, 0x1e35,
- 0x1e37, 0x1e37,
- 0x1e39, 0x1e39,
- 0x1e3b, 0x1e3b,
- 0x1e3d, 0x1e3d,
- 0x1e3f, 0x1e3f,
- 0x1e41, 0x1e41,
- 0x1e43, 0x1e43,
- 0x1e45, 0x1e45,
- 0x1e47, 0x1e47,
- 0x1e49, 0x1e49,
- 0x1e4b, 0x1e4b,
- 0x1e4d, 0x1e4d,
- 0x1e4f, 0x1e4f,
- 0x1e51, 0x1e51,
- 0x1e53, 0x1e53,
- 0x1e55, 0x1e55,
- 0x1e57, 0x1e57,
- 0x1e59, 0x1e59,
- 0x1e5b, 0x1e5b,
- 0x1e5d, 0x1e5d,
- 0x1e5f, 0x1e5f,
- 0x1e61, 0x1e61,
- 0x1e63, 0x1e63,
- 0x1e65, 0x1e65,
- 0x1e67, 0x1e67,
- 0x1e69, 0x1e69,
- 0x1e6b, 0x1e6b,
- 0x1e6d, 0x1e6d,
- 0x1e6f, 0x1e6f,
- 0x1e71, 0x1e71,
- 0x1e73, 0x1e73,
- 0x1e75, 0x1e75,
- 0x1e77, 0x1e77,
- 0x1e79, 0x1e79,
- 0x1e7b, 0x1e7b,
- 0x1e7d, 0x1e7d,
- 0x1e7f, 0x1e7f,
- 0x1e81, 0x1e81,
- 0x1e83, 0x1e83,
- 0x1e85, 0x1e85,
- 0x1e87, 0x1e87,
- 0x1e89, 0x1e89,
- 0x1e8b, 0x1e8b,
- 0x1e8d, 0x1e8d,
- 0x1e8f, 0x1e8f,
- 0x1e91, 0x1e91,
- 0x1e93, 0x1e93,
- 0x1e95, 0x1e9b,
- 0x1ea1, 0x1ea1,
- 0x1ea3, 0x1ea3,
- 0x1ea5, 0x1ea5,
- 0x1ea7, 0x1ea7,
- 0x1ea9, 0x1ea9,
- 0x1eab, 0x1eab,
- 0x1ead, 0x1ead,
- 0x1eaf, 0x1eaf,
- 0x1eb1, 0x1eb1,
- 0x1eb3, 0x1eb3,
- 0x1eb5, 0x1eb5,
- 0x1eb7, 0x1eb7,
- 0x1eb9, 0x1eb9,
- 0x1ebb, 0x1ebb,
- 0x1ebd, 0x1ebd,
- 0x1ebf, 0x1ebf,
- 0x1ec1, 0x1ec1,
- 0x1ec3, 0x1ec3,
- 0x1ec5, 0x1ec5,
- 0x1ec7, 0x1ec7,
- 0x1ec9, 0x1ec9,
- 0x1ecb, 0x1ecb,
- 0x1ecd, 0x1ecd,
- 0x1ecf, 0x1ecf,
- 0x1ed1, 0x1ed1,
- 0x1ed3, 0x1ed3,
- 0x1ed5, 0x1ed5,
- 0x1ed7, 0x1ed7,
- 0x1ed9, 0x1ed9,
- 0x1edb, 0x1edb,
- 0x1edd, 0x1edd,
- 0x1edf, 0x1edf,
- 0x1ee1, 0x1ee1,
- 0x1ee3, 0x1ee3,
- 0x1ee5, 0x1ee5,
- 0x1ee7, 0x1ee7,
- 0x1ee9, 0x1ee9,
- 0x1eeb, 0x1eeb,
- 0x1eed, 0x1eed,
- 0x1eef, 0x1eef,
- 0x1ef1, 0x1ef1,
- 0x1ef3, 0x1ef3,
- 0x1ef5, 0x1ef5,
- 0x1ef7, 0x1ef7,
- 0x1ef9, 0x1ef9,
- 0x1efb, 0x1efb,
- 0x1efd, 0x1efd,
- 0x1eff, 0x1f07,
- 0x1f10, 0x1f15,
- 0x1f20, 0x1f27,
- 0x1f30, 0x1f37,
- 0x1f40, 0x1f45,
- 0x1f50, 0x1f57,
- 0x1f60, 0x1f67,
- 0x1f70, 0x1f7d,
- 0x1f80, 0x1fb4,
- 0x1fb6, 0x1fb7,
- 0x1fbc, 0x1fbc,
- 0x1fbe, 0x1fbe,
- 0x1fc2, 0x1fc4,
- 0x1fc6, 0x1fc7,
- 0x1fcc, 0x1fcc,
- 0x1fd0, 0x1fd3,
- 0x1fd6, 0x1fd7,
- 0x1fe0, 0x1fe7,
- 0x1ff2, 0x1ff4,
- 0x1ff6, 0x1ff7,
- 0x1ffc, 0x1ffc,
- 0x214e, 0x214e,
- 0x2170, 0x217f,
- 0x2184, 0x2184,
- 0x24d0, 0x24e9,
- 0x2c30, 0x2c5f,
- 0x2c61, 0x2c61,
- 0x2c65, 0x2c66,
- 0x2c68, 0x2c68,
- 0x2c6a, 0x2c6a,
- 0x2c6c, 0x2c6c,
- 0x2c73, 0x2c73,
- 0x2c76, 0x2c76,
- 0x2c81, 0x2c81,
- 0x2c83, 0x2c83,
- 0x2c85, 0x2c85,
- 0x2c87, 0x2c87,
- 0x2c89, 0x2c89,
- 0x2c8b, 0x2c8b,
- 0x2c8d, 0x2c8d,
- 0x2c8f, 0x2c8f,
- 0x2c91, 0x2c91,
- 0x2c93, 0x2c93,
- 0x2c95, 0x2c95,
- 0x2c97, 0x2c97,
- 0x2c99, 0x2c99,
- 0x2c9b, 0x2c9b,
- 0x2c9d, 0x2c9d,
- 0x2c9f, 0x2c9f,
- 0x2ca1, 0x2ca1,
- 0x2ca3, 0x2ca3,
- 0x2ca5, 0x2ca5,
- 0x2ca7, 0x2ca7,
- 0x2ca9, 0x2ca9,
- 0x2cab, 0x2cab,
- 0x2cad, 0x2cad,
- 0x2caf, 0x2caf,
- 0x2cb1, 0x2cb1,
- 0x2cb3, 0x2cb3,
- 0x2cb5, 0x2cb5,
- 0x2cb7, 0x2cb7,
- 0x2cb9, 0x2cb9,
- 0x2cbb, 0x2cbb,
- 0x2cbd, 0x2cbd,
- 0x2cbf, 0x2cbf,
- 0x2cc1, 0x2cc1,
- 0x2cc3, 0x2cc3,
- 0x2cc5, 0x2cc5,
- 0x2cc7, 0x2cc7,
- 0x2cc9, 0x2cc9,
- 0x2ccb, 0x2ccb,
- 0x2ccd, 0x2ccd,
- 0x2ccf, 0x2ccf,
- 0x2cd1, 0x2cd1,
- 0x2cd3, 0x2cd3,
- 0x2cd5, 0x2cd5,
- 0x2cd7, 0x2cd7,
- 0x2cd9, 0x2cd9,
- 0x2cdb, 0x2cdb,
- 0x2cdd, 0x2cdd,
- 0x2cdf, 0x2cdf,
- 0x2ce1, 0x2ce1,
- 0x2ce3, 0x2ce3,
- 0x2cec, 0x2cec,
- 0x2cee, 0x2cee,
- 0x2cf3, 0x2cf3,
- 0x2d00, 0x2d25,
- 0x2d27, 0x2d27,
- 0x2d2d, 0x2d2d,
- 0xa641, 0xa641,
- 0xa643, 0xa643,
- 0xa645, 0xa645,
- 0xa647, 0xa647,
- 0xa649, 0xa649,
- 0xa64b, 0xa64b,
- 0xa64d, 0xa64d,
- 0xa64f, 0xa64f,
- 0xa651, 0xa651,
- 0xa653, 0xa653,
- 0xa655, 0xa655,
- 0xa657, 0xa657,
- 0xa659, 0xa659,
- 0xa65b, 0xa65b,
- 0xa65d, 0xa65d,
- 0xa65f, 0xa65f,
- 0xa661, 0xa661,
- 0xa663, 0xa663,
- 0xa665, 0xa665,
- 0xa667, 0xa667,
- 0xa669, 0xa669,
- 0xa66b, 0xa66b,
- 0xa66d, 0xa66d,
- 0xa681, 0xa681,
- 0xa683, 0xa683,
- 0xa685, 0xa685,
- 0xa687, 0xa687,
- 0xa689, 0xa689,
- 0xa68b, 0xa68b,
- 0xa68d, 0xa68d,
- 0xa68f, 0xa68f,
- 0xa691, 0xa691,
- 0xa693, 0xa693,
- 0xa695, 0xa695,
- 0xa697, 0xa697,
- 0xa699, 0xa699,
- 0xa69b, 0xa69b,
- 0xa723, 0xa723,
- 0xa725, 0xa725,
- 0xa727, 0xa727,
- 0xa729, 0xa729,
- 0xa72b, 0xa72b,
- 0xa72d, 0xa72d,
- 0xa72f, 0xa72f,
- 0xa733, 0xa733,
- 0xa735, 0xa735,
- 0xa737, 0xa737,
- 0xa739, 0xa739,
- 0xa73b, 0xa73b,
- 0xa73d, 0xa73d,
- 0xa73f, 0xa73f,
- 0xa741, 0xa741,
- 0xa743, 0xa743,
- 0xa745, 0xa745,
- 0xa747, 0xa747,
- 0xa749, 0xa749,
- 0xa74b, 0xa74b,
- 0xa74d, 0xa74d,
- 0xa74f, 0xa74f,
- 0xa751, 0xa751,
- 0xa753, 0xa753,
- 0xa755, 0xa755,
- 0xa757, 0xa757,
- 0xa759, 0xa759,
- 0xa75b, 0xa75b,
- 0xa75d, 0xa75d,
- 0xa75f, 0xa75f,
- 0xa761, 0xa761,
- 0xa763, 0xa763,
- 0xa765, 0xa765,
- 0xa767, 0xa767,
- 0xa769, 0xa769,
- 0xa76b, 0xa76b,
- 0xa76d, 0xa76d,
- 0xa76f, 0xa76f,
- 0xa77a, 0xa77a,
- 0xa77c, 0xa77c,
- 0xa77f, 0xa77f,
- 0xa781, 0xa781,
- 0xa783, 0xa783,
- 0xa785, 0xa785,
- 0xa787, 0xa787,
- 0xa78c, 0xa78c,
- 0xa791, 0xa791,
- 0xa793, 0xa794,
- 0xa797, 0xa797,
- 0xa799, 0xa799,
- 0xa79b, 0xa79b,
- 0xa79d, 0xa79d,
- 0xa79f, 0xa79f,
- 0xa7a1, 0xa7a1,
- 0xa7a3, 0xa7a3,
- 0xa7a5, 0xa7a5,
- 0xa7a7, 0xa7a7,
- 0xa7a9, 0xa7a9,
- 0xa7b5, 0xa7b5,
- 0xa7b7, 0xa7b7,
- 0xa7b9, 0xa7b9,
- 0xa7bb, 0xa7bb,
- 0xa7bd, 0xa7bd,
- 0xa7bf, 0xa7bf,
- 0xa7c1, 0xa7c1,
- 0xa7c3, 0xa7c3,
- 0xa7c8, 0xa7c8,
- 0xa7ca, 0xa7ca,
- 0xa7cd, 0xa7cd,
- 0xa7d1, 0xa7d1,
- 0xa7d7, 0xa7d7,
- 0xa7d9, 0xa7d9,
- 0xa7db, 0xa7db,
- 0xa7f6, 0xa7f6,
- 0xab53, 0xab53,
- 0xab70, 0xabbf,
- 0xfb00, 0xfb06,
- 0xfb13, 0xfb17,
- 0xff41, 0xff5a,
- 0x10428, 0x1044f,
- 0x104d8, 0x104fb,
- 0x10597, 0x105a1,
- 0x105a3, 0x105b1,
- 0x105b3, 0x105b9,
- 0x105bb, 0x105bc,
- 0x10cc0, 0x10cf2,
- 0x10d70, 0x10d85,
- 0x118c0, 0x118df,
- 0x16e60, 0x16e7f,
- 0x1e922, 0x1e943,
-}; /* CR_Changes_When_Uppercased */
-
-/* 'Changes_When_Titlecased': Derived Property */
-static const OnigCodePoint CR_Changes_When_Titlecased[] = {
- 629,
- 0x0061, 0x007a,
- 0x00b5, 0x00b5,
- 0x00df, 0x00f6,
- 0x00f8, 0x00ff,
- 0x0101, 0x0101,
- 0x0103, 0x0103,
- 0x0105, 0x0105,
- 0x0107, 0x0107,
- 0x0109, 0x0109,
- 0x010b, 0x010b,
- 0x010d, 0x010d,
- 0x010f, 0x010f,
- 0x0111, 0x0111,
- 0x0113, 0x0113,
- 0x0115, 0x0115,
- 0x0117, 0x0117,
- 0x0119, 0x0119,
- 0x011b, 0x011b,
- 0x011d, 0x011d,
- 0x011f, 0x011f,
- 0x0121, 0x0121,
- 0x0123, 0x0123,
- 0x0125, 0x0125,
- 0x0127, 0x0127,
- 0x0129, 0x0129,
- 0x012b, 0x012b,
- 0x012d, 0x012d,
- 0x012f, 0x012f,
- 0x0131, 0x0131,
- 0x0133, 0x0133,
- 0x0135, 0x0135,
- 0x0137, 0x0137,
- 0x013a, 0x013a,
- 0x013c, 0x013c,
- 0x013e, 0x013e,
- 0x0140, 0x0140,
- 0x0142, 0x0142,
- 0x0144, 0x0144,
- 0x0146, 0x0146,
- 0x0148, 0x0149,
- 0x014b, 0x014b,
- 0x014d, 0x014d,
- 0x014f, 0x014f,
- 0x0151, 0x0151,
- 0x0153, 0x0153,
- 0x0155, 0x0155,
- 0x0157, 0x0157,
- 0x0159, 0x0159,
- 0x015b, 0x015b,
- 0x015d, 0x015d,
- 0x015f, 0x015f,
- 0x0161, 0x0161,
- 0x0163, 0x0163,
- 0x0165, 0x0165,
- 0x0167, 0x0167,
- 0x0169, 0x0169,
- 0x016b, 0x016b,
- 0x016d, 0x016d,
- 0x016f, 0x016f,
- 0x0171, 0x0171,
- 0x0173, 0x0173,
- 0x0175, 0x0175,
- 0x0177, 0x0177,
- 0x017a, 0x017a,
- 0x017c, 0x017c,
- 0x017e, 0x0180,
- 0x0183, 0x0183,
- 0x0185, 0x0185,
- 0x0188, 0x0188,
- 0x018c, 0x018c,
- 0x0192, 0x0192,
- 0x0195, 0x0195,
- 0x0199, 0x019b,
- 0x019e, 0x019e,
- 0x01a1, 0x01a1,
- 0x01a3, 0x01a3,
- 0x01a5, 0x01a5,
- 0x01a8, 0x01a8,
- 0x01ad, 0x01ad,
- 0x01b0, 0x01b0,
- 0x01b4, 0x01b4,
- 0x01b6, 0x01b6,
- 0x01b9, 0x01b9,
- 0x01bd, 0x01bd,
- 0x01bf, 0x01bf,
- 0x01c4, 0x01c4,
- 0x01c6, 0x01c7,
- 0x01c9, 0x01ca,
- 0x01cc, 0x01cc,
- 0x01ce, 0x01ce,
- 0x01d0, 0x01d0,
- 0x01d2, 0x01d2,
- 0x01d4, 0x01d4,
- 0x01d6, 0x01d6,
- 0x01d8, 0x01d8,
- 0x01da, 0x01da,
- 0x01dc, 0x01dd,
- 0x01df, 0x01df,
- 0x01e1, 0x01e1,
- 0x01e3, 0x01e3,
- 0x01e5, 0x01e5,
- 0x01e7, 0x01e7,
- 0x01e9, 0x01e9,
- 0x01eb, 0x01eb,
- 0x01ed, 0x01ed,
- 0x01ef, 0x01f1,
- 0x01f3, 0x01f3,
- 0x01f5, 0x01f5,
- 0x01f9, 0x01f9,
- 0x01fb, 0x01fb,
- 0x01fd, 0x01fd,
- 0x01ff, 0x01ff,
- 0x0201, 0x0201,
- 0x0203, 0x0203,
- 0x0205, 0x0205,
- 0x0207, 0x0207,
- 0x0209, 0x0209,
- 0x020b, 0x020b,
- 0x020d, 0x020d,
- 0x020f, 0x020f,
- 0x0211, 0x0211,
- 0x0213, 0x0213,
- 0x0215, 0x0215,
- 0x0217, 0x0217,
- 0x0219, 0x0219,
- 0x021b, 0x021b,
- 0x021d, 0x021d,
- 0x021f, 0x021f,
- 0x0223, 0x0223,
- 0x0225, 0x0225,
- 0x0227, 0x0227,
- 0x0229, 0x0229,
- 0x022b, 0x022b,
- 0x022d, 0x022d,
- 0x022f, 0x022f,
- 0x0231, 0x0231,
- 0x0233, 0x0233,
- 0x023c, 0x023c,
- 0x023f, 0x0240,
- 0x0242, 0x0242,
- 0x0247, 0x0247,
- 0x0249, 0x0249,
- 0x024b, 0x024b,
- 0x024d, 0x024d,
- 0x024f, 0x0254,
- 0x0256, 0x0257,
- 0x0259, 0x0259,
- 0x025b, 0x025c,
- 0x0260, 0x0261,
- 0x0263, 0x0266,
- 0x0268, 0x026c,
- 0x026f, 0x026f,
- 0x0271, 0x0272,
- 0x0275, 0x0275,
- 0x027d, 0x027d,
- 0x0280, 0x0280,
- 0x0282, 0x0283,
- 0x0287, 0x028c,
- 0x0292, 0x0292,
- 0x029d, 0x029e,
- 0x0345, 0x0345,
- 0x0371, 0x0371,
- 0x0373, 0x0373,
- 0x0377, 0x0377,
- 0x037b, 0x037d,
- 0x0390, 0x0390,
- 0x03ac, 0x03ce,
- 0x03d0, 0x03d1,
- 0x03d5, 0x03d7,
- 0x03d9, 0x03d9,
- 0x03db, 0x03db,
- 0x03dd, 0x03dd,
- 0x03df, 0x03df,
- 0x03e1, 0x03e1,
- 0x03e3, 0x03e3,
- 0x03e5, 0x03e5,
- 0x03e7, 0x03e7,
- 0x03e9, 0x03e9,
- 0x03eb, 0x03eb,
- 0x03ed, 0x03ed,
- 0x03ef, 0x03f3,
- 0x03f5, 0x03f5,
- 0x03f8, 0x03f8,
- 0x03fb, 0x03fb,
- 0x0430, 0x045f,
- 0x0461, 0x0461,
- 0x0463, 0x0463,
- 0x0465, 0x0465,
- 0x0467, 0x0467,
- 0x0469, 0x0469,
- 0x046b, 0x046b,
- 0x046d, 0x046d,
- 0x046f, 0x046f,
- 0x0471, 0x0471,
- 0x0473, 0x0473,
- 0x0475, 0x0475,
- 0x0477, 0x0477,
- 0x0479, 0x0479,
- 0x047b, 0x047b,
- 0x047d, 0x047d,
- 0x047f, 0x047f,
- 0x0481, 0x0481,
- 0x048b, 0x048b,
- 0x048d, 0x048d,
- 0x048f, 0x048f,
- 0x0491, 0x0491,
- 0x0493, 0x0493,
- 0x0495, 0x0495,
- 0x0497, 0x0497,
- 0x0499, 0x0499,
- 0x049b, 0x049b,
- 0x049d, 0x049d,
- 0x049f, 0x049f,
- 0x04a1, 0x04a1,
- 0x04a3, 0x04a3,
- 0x04a5, 0x04a5,
- 0x04a7, 0x04a7,
- 0x04a9, 0x04a9,
- 0x04ab, 0x04ab,
- 0x04ad, 0x04ad,
- 0x04af, 0x04af,
- 0x04b1, 0x04b1,
- 0x04b3, 0x04b3,
- 0x04b5, 0x04b5,
- 0x04b7, 0x04b7,
- 0x04b9, 0x04b9,
- 0x04bb, 0x04bb,
- 0x04bd, 0x04bd,
- 0x04bf, 0x04bf,
- 0x04c2, 0x04c2,
- 0x04c4, 0x04c4,
- 0x04c6, 0x04c6,
- 0x04c8, 0x04c8,
- 0x04ca, 0x04ca,
- 0x04cc, 0x04cc,
- 0x04ce, 0x04cf,
- 0x04d1, 0x04d1,
- 0x04d3, 0x04d3,
- 0x04d5, 0x04d5,
- 0x04d7, 0x04d7,
- 0x04d9, 0x04d9,
- 0x04db, 0x04db,
- 0x04dd, 0x04dd,
- 0x04df, 0x04df,
- 0x04e1, 0x04e1,
- 0x04e3, 0x04e3,
- 0x04e5, 0x04e5,
- 0x04e7, 0x04e7,
- 0x04e9, 0x04e9,
- 0x04eb, 0x04eb,
- 0x04ed, 0x04ed,
- 0x04ef, 0x04ef,
- 0x04f1, 0x04f1,
- 0x04f3, 0x04f3,
- 0x04f5, 0x04f5,
- 0x04f7, 0x04f7,
- 0x04f9, 0x04f9,
- 0x04fb, 0x04fb,
- 0x04fd, 0x04fd,
- 0x04ff, 0x04ff,
- 0x0501, 0x0501,
- 0x0503, 0x0503,
- 0x0505, 0x0505,
- 0x0507, 0x0507,
- 0x0509, 0x0509,
- 0x050b, 0x050b,
- 0x050d, 0x050d,
- 0x050f, 0x050f,
- 0x0511, 0x0511,
- 0x0513, 0x0513,
- 0x0515, 0x0515,
- 0x0517, 0x0517,
- 0x0519, 0x0519,
- 0x051b, 0x051b,
- 0x051d, 0x051d,
- 0x051f, 0x051f,
- 0x0521, 0x0521,
- 0x0523, 0x0523,
- 0x0525, 0x0525,
- 0x0527, 0x0527,
- 0x0529, 0x0529,
- 0x052b, 0x052b,
- 0x052d, 0x052d,
- 0x052f, 0x052f,
- 0x0561, 0x0587,
- 0x13f8, 0x13fd,
- 0x1c80, 0x1c88,
- 0x1c8a, 0x1c8a,
- 0x1d79, 0x1d79,
- 0x1d7d, 0x1d7d,
- 0x1d8e, 0x1d8e,
- 0x1e01, 0x1e01,
- 0x1e03, 0x1e03,
- 0x1e05, 0x1e05,
- 0x1e07, 0x1e07,
- 0x1e09, 0x1e09,
- 0x1e0b, 0x1e0b,
- 0x1e0d, 0x1e0d,
- 0x1e0f, 0x1e0f,
- 0x1e11, 0x1e11,
- 0x1e13, 0x1e13,
- 0x1e15, 0x1e15,
- 0x1e17, 0x1e17,
- 0x1e19, 0x1e19,
- 0x1e1b, 0x1e1b,
- 0x1e1d, 0x1e1d,
- 0x1e1f, 0x1e1f,
- 0x1e21, 0x1e21,
- 0x1e23, 0x1e23,
- 0x1e25, 0x1e25,
- 0x1e27, 0x1e27,
- 0x1e29, 0x1e29,
- 0x1e2b, 0x1e2b,
- 0x1e2d, 0x1e2d,
- 0x1e2f, 0x1e2f,
- 0x1e31, 0x1e31,
- 0x1e33, 0x1e33,
- 0x1e35, 0x1e35,
- 0x1e37, 0x1e37,
- 0x1e39, 0x1e39,
- 0x1e3b, 0x1e3b,
- 0x1e3d, 0x1e3d,
- 0x1e3f, 0x1e3f,
- 0x1e41, 0x1e41,
- 0x1e43, 0x1e43,
- 0x1e45, 0x1e45,
- 0x1e47, 0x1e47,
- 0x1e49, 0x1e49,
- 0x1e4b, 0x1e4b,
- 0x1e4d, 0x1e4d,
- 0x1e4f, 0x1e4f,
- 0x1e51, 0x1e51,
- 0x1e53, 0x1e53,
- 0x1e55, 0x1e55,
- 0x1e57, 0x1e57,
- 0x1e59, 0x1e59,
- 0x1e5b, 0x1e5b,
- 0x1e5d, 0x1e5d,
- 0x1e5f, 0x1e5f,
- 0x1e61, 0x1e61,
- 0x1e63, 0x1e63,
- 0x1e65, 0x1e65,
- 0x1e67, 0x1e67,
- 0x1e69, 0x1e69,
- 0x1e6b, 0x1e6b,
- 0x1e6d, 0x1e6d,
- 0x1e6f, 0x1e6f,
- 0x1e71, 0x1e71,
- 0x1e73, 0x1e73,
- 0x1e75, 0x1e75,
- 0x1e77, 0x1e77,
- 0x1e79, 0x1e79,
- 0x1e7b, 0x1e7b,
- 0x1e7d, 0x1e7d,
- 0x1e7f, 0x1e7f,
- 0x1e81, 0x1e81,
- 0x1e83, 0x1e83,
- 0x1e85, 0x1e85,
- 0x1e87, 0x1e87,
- 0x1e89, 0x1e89,
- 0x1e8b, 0x1e8b,
- 0x1e8d, 0x1e8d,
- 0x1e8f, 0x1e8f,
- 0x1e91, 0x1e91,
- 0x1e93, 0x1e93,
- 0x1e95, 0x1e9b,
- 0x1ea1, 0x1ea1,
- 0x1ea3, 0x1ea3,
- 0x1ea5, 0x1ea5,
- 0x1ea7, 0x1ea7,
- 0x1ea9, 0x1ea9,
- 0x1eab, 0x1eab,
- 0x1ead, 0x1ead,
- 0x1eaf, 0x1eaf,
- 0x1eb1, 0x1eb1,
- 0x1eb3, 0x1eb3,
- 0x1eb5, 0x1eb5,
- 0x1eb7, 0x1eb7,
- 0x1eb9, 0x1eb9,
- 0x1ebb, 0x1ebb,
- 0x1ebd, 0x1ebd,
- 0x1ebf, 0x1ebf,
- 0x1ec1, 0x1ec1,
- 0x1ec3, 0x1ec3,
- 0x1ec5, 0x1ec5,
- 0x1ec7, 0x1ec7,
- 0x1ec9, 0x1ec9,
- 0x1ecb, 0x1ecb,
- 0x1ecd, 0x1ecd,
- 0x1ecf, 0x1ecf,
- 0x1ed1, 0x1ed1,
- 0x1ed3, 0x1ed3,
- 0x1ed5, 0x1ed5,
- 0x1ed7, 0x1ed7,
- 0x1ed9, 0x1ed9,
- 0x1edb, 0x1edb,
- 0x1edd, 0x1edd,
- 0x1edf, 0x1edf,
- 0x1ee1, 0x1ee1,
- 0x1ee3, 0x1ee3,
- 0x1ee5, 0x1ee5,
- 0x1ee7, 0x1ee7,
- 0x1ee9, 0x1ee9,
- 0x1eeb, 0x1eeb,
- 0x1eed, 0x1eed,
- 0x1eef, 0x1eef,
- 0x1ef1, 0x1ef1,
- 0x1ef3, 0x1ef3,
- 0x1ef5, 0x1ef5,
- 0x1ef7, 0x1ef7,
- 0x1ef9, 0x1ef9,
- 0x1efb, 0x1efb,
- 0x1efd, 0x1efd,
- 0x1eff, 0x1f07,
- 0x1f10, 0x1f15,
- 0x1f20, 0x1f27,
- 0x1f30, 0x1f37,
- 0x1f40, 0x1f45,
- 0x1f50, 0x1f57,
- 0x1f60, 0x1f67,
- 0x1f70, 0x1f7d,
- 0x1f80, 0x1f87,
- 0x1f90, 0x1f97,
- 0x1fa0, 0x1fa7,
- 0x1fb0, 0x1fb4,
- 0x1fb6, 0x1fb7,
- 0x1fbe, 0x1fbe,
- 0x1fc2, 0x1fc4,
- 0x1fc6, 0x1fc7,
- 0x1fd0, 0x1fd3,
- 0x1fd6, 0x1fd7,
- 0x1fe0, 0x1fe7,
- 0x1ff2, 0x1ff4,
- 0x1ff6, 0x1ff7,
- 0x214e, 0x214e,
- 0x2170, 0x217f,
- 0x2184, 0x2184,
- 0x24d0, 0x24e9,
- 0x2c30, 0x2c5f,
- 0x2c61, 0x2c61,
- 0x2c65, 0x2c66,
- 0x2c68, 0x2c68,
- 0x2c6a, 0x2c6a,
- 0x2c6c, 0x2c6c,
- 0x2c73, 0x2c73,
- 0x2c76, 0x2c76,
- 0x2c81, 0x2c81,
- 0x2c83, 0x2c83,
- 0x2c85, 0x2c85,
- 0x2c87, 0x2c87,
- 0x2c89, 0x2c89,
- 0x2c8b, 0x2c8b,
- 0x2c8d, 0x2c8d,
- 0x2c8f, 0x2c8f,
- 0x2c91, 0x2c91,
- 0x2c93, 0x2c93,
- 0x2c95, 0x2c95,
- 0x2c97, 0x2c97,
- 0x2c99, 0x2c99,
- 0x2c9b, 0x2c9b,
- 0x2c9d, 0x2c9d,
- 0x2c9f, 0x2c9f,
- 0x2ca1, 0x2ca1,
- 0x2ca3, 0x2ca3,
- 0x2ca5, 0x2ca5,
- 0x2ca7, 0x2ca7,
- 0x2ca9, 0x2ca9,
- 0x2cab, 0x2cab,
- 0x2cad, 0x2cad,
- 0x2caf, 0x2caf,
- 0x2cb1, 0x2cb1,
- 0x2cb3, 0x2cb3,
- 0x2cb5, 0x2cb5,
- 0x2cb7, 0x2cb7,
- 0x2cb9, 0x2cb9,
- 0x2cbb, 0x2cbb,
- 0x2cbd, 0x2cbd,
- 0x2cbf, 0x2cbf,
- 0x2cc1, 0x2cc1,
- 0x2cc3, 0x2cc3,
- 0x2cc5, 0x2cc5,
- 0x2cc7, 0x2cc7,
- 0x2cc9, 0x2cc9,
- 0x2ccb, 0x2ccb,
- 0x2ccd, 0x2ccd,
- 0x2ccf, 0x2ccf,
- 0x2cd1, 0x2cd1,
- 0x2cd3, 0x2cd3,
- 0x2cd5, 0x2cd5,
- 0x2cd7, 0x2cd7,
- 0x2cd9, 0x2cd9,
- 0x2cdb, 0x2cdb,
- 0x2cdd, 0x2cdd,
- 0x2cdf, 0x2cdf,
- 0x2ce1, 0x2ce1,
- 0x2ce3, 0x2ce3,
- 0x2cec, 0x2cec,
- 0x2cee, 0x2cee,
- 0x2cf3, 0x2cf3,
- 0x2d00, 0x2d25,
- 0x2d27, 0x2d27,
- 0x2d2d, 0x2d2d,
- 0xa641, 0xa641,
- 0xa643, 0xa643,
- 0xa645, 0xa645,
- 0xa647, 0xa647,
- 0xa649, 0xa649,
- 0xa64b, 0xa64b,
- 0xa64d, 0xa64d,
- 0xa64f, 0xa64f,
- 0xa651, 0xa651,
- 0xa653, 0xa653,
- 0xa655, 0xa655,
- 0xa657, 0xa657,
- 0xa659, 0xa659,
- 0xa65b, 0xa65b,
- 0xa65d, 0xa65d,
- 0xa65f, 0xa65f,
- 0xa661, 0xa661,
- 0xa663, 0xa663,
- 0xa665, 0xa665,
- 0xa667, 0xa667,
- 0xa669, 0xa669,
- 0xa66b, 0xa66b,
- 0xa66d, 0xa66d,
- 0xa681, 0xa681,
- 0xa683, 0xa683,
- 0xa685, 0xa685,
- 0xa687, 0xa687,
- 0xa689, 0xa689,
- 0xa68b, 0xa68b,
- 0xa68d, 0xa68d,
- 0xa68f, 0xa68f,
- 0xa691, 0xa691,
- 0xa693, 0xa693,
- 0xa695, 0xa695,
- 0xa697, 0xa697,
- 0xa699, 0xa699,
- 0xa69b, 0xa69b,
- 0xa723, 0xa723,
- 0xa725, 0xa725,
- 0xa727, 0xa727,
- 0xa729, 0xa729,
- 0xa72b, 0xa72b,
- 0xa72d, 0xa72d,
- 0xa72f, 0xa72f,
- 0xa733, 0xa733,
- 0xa735, 0xa735,
- 0xa737, 0xa737,
- 0xa739, 0xa739,
- 0xa73b, 0xa73b,
- 0xa73d, 0xa73d,
- 0xa73f, 0xa73f,
- 0xa741, 0xa741,
- 0xa743, 0xa743,
- 0xa745, 0xa745,
- 0xa747, 0xa747,
- 0xa749, 0xa749,
- 0xa74b, 0xa74b,
- 0xa74d, 0xa74d,
- 0xa74f, 0xa74f,
- 0xa751, 0xa751,
- 0xa753, 0xa753,
- 0xa755, 0xa755,
- 0xa757, 0xa757,
- 0xa759, 0xa759,
- 0xa75b, 0xa75b,
- 0xa75d, 0xa75d,
- 0xa75f, 0xa75f,
- 0xa761, 0xa761,
- 0xa763, 0xa763,
- 0xa765, 0xa765,
- 0xa767, 0xa767,
- 0xa769, 0xa769,
- 0xa76b, 0xa76b,
- 0xa76d, 0xa76d,
- 0xa76f, 0xa76f,
- 0xa77a, 0xa77a,
- 0xa77c, 0xa77c,
- 0xa77f, 0xa77f,
- 0xa781, 0xa781,
- 0xa783, 0xa783,
- 0xa785, 0xa785,
- 0xa787, 0xa787,
- 0xa78c, 0xa78c,
- 0xa791, 0xa791,
- 0xa793, 0xa794,
- 0xa797, 0xa797,
- 0xa799, 0xa799,
- 0xa79b, 0xa79b,
- 0xa79d, 0xa79d,
- 0xa79f, 0xa79f,
- 0xa7a1, 0xa7a1,
- 0xa7a3, 0xa7a3,
- 0xa7a5, 0xa7a5,
- 0xa7a7, 0xa7a7,
- 0xa7a9, 0xa7a9,
- 0xa7b5, 0xa7b5,
- 0xa7b7, 0xa7b7,
- 0xa7b9, 0xa7b9,
- 0xa7bb, 0xa7bb,
- 0xa7bd, 0xa7bd,
- 0xa7bf, 0xa7bf,
- 0xa7c1, 0xa7c1,
- 0xa7c3, 0xa7c3,
- 0xa7c8, 0xa7c8,
- 0xa7ca, 0xa7ca,
- 0xa7cd, 0xa7cd,
- 0xa7d1, 0xa7d1,
- 0xa7d7, 0xa7d7,
- 0xa7d9, 0xa7d9,
- 0xa7db, 0xa7db,
- 0xa7f6, 0xa7f6,
- 0xab53, 0xab53,
- 0xab70, 0xabbf,
- 0xfb00, 0xfb06,
- 0xfb13, 0xfb17,
- 0xff41, 0xff5a,
- 0x10428, 0x1044f,
- 0x104d8, 0x104fb,
- 0x10597, 0x105a1,
- 0x105a3, 0x105b1,
- 0x105b3, 0x105b9,
- 0x105bb, 0x105bc,
- 0x10cc0, 0x10cf2,
- 0x10d70, 0x10d85,
- 0x118c0, 0x118df,
- 0x16e60, 0x16e7f,
- 0x1e922, 0x1e943,
-}; /* CR_Changes_When_Titlecased */
-
-/* 'Changes_When_Casefolded': Derived Property */
-static const OnigCodePoint CR_Changes_When_Casefolded[] = {
- 626,
- 0x0041, 0x005a,
- 0x00b5, 0x00b5,
- 0x00c0, 0x00d6,
- 0x00d8, 0x00df,
- 0x0100, 0x0100,
- 0x0102, 0x0102,
- 0x0104, 0x0104,
- 0x0106, 0x0106,
- 0x0108, 0x0108,
- 0x010a, 0x010a,
- 0x010c, 0x010c,
- 0x010e, 0x010e,
- 0x0110, 0x0110,
- 0x0112, 0x0112,
- 0x0114, 0x0114,
- 0x0116, 0x0116,
- 0x0118, 0x0118,
- 0x011a, 0x011a,
- 0x011c, 0x011c,
- 0x011e, 0x011e,
- 0x0120, 0x0120,
- 0x0122, 0x0122,
- 0x0124, 0x0124,
- 0x0126, 0x0126,
- 0x0128, 0x0128,
- 0x012a, 0x012a,
- 0x012c, 0x012c,
- 0x012e, 0x012e,
- 0x0130, 0x0130,
- 0x0132, 0x0132,
- 0x0134, 0x0134,
- 0x0136, 0x0136,
- 0x0139, 0x0139,
- 0x013b, 0x013b,
- 0x013d, 0x013d,
- 0x013f, 0x013f,
- 0x0141, 0x0141,
- 0x0143, 0x0143,
- 0x0145, 0x0145,
- 0x0147, 0x0147,
- 0x0149, 0x014a,
- 0x014c, 0x014c,
- 0x014e, 0x014e,
- 0x0150, 0x0150,
- 0x0152, 0x0152,
- 0x0154, 0x0154,
- 0x0156, 0x0156,
- 0x0158, 0x0158,
- 0x015a, 0x015a,
- 0x015c, 0x015c,
- 0x015e, 0x015e,
- 0x0160, 0x0160,
- 0x0162, 0x0162,
- 0x0164, 0x0164,
- 0x0166, 0x0166,
- 0x0168, 0x0168,
- 0x016a, 0x016a,
- 0x016c, 0x016c,
- 0x016e, 0x016e,
- 0x0170, 0x0170,
- 0x0172, 0x0172,
- 0x0174, 0x0174,
- 0x0176, 0x0176,
- 0x0178, 0x0179,
- 0x017b, 0x017b,
- 0x017d, 0x017d,
- 0x017f, 0x017f,
- 0x0181, 0x0182,
- 0x0184, 0x0184,
- 0x0186, 0x0187,
- 0x0189, 0x018b,
- 0x018e, 0x0191,
- 0x0193, 0x0194,
- 0x0196, 0x0198,
- 0x019c, 0x019d,
- 0x019f, 0x01a0,
- 0x01a2, 0x01a2,
- 0x01a4, 0x01a4,
- 0x01a6, 0x01a7,
- 0x01a9, 0x01a9,
- 0x01ac, 0x01ac,
- 0x01ae, 0x01af,
- 0x01b1, 0x01b3,
- 0x01b5, 0x01b5,
- 0x01b7, 0x01b8,
- 0x01bc, 0x01bc,
- 0x01c4, 0x01c5,
- 0x01c7, 0x01c8,
- 0x01ca, 0x01cb,
- 0x01cd, 0x01cd,
- 0x01cf, 0x01cf,
- 0x01d1, 0x01d1,
- 0x01d3, 0x01d3,
- 0x01d5, 0x01d5,
- 0x01d7, 0x01d7,
- 0x01d9, 0x01d9,
- 0x01db, 0x01db,
- 0x01de, 0x01de,
- 0x01e0, 0x01e0,
- 0x01e2, 0x01e2,
- 0x01e4, 0x01e4,
- 0x01e6, 0x01e6,
- 0x01e8, 0x01e8,
- 0x01ea, 0x01ea,
- 0x01ec, 0x01ec,
- 0x01ee, 0x01ee,
- 0x01f1, 0x01f2,
- 0x01f4, 0x01f4,
- 0x01f6, 0x01f8,
- 0x01fa, 0x01fa,
- 0x01fc, 0x01fc,
- 0x01fe, 0x01fe,
- 0x0200, 0x0200,
- 0x0202, 0x0202,
- 0x0204, 0x0204,
- 0x0206, 0x0206,
- 0x0208, 0x0208,
- 0x020a, 0x020a,
- 0x020c, 0x020c,
- 0x020e, 0x020e,
- 0x0210, 0x0210,
- 0x0212, 0x0212,
- 0x0214, 0x0214,
- 0x0216, 0x0216,
- 0x0218, 0x0218,
- 0x021a, 0x021a,
- 0x021c, 0x021c,
- 0x021e, 0x021e,
- 0x0220, 0x0220,
- 0x0222, 0x0222,
- 0x0224, 0x0224,
- 0x0226, 0x0226,
- 0x0228, 0x0228,
- 0x022a, 0x022a,
- 0x022c, 0x022c,
- 0x022e, 0x022e,
- 0x0230, 0x0230,
- 0x0232, 0x0232,
- 0x023a, 0x023b,
- 0x023d, 0x023e,
- 0x0241, 0x0241,
- 0x0243, 0x0246,
- 0x0248, 0x0248,
- 0x024a, 0x024a,
- 0x024c, 0x024c,
- 0x024e, 0x024e,
- 0x0345, 0x0345,
- 0x0370, 0x0370,
- 0x0372, 0x0372,
- 0x0376, 0x0376,
- 0x037f, 0x037f,
- 0x0386, 0x0386,
- 0x0388, 0x038a,
- 0x038c, 0x038c,
- 0x038e, 0x038f,
- 0x0391, 0x03a1,
- 0x03a3, 0x03ab,
- 0x03c2, 0x03c2,
- 0x03cf, 0x03d1,
- 0x03d5, 0x03d6,
- 0x03d8, 0x03d8,
- 0x03da, 0x03da,
- 0x03dc, 0x03dc,
- 0x03de, 0x03de,
- 0x03e0, 0x03e0,
- 0x03e2, 0x03e2,
- 0x03e4, 0x03e4,
- 0x03e6, 0x03e6,
- 0x03e8, 0x03e8,
- 0x03ea, 0x03ea,
- 0x03ec, 0x03ec,
- 0x03ee, 0x03ee,
- 0x03f0, 0x03f1,
- 0x03f4, 0x03f5,
- 0x03f7, 0x03f7,
- 0x03f9, 0x03fa,
- 0x03fd, 0x042f,
- 0x0460, 0x0460,
- 0x0462, 0x0462,
- 0x0464, 0x0464,
- 0x0466, 0x0466,
- 0x0468, 0x0468,
- 0x046a, 0x046a,
- 0x046c, 0x046c,
- 0x046e, 0x046e,
- 0x0470, 0x0470,
- 0x0472, 0x0472,
- 0x0474, 0x0474,
- 0x0476, 0x0476,
- 0x0478, 0x0478,
- 0x047a, 0x047a,
- 0x047c, 0x047c,
- 0x047e, 0x047e,
- 0x0480, 0x0480,
- 0x048a, 0x048a,
- 0x048c, 0x048c,
- 0x048e, 0x048e,
- 0x0490, 0x0490,
- 0x0492, 0x0492,
- 0x0494, 0x0494,
- 0x0496, 0x0496,
- 0x0498, 0x0498,
- 0x049a, 0x049a,
- 0x049c, 0x049c,
- 0x049e, 0x049e,
- 0x04a0, 0x04a0,
- 0x04a2, 0x04a2,
- 0x04a4, 0x04a4,
- 0x04a6, 0x04a6,
- 0x04a8, 0x04a8,
- 0x04aa, 0x04aa,
- 0x04ac, 0x04ac,
- 0x04ae, 0x04ae,
- 0x04b0, 0x04b0,
- 0x04b2, 0x04b2,
- 0x04b4, 0x04b4,
- 0x04b6, 0x04b6,
- 0x04b8, 0x04b8,
- 0x04ba, 0x04ba,
- 0x04bc, 0x04bc,
- 0x04be, 0x04be,
- 0x04c0, 0x04c1,
- 0x04c3, 0x04c3,
- 0x04c5, 0x04c5,
- 0x04c7, 0x04c7,
- 0x04c9, 0x04c9,
- 0x04cb, 0x04cb,
- 0x04cd, 0x04cd,
- 0x04d0, 0x04d0,
- 0x04d2, 0x04d2,
- 0x04d4, 0x04d4,
- 0x04d6, 0x04d6,
- 0x04d8, 0x04d8,
- 0x04da, 0x04da,
- 0x04dc, 0x04dc,
- 0x04de, 0x04de,
- 0x04e0, 0x04e0,
- 0x04e2, 0x04e2,
- 0x04e4, 0x04e4,
- 0x04e6, 0x04e6,
- 0x04e8, 0x04e8,
- 0x04ea, 0x04ea,
- 0x04ec, 0x04ec,
- 0x04ee, 0x04ee,
- 0x04f0, 0x04f0,
- 0x04f2, 0x04f2,
- 0x04f4, 0x04f4,
- 0x04f6, 0x04f6,
- 0x04f8, 0x04f8,
- 0x04fa, 0x04fa,
- 0x04fc, 0x04fc,
- 0x04fe, 0x04fe,
- 0x0500, 0x0500,
- 0x0502, 0x0502,
- 0x0504, 0x0504,
- 0x0506, 0x0506,
- 0x0508, 0x0508,
- 0x050a, 0x050a,
- 0x050c, 0x050c,
- 0x050e, 0x050e,
- 0x0510, 0x0510,
- 0x0512, 0x0512,
- 0x0514, 0x0514,
- 0x0516, 0x0516,
- 0x0518, 0x0518,
- 0x051a, 0x051a,
- 0x051c, 0x051c,
- 0x051e, 0x051e,
- 0x0520, 0x0520,
- 0x0522, 0x0522,
- 0x0524, 0x0524,
- 0x0526, 0x0526,
- 0x0528, 0x0528,
- 0x052a, 0x052a,
- 0x052c, 0x052c,
- 0x052e, 0x052e,
- 0x0531, 0x0556,
- 0x0587, 0x0587,
- 0x10a0, 0x10c5,
- 0x10c7, 0x10c7,
- 0x10cd, 0x10cd,
- 0x13f8, 0x13fd,
- 0x1c80, 0x1c89,
- 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,
- 0x1e9a, 0x1e9b,
- 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,
- 0x1f80, 0x1faf,
- 0x1fb2, 0x1fb4,
- 0x1fb7, 0x1fbc,
- 0x1fc2, 0x1fc4,
- 0x1fc7, 0x1fcc,
- 0x1fd8, 0x1fdb,
- 0x1fe8, 0x1fec,
- 0x1ff2, 0x1ff4,
- 0x1ff7, 0x1ffc,
- 0x2126, 0x2126,
- 0x212a, 0x212b,
- 0x2132, 0x2132,
- 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,
- 0xa7cb, 0xa7cc,
- 0xa7d0, 0xa7d0,
- 0xa7d6, 0xa7d6,
- 0xa7d8, 0xa7d8,
- 0xa7da, 0xa7da,
- 0xa7dc, 0xa7dc,
- 0xa7f5, 0xa7f5,
- 0xab70, 0xabbf,
- 0xfb00, 0xfb06,
- 0xfb13, 0xfb17,
- 0xff21, 0xff3a,
- 0x10400, 0x10427,
- 0x104b0, 0x104d3,
- 0x10570, 0x1057a,
- 0x1057c, 0x1058a,
- 0x1058c, 0x10592,
- 0x10594, 0x10595,
- 0x10c80, 0x10cb2,
- 0x10d50, 0x10d65,
- 0x118a0, 0x118bf,
- 0x16e40, 0x16e5f,
- 0x1e900, 0x1e921,
-}; /* CR_Changes_When_Casefolded */
-
-/* 'Changes_When_Casemapped': Derived Property */
-static const OnigCodePoint CR_Changes_When_Casemapped[] = {
- 131,
- 0x0041, 0x005a,
- 0x0061, 0x007a,
- 0x00b5, 0x00b5,
- 0x00c0, 0x00d6,
- 0x00d8, 0x00f6,
- 0x00f8, 0x0137,
- 0x0139, 0x018c,
- 0x018e, 0x01a9,
- 0x01ac, 0x01b9,
- 0x01bc, 0x01bd,
- 0x01bf, 0x01bf,
- 0x01c4, 0x0220,
- 0x0222, 0x0233,
- 0x023a, 0x0254,
- 0x0256, 0x0257,
- 0x0259, 0x0259,
- 0x025b, 0x025c,
- 0x0260, 0x0261,
- 0x0263, 0x0266,
- 0x0268, 0x026c,
- 0x026f, 0x026f,
- 0x0271, 0x0272,
- 0x0275, 0x0275,
- 0x027d, 0x027d,
- 0x0280, 0x0280,
- 0x0282, 0x0283,
- 0x0287, 0x028c,
- 0x0292, 0x0292,
- 0x029d, 0x029e,
- 0x0345, 0x0345,
- 0x0370, 0x0373,
- 0x0376, 0x0377,
- 0x037b, 0x037d,
- 0x037f, 0x037f,
- 0x0386, 0x0386,
- 0x0388, 0x038a,
- 0x038c, 0x038c,
- 0x038e, 0x03a1,
- 0x03a3, 0x03d1,
- 0x03d5, 0x03f5,
- 0x03f7, 0x03fb,
- 0x03fd, 0x0481,
- 0x048a, 0x052f,
- 0x0531, 0x0556,
- 0x0561, 0x0587,
- 0x10a0, 0x10c5,
- 0x10c7, 0x10c7,
- 0x10cd, 0x10cd,
- 0x10d0, 0x10fa,
- 0x10fd, 0x10ff,
- 0x13a0, 0x13f5,
- 0x13f8, 0x13fd,
- 0x1c80, 0x1c8a,
- 0x1c90, 0x1cba,
- 0x1cbd, 0x1cbf,
- 0x1d79, 0x1d79,
- 0x1d7d, 0x1d7d,
- 0x1d8e, 0x1d8e,
- 0x1e00, 0x1e9b,
- 0x1e9e, 0x1e9e,
- 0x1ea0, 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,
- 0x2126, 0x2126,
- 0x212a, 0x212b,
- 0x2132, 0x2132,
- 0x214e, 0x214e,
- 0x2160, 0x217f,
- 0x2183, 0x2184,
- 0x24b6, 0x24e9,
- 0x2c00, 0x2c70,
- 0x2c72, 0x2c73,
- 0x2c75, 0x2c76,
- 0x2c7e, 0x2ce3,
- 0x2ceb, 0x2cee,
- 0x2cf2, 0x2cf3,
- 0x2d00, 0x2d25,
- 0x2d27, 0x2d27,
- 0x2d2d, 0x2d2d,
- 0xa640, 0xa66d,
- 0xa680, 0xa69b,
- 0xa722, 0xa72f,
- 0xa732, 0xa76f,
- 0xa779, 0xa787,
- 0xa78b, 0xa78d,
- 0xa790, 0xa794,
- 0xa796, 0xa7ae,
- 0xa7b0, 0xa7cd,
- 0xa7d0, 0xa7d1,
- 0xa7d6, 0xa7dc,
- 0xa7f5, 0xa7f6,
- 0xab53, 0xab53,
- 0xab70, 0xabbf,
- 0xfb00, 0xfb06,
- 0xfb13, 0xfb17,
- 0xff21, 0xff3a,
- 0xff41, 0xff5a,
- 0x10400, 0x1044f,
- 0x104b0, 0x104d3,
- 0x104d8, 0x104fb,
- 0x10570, 0x1057a,
- 0x1057c, 0x1058a,
- 0x1058c, 0x10592,
- 0x10594, 0x10595,
- 0x10597, 0x105a1,
- 0x105a3, 0x105b1,
- 0x105b3, 0x105b9,
- 0x105bb, 0x105bc,
- 0x10c80, 0x10cb2,
- 0x10cc0, 0x10cf2,
- 0x10d50, 0x10d65,
- 0x10d70, 0x10d85,
- 0x118a0, 0x118df,
- 0x16e40, 0x16e7f,
- 0x1e900, 0x1e943,
-}; /* CR_Changes_When_Casemapped */
-
-/* 'ID_Start': Derived Property */
-static const OnigCodePoint CR_ID_Start[] = {
- 677,
- 0x0041, 0x005a,
- 0x0061, 0x007a,
- 0x00aa, 0x00aa,
- 0x00b5, 0x00b5,
- 0x00ba, 0x00ba,
- 0x00c0, 0x00d6,
- 0x00d8, 0x00f6,
- 0x00f8, 0x02c1,
- 0x02c6, 0x02d1,
- 0x02e0, 0x02e4,
- 0x02ec, 0x02ec,
- 0x02ee, 0x02ee,
- 0x0370, 0x0374,
- 0x0376, 0x0377,
- 0x037a, 0x037d,
- 0x037f, 0x037f,
- 0x0386, 0x0386,
- 0x0388, 0x038a,
- 0x038c, 0x038c,
- 0x038e, 0x03a1,
- 0x03a3, 0x03f5,
- 0x03f7, 0x0481,
- 0x048a, 0x052f,
- 0x0531, 0x0556,
- 0x0559, 0x0559,
- 0x0560, 0x0588,
- 0x05d0, 0x05ea,
- 0x05ef, 0x05f2,
- 0x0620, 0x064a,
- 0x066e, 0x066f,
- 0x0671, 0x06d3,
- 0x06d5, 0x06d5,
- 0x06e5, 0x06e6,
- 0x06ee, 0x06ef,
- 0x06fa, 0x06fc,
- 0x06ff, 0x06ff,
- 0x0710, 0x0710,
- 0x0712, 0x072f,
- 0x074d, 0x07a5,
- 0x07b1, 0x07b1,
- 0x07ca, 0x07ea,
- 0x07f4, 0x07f5,
- 0x07fa, 0x07fa,
- 0x0800, 0x0815,
- 0x081a, 0x081a,
- 0x0824, 0x0824,
- 0x0828, 0x0828,
- 0x0840, 0x0858,
- 0x0860, 0x086a,
- 0x0870, 0x0887,
- 0x0889, 0x088e,
- 0x08a0, 0x08c9,
- 0x0904, 0x0939,
- 0x093d, 0x093d,
- 0x0950, 0x0950,
- 0x0958, 0x0961,
- 0x0971, 0x0980,
- 0x0985, 0x098c,
- 0x098f, 0x0990,
- 0x0993, 0x09a8,
- 0x09aa, 0x09b0,
- 0x09b2, 0x09b2,
- 0x09b6, 0x09b9,
- 0x09bd, 0x09bd,
- 0x09ce, 0x09ce,
- 0x09dc, 0x09dd,
- 0x09df, 0x09e1,
- 0x09f0, 0x09f1,
- 0x09fc, 0x09fc,
- 0x0a05, 0x0a0a,
- 0x0a0f, 0x0a10,
- 0x0a13, 0x0a28,
- 0x0a2a, 0x0a30,
- 0x0a32, 0x0a33,
- 0x0a35, 0x0a36,
- 0x0a38, 0x0a39,
- 0x0a59, 0x0a5c,
- 0x0a5e, 0x0a5e,
- 0x0a72, 0x0a74,
- 0x0a85, 0x0a8d,
- 0x0a8f, 0x0a91,
- 0x0a93, 0x0aa8,
- 0x0aaa, 0x0ab0,
- 0x0ab2, 0x0ab3,
- 0x0ab5, 0x0ab9,
- 0x0abd, 0x0abd,
- 0x0ad0, 0x0ad0,
- 0x0ae0, 0x0ae1,
- 0x0af9, 0x0af9,
- 0x0b05, 0x0b0c,
- 0x0b0f, 0x0b10,
- 0x0b13, 0x0b28,
- 0x0b2a, 0x0b30,
- 0x0b32, 0x0b33,
- 0x0b35, 0x0b39,
- 0x0b3d, 0x0b3d,
- 0x0b5c, 0x0b5d,
- 0x0b5f, 0x0b61,
- 0x0b71, 0x0b71,
- 0x0b83, 0x0b83,
- 0x0b85, 0x0b8a,
- 0x0b8e, 0x0b90,
- 0x0b92, 0x0b95,
- 0x0b99, 0x0b9a,
- 0x0b9c, 0x0b9c,
- 0x0b9e, 0x0b9f,
- 0x0ba3, 0x0ba4,
- 0x0ba8, 0x0baa,
- 0x0bae, 0x0bb9,
- 0x0bd0, 0x0bd0,
- 0x0c05, 0x0c0c,
- 0x0c0e, 0x0c10,
- 0x0c12, 0x0c28,
- 0x0c2a, 0x0c39,
- 0x0c3d, 0x0c3d,
- 0x0c58, 0x0c5a,
- 0x0c5d, 0x0c5d,
- 0x0c60, 0x0c61,
- 0x0c80, 0x0c80,
- 0x0c85, 0x0c8c,
- 0x0c8e, 0x0c90,
- 0x0c92, 0x0ca8,
- 0x0caa, 0x0cb3,
- 0x0cb5, 0x0cb9,
- 0x0cbd, 0x0cbd,
- 0x0cdd, 0x0cde,
- 0x0ce0, 0x0ce1,
- 0x0cf1, 0x0cf2,
- 0x0d04, 0x0d0c,
- 0x0d0e, 0x0d10,
- 0x0d12, 0x0d3a,
- 0x0d3d, 0x0d3d,
- 0x0d4e, 0x0d4e,
- 0x0d54, 0x0d56,
- 0x0d5f, 0x0d61,
- 0x0d7a, 0x0d7f,
- 0x0d85, 0x0d96,
- 0x0d9a, 0x0db1,
- 0x0db3, 0x0dbb,
- 0x0dbd, 0x0dbd,
- 0x0dc0, 0x0dc6,
- 0x0e01, 0x0e30,
- 0x0e32, 0x0e33,
- 0x0e40, 0x0e46,
- 0x0e81, 0x0e82,
- 0x0e84, 0x0e84,
- 0x0e86, 0x0e8a,
- 0x0e8c, 0x0ea3,
- 0x0ea5, 0x0ea5,
- 0x0ea7, 0x0eb0,
- 0x0eb2, 0x0eb3,
- 0x0ebd, 0x0ebd,
- 0x0ec0, 0x0ec4,
- 0x0ec6, 0x0ec6,
- 0x0edc, 0x0edf,
- 0x0f00, 0x0f00,
- 0x0f40, 0x0f47,
- 0x0f49, 0x0f6c,
- 0x0f88, 0x0f8c,
- 0x1000, 0x102a,
- 0x103f, 0x103f,
- 0x1050, 0x1055,
- 0x105a, 0x105d,
- 0x1061, 0x1061,
- 0x1065, 0x1066,
- 0x106e, 0x1070,
- 0x1075, 0x1081,
- 0x108e, 0x108e,
- 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, 0x1711,
- 0x171f, 0x1731,
- 0x1740, 0x1751,
- 0x1760, 0x176c,
- 0x176e, 0x1770,
- 0x1780, 0x17b3,
- 0x17d7, 0x17d7,
- 0x17dc, 0x17dc,
- 0x1820, 0x1878,
- 0x1880, 0x18a8,
- 0x18aa, 0x18aa,
- 0x18b0, 0x18f5,
- 0x1900, 0x191e,
- 0x1950, 0x196d,
- 0x1970, 0x1974,
- 0x1980, 0x19ab,
- 0x19b0, 0x19c9,
- 0x1a00, 0x1a16,
- 0x1a20, 0x1a54,
- 0x1aa7, 0x1aa7,
- 0x1b05, 0x1b33,
- 0x1b45, 0x1b4c,
- 0x1b83, 0x1ba0,
- 0x1bae, 0x1baf,
- 0x1bba, 0x1be5,
- 0x1c00, 0x1c23,
- 0x1c4d, 0x1c4f,
- 0x1c5a, 0x1c7d,
- 0x1c80, 0x1c8a,
- 0x1c90, 0x1cba,
- 0x1cbd, 0x1cbf,
- 0x1ce9, 0x1cec,
- 0x1cee, 0x1cf3,
- 0x1cf5, 0x1cf6,
- 0x1cfa, 0x1cfa,
- 0x1d00, 0x1dbf,
- 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,
- 0x2118, 0x211d,
- 0x2124, 0x2124,
- 0x2126, 0x2126,
- 0x2128, 0x2128,
- 0x212a, 0x2139,
- 0x213c, 0x213f,
- 0x2145, 0x2149,
- 0x214e, 0x214e,
- 0x2160, 0x2188,
- 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,
- 0x3005, 0x3007,
- 0x3021, 0x3029,
- 0x3031, 0x3035,
- 0x3038, 0x303c,
- 0x3041, 0x3096,
- 0x309b, 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,
- 0xa67f, 0xa69d,
- 0xa6a0, 0xa6ef,
- 0xa717, 0xa71f,
- 0xa722, 0xa788,
- 0xa78b, 0xa7cd,
- 0xa7d0, 0xa7d1,
- 0xa7d3, 0xa7d3,
- 0xa7d5, 0xa7dc,
- 0xa7f2, 0xa801,
- 0xa803, 0xa805,
- 0xa807, 0xa80a,
- 0xa80c, 0xa822,
- 0xa840, 0xa873,
- 0xa882, 0xa8b3,
- 0xa8f2, 0xa8f7,
- 0xa8fb, 0xa8fb,
- 0xa8fd, 0xa8fe,
- 0xa90a, 0xa925,
- 0xa930, 0xa946,
- 0xa960, 0xa97c,
- 0xa984, 0xa9b2,
- 0xa9cf, 0xa9cf,
- 0xa9e0, 0xa9e4,
- 0xa9e6, 0xa9ef,
- 0xa9fa, 0xa9fe,
- 0xaa00, 0xaa28,
- 0xaa40, 0xaa42,
- 0xaa44, 0xaa4b,
- 0xaa60, 0xaa76,
- 0xaa7a, 0xaa7a,
- 0xaa7e, 0xaaaf,
- 0xaab1, 0xaab1,
- 0xaab5, 0xaab6,
- 0xaab9, 0xaabd,
- 0xaac0, 0xaac0,
- 0xaac2, 0xaac2,
- 0xaadb, 0xaadd,
- 0xaae0, 0xaaea,
- 0xaaf2, 0xaaf4,
- 0xab01, 0xab06,
- 0xab09, 0xab0e,
- 0xab11, 0xab16,
- 0xab20, 0xab26,
- 0xab28, 0xab2e,
- 0xab30, 0xab5a,
- 0xab5c, 0xab69,
- 0xab70, 0xabe2,
- 0xac00, 0xd7a3,
- 0xd7b0, 0xd7c6,
- 0xd7cb, 0xd7fb,
- 0xf900, 0xfa6d,
- 0xfa70, 0xfad9,
- 0xfb00, 0xfb06,
- 0xfb13, 0xfb17,
- 0xfb1d, 0xfb1d,
- 0xfb1f, 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, 0x10375,
- 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,
- 0x105c0, 0x105f3,
- 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, 0x10a00,
- 0x10a10, 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, 0x10d23,
- 0x10d4a, 0x10d65,
- 0x10d6f, 0x10d85,
- 0x10e80, 0x10ea9,
- 0x10eb0, 0x10eb1,
- 0x10ec2, 0x10ec4,
- 0x10f00, 0x10f1c,
- 0x10f27, 0x10f27,
- 0x10f30, 0x10f45,
- 0x10f70, 0x10f81,
- 0x10fb0, 0x10fc4,
- 0x10fe0, 0x10ff6,
- 0x11003, 0x11037,
- 0x11071, 0x11072,
- 0x11075, 0x11075,
- 0x11083, 0x110af,
- 0x110d0, 0x110e8,
- 0x11103, 0x11126,
- 0x11144, 0x11144,
- 0x11147, 0x11147,
- 0x11150, 0x11172,
- 0x11176, 0x11176,
- 0x11183, 0x111b2,
- 0x111c1, 0x111c4,
- 0x111da, 0x111da,
- 0x111dc, 0x111dc,
- 0x11200, 0x11211,
- 0x11213, 0x1122b,
- 0x1123f, 0x11240,
- 0x11280, 0x11286,
- 0x11288, 0x11288,
- 0x1128a, 0x1128d,
- 0x1128f, 0x1129d,
- 0x1129f, 0x112a8,
- 0x112b0, 0x112de,
- 0x11305, 0x1130c,
- 0x1130f, 0x11310,
- 0x11313, 0x11328,
- 0x1132a, 0x11330,
- 0x11332, 0x11333,
- 0x11335, 0x11339,
- 0x1133d, 0x1133d,
- 0x11350, 0x11350,
- 0x1135d, 0x11361,
- 0x11380, 0x11389,
- 0x1138b, 0x1138b,
- 0x1138e, 0x1138e,
- 0x11390, 0x113b5,
- 0x113b7, 0x113b7,
- 0x113d1, 0x113d1,
- 0x113d3, 0x113d3,
- 0x11400, 0x11434,
- 0x11447, 0x1144a,
- 0x1145f, 0x11461,
- 0x11480, 0x114af,
- 0x114c4, 0x114c5,
- 0x114c7, 0x114c7,
- 0x11580, 0x115ae,
- 0x115d8, 0x115db,
- 0x11600, 0x1162f,
- 0x11644, 0x11644,
- 0x11680, 0x116aa,
- 0x116b8, 0x116b8,
- 0x11700, 0x1171a,
- 0x11740, 0x11746,
- 0x11800, 0x1182b,
- 0x118a0, 0x118df,
- 0x118ff, 0x11906,
- 0x11909, 0x11909,
- 0x1190c, 0x11913,
- 0x11915, 0x11916,
- 0x11918, 0x1192f,
- 0x1193f, 0x1193f,
- 0x11941, 0x11941,
- 0x119a0, 0x119a7,
- 0x119aa, 0x119d0,
- 0x119e1, 0x119e1,
- 0x119e3, 0x119e3,
- 0x11a00, 0x11a00,
- 0x11a0b, 0x11a32,
- 0x11a3a, 0x11a3a,
- 0x11a50, 0x11a50,
- 0x11a5c, 0x11a89,
- 0x11a9d, 0x11a9d,
- 0x11ab0, 0x11af8,
- 0x11bc0, 0x11be0,
- 0x11c00, 0x11c08,
- 0x11c0a, 0x11c2e,
- 0x11c40, 0x11c40,
- 0x11c72, 0x11c8f,
- 0x11d00, 0x11d06,
- 0x11d08, 0x11d09,
- 0x11d0b, 0x11d30,
- 0x11d46, 0x11d46,
- 0x11d60, 0x11d65,
- 0x11d67, 0x11d68,
- 0x11d6a, 0x11d89,
- 0x11d98, 0x11d98,
- 0x11ee0, 0x11ef2,
- 0x11f02, 0x11f02,
- 0x11f04, 0x11f10,
- 0x11f12, 0x11f33,
- 0x11fb0, 0x11fb0,
- 0x12000, 0x12399,
- 0x12400, 0x1246e,
- 0x12480, 0x12543,
- 0x12f90, 0x12ff0,
- 0x13000, 0x1342f,
- 0x13441, 0x13446,
- 0x13460, 0x143fa,
- 0x14400, 0x14646,
- 0x16100, 0x1611d,
- 0x16800, 0x16a38,
- 0x16a40, 0x16a5e,
- 0x16a70, 0x16abe,
- 0x16ad0, 0x16aed,
- 0x16b00, 0x16b2f,
- 0x16b40, 0x16b43,
- 0x16b63, 0x16b77,
- 0x16b7d, 0x16b8f,
- 0x16d40, 0x16d6c,
- 0x16e40, 0x16e7f,
- 0x16f00, 0x16f4a,
- 0x16f50, 0x16f50,
- 0x16f93, 0x16f9f,
- 0x16fe0, 0x16fe1,
- 0x16fe3, 0x16fe3,
- 0x17000, 0x187f7,
- 0x18800, 0x18cd5,
- 0x18cff, 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,
- 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,
- 0x1e030, 0x1e06d,
- 0x1e100, 0x1e12c,
- 0x1e137, 0x1e13d,
- 0x1e14e, 0x1e14e,
- 0x1e290, 0x1e2ad,
- 0x1e2c0, 0x1e2eb,
- 0x1e4d0, 0x1e4eb,
- 0x1e5d0, 0x1e5ed,
- 0x1e5f0, 0x1e5f0,
- 0x1e7e0, 0x1e7e6,
- 0x1e7e8, 0x1e7eb,
- 0x1e7ed, 0x1e7ee,
- 0x1e7f0, 0x1e7fe,
- 0x1e800, 0x1e8c4,
- 0x1e900, 0x1e943,
- 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,
- 0x20000, 0x2a6df,
- 0x2a700, 0x2b739,
- 0x2b740, 0x2b81d,
- 0x2b820, 0x2cea1,
- 0x2ceb0, 0x2ebe0,
- 0x2ebf0, 0x2ee5d,
- 0x2f800, 0x2fa1d,
- 0x30000, 0x3134a,
- 0x31350, 0x323af,
-}; /* CR_ID_Start */
-
-/* 'ID_Continue': Derived Property */
-static const OnigCodePoint CR_ID_Continue[] = {
- 793,
- 0x0030, 0x0039,
- 0x0041, 0x005a,
- 0x005f, 0x005f,
- 0x0061, 0x007a,
- 0x00aa, 0x00aa,
- 0x00b5, 0x00b5,
- 0x00b7, 0x00b7,
- 0x00ba, 0x00ba,
- 0x00c0, 0x00d6,
- 0x00d8, 0x00f6,
- 0x00f8, 0x02c1,
- 0x02c6, 0x02d1,
- 0x02e0, 0x02e4,
- 0x02ec, 0x02ec,
- 0x02ee, 0x02ee,
- 0x0300, 0x0374,
- 0x0376, 0x0377,
- 0x037a, 0x037d,
- 0x037f, 0x037f,
- 0x0386, 0x038a,
- 0x038c, 0x038c,
- 0x038e, 0x03a1,
- 0x03a3, 0x03f5,
- 0x03f7, 0x0481,
- 0x0483, 0x0487,
- 0x048a, 0x052f,
- 0x0531, 0x0556,
- 0x0559, 0x0559,
- 0x0560, 0x0588,
- 0x0591, 0x05bd,
- 0x05bf, 0x05bf,
- 0x05c1, 0x05c2,
- 0x05c4, 0x05c5,
- 0x05c7, 0x05c7,
- 0x05d0, 0x05ea,
- 0x05ef, 0x05f2,
- 0x0610, 0x061a,
- 0x0620, 0x0669,
- 0x066e, 0x06d3,
- 0x06d5, 0x06dc,
- 0x06df, 0x06e8,
- 0x06ea, 0x06fc,
- 0x06ff, 0x06ff,
- 0x0710, 0x074a,
- 0x074d, 0x07b1,
- 0x07c0, 0x07f5,
- 0x07fa, 0x07fa,
- 0x07fd, 0x07fd,
- 0x0800, 0x082d,
- 0x0840, 0x085b,
- 0x0860, 0x086a,
- 0x0870, 0x0887,
- 0x0889, 0x088e,
- 0x0897, 0x08e1,
- 0x08e3, 0x0963,
- 0x0966, 0x096f,
- 0x0971, 0x0983,
- 0x0985, 0x098c,
- 0x098f, 0x0990,
- 0x0993, 0x09a8,
- 0x09aa, 0x09b0,
- 0x09b2, 0x09b2,
- 0x09b6, 0x09b9,
- 0x09bc, 0x09c4,
- 0x09c7, 0x09c8,
- 0x09cb, 0x09ce,
- 0x09d7, 0x09d7,
- 0x09dc, 0x09dd,
- 0x09df, 0x09e3,
- 0x09e6, 0x09f1,
- 0x09fc, 0x09fc,
- 0x09fe, 0x09fe,
- 0x0a01, 0x0a03,
- 0x0a05, 0x0a0a,
- 0x0a0f, 0x0a10,
- 0x0a13, 0x0a28,
- 0x0a2a, 0x0a30,
- 0x0a32, 0x0a33,
- 0x0a35, 0x0a36,
- 0x0a38, 0x0a39,
- 0x0a3c, 0x0a3c,
- 0x0a3e, 0x0a42,
- 0x0a47, 0x0a48,
- 0x0a4b, 0x0a4d,
- 0x0a51, 0x0a51,
- 0x0a59, 0x0a5c,
- 0x0a5e, 0x0a5e,
- 0x0a66, 0x0a75,
- 0x0a81, 0x0a83,
- 0x0a85, 0x0a8d,
- 0x0a8f, 0x0a91,
- 0x0a93, 0x0aa8,
- 0x0aaa, 0x0ab0,
- 0x0ab2, 0x0ab3,
- 0x0ab5, 0x0ab9,
- 0x0abc, 0x0ac5,
- 0x0ac7, 0x0ac9,
- 0x0acb, 0x0acd,
- 0x0ad0, 0x0ad0,
- 0x0ae0, 0x0ae3,
- 0x0ae6, 0x0aef,
- 0x0af9, 0x0aff,
- 0x0b01, 0x0b03,
- 0x0b05, 0x0b0c,
- 0x0b0f, 0x0b10,
- 0x0b13, 0x0b28,
- 0x0b2a, 0x0b30,
- 0x0b32, 0x0b33,
- 0x0b35, 0x0b39,
- 0x0b3c, 0x0b44,
- 0x0b47, 0x0b48,
- 0x0b4b, 0x0b4d,
- 0x0b55, 0x0b57,
- 0x0b5c, 0x0b5d,
- 0x0b5f, 0x0b63,
- 0x0b66, 0x0b6f,
- 0x0b71, 0x0b71,
- 0x0b82, 0x0b83,
- 0x0b85, 0x0b8a,
- 0x0b8e, 0x0b90,
- 0x0b92, 0x0b95,
- 0x0b99, 0x0b9a,
- 0x0b9c, 0x0b9c,
- 0x0b9e, 0x0b9f,
- 0x0ba3, 0x0ba4,
- 0x0ba8, 0x0baa,
- 0x0bae, 0x0bb9,
- 0x0bbe, 0x0bc2,
- 0x0bc6, 0x0bc8,
- 0x0bca, 0x0bcd,
- 0x0bd0, 0x0bd0,
- 0x0bd7, 0x0bd7,
- 0x0be6, 0x0bef,
- 0x0c00, 0x0c0c,
- 0x0c0e, 0x0c10,
- 0x0c12, 0x0c28,
- 0x0c2a, 0x0c39,
- 0x0c3c, 0x0c44,
- 0x0c46, 0x0c48,
- 0x0c4a, 0x0c4d,
- 0x0c55, 0x0c56,
- 0x0c58, 0x0c5a,
- 0x0c5d, 0x0c5d,
- 0x0c60, 0x0c63,
- 0x0c66, 0x0c6f,
- 0x0c80, 0x0c83,
- 0x0c85, 0x0c8c,
- 0x0c8e, 0x0c90,
- 0x0c92, 0x0ca8,
- 0x0caa, 0x0cb3,
- 0x0cb5, 0x0cb9,
- 0x0cbc, 0x0cc4,
- 0x0cc6, 0x0cc8,
- 0x0cca, 0x0ccd,
- 0x0cd5, 0x0cd6,
- 0x0cdd, 0x0cde,
- 0x0ce0, 0x0ce3,
- 0x0ce6, 0x0cef,
- 0x0cf1, 0x0cf3,
- 0x0d00, 0x0d0c,
- 0x0d0e, 0x0d10,
- 0x0d12, 0x0d44,
- 0x0d46, 0x0d48,
- 0x0d4a, 0x0d4e,
- 0x0d54, 0x0d57,
- 0x0d5f, 0x0d63,
- 0x0d66, 0x0d6f,
- 0x0d7a, 0x0d7f,
- 0x0d81, 0x0d83,
- 0x0d85, 0x0d96,
- 0x0d9a, 0x0db1,
- 0x0db3, 0x0dbb,
- 0x0dbd, 0x0dbd,
- 0x0dc0, 0x0dc6,
- 0x0dca, 0x0dca,
- 0x0dcf, 0x0dd4,
- 0x0dd6, 0x0dd6,
- 0x0dd8, 0x0ddf,
- 0x0de6, 0x0def,
- 0x0df2, 0x0df3,
- 0x0e01, 0x0e3a,
- 0x0e40, 0x0e4e,
- 0x0e50, 0x0e59,
- 0x0e81, 0x0e82,
- 0x0e84, 0x0e84,
- 0x0e86, 0x0e8a,
- 0x0e8c, 0x0ea3,
- 0x0ea5, 0x0ea5,
- 0x0ea7, 0x0ebd,
- 0x0ec0, 0x0ec4,
- 0x0ec6, 0x0ec6,
- 0x0ec8, 0x0ece,
- 0x0ed0, 0x0ed9,
- 0x0edc, 0x0edf,
- 0x0f00, 0x0f00,
- 0x0f18, 0x0f19,
- 0x0f20, 0x0f29,
- 0x0f35, 0x0f35,
- 0x0f37, 0x0f37,
- 0x0f39, 0x0f39,
- 0x0f3e, 0x0f47,
- 0x0f49, 0x0f6c,
- 0x0f71, 0x0f84,
- 0x0f86, 0x0f97,
- 0x0f99, 0x0fbc,
- 0x0fc6, 0x0fc6,
- 0x1000, 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,
- 0x135d, 0x135f,
- 0x1369, 0x1371,
- 0x1380, 0x138f,
- 0x13a0, 0x13f5,
- 0x13f8, 0x13fd,
- 0x1401, 0x166c,
- 0x166f, 0x167f,
- 0x1681, 0x169a,
- 0x16a0, 0x16ea,
- 0x16ee, 0x16f8,
- 0x1700, 0x1715,
- 0x171f, 0x1734,
- 0x1740, 0x1753,
- 0x1760, 0x176c,
- 0x176e, 0x1770,
- 0x1772, 0x1773,
- 0x1780, 0x17d3,
- 0x17d7, 0x17d7,
- 0x17dc, 0x17dd,
- 0x17e0, 0x17e9,
- 0x180b, 0x180d,
- 0x180f, 0x1819,
- 0x1820, 0x1878,
- 0x1880, 0x18aa,
- 0x18b0, 0x18f5,
- 0x1900, 0x191e,
- 0x1920, 0x192b,
- 0x1930, 0x193b,
- 0x1946, 0x196d,
- 0x1970, 0x1974,
- 0x1980, 0x19ab,
- 0x19b0, 0x19c9,
- 0x19d0, 0x19da,
- 0x1a00, 0x1a1b,
- 0x1a20, 0x1a5e,
- 0x1a60, 0x1a7c,
- 0x1a7f, 0x1a89,
- 0x1a90, 0x1a99,
- 0x1aa7, 0x1aa7,
- 0x1ab0, 0x1abd,
- 0x1abf, 0x1ace,
- 0x1b00, 0x1b4c,
- 0x1b50, 0x1b59,
- 0x1b6b, 0x1b73,
- 0x1b80, 0x1bf3,
- 0x1c00, 0x1c37,
- 0x1c40, 0x1c49,
- 0x1c4d, 0x1c7d,
- 0x1c80, 0x1c8a,
- 0x1c90, 0x1cba,
- 0x1cbd, 0x1cbf,
- 0x1cd0, 0x1cd2,
- 0x1cd4, 0x1cfa,
- 0x1d00, 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,
- 0x200c, 0x200d,
- 0x203f, 0x2040,
- 0x2054, 0x2054,
- 0x2071, 0x2071,
- 0x207f, 0x207f,
- 0x2090, 0x209c,
- 0x20d0, 0x20dc,
- 0x20e1, 0x20e1,
- 0x20e5, 0x20f0,
- 0x2102, 0x2102,
- 0x2107, 0x2107,
- 0x210a, 0x2113,
- 0x2115, 0x2115,
- 0x2118, 0x211d,
- 0x2124, 0x2124,
- 0x2126, 0x2126,
- 0x2128, 0x2128,
- 0x212a, 0x2139,
- 0x213c, 0x213f,
- 0x2145, 0x2149,
- 0x214e, 0x214e,
- 0x2160, 0x2188,
- 0x2c00, 0x2ce4,
- 0x2ceb, 0x2cf3,
- 0x2d00, 0x2d25,
- 0x2d27, 0x2d27,
- 0x2d2d, 0x2d2d,
- 0x2d30, 0x2d67,
- 0x2d6f, 0x2d6f,
- 0x2d7f, 0x2d96,
- 0x2da0, 0x2da6,
- 0x2da8, 0x2dae,
- 0x2db0, 0x2db6,
- 0x2db8, 0x2dbe,
- 0x2dc0, 0x2dc6,
- 0x2dc8, 0x2dce,
- 0x2dd0, 0x2dd6,
- 0x2dd8, 0x2dde,
- 0x2de0, 0x2dff,
- 0x3005, 0x3007,
- 0x3021, 0x302f,
- 0x3031, 0x3035,
- 0x3038, 0x303c,
- 0x3041, 0x3096,
- 0x3099, 0x309f,
- 0x30a1, 0x30ff,
- 0x3105, 0x312f,
- 0x3131, 0x318e,
- 0x31a0, 0x31bf,
- 0x31f0, 0x31ff,
- 0x3400, 0x4dbf,
- 0x4e00, 0xa48c,
- 0xa4d0, 0xa4fd,
- 0xa500, 0xa60c,
- 0xa610, 0xa62b,
- 0xa640, 0xa66f,
- 0xa674, 0xa67d,
- 0xa67f, 0xa6f1,
- 0xa717, 0xa71f,
- 0xa722, 0xa788,
- 0xa78b, 0xa7cd,
- 0xa7d0, 0xa7d1,
- 0xa7d3, 0xa7d3,
- 0xa7d5, 0xa7dc,
- 0xa7f2, 0xa827,
- 0xa82c, 0xa82c,
- 0xa840, 0xa873,
- 0xa880, 0xa8c5,
- 0xa8d0, 0xa8d9,
- 0xa8e0, 0xa8f7,
- 0xa8fb, 0xa8fb,
- 0xa8fd, 0xa92d,
- 0xa930, 0xa953,
- 0xa960, 0xa97c,
- 0xa980, 0xa9c0,
- 0xa9cf, 0xa9d9,
- 0xa9e0, 0xa9fe,
- 0xaa00, 0xaa36,
- 0xaa40, 0xaa4d,
- 0xaa50, 0xaa59,
- 0xaa60, 0xaa76,
- 0xaa7a, 0xaac2,
- 0xaadb, 0xaadd,
- 0xaae0, 0xaaef,
- 0xaaf2, 0xaaf6,
- 0xab01, 0xab06,
- 0xab09, 0xab0e,
- 0xab11, 0xab16,
- 0xab20, 0xab26,
- 0xab28, 0xab2e,
- 0xab30, 0xab5a,
- 0xab5c, 0xab69,
- 0xab70, 0xabea,
- 0xabec, 0xabed,
- 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,
- 0xfe00, 0xfe0f,
- 0xfe20, 0xfe2f,
- 0xfe33, 0xfe34,
- 0xfe4d, 0xfe4f,
- 0xfe70, 0xfe74,
- 0xfe76, 0xfefc,
- 0xff10, 0xff19,
- 0xff21, 0xff3a,
- 0xff3f, 0xff3f,
- 0xff41, 0xff5a,
- 0xff65, 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,
- 0x101fd, 0x101fd,
- 0x10280, 0x1029c,
- 0x102a0, 0x102d0,
- 0x102e0, 0x102e0,
- 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,
- 0x105c0, 0x105f3,
- 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,
- 0x10a38, 0x10a3a,
- 0x10a3f, 0x10a3f,
- 0x10a60, 0x10a7c,
- 0x10a80, 0x10a9c,
- 0x10ac0, 0x10ac7,
- 0x10ac9, 0x10ae6,
- 0x10b00, 0x10b35,
- 0x10b40, 0x10b55,
- 0x10b60, 0x10b72,
- 0x10b80, 0x10b91,
- 0x10c00, 0x10c48,
- 0x10c80, 0x10cb2,
- 0x10cc0, 0x10cf2,
- 0x10d00, 0x10d27,
- 0x10d30, 0x10d39,
- 0x10d40, 0x10d65,
- 0x10d69, 0x10d6d,
- 0x10d6f, 0x10d85,
- 0x10e80, 0x10ea9,
- 0x10eab, 0x10eac,
- 0x10eb0, 0x10eb1,
- 0x10ec2, 0x10ec4,
- 0x10efc, 0x10f1c,
- 0x10f27, 0x10f27,
- 0x10f30, 0x10f50,
- 0x10f70, 0x10f85,
- 0x10fb0, 0x10fc4,
- 0x10fe0, 0x10ff6,
- 0x11000, 0x11046,
- 0x11066, 0x11075,
- 0x1107f, 0x110ba,
- 0x110c2, 0x110c2,
- 0x110d0, 0x110e8,
- 0x110f0, 0x110f9,
- 0x11100, 0x11134,
- 0x11136, 0x1113f,
- 0x11144, 0x11147,
- 0x11150, 0x11173,
- 0x11176, 0x11176,
- 0x11180, 0x111c4,
- 0x111c9, 0x111cc,
- 0x111ce, 0x111da,
- 0x111dc, 0x111dc,
- 0x11200, 0x11211,
- 0x11213, 0x11237,
- 0x1123e, 0x11241,
- 0x11280, 0x11286,
- 0x11288, 0x11288,
- 0x1128a, 0x1128d,
- 0x1128f, 0x1129d,
- 0x1129f, 0x112a8,
- 0x112b0, 0x112ea,
- 0x112f0, 0x112f9,
- 0x11300, 0x11303,
- 0x11305, 0x1130c,
- 0x1130f, 0x11310,
- 0x11313, 0x11328,
- 0x1132a, 0x11330,
- 0x11332, 0x11333,
- 0x11335, 0x11339,
- 0x1133b, 0x11344,
- 0x11347, 0x11348,
- 0x1134b, 0x1134d,
- 0x11350, 0x11350,
- 0x11357, 0x11357,
- 0x1135d, 0x11363,
- 0x11366, 0x1136c,
- 0x11370, 0x11374,
- 0x11380, 0x11389,
- 0x1138b, 0x1138b,
- 0x1138e, 0x1138e,
- 0x11390, 0x113b5,
- 0x113b7, 0x113c0,
- 0x113c2, 0x113c2,
- 0x113c5, 0x113c5,
- 0x113c7, 0x113ca,
- 0x113cc, 0x113d3,
- 0x113e1, 0x113e2,
- 0x11400, 0x1144a,
- 0x11450, 0x11459,
- 0x1145e, 0x11461,
- 0x11480, 0x114c5,
- 0x114c7, 0x114c7,
- 0x114d0, 0x114d9,
- 0x11580, 0x115b5,
- 0x115b8, 0x115c0,
- 0x115d8, 0x115dd,
- 0x11600, 0x11640,
- 0x11644, 0x11644,
- 0x11650, 0x11659,
- 0x11680, 0x116b8,
- 0x116c0, 0x116c9,
- 0x116d0, 0x116e3,
- 0x11700, 0x1171a,
- 0x1171d, 0x1172b,
- 0x11730, 0x11739,
- 0x11740, 0x11746,
- 0x11800, 0x1183a,
- 0x118a0, 0x118e9,
- 0x118ff, 0x11906,
- 0x11909, 0x11909,
- 0x1190c, 0x11913,
- 0x11915, 0x11916,
- 0x11918, 0x11935,
- 0x11937, 0x11938,
- 0x1193b, 0x11943,
- 0x11950, 0x11959,
- 0x119a0, 0x119a7,
- 0x119aa, 0x119d7,
- 0x119da, 0x119e1,
- 0x119e3, 0x119e4,
- 0x11a00, 0x11a3e,
- 0x11a47, 0x11a47,
- 0x11a50, 0x11a99,
- 0x11a9d, 0x11a9d,
- 0x11ab0, 0x11af8,
- 0x11bc0, 0x11be0,
- 0x11bf0, 0x11bf9,
- 0x11c00, 0x11c08,
- 0x11c0a, 0x11c36,
- 0x11c38, 0x11c40,
- 0x11c50, 0x11c59,
- 0x11c72, 0x11c8f,
- 0x11c92, 0x11ca7,
- 0x11ca9, 0x11cb6,
- 0x11d00, 0x11d06,
- 0x11d08, 0x11d09,
- 0x11d0b, 0x11d36,
- 0x11d3a, 0x11d3a,
- 0x11d3c, 0x11d3d,
- 0x11d3f, 0x11d47,
- 0x11d50, 0x11d59,
- 0x11d60, 0x11d65,
- 0x11d67, 0x11d68,
- 0x11d6a, 0x11d8e,
- 0x11d90, 0x11d91,
- 0x11d93, 0x11d98,
- 0x11da0, 0x11da9,
- 0x11ee0, 0x11ef6,
- 0x11f00, 0x11f10,
- 0x11f12, 0x11f3a,
- 0x11f3e, 0x11f42,
- 0x11f50, 0x11f5a,
- 0x11fb0, 0x11fb0,
- 0x12000, 0x12399,
- 0x12400, 0x1246e,
- 0x12480, 0x12543,
- 0x12f90, 0x12ff0,
- 0x13000, 0x1342f,
- 0x13440, 0x13455,
- 0x13460, 0x143fa,
- 0x14400, 0x14646,
- 0x16100, 0x16139,
- 0x16800, 0x16a38,
- 0x16a40, 0x16a5e,
- 0x16a60, 0x16a69,
- 0x16a70, 0x16abe,
- 0x16ac0, 0x16ac9,
- 0x16ad0, 0x16aed,
- 0x16af0, 0x16af4,
- 0x16b00, 0x16b36,
- 0x16b40, 0x16b43,
- 0x16b50, 0x16b59,
- 0x16b63, 0x16b77,
- 0x16b7d, 0x16b8f,
- 0x16d40, 0x16d6c,
- 0x16d70, 0x16d79,
- 0x16e40, 0x16e7f,
- 0x16f00, 0x16f4a,
- 0x16f4f, 0x16f87,
- 0x16f8f, 0x16f9f,
- 0x16fe0, 0x16fe1,
- 0x16fe3, 0x16fe4,
- 0x16ff0, 0x16ff1,
- 0x17000, 0x187f7,
- 0x18800, 0x18cd5,
- 0x18cff, 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,
- 0x1bc9d, 0x1bc9e,
- 0x1ccf0, 0x1ccf9,
- 0x1cf00, 0x1cf2d,
- 0x1cf30, 0x1cf46,
- 0x1d165, 0x1d169,
- 0x1d16d, 0x1d172,
- 0x1d17b, 0x1d182,
- 0x1d185, 0x1d18b,
- 0x1d1aa, 0x1d1ad,
- 0x1d242, 0x1d244,
- 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,
- 0x1da00, 0x1da36,
- 0x1da3b, 0x1da6c,
- 0x1da75, 0x1da75,
- 0x1da84, 0x1da84,
- 0x1da9b, 0x1da9f,
- 0x1daa1, 0x1daaf,
- 0x1df00, 0x1df1e,
- 0x1df25, 0x1df2a,
- 0x1e000, 0x1e006,
- 0x1e008, 0x1e018,
- 0x1e01b, 0x1e021,
- 0x1e023, 0x1e024,
- 0x1e026, 0x1e02a,
- 0x1e030, 0x1e06d,
- 0x1e08f, 0x1e08f,
- 0x1e100, 0x1e12c,
- 0x1e130, 0x1e13d,
- 0x1e140, 0x1e149,
- 0x1e14e, 0x1e14e,
- 0x1e290, 0x1e2ae,
- 0x1e2c0, 0x1e2f9,
- 0x1e4d0, 0x1e4f9,
- 0x1e5d0, 0x1e5fa,
- 0x1e7e0, 0x1e7e6,
- 0x1e7e8, 0x1e7eb,
- 0x1e7ed, 0x1e7ee,
- 0x1e7f0, 0x1e7fe,
- 0x1e800, 0x1e8c4,
- 0x1e8d0, 0x1e8d6,
- 0x1e900, 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,
- 0x1fbf0, 0x1fbf9,
- 0x20000, 0x2a6df,
- 0x2a700, 0x2b739,
- 0x2b740, 0x2b81d,
- 0x2b820, 0x2cea1,
- 0x2ceb0, 0x2ebe0,
- 0x2ebf0, 0x2ee5d,
- 0x2f800, 0x2fa1d,
- 0x30000, 0x3134a,
- 0x31350, 0x323af,
- 0xe0100, 0xe01ef,
-}; /* CR_ID_Continue */
-
-/* 'XID_Start': Derived Property */
-static const OnigCodePoint CR_XID_Start[] = {
- 684,
- 0x0041, 0x005a,
- 0x0061, 0x007a,
- 0x00aa, 0x00aa,
- 0x00b5, 0x00b5,
- 0x00ba, 0x00ba,
- 0x00c0, 0x00d6,
- 0x00d8, 0x00f6,
- 0x00f8, 0x02c1,
- 0x02c6, 0x02d1,
- 0x02e0, 0x02e4,
- 0x02ec, 0x02ec,
- 0x02ee, 0x02ee,
- 0x0370, 0x0374,
- 0x0376, 0x0377,
- 0x037b, 0x037d,
- 0x037f, 0x037f,
- 0x0386, 0x0386,
- 0x0388, 0x038a,
- 0x038c, 0x038c,
- 0x038e, 0x03a1,
- 0x03a3, 0x03f5,
- 0x03f7, 0x0481,
- 0x048a, 0x052f,
- 0x0531, 0x0556,
- 0x0559, 0x0559,
- 0x0560, 0x0588,
- 0x05d0, 0x05ea,
- 0x05ef, 0x05f2,
- 0x0620, 0x064a,
- 0x066e, 0x066f,
- 0x0671, 0x06d3,
- 0x06d5, 0x06d5,
- 0x06e5, 0x06e6,
- 0x06ee, 0x06ef,
- 0x06fa, 0x06fc,
- 0x06ff, 0x06ff,
- 0x0710, 0x0710,
- 0x0712, 0x072f,
- 0x074d, 0x07a5,
- 0x07b1, 0x07b1,
- 0x07ca, 0x07ea,
- 0x07f4, 0x07f5,
- 0x07fa, 0x07fa,
- 0x0800, 0x0815,
- 0x081a, 0x081a,
- 0x0824, 0x0824,
- 0x0828, 0x0828,
- 0x0840, 0x0858,
- 0x0860, 0x086a,
- 0x0870, 0x0887,
- 0x0889, 0x088e,
- 0x08a0, 0x08c9,
- 0x0904, 0x0939,
- 0x093d, 0x093d,
- 0x0950, 0x0950,
- 0x0958, 0x0961,
- 0x0971, 0x0980,
- 0x0985, 0x098c,
- 0x098f, 0x0990,
- 0x0993, 0x09a8,
- 0x09aa, 0x09b0,
- 0x09b2, 0x09b2,
- 0x09b6, 0x09b9,
- 0x09bd, 0x09bd,
- 0x09ce, 0x09ce,
- 0x09dc, 0x09dd,
- 0x09df, 0x09e1,
- 0x09f0, 0x09f1,
- 0x09fc, 0x09fc,
- 0x0a05, 0x0a0a,
- 0x0a0f, 0x0a10,
- 0x0a13, 0x0a28,
- 0x0a2a, 0x0a30,
- 0x0a32, 0x0a33,
- 0x0a35, 0x0a36,
- 0x0a38, 0x0a39,
- 0x0a59, 0x0a5c,
- 0x0a5e, 0x0a5e,
- 0x0a72, 0x0a74,
- 0x0a85, 0x0a8d,
- 0x0a8f, 0x0a91,
- 0x0a93, 0x0aa8,
- 0x0aaa, 0x0ab0,
- 0x0ab2, 0x0ab3,
- 0x0ab5, 0x0ab9,
- 0x0abd, 0x0abd,
- 0x0ad0, 0x0ad0,
- 0x0ae0, 0x0ae1,
- 0x0af9, 0x0af9,
- 0x0b05, 0x0b0c,
- 0x0b0f, 0x0b10,
- 0x0b13, 0x0b28,
- 0x0b2a, 0x0b30,
- 0x0b32, 0x0b33,
- 0x0b35, 0x0b39,
- 0x0b3d, 0x0b3d,
- 0x0b5c, 0x0b5d,
- 0x0b5f, 0x0b61,
- 0x0b71, 0x0b71,
- 0x0b83, 0x0b83,
- 0x0b85, 0x0b8a,
- 0x0b8e, 0x0b90,
- 0x0b92, 0x0b95,
- 0x0b99, 0x0b9a,
- 0x0b9c, 0x0b9c,
- 0x0b9e, 0x0b9f,
- 0x0ba3, 0x0ba4,
- 0x0ba8, 0x0baa,
- 0x0bae, 0x0bb9,
- 0x0bd0, 0x0bd0,
- 0x0c05, 0x0c0c,
- 0x0c0e, 0x0c10,
- 0x0c12, 0x0c28,
- 0x0c2a, 0x0c39,
- 0x0c3d, 0x0c3d,
- 0x0c58, 0x0c5a,
- 0x0c5d, 0x0c5d,
- 0x0c60, 0x0c61,
- 0x0c80, 0x0c80,
- 0x0c85, 0x0c8c,
- 0x0c8e, 0x0c90,
- 0x0c92, 0x0ca8,
- 0x0caa, 0x0cb3,
- 0x0cb5, 0x0cb9,
- 0x0cbd, 0x0cbd,
- 0x0cdd, 0x0cde,
- 0x0ce0, 0x0ce1,
- 0x0cf1, 0x0cf2,
- 0x0d04, 0x0d0c,
- 0x0d0e, 0x0d10,
- 0x0d12, 0x0d3a,
- 0x0d3d, 0x0d3d,
- 0x0d4e, 0x0d4e,
- 0x0d54, 0x0d56,
- 0x0d5f, 0x0d61,
- 0x0d7a, 0x0d7f,
- 0x0d85, 0x0d96,
- 0x0d9a, 0x0db1,
- 0x0db3, 0x0dbb,
- 0x0dbd, 0x0dbd,
- 0x0dc0, 0x0dc6,
- 0x0e01, 0x0e30,
- 0x0e32, 0x0e32,
- 0x0e40, 0x0e46,
- 0x0e81, 0x0e82,
- 0x0e84, 0x0e84,
- 0x0e86, 0x0e8a,
- 0x0e8c, 0x0ea3,
- 0x0ea5, 0x0ea5,
- 0x0ea7, 0x0eb0,
- 0x0eb2, 0x0eb2,
- 0x0ebd, 0x0ebd,
- 0x0ec0, 0x0ec4,
- 0x0ec6, 0x0ec6,
- 0x0edc, 0x0edf,
- 0x0f00, 0x0f00,
- 0x0f40, 0x0f47,
- 0x0f49, 0x0f6c,
- 0x0f88, 0x0f8c,
- 0x1000, 0x102a,
- 0x103f, 0x103f,
- 0x1050, 0x1055,
- 0x105a, 0x105d,
- 0x1061, 0x1061,
- 0x1065, 0x1066,
- 0x106e, 0x1070,
- 0x1075, 0x1081,
- 0x108e, 0x108e,
- 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, 0x1711,
- 0x171f, 0x1731,
- 0x1740, 0x1751,
- 0x1760, 0x176c,
- 0x176e, 0x1770,
- 0x1780, 0x17b3,
- 0x17d7, 0x17d7,
- 0x17dc, 0x17dc,
- 0x1820, 0x1878,
- 0x1880, 0x18a8,
- 0x18aa, 0x18aa,
- 0x18b0, 0x18f5,
- 0x1900, 0x191e,
- 0x1950, 0x196d,
- 0x1970, 0x1974,
- 0x1980, 0x19ab,
- 0x19b0, 0x19c9,
- 0x1a00, 0x1a16,
- 0x1a20, 0x1a54,
- 0x1aa7, 0x1aa7,
- 0x1b05, 0x1b33,
- 0x1b45, 0x1b4c,
- 0x1b83, 0x1ba0,
- 0x1bae, 0x1baf,
- 0x1bba, 0x1be5,
- 0x1c00, 0x1c23,
- 0x1c4d, 0x1c4f,
- 0x1c5a, 0x1c7d,
- 0x1c80, 0x1c8a,
- 0x1c90, 0x1cba,
- 0x1cbd, 0x1cbf,
- 0x1ce9, 0x1cec,
- 0x1cee, 0x1cf3,
- 0x1cf5, 0x1cf6,
- 0x1cfa, 0x1cfa,
- 0x1d00, 0x1dbf,
- 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,
- 0x2118, 0x211d,
- 0x2124, 0x2124,
- 0x2126, 0x2126,
- 0x2128, 0x2128,
- 0x212a, 0x2139,
- 0x213c, 0x213f,
- 0x2145, 0x2149,
- 0x214e, 0x214e,
- 0x2160, 0x2188,
- 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,
- 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,
- 0xa67f, 0xa69d,
- 0xa6a0, 0xa6ef,
- 0xa717, 0xa71f,
- 0xa722, 0xa788,
- 0xa78b, 0xa7cd,
- 0xa7d0, 0xa7d1,
- 0xa7d3, 0xa7d3,
- 0xa7d5, 0xa7dc,
- 0xa7f2, 0xa801,
- 0xa803, 0xa805,
- 0xa807, 0xa80a,
- 0xa80c, 0xa822,
- 0xa840, 0xa873,
- 0xa882, 0xa8b3,
- 0xa8f2, 0xa8f7,
- 0xa8fb, 0xa8fb,
- 0xa8fd, 0xa8fe,
- 0xa90a, 0xa925,
- 0xa930, 0xa946,
- 0xa960, 0xa97c,
- 0xa984, 0xa9b2,
- 0xa9cf, 0xa9cf,
- 0xa9e0, 0xa9e4,
- 0xa9e6, 0xa9ef,
- 0xa9fa, 0xa9fe,
- 0xaa00, 0xaa28,
- 0xaa40, 0xaa42,
- 0xaa44, 0xaa4b,
- 0xaa60, 0xaa76,
- 0xaa7a, 0xaa7a,
- 0xaa7e, 0xaaaf,
- 0xaab1, 0xaab1,
- 0xaab5, 0xaab6,
- 0xaab9, 0xaabd,
- 0xaac0, 0xaac0,
- 0xaac2, 0xaac2,
- 0xaadb, 0xaadd,
- 0xaae0, 0xaaea,
- 0xaaf2, 0xaaf4,
- 0xab01, 0xab06,
- 0xab09, 0xab0e,
- 0xab11, 0xab16,
- 0xab20, 0xab26,
- 0xab28, 0xab2e,
- 0xab30, 0xab5a,
- 0xab5c, 0xab69,
- 0xab70, 0xabe2,
- 0xac00, 0xd7a3,
- 0xd7b0, 0xd7c6,
- 0xd7cb, 0xd7fb,
- 0xf900, 0xfa6d,
- 0xfa70, 0xfad9,
- 0xfb00, 0xfb06,
- 0xfb13, 0xfb17,
- 0xfb1d, 0xfb1d,
- 0xfb1f, 0xfb28,
- 0xfb2a, 0xfb36,
- 0xfb38, 0xfb3c,
- 0xfb3e, 0xfb3e,
- 0xfb40, 0xfb41,
- 0xfb43, 0xfb44,
- 0xfb46, 0xfbb1,
- 0xfbd3, 0xfc5d,
- 0xfc64, 0xfd3d,
- 0xfd50, 0xfd8f,
- 0xfd92, 0xfdc7,
- 0xfdf0, 0xfdf9,
- 0xfe71, 0xfe71,
- 0xfe73, 0xfe73,
- 0xfe77, 0xfe77,
- 0xfe79, 0xfe79,
- 0xfe7b, 0xfe7b,
- 0xfe7d, 0xfe7d,
- 0xfe7f, 0xfefc,
- 0xff21, 0xff3a,
- 0xff41, 0xff5a,
- 0xff66, 0xff9d,
- 0xffa0, 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, 0x10375,
- 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,
- 0x105c0, 0x105f3,
- 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, 0x10a00,
- 0x10a10, 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, 0x10d23,
- 0x10d4a, 0x10d65,
- 0x10d6f, 0x10d85,
- 0x10e80, 0x10ea9,
- 0x10eb0, 0x10eb1,
- 0x10ec2, 0x10ec4,
- 0x10f00, 0x10f1c,
- 0x10f27, 0x10f27,
- 0x10f30, 0x10f45,
- 0x10f70, 0x10f81,
- 0x10fb0, 0x10fc4,
- 0x10fe0, 0x10ff6,
- 0x11003, 0x11037,
- 0x11071, 0x11072,
- 0x11075, 0x11075,
- 0x11083, 0x110af,
- 0x110d0, 0x110e8,
- 0x11103, 0x11126,
- 0x11144, 0x11144,
- 0x11147, 0x11147,
- 0x11150, 0x11172,
- 0x11176, 0x11176,
- 0x11183, 0x111b2,
- 0x111c1, 0x111c4,
- 0x111da, 0x111da,
- 0x111dc, 0x111dc,
- 0x11200, 0x11211,
- 0x11213, 0x1122b,
- 0x1123f, 0x11240,
- 0x11280, 0x11286,
- 0x11288, 0x11288,
- 0x1128a, 0x1128d,
- 0x1128f, 0x1129d,
- 0x1129f, 0x112a8,
- 0x112b0, 0x112de,
- 0x11305, 0x1130c,
- 0x1130f, 0x11310,
- 0x11313, 0x11328,
- 0x1132a, 0x11330,
- 0x11332, 0x11333,
- 0x11335, 0x11339,
- 0x1133d, 0x1133d,
- 0x11350, 0x11350,
- 0x1135d, 0x11361,
- 0x11380, 0x11389,
- 0x1138b, 0x1138b,
- 0x1138e, 0x1138e,
- 0x11390, 0x113b5,
- 0x113b7, 0x113b7,
- 0x113d1, 0x113d1,
- 0x113d3, 0x113d3,
- 0x11400, 0x11434,
- 0x11447, 0x1144a,
- 0x1145f, 0x11461,
- 0x11480, 0x114af,
- 0x114c4, 0x114c5,
- 0x114c7, 0x114c7,
- 0x11580, 0x115ae,
- 0x115d8, 0x115db,
- 0x11600, 0x1162f,
- 0x11644, 0x11644,
- 0x11680, 0x116aa,
- 0x116b8, 0x116b8,
- 0x11700, 0x1171a,
- 0x11740, 0x11746,
- 0x11800, 0x1182b,
- 0x118a0, 0x118df,
- 0x118ff, 0x11906,
- 0x11909, 0x11909,
- 0x1190c, 0x11913,
- 0x11915, 0x11916,
- 0x11918, 0x1192f,
- 0x1193f, 0x1193f,
- 0x11941, 0x11941,
- 0x119a0, 0x119a7,
- 0x119aa, 0x119d0,
- 0x119e1, 0x119e1,
- 0x119e3, 0x119e3,
- 0x11a00, 0x11a00,
- 0x11a0b, 0x11a32,
- 0x11a3a, 0x11a3a,
- 0x11a50, 0x11a50,
- 0x11a5c, 0x11a89,
- 0x11a9d, 0x11a9d,
- 0x11ab0, 0x11af8,
- 0x11bc0, 0x11be0,
- 0x11c00, 0x11c08,
- 0x11c0a, 0x11c2e,
- 0x11c40, 0x11c40,
- 0x11c72, 0x11c8f,
- 0x11d00, 0x11d06,
- 0x11d08, 0x11d09,
- 0x11d0b, 0x11d30,
- 0x11d46, 0x11d46,
- 0x11d60, 0x11d65,
- 0x11d67, 0x11d68,
- 0x11d6a, 0x11d89,
- 0x11d98, 0x11d98,
- 0x11ee0, 0x11ef2,
- 0x11f02, 0x11f02,
- 0x11f04, 0x11f10,
- 0x11f12, 0x11f33,
- 0x11fb0, 0x11fb0,
- 0x12000, 0x12399,
- 0x12400, 0x1246e,
- 0x12480, 0x12543,
- 0x12f90, 0x12ff0,
- 0x13000, 0x1342f,
- 0x13441, 0x13446,
- 0x13460, 0x143fa,
- 0x14400, 0x14646,
- 0x16100, 0x1611d,
- 0x16800, 0x16a38,
- 0x16a40, 0x16a5e,
- 0x16a70, 0x16abe,
- 0x16ad0, 0x16aed,
- 0x16b00, 0x16b2f,
- 0x16b40, 0x16b43,
- 0x16b63, 0x16b77,
- 0x16b7d, 0x16b8f,
- 0x16d40, 0x16d6c,
- 0x16e40, 0x16e7f,
- 0x16f00, 0x16f4a,
- 0x16f50, 0x16f50,
- 0x16f93, 0x16f9f,
- 0x16fe0, 0x16fe1,
- 0x16fe3, 0x16fe3,
- 0x17000, 0x187f7,
- 0x18800, 0x18cd5,
- 0x18cff, 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,
- 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,
- 0x1e030, 0x1e06d,
- 0x1e100, 0x1e12c,
- 0x1e137, 0x1e13d,
- 0x1e14e, 0x1e14e,
- 0x1e290, 0x1e2ad,
- 0x1e2c0, 0x1e2eb,
- 0x1e4d0, 0x1e4eb,
- 0x1e5d0, 0x1e5ed,
- 0x1e5f0, 0x1e5f0,
- 0x1e7e0, 0x1e7e6,
- 0x1e7e8, 0x1e7eb,
- 0x1e7ed, 0x1e7ee,
- 0x1e7f0, 0x1e7fe,
- 0x1e800, 0x1e8c4,
- 0x1e900, 0x1e943,
- 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,
- 0x20000, 0x2a6df,
- 0x2a700, 0x2b739,
- 0x2b740, 0x2b81d,
- 0x2b820, 0x2cea1,
- 0x2ceb0, 0x2ebe0,
- 0x2ebf0, 0x2ee5d,
- 0x2f800, 0x2fa1d,
- 0x30000, 0x3134a,
- 0x31350, 0x323af,
-}; /* CR_XID_Start */
-
-/* 'XID_Continue': Derived Property */
-static const OnigCodePoint CR_XID_Continue[] = {
- 800,
- 0x0030, 0x0039,
- 0x0041, 0x005a,
- 0x005f, 0x005f,
- 0x0061, 0x007a,
- 0x00aa, 0x00aa,
- 0x00b5, 0x00b5,
- 0x00b7, 0x00b7,
- 0x00ba, 0x00ba,
- 0x00c0, 0x00d6,
- 0x00d8, 0x00f6,
- 0x00f8, 0x02c1,
- 0x02c6, 0x02d1,
- 0x02e0, 0x02e4,
- 0x02ec, 0x02ec,
- 0x02ee, 0x02ee,
- 0x0300, 0x0374,
- 0x0376, 0x0377,
- 0x037b, 0x037d,
- 0x037f, 0x037f,
- 0x0386, 0x038a,
- 0x038c, 0x038c,
- 0x038e, 0x03a1,
- 0x03a3, 0x03f5,
- 0x03f7, 0x0481,
- 0x0483, 0x0487,
- 0x048a, 0x052f,
- 0x0531, 0x0556,
- 0x0559, 0x0559,
- 0x0560, 0x0588,
- 0x0591, 0x05bd,
- 0x05bf, 0x05bf,
- 0x05c1, 0x05c2,
- 0x05c4, 0x05c5,
- 0x05c7, 0x05c7,
- 0x05d0, 0x05ea,
- 0x05ef, 0x05f2,
- 0x0610, 0x061a,
- 0x0620, 0x0669,
- 0x066e, 0x06d3,
- 0x06d5, 0x06dc,
- 0x06df, 0x06e8,
- 0x06ea, 0x06fc,
- 0x06ff, 0x06ff,
- 0x0710, 0x074a,
- 0x074d, 0x07b1,
- 0x07c0, 0x07f5,
- 0x07fa, 0x07fa,
- 0x07fd, 0x07fd,
- 0x0800, 0x082d,
- 0x0840, 0x085b,
- 0x0860, 0x086a,
- 0x0870, 0x0887,
- 0x0889, 0x088e,
- 0x0897, 0x08e1,
- 0x08e3, 0x0963,
- 0x0966, 0x096f,
- 0x0971, 0x0983,
- 0x0985, 0x098c,
- 0x098f, 0x0990,
- 0x0993, 0x09a8,
- 0x09aa, 0x09b0,
- 0x09b2, 0x09b2,
- 0x09b6, 0x09b9,
- 0x09bc, 0x09c4,
- 0x09c7, 0x09c8,
- 0x09cb, 0x09ce,
- 0x09d7, 0x09d7,
- 0x09dc, 0x09dd,
- 0x09df, 0x09e3,
- 0x09e6, 0x09f1,
- 0x09fc, 0x09fc,
- 0x09fe, 0x09fe,
- 0x0a01, 0x0a03,
- 0x0a05, 0x0a0a,
- 0x0a0f, 0x0a10,
- 0x0a13, 0x0a28,
- 0x0a2a, 0x0a30,
- 0x0a32, 0x0a33,
- 0x0a35, 0x0a36,
- 0x0a38, 0x0a39,
- 0x0a3c, 0x0a3c,
- 0x0a3e, 0x0a42,
- 0x0a47, 0x0a48,
- 0x0a4b, 0x0a4d,
- 0x0a51, 0x0a51,
- 0x0a59, 0x0a5c,
- 0x0a5e, 0x0a5e,
- 0x0a66, 0x0a75,
- 0x0a81, 0x0a83,
- 0x0a85, 0x0a8d,
- 0x0a8f, 0x0a91,
- 0x0a93, 0x0aa8,
- 0x0aaa, 0x0ab0,
- 0x0ab2, 0x0ab3,
- 0x0ab5, 0x0ab9,
- 0x0abc, 0x0ac5,
- 0x0ac7, 0x0ac9,
- 0x0acb, 0x0acd,
- 0x0ad0, 0x0ad0,
- 0x0ae0, 0x0ae3,
- 0x0ae6, 0x0aef,
- 0x0af9, 0x0aff,
- 0x0b01, 0x0b03,
- 0x0b05, 0x0b0c,
- 0x0b0f, 0x0b10,
- 0x0b13, 0x0b28,
- 0x0b2a, 0x0b30,
- 0x0b32, 0x0b33,
- 0x0b35, 0x0b39,
- 0x0b3c, 0x0b44,
- 0x0b47, 0x0b48,
- 0x0b4b, 0x0b4d,
- 0x0b55, 0x0b57,
- 0x0b5c, 0x0b5d,
- 0x0b5f, 0x0b63,
- 0x0b66, 0x0b6f,
- 0x0b71, 0x0b71,
- 0x0b82, 0x0b83,
- 0x0b85, 0x0b8a,
- 0x0b8e, 0x0b90,
- 0x0b92, 0x0b95,
- 0x0b99, 0x0b9a,
- 0x0b9c, 0x0b9c,
- 0x0b9e, 0x0b9f,
- 0x0ba3, 0x0ba4,
- 0x0ba8, 0x0baa,
- 0x0bae, 0x0bb9,
- 0x0bbe, 0x0bc2,
- 0x0bc6, 0x0bc8,
- 0x0bca, 0x0bcd,
- 0x0bd0, 0x0bd0,
- 0x0bd7, 0x0bd7,
- 0x0be6, 0x0bef,
- 0x0c00, 0x0c0c,
- 0x0c0e, 0x0c10,
- 0x0c12, 0x0c28,
- 0x0c2a, 0x0c39,
- 0x0c3c, 0x0c44,
- 0x0c46, 0x0c48,
- 0x0c4a, 0x0c4d,
- 0x0c55, 0x0c56,
- 0x0c58, 0x0c5a,
- 0x0c5d, 0x0c5d,
- 0x0c60, 0x0c63,
- 0x0c66, 0x0c6f,
- 0x0c80, 0x0c83,
- 0x0c85, 0x0c8c,
- 0x0c8e, 0x0c90,
- 0x0c92, 0x0ca8,
- 0x0caa, 0x0cb3,
- 0x0cb5, 0x0cb9,
- 0x0cbc, 0x0cc4,
- 0x0cc6, 0x0cc8,
- 0x0cca, 0x0ccd,
- 0x0cd5, 0x0cd6,
- 0x0cdd, 0x0cde,
- 0x0ce0, 0x0ce3,
- 0x0ce6, 0x0cef,
- 0x0cf1, 0x0cf3,
- 0x0d00, 0x0d0c,
- 0x0d0e, 0x0d10,
- 0x0d12, 0x0d44,
- 0x0d46, 0x0d48,
- 0x0d4a, 0x0d4e,
- 0x0d54, 0x0d57,
- 0x0d5f, 0x0d63,
- 0x0d66, 0x0d6f,
- 0x0d7a, 0x0d7f,
- 0x0d81, 0x0d83,
- 0x0d85, 0x0d96,
- 0x0d9a, 0x0db1,
- 0x0db3, 0x0dbb,
- 0x0dbd, 0x0dbd,
- 0x0dc0, 0x0dc6,
- 0x0dca, 0x0dca,
- 0x0dcf, 0x0dd4,
- 0x0dd6, 0x0dd6,
- 0x0dd8, 0x0ddf,
- 0x0de6, 0x0def,
- 0x0df2, 0x0df3,
- 0x0e01, 0x0e3a,
- 0x0e40, 0x0e4e,
- 0x0e50, 0x0e59,
- 0x0e81, 0x0e82,
- 0x0e84, 0x0e84,
- 0x0e86, 0x0e8a,
- 0x0e8c, 0x0ea3,
- 0x0ea5, 0x0ea5,
- 0x0ea7, 0x0ebd,
- 0x0ec0, 0x0ec4,
- 0x0ec6, 0x0ec6,
- 0x0ec8, 0x0ece,
- 0x0ed0, 0x0ed9,
- 0x0edc, 0x0edf,
- 0x0f00, 0x0f00,
- 0x0f18, 0x0f19,
- 0x0f20, 0x0f29,
- 0x0f35, 0x0f35,
- 0x0f37, 0x0f37,
- 0x0f39, 0x0f39,
- 0x0f3e, 0x0f47,
- 0x0f49, 0x0f6c,
- 0x0f71, 0x0f84,
- 0x0f86, 0x0f97,
- 0x0f99, 0x0fbc,
- 0x0fc6, 0x0fc6,
- 0x1000, 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,
- 0x135d, 0x135f,
- 0x1369, 0x1371,
- 0x1380, 0x138f,
- 0x13a0, 0x13f5,
- 0x13f8, 0x13fd,
- 0x1401, 0x166c,
- 0x166f, 0x167f,
- 0x1681, 0x169a,
- 0x16a0, 0x16ea,
- 0x16ee, 0x16f8,
- 0x1700, 0x1715,
- 0x171f, 0x1734,
- 0x1740, 0x1753,
- 0x1760, 0x176c,
- 0x176e, 0x1770,
- 0x1772, 0x1773,
- 0x1780, 0x17d3,
- 0x17d7, 0x17d7,
- 0x17dc, 0x17dd,
- 0x17e0, 0x17e9,
- 0x180b, 0x180d,
- 0x180f, 0x1819,
- 0x1820, 0x1878,
- 0x1880, 0x18aa,
- 0x18b0, 0x18f5,
- 0x1900, 0x191e,
- 0x1920, 0x192b,
- 0x1930, 0x193b,
- 0x1946, 0x196d,
- 0x1970, 0x1974,
- 0x1980, 0x19ab,
- 0x19b0, 0x19c9,
- 0x19d0, 0x19da,
- 0x1a00, 0x1a1b,
- 0x1a20, 0x1a5e,
- 0x1a60, 0x1a7c,
- 0x1a7f, 0x1a89,
- 0x1a90, 0x1a99,
- 0x1aa7, 0x1aa7,
- 0x1ab0, 0x1abd,
- 0x1abf, 0x1ace,
- 0x1b00, 0x1b4c,
- 0x1b50, 0x1b59,
- 0x1b6b, 0x1b73,
- 0x1b80, 0x1bf3,
- 0x1c00, 0x1c37,
- 0x1c40, 0x1c49,
- 0x1c4d, 0x1c7d,
- 0x1c80, 0x1c8a,
- 0x1c90, 0x1cba,
- 0x1cbd, 0x1cbf,
- 0x1cd0, 0x1cd2,
- 0x1cd4, 0x1cfa,
- 0x1d00, 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,
- 0x200c, 0x200d,
- 0x203f, 0x2040,
- 0x2054, 0x2054,
- 0x2071, 0x2071,
- 0x207f, 0x207f,
- 0x2090, 0x209c,
- 0x20d0, 0x20dc,
- 0x20e1, 0x20e1,
- 0x20e5, 0x20f0,
- 0x2102, 0x2102,
- 0x2107, 0x2107,
- 0x210a, 0x2113,
- 0x2115, 0x2115,
- 0x2118, 0x211d,
- 0x2124, 0x2124,
- 0x2126, 0x2126,
- 0x2128, 0x2128,
- 0x212a, 0x2139,
- 0x213c, 0x213f,
- 0x2145, 0x2149,
- 0x214e, 0x214e,
- 0x2160, 0x2188,
- 0x2c00, 0x2ce4,
- 0x2ceb, 0x2cf3,
- 0x2d00, 0x2d25,
- 0x2d27, 0x2d27,
- 0x2d2d, 0x2d2d,
- 0x2d30, 0x2d67,
- 0x2d6f, 0x2d6f,
- 0x2d7f, 0x2d96,
- 0x2da0, 0x2da6,
- 0x2da8, 0x2dae,
- 0x2db0, 0x2db6,
- 0x2db8, 0x2dbe,
- 0x2dc0, 0x2dc6,
- 0x2dc8, 0x2dce,
- 0x2dd0, 0x2dd6,
- 0x2dd8, 0x2dde,
- 0x2de0, 0x2dff,
- 0x3005, 0x3007,
- 0x3021, 0x302f,
- 0x3031, 0x3035,
- 0x3038, 0x303c,
- 0x3041, 0x3096,
- 0x3099, 0x309a,
- 0x309d, 0x309f,
- 0x30a1, 0x30ff,
- 0x3105, 0x312f,
- 0x3131, 0x318e,
- 0x31a0, 0x31bf,
- 0x31f0, 0x31ff,
- 0x3400, 0x4dbf,
- 0x4e00, 0xa48c,
- 0xa4d0, 0xa4fd,
- 0xa500, 0xa60c,
- 0xa610, 0xa62b,
- 0xa640, 0xa66f,
- 0xa674, 0xa67d,
- 0xa67f, 0xa6f1,
- 0xa717, 0xa71f,
- 0xa722, 0xa788,
- 0xa78b, 0xa7cd,
- 0xa7d0, 0xa7d1,
- 0xa7d3, 0xa7d3,
- 0xa7d5, 0xa7dc,
- 0xa7f2, 0xa827,
- 0xa82c, 0xa82c,
- 0xa840, 0xa873,
- 0xa880, 0xa8c5,
- 0xa8d0, 0xa8d9,
- 0xa8e0, 0xa8f7,
- 0xa8fb, 0xa8fb,
- 0xa8fd, 0xa92d,
- 0xa930, 0xa953,
- 0xa960, 0xa97c,
- 0xa980, 0xa9c0,
- 0xa9cf, 0xa9d9,
- 0xa9e0, 0xa9fe,
- 0xaa00, 0xaa36,
- 0xaa40, 0xaa4d,
- 0xaa50, 0xaa59,
- 0xaa60, 0xaa76,
- 0xaa7a, 0xaac2,
- 0xaadb, 0xaadd,
- 0xaae0, 0xaaef,
- 0xaaf2, 0xaaf6,
- 0xab01, 0xab06,
- 0xab09, 0xab0e,
- 0xab11, 0xab16,
- 0xab20, 0xab26,
- 0xab28, 0xab2e,
- 0xab30, 0xab5a,
- 0xab5c, 0xab69,
- 0xab70, 0xabea,
- 0xabec, 0xabed,
- 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, 0xfc5d,
- 0xfc64, 0xfd3d,
- 0xfd50, 0xfd8f,
- 0xfd92, 0xfdc7,
- 0xfdf0, 0xfdf9,
- 0xfe00, 0xfe0f,
- 0xfe20, 0xfe2f,
- 0xfe33, 0xfe34,
- 0xfe4d, 0xfe4f,
- 0xfe71, 0xfe71,
- 0xfe73, 0xfe73,
- 0xfe77, 0xfe77,
- 0xfe79, 0xfe79,
- 0xfe7b, 0xfe7b,
- 0xfe7d, 0xfe7d,
- 0xfe7f, 0xfefc,
- 0xff10, 0xff19,
- 0xff21, 0xff3a,
- 0xff3f, 0xff3f,
- 0xff41, 0xff5a,
- 0xff65, 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,
- 0x101fd, 0x101fd,
- 0x10280, 0x1029c,
- 0x102a0, 0x102d0,
- 0x102e0, 0x102e0,
- 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,
- 0x105c0, 0x105f3,
- 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,
- 0x10a38, 0x10a3a,
- 0x10a3f, 0x10a3f,
- 0x10a60, 0x10a7c,
- 0x10a80, 0x10a9c,
- 0x10ac0, 0x10ac7,
- 0x10ac9, 0x10ae6,
- 0x10b00, 0x10b35,
- 0x10b40, 0x10b55,
- 0x10b60, 0x10b72,
- 0x10b80, 0x10b91,
- 0x10c00, 0x10c48,
- 0x10c80, 0x10cb2,
- 0x10cc0, 0x10cf2,
- 0x10d00, 0x10d27,
- 0x10d30, 0x10d39,
- 0x10d40, 0x10d65,
- 0x10d69, 0x10d6d,
- 0x10d6f, 0x10d85,
- 0x10e80, 0x10ea9,
- 0x10eab, 0x10eac,
- 0x10eb0, 0x10eb1,
- 0x10ec2, 0x10ec4,
- 0x10efc, 0x10f1c,
- 0x10f27, 0x10f27,
- 0x10f30, 0x10f50,
- 0x10f70, 0x10f85,
- 0x10fb0, 0x10fc4,
- 0x10fe0, 0x10ff6,
- 0x11000, 0x11046,
- 0x11066, 0x11075,
- 0x1107f, 0x110ba,
- 0x110c2, 0x110c2,
- 0x110d0, 0x110e8,
- 0x110f0, 0x110f9,
- 0x11100, 0x11134,
- 0x11136, 0x1113f,
- 0x11144, 0x11147,
- 0x11150, 0x11173,
- 0x11176, 0x11176,
- 0x11180, 0x111c4,
- 0x111c9, 0x111cc,
- 0x111ce, 0x111da,
- 0x111dc, 0x111dc,
- 0x11200, 0x11211,
- 0x11213, 0x11237,
- 0x1123e, 0x11241,
- 0x11280, 0x11286,
- 0x11288, 0x11288,
- 0x1128a, 0x1128d,
- 0x1128f, 0x1129d,
- 0x1129f, 0x112a8,
- 0x112b0, 0x112ea,
- 0x112f0, 0x112f9,
- 0x11300, 0x11303,
- 0x11305, 0x1130c,
- 0x1130f, 0x11310,
- 0x11313, 0x11328,
- 0x1132a, 0x11330,
- 0x11332, 0x11333,
- 0x11335, 0x11339,
- 0x1133b, 0x11344,
- 0x11347, 0x11348,
- 0x1134b, 0x1134d,
- 0x11350, 0x11350,
- 0x11357, 0x11357,
- 0x1135d, 0x11363,
- 0x11366, 0x1136c,
- 0x11370, 0x11374,
- 0x11380, 0x11389,
- 0x1138b, 0x1138b,
- 0x1138e, 0x1138e,
- 0x11390, 0x113b5,
- 0x113b7, 0x113c0,
- 0x113c2, 0x113c2,
- 0x113c5, 0x113c5,
- 0x113c7, 0x113ca,
- 0x113cc, 0x113d3,
- 0x113e1, 0x113e2,
- 0x11400, 0x1144a,
- 0x11450, 0x11459,
- 0x1145e, 0x11461,
- 0x11480, 0x114c5,
- 0x114c7, 0x114c7,
- 0x114d0, 0x114d9,
- 0x11580, 0x115b5,
- 0x115b8, 0x115c0,
- 0x115d8, 0x115dd,
- 0x11600, 0x11640,
- 0x11644, 0x11644,
- 0x11650, 0x11659,
- 0x11680, 0x116b8,
- 0x116c0, 0x116c9,
- 0x116d0, 0x116e3,
- 0x11700, 0x1171a,
- 0x1171d, 0x1172b,
- 0x11730, 0x11739,
- 0x11740, 0x11746,
- 0x11800, 0x1183a,
- 0x118a0, 0x118e9,
- 0x118ff, 0x11906,
- 0x11909, 0x11909,
- 0x1190c, 0x11913,
- 0x11915, 0x11916,
- 0x11918, 0x11935,
- 0x11937, 0x11938,
- 0x1193b, 0x11943,
- 0x11950, 0x11959,
- 0x119a0, 0x119a7,
- 0x119aa, 0x119d7,
- 0x119da, 0x119e1,
- 0x119e3, 0x119e4,
- 0x11a00, 0x11a3e,
- 0x11a47, 0x11a47,
- 0x11a50, 0x11a99,
- 0x11a9d, 0x11a9d,
- 0x11ab0, 0x11af8,
- 0x11bc0, 0x11be0,
- 0x11bf0, 0x11bf9,
- 0x11c00, 0x11c08,
- 0x11c0a, 0x11c36,
- 0x11c38, 0x11c40,
- 0x11c50, 0x11c59,
- 0x11c72, 0x11c8f,
- 0x11c92, 0x11ca7,
- 0x11ca9, 0x11cb6,
- 0x11d00, 0x11d06,
- 0x11d08, 0x11d09,
- 0x11d0b, 0x11d36,
- 0x11d3a, 0x11d3a,
- 0x11d3c, 0x11d3d,
- 0x11d3f, 0x11d47,
- 0x11d50, 0x11d59,
- 0x11d60, 0x11d65,
- 0x11d67, 0x11d68,
- 0x11d6a, 0x11d8e,
- 0x11d90, 0x11d91,
- 0x11d93, 0x11d98,
- 0x11da0, 0x11da9,
- 0x11ee0, 0x11ef6,
- 0x11f00, 0x11f10,
- 0x11f12, 0x11f3a,
- 0x11f3e, 0x11f42,
- 0x11f50, 0x11f5a,
- 0x11fb0, 0x11fb0,
- 0x12000, 0x12399,
- 0x12400, 0x1246e,
- 0x12480, 0x12543,
- 0x12f90, 0x12ff0,
- 0x13000, 0x1342f,
- 0x13440, 0x13455,
- 0x13460, 0x143fa,
- 0x14400, 0x14646,
- 0x16100, 0x16139,
- 0x16800, 0x16a38,
- 0x16a40, 0x16a5e,
- 0x16a60, 0x16a69,
- 0x16a70, 0x16abe,
- 0x16ac0, 0x16ac9,
- 0x16ad0, 0x16aed,
- 0x16af0, 0x16af4,
- 0x16b00, 0x16b36,
- 0x16b40, 0x16b43,
- 0x16b50, 0x16b59,
- 0x16b63, 0x16b77,
- 0x16b7d, 0x16b8f,
- 0x16d40, 0x16d6c,
- 0x16d70, 0x16d79,
- 0x16e40, 0x16e7f,
- 0x16f00, 0x16f4a,
- 0x16f4f, 0x16f87,
- 0x16f8f, 0x16f9f,
- 0x16fe0, 0x16fe1,
- 0x16fe3, 0x16fe4,
- 0x16ff0, 0x16ff1,
- 0x17000, 0x187f7,
- 0x18800, 0x18cd5,
- 0x18cff, 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,
- 0x1bc9d, 0x1bc9e,
- 0x1ccf0, 0x1ccf9,
- 0x1cf00, 0x1cf2d,
- 0x1cf30, 0x1cf46,
- 0x1d165, 0x1d169,
- 0x1d16d, 0x1d172,
- 0x1d17b, 0x1d182,
- 0x1d185, 0x1d18b,
- 0x1d1aa, 0x1d1ad,
- 0x1d242, 0x1d244,
- 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,
- 0x1da00, 0x1da36,
- 0x1da3b, 0x1da6c,
- 0x1da75, 0x1da75,
- 0x1da84, 0x1da84,
- 0x1da9b, 0x1da9f,
- 0x1daa1, 0x1daaf,
- 0x1df00, 0x1df1e,
- 0x1df25, 0x1df2a,
- 0x1e000, 0x1e006,
- 0x1e008, 0x1e018,
- 0x1e01b, 0x1e021,
- 0x1e023, 0x1e024,
- 0x1e026, 0x1e02a,
- 0x1e030, 0x1e06d,
- 0x1e08f, 0x1e08f,
- 0x1e100, 0x1e12c,
- 0x1e130, 0x1e13d,
- 0x1e140, 0x1e149,
- 0x1e14e, 0x1e14e,
- 0x1e290, 0x1e2ae,
- 0x1e2c0, 0x1e2f9,
- 0x1e4d0, 0x1e4f9,
- 0x1e5d0, 0x1e5fa,
- 0x1e7e0, 0x1e7e6,
- 0x1e7e8, 0x1e7eb,
- 0x1e7ed, 0x1e7ee,
- 0x1e7f0, 0x1e7fe,
- 0x1e800, 0x1e8c4,
- 0x1e8d0, 0x1e8d6,
- 0x1e900, 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,
- 0x1fbf0, 0x1fbf9,
- 0x20000, 0x2a6df,
- 0x2a700, 0x2b739,
- 0x2b740, 0x2b81d,
- 0x2b820, 0x2cea1,
- 0x2ceb0, 0x2ebe0,
- 0x2ebf0, 0x2ee5d,
- 0x2f800, 0x2fa1d,
- 0x30000, 0x3134a,
- 0x31350, 0x323af,
- 0xe0100, 0xe01ef,
-}; /* CR_XID_Continue */
-
-/* 'Default_Ignorable_Code_Point': Derived Property */
-static const OnigCodePoint CR_Default_Ignorable_Code_Point[] = {
- 17,
- 0x00ad, 0x00ad,
- 0x034f, 0x034f,
- 0x061c, 0x061c,
- 0x115f, 0x1160,
- 0x17b4, 0x17b5,
- 0x180b, 0x180f,
- 0x200b, 0x200f,
- 0x202a, 0x202e,
- 0x2060, 0x206f,
- 0x3164, 0x3164,
- 0xfe00, 0xfe0f,
- 0xfeff, 0xfeff,
- 0xffa0, 0xffa0,
- 0xfff0, 0xfff8,
- 0x1bca0, 0x1bca3,
- 0x1d173, 0x1d17a,
- 0xe0000, 0xe0fff,
-}; /* CR_Default_Ignorable_Code_Point */
-
-/* 'Grapheme_Extend': Derived Property */
-static const OnigCodePoint CR_Grapheme_Extend[] = {
- 375,
- 0x0300, 0x036f,
- 0x0483, 0x0489,
- 0x0591, 0x05bd,
- 0x05bf, 0x05bf,
- 0x05c1, 0x05c2,
- 0x05c4, 0x05c5,
- 0x05c7, 0x05c7,
- 0x0610, 0x061a,
- 0x064b, 0x065f,
- 0x0670, 0x0670,
- 0x06d6, 0x06dc,
- 0x06df, 0x06e4,
- 0x06e7, 0x06e8,
- 0x06ea, 0x06ed,
- 0x0711, 0x0711,
- 0x0730, 0x074a,
- 0x07a6, 0x07b0,
- 0x07eb, 0x07f3,
- 0x07fd, 0x07fd,
- 0x0816, 0x0819,
- 0x081b, 0x0823,
- 0x0825, 0x0827,
- 0x0829, 0x082d,
- 0x0859, 0x085b,
- 0x0897, 0x089f,
- 0x08ca, 0x08e1,
- 0x08e3, 0x0902,
- 0x093a, 0x093a,
- 0x093c, 0x093c,
- 0x0941, 0x0948,
- 0x094d, 0x094d,
- 0x0951, 0x0957,
- 0x0962, 0x0963,
- 0x0981, 0x0981,
- 0x09bc, 0x09bc,
- 0x09be, 0x09be,
- 0x09c1, 0x09c4,
- 0x09cd, 0x09cd,
- 0x09d7, 0x09d7,
- 0x09e2, 0x09e3,
- 0x09fe, 0x09fe,
- 0x0a01, 0x0a02,
- 0x0a3c, 0x0a3c,
- 0x0a41, 0x0a42,
- 0x0a47, 0x0a48,
- 0x0a4b, 0x0a4d,
- 0x0a51, 0x0a51,
- 0x0a70, 0x0a71,
- 0x0a75, 0x0a75,
- 0x0a81, 0x0a82,
- 0x0abc, 0x0abc,
- 0x0ac1, 0x0ac5,
- 0x0ac7, 0x0ac8,
- 0x0acd, 0x0acd,
- 0x0ae2, 0x0ae3,
- 0x0afa, 0x0aff,
- 0x0b01, 0x0b01,
- 0x0b3c, 0x0b3c,
- 0x0b3e, 0x0b3f,
- 0x0b41, 0x0b44,
- 0x0b4d, 0x0b4d,
- 0x0b55, 0x0b57,
- 0x0b62, 0x0b63,
- 0x0b82, 0x0b82,
- 0x0bbe, 0x0bbe,
- 0x0bc0, 0x0bc0,
- 0x0bcd, 0x0bcd,
- 0x0bd7, 0x0bd7,
- 0x0c00, 0x0c00,
- 0x0c04, 0x0c04,
- 0x0c3c, 0x0c3c,
- 0x0c3e, 0x0c40,
- 0x0c46, 0x0c48,
- 0x0c4a, 0x0c4d,
- 0x0c55, 0x0c56,
- 0x0c62, 0x0c63,
- 0x0c81, 0x0c81,
- 0x0cbc, 0x0cbc,
- 0x0cbf, 0x0cc0,
- 0x0cc2, 0x0cc2,
- 0x0cc6, 0x0cc8,
- 0x0cca, 0x0ccd,
- 0x0cd5, 0x0cd6,
- 0x0ce2, 0x0ce3,
- 0x0d00, 0x0d01,
- 0x0d3b, 0x0d3c,
- 0x0d3e, 0x0d3e,
- 0x0d41, 0x0d44,
- 0x0d4d, 0x0d4d,
- 0x0d57, 0x0d57,
- 0x0d62, 0x0d63,
- 0x0d81, 0x0d81,
- 0x0dca, 0x0dca,
- 0x0dcf, 0x0dcf,
- 0x0dd2, 0x0dd4,
- 0x0dd6, 0x0dd6,
- 0x0ddf, 0x0ddf,
- 0x0e31, 0x0e31,
- 0x0e34, 0x0e3a,
- 0x0e47, 0x0e4e,
- 0x0eb1, 0x0eb1,
- 0x0eb4, 0x0ebc,
- 0x0ec8, 0x0ece,
- 0x0f18, 0x0f19,
- 0x0f35, 0x0f35,
- 0x0f37, 0x0f37,
- 0x0f39, 0x0f39,
- 0x0f71, 0x0f7e,
- 0x0f80, 0x0f84,
- 0x0f86, 0x0f87,
- 0x0f8d, 0x0f97,
- 0x0f99, 0x0fbc,
- 0x0fc6, 0x0fc6,
- 0x102d, 0x1030,
- 0x1032, 0x1037,
- 0x1039, 0x103a,
- 0x103d, 0x103e,
- 0x1058, 0x1059,
- 0x105e, 0x1060,
- 0x1071, 0x1074,
- 0x1082, 0x1082,
- 0x1085, 0x1086,
- 0x108d, 0x108d,
- 0x109d, 0x109d,
- 0x135d, 0x135f,
- 0x1712, 0x1715,
- 0x1732, 0x1734,
- 0x1752, 0x1753,
- 0x1772, 0x1773,
- 0x17b4, 0x17b5,
- 0x17b7, 0x17bd,
- 0x17c6, 0x17c6,
- 0x17c9, 0x17d3,
- 0x17dd, 0x17dd,
- 0x180b, 0x180d,
- 0x180f, 0x180f,
- 0x1885, 0x1886,
- 0x18a9, 0x18a9,
- 0x1920, 0x1922,
- 0x1927, 0x1928,
- 0x1932, 0x1932,
- 0x1939, 0x193b,
- 0x1a17, 0x1a18,
- 0x1a1b, 0x1a1b,
- 0x1a56, 0x1a56,
- 0x1a58, 0x1a5e,
- 0x1a60, 0x1a60,
- 0x1a62, 0x1a62,
- 0x1a65, 0x1a6c,
- 0x1a73, 0x1a7c,
- 0x1a7f, 0x1a7f,
- 0x1ab0, 0x1ace,
- 0x1b00, 0x1b03,
- 0x1b34, 0x1b3d,
- 0x1b42, 0x1b44,
- 0x1b6b, 0x1b73,
- 0x1b80, 0x1b81,
- 0x1ba2, 0x1ba5,
- 0x1ba8, 0x1bad,
- 0x1be6, 0x1be6,
- 0x1be8, 0x1be9,
- 0x1bed, 0x1bed,
- 0x1bef, 0x1bf3,
- 0x1c2c, 0x1c33,
- 0x1c36, 0x1c37,
- 0x1cd0, 0x1cd2,
- 0x1cd4, 0x1ce0,
- 0x1ce2, 0x1ce8,
- 0x1ced, 0x1ced,
- 0x1cf4, 0x1cf4,
- 0x1cf8, 0x1cf9,
- 0x1dc0, 0x1dff,
- 0x200c, 0x200c,
- 0x20d0, 0x20f0,
- 0x2cef, 0x2cf1,
- 0x2d7f, 0x2d7f,
- 0x2de0, 0x2dff,
- 0x302a, 0x302f,
- 0x3099, 0x309a,
- 0xa66f, 0xa672,
- 0xa674, 0xa67d,
- 0xa69e, 0xa69f,
- 0xa6f0, 0xa6f1,
- 0xa802, 0xa802,
- 0xa806, 0xa806,
- 0xa80b, 0xa80b,
- 0xa825, 0xa826,
- 0xa82c, 0xa82c,
- 0xa8c4, 0xa8c5,
- 0xa8e0, 0xa8f1,
- 0xa8ff, 0xa8ff,
- 0xa926, 0xa92d,
- 0xa947, 0xa951,
- 0xa953, 0xa953,
- 0xa980, 0xa982,
- 0xa9b3, 0xa9b3,
- 0xa9b6, 0xa9b9,
- 0xa9bc, 0xa9bd,
- 0xa9c0, 0xa9c0,
- 0xa9e5, 0xa9e5,
- 0xaa29, 0xaa2e,
- 0xaa31, 0xaa32,
- 0xaa35, 0xaa36,
- 0xaa43, 0xaa43,
- 0xaa4c, 0xaa4c,
- 0xaa7c, 0xaa7c,
- 0xaab0, 0xaab0,
- 0xaab2, 0xaab4,
- 0xaab7, 0xaab8,
- 0xaabe, 0xaabf,
- 0xaac1, 0xaac1,
- 0xaaec, 0xaaed,
- 0xaaf6, 0xaaf6,
- 0xabe5, 0xabe5,
- 0xabe8, 0xabe8,
- 0xabed, 0xabed,
- 0xfb1e, 0xfb1e,
- 0xfe00, 0xfe0f,
- 0xfe20, 0xfe2f,
- 0xff9e, 0xff9f,
- 0x101fd, 0x101fd,
- 0x102e0, 0x102e0,
- 0x10376, 0x1037a,
- 0x10a01, 0x10a03,
- 0x10a05, 0x10a06,
- 0x10a0c, 0x10a0f,
- 0x10a38, 0x10a3a,
- 0x10a3f, 0x10a3f,
- 0x10ae5, 0x10ae6,
- 0x10d24, 0x10d27,
- 0x10d69, 0x10d6d,
- 0x10eab, 0x10eac,
- 0x10efc, 0x10eff,
- 0x10f46, 0x10f50,
- 0x10f82, 0x10f85,
- 0x11001, 0x11001,
- 0x11038, 0x11046,
- 0x11070, 0x11070,
- 0x11073, 0x11074,
- 0x1107f, 0x11081,
- 0x110b3, 0x110b6,
- 0x110b9, 0x110ba,
- 0x110c2, 0x110c2,
- 0x11100, 0x11102,
- 0x11127, 0x1112b,
- 0x1112d, 0x11134,
- 0x11173, 0x11173,
- 0x11180, 0x11181,
- 0x111b6, 0x111be,
- 0x111c0, 0x111c0,
- 0x111c9, 0x111cc,
- 0x111cf, 0x111cf,
- 0x1122f, 0x11231,
- 0x11234, 0x11237,
- 0x1123e, 0x1123e,
- 0x11241, 0x11241,
- 0x112df, 0x112df,
- 0x112e3, 0x112ea,
- 0x11300, 0x11301,
- 0x1133b, 0x1133c,
- 0x1133e, 0x1133e,
- 0x11340, 0x11340,
- 0x1134d, 0x1134d,
- 0x11357, 0x11357,
- 0x11366, 0x1136c,
- 0x11370, 0x11374,
- 0x113b8, 0x113b8,
- 0x113bb, 0x113c0,
- 0x113c2, 0x113c2,
- 0x113c5, 0x113c5,
- 0x113c7, 0x113c9,
- 0x113ce, 0x113d0,
- 0x113d2, 0x113d2,
- 0x113e1, 0x113e2,
- 0x11438, 0x1143f,
- 0x11442, 0x11444,
- 0x11446, 0x11446,
- 0x1145e, 0x1145e,
- 0x114b0, 0x114b0,
- 0x114b3, 0x114b8,
- 0x114ba, 0x114ba,
- 0x114bd, 0x114bd,
- 0x114bf, 0x114c0,
- 0x114c2, 0x114c3,
- 0x115af, 0x115af,
- 0x115b2, 0x115b5,
- 0x115bc, 0x115bd,
- 0x115bf, 0x115c0,
- 0x115dc, 0x115dd,
- 0x11633, 0x1163a,
- 0x1163d, 0x1163d,
- 0x1163f, 0x11640,
- 0x116ab, 0x116ab,
- 0x116ad, 0x116ad,
- 0x116b0, 0x116b7,
- 0x1171d, 0x1171d,
- 0x1171f, 0x1171f,
- 0x11722, 0x11725,
- 0x11727, 0x1172b,
- 0x1182f, 0x11837,
- 0x11839, 0x1183a,
- 0x11930, 0x11930,
- 0x1193b, 0x1193e,
- 0x11943, 0x11943,
- 0x119d4, 0x119d7,
- 0x119da, 0x119db,
- 0x119e0, 0x119e0,
- 0x11a01, 0x11a0a,
- 0x11a33, 0x11a38,
- 0x11a3b, 0x11a3e,
- 0x11a47, 0x11a47,
- 0x11a51, 0x11a56,
- 0x11a59, 0x11a5b,
- 0x11a8a, 0x11a96,
- 0x11a98, 0x11a99,
- 0x11c30, 0x11c36,
- 0x11c38, 0x11c3d,
- 0x11c3f, 0x11c3f,
- 0x11c92, 0x11ca7,
- 0x11caa, 0x11cb0,
- 0x11cb2, 0x11cb3,
- 0x11cb5, 0x11cb6,
- 0x11d31, 0x11d36,
- 0x11d3a, 0x11d3a,
- 0x11d3c, 0x11d3d,
- 0x11d3f, 0x11d45,
- 0x11d47, 0x11d47,
- 0x11d90, 0x11d91,
- 0x11d95, 0x11d95,
- 0x11d97, 0x11d97,
- 0x11ef3, 0x11ef4,
- 0x11f00, 0x11f01,
- 0x11f36, 0x11f3a,
- 0x11f40, 0x11f42,
- 0x11f5a, 0x11f5a,
- 0x13440, 0x13440,
- 0x13447, 0x13455,
- 0x1611e, 0x16129,
- 0x1612d, 0x1612f,
- 0x16af0, 0x16af4,
- 0x16b30, 0x16b36,
- 0x16f4f, 0x16f4f,
- 0x16f8f, 0x16f92,
- 0x16fe4, 0x16fe4,
- 0x16ff0, 0x16ff1,
- 0x1bc9d, 0x1bc9e,
- 0x1cf00, 0x1cf2d,
- 0x1cf30, 0x1cf46,
- 0x1d165, 0x1d169,
- 0x1d16d, 0x1d172,
- 0x1d17b, 0x1d182,
- 0x1d185, 0x1d18b,
- 0x1d1aa, 0x1d1ad,
- 0x1d242, 0x1d244,
- 0x1da00, 0x1da36,
- 0x1da3b, 0x1da6c,
- 0x1da75, 0x1da75,
- 0x1da84, 0x1da84,
- 0x1da9b, 0x1da9f,
- 0x1daa1, 0x1daaf,
- 0x1e000, 0x1e006,
- 0x1e008, 0x1e018,
- 0x1e01b, 0x1e021,
- 0x1e023, 0x1e024,
- 0x1e026, 0x1e02a,
- 0x1e08f, 0x1e08f,
- 0x1e130, 0x1e136,
- 0x1e2ae, 0x1e2ae,
- 0x1e2ec, 0x1e2ef,
- 0x1e4ec, 0x1e4ef,
- 0x1e5ee, 0x1e5ef,
- 0x1e8d0, 0x1e8d6,
- 0x1e944, 0x1e94a,
- 0xe0020, 0xe007f,
- 0xe0100, 0xe01ef,
-}; /* CR_Grapheme_Extend */
-
-/* 'Grapheme_Base': Derived Property */
-static const OnigCodePoint CR_Grapheme_Base[] = {
- 894,
- 0x0020, 0x007e,
- 0x00a0, 0x00ac,
- 0x00ae, 0x02ff,
- 0x0370, 0x0377,
- 0x037a, 0x037f,
- 0x0384, 0x038a,
- 0x038c, 0x038c,
- 0x038e, 0x03a1,
- 0x03a3, 0x0482,
- 0x048a, 0x052f,
- 0x0531, 0x0556,
- 0x0559, 0x058a,
- 0x058d, 0x058f,
- 0x05be, 0x05be,
- 0x05c0, 0x05c0,
- 0x05c3, 0x05c3,
- 0x05c6, 0x05c6,
- 0x05d0, 0x05ea,
- 0x05ef, 0x05f4,
- 0x0606, 0x060f,
- 0x061b, 0x061b,
- 0x061d, 0x064a,
- 0x0660, 0x066f,
- 0x0671, 0x06d5,
- 0x06de, 0x06de,
- 0x06e5, 0x06e6,
- 0x06e9, 0x06e9,
- 0x06ee, 0x070d,
- 0x0710, 0x0710,
- 0x0712, 0x072f,
- 0x074d, 0x07a5,
- 0x07b1, 0x07b1,
- 0x07c0, 0x07ea,
- 0x07f4, 0x07fa,
- 0x07fe, 0x0815,
- 0x081a, 0x081a,
- 0x0824, 0x0824,
- 0x0828, 0x0828,
- 0x0830, 0x083e,
- 0x0840, 0x0858,
- 0x085e, 0x085e,
- 0x0860, 0x086a,
- 0x0870, 0x088e,
- 0x08a0, 0x08c9,
- 0x0903, 0x0939,
- 0x093b, 0x093b,
- 0x093d, 0x0940,
- 0x0949, 0x094c,
- 0x094e, 0x0950,
- 0x0958, 0x0961,
- 0x0964, 0x0980,
- 0x0982, 0x0983,
- 0x0985, 0x098c,
- 0x098f, 0x0990,
- 0x0993, 0x09a8,
- 0x09aa, 0x09b0,
- 0x09b2, 0x09b2,
- 0x09b6, 0x09b9,
- 0x09bd, 0x09bd,
- 0x09bf, 0x09c0,
- 0x09c7, 0x09c8,
- 0x09cb, 0x09cc,
- 0x09ce, 0x09ce,
- 0x09dc, 0x09dd,
- 0x09df, 0x09e1,
- 0x09e6, 0x09fd,
- 0x0a03, 0x0a03,
- 0x0a05, 0x0a0a,
- 0x0a0f, 0x0a10,
- 0x0a13, 0x0a28,
- 0x0a2a, 0x0a30,
- 0x0a32, 0x0a33,
- 0x0a35, 0x0a36,
- 0x0a38, 0x0a39,
- 0x0a3e, 0x0a40,
- 0x0a59, 0x0a5c,
- 0x0a5e, 0x0a5e,
- 0x0a66, 0x0a6f,
- 0x0a72, 0x0a74,
- 0x0a76, 0x0a76,
- 0x0a83, 0x0a83,
- 0x0a85, 0x0a8d,
- 0x0a8f, 0x0a91,
- 0x0a93, 0x0aa8,
- 0x0aaa, 0x0ab0,
- 0x0ab2, 0x0ab3,
- 0x0ab5, 0x0ab9,
- 0x0abd, 0x0ac0,
- 0x0ac9, 0x0ac9,
- 0x0acb, 0x0acc,
- 0x0ad0, 0x0ad0,
- 0x0ae0, 0x0ae1,
- 0x0ae6, 0x0af1,
- 0x0af9, 0x0af9,
- 0x0b02, 0x0b03,
- 0x0b05, 0x0b0c,
- 0x0b0f, 0x0b10,
- 0x0b13, 0x0b28,
- 0x0b2a, 0x0b30,
- 0x0b32, 0x0b33,
- 0x0b35, 0x0b39,
- 0x0b3d, 0x0b3d,
- 0x0b40, 0x0b40,
- 0x0b47, 0x0b48,
- 0x0b4b, 0x0b4c,
- 0x0b5c, 0x0b5d,
- 0x0b5f, 0x0b61,
- 0x0b66, 0x0b77,
- 0x0b83, 0x0b83,
- 0x0b85, 0x0b8a,
- 0x0b8e, 0x0b90,
- 0x0b92, 0x0b95,
- 0x0b99, 0x0b9a,
- 0x0b9c, 0x0b9c,
- 0x0b9e, 0x0b9f,
- 0x0ba3, 0x0ba4,
- 0x0ba8, 0x0baa,
- 0x0bae, 0x0bb9,
- 0x0bbf, 0x0bbf,
- 0x0bc1, 0x0bc2,
- 0x0bc6, 0x0bc8,
- 0x0bca, 0x0bcc,
- 0x0bd0, 0x0bd0,
- 0x0be6, 0x0bfa,
- 0x0c01, 0x0c03,
- 0x0c05, 0x0c0c,
- 0x0c0e, 0x0c10,
- 0x0c12, 0x0c28,
- 0x0c2a, 0x0c39,
- 0x0c3d, 0x0c3d,
- 0x0c41, 0x0c44,
- 0x0c58, 0x0c5a,
- 0x0c5d, 0x0c5d,
- 0x0c60, 0x0c61,
- 0x0c66, 0x0c6f,
- 0x0c77, 0x0c80,
- 0x0c82, 0x0c8c,
- 0x0c8e, 0x0c90,
- 0x0c92, 0x0ca8,
- 0x0caa, 0x0cb3,
- 0x0cb5, 0x0cb9,
- 0x0cbd, 0x0cbe,
- 0x0cc1, 0x0cc1,
- 0x0cc3, 0x0cc4,
- 0x0cdd, 0x0cde,
- 0x0ce0, 0x0ce1,
- 0x0ce6, 0x0cef,
- 0x0cf1, 0x0cf3,
- 0x0d02, 0x0d0c,
- 0x0d0e, 0x0d10,
- 0x0d12, 0x0d3a,
- 0x0d3d, 0x0d3d,
- 0x0d3f, 0x0d40,
- 0x0d46, 0x0d48,
- 0x0d4a, 0x0d4c,
- 0x0d4e, 0x0d4f,
- 0x0d54, 0x0d56,
- 0x0d58, 0x0d61,
- 0x0d66, 0x0d7f,
- 0x0d82, 0x0d83,
- 0x0d85, 0x0d96,
- 0x0d9a, 0x0db1,
- 0x0db3, 0x0dbb,
- 0x0dbd, 0x0dbd,
- 0x0dc0, 0x0dc6,
- 0x0dd0, 0x0dd1,
- 0x0dd8, 0x0dde,
- 0x0de6, 0x0def,
- 0x0df2, 0x0df4,
- 0x0e01, 0x0e30,
- 0x0e32, 0x0e33,
- 0x0e3f, 0x0e46,
- 0x0e4f, 0x0e5b,
- 0x0e81, 0x0e82,
- 0x0e84, 0x0e84,
- 0x0e86, 0x0e8a,
- 0x0e8c, 0x0ea3,
- 0x0ea5, 0x0ea5,
- 0x0ea7, 0x0eb0,
- 0x0eb2, 0x0eb3,
- 0x0ebd, 0x0ebd,
- 0x0ec0, 0x0ec4,
- 0x0ec6, 0x0ec6,
- 0x0ed0, 0x0ed9,
- 0x0edc, 0x0edf,
- 0x0f00, 0x0f17,
- 0x0f1a, 0x0f34,
- 0x0f36, 0x0f36,
- 0x0f38, 0x0f38,
- 0x0f3a, 0x0f47,
- 0x0f49, 0x0f6c,
- 0x0f7f, 0x0f7f,
- 0x0f85, 0x0f85,
- 0x0f88, 0x0f8c,
- 0x0fbe, 0x0fc5,
- 0x0fc7, 0x0fcc,
- 0x0fce, 0x0fda,
- 0x1000, 0x102c,
- 0x1031, 0x1031,
- 0x1038, 0x1038,
- 0x103b, 0x103c,
- 0x103f, 0x1057,
- 0x105a, 0x105d,
- 0x1061, 0x1070,
- 0x1075, 0x1081,
- 0x1083, 0x1084,
- 0x1087, 0x108c,
- 0x108e, 0x109c,
- 0x109e, 0x10c5,
- 0x10c7, 0x10c7,
- 0x10cd, 0x10cd,
- 0x10d0, 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,
- 0x1360, 0x137c,
- 0x1380, 0x1399,
- 0x13a0, 0x13f5,
- 0x13f8, 0x13fd,
- 0x1400, 0x169c,
- 0x16a0, 0x16f8,
- 0x1700, 0x1711,
- 0x171f, 0x1731,
- 0x1735, 0x1736,
- 0x1740, 0x1751,
- 0x1760, 0x176c,
- 0x176e, 0x1770,
- 0x1780, 0x17b3,
- 0x17b6, 0x17b6,
- 0x17be, 0x17c5,
- 0x17c7, 0x17c8,
- 0x17d4, 0x17dc,
- 0x17e0, 0x17e9,
- 0x17f0, 0x17f9,
- 0x1800, 0x180a,
- 0x1810, 0x1819,
- 0x1820, 0x1878,
- 0x1880, 0x1884,
- 0x1887, 0x18a8,
- 0x18aa, 0x18aa,
- 0x18b0, 0x18f5,
- 0x1900, 0x191e,
- 0x1923, 0x1926,
- 0x1929, 0x192b,
- 0x1930, 0x1931,
- 0x1933, 0x1938,
- 0x1940, 0x1940,
- 0x1944, 0x196d,
- 0x1970, 0x1974,
- 0x1980, 0x19ab,
- 0x19b0, 0x19c9,
- 0x19d0, 0x19da,
- 0x19de, 0x1a16,
- 0x1a19, 0x1a1a,
- 0x1a1e, 0x1a55,
- 0x1a57, 0x1a57,
- 0x1a61, 0x1a61,
- 0x1a63, 0x1a64,
- 0x1a6d, 0x1a72,
- 0x1a80, 0x1a89,
- 0x1a90, 0x1a99,
- 0x1aa0, 0x1aad,
- 0x1b04, 0x1b33,
- 0x1b3e, 0x1b41,
- 0x1b45, 0x1b4c,
- 0x1b4e, 0x1b6a,
- 0x1b74, 0x1b7f,
- 0x1b82, 0x1ba1,
- 0x1ba6, 0x1ba7,
- 0x1bae, 0x1be5,
- 0x1be7, 0x1be7,
- 0x1bea, 0x1bec,
- 0x1bee, 0x1bee,
- 0x1bfc, 0x1c2b,
- 0x1c34, 0x1c35,
- 0x1c3b, 0x1c49,
- 0x1c4d, 0x1c8a,
- 0x1c90, 0x1cba,
- 0x1cbd, 0x1cc7,
- 0x1cd3, 0x1cd3,
- 0x1ce1, 0x1ce1,
- 0x1ce9, 0x1cec,
- 0x1cee, 0x1cf3,
- 0x1cf5, 0x1cf7,
- 0x1cfa, 0x1cfa,
- 0x1d00, 0x1dbf,
- 0x1e00, 0x1f15,
- 0x1f18, 0x1f1d,
- 0x1f20, 0x1f45,
- 0x1f48, 0x1f4d,
- 0x1f50, 0x1f57,
- 0x1f59, 0x1f59,
- 0x1f5b, 0x1f5b,
- 0x1f5d, 0x1f5d,
- 0x1f5f, 0x1f7d,
- 0x1f80, 0x1fb4,
- 0x1fb6, 0x1fc4,
- 0x1fc6, 0x1fd3,
- 0x1fd6, 0x1fdb,
- 0x1fdd, 0x1fef,
- 0x1ff2, 0x1ff4,
- 0x1ff6, 0x1ffe,
- 0x2000, 0x200a,
- 0x2010, 0x2027,
- 0x202f, 0x205f,
- 0x2070, 0x2071,
- 0x2074, 0x208e,
- 0x2090, 0x209c,
- 0x20a0, 0x20c0,
- 0x2100, 0x218b,
- 0x2190, 0x2429,
- 0x2440, 0x244a,
- 0x2460, 0x2b73,
- 0x2b76, 0x2b95,
- 0x2b97, 0x2cee,
- 0x2cf2, 0x2cf3,
- 0x2cf9, 0x2d25,
- 0x2d27, 0x2d27,
- 0x2d2d, 0x2d2d,
- 0x2d30, 0x2d67,
- 0x2d6f, 0x2d70,
- 0x2d80, 0x2d96,
- 0x2da0, 0x2da6,
- 0x2da8, 0x2dae,
- 0x2db0, 0x2db6,
- 0x2db8, 0x2dbe,
- 0x2dc0, 0x2dc6,
- 0x2dc8, 0x2dce,
- 0x2dd0, 0x2dd6,
- 0x2dd8, 0x2dde,
- 0x2e00, 0x2e5d,
- 0x2e80, 0x2e99,
- 0x2e9b, 0x2ef3,
- 0x2f00, 0x2fd5,
- 0x2ff0, 0x3029,
- 0x3030, 0x303f,
- 0x3041, 0x3096,
- 0x309b, 0x30ff,
- 0x3105, 0x312f,
- 0x3131, 0x318e,
- 0x3190, 0x31e5,
- 0x31ef, 0x321e,
- 0x3220, 0xa48c,
- 0xa490, 0xa4c6,
- 0xa4d0, 0xa62b,
- 0xa640, 0xa66e,
- 0xa673, 0xa673,
- 0xa67e, 0xa69d,
- 0xa6a0, 0xa6ef,
- 0xa6f2, 0xa6f7,
- 0xa700, 0xa7cd,
- 0xa7d0, 0xa7d1,
- 0xa7d3, 0xa7d3,
- 0xa7d5, 0xa7dc,
- 0xa7f2, 0xa801,
- 0xa803, 0xa805,
- 0xa807, 0xa80a,
- 0xa80c, 0xa824,
- 0xa827, 0xa82b,
- 0xa830, 0xa839,
- 0xa840, 0xa877,
- 0xa880, 0xa8c3,
- 0xa8ce, 0xa8d9,
- 0xa8f2, 0xa8fe,
- 0xa900, 0xa925,
- 0xa92e, 0xa946,
- 0xa952, 0xa952,
- 0xa95f, 0xa97c,
- 0xa983, 0xa9b2,
- 0xa9b4, 0xa9b5,
- 0xa9ba, 0xa9bb,
- 0xa9be, 0xa9bf,
- 0xa9c1, 0xa9cd,
- 0xa9cf, 0xa9d9,
- 0xa9de, 0xa9e4,
- 0xa9e6, 0xa9fe,
- 0xaa00, 0xaa28,
- 0xaa2f, 0xaa30,
- 0xaa33, 0xaa34,
- 0xaa40, 0xaa42,
- 0xaa44, 0xaa4b,
- 0xaa4d, 0xaa4d,
- 0xaa50, 0xaa59,
- 0xaa5c, 0xaa7b,
- 0xaa7d, 0xaaaf,
- 0xaab1, 0xaab1,
- 0xaab5, 0xaab6,
- 0xaab9, 0xaabd,
- 0xaac0, 0xaac0,
- 0xaac2, 0xaac2,
- 0xaadb, 0xaaeb,
- 0xaaee, 0xaaf5,
- 0xab01, 0xab06,
- 0xab09, 0xab0e,
- 0xab11, 0xab16,
- 0xab20, 0xab26,
- 0xab28, 0xab2e,
- 0xab30, 0xab6b,
- 0xab70, 0xabe4,
- 0xabe6, 0xabe7,
- 0xabe9, 0xabec,
- 0xabf0, 0xabf9,
- 0xac00, 0xd7a3,
- 0xd7b0, 0xd7c6,
- 0xd7cb, 0xd7fb,
- 0xf900, 0xfa6d,
- 0xfa70, 0xfad9,
- 0xfb00, 0xfb06,
- 0xfb13, 0xfb17,
- 0xfb1d, 0xfb1d,
- 0xfb1f, 0xfb36,
- 0xfb38, 0xfb3c,
- 0xfb3e, 0xfb3e,
- 0xfb40, 0xfb41,
- 0xfb43, 0xfb44,
- 0xfb46, 0xfbc2,
- 0xfbd3, 0xfd8f,
- 0xfd92, 0xfdc7,
- 0xfdcf, 0xfdcf,
- 0xfdf0, 0xfdff,
- 0xfe10, 0xfe19,
- 0xfe30, 0xfe52,
- 0xfe54, 0xfe66,
- 0xfe68, 0xfe6b,
- 0xfe70, 0xfe74,
- 0xfe76, 0xfefc,
- 0xff01, 0xff9d,
- 0xffa0, 0xffbe,
- 0xffc2, 0xffc7,
- 0xffca, 0xffcf,
- 0xffd2, 0xffd7,
- 0xffda, 0xffdc,
- 0xffe0, 0xffe6,
- 0xffe8, 0xffee,
- 0xfffc, 0xfffd,
- 0x10000, 0x1000b,
- 0x1000d, 0x10026,
- 0x10028, 0x1003a,
- 0x1003c, 0x1003d,
- 0x1003f, 0x1004d,
- 0x10050, 0x1005d,
- 0x10080, 0x100fa,
- 0x10100, 0x10102,
- 0x10107, 0x10133,
- 0x10137, 0x1018e,
- 0x10190, 0x1019c,
- 0x101a0, 0x101a0,
- 0x101d0, 0x101fc,
- 0x10280, 0x1029c,
- 0x102a0, 0x102d0,
- 0x102e1, 0x102fb,
- 0x10300, 0x10323,
- 0x1032d, 0x1034a,
- 0x10350, 0x10375,
- 0x10380, 0x1039d,
- 0x1039f, 0x103c3,
- 0x103c8, 0x103d5,
- 0x10400, 0x1049d,
- 0x104a0, 0x104a9,
- 0x104b0, 0x104d3,
- 0x104d8, 0x104fb,
- 0x10500, 0x10527,
- 0x10530, 0x10563,
- 0x1056f, 0x1057a,
- 0x1057c, 0x1058a,
- 0x1058c, 0x10592,
- 0x10594, 0x10595,
- 0x10597, 0x105a1,
- 0x105a3, 0x105b1,
- 0x105b3, 0x105b9,
- 0x105bb, 0x105bc,
- 0x105c0, 0x105f3,
- 0x10600, 0x10736,
- 0x10740, 0x10755,
- 0x10760, 0x10767,
- 0x10780, 0x10785,
- 0x10787, 0x107b0,
- 0x107b2, 0x107ba,
- 0x10800, 0x10805,
- 0x10808, 0x10808,
- 0x1080a, 0x10835,
- 0x10837, 0x10838,
- 0x1083c, 0x1083c,
- 0x1083f, 0x10855,
- 0x10857, 0x1089e,
- 0x108a7, 0x108af,
- 0x108e0, 0x108f2,
- 0x108f4, 0x108f5,
- 0x108fb, 0x1091b,
- 0x1091f, 0x10939,
- 0x1093f, 0x1093f,
- 0x10980, 0x109b7,
- 0x109bc, 0x109cf,
- 0x109d2, 0x10a00,
- 0x10a10, 0x10a13,
- 0x10a15, 0x10a17,
- 0x10a19, 0x10a35,
- 0x10a40, 0x10a48,
- 0x10a50, 0x10a58,
- 0x10a60, 0x10a9f,
- 0x10ac0, 0x10ae4,
- 0x10aeb, 0x10af6,
- 0x10b00, 0x10b35,
- 0x10b39, 0x10b55,
- 0x10b58, 0x10b72,
- 0x10b78, 0x10b91,
- 0x10b99, 0x10b9c,
- 0x10ba9, 0x10baf,
- 0x10c00, 0x10c48,
- 0x10c80, 0x10cb2,
- 0x10cc0, 0x10cf2,
- 0x10cfa, 0x10d23,
- 0x10d30, 0x10d39,
- 0x10d40, 0x10d65,
- 0x10d6e, 0x10d85,
- 0x10d8e, 0x10d8f,
- 0x10e60, 0x10e7e,
- 0x10e80, 0x10ea9,
- 0x10ead, 0x10ead,
- 0x10eb0, 0x10eb1,
- 0x10ec2, 0x10ec4,
- 0x10f00, 0x10f27,
- 0x10f30, 0x10f45,
- 0x10f51, 0x10f59,
- 0x10f70, 0x10f81,
- 0x10f86, 0x10f89,
- 0x10fb0, 0x10fcb,
- 0x10fe0, 0x10ff6,
- 0x11000, 0x11000,
- 0x11002, 0x11037,
- 0x11047, 0x1104d,
- 0x11052, 0x1106f,
- 0x11071, 0x11072,
- 0x11075, 0x11075,
- 0x11082, 0x110b2,
- 0x110b7, 0x110b8,
- 0x110bb, 0x110bc,
- 0x110be, 0x110c1,
- 0x110d0, 0x110e8,
- 0x110f0, 0x110f9,
- 0x11103, 0x11126,
- 0x1112c, 0x1112c,
- 0x11136, 0x11147,
- 0x11150, 0x11172,
- 0x11174, 0x11176,
- 0x11182, 0x111b5,
- 0x111bf, 0x111bf,
- 0x111c1, 0x111c8,
- 0x111cd, 0x111ce,
- 0x111d0, 0x111df,
- 0x111e1, 0x111f4,
- 0x11200, 0x11211,
- 0x11213, 0x1122e,
- 0x11232, 0x11233,
- 0x11238, 0x1123d,
- 0x1123f, 0x11240,
- 0x11280, 0x11286,
- 0x11288, 0x11288,
- 0x1128a, 0x1128d,
- 0x1128f, 0x1129d,
- 0x1129f, 0x112a9,
- 0x112b0, 0x112de,
- 0x112e0, 0x112e2,
- 0x112f0, 0x112f9,
- 0x11302, 0x11303,
- 0x11305, 0x1130c,
- 0x1130f, 0x11310,
- 0x11313, 0x11328,
- 0x1132a, 0x11330,
- 0x11332, 0x11333,
- 0x11335, 0x11339,
- 0x1133d, 0x1133d,
- 0x1133f, 0x1133f,
- 0x11341, 0x11344,
- 0x11347, 0x11348,
- 0x1134b, 0x1134c,
- 0x11350, 0x11350,
- 0x1135d, 0x11363,
- 0x11380, 0x11389,
- 0x1138b, 0x1138b,
- 0x1138e, 0x1138e,
- 0x11390, 0x113b5,
- 0x113b7, 0x113b7,
- 0x113b9, 0x113ba,
- 0x113ca, 0x113ca,
- 0x113cc, 0x113cd,
- 0x113d1, 0x113d1,
- 0x113d3, 0x113d5,
- 0x113d7, 0x113d8,
- 0x11400, 0x11437,
- 0x11440, 0x11441,
- 0x11445, 0x11445,
- 0x11447, 0x1145b,
- 0x1145d, 0x1145d,
- 0x1145f, 0x11461,
- 0x11480, 0x114af,
- 0x114b1, 0x114b2,
- 0x114b9, 0x114b9,
- 0x114bb, 0x114bc,
- 0x114be, 0x114be,
- 0x114c1, 0x114c1,
- 0x114c4, 0x114c7,
- 0x114d0, 0x114d9,
- 0x11580, 0x115ae,
- 0x115b0, 0x115b1,
- 0x115b8, 0x115bb,
- 0x115be, 0x115be,
- 0x115c1, 0x115db,
- 0x11600, 0x11632,
- 0x1163b, 0x1163c,
- 0x1163e, 0x1163e,
- 0x11641, 0x11644,
- 0x11650, 0x11659,
- 0x11660, 0x1166c,
- 0x11680, 0x116aa,
- 0x116ac, 0x116ac,
- 0x116ae, 0x116af,
- 0x116b8, 0x116b9,
- 0x116c0, 0x116c9,
- 0x116d0, 0x116e3,
- 0x11700, 0x1171a,
- 0x1171e, 0x1171e,
- 0x11720, 0x11721,
- 0x11726, 0x11726,
- 0x11730, 0x11746,
- 0x11800, 0x1182e,
- 0x11838, 0x11838,
- 0x1183b, 0x1183b,
- 0x118a0, 0x118f2,
- 0x118ff, 0x11906,
- 0x11909, 0x11909,
- 0x1190c, 0x11913,
- 0x11915, 0x11916,
- 0x11918, 0x1192f,
- 0x11931, 0x11935,
- 0x11937, 0x11938,
- 0x1193f, 0x11942,
- 0x11944, 0x11946,
- 0x11950, 0x11959,
- 0x119a0, 0x119a7,
- 0x119aa, 0x119d3,
- 0x119dc, 0x119df,
- 0x119e1, 0x119e4,
- 0x11a00, 0x11a00,
- 0x11a0b, 0x11a32,
- 0x11a39, 0x11a3a,
- 0x11a3f, 0x11a46,
- 0x11a50, 0x11a50,
- 0x11a57, 0x11a58,
- 0x11a5c, 0x11a89,
- 0x11a97, 0x11a97,
- 0x11a9a, 0x11aa2,
- 0x11ab0, 0x11af8,
- 0x11b00, 0x11b09,
- 0x11bc0, 0x11be1,
- 0x11bf0, 0x11bf9,
- 0x11c00, 0x11c08,
- 0x11c0a, 0x11c2f,
- 0x11c3e, 0x11c3e,
- 0x11c40, 0x11c45,
- 0x11c50, 0x11c6c,
- 0x11c70, 0x11c8f,
- 0x11ca9, 0x11ca9,
- 0x11cb1, 0x11cb1,
- 0x11cb4, 0x11cb4,
- 0x11d00, 0x11d06,
- 0x11d08, 0x11d09,
- 0x11d0b, 0x11d30,
- 0x11d46, 0x11d46,
- 0x11d50, 0x11d59,
- 0x11d60, 0x11d65,
- 0x11d67, 0x11d68,
- 0x11d6a, 0x11d8e,
- 0x11d93, 0x11d94,
- 0x11d96, 0x11d96,
- 0x11d98, 0x11d98,
- 0x11da0, 0x11da9,
- 0x11ee0, 0x11ef2,
- 0x11ef5, 0x11ef8,
- 0x11f02, 0x11f10,
- 0x11f12, 0x11f35,
- 0x11f3e, 0x11f3f,
- 0x11f43, 0x11f59,
- 0x11fb0, 0x11fb0,
- 0x11fc0, 0x11ff1,
- 0x11fff, 0x12399,
- 0x12400, 0x1246e,
- 0x12470, 0x12474,
- 0x12480, 0x12543,
- 0x12f90, 0x12ff2,
- 0x13000, 0x1342f,
- 0x13441, 0x13446,
- 0x13460, 0x143fa,
- 0x14400, 0x14646,
- 0x16100, 0x1611d,
- 0x1612a, 0x1612c,
- 0x16130, 0x16139,
- 0x16800, 0x16a38,
- 0x16a40, 0x16a5e,
- 0x16a60, 0x16a69,
- 0x16a6e, 0x16abe,
- 0x16ac0, 0x16ac9,
- 0x16ad0, 0x16aed,
- 0x16af5, 0x16af5,
- 0x16b00, 0x16b2f,
- 0x16b37, 0x16b45,
- 0x16b50, 0x16b59,
- 0x16b5b, 0x16b61,
- 0x16b63, 0x16b77,
- 0x16b7d, 0x16b8f,
- 0x16d40, 0x16d79,
- 0x16e40, 0x16e9a,
- 0x16f00, 0x16f4a,
- 0x16f50, 0x16f87,
- 0x16f93, 0x16f9f,
- 0x16fe0, 0x16fe3,
- 0x17000, 0x187f7,
- 0x18800, 0x18cd5,
- 0x18cff, 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,
- 0x1bc9c, 0x1bc9c,
- 0x1bc9f, 0x1bc9f,
- 0x1cc00, 0x1ccf9,
- 0x1cd00, 0x1ceb3,
- 0x1cf50, 0x1cfc3,
- 0x1d000, 0x1d0f5,
- 0x1d100, 0x1d126,
- 0x1d129, 0x1d164,
- 0x1d16a, 0x1d16c,
- 0x1d183, 0x1d184,
- 0x1d18c, 0x1d1a9,
- 0x1d1ae, 0x1d1ea,
- 0x1d200, 0x1d241,
- 0x1d245, 0x1d245,
- 0x1d2c0, 0x1d2d3,
- 0x1d2e0, 0x1d2f3,
- 0x1d300, 0x1d356,
- 0x1d360, 0x1d378,
- 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, 0x1d7cb,
- 0x1d7ce, 0x1d9ff,
- 0x1da37, 0x1da3a,
- 0x1da6d, 0x1da74,
- 0x1da76, 0x1da83,
- 0x1da85, 0x1da8b,
- 0x1df00, 0x1df1e,
- 0x1df25, 0x1df2a,
- 0x1e030, 0x1e06d,
- 0x1e100, 0x1e12c,
- 0x1e137, 0x1e13d,
- 0x1e140, 0x1e149,
- 0x1e14e, 0x1e14f,
- 0x1e290, 0x1e2ad,
- 0x1e2c0, 0x1e2eb,
- 0x1e2f0, 0x1e2f9,
- 0x1e2ff, 0x1e2ff,
- 0x1e4d0, 0x1e4eb,
- 0x1e4f0, 0x1e4f9,
- 0x1e5d0, 0x1e5ed,
- 0x1e5f0, 0x1e5fa,
- 0x1e5ff, 0x1e5ff,
- 0x1e7e0, 0x1e7e6,
- 0x1e7e8, 0x1e7eb,
- 0x1e7ed, 0x1e7ee,
- 0x1e7f0, 0x1e7fe,
- 0x1e800, 0x1e8c4,
- 0x1e8c7, 0x1e8cf,
- 0x1e900, 0x1e943,
- 0x1e94b, 0x1e94b,
- 0x1e950, 0x1e959,
- 0x1e95e, 0x1e95f,
- 0x1ec71, 0x1ecb4,
- 0x1ed01, 0x1ed3d,
- 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,
- 0x1eef0, 0x1eef1,
- 0x1f000, 0x1f02b,
- 0x1f030, 0x1f093,
- 0x1f0a0, 0x1f0ae,
- 0x1f0b1, 0x1f0bf,
- 0x1f0c1, 0x1f0cf,
- 0x1f0d1, 0x1f0f5,
- 0x1f100, 0x1f1ad,
- 0x1f1e6, 0x1f202,
- 0x1f210, 0x1f23b,
- 0x1f240, 0x1f248,
- 0x1f250, 0x1f251,
- 0x1f260, 0x1f265,
- 0x1f300, 0x1f6d7,
- 0x1f6dc, 0x1f6ec,
- 0x1f6f0, 0x1f6fc,
- 0x1f700, 0x1f776,
- 0x1f77b, 0x1f7d9,
- 0x1f7e0, 0x1f7eb,
- 0x1f7f0, 0x1f7f0,
- 0x1f800, 0x1f80b,
- 0x1f810, 0x1f847,
- 0x1f850, 0x1f859,
- 0x1f860, 0x1f887,
- 0x1f890, 0x1f8ad,
- 0x1f8b0, 0x1f8bb,
- 0x1f8c0, 0x1f8c1,
- 0x1f900, 0x1fa53,
- 0x1fa60, 0x1fa6d,
- 0x1fa70, 0x1fa7c,
- 0x1fa80, 0x1fa89,
- 0x1fa8f, 0x1fac6,
- 0x1face, 0x1fadc,
- 0x1fadf, 0x1fae9,
- 0x1faf0, 0x1faf8,
- 0x1fb00, 0x1fb92,
- 0x1fb94, 0x1fbf9,
- 0x20000, 0x2a6df,
- 0x2a700, 0x2b739,
- 0x2b740, 0x2b81d,
- 0x2b820, 0x2cea1,
- 0x2ceb0, 0x2ebe0,
- 0x2ebf0, 0x2ee5d,
- 0x2f800, 0x2fa1d,
- 0x30000, 0x3134a,
- 0x31350, 0x323af,
-}; /* CR_Grapheme_Base */
-
-/* 'Grapheme_Link': Derived Property */
-static const OnigCodePoint CR_Grapheme_Link[] = {
- 58,
- 0x094d, 0x094d,
- 0x09cd, 0x09cd,
- 0x0a4d, 0x0a4d,
- 0x0acd, 0x0acd,
- 0x0b4d, 0x0b4d,
- 0x0bcd, 0x0bcd,
- 0x0c4d, 0x0c4d,
- 0x0ccd, 0x0ccd,
- 0x0d3b, 0x0d3c,
- 0x0d4d, 0x0d4d,
- 0x0dca, 0x0dca,
- 0x0e3a, 0x0e3a,
- 0x0eba, 0x0eba,
- 0x0f84, 0x0f84,
- 0x1039, 0x103a,
- 0x1714, 0x1715,
- 0x1734, 0x1734,
- 0x17d2, 0x17d2,
- 0x1a60, 0x1a60,
- 0x1b44, 0x1b44,
- 0x1baa, 0x1bab,
- 0x1bf2, 0x1bf3,
- 0x2d7f, 0x2d7f,
- 0xa806, 0xa806,
- 0xa82c, 0xa82c,
- 0xa8c4, 0xa8c4,
- 0xa953, 0xa953,
- 0xa9c0, 0xa9c0,
- 0xaaf6, 0xaaf6,
- 0xabed, 0xabed,
- 0x10a3f, 0x10a3f,
- 0x11046, 0x11046,
- 0x11070, 0x11070,
- 0x1107f, 0x1107f,
- 0x110b9, 0x110b9,
- 0x11133, 0x11134,
- 0x111c0, 0x111c0,
- 0x11235, 0x11235,
- 0x112ea, 0x112ea,
- 0x1134d, 0x1134d,
- 0x113ce, 0x113d0,
- 0x11442, 0x11442,
- 0x114c2, 0x114c2,
- 0x115bf, 0x115bf,
- 0x1163f, 0x1163f,
- 0x116b6, 0x116b6,
- 0x1172b, 0x1172b,
- 0x11839, 0x11839,
- 0x1193d, 0x1193e,
- 0x119e0, 0x119e0,
- 0x11a34, 0x11a34,
- 0x11a47, 0x11a47,
- 0x11a99, 0x11a99,
- 0x11c3f, 0x11c3f,
- 0x11d44, 0x11d45,
- 0x11d97, 0x11d97,
- 0x11f41, 0x11f42,
- 0x1612f, 0x1612f,
-}; /* CR_Grapheme_Link */
-
-/* 'InCB_Linker': Derived Property */
-static const OnigCodePoint CR_InCB_Linker[] = {
- 6,
- 0x094d, 0x094d,
- 0x09cd, 0x09cd,
- 0x0acd, 0x0acd,
- 0x0b4d, 0x0b4d,
- 0x0c4d, 0x0c4d,
- 0x0d4d, 0x0d4d,
-}; /* CR_InCB_Linker */
-
-/* 'InCB_Consonant': Derived Property */
-static const OnigCodePoint CR_InCB_Consonant[] = {
- 26,
- 0x0915, 0x0939,
- 0x0958, 0x095f,
- 0x0978, 0x097f,
- 0x0995, 0x09a8,
- 0x09aa, 0x09b0,
- 0x09b2, 0x09b2,
- 0x09b6, 0x09b9,
- 0x09dc, 0x09dd,
- 0x09df, 0x09df,
- 0x09f0, 0x09f1,
- 0x0a95, 0x0aa8,
- 0x0aaa, 0x0ab0,
- 0x0ab2, 0x0ab3,
- 0x0ab5, 0x0ab9,
- 0x0af9, 0x0af9,
- 0x0b15, 0x0b28,
- 0x0b2a, 0x0b30,
- 0x0b32, 0x0b33,
- 0x0b35, 0x0b39,
- 0x0b5c, 0x0b5d,
- 0x0b5f, 0x0b5f,
- 0x0b71, 0x0b71,
- 0x0c15, 0x0c28,
- 0x0c2a, 0x0c39,
- 0x0c58, 0x0c5a,
- 0x0d15, 0x0d3a,
-}; /* CR_InCB_Consonant */
-
-/* 'InCB_Extend': Derived Property */
-static const OnigCodePoint CR_InCB_Extend[] = {
- 371,
- 0x0300, 0x036f,
- 0x0483, 0x0489,
- 0x0591, 0x05bd,
- 0x05bf, 0x05bf,
- 0x05c1, 0x05c2,
- 0x05c4, 0x05c5,
- 0x05c7, 0x05c7,
- 0x0610, 0x061a,
- 0x064b, 0x065f,
- 0x0670, 0x0670,
- 0x06d6, 0x06dc,
- 0x06df, 0x06e4,
- 0x06e7, 0x06e8,
- 0x06ea, 0x06ed,
- 0x0711, 0x0711,
- 0x0730, 0x074a,
- 0x07a6, 0x07b0,
- 0x07eb, 0x07f3,
- 0x07fd, 0x07fd,
- 0x0816, 0x0819,
- 0x081b, 0x0823,
- 0x0825, 0x0827,
- 0x0829, 0x082d,
- 0x0859, 0x085b,
- 0x0897, 0x089f,
- 0x08ca, 0x08e1,
- 0x08e3, 0x0902,
- 0x093a, 0x093a,
- 0x093c, 0x093c,
- 0x0941, 0x0948,
- 0x0951, 0x0957,
- 0x0962, 0x0963,
- 0x0981, 0x0981,
- 0x09bc, 0x09bc,
- 0x09be, 0x09be,
- 0x09c1, 0x09c4,
- 0x09d7, 0x09d7,
- 0x09e2, 0x09e3,
- 0x09fe, 0x09fe,
- 0x0a01, 0x0a02,
- 0x0a3c, 0x0a3c,
- 0x0a41, 0x0a42,
- 0x0a47, 0x0a48,
- 0x0a4b, 0x0a4d,
- 0x0a51, 0x0a51,
- 0x0a70, 0x0a71,
- 0x0a75, 0x0a75,
- 0x0a81, 0x0a82,
- 0x0abc, 0x0abc,
- 0x0ac1, 0x0ac5,
- 0x0ac7, 0x0ac8,
- 0x0ae2, 0x0ae3,
- 0x0afa, 0x0aff,
- 0x0b01, 0x0b01,
- 0x0b3c, 0x0b3c,
- 0x0b3e, 0x0b3f,
- 0x0b41, 0x0b44,
- 0x0b55, 0x0b57,
- 0x0b62, 0x0b63,
- 0x0b82, 0x0b82,
- 0x0bbe, 0x0bbe,
- 0x0bc0, 0x0bc0,
- 0x0bcd, 0x0bcd,
- 0x0bd7, 0x0bd7,
- 0x0c00, 0x0c00,
- 0x0c04, 0x0c04,
- 0x0c3c, 0x0c3c,
- 0x0c3e, 0x0c40,
- 0x0c46, 0x0c48,
- 0x0c4a, 0x0c4c,
- 0x0c55, 0x0c56,
- 0x0c62, 0x0c63,
- 0x0c81, 0x0c81,
- 0x0cbc, 0x0cbc,
- 0x0cbf, 0x0cc0,
- 0x0cc2, 0x0cc2,
- 0x0cc6, 0x0cc8,
- 0x0cca, 0x0ccd,
- 0x0cd5, 0x0cd6,
- 0x0ce2, 0x0ce3,
- 0x0d00, 0x0d01,
- 0x0d3b, 0x0d3c,
- 0x0d3e, 0x0d3e,
- 0x0d41, 0x0d44,
- 0x0d57, 0x0d57,
- 0x0d62, 0x0d63,
- 0x0d81, 0x0d81,
- 0x0dca, 0x0dca,
- 0x0dcf, 0x0dcf,
- 0x0dd2, 0x0dd4,
- 0x0dd6, 0x0dd6,
- 0x0ddf, 0x0ddf,
- 0x0e31, 0x0e31,
- 0x0e34, 0x0e3a,
- 0x0e47, 0x0e4e,
- 0x0eb1, 0x0eb1,
- 0x0eb4, 0x0ebc,
- 0x0ec8, 0x0ece,
- 0x0f18, 0x0f19,
- 0x0f35, 0x0f35,
- 0x0f37, 0x0f37,
- 0x0f39, 0x0f39,
- 0x0f71, 0x0f7e,
- 0x0f80, 0x0f84,
- 0x0f86, 0x0f87,
- 0x0f8d, 0x0f97,
- 0x0f99, 0x0fbc,
- 0x0fc6, 0x0fc6,
- 0x102d, 0x1030,
- 0x1032, 0x1037,
- 0x1039, 0x103a,
- 0x103d, 0x103e,
- 0x1058, 0x1059,
- 0x105e, 0x1060,
- 0x1071, 0x1074,
- 0x1082, 0x1082,
- 0x1085, 0x1086,
- 0x108d, 0x108d,
- 0x109d, 0x109d,
- 0x135d, 0x135f,
- 0x1712, 0x1715,
- 0x1732, 0x1734,
- 0x1752, 0x1753,
- 0x1772, 0x1773,
- 0x17b4, 0x17b5,
- 0x17b7, 0x17bd,
- 0x17c6, 0x17c6,
- 0x17c9, 0x17d3,
- 0x17dd, 0x17dd,
- 0x180b, 0x180d,
- 0x180f, 0x180f,
- 0x1885, 0x1886,
- 0x18a9, 0x18a9,
- 0x1920, 0x1922,
- 0x1927, 0x1928,
- 0x1932, 0x1932,
- 0x1939, 0x193b,
- 0x1a17, 0x1a18,
- 0x1a1b, 0x1a1b,
- 0x1a56, 0x1a56,
- 0x1a58, 0x1a5e,
- 0x1a60, 0x1a60,
- 0x1a62, 0x1a62,
- 0x1a65, 0x1a6c,
- 0x1a73, 0x1a7c,
- 0x1a7f, 0x1a7f,
- 0x1ab0, 0x1ace,
- 0x1b00, 0x1b03,
- 0x1b34, 0x1b3d,
- 0x1b42, 0x1b44,
- 0x1b6b, 0x1b73,
- 0x1b80, 0x1b81,
- 0x1ba2, 0x1ba5,
- 0x1ba8, 0x1bad,
- 0x1be6, 0x1be6,
- 0x1be8, 0x1be9,
- 0x1bed, 0x1bed,
- 0x1bef, 0x1bf3,
- 0x1c2c, 0x1c33,
- 0x1c36, 0x1c37,
- 0x1cd0, 0x1cd2,
- 0x1cd4, 0x1ce0,
- 0x1ce2, 0x1ce8,
- 0x1ced, 0x1ced,
- 0x1cf4, 0x1cf4,
- 0x1cf8, 0x1cf9,
- 0x1dc0, 0x1dff,
- 0x200d, 0x200d,
- 0x20d0, 0x20f0,
- 0x2cef, 0x2cf1,
- 0x2d7f, 0x2d7f,
- 0x2de0, 0x2dff,
- 0x302a, 0x302f,
- 0x3099, 0x309a,
- 0xa66f, 0xa672,
- 0xa674, 0xa67d,
- 0xa69e, 0xa69f,
- 0xa6f0, 0xa6f1,
- 0xa802, 0xa802,
- 0xa806, 0xa806,
- 0xa80b, 0xa80b,
- 0xa825, 0xa826,
- 0xa82c, 0xa82c,
- 0xa8c4, 0xa8c5,
- 0xa8e0, 0xa8f1,
- 0xa8ff, 0xa8ff,
- 0xa926, 0xa92d,
- 0xa947, 0xa951,
- 0xa953, 0xa953,
- 0xa980, 0xa982,
- 0xa9b3, 0xa9b3,
- 0xa9b6, 0xa9b9,
- 0xa9bc, 0xa9bd,
- 0xa9c0, 0xa9c0,
- 0xa9e5, 0xa9e5,
- 0xaa29, 0xaa2e,
- 0xaa31, 0xaa32,
- 0xaa35, 0xaa36,
- 0xaa43, 0xaa43,
- 0xaa4c, 0xaa4c,
- 0xaa7c, 0xaa7c,
- 0xaab0, 0xaab0,
- 0xaab2, 0xaab4,
- 0xaab7, 0xaab8,
- 0xaabe, 0xaabf,
- 0xaac1, 0xaac1,
- 0xaaec, 0xaaed,
- 0xaaf6, 0xaaf6,
- 0xabe5, 0xabe5,
- 0xabe8, 0xabe8,
- 0xabed, 0xabed,
- 0xfb1e, 0xfb1e,
- 0xfe00, 0xfe0f,
- 0xfe20, 0xfe2f,
- 0xff9e, 0xff9f,
- 0x101fd, 0x101fd,
- 0x102e0, 0x102e0,
- 0x10376, 0x1037a,
- 0x10a01, 0x10a03,
- 0x10a05, 0x10a06,
- 0x10a0c, 0x10a0f,
- 0x10a38, 0x10a3a,
- 0x10a3f, 0x10a3f,
- 0x10ae5, 0x10ae6,
- 0x10d24, 0x10d27,
- 0x10d69, 0x10d6d,
- 0x10eab, 0x10eac,
- 0x10efc, 0x10eff,
- 0x10f46, 0x10f50,
- 0x10f82, 0x10f85,
- 0x11001, 0x11001,
- 0x11038, 0x11046,
- 0x11070, 0x11070,
- 0x11073, 0x11074,
- 0x1107f, 0x11081,
- 0x110b3, 0x110b6,
- 0x110b9, 0x110ba,
- 0x110c2, 0x110c2,
- 0x11100, 0x11102,
- 0x11127, 0x1112b,
- 0x1112d, 0x11134,
- 0x11173, 0x11173,
- 0x11180, 0x11181,
- 0x111b6, 0x111be,
- 0x111c0, 0x111c0,
- 0x111c9, 0x111cc,
- 0x111cf, 0x111cf,
- 0x1122f, 0x11231,
- 0x11234, 0x11237,
- 0x1123e, 0x1123e,
- 0x11241, 0x11241,
- 0x112df, 0x112df,
- 0x112e3, 0x112ea,
- 0x11300, 0x11301,
- 0x1133b, 0x1133c,
- 0x1133e, 0x1133e,
- 0x11340, 0x11340,
- 0x1134d, 0x1134d,
- 0x11357, 0x11357,
- 0x11366, 0x1136c,
- 0x11370, 0x11374,
- 0x113b8, 0x113b8,
- 0x113bb, 0x113c0,
- 0x113c2, 0x113c2,
- 0x113c5, 0x113c5,
- 0x113c7, 0x113c9,
- 0x113ce, 0x113d0,
- 0x113d2, 0x113d2,
- 0x113e1, 0x113e2,
- 0x11438, 0x1143f,
- 0x11442, 0x11444,
- 0x11446, 0x11446,
- 0x1145e, 0x1145e,
- 0x114b0, 0x114b0,
- 0x114b3, 0x114b8,
- 0x114ba, 0x114ba,
- 0x114bd, 0x114bd,
- 0x114bf, 0x114c0,
- 0x114c2, 0x114c3,
- 0x115af, 0x115af,
- 0x115b2, 0x115b5,
- 0x115bc, 0x115bd,
- 0x115bf, 0x115c0,
- 0x115dc, 0x115dd,
- 0x11633, 0x1163a,
- 0x1163d, 0x1163d,
- 0x1163f, 0x11640,
- 0x116ab, 0x116ab,
- 0x116ad, 0x116ad,
- 0x116b0, 0x116b7,
- 0x1171d, 0x1171d,
- 0x1171f, 0x1171f,
- 0x11722, 0x11725,
- 0x11727, 0x1172b,
- 0x1182f, 0x11837,
- 0x11839, 0x1183a,
- 0x11930, 0x11930,
- 0x1193b, 0x1193e,
- 0x11943, 0x11943,
- 0x119d4, 0x119d7,
- 0x119da, 0x119db,
- 0x119e0, 0x119e0,
- 0x11a01, 0x11a0a,
- 0x11a33, 0x11a38,
- 0x11a3b, 0x11a3e,
- 0x11a47, 0x11a47,
- 0x11a51, 0x11a56,
- 0x11a59, 0x11a5b,
- 0x11a8a, 0x11a96,
- 0x11a98, 0x11a99,
- 0x11c30, 0x11c36,
- 0x11c38, 0x11c3d,
- 0x11c3f, 0x11c3f,
- 0x11c92, 0x11ca7,
- 0x11caa, 0x11cb0,
- 0x11cb2, 0x11cb3,
- 0x11cb5, 0x11cb6,
- 0x11d31, 0x11d36,
- 0x11d3a, 0x11d3a,
- 0x11d3c, 0x11d3d,
- 0x11d3f, 0x11d45,
- 0x11d47, 0x11d47,
- 0x11d90, 0x11d91,
- 0x11d95, 0x11d95,
- 0x11d97, 0x11d97,
- 0x11ef3, 0x11ef4,
- 0x11f00, 0x11f01,
- 0x11f36, 0x11f3a,
- 0x11f40, 0x11f42,
- 0x11f5a, 0x11f5a,
- 0x13440, 0x13440,
- 0x13447, 0x13455,
- 0x1611e, 0x16129,
- 0x1612d, 0x1612f,
- 0x16af0, 0x16af4,
- 0x16b30, 0x16b36,
- 0x16f4f, 0x16f4f,
- 0x16f8f, 0x16f92,
- 0x16fe4, 0x16fe4,
- 0x16ff0, 0x16ff1,
- 0x1bc9d, 0x1bc9e,
- 0x1cf00, 0x1cf2d,
- 0x1cf30, 0x1cf46,
- 0x1d165, 0x1d169,
- 0x1d16d, 0x1d172,
- 0x1d17b, 0x1d182,
- 0x1d185, 0x1d18b,
- 0x1d1aa, 0x1d1ad,
- 0x1d242, 0x1d244,
- 0x1da00, 0x1da36,
- 0x1da3b, 0x1da6c,
- 0x1da75, 0x1da75,
- 0x1da84, 0x1da84,
- 0x1da9b, 0x1da9f,
- 0x1daa1, 0x1daaf,
- 0x1e000, 0x1e006,
- 0x1e008, 0x1e018,
- 0x1e01b, 0x1e021,
- 0x1e023, 0x1e024,
- 0x1e026, 0x1e02a,
- 0x1e08f, 0x1e08f,
- 0x1e130, 0x1e136,
- 0x1e2ae, 0x1e2ae,
- 0x1e2ec, 0x1e2ef,
- 0x1e4ec, 0x1e4ef,
- 0x1e5ee, 0x1e5ef,
- 0x1e8d0, 0x1e8d6,
- 0x1e944, 0x1e94a,
- 0x1f3fb, 0x1f3ff,
- 0xe0020, 0xe007f,
- 0xe0100, 0xe01ef,
-}; /* CR_InCB_Extend */
-
-/* 'Common': Script */
-static const OnigCodePoint CR_Common[] = {
- 174,
- 0x0000, 0x0040,
- 0x005b, 0x0060,
- 0x007b, 0x00a9,
- 0x00ab, 0x00b9,
- 0x00bb, 0x00bf,
- 0x00d7, 0x00d7,
- 0x00f7, 0x00f7,
- 0x02b9, 0x02df,
- 0x02e5, 0x02e9,
- 0x02ec, 0x02ff,
- 0x0374, 0x0374,
- 0x037e, 0x037e,
- 0x0385, 0x0385,
- 0x0387, 0x0387,
- 0x0605, 0x0605,
- 0x060c, 0x060c,
- 0x061b, 0x061b,
- 0x061f, 0x061f,
- 0x0640, 0x0640,
- 0x06dd, 0x06dd,
- 0x08e2, 0x08e2,
- 0x0964, 0x0965,
- 0x0e3f, 0x0e3f,
- 0x0fd5, 0x0fd8,
- 0x10fb, 0x10fb,
- 0x16eb, 0x16ed,
- 0x1735, 0x1736,
- 0x1802, 0x1803,
- 0x1805, 0x1805,
- 0x1cd3, 0x1cd3,
- 0x1ce1, 0x1ce1,
- 0x1ce9, 0x1cec,
- 0x1cee, 0x1cf3,
- 0x1cf5, 0x1cf7,
- 0x1cfa, 0x1cfa,
- 0x2000, 0x200b,
- 0x200e, 0x2064,
- 0x2066, 0x2070,
- 0x2074, 0x207e,
- 0x2080, 0x208e,
- 0x20a0, 0x20c0,
- 0x2100, 0x2125,
- 0x2127, 0x2129,
- 0x212c, 0x2131,
- 0x2133, 0x214d,
- 0x214f, 0x215f,
- 0x2189, 0x218b,
- 0x2190, 0x2429,
- 0x2440, 0x244a,
- 0x2460, 0x27ff,
- 0x2900, 0x2b73,
- 0x2b76, 0x2b95,
- 0x2b97, 0x2bff,
- 0x2e00, 0x2e5d,
- 0x2ff0, 0x3004,
- 0x3006, 0x3006,
- 0x3008, 0x3020,
- 0x3030, 0x3037,
- 0x303c, 0x303f,
- 0x309b, 0x309c,
- 0x30a0, 0x30a0,
- 0x30fb, 0x30fc,
- 0x3190, 0x319f,
- 0x31c0, 0x31e5,
- 0x31ef, 0x31ef,
- 0x3220, 0x325f,
- 0x327f, 0x32cf,
- 0x32ff, 0x32ff,
- 0x3358, 0x33ff,
- 0x4dc0, 0x4dff,
- 0xa700, 0xa721,
- 0xa788, 0xa78a,
- 0xa830, 0xa839,
- 0xa92e, 0xa92e,
- 0xa9cf, 0xa9cf,
- 0xab5b, 0xab5b,
- 0xab6a, 0xab6b,
- 0xfd3e, 0xfd3f,
- 0xfe10, 0xfe19,
- 0xfe30, 0xfe52,
- 0xfe54, 0xfe66,
- 0xfe68, 0xfe6b,
- 0xfeff, 0xfeff,
- 0xff01, 0xff20,
- 0xff3b, 0xff40,
- 0xff5b, 0xff65,
- 0xff70, 0xff70,
- 0xff9e, 0xff9f,
- 0xffe0, 0xffe6,
- 0xffe8, 0xffee,
- 0xfff9, 0xfffd,
- 0x10100, 0x10102,
- 0x10107, 0x10133,
- 0x10137, 0x1013f,
- 0x10190, 0x1019c,
- 0x101d0, 0x101fc,
- 0x102e1, 0x102fb,
- 0x1bca0, 0x1bca3,
- 0x1cc00, 0x1ccf9,
- 0x1cd00, 0x1ceb3,
- 0x1cf50, 0x1cfc3,
- 0x1d000, 0x1d0f5,
- 0x1d100, 0x1d126,
- 0x1d129, 0x1d166,
- 0x1d16a, 0x1d17a,
- 0x1d183, 0x1d184,
- 0x1d18c, 0x1d1a9,
- 0x1d1ae, 0x1d1ea,
- 0x1d2c0, 0x1d2d3,
- 0x1d2e0, 0x1d2f3,
- 0x1d300, 0x1d356,
- 0x1d360, 0x1d378,
- 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, 0x1d7cb,
- 0x1d7ce, 0x1d7ff,
- 0x1ec71, 0x1ecb4,
- 0x1ed01, 0x1ed3d,
- 0x1f000, 0x1f02b,
- 0x1f030, 0x1f093,
- 0x1f0a0, 0x1f0ae,
- 0x1f0b1, 0x1f0bf,
- 0x1f0c1, 0x1f0cf,
- 0x1f0d1, 0x1f0f5,
- 0x1f100, 0x1f1ad,
- 0x1f1e6, 0x1f1ff,
- 0x1f201, 0x1f202,
- 0x1f210, 0x1f23b,
- 0x1f240, 0x1f248,
- 0x1f250, 0x1f251,
- 0x1f260, 0x1f265,
- 0x1f300, 0x1f6d7,
- 0x1f6dc, 0x1f6ec,
- 0x1f6f0, 0x1f6fc,
- 0x1f700, 0x1f776,
- 0x1f77b, 0x1f7d9,
- 0x1f7e0, 0x1f7eb,
- 0x1f7f0, 0x1f7f0,
- 0x1f800, 0x1f80b,
- 0x1f810, 0x1f847,
- 0x1f850, 0x1f859,
- 0x1f860, 0x1f887,
- 0x1f890, 0x1f8ad,
- 0x1f8b0, 0x1f8bb,
- 0x1f8c0, 0x1f8c1,
- 0x1f900, 0x1fa53,
- 0x1fa60, 0x1fa6d,
- 0x1fa70, 0x1fa7c,
- 0x1fa80, 0x1fa89,
- 0x1fa8f, 0x1fac6,
- 0x1face, 0x1fadc,
- 0x1fadf, 0x1fae9,
- 0x1faf0, 0x1faf8,
- 0x1fb00, 0x1fb92,
- 0x1fb94, 0x1fbf9,
- 0xe0001, 0xe0001,
- 0xe0020, 0xe007f,
-}; /* CR_Common */
-
-/* 'Latin': Script */
-static const OnigCodePoint CR_Latin[] = {
- 39,
- 0x0041, 0x005a,
- 0x0061, 0x007a,
- 0x00aa, 0x00aa,
- 0x00ba, 0x00ba,
- 0x00c0, 0x00d6,
- 0x00d8, 0x00f6,
- 0x00f8, 0x02b8,
- 0x02e0, 0x02e4,
- 0x1d00, 0x1d25,
- 0x1d2c, 0x1d5c,
- 0x1d62, 0x1d65,
- 0x1d6b, 0x1d77,
- 0x1d79, 0x1dbe,
- 0x1e00, 0x1eff,
- 0x2071, 0x2071,
- 0x207f, 0x207f,
- 0x2090, 0x209c,
- 0x212a, 0x212b,
- 0x2132, 0x2132,
- 0x214e, 0x214e,
- 0x2160, 0x2188,
- 0x2c60, 0x2c7f,
- 0xa722, 0xa787,
- 0xa78b, 0xa7cd,
- 0xa7d0, 0xa7d1,
- 0xa7d3, 0xa7d3,
- 0xa7d5, 0xa7dc,
- 0xa7f2, 0xa7ff,
- 0xab30, 0xab5a,
- 0xab5c, 0xab64,
- 0xab66, 0xab69,
- 0xfb00, 0xfb06,
- 0xff21, 0xff3a,
- 0xff41, 0xff5a,
- 0x10780, 0x10785,
- 0x10787, 0x107b0,
- 0x107b2, 0x107ba,
- 0x1df00, 0x1df1e,
- 0x1df25, 0x1df2a,
-}; /* CR_Latin */
-
-/* 'Greek': Script */
-static const OnigCodePoint CR_Greek[] = {
- 36,
- 0x0370, 0x0373,
- 0x0375, 0x0377,
- 0x037a, 0x037d,
- 0x037f, 0x037f,
- 0x0384, 0x0384,
- 0x0386, 0x0386,
- 0x0388, 0x038a,
- 0x038c, 0x038c,
- 0x038e, 0x03a1,
- 0x03a3, 0x03e1,
- 0x03f0, 0x03ff,
- 0x1d26, 0x1d2a,
- 0x1d5d, 0x1d61,
- 0x1d66, 0x1d6a,
- 0x1dbf, 0x1dbf,
- 0x1f00, 0x1f15,
- 0x1f18, 0x1f1d,
- 0x1f20, 0x1f45,
- 0x1f48, 0x1f4d,
- 0x1f50, 0x1f57,
- 0x1f59, 0x1f59,
- 0x1f5b, 0x1f5b,
- 0x1f5d, 0x1f5d,
- 0x1f5f, 0x1f7d,
- 0x1f80, 0x1fb4,
- 0x1fb6, 0x1fc4,
- 0x1fc6, 0x1fd3,
- 0x1fd6, 0x1fdb,
- 0x1fdd, 0x1fef,
- 0x1ff2, 0x1ff4,
- 0x1ff6, 0x1ffe,
- 0x2126, 0x2126,
- 0xab65, 0xab65,
- 0x10140, 0x1018e,
- 0x101a0, 0x101a0,
- 0x1d200, 0x1d245,
-}; /* CR_Greek */
-
-/* 'Cyrillic': Script */
-static const OnigCodePoint CR_Cyrillic[] = {
- 10,
- 0x0400, 0x0484,
- 0x0487, 0x052f,
- 0x1c80, 0x1c8a,
- 0x1d2b, 0x1d2b,
- 0x1d78, 0x1d78,
- 0x2de0, 0x2dff,
- 0xa640, 0xa69f,
- 0xfe2e, 0xfe2f,
- 0x1e030, 0x1e06d,
- 0x1e08f, 0x1e08f,
-}; /* CR_Cyrillic */
-
-/* 'Armenian': Script */
-static const OnigCodePoint CR_Armenian[] = {
- 4,
- 0x0531, 0x0556,
- 0x0559, 0x058a,
- 0x058d, 0x058f,
- 0xfb13, 0xfb17,
-}; /* CR_Armenian */
-
-/* 'Hebrew': Script */
-static const OnigCodePoint CR_Hebrew[] = {
- 9,
- 0x0591, 0x05c7,
- 0x05d0, 0x05ea,
- 0x05ef, 0x05f4,
- 0xfb1d, 0xfb36,
- 0xfb38, 0xfb3c,
- 0xfb3e, 0xfb3e,
- 0xfb40, 0xfb41,
- 0xfb43, 0xfb44,
- 0xfb46, 0xfb4f,
-}; /* CR_Hebrew */
-
-/* 'Arabic': Script */
-static const OnigCodePoint CR_Arabic[] = {
- 59,
- 0x0600, 0x0604,
- 0x0606, 0x060b,
- 0x060d, 0x061a,
- 0x061c, 0x061e,
- 0x0620, 0x063f,
- 0x0641, 0x064a,
- 0x0656, 0x066f,
- 0x0671, 0x06dc,
- 0x06de, 0x06ff,
- 0x0750, 0x077f,
- 0x0870, 0x088e,
- 0x0890, 0x0891,
- 0x0897, 0x08e1,
- 0x08e3, 0x08ff,
- 0xfb50, 0xfbc2,
- 0xfbd3, 0xfd3d,
- 0xfd40, 0xfd8f,
- 0xfd92, 0xfdc7,
- 0xfdcf, 0xfdcf,
- 0xfdf0, 0xfdff,
- 0xfe70, 0xfe74,
- 0xfe76, 0xfefc,
- 0x10e60, 0x10e7e,
- 0x10ec2, 0x10ec4,
- 0x10efc, 0x10eff,
- 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,
- 0x1eef0, 0x1eef1,
-}; /* CR_Arabic */
-
-/* 'Syriac': Script */
-static const OnigCodePoint CR_Syriac[] = {
- 4,
- 0x0700, 0x070d,
- 0x070f, 0x074a,
- 0x074d, 0x074f,
- 0x0860, 0x086a,
-}; /* CR_Syriac */
-
-/* 'Thaana': Script */
-static const OnigCodePoint CR_Thaana[] = {
- 1,
- 0x0780, 0x07b1,
-}; /* CR_Thaana */
-
-/* 'Devanagari': Script */
-static const OnigCodePoint CR_Devanagari[] = {
- 5,
- 0x0900, 0x0950,
- 0x0955, 0x0963,
- 0x0966, 0x097f,
- 0xa8e0, 0xa8ff,
- 0x11b00, 0x11b09,
-}; /* CR_Devanagari */
-
-/* 'Bengali': Script */
-static const OnigCodePoint CR_Bengali[] = {
- 14,
- 0x0980, 0x0983,
- 0x0985, 0x098c,
- 0x098f, 0x0990,
- 0x0993, 0x09a8,
- 0x09aa, 0x09b0,
- 0x09b2, 0x09b2,
- 0x09b6, 0x09b9,
- 0x09bc, 0x09c4,
- 0x09c7, 0x09c8,
- 0x09cb, 0x09ce,
- 0x09d7, 0x09d7,
- 0x09dc, 0x09dd,
- 0x09df, 0x09e3,
- 0x09e6, 0x09fe,
-}; /* CR_Bengali */
-
-/* 'Gurmukhi': Script */
-static const OnigCodePoint CR_Gurmukhi[] = {
- 16,
- 0x0a01, 0x0a03,
- 0x0a05, 0x0a0a,
- 0x0a0f, 0x0a10,
- 0x0a13, 0x0a28,
- 0x0a2a, 0x0a30,
- 0x0a32, 0x0a33,
- 0x0a35, 0x0a36,
- 0x0a38, 0x0a39,
- 0x0a3c, 0x0a3c,
- 0x0a3e, 0x0a42,
- 0x0a47, 0x0a48,
- 0x0a4b, 0x0a4d,
- 0x0a51, 0x0a51,
- 0x0a59, 0x0a5c,
- 0x0a5e, 0x0a5e,
- 0x0a66, 0x0a76,
-}; /* CR_Gurmukhi */
-
-/* 'Gujarati': Script */
-static const OnigCodePoint CR_Gujarati[] = {
- 14,
- 0x0a81, 0x0a83,
- 0x0a85, 0x0a8d,
- 0x0a8f, 0x0a91,
- 0x0a93, 0x0aa8,
- 0x0aaa, 0x0ab0,
- 0x0ab2, 0x0ab3,
- 0x0ab5, 0x0ab9,
- 0x0abc, 0x0ac5,
- 0x0ac7, 0x0ac9,
- 0x0acb, 0x0acd,
- 0x0ad0, 0x0ad0,
- 0x0ae0, 0x0ae3,
- 0x0ae6, 0x0af1,
- 0x0af9, 0x0aff,
-}; /* CR_Gujarati */
-
-/* 'Oriya': Script */
-static const OnigCodePoint CR_Oriya[] = {
- 14,
- 0x0b01, 0x0b03,
- 0x0b05, 0x0b0c,
- 0x0b0f, 0x0b10,
- 0x0b13, 0x0b28,
- 0x0b2a, 0x0b30,
- 0x0b32, 0x0b33,
- 0x0b35, 0x0b39,
- 0x0b3c, 0x0b44,
- 0x0b47, 0x0b48,
- 0x0b4b, 0x0b4d,
- 0x0b55, 0x0b57,
- 0x0b5c, 0x0b5d,
- 0x0b5f, 0x0b63,
- 0x0b66, 0x0b77,
-}; /* CR_Oriya */
-
-/* 'Tamil': Script */
-static const OnigCodePoint CR_Tamil[] = {
- 18,
- 0x0b82, 0x0b83,
- 0x0b85, 0x0b8a,
- 0x0b8e, 0x0b90,
- 0x0b92, 0x0b95,
- 0x0b99, 0x0b9a,
- 0x0b9c, 0x0b9c,
- 0x0b9e, 0x0b9f,
- 0x0ba3, 0x0ba4,
- 0x0ba8, 0x0baa,
- 0x0bae, 0x0bb9,
- 0x0bbe, 0x0bc2,
- 0x0bc6, 0x0bc8,
- 0x0bca, 0x0bcd,
- 0x0bd0, 0x0bd0,
- 0x0bd7, 0x0bd7,
- 0x0be6, 0x0bfa,
- 0x11fc0, 0x11ff1,
- 0x11fff, 0x11fff,
-}; /* CR_Tamil */
-
-/* 'Telugu': Script */
-static const OnigCodePoint CR_Telugu[] = {
- 13,
- 0x0c00, 0x0c0c,
- 0x0c0e, 0x0c10,
- 0x0c12, 0x0c28,
- 0x0c2a, 0x0c39,
- 0x0c3c, 0x0c44,
- 0x0c46, 0x0c48,
- 0x0c4a, 0x0c4d,
- 0x0c55, 0x0c56,
- 0x0c58, 0x0c5a,
- 0x0c5d, 0x0c5d,
- 0x0c60, 0x0c63,
- 0x0c66, 0x0c6f,
- 0x0c77, 0x0c7f,
-}; /* CR_Telugu */
-
-/* 'Kannada': Script */
-static const OnigCodePoint CR_Kannada[] = {
- 13,
- 0x0c80, 0x0c8c,
- 0x0c8e, 0x0c90,
- 0x0c92, 0x0ca8,
- 0x0caa, 0x0cb3,
- 0x0cb5, 0x0cb9,
- 0x0cbc, 0x0cc4,
- 0x0cc6, 0x0cc8,
- 0x0cca, 0x0ccd,
- 0x0cd5, 0x0cd6,
- 0x0cdd, 0x0cde,
- 0x0ce0, 0x0ce3,
- 0x0ce6, 0x0cef,
- 0x0cf1, 0x0cf3,
-}; /* CR_Kannada */
-
-/* 'Malayalam': Script */
-static const OnigCodePoint CR_Malayalam[] = {
- 7,
- 0x0d00, 0x0d0c,
- 0x0d0e, 0x0d10,
- 0x0d12, 0x0d44,
- 0x0d46, 0x0d48,
- 0x0d4a, 0x0d4f,
- 0x0d54, 0x0d63,
- 0x0d66, 0x0d7f,
-}; /* CR_Malayalam */
-
-/* 'Sinhala': Script */
-static const OnigCodePoint CR_Sinhala[] = {
- 13,
- 0x0d81, 0x0d83,
- 0x0d85, 0x0d96,
- 0x0d9a, 0x0db1,
- 0x0db3, 0x0dbb,
- 0x0dbd, 0x0dbd,
- 0x0dc0, 0x0dc6,
- 0x0dca, 0x0dca,
- 0x0dcf, 0x0dd4,
- 0x0dd6, 0x0dd6,
- 0x0dd8, 0x0ddf,
- 0x0de6, 0x0def,
- 0x0df2, 0x0df4,
- 0x111e1, 0x111f4,
-}; /* CR_Sinhala */
-
-/* 'Thai': Script */
-static const OnigCodePoint CR_Thai[] = {
- 2,
- 0x0e01, 0x0e3a,
- 0x0e40, 0x0e5b,
-}; /* CR_Thai */
-
-/* 'Lao': Script */
-static const OnigCodePoint CR_Lao[] = {
- 11,
- 0x0e81, 0x0e82,
- 0x0e84, 0x0e84,
- 0x0e86, 0x0e8a,
- 0x0e8c, 0x0ea3,
- 0x0ea5, 0x0ea5,
- 0x0ea7, 0x0ebd,
- 0x0ec0, 0x0ec4,
- 0x0ec6, 0x0ec6,
- 0x0ec8, 0x0ece,
- 0x0ed0, 0x0ed9,
- 0x0edc, 0x0edf,
-}; /* CR_Lao */
-
-/* 'Tibetan': Script */
-static const OnigCodePoint CR_Tibetan[] = {
- 7,
- 0x0f00, 0x0f47,
- 0x0f49, 0x0f6c,
- 0x0f71, 0x0f97,
- 0x0f99, 0x0fbc,
- 0x0fbe, 0x0fcc,
- 0x0fce, 0x0fd4,
- 0x0fd9, 0x0fda,
-}; /* CR_Tibetan */
-
-/* 'Myanmar': Script */
-static const OnigCodePoint CR_Myanmar[] = {
- 4,
- 0x1000, 0x109f,
- 0xa9e0, 0xa9fe,
- 0xaa60, 0xaa7f,
- 0x116d0, 0x116e3,
-}; /* CR_Myanmar */
-
-/* 'Georgian': Script */
-static const OnigCodePoint CR_Georgian[] = {
- 10,
- 0x10a0, 0x10c5,
- 0x10c7, 0x10c7,
- 0x10cd, 0x10cd,
- 0x10d0, 0x10fa,
- 0x10fc, 0x10ff,
- 0x1c90, 0x1cba,
- 0x1cbd, 0x1cbf,
- 0x2d00, 0x2d25,
- 0x2d27, 0x2d27,
- 0x2d2d, 0x2d2d,
-}; /* CR_Georgian */
-
-/* 'Hangul': Script */
-static const OnigCodePoint CR_Hangul[] = {
- 14,
- 0x1100, 0x11ff,
- 0x302e, 0x302f,
- 0x3131, 0x318e,
- 0x3200, 0x321e,
- 0x3260, 0x327e,
- 0xa960, 0xa97c,
- 0xac00, 0xd7a3,
- 0xd7b0, 0xd7c6,
- 0xd7cb, 0xd7fb,
- 0xffa0, 0xffbe,
- 0xffc2, 0xffc7,
- 0xffca, 0xffcf,
- 0xffd2, 0xffd7,
- 0xffda, 0xffdc,
-}; /* CR_Hangul */
-
-/* 'Ethiopic': Script */
-static const OnigCodePoint CR_Ethiopic[] = {
- 36,
- 0x1200, 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,
- 0x135d, 0x137c,
- 0x1380, 0x1399,
- 0x2d80, 0x2d96,
- 0x2da0, 0x2da6,
- 0x2da8, 0x2dae,
- 0x2db0, 0x2db6,
- 0x2db8, 0x2dbe,
- 0x2dc0, 0x2dc6,
- 0x2dc8, 0x2dce,
- 0x2dd0, 0x2dd6,
- 0x2dd8, 0x2dde,
- 0xab01, 0xab06,
- 0xab09, 0xab0e,
- 0xab11, 0xab16,
- 0xab20, 0xab26,
- 0xab28, 0xab2e,
- 0x1e7e0, 0x1e7e6,
- 0x1e7e8, 0x1e7eb,
- 0x1e7ed, 0x1e7ee,
- 0x1e7f0, 0x1e7fe,
-}; /* CR_Ethiopic */
-
-/* 'Cherokee': Script */
-static const OnigCodePoint CR_Cherokee[] = {
- 3,
- 0x13a0, 0x13f5,
- 0x13f8, 0x13fd,
- 0xab70, 0xabbf,
-}; /* CR_Cherokee */
-
-/* 'Canadian_Aboriginal': Script */
-static const OnigCodePoint CR_Canadian_Aboriginal[] = {
- 3,
- 0x1400, 0x167f,
- 0x18b0, 0x18f5,
- 0x11ab0, 0x11abf,
-}; /* CR_Canadian_Aboriginal */
-
-/* 'Ogham': Script */
-static const OnigCodePoint CR_Ogham[] = {
- 1,
- 0x1680, 0x169c,
-}; /* CR_Ogham */
-
-/* 'Runic': Script */
-static const OnigCodePoint CR_Runic[] = {
- 2,
- 0x16a0, 0x16ea,
- 0x16ee, 0x16f8,
-}; /* CR_Runic */
-
-/* 'Khmer': Script */
-static const OnigCodePoint CR_Khmer[] = {
- 4,
- 0x1780, 0x17dd,
- 0x17e0, 0x17e9,
- 0x17f0, 0x17f9,
- 0x19e0, 0x19ff,
-}; /* CR_Khmer */
-
-/* 'Mongolian': Script */
-static const OnigCodePoint CR_Mongolian[] = {
- 6,
- 0x1800, 0x1801,
- 0x1804, 0x1804,
- 0x1806, 0x1819,
- 0x1820, 0x1878,
- 0x1880, 0x18aa,
- 0x11660, 0x1166c,
-}; /* CR_Mongolian */
-
-/* 'Hiragana': Script */
-static const OnigCodePoint CR_Hiragana[] = {
- 6,
- 0x3041, 0x3096,
- 0x309d, 0x309f,
- 0x1b001, 0x1b11f,
- 0x1b132, 0x1b132,
- 0x1b150, 0x1b152,
- 0x1f200, 0x1f200,
-}; /* CR_Hiragana */
-
-/* 'Katakana': Script */
-static const OnigCodePoint CR_Katakana[] = {
- 14,
- 0x30a1, 0x30fa,
- 0x30fd, 0x30ff,
- 0x31f0, 0x31ff,
- 0x32d0, 0x32fe,
- 0x3300, 0x3357,
- 0xff66, 0xff6f,
- 0xff71, 0xff9d,
- 0x1aff0, 0x1aff3,
- 0x1aff5, 0x1affb,
- 0x1affd, 0x1affe,
- 0x1b000, 0x1b000,
- 0x1b120, 0x1b122,
- 0x1b155, 0x1b155,
- 0x1b164, 0x1b167,
-}; /* CR_Katakana */
-
-/* 'Bopomofo': Script */
-static const OnigCodePoint CR_Bopomofo[] = {
- 3,
- 0x02ea, 0x02eb,
- 0x3105, 0x312f,
- 0x31a0, 0x31bf,
-}; /* CR_Bopomofo */
-
-/* 'Han': Script */
-static const OnigCodePoint CR_Han[] = {
- 22,
- 0x2e80, 0x2e99,
- 0x2e9b, 0x2ef3,
- 0x2f00, 0x2fd5,
- 0x3005, 0x3005,
- 0x3007, 0x3007,
- 0x3021, 0x3029,
- 0x3038, 0x303b,
- 0x3400, 0x4dbf,
- 0x4e00, 0x9fff,
- 0xf900, 0xfa6d,
- 0xfa70, 0xfad9,
- 0x16fe2, 0x16fe3,
- 0x16ff0, 0x16ff1,
- 0x20000, 0x2a6df,
- 0x2a700, 0x2b739,
- 0x2b740, 0x2b81d,
- 0x2b820, 0x2cea1,
- 0x2ceb0, 0x2ebe0,
- 0x2ebf0, 0x2ee5d,
- 0x2f800, 0x2fa1d,
- 0x30000, 0x3134a,
- 0x31350, 0x323af,
-}; /* CR_Han */
-
-/* 'Yi': Script */
-static const OnigCodePoint CR_Yi[] = {
- 2,
- 0xa000, 0xa48c,
- 0xa490, 0xa4c6,
-}; /* CR_Yi */
-
-/* 'Old_Italic': Script */
-static const OnigCodePoint CR_Old_Italic[] = {
- 2,
- 0x10300, 0x10323,
- 0x1032d, 0x1032f,
-}; /* CR_Old_Italic */
-
-/* 'Gothic': Script */
-static const OnigCodePoint CR_Gothic[] = {
- 1,
- 0x10330, 0x1034a,
-}; /* CR_Gothic */
-
-/* 'Deseret': Script */
-static const OnigCodePoint CR_Deseret[] = {
- 1,
- 0x10400, 0x1044f,
-}; /* CR_Deseret */
-
-/* 'Inherited': Script */
-static const OnigCodePoint CR_Inherited[] = {
- 29,
- 0x0300, 0x036f,
- 0x0485, 0x0486,
- 0x064b, 0x0655,
- 0x0670, 0x0670,
- 0x0951, 0x0954,
- 0x1ab0, 0x1ace,
- 0x1cd0, 0x1cd2,
- 0x1cd4, 0x1ce0,
- 0x1ce2, 0x1ce8,
- 0x1ced, 0x1ced,
- 0x1cf4, 0x1cf4,
- 0x1cf8, 0x1cf9,
- 0x1dc0, 0x1dff,
- 0x200c, 0x200d,
- 0x20d0, 0x20f0,
- 0x302a, 0x302d,
- 0x3099, 0x309a,
- 0xfe00, 0xfe0f,
- 0xfe20, 0xfe2d,
- 0x101fd, 0x101fd,
- 0x102e0, 0x102e0,
- 0x1133b, 0x1133b,
- 0x1cf00, 0x1cf2d,
- 0x1cf30, 0x1cf46,
- 0x1d167, 0x1d169,
- 0x1d17b, 0x1d182,
- 0x1d185, 0x1d18b,
- 0x1d1aa, 0x1d1ad,
- 0xe0100, 0xe01ef,
-}; /* CR_Inherited */
-
-/* 'Tagalog': Script */
-static const OnigCodePoint CR_Tagalog[] = {
- 2,
- 0x1700, 0x1715,
- 0x171f, 0x171f,
-}; /* CR_Tagalog */
-
-/* 'Hanunoo': Script */
-static const OnigCodePoint CR_Hanunoo[] = {
- 1,
- 0x1720, 0x1734,
-}; /* CR_Hanunoo */
-
-/* 'Buhid': Script */
-static const OnigCodePoint CR_Buhid[] = {
- 1,
- 0x1740, 0x1753,
-}; /* CR_Buhid */
-
-/* 'Tagbanwa': Script */
-static const OnigCodePoint CR_Tagbanwa[] = {
- 3,
- 0x1760, 0x176c,
- 0x176e, 0x1770,
- 0x1772, 0x1773,
-}; /* CR_Tagbanwa */
-
-/* 'Limbu': Script */
-static const OnigCodePoint CR_Limbu[] = {
- 5,
- 0x1900, 0x191e,
- 0x1920, 0x192b,
- 0x1930, 0x193b,
- 0x1940, 0x1940,
- 0x1944, 0x194f,
-}; /* CR_Limbu */
-
-/* 'Tai_Le': Script */
-static const OnigCodePoint CR_Tai_Le[] = {
- 2,
- 0x1950, 0x196d,
- 0x1970, 0x1974,
-}; /* CR_Tai_Le */
-
-/* 'Linear_B': Script */
-static const OnigCodePoint CR_Linear_B[] = {
- 7,
- 0x10000, 0x1000b,
- 0x1000d, 0x10026,
- 0x10028, 0x1003a,
- 0x1003c, 0x1003d,
- 0x1003f, 0x1004d,
- 0x10050, 0x1005d,
- 0x10080, 0x100fa,
-}; /* CR_Linear_B */
-
-/* 'Ugaritic': Script */
-static const OnigCodePoint CR_Ugaritic[] = {
- 2,
- 0x10380, 0x1039d,
- 0x1039f, 0x1039f,
-}; /* CR_Ugaritic */
-
-/* 'Shavian': Script */
-static const OnigCodePoint CR_Shavian[] = {
- 1,
- 0x10450, 0x1047f,
-}; /* CR_Shavian */
-
-/* 'Osmanya': Script */
-static const OnigCodePoint CR_Osmanya[] = {
- 2,
- 0x10480, 0x1049d,
- 0x104a0, 0x104a9,
-}; /* CR_Osmanya */
-
-/* 'Cypriot': Script */
-static const OnigCodePoint CR_Cypriot[] = {
- 6,
- 0x10800, 0x10805,
- 0x10808, 0x10808,
- 0x1080a, 0x10835,
- 0x10837, 0x10838,
- 0x1083c, 0x1083c,
- 0x1083f, 0x1083f,
-}; /* CR_Cypriot */
-
-/* 'Braille': Script */
-static const OnigCodePoint CR_Braille[] = {
- 1,
- 0x2800, 0x28ff,
-}; /* CR_Braille */
-
-/* 'Buginese': Script */
-static const OnigCodePoint CR_Buginese[] = {
- 2,
- 0x1a00, 0x1a1b,
- 0x1a1e, 0x1a1f,
-}; /* CR_Buginese */
-
-/* 'Coptic': Script */
-static const OnigCodePoint CR_Coptic[] = {
- 3,
- 0x03e2, 0x03ef,
- 0x2c80, 0x2cf3,
- 0x2cf9, 0x2cff,
-}; /* CR_Coptic */
-
-/* 'New_Tai_Lue': Script */
-static const OnigCodePoint CR_New_Tai_Lue[] = {
- 4,
- 0x1980, 0x19ab,
- 0x19b0, 0x19c9,
- 0x19d0, 0x19da,
- 0x19de, 0x19df,
-}; /* CR_New_Tai_Lue */
-
-/* 'Glagolitic': Script */
-static const OnigCodePoint CR_Glagolitic[] = {
- 6,
- 0x2c00, 0x2c5f,
- 0x1e000, 0x1e006,
- 0x1e008, 0x1e018,
- 0x1e01b, 0x1e021,
- 0x1e023, 0x1e024,
- 0x1e026, 0x1e02a,
-}; /* CR_Glagolitic */
-
-/* 'Tifinagh': Script */
-static const OnigCodePoint CR_Tifinagh[] = {
- 3,
- 0x2d30, 0x2d67,
- 0x2d6f, 0x2d70,
- 0x2d7f, 0x2d7f,
-}; /* CR_Tifinagh */
-
-/* 'Syloti_Nagri': Script */
-static const OnigCodePoint CR_Syloti_Nagri[] = {
- 1,
- 0xa800, 0xa82c,
-}; /* CR_Syloti_Nagri */
-
-/* 'Old_Persian': Script */
-static const OnigCodePoint CR_Old_Persian[] = {
- 2,
- 0x103a0, 0x103c3,
- 0x103c8, 0x103d5,
-}; /* CR_Old_Persian */
-
-/* 'Kharoshthi': Script */
-static const OnigCodePoint CR_Kharoshthi[] = {
- 8,
- 0x10a00, 0x10a03,
- 0x10a05, 0x10a06,
- 0x10a0c, 0x10a13,
- 0x10a15, 0x10a17,
- 0x10a19, 0x10a35,
- 0x10a38, 0x10a3a,
- 0x10a3f, 0x10a48,
- 0x10a50, 0x10a58,
-}; /* CR_Kharoshthi */
-
-/* 'Balinese': Script */
-static const OnigCodePoint CR_Balinese[] = {
- 2,
- 0x1b00, 0x1b4c,
- 0x1b4e, 0x1b7f,
-}; /* CR_Balinese */
-
-/* 'Cuneiform': Script */
-static const OnigCodePoint CR_Cuneiform[] = {
- 4,
- 0x12000, 0x12399,
- 0x12400, 0x1246e,
- 0x12470, 0x12474,
- 0x12480, 0x12543,
-}; /* CR_Cuneiform */
-
-/* 'Phoenician': Script */
-static const OnigCodePoint CR_Phoenician[] = {
- 2,
- 0x10900, 0x1091b,
- 0x1091f, 0x1091f,
-}; /* CR_Phoenician */
-
-/* 'Phags_Pa': Script */
-static const OnigCodePoint CR_Phags_Pa[] = {
- 1,
- 0xa840, 0xa877,
-}; /* CR_Phags_Pa */
-
-/* 'Nko': Script */
-static const OnigCodePoint CR_Nko[] = {
- 2,
- 0x07c0, 0x07fa,
- 0x07fd, 0x07ff,
-}; /* CR_Nko */
-
-/* 'Sundanese': Script */
-static const OnigCodePoint CR_Sundanese[] = {
- 2,
- 0x1b80, 0x1bbf,
- 0x1cc0, 0x1cc7,
-}; /* CR_Sundanese */
-
-/* 'Lepcha': Script */
-static const OnigCodePoint CR_Lepcha[] = {
- 3,
- 0x1c00, 0x1c37,
- 0x1c3b, 0x1c49,
- 0x1c4d, 0x1c4f,
-}; /* CR_Lepcha */
-
-/* 'Ol_Chiki': Script */
-static const OnigCodePoint CR_Ol_Chiki[] = {
- 1,
- 0x1c50, 0x1c7f,
-}; /* CR_Ol_Chiki */
-
-/* 'Vai': Script */
-static const OnigCodePoint CR_Vai[] = {
- 1,
- 0xa500, 0xa62b,
-}; /* CR_Vai */
-
-/* 'Saurashtra': Script */
-static const OnigCodePoint CR_Saurashtra[] = {
- 2,
- 0xa880, 0xa8c5,
- 0xa8ce, 0xa8d9,
-}; /* CR_Saurashtra */
-
-/* 'Kayah_Li': Script */
-static const OnigCodePoint CR_Kayah_Li[] = {
- 2,
- 0xa900, 0xa92d,
- 0xa92f, 0xa92f,
-}; /* CR_Kayah_Li */
-
-/* 'Rejang': Script */
-static const OnigCodePoint CR_Rejang[] = {
- 2,
- 0xa930, 0xa953,
- 0xa95f, 0xa95f,
-}; /* CR_Rejang */
-
-/* 'Lycian': Script */
-static const OnigCodePoint CR_Lycian[] = {
- 1,
- 0x10280, 0x1029c,
-}; /* CR_Lycian */
-
-/* 'Carian': Script */
-static const OnigCodePoint CR_Carian[] = {
- 1,
- 0x102a0, 0x102d0,
-}; /* CR_Carian */
-
-/* 'Lydian': Script */
-static const OnigCodePoint CR_Lydian[] = {
- 2,
- 0x10920, 0x10939,
- 0x1093f, 0x1093f,
-}; /* CR_Lydian */
-
-/* 'Cham': Script */
-static const OnigCodePoint CR_Cham[] = {
- 4,
- 0xaa00, 0xaa36,
- 0xaa40, 0xaa4d,
- 0xaa50, 0xaa59,
- 0xaa5c, 0xaa5f,
-}; /* CR_Cham */
-
-/* 'Tai_Tham': Script */
-static const OnigCodePoint CR_Tai_Tham[] = {
- 5,
- 0x1a20, 0x1a5e,
- 0x1a60, 0x1a7c,
- 0x1a7f, 0x1a89,
- 0x1a90, 0x1a99,
- 0x1aa0, 0x1aad,
-}; /* CR_Tai_Tham */
-
-/* 'Tai_Viet': Script */
-static const OnigCodePoint CR_Tai_Viet[] = {
- 2,
- 0xaa80, 0xaac2,
- 0xaadb, 0xaadf,
-}; /* CR_Tai_Viet */
-
-/* 'Avestan': Script */
-static const OnigCodePoint CR_Avestan[] = {
- 2,
- 0x10b00, 0x10b35,
- 0x10b39, 0x10b3f,
-}; /* CR_Avestan */
-
-/* 'Egyptian_Hieroglyphs': Script */
-static const OnigCodePoint CR_Egyptian_Hieroglyphs[] = {
- 2,
- 0x13000, 0x13455,
- 0x13460, 0x143fa,
-}; /* CR_Egyptian_Hieroglyphs */
-
-/* 'Samaritan': Script */
-static const OnigCodePoint CR_Samaritan[] = {
- 2,
- 0x0800, 0x082d,
- 0x0830, 0x083e,
-}; /* CR_Samaritan */
-
-/* 'Lisu': Script */
-static const OnigCodePoint CR_Lisu[] = {
- 2,
- 0xa4d0, 0xa4ff,
- 0x11fb0, 0x11fb0,
-}; /* CR_Lisu */
-
-/* 'Bamum': Script */
-static const OnigCodePoint CR_Bamum[] = {
- 2,
- 0xa6a0, 0xa6f7,
- 0x16800, 0x16a38,
-}; /* CR_Bamum */
-
-/* 'Javanese': Script */
-static const OnigCodePoint CR_Javanese[] = {
- 3,
- 0xa980, 0xa9cd,
- 0xa9d0, 0xa9d9,
- 0xa9de, 0xa9df,
-}; /* CR_Javanese */
-
-/* 'Meetei_Mayek': Script */
-static const OnigCodePoint CR_Meetei_Mayek[] = {
- 3,
- 0xaae0, 0xaaf6,
- 0xabc0, 0xabed,
- 0xabf0, 0xabf9,
-}; /* CR_Meetei_Mayek */
-
-/* 'Imperial_Aramaic': Script */
-static const OnigCodePoint CR_Imperial_Aramaic[] = {
- 2,
- 0x10840, 0x10855,
- 0x10857, 0x1085f,
-}; /* CR_Imperial_Aramaic */
-
-/* 'Old_South_Arabian': Script */
-static const OnigCodePoint CR_Old_South_Arabian[] = {
- 1,
- 0x10a60, 0x10a7f,
-}; /* CR_Old_South_Arabian */
-
-/* 'Inscriptional_Parthian': Script */
-static const OnigCodePoint CR_Inscriptional_Parthian[] = {
- 2,
- 0x10b40, 0x10b55,
- 0x10b58, 0x10b5f,
-}; /* CR_Inscriptional_Parthian */
-
-/* 'Inscriptional_Pahlavi': Script */
-static const OnigCodePoint CR_Inscriptional_Pahlavi[] = {
- 2,
- 0x10b60, 0x10b72,
- 0x10b78, 0x10b7f,
-}; /* CR_Inscriptional_Pahlavi */
-
-/* 'Old_Turkic': Script */
-static const OnigCodePoint CR_Old_Turkic[] = {
- 1,
- 0x10c00, 0x10c48,
-}; /* CR_Old_Turkic */
-
-/* 'Kaithi': Script */
-static const OnigCodePoint CR_Kaithi[] = {
- 2,
- 0x11080, 0x110c2,
- 0x110cd, 0x110cd,
-}; /* CR_Kaithi */
-
-/* 'Batak': Script */
-static const OnigCodePoint CR_Batak[] = {
- 2,
- 0x1bc0, 0x1bf3,
- 0x1bfc, 0x1bff,
-}; /* CR_Batak */
-
-/* 'Brahmi': Script */
-static const OnigCodePoint CR_Brahmi[] = {
- 3,
- 0x11000, 0x1104d,
- 0x11052, 0x11075,
- 0x1107f, 0x1107f,
-}; /* CR_Brahmi */
-
-/* 'Mandaic': Script */
-static const OnigCodePoint CR_Mandaic[] = {
- 2,
- 0x0840, 0x085b,
- 0x085e, 0x085e,
-}; /* CR_Mandaic */
-
-/* 'Chakma': Script */
-static const OnigCodePoint CR_Chakma[] = {
- 2,
- 0x11100, 0x11134,
- 0x11136, 0x11147,
-}; /* CR_Chakma */
-
-/* 'Meroitic_Cursive': Script */
-static const OnigCodePoint CR_Meroitic_Cursive[] = {
- 3,
- 0x109a0, 0x109b7,
- 0x109bc, 0x109cf,
- 0x109d2, 0x109ff,
-}; /* CR_Meroitic_Cursive */
-
-/* 'Meroitic_Hieroglyphs': Script */
-static const OnigCodePoint CR_Meroitic_Hieroglyphs[] = {
- 1,
- 0x10980, 0x1099f,
-}; /* CR_Meroitic_Hieroglyphs */
-
-/* 'Miao': Script */
-static const OnigCodePoint CR_Miao[] = {
- 3,
- 0x16f00, 0x16f4a,
- 0x16f4f, 0x16f87,
- 0x16f8f, 0x16f9f,
-}; /* CR_Miao */
-
-/* 'Sharada': Script */
-static const OnigCodePoint CR_Sharada[] = {
- 1,
- 0x11180, 0x111df,
-}; /* CR_Sharada */
-
-/* 'Sora_Sompeng': Script */
-static const OnigCodePoint CR_Sora_Sompeng[] = {
- 2,
- 0x110d0, 0x110e8,
- 0x110f0, 0x110f9,
-}; /* CR_Sora_Sompeng */
-
-/* 'Takri': Script */
-static const OnigCodePoint CR_Takri[] = {
- 2,
- 0x11680, 0x116b9,
- 0x116c0, 0x116c9,
-}; /* CR_Takri */
-
-/* 'Caucasian_Albanian': Script */
-static const OnigCodePoint CR_Caucasian_Albanian[] = {
- 2,
- 0x10530, 0x10563,
- 0x1056f, 0x1056f,
-}; /* CR_Caucasian_Albanian */
-
-/* 'Bassa_Vah': Script */
-static const OnigCodePoint CR_Bassa_Vah[] = {
- 2,
- 0x16ad0, 0x16aed,
- 0x16af0, 0x16af5,
-}; /* CR_Bassa_Vah */
-
-/* 'Duployan': Script */
-static const OnigCodePoint CR_Duployan[] = {
- 5,
- 0x1bc00, 0x1bc6a,
- 0x1bc70, 0x1bc7c,
- 0x1bc80, 0x1bc88,
- 0x1bc90, 0x1bc99,
- 0x1bc9c, 0x1bc9f,
-}; /* CR_Duployan */
-
-/* 'Elbasan': Script */
-static const OnigCodePoint CR_Elbasan[] = {
- 1,
- 0x10500, 0x10527,
-}; /* CR_Elbasan */
-
-/* 'Grantha': Script */
-static const OnigCodePoint CR_Grantha[] = {
- 15,
- 0x11300, 0x11303,
- 0x11305, 0x1130c,
- 0x1130f, 0x11310,
- 0x11313, 0x11328,
- 0x1132a, 0x11330,
- 0x11332, 0x11333,
- 0x11335, 0x11339,
- 0x1133c, 0x11344,
- 0x11347, 0x11348,
- 0x1134b, 0x1134d,
- 0x11350, 0x11350,
- 0x11357, 0x11357,
- 0x1135d, 0x11363,
- 0x11366, 0x1136c,
- 0x11370, 0x11374,
-}; /* CR_Grantha */
-
-/* 'Pahawh_Hmong': Script */
-static const OnigCodePoint CR_Pahawh_Hmong[] = {
- 5,
- 0x16b00, 0x16b45,
- 0x16b50, 0x16b59,
- 0x16b5b, 0x16b61,
- 0x16b63, 0x16b77,
- 0x16b7d, 0x16b8f,
-}; /* CR_Pahawh_Hmong */
-
-/* 'Khojki': Script */
-static const OnigCodePoint CR_Khojki[] = {
- 2,
- 0x11200, 0x11211,
- 0x11213, 0x11241,
-}; /* CR_Khojki */
-
-/* 'Linear_A': Script */
-static const OnigCodePoint CR_Linear_A[] = {
- 3,
- 0x10600, 0x10736,
- 0x10740, 0x10755,
- 0x10760, 0x10767,
-}; /* CR_Linear_A */
-
-/* 'Mahajani': Script */
-static const OnigCodePoint CR_Mahajani[] = {
- 1,
- 0x11150, 0x11176,
-}; /* CR_Mahajani */
-
-/* 'Manichaean': Script */
-static const OnigCodePoint CR_Manichaean[] = {
- 2,
- 0x10ac0, 0x10ae6,
- 0x10aeb, 0x10af6,
-}; /* CR_Manichaean */
-
-/* 'Mende_Kikakui': Script */
-static const OnigCodePoint CR_Mende_Kikakui[] = {
- 2,
- 0x1e800, 0x1e8c4,
- 0x1e8c7, 0x1e8d6,
-}; /* CR_Mende_Kikakui */
-
-/* 'Modi': Script */
-static const OnigCodePoint CR_Modi[] = {
- 2,
- 0x11600, 0x11644,
- 0x11650, 0x11659,
-}; /* CR_Modi */
-
-/* 'Mro': Script */
-static const OnigCodePoint CR_Mro[] = {
- 3,
- 0x16a40, 0x16a5e,
- 0x16a60, 0x16a69,
- 0x16a6e, 0x16a6f,
-}; /* CR_Mro */
-
-/* 'Old_North_Arabian': Script */
-static const OnigCodePoint CR_Old_North_Arabian[] = {
- 1,
- 0x10a80, 0x10a9f,
-}; /* CR_Old_North_Arabian */
-
-/* 'Nabataean': Script */
-static const OnigCodePoint CR_Nabataean[] = {
- 2,
- 0x10880, 0x1089e,
- 0x108a7, 0x108af,
-}; /* CR_Nabataean */
-
-/* 'Palmyrene': Script */
-static const OnigCodePoint CR_Palmyrene[] = {
- 1,
- 0x10860, 0x1087f,
-}; /* CR_Palmyrene */
-
-/* 'Pau_Cin_Hau': Script */
-static const OnigCodePoint CR_Pau_Cin_Hau[] = {
- 1,
- 0x11ac0, 0x11af8,
-}; /* CR_Pau_Cin_Hau */
-
-/* 'Old_Permic': Script */
-static const OnigCodePoint CR_Old_Permic[] = {
- 1,
- 0x10350, 0x1037a,
-}; /* CR_Old_Permic */
-
-/* 'Psalter_Pahlavi': Script */
-static const OnigCodePoint CR_Psalter_Pahlavi[] = {
- 3,
- 0x10b80, 0x10b91,
- 0x10b99, 0x10b9c,
- 0x10ba9, 0x10baf,
-}; /* CR_Psalter_Pahlavi */
-
-/* 'Siddham': Script */
-static const OnigCodePoint CR_Siddham[] = {
- 2,
- 0x11580, 0x115b5,
- 0x115b8, 0x115dd,
-}; /* CR_Siddham */
-
-/* 'Khudawadi': Script */
-static const OnigCodePoint CR_Khudawadi[] = {
- 2,
- 0x112b0, 0x112ea,
- 0x112f0, 0x112f9,
-}; /* CR_Khudawadi */
-
-/* 'Tirhuta': Script */
-static const OnigCodePoint CR_Tirhuta[] = {
- 2,
- 0x11480, 0x114c7,
- 0x114d0, 0x114d9,
-}; /* CR_Tirhuta */
-
-/* 'Warang_Citi': Script */
-static const OnigCodePoint CR_Warang_Citi[] = {
- 2,
- 0x118a0, 0x118f2,
- 0x118ff, 0x118ff,
-}; /* CR_Warang_Citi */
-
-/* 'Ahom': Script */
-static const OnigCodePoint CR_Ahom[] = {
- 3,
- 0x11700, 0x1171a,
- 0x1171d, 0x1172b,
- 0x11730, 0x11746,
-}; /* CR_Ahom */
-
-/* 'Anatolian_Hieroglyphs': Script */
-static const OnigCodePoint CR_Anatolian_Hieroglyphs[] = {
- 1,
- 0x14400, 0x14646,
-}; /* CR_Anatolian_Hieroglyphs */
-
-/* 'Hatran': Script */
-static const OnigCodePoint CR_Hatran[] = {
- 3,
- 0x108e0, 0x108f2,
- 0x108f4, 0x108f5,
- 0x108fb, 0x108ff,
-}; /* CR_Hatran */
-
-/* 'Multani': Script */
-static const OnigCodePoint CR_Multani[] = {
- 5,
- 0x11280, 0x11286,
- 0x11288, 0x11288,
- 0x1128a, 0x1128d,
- 0x1128f, 0x1129d,
- 0x1129f, 0x112a9,
-}; /* CR_Multani */
-
-/* 'Old_Hungarian': Script */
-static const OnigCodePoint CR_Old_Hungarian[] = {
- 3,
- 0x10c80, 0x10cb2,
- 0x10cc0, 0x10cf2,
- 0x10cfa, 0x10cff,
-}; /* CR_Old_Hungarian */
-
-/* 'SignWriting': Script */
-static const OnigCodePoint CR_SignWriting[] = {
- 3,
- 0x1d800, 0x1da8b,
- 0x1da9b, 0x1da9f,
- 0x1daa1, 0x1daaf,
-}; /* CR_SignWriting */
-
-/* 'Adlam': Script */
-static const OnigCodePoint CR_Adlam[] = {
- 3,
- 0x1e900, 0x1e94b,
- 0x1e950, 0x1e959,
- 0x1e95e, 0x1e95f,
-}; /* CR_Adlam */
-
-/* 'Bhaiksuki': Script */
-static const OnigCodePoint CR_Bhaiksuki[] = {
- 4,
- 0x11c00, 0x11c08,
- 0x11c0a, 0x11c36,
- 0x11c38, 0x11c45,
- 0x11c50, 0x11c6c,
-}; /* CR_Bhaiksuki */
-
-/* 'Marchen': Script */
-static const OnigCodePoint CR_Marchen[] = {
- 3,
- 0x11c70, 0x11c8f,
- 0x11c92, 0x11ca7,
- 0x11ca9, 0x11cb6,
-}; /* CR_Marchen */
-
-/* 'Newa': Script */
-static const OnigCodePoint CR_Newa[] = {
- 2,
- 0x11400, 0x1145b,
- 0x1145d, 0x11461,
-}; /* CR_Newa */
-
-/* 'Osage': Script */
-static const OnigCodePoint CR_Osage[] = {
- 2,
- 0x104b0, 0x104d3,
- 0x104d8, 0x104fb,
-}; /* CR_Osage */
-
-/* 'Tangut': Script */
-static const OnigCodePoint CR_Tangut[] = {
- 4,
- 0x16fe0, 0x16fe0,
- 0x17000, 0x187f7,
- 0x18800, 0x18aff,
- 0x18d00, 0x18d08,
-}; /* CR_Tangut */
-
-/* 'Masaram_Gondi': Script */
-static const OnigCodePoint CR_Masaram_Gondi[] = {
- 7,
- 0x11d00, 0x11d06,
- 0x11d08, 0x11d09,
- 0x11d0b, 0x11d36,
- 0x11d3a, 0x11d3a,
- 0x11d3c, 0x11d3d,
- 0x11d3f, 0x11d47,
- 0x11d50, 0x11d59,
-}; /* CR_Masaram_Gondi */
-
-/* 'Nushu': Script */
-static const OnigCodePoint CR_Nushu[] = {
- 2,
- 0x16fe1, 0x16fe1,
- 0x1b170, 0x1b2fb,
-}; /* CR_Nushu */
-
-/* 'Soyombo': Script */
-static const OnigCodePoint CR_Soyombo[] = {
- 1,
- 0x11a50, 0x11aa2,
-}; /* CR_Soyombo */
-
-/* 'Zanabazar_Square': Script */
-static const OnigCodePoint CR_Zanabazar_Square[] = {
- 1,
- 0x11a00, 0x11a47,
-}; /* CR_Zanabazar_Square */
-
-/* 'Dogra': Script */
-static const OnigCodePoint CR_Dogra[] = {
- 1,
- 0x11800, 0x1183b,
-}; /* CR_Dogra */
-
-/* 'Gunjala_Gondi': Script */
-static const OnigCodePoint CR_Gunjala_Gondi[] = {
- 6,
- 0x11d60, 0x11d65,
- 0x11d67, 0x11d68,
- 0x11d6a, 0x11d8e,
- 0x11d90, 0x11d91,
- 0x11d93, 0x11d98,
- 0x11da0, 0x11da9,
-}; /* CR_Gunjala_Gondi */
-
-/* 'Makasar': Script */
-static const OnigCodePoint CR_Makasar[] = {
- 1,
- 0x11ee0, 0x11ef8,
-}; /* CR_Makasar */
-
-/* 'Medefaidrin': Script */
-static const OnigCodePoint CR_Medefaidrin[] = {
- 1,
- 0x16e40, 0x16e9a,
-}; /* CR_Medefaidrin */
-
-/* 'Hanifi_Rohingya': Script */
-static const OnigCodePoint CR_Hanifi_Rohingya[] = {
- 2,
- 0x10d00, 0x10d27,
- 0x10d30, 0x10d39,
-}; /* CR_Hanifi_Rohingya */
-
-/* 'Sogdian': Script */
-static const OnigCodePoint CR_Sogdian[] = {
- 1,
- 0x10f30, 0x10f59,
-}; /* CR_Sogdian */
-
-/* 'Old_Sogdian': Script */
-static const OnigCodePoint CR_Old_Sogdian[] = {
- 1,
- 0x10f00, 0x10f27,
-}; /* CR_Old_Sogdian */
-
-/* 'Elymaic': Script */
-static const OnigCodePoint CR_Elymaic[] = {
- 1,
- 0x10fe0, 0x10ff6,
-}; /* CR_Elymaic */
-
-/* 'Nandinagari': Script */
-static const OnigCodePoint CR_Nandinagari[] = {
- 3,
- 0x119a0, 0x119a7,
- 0x119aa, 0x119d7,
- 0x119da, 0x119e4,
-}; /* CR_Nandinagari */
-
-/* 'Nyiakeng_Puachue_Hmong': Script */
-static const OnigCodePoint CR_Nyiakeng_Puachue_Hmong[] = {
- 4,
- 0x1e100, 0x1e12c,
- 0x1e130, 0x1e13d,
- 0x1e140, 0x1e149,
- 0x1e14e, 0x1e14f,
-}; /* CR_Nyiakeng_Puachue_Hmong */
-
-/* 'Wancho': Script */
-static const OnigCodePoint CR_Wancho[] = {
- 2,
- 0x1e2c0, 0x1e2f9,
- 0x1e2ff, 0x1e2ff,
-}; /* CR_Wancho */
-
-/* 'Chorasmian': Script */
-static const OnigCodePoint CR_Chorasmian[] = {
- 1,
- 0x10fb0, 0x10fcb,
-}; /* CR_Chorasmian */
-
-/* 'Dives_Akuru': Script */
-static const OnigCodePoint CR_Dives_Akuru[] = {
- 8,
- 0x11900, 0x11906,
- 0x11909, 0x11909,
- 0x1190c, 0x11913,
- 0x11915, 0x11916,
- 0x11918, 0x11935,
- 0x11937, 0x11938,
- 0x1193b, 0x11946,
- 0x11950, 0x11959,
-}; /* CR_Dives_Akuru */
-
-/* 'Khitan_Small_Script': Script */
-static const OnigCodePoint CR_Khitan_Small_Script[] = {
- 3,
- 0x16fe4, 0x16fe4,
- 0x18b00, 0x18cd5,
- 0x18cff, 0x18cff,
-}; /* CR_Khitan_Small_Script */
-
-/* 'Yezidi': Script */
-static const OnigCodePoint CR_Yezidi[] = {
- 3,
- 0x10e80, 0x10ea9,
- 0x10eab, 0x10ead,
- 0x10eb0, 0x10eb1,
-}; /* CR_Yezidi */
-
-/* 'Cypro_Minoan': Script */
-static const OnigCodePoint CR_Cypro_Minoan[] = {
- 1,
- 0x12f90, 0x12ff2,
-}; /* CR_Cypro_Minoan */
-
-/* 'Old_Uyghur': Script */
-static const OnigCodePoint CR_Old_Uyghur[] = {
- 1,
- 0x10f70, 0x10f89,
-}; /* CR_Old_Uyghur */
-
-/* 'Tangsa': Script */
-static const OnigCodePoint CR_Tangsa[] = {
- 2,
- 0x16a70, 0x16abe,
- 0x16ac0, 0x16ac9,
-}; /* CR_Tangsa */
-
-/* 'Toto': Script */
-static const OnigCodePoint CR_Toto[] = {
- 1,
- 0x1e290, 0x1e2ae,
-}; /* CR_Toto */
-
-/* 'Vithkuqi': Script */
-static const OnigCodePoint CR_Vithkuqi[] = {
- 8,
- 0x10570, 0x1057a,
- 0x1057c, 0x1058a,
- 0x1058c, 0x10592,
- 0x10594, 0x10595,
- 0x10597, 0x105a1,
- 0x105a3, 0x105b1,
- 0x105b3, 0x105b9,
- 0x105bb, 0x105bc,
-}; /* CR_Vithkuqi */
-
-/* 'Kawi': Script */
-static const OnigCodePoint CR_Kawi[] = {
- 3,
- 0x11f00, 0x11f10,
- 0x11f12, 0x11f3a,
- 0x11f3e, 0x11f5a,
-}; /* CR_Kawi */
-
-/* 'Nag_Mundari': Script */
-static const OnigCodePoint CR_Nag_Mundari[] = {
- 1,
- 0x1e4d0, 0x1e4f9,
-}; /* CR_Nag_Mundari */
-
-/* 'Garay': Script */
-static const OnigCodePoint CR_Garay[] = {
- 3,
- 0x10d40, 0x10d65,
- 0x10d69, 0x10d85,
- 0x10d8e, 0x10d8f,
-}; /* CR_Garay */
-
-/* 'Gurung_Khema': Script */
-static const OnigCodePoint CR_Gurung_Khema[] = {
- 1,
- 0x16100, 0x16139,
-}; /* CR_Gurung_Khema */
-
-/* 'Kirat_Rai': Script */
-static const OnigCodePoint CR_Kirat_Rai[] = {
- 1,
- 0x16d40, 0x16d79,
-}; /* CR_Kirat_Rai */
-
-/* 'Ol_Onal': Script */
-static const OnigCodePoint CR_Ol_Onal[] = {
- 2,
- 0x1e5d0, 0x1e5fa,
- 0x1e5ff, 0x1e5ff,
-}; /* CR_Ol_Onal */
-
-/* 'Sunuwar': Script */
-static const OnigCodePoint CR_Sunuwar[] = {
- 2,
- 0x11bc0, 0x11be1,
- 0x11bf0, 0x11bf9,
-}; /* CR_Sunuwar */
-
-/* 'Todhri': Script */
-static const OnigCodePoint CR_Todhri[] = {
- 1,
- 0x105c0, 0x105f3,
-}; /* CR_Todhri */
-
-/* 'Tulu_Tigalari': Script */
-static const OnigCodePoint CR_Tulu_Tigalari[] = {
- 11,
- 0x11380, 0x11389,
- 0x1138b, 0x1138b,
- 0x1138e, 0x1138e,
- 0x11390, 0x113b5,
- 0x113b7, 0x113c0,
- 0x113c2, 0x113c2,
- 0x113c5, 0x113c5,
- 0x113c7, 0x113ca,
- 0x113cc, 0x113d5,
- 0x113d7, 0x113d8,
- 0x113e1, 0x113e2,
-}; /* CR_Tulu_Tigalari */
-
-/* 'White_Space': Binary Property */
-#define CR_White_Space CR_Space
-
-/* 'Bidi_Control': Binary Property */
-static const OnigCodePoint CR_Bidi_Control[] = {
- 4,
- 0x061c, 0x061c,
- 0x200e, 0x200f,
- 0x202a, 0x202e,
- 0x2066, 0x2069,
-}; /* CR_Bidi_Control */
-
-/* 'Join_Control': Binary Property */
-static const OnigCodePoint CR_Join_Control[] = {
- 1,
- 0x200c, 0x200d,
-}; /* CR_Join_Control */
-
-/* 'Dash': Binary Property */
-static const OnigCodePoint CR_Dash[] = {
- 24,
- 0x002d, 0x002d,
- 0x058a, 0x058a,
- 0x05be, 0x05be,
- 0x1400, 0x1400,
- 0x1806, 0x1806,
- 0x2010, 0x2015,
- 0x2053, 0x2053,
- 0x207b, 0x207b,
- 0x208b, 0x208b,
- 0x2212, 0x2212,
- 0x2e17, 0x2e17,
- 0x2e1a, 0x2e1a,
- 0x2e3a, 0x2e3b,
- 0x2e40, 0x2e40,
- 0x2e5d, 0x2e5d,
- 0x301c, 0x301c,
- 0x3030, 0x3030,
- 0x30a0, 0x30a0,
- 0xfe31, 0xfe32,
- 0xfe58, 0xfe58,
- 0xfe63, 0xfe63,
- 0xff0d, 0xff0d,
- 0x10d6e, 0x10d6e,
- 0x10ead, 0x10ead,
-}; /* CR_Dash */
-
-/* 'Hyphen': Binary Property */
-static const OnigCodePoint CR_Hyphen[] = {
- 10,
- 0x002d, 0x002d,
- 0x00ad, 0x00ad,
- 0x058a, 0x058a,
- 0x1806, 0x1806,
- 0x2010, 0x2011,
- 0x2e17, 0x2e17,
- 0x30fb, 0x30fb,
- 0xfe63, 0xfe63,
- 0xff0d, 0xff0d,
- 0xff65, 0xff65,
-}; /* CR_Hyphen */
-
-/* 'Quotation_Mark': Binary Property */
-static const OnigCodePoint CR_Quotation_Mark[] = {
- 13,
- 0x0022, 0x0022,
- 0x0027, 0x0027,
- 0x00ab, 0x00ab,
- 0x00bb, 0x00bb,
- 0x2018, 0x201f,
- 0x2039, 0x203a,
- 0x2e42, 0x2e42,
- 0x300c, 0x300f,
- 0x301d, 0x301f,
- 0xfe41, 0xfe44,
- 0xff02, 0xff02,
- 0xff07, 0xff07,
- 0xff62, 0xff63,
-}; /* CR_Quotation_Mark */
-
-/* 'Terminal_Punctuation': Binary Property */
-static const OnigCodePoint CR_Terminal_Punctuation[] = {
- 116,
- 0x0021, 0x0021,
- 0x002c, 0x002c,
- 0x002e, 0x002e,
- 0x003a, 0x003b,
- 0x003f, 0x003f,
- 0x037e, 0x037e,
- 0x0387, 0x0387,
- 0x0589, 0x0589,
- 0x05c3, 0x05c3,
- 0x060c, 0x060c,
- 0x061b, 0x061b,
- 0x061d, 0x061f,
- 0x06d4, 0x06d4,
- 0x0700, 0x070a,
- 0x070c, 0x070c,
- 0x07f8, 0x07f9,
- 0x0830, 0x0835,
- 0x0837, 0x083e,
- 0x085e, 0x085e,
- 0x0964, 0x0965,
- 0x0e5a, 0x0e5b,
- 0x0f08, 0x0f08,
- 0x0f0d, 0x0f12,
- 0x104a, 0x104b,
- 0x1361, 0x1368,
- 0x166e, 0x166e,
- 0x16eb, 0x16ed,
- 0x1735, 0x1736,
- 0x17d4, 0x17d6,
- 0x17da, 0x17da,
- 0x1802, 0x1805,
- 0x1808, 0x1809,
- 0x1944, 0x1945,
- 0x1aa8, 0x1aab,
- 0x1b4e, 0x1b4f,
- 0x1b5a, 0x1b5b,
- 0x1b5d, 0x1b5f,
- 0x1b7d, 0x1b7f,
- 0x1c3b, 0x1c3f,
- 0x1c7e, 0x1c7f,
- 0x2024, 0x2024,
- 0x203c, 0x203d,
- 0x2047, 0x2049,
- 0x2cf9, 0x2cfb,
- 0x2e2e, 0x2e2e,
- 0x2e3c, 0x2e3c,
- 0x2e41, 0x2e41,
- 0x2e4c, 0x2e4c,
- 0x2e4e, 0x2e4f,
- 0x2e53, 0x2e54,
- 0x3001, 0x3002,
- 0xa4fe, 0xa4ff,
- 0xa60d, 0xa60f,
- 0xa6f3, 0xa6f7,
- 0xa876, 0xa877,
- 0xa8ce, 0xa8cf,
- 0xa92f, 0xa92f,
- 0xa9c7, 0xa9c9,
- 0xaa5d, 0xaa5f,
- 0xaadf, 0xaadf,
- 0xaaf0, 0xaaf1,
- 0xabeb, 0xabeb,
- 0xfe12, 0xfe12,
- 0xfe15, 0xfe16,
- 0xfe50, 0xfe52,
- 0xfe54, 0xfe57,
- 0xff01, 0xff01,
- 0xff0c, 0xff0c,
- 0xff0e, 0xff0e,
- 0xff1a, 0xff1b,
- 0xff1f, 0xff1f,
- 0xff61, 0xff61,
- 0xff64, 0xff64,
- 0x1039f, 0x1039f,
- 0x103d0, 0x103d0,
- 0x10857, 0x10857,
- 0x1091f, 0x1091f,
- 0x10a56, 0x10a57,
- 0x10af0, 0x10af5,
- 0x10b3a, 0x10b3f,
- 0x10b99, 0x10b9c,
- 0x10f55, 0x10f59,
- 0x10f86, 0x10f89,
- 0x11047, 0x1104d,
- 0x110be, 0x110c1,
- 0x11141, 0x11143,
- 0x111c5, 0x111c6,
- 0x111cd, 0x111cd,
- 0x111de, 0x111df,
- 0x11238, 0x1123c,
- 0x112a9, 0x112a9,
- 0x113d4, 0x113d5,
- 0x1144b, 0x1144d,
- 0x1145a, 0x1145b,
- 0x115c2, 0x115c5,
- 0x115c9, 0x115d7,
- 0x11641, 0x11642,
- 0x1173c, 0x1173e,
- 0x11944, 0x11944,
- 0x11946, 0x11946,
- 0x11a42, 0x11a43,
- 0x11a9b, 0x11a9c,
- 0x11aa1, 0x11aa2,
- 0x11c41, 0x11c43,
- 0x11c71, 0x11c71,
- 0x11ef7, 0x11ef8,
- 0x11f43, 0x11f44,
- 0x12470, 0x12474,
- 0x16a6e, 0x16a6f,
- 0x16af5, 0x16af5,
- 0x16b37, 0x16b39,
- 0x16b44, 0x16b44,
- 0x16d6e, 0x16d6f,
- 0x16e97, 0x16e98,
- 0x1bc9f, 0x1bc9f,
- 0x1da87, 0x1da8a,
-}; /* CR_Terminal_Punctuation */
-
-/* 'Other_Math': Binary Property */
-static const OnigCodePoint CR_Other_Math[] = {
- 134,
- 0x005e, 0x005e,
- 0x03d0, 0x03d2,
- 0x03d5, 0x03d5,
- 0x03f0, 0x03f1,
- 0x03f4, 0x03f5,
- 0x2016, 0x2016,
- 0x2032, 0x2034,
- 0x2040, 0x2040,
- 0x2061, 0x2064,
- 0x207d, 0x207e,
- 0x208d, 0x208e,
- 0x20d0, 0x20dc,
- 0x20e1, 0x20e1,
- 0x20e5, 0x20e6,
- 0x20eb, 0x20ef,
- 0x2102, 0x2102,
- 0x2107, 0x2107,
- 0x210a, 0x2113,
- 0x2115, 0x2115,
- 0x2119, 0x211d,
- 0x2124, 0x2124,
- 0x2128, 0x2129,
- 0x212c, 0x212d,
- 0x212f, 0x2131,
- 0x2133, 0x2138,
- 0x213c, 0x213f,
- 0x2145, 0x2149,
- 0x2195, 0x2199,
- 0x219c, 0x219f,
- 0x21a1, 0x21a2,
- 0x21a4, 0x21a5,
- 0x21a7, 0x21a7,
- 0x21a9, 0x21ad,
- 0x21b0, 0x21b1,
- 0x21b6, 0x21b7,
- 0x21bc, 0x21cd,
- 0x21d0, 0x21d1,
- 0x21d3, 0x21d3,
- 0x21d5, 0x21db,
- 0x21dd, 0x21dd,
- 0x21e4, 0x21e5,
- 0x2308, 0x230b,
- 0x23b4, 0x23b5,
- 0x23b7, 0x23b7,
- 0x23d0, 0x23d0,
- 0x23e2, 0x23e2,
- 0x25a0, 0x25a1,
- 0x25ae, 0x25b6,
- 0x25bc, 0x25c0,
- 0x25c6, 0x25c7,
- 0x25ca, 0x25cb,
- 0x25cf, 0x25d3,
- 0x25e2, 0x25e2,
- 0x25e4, 0x25e4,
- 0x25e7, 0x25ec,
- 0x2605, 0x2606,
- 0x2640, 0x2640,
- 0x2642, 0x2642,
- 0x2660, 0x2663,
- 0x266d, 0x266e,
- 0x27c5, 0x27c6,
- 0x27e6, 0x27ef,
- 0x2983, 0x2998,
- 0x29d8, 0x29db,
- 0x29fc, 0x29fd,
- 0xfe61, 0xfe61,
- 0xfe63, 0xfe63,
- 0xfe68, 0xfe68,
- 0xff3c, 0xff3c,
- 0xff3e, 0xff3e,
- 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,
- 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,
-}; /* CR_Other_Math */
-
-/* 'Hex_Digit': Binary Property */
-static const OnigCodePoint CR_Hex_Digit[] = {
- 6,
- 0x0030, 0x0039,
- 0x0041, 0x0046,
- 0x0061, 0x0066,
- 0xff10, 0xff19,
- 0xff21, 0xff26,
- 0xff41, 0xff46,
-}; /* CR_Hex_Digit */
-
-/* 'ASCII_Hex_Digit': Binary Property */
-#define CR_ASCII_Hex_Digit CR_XDigit
-
-/* 'Other_Alphabetic': Binary Property */
-static const OnigCodePoint CR_Other_Alphabetic[] = {
- 250,
- 0x0345, 0x0345,
- 0x0363, 0x036f,
- 0x05b0, 0x05bd,
- 0x05bf, 0x05bf,
- 0x05c1, 0x05c2,
- 0x05c4, 0x05c5,
- 0x05c7, 0x05c7,
- 0x0610, 0x061a,
- 0x064b, 0x0657,
- 0x0659, 0x065f,
- 0x0670, 0x0670,
- 0x06d6, 0x06dc,
- 0x06e1, 0x06e4,
- 0x06e7, 0x06e8,
- 0x06ed, 0x06ed,
- 0x0711, 0x0711,
- 0x0730, 0x073f,
- 0x07a6, 0x07b0,
- 0x0816, 0x0817,
- 0x081b, 0x0823,
- 0x0825, 0x0827,
- 0x0829, 0x082c,
- 0x0897, 0x0897,
- 0x08d4, 0x08df,
- 0x08e3, 0x08e9,
- 0x08f0, 0x0903,
- 0x093a, 0x093b,
- 0x093e, 0x094c,
- 0x094e, 0x094f,
- 0x0955, 0x0957,
- 0x0962, 0x0963,
- 0x0981, 0x0983,
- 0x09be, 0x09c4,
- 0x09c7, 0x09c8,
- 0x09cb, 0x09cc,
- 0x09d7, 0x09d7,
- 0x09e2, 0x09e3,
- 0x0a01, 0x0a03,
- 0x0a3e, 0x0a42,
- 0x0a47, 0x0a48,
- 0x0a4b, 0x0a4c,
- 0x0a51, 0x0a51,
- 0x0a70, 0x0a71,
- 0x0a75, 0x0a75,
- 0x0a81, 0x0a83,
- 0x0abe, 0x0ac5,
- 0x0ac7, 0x0ac9,
- 0x0acb, 0x0acc,
- 0x0ae2, 0x0ae3,
- 0x0afa, 0x0afc,
- 0x0b01, 0x0b03,
- 0x0b3e, 0x0b44,
- 0x0b47, 0x0b48,
- 0x0b4b, 0x0b4c,
- 0x0b56, 0x0b57,
- 0x0b62, 0x0b63,
- 0x0b82, 0x0b82,
- 0x0bbe, 0x0bc2,
- 0x0bc6, 0x0bc8,
- 0x0bca, 0x0bcc,
- 0x0bd7, 0x0bd7,
- 0x0c00, 0x0c04,
- 0x0c3e, 0x0c44,
- 0x0c46, 0x0c48,
- 0x0c4a, 0x0c4c,
- 0x0c55, 0x0c56,
- 0x0c62, 0x0c63,
- 0x0c81, 0x0c83,
- 0x0cbe, 0x0cc4,
- 0x0cc6, 0x0cc8,
- 0x0cca, 0x0ccc,
- 0x0cd5, 0x0cd6,
- 0x0ce2, 0x0ce3,
- 0x0cf3, 0x0cf3,
- 0x0d00, 0x0d03,
- 0x0d3e, 0x0d44,
- 0x0d46, 0x0d48,
- 0x0d4a, 0x0d4c,
- 0x0d57, 0x0d57,
- 0x0d62, 0x0d63,
- 0x0d81, 0x0d83,
- 0x0dcf, 0x0dd4,
- 0x0dd6, 0x0dd6,
- 0x0dd8, 0x0ddf,
- 0x0df2, 0x0df3,
- 0x0e31, 0x0e31,
- 0x0e34, 0x0e3a,
- 0x0e4d, 0x0e4d,
- 0x0eb1, 0x0eb1,
- 0x0eb4, 0x0eb9,
- 0x0ebb, 0x0ebc,
- 0x0ecd, 0x0ecd,
- 0x0f71, 0x0f83,
- 0x0f8d, 0x0f97,
- 0x0f99, 0x0fbc,
- 0x102b, 0x1036,
- 0x1038, 0x1038,
- 0x103b, 0x103e,
- 0x1056, 0x1059,
- 0x105e, 0x1060,
- 0x1062, 0x1064,
- 0x1067, 0x106d,
- 0x1071, 0x1074,
- 0x1082, 0x108d,
- 0x108f, 0x108f,
- 0x109a, 0x109d,
- 0x1712, 0x1713,
- 0x1732, 0x1733,
- 0x1752, 0x1753,
- 0x1772, 0x1773,
- 0x17b6, 0x17c8,
- 0x1885, 0x1886,
- 0x18a9, 0x18a9,
- 0x1920, 0x192b,
- 0x1930, 0x1938,
- 0x1a17, 0x1a1b,
- 0x1a55, 0x1a5e,
- 0x1a61, 0x1a74,
- 0x1abf, 0x1ac0,
- 0x1acc, 0x1ace,
- 0x1b00, 0x1b04,
- 0x1b35, 0x1b43,
- 0x1b80, 0x1b82,
- 0x1ba1, 0x1ba9,
- 0x1bac, 0x1bad,
- 0x1be7, 0x1bf1,
- 0x1c24, 0x1c36,
- 0x1dd3, 0x1df4,
- 0x24b6, 0x24e9,
- 0x2de0, 0x2dff,
- 0xa674, 0xa67b,
- 0xa69e, 0xa69f,
- 0xa802, 0xa802,
- 0xa80b, 0xa80b,
- 0xa823, 0xa827,
- 0xa880, 0xa881,
- 0xa8b4, 0xa8c3,
- 0xa8c5, 0xa8c5,
- 0xa8ff, 0xa8ff,
- 0xa926, 0xa92a,
- 0xa947, 0xa952,
- 0xa980, 0xa983,
- 0xa9b4, 0xa9bf,
- 0xa9e5, 0xa9e5,
- 0xaa29, 0xaa36,
- 0xaa43, 0xaa43,
- 0xaa4c, 0xaa4d,
- 0xaa7b, 0xaa7d,
- 0xaab0, 0xaab0,
- 0xaab2, 0xaab4,
- 0xaab7, 0xaab8,
- 0xaabe, 0xaabe,
- 0xaaeb, 0xaaef,
- 0xaaf5, 0xaaf5,
- 0xabe3, 0xabea,
- 0xfb1e, 0xfb1e,
- 0x10376, 0x1037a,
- 0x10a01, 0x10a03,
- 0x10a05, 0x10a06,
- 0x10a0c, 0x10a0f,
- 0x10d24, 0x10d27,
- 0x10d69, 0x10d69,
- 0x10eab, 0x10eac,
- 0x10efc, 0x10efc,
- 0x11000, 0x11002,
- 0x11038, 0x11045,
- 0x11073, 0x11074,
- 0x11080, 0x11082,
- 0x110b0, 0x110b8,
- 0x110c2, 0x110c2,
- 0x11100, 0x11102,
- 0x11127, 0x11132,
- 0x11145, 0x11146,
- 0x11180, 0x11182,
- 0x111b3, 0x111bf,
- 0x111ce, 0x111cf,
- 0x1122c, 0x11234,
- 0x11237, 0x11237,
- 0x1123e, 0x1123e,
- 0x11241, 0x11241,
- 0x112df, 0x112e8,
- 0x11300, 0x11303,
- 0x1133e, 0x11344,
- 0x11347, 0x11348,
- 0x1134b, 0x1134c,
- 0x11357, 0x11357,
- 0x11362, 0x11363,
- 0x113b8, 0x113c0,
- 0x113c2, 0x113c2,
- 0x113c5, 0x113c5,
- 0x113c7, 0x113ca,
- 0x113cc, 0x113cd,
- 0x11435, 0x11441,
- 0x11443, 0x11445,
- 0x114b0, 0x114c1,
- 0x115af, 0x115b5,
- 0x115b8, 0x115be,
- 0x115dc, 0x115dd,
- 0x11630, 0x1163e,
- 0x11640, 0x11640,
- 0x116ab, 0x116b5,
- 0x1171d, 0x1172a,
- 0x1182c, 0x11838,
- 0x11930, 0x11935,
- 0x11937, 0x11938,
- 0x1193b, 0x1193c,
- 0x11940, 0x11940,
- 0x11942, 0x11942,
- 0x119d1, 0x119d7,
- 0x119da, 0x119df,
- 0x119e4, 0x119e4,
- 0x11a01, 0x11a0a,
- 0x11a35, 0x11a39,
- 0x11a3b, 0x11a3e,
- 0x11a51, 0x11a5b,
- 0x11a8a, 0x11a97,
- 0x11c2f, 0x11c36,
- 0x11c38, 0x11c3e,
- 0x11c92, 0x11ca7,
- 0x11ca9, 0x11cb6,
- 0x11d31, 0x11d36,
- 0x11d3a, 0x11d3a,
- 0x11d3c, 0x11d3d,
- 0x11d3f, 0x11d41,
- 0x11d43, 0x11d43,
- 0x11d47, 0x11d47,
- 0x11d8a, 0x11d8e,
- 0x11d90, 0x11d91,
- 0x11d93, 0x11d96,
- 0x11ef3, 0x11ef6,
- 0x11f00, 0x11f01,
- 0x11f03, 0x11f03,
- 0x11f34, 0x11f3a,
- 0x11f3e, 0x11f40,
- 0x1611e, 0x1612e,
- 0x16f4f, 0x16f4f,
- 0x16f51, 0x16f87,
- 0x16f8f, 0x16f92,
- 0x16ff0, 0x16ff1,
- 0x1bc9e, 0x1bc9e,
- 0x1e000, 0x1e006,
- 0x1e008, 0x1e018,
- 0x1e01b, 0x1e021,
- 0x1e023, 0x1e024,
- 0x1e026, 0x1e02a,
- 0x1e08f, 0x1e08f,
- 0x1e947, 0x1e947,
- 0x1f130, 0x1f149,
- 0x1f150, 0x1f169,
- 0x1f170, 0x1f189,
-}; /* CR_Other_Alphabetic */
-
-/* 'Ideographic': Binary Property */
-static const OnigCodePoint CR_Ideographic[] = {
- 21,
- 0x3006, 0x3007,
- 0x3021, 0x3029,
- 0x3038, 0x303a,
- 0x3400, 0x4dbf,
- 0x4e00, 0x9fff,
- 0xf900, 0xfa6d,
- 0xfa70, 0xfad9,
- 0x16fe4, 0x16fe4,
- 0x17000, 0x187f7,
- 0x18800, 0x18cd5,
- 0x18cff, 0x18d08,
- 0x1b170, 0x1b2fb,
- 0x20000, 0x2a6df,
- 0x2a700, 0x2b739,
- 0x2b740, 0x2b81d,
- 0x2b820, 0x2cea1,
- 0x2ceb0, 0x2ebe0,
- 0x2ebf0, 0x2ee5d,
- 0x2f800, 0x2fa1d,
- 0x30000, 0x3134a,
- 0x31350, 0x323af,
-}; /* CR_Ideographic */
-
-/* 'Diacritic': Binary Property */
-static const OnigCodePoint CR_Diacritic[] = {
- 214,
- 0x005e, 0x005e,
- 0x0060, 0x0060,
- 0x00a8, 0x00a8,
- 0x00af, 0x00af,
- 0x00b4, 0x00b4,
- 0x00b7, 0x00b8,
- 0x02b0, 0x034e,
- 0x0350, 0x0357,
- 0x035d, 0x0362,
- 0x0374, 0x0375,
- 0x037a, 0x037a,
- 0x0384, 0x0385,
- 0x0483, 0x0487,
- 0x0559, 0x0559,
- 0x0591, 0x05a1,
- 0x05a3, 0x05bd,
- 0x05bf, 0x05bf,
- 0x05c1, 0x05c2,
- 0x05c4, 0x05c4,
- 0x064b, 0x0652,
- 0x0657, 0x0658,
- 0x06df, 0x06e0,
- 0x06e5, 0x06e6,
- 0x06ea, 0x06ec,
- 0x0730, 0x074a,
- 0x07a6, 0x07b0,
- 0x07eb, 0x07f5,
- 0x0818, 0x0819,
- 0x0898, 0x089f,
- 0x08c9, 0x08d2,
- 0x08e3, 0x08fe,
- 0x093c, 0x093c,
- 0x094d, 0x094d,
- 0x0951, 0x0954,
- 0x0971, 0x0971,
- 0x09bc, 0x09bc,
- 0x09cd, 0x09cd,
- 0x0a3c, 0x0a3c,
- 0x0a4d, 0x0a4d,
- 0x0abc, 0x0abc,
- 0x0acd, 0x0acd,
- 0x0afd, 0x0aff,
- 0x0b3c, 0x0b3c,
- 0x0b4d, 0x0b4d,
- 0x0b55, 0x0b55,
- 0x0bcd, 0x0bcd,
- 0x0c3c, 0x0c3c,
- 0x0c4d, 0x0c4d,
- 0x0cbc, 0x0cbc,
- 0x0ccd, 0x0ccd,
- 0x0d3b, 0x0d3c,
- 0x0d4d, 0x0d4d,
- 0x0dca, 0x0dca,
- 0x0e3a, 0x0e3a,
- 0x0e47, 0x0e4c,
- 0x0e4e, 0x0e4e,
- 0x0eba, 0x0eba,
- 0x0ec8, 0x0ecc,
- 0x0f18, 0x0f19,
- 0x0f35, 0x0f35,
- 0x0f37, 0x0f37,
- 0x0f39, 0x0f39,
- 0x0f3e, 0x0f3f,
- 0x0f82, 0x0f84,
- 0x0f86, 0x0f87,
- 0x0fc6, 0x0fc6,
- 0x1037, 0x1037,
- 0x1039, 0x103a,
- 0x1063, 0x1064,
- 0x1069, 0x106d,
- 0x1087, 0x108d,
- 0x108f, 0x108f,
- 0x109a, 0x109b,
- 0x135d, 0x135f,
- 0x1714, 0x1715,
- 0x1734, 0x1734,
- 0x17c9, 0x17d3,
- 0x17dd, 0x17dd,
- 0x1939, 0x193b,
- 0x1a60, 0x1a60,
- 0x1a75, 0x1a7c,
- 0x1a7f, 0x1a7f,
- 0x1ab0, 0x1abe,
- 0x1ac1, 0x1acb,
- 0x1b34, 0x1b34,
- 0x1b44, 0x1b44,
- 0x1b6b, 0x1b73,
- 0x1baa, 0x1bab,
- 0x1be6, 0x1be6,
- 0x1bf2, 0x1bf3,
- 0x1c36, 0x1c37,
- 0x1c78, 0x1c7d,
- 0x1cd0, 0x1ce8,
- 0x1ced, 0x1ced,
- 0x1cf4, 0x1cf4,
- 0x1cf7, 0x1cf9,
- 0x1d2c, 0x1d6a,
- 0x1dc4, 0x1dcf,
- 0x1df5, 0x1dff,
- 0x1fbd, 0x1fbd,
- 0x1fbf, 0x1fc1,
- 0x1fcd, 0x1fcf,
- 0x1fdd, 0x1fdf,
- 0x1fed, 0x1fef,
- 0x1ffd, 0x1ffe,
- 0x2cef, 0x2cf1,
- 0x2e2f, 0x2e2f,
- 0x302a, 0x302f,
- 0x3099, 0x309c,
- 0x30fc, 0x30fc,
- 0xa66f, 0xa66f,
- 0xa67c, 0xa67d,
- 0xa67f, 0xa67f,
- 0xa69c, 0xa69d,
- 0xa6f0, 0xa6f1,
- 0xa700, 0xa721,
- 0xa788, 0xa78a,
- 0xa7f8, 0xa7f9,
- 0xa806, 0xa806,
- 0xa82c, 0xa82c,
- 0xa8c4, 0xa8c4,
- 0xa8e0, 0xa8f1,
- 0xa92b, 0xa92e,
- 0xa953, 0xa953,
- 0xa9b3, 0xa9b3,
- 0xa9c0, 0xa9c0,
- 0xa9e5, 0xa9e5,
- 0xaa7b, 0xaa7d,
- 0xaabf, 0xaac2,
- 0xaaf6, 0xaaf6,
- 0xab5b, 0xab5f,
- 0xab69, 0xab6b,
- 0xabec, 0xabed,
- 0xfb1e, 0xfb1e,
- 0xfe20, 0xfe2f,
- 0xff3e, 0xff3e,
- 0xff40, 0xff40,
- 0xff70, 0xff70,
- 0xff9e, 0xff9f,
- 0xffe3, 0xffe3,
- 0x102e0, 0x102e0,
- 0x10780, 0x10785,
- 0x10787, 0x107b0,
- 0x107b2, 0x107ba,
- 0x10a38, 0x10a3a,
- 0x10a3f, 0x10a3f,
- 0x10ae5, 0x10ae6,
- 0x10d22, 0x10d27,
- 0x10d4e, 0x10d4e,
- 0x10d69, 0x10d6d,
- 0x10efd, 0x10eff,
- 0x10f46, 0x10f50,
- 0x10f82, 0x10f85,
- 0x11046, 0x11046,
- 0x11070, 0x11070,
- 0x110b9, 0x110ba,
- 0x11133, 0x11134,
- 0x11173, 0x11173,
- 0x111c0, 0x111c0,
- 0x111ca, 0x111cc,
- 0x11235, 0x11236,
- 0x112e9, 0x112ea,
- 0x1133b, 0x1133c,
- 0x1134d, 0x1134d,
- 0x11366, 0x1136c,
- 0x11370, 0x11374,
- 0x113ce, 0x113d0,
- 0x113d2, 0x113d3,
- 0x113e1, 0x113e2,
- 0x11442, 0x11442,
- 0x11446, 0x11446,
- 0x114c2, 0x114c3,
- 0x115bf, 0x115c0,
- 0x1163f, 0x1163f,
- 0x116b6, 0x116b7,
- 0x1172b, 0x1172b,
- 0x11839, 0x1183a,
- 0x1193d, 0x1193e,
- 0x11943, 0x11943,
- 0x119e0, 0x119e0,
- 0x11a34, 0x11a34,
- 0x11a47, 0x11a47,
- 0x11a99, 0x11a99,
- 0x11c3f, 0x11c3f,
- 0x11d42, 0x11d42,
- 0x11d44, 0x11d45,
- 0x11d97, 0x11d97,
- 0x11f41, 0x11f42,
- 0x11f5a, 0x11f5a,
- 0x13447, 0x13455,
- 0x1612f, 0x1612f,
- 0x16af0, 0x16af4,
- 0x16b30, 0x16b36,
- 0x16d6b, 0x16d6c,
- 0x16f8f, 0x16f9f,
- 0x16ff0, 0x16ff1,
- 0x1aff0, 0x1aff3,
- 0x1aff5, 0x1affb,
- 0x1affd, 0x1affe,
- 0x1cf00, 0x1cf2d,
- 0x1cf30, 0x1cf46,
- 0x1d167, 0x1d169,
- 0x1d16d, 0x1d172,
- 0x1d17b, 0x1d182,
- 0x1d185, 0x1d18b,
- 0x1d1aa, 0x1d1ad,
- 0x1e030, 0x1e06d,
- 0x1e130, 0x1e136,
- 0x1e2ae, 0x1e2ae,
- 0x1e2ec, 0x1e2ef,
- 0x1e5ee, 0x1e5ef,
- 0x1e8d0, 0x1e8d6,
- 0x1e944, 0x1e946,
- 0x1e948, 0x1e94a,
-}; /* CR_Diacritic */
-
-/* 'Extender': Binary Property */
-static const OnigCodePoint CR_Extender[] = {
- 41,
- 0x00b7, 0x00b7,
- 0x02d0, 0x02d1,
- 0x0640, 0x0640,
- 0x07fa, 0x07fa,
- 0x0a71, 0x0a71,
- 0x0afb, 0x0afb,
- 0x0b55, 0x0b55,
- 0x0e46, 0x0e46,
- 0x0ec6, 0x0ec6,
- 0x180a, 0x180a,
- 0x1843, 0x1843,
- 0x1aa7, 0x1aa7,
- 0x1c36, 0x1c36,
- 0x1c7b, 0x1c7b,
- 0x3005, 0x3005,
- 0x3031, 0x3035,
- 0x309d, 0x309e,
- 0x30fc, 0x30fe,
- 0xa015, 0xa015,
- 0xa60c, 0xa60c,
- 0xa9cf, 0xa9cf,
- 0xa9e6, 0xa9e6,
- 0xaa70, 0xaa70,
- 0xaadd, 0xaadd,
- 0xaaf3, 0xaaf4,
- 0xff70, 0xff70,
- 0x10781, 0x10782,
- 0x10d4e, 0x10d4e,
- 0x10d6a, 0x10d6a,
- 0x10d6f, 0x10d6f,
- 0x11237, 0x11237,
- 0x1135d, 0x1135d,
- 0x113d2, 0x113d3,
- 0x115c6, 0x115c8,
- 0x11a98, 0x11a98,
- 0x16b42, 0x16b43,
- 0x16fe0, 0x16fe1,
- 0x16fe3, 0x16fe3,
- 0x1e13c, 0x1e13d,
- 0x1e5ef, 0x1e5ef,
- 0x1e944, 0x1e946,
-}; /* CR_Extender */
-
-/* 'Other_Lowercase': Binary Property */
-static const OnigCodePoint CR_Other_Lowercase[] = {
- 28,
- 0x00aa, 0x00aa,
- 0x00ba, 0x00ba,
- 0x02b0, 0x02b8,
- 0x02c0, 0x02c1,
- 0x02e0, 0x02e4,
- 0x0345, 0x0345,
- 0x037a, 0x037a,
- 0x10fc, 0x10fc,
- 0x1d2c, 0x1d6a,
- 0x1d78, 0x1d78,
- 0x1d9b, 0x1dbf,
- 0x2071, 0x2071,
- 0x207f, 0x207f,
- 0x2090, 0x209c,
- 0x2170, 0x217f,
- 0x24d0, 0x24e9,
- 0x2c7c, 0x2c7d,
- 0xa69c, 0xa69d,
- 0xa770, 0xa770,
- 0xa7f2, 0xa7f4,
- 0xa7f8, 0xa7f9,
- 0xab5c, 0xab5f,
- 0xab69, 0xab69,
- 0x10780, 0x10780,
- 0x10783, 0x10785,
- 0x10787, 0x107b0,
- 0x107b2, 0x107ba,
- 0x1e030, 0x1e06d,
-}; /* CR_Other_Lowercase */
-
-/* 'Other_Uppercase': Binary Property */
-static const OnigCodePoint CR_Other_Uppercase[] = {
- 5,
- 0x2160, 0x216f,
- 0x24b6, 0x24cf,
- 0x1f130, 0x1f149,
- 0x1f150, 0x1f169,
- 0x1f170, 0x1f189,
-}; /* CR_Other_Uppercase */
-
-/* 'Noncharacter_Code_Point': Binary Property */
-static const OnigCodePoint CR_Noncharacter_Code_Point[] = {
- 18,
- 0xfdd0, 0xfdef,
- 0xfffe, 0xffff,
- 0x1fffe, 0x1ffff,
- 0x2fffe, 0x2ffff,
- 0x3fffe, 0x3ffff,
- 0x4fffe, 0x4ffff,
- 0x5fffe, 0x5ffff,
- 0x6fffe, 0x6ffff,
- 0x7fffe, 0x7ffff,
- 0x8fffe, 0x8ffff,
- 0x9fffe, 0x9ffff,
- 0xafffe, 0xaffff,
- 0xbfffe, 0xbffff,
- 0xcfffe, 0xcffff,
- 0xdfffe, 0xdffff,
- 0xefffe, 0xeffff,
- 0xffffe, 0xfffff,
- 0x10fffe, 0x10ffff,
-}; /* CR_Noncharacter_Code_Point */
-
-/* 'Other_Grapheme_Extend': Binary Property */
-static const OnigCodePoint CR_Other_Grapheme_Extend[] = {
- 49,
- 0x09be, 0x09be,
- 0x09d7, 0x09d7,
- 0x0b3e, 0x0b3e,
- 0x0b57, 0x0b57,
- 0x0bbe, 0x0bbe,
- 0x0bd7, 0x0bd7,
- 0x0cc0, 0x0cc0,
- 0x0cc2, 0x0cc2,
- 0x0cc7, 0x0cc8,
- 0x0cca, 0x0ccb,
- 0x0cd5, 0x0cd6,
- 0x0d3e, 0x0d3e,
- 0x0d57, 0x0d57,
- 0x0dcf, 0x0dcf,
- 0x0ddf, 0x0ddf,
- 0x1715, 0x1715,
- 0x1734, 0x1734,
- 0x1b35, 0x1b35,
- 0x1b3b, 0x1b3b,
- 0x1b3d, 0x1b3d,
- 0x1b43, 0x1b44,
- 0x1baa, 0x1baa,
- 0x1bf2, 0x1bf3,
- 0x200c, 0x200c,
- 0x302e, 0x302f,
- 0xa953, 0xa953,
- 0xa9c0, 0xa9c0,
- 0xff9e, 0xff9f,
- 0x111c0, 0x111c0,
- 0x11235, 0x11235,
- 0x1133e, 0x1133e,
- 0x1134d, 0x1134d,
- 0x11357, 0x11357,
- 0x113b8, 0x113b8,
- 0x113c2, 0x113c2,
- 0x113c5, 0x113c5,
- 0x113c7, 0x113c9,
- 0x113cf, 0x113cf,
- 0x114b0, 0x114b0,
- 0x114bd, 0x114bd,
- 0x115af, 0x115af,
- 0x116b6, 0x116b6,
- 0x11930, 0x11930,
- 0x1193d, 0x1193d,
- 0x11f41, 0x11f41,
- 0x16ff0, 0x16ff1,
- 0x1d165, 0x1d166,
- 0x1d16d, 0x1d172,
- 0xe0020, 0xe007f,
-}; /* CR_Other_Grapheme_Extend */
-
-/* 'IDS_Binary_Operator': Binary Property */
-static const OnigCodePoint CR_IDS_Binary_Operator[] = {
- 3,
- 0x2ff0, 0x2ff1,
- 0x2ff4, 0x2ffd,
- 0x31ef, 0x31ef,
-}; /* CR_IDS_Binary_Operator */
-
-/* 'IDS_Trinary_Operator': Binary Property */
-static const OnigCodePoint CR_IDS_Trinary_Operator[] = {
- 1,
- 0x2ff2, 0x2ff3,
-}; /* CR_IDS_Trinary_Operator */
-
-/* 'IDS_Unary_Operator': Binary Property */
-static const OnigCodePoint CR_IDS_Unary_Operator[] = {
- 1,
- 0x2ffe, 0x2fff,
-}; /* CR_IDS_Unary_Operator */
-
-/* 'Radical': Binary Property */
-static const OnigCodePoint CR_Radical[] = {
- 3,
- 0x2e80, 0x2e99,
- 0x2e9b, 0x2ef3,
- 0x2f00, 0x2fd5,
-}; /* CR_Radical */
-
-/* 'Unified_Ideograph': Binary Property */
-static const OnigCodePoint CR_Unified_Ideograph[] = {
- 17,
- 0x3400, 0x4dbf,
- 0x4e00, 0x9fff,
- 0xfa0e, 0xfa0f,
- 0xfa11, 0xfa11,
- 0xfa13, 0xfa14,
- 0xfa1f, 0xfa1f,
- 0xfa21, 0xfa21,
- 0xfa23, 0xfa24,
- 0xfa27, 0xfa29,
- 0x20000, 0x2a6df,
- 0x2a700, 0x2b739,
- 0x2b740, 0x2b81d,
- 0x2b820, 0x2cea1,
- 0x2ceb0, 0x2ebe0,
- 0x2ebf0, 0x2ee5d,
- 0x30000, 0x3134a,
- 0x31350, 0x323af,
-}; /* CR_Unified_Ideograph */
-
-/* 'Other_Default_Ignorable_Code_Point': Binary Property */
-static const OnigCodePoint CR_Other_Default_Ignorable_Code_Point[] = {
- 11,
- 0x034f, 0x034f,
- 0x115f, 0x1160,
- 0x17b4, 0x17b5,
- 0x2065, 0x2065,
- 0x3164, 0x3164,
- 0xffa0, 0xffa0,
- 0xfff0, 0xfff8,
- 0xe0000, 0xe0000,
- 0xe0002, 0xe001f,
- 0xe0080, 0xe00ff,
- 0xe01f0, 0xe0fff,
-}; /* CR_Other_Default_Ignorable_Code_Point */
-
-/* 'Deprecated': Binary Property */
-static const OnigCodePoint CR_Deprecated[] = {
- 8,
- 0x0149, 0x0149,
- 0x0673, 0x0673,
- 0x0f77, 0x0f77,
- 0x0f79, 0x0f79,
- 0x17a3, 0x17a4,
- 0x206a, 0x206f,
- 0x2329, 0x232a,
- 0xe0001, 0xe0001,
-}; /* CR_Deprecated */
-
-/* 'Soft_Dotted': Binary Property */
-static const OnigCodePoint CR_Soft_Dotted[] = {
- 34,
- 0x0069, 0x006a,
- 0x012f, 0x012f,
- 0x0249, 0x0249,
- 0x0268, 0x0268,
- 0x029d, 0x029d,
- 0x02b2, 0x02b2,
- 0x03f3, 0x03f3,
- 0x0456, 0x0456,
- 0x0458, 0x0458,
- 0x1d62, 0x1d62,
- 0x1d96, 0x1d96,
- 0x1da4, 0x1da4,
- 0x1da8, 0x1da8,
- 0x1e2d, 0x1e2d,
- 0x1ecb, 0x1ecb,
- 0x2071, 0x2071,
- 0x2148, 0x2149,
- 0x2c7c, 0x2c7c,
- 0x1d422, 0x1d423,
- 0x1d456, 0x1d457,
- 0x1d48a, 0x1d48b,
- 0x1d4be, 0x1d4bf,
- 0x1d4f2, 0x1d4f3,
- 0x1d526, 0x1d527,
- 0x1d55a, 0x1d55b,
- 0x1d58e, 0x1d58f,
- 0x1d5c2, 0x1d5c3,
- 0x1d5f6, 0x1d5f7,
- 0x1d62a, 0x1d62b,
- 0x1d65e, 0x1d65f,
- 0x1d692, 0x1d693,
- 0x1df1a, 0x1df1a,
- 0x1e04c, 0x1e04d,
- 0x1e068, 0x1e068,
-}; /* CR_Soft_Dotted */
-
-/* 'Logical_Order_Exception': Binary Property */
-static const OnigCodePoint CR_Logical_Order_Exception[] = {
- 7,
- 0x0e40, 0x0e44,
- 0x0ec0, 0x0ec4,
- 0x19b5, 0x19b7,
- 0x19ba, 0x19ba,
- 0xaab5, 0xaab6,
- 0xaab9, 0xaab9,
- 0xaabb, 0xaabc,
-}; /* CR_Logical_Order_Exception */
-
-/* 'Other_ID_Start': Binary Property */
-static const OnigCodePoint CR_Other_ID_Start[] = {
- 4,
- 0x1885, 0x1886,
- 0x2118, 0x2118,
- 0x212e, 0x212e,
- 0x309b, 0x309c,
-}; /* CR_Other_ID_Start */
-
-/* 'Other_ID_Continue': Binary Property */
-static const OnigCodePoint CR_Other_ID_Continue[] = {
- 7,
- 0x00b7, 0x00b7,
- 0x0387, 0x0387,
- 0x1369, 0x1371,
- 0x19da, 0x19da,
- 0x200c, 0x200d,
- 0x30fb, 0x30fb,
- 0xff65, 0xff65,
-}; /* CR_Other_ID_Continue */
-
-/* 'ID_Compat_Math_Continue': Binary Property */
-static const OnigCodePoint CR_ID_Compat_Math_Continue[] = {
- 18,
- 0x00b2, 0x00b3,
- 0x00b9, 0x00b9,
- 0x2070, 0x2070,
- 0x2074, 0x207e,
- 0x2080, 0x208e,
- 0x2202, 0x2202,
- 0x2207, 0x2207,
- 0x221e, 0x221e,
- 0x1d6c1, 0x1d6c1,
- 0x1d6db, 0x1d6db,
- 0x1d6fb, 0x1d6fb,
- 0x1d715, 0x1d715,
- 0x1d735, 0x1d735,
- 0x1d74f, 0x1d74f,
- 0x1d76f, 0x1d76f,
- 0x1d789, 0x1d789,
- 0x1d7a9, 0x1d7a9,
- 0x1d7c3, 0x1d7c3,
-}; /* CR_ID_Compat_Math_Continue */
-
-/* 'ID_Compat_Math_Start': Binary Property */
-static const OnigCodePoint CR_ID_Compat_Math_Start[] = {
- 13,
- 0x2202, 0x2202,
- 0x2207, 0x2207,
- 0x221e, 0x221e,
- 0x1d6c1, 0x1d6c1,
- 0x1d6db, 0x1d6db,
- 0x1d6fb, 0x1d6fb,
- 0x1d715, 0x1d715,
- 0x1d735, 0x1d735,
- 0x1d74f, 0x1d74f,
- 0x1d76f, 0x1d76f,
- 0x1d789, 0x1d789,
- 0x1d7a9, 0x1d7a9,
- 0x1d7c3, 0x1d7c3,
-}; /* CR_ID_Compat_Math_Start */
-
-/* 'Sentence_Terminal': Binary Property */
-static const OnigCodePoint CR_Sentence_Terminal[] = {
- 88,
- 0x0021, 0x0021,
- 0x002e, 0x002e,
- 0x003f, 0x003f,
- 0x0589, 0x0589,
- 0x061d, 0x061f,
- 0x06d4, 0x06d4,
- 0x0700, 0x0702,
- 0x07f9, 0x07f9,
- 0x0837, 0x0837,
- 0x0839, 0x0839,
- 0x083d, 0x083e,
- 0x0964, 0x0965,
- 0x104a, 0x104b,
- 0x1362, 0x1362,
- 0x1367, 0x1368,
- 0x166e, 0x166e,
- 0x1735, 0x1736,
- 0x17d4, 0x17d5,
- 0x1803, 0x1803,
- 0x1809, 0x1809,
- 0x1944, 0x1945,
- 0x1aa8, 0x1aab,
- 0x1b4e, 0x1b4f,
- 0x1b5a, 0x1b5b,
- 0x1b5e, 0x1b5f,
- 0x1b7d, 0x1b7f,
- 0x1c3b, 0x1c3c,
- 0x1c7e, 0x1c7f,
- 0x2024, 0x2024,
- 0x203c, 0x203d,
- 0x2047, 0x2049,
- 0x2cf9, 0x2cfb,
- 0x2e2e, 0x2e2e,
- 0x2e3c, 0x2e3c,
- 0x2e53, 0x2e54,
- 0x3002, 0x3002,
- 0xa4ff, 0xa4ff,
- 0xa60e, 0xa60f,
- 0xa6f3, 0xa6f3,
- 0xa6f7, 0xa6f7,
- 0xa876, 0xa877,
- 0xa8ce, 0xa8cf,
- 0xa92f, 0xa92f,
- 0xa9c8, 0xa9c9,
- 0xaa5d, 0xaa5f,
- 0xaaf0, 0xaaf1,
- 0xabeb, 0xabeb,
- 0xfe12, 0xfe12,
- 0xfe15, 0xfe16,
- 0xfe52, 0xfe52,
- 0xfe56, 0xfe57,
- 0xff01, 0xff01,
- 0xff0e, 0xff0e,
- 0xff1f, 0xff1f,
- 0xff61, 0xff61,
- 0x10a56, 0x10a57,
- 0x10f55, 0x10f59,
- 0x10f86, 0x10f89,
- 0x11047, 0x11048,
- 0x110be, 0x110c1,
- 0x11141, 0x11143,
- 0x111c5, 0x111c6,
- 0x111cd, 0x111cd,
- 0x111de, 0x111df,
- 0x11238, 0x11239,
- 0x1123b, 0x1123c,
- 0x112a9, 0x112a9,
- 0x113d4, 0x113d5,
- 0x1144b, 0x1144c,
- 0x115c2, 0x115c3,
- 0x115c9, 0x115d7,
- 0x11641, 0x11642,
- 0x1173c, 0x1173e,
- 0x11944, 0x11944,
- 0x11946, 0x11946,
- 0x11a42, 0x11a43,
- 0x11a9b, 0x11a9c,
- 0x11c41, 0x11c42,
- 0x11ef7, 0x11ef8,
- 0x11f43, 0x11f44,
- 0x16a6e, 0x16a6f,
- 0x16af5, 0x16af5,
- 0x16b37, 0x16b38,
- 0x16b44, 0x16b44,
- 0x16d6e, 0x16d6f,
- 0x16e98, 0x16e98,
- 0x1bc9f, 0x1bc9f,
- 0x1da88, 0x1da88,
-}; /* CR_Sentence_Terminal */
-
-/* 'Variation_Selector': Binary Property */
-static const OnigCodePoint CR_Variation_Selector[] = {
- 4,
- 0x180b, 0x180d,
- 0x180f, 0x180f,
- 0xfe00, 0xfe0f,
- 0xe0100, 0xe01ef,
-}; /* CR_Variation_Selector */
-
-/* 'Pattern_White_Space': Binary Property */
-static const OnigCodePoint CR_Pattern_White_Space[] = {
- 5,
- 0x0009, 0x000d,
- 0x0020, 0x0020,
- 0x0085, 0x0085,
- 0x200e, 0x200f,
- 0x2028, 0x2029,
-}; /* CR_Pattern_White_Space */
-
-/* 'Pattern_Syntax': Binary Property */
-static const OnigCodePoint CR_Pattern_Syntax[] = {
- 28,
- 0x0021, 0x002f,
- 0x003a, 0x0040,
- 0x005b, 0x005e,
- 0x0060, 0x0060,
- 0x007b, 0x007e,
- 0x00a1, 0x00a7,
- 0x00a9, 0x00a9,
- 0x00ab, 0x00ac,
- 0x00ae, 0x00ae,
- 0x00b0, 0x00b1,
- 0x00b6, 0x00b6,
- 0x00bb, 0x00bb,
- 0x00bf, 0x00bf,
- 0x00d7, 0x00d7,
- 0x00f7, 0x00f7,
- 0x2010, 0x2027,
- 0x2030, 0x203e,
- 0x2041, 0x2053,
- 0x2055, 0x205e,
- 0x2190, 0x245f,
- 0x2500, 0x2775,
- 0x2794, 0x2bff,
- 0x2e00, 0x2e7f,
- 0x3001, 0x3003,
- 0x3008, 0x3020,
- 0x3030, 0x3030,
- 0xfd3e, 0xfd3f,
- 0xfe45, 0xfe46,
-}; /* CR_Pattern_Syntax */
-
-/* 'Prepended_Concatenation_Mark': Binary Property */
-static const OnigCodePoint CR_Prepended_Concatenation_Mark[] = {
- 7,
- 0x0600, 0x0605,
- 0x06dd, 0x06dd,
- 0x070f, 0x070f,
- 0x0890, 0x0891,
- 0x08e2, 0x08e2,
- 0x110bd, 0x110bd,
- 0x110cd, 0x110cd,
-}; /* CR_Prepended_Concatenation_Mark */
-
-/* 'Regional_Indicator': Binary Property */
-static const OnigCodePoint CR_Regional_Indicator[] = {
- 1,
- 0x1f1e6, 0x1f1ff,
-}; /* CR_Regional_Indicator */
-
-/* 'Modifier_Combining_Mark': Binary Property */
-static const OnigCodePoint CR_Modifier_Combining_Mark[] = {
- 9,
- 0x0654, 0x0655,
- 0x0658, 0x0658,
- 0x06dc, 0x06dc,
- 0x06e3, 0x06e3,
- 0x06e7, 0x06e8,
- 0x08ca, 0x08cb,
- 0x08cd, 0x08cf,
- 0x08d3, 0x08d3,
- 0x08f3, 0x08f3,
-}; /* CR_Modifier_Combining_Mark */
-
-/* 'Emoji': Emoji */
-static const OnigCodePoint CR_Emoji[] = {
- 150,
- 0x0023, 0x0023,
- 0x002a, 0x002a,
- 0x0030, 0x0039,
- 0x00a9, 0x00a9,
- 0x00ae, 0x00ae,
- 0x203c, 0x203c,
- 0x2049, 0x2049,
- 0x2122, 0x2122,
- 0x2139, 0x2139,
- 0x2194, 0x2199,
- 0x21a9, 0x21aa,
- 0x231a, 0x231b,
- 0x2328, 0x2328,
- 0x23cf, 0x23cf,
- 0x23e9, 0x23f3,
- 0x23f8, 0x23fa,
- 0x24c2, 0x24c2,
- 0x25aa, 0x25ab,
- 0x25b6, 0x25b6,
- 0x25c0, 0x25c0,
- 0x25fb, 0x25fe,
- 0x2600, 0x2604,
- 0x260e, 0x260e,
- 0x2611, 0x2611,
- 0x2614, 0x2615,
- 0x2618, 0x2618,
- 0x261d, 0x261d,
- 0x2620, 0x2620,
- 0x2622, 0x2623,
- 0x2626, 0x2626,
- 0x262a, 0x262a,
- 0x262e, 0x262f,
- 0x2638, 0x263a,
- 0x2640, 0x2640,
- 0x2642, 0x2642,
- 0x2648, 0x2653,
- 0x265f, 0x2660,
- 0x2663, 0x2663,
- 0x2665, 0x2666,
- 0x2668, 0x2668,
- 0x267b, 0x267b,
- 0x267e, 0x267f,
- 0x2692, 0x2697,
- 0x2699, 0x2699,
- 0x269b, 0x269c,
- 0x26a0, 0x26a1,
- 0x26a7, 0x26a7,
- 0x26aa, 0x26ab,
- 0x26b0, 0x26b1,
- 0x26bd, 0x26be,
- 0x26c4, 0x26c5,
- 0x26c8, 0x26c8,
- 0x26ce, 0x26cf,
- 0x26d1, 0x26d1,
- 0x26d3, 0x26d4,
- 0x26e9, 0x26ea,
- 0x26f0, 0x26f5,
- 0x26f7, 0x26fa,
- 0x26fd, 0x26fd,
- 0x2702, 0x2702,
- 0x2705, 0x2705,
- 0x2708, 0x270d,
- 0x270f, 0x270f,
- 0x2712, 0x2712,
- 0x2714, 0x2714,
- 0x2716, 0x2716,
- 0x271d, 0x271d,
- 0x2721, 0x2721,
- 0x2728, 0x2728,
- 0x2733, 0x2734,
- 0x2744, 0x2744,
- 0x2747, 0x2747,
- 0x274c, 0x274c,
- 0x274e, 0x274e,
- 0x2753, 0x2755,
- 0x2757, 0x2757,
- 0x2763, 0x2764,
- 0x2795, 0x2797,
- 0x27a1, 0x27a1,
- 0x27b0, 0x27b0,
- 0x27bf, 0x27bf,
- 0x2934, 0x2935,
- 0x2b05, 0x2b07,
- 0x2b1b, 0x2b1c,
- 0x2b50, 0x2b50,
- 0x2b55, 0x2b55,
- 0x3030, 0x3030,
- 0x303d, 0x303d,
- 0x3297, 0x3297,
- 0x3299, 0x3299,
- 0x1f004, 0x1f004,
- 0x1f0cf, 0x1f0cf,
- 0x1f170, 0x1f171,
- 0x1f17e, 0x1f17f,
- 0x1f18e, 0x1f18e,
- 0x1f191, 0x1f19a,
- 0x1f1e6, 0x1f1ff,
- 0x1f201, 0x1f202,
- 0x1f21a, 0x1f21a,
- 0x1f22f, 0x1f22f,
- 0x1f232, 0x1f23a,
- 0x1f250, 0x1f251,
- 0x1f300, 0x1f321,
- 0x1f324, 0x1f393,
- 0x1f396, 0x1f397,
- 0x1f399, 0x1f39b,
- 0x1f39e, 0x1f3f0,
- 0x1f3f3, 0x1f3f5,
- 0x1f3f7, 0x1f4fd,
- 0x1f4ff, 0x1f53d,
- 0x1f549, 0x1f54e,
- 0x1f550, 0x1f567,
- 0x1f56f, 0x1f570,
- 0x1f573, 0x1f57a,
- 0x1f587, 0x1f587,
- 0x1f58a, 0x1f58d,
- 0x1f590, 0x1f590,
- 0x1f595, 0x1f596,
- 0x1f5a4, 0x1f5a5,
- 0x1f5a8, 0x1f5a8,
- 0x1f5b1, 0x1f5b2,
- 0x1f5bc, 0x1f5bc,
- 0x1f5c2, 0x1f5c4,
- 0x1f5d1, 0x1f5d3,
- 0x1f5dc, 0x1f5de,
- 0x1f5e1, 0x1f5e1,
- 0x1f5e3, 0x1f5e3,
- 0x1f5e8, 0x1f5e8,
- 0x1f5ef, 0x1f5ef,
- 0x1f5f3, 0x1f5f3,
- 0x1f5fa, 0x1f64f,
- 0x1f680, 0x1f6c5,
- 0x1f6cb, 0x1f6d2,
- 0x1f6d5, 0x1f6d7,
- 0x1f6dc, 0x1f6e5,
- 0x1f6e9, 0x1f6e9,
- 0x1f6eb, 0x1f6ec,
- 0x1f6f0, 0x1f6f0,
- 0x1f6f3, 0x1f6fc,
- 0x1f7e0, 0x1f7eb,
- 0x1f7f0, 0x1f7f0,
- 0x1f90c, 0x1f93a,
- 0x1f93c, 0x1f945,
- 0x1f947, 0x1f9ff,
- 0x1fa70, 0x1fa7c,
- 0x1fa80, 0x1fa89,
- 0x1fa8f, 0x1fac6,
- 0x1face, 0x1fadc,
- 0x1fadf, 0x1fae9,
- 0x1faf0, 0x1faf8,
-}; /* CR_Emoji */
-
-/* 'Emoji_Presentation': Emoji */
-static const OnigCodePoint CR_Emoji_Presentation[] = {
- 80,
- 0x231a, 0x231b,
- 0x23e9, 0x23ec,
- 0x23f0, 0x23f0,
- 0x23f3, 0x23f3,
- 0x25fd, 0x25fe,
- 0x2614, 0x2615,
- 0x2648, 0x2653,
- 0x267f, 0x267f,
- 0x2693, 0x2693,
- 0x26a1, 0x26a1,
- 0x26aa, 0x26ab,
- 0x26bd, 0x26be,
- 0x26c4, 0x26c5,
- 0x26ce, 0x26ce,
- 0x26d4, 0x26d4,
- 0x26ea, 0x26ea,
- 0x26f2, 0x26f3,
- 0x26f5, 0x26f5,
- 0x26fa, 0x26fa,
- 0x26fd, 0x26fd,
- 0x2705, 0x2705,
- 0x270a, 0x270b,
- 0x2728, 0x2728,
- 0x274c, 0x274c,
- 0x274e, 0x274e,
- 0x2753, 0x2755,
- 0x2757, 0x2757,
- 0x2795, 0x2797,
- 0x27b0, 0x27b0,
- 0x27bf, 0x27bf,
- 0x2b1b, 0x2b1c,
- 0x2b50, 0x2b50,
- 0x2b55, 0x2b55,
- 0x1f004, 0x1f004,
- 0x1f0cf, 0x1f0cf,
- 0x1f18e, 0x1f18e,
- 0x1f191, 0x1f19a,
- 0x1f1e6, 0x1f1ff,
- 0x1f201, 0x1f201,
- 0x1f21a, 0x1f21a,
- 0x1f22f, 0x1f22f,
- 0x1f232, 0x1f236,
- 0x1f238, 0x1f23a,
- 0x1f250, 0x1f251,
- 0x1f300, 0x1f320,
- 0x1f32d, 0x1f335,
- 0x1f337, 0x1f37c,
- 0x1f37e, 0x1f393,
- 0x1f3a0, 0x1f3ca,
- 0x1f3cf, 0x1f3d3,
- 0x1f3e0, 0x1f3f0,
- 0x1f3f4, 0x1f3f4,
- 0x1f3f8, 0x1f43e,
- 0x1f440, 0x1f440,
- 0x1f442, 0x1f4fc,
- 0x1f4ff, 0x1f53d,
- 0x1f54b, 0x1f54e,
- 0x1f550, 0x1f567,
- 0x1f57a, 0x1f57a,
- 0x1f595, 0x1f596,
- 0x1f5a4, 0x1f5a4,
- 0x1f5fb, 0x1f64f,
- 0x1f680, 0x1f6c5,
- 0x1f6cc, 0x1f6cc,
- 0x1f6d0, 0x1f6d2,
- 0x1f6d5, 0x1f6d7,
- 0x1f6dc, 0x1f6df,
- 0x1f6eb, 0x1f6ec,
- 0x1f6f4, 0x1f6fc,
- 0x1f7e0, 0x1f7eb,
- 0x1f7f0, 0x1f7f0,
- 0x1f90c, 0x1f93a,
- 0x1f93c, 0x1f945,
- 0x1f947, 0x1f9ff,
- 0x1fa70, 0x1fa7c,
- 0x1fa80, 0x1fa89,
- 0x1fa8f, 0x1fac6,
- 0x1face, 0x1fadc,
- 0x1fadf, 0x1fae9,
- 0x1faf0, 0x1faf8,
-}; /* CR_Emoji_Presentation */
-
-/* 'Emoji_Modifier': Emoji */
-static const OnigCodePoint CR_Emoji_Modifier[] = {
- 1,
- 0x1f3fb, 0x1f3ff,
-}; /* CR_Emoji_Modifier */
-
-/* 'Emoji_Modifier_Base': Emoji */
-static const OnigCodePoint CR_Emoji_Modifier_Base[] = {
- 40,
- 0x261d, 0x261d,
- 0x26f9, 0x26f9,
- 0x270a, 0x270d,
- 0x1f385, 0x1f385,
- 0x1f3c2, 0x1f3c4,
- 0x1f3c7, 0x1f3c7,
- 0x1f3ca, 0x1f3cc,
- 0x1f442, 0x1f443,
- 0x1f446, 0x1f450,
- 0x1f466, 0x1f478,
- 0x1f47c, 0x1f47c,
- 0x1f481, 0x1f483,
- 0x1f485, 0x1f487,
- 0x1f48f, 0x1f48f,
- 0x1f491, 0x1f491,
- 0x1f4aa, 0x1f4aa,
- 0x1f574, 0x1f575,
- 0x1f57a, 0x1f57a,
- 0x1f590, 0x1f590,
- 0x1f595, 0x1f596,
- 0x1f645, 0x1f647,
- 0x1f64b, 0x1f64f,
- 0x1f6a3, 0x1f6a3,
- 0x1f6b4, 0x1f6b6,
- 0x1f6c0, 0x1f6c0,
- 0x1f6cc, 0x1f6cc,
- 0x1f90c, 0x1f90c,
- 0x1f90f, 0x1f90f,
- 0x1f918, 0x1f91f,
- 0x1f926, 0x1f926,
- 0x1f930, 0x1f939,
- 0x1f93c, 0x1f93e,
- 0x1f977, 0x1f977,
- 0x1f9b5, 0x1f9b6,
- 0x1f9b8, 0x1f9b9,
- 0x1f9bb, 0x1f9bb,
- 0x1f9cd, 0x1f9cf,
- 0x1f9d1, 0x1f9dd,
- 0x1fac3, 0x1fac5,
- 0x1faf0, 0x1faf8,
-}; /* CR_Emoji_Modifier_Base */
-
-/* 'Emoji_Component': Emoji */
-static const OnigCodePoint CR_Emoji_Component[] = {
- 10,
- 0x0023, 0x0023,
- 0x002a, 0x002a,
- 0x0030, 0x0039,
- 0x200d, 0x200d,
- 0x20e3, 0x20e3,
- 0xfe0f, 0xfe0f,
- 0x1f1e6, 0x1f1ff,
- 0x1f3fb, 0x1f3ff,
- 0x1f9b0, 0x1f9b3,
- 0xe0020, 0xe007f,
-}; /* CR_Emoji_Component */
-
-/* 'Extended_Pictographic': Emoji */
-static const OnigCodePoint CR_Extended_Pictographic[] = {
- 78,
- 0x00a9, 0x00a9,
- 0x00ae, 0x00ae,
- 0x203c, 0x203c,
- 0x2049, 0x2049,
- 0x2122, 0x2122,
- 0x2139, 0x2139,
- 0x2194, 0x2199,
- 0x21a9, 0x21aa,
- 0x231a, 0x231b,
- 0x2328, 0x2328,
- 0x2388, 0x2388,
- 0x23cf, 0x23cf,
- 0x23e9, 0x23f3,
- 0x23f8, 0x23fa,
- 0x24c2, 0x24c2,
- 0x25aa, 0x25ab,
- 0x25b6, 0x25b6,
- 0x25c0, 0x25c0,
- 0x25fb, 0x25fe,
- 0x2600, 0x2605,
- 0x2607, 0x2612,
- 0x2614, 0x2685,
- 0x2690, 0x2705,
- 0x2708, 0x2712,
- 0x2714, 0x2714,
- 0x2716, 0x2716,
- 0x271d, 0x271d,
- 0x2721, 0x2721,
- 0x2728, 0x2728,
- 0x2733, 0x2734,
- 0x2744, 0x2744,
- 0x2747, 0x2747,
- 0x274c, 0x274c,
- 0x274e, 0x274e,
- 0x2753, 0x2755,
- 0x2757, 0x2757,
- 0x2763, 0x2767,
- 0x2795, 0x2797,
- 0x27a1, 0x27a1,
- 0x27b0, 0x27b0,
- 0x27bf, 0x27bf,
- 0x2934, 0x2935,
- 0x2b05, 0x2b07,
- 0x2b1b, 0x2b1c,
- 0x2b50, 0x2b50,
- 0x2b55, 0x2b55,
- 0x3030, 0x3030,
- 0x303d, 0x303d,
- 0x3297, 0x3297,
- 0x3299, 0x3299,
- 0x1f000, 0x1f0ff,
- 0x1f10d, 0x1f10f,
- 0x1f12f, 0x1f12f,
- 0x1f16c, 0x1f171,
- 0x1f17e, 0x1f17f,
- 0x1f18e, 0x1f18e,
- 0x1f191, 0x1f19a,
- 0x1f1ad, 0x1f1e5,
- 0x1f201, 0x1f20f,
- 0x1f21a, 0x1f21a,
- 0x1f22f, 0x1f22f,
- 0x1f232, 0x1f23a,
- 0x1f23c, 0x1f23f,
- 0x1f249, 0x1f3fa,
- 0x1f400, 0x1f53d,
- 0x1f546, 0x1f64f,
- 0x1f680, 0x1f6ff,
- 0x1f774, 0x1f77f,
- 0x1f7d5, 0x1f7ff,
- 0x1f80c, 0x1f80f,
- 0x1f848, 0x1f84f,
- 0x1f85a, 0x1f85f,
- 0x1f888, 0x1f88f,
- 0x1f8ae, 0x1f8ff,
- 0x1f90c, 0x1f93a,
- 0x1f93c, 0x1f945,
- 0x1f947, 0x1faff,
- 0x1fc00, 0x1fffd,
-}; /* CR_Extended_Pictographic */
-
-/* 'Unknown': Script */
-static const OnigCodePoint CR_Unknown[] = {
- 729,
- 0x0378, 0x0379,
- 0x0380, 0x0383,
- 0x038b, 0x038b,
- 0x038d, 0x038d,
- 0x03a2, 0x03a2,
- 0x0530, 0x0530,
- 0x0557, 0x0558,
- 0x058b, 0x058c,
- 0x0590, 0x0590,
- 0x05c8, 0x05cf,
- 0x05eb, 0x05ee,
- 0x05f5, 0x05ff,
- 0x070e, 0x070e,
- 0x074b, 0x074c,
- 0x07b2, 0x07bf,
- 0x07fb, 0x07fc,
- 0x082e, 0x082f,
- 0x083f, 0x083f,
- 0x085c, 0x085d,
- 0x085f, 0x085f,
- 0x086b, 0x086f,
- 0x088f, 0x088f,
- 0x0892, 0x0896,
- 0x0984, 0x0984,
- 0x098d, 0x098e,
- 0x0991, 0x0992,
- 0x09a9, 0x09a9,
- 0x09b1, 0x09b1,
- 0x09b3, 0x09b5,
- 0x09ba, 0x09bb,
- 0x09c5, 0x09c6,
- 0x09c9, 0x09ca,
- 0x09cf, 0x09d6,
- 0x09d8, 0x09db,
- 0x09de, 0x09de,
- 0x09e4, 0x09e5,
- 0x09ff, 0x0a00,
- 0x0a04, 0x0a04,
- 0x0a0b, 0x0a0e,
- 0x0a11, 0x0a12,
- 0x0a29, 0x0a29,
- 0x0a31, 0x0a31,
- 0x0a34, 0x0a34,
- 0x0a37, 0x0a37,
- 0x0a3a, 0x0a3b,
- 0x0a3d, 0x0a3d,
- 0x0a43, 0x0a46,
- 0x0a49, 0x0a4a,
- 0x0a4e, 0x0a50,
- 0x0a52, 0x0a58,
- 0x0a5d, 0x0a5d,
- 0x0a5f, 0x0a65,
- 0x0a77, 0x0a80,
- 0x0a84, 0x0a84,
- 0x0a8e, 0x0a8e,
- 0x0a92, 0x0a92,
- 0x0aa9, 0x0aa9,
- 0x0ab1, 0x0ab1,
- 0x0ab4, 0x0ab4,
- 0x0aba, 0x0abb,
- 0x0ac6, 0x0ac6,
- 0x0aca, 0x0aca,
- 0x0ace, 0x0acf,
- 0x0ad1, 0x0adf,
- 0x0ae4, 0x0ae5,
- 0x0af2, 0x0af8,
- 0x0b00, 0x0b00,
- 0x0b04, 0x0b04,
- 0x0b0d, 0x0b0e,
- 0x0b11, 0x0b12,
- 0x0b29, 0x0b29,
- 0x0b31, 0x0b31,
- 0x0b34, 0x0b34,
- 0x0b3a, 0x0b3b,
- 0x0b45, 0x0b46,
- 0x0b49, 0x0b4a,
- 0x0b4e, 0x0b54,
- 0x0b58, 0x0b5b,
- 0x0b5e, 0x0b5e,
- 0x0b64, 0x0b65,
- 0x0b78, 0x0b81,
- 0x0b84, 0x0b84,
- 0x0b8b, 0x0b8d,
- 0x0b91, 0x0b91,
- 0x0b96, 0x0b98,
- 0x0b9b, 0x0b9b,
- 0x0b9d, 0x0b9d,
- 0x0ba0, 0x0ba2,
- 0x0ba5, 0x0ba7,
- 0x0bab, 0x0bad,
- 0x0bba, 0x0bbd,
- 0x0bc3, 0x0bc5,
- 0x0bc9, 0x0bc9,
- 0x0bce, 0x0bcf,
- 0x0bd1, 0x0bd6,
- 0x0bd8, 0x0be5,
- 0x0bfb, 0x0bff,
- 0x0c0d, 0x0c0d,
- 0x0c11, 0x0c11,
- 0x0c29, 0x0c29,
- 0x0c3a, 0x0c3b,
- 0x0c45, 0x0c45,
- 0x0c49, 0x0c49,
- 0x0c4e, 0x0c54,
- 0x0c57, 0x0c57,
- 0x0c5b, 0x0c5c,
- 0x0c5e, 0x0c5f,
- 0x0c64, 0x0c65,
- 0x0c70, 0x0c76,
- 0x0c8d, 0x0c8d,
- 0x0c91, 0x0c91,
- 0x0ca9, 0x0ca9,
- 0x0cb4, 0x0cb4,
- 0x0cba, 0x0cbb,
- 0x0cc5, 0x0cc5,
- 0x0cc9, 0x0cc9,
- 0x0cce, 0x0cd4,
- 0x0cd7, 0x0cdc,
- 0x0cdf, 0x0cdf,
- 0x0ce4, 0x0ce5,
- 0x0cf0, 0x0cf0,
- 0x0cf4, 0x0cff,
- 0x0d0d, 0x0d0d,
- 0x0d11, 0x0d11,
- 0x0d45, 0x0d45,
- 0x0d49, 0x0d49,
- 0x0d50, 0x0d53,
- 0x0d64, 0x0d65,
- 0x0d80, 0x0d80,
- 0x0d84, 0x0d84,
- 0x0d97, 0x0d99,
- 0x0db2, 0x0db2,
- 0x0dbc, 0x0dbc,
- 0x0dbe, 0x0dbf,
- 0x0dc7, 0x0dc9,
- 0x0dcb, 0x0dce,
- 0x0dd5, 0x0dd5,
- 0x0dd7, 0x0dd7,
- 0x0de0, 0x0de5,
- 0x0df0, 0x0df1,
- 0x0df5, 0x0e00,
- 0x0e3b, 0x0e3e,
- 0x0e5c, 0x0e80,
- 0x0e83, 0x0e83,
- 0x0e85, 0x0e85,
- 0x0e8b, 0x0e8b,
- 0x0ea4, 0x0ea4,
- 0x0ea6, 0x0ea6,
- 0x0ebe, 0x0ebf,
- 0x0ec5, 0x0ec5,
- 0x0ec7, 0x0ec7,
- 0x0ecf, 0x0ecf,
- 0x0eda, 0x0edb,
- 0x0ee0, 0x0eff,
- 0x0f48, 0x0f48,
- 0x0f6d, 0x0f70,
- 0x0f98, 0x0f98,
- 0x0fbd, 0x0fbd,
- 0x0fcd, 0x0fcd,
- 0x0fdb, 0x0fff,
- 0x10c6, 0x10c6,
- 0x10c8, 0x10cc,
- 0x10ce, 0x10cf,
- 0x1249, 0x1249,
- 0x124e, 0x124f,
- 0x1257, 0x1257,
- 0x1259, 0x1259,
- 0x125e, 0x125f,
- 0x1289, 0x1289,
- 0x128e, 0x128f,
- 0x12b1, 0x12b1,
- 0x12b6, 0x12b7,
- 0x12bf, 0x12bf,
- 0x12c1, 0x12c1,
- 0x12c6, 0x12c7,
- 0x12d7, 0x12d7,
- 0x1311, 0x1311,
- 0x1316, 0x1317,
- 0x135b, 0x135c,
- 0x137d, 0x137f,
- 0x139a, 0x139f,
- 0x13f6, 0x13f7,
- 0x13fe, 0x13ff,
- 0x169d, 0x169f,
- 0x16f9, 0x16ff,
- 0x1716, 0x171e,
- 0x1737, 0x173f,
- 0x1754, 0x175f,
- 0x176d, 0x176d,
- 0x1771, 0x1771,
- 0x1774, 0x177f,
- 0x17de, 0x17df,
- 0x17ea, 0x17ef,
- 0x17fa, 0x17ff,
- 0x181a, 0x181f,
- 0x1879, 0x187f,
- 0x18ab, 0x18af,
- 0x18f6, 0x18ff,
- 0x191f, 0x191f,
- 0x192c, 0x192f,
- 0x193c, 0x193f,
- 0x1941, 0x1943,
- 0x196e, 0x196f,
- 0x1975, 0x197f,
- 0x19ac, 0x19af,
- 0x19ca, 0x19cf,
- 0x19db, 0x19dd,
- 0x1a1c, 0x1a1d,
- 0x1a5f, 0x1a5f,
- 0x1a7d, 0x1a7e,
- 0x1a8a, 0x1a8f,
- 0x1a9a, 0x1a9f,
- 0x1aae, 0x1aaf,
- 0x1acf, 0x1aff,
- 0x1b4d, 0x1b4d,
- 0x1bf4, 0x1bfb,
- 0x1c38, 0x1c3a,
- 0x1c4a, 0x1c4c,
- 0x1c8b, 0x1c8f,
- 0x1cbb, 0x1cbc,
- 0x1cc8, 0x1ccf,
- 0x1cfb, 0x1cff,
- 0x1f16, 0x1f17,
- 0x1f1e, 0x1f1f,
- 0x1f46, 0x1f47,
- 0x1f4e, 0x1f4f,
- 0x1f58, 0x1f58,
- 0x1f5a, 0x1f5a,
- 0x1f5c, 0x1f5c,
- 0x1f5e, 0x1f5e,
- 0x1f7e, 0x1f7f,
- 0x1fb5, 0x1fb5,
- 0x1fc5, 0x1fc5,
- 0x1fd4, 0x1fd5,
- 0x1fdc, 0x1fdc,
- 0x1ff0, 0x1ff1,
- 0x1ff5, 0x1ff5,
- 0x1fff, 0x1fff,
- 0x2065, 0x2065,
- 0x2072, 0x2073,
- 0x208f, 0x208f,
- 0x209d, 0x209f,
- 0x20c1, 0x20cf,
- 0x20f1, 0x20ff,
- 0x218c, 0x218f,
- 0x242a, 0x243f,
- 0x244b, 0x245f,
- 0x2b74, 0x2b75,
- 0x2b96, 0x2b96,
- 0x2cf4, 0x2cf8,
- 0x2d26, 0x2d26,
- 0x2d28, 0x2d2c,
- 0x2d2e, 0x2d2f,
- 0x2d68, 0x2d6e,
- 0x2d71, 0x2d7e,
- 0x2d97, 0x2d9f,
- 0x2da7, 0x2da7,
- 0x2daf, 0x2daf,
- 0x2db7, 0x2db7,
- 0x2dbf, 0x2dbf,
- 0x2dc7, 0x2dc7,
- 0x2dcf, 0x2dcf,
- 0x2dd7, 0x2dd7,
- 0x2ddf, 0x2ddf,
- 0x2e5e, 0x2e7f,
- 0x2e9a, 0x2e9a,
- 0x2ef4, 0x2eff,
- 0x2fd6, 0x2fef,
- 0x3040, 0x3040,
- 0x3097, 0x3098,
- 0x3100, 0x3104,
- 0x3130, 0x3130,
- 0x318f, 0x318f,
- 0x31e6, 0x31ee,
- 0x321f, 0x321f,
- 0xa48d, 0xa48f,
- 0xa4c7, 0xa4cf,
- 0xa62c, 0xa63f,
- 0xa6f8, 0xa6ff,
- 0xa7ce, 0xa7cf,
- 0xa7d2, 0xa7d2,
- 0xa7d4, 0xa7d4,
- 0xa7dd, 0xa7f1,
- 0xa82d, 0xa82f,
- 0xa83a, 0xa83f,
- 0xa878, 0xa87f,
- 0xa8c6, 0xa8cd,
- 0xa8da, 0xa8df,
- 0xa954, 0xa95e,
- 0xa97d, 0xa97f,
- 0xa9ce, 0xa9ce,
- 0xa9da, 0xa9dd,
- 0xa9ff, 0xa9ff,
- 0xaa37, 0xaa3f,
- 0xaa4e, 0xaa4f,
- 0xaa5a, 0xaa5b,
- 0xaac3, 0xaada,
- 0xaaf7, 0xab00,
- 0xab07, 0xab08,
- 0xab0f, 0xab10,
- 0xab17, 0xab1f,
- 0xab27, 0xab27,
- 0xab2f, 0xab2f,
- 0xab6c, 0xab6f,
- 0xabee, 0xabef,
- 0xabfa, 0xabff,
- 0xd7a4, 0xd7af,
- 0xd7c7, 0xd7ca,
- 0xd7fc, 0xf8ff,
- 0xfa6e, 0xfa6f,
- 0xfada, 0xfaff,
- 0xfb07, 0xfb12,
- 0xfb18, 0xfb1c,
- 0xfb37, 0xfb37,
- 0xfb3d, 0xfb3d,
- 0xfb3f, 0xfb3f,
- 0xfb42, 0xfb42,
- 0xfb45, 0xfb45,
- 0xfbc3, 0xfbd2,
- 0xfd90, 0xfd91,
- 0xfdc8, 0xfdce,
- 0xfdd0, 0xfdef,
- 0xfe1a, 0xfe1f,
- 0xfe53, 0xfe53,
- 0xfe67, 0xfe67,
- 0xfe6c, 0xfe6f,
- 0xfe75, 0xfe75,
- 0xfefd, 0xfefe,
- 0xff00, 0xff00,
- 0xffbf, 0xffc1,
- 0xffc8, 0xffc9,
- 0xffd0, 0xffd1,
- 0xffd8, 0xffd9,
- 0xffdd, 0xffdf,
- 0xffe7, 0xffe7,
- 0xffef, 0xfff8,
- 0xfffe, 0xffff,
- 0x1000c, 0x1000c,
- 0x10027, 0x10027,
- 0x1003b, 0x1003b,
- 0x1003e, 0x1003e,
- 0x1004e, 0x1004f,
- 0x1005e, 0x1007f,
- 0x100fb, 0x100ff,
- 0x10103, 0x10106,
- 0x10134, 0x10136,
- 0x1018f, 0x1018f,
- 0x1019d, 0x1019f,
- 0x101a1, 0x101cf,
- 0x101fe, 0x1027f,
- 0x1029d, 0x1029f,
- 0x102d1, 0x102df,
- 0x102fc, 0x102ff,
- 0x10324, 0x1032c,
- 0x1034b, 0x1034f,
- 0x1037b, 0x1037f,
- 0x1039e, 0x1039e,
- 0x103c4, 0x103c7,
- 0x103d6, 0x103ff,
- 0x1049e, 0x1049f,
- 0x104aa, 0x104af,
- 0x104d4, 0x104d7,
- 0x104fc, 0x104ff,
- 0x10528, 0x1052f,
- 0x10564, 0x1056e,
- 0x1057b, 0x1057b,
- 0x1058b, 0x1058b,
- 0x10593, 0x10593,
- 0x10596, 0x10596,
- 0x105a2, 0x105a2,
- 0x105b2, 0x105b2,
- 0x105ba, 0x105ba,
- 0x105bd, 0x105bf,
- 0x105f4, 0x105ff,
- 0x10737, 0x1073f,
- 0x10756, 0x1075f,
- 0x10768, 0x1077f,
- 0x10786, 0x10786,
- 0x107b1, 0x107b1,
- 0x107bb, 0x107ff,
- 0x10806, 0x10807,
- 0x10809, 0x10809,
- 0x10836, 0x10836,
- 0x10839, 0x1083b,
- 0x1083d, 0x1083e,
- 0x10856, 0x10856,
- 0x1089f, 0x108a6,
- 0x108b0, 0x108df,
- 0x108f3, 0x108f3,
- 0x108f6, 0x108fa,
- 0x1091c, 0x1091e,
- 0x1093a, 0x1093e,
- 0x10940, 0x1097f,
- 0x109b8, 0x109bb,
- 0x109d0, 0x109d1,
- 0x10a04, 0x10a04,
- 0x10a07, 0x10a0b,
- 0x10a14, 0x10a14,
- 0x10a18, 0x10a18,
- 0x10a36, 0x10a37,
- 0x10a3b, 0x10a3e,
- 0x10a49, 0x10a4f,
- 0x10a59, 0x10a5f,
- 0x10aa0, 0x10abf,
- 0x10ae7, 0x10aea,
- 0x10af7, 0x10aff,
- 0x10b36, 0x10b38,
- 0x10b56, 0x10b57,
- 0x10b73, 0x10b77,
- 0x10b92, 0x10b98,
- 0x10b9d, 0x10ba8,
- 0x10bb0, 0x10bff,
- 0x10c49, 0x10c7f,
- 0x10cb3, 0x10cbf,
- 0x10cf3, 0x10cf9,
- 0x10d28, 0x10d2f,
- 0x10d3a, 0x10d3f,
- 0x10d66, 0x10d68,
- 0x10d86, 0x10d8d,
- 0x10d90, 0x10e5f,
- 0x10e7f, 0x10e7f,
- 0x10eaa, 0x10eaa,
- 0x10eae, 0x10eaf,
- 0x10eb2, 0x10ec1,
- 0x10ec5, 0x10efb,
- 0x10f28, 0x10f2f,
- 0x10f5a, 0x10f6f,
- 0x10f8a, 0x10faf,
- 0x10fcc, 0x10fdf,
- 0x10ff7, 0x10fff,
- 0x1104e, 0x11051,
- 0x11076, 0x1107e,
- 0x110c3, 0x110cc,
- 0x110ce, 0x110cf,
- 0x110e9, 0x110ef,
- 0x110fa, 0x110ff,
- 0x11135, 0x11135,
- 0x11148, 0x1114f,
- 0x11177, 0x1117f,
- 0x111e0, 0x111e0,
- 0x111f5, 0x111ff,
- 0x11212, 0x11212,
- 0x11242, 0x1127f,
- 0x11287, 0x11287,
- 0x11289, 0x11289,
- 0x1128e, 0x1128e,
- 0x1129e, 0x1129e,
- 0x112aa, 0x112af,
- 0x112eb, 0x112ef,
- 0x112fa, 0x112ff,
- 0x11304, 0x11304,
- 0x1130d, 0x1130e,
- 0x11311, 0x11312,
- 0x11329, 0x11329,
- 0x11331, 0x11331,
- 0x11334, 0x11334,
- 0x1133a, 0x1133a,
- 0x11345, 0x11346,
- 0x11349, 0x1134a,
- 0x1134e, 0x1134f,
- 0x11351, 0x11356,
- 0x11358, 0x1135c,
- 0x11364, 0x11365,
- 0x1136d, 0x1136f,
- 0x11375, 0x1137f,
- 0x1138a, 0x1138a,
- 0x1138c, 0x1138d,
- 0x1138f, 0x1138f,
- 0x113b6, 0x113b6,
- 0x113c1, 0x113c1,
- 0x113c3, 0x113c4,
- 0x113c6, 0x113c6,
- 0x113cb, 0x113cb,
- 0x113d6, 0x113d6,
- 0x113d9, 0x113e0,
- 0x113e3, 0x113ff,
- 0x1145c, 0x1145c,
- 0x11462, 0x1147f,
- 0x114c8, 0x114cf,
- 0x114da, 0x1157f,
- 0x115b6, 0x115b7,
- 0x115de, 0x115ff,
- 0x11645, 0x1164f,
- 0x1165a, 0x1165f,
- 0x1166d, 0x1167f,
- 0x116ba, 0x116bf,
- 0x116ca, 0x116cf,
- 0x116e4, 0x116ff,
- 0x1171b, 0x1171c,
- 0x1172c, 0x1172f,
- 0x11747, 0x117ff,
- 0x1183c, 0x1189f,
- 0x118f3, 0x118fe,
- 0x11907, 0x11908,
- 0x1190a, 0x1190b,
- 0x11914, 0x11914,
- 0x11917, 0x11917,
- 0x11936, 0x11936,
- 0x11939, 0x1193a,
- 0x11947, 0x1194f,
- 0x1195a, 0x1199f,
- 0x119a8, 0x119a9,
- 0x119d8, 0x119d9,
- 0x119e5, 0x119ff,
- 0x11a48, 0x11a4f,
- 0x11aa3, 0x11aaf,
- 0x11af9, 0x11aff,
- 0x11b0a, 0x11bbf,
- 0x11be2, 0x11bef,
- 0x11bfa, 0x11bff,
- 0x11c09, 0x11c09,
- 0x11c37, 0x11c37,
- 0x11c46, 0x11c4f,
- 0x11c6d, 0x11c6f,
- 0x11c90, 0x11c91,
- 0x11ca8, 0x11ca8,
- 0x11cb7, 0x11cff,
- 0x11d07, 0x11d07,
- 0x11d0a, 0x11d0a,
- 0x11d37, 0x11d39,
- 0x11d3b, 0x11d3b,
- 0x11d3e, 0x11d3e,
- 0x11d48, 0x11d4f,
- 0x11d5a, 0x11d5f,
- 0x11d66, 0x11d66,
- 0x11d69, 0x11d69,
- 0x11d8f, 0x11d8f,
- 0x11d92, 0x11d92,
- 0x11d99, 0x11d9f,
- 0x11daa, 0x11edf,
- 0x11ef9, 0x11eff,
- 0x11f11, 0x11f11,
- 0x11f3b, 0x11f3d,
- 0x11f5b, 0x11faf,
- 0x11fb1, 0x11fbf,
- 0x11ff2, 0x11ffe,
- 0x1239a, 0x123ff,
- 0x1246f, 0x1246f,
- 0x12475, 0x1247f,
- 0x12544, 0x12f8f,
- 0x12ff3, 0x12fff,
- 0x13456, 0x1345f,
- 0x143fb, 0x143ff,
- 0x14647, 0x160ff,
- 0x1613a, 0x167ff,
- 0x16a39, 0x16a3f,
- 0x16a5f, 0x16a5f,
- 0x16a6a, 0x16a6d,
- 0x16abf, 0x16abf,
- 0x16aca, 0x16acf,
- 0x16aee, 0x16aef,
- 0x16af6, 0x16aff,
- 0x16b46, 0x16b4f,
- 0x16b5a, 0x16b5a,
- 0x16b62, 0x16b62,
- 0x16b78, 0x16b7c,
- 0x16b90, 0x16d3f,
- 0x16d7a, 0x16e3f,
- 0x16e9b, 0x16eff,
- 0x16f4b, 0x16f4e,
- 0x16f88, 0x16f8e,
- 0x16fa0, 0x16fdf,
- 0x16fe5, 0x16fef,
- 0x16ff2, 0x16fff,
- 0x187f8, 0x187ff,
- 0x18cd6, 0x18cfe,
- 0x18d09, 0x1afef,
- 0x1aff4, 0x1aff4,
- 0x1affc, 0x1affc,
- 0x1afff, 0x1afff,
- 0x1b123, 0x1b131,
- 0x1b133, 0x1b14f,
- 0x1b153, 0x1b154,
- 0x1b156, 0x1b163,
- 0x1b168, 0x1b16f,
- 0x1b2fc, 0x1bbff,
- 0x1bc6b, 0x1bc6f,
- 0x1bc7d, 0x1bc7f,
- 0x1bc89, 0x1bc8f,
- 0x1bc9a, 0x1bc9b,
- 0x1bca4, 0x1cbff,
- 0x1ccfa, 0x1ccff,
- 0x1ceb4, 0x1ceff,
- 0x1cf2e, 0x1cf2f,
- 0x1cf47, 0x1cf4f,
- 0x1cfc4, 0x1cfff,
- 0x1d0f6, 0x1d0ff,
- 0x1d127, 0x1d128,
- 0x1d1eb, 0x1d1ff,
- 0x1d246, 0x1d2bf,
- 0x1d2d4, 0x1d2df,
- 0x1d2f4, 0x1d2ff,
- 0x1d357, 0x1d35f,
- 0x1d379, 0x1d3ff,
- 0x1d455, 0x1d455,
- 0x1d49d, 0x1d49d,
- 0x1d4a0, 0x1d4a1,
- 0x1d4a3, 0x1d4a4,
- 0x1d4a7, 0x1d4a8,
- 0x1d4ad, 0x1d4ad,
- 0x1d4ba, 0x1d4ba,
- 0x1d4bc, 0x1d4bc,
- 0x1d4c4, 0x1d4c4,
- 0x1d506, 0x1d506,
- 0x1d50b, 0x1d50c,
- 0x1d515, 0x1d515,
- 0x1d51d, 0x1d51d,
- 0x1d53a, 0x1d53a,
- 0x1d53f, 0x1d53f,
- 0x1d545, 0x1d545,
- 0x1d547, 0x1d549,
- 0x1d551, 0x1d551,
- 0x1d6a6, 0x1d6a7,
- 0x1d7cc, 0x1d7cd,
- 0x1da8c, 0x1da9a,
- 0x1daa0, 0x1daa0,
- 0x1dab0, 0x1deff,
- 0x1df1f, 0x1df24,
- 0x1df2b, 0x1dfff,
- 0x1e007, 0x1e007,
- 0x1e019, 0x1e01a,
- 0x1e022, 0x1e022,
- 0x1e025, 0x1e025,
- 0x1e02b, 0x1e02f,
- 0x1e06e, 0x1e08e,
- 0x1e090, 0x1e0ff,
- 0x1e12d, 0x1e12f,
- 0x1e13e, 0x1e13f,
- 0x1e14a, 0x1e14d,
- 0x1e150, 0x1e28f,
- 0x1e2af, 0x1e2bf,
- 0x1e2fa, 0x1e2fe,
- 0x1e300, 0x1e4cf,
- 0x1e4fa, 0x1e5cf,
- 0x1e5fb, 0x1e5fe,
- 0x1e600, 0x1e7df,
- 0x1e7e7, 0x1e7e7,
- 0x1e7ec, 0x1e7ec,
- 0x1e7ef, 0x1e7ef,
- 0x1e7ff, 0x1e7ff,
- 0x1e8c5, 0x1e8c6,
- 0x1e8d7, 0x1e8ff,
- 0x1e94c, 0x1e94f,
- 0x1e95a, 0x1e95d,
- 0x1e960, 0x1ec70,
- 0x1ecb5, 0x1ed00,
- 0x1ed3e, 0x1edff,
- 0x1ee04, 0x1ee04,
- 0x1ee20, 0x1ee20,
- 0x1ee23, 0x1ee23,
- 0x1ee25, 0x1ee26,
- 0x1ee28, 0x1ee28,
- 0x1ee33, 0x1ee33,
- 0x1ee38, 0x1ee38,
- 0x1ee3a, 0x1ee3a,
- 0x1ee3c, 0x1ee41,
- 0x1ee43, 0x1ee46,
- 0x1ee48, 0x1ee48,
- 0x1ee4a, 0x1ee4a,
- 0x1ee4c, 0x1ee4c,
- 0x1ee50, 0x1ee50,
- 0x1ee53, 0x1ee53,
- 0x1ee55, 0x1ee56,
- 0x1ee58, 0x1ee58,
- 0x1ee5a, 0x1ee5a,
- 0x1ee5c, 0x1ee5c,
- 0x1ee5e, 0x1ee5e,
- 0x1ee60, 0x1ee60,
- 0x1ee63, 0x1ee63,
- 0x1ee65, 0x1ee66,
- 0x1ee6b, 0x1ee6b,
- 0x1ee73, 0x1ee73,
- 0x1ee78, 0x1ee78,
- 0x1ee7d, 0x1ee7d,
- 0x1ee7f, 0x1ee7f,
- 0x1ee8a, 0x1ee8a,
- 0x1ee9c, 0x1eea0,
- 0x1eea4, 0x1eea4,
- 0x1eeaa, 0x1eeaa,
- 0x1eebc, 0x1eeef,
- 0x1eef2, 0x1efff,
- 0x1f02c, 0x1f02f,
- 0x1f094, 0x1f09f,
- 0x1f0af, 0x1f0b0,
- 0x1f0c0, 0x1f0c0,
- 0x1f0d0, 0x1f0d0,
- 0x1f0f6, 0x1f0ff,
- 0x1f1ae, 0x1f1e5,
- 0x1f203, 0x1f20f,
- 0x1f23c, 0x1f23f,
- 0x1f249, 0x1f24f,
- 0x1f252, 0x1f25f,
- 0x1f266, 0x1f2ff,
- 0x1f6d8, 0x1f6db,
- 0x1f6ed, 0x1f6ef,
- 0x1f6fd, 0x1f6ff,
- 0x1f777, 0x1f77a,
- 0x1f7da, 0x1f7df,
- 0x1f7ec, 0x1f7ef,
- 0x1f7f1, 0x1f7ff,
- 0x1f80c, 0x1f80f,
- 0x1f848, 0x1f84f,
- 0x1f85a, 0x1f85f,
- 0x1f888, 0x1f88f,
- 0x1f8ae, 0x1f8af,
- 0x1f8bc, 0x1f8bf,
- 0x1f8c2, 0x1f8ff,
- 0x1fa54, 0x1fa5f,
- 0x1fa6e, 0x1fa6f,
- 0x1fa7d, 0x1fa7f,
- 0x1fa8a, 0x1fa8e,
- 0x1fac7, 0x1facd,
- 0x1fadd, 0x1fade,
- 0x1faea, 0x1faef,
- 0x1faf9, 0x1faff,
- 0x1fb93, 0x1fb93,
- 0x1fbfa, 0x1ffff,
- 0x2a6e0, 0x2a6ff,
- 0x2b73a, 0x2b73f,
- 0x2b81e, 0x2b81f,
- 0x2cea2, 0x2ceaf,
- 0x2ebe1, 0x2ebef,
- 0x2ee5e, 0x2f7ff,
- 0x2fa1e, 0x2ffff,
- 0x3134b, 0x3134f,
- 0x323b0, 0xe0000,
- 0xe0002, 0xe001f,
- 0xe0080, 0xe00ff,
- 0xe01f0, 0x10ffff,
-}; /* CR_Unknown */
-
-#ifdef USE_UNICODE_AGE_PROPERTIES
-/* 'Age_1_1': Derived Age 1.1 */
-static const OnigCodePoint CR_Age_1_1[] = {
- 288,
- 0x0000, 0x01f5,
- 0x01fa, 0x0217,
- 0x0250, 0x02a8,
- 0x02b0, 0x02de,
- 0x02e0, 0x02e9,
- 0x0300, 0x0345,
- 0x0360, 0x0361,
- 0x0374, 0x0375,
- 0x037a, 0x037a,
- 0x037e, 0x037e,
- 0x0384, 0x038a,
- 0x038c, 0x038c,
- 0x038e, 0x03a1,
- 0x03a3, 0x03ce,
- 0x03d0, 0x03d6,
- 0x03da, 0x03da,
- 0x03dc, 0x03dc,
- 0x03de, 0x03de,
- 0x03e0, 0x03e0,
- 0x03e2, 0x03f3,
- 0x0401, 0x040c,
- 0x040e, 0x044f,
- 0x0451, 0x045c,
- 0x045e, 0x0486,
- 0x0490, 0x04c4,
- 0x04c7, 0x04c8,
- 0x04cb, 0x04cc,
- 0x04d0, 0x04eb,
- 0x04ee, 0x04f5,
- 0x04f8, 0x04f9,
- 0x0531, 0x0556,
- 0x0559, 0x055f,
- 0x0561, 0x0587,
- 0x0589, 0x0589,
- 0x05b0, 0x05b9,
- 0x05bb, 0x05c3,
- 0x05d0, 0x05ea,
- 0x05f0, 0x05f4,
- 0x060c, 0x060c,
- 0x061b, 0x061b,
- 0x061f, 0x061f,
- 0x0621, 0x063a,
- 0x0640, 0x0652,
- 0x0660, 0x066d,
- 0x0670, 0x06b7,
- 0x06ba, 0x06be,
- 0x06c0, 0x06ce,
- 0x06d0, 0x06ed,
- 0x06f0, 0x06f9,
- 0x0901, 0x0903,
- 0x0905, 0x0939,
- 0x093c, 0x094d,
- 0x0950, 0x0954,
- 0x0958, 0x0970,
- 0x0981, 0x0983,
- 0x0985, 0x098c,
- 0x098f, 0x0990,
- 0x0993, 0x09a8,
- 0x09aa, 0x09b0,
- 0x09b2, 0x09b2,
- 0x09b6, 0x09b9,
- 0x09bc, 0x09bc,
- 0x09be, 0x09c4,
- 0x09c7, 0x09c8,
- 0x09cb, 0x09cd,
- 0x09d7, 0x09d7,
- 0x09dc, 0x09dd,
- 0x09df, 0x09e3,
- 0x09e6, 0x09fa,
- 0x0a02, 0x0a02,
- 0x0a05, 0x0a0a,
- 0x0a0f, 0x0a10,
- 0x0a13, 0x0a28,
- 0x0a2a, 0x0a30,
- 0x0a32, 0x0a33,
- 0x0a35, 0x0a36,
- 0x0a38, 0x0a39,
- 0x0a3c, 0x0a3c,
- 0x0a3e, 0x0a42,
- 0x0a47, 0x0a48,
- 0x0a4b, 0x0a4d,
- 0x0a59, 0x0a5c,
- 0x0a5e, 0x0a5e,
- 0x0a66, 0x0a74,
- 0x0a81, 0x0a83,
- 0x0a85, 0x0a8b,
- 0x0a8d, 0x0a8d,
- 0x0a8f, 0x0a91,
- 0x0a93, 0x0aa8,
- 0x0aaa, 0x0ab0,
- 0x0ab2, 0x0ab3,
- 0x0ab5, 0x0ab9,
- 0x0abc, 0x0ac5,
- 0x0ac7, 0x0ac9,
- 0x0acb, 0x0acd,
- 0x0ad0, 0x0ad0,
- 0x0ae0, 0x0ae0,
- 0x0ae6, 0x0aef,
- 0x0b01, 0x0b03,
- 0x0b05, 0x0b0c,
- 0x0b0f, 0x0b10,
- 0x0b13, 0x0b28,
- 0x0b2a, 0x0b30,
- 0x0b32, 0x0b33,
- 0x0b36, 0x0b39,
- 0x0b3c, 0x0b43,
- 0x0b47, 0x0b48,
- 0x0b4b, 0x0b4d,
- 0x0b56, 0x0b57,
- 0x0b5c, 0x0b5d,
- 0x0b5f, 0x0b61,
- 0x0b66, 0x0b70,
- 0x0b82, 0x0b83,
- 0x0b85, 0x0b8a,
- 0x0b8e, 0x0b90,
- 0x0b92, 0x0b95,
- 0x0b99, 0x0b9a,
- 0x0b9c, 0x0b9c,
- 0x0b9e, 0x0b9f,
- 0x0ba3, 0x0ba4,
- 0x0ba8, 0x0baa,
- 0x0bae, 0x0bb5,
- 0x0bb7, 0x0bb9,
- 0x0bbe, 0x0bc2,
- 0x0bc6, 0x0bc8,
- 0x0bca, 0x0bcd,
- 0x0bd7, 0x0bd7,
- 0x0be7, 0x0bf2,
- 0x0c01, 0x0c03,
- 0x0c05, 0x0c0c,
- 0x0c0e, 0x0c10,
- 0x0c12, 0x0c28,
- 0x0c2a, 0x0c33,
- 0x0c35, 0x0c39,
- 0x0c3e, 0x0c44,
- 0x0c46, 0x0c48,
- 0x0c4a, 0x0c4d,
- 0x0c55, 0x0c56,
- 0x0c60, 0x0c61,
- 0x0c66, 0x0c6f,
- 0x0c82, 0x0c83,
- 0x0c85, 0x0c8c,
- 0x0c8e, 0x0c90,
- 0x0c92, 0x0ca8,
- 0x0caa, 0x0cb3,
- 0x0cb5, 0x0cb9,
- 0x0cbe, 0x0cc4,
- 0x0cc6, 0x0cc8,
- 0x0cca, 0x0ccd,
- 0x0cd5, 0x0cd6,
- 0x0cde, 0x0cde,
- 0x0ce0, 0x0ce1,
- 0x0ce6, 0x0cef,
- 0x0d02, 0x0d03,
- 0x0d05, 0x0d0c,
- 0x0d0e, 0x0d10,
- 0x0d12, 0x0d28,
- 0x0d2a, 0x0d39,
- 0x0d3e, 0x0d43,
- 0x0d46, 0x0d48,
- 0x0d4a, 0x0d4d,
- 0x0d57, 0x0d57,
- 0x0d60, 0x0d61,
- 0x0d66, 0x0d6f,
- 0x0e01, 0x0e3a,
- 0x0e3f, 0x0e5b,
- 0x0e81, 0x0e82,
- 0x0e84, 0x0e84,
- 0x0e87, 0x0e88,
- 0x0e8a, 0x0e8a,
- 0x0e8d, 0x0e8d,
- 0x0e94, 0x0e97,
- 0x0e99, 0x0e9f,
- 0x0ea1, 0x0ea3,
- 0x0ea5, 0x0ea5,
- 0x0ea7, 0x0ea7,
- 0x0eaa, 0x0eab,
- 0x0ead, 0x0eb9,
- 0x0ebb, 0x0ebd,
- 0x0ec0, 0x0ec4,
- 0x0ec6, 0x0ec6,
- 0x0ec8, 0x0ecd,
- 0x0ed0, 0x0ed9,
- 0x0edc, 0x0edd,
- 0x10a0, 0x10c5,
- 0x10d0, 0x10f6,
- 0x10fb, 0x10fb,
- 0x1100, 0x1159,
- 0x115f, 0x11a2,
- 0x11a8, 0x11f9,
- 0x1e00, 0x1e9a,
- 0x1ea0, 0x1ef9,
- 0x1f00, 0x1f15,
- 0x1f18, 0x1f1d,
- 0x1f20, 0x1f45,
- 0x1f48, 0x1f4d,
- 0x1f50, 0x1f57,
- 0x1f59, 0x1f59,
- 0x1f5b, 0x1f5b,
- 0x1f5d, 0x1f5d,
- 0x1f5f, 0x1f7d,
- 0x1f80, 0x1fb4,
- 0x1fb6, 0x1fc4,
- 0x1fc6, 0x1fd3,
- 0x1fd6, 0x1fdb,
- 0x1fdd, 0x1fef,
- 0x1ff2, 0x1ff4,
- 0x1ff6, 0x1ffe,
- 0x2000, 0x202e,
- 0x2030, 0x2046,
- 0x206a, 0x2070,
- 0x2074, 0x208e,
- 0x20a0, 0x20aa,
- 0x20d0, 0x20e1,
- 0x2100, 0x2138,
- 0x2153, 0x2182,
- 0x2190, 0x21ea,
- 0x2200, 0x22f1,
- 0x2300, 0x2300,
- 0x2302, 0x237a,
- 0x2400, 0x2424,
- 0x2440, 0x244a,
- 0x2460, 0x24ea,
- 0x2500, 0x2595,
- 0x25a0, 0x25ef,
- 0x2600, 0x2613,
- 0x261a, 0x266f,
- 0x2701, 0x2704,
- 0x2706, 0x2709,
- 0x270c, 0x2727,
- 0x2729, 0x274b,
- 0x274d, 0x274d,
- 0x274f, 0x2752,
- 0x2756, 0x2756,
- 0x2758, 0x275e,
- 0x2761, 0x2767,
- 0x2776, 0x2794,
- 0x2798, 0x27af,
- 0x27b1, 0x27be,
- 0x3000, 0x3037,
- 0x303f, 0x303f,
- 0x3041, 0x3094,
- 0x3099, 0x309e,
- 0x30a1, 0x30fe,
- 0x3105, 0x312c,
- 0x3131, 0x318e,
- 0x3190, 0x319f,
- 0x3200, 0x321c,
- 0x3220, 0x3243,
- 0x3260, 0x327b,
- 0x327f, 0x32b0,
- 0x32c0, 0x32cb,
- 0x32d0, 0x32fe,
- 0x3300, 0x3376,
- 0x337b, 0x33dd,
- 0x33e0, 0x33fe,
- 0x4e00, 0x9fa5,
- 0xe000, 0xfa2d,
- 0xfb00, 0xfb06,
- 0xfb13, 0xfb17,
- 0xfb1e, 0xfb36,
- 0xfb38, 0xfb3c,
- 0xfb3e, 0xfb3e,
- 0xfb40, 0xfb41,
- 0xfb43, 0xfb44,
- 0xfb46, 0xfbb1,
- 0xfbd3, 0xfd3f,
- 0xfd50, 0xfd8f,
- 0xfd92, 0xfdc7,
- 0xfdf0, 0xfdfb,
- 0xfe20, 0xfe23,
- 0xfe30, 0xfe44,
- 0xfe49, 0xfe52,
- 0xfe54, 0xfe66,
- 0xfe68, 0xfe6b,
- 0xfe70, 0xfe72,
- 0xfe74, 0xfe74,
- 0xfe76, 0xfefc,
- 0xfeff, 0xfeff,
- 0xff01, 0xff5e,
- 0xff61, 0xffbe,
- 0xffc2, 0xffc7,
- 0xffca, 0xffcf,
- 0xffd2, 0xffd7,
- 0xffda, 0xffdc,
- 0xffe0, 0xffe6,
- 0xffe8, 0xffee,
- 0xfffd, 0xffff,
-}; /* CR_Age_1_1 */
-
-/* 'Age_2_0': Derived Age 2.0 */
-static const OnigCodePoint CR_Age_2_0[] = {
- 312,
- 0x0000, 0x01f5,
- 0x01fa, 0x0217,
- 0x0250, 0x02a8,
- 0x02b0, 0x02de,
- 0x02e0, 0x02e9,
- 0x0300, 0x0345,
- 0x0360, 0x0361,
- 0x0374, 0x0375,
- 0x037a, 0x037a,
- 0x037e, 0x037e,
- 0x0384, 0x038a,
- 0x038c, 0x038c,
- 0x038e, 0x03a1,
- 0x03a3, 0x03ce,
- 0x03d0, 0x03d6,
- 0x03da, 0x03da,
- 0x03dc, 0x03dc,
- 0x03de, 0x03de,
- 0x03e0, 0x03e0,
- 0x03e2, 0x03f3,
- 0x0401, 0x040c,
- 0x040e, 0x044f,
- 0x0451, 0x045c,
- 0x045e, 0x0486,
- 0x0490, 0x04c4,
- 0x04c7, 0x04c8,
- 0x04cb, 0x04cc,
- 0x04d0, 0x04eb,
- 0x04ee, 0x04f5,
- 0x04f8, 0x04f9,
- 0x0531, 0x0556,
- 0x0559, 0x055f,
- 0x0561, 0x0587,
- 0x0589, 0x0589,
- 0x0591, 0x05a1,
- 0x05a3, 0x05b9,
- 0x05bb, 0x05c4,
- 0x05d0, 0x05ea,
- 0x05f0, 0x05f4,
- 0x060c, 0x060c,
- 0x061b, 0x061b,
- 0x061f, 0x061f,
- 0x0621, 0x063a,
- 0x0640, 0x0652,
- 0x0660, 0x066d,
- 0x0670, 0x06b7,
- 0x06ba, 0x06be,
- 0x06c0, 0x06ce,
- 0x06d0, 0x06ed,
- 0x06f0, 0x06f9,
- 0x0901, 0x0903,
- 0x0905, 0x0939,
- 0x093c, 0x094d,
- 0x0950, 0x0954,
- 0x0958, 0x0970,
- 0x0981, 0x0983,
- 0x0985, 0x098c,
- 0x098f, 0x0990,
- 0x0993, 0x09a8,
- 0x09aa, 0x09b0,
- 0x09b2, 0x09b2,
- 0x09b6, 0x09b9,
- 0x09bc, 0x09bc,
- 0x09be, 0x09c4,
- 0x09c7, 0x09c8,
- 0x09cb, 0x09cd,
- 0x09d7, 0x09d7,
- 0x09dc, 0x09dd,
- 0x09df, 0x09e3,
- 0x09e6, 0x09fa,
- 0x0a02, 0x0a02,
- 0x0a05, 0x0a0a,
- 0x0a0f, 0x0a10,
- 0x0a13, 0x0a28,
- 0x0a2a, 0x0a30,
- 0x0a32, 0x0a33,
- 0x0a35, 0x0a36,
- 0x0a38, 0x0a39,
- 0x0a3c, 0x0a3c,
- 0x0a3e, 0x0a42,
- 0x0a47, 0x0a48,
- 0x0a4b, 0x0a4d,
- 0x0a59, 0x0a5c,
- 0x0a5e, 0x0a5e,
- 0x0a66, 0x0a74,
- 0x0a81, 0x0a83,
- 0x0a85, 0x0a8b,
- 0x0a8d, 0x0a8d,
- 0x0a8f, 0x0a91,
- 0x0a93, 0x0aa8,
- 0x0aaa, 0x0ab0,
- 0x0ab2, 0x0ab3,
- 0x0ab5, 0x0ab9,
- 0x0abc, 0x0ac5,
- 0x0ac7, 0x0ac9,
- 0x0acb, 0x0acd,
- 0x0ad0, 0x0ad0,
- 0x0ae0, 0x0ae0,
- 0x0ae6, 0x0aef,
- 0x0b01, 0x0b03,
- 0x0b05, 0x0b0c,
- 0x0b0f, 0x0b10,
- 0x0b13, 0x0b28,
- 0x0b2a, 0x0b30,
- 0x0b32, 0x0b33,
- 0x0b36, 0x0b39,
- 0x0b3c, 0x0b43,
- 0x0b47, 0x0b48,
- 0x0b4b, 0x0b4d,
- 0x0b56, 0x0b57,
- 0x0b5c, 0x0b5d,
- 0x0b5f, 0x0b61,
- 0x0b66, 0x0b70,
- 0x0b82, 0x0b83,
- 0x0b85, 0x0b8a,
- 0x0b8e, 0x0b90,
- 0x0b92, 0x0b95,
- 0x0b99, 0x0b9a,
- 0x0b9c, 0x0b9c,
- 0x0b9e, 0x0b9f,
- 0x0ba3, 0x0ba4,
- 0x0ba8, 0x0baa,
- 0x0bae, 0x0bb5,
- 0x0bb7, 0x0bb9,
- 0x0bbe, 0x0bc2,
- 0x0bc6, 0x0bc8,
- 0x0bca, 0x0bcd,
- 0x0bd7, 0x0bd7,
- 0x0be7, 0x0bf2,
- 0x0c01, 0x0c03,
- 0x0c05, 0x0c0c,
- 0x0c0e, 0x0c10,
- 0x0c12, 0x0c28,
- 0x0c2a, 0x0c33,
- 0x0c35, 0x0c39,
- 0x0c3e, 0x0c44,
- 0x0c46, 0x0c48,
- 0x0c4a, 0x0c4d,
- 0x0c55, 0x0c56,
- 0x0c60, 0x0c61,
- 0x0c66, 0x0c6f,
- 0x0c82, 0x0c83,
- 0x0c85, 0x0c8c,
- 0x0c8e, 0x0c90,
- 0x0c92, 0x0ca8,
- 0x0caa, 0x0cb3,
- 0x0cb5, 0x0cb9,
- 0x0cbe, 0x0cc4,
- 0x0cc6, 0x0cc8,
- 0x0cca, 0x0ccd,
- 0x0cd5, 0x0cd6,
- 0x0cde, 0x0cde,
- 0x0ce0, 0x0ce1,
- 0x0ce6, 0x0cef,
- 0x0d02, 0x0d03,
- 0x0d05, 0x0d0c,
- 0x0d0e, 0x0d10,
- 0x0d12, 0x0d28,
- 0x0d2a, 0x0d39,
- 0x0d3e, 0x0d43,
- 0x0d46, 0x0d48,
- 0x0d4a, 0x0d4d,
- 0x0d57, 0x0d57,
- 0x0d60, 0x0d61,
- 0x0d66, 0x0d6f,
- 0x0e01, 0x0e3a,
- 0x0e3f, 0x0e5b,
- 0x0e81, 0x0e82,
- 0x0e84, 0x0e84,
- 0x0e87, 0x0e88,
- 0x0e8a, 0x0e8a,
- 0x0e8d, 0x0e8d,
- 0x0e94, 0x0e97,
- 0x0e99, 0x0e9f,
- 0x0ea1, 0x0ea3,
- 0x0ea5, 0x0ea5,
- 0x0ea7, 0x0ea7,
- 0x0eaa, 0x0eab,
- 0x0ead, 0x0eb9,
- 0x0ebb, 0x0ebd,
- 0x0ec0, 0x0ec4,
- 0x0ec6, 0x0ec6,
- 0x0ec8, 0x0ecd,
- 0x0ed0, 0x0ed9,
- 0x0edc, 0x0edd,
- 0x0f00, 0x0f47,
- 0x0f49, 0x0f69,
- 0x0f71, 0x0f8b,
- 0x0f90, 0x0f95,
- 0x0f97, 0x0f97,
- 0x0f99, 0x0fad,
- 0x0fb1, 0x0fb7,
- 0x0fb9, 0x0fb9,
- 0x10a0, 0x10c5,
- 0x10d0, 0x10f6,
- 0x10fb, 0x10fb,
- 0x1100, 0x1159,
- 0x115f, 0x11a2,
- 0x11a8, 0x11f9,
- 0x1e00, 0x1e9b,
- 0x1ea0, 0x1ef9,
- 0x1f00, 0x1f15,
- 0x1f18, 0x1f1d,
- 0x1f20, 0x1f45,
- 0x1f48, 0x1f4d,
- 0x1f50, 0x1f57,
- 0x1f59, 0x1f59,
- 0x1f5b, 0x1f5b,
- 0x1f5d, 0x1f5d,
- 0x1f5f, 0x1f7d,
- 0x1f80, 0x1fb4,
- 0x1fb6, 0x1fc4,
- 0x1fc6, 0x1fd3,
- 0x1fd6, 0x1fdb,
- 0x1fdd, 0x1fef,
- 0x1ff2, 0x1ff4,
- 0x1ff6, 0x1ffe,
- 0x2000, 0x202e,
- 0x2030, 0x2046,
- 0x206a, 0x2070,
- 0x2074, 0x208e,
- 0x20a0, 0x20ab,
- 0x20d0, 0x20e1,
- 0x2100, 0x2138,
- 0x2153, 0x2182,
- 0x2190, 0x21ea,
- 0x2200, 0x22f1,
- 0x2300, 0x2300,
- 0x2302, 0x237a,
- 0x2400, 0x2424,
- 0x2440, 0x244a,
- 0x2460, 0x24ea,
- 0x2500, 0x2595,
- 0x25a0, 0x25ef,
- 0x2600, 0x2613,
- 0x261a, 0x266f,
- 0x2701, 0x2704,
- 0x2706, 0x2709,
- 0x270c, 0x2727,
- 0x2729, 0x274b,
- 0x274d, 0x274d,
- 0x274f, 0x2752,
- 0x2756, 0x2756,
- 0x2758, 0x275e,
- 0x2761, 0x2767,
- 0x2776, 0x2794,
- 0x2798, 0x27af,
- 0x27b1, 0x27be,
- 0x3000, 0x3037,
- 0x303f, 0x303f,
- 0x3041, 0x3094,
- 0x3099, 0x309e,
- 0x30a1, 0x30fe,
- 0x3105, 0x312c,
- 0x3131, 0x318e,
- 0x3190, 0x319f,
- 0x3200, 0x321c,
- 0x3220, 0x3243,
- 0x3260, 0x327b,
- 0x327f, 0x32b0,
- 0x32c0, 0x32cb,
- 0x32d0, 0x32fe,
- 0x3300, 0x3376,
- 0x337b, 0x33dd,
- 0x33e0, 0x33fe,
- 0x4e00, 0x9fa5,
- 0xac00, 0xd7a3,
- 0xd800, 0xfa2d,
- 0xfb00, 0xfb06,
- 0xfb13, 0xfb17,
- 0xfb1e, 0xfb36,
- 0xfb38, 0xfb3c,
- 0xfb3e, 0xfb3e,
- 0xfb40, 0xfb41,
- 0xfb43, 0xfb44,
- 0xfb46, 0xfbb1,
- 0xfbd3, 0xfd3f,
- 0xfd50, 0xfd8f,
- 0xfd92, 0xfdc7,
- 0xfdf0, 0xfdfb,
- 0xfe20, 0xfe23,
- 0xfe30, 0xfe44,
- 0xfe49, 0xfe52,
- 0xfe54, 0xfe66,
- 0xfe68, 0xfe6b,
- 0xfe70, 0xfe72,
- 0xfe74, 0xfe74,
- 0xfe76, 0xfefc,
- 0xfeff, 0xfeff,
- 0xff01, 0xff5e,
- 0xff61, 0xffbe,
- 0xffc2, 0xffc7,
- 0xffca, 0xffcf,
- 0xffd2, 0xffd7,
- 0xffda, 0xffdc,
- 0xffe0, 0xffe6,
- 0xffe8, 0xffee,
- 0xfffd, 0xffff,
- 0x1fffe, 0x1ffff,
- 0x2fffe, 0x2ffff,
- 0x3fffe, 0x3ffff,
- 0x4fffe, 0x4ffff,
- 0x5fffe, 0x5ffff,
- 0x6fffe, 0x6ffff,
- 0x7fffe, 0x7ffff,
- 0x8fffe, 0x8ffff,
- 0x9fffe, 0x9ffff,
- 0xafffe, 0xaffff,
- 0xbfffe, 0xbffff,
- 0xcfffe, 0xcffff,
- 0xdfffe, 0xdffff,
- 0xefffe, 0x10ffff,
-}; /* CR_Age_2_0 */
-
-/* 'Age_2_1': Derived Age 2.1 */
-static const OnigCodePoint CR_Age_2_1[] = {
- 312,
- 0x0000, 0x01f5,
- 0x01fa, 0x0217,
- 0x0250, 0x02a8,
- 0x02b0, 0x02de,
- 0x02e0, 0x02e9,
- 0x0300, 0x0345,
- 0x0360, 0x0361,
- 0x0374, 0x0375,
- 0x037a, 0x037a,
- 0x037e, 0x037e,
- 0x0384, 0x038a,
- 0x038c, 0x038c,
- 0x038e, 0x03a1,
- 0x03a3, 0x03ce,
- 0x03d0, 0x03d6,
- 0x03da, 0x03da,
- 0x03dc, 0x03dc,
- 0x03de, 0x03de,
- 0x03e0, 0x03e0,
- 0x03e2, 0x03f3,
- 0x0401, 0x040c,
- 0x040e, 0x044f,
- 0x0451, 0x045c,
- 0x045e, 0x0486,
- 0x0490, 0x04c4,
- 0x04c7, 0x04c8,
- 0x04cb, 0x04cc,
- 0x04d0, 0x04eb,
- 0x04ee, 0x04f5,
- 0x04f8, 0x04f9,
- 0x0531, 0x0556,
- 0x0559, 0x055f,
- 0x0561, 0x0587,
- 0x0589, 0x0589,
- 0x0591, 0x05a1,
- 0x05a3, 0x05b9,
- 0x05bb, 0x05c4,
- 0x05d0, 0x05ea,
- 0x05f0, 0x05f4,
- 0x060c, 0x060c,
- 0x061b, 0x061b,
- 0x061f, 0x061f,
- 0x0621, 0x063a,
- 0x0640, 0x0652,
- 0x0660, 0x066d,
- 0x0670, 0x06b7,
- 0x06ba, 0x06be,
- 0x06c0, 0x06ce,
- 0x06d0, 0x06ed,
- 0x06f0, 0x06f9,
- 0x0901, 0x0903,
- 0x0905, 0x0939,
- 0x093c, 0x094d,
- 0x0950, 0x0954,
- 0x0958, 0x0970,
- 0x0981, 0x0983,
- 0x0985, 0x098c,
- 0x098f, 0x0990,
- 0x0993, 0x09a8,
- 0x09aa, 0x09b0,
- 0x09b2, 0x09b2,
- 0x09b6, 0x09b9,
- 0x09bc, 0x09bc,
- 0x09be, 0x09c4,
- 0x09c7, 0x09c8,
- 0x09cb, 0x09cd,
- 0x09d7, 0x09d7,
- 0x09dc, 0x09dd,
- 0x09df, 0x09e3,
- 0x09e6, 0x09fa,
- 0x0a02, 0x0a02,
- 0x0a05, 0x0a0a,
- 0x0a0f, 0x0a10,
- 0x0a13, 0x0a28,
- 0x0a2a, 0x0a30,
- 0x0a32, 0x0a33,
- 0x0a35, 0x0a36,
- 0x0a38, 0x0a39,
- 0x0a3c, 0x0a3c,
- 0x0a3e, 0x0a42,
- 0x0a47, 0x0a48,
- 0x0a4b, 0x0a4d,
- 0x0a59, 0x0a5c,
- 0x0a5e, 0x0a5e,
- 0x0a66, 0x0a74,
- 0x0a81, 0x0a83,
- 0x0a85, 0x0a8b,
- 0x0a8d, 0x0a8d,
- 0x0a8f, 0x0a91,
- 0x0a93, 0x0aa8,
- 0x0aaa, 0x0ab0,
- 0x0ab2, 0x0ab3,
- 0x0ab5, 0x0ab9,
- 0x0abc, 0x0ac5,
- 0x0ac7, 0x0ac9,
- 0x0acb, 0x0acd,
- 0x0ad0, 0x0ad0,
- 0x0ae0, 0x0ae0,
- 0x0ae6, 0x0aef,
- 0x0b01, 0x0b03,
- 0x0b05, 0x0b0c,
- 0x0b0f, 0x0b10,
- 0x0b13, 0x0b28,
- 0x0b2a, 0x0b30,
- 0x0b32, 0x0b33,
- 0x0b36, 0x0b39,
- 0x0b3c, 0x0b43,
- 0x0b47, 0x0b48,
- 0x0b4b, 0x0b4d,
- 0x0b56, 0x0b57,
- 0x0b5c, 0x0b5d,
- 0x0b5f, 0x0b61,
- 0x0b66, 0x0b70,
- 0x0b82, 0x0b83,
- 0x0b85, 0x0b8a,
- 0x0b8e, 0x0b90,
- 0x0b92, 0x0b95,
- 0x0b99, 0x0b9a,
- 0x0b9c, 0x0b9c,
- 0x0b9e, 0x0b9f,
- 0x0ba3, 0x0ba4,
- 0x0ba8, 0x0baa,
- 0x0bae, 0x0bb5,
- 0x0bb7, 0x0bb9,
- 0x0bbe, 0x0bc2,
- 0x0bc6, 0x0bc8,
- 0x0bca, 0x0bcd,
- 0x0bd7, 0x0bd7,
- 0x0be7, 0x0bf2,
- 0x0c01, 0x0c03,
- 0x0c05, 0x0c0c,
- 0x0c0e, 0x0c10,
- 0x0c12, 0x0c28,
- 0x0c2a, 0x0c33,
- 0x0c35, 0x0c39,
- 0x0c3e, 0x0c44,
- 0x0c46, 0x0c48,
- 0x0c4a, 0x0c4d,
- 0x0c55, 0x0c56,
- 0x0c60, 0x0c61,
- 0x0c66, 0x0c6f,
- 0x0c82, 0x0c83,
- 0x0c85, 0x0c8c,
- 0x0c8e, 0x0c90,
- 0x0c92, 0x0ca8,
- 0x0caa, 0x0cb3,
- 0x0cb5, 0x0cb9,
- 0x0cbe, 0x0cc4,
- 0x0cc6, 0x0cc8,
- 0x0cca, 0x0ccd,
- 0x0cd5, 0x0cd6,
- 0x0cde, 0x0cde,
- 0x0ce0, 0x0ce1,
- 0x0ce6, 0x0cef,
- 0x0d02, 0x0d03,
- 0x0d05, 0x0d0c,
- 0x0d0e, 0x0d10,
- 0x0d12, 0x0d28,
- 0x0d2a, 0x0d39,
- 0x0d3e, 0x0d43,
- 0x0d46, 0x0d48,
- 0x0d4a, 0x0d4d,
- 0x0d57, 0x0d57,
- 0x0d60, 0x0d61,
- 0x0d66, 0x0d6f,
- 0x0e01, 0x0e3a,
- 0x0e3f, 0x0e5b,
- 0x0e81, 0x0e82,
- 0x0e84, 0x0e84,
- 0x0e87, 0x0e88,
- 0x0e8a, 0x0e8a,
- 0x0e8d, 0x0e8d,
- 0x0e94, 0x0e97,
- 0x0e99, 0x0e9f,
- 0x0ea1, 0x0ea3,
- 0x0ea5, 0x0ea5,
- 0x0ea7, 0x0ea7,
- 0x0eaa, 0x0eab,
- 0x0ead, 0x0eb9,
- 0x0ebb, 0x0ebd,
- 0x0ec0, 0x0ec4,
- 0x0ec6, 0x0ec6,
- 0x0ec8, 0x0ecd,
- 0x0ed0, 0x0ed9,
- 0x0edc, 0x0edd,
- 0x0f00, 0x0f47,
- 0x0f49, 0x0f69,
- 0x0f71, 0x0f8b,
- 0x0f90, 0x0f95,
- 0x0f97, 0x0f97,
- 0x0f99, 0x0fad,
- 0x0fb1, 0x0fb7,
- 0x0fb9, 0x0fb9,
- 0x10a0, 0x10c5,
- 0x10d0, 0x10f6,
- 0x10fb, 0x10fb,
- 0x1100, 0x1159,
- 0x115f, 0x11a2,
- 0x11a8, 0x11f9,
- 0x1e00, 0x1e9b,
- 0x1ea0, 0x1ef9,
- 0x1f00, 0x1f15,
- 0x1f18, 0x1f1d,
- 0x1f20, 0x1f45,
- 0x1f48, 0x1f4d,
- 0x1f50, 0x1f57,
- 0x1f59, 0x1f59,
- 0x1f5b, 0x1f5b,
- 0x1f5d, 0x1f5d,
- 0x1f5f, 0x1f7d,
- 0x1f80, 0x1fb4,
- 0x1fb6, 0x1fc4,
- 0x1fc6, 0x1fd3,
- 0x1fd6, 0x1fdb,
- 0x1fdd, 0x1fef,
- 0x1ff2, 0x1ff4,
- 0x1ff6, 0x1ffe,
- 0x2000, 0x202e,
- 0x2030, 0x2046,
- 0x206a, 0x2070,
- 0x2074, 0x208e,
- 0x20a0, 0x20ac,
- 0x20d0, 0x20e1,
- 0x2100, 0x2138,
- 0x2153, 0x2182,
- 0x2190, 0x21ea,
- 0x2200, 0x22f1,
- 0x2300, 0x2300,
- 0x2302, 0x237a,
- 0x2400, 0x2424,
- 0x2440, 0x244a,
- 0x2460, 0x24ea,
- 0x2500, 0x2595,
- 0x25a0, 0x25ef,
- 0x2600, 0x2613,
- 0x261a, 0x266f,
- 0x2701, 0x2704,
- 0x2706, 0x2709,
- 0x270c, 0x2727,
- 0x2729, 0x274b,
- 0x274d, 0x274d,
- 0x274f, 0x2752,
- 0x2756, 0x2756,
- 0x2758, 0x275e,
- 0x2761, 0x2767,
- 0x2776, 0x2794,
- 0x2798, 0x27af,
- 0x27b1, 0x27be,
- 0x3000, 0x3037,
- 0x303f, 0x303f,
- 0x3041, 0x3094,
- 0x3099, 0x309e,
- 0x30a1, 0x30fe,
- 0x3105, 0x312c,
- 0x3131, 0x318e,
- 0x3190, 0x319f,
- 0x3200, 0x321c,
- 0x3220, 0x3243,
- 0x3260, 0x327b,
- 0x327f, 0x32b0,
- 0x32c0, 0x32cb,
- 0x32d0, 0x32fe,
- 0x3300, 0x3376,
- 0x337b, 0x33dd,
- 0x33e0, 0x33fe,
- 0x4e00, 0x9fa5,
- 0xac00, 0xd7a3,
- 0xd800, 0xfa2d,
- 0xfb00, 0xfb06,
- 0xfb13, 0xfb17,
- 0xfb1e, 0xfb36,
- 0xfb38, 0xfb3c,
- 0xfb3e, 0xfb3e,
- 0xfb40, 0xfb41,
- 0xfb43, 0xfb44,
- 0xfb46, 0xfbb1,
- 0xfbd3, 0xfd3f,
- 0xfd50, 0xfd8f,
- 0xfd92, 0xfdc7,
- 0xfdf0, 0xfdfb,
- 0xfe20, 0xfe23,
- 0xfe30, 0xfe44,
- 0xfe49, 0xfe52,
- 0xfe54, 0xfe66,
- 0xfe68, 0xfe6b,
- 0xfe70, 0xfe72,
- 0xfe74, 0xfe74,
- 0xfe76, 0xfefc,
- 0xfeff, 0xfeff,
- 0xff01, 0xff5e,
- 0xff61, 0xffbe,
- 0xffc2, 0xffc7,
- 0xffca, 0xffcf,
- 0xffd2, 0xffd7,
- 0xffda, 0xffdc,
- 0xffe0, 0xffe6,
- 0xffe8, 0xffee,
- 0xfffc, 0xffff,
- 0x1fffe, 0x1ffff,
- 0x2fffe, 0x2ffff,
- 0x3fffe, 0x3ffff,
- 0x4fffe, 0x4ffff,
- 0x5fffe, 0x5ffff,
- 0x6fffe, 0x6ffff,
- 0x7fffe, 0x7ffff,
- 0x8fffe, 0x8ffff,
- 0x9fffe, 0x9ffff,
- 0xafffe, 0xaffff,
- 0xbfffe, 0xbffff,
- 0xcfffe, 0xcffff,
- 0xdfffe, 0xdffff,
- 0xefffe, 0x10ffff,
-}; /* CR_Age_2_1 */
-
-/* 'Age_3_0': Derived Age 3.0 */
-static const OnigCodePoint CR_Age_3_0[] = {
- 369,
- 0x0000, 0x021f,
- 0x0222, 0x0233,
- 0x0250, 0x02ad,
- 0x02b0, 0x02ee,
- 0x0300, 0x034e,
- 0x0360, 0x0362,
- 0x0374, 0x0375,
- 0x037a, 0x037a,
- 0x037e, 0x037e,
- 0x0384, 0x038a,
- 0x038c, 0x038c,
- 0x038e, 0x03a1,
- 0x03a3, 0x03ce,
- 0x03d0, 0x03d7,
- 0x03da, 0x03f3,
- 0x0400, 0x0486,
- 0x0488, 0x0489,
- 0x048c, 0x04c4,
- 0x04c7, 0x04c8,
- 0x04cb, 0x04cc,
- 0x04d0, 0x04f5,
- 0x04f8, 0x04f9,
- 0x0531, 0x0556,
- 0x0559, 0x055f,
- 0x0561, 0x0587,
- 0x0589, 0x058a,
- 0x0591, 0x05a1,
- 0x05a3, 0x05b9,
- 0x05bb, 0x05c4,
- 0x05d0, 0x05ea,
- 0x05f0, 0x05f4,
- 0x060c, 0x060c,
- 0x061b, 0x061b,
- 0x061f, 0x061f,
- 0x0621, 0x063a,
- 0x0640, 0x0655,
- 0x0660, 0x066d,
- 0x0670, 0x06ed,
- 0x06f0, 0x06fe,
- 0x0700, 0x070d,
- 0x070f, 0x072c,
- 0x0730, 0x074a,
- 0x0780, 0x07b0,
- 0x0901, 0x0903,
- 0x0905, 0x0939,
- 0x093c, 0x094d,
- 0x0950, 0x0954,
- 0x0958, 0x0970,
- 0x0981, 0x0983,
- 0x0985, 0x098c,
- 0x098f, 0x0990,
- 0x0993, 0x09a8,
- 0x09aa, 0x09b0,
- 0x09b2, 0x09b2,
- 0x09b6, 0x09b9,
- 0x09bc, 0x09bc,
- 0x09be, 0x09c4,
- 0x09c7, 0x09c8,
- 0x09cb, 0x09cd,
- 0x09d7, 0x09d7,
- 0x09dc, 0x09dd,
- 0x09df, 0x09e3,
- 0x09e6, 0x09fa,
- 0x0a02, 0x0a02,
- 0x0a05, 0x0a0a,
- 0x0a0f, 0x0a10,
- 0x0a13, 0x0a28,
- 0x0a2a, 0x0a30,
- 0x0a32, 0x0a33,
- 0x0a35, 0x0a36,
- 0x0a38, 0x0a39,
- 0x0a3c, 0x0a3c,
- 0x0a3e, 0x0a42,
- 0x0a47, 0x0a48,
- 0x0a4b, 0x0a4d,
- 0x0a59, 0x0a5c,
- 0x0a5e, 0x0a5e,
- 0x0a66, 0x0a74,
- 0x0a81, 0x0a83,
- 0x0a85, 0x0a8b,
- 0x0a8d, 0x0a8d,
- 0x0a8f, 0x0a91,
- 0x0a93, 0x0aa8,
- 0x0aaa, 0x0ab0,
- 0x0ab2, 0x0ab3,
- 0x0ab5, 0x0ab9,
- 0x0abc, 0x0ac5,
- 0x0ac7, 0x0ac9,
- 0x0acb, 0x0acd,
- 0x0ad0, 0x0ad0,
- 0x0ae0, 0x0ae0,
- 0x0ae6, 0x0aef,
- 0x0b01, 0x0b03,
- 0x0b05, 0x0b0c,
- 0x0b0f, 0x0b10,
- 0x0b13, 0x0b28,
- 0x0b2a, 0x0b30,
- 0x0b32, 0x0b33,
- 0x0b36, 0x0b39,
- 0x0b3c, 0x0b43,
- 0x0b47, 0x0b48,
- 0x0b4b, 0x0b4d,
- 0x0b56, 0x0b57,
- 0x0b5c, 0x0b5d,
- 0x0b5f, 0x0b61,
- 0x0b66, 0x0b70,
- 0x0b82, 0x0b83,
- 0x0b85, 0x0b8a,
- 0x0b8e, 0x0b90,
- 0x0b92, 0x0b95,
- 0x0b99, 0x0b9a,
- 0x0b9c, 0x0b9c,
- 0x0b9e, 0x0b9f,
- 0x0ba3, 0x0ba4,
- 0x0ba8, 0x0baa,
- 0x0bae, 0x0bb5,
- 0x0bb7, 0x0bb9,
- 0x0bbe, 0x0bc2,
- 0x0bc6, 0x0bc8,
- 0x0bca, 0x0bcd,
- 0x0bd7, 0x0bd7,
- 0x0be7, 0x0bf2,
- 0x0c01, 0x0c03,
- 0x0c05, 0x0c0c,
- 0x0c0e, 0x0c10,
- 0x0c12, 0x0c28,
- 0x0c2a, 0x0c33,
- 0x0c35, 0x0c39,
- 0x0c3e, 0x0c44,
- 0x0c46, 0x0c48,
- 0x0c4a, 0x0c4d,
- 0x0c55, 0x0c56,
- 0x0c60, 0x0c61,
- 0x0c66, 0x0c6f,
- 0x0c82, 0x0c83,
- 0x0c85, 0x0c8c,
- 0x0c8e, 0x0c90,
- 0x0c92, 0x0ca8,
- 0x0caa, 0x0cb3,
- 0x0cb5, 0x0cb9,
- 0x0cbe, 0x0cc4,
- 0x0cc6, 0x0cc8,
- 0x0cca, 0x0ccd,
- 0x0cd5, 0x0cd6,
- 0x0cde, 0x0cde,
- 0x0ce0, 0x0ce1,
- 0x0ce6, 0x0cef,
- 0x0d02, 0x0d03,
- 0x0d05, 0x0d0c,
- 0x0d0e, 0x0d10,
- 0x0d12, 0x0d28,
- 0x0d2a, 0x0d39,
- 0x0d3e, 0x0d43,
- 0x0d46, 0x0d48,
- 0x0d4a, 0x0d4d,
- 0x0d57, 0x0d57,
- 0x0d60, 0x0d61,
- 0x0d66, 0x0d6f,
- 0x0d82, 0x0d83,
- 0x0d85, 0x0d96,
- 0x0d9a, 0x0db1,
- 0x0db3, 0x0dbb,
- 0x0dbd, 0x0dbd,
- 0x0dc0, 0x0dc6,
- 0x0dca, 0x0dca,
- 0x0dcf, 0x0dd4,
- 0x0dd6, 0x0dd6,
- 0x0dd8, 0x0ddf,
- 0x0df2, 0x0df4,
- 0x0e01, 0x0e3a,
- 0x0e3f, 0x0e5b,
- 0x0e81, 0x0e82,
- 0x0e84, 0x0e84,
- 0x0e87, 0x0e88,
- 0x0e8a, 0x0e8a,
- 0x0e8d, 0x0e8d,
- 0x0e94, 0x0e97,
- 0x0e99, 0x0e9f,
- 0x0ea1, 0x0ea3,
- 0x0ea5, 0x0ea5,
- 0x0ea7, 0x0ea7,
- 0x0eaa, 0x0eab,
- 0x0ead, 0x0eb9,
- 0x0ebb, 0x0ebd,
- 0x0ec0, 0x0ec4,
- 0x0ec6, 0x0ec6,
- 0x0ec8, 0x0ecd,
- 0x0ed0, 0x0ed9,
- 0x0edc, 0x0edd,
- 0x0f00, 0x0f47,
- 0x0f49, 0x0f6a,
- 0x0f71, 0x0f8b,
- 0x0f90, 0x0f97,
- 0x0f99, 0x0fbc,
- 0x0fbe, 0x0fcc,
- 0x0fcf, 0x0fcf,
- 0x1000, 0x1021,
- 0x1023, 0x1027,
- 0x1029, 0x102a,
- 0x102c, 0x1032,
- 0x1036, 0x1039,
- 0x1040, 0x1059,
- 0x10a0, 0x10c5,
- 0x10d0, 0x10f6,
- 0x10fb, 0x10fb,
- 0x1100, 0x1159,
- 0x115f, 0x11a2,
- 0x11a8, 0x11f9,
- 0x1200, 0x1206,
- 0x1208, 0x1246,
- 0x1248, 0x1248,
- 0x124a, 0x124d,
- 0x1250, 0x1256,
- 0x1258, 0x1258,
- 0x125a, 0x125d,
- 0x1260, 0x1286,
- 0x1288, 0x1288,
- 0x128a, 0x128d,
- 0x1290, 0x12ae,
- 0x12b0, 0x12b0,
- 0x12b2, 0x12b5,
- 0x12b8, 0x12be,
- 0x12c0, 0x12c0,
- 0x12c2, 0x12c5,
- 0x12c8, 0x12ce,
- 0x12d0, 0x12d6,
- 0x12d8, 0x12ee,
- 0x12f0, 0x130e,
- 0x1310, 0x1310,
- 0x1312, 0x1315,
- 0x1318, 0x131e,
- 0x1320, 0x1346,
- 0x1348, 0x135a,
- 0x1361, 0x137c,
- 0x13a0, 0x13f4,
- 0x1401, 0x1676,
- 0x1680, 0x169c,
- 0x16a0, 0x16f0,
- 0x1780, 0x17dc,
- 0x17e0, 0x17e9,
- 0x1800, 0x180e,
- 0x1810, 0x1819,
- 0x1820, 0x1877,
- 0x1880, 0x18a9,
- 0x1e00, 0x1e9b,
- 0x1ea0, 0x1ef9,
- 0x1f00, 0x1f15,
- 0x1f18, 0x1f1d,
- 0x1f20, 0x1f45,
- 0x1f48, 0x1f4d,
- 0x1f50, 0x1f57,
- 0x1f59, 0x1f59,
- 0x1f5b, 0x1f5b,
- 0x1f5d, 0x1f5d,
- 0x1f5f, 0x1f7d,
- 0x1f80, 0x1fb4,
- 0x1fb6, 0x1fc4,
- 0x1fc6, 0x1fd3,
- 0x1fd6, 0x1fdb,
- 0x1fdd, 0x1fef,
- 0x1ff2, 0x1ff4,
- 0x1ff6, 0x1ffe,
- 0x2000, 0x2046,
- 0x2048, 0x204d,
- 0x206a, 0x2070,
- 0x2074, 0x208e,
- 0x20a0, 0x20af,
- 0x20d0, 0x20e3,
- 0x2100, 0x213a,
- 0x2153, 0x2183,
- 0x2190, 0x21f3,
- 0x2200, 0x22f1,
- 0x2300, 0x237b,
- 0x237d, 0x239a,
- 0x2400, 0x2426,
- 0x2440, 0x244a,
- 0x2460, 0x24ea,
- 0x2500, 0x2595,
- 0x25a0, 0x25f7,
- 0x2600, 0x2613,
- 0x2619, 0x2671,
- 0x2701, 0x2704,
- 0x2706, 0x2709,
- 0x270c, 0x2727,
- 0x2729, 0x274b,
- 0x274d, 0x274d,
- 0x274f, 0x2752,
- 0x2756, 0x2756,
- 0x2758, 0x275e,
- 0x2761, 0x2767,
- 0x2776, 0x2794,
- 0x2798, 0x27af,
- 0x27b1, 0x27be,
- 0x2800, 0x28ff,
- 0x2e80, 0x2e99,
- 0x2e9b, 0x2ef3,
- 0x2f00, 0x2fd5,
- 0x2ff0, 0x2ffb,
- 0x3000, 0x303a,
- 0x303e, 0x303f,
- 0x3041, 0x3094,
- 0x3099, 0x309e,
- 0x30a1, 0x30fe,
- 0x3105, 0x312c,
- 0x3131, 0x318e,
- 0x3190, 0x31b7,
- 0x3200, 0x321c,
- 0x3220, 0x3243,
- 0x3260, 0x327b,
- 0x327f, 0x32b0,
- 0x32c0, 0x32cb,
- 0x32d0, 0x32fe,
- 0x3300, 0x3376,
- 0x337b, 0x33dd,
- 0x33e0, 0x33fe,
- 0x3400, 0x4db5,
- 0x4e00, 0x9fa5,
- 0xa000, 0xa48c,
- 0xa490, 0xa4a1,
- 0xa4a4, 0xa4b3,
- 0xa4b5, 0xa4c0,
- 0xa4c2, 0xa4c4,
- 0xa4c6, 0xa4c6,
- 0xac00, 0xd7a3,
- 0xd800, 0xfa2d,
- 0xfb00, 0xfb06,
- 0xfb13, 0xfb17,
- 0xfb1d, 0xfb36,
- 0xfb38, 0xfb3c,
- 0xfb3e, 0xfb3e,
- 0xfb40, 0xfb41,
- 0xfb43, 0xfb44,
- 0xfb46, 0xfbb1,
- 0xfbd3, 0xfd3f,
- 0xfd50, 0xfd8f,
- 0xfd92, 0xfdc7,
- 0xfdf0, 0xfdfb,
- 0xfe20, 0xfe23,
- 0xfe30, 0xfe44,
- 0xfe49, 0xfe52,
- 0xfe54, 0xfe66,
- 0xfe68, 0xfe6b,
- 0xfe70, 0xfe72,
- 0xfe74, 0xfe74,
- 0xfe76, 0xfefc,
- 0xfeff, 0xfeff,
- 0xff01, 0xff5e,
- 0xff61, 0xffbe,
- 0xffc2, 0xffc7,
- 0xffca, 0xffcf,
- 0xffd2, 0xffd7,
- 0xffda, 0xffdc,
- 0xffe0, 0xffe6,
- 0xffe8, 0xffee,
- 0xfff9, 0xffff,
- 0x1fffe, 0x1ffff,
- 0x2fffe, 0x2ffff,
- 0x3fffe, 0x3ffff,
- 0x4fffe, 0x4ffff,
- 0x5fffe, 0x5ffff,
- 0x6fffe, 0x6ffff,
- 0x7fffe, 0x7ffff,
- 0x8fffe, 0x8ffff,
- 0x9fffe, 0x9ffff,
- 0xafffe, 0xaffff,
- 0xbfffe, 0xbffff,
- 0xcfffe, 0xcffff,
- 0xdfffe, 0xdffff,
- 0xefffe, 0x10ffff,
-}; /* CR_Age_3_0 */
-
-/* 'Age_3_1': Derived Age 3.1 */
-static const OnigCodePoint CR_Age_3_1[] = {
- 402,
- 0x0000, 0x021f,
- 0x0222, 0x0233,
- 0x0250, 0x02ad,
- 0x02b0, 0x02ee,
- 0x0300, 0x034e,
- 0x0360, 0x0362,
- 0x0374, 0x0375,
- 0x037a, 0x037a,
- 0x037e, 0x037e,
- 0x0384, 0x038a,
- 0x038c, 0x038c,
- 0x038e, 0x03a1,
- 0x03a3, 0x03ce,
- 0x03d0, 0x03d7,
- 0x03da, 0x03f5,
- 0x0400, 0x0486,
- 0x0488, 0x0489,
- 0x048c, 0x04c4,
- 0x04c7, 0x04c8,
- 0x04cb, 0x04cc,
- 0x04d0, 0x04f5,
- 0x04f8, 0x04f9,
- 0x0531, 0x0556,
- 0x0559, 0x055f,
- 0x0561, 0x0587,
- 0x0589, 0x058a,
- 0x0591, 0x05a1,
- 0x05a3, 0x05b9,
- 0x05bb, 0x05c4,
- 0x05d0, 0x05ea,
- 0x05f0, 0x05f4,
- 0x060c, 0x060c,
- 0x061b, 0x061b,
- 0x061f, 0x061f,
- 0x0621, 0x063a,
- 0x0640, 0x0655,
- 0x0660, 0x066d,
- 0x0670, 0x06ed,
- 0x06f0, 0x06fe,
- 0x0700, 0x070d,
- 0x070f, 0x072c,
- 0x0730, 0x074a,
- 0x0780, 0x07b0,
- 0x0901, 0x0903,
- 0x0905, 0x0939,
- 0x093c, 0x094d,
- 0x0950, 0x0954,
- 0x0958, 0x0970,
- 0x0981, 0x0983,
- 0x0985, 0x098c,
- 0x098f, 0x0990,
- 0x0993, 0x09a8,
- 0x09aa, 0x09b0,
- 0x09b2, 0x09b2,
- 0x09b6, 0x09b9,
- 0x09bc, 0x09bc,
- 0x09be, 0x09c4,
- 0x09c7, 0x09c8,
- 0x09cb, 0x09cd,
- 0x09d7, 0x09d7,
- 0x09dc, 0x09dd,
- 0x09df, 0x09e3,
- 0x09e6, 0x09fa,
- 0x0a02, 0x0a02,
- 0x0a05, 0x0a0a,
- 0x0a0f, 0x0a10,
- 0x0a13, 0x0a28,
- 0x0a2a, 0x0a30,
- 0x0a32, 0x0a33,
- 0x0a35, 0x0a36,
- 0x0a38, 0x0a39,
- 0x0a3c, 0x0a3c,
- 0x0a3e, 0x0a42,
- 0x0a47, 0x0a48,
- 0x0a4b, 0x0a4d,
- 0x0a59, 0x0a5c,
- 0x0a5e, 0x0a5e,
- 0x0a66, 0x0a74,
- 0x0a81, 0x0a83,
- 0x0a85, 0x0a8b,
- 0x0a8d, 0x0a8d,
- 0x0a8f, 0x0a91,
- 0x0a93, 0x0aa8,
- 0x0aaa, 0x0ab0,
- 0x0ab2, 0x0ab3,
- 0x0ab5, 0x0ab9,
- 0x0abc, 0x0ac5,
- 0x0ac7, 0x0ac9,
- 0x0acb, 0x0acd,
- 0x0ad0, 0x0ad0,
- 0x0ae0, 0x0ae0,
- 0x0ae6, 0x0aef,
- 0x0b01, 0x0b03,
- 0x0b05, 0x0b0c,
- 0x0b0f, 0x0b10,
- 0x0b13, 0x0b28,
- 0x0b2a, 0x0b30,
- 0x0b32, 0x0b33,
- 0x0b36, 0x0b39,
- 0x0b3c, 0x0b43,
- 0x0b47, 0x0b48,
- 0x0b4b, 0x0b4d,
- 0x0b56, 0x0b57,
- 0x0b5c, 0x0b5d,
- 0x0b5f, 0x0b61,
- 0x0b66, 0x0b70,
- 0x0b82, 0x0b83,
- 0x0b85, 0x0b8a,
- 0x0b8e, 0x0b90,
- 0x0b92, 0x0b95,
- 0x0b99, 0x0b9a,
- 0x0b9c, 0x0b9c,
- 0x0b9e, 0x0b9f,
- 0x0ba3, 0x0ba4,
- 0x0ba8, 0x0baa,
- 0x0bae, 0x0bb5,
- 0x0bb7, 0x0bb9,
- 0x0bbe, 0x0bc2,
- 0x0bc6, 0x0bc8,
- 0x0bca, 0x0bcd,
- 0x0bd7, 0x0bd7,
- 0x0be7, 0x0bf2,
- 0x0c01, 0x0c03,
- 0x0c05, 0x0c0c,
- 0x0c0e, 0x0c10,
- 0x0c12, 0x0c28,
- 0x0c2a, 0x0c33,
- 0x0c35, 0x0c39,
- 0x0c3e, 0x0c44,
- 0x0c46, 0x0c48,
- 0x0c4a, 0x0c4d,
- 0x0c55, 0x0c56,
- 0x0c60, 0x0c61,
- 0x0c66, 0x0c6f,
- 0x0c82, 0x0c83,
- 0x0c85, 0x0c8c,
- 0x0c8e, 0x0c90,
- 0x0c92, 0x0ca8,
- 0x0caa, 0x0cb3,
- 0x0cb5, 0x0cb9,
- 0x0cbe, 0x0cc4,
- 0x0cc6, 0x0cc8,
- 0x0cca, 0x0ccd,
- 0x0cd5, 0x0cd6,
- 0x0cde, 0x0cde,
- 0x0ce0, 0x0ce1,
- 0x0ce6, 0x0cef,
- 0x0d02, 0x0d03,
- 0x0d05, 0x0d0c,
- 0x0d0e, 0x0d10,
- 0x0d12, 0x0d28,
- 0x0d2a, 0x0d39,
- 0x0d3e, 0x0d43,
- 0x0d46, 0x0d48,
- 0x0d4a, 0x0d4d,
- 0x0d57, 0x0d57,
- 0x0d60, 0x0d61,
- 0x0d66, 0x0d6f,
- 0x0d82, 0x0d83,
- 0x0d85, 0x0d96,
- 0x0d9a, 0x0db1,
- 0x0db3, 0x0dbb,
- 0x0dbd, 0x0dbd,
- 0x0dc0, 0x0dc6,
- 0x0dca, 0x0dca,
- 0x0dcf, 0x0dd4,
- 0x0dd6, 0x0dd6,
- 0x0dd8, 0x0ddf,
- 0x0df2, 0x0df4,
- 0x0e01, 0x0e3a,
- 0x0e3f, 0x0e5b,
- 0x0e81, 0x0e82,
- 0x0e84, 0x0e84,
- 0x0e87, 0x0e88,
- 0x0e8a, 0x0e8a,
- 0x0e8d, 0x0e8d,
- 0x0e94, 0x0e97,
- 0x0e99, 0x0e9f,
- 0x0ea1, 0x0ea3,
- 0x0ea5, 0x0ea5,
- 0x0ea7, 0x0ea7,
- 0x0eaa, 0x0eab,
- 0x0ead, 0x0eb9,
- 0x0ebb, 0x0ebd,
- 0x0ec0, 0x0ec4,
- 0x0ec6, 0x0ec6,
- 0x0ec8, 0x0ecd,
- 0x0ed0, 0x0ed9,
- 0x0edc, 0x0edd,
- 0x0f00, 0x0f47,
- 0x0f49, 0x0f6a,
- 0x0f71, 0x0f8b,
- 0x0f90, 0x0f97,
- 0x0f99, 0x0fbc,
- 0x0fbe, 0x0fcc,
- 0x0fcf, 0x0fcf,
- 0x1000, 0x1021,
- 0x1023, 0x1027,
- 0x1029, 0x102a,
- 0x102c, 0x1032,
- 0x1036, 0x1039,
- 0x1040, 0x1059,
- 0x10a0, 0x10c5,
- 0x10d0, 0x10f6,
- 0x10fb, 0x10fb,
- 0x1100, 0x1159,
- 0x115f, 0x11a2,
- 0x11a8, 0x11f9,
- 0x1200, 0x1206,
- 0x1208, 0x1246,
- 0x1248, 0x1248,
- 0x124a, 0x124d,
- 0x1250, 0x1256,
- 0x1258, 0x1258,
- 0x125a, 0x125d,
- 0x1260, 0x1286,
- 0x1288, 0x1288,
- 0x128a, 0x128d,
- 0x1290, 0x12ae,
- 0x12b0, 0x12b0,
- 0x12b2, 0x12b5,
- 0x12b8, 0x12be,
- 0x12c0, 0x12c0,
- 0x12c2, 0x12c5,
- 0x12c8, 0x12ce,
- 0x12d0, 0x12d6,
- 0x12d8, 0x12ee,
- 0x12f0, 0x130e,
- 0x1310, 0x1310,
- 0x1312, 0x1315,
- 0x1318, 0x131e,
- 0x1320, 0x1346,
- 0x1348, 0x135a,
- 0x1361, 0x137c,
- 0x13a0, 0x13f4,
- 0x1401, 0x1676,
- 0x1680, 0x169c,
- 0x16a0, 0x16f0,
- 0x1780, 0x17dc,
- 0x17e0, 0x17e9,
- 0x1800, 0x180e,
- 0x1810, 0x1819,
- 0x1820, 0x1877,
- 0x1880, 0x18a9,
- 0x1e00, 0x1e9b,
- 0x1ea0, 0x1ef9,
- 0x1f00, 0x1f15,
- 0x1f18, 0x1f1d,
- 0x1f20, 0x1f45,
- 0x1f48, 0x1f4d,
- 0x1f50, 0x1f57,
- 0x1f59, 0x1f59,
- 0x1f5b, 0x1f5b,
- 0x1f5d, 0x1f5d,
- 0x1f5f, 0x1f7d,
- 0x1f80, 0x1fb4,
- 0x1fb6, 0x1fc4,
- 0x1fc6, 0x1fd3,
- 0x1fd6, 0x1fdb,
- 0x1fdd, 0x1fef,
- 0x1ff2, 0x1ff4,
- 0x1ff6, 0x1ffe,
- 0x2000, 0x2046,
- 0x2048, 0x204d,
- 0x206a, 0x2070,
- 0x2074, 0x208e,
- 0x20a0, 0x20af,
- 0x20d0, 0x20e3,
- 0x2100, 0x213a,
- 0x2153, 0x2183,
- 0x2190, 0x21f3,
- 0x2200, 0x22f1,
- 0x2300, 0x237b,
- 0x237d, 0x239a,
- 0x2400, 0x2426,
- 0x2440, 0x244a,
- 0x2460, 0x24ea,
- 0x2500, 0x2595,
- 0x25a0, 0x25f7,
- 0x2600, 0x2613,
- 0x2619, 0x2671,
- 0x2701, 0x2704,
- 0x2706, 0x2709,
- 0x270c, 0x2727,
- 0x2729, 0x274b,
- 0x274d, 0x274d,
- 0x274f, 0x2752,
- 0x2756, 0x2756,
- 0x2758, 0x275e,
- 0x2761, 0x2767,
- 0x2776, 0x2794,
- 0x2798, 0x27af,
- 0x27b1, 0x27be,
- 0x2800, 0x28ff,
- 0x2e80, 0x2e99,
- 0x2e9b, 0x2ef3,
- 0x2f00, 0x2fd5,
- 0x2ff0, 0x2ffb,
- 0x3000, 0x303a,
- 0x303e, 0x303f,
- 0x3041, 0x3094,
- 0x3099, 0x309e,
- 0x30a1, 0x30fe,
- 0x3105, 0x312c,
- 0x3131, 0x318e,
- 0x3190, 0x31b7,
- 0x3200, 0x321c,
- 0x3220, 0x3243,
- 0x3260, 0x327b,
- 0x327f, 0x32b0,
- 0x32c0, 0x32cb,
- 0x32d0, 0x32fe,
- 0x3300, 0x3376,
- 0x337b, 0x33dd,
- 0x33e0, 0x33fe,
- 0x3400, 0x4db5,
- 0x4e00, 0x9fa5,
- 0xa000, 0xa48c,
- 0xa490, 0xa4a1,
- 0xa4a4, 0xa4b3,
- 0xa4b5, 0xa4c0,
- 0xa4c2, 0xa4c4,
- 0xa4c6, 0xa4c6,
- 0xac00, 0xd7a3,
- 0xd800, 0xfa2d,
- 0xfb00, 0xfb06,
- 0xfb13, 0xfb17,
- 0xfb1d, 0xfb36,
- 0xfb38, 0xfb3c,
- 0xfb3e, 0xfb3e,
- 0xfb40, 0xfb41,
- 0xfb43, 0xfb44,
- 0xfb46, 0xfbb1,
- 0xfbd3, 0xfd3f,
- 0xfd50, 0xfd8f,
- 0xfd92, 0xfdc7,
- 0xfdd0, 0xfdfb,
- 0xfe20, 0xfe23,
- 0xfe30, 0xfe44,
- 0xfe49, 0xfe52,
- 0xfe54, 0xfe66,
- 0xfe68, 0xfe6b,
- 0xfe70, 0xfe72,
- 0xfe74, 0xfe74,
- 0xfe76, 0xfefc,
- 0xfeff, 0xfeff,
- 0xff01, 0xff5e,
- 0xff61, 0xffbe,
- 0xffc2, 0xffc7,
- 0xffca, 0xffcf,
- 0xffd2, 0xffd7,
- 0xffda, 0xffdc,
- 0xffe0, 0xffe6,
- 0xffe8, 0xffee,
- 0xfff9, 0xffff,
- 0x10300, 0x1031e,
- 0x10320, 0x10323,
- 0x10330, 0x1034a,
- 0x10400, 0x10425,
- 0x10428, 0x1044d,
- 0x1d000, 0x1d0f5,
- 0x1d100, 0x1d126,
- 0x1d12a, 0x1d1dd,
- 0x1d400, 0x1d454,
- 0x1d456, 0x1d49c,
- 0x1d49e, 0x1d49f,
- 0x1d4a2, 0x1d4a2,
- 0x1d4a5, 0x1d4a6,
- 0x1d4a9, 0x1d4ac,
- 0x1d4ae, 0x1d4b9,
- 0x1d4bb, 0x1d4bb,
- 0x1d4bd, 0x1d4c0,
- 0x1d4c2, 0x1d4c3,
- 0x1d4c5, 0x1d505,
- 0x1d507, 0x1d50a,
- 0x1d50d, 0x1d514,
- 0x1d516, 0x1d51c,
- 0x1d51e, 0x1d539,
- 0x1d53b, 0x1d53e,
- 0x1d540, 0x1d544,
- 0x1d546, 0x1d546,
- 0x1d54a, 0x1d550,
- 0x1d552, 0x1d6a3,
- 0x1d6a8, 0x1d7c9,
- 0x1d7ce, 0x1d7ff,
- 0x1fffe, 0x2a6d6,
- 0x2f800, 0x2fa1d,
- 0x2fffe, 0x2ffff,
- 0x3fffe, 0x3ffff,
- 0x4fffe, 0x4ffff,
- 0x5fffe, 0x5ffff,
- 0x6fffe, 0x6ffff,
- 0x7fffe, 0x7ffff,
- 0x8fffe, 0x8ffff,
- 0x9fffe, 0x9ffff,
- 0xafffe, 0xaffff,
- 0xbfffe, 0xbffff,
- 0xcfffe, 0xcffff,
- 0xdfffe, 0xdffff,
- 0xe0001, 0xe0001,
- 0xe0020, 0xe007f,
- 0xefffe, 0x10ffff,
-}; /* CR_Age_3_1 */
-
-/* 'Age_3_2': Derived Age 3.2 */
-static const OnigCodePoint CR_Age_3_2[] = {
- 397,
- 0x0000, 0x0220,
- 0x0222, 0x0233,
- 0x0250, 0x02ad,
- 0x02b0, 0x02ee,
- 0x0300, 0x034f,
- 0x0360, 0x036f,
- 0x0374, 0x0375,
- 0x037a, 0x037a,
- 0x037e, 0x037e,
- 0x0384, 0x038a,
- 0x038c, 0x038c,
- 0x038e, 0x03a1,
- 0x03a3, 0x03ce,
- 0x03d0, 0x03f6,
- 0x0400, 0x0486,
- 0x0488, 0x04ce,
- 0x04d0, 0x04f5,
- 0x04f8, 0x04f9,
- 0x0500, 0x050f,
- 0x0531, 0x0556,
- 0x0559, 0x055f,
- 0x0561, 0x0587,
- 0x0589, 0x058a,
- 0x0591, 0x05a1,
- 0x05a3, 0x05b9,
- 0x05bb, 0x05c4,
- 0x05d0, 0x05ea,
- 0x05f0, 0x05f4,
- 0x060c, 0x060c,
- 0x061b, 0x061b,
- 0x061f, 0x061f,
- 0x0621, 0x063a,
- 0x0640, 0x0655,
- 0x0660, 0x06ed,
- 0x06f0, 0x06fe,
- 0x0700, 0x070d,
- 0x070f, 0x072c,
- 0x0730, 0x074a,
- 0x0780, 0x07b1,
- 0x0901, 0x0903,
- 0x0905, 0x0939,
- 0x093c, 0x094d,
- 0x0950, 0x0954,
- 0x0958, 0x0970,
- 0x0981, 0x0983,
- 0x0985, 0x098c,
- 0x098f, 0x0990,
- 0x0993, 0x09a8,
- 0x09aa, 0x09b0,
- 0x09b2, 0x09b2,
- 0x09b6, 0x09b9,
- 0x09bc, 0x09bc,
- 0x09be, 0x09c4,
- 0x09c7, 0x09c8,
- 0x09cb, 0x09cd,
- 0x09d7, 0x09d7,
- 0x09dc, 0x09dd,
- 0x09df, 0x09e3,
- 0x09e6, 0x09fa,
- 0x0a02, 0x0a02,
- 0x0a05, 0x0a0a,
- 0x0a0f, 0x0a10,
- 0x0a13, 0x0a28,
- 0x0a2a, 0x0a30,
- 0x0a32, 0x0a33,
- 0x0a35, 0x0a36,
- 0x0a38, 0x0a39,
- 0x0a3c, 0x0a3c,
- 0x0a3e, 0x0a42,
- 0x0a47, 0x0a48,
- 0x0a4b, 0x0a4d,
- 0x0a59, 0x0a5c,
- 0x0a5e, 0x0a5e,
- 0x0a66, 0x0a74,
- 0x0a81, 0x0a83,
- 0x0a85, 0x0a8b,
- 0x0a8d, 0x0a8d,
- 0x0a8f, 0x0a91,
- 0x0a93, 0x0aa8,
- 0x0aaa, 0x0ab0,
- 0x0ab2, 0x0ab3,
- 0x0ab5, 0x0ab9,
- 0x0abc, 0x0ac5,
- 0x0ac7, 0x0ac9,
- 0x0acb, 0x0acd,
- 0x0ad0, 0x0ad0,
- 0x0ae0, 0x0ae0,
- 0x0ae6, 0x0aef,
- 0x0b01, 0x0b03,
- 0x0b05, 0x0b0c,
- 0x0b0f, 0x0b10,
- 0x0b13, 0x0b28,
- 0x0b2a, 0x0b30,
- 0x0b32, 0x0b33,
- 0x0b36, 0x0b39,
- 0x0b3c, 0x0b43,
- 0x0b47, 0x0b48,
- 0x0b4b, 0x0b4d,
- 0x0b56, 0x0b57,
- 0x0b5c, 0x0b5d,
- 0x0b5f, 0x0b61,
- 0x0b66, 0x0b70,
- 0x0b82, 0x0b83,
- 0x0b85, 0x0b8a,
- 0x0b8e, 0x0b90,
- 0x0b92, 0x0b95,
- 0x0b99, 0x0b9a,
- 0x0b9c, 0x0b9c,
- 0x0b9e, 0x0b9f,
- 0x0ba3, 0x0ba4,
- 0x0ba8, 0x0baa,
- 0x0bae, 0x0bb5,
- 0x0bb7, 0x0bb9,
- 0x0bbe, 0x0bc2,
- 0x0bc6, 0x0bc8,
- 0x0bca, 0x0bcd,
- 0x0bd7, 0x0bd7,
- 0x0be7, 0x0bf2,
- 0x0c01, 0x0c03,
- 0x0c05, 0x0c0c,
- 0x0c0e, 0x0c10,
- 0x0c12, 0x0c28,
- 0x0c2a, 0x0c33,
- 0x0c35, 0x0c39,
- 0x0c3e, 0x0c44,
- 0x0c46, 0x0c48,
- 0x0c4a, 0x0c4d,
- 0x0c55, 0x0c56,
- 0x0c60, 0x0c61,
- 0x0c66, 0x0c6f,
- 0x0c82, 0x0c83,
- 0x0c85, 0x0c8c,
- 0x0c8e, 0x0c90,
- 0x0c92, 0x0ca8,
- 0x0caa, 0x0cb3,
- 0x0cb5, 0x0cb9,
- 0x0cbe, 0x0cc4,
- 0x0cc6, 0x0cc8,
- 0x0cca, 0x0ccd,
- 0x0cd5, 0x0cd6,
- 0x0cde, 0x0cde,
- 0x0ce0, 0x0ce1,
- 0x0ce6, 0x0cef,
- 0x0d02, 0x0d03,
- 0x0d05, 0x0d0c,
- 0x0d0e, 0x0d10,
- 0x0d12, 0x0d28,
- 0x0d2a, 0x0d39,
- 0x0d3e, 0x0d43,
- 0x0d46, 0x0d48,
- 0x0d4a, 0x0d4d,
- 0x0d57, 0x0d57,
- 0x0d60, 0x0d61,
- 0x0d66, 0x0d6f,
- 0x0d82, 0x0d83,
- 0x0d85, 0x0d96,
- 0x0d9a, 0x0db1,
- 0x0db3, 0x0dbb,
- 0x0dbd, 0x0dbd,
- 0x0dc0, 0x0dc6,
- 0x0dca, 0x0dca,
- 0x0dcf, 0x0dd4,
- 0x0dd6, 0x0dd6,
- 0x0dd8, 0x0ddf,
- 0x0df2, 0x0df4,
- 0x0e01, 0x0e3a,
- 0x0e3f, 0x0e5b,
- 0x0e81, 0x0e82,
- 0x0e84, 0x0e84,
- 0x0e87, 0x0e88,
- 0x0e8a, 0x0e8a,
- 0x0e8d, 0x0e8d,
- 0x0e94, 0x0e97,
- 0x0e99, 0x0e9f,
- 0x0ea1, 0x0ea3,
- 0x0ea5, 0x0ea5,
- 0x0ea7, 0x0ea7,
- 0x0eaa, 0x0eab,
- 0x0ead, 0x0eb9,
- 0x0ebb, 0x0ebd,
- 0x0ec0, 0x0ec4,
- 0x0ec6, 0x0ec6,
- 0x0ec8, 0x0ecd,
- 0x0ed0, 0x0ed9,
- 0x0edc, 0x0edd,
- 0x0f00, 0x0f47,
- 0x0f49, 0x0f6a,
- 0x0f71, 0x0f8b,
- 0x0f90, 0x0f97,
- 0x0f99, 0x0fbc,
- 0x0fbe, 0x0fcc,
- 0x0fcf, 0x0fcf,
- 0x1000, 0x1021,
- 0x1023, 0x1027,
- 0x1029, 0x102a,
- 0x102c, 0x1032,
- 0x1036, 0x1039,
- 0x1040, 0x1059,
- 0x10a0, 0x10c5,
- 0x10d0, 0x10f8,
- 0x10fb, 0x10fb,
- 0x1100, 0x1159,
- 0x115f, 0x11a2,
- 0x11a8, 0x11f9,
- 0x1200, 0x1206,
- 0x1208, 0x1246,
- 0x1248, 0x1248,
- 0x124a, 0x124d,
- 0x1250, 0x1256,
- 0x1258, 0x1258,
- 0x125a, 0x125d,
- 0x1260, 0x1286,
- 0x1288, 0x1288,
- 0x128a, 0x128d,
- 0x1290, 0x12ae,
- 0x12b0, 0x12b0,
- 0x12b2, 0x12b5,
- 0x12b8, 0x12be,
- 0x12c0, 0x12c0,
- 0x12c2, 0x12c5,
- 0x12c8, 0x12ce,
- 0x12d0, 0x12d6,
- 0x12d8, 0x12ee,
- 0x12f0, 0x130e,
- 0x1310, 0x1310,
- 0x1312, 0x1315,
- 0x1318, 0x131e,
- 0x1320, 0x1346,
- 0x1348, 0x135a,
- 0x1361, 0x137c,
- 0x13a0, 0x13f4,
- 0x1401, 0x1676,
- 0x1680, 0x169c,
- 0x16a0, 0x16f0,
- 0x1700, 0x170c,
- 0x170e, 0x1714,
- 0x1720, 0x1736,
- 0x1740, 0x1753,
- 0x1760, 0x176c,
- 0x176e, 0x1770,
- 0x1772, 0x1773,
- 0x1780, 0x17dc,
- 0x17e0, 0x17e9,
- 0x1800, 0x180e,
- 0x1810, 0x1819,
- 0x1820, 0x1877,
- 0x1880, 0x18a9,
- 0x1e00, 0x1e9b,
- 0x1ea0, 0x1ef9,
- 0x1f00, 0x1f15,
- 0x1f18, 0x1f1d,
- 0x1f20, 0x1f45,
- 0x1f48, 0x1f4d,
- 0x1f50, 0x1f57,
- 0x1f59, 0x1f59,
- 0x1f5b, 0x1f5b,
- 0x1f5d, 0x1f5d,
- 0x1f5f, 0x1f7d,
- 0x1f80, 0x1fb4,
- 0x1fb6, 0x1fc4,
- 0x1fc6, 0x1fd3,
- 0x1fd6, 0x1fdb,
- 0x1fdd, 0x1fef,
- 0x1ff2, 0x1ff4,
- 0x1ff6, 0x1ffe,
- 0x2000, 0x2052,
- 0x2057, 0x2057,
- 0x205f, 0x2063,
- 0x206a, 0x2071,
- 0x2074, 0x208e,
- 0x20a0, 0x20b1,
- 0x20d0, 0x20ea,
- 0x2100, 0x213a,
- 0x213d, 0x214b,
- 0x2153, 0x2183,
- 0x2190, 0x23ce,
- 0x2400, 0x2426,
- 0x2440, 0x244a,
- 0x2460, 0x24fe,
- 0x2500, 0x2613,
- 0x2616, 0x2617,
- 0x2619, 0x267d,
- 0x2680, 0x2689,
- 0x2701, 0x2704,
- 0x2706, 0x2709,
- 0x270c, 0x2727,
- 0x2729, 0x274b,
- 0x274d, 0x274d,
- 0x274f, 0x2752,
- 0x2756, 0x2756,
- 0x2758, 0x275e,
- 0x2761, 0x2794,
- 0x2798, 0x27af,
- 0x27b1, 0x27be,
- 0x27d0, 0x27eb,
- 0x27f0, 0x2aff,
- 0x2e80, 0x2e99,
- 0x2e9b, 0x2ef3,
- 0x2f00, 0x2fd5,
- 0x2ff0, 0x2ffb,
- 0x3000, 0x303f,
- 0x3041, 0x3096,
- 0x3099, 0x30ff,
- 0x3105, 0x312c,
- 0x3131, 0x318e,
- 0x3190, 0x31b7,
- 0x31f0, 0x321c,
- 0x3220, 0x3243,
- 0x3251, 0x327b,
- 0x327f, 0x32cb,
- 0x32d0, 0x32fe,
- 0x3300, 0x3376,
- 0x337b, 0x33dd,
- 0x33e0, 0x33fe,
- 0x3400, 0x4db5,
- 0x4e00, 0x9fa5,
- 0xa000, 0xa48c,
- 0xa490, 0xa4c6,
- 0xac00, 0xd7a3,
- 0xd800, 0xfa2d,
- 0xfa30, 0xfa6a,
- 0xfb00, 0xfb06,
- 0xfb13, 0xfb17,
- 0xfb1d, 0xfb36,
- 0xfb38, 0xfb3c,
- 0xfb3e, 0xfb3e,
- 0xfb40, 0xfb41,
- 0xfb43, 0xfb44,
- 0xfb46, 0xfbb1,
- 0xfbd3, 0xfd3f,
- 0xfd50, 0xfd8f,
- 0xfd92, 0xfdc7,
- 0xfdd0, 0xfdfc,
- 0xfe00, 0xfe0f,
- 0xfe20, 0xfe23,
- 0xfe30, 0xfe46,
- 0xfe49, 0xfe52,
- 0xfe54, 0xfe66,
- 0xfe68, 0xfe6b,
- 0xfe70, 0xfe74,
- 0xfe76, 0xfefc,
- 0xfeff, 0xfeff,
- 0xff01, 0xffbe,
- 0xffc2, 0xffc7,
- 0xffca, 0xffcf,
- 0xffd2, 0xffd7,
- 0xffda, 0xffdc,
- 0xffe0, 0xffe6,
- 0xffe8, 0xffee,
- 0xfff9, 0xffff,
- 0x10300, 0x1031e,
- 0x10320, 0x10323,
- 0x10330, 0x1034a,
- 0x10400, 0x10425,
- 0x10428, 0x1044d,
- 0x1d000, 0x1d0f5,
- 0x1d100, 0x1d126,
- 0x1d12a, 0x1d1dd,
- 0x1d400, 0x1d454,
- 0x1d456, 0x1d49c,
- 0x1d49e, 0x1d49f,
- 0x1d4a2, 0x1d4a2,
- 0x1d4a5, 0x1d4a6,
- 0x1d4a9, 0x1d4ac,
- 0x1d4ae, 0x1d4b9,
- 0x1d4bb, 0x1d4bb,
- 0x1d4bd, 0x1d4c0,
- 0x1d4c2, 0x1d4c3,
- 0x1d4c5, 0x1d505,
- 0x1d507, 0x1d50a,
- 0x1d50d, 0x1d514,
- 0x1d516, 0x1d51c,
- 0x1d51e, 0x1d539,
- 0x1d53b, 0x1d53e,
- 0x1d540, 0x1d544,
- 0x1d546, 0x1d546,
- 0x1d54a, 0x1d550,
- 0x1d552, 0x1d6a3,
- 0x1d6a8, 0x1d7c9,
- 0x1d7ce, 0x1d7ff,
- 0x1fffe, 0x2a6d6,
- 0x2f800, 0x2fa1d,
- 0x2fffe, 0x2ffff,
- 0x3fffe, 0x3ffff,
- 0x4fffe, 0x4ffff,
- 0x5fffe, 0x5ffff,
- 0x6fffe, 0x6ffff,
- 0x7fffe, 0x7ffff,
- 0x8fffe, 0x8ffff,
- 0x9fffe, 0x9ffff,
- 0xafffe, 0xaffff,
- 0xbfffe, 0xbffff,
- 0xcfffe, 0xcffff,
- 0xdfffe, 0xdffff,
- 0xe0001, 0xe0001,
- 0xe0020, 0xe007f,
- 0xefffe, 0x10ffff,
-}; /* CR_Age_3_2 */
-
-/* 'Age_4_0': Derived Age 4.0 */
-static const OnigCodePoint CR_Age_4_0[] = {
- 412,
- 0x0000, 0x0236,
- 0x0250, 0x0357,
- 0x035d, 0x036f,
- 0x0374, 0x0375,
- 0x037a, 0x037a,
- 0x037e, 0x037e,
- 0x0384, 0x038a,
- 0x038c, 0x038c,
- 0x038e, 0x03a1,
- 0x03a3, 0x03ce,
- 0x03d0, 0x03fb,
- 0x0400, 0x0486,
- 0x0488, 0x04ce,
- 0x04d0, 0x04f5,
- 0x04f8, 0x04f9,
- 0x0500, 0x050f,
- 0x0531, 0x0556,
- 0x0559, 0x055f,
- 0x0561, 0x0587,
- 0x0589, 0x058a,
- 0x0591, 0x05a1,
- 0x05a3, 0x05b9,
- 0x05bb, 0x05c4,
- 0x05d0, 0x05ea,
- 0x05f0, 0x05f4,
- 0x0600, 0x0603,
- 0x060c, 0x0615,
- 0x061b, 0x061b,
- 0x061f, 0x061f,
- 0x0621, 0x063a,
- 0x0640, 0x0658,
- 0x0660, 0x070d,
- 0x070f, 0x074a,
- 0x074d, 0x074f,
- 0x0780, 0x07b1,
- 0x0901, 0x0939,
- 0x093c, 0x094d,
- 0x0950, 0x0954,
- 0x0958, 0x0970,
- 0x0981, 0x0983,
- 0x0985, 0x098c,
- 0x098f, 0x0990,
- 0x0993, 0x09a8,
- 0x09aa, 0x09b0,
- 0x09b2, 0x09b2,
- 0x09b6, 0x09b9,
- 0x09bc, 0x09c4,
- 0x09c7, 0x09c8,
- 0x09cb, 0x09cd,
- 0x09d7, 0x09d7,
- 0x09dc, 0x09dd,
- 0x09df, 0x09e3,
- 0x09e6, 0x09fa,
- 0x0a01, 0x0a03,
- 0x0a05, 0x0a0a,
- 0x0a0f, 0x0a10,
- 0x0a13, 0x0a28,
- 0x0a2a, 0x0a30,
- 0x0a32, 0x0a33,
- 0x0a35, 0x0a36,
- 0x0a38, 0x0a39,
- 0x0a3c, 0x0a3c,
- 0x0a3e, 0x0a42,
- 0x0a47, 0x0a48,
- 0x0a4b, 0x0a4d,
- 0x0a59, 0x0a5c,
- 0x0a5e, 0x0a5e,
- 0x0a66, 0x0a74,
- 0x0a81, 0x0a83,
- 0x0a85, 0x0a8d,
- 0x0a8f, 0x0a91,
- 0x0a93, 0x0aa8,
- 0x0aaa, 0x0ab0,
- 0x0ab2, 0x0ab3,
- 0x0ab5, 0x0ab9,
- 0x0abc, 0x0ac5,
- 0x0ac7, 0x0ac9,
- 0x0acb, 0x0acd,
- 0x0ad0, 0x0ad0,
- 0x0ae0, 0x0ae3,
- 0x0ae6, 0x0aef,
- 0x0af1, 0x0af1,
- 0x0b01, 0x0b03,
- 0x0b05, 0x0b0c,
- 0x0b0f, 0x0b10,
- 0x0b13, 0x0b28,
- 0x0b2a, 0x0b30,
- 0x0b32, 0x0b33,
- 0x0b35, 0x0b39,
- 0x0b3c, 0x0b43,
- 0x0b47, 0x0b48,
- 0x0b4b, 0x0b4d,
- 0x0b56, 0x0b57,
- 0x0b5c, 0x0b5d,
- 0x0b5f, 0x0b61,
- 0x0b66, 0x0b71,
- 0x0b82, 0x0b83,
- 0x0b85, 0x0b8a,
- 0x0b8e, 0x0b90,
- 0x0b92, 0x0b95,
- 0x0b99, 0x0b9a,
- 0x0b9c, 0x0b9c,
- 0x0b9e, 0x0b9f,
- 0x0ba3, 0x0ba4,
- 0x0ba8, 0x0baa,
- 0x0bae, 0x0bb5,
- 0x0bb7, 0x0bb9,
- 0x0bbe, 0x0bc2,
- 0x0bc6, 0x0bc8,
- 0x0bca, 0x0bcd,
- 0x0bd7, 0x0bd7,
- 0x0be7, 0x0bfa,
- 0x0c01, 0x0c03,
- 0x0c05, 0x0c0c,
- 0x0c0e, 0x0c10,
- 0x0c12, 0x0c28,
- 0x0c2a, 0x0c33,
- 0x0c35, 0x0c39,
- 0x0c3e, 0x0c44,
- 0x0c46, 0x0c48,
- 0x0c4a, 0x0c4d,
- 0x0c55, 0x0c56,
- 0x0c60, 0x0c61,
- 0x0c66, 0x0c6f,
- 0x0c82, 0x0c83,
- 0x0c85, 0x0c8c,
- 0x0c8e, 0x0c90,
- 0x0c92, 0x0ca8,
- 0x0caa, 0x0cb3,
- 0x0cb5, 0x0cb9,
- 0x0cbc, 0x0cc4,
- 0x0cc6, 0x0cc8,
- 0x0cca, 0x0ccd,
- 0x0cd5, 0x0cd6,
- 0x0cde, 0x0cde,
- 0x0ce0, 0x0ce1,
- 0x0ce6, 0x0cef,
- 0x0d02, 0x0d03,
- 0x0d05, 0x0d0c,
- 0x0d0e, 0x0d10,
- 0x0d12, 0x0d28,
- 0x0d2a, 0x0d39,
- 0x0d3e, 0x0d43,
- 0x0d46, 0x0d48,
- 0x0d4a, 0x0d4d,
- 0x0d57, 0x0d57,
- 0x0d60, 0x0d61,
- 0x0d66, 0x0d6f,
- 0x0d82, 0x0d83,
- 0x0d85, 0x0d96,
- 0x0d9a, 0x0db1,
- 0x0db3, 0x0dbb,
- 0x0dbd, 0x0dbd,
- 0x0dc0, 0x0dc6,
- 0x0dca, 0x0dca,
- 0x0dcf, 0x0dd4,
- 0x0dd6, 0x0dd6,
- 0x0dd8, 0x0ddf,
- 0x0df2, 0x0df4,
- 0x0e01, 0x0e3a,
- 0x0e3f, 0x0e5b,
- 0x0e81, 0x0e82,
- 0x0e84, 0x0e84,
- 0x0e87, 0x0e88,
- 0x0e8a, 0x0e8a,
- 0x0e8d, 0x0e8d,
- 0x0e94, 0x0e97,
- 0x0e99, 0x0e9f,
- 0x0ea1, 0x0ea3,
- 0x0ea5, 0x0ea5,
- 0x0ea7, 0x0ea7,
- 0x0eaa, 0x0eab,
- 0x0ead, 0x0eb9,
- 0x0ebb, 0x0ebd,
- 0x0ec0, 0x0ec4,
- 0x0ec6, 0x0ec6,
- 0x0ec8, 0x0ecd,
- 0x0ed0, 0x0ed9,
- 0x0edc, 0x0edd,
- 0x0f00, 0x0f47,
- 0x0f49, 0x0f6a,
- 0x0f71, 0x0f8b,
- 0x0f90, 0x0f97,
- 0x0f99, 0x0fbc,
- 0x0fbe, 0x0fcc,
- 0x0fcf, 0x0fcf,
- 0x1000, 0x1021,
- 0x1023, 0x1027,
- 0x1029, 0x102a,
- 0x102c, 0x1032,
- 0x1036, 0x1039,
- 0x1040, 0x1059,
- 0x10a0, 0x10c5,
- 0x10d0, 0x10f8,
- 0x10fb, 0x10fb,
- 0x1100, 0x1159,
- 0x115f, 0x11a2,
- 0x11a8, 0x11f9,
- 0x1200, 0x1206,
- 0x1208, 0x1246,
- 0x1248, 0x1248,
- 0x124a, 0x124d,
- 0x1250, 0x1256,
- 0x1258, 0x1258,
- 0x125a, 0x125d,
- 0x1260, 0x1286,
- 0x1288, 0x1288,
- 0x128a, 0x128d,
- 0x1290, 0x12ae,
- 0x12b0, 0x12b0,
- 0x12b2, 0x12b5,
- 0x12b8, 0x12be,
- 0x12c0, 0x12c0,
- 0x12c2, 0x12c5,
- 0x12c8, 0x12ce,
- 0x12d0, 0x12d6,
- 0x12d8, 0x12ee,
- 0x12f0, 0x130e,
- 0x1310, 0x1310,
- 0x1312, 0x1315,
- 0x1318, 0x131e,
- 0x1320, 0x1346,
- 0x1348, 0x135a,
- 0x1361, 0x137c,
- 0x13a0, 0x13f4,
- 0x1401, 0x1676,
- 0x1680, 0x169c,
- 0x16a0, 0x16f0,
- 0x1700, 0x170c,
- 0x170e, 0x1714,
- 0x1720, 0x1736,
- 0x1740, 0x1753,
- 0x1760, 0x176c,
- 0x176e, 0x1770,
- 0x1772, 0x1773,
- 0x1780, 0x17dd,
- 0x17e0, 0x17e9,
- 0x17f0, 0x17f9,
- 0x1800, 0x180e,
- 0x1810, 0x1819,
- 0x1820, 0x1877,
- 0x1880, 0x18a9,
- 0x1900, 0x191c,
- 0x1920, 0x192b,
- 0x1930, 0x193b,
- 0x1940, 0x1940,
- 0x1944, 0x196d,
- 0x1970, 0x1974,
- 0x19e0, 0x19ff,
- 0x1d00, 0x1d6b,
- 0x1e00, 0x1e9b,
- 0x1ea0, 0x1ef9,
- 0x1f00, 0x1f15,
- 0x1f18, 0x1f1d,
- 0x1f20, 0x1f45,
- 0x1f48, 0x1f4d,
- 0x1f50, 0x1f57,
- 0x1f59, 0x1f59,
- 0x1f5b, 0x1f5b,
- 0x1f5d, 0x1f5d,
- 0x1f5f, 0x1f7d,
- 0x1f80, 0x1fb4,
- 0x1fb6, 0x1fc4,
- 0x1fc6, 0x1fd3,
- 0x1fd6, 0x1fdb,
- 0x1fdd, 0x1fef,
- 0x1ff2, 0x1ff4,
- 0x1ff6, 0x1ffe,
- 0x2000, 0x2054,
- 0x2057, 0x2057,
- 0x205f, 0x2063,
- 0x206a, 0x2071,
- 0x2074, 0x208e,
- 0x20a0, 0x20b1,
- 0x20d0, 0x20ea,
- 0x2100, 0x213b,
- 0x213d, 0x214b,
- 0x2153, 0x2183,
- 0x2190, 0x23d0,
- 0x2400, 0x2426,
- 0x2440, 0x244a,
- 0x2460, 0x2617,
- 0x2619, 0x267d,
- 0x2680, 0x2691,
- 0x26a0, 0x26a1,
- 0x2701, 0x2704,
- 0x2706, 0x2709,
- 0x270c, 0x2727,
- 0x2729, 0x274b,
- 0x274d, 0x274d,
- 0x274f, 0x2752,
- 0x2756, 0x2756,
- 0x2758, 0x275e,
- 0x2761, 0x2794,
- 0x2798, 0x27af,
- 0x27b1, 0x27be,
- 0x27d0, 0x27eb,
- 0x27f0, 0x2b0d,
- 0x2e80, 0x2e99,
- 0x2e9b, 0x2ef3,
- 0x2f00, 0x2fd5,
- 0x2ff0, 0x2ffb,
- 0x3000, 0x303f,
- 0x3041, 0x3096,
- 0x3099, 0x30ff,
- 0x3105, 0x312c,
- 0x3131, 0x318e,
- 0x3190, 0x31b7,
- 0x31f0, 0x321e,
- 0x3220, 0x3243,
- 0x3250, 0x327d,
- 0x327f, 0x32fe,
- 0x3300, 0x4db5,
- 0x4dc0, 0x9fa5,
- 0xa000, 0xa48c,
- 0xa490, 0xa4c6,
- 0xac00, 0xd7a3,
- 0xd800, 0xfa2d,
- 0xfa30, 0xfa6a,
- 0xfb00, 0xfb06,
- 0xfb13, 0xfb17,
- 0xfb1d, 0xfb36,
- 0xfb38, 0xfb3c,
- 0xfb3e, 0xfb3e,
- 0xfb40, 0xfb41,
- 0xfb43, 0xfb44,
- 0xfb46, 0xfbb1,
- 0xfbd3, 0xfd3f,
- 0xfd50, 0xfd8f,
- 0xfd92, 0xfdc7,
- 0xfdd0, 0xfdfd,
- 0xfe00, 0xfe0f,
- 0xfe20, 0xfe23,
- 0xfe30, 0xfe52,
- 0xfe54, 0xfe66,
- 0xfe68, 0xfe6b,
- 0xfe70, 0xfe74,
- 0xfe76, 0xfefc,
- 0xfeff, 0xfeff,
- 0xff01, 0xffbe,
- 0xffc2, 0xffc7,
- 0xffca, 0xffcf,
- 0xffd2, 0xffd7,
- 0xffda, 0xffdc,
- 0xffe0, 0xffe6,
- 0xffe8, 0xffee,
- 0xfff9, 0x1000b,
- 0x1000d, 0x10026,
- 0x10028, 0x1003a,
- 0x1003c, 0x1003d,
- 0x1003f, 0x1004d,
- 0x10050, 0x1005d,
- 0x10080, 0x100fa,
- 0x10100, 0x10102,
- 0x10107, 0x10133,
- 0x10137, 0x1013f,
- 0x10300, 0x1031e,
- 0x10320, 0x10323,
- 0x10330, 0x1034a,
- 0x10380, 0x1039d,
- 0x1039f, 0x1039f,
- 0x10400, 0x1049d,
- 0x104a0, 0x104a9,
- 0x10800, 0x10805,
- 0x10808, 0x10808,
- 0x1080a, 0x10835,
- 0x10837, 0x10838,
- 0x1083c, 0x1083c,
- 0x1083f, 0x1083f,
- 0x1d000, 0x1d0f5,
- 0x1d100, 0x1d126,
- 0x1d12a, 0x1d1dd,
- 0x1d300, 0x1d356,
- 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, 0x1d6a3,
- 0x1d6a8, 0x1d7c9,
- 0x1d7ce, 0x1d7ff,
- 0x1fffe, 0x2a6d6,
- 0x2f800, 0x2fa1d,
- 0x2fffe, 0x2ffff,
- 0x3fffe, 0x3ffff,
- 0x4fffe, 0x4ffff,
- 0x5fffe, 0x5ffff,
- 0x6fffe, 0x6ffff,
- 0x7fffe, 0x7ffff,
- 0x8fffe, 0x8ffff,
- 0x9fffe, 0x9ffff,
- 0xafffe, 0xaffff,
- 0xbfffe, 0xbffff,
- 0xcfffe, 0xcffff,
- 0xdfffe, 0xdffff,
- 0xe0001, 0xe0001,
- 0xe0020, 0xe007f,
- 0xe0100, 0xe01ef,
- 0xefffe, 0x10ffff,
-}; /* CR_Age_4_0 */
-
-/* 'Age_4_1': Derived Age 4.1 */
-static const OnigCodePoint CR_Age_4_1[] = {
- 430,
- 0x0000, 0x0241,
- 0x0250, 0x036f,
- 0x0374, 0x0375,
- 0x037a, 0x037a,
- 0x037e, 0x037e,
- 0x0384, 0x038a,
- 0x038c, 0x038c,
- 0x038e, 0x03a1,
- 0x03a3, 0x03ce,
- 0x03d0, 0x0486,
- 0x0488, 0x04ce,
- 0x04d0, 0x04f9,
- 0x0500, 0x050f,
- 0x0531, 0x0556,
- 0x0559, 0x055f,
- 0x0561, 0x0587,
- 0x0589, 0x058a,
- 0x0591, 0x05b9,
- 0x05bb, 0x05c7,
- 0x05d0, 0x05ea,
- 0x05f0, 0x05f4,
- 0x0600, 0x0603,
- 0x060b, 0x0615,
- 0x061b, 0x061b,
- 0x061e, 0x061f,
- 0x0621, 0x063a,
- 0x0640, 0x065e,
- 0x0660, 0x070d,
- 0x070f, 0x074a,
- 0x074d, 0x076d,
- 0x0780, 0x07b1,
- 0x0901, 0x0939,
- 0x093c, 0x094d,
- 0x0950, 0x0954,
- 0x0958, 0x0970,
- 0x097d, 0x097d,
- 0x0981, 0x0983,
- 0x0985, 0x098c,
- 0x098f, 0x0990,
- 0x0993, 0x09a8,
- 0x09aa, 0x09b0,
- 0x09b2, 0x09b2,
- 0x09b6, 0x09b9,
- 0x09bc, 0x09c4,
- 0x09c7, 0x09c8,
- 0x09cb, 0x09ce,
- 0x09d7, 0x09d7,
- 0x09dc, 0x09dd,
- 0x09df, 0x09e3,
- 0x09e6, 0x09fa,
- 0x0a01, 0x0a03,
- 0x0a05, 0x0a0a,
- 0x0a0f, 0x0a10,
- 0x0a13, 0x0a28,
- 0x0a2a, 0x0a30,
- 0x0a32, 0x0a33,
- 0x0a35, 0x0a36,
- 0x0a38, 0x0a39,
- 0x0a3c, 0x0a3c,
- 0x0a3e, 0x0a42,
- 0x0a47, 0x0a48,
- 0x0a4b, 0x0a4d,
- 0x0a59, 0x0a5c,
- 0x0a5e, 0x0a5e,
- 0x0a66, 0x0a74,
- 0x0a81, 0x0a83,
- 0x0a85, 0x0a8d,
- 0x0a8f, 0x0a91,
- 0x0a93, 0x0aa8,
- 0x0aaa, 0x0ab0,
- 0x0ab2, 0x0ab3,
- 0x0ab5, 0x0ab9,
- 0x0abc, 0x0ac5,
- 0x0ac7, 0x0ac9,
- 0x0acb, 0x0acd,
- 0x0ad0, 0x0ad0,
- 0x0ae0, 0x0ae3,
- 0x0ae6, 0x0aef,
- 0x0af1, 0x0af1,
- 0x0b01, 0x0b03,
- 0x0b05, 0x0b0c,
- 0x0b0f, 0x0b10,
- 0x0b13, 0x0b28,
- 0x0b2a, 0x0b30,
- 0x0b32, 0x0b33,
- 0x0b35, 0x0b39,
- 0x0b3c, 0x0b43,
- 0x0b47, 0x0b48,
- 0x0b4b, 0x0b4d,
- 0x0b56, 0x0b57,
- 0x0b5c, 0x0b5d,
- 0x0b5f, 0x0b61,
- 0x0b66, 0x0b71,
- 0x0b82, 0x0b83,
- 0x0b85, 0x0b8a,
- 0x0b8e, 0x0b90,
- 0x0b92, 0x0b95,
- 0x0b99, 0x0b9a,
- 0x0b9c, 0x0b9c,
- 0x0b9e, 0x0b9f,
- 0x0ba3, 0x0ba4,
- 0x0ba8, 0x0baa,
- 0x0bae, 0x0bb9,
- 0x0bbe, 0x0bc2,
- 0x0bc6, 0x0bc8,
- 0x0bca, 0x0bcd,
- 0x0bd7, 0x0bd7,
- 0x0be6, 0x0bfa,
- 0x0c01, 0x0c03,
- 0x0c05, 0x0c0c,
- 0x0c0e, 0x0c10,
- 0x0c12, 0x0c28,
- 0x0c2a, 0x0c33,
- 0x0c35, 0x0c39,
- 0x0c3e, 0x0c44,
- 0x0c46, 0x0c48,
- 0x0c4a, 0x0c4d,
- 0x0c55, 0x0c56,
- 0x0c60, 0x0c61,
- 0x0c66, 0x0c6f,
- 0x0c82, 0x0c83,
- 0x0c85, 0x0c8c,
- 0x0c8e, 0x0c90,
- 0x0c92, 0x0ca8,
- 0x0caa, 0x0cb3,
- 0x0cb5, 0x0cb9,
- 0x0cbc, 0x0cc4,
- 0x0cc6, 0x0cc8,
- 0x0cca, 0x0ccd,
- 0x0cd5, 0x0cd6,
- 0x0cde, 0x0cde,
- 0x0ce0, 0x0ce1,
- 0x0ce6, 0x0cef,
- 0x0d02, 0x0d03,
- 0x0d05, 0x0d0c,
- 0x0d0e, 0x0d10,
- 0x0d12, 0x0d28,
- 0x0d2a, 0x0d39,
- 0x0d3e, 0x0d43,
- 0x0d46, 0x0d48,
- 0x0d4a, 0x0d4d,
- 0x0d57, 0x0d57,
- 0x0d60, 0x0d61,
- 0x0d66, 0x0d6f,
- 0x0d82, 0x0d83,
- 0x0d85, 0x0d96,
- 0x0d9a, 0x0db1,
- 0x0db3, 0x0dbb,
- 0x0dbd, 0x0dbd,
- 0x0dc0, 0x0dc6,
- 0x0dca, 0x0dca,
- 0x0dcf, 0x0dd4,
- 0x0dd6, 0x0dd6,
- 0x0dd8, 0x0ddf,
- 0x0df2, 0x0df4,
- 0x0e01, 0x0e3a,
- 0x0e3f, 0x0e5b,
- 0x0e81, 0x0e82,
- 0x0e84, 0x0e84,
- 0x0e87, 0x0e88,
- 0x0e8a, 0x0e8a,
- 0x0e8d, 0x0e8d,
- 0x0e94, 0x0e97,
- 0x0e99, 0x0e9f,
- 0x0ea1, 0x0ea3,
- 0x0ea5, 0x0ea5,
- 0x0ea7, 0x0ea7,
- 0x0eaa, 0x0eab,
- 0x0ead, 0x0eb9,
- 0x0ebb, 0x0ebd,
- 0x0ec0, 0x0ec4,
- 0x0ec6, 0x0ec6,
- 0x0ec8, 0x0ecd,
- 0x0ed0, 0x0ed9,
- 0x0edc, 0x0edd,
- 0x0f00, 0x0f47,
- 0x0f49, 0x0f6a,
- 0x0f71, 0x0f8b,
- 0x0f90, 0x0f97,
- 0x0f99, 0x0fbc,
- 0x0fbe, 0x0fcc,
- 0x0fcf, 0x0fd1,
- 0x1000, 0x1021,
- 0x1023, 0x1027,
- 0x1029, 0x102a,
- 0x102c, 0x1032,
- 0x1036, 0x1039,
- 0x1040, 0x1059,
- 0x10a0, 0x10c5,
- 0x10d0, 0x10fc,
- 0x1100, 0x1159,
- 0x115f, 0x11a2,
- 0x11a8, 0x11f9,
- 0x1200, 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,
- 0x135f, 0x137c,
- 0x1380, 0x1399,
- 0x13a0, 0x13f4,
- 0x1401, 0x1676,
- 0x1680, 0x169c,
- 0x16a0, 0x16f0,
- 0x1700, 0x170c,
- 0x170e, 0x1714,
- 0x1720, 0x1736,
- 0x1740, 0x1753,
- 0x1760, 0x176c,
- 0x176e, 0x1770,
- 0x1772, 0x1773,
- 0x1780, 0x17dd,
- 0x17e0, 0x17e9,
- 0x17f0, 0x17f9,
- 0x1800, 0x180e,
- 0x1810, 0x1819,
- 0x1820, 0x1877,
- 0x1880, 0x18a9,
- 0x1900, 0x191c,
- 0x1920, 0x192b,
- 0x1930, 0x193b,
- 0x1940, 0x1940,
- 0x1944, 0x196d,
- 0x1970, 0x1974,
- 0x1980, 0x19a9,
- 0x19b0, 0x19c9,
- 0x19d0, 0x19d9,
- 0x19de, 0x1a1b,
- 0x1a1e, 0x1a1f,
- 0x1d00, 0x1dc3,
- 0x1e00, 0x1e9b,
- 0x1ea0, 0x1ef9,
- 0x1f00, 0x1f15,
- 0x1f18, 0x1f1d,
- 0x1f20, 0x1f45,
- 0x1f48, 0x1f4d,
- 0x1f50, 0x1f57,
- 0x1f59, 0x1f59,
- 0x1f5b, 0x1f5b,
- 0x1f5d, 0x1f5d,
- 0x1f5f, 0x1f7d,
- 0x1f80, 0x1fb4,
- 0x1fb6, 0x1fc4,
- 0x1fc6, 0x1fd3,
- 0x1fd6, 0x1fdb,
- 0x1fdd, 0x1fef,
- 0x1ff2, 0x1ff4,
- 0x1ff6, 0x1ffe,
- 0x2000, 0x2063,
- 0x206a, 0x2071,
- 0x2074, 0x208e,
- 0x2090, 0x2094,
- 0x20a0, 0x20b5,
- 0x20d0, 0x20eb,
- 0x2100, 0x214c,
- 0x2153, 0x2183,
- 0x2190, 0x23db,
- 0x2400, 0x2426,
- 0x2440, 0x244a,
- 0x2460, 0x269c,
- 0x26a0, 0x26b1,
- 0x2701, 0x2704,
- 0x2706, 0x2709,
- 0x270c, 0x2727,
- 0x2729, 0x274b,
- 0x274d, 0x274d,
- 0x274f, 0x2752,
- 0x2756, 0x2756,
- 0x2758, 0x275e,
- 0x2761, 0x2794,
- 0x2798, 0x27af,
- 0x27b1, 0x27be,
- 0x27c0, 0x27c6,
- 0x27d0, 0x27eb,
- 0x27f0, 0x2b13,
- 0x2c00, 0x2c2e,
- 0x2c30, 0x2c5e,
- 0x2c80, 0x2cea,
- 0x2cf9, 0x2d25,
- 0x2d30, 0x2d65,
- 0x2d6f, 0x2d6f,
- 0x2d80, 0x2d96,
- 0x2da0, 0x2da6,
- 0x2da8, 0x2dae,
- 0x2db0, 0x2db6,
- 0x2db8, 0x2dbe,
- 0x2dc0, 0x2dc6,
- 0x2dc8, 0x2dce,
- 0x2dd0, 0x2dd6,
- 0x2dd8, 0x2dde,
- 0x2e00, 0x2e17,
- 0x2e1c, 0x2e1d,
- 0x2e80, 0x2e99,
- 0x2e9b, 0x2ef3,
- 0x2f00, 0x2fd5,
- 0x2ff0, 0x2ffb,
- 0x3000, 0x303f,
- 0x3041, 0x3096,
- 0x3099, 0x30ff,
- 0x3105, 0x312c,
- 0x3131, 0x318e,
- 0x3190, 0x31b7,
- 0x31c0, 0x31cf,
- 0x31f0, 0x321e,
- 0x3220, 0x3243,
- 0x3250, 0x32fe,
- 0x3300, 0x4db5,
- 0x4dc0, 0x9fbb,
- 0xa000, 0xa48c,
- 0xa490, 0xa4c6,
- 0xa700, 0xa716,
- 0xa800, 0xa82b,
- 0xac00, 0xd7a3,
- 0xd800, 0xfa2d,
- 0xfa30, 0xfa6a,
- 0xfa70, 0xfad9,
- 0xfb00, 0xfb06,
- 0xfb13, 0xfb17,
- 0xfb1d, 0xfb36,
- 0xfb38, 0xfb3c,
- 0xfb3e, 0xfb3e,
- 0xfb40, 0xfb41,
- 0xfb43, 0xfb44,
- 0xfb46, 0xfbb1,
- 0xfbd3, 0xfd3f,
- 0xfd50, 0xfd8f,
- 0xfd92, 0xfdc7,
- 0xfdd0, 0xfdfd,
- 0xfe00, 0xfe19,
- 0xfe20, 0xfe23,
- 0xfe30, 0xfe52,
- 0xfe54, 0xfe66,
- 0xfe68, 0xfe6b,
- 0xfe70, 0xfe74,
- 0xfe76, 0xfefc,
- 0xfeff, 0xfeff,
- 0xff01, 0xffbe,
- 0xffc2, 0xffc7,
- 0xffca, 0xffcf,
- 0xffd2, 0xffd7,
- 0xffda, 0xffdc,
- 0xffe0, 0xffe6,
- 0xffe8, 0xffee,
- 0xfff9, 0x1000b,
- 0x1000d, 0x10026,
- 0x10028, 0x1003a,
- 0x1003c, 0x1003d,
- 0x1003f, 0x1004d,
- 0x10050, 0x1005d,
- 0x10080, 0x100fa,
- 0x10100, 0x10102,
- 0x10107, 0x10133,
- 0x10137, 0x1018a,
- 0x10300, 0x1031e,
- 0x10320, 0x10323,
- 0x10330, 0x1034a,
- 0x10380, 0x1039d,
- 0x1039f, 0x103c3,
- 0x103c8, 0x103d5,
- 0x10400, 0x1049d,
- 0x104a0, 0x104a9,
- 0x10800, 0x10805,
- 0x10808, 0x10808,
- 0x1080a, 0x10835,
- 0x10837, 0x10838,
- 0x1083c, 0x1083c,
- 0x1083f, 0x1083f,
- 0x10a00, 0x10a03,
- 0x10a05, 0x10a06,
- 0x10a0c, 0x10a13,
- 0x10a15, 0x10a17,
- 0x10a19, 0x10a33,
- 0x10a38, 0x10a3a,
- 0x10a3f, 0x10a47,
- 0x10a50, 0x10a58,
- 0x1d000, 0x1d0f5,
- 0x1d100, 0x1d126,
- 0x1d12a, 0x1d1dd,
- 0x1d200, 0x1d245,
- 0x1d300, 0x1d356,
- 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, 0x1d7c9,
- 0x1d7ce, 0x1d7ff,
- 0x1fffe, 0x2a6d6,
- 0x2f800, 0x2fa1d,
- 0x2fffe, 0x2ffff,
- 0x3fffe, 0x3ffff,
- 0x4fffe, 0x4ffff,
- 0x5fffe, 0x5ffff,
- 0x6fffe, 0x6ffff,
- 0x7fffe, 0x7ffff,
- 0x8fffe, 0x8ffff,
- 0x9fffe, 0x9ffff,
- 0xafffe, 0xaffff,
- 0xbfffe, 0xbffff,
- 0xcfffe, 0xcffff,
- 0xdfffe, 0xdffff,
- 0xe0001, 0xe0001,
- 0xe0020, 0xe007f,
- 0xe0100, 0xe01ef,
- 0xefffe, 0x10ffff,
-}; /* CR_Age_4_1 */
-
-/* 'Age_5_0': Derived Age 5.0 */
-static const OnigCodePoint CR_Age_5_0[] = {
- 440,
- 0x0000, 0x036f,
- 0x0374, 0x0375,
- 0x037a, 0x037e,
- 0x0384, 0x038a,
- 0x038c, 0x038c,
- 0x038e, 0x03a1,
- 0x03a3, 0x03ce,
- 0x03d0, 0x0486,
- 0x0488, 0x0513,
- 0x0531, 0x0556,
- 0x0559, 0x055f,
- 0x0561, 0x0587,
- 0x0589, 0x058a,
- 0x0591, 0x05c7,
- 0x05d0, 0x05ea,
- 0x05f0, 0x05f4,
- 0x0600, 0x0603,
- 0x060b, 0x0615,
- 0x061b, 0x061b,
- 0x061e, 0x061f,
- 0x0621, 0x063a,
- 0x0640, 0x065e,
- 0x0660, 0x070d,
- 0x070f, 0x074a,
- 0x074d, 0x076d,
- 0x0780, 0x07b1,
- 0x07c0, 0x07fa,
- 0x0901, 0x0939,
- 0x093c, 0x094d,
- 0x0950, 0x0954,
- 0x0958, 0x0970,
- 0x097b, 0x097f,
- 0x0981, 0x0983,
- 0x0985, 0x098c,
- 0x098f, 0x0990,
- 0x0993, 0x09a8,
- 0x09aa, 0x09b0,
- 0x09b2, 0x09b2,
- 0x09b6, 0x09b9,
- 0x09bc, 0x09c4,
- 0x09c7, 0x09c8,
- 0x09cb, 0x09ce,
- 0x09d7, 0x09d7,
- 0x09dc, 0x09dd,
- 0x09df, 0x09e3,
- 0x09e6, 0x09fa,
- 0x0a01, 0x0a03,
- 0x0a05, 0x0a0a,
- 0x0a0f, 0x0a10,
- 0x0a13, 0x0a28,
- 0x0a2a, 0x0a30,
- 0x0a32, 0x0a33,
- 0x0a35, 0x0a36,
- 0x0a38, 0x0a39,
- 0x0a3c, 0x0a3c,
- 0x0a3e, 0x0a42,
- 0x0a47, 0x0a48,
- 0x0a4b, 0x0a4d,
- 0x0a59, 0x0a5c,
- 0x0a5e, 0x0a5e,
- 0x0a66, 0x0a74,
- 0x0a81, 0x0a83,
- 0x0a85, 0x0a8d,
- 0x0a8f, 0x0a91,
- 0x0a93, 0x0aa8,
- 0x0aaa, 0x0ab0,
- 0x0ab2, 0x0ab3,
- 0x0ab5, 0x0ab9,
- 0x0abc, 0x0ac5,
- 0x0ac7, 0x0ac9,
- 0x0acb, 0x0acd,
- 0x0ad0, 0x0ad0,
- 0x0ae0, 0x0ae3,
- 0x0ae6, 0x0aef,
- 0x0af1, 0x0af1,
- 0x0b01, 0x0b03,
- 0x0b05, 0x0b0c,
- 0x0b0f, 0x0b10,
- 0x0b13, 0x0b28,
- 0x0b2a, 0x0b30,
- 0x0b32, 0x0b33,
- 0x0b35, 0x0b39,
- 0x0b3c, 0x0b43,
- 0x0b47, 0x0b48,
- 0x0b4b, 0x0b4d,
- 0x0b56, 0x0b57,
- 0x0b5c, 0x0b5d,
- 0x0b5f, 0x0b61,
- 0x0b66, 0x0b71,
- 0x0b82, 0x0b83,
- 0x0b85, 0x0b8a,
- 0x0b8e, 0x0b90,
- 0x0b92, 0x0b95,
- 0x0b99, 0x0b9a,
- 0x0b9c, 0x0b9c,
- 0x0b9e, 0x0b9f,
- 0x0ba3, 0x0ba4,
- 0x0ba8, 0x0baa,
- 0x0bae, 0x0bb9,
- 0x0bbe, 0x0bc2,
- 0x0bc6, 0x0bc8,
- 0x0bca, 0x0bcd,
- 0x0bd7, 0x0bd7,
- 0x0be6, 0x0bfa,
- 0x0c01, 0x0c03,
- 0x0c05, 0x0c0c,
- 0x0c0e, 0x0c10,
- 0x0c12, 0x0c28,
- 0x0c2a, 0x0c33,
- 0x0c35, 0x0c39,
- 0x0c3e, 0x0c44,
- 0x0c46, 0x0c48,
- 0x0c4a, 0x0c4d,
- 0x0c55, 0x0c56,
- 0x0c60, 0x0c61,
- 0x0c66, 0x0c6f,
- 0x0c82, 0x0c83,
- 0x0c85, 0x0c8c,
- 0x0c8e, 0x0c90,
- 0x0c92, 0x0ca8,
- 0x0caa, 0x0cb3,
- 0x0cb5, 0x0cb9,
- 0x0cbc, 0x0cc4,
- 0x0cc6, 0x0cc8,
- 0x0cca, 0x0ccd,
- 0x0cd5, 0x0cd6,
- 0x0cde, 0x0cde,
- 0x0ce0, 0x0ce3,
- 0x0ce6, 0x0cef,
- 0x0cf1, 0x0cf2,
- 0x0d02, 0x0d03,
- 0x0d05, 0x0d0c,
- 0x0d0e, 0x0d10,
- 0x0d12, 0x0d28,
- 0x0d2a, 0x0d39,
- 0x0d3e, 0x0d43,
- 0x0d46, 0x0d48,
- 0x0d4a, 0x0d4d,
- 0x0d57, 0x0d57,
- 0x0d60, 0x0d61,
- 0x0d66, 0x0d6f,
- 0x0d82, 0x0d83,
- 0x0d85, 0x0d96,
- 0x0d9a, 0x0db1,
- 0x0db3, 0x0dbb,
- 0x0dbd, 0x0dbd,
- 0x0dc0, 0x0dc6,
- 0x0dca, 0x0dca,
- 0x0dcf, 0x0dd4,
- 0x0dd6, 0x0dd6,
- 0x0dd8, 0x0ddf,
- 0x0df2, 0x0df4,
- 0x0e01, 0x0e3a,
- 0x0e3f, 0x0e5b,
- 0x0e81, 0x0e82,
- 0x0e84, 0x0e84,
- 0x0e87, 0x0e88,
- 0x0e8a, 0x0e8a,
- 0x0e8d, 0x0e8d,
- 0x0e94, 0x0e97,
- 0x0e99, 0x0e9f,
- 0x0ea1, 0x0ea3,
- 0x0ea5, 0x0ea5,
- 0x0ea7, 0x0ea7,
- 0x0eaa, 0x0eab,
- 0x0ead, 0x0eb9,
- 0x0ebb, 0x0ebd,
- 0x0ec0, 0x0ec4,
- 0x0ec6, 0x0ec6,
- 0x0ec8, 0x0ecd,
- 0x0ed0, 0x0ed9,
- 0x0edc, 0x0edd,
- 0x0f00, 0x0f47,
- 0x0f49, 0x0f6a,
- 0x0f71, 0x0f8b,
- 0x0f90, 0x0f97,
- 0x0f99, 0x0fbc,
- 0x0fbe, 0x0fcc,
- 0x0fcf, 0x0fd1,
- 0x1000, 0x1021,
- 0x1023, 0x1027,
- 0x1029, 0x102a,
- 0x102c, 0x1032,
- 0x1036, 0x1039,
- 0x1040, 0x1059,
- 0x10a0, 0x10c5,
- 0x10d0, 0x10fc,
- 0x1100, 0x1159,
- 0x115f, 0x11a2,
- 0x11a8, 0x11f9,
- 0x1200, 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,
- 0x135f, 0x137c,
- 0x1380, 0x1399,
- 0x13a0, 0x13f4,
- 0x1401, 0x1676,
- 0x1680, 0x169c,
- 0x16a0, 0x16f0,
- 0x1700, 0x170c,
- 0x170e, 0x1714,
- 0x1720, 0x1736,
- 0x1740, 0x1753,
- 0x1760, 0x176c,
- 0x176e, 0x1770,
- 0x1772, 0x1773,
- 0x1780, 0x17dd,
- 0x17e0, 0x17e9,
- 0x17f0, 0x17f9,
- 0x1800, 0x180e,
- 0x1810, 0x1819,
- 0x1820, 0x1877,
- 0x1880, 0x18a9,
- 0x1900, 0x191c,
- 0x1920, 0x192b,
- 0x1930, 0x193b,
- 0x1940, 0x1940,
- 0x1944, 0x196d,
- 0x1970, 0x1974,
- 0x1980, 0x19a9,
- 0x19b0, 0x19c9,
- 0x19d0, 0x19d9,
- 0x19de, 0x1a1b,
- 0x1a1e, 0x1a1f,
- 0x1b00, 0x1b4b,
- 0x1b50, 0x1b7c,
- 0x1d00, 0x1dca,
- 0x1dfe, 0x1e9b,
- 0x1ea0, 0x1ef9,
- 0x1f00, 0x1f15,
- 0x1f18, 0x1f1d,
- 0x1f20, 0x1f45,
- 0x1f48, 0x1f4d,
- 0x1f50, 0x1f57,
- 0x1f59, 0x1f59,
- 0x1f5b, 0x1f5b,
- 0x1f5d, 0x1f5d,
- 0x1f5f, 0x1f7d,
- 0x1f80, 0x1fb4,
- 0x1fb6, 0x1fc4,
- 0x1fc6, 0x1fd3,
- 0x1fd6, 0x1fdb,
- 0x1fdd, 0x1fef,
- 0x1ff2, 0x1ff4,
- 0x1ff6, 0x1ffe,
- 0x2000, 0x2063,
- 0x206a, 0x2071,
- 0x2074, 0x208e,
- 0x2090, 0x2094,
- 0x20a0, 0x20b5,
- 0x20d0, 0x20ef,
- 0x2100, 0x214e,
- 0x2153, 0x2184,
- 0x2190, 0x23e7,
- 0x2400, 0x2426,
- 0x2440, 0x244a,
- 0x2460, 0x269c,
- 0x26a0, 0x26b2,
- 0x2701, 0x2704,
- 0x2706, 0x2709,
- 0x270c, 0x2727,
- 0x2729, 0x274b,
- 0x274d, 0x274d,
- 0x274f, 0x2752,
- 0x2756, 0x2756,
- 0x2758, 0x275e,
- 0x2761, 0x2794,
- 0x2798, 0x27af,
- 0x27b1, 0x27be,
- 0x27c0, 0x27ca,
- 0x27d0, 0x27eb,
- 0x27f0, 0x2b1a,
- 0x2b20, 0x2b23,
- 0x2c00, 0x2c2e,
- 0x2c30, 0x2c5e,
- 0x2c60, 0x2c6c,
- 0x2c74, 0x2c77,
- 0x2c80, 0x2cea,
- 0x2cf9, 0x2d25,
- 0x2d30, 0x2d65,
- 0x2d6f, 0x2d6f,
- 0x2d80, 0x2d96,
- 0x2da0, 0x2da6,
- 0x2da8, 0x2dae,
- 0x2db0, 0x2db6,
- 0x2db8, 0x2dbe,
- 0x2dc0, 0x2dc6,
- 0x2dc8, 0x2dce,
- 0x2dd0, 0x2dd6,
- 0x2dd8, 0x2dde,
- 0x2e00, 0x2e17,
- 0x2e1c, 0x2e1d,
- 0x2e80, 0x2e99,
- 0x2e9b, 0x2ef3,
- 0x2f00, 0x2fd5,
- 0x2ff0, 0x2ffb,
- 0x3000, 0x303f,
- 0x3041, 0x3096,
- 0x3099, 0x30ff,
- 0x3105, 0x312c,
- 0x3131, 0x318e,
- 0x3190, 0x31b7,
- 0x31c0, 0x31cf,
- 0x31f0, 0x321e,
- 0x3220, 0x3243,
- 0x3250, 0x32fe,
- 0x3300, 0x4db5,
- 0x4dc0, 0x9fbb,
- 0xa000, 0xa48c,
- 0xa490, 0xa4c6,
- 0xa700, 0xa71a,
- 0xa720, 0xa721,
- 0xa800, 0xa82b,
- 0xa840, 0xa877,
- 0xac00, 0xd7a3,
- 0xd800, 0xfa2d,
- 0xfa30, 0xfa6a,
- 0xfa70, 0xfad9,
- 0xfb00, 0xfb06,
- 0xfb13, 0xfb17,
- 0xfb1d, 0xfb36,
- 0xfb38, 0xfb3c,
- 0xfb3e, 0xfb3e,
- 0xfb40, 0xfb41,
- 0xfb43, 0xfb44,
- 0xfb46, 0xfbb1,
- 0xfbd3, 0xfd3f,
- 0xfd50, 0xfd8f,
- 0xfd92, 0xfdc7,
- 0xfdd0, 0xfdfd,
- 0xfe00, 0xfe19,
- 0xfe20, 0xfe23,
- 0xfe30, 0xfe52,
- 0xfe54, 0xfe66,
- 0xfe68, 0xfe6b,
- 0xfe70, 0xfe74,
- 0xfe76, 0xfefc,
- 0xfeff, 0xfeff,
- 0xff01, 0xffbe,
- 0xffc2, 0xffc7,
- 0xffca, 0xffcf,
- 0xffd2, 0xffd7,
- 0xffda, 0xffdc,
- 0xffe0, 0xffe6,
- 0xffe8, 0xffee,
- 0xfff9, 0x1000b,
- 0x1000d, 0x10026,
- 0x10028, 0x1003a,
- 0x1003c, 0x1003d,
- 0x1003f, 0x1004d,
- 0x10050, 0x1005d,
- 0x10080, 0x100fa,
- 0x10100, 0x10102,
- 0x10107, 0x10133,
- 0x10137, 0x1018a,
- 0x10300, 0x1031e,
- 0x10320, 0x10323,
- 0x10330, 0x1034a,
- 0x10380, 0x1039d,
- 0x1039f, 0x103c3,
- 0x103c8, 0x103d5,
- 0x10400, 0x1049d,
- 0x104a0, 0x104a9,
- 0x10800, 0x10805,
- 0x10808, 0x10808,
- 0x1080a, 0x10835,
- 0x10837, 0x10838,
- 0x1083c, 0x1083c,
- 0x1083f, 0x1083f,
- 0x10900, 0x10919,
- 0x1091f, 0x1091f,
- 0x10a00, 0x10a03,
- 0x10a05, 0x10a06,
- 0x10a0c, 0x10a13,
- 0x10a15, 0x10a17,
- 0x10a19, 0x10a33,
- 0x10a38, 0x10a3a,
- 0x10a3f, 0x10a47,
- 0x10a50, 0x10a58,
- 0x12000, 0x1236e,
- 0x12400, 0x12462,
- 0x12470, 0x12473,
- 0x1d000, 0x1d0f5,
- 0x1d100, 0x1d126,
- 0x1d12a, 0x1d1dd,
- 0x1d200, 0x1d245,
- 0x1d300, 0x1d356,
- 0x1d360, 0x1d371,
- 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, 0x1d7cb,
- 0x1d7ce, 0x1d7ff,
- 0x1fffe, 0x2a6d6,
- 0x2f800, 0x2fa1d,
- 0x2fffe, 0x2ffff,
- 0x3fffe, 0x3ffff,
- 0x4fffe, 0x4ffff,
- 0x5fffe, 0x5ffff,
- 0x6fffe, 0x6ffff,
- 0x7fffe, 0x7ffff,
- 0x8fffe, 0x8ffff,
- 0x9fffe, 0x9ffff,
- 0xafffe, 0xaffff,
- 0xbfffe, 0xbffff,
- 0xcfffe, 0xcffff,
- 0xdfffe, 0xdffff,
- 0xe0001, 0xe0001,
- 0xe0020, 0xe007f,
- 0xe0100, 0xe01ef,
- 0xefffe, 0x10ffff,
-}; /* CR_Age_5_0 */
-
-/* 'Age_5_1': Derived Age 5.1 */
-static const OnigCodePoint CR_Age_5_1[] = {
- 455,
- 0x0000, 0x0377,
- 0x037a, 0x037e,
- 0x0384, 0x038a,
- 0x038c, 0x038c,
- 0x038e, 0x03a1,
- 0x03a3, 0x0523,
- 0x0531, 0x0556,
- 0x0559, 0x055f,
- 0x0561, 0x0587,
- 0x0589, 0x058a,
- 0x0591, 0x05c7,
- 0x05d0, 0x05ea,
- 0x05f0, 0x05f4,
- 0x0600, 0x0603,
- 0x0606, 0x061b,
- 0x061e, 0x061f,
- 0x0621, 0x065e,
- 0x0660, 0x070d,
- 0x070f, 0x074a,
- 0x074d, 0x07b1,
- 0x07c0, 0x07fa,
- 0x0901, 0x0939,
- 0x093c, 0x094d,
- 0x0950, 0x0954,
- 0x0958, 0x0972,
- 0x097b, 0x097f,
- 0x0981, 0x0983,
- 0x0985, 0x098c,
- 0x098f, 0x0990,
- 0x0993, 0x09a8,
- 0x09aa, 0x09b0,
- 0x09b2, 0x09b2,
- 0x09b6, 0x09b9,
- 0x09bc, 0x09c4,
- 0x09c7, 0x09c8,
- 0x09cb, 0x09ce,
- 0x09d7, 0x09d7,
- 0x09dc, 0x09dd,
- 0x09df, 0x09e3,
- 0x09e6, 0x09fa,
- 0x0a01, 0x0a03,
- 0x0a05, 0x0a0a,
- 0x0a0f, 0x0a10,
- 0x0a13, 0x0a28,
- 0x0a2a, 0x0a30,
- 0x0a32, 0x0a33,
- 0x0a35, 0x0a36,
- 0x0a38, 0x0a39,
- 0x0a3c, 0x0a3c,
- 0x0a3e, 0x0a42,
- 0x0a47, 0x0a48,
- 0x0a4b, 0x0a4d,
- 0x0a51, 0x0a51,
- 0x0a59, 0x0a5c,
- 0x0a5e, 0x0a5e,
- 0x0a66, 0x0a75,
- 0x0a81, 0x0a83,
- 0x0a85, 0x0a8d,
- 0x0a8f, 0x0a91,
- 0x0a93, 0x0aa8,
- 0x0aaa, 0x0ab0,
- 0x0ab2, 0x0ab3,
- 0x0ab5, 0x0ab9,
- 0x0abc, 0x0ac5,
- 0x0ac7, 0x0ac9,
- 0x0acb, 0x0acd,
- 0x0ad0, 0x0ad0,
- 0x0ae0, 0x0ae3,
- 0x0ae6, 0x0aef,
- 0x0af1, 0x0af1,
- 0x0b01, 0x0b03,
- 0x0b05, 0x0b0c,
- 0x0b0f, 0x0b10,
- 0x0b13, 0x0b28,
- 0x0b2a, 0x0b30,
- 0x0b32, 0x0b33,
- 0x0b35, 0x0b39,
- 0x0b3c, 0x0b44,
- 0x0b47, 0x0b48,
- 0x0b4b, 0x0b4d,
- 0x0b56, 0x0b57,
- 0x0b5c, 0x0b5d,
- 0x0b5f, 0x0b63,
- 0x0b66, 0x0b71,
- 0x0b82, 0x0b83,
- 0x0b85, 0x0b8a,
- 0x0b8e, 0x0b90,
- 0x0b92, 0x0b95,
- 0x0b99, 0x0b9a,
- 0x0b9c, 0x0b9c,
- 0x0b9e, 0x0b9f,
- 0x0ba3, 0x0ba4,
- 0x0ba8, 0x0baa,
- 0x0bae, 0x0bb9,
- 0x0bbe, 0x0bc2,
- 0x0bc6, 0x0bc8,
- 0x0bca, 0x0bcd,
- 0x0bd0, 0x0bd0,
- 0x0bd7, 0x0bd7,
- 0x0be6, 0x0bfa,
- 0x0c01, 0x0c03,
- 0x0c05, 0x0c0c,
- 0x0c0e, 0x0c10,
- 0x0c12, 0x0c28,
- 0x0c2a, 0x0c33,
- 0x0c35, 0x0c39,
- 0x0c3d, 0x0c44,
- 0x0c46, 0x0c48,
- 0x0c4a, 0x0c4d,
- 0x0c55, 0x0c56,
- 0x0c58, 0x0c59,
- 0x0c60, 0x0c63,
- 0x0c66, 0x0c6f,
- 0x0c78, 0x0c7f,
- 0x0c82, 0x0c83,
- 0x0c85, 0x0c8c,
- 0x0c8e, 0x0c90,
- 0x0c92, 0x0ca8,
- 0x0caa, 0x0cb3,
- 0x0cb5, 0x0cb9,
- 0x0cbc, 0x0cc4,
- 0x0cc6, 0x0cc8,
- 0x0cca, 0x0ccd,
- 0x0cd5, 0x0cd6,
- 0x0cde, 0x0cde,
- 0x0ce0, 0x0ce3,
- 0x0ce6, 0x0cef,
- 0x0cf1, 0x0cf2,
- 0x0d02, 0x0d03,
- 0x0d05, 0x0d0c,
- 0x0d0e, 0x0d10,
- 0x0d12, 0x0d28,
- 0x0d2a, 0x0d39,
- 0x0d3d, 0x0d44,
- 0x0d46, 0x0d48,
- 0x0d4a, 0x0d4d,
- 0x0d57, 0x0d57,
- 0x0d60, 0x0d63,
- 0x0d66, 0x0d75,
- 0x0d79, 0x0d7f,
- 0x0d82, 0x0d83,
- 0x0d85, 0x0d96,
- 0x0d9a, 0x0db1,
- 0x0db3, 0x0dbb,
- 0x0dbd, 0x0dbd,
- 0x0dc0, 0x0dc6,
- 0x0dca, 0x0dca,
- 0x0dcf, 0x0dd4,
- 0x0dd6, 0x0dd6,
- 0x0dd8, 0x0ddf,
- 0x0df2, 0x0df4,
- 0x0e01, 0x0e3a,
- 0x0e3f, 0x0e5b,
- 0x0e81, 0x0e82,
- 0x0e84, 0x0e84,
- 0x0e87, 0x0e88,
- 0x0e8a, 0x0e8a,
- 0x0e8d, 0x0e8d,
- 0x0e94, 0x0e97,
- 0x0e99, 0x0e9f,
- 0x0ea1, 0x0ea3,
- 0x0ea5, 0x0ea5,
- 0x0ea7, 0x0ea7,
- 0x0eaa, 0x0eab,
- 0x0ead, 0x0eb9,
- 0x0ebb, 0x0ebd,
- 0x0ec0, 0x0ec4,
- 0x0ec6, 0x0ec6,
- 0x0ec8, 0x0ecd,
- 0x0ed0, 0x0ed9,
- 0x0edc, 0x0edd,
- 0x0f00, 0x0f47,
- 0x0f49, 0x0f6c,
- 0x0f71, 0x0f8b,
- 0x0f90, 0x0f97,
- 0x0f99, 0x0fbc,
- 0x0fbe, 0x0fcc,
- 0x0fce, 0x0fd4,
- 0x1000, 0x1099,
- 0x109e, 0x10c5,
- 0x10d0, 0x10fc,
- 0x1100, 0x1159,
- 0x115f, 0x11a2,
- 0x11a8, 0x11f9,
- 0x1200, 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,
- 0x135f, 0x137c,
- 0x1380, 0x1399,
- 0x13a0, 0x13f4,
- 0x1401, 0x1676,
- 0x1680, 0x169c,
- 0x16a0, 0x16f0,
- 0x1700, 0x170c,
- 0x170e, 0x1714,
- 0x1720, 0x1736,
- 0x1740, 0x1753,
- 0x1760, 0x176c,
- 0x176e, 0x1770,
- 0x1772, 0x1773,
- 0x1780, 0x17dd,
- 0x17e0, 0x17e9,
- 0x17f0, 0x17f9,
- 0x1800, 0x180e,
- 0x1810, 0x1819,
- 0x1820, 0x1877,
- 0x1880, 0x18aa,
- 0x1900, 0x191c,
- 0x1920, 0x192b,
- 0x1930, 0x193b,
- 0x1940, 0x1940,
- 0x1944, 0x196d,
- 0x1970, 0x1974,
- 0x1980, 0x19a9,
- 0x19b0, 0x19c9,
- 0x19d0, 0x19d9,
- 0x19de, 0x1a1b,
- 0x1a1e, 0x1a1f,
- 0x1b00, 0x1b4b,
- 0x1b50, 0x1b7c,
- 0x1b80, 0x1baa,
- 0x1bae, 0x1bb9,
- 0x1c00, 0x1c37,
- 0x1c3b, 0x1c49,
- 0x1c4d, 0x1c7f,
- 0x1d00, 0x1de6,
- 0x1dfe, 0x1f15,
- 0x1f18, 0x1f1d,
- 0x1f20, 0x1f45,
- 0x1f48, 0x1f4d,
- 0x1f50, 0x1f57,
- 0x1f59, 0x1f59,
- 0x1f5b, 0x1f5b,
- 0x1f5d, 0x1f5d,
- 0x1f5f, 0x1f7d,
- 0x1f80, 0x1fb4,
- 0x1fb6, 0x1fc4,
- 0x1fc6, 0x1fd3,
- 0x1fd6, 0x1fdb,
- 0x1fdd, 0x1fef,
- 0x1ff2, 0x1ff4,
- 0x1ff6, 0x1ffe,
- 0x2000, 0x2064,
- 0x206a, 0x2071,
- 0x2074, 0x208e,
- 0x2090, 0x2094,
- 0x20a0, 0x20b5,
- 0x20d0, 0x20f0,
- 0x2100, 0x214f,
- 0x2153, 0x2188,
- 0x2190, 0x23e7,
- 0x2400, 0x2426,
- 0x2440, 0x244a,
- 0x2460, 0x269d,
- 0x26a0, 0x26bc,
- 0x26c0, 0x26c3,
- 0x2701, 0x2704,
- 0x2706, 0x2709,
- 0x270c, 0x2727,
- 0x2729, 0x274b,
- 0x274d, 0x274d,
- 0x274f, 0x2752,
- 0x2756, 0x2756,
- 0x2758, 0x275e,
- 0x2761, 0x2794,
- 0x2798, 0x27af,
- 0x27b1, 0x27be,
- 0x27c0, 0x27ca,
- 0x27cc, 0x27cc,
- 0x27d0, 0x2b4c,
- 0x2b50, 0x2b54,
- 0x2c00, 0x2c2e,
- 0x2c30, 0x2c5e,
- 0x2c60, 0x2c6f,
- 0x2c71, 0x2c7d,
- 0x2c80, 0x2cea,
- 0x2cf9, 0x2d25,
- 0x2d30, 0x2d65,
- 0x2d6f, 0x2d6f,
- 0x2d80, 0x2d96,
- 0x2da0, 0x2da6,
- 0x2da8, 0x2dae,
- 0x2db0, 0x2db6,
- 0x2db8, 0x2dbe,
- 0x2dc0, 0x2dc6,
- 0x2dc8, 0x2dce,
- 0x2dd0, 0x2dd6,
- 0x2dd8, 0x2dde,
- 0x2de0, 0x2e30,
- 0x2e80, 0x2e99,
- 0x2e9b, 0x2ef3,
- 0x2f00, 0x2fd5,
- 0x2ff0, 0x2ffb,
- 0x3000, 0x303f,
- 0x3041, 0x3096,
- 0x3099, 0x30ff,
- 0x3105, 0x312d,
- 0x3131, 0x318e,
- 0x3190, 0x31b7,
- 0x31c0, 0x31e3,
- 0x31f0, 0x321e,
- 0x3220, 0x3243,
- 0x3250, 0x32fe,
- 0x3300, 0x4db5,
- 0x4dc0, 0x9fc3,
- 0xa000, 0xa48c,
- 0xa490, 0xa4c6,
- 0xa500, 0xa62b,
- 0xa640, 0xa65f,
- 0xa662, 0xa673,
- 0xa67c, 0xa697,
- 0xa700, 0xa78c,
- 0xa7fb, 0xa82b,
- 0xa840, 0xa877,
- 0xa880, 0xa8c4,
- 0xa8ce, 0xa8d9,
- 0xa900, 0xa953,
- 0xa95f, 0xa95f,
- 0xaa00, 0xaa36,
- 0xaa40, 0xaa4d,
- 0xaa50, 0xaa59,
- 0xaa5c, 0xaa5f,
- 0xac00, 0xd7a3,
- 0xd800, 0xfa2d,
- 0xfa30, 0xfa6a,
- 0xfa70, 0xfad9,
- 0xfb00, 0xfb06,
- 0xfb13, 0xfb17,
- 0xfb1d, 0xfb36,
- 0xfb38, 0xfb3c,
- 0xfb3e, 0xfb3e,
- 0xfb40, 0xfb41,
- 0xfb43, 0xfb44,
- 0xfb46, 0xfbb1,
- 0xfbd3, 0xfd3f,
- 0xfd50, 0xfd8f,
- 0xfd92, 0xfdc7,
- 0xfdd0, 0xfdfd,
- 0xfe00, 0xfe19,
- 0xfe20, 0xfe26,
- 0xfe30, 0xfe52,
- 0xfe54, 0xfe66,
- 0xfe68, 0xfe6b,
- 0xfe70, 0xfe74,
- 0xfe76, 0xfefc,
- 0xfeff, 0xfeff,
- 0xff01, 0xffbe,
- 0xffc2, 0xffc7,
- 0xffca, 0xffcf,
- 0xffd2, 0xffd7,
- 0xffda, 0xffdc,
- 0xffe0, 0xffe6,
- 0xffe8, 0xffee,
- 0xfff9, 0x1000b,
- 0x1000d, 0x10026,
- 0x10028, 0x1003a,
- 0x1003c, 0x1003d,
- 0x1003f, 0x1004d,
- 0x10050, 0x1005d,
- 0x10080, 0x100fa,
- 0x10100, 0x10102,
- 0x10107, 0x10133,
- 0x10137, 0x1018a,
- 0x10190, 0x1019b,
- 0x101d0, 0x101fd,
- 0x10280, 0x1029c,
- 0x102a0, 0x102d0,
- 0x10300, 0x1031e,
- 0x10320, 0x10323,
- 0x10330, 0x1034a,
- 0x10380, 0x1039d,
- 0x1039f, 0x103c3,
- 0x103c8, 0x103d5,
- 0x10400, 0x1049d,
- 0x104a0, 0x104a9,
- 0x10800, 0x10805,
- 0x10808, 0x10808,
- 0x1080a, 0x10835,
- 0x10837, 0x10838,
- 0x1083c, 0x1083c,
- 0x1083f, 0x1083f,
- 0x10900, 0x10919,
- 0x1091f, 0x10939,
- 0x1093f, 0x1093f,
- 0x10a00, 0x10a03,
- 0x10a05, 0x10a06,
- 0x10a0c, 0x10a13,
- 0x10a15, 0x10a17,
- 0x10a19, 0x10a33,
- 0x10a38, 0x10a3a,
- 0x10a3f, 0x10a47,
- 0x10a50, 0x10a58,
- 0x12000, 0x1236e,
- 0x12400, 0x12462,
- 0x12470, 0x12473,
- 0x1d000, 0x1d0f5,
- 0x1d100, 0x1d126,
- 0x1d129, 0x1d1dd,
- 0x1d200, 0x1d245,
- 0x1d300, 0x1d356,
- 0x1d360, 0x1d371,
- 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, 0x1d7cb,
- 0x1d7ce, 0x1d7ff,
- 0x1f000, 0x1f02b,
- 0x1f030, 0x1f093,
- 0x1fffe, 0x2a6d6,
- 0x2f800, 0x2fa1d,
- 0x2fffe, 0x2ffff,
- 0x3fffe, 0x3ffff,
- 0x4fffe, 0x4ffff,
- 0x5fffe, 0x5ffff,
- 0x6fffe, 0x6ffff,
- 0x7fffe, 0x7ffff,
- 0x8fffe, 0x8ffff,
- 0x9fffe, 0x9ffff,
- 0xafffe, 0xaffff,
- 0xbfffe, 0xbffff,
- 0xcfffe, 0xcffff,
- 0xdfffe, 0xdffff,
- 0xe0001, 0xe0001,
- 0xe0020, 0xe007f,
- 0xe0100, 0xe01ef,
- 0xefffe, 0x10ffff,
-}; /* CR_Age_5_1 */
-
-/* 'Age_5_2': Derived Age 5.2 */
-static const OnigCodePoint CR_Age_5_2[] = {
- 495,
- 0x0000, 0x0377,
- 0x037a, 0x037e,
- 0x0384, 0x038a,
- 0x038c, 0x038c,
- 0x038e, 0x03a1,
- 0x03a3, 0x0525,
- 0x0531, 0x0556,
- 0x0559, 0x055f,
- 0x0561, 0x0587,
- 0x0589, 0x058a,
- 0x0591, 0x05c7,
- 0x05d0, 0x05ea,
- 0x05f0, 0x05f4,
- 0x0600, 0x0603,
- 0x0606, 0x061b,
- 0x061e, 0x061f,
- 0x0621, 0x065e,
- 0x0660, 0x070d,
- 0x070f, 0x074a,
- 0x074d, 0x07b1,
- 0x07c0, 0x07fa,
- 0x0800, 0x082d,
- 0x0830, 0x083e,
- 0x0900, 0x0939,
- 0x093c, 0x094e,
- 0x0950, 0x0955,
- 0x0958, 0x0972,
- 0x0979, 0x097f,
- 0x0981, 0x0983,
- 0x0985, 0x098c,
- 0x098f, 0x0990,
- 0x0993, 0x09a8,
- 0x09aa, 0x09b0,
- 0x09b2, 0x09b2,
- 0x09b6, 0x09b9,
- 0x09bc, 0x09c4,
- 0x09c7, 0x09c8,
- 0x09cb, 0x09ce,
- 0x09d7, 0x09d7,
- 0x09dc, 0x09dd,
- 0x09df, 0x09e3,
- 0x09e6, 0x09fb,
- 0x0a01, 0x0a03,
- 0x0a05, 0x0a0a,
- 0x0a0f, 0x0a10,
- 0x0a13, 0x0a28,
- 0x0a2a, 0x0a30,
- 0x0a32, 0x0a33,
- 0x0a35, 0x0a36,
- 0x0a38, 0x0a39,
- 0x0a3c, 0x0a3c,
- 0x0a3e, 0x0a42,
- 0x0a47, 0x0a48,
- 0x0a4b, 0x0a4d,
- 0x0a51, 0x0a51,
- 0x0a59, 0x0a5c,
- 0x0a5e, 0x0a5e,
- 0x0a66, 0x0a75,
- 0x0a81, 0x0a83,
- 0x0a85, 0x0a8d,
- 0x0a8f, 0x0a91,
- 0x0a93, 0x0aa8,
- 0x0aaa, 0x0ab0,
- 0x0ab2, 0x0ab3,
- 0x0ab5, 0x0ab9,
- 0x0abc, 0x0ac5,
- 0x0ac7, 0x0ac9,
- 0x0acb, 0x0acd,
- 0x0ad0, 0x0ad0,
- 0x0ae0, 0x0ae3,
- 0x0ae6, 0x0aef,
- 0x0af1, 0x0af1,
- 0x0b01, 0x0b03,
- 0x0b05, 0x0b0c,
- 0x0b0f, 0x0b10,
- 0x0b13, 0x0b28,
- 0x0b2a, 0x0b30,
- 0x0b32, 0x0b33,
- 0x0b35, 0x0b39,
- 0x0b3c, 0x0b44,
- 0x0b47, 0x0b48,
- 0x0b4b, 0x0b4d,
- 0x0b56, 0x0b57,
- 0x0b5c, 0x0b5d,
- 0x0b5f, 0x0b63,
- 0x0b66, 0x0b71,
- 0x0b82, 0x0b83,
- 0x0b85, 0x0b8a,
- 0x0b8e, 0x0b90,
- 0x0b92, 0x0b95,
- 0x0b99, 0x0b9a,
- 0x0b9c, 0x0b9c,
- 0x0b9e, 0x0b9f,
- 0x0ba3, 0x0ba4,
- 0x0ba8, 0x0baa,
- 0x0bae, 0x0bb9,
- 0x0bbe, 0x0bc2,
- 0x0bc6, 0x0bc8,
- 0x0bca, 0x0bcd,
- 0x0bd0, 0x0bd0,
- 0x0bd7, 0x0bd7,
- 0x0be6, 0x0bfa,
- 0x0c01, 0x0c03,
- 0x0c05, 0x0c0c,
- 0x0c0e, 0x0c10,
- 0x0c12, 0x0c28,
- 0x0c2a, 0x0c33,
- 0x0c35, 0x0c39,
- 0x0c3d, 0x0c44,
- 0x0c46, 0x0c48,
- 0x0c4a, 0x0c4d,
- 0x0c55, 0x0c56,
- 0x0c58, 0x0c59,
- 0x0c60, 0x0c63,
- 0x0c66, 0x0c6f,
- 0x0c78, 0x0c7f,
- 0x0c82, 0x0c83,
- 0x0c85, 0x0c8c,
- 0x0c8e, 0x0c90,
- 0x0c92, 0x0ca8,
- 0x0caa, 0x0cb3,
- 0x0cb5, 0x0cb9,
- 0x0cbc, 0x0cc4,
- 0x0cc6, 0x0cc8,
- 0x0cca, 0x0ccd,
- 0x0cd5, 0x0cd6,
- 0x0cde, 0x0cde,
- 0x0ce0, 0x0ce3,
- 0x0ce6, 0x0cef,
- 0x0cf1, 0x0cf2,
- 0x0d02, 0x0d03,
- 0x0d05, 0x0d0c,
- 0x0d0e, 0x0d10,
- 0x0d12, 0x0d28,
- 0x0d2a, 0x0d39,
- 0x0d3d, 0x0d44,
- 0x0d46, 0x0d48,
- 0x0d4a, 0x0d4d,
- 0x0d57, 0x0d57,
- 0x0d60, 0x0d63,
- 0x0d66, 0x0d75,
- 0x0d79, 0x0d7f,
- 0x0d82, 0x0d83,
- 0x0d85, 0x0d96,
- 0x0d9a, 0x0db1,
- 0x0db3, 0x0dbb,
- 0x0dbd, 0x0dbd,
- 0x0dc0, 0x0dc6,
- 0x0dca, 0x0dca,
- 0x0dcf, 0x0dd4,
- 0x0dd6, 0x0dd6,
- 0x0dd8, 0x0ddf,
- 0x0df2, 0x0df4,
- 0x0e01, 0x0e3a,
- 0x0e3f, 0x0e5b,
- 0x0e81, 0x0e82,
- 0x0e84, 0x0e84,
- 0x0e87, 0x0e88,
- 0x0e8a, 0x0e8a,
- 0x0e8d, 0x0e8d,
- 0x0e94, 0x0e97,
- 0x0e99, 0x0e9f,
- 0x0ea1, 0x0ea3,
- 0x0ea5, 0x0ea5,
- 0x0ea7, 0x0ea7,
- 0x0eaa, 0x0eab,
- 0x0ead, 0x0eb9,
- 0x0ebb, 0x0ebd,
- 0x0ec0, 0x0ec4,
- 0x0ec6, 0x0ec6,
- 0x0ec8, 0x0ecd,
- 0x0ed0, 0x0ed9,
- 0x0edc, 0x0edd,
- 0x0f00, 0x0f47,
- 0x0f49, 0x0f6c,
- 0x0f71, 0x0f8b,
- 0x0f90, 0x0f97,
- 0x0f99, 0x0fbc,
- 0x0fbe, 0x0fcc,
- 0x0fce, 0x0fd8,
- 0x1000, 0x10c5,
- 0x10d0, 0x10fc,
- 0x1100, 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,
- 0x135f, 0x137c,
- 0x1380, 0x1399,
- 0x13a0, 0x13f4,
- 0x1400, 0x169c,
- 0x16a0, 0x16f0,
- 0x1700, 0x170c,
- 0x170e, 0x1714,
- 0x1720, 0x1736,
- 0x1740, 0x1753,
- 0x1760, 0x176c,
- 0x176e, 0x1770,
- 0x1772, 0x1773,
- 0x1780, 0x17dd,
- 0x17e0, 0x17e9,
- 0x17f0, 0x17f9,
- 0x1800, 0x180e,
- 0x1810, 0x1819,
- 0x1820, 0x1877,
- 0x1880, 0x18aa,
- 0x18b0, 0x18f5,
- 0x1900, 0x191c,
- 0x1920, 0x192b,
- 0x1930, 0x193b,
- 0x1940, 0x1940,
- 0x1944, 0x196d,
- 0x1970, 0x1974,
- 0x1980, 0x19ab,
- 0x19b0, 0x19c9,
- 0x19d0, 0x19da,
- 0x19de, 0x1a1b,
- 0x1a1e, 0x1a5e,
- 0x1a60, 0x1a7c,
- 0x1a7f, 0x1a89,
- 0x1a90, 0x1a99,
- 0x1aa0, 0x1aad,
- 0x1b00, 0x1b4b,
- 0x1b50, 0x1b7c,
- 0x1b80, 0x1baa,
- 0x1bae, 0x1bb9,
- 0x1c00, 0x1c37,
- 0x1c3b, 0x1c49,
- 0x1c4d, 0x1c7f,
- 0x1cd0, 0x1cf2,
- 0x1d00, 0x1de6,
- 0x1dfd, 0x1f15,
- 0x1f18, 0x1f1d,
- 0x1f20, 0x1f45,
- 0x1f48, 0x1f4d,
- 0x1f50, 0x1f57,
- 0x1f59, 0x1f59,
- 0x1f5b, 0x1f5b,
- 0x1f5d, 0x1f5d,
- 0x1f5f, 0x1f7d,
- 0x1f80, 0x1fb4,
- 0x1fb6, 0x1fc4,
- 0x1fc6, 0x1fd3,
- 0x1fd6, 0x1fdb,
- 0x1fdd, 0x1fef,
- 0x1ff2, 0x1ff4,
- 0x1ff6, 0x1ffe,
- 0x2000, 0x2064,
- 0x206a, 0x2071,
- 0x2074, 0x208e,
- 0x2090, 0x2094,
- 0x20a0, 0x20b8,
- 0x20d0, 0x20f0,
- 0x2100, 0x2189,
- 0x2190, 0x23e8,
- 0x2400, 0x2426,
- 0x2440, 0x244a,
- 0x2460, 0x26cd,
- 0x26cf, 0x26e1,
- 0x26e3, 0x26e3,
- 0x26e8, 0x26ff,
- 0x2701, 0x2704,
- 0x2706, 0x2709,
- 0x270c, 0x2727,
- 0x2729, 0x274b,
- 0x274d, 0x274d,
- 0x274f, 0x2752,
- 0x2756, 0x275e,
- 0x2761, 0x2794,
- 0x2798, 0x27af,
- 0x27b1, 0x27be,
- 0x27c0, 0x27ca,
- 0x27cc, 0x27cc,
- 0x27d0, 0x2b4c,
- 0x2b50, 0x2b59,
- 0x2c00, 0x2c2e,
- 0x2c30, 0x2c5e,
- 0x2c60, 0x2cf1,
- 0x2cf9, 0x2d25,
- 0x2d30, 0x2d65,
- 0x2d6f, 0x2d6f,
- 0x2d80, 0x2d96,
- 0x2da0, 0x2da6,
- 0x2da8, 0x2dae,
- 0x2db0, 0x2db6,
- 0x2db8, 0x2dbe,
- 0x2dc0, 0x2dc6,
- 0x2dc8, 0x2dce,
- 0x2dd0, 0x2dd6,
- 0x2dd8, 0x2dde,
- 0x2de0, 0x2e31,
- 0x2e80, 0x2e99,
- 0x2e9b, 0x2ef3,
- 0x2f00, 0x2fd5,
- 0x2ff0, 0x2ffb,
- 0x3000, 0x303f,
- 0x3041, 0x3096,
- 0x3099, 0x30ff,
- 0x3105, 0x312d,
- 0x3131, 0x318e,
- 0x3190, 0x31b7,
- 0x31c0, 0x31e3,
- 0x31f0, 0x321e,
- 0x3220, 0x32fe,
- 0x3300, 0x4db5,
- 0x4dc0, 0x9fcb,
- 0xa000, 0xa48c,
- 0xa490, 0xa4c6,
- 0xa4d0, 0xa62b,
- 0xa640, 0xa65f,
- 0xa662, 0xa673,
- 0xa67c, 0xa697,
- 0xa6a0, 0xa6f7,
- 0xa700, 0xa78c,
- 0xa7fb, 0xa82b,
- 0xa830, 0xa839,
- 0xa840, 0xa877,
- 0xa880, 0xa8c4,
- 0xa8ce, 0xa8d9,
- 0xa8e0, 0xa8fb,
- 0xa900, 0xa953,
- 0xa95f, 0xa97c,
- 0xa980, 0xa9cd,
- 0xa9cf, 0xa9d9,
- 0xa9de, 0xa9df,
- 0xaa00, 0xaa36,
- 0xaa40, 0xaa4d,
- 0xaa50, 0xaa59,
- 0xaa5c, 0xaa7b,
- 0xaa80, 0xaac2,
- 0xaadb, 0xaadf,
- 0xabc0, 0xabed,
- 0xabf0, 0xabf9,
- 0xac00, 0xd7a3,
- 0xd7b0, 0xd7c6,
- 0xd7cb, 0xd7fb,
- 0xd800, 0xfa2d,
- 0xfa30, 0xfa6d,
- 0xfa70, 0xfad9,
- 0xfb00, 0xfb06,
- 0xfb13, 0xfb17,
- 0xfb1d, 0xfb36,
- 0xfb38, 0xfb3c,
- 0xfb3e, 0xfb3e,
- 0xfb40, 0xfb41,
- 0xfb43, 0xfb44,
- 0xfb46, 0xfbb1,
- 0xfbd3, 0xfd3f,
- 0xfd50, 0xfd8f,
- 0xfd92, 0xfdc7,
- 0xfdd0, 0xfdfd,
- 0xfe00, 0xfe19,
- 0xfe20, 0xfe26,
- 0xfe30, 0xfe52,
- 0xfe54, 0xfe66,
- 0xfe68, 0xfe6b,
- 0xfe70, 0xfe74,
- 0xfe76, 0xfefc,
- 0xfeff, 0xfeff,
- 0xff01, 0xffbe,
- 0xffc2, 0xffc7,
- 0xffca, 0xffcf,
- 0xffd2, 0xffd7,
- 0xffda, 0xffdc,
- 0xffe0, 0xffe6,
- 0xffe8, 0xffee,
- 0xfff9, 0x1000b,
- 0x1000d, 0x10026,
- 0x10028, 0x1003a,
- 0x1003c, 0x1003d,
- 0x1003f, 0x1004d,
- 0x10050, 0x1005d,
- 0x10080, 0x100fa,
- 0x10100, 0x10102,
- 0x10107, 0x10133,
- 0x10137, 0x1018a,
- 0x10190, 0x1019b,
- 0x101d0, 0x101fd,
- 0x10280, 0x1029c,
- 0x102a0, 0x102d0,
- 0x10300, 0x1031e,
- 0x10320, 0x10323,
- 0x10330, 0x1034a,
- 0x10380, 0x1039d,
- 0x1039f, 0x103c3,
- 0x103c8, 0x103d5,
- 0x10400, 0x1049d,
- 0x104a0, 0x104a9,
- 0x10800, 0x10805,
- 0x10808, 0x10808,
- 0x1080a, 0x10835,
- 0x10837, 0x10838,
- 0x1083c, 0x1083c,
- 0x1083f, 0x10855,
- 0x10857, 0x1085f,
- 0x10900, 0x1091b,
- 0x1091f, 0x10939,
- 0x1093f, 0x1093f,
- 0x10a00, 0x10a03,
- 0x10a05, 0x10a06,
- 0x10a0c, 0x10a13,
- 0x10a15, 0x10a17,
- 0x10a19, 0x10a33,
- 0x10a38, 0x10a3a,
- 0x10a3f, 0x10a47,
- 0x10a50, 0x10a58,
- 0x10a60, 0x10a7f,
- 0x10b00, 0x10b35,
- 0x10b39, 0x10b55,
- 0x10b58, 0x10b72,
- 0x10b78, 0x10b7f,
- 0x10c00, 0x10c48,
- 0x10e60, 0x10e7e,
- 0x11080, 0x110c1,
- 0x12000, 0x1236e,
- 0x12400, 0x12462,
- 0x12470, 0x12473,
- 0x13000, 0x1342e,
- 0x1d000, 0x1d0f5,
- 0x1d100, 0x1d126,
- 0x1d129, 0x1d1dd,
- 0x1d200, 0x1d245,
- 0x1d300, 0x1d356,
- 0x1d360, 0x1d371,
- 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, 0x1d7cb,
- 0x1d7ce, 0x1d7ff,
- 0x1f000, 0x1f02b,
- 0x1f030, 0x1f093,
- 0x1f100, 0x1f10a,
- 0x1f110, 0x1f12e,
- 0x1f131, 0x1f131,
- 0x1f13d, 0x1f13d,
- 0x1f13f, 0x1f13f,
- 0x1f142, 0x1f142,
- 0x1f146, 0x1f146,
- 0x1f14a, 0x1f14e,
- 0x1f157, 0x1f157,
- 0x1f15f, 0x1f15f,
- 0x1f179, 0x1f179,
- 0x1f17b, 0x1f17c,
- 0x1f17f, 0x1f17f,
- 0x1f18a, 0x1f18d,
- 0x1f190, 0x1f190,
- 0x1f200, 0x1f200,
- 0x1f210, 0x1f231,
- 0x1f240, 0x1f248,
- 0x1fffe, 0x2a6d6,
- 0x2a700, 0x2b734,
- 0x2f800, 0x2fa1d,
- 0x2fffe, 0x2ffff,
- 0x3fffe, 0x3ffff,
- 0x4fffe, 0x4ffff,
- 0x5fffe, 0x5ffff,
- 0x6fffe, 0x6ffff,
- 0x7fffe, 0x7ffff,
- 0x8fffe, 0x8ffff,
- 0x9fffe, 0x9ffff,
- 0xafffe, 0xaffff,
- 0xbfffe, 0xbffff,
- 0xcfffe, 0xcffff,
- 0xdfffe, 0xdffff,
- 0xe0001, 0xe0001,
- 0xe0020, 0xe007f,
- 0xe0100, 0xe01ef,
- 0xefffe, 0x10ffff,
-}; /* CR_Age_5_2 */
-
-/* 'Age_6_0': Derived Age 6.0 */
-static const OnigCodePoint CR_Age_6_0[] = {
- 511,
- 0x0000, 0x0377,
- 0x037a, 0x037e,
- 0x0384, 0x038a,
- 0x038c, 0x038c,
- 0x038e, 0x03a1,
- 0x03a3, 0x0527,
- 0x0531, 0x0556,
- 0x0559, 0x055f,
- 0x0561, 0x0587,
- 0x0589, 0x058a,
- 0x0591, 0x05c7,
- 0x05d0, 0x05ea,
- 0x05f0, 0x05f4,
- 0x0600, 0x0603,
- 0x0606, 0x061b,
- 0x061e, 0x070d,
- 0x070f, 0x074a,
- 0x074d, 0x07b1,
- 0x07c0, 0x07fa,
- 0x0800, 0x082d,
- 0x0830, 0x083e,
- 0x0840, 0x085b,
- 0x085e, 0x085e,
- 0x0900, 0x0977,
- 0x0979, 0x097f,
- 0x0981, 0x0983,
- 0x0985, 0x098c,
- 0x098f, 0x0990,
- 0x0993, 0x09a8,
- 0x09aa, 0x09b0,
- 0x09b2, 0x09b2,
- 0x09b6, 0x09b9,
- 0x09bc, 0x09c4,
- 0x09c7, 0x09c8,
- 0x09cb, 0x09ce,
- 0x09d7, 0x09d7,
- 0x09dc, 0x09dd,
- 0x09df, 0x09e3,
- 0x09e6, 0x09fb,
- 0x0a01, 0x0a03,
- 0x0a05, 0x0a0a,
- 0x0a0f, 0x0a10,
- 0x0a13, 0x0a28,
- 0x0a2a, 0x0a30,
- 0x0a32, 0x0a33,
- 0x0a35, 0x0a36,
- 0x0a38, 0x0a39,
- 0x0a3c, 0x0a3c,
- 0x0a3e, 0x0a42,
- 0x0a47, 0x0a48,
- 0x0a4b, 0x0a4d,
- 0x0a51, 0x0a51,
- 0x0a59, 0x0a5c,
- 0x0a5e, 0x0a5e,
- 0x0a66, 0x0a75,
- 0x0a81, 0x0a83,
- 0x0a85, 0x0a8d,
- 0x0a8f, 0x0a91,
- 0x0a93, 0x0aa8,
- 0x0aaa, 0x0ab0,
- 0x0ab2, 0x0ab3,
- 0x0ab5, 0x0ab9,
- 0x0abc, 0x0ac5,
- 0x0ac7, 0x0ac9,
- 0x0acb, 0x0acd,
- 0x0ad0, 0x0ad0,
- 0x0ae0, 0x0ae3,
- 0x0ae6, 0x0aef,
- 0x0af1, 0x0af1,
- 0x0b01, 0x0b03,
- 0x0b05, 0x0b0c,
- 0x0b0f, 0x0b10,
- 0x0b13, 0x0b28,
- 0x0b2a, 0x0b30,
- 0x0b32, 0x0b33,
- 0x0b35, 0x0b39,
- 0x0b3c, 0x0b44,
- 0x0b47, 0x0b48,
- 0x0b4b, 0x0b4d,
- 0x0b56, 0x0b57,
- 0x0b5c, 0x0b5d,
- 0x0b5f, 0x0b63,
- 0x0b66, 0x0b77,
- 0x0b82, 0x0b83,
- 0x0b85, 0x0b8a,
- 0x0b8e, 0x0b90,
- 0x0b92, 0x0b95,
- 0x0b99, 0x0b9a,
- 0x0b9c, 0x0b9c,
- 0x0b9e, 0x0b9f,
- 0x0ba3, 0x0ba4,
- 0x0ba8, 0x0baa,
- 0x0bae, 0x0bb9,
- 0x0bbe, 0x0bc2,
- 0x0bc6, 0x0bc8,
- 0x0bca, 0x0bcd,
- 0x0bd0, 0x0bd0,
- 0x0bd7, 0x0bd7,
- 0x0be6, 0x0bfa,
- 0x0c01, 0x0c03,
- 0x0c05, 0x0c0c,
- 0x0c0e, 0x0c10,
- 0x0c12, 0x0c28,
- 0x0c2a, 0x0c33,
- 0x0c35, 0x0c39,
- 0x0c3d, 0x0c44,
- 0x0c46, 0x0c48,
- 0x0c4a, 0x0c4d,
- 0x0c55, 0x0c56,
- 0x0c58, 0x0c59,
- 0x0c60, 0x0c63,
- 0x0c66, 0x0c6f,
- 0x0c78, 0x0c7f,
- 0x0c82, 0x0c83,
- 0x0c85, 0x0c8c,
- 0x0c8e, 0x0c90,
- 0x0c92, 0x0ca8,
- 0x0caa, 0x0cb3,
- 0x0cb5, 0x0cb9,
- 0x0cbc, 0x0cc4,
- 0x0cc6, 0x0cc8,
- 0x0cca, 0x0ccd,
- 0x0cd5, 0x0cd6,
- 0x0cde, 0x0cde,
- 0x0ce0, 0x0ce3,
- 0x0ce6, 0x0cef,
- 0x0cf1, 0x0cf2,
- 0x0d02, 0x0d03,
- 0x0d05, 0x0d0c,
- 0x0d0e, 0x0d10,
- 0x0d12, 0x0d3a,
- 0x0d3d, 0x0d44,
- 0x0d46, 0x0d48,
- 0x0d4a, 0x0d4e,
- 0x0d57, 0x0d57,
- 0x0d60, 0x0d63,
- 0x0d66, 0x0d75,
- 0x0d79, 0x0d7f,
- 0x0d82, 0x0d83,
- 0x0d85, 0x0d96,
- 0x0d9a, 0x0db1,
- 0x0db3, 0x0dbb,
- 0x0dbd, 0x0dbd,
- 0x0dc0, 0x0dc6,
- 0x0dca, 0x0dca,
- 0x0dcf, 0x0dd4,
- 0x0dd6, 0x0dd6,
- 0x0dd8, 0x0ddf,
- 0x0df2, 0x0df4,
- 0x0e01, 0x0e3a,
- 0x0e3f, 0x0e5b,
- 0x0e81, 0x0e82,
- 0x0e84, 0x0e84,
- 0x0e87, 0x0e88,
- 0x0e8a, 0x0e8a,
- 0x0e8d, 0x0e8d,
- 0x0e94, 0x0e97,
- 0x0e99, 0x0e9f,
- 0x0ea1, 0x0ea3,
- 0x0ea5, 0x0ea5,
- 0x0ea7, 0x0ea7,
- 0x0eaa, 0x0eab,
- 0x0ead, 0x0eb9,
- 0x0ebb, 0x0ebd,
- 0x0ec0, 0x0ec4,
- 0x0ec6, 0x0ec6,
- 0x0ec8, 0x0ecd,
- 0x0ed0, 0x0ed9,
- 0x0edc, 0x0edd,
- 0x0f00, 0x0f47,
- 0x0f49, 0x0f6c,
- 0x0f71, 0x0f97,
- 0x0f99, 0x0fbc,
- 0x0fbe, 0x0fcc,
- 0x0fce, 0x0fda,
- 0x1000, 0x10c5,
- 0x10d0, 0x10fc,
- 0x1100, 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,
- 0x135d, 0x137c,
- 0x1380, 0x1399,
- 0x13a0, 0x13f4,
- 0x1400, 0x169c,
- 0x16a0, 0x16f0,
- 0x1700, 0x170c,
- 0x170e, 0x1714,
- 0x1720, 0x1736,
- 0x1740, 0x1753,
- 0x1760, 0x176c,
- 0x176e, 0x1770,
- 0x1772, 0x1773,
- 0x1780, 0x17dd,
- 0x17e0, 0x17e9,
- 0x17f0, 0x17f9,
- 0x1800, 0x180e,
- 0x1810, 0x1819,
- 0x1820, 0x1877,
- 0x1880, 0x18aa,
- 0x18b0, 0x18f5,
- 0x1900, 0x191c,
- 0x1920, 0x192b,
- 0x1930, 0x193b,
- 0x1940, 0x1940,
- 0x1944, 0x196d,
- 0x1970, 0x1974,
- 0x1980, 0x19ab,
- 0x19b0, 0x19c9,
- 0x19d0, 0x19da,
- 0x19de, 0x1a1b,
- 0x1a1e, 0x1a5e,
- 0x1a60, 0x1a7c,
- 0x1a7f, 0x1a89,
- 0x1a90, 0x1a99,
- 0x1aa0, 0x1aad,
- 0x1b00, 0x1b4b,
- 0x1b50, 0x1b7c,
- 0x1b80, 0x1baa,
- 0x1bae, 0x1bb9,
- 0x1bc0, 0x1bf3,
- 0x1bfc, 0x1c37,
- 0x1c3b, 0x1c49,
- 0x1c4d, 0x1c7f,
- 0x1cd0, 0x1cf2,
- 0x1d00, 0x1de6,
- 0x1dfc, 0x1f15,
- 0x1f18, 0x1f1d,
- 0x1f20, 0x1f45,
- 0x1f48, 0x1f4d,
- 0x1f50, 0x1f57,
- 0x1f59, 0x1f59,
- 0x1f5b, 0x1f5b,
- 0x1f5d, 0x1f5d,
- 0x1f5f, 0x1f7d,
- 0x1f80, 0x1fb4,
- 0x1fb6, 0x1fc4,
- 0x1fc6, 0x1fd3,
- 0x1fd6, 0x1fdb,
- 0x1fdd, 0x1fef,
- 0x1ff2, 0x1ff4,
- 0x1ff6, 0x1ffe,
- 0x2000, 0x2064,
- 0x206a, 0x2071,
- 0x2074, 0x208e,
- 0x2090, 0x209c,
- 0x20a0, 0x20b9,
- 0x20d0, 0x20f0,
- 0x2100, 0x2189,
- 0x2190, 0x23f3,
- 0x2400, 0x2426,
- 0x2440, 0x244a,
- 0x2460, 0x26ff,
- 0x2701, 0x27ca,
- 0x27cc, 0x27cc,
- 0x27ce, 0x2b4c,
- 0x2b50, 0x2b59,
- 0x2c00, 0x2c2e,
- 0x2c30, 0x2c5e,
- 0x2c60, 0x2cf1,
- 0x2cf9, 0x2d25,
- 0x2d30, 0x2d65,
- 0x2d6f, 0x2d70,
- 0x2d7f, 0x2d96,
- 0x2da0, 0x2da6,
- 0x2da8, 0x2dae,
- 0x2db0, 0x2db6,
- 0x2db8, 0x2dbe,
- 0x2dc0, 0x2dc6,
- 0x2dc8, 0x2dce,
- 0x2dd0, 0x2dd6,
- 0x2dd8, 0x2dde,
- 0x2de0, 0x2e31,
- 0x2e80, 0x2e99,
- 0x2e9b, 0x2ef3,
- 0x2f00, 0x2fd5,
- 0x2ff0, 0x2ffb,
- 0x3000, 0x303f,
- 0x3041, 0x3096,
- 0x3099, 0x30ff,
- 0x3105, 0x312d,
- 0x3131, 0x318e,
- 0x3190, 0x31ba,
- 0x31c0, 0x31e3,
- 0x31f0, 0x321e,
- 0x3220, 0x32fe,
- 0x3300, 0x4db5,
- 0x4dc0, 0x9fcb,
- 0xa000, 0xa48c,
- 0xa490, 0xa4c6,
- 0xa4d0, 0xa62b,
- 0xa640, 0xa673,
- 0xa67c, 0xa697,
- 0xa6a0, 0xa6f7,
- 0xa700, 0xa78e,
- 0xa790, 0xa791,
- 0xa7a0, 0xa7a9,
- 0xa7fa, 0xa82b,
- 0xa830, 0xa839,
- 0xa840, 0xa877,
- 0xa880, 0xa8c4,
- 0xa8ce, 0xa8d9,
- 0xa8e0, 0xa8fb,
- 0xa900, 0xa953,
- 0xa95f, 0xa97c,
- 0xa980, 0xa9cd,
- 0xa9cf, 0xa9d9,
- 0xa9de, 0xa9df,
- 0xaa00, 0xaa36,
- 0xaa40, 0xaa4d,
- 0xaa50, 0xaa59,
- 0xaa5c, 0xaa7b,
- 0xaa80, 0xaac2,
- 0xaadb, 0xaadf,
- 0xab01, 0xab06,
- 0xab09, 0xab0e,
- 0xab11, 0xab16,
- 0xab20, 0xab26,
- 0xab28, 0xab2e,
- 0xabc0, 0xabed,
- 0xabf0, 0xabf9,
- 0xac00, 0xd7a3,
- 0xd7b0, 0xd7c6,
- 0xd7cb, 0xd7fb,
- 0xd800, 0xfa2d,
- 0xfa30, 0xfa6d,
- 0xfa70, 0xfad9,
- 0xfb00, 0xfb06,
- 0xfb13, 0xfb17,
- 0xfb1d, 0xfb36,
- 0xfb38, 0xfb3c,
- 0xfb3e, 0xfb3e,
- 0xfb40, 0xfb41,
- 0xfb43, 0xfb44,
- 0xfb46, 0xfbc1,
- 0xfbd3, 0xfd3f,
- 0xfd50, 0xfd8f,
- 0xfd92, 0xfdc7,
- 0xfdd0, 0xfdfd,
- 0xfe00, 0xfe19,
- 0xfe20, 0xfe26,
- 0xfe30, 0xfe52,
- 0xfe54, 0xfe66,
- 0xfe68, 0xfe6b,
- 0xfe70, 0xfe74,
- 0xfe76, 0xfefc,
- 0xfeff, 0xfeff,
- 0xff01, 0xffbe,
- 0xffc2, 0xffc7,
- 0xffca, 0xffcf,
- 0xffd2, 0xffd7,
- 0xffda, 0xffdc,
- 0xffe0, 0xffe6,
- 0xffe8, 0xffee,
- 0xfff9, 0x1000b,
- 0x1000d, 0x10026,
- 0x10028, 0x1003a,
- 0x1003c, 0x1003d,
- 0x1003f, 0x1004d,
- 0x10050, 0x1005d,
- 0x10080, 0x100fa,
- 0x10100, 0x10102,
- 0x10107, 0x10133,
- 0x10137, 0x1018a,
- 0x10190, 0x1019b,
- 0x101d0, 0x101fd,
- 0x10280, 0x1029c,
- 0x102a0, 0x102d0,
- 0x10300, 0x1031e,
- 0x10320, 0x10323,
- 0x10330, 0x1034a,
- 0x10380, 0x1039d,
- 0x1039f, 0x103c3,
- 0x103c8, 0x103d5,
- 0x10400, 0x1049d,
- 0x104a0, 0x104a9,
- 0x10800, 0x10805,
- 0x10808, 0x10808,
- 0x1080a, 0x10835,
- 0x10837, 0x10838,
- 0x1083c, 0x1083c,
- 0x1083f, 0x10855,
- 0x10857, 0x1085f,
- 0x10900, 0x1091b,
- 0x1091f, 0x10939,
- 0x1093f, 0x1093f,
- 0x10a00, 0x10a03,
- 0x10a05, 0x10a06,
- 0x10a0c, 0x10a13,
- 0x10a15, 0x10a17,
- 0x10a19, 0x10a33,
- 0x10a38, 0x10a3a,
- 0x10a3f, 0x10a47,
- 0x10a50, 0x10a58,
- 0x10a60, 0x10a7f,
- 0x10b00, 0x10b35,
- 0x10b39, 0x10b55,
- 0x10b58, 0x10b72,
- 0x10b78, 0x10b7f,
- 0x10c00, 0x10c48,
- 0x10e60, 0x10e7e,
- 0x11000, 0x1104d,
- 0x11052, 0x1106f,
- 0x11080, 0x110c1,
- 0x12000, 0x1236e,
- 0x12400, 0x12462,
- 0x12470, 0x12473,
- 0x13000, 0x1342e,
- 0x16800, 0x16a38,
- 0x1b000, 0x1b001,
- 0x1d000, 0x1d0f5,
- 0x1d100, 0x1d126,
- 0x1d129, 0x1d1dd,
- 0x1d200, 0x1d245,
- 0x1d300, 0x1d356,
- 0x1d360, 0x1d371,
- 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, 0x1d7cb,
- 0x1d7ce, 0x1d7ff,
- 0x1f000, 0x1f02b,
- 0x1f030, 0x1f093,
- 0x1f0a0, 0x1f0ae,
- 0x1f0b1, 0x1f0be,
- 0x1f0c1, 0x1f0cf,
- 0x1f0d1, 0x1f0df,
- 0x1f100, 0x1f10a,
- 0x1f110, 0x1f12e,
- 0x1f130, 0x1f169,
- 0x1f170, 0x1f19a,
- 0x1f1e6, 0x1f202,
- 0x1f210, 0x1f23a,
- 0x1f240, 0x1f248,
- 0x1f250, 0x1f251,
- 0x1f300, 0x1f320,
- 0x1f330, 0x1f335,
- 0x1f337, 0x1f37c,
- 0x1f380, 0x1f393,
- 0x1f3a0, 0x1f3c4,
- 0x1f3c6, 0x1f3ca,
- 0x1f3e0, 0x1f3f0,
- 0x1f400, 0x1f43e,
- 0x1f440, 0x1f440,
- 0x1f442, 0x1f4f7,
- 0x1f4f9, 0x1f4fc,
- 0x1f500, 0x1f53d,
- 0x1f550, 0x1f567,
- 0x1f5fb, 0x1f5ff,
- 0x1f601, 0x1f610,
- 0x1f612, 0x1f614,
- 0x1f616, 0x1f616,
- 0x1f618, 0x1f618,
- 0x1f61a, 0x1f61a,
- 0x1f61c, 0x1f61e,
- 0x1f620, 0x1f625,
- 0x1f628, 0x1f62b,
- 0x1f62d, 0x1f62d,
- 0x1f630, 0x1f633,
- 0x1f635, 0x1f640,
- 0x1f645, 0x1f64f,
- 0x1f680, 0x1f6c5,
- 0x1f700, 0x1f773,
- 0x1fffe, 0x2a6d6,
- 0x2a700, 0x2b734,
- 0x2b740, 0x2b81d,
- 0x2f800, 0x2fa1d,
- 0x2fffe, 0x2ffff,
- 0x3fffe, 0x3ffff,
- 0x4fffe, 0x4ffff,
- 0x5fffe, 0x5ffff,
- 0x6fffe, 0x6ffff,
- 0x7fffe, 0x7ffff,
- 0x8fffe, 0x8ffff,
- 0x9fffe, 0x9ffff,
- 0xafffe, 0xaffff,
- 0xbfffe, 0xbffff,
- 0xcfffe, 0xcffff,
- 0xdfffe, 0xdffff,
- 0xe0001, 0xe0001,
- 0xe0020, 0xe007f,
- 0xe0100, 0xe01ef,
- 0xefffe, 0x10ffff,
-}; /* CR_Age_6_0 */
-
-/* 'Age_6_1': Derived Age 6.1 */
-static const OnigCodePoint CR_Age_6_1[] = {
- 549,
- 0x0000, 0x0377,
- 0x037a, 0x037e,
- 0x0384, 0x038a,
- 0x038c, 0x038c,
- 0x038e, 0x03a1,
- 0x03a3, 0x0527,
- 0x0531, 0x0556,
- 0x0559, 0x055f,
- 0x0561, 0x0587,
- 0x0589, 0x058a,
- 0x058f, 0x058f,
- 0x0591, 0x05c7,
- 0x05d0, 0x05ea,
- 0x05f0, 0x05f4,
- 0x0600, 0x0604,
- 0x0606, 0x061b,
- 0x061e, 0x070d,
- 0x070f, 0x074a,
- 0x074d, 0x07b1,
- 0x07c0, 0x07fa,
- 0x0800, 0x082d,
- 0x0830, 0x083e,
- 0x0840, 0x085b,
- 0x085e, 0x085e,
- 0x08a0, 0x08a0,
- 0x08a2, 0x08ac,
- 0x08e4, 0x08fe,
- 0x0900, 0x0977,
- 0x0979, 0x097f,
- 0x0981, 0x0983,
- 0x0985, 0x098c,
- 0x098f, 0x0990,
- 0x0993, 0x09a8,
- 0x09aa, 0x09b0,
- 0x09b2, 0x09b2,
- 0x09b6, 0x09b9,
- 0x09bc, 0x09c4,
- 0x09c7, 0x09c8,
- 0x09cb, 0x09ce,
- 0x09d7, 0x09d7,
- 0x09dc, 0x09dd,
- 0x09df, 0x09e3,
- 0x09e6, 0x09fb,
- 0x0a01, 0x0a03,
- 0x0a05, 0x0a0a,
- 0x0a0f, 0x0a10,
- 0x0a13, 0x0a28,
- 0x0a2a, 0x0a30,
- 0x0a32, 0x0a33,
- 0x0a35, 0x0a36,
- 0x0a38, 0x0a39,
- 0x0a3c, 0x0a3c,
- 0x0a3e, 0x0a42,
- 0x0a47, 0x0a48,
- 0x0a4b, 0x0a4d,
- 0x0a51, 0x0a51,
- 0x0a59, 0x0a5c,
- 0x0a5e, 0x0a5e,
- 0x0a66, 0x0a75,
- 0x0a81, 0x0a83,
- 0x0a85, 0x0a8d,
- 0x0a8f, 0x0a91,
- 0x0a93, 0x0aa8,
- 0x0aaa, 0x0ab0,
- 0x0ab2, 0x0ab3,
- 0x0ab5, 0x0ab9,
- 0x0abc, 0x0ac5,
- 0x0ac7, 0x0ac9,
- 0x0acb, 0x0acd,
- 0x0ad0, 0x0ad0,
- 0x0ae0, 0x0ae3,
- 0x0ae6, 0x0af1,
- 0x0b01, 0x0b03,
- 0x0b05, 0x0b0c,
- 0x0b0f, 0x0b10,
- 0x0b13, 0x0b28,
- 0x0b2a, 0x0b30,
- 0x0b32, 0x0b33,
- 0x0b35, 0x0b39,
- 0x0b3c, 0x0b44,
- 0x0b47, 0x0b48,
- 0x0b4b, 0x0b4d,
- 0x0b56, 0x0b57,
- 0x0b5c, 0x0b5d,
- 0x0b5f, 0x0b63,
- 0x0b66, 0x0b77,
- 0x0b82, 0x0b83,
- 0x0b85, 0x0b8a,
- 0x0b8e, 0x0b90,
- 0x0b92, 0x0b95,
- 0x0b99, 0x0b9a,
- 0x0b9c, 0x0b9c,
- 0x0b9e, 0x0b9f,
- 0x0ba3, 0x0ba4,
- 0x0ba8, 0x0baa,
- 0x0bae, 0x0bb9,
- 0x0bbe, 0x0bc2,
- 0x0bc6, 0x0bc8,
- 0x0bca, 0x0bcd,
- 0x0bd0, 0x0bd0,
- 0x0bd7, 0x0bd7,
- 0x0be6, 0x0bfa,
- 0x0c01, 0x0c03,
- 0x0c05, 0x0c0c,
- 0x0c0e, 0x0c10,
- 0x0c12, 0x0c28,
- 0x0c2a, 0x0c33,
- 0x0c35, 0x0c39,
- 0x0c3d, 0x0c44,
- 0x0c46, 0x0c48,
- 0x0c4a, 0x0c4d,
- 0x0c55, 0x0c56,
- 0x0c58, 0x0c59,
- 0x0c60, 0x0c63,
- 0x0c66, 0x0c6f,
- 0x0c78, 0x0c7f,
- 0x0c82, 0x0c83,
- 0x0c85, 0x0c8c,
- 0x0c8e, 0x0c90,
- 0x0c92, 0x0ca8,
- 0x0caa, 0x0cb3,
- 0x0cb5, 0x0cb9,
- 0x0cbc, 0x0cc4,
- 0x0cc6, 0x0cc8,
- 0x0cca, 0x0ccd,
- 0x0cd5, 0x0cd6,
- 0x0cde, 0x0cde,
- 0x0ce0, 0x0ce3,
- 0x0ce6, 0x0cef,
- 0x0cf1, 0x0cf2,
- 0x0d02, 0x0d03,
- 0x0d05, 0x0d0c,
- 0x0d0e, 0x0d10,
- 0x0d12, 0x0d3a,
- 0x0d3d, 0x0d44,
- 0x0d46, 0x0d48,
- 0x0d4a, 0x0d4e,
- 0x0d57, 0x0d57,
- 0x0d60, 0x0d63,
- 0x0d66, 0x0d75,
- 0x0d79, 0x0d7f,
- 0x0d82, 0x0d83,
- 0x0d85, 0x0d96,
- 0x0d9a, 0x0db1,
- 0x0db3, 0x0dbb,
- 0x0dbd, 0x0dbd,
- 0x0dc0, 0x0dc6,
- 0x0dca, 0x0dca,
- 0x0dcf, 0x0dd4,
- 0x0dd6, 0x0dd6,
- 0x0dd8, 0x0ddf,
- 0x0df2, 0x0df4,
- 0x0e01, 0x0e3a,
- 0x0e3f, 0x0e5b,
- 0x0e81, 0x0e82,
- 0x0e84, 0x0e84,
- 0x0e87, 0x0e88,
- 0x0e8a, 0x0e8a,
- 0x0e8d, 0x0e8d,
- 0x0e94, 0x0e97,
- 0x0e99, 0x0e9f,
- 0x0ea1, 0x0ea3,
- 0x0ea5, 0x0ea5,
- 0x0ea7, 0x0ea7,
- 0x0eaa, 0x0eab,
- 0x0ead, 0x0eb9,
- 0x0ebb, 0x0ebd,
- 0x0ec0, 0x0ec4,
- 0x0ec6, 0x0ec6,
- 0x0ec8, 0x0ecd,
- 0x0ed0, 0x0ed9,
- 0x0edc, 0x0edf,
- 0x0f00, 0x0f47,
- 0x0f49, 0x0f6c,
- 0x0f71, 0x0f97,
- 0x0f99, 0x0fbc,
- 0x0fbe, 0x0fcc,
- 0x0fce, 0x0fda,
- 0x1000, 0x10c5,
- 0x10c7, 0x10c7,
- 0x10cd, 0x10cd,
- 0x10d0, 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,
- 0x135d, 0x137c,
- 0x1380, 0x1399,
- 0x13a0, 0x13f4,
- 0x1400, 0x169c,
- 0x16a0, 0x16f0,
- 0x1700, 0x170c,
- 0x170e, 0x1714,
- 0x1720, 0x1736,
- 0x1740, 0x1753,
- 0x1760, 0x176c,
- 0x176e, 0x1770,
- 0x1772, 0x1773,
- 0x1780, 0x17dd,
- 0x17e0, 0x17e9,
- 0x17f0, 0x17f9,
- 0x1800, 0x180e,
- 0x1810, 0x1819,
- 0x1820, 0x1877,
- 0x1880, 0x18aa,
- 0x18b0, 0x18f5,
- 0x1900, 0x191c,
- 0x1920, 0x192b,
- 0x1930, 0x193b,
- 0x1940, 0x1940,
- 0x1944, 0x196d,
- 0x1970, 0x1974,
- 0x1980, 0x19ab,
- 0x19b0, 0x19c9,
- 0x19d0, 0x19da,
- 0x19de, 0x1a1b,
- 0x1a1e, 0x1a5e,
- 0x1a60, 0x1a7c,
- 0x1a7f, 0x1a89,
- 0x1a90, 0x1a99,
- 0x1aa0, 0x1aad,
- 0x1b00, 0x1b4b,
- 0x1b50, 0x1b7c,
- 0x1b80, 0x1bf3,
- 0x1bfc, 0x1c37,
- 0x1c3b, 0x1c49,
- 0x1c4d, 0x1c7f,
- 0x1cc0, 0x1cc7,
- 0x1cd0, 0x1cf6,
- 0x1d00, 0x1de6,
- 0x1dfc, 0x1f15,
- 0x1f18, 0x1f1d,
- 0x1f20, 0x1f45,
- 0x1f48, 0x1f4d,
- 0x1f50, 0x1f57,
- 0x1f59, 0x1f59,
- 0x1f5b, 0x1f5b,
- 0x1f5d, 0x1f5d,
- 0x1f5f, 0x1f7d,
- 0x1f80, 0x1fb4,
- 0x1fb6, 0x1fc4,
- 0x1fc6, 0x1fd3,
- 0x1fd6, 0x1fdb,
- 0x1fdd, 0x1fef,
- 0x1ff2, 0x1ff4,
- 0x1ff6, 0x1ffe,
- 0x2000, 0x2064,
- 0x206a, 0x2071,
- 0x2074, 0x208e,
- 0x2090, 0x209c,
- 0x20a0, 0x20b9,
- 0x20d0, 0x20f0,
- 0x2100, 0x2189,
- 0x2190, 0x23f3,
- 0x2400, 0x2426,
- 0x2440, 0x244a,
- 0x2460, 0x26ff,
- 0x2701, 0x2b4c,
- 0x2b50, 0x2b59,
- 0x2c00, 0x2c2e,
- 0x2c30, 0x2c5e,
- 0x2c60, 0x2cf3,
- 0x2cf9, 0x2d25,
- 0x2d27, 0x2d27,
- 0x2d2d, 0x2d2d,
- 0x2d30, 0x2d67,
- 0x2d6f, 0x2d70,
- 0x2d7f, 0x2d96,
- 0x2da0, 0x2da6,
- 0x2da8, 0x2dae,
- 0x2db0, 0x2db6,
- 0x2db8, 0x2dbe,
- 0x2dc0, 0x2dc6,
- 0x2dc8, 0x2dce,
- 0x2dd0, 0x2dd6,
- 0x2dd8, 0x2dde,
- 0x2de0, 0x2e3b,
- 0x2e80, 0x2e99,
- 0x2e9b, 0x2ef3,
- 0x2f00, 0x2fd5,
- 0x2ff0, 0x2ffb,
- 0x3000, 0x303f,
- 0x3041, 0x3096,
- 0x3099, 0x30ff,
- 0x3105, 0x312d,
- 0x3131, 0x318e,
- 0x3190, 0x31ba,
- 0x31c0, 0x31e3,
- 0x31f0, 0x321e,
- 0x3220, 0x32fe,
- 0x3300, 0x4db5,
- 0x4dc0, 0x9fcc,
- 0xa000, 0xa48c,
- 0xa490, 0xa4c6,
- 0xa4d0, 0xa62b,
- 0xa640, 0xa697,
- 0xa69f, 0xa6f7,
- 0xa700, 0xa78e,
- 0xa790, 0xa793,
- 0xa7a0, 0xa7aa,
- 0xa7f8, 0xa82b,
- 0xa830, 0xa839,
- 0xa840, 0xa877,
- 0xa880, 0xa8c4,
- 0xa8ce, 0xa8d9,
- 0xa8e0, 0xa8fb,
- 0xa900, 0xa953,
- 0xa95f, 0xa97c,
- 0xa980, 0xa9cd,
- 0xa9cf, 0xa9d9,
- 0xa9de, 0xa9df,
- 0xaa00, 0xaa36,
- 0xaa40, 0xaa4d,
- 0xaa50, 0xaa59,
- 0xaa5c, 0xaa7b,
- 0xaa80, 0xaac2,
- 0xaadb, 0xaaf6,
- 0xab01, 0xab06,
- 0xab09, 0xab0e,
- 0xab11, 0xab16,
- 0xab20, 0xab26,
- 0xab28, 0xab2e,
- 0xabc0, 0xabed,
- 0xabf0, 0xabf9,
- 0xac00, 0xd7a3,
- 0xd7b0, 0xd7c6,
- 0xd7cb, 0xd7fb,
- 0xd800, 0xfa6d,
- 0xfa70, 0xfad9,
- 0xfb00, 0xfb06,
- 0xfb13, 0xfb17,
- 0xfb1d, 0xfb36,
- 0xfb38, 0xfb3c,
- 0xfb3e, 0xfb3e,
- 0xfb40, 0xfb41,
- 0xfb43, 0xfb44,
- 0xfb46, 0xfbc1,
- 0xfbd3, 0xfd3f,
- 0xfd50, 0xfd8f,
- 0xfd92, 0xfdc7,
- 0xfdd0, 0xfdfd,
- 0xfe00, 0xfe19,
- 0xfe20, 0xfe26,
- 0xfe30, 0xfe52,
- 0xfe54, 0xfe66,
- 0xfe68, 0xfe6b,
- 0xfe70, 0xfe74,
- 0xfe76, 0xfefc,
- 0xfeff, 0xfeff,
- 0xff01, 0xffbe,
- 0xffc2, 0xffc7,
- 0xffca, 0xffcf,
- 0xffd2, 0xffd7,
- 0xffda, 0xffdc,
- 0xffe0, 0xffe6,
- 0xffe8, 0xffee,
- 0xfff9, 0x1000b,
- 0x1000d, 0x10026,
- 0x10028, 0x1003a,
- 0x1003c, 0x1003d,
- 0x1003f, 0x1004d,
- 0x10050, 0x1005d,
- 0x10080, 0x100fa,
- 0x10100, 0x10102,
- 0x10107, 0x10133,
- 0x10137, 0x1018a,
- 0x10190, 0x1019b,
- 0x101d0, 0x101fd,
- 0x10280, 0x1029c,
- 0x102a0, 0x102d0,
- 0x10300, 0x1031e,
- 0x10320, 0x10323,
- 0x10330, 0x1034a,
- 0x10380, 0x1039d,
- 0x1039f, 0x103c3,
- 0x103c8, 0x103d5,
- 0x10400, 0x1049d,
- 0x104a0, 0x104a9,
- 0x10800, 0x10805,
- 0x10808, 0x10808,
- 0x1080a, 0x10835,
- 0x10837, 0x10838,
- 0x1083c, 0x1083c,
- 0x1083f, 0x10855,
- 0x10857, 0x1085f,
- 0x10900, 0x1091b,
- 0x1091f, 0x10939,
- 0x1093f, 0x1093f,
- 0x10980, 0x109b7,
- 0x109be, 0x109bf,
- 0x10a00, 0x10a03,
- 0x10a05, 0x10a06,
- 0x10a0c, 0x10a13,
- 0x10a15, 0x10a17,
- 0x10a19, 0x10a33,
- 0x10a38, 0x10a3a,
- 0x10a3f, 0x10a47,
- 0x10a50, 0x10a58,
- 0x10a60, 0x10a7f,
- 0x10b00, 0x10b35,
- 0x10b39, 0x10b55,
- 0x10b58, 0x10b72,
- 0x10b78, 0x10b7f,
- 0x10c00, 0x10c48,
- 0x10e60, 0x10e7e,
- 0x11000, 0x1104d,
- 0x11052, 0x1106f,
- 0x11080, 0x110c1,
- 0x110d0, 0x110e8,
- 0x110f0, 0x110f9,
- 0x11100, 0x11134,
- 0x11136, 0x11143,
- 0x11180, 0x111c8,
- 0x111d0, 0x111d9,
- 0x11680, 0x116b7,
- 0x116c0, 0x116c9,
- 0x12000, 0x1236e,
- 0x12400, 0x12462,
- 0x12470, 0x12473,
- 0x13000, 0x1342e,
- 0x16800, 0x16a38,
- 0x16f00, 0x16f44,
- 0x16f50, 0x16f7e,
- 0x16f8f, 0x16f9f,
- 0x1b000, 0x1b001,
- 0x1d000, 0x1d0f5,
- 0x1d100, 0x1d126,
- 0x1d129, 0x1d1dd,
- 0x1d200, 0x1d245,
- 0x1d300, 0x1d356,
- 0x1d360, 0x1d371,
- 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, 0x1d7cb,
- 0x1d7ce, 0x1d7ff,
- 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,
- 0x1eef0, 0x1eef1,
- 0x1f000, 0x1f02b,
- 0x1f030, 0x1f093,
- 0x1f0a0, 0x1f0ae,
- 0x1f0b1, 0x1f0be,
- 0x1f0c1, 0x1f0cf,
- 0x1f0d1, 0x1f0df,
- 0x1f100, 0x1f10a,
- 0x1f110, 0x1f12e,
- 0x1f130, 0x1f16b,
- 0x1f170, 0x1f19a,
- 0x1f1e6, 0x1f202,
- 0x1f210, 0x1f23a,
- 0x1f240, 0x1f248,
- 0x1f250, 0x1f251,
- 0x1f300, 0x1f320,
- 0x1f330, 0x1f335,
- 0x1f337, 0x1f37c,
- 0x1f380, 0x1f393,
- 0x1f3a0, 0x1f3c4,
- 0x1f3c6, 0x1f3ca,
- 0x1f3e0, 0x1f3f0,
- 0x1f400, 0x1f43e,
- 0x1f440, 0x1f440,
- 0x1f442, 0x1f4f7,
- 0x1f4f9, 0x1f4fc,
- 0x1f500, 0x1f53d,
- 0x1f540, 0x1f543,
- 0x1f550, 0x1f567,
- 0x1f5fb, 0x1f640,
- 0x1f645, 0x1f64f,
- 0x1f680, 0x1f6c5,
- 0x1f700, 0x1f773,
- 0x1fffe, 0x2a6d6,
- 0x2a700, 0x2b734,
- 0x2b740, 0x2b81d,
- 0x2f800, 0x2fa1d,
- 0x2fffe, 0x2ffff,
- 0x3fffe, 0x3ffff,
- 0x4fffe, 0x4ffff,
- 0x5fffe, 0x5ffff,
- 0x6fffe, 0x6ffff,
- 0x7fffe, 0x7ffff,
- 0x8fffe, 0x8ffff,
- 0x9fffe, 0x9ffff,
- 0xafffe, 0xaffff,
- 0xbfffe, 0xbffff,
- 0xcfffe, 0xcffff,
- 0xdfffe, 0xdffff,
- 0xe0001, 0xe0001,
- 0xe0020, 0xe007f,
- 0xe0100, 0xe01ef,
- 0xefffe, 0x10ffff,
-}; /* CR_Age_6_1 */
-
-/* 'Age_6_2': Derived Age 6.2 */
-static const OnigCodePoint CR_Age_6_2[] = {
- 549,
- 0x0000, 0x0377,
- 0x037a, 0x037e,
- 0x0384, 0x038a,
- 0x038c, 0x038c,
- 0x038e, 0x03a1,
- 0x03a3, 0x0527,
- 0x0531, 0x0556,
- 0x0559, 0x055f,
- 0x0561, 0x0587,
- 0x0589, 0x058a,
- 0x058f, 0x058f,
- 0x0591, 0x05c7,
- 0x05d0, 0x05ea,
- 0x05f0, 0x05f4,
- 0x0600, 0x0604,
- 0x0606, 0x061b,
- 0x061e, 0x070d,
- 0x070f, 0x074a,
- 0x074d, 0x07b1,
- 0x07c0, 0x07fa,
- 0x0800, 0x082d,
- 0x0830, 0x083e,
- 0x0840, 0x085b,
- 0x085e, 0x085e,
- 0x08a0, 0x08a0,
- 0x08a2, 0x08ac,
- 0x08e4, 0x08fe,
- 0x0900, 0x0977,
- 0x0979, 0x097f,
- 0x0981, 0x0983,
- 0x0985, 0x098c,
- 0x098f, 0x0990,
- 0x0993, 0x09a8,
- 0x09aa, 0x09b0,
- 0x09b2, 0x09b2,
- 0x09b6, 0x09b9,
- 0x09bc, 0x09c4,
- 0x09c7, 0x09c8,
- 0x09cb, 0x09ce,
- 0x09d7, 0x09d7,
- 0x09dc, 0x09dd,
- 0x09df, 0x09e3,
- 0x09e6, 0x09fb,
- 0x0a01, 0x0a03,
- 0x0a05, 0x0a0a,
- 0x0a0f, 0x0a10,
- 0x0a13, 0x0a28,
- 0x0a2a, 0x0a30,
- 0x0a32, 0x0a33,
- 0x0a35, 0x0a36,
- 0x0a38, 0x0a39,
- 0x0a3c, 0x0a3c,
- 0x0a3e, 0x0a42,
- 0x0a47, 0x0a48,
- 0x0a4b, 0x0a4d,
- 0x0a51, 0x0a51,
- 0x0a59, 0x0a5c,
- 0x0a5e, 0x0a5e,
- 0x0a66, 0x0a75,
- 0x0a81, 0x0a83,
- 0x0a85, 0x0a8d,
- 0x0a8f, 0x0a91,
- 0x0a93, 0x0aa8,
- 0x0aaa, 0x0ab0,
- 0x0ab2, 0x0ab3,
- 0x0ab5, 0x0ab9,
- 0x0abc, 0x0ac5,
- 0x0ac7, 0x0ac9,
- 0x0acb, 0x0acd,
- 0x0ad0, 0x0ad0,
- 0x0ae0, 0x0ae3,
- 0x0ae6, 0x0af1,
- 0x0b01, 0x0b03,
- 0x0b05, 0x0b0c,
- 0x0b0f, 0x0b10,
- 0x0b13, 0x0b28,
- 0x0b2a, 0x0b30,
- 0x0b32, 0x0b33,
- 0x0b35, 0x0b39,
- 0x0b3c, 0x0b44,
- 0x0b47, 0x0b48,
- 0x0b4b, 0x0b4d,
- 0x0b56, 0x0b57,
- 0x0b5c, 0x0b5d,
- 0x0b5f, 0x0b63,
- 0x0b66, 0x0b77,
- 0x0b82, 0x0b83,
- 0x0b85, 0x0b8a,
- 0x0b8e, 0x0b90,
- 0x0b92, 0x0b95,
- 0x0b99, 0x0b9a,
- 0x0b9c, 0x0b9c,
- 0x0b9e, 0x0b9f,
- 0x0ba3, 0x0ba4,
- 0x0ba8, 0x0baa,
- 0x0bae, 0x0bb9,
- 0x0bbe, 0x0bc2,
- 0x0bc6, 0x0bc8,
- 0x0bca, 0x0bcd,
- 0x0bd0, 0x0bd0,
- 0x0bd7, 0x0bd7,
- 0x0be6, 0x0bfa,
- 0x0c01, 0x0c03,
- 0x0c05, 0x0c0c,
- 0x0c0e, 0x0c10,
- 0x0c12, 0x0c28,
- 0x0c2a, 0x0c33,
- 0x0c35, 0x0c39,
- 0x0c3d, 0x0c44,
- 0x0c46, 0x0c48,
- 0x0c4a, 0x0c4d,
- 0x0c55, 0x0c56,
- 0x0c58, 0x0c59,
- 0x0c60, 0x0c63,
- 0x0c66, 0x0c6f,
- 0x0c78, 0x0c7f,
- 0x0c82, 0x0c83,
- 0x0c85, 0x0c8c,
- 0x0c8e, 0x0c90,
- 0x0c92, 0x0ca8,
- 0x0caa, 0x0cb3,
- 0x0cb5, 0x0cb9,
- 0x0cbc, 0x0cc4,
- 0x0cc6, 0x0cc8,
- 0x0cca, 0x0ccd,
- 0x0cd5, 0x0cd6,
- 0x0cde, 0x0cde,
- 0x0ce0, 0x0ce3,
- 0x0ce6, 0x0cef,
- 0x0cf1, 0x0cf2,
- 0x0d02, 0x0d03,
- 0x0d05, 0x0d0c,
- 0x0d0e, 0x0d10,
- 0x0d12, 0x0d3a,
- 0x0d3d, 0x0d44,
- 0x0d46, 0x0d48,
- 0x0d4a, 0x0d4e,
- 0x0d57, 0x0d57,
- 0x0d60, 0x0d63,
- 0x0d66, 0x0d75,
- 0x0d79, 0x0d7f,
- 0x0d82, 0x0d83,
- 0x0d85, 0x0d96,
- 0x0d9a, 0x0db1,
- 0x0db3, 0x0dbb,
- 0x0dbd, 0x0dbd,
- 0x0dc0, 0x0dc6,
- 0x0dca, 0x0dca,
- 0x0dcf, 0x0dd4,
- 0x0dd6, 0x0dd6,
- 0x0dd8, 0x0ddf,
- 0x0df2, 0x0df4,
- 0x0e01, 0x0e3a,
- 0x0e3f, 0x0e5b,
- 0x0e81, 0x0e82,
- 0x0e84, 0x0e84,
- 0x0e87, 0x0e88,
- 0x0e8a, 0x0e8a,
- 0x0e8d, 0x0e8d,
- 0x0e94, 0x0e97,
- 0x0e99, 0x0e9f,
- 0x0ea1, 0x0ea3,
- 0x0ea5, 0x0ea5,
- 0x0ea7, 0x0ea7,
- 0x0eaa, 0x0eab,
- 0x0ead, 0x0eb9,
- 0x0ebb, 0x0ebd,
- 0x0ec0, 0x0ec4,
- 0x0ec6, 0x0ec6,
- 0x0ec8, 0x0ecd,
- 0x0ed0, 0x0ed9,
- 0x0edc, 0x0edf,
- 0x0f00, 0x0f47,
- 0x0f49, 0x0f6c,
- 0x0f71, 0x0f97,
- 0x0f99, 0x0fbc,
- 0x0fbe, 0x0fcc,
- 0x0fce, 0x0fda,
- 0x1000, 0x10c5,
- 0x10c7, 0x10c7,
- 0x10cd, 0x10cd,
- 0x10d0, 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,
- 0x135d, 0x137c,
- 0x1380, 0x1399,
- 0x13a0, 0x13f4,
- 0x1400, 0x169c,
- 0x16a0, 0x16f0,
- 0x1700, 0x170c,
- 0x170e, 0x1714,
- 0x1720, 0x1736,
- 0x1740, 0x1753,
- 0x1760, 0x176c,
- 0x176e, 0x1770,
- 0x1772, 0x1773,
- 0x1780, 0x17dd,
- 0x17e0, 0x17e9,
- 0x17f0, 0x17f9,
- 0x1800, 0x180e,
- 0x1810, 0x1819,
- 0x1820, 0x1877,
- 0x1880, 0x18aa,
- 0x18b0, 0x18f5,
- 0x1900, 0x191c,
- 0x1920, 0x192b,
- 0x1930, 0x193b,
- 0x1940, 0x1940,
- 0x1944, 0x196d,
- 0x1970, 0x1974,
- 0x1980, 0x19ab,
- 0x19b0, 0x19c9,
- 0x19d0, 0x19da,
- 0x19de, 0x1a1b,
- 0x1a1e, 0x1a5e,
- 0x1a60, 0x1a7c,
- 0x1a7f, 0x1a89,
- 0x1a90, 0x1a99,
- 0x1aa0, 0x1aad,
- 0x1b00, 0x1b4b,
- 0x1b50, 0x1b7c,
- 0x1b80, 0x1bf3,
- 0x1bfc, 0x1c37,
- 0x1c3b, 0x1c49,
- 0x1c4d, 0x1c7f,
- 0x1cc0, 0x1cc7,
- 0x1cd0, 0x1cf6,
- 0x1d00, 0x1de6,
- 0x1dfc, 0x1f15,
- 0x1f18, 0x1f1d,
- 0x1f20, 0x1f45,
- 0x1f48, 0x1f4d,
- 0x1f50, 0x1f57,
- 0x1f59, 0x1f59,
- 0x1f5b, 0x1f5b,
- 0x1f5d, 0x1f5d,
- 0x1f5f, 0x1f7d,
- 0x1f80, 0x1fb4,
- 0x1fb6, 0x1fc4,
- 0x1fc6, 0x1fd3,
- 0x1fd6, 0x1fdb,
- 0x1fdd, 0x1fef,
- 0x1ff2, 0x1ff4,
- 0x1ff6, 0x1ffe,
- 0x2000, 0x2064,
- 0x206a, 0x2071,
- 0x2074, 0x208e,
- 0x2090, 0x209c,
- 0x20a0, 0x20ba,
- 0x20d0, 0x20f0,
- 0x2100, 0x2189,
- 0x2190, 0x23f3,
- 0x2400, 0x2426,
- 0x2440, 0x244a,
- 0x2460, 0x26ff,
- 0x2701, 0x2b4c,
- 0x2b50, 0x2b59,
- 0x2c00, 0x2c2e,
- 0x2c30, 0x2c5e,
- 0x2c60, 0x2cf3,
- 0x2cf9, 0x2d25,
- 0x2d27, 0x2d27,
- 0x2d2d, 0x2d2d,
- 0x2d30, 0x2d67,
- 0x2d6f, 0x2d70,
- 0x2d7f, 0x2d96,
- 0x2da0, 0x2da6,
- 0x2da8, 0x2dae,
- 0x2db0, 0x2db6,
- 0x2db8, 0x2dbe,
- 0x2dc0, 0x2dc6,
- 0x2dc8, 0x2dce,
- 0x2dd0, 0x2dd6,
- 0x2dd8, 0x2dde,
- 0x2de0, 0x2e3b,
- 0x2e80, 0x2e99,
- 0x2e9b, 0x2ef3,
- 0x2f00, 0x2fd5,
- 0x2ff0, 0x2ffb,
- 0x3000, 0x303f,
- 0x3041, 0x3096,
- 0x3099, 0x30ff,
- 0x3105, 0x312d,
- 0x3131, 0x318e,
- 0x3190, 0x31ba,
- 0x31c0, 0x31e3,
- 0x31f0, 0x321e,
- 0x3220, 0x32fe,
- 0x3300, 0x4db5,
- 0x4dc0, 0x9fcc,
- 0xa000, 0xa48c,
- 0xa490, 0xa4c6,
- 0xa4d0, 0xa62b,
- 0xa640, 0xa697,
- 0xa69f, 0xa6f7,
- 0xa700, 0xa78e,
- 0xa790, 0xa793,
- 0xa7a0, 0xa7aa,
- 0xa7f8, 0xa82b,
- 0xa830, 0xa839,
- 0xa840, 0xa877,
- 0xa880, 0xa8c4,
- 0xa8ce, 0xa8d9,
- 0xa8e0, 0xa8fb,
- 0xa900, 0xa953,
- 0xa95f, 0xa97c,
- 0xa980, 0xa9cd,
- 0xa9cf, 0xa9d9,
- 0xa9de, 0xa9df,
- 0xaa00, 0xaa36,
- 0xaa40, 0xaa4d,
- 0xaa50, 0xaa59,
- 0xaa5c, 0xaa7b,
- 0xaa80, 0xaac2,
- 0xaadb, 0xaaf6,
- 0xab01, 0xab06,
- 0xab09, 0xab0e,
- 0xab11, 0xab16,
- 0xab20, 0xab26,
- 0xab28, 0xab2e,
- 0xabc0, 0xabed,
- 0xabf0, 0xabf9,
- 0xac00, 0xd7a3,
- 0xd7b0, 0xd7c6,
- 0xd7cb, 0xd7fb,
- 0xd800, 0xfa6d,
- 0xfa70, 0xfad9,
- 0xfb00, 0xfb06,
- 0xfb13, 0xfb17,
- 0xfb1d, 0xfb36,
- 0xfb38, 0xfb3c,
- 0xfb3e, 0xfb3e,
- 0xfb40, 0xfb41,
- 0xfb43, 0xfb44,
- 0xfb46, 0xfbc1,
- 0xfbd3, 0xfd3f,
- 0xfd50, 0xfd8f,
- 0xfd92, 0xfdc7,
- 0xfdd0, 0xfdfd,
- 0xfe00, 0xfe19,
- 0xfe20, 0xfe26,
- 0xfe30, 0xfe52,
- 0xfe54, 0xfe66,
- 0xfe68, 0xfe6b,
- 0xfe70, 0xfe74,
- 0xfe76, 0xfefc,
- 0xfeff, 0xfeff,
- 0xff01, 0xffbe,
- 0xffc2, 0xffc7,
- 0xffca, 0xffcf,
- 0xffd2, 0xffd7,
- 0xffda, 0xffdc,
- 0xffe0, 0xffe6,
- 0xffe8, 0xffee,
- 0xfff9, 0x1000b,
- 0x1000d, 0x10026,
- 0x10028, 0x1003a,
- 0x1003c, 0x1003d,
- 0x1003f, 0x1004d,
- 0x10050, 0x1005d,
- 0x10080, 0x100fa,
- 0x10100, 0x10102,
- 0x10107, 0x10133,
- 0x10137, 0x1018a,
- 0x10190, 0x1019b,
- 0x101d0, 0x101fd,
- 0x10280, 0x1029c,
- 0x102a0, 0x102d0,
- 0x10300, 0x1031e,
- 0x10320, 0x10323,
- 0x10330, 0x1034a,
- 0x10380, 0x1039d,
- 0x1039f, 0x103c3,
- 0x103c8, 0x103d5,
- 0x10400, 0x1049d,
- 0x104a0, 0x104a9,
- 0x10800, 0x10805,
- 0x10808, 0x10808,
- 0x1080a, 0x10835,
- 0x10837, 0x10838,
- 0x1083c, 0x1083c,
- 0x1083f, 0x10855,
- 0x10857, 0x1085f,
- 0x10900, 0x1091b,
- 0x1091f, 0x10939,
- 0x1093f, 0x1093f,
- 0x10980, 0x109b7,
- 0x109be, 0x109bf,
- 0x10a00, 0x10a03,
- 0x10a05, 0x10a06,
- 0x10a0c, 0x10a13,
- 0x10a15, 0x10a17,
- 0x10a19, 0x10a33,
- 0x10a38, 0x10a3a,
- 0x10a3f, 0x10a47,
- 0x10a50, 0x10a58,
- 0x10a60, 0x10a7f,
- 0x10b00, 0x10b35,
- 0x10b39, 0x10b55,
- 0x10b58, 0x10b72,
- 0x10b78, 0x10b7f,
- 0x10c00, 0x10c48,
- 0x10e60, 0x10e7e,
- 0x11000, 0x1104d,
- 0x11052, 0x1106f,
- 0x11080, 0x110c1,
- 0x110d0, 0x110e8,
- 0x110f0, 0x110f9,
- 0x11100, 0x11134,
- 0x11136, 0x11143,
- 0x11180, 0x111c8,
- 0x111d0, 0x111d9,
- 0x11680, 0x116b7,
- 0x116c0, 0x116c9,
- 0x12000, 0x1236e,
- 0x12400, 0x12462,
- 0x12470, 0x12473,
- 0x13000, 0x1342e,
- 0x16800, 0x16a38,
- 0x16f00, 0x16f44,
- 0x16f50, 0x16f7e,
- 0x16f8f, 0x16f9f,
- 0x1b000, 0x1b001,
- 0x1d000, 0x1d0f5,
- 0x1d100, 0x1d126,
- 0x1d129, 0x1d1dd,
- 0x1d200, 0x1d245,
- 0x1d300, 0x1d356,
- 0x1d360, 0x1d371,
- 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, 0x1d7cb,
- 0x1d7ce, 0x1d7ff,
- 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,
- 0x1eef0, 0x1eef1,
- 0x1f000, 0x1f02b,
- 0x1f030, 0x1f093,
- 0x1f0a0, 0x1f0ae,
- 0x1f0b1, 0x1f0be,
- 0x1f0c1, 0x1f0cf,
- 0x1f0d1, 0x1f0df,
- 0x1f100, 0x1f10a,
- 0x1f110, 0x1f12e,
- 0x1f130, 0x1f16b,
- 0x1f170, 0x1f19a,
- 0x1f1e6, 0x1f202,
- 0x1f210, 0x1f23a,
- 0x1f240, 0x1f248,
- 0x1f250, 0x1f251,
- 0x1f300, 0x1f320,
- 0x1f330, 0x1f335,
- 0x1f337, 0x1f37c,
- 0x1f380, 0x1f393,
- 0x1f3a0, 0x1f3c4,
- 0x1f3c6, 0x1f3ca,
- 0x1f3e0, 0x1f3f0,
- 0x1f400, 0x1f43e,
- 0x1f440, 0x1f440,
- 0x1f442, 0x1f4f7,
- 0x1f4f9, 0x1f4fc,
- 0x1f500, 0x1f53d,
- 0x1f540, 0x1f543,
- 0x1f550, 0x1f567,
- 0x1f5fb, 0x1f640,
- 0x1f645, 0x1f64f,
- 0x1f680, 0x1f6c5,
- 0x1f700, 0x1f773,
- 0x1fffe, 0x2a6d6,
- 0x2a700, 0x2b734,
- 0x2b740, 0x2b81d,
- 0x2f800, 0x2fa1d,
- 0x2fffe, 0x2ffff,
- 0x3fffe, 0x3ffff,
- 0x4fffe, 0x4ffff,
- 0x5fffe, 0x5ffff,
- 0x6fffe, 0x6ffff,
- 0x7fffe, 0x7ffff,
- 0x8fffe, 0x8ffff,
- 0x9fffe, 0x9ffff,
- 0xafffe, 0xaffff,
- 0xbfffe, 0xbffff,
- 0xcfffe, 0xcffff,
- 0xdfffe, 0xdffff,
- 0xe0001, 0xe0001,
- 0xe0020, 0xe007f,
- 0xe0100, 0xe01ef,
- 0xefffe, 0x10ffff,
-}; /* CR_Age_6_2 */
-
-/* 'Age_6_3': Derived Age 6.3 */
-static const OnigCodePoint CR_Age_6_3[] = {
- 549,
- 0x0000, 0x0377,
- 0x037a, 0x037e,
- 0x0384, 0x038a,
- 0x038c, 0x038c,
- 0x038e, 0x03a1,
- 0x03a3, 0x0527,
- 0x0531, 0x0556,
- 0x0559, 0x055f,
- 0x0561, 0x0587,
- 0x0589, 0x058a,
- 0x058f, 0x058f,
- 0x0591, 0x05c7,
- 0x05d0, 0x05ea,
- 0x05f0, 0x05f4,
- 0x0600, 0x0604,
- 0x0606, 0x061c,
- 0x061e, 0x070d,
- 0x070f, 0x074a,
- 0x074d, 0x07b1,
- 0x07c0, 0x07fa,
- 0x0800, 0x082d,
- 0x0830, 0x083e,
- 0x0840, 0x085b,
- 0x085e, 0x085e,
- 0x08a0, 0x08a0,
- 0x08a2, 0x08ac,
- 0x08e4, 0x08fe,
- 0x0900, 0x0977,
- 0x0979, 0x097f,
- 0x0981, 0x0983,
- 0x0985, 0x098c,
- 0x098f, 0x0990,
- 0x0993, 0x09a8,
- 0x09aa, 0x09b0,
- 0x09b2, 0x09b2,
- 0x09b6, 0x09b9,
- 0x09bc, 0x09c4,
- 0x09c7, 0x09c8,
- 0x09cb, 0x09ce,
- 0x09d7, 0x09d7,
- 0x09dc, 0x09dd,
- 0x09df, 0x09e3,
- 0x09e6, 0x09fb,
- 0x0a01, 0x0a03,
- 0x0a05, 0x0a0a,
- 0x0a0f, 0x0a10,
- 0x0a13, 0x0a28,
- 0x0a2a, 0x0a30,
- 0x0a32, 0x0a33,
- 0x0a35, 0x0a36,
- 0x0a38, 0x0a39,
- 0x0a3c, 0x0a3c,
- 0x0a3e, 0x0a42,
- 0x0a47, 0x0a48,
- 0x0a4b, 0x0a4d,
- 0x0a51, 0x0a51,
- 0x0a59, 0x0a5c,
- 0x0a5e, 0x0a5e,
- 0x0a66, 0x0a75,
- 0x0a81, 0x0a83,
- 0x0a85, 0x0a8d,
- 0x0a8f, 0x0a91,
- 0x0a93, 0x0aa8,
- 0x0aaa, 0x0ab0,
- 0x0ab2, 0x0ab3,
- 0x0ab5, 0x0ab9,
- 0x0abc, 0x0ac5,
- 0x0ac7, 0x0ac9,
- 0x0acb, 0x0acd,
- 0x0ad0, 0x0ad0,
- 0x0ae0, 0x0ae3,
- 0x0ae6, 0x0af1,
- 0x0b01, 0x0b03,
- 0x0b05, 0x0b0c,
- 0x0b0f, 0x0b10,
- 0x0b13, 0x0b28,
- 0x0b2a, 0x0b30,
- 0x0b32, 0x0b33,
- 0x0b35, 0x0b39,
- 0x0b3c, 0x0b44,
- 0x0b47, 0x0b48,
- 0x0b4b, 0x0b4d,
- 0x0b56, 0x0b57,
- 0x0b5c, 0x0b5d,
- 0x0b5f, 0x0b63,
- 0x0b66, 0x0b77,
- 0x0b82, 0x0b83,
- 0x0b85, 0x0b8a,
- 0x0b8e, 0x0b90,
- 0x0b92, 0x0b95,
- 0x0b99, 0x0b9a,
- 0x0b9c, 0x0b9c,
- 0x0b9e, 0x0b9f,
- 0x0ba3, 0x0ba4,
- 0x0ba8, 0x0baa,
- 0x0bae, 0x0bb9,
- 0x0bbe, 0x0bc2,
- 0x0bc6, 0x0bc8,
- 0x0bca, 0x0bcd,
- 0x0bd0, 0x0bd0,
- 0x0bd7, 0x0bd7,
- 0x0be6, 0x0bfa,
- 0x0c01, 0x0c03,
- 0x0c05, 0x0c0c,
- 0x0c0e, 0x0c10,
- 0x0c12, 0x0c28,
- 0x0c2a, 0x0c33,
- 0x0c35, 0x0c39,
- 0x0c3d, 0x0c44,
- 0x0c46, 0x0c48,
- 0x0c4a, 0x0c4d,
- 0x0c55, 0x0c56,
- 0x0c58, 0x0c59,
- 0x0c60, 0x0c63,
- 0x0c66, 0x0c6f,
- 0x0c78, 0x0c7f,
- 0x0c82, 0x0c83,
- 0x0c85, 0x0c8c,
- 0x0c8e, 0x0c90,
- 0x0c92, 0x0ca8,
- 0x0caa, 0x0cb3,
- 0x0cb5, 0x0cb9,
- 0x0cbc, 0x0cc4,
- 0x0cc6, 0x0cc8,
- 0x0cca, 0x0ccd,
- 0x0cd5, 0x0cd6,
- 0x0cde, 0x0cde,
- 0x0ce0, 0x0ce3,
- 0x0ce6, 0x0cef,
- 0x0cf1, 0x0cf2,
- 0x0d02, 0x0d03,
- 0x0d05, 0x0d0c,
- 0x0d0e, 0x0d10,
- 0x0d12, 0x0d3a,
- 0x0d3d, 0x0d44,
- 0x0d46, 0x0d48,
- 0x0d4a, 0x0d4e,
- 0x0d57, 0x0d57,
- 0x0d60, 0x0d63,
- 0x0d66, 0x0d75,
- 0x0d79, 0x0d7f,
- 0x0d82, 0x0d83,
- 0x0d85, 0x0d96,
- 0x0d9a, 0x0db1,
- 0x0db3, 0x0dbb,
- 0x0dbd, 0x0dbd,
- 0x0dc0, 0x0dc6,
- 0x0dca, 0x0dca,
- 0x0dcf, 0x0dd4,
- 0x0dd6, 0x0dd6,
- 0x0dd8, 0x0ddf,
- 0x0df2, 0x0df4,
- 0x0e01, 0x0e3a,
- 0x0e3f, 0x0e5b,
- 0x0e81, 0x0e82,
- 0x0e84, 0x0e84,
- 0x0e87, 0x0e88,
- 0x0e8a, 0x0e8a,
- 0x0e8d, 0x0e8d,
- 0x0e94, 0x0e97,
- 0x0e99, 0x0e9f,
- 0x0ea1, 0x0ea3,
- 0x0ea5, 0x0ea5,
- 0x0ea7, 0x0ea7,
- 0x0eaa, 0x0eab,
- 0x0ead, 0x0eb9,
- 0x0ebb, 0x0ebd,
- 0x0ec0, 0x0ec4,
- 0x0ec6, 0x0ec6,
- 0x0ec8, 0x0ecd,
- 0x0ed0, 0x0ed9,
- 0x0edc, 0x0edf,
- 0x0f00, 0x0f47,
- 0x0f49, 0x0f6c,
- 0x0f71, 0x0f97,
- 0x0f99, 0x0fbc,
- 0x0fbe, 0x0fcc,
- 0x0fce, 0x0fda,
- 0x1000, 0x10c5,
- 0x10c7, 0x10c7,
- 0x10cd, 0x10cd,
- 0x10d0, 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,
- 0x135d, 0x137c,
- 0x1380, 0x1399,
- 0x13a0, 0x13f4,
- 0x1400, 0x169c,
- 0x16a0, 0x16f0,
- 0x1700, 0x170c,
- 0x170e, 0x1714,
- 0x1720, 0x1736,
- 0x1740, 0x1753,
- 0x1760, 0x176c,
- 0x176e, 0x1770,
- 0x1772, 0x1773,
- 0x1780, 0x17dd,
- 0x17e0, 0x17e9,
- 0x17f0, 0x17f9,
- 0x1800, 0x180e,
- 0x1810, 0x1819,
- 0x1820, 0x1877,
- 0x1880, 0x18aa,
- 0x18b0, 0x18f5,
- 0x1900, 0x191c,
- 0x1920, 0x192b,
- 0x1930, 0x193b,
- 0x1940, 0x1940,
- 0x1944, 0x196d,
- 0x1970, 0x1974,
- 0x1980, 0x19ab,
- 0x19b0, 0x19c9,
- 0x19d0, 0x19da,
- 0x19de, 0x1a1b,
- 0x1a1e, 0x1a5e,
- 0x1a60, 0x1a7c,
- 0x1a7f, 0x1a89,
- 0x1a90, 0x1a99,
- 0x1aa0, 0x1aad,
- 0x1b00, 0x1b4b,
- 0x1b50, 0x1b7c,
- 0x1b80, 0x1bf3,
- 0x1bfc, 0x1c37,
- 0x1c3b, 0x1c49,
- 0x1c4d, 0x1c7f,
- 0x1cc0, 0x1cc7,
- 0x1cd0, 0x1cf6,
- 0x1d00, 0x1de6,
- 0x1dfc, 0x1f15,
- 0x1f18, 0x1f1d,
- 0x1f20, 0x1f45,
- 0x1f48, 0x1f4d,
- 0x1f50, 0x1f57,
- 0x1f59, 0x1f59,
- 0x1f5b, 0x1f5b,
- 0x1f5d, 0x1f5d,
- 0x1f5f, 0x1f7d,
- 0x1f80, 0x1fb4,
- 0x1fb6, 0x1fc4,
- 0x1fc6, 0x1fd3,
- 0x1fd6, 0x1fdb,
- 0x1fdd, 0x1fef,
- 0x1ff2, 0x1ff4,
- 0x1ff6, 0x1ffe,
- 0x2000, 0x2064,
- 0x2066, 0x2071,
- 0x2074, 0x208e,
- 0x2090, 0x209c,
- 0x20a0, 0x20ba,
- 0x20d0, 0x20f0,
- 0x2100, 0x2189,
- 0x2190, 0x23f3,
- 0x2400, 0x2426,
- 0x2440, 0x244a,
- 0x2460, 0x26ff,
- 0x2701, 0x2b4c,
- 0x2b50, 0x2b59,
- 0x2c00, 0x2c2e,
- 0x2c30, 0x2c5e,
- 0x2c60, 0x2cf3,
- 0x2cf9, 0x2d25,
- 0x2d27, 0x2d27,
- 0x2d2d, 0x2d2d,
- 0x2d30, 0x2d67,
- 0x2d6f, 0x2d70,
- 0x2d7f, 0x2d96,
- 0x2da0, 0x2da6,
- 0x2da8, 0x2dae,
- 0x2db0, 0x2db6,
- 0x2db8, 0x2dbe,
- 0x2dc0, 0x2dc6,
- 0x2dc8, 0x2dce,
- 0x2dd0, 0x2dd6,
- 0x2dd8, 0x2dde,
- 0x2de0, 0x2e3b,
- 0x2e80, 0x2e99,
- 0x2e9b, 0x2ef3,
- 0x2f00, 0x2fd5,
- 0x2ff0, 0x2ffb,
- 0x3000, 0x303f,
- 0x3041, 0x3096,
- 0x3099, 0x30ff,
- 0x3105, 0x312d,
- 0x3131, 0x318e,
- 0x3190, 0x31ba,
- 0x31c0, 0x31e3,
- 0x31f0, 0x321e,
- 0x3220, 0x32fe,
- 0x3300, 0x4db5,
- 0x4dc0, 0x9fcc,
- 0xa000, 0xa48c,
- 0xa490, 0xa4c6,
- 0xa4d0, 0xa62b,
- 0xa640, 0xa697,
- 0xa69f, 0xa6f7,
- 0xa700, 0xa78e,
- 0xa790, 0xa793,
- 0xa7a0, 0xa7aa,
- 0xa7f8, 0xa82b,
- 0xa830, 0xa839,
- 0xa840, 0xa877,
- 0xa880, 0xa8c4,
- 0xa8ce, 0xa8d9,
- 0xa8e0, 0xa8fb,
- 0xa900, 0xa953,
- 0xa95f, 0xa97c,
- 0xa980, 0xa9cd,
- 0xa9cf, 0xa9d9,
- 0xa9de, 0xa9df,
- 0xaa00, 0xaa36,
- 0xaa40, 0xaa4d,
- 0xaa50, 0xaa59,
- 0xaa5c, 0xaa7b,
- 0xaa80, 0xaac2,
- 0xaadb, 0xaaf6,
- 0xab01, 0xab06,
- 0xab09, 0xab0e,
- 0xab11, 0xab16,
- 0xab20, 0xab26,
- 0xab28, 0xab2e,
- 0xabc0, 0xabed,
- 0xabf0, 0xabf9,
- 0xac00, 0xd7a3,
- 0xd7b0, 0xd7c6,
- 0xd7cb, 0xd7fb,
- 0xd800, 0xfa6d,
- 0xfa70, 0xfad9,
- 0xfb00, 0xfb06,
- 0xfb13, 0xfb17,
- 0xfb1d, 0xfb36,
- 0xfb38, 0xfb3c,
- 0xfb3e, 0xfb3e,
- 0xfb40, 0xfb41,
- 0xfb43, 0xfb44,
- 0xfb46, 0xfbc1,
- 0xfbd3, 0xfd3f,
- 0xfd50, 0xfd8f,
- 0xfd92, 0xfdc7,
- 0xfdd0, 0xfdfd,
- 0xfe00, 0xfe19,
- 0xfe20, 0xfe26,
- 0xfe30, 0xfe52,
- 0xfe54, 0xfe66,
- 0xfe68, 0xfe6b,
- 0xfe70, 0xfe74,
- 0xfe76, 0xfefc,
- 0xfeff, 0xfeff,
- 0xff01, 0xffbe,
- 0xffc2, 0xffc7,
- 0xffca, 0xffcf,
- 0xffd2, 0xffd7,
- 0xffda, 0xffdc,
- 0xffe0, 0xffe6,
- 0xffe8, 0xffee,
- 0xfff9, 0x1000b,
- 0x1000d, 0x10026,
- 0x10028, 0x1003a,
- 0x1003c, 0x1003d,
- 0x1003f, 0x1004d,
- 0x10050, 0x1005d,
- 0x10080, 0x100fa,
- 0x10100, 0x10102,
- 0x10107, 0x10133,
- 0x10137, 0x1018a,
- 0x10190, 0x1019b,
- 0x101d0, 0x101fd,
- 0x10280, 0x1029c,
- 0x102a0, 0x102d0,
- 0x10300, 0x1031e,
- 0x10320, 0x10323,
- 0x10330, 0x1034a,
- 0x10380, 0x1039d,
- 0x1039f, 0x103c3,
- 0x103c8, 0x103d5,
- 0x10400, 0x1049d,
- 0x104a0, 0x104a9,
- 0x10800, 0x10805,
- 0x10808, 0x10808,
- 0x1080a, 0x10835,
- 0x10837, 0x10838,
- 0x1083c, 0x1083c,
- 0x1083f, 0x10855,
- 0x10857, 0x1085f,
- 0x10900, 0x1091b,
- 0x1091f, 0x10939,
- 0x1093f, 0x1093f,
- 0x10980, 0x109b7,
- 0x109be, 0x109bf,
- 0x10a00, 0x10a03,
- 0x10a05, 0x10a06,
- 0x10a0c, 0x10a13,
- 0x10a15, 0x10a17,
- 0x10a19, 0x10a33,
- 0x10a38, 0x10a3a,
- 0x10a3f, 0x10a47,
- 0x10a50, 0x10a58,
- 0x10a60, 0x10a7f,
- 0x10b00, 0x10b35,
- 0x10b39, 0x10b55,
- 0x10b58, 0x10b72,
- 0x10b78, 0x10b7f,
- 0x10c00, 0x10c48,
- 0x10e60, 0x10e7e,
- 0x11000, 0x1104d,
- 0x11052, 0x1106f,
- 0x11080, 0x110c1,
- 0x110d0, 0x110e8,
- 0x110f0, 0x110f9,
- 0x11100, 0x11134,
- 0x11136, 0x11143,
- 0x11180, 0x111c8,
- 0x111d0, 0x111d9,
- 0x11680, 0x116b7,
- 0x116c0, 0x116c9,
- 0x12000, 0x1236e,
- 0x12400, 0x12462,
- 0x12470, 0x12473,
- 0x13000, 0x1342e,
- 0x16800, 0x16a38,
- 0x16f00, 0x16f44,
- 0x16f50, 0x16f7e,
- 0x16f8f, 0x16f9f,
- 0x1b000, 0x1b001,
- 0x1d000, 0x1d0f5,
- 0x1d100, 0x1d126,
- 0x1d129, 0x1d1dd,
- 0x1d200, 0x1d245,
- 0x1d300, 0x1d356,
- 0x1d360, 0x1d371,
- 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, 0x1d7cb,
- 0x1d7ce, 0x1d7ff,
- 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,
- 0x1eef0, 0x1eef1,
- 0x1f000, 0x1f02b,
- 0x1f030, 0x1f093,
- 0x1f0a0, 0x1f0ae,
- 0x1f0b1, 0x1f0be,
- 0x1f0c1, 0x1f0cf,
- 0x1f0d1, 0x1f0df,
- 0x1f100, 0x1f10a,
- 0x1f110, 0x1f12e,
- 0x1f130, 0x1f16b,
- 0x1f170, 0x1f19a,
- 0x1f1e6, 0x1f202,
- 0x1f210, 0x1f23a,
- 0x1f240, 0x1f248,
- 0x1f250, 0x1f251,
- 0x1f300, 0x1f320,
- 0x1f330, 0x1f335,
- 0x1f337, 0x1f37c,
- 0x1f380, 0x1f393,
- 0x1f3a0, 0x1f3c4,
- 0x1f3c6, 0x1f3ca,
- 0x1f3e0, 0x1f3f0,
- 0x1f400, 0x1f43e,
- 0x1f440, 0x1f440,
- 0x1f442, 0x1f4f7,
- 0x1f4f9, 0x1f4fc,
- 0x1f500, 0x1f53d,
- 0x1f540, 0x1f543,
- 0x1f550, 0x1f567,
- 0x1f5fb, 0x1f640,
- 0x1f645, 0x1f64f,
- 0x1f680, 0x1f6c5,
- 0x1f700, 0x1f773,
- 0x1fffe, 0x2a6d6,
- 0x2a700, 0x2b734,
- 0x2b740, 0x2b81d,
- 0x2f800, 0x2fa1d,
- 0x2fffe, 0x2ffff,
- 0x3fffe, 0x3ffff,
- 0x4fffe, 0x4ffff,
- 0x5fffe, 0x5ffff,
- 0x6fffe, 0x6ffff,
- 0x7fffe, 0x7ffff,
- 0x8fffe, 0x8ffff,
- 0x9fffe, 0x9ffff,
- 0xafffe, 0xaffff,
- 0xbfffe, 0xbffff,
- 0xcfffe, 0xcffff,
- 0xdfffe, 0xdffff,
- 0xe0001, 0xe0001,
- 0xe0020, 0xe007f,
- 0xe0100, 0xe01ef,
- 0xefffe, 0x10ffff,
-}; /* CR_Age_6_3 */
-
-/* 'Age_7_0': Derived Age 7.0 */
-static const OnigCodePoint CR_Age_7_0[] = {
- 610,
- 0x0000, 0x0377,
- 0x037a, 0x037f,
- 0x0384, 0x038a,
- 0x038c, 0x038c,
- 0x038e, 0x03a1,
- 0x03a3, 0x052f,
- 0x0531, 0x0556,
- 0x0559, 0x055f,
- 0x0561, 0x0587,
- 0x0589, 0x058a,
- 0x058d, 0x058f,
- 0x0591, 0x05c7,
- 0x05d0, 0x05ea,
- 0x05f0, 0x05f4,
- 0x0600, 0x061c,
- 0x061e, 0x070d,
- 0x070f, 0x074a,
- 0x074d, 0x07b1,
- 0x07c0, 0x07fa,
- 0x0800, 0x082d,
- 0x0830, 0x083e,
- 0x0840, 0x085b,
- 0x085e, 0x085e,
- 0x08a0, 0x08b2,
- 0x08e4, 0x0983,
- 0x0985, 0x098c,
- 0x098f, 0x0990,
- 0x0993, 0x09a8,
- 0x09aa, 0x09b0,
- 0x09b2, 0x09b2,
- 0x09b6, 0x09b9,
- 0x09bc, 0x09c4,
- 0x09c7, 0x09c8,
- 0x09cb, 0x09ce,
- 0x09d7, 0x09d7,
- 0x09dc, 0x09dd,
- 0x09df, 0x09e3,
- 0x09e6, 0x09fb,
- 0x0a01, 0x0a03,
- 0x0a05, 0x0a0a,
- 0x0a0f, 0x0a10,
- 0x0a13, 0x0a28,
- 0x0a2a, 0x0a30,
- 0x0a32, 0x0a33,
- 0x0a35, 0x0a36,
- 0x0a38, 0x0a39,
- 0x0a3c, 0x0a3c,
- 0x0a3e, 0x0a42,
- 0x0a47, 0x0a48,
- 0x0a4b, 0x0a4d,
- 0x0a51, 0x0a51,
- 0x0a59, 0x0a5c,
- 0x0a5e, 0x0a5e,
- 0x0a66, 0x0a75,
- 0x0a81, 0x0a83,
- 0x0a85, 0x0a8d,
- 0x0a8f, 0x0a91,
- 0x0a93, 0x0aa8,
- 0x0aaa, 0x0ab0,
- 0x0ab2, 0x0ab3,
- 0x0ab5, 0x0ab9,
- 0x0abc, 0x0ac5,
- 0x0ac7, 0x0ac9,
- 0x0acb, 0x0acd,
- 0x0ad0, 0x0ad0,
- 0x0ae0, 0x0ae3,
- 0x0ae6, 0x0af1,
- 0x0b01, 0x0b03,
- 0x0b05, 0x0b0c,
- 0x0b0f, 0x0b10,
- 0x0b13, 0x0b28,
- 0x0b2a, 0x0b30,
- 0x0b32, 0x0b33,
- 0x0b35, 0x0b39,
- 0x0b3c, 0x0b44,
- 0x0b47, 0x0b48,
- 0x0b4b, 0x0b4d,
- 0x0b56, 0x0b57,
- 0x0b5c, 0x0b5d,
- 0x0b5f, 0x0b63,
- 0x0b66, 0x0b77,
- 0x0b82, 0x0b83,
- 0x0b85, 0x0b8a,
- 0x0b8e, 0x0b90,
- 0x0b92, 0x0b95,
- 0x0b99, 0x0b9a,
- 0x0b9c, 0x0b9c,
- 0x0b9e, 0x0b9f,
- 0x0ba3, 0x0ba4,
- 0x0ba8, 0x0baa,
- 0x0bae, 0x0bb9,
- 0x0bbe, 0x0bc2,
- 0x0bc6, 0x0bc8,
- 0x0bca, 0x0bcd,
- 0x0bd0, 0x0bd0,
- 0x0bd7, 0x0bd7,
- 0x0be6, 0x0bfa,
- 0x0c00, 0x0c03,
- 0x0c05, 0x0c0c,
- 0x0c0e, 0x0c10,
- 0x0c12, 0x0c28,
- 0x0c2a, 0x0c39,
- 0x0c3d, 0x0c44,
- 0x0c46, 0x0c48,
- 0x0c4a, 0x0c4d,
- 0x0c55, 0x0c56,
- 0x0c58, 0x0c59,
- 0x0c60, 0x0c63,
- 0x0c66, 0x0c6f,
- 0x0c78, 0x0c7f,
- 0x0c81, 0x0c83,
- 0x0c85, 0x0c8c,
- 0x0c8e, 0x0c90,
- 0x0c92, 0x0ca8,
- 0x0caa, 0x0cb3,
- 0x0cb5, 0x0cb9,
- 0x0cbc, 0x0cc4,
- 0x0cc6, 0x0cc8,
- 0x0cca, 0x0ccd,
- 0x0cd5, 0x0cd6,
- 0x0cde, 0x0cde,
- 0x0ce0, 0x0ce3,
- 0x0ce6, 0x0cef,
- 0x0cf1, 0x0cf2,
- 0x0d01, 0x0d03,
- 0x0d05, 0x0d0c,
- 0x0d0e, 0x0d10,
- 0x0d12, 0x0d3a,
- 0x0d3d, 0x0d44,
- 0x0d46, 0x0d48,
- 0x0d4a, 0x0d4e,
- 0x0d57, 0x0d57,
- 0x0d60, 0x0d63,
- 0x0d66, 0x0d75,
- 0x0d79, 0x0d7f,
- 0x0d82, 0x0d83,
- 0x0d85, 0x0d96,
- 0x0d9a, 0x0db1,
- 0x0db3, 0x0dbb,
- 0x0dbd, 0x0dbd,
- 0x0dc0, 0x0dc6,
- 0x0dca, 0x0dca,
- 0x0dcf, 0x0dd4,
- 0x0dd6, 0x0dd6,
- 0x0dd8, 0x0ddf,
- 0x0de6, 0x0def,
- 0x0df2, 0x0df4,
- 0x0e01, 0x0e3a,
- 0x0e3f, 0x0e5b,
- 0x0e81, 0x0e82,
- 0x0e84, 0x0e84,
- 0x0e87, 0x0e88,
- 0x0e8a, 0x0e8a,
- 0x0e8d, 0x0e8d,
- 0x0e94, 0x0e97,
- 0x0e99, 0x0e9f,
- 0x0ea1, 0x0ea3,
- 0x0ea5, 0x0ea5,
- 0x0ea7, 0x0ea7,
- 0x0eaa, 0x0eab,
- 0x0ead, 0x0eb9,
- 0x0ebb, 0x0ebd,
- 0x0ec0, 0x0ec4,
- 0x0ec6, 0x0ec6,
- 0x0ec8, 0x0ecd,
- 0x0ed0, 0x0ed9,
- 0x0edc, 0x0edf,
- 0x0f00, 0x0f47,
- 0x0f49, 0x0f6c,
- 0x0f71, 0x0f97,
- 0x0f99, 0x0fbc,
- 0x0fbe, 0x0fcc,
- 0x0fce, 0x0fda,
- 0x1000, 0x10c5,
- 0x10c7, 0x10c7,
- 0x10cd, 0x10cd,
- 0x10d0, 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,
- 0x135d, 0x137c,
- 0x1380, 0x1399,
- 0x13a0, 0x13f4,
- 0x1400, 0x169c,
- 0x16a0, 0x16f8,
- 0x1700, 0x170c,
- 0x170e, 0x1714,
- 0x1720, 0x1736,
- 0x1740, 0x1753,
- 0x1760, 0x176c,
- 0x176e, 0x1770,
- 0x1772, 0x1773,
- 0x1780, 0x17dd,
- 0x17e0, 0x17e9,
- 0x17f0, 0x17f9,
- 0x1800, 0x180e,
- 0x1810, 0x1819,
- 0x1820, 0x1877,
- 0x1880, 0x18aa,
- 0x18b0, 0x18f5,
- 0x1900, 0x191e,
- 0x1920, 0x192b,
- 0x1930, 0x193b,
- 0x1940, 0x1940,
- 0x1944, 0x196d,
- 0x1970, 0x1974,
- 0x1980, 0x19ab,
- 0x19b0, 0x19c9,
- 0x19d0, 0x19da,
- 0x19de, 0x1a1b,
- 0x1a1e, 0x1a5e,
- 0x1a60, 0x1a7c,
- 0x1a7f, 0x1a89,
- 0x1a90, 0x1a99,
- 0x1aa0, 0x1aad,
- 0x1ab0, 0x1abe,
- 0x1b00, 0x1b4b,
- 0x1b50, 0x1b7c,
- 0x1b80, 0x1bf3,
- 0x1bfc, 0x1c37,
- 0x1c3b, 0x1c49,
- 0x1c4d, 0x1c7f,
- 0x1cc0, 0x1cc7,
- 0x1cd0, 0x1cf6,
- 0x1cf8, 0x1cf9,
- 0x1d00, 0x1df5,
- 0x1dfc, 0x1f15,
- 0x1f18, 0x1f1d,
- 0x1f20, 0x1f45,
- 0x1f48, 0x1f4d,
- 0x1f50, 0x1f57,
- 0x1f59, 0x1f59,
- 0x1f5b, 0x1f5b,
- 0x1f5d, 0x1f5d,
- 0x1f5f, 0x1f7d,
- 0x1f80, 0x1fb4,
- 0x1fb6, 0x1fc4,
- 0x1fc6, 0x1fd3,
- 0x1fd6, 0x1fdb,
- 0x1fdd, 0x1fef,
- 0x1ff2, 0x1ff4,
- 0x1ff6, 0x1ffe,
- 0x2000, 0x2064,
- 0x2066, 0x2071,
- 0x2074, 0x208e,
- 0x2090, 0x209c,
- 0x20a0, 0x20bd,
- 0x20d0, 0x20f0,
- 0x2100, 0x2189,
- 0x2190, 0x23fa,
- 0x2400, 0x2426,
- 0x2440, 0x244a,
- 0x2460, 0x2b73,
- 0x2b76, 0x2b95,
- 0x2b98, 0x2bb9,
- 0x2bbd, 0x2bc8,
- 0x2bca, 0x2bd1,
- 0x2c00, 0x2c2e,
- 0x2c30, 0x2c5e,
- 0x2c60, 0x2cf3,
- 0x2cf9, 0x2d25,
- 0x2d27, 0x2d27,
- 0x2d2d, 0x2d2d,
- 0x2d30, 0x2d67,
- 0x2d6f, 0x2d70,
- 0x2d7f, 0x2d96,
- 0x2da0, 0x2da6,
- 0x2da8, 0x2dae,
- 0x2db0, 0x2db6,
- 0x2db8, 0x2dbe,
- 0x2dc0, 0x2dc6,
- 0x2dc8, 0x2dce,
- 0x2dd0, 0x2dd6,
- 0x2dd8, 0x2dde,
- 0x2de0, 0x2e42,
- 0x2e80, 0x2e99,
- 0x2e9b, 0x2ef3,
- 0x2f00, 0x2fd5,
- 0x2ff0, 0x2ffb,
- 0x3000, 0x303f,
- 0x3041, 0x3096,
- 0x3099, 0x30ff,
- 0x3105, 0x312d,
- 0x3131, 0x318e,
- 0x3190, 0x31ba,
- 0x31c0, 0x31e3,
- 0x31f0, 0x321e,
- 0x3220, 0x32fe,
- 0x3300, 0x4db5,
- 0x4dc0, 0x9fcc,
- 0xa000, 0xa48c,
- 0xa490, 0xa4c6,
- 0xa4d0, 0xa62b,
- 0xa640, 0xa69d,
- 0xa69f, 0xa6f7,
- 0xa700, 0xa78e,
- 0xa790, 0xa7ad,
- 0xa7b0, 0xa7b1,
- 0xa7f7, 0xa82b,
- 0xa830, 0xa839,
- 0xa840, 0xa877,
- 0xa880, 0xa8c4,
- 0xa8ce, 0xa8d9,
- 0xa8e0, 0xa8fb,
- 0xa900, 0xa953,
- 0xa95f, 0xa97c,
- 0xa980, 0xa9cd,
- 0xa9cf, 0xa9d9,
- 0xa9de, 0xa9fe,
- 0xaa00, 0xaa36,
- 0xaa40, 0xaa4d,
- 0xaa50, 0xaa59,
- 0xaa5c, 0xaac2,
- 0xaadb, 0xaaf6,
- 0xab01, 0xab06,
- 0xab09, 0xab0e,
- 0xab11, 0xab16,
- 0xab20, 0xab26,
- 0xab28, 0xab2e,
- 0xab30, 0xab5f,
- 0xab64, 0xab65,
- 0xabc0, 0xabed,
- 0xabf0, 0xabf9,
- 0xac00, 0xd7a3,
- 0xd7b0, 0xd7c6,
- 0xd7cb, 0xd7fb,
- 0xd800, 0xfa6d,
- 0xfa70, 0xfad9,
- 0xfb00, 0xfb06,
- 0xfb13, 0xfb17,
- 0xfb1d, 0xfb36,
- 0xfb38, 0xfb3c,
- 0xfb3e, 0xfb3e,
- 0xfb40, 0xfb41,
- 0xfb43, 0xfb44,
- 0xfb46, 0xfbc1,
- 0xfbd3, 0xfd3f,
- 0xfd50, 0xfd8f,
- 0xfd92, 0xfdc7,
- 0xfdd0, 0xfdfd,
- 0xfe00, 0xfe19,
- 0xfe20, 0xfe2d,
- 0xfe30, 0xfe52,
- 0xfe54, 0xfe66,
- 0xfe68, 0xfe6b,
- 0xfe70, 0xfe74,
- 0xfe76, 0xfefc,
- 0xfeff, 0xfeff,
- 0xff01, 0xffbe,
- 0xffc2, 0xffc7,
- 0xffca, 0xffcf,
- 0xffd2, 0xffd7,
- 0xffda, 0xffdc,
- 0xffe0, 0xffe6,
- 0xffe8, 0xffee,
- 0xfff9, 0x1000b,
- 0x1000d, 0x10026,
- 0x10028, 0x1003a,
- 0x1003c, 0x1003d,
- 0x1003f, 0x1004d,
- 0x10050, 0x1005d,
- 0x10080, 0x100fa,
- 0x10100, 0x10102,
- 0x10107, 0x10133,
- 0x10137, 0x1018c,
- 0x10190, 0x1019b,
- 0x101a0, 0x101a0,
- 0x101d0, 0x101fd,
- 0x10280, 0x1029c,
- 0x102a0, 0x102d0,
- 0x102e0, 0x102fb,
- 0x10300, 0x10323,
- 0x10330, 0x1034a,
- 0x10350, 0x1037a,
- 0x10380, 0x1039d,
- 0x1039f, 0x103c3,
- 0x103c8, 0x103d5,
- 0x10400, 0x1049d,
- 0x104a0, 0x104a9,
- 0x10500, 0x10527,
- 0x10530, 0x10563,
- 0x1056f, 0x1056f,
- 0x10600, 0x10736,
- 0x10740, 0x10755,
- 0x10760, 0x10767,
- 0x10800, 0x10805,
- 0x10808, 0x10808,
- 0x1080a, 0x10835,
- 0x10837, 0x10838,
- 0x1083c, 0x1083c,
- 0x1083f, 0x10855,
- 0x10857, 0x1089e,
- 0x108a7, 0x108af,
- 0x10900, 0x1091b,
- 0x1091f, 0x10939,
- 0x1093f, 0x1093f,
- 0x10980, 0x109b7,
- 0x109be, 0x109bf,
- 0x10a00, 0x10a03,
- 0x10a05, 0x10a06,
- 0x10a0c, 0x10a13,
- 0x10a15, 0x10a17,
- 0x10a19, 0x10a33,
- 0x10a38, 0x10a3a,
- 0x10a3f, 0x10a47,
- 0x10a50, 0x10a58,
- 0x10a60, 0x10a9f,
- 0x10ac0, 0x10ae6,
- 0x10aeb, 0x10af6,
- 0x10b00, 0x10b35,
- 0x10b39, 0x10b55,
- 0x10b58, 0x10b72,
- 0x10b78, 0x10b91,
- 0x10b99, 0x10b9c,
- 0x10ba9, 0x10baf,
- 0x10c00, 0x10c48,
- 0x10e60, 0x10e7e,
- 0x11000, 0x1104d,
- 0x11052, 0x1106f,
- 0x1107f, 0x110c1,
- 0x110d0, 0x110e8,
- 0x110f0, 0x110f9,
- 0x11100, 0x11134,
- 0x11136, 0x11143,
- 0x11150, 0x11176,
- 0x11180, 0x111c8,
- 0x111cd, 0x111cd,
- 0x111d0, 0x111da,
- 0x111e1, 0x111f4,
- 0x11200, 0x11211,
- 0x11213, 0x1123d,
- 0x112b0, 0x112ea,
- 0x112f0, 0x112f9,
- 0x11301, 0x11303,
- 0x11305, 0x1130c,
- 0x1130f, 0x11310,
- 0x11313, 0x11328,
- 0x1132a, 0x11330,
- 0x11332, 0x11333,
- 0x11335, 0x11339,
- 0x1133c, 0x11344,
- 0x11347, 0x11348,
- 0x1134b, 0x1134d,
- 0x11357, 0x11357,
- 0x1135d, 0x11363,
- 0x11366, 0x1136c,
- 0x11370, 0x11374,
- 0x11480, 0x114c7,
- 0x114d0, 0x114d9,
- 0x11580, 0x115b5,
- 0x115b8, 0x115c9,
- 0x11600, 0x11644,
- 0x11650, 0x11659,
- 0x11680, 0x116b7,
- 0x116c0, 0x116c9,
- 0x118a0, 0x118f2,
- 0x118ff, 0x118ff,
- 0x11ac0, 0x11af8,
- 0x12000, 0x12398,
- 0x12400, 0x1246e,
- 0x12470, 0x12474,
- 0x13000, 0x1342e,
- 0x16800, 0x16a38,
- 0x16a40, 0x16a5e,
- 0x16a60, 0x16a69,
- 0x16a6e, 0x16a6f,
- 0x16ad0, 0x16aed,
- 0x16af0, 0x16af5,
- 0x16b00, 0x16b45,
- 0x16b50, 0x16b59,
- 0x16b5b, 0x16b61,
- 0x16b63, 0x16b77,
- 0x16b7d, 0x16b8f,
- 0x16f00, 0x16f44,
- 0x16f50, 0x16f7e,
- 0x16f8f, 0x16f9f,
- 0x1b000, 0x1b001,
- 0x1bc00, 0x1bc6a,
- 0x1bc70, 0x1bc7c,
- 0x1bc80, 0x1bc88,
- 0x1bc90, 0x1bc99,
- 0x1bc9c, 0x1bca3,
- 0x1d000, 0x1d0f5,
- 0x1d100, 0x1d126,
- 0x1d129, 0x1d1dd,
- 0x1d200, 0x1d245,
- 0x1d300, 0x1d356,
- 0x1d360, 0x1d371,
- 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, 0x1d7cb,
- 0x1d7ce, 0x1d7ff,
- 0x1e800, 0x1e8c4,
- 0x1e8c7, 0x1e8d6,
- 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,
- 0x1eef0, 0x1eef1,
- 0x1f000, 0x1f02b,
- 0x1f030, 0x1f093,
- 0x1f0a0, 0x1f0ae,
- 0x1f0b1, 0x1f0bf,
- 0x1f0c1, 0x1f0cf,
- 0x1f0d1, 0x1f0f5,
- 0x1f100, 0x1f10c,
- 0x1f110, 0x1f12e,
- 0x1f130, 0x1f16b,
- 0x1f170, 0x1f19a,
- 0x1f1e6, 0x1f202,
- 0x1f210, 0x1f23a,
- 0x1f240, 0x1f248,
- 0x1f250, 0x1f251,
- 0x1f300, 0x1f32c,
- 0x1f330, 0x1f37d,
- 0x1f380, 0x1f3ce,
- 0x1f3d4, 0x1f3f7,
- 0x1f400, 0x1f4fe,
- 0x1f500, 0x1f54a,
- 0x1f550, 0x1f579,
- 0x1f57b, 0x1f5a3,
- 0x1f5a5, 0x1f642,
- 0x1f645, 0x1f6cf,
- 0x1f6e0, 0x1f6ec,
- 0x1f6f0, 0x1f6f3,
- 0x1f700, 0x1f773,
- 0x1f780, 0x1f7d4,
- 0x1f800, 0x1f80b,
- 0x1f810, 0x1f847,
- 0x1f850, 0x1f859,
- 0x1f860, 0x1f887,
- 0x1f890, 0x1f8ad,
- 0x1fffe, 0x2a6d6,
- 0x2a700, 0x2b734,
- 0x2b740, 0x2b81d,
- 0x2f800, 0x2fa1d,
- 0x2fffe, 0x2ffff,
- 0x3fffe, 0x3ffff,
- 0x4fffe, 0x4ffff,
- 0x5fffe, 0x5ffff,
- 0x6fffe, 0x6ffff,
- 0x7fffe, 0x7ffff,
- 0x8fffe, 0x8ffff,
- 0x9fffe, 0x9ffff,
- 0xafffe, 0xaffff,
- 0xbfffe, 0xbffff,
- 0xcfffe, 0xcffff,
- 0xdfffe, 0xdffff,
- 0xe0001, 0xe0001,
- 0xe0020, 0xe007f,
- 0xe0100, 0xe01ef,
- 0xefffe, 0x10ffff,
-}; /* CR_Age_7_0 */
-
-/* 'Age_8_0': Derived Age 8.0 */
-static const OnigCodePoint CR_Age_8_0[] = {
- 623,
- 0x0000, 0x0377,
- 0x037a, 0x037f,
- 0x0384, 0x038a,
- 0x038c, 0x038c,
- 0x038e, 0x03a1,
- 0x03a3, 0x052f,
- 0x0531, 0x0556,
- 0x0559, 0x055f,
- 0x0561, 0x0587,
- 0x0589, 0x058a,
- 0x058d, 0x058f,
- 0x0591, 0x05c7,
- 0x05d0, 0x05ea,
- 0x05f0, 0x05f4,
- 0x0600, 0x061c,
- 0x061e, 0x070d,
- 0x070f, 0x074a,
- 0x074d, 0x07b1,
- 0x07c0, 0x07fa,
- 0x0800, 0x082d,
- 0x0830, 0x083e,
- 0x0840, 0x085b,
- 0x085e, 0x085e,
- 0x08a0, 0x08b4,
- 0x08e3, 0x0983,
- 0x0985, 0x098c,
- 0x098f, 0x0990,
- 0x0993, 0x09a8,
- 0x09aa, 0x09b0,
- 0x09b2, 0x09b2,
- 0x09b6, 0x09b9,
- 0x09bc, 0x09c4,
- 0x09c7, 0x09c8,
- 0x09cb, 0x09ce,
- 0x09d7, 0x09d7,
- 0x09dc, 0x09dd,
- 0x09df, 0x09e3,
- 0x09e6, 0x09fb,
- 0x0a01, 0x0a03,
- 0x0a05, 0x0a0a,
- 0x0a0f, 0x0a10,
- 0x0a13, 0x0a28,
- 0x0a2a, 0x0a30,
- 0x0a32, 0x0a33,
- 0x0a35, 0x0a36,
- 0x0a38, 0x0a39,
- 0x0a3c, 0x0a3c,
- 0x0a3e, 0x0a42,
- 0x0a47, 0x0a48,
- 0x0a4b, 0x0a4d,
- 0x0a51, 0x0a51,
- 0x0a59, 0x0a5c,
- 0x0a5e, 0x0a5e,
- 0x0a66, 0x0a75,
- 0x0a81, 0x0a83,
- 0x0a85, 0x0a8d,
- 0x0a8f, 0x0a91,
- 0x0a93, 0x0aa8,
- 0x0aaa, 0x0ab0,
- 0x0ab2, 0x0ab3,
- 0x0ab5, 0x0ab9,
- 0x0abc, 0x0ac5,
- 0x0ac7, 0x0ac9,
- 0x0acb, 0x0acd,
- 0x0ad0, 0x0ad0,
- 0x0ae0, 0x0ae3,
- 0x0ae6, 0x0af1,
- 0x0af9, 0x0af9,
- 0x0b01, 0x0b03,
- 0x0b05, 0x0b0c,
- 0x0b0f, 0x0b10,
- 0x0b13, 0x0b28,
- 0x0b2a, 0x0b30,
- 0x0b32, 0x0b33,
- 0x0b35, 0x0b39,
- 0x0b3c, 0x0b44,
- 0x0b47, 0x0b48,
- 0x0b4b, 0x0b4d,
- 0x0b56, 0x0b57,
- 0x0b5c, 0x0b5d,
- 0x0b5f, 0x0b63,
- 0x0b66, 0x0b77,
- 0x0b82, 0x0b83,
- 0x0b85, 0x0b8a,
- 0x0b8e, 0x0b90,
- 0x0b92, 0x0b95,
- 0x0b99, 0x0b9a,
- 0x0b9c, 0x0b9c,
- 0x0b9e, 0x0b9f,
- 0x0ba3, 0x0ba4,
- 0x0ba8, 0x0baa,
- 0x0bae, 0x0bb9,
- 0x0bbe, 0x0bc2,
- 0x0bc6, 0x0bc8,
- 0x0bca, 0x0bcd,
- 0x0bd0, 0x0bd0,
- 0x0bd7, 0x0bd7,
- 0x0be6, 0x0bfa,
- 0x0c00, 0x0c03,
- 0x0c05, 0x0c0c,
- 0x0c0e, 0x0c10,
- 0x0c12, 0x0c28,
- 0x0c2a, 0x0c39,
- 0x0c3d, 0x0c44,
- 0x0c46, 0x0c48,
- 0x0c4a, 0x0c4d,
- 0x0c55, 0x0c56,
- 0x0c58, 0x0c5a,
- 0x0c60, 0x0c63,
- 0x0c66, 0x0c6f,
- 0x0c78, 0x0c7f,
- 0x0c81, 0x0c83,
- 0x0c85, 0x0c8c,
- 0x0c8e, 0x0c90,
- 0x0c92, 0x0ca8,
- 0x0caa, 0x0cb3,
- 0x0cb5, 0x0cb9,
- 0x0cbc, 0x0cc4,
- 0x0cc6, 0x0cc8,
- 0x0cca, 0x0ccd,
- 0x0cd5, 0x0cd6,
- 0x0cde, 0x0cde,
- 0x0ce0, 0x0ce3,
- 0x0ce6, 0x0cef,
- 0x0cf1, 0x0cf2,
- 0x0d01, 0x0d03,
- 0x0d05, 0x0d0c,
- 0x0d0e, 0x0d10,
- 0x0d12, 0x0d3a,
- 0x0d3d, 0x0d44,
- 0x0d46, 0x0d48,
- 0x0d4a, 0x0d4e,
- 0x0d57, 0x0d57,
- 0x0d5f, 0x0d63,
- 0x0d66, 0x0d75,
- 0x0d79, 0x0d7f,
- 0x0d82, 0x0d83,
- 0x0d85, 0x0d96,
- 0x0d9a, 0x0db1,
- 0x0db3, 0x0dbb,
- 0x0dbd, 0x0dbd,
- 0x0dc0, 0x0dc6,
- 0x0dca, 0x0dca,
- 0x0dcf, 0x0dd4,
- 0x0dd6, 0x0dd6,
- 0x0dd8, 0x0ddf,
- 0x0de6, 0x0def,
- 0x0df2, 0x0df4,
- 0x0e01, 0x0e3a,
- 0x0e3f, 0x0e5b,
- 0x0e81, 0x0e82,
- 0x0e84, 0x0e84,
- 0x0e87, 0x0e88,
- 0x0e8a, 0x0e8a,
- 0x0e8d, 0x0e8d,
- 0x0e94, 0x0e97,
- 0x0e99, 0x0e9f,
- 0x0ea1, 0x0ea3,
- 0x0ea5, 0x0ea5,
- 0x0ea7, 0x0ea7,
- 0x0eaa, 0x0eab,
- 0x0ead, 0x0eb9,
- 0x0ebb, 0x0ebd,
- 0x0ec0, 0x0ec4,
- 0x0ec6, 0x0ec6,
- 0x0ec8, 0x0ecd,
- 0x0ed0, 0x0ed9,
- 0x0edc, 0x0edf,
- 0x0f00, 0x0f47,
- 0x0f49, 0x0f6c,
- 0x0f71, 0x0f97,
- 0x0f99, 0x0fbc,
- 0x0fbe, 0x0fcc,
- 0x0fce, 0x0fda,
- 0x1000, 0x10c5,
- 0x10c7, 0x10c7,
- 0x10cd, 0x10cd,
- 0x10d0, 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,
- 0x135d, 0x137c,
- 0x1380, 0x1399,
- 0x13a0, 0x13f5,
- 0x13f8, 0x13fd,
- 0x1400, 0x169c,
- 0x16a0, 0x16f8,
- 0x1700, 0x170c,
- 0x170e, 0x1714,
- 0x1720, 0x1736,
- 0x1740, 0x1753,
- 0x1760, 0x176c,
- 0x176e, 0x1770,
- 0x1772, 0x1773,
- 0x1780, 0x17dd,
- 0x17e0, 0x17e9,
- 0x17f0, 0x17f9,
- 0x1800, 0x180e,
- 0x1810, 0x1819,
- 0x1820, 0x1877,
- 0x1880, 0x18aa,
- 0x18b0, 0x18f5,
- 0x1900, 0x191e,
- 0x1920, 0x192b,
- 0x1930, 0x193b,
- 0x1940, 0x1940,
- 0x1944, 0x196d,
- 0x1970, 0x1974,
- 0x1980, 0x19ab,
- 0x19b0, 0x19c9,
- 0x19d0, 0x19da,
- 0x19de, 0x1a1b,
- 0x1a1e, 0x1a5e,
- 0x1a60, 0x1a7c,
- 0x1a7f, 0x1a89,
- 0x1a90, 0x1a99,
- 0x1aa0, 0x1aad,
- 0x1ab0, 0x1abe,
- 0x1b00, 0x1b4b,
- 0x1b50, 0x1b7c,
- 0x1b80, 0x1bf3,
- 0x1bfc, 0x1c37,
- 0x1c3b, 0x1c49,
- 0x1c4d, 0x1c7f,
- 0x1cc0, 0x1cc7,
- 0x1cd0, 0x1cf6,
- 0x1cf8, 0x1cf9,
- 0x1d00, 0x1df5,
- 0x1dfc, 0x1f15,
- 0x1f18, 0x1f1d,
- 0x1f20, 0x1f45,
- 0x1f48, 0x1f4d,
- 0x1f50, 0x1f57,
- 0x1f59, 0x1f59,
- 0x1f5b, 0x1f5b,
- 0x1f5d, 0x1f5d,
- 0x1f5f, 0x1f7d,
- 0x1f80, 0x1fb4,
- 0x1fb6, 0x1fc4,
- 0x1fc6, 0x1fd3,
- 0x1fd6, 0x1fdb,
- 0x1fdd, 0x1fef,
- 0x1ff2, 0x1ff4,
- 0x1ff6, 0x1ffe,
- 0x2000, 0x2064,
- 0x2066, 0x2071,
- 0x2074, 0x208e,
- 0x2090, 0x209c,
- 0x20a0, 0x20be,
- 0x20d0, 0x20f0,
- 0x2100, 0x218b,
- 0x2190, 0x23fa,
- 0x2400, 0x2426,
- 0x2440, 0x244a,
- 0x2460, 0x2b73,
- 0x2b76, 0x2b95,
- 0x2b98, 0x2bb9,
- 0x2bbd, 0x2bc8,
- 0x2bca, 0x2bd1,
- 0x2bec, 0x2bef,
- 0x2c00, 0x2c2e,
- 0x2c30, 0x2c5e,
- 0x2c60, 0x2cf3,
- 0x2cf9, 0x2d25,
- 0x2d27, 0x2d27,
- 0x2d2d, 0x2d2d,
- 0x2d30, 0x2d67,
- 0x2d6f, 0x2d70,
- 0x2d7f, 0x2d96,
- 0x2da0, 0x2da6,
- 0x2da8, 0x2dae,
- 0x2db0, 0x2db6,
- 0x2db8, 0x2dbe,
- 0x2dc0, 0x2dc6,
- 0x2dc8, 0x2dce,
- 0x2dd0, 0x2dd6,
- 0x2dd8, 0x2dde,
- 0x2de0, 0x2e42,
- 0x2e80, 0x2e99,
- 0x2e9b, 0x2ef3,
- 0x2f00, 0x2fd5,
- 0x2ff0, 0x2ffb,
- 0x3000, 0x303f,
- 0x3041, 0x3096,
- 0x3099, 0x30ff,
- 0x3105, 0x312d,
- 0x3131, 0x318e,
- 0x3190, 0x31ba,
- 0x31c0, 0x31e3,
- 0x31f0, 0x321e,
- 0x3220, 0x32fe,
- 0x3300, 0x4db5,
- 0x4dc0, 0x9fd5,
- 0xa000, 0xa48c,
- 0xa490, 0xa4c6,
- 0xa4d0, 0xa62b,
- 0xa640, 0xa6f7,
- 0xa700, 0xa7ad,
- 0xa7b0, 0xa7b7,
- 0xa7f7, 0xa82b,
- 0xa830, 0xa839,
- 0xa840, 0xa877,
- 0xa880, 0xa8c4,
- 0xa8ce, 0xa8d9,
- 0xa8e0, 0xa8fd,
- 0xa900, 0xa953,
- 0xa95f, 0xa97c,
- 0xa980, 0xa9cd,
- 0xa9cf, 0xa9d9,
- 0xa9de, 0xa9fe,
- 0xaa00, 0xaa36,
- 0xaa40, 0xaa4d,
- 0xaa50, 0xaa59,
- 0xaa5c, 0xaac2,
- 0xaadb, 0xaaf6,
- 0xab01, 0xab06,
- 0xab09, 0xab0e,
- 0xab11, 0xab16,
- 0xab20, 0xab26,
- 0xab28, 0xab2e,
- 0xab30, 0xab65,
- 0xab70, 0xabed,
- 0xabf0, 0xabf9,
- 0xac00, 0xd7a3,
- 0xd7b0, 0xd7c6,
- 0xd7cb, 0xd7fb,
- 0xd800, 0xfa6d,
- 0xfa70, 0xfad9,
- 0xfb00, 0xfb06,
- 0xfb13, 0xfb17,
- 0xfb1d, 0xfb36,
- 0xfb38, 0xfb3c,
- 0xfb3e, 0xfb3e,
- 0xfb40, 0xfb41,
- 0xfb43, 0xfb44,
- 0xfb46, 0xfbc1,
- 0xfbd3, 0xfd3f,
- 0xfd50, 0xfd8f,
- 0xfd92, 0xfdc7,
- 0xfdd0, 0xfdfd,
- 0xfe00, 0xfe19,
- 0xfe20, 0xfe52,
- 0xfe54, 0xfe66,
- 0xfe68, 0xfe6b,
- 0xfe70, 0xfe74,
- 0xfe76, 0xfefc,
- 0xfeff, 0xfeff,
- 0xff01, 0xffbe,
- 0xffc2, 0xffc7,
- 0xffca, 0xffcf,
- 0xffd2, 0xffd7,
- 0xffda, 0xffdc,
- 0xffe0, 0xffe6,
- 0xffe8, 0xffee,
- 0xfff9, 0x1000b,
- 0x1000d, 0x10026,
- 0x10028, 0x1003a,
- 0x1003c, 0x1003d,
- 0x1003f, 0x1004d,
- 0x10050, 0x1005d,
- 0x10080, 0x100fa,
- 0x10100, 0x10102,
- 0x10107, 0x10133,
- 0x10137, 0x1018c,
- 0x10190, 0x1019b,
- 0x101a0, 0x101a0,
- 0x101d0, 0x101fd,
- 0x10280, 0x1029c,
- 0x102a0, 0x102d0,
- 0x102e0, 0x102fb,
- 0x10300, 0x10323,
- 0x10330, 0x1034a,
- 0x10350, 0x1037a,
- 0x10380, 0x1039d,
- 0x1039f, 0x103c3,
- 0x103c8, 0x103d5,
- 0x10400, 0x1049d,
- 0x104a0, 0x104a9,
- 0x10500, 0x10527,
- 0x10530, 0x10563,
- 0x1056f, 0x1056f,
- 0x10600, 0x10736,
- 0x10740, 0x10755,
- 0x10760, 0x10767,
- 0x10800, 0x10805,
- 0x10808, 0x10808,
- 0x1080a, 0x10835,
- 0x10837, 0x10838,
- 0x1083c, 0x1083c,
- 0x1083f, 0x10855,
- 0x10857, 0x1089e,
- 0x108a7, 0x108af,
- 0x108e0, 0x108f2,
- 0x108f4, 0x108f5,
- 0x108fb, 0x1091b,
- 0x1091f, 0x10939,
- 0x1093f, 0x1093f,
- 0x10980, 0x109b7,
- 0x109bc, 0x109cf,
- 0x109d2, 0x10a03,
- 0x10a05, 0x10a06,
- 0x10a0c, 0x10a13,
- 0x10a15, 0x10a17,
- 0x10a19, 0x10a33,
- 0x10a38, 0x10a3a,
- 0x10a3f, 0x10a47,
- 0x10a50, 0x10a58,
- 0x10a60, 0x10a9f,
- 0x10ac0, 0x10ae6,
- 0x10aeb, 0x10af6,
- 0x10b00, 0x10b35,
- 0x10b39, 0x10b55,
- 0x10b58, 0x10b72,
- 0x10b78, 0x10b91,
- 0x10b99, 0x10b9c,
- 0x10ba9, 0x10baf,
- 0x10c00, 0x10c48,
- 0x10c80, 0x10cb2,
- 0x10cc0, 0x10cf2,
- 0x10cfa, 0x10cff,
- 0x10e60, 0x10e7e,
- 0x11000, 0x1104d,
- 0x11052, 0x1106f,
- 0x1107f, 0x110c1,
- 0x110d0, 0x110e8,
- 0x110f0, 0x110f9,
- 0x11100, 0x11134,
- 0x11136, 0x11143,
- 0x11150, 0x11176,
- 0x11180, 0x111cd,
- 0x111d0, 0x111df,
- 0x111e1, 0x111f4,
- 0x11200, 0x11211,
- 0x11213, 0x1123d,
- 0x11280, 0x11286,
- 0x11288, 0x11288,
- 0x1128a, 0x1128d,
- 0x1128f, 0x1129d,
- 0x1129f, 0x112a9,
- 0x112b0, 0x112ea,
- 0x112f0, 0x112f9,
- 0x11300, 0x11303,
- 0x11305, 0x1130c,
- 0x1130f, 0x11310,
- 0x11313, 0x11328,
- 0x1132a, 0x11330,
- 0x11332, 0x11333,
- 0x11335, 0x11339,
- 0x1133c, 0x11344,
- 0x11347, 0x11348,
- 0x1134b, 0x1134d,
- 0x11350, 0x11350,
- 0x11357, 0x11357,
- 0x1135d, 0x11363,
- 0x11366, 0x1136c,
- 0x11370, 0x11374,
- 0x11480, 0x114c7,
- 0x114d0, 0x114d9,
- 0x11580, 0x115b5,
- 0x115b8, 0x115dd,
- 0x11600, 0x11644,
- 0x11650, 0x11659,
- 0x11680, 0x116b7,
- 0x116c0, 0x116c9,
- 0x11700, 0x11719,
- 0x1171d, 0x1172b,
- 0x11730, 0x1173f,
- 0x118a0, 0x118f2,
- 0x118ff, 0x118ff,
- 0x11ac0, 0x11af8,
- 0x12000, 0x12399,
- 0x12400, 0x1246e,
- 0x12470, 0x12474,
- 0x12480, 0x12543,
- 0x13000, 0x1342e,
- 0x14400, 0x14646,
- 0x16800, 0x16a38,
- 0x16a40, 0x16a5e,
- 0x16a60, 0x16a69,
- 0x16a6e, 0x16a6f,
- 0x16ad0, 0x16aed,
- 0x16af0, 0x16af5,
- 0x16b00, 0x16b45,
- 0x16b50, 0x16b59,
- 0x16b5b, 0x16b61,
- 0x16b63, 0x16b77,
- 0x16b7d, 0x16b8f,
- 0x16f00, 0x16f44,
- 0x16f50, 0x16f7e,
- 0x16f8f, 0x16f9f,
- 0x1b000, 0x1b001,
- 0x1bc00, 0x1bc6a,
- 0x1bc70, 0x1bc7c,
- 0x1bc80, 0x1bc88,
- 0x1bc90, 0x1bc99,
- 0x1bc9c, 0x1bca3,
- 0x1d000, 0x1d0f5,
- 0x1d100, 0x1d126,
- 0x1d129, 0x1d1e8,
- 0x1d200, 0x1d245,
- 0x1d300, 0x1d356,
- 0x1d360, 0x1d371,
- 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, 0x1d7cb,
- 0x1d7ce, 0x1da8b,
- 0x1da9b, 0x1da9f,
- 0x1daa1, 0x1daaf,
- 0x1e800, 0x1e8c4,
- 0x1e8c7, 0x1e8d6,
- 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,
- 0x1eef0, 0x1eef1,
- 0x1f000, 0x1f02b,
- 0x1f030, 0x1f093,
- 0x1f0a0, 0x1f0ae,
- 0x1f0b1, 0x1f0bf,
- 0x1f0c1, 0x1f0cf,
- 0x1f0d1, 0x1f0f5,
- 0x1f100, 0x1f10c,
- 0x1f110, 0x1f12e,
- 0x1f130, 0x1f16b,
- 0x1f170, 0x1f19a,
- 0x1f1e6, 0x1f202,
- 0x1f210, 0x1f23a,
- 0x1f240, 0x1f248,
- 0x1f250, 0x1f251,
- 0x1f300, 0x1f579,
- 0x1f57b, 0x1f5a3,
- 0x1f5a5, 0x1f6d0,
- 0x1f6e0, 0x1f6ec,
- 0x1f6f0, 0x1f6f3,
- 0x1f700, 0x1f773,
- 0x1f780, 0x1f7d4,
- 0x1f800, 0x1f80b,
- 0x1f810, 0x1f847,
- 0x1f850, 0x1f859,
- 0x1f860, 0x1f887,
- 0x1f890, 0x1f8ad,
- 0x1f910, 0x1f918,
- 0x1f980, 0x1f984,
- 0x1f9c0, 0x1f9c0,
- 0x1fffe, 0x2a6d6,
- 0x2a700, 0x2b734,
- 0x2b740, 0x2b81d,
- 0x2b820, 0x2cea1,
- 0x2f800, 0x2fa1d,
- 0x2fffe, 0x2ffff,
- 0x3fffe, 0x3ffff,
- 0x4fffe, 0x4ffff,
- 0x5fffe, 0x5ffff,
- 0x6fffe, 0x6ffff,
- 0x7fffe, 0x7ffff,
- 0x8fffe, 0x8ffff,
- 0x9fffe, 0x9ffff,
- 0xafffe, 0xaffff,
- 0xbfffe, 0xbffff,
- 0xcfffe, 0xcffff,
- 0xdfffe, 0xdffff,
- 0xe0001, 0xe0001,
- 0xe0020, 0xe007f,
- 0xe0100, 0xe01ef,
- 0xefffe, 0x10ffff,
-}; /* CR_Age_8_0 */
-
-/* 'Age_9_0': Derived Age 9.0 */
-static const OnigCodePoint CR_Age_9_0[] = {
- 648,
- 0x0000, 0x0377,
- 0x037a, 0x037f,
- 0x0384, 0x038a,
- 0x038c, 0x038c,
- 0x038e, 0x03a1,
- 0x03a3, 0x052f,
- 0x0531, 0x0556,
- 0x0559, 0x055f,
- 0x0561, 0x0587,
- 0x0589, 0x058a,
- 0x058d, 0x058f,
- 0x0591, 0x05c7,
- 0x05d0, 0x05ea,
- 0x05f0, 0x05f4,
- 0x0600, 0x061c,
- 0x061e, 0x070d,
- 0x070f, 0x074a,
- 0x074d, 0x07b1,
- 0x07c0, 0x07fa,
- 0x0800, 0x082d,
- 0x0830, 0x083e,
- 0x0840, 0x085b,
- 0x085e, 0x085e,
- 0x08a0, 0x08b4,
- 0x08b6, 0x08bd,
- 0x08d4, 0x0983,
- 0x0985, 0x098c,
- 0x098f, 0x0990,
- 0x0993, 0x09a8,
- 0x09aa, 0x09b0,
- 0x09b2, 0x09b2,
- 0x09b6, 0x09b9,
- 0x09bc, 0x09c4,
- 0x09c7, 0x09c8,
- 0x09cb, 0x09ce,
- 0x09d7, 0x09d7,
- 0x09dc, 0x09dd,
- 0x09df, 0x09e3,
- 0x09e6, 0x09fb,
- 0x0a01, 0x0a03,
- 0x0a05, 0x0a0a,
- 0x0a0f, 0x0a10,
- 0x0a13, 0x0a28,
- 0x0a2a, 0x0a30,
- 0x0a32, 0x0a33,
- 0x0a35, 0x0a36,
- 0x0a38, 0x0a39,
- 0x0a3c, 0x0a3c,
- 0x0a3e, 0x0a42,
- 0x0a47, 0x0a48,
- 0x0a4b, 0x0a4d,
- 0x0a51, 0x0a51,
- 0x0a59, 0x0a5c,
- 0x0a5e, 0x0a5e,
- 0x0a66, 0x0a75,
- 0x0a81, 0x0a83,
- 0x0a85, 0x0a8d,
- 0x0a8f, 0x0a91,
- 0x0a93, 0x0aa8,
- 0x0aaa, 0x0ab0,
- 0x0ab2, 0x0ab3,
- 0x0ab5, 0x0ab9,
- 0x0abc, 0x0ac5,
- 0x0ac7, 0x0ac9,
- 0x0acb, 0x0acd,
- 0x0ad0, 0x0ad0,
- 0x0ae0, 0x0ae3,
- 0x0ae6, 0x0af1,
- 0x0af9, 0x0af9,
- 0x0b01, 0x0b03,
- 0x0b05, 0x0b0c,
- 0x0b0f, 0x0b10,
- 0x0b13, 0x0b28,
- 0x0b2a, 0x0b30,
- 0x0b32, 0x0b33,
- 0x0b35, 0x0b39,
- 0x0b3c, 0x0b44,
- 0x0b47, 0x0b48,
- 0x0b4b, 0x0b4d,
- 0x0b56, 0x0b57,
- 0x0b5c, 0x0b5d,
- 0x0b5f, 0x0b63,
- 0x0b66, 0x0b77,
- 0x0b82, 0x0b83,
- 0x0b85, 0x0b8a,
- 0x0b8e, 0x0b90,
- 0x0b92, 0x0b95,
- 0x0b99, 0x0b9a,
- 0x0b9c, 0x0b9c,
- 0x0b9e, 0x0b9f,
- 0x0ba3, 0x0ba4,
- 0x0ba8, 0x0baa,
- 0x0bae, 0x0bb9,
- 0x0bbe, 0x0bc2,
- 0x0bc6, 0x0bc8,
- 0x0bca, 0x0bcd,
- 0x0bd0, 0x0bd0,
- 0x0bd7, 0x0bd7,
- 0x0be6, 0x0bfa,
- 0x0c00, 0x0c03,
- 0x0c05, 0x0c0c,
- 0x0c0e, 0x0c10,
- 0x0c12, 0x0c28,
- 0x0c2a, 0x0c39,
- 0x0c3d, 0x0c44,
- 0x0c46, 0x0c48,
- 0x0c4a, 0x0c4d,
- 0x0c55, 0x0c56,
- 0x0c58, 0x0c5a,
- 0x0c60, 0x0c63,
- 0x0c66, 0x0c6f,
- 0x0c78, 0x0c83,
- 0x0c85, 0x0c8c,
- 0x0c8e, 0x0c90,
- 0x0c92, 0x0ca8,
- 0x0caa, 0x0cb3,
- 0x0cb5, 0x0cb9,
- 0x0cbc, 0x0cc4,
- 0x0cc6, 0x0cc8,
- 0x0cca, 0x0ccd,
- 0x0cd5, 0x0cd6,
- 0x0cde, 0x0cde,
- 0x0ce0, 0x0ce3,
- 0x0ce6, 0x0cef,
- 0x0cf1, 0x0cf2,
- 0x0d01, 0x0d03,
- 0x0d05, 0x0d0c,
- 0x0d0e, 0x0d10,
- 0x0d12, 0x0d3a,
- 0x0d3d, 0x0d44,
- 0x0d46, 0x0d48,
- 0x0d4a, 0x0d4f,
- 0x0d54, 0x0d63,
- 0x0d66, 0x0d7f,
- 0x0d82, 0x0d83,
- 0x0d85, 0x0d96,
- 0x0d9a, 0x0db1,
- 0x0db3, 0x0dbb,
- 0x0dbd, 0x0dbd,
- 0x0dc0, 0x0dc6,
- 0x0dca, 0x0dca,
- 0x0dcf, 0x0dd4,
- 0x0dd6, 0x0dd6,
- 0x0dd8, 0x0ddf,
- 0x0de6, 0x0def,
- 0x0df2, 0x0df4,
- 0x0e01, 0x0e3a,
- 0x0e3f, 0x0e5b,
- 0x0e81, 0x0e82,
- 0x0e84, 0x0e84,
- 0x0e87, 0x0e88,
- 0x0e8a, 0x0e8a,
- 0x0e8d, 0x0e8d,
- 0x0e94, 0x0e97,
- 0x0e99, 0x0e9f,
- 0x0ea1, 0x0ea3,
- 0x0ea5, 0x0ea5,
- 0x0ea7, 0x0ea7,
- 0x0eaa, 0x0eab,
- 0x0ead, 0x0eb9,
- 0x0ebb, 0x0ebd,
- 0x0ec0, 0x0ec4,
- 0x0ec6, 0x0ec6,
- 0x0ec8, 0x0ecd,
- 0x0ed0, 0x0ed9,
- 0x0edc, 0x0edf,
- 0x0f00, 0x0f47,
- 0x0f49, 0x0f6c,
- 0x0f71, 0x0f97,
- 0x0f99, 0x0fbc,
- 0x0fbe, 0x0fcc,
- 0x0fce, 0x0fda,
- 0x1000, 0x10c5,
- 0x10c7, 0x10c7,
- 0x10cd, 0x10cd,
- 0x10d0, 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,
- 0x135d, 0x137c,
- 0x1380, 0x1399,
- 0x13a0, 0x13f5,
- 0x13f8, 0x13fd,
- 0x1400, 0x169c,
- 0x16a0, 0x16f8,
- 0x1700, 0x170c,
- 0x170e, 0x1714,
- 0x1720, 0x1736,
- 0x1740, 0x1753,
- 0x1760, 0x176c,
- 0x176e, 0x1770,
- 0x1772, 0x1773,
- 0x1780, 0x17dd,
- 0x17e0, 0x17e9,
- 0x17f0, 0x17f9,
- 0x1800, 0x180e,
- 0x1810, 0x1819,
- 0x1820, 0x1877,
- 0x1880, 0x18aa,
- 0x18b0, 0x18f5,
- 0x1900, 0x191e,
- 0x1920, 0x192b,
- 0x1930, 0x193b,
- 0x1940, 0x1940,
- 0x1944, 0x196d,
- 0x1970, 0x1974,
- 0x1980, 0x19ab,
- 0x19b0, 0x19c9,
- 0x19d0, 0x19da,
- 0x19de, 0x1a1b,
- 0x1a1e, 0x1a5e,
- 0x1a60, 0x1a7c,
- 0x1a7f, 0x1a89,
- 0x1a90, 0x1a99,
- 0x1aa0, 0x1aad,
- 0x1ab0, 0x1abe,
- 0x1b00, 0x1b4b,
- 0x1b50, 0x1b7c,
- 0x1b80, 0x1bf3,
- 0x1bfc, 0x1c37,
- 0x1c3b, 0x1c49,
- 0x1c4d, 0x1c88,
- 0x1cc0, 0x1cc7,
- 0x1cd0, 0x1cf6,
- 0x1cf8, 0x1cf9,
- 0x1d00, 0x1df5,
- 0x1dfb, 0x1f15,
- 0x1f18, 0x1f1d,
- 0x1f20, 0x1f45,
- 0x1f48, 0x1f4d,
- 0x1f50, 0x1f57,
- 0x1f59, 0x1f59,
- 0x1f5b, 0x1f5b,
- 0x1f5d, 0x1f5d,
- 0x1f5f, 0x1f7d,
- 0x1f80, 0x1fb4,
- 0x1fb6, 0x1fc4,
- 0x1fc6, 0x1fd3,
- 0x1fd6, 0x1fdb,
- 0x1fdd, 0x1fef,
- 0x1ff2, 0x1ff4,
- 0x1ff6, 0x1ffe,
- 0x2000, 0x2064,
- 0x2066, 0x2071,
- 0x2074, 0x208e,
- 0x2090, 0x209c,
- 0x20a0, 0x20be,
- 0x20d0, 0x20f0,
- 0x2100, 0x218b,
- 0x2190, 0x23fe,
- 0x2400, 0x2426,
- 0x2440, 0x244a,
- 0x2460, 0x2b73,
- 0x2b76, 0x2b95,
- 0x2b98, 0x2bb9,
- 0x2bbd, 0x2bc8,
- 0x2bca, 0x2bd1,
- 0x2bec, 0x2bef,
- 0x2c00, 0x2c2e,
- 0x2c30, 0x2c5e,
- 0x2c60, 0x2cf3,
- 0x2cf9, 0x2d25,
- 0x2d27, 0x2d27,
- 0x2d2d, 0x2d2d,
- 0x2d30, 0x2d67,
- 0x2d6f, 0x2d70,
- 0x2d7f, 0x2d96,
- 0x2da0, 0x2da6,
- 0x2da8, 0x2dae,
- 0x2db0, 0x2db6,
- 0x2db8, 0x2dbe,
- 0x2dc0, 0x2dc6,
- 0x2dc8, 0x2dce,
- 0x2dd0, 0x2dd6,
- 0x2dd8, 0x2dde,
- 0x2de0, 0x2e44,
- 0x2e80, 0x2e99,
- 0x2e9b, 0x2ef3,
- 0x2f00, 0x2fd5,
- 0x2ff0, 0x2ffb,
- 0x3000, 0x303f,
- 0x3041, 0x3096,
- 0x3099, 0x30ff,
- 0x3105, 0x312d,
- 0x3131, 0x318e,
- 0x3190, 0x31ba,
- 0x31c0, 0x31e3,
- 0x31f0, 0x321e,
- 0x3220, 0x32fe,
- 0x3300, 0x4db5,
- 0x4dc0, 0x9fd5,
- 0xa000, 0xa48c,
- 0xa490, 0xa4c6,
- 0xa4d0, 0xa62b,
- 0xa640, 0xa6f7,
- 0xa700, 0xa7ae,
- 0xa7b0, 0xa7b7,
- 0xa7f7, 0xa82b,
- 0xa830, 0xa839,
- 0xa840, 0xa877,
- 0xa880, 0xa8c5,
- 0xa8ce, 0xa8d9,
- 0xa8e0, 0xa8fd,
- 0xa900, 0xa953,
- 0xa95f, 0xa97c,
- 0xa980, 0xa9cd,
- 0xa9cf, 0xa9d9,
- 0xa9de, 0xa9fe,
- 0xaa00, 0xaa36,
- 0xaa40, 0xaa4d,
- 0xaa50, 0xaa59,
- 0xaa5c, 0xaac2,
- 0xaadb, 0xaaf6,
- 0xab01, 0xab06,
- 0xab09, 0xab0e,
- 0xab11, 0xab16,
- 0xab20, 0xab26,
- 0xab28, 0xab2e,
- 0xab30, 0xab65,
- 0xab70, 0xabed,
- 0xabf0, 0xabf9,
- 0xac00, 0xd7a3,
- 0xd7b0, 0xd7c6,
- 0xd7cb, 0xd7fb,
- 0xd800, 0xfa6d,
- 0xfa70, 0xfad9,
- 0xfb00, 0xfb06,
- 0xfb13, 0xfb17,
- 0xfb1d, 0xfb36,
- 0xfb38, 0xfb3c,
- 0xfb3e, 0xfb3e,
- 0xfb40, 0xfb41,
- 0xfb43, 0xfb44,
- 0xfb46, 0xfbc1,
- 0xfbd3, 0xfd3f,
- 0xfd50, 0xfd8f,
- 0xfd92, 0xfdc7,
- 0xfdd0, 0xfdfd,
- 0xfe00, 0xfe19,
- 0xfe20, 0xfe52,
- 0xfe54, 0xfe66,
- 0xfe68, 0xfe6b,
- 0xfe70, 0xfe74,
- 0xfe76, 0xfefc,
- 0xfeff, 0xfeff,
- 0xff01, 0xffbe,
- 0xffc2, 0xffc7,
- 0xffca, 0xffcf,
- 0xffd2, 0xffd7,
- 0xffda, 0xffdc,
- 0xffe0, 0xffe6,
- 0xffe8, 0xffee,
- 0xfff9, 0x1000b,
- 0x1000d, 0x10026,
- 0x10028, 0x1003a,
- 0x1003c, 0x1003d,
- 0x1003f, 0x1004d,
- 0x10050, 0x1005d,
- 0x10080, 0x100fa,
- 0x10100, 0x10102,
- 0x10107, 0x10133,
- 0x10137, 0x1018e,
- 0x10190, 0x1019b,
- 0x101a0, 0x101a0,
- 0x101d0, 0x101fd,
- 0x10280, 0x1029c,
- 0x102a0, 0x102d0,
- 0x102e0, 0x102fb,
- 0x10300, 0x10323,
- 0x10330, 0x1034a,
- 0x10350, 0x1037a,
- 0x10380, 0x1039d,
- 0x1039f, 0x103c3,
- 0x103c8, 0x103d5,
- 0x10400, 0x1049d,
- 0x104a0, 0x104a9,
- 0x104b0, 0x104d3,
- 0x104d8, 0x104fb,
- 0x10500, 0x10527,
- 0x10530, 0x10563,
- 0x1056f, 0x1056f,
- 0x10600, 0x10736,
- 0x10740, 0x10755,
- 0x10760, 0x10767,
- 0x10800, 0x10805,
- 0x10808, 0x10808,
- 0x1080a, 0x10835,
- 0x10837, 0x10838,
- 0x1083c, 0x1083c,
- 0x1083f, 0x10855,
- 0x10857, 0x1089e,
- 0x108a7, 0x108af,
- 0x108e0, 0x108f2,
- 0x108f4, 0x108f5,
- 0x108fb, 0x1091b,
- 0x1091f, 0x10939,
- 0x1093f, 0x1093f,
- 0x10980, 0x109b7,
- 0x109bc, 0x109cf,
- 0x109d2, 0x10a03,
- 0x10a05, 0x10a06,
- 0x10a0c, 0x10a13,
- 0x10a15, 0x10a17,
- 0x10a19, 0x10a33,
- 0x10a38, 0x10a3a,
- 0x10a3f, 0x10a47,
- 0x10a50, 0x10a58,
- 0x10a60, 0x10a9f,
- 0x10ac0, 0x10ae6,
- 0x10aeb, 0x10af6,
- 0x10b00, 0x10b35,
- 0x10b39, 0x10b55,
- 0x10b58, 0x10b72,
- 0x10b78, 0x10b91,
- 0x10b99, 0x10b9c,
- 0x10ba9, 0x10baf,
- 0x10c00, 0x10c48,
- 0x10c80, 0x10cb2,
- 0x10cc0, 0x10cf2,
- 0x10cfa, 0x10cff,
- 0x10e60, 0x10e7e,
- 0x11000, 0x1104d,
- 0x11052, 0x1106f,
- 0x1107f, 0x110c1,
- 0x110d0, 0x110e8,
- 0x110f0, 0x110f9,
- 0x11100, 0x11134,
- 0x11136, 0x11143,
- 0x11150, 0x11176,
- 0x11180, 0x111cd,
- 0x111d0, 0x111df,
- 0x111e1, 0x111f4,
- 0x11200, 0x11211,
- 0x11213, 0x1123e,
- 0x11280, 0x11286,
- 0x11288, 0x11288,
- 0x1128a, 0x1128d,
- 0x1128f, 0x1129d,
- 0x1129f, 0x112a9,
- 0x112b0, 0x112ea,
- 0x112f0, 0x112f9,
- 0x11300, 0x11303,
- 0x11305, 0x1130c,
- 0x1130f, 0x11310,
- 0x11313, 0x11328,
- 0x1132a, 0x11330,
- 0x11332, 0x11333,
- 0x11335, 0x11339,
- 0x1133c, 0x11344,
- 0x11347, 0x11348,
- 0x1134b, 0x1134d,
- 0x11350, 0x11350,
- 0x11357, 0x11357,
- 0x1135d, 0x11363,
- 0x11366, 0x1136c,
- 0x11370, 0x11374,
- 0x11400, 0x11459,
- 0x1145b, 0x1145b,
- 0x1145d, 0x1145d,
- 0x11480, 0x114c7,
- 0x114d0, 0x114d9,
- 0x11580, 0x115b5,
- 0x115b8, 0x115dd,
- 0x11600, 0x11644,
- 0x11650, 0x11659,
- 0x11660, 0x1166c,
- 0x11680, 0x116b7,
- 0x116c0, 0x116c9,
- 0x11700, 0x11719,
- 0x1171d, 0x1172b,
- 0x11730, 0x1173f,
- 0x118a0, 0x118f2,
- 0x118ff, 0x118ff,
- 0x11ac0, 0x11af8,
- 0x11c00, 0x11c08,
- 0x11c0a, 0x11c36,
- 0x11c38, 0x11c45,
- 0x11c50, 0x11c6c,
- 0x11c70, 0x11c8f,
- 0x11c92, 0x11ca7,
- 0x11ca9, 0x11cb6,
- 0x12000, 0x12399,
- 0x12400, 0x1246e,
- 0x12470, 0x12474,
- 0x12480, 0x12543,
- 0x13000, 0x1342e,
- 0x14400, 0x14646,
- 0x16800, 0x16a38,
- 0x16a40, 0x16a5e,
- 0x16a60, 0x16a69,
- 0x16a6e, 0x16a6f,
- 0x16ad0, 0x16aed,
- 0x16af0, 0x16af5,
- 0x16b00, 0x16b45,
- 0x16b50, 0x16b59,
- 0x16b5b, 0x16b61,
- 0x16b63, 0x16b77,
- 0x16b7d, 0x16b8f,
- 0x16f00, 0x16f44,
- 0x16f50, 0x16f7e,
- 0x16f8f, 0x16f9f,
- 0x16fe0, 0x16fe0,
- 0x17000, 0x187ec,
- 0x18800, 0x18af2,
- 0x1b000, 0x1b001,
- 0x1bc00, 0x1bc6a,
- 0x1bc70, 0x1bc7c,
- 0x1bc80, 0x1bc88,
- 0x1bc90, 0x1bc99,
- 0x1bc9c, 0x1bca3,
- 0x1d000, 0x1d0f5,
- 0x1d100, 0x1d126,
- 0x1d129, 0x1d1e8,
- 0x1d200, 0x1d245,
- 0x1d300, 0x1d356,
- 0x1d360, 0x1d371,
- 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, 0x1d7cb,
- 0x1d7ce, 0x1da8b,
- 0x1da9b, 0x1da9f,
- 0x1daa1, 0x1daaf,
- 0x1e000, 0x1e006,
- 0x1e008, 0x1e018,
- 0x1e01b, 0x1e021,
- 0x1e023, 0x1e024,
- 0x1e026, 0x1e02a,
- 0x1e800, 0x1e8c4,
- 0x1e8c7, 0x1e8d6,
- 0x1e900, 0x1e94a,
- 0x1e950, 0x1e959,
- 0x1e95e, 0x1e95f,
- 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,
- 0x1eef0, 0x1eef1,
- 0x1f000, 0x1f02b,
- 0x1f030, 0x1f093,
- 0x1f0a0, 0x1f0ae,
- 0x1f0b1, 0x1f0bf,
- 0x1f0c1, 0x1f0cf,
- 0x1f0d1, 0x1f0f5,
- 0x1f100, 0x1f10c,
- 0x1f110, 0x1f12e,
- 0x1f130, 0x1f16b,
- 0x1f170, 0x1f1ac,
- 0x1f1e6, 0x1f202,
- 0x1f210, 0x1f23b,
- 0x1f240, 0x1f248,
- 0x1f250, 0x1f251,
- 0x1f300, 0x1f6d2,
- 0x1f6e0, 0x1f6ec,
- 0x1f6f0, 0x1f6f6,
- 0x1f700, 0x1f773,
- 0x1f780, 0x1f7d4,
- 0x1f800, 0x1f80b,
- 0x1f810, 0x1f847,
- 0x1f850, 0x1f859,
- 0x1f860, 0x1f887,
- 0x1f890, 0x1f8ad,
- 0x1f910, 0x1f91e,
- 0x1f920, 0x1f927,
- 0x1f930, 0x1f930,
- 0x1f933, 0x1f93e,
- 0x1f940, 0x1f94b,
- 0x1f950, 0x1f95e,
- 0x1f980, 0x1f991,
- 0x1f9c0, 0x1f9c0,
- 0x1fffe, 0x2a6d6,
- 0x2a700, 0x2b734,
- 0x2b740, 0x2b81d,
- 0x2b820, 0x2cea1,
- 0x2f800, 0x2fa1d,
- 0x2fffe, 0x2ffff,
- 0x3fffe, 0x3ffff,
- 0x4fffe, 0x4ffff,
- 0x5fffe, 0x5ffff,
- 0x6fffe, 0x6ffff,
- 0x7fffe, 0x7ffff,
- 0x8fffe, 0x8ffff,
- 0x9fffe, 0x9ffff,
- 0xafffe, 0xaffff,
- 0xbfffe, 0xbffff,
- 0xcfffe, 0xcffff,
- 0xdfffe, 0xdffff,
- 0xe0001, 0xe0001,
- 0xe0020, 0xe007f,
- 0xe0100, 0xe01ef,
- 0xefffe, 0x10ffff,
-}; /* CR_Age_9_0 */
-
-/* 'Age_10_0': Derived Age 10.0 */
-static const OnigCodePoint CR_Age_10_0[] = {
- 659,
- 0x0000, 0x0377,
- 0x037a, 0x037f,
- 0x0384, 0x038a,
- 0x038c, 0x038c,
- 0x038e, 0x03a1,
- 0x03a3, 0x052f,
- 0x0531, 0x0556,
- 0x0559, 0x055f,
- 0x0561, 0x0587,
- 0x0589, 0x058a,
- 0x058d, 0x058f,
- 0x0591, 0x05c7,
- 0x05d0, 0x05ea,
- 0x05f0, 0x05f4,
- 0x0600, 0x061c,
- 0x061e, 0x070d,
- 0x070f, 0x074a,
- 0x074d, 0x07b1,
- 0x07c0, 0x07fa,
- 0x0800, 0x082d,
- 0x0830, 0x083e,
- 0x0840, 0x085b,
- 0x085e, 0x085e,
- 0x0860, 0x086a,
- 0x08a0, 0x08b4,
- 0x08b6, 0x08bd,
- 0x08d4, 0x0983,
- 0x0985, 0x098c,
- 0x098f, 0x0990,
- 0x0993, 0x09a8,
- 0x09aa, 0x09b0,
- 0x09b2, 0x09b2,
- 0x09b6, 0x09b9,
- 0x09bc, 0x09c4,
- 0x09c7, 0x09c8,
- 0x09cb, 0x09ce,
- 0x09d7, 0x09d7,
- 0x09dc, 0x09dd,
- 0x09df, 0x09e3,
- 0x09e6, 0x09fd,
- 0x0a01, 0x0a03,
- 0x0a05, 0x0a0a,
- 0x0a0f, 0x0a10,
- 0x0a13, 0x0a28,
- 0x0a2a, 0x0a30,
- 0x0a32, 0x0a33,
- 0x0a35, 0x0a36,
- 0x0a38, 0x0a39,
- 0x0a3c, 0x0a3c,
- 0x0a3e, 0x0a42,
- 0x0a47, 0x0a48,
- 0x0a4b, 0x0a4d,
- 0x0a51, 0x0a51,
- 0x0a59, 0x0a5c,
- 0x0a5e, 0x0a5e,
- 0x0a66, 0x0a75,
- 0x0a81, 0x0a83,
- 0x0a85, 0x0a8d,
- 0x0a8f, 0x0a91,
- 0x0a93, 0x0aa8,
- 0x0aaa, 0x0ab0,
- 0x0ab2, 0x0ab3,
- 0x0ab5, 0x0ab9,
- 0x0abc, 0x0ac5,
- 0x0ac7, 0x0ac9,
- 0x0acb, 0x0acd,
- 0x0ad0, 0x0ad0,
- 0x0ae0, 0x0ae3,
- 0x0ae6, 0x0af1,
- 0x0af9, 0x0aff,
- 0x0b01, 0x0b03,
- 0x0b05, 0x0b0c,
- 0x0b0f, 0x0b10,
- 0x0b13, 0x0b28,
- 0x0b2a, 0x0b30,
- 0x0b32, 0x0b33,
- 0x0b35, 0x0b39,
- 0x0b3c, 0x0b44,
- 0x0b47, 0x0b48,
- 0x0b4b, 0x0b4d,
- 0x0b56, 0x0b57,
- 0x0b5c, 0x0b5d,
- 0x0b5f, 0x0b63,
- 0x0b66, 0x0b77,
- 0x0b82, 0x0b83,
- 0x0b85, 0x0b8a,
- 0x0b8e, 0x0b90,
- 0x0b92, 0x0b95,
- 0x0b99, 0x0b9a,
- 0x0b9c, 0x0b9c,
- 0x0b9e, 0x0b9f,
- 0x0ba3, 0x0ba4,
- 0x0ba8, 0x0baa,
- 0x0bae, 0x0bb9,
- 0x0bbe, 0x0bc2,
- 0x0bc6, 0x0bc8,
- 0x0bca, 0x0bcd,
- 0x0bd0, 0x0bd0,
- 0x0bd7, 0x0bd7,
- 0x0be6, 0x0bfa,
- 0x0c00, 0x0c03,
- 0x0c05, 0x0c0c,
- 0x0c0e, 0x0c10,
- 0x0c12, 0x0c28,
- 0x0c2a, 0x0c39,
- 0x0c3d, 0x0c44,
- 0x0c46, 0x0c48,
- 0x0c4a, 0x0c4d,
- 0x0c55, 0x0c56,
- 0x0c58, 0x0c5a,
- 0x0c60, 0x0c63,
- 0x0c66, 0x0c6f,
- 0x0c78, 0x0c83,
- 0x0c85, 0x0c8c,
- 0x0c8e, 0x0c90,
- 0x0c92, 0x0ca8,
- 0x0caa, 0x0cb3,
- 0x0cb5, 0x0cb9,
- 0x0cbc, 0x0cc4,
- 0x0cc6, 0x0cc8,
- 0x0cca, 0x0ccd,
- 0x0cd5, 0x0cd6,
- 0x0cde, 0x0cde,
- 0x0ce0, 0x0ce3,
- 0x0ce6, 0x0cef,
- 0x0cf1, 0x0cf2,
- 0x0d00, 0x0d03,
- 0x0d05, 0x0d0c,
- 0x0d0e, 0x0d10,
- 0x0d12, 0x0d44,
- 0x0d46, 0x0d48,
- 0x0d4a, 0x0d4f,
- 0x0d54, 0x0d63,
- 0x0d66, 0x0d7f,
- 0x0d82, 0x0d83,
- 0x0d85, 0x0d96,
- 0x0d9a, 0x0db1,
- 0x0db3, 0x0dbb,
- 0x0dbd, 0x0dbd,
- 0x0dc0, 0x0dc6,
- 0x0dca, 0x0dca,
- 0x0dcf, 0x0dd4,
- 0x0dd6, 0x0dd6,
- 0x0dd8, 0x0ddf,
- 0x0de6, 0x0def,
- 0x0df2, 0x0df4,
- 0x0e01, 0x0e3a,
- 0x0e3f, 0x0e5b,
- 0x0e81, 0x0e82,
- 0x0e84, 0x0e84,
- 0x0e87, 0x0e88,
- 0x0e8a, 0x0e8a,
- 0x0e8d, 0x0e8d,
- 0x0e94, 0x0e97,
- 0x0e99, 0x0e9f,
- 0x0ea1, 0x0ea3,
- 0x0ea5, 0x0ea5,
- 0x0ea7, 0x0ea7,
- 0x0eaa, 0x0eab,
- 0x0ead, 0x0eb9,
- 0x0ebb, 0x0ebd,
- 0x0ec0, 0x0ec4,
- 0x0ec6, 0x0ec6,
- 0x0ec8, 0x0ecd,
- 0x0ed0, 0x0ed9,
- 0x0edc, 0x0edf,
- 0x0f00, 0x0f47,
- 0x0f49, 0x0f6c,
- 0x0f71, 0x0f97,
- 0x0f99, 0x0fbc,
- 0x0fbe, 0x0fcc,
- 0x0fce, 0x0fda,
- 0x1000, 0x10c5,
- 0x10c7, 0x10c7,
- 0x10cd, 0x10cd,
- 0x10d0, 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,
- 0x135d, 0x137c,
- 0x1380, 0x1399,
- 0x13a0, 0x13f5,
- 0x13f8, 0x13fd,
- 0x1400, 0x169c,
- 0x16a0, 0x16f8,
- 0x1700, 0x170c,
- 0x170e, 0x1714,
- 0x1720, 0x1736,
- 0x1740, 0x1753,
- 0x1760, 0x176c,
- 0x176e, 0x1770,
- 0x1772, 0x1773,
- 0x1780, 0x17dd,
- 0x17e0, 0x17e9,
- 0x17f0, 0x17f9,
- 0x1800, 0x180e,
- 0x1810, 0x1819,
- 0x1820, 0x1877,
- 0x1880, 0x18aa,
- 0x18b0, 0x18f5,
- 0x1900, 0x191e,
- 0x1920, 0x192b,
- 0x1930, 0x193b,
- 0x1940, 0x1940,
- 0x1944, 0x196d,
- 0x1970, 0x1974,
- 0x1980, 0x19ab,
- 0x19b0, 0x19c9,
- 0x19d0, 0x19da,
- 0x19de, 0x1a1b,
- 0x1a1e, 0x1a5e,
- 0x1a60, 0x1a7c,
- 0x1a7f, 0x1a89,
- 0x1a90, 0x1a99,
- 0x1aa0, 0x1aad,
- 0x1ab0, 0x1abe,
- 0x1b00, 0x1b4b,
- 0x1b50, 0x1b7c,
- 0x1b80, 0x1bf3,
- 0x1bfc, 0x1c37,
- 0x1c3b, 0x1c49,
- 0x1c4d, 0x1c88,
- 0x1cc0, 0x1cc7,
- 0x1cd0, 0x1cf9,
- 0x1d00, 0x1df9,
- 0x1dfb, 0x1f15,
- 0x1f18, 0x1f1d,
- 0x1f20, 0x1f45,
- 0x1f48, 0x1f4d,
- 0x1f50, 0x1f57,
- 0x1f59, 0x1f59,
- 0x1f5b, 0x1f5b,
- 0x1f5d, 0x1f5d,
- 0x1f5f, 0x1f7d,
- 0x1f80, 0x1fb4,
- 0x1fb6, 0x1fc4,
- 0x1fc6, 0x1fd3,
- 0x1fd6, 0x1fdb,
- 0x1fdd, 0x1fef,
- 0x1ff2, 0x1ff4,
- 0x1ff6, 0x1ffe,
- 0x2000, 0x2064,
- 0x2066, 0x2071,
- 0x2074, 0x208e,
- 0x2090, 0x209c,
- 0x20a0, 0x20bf,
- 0x20d0, 0x20f0,
- 0x2100, 0x218b,
- 0x2190, 0x2426,
- 0x2440, 0x244a,
- 0x2460, 0x2b73,
- 0x2b76, 0x2b95,
- 0x2b98, 0x2bb9,
- 0x2bbd, 0x2bc8,
- 0x2bca, 0x2bd2,
- 0x2bec, 0x2bef,
- 0x2c00, 0x2c2e,
- 0x2c30, 0x2c5e,
- 0x2c60, 0x2cf3,
- 0x2cf9, 0x2d25,
- 0x2d27, 0x2d27,
- 0x2d2d, 0x2d2d,
- 0x2d30, 0x2d67,
- 0x2d6f, 0x2d70,
- 0x2d7f, 0x2d96,
- 0x2da0, 0x2da6,
- 0x2da8, 0x2dae,
- 0x2db0, 0x2db6,
- 0x2db8, 0x2dbe,
- 0x2dc0, 0x2dc6,
- 0x2dc8, 0x2dce,
- 0x2dd0, 0x2dd6,
- 0x2dd8, 0x2dde,
- 0x2de0, 0x2e49,
- 0x2e80, 0x2e99,
- 0x2e9b, 0x2ef3,
- 0x2f00, 0x2fd5,
- 0x2ff0, 0x2ffb,
- 0x3000, 0x303f,
- 0x3041, 0x3096,
- 0x3099, 0x30ff,
- 0x3105, 0x312e,
- 0x3131, 0x318e,
- 0x3190, 0x31ba,
- 0x31c0, 0x31e3,
- 0x31f0, 0x321e,
- 0x3220, 0x32fe,
- 0x3300, 0x4db5,
- 0x4dc0, 0x9fea,
- 0xa000, 0xa48c,
- 0xa490, 0xa4c6,
- 0xa4d0, 0xa62b,
- 0xa640, 0xa6f7,
- 0xa700, 0xa7ae,
- 0xa7b0, 0xa7b7,
- 0xa7f7, 0xa82b,
- 0xa830, 0xa839,
- 0xa840, 0xa877,
- 0xa880, 0xa8c5,
- 0xa8ce, 0xa8d9,
- 0xa8e0, 0xa8fd,
- 0xa900, 0xa953,
- 0xa95f, 0xa97c,
- 0xa980, 0xa9cd,
- 0xa9cf, 0xa9d9,
- 0xa9de, 0xa9fe,
- 0xaa00, 0xaa36,
- 0xaa40, 0xaa4d,
- 0xaa50, 0xaa59,
- 0xaa5c, 0xaac2,
- 0xaadb, 0xaaf6,
- 0xab01, 0xab06,
- 0xab09, 0xab0e,
- 0xab11, 0xab16,
- 0xab20, 0xab26,
- 0xab28, 0xab2e,
- 0xab30, 0xab65,
- 0xab70, 0xabed,
- 0xabf0, 0xabf9,
- 0xac00, 0xd7a3,
- 0xd7b0, 0xd7c6,
- 0xd7cb, 0xd7fb,
- 0xd800, 0xfa6d,
- 0xfa70, 0xfad9,
- 0xfb00, 0xfb06,
- 0xfb13, 0xfb17,
- 0xfb1d, 0xfb36,
- 0xfb38, 0xfb3c,
- 0xfb3e, 0xfb3e,
- 0xfb40, 0xfb41,
- 0xfb43, 0xfb44,
- 0xfb46, 0xfbc1,
- 0xfbd3, 0xfd3f,
- 0xfd50, 0xfd8f,
- 0xfd92, 0xfdc7,
- 0xfdd0, 0xfdfd,
- 0xfe00, 0xfe19,
- 0xfe20, 0xfe52,
- 0xfe54, 0xfe66,
- 0xfe68, 0xfe6b,
- 0xfe70, 0xfe74,
- 0xfe76, 0xfefc,
- 0xfeff, 0xfeff,
- 0xff01, 0xffbe,
- 0xffc2, 0xffc7,
- 0xffca, 0xffcf,
- 0xffd2, 0xffd7,
- 0xffda, 0xffdc,
- 0xffe0, 0xffe6,
- 0xffe8, 0xffee,
- 0xfff9, 0x1000b,
- 0x1000d, 0x10026,
- 0x10028, 0x1003a,
- 0x1003c, 0x1003d,
- 0x1003f, 0x1004d,
- 0x10050, 0x1005d,
- 0x10080, 0x100fa,
- 0x10100, 0x10102,
- 0x10107, 0x10133,
- 0x10137, 0x1018e,
- 0x10190, 0x1019b,
- 0x101a0, 0x101a0,
- 0x101d0, 0x101fd,
- 0x10280, 0x1029c,
- 0x102a0, 0x102d0,
- 0x102e0, 0x102fb,
- 0x10300, 0x10323,
- 0x1032d, 0x1034a,
- 0x10350, 0x1037a,
- 0x10380, 0x1039d,
- 0x1039f, 0x103c3,
- 0x103c8, 0x103d5,
- 0x10400, 0x1049d,
- 0x104a0, 0x104a9,
- 0x104b0, 0x104d3,
- 0x104d8, 0x104fb,
- 0x10500, 0x10527,
- 0x10530, 0x10563,
- 0x1056f, 0x1056f,
- 0x10600, 0x10736,
- 0x10740, 0x10755,
- 0x10760, 0x10767,
- 0x10800, 0x10805,
- 0x10808, 0x10808,
- 0x1080a, 0x10835,
- 0x10837, 0x10838,
- 0x1083c, 0x1083c,
- 0x1083f, 0x10855,
- 0x10857, 0x1089e,
- 0x108a7, 0x108af,
- 0x108e0, 0x108f2,
- 0x108f4, 0x108f5,
- 0x108fb, 0x1091b,
- 0x1091f, 0x10939,
- 0x1093f, 0x1093f,
- 0x10980, 0x109b7,
- 0x109bc, 0x109cf,
- 0x109d2, 0x10a03,
- 0x10a05, 0x10a06,
- 0x10a0c, 0x10a13,
- 0x10a15, 0x10a17,
- 0x10a19, 0x10a33,
- 0x10a38, 0x10a3a,
- 0x10a3f, 0x10a47,
- 0x10a50, 0x10a58,
- 0x10a60, 0x10a9f,
- 0x10ac0, 0x10ae6,
- 0x10aeb, 0x10af6,
- 0x10b00, 0x10b35,
- 0x10b39, 0x10b55,
- 0x10b58, 0x10b72,
- 0x10b78, 0x10b91,
- 0x10b99, 0x10b9c,
- 0x10ba9, 0x10baf,
- 0x10c00, 0x10c48,
- 0x10c80, 0x10cb2,
- 0x10cc0, 0x10cf2,
- 0x10cfa, 0x10cff,
- 0x10e60, 0x10e7e,
- 0x11000, 0x1104d,
- 0x11052, 0x1106f,
- 0x1107f, 0x110c1,
- 0x110d0, 0x110e8,
- 0x110f0, 0x110f9,
- 0x11100, 0x11134,
- 0x11136, 0x11143,
- 0x11150, 0x11176,
- 0x11180, 0x111cd,
- 0x111d0, 0x111df,
- 0x111e1, 0x111f4,
- 0x11200, 0x11211,
- 0x11213, 0x1123e,
- 0x11280, 0x11286,
- 0x11288, 0x11288,
- 0x1128a, 0x1128d,
- 0x1128f, 0x1129d,
- 0x1129f, 0x112a9,
- 0x112b0, 0x112ea,
- 0x112f0, 0x112f9,
- 0x11300, 0x11303,
- 0x11305, 0x1130c,
- 0x1130f, 0x11310,
- 0x11313, 0x11328,
- 0x1132a, 0x11330,
- 0x11332, 0x11333,
- 0x11335, 0x11339,
- 0x1133c, 0x11344,
- 0x11347, 0x11348,
- 0x1134b, 0x1134d,
- 0x11350, 0x11350,
- 0x11357, 0x11357,
- 0x1135d, 0x11363,
- 0x11366, 0x1136c,
- 0x11370, 0x11374,
- 0x11400, 0x11459,
- 0x1145b, 0x1145b,
- 0x1145d, 0x1145d,
- 0x11480, 0x114c7,
- 0x114d0, 0x114d9,
- 0x11580, 0x115b5,
- 0x115b8, 0x115dd,
- 0x11600, 0x11644,
- 0x11650, 0x11659,
- 0x11660, 0x1166c,
- 0x11680, 0x116b7,
- 0x116c0, 0x116c9,
- 0x11700, 0x11719,
- 0x1171d, 0x1172b,
- 0x11730, 0x1173f,
- 0x118a0, 0x118f2,
- 0x118ff, 0x118ff,
- 0x11a00, 0x11a47,
- 0x11a50, 0x11a83,
- 0x11a86, 0x11a9c,
- 0x11a9e, 0x11aa2,
- 0x11ac0, 0x11af8,
- 0x11c00, 0x11c08,
- 0x11c0a, 0x11c36,
- 0x11c38, 0x11c45,
- 0x11c50, 0x11c6c,
- 0x11c70, 0x11c8f,
- 0x11c92, 0x11ca7,
- 0x11ca9, 0x11cb6,
- 0x11d00, 0x11d06,
- 0x11d08, 0x11d09,
- 0x11d0b, 0x11d36,
- 0x11d3a, 0x11d3a,
- 0x11d3c, 0x11d3d,
- 0x11d3f, 0x11d47,
- 0x11d50, 0x11d59,
- 0x12000, 0x12399,
- 0x12400, 0x1246e,
- 0x12470, 0x12474,
- 0x12480, 0x12543,
- 0x13000, 0x1342e,
- 0x14400, 0x14646,
- 0x16800, 0x16a38,
- 0x16a40, 0x16a5e,
- 0x16a60, 0x16a69,
- 0x16a6e, 0x16a6f,
- 0x16ad0, 0x16aed,
- 0x16af0, 0x16af5,
- 0x16b00, 0x16b45,
- 0x16b50, 0x16b59,
- 0x16b5b, 0x16b61,
- 0x16b63, 0x16b77,
- 0x16b7d, 0x16b8f,
- 0x16f00, 0x16f44,
- 0x16f50, 0x16f7e,
- 0x16f8f, 0x16f9f,
- 0x16fe0, 0x16fe1,
- 0x17000, 0x187ec,
- 0x18800, 0x18af2,
- 0x1b000, 0x1b11e,
- 0x1b170, 0x1b2fb,
- 0x1bc00, 0x1bc6a,
- 0x1bc70, 0x1bc7c,
- 0x1bc80, 0x1bc88,
- 0x1bc90, 0x1bc99,
- 0x1bc9c, 0x1bca3,
- 0x1d000, 0x1d0f5,
- 0x1d100, 0x1d126,
- 0x1d129, 0x1d1e8,
- 0x1d200, 0x1d245,
- 0x1d300, 0x1d356,
- 0x1d360, 0x1d371,
- 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, 0x1d7cb,
- 0x1d7ce, 0x1da8b,
- 0x1da9b, 0x1da9f,
- 0x1daa1, 0x1daaf,
- 0x1e000, 0x1e006,
- 0x1e008, 0x1e018,
- 0x1e01b, 0x1e021,
- 0x1e023, 0x1e024,
- 0x1e026, 0x1e02a,
- 0x1e800, 0x1e8c4,
- 0x1e8c7, 0x1e8d6,
- 0x1e900, 0x1e94a,
- 0x1e950, 0x1e959,
- 0x1e95e, 0x1e95f,
- 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,
- 0x1eef0, 0x1eef1,
- 0x1f000, 0x1f02b,
- 0x1f030, 0x1f093,
- 0x1f0a0, 0x1f0ae,
- 0x1f0b1, 0x1f0bf,
- 0x1f0c1, 0x1f0cf,
- 0x1f0d1, 0x1f0f5,
- 0x1f100, 0x1f10c,
- 0x1f110, 0x1f12e,
- 0x1f130, 0x1f16b,
- 0x1f170, 0x1f1ac,
- 0x1f1e6, 0x1f202,
- 0x1f210, 0x1f23b,
- 0x1f240, 0x1f248,
- 0x1f250, 0x1f251,
- 0x1f260, 0x1f265,
- 0x1f300, 0x1f6d4,
- 0x1f6e0, 0x1f6ec,
- 0x1f6f0, 0x1f6f8,
- 0x1f700, 0x1f773,
- 0x1f780, 0x1f7d4,
- 0x1f800, 0x1f80b,
- 0x1f810, 0x1f847,
- 0x1f850, 0x1f859,
- 0x1f860, 0x1f887,
- 0x1f890, 0x1f8ad,
- 0x1f900, 0x1f90b,
- 0x1f910, 0x1f93e,
- 0x1f940, 0x1f94c,
- 0x1f950, 0x1f96b,
- 0x1f980, 0x1f997,
- 0x1f9c0, 0x1f9c0,
- 0x1f9d0, 0x1f9e6,
- 0x1fffe, 0x2a6d6,
- 0x2a700, 0x2b734,
- 0x2b740, 0x2b81d,
- 0x2b820, 0x2cea1,
- 0x2ceb0, 0x2ebe0,
- 0x2f800, 0x2fa1d,
- 0x2fffe, 0x2ffff,
- 0x3fffe, 0x3ffff,
- 0x4fffe, 0x4ffff,
- 0x5fffe, 0x5ffff,
- 0x6fffe, 0x6ffff,
- 0x7fffe, 0x7ffff,
- 0x8fffe, 0x8ffff,
- 0x9fffe, 0x9ffff,
- 0xafffe, 0xaffff,
- 0xbfffe, 0xbffff,
- 0xcfffe, 0xcffff,
- 0xdfffe, 0xdffff,
- 0xe0001, 0xe0001,
- 0xe0020, 0xe007f,
- 0xe0100, 0xe01ef,
- 0xefffe, 0x10ffff,
-}; /* CR_Age_10_0 */
-
-/* 'Age_11_0': Derived Age 11.0 */
-static const OnigCodePoint CR_Age_11_0[] = {
- 668,
- 0x0000, 0x0377,
- 0x037a, 0x037f,
- 0x0384, 0x038a,
- 0x038c, 0x038c,
- 0x038e, 0x03a1,
- 0x03a3, 0x052f,
- 0x0531, 0x0556,
- 0x0559, 0x058a,
- 0x058d, 0x058f,
- 0x0591, 0x05c7,
- 0x05d0, 0x05ea,
- 0x05ef, 0x05f4,
- 0x0600, 0x061c,
- 0x061e, 0x070d,
- 0x070f, 0x074a,
- 0x074d, 0x07b1,
- 0x07c0, 0x07fa,
- 0x07fd, 0x082d,
- 0x0830, 0x083e,
- 0x0840, 0x085b,
- 0x085e, 0x085e,
- 0x0860, 0x086a,
- 0x08a0, 0x08b4,
- 0x08b6, 0x08bd,
- 0x08d3, 0x0983,
- 0x0985, 0x098c,
- 0x098f, 0x0990,
- 0x0993, 0x09a8,
- 0x09aa, 0x09b0,
- 0x09b2, 0x09b2,
- 0x09b6, 0x09b9,
- 0x09bc, 0x09c4,
- 0x09c7, 0x09c8,
- 0x09cb, 0x09ce,
- 0x09d7, 0x09d7,
- 0x09dc, 0x09dd,
- 0x09df, 0x09e3,
- 0x09e6, 0x09fe,
- 0x0a01, 0x0a03,
- 0x0a05, 0x0a0a,
- 0x0a0f, 0x0a10,
- 0x0a13, 0x0a28,
- 0x0a2a, 0x0a30,
- 0x0a32, 0x0a33,
- 0x0a35, 0x0a36,
- 0x0a38, 0x0a39,
- 0x0a3c, 0x0a3c,
- 0x0a3e, 0x0a42,
- 0x0a47, 0x0a48,
- 0x0a4b, 0x0a4d,
- 0x0a51, 0x0a51,
- 0x0a59, 0x0a5c,
- 0x0a5e, 0x0a5e,
- 0x0a66, 0x0a76,
- 0x0a81, 0x0a83,
- 0x0a85, 0x0a8d,
- 0x0a8f, 0x0a91,
- 0x0a93, 0x0aa8,
- 0x0aaa, 0x0ab0,
- 0x0ab2, 0x0ab3,
- 0x0ab5, 0x0ab9,
- 0x0abc, 0x0ac5,
- 0x0ac7, 0x0ac9,
- 0x0acb, 0x0acd,
- 0x0ad0, 0x0ad0,
- 0x0ae0, 0x0ae3,
- 0x0ae6, 0x0af1,
- 0x0af9, 0x0aff,
- 0x0b01, 0x0b03,
- 0x0b05, 0x0b0c,
- 0x0b0f, 0x0b10,
- 0x0b13, 0x0b28,
- 0x0b2a, 0x0b30,
- 0x0b32, 0x0b33,
- 0x0b35, 0x0b39,
- 0x0b3c, 0x0b44,
- 0x0b47, 0x0b48,
- 0x0b4b, 0x0b4d,
- 0x0b56, 0x0b57,
- 0x0b5c, 0x0b5d,
- 0x0b5f, 0x0b63,
- 0x0b66, 0x0b77,
- 0x0b82, 0x0b83,
- 0x0b85, 0x0b8a,
- 0x0b8e, 0x0b90,
- 0x0b92, 0x0b95,
- 0x0b99, 0x0b9a,
- 0x0b9c, 0x0b9c,
- 0x0b9e, 0x0b9f,
- 0x0ba3, 0x0ba4,
- 0x0ba8, 0x0baa,
- 0x0bae, 0x0bb9,
- 0x0bbe, 0x0bc2,
- 0x0bc6, 0x0bc8,
- 0x0bca, 0x0bcd,
- 0x0bd0, 0x0bd0,
- 0x0bd7, 0x0bd7,
- 0x0be6, 0x0bfa,
- 0x0c00, 0x0c0c,
- 0x0c0e, 0x0c10,
- 0x0c12, 0x0c28,
- 0x0c2a, 0x0c39,
- 0x0c3d, 0x0c44,
- 0x0c46, 0x0c48,
- 0x0c4a, 0x0c4d,
- 0x0c55, 0x0c56,
- 0x0c58, 0x0c5a,
- 0x0c60, 0x0c63,
- 0x0c66, 0x0c6f,
- 0x0c78, 0x0c8c,
- 0x0c8e, 0x0c90,
- 0x0c92, 0x0ca8,
- 0x0caa, 0x0cb3,
- 0x0cb5, 0x0cb9,
- 0x0cbc, 0x0cc4,
- 0x0cc6, 0x0cc8,
- 0x0cca, 0x0ccd,
- 0x0cd5, 0x0cd6,
- 0x0cde, 0x0cde,
- 0x0ce0, 0x0ce3,
- 0x0ce6, 0x0cef,
- 0x0cf1, 0x0cf2,
- 0x0d00, 0x0d03,
- 0x0d05, 0x0d0c,
- 0x0d0e, 0x0d10,
- 0x0d12, 0x0d44,
- 0x0d46, 0x0d48,
- 0x0d4a, 0x0d4f,
- 0x0d54, 0x0d63,
- 0x0d66, 0x0d7f,
- 0x0d82, 0x0d83,
- 0x0d85, 0x0d96,
- 0x0d9a, 0x0db1,
- 0x0db3, 0x0dbb,
- 0x0dbd, 0x0dbd,
- 0x0dc0, 0x0dc6,
- 0x0dca, 0x0dca,
- 0x0dcf, 0x0dd4,
- 0x0dd6, 0x0dd6,
- 0x0dd8, 0x0ddf,
- 0x0de6, 0x0def,
- 0x0df2, 0x0df4,
- 0x0e01, 0x0e3a,
- 0x0e3f, 0x0e5b,
- 0x0e81, 0x0e82,
- 0x0e84, 0x0e84,
- 0x0e87, 0x0e88,
- 0x0e8a, 0x0e8a,
- 0x0e8d, 0x0e8d,
- 0x0e94, 0x0e97,
- 0x0e99, 0x0e9f,
- 0x0ea1, 0x0ea3,
- 0x0ea5, 0x0ea5,
- 0x0ea7, 0x0ea7,
- 0x0eaa, 0x0eab,
- 0x0ead, 0x0eb9,
- 0x0ebb, 0x0ebd,
- 0x0ec0, 0x0ec4,
- 0x0ec6, 0x0ec6,
- 0x0ec8, 0x0ecd,
- 0x0ed0, 0x0ed9,
- 0x0edc, 0x0edf,
- 0x0f00, 0x0f47,
- 0x0f49, 0x0f6c,
- 0x0f71, 0x0f97,
- 0x0f99, 0x0fbc,
- 0x0fbe, 0x0fcc,
- 0x0fce, 0x0fda,
- 0x1000, 0x10c5,
- 0x10c7, 0x10c7,
- 0x10cd, 0x10cd,
- 0x10d0, 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,
- 0x135d, 0x137c,
- 0x1380, 0x1399,
- 0x13a0, 0x13f5,
- 0x13f8, 0x13fd,
- 0x1400, 0x169c,
- 0x16a0, 0x16f8,
- 0x1700, 0x170c,
- 0x170e, 0x1714,
- 0x1720, 0x1736,
- 0x1740, 0x1753,
- 0x1760, 0x176c,
- 0x176e, 0x1770,
- 0x1772, 0x1773,
- 0x1780, 0x17dd,
- 0x17e0, 0x17e9,
- 0x17f0, 0x17f9,
- 0x1800, 0x180e,
- 0x1810, 0x1819,
- 0x1820, 0x1878,
- 0x1880, 0x18aa,
- 0x18b0, 0x18f5,
- 0x1900, 0x191e,
- 0x1920, 0x192b,
- 0x1930, 0x193b,
- 0x1940, 0x1940,
- 0x1944, 0x196d,
- 0x1970, 0x1974,
- 0x1980, 0x19ab,
- 0x19b0, 0x19c9,
- 0x19d0, 0x19da,
- 0x19de, 0x1a1b,
- 0x1a1e, 0x1a5e,
- 0x1a60, 0x1a7c,
- 0x1a7f, 0x1a89,
- 0x1a90, 0x1a99,
- 0x1aa0, 0x1aad,
- 0x1ab0, 0x1abe,
- 0x1b00, 0x1b4b,
- 0x1b50, 0x1b7c,
- 0x1b80, 0x1bf3,
- 0x1bfc, 0x1c37,
- 0x1c3b, 0x1c49,
- 0x1c4d, 0x1c88,
- 0x1c90, 0x1cba,
- 0x1cbd, 0x1cc7,
- 0x1cd0, 0x1cf9,
- 0x1d00, 0x1df9,
- 0x1dfb, 0x1f15,
- 0x1f18, 0x1f1d,
- 0x1f20, 0x1f45,
- 0x1f48, 0x1f4d,
- 0x1f50, 0x1f57,
- 0x1f59, 0x1f59,
- 0x1f5b, 0x1f5b,
- 0x1f5d, 0x1f5d,
- 0x1f5f, 0x1f7d,
- 0x1f80, 0x1fb4,
- 0x1fb6, 0x1fc4,
- 0x1fc6, 0x1fd3,
- 0x1fd6, 0x1fdb,
- 0x1fdd, 0x1fef,
- 0x1ff2, 0x1ff4,
- 0x1ff6, 0x1ffe,
- 0x2000, 0x2064,
- 0x2066, 0x2071,
- 0x2074, 0x208e,
- 0x2090, 0x209c,
- 0x20a0, 0x20bf,
- 0x20d0, 0x20f0,
- 0x2100, 0x218b,
- 0x2190, 0x2426,
- 0x2440, 0x244a,
- 0x2460, 0x2b73,
- 0x2b76, 0x2b95,
- 0x2b98, 0x2bc8,
- 0x2bca, 0x2bfe,
- 0x2c00, 0x2c2e,
- 0x2c30, 0x2c5e,
- 0x2c60, 0x2cf3,
- 0x2cf9, 0x2d25,
- 0x2d27, 0x2d27,
- 0x2d2d, 0x2d2d,
- 0x2d30, 0x2d67,
- 0x2d6f, 0x2d70,
- 0x2d7f, 0x2d96,
- 0x2da0, 0x2da6,
- 0x2da8, 0x2dae,
- 0x2db0, 0x2db6,
- 0x2db8, 0x2dbe,
- 0x2dc0, 0x2dc6,
- 0x2dc8, 0x2dce,
- 0x2dd0, 0x2dd6,
- 0x2dd8, 0x2dde,
- 0x2de0, 0x2e4e,
- 0x2e80, 0x2e99,
- 0x2e9b, 0x2ef3,
- 0x2f00, 0x2fd5,
- 0x2ff0, 0x2ffb,
- 0x3000, 0x303f,
- 0x3041, 0x3096,
- 0x3099, 0x30ff,
- 0x3105, 0x312f,
- 0x3131, 0x318e,
- 0x3190, 0x31ba,
- 0x31c0, 0x31e3,
- 0x31f0, 0x321e,
- 0x3220, 0x32fe,
- 0x3300, 0x4db5,
- 0x4dc0, 0x9fef,
- 0xa000, 0xa48c,
- 0xa490, 0xa4c6,
- 0xa4d0, 0xa62b,
- 0xa640, 0xa6f7,
- 0xa700, 0xa7b9,
- 0xa7f7, 0xa82b,
- 0xa830, 0xa839,
- 0xa840, 0xa877,
- 0xa880, 0xa8c5,
- 0xa8ce, 0xa8d9,
- 0xa8e0, 0xa953,
- 0xa95f, 0xa97c,
- 0xa980, 0xa9cd,
- 0xa9cf, 0xa9d9,
- 0xa9de, 0xa9fe,
- 0xaa00, 0xaa36,
- 0xaa40, 0xaa4d,
- 0xaa50, 0xaa59,
- 0xaa5c, 0xaac2,
- 0xaadb, 0xaaf6,
- 0xab01, 0xab06,
- 0xab09, 0xab0e,
- 0xab11, 0xab16,
- 0xab20, 0xab26,
- 0xab28, 0xab2e,
- 0xab30, 0xab65,
- 0xab70, 0xabed,
- 0xabf0, 0xabf9,
- 0xac00, 0xd7a3,
- 0xd7b0, 0xd7c6,
- 0xd7cb, 0xd7fb,
- 0xd800, 0xfa6d,
- 0xfa70, 0xfad9,
- 0xfb00, 0xfb06,
- 0xfb13, 0xfb17,
- 0xfb1d, 0xfb36,
- 0xfb38, 0xfb3c,
- 0xfb3e, 0xfb3e,
- 0xfb40, 0xfb41,
- 0xfb43, 0xfb44,
- 0xfb46, 0xfbc1,
- 0xfbd3, 0xfd3f,
- 0xfd50, 0xfd8f,
- 0xfd92, 0xfdc7,
- 0xfdd0, 0xfdfd,
- 0xfe00, 0xfe19,
- 0xfe20, 0xfe52,
- 0xfe54, 0xfe66,
- 0xfe68, 0xfe6b,
- 0xfe70, 0xfe74,
- 0xfe76, 0xfefc,
- 0xfeff, 0xfeff,
- 0xff01, 0xffbe,
- 0xffc2, 0xffc7,
- 0xffca, 0xffcf,
- 0xffd2, 0xffd7,
- 0xffda, 0xffdc,
- 0xffe0, 0xffe6,
- 0xffe8, 0xffee,
- 0xfff9, 0x1000b,
- 0x1000d, 0x10026,
- 0x10028, 0x1003a,
- 0x1003c, 0x1003d,
- 0x1003f, 0x1004d,
- 0x10050, 0x1005d,
- 0x10080, 0x100fa,
- 0x10100, 0x10102,
- 0x10107, 0x10133,
- 0x10137, 0x1018e,
- 0x10190, 0x1019b,
- 0x101a0, 0x101a0,
- 0x101d0, 0x101fd,
- 0x10280, 0x1029c,
- 0x102a0, 0x102d0,
- 0x102e0, 0x102fb,
- 0x10300, 0x10323,
- 0x1032d, 0x1034a,
- 0x10350, 0x1037a,
- 0x10380, 0x1039d,
- 0x1039f, 0x103c3,
- 0x103c8, 0x103d5,
- 0x10400, 0x1049d,
- 0x104a0, 0x104a9,
- 0x104b0, 0x104d3,
- 0x104d8, 0x104fb,
- 0x10500, 0x10527,
- 0x10530, 0x10563,
- 0x1056f, 0x1056f,
- 0x10600, 0x10736,
- 0x10740, 0x10755,
- 0x10760, 0x10767,
- 0x10800, 0x10805,
- 0x10808, 0x10808,
- 0x1080a, 0x10835,
- 0x10837, 0x10838,
- 0x1083c, 0x1083c,
- 0x1083f, 0x10855,
- 0x10857, 0x1089e,
- 0x108a7, 0x108af,
- 0x108e0, 0x108f2,
- 0x108f4, 0x108f5,
- 0x108fb, 0x1091b,
- 0x1091f, 0x10939,
- 0x1093f, 0x1093f,
- 0x10980, 0x109b7,
- 0x109bc, 0x109cf,
- 0x109d2, 0x10a03,
- 0x10a05, 0x10a06,
- 0x10a0c, 0x10a13,
- 0x10a15, 0x10a17,
- 0x10a19, 0x10a35,
- 0x10a38, 0x10a3a,
- 0x10a3f, 0x10a48,
- 0x10a50, 0x10a58,
- 0x10a60, 0x10a9f,
- 0x10ac0, 0x10ae6,
- 0x10aeb, 0x10af6,
- 0x10b00, 0x10b35,
- 0x10b39, 0x10b55,
- 0x10b58, 0x10b72,
- 0x10b78, 0x10b91,
- 0x10b99, 0x10b9c,
- 0x10ba9, 0x10baf,
- 0x10c00, 0x10c48,
- 0x10c80, 0x10cb2,
- 0x10cc0, 0x10cf2,
- 0x10cfa, 0x10d27,
- 0x10d30, 0x10d39,
- 0x10e60, 0x10e7e,
- 0x10f00, 0x10f27,
- 0x10f30, 0x10f59,
- 0x11000, 0x1104d,
- 0x11052, 0x1106f,
- 0x1107f, 0x110c1,
- 0x110cd, 0x110cd,
- 0x110d0, 0x110e8,
- 0x110f0, 0x110f9,
- 0x11100, 0x11134,
- 0x11136, 0x11146,
- 0x11150, 0x11176,
- 0x11180, 0x111cd,
- 0x111d0, 0x111df,
- 0x111e1, 0x111f4,
- 0x11200, 0x11211,
- 0x11213, 0x1123e,
- 0x11280, 0x11286,
- 0x11288, 0x11288,
- 0x1128a, 0x1128d,
- 0x1128f, 0x1129d,
- 0x1129f, 0x112a9,
- 0x112b0, 0x112ea,
- 0x112f0, 0x112f9,
- 0x11300, 0x11303,
- 0x11305, 0x1130c,
- 0x1130f, 0x11310,
- 0x11313, 0x11328,
- 0x1132a, 0x11330,
- 0x11332, 0x11333,
- 0x11335, 0x11339,
- 0x1133b, 0x11344,
- 0x11347, 0x11348,
- 0x1134b, 0x1134d,
- 0x11350, 0x11350,
- 0x11357, 0x11357,
- 0x1135d, 0x11363,
- 0x11366, 0x1136c,
- 0x11370, 0x11374,
- 0x11400, 0x11459,
- 0x1145b, 0x1145b,
- 0x1145d, 0x1145e,
- 0x11480, 0x114c7,
- 0x114d0, 0x114d9,
- 0x11580, 0x115b5,
- 0x115b8, 0x115dd,
- 0x11600, 0x11644,
- 0x11650, 0x11659,
- 0x11660, 0x1166c,
- 0x11680, 0x116b7,
- 0x116c0, 0x116c9,
- 0x11700, 0x1171a,
- 0x1171d, 0x1172b,
- 0x11730, 0x1173f,
- 0x11800, 0x1183b,
- 0x118a0, 0x118f2,
- 0x118ff, 0x118ff,
- 0x11a00, 0x11a47,
- 0x11a50, 0x11a83,
- 0x11a86, 0x11aa2,
- 0x11ac0, 0x11af8,
- 0x11c00, 0x11c08,
- 0x11c0a, 0x11c36,
- 0x11c38, 0x11c45,
- 0x11c50, 0x11c6c,
- 0x11c70, 0x11c8f,
- 0x11c92, 0x11ca7,
- 0x11ca9, 0x11cb6,
- 0x11d00, 0x11d06,
- 0x11d08, 0x11d09,
- 0x11d0b, 0x11d36,
- 0x11d3a, 0x11d3a,
- 0x11d3c, 0x11d3d,
- 0x11d3f, 0x11d47,
- 0x11d50, 0x11d59,
- 0x11d60, 0x11d65,
- 0x11d67, 0x11d68,
- 0x11d6a, 0x11d8e,
- 0x11d90, 0x11d91,
- 0x11d93, 0x11d98,
- 0x11da0, 0x11da9,
- 0x11ee0, 0x11ef8,
- 0x12000, 0x12399,
- 0x12400, 0x1246e,
- 0x12470, 0x12474,
- 0x12480, 0x12543,
- 0x13000, 0x1342e,
- 0x14400, 0x14646,
- 0x16800, 0x16a38,
- 0x16a40, 0x16a5e,
- 0x16a60, 0x16a69,
- 0x16a6e, 0x16a6f,
- 0x16ad0, 0x16aed,
- 0x16af0, 0x16af5,
- 0x16b00, 0x16b45,
- 0x16b50, 0x16b59,
- 0x16b5b, 0x16b61,
- 0x16b63, 0x16b77,
- 0x16b7d, 0x16b8f,
- 0x16e40, 0x16e9a,
- 0x16f00, 0x16f44,
- 0x16f50, 0x16f7e,
- 0x16f8f, 0x16f9f,
- 0x16fe0, 0x16fe1,
- 0x17000, 0x187f1,
- 0x18800, 0x18af2,
- 0x1b000, 0x1b11e,
- 0x1b170, 0x1b2fb,
- 0x1bc00, 0x1bc6a,
- 0x1bc70, 0x1bc7c,
- 0x1bc80, 0x1bc88,
- 0x1bc90, 0x1bc99,
- 0x1bc9c, 0x1bca3,
- 0x1d000, 0x1d0f5,
- 0x1d100, 0x1d126,
- 0x1d129, 0x1d1e8,
- 0x1d200, 0x1d245,
- 0x1d2e0, 0x1d2f3,
- 0x1d300, 0x1d356,
- 0x1d360, 0x1d378,
- 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, 0x1d7cb,
- 0x1d7ce, 0x1da8b,
- 0x1da9b, 0x1da9f,
- 0x1daa1, 0x1daaf,
- 0x1e000, 0x1e006,
- 0x1e008, 0x1e018,
- 0x1e01b, 0x1e021,
- 0x1e023, 0x1e024,
- 0x1e026, 0x1e02a,
- 0x1e800, 0x1e8c4,
- 0x1e8c7, 0x1e8d6,
- 0x1e900, 0x1e94a,
- 0x1e950, 0x1e959,
- 0x1e95e, 0x1e95f,
- 0x1ec71, 0x1ecb4,
- 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,
- 0x1eef0, 0x1eef1,
- 0x1f000, 0x1f02b,
- 0x1f030, 0x1f093,
- 0x1f0a0, 0x1f0ae,
- 0x1f0b1, 0x1f0bf,
- 0x1f0c1, 0x1f0cf,
- 0x1f0d1, 0x1f0f5,
- 0x1f100, 0x1f10c,
- 0x1f110, 0x1f16b,
- 0x1f170, 0x1f1ac,
- 0x1f1e6, 0x1f202,
- 0x1f210, 0x1f23b,
- 0x1f240, 0x1f248,
- 0x1f250, 0x1f251,
- 0x1f260, 0x1f265,
- 0x1f300, 0x1f6d4,
- 0x1f6e0, 0x1f6ec,
- 0x1f6f0, 0x1f6f9,
- 0x1f700, 0x1f773,
- 0x1f780, 0x1f7d8,
- 0x1f800, 0x1f80b,
- 0x1f810, 0x1f847,
- 0x1f850, 0x1f859,
- 0x1f860, 0x1f887,
- 0x1f890, 0x1f8ad,
- 0x1f900, 0x1f90b,
- 0x1f910, 0x1f93e,
- 0x1f940, 0x1f970,
- 0x1f973, 0x1f976,
- 0x1f97a, 0x1f97a,
- 0x1f97c, 0x1f9a2,
- 0x1f9b0, 0x1f9b9,
- 0x1f9c0, 0x1f9c2,
- 0x1f9d0, 0x1f9ff,
- 0x1fa60, 0x1fa6d,
- 0x1fffe, 0x2a6d6,
- 0x2a700, 0x2b734,
- 0x2b740, 0x2b81d,
- 0x2b820, 0x2cea1,
- 0x2ceb0, 0x2ebe0,
- 0x2f800, 0x2fa1d,
- 0x2fffe, 0x2ffff,
- 0x3fffe, 0x3ffff,
- 0x4fffe, 0x4ffff,
- 0x5fffe, 0x5ffff,
- 0x6fffe, 0x6ffff,
- 0x7fffe, 0x7ffff,
- 0x8fffe, 0x8ffff,
- 0x9fffe, 0x9ffff,
- 0xafffe, 0xaffff,
- 0xbfffe, 0xbffff,
- 0xcfffe, 0xcffff,
- 0xdfffe, 0xdffff,
- 0xe0001, 0xe0001,
- 0xe0020, 0xe007f,
- 0xe0100, 0xe01ef,
- 0xefffe, 0x10ffff,
-}; /* CR_Age_11_0 */
-
-/* 'Age_12_0': Derived Age 12.0 */
-static const OnigCodePoint CR_Age_12_0[] = {
- 677,
- 0x0000, 0x0377,
- 0x037a, 0x037f,
- 0x0384, 0x038a,
- 0x038c, 0x038c,
- 0x038e, 0x03a1,
- 0x03a3, 0x052f,
- 0x0531, 0x0556,
- 0x0559, 0x058a,
- 0x058d, 0x058f,
- 0x0591, 0x05c7,
- 0x05d0, 0x05ea,
- 0x05ef, 0x05f4,
- 0x0600, 0x061c,
- 0x061e, 0x070d,
- 0x070f, 0x074a,
- 0x074d, 0x07b1,
- 0x07c0, 0x07fa,
- 0x07fd, 0x082d,
- 0x0830, 0x083e,
- 0x0840, 0x085b,
- 0x085e, 0x085e,
- 0x0860, 0x086a,
- 0x08a0, 0x08b4,
- 0x08b6, 0x08bd,
- 0x08d3, 0x0983,
- 0x0985, 0x098c,
- 0x098f, 0x0990,
- 0x0993, 0x09a8,
- 0x09aa, 0x09b0,
- 0x09b2, 0x09b2,
- 0x09b6, 0x09b9,
- 0x09bc, 0x09c4,
- 0x09c7, 0x09c8,
- 0x09cb, 0x09ce,
- 0x09d7, 0x09d7,
- 0x09dc, 0x09dd,
- 0x09df, 0x09e3,
- 0x09e6, 0x09fe,
- 0x0a01, 0x0a03,
- 0x0a05, 0x0a0a,
- 0x0a0f, 0x0a10,
- 0x0a13, 0x0a28,
- 0x0a2a, 0x0a30,
- 0x0a32, 0x0a33,
- 0x0a35, 0x0a36,
- 0x0a38, 0x0a39,
- 0x0a3c, 0x0a3c,
- 0x0a3e, 0x0a42,
- 0x0a47, 0x0a48,
- 0x0a4b, 0x0a4d,
- 0x0a51, 0x0a51,
- 0x0a59, 0x0a5c,
- 0x0a5e, 0x0a5e,
- 0x0a66, 0x0a76,
- 0x0a81, 0x0a83,
- 0x0a85, 0x0a8d,
- 0x0a8f, 0x0a91,
- 0x0a93, 0x0aa8,
- 0x0aaa, 0x0ab0,
- 0x0ab2, 0x0ab3,
- 0x0ab5, 0x0ab9,
- 0x0abc, 0x0ac5,
- 0x0ac7, 0x0ac9,
- 0x0acb, 0x0acd,
- 0x0ad0, 0x0ad0,
- 0x0ae0, 0x0ae3,
- 0x0ae6, 0x0af1,
- 0x0af9, 0x0aff,
- 0x0b01, 0x0b03,
- 0x0b05, 0x0b0c,
- 0x0b0f, 0x0b10,
- 0x0b13, 0x0b28,
- 0x0b2a, 0x0b30,
- 0x0b32, 0x0b33,
- 0x0b35, 0x0b39,
- 0x0b3c, 0x0b44,
- 0x0b47, 0x0b48,
- 0x0b4b, 0x0b4d,
- 0x0b56, 0x0b57,
- 0x0b5c, 0x0b5d,
- 0x0b5f, 0x0b63,
- 0x0b66, 0x0b77,
- 0x0b82, 0x0b83,
- 0x0b85, 0x0b8a,
- 0x0b8e, 0x0b90,
- 0x0b92, 0x0b95,
- 0x0b99, 0x0b9a,
- 0x0b9c, 0x0b9c,
- 0x0b9e, 0x0b9f,
- 0x0ba3, 0x0ba4,
- 0x0ba8, 0x0baa,
- 0x0bae, 0x0bb9,
- 0x0bbe, 0x0bc2,
- 0x0bc6, 0x0bc8,
- 0x0bca, 0x0bcd,
- 0x0bd0, 0x0bd0,
- 0x0bd7, 0x0bd7,
- 0x0be6, 0x0bfa,
- 0x0c00, 0x0c0c,
- 0x0c0e, 0x0c10,
- 0x0c12, 0x0c28,
- 0x0c2a, 0x0c39,
- 0x0c3d, 0x0c44,
- 0x0c46, 0x0c48,
- 0x0c4a, 0x0c4d,
- 0x0c55, 0x0c56,
- 0x0c58, 0x0c5a,
- 0x0c60, 0x0c63,
- 0x0c66, 0x0c6f,
- 0x0c77, 0x0c8c,
- 0x0c8e, 0x0c90,
- 0x0c92, 0x0ca8,
- 0x0caa, 0x0cb3,
- 0x0cb5, 0x0cb9,
- 0x0cbc, 0x0cc4,
- 0x0cc6, 0x0cc8,
- 0x0cca, 0x0ccd,
- 0x0cd5, 0x0cd6,
- 0x0cde, 0x0cde,
- 0x0ce0, 0x0ce3,
- 0x0ce6, 0x0cef,
- 0x0cf1, 0x0cf2,
- 0x0d00, 0x0d03,
- 0x0d05, 0x0d0c,
- 0x0d0e, 0x0d10,
- 0x0d12, 0x0d44,
- 0x0d46, 0x0d48,
- 0x0d4a, 0x0d4f,
- 0x0d54, 0x0d63,
- 0x0d66, 0x0d7f,
- 0x0d82, 0x0d83,
- 0x0d85, 0x0d96,
- 0x0d9a, 0x0db1,
- 0x0db3, 0x0dbb,
- 0x0dbd, 0x0dbd,
- 0x0dc0, 0x0dc6,
- 0x0dca, 0x0dca,
- 0x0dcf, 0x0dd4,
- 0x0dd6, 0x0dd6,
- 0x0dd8, 0x0ddf,
- 0x0de6, 0x0def,
- 0x0df2, 0x0df4,
- 0x0e01, 0x0e3a,
- 0x0e3f, 0x0e5b,
- 0x0e81, 0x0e82,
- 0x0e84, 0x0e84,
- 0x0e86, 0x0e8a,
- 0x0e8c, 0x0ea3,
- 0x0ea5, 0x0ea5,
- 0x0ea7, 0x0ebd,
- 0x0ec0, 0x0ec4,
- 0x0ec6, 0x0ec6,
- 0x0ec8, 0x0ecd,
- 0x0ed0, 0x0ed9,
- 0x0edc, 0x0edf,
- 0x0f00, 0x0f47,
- 0x0f49, 0x0f6c,
- 0x0f71, 0x0f97,
- 0x0f99, 0x0fbc,
- 0x0fbe, 0x0fcc,
- 0x0fce, 0x0fda,
- 0x1000, 0x10c5,
- 0x10c7, 0x10c7,
- 0x10cd, 0x10cd,
- 0x10d0, 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,
- 0x135d, 0x137c,
- 0x1380, 0x1399,
- 0x13a0, 0x13f5,
- 0x13f8, 0x13fd,
- 0x1400, 0x169c,
- 0x16a0, 0x16f8,
- 0x1700, 0x170c,
- 0x170e, 0x1714,
- 0x1720, 0x1736,
- 0x1740, 0x1753,
- 0x1760, 0x176c,
- 0x176e, 0x1770,
- 0x1772, 0x1773,
- 0x1780, 0x17dd,
- 0x17e0, 0x17e9,
- 0x17f0, 0x17f9,
- 0x1800, 0x180e,
- 0x1810, 0x1819,
- 0x1820, 0x1878,
- 0x1880, 0x18aa,
- 0x18b0, 0x18f5,
- 0x1900, 0x191e,
- 0x1920, 0x192b,
- 0x1930, 0x193b,
- 0x1940, 0x1940,
- 0x1944, 0x196d,
- 0x1970, 0x1974,
- 0x1980, 0x19ab,
- 0x19b0, 0x19c9,
- 0x19d0, 0x19da,
- 0x19de, 0x1a1b,
- 0x1a1e, 0x1a5e,
- 0x1a60, 0x1a7c,
- 0x1a7f, 0x1a89,
- 0x1a90, 0x1a99,
- 0x1aa0, 0x1aad,
- 0x1ab0, 0x1abe,
- 0x1b00, 0x1b4b,
- 0x1b50, 0x1b7c,
- 0x1b80, 0x1bf3,
- 0x1bfc, 0x1c37,
- 0x1c3b, 0x1c49,
- 0x1c4d, 0x1c88,
- 0x1c90, 0x1cba,
- 0x1cbd, 0x1cc7,
- 0x1cd0, 0x1cfa,
- 0x1d00, 0x1df9,
- 0x1dfb, 0x1f15,
- 0x1f18, 0x1f1d,
- 0x1f20, 0x1f45,
- 0x1f48, 0x1f4d,
- 0x1f50, 0x1f57,
- 0x1f59, 0x1f59,
- 0x1f5b, 0x1f5b,
- 0x1f5d, 0x1f5d,
- 0x1f5f, 0x1f7d,
- 0x1f80, 0x1fb4,
- 0x1fb6, 0x1fc4,
- 0x1fc6, 0x1fd3,
- 0x1fd6, 0x1fdb,
- 0x1fdd, 0x1fef,
- 0x1ff2, 0x1ff4,
- 0x1ff6, 0x1ffe,
- 0x2000, 0x2064,
- 0x2066, 0x2071,
- 0x2074, 0x208e,
- 0x2090, 0x209c,
- 0x20a0, 0x20bf,
- 0x20d0, 0x20f0,
- 0x2100, 0x218b,
- 0x2190, 0x2426,
- 0x2440, 0x244a,
- 0x2460, 0x2b73,
- 0x2b76, 0x2b95,
- 0x2b98, 0x2c2e,
- 0x2c30, 0x2c5e,
- 0x2c60, 0x2cf3,
- 0x2cf9, 0x2d25,
- 0x2d27, 0x2d27,
- 0x2d2d, 0x2d2d,
- 0x2d30, 0x2d67,
- 0x2d6f, 0x2d70,
- 0x2d7f, 0x2d96,
- 0x2da0, 0x2da6,
- 0x2da8, 0x2dae,
- 0x2db0, 0x2db6,
- 0x2db8, 0x2dbe,
- 0x2dc0, 0x2dc6,
- 0x2dc8, 0x2dce,
- 0x2dd0, 0x2dd6,
- 0x2dd8, 0x2dde,
- 0x2de0, 0x2e4f,
- 0x2e80, 0x2e99,
- 0x2e9b, 0x2ef3,
- 0x2f00, 0x2fd5,
- 0x2ff0, 0x2ffb,
- 0x3000, 0x303f,
- 0x3041, 0x3096,
- 0x3099, 0x30ff,
- 0x3105, 0x312f,
- 0x3131, 0x318e,
- 0x3190, 0x31ba,
- 0x31c0, 0x31e3,
- 0x31f0, 0x321e,
- 0x3220, 0x32fe,
- 0x3300, 0x4db5,
- 0x4dc0, 0x9fef,
- 0xa000, 0xa48c,
- 0xa490, 0xa4c6,
- 0xa4d0, 0xa62b,
- 0xa640, 0xa6f7,
- 0xa700, 0xa7bf,
- 0xa7c2, 0xa7c6,
- 0xa7f7, 0xa82b,
- 0xa830, 0xa839,
- 0xa840, 0xa877,
- 0xa880, 0xa8c5,
- 0xa8ce, 0xa8d9,
- 0xa8e0, 0xa953,
- 0xa95f, 0xa97c,
- 0xa980, 0xa9cd,
- 0xa9cf, 0xa9d9,
- 0xa9de, 0xa9fe,
- 0xaa00, 0xaa36,
- 0xaa40, 0xaa4d,
- 0xaa50, 0xaa59,
- 0xaa5c, 0xaac2,
- 0xaadb, 0xaaf6,
- 0xab01, 0xab06,
- 0xab09, 0xab0e,
- 0xab11, 0xab16,
- 0xab20, 0xab26,
- 0xab28, 0xab2e,
- 0xab30, 0xab67,
- 0xab70, 0xabed,
- 0xabf0, 0xabf9,
- 0xac00, 0xd7a3,
- 0xd7b0, 0xd7c6,
- 0xd7cb, 0xd7fb,
- 0xd800, 0xfa6d,
- 0xfa70, 0xfad9,
- 0xfb00, 0xfb06,
- 0xfb13, 0xfb17,
- 0xfb1d, 0xfb36,
- 0xfb38, 0xfb3c,
- 0xfb3e, 0xfb3e,
- 0xfb40, 0xfb41,
- 0xfb43, 0xfb44,
- 0xfb46, 0xfbc1,
- 0xfbd3, 0xfd3f,
- 0xfd50, 0xfd8f,
- 0xfd92, 0xfdc7,
- 0xfdd0, 0xfdfd,
- 0xfe00, 0xfe19,
- 0xfe20, 0xfe52,
- 0xfe54, 0xfe66,
- 0xfe68, 0xfe6b,
- 0xfe70, 0xfe74,
- 0xfe76, 0xfefc,
- 0xfeff, 0xfeff,
- 0xff01, 0xffbe,
- 0xffc2, 0xffc7,
- 0xffca, 0xffcf,
- 0xffd2, 0xffd7,
- 0xffda, 0xffdc,
- 0xffe0, 0xffe6,
- 0xffe8, 0xffee,
- 0xfff9, 0x1000b,
- 0x1000d, 0x10026,
- 0x10028, 0x1003a,
- 0x1003c, 0x1003d,
- 0x1003f, 0x1004d,
- 0x10050, 0x1005d,
- 0x10080, 0x100fa,
- 0x10100, 0x10102,
- 0x10107, 0x10133,
- 0x10137, 0x1018e,
- 0x10190, 0x1019b,
- 0x101a0, 0x101a0,
- 0x101d0, 0x101fd,
- 0x10280, 0x1029c,
- 0x102a0, 0x102d0,
- 0x102e0, 0x102fb,
- 0x10300, 0x10323,
- 0x1032d, 0x1034a,
- 0x10350, 0x1037a,
- 0x10380, 0x1039d,
- 0x1039f, 0x103c3,
- 0x103c8, 0x103d5,
- 0x10400, 0x1049d,
- 0x104a0, 0x104a9,
- 0x104b0, 0x104d3,
- 0x104d8, 0x104fb,
- 0x10500, 0x10527,
- 0x10530, 0x10563,
- 0x1056f, 0x1056f,
- 0x10600, 0x10736,
- 0x10740, 0x10755,
- 0x10760, 0x10767,
- 0x10800, 0x10805,
- 0x10808, 0x10808,
- 0x1080a, 0x10835,
- 0x10837, 0x10838,
- 0x1083c, 0x1083c,
- 0x1083f, 0x10855,
- 0x10857, 0x1089e,
- 0x108a7, 0x108af,
- 0x108e0, 0x108f2,
- 0x108f4, 0x108f5,
- 0x108fb, 0x1091b,
- 0x1091f, 0x10939,
- 0x1093f, 0x1093f,
- 0x10980, 0x109b7,
- 0x109bc, 0x109cf,
- 0x109d2, 0x10a03,
- 0x10a05, 0x10a06,
- 0x10a0c, 0x10a13,
- 0x10a15, 0x10a17,
- 0x10a19, 0x10a35,
- 0x10a38, 0x10a3a,
- 0x10a3f, 0x10a48,
- 0x10a50, 0x10a58,
- 0x10a60, 0x10a9f,
- 0x10ac0, 0x10ae6,
- 0x10aeb, 0x10af6,
- 0x10b00, 0x10b35,
- 0x10b39, 0x10b55,
- 0x10b58, 0x10b72,
- 0x10b78, 0x10b91,
- 0x10b99, 0x10b9c,
- 0x10ba9, 0x10baf,
- 0x10c00, 0x10c48,
- 0x10c80, 0x10cb2,
- 0x10cc0, 0x10cf2,
- 0x10cfa, 0x10d27,
- 0x10d30, 0x10d39,
- 0x10e60, 0x10e7e,
- 0x10f00, 0x10f27,
- 0x10f30, 0x10f59,
- 0x10fe0, 0x10ff6,
- 0x11000, 0x1104d,
- 0x11052, 0x1106f,
- 0x1107f, 0x110c1,
- 0x110cd, 0x110cd,
- 0x110d0, 0x110e8,
- 0x110f0, 0x110f9,
- 0x11100, 0x11134,
- 0x11136, 0x11146,
- 0x11150, 0x11176,
- 0x11180, 0x111cd,
- 0x111d0, 0x111df,
- 0x111e1, 0x111f4,
- 0x11200, 0x11211,
- 0x11213, 0x1123e,
- 0x11280, 0x11286,
- 0x11288, 0x11288,
- 0x1128a, 0x1128d,
- 0x1128f, 0x1129d,
- 0x1129f, 0x112a9,
- 0x112b0, 0x112ea,
- 0x112f0, 0x112f9,
- 0x11300, 0x11303,
- 0x11305, 0x1130c,
- 0x1130f, 0x11310,
- 0x11313, 0x11328,
- 0x1132a, 0x11330,
- 0x11332, 0x11333,
- 0x11335, 0x11339,
- 0x1133b, 0x11344,
- 0x11347, 0x11348,
- 0x1134b, 0x1134d,
- 0x11350, 0x11350,
- 0x11357, 0x11357,
- 0x1135d, 0x11363,
- 0x11366, 0x1136c,
- 0x11370, 0x11374,
- 0x11400, 0x11459,
- 0x1145b, 0x1145b,
- 0x1145d, 0x1145f,
- 0x11480, 0x114c7,
- 0x114d0, 0x114d9,
- 0x11580, 0x115b5,
- 0x115b8, 0x115dd,
- 0x11600, 0x11644,
- 0x11650, 0x11659,
- 0x11660, 0x1166c,
- 0x11680, 0x116b8,
- 0x116c0, 0x116c9,
- 0x11700, 0x1171a,
- 0x1171d, 0x1172b,
- 0x11730, 0x1173f,
- 0x11800, 0x1183b,
- 0x118a0, 0x118f2,
- 0x118ff, 0x118ff,
- 0x119a0, 0x119a7,
- 0x119aa, 0x119d7,
- 0x119da, 0x119e4,
- 0x11a00, 0x11a47,
- 0x11a50, 0x11aa2,
- 0x11ac0, 0x11af8,
- 0x11c00, 0x11c08,
- 0x11c0a, 0x11c36,
- 0x11c38, 0x11c45,
- 0x11c50, 0x11c6c,
- 0x11c70, 0x11c8f,
- 0x11c92, 0x11ca7,
- 0x11ca9, 0x11cb6,
- 0x11d00, 0x11d06,
- 0x11d08, 0x11d09,
- 0x11d0b, 0x11d36,
- 0x11d3a, 0x11d3a,
- 0x11d3c, 0x11d3d,
- 0x11d3f, 0x11d47,
- 0x11d50, 0x11d59,
- 0x11d60, 0x11d65,
- 0x11d67, 0x11d68,
- 0x11d6a, 0x11d8e,
- 0x11d90, 0x11d91,
- 0x11d93, 0x11d98,
- 0x11da0, 0x11da9,
- 0x11ee0, 0x11ef8,
- 0x11fc0, 0x11ff1,
- 0x11fff, 0x12399,
- 0x12400, 0x1246e,
- 0x12470, 0x12474,
- 0x12480, 0x12543,
- 0x13000, 0x1342e,
- 0x13430, 0x13438,
- 0x14400, 0x14646,
- 0x16800, 0x16a38,
- 0x16a40, 0x16a5e,
- 0x16a60, 0x16a69,
- 0x16a6e, 0x16a6f,
- 0x16ad0, 0x16aed,
- 0x16af0, 0x16af5,
- 0x16b00, 0x16b45,
- 0x16b50, 0x16b59,
- 0x16b5b, 0x16b61,
- 0x16b63, 0x16b77,
- 0x16b7d, 0x16b8f,
- 0x16e40, 0x16e9a,
- 0x16f00, 0x16f4a,
- 0x16f4f, 0x16f87,
- 0x16f8f, 0x16f9f,
- 0x16fe0, 0x16fe3,
- 0x17000, 0x187f7,
- 0x18800, 0x18af2,
- 0x1b000, 0x1b11e,
- 0x1b150, 0x1b152,
- 0x1b164, 0x1b167,
- 0x1b170, 0x1b2fb,
- 0x1bc00, 0x1bc6a,
- 0x1bc70, 0x1bc7c,
- 0x1bc80, 0x1bc88,
- 0x1bc90, 0x1bc99,
- 0x1bc9c, 0x1bca3,
- 0x1d000, 0x1d0f5,
- 0x1d100, 0x1d126,
- 0x1d129, 0x1d1e8,
- 0x1d200, 0x1d245,
- 0x1d2e0, 0x1d2f3,
- 0x1d300, 0x1d356,
- 0x1d360, 0x1d378,
- 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, 0x1d7cb,
- 0x1d7ce, 0x1da8b,
- 0x1da9b, 0x1da9f,
- 0x1daa1, 0x1daaf,
- 0x1e000, 0x1e006,
- 0x1e008, 0x1e018,
- 0x1e01b, 0x1e021,
- 0x1e023, 0x1e024,
- 0x1e026, 0x1e02a,
- 0x1e100, 0x1e12c,
- 0x1e130, 0x1e13d,
- 0x1e140, 0x1e149,
- 0x1e14e, 0x1e14f,
- 0x1e2c0, 0x1e2f9,
- 0x1e2ff, 0x1e2ff,
- 0x1e800, 0x1e8c4,
- 0x1e8c7, 0x1e8d6,
- 0x1e900, 0x1e94b,
- 0x1e950, 0x1e959,
- 0x1e95e, 0x1e95f,
- 0x1ec71, 0x1ecb4,
- 0x1ed01, 0x1ed3d,
- 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,
- 0x1eef0, 0x1eef1,
- 0x1f000, 0x1f02b,
- 0x1f030, 0x1f093,
- 0x1f0a0, 0x1f0ae,
- 0x1f0b1, 0x1f0bf,
- 0x1f0c1, 0x1f0cf,
- 0x1f0d1, 0x1f0f5,
- 0x1f100, 0x1f10c,
- 0x1f110, 0x1f16c,
- 0x1f170, 0x1f1ac,
- 0x1f1e6, 0x1f202,
- 0x1f210, 0x1f23b,
- 0x1f240, 0x1f248,
- 0x1f250, 0x1f251,
- 0x1f260, 0x1f265,
- 0x1f300, 0x1f6d5,
- 0x1f6e0, 0x1f6ec,
- 0x1f6f0, 0x1f6fa,
- 0x1f700, 0x1f773,
- 0x1f780, 0x1f7d8,
- 0x1f7e0, 0x1f7eb,
- 0x1f800, 0x1f80b,
- 0x1f810, 0x1f847,
- 0x1f850, 0x1f859,
- 0x1f860, 0x1f887,
- 0x1f890, 0x1f8ad,
- 0x1f900, 0x1f90b,
- 0x1f90d, 0x1f971,
- 0x1f973, 0x1f976,
- 0x1f97a, 0x1f9a2,
- 0x1f9a5, 0x1f9aa,
- 0x1f9ae, 0x1f9ca,
- 0x1f9cd, 0x1fa53,
- 0x1fa60, 0x1fa6d,
- 0x1fa70, 0x1fa73,
- 0x1fa78, 0x1fa7a,
- 0x1fa80, 0x1fa82,
- 0x1fa90, 0x1fa95,
- 0x1fffe, 0x2a6d6,
- 0x2a700, 0x2b734,
- 0x2b740, 0x2b81d,
- 0x2b820, 0x2cea1,
- 0x2ceb0, 0x2ebe0,
- 0x2f800, 0x2fa1d,
- 0x2fffe, 0x2ffff,
- 0x3fffe, 0x3ffff,
- 0x4fffe, 0x4ffff,
- 0x5fffe, 0x5ffff,
- 0x6fffe, 0x6ffff,
- 0x7fffe, 0x7ffff,
- 0x8fffe, 0x8ffff,
- 0x9fffe, 0x9ffff,
- 0xafffe, 0xaffff,
- 0xbfffe, 0xbffff,
- 0xcfffe, 0xcffff,
- 0xdfffe, 0xdffff,
- 0xe0001, 0xe0001,
- 0xe0020, 0xe007f,
- 0xe0100, 0xe01ef,
- 0xefffe, 0x10ffff,
-}; /* CR_Age_12_0 */
-
-/* 'Age_12_1': Derived Age 12.1 */
-static const OnigCodePoint CR_Age_12_1[] = {
- 676,
- 0x0000, 0x0377,
- 0x037a, 0x037f,
- 0x0384, 0x038a,
- 0x038c, 0x038c,
- 0x038e, 0x03a1,
- 0x03a3, 0x052f,
- 0x0531, 0x0556,
- 0x0559, 0x058a,
- 0x058d, 0x058f,
- 0x0591, 0x05c7,
- 0x05d0, 0x05ea,
- 0x05ef, 0x05f4,
- 0x0600, 0x061c,
- 0x061e, 0x070d,
- 0x070f, 0x074a,
- 0x074d, 0x07b1,
- 0x07c0, 0x07fa,
- 0x07fd, 0x082d,
- 0x0830, 0x083e,
- 0x0840, 0x085b,
- 0x085e, 0x085e,
- 0x0860, 0x086a,
- 0x08a0, 0x08b4,
- 0x08b6, 0x08bd,
- 0x08d3, 0x0983,
- 0x0985, 0x098c,
- 0x098f, 0x0990,
- 0x0993, 0x09a8,
- 0x09aa, 0x09b0,
- 0x09b2, 0x09b2,
- 0x09b6, 0x09b9,
- 0x09bc, 0x09c4,
- 0x09c7, 0x09c8,
- 0x09cb, 0x09ce,
- 0x09d7, 0x09d7,
- 0x09dc, 0x09dd,
- 0x09df, 0x09e3,
- 0x09e6, 0x09fe,
- 0x0a01, 0x0a03,
- 0x0a05, 0x0a0a,
- 0x0a0f, 0x0a10,
- 0x0a13, 0x0a28,
- 0x0a2a, 0x0a30,
- 0x0a32, 0x0a33,
- 0x0a35, 0x0a36,
- 0x0a38, 0x0a39,
- 0x0a3c, 0x0a3c,
- 0x0a3e, 0x0a42,
- 0x0a47, 0x0a48,
- 0x0a4b, 0x0a4d,
- 0x0a51, 0x0a51,
- 0x0a59, 0x0a5c,
- 0x0a5e, 0x0a5e,
- 0x0a66, 0x0a76,
- 0x0a81, 0x0a83,
- 0x0a85, 0x0a8d,
- 0x0a8f, 0x0a91,
- 0x0a93, 0x0aa8,
- 0x0aaa, 0x0ab0,
- 0x0ab2, 0x0ab3,
- 0x0ab5, 0x0ab9,
- 0x0abc, 0x0ac5,
- 0x0ac7, 0x0ac9,
- 0x0acb, 0x0acd,
- 0x0ad0, 0x0ad0,
- 0x0ae0, 0x0ae3,
- 0x0ae6, 0x0af1,
- 0x0af9, 0x0aff,
- 0x0b01, 0x0b03,
- 0x0b05, 0x0b0c,
- 0x0b0f, 0x0b10,
- 0x0b13, 0x0b28,
- 0x0b2a, 0x0b30,
- 0x0b32, 0x0b33,
- 0x0b35, 0x0b39,
- 0x0b3c, 0x0b44,
- 0x0b47, 0x0b48,
- 0x0b4b, 0x0b4d,
- 0x0b56, 0x0b57,
- 0x0b5c, 0x0b5d,
- 0x0b5f, 0x0b63,
- 0x0b66, 0x0b77,
- 0x0b82, 0x0b83,
- 0x0b85, 0x0b8a,
- 0x0b8e, 0x0b90,
- 0x0b92, 0x0b95,
- 0x0b99, 0x0b9a,
- 0x0b9c, 0x0b9c,
- 0x0b9e, 0x0b9f,
- 0x0ba3, 0x0ba4,
- 0x0ba8, 0x0baa,
- 0x0bae, 0x0bb9,
- 0x0bbe, 0x0bc2,
- 0x0bc6, 0x0bc8,
- 0x0bca, 0x0bcd,
- 0x0bd0, 0x0bd0,
- 0x0bd7, 0x0bd7,
- 0x0be6, 0x0bfa,
- 0x0c00, 0x0c0c,
- 0x0c0e, 0x0c10,
- 0x0c12, 0x0c28,
- 0x0c2a, 0x0c39,
- 0x0c3d, 0x0c44,
- 0x0c46, 0x0c48,
- 0x0c4a, 0x0c4d,
- 0x0c55, 0x0c56,
- 0x0c58, 0x0c5a,
- 0x0c60, 0x0c63,
- 0x0c66, 0x0c6f,
- 0x0c77, 0x0c8c,
- 0x0c8e, 0x0c90,
- 0x0c92, 0x0ca8,
- 0x0caa, 0x0cb3,
- 0x0cb5, 0x0cb9,
- 0x0cbc, 0x0cc4,
- 0x0cc6, 0x0cc8,
- 0x0cca, 0x0ccd,
- 0x0cd5, 0x0cd6,
- 0x0cde, 0x0cde,
- 0x0ce0, 0x0ce3,
- 0x0ce6, 0x0cef,
- 0x0cf1, 0x0cf2,
- 0x0d00, 0x0d03,
- 0x0d05, 0x0d0c,
- 0x0d0e, 0x0d10,
- 0x0d12, 0x0d44,
- 0x0d46, 0x0d48,
- 0x0d4a, 0x0d4f,
- 0x0d54, 0x0d63,
- 0x0d66, 0x0d7f,
- 0x0d82, 0x0d83,
- 0x0d85, 0x0d96,
- 0x0d9a, 0x0db1,
- 0x0db3, 0x0dbb,
- 0x0dbd, 0x0dbd,
- 0x0dc0, 0x0dc6,
- 0x0dca, 0x0dca,
- 0x0dcf, 0x0dd4,
- 0x0dd6, 0x0dd6,
- 0x0dd8, 0x0ddf,
- 0x0de6, 0x0def,
- 0x0df2, 0x0df4,
- 0x0e01, 0x0e3a,
- 0x0e3f, 0x0e5b,
- 0x0e81, 0x0e82,
- 0x0e84, 0x0e84,
- 0x0e86, 0x0e8a,
- 0x0e8c, 0x0ea3,
- 0x0ea5, 0x0ea5,
- 0x0ea7, 0x0ebd,
- 0x0ec0, 0x0ec4,
- 0x0ec6, 0x0ec6,
- 0x0ec8, 0x0ecd,
- 0x0ed0, 0x0ed9,
- 0x0edc, 0x0edf,
- 0x0f00, 0x0f47,
- 0x0f49, 0x0f6c,
- 0x0f71, 0x0f97,
- 0x0f99, 0x0fbc,
- 0x0fbe, 0x0fcc,
- 0x0fce, 0x0fda,
- 0x1000, 0x10c5,
- 0x10c7, 0x10c7,
- 0x10cd, 0x10cd,
- 0x10d0, 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,
- 0x135d, 0x137c,
- 0x1380, 0x1399,
- 0x13a0, 0x13f5,
- 0x13f8, 0x13fd,
- 0x1400, 0x169c,
- 0x16a0, 0x16f8,
- 0x1700, 0x170c,
- 0x170e, 0x1714,
- 0x1720, 0x1736,
- 0x1740, 0x1753,
- 0x1760, 0x176c,
- 0x176e, 0x1770,
- 0x1772, 0x1773,
- 0x1780, 0x17dd,
- 0x17e0, 0x17e9,
- 0x17f0, 0x17f9,
- 0x1800, 0x180e,
- 0x1810, 0x1819,
- 0x1820, 0x1878,
- 0x1880, 0x18aa,
- 0x18b0, 0x18f5,
- 0x1900, 0x191e,
- 0x1920, 0x192b,
- 0x1930, 0x193b,
- 0x1940, 0x1940,
- 0x1944, 0x196d,
- 0x1970, 0x1974,
- 0x1980, 0x19ab,
- 0x19b0, 0x19c9,
- 0x19d0, 0x19da,
- 0x19de, 0x1a1b,
- 0x1a1e, 0x1a5e,
- 0x1a60, 0x1a7c,
- 0x1a7f, 0x1a89,
- 0x1a90, 0x1a99,
- 0x1aa0, 0x1aad,
- 0x1ab0, 0x1abe,
- 0x1b00, 0x1b4b,
- 0x1b50, 0x1b7c,
- 0x1b80, 0x1bf3,
- 0x1bfc, 0x1c37,
- 0x1c3b, 0x1c49,
- 0x1c4d, 0x1c88,
- 0x1c90, 0x1cba,
- 0x1cbd, 0x1cc7,
- 0x1cd0, 0x1cfa,
- 0x1d00, 0x1df9,
- 0x1dfb, 0x1f15,
- 0x1f18, 0x1f1d,
- 0x1f20, 0x1f45,
- 0x1f48, 0x1f4d,
- 0x1f50, 0x1f57,
- 0x1f59, 0x1f59,
- 0x1f5b, 0x1f5b,
- 0x1f5d, 0x1f5d,
- 0x1f5f, 0x1f7d,
- 0x1f80, 0x1fb4,
- 0x1fb6, 0x1fc4,
- 0x1fc6, 0x1fd3,
- 0x1fd6, 0x1fdb,
- 0x1fdd, 0x1fef,
- 0x1ff2, 0x1ff4,
- 0x1ff6, 0x1ffe,
- 0x2000, 0x2064,
- 0x2066, 0x2071,
- 0x2074, 0x208e,
- 0x2090, 0x209c,
- 0x20a0, 0x20bf,
- 0x20d0, 0x20f0,
- 0x2100, 0x218b,
- 0x2190, 0x2426,
- 0x2440, 0x244a,
- 0x2460, 0x2b73,
- 0x2b76, 0x2b95,
- 0x2b98, 0x2c2e,
- 0x2c30, 0x2c5e,
- 0x2c60, 0x2cf3,
- 0x2cf9, 0x2d25,
- 0x2d27, 0x2d27,
- 0x2d2d, 0x2d2d,
- 0x2d30, 0x2d67,
- 0x2d6f, 0x2d70,
- 0x2d7f, 0x2d96,
- 0x2da0, 0x2da6,
- 0x2da8, 0x2dae,
- 0x2db0, 0x2db6,
- 0x2db8, 0x2dbe,
- 0x2dc0, 0x2dc6,
- 0x2dc8, 0x2dce,
- 0x2dd0, 0x2dd6,
- 0x2dd8, 0x2dde,
- 0x2de0, 0x2e4f,
- 0x2e80, 0x2e99,
- 0x2e9b, 0x2ef3,
- 0x2f00, 0x2fd5,
- 0x2ff0, 0x2ffb,
- 0x3000, 0x303f,
- 0x3041, 0x3096,
- 0x3099, 0x30ff,
- 0x3105, 0x312f,
- 0x3131, 0x318e,
- 0x3190, 0x31ba,
- 0x31c0, 0x31e3,
- 0x31f0, 0x321e,
- 0x3220, 0x4db5,
- 0x4dc0, 0x9fef,
- 0xa000, 0xa48c,
- 0xa490, 0xa4c6,
- 0xa4d0, 0xa62b,
- 0xa640, 0xa6f7,
- 0xa700, 0xa7bf,
- 0xa7c2, 0xa7c6,
- 0xa7f7, 0xa82b,
- 0xa830, 0xa839,
- 0xa840, 0xa877,
- 0xa880, 0xa8c5,
- 0xa8ce, 0xa8d9,
- 0xa8e0, 0xa953,
- 0xa95f, 0xa97c,
- 0xa980, 0xa9cd,
- 0xa9cf, 0xa9d9,
- 0xa9de, 0xa9fe,
- 0xaa00, 0xaa36,
- 0xaa40, 0xaa4d,
- 0xaa50, 0xaa59,
- 0xaa5c, 0xaac2,
- 0xaadb, 0xaaf6,
- 0xab01, 0xab06,
- 0xab09, 0xab0e,
- 0xab11, 0xab16,
- 0xab20, 0xab26,
- 0xab28, 0xab2e,
- 0xab30, 0xab67,
- 0xab70, 0xabed,
- 0xabf0, 0xabf9,
- 0xac00, 0xd7a3,
- 0xd7b0, 0xd7c6,
- 0xd7cb, 0xd7fb,
- 0xd800, 0xfa6d,
- 0xfa70, 0xfad9,
- 0xfb00, 0xfb06,
- 0xfb13, 0xfb17,
- 0xfb1d, 0xfb36,
- 0xfb38, 0xfb3c,
- 0xfb3e, 0xfb3e,
- 0xfb40, 0xfb41,
- 0xfb43, 0xfb44,
- 0xfb46, 0xfbc1,
- 0xfbd3, 0xfd3f,
- 0xfd50, 0xfd8f,
- 0xfd92, 0xfdc7,
- 0xfdd0, 0xfdfd,
- 0xfe00, 0xfe19,
- 0xfe20, 0xfe52,
- 0xfe54, 0xfe66,
- 0xfe68, 0xfe6b,
- 0xfe70, 0xfe74,
- 0xfe76, 0xfefc,
- 0xfeff, 0xfeff,
- 0xff01, 0xffbe,
- 0xffc2, 0xffc7,
- 0xffca, 0xffcf,
- 0xffd2, 0xffd7,
- 0xffda, 0xffdc,
- 0xffe0, 0xffe6,
- 0xffe8, 0xffee,
- 0xfff9, 0x1000b,
- 0x1000d, 0x10026,
- 0x10028, 0x1003a,
- 0x1003c, 0x1003d,
- 0x1003f, 0x1004d,
- 0x10050, 0x1005d,
- 0x10080, 0x100fa,
- 0x10100, 0x10102,
- 0x10107, 0x10133,
- 0x10137, 0x1018e,
- 0x10190, 0x1019b,
- 0x101a0, 0x101a0,
- 0x101d0, 0x101fd,
- 0x10280, 0x1029c,
- 0x102a0, 0x102d0,
- 0x102e0, 0x102fb,
- 0x10300, 0x10323,
- 0x1032d, 0x1034a,
- 0x10350, 0x1037a,
- 0x10380, 0x1039d,
- 0x1039f, 0x103c3,
- 0x103c8, 0x103d5,
- 0x10400, 0x1049d,
- 0x104a0, 0x104a9,
- 0x104b0, 0x104d3,
- 0x104d8, 0x104fb,
- 0x10500, 0x10527,
- 0x10530, 0x10563,
- 0x1056f, 0x1056f,
- 0x10600, 0x10736,
- 0x10740, 0x10755,
- 0x10760, 0x10767,
- 0x10800, 0x10805,
- 0x10808, 0x10808,
- 0x1080a, 0x10835,
- 0x10837, 0x10838,
- 0x1083c, 0x1083c,
- 0x1083f, 0x10855,
- 0x10857, 0x1089e,
- 0x108a7, 0x108af,
- 0x108e0, 0x108f2,
- 0x108f4, 0x108f5,
- 0x108fb, 0x1091b,
- 0x1091f, 0x10939,
- 0x1093f, 0x1093f,
- 0x10980, 0x109b7,
- 0x109bc, 0x109cf,
- 0x109d2, 0x10a03,
- 0x10a05, 0x10a06,
- 0x10a0c, 0x10a13,
- 0x10a15, 0x10a17,
- 0x10a19, 0x10a35,
- 0x10a38, 0x10a3a,
- 0x10a3f, 0x10a48,
- 0x10a50, 0x10a58,
- 0x10a60, 0x10a9f,
- 0x10ac0, 0x10ae6,
- 0x10aeb, 0x10af6,
- 0x10b00, 0x10b35,
- 0x10b39, 0x10b55,
- 0x10b58, 0x10b72,
- 0x10b78, 0x10b91,
- 0x10b99, 0x10b9c,
- 0x10ba9, 0x10baf,
- 0x10c00, 0x10c48,
- 0x10c80, 0x10cb2,
- 0x10cc0, 0x10cf2,
- 0x10cfa, 0x10d27,
- 0x10d30, 0x10d39,
- 0x10e60, 0x10e7e,
- 0x10f00, 0x10f27,
- 0x10f30, 0x10f59,
- 0x10fe0, 0x10ff6,
- 0x11000, 0x1104d,
- 0x11052, 0x1106f,
- 0x1107f, 0x110c1,
- 0x110cd, 0x110cd,
- 0x110d0, 0x110e8,
- 0x110f0, 0x110f9,
- 0x11100, 0x11134,
- 0x11136, 0x11146,
- 0x11150, 0x11176,
- 0x11180, 0x111cd,
- 0x111d0, 0x111df,
- 0x111e1, 0x111f4,
- 0x11200, 0x11211,
- 0x11213, 0x1123e,
- 0x11280, 0x11286,
- 0x11288, 0x11288,
- 0x1128a, 0x1128d,
- 0x1128f, 0x1129d,
- 0x1129f, 0x112a9,
- 0x112b0, 0x112ea,
- 0x112f0, 0x112f9,
- 0x11300, 0x11303,
- 0x11305, 0x1130c,
- 0x1130f, 0x11310,
- 0x11313, 0x11328,
- 0x1132a, 0x11330,
- 0x11332, 0x11333,
- 0x11335, 0x11339,
- 0x1133b, 0x11344,
- 0x11347, 0x11348,
- 0x1134b, 0x1134d,
- 0x11350, 0x11350,
- 0x11357, 0x11357,
- 0x1135d, 0x11363,
- 0x11366, 0x1136c,
- 0x11370, 0x11374,
- 0x11400, 0x11459,
- 0x1145b, 0x1145b,
- 0x1145d, 0x1145f,
- 0x11480, 0x114c7,
- 0x114d0, 0x114d9,
- 0x11580, 0x115b5,
- 0x115b8, 0x115dd,
- 0x11600, 0x11644,
- 0x11650, 0x11659,
- 0x11660, 0x1166c,
- 0x11680, 0x116b8,
- 0x116c0, 0x116c9,
- 0x11700, 0x1171a,
- 0x1171d, 0x1172b,
- 0x11730, 0x1173f,
- 0x11800, 0x1183b,
- 0x118a0, 0x118f2,
- 0x118ff, 0x118ff,
- 0x119a0, 0x119a7,
- 0x119aa, 0x119d7,
- 0x119da, 0x119e4,
- 0x11a00, 0x11a47,
- 0x11a50, 0x11aa2,
- 0x11ac0, 0x11af8,
- 0x11c00, 0x11c08,
- 0x11c0a, 0x11c36,
- 0x11c38, 0x11c45,
- 0x11c50, 0x11c6c,
- 0x11c70, 0x11c8f,
- 0x11c92, 0x11ca7,
- 0x11ca9, 0x11cb6,
- 0x11d00, 0x11d06,
- 0x11d08, 0x11d09,
- 0x11d0b, 0x11d36,
- 0x11d3a, 0x11d3a,
- 0x11d3c, 0x11d3d,
- 0x11d3f, 0x11d47,
- 0x11d50, 0x11d59,
- 0x11d60, 0x11d65,
- 0x11d67, 0x11d68,
- 0x11d6a, 0x11d8e,
- 0x11d90, 0x11d91,
- 0x11d93, 0x11d98,
- 0x11da0, 0x11da9,
- 0x11ee0, 0x11ef8,
- 0x11fc0, 0x11ff1,
- 0x11fff, 0x12399,
- 0x12400, 0x1246e,
- 0x12470, 0x12474,
- 0x12480, 0x12543,
- 0x13000, 0x1342e,
- 0x13430, 0x13438,
- 0x14400, 0x14646,
- 0x16800, 0x16a38,
- 0x16a40, 0x16a5e,
- 0x16a60, 0x16a69,
- 0x16a6e, 0x16a6f,
- 0x16ad0, 0x16aed,
- 0x16af0, 0x16af5,
- 0x16b00, 0x16b45,
- 0x16b50, 0x16b59,
- 0x16b5b, 0x16b61,
- 0x16b63, 0x16b77,
- 0x16b7d, 0x16b8f,
- 0x16e40, 0x16e9a,
- 0x16f00, 0x16f4a,
- 0x16f4f, 0x16f87,
- 0x16f8f, 0x16f9f,
- 0x16fe0, 0x16fe3,
- 0x17000, 0x187f7,
- 0x18800, 0x18af2,
- 0x1b000, 0x1b11e,
- 0x1b150, 0x1b152,
- 0x1b164, 0x1b167,
- 0x1b170, 0x1b2fb,
- 0x1bc00, 0x1bc6a,
- 0x1bc70, 0x1bc7c,
- 0x1bc80, 0x1bc88,
- 0x1bc90, 0x1bc99,
- 0x1bc9c, 0x1bca3,
- 0x1d000, 0x1d0f5,
- 0x1d100, 0x1d126,
- 0x1d129, 0x1d1e8,
- 0x1d200, 0x1d245,
- 0x1d2e0, 0x1d2f3,
- 0x1d300, 0x1d356,
- 0x1d360, 0x1d378,
- 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, 0x1d7cb,
- 0x1d7ce, 0x1da8b,
- 0x1da9b, 0x1da9f,
- 0x1daa1, 0x1daaf,
- 0x1e000, 0x1e006,
- 0x1e008, 0x1e018,
- 0x1e01b, 0x1e021,
- 0x1e023, 0x1e024,
- 0x1e026, 0x1e02a,
- 0x1e100, 0x1e12c,
- 0x1e130, 0x1e13d,
- 0x1e140, 0x1e149,
- 0x1e14e, 0x1e14f,
- 0x1e2c0, 0x1e2f9,
- 0x1e2ff, 0x1e2ff,
- 0x1e800, 0x1e8c4,
- 0x1e8c7, 0x1e8d6,
- 0x1e900, 0x1e94b,
- 0x1e950, 0x1e959,
- 0x1e95e, 0x1e95f,
- 0x1ec71, 0x1ecb4,
- 0x1ed01, 0x1ed3d,
- 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,
- 0x1eef0, 0x1eef1,
- 0x1f000, 0x1f02b,
- 0x1f030, 0x1f093,
- 0x1f0a0, 0x1f0ae,
- 0x1f0b1, 0x1f0bf,
- 0x1f0c1, 0x1f0cf,
- 0x1f0d1, 0x1f0f5,
- 0x1f100, 0x1f10c,
- 0x1f110, 0x1f16c,
- 0x1f170, 0x1f1ac,
- 0x1f1e6, 0x1f202,
- 0x1f210, 0x1f23b,
- 0x1f240, 0x1f248,
- 0x1f250, 0x1f251,
- 0x1f260, 0x1f265,
- 0x1f300, 0x1f6d5,
- 0x1f6e0, 0x1f6ec,
- 0x1f6f0, 0x1f6fa,
- 0x1f700, 0x1f773,
- 0x1f780, 0x1f7d8,
- 0x1f7e0, 0x1f7eb,
- 0x1f800, 0x1f80b,
- 0x1f810, 0x1f847,
- 0x1f850, 0x1f859,
- 0x1f860, 0x1f887,
- 0x1f890, 0x1f8ad,
- 0x1f900, 0x1f90b,
- 0x1f90d, 0x1f971,
- 0x1f973, 0x1f976,
- 0x1f97a, 0x1f9a2,
- 0x1f9a5, 0x1f9aa,
- 0x1f9ae, 0x1f9ca,
- 0x1f9cd, 0x1fa53,
- 0x1fa60, 0x1fa6d,
- 0x1fa70, 0x1fa73,
- 0x1fa78, 0x1fa7a,
- 0x1fa80, 0x1fa82,
- 0x1fa90, 0x1fa95,
- 0x1fffe, 0x2a6d6,
- 0x2a700, 0x2b734,
- 0x2b740, 0x2b81d,
- 0x2b820, 0x2cea1,
- 0x2ceb0, 0x2ebe0,
- 0x2f800, 0x2fa1d,
- 0x2fffe, 0x2ffff,
- 0x3fffe, 0x3ffff,
- 0x4fffe, 0x4ffff,
- 0x5fffe, 0x5ffff,
- 0x6fffe, 0x6ffff,
- 0x7fffe, 0x7ffff,
- 0x8fffe, 0x8ffff,
- 0x9fffe, 0x9ffff,
- 0xafffe, 0xaffff,
- 0xbfffe, 0xbffff,
- 0xcfffe, 0xcffff,
- 0xdfffe, 0xdffff,
- 0xe0001, 0xe0001,
- 0xe0020, 0xe007f,
- 0xe0100, 0xe01ef,
- 0xefffe, 0x10ffff,
-}; /* CR_Age_12_1 */
-
-/* 'Age_13_0': Derived Age 13.0 */
-static const OnigCodePoint CR_Age_13_0[] = {
- 686,
- 0x0000, 0x0377,
- 0x037a, 0x037f,
- 0x0384, 0x038a,
- 0x038c, 0x038c,
- 0x038e, 0x03a1,
- 0x03a3, 0x052f,
- 0x0531, 0x0556,
- 0x0559, 0x058a,
- 0x058d, 0x058f,
- 0x0591, 0x05c7,
- 0x05d0, 0x05ea,
- 0x05ef, 0x05f4,
- 0x0600, 0x061c,
- 0x061e, 0x070d,
- 0x070f, 0x074a,
- 0x074d, 0x07b1,
- 0x07c0, 0x07fa,
- 0x07fd, 0x082d,
- 0x0830, 0x083e,
- 0x0840, 0x085b,
- 0x085e, 0x085e,
- 0x0860, 0x086a,
- 0x08a0, 0x08b4,
- 0x08b6, 0x08c7,
- 0x08d3, 0x0983,
- 0x0985, 0x098c,
- 0x098f, 0x0990,
- 0x0993, 0x09a8,
- 0x09aa, 0x09b0,
- 0x09b2, 0x09b2,
- 0x09b6, 0x09b9,
- 0x09bc, 0x09c4,
- 0x09c7, 0x09c8,
- 0x09cb, 0x09ce,
- 0x09d7, 0x09d7,
- 0x09dc, 0x09dd,
- 0x09df, 0x09e3,
- 0x09e6, 0x09fe,
- 0x0a01, 0x0a03,
- 0x0a05, 0x0a0a,
- 0x0a0f, 0x0a10,
- 0x0a13, 0x0a28,
- 0x0a2a, 0x0a30,
- 0x0a32, 0x0a33,
- 0x0a35, 0x0a36,
- 0x0a38, 0x0a39,
- 0x0a3c, 0x0a3c,
- 0x0a3e, 0x0a42,
- 0x0a47, 0x0a48,
- 0x0a4b, 0x0a4d,
- 0x0a51, 0x0a51,
- 0x0a59, 0x0a5c,
- 0x0a5e, 0x0a5e,
- 0x0a66, 0x0a76,
- 0x0a81, 0x0a83,
- 0x0a85, 0x0a8d,
- 0x0a8f, 0x0a91,
- 0x0a93, 0x0aa8,
- 0x0aaa, 0x0ab0,
- 0x0ab2, 0x0ab3,
- 0x0ab5, 0x0ab9,
- 0x0abc, 0x0ac5,
- 0x0ac7, 0x0ac9,
- 0x0acb, 0x0acd,
- 0x0ad0, 0x0ad0,
- 0x0ae0, 0x0ae3,
- 0x0ae6, 0x0af1,
- 0x0af9, 0x0aff,
- 0x0b01, 0x0b03,
- 0x0b05, 0x0b0c,
- 0x0b0f, 0x0b10,
- 0x0b13, 0x0b28,
- 0x0b2a, 0x0b30,
- 0x0b32, 0x0b33,
- 0x0b35, 0x0b39,
- 0x0b3c, 0x0b44,
- 0x0b47, 0x0b48,
- 0x0b4b, 0x0b4d,
- 0x0b55, 0x0b57,
- 0x0b5c, 0x0b5d,
- 0x0b5f, 0x0b63,
- 0x0b66, 0x0b77,
- 0x0b82, 0x0b83,
- 0x0b85, 0x0b8a,
- 0x0b8e, 0x0b90,
- 0x0b92, 0x0b95,
- 0x0b99, 0x0b9a,
- 0x0b9c, 0x0b9c,
- 0x0b9e, 0x0b9f,
- 0x0ba3, 0x0ba4,
- 0x0ba8, 0x0baa,
- 0x0bae, 0x0bb9,
- 0x0bbe, 0x0bc2,
- 0x0bc6, 0x0bc8,
- 0x0bca, 0x0bcd,
- 0x0bd0, 0x0bd0,
- 0x0bd7, 0x0bd7,
- 0x0be6, 0x0bfa,
- 0x0c00, 0x0c0c,
- 0x0c0e, 0x0c10,
- 0x0c12, 0x0c28,
- 0x0c2a, 0x0c39,
- 0x0c3d, 0x0c44,
- 0x0c46, 0x0c48,
- 0x0c4a, 0x0c4d,
- 0x0c55, 0x0c56,
- 0x0c58, 0x0c5a,
- 0x0c60, 0x0c63,
- 0x0c66, 0x0c6f,
- 0x0c77, 0x0c8c,
- 0x0c8e, 0x0c90,
- 0x0c92, 0x0ca8,
- 0x0caa, 0x0cb3,
- 0x0cb5, 0x0cb9,
- 0x0cbc, 0x0cc4,
- 0x0cc6, 0x0cc8,
- 0x0cca, 0x0ccd,
- 0x0cd5, 0x0cd6,
- 0x0cde, 0x0cde,
- 0x0ce0, 0x0ce3,
- 0x0ce6, 0x0cef,
- 0x0cf1, 0x0cf2,
- 0x0d00, 0x0d0c,
- 0x0d0e, 0x0d10,
- 0x0d12, 0x0d44,
- 0x0d46, 0x0d48,
- 0x0d4a, 0x0d4f,
- 0x0d54, 0x0d63,
- 0x0d66, 0x0d7f,
- 0x0d81, 0x0d83,
- 0x0d85, 0x0d96,
- 0x0d9a, 0x0db1,
- 0x0db3, 0x0dbb,
- 0x0dbd, 0x0dbd,
- 0x0dc0, 0x0dc6,
- 0x0dca, 0x0dca,
- 0x0dcf, 0x0dd4,
- 0x0dd6, 0x0dd6,
- 0x0dd8, 0x0ddf,
- 0x0de6, 0x0def,
- 0x0df2, 0x0df4,
- 0x0e01, 0x0e3a,
- 0x0e3f, 0x0e5b,
- 0x0e81, 0x0e82,
- 0x0e84, 0x0e84,
- 0x0e86, 0x0e8a,
- 0x0e8c, 0x0ea3,
- 0x0ea5, 0x0ea5,
- 0x0ea7, 0x0ebd,
- 0x0ec0, 0x0ec4,
- 0x0ec6, 0x0ec6,
- 0x0ec8, 0x0ecd,
- 0x0ed0, 0x0ed9,
- 0x0edc, 0x0edf,
- 0x0f00, 0x0f47,
- 0x0f49, 0x0f6c,
- 0x0f71, 0x0f97,
- 0x0f99, 0x0fbc,
- 0x0fbe, 0x0fcc,
- 0x0fce, 0x0fda,
- 0x1000, 0x10c5,
- 0x10c7, 0x10c7,
- 0x10cd, 0x10cd,
- 0x10d0, 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,
- 0x135d, 0x137c,
- 0x1380, 0x1399,
- 0x13a0, 0x13f5,
- 0x13f8, 0x13fd,
- 0x1400, 0x169c,
- 0x16a0, 0x16f8,
- 0x1700, 0x170c,
- 0x170e, 0x1714,
- 0x1720, 0x1736,
- 0x1740, 0x1753,
- 0x1760, 0x176c,
- 0x176e, 0x1770,
- 0x1772, 0x1773,
- 0x1780, 0x17dd,
- 0x17e0, 0x17e9,
- 0x17f0, 0x17f9,
- 0x1800, 0x180e,
- 0x1810, 0x1819,
- 0x1820, 0x1878,
- 0x1880, 0x18aa,
- 0x18b0, 0x18f5,
- 0x1900, 0x191e,
- 0x1920, 0x192b,
- 0x1930, 0x193b,
- 0x1940, 0x1940,
- 0x1944, 0x196d,
- 0x1970, 0x1974,
- 0x1980, 0x19ab,
- 0x19b0, 0x19c9,
- 0x19d0, 0x19da,
- 0x19de, 0x1a1b,
- 0x1a1e, 0x1a5e,
- 0x1a60, 0x1a7c,
- 0x1a7f, 0x1a89,
- 0x1a90, 0x1a99,
- 0x1aa0, 0x1aad,
- 0x1ab0, 0x1ac0,
- 0x1b00, 0x1b4b,
- 0x1b50, 0x1b7c,
- 0x1b80, 0x1bf3,
- 0x1bfc, 0x1c37,
- 0x1c3b, 0x1c49,
- 0x1c4d, 0x1c88,
- 0x1c90, 0x1cba,
- 0x1cbd, 0x1cc7,
- 0x1cd0, 0x1cfa,
- 0x1d00, 0x1df9,
- 0x1dfb, 0x1f15,
- 0x1f18, 0x1f1d,
- 0x1f20, 0x1f45,
- 0x1f48, 0x1f4d,
- 0x1f50, 0x1f57,
- 0x1f59, 0x1f59,
- 0x1f5b, 0x1f5b,
- 0x1f5d, 0x1f5d,
- 0x1f5f, 0x1f7d,
- 0x1f80, 0x1fb4,
- 0x1fb6, 0x1fc4,
- 0x1fc6, 0x1fd3,
- 0x1fd6, 0x1fdb,
- 0x1fdd, 0x1fef,
- 0x1ff2, 0x1ff4,
- 0x1ff6, 0x1ffe,
- 0x2000, 0x2064,
- 0x2066, 0x2071,
- 0x2074, 0x208e,
- 0x2090, 0x209c,
- 0x20a0, 0x20bf,
- 0x20d0, 0x20f0,
- 0x2100, 0x218b,
- 0x2190, 0x2426,
- 0x2440, 0x244a,
- 0x2460, 0x2b73,
- 0x2b76, 0x2b95,
- 0x2b97, 0x2c2e,
- 0x2c30, 0x2c5e,
- 0x2c60, 0x2cf3,
- 0x2cf9, 0x2d25,
- 0x2d27, 0x2d27,
- 0x2d2d, 0x2d2d,
- 0x2d30, 0x2d67,
- 0x2d6f, 0x2d70,
- 0x2d7f, 0x2d96,
- 0x2da0, 0x2da6,
- 0x2da8, 0x2dae,
- 0x2db0, 0x2db6,
- 0x2db8, 0x2dbe,
- 0x2dc0, 0x2dc6,
- 0x2dc8, 0x2dce,
- 0x2dd0, 0x2dd6,
- 0x2dd8, 0x2dde,
- 0x2de0, 0x2e52,
- 0x2e80, 0x2e99,
- 0x2e9b, 0x2ef3,
- 0x2f00, 0x2fd5,
- 0x2ff0, 0x2ffb,
- 0x3000, 0x303f,
- 0x3041, 0x3096,
- 0x3099, 0x30ff,
- 0x3105, 0x312f,
- 0x3131, 0x318e,
- 0x3190, 0x31e3,
- 0x31f0, 0x321e,
- 0x3220, 0x9ffc,
- 0xa000, 0xa48c,
- 0xa490, 0xa4c6,
- 0xa4d0, 0xa62b,
- 0xa640, 0xa6f7,
- 0xa700, 0xa7bf,
- 0xa7c2, 0xa7ca,
- 0xa7f5, 0xa82c,
- 0xa830, 0xa839,
- 0xa840, 0xa877,
- 0xa880, 0xa8c5,
- 0xa8ce, 0xa8d9,
- 0xa8e0, 0xa953,
- 0xa95f, 0xa97c,
- 0xa980, 0xa9cd,
- 0xa9cf, 0xa9d9,
- 0xa9de, 0xa9fe,
- 0xaa00, 0xaa36,
- 0xaa40, 0xaa4d,
- 0xaa50, 0xaa59,
- 0xaa5c, 0xaac2,
- 0xaadb, 0xaaf6,
- 0xab01, 0xab06,
- 0xab09, 0xab0e,
- 0xab11, 0xab16,
- 0xab20, 0xab26,
- 0xab28, 0xab2e,
- 0xab30, 0xab6b,
- 0xab70, 0xabed,
- 0xabf0, 0xabf9,
- 0xac00, 0xd7a3,
- 0xd7b0, 0xd7c6,
- 0xd7cb, 0xd7fb,
- 0xd800, 0xfa6d,
- 0xfa70, 0xfad9,
- 0xfb00, 0xfb06,
- 0xfb13, 0xfb17,
- 0xfb1d, 0xfb36,
- 0xfb38, 0xfb3c,
- 0xfb3e, 0xfb3e,
- 0xfb40, 0xfb41,
- 0xfb43, 0xfb44,
- 0xfb46, 0xfbc1,
- 0xfbd3, 0xfd3f,
- 0xfd50, 0xfd8f,
- 0xfd92, 0xfdc7,
- 0xfdd0, 0xfdfd,
- 0xfe00, 0xfe19,
- 0xfe20, 0xfe52,
- 0xfe54, 0xfe66,
- 0xfe68, 0xfe6b,
- 0xfe70, 0xfe74,
- 0xfe76, 0xfefc,
- 0xfeff, 0xfeff,
- 0xff01, 0xffbe,
- 0xffc2, 0xffc7,
- 0xffca, 0xffcf,
- 0xffd2, 0xffd7,
- 0xffda, 0xffdc,
- 0xffe0, 0xffe6,
- 0xffe8, 0xffee,
- 0xfff9, 0x1000b,
- 0x1000d, 0x10026,
- 0x10028, 0x1003a,
- 0x1003c, 0x1003d,
- 0x1003f, 0x1004d,
- 0x10050, 0x1005d,
- 0x10080, 0x100fa,
- 0x10100, 0x10102,
- 0x10107, 0x10133,
- 0x10137, 0x1018e,
- 0x10190, 0x1019c,
- 0x101a0, 0x101a0,
- 0x101d0, 0x101fd,
- 0x10280, 0x1029c,
- 0x102a0, 0x102d0,
- 0x102e0, 0x102fb,
- 0x10300, 0x10323,
- 0x1032d, 0x1034a,
- 0x10350, 0x1037a,
- 0x10380, 0x1039d,
- 0x1039f, 0x103c3,
- 0x103c8, 0x103d5,
- 0x10400, 0x1049d,
- 0x104a0, 0x104a9,
- 0x104b0, 0x104d3,
- 0x104d8, 0x104fb,
- 0x10500, 0x10527,
- 0x10530, 0x10563,
- 0x1056f, 0x1056f,
- 0x10600, 0x10736,
- 0x10740, 0x10755,
- 0x10760, 0x10767,
- 0x10800, 0x10805,
- 0x10808, 0x10808,
- 0x1080a, 0x10835,
- 0x10837, 0x10838,
- 0x1083c, 0x1083c,
- 0x1083f, 0x10855,
- 0x10857, 0x1089e,
- 0x108a7, 0x108af,
- 0x108e0, 0x108f2,
- 0x108f4, 0x108f5,
- 0x108fb, 0x1091b,
- 0x1091f, 0x10939,
- 0x1093f, 0x1093f,
- 0x10980, 0x109b7,
- 0x109bc, 0x109cf,
- 0x109d2, 0x10a03,
- 0x10a05, 0x10a06,
- 0x10a0c, 0x10a13,
- 0x10a15, 0x10a17,
- 0x10a19, 0x10a35,
- 0x10a38, 0x10a3a,
- 0x10a3f, 0x10a48,
- 0x10a50, 0x10a58,
- 0x10a60, 0x10a9f,
- 0x10ac0, 0x10ae6,
- 0x10aeb, 0x10af6,
- 0x10b00, 0x10b35,
- 0x10b39, 0x10b55,
- 0x10b58, 0x10b72,
- 0x10b78, 0x10b91,
- 0x10b99, 0x10b9c,
- 0x10ba9, 0x10baf,
- 0x10c00, 0x10c48,
- 0x10c80, 0x10cb2,
- 0x10cc0, 0x10cf2,
- 0x10cfa, 0x10d27,
- 0x10d30, 0x10d39,
- 0x10e60, 0x10e7e,
- 0x10e80, 0x10ea9,
- 0x10eab, 0x10ead,
- 0x10eb0, 0x10eb1,
- 0x10f00, 0x10f27,
- 0x10f30, 0x10f59,
- 0x10fb0, 0x10fcb,
- 0x10fe0, 0x10ff6,
- 0x11000, 0x1104d,
- 0x11052, 0x1106f,
- 0x1107f, 0x110c1,
- 0x110cd, 0x110cd,
- 0x110d0, 0x110e8,
- 0x110f0, 0x110f9,
- 0x11100, 0x11134,
- 0x11136, 0x11147,
- 0x11150, 0x11176,
- 0x11180, 0x111df,
- 0x111e1, 0x111f4,
- 0x11200, 0x11211,
- 0x11213, 0x1123e,
- 0x11280, 0x11286,
- 0x11288, 0x11288,
- 0x1128a, 0x1128d,
- 0x1128f, 0x1129d,
- 0x1129f, 0x112a9,
- 0x112b0, 0x112ea,
- 0x112f0, 0x112f9,
- 0x11300, 0x11303,
- 0x11305, 0x1130c,
- 0x1130f, 0x11310,
- 0x11313, 0x11328,
- 0x1132a, 0x11330,
- 0x11332, 0x11333,
- 0x11335, 0x11339,
- 0x1133b, 0x11344,
- 0x11347, 0x11348,
- 0x1134b, 0x1134d,
- 0x11350, 0x11350,
- 0x11357, 0x11357,
- 0x1135d, 0x11363,
- 0x11366, 0x1136c,
- 0x11370, 0x11374,
- 0x11400, 0x1145b,
- 0x1145d, 0x11461,
- 0x11480, 0x114c7,
- 0x114d0, 0x114d9,
- 0x11580, 0x115b5,
- 0x115b8, 0x115dd,
- 0x11600, 0x11644,
- 0x11650, 0x11659,
- 0x11660, 0x1166c,
- 0x11680, 0x116b8,
- 0x116c0, 0x116c9,
- 0x11700, 0x1171a,
- 0x1171d, 0x1172b,
- 0x11730, 0x1173f,
- 0x11800, 0x1183b,
- 0x118a0, 0x118f2,
- 0x118ff, 0x11906,
- 0x11909, 0x11909,
- 0x1190c, 0x11913,
- 0x11915, 0x11916,
- 0x11918, 0x11935,
- 0x11937, 0x11938,
- 0x1193b, 0x11946,
- 0x11950, 0x11959,
- 0x119a0, 0x119a7,
- 0x119aa, 0x119d7,
- 0x119da, 0x119e4,
- 0x11a00, 0x11a47,
- 0x11a50, 0x11aa2,
- 0x11ac0, 0x11af8,
- 0x11c00, 0x11c08,
- 0x11c0a, 0x11c36,
- 0x11c38, 0x11c45,
- 0x11c50, 0x11c6c,
- 0x11c70, 0x11c8f,
- 0x11c92, 0x11ca7,
- 0x11ca9, 0x11cb6,
- 0x11d00, 0x11d06,
- 0x11d08, 0x11d09,
- 0x11d0b, 0x11d36,
- 0x11d3a, 0x11d3a,
- 0x11d3c, 0x11d3d,
- 0x11d3f, 0x11d47,
- 0x11d50, 0x11d59,
- 0x11d60, 0x11d65,
- 0x11d67, 0x11d68,
- 0x11d6a, 0x11d8e,
- 0x11d90, 0x11d91,
- 0x11d93, 0x11d98,
- 0x11da0, 0x11da9,
- 0x11ee0, 0x11ef8,
- 0x11fb0, 0x11fb0,
- 0x11fc0, 0x11ff1,
- 0x11fff, 0x12399,
- 0x12400, 0x1246e,
- 0x12470, 0x12474,
- 0x12480, 0x12543,
- 0x13000, 0x1342e,
- 0x13430, 0x13438,
- 0x14400, 0x14646,
- 0x16800, 0x16a38,
- 0x16a40, 0x16a5e,
- 0x16a60, 0x16a69,
- 0x16a6e, 0x16a6f,
- 0x16ad0, 0x16aed,
- 0x16af0, 0x16af5,
- 0x16b00, 0x16b45,
- 0x16b50, 0x16b59,
- 0x16b5b, 0x16b61,
- 0x16b63, 0x16b77,
- 0x16b7d, 0x16b8f,
- 0x16e40, 0x16e9a,
- 0x16f00, 0x16f4a,
- 0x16f4f, 0x16f87,
- 0x16f8f, 0x16f9f,
- 0x16fe0, 0x16fe4,
- 0x16ff0, 0x16ff1,
- 0x17000, 0x187f7,
- 0x18800, 0x18cd5,
- 0x18d00, 0x18d08,
- 0x1b000, 0x1b11e,
- 0x1b150, 0x1b152,
- 0x1b164, 0x1b167,
- 0x1b170, 0x1b2fb,
- 0x1bc00, 0x1bc6a,
- 0x1bc70, 0x1bc7c,
- 0x1bc80, 0x1bc88,
- 0x1bc90, 0x1bc99,
- 0x1bc9c, 0x1bca3,
- 0x1d000, 0x1d0f5,
- 0x1d100, 0x1d126,
- 0x1d129, 0x1d1e8,
- 0x1d200, 0x1d245,
- 0x1d2e0, 0x1d2f3,
- 0x1d300, 0x1d356,
- 0x1d360, 0x1d378,
- 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, 0x1d7cb,
- 0x1d7ce, 0x1da8b,
- 0x1da9b, 0x1da9f,
- 0x1daa1, 0x1daaf,
- 0x1e000, 0x1e006,
- 0x1e008, 0x1e018,
- 0x1e01b, 0x1e021,
- 0x1e023, 0x1e024,
- 0x1e026, 0x1e02a,
- 0x1e100, 0x1e12c,
- 0x1e130, 0x1e13d,
- 0x1e140, 0x1e149,
- 0x1e14e, 0x1e14f,
- 0x1e2c0, 0x1e2f9,
- 0x1e2ff, 0x1e2ff,
- 0x1e800, 0x1e8c4,
- 0x1e8c7, 0x1e8d6,
- 0x1e900, 0x1e94b,
- 0x1e950, 0x1e959,
- 0x1e95e, 0x1e95f,
- 0x1ec71, 0x1ecb4,
- 0x1ed01, 0x1ed3d,
- 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,
- 0x1eef0, 0x1eef1,
- 0x1f000, 0x1f02b,
- 0x1f030, 0x1f093,
- 0x1f0a0, 0x1f0ae,
- 0x1f0b1, 0x1f0bf,
- 0x1f0c1, 0x1f0cf,
- 0x1f0d1, 0x1f0f5,
- 0x1f100, 0x1f1ad,
- 0x1f1e6, 0x1f202,
- 0x1f210, 0x1f23b,
- 0x1f240, 0x1f248,
- 0x1f250, 0x1f251,
- 0x1f260, 0x1f265,
- 0x1f300, 0x1f6d7,
- 0x1f6e0, 0x1f6ec,
- 0x1f6f0, 0x1f6fc,
- 0x1f700, 0x1f773,
- 0x1f780, 0x1f7d8,
- 0x1f7e0, 0x1f7eb,
- 0x1f800, 0x1f80b,
- 0x1f810, 0x1f847,
- 0x1f850, 0x1f859,
- 0x1f860, 0x1f887,
- 0x1f890, 0x1f8ad,
- 0x1f8b0, 0x1f8b1,
- 0x1f900, 0x1f978,
- 0x1f97a, 0x1f9cb,
- 0x1f9cd, 0x1fa53,
- 0x1fa60, 0x1fa6d,
- 0x1fa70, 0x1fa74,
- 0x1fa78, 0x1fa7a,
- 0x1fa80, 0x1fa86,
- 0x1fa90, 0x1faa8,
- 0x1fab0, 0x1fab6,
- 0x1fac0, 0x1fac2,
- 0x1fad0, 0x1fad6,
- 0x1fb00, 0x1fb92,
- 0x1fb94, 0x1fbca,
- 0x1fbf0, 0x1fbf9,
- 0x1fffe, 0x2a6dd,
- 0x2a700, 0x2b734,
- 0x2b740, 0x2b81d,
- 0x2b820, 0x2cea1,
- 0x2ceb0, 0x2ebe0,
- 0x2f800, 0x2fa1d,
- 0x2fffe, 0x3134a,
- 0x3fffe, 0x3ffff,
- 0x4fffe, 0x4ffff,
- 0x5fffe, 0x5ffff,
- 0x6fffe, 0x6ffff,
- 0x7fffe, 0x7ffff,
- 0x8fffe, 0x8ffff,
- 0x9fffe, 0x9ffff,
- 0xafffe, 0xaffff,
- 0xbfffe, 0xbffff,
- 0xcfffe, 0xcffff,
- 0xdfffe, 0xdffff,
- 0xe0001, 0xe0001,
- 0xe0020, 0xe007f,
- 0xe0100, 0xe01ef,
- 0xefffe, 0x10ffff,
-}; /* CR_Age_13_0 */
-
-/* 'Age_14_0': Derived Age 14.0 */
-static const OnigCodePoint CR_Age_14_0[] = {
- 706,
- 0x0000, 0x0377,
- 0x037a, 0x037f,
- 0x0384, 0x038a,
- 0x038c, 0x038c,
- 0x038e, 0x03a1,
- 0x03a3, 0x052f,
- 0x0531, 0x0556,
- 0x0559, 0x058a,
- 0x058d, 0x058f,
- 0x0591, 0x05c7,
- 0x05d0, 0x05ea,
- 0x05ef, 0x05f4,
- 0x0600, 0x070d,
- 0x070f, 0x074a,
- 0x074d, 0x07b1,
- 0x07c0, 0x07fa,
- 0x07fd, 0x082d,
- 0x0830, 0x083e,
- 0x0840, 0x085b,
- 0x085e, 0x085e,
- 0x0860, 0x086a,
- 0x0870, 0x088e,
- 0x0890, 0x0891,
- 0x0898, 0x0983,
- 0x0985, 0x098c,
- 0x098f, 0x0990,
- 0x0993, 0x09a8,
- 0x09aa, 0x09b0,
- 0x09b2, 0x09b2,
- 0x09b6, 0x09b9,
- 0x09bc, 0x09c4,
- 0x09c7, 0x09c8,
- 0x09cb, 0x09ce,
- 0x09d7, 0x09d7,
- 0x09dc, 0x09dd,
- 0x09df, 0x09e3,
- 0x09e6, 0x09fe,
- 0x0a01, 0x0a03,
- 0x0a05, 0x0a0a,
- 0x0a0f, 0x0a10,
- 0x0a13, 0x0a28,
- 0x0a2a, 0x0a30,
- 0x0a32, 0x0a33,
- 0x0a35, 0x0a36,
- 0x0a38, 0x0a39,
- 0x0a3c, 0x0a3c,
- 0x0a3e, 0x0a42,
- 0x0a47, 0x0a48,
- 0x0a4b, 0x0a4d,
- 0x0a51, 0x0a51,
- 0x0a59, 0x0a5c,
- 0x0a5e, 0x0a5e,
- 0x0a66, 0x0a76,
- 0x0a81, 0x0a83,
- 0x0a85, 0x0a8d,
- 0x0a8f, 0x0a91,
- 0x0a93, 0x0aa8,
- 0x0aaa, 0x0ab0,
- 0x0ab2, 0x0ab3,
- 0x0ab5, 0x0ab9,
- 0x0abc, 0x0ac5,
- 0x0ac7, 0x0ac9,
- 0x0acb, 0x0acd,
- 0x0ad0, 0x0ad0,
- 0x0ae0, 0x0ae3,
- 0x0ae6, 0x0af1,
- 0x0af9, 0x0aff,
- 0x0b01, 0x0b03,
- 0x0b05, 0x0b0c,
- 0x0b0f, 0x0b10,
- 0x0b13, 0x0b28,
- 0x0b2a, 0x0b30,
- 0x0b32, 0x0b33,
- 0x0b35, 0x0b39,
- 0x0b3c, 0x0b44,
- 0x0b47, 0x0b48,
- 0x0b4b, 0x0b4d,
- 0x0b55, 0x0b57,
- 0x0b5c, 0x0b5d,
- 0x0b5f, 0x0b63,
- 0x0b66, 0x0b77,
- 0x0b82, 0x0b83,
- 0x0b85, 0x0b8a,
- 0x0b8e, 0x0b90,
- 0x0b92, 0x0b95,
- 0x0b99, 0x0b9a,
- 0x0b9c, 0x0b9c,
- 0x0b9e, 0x0b9f,
- 0x0ba3, 0x0ba4,
- 0x0ba8, 0x0baa,
- 0x0bae, 0x0bb9,
- 0x0bbe, 0x0bc2,
- 0x0bc6, 0x0bc8,
- 0x0bca, 0x0bcd,
- 0x0bd0, 0x0bd0,
- 0x0bd7, 0x0bd7,
- 0x0be6, 0x0bfa,
- 0x0c00, 0x0c0c,
- 0x0c0e, 0x0c10,
- 0x0c12, 0x0c28,
- 0x0c2a, 0x0c39,
- 0x0c3c, 0x0c44,
- 0x0c46, 0x0c48,
- 0x0c4a, 0x0c4d,
- 0x0c55, 0x0c56,
- 0x0c58, 0x0c5a,
- 0x0c5d, 0x0c5d,
- 0x0c60, 0x0c63,
- 0x0c66, 0x0c6f,
- 0x0c77, 0x0c8c,
- 0x0c8e, 0x0c90,
- 0x0c92, 0x0ca8,
- 0x0caa, 0x0cb3,
- 0x0cb5, 0x0cb9,
- 0x0cbc, 0x0cc4,
- 0x0cc6, 0x0cc8,
- 0x0cca, 0x0ccd,
- 0x0cd5, 0x0cd6,
- 0x0cdd, 0x0cde,
- 0x0ce0, 0x0ce3,
- 0x0ce6, 0x0cef,
- 0x0cf1, 0x0cf2,
- 0x0d00, 0x0d0c,
- 0x0d0e, 0x0d10,
- 0x0d12, 0x0d44,
- 0x0d46, 0x0d48,
- 0x0d4a, 0x0d4f,
- 0x0d54, 0x0d63,
- 0x0d66, 0x0d7f,
- 0x0d81, 0x0d83,
- 0x0d85, 0x0d96,
- 0x0d9a, 0x0db1,
- 0x0db3, 0x0dbb,
- 0x0dbd, 0x0dbd,
- 0x0dc0, 0x0dc6,
- 0x0dca, 0x0dca,
- 0x0dcf, 0x0dd4,
- 0x0dd6, 0x0dd6,
- 0x0dd8, 0x0ddf,
- 0x0de6, 0x0def,
- 0x0df2, 0x0df4,
- 0x0e01, 0x0e3a,
- 0x0e3f, 0x0e5b,
- 0x0e81, 0x0e82,
- 0x0e84, 0x0e84,
- 0x0e86, 0x0e8a,
- 0x0e8c, 0x0ea3,
- 0x0ea5, 0x0ea5,
- 0x0ea7, 0x0ebd,
- 0x0ec0, 0x0ec4,
- 0x0ec6, 0x0ec6,
- 0x0ec8, 0x0ecd,
- 0x0ed0, 0x0ed9,
- 0x0edc, 0x0edf,
- 0x0f00, 0x0f47,
- 0x0f49, 0x0f6c,
- 0x0f71, 0x0f97,
- 0x0f99, 0x0fbc,
- 0x0fbe, 0x0fcc,
- 0x0fce, 0x0fda,
- 0x1000, 0x10c5,
- 0x10c7, 0x10c7,
- 0x10cd, 0x10cd,
- 0x10d0, 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,
- 0x135d, 0x137c,
- 0x1380, 0x1399,
- 0x13a0, 0x13f5,
- 0x13f8, 0x13fd,
- 0x1400, 0x169c,
- 0x16a0, 0x16f8,
- 0x1700, 0x1715,
- 0x171f, 0x1736,
- 0x1740, 0x1753,
- 0x1760, 0x176c,
- 0x176e, 0x1770,
- 0x1772, 0x1773,
- 0x1780, 0x17dd,
- 0x17e0, 0x17e9,
- 0x17f0, 0x17f9,
- 0x1800, 0x1819,
- 0x1820, 0x1878,
- 0x1880, 0x18aa,
- 0x18b0, 0x18f5,
- 0x1900, 0x191e,
- 0x1920, 0x192b,
- 0x1930, 0x193b,
- 0x1940, 0x1940,
- 0x1944, 0x196d,
- 0x1970, 0x1974,
- 0x1980, 0x19ab,
- 0x19b0, 0x19c9,
- 0x19d0, 0x19da,
- 0x19de, 0x1a1b,
- 0x1a1e, 0x1a5e,
- 0x1a60, 0x1a7c,
- 0x1a7f, 0x1a89,
- 0x1a90, 0x1a99,
- 0x1aa0, 0x1aad,
- 0x1ab0, 0x1ace,
- 0x1b00, 0x1b4c,
- 0x1b50, 0x1b7e,
- 0x1b80, 0x1bf3,
- 0x1bfc, 0x1c37,
- 0x1c3b, 0x1c49,
- 0x1c4d, 0x1c88,
- 0x1c90, 0x1cba,
- 0x1cbd, 0x1cc7,
- 0x1cd0, 0x1cfa,
- 0x1d00, 0x1f15,
- 0x1f18, 0x1f1d,
- 0x1f20, 0x1f45,
- 0x1f48, 0x1f4d,
- 0x1f50, 0x1f57,
- 0x1f59, 0x1f59,
- 0x1f5b, 0x1f5b,
- 0x1f5d, 0x1f5d,
- 0x1f5f, 0x1f7d,
- 0x1f80, 0x1fb4,
- 0x1fb6, 0x1fc4,
- 0x1fc6, 0x1fd3,
- 0x1fd6, 0x1fdb,
- 0x1fdd, 0x1fef,
- 0x1ff2, 0x1ff4,
- 0x1ff6, 0x1ffe,
- 0x2000, 0x2064,
- 0x2066, 0x2071,
- 0x2074, 0x208e,
- 0x2090, 0x209c,
- 0x20a0, 0x20c0,
- 0x20d0, 0x20f0,
- 0x2100, 0x218b,
- 0x2190, 0x2426,
- 0x2440, 0x244a,
- 0x2460, 0x2b73,
- 0x2b76, 0x2b95,
- 0x2b97, 0x2cf3,
- 0x2cf9, 0x2d25,
- 0x2d27, 0x2d27,
- 0x2d2d, 0x2d2d,
- 0x2d30, 0x2d67,
- 0x2d6f, 0x2d70,
- 0x2d7f, 0x2d96,
- 0x2da0, 0x2da6,
- 0x2da8, 0x2dae,
- 0x2db0, 0x2db6,
- 0x2db8, 0x2dbe,
- 0x2dc0, 0x2dc6,
- 0x2dc8, 0x2dce,
- 0x2dd0, 0x2dd6,
- 0x2dd8, 0x2dde,
- 0x2de0, 0x2e5d,
- 0x2e80, 0x2e99,
- 0x2e9b, 0x2ef3,
- 0x2f00, 0x2fd5,
- 0x2ff0, 0x2ffb,
- 0x3000, 0x303f,
- 0x3041, 0x3096,
- 0x3099, 0x30ff,
- 0x3105, 0x312f,
- 0x3131, 0x318e,
- 0x3190, 0x31e3,
- 0x31f0, 0x321e,
- 0x3220, 0xa48c,
- 0xa490, 0xa4c6,
- 0xa4d0, 0xa62b,
- 0xa640, 0xa6f7,
- 0xa700, 0xa7ca,
- 0xa7d0, 0xa7d1,
- 0xa7d3, 0xa7d3,
- 0xa7d5, 0xa7d9,
- 0xa7f2, 0xa82c,
- 0xa830, 0xa839,
- 0xa840, 0xa877,
- 0xa880, 0xa8c5,
- 0xa8ce, 0xa8d9,
- 0xa8e0, 0xa953,
- 0xa95f, 0xa97c,
- 0xa980, 0xa9cd,
- 0xa9cf, 0xa9d9,
- 0xa9de, 0xa9fe,
- 0xaa00, 0xaa36,
- 0xaa40, 0xaa4d,
- 0xaa50, 0xaa59,
- 0xaa5c, 0xaac2,
- 0xaadb, 0xaaf6,
- 0xab01, 0xab06,
- 0xab09, 0xab0e,
- 0xab11, 0xab16,
- 0xab20, 0xab26,
- 0xab28, 0xab2e,
- 0xab30, 0xab6b,
- 0xab70, 0xabed,
- 0xabf0, 0xabf9,
- 0xac00, 0xd7a3,
- 0xd7b0, 0xd7c6,
- 0xd7cb, 0xd7fb,
- 0xd800, 0xfa6d,
- 0xfa70, 0xfad9,
- 0xfb00, 0xfb06,
- 0xfb13, 0xfb17,
- 0xfb1d, 0xfb36,
- 0xfb38, 0xfb3c,
- 0xfb3e, 0xfb3e,
- 0xfb40, 0xfb41,
- 0xfb43, 0xfb44,
- 0xfb46, 0xfbc2,
- 0xfbd3, 0xfd8f,
- 0xfd92, 0xfdc7,
- 0xfdcf, 0xfe19,
- 0xfe20, 0xfe52,
- 0xfe54, 0xfe66,
- 0xfe68, 0xfe6b,
- 0xfe70, 0xfe74,
- 0xfe76, 0xfefc,
- 0xfeff, 0xfeff,
- 0xff01, 0xffbe,
- 0xffc2, 0xffc7,
- 0xffca, 0xffcf,
- 0xffd2, 0xffd7,
- 0xffda, 0xffdc,
- 0xffe0, 0xffe6,
- 0xffe8, 0xffee,
- 0xfff9, 0x1000b,
- 0x1000d, 0x10026,
- 0x10028, 0x1003a,
- 0x1003c, 0x1003d,
- 0x1003f, 0x1004d,
- 0x10050, 0x1005d,
- 0x10080, 0x100fa,
- 0x10100, 0x10102,
- 0x10107, 0x10133,
- 0x10137, 0x1018e,
- 0x10190, 0x1019c,
- 0x101a0, 0x101a0,
- 0x101d0, 0x101fd,
- 0x10280, 0x1029c,
- 0x102a0, 0x102d0,
- 0x102e0, 0x102fb,
- 0x10300, 0x10323,
- 0x1032d, 0x1034a,
- 0x10350, 0x1037a,
- 0x10380, 0x1039d,
- 0x1039f, 0x103c3,
- 0x103c8, 0x103d5,
- 0x10400, 0x1049d,
- 0x104a0, 0x104a9,
- 0x104b0, 0x104d3,
- 0x104d8, 0x104fb,
- 0x10500, 0x10527,
- 0x10530, 0x10563,
- 0x1056f, 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,
- 0x10857, 0x1089e,
- 0x108a7, 0x108af,
- 0x108e0, 0x108f2,
- 0x108f4, 0x108f5,
- 0x108fb, 0x1091b,
- 0x1091f, 0x10939,
- 0x1093f, 0x1093f,
- 0x10980, 0x109b7,
- 0x109bc, 0x109cf,
- 0x109d2, 0x10a03,
- 0x10a05, 0x10a06,
- 0x10a0c, 0x10a13,
- 0x10a15, 0x10a17,
- 0x10a19, 0x10a35,
- 0x10a38, 0x10a3a,
- 0x10a3f, 0x10a48,
- 0x10a50, 0x10a58,
- 0x10a60, 0x10a9f,
- 0x10ac0, 0x10ae6,
- 0x10aeb, 0x10af6,
- 0x10b00, 0x10b35,
- 0x10b39, 0x10b55,
- 0x10b58, 0x10b72,
- 0x10b78, 0x10b91,
- 0x10b99, 0x10b9c,
- 0x10ba9, 0x10baf,
- 0x10c00, 0x10c48,
- 0x10c80, 0x10cb2,
- 0x10cc0, 0x10cf2,
- 0x10cfa, 0x10d27,
- 0x10d30, 0x10d39,
- 0x10e60, 0x10e7e,
- 0x10e80, 0x10ea9,
- 0x10eab, 0x10ead,
- 0x10eb0, 0x10eb1,
- 0x10f00, 0x10f27,
- 0x10f30, 0x10f59,
- 0x10f70, 0x10f89,
- 0x10fb0, 0x10fcb,
- 0x10fe0, 0x10ff6,
- 0x11000, 0x1104d,
- 0x11052, 0x11075,
- 0x1107f, 0x110c2,
- 0x110cd, 0x110cd,
- 0x110d0, 0x110e8,
- 0x110f0, 0x110f9,
- 0x11100, 0x11134,
- 0x11136, 0x11147,
- 0x11150, 0x11176,
- 0x11180, 0x111df,
- 0x111e1, 0x111f4,
- 0x11200, 0x11211,
- 0x11213, 0x1123e,
- 0x11280, 0x11286,
- 0x11288, 0x11288,
- 0x1128a, 0x1128d,
- 0x1128f, 0x1129d,
- 0x1129f, 0x112a9,
- 0x112b0, 0x112ea,
- 0x112f0, 0x112f9,
- 0x11300, 0x11303,
- 0x11305, 0x1130c,
- 0x1130f, 0x11310,
- 0x11313, 0x11328,
- 0x1132a, 0x11330,
- 0x11332, 0x11333,
- 0x11335, 0x11339,
- 0x1133b, 0x11344,
- 0x11347, 0x11348,
- 0x1134b, 0x1134d,
- 0x11350, 0x11350,
- 0x11357, 0x11357,
- 0x1135d, 0x11363,
- 0x11366, 0x1136c,
- 0x11370, 0x11374,
- 0x11400, 0x1145b,
- 0x1145d, 0x11461,
- 0x11480, 0x114c7,
- 0x114d0, 0x114d9,
- 0x11580, 0x115b5,
- 0x115b8, 0x115dd,
- 0x11600, 0x11644,
- 0x11650, 0x11659,
- 0x11660, 0x1166c,
- 0x11680, 0x116b9,
- 0x116c0, 0x116c9,
- 0x11700, 0x1171a,
- 0x1171d, 0x1172b,
- 0x11730, 0x11746,
- 0x11800, 0x1183b,
- 0x118a0, 0x118f2,
- 0x118ff, 0x11906,
- 0x11909, 0x11909,
- 0x1190c, 0x11913,
- 0x11915, 0x11916,
- 0x11918, 0x11935,
- 0x11937, 0x11938,
- 0x1193b, 0x11946,
- 0x11950, 0x11959,
- 0x119a0, 0x119a7,
- 0x119aa, 0x119d7,
- 0x119da, 0x119e4,
- 0x11a00, 0x11a47,
- 0x11a50, 0x11aa2,
- 0x11ab0, 0x11af8,
- 0x11c00, 0x11c08,
- 0x11c0a, 0x11c36,
- 0x11c38, 0x11c45,
- 0x11c50, 0x11c6c,
- 0x11c70, 0x11c8f,
- 0x11c92, 0x11ca7,
- 0x11ca9, 0x11cb6,
- 0x11d00, 0x11d06,
- 0x11d08, 0x11d09,
- 0x11d0b, 0x11d36,
- 0x11d3a, 0x11d3a,
- 0x11d3c, 0x11d3d,
- 0x11d3f, 0x11d47,
- 0x11d50, 0x11d59,
- 0x11d60, 0x11d65,
- 0x11d67, 0x11d68,
- 0x11d6a, 0x11d8e,
- 0x11d90, 0x11d91,
- 0x11d93, 0x11d98,
- 0x11da0, 0x11da9,
- 0x11ee0, 0x11ef8,
- 0x11fb0, 0x11fb0,
- 0x11fc0, 0x11ff1,
- 0x11fff, 0x12399,
- 0x12400, 0x1246e,
- 0x12470, 0x12474,
- 0x12480, 0x12543,
- 0x12f90, 0x12ff2,
- 0x13000, 0x1342e,
- 0x13430, 0x13438,
- 0x14400, 0x14646,
- 0x16800, 0x16a38,
- 0x16a40, 0x16a5e,
- 0x16a60, 0x16a69,
- 0x16a6e, 0x16abe,
- 0x16ac0, 0x16ac9,
- 0x16ad0, 0x16aed,
- 0x16af0, 0x16af5,
- 0x16b00, 0x16b45,
- 0x16b50, 0x16b59,
- 0x16b5b, 0x16b61,
- 0x16b63, 0x16b77,
- 0x16b7d, 0x16b8f,
- 0x16e40, 0x16e9a,
- 0x16f00, 0x16f4a,
- 0x16f4f, 0x16f87,
- 0x16f8f, 0x16f9f,
- 0x16fe0, 0x16fe4,
- 0x16ff0, 0x16ff1,
- 0x17000, 0x187f7,
- 0x18800, 0x18cd5,
- 0x18d00, 0x18d08,
- 0x1aff0, 0x1aff3,
- 0x1aff5, 0x1affb,
- 0x1affd, 0x1affe,
- 0x1b000, 0x1b122,
- 0x1b150, 0x1b152,
- 0x1b164, 0x1b167,
- 0x1b170, 0x1b2fb,
- 0x1bc00, 0x1bc6a,
- 0x1bc70, 0x1bc7c,
- 0x1bc80, 0x1bc88,
- 0x1bc90, 0x1bc99,
- 0x1bc9c, 0x1bca3,
- 0x1cf00, 0x1cf2d,
- 0x1cf30, 0x1cf46,
- 0x1cf50, 0x1cfc3,
- 0x1d000, 0x1d0f5,
- 0x1d100, 0x1d126,
- 0x1d129, 0x1d1ea,
- 0x1d200, 0x1d245,
- 0x1d2e0, 0x1d2f3,
- 0x1d300, 0x1d356,
- 0x1d360, 0x1d378,
- 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, 0x1d7cb,
- 0x1d7ce, 0x1da8b,
- 0x1da9b, 0x1da9f,
- 0x1daa1, 0x1daaf,
- 0x1df00, 0x1df1e,
- 0x1e000, 0x1e006,
- 0x1e008, 0x1e018,
- 0x1e01b, 0x1e021,
- 0x1e023, 0x1e024,
- 0x1e026, 0x1e02a,
- 0x1e100, 0x1e12c,
- 0x1e130, 0x1e13d,
- 0x1e140, 0x1e149,
- 0x1e14e, 0x1e14f,
- 0x1e290, 0x1e2ae,
- 0x1e2c0, 0x1e2f9,
- 0x1e2ff, 0x1e2ff,
- 0x1e7e0, 0x1e7e6,
- 0x1e7e8, 0x1e7eb,
- 0x1e7ed, 0x1e7ee,
- 0x1e7f0, 0x1e7fe,
- 0x1e800, 0x1e8c4,
- 0x1e8c7, 0x1e8d6,
- 0x1e900, 0x1e94b,
- 0x1e950, 0x1e959,
- 0x1e95e, 0x1e95f,
- 0x1ec71, 0x1ecb4,
- 0x1ed01, 0x1ed3d,
- 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,
- 0x1eef0, 0x1eef1,
- 0x1f000, 0x1f02b,
- 0x1f030, 0x1f093,
- 0x1f0a0, 0x1f0ae,
- 0x1f0b1, 0x1f0bf,
- 0x1f0c1, 0x1f0cf,
- 0x1f0d1, 0x1f0f5,
- 0x1f100, 0x1f1ad,
- 0x1f1e6, 0x1f202,
- 0x1f210, 0x1f23b,
- 0x1f240, 0x1f248,
- 0x1f250, 0x1f251,
- 0x1f260, 0x1f265,
- 0x1f300, 0x1f6d7,
- 0x1f6dd, 0x1f6ec,
- 0x1f6f0, 0x1f6fc,
- 0x1f700, 0x1f773,
- 0x1f780, 0x1f7d8,
- 0x1f7e0, 0x1f7eb,
- 0x1f7f0, 0x1f7f0,
- 0x1f800, 0x1f80b,
- 0x1f810, 0x1f847,
- 0x1f850, 0x1f859,
- 0x1f860, 0x1f887,
- 0x1f890, 0x1f8ad,
- 0x1f8b0, 0x1f8b1,
- 0x1f900, 0x1fa53,
- 0x1fa60, 0x1fa6d,
- 0x1fa70, 0x1fa74,
- 0x1fa78, 0x1fa7c,
- 0x1fa80, 0x1fa86,
- 0x1fa90, 0x1faac,
- 0x1fab0, 0x1faba,
- 0x1fac0, 0x1fac5,
- 0x1fad0, 0x1fad9,
- 0x1fae0, 0x1fae7,
- 0x1faf0, 0x1faf6,
- 0x1fb00, 0x1fb92,
- 0x1fb94, 0x1fbca,
- 0x1fbf0, 0x1fbf9,
- 0x1fffe, 0x2a6df,
- 0x2a700, 0x2b738,
- 0x2b740, 0x2b81d,
- 0x2b820, 0x2cea1,
- 0x2ceb0, 0x2ebe0,
- 0x2f800, 0x2fa1d,
- 0x2fffe, 0x3134a,
- 0x3fffe, 0x3ffff,
- 0x4fffe, 0x4ffff,
- 0x5fffe, 0x5ffff,
- 0x6fffe, 0x6ffff,
- 0x7fffe, 0x7ffff,
- 0x8fffe, 0x8ffff,
- 0x9fffe, 0x9ffff,
- 0xafffe, 0xaffff,
- 0xbfffe, 0xbffff,
- 0xcfffe, 0xcffff,
- 0xdfffe, 0xdffff,
- 0xe0001, 0xe0001,
- 0xe0020, 0xe007f,
- 0xe0100, 0xe01ef,
- 0xefffe, 0x10ffff,
-}; /* CR_Age_14_0 */
-
-/* 'Age_15_0': Derived Age 15.0 */
-static const OnigCodePoint CR_Age_15_0[] = {
- 715,
- 0x0000, 0x0377,
- 0x037a, 0x037f,
- 0x0384, 0x038a,
- 0x038c, 0x038c,
- 0x038e, 0x03a1,
- 0x03a3, 0x052f,
- 0x0531, 0x0556,
- 0x0559, 0x058a,
- 0x058d, 0x058f,
- 0x0591, 0x05c7,
- 0x05d0, 0x05ea,
- 0x05ef, 0x05f4,
- 0x0600, 0x070d,
- 0x070f, 0x074a,
- 0x074d, 0x07b1,
- 0x07c0, 0x07fa,
- 0x07fd, 0x082d,
- 0x0830, 0x083e,
- 0x0840, 0x085b,
- 0x085e, 0x085e,
- 0x0860, 0x086a,
- 0x0870, 0x088e,
- 0x0890, 0x0891,
- 0x0898, 0x0983,
- 0x0985, 0x098c,
- 0x098f, 0x0990,
- 0x0993, 0x09a8,
- 0x09aa, 0x09b0,
- 0x09b2, 0x09b2,
- 0x09b6, 0x09b9,
- 0x09bc, 0x09c4,
- 0x09c7, 0x09c8,
- 0x09cb, 0x09ce,
- 0x09d7, 0x09d7,
- 0x09dc, 0x09dd,
- 0x09df, 0x09e3,
- 0x09e6, 0x09fe,
- 0x0a01, 0x0a03,
- 0x0a05, 0x0a0a,
- 0x0a0f, 0x0a10,
- 0x0a13, 0x0a28,
- 0x0a2a, 0x0a30,
- 0x0a32, 0x0a33,
- 0x0a35, 0x0a36,
- 0x0a38, 0x0a39,
- 0x0a3c, 0x0a3c,
- 0x0a3e, 0x0a42,
- 0x0a47, 0x0a48,
- 0x0a4b, 0x0a4d,
- 0x0a51, 0x0a51,
- 0x0a59, 0x0a5c,
- 0x0a5e, 0x0a5e,
- 0x0a66, 0x0a76,
- 0x0a81, 0x0a83,
- 0x0a85, 0x0a8d,
- 0x0a8f, 0x0a91,
- 0x0a93, 0x0aa8,
- 0x0aaa, 0x0ab0,
- 0x0ab2, 0x0ab3,
- 0x0ab5, 0x0ab9,
- 0x0abc, 0x0ac5,
- 0x0ac7, 0x0ac9,
- 0x0acb, 0x0acd,
- 0x0ad0, 0x0ad0,
- 0x0ae0, 0x0ae3,
- 0x0ae6, 0x0af1,
- 0x0af9, 0x0aff,
- 0x0b01, 0x0b03,
- 0x0b05, 0x0b0c,
- 0x0b0f, 0x0b10,
- 0x0b13, 0x0b28,
- 0x0b2a, 0x0b30,
- 0x0b32, 0x0b33,
- 0x0b35, 0x0b39,
- 0x0b3c, 0x0b44,
- 0x0b47, 0x0b48,
- 0x0b4b, 0x0b4d,
- 0x0b55, 0x0b57,
- 0x0b5c, 0x0b5d,
- 0x0b5f, 0x0b63,
- 0x0b66, 0x0b77,
- 0x0b82, 0x0b83,
- 0x0b85, 0x0b8a,
- 0x0b8e, 0x0b90,
- 0x0b92, 0x0b95,
- 0x0b99, 0x0b9a,
- 0x0b9c, 0x0b9c,
- 0x0b9e, 0x0b9f,
- 0x0ba3, 0x0ba4,
- 0x0ba8, 0x0baa,
- 0x0bae, 0x0bb9,
- 0x0bbe, 0x0bc2,
- 0x0bc6, 0x0bc8,
- 0x0bca, 0x0bcd,
- 0x0bd0, 0x0bd0,
- 0x0bd7, 0x0bd7,
- 0x0be6, 0x0bfa,
- 0x0c00, 0x0c0c,
- 0x0c0e, 0x0c10,
- 0x0c12, 0x0c28,
- 0x0c2a, 0x0c39,
- 0x0c3c, 0x0c44,
- 0x0c46, 0x0c48,
- 0x0c4a, 0x0c4d,
- 0x0c55, 0x0c56,
- 0x0c58, 0x0c5a,
- 0x0c5d, 0x0c5d,
- 0x0c60, 0x0c63,
- 0x0c66, 0x0c6f,
- 0x0c77, 0x0c8c,
- 0x0c8e, 0x0c90,
- 0x0c92, 0x0ca8,
- 0x0caa, 0x0cb3,
- 0x0cb5, 0x0cb9,
- 0x0cbc, 0x0cc4,
- 0x0cc6, 0x0cc8,
- 0x0cca, 0x0ccd,
- 0x0cd5, 0x0cd6,
- 0x0cdd, 0x0cde,
- 0x0ce0, 0x0ce3,
- 0x0ce6, 0x0cef,
- 0x0cf1, 0x0cf3,
- 0x0d00, 0x0d0c,
- 0x0d0e, 0x0d10,
- 0x0d12, 0x0d44,
- 0x0d46, 0x0d48,
- 0x0d4a, 0x0d4f,
- 0x0d54, 0x0d63,
- 0x0d66, 0x0d7f,
- 0x0d81, 0x0d83,
- 0x0d85, 0x0d96,
- 0x0d9a, 0x0db1,
- 0x0db3, 0x0dbb,
- 0x0dbd, 0x0dbd,
- 0x0dc0, 0x0dc6,
- 0x0dca, 0x0dca,
- 0x0dcf, 0x0dd4,
- 0x0dd6, 0x0dd6,
- 0x0dd8, 0x0ddf,
- 0x0de6, 0x0def,
- 0x0df2, 0x0df4,
- 0x0e01, 0x0e3a,
- 0x0e3f, 0x0e5b,
- 0x0e81, 0x0e82,
- 0x0e84, 0x0e84,
- 0x0e86, 0x0e8a,
- 0x0e8c, 0x0ea3,
- 0x0ea5, 0x0ea5,
- 0x0ea7, 0x0ebd,
- 0x0ec0, 0x0ec4,
- 0x0ec6, 0x0ec6,
- 0x0ec8, 0x0ece,
- 0x0ed0, 0x0ed9,
- 0x0edc, 0x0edf,
- 0x0f00, 0x0f47,
- 0x0f49, 0x0f6c,
- 0x0f71, 0x0f97,
- 0x0f99, 0x0fbc,
- 0x0fbe, 0x0fcc,
- 0x0fce, 0x0fda,
- 0x1000, 0x10c5,
- 0x10c7, 0x10c7,
- 0x10cd, 0x10cd,
- 0x10d0, 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,
- 0x135d, 0x137c,
- 0x1380, 0x1399,
- 0x13a0, 0x13f5,
- 0x13f8, 0x13fd,
- 0x1400, 0x169c,
- 0x16a0, 0x16f8,
- 0x1700, 0x1715,
- 0x171f, 0x1736,
- 0x1740, 0x1753,
- 0x1760, 0x176c,
- 0x176e, 0x1770,
- 0x1772, 0x1773,
- 0x1780, 0x17dd,
- 0x17e0, 0x17e9,
- 0x17f0, 0x17f9,
- 0x1800, 0x1819,
- 0x1820, 0x1878,
- 0x1880, 0x18aa,
- 0x18b0, 0x18f5,
- 0x1900, 0x191e,
- 0x1920, 0x192b,
- 0x1930, 0x193b,
- 0x1940, 0x1940,
- 0x1944, 0x196d,
- 0x1970, 0x1974,
- 0x1980, 0x19ab,
- 0x19b0, 0x19c9,
- 0x19d0, 0x19da,
- 0x19de, 0x1a1b,
- 0x1a1e, 0x1a5e,
- 0x1a60, 0x1a7c,
- 0x1a7f, 0x1a89,
- 0x1a90, 0x1a99,
- 0x1aa0, 0x1aad,
- 0x1ab0, 0x1ace,
- 0x1b00, 0x1b4c,
- 0x1b50, 0x1b7e,
- 0x1b80, 0x1bf3,
- 0x1bfc, 0x1c37,
- 0x1c3b, 0x1c49,
- 0x1c4d, 0x1c88,
- 0x1c90, 0x1cba,
- 0x1cbd, 0x1cc7,
- 0x1cd0, 0x1cfa,
- 0x1d00, 0x1f15,
- 0x1f18, 0x1f1d,
- 0x1f20, 0x1f45,
- 0x1f48, 0x1f4d,
- 0x1f50, 0x1f57,
- 0x1f59, 0x1f59,
- 0x1f5b, 0x1f5b,
- 0x1f5d, 0x1f5d,
- 0x1f5f, 0x1f7d,
- 0x1f80, 0x1fb4,
- 0x1fb6, 0x1fc4,
- 0x1fc6, 0x1fd3,
- 0x1fd6, 0x1fdb,
- 0x1fdd, 0x1fef,
- 0x1ff2, 0x1ff4,
- 0x1ff6, 0x1ffe,
- 0x2000, 0x2064,
- 0x2066, 0x2071,
- 0x2074, 0x208e,
- 0x2090, 0x209c,
- 0x20a0, 0x20c0,
- 0x20d0, 0x20f0,
- 0x2100, 0x218b,
- 0x2190, 0x2426,
- 0x2440, 0x244a,
- 0x2460, 0x2b73,
- 0x2b76, 0x2b95,
- 0x2b97, 0x2cf3,
- 0x2cf9, 0x2d25,
- 0x2d27, 0x2d27,
- 0x2d2d, 0x2d2d,
- 0x2d30, 0x2d67,
- 0x2d6f, 0x2d70,
- 0x2d7f, 0x2d96,
- 0x2da0, 0x2da6,
- 0x2da8, 0x2dae,
- 0x2db0, 0x2db6,
- 0x2db8, 0x2dbe,
- 0x2dc0, 0x2dc6,
- 0x2dc8, 0x2dce,
- 0x2dd0, 0x2dd6,
- 0x2dd8, 0x2dde,
- 0x2de0, 0x2e5d,
- 0x2e80, 0x2e99,
- 0x2e9b, 0x2ef3,
- 0x2f00, 0x2fd5,
- 0x2ff0, 0x2ffb,
- 0x3000, 0x303f,
- 0x3041, 0x3096,
- 0x3099, 0x30ff,
- 0x3105, 0x312f,
- 0x3131, 0x318e,
- 0x3190, 0x31e3,
- 0x31f0, 0x321e,
- 0x3220, 0xa48c,
- 0xa490, 0xa4c6,
- 0xa4d0, 0xa62b,
- 0xa640, 0xa6f7,
- 0xa700, 0xa7ca,
- 0xa7d0, 0xa7d1,
- 0xa7d3, 0xa7d3,
- 0xa7d5, 0xa7d9,
- 0xa7f2, 0xa82c,
- 0xa830, 0xa839,
- 0xa840, 0xa877,
- 0xa880, 0xa8c5,
- 0xa8ce, 0xa8d9,
- 0xa8e0, 0xa953,
- 0xa95f, 0xa97c,
- 0xa980, 0xa9cd,
- 0xa9cf, 0xa9d9,
- 0xa9de, 0xa9fe,
- 0xaa00, 0xaa36,
- 0xaa40, 0xaa4d,
- 0xaa50, 0xaa59,
- 0xaa5c, 0xaac2,
- 0xaadb, 0xaaf6,
- 0xab01, 0xab06,
- 0xab09, 0xab0e,
- 0xab11, 0xab16,
- 0xab20, 0xab26,
- 0xab28, 0xab2e,
- 0xab30, 0xab6b,
- 0xab70, 0xabed,
- 0xabf0, 0xabf9,
- 0xac00, 0xd7a3,
- 0xd7b0, 0xd7c6,
- 0xd7cb, 0xd7fb,
- 0xd800, 0xfa6d,
- 0xfa70, 0xfad9,
- 0xfb00, 0xfb06,
- 0xfb13, 0xfb17,
- 0xfb1d, 0xfb36,
- 0xfb38, 0xfb3c,
- 0xfb3e, 0xfb3e,
- 0xfb40, 0xfb41,
- 0xfb43, 0xfb44,
- 0xfb46, 0xfbc2,
- 0xfbd3, 0xfd8f,
- 0xfd92, 0xfdc7,
- 0xfdcf, 0xfe19,
- 0xfe20, 0xfe52,
- 0xfe54, 0xfe66,
- 0xfe68, 0xfe6b,
- 0xfe70, 0xfe74,
- 0xfe76, 0xfefc,
- 0xfeff, 0xfeff,
- 0xff01, 0xffbe,
- 0xffc2, 0xffc7,
- 0xffca, 0xffcf,
- 0xffd2, 0xffd7,
- 0xffda, 0xffdc,
- 0xffe0, 0xffe6,
- 0xffe8, 0xffee,
- 0xfff9, 0x1000b,
- 0x1000d, 0x10026,
- 0x10028, 0x1003a,
- 0x1003c, 0x1003d,
- 0x1003f, 0x1004d,
- 0x10050, 0x1005d,
- 0x10080, 0x100fa,
- 0x10100, 0x10102,
- 0x10107, 0x10133,
- 0x10137, 0x1018e,
- 0x10190, 0x1019c,
- 0x101a0, 0x101a0,
- 0x101d0, 0x101fd,
- 0x10280, 0x1029c,
- 0x102a0, 0x102d0,
- 0x102e0, 0x102fb,
- 0x10300, 0x10323,
- 0x1032d, 0x1034a,
- 0x10350, 0x1037a,
- 0x10380, 0x1039d,
- 0x1039f, 0x103c3,
- 0x103c8, 0x103d5,
- 0x10400, 0x1049d,
- 0x104a0, 0x104a9,
- 0x104b0, 0x104d3,
- 0x104d8, 0x104fb,
- 0x10500, 0x10527,
- 0x10530, 0x10563,
- 0x1056f, 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,
- 0x10857, 0x1089e,
- 0x108a7, 0x108af,
- 0x108e0, 0x108f2,
- 0x108f4, 0x108f5,
- 0x108fb, 0x1091b,
- 0x1091f, 0x10939,
- 0x1093f, 0x1093f,
- 0x10980, 0x109b7,
- 0x109bc, 0x109cf,
- 0x109d2, 0x10a03,
- 0x10a05, 0x10a06,
- 0x10a0c, 0x10a13,
- 0x10a15, 0x10a17,
- 0x10a19, 0x10a35,
- 0x10a38, 0x10a3a,
- 0x10a3f, 0x10a48,
- 0x10a50, 0x10a58,
- 0x10a60, 0x10a9f,
- 0x10ac0, 0x10ae6,
- 0x10aeb, 0x10af6,
- 0x10b00, 0x10b35,
- 0x10b39, 0x10b55,
- 0x10b58, 0x10b72,
- 0x10b78, 0x10b91,
- 0x10b99, 0x10b9c,
- 0x10ba9, 0x10baf,
- 0x10c00, 0x10c48,
- 0x10c80, 0x10cb2,
- 0x10cc0, 0x10cf2,
- 0x10cfa, 0x10d27,
- 0x10d30, 0x10d39,
- 0x10e60, 0x10e7e,
- 0x10e80, 0x10ea9,
- 0x10eab, 0x10ead,
- 0x10eb0, 0x10eb1,
- 0x10efd, 0x10f27,
- 0x10f30, 0x10f59,
- 0x10f70, 0x10f89,
- 0x10fb0, 0x10fcb,
- 0x10fe0, 0x10ff6,
- 0x11000, 0x1104d,
- 0x11052, 0x11075,
- 0x1107f, 0x110c2,
- 0x110cd, 0x110cd,
- 0x110d0, 0x110e8,
- 0x110f0, 0x110f9,
- 0x11100, 0x11134,
- 0x11136, 0x11147,
- 0x11150, 0x11176,
- 0x11180, 0x111df,
- 0x111e1, 0x111f4,
- 0x11200, 0x11211,
- 0x11213, 0x11241,
- 0x11280, 0x11286,
- 0x11288, 0x11288,
- 0x1128a, 0x1128d,
- 0x1128f, 0x1129d,
- 0x1129f, 0x112a9,
- 0x112b0, 0x112ea,
- 0x112f0, 0x112f9,
- 0x11300, 0x11303,
- 0x11305, 0x1130c,
- 0x1130f, 0x11310,
- 0x11313, 0x11328,
- 0x1132a, 0x11330,
- 0x11332, 0x11333,
- 0x11335, 0x11339,
- 0x1133b, 0x11344,
- 0x11347, 0x11348,
- 0x1134b, 0x1134d,
- 0x11350, 0x11350,
- 0x11357, 0x11357,
- 0x1135d, 0x11363,
- 0x11366, 0x1136c,
- 0x11370, 0x11374,
- 0x11400, 0x1145b,
- 0x1145d, 0x11461,
- 0x11480, 0x114c7,
- 0x114d0, 0x114d9,
- 0x11580, 0x115b5,
- 0x115b8, 0x115dd,
- 0x11600, 0x11644,
- 0x11650, 0x11659,
- 0x11660, 0x1166c,
- 0x11680, 0x116b9,
- 0x116c0, 0x116c9,
- 0x11700, 0x1171a,
- 0x1171d, 0x1172b,
- 0x11730, 0x11746,
- 0x11800, 0x1183b,
- 0x118a0, 0x118f2,
- 0x118ff, 0x11906,
- 0x11909, 0x11909,
- 0x1190c, 0x11913,
- 0x11915, 0x11916,
- 0x11918, 0x11935,
- 0x11937, 0x11938,
- 0x1193b, 0x11946,
- 0x11950, 0x11959,
- 0x119a0, 0x119a7,
- 0x119aa, 0x119d7,
- 0x119da, 0x119e4,
- 0x11a00, 0x11a47,
- 0x11a50, 0x11aa2,
- 0x11ab0, 0x11af8,
- 0x11b00, 0x11b09,
- 0x11c00, 0x11c08,
- 0x11c0a, 0x11c36,
- 0x11c38, 0x11c45,
- 0x11c50, 0x11c6c,
- 0x11c70, 0x11c8f,
- 0x11c92, 0x11ca7,
- 0x11ca9, 0x11cb6,
- 0x11d00, 0x11d06,
- 0x11d08, 0x11d09,
- 0x11d0b, 0x11d36,
- 0x11d3a, 0x11d3a,
- 0x11d3c, 0x11d3d,
- 0x11d3f, 0x11d47,
- 0x11d50, 0x11d59,
- 0x11d60, 0x11d65,
- 0x11d67, 0x11d68,
- 0x11d6a, 0x11d8e,
- 0x11d90, 0x11d91,
- 0x11d93, 0x11d98,
- 0x11da0, 0x11da9,
- 0x11ee0, 0x11ef8,
- 0x11f00, 0x11f10,
- 0x11f12, 0x11f3a,
- 0x11f3e, 0x11f59,
- 0x11fb0, 0x11fb0,
- 0x11fc0, 0x11ff1,
- 0x11fff, 0x12399,
- 0x12400, 0x1246e,
- 0x12470, 0x12474,
- 0x12480, 0x12543,
- 0x12f90, 0x12ff2,
- 0x13000, 0x13455,
- 0x14400, 0x14646,
- 0x16800, 0x16a38,
- 0x16a40, 0x16a5e,
- 0x16a60, 0x16a69,
- 0x16a6e, 0x16abe,
- 0x16ac0, 0x16ac9,
- 0x16ad0, 0x16aed,
- 0x16af0, 0x16af5,
- 0x16b00, 0x16b45,
- 0x16b50, 0x16b59,
- 0x16b5b, 0x16b61,
- 0x16b63, 0x16b77,
- 0x16b7d, 0x16b8f,
- 0x16e40, 0x16e9a,
- 0x16f00, 0x16f4a,
- 0x16f4f, 0x16f87,
- 0x16f8f, 0x16f9f,
- 0x16fe0, 0x16fe4,
- 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,
- 0x1bc9c, 0x1bca3,
- 0x1cf00, 0x1cf2d,
- 0x1cf30, 0x1cf46,
- 0x1cf50, 0x1cfc3,
- 0x1d000, 0x1d0f5,
- 0x1d100, 0x1d126,
- 0x1d129, 0x1d1ea,
- 0x1d200, 0x1d245,
- 0x1d2c0, 0x1d2d3,
- 0x1d2e0, 0x1d2f3,
- 0x1d300, 0x1d356,
- 0x1d360, 0x1d378,
- 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, 0x1d7cb,
- 0x1d7ce, 0x1da8b,
- 0x1da9b, 0x1da9f,
- 0x1daa1, 0x1daaf,
- 0x1df00, 0x1df1e,
- 0x1df25, 0x1df2a,
- 0x1e000, 0x1e006,
- 0x1e008, 0x1e018,
- 0x1e01b, 0x1e021,
- 0x1e023, 0x1e024,
- 0x1e026, 0x1e02a,
- 0x1e030, 0x1e06d,
- 0x1e08f, 0x1e08f,
- 0x1e100, 0x1e12c,
- 0x1e130, 0x1e13d,
- 0x1e140, 0x1e149,
- 0x1e14e, 0x1e14f,
- 0x1e290, 0x1e2ae,
- 0x1e2c0, 0x1e2f9,
- 0x1e2ff, 0x1e2ff,
- 0x1e4d0, 0x1e4f9,
- 0x1e7e0, 0x1e7e6,
- 0x1e7e8, 0x1e7eb,
- 0x1e7ed, 0x1e7ee,
- 0x1e7f0, 0x1e7fe,
- 0x1e800, 0x1e8c4,
- 0x1e8c7, 0x1e8d6,
- 0x1e900, 0x1e94b,
- 0x1e950, 0x1e959,
- 0x1e95e, 0x1e95f,
- 0x1ec71, 0x1ecb4,
- 0x1ed01, 0x1ed3d,
- 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,
- 0x1eef0, 0x1eef1,
- 0x1f000, 0x1f02b,
- 0x1f030, 0x1f093,
- 0x1f0a0, 0x1f0ae,
- 0x1f0b1, 0x1f0bf,
- 0x1f0c1, 0x1f0cf,
- 0x1f0d1, 0x1f0f5,
- 0x1f100, 0x1f1ad,
- 0x1f1e6, 0x1f202,
- 0x1f210, 0x1f23b,
- 0x1f240, 0x1f248,
- 0x1f250, 0x1f251,
- 0x1f260, 0x1f265,
- 0x1f300, 0x1f6d7,
- 0x1f6dc, 0x1f6ec,
- 0x1f6f0, 0x1f6fc,
- 0x1f700, 0x1f776,
- 0x1f77b, 0x1f7d9,
- 0x1f7e0, 0x1f7eb,
- 0x1f7f0, 0x1f7f0,
- 0x1f800, 0x1f80b,
- 0x1f810, 0x1f847,
- 0x1f850, 0x1f859,
- 0x1f860, 0x1f887,
- 0x1f890, 0x1f8ad,
- 0x1f8b0, 0x1f8b1,
- 0x1f900, 0x1fa53,
- 0x1fa60, 0x1fa6d,
- 0x1fa70, 0x1fa7c,
- 0x1fa80, 0x1fa88,
- 0x1fa90, 0x1fabd,
- 0x1fabf, 0x1fac5,
- 0x1face, 0x1fadb,
- 0x1fae0, 0x1fae8,
- 0x1faf0, 0x1faf8,
- 0x1fb00, 0x1fb92,
- 0x1fb94, 0x1fbca,
- 0x1fbf0, 0x1fbf9,
- 0x1fffe, 0x2a6df,
- 0x2a700, 0x2b739,
- 0x2b740, 0x2b81d,
- 0x2b820, 0x2cea1,
- 0x2ceb0, 0x2ebe0,
- 0x2f800, 0x2fa1d,
- 0x2fffe, 0x3134a,
- 0x31350, 0x323af,
- 0x3fffe, 0x3ffff,
- 0x4fffe, 0x4ffff,
- 0x5fffe, 0x5ffff,
- 0x6fffe, 0x6ffff,
- 0x7fffe, 0x7ffff,
- 0x8fffe, 0x8ffff,
- 0x9fffe, 0x9ffff,
- 0xafffe, 0xaffff,
- 0xbfffe, 0xbffff,
- 0xcfffe, 0xcffff,
- 0xdfffe, 0xdffff,
- 0xe0001, 0xe0001,
- 0xe0020, 0xe007f,
- 0xe0100, 0xe01ef,
- 0xefffe, 0x10ffff,
-}; /* CR_Age_15_0 */
-
-/* 'Age_15_1': Derived Age 15.1 */
-static const OnigCodePoint CR_Age_15_1[] = {
- 715,
- 0x0000, 0x0377,
- 0x037a, 0x037f,
- 0x0384, 0x038a,
- 0x038c, 0x038c,
- 0x038e, 0x03a1,
- 0x03a3, 0x052f,
- 0x0531, 0x0556,
- 0x0559, 0x058a,
- 0x058d, 0x058f,
- 0x0591, 0x05c7,
- 0x05d0, 0x05ea,
- 0x05ef, 0x05f4,
- 0x0600, 0x070d,
- 0x070f, 0x074a,
- 0x074d, 0x07b1,
- 0x07c0, 0x07fa,
- 0x07fd, 0x082d,
- 0x0830, 0x083e,
- 0x0840, 0x085b,
- 0x085e, 0x085e,
- 0x0860, 0x086a,
- 0x0870, 0x088e,
- 0x0890, 0x0891,
- 0x0898, 0x0983,
- 0x0985, 0x098c,
- 0x098f, 0x0990,
- 0x0993, 0x09a8,
- 0x09aa, 0x09b0,
- 0x09b2, 0x09b2,
- 0x09b6, 0x09b9,
- 0x09bc, 0x09c4,
- 0x09c7, 0x09c8,
- 0x09cb, 0x09ce,
- 0x09d7, 0x09d7,
- 0x09dc, 0x09dd,
- 0x09df, 0x09e3,
- 0x09e6, 0x09fe,
- 0x0a01, 0x0a03,
- 0x0a05, 0x0a0a,
- 0x0a0f, 0x0a10,
- 0x0a13, 0x0a28,
- 0x0a2a, 0x0a30,
- 0x0a32, 0x0a33,
- 0x0a35, 0x0a36,
- 0x0a38, 0x0a39,
- 0x0a3c, 0x0a3c,
- 0x0a3e, 0x0a42,
- 0x0a47, 0x0a48,
- 0x0a4b, 0x0a4d,
- 0x0a51, 0x0a51,
- 0x0a59, 0x0a5c,
- 0x0a5e, 0x0a5e,
- 0x0a66, 0x0a76,
- 0x0a81, 0x0a83,
- 0x0a85, 0x0a8d,
- 0x0a8f, 0x0a91,
- 0x0a93, 0x0aa8,
- 0x0aaa, 0x0ab0,
- 0x0ab2, 0x0ab3,
- 0x0ab5, 0x0ab9,
- 0x0abc, 0x0ac5,
- 0x0ac7, 0x0ac9,
- 0x0acb, 0x0acd,
- 0x0ad0, 0x0ad0,
- 0x0ae0, 0x0ae3,
- 0x0ae6, 0x0af1,
- 0x0af9, 0x0aff,
- 0x0b01, 0x0b03,
- 0x0b05, 0x0b0c,
- 0x0b0f, 0x0b10,
- 0x0b13, 0x0b28,
- 0x0b2a, 0x0b30,
- 0x0b32, 0x0b33,
- 0x0b35, 0x0b39,
- 0x0b3c, 0x0b44,
- 0x0b47, 0x0b48,
- 0x0b4b, 0x0b4d,
- 0x0b55, 0x0b57,
- 0x0b5c, 0x0b5d,
- 0x0b5f, 0x0b63,
- 0x0b66, 0x0b77,
- 0x0b82, 0x0b83,
- 0x0b85, 0x0b8a,
- 0x0b8e, 0x0b90,
- 0x0b92, 0x0b95,
- 0x0b99, 0x0b9a,
- 0x0b9c, 0x0b9c,
- 0x0b9e, 0x0b9f,
- 0x0ba3, 0x0ba4,
- 0x0ba8, 0x0baa,
- 0x0bae, 0x0bb9,
- 0x0bbe, 0x0bc2,
- 0x0bc6, 0x0bc8,
- 0x0bca, 0x0bcd,
- 0x0bd0, 0x0bd0,
- 0x0bd7, 0x0bd7,
- 0x0be6, 0x0bfa,
- 0x0c00, 0x0c0c,
- 0x0c0e, 0x0c10,
- 0x0c12, 0x0c28,
- 0x0c2a, 0x0c39,
- 0x0c3c, 0x0c44,
- 0x0c46, 0x0c48,
- 0x0c4a, 0x0c4d,
- 0x0c55, 0x0c56,
- 0x0c58, 0x0c5a,
- 0x0c5d, 0x0c5d,
- 0x0c60, 0x0c63,
- 0x0c66, 0x0c6f,
- 0x0c77, 0x0c8c,
- 0x0c8e, 0x0c90,
- 0x0c92, 0x0ca8,
- 0x0caa, 0x0cb3,
- 0x0cb5, 0x0cb9,
- 0x0cbc, 0x0cc4,
- 0x0cc6, 0x0cc8,
- 0x0cca, 0x0ccd,
- 0x0cd5, 0x0cd6,
- 0x0cdd, 0x0cde,
- 0x0ce0, 0x0ce3,
- 0x0ce6, 0x0cef,
- 0x0cf1, 0x0cf3,
- 0x0d00, 0x0d0c,
- 0x0d0e, 0x0d10,
- 0x0d12, 0x0d44,
- 0x0d46, 0x0d48,
- 0x0d4a, 0x0d4f,
- 0x0d54, 0x0d63,
- 0x0d66, 0x0d7f,
- 0x0d81, 0x0d83,
- 0x0d85, 0x0d96,
- 0x0d9a, 0x0db1,
- 0x0db3, 0x0dbb,
- 0x0dbd, 0x0dbd,
- 0x0dc0, 0x0dc6,
- 0x0dca, 0x0dca,
- 0x0dcf, 0x0dd4,
- 0x0dd6, 0x0dd6,
- 0x0dd8, 0x0ddf,
- 0x0de6, 0x0def,
- 0x0df2, 0x0df4,
- 0x0e01, 0x0e3a,
- 0x0e3f, 0x0e5b,
- 0x0e81, 0x0e82,
- 0x0e84, 0x0e84,
- 0x0e86, 0x0e8a,
- 0x0e8c, 0x0ea3,
- 0x0ea5, 0x0ea5,
- 0x0ea7, 0x0ebd,
- 0x0ec0, 0x0ec4,
- 0x0ec6, 0x0ec6,
- 0x0ec8, 0x0ece,
- 0x0ed0, 0x0ed9,
- 0x0edc, 0x0edf,
- 0x0f00, 0x0f47,
- 0x0f49, 0x0f6c,
- 0x0f71, 0x0f97,
- 0x0f99, 0x0fbc,
- 0x0fbe, 0x0fcc,
- 0x0fce, 0x0fda,
- 0x1000, 0x10c5,
- 0x10c7, 0x10c7,
- 0x10cd, 0x10cd,
- 0x10d0, 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,
- 0x135d, 0x137c,
- 0x1380, 0x1399,
- 0x13a0, 0x13f5,
- 0x13f8, 0x13fd,
- 0x1400, 0x169c,
- 0x16a0, 0x16f8,
- 0x1700, 0x1715,
- 0x171f, 0x1736,
- 0x1740, 0x1753,
- 0x1760, 0x176c,
- 0x176e, 0x1770,
- 0x1772, 0x1773,
- 0x1780, 0x17dd,
- 0x17e0, 0x17e9,
- 0x17f0, 0x17f9,
- 0x1800, 0x1819,
- 0x1820, 0x1878,
- 0x1880, 0x18aa,
- 0x18b0, 0x18f5,
- 0x1900, 0x191e,
- 0x1920, 0x192b,
- 0x1930, 0x193b,
- 0x1940, 0x1940,
- 0x1944, 0x196d,
- 0x1970, 0x1974,
- 0x1980, 0x19ab,
- 0x19b0, 0x19c9,
- 0x19d0, 0x19da,
- 0x19de, 0x1a1b,
- 0x1a1e, 0x1a5e,
- 0x1a60, 0x1a7c,
- 0x1a7f, 0x1a89,
- 0x1a90, 0x1a99,
- 0x1aa0, 0x1aad,
- 0x1ab0, 0x1ace,
- 0x1b00, 0x1b4c,
- 0x1b50, 0x1b7e,
- 0x1b80, 0x1bf3,
- 0x1bfc, 0x1c37,
- 0x1c3b, 0x1c49,
- 0x1c4d, 0x1c88,
- 0x1c90, 0x1cba,
- 0x1cbd, 0x1cc7,
- 0x1cd0, 0x1cfa,
- 0x1d00, 0x1f15,
- 0x1f18, 0x1f1d,
- 0x1f20, 0x1f45,
- 0x1f48, 0x1f4d,
- 0x1f50, 0x1f57,
- 0x1f59, 0x1f59,
- 0x1f5b, 0x1f5b,
- 0x1f5d, 0x1f5d,
- 0x1f5f, 0x1f7d,
- 0x1f80, 0x1fb4,
- 0x1fb6, 0x1fc4,
- 0x1fc6, 0x1fd3,
- 0x1fd6, 0x1fdb,
- 0x1fdd, 0x1fef,
- 0x1ff2, 0x1ff4,
- 0x1ff6, 0x1ffe,
- 0x2000, 0x2064,
- 0x2066, 0x2071,
- 0x2074, 0x208e,
- 0x2090, 0x209c,
- 0x20a0, 0x20c0,
- 0x20d0, 0x20f0,
- 0x2100, 0x218b,
- 0x2190, 0x2426,
- 0x2440, 0x244a,
- 0x2460, 0x2b73,
- 0x2b76, 0x2b95,
- 0x2b97, 0x2cf3,
- 0x2cf9, 0x2d25,
- 0x2d27, 0x2d27,
- 0x2d2d, 0x2d2d,
- 0x2d30, 0x2d67,
- 0x2d6f, 0x2d70,
- 0x2d7f, 0x2d96,
- 0x2da0, 0x2da6,
- 0x2da8, 0x2dae,
- 0x2db0, 0x2db6,
- 0x2db8, 0x2dbe,
- 0x2dc0, 0x2dc6,
- 0x2dc8, 0x2dce,
- 0x2dd0, 0x2dd6,
- 0x2dd8, 0x2dde,
- 0x2de0, 0x2e5d,
- 0x2e80, 0x2e99,
- 0x2e9b, 0x2ef3,
- 0x2f00, 0x2fd5,
- 0x2ff0, 0x303f,
- 0x3041, 0x3096,
- 0x3099, 0x30ff,
- 0x3105, 0x312f,
- 0x3131, 0x318e,
- 0x3190, 0x31e3,
- 0x31ef, 0x321e,
- 0x3220, 0xa48c,
- 0xa490, 0xa4c6,
- 0xa4d0, 0xa62b,
- 0xa640, 0xa6f7,
- 0xa700, 0xa7ca,
- 0xa7d0, 0xa7d1,
- 0xa7d3, 0xa7d3,
- 0xa7d5, 0xa7d9,
- 0xa7f2, 0xa82c,
- 0xa830, 0xa839,
- 0xa840, 0xa877,
- 0xa880, 0xa8c5,
- 0xa8ce, 0xa8d9,
- 0xa8e0, 0xa953,
- 0xa95f, 0xa97c,
- 0xa980, 0xa9cd,
- 0xa9cf, 0xa9d9,
- 0xa9de, 0xa9fe,
- 0xaa00, 0xaa36,
- 0xaa40, 0xaa4d,
- 0xaa50, 0xaa59,
- 0xaa5c, 0xaac2,
- 0xaadb, 0xaaf6,
- 0xab01, 0xab06,
- 0xab09, 0xab0e,
- 0xab11, 0xab16,
- 0xab20, 0xab26,
- 0xab28, 0xab2e,
- 0xab30, 0xab6b,
- 0xab70, 0xabed,
- 0xabf0, 0xabf9,
- 0xac00, 0xd7a3,
- 0xd7b0, 0xd7c6,
- 0xd7cb, 0xd7fb,
- 0xd800, 0xfa6d,
- 0xfa70, 0xfad9,
- 0xfb00, 0xfb06,
- 0xfb13, 0xfb17,
- 0xfb1d, 0xfb36,
- 0xfb38, 0xfb3c,
- 0xfb3e, 0xfb3e,
- 0xfb40, 0xfb41,
- 0xfb43, 0xfb44,
- 0xfb46, 0xfbc2,
- 0xfbd3, 0xfd8f,
- 0xfd92, 0xfdc7,
- 0xfdcf, 0xfe19,
- 0xfe20, 0xfe52,
- 0xfe54, 0xfe66,
- 0xfe68, 0xfe6b,
- 0xfe70, 0xfe74,
- 0xfe76, 0xfefc,
- 0xfeff, 0xfeff,
- 0xff01, 0xffbe,
- 0xffc2, 0xffc7,
- 0xffca, 0xffcf,
- 0xffd2, 0xffd7,
- 0xffda, 0xffdc,
- 0xffe0, 0xffe6,
- 0xffe8, 0xffee,
- 0xfff9, 0x1000b,
- 0x1000d, 0x10026,
- 0x10028, 0x1003a,
- 0x1003c, 0x1003d,
- 0x1003f, 0x1004d,
- 0x10050, 0x1005d,
- 0x10080, 0x100fa,
- 0x10100, 0x10102,
- 0x10107, 0x10133,
- 0x10137, 0x1018e,
- 0x10190, 0x1019c,
- 0x101a0, 0x101a0,
- 0x101d0, 0x101fd,
- 0x10280, 0x1029c,
- 0x102a0, 0x102d0,
- 0x102e0, 0x102fb,
- 0x10300, 0x10323,
- 0x1032d, 0x1034a,
- 0x10350, 0x1037a,
- 0x10380, 0x1039d,
- 0x1039f, 0x103c3,
- 0x103c8, 0x103d5,
- 0x10400, 0x1049d,
- 0x104a0, 0x104a9,
- 0x104b0, 0x104d3,
- 0x104d8, 0x104fb,
- 0x10500, 0x10527,
- 0x10530, 0x10563,
- 0x1056f, 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,
- 0x10857, 0x1089e,
- 0x108a7, 0x108af,
- 0x108e0, 0x108f2,
- 0x108f4, 0x108f5,
- 0x108fb, 0x1091b,
- 0x1091f, 0x10939,
- 0x1093f, 0x1093f,
- 0x10980, 0x109b7,
- 0x109bc, 0x109cf,
- 0x109d2, 0x10a03,
- 0x10a05, 0x10a06,
- 0x10a0c, 0x10a13,
- 0x10a15, 0x10a17,
- 0x10a19, 0x10a35,
- 0x10a38, 0x10a3a,
- 0x10a3f, 0x10a48,
- 0x10a50, 0x10a58,
- 0x10a60, 0x10a9f,
- 0x10ac0, 0x10ae6,
- 0x10aeb, 0x10af6,
- 0x10b00, 0x10b35,
- 0x10b39, 0x10b55,
- 0x10b58, 0x10b72,
- 0x10b78, 0x10b91,
- 0x10b99, 0x10b9c,
- 0x10ba9, 0x10baf,
- 0x10c00, 0x10c48,
- 0x10c80, 0x10cb2,
- 0x10cc0, 0x10cf2,
- 0x10cfa, 0x10d27,
- 0x10d30, 0x10d39,
- 0x10e60, 0x10e7e,
- 0x10e80, 0x10ea9,
- 0x10eab, 0x10ead,
- 0x10eb0, 0x10eb1,
- 0x10efd, 0x10f27,
- 0x10f30, 0x10f59,
- 0x10f70, 0x10f89,
- 0x10fb0, 0x10fcb,
- 0x10fe0, 0x10ff6,
- 0x11000, 0x1104d,
- 0x11052, 0x11075,
- 0x1107f, 0x110c2,
- 0x110cd, 0x110cd,
- 0x110d0, 0x110e8,
- 0x110f0, 0x110f9,
- 0x11100, 0x11134,
- 0x11136, 0x11147,
- 0x11150, 0x11176,
- 0x11180, 0x111df,
- 0x111e1, 0x111f4,
- 0x11200, 0x11211,
- 0x11213, 0x11241,
- 0x11280, 0x11286,
- 0x11288, 0x11288,
- 0x1128a, 0x1128d,
- 0x1128f, 0x1129d,
- 0x1129f, 0x112a9,
- 0x112b0, 0x112ea,
- 0x112f0, 0x112f9,
- 0x11300, 0x11303,
- 0x11305, 0x1130c,
- 0x1130f, 0x11310,
- 0x11313, 0x11328,
- 0x1132a, 0x11330,
- 0x11332, 0x11333,
- 0x11335, 0x11339,
- 0x1133b, 0x11344,
- 0x11347, 0x11348,
- 0x1134b, 0x1134d,
- 0x11350, 0x11350,
- 0x11357, 0x11357,
- 0x1135d, 0x11363,
- 0x11366, 0x1136c,
- 0x11370, 0x11374,
- 0x11400, 0x1145b,
- 0x1145d, 0x11461,
- 0x11480, 0x114c7,
- 0x114d0, 0x114d9,
- 0x11580, 0x115b5,
- 0x115b8, 0x115dd,
- 0x11600, 0x11644,
- 0x11650, 0x11659,
- 0x11660, 0x1166c,
- 0x11680, 0x116b9,
- 0x116c0, 0x116c9,
- 0x11700, 0x1171a,
- 0x1171d, 0x1172b,
- 0x11730, 0x11746,
- 0x11800, 0x1183b,
- 0x118a0, 0x118f2,
- 0x118ff, 0x11906,
- 0x11909, 0x11909,
- 0x1190c, 0x11913,
- 0x11915, 0x11916,
- 0x11918, 0x11935,
- 0x11937, 0x11938,
- 0x1193b, 0x11946,
- 0x11950, 0x11959,
- 0x119a0, 0x119a7,
- 0x119aa, 0x119d7,
- 0x119da, 0x119e4,
- 0x11a00, 0x11a47,
- 0x11a50, 0x11aa2,
- 0x11ab0, 0x11af8,
- 0x11b00, 0x11b09,
- 0x11c00, 0x11c08,
- 0x11c0a, 0x11c36,
- 0x11c38, 0x11c45,
- 0x11c50, 0x11c6c,
- 0x11c70, 0x11c8f,
- 0x11c92, 0x11ca7,
- 0x11ca9, 0x11cb6,
- 0x11d00, 0x11d06,
- 0x11d08, 0x11d09,
- 0x11d0b, 0x11d36,
- 0x11d3a, 0x11d3a,
- 0x11d3c, 0x11d3d,
- 0x11d3f, 0x11d47,
- 0x11d50, 0x11d59,
- 0x11d60, 0x11d65,
- 0x11d67, 0x11d68,
- 0x11d6a, 0x11d8e,
- 0x11d90, 0x11d91,
- 0x11d93, 0x11d98,
- 0x11da0, 0x11da9,
- 0x11ee0, 0x11ef8,
- 0x11f00, 0x11f10,
- 0x11f12, 0x11f3a,
- 0x11f3e, 0x11f59,
- 0x11fb0, 0x11fb0,
- 0x11fc0, 0x11ff1,
- 0x11fff, 0x12399,
- 0x12400, 0x1246e,
- 0x12470, 0x12474,
- 0x12480, 0x12543,
- 0x12f90, 0x12ff2,
- 0x13000, 0x13455,
- 0x14400, 0x14646,
- 0x16800, 0x16a38,
- 0x16a40, 0x16a5e,
- 0x16a60, 0x16a69,
- 0x16a6e, 0x16abe,
- 0x16ac0, 0x16ac9,
- 0x16ad0, 0x16aed,
- 0x16af0, 0x16af5,
- 0x16b00, 0x16b45,
- 0x16b50, 0x16b59,
- 0x16b5b, 0x16b61,
- 0x16b63, 0x16b77,
- 0x16b7d, 0x16b8f,
- 0x16e40, 0x16e9a,
- 0x16f00, 0x16f4a,
- 0x16f4f, 0x16f87,
- 0x16f8f, 0x16f9f,
- 0x16fe0, 0x16fe4,
- 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,
- 0x1bc9c, 0x1bca3,
- 0x1cf00, 0x1cf2d,
- 0x1cf30, 0x1cf46,
- 0x1cf50, 0x1cfc3,
- 0x1d000, 0x1d0f5,
- 0x1d100, 0x1d126,
- 0x1d129, 0x1d1ea,
- 0x1d200, 0x1d245,
- 0x1d2c0, 0x1d2d3,
- 0x1d2e0, 0x1d2f3,
- 0x1d300, 0x1d356,
- 0x1d360, 0x1d378,
- 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, 0x1d7cb,
- 0x1d7ce, 0x1da8b,
- 0x1da9b, 0x1da9f,
- 0x1daa1, 0x1daaf,
- 0x1df00, 0x1df1e,
- 0x1df25, 0x1df2a,
- 0x1e000, 0x1e006,
- 0x1e008, 0x1e018,
- 0x1e01b, 0x1e021,
- 0x1e023, 0x1e024,
- 0x1e026, 0x1e02a,
- 0x1e030, 0x1e06d,
- 0x1e08f, 0x1e08f,
- 0x1e100, 0x1e12c,
- 0x1e130, 0x1e13d,
- 0x1e140, 0x1e149,
- 0x1e14e, 0x1e14f,
- 0x1e290, 0x1e2ae,
- 0x1e2c0, 0x1e2f9,
- 0x1e2ff, 0x1e2ff,
- 0x1e4d0, 0x1e4f9,
- 0x1e7e0, 0x1e7e6,
- 0x1e7e8, 0x1e7eb,
- 0x1e7ed, 0x1e7ee,
- 0x1e7f0, 0x1e7fe,
- 0x1e800, 0x1e8c4,
- 0x1e8c7, 0x1e8d6,
- 0x1e900, 0x1e94b,
- 0x1e950, 0x1e959,
- 0x1e95e, 0x1e95f,
- 0x1ec71, 0x1ecb4,
- 0x1ed01, 0x1ed3d,
- 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,
- 0x1eef0, 0x1eef1,
- 0x1f000, 0x1f02b,
- 0x1f030, 0x1f093,
- 0x1f0a0, 0x1f0ae,
- 0x1f0b1, 0x1f0bf,
- 0x1f0c1, 0x1f0cf,
- 0x1f0d1, 0x1f0f5,
- 0x1f100, 0x1f1ad,
- 0x1f1e6, 0x1f202,
- 0x1f210, 0x1f23b,
- 0x1f240, 0x1f248,
- 0x1f250, 0x1f251,
- 0x1f260, 0x1f265,
- 0x1f300, 0x1f6d7,
- 0x1f6dc, 0x1f6ec,
- 0x1f6f0, 0x1f6fc,
- 0x1f700, 0x1f776,
- 0x1f77b, 0x1f7d9,
- 0x1f7e0, 0x1f7eb,
- 0x1f7f0, 0x1f7f0,
- 0x1f800, 0x1f80b,
- 0x1f810, 0x1f847,
- 0x1f850, 0x1f859,
- 0x1f860, 0x1f887,
- 0x1f890, 0x1f8ad,
- 0x1f8b0, 0x1f8b1,
- 0x1f900, 0x1fa53,
- 0x1fa60, 0x1fa6d,
- 0x1fa70, 0x1fa7c,
- 0x1fa80, 0x1fa88,
- 0x1fa90, 0x1fabd,
- 0x1fabf, 0x1fac5,
- 0x1face, 0x1fadb,
- 0x1fae0, 0x1fae8,
- 0x1faf0, 0x1faf8,
- 0x1fb00, 0x1fb92,
- 0x1fb94, 0x1fbca,
- 0x1fbf0, 0x1fbf9,
- 0x1fffe, 0x2a6df,
- 0x2a700, 0x2b739,
- 0x2b740, 0x2b81d,
- 0x2b820, 0x2cea1,
- 0x2ceb0, 0x2ebe0,
- 0x2ebf0, 0x2ee5d,
- 0x2f800, 0x2fa1d,
- 0x2fffe, 0x3134a,
- 0x31350, 0x323af,
- 0x3fffe, 0x3ffff,
- 0x4fffe, 0x4ffff,
- 0x5fffe, 0x5ffff,
- 0x6fffe, 0x6ffff,
- 0x7fffe, 0x7ffff,
- 0x8fffe, 0x8ffff,
- 0x9fffe, 0x9ffff,
- 0xafffe, 0xaffff,
- 0xbfffe, 0xbffff,
- 0xcfffe, 0xcffff,
- 0xdfffe, 0xdffff,
- 0xe0001, 0xe0001,
- 0xe0020, 0xe007f,
- 0xe0100, 0xe01ef,
- 0xefffe, 0x10ffff,
-}; /* CR_Age_15_1 */
-
-/* 'Age_16_0': Derived Age 16.0 */
-static const OnigCodePoint CR_Age_16_0[] = {
- 739,
- 0x0000, 0x0377,
- 0x037a, 0x037f,
- 0x0384, 0x038a,
- 0x038c, 0x038c,
- 0x038e, 0x03a1,
- 0x03a3, 0x052f,
- 0x0531, 0x0556,
- 0x0559, 0x058a,
- 0x058d, 0x058f,
- 0x0591, 0x05c7,
- 0x05d0, 0x05ea,
- 0x05ef, 0x05f4,
- 0x0600, 0x070d,
- 0x070f, 0x074a,
- 0x074d, 0x07b1,
- 0x07c0, 0x07fa,
- 0x07fd, 0x082d,
- 0x0830, 0x083e,
- 0x0840, 0x085b,
- 0x085e, 0x085e,
- 0x0860, 0x086a,
- 0x0870, 0x088e,
- 0x0890, 0x0891,
- 0x0897, 0x0983,
- 0x0985, 0x098c,
- 0x098f, 0x0990,
- 0x0993, 0x09a8,
- 0x09aa, 0x09b0,
- 0x09b2, 0x09b2,
- 0x09b6, 0x09b9,
- 0x09bc, 0x09c4,
- 0x09c7, 0x09c8,
- 0x09cb, 0x09ce,
- 0x09d7, 0x09d7,
- 0x09dc, 0x09dd,
- 0x09df, 0x09e3,
- 0x09e6, 0x09fe,
- 0x0a01, 0x0a03,
- 0x0a05, 0x0a0a,
- 0x0a0f, 0x0a10,
- 0x0a13, 0x0a28,
- 0x0a2a, 0x0a30,
- 0x0a32, 0x0a33,
- 0x0a35, 0x0a36,
- 0x0a38, 0x0a39,
- 0x0a3c, 0x0a3c,
- 0x0a3e, 0x0a42,
- 0x0a47, 0x0a48,
- 0x0a4b, 0x0a4d,
- 0x0a51, 0x0a51,
- 0x0a59, 0x0a5c,
- 0x0a5e, 0x0a5e,
- 0x0a66, 0x0a76,
- 0x0a81, 0x0a83,
- 0x0a85, 0x0a8d,
- 0x0a8f, 0x0a91,
- 0x0a93, 0x0aa8,
- 0x0aaa, 0x0ab0,
- 0x0ab2, 0x0ab3,
- 0x0ab5, 0x0ab9,
- 0x0abc, 0x0ac5,
- 0x0ac7, 0x0ac9,
- 0x0acb, 0x0acd,
- 0x0ad0, 0x0ad0,
- 0x0ae0, 0x0ae3,
- 0x0ae6, 0x0af1,
- 0x0af9, 0x0aff,
- 0x0b01, 0x0b03,
- 0x0b05, 0x0b0c,
- 0x0b0f, 0x0b10,
- 0x0b13, 0x0b28,
- 0x0b2a, 0x0b30,
- 0x0b32, 0x0b33,
- 0x0b35, 0x0b39,
- 0x0b3c, 0x0b44,
- 0x0b47, 0x0b48,
- 0x0b4b, 0x0b4d,
- 0x0b55, 0x0b57,
- 0x0b5c, 0x0b5d,
- 0x0b5f, 0x0b63,
- 0x0b66, 0x0b77,
- 0x0b82, 0x0b83,
- 0x0b85, 0x0b8a,
- 0x0b8e, 0x0b90,
- 0x0b92, 0x0b95,
- 0x0b99, 0x0b9a,
- 0x0b9c, 0x0b9c,
- 0x0b9e, 0x0b9f,
- 0x0ba3, 0x0ba4,
- 0x0ba8, 0x0baa,
- 0x0bae, 0x0bb9,
- 0x0bbe, 0x0bc2,
- 0x0bc6, 0x0bc8,
- 0x0bca, 0x0bcd,
- 0x0bd0, 0x0bd0,
- 0x0bd7, 0x0bd7,
- 0x0be6, 0x0bfa,
- 0x0c00, 0x0c0c,
- 0x0c0e, 0x0c10,
- 0x0c12, 0x0c28,
- 0x0c2a, 0x0c39,
- 0x0c3c, 0x0c44,
- 0x0c46, 0x0c48,
- 0x0c4a, 0x0c4d,
- 0x0c55, 0x0c56,
- 0x0c58, 0x0c5a,
- 0x0c5d, 0x0c5d,
- 0x0c60, 0x0c63,
- 0x0c66, 0x0c6f,
- 0x0c77, 0x0c8c,
- 0x0c8e, 0x0c90,
- 0x0c92, 0x0ca8,
- 0x0caa, 0x0cb3,
- 0x0cb5, 0x0cb9,
- 0x0cbc, 0x0cc4,
- 0x0cc6, 0x0cc8,
- 0x0cca, 0x0ccd,
- 0x0cd5, 0x0cd6,
- 0x0cdd, 0x0cde,
- 0x0ce0, 0x0ce3,
- 0x0ce6, 0x0cef,
- 0x0cf1, 0x0cf3,
- 0x0d00, 0x0d0c,
- 0x0d0e, 0x0d10,
- 0x0d12, 0x0d44,
- 0x0d46, 0x0d48,
- 0x0d4a, 0x0d4f,
- 0x0d54, 0x0d63,
- 0x0d66, 0x0d7f,
- 0x0d81, 0x0d83,
- 0x0d85, 0x0d96,
- 0x0d9a, 0x0db1,
- 0x0db3, 0x0dbb,
- 0x0dbd, 0x0dbd,
- 0x0dc0, 0x0dc6,
- 0x0dca, 0x0dca,
- 0x0dcf, 0x0dd4,
- 0x0dd6, 0x0dd6,
- 0x0dd8, 0x0ddf,
- 0x0de6, 0x0def,
- 0x0df2, 0x0df4,
- 0x0e01, 0x0e3a,
- 0x0e3f, 0x0e5b,
- 0x0e81, 0x0e82,
- 0x0e84, 0x0e84,
- 0x0e86, 0x0e8a,
- 0x0e8c, 0x0ea3,
- 0x0ea5, 0x0ea5,
- 0x0ea7, 0x0ebd,
- 0x0ec0, 0x0ec4,
- 0x0ec6, 0x0ec6,
- 0x0ec8, 0x0ece,
- 0x0ed0, 0x0ed9,
- 0x0edc, 0x0edf,
- 0x0f00, 0x0f47,
- 0x0f49, 0x0f6c,
- 0x0f71, 0x0f97,
- 0x0f99, 0x0fbc,
- 0x0fbe, 0x0fcc,
- 0x0fce, 0x0fda,
- 0x1000, 0x10c5,
- 0x10c7, 0x10c7,
- 0x10cd, 0x10cd,
- 0x10d0, 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,
- 0x135d, 0x137c,
- 0x1380, 0x1399,
- 0x13a0, 0x13f5,
- 0x13f8, 0x13fd,
- 0x1400, 0x169c,
- 0x16a0, 0x16f8,
- 0x1700, 0x1715,
- 0x171f, 0x1736,
- 0x1740, 0x1753,
- 0x1760, 0x176c,
- 0x176e, 0x1770,
- 0x1772, 0x1773,
- 0x1780, 0x17dd,
- 0x17e0, 0x17e9,
- 0x17f0, 0x17f9,
- 0x1800, 0x1819,
- 0x1820, 0x1878,
- 0x1880, 0x18aa,
- 0x18b0, 0x18f5,
- 0x1900, 0x191e,
- 0x1920, 0x192b,
- 0x1930, 0x193b,
- 0x1940, 0x1940,
- 0x1944, 0x196d,
- 0x1970, 0x1974,
- 0x1980, 0x19ab,
- 0x19b0, 0x19c9,
- 0x19d0, 0x19da,
- 0x19de, 0x1a1b,
- 0x1a1e, 0x1a5e,
- 0x1a60, 0x1a7c,
- 0x1a7f, 0x1a89,
- 0x1a90, 0x1a99,
- 0x1aa0, 0x1aad,
- 0x1ab0, 0x1ace,
- 0x1b00, 0x1b4c,
- 0x1b4e, 0x1bf3,
- 0x1bfc, 0x1c37,
- 0x1c3b, 0x1c49,
- 0x1c4d, 0x1c8a,
- 0x1c90, 0x1cba,
- 0x1cbd, 0x1cc7,
- 0x1cd0, 0x1cfa,
- 0x1d00, 0x1f15,
- 0x1f18, 0x1f1d,
- 0x1f20, 0x1f45,
- 0x1f48, 0x1f4d,
- 0x1f50, 0x1f57,
- 0x1f59, 0x1f59,
- 0x1f5b, 0x1f5b,
- 0x1f5d, 0x1f5d,
- 0x1f5f, 0x1f7d,
- 0x1f80, 0x1fb4,
- 0x1fb6, 0x1fc4,
- 0x1fc6, 0x1fd3,
- 0x1fd6, 0x1fdb,
- 0x1fdd, 0x1fef,
- 0x1ff2, 0x1ff4,
- 0x1ff6, 0x1ffe,
- 0x2000, 0x2064,
- 0x2066, 0x2071,
- 0x2074, 0x208e,
- 0x2090, 0x209c,
- 0x20a0, 0x20c0,
- 0x20d0, 0x20f0,
- 0x2100, 0x218b,
- 0x2190, 0x2429,
- 0x2440, 0x244a,
- 0x2460, 0x2b73,
- 0x2b76, 0x2b95,
- 0x2b97, 0x2cf3,
- 0x2cf9, 0x2d25,
- 0x2d27, 0x2d27,
- 0x2d2d, 0x2d2d,
- 0x2d30, 0x2d67,
- 0x2d6f, 0x2d70,
- 0x2d7f, 0x2d96,
- 0x2da0, 0x2da6,
- 0x2da8, 0x2dae,
- 0x2db0, 0x2db6,
- 0x2db8, 0x2dbe,
- 0x2dc0, 0x2dc6,
- 0x2dc8, 0x2dce,
- 0x2dd0, 0x2dd6,
- 0x2dd8, 0x2dde,
- 0x2de0, 0x2e5d,
- 0x2e80, 0x2e99,
- 0x2e9b, 0x2ef3,
- 0x2f00, 0x2fd5,
- 0x2ff0, 0x303f,
- 0x3041, 0x3096,
- 0x3099, 0x30ff,
- 0x3105, 0x312f,
- 0x3131, 0x318e,
- 0x3190, 0x31e5,
- 0x31ef, 0x321e,
- 0x3220, 0xa48c,
- 0xa490, 0xa4c6,
- 0xa4d0, 0xa62b,
- 0xa640, 0xa6f7,
- 0xa700, 0xa7cd,
- 0xa7d0, 0xa7d1,
- 0xa7d3, 0xa7d3,
- 0xa7d5, 0xa7dc,
- 0xa7f2, 0xa82c,
- 0xa830, 0xa839,
- 0xa840, 0xa877,
- 0xa880, 0xa8c5,
- 0xa8ce, 0xa8d9,
- 0xa8e0, 0xa953,
- 0xa95f, 0xa97c,
- 0xa980, 0xa9cd,
- 0xa9cf, 0xa9d9,
- 0xa9de, 0xa9fe,
- 0xaa00, 0xaa36,
- 0xaa40, 0xaa4d,
- 0xaa50, 0xaa59,
- 0xaa5c, 0xaac2,
- 0xaadb, 0xaaf6,
- 0xab01, 0xab06,
- 0xab09, 0xab0e,
- 0xab11, 0xab16,
- 0xab20, 0xab26,
- 0xab28, 0xab2e,
- 0xab30, 0xab6b,
- 0xab70, 0xabed,
- 0xabf0, 0xabf9,
- 0xac00, 0xd7a3,
- 0xd7b0, 0xd7c6,
- 0xd7cb, 0xd7fb,
- 0xd800, 0xfa6d,
- 0xfa70, 0xfad9,
- 0xfb00, 0xfb06,
- 0xfb13, 0xfb17,
- 0xfb1d, 0xfb36,
- 0xfb38, 0xfb3c,
- 0xfb3e, 0xfb3e,
- 0xfb40, 0xfb41,
- 0xfb43, 0xfb44,
- 0xfb46, 0xfbc2,
- 0xfbd3, 0xfd8f,
- 0xfd92, 0xfdc7,
- 0xfdcf, 0xfe19,
- 0xfe20, 0xfe52,
- 0xfe54, 0xfe66,
- 0xfe68, 0xfe6b,
- 0xfe70, 0xfe74,
- 0xfe76, 0xfefc,
- 0xfeff, 0xfeff,
- 0xff01, 0xffbe,
- 0xffc2, 0xffc7,
- 0xffca, 0xffcf,
- 0xffd2, 0xffd7,
- 0xffda, 0xffdc,
- 0xffe0, 0xffe6,
- 0xffe8, 0xffee,
- 0xfff9, 0x1000b,
- 0x1000d, 0x10026,
- 0x10028, 0x1003a,
- 0x1003c, 0x1003d,
- 0x1003f, 0x1004d,
- 0x10050, 0x1005d,
- 0x10080, 0x100fa,
- 0x10100, 0x10102,
- 0x10107, 0x10133,
- 0x10137, 0x1018e,
- 0x10190, 0x1019c,
- 0x101a0, 0x101a0,
- 0x101d0, 0x101fd,
- 0x10280, 0x1029c,
- 0x102a0, 0x102d0,
- 0x102e0, 0x102fb,
- 0x10300, 0x10323,
- 0x1032d, 0x1034a,
- 0x10350, 0x1037a,
- 0x10380, 0x1039d,
- 0x1039f, 0x103c3,
- 0x103c8, 0x103d5,
- 0x10400, 0x1049d,
- 0x104a0, 0x104a9,
- 0x104b0, 0x104d3,
- 0x104d8, 0x104fb,
- 0x10500, 0x10527,
- 0x10530, 0x10563,
- 0x1056f, 0x1057a,
- 0x1057c, 0x1058a,
- 0x1058c, 0x10592,
- 0x10594, 0x10595,
- 0x10597, 0x105a1,
- 0x105a3, 0x105b1,
- 0x105b3, 0x105b9,
- 0x105bb, 0x105bc,
- 0x105c0, 0x105f3,
- 0x10600, 0x10736,
- 0x10740, 0x10755,
- 0x10760, 0x10767,
- 0x10780, 0x10785,
- 0x10787, 0x107b0,
- 0x107b2, 0x107ba,
- 0x10800, 0x10805,
- 0x10808, 0x10808,
- 0x1080a, 0x10835,
- 0x10837, 0x10838,
- 0x1083c, 0x1083c,
- 0x1083f, 0x10855,
- 0x10857, 0x1089e,
- 0x108a7, 0x108af,
- 0x108e0, 0x108f2,
- 0x108f4, 0x108f5,
- 0x108fb, 0x1091b,
- 0x1091f, 0x10939,
- 0x1093f, 0x1093f,
- 0x10980, 0x109b7,
- 0x109bc, 0x109cf,
- 0x109d2, 0x10a03,
- 0x10a05, 0x10a06,
- 0x10a0c, 0x10a13,
- 0x10a15, 0x10a17,
- 0x10a19, 0x10a35,
- 0x10a38, 0x10a3a,
- 0x10a3f, 0x10a48,
- 0x10a50, 0x10a58,
- 0x10a60, 0x10a9f,
- 0x10ac0, 0x10ae6,
- 0x10aeb, 0x10af6,
- 0x10b00, 0x10b35,
- 0x10b39, 0x10b55,
- 0x10b58, 0x10b72,
- 0x10b78, 0x10b91,
- 0x10b99, 0x10b9c,
- 0x10ba9, 0x10baf,
- 0x10c00, 0x10c48,
- 0x10c80, 0x10cb2,
- 0x10cc0, 0x10cf2,
- 0x10cfa, 0x10d27,
- 0x10d30, 0x10d39,
- 0x10d40, 0x10d65,
- 0x10d69, 0x10d85,
- 0x10d8e, 0x10d8f,
- 0x10e60, 0x10e7e,
- 0x10e80, 0x10ea9,
- 0x10eab, 0x10ead,
- 0x10eb0, 0x10eb1,
- 0x10ec2, 0x10ec4,
- 0x10efc, 0x10f27,
- 0x10f30, 0x10f59,
- 0x10f70, 0x10f89,
- 0x10fb0, 0x10fcb,
- 0x10fe0, 0x10ff6,
- 0x11000, 0x1104d,
- 0x11052, 0x11075,
- 0x1107f, 0x110c2,
- 0x110cd, 0x110cd,
- 0x110d0, 0x110e8,
- 0x110f0, 0x110f9,
- 0x11100, 0x11134,
- 0x11136, 0x11147,
- 0x11150, 0x11176,
- 0x11180, 0x111df,
- 0x111e1, 0x111f4,
- 0x11200, 0x11211,
- 0x11213, 0x11241,
- 0x11280, 0x11286,
- 0x11288, 0x11288,
- 0x1128a, 0x1128d,
- 0x1128f, 0x1129d,
- 0x1129f, 0x112a9,
- 0x112b0, 0x112ea,
- 0x112f0, 0x112f9,
- 0x11300, 0x11303,
- 0x11305, 0x1130c,
- 0x1130f, 0x11310,
- 0x11313, 0x11328,
- 0x1132a, 0x11330,
- 0x11332, 0x11333,
- 0x11335, 0x11339,
- 0x1133b, 0x11344,
- 0x11347, 0x11348,
- 0x1134b, 0x1134d,
- 0x11350, 0x11350,
- 0x11357, 0x11357,
- 0x1135d, 0x11363,
- 0x11366, 0x1136c,
- 0x11370, 0x11374,
- 0x11380, 0x11389,
- 0x1138b, 0x1138b,
- 0x1138e, 0x1138e,
- 0x11390, 0x113b5,
- 0x113b7, 0x113c0,
- 0x113c2, 0x113c2,
- 0x113c5, 0x113c5,
- 0x113c7, 0x113ca,
- 0x113cc, 0x113d5,
- 0x113d7, 0x113d8,
- 0x113e1, 0x113e2,
- 0x11400, 0x1145b,
- 0x1145d, 0x11461,
- 0x11480, 0x114c7,
- 0x114d0, 0x114d9,
- 0x11580, 0x115b5,
- 0x115b8, 0x115dd,
- 0x11600, 0x11644,
- 0x11650, 0x11659,
- 0x11660, 0x1166c,
- 0x11680, 0x116b9,
- 0x116c0, 0x116c9,
- 0x116d0, 0x116e3,
- 0x11700, 0x1171a,
- 0x1171d, 0x1172b,
- 0x11730, 0x11746,
- 0x11800, 0x1183b,
- 0x118a0, 0x118f2,
- 0x118ff, 0x11906,
- 0x11909, 0x11909,
- 0x1190c, 0x11913,
- 0x11915, 0x11916,
- 0x11918, 0x11935,
- 0x11937, 0x11938,
- 0x1193b, 0x11946,
- 0x11950, 0x11959,
- 0x119a0, 0x119a7,
- 0x119aa, 0x119d7,
- 0x119da, 0x119e4,
- 0x11a00, 0x11a47,
- 0x11a50, 0x11aa2,
- 0x11ab0, 0x11af8,
- 0x11b00, 0x11b09,
- 0x11bc0, 0x11be1,
- 0x11bf0, 0x11bf9,
- 0x11c00, 0x11c08,
- 0x11c0a, 0x11c36,
- 0x11c38, 0x11c45,
- 0x11c50, 0x11c6c,
- 0x11c70, 0x11c8f,
- 0x11c92, 0x11ca7,
- 0x11ca9, 0x11cb6,
- 0x11d00, 0x11d06,
- 0x11d08, 0x11d09,
- 0x11d0b, 0x11d36,
- 0x11d3a, 0x11d3a,
- 0x11d3c, 0x11d3d,
- 0x11d3f, 0x11d47,
- 0x11d50, 0x11d59,
- 0x11d60, 0x11d65,
- 0x11d67, 0x11d68,
- 0x11d6a, 0x11d8e,
- 0x11d90, 0x11d91,
- 0x11d93, 0x11d98,
- 0x11da0, 0x11da9,
- 0x11ee0, 0x11ef8,
- 0x11f00, 0x11f10,
- 0x11f12, 0x11f3a,
- 0x11f3e, 0x11f5a,
- 0x11fb0, 0x11fb0,
- 0x11fc0, 0x11ff1,
- 0x11fff, 0x12399,
- 0x12400, 0x1246e,
- 0x12470, 0x12474,
- 0x12480, 0x12543,
- 0x12f90, 0x12ff2,
- 0x13000, 0x13455,
- 0x13460, 0x143fa,
- 0x14400, 0x14646,
- 0x16100, 0x16139,
- 0x16800, 0x16a38,
- 0x16a40, 0x16a5e,
- 0x16a60, 0x16a69,
- 0x16a6e, 0x16abe,
- 0x16ac0, 0x16ac9,
- 0x16ad0, 0x16aed,
- 0x16af0, 0x16af5,
- 0x16b00, 0x16b45,
- 0x16b50, 0x16b59,
- 0x16b5b, 0x16b61,
- 0x16b63, 0x16b77,
- 0x16b7d, 0x16b8f,
- 0x16d40, 0x16d79,
- 0x16e40, 0x16e9a,
- 0x16f00, 0x16f4a,
- 0x16f4f, 0x16f87,
- 0x16f8f, 0x16f9f,
- 0x16fe0, 0x16fe4,
- 0x16ff0, 0x16ff1,
- 0x17000, 0x187f7,
- 0x18800, 0x18cd5,
- 0x18cff, 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,
- 0x1bc9c, 0x1bca3,
- 0x1cc00, 0x1ccf9,
- 0x1cd00, 0x1ceb3,
- 0x1cf00, 0x1cf2d,
- 0x1cf30, 0x1cf46,
- 0x1cf50, 0x1cfc3,
- 0x1d000, 0x1d0f5,
- 0x1d100, 0x1d126,
- 0x1d129, 0x1d1ea,
- 0x1d200, 0x1d245,
- 0x1d2c0, 0x1d2d3,
- 0x1d2e0, 0x1d2f3,
- 0x1d300, 0x1d356,
- 0x1d360, 0x1d378,
- 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, 0x1d7cb,
- 0x1d7ce, 0x1da8b,
- 0x1da9b, 0x1da9f,
- 0x1daa1, 0x1daaf,
- 0x1df00, 0x1df1e,
- 0x1df25, 0x1df2a,
- 0x1e000, 0x1e006,
- 0x1e008, 0x1e018,
- 0x1e01b, 0x1e021,
- 0x1e023, 0x1e024,
- 0x1e026, 0x1e02a,
- 0x1e030, 0x1e06d,
- 0x1e08f, 0x1e08f,
- 0x1e100, 0x1e12c,
- 0x1e130, 0x1e13d,
- 0x1e140, 0x1e149,
- 0x1e14e, 0x1e14f,
- 0x1e290, 0x1e2ae,
- 0x1e2c0, 0x1e2f9,
- 0x1e2ff, 0x1e2ff,
- 0x1e4d0, 0x1e4f9,
- 0x1e5d0, 0x1e5fa,
- 0x1e5ff, 0x1e5ff,
- 0x1e7e0, 0x1e7e6,
- 0x1e7e8, 0x1e7eb,
- 0x1e7ed, 0x1e7ee,
- 0x1e7f0, 0x1e7fe,
- 0x1e800, 0x1e8c4,
- 0x1e8c7, 0x1e8d6,
- 0x1e900, 0x1e94b,
- 0x1e950, 0x1e959,
- 0x1e95e, 0x1e95f,
- 0x1ec71, 0x1ecb4,
- 0x1ed01, 0x1ed3d,
- 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,
- 0x1eef0, 0x1eef1,
- 0x1f000, 0x1f02b,
- 0x1f030, 0x1f093,
- 0x1f0a0, 0x1f0ae,
- 0x1f0b1, 0x1f0bf,
- 0x1f0c1, 0x1f0cf,
- 0x1f0d1, 0x1f0f5,
- 0x1f100, 0x1f1ad,
- 0x1f1e6, 0x1f202,
- 0x1f210, 0x1f23b,
- 0x1f240, 0x1f248,
- 0x1f250, 0x1f251,
- 0x1f260, 0x1f265,
- 0x1f300, 0x1f6d7,
- 0x1f6dc, 0x1f6ec,
- 0x1f6f0, 0x1f6fc,
- 0x1f700, 0x1f776,
- 0x1f77b, 0x1f7d9,
- 0x1f7e0, 0x1f7eb,
- 0x1f7f0, 0x1f7f0,
- 0x1f800, 0x1f80b,
- 0x1f810, 0x1f847,
- 0x1f850, 0x1f859,
- 0x1f860, 0x1f887,
- 0x1f890, 0x1f8ad,
- 0x1f8b0, 0x1f8bb,
- 0x1f8c0, 0x1f8c1,
- 0x1f900, 0x1fa53,
- 0x1fa60, 0x1fa6d,
- 0x1fa70, 0x1fa7c,
- 0x1fa80, 0x1fa89,
- 0x1fa8f, 0x1fac6,
- 0x1face, 0x1fadc,
- 0x1fadf, 0x1fae9,
- 0x1faf0, 0x1faf8,
- 0x1fb00, 0x1fb92,
- 0x1fb94, 0x1fbf9,
- 0x1fffe, 0x2a6df,
- 0x2a700, 0x2b739,
- 0x2b740, 0x2b81d,
- 0x2b820, 0x2cea1,
- 0x2ceb0, 0x2ebe0,
- 0x2ebf0, 0x2ee5d,
- 0x2f800, 0x2fa1d,
- 0x2fffe, 0x3134a,
- 0x31350, 0x323af,
- 0x3fffe, 0x3ffff,
- 0x4fffe, 0x4ffff,
- 0x5fffe, 0x5ffff,
- 0x6fffe, 0x6ffff,
- 0x7fffe, 0x7ffff,
- 0x8fffe, 0x8ffff,
- 0x9fffe, 0x9ffff,
- 0xafffe, 0xaffff,
- 0xbfffe, 0xbffff,
- 0xcfffe, 0xcffff,
- 0xdfffe, 0xdffff,
- 0xe0001, 0xe0001,
- 0xe0020, 0xe007f,
- 0xe0100, 0xe01ef,
- 0xefffe, 0x10ffff,
-}; /* CR_Age_16_0 */
-
-#endif /* USE_UNICODE_AGE_PROPERTIES */
-/* 'Grapheme_Cluster_Break_Prepend': Grapheme_Cluster_Break=Prepend */
-static const OnigCodePoint CR_Grapheme_Cluster_Break_Prepend[] = {
- 16,
- 0x0600, 0x0605,
- 0x06dd, 0x06dd,
- 0x070f, 0x070f,
- 0x0890, 0x0891,
- 0x08e2, 0x08e2,
- 0x0d4e, 0x0d4e,
- 0x110bd, 0x110bd,
- 0x110cd, 0x110cd,
- 0x111c2, 0x111c3,
- 0x113d1, 0x113d1,
- 0x1193f, 0x1193f,
- 0x11941, 0x11941,
- 0x11a3a, 0x11a3a,
- 0x11a84, 0x11a89,
- 0x11d46, 0x11d46,
- 0x11f02, 0x11f02,
-}; /* CR_Grapheme_Cluster_Break_Prepend */
-
-/* 'Grapheme_Cluster_Break_CR': Grapheme_Cluster_Break=CR */
-static const OnigCodePoint CR_Grapheme_Cluster_Break_CR[] = {
- 1,
- 0x000d, 0x000d,
-}; /* CR_Grapheme_Cluster_Break_CR */
-
-/* 'Grapheme_Cluster_Break_LF': Grapheme_Cluster_Break=LF */
-#define CR_Grapheme_Cluster_Break_LF CR_NEWLINE
-
-/* 'Grapheme_Cluster_Break_Control': Grapheme_Cluster_Break=Control */
-static const OnigCodePoint CR_Grapheme_Cluster_Break_Control[] = {
- 19,
- 0x0000, 0x0009,
- 0x000b, 0x000c,
- 0x000e, 0x001f,
- 0x007f, 0x009f,
- 0x00ad, 0x00ad,
- 0x061c, 0x061c,
- 0x180e, 0x180e,
- 0x200b, 0x200b,
- 0x200e, 0x200f,
- 0x2028, 0x202e,
- 0x2060, 0x206f,
- 0xfeff, 0xfeff,
- 0xfff0, 0xfffb,
- 0x13430, 0x1343f,
- 0x1bca0, 0x1bca3,
- 0x1d173, 0x1d17a,
- 0xe0000, 0xe001f,
- 0xe0080, 0xe00ff,
- 0xe01f0, 0xe0fff,
-}; /* CR_Grapheme_Cluster_Break_Control */
-
-/* 'Grapheme_Cluster_Break_Extend': Grapheme_Cluster_Break=Extend */
-static const OnigCodePoint CR_Grapheme_Cluster_Break_Extend[] = {
- 376,
- 0x0300, 0x036f,
- 0x0483, 0x0489,
- 0x0591, 0x05bd,
- 0x05bf, 0x05bf,
- 0x05c1, 0x05c2,
- 0x05c4, 0x05c5,
- 0x05c7, 0x05c7,
- 0x0610, 0x061a,
- 0x064b, 0x065f,
- 0x0670, 0x0670,
- 0x06d6, 0x06dc,
- 0x06df, 0x06e4,
- 0x06e7, 0x06e8,
- 0x06ea, 0x06ed,
- 0x0711, 0x0711,
- 0x0730, 0x074a,
- 0x07a6, 0x07b0,
- 0x07eb, 0x07f3,
- 0x07fd, 0x07fd,
- 0x0816, 0x0819,
- 0x081b, 0x0823,
- 0x0825, 0x0827,
- 0x0829, 0x082d,
- 0x0859, 0x085b,
- 0x0897, 0x089f,
- 0x08ca, 0x08e1,
- 0x08e3, 0x0902,
- 0x093a, 0x093a,
- 0x093c, 0x093c,
- 0x0941, 0x0948,
- 0x094d, 0x094d,
- 0x0951, 0x0957,
- 0x0962, 0x0963,
- 0x0981, 0x0981,
- 0x09bc, 0x09bc,
- 0x09be, 0x09be,
- 0x09c1, 0x09c4,
- 0x09cd, 0x09cd,
- 0x09d7, 0x09d7,
- 0x09e2, 0x09e3,
- 0x09fe, 0x09fe,
- 0x0a01, 0x0a02,
- 0x0a3c, 0x0a3c,
- 0x0a41, 0x0a42,
- 0x0a47, 0x0a48,
- 0x0a4b, 0x0a4d,
- 0x0a51, 0x0a51,
- 0x0a70, 0x0a71,
- 0x0a75, 0x0a75,
- 0x0a81, 0x0a82,
- 0x0abc, 0x0abc,
- 0x0ac1, 0x0ac5,
- 0x0ac7, 0x0ac8,
- 0x0acd, 0x0acd,
- 0x0ae2, 0x0ae3,
- 0x0afa, 0x0aff,
- 0x0b01, 0x0b01,
- 0x0b3c, 0x0b3c,
- 0x0b3e, 0x0b3f,
- 0x0b41, 0x0b44,
- 0x0b4d, 0x0b4d,
- 0x0b55, 0x0b57,
- 0x0b62, 0x0b63,
- 0x0b82, 0x0b82,
- 0x0bbe, 0x0bbe,
- 0x0bc0, 0x0bc0,
- 0x0bcd, 0x0bcd,
- 0x0bd7, 0x0bd7,
- 0x0c00, 0x0c00,
- 0x0c04, 0x0c04,
- 0x0c3c, 0x0c3c,
- 0x0c3e, 0x0c40,
- 0x0c46, 0x0c48,
- 0x0c4a, 0x0c4d,
- 0x0c55, 0x0c56,
- 0x0c62, 0x0c63,
- 0x0c81, 0x0c81,
- 0x0cbc, 0x0cbc,
- 0x0cbf, 0x0cc0,
- 0x0cc2, 0x0cc2,
- 0x0cc6, 0x0cc8,
- 0x0cca, 0x0ccd,
- 0x0cd5, 0x0cd6,
- 0x0ce2, 0x0ce3,
- 0x0d00, 0x0d01,
- 0x0d3b, 0x0d3c,
- 0x0d3e, 0x0d3e,
- 0x0d41, 0x0d44,
- 0x0d4d, 0x0d4d,
- 0x0d57, 0x0d57,
- 0x0d62, 0x0d63,
- 0x0d81, 0x0d81,
- 0x0dca, 0x0dca,
- 0x0dcf, 0x0dcf,
- 0x0dd2, 0x0dd4,
- 0x0dd6, 0x0dd6,
- 0x0ddf, 0x0ddf,
- 0x0e31, 0x0e31,
- 0x0e34, 0x0e3a,
- 0x0e47, 0x0e4e,
- 0x0eb1, 0x0eb1,
- 0x0eb4, 0x0ebc,
- 0x0ec8, 0x0ece,
- 0x0f18, 0x0f19,
- 0x0f35, 0x0f35,
- 0x0f37, 0x0f37,
- 0x0f39, 0x0f39,
- 0x0f71, 0x0f7e,
- 0x0f80, 0x0f84,
- 0x0f86, 0x0f87,
- 0x0f8d, 0x0f97,
- 0x0f99, 0x0fbc,
- 0x0fc6, 0x0fc6,
- 0x102d, 0x1030,
- 0x1032, 0x1037,
- 0x1039, 0x103a,
- 0x103d, 0x103e,
- 0x1058, 0x1059,
- 0x105e, 0x1060,
- 0x1071, 0x1074,
- 0x1082, 0x1082,
- 0x1085, 0x1086,
- 0x108d, 0x108d,
- 0x109d, 0x109d,
- 0x135d, 0x135f,
- 0x1712, 0x1715,
- 0x1732, 0x1734,
- 0x1752, 0x1753,
- 0x1772, 0x1773,
- 0x17b4, 0x17b5,
- 0x17b7, 0x17bd,
- 0x17c6, 0x17c6,
- 0x17c9, 0x17d3,
- 0x17dd, 0x17dd,
- 0x180b, 0x180d,
- 0x180f, 0x180f,
- 0x1885, 0x1886,
- 0x18a9, 0x18a9,
- 0x1920, 0x1922,
- 0x1927, 0x1928,
- 0x1932, 0x1932,
- 0x1939, 0x193b,
- 0x1a17, 0x1a18,
- 0x1a1b, 0x1a1b,
- 0x1a56, 0x1a56,
- 0x1a58, 0x1a5e,
- 0x1a60, 0x1a60,
- 0x1a62, 0x1a62,
- 0x1a65, 0x1a6c,
- 0x1a73, 0x1a7c,
- 0x1a7f, 0x1a7f,
- 0x1ab0, 0x1ace,
- 0x1b00, 0x1b03,
- 0x1b34, 0x1b3d,
- 0x1b42, 0x1b44,
- 0x1b6b, 0x1b73,
- 0x1b80, 0x1b81,
- 0x1ba2, 0x1ba5,
- 0x1ba8, 0x1bad,
- 0x1be6, 0x1be6,
- 0x1be8, 0x1be9,
- 0x1bed, 0x1bed,
- 0x1bef, 0x1bf3,
- 0x1c2c, 0x1c33,
- 0x1c36, 0x1c37,
- 0x1cd0, 0x1cd2,
- 0x1cd4, 0x1ce0,
- 0x1ce2, 0x1ce8,
- 0x1ced, 0x1ced,
- 0x1cf4, 0x1cf4,
- 0x1cf8, 0x1cf9,
- 0x1dc0, 0x1dff,
- 0x200c, 0x200c,
- 0x20d0, 0x20f0,
- 0x2cef, 0x2cf1,
- 0x2d7f, 0x2d7f,
- 0x2de0, 0x2dff,
- 0x302a, 0x302f,
- 0x3099, 0x309a,
- 0xa66f, 0xa672,
- 0xa674, 0xa67d,
- 0xa69e, 0xa69f,
- 0xa6f0, 0xa6f1,
- 0xa802, 0xa802,
- 0xa806, 0xa806,
- 0xa80b, 0xa80b,
- 0xa825, 0xa826,
- 0xa82c, 0xa82c,
- 0xa8c4, 0xa8c5,
- 0xa8e0, 0xa8f1,
- 0xa8ff, 0xa8ff,
- 0xa926, 0xa92d,
- 0xa947, 0xa951,
- 0xa953, 0xa953,
- 0xa980, 0xa982,
- 0xa9b3, 0xa9b3,
- 0xa9b6, 0xa9b9,
- 0xa9bc, 0xa9bd,
- 0xa9c0, 0xa9c0,
- 0xa9e5, 0xa9e5,
- 0xaa29, 0xaa2e,
- 0xaa31, 0xaa32,
- 0xaa35, 0xaa36,
- 0xaa43, 0xaa43,
- 0xaa4c, 0xaa4c,
- 0xaa7c, 0xaa7c,
- 0xaab0, 0xaab0,
- 0xaab2, 0xaab4,
- 0xaab7, 0xaab8,
- 0xaabe, 0xaabf,
- 0xaac1, 0xaac1,
- 0xaaec, 0xaaed,
- 0xaaf6, 0xaaf6,
- 0xabe5, 0xabe5,
- 0xabe8, 0xabe8,
- 0xabed, 0xabed,
- 0xfb1e, 0xfb1e,
- 0xfe00, 0xfe0f,
- 0xfe20, 0xfe2f,
- 0xff9e, 0xff9f,
- 0x101fd, 0x101fd,
- 0x102e0, 0x102e0,
- 0x10376, 0x1037a,
- 0x10a01, 0x10a03,
- 0x10a05, 0x10a06,
- 0x10a0c, 0x10a0f,
- 0x10a38, 0x10a3a,
- 0x10a3f, 0x10a3f,
- 0x10ae5, 0x10ae6,
- 0x10d24, 0x10d27,
- 0x10d69, 0x10d6d,
- 0x10eab, 0x10eac,
- 0x10efc, 0x10eff,
- 0x10f46, 0x10f50,
- 0x10f82, 0x10f85,
- 0x11001, 0x11001,
- 0x11038, 0x11046,
- 0x11070, 0x11070,
- 0x11073, 0x11074,
- 0x1107f, 0x11081,
- 0x110b3, 0x110b6,
- 0x110b9, 0x110ba,
- 0x110c2, 0x110c2,
- 0x11100, 0x11102,
- 0x11127, 0x1112b,
- 0x1112d, 0x11134,
- 0x11173, 0x11173,
- 0x11180, 0x11181,
- 0x111b6, 0x111be,
- 0x111c0, 0x111c0,
- 0x111c9, 0x111cc,
- 0x111cf, 0x111cf,
- 0x1122f, 0x11231,
- 0x11234, 0x11237,
- 0x1123e, 0x1123e,
- 0x11241, 0x11241,
- 0x112df, 0x112df,
- 0x112e3, 0x112ea,
- 0x11300, 0x11301,
- 0x1133b, 0x1133c,
- 0x1133e, 0x1133e,
- 0x11340, 0x11340,
- 0x1134d, 0x1134d,
- 0x11357, 0x11357,
- 0x11366, 0x1136c,
- 0x11370, 0x11374,
- 0x113b8, 0x113b8,
- 0x113bb, 0x113c0,
- 0x113c2, 0x113c2,
- 0x113c5, 0x113c5,
- 0x113c7, 0x113c9,
- 0x113ce, 0x113d0,
- 0x113d2, 0x113d2,
- 0x113e1, 0x113e2,
- 0x11438, 0x1143f,
- 0x11442, 0x11444,
- 0x11446, 0x11446,
- 0x1145e, 0x1145e,
- 0x114b0, 0x114b0,
- 0x114b3, 0x114b8,
- 0x114ba, 0x114ba,
- 0x114bd, 0x114bd,
- 0x114bf, 0x114c0,
- 0x114c2, 0x114c3,
- 0x115af, 0x115af,
- 0x115b2, 0x115b5,
- 0x115bc, 0x115bd,
- 0x115bf, 0x115c0,
- 0x115dc, 0x115dd,
- 0x11633, 0x1163a,
- 0x1163d, 0x1163d,
- 0x1163f, 0x11640,
- 0x116ab, 0x116ab,
- 0x116ad, 0x116ad,
- 0x116b0, 0x116b7,
- 0x1171d, 0x1171d,
- 0x1171f, 0x1171f,
- 0x11722, 0x11725,
- 0x11727, 0x1172b,
- 0x1182f, 0x11837,
- 0x11839, 0x1183a,
- 0x11930, 0x11930,
- 0x1193b, 0x1193e,
- 0x11943, 0x11943,
- 0x119d4, 0x119d7,
- 0x119da, 0x119db,
- 0x119e0, 0x119e0,
- 0x11a01, 0x11a0a,
- 0x11a33, 0x11a38,
- 0x11a3b, 0x11a3e,
- 0x11a47, 0x11a47,
- 0x11a51, 0x11a56,
- 0x11a59, 0x11a5b,
- 0x11a8a, 0x11a96,
- 0x11a98, 0x11a99,
- 0x11c30, 0x11c36,
- 0x11c38, 0x11c3d,
- 0x11c3f, 0x11c3f,
- 0x11c92, 0x11ca7,
- 0x11caa, 0x11cb0,
- 0x11cb2, 0x11cb3,
- 0x11cb5, 0x11cb6,
- 0x11d31, 0x11d36,
- 0x11d3a, 0x11d3a,
- 0x11d3c, 0x11d3d,
- 0x11d3f, 0x11d45,
- 0x11d47, 0x11d47,
- 0x11d90, 0x11d91,
- 0x11d95, 0x11d95,
- 0x11d97, 0x11d97,
- 0x11ef3, 0x11ef4,
- 0x11f00, 0x11f01,
- 0x11f36, 0x11f3a,
- 0x11f40, 0x11f42,
- 0x11f5a, 0x11f5a,
- 0x13440, 0x13440,
- 0x13447, 0x13455,
- 0x1611e, 0x16129,
- 0x1612d, 0x1612f,
- 0x16af0, 0x16af4,
- 0x16b30, 0x16b36,
- 0x16f4f, 0x16f4f,
- 0x16f8f, 0x16f92,
- 0x16fe4, 0x16fe4,
- 0x16ff0, 0x16ff1,
- 0x1bc9d, 0x1bc9e,
- 0x1cf00, 0x1cf2d,
- 0x1cf30, 0x1cf46,
- 0x1d165, 0x1d169,
- 0x1d16d, 0x1d172,
- 0x1d17b, 0x1d182,
- 0x1d185, 0x1d18b,
- 0x1d1aa, 0x1d1ad,
- 0x1d242, 0x1d244,
- 0x1da00, 0x1da36,
- 0x1da3b, 0x1da6c,
- 0x1da75, 0x1da75,
- 0x1da84, 0x1da84,
- 0x1da9b, 0x1da9f,
- 0x1daa1, 0x1daaf,
- 0x1e000, 0x1e006,
- 0x1e008, 0x1e018,
- 0x1e01b, 0x1e021,
- 0x1e023, 0x1e024,
- 0x1e026, 0x1e02a,
- 0x1e08f, 0x1e08f,
- 0x1e130, 0x1e136,
- 0x1e2ae, 0x1e2ae,
- 0x1e2ec, 0x1e2ef,
- 0x1e4ec, 0x1e4ef,
- 0x1e5ee, 0x1e5ef,
- 0x1e8d0, 0x1e8d6,
- 0x1e944, 0x1e94a,
- 0x1f3fb, 0x1f3ff,
- 0xe0020, 0xe007f,
- 0xe0100, 0xe01ef,
-}; /* CR_Grapheme_Cluster_Break_Extend */
-
-/* 'Grapheme_Cluster_Break_Regional_Indicator': Grapheme_Cluster_Break=Regional_Indicator */
-#define CR_Grapheme_Cluster_Break_Regional_Indicator CR_Regional_Indicator
-
-/* 'Grapheme_Cluster_Break_SpacingMark': Grapheme_Cluster_Break=SpacingMark */
-static const OnigCodePoint CR_Grapheme_Cluster_Break_SpacingMark[] = {
- 155,
- 0x0903, 0x0903,
- 0x093b, 0x093b,
- 0x093e, 0x0940,
- 0x0949, 0x094c,
- 0x094e, 0x094f,
- 0x0982, 0x0983,
- 0x09bf, 0x09c0,
- 0x09c7, 0x09c8,
- 0x09cb, 0x09cc,
- 0x0a03, 0x0a03,
- 0x0a3e, 0x0a40,
- 0x0a83, 0x0a83,
- 0x0abe, 0x0ac0,
- 0x0ac9, 0x0ac9,
- 0x0acb, 0x0acc,
- 0x0b02, 0x0b03,
- 0x0b40, 0x0b40,
- 0x0b47, 0x0b48,
- 0x0b4b, 0x0b4c,
- 0x0bbf, 0x0bbf,
- 0x0bc1, 0x0bc2,
- 0x0bc6, 0x0bc8,
- 0x0bca, 0x0bcc,
- 0x0c01, 0x0c03,
- 0x0c41, 0x0c44,
- 0x0c82, 0x0c83,
- 0x0cbe, 0x0cbe,
- 0x0cc1, 0x0cc1,
- 0x0cc3, 0x0cc4,
- 0x0cf3, 0x0cf3,
- 0x0d02, 0x0d03,
- 0x0d3f, 0x0d40,
- 0x0d46, 0x0d48,
- 0x0d4a, 0x0d4c,
- 0x0d82, 0x0d83,
- 0x0dd0, 0x0dd1,
- 0x0dd8, 0x0dde,
- 0x0df2, 0x0df3,
- 0x0e33, 0x0e33,
- 0x0eb3, 0x0eb3,
- 0x0f3e, 0x0f3f,
- 0x0f7f, 0x0f7f,
- 0x1031, 0x1031,
- 0x103b, 0x103c,
- 0x1056, 0x1057,
- 0x1084, 0x1084,
- 0x17b6, 0x17b6,
- 0x17be, 0x17c5,
- 0x17c7, 0x17c8,
- 0x1923, 0x1926,
- 0x1929, 0x192b,
- 0x1930, 0x1931,
- 0x1933, 0x1938,
- 0x1a19, 0x1a1a,
- 0x1a55, 0x1a55,
- 0x1a57, 0x1a57,
- 0x1a6d, 0x1a72,
- 0x1b04, 0x1b04,
- 0x1b3e, 0x1b41,
- 0x1b82, 0x1b82,
- 0x1ba1, 0x1ba1,
- 0x1ba6, 0x1ba7,
- 0x1be7, 0x1be7,
- 0x1bea, 0x1bec,
- 0x1bee, 0x1bee,
- 0x1c24, 0x1c2b,
- 0x1c34, 0x1c35,
- 0x1ce1, 0x1ce1,
- 0x1cf7, 0x1cf7,
- 0xa823, 0xa824,
- 0xa827, 0xa827,
- 0xa880, 0xa881,
- 0xa8b4, 0xa8c3,
- 0xa952, 0xa952,
- 0xa983, 0xa983,
- 0xa9b4, 0xa9b5,
- 0xa9ba, 0xa9bb,
- 0xa9be, 0xa9bf,
- 0xaa2f, 0xaa30,
- 0xaa33, 0xaa34,
- 0xaa4d, 0xaa4d,
- 0xaaeb, 0xaaeb,
- 0xaaee, 0xaaef,
- 0xaaf5, 0xaaf5,
- 0xabe3, 0xabe4,
- 0xabe6, 0xabe7,
- 0xabe9, 0xabea,
- 0xabec, 0xabec,
- 0x11000, 0x11000,
- 0x11002, 0x11002,
- 0x11082, 0x11082,
- 0x110b0, 0x110b2,
- 0x110b7, 0x110b8,
- 0x1112c, 0x1112c,
- 0x11145, 0x11146,
- 0x11182, 0x11182,
- 0x111b3, 0x111b5,
- 0x111bf, 0x111bf,
- 0x111ce, 0x111ce,
- 0x1122c, 0x1122e,
- 0x11232, 0x11233,
- 0x112e0, 0x112e2,
- 0x11302, 0x11303,
- 0x1133f, 0x1133f,
- 0x11341, 0x11344,
- 0x11347, 0x11348,
- 0x1134b, 0x1134c,
- 0x11362, 0x11363,
- 0x113b9, 0x113ba,
- 0x113ca, 0x113ca,
- 0x113cc, 0x113cd,
- 0x11435, 0x11437,
- 0x11440, 0x11441,
- 0x11445, 0x11445,
- 0x114b1, 0x114b2,
- 0x114b9, 0x114b9,
- 0x114bb, 0x114bc,
- 0x114be, 0x114be,
- 0x114c1, 0x114c1,
- 0x115b0, 0x115b1,
- 0x115b8, 0x115bb,
- 0x115be, 0x115be,
- 0x11630, 0x11632,
- 0x1163b, 0x1163c,
- 0x1163e, 0x1163e,
- 0x116ac, 0x116ac,
- 0x116ae, 0x116af,
- 0x1171e, 0x1171e,
- 0x11726, 0x11726,
- 0x1182c, 0x1182e,
- 0x11838, 0x11838,
- 0x11931, 0x11935,
- 0x11937, 0x11938,
- 0x11940, 0x11940,
- 0x11942, 0x11942,
- 0x119d1, 0x119d3,
- 0x119dc, 0x119df,
- 0x119e4, 0x119e4,
- 0x11a39, 0x11a39,
- 0x11a57, 0x11a58,
- 0x11a97, 0x11a97,
- 0x11c2f, 0x11c2f,
- 0x11c3e, 0x11c3e,
- 0x11ca9, 0x11ca9,
- 0x11cb1, 0x11cb1,
- 0x11cb4, 0x11cb4,
- 0x11d8a, 0x11d8e,
- 0x11d93, 0x11d94,
- 0x11d96, 0x11d96,
- 0x11ef5, 0x11ef6,
- 0x11f03, 0x11f03,
- 0x11f34, 0x11f35,
- 0x11f3e, 0x11f3f,
- 0x1612a, 0x1612c,
- 0x16f51, 0x16f87,
-}; /* CR_Grapheme_Cluster_Break_SpacingMark */
-
-/* 'Grapheme_Cluster_Break_L': Grapheme_Cluster_Break=L */
-static const OnigCodePoint CR_Grapheme_Cluster_Break_L[] = {
- 2,
- 0x1100, 0x115f,
- 0xa960, 0xa97c,
-}; /* CR_Grapheme_Cluster_Break_L */
-
-/* 'Grapheme_Cluster_Break_V': Grapheme_Cluster_Break=V */
-static const OnigCodePoint CR_Grapheme_Cluster_Break_V[] = {
- 4,
- 0x1160, 0x11a7,
- 0xd7b0, 0xd7c6,
- 0x16d63, 0x16d63,
- 0x16d67, 0x16d6a,
-}; /* CR_Grapheme_Cluster_Break_V */
-
-/* 'Grapheme_Cluster_Break_T': Grapheme_Cluster_Break=T */
-static const OnigCodePoint CR_Grapheme_Cluster_Break_T[] = {
- 2,
- 0x11a8, 0x11ff,
- 0xd7cb, 0xd7fb,
-}; /* CR_Grapheme_Cluster_Break_T */
-
-/* 'Grapheme_Cluster_Break_LV': Grapheme_Cluster_Break=LV */
-static const OnigCodePoint CR_Grapheme_Cluster_Break_LV[] = {
- 399,
- 0xac00, 0xac00,
- 0xac1c, 0xac1c,
- 0xac38, 0xac38,
- 0xac54, 0xac54,
- 0xac70, 0xac70,
- 0xac8c, 0xac8c,
- 0xaca8, 0xaca8,
- 0xacc4, 0xacc4,
- 0xace0, 0xace0,
- 0xacfc, 0xacfc,
- 0xad18, 0xad18,
- 0xad34, 0xad34,
- 0xad50, 0xad50,
- 0xad6c, 0xad6c,
- 0xad88, 0xad88,
- 0xada4, 0xada4,
- 0xadc0, 0xadc0,
- 0xaddc, 0xaddc,
- 0xadf8, 0xadf8,
- 0xae14, 0xae14,
- 0xae30, 0xae30,
- 0xae4c, 0xae4c,
- 0xae68, 0xae68,
- 0xae84, 0xae84,
- 0xaea0, 0xaea0,
- 0xaebc, 0xaebc,
- 0xaed8, 0xaed8,
- 0xaef4, 0xaef4,
- 0xaf10, 0xaf10,
- 0xaf2c, 0xaf2c,
- 0xaf48, 0xaf48,
- 0xaf64, 0xaf64,
- 0xaf80, 0xaf80,
- 0xaf9c, 0xaf9c,
- 0xafb8, 0xafb8,
- 0xafd4, 0xafd4,
- 0xaff0, 0xaff0,
- 0xb00c, 0xb00c,
- 0xb028, 0xb028,
- 0xb044, 0xb044,
- 0xb060, 0xb060,
- 0xb07c, 0xb07c,
- 0xb098, 0xb098,
- 0xb0b4, 0xb0b4,
- 0xb0d0, 0xb0d0,
- 0xb0ec, 0xb0ec,
- 0xb108, 0xb108,
- 0xb124, 0xb124,
- 0xb140, 0xb140,
- 0xb15c, 0xb15c,
- 0xb178, 0xb178,
- 0xb194, 0xb194,
- 0xb1b0, 0xb1b0,
- 0xb1cc, 0xb1cc,
- 0xb1e8, 0xb1e8,
- 0xb204, 0xb204,
- 0xb220, 0xb220,
- 0xb23c, 0xb23c,
- 0xb258, 0xb258,
- 0xb274, 0xb274,
- 0xb290, 0xb290,
- 0xb2ac, 0xb2ac,
- 0xb2c8, 0xb2c8,
- 0xb2e4, 0xb2e4,
- 0xb300, 0xb300,
- 0xb31c, 0xb31c,
- 0xb338, 0xb338,
- 0xb354, 0xb354,
- 0xb370, 0xb370,
- 0xb38c, 0xb38c,
- 0xb3a8, 0xb3a8,
- 0xb3c4, 0xb3c4,
- 0xb3e0, 0xb3e0,
- 0xb3fc, 0xb3fc,
- 0xb418, 0xb418,
- 0xb434, 0xb434,
- 0xb450, 0xb450,
- 0xb46c, 0xb46c,
- 0xb488, 0xb488,
- 0xb4a4, 0xb4a4,
- 0xb4c0, 0xb4c0,
- 0xb4dc, 0xb4dc,
- 0xb4f8, 0xb4f8,
- 0xb514, 0xb514,
- 0xb530, 0xb530,
- 0xb54c, 0xb54c,
- 0xb568, 0xb568,
- 0xb584, 0xb584,
- 0xb5a0, 0xb5a0,
- 0xb5bc, 0xb5bc,
- 0xb5d8, 0xb5d8,
- 0xb5f4, 0xb5f4,
- 0xb610, 0xb610,
- 0xb62c, 0xb62c,
- 0xb648, 0xb648,
- 0xb664, 0xb664,
- 0xb680, 0xb680,
- 0xb69c, 0xb69c,
- 0xb6b8, 0xb6b8,
- 0xb6d4, 0xb6d4,
- 0xb6f0, 0xb6f0,
- 0xb70c, 0xb70c,
- 0xb728, 0xb728,
- 0xb744, 0xb744,
- 0xb760, 0xb760,
- 0xb77c, 0xb77c,
- 0xb798, 0xb798,
- 0xb7b4, 0xb7b4,
- 0xb7d0, 0xb7d0,
- 0xb7ec, 0xb7ec,
- 0xb808, 0xb808,
- 0xb824, 0xb824,
- 0xb840, 0xb840,
- 0xb85c, 0xb85c,
- 0xb878, 0xb878,
- 0xb894, 0xb894,
- 0xb8b0, 0xb8b0,
- 0xb8cc, 0xb8cc,
- 0xb8e8, 0xb8e8,
- 0xb904, 0xb904,
- 0xb920, 0xb920,
- 0xb93c, 0xb93c,
- 0xb958, 0xb958,
- 0xb974, 0xb974,
- 0xb990, 0xb990,
- 0xb9ac, 0xb9ac,
- 0xb9c8, 0xb9c8,
- 0xb9e4, 0xb9e4,
- 0xba00, 0xba00,
- 0xba1c, 0xba1c,
- 0xba38, 0xba38,
- 0xba54, 0xba54,
- 0xba70, 0xba70,
- 0xba8c, 0xba8c,
- 0xbaa8, 0xbaa8,
- 0xbac4, 0xbac4,
- 0xbae0, 0xbae0,
- 0xbafc, 0xbafc,
- 0xbb18, 0xbb18,
- 0xbb34, 0xbb34,
- 0xbb50, 0xbb50,
- 0xbb6c, 0xbb6c,
- 0xbb88, 0xbb88,
- 0xbba4, 0xbba4,
- 0xbbc0, 0xbbc0,
- 0xbbdc, 0xbbdc,
- 0xbbf8, 0xbbf8,
- 0xbc14, 0xbc14,
- 0xbc30, 0xbc30,
- 0xbc4c, 0xbc4c,
- 0xbc68, 0xbc68,
- 0xbc84, 0xbc84,
- 0xbca0, 0xbca0,
- 0xbcbc, 0xbcbc,
- 0xbcd8, 0xbcd8,
- 0xbcf4, 0xbcf4,
- 0xbd10, 0xbd10,
- 0xbd2c, 0xbd2c,
- 0xbd48, 0xbd48,
- 0xbd64, 0xbd64,
- 0xbd80, 0xbd80,
- 0xbd9c, 0xbd9c,
- 0xbdb8, 0xbdb8,
- 0xbdd4, 0xbdd4,
- 0xbdf0, 0xbdf0,
- 0xbe0c, 0xbe0c,
- 0xbe28, 0xbe28,
- 0xbe44, 0xbe44,
- 0xbe60, 0xbe60,
- 0xbe7c, 0xbe7c,
- 0xbe98, 0xbe98,
- 0xbeb4, 0xbeb4,
- 0xbed0, 0xbed0,
- 0xbeec, 0xbeec,
- 0xbf08, 0xbf08,
- 0xbf24, 0xbf24,
- 0xbf40, 0xbf40,
- 0xbf5c, 0xbf5c,
- 0xbf78, 0xbf78,
- 0xbf94, 0xbf94,
- 0xbfb0, 0xbfb0,
- 0xbfcc, 0xbfcc,
- 0xbfe8, 0xbfe8,
- 0xc004, 0xc004,
- 0xc020, 0xc020,
- 0xc03c, 0xc03c,
- 0xc058, 0xc058,
- 0xc074, 0xc074,
- 0xc090, 0xc090,
- 0xc0ac, 0xc0ac,
- 0xc0c8, 0xc0c8,
- 0xc0e4, 0xc0e4,
- 0xc100, 0xc100,
- 0xc11c, 0xc11c,
- 0xc138, 0xc138,
- 0xc154, 0xc154,
- 0xc170, 0xc170,
- 0xc18c, 0xc18c,
- 0xc1a8, 0xc1a8,
- 0xc1c4, 0xc1c4,
- 0xc1e0, 0xc1e0,
- 0xc1fc, 0xc1fc,
- 0xc218, 0xc218,
- 0xc234, 0xc234,
- 0xc250, 0xc250,
- 0xc26c, 0xc26c,
- 0xc288, 0xc288,
- 0xc2a4, 0xc2a4,
- 0xc2c0, 0xc2c0,
- 0xc2dc, 0xc2dc,
- 0xc2f8, 0xc2f8,
- 0xc314, 0xc314,
- 0xc330, 0xc330,
- 0xc34c, 0xc34c,
- 0xc368, 0xc368,
- 0xc384, 0xc384,
- 0xc3a0, 0xc3a0,
- 0xc3bc, 0xc3bc,
- 0xc3d8, 0xc3d8,
- 0xc3f4, 0xc3f4,
- 0xc410, 0xc410,
- 0xc42c, 0xc42c,
- 0xc448, 0xc448,
- 0xc464, 0xc464,
- 0xc480, 0xc480,
- 0xc49c, 0xc49c,
- 0xc4b8, 0xc4b8,
- 0xc4d4, 0xc4d4,
- 0xc4f0, 0xc4f0,
- 0xc50c, 0xc50c,
- 0xc528, 0xc528,
- 0xc544, 0xc544,
- 0xc560, 0xc560,
- 0xc57c, 0xc57c,
- 0xc598, 0xc598,
- 0xc5b4, 0xc5b4,
- 0xc5d0, 0xc5d0,
- 0xc5ec, 0xc5ec,
- 0xc608, 0xc608,
- 0xc624, 0xc624,
- 0xc640, 0xc640,
- 0xc65c, 0xc65c,
- 0xc678, 0xc678,
- 0xc694, 0xc694,
- 0xc6b0, 0xc6b0,
- 0xc6cc, 0xc6cc,
- 0xc6e8, 0xc6e8,
- 0xc704, 0xc704,
- 0xc720, 0xc720,
- 0xc73c, 0xc73c,
- 0xc758, 0xc758,
- 0xc774, 0xc774,
- 0xc790, 0xc790,
- 0xc7ac, 0xc7ac,
- 0xc7c8, 0xc7c8,
- 0xc7e4, 0xc7e4,
- 0xc800, 0xc800,
- 0xc81c, 0xc81c,
- 0xc838, 0xc838,
- 0xc854, 0xc854,
- 0xc870, 0xc870,
- 0xc88c, 0xc88c,
- 0xc8a8, 0xc8a8,
- 0xc8c4, 0xc8c4,
- 0xc8e0, 0xc8e0,
- 0xc8fc, 0xc8fc,
- 0xc918, 0xc918,
- 0xc934, 0xc934,
- 0xc950, 0xc950,
- 0xc96c, 0xc96c,
- 0xc988, 0xc988,
- 0xc9a4, 0xc9a4,
- 0xc9c0, 0xc9c0,
- 0xc9dc, 0xc9dc,
- 0xc9f8, 0xc9f8,
- 0xca14, 0xca14,
- 0xca30, 0xca30,
- 0xca4c, 0xca4c,
- 0xca68, 0xca68,
- 0xca84, 0xca84,
- 0xcaa0, 0xcaa0,
- 0xcabc, 0xcabc,
- 0xcad8, 0xcad8,
- 0xcaf4, 0xcaf4,
- 0xcb10, 0xcb10,
- 0xcb2c, 0xcb2c,
- 0xcb48, 0xcb48,
- 0xcb64, 0xcb64,
- 0xcb80, 0xcb80,
- 0xcb9c, 0xcb9c,
- 0xcbb8, 0xcbb8,
- 0xcbd4, 0xcbd4,
- 0xcbf0, 0xcbf0,
- 0xcc0c, 0xcc0c,
- 0xcc28, 0xcc28,
- 0xcc44, 0xcc44,
- 0xcc60, 0xcc60,
- 0xcc7c, 0xcc7c,
- 0xcc98, 0xcc98,
- 0xccb4, 0xccb4,
- 0xccd0, 0xccd0,
- 0xccec, 0xccec,
- 0xcd08, 0xcd08,
- 0xcd24, 0xcd24,
- 0xcd40, 0xcd40,
- 0xcd5c, 0xcd5c,
- 0xcd78, 0xcd78,
- 0xcd94, 0xcd94,
- 0xcdb0, 0xcdb0,
- 0xcdcc, 0xcdcc,
- 0xcde8, 0xcde8,
- 0xce04, 0xce04,
- 0xce20, 0xce20,
- 0xce3c, 0xce3c,
- 0xce58, 0xce58,
- 0xce74, 0xce74,
- 0xce90, 0xce90,
- 0xceac, 0xceac,
- 0xcec8, 0xcec8,
- 0xcee4, 0xcee4,
- 0xcf00, 0xcf00,
- 0xcf1c, 0xcf1c,
- 0xcf38, 0xcf38,
- 0xcf54, 0xcf54,
- 0xcf70, 0xcf70,
- 0xcf8c, 0xcf8c,
- 0xcfa8, 0xcfa8,
- 0xcfc4, 0xcfc4,
- 0xcfe0, 0xcfe0,
- 0xcffc, 0xcffc,
- 0xd018, 0xd018,
- 0xd034, 0xd034,
- 0xd050, 0xd050,
- 0xd06c, 0xd06c,
- 0xd088, 0xd088,
- 0xd0a4, 0xd0a4,
- 0xd0c0, 0xd0c0,
- 0xd0dc, 0xd0dc,
- 0xd0f8, 0xd0f8,
- 0xd114, 0xd114,
- 0xd130, 0xd130,
- 0xd14c, 0xd14c,
- 0xd168, 0xd168,
- 0xd184, 0xd184,
- 0xd1a0, 0xd1a0,
- 0xd1bc, 0xd1bc,
- 0xd1d8, 0xd1d8,
- 0xd1f4, 0xd1f4,
- 0xd210, 0xd210,
- 0xd22c, 0xd22c,
- 0xd248, 0xd248,
- 0xd264, 0xd264,
- 0xd280, 0xd280,
- 0xd29c, 0xd29c,
- 0xd2b8, 0xd2b8,
- 0xd2d4, 0xd2d4,
- 0xd2f0, 0xd2f0,
- 0xd30c, 0xd30c,
- 0xd328, 0xd328,
- 0xd344, 0xd344,
- 0xd360, 0xd360,
- 0xd37c, 0xd37c,
- 0xd398, 0xd398,
- 0xd3b4, 0xd3b4,
- 0xd3d0, 0xd3d0,
- 0xd3ec, 0xd3ec,
- 0xd408, 0xd408,
- 0xd424, 0xd424,
- 0xd440, 0xd440,
- 0xd45c, 0xd45c,
- 0xd478, 0xd478,
- 0xd494, 0xd494,
- 0xd4b0, 0xd4b0,
- 0xd4cc, 0xd4cc,
- 0xd4e8, 0xd4e8,
- 0xd504, 0xd504,
- 0xd520, 0xd520,
- 0xd53c, 0xd53c,
- 0xd558, 0xd558,
- 0xd574, 0xd574,
- 0xd590, 0xd590,
- 0xd5ac, 0xd5ac,
- 0xd5c8, 0xd5c8,
- 0xd5e4, 0xd5e4,
- 0xd600, 0xd600,
- 0xd61c, 0xd61c,
- 0xd638, 0xd638,
- 0xd654, 0xd654,
- 0xd670, 0xd670,
- 0xd68c, 0xd68c,
- 0xd6a8, 0xd6a8,
- 0xd6c4, 0xd6c4,
- 0xd6e0, 0xd6e0,
- 0xd6fc, 0xd6fc,
- 0xd718, 0xd718,
- 0xd734, 0xd734,
- 0xd750, 0xd750,
- 0xd76c, 0xd76c,
- 0xd788, 0xd788,
-}; /* CR_Grapheme_Cluster_Break_LV */
-
-/* 'Grapheme_Cluster_Break_LVT': Grapheme_Cluster_Break=LVT */
-static const OnigCodePoint CR_Grapheme_Cluster_Break_LVT[] = {
- 399,
- 0xac01, 0xac1b,
- 0xac1d, 0xac37,
- 0xac39, 0xac53,
- 0xac55, 0xac6f,
- 0xac71, 0xac8b,
- 0xac8d, 0xaca7,
- 0xaca9, 0xacc3,
- 0xacc5, 0xacdf,
- 0xace1, 0xacfb,
- 0xacfd, 0xad17,
- 0xad19, 0xad33,
- 0xad35, 0xad4f,
- 0xad51, 0xad6b,
- 0xad6d, 0xad87,
- 0xad89, 0xada3,
- 0xada5, 0xadbf,
- 0xadc1, 0xaddb,
- 0xaddd, 0xadf7,
- 0xadf9, 0xae13,
- 0xae15, 0xae2f,
- 0xae31, 0xae4b,
- 0xae4d, 0xae67,
- 0xae69, 0xae83,
- 0xae85, 0xae9f,
- 0xaea1, 0xaebb,
- 0xaebd, 0xaed7,
- 0xaed9, 0xaef3,
- 0xaef5, 0xaf0f,
- 0xaf11, 0xaf2b,
- 0xaf2d, 0xaf47,
- 0xaf49, 0xaf63,
- 0xaf65, 0xaf7f,
- 0xaf81, 0xaf9b,
- 0xaf9d, 0xafb7,
- 0xafb9, 0xafd3,
- 0xafd5, 0xafef,
- 0xaff1, 0xb00b,
- 0xb00d, 0xb027,
- 0xb029, 0xb043,
- 0xb045, 0xb05f,
- 0xb061, 0xb07b,
- 0xb07d, 0xb097,
- 0xb099, 0xb0b3,
- 0xb0b5, 0xb0cf,
- 0xb0d1, 0xb0eb,
- 0xb0ed, 0xb107,
- 0xb109, 0xb123,
- 0xb125, 0xb13f,
- 0xb141, 0xb15b,
- 0xb15d, 0xb177,
- 0xb179, 0xb193,
- 0xb195, 0xb1af,
- 0xb1b1, 0xb1cb,
- 0xb1cd, 0xb1e7,
- 0xb1e9, 0xb203,
- 0xb205, 0xb21f,
- 0xb221, 0xb23b,
- 0xb23d, 0xb257,
- 0xb259, 0xb273,
- 0xb275, 0xb28f,
- 0xb291, 0xb2ab,
- 0xb2ad, 0xb2c7,
- 0xb2c9, 0xb2e3,
- 0xb2e5, 0xb2ff,
- 0xb301, 0xb31b,
- 0xb31d, 0xb337,
- 0xb339, 0xb353,
- 0xb355, 0xb36f,
- 0xb371, 0xb38b,
- 0xb38d, 0xb3a7,
- 0xb3a9, 0xb3c3,
- 0xb3c5, 0xb3df,
- 0xb3e1, 0xb3fb,
- 0xb3fd, 0xb417,
- 0xb419, 0xb433,
- 0xb435, 0xb44f,
- 0xb451, 0xb46b,
- 0xb46d, 0xb487,
- 0xb489, 0xb4a3,
- 0xb4a5, 0xb4bf,
- 0xb4c1, 0xb4db,
- 0xb4dd, 0xb4f7,
- 0xb4f9, 0xb513,
- 0xb515, 0xb52f,
- 0xb531, 0xb54b,
- 0xb54d, 0xb567,
- 0xb569, 0xb583,
- 0xb585, 0xb59f,
- 0xb5a1, 0xb5bb,
- 0xb5bd, 0xb5d7,
- 0xb5d9, 0xb5f3,
- 0xb5f5, 0xb60f,
- 0xb611, 0xb62b,
- 0xb62d, 0xb647,
- 0xb649, 0xb663,
- 0xb665, 0xb67f,
- 0xb681, 0xb69b,
- 0xb69d, 0xb6b7,
- 0xb6b9, 0xb6d3,
- 0xb6d5, 0xb6ef,
- 0xb6f1, 0xb70b,
- 0xb70d, 0xb727,
- 0xb729, 0xb743,
- 0xb745, 0xb75f,
- 0xb761, 0xb77b,
- 0xb77d, 0xb797,
- 0xb799, 0xb7b3,
- 0xb7b5, 0xb7cf,
- 0xb7d1, 0xb7eb,
- 0xb7ed, 0xb807,
- 0xb809, 0xb823,
- 0xb825, 0xb83f,
- 0xb841, 0xb85b,
- 0xb85d, 0xb877,
- 0xb879, 0xb893,
- 0xb895, 0xb8af,
- 0xb8b1, 0xb8cb,
- 0xb8cd, 0xb8e7,
- 0xb8e9, 0xb903,
- 0xb905, 0xb91f,
- 0xb921, 0xb93b,
- 0xb93d, 0xb957,
- 0xb959, 0xb973,
- 0xb975, 0xb98f,
- 0xb991, 0xb9ab,
- 0xb9ad, 0xb9c7,
- 0xb9c9, 0xb9e3,
- 0xb9e5, 0xb9ff,
- 0xba01, 0xba1b,
- 0xba1d, 0xba37,
- 0xba39, 0xba53,
- 0xba55, 0xba6f,
- 0xba71, 0xba8b,
- 0xba8d, 0xbaa7,
- 0xbaa9, 0xbac3,
- 0xbac5, 0xbadf,
- 0xbae1, 0xbafb,
- 0xbafd, 0xbb17,
- 0xbb19, 0xbb33,
- 0xbb35, 0xbb4f,
- 0xbb51, 0xbb6b,
- 0xbb6d, 0xbb87,
- 0xbb89, 0xbba3,
- 0xbba5, 0xbbbf,
- 0xbbc1, 0xbbdb,
- 0xbbdd, 0xbbf7,
- 0xbbf9, 0xbc13,
- 0xbc15, 0xbc2f,
- 0xbc31, 0xbc4b,
- 0xbc4d, 0xbc67,
- 0xbc69, 0xbc83,
- 0xbc85, 0xbc9f,
- 0xbca1, 0xbcbb,
- 0xbcbd, 0xbcd7,
- 0xbcd9, 0xbcf3,
- 0xbcf5, 0xbd0f,
- 0xbd11, 0xbd2b,
- 0xbd2d, 0xbd47,
- 0xbd49, 0xbd63,
- 0xbd65, 0xbd7f,
- 0xbd81, 0xbd9b,
- 0xbd9d, 0xbdb7,
- 0xbdb9, 0xbdd3,
- 0xbdd5, 0xbdef,
- 0xbdf1, 0xbe0b,
- 0xbe0d, 0xbe27,
- 0xbe29, 0xbe43,
- 0xbe45, 0xbe5f,
- 0xbe61, 0xbe7b,
- 0xbe7d, 0xbe97,
- 0xbe99, 0xbeb3,
- 0xbeb5, 0xbecf,
- 0xbed1, 0xbeeb,
- 0xbeed, 0xbf07,
- 0xbf09, 0xbf23,
- 0xbf25, 0xbf3f,
- 0xbf41, 0xbf5b,
- 0xbf5d, 0xbf77,
- 0xbf79, 0xbf93,
- 0xbf95, 0xbfaf,
- 0xbfb1, 0xbfcb,
- 0xbfcd, 0xbfe7,
- 0xbfe9, 0xc003,
- 0xc005, 0xc01f,
- 0xc021, 0xc03b,
- 0xc03d, 0xc057,
- 0xc059, 0xc073,
- 0xc075, 0xc08f,
- 0xc091, 0xc0ab,
- 0xc0ad, 0xc0c7,
- 0xc0c9, 0xc0e3,
- 0xc0e5, 0xc0ff,
- 0xc101, 0xc11b,
- 0xc11d, 0xc137,
- 0xc139, 0xc153,
- 0xc155, 0xc16f,
- 0xc171, 0xc18b,
- 0xc18d, 0xc1a7,
- 0xc1a9, 0xc1c3,
- 0xc1c5, 0xc1df,
- 0xc1e1, 0xc1fb,
- 0xc1fd, 0xc217,
- 0xc219, 0xc233,
- 0xc235, 0xc24f,
- 0xc251, 0xc26b,
- 0xc26d, 0xc287,
- 0xc289, 0xc2a3,
- 0xc2a5, 0xc2bf,
- 0xc2c1, 0xc2db,
- 0xc2dd, 0xc2f7,
- 0xc2f9, 0xc313,
- 0xc315, 0xc32f,
- 0xc331, 0xc34b,
- 0xc34d, 0xc367,
- 0xc369, 0xc383,
- 0xc385, 0xc39f,
- 0xc3a1, 0xc3bb,
- 0xc3bd, 0xc3d7,
- 0xc3d9, 0xc3f3,
- 0xc3f5, 0xc40f,
- 0xc411, 0xc42b,
- 0xc42d, 0xc447,
- 0xc449, 0xc463,
- 0xc465, 0xc47f,
- 0xc481, 0xc49b,
- 0xc49d, 0xc4b7,
- 0xc4b9, 0xc4d3,
- 0xc4d5, 0xc4ef,
- 0xc4f1, 0xc50b,
- 0xc50d, 0xc527,
- 0xc529, 0xc543,
- 0xc545, 0xc55f,
- 0xc561, 0xc57b,
- 0xc57d, 0xc597,
- 0xc599, 0xc5b3,
- 0xc5b5, 0xc5cf,
- 0xc5d1, 0xc5eb,
- 0xc5ed, 0xc607,
- 0xc609, 0xc623,
- 0xc625, 0xc63f,
- 0xc641, 0xc65b,
- 0xc65d, 0xc677,
- 0xc679, 0xc693,
- 0xc695, 0xc6af,
- 0xc6b1, 0xc6cb,
- 0xc6cd, 0xc6e7,
- 0xc6e9, 0xc703,
- 0xc705, 0xc71f,
- 0xc721, 0xc73b,
- 0xc73d, 0xc757,
- 0xc759, 0xc773,
- 0xc775, 0xc78f,
- 0xc791, 0xc7ab,
- 0xc7ad, 0xc7c7,
- 0xc7c9, 0xc7e3,
- 0xc7e5, 0xc7ff,
- 0xc801, 0xc81b,
- 0xc81d, 0xc837,
- 0xc839, 0xc853,
- 0xc855, 0xc86f,
- 0xc871, 0xc88b,
- 0xc88d, 0xc8a7,
- 0xc8a9, 0xc8c3,
- 0xc8c5, 0xc8df,
- 0xc8e1, 0xc8fb,
- 0xc8fd, 0xc917,
- 0xc919, 0xc933,
- 0xc935, 0xc94f,
- 0xc951, 0xc96b,
- 0xc96d, 0xc987,
- 0xc989, 0xc9a3,
- 0xc9a5, 0xc9bf,
- 0xc9c1, 0xc9db,
- 0xc9dd, 0xc9f7,
- 0xc9f9, 0xca13,
- 0xca15, 0xca2f,
- 0xca31, 0xca4b,
- 0xca4d, 0xca67,
- 0xca69, 0xca83,
- 0xca85, 0xca9f,
- 0xcaa1, 0xcabb,
- 0xcabd, 0xcad7,
- 0xcad9, 0xcaf3,
- 0xcaf5, 0xcb0f,
- 0xcb11, 0xcb2b,
- 0xcb2d, 0xcb47,
- 0xcb49, 0xcb63,
- 0xcb65, 0xcb7f,
- 0xcb81, 0xcb9b,
- 0xcb9d, 0xcbb7,
- 0xcbb9, 0xcbd3,
- 0xcbd5, 0xcbef,
- 0xcbf1, 0xcc0b,
- 0xcc0d, 0xcc27,
- 0xcc29, 0xcc43,
- 0xcc45, 0xcc5f,
- 0xcc61, 0xcc7b,
- 0xcc7d, 0xcc97,
- 0xcc99, 0xccb3,
- 0xccb5, 0xcccf,
- 0xccd1, 0xcceb,
- 0xcced, 0xcd07,
- 0xcd09, 0xcd23,
- 0xcd25, 0xcd3f,
- 0xcd41, 0xcd5b,
- 0xcd5d, 0xcd77,
- 0xcd79, 0xcd93,
- 0xcd95, 0xcdaf,
- 0xcdb1, 0xcdcb,
- 0xcdcd, 0xcde7,
- 0xcde9, 0xce03,
- 0xce05, 0xce1f,
- 0xce21, 0xce3b,
- 0xce3d, 0xce57,
- 0xce59, 0xce73,
- 0xce75, 0xce8f,
- 0xce91, 0xceab,
- 0xcead, 0xcec7,
- 0xcec9, 0xcee3,
- 0xcee5, 0xceff,
- 0xcf01, 0xcf1b,
- 0xcf1d, 0xcf37,
- 0xcf39, 0xcf53,
- 0xcf55, 0xcf6f,
- 0xcf71, 0xcf8b,
- 0xcf8d, 0xcfa7,
- 0xcfa9, 0xcfc3,
- 0xcfc5, 0xcfdf,
- 0xcfe1, 0xcffb,
- 0xcffd, 0xd017,
- 0xd019, 0xd033,
- 0xd035, 0xd04f,
- 0xd051, 0xd06b,
- 0xd06d, 0xd087,
- 0xd089, 0xd0a3,
- 0xd0a5, 0xd0bf,
- 0xd0c1, 0xd0db,
- 0xd0dd, 0xd0f7,
- 0xd0f9, 0xd113,
- 0xd115, 0xd12f,
- 0xd131, 0xd14b,
- 0xd14d, 0xd167,
- 0xd169, 0xd183,
- 0xd185, 0xd19f,
- 0xd1a1, 0xd1bb,
- 0xd1bd, 0xd1d7,
- 0xd1d9, 0xd1f3,
- 0xd1f5, 0xd20f,
- 0xd211, 0xd22b,
- 0xd22d, 0xd247,
- 0xd249, 0xd263,
- 0xd265, 0xd27f,
- 0xd281, 0xd29b,
- 0xd29d, 0xd2b7,
- 0xd2b9, 0xd2d3,
- 0xd2d5, 0xd2ef,
- 0xd2f1, 0xd30b,
- 0xd30d, 0xd327,
- 0xd329, 0xd343,
- 0xd345, 0xd35f,
- 0xd361, 0xd37b,
- 0xd37d, 0xd397,
- 0xd399, 0xd3b3,
- 0xd3b5, 0xd3cf,
- 0xd3d1, 0xd3eb,
- 0xd3ed, 0xd407,
- 0xd409, 0xd423,
- 0xd425, 0xd43f,
- 0xd441, 0xd45b,
- 0xd45d, 0xd477,
- 0xd479, 0xd493,
- 0xd495, 0xd4af,
- 0xd4b1, 0xd4cb,
- 0xd4cd, 0xd4e7,
- 0xd4e9, 0xd503,
- 0xd505, 0xd51f,
- 0xd521, 0xd53b,
- 0xd53d, 0xd557,
- 0xd559, 0xd573,
- 0xd575, 0xd58f,
- 0xd591, 0xd5ab,
- 0xd5ad, 0xd5c7,
- 0xd5c9, 0xd5e3,
- 0xd5e5, 0xd5ff,
- 0xd601, 0xd61b,
- 0xd61d, 0xd637,
- 0xd639, 0xd653,
- 0xd655, 0xd66f,
- 0xd671, 0xd68b,
- 0xd68d, 0xd6a7,
- 0xd6a9, 0xd6c3,
- 0xd6c5, 0xd6df,
- 0xd6e1, 0xd6fb,
- 0xd6fd, 0xd717,
- 0xd719, 0xd733,
- 0xd735, 0xd74f,
- 0xd751, 0xd76b,
- 0xd76d, 0xd787,
- 0xd789, 0xd7a3,
-}; /* CR_Grapheme_Cluster_Break_LVT */
-
-/* 'Grapheme_Cluster_Break_ZWJ': Grapheme_Cluster_Break=ZWJ */
-static const OnigCodePoint CR_Grapheme_Cluster_Break_ZWJ[] = {
- 1,
- 0x200d, 0x200d,
-}; /* CR_Grapheme_Cluster_Break_ZWJ */
-
-/* 'In_Basic_Latin': Block */
-#define CR_In_Basic_Latin CR_ASCII
-
-/* 'In_Latin_1_Supplement': Block */
-static const OnigCodePoint CR_In_Latin_1_Supplement[] = {
- 1,
- 0x0080, 0x00ff,
-}; /* CR_In_Latin_1_Supplement */
-
-/* 'In_Latin_Extended_A': Block */
-static const OnigCodePoint CR_In_Latin_Extended_A[] = {
- 1,
- 0x0100, 0x017f,
-}; /* CR_In_Latin_Extended_A */
-
-/* 'In_Latin_Extended_B': Block */
-static const OnigCodePoint CR_In_Latin_Extended_B[] = {
- 1,
- 0x0180, 0x024f,
-}; /* CR_In_Latin_Extended_B */
-
-/* 'In_IPA_Extensions': Block */
-static const OnigCodePoint CR_In_IPA_Extensions[] = {
- 1,
- 0x0250, 0x02af,
-}; /* CR_In_IPA_Extensions */
-
-/* 'In_Spacing_Modifier_Letters': Block */
-static const OnigCodePoint CR_In_Spacing_Modifier_Letters[] = {
- 1,
- 0x02b0, 0x02ff,
-}; /* CR_In_Spacing_Modifier_Letters */
-
-/* 'In_Combining_Diacritical_Marks': Block */
-static const OnigCodePoint CR_In_Combining_Diacritical_Marks[] = {
- 1,
- 0x0300, 0x036f,
-}; /* CR_In_Combining_Diacritical_Marks */
-
-/* 'In_Greek_and_Coptic': Block */
-static const OnigCodePoint CR_In_Greek_and_Coptic[] = {
- 1,
- 0x0370, 0x03ff,
-}; /* CR_In_Greek_and_Coptic */
-
-/* 'In_Cyrillic': Block */
-static const OnigCodePoint CR_In_Cyrillic[] = {
- 1,
- 0x0400, 0x04ff,
-}; /* CR_In_Cyrillic */
-
-/* 'In_Cyrillic_Supplement': Block */
-static const OnigCodePoint CR_In_Cyrillic_Supplement[] = {
- 1,
- 0x0500, 0x052f,
-}; /* CR_In_Cyrillic_Supplement */
-
-/* 'In_Armenian': Block */
-static const OnigCodePoint CR_In_Armenian[] = {
- 1,
- 0x0530, 0x058f,
-}; /* CR_In_Armenian */
-
-/* 'In_Hebrew': Block */
-static const OnigCodePoint CR_In_Hebrew[] = {
- 1,
- 0x0590, 0x05ff,
-}; /* CR_In_Hebrew */
-
-/* 'In_Arabic': Block */
-static const OnigCodePoint CR_In_Arabic[] = {
- 1,
- 0x0600, 0x06ff,
-}; /* CR_In_Arabic */
-
-/* 'In_Syriac': Block */
-static const OnigCodePoint CR_In_Syriac[] = {
- 1,
- 0x0700, 0x074f,
-}; /* CR_In_Syriac */
-
-/* 'In_Arabic_Supplement': Block */
-static const OnigCodePoint CR_In_Arabic_Supplement[] = {
- 1,
- 0x0750, 0x077f,
-}; /* CR_In_Arabic_Supplement */
-
-/* 'In_Thaana': Block */
-static const OnigCodePoint CR_In_Thaana[] = {
- 1,
- 0x0780, 0x07bf,
-}; /* CR_In_Thaana */
-
-/* 'In_NKo': Block */
-static const OnigCodePoint CR_In_NKo[] = {
- 1,
- 0x07c0, 0x07ff,
-}; /* CR_In_NKo */
-
-/* 'In_Samaritan': Block */
-static const OnigCodePoint CR_In_Samaritan[] = {
- 1,
- 0x0800, 0x083f,
-}; /* CR_In_Samaritan */
-
-/* 'In_Mandaic': Block */
-static const OnigCodePoint CR_In_Mandaic[] = {
- 1,
- 0x0840, 0x085f,
-}; /* CR_In_Mandaic */
-
-/* 'In_Syriac_Supplement': Block */
-static const OnigCodePoint CR_In_Syriac_Supplement[] = {
- 1,
- 0x0860, 0x086f,
-}; /* CR_In_Syriac_Supplement */
-
-/* 'In_Arabic_Extended_B': Block */
-static const OnigCodePoint CR_In_Arabic_Extended_B[] = {
- 1,
- 0x0870, 0x089f,
-}; /* CR_In_Arabic_Extended_B */
-
-/* 'In_Arabic_Extended_A': Block */
-static const OnigCodePoint CR_In_Arabic_Extended_A[] = {
- 1,
- 0x08a0, 0x08ff,
-}; /* CR_In_Arabic_Extended_A */
-
-/* 'In_Devanagari': Block */
-static const OnigCodePoint CR_In_Devanagari[] = {
- 1,
- 0x0900, 0x097f,
-}; /* CR_In_Devanagari */
-
-/* 'In_Bengali': Block */
-static const OnigCodePoint CR_In_Bengali[] = {
- 1,
- 0x0980, 0x09ff,
-}; /* CR_In_Bengali */
-
-/* 'In_Gurmukhi': Block */
-static const OnigCodePoint CR_In_Gurmukhi[] = {
- 1,
- 0x0a00, 0x0a7f,
-}; /* CR_In_Gurmukhi */
-
-/* 'In_Gujarati': Block */
-static const OnigCodePoint CR_In_Gujarati[] = {
- 1,
- 0x0a80, 0x0aff,
-}; /* CR_In_Gujarati */
-
-/* 'In_Oriya': Block */
-static const OnigCodePoint CR_In_Oriya[] = {
- 1,
- 0x0b00, 0x0b7f,
-}; /* CR_In_Oriya */
-
-/* 'In_Tamil': Block */
-static const OnigCodePoint CR_In_Tamil[] = {
- 1,
- 0x0b80, 0x0bff,
-}; /* CR_In_Tamil */
-
-/* 'In_Telugu': Block */
-static const OnigCodePoint CR_In_Telugu[] = {
- 1,
- 0x0c00, 0x0c7f,
-}; /* CR_In_Telugu */
-
-/* 'In_Kannada': Block */
-static const OnigCodePoint CR_In_Kannada[] = {
- 1,
- 0x0c80, 0x0cff,
-}; /* CR_In_Kannada */
-
-/* 'In_Malayalam': Block */
-static const OnigCodePoint CR_In_Malayalam[] = {
- 1,
- 0x0d00, 0x0d7f,
-}; /* CR_In_Malayalam */
-
-/* 'In_Sinhala': Block */
-static const OnigCodePoint CR_In_Sinhala[] = {
- 1,
- 0x0d80, 0x0dff,
-}; /* CR_In_Sinhala */
-
-/* 'In_Thai': Block */
-static const OnigCodePoint CR_In_Thai[] = {
- 1,
- 0x0e00, 0x0e7f,
-}; /* CR_In_Thai */
-
-/* 'In_Lao': Block */
-static const OnigCodePoint CR_In_Lao[] = {
- 1,
- 0x0e80, 0x0eff,
-}; /* CR_In_Lao */
-
-/* 'In_Tibetan': Block */
-static const OnigCodePoint CR_In_Tibetan[] = {
- 1,
- 0x0f00, 0x0fff,
-}; /* CR_In_Tibetan */
-
-/* 'In_Myanmar': Block */
-static const OnigCodePoint CR_In_Myanmar[] = {
- 1,
- 0x1000, 0x109f,
-}; /* CR_In_Myanmar */
-
-/* 'In_Georgian': Block */
-static const OnigCodePoint CR_In_Georgian[] = {
- 1,
- 0x10a0, 0x10ff,
-}; /* CR_In_Georgian */
-
-/* 'In_Hangul_Jamo': Block */
-static const OnigCodePoint CR_In_Hangul_Jamo[] = {
- 1,
- 0x1100, 0x11ff,
-}; /* CR_In_Hangul_Jamo */
-
-/* 'In_Ethiopic': Block */
-static const OnigCodePoint CR_In_Ethiopic[] = {
- 1,
- 0x1200, 0x137f,
-}; /* CR_In_Ethiopic */
-
-/* 'In_Ethiopic_Supplement': Block */
-static const OnigCodePoint CR_In_Ethiopic_Supplement[] = {
- 1,
- 0x1380, 0x139f,
-}; /* CR_In_Ethiopic_Supplement */
-
-/* 'In_Cherokee': Block */
-static const OnigCodePoint CR_In_Cherokee[] = {
- 1,
- 0x13a0, 0x13ff,
-}; /* CR_In_Cherokee */
-
-/* 'In_Unified_Canadian_Aboriginal_Syllabics': Block */
-static const OnigCodePoint CR_In_Unified_Canadian_Aboriginal_Syllabics[] = {
- 1,
- 0x1400, 0x167f,
-}; /* CR_In_Unified_Canadian_Aboriginal_Syllabics */
-
-/* 'In_Ogham': Block */
-static const OnigCodePoint CR_In_Ogham[] = {
- 1,
- 0x1680, 0x169f,
-}; /* CR_In_Ogham */
-
-/* 'In_Runic': Block */
-static const OnigCodePoint CR_In_Runic[] = {
- 1,
- 0x16a0, 0x16ff,
-}; /* CR_In_Runic */
-
-/* 'In_Tagalog': Block */
-static const OnigCodePoint CR_In_Tagalog[] = {
- 1,
- 0x1700, 0x171f,
-}; /* CR_In_Tagalog */
-
-/* 'In_Hanunoo': Block */
-static const OnigCodePoint CR_In_Hanunoo[] = {
- 1,
- 0x1720, 0x173f,
-}; /* CR_In_Hanunoo */
-
-/* 'In_Buhid': Block */
-static const OnigCodePoint CR_In_Buhid[] = {
- 1,
- 0x1740, 0x175f,
-}; /* CR_In_Buhid */
-
-/* 'In_Tagbanwa': Block */
-static const OnigCodePoint CR_In_Tagbanwa[] = {
- 1,
- 0x1760, 0x177f,
-}; /* CR_In_Tagbanwa */
-
-/* 'In_Khmer': Block */
-static const OnigCodePoint CR_In_Khmer[] = {
- 1,
- 0x1780, 0x17ff,
-}; /* CR_In_Khmer */
-
-/* 'In_Mongolian': Block */
-static const OnigCodePoint CR_In_Mongolian[] = {
- 1,
- 0x1800, 0x18af,
-}; /* CR_In_Mongolian */
-
-/* 'In_Unified_Canadian_Aboriginal_Syllabics_Extended': Block */
-static const OnigCodePoint CR_In_Unified_Canadian_Aboriginal_Syllabics_Extended[] = {
- 1,
- 0x18b0, 0x18ff,
-}; /* CR_In_Unified_Canadian_Aboriginal_Syllabics_Extended */
-
-/* 'In_Limbu': Block */
-static const OnigCodePoint CR_In_Limbu[] = {
- 1,
- 0x1900, 0x194f,
-}; /* CR_In_Limbu */
-
-/* 'In_Tai_Le': Block */
-static const OnigCodePoint CR_In_Tai_Le[] = {
- 1,
- 0x1950, 0x197f,
-}; /* CR_In_Tai_Le */
-
-/* 'In_New_Tai_Lue': Block */
-static const OnigCodePoint CR_In_New_Tai_Lue[] = {
- 1,
- 0x1980, 0x19df,
-}; /* CR_In_New_Tai_Lue */
-
-/* 'In_Khmer_Symbols': Block */
-static const OnigCodePoint CR_In_Khmer_Symbols[] = {
- 1,
- 0x19e0, 0x19ff,
-}; /* CR_In_Khmer_Symbols */
-
-/* 'In_Buginese': Block */
-static const OnigCodePoint CR_In_Buginese[] = {
- 1,
- 0x1a00, 0x1a1f,
-}; /* CR_In_Buginese */
-
-/* 'In_Tai_Tham': Block */
-static const OnigCodePoint CR_In_Tai_Tham[] = {
- 1,
- 0x1a20, 0x1aaf,
-}; /* CR_In_Tai_Tham */
-
-/* 'In_Combining_Diacritical_Marks_Extended': Block */
-static const OnigCodePoint CR_In_Combining_Diacritical_Marks_Extended[] = {
- 1,
- 0x1ab0, 0x1aff,
-}; /* CR_In_Combining_Diacritical_Marks_Extended */
-
-/* 'In_Balinese': Block */
-static const OnigCodePoint CR_In_Balinese[] = {
- 1,
- 0x1b00, 0x1b7f,
-}; /* CR_In_Balinese */
-
-/* 'In_Sundanese': Block */
-static const OnigCodePoint CR_In_Sundanese[] = {
- 1,
- 0x1b80, 0x1bbf,
-}; /* CR_In_Sundanese */
-
-/* 'In_Batak': Block */
-static const OnigCodePoint CR_In_Batak[] = {
- 1,
- 0x1bc0, 0x1bff,
-}; /* CR_In_Batak */
-
-/* 'In_Lepcha': Block */
-static const OnigCodePoint CR_In_Lepcha[] = {
- 1,
- 0x1c00, 0x1c4f,
-}; /* CR_In_Lepcha */
-
-/* 'In_Ol_Chiki': Block */
-#define CR_In_Ol_Chiki CR_Ol_Chiki
-
-/* 'In_Cyrillic_Extended_C': Block */
-static const OnigCodePoint CR_In_Cyrillic_Extended_C[] = {
- 1,
- 0x1c80, 0x1c8f,
-}; /* CR_In_Cyrillic_Extended_C */
-
-/* 'In_Georgian_Extended': Block */
-static const OnigCodePoint CR_In_Georgian_Extended[] = {
- 1,
- 0x1c90, 0x1cbf,
-}; /* CR_In_Georgian_Extended */
-
-/* 'In_Sundanese_Supplement': Block */
-static const OnigCodePoint CR_In_Sundanese_Supplement[] = {
- 1,
- 0x1cc0, 0x1ccf,
-}; /* CR_In_Sundanese_Supplement */
-
-/* 'In_Vedic_Extensions': Block */
-static const OnigCodePoint CR_In_Vedic_Extensions[] = {
- 1,
- 0x1cd0, 0x1cff,
-}; /* CR_In_Vedic_Extensions */
-
-/* 'In_Phonetic_Extensions': Block */
-static const OnigCodePoint CR_In_Phonetic_Extensions[] = {
- 1,
- 0x1d00, 0x1d7f,
-}; /* CR_In_Phonetic_Extensions */
-
-/* 'In_Phonetic_Extensions_Supplement': Block */
-static const OnigCodePoint CR_In_Phonetic_Extensions_Supplement[] = {
- 1,
- 0x1d80, 0x1dbf,
-}; /* CR_In_Phonetic_Extensions_Supplement */
-
-/* 'In_Combining_Diacritical_Marks_Supplement': Block */
-static const OnigCodePoint CR_In_Combining_Diacritical_Marks_Supplement[] = {
- 1,
- 0x1dc0, 0x1dff,
-}; /* CR_In_Combining_Diacritical_Marks_Supplement */
-
-/* 'In_Latin_Extended_Additional': Block */
-static const OnigCodePoint CR_In_Latin_Extended_Additional[] = {
- 1,
- 0x1e00, 0x1eff,
-}; /* CR_In_Latin_Extended_Additional */
-
-/* 'In_Greek_Extended': Block */
-static const OnigCodePoint CR_In_Greek_Extended[] = {
- 1,
- 0x1f00, 0x1fff,
-}; /* CR_In_Greek_Extended */
-
-/* 'In_General_Punctuation': Block */
-static const OnigCodePoint CR_In_General_Punctuation[] = {
- 1,
- 0x2000, 0x206f,
-}; /* CR_In_General_Punctuation */
-
-/* 'In_Superscripts_and_Subscripts': Block */
-static const OnigCodePoint CR_In_Superscripts_and_Subscripts[] = {
- 1,
- 0x2070, 0x209f,
-}; /* CR_In_Superscripts_and_Subscripts */
-
-/* 'In_Currency_Symbols': Block */
-static const OnigCodePoint CR_In_Currency_Symbols[] = {
- 1,
- 0x20a0, 0x20cf,
-}; /* CR_In_Currency_Symbols */
-
-/* 'In_Combining_Diacritical_Marks_for_Symbols': Block */
-static const OnigCodePoint CR_In_Combining_Diacritical_Marks_for_Symbols[] = {
- 1,
- 0x20d0, 0x20ff,
-}; /* CR_In_Combining_Diacritical_Marks_for_Symbols */
-
-/* 'In_Letterlike_Symbols': Block */
-static const OnigCodePoint CR_In_Letterlike_Symbols[] = {
- 1,
- 0x2100, 0x214f,
-}; /* CR_In_Letterlike_Symbols */
-
-/* 'In_Number_Forms': Block */
-static const OnigCodePoint CR_In_Number_Forms[] = {
- 1,
- 0x2150, 0x218f,
-}; /* CR_In_Number_Forms */
-
-/* 'In_Arrows': Block */
-static const OnigCodePoint CR_In_Arrows[] = {
- 1,
- 0x2190, 0x21ff,
-}; /* CR_In_Arrows */
-
-/* 'In_Mathematical_Operators': Block */
-static const OnigCodePoint CR_In_Mathematical_Operators[] = {
- 1,
- 0x2200, 0x22ff,
-}; /* CR_In_Mathematical_Operators */
-
-/* 'In_Miscellaneous_Technical': Block */
-static const OnigCodePoint CR_In_Miscellaneous_Technical[] = {
- 1,
- 0x2300, 0x23ff,
-}; /* CR_In_Miscellaneous_Technical */
-
-/* 'In_Control_Pictures': Block */
-static const OnigCodePoint CR_In_Control_Pictures[] = {
- 1,
- 0x2400, 0x243f,
-}; /* CR_In_Control_Pictures */
-
-/* 'In_Optical_Character_Recognition': Block */
-static const OnigCodePoint CR_In_Optical_Character_Recognition[] = {
- 1,
- 0x2440, 0x245f,
-}; /* CR_In_Optical_Character_Recognition */
-
-/* 'In_Enclosed_Alphanumerics': Block */
-static const OnigCodePoint CR_In_Enclosed_Alphanumerics[] = {
- 1,
- 0x2460, 0x24ff,
-}; /* CR_In_Enclosed_Alphanumerics */
-
-/* 'In_Box_Drawing': Block */
-static const OnigCodePoint CR_In_Box_Drawing[] = {
- 1,
- 0x2500, 0x257f,
-}; /* CR_In_Box_Drawing */
-
-/* 'In_Block_Elements': Block */
-static const OnigCodePoint CR_In_Block_Elements[] = {
- 1,
- 0x2580, 0x259f,
-}; /* CR_In_Block_Elements */
-
-/* 'In_Geometric_Shapes': Block */
-static const OnigCodePoint CR_In_Geometric_Shapes[] = {
- 1,
- 0x25a0, 0x25ff,
-}; /* CR_In_Geometric_Shapes */
-
-/* 'In_Miscellaneous_Symbols': Block */
-static const OnigCodePoint CR_In_Miscellaneous_Symbols[] = {
- 1,
- 0x2600, 0x26ff,
-}; /* CR_In_Miscellaneous_Symbols */
-
-/* 'In_Dingbats': Block */
-static const OnigCodePoint CR_In_Dingbats[] = {
- 1,
- 0x2700, 0x27bf,
-}; /* CR_In_Dingbats */
-
-/* 'In_Miscellaneous_Mathematical_Symbols_A': Block */
-static const OnigCodePoint CR_In_Miscellaneous_Mathematical_Symbols_A[] = {
- 1,
- 0x27c0, 0x27ef,
-}; /* CR_In_Miscellaneous_Mathematical_Symbols_A */
-
-/* 'In_Supplemental_Arrows_A': Block */
-static const OnigCodePoint CR_In_Supplemental_Arrows_A[] = {
- 1,
- 0x27f0, 0x27ff,
-}; /* CR_In_Supplemental_Arrows_A */
-
-/* 'In_Braille_Patterns': Block */
-#define CR_In_Braille_Patterns CR_Braille
-
-/* 'In_Supplemental_Arrows_B': Block */
-static const OnigCodePoint CR_In_Supplemental_Arrows_B[] = {
- 1,
- 0x2900, 0x297f,
-}; /* CR_In_Supplemental_Arrows_B */
-
-/* 'In_Miscellaneous_Mathematical_Symbols_B': Block */
-static const OnigCodePoint CR_In_Miscellaneous_Mathematical_Symbols_B[] = {
- 1,
- 0x2980, 0x29ff,
-}; /* CR_In_Miscellaneous_Mathematical_Symbols_B */
-
-/* 'In_Supplemental_Mathematical_Operators': Block */
-static const OnigCodePoint CR_In_Supplemental_Mathematical_Operators[] = {
- 1,
- 0x2a00, 0x2aff,
-}; /* CR_In_Supplemental_Mathematical_Operators */
-
-/* 'In_Miscellaneous_Symbols_and_Arrows': Block */
-static const OnigCodePoint CR_In_Miscellaneous_Symbols_and_Arrows[] = {
- 1,
- 0x2b00, 0x2bff,
-}; /* CR_In_Miscellaneous_Symbols_and_Arrows */
-
-/* 'In_Glagolitic': Block */
-static const OnigCodePoint CR_In_Glagolitic[] = {
- 1,
- 0x2c00, 0x2c5f,
-}; /* CR_In_Glagolitic */
-
-/* 'In_Latin_Extended_C': Block */
-static const OnigCodePoint CR_In_Latin_Extended_C[] = {
- 1,
- 0x2c60, 0x2c7f,
-}; /* CR_In_Latin_Extended_C */
-
-/* 'In_Coptic': Block */
-static const OnigCodePoint CR_In_Coptic[] = {
- 1,
- 0x2c80, 0x2cff,
-}; /* CR_In_Coptic */
-
-/* 'In_Georgian_Supplement': Block */
-static const OnigCodePoint CR_In_Georgian_Supplement[] = {
- 1,
- 0x2d00, 0x2d2f,
-}; /* CR_In_Georgian_Supplement */
-
-/* 'In_Tifinagh': Block */
-static const OnigCodePoint CR_In_Tifinagh[] = {
- 1,
- 0x2d30, 0x2d7f,
-}; /* CR_In_Tifinagh */
-
-/* 'In_Ethiopic_Extended': Block */
-static const OnigCodePoint CR_In_Ethiopic_Extended[] = {
- 1,
- 0x2d80, 0x2ddf,
-}; /* CR_In_Ethiopic_Extended */
-
-/* 'In_Cyrillic_Extended_A': Block */
-static const OnigCodePoint CR_In_Cyrillic_Extended_A[] = {
- 1,
- 0x2de0, 0x2dff,
-}; /* CR_In_Cyrillic_Extended_A */
-
-/* 'In_Supplemental_Punctuation': Block */
-static const OnigCodePoint CR_In_Supplemental_Punctuation[] = {
- 1,
- 0x2e00, 0x2e7f,
-}; /* CR_In_Supplemental_Punctuation */
-
-/* 'In_CJK_Radicals_Supplement': Block */
-static const OnigCodePoint CR_In_CJK_Radicals_Supplement[] = {
- 1,
- 0x2e80, 0x2eff,
-}; /* CR_In_CJK_Radicals_Supplement */
-
-/* 'In_Kangxi_Radicals': Block */
-static const OnigCodePoint CR_In_Kangxi_Radicals[] = {
- 1,
- 0x2f00, 0x2fdf,
-}; /* CR_In_Kangxi_Radicals */
-
-/* 'In_Ideographic_Description_Characters': Block */
-static const OnigCodePoint CR_In_Ideographic_Description_Characters[] = {
- 1,
- 0x2ff0, 0x2fff,
-}; /* CR_In_Ideographic_Description_Characters */
-
-/* 'In_CJK_Symbols_and_Punctuation': Block */
-static const OnigCodePoint CR_In_CJK_Symbols_and_Punctuation[] = {
- 1,
- 0x3000, 0x303f,
-}; /* CR_In_CJK_Symbols_and_Punctuation */
-
-/* 'In_Hiragana': Block */
-static const OnigCodePoint CR_In_Hiragana[] = {
- 1,
- 0x3040, 0x309f,
-}; /* CR_In_Hiragana */
-
-/* 'In_Katakana': Block */
-static const OnigCodePoint CR_In_Katakana[] = {
- 1,
- 0x30a0, 0x30ff,
-}; /* CR_In_Katakana */
-
-/* 'In_Bopomofo': Block */
-static const OnigCodePoint CR_In_Bopomofo[] = {
- 1,
- 0x3100, 0x312f,
-}; /* CR_In_Bopomofo */
-
-/* 'In_Hangul_Compatibility_Jamo': Block */
-static const OnigCodePoint CR_In_Hangul_Compatibility_Jamo[] = {
- 1,
- 0x3130, 0x318f,
-}; /* CR_In_Hangul_Compatibility_Jamo */
-
-/* 'In_Kanbun': Block */
-static const OnigCodePoint CR_In_Kanbun[] = {
- 1,
- 0x3190, 0x319f,
-}; /* CR_In_Kanbun */
-
-/* 'In_Bopomofo_Extended': Block */
-static const OnigCodePoint CR_In_Bopomofo_Extended[] = {
- 1,
- 0x31a0, 0x31bf,
-}; /* CR_In_Bopomofo_Extended */
-
-/* 'In_CJK_Strokes': Block */
-static const OnigCodePoint CR_In_CJK_Strokes[] = {
- 1,
- 0x31c0, 0x31ef,
-}; /* CR_In_CJK_Strokes */
-
-/* 'In_Katakana_Phonetic_Extensions': Block */
-static const OnigCodePoint CR_In_Katakana_Phonetic_Extensions[] = {
- 1,
- 0x31f0, 0x31ff,
-}; /* CR_In_Katakana_Phonetic_Extensions */
-
-/* 'In_Enclosed_CJK_Letters_and_Months': Block */
-static const OnigCodePoint CR_In_Enclosed_CJK_Letters_and_Months[] = {
- 1,
- 0x3200, 0x32ff,
-}; /* CR_In_Enclosed_CJK_Letters_and_Months */
-
-/* 'In_CJK_Compatibility': Block */
-static const OnigCodePoint CR_In_CJK_Compatibility[] = {
- 1,
- 0x3300, 0x33ff,
-}; /* CR_In_CJK_Compatibility */
-
-/* 'In_CJK_Unified_Ideographs_Extension_A': Block */
-static const OnigCodePoint CR_In_CJK_Unified_Ideographs_Extension_A[] = {
- 1,
- 0x3400, 0x4dbf,
-}; /* CR_In_CJK_Unified_Ideographs_Extension_A */
-
-/* 'In_Yijing_Hexagram_Symbols': Block */
-static const OnigCodePoint CR_In_Yijing_Hexagram_Symbols[] = {
- 1,
- 0x4dc0, 0x4dff,
-}; /* CR_In_Yijing_Hexagram_Symbols */
-
-/* 'In_CJK_Unified_Ideographs': Block */
-static const OnigCodePoint CR_In_CJK_Unified_Ideographs[] = {
- 1,
- 0x4e00, 0x9fff,
-}; /* CR_In_CJK_Unified_Ideographs */
-
-/* 'In_Yi_Syllables': Block */
-static const OnigCodePoint CR_In_Yi_Syllables[] = {
- 1,
- 0xa000, 0xa48f,
-}; /* CR_In_Yi_Syllables */
-
-/* 'In_Yi_Radicals': Block */
-static const OnigCodePoint CR_In_Yi_Radicals[] = {
- 1,
- 0xa490, 0xa4cf,
-}; /* CR_In_Yi_Radicals */
-
-/* 'In_Lisu': Block */
-static const OnigCodePoint CR_In_Lisu[] = {
- 1,
- 0xa4d0, 0xa4ff,
-}; /* CR_In_Lisu */
-
-/* 'In_Vai': Block */
-static const OnigCodePoint CR_In_Vai[] = {
- 1,
- 0xa500, 0xa63f,
-}; /* CR_In_Vai */
-
-/* 'In_Cyrillic_Extended_B': Block */
-static const OnigCodePoint CR_In_Cyrillic_Extended_B[] = {
- 1,
- 0xa640, 0xa69f,
-}; /* CR_In_Cyrillic_Extended_B */
-
-/* 'In_Bamum': Block */
-static const OnigCodePoint CR_In_Bamum[] = {
- 1,
- 0xa6a0, 0xa6ff,
-}; /* CR_In_Bamum */
-
-/* 'In_Modifier_Tone_Letters': Block */
-static const OnigCodePoint CR_In_Modifier_Tone_Letters[] = {
- 1,
- 0xa700, 0xa71f,
-}; /* CR_In_Modifier_Tone_Letters */
-
-/* 'In_Latin_Extended_D': Block */
-static const OnigCodePoint CR_In_Latin_Extended_D[] = {
- 1,
- 0xa720, 0xa7ff,
-}; /* CR_In_Latin_Extended_D */
-
-/* 'In_Syloti_Nagri': Block */
-static const OnigCodePoint CR_In_Syloti_Nagri[] = {
- 1,
- 0xa800, 0xa82f,
-}; /* CR_In_Syloti_Nagri */
-
-/* 'In_Common_Indic_Number_Forms': Block */
-static const OnigCodePoint CR_In_Common_Indic_Number_Forms[] = {
- 1,
- 0xa830, 0xa83f,
-}; /* CR_In_Common_Indic_Number_Forms */
-
-/* 'In_Phags_pa': Block */
-static const OnigCodePoint CR_In_Phags_pa[] = {
- 1,
- 0xa840, 0xa87f,
-}; /* CR_In_Phags_pa */
-
-/* 'In_Saurashtra': Block */
-static const OnigCodePoint CR_In_Saurashtra[] = {
- 1,
- 0xa880, 0xa8df,
-}; /* CR_In_Saurashtra */
-
-/* 'In_Devanagari_Extended': Block */
-static const OnigCodePoint CR_In_Devanagari_Extended[] = {
- 1,
- 0xa8e0, 0xa8ff,
-}; /* CR_In_Devanagari_Extended */
-
-/* 'In_Kayah_Li': Block */
-static const OnigCodePoint CR_In_Kayah_Li[] = {
- 1,
- 0xa900, 0xa92f,
-}; /* CR_In_Kayah_Li */
-
-/* 'In_Rejang': Block */
-static const OnigCodePoint CR_In_Rejang[] = {
- 1,
- 0xa930, 0xa95f,
-}; /* CR_In_Rejang */
-
-/* 'In_Hangul_Jamo_Extended_A': Block */
-static const OnigCodePoint CR_In_Hangul_Jamo_Extended_A[] = {
- 1,
- 0xa960, 0xa97f,
-}; /* CR_In_Hangul_Jamo_Extended_A */
-
-/* 'In_Javanese': Block */
-static const OnigCodePoint CR_In_Javanese[] = {
- 1,
- 0xa980, 0xa9df,
-}; /* CR_In_Javanese */
-
-/* 'In_Myanmar_Extended_B': Block */
-static const OnigCodePoint CR_In_Myanmar_Extended_B[] = {
- 1,
- 0xa9e0, 0xa9ff,
-}; /* CR_In_Myanmar_Extended_B */
-
-/* 'In_Cham': Block */
-static const OnigCodePoint CR_In_Cham[] = {
- 1,
- 0xaa00, 0xaa5f,
-}; /* CR_In_Cham */
-
-/* 'In_Myanmar_Extended_A': Block */
-static const OnigCodePoint CR_In_Myanmar_Extended_A[] = {
- 1,
- 0xaa60, 0xaa7f,
-}; /* CR_In_Myanmar_Extended_A */
-
-/* 'In_Tai_Viet': Block */
-static const OnigCodePoint CR_In_Tai_Viet[] = {
- 1,
- 0xaa80, 0xaadf,
-}; /* CR_In_Tai_Viet */
-
-/* 'In_Meetei_Mayek_Extensions': Block */
-static const OnigCodePoint CR_In_Meetei_Mayek_Extensions[] = {
- 1,
- 0xaae0, 0xaaff,
-}; /* CR_In_Meetei_Mayek_Extensions */
-
-/* 'In_Ethiopic_Extended_A': Block */
-static const OnigCodePoint CR_In_Ethiopic_Extended_A[] = {
- 1,
- 0xab00, 0xab2f,
-}; /* CR_In_Ethiopic_Extended_A */
-
-/* 'In_Latin_Extended_E': Block */
-static const OnigCodePoint CR_In_Latin_Extended_E[] = {
- 1,
- 0xab30, 0xab6f,
-}; /* CR_In_Latin_Extended_E */
-
-/* 'In_Cherokee_Supplement': Block */
-static const OnigCodePoint CR_In_Cherokee_Supplement[] = {
- 1,
- 0xab70, 0xabbf,
-}; /* CR_In_Cherokee_Supplement */
-
-/* 'In_Meetei_Mayek': Block */
-static const OnigCodePoint CR_In_Meetei_Mayek[] = {
- 1,
- 0xabc0, 0xabff,
-}; /* CR_In_Meetei_Mayek */
-
-/* 'In_Hangul_Syllables': Block */
-static const OnigCodePoint CR_In_Hangul_Syllables[] = {
- 1,
- 0xac00, 0xd7af,
-}; /* CR_In_Hangul_Syllables */
-
-/* 'In_Hangul_Jamo_Extended_B': Block */
-static const OnigCodePoint CR_In_Hangul_Jamo_Extended_B[] = {
- 1,
- 0xd7b0, 0xd7ff,
-}; /* CR_In_Hangul_Jamo_Extended_B */
-
-/* 'In_High_Surrogates': Block */
-static const OnigCodePoint CR_In_High_Surrogates[] = {
- 1,
- 0xd800, 0xdb7f,
-}; /* CR_In_High_Surrogates */
-
-/* 'In_High_Private_Use_Surrogates': Block */
-static const OnigCodePoint CR_In_High_Private_Use_Surrogates[] = {
- 1,
- 0xdb80, 0xdbff,
-}; /* CR_In_High_Private_Use_Surrogates */
-
-/* 'In_Low_Surrogates': Block */
-static const OnigCodePoint CR_In_Low_Surrogates[] = {
- 1,
- 0xdc00, 0xdfff,
-}; /* CR_In_Low_Surrogates */
-
-/* 'In_Private_Use_Area': Block */
-static const OnigCodePoint CR_In_Private_Use_Area[] = {
- 1,
- 0xe000, 0xf8ff,
-}; /* CR_In_Private_Use_Area */
-
-/* 'In_CJK_Compatibility_Ideographs': Block */
-static const OnigCodePoint CR_In_CJK_Compatibility_Ideographs[] = {
- 1,
- 0xf900, 0xfaff,
-}; /* CR_In_CJK_Compatibility_Ideographs */
-
-/* 'In_Alphabetic_Presentation_Forms': Block */
-static const OnigCodePoint CR_In_Alphabetic_Presentation_Forms[] = {
- 1,
- 0xfb00, 0xfb4f,
-}; /* CR_In_Alphabetic_Presentation_Forms */
-
-/* 'In_Arabic_Presentation_Forms_A': Block */
-static const OnigCodePoint CR_In_Arabic_Presentation_Forms_A[] = {
- 1,
- 0xfb50, 0xfdff,
-}; /* CR_In_Arabic_Presentation_Forms_A */
-
-/* 'In_Variation_Selectors': Block */
-static const OnigCodePoint CR_In_Variation_Selectors[] = {
- 1,
- 0xfe00, 0xfe0f,
-}; /* CR_In_Variation_Selectors */
-
-/* 'In_Vertical_Forms': Block */
-static const OnigCodePoint CR_In_Vertical_Forms[] = {
- 1,
- 0xfe10, 0xfe1f,
-}; /* CR_In_Vertical_Forms */
-
-/* 'In_Combining_Half_Marks': Block */
-static const OnigCodePoint CR_In_Combining_Half_Marks[] = {
- 1,
- 0xfe20, 0xfe2f,
-}; /* CR_In_Combining_Half_Marks */
-
-/* 'In_CJK_Compatibility_Forms': Block */
-static const OnigCodePoint CR_In_CJK_Compatibility_Forms[] = {
- 1,
- 0xfe30, 0xfe4f,
-}; /* CR_In_CJK_Compatibility_Forms */
-
-/* 'In_Small_Form_Variants': Block */
-static const OnigCodePoint CR_In_Small_Form_Variants[] = {
- 1,
- 0xfe50, 0xfe6f,
-}; /* CR_In_Small_Form_Variants */
-
-/* 'In_Arabic_Presentation_Forms_B': Block */
-static const OnigCodePoint CR_In_Arabic_Presentation_Forms_B[] = {
- 1,
- 0xfe70, 0xfeff,
-}; /* CR_In_Arabic_Presentation_Forms_B */
-
-/* 'In_Halfwidth_and_Fullwidth_Forms': Block */
-static const OnigCodePoint CR_In_Halfwidth_and_Fullwidth_Forms[] = {
- 1,
- 0xff00, 0xffef,
-}; /* CR_In_Halfwidth_and_Fullwidth_Forms */
-
-/* 'In_Specials': Block */
-static const OnigCodePoint CR_In_Specials[] = {
- 1,
- 0xfff0, 0xffff,
-}; /* CR_In_Specials */
-
-/* 'In_Linear_B_Syllabary': Block */
-static const OnigCodePoint CR_In_Linear_B_Syllabary[] = {
- 1,
- 0x10000, 0x1007f,
-}; /* CR_In_Linear_B_Syllabary */
-
-/* 'In_Linear_B_Ideograms': Block */
-static const OnigCodePoint CR_In_Linear_B_Ideograms[] = {
- 1,
- 0x10080, 0x100ff,
-}; /* CR_In_Linear_B_Ideograms */
-
-/* 'In_Aegean_Numbers': Block */
-static const OnigCodePoint CR_In_Aegean_Numbers[] = {
- 1,
- 0x10100, 0x1013f,
-}; /* CR_In_Aegean_Numbers */
-
-/* 'In_Ancient_Greek_Numbers': Block */
-static const OnigCodePoint CR_In_Ancient_Greek_Numbers[] = {
- 1,
- 0x10140, 0x1018f,
-}; /* CR_In_Ancient_Greek_Numbers */
-
-/* 'In_Ancient_Symbols': Block */
-static const OnigCodePoint CR_In_Ancient_Symbols[] = {
- 1,
- 0x10190, 0x101cf,
-}; /* CR_In_Ancient_Symbols */
-
-/* 'In_Phaistos_Disc': Block */
-static const OnigCodePoint CR_In_Phaistos_Disc[] = {
- 1,
- 0x101d0, 0x101ff,
-}; /* CR_In_Phaistos_Disc */
-
-/* 'In_Lycian': Block */
-static const OnigCodePoint CR_In_Lycian[] = {
- 1,
- 0x10280, 0x1029f,
-}; /* CR_In_Lycian */
-
-/* 'In_Carian': Block */
-static const OnigCodePoint CR_In_Carian[] = {
- 1,
- 0x102a0, 0x102df,
-}; /* CR_In_Carian */
-
-/* 'In_Coptic_Epact_Numbers': Block */
-static const OnigCodePoint CR_In_Coptic_Epact_Numbers[] = {
- 1,
- 0x102e0, 0x102ff,
-}; /* CR_In_Coptic_Epact_Numbers */
-
-/* 'In_Old_Italic': Block */
-static const OnigCodePoint CR_In_Old_Italic[] = {
- 1,
- 0x10300, 0x1032f,
-}; /* CR_In_Old_Italic */
-
-/* 'In_Gothic': Block */
-static const OnigCodePoint CR_In_Gothic[] = {
- 1,
- 0x10330, 0x1034f,
-}; /* CR_In_Gothic */
-
-/* 'In_Old_Permic': Block */
-static const OnigCodePoint CR_In_Old_Permic[] = {
- 1,
- 0x10350, 0x1037f,
-}; /* CR_In_Old_Permic */
-
-/* 'In_Ugaritic': Block */
-static const OnigCodePoint CR_In_Ugaritic[] = {
- 1,
- 0x10380, 0x1039f,
-}; /* CR_In_Ugaritic */
-
-/* 'In_Old_Persian': Block */
-static const OnigCodePoint CR_In_Old_Persian[] = {
- 1,
- 0x103a0, 0x103df,
-}; /* CR_In_Old_Persian */
-
-/* 'In_Deseret': Block */
-#define CR_In_Deseret CR_Deseret
-
-/* 'In_Shavian': Block */
-#define CR_In_Shavian CR_Shavian
-
-/* 'In_Osmanya': Block */
-static const OnigCodePoint CR_In_Osmanya[] = {
- 1,
- 0x10480, 0x104af,
-}; /* CR_In_Osmanya */
-
-/* 'In_Osage': Block */
-static const OnigCodePoint CR_In_Osage[] = {
- 1,
- 0x104b0, 0x104ff,
-}; /* CR_In_Osage */
-
-/* 'In_Elbasan': Block */
-static const OnigCodePoint CR_In_Elbasan[] = {
- 1,
- 0x10500, 0x1052f,
-}; /* CR_In_Elbasan */
-
-/* 'In_Caucasian_Albanian': Block */
-static const OnigCodePoint CR_In_Caucasian_Albanian[] = {
- 1,
- 0x10530, 0x1056f,
-}; /* CR_In_Caucasian_Albanian */
-
-/* 'In_Vithkuqi': Block */
-static const OnigCodePoint CR_In_Vithkuqi[] = {
- 1,
- 0x10570, 0x105bf,
-}; /* CR_In_Vithkuqi */
-
-/* 'In_Todhri': Block */
-static const OnigCodePoint CR_In_Todhri[] = {
- 1,
- 0x105c0, 0x105ff,
-}; /* CR_In_Todhri */
-
-/* 'In_Linear_A': Block */
-static const OnigCodePoint CR_In_Linear_A[] = {
- 1,
- 0x10600, 0x1077f,
-}; /* CR_In_Linear_A */
-
-/* 'In_Latin_Extended_F': Block */
-static const OnigCodePoint CR_In_Latin_Extended_F[] = {
- 1,
- 0x10780, 0x107bf,
-}; /* CR_In_Latin_Extended_F */
-
-/* 'In_Cypriot_Syllabary': Block */
-static const OnigCodePoint CR_In_Cypriot_Syllabary[] = {
- 1,
- 0x10800, 0x1083f,
-}; /* CR_In_Cypriot_Syllabary */
-
-/* 'In_Imperial_Aramaic': Block */
-static const OnigCodePoint CR_In_Imperial_Aramaic[] = {
- 1,
- 0x10840, 0x1085f,
-}; /* CR_In_Imperial_Aramaic */
-
-/* 'In_Palmyrene': Block */
-#define CR_In_Palmyrene CR_Palmyrene
-
-/* 'In_Nabataean': Block */
-static const OnigCodePoint CR_In_Nabataean[] = {
- 1,
- 0x10880, 0x108af,
-}; /* CR_In_Nabataean */
-
-/* 'In_Hatran': Block */
-static const OnigCodePoint CR_In_Hatran[] = {
- 1,
- 0x108e0, 0x108ff,
-}; /* CR_In_Hatran */
-
-/* 'In_Phoenician': Block */
-static const OnigCodePoint CR_In_Phoenician[] = {
- 1,
- 0x10900, 0x1091f,
-}; /* CR_In_Phoenician */
-
-/* 'In_Lydian': Block */
-static const OnigCodePoint CR_In_Lydian[] = {
- 1,
- 0x10920, 0x1093f,
-}; /* CR_In_Lydian */
-
-/* 'In_Meroitic_Hieroglyphs': Block */
-#define CR_In_Meroitic_Hieroglyphs CR_Meroitic_Hieroglyphs
-
-/* 'In_Meroitic_Cursive': Block */
-static const OnigCodePoint CR_In_Meroitic_Cursive[] = {
- 1,
- 0x109a0, 0x109ff,
-}; /* CR_In_Meroitic_Cursive */
-
-/* 'In_Kharoshthi': Block */
-static const OnigCodePoint CR_In_Kharoshthi[] = {
- 1,
- 0x10a00, 0x10a5f,
-}; /* CR_In_Kharoshthi */
-
-/* 'In_Old_South_Arabian': Block */
-#define CR_In_Old_South_Arabian CR_Old_South_Arabian
-
-/* 'In_Old_North_Arabian': Block */
-#define CR_In_Old_North_Arabian CR_Old_North_Arabian
-
-/* 'In_Manichaean': Block */
-static const OnigCodePoint CR_In_Manichaean[] = {
- 1,
- 0x10ac0, 0x10aff,
-}; /* CR_In_Manichaean */
-
-/* 'In_Avestan': Block */
-static const OnigCodePoint CR_In_Avestan[] = {
- 1,
- 0x10b00, 0x10b3f,
-}; /* CR_In_Avestan */
-
-/* 'In_Inscriptional_Parthian': Block */
-static const OnigCodePoint CR_In_Inscriptional_Parthian[] = {
- 1,
- 0x10b40, 0x10b5f,
-}; /* CR_In_Inscriptional_Parthian */
-
-/* 'In_Inscriptional_Pahlavi': Block */
-static const OnigCodePoint CR_In_Inscriptional_Pahlavi[] = {
- 1,
- 0x10b60, 0x10b7f,
-}; /* CR_In_Inscriptional_Pahlavi */
-
-/* 'In_Psalter_Pahlavi': Block */
-static const OnigCodePoint CR_In_Psalter_Pahlavi[] = {
- 1,
- 0x10b80, 0x10baf,
-}; /* CR_In_Psalter_Pahlavi */
-
-/* 'In_Old_Turkic': Block */
-static const OnigCodePoint CR_In_Old_Turkic[] = {
- 1,
- 0x10c00, 0x10c4f,
-}; /* CR_In_Old_Turkic */
-
-/* 'In_Old_Hungarian': Block */
-static const OnigCodePoint CR_In_Old_Hungarian[] = {
- 1,
- 0x10c80, 0x10cff,
-}; /* CR_In_Old_Hungarian */
-
-/* 'In_Hanifi_Rohingya': Block */
-static const OnigCodePoint CR_In_Hanifi_Rohingya[] = {
- 1,
- 0x10d00, 0x10d3f,
-}; /* CR_In_Hanifi_Rohingya */
-
-/* 'In_Garay': Block */
-static const OnigCodePoint CR_In_Garay[] = {
- 1,
- 0x10d40, 0x10d8f,
-}; /* CR_In_Garay */
-
-/* 'In_Rumi_Numeral_Symbols': Block */
-static const OnigCodePoint CR_In_Rumi_Numeral_Symbols[] = {
- 1,
- 0x10e60, 0x10e7f,
-}; /* CR_In_Rumi_Numeral_Symbols */
-
-/* 'In_Yezidi': Block */
-static const OnigCodePoint CR_In_Yezidi[] = {
- 1,
- 0x10e80, 0x10ebf,
-}; /* CR_In_Yezidi */
-
-/* 'In_Arabic_Extended_C': Block */
-static const OnigCodePoint CR_In_Arabic_Extended_C[] = {
- 1,
- 0x10ec0, 0x10eff,
-}; /* CR_In_Arabic_Extended_C */
-
-/* 'In_Old_Sogdian': Block */
-static const OnigCodePoint CR_In_Old_Sogdian[] = {
- 1,
- 0x10f00, 0x10f2f,
-}; /* CR_In_Old_Sogdian */
-
-/* 'In_Sogdian': Block */
-static const OnigCodePoint CR_In_Sogdian[] = {
- 1,
- 0x10f30, 0x10f6f,
-}; /* CR_In_Sogdian */
-
-/* 'In_Old_Uyghur': Block */
-static const OnigCodePoint CR_In_Old_Uyghur[] = {
- 1,
- 0x10f70, 0x10faf,
-}; /* CR_In_Old_Uyghur */
-
-/* 'In_Chorasmian': Block */
-static const OnigCodePoint CR_In_Chorasmian[] = {
- 1,
- 0x10fb0, 0x10fdf,
-}; /* CR_In_Chorasmian */
-
-/* 'In_Elymaic': Block */
-static const OnigCodePoint CR_In_Elymaic[] = {
- 1,
- 0x10fe0, 0x10fff,
-}; /* CR_In_Elymaic */
-
-/* 'In_Brahmi': Block */
-static const OnigCodePoint CR_In_Brahmi[] = {
- 1,
- 0x11000, 0x1107f,
-}; /* CR_In_Brahmi */
-
-/* 'In_Kaithi': Block */
-static const OnigCodePoint CR_In_Kaithi[] = {
- 1,
- 0x11080, 0x110cf,
-}; /* CR_In_Kaithi */
-
-/* 'In_Sora_Sompeng': Block */
-static const OnigCodePoint CR_In_Sora_Sompeng[] = {
- 1,
- 0x110d0, 0x110ff,
-}; /* CR_In_Sora_Sompeng */
-
-/* 'In_Chakma': Block */
-static const OnigCodePoint CR_In_Chakma[] = {
- 1,
- 0x11100, 0x1114f,
-}; /* CR_In_Chakma */
-
-/* 'In_Mahajani': Block */
-static const OnigCodePoint CR_In_Mahajani[] = {
- 1,
- 0x11150, 0x1117f,
-}; /* CR_In_Mahajani */
-
-/* 'In_Sharada': Block */
-#define CR_In_Sharada CR_Sharada
-
-/* 'In_Sinhala_Archaic_Numbers': Block */
-static const OnigCodePoint CR_In_Sinhala_Archaic_Numbers[] = {
- 1,
- 0x111e0, 0x111ff,
-}; /* CR_In_Sinhala_Archaic_Numbers */
-
-/* 'In_Khojki': Block */
-static const OnigCodePoint CR_In_Khojki[] = {
- 1,
- 0x11200, 0x1124f,
-}; /* CR_In_Khojki */
-
-/* 'In_Multani': Block */
-static const OnigCodePoint CR_In_Multani[] = {
- 1,
- 0x11280, 0x112af,
-}; /* CR_In_Multani */
-
-/* 'In_Khudawadi': Block */
-static const OnigCodePoint CR_In_Khudawadi[] = {
- 1,
- 0x112b0, 0x112ff,
-}; /* CR_In_Khudawadi */
-
-/* 'In_Grantha': Block */
-static const OnigCodePoint CR_In_Grantha[] = {
- 1,
- 0x11300, 0x1137f,
-}; /* CR_In_Grantha */
-
-/* 'In_Tulu_Tigalari': Block */
-static const OnigCodePoint CR_In_Tulu_Tigalari[] = {
- 1,
- 0x11380, 0x113ff,
-}; /* CR_In_Tulu_Tigalari */
-
-/* 'In_Newa': Block */
-static const OnigCodePoint CR_In_Newa[] = {
- 1,
- 0x11400, 0x1147f,
-}; /* CR_In_Newa */
-
-/* 'In_Tirhuta': Block */
-static const OnigCodePoint CR_In_Tirhuta[] = {
- 1,
- 0x11480, 0x114df,
-}; /* CR_In_Tirhuta */
-
-/* 'In_Siddham': Block */
-static const OnigCodePoint CR_In_Siddham[] = {
- 1,
- 0x11580, 0x115ff,
-}; /* CR_In_Siddham */
-
-/* 'In_Modi': Block */
-static const OnigCodePoint CR_In_Modi[] = {
- 1,
- 0x11600, 0x1165f,
-}; /* CR_In_Modi */
-
-/* 'In_Mongolian_Supplement': Block */
-static const OnigCodePoint CR_In_Mongolian_Supplement[] = {
- 1,
- 0x11660, 0x1167f,
-}; /* CR_In_Mongolian_Supplement */
-
-/* 'In_Takri': Block */
-static const OnigCodePoint CR_In_Takri[] = {
- 1,
- 0x11680, 0x116cf,
-}; /* CR_In_Takri */
-
-/* 'In_Myanmar_Extended_C': Block */
-static const OnigCodePoint CR_In_Myanmar_Extended_C[] = {
- 1,
- 0x116d0, 0x116ff,
-}; /* CR_In_Myanmar_Extended_C */
-
-/* 'In_Ahom': Block */
-static const OnigCodePoint CR_In_Ahom[] = {
- 1,
- 0x11700, 0x1174f,
-}; /* CR_In_Ahom */
-
-/* 'In_Dogra': Block */
-static const OnigCodePoint CR_In_Dogra[] = {
- 1,
- 0x11800, 0x1184f,
-}; /* CR_In_Dogra */
-
-/* 'In_Warang_Citi': Block */
-static const OnigCodePoint CR_In_Warang_Citi[] = {
- 1,
- 0x118a0, 0x118ff,
-}; /* CR_In_Warang_Citi */
-
-/* 'In_Dives_Akuru': Block */
-static const OnigCodePoint CR_In_Dives_Akuru[] = {
- 1,
- 0x11900, 0x1195f,
-}; /* CR_In_Dives_Akuru */
-
-/* 'In_Nandinagari': Block */
-static const OnigCodePoint CR_In_Nandinagari[] = {
- 1,
- 0x119a0, 0x119ff,
-}; /* CR_In_Nandinagari */
-
-/* 'In_Zanabazar_Square': Block */
-static const OnigCodePoint CR_In_Zanabazar_Square[] = {
- 1,
- 0x11a00, 0x11a4f,
-}; /* CR_In_Zanabazar_Square */
-
-/* 'In_Soyombo': Block */
-static const OnigCodePoint CR_In_Soyombo[] = {
- 1,
- 0x11a50, 0x11aaf,
-}; /* CR_In_Soyombo */
-
-/* 'In_Unified_Canadian_Aboriginal_Syllabics_Extended_A': Block */
-static const OnigCodePoint CR_In_Unified_Canadian_Aboriginal_Syllabics_Extended_A[] = {
- 1,
- 0x11ab0, 0x11abf,
-}; /* CR_In_Unified_Canadian_Aboriginal_Syllabics_Extended_A */
-
-/* 'In_Pau_Cin_Hau': Block */
-static const OnigCodePoint CR_In_Pau_Cin_Hau[] = {
- 1,
- 0x11ac0, 0x11aff,
-}; /* CR_In_Pau_Cin_Hau */
-
-/* 'In_Devanagari_Extended_A': Block */
-static const OnigCodePoint CR_In_Devanagari_Extended_A[] = {
- 1,
- 0x11b00, 0x11b5f,
-}; /* CR_In_Devanagari_Extended_A */
-
-/* 'In_Sunuwar': Block */
-static const OnigCodePoint CR_In_Sunuwar[] = {
- 1,
- 0x11bc0, 0x11bff,
-}; /* CR_In_Sunuwar */
-
-/* 'In_Bhaiksuki': Block */
-static const OnigCodePoint CR_In_Bhaiksuki[] = {
- 1,
- 0x11c00, 0x11c6f,
-}; /* CR_In_Bhaiksuki */
-
-/* 'In_Marchen': Block */
-static const OnigCodePoint CR_In_Marchen[] = {
- 1,
- 0x11c70, 0x11cbf,
-}; /* CR_In_Marchen */
-
-/* 'In_Masaram_Gondi': Block */
-static const OnigCodePoint CR_In_Masaram_Gondi[] = {
- 1,
- 0x11d00, 0x11d5f,
-}; /* CR_In_Masaram_Gondi */
-
-/* 'In_Gunjala_Gondi': Block */
-static const OnigCodePoint CR_In_Gunjala_Gondi[] = {
- 1,
- 0x11d60, 0x11daf,
-}; /* CR_In_Gunjala_Gondi */
-
-/* 'In_Makasar': Block */
-static const OnigCodePoint CR_In_Makasar[] = {
- 1,
- 0x11ee0, 0x11eff,
-}; /* CR_In_Makasar */
-
-/* 'In_Kawi': Block */
-static const OnigCodePoint CR_In_Kawi[] = {
- 1,
- 0x11f00, 0x11f5f,
-}; /* CR_In_Kawi */
-
-/* 'In_Lisu_Supplement': Block */
-static const OnigCodePoint CR_In_Lisu_Supplement[] = {
- 1,
- 0x11fb0, 0x11fbf,
-}; /* CR_In_Lisu_Supplement */
-
-/* 'In_Tamil_Supplement': Block */
-static const OnigCodePoint CR_In_Tamil_Supplement[] = {
- 1,
- 0x11fc0, 0x11fff,
-}; /* CR_In_Tamil_Supplement */
-
-/* 'In_Cuneiform': Block */
-static const OnigCodePoint CR_In_Cuneiform[] = {
- 1,
- 0x12000, 0x123ff,
-}; /* CR_In_Cuneiform */
-
-/* 'In_Cuneiform_Numbers_and_Punctuation': Block */
-static const OnigCodePoint CR_In_Cuneiform_Numbers_and_Punctuation[] = {
- 1,
- 0x12400, 0x1247f,
-}; /* CR_In_Cuneiform_Numbers_and_Punctuation */
-
-/* 'In_Early_Dynastic_Cuneiform': Block */
-static const OnigCodePoint CR_In_Early_Dynastic_Cuneiform[] = {
- 1,
- 0x12480, 0x1254f,
-}; /* CR_In_Early_Dynastic_Cuneiform */
-
-/* 'In_Cypro_Minoan': Block */
-static const OnigCodePoint CR_In_Cypro_Minoan[] = {
- 1,
- 0x12f90, 0x12fff,
-}; /* CR_In_Cypro_Minoan */
-
-/* 'In_Egyptian_Hieroglyphs': Block */
-static const OnigCodePoint CR_In_Egyptian_Hieroglyphs[] = {
- 1,
- 0x13000, 0x1342f,
-}; /* CR_In_Egyptian_Hieroglyphs */
-
-/* 'In_Egyptian_Hieroglyph_Format_Controls': Block */
-static const OnigCodePoint CR_In_Egyptian_Hieroglyph_Format_Controls[] = {
- 1,
- 0x13430, 0x1345f,
-}; /* CR_In_Egyptian_Hieroglyph_Format_Controls */
-
-/* 'In_Egyptian_Hieroglyphs_Extended_A': Block */
-static const OnigCodePoint CR_In_Egyptian_Hieroglyphs_Extended_A[] = {
- 1,
- 0x13460, 0x143ff,
-}; /* CR_In_Egyptian_Hieroglyphs_Extended_A */
-
-/* 'In_Anatolian_Hieroglyphs': Block */
-static const OnigCodePoint CR_In_Anatolian_Hieroglyphs[] = {
- 1,
- 0x14400, 0x1467f,
-}; /* CR_In_Anatolian_Hieroglyphs */
-
-/* 'In_Gurung_Khema': Block */
-static const OnigCodePoint CR_In_Gurung_Khema[] = {
- 1,
- 0x16100, 0x1613f,
-}; /* CR_In_Gurung_Khema */
-
-/* 'In_Bamum_Supplement': Block */
-static const OnigCodePoint CR_In_Bamum_Supplement[] = {
- 1,
- 0x16800, 0x16a3f,
-}; /* CR_In_Bamum_Supplement */
-
-/* 'In_Mro': Block */
-static const OnigCodePoint CR_In_Mro[] = {
- 1,
- 0x16a40, 0x16a6f,
-}; /* CR_In_Mro */
-
-/* 'In_Tangsa': Block */
-static const OnigCodePoint CR_In_Tangsa[] = {
- 1,
- 0x16a70, 0x16acf,
-}; /* CR_In_Tangsa */
-
-/* 'In_Bassa_Vah': Block */
-static const OnigCodePoint CR_In_Bassa_Vah[] = {
- 1,
- 0x16ad0, 0x16aff,
-}; /* CR_In_Bassa_Vah */
-
-/* 'In_Pahawh_Hmong': Block */
-static const OnigCodePoint CR_In_Pahawh_Hmong[] = {
- 1,
- 0x16b00, 0x16b8f,
-}; /* CR_In_Pahawh_Hmong */
-
-/* 'In_Kirat_Rai': Block */
-static const OnigCodePoint CR_In_Kirat_Rai[] = {
- 1,
- 0x16d40, 0x16d7f,
-}; /* CR_In_Kirat_Rai */
-
-/* 'In_Medefaidrin': Block */
-static const OnigCodePoint CR_In_Medefaidrin[] = {
- 1,
- 0x16e40, 0x16e9f,
-}; /* CR_In_Medefaidrin */
-
-/* 'In_Miao': Block */
-static const OnigCodePoint CR_In_Miao[] = {
- 1,
- 0x16f00, 0x16f9f,
-}; /* CR_In_Miao */
-
-/* 'In_Ideographic_Symbols_and_Punctuation': Block */
-static const OnigCodePoint CR_In_Ideographic_Symbols_and_Punctuation[] = {
- 1,
- 0x16fe0, 0x16fff,
-}; /* CR_In_Ideographic_Symbols_and_Punctuation */
-
-/* 'In_Tangut': Block */
-static const OnigCodePoint CR_In_Tangut[] = {
- 1,
- 0x17000, 0x187ff,
-}; /* CR_In_Tangut */
-
-/* 'In_Tangut_Components': Block */
-static const OnigCodePoint CR_In_Tangut_Components[] = {
- 1,
- 0x18800, 0x18aff,
-}; /* CR_In_Tangut_Components */
-
-/* 'In_Khitan_Small_Script': Block */
-static const OnigCodePoint CR_In_Khitan_Small_Script[] = {
- 1,
- 0x18b00, 0x18cff,
-}; /* CR_In_Khitan_Small_Script */
-
-/* 'In_Tangut_Supplement': Block */
-static const OnigCodePoint CR_In_Tangut_Supplement[] = {
- 1,
- 0x18d00, 0x18d7f,
-}; /* CR_In_Tangut_Supplement */
-
-/* 'In_Kana_Extended_B': Block */
-static const OnigCodePoint CR_In_Kana_Extended_B[] = {
- 1,
- 0x1aff0, 0x1afff,
-}; /* CR_In_Kana_Extended_B */
-
-/* 'In_Kana_Supplement': Block */
-static const OnigCodePoint CR_In_Kana_Supplement[] = {
- 1,
- 0x1b000, 0x1b0ff,
-}; /* CR_In_Kana_Supplement */
-
-/* 'In_Kana_Extended_A': Block */
-static const OnigCodePoint CR_In_Kana_Extended_A[] = {
- 1,
- 0x1b100, 0x1b12f,
-}; /* CR_In_Kana_Extended_A */
-
-/* 'In_Small_Kana_Extension': Block */
-static const OnigCodePoint CR_In_Small_Kana_Extension[] = {
- 1,
- 0x1b130, 0x1b16f,
-}; /* CR_In_Small_Kana_Extension */
-
-/* 'In_Nushu': Block */
-static const OnigCodePoint CR_In_Nushu[] = {
- 1,
- 0x1b170, 0x1b2ff,
-}; /* CR_In_Nushu */
-
-/* 'In_Duployan': Block */
-static const OnigCodePoint CR_In_Duployan[] = {
- 1,
- 0x1bc00, 0x1bc9f,
-}; /* CR_In_Duployan */
-
-/* 'In_Shorthand_Format_Controls': Block */
-static const OnigCodePoint CR_In_Shorthand_Format_Controls[] = {
- 1,
- 0x1bca0, 0x1bcaf,
-}; /* CR_In_Shorthand_Format_Controls */
-
-/* 'In_Symbols_for_Legacy_Computing_Supplement': Block */
-static const OnigCodePoint CR_In_Symbols_for_Legacy_Computing_Supplement[] = {
- 1,
- 0x1cc00, 0x1cebf,
-}; /* CR_In_Symbols_for_Legacy_Computing_Supplement */
-
-/* 'In_Znamenny_Musical_Notation': Block */
-static const OnigCodePoint CR_In_Znamenny_Musical_Notation[] = {
- 1,
- 0x1cf00, 0x1cfcf,
-}; /* CR_In_Znamenny_Musical_Notation */
-
-/* 'In_Byzantine_Musical_Symbols': Block */
-static const OnigCodePoint CR_In_Byzantine_Musical_Symbols[] = {
- 1,
- 0x1d000, 0x1d0ff,
-}; /* CR_In_Byzantine_Musical_Symbols */
-
-/* 'In_Musical_Symbols': Block */
-static const OnigCodePoint CR_In_Musical_Symbols[] = {
- 1,
- 0x1d100, 0x1d1ff,
-}; /* CR_In_Musical_Symbols */
-
-/* 'In_Ancient_Greek_Musical_Notation': Block */
-static const OnigCodePoint CR_In_Ancient_Greek_Musical_Notation[] = {
- 1,
- 0x1d200, 0x1d24f,
-}; /* CR_In_Ancient_Greek_Musical_Notation */
-
-/* 'In_Kaktovik_Numerals': Block */
-static const OnigCodePoint CR_In_Kaktovik_Numerals[] = {
- 1,
- 0x1d2c0, 0x1d2df,
-}; /* CR_In_Kaktovik_Numerals */
-
-/* 'In_Mayan_Numerals': Block */
-static const OnigCodePoint CR_In_Mayan_Numerals[] = {
- 1,
- 0x1d2e0, 0x1d2ff,
-}; /* CR_In_Mayan_Numerals */
-
-/* 'In_Tai_Xuan_Jing_Symbols': Block */
-static const OnigCodePoint CR_In_Tai_Xuan_Jing_Symbols[] = {
- 1,
- 0x1d300, 0x1d35f,
-}; /* CR_In_Tai_Xuan_Jing_Symbols */
-
-/* 'In_Counting_Rod_Numerals': Block */
-static const OnigCodePoint CR_In_Counting_Rod_Numerals[] = {
- 1,
- 0x1d360, 0x1d37f,
-}; /* CR_In_Counting_Rod_Numerals */
-
-/* 'In_Mathematical_Alphanumeric_Symbols': Block */
-static const OnigCodePoint CR_In_Mathematical_Alphanumeric_Symbols[] = {
- 1,
- 0x1d400, 0x1d7ff,
-}; /* CR_In_Mathematical_Alphanumeric_Symbols */
-
-/* 'In_Sutton_SignWriting': Block */
-static const OnigCodePoint CR_In_Sutton_SignWriting[] = {
- 1,
- 0x1d800, 0x1daaf,
-}; /* CR_In_Sutton_SignWriting */
-
-/* 'In_Latin_Extended_G': Block */
-static const OnigCodePoint CR_In_Latin_Extended_G[] = {
- 1,
- 0x1df00, 0x1dfff,
-}; /* CR_In_Latin_Extended_G */
-
-/* 'In_Glagolitic_Supplement': Block */
-static const OnigCodePoint CR_In_Glagolitic_Supplement[] = {
- 1,
- 0x1e000, 0x1e02f,
-}; /* CR_In_Glagolitic_Supplement */
-
-/* 'In_Cyrillic_Extended_D': Block */
-static const OnigCodePoint CR_In_Cyrillic_Extended_D[] = {
- 1,
- 0x1e030, 0x1e08f,
-}; /* CR_In_Cyrillic_Extended_D */
-
-/* 'In_Nyiakeng_Puachue_Hmong': Block */
-static const OnigCodePoint CR_In_Nyiakeng_Puachue_Hmong[] = {
- 1,
- 0x1e100, 0x1e14f,
-}; /* CR_In_Nyiakeng_Puachue_Hmong */
-
-/* 'In_Toto': Block */
-static const OnigCodePoint CR_In_Toto[] = {
- 1,
- 0x1e290, 0x1e2bf,
-}; /* CR_In_Toto */
-
-/* 'In_Wancho': Block */
-static const OnigCodePoint CR_In_Wancho[] = {
- 1,
- 0x1e2c0, 0x1e2ff,
-}; /* CR_In_Wancho */
-
-/* 'In_Nag_Mundari': Block */
-static const OnigCodePoint CR_In_Nag_Mundari[] = {
- 1,
- 0x1e4d0, 0x1e4ff,
-}; /* CR_In_Nag_Mundari */
-
-/* 'In_Ol_Onal': Block */
-static const OnigCodePoint CR_In_Ol_Onal[] = {
- 1,
- 0x1e5d0, 0x1e5ff,
-}; /* CR_In_Ol_Onal */
-
-/* 'In_Ethiopic_Extended_B': Block */
-static const OnigCodePoint CR_In_Ethiopic_Extended_B[] = {
- 1,
- 0x1e7e0, 0x1e7ff,
-}; /* CR_In_Ethiopic_Extended_B */
-
-/* 'In_Mende_Kikakui': Block */
-static const OnigCodePoint CR_In_Mende_Kikakui[] = {
- 1,
- 0x1e800, 0x1e8df,
-}; /* CR_In_Mende_Kikakui */
-
-/* 'In_Adlam': Block */
-static const OnigCodePoint CR_In_Adlam[] = {
- 1,
- 0x1e900, 0x1e95f,
-}; /* CR_In_Adlam */
-
-/* 'In_Indic_Siyaq_Numbers': Block */
-static const OnigCodePoint CR_In_Indic_Siyaq_Numbers[] = {
- 1,
- 0x1ec70, 0x1ecbf,
-}; /* CR_In_Indic_Siyaq_Numbers */
-
-/* 'In_Ottoman_Siyaq_Numbers': Block */
-static const OnigCodePoint CR_In_Ottoman_Siyaq_Numbers[] = {
- 1,
- 0x1ed00, 0x1ed4f,
-}; /* CR_In_Ottoman_Siyaq_Numbers */
-
-/* 'In_Arabic_Mathematical_Alphabetic_Symbols': Block */
-static const OnigCodePoint CR_In_Arabic_Mathematical_Alphabetic_Symbols[] = {
- 1,
- 0x1ee00, 0x1eeff,
-}; /* CR_In_Arabic_Mathematical_Alphabetic_Symbols */
-
-/* 'In_Mahjong_Tiles': Block */
-static const OnigCodePoint CR_In_Mahjong_Tiles[] = {
- 1,
- 0x1f000, 0x1f02f,
-}; /* CR_In_Mahjong_Tiles */
-
-/* 'In_Domino_Tiles': Block */
-static const OnigCodePoint CR_In_Domino_Tiles[] = {
- 1,
- 0x1f030, 0x1f09f,
-}; /* CR_In_Domino_Tiles */
-
-/* 'In_Playing_Cards': Block */
-static const OnigCodePoint CR_In_Playing_Cards[] = {
- 1,
- 0x1f0a0, 0x1f0ff,
-}; /* CR_In_Playing_Cards */
-
-/* 'In_Enclosed_Alphanumeric_Supplement': Block */
-static const OnigCodePoint CR_In_Enclosed_Alphanumeric_Supplement[] = {
- 1,
- 0x1f100, 0x1f1ff,
-}; /* CR_In_Enclosed_Alphanumeric_Supplement */
-
-/* 'In_Enclosed_Ideographic_Supplement': Block */
-static const OnigCodePoint CR_In_Enclosed_Ideographic_Supplement[] = {
- 1,
- 0x1f200, 0x1f2ff,
-}; /* CR_In_Enclosed_Ideographic_Supplement */
-
-/* 'In_Miscellaneous_Symbols_and_Pictographs': Block */
-static const OnigCodePoint CR_In_Miscellaneous_Symbols_and_Pictographs[] = {
- 1,
- 0x1f300, 0x1f5ff,
-}; /* CR_In_Miscellaneous_Symbols_and_Pictographs */
-
-/* 'In_Emoticons': Block */
-static const OnigCodePoint CR_In_Emoticons[] = {
- 1,
- 0x1f600, 0x1f64f,
-}; /* CR_In_Emoticons */
-
-/* 'In_Ornamental_Dingbats': Block */
-static const OnigCodePoint CR_In_Ornamental_Dingbats[] = {
- 1,
- 0x1f650, 0x1f67f,
-}; /* CR_In_Ornamental_Dingbats */
-
-/* 'In_Transport_and_Map_Symbols': Block */
-static const OnigCodePoint CR_In_Transport_and_Map_Symbols[] = {
- 1,
- 0x1f680, 0x1f6ff,
-}; /* CR_In_Transport_and_Map_Symbols */
-
-/* 'In_Alchemical_Symbols': Block */
-static const OnigCodePoint CR_In_Alchemical_Symbols[] = {
- 1,
- 0x1f700, 0x1f77f,
-}; /* CR_In_Alchemical_Symbols */
-
-/* 'In_Geometric_Shapes_Extended': Block */
-static const OnigCodePoint CR_In_Geometric_Shapes_Extended[] = {
- 1,
- 0x1f780, 0x1f7ff,
-}; /* CR_In_Geometric_Shapes_Extended */
-
-/* 'In_Supplemental_Arrows_C': Block */
-static const OnigCodePoint CR_In_Supplemental_Arrows_C[] = {
- 1,
- 0x1f800, 0x1f8ff,
-}; /* CR_In_Supplemental_Arrows_C */
-
-/* 'In_Supplemental_Symbols_and_Pictographs': Block */
-static const OnigCodePoint CR_In_Supplemental_Symbols_and_Pictographs[] = {
- 1,
- 0x1f900, 0x1f9ff,
-}; /* CR_In_Supplemental_Symbols_and_Pictographs */
-
-/* 'In_Chess_Symbols': Block */
-static const OnigCodePoint CR_In_Chess_Symbols[] = {
- 1,
- 0x1fa00, 0x1fa6f,
-}; /* CR_In_Chess_Symbols */
-
-/* 'In_Symbols_and_Pictographs_Extended_A': Block */
-static const OnigCodePoint CR_In_Symbols_and_Pictographs_Extended_A[] = {
- 1,
- 0x1fa70, 0x1faff,
-}; /* CR_In_Symbols_and_Pictographs_Extended_A */
-
-/* 'In_Symbols_for_Legacy_Computing': Block */
-static const OnigCodePoint CR_In_Symbols_for_Legacy_Computing[] = {
- 1,
- 0x1fb00, 0x1fbff,
-}; /* CR_In_Symbols_for_Legacy_Computing */
-
-/* 'In_CJK_Unified_Ideographs_Extension_B': Block */
-static const OnigCodePoint CR_In_CJK_Unified_Ideographs_Extension_B[] = {
- 1,
- 0x20000, 0x2a6df,
-}; /* CR_In_CJK_Unified_Ideographs_Extension_B */
-
-/* 'In_CJK_Unified_Ideographs_Extension_C': Block */
-static const OnigCodePoint CR_In_CJK_Unified_Ideographs_Extension_C[] = {
- 1,
- 0x2a700, 0x2b73f,
-}; /* CR_In_CJK_Unified_Ideographs_Extension_C */
-
-/* 'In_CJK_Unified_Ideographs_Extension_D': Block */
-static const OnigCodePoint CR_In_CJK_Unified_Ideographs_Extension_D[] = {
- 1,
- 0x2b740, 0x2b81f,
-}; /* CR_In_CJK_Unified_Ideographs_Extension_D */
-
-/* 'In_CJK_Unified_Ideographs_Extension_E': Block */
-static const OnigCodePoint CR_In_CJK_Unified_Ideographs_Extension_E[] = {
- 1,
- 0x2b820, 0x2ceaf,
-}; /* CR_In_CJK_Unified_Ideographs_Extension_E */
-
-/* 'In_CJK_Unified_Ideographs_Extension_F': Block */
-static const OnigCodePoint CR_In_CJK_Unified_Ideographs_Extension_F[] = {
- 1,
- 0x2ceb0, 0x2ebef,
-}; /* CR_In_CJK_Unified_Ideographs_Extension_F */
-
-/* 'In_CJK_Unified_Ideographs_Extension_I': Block */
-static const OnigCodePoint CR_In_CJK_Unified_Ideographs_Extension_I[] = {
- 1,
- 0x2ebf0, 0x2ee5f,
-}; /* CR_In_CJK_Unified_Ideographs_Extension_I */
-
-/* 'In_CJK_Compatibility_Ideographs_Supplement': Block */
-static const OnigCodePoint CR_In_CJK_Compatibility_Ideographs_Supplement[] = {
- 1,
- 0x2f800, 0x2fa1f,
-}; /* CR_In_CJK_Compatibility_Ideographs_Supplement */
-
-/* 'In_CJK_Unified_Ideographs_Extension_G': Block */
-static const OnigCodePoint CR_In_CJK_Unified_Ideographs_Extension_G[] = {
- 1,
- 0x30000, 0x3134f,
-}; /* CR_In_CJK_Unified_Ideographs_Extension_G */
-
-/* 'In_CJK_Unified_Ideographs_Extension_H': Block */
-static const OnigCodePoint CR_In_CJK_Unified_Ideographs_Extension_H[] = {
- 1,
- 0x31350, 0x323af,
-}; /* CR_In_CJK_Unified_Ideographs_Extension_H */
-
-/* 'In_Tags': Block */
-static const OnigCodePoint CR_In_Tags[] = {
- 1,
- 0xe0000, 0xe007f,
-}; /* CR_In_Tags */
-
-/* 'In_Variation_Selectors_Supplement': Block */
-static const OnigCodePoint CR_In_Variation_Selectors_Supplement[] = {
- 1,
- 0xe0100, 0xe01ef,
-}; /* CR_In_Variation_Selectors_Supplement */
-
-/* 'In_Supplementary_Private_Use_Area_A': Block */
-static const OnigCodePoint CR_In_Supplementary_Private_Use_Area_A[] = {
- 1,
- 0xf0000, 0xfffff,
-}; /* CR_In_Supplementary_Private_Use_Area_A */
-
-/* 'In_Supplementary_Private_Use_Area_B': Block */
-static const OnigCodePoint CR_In_Supplementary_Private_Use_Area_B[] = {
- 1,
- 0x100000, 0x10ffff,
-}; /* CR_In_Supplementary_Private_Use_Area_B */
-
-/* 'In_No_Block': Block */
-static const OnigCodePoint CR_In_No_Block[] = {
- 51,
- 0x2fe0, 0x2fef,
- 0x10200, 0x1027f,
- 0x103e0, 0x103ff,
- 0x107c0, 0x107ff,
- 0x108b0, 0x108df,
- 0x10940, 0x1097f,
- 0x10aa0, 0x10abf,
- 0x10bb0, 0x10bff,
- 0x10c50, 0x10c7f,
- 0x10d90, 0x10e5f,
- 0x11250, 0x1127f,
- 0x114e0, 0x1157f,
- 0x11750, 0x117ff,
- 0x11850, 0x1189f,
- 0x11960, 0x1199f,
- 0x11b60, 0x11bbf,
- 0x11cc0, 0x11cff,
- 0x11db0, 0x11edf,
- 0x11f60, 0x11faf,
- 0x12550, 0x12f8f,
- 0x14680, 0x160ff,
- 0x16140, 0x167ff,
- 0x16b90, 0x16d3f,
- 0x16d80, 0x16e3f,
- 0x16ea0, 0x16eff,
- 0x16fa0, 0x16fdf,
- 0x18d80, 0x1afef,
- 0x1b300, 0x1bbff,
- 0x1bcb0, 0x1cbff,
- 0x1cec0, 0x1ceff,
- 0x1cfd0, 0x1cfff,
- 0x1d250, 0x1d2bf,
- 0x1d380, 0x1d3ff,
- 0x1dab0, 0x1deff,
- 0x1e090, 0x1e0ff,
- 0x1e150, 0x1e28f,
- 0x1e300, 0x1e4cf,
- 0x1e500, 0x1e5cf,
- 0x1e600, 0x1e7df,
- 0x1e8e0, 0x1e8ff,
- 0x1e960, 0x1ec6f,
- 0x1ecc0, 0x1ecff,
- 0x1ed50, 0x1edff,
- 0x1ef00, 0x1efff,
- 0x1fc00, 0x1ffff,
- 0x2a6e0, 0x2a6ff,
- 0x2ee60, 0x2f7ff,
- 0x2fa20, 0x2ffff,
- 0x323b0, 0xdffff,
- 0xe0080, 0xe00ff,
- 0xe01f0, 0xeffff,
-}; /* CR_In_No_Block */
-
-#endif /* USE_UNICODE_PROPERTIES */
-static const OnigCodePoint* const CodeRanges[] = {
- CR_NEWLINE,
- CR_Alpha,
- CR_Blank,
- CR_Cntrl,
- CR_Digit,
- CR_Graph,
- CR_Lower,
- CR_Print,
- CR_XPosixPunct,
- CR_Space,
- CR_Upper,
- CR_XDigit,
- CR_Word,
- CR_Alnum,
- CR_ASCII,
- CR_Punct,
-#ifdef USE_UNICODE_PROPERTIES
- CR_Any,
- CR_Assigned,
- CR_C,
- CR_Cc,
- CR_Cf,
- CR_Cn,
- CR_Co,
- CR_Cs,
- CR_L,
- CR_LC,
- CR_Ll,
- CR_Lm,
- CR_Lo,
- CR_Lt,
- CR_Lu,
- CR_M,
- CR_Mc,
- CR_Me,
- CR_Mn,
- CR_N,
- CR_Nd,
- CR_Nl,
- CR_No,
- CR_P,
- CR_Pc,
- CR_Pd,
- CR_Pe,
- CR_Pf,
- CR_Pi,
- CR_Po,
- CR_Ps,
- CR_S,
- CR_Sc,
- CR_Sk,
- CR_Sm,
- CR_So,
- CR_Z,
- CR_Zl,
- CR_Zp,
- CR_Zs,
- CR_Math,
- CR_Alphabetic,
- CR_Lowercase,
- CR_Uppercase,
- CR_Cased,
- CR_Case_Ignorable,
- CR_Changes_When_Lowercased,
- CR_Changes_When_Uppercased,
- CR_Changes_When_Titlecased,
- CR_Changes_When_Casefolded,
- CR_Changes_When_Casemapped,
- CR_ID_Start,
- CR_ID_Continue,
- CR_XID_Start,
- CR_XID_Continue,
- CR_Default_Ignorable_Code_Point,
- CR_Grapheme_Extend,
- CR_Grapheme_Base,
- CR_Grapheme_Link,
- CR_InCB_Linker,
- CR_InCB_Consonant,
- CR_InCB_Extend,
- CR_Common,
- CR_Latin,
- CR_Greek,
- CR_Cyrillic,
- CR_Armenian,
- CR_Hebrew,
- CR_Arabic,
- CR_Syriac,
- CR_Thaana,
- CR_Devanagari,
- CR_Bengali,
- CR_Gurmukhi,
- CR_Gujarati,
- CR_Oriya,
- CR_Tamil,
- CR_Telugu,
- CR_Kannada,
- CR_Malayalam,
- CR_Sinhala,
- CR_Thai,
- CR_Lao,
- CR_Tibetan,
- CR_Myanmar,
- CR_Georgian,
- CR_Hangul,
- CR_Ethiopic,
- CR_Cherokee,
- CR_Canadian_Aboriginal,
- CR_Ogham,
- CR_Runic,
- CR_Khmer,
- CR_Mongolian,
- CR_Hiragana,
- CR_Katakana,
- CR_Bopomofo,
- CR_Han,
- CR_Yi,
- CR_Old_Italic,
- CR_Gothic,
- CR_Deseret,
- CR_Inherited,
- CR_Tagalog,
- CR_Hanunoo,
- CR_Buhid,
- CR_Tagbanwa,
- CR_Limbu,
- CR_Tai_Le,
- CR_Linear_B,
- CR_Ugaritic,
- CR_Shavian,
- CR_Osmanya,
- CR_Cypriot,
- CR_Braille,
- CR_Buginese,
- CR_Coptic,
- CR_New_Tai_Lue,
- CR_Glagolitic,
- CR_Tifinagh,
- CR_Syloti_Nagri,
- CR_Old_Persian,
- CR_Kharoshthi,
- CR_Balinese,
- CR_Cuneiform,
- CR_Phoenician,
- CR_Phags_Pa,
- CR_Nko,
- CR_Sundanese,
- CR_Lepcha,
- CR_Ol_Chiki,
- CR_Vai,
- CR_Saurashtra,
- CR_Kayah_Li,
- CR_Rejang,
- CR_Lycian,
- CR_Carian,
- CR_Lydian,
- CR_Cham,
- CR_Tai_Tham,
- CR_Tai_Viet,
- CR_Avestan,
- CR_Egyptian_Hieroglyphs,
- CR_Samaritan,
- CR_Lisu,
- CR_Bamum,
- CR_Javanese,
- CR_Meetei_Mayek,
- CR_Imperial_Aramaic,
- CR_Old_South_Arabian,
- CR_Inscriptional_Parthian,
- CR_Inscriptional_Pahlavi,
- CR_Old_Turkic,
- CR_Kaithi,
- CR_Batak,
- CR_Brahmi,
- CR_Mandaic,
- CR_Chakma,
- CR_Meroitic_Cursive,
- CR_Meroitic_Hieroglyphs,
- CR_Miao,
- CR_Sharada,
- CR_Sora_Sompeng,
- CR_Takri,
- CR_Caucasian_Albanian,
- CR_Bassa_Vah,
- CR_Duployan,
- CR_Elbasan,
- CR_Grantha,
- CR_Pahawh_Hmong,
- CR_Khojki,
- CR_Linear_A,
- CR_Mahajani,
- CR_Manichaean,
- CR_Mende_Kikakui,
- CR_Modi,
- CR_Mro,
- CR_Old_North_Arabian,
- CR_Nabataean,
- CR_Palmyrene,
- CR_Pau_Cin_Hau,
- CR_Old_Permic,
- CR_Psalter_Pahlavi,
- CR_Siddham,
- CR_Khudawadi,
- CR_Tirhuta,
- CR_Warang_Citi,
- CR_Ahom,
- CR_Anatolian_Hieroglyphs,
- CR_Hatran,
- CR_Multani,
- CR_Old_Hungarian,
- CR_SignWriting,
- CR_Adlam,
- CR_Bhaiksuki,
- CR_Marchen,
- CR_Newa,
- CR_Osage,
- CR_Tangut,
- CR_Masaram_Gondi,
- CR_Nushu,
- CR_Soyombo,
- CR_Zanabazar_Square,
- CR_Dogra,
- CR_Gunjala_Gondi,
- CR_Makasar,
- CR_Medefaidrin,
- CR_Hanifi_Rohingya,
- CR_Sogdian,
- CR_Old_Sogdian,
- CR_Elymaic,
- CR_Nandinagari,
- CR_Nyiakeng_Puachue_Hmong,
- CR_Wancho,
- CR_Chorasmian,
- CR_Dives_Akuru,
- CR_Khitan_Small_Script,
- CR_Yezidi,
- CR_Cypro_Minoan,
- CR_Old_Uyghur,
- CR_Tangsa,
- CR_Toto,
- CR_Vithkuqi,
- CR_Kawi,
- CR_Nag_Mundari,
- CR_Garay,
- CR_Gurung_Khema,
- CR_Kirat_Rai,
- CR_Ol_Onal,
- CR_Sunuwar,
- CR_Todhri,
- CR_Tulu_Tigalari,
- CR_White_Space,
- CR_Bidi_Control,
- CR_Join_Control,
- CR_Dash,
- CR_Hyphen,
- CR_Quotation_Mark,
- CR_Terminal_Punctuation,
- CR_Other_Math,
- CR_Hex_Digit,
- CR_ASCII_Hex_Digit,
- CR_Other_Alphabetic,
- CR_Ideographic,
- CR_Diacritic,
- CR_Extender,
- CR_Other_Lowercase,
- CR_Other_Uppercase,
- CR_Noncharacter_Code_Point,
- CR_Other_Grapheme_Extend,
- CR_IDS_Binary_Operator,
- CR_IDS_Trinary_Operator,
- CR_IDS_Unary_Operator,
- CR_Radical,
- CR_Unified_Ideograph,
- CR_Other_Default_Ignorable_Code_Point,
- CR_Deprecated,
- CR_Soft_Dotted,
- CR_Logical_Order_Exception,
- CR_Other_ID_Start,
- CR_Other_ID_Continue,
- CR_ID_Compat_Math_Continue,
- CR_ID_Compat_Math_Start,
- CR_Sentence_Terminal,
- CR_Variation_Selector,
- CR_Pattern_White_Space,
- CR_Pattern_Syntax,
- CR_Prepended_Concatenation_Mark,
- CR_Regional_Indicator,
- CR_Modifier_Combining_Mark,
- CR_Emoji,
- CR_Emoji_Presentation,
- CR_Emoji_Modifier,
- CR_Emoji_Modifier_Base,
- CR_Emoji_Component,
- CR_Extended_Pictographic,
- CR_Unknown,
-#ifdef USE_UNICODE_AGE_PROPERTIES
- CR_Age_1_1,
- CR_Age_2_0,
- CR_Age_2_1,
- CR_Age_3_0,
- CR_Age_3_1,
- CR_Age_3_2,
- CR_Age_4_0,
- CR_Age_4_1,
- CR_Age_5_0,
- CR_Age_5_1,
- CR_Age_5_2,
- CR_Age_6_0,
- CR_Age_6_1,
- CR_Age_6_2,
- CR_Age_6_3,
- CR_Age_7_0,
- CR_Age_8_0,
- CR_Age_9_0,
- CR_Age_10_0,
- CR_Age_11_0,
- CR_Age_12_0,
- CR_Age_12_1,
- CR_Age_13_0,
- CR_Age_14_0,
- CR_Age_15_0,
- CR_Age_15_1,
- CR_Age_16_0,
-#endif /* USE_UNICODE_AGE_PROPERTIES */
- CR_Grapheme_Cluster_Break_Prepend,
- CR_Grapheme_Cluster_Break_CR,
- CR_Grapheme_Cluster_Break_LF,
- CR_Grapheme_Cluster_Break_Control,
- CR_Grapheme_Cluster_Break_Extend,
- CR_Grapheme_Cluster_Break_Regional_Indicator,
- CR_Grapheme_Cluster_Break_SpacingMark,
- CR_Grapheme_Cluster_Break_L,
- CR_Grapheme_Cluster_Break_V,
- CR_Grapheme_Cluster_Break_T,
- CR_Grapheme_Cluster_Break_LV,
- CR_Grapheme_Cluster_Break_LVT,
- CR_Grapheme_Cluster_Break_ZWJ,
- CR_In_Basic_Latin,
- CR_In_Latin_1_Supplement,
- CR_In_Latin_Extended_A,
- CR_In_Latin_Extended_B,
- CR_In_IPA_Extensions,
- CR_In_Spacing_Modifier_Letters,
- CR_In_Combining_Diacritical_Marks,
- CR_In_Greek_and_Coptic,
- CR_In_Cyrillic,
- CR_In_Cyrillic_Supplement,
- CR_In_Armenian,
- CR_In_Hebrew,
- CR_In_Arabic,
- CR_In_Syriac,
- CR_In_Arabic_Supplement,
- CR_In_Thaana,
- CR_In_NKo,
- CR_In_Samaritan,
- CR_In_Mandaic,
- CR_In_Syriac_Supplement,
- CR_In_Arabic_Extended_B,
- CR_In_Arabic_Extended_A,
- CR_In_Devanagari,
- CR_In_Bengali,
- CR_In_Gurmukhi,
- CR_In_Gujarati,
- CR_In_Oriya,
- CR_In_Tamil,
- CR_In_Telugu,
- CR_In_Kannada,
- CR_In_Malayalam,
- CR_In_Sinhala,
- CR_In_Thai,
- CR_In_Lao,
- CR_In_Tibetan,
- CR_In_Myanmar,
- CR_In_Georgian,
- CR_In_Hangul_Jamo,
- CR_In_Ethiopic,
- CR_In_Ethiopic_Supplement,
- CR_In_Cherokee,
- CR_In_Unified_Canadian_Aboriginal_Syllabics,
- CR_In_Ogham,
- CR_In_Runic,
- CR_In_Tagalog,
- CR_In_Hanunoo,
- CR_In_Buhid,
- CR_In_Tagbanwa,
- CR_In_Khmer,
- CR_In_Mongolian,
- CR_In_Unified_Canadian_Aboriginal_Syllabics_Extended,
- CR_In_Limbu,
- CR_In_Tai_Le,
- CR_In_New_Tai_Lue,
- CR_In_Khmer_Symbols,
- CR_In_Buginese,
- CR_In_Tai_Tham,
- CR_In_Combining_Diacritical_Marks_Extended,
- CR_In_Balinese,
- CR_In_Sundanese,
- CR_In_Batak,
- CR_In_Lepcha,
- CR_In_Ol_Chiki,
- CR_In_Cyrillic_Extended_C,
- CR_In_Georgian_Extended,
- CR_In_Sundanese_Supplement,
- CR_In_Vedic_Extensions,
- CR_In_Phonetic_Extensions,
- CR_In_Phonetic_Extensions_Supplement,
- CR_In_Combining_Diacritical_Marks_Supplement,
- CR_In_Latin_Extended_Additional,
- CR_In_Greek_Extended,
- CR_In_General_Punctuation,
- CR_In_Superscripts_and_Subscripts,
- CR_In_Currency_Symbols,
- CR_In_Combining_Diacritical_Marks_for_Symbols,
- CR_In_Letterlike_Symbols,
- CR_In_Number_Forms,
- CR_In_Arrows,
- CR_In_Mathematical_Operators,
- CR_In_Miscellaneous_Technical,
- CR_In_Control_Pictures,
- CR_In_Optical_Character_Recognition,
- CR_In_Enclosed_Alphanumerics,
- CR_In_Box_Drawing,
- CR_In_Block_Elements,
- CR_In_Geometric_Shapes,
- CR_In_Miscellaneous_Symbols,
- CR_In_Dingbats,
- CR_In_Miscellaneous_Mathematical_Symbols_A,
- CR_In_Supplemental_Arrows_A,
- CR_In_Braille_Patterns,
- CR_In_Supplemental_Arrows_B,
- CR_In_Miscellaneous_Mathematical_Symbols_B,
- CR_In_Supplemental_Mathematical_Operators,
- CR_In_Miscellaneous_Symbols_and_Arrows,
- CR_In_Glagolitic,
- CR_In_Latin_Extended_C,
- CR_In_Coptic,
- CR_In_Georgian_Supplement,
- CR_In_Tifinagh,
- CR_In_Ethiopic_Extended,
- CR_In_Cyrillic_Extended_A,
- CR_In_Supplemental_Punctuation,
- CR_In_CJK_Radicals_Supplement,
- CR_In_Kangxi_Radicals,
- CR_In_Ideographic_Description_Characters,
- CR_In_CJK_Symbols_and_Punctuation,
- CR_In_Hiragana,
- CR_In_Katakana,
- CR_In_Bopomofo,
- CR_In_Hangul_Compatibility_Jamo,
- CR_In_Kanbun,
- CR_In_Bopomofo_Extended,
- CR_In_CJK_Strokes,
- CR_In_Katakana_Phonetic_Extensions,
- CR_In_Enclosed_CJK_Letters_and_Months,
- CR_In_CJK_Compatibility,
- CR_In_CJK_Unified_Ideographs_Extension_A,
- CR_In_Yijing_Hexagram_Symbols,
- CR_In_CJK_Unified_Ideographs,
- CR_In_Yi_Syllables,
- CR_In_Yi_Radicals,
- CR_In_Lisu,
- CR_In_Vai,
- CR_In_Cyrillic_Extended_B,
- CR_In_Bamum,
- CR_In_Modifier_Tone_Letters,
- CR_In_Latin_Extended_D,
- CR_In_Syloti_Nagri,
- CR_In_Common_Indic_Number_Forms,
- CR_In_Phags_pa,
- CR_In_Saurashtra,
- CR_In_Devanagari_Extended,
- CR_In_Kayah_Li,
- CR_In_Rejang,
- CR_In_Hangul_Jamo_Extended_A,
- CR_In_Javanese,
- CR_In_Myanmar_Extended_B,
- CR_In_Cham,
- CR_In_Myanmar_Extended_A,
- CR_In_Tai_Viet,
- CR_In_Meetei_Mayek_Extensions,
- CR_In_Ethiopic_Extended_A,
- CR_In_Latin_Extended_E,
- CR_In_Cherokee_Supplement,
- CR_In_Meetei_Mayek,
- CR_In_Hangul_Syllables,
- CR_In_Hangul_Jamo_Extended_B,
- CR_In_High_Surrogates,
- CR_In_High_Private_Use_Surrogates,
- CR_In_Low_Surrogates,
- CR_In_Private_Use_Area,
- CR_In_CJK_Compatibility_Ideographs,
- CR_In_Alphabetic_Presentation_Forms,
- CR_In_Arabic_Presentation_Forms_A,
- CR_In_Variation_Selectors,
- CR_In_Vertical_Forms,
- CR_In_Combining_Half_Marks,
- CR_In_CJK_Compatibility_Forms,
- CR_In_Small_Form_Variants,
- CR_In_Arabic_Presentation_Forms_B,
- CR_In_Halfwidth_and_Fullwidth_Forms,
- CR_In_Specials,
- CR_In_Linear_B_Syllabary,
- CR_In_Linear_B_Ideograms,
- CR_In_Aegean_Numbers,
- CR_In_Ancient_Greek_Numbers,
- CR_In_Ancient_Symbols,
- CR_In_Phaistos_Disc,
- CR_In_Lycian,
- CR_In_Carian,
- CR_In_Coptic_Epact_Numbers,
- CR_In_Old_Italic,
- CR_In_Gothic,
- CR_In_Old_Permic,
- CR_In_Ugaritic,
- CR_In_Old_Persian,
- CR_In_Deseret,
- CR_In_Shavian,
- CR_In_Osmanya,
- CR_In_Osage,
- CR_In_Elbasan,
- CR_In_Caucasian_Albanian,
- CR_In_Vithkuqi,
- CR_In_Todhri,
- CR_In_Linear_A,
- CR_In_Latin_Extended_F,
- CR_In_Cypriot_Syllabary,
- CR_In_Imperial_Aramaic,
- CR_In_Palmyrene,
- CR_In_Nabataean,
- CR_In_Hatran,
- CR_In_Phoenician,
- CR_In_Lydian,
- CR_In_Meroitic_Hieroglyphs,
- CR_In_Meroitic_Cursive,
- CR_In_Kharoshthi,
- CR_In_Old_South_Arabian,
- CR_In_Old_North_Arabian,
- CR_In_Manichaean,
- CR_In_Avestan,
- CR_In_Inscriptional_Parthian,
- CR_In_Inscriptional_Pahlavi,
- CR_In_Psalter_Pahlavi,
- CR_In_Old_Turkic,
- CR_In_Old_Hungarian,
- CR_In_Hanifi_Rohingya,
- CR_In_Garay,
- CR_In_Rumi_Numeral_Symbols,
- CR_In_Yezidi,
- CR_In_Arabic_Extended_C,
- CR_In_Old_Sogdian,
- CR_In_Sogdian,
- CR_In_Old_Uyghur,
- CR_In_Chorasmian,
- CR_In_Elymaic,
- CR_In_Brahmi,
- CR_In_Kaithi,
- CR_In_Sora_Sompeng,
- CR_In_Chakma,
- CR_In_Mahajani,
- CR_In_Sharada,
- CR_In_Sinhala_Archaic_Numbers,
- CR_In_Khojki,
- CR_In_Multani,
- CR_In_Khudawadi,
- CR_In_Grantha,
- CR_In_Tulu_Tigalari,
- CR_In_Newa,
- CR_In_Tirhuta,
- CR_In_Siddham,
- CR_In_Modi,
- CR_In_Mongolian_Supplement,
- CR_In_Takri,
- CR_In_Myanmar_Extended_C,
- CR_In_Ahom,
- CR_In_Dogra,
- CR_In_Warang_Citi,
- CR_In_Dives_Akuru,
- CR_In_Nandinagari,
- CR_In_Zanabazar_Square,
- CR_In_Soyombo,
- CR_In_Unified_Canadian_Aboriginal_Syllabics_Extended_A,
- CR_In_Pau_Cin_Hau,
- CR_In_Devanagari_Extended_A,
- CR_In_Sunuwar,
- CR_In_Bhaiksuki,
- CR_In_Marchen,
- CR_In_Masaram_Gondi,
- CR_In_Gunjala_Gondi,
- CR_In_Makasar,
- CR_In_Kawi,
- CR_In_Lisu_Supplement,
- CR_In_Tamil_Supplement,
- CR_In_Cuneiform,
- CR_In_Cuneiform_Numbers_and_Punctuation,
- CR_In_Early_Dynastic_Cuneiform,
- CR_In_Cypro_Minoan,
- CR_In_Egyptian_Hieroglyphs,
- CR_In_Egyptian_Hieroglyph_Format_Controls,
- CR_In_Egyptian_Hieroglyphs_Extended_A,
- CR_In_Anatolian_Hieroglyphs,
- CR_In_Gurung_Khema,
- CR_In_Bamum_Supplement,
- CR_In_Mro,
- CR_In_Tangsa,
- CR_In_Bassa_Vah,
- CR_In_Pahawh_Hmong,
- CR_In_Kirat_Rai,
- CR_In_Medefaidrin,
- CR_In_Miao,
- CR_In_Ideographic_Symbols_and_Punctuation,
- CR_In_Tangut,
- CR_In_Tangut_Components,
- CR_In_Khitan_Small_Script,
- CR_In_Tangut_Supplement,
- CR_In_Kana_Extended_B,
- CR_In_Kana_Supplement,
- CR_In_Kana_Extended_A,
- CR_In_Small_Kana_Extension,
- CR_In_Nushu,
- CR_In_Duployan,
- CR_In_Shorthand_Format_Controls,
- CR_In_Symbols_for_Legacy_Computing_Supplement,
- CR_In_Znamenny_Musical_Notation,
- CR_In_Byzantine_Musical_Symbols,
- CR_In_Musical_Symbols,
- CR_In_Ancient_Greek_Musical_Notation,
- CR_In_Kaktovik_Numerals,
- CR_In_Mayan_Numerals,
- CR_In_Tai_Xuan_Jing_Symbols,
- CR_In_Counting_Rod_Numerals,
- CR_In_Mathematical_Alphanumeric_Symbols,
- CR_In_Sutton_SignWriting,
- CR_In_Latin_Extended_G,
- CR_In_Glagolitic_Supplement,
- CR_In_Cyrillic_Extended_D,
- CR_In_Nyiakeng_Puachue_Hmong,
- CR_In_Toto,
- CR_In_Wancho,
- CR_In_Nag_Mundari,
- CR_In_Ol_Onal,
- CR_In_Ethiopic_Extended_B,
- CR_In_Mende_Kikakui,
- CR_In_Adlam,
- CR_In_Indic_Siyaq_Numbers,
- CR_In_Ottoman_Siyaq_Numbers,
- CR_In_Arabic_Mathematical_Alphabetic_Symbols,
- CR_In_Mahjong_Tiles,
- CR_In_Domino_Tiles,
- CR_In_Playing_Cards,
- CR_In_Enclosed_Alphanumeric_Supplement,
- CR_In_Enclosed_Ideographic_Supplement,
- CR_In_Miscellaneous_Symbols_and_Pictographs,
- CR_In_Emoticons,
- CR_In_Ornamental_Dingbats,
- CR_In_Transport_and_Map_Symbols,
- CR_In_Alchemical_Symbols,
- CR_In_Geometric_Shapes_Extended,
- CR_In_Supplemental_Arrows_C,
- CR_In_Supplemental_Symbols_and_Pictographs,
- CR_In_Chess_Symbols,
- CR_In_Symbols_and_Pictographs_Extended_A,
- CR_In_Symbols_for_Legacy_Computing,
- CR_In_CJK_Unified_Ideographs_Extension_B,
- CR_In_CJK_Unified_Ideographs_Extension_C,
- CR_In_CJK_Unified_Ideographs_Extension_D,
- CR_In_CJK_Unified_Ideographs_Extension_E,
- CR_In_CJK_Unified_Ideographs_Extension_F,
- CR_In_CJK_Unified_Ideographs_Extension_I,
- CR_In_CJK_Compatibility_Ideographs_Supplement,
- CR_In_CJK_Unified_Ideographs_Extension_G,
- CR_In_CJK_Unified_Ideographs_Extension_H,
- CR_In_Tags,
- CR_In_Variation_Selectors_Supplement,
- CR_In_Supplementary_Private_Use_Area_A,
- CR_In_Supplementary_Private_Use_Area_B,
- CR_In_No_Block,
-#endif /* USE_UNICODE_PROPERTIES */
-};
-struct uniname2ctype_struct {
- short name;
- unsigned short ctype;
-};
-#define uniname2ctype_offset(str) offsetof(struct uniname2ctype_pool_t, uniname2ctype_pool_##str)
-
-static const struct uniname2ctype_struct *uniname2ctype_p(register const char *str, register size_t len);
-
-#ifndef USE_UNICODE_PROPERTIES
-#define TOTAL_KEYWORDS 15
-#define MIN_WORD_LENGTH 4
-#define MAX_WORD_LENGTH 11
-#define MIN_HASH_VALUE 6
-#define MAX_HASH_VALUE 20
-/* maximum key range = 15, duplicates = 0 */
-#else /* USE_UNICODE_PROPERTIES */
-#ifndef USE_UNICODE_AGE_PROPERTIES
-#define TOTAL_KEYWORDS 900
-#else /* USE_UNICODE_AGE_PROPERTIES */
-#define TOTAL_KEYWORDS 927
-#endif /* USE_UNICODE_AGE_PROPERTIES */
-#define MIN_WORD_LENGTH 1
-#define MAX_WORD_LENGTH 45
-#define MIN_HASH_VALUE 12
-#define MAX_HASH_VALUE 6807
-/* maximum key range = 6796, duplicates = 0 */
-#endif /* USE_UNICODE_PROPERTIES */
-
-#ifdef __GNUC__
-__inline
-#else
-#ifdef __cplusplus
-inline
-#endif
-#endif
-static unsigned int
-uniname2ctype_hash (register const char *str, register size_t len)
-{
-#ifndef USE_UNICODE_PROPERTIES
- static const unsigned char asso_values[] =
-#else /* USE_UNICODE_PROPERTIES */
- static const unsigned short asso_values[] =
-#endif /* USE_UNICODE_PROPERTIES */
- {
-#ifndef USE_UNICODE_PROPERTIES
- 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,
- 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,
- 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,
- 21, 21, 21, 21, 21, 21, 21, 3, 12, 5,
- 4, 21, 21, 10, 21, 1, 21, 21, 11, 21,
- 2, 1, 1, 21, 1, 7, 4, 6, 21, 1,
- 4, 21, 21, 21, 21, 21, 21, 21
-#else /* USE_UNICODE_PROPERTIES */
- 6808, 6808, 6808, 6808, 6808, 6808, 6808, 6808, 6808, 6808,
- 6808, 6808, 6808, 6808, 6808, 6808, 6808, 6808, 6808, 6808,
- 6808, 6808, 6808, 6808, 6808, 6808, 6808, 6808, 6808, 6808,
- 6808, 6808, 6808, 6808, 6808, 6808, 6808, 6808, 6808, 6808,
-#ifndef USE_UNICODE_AGE_PROPERTIES
- 6808, 6808, 6808, 6808, 6808, 6808, 6808, 6808, 6808, 6808,
- 6808, 6808, 6808, 6808, 6808, 6808, 6808, 6808, 6808, 6808,
-#else /* USE_UNICODE_AGE_PROPERTIES */
- 6808, 6808, 6808, 6808, 6808, 6808, 7, 6808, 2, 1,
- 4, 42, 27, 21, 6, 10, 9, 2, 6808, 6808,
-#endif /* USE_UNICODE_AGE_PROPERTIES */
- 6808, 1, 6808, 6808, 6808, 6808, 6808, 6808, 6808, 6808,
- 6808, 6808, 6808, 6808, 6808, 6808, 6808, 6808, 6808, 6808,
- 6808, 6808, 6808, 6808, 6808, 6808, 6808, 6808, 6808, 6808,
- 6808, 6808, 6808, 6808, 6808, 6808, 6808, 1, 1475, 140,
- 423, 30, 1736, 1065, 1241, 5, 907, 6, 795, 96,
- 3, 10, 1388, 543, 48, 197, 370, 502, 1709, 2040,
- 816, 2019, 52, 5, 12, 6808, 6808, 6808, 6808, 6808
-#endif /* USE_UNICODE_PROPERTIES */
- };
-#ifndef USE_UNICODE_PROPERTIES
- return len + asso_values[(unsigned char)str[2]] + asso_values[(unsigned char)str[0]];
-#else /* USE_UNICODE_PROPERTIES */
- register unsigned int hval = (unsigned int)len;
-
- switch (hval)
- {
- default:
- hval += asso_values[(unsigned char)str[15]];
- /*FALLTHROUGH*/
- case 15:
- case 14:
- case 13:
- case 12:
- hval += asso_values[(unsigned char)str[11]];
- /*FALLTHROUGH*/
- case 11:
- case 10:
- case 9:
- case 8:
- case 7:
- case 6:
- hval += asso_values[(unsigned char)str[5]];
- /*FALLTHROUGH*/
- case 5:
- hval += asso_values[(unsigned char)str[4]];
- /*FALLTHROUGH*/
- case 4:
- case 3:
- hval += asso_values[(unsigned char)str[2]];
- /*FALLTHROUGH*/
- case 2:
- hval += asso_values[(unsigned char)str[1]];
- /*FALLTHROUGH*/
- case 1:
- hval += asso_values[(unsigned char)str[0]+2];
- break;
- }
- return hval + asso_values[(unsigned char)str[len - 1]];
-#endif /* USE_UNICODE_PROPERTIES */
-}
-
-struct uniname2ctype_pool_t
- {
-#ifndef USE_UNICODE_PROPERTIES
- char uniname2ctype_pool_str6[sizeof("word")];
- char uniname2ctype_pool_str7[sizeof("print")];
- char uniname2ctype_pool_str8[sizeof("punct")];
- char uniname2ctype_pool_str9[sizeof("alpha")];
- char uniname2ctype_pool_str10[sizeof("alnum")];
- char uniname2ctype_pool_str11[sizeof("xdigit")];
- char uniname2ctype_pool_str12[sizeof("upper")];
- char uniname2ctype_pool_str13[sizeof("ascii")];
- char uniname2ctype_pool_str14[sizeof("cntrl")];
- char uniname2ctype_pool_str15[sizeof("space")];
- char uniname2ctype_pool_str16[sizeof("xposixpunct")];
- char uniname2ctype_pool_str17[sizeof("lower")];
- char uniname2ctype_pool_str18[sizeof("graph")];
- char uniname2ctype_pool_str19[sizeof("digit")];
- char uniname2ctype_pool_str20[sizeof("blank")];
-#else /* USE_UNICODE_PROPERTIES */
- char uniname2ctype_pool_str12[sizeof("lana")];
- char uniname2ctype_pool_str16[sizeof("lina")];
- char uniname2ctype_pool_str17[sizeof("yi")];
- char uniname2ctype_pool_str18[sizeof("mn")];
- char uniname2ctype_pool_str22[sizeof("maka")];
- char uniname2ctype_pool_str23[sizeof("mani")];
- char uniname2ctype_pool_str24[sizeof("yiii")];
- char uniname2ctype_pool_str25[sizeof("lo")];
- char uniname2ctype_pool_str27[sizeof("lao")];
- char uniname2ctype_pool_str28[sizeof("laoo")];
- char uniname2ctype_pool_str30[sizeof("miao")];
- char uniname2ctype_pool_str31[sizeof("inkannada")];
- char uniname2ctype_pool_str37[sizeof("innko")];
- char uniname2ctype_pool_str38[sizeof("cn")];
- char uniname2ctype_pool_str42[sizeof("ci")];
- char uniname2ctype_pool_str52[sizeof("co")];
- char uniname2ctype_pool_str59[sizeof("gara")];
- char uniname2ctype_pool_str60[sizeof("pi")];
- char uniname2ctype_pool_str61[sizeof("gran")];
- char uniname2ctype_pool_str65[sizeof("z")];
- char uniname2ctype_pool_str68[sizeof("lineara")];
- char uniname2ctype_pool_str69[sizeof("mark")];
- char uniname2ctype_pool_str70[sizeof("po")];
- char uniname2ctype_pool_str72[sizeof("me")];
- char uniname2ctype_pool_str76[sizeof("loe")];
- char uniname2ctype_pool_str79[sizeof("inkiratrai")];
- char uniname2ctype_pool_str81[sizeof("mro")];
- char uniname2ctype_pool_str82[sizeof("mroo")];
- char uniname2ctype_pool_str86[sizeof("inkharoshthi")];
- char uniname2ctype_pool_str88[sizeof("cari")];
- char uniname2ctype_pool_str92[sizeof("carian")];
- char uniname2ctype_pool_str93[sizeof("grek")];
- char uniname2ctype_pool_str96[sizeof("yezi")];
- char uniname2ctype_pool_str97[sizeof("geor")];
- char uniname2ctype_pool_str100[sizeof("greek")];
- char uniname2ctype_pool_str101[sizeof("mendekikakui")];
- char uniname2ctype_pool_str102[sizeof("mero")];
- char uniname2ctype_pool_str105[sizeof("kana")];
- char uniname2ctype_pool_str107[sizeof("m")];
- char uniname2ctype_pool_str110[sizeof("pe")];
- char uniname2ctype_pool_str118[sizeof("gonm")];
- char uniname2ctype_pool_str122[sizeof("meeteimayek")];
- char uniname2ctype_pool_str126[sizeof("inosmanya")];
- char uniname2ctype_pool_str130[sizeof("inmro")];
- char uniname2ctype_pool_str131[sizeof("inmanichaean")];
- char uniname2ctype_pool_str132[sizeof("inmiao")];
- char uniname2ctype_pool_str137[sizeof("cakm")];
- char uniname2ctype_pool_str149[sizeof("inarmenian")];
- char uniname2ctype_pool_str154[sizeof("krai")];
- char uniname2ctype_pool_str158[sizeof("common")];
- char uniname2ctype_pool_str165[sizeof("inchakma")];
- char uniname2ctype_pool_str166[sizeof("inmyanmar")];
- char uniname2ctype_pool_str167[sizeof("mandaic")];
- char uniname2ctype_pool_str169[sizeof("inmakasar")];
- char uniname2ctype_pool_str171[sizeof("c")];
- char uniname2ctype_pool_str172[sizeof("zzzz")];
- char uniname2ctype_pool_str192[sizeof("inideographicsymbolsandpunctuation")];
- char uniname2ctype_pool_str196[sizeof("inkhmer")];
- char uniname2ctype_pool_str197[sizeof("lm")];
- char uniname2ctype_pool_str203[sizeof("marc")];
- char uniname2ctype_pool_str208[sizeof("qaai")];
- char uniname2ctype_pool_str211[sizeof("combiningmark")];
- char uniname2ctype_pool_str212[sizeof("inrunic")];
- char uniname2ctype_pool_str213[sizeof("incarian")];
- char uniname2ctype_pool_str218[sizeof("inahom")];
- char uniname2ctype_pool_str224[sizeof("prependedconcatenationmark")];
- char uniname2ctype_pool_str225[sizeof("inchorasmian")];
- char uniname2ctype_pool_str226[sizeof("perm")];
- char uniname2ctype_pool_str232[sizeof("merc")];
- char uniname2ctype_pool_str235[sizeof("cans")];
- char uniname2ctype_pool_str240[sizeof("connectorpunctuation")];
- char uniname2ctype_pool_str249[sizeof("inavestan")];
- char uniname2ctype_pool_str250[sizeof("incuneiformnumbersandpunctuation")];
- char uniname2ctype_pool_str262[sizeof("inipaextensions")];
- char uniname2ctype_pool_str265[sizeof("insharada")];
- char uniname2ctype_pool_str267[sizeof("incherokee")];
- char uniname2ctype_pool_str270[sizeof("makasar")];
- char uniname2ctype_pool_str273[sizeof("inarrows")];
- char uniname2ctype_pool_str279[sizeof("masaramgondi")];
- char uniname2ctype_pool_str285[sizeof("lc")];
- char uniname2ctype_pool_str289[sizeof("incuneiform")];
- char uniname2ctype_pool_str291[sizeof("armn")];
- char uniname2ctype_pool_str292[sizeof("mc")];
- char uniname2ctype_pool_str293[sizeof("armi")];
- char uniname2ctype_pool_str303[sizeof("armenian")];
- char uniname2ctype_pool_str305[sizeof("inmarchen")];
- char uniname2ctype_pool_str309[sizeof("lineseparator")];
- char uniname2ctype_pool_str311[sizeof("qmark")];
- char uniname2ctype_pool_str312[sizeof("cc")];
- char uniname2ctype_pool_str317[sizeof("insamaritan")];
- char uniname2ctype_pool_str325[sizeof("inmasaramgondi")];
- char uniname2ctype_pool_str330[sizeof("pc")];
- char uniname2ctype_pool_str332[sizeof("inscriptionalparthian")];
- char uniname2ctype_pool_str343[sizeof("qaac")];
- char uniname2ctype_pool_str345[sizeof("mcm")];
- char uniname2ctype_pool_str348[sizeof("incham")];
- char uniname2ctype_pool_str352[sizeof("incyrillic")];
- char uniname2ctype_pool_str357[sizeof("inzanabazarsquare")];
- char uniname2ctype_pool_str362[sizeof("inkhmersymbols")];
- char uniname2ctype_pool_str381[sizeof("latn")];
- char uniname2ctype_pool_str382[sizeof("ri")];
- char uniname2ctype_pool_str383[sizeof("pcm")];
- char uniname2ctype_pool_str385[sizeof("latin")];
- char uniname2ctype_pool_str390[sizeof("inthaana")];
- char uniname2ctype_pool_str396[sizeof("inthai")];
- char uniname2ctype_pool_str397[sizeof("inkatakana")];
- char uniname2ctype_pool_str403[sizeof("inkaithi")];
- char uniname2ctype_pool_str407[sizeof("insyriac")];
- char uniname2ctype_pool_str408[sizeof("zs")];
- char uniname2ctype_pool_str416[sizeof("initialpunctuation")];
- char uniname2ctype_pool_str419[sizeof("mtei")];
- char uniname2ctype_pool_str426[sizeof("cs")];
- char uniname2ctype_pool_str441[sizeof("mand")];
- char uniname2ctype_pool_str444[sizeof("ps")];
- char uniname2ctype_pool_str445[sizeof("intakri")];
- char uniname2ctype_pool_str452[sizeof("modi")];
- char uniname2ctype_pool_str458[sizeof("inkanaextendeda")];
- char uniname2ctype_pool_str470[sizeof("mend")];
- char uniname2ctype_pool_str472[sizeof("inruminumeralsymbols")];
- char uniname2ctype_pool_str473[sizeof("ideo")];
- char uniname2ctype_pool_str475[sizeof("prti")];
- char uniname2ctype_pool_str480[sizeof("arabic")];
- char uniname2ctype_pool_str481[sizeof("brai")];
- char uniname2ctype_pool_str483[sizeof("katakana")];
- char uniname2ctype_pool_str487[sizeof("inideographicdescriptioncharacters")];
- char uniname2ctype_pool_str492[sizeof("ascii")];
- char uniname2ctype_pool_str504[sizeof("innandinagari")];
- char uniname2ctype_pool_str512[sizeof("privateuse")];
- char uniname2ctype_pool_str514[sizeof("inoldnortharabian")];
- char uniname2ctype_pool_str516[sizeof("sk")];
- char uniname2ctype_pool_str524[sizeof("so")];
- char uniname2ctype_pool_str525[sizeof("incjkcompatibilityforms")];
- char uniname2ctype_pool_str526[sizeof("yezidi")];
- char uniname2ctype_pool_str527[sizeof("knda")];
- char uniname2ctype_pool_str528[sizeof("inmyanmarextendeda")];
- char uniname2ctype_pool_str530[sizeof("incjkcompatibilityideographs")];
- char uniname2ctype_pool_str532[sizeof("kannada")];
- char uniname2ctype_pool_str534[sizeof("xidcontinue")];
- char uniname2ctype_pool_str535[sizeof("letter")];
- char uniname2ctype_pool_str544[sizeof("inmodi")];
- char uniname2ctype_pool_str554[sizeof("inmeeteimayek")];
- char uniname2ctype_pool_str556[sizeof("inmendekikakui")];
- char uniname2ctype_pool_str561[sizeof("onao")];
- char uniname2ctype_pool_str565[sizeof("sora")];
- char uniname2ctype_pool_str579[sizeof("inmedefaidrin")];
- char uniname2ctype_pool_str580[sizeof("kiratrai")];
- char uniname2ctype_pool_str583[sizeof("inspecials")];
- char uniname2ctype_pool_str584[sizeof("brahmi")];
- char uniname2ctype_pool_str589[sizeof("letternumber")];
- char uniname2ctype_pool_str597[sizeof("inchesssymbols")];
- char uniname2ctype_pool_str598[sizeof("inolditalic")];
- char uniname2ctype_pool_str603[sizeof("oriya")];
- char uniname2ctype_pool_str604[sizeof("inmiscellaneousmathematicalsymbolsa")];
- char uniname2ctype_pool_str606[sizeof("intransportandmapsymbols")];
- char uniname2ctype_pool_str614[sizeof("incb=extend")];
- char uniname2ctype_pool_str624[sizeof("xidc")];
- char uniname2ctype_pool_str627[sizeof("inemoticons")];
- char uniname2ctype_pool_str651[sizeof("samr")];
- char uniname2ctype_pool_str657[sizeof("inoldsogdian")];
- char uniname2ctype_pool_str661[sizeof("inancientsymbols")];
- char uniname2ctype_pool_str663[sizeof("incommonindicnumberforms")];
- char uniname2ctype_pool_str664[sizeof("samaritan")];
- char uniname2ctype_pool_str666[sizeof("psalterpahlavi")];
- char uniname2ctype_pool_str667[sizeof("inmyanmarextendedc")];
- char uniname2ctype_pool_str672[sizeof("kits")];
- char uniname2ctype_pool_str673[sizeof("insundanese")];
- char uniname2ctype_pool_str675[sizeof("incb=consonant")];
- char uniname2ctype_pool_str676[sizeof("gothic")];
- char uniname2ctype_pool_str680[sizeof("inmandaic")];
- char uniname2ctype_pool_str681[sizeof("xids")];
- char uniname2ctype_pool_str689[sizeof("inznamennymusicalnotation")];
- char uniname2ctype_pool_str695[sizeof("pauc")];
- char uniname2ctype_pool_str696[sizeof("sm")];
- char uniname2ctype_pool_str700[sizeof("s")];
- char uniname2ctype_pool_str705[sizeof("meroiticcursive")];
- char uniname2ctype_pool_str708[sizeof("inoldsoutharabian")];
- char uniname2ctype_pool_str710[sizeof("inugaritic")];
- char uniname2ctype_pool_str711[sizeof("lisu")];
- char uniname2ctype_pool_str712[sizeof("idc")];
- char uniname2ctype_pool_str713[sizeof("incjkcompatibilityideographssupplement")];
- char uniname2ctype_pool_str714[sizeof("patternwhitespace")];
- char uniname2ctype_pool_str717[sizeof("bamum")];
- char uniname2ctype_pool_str719[sizeof("inancientgreekmusicalnotation")];
- char uniname2ctype_pool_str739[sizeof("idsbinaryoperator")];
- char uniname2ctype_pool_str745[sizeof("lt")];
- char uniname2ctype_pool_str758[sizeof("incjkstrokes")];
- char uniname2ctype_pool_str768[sizeof("insunuwar")];
- char uniname2ctype_pool_str770[sizeof("insaurashtra")];
- char uniname2ctype_pool_str773[sizeof("indominotiles")];
- char uniname2ctype_pool_str775[sizeof("intoto")];
- char uniname2ctype_pool_str784[sizeof("sc")];
- char uniname2ctype_pool_str790[sizeof("idsunaryoperator")];
- char uniname2ctype_pool_str791[sizeof("inmodifiertoneletters")];
- char uniname2ctype_pool_str797[sizeof("inopticalcharacterrecognition")];
- char uniname2ctype_pool_str799[sizeof("l")];
- char uniname2ctype_pool_str804[sizeof("batk")];
- char uniname2ctype_pool_str805[sizeof("inkanasupplement")];
- char uniname2ctype_pool_str806[sizeof("osage")];
- char uniname2ctype_pool_str811[sizeof("batak")];
- char uniname2ctype_pool_str813[sizeof("inmusicalsymbols")];
- char uniname2ctype_pool_str817[sizeof("incaucasianalbanian")];
- char uniname2ctype_pool_str818[sizeof("patws")];
- char uniname2ctype_pool_str822[sizeof("bass")];
- char uniname2ctype_pool_str826[sizeof("ids")];
- char uniname2ctype_pool_str828[sizeof("grext")];
- char uniname2ctype_pool_str829[sizeof("inlao")];
- char uniname2ctype_pool_str830[sizeof("vai")];
- char uniname2ctype_pool_str831[sizeof("vaii")];
- char uniname2ctype_pool_str835[sizeof("inolonal")];
- char uniname2ctype_pool_str840[sizeof("mongolian")];
- char uniname2ctype_pool_str841[sizeof("osma")];
- char uniname2ctype_pool_str846[sizeof("print")];
- char uniname2ctype_pool_str847[sizeof("inlineara")];
- char uniname2ctype_pool_str859[sizeof("intaitham")];
- char uniname2ctype_pool_str869[sizeof("grlink")];
- char uniname2ctype_pool_str888[sizeof("inmiscellaneoussymbols")];
- char uniname2ctype_pool_str896[sizeof("pd")];
- char uniname2ctype_pool_str897[sizeof("inmiscellaneoussymbolsandarrows")];
- char uniname2ctype_pool_str901[sizeof("kali")];
- char uniname2ctype_pool_str902[sizeof("inmiscellaneoussymbolsandpictographs")];
- char uniname2ctype_pool_str903[sizeof("control")];
- char uniname2ctype_pool_str905[sizeof("inancientgreeknumbers")];
- char uniname2ctype_pool_str906[sizeof("incontrolpictures")];
- char uniname2ctype_pool_str909[sizeof("inadlam")];
- char uniname2ctype_pool_str917[sizeof("han")];
- char uniname2ctype_pool_str920[sizeof("hani")];
- char uniname2ctype_pool_str925[sizeof("hano")];
- char uniname2ctype_pool_str927[sizeof("runr")];
- char uniname2ctype_pool_str937[sizeof("sind")];
- char uniname2ctype_pool_str941[sizeof("hanunoo")];
- char uniname2ctype_pool_str944[sizeof("palm")];
- char uniname2ctype_pool_str945[sizeof("inkhojki")];
- char uniname2ctype_pool_str956[sizeof("inkhudawadi")];
- char uniname2ctype_pool_str960[sizeof("inlycian")];
- char uniname2ctype_pool_str963[sizeof("inoldturkic")];
- char uniname2ctype_pool_str965[sizeof("hira")];
- char uniname2ctype_pool_str978[sizeof("incountingrodnumerals")];
- char uniname2ctype_pool_str979[sizeof("odi")];
- char uniname2ctype_pool_str982[sizeof("idcontinue")];
- char uniname2ctype_pool_str1000[sizeof("idst")];
- char uniname2ctype_pool_str1003[sizeof("inolduyghur")];
- char uniname2ctype_pool_str1004[sizeof("incb=linker")];
- char uniname2ctype_pool_str1008[sizeof("inmalayalam")];
- char uniname2ctype_pool_str1009[sizeof("lu")];
- char uniname2ctype_pool_str1021[sizeof("inspacingmodifierletters")];
- char uniname2ctype_pool_str1026[sizeof("bamu")];
- char uniname2ctype_pool_str1038[sizeof("indeseret")];
- char uniname2ctype_pool_str1050[sizeof("sundanese")];
- char uniname2ctype_pool_str1052[sizeof("idstart")];
- char uniname2ctype_pool_str1057[sizeof("saur")];
- char uniname2ctype_pool_str1058[sizeof("insmallkanaextension")];
- char uniname2ctype_pool_str1061[sizeof("guru")];
- char uniname2ctype_pool_str1070[sizeof("paucinhau")];
- char uniname2ctype_pool_str1076[sizeof("gurmukhi")];
- char uniname2ctype_pool_str1077[sizeof("insylotinagri")];
- char uniname2ctype_pool_str1079[sizeof("cased")];
- char uniname2ctype_pool_str1083[sizeof("inlinearbideograms")];
- char uniname2ctype_pool_str1087[sizeof("gong")];
- char uniname2ctype_pool_str1088[sizeof("ingrantha")];
- char uniname2ctype_pool_str1092[sizeof("mong")];
- char uniname2ctype_pool_str1095[sizeof("joinc")];
- char uniname2ctype_pool_str1099[sizeof("sterm")];
- char uniname2ctype_pool_str1109[sizeof("inkaktoviknumerals")];
- char uniname2ctype_pool_str1113[sizeof("limbu")];
- char uniname2ctype_pool_str1115[sizeof("oidc")];
- char uniname2ctype_pool_str1122[sizeof("inosage")];
- char uniname2ctype_pool_str1123[sizeof("incjkunifiedideographsextensiona")];
- char uniname2ctype_pool_str1124[sizeof("incyrillicsupplement")];
- char uniname2ctype_pool_str1125[sizeof("inmeeteimayekextensions")];
- char uniname2ctype_pool_str1126[sizeof("georgian")];
- char uniname2ctype_pool_str1127[sizeof("incjkunifiedideographsextensioni")];
- char uniname2ctype_pool_str1132[sizeof("idsu")];
- char uniname2ctype_pool_str1134[sizeof("ingeneralpunctuation")];
- char uniname2ctype_pool_str1135[sizeof("alnum")];
- char uniname2ctype_pool_str1136[sizeof("bidic")];
- char uniname2ctype_pool_str1145[sizeof("ingeorgian")];
- char uniname2ctype_pool_str1147[sizeof("quotationmark")];
- char uniname2ctype_pool_str1149[sizeof("incherokeesupplement")];
- char uniname2ctype_pool_str1152[sizeof("incjkunifiedideographsextensione")];
- char uniname2ctype_pool_str1157[sizeof("insiddham")];
- char uniname2ctype_pool_str1160[sizeof("runic")];
- char uniname2ctype_pool_str1172[sizeof("oids")];
- char uniname2ctype_pool_str1176[sizeof("ital")];
- char uniname2ctype_pool_str1186[sizeof("emoji")];
- char uniname2ctype_pool_str1187[sizeof("inmongolian")];
- char uniname2ctype_pool_str1195[sizeof("innagmundari")];
- char uniname2ctype_pool_str1200[sizeof("inlatinextendeda")];
- char uniname2ctype_pool_str1212[sizeof("vs")];
- char uniname2ctype_pool_str1214[sizeof("saurashtra")];
- char uniname2ctype_pool_str1216[sizeof("intaile")];
- char uniname2ctype_pool_str1228[sizeof("bali")];
- char uniname2ctype_pool_str1229[sizeof("xidstart")];
- char uniname2ctype_pool_str1231[sizeof("xdigit")];
- char uniname2ctype_pool_str1233[sizeof("ingurmukhi")];
- char uniname2ctype_pool_str1236[sizeof("blank")];
- char uniname2ctype_pool_str1243[sizeof("inlydian")];
-#ifdef USE_UNICODE_AGE_PROPERTIES
- char uniname2ctype_pool_str1247[sizeof("age=11.0")];
- char uniname2ctype_pool_str1248[sizeof("age=10.0")];
- char uniname2ctype_pool_str1249[sizeof("age=12.1")];
- char uniname2ctype_pool_str1250[sizeof("age=12.0")];
- char uniname2ctype_pool_str1251[sizeof("age=1.1")];
- char uniname2ctype_pool_str1252[sizeof("age=16.0")];
- char uniname2ctype_pool_str1253[sizeof("age=9.0")];
- char uniname2ctype_pool_str1254[sizeof("age=2.1")];
- char uniname2ctype_pool_str1255[sizeof("age=2.0")];
- char uniname2ctype_pool_str1256[sizeof("age=6.1")];
- char uniname2ctype_pool_str1257[sizeof("age=6.0")];
-#endif /* USE_UNICODE_AGE_PROPERTIES */
- char uniname2ctype_pool_str1258[sizeof("inlatinextendede")];
-#ifdef USE_UNICODE_AGE_PROPERTIES
- char uniname2ctype_pool_str1259[sizeof("age=6.2")];
- char uniname2ctype_pool_str1260[sizeof("age=8.0")];
- char uniname2ctype_pool_str1261[sizeof("age=7.0")];
-#endif /* USE_UNICODE_AGE_PROPERTIES */
- char uniname2ctype_pool_str1262[sizeof("incjkunifiedideographsextensionc")];
- char uniname2ctype_pool_str1264[sizeof("bengali")];
- char uniname2ctype_pool_str1265[sizeof("zinh")];
-#ifdef USE_UNICODE_AGE_PROPERTIES
- char uniname2ctype_pool_str1266[sizeof("age=15.1")];
- char uniname2ctype_pool_str1267[sizeof("age=15.0")];
- char uniname2ctype_pool_str1271[sizeof("age=5.1")];
- char uniname2ctype_pool_str1272[sizeof("age=5.0")];
- char uniname2ctype_pool_str1273[sizeof("age=14.0")];
- char uniname2ctype_pool_str1274[sizeof("age=5.2")];
- char uniname2ctype_pool_str1277[sizeof("age=4.1")];
- char uniname2ctype_pool_str1278[sizeof("age=4.0")];
-#endif /* USE_UNICODE_AGE_PROPERTIES */
- char uniname2ctype_pool_str1281[sizeof("inhanifirohingya")];
- char uniname2ctype_pool_str1282[sizeof("intamil")];
- char uniname2ctype_pool_str1284[sizeof("inmultani")];
-#ifdef USE_UNICODE_AGE_PROPERTIES
- char uniname2ctype_pool_str1288[sizeof("age=13.0")];
-#endif /* USE_UNICODE_AGE_PROPERTIES */
- char uniname2ctype_pool_str1290[sizeof("balinese")];
- char uniname2ctype_pool_str1291[sizeof("hatran")];
-#ifdef USE_UNICODE_AGE_PROPERTIES
- char uniname2ctype_pool_str1292[sizeof("age=3.1")];
- char uniname2ctype_pool_str1293[sizeof("age=3.0")];
- char uniname2ctype_pool_str1295[sizeof("age=3.2")];
- char uniname2ctype_pool_str1297[sizeof("age=6.3")];
-#endif /* USE_UNICODE_AGE_PROPERTIES */
- char uniname2ctype_pool_str1298[sizeof("punct")];
- char uniname2ctype_pool_str1309[sizeof("incjkunifiedideographs")];
- char uniname2ctype_pool_str1310[sizeof("inhiragana")];
- char uniname2ctype_pool_str1314[sizeof("sinhala")];
- char uniname2ctype_pool_str1318[sizeof("plrd")];
- char uniname2ctype_pool_str1320[sizeof("phoenician")];
- char uniname2ctype_pool_str1321[sizeof("logicalorderexception")];
- char uniname2ctype_pool_str1323[sizeof("multani")];
- char uniname2ctype_pool_str1326[sizeof("canadianaboriginal")];
- char uniname2ctype_pool_str1327[sizeof("patternsyntax")];
- char uniname2ctype_pool_str1328[sizeof("gunjalagondi")];
- char uniname2ctype_pool_str1330[sizeof("hatr")];
- char uniname2ctype_pool_str1336[sizeof("insorasompeng")];
- char uniname2ctype_pool_str1339[sizeof("inearlydynasticcuneiform")];
- char uniname2ctype_pool_str1340[sizeof("marchen")];
- char uniname2ctype_pool_str1349[sizeof("graphemelink")];
- char uniname2ctype_pool_str1350[sizeof("sd")];
- char uniname2ctype_pool_str1353[sizeof("cher")];
- char uniname2ctype_pool_str1355[sizeof("cherokee")];
- char uniname2ctype_pool_str1357[sizeof("sidd")];
- char uniname2ctype_pool_str1359[sizeof("kaithi")];
- char uniname2ctype_pool_str1362[sizeof("inmahajani")];
- char uniname2ctype_pool_str1363[sizeof("emojimodifier")];
- char uniname2ctype_pool_str1364[sizeof("inogham")];
- char uniname2ctype_pool_str1369[sizeof("khojki")];
- char uniname2ctype_pool_str1372[sizeof("cham")];
- char uniname2ctype_pool_str1376[sizeof("chakma")];
- char uniname2ctype_pool_str1390[sizeof("khar")];
- char uniname2ctype_pool_str1392[sizeof("n")];
- char uniname2ctype_pool_str1397[sizeof("graphemebase")];
- char uniname2ctype_pool_str1408[sizeof("manichaean")];
- char uniname2ctype_pool_str1410[sizeof("no")];
- char uniname2ctype_pool_str1414[sizeof("inolchiki")];
- char uniname2ctype_pool_str1416[sizeof("nandinagari")];
- char uniname2ctype_pool_str1417[sizeof("nko")];
- char uniname2ctype_pool_str1418[sizeof("nkoo")];
- char uniname2ctype_pool_str1434[sizeof("sund")];
- char uniname2ctype_pool_str1435[sizeof("inethiopic")];
- char uniname2ctype_pool_str1437[sizeof("p")];
- char uniname2ctype_pool_str1439[sizeof("punctuation")];
- char uniname2ctype_pool_str1440[sizeof("ingreekandcoptic")];
- char uniname2ctype_pool_str1451[sizeof("inmeroitichieroglyphs")];
- char uniname2ctype_pool_str1455[sizeof("inphoenician")];
- char uniname2ctype_pool_str1456[sizeof("intangsa")];
- char uniname2ctype_pool_str1458[sizeof("adlm")];
- char uniname2ctype_pool_str1460[sizeof("insinhala")];
- char uniname2ctype_pool_str1461[sizeof("incyrillicextendeda")];
- char uniname2ctype_pool_str1466[sizeof("gujr")];
- char uniname2ctype_pool_str1476[sizeof("gujarati")];
- char uniname2ctype_pool_str1478[sizeof("inlatinextendedc")];
- char uniname2ctype_pool_str1480[sizeof("olower")];
- char uniname2ctype_pool_str1482[sizeof("enclosingmark")];
- char uniname2ctype_pool_str1484[sizeof("xpeo")];
- char uniname2ctype_pool_str1485[sizeof("khmr")];
- char uniname2ctype_pool_str1488[sizeof("olck")];
- char uniname2ctype_pool_str1490[sizeof("linb")];
- char uniname2ctype_pool_str1491[sizeof("ahom")];
- char uniname2ctype_pool_str1492[sizeof("chorasmian")];
- char uniname2ctype_pool_str1495[sizeof("zanb")];
- char uniname2ctype_pool_str1498[sizeof("inkangxiradicals")];
- char uniname2ctype_pool_str1501[sizeof("olchiki")];
- char uniname2ctype_pool_str1502[sizeof("innabataean")];
- char uniname2ctype_pool_str1504[sizeof("inkanbun")];
- char uniname2ctype_pool_str1505[sizeof("casedletter")];
- char uniname2ctype_pool_str1506[sizeof("inbhaiksuki")];
- char uniname2ctype_pool_str1513[sizeof("sunu")];
- char uniname2ctype_pool_str1516[sizeof("intaixuanjingsymbols")];
- char uniname2ctype_pool_str1520[sizeof("chrs")];
- char uniname2ctype_pool_str1521[sizeof("cpmn")];
- char uniname2ctype_pool_str1525[sizeof("beng")];
- char uniname2ctype_pool_str1526[sizeof("inscriptionalpahlavi")];
- char uniname2ctype_pool_str1527[sizeof("inelbasan")];
- char uniname2ctype_pool_str1534[sizeof("khmer")];
- char uniname2ctype_pool_str1542[sizeof("linearb")];
- char uniname2ctype_pool_str1545[sizeof("incjkunifiedideographsextensiond")];
- char uniname2ctype_pool_str1546[sizeof("emojimodifierbase")];
- char uniname2ctype_pool_str1553[sizeof("indogra")];
- char uniname2ctype_pool_str1555[sizeof("adlam")];
- char uniname2ctype_pool_str1558[sizeof("regionalindicator")];
- char uniname2ctype_pool_str1560[sizeof("kharoshthi")];
- char uniname2ctype_pool_str1562[sizeof("inphaistosdisc")];
- char uniname2ctype_pool_str1565[sizeof("lepc")];
- char uniname2ctype_pool_str1571[sizeof("xsux")];
- char uniname2ctype_pool_str1575[sizeof("ingreekextended")];
- char uniname2ctype_pool_str1583[sizeof("limb")];
- char uniname2ctype_pool_str1591[sizeof("sogo")];
- char uniname2ctype_pool_str1593[sizeof("sogdian")];
- char uniname2ctype_pool_str1595[sizeof("ll")];
- char uniname2ctype_pool_str1598[sizeof("emod")];
- char uniname2ctype_pool_str1600[sizeof("incyrillicextendedc")];
- char uniname2ctype_pool_str1602[sizeof("incyprominoan")];
- char uniname2ctype_pool_str1604[sizeof("zl")];
- char uniname2ctype_pool_str1621[sizeof("ingeometricshapes")];
- char uniname2ctype_pool_str1622[sizeof("inkhitansmallscript")];
- char uniname2ctype_pool_str1626[sizeof("math")];
- char uniname2ctype_pool_str1630[sizeof("goth")];
- char uniname2ctype_pool_str1634[sizeof("inarabic")];
- char uniname2ctype_pool_str1635[sizeof("gurungkhema")];
- char uniname2ctype_pool_str1642[sizeof("inimperialaramaic")];
- char uniname2ctype_pool_str1661[sizeof("inmiscellaneoustechnical")];
- char uniname2ctype_pool_str1665[sizeof("intamilsupplement")];
- char uniname2ctype_pool_str1668[sizeof("arab")];
- char uniname2ctype_pool_str1673[sizeof("grantha")];
- char uniname2ctype_pool_str1678[sizeof("intirhuta")];
- char uniname2ctype_pool_str1679[sizeof("inhatran")];
- char uniname2ctype_pool_str1681[sizeof("mult")];
- char uniname2ctype_pool_str1696[sizeof("intulutigalari")];
- char uniname2ctype_pool_str1704[sizeof("inbasiclatin")];
- char uniname2ctype_pool_str1705[sizeof("inoldhungarian")];
- char uniname2ctype_pool_str1706[sizeof("insogdian")];
- char uniname2ctype_pool_str1707[sizeof("indingbats")];
- char uniname2ctype_pool_str1709[sizeof("ogam")];
- char uniname2ctype_pool_str1711[sizeof("inarabicpresentationformsa")];
- char uniname2ctype_pool_str1712[sizeof("vithkuqi")];
- char uniname2ctype_pool_str1716[sizeof("kthi")];
- char uniname2ctype_pool_str1717[sizeof("brah")];
- char uniname2ctype_pool_str1719[sizeof("coptic")];
- char uniname2ctype_pool_str1723[sizeof("ideographic")];
- char uniname2ctype_pool_str1730[sizeof("emojicomponent")];
- char uniname2ctype_pool_str1731[sizeof("takri")];
- char uniname2ctype_pool_str1733[sizeof("invai")];
- char uniname2ctype_pool_str1734[sizeof("ingurungkhema")];
- char uniname2ctype_pool_str1735[sizeof("inherited")];
- char uniname2ctype_pool_str1737[sizeof("radical")];
- char uniname2ctype_pool_str1746[sizeof("dia")];
- char uniname2ctype_pool_str1748[sizeof("di")];
- char uniname2ctype_pool_str1752[sizeof("diak")];
- char uniname2ctype_pool_str1755[sizeof("sinh")];
- char uniname2ctype_pool_str1756[sizeof("glagolitic")];
- char uniname2ctype_pool_str1758[sizeof("gukh")];
- char uniname2ctype_pool_str1760[sizeof("shavian")];
- char uniname2ctype_pool_str1766[sizeof("joincontrol")];
- char uniname2ctype_pool_str1768[sizeof("takr")];
- char uniname2ctype_pool_str1774[sizeof("inhanunoo")];
- char uniname2ctype_pool_str1775[sizeof("ininscriptionalparthian")];
- char uniname2ctype_pool_str1776[sizeof("ininscriptionalpahlavi")];
- char uniname2ctype_pool_str1780[sizeof("taile")];
- char uniname2ctype_pool_str1791[sizeof("grbase")];
- char uniname2ctype_pool_str1792[sizeof("graphemeextend")];
- char uniname2ctype_pool_str1794[sizeof("imperialaramaic")];
- char uniname2ctype_pool_str1802[sizeof("copt")];
- char uniname2ctype_pool_str1807[sizeof("bidicontrol")];
- char uniname2ctype_pool_str1819[sizeof("nand")];
- char uniname2ctype_pool_str1825[sizeof("intangut")];
- char uniname2ctype_pool_str1835[sizeof("bopo")];
- char uniname2ctype_pool_str1839[sizeof("osge")];
- char uniname2ctype_pool_str1840[sizeof("cprt")];
- char uniname2ctype_pool_str1842[sizeof("orkh")];
- char uniname2ctype_pool_str1843[sizeof("sorasompeng")];
- char uniname2ctype_pool_str1844[sizeof("intags")];
- char uniname2ctype_pool_str1846[sizeof("inenclosedideographicsupplement")];
- char uniname2ctype_pool_str1848[sizeof("inoldpersian")];
- char uniname2ctype_pool_str1851[sizeof("inanatolianhieroglyphs")];
- char uniname2ctype_pool_str1852[sizeof("oldpersian")];
- char uniname2ctype_pool_str1855[sizeof("ingeometricshapesextended")];
- char uniname2ctype_pool_str1868[sizeof("inbatak")];
- char uniname2ctype_pool_str1870[sizeof("glag")];
- char uniname2ctype_pool_str1871[sizeof("bhks")];
- char uniname2ctype_pool_str1876[sizeof("inblockelements")];
- char uniname2ctype_pool_str1882[sizeof("bhaiksuki")];
- char uniname2ctype_pool_str1883[sizeof("incyrillicextendedd")];
- char uniname2ctype_pool_str1887[sizeof("term")];
- char uniname2ctype_pool_str1889[sizeof("innumberforms")];
- char uniname2ctype_pool_str1896[sizeof("intibetan")];
- char uniname2ctype_pool_str1914[sizeof("tnsa")];
- char uniname2ctype_pool_str1916[sizeof("spacingmark")];
- char uniname2ctype_pool_str1918[sizeof("tangsa")];
- char uniname2ctype_pool_str1928[sizeof("inshavian")];
- char uniname2ctype_pool_str1932[sizeof("inkanaextendedb")];
- char uniname2ctype_pool_str1944[sizeof("diacritic")];
- char uniname2ctype_pool_str1945[sizeof("bopomofo")];
- char uniname2ctype_pool_str1950[sizeof("insinhalaarchaicnumbers")];
- char uniname2ctype_pool_str1956[sizeof("space")];
- char uniname2ctype_pool_str1957[sizeof("inarabicextendeda")];
- char uniname2ctype_pool_str1959[sizeof("innushu")];
- char uniname2ctype_pool_str1966[sizeof("incjksymbolsandpunctuation")];
- char uniname2ctype_pool_str1980[sizeof("hang")];
- char uniname2ctype_pool_str1981[sizeof("inoldpermic")];
- char uniname2ctype_pool_str1988[sizeof("oldpermic")];
- char uniname2ctype_pool_str1991[sizeof("anatolianhieroglyphs")];
- char uniname2ctype_pool_str1992[sizeof("inenclosedalphanumerics")];
- char uniname2ctype_pool_str1995[sizeof("inbyzantinemusicalsymbols")];
- char uniname2ctype_pool_str1997[sizeof("ingujarati")];
- char uniname2ctype_pool_str1998[sizeof("cntrl")];
- char uniname2ctype_pool_str1999[sizeof("bugi")];
- char uniname2ctype_pool_str2002[sizeof("inmyanmarextendedb")];
- char uniname2ctype_pool_str2003[sizeof("inlatinextendedadditional")];
- char uniname2ctype_pool_str2004[sizeof("sogd")];
- char uniname2ctype_pool_str2006[sizeof("ingunjalagondi")];
- char uniname2ctype_pool_str2011[sizeof("inlisu")];
- char uniname2ctype_pool_str2015[sizeof("insundanesesupplement")];
- char uniname2ctype_pool_str2026[sizeof("separator")];
- char uniname2ctype_pool_str2030[sizeof("sarb")];
- char uniname2ctype_pool_str2033[sizeof("assigned")];
- char uniname2ctype_pool_str2035[sizeof("hiragana")];
- char uniname2ctype_pool_str2038[sizeof("inrejang")];
- char uniname2ctype_pool_str2039[sizeof("zanabazarsquare")];
- char uniname2ctype_pool_str2044[sizeof("inlatinextendedd")];
- char uniname2ctype_pool_str2046[sizeof("format")];
- char uniname2ctype_pool_str2049[sizeof("inkayahli")];
- char uniname2ctype_pool_str2051[sizeof("inoriya")];
- char uniname2ctype_pool_str2054[sizeof("ingeorgiansupplement")];
- char uniname2ctype_pool_str2055[sizeof("incoptic")];
- char uniname2ctype_pool_str2056[sizeof("intodhri")];
- char uniname2ctype_pool_str2060[sizeof("innewa")];
- char uniname2ctype_pool_str2061[sizeof("buginese")];
- char uniname2ctype_pool_str2065[sizeof("insyriacsupplement")];
- char uniname2ctype_pool_str2071[sizeof("inkawi")];
- char uniname2ctype_pool_str2073[sizeof("wara")];
- char uniname2ctype_pool_str2075[sizeof("hmng")];
- char uniname2ctype_pool_str2077[sizeof("inbraillepatterns")];
- char uniname2ctype_pool_str2078[sizeof("inmiscellaneousmathematicalsymbolsb")];
- char uniname2ctype_pool_str2093[sizeof("phli")];
- char uniname2ctype_pool_str2094[sizeof("decimalnumber")];
- char uniname2ctype_pool_str2096[sizeof("inarabicextendedc")];
- char uniname2ctype_pool_str2098[sizeof("inyezidi")];
- char uniname2ctype_pool_str2099[sizeof("braille")];
- char uniname2ctype_pool_str2100[sizeof("inornamentaldingbats")];
- char uniname2ctype_pool_str2103[sizeof("toto")];
- char uniname2ctype_pool_str2105[sizeof("idsb")];
- char uniname2ctype_pool_str2106[sizeof("variationselector")];
- char uniname2ctype_pool_str2109[sizeof("innyiakengpuachuehmong")];
- char uniname2ctype_pool_str2111[sizeof("asciihexdigit")];
- char uniname2ctype_pool_str2112[sizeof("phnx")];
- char uniname2ctype_pool_str2118[sizeof("number")];
- char uniname2ctype_pool_str2120[sizeof("inwarangciti")];
- char uniname2ctype_pool_str2127[sizeof("taiviet")];
- char uniname2ctype_pool_str2136[sizeof("caseignorable")];
- char uniname2ctype_pool_str2146[sizeof("kawi")];
- char uniname2ctype_pool_str2154[sizeof("lower")];
- char uniname2ctype_pool_str2162[sizeof("ougr")];
- char uniname2ctype_pool_str2163[sizeof("mahj")];
- char uniname2ctype_pool_str2164[sizeof("indevanagari")];
- char uniname2ctype_pool_str2166[sizeof("surrogate")];
- char uniname2ctype_pool_str2171[sizeof("lyci")];
- char uniname2ctype_pool_str2173[sizeof("mahajani")];
- char uniname2ctype_pool_str2174[sizeof("inenclosedalphanumericsupplement")];
- char uniname2ctype_pool_str2175[sizeof("lycian")];
- char uniname2ctype_pool_str2176[sizeof("sharada")];
- char uniname2ctype_pool_str2177[sizeof("mymr")];
- char uniname2ctype_pool_str2182[sizeof("myanmar")];
- char uniname2ctype_pool_str2185[sizeof("inbamum")];
- char uniname2ctype_pool_str2186[sizeof("intelugu")];
- char uniname2ctype_pool_str2187[sizeof("incjkunifiedideographsextensiong")];
- char uniname2ctype_pool_str2194[sizeof("todr")];
- char uniname2ctype_pool_str2199[sizeof("indevanagariextendeda")];
- char uniname2ctype_pool_str2203[sizeof("medf")];
- char uniname2ctype_pool_str2206[sizeof("todhri")];
- char uniname2ctype_pool_str2207[sizeof("inethiopicsupplement")];
- char uniname2ctype_pool_str2210[sizeof("inwancho")];
- char uniname2ctype_pool_str2214[sizeof("medefaidrin")];
- char uniname2ctype_pool_str2218[sizeof("shrd")];
- char uniname2ctype_pool_str2222[sizeof("inkatakanaphoneticextensions")];
- char uniname2ctype_pool_str2223[sizeof("inshorthandformatcontrols")];
- char uniname2ctype_pool_str2227[sizeof("caucasianalbanian")];
- char uniname2ctype_pool_str2231[sizeof("ahex")];
- char uniname2ctype_pool_str2233[sizeof("insymbolsforlegacycomputingsupplement")];
- char uniname2ctype_pool_str2236[sizeof("nd")];
- char uniname2ctype_pool_str2254[sizeof("insoyombo")];
- char uniname2ctype_pool_str2255[sizeof("other")];
- char uniname2ctype_pool_str2257[sizeof("otheridcontinue")];
- char uniname2ctype_pool_str2258[sizeof("khoj")];
- char uniname2ctype_pool_str2260[sizeof("avestan")];
- char uniname2ctype_pool_str2264[sizeof("othernumber")];
- char uniname2ctype_pool_str2270[sizeof("sentenceterminal")];
- char uniname2ctype_pool_str2275[sizeof("siddham")];
- char uniname2ctype_pool_str2276[sizeof("closepunctuation")];
- char uniname2ctype_pool_str2280[sizeof("lowercase")];
- char uniname2ctype_pool_str2281[sizeof("olditalic")];
- char uniname2ctype_pool_str2284[sizeof("oldhungarian")];
- char uniname2ctype_pool_str2289[sizeof("inlisusupplement")];
- char uniname2ctype_pool_str2297[sizeof("innoblock")];
- char uniname2ctype_pool_str2302[sizeof("inunifiedcanadianaboriginalsyllabicsextendeda")];
- char uniname2ctype_pool_str2303[sizeof("inelymaic")];
- char uniname2ctype_pool_str2310[sizeof("cwcm")];
- char uniname2ctype_pool_str2324[sizeof("inbalinese")];
- char uniname2ctype_pool_str2325[sizeof("invariationselectors")];
- char uniname2ctype_pool_str2327[sizeof("terminalpunctuation")];
- char uniname2ctype_pool_str2329[sizeof("inpalmyrene")];
- char uniname2ctype_pool_str2330[sizeof("alpha")];
- char uniname2ctype_pool_str2341[sizeof("inlepcha")];
- char uniname2ctype_pool_str2342[sizeof("incjkcompatibility")];
- char uniname2ctype_pool_str2349[sizeof("rjng")];
- char uniname2ctype_pool_str2350[sizeof("inhanguljamo")];
- char uniname2ctype_pool_str2355[sizeof("dsrt")];
- char uniname2ctype_pool_str2358[sizeof("inverticalforms")];
- char uniname2ctype_pool_str2359[sizeof("phag")];
- char uniname2ctype_pool_str2360[sizeof("incopticepactnumbers")];
- char uniname2ctype_pool_str2363[sizeof("incjkunifiedideographsextensionh")];
- char uniname2ctype_pool_str2366[sizeof("invedicextensions")];
- char uniname2ctype_pool_str2380[sizeof("inhanguljamoextendeda")];
- char uniname2ctype_pool_str2381[sizeof("cuneiform")];
- char uniname2ctype_pool_str2385[sizeof("inmayannumerals")];
- char uniname2ctype_pool_str2388[sizeof("otheralphabetic")];
- char uniname2ctype_pool_str2398[sizeof("hmnp")];
- char uniname2ctype_pool_str2403[sizeof("insuttonsignwriting")];
- char uniname2ctype_pool_str2415[sizeof("incombiningdiacriticalmarks")];
- char uniname2ctype_pool_str2418[sizeof("deseret")];
- char uniname2ctype_pool_str2420[sizeof("avst")];
- char uniname2ctype_pool_str2421[sizeof("inmeroiticcursive")];
- char uniname2ctype_pool_str2425[sizeof("incombiningdiacriticalmarksforsymbols")];
- char uniname2ctype_pool_str2432[sizeof("inglagolitic")];
- char uniname2ctype_pool_str2436[sizeof("vith")];
- char uniname2ctype_pool_str2450[sizeof("patsyn")];
- char uniname2ctype_pool_str2454[sizeof("lydi")];
- char uniname2ctype_pool_str2458[sizeof("lydian")];
- char uniname2ctype_pool_str2460[sizeof("oldturkic")];
- char uniname2ctype_pool_str2463[sizeof("innewtailue")];
- char uniname2ctype_pool_str2464[sizeof("hebr")];
- char uniname2ctype_pool_str2472[sizeof("intaiviet")];
- char uniname2ctype_pool_str2473[sizeof("inphagspa")];
- char uniname2ctype_pool_str2477[sizeof("inenclosedcjklettersandmonths")];
- char uniname2ctype_pool_str2481[sizeof("hung")];
- char uniname2ctype_pool_str2483[sizeof("inyiradicals")];
- char uniname2ctype_pool_str2489[sizeof("inunifiedcanadianaboriginalsyllabics")];
- char uniname2ctype_pool_str2493[sizeof("uideo")];
- char uniname2ctype_pool_str2503[sizeof("idstrinaryoperator")];
- char uniname2ctype_pool_str2504[sizeof("word")];
- char uniname2ctype_pool_str2508[sizeof("invariationselectorssupplement")];
- char uniname2ctype_pool_str2510[sizeof("java")];
- char uniname2ctype_pool_str2519[sizeof("intagalog")];
- char uniname2ctype_pool_str2539[sizeof("tale")];
- char uniname2ctype_pool_str2541[sizeof("graph")];
- char uniname2ctype_pool_str2544[sizeof("inethiopicextendeda")];
- char uniname2ctype_pool_str2545[sizeof("soyo")];
- char uniname2ctype_pool_str2550[sizeof("spaceseparator")];
- char uniname2ctype_pool_str2552[sizeof("inpaucinhau")];
- char uniname2ctype_pool_str2554[sizeof("nagm")];
- char uniname2ctype_pool_str2556[sizeof("inmongoliansupplement")];
- char uniname2ctype_pool_str2565[sizeof("oupper")];
- char uniname2ctype_pool_str2566[sizeof("inbengali")];
- char uniname2ctype_pool_str2572[sizeof("hex")];
- char uniname2ctype_pool_str2576[sizeof("javanese")];
- char uniname2ctype_pool_str2588[sizeof("oalpha")];
- char uniname2ctype_pool_str2593[sizeof("buhd")];
- char uniname2ctype_pool_str2594[sizeof("inbuginese")];
- char uniname2ctype_pool_str2597[sizeof("incjkunifiedideographsextensionb")];
- char uniname2ctype_pool_str2598[sizeof("incombiningdiacriticalmarkssupplement")];
- char uniname2ctype_pool_str2603[sizeof("insymbolsandpictographsextendeda")];
- char uniname2ctype_pool_str2605[sizeof("taml")];
- char uniname2ctype_pool_str2606[sizeof("ebase")];
- char uniname2ctype_pool_str2615[sizeof("orya")];
- char uniname2ctype_pool_str2616[sizeof("modifierletter")];
- char uniname2ctype_pool_str2620[sizeof("indevanagariextended")];
- char uniname2ctype_pool_str2624[sizeof("ext")];
- char uniname2ctype_pool_str2628[sizeof("induployan")];
- char uniname2ctype_pool_str2640[sizeof("inphoneticextensions")];
- char uniname2ctype_pool_str2642[sizeof("tirhuta")];
- char uniname2ctype_pool_str2649[sizeof("incombiningdiacriticalmarksextended")];
- char uniname2ctype_pool_str2652[sizeof("xposixpunct")];
- char uniname2ctype_pool_str2666[sizeof("injavanese")];
- char uniname2ctype_pool_str2670[sizeof("lepcha")];
- char uniname2ctype_pool_str2674[sizeof("lowercaseletter")];
- char uniname2ctype_pool_str2676[sizeof("inindicsiyaqnumbers")];
- char uniname2ctype_pool_str2679[sizeof("unassigned")];
- char uniname2ctype_pool_str2685[sizeof("ethi")];
- char uniname2ctype_pool_str2687[sizeof("titlecaseletter")];
- char uniname2ctype_pool_str2690[sizeof("rohg")];
- char uniname2ctype_pool_str2713[sizeof("syrc")];
- char uniname2ctype_pool_str2723[sizeof("inunifiedcanadianaboriginalsyllabicsextended")];
- char uniname2ctype_pool_str2733[sizeof("extender")];
- char uniname2ctype_pool_str2739[sizeof("inbrahmi")];
- char uniname2ctype_pool_str2746[sizeof("meroitichieroglyphs")];
- char uniname2ctype_pool_str2749[sizeof("otheruppercase")];
- char uniname2ctype_pool_str2773[sizeof("extpict")];
- char uniname2ctype_pool_str2779[sizeof("incjkradicalssupplement")];
- char uniname2ctype_pool_str2782[sizeof("tang")];
- char uniname2ctype_pool_str2788[sizeof("tagbanwa")];
- char uniname2ctype_pool_str2790[sizeof("zp")];
- char uniname2ctype_pool_str2792[sizeof("inaegeannumbers")];
- char uniname2ctype_pool_str2811[sizeof("nonspacingmark")];
- char uniname2ctype_pool_str2812[sizeof("ingeorgianextended")];
- char uniname2ctype_pool_str2813[sizeof("cwt")];
- char uniname2ctype_pool_str2818[sizeof("dogra")];
- char uniname2ctype_pool_str2823[sizeof("inphoneticextensionssupplement")];
- char uniname2ctype_pool_str2833[sizeof("ingothic")];
- char uniname2ctype_pool_str2849[sizeof("oldsogdian")];
- char uniname2ctype_pool_str2856[sizeof("syriac")];
- char uniname2ctype_pool_str2858[sizeof("incjkunifiedideographsextensionf")];
- char uniname2ctype_pool_str2863[sizeof("dogr")];
- char uniname2ctype_pool_str2866[sizeof("osmanya")];
- char uniname2ctype_pool_str2870[sizeof("nchar")];
- char uniname2ctype_pool_str2881[sizeof("inmathematicalalphanumericsymbols")];
- char uniname2ctype_pool_str2883[sizeof("phagspa")];
- char uniname2ctype_pool_str2884[sizeof("inlimbu")];
- char uniname2ctype_pool_str2896[sizeof("cyrl")];
- char uniname2ctype_pool_str2897[sizeof("currencysymbol")];
- char uniname2ctype_pool_str2900[sizeof("epres")];
- char uniname2ctype_pool_str2902[sizeof("inbopomofo")];
- char uniname2ctype_pool_str2916[sizeof("narb")];
- char uniname2ctype_pool_str2918[sizeof("insymbolsforlegacycomputing")];
- char uniname2ctype_pool_str2924[sizeof("mlym")];
- char uniname2ctype_pool_str2928[sizeof("insmallformvariants")];
- char uniname2ctype_pool_str2930[sizeof("intagbanwa")];
- char uniname2ctype_pool_str2931[sizeof("malayalam")];
- char uniname2ctype_pool_str2935[sizeof("incyrillicextendedb")];
- char uniname2ctype_pool_str2945[sizeof("olonal")];
- char uniname2ctype_pool_str2950[sizeof("palmyrene")];
- char uniname2ctype_pool_str2956[sizeof("thaa")];
- char uniname2ctype_pool_str2959[sizeof("otheridstart")];
- char uniname2ctype_pool_str2960[sizeof("thai")];
- char uniname2ctype_pool_str2961[sizeof("tangut")];
- char uniname2ctype_pool_str2962[sizeof("thaana")];
- char uniname2ctype_pool_str2964[sizeof("emojipresentation")];
- char uniname2ctype_pool_str2965[sizeof("inethiopicextended")];
- char uniname2ctype_pool_str2974[sizeof("nagmundari")];
- char uniname2ctype_pool_str2980[sizeof("nl")];
- char uniname2ctype_pool_str2985[sizeof("inlatin1supplement")];
- char uniname2ctype_pool_str3007[sizeof("tirh")];
- char uniname2ctype_pool_str3009[sizeof("hangul")];
- char uniname2ctype_pool_str3011[sizeof("talu")];
- char uniname2ctype_pool_str3017[sizeof("buhid")];
- char uniname2ctype_pool_str3034[sizeof("paragraphseparator")];
- char uniname2ctype_pool_str3035[sizeof("graphemeclusterbreak=spacingmark")];
- char uniname2ctype_pool_str3040[sizeof("telu")];
- char uniname2ctype_pool_str3042[sizeof("otherlowercase")];
- char uniname2ctype_pool_str3046[sizeof("ogham")];
- char uniname2ctype_pool_str3047[sizeof("changeswhencasemapped")];
- char uniname2ctype_pool_str3053[sizeof("intangutcomponents")];
- char uniname2ctype_pool_str3056[sizeof("otherletter")];
- char uniname2ctype_pool_str3060[sizeof("taitham")];
- char uniname2ctype_pool_str3068[sizeof("graphemeclusterbreak=cr")];
- char uniname2ctype_pool_str3077[sizeof("cwu")];
- char uniname2ctype_pool_str3083[sizeof("graphemeclusterbreak=regionalindicator")];
- char uniname2ctype_pool_str3096[sizeof("nushu")];
- char uniname2ctype_pool_str3103[sizeof("sunuwar")];
- char uniname2ctype_pool_str3112[sizeof("noncharactercodepoint")];
- char uniname2ctype_pool_str3114[sizeof("softdotted")];
- char uniname2ctype_pool_str3127[sizeof("omath")];
- char uniname2ctype_pool_str3129[sizeof("inbassavah")];
- char uniname2ctype_pool_str3138[sizeof("inottomansiyaqnumbers")];
- char uniname2ctype_pool_str3149[sizeof("ingaray")];
- char uniname2ctype_pool_str3151[sizeof("warangciti")];
- char uniname2ctype_pool_str3158[sizeof("ugar")];
- char uniname2ctype_pool_str3159[sizeof("inprivateusearea")];
- char uniname2ctype_pool_str3160[sizeof("inbuhid")];
- char uniname2ctype_pool_str3179[sizeof("dash")];
- char uniname2ctype_pool_str3185[sizeof("inarabicpresentationformsb")];
- char uniname2ctype_pool_str3187[sizeof("indivesakuru")];
- char uniname2ctype_pool_str3201[sizeof("hexdigit")];
- char uniname2ctype_pool_str3202[sizeof("inalphabeticpresentationforms")];
- char uniname2ctype_pool_str3205[sizeof("othersymbol")];
- char uniname2ctype_pool_str3208[sizeof("extendedpictographic")];
- char uniname2ctype_pool_str3211[sizeof("changeswhentitlecased")];
- char uniname2ctype_pool_str3218[sizeof("ogrext")];
- char uniname2ctype_pool_str3238[sizeof("nbat")];
- char uniname2ctype_pool_str3239[sizeof("insuperscriptsandsubscripts")];
- char uniname2ctype_pool_str3247[sizeof("nabataean")];
- char uniname2ctype_pool_str3253[sizeof("intangutsupplement")];
- char uniname2ctype_pool_str3254[sizeof("inlowsurrogates")];
- char uniname2ctype_pool_str3257[sizeof("inyijinghexagramsymbols")];
- char uniname2ctype_pool_str3259[sizeof("inmahjongtiles")];
- char uniname2ctype_pool_str3265[sizeof("inletterlikesymbols")];
- char uniname2ctype_pool_str3267[sizeof("inbamumsupplement")];
- char uniname2ctype_pool_str3273[sizeof("incurrencysymbols")];
- char uniname2ctype_pool_str3274[sizeof("incombininghalfmarks")];
- char uniname2ctype_pool_str3290[sizeof("wancho")];
- char uniname2ctype_pool_str3292[sizeof("inarabicsupplement")];
- char uniname2ctype_pool_str3312[sizeof("oldnortharabian")];
- char uniname2ctype_pool_str3318[sizeof("khitansmallscript")];
- char uniname2ctype_pool_str3328[sizeof("inlatinextendedg")];
- char uniname2ctype_pool_str3330[sizeof("sylo")];
- char uniname2ctype_pool_str3331[sizeof("inarabicmathematicalalphabeticsymbols")];
- char uniname2ctype_pool_str3332[sizeof("nshu")];
- char uniname2ctype_pool_str3340[sizeof("elba")];
- char uniname2ctype_pool_str3344[sizeof("invithkuqi")];
- char uniname2ctype_pool_str3357[sizeof("inhangulsyllables")];
- char uniname2ctype_pool_str3361[sizeof("changeswhenuppercased")];
- char uniname2ctype_pool_str3371[sizeof("intifinagh")];
- char uniname2ctype_pool_str3389[sizeof("graphemeclusterbreak=t")];
- char uniname2ctype_pool_str3391[sizeof("graphemeclusterbreak=lvt")];
- char uniname2ctype_pool_str3401[sizeof("tamil")];
- char uniname2ctype_pool_str3402[sizeof("mathsymbol")];
- char uniname2ctype_pool_str3403[sizeof("tulutigalari")];
- char uniname2ctype_pool_str3405[sizeof("otherdefaultignorablecodepoint")];
- char uniname2ctype_pool_str3414[sizeof("wcho")];
- char uniname2ctype_pool_str3422[sizeof("insupplementalarrowsa")];
- char uniname2ctype_pool_str3431[sizeof("inarabicextendedb")];
- char uniname2ctype_pool_str3446[sizeof("rejang")];
- char uniname2ctype_pool_str3447[sizeof("graphemeclusterbreak=extend")];
- char uniname2ctype_pool_str3448[sizeof("graphemeclusterbreak=prepend")];
- char uniname2ctype_pool_str3455[sizeof("finalpunctuation")];
- char uniname2ctype_pool_str3460[sizeof("inpsalterpahlavi")];
- char uniname2ctype_pool_str3463[sizeof("newa")];
- char uniname2ctype_pool_str3464[sizeof("inmathematicaloperators")];
- char uniname2ctype_pool_str3476[sizeof("phlp")];
- char uniname2ctype_pool_str3480[sizeof("deva")];
- char uniname2ctype_pool_str3494[sizeof("devanagari")];
- char uniname2ctype_pool_str3503[sizeof("newtailue")];
- char uniname2ctype_pool_str3504[sizeof("cf")];
- char uniname2ctype_pool_str3522[sizeof("pf")];
- char uniname2ctype_pool_str3532[sizeof("whitespace")];
- char uniname2ctype_pool_str3543[sizeof("elbasan")];
- char uniname2ctype_pool_str3548[sizeof("othermath")];
- char uniname2ctype_pool_str3551[sizeof("digit")];
- char uniname2ctype_pool_str3557[sizeof("cyprominoan")];
- char uniname2ctype_pool_str3561[sizeof("insupplementalarrowsc")];
- char uniname2ctype_pool_str3563[sizeof("tibt")];
- char uniname2ctype_pool_str3570[sizeof("tibetan")];
- char uniname2ctype_pool_str3580[sizeof("bassavah")];
- char uniname2ctype_pool_str3585[sizeof("insupplementalmathematicaloperators")];
- char uniname2ctype_pool_str3613[sizeof("otherpunctuation")];
- char uniname2ctype_pool_str3614[sizeof("sgnw")];
- char uniname2ctype_pool_str3629[sizeof("ugaritic")];
- char uniname2ctype_pool_str3650[sizeof("tutg")];
- char uniname2ctype_pool_str3654[sizeof("changeswhenlowercased")];
- char uniname2ctype_pool_str3663[sizeof("cwl")];
- char uniname2ctype_pool_str3670[sizeof("inlinearbsyllabary")];
- char uniname2ctype_pool_str3676[sizeof("inplayingcards")];
- char uniname2ctype_pool_str3689[sizeof("modifiercombiningmark")];
- char uniname2ctype_pool_str3707[sizeof("sylotinagri")];
- char uniname2ctype_pool_str3714[sizeof("idcompatmathcontinue")];
- char uniname2ctype_pool_str3720[sizeof("inpahawhhmong")];
- char uniname2ctype_pool_str3729[sizeof("idcompatmathstart")];
- char uniname2ctype_pool_str3732[sizeof("hanifirohingya")];
- char uniname2ctype_pool_str3757[sizeof("deprecated")];
- char uniname2ctype_pool_str3766[sizeof("oldsoutharabian")];
- char uniname2ctype_pool_str3788[sizeof("shaw")];
- char uniname2ctype_pool_str3793[sizeof("tavt")];
- char uniname2ctype_pool_str3810[sizeof("wspace")];
- char uniname2ctype_pool_str3814[sizeof("graphemeclusterbreak=l")];
- char uniname2ctype_pool_str3820[sizeof("graphemeclusterbreak=control")];
- char uniname2ctype_pool_str3829[sizeof("cypriot")];
- char uniname2ctype_pool_str3835[sizeof("cyrillic")];
- char uniname2ctype_pool_str3854[sizeof("inhanguljamoextendedb")];
- char uniname2ctype_pool_str3877[sizeof("inalchemicalsymbols")];
- char uniname2ctype_pool_str3882[sizeof("insupplementalpunctuation")];
- char uniname2ctype_pool_str3894[sizeof("khudawadi")];
- char uniname2ctype_pool_str3925[sizeof("aghb")];
- char uniname2ctype_pool_str3928[sizeof("graphemeclusterbreak=zwj")];
- char uniname2ctype_pool_str3949[sizeof("alphabetic")];
- char uniname2ctype_pool_str3950[sizeof("cwcf")];
- char uniname2ctype_pool_str3979[sizeof("elym")];
- char uniname2ctype_pool_str3996[sizeof("ecomp")];
- char uniname2ctype_pool_str4018[sizeof("inethiopicextendedb")];
- char uniname2ctype_pool_str4032[sizeof("elymaic")];
- char uniname2ctype_pool_str4060[sizeof("inglagoliticsupplement")];
- char uniname2ctype_pool_str4097[sizeof("garay")];
- char uniname2ctype_pool_str4109[sizeof("unknown")];
- char uniname2ctype_pool_str4119[sizeof("soyombo")];
- char uniname2ctype_pool_str4148[sizeof("inlatinextendedb")];
- char uniname2ctype_pool_str4160[sizeof("divesakuru")];
- char uniname2ctype_pool_str4164[sizeof("kayahli")];
- char uniname2ctype_pool_str4175[sizeof("othergraphemeextend")];
- char uniname2ctype_pool_str4179[sizeof("inhighprivateusesurrogates")];
- char uniname2ctype_pool_str4184[sizeof("any")];
- char uniname2ctype_pool_str4212[sizeof("dashpunctuation")];
- char uniname2ctype_pool_str4222[sizeof("ethiopic")];
- char uniname2ctype_pool_str4223[sizeof("symbol")];
- char uniname2ctype_pool_str4239[sizeof("openpunctuation")];
- char uniname2ctype_pool_str4248[sizeof("hluw")];
- char uniname2ctype_pool_str4254[sizeof("tagb")];
- char uniname2ctype_pool_str4356[sizeof("hyphen")];
- char uniname2ctype_pool_str4418[sizeof("incypriotsyllabary")];
- char uniname2ctype_pool_str4425[sizeof("dupl")];
- char uniname2ctype_pool_str4468[sizeof("modifiersymbol")];
- char uniname2ctype_pool_str4484[sizeof("inyisyllables")];
- char uniname2ctype_pool_str4509[sizeof("inhalfwidthandfullwidthforms")];
- char uniname2ctype_pool_str4517[sizeof("tfng")];
- char uniname2ctype_pool_str4545[sizeof("dep")];
- char uniname2ctype_pool_str4547[sizeof("inegyptianhieroglyphsextendeda")];
- char uniname2ctype_pool_str4562[sizeof("inbopomofoextended")];
- char uniname2ctype_pool_str4609[sizeof("telugu")];
- char uniname2ctype_pool_str4638[sizeof("tglg")];
- char uniname2ctype_pool_str4652[sizeof("tagalog")];
- char uniname2ctype_pool_str4670[sizeof("inlatinextendedf")];
- char uniname2ctype_pool_str4687[sizeof("changeswhencasefolded")];
- char uniname2ctype_pool_str4703[sizeof("tifinagh")];
- char uniname2ctype_pool_str4728[sizeof("graphemeclusterbreak=v")];
- char uniname2ctype_pool_str4729[sizeof("graphemeclusterbreak=lv")];
- char uniname2ctype_pool_str4734[sizeof("inegyptianhieroglyphs")];
- char uniname2ctype_pool_str4736[sizeof("signwriting")];
- char uniname2ctype_pool_str4747[sizeof("inegyptianhieroglyphformatcontrols")];
- char uniname2ctype_pool_str4756[sizeof("graphemeclusterbreak=lf")];
- char uniname2ctype_pool_str4771[sizeof("insupplementaryprivateuseareaa")];
- char uniname2ctype_pool_str4821[sizeof("inhebrew")];
- char uniname2ctype_pool_str4865[sizeof("inboxdrawing")];
- char uniname2ctype_pool_str4896[sizeof("insupplementalarrowsb")];
- char uniname2ctype_pool_str4902[sizeof("olduyghur")];
- char uniname2ctype_pool_str4917[sizeof("upper")];
- char uniname2ctype_pool_str5031[sizeof("inhighsurrogates")];
- char uniname2ctype_pool_str5043[sizeof("uppercase")];
- char uniname2ctype_pool_str5216[sizeof("inhangulcompatibilityjamo")];
- char uniname2ctype_pool_str5272[sizeof("defaultignorablecodepoint")];
- char uniname2ctype_pool_str5437[sizeof("uppercaseletter")];
- char uniname2ctype_pool_str5541[sizeof("egyp")];
- char uniname2ctype_pool_str5603[sizeof("insupplementalsymbolsandpictographs")];
- char uniname2ctype_pool_str5646[sizeof("unifiedideograph")];
- char uniname2ctype_pool_str5647[sizeof("pahawhhmong")];
- char uniname2ctype_pool_str5666[sizeof("duployan")];
- char uniname2ctype_pool_str5914[sizeof("nyiakengpuachuehmong")];
- char uniname2ctype_pool_str6073[sizeof("zyyy")];
- char uniname2ctype_pool_str6245[sizeof("insupplementaryprivateuseareab")];
- char uniname2ctype_pool_str6528[sizeof("hebrew")];
- char uniname2ctype_pool_str6807[sizeof("egyptianhieroglyphs")];
-#endif /* USE_UNICODE_PROPERTIES */
- };
-static const struct uniname2ctype_pool_t uniname2ctype_pool_contents =
- {
-#ifndef USE_UNICODE_PROPERTIES
- "word",
-#else /* USE_UNICODE_PROPERTIES */
- "lana",
- "lina",
- "yi",
- "mn",
- "maka",
- "mani",
- "yiii",
- "lo",
- "lao",
- "laoo",
- "miao",
- "inkannada",
- "innko",
- "cn",
- "ci",
- "co",
- "gara",
- "pi",
- "gran",
- "z",
- "lineara",
- "mark",
- "po",
- "me",
- "loe",
- "inkiratrai",
- "mro",
- "mroo",
- "inkharoshthi",
- "cari",
- "carian",
- "grek",
- "yezi",
- "geor",
- "greek",
- "mendekikakui",
- "mero",
- "kana",
- "m",
- "pe",
- "gonm",
- "meeteimayek",
- "inosmanya",
- "inmro",
- "inmanichaean",
- "inmiao",
- "cakm",
- "inarmenian",
- "krai",
- "common",
- "inchakma",
- "inmyanmar",
- "mandaic",
- "inmakasar",
- "c",
- "zzzz",
- "inideographicsymbolsandpunctuation",
- "inkhmer",
- "lm",
- "marc",
- "qaai",
- "combiningmark",
- "inrunic",
- "incarian",
- "inahom",
- "prependedconcatenationmark",
- "inchorasmian",
- "perm",
- "merc",
- "cans",
- "connectorpunctuation",
- "inavestan",
- "incuneiformnumbersandpunctuation",
- "inipaextensions",
- "insharada",
- "incherokee",
- "makasar",
- "inarrows",
- "masaramgondi",
- "lc",
- "incuneiform",
- "armn",
- "mc",
- "armi",
- "armenian",
- "inmarchen",
- "lineseparator",
- "qmark",
- "cc",
- "insamaritan",
- "inmasaramgondi",
- "pc",
- "inscriptionalparthian",
- "qaac",
- "mcm",
- "incham",
- "incyrillic",
- "inzanabazarsquare",
- "inkhmersymbols",
- "latn",
- "ri",
- "pcm",
- "latin",
- "inthaana",
- "inthai",
- "inkatakana",
- "inkaithi",
- "insyriac",
- "zs",
- "initialpunctuation",
- "mtei",
- "cs",
- "mand",
- "ps",
- "intakri",
- "modi",
- "inkanaextendeda",
- "mend",
- "inruminumeralsymbols",
- "ideo",
- "prti",
- "arabic",
- "brai",
- "katakana",
- "inideographicdescriptioncharacters",
- "ascii",
- "innandinagari",
- "privateuse",
- "inoldnortharabian",
- "sk",
- "so",
- "incjkcompatibilityforms",
- "yezidi",
- "knda",
- "inmyanmarextendeda",
- "incjkcompatibilityideographs",
- "kannada",
- "xidcontinue",
- "letter",
- "inmodi",
- "inmeeteimayek",
- "inmendekikakui",
- "onao",
- "sora",
- "inmedefaidrin",
- "kiratrai",
- "inspecials",
- "brahmi",
- "letternumber",
- "inchesssymbols",
- "inolditalic",
- "oriya",
- "inmiscellaneousmathematicalsymbolsa",
- "intransportandmapsymbols",
- "incb=extend",
- "xidc",
- "inemoticons",
- "samr",
- "inoldsogdian",
- "inancientsymbols",
- "incommonindicnumberforms",
- "samaritan",
- "psalterpahlavi",
- "inmyanmarextendedc",
- "kits",
- "insundanese",
- "incb=consonant",
- "gothic",
- "inmandaic",
- "xids",
- "inznamennymusicalnotation",
- "pauc",
- "sm",
- "s",
- "meroiticcursive",
- "inoldsoutharabian",
- "inugaritic",
- "lisu",
- "idc",
- "incjkcompatibilityideographssupplement",
- "patternwhitespace",
- "bamum",
- "inancientgreekmusicalnotation",
- "idsbinaryoperator",
- "lt",
- "incjkstrokes",
- "insunuwar",
- "insaurashtra",
- "indominotiles",
- "intoto",
- "sc",
- "idsunaryoperator",
- "inmodifiertoneletters",
- "inopticalcharacterrecognition",
- "l",
- "batk",
- "inkanasupplement",
- "osage",
- "batak",
- "inmusicalsymbols",
- "incaucasianalbanian",
- "patws",
- "bass",
- "ids",
- "grext",
- "inlao",
- "vai",
- "vaii",
- "inolonal",
- "mongolian",
- "osma",
-#endif /* USE_UNICODE_PROPERTIES */
- "print",
-#ifndef USE_UNICODE_PROPERTIES
- "punct",
- "alpha",
-#else /* USE_UNICODE_PROPERTIES */
- "inlineara",
- "intaitham",
- "grlink",
- "inmiscellaneoussymbols",
- "pd",
- "inmiscellaneoussymbolsandarrows",
- "kali",
- "inmiscellaneoussymbolsandpictographs",
- "control",
- "inancientgreeknumbers",
- "incontrolpictures",
- "inadlam",
- "han",
- "hani",
- "hano",
- "runr",
- "sind",
- "hanunoo",
- "palm",
- "inkhojki",
- "inkhudawadi",
- "inlycian",
- "inoldturkic",
- "hira",
- "incountingrodnumerals",
- "odi",
- "idcontinue",
- "idst",
- "inolduyghur",
- "incb=linker",
- "inmalayalam",
- "lu",
- "inspacingmodifierletters",
- "bamu",
- "indeseret",
- "sundanese",
- "idstart",
- "saur",
- "insmallkanaextension",
- "guru",
- "paucinhau",
- "gurmukhi",
- "insylotinagri",
- "cased",
- "inlinearbideograms",
- "gong",
- "ingrantha",
- "mong",
- "joinc",
- "sterm",
- "inkaktoviknumerals",
- "limbu",
- "oidc",
- "inosage",
- "incjkunifiedideographsextensiona",
- "incyrillicsupplement",
- "inmeeteimayekextensions",
- "georgian",
- "incjkunifiedideographsextensioni",
- "idsu",
- "ingeneralpunctuation",
-#endif /* USE_UNICODE_PROPERTIES */
- "alnum",
-#ifdef USE_UNICODE_PROPERTIES
- "bidic",
- "ingeorgian",
- "quotationmark",
- "incherokeesupplement",
- "incjkunifiedideographsextensione",
- "insiddham",
- "runic",
- "oids",
- "ital",
- "emoji",
- "inmongolian",
- "innagmundari",
- "inlatinextendeda",
- "vs",
- "saurashtra",
- "intaile",
- "bali",
- "xidstart",
-#endif /* USE_UNICODE_PROPERTIES */
- "xdigit",
-#ifndef USE_UNICODE_PROPERTIES
- "upper",
- "ascii",
- "cntrl",
-#else /* USE_UNICODE_PROPERTIES */
- "ingurmukhi",
- "blank",
- "inlydian",
-#ifdef USE_UNICODE_AGE_PROPERTIES
- "age=11.0",
- "age=10.0",
- "age=12.1",
- "age=12.0",
- "age=1.1",
- "age=16.0",
- "age=9.0",
- "age=2.1",
- "age=2.0",
- "age=6.1",
- "age=6.0",
-#endif /* USE_UNICODE_AGE_PROPERTIES */
- "inlatinextendede",
-#ifdef USE_UNICODE_AGE_PROPERTIES
- "age=6.2",
- "age=8.0",
- "age=7.0",
-#endif /* USE_UNICODE_AGE_PROPERTIES */
- "incjkunifiedideographsextensionc",
- "bengali",
- "zinh",
-#ifdef USE_UNICODE_AGE_PROPERTIES
- "age=15.1",
- "age=15.0",
- "age=5.1",
- "age=5.0",
- "age=14.0",
- "age=5.2",
- "age=4.1",
- "age=4.0",
-#endif /* USE_UNICODE_AGE_PROPERTIES */
- "inhanifirohingya",
- "intamil",
- "inmultani",
-#ifdef USE_UNICODE_AGE_PROPERTIES
- "age=13.0",
-#endif /* USE_UNICODE_AGE_PROPERTIES */
- "balinese",
- "hatran",
-#ifdef USE_UNICODE_AGE_PROPERTIES
- "age=3.1",
- "age=3.0",
- "age=3.2",
- "age=6.3",
-#endif /* USE_UNICODE_AGE_PROPERTIES */
- "punct",
- "incjkunifiedideographs",
- "inhiragana",
- "sinhala",
- "plrd",
- "phoenician",
- "logicalorderexception",
- "multani",
- "canadianaboriginal",
- "patternsyntax",
- "gunjalagondi",
- "hatr",
- "insorasompeng",
- "inearlydynasticcuneiform",
- "marchen",
- "graphemelink",
- "sd",
- "cher",
- "cherokee",
- "sidd",
- "kaithi",
- "inmahajani",
- "emojimodifier",
- "inogham",
- "khojki",
- "cham",
- "chakma",
- "khar",
- "n",
- "graphemebase",
- "manichaean",
- "no",
- "inolchiki",
- "nandinagari",
- "nko",
- "nkoo",
- "sund",
- "inethiopic",
- "p",
- "punctuation",
- "ingreekandcoptic",
- "inmeroitichieroglyphs",
- "inphoenician",
- "intangsa",
- "adlm",
- "insinhala",
- "incyrillicextendeda",
- "gujr",
- "gujarati",
- "inlatinextendedc",
- "olower",
- "enclosingmark",
- "xpeo",
- "khmr",
- "olck",
- "linb",
- "ahom",
- "chorasmian",
- "zanb",
- "inkangxiradicals",
- "olchiki",
- "innabataean",
- "inkanbun",
- "casedletter",
- "inbhaiksuki",
- "sunu",
- "intaixuanjingsymbols",
- "chrs",
- "cpmn",
- "beng",
- "inscriptionalpahlavi",
- "inelbasan",
- "khmer",
- "linearb",
- "incjkunifiedideographsextensiond",
- "emojimodifierbase",
- "indogra",
- "adlam",
- "regionalindicator",
- "kharoshthi",
- "inphaistosdisc",
- "lepc",
- "xsux",
- "ingreekextended",
- "limb",
- "sogo",
- "sogdian",
- "ll",
- "emod",
- "incyrillicextendedc",
- "incyprominoan",
- "zl",
- "ingeometricshapes",
- "inkhitansmallscript",
- "math",
- "goth",
- "inarabic",
- "gurungkhema",
- "inimperialaramaic",
- "inmiscellaneoustechnical",
- "intamilsupplement",
- "arab",
- "grantha",
- "intirhuta",
- "inhatran",
- "mult",
- "intulutigalari",
- "inbasiclatin",
- "inoldhungarian",
- "insogdian",
- "indingbats",
- "ogam",
- "inarabicpresentationformsa",
- "vithkuqi",
- "kthi",
- "brah",
- "coptic",
- "ideographic",
- "emojicomponent",
- "takri",
- "invai",
- "ingurungkhema",
- "inherited",
- "radical",
- "dia",
- "di",
- "diak",
- "sinh",
- "glagolitic",
- "gukh",
- "shavian",
- "joincontrol",
- "takr",
- "inhanunoo",
- "ininscriptionalparthian",
- "ininscriptionalpahlavi",
- "taile",
- "grbase",
- "graphemeextend",
- "imperialaramaic",
- "copt",
- "bidicontrol",
- "nand",
- "intangut",
- "bopo",
- "osge",
- "cprt",
- "orkh",
- "sorasompeng",
- "intags",
- "inenclosedideographicsupplement",
- "inoldpersian",
- "inanatolianhieroglyphs",
- "oldpersian",
- "ingeometricshapesextended",
- "inbatak",
- "glag",
- "bhks",
- "inblockelements",
- "bhaiksuki",
- "incyrillicextendedd",
- "term",
- "innumberforms",
- "intibetan",
- "tnsa",
- "spacingmark",
- "tangsa",
- "inshavian",
- "inkanaextendedb",
- "diacritic",
- "bopomofo",
- "insinhalaarchaicnumbers",
-#endif /* USE_UNICODE_PROPERTIES */
- "space",
-#ifndef USE_UNICODE_PROPERTIES
- "xposixpunct",
-#else /* USE_UNICODE_PROPERTIES */
- "inarabicextendeda",
- "innushu",
- "incjksymbolsandpunctuation",
- "hang",
- "inoldpermic",
- "oldpermic",
- "anatolianhieroglyphs",
- "inenclosedalphanumerics",
- "inbyzantinemusicalsymbols",
- "ingujarati",
- "cntrl",
- "bugi",
- "inmyanmarextendedb",
- "inlatinextendedadditional",
- "sogd",
- "ingunjalagondi",
- "inlisu",
- "insundanesesupplement",
- "separator",
- "sarb",
- "assigned",
- "hiragana",
- "inrejang",
- "zanabazarsquare",
- "inlatinextendedd",
- "format",
- "inkayahli",
- "inoriya",
- "ingeorgiansupplement",
- "incoptic",
- "intodhri",
- "innewa",
- "buginese",
- "insyriacsupplement",
- "inkawi",
- "wara",
- "hmng",
- "inbraillepatterns",
- "inmiscellaneousmathematicalsymbolsb",
- "phli",
- "decimalnumber",
- "inarabicextendedc",
- "inyezidi",
- "braille",
- "inornamentaldingbats",
- "toto",
- "idsb",
- "variationselector",
- "innyiakengpuachuehmong",
- "asciihexdigit",
- "phnx",
- "number",
- "inwarangciti",
- "taiviet",
- "caseignorable",
- "kawi",
-#endif /* USE_UNICODE_PROPERTIES */
- "lower",
-#ifdef USE_UNICODE_PROPERTIES
- "ougr",
- "mahj",
- "indevanagari",
- "surrogate",
- "lyci",
- "mahajani",
- "inenclosedalphanumericsupplement",
- "lycian",
- "sharada",
- "mymr",
- "myanmar",
- "inbamum",
- "intelugu",
- "incjkunifiedideographsextensiong",
- "todr",
- "indevanagariextendeda",
- "medf",
- "todhri",
- "inethiopicsupplement",
- "inwancho",
- "medefaidrin",
- "shrd",
- "inkatakanaphoneticextensions",
- "inshorthandformatcontrols",
- "caucasianalbanian",
- "ahex",
- "insymbolsforlegacycomputingsupplement",
- "nd",
- "insoyombo",
- "other",
- "otheridcontinue",
- "khoj",
- "avestan",
- "othernumber",
- "sentenceterminal",
- "siddham",
- "closepunctuation",
- "lowercase",
- "olditalic",
- "oldhungarian",
- "inlisusupplement",
- "innoblock",
- "inunifiedcanadianaboriginalsyllabicsextendeda",
- "inelymaic",
- "cwcm",
- "inbalinese",
- "invariationselectors",
- "terminalpunctuation",
- "inpalmyrene",
- "alpha",
- "inlepcha",
- "incjkcompatibility",
- "rjng",
- "inhanguljamo",
- "dsrt",
- "inverticalforms",
- "phag",
- "incopticepactnumbers",
- "incjkunifiedideographsextensionh",
- "invedicextensions",
- "inhanguljamoextendeda",
- "cuneiform",
- "inmayannumerals",
- "otheralphabetic",
- "hmnp",
- "insuttonsignwriting",
- "incombiningdiacriticalmarks",
- "deseret",
- "avst",
- "inmeroiticcursive",
- "incombiningdiacriticalmarksforsymbols",
- "inglagolitic",
- "vith",
- "patsyn",
- "lydi",
- "lydian",
- "oldturkic",
- "innewtailue",
- "hebr",
- "intaiviet",
- "inphagspa",
- "inenclosedcjklettersandmonths",
- "hung",
- "inyiradicals",
- "inunifiedcanadianaboriginalsyllabics",
- "uideo",
- "idstrinaryoperator",
- "word",
- "invariationselectorssupplement",
- "java",
- "intagalog",
- "tale",
-#endif /* USE_UNICODE_PROPERTIES */
- "graph",
-#ifdef USE_UNICODE_PROPERTIES
- "inethiopicextendeda",
- "soyo",
- "spaceseparator",
- "inpaucinhau",
- "nagm",
- "inmongoliansupplement",
- "oupper",
- "inbengali",
- "hex",
- "javanese",
- "oalpha",
- "buhd",
- "inbuginese",
- "incjkunifiedideographsextensionb",
- "incombiningdiacriticalmarkssupplement",
- "insymbolsandpictographsextendeda",
- "taml",
- "ebase",
- "orya",
- "modifierletter",
- "indevanagariextended",
- "ext",
- "induployan",
- "inphoneticextensions",
- "tirhuta",
- "incombiningdiacriticalmarksextended",
- "xposixpunct",
- "injavanese",
- "lepcha",
- "lowercaseletter",
- "inindicsiyaqnumbers",
- "unassigned",
- "ethi",
- "titlecaseletter",
- "rohg",
- "syrc",
- "inunifiedcanadianaboriginalsyllabicsextended",
- "extender",
- "inbrahmi",
- "meroitichieroglyphs",
- "otheruppercase",
- "extpict",
- "incjkradicalssupplement",
- "tang",
- "tagbanwa",
- "zp",
- "inaegeannumbers",
- "nonspacingmark",
- "ingeorgianextended",
- "cwt",
- "dogra",
- "inphoneticextensionssupplement",
- "ingothic",
- "oldsogdian",
- "syriac",
- "incjkunifiedideographsextensionf",
- "dogr",
- "osmanya",
- "nchar",
- "inmathematicalalphanumericsymbols",
- "phagspa",
- "inlimbu",
- "cyrl",
- "currencysymbol",
- "epres",
- "inbopomofo",
- "narb",
- "insymbolsforlegacycomputing",
- "mlym",
- "insmallformvariants",
- "intagbanwa",
- "malayalam",
- "incyrillicextendedb",
- "olonal",
- "palmyrene",
- "thaa",
- "otheridstart",
- "thai",
- "tangut",
- "thaana",
- "emojipresentation",
- "inethiopicextended",
- "nagmundari",
- "nl",
- "inlatin1supplement",
- "tirh",
- "hangul",
- "talu",
- "buhid",
- "paragraphseparator",
- "graphemeclusterbreak=spacingmark",
- "telu",
- "otherlowercase",
- "ogham",
- "changeswhencasemapped",
- "intangutcomponents",
- "otherletter",
- "taitham",
- "graphemeclusterbreak=cr",
- "cwu",
- "graphemeclusterbreak=regionalindicator",
- "nushu",
- "sunuwar",
- "noncharactercodepoint",
- "softdotted",
- "omath",
- "inbassavah",
- "inottomansiyaqnumbers",
- "ingaray",
- "warangciti",
- "ugar",
- "inprivateusearea",
- "inbuhid",
- "dash",
- "inarabicpresentationformsb",
- "indivesakuru",
- "hexdigit",
- "inalphabeticpresentationforms",
- "othersymbol",
- "extendedpictographic",
- "changeswhentitlecased",
- "ogrext",
- "nbat",
- "insuperscriptsandsubscripts",
- "nabataean",
- "intangutsupplement",
- "inlowsurrogates",
- "inyijinghexagramsymbols",
- "inmahjongtiles",
- "inletterlikesymbols",
- "inbamumsupplement",
- "incurrencysymbols",
- "incombininghalfmarks",
- "wancho",
- "inarabicsupplement",
- "oldnortharabian",
- "khitansmallscript",
- "inlatinextendedg",
- "sylo",
- "inarabicmathematicalalphabeticsymbols",
- "nshu",
- "elba",
- "invithkuqi",
- "inhangulsyllables",
- "changeswhenuppercased",
- "intifinagh",
- "graphemeclusterbreak=t",
- "graphemeclusterbreak=lvt",
- "tamil",
- "mathsymbol",
- "tulutigalari",
- "otherdefaultignorablecodepoint",
- "wcho",
- "insupplementalarrowsa",
- "inarabicextendedb",
- "rejang",
- "graphemeclusterbreak=extend",
- "graphemeclusterbreak=prepend",
- "finalpunctuation",
- "inpsalterpahlavi",
- "newa",
- "inmathematicaloperators",
- "phlp",
- "deva",
- "devanagari",
- "newtailue",
- "cf",
- "pf",
- "whitespace",
- "elbasan",
- "othermath",
-#endif /* USE_UNICODE_PROPERTIES */
- "digit",
-#ifndef USE_UNICODE_PROPERTIES
- "blank"
-#else /* USE_UNICODE_PROPERTIES */
- "cyprominoan",
- "insupplementalarrowsc",
- "tibt",
- "tibetan",
- "bassavah",
- "insupplementalmathematicaloperators",
- "otherpunctuation",
- "sgnw",
- "ugaritic",
- "tutg",
- "changeswhenlowercased",
- "cwl",
- "inlinearbsyllabary",
- "inplayingcards",
- "modifiercombiningmark",
- "sylotinagri",
- "idcompatmathcontinue",
- "inpahawhhmong",
- "idcompatmathstart",
- "hanifirohingya",
- "deprecated",
- "oldsoutharabian",
- "shaw",
- "tavt",
- "wspace",
- "graphemeclusterbreak=l",
- "graphemeclusterbreak=control",
- "cypriot",
- "cyrillic",
- "inhanguljamoextendedb",
- "inalchemicalsymbols",
- "insupplementalpunctuation",
- "khudawadi",
- "aghb",
- "graphemeclusterbreak=zwj",
- "alphabetic",
- "cwcf",
- "elym",
- "ecomp",
- "inethiopicextendedb",
- "elymaic",
- "inglagoliticsupplement",
- "garay",
- "unknown",
- "soyombo",
- "inlatinextendedb",
- "divesakuru",
- "kayahli",
- "othergraphemeextend",
- "inhighprivateusesurrogates",
- "any",
- "dashpunctuation",
- "ethiopic",
- "symbol",
- "openpunctuation",
- "hluw",
- "tagb",
- "hyphen",
- "incypriotsyllabary",
- "dupl",
- "modifiersymbol",
- "inyisyllables",
- "inhalfwidthandfullwidthforms",
- "tfng",
- "dep",
- "inegyptianhieroglyphsextendeda",
- "inbopomofoextended",
- "telugu",
- "tglg",
- "tagalog",
- "inlatinextendedf",
- "changeswhencasefolded",
- "tifinagh",
- "graphemeclusterbreak=v",
- "graphemeclusterbreak=lv",
- "inegyptianhieroglyphs",
- "signwriting",
- "inegyptianhieroglyphformatcontrols",
- "graphemeclusterbreak=lf",
- "insupplementaryprivateuseareaa",
- "inhebrew",
- "inboxdrawing",
- "insupplementalarrowsb",
- "olduyghur",
- "upper",
- "inhighsurrogates",
- "uppercase",
- "inhangulcompatibilityjamo",
- "defaultignorablecodepoint",
- "uppercaseletter",
- "egyp",
- "insupplementalsymbolsandpictographs",
- "unifiedideograph",
- "pahawhhmong",
- "duployan",
- "nyiakengpuachuehmong",
- "zyyy",
- "insupplementaryprivateuseareab",
- "hebrew",
- "egyptianhieroglyphs"
-#endif /* USE_UNICODE_PROPERTIES */
- };
-#define uniname2ctype_pool ((const char *) &uniname2ctype_pool_contents)
-const struct uniname2ctype_struct *
-uniname2ctype_p (register const char *str, register size_t len)
-{
- static const struct uniname2ctype_struct wordlist[] =
- {
-#ifdef USE_UNICODE_PROPERTIES
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str12), 155},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str16), 187},
- {uniname2ctype_offset(str17), 114},
- {uniname2ctype_offset(str18), 34},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str22), 221},
- {uniname2ctype_offset(str23), 189},
- {uniname2ctype_offset(str24), 114},
- {uniname2ctype_offset(str25), 28},
- {-1},
- {uniname2ctype_offset(str27), 98},
- {uniname2ctype_offset(str28), 98},
- {-1},
- {uniname2ctype_offset(str30), 176},
- {uniname2ctype_offset(str31), 362},
- {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str37), 349},
- {uniname2ctype_offset(str38), 21},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str42), 61},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str52), 22},
-#endif /* USE_UNICODE_PROPERTIES */
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
-#ifndef USE_UNICODE_PROPERTIES
- {uniname2ctype_offset(str6), 12},
- {uniname2ctype_offset(str7), 7},
- {uniname2ctype_offset(str8), 15},
- {uniname2ctype_offset(str9), 1},
- {uniname2ctype_offset(str10), 13},
- {uniname2ctype_offset(str11), 11},
- {uniname2ctype_offset(str12), 10},
- {uniname2ctype_offset(str13), 14},
- {uniname2ctype_offset(str14), 3},
- {uniname2ctype_offset(str15), 9},
- {uniname2ctype_offset(str16), 8},
- {uniname2ctype_offset(str17), 6},
- {uniname2ctype_offset(str18), 5},
- {uniname2ctype_offset(str19), 4},
- {uniname2ctype_offset(str20), 2}
-#else /* USE_UNICODE_PROPERTIES */
- {uniname2ctype_offset(str59), 241},
- {uniname2ctype_offset(str60), 44},
- {uniname2ctype_offset(str61), 184},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str65), 52},
- {-1}, {-1},
- {uniname2ctype_offset(str68), 187},
- {uniname2ctype_offset(str69), 31},
- {uniname2ctype_offset(str70), 45},
- {-1},
- {uniname2ctype_offset(str72), 33},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str76), 274},
- {-1}, {-1},
- {uniname2ctype_offset(str79), 602},
- {-1},
- {uniname2ctype_offset(str81), 192},
- {uniname2ctype_offset(str82), 192},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str86), 530},
- {-1},
- {uniname2ctype_offset(str88), 152},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str92), 152},
- {uniname2ctype_offset(str93), 80},
- {-1}, {-1},
- {uniname2ctype_offset(str96), 233},
- {uniname2ctype_offset(str97), 101},
- {-1}, {-1},
- {uniname2ctype_offset(str100), 80},
- {uniname2ctype_offset(str101), 190},
- {uniname2ctype_offset(str102), 175},
- {-1}, {-1},
- {uniname2ctype_offset(str105), 111},
- {-1},
- {uniname2ctype_offset(str107), 31},
- {-1}, {-1},
- {uniname2ctype_offset(str110), 42},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str118), 215},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str122), 163},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str126), 513},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str130), 598},
- {uniname2ctype_offset(str131), 533},
- {uniname2ctype_offset(str132), 604},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str137), 173},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1},
- {uniname2ctype_offset(str149), 343},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str154), 243},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str158), 78},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str165), 553},
- {uniname2ctype_offset(str166), 368},
- {uniname2ctype_offset(str167), 172},
- {-1},
- {uniname2ctype_offset(str169), 584},
- {-1},
- {uniname2ctype_offset(str171), 18},
- {uniname2ctype_offset(str172), 292},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1},
- {uniname2ctype_offset(str192), 605},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str196), 381},
- {uniname2ctype_offset(str197), 27},
- {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str203), 211},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str208), 118},
- {-1}, {-1},
- {uniname2ctype_offset(str211), 31},
- {uniname2ctype_offset(str212), 376},
- {uniname2ctype_offset(str213), 504},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str218), 569},
- {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str224), 283},
- {uniname2ctype_offset(str225), 548},
- {uniname2ctype_offset(str226), 197},
- {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str232), 174},
- {-1}, {-1},
- {uniname2ctype_offset(str235), 105},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str240), 40},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str249), 534},
- {uniname2ctype_offset(str250), 589},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1},
- {uniname2ctype_offset(str262), 337},
- {-1}, {-1},
- {uniname2ctype_offset(str265), 555},
- {-1},
- {uniname2ctype_offset(str267), 373},
- {-1}, {-1},
- {uniname2ctype_offset(str270), 221},
- {-1}, {-1},
- {uniname2ctype_offset(str273), 411},
- {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str279), 215},
- {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str285), 25},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str289), 588},
- {-1},
- {uniname2ctype_offset(str291), 82},
- {uniname2ctype_offset(str292), 32},
- {uniname2ctype_offset(str293), 164},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str303), 82},
- {-1},
- {uniname2ctype_offset(str305), 581},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str309), 53},
- {-1},
- {uniname2ctype_offset(str311), 253},
- {uniname2ctype_offset(str312), 19},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str317), 350},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str325), 582},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str330), 40},
- {-1},
- {uniname2ctype_offset(str332), 166},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1},
- {uniname2ctype_offset(str343), 132},
- {-1},
- {uniname2ctype_offset(str345), 285},
- {-1}, {-1},
- {uniname2ctype_offset(str348), 472},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str352), 341},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str357), 574},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str362), 387},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str381), 79},
- {uniname2ctype_offset(str382), 284},
- {uniname2ctype_offset(str383), 283},
- {-1},
- {uniname2ctype_offset(str385), 79},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str390), 348},
- {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str396), 365},
- {uniname2ctype_offset(str397), 442},
- {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str403), 551},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str407), 346},
- {uniname2ctype_offset(str408), 55},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str416), 44},
- {-1}, {-1},
- {uniname2ctype_offset(str419), 163},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str426), 23},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str441), 172},
- {-1}, {-1},
- {uniname2ctype_offset(str444), 46},
- {uniname2ctype_offset(str445), 567},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str452), 191},
- {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str458), 612},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1},
- {uniname2ctype_offset(str470), 190},
- {-1},
- {uniname2ctype_offset(str472), 542},
- {uniname2ctype_offset(str473), 259},
- {-1},
- {uniname2ctype_offset(str475), 166},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str480), 84},
- {uniname2ctype_offset(str481), 130},
- {-1},
- {uniname2ctype_offset(str483), 111},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str487), 439},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str492), 14},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1},
- {uniname2ctype_offset(str504), 573},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str512), 22},
- {-1},
- {uniname2ctype_offset(str514), 532},
- {-1},
- {uniname2ctype_offset(str516), 49},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str524), 51},
- {uniname2ctype_offset(str525), 492},
- {uniname2ctype_offset(str526), 233},
- {uniname2ctype_offset(str527), 94},
- {uniname2ctype_offset(str528), 473},
- {-1},
- {uniname2ctype_offset(str530), 486},
- {-1},
- {uniname2ctype_offset(str532), 94},
- {-1},
- {uniname2ctype_offset(str534), 70},
- {uniname2ctype_offset(str535), 24},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str544), 565},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str554), 479},
- {-1},
- {uniname2ctype_offset(str556), 637},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str561), 244},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str565), 178},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str579), 603},
- {uniname2ctype_offset(str580), 243},
- {-1}, {-1},
- {uniname2ctype_offset(str583), 496},
- {uniname2ctype_offset(str584), 171},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str589), 37},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str597), 655},
- {uniname2ctype_offset(str598), 506},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str603), 91},
- {uniname2ctype_offset(str604), 422},
- {-1},
- {uniname2ctype_offset(str606), 650},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str614), 77},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str624), 70},
- {-1}, {-1},
- {uniname2ctype_offset(str627), 648},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str651), 159},
- {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str657), 545},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str661), 501},
- {-1},
- {uniname2ctype_offset(str663), 463},
- {uniname2ctype_offset(str664), 159},
- {-1},
- {uniname2ctype_offset(str666), 198},
- {uniname2ctype_offset(str667), 568},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str672), 232},
- {uniname2ctype_offset(str673), 392},
- {-1},
- {uniname2ctype_offset(str675), 76},
- {uniname2ctype_offset(str676), 116},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str680), 351},
- {uniname2ctype_offset(str681), 69},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str689), 618},
- {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str695), 196},
- {uniname2ctype_offset(str696), 50},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str700), 47},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str705), 174},
- {-1}, {-1},
- {uniname2ctype_offset(str708), 531},
- {-1},
- {uniname2ctype_offset(str710), 509},
- {uniname2ctype_offset(str711), 160},
- {uniname2ctype_offset(str712), 68},
- {uniname2ctype_offset(str713), 664},
- {uniname2ctype_offset(str714), 281},
- {-1}, {-1},
- {uniname2ctype_offset(str717), 161},
- {-1},
- {uniname2ctype_offset(str719), 621},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1},
- {uniname2ctype_offset(str739), 266},
- {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str745), 29},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str758), 447},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str768), 579},
- {-1},
- {uniname2ctype_offset(str770), 465},
- {-1}, {-1},
- {uniname2ctype_offset(str773), 643},
- {-1},
- {uniname2ctype_offset(str775), 632},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str784), 48},
- {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str790), 268},
- {uniname2ctype_offset(str791), 460},
- {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str797), 415},
- {-1},
- {uniname2ctype_offset(str799), 24},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str804), 170},
- {uniname2ctype_offset(str805), 611},
- {uniname2ctype_offset(str806), 213},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str811), 170},
- {-1},
- {uniname2ctype_offset(str813), 620},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str817), 516},
- {uniname2ctype_offset(str818), 281},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str822), 181},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str826), 67},
- {-1},
- {uniname2ctype_offset(str828), 72},
- {uniname2ctype_offset(str829), 366},
- {uniname2ctype_offset(str830), 147},
- {uniname2ctype_offset(str831), 147},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str835), 635},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str840), 109},
- {uniname2ctype_offset(str841), 128},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str846), 7},
- {uniname2ctype_offset(str847), 519},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1},
- {uniname2ctype_offset(str859), 389},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str869), 74},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str888), 420},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str896), 41},
- {uniname2ctype_offset(str897), 428},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str901), 149},
- {uniname2ctype_offset(str902), 647},
- {uniname2ctype_offset(str903), 19},
- {-1},
- {uniname2ctype_offset(str905), 500},
- {uniname2ctype_offset(str906), 414},
- {-1}, {-1},
- {uniname2ctype_offset(str909), 638},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str917), 113},
- {-1}, {-1},
- {uniname2ctype_offset(str920), 113},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str925), 120},
- {-1},
- {uniname2ctype_offset(str927), 107},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str937), 200},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str941), 120},
- {-1}, {-1},
- {uniname2ctype_offset(str944), 195},
- {uniname2ctype_offset(str945), 557},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1},
- {uniname2ctype_offset(str956), 559},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str960), 503},
- {-1}, {-1},
- {uniname2ctype_offset(str963), 538},
- {-1},
- {uniname2ctype_offset(str965), 110},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str978), 625},
- {uniname2ctype_offset(str979), 271},
- {-1}, {-1},
- {uniname2ctype_offset(str982), 68},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1000), 267},
- {-1}, {-1},
- {uniname2ctype_offset(str1003), 547},
- {uniname2ctype_offset(str1004), 75},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1008), 363},
- {uniname2ctype_offset(str1009), 30},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1},
- {uniname2ctype_offset(str1021), 338},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1026), 161},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1},
- {uniname2ctype_offset(str1038), 511},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1},
- {uniname2ctype_offset(str1050), 144},
- {-1},
- {uniname2ctype_offset(str1052), 67},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1057), 148},
- {uniname2ctype_offset(str1058), 613},
- {-1}, {-1},
- {uniname2ctype_offset(str1061), 89},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1070), 196},
- {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1076), 89},
- {uniname2ctype_offset(str1077), 462},
- {-1},
- {uniname2ctype_offset(str1079), 60},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1083), 498},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1087), 220},
- {uniname2ctype_offset(str1088), 560},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1092), 109},
- {-1}, {-1},
- {uniname2ctype_offset(str1095), 250},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1099), 279},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1109), 622},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1113), 123},
- {-1},
- {uniname2ctype_offset(str1115), 276},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1122), 514},
- {uniname2ctype_offset(str1123), 451},
- {uniname2ctype_offset(str1124), 342},
- {uniname2ctype_offset(str1125), 475},
- {uniname2ctype_offset(str1126), 101},
- {uniname2ctype_offset(str1127), 663},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1132), 268},
- {-1},
- {uniname2ctype_offset(str1134), 405},
- {uniname2ctype_offset(str1135), 13},
- {uniname2ctype_offset(str1136), 249},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1145), 369},
- {-1},
- {uniname2ctype_offset(str1147), 253},
- {-1},
- {uniname2ctype_offset(str1149), 478},
- {-1}, {-1},
- {uniname2ctype_offset(str1152), 661},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1157), 564},
- {-1}, {-1},
- {uniname2ctype_offset(str1160), 107},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1},
- {uniname2ctype_offset(str1172), 275},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1176), 115},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1186), 286},
- {uniname2ctype_offset(str1187), 382},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1195), 634},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1200), 335},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1},
- {uniname2ctype_offset(str1212), 280},
- {-1},
- {uniname2ctype_offset(str1214), 148},
- {-1},
- {uniname2ctype_offset(str1216), 385},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1},
- {uniname2ctype_offset(str1228), 139},
- {uniname2ctype_offset(str1229), 69},
- {-1},
- {uniname2ctype_offset(str1231), 11},
- {-1},
- {uniname2ctype_offset(str1233), 357},
- {-1}, {-1},
- {uniname2ctype_offset(str1236), 2},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1243), 527},
-#ifndef USE_UNICODE_AGE_PROPERTIES
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1258), 477},
-#endif /* USE_UNICODE_AGE_PROPERTIES */
- {-1}, {-1}, {-1},
-#ifdef USE_UNICODE_AGE_PROPERTIES
- {uniname2ctype_offset(str1247), 312},
- {uniname2ctype_offset(str1248), 311},
- {uniname2ctype_offset(str1249), 314},
- {uniname2ctype_offset(str1250), 313},
- {uniname2ctype_offset(str1251), 293},
- {uniname2ctype_offset(str1252), 319},
- {uniname2ctype_offset(str1253), 310},
- {uniname2ctype_offset(str1254), 295},
- {uniname2ctype_offset(str1255), 294},
- {uniname2ctype_offset(str1256), 305},
- {uniname2ctype_offset(str1257), 304},
- {uniname2ctype_offset(str1258), 477},
- {uniname2ctype_offset(str1259), 306},
- {uniname2ctype_offset(str1260), 309},
- {uniname2ctype_offset(str1261), 308},
-#endif /* USE_UNICODE_AGE_PROPERTIES */
- {uniname2ctype_offset(str1262), 659},
- {-1},
- {uniname2ctype_offset(str1264), 88},
- {uniname2ctype_offset(str1265), 118},
-#ifndef USE_UNICODE_AGE_PROPERTIES
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
-#else /* USE_UNICODE_AGE_PROPERTIES */
- {uniname2ctype_offset(str1266), 318},
- {uniname2ctype_offset(str1267), 317},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1271), 302},
- {uniname2ctype_offset(str1272), 301},
- {uniname2ctype_offset(str1273), 316},
- {uniname2ctype_offset(str1274), 303},
- {-1}, {-1},
- {uniname2ctype_offset(str1277), 300},
- {uniname2ctype_offset(str1278), 299},
- {-1}, {-1},
-#endif /* USE_UNICODE_AGE_PROPERTIES */
- {uniname2ctype_offset(str1281), 540},
- {uniname2ctype_offset(str1282), 360},
- {-1},
- {uniname2ctype_offset(str1284), 558},
-#ifndef USE_UNICODE_AGE_PROPERTIES
- {-1}, {-1}, {-1}, {-1}, {-1},
-#else /* USE_UNICODE_AGE_PROPERTIES */
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1288), 315},
- {-1},
-#endif /* USE_UNICODE_AGE_PROPERTIES */
- {uniname2ctype_offset(str1290), 139},
- {uniname2ctype_offset(str1291), 205},
-#ifndef USE_UNICODE_AGE_PROPERTIES
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
-#else /* USE_UNICODE_AGE_PROPERTIES */
- {uniname2ctype_offset(str1292), 297},
- {uniname2ctype_offset(str1293), 296},
- {-1},
- {uniname2ctype_offset(str1295), 298},
- {-1},
- {uniname2ctype_offset(str1297), 307},
-#endif /* USE_UNICODE_AGE_PROPERTIES */
- {uniname2ctype_offset(str1298), 15},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1},
- {uniname2ctype_offset(str1309), 453},
- {uniname2ctype_offset(str1310), 441},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1314), 96},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1318), 176},
- {-1},
- {uniname2ctype_offset(str1320), 141},
- {uniname2ctype_offset(str1321), 274},
- {-1},
- {uniname2ctype_offset(str1323), 206},
- {-1}, {-1},
- {uniname2ctype_offset(str1326), 105},
- {uniname2ctype_offset(str1327), 282},
- {uniname2ctype_offset(str1328), 220},
- {-1},
- {uniname2ctype_offset(str1330), 205},
- {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1336), 552},
- {-1}, {-1},
- {uniname2ctype_offset(str1339), 590},
- {uniname2ctype_offset(str1340), 211},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1349), 74},
- {uniname2ctype_offset(str1350), 273},
- {-1}, {-1},
- {uniname2ctype_offset(str1353), 104},
- {-1},
- {uniname2ctype_offset(str1355), 104},
- {-1},
- {uniname2ctype_offset(str1357), 199},
- {-1},
- {uniname2ctype_offset(str1359), 169},
- {-1}, {-1},
- {uniname2ctype_offset(str1362), 554},
- {uniname2ctype_offset(str1363), 288},
- {uniname2ctype_offset(str1364), 375},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1369), 186},
- {-1}, {-1},
- {uniname2ctype_offset(str1372), 154},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1376), 173},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1390), 138},
- {-1},
- {uniname2ctype_offset(str1392), 35},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1397), 73},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1},
- {uniname2ctype_offset(str1408), 189},
- {-1},
- {uniname2ctype_offset(str1410), 38},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1414), 395},
- {-1},
- {uniname2ctype_offset(str1416), 227},
- {uniname2ctype_offset(str1417), 143},
- {uniname2ctype_offset(str1418), 143},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1434), 144},
- {uniname2ctype_offset(str1435), 371},
- {-1},
- {uniname2ctype_offset(str1437), 39},
- {-1},
- {uniname2ctype_offset(str1439), 39},
- {uniname2ctype_offset(str1440), 340},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1},
- {uniname2ctype_offset(str1451), 528},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1455), 526},
- {uniname2ctype_offset(str1456), 599},
- {-1},
- {uniname2ctype_offset(str1458), 209},
- {-1},
- {uniname2ctype_offset(str1460), 364},
- {uniname2ctype_offset(str1461), 435},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1466), 90},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1476), 90},
- {-1},
- {uniname2ctype_offset(str1478), 430},
- {-1},
- {uniname2ctype_offset(str1480), 262},
- {-1},
- {uniname2ctype_offset(str1482), 33},
- {-1},
- {uniname2ctype_offset(str1484), 137},
- {uniname2ctype_offset(str1485), 108},
- {-1}, {-1},
- {uniname2ctype_offset(str1488), 146},
- {-1},
- {uniname2ctype_offset(str1490), 125},
- {uniname2ctype_offset(str1491), 203},
- {uniname2ctype_offset(str1492), 230},
- {-1}, {-1},
- {uniname2ctype_offset(str1495), 218},
- {-1}, {-1},
- {uniname2ctype_offset(str1498), 438},
- {-1}, {-1},
- {uniname2ctype_offset(str1501), 146},
- {uniname2ctype_offset(str1502), 524},
- {-1},
- {uniname2ctype_offset(str1504), 445},
- {uniname2ctype_offset(str1505), 25},
- {uniname2ctype_offset(str1506), 580},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1513), 245},
- {-1}, {-1},
- {uniname2ctype_offset(str1516), 624},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1520), 230},
- {uniname2ctype_offset(str1521), 234},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1525), 88},
- {uniname2ctype_offset(str1526), 167},
- {uniname2ctype_offset(str1527), 515},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1534), 108},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1542), 125},
- {-1}, {-1},
- {uniname2ctype_offset(str1545), 660},
- {uniname2ctype_offset(str1546), 289},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1553), 570},
- {-1},
- {uniname2ctype_offset(str1555), 209},
- {-1}, {-1},
- {uniname2ctype_offset(str1558), 284},
- {-1},
- {uniname2ctype_offset(str1560), 138},
- {-1},
- {uniname2ctype_offset(str1562), 502},
- {-1}, {-1},
- {uniname2ctype_offset(str1565), 145},
- {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1571), 140},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1575), 404},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1583), 123},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1591), 225},
- {-1},
- {uniname2ctype_offset(str1593), 224},
- {-1},
- {uniname2ctype_offset(str1595), 26},
- {-1}, {-1},
- {uniname2ctype_offset(str1598), 288},
- {-1},
- {uniname2ctype_offset(str1600), 396},
- {-1},
- {uniname2ctype_offset(str1602), 591},
- {-1},
- {uniname2ctype_offset(str1604), 53},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1621), 419},
- {uniname2ctype_offset(str1622), 608},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1626), 56},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1630), 116},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1634), 345},
- {uniname2ctype_offset(str1635), 242},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1642), 522},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1661), 413},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1665), 587},
- {-1}, {-1},
- {uniname2ctype_offset(str1668), 84},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1673), 184},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1678), 563},
- {uniname2ctype_offset(str1679), 525},
- {-1},
- {uniname2ctype_offset(str1681), 206},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1696), 561},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1704), 333},
- {uniname2ctype_offset(str1705), 539},
- {uniname2ctype_offset(str1706), 546},
- {uniname2ctype_offset(str1707), 421},
- {-1},
- {uniname2ctype_offset(str1709), 106},
- {-1},
- {uniname2ctype_offset(str1711), 488},
- {uniname2ctype_offset(str1712), 238},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1716), 169},
- {uniname2ctype_offset(str1717), 171},
- {-1},
- {uniname2ctype_offset(str1719), 132},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1723), 259},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1730), 290},
- {uniname2ctype_offset(str1731), 179},
- {-1},
- {uniname2ctype_offset(str1733), 457},
- {uniname2ctype_offset(str1734), 596},
- {uniname2ctype_offset(str1735), 118},
- {-1},
- {uniname2ctype_offset(str1737), 269},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1746), 260},
- {-1},
- {uniname2ctype_offset(str1748), 71},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1752), 231},
- {-1}, {-1},
- {uniname2ctype_offset(str1755), 96},
- {uniname2ctype_offset(str1756), 134},
- {-1},
- {uniname2ctype_offset(str1758), 242},
- {-1},
- {uniname2ctype_offset(str1760), 127},
- {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1766), 250},
- {-1},
- {uniname2ctype_offset(str1768), 179},
- {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1774), 378},
- {uniname2ctype_offset(str1775), 535},
- {uniname2ctype_offset(str1776), 536},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1780), 124},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1},
- {uniname2ctype_offset(str1791), 73},
- {uniname2ctype_offset(str1792), 72},
- {-1},
- {uniname2ctype_offset(str1794), 164},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1802), 132},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1807), 249},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1},
- {uniname2ctype_offset(str1819), 227},
- {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1825), 606},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1835), 112},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1839), 213},
- {uniname2ctype_offset(str1840), 129},
- {-1},
- {uniname2ctype_offset(str1842), 168},
- {uniname2ctype_offset(str1843), 178},
- {uniname2ctype_offset(str1844), 667},
- {-1},
- {uniname2ctype_offset(str1846), 646},
- {-1},
- {uniname2ctype_offset(str1848), 510},
- {-1}, {-1},
- {uniname2ctype_offset(str1851), 595},
- {uniname2ctype_offset(str1852), 137},
- {-1}, {-1},
- {uniname2ctype_offset(str1855), 652},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1868), 393},
- {-1},
- {uniname2ctype_offset(str1870), 134},
- {uniname2ctype_offset(str1871), 210},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1876), 418},
- {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1882), 210},
- {uniname2ctype_offset(str1883), 630},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1887), 254},
- {-1},
- {uniname2ctype_offset(str1889), 410},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1896), 367},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1914), 236},
- {-1},
- {uniname2ctype_offset(str1916), 32},
- {-1},
- {uniname2ctype_offset(str1918), 236},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1928), 512},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1932), 610},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1},
- {uniname2ctype_offset(str1944), 260},
- {uniname2ctype_offset(str1945), 112},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1950), 556},
- {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1956), 9},
- {uniname2ctype_offset(str1957), 354},
- {-1},
- {uniname2ctype_offset(str1959), 614},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1966), 440},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1980), 102},
- {uniname2ctype_offset(str1981), 508},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1988), 197},
- {-1}, {-1},
- {uniname2ctype_offset(str1991), 204},
- {uniname2ctype_offset(str1992), 416},
- {-1}, {-1},
- {uniname2ctype_offset(str1995), 619},
- {-1},
- {uniname2ctype_offset(str1997), 358},
- {uniname2ctype_offset(str1998), 3},
- {uniname2ctype_offset(str1999), 131},
- {-1}, {-1},
- {uniname2ctype_offset(str2002), 471},
- {uniname2ctype_offset(str2003), 403},
- {uniname2ctype_offset(str2004), 224},
- {-1},
- {uniname2ctype_offset(str2006), 583},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2011), 456},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2015), 398},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1},
- {uniname2ctype_offset(str2026), 52},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2030), 165},
- {-1}, {-1},
- {uniname2ctype_offset(str2033), 17},
- {-1},
- {uniname2ctype_offset(str2035), 110},
- {-1}, {-1},
- {uniname2ctype_offset(str2038), 468},
- {uniname2ctype_offset(str2039), 218},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2044), 461},
- {-1},
- {uniname2ctype_offset(str2046), 20},
- {-1}, {-1},
- {uniname2ctype_offset(str2049), 467},
- {-1},
- {uniname2ctype_offset(str2051), 359},
- {-1}, {-1},
- {uniname2ctype_offset(str2054), 432},
- {uniname2ctype_offset(str2055), 431},
- {uniname2ctype_offset(str2056), 518},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2060), 562},
- {uniname2ctype_offset(str2061), 131},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2065), 352},
- {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2071), 585},
- {-1},
- {uniname2ctype_offset(str2073), 202},
- {-1},
- {uniname2ctype_offset(str2075), 185},
- {-1},
- {uniname2ctype_offset(str2077), 424},
- {uniname2ctype_offset(str2078), 426},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2093), 167},
- {uniname2ctype_offset(str2094), 36},
- {-1},
- {uniname2ctype_offset(str2096), 544},
- {-1},
- {uniname2ctype_offset(str2098), 543},
- {uniname2ctype_offset(str2099), 130},
- {uniname2ctype_offset(str2100), 649},
- {-1}, {-1},
- {uniname2ctype_offset(str2103), 237},
- {-1},
- {uniname2ctype_offset(str2105), 266},
- {uniname2ctype_offset(str2106), 280},
- {-1}, {-1},
- {uniname2ctype_offset(str2109), 631},
- {-1},
- {uniname2ctype_offset(str2111), 257},
- {uniname2ctype_offset(str2112), 141},
- {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2118), 35},
- {-1},
- {uniname2ctype_offset(str2120), 571},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2127), 156},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2136), 61},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2146), 239},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2154), 6},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2162), 235},
- {uniname2ctype_offset(str2163), 188},
- {uniname2ctype_offset(str2164), 355},
- {-1},
- {uniname2ctype_offset(str2166), 23},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2171), 151},
- {-1},
- {uniname2ctype_offset(str2173), 188},
- {uniname2ctype_offset(str2174), 645},
- {uniname2ctype_offset(str2175), 151},
- {uniname2ctype_offset(str2176), 177},
- {uniname2ctype_offset(str2177), 100},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2182), 100},
- {-1}, {-1},
- {uniname2ctype_offset(str2185), 459},
- {uniname2ctype_offset(str2186), 361},
- {uniname2ctype_offset(str2187), 665},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2194), 246},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2199), 578},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2203), 222},
- {-1}, {-1},
- {uniname2ctype_offset(str2206), 246},
- {uniname2ctype_offset(str2207), 372},
- {-1}, {-1},
- {uniname2ctype_offset(str2210), 633},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2214), 222},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2218), 177},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2222), 448},
- {uniname2ctype_offset(str2223), 616},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2227), 180},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2231), 257},
- {-1},
- {uniname2ctype_offset(str2233), 617},
- {-1}, {-1},
- {uniname2ctype_offset(str2236), 36},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2254), 575},
- {uniname2ctype_offset(str2255), 18},
- {-1},
- {uniname2ctype_offset(str2257), 276},
- {uniname2ctype_offset(str2258), 186},
- {-1},
- {uniname2ctype_offset(str2260), 157},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2264), 38},
- {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2270), 279},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2275), 199},
- {uniname2ctype_offset(str2276), 42},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2280), 58},
- {uniname2ctype_offset(str2281), 115},
- {-1}, {-1},
- {uniname2ctype_offset(str2284), 207},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2289), 586},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2297), 671},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2302), 576},
- {uniname2ctype_offset(str2303), 549},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2310), 66},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2324), 391},
- {uniname2ctype_offset(str2325), 489},
- {-1},
- {uniname2ctype_offset(str2327), 254},
- {-1},
- {uniname2ctype_offset(str2329), 523},
- {uniname2ctype_offset(str2330), 1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1},
- {uniname2ctype_offset(str2341), 394},
- {uniname2ctype_offset(str2342), 450},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2349), 150},
- {uniname2ctype_offset(str2350), 370},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2355), 117},
- {-1}, {-1},
- {uniname2ctype_offset(str2358), 490},
- {uniname2ctype_offset(str2359), 142},
- {uniname2ctype_offset(str2360), 505},
- {-1}, {-1},
- {uniname2ctype_offset(str2363), 666},
- {-1}, {-1},
- {uniname2ctype_offset(str2366), 399},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2380), 469},
- {uniname2ctype_offset(str2381), 140},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2385), 623},
- {-1}, {-1},
- {uniname2ctype_offset(str2388), 258},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2398), 228},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2403), 627},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1},
- {uniname2ctype_offset(str2415), 339},
- {-1}, {-1},
- {uniname2ctype_offset(str2418), 117},
- {-1},
- {uniname2ctype_offset(str2420), 157},
- {uniname2ctype_offset(str2421), 529},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2425), 408},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2432), 429},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2436), 238},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2450), 282},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2454), 153},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2458), 153},
- {-1},
- {uniname2ctype_offset(str2460), 168},
- {-1}, {-1},
- {uniname2ctype_offset(str2463), 386},
- {uniname2ctype_offset(str2464), 83},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2472), 474},
- {uniname2ctype_offset(str2473), 464},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2477), 449},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2481), 207},
- {-1},
- {uniname2ctype_offset(str2483), 455},
- {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2489), 374},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2493), 270},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2503), 267},
- {uniname2ctype_offset(str2504), 12},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2508), 668},
- {-1},
- {uniname2ctype_offset(str2510), 162},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2519), 377},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1},
- {uniname2ctype_offset(str2539), 124},
- {-1},
- {uniname2ctype_offset(str2541), 5},
- {-1}, {-1},
- {uniname2ctype_offset(str2544), 476},
- {uniname2ctype_offset(str2545), 217},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2550), 55},
- {-1},
- {uniname2ctype_offset(str2552), 577},
- {-1},
- {uniname2ctype_offset(str2554), 240},
- {-1},
- {uniname2ctype_offset(str2556), 566},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2565), 263},
- {uniname2ctype_offset(str2566), 356},
- {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2572), 256},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2576), 162},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1},
- {uniname2ctype_offset(str2588), 258},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2593), 121},
- {uniname2ctype_offset(str2594), 388},
- {-1}, {-1},
- {uniname2ctype_offset(str2597), 658},
- {uniname2ctype_offset(str2598), 402},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2603), 656},
- {-1},
- {uniname2ctype_offset(str2605), 92},
- {uniname2ctype_offset(str2606), 289},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2615), 91},
- {uniname2ctype_offset(str2616), 27},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2620), 466},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2624), 261},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2628), 615},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1},
- {uniname2ctype_offset(str2640), 400},
- {-1},
- {uniname2ctype_offset(str2642), 201},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2649), 390},
- {-1}, {-1},
- {uniname2ctype_offset(str2652), 8},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2666), 470},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2670), 145},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2674), 26},
- {-1},
- {uniname2ctype_offset(str2676), 639},
- {-1}, {-1},
- {uniname2ctype_offset(str2679), 21},
- {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2685), 103},
- {-1},
- {uniname2ctype_offset(str2687), 29},
- {-1}, {-1},
- {uniname2ctype_offset(str2690), 223},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2713), 85},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2723), 383},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2733), 261},
- {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2739), 550},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2746), 175},
- {-1}, {-1},
- {uniname2ctype_offset(str2749), 263},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2773), 291},
- {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2779), 437},
- {-1}, {-1},
- {uniname2ctype_offset(str2782), 214},
- {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2788), 122},
- {-1},
- {uniname2ctype_offset(str2790), 54},
- {-1},
- {uniname2ctype_offset(str2792), 499},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2811), 34},
- {uniname2ctype_offset(str2812), 397},
- {uniname2ctype_offset(str2813), 64},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2818), 219},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2823), 401},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2833), 507},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2849), 225},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2856), 85},
- {-1},
- {uniname2ctype_offset(str2858), 662},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2863), 219},
- {-1}, {-1},
- {uniname2ctype_offset(str2866), 128},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2870), 264},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1},
- {uniname2ctype_offset(str2881), 626},
- {-1},
- {uniname2ctype_offset(str2883), 142},
- {uniname2ctype_offset(str2884), 384},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1},
- {uniname2ctype_offset(str2896), 81},
- {uniname2ctype_offset(str2897), 48},
- {-1}, {-1},
- {uniname2ctype_offset(str2900), 287},
- {-1},
- {uniname2ctype_offset(str2902), 443},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2916), 193},
- {-1},
- {uniname2ctype_offset(str2918), 657},
- {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2924), 95},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2928), 493},
- {-1},
- {uniname2ctype_offset(str2930), 380},
- {uniname2ctype_offset(str2931), 95},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2935), 458},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2945), 244},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2950), 195},
- {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2956), 86},
- {-1}, {-1},
- {uniname2ctype_offset(str2959), 275},
- {uniname2ctype_offset(str2960), 97},
- {uniname2ctype_offset(str2961), 214},
- {uniname2ctype_offset(str2962), 86},
- {-1},
- {uniname2ctype_offset(str2964), 287},
- {uniname2ctype_offset(str2965), 434},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2974), 240},
- {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2980), 37},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2985), 334},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str3007), 201},
- {-1},
- {uniname2ctype_offset(str3009), 102},
- {-1},
- {uniname2ctype_offset(str3011), 133},
- {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str3017), 121},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str3034), 54},
- {uniname2ctype_offset(str3035), 326},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str3040), 93},
- {-1},
- {uniname2ctype_offset(str3042), 262},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str3046), 106},
- {uniname2ctype_offset(str3047), 66},
- {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str3053), 607},
- {-1}, {-1},
- {uniname2ctype_offset(str3056), 28},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str3060), 155},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str3068), 321},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str3077), 63},
- {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str3083), 325},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str3096), 216},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str3103), 245},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str3112), 264},
- {-1},
- {uniname2ctype_offset(str3114), 273},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str3127), 255},
- {-1},
- {uniname2ctype_offset(str3129), 600},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str3138), 640},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1},
- {uniname2ctype_offset(str3149), 541},
- {-1},
- {uniname2ctype_offset(str3151), 202},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str3158), 126},
- {uniname2ctype_offset(str3159), 485},
- {uniname2ctype_offset(str3160), 379},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str3179), 251},
- {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str3185), 494},
- {-1},
- {uniname2ctype_offset(str3187), 572},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str3201), 256},
- {uniname2ctype_offset(str3202), 487},
- {-1}, {-1},
- {uniname2ctype_offset(str3205), 51},
- {-1}, {-1},
- {uniname2ctype_offset(str3208), 291},
- {-1}, {-1},
- {uniname2ctype_offset(str3211), 64},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str3218), 265},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1},
- {uniname2ctype_offset(str3238), 194},
- {uniname2ctype_offset(str3239), 406},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str3247), 194},
- {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str3253), 609},
- {uniname2ctype_offset(str3254), 484},
- {-1}, {-1},
- {uniname2ctype_offset(str3257), 452},
- {-1},
- {uniname2ctype_offset(str3259), 642},
- {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str3265), 409},
- {-1},
- {uniname2ctype_offset(str3267), 597},
- {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str3273), 407},
- {uniname2ctype_offset(str3274), 491},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str3290), 229},
- {-1},
- {uniname2ctype_offset(str3292), 347},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1},
- {uniname2ctype_offset(str3312), 193},
- {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str3318), 232},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str3328), 628},
- {-1},
- {uniname2ctype_offset(str3330), 136},
- {uniname2ctype_offset(str3331), 641},
- {uniname2ctype_offset(str3332), 216},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str3340), 183},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str3344), 517},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str3357), 480},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str3361), 63},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str3371), 433},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str3389), 329},
- {-1},
- {uniname2ctype_offset(str3391), 331},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str3401), 92},
- {uniname2ctype_offset(str3402), 50},
- {uniname2ctype_offset(str3403), 247},
- {-1},
- {uniname2ctype_offset(str3405), 271},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str3414), 229},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str3422), 423},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str3431), 353},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str3446), 150},
- {uniname2ctype_offset(str3447), 324},
- {uniname2ctype_offset(str3448), 320},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str3455), 43},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str3460), 537},
- {-1}, {-1},
- {uniname2ctype_offset(str3463), 212},
- {uniname2ctype_offset(str3464), 412},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1},
- {uniname2ctype_offset(str3476), 198},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str3480), 87},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str3494), 87},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str3503), 133},
- {uniname2ctype_offset(str3504), 20},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str3522), 43},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str3532), 248},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1},
- {uniname2ctype_offset(str3543), 183},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str3548), 255},
- {-1}, {-1},
- {uniname2ctype_offset(str3551), 4},
- {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str3557), 234},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str3561), 653},
- {-1},
- {uniname2ctype_offset(str3563), 99},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str3570), 99},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str3580), 181},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str3585), 427},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str3613), 45},
- {uniname2ctype_offset(str3614), 208},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str3629), 126},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1},
- {uniname2ctype_offset(str3650), 247},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str3654), 62},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str3663), 62},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str3670), 497},
- {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str3676), 644},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str3689), 285},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str3707), 136},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str3714), 277},
- {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str3720), 601},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str3729), 278},
- {-1}, {-1},
- {uniname2ctype_offset(str3732), 223},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str3757), 272},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str3766), 165},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str3788), 127},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str3793), 156},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str3810), 248},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str3814), 327},
- {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str3820), 323},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str3829), 129},
- {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str3835), 81},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str3854), 481},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str3877), 651},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str3882), 436},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1},
- {uniname2ctype_offset(str3894), 200},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str3925), 180},
- {-1}, {-1},
- {uniname2ctype_offset(str3928), 332},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1},
- {uniname2ctype_offset(str3949), 57},
- {uniname2ctype_offset(str3950), 65},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1},
- {uniname2ctype_offset(str3979), 226},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str3996), 290},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str4018), 636},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str4032), 226},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str4060), 629},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str4097), 241},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1},
- {uniname2ctype_offset(str4109), 292},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str4119), 217},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1},
- {uniname2ctype_offset(str4148), 336},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1},
- {uniname2ctype_offset(str4160), 231},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str4164), 149},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1},
- {uniname2ctype_offset(str4175), 265},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str4179), 483},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str4184), 16},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str4212), 41},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str4222), 103},
- {uniname2ctype_offset(str4223), 47},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str4239), 46},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str4248), 204},
- {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str4254), 122},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1},
- {uniname2ctype_offset(str4356), 252},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str4418), 521},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str4425), 182},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str4468), 49},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str4484), 454},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str4509), 495},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str4517), 135},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str4545), 272},
- {-1},
- {uniname2ctype_offset(str4547), 594},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str4562), 446},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1},
- {uniname2ctype_offset(str4609), 93},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1},
- {uniname2ctype_offset(str4638), 119},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str4652), 119},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str4670), 520},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str4687), 65},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str4703), 135},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str4728), 328},
- {uniname2ctype_offset(str4729), 330},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str4734), 592},
- {-1},
- {uniname2ctype_offset(str4736), 208},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1},
- {uniname2ctype_offset(str4747), 593},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str4756), 322},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str4771), 669},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str4821), 344},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str4865), 417},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str4896), 425},
- {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str4902), 235},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str4917), 10},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str5031), 482},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1},
- {uniname2ctype_offset(str5043), 59},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1},
- {uniname2ctype_offset(str5216), 444},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1},
- {uniname2ctype_offset(str5272), 71},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1},
- {uniname2ctype_offset(str5437), 30},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str5541), 158},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str5603), 654},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str5646), 270},
- {uniname2ctype_offset(str5647), 185},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str5666), 182},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str5914), 228},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str6073), 78},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str6245), 670},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str6528), 83},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str6807), 158}
-#endif /* USE_UNICODE_PROPERTIES */
- };
-
- if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
- {
- register unsigned int key = uniname2ctype_hash (str, len);
-
- if (key <= MAX_HASH_VALUE)
- {
- register int o = wordlist[key].name;
- if (o >= 0)
- {
- register const char *s = o + uniname2ctype_pool;
-
- if (*str == *s && !strncmp (str + 1, s + 1, len - 1) && s[len] == '\0')
- return &wordlist[key];
- }
- }
- }
- return 0;
-}
-
-static int
-uniname2ctype(const UChar *name, unsigned int len)
-{
- const struct uniname2ctype_struct *p = uniname2ctype_p((const char *)name, len);
- if (p) return p->ctype;
- return -1;
-}
-#if defined ONIG_UNICODE_VERSION_STRING && !( \
- ONIG_UNICODE_VERSION_MAJOR == 16 && \
- ONIG_UNICODE_VERSION_MINOR == 0 && \
- ONIG_UNICODE_VERSION_TEENY == 0 && \
- 1)
-# error ONIG_UNICODE_VERSION_STRING mismatch
-#endif
-#define ONIG_UNICODE_VERSION_STRING "16.0.0"
-#define ONIG_UNICODE_VERSION_MAJOR 16
-#define ONIG_UNICODE_VERSION_MINOR 0
-#define ONIG_UNICODE_VERSION_TEENY 0
-#if defined ONIG_UNICODE_EMOJI_VERSION_STRING && !( \
- ONIG_UNICODE_EMOJI_VERSION_MAJOR == 16 && \
- ONIG_UNICODE_EMOJI_VERSION_MINOR == 0 && \
- 1)
-# error ONIG_UNICODE_EMOJI_VERSION_STRING mismatch
-#endif
-#define ONIG_UNICODE_EMOJI_VERSION_STRING "16.0"
-#define ONIG_UNICODE_EMOJI_VERSION_MAJOR 16
-#define ONIG_UNICODE_EMOJI_VERSION_MINOR 0
diff --git a/enc/unicode/17.0.0/casefold.h b/enc/unicode/17.0.0/casefold.h
new file mode 100644
index 0000000000..82439f35fb
--- /dev/null
+++ b/enc/unicode/17.0.0/casefold.h
@@ -0,0 +1,8013 @@
+/* DO NOT EDIT THIS FILE. */
+/* Generated by enc-case-folding.rb */
+
+#if defined ONIG_UNICODE_VERSION_STRING && !( \
+ ONIG_UNICODE_VERSION_MAJOR == 17 && \
+ ONIG_UNICODE_VERSION_MINOR == 0 && \
+ ONIG_UNICODE_VERSION_TEENY == 0 && \
+ 1)
+# error ONIG_UNICODE_VERSION_STRING mismatch
+#endif
+#define ONIG_UNICODE_VERSION_STRING "17.0.0"
+#define ONIG_UNICODE_VERSION_MAJOR 17
+#define ONIG_UNICODE_VERSION_MINOR 0
+#define ONIG_UNICODE_VERSION_TEENY 0
+
+static const CaseFold_11_Type CaseFold_11_Table[] = {
+#define CaseFold (*(CaseFold_11_Type (*)[1583])(CaseFold_11_Table+0))
+ {0x0041, {1|F|D, {0x0061}}},
+ {0x0042, {1|F|D, {0x0062}}},
+ {0x0043, {1|F|D, {0x0063}}},
+ {0x0044, {1|F|D, {0x0064}}},
+ {0x0045, {1|F|D, {0x0065}}},
+ {0x0046, {1|F|D, {0x0066}}},
+ {0x0047, {1|F|D, {0x0067}}},
+ {0x0048, {1|F|D, {0x0068}}},
+ {0x004a, {1|F|D, {0x006a}}},
+ {0x004b, {1|F|D, {0x006b}}},
+ {0x004c, {1|F|D, {0x006c}}},
+ {0x004d, {1|F|D, {0x006d}}},
+ {0x004e, {1|F|D, {0x006e}}},
+ {0x004f, {1|F|D, {0x006f}}},
+ {0x0050, {1|F|D, {0x0070}}},
+ {0x0051, {1|F|D, {0x0071}}},
+ {0x0052, {1|F|D, {0x0072}}},
+ {0x0053, {1|F|D, {0x0073}}},
+ {0x0054, {1|F|D, {0x0074}}},
+ {0x0055, {1|F|D, {0x0075}}},
+ {0x0056, {1|F|D, {0x0076}}},
+ {0x0057, {1|F|D, {0x0077}}},
+ {0x0058, {1|F|D, {0x0078}}},
+ {0x0059, {1|F|D, {0x0079}}},
+ {0x005a, {1|F|D, {0x007a}}},
+ {0x00b5, {1|F|SU|I(0), {0x03bc}}},
+ {0x00c0, {1|F|D, {0x00e0}}},
+ {0x00c1, {1|F|D, {0x00e1}}},
+ {0x00c2, {1|F|D, {0x00e2}}},
+ {0x00c3, {1|F|D, {0x00e3}}},
+ {0x00c4, {1|F|D, {0x00e4}}},
+ {0x00c5, {1|F|D, {0x00e5}}},
+ {0x00c6, {1|F|D, {0x00e6}}},
+ {0x00c7, {1|F|D, {0x00e7}}},
+ {0x00c8, {1|F|D, {0x00e8}}},
+ {0x00c9, {1|F|D, {0x00e9}}},
+ {0x00ca, {1|F|D, {0x00ea}}},
+ {0x00cb, {1|F|D, {0x00eb}}},
+ {0x00cc, {1|F|D, {0x00ec}}},
+ {0x00cd, {1|F|D, {0x00ed}}},
+ {0x00ce, {1|F|D, {0x00ee}}},
+ {0x00cf, {1|F|D, {0x00ef}}},
+ {0x00d0, {1|F|D, {0x00f0}}},
+ {0x00d1, {1|F|D, {0x00f1}}},
+ {0x00d2, {1|F|D, {0x00f2}}},
+ {0x00d3, {1|F|D, {0x00f3}}},
+ {0x00d4, {1|F|D, {0x00f4}}},
+ {0x00d5, {1|F|D, {0x00f5}}},
+ {0x00d6, {1|F|D, {0x00f6}}},
+ {0x00d8, {1|F|D, {0x00f8}}},
+ {0x00d9, {1|F|D, {0x00f9}}},
+ {0x00da, {1|F|D, {0x00fa}}},
+ {0x00db, {1|F|D, {0x00fb}}},
+ {0x00dc, {1|F|D, {0x00fc}}},
+ {0x00dd, {1|F|D, {0x00fd}}},
+ {0x00de, {1|F|D, {0x00fe}}},
+ {0x00df, {2|F|ST|SU|I(1), {0x0073, 0x0073}}},
+ {0x0100, {1|F|D, {0x0101}}},
+ {0x0102, {1|F|D, {0x0103}}},
+ {0x0104, {1|F|D, {0x0105}}},
+ {0x0106, {1|F|D, {0x0107}}},
+ {0x0108, {1|F|D, {0x0109}}},
+ {0x010a, {1|F|D, {0x010b}}},
+ {0x010c, {1|F|D, {0x010d}}},
+ {0x010e, {1|F|D, {0x010f}}},
+ {0x0110, {1|F|D, {0x0111}}},
+ {0x0112, {1|F|D, {0x0113}}},
+ {0x0114, {1|F|D, {0x0115}}},
+ {0x0116, {1|F|D, {0x0117}}},
+ {0x0118, {1|F|D, {0x0119}}},
+ {0x011a, {1|F|D, {0x011b}}},
+ {0x011c, {1|F|D, {0x011d}}},
+ {0x011e, {1|F|D, {0x011f}}},
+ {0x0120, {1|F|D, {0x0121}}},
+ {0x0122, {1|F|D, {0x0123}}},
+ {0x0124, {1|F|D, {0x0125}}},
+ {0x0126, {1|F|D, {0x0127}}},
+ {0x0128, {1|F|D, {0x0129}}},
+ {0x012a, {1|F|D, {0x012b}}},
+ {0x012c, {1|F|D, {0x012d}}},
+ {0x012e, {1|F|D, {0x012f}}},
+ {0x0132, {1|F|D, {0x0133}}},
+ {0x0134, {1|F|D, {0x0135}}},
+ {0x0136, {1|F|D, {0x0137}}},
+ {0x0139, {1|F|D, {0x013a}}},
+ {0x013b, {1|F|D, {0x013c}}},
+ {0x013d, {1|F|D, {0x013e}}},
+ {0x013f, {1|F|D, {0x0140}}},
+ {0x0141, {1|F|D, {0x0142}}},
+ {0x0143, {1|F|D, {0x0144}}},
+ {0x0145, {1|F|D, {0x0146}}},
+ {0x0147, {1|F|D, {0x0148}}},
+ {0x0149, {2|F|SU|I(5), {0x02bc, 0x006e}}},
+ {0x014a, {1|F|D, {0x014b}}},
+ {0x014c, {1|F|D, {0x014d}}},
+ {0x014e, {1|F|D, {0x014f}}},
+ {0x0150, {1|F|D, {0x0151}}},
+ {0x0152, {1|F|D, {0x0153}}},
+ {0x0154, {1|F|D, {0x0155}}},
+ {0x0156, {1|F|D, {0x0157}}},
+ {0x0158, {1|F|D, {0x0159}}},
+ {0x015a, {1|F|D, {0x015b}}},
+ {0x015c, {1|F|D, {0x015d}}},
+ {0x015e, {1|F|D, {0x015f}}},
+ {0x0160, {1|F|D, {0x0161}}},
+ {0x0162, {1|F|D, {0x0163}}},
+ {0x0164, {1|F|D, {0x0165}}},
+ {0x0166, {1|F|D, {0x0167}}},
+ {0x0168, {1|F|D, {0x0169}}},
+ {0x016a, {1|F|D, {0x016b}}},
+ {0x016c, {1|F|D, {0x016d}}},
+ {0x016e, {1|F|D, {0x016f}}},
+ {0x0170, {1|F|D, {0x0171}}},
+ {0x0172, {1|F|D, {0x0173}}},
+ {0x0174, {1|F|D, {0x0175}}},
+ {0x0176, {1|F|D, {0x0177}}},
+ {0x0178, {1|F|D, {0x00ff}}},
+ {0x0179, {1|F|D, {0x017a}}},
+ {0x017b, {1|F|D, {0x017c}}},
+ {0x017d, {1|F|D, {0x017e}}},
+ {0x017f, {1|F|SU|I(7), {0x0073}}},
+ {0x0181, {1|F|D, {0x0253}}},
+ {0x0182, {1|F|D, {0x0183}}},
+ {0x0184, {1|F|D, {0x0185}}},
+ {0x0186, {1|F|D, {0x0254}}},
+ {0x0187, {1|F|D, {0x0188}}},
+ {0x0189, {1|F|D, {0x0256}}},
+ {0x018a, {1|F|D, {0x0257}}},
+ {0x018b, {1|F|D, {0x018c}}},
+ {0x018e, {1|F|D, {0x01dd}}},
+ {0x018f, {1|F|D, {0x0259}}},
+ {0x0190, {1|F|D, {0x025b}}},
+ {0x0191, {1|F|D, {0x0192}}},
+ {0x0193, {1|F|D, {0x0260}}},
+ {0x0194, {1|F|D, {0x0263}}},
+ {0x0196, {1|F|D, {0x0269}}},
+ {0x0197, {1|F|D, {0x0268}}},
+ {0x0198, {1|F|D, {0x0199}}},
+ {0x019c, {1|F|D, {0x026f}}},
+ {0x019d, {1|F|D, {0x0272}}},
+ {0x019f, {1|F|D, {0x0275}}},
+ {0x01a0, {1|F|D, {0x01a1}}},
+ {0x01a2, {1|F|D, {0x01a3}}},
+ {0x01a4, {1|F|D, {0x01a5}}},
+ {0x01a6, {1|F|D, {0x0280}}},
+ {0x01a7, {1|F|D, {0x01a8}}},
+ {0x01a9, {1|F|D, {0x0283}}},
+ {0x01ac, {1|F|D, {0x01ad}}},
+ {0x01ae, {1|F|D, {0x0288}}},
+ {0x01af, {1|F|D, {0x01b0}}},
+ {0x01b1, {1|F|D, {0x028a}}},
+ {0x01b2, {1|F|D, {0x028b}}},
+ {0x01b3, {1|F|D, {0x01b4}}},
+ {0x01b5, {1|F|D, {0x01b6}}},
+ {0x01b7, {1|F|D, {0x0292}}},
+ {0x01b8, {1|F|D, {0x01b9}}},
+ {0x01bc, {1|F|D, {0x01bd}}},
+ {0x01c4, {1|F|D|ST|I(8), {0x01c6}}},
+ {0x01c5, {1|F|D|IT|SU|I(9), {0x01c6}}},
+ {0x01c7, {1|F|D|ST|I(12), {0x01c9}}},
+ {0x01c8, {1|F|D|IT|SU|I(13), {0x01c9}}},
+ {0x01ca, {1|F|D|ST|I(16), {0x01cc}}},
+ {0x01cb, {1|F|D|IT|SU|I(17), {0x01cc}}},
+ {0x01cd, {1|F|D, {0x01ce}}},
+ {0x01cf, {1|F|D, {0x01d0}}},
+ {0x01d1, {1|F|D, {0x01d2}}},
+ {0x01d3, {1|F|D, {0x01d4}}},
+ {0x01d5, {1|F|D, {0x01d6}}},
+ {0x01d7, {1|F|D, {0x01d8}}},
+ {0x01d9, {1|F|D, {0x01da}}},
+ {0x01db, {1|F|D, {0x01dc}}},
+ {0x01de, {1|F|D, {0x01df}}},
+ {0x01e0, {1|F|D, {0x01e1}}},
+ {0x01e2, {1|F|D, {0x01e3}}},
+ {0x01e4, {1|F|D, {0x01e5}}},
+ {0x01e6, {1|F|D, {0x01e7}}},
+ {0x01e8, {1|F|D, {0x01e9}}},
+ {0x01ea, {1|F|D, {0x01eb}}},
+ {0x01ec, {1|F|D, {0x01ed}}},
+ {0x01ee, {1|F|D, {0x01ef}}},
+ {0x01f0, {2|F|SU|I(20), {0x006a, 0x030c}}},
+ {0x01f1, {1|F|D|ST|I(22), {0x01f3}}},
+ {0x01f2, {1|F|D|IT|SU|I(23), {0x01f3}}},
+ {0x01f4, {1|F|D, {0x01f5}}},
+ {0x01f6, {1|F|D, {0x0195}}},
+ {0x01f7, {1|F|D, {0x01bf}}},
+ {0x01f8, {1|F|D, {0x01f9}}},
+ {0x01fa, {1|F|D, {0x01fb}}},
+ {0x01fc, {1|F|D, {0x01fd}}},
+ {0x01fe, {1|F|D, {0x01ff}}},
+ {0x0200, {1|F|D, {0x0201}}},
+ {0x0202, {1|F|D, {0x0203}}},
+ {0x0204, {1|F|D, {0x0205}}},
+ {0x0206, {1|F|D, {0x0207}}},
+ {0x0208, {1|F|D, {0x0209}}},
+ {0x020a, {1|F|D, {0x020b}}},
+ {0x020c, {1|F|D, {0x020d}}},
+ {0x020e, {1|F|D, {0x020f}}},
+ {0x0210, {1|F|D, {0x0211}}},
+ {0x0212, {1|F|D, {0x0213}}},
+ {0x0214, {1|F|D, {0x0215}}},
+ {0x0216, {1|F|D, {0x0217}}},
+ {0x0218, {1|F|D, {0x0219}}},
+ {0x021a, {1|F|D, {0x021b}}},
+ {0x021c, {1|F|D, {0x021d}}},
+ {0x021e, {1|F|D, {0x021f}}},
+ {0x0220, {1|F|D, {0x019e}}},
+ {0x0222, {1|F|D, {0x0223}}},
+ {0x0224, {1|F|D, {0x0225}}},
+ {0x0226, {1|F|D, {0x0227}}},
+ {0x0228, {1|F|D, {0x0229}}},
+ {0x022a, {1|F|D, {0x022b}}},
+ {0x022c, {1|F|D, {0x022d}}},
+ {0x022e, {1|F|D, {0x022f}}},
+ {0x0230, {1|F|D, {0x0231}}},
+ {0x0232, {1|F|D, {0x0233}}},
+ {0x023a, {1|F|D, {0x2c65}}},
+ {0x023b, {1|F|D, {0x023c}}},
+ {0x023d, {1|F|D, {0x019a}}},
+ {0x023e, {1|F|D, {0x2c66}}},
+ {0x0241, {1|F|D, {0x0242}}},
+ {0x0243, {1|F|D, {0x0180}}},
+ {0x0244, {1|F|D, {0x0289}}},
+ {0x0245, {1|F|D, {0x028c}}},
+ {0x0246, {1|F|D, {0x0247}}},
+ {0x0248, {1|F|D, {0x0249}}},
+ {0x024a, {1|F|D, {0x024b}}},
+ {0x024c, {1|F|D, {0x024d}}},
+ {0x024e, {1|F|D, {0x024f}}},
+ {0x0345, {1|F|SU|I(26), {0x03b9}}},
+ {0x0370, {1|F|D, {0x0371}}},
+ {0x0372, {1|F|D, {0x0373}}},
+ {0x0376, {1|F|D, {0x0377}}},
+ {0x037f, {1|F|D, {0x03f3}}},
+ {0x0386, {1|F|D, {0x03ac}}},
+ {0x0388, {1|F|D, {0x03ad}}},
+ {0x0389, {1|F|D, {0x03ae}}},
+ {0x038a, {1|F|D, {0x03af}}},
+ {0x038c, {1|F|D, {0x03cc}}},
+ {0x038e, {1|F|D, {0x03cd}}},
+ {0x038f, {1|F|D, {0x03ce}}},
+ {0x0390, {3|F|SU|I(27), {0x03b9, 0x0308, 0x0301}}},
+ {0x0391, {1|F|D, {0x03b1}}},
+ {0x0392, {1|F|D, {0x03b2}}},
+ {0x0393, {1|F|D, {0x03b3}}},
+ {0x0394, {1|F|D, {0x03b4}}},
+ {0x0395, {1|F|D, {0x03b5}}},
+ {0x0396, {1|F|D, {0x03b6}}},
+ {0x0397, {1|F|D, {0x03b7}}},
+ {0x0398, {1|F|D, {0x03b8}}},
+ {0x0399, {1|F|D, {0x03b9}}},
+ {0x039a, {1|F|D, {0x03ba}}},
+ {0x039b, {1|F|D, {0x03bb}}},
+ {0x039c, {1|F|D, {0x03bc}}},
+ {0x039d, {1|F|D, {0x03bd}}},
+ {0x039e, {1|F|D, {0x03be}}},
+ {0x039f, {1|F|D, {0x03bf}}},
+ {0x03a0, {1|F|D, {0x03c0}}},
+ {0x03a1, {1|F|D, {0x03c1}}},
+ {0x03a3, {1|F|D, {0x03c3}}},
+ {0x03a4, {1|F|D, {0x03c4}}},
+ {0x03a5, {1|F|D, {0x03c5}}},
+ {0x03a6, {1|F|D, {0x03c6}}},
+ {0x03a7, {1|F|D, {0x03c7}}},
+ {0x03a8, {1|F|D, {0x03c8}}},
+ {0x03a9, {1|F|D, {0x03c9}}},
+ {0x03aa, {1|F|D, {0x03ca}}},
+ {0x03ab, {1|F|D, {0x03cb}}},
+ {0x03b0, {3|F|SU|I(30), {0x03c5, 0x0308, 0x0301}}},
+ {0x03c2, {1|F|SU|I(33), {0x03c3}}},
+ {0x03cf, {1|F|D, {0x03d7}}},
+ {0x03d0, {1|F|SU|I(34), {0x03b2}}},
+ {0x03d1, {1|F|SU|I(35), {0x03b8}}},
+ {0x03d5, {1|F|SU|I(36), {0x03c6}}},
+ {0x03d6, {1|F|SU|I(37), {0x03c0}}},
+ {0x03d8, {1|F|D, {0x03d9}}},
+ {0x03da, {1|F|D, {0x03db}}},
+ {0x03dc, {1|F|D, {0x03dd}}},
+ {0x03de, {1|F|D, {0x03df}}},
+ {0x03e0, {1|F|D, {0x03e1}}},
+ {0x03e2, {1|F|D, {0x03e3}}},
+ {0x03e4, {1|F|D, {0x03e5}}},
+ {0x03e6, {1|F|D, {0x03e7}}},
+ {0x03e8, {1|F|D, {0x03e9}}},
+ {0x03ea, {1|F|D, {0x03eb}}},
+ {0x03ec, {1|F|D, {0x03ed}}},
+ {0x03ee, {1|F|D, {0x03ef}}},
+ {0x03f0, {1|F|SU|I(38), {0x03ba}}},
+ {0x03f1, {1|F|SU|I(39), {0x03c1}}},
+ {0x03f4, {1|F|D, {0x03b8}}},
+ {0x03f5, {1|F|SU|I(40), {0x03b5}}},
+ {0x03f7, {1|F|D, {0x03f8}}},
+ {0x03f9, {1|F|D, {0x03f2}}},
+ {0x03fa, {1|F|D, {0x03fb}}},
+ {0x03fd, {1|F|D, {0x037b}}},
+ {0x03fe, {1|F|D, {0x037c}}},
+ {0x03ff, {1|F|D, {0x037d}}},
+ {0x0400, {1|F|D, {0x0450}}},
+ {0x0401, {1|F|D, {0x0451}}},
+ {0x0402, {1|F|D, {0x0452}}},
+ {0x0403, {1|F|D, {0x0453}}},
+ {0x0404, {1|F|D, {0x0454}}},
+ {0x0405, {1|F|D, {0x0455}}},
+ {0x0406, {1|F|D, {0x0456}}},
+ {0x0407, {1|F|D, {0x0457}}},
+ {0x0408, {1|F|D, {0x0458}}},
+ {0x0409, {1|F|D, {0x0459}}},
+ {0x040a, {1|F|D, {0x045a}}},
+ {0x040b, {1|F|D, {0x045b}}},
+ {0x040c, {1|F|D, {0x045c}}},
+ {0x040d, {1|F|D, {0x045d}}},
+ {0x040e, {1|F|D, {0x045e}}},
+ {0x040f, {1|F|D, {0x045f}}},
+ {0x0410, {1|F|D, {0x0430}}},
+ {0x0411, {1|F|D, {0x0431}}},
+ {0x0412, {1|F|D, {0x0432}}},
+ {0x0413, {1|F|D, {0x0433}}},
+ {0x0414, {1|F|D, {0x0434}}},
+ {0x0415, {1|F|D, {0x0435}}},
+ {0x0416, {1|F|D, {0x0436}}},
+ {0x0417, {1|F|D, {0x0437}}},
+ {0x0418, {1|F|D, {0x0438}}},
+ {0x0419, {1|F|D, {0x0439}}},
+ {0x041a, {1|F|D, {0x043a}}},
+ {0x041b, {1|F|D, {0x043b}}},
+ {0x041c, {1|F|D, {0x043c}}},
+ {0x041d, {1|F|D, {0x043d}}},
+ {0x041e, {1|F|D, {0x043e}}},
+ {0x041f, {1|F|D, {0x043f}}},
+ {0x0420, {1|F|D, {0x0440}}},
+ {0x0421, {1|F|D, {0x0441}}},
+ {0x0422, {1|F|D, {0x0442}}},
+ {0x0423, {1|F|D, {0x0443}}},
+ {0x0424, {1|F|D, {0x0444}}},
+ {0x0425, {1|F|D, {0x0445}}},
+ {0x0426, {1|F|D, {0x0446}}},
+ {0x0427, {1|F|D, {0x0447}}},
+ {0x0428, {1|F|D, {0x0448}}},
+ {0x0429, {1|F|D, {0x0449}}},
+ {0x042a, {1|F|D, {0x044a}}},
+ {0x042b, {1|F|D, {0x044b}}},
+ {0x042c, {1|F|D, {0x044c}}},
+ {0x042d, {1|F|D, {0x044d}}},
+ {0x042e, {1|F|D, {0x044e}}},
+ {0x042f, {1|F|D, {0x044f}}},
+ {0x0460, {1|F|D, {0x0461}}},
+ {0x0462, {1|F|D, {0x0463}}},
+ {0x0464, {1|F|D, {0x0465}}},
+ {0x0466, {1|F|D, {0x0467}}},
+ {0x0468, {1|F|D, {0x0469}}},
+ {0x046a, {1|F|D, {0x046b}}},
+ {0x046c, {1|F|D, {0x046d}}},
+ {0x046e, {1|F|D, {0x046f}}},
+ {0x0470, {1|F|D, {0x0471}}},
+ {0x0472, {1|F|D, {0x0473}}},
+ {0x0474, {1|F|D, {0x0475}}},
+ {0x0476, {1|F|D, {0x0477}}},
+ {0x0478, {1|F|D, {0x0479}}},
+ {0x047a, {1|F|D, {0x047b}}},
+ {0x047c, {1|F|D, {0x047d}}},
+ {0x047e, {1|F|D, {0x047f}}},
+ {0x0480, {1|F|D, {0x0481}}},
+ {0x048a, {1|F|D, {0x048b}}},
+ {0x048c, {1|F|D, {0x048d}}},
+ {0x048e, {1|F|D, {0x048f}}},
+ {0x0490, {1|F|D, {0x0491}}},
+ {0x0492, {1|F|D, {0x0493}}},
+ {0x0494, {1|F|D, {0x0495}}},
+ {0x0496, {1|F|D, {0x0497}}},
+ {0x0498, {1|F|D, {0x0499}}},
+ {0x049a, {1|F|D, {0x049b}}},
+ {0x049c, {1|F|D, {0x049d}}},
+ {0x049e, {1|F|D, {0x049f}}},
+ {0x04a0, {1|F|D, {0x04a1}}},
+ {0x04a2, {1|F|D, {0x04a3}}},
+ {0x04a4, {1|F|D, {0x04a5}}},
+ {0x04a6, {1|F|D, {0x04a7}}},
+ {0x04a8, {1|F|D, {0x04a9}}},
+ {0x04aa, {1|F|D, {0x04ab}}},
+ {0x04ac, {1|F|D, {0x04ad}}},
+ {0x04ae, {1|F|D, {0x04af}}},
+ {0x04b0, {1|F|D, {0x04b1}}},
+ {0x04b2, {1|F|D, {0x04b3}}},
+ {0x04b4, {1|F|D, {0x04b5}}},
+ {0x04b6, {1|F|D, {0x04b7}}},
+ {0x04b8, {1|F|D, {0x04b9}}},
+ {0x04ba, {1|F|D, {0x04bb}}},
+ {0x04bc, {1|F|D, {0x04bd}}},
+ {0x04be, {1|F|D, {0x04bf}}},
+ {0x04c0, {1|F|D, {0x04cf}}},
+ {0x04c1, {1|F|D, {0x04c2}}},
+ {0x04c3, {1|F|D, {0x04c4}}},
+ {0x04c5, {1|F|D, {0x04c6}}},
+ {0x04c7, {1|F|D, {0x04c8}}},
+ {0x04c9, {1|F|D, {0x04ca}}},
+ {0x04cb, {1|F|D, {0x04cc}}},
+ {0x04cd, {1|F|D, {0x04ce}}},
+ {0x04d0, {1|F|D, {0x04d1}}},
+ {0x04d2, {1|F|D, {0x04d3}}},
+ {0x04d4, {1|F|D, {0x04d5}}},
+ {0x04d6, {1|F|D, {0x04d7}}},
+ {0x04d8, {1|F|D, {0x04d9}}},
+ {0x04da, {1|F|D, {0x04db}}},
+ {0x04dc, {1|F|D, {0x04dd}}},
+ {0x04de, {1|F|D, {0x04df}}},
+ {0x04e0, {1|F|D, {0x04e1}}},
+ {0x04e2, {1|F|D, {0x04e3}}},
+ {0x04e4, {1|F|D, {0x04e5}}},
+ {0x04e6, {1|F|D, {0x04e7}}},
+ {0x04e8, {1|F|D, {0x04e9}}},
+ {0x04ea, {1|F|D, {0x04eb}}},
+ {0x04ec, {1|F|D, {0x04ed}}},
+ {0x04ee, {1|F|D, {0x04ef}}},
+ {0x04f0, {1|F|D, {0x04f1}}},
+ {0x04f2, {1|F|D, {0x04f3}}},
+ {0x04f4, {1|F|D, {0x04f5}}},
+ {0x04f6, {1|F|D, {0x04f7}}},
+ {0x04f8, {1|F|D, {0x04f9}}},
+ {0x04fa, {1|F|D, {0x04fb}}},
+ {0x04fc, {1|F|D, {0x04fd}}},
+ {0x04fe, {1|F|D, {0x04ff}}},
+ {0x0500, {1|F|D, {0x0501}}},
+ {0x0502, {1|F|D, {0x0503}}},
+ {0x0504, {1|F|D, {0x0505}}},
+ {0x0506, {1|F|D, {0x0507}}},
+ {0x0508, {1|F|D, {0x0509}}},
+ {0x050a, {1|F|D, {0x050b}}},
+ {0x050c, {1|F|D, {0x050d}}},
+ {0x050e, {1|F|D, {0x050f}}},
+ {0x0510, {1|F|D, {0x0511}}},
+ {0x0512, {1|F|D, {0x0513}}},
+ {0x0514, {1|F|D, {0x0515}}},
+ {0x0516, {1|F|D, {0x0517}}},
+ {0x0518, {1|F|D, {0x0519}}},
+ {0x051a, {1|F|D, {0x051b}}},
+ {0x051c, {1|F|D, {0x051d}}},
+ {0x051e, {1|F|D, {0x051f}}},
+ {0x0520, {1|F|D, {0x0521}}},
+ {0x0522, {1|F|D, {0x0523}}},
+ {0x0524, {1|F|D, {0x0525}}},
+ {0x0526, {1|F|D, {0x0527}}},
+ {0x0528, {1|F|D, {0x0529}}},
+ {0x052a, {1|F|D, {0x052b}}},
+ {0x052c, {1|F|D, {0x052d}}},
+ {0x052e, {1|F|D, {0x052f}}},
+ {0x0531, {1|F|D, {0x0561}}},
+ {0x0532, {1|F|D, {0x0562}}},
+ {0x0533, {1|F|D, {0x0563}}},
+ {0x0534, {1|F|D, {0x0564}}},
+ {0x0535, {1|F|D, {0x0565}}},
+ {0x0536, {1|F|D, {0x0566}}},
+ {0x0537, {1|F|D, {0x0567}}},
+ {0x0538, {1|F|D, {0x0568}}},
+ {0x0539, {1|F|D, {0x0569}}},
+ {0x053a, {1|F|D, {0x056a}}},
+ {0x053b, {1|F|D, {0x056b}}},
+ {0x053c, {1|F|D, {0x056c}}},
+ {0x053d, {1|F|D, {0x056d}}},
+ {0x053e, {1|F|D, {0x056e}}},
+ {0x053f, {1|F|D, {0x056f}}},
+ {0x0540, {1|F|D, {0x0570}}},
+ {0x0541, {1|F|D, {0x0571}}},
+ {0x0542, {1|F|D, {0x0572}}},
+ {0x0543, {1|F|D, {0x0573}}},
+ {0x0544, {1|F|D, {0x0574}}},
+ {0x0545, {1|F|D, {0x0575}}},
+ {0x0546, {1|F|D, {0x0576}}},
+ {0x0547, {1|F|D, {0x0577}}},
+ {0x0548, {1|F|D, {0x0578}}},
+ {0x0549, {1|F|D, {0x0579}}},
+ {0x054a, {1|F|D, {0x057a}}},
+ {0x054b, {1|F|D, {0x057b}}},
+ {0x054c, {1|F|D, {0x057c}}},
+ {0x054d, {1|F|D, {0x057d}}},
+ {0x054e, {1|F|D, {0x057e}}},
+ {0x054f, {1|F|D, {0x057f}}},
+ {0x0550, {1|F|D, {0x0580}}},
+ {0x0551, {1|F|D, {0x0581}}},
+ {0x0552, {1|F|D, {0x0582}}},
+ {0x0553, {1|F|D, {0x0583}}},
+ {0x0554, {1|F|D, {0x0584}}},
+ {0x0555, {1|F|D, {0x0585}}},
+ {0x0556, {1|F|D, {0x0586}}},
+ {0x0587, {2|F|ST|SU|I(41), {0x0565, 0x0582}}},
+ {0x10a0, {1|F|D, {0x2d00}}},
+ {0x10a1, {1|F|D, {0x2d01}}},
+ {0x10a2, {1|F|D, {0x2d02}}},
+ {0x10a3, {1|F|D, {0x2d03}}},
+ {0x10a4, {1|F|D, {0x2d04}}},
+ {0x10a5, {1|F|D, {0x2d05}}},
+ {0x10a6, {1|F|D, {0x2d06}}},
+ {0x10a7, {1|F|D, {0x2d07}}},
+ {0x10a8, {1|F|D, {0x2d08}}},
+ {0x10a9, {1|F|D, {0x2d09}}},
+ {0x10aa, {1|F|D, {0x2d0a}}},
+ {0x10ab, {1|F|D, {0x2d0b}}},
+ {0x10ac, {1|F|D, {0x2d0c}}},
+ {0x10ad, {1|F|D, {0x2d0d}}},
+ {0x10ae, {1|F|D, {0x2d0e}}},
+ {0x10af, {1|F|D, {0x2d0f}}},
+ {0x10b0, {1|F|D, {0x2d10}}},
+ {0x10b1, {1|F|D, {0x2d11}}},
+ {0x10b2, {1|F|D, {0x2d12}}},
+ {0x10b3, {1|F|D, {0x2d13}}},
+ {0x10b4, {1|F|D, {0x2d14}}},
+ {0x10b5, {1|F|D, {0x2d15}}},
+ {0x10b6, {1|F|D, {0x2d16}}},
+ {0x10b7, {1|F|D, {0x2d17}}},
+ {0x10b8, {1|F|D, {0x2d18}}},
+ {0x10b9, {1|F|D, {0x2d19}}},
+ {0x10ba, {1|F|D, {0x2d1a}}},
+ {0x10bb, {1|F|D, {0x2d1b}}},
+ {0x10bc, {1|F|D, {0x2d1c}}},
+ {0x10bd, {1|F|D, {0x2d1d}}},
+ {0x10be, {1|F|D, {0x2d1e}}},
+ {0x10bf, {1|F|D, {0x2d1f}}},
+ {0x10c0, {1|F|D, {0x2d20}}},
+ {0x10c1, {1|F|D, {0x2d21}}},
+ {0x10c2, {1|F|D, {0x2d22}}},
+ {0x10c3, {1|F|D, {0x2d23}}},
+ {0x10c4, {1|F|D, {0x2d24}}},
+ {0x10c5, {1|F|D, {0x2d25}}},
+ {0x10c7, {1|F|D, {0x2d27}}},
+ {0x10cd, {1|F|D, {0x2d2d}}},
+ {0x13f8, {1|F|U, {0x13f0}}},
+ {0x13f9, {1|F|U, {0x13f1}}},
+ {0x13fa, {1|F|U, {0x13f2}}},
+ {0x13fb, {1|F|U, {0x13f3}}},
+ {0x13fc, {1|F|U, {0x13f4}}},
+ {0x13fd, {1|F|U, {0x13f5}}},
+ {0x1c80, {1|F|SU|I(45), {0x0432}}},
+ {0x1c81, {1|F|SU|I(46), {0x0434}}},
+ {0x1c82, {1|F|SU|I(47), {0x043e}}},
+ {0x1c83, {1|F|SU|I(48), {0x0441}}},
+ {0x1c84, {1|F|SU|I(49), {0x0442}}},
+ {0x1c85, {1|F|SU|I(50), {0x0442}}},
+ {0x1c86, {1|F|SU|I(51), {0x044a}}},
+ {0x1c87, {1|F|SU|I(52), {0x0463}}},
+ {0x1c88, {1|F|SU|I(53), {0xa64b}}},
+ {0x1c89, {1|F|D, {0x1c8a}}},
+ {0x1c90, {1|F|D, {0x10d0}}},
+ {0x1c91, {1|F|D, {0x10d1}}},
+ {0x1c92, {1|F|D, {0x10d2}}},
+ {0x1c93, {1|F|D, {0x10d3}}},
+ {0x1c94, {1|F|D, {0x10d4}}},
+ {0x1c95, {1|F|D, {0x10d5}}},
+ {0x1c96, {1|F|D, {0x10d6}}},
+ {0x1c97, {1|F|D, {0x10d7}}},
+ {0x1c98, {1|F|D, {0x10d8}}},
+ {0x1c99, {1|F|D, {0x10d9}}},
+ {0x1c9a, {1|F|D, {0x10da}}},
+ {0x1c9b, {1|F|D, {0x10db}}},
+ {0x1c9c, {1|F|D, {0x10dc}}},
+ {0x1c9d, {1|F|D, {0x10dd}}},
+ {0x1c9e, {1|F|D, {0x10de}}},
+ {0x1c9f, {1|F|D, {0x10df}}},
+ {0x1ca0, {1|F|D, {0x10e0}}},
+ {0x1ca1, {1|F|D, {0x10e1}}},
+ {0x1ca2, {1|F|D, {0x10e2}}},
+ {0x1ca3, {1|F|D, {0x10e3}}},
+ {0x1ca4, {1|F|D, {0x10e4}}},
+ {0x1ca5, {1|F|D, {0x10e5}}},
+ {0x1ca6, {1|F|D, {0x10e6}}},
+ {0x1ca7, {1|F|D, {0x10e7}}},
+ {0x1ca8, {1|F|D, {0x10e8}}},
+ {0x1ca9, {1|F|D, {0x10e9}}},
+ {0x1caa, {1|F|D, {0x10ea}}},
+ {0x1cab, {1|F|D, {0x10eb}}},
+ {0x1cac, {1|F|D, {0x10ec}}},
+ {0x1cad, {1|F|D, {0x10ed}}},
+ {0x1cae, {1|F|D, {0x10ee}}},
+ {0x1caf, {1|F|D, {0x10ef}}},
+ {0x1cb0, {1|F|D, {0x10f0}}},
+ {0x1cb1, {1|F|D, {0x10f1}}},
+ {0x1cb2, {1|F|D, {0x10f2}}},
+ {0x1cb3, {1|F|D, {0x10f3}}},
+ {0x1cb4, {1|F|D, {0x10f4}}},
+ {0x1cb5, {1|F|D, {0x10f5}}},
+ {0x1cb6, {1|F|D, {0x10f6}}},
+ {0x1cb7, {1|F|D, {0x10f7}}},
+ {0x1cb8, {1|F|D, {0x10f8}}},
+ {0x1cb9, {1|F|D, {0x10f9}}},
+ {0x1cba, {1|F|D, {0x10fa}}},
+ {0x1cbd, {1|F|D, {0x10fd}}},
+ {0x1cbe, {1|F|D, {0x10fe}}},
+ {0x1cbf, {1|F|D, {0x10ff}}},
+ {0x1e00, {1|F|D, {0x1e01}}},
+ {0x1e02, {1|F|D, {0x1e03}}},
+ {0x1e04, {1|F|D, {0x1e05}}},
+ {0x1e06, {1|F|D, {0x1e07}}},
+ {0x1e08, {1|F|D, {0x1e09}}},
+ {0x1e0a, {1|F|D, {0x1e0b}}},
+ {0x1e0c, {1|F|D, {0x1e0d}}},
+ {0x1e0e, {1|F|D, {0x1e0f}}},
+ {0x1e10, {1|F|D, {0x1e11}}},
+ {0x1e12, {1|F|D, {0x1e13}}},
+ {0x1e14, {1|F|D, {0x1e15}}},
+ {0x1e16, {1|F|D, {0x1e17}}},
+ {0x1e18, {1|F|D, {0x1e19}}},
+ {0x1e1a, {1|F|D, {0x1e1b}}},
+ {0x1e1c, {1|F|D, {0x1e1d}}},
+ {0x1e1e, {1|F|D, {0x1e1f}}},
+ {0x1e20, {1|F|D, {0x1e21}}},
+ {0x1e22, {1|F|D, {0x1e23}}},
+ {0x1e24, {1|F|D, {0x1e25}}},
+ {0x1e26, {1|F|D, {0x1e27}}},
+ {0x1e28, {1|F|D, {0x1e29}}},
+ {0x1e2a, {1|F|D, {0x1e2b}}},
+ {0x1e2c, {1|F|D, {0x1e2d}}},
+ {0x1e2e, {1|F|D, {0x1e2f}}},
+ {0x1e30, {1|F|D, {0x1e31}}},
+ {0x1e32, {1|F|D, {0x1e33}}},
+ {0x1e34, {1|F|D, {0x1e35}}},
+ {0x1e36, {1|F|D, {0x1e37}}},
+ {0x1e38, {1|F|D, {0x1e39}}},
+ {0x1e3a, {1|F|D, {0x1e3b}}},
+ {0x1e3c, {1|F|D, {0x1e3d}}},
+ {0x1e3e, {1|F|D, {0x1e3f}}},
+ {0x1e40, {1|F|D, {0x1e41}}},
+ {0x1e42, {1|F|D, {0x1e43}}},
+ {0x1e44, {1|F|D, {0x1e45}}},
+ {0x1e46, {1|F|D, {0x1e47}}},
+ {0x1e48, {1|F|D, {0x1e49}}},
+ {0x1e4a, {1|F|D, {0x1e4b}}},
+ {0x1e4c, {1|F|D, {0x1e4d}}},
+ {0x1e4e, {1|F|D, {0x1e4f}}},
+ {0x1e50, {1|F|D, {0x1e51}}},
+ {0x1e52, {1|F|D, {0x1e53}}},
+ {0x1e54, {1|F|D, {0x1e55}}},
+ {0x1e56, {1|F|D, {0x1e57}}},
+ {0x1e58, {1|F|D, {0x1e59}}},
+ {0x1e5a, {1|F|D, {0x1e5b}}},
+ {0x1e5c, {1|F|D, {0x1e5d}}},
+ {0x1e5e, {1|F|D, {0x1e5f}}},
+ {0x1e60, {1|F|D, {0x1e61}}},
+ {0x1e62, {1|F|D, {0x1e63}}},
+ {0x1e64, {1|F|D, {0x1e65}}},
+ {0x1e66, {1|F|D, {0x1e67}}},
+ {0x1e68, {1|F|D, {0x1e69}}},
+ {0x1e6a, {1|F|D, {0x1e6b}}},
+ {0x1e6c, {1|F|D, {0x1e6d}}},
+ {0x1e6e, {1|F|D, {0x1e6f}}},
+ {0x1e70, {1|F|D, {0x1e71}}},
+ {0x1e72, {1|F|D, {0x1e73}}},
+ {0x1e74, {1|F|D, {0x1e75}}},
+ {0x1e76, {1|F|D, {0x1e77}}},
+ {0x1e78, {1|F|D, {0x1e79}}},
+ {0x1e7a, {1|F|D, {0x1e7b}}},
+ {0x1e7c, {1|F|D, {0x1e7d}}},
+ {0x1e7e, {1|F|D, {0x1e7f}}},
+ {0x1e80, {1|F|D, {0x1e81}}},
+ {0x1e82, {1|F|D, {0x1e83}}},
+ {0x1e84, {1|F|D, {0x1e85}}},
+ {0x1e86, {1|F|D, {0x1e87}}},
+ {0x1e88, {1|F|D, {0x1e89}}},
+ {0x1e8a, {1|F|D, {0x1e8b}}},
+ {0x1e8c, {1|F|D, {0x1e8d}}},
+ {0x1e8e, {1|F|D, {0x1e8f}}},
+ {0x1e90, {1|F|D, {0x1e91}}},
+ {0x1e92, {1|F|D, {0x1e93}}},
+ {0x1e94, {1|F|D, {0x1e95}}},
+ {0x1e96, {2|F|SU|I(54), {0x0068, 0x0331}}},
+ {0x1e97, {2|F|SU|I(56), {0x0074, 0x0308}}},
+ {0x1e98, {2|F|SU|I(58), {0x0077, 0x030a}}},
+ {0x1e99, {2|F|SU|I(60), {0x0079, 0x030a}}},
+ {0x1e9a, {2|F|SU|I(62), {0x0061, 0x02be}}},
+ {0x1e9b, {1|F|SU|I(64), {0x1e61}}},
+ {0x1e9e, {2|F|SL|I(65), {0x0073, 0x0073}}},
+ {0x1ea0, {1|F|D, {0x1ea1}}},
+ {0x1ea2, {1|F|D, {0x1ea3}}},
+ {0x1ea4, {1|F|D, {0x1ea5}}},
+ {0x1ea6, {1|F|D, {0x1ea7}}},
+ {0x1ea8, {1|F|D, {0x1ea9}}},
+ {0x1eaa, {1|F|D, {0x1eab}}},
+ {0x1eac, {1|F|D, {0x1ead}}},
+ {0x1eae, {1|F|D, {0x1eaf}}},
+ {0x1eb0, {1|F|D, {0x1eb1}}},
+ {0x1eb2, {1|F|D, {0x1eb3}}},
+ {0x1eb4, {1|F|D, {0x1eb5}}},
+ {0x1eb6, {1|F|D, {0x1eb7}}},
+ {0x1eb8, {1|F|D, {0x1eb9}}},
+ {0x1eba, {1|F|D, {0x1ebb}}},
+ {0x1ebc, {1|F|D, {0x1ebd}}},
+ {0x1ebe, {1|F|D, {0x1ebf}}},
+ {0x1ec0, {1|F|D, {0x1ec1}}},
+ {0x1ec2, {1|F|D, {0x1ec3}}},
+ {0x1ec4, {1|F|D, {0x1ec5}}},
+ {0x1ec6, {1|F|D, {0x1ec7}}},
+ {0x1ec8, {1|F|D, {0x1ec9}}},
+ {0x1eca, {1|F|D, {0x1ecb}}},
+ {0x1ecc, {1|F|D, {0x1ecd}}},
+ {0x1ece, {1|F|D, {0x1ecf}}},
+ {0x1ed0, {1|F|D, {0x1ed1}}},
+ {0x1ed2, {1|F|D, {0x1ed3}}},
+ {0x1ed4, {1|F|D, {0x1ed5}}},
+ {0x1ed6, {1|F|D, {0x1ed7}}},
+ {0x1ed8, {1|F|D, {0x1ed9}}},
+ {0x1eda, {1|F|D, {0x1edb}}},
+ {0x1edc, {1|F|D, {0x1edd}}},
+ {0x1ede, {1|F|D, {0x1edf}}},
+ {0x1ee0, {1|F|D, {0x1ee1}}},
+ {0x1ee2, {1|F|D, {0x1ee3}}},
+ {0x1ee4, {1|F|D, {0x1ee5}}},
+ {0x1ee6, {1|F|D, {0x1ee7}}},
+ {0x1ee8, {1|F|D, {0x1ee9}}},
+ {0x1eea, {1|F|D, {0x1eeb}}},
+ {0x1eec, {1|F|D, {0x1eed}}},
+ {0x1eee, {1|F|D, {0x1eef}}},
+ {0x1ef0, {1|F|D, {0x1ef1}}},
+ {0x1ef2, {1|F|D, {0x1ef3}}},
+ {0x1ef4, {1|F|D, {0x1ef5}}},
+ {0x1ef6, {1|F|D, {0x1ef7}}},
+ {0x1ef8, {1|F|D, {0x1ef9}}},
+ {0x1efa, {1|F|D, {0x1efb}}},
+ {0x1efc, {1|F|D, {0x1efd}}},
+ {0x1efe, {1|F|D, {0x1eff}}},
+ {0x1f08, {1|F|D, {0x1f00}}},
+ {0x1f09, {1|F|D, {0x1f01}}},
+ {0x1f0a, {1|F|D, {0x1f02}}},
+ {0x1f0b, {1|F|D, {0x1f03}}},
+ {0x1f0c, {1|F|D, {0x1f04}}},
+ {0x1f0d, {1|F|D, {0x1f05}}},
+ {0x1f0e, {1|F|D, {0x1f06}}},
+ {0x1f0f, {1|F|D, {0x1f07}}},
+ {0x1f18, {1|F|D, {0x1f10}}},
+ {0x1f19, {1|F|D, {0x1f11}}},
+ {0x1f1a, {1|F|D, {0x1f12}}},
+ {0x1f1b, {1|F|D, {0x1f13}}},
+ {0x1f1c, {1|F|D, {0x1f14}}},
+ {0x1f1d, {1|F|D, {0x1f15}}},
+ {0x1f28, {1|F|D, {0x1f20}}},
+ {0x1f29, {1|F|D, {0x1f21}}},
+ {0x1f2a, {1|F|D, {0x1f22}}},
+ {0x1f2b, {1|F|D, {0x1f23}}},
+ {0x1f2c, {1|F|D, {0x1f24}}},
+ {0x1f2d, {1|F|D, {0x1f25}}},
+ {0x1f2e, {1|F|D, {0x1f26}}},
+ {0x1f2f, {1|F|D, {0x1f27}}},
+ {0x1f38, {1|F|D, {0x1f30}}},
+ {0x1f39, {1|F|D, {0x1f31}}},
+ {0x1f3a, {1|F|D, {0x1f32}}},
+ {0x1f3b, {1|F|D, {0x1f33}}},
+ {0x1f3c, {1|F|D, {0x1f34}}},
+ {0x1f3d, {1|F|D, {0x1f35}}},
+ {0x1f3e, {1|F|D, {0x1f36}}},
+ {0x1f3f, {1|F|D, {0x1f37}}},
+ {0x1f48, {1|F|D, {0x1f40}}},
+ {0x1f49, {1|F|D, {0x1f41}}},
+ {0x1f4a, {1|F|D, {0x1f42}}},
+ {0x1f4b, {1|F|D, {0x1f43}}},
+ {0x1f4c, {1|F|D, {0x1f44}}},
+ {0x1f4d, {1|F|D, {0x1f45}}},
+ {0x1f50, {2|F|SU|I(66), {0x03c5, 0x0313}}},
+ {0x1f52, {3|F|SU|I(68), {0x03c5, 0x0313, 0x0300}}},
+ {0x1f54, {3|F|SU|I(71), {0x03c5, 0x0313, 0x0301}}},
+ {0x1f56, {3|F|SU|I(74), {0x03c5, 0x0313, 0x0342}}},
+ {0x1f59, {1|F|D, {0x1f51}}},
+ {0x1f5b, {1|F|D, {0x1f53}}},
+ {0x1f5d, {1|F|D, {0x1f55}}},
+ {0x1f5f, {1|F|D, {0x1f57}}},
+ {0x1f68, {1|F|D, {0x1f60}}},
+ {0x1f69, {1|F|D, {0x1f61}}},
+ {0x1f6a, {1|F|D, {0x1f62}}},
+ {0x1f6b, {1|F|D, {0x1f63}}},
+ {0x1f6c, {1|F|D, {0x1f64}}},
+ {0x1f6d, {1|F|D, {0x1f65}}},
+ {0x1f6e, {1|F|D, {0x1f66}}},
+ {0x1f6f, {1|F|D, {0x1f67}}},
+ {0x1f80, {2|F|ST|SU|I(77), {0x1f00, 0x03b9}}},
+ {0x1f81, {2|F|ST|SU|I(80), {0x1f01, 0x03b9}}},
+ {0x1f82, {2|F|ST|SU|I(83), {0x1f02, 0x03b9}}},
+ {0x1f83, {2|F|ST|SU|I(86), {0x1f03, 0x03b9}}},
+ {0x1f84, {2|F|ST|SU|I(89), {0x1f04, 0x03b9}}},
+ {0x1f85, {2|F|ST|SU|I(92), {0x1f05, 0x03b9}}},
+ {0x1f86, {2|F|ST|SU|I(95), {0x1f06, 0x03b9}}},
+ {0x1f87, {2|F|ST|SU|I(98), {0x1f07, 0x03b9}}},
+ {0x1f88, {2|F|IT|SL|SU|I(101), {0x1f00, 0x03b9}}},
+ {0x1f89, {2|F|IT|SL|SU|I(106), {0x1f01, 0x03b9}}},
+ {0x1f8a, {2|F|IT|SL|SU|I(111), {0x1f02, 0x03b9}}},
+ {0x1f8b, {2|F|IT|SL|SU|I(116), {0x1f03, 0x03b9}}},
+ {0x1f8c, {2|F|IT|SL|SU|I(121), {0x1f04, 0x03b9}}},
+ {0x1f8d, {2|F|IT|SL|SU|I(126), {0x1f05, 0x03b9}}},
+ {0x1f8e, {2|F|IT|SL|SU|I(131), {0x1f06, 0x03b9}}},
+ {0x1f8f, {2|F|IT|SL|SU|I(136), {0x1f07, 0x03b9}}},
+ {0x1f90, {2|F|ST|SU|I(141), {0x1f20, 0x03b9}}},
+ {0x1f91, {2|F|ST|SU|I(144), {0x1f21, 0x03b9}}},
+ {0x1f92, {2|F|ST|SU|I(147), {0x1f22, 0x03b9}}},
+ {0x1f93, {2|F|ST|SU|I(150), {0x1f23, 0x03b9}}},
+ {0x1f94, {2|F|ST|SU|I(153), {0x1f24, 0x03b9}}},
+ {0x1f95, {2|F|ST|SU|I(156), {0x1f25, 0x03b9}}},
+ {0x1f96, {2|F|ST|SU|I(159), {0x1f26, 0x03b9}}},
+ {0x1f97, {2|F|ST|SU|I(162), {0x1f27, 0x03b9}}},
+ {0x1f98, {2|F|IT|SL|SU|I(165), {0x1f20, 0x03b9}}},
+ {0x1f99, {2|F|IT|SL|SU|I(170), {0x1f21, 0x03b9}}},
+ {0x1f9a, {2|F|IT|SL|SU|I(175), {0x1f22, 0x03b9}}},
+ {0x1f9b, {2|F|IT|SL|SU|I(180), {0x1f23, 0x03b9}}},
+ {0x1f9c, {2|F|IT|SL|SU|I(185), {0x1f24, 0x03b9}}},
+ {0x1f9d, {2|F|IT|SL|SU|I(190), {0x1f25, 0x03b9}}},
+ {0x1f9e, {2|F|IT|SL|SU|I(195), {0x1f26, 0x03b9}}},
+ {0x1f9f, {2|F|IT|SL|SU|I(200), {0x1f27, 0x03b9}}},
+ {0x1fa0, {2|F|ST|SU|I(205), {0x1f60, 0x03b9}}},
+ {0x1fa1, {2|F|ST|SU|I(208), {0x1f61, 0x03b9}}},
+ {0x1fa2, {2|F|ST|SU|I(211), {0x1f62, 0x03b9}}},
+ {0x1fa3, {2|F|ST|SU|I(214), {0x1f63, 0x03b9}}},
+ {0x1fa4, {2|F|ST|SU|I(217), {0x1f64, 0x03b9}}},
+ {0x1fa5, {2|F|ST|SU|I(220), {0x1f65, 0x03b9}}},
+ {0x1fa6, {2|F|ST|SU|I(223), {0x1f66, 0x03b9}}},
+ {0x1fa7, {2|F|ST|SU|I(226), {0x1f67, 0x03b9}}},
+ {0x1fa8, {2|F|IT|SL|SU|I(229), {0x1f60, 0x03b9}}},
+ {0x1fa9, {2|F|IT|SL|SU|I(234), {0x1f61, 0x03b9}}},
+ {0x1faa, {2|F|IT|SL|SU|I(239), {0x1f62, 0x03b9}}},
+ {0x1fab, {2|F|IT|SL|SU|I(244), {0x1f63, 0x03b9}}},
+ {0x1fac, {2|F|IT|SL|SU|I(249), {0x1f64, 0x03b9}}},
+ {0x1fad, {2|F|IT|SL|SU|I(254), {0x1f65, 0x03b9}}},
+ {0x1fae, {2|F|IT|SL|SU|I(259), {0x1f66, 0x03b9}}},
+ {0x1faf, {2|F|IT|SL|SU|I(264), {0x1f67, 0x03b9}}},
+ {0x1fb2, {2|F|ST|SU|I(269), {0x1f70, 0x03b9}}},
+ {0x1fb3, {2|F|ST|SU|I(273), {0x03b1, 0x03b9}}},
+ {0x1fb4, {2|F|ST|SU|I(276), {0x03ac, 0x03b9}}},
+ {0x1fb6, {2|F|SU|I(280), {0x03b1, 0x0342}}},
+ {0x1fb7, {3|F|ST|SU|I(282), {0x03b1, 0x0342, 0x03b9}}},
+ {0x1fb8, {1|F|D, {0x1fb0}}},
+ {0x1fb9, {1|F|D, {0x1fb1}}},
+ {0x1fba, {1|F|D, {0x1f70}}},
+ {0x1fbb, {1|F|D, {0x1f71}}},
+ {0x1fbc, {2|F|IT|SL|SU|I(288), {0x03b1, 0x03b9}}},
+ {0x1fbe, {1|F|SU|I(293), {0x03b9}}},
+ {0x1fc2, {2|F|ST|SU|I(294), {0x1f74, 0x03b9}}},
+ {0x1fc3, {2|F|ST|SU|I(298), {0x03b7, 0x03b9}}},
+ {0x1fc4, {2|F|ST|SU|I(301), {0x03ae, 0x03b9}}},
+ {0x1fc6, {2|F|SU|I(305), {0x03b7, 0x0342}}},
+ {0x1fc7, {3|F|ST|SU|I(307), {0x03b7, 0x0342, 0x03b9}}},
+ {0x1fc8, {1|F|D, {0x1f72}}},
+ {0x1fc9, {1|F|D, {0x1f73}}},
+ {0x1fca, {1|F|D, {0x1f74}}},
+ {0x1fcb, {1|F|D, {0x1f75}}},
+ {0x1fcc, {2|F|IT|SL|SU|I(313), {0x03b7, 0x03b9}}},
+ {0x1fd2, {3|F|SU|I(318), {0x03b9, 0x0308, 0x0300}}},
+ {0x1fd3, {3|F|SU|I(321), {0x03b9, 0x0308, 0x0301}}},
+ {0x1fd6, {2|F|SU|I(324), {0x03b9, 0x0342}}},
+ {0x1fd7, {3|F|SU|I(326), {0x03b9, 0x0308, 0x0342}}},
+ {0x1fd8, {1|F|D, {0x1fd0}}},
+ {0x1fd9, {1|F|D, {0x1fd1}}},
+ {0x1fda, {1|F|D, {0x1f76}}},
+ {0x1fdb, {1|F|D, {0x1f77}}},
+ {0x1fe2, {3|F|SU|I(329), {0x03c5, 0x0308, 0x0300}}},
+ {0x1fe3, {3|F|SU|I(332), {0x03c5, 0x0308, 0x0301}}},
+ {0x1fe4, {2|F|SU|I(335), {0x03c1, 0x0313}}},
+ {0x1fe6, {2|F|SU|I(337), {0x03c5, 0x0342}}},
+ {0x1fe7, {3|F|SU|I(339), {0x03c5, 0x0308, 0x0342}}},
+ {0x1fe8, {1|F|D, {0x1fe0}}},
+ {0x1fe9, {1|F|D, {0x1fe1}}},
+ {0x1fea, {1|F|D, {0x1f7a}}},
+ {0x1feb, {1|F|D, {0x1f7b}}},
+ {0x1fec, {1|F|D, {0x1fe5}}},
+ {0x1ff2, {2|F|ST|SU|I(342), {0x1f7c, 0x03b9}}},
+ {0x1ff3, {2|F|ST|SU|I(346), {0x03c9, 0x03b9}}},
+ {0x1ff4, {2|F|ST|SU|I(349), {0x03ce, 0x03b9}}},
+ {0x1ff6, {2|F|SU|I(353), {0x03c9, 0x0342}}},
+ {0x1ff7, {3|F|ST|SU|I(355), {0x03c9, 0x0342, 0x03b9}}},
+ {0x1ff8, {1|F|D, {0x1f78}}},
+ {0x1ff9, {1|F|D, {0x1f79}}},
+ {0x1ffa, {1|F|D, {0x1f7c}}},
+ {0x1ffb, {1|F|D, {0x1f7d}}},
+ {0x1ffc, {2|F|IT|SL|SU|I(361), {0x03c9, 0x03b9}}},
+ {0x2126, {1|F|D, {0x03c9}}},
+ {0x212a, {1|F|D, {0x006b}}},
+ {0x212b, {1|F|D, {0x00e5}}},
+ {0x2132, {1|F|D, {0x214e}}},
+ {0x2160, {1|F|D, {0x2170}}},
+ {0x2161, {1|F|D, {0x2171}}},
+ {0x2162, {1|F|D, {0x2172}}},
+ {0x2163, {1|F|D, {0x2173}}},
+ {0x2164, {1|F|D, {0x2174}}},
+ {0x2165, {1|F|D, {0x2175}}},
+ {0x2166, {1|F|D, {0x2176}}},
+ {0x2167, {1|F|D, {0x2177}}},
+ {0x2168, {1|F|D, {0x2178}}},
+ {0x2169, {1|F|D, {0x2179}}},
+ {0x216a, {1|F|D, {0x217a}}},
+ {0x216b, {1|F|D, {0x217b}}},
+ {0x216c, {1|F|D, {0x217c}}},
+ {0x216d, {1|F|D, {0x217d}}},
+ {0x216e, {1|F|D, {0x217e}}},
+ {0x216f, {1|F|D, {0x217f}}},
+ {0x2183, {1|F|D, {0x2184}}},
+ {0x24b6, {1|F|D, {0x24d0}}},
+ {0x24b7, {1|F|D, {0x24d1}}},
+ {0x24b8, {1|F|D, {0x24d2}}},
+ {0x24b9, {1|F|D, {0x24d3}}},
+ {0x24ba, {1|F|D, {0x24d4}}},
+ {0x24bb, {1|F|D, {0x24d5}}},
+ {0x24bc, {1|F|D, {0x24d6}}},
+ {0x24bd, {1|F|D, {0x24d7}}},
+ {0x24be, {1|F|D, {0x24d8}}},
+ {0x24bf, {1|F|D, {0x24d9}}},
+ {0x24c0, {1|F|D, {0x24da}}},
+ {0x24c1, {1|F|D, {0x24db}}},
+ {0x24c2, {1|F|D, {0x24dc}}},
+ {0x24c3, {1|F|D, {0x24dd}}},
+ {0x24c4, {1|F|D, {0x24de}}},
+ {0x24c5, {1|F|D, {0x24df}}},
+ {0x24c6, {1|F|D, {0x24e0}}},
+ {0x24c7, {1|F|D, {0x24e1}}},
+ {0x24c8, {1|F|D, {0x24e2}}},
+ {0x24c9, {1|F|D, {0x24e3}}},
+ {0x24ca, {1|F|D, {0x24e4}}},
+ {0x24cb, {1|F|D, {0x24e5}}},
+ {0x24cc, {1|F|D, {0x24e6}}},
+ {0x24cd, {1|F|D, {0x24e7}}},
+ {0x24ce, {1|F|D, {0x24e8}}},
+ {0x24cf, {1|F|D, {0x24e9}}},
+ {0x2c00, {1|F|D, {0x2c30}}},
+ {0x2c01, {1|F|D, {0x2c31}}},
+ {0x2c02, {1|F|D, {0x2c32}}},
+ {0x2c03, {1|F|D, {0x2c33}}},
+ {0x2c04, {1|F|D, {0x2c34}}},
+ {0x2c05, {1|F|D, {0x2c35}}},
+ {0x2c06, {1|F|D, {0x2c36}}},
+ {0x2c07, {1|F|D, {0x2c37}}},
+ {0x2c08, {1|F|D, {0x2c38}}},
+ {0x2c09, {1|F|D, {0x2c39}}},
+ {0x2c0a, {1|F|D, {0x2c3a}}},
+ {0x2c0b, {1|F|D, {0x2c3b}}},
+ {0x2c0c, {1|F|D, {0x2c3c}}},
+ {0x2c0d, {1|F|D, {0x2c3d}}},
+ {0x2c0e, {1|F|D, {0x2c3e}}},
+ {0x2c0f, {1|F|D, {0x2c3f}}},
+ {0x2c10, {1|F|D, {0x2c40}}},
+ {0x2c11, {1|F|D, {0x2c41}}},
+ {0x2c12, {1|F|D, {0x2c42}}},
+ {0x2c13, {1|F|D, {0x2c43}}},
+ {0x2c14, {1|F|D, {0x2c44}}},
+ {0x2c15, {1|F|D, {0x2c45}}},
+ {0x2c16, {1|F|D, {0x2c46}}},
+ {0x2c17, {1|F|D, {0x2c47}}},
+ {0x2c18, {1|F|D, {0x2c48}}},
+ {0x2c19, {1|F|D, {0x2c49}}},
+ {0x2c1a, {1|F|D, {0x2c4a}}},
+ {0x2c1b, {1|F|D, {0x2c4b}}},
+ {0x2c1c, {1|F|D, {0x2c4c}}},
+ {0x2c1d, {1|F|D, {0x2c4d}}},
+ {0x2c1e, {1|F|D, {0x2c4e}}},
+ {0x2c1f, {1|F|D, {0x2c4f}}},
+ {0x2c20, {1|F|D, {0x2c50}}},
+ {0x2c21, {1|F|D, {0x2c51}}},
+ {0x2c22, {1|F|D, {0x2c52}}},
+ {0x2c23, {1|F|D, {0x2c53}}},
+ {0x2c24, {1|F|D, {0x2c54}}},
+ {0x2c25, {1|F|D, {0x2c55}}},
+ {0x2c26, {1|F|D, {0x2c56}}},
+ {0x2c27, {1|F|D, {0x2c57}}},
+ {0x2c28, {1|F|D, {0x2c58}}},
+ {0x2c29, {1|F|D, {0x2c59}}},
+ {0x2c2a, {1|F|D, {0x2c5a}}},
+ {0x2c2b, {1|F|D, {0x2c5b}}},
+ {0x2c2c, {1|F|D, {0x2c5c}}},
+ {0x2c2d, {1|F|D, {0x2c5d}}},
+ {0x2c2e, {1|F|D, {0x2c5e}}},
+ {0x2c2f, {1|F|D, {0x2c5f}}},
+ {0x2c60, {1|F|D, {0x2c61}}},
+ {0x2c62, {1|F|D, {0x026b}}},
+ {0x2c63, {1|F|D, {0x1d7d}}},
+ {0x2c64, {1|F|D, {0x027d}}},
+ {0x2c67, {1|F|D, {0x2c68}}},
+ {0x2c69, {1|F|D, {0x2c6a}}},
+ {0x2c6b, {1|F|D, {0x2c6c}}},
+ {0x2c6d, {1|F|D, {0x0251}}},
+ {0x2c6e, {1|F|D, {0x0271}}},
+ {0x2c6f, {1|F|D, {0x0250}}},
+ {0x2c70, {1|F|D, {0x0252}}},
+ {0x2c72, {1|F|D, {0x2c73}}},
+ {0x2c75, {1|F|D, {0x2c76}}},
+ {0x2c7e, {1|F|D, {0x023f}}},
+ {0x2c7f, {1|F|D, {0x0240}}},
+ {0x2c80, {1|F|D, {0x2c81}}},
+ {0x2c82, {1|F|D, {0x2c83}}},
+ {0x2c84, {1|F|D, {0x2c85}}},
+ {0x2c86, {1|F|D, {0x2c87}}},
+ {0x2c88, {1|F|D, {0x2c89}}},
+ {0x2c8a, {1|F|D, {0x2c8b}}},
+ {0x2c8c, {1|F|D, {0x2c8d}}},
+ {0x2c8e, {1|F|D, {0x2c8f}}},
+ {0x2c90, {1|F|D, {0x2c91}}},
+ {0x2c92, {1|F|D, {0x2c93}}},
+ {0x2c94, {1|F|D, {0x2c95}}},
+ {0x2c96, {1|F|D, {0x2c97}}},
+ {0x2c98, {1|F|D, {0x2c99}}},
+ {0x2c9a, {1|F|D, {0x2c9b}}},
+ {0x2c9c, {1|F|D, {0x2c9d}}},
+ {0x2c9e, {1|F|D, {0x2c9f}}},
+ {0x2ca0, {1|F|D, {0x2ca1}}},
+ {0x2ca2, {1|F|D, {0x2ca3}}},
+ {0x2ca4, {1|F|D, {0x2ca5}}},
+ {0x2ca6, {1|F|D, {0x2ca7}}},
+ {0x2ca8, {1|F|D, {0x2ca9}}},
+ {0x2caa, {1|F|D, {0x2cab}}},
+ {0x2cac, {1|F|D, {0x2cad}}},
+ {0x2cae, {1|F|D, {0x2caf}}},
+ {0x2cb0, {1|F|D, {0x2cb1}}},
+ {0x2cb2, {1|F|D, {0x2cb3}}},
+ {0x2cb4, {1|F|D, {0x2cb5}}},
+ {0x2cb6, {1|F|D, {0x2cb7}}},
+ {0x2cb8, {1|F|D, {0x2cb9}}},
+ {0x2cba, {1|F|D, {0x2cbb}}},
+ {0x2cbc, {1|F|D, {0x2cbd}}},
+ {0x2cbe, {1|F|D, {0x2cbf}}},
+ {0x2cc0, {1|F|D, {0x2cc1}}},
+ {0x2cc2, {1|F|D, {0x2cc3}}},
+ {0x2cc4, {1|F|D, {0x2cc5}}},
+ {0x2cc6, {1|F|D, {0x2cc7}}},
+ {0x2cc8, {1|F|D, {0x2cc9}}},
+ {0x2cca, {1|F|D, {0x2ccb}}},
+ {0x2ccc, {1|F|D, {0x2ccd}}},
+ {0x2cce, {1|F|D, {0x2ccf}}},
+ {0x2cd0, {1|F|D, {0x2cd1}}},
+ {0x2cd2, {1|F|D, {0x2cd3}}},
+ {0x2cd4, {1|F|D, {0x2cd5}}},
+ {0x2cd6, {1|F|D, {0x2cd7}}},
+ {0x2cd8, {1|F|D, {0x2cd9}}},
+ {0x2cda, {1|F|D, {0x2cdb}}},
+ {0x2cdc, {1|F|D, {0x2cdd}}},
+ {0x2cde, {1|F|D, {0x2cdf}}},
+ {0x2ce0, {1|F|D, {0x2ce1}}},
+ {0x2ce2, {1|F|D, {0x2ce3}}},
+ {0x2ceb, {1|F|D, {0x2cec}}},
+ {0x2ced, {1|F|D, {0x2cee}}},
+ {0x2cf2, {1|F|D, {0x2cf3}}},
+ {0xa640, {1|F|D, {0xa641}}},
+ {0xa642, {1|F|D, {0xa643}}},
+ {0xa644, {1|F|D, {0xa645}}},
+ {0xa646, {1|F|D, {0xa647}}},
+ {0xa648, {1|F|D, {0xa649}}},
+ {0xa64a, {1|F|D, {0xa64b}}},
+ {0xa64c, {1|F|D, {0xa64d}}},
+ {0xa64e, {1|F|D, {0xa64f}}},
+ {0xa650, {1|F|D, {0xa651}}},
+ {0xa652, {1|F|D, {0xa653}}},
+ {0xa654, {1|F|D, {0xa655}}},
+ {0xa656, {1|F|D, {0xa657}}},
+ {0xa658, {1|F|D, {0xa659}}},
+ {0xa65a, {1|F|D, {0xa65b}}},
+ {0xa65c, {1|F|D, {0xa65d}}},
+ {0xa65e, {1|F|D, {0xa65f}}},
+ {0xa660, {1|F|D, {0xa661}}},
+ {0xa662, {1|F|D, {0xa663}}},
+ {0xa664, {1|F|D, {0xa665}}},
+ {0xa666, {1|F|D, {0xa667}}},
+ {0xa668, {1|F|D, {0xa669}}},
+ {0xa66a, {1|F|D, {0xa66b}}},
+ {0xa66c, {1|F|D, {0xa66d}}},
+ {0xa680, {1|F|D, {0xa681}}},
+ {0xa682, {1|F|D, {0xa683}}},
+ {0xa684, {1|F|D, {0xa685}}},
+ {0xa686, {1|F|D, {0xa687}}},
+ {0xa688, {1|F|D, {0xa689}}},
+ {0xa68a, {1|F|D, {0xa68b}}},
+ {0xa68c, {1|F|D, {0xa68d}}},
+ {0xa68e, {1|F|D, {0xa68f}}},
+ {0xa690, {1|F|D, {0xa691}}},
+ {0xa692, {1|F|D, {0xa693}}},
+ {0xa694, {1|F|D, {0xa695}}},
+ {0xa696, {1|F|D, {0xa697}}},
+ {0xa698, {1|F|D, {0xa699}}},
+ {0xa69a, {1|F|D, {0xa69b}}},
+ {0xa722, {1|F|D, {0xa723}}},
+ {0xa724, {1|F|D, {0xa725}}},
+ {0xa726, {1|F|D, {0xa727}}},
+ {0xa728, {1|F|D, {0xa729}}},
+ {0xa72a, {1|F|D, {0xa72b}}},
+ {0xa72c, {1|F|D, {0xa72d}}},
+ {0xa72e, {1|F|D, {0xa72f}}},
+ {0xa732, {1|F|D, {0xa733}}},
+ {0xa734, {1|F|D, {0xa735}}},
+ {0xa736, {1|F|D, {0xa737}}},
+ {0xa738, {1|F|D, {0xa739}}},
+ {0xa73a, {1|F|D, {0xa73b}}},
+ {0xa73c, {1|F|D, {0xa73d}}},
+ {0xa73e, {1|F|D, {0xa73f}}},
+ {0xa740, {1|F|D, {0xa741}}},
+ {0xa742, {1|F|D, {0xa743}}},
+ {0xa744, {1|F|D, {0xa745}}},
+ {0xa746, {1|F|D, {0xa747}}},
+ {0xa748, {1|F|D, {0xa749}}},
+ {0xa74a, {1|F|D, {0xa74b}}},
+ {0xa74c, {1|F|D, {0xa74d}}},
+ {0xa74e, {1|F|D, {0xa74f}}},
+ {0xa750, {1|F|D, {0xa751}}},
+ {0xa752, {1|F|D, {0xa753}}},
+ {0xa754, {1|F|D, {0xa755}}},
+ {0xa756, {1|F|D, {0xa757}}},
+ {0xa758, {1|F|D, {0xa759}}},
+ {0xa75a, {1|F|D, {0xa75b}}},
+ {0xa75c, {1|F|D, {0xa75d}}},
+ {0xa75e, {1|F|D, {0xa75f}}},
+ {0xa760, {1|F|D, {0xa761}}},
+ {0xa762, {1|F|D, {0xa763}}},
+ {0xa764, {1|F|D, {0xa765}}},
+ {0xa766, {1|F|D, {0xa767}}},
+ {0xa768, {1|F|D, {0xa769}}},
+ {0xa76a, {1|F|D, {0xa76b}}},
+ {0xa76c, {1|F|D, {0xa76d}}},
+ {0xa76e, {1|F|D, {0xa76f}}},
+ {0xa779, {1|F|D, {0xa77a}}},
+ {0xa77b, {1|F|D, {0xa77c}}},
+ {0xa77d, {1|F|D, {0x1d79}}},
+ {0xa77e, {1|F|D, {0xa77f}}},
+ {0xa780, {1|F|D, {0xa781}}},
+ {0xa782, {1|F|D, {0xa783}}},
+ {0xa784, {1|F|D, {0xa785}}},
+ {0xa786, {1|F|D, {0xa787}}},
+ {0xa78b, {1|F|D, {0xa78c}}},
+ {0xa78d, {1|F|D, {0x0265}}},
+ {0xa790, {1|F|D, {0xa791}}},
+ {0xa792, {1|F|D, {0xa793}}},
+ {0xa796, {1|F|D, {0xa797}}},
+ {0xa798, {1|F|D, {0xa799}}},
+ {0xa79a, {1|F|D, {0xa79b}}},
+ {0xa79c, {1|F|D, {0xa79d}}},
+ {0xa79e, {1|F|D, {0xa79f}}},
+ {0xa7a0, {1|F|D, {0xa7a1}}},
+ {0xa7a2, {1|F|D, {0xa7a3}}},
+ {0xa7a4, {1|F|D, {0xa7a5}}},
+ {0xa7a6, {1|F|D, {0xa7a7}}},
+ {0xa7a8, {1|F|D, {0xa7a9}}},
+ {0xa7aa, {1|F|D, {0x0266}}},
+ {0xa7ab, {1|F|D, {0x025c}}},
+ {0xa7ac, {1|F|D, {0x0261}}},
+ {0xa7ad, {1|F|D, {0x026c}}},
+ {0xa7ae, {1|F|D, {0x026a}}},
+ {0xa7b0, {1|F|D, {0x029e}}},
+ {0xa7b1, {1|F|D, {0x0287}}},
+ {0xa7b2, {1|F|D, {0x029d}}},
+ {0xa7b3, {1|F|D, {0xab53}}},
+ {0xa7b4, {1|F|D, {0xa7b5}}},
+ {0xa7b6, {1|F|D, {0xa7b7}}},
+ {0xa7b8, {1|F|D, {0xa7b9}}},
+ {0xa7ba, {1|F|D, {0xa7bb}}},
+ {0xa7bc, {1|F|D, {0xa7bd}}},
+ {0xa7be, {1|F|D, {0xa7bf}}},
+ {0xa7c0, {1|F|D, {0xa7c1}}},
+ {0xa7c2, {1|F|D, {0xa7c3}}},
+ {0xa7c4, {1|F|D, {0xa794}}},
+ {0xa7c5, {1|F|D, {0x0282}}},
+ {0xa7c6, {1|F|D, {0x1d8e}}},
+ {0xa7c7, {1|F|D, {0xa7c8}}},
+ {0xa7c9, {1|F|D, {0xa7ca}}},
+ {0xa7cb, {1|F|D, {0x0264}}},
+ {0xa7cc, {1|F|D, {0xa7cd}}},
+ {0xa7ce, {1|F|D, {0xa7cf}}},
+ {0xa7d0, {1|F|D, {0xa7d1}}},
+ {0xa7d2, {1|F|D, {0xa7d3}}},
+ {0xa7d4, {1|F|D, {0xa7d5}}},
+ {0xa7d6, {1|F|D, {0xa7d7}}},
+ {0xa7d8, {1|F|D, {0xa7d9}}},
+ {0xa7da, {1|F|D, {0xa7db}}},
+ {0xa7dc, {1|F|D, {0x019b}}},
+ {0xa7f5, {1|F|D, {0xa7f6}}},
+ {0xab70, {1|F|U, {0x13a0}}},
+ {0xab71, {1|F|U, {0x13a1}}},
+ {0xab72, {1|F|U, {0x13a2}}},
+ {0xab73, {1|F|U, {0x13a3}}},
+ {0xab74, {1|F|U, {0x13a4}}},
+ {0xab75, {1|F|U, {0x13a5}}},
+ {0xab76, {1|F|U, {0x13a6}}},
+ {0xab77, {1|F|U, {0x13a7}}},
+ {0xab78, {1|F|U, {0x13a8}}},
+ {0xab79, {1|F|U, {0x13a9}}},
+ {0xab7a, {1|F|U, {0x13aa}}},
+ {0xab7b, {1|F|U, {0x13ab}}},
+ {0xab7c, {1|F|U, {0x13ac}}},
+ {0xab7d, {1|F|U, {0x13ad}}},
+ {0xab7e, {1|F|U, {0x13ae}}},
+ {0xab7f, {1|F|U, {0x13af}}},
+ {0xab80, {1|F|U, {0x13b0}}},
+ {0xab81, {1|F|U, {0x13b1}}},
+ {0xab82, {1|F|U, {0x13b2}}},
+ {0xab83, {1|F|U, {0x13b3}}},
+ {0xab84, {1|F|U, {0x13b4}}},
+ {0xab85, {1|F|U, {0x13b5}}},
+ {0xab86, {1|F|U, {0x13b6}}},
+ {0xab87, {1|F|U, {0x13b7}}},
+ {0xab88, {1|F|U, {0x13b8}}},
+ {0xab89, {1|F|U, {0x13b9}}},
+ {0xab8a, {1|F|U, {0x13ba}}},
+ {0xab8b, {1|F|U, {0x13bb}}},
+ {0xab8c, {1|F|U, {0x13bc}}},
+ {0xab8d, {1|F|U, {0x13bd}}},
+ {0xab8e, {1|F|U, {0x13be}}},
+ {0xab8f, {1|F|U, {0x13bf}}},
+ {0xab90, {1|F|U, {0x13c0}}},
+ {0xab91, {1|F|U, {0x13c1}}},
+ {0xab92, {1|F|U, {0x13c2}}},
+ {0xab93, {1|F|U, {0x13c3}}},
+ {0xab94, {1|F|U, {0x13c4}}},
+ {0xab95, {1|F|U, {0x13c5}}},
+ {0xab96, {1|F|U, {0x13c6}}},
+ {0xab97, {1|F|U, {0x13c7}}},
+ {0xab98, {1|F|U, {0x13c8}}},
+ {0xab99, {1|F|U, {0x13c9}}},
+ {0xab9a, {1|F|U, {0x13ca}}},
+ {0xab9b, {1|F|U, {0x13cb}}},
+ {0xab9c, {1|F|U, {0x13cc}}},
+ {0xab9d, {1|F|U, {0x13cd}}},
+ {0xab9e, {1|F|U, {0x13ce}}},
+ {0xab9f, {1|F|U, {0x13cf}}},
+ {0xaba0, {1|F|U, {0x13d0}}},
+ {0xaba1, {1|F|U, {0x13d1}}},
+ {0xaba2, {1|F|U, {0x13d2}}},
+ {0xaba3, {1|F|U, {0x13d3}}},
+ {0xaba4, {1|F|U, {0x13d4}}},
+ {0xaba5, {1|F|U, {0x13d5}}},
+ {0xaba6, {1|F|U, {0x13d6}}},
+ {0xaba7, {1|F|U, {0x13d7}}},
+ {0xaba8, {1|F|U, {0x13d8}}},
+ {0xaba9, {1|F|U, {0x13d9}}},
+ {0xabaa, {1|F|U, {0x13da}}},
+ {0xabab, {1|F|U, {0x13db}}},
+ {0xabac, {1|F|U, {0x13dc}}},
+ {0xabad, {1|F|U, {0x13dd}}},
+ {0xabae, {1|F|U, {0x13de}}},
+ {0xabaf, {1|F|U, {0x13df}}},
+ {0xabb0, {1|F|U, {0x13e0}}},
+ {0xabb1, {1|F|U, {0x13e1}}},
+ {0xabb2, {1|F|U, {0x13e2}}},
+ {0xabb3, {1|F|U, {0x13e3}}},
+ {0xabb4, {1|F|U, {0x13e4}}},
+ {0xabb5, {1|F|U, {0x13e5}}},
+ {0xabb6, {1|F|U, {0x13e6}}},
+ {0xabb7, {1|F|U, {0x13e7}}},
+ {0xabb8, {1|F|U, {0x13e8}}},
+ {0xabb9, {1|F|U, {0x13e9}}},
+ {0xabba, {1|F|U, {0x13ea}}},
+ {0xabbb, {1|F|U, {0x13eb}}},
+ {0xabbc, {1|F|U, {0x13ec}}},
+ {0xabbd, {1|F|U, {0x13ed}}},
+ {0xabbe, {1|F|U, {0x13ee}}},
+ {0xabbf, {1|F|U, {0x13ef}}},
+ {0xfb00, {2|F|ST|SU|I(366), {0x0066, 0x0066}}},
+ {0xfb01, {2|F|ST|SU|I(370), {0x0066, 0x0069}}},
+ {0xfb02, {2|F|ST|SU|I(374), {0x0066, 0x006c}}},
+ {0xfb03, {3|F|ST|SU|I(378), {0x0066, 0x0066, 0x0069}}},
+ {0xfb04, {3|F|ST|SU|I(384), {0x0066, 0x0066, 0x006c}}},
+ {0xfb05, {2|F|ST|SU|I(390), {0x0073, 0x0074}}},
+ {0xfb06, {2|F|ST|SU|I(394), {0x0073, 0x0074}}},
+ {0xfb13, {2|F|ST|SU|I(398), {0x0574, 0x0576}}},
+ {0xfb14, {2|F|ST|SU|I(402), {0x0574, 0x0565}}},
+ {0xfb15, {2|F|ST|SU|I(406), {0x0574, 0x056b}}},
+ {0xfb16, {2|F|ST|SU|I(410), {0x057e, 0x0576}}},
+ {0xfb17, {2|F|ST|SU|I(414), {0x0574, 0x056d}}},
+ {0xff21, {1|F|D, {0xff41}}},
+ {0xff22, {1|F|D, {0xff42}}},
+ {0xff23, {1|F|D, {0xff43}}},
+ {0xff24, {1|F|D, {0xff44}}},
+ {0xff25, {1|F|D, {0xff45}}},
+ {0xff26, {1|F|D, {0xff46}}},
+ {0xff27, {1|F|D, {0xff47}}},
+ {0xff28, {1|F|D, {0xff48}}},
+ {0xff29, {1|F|D, {0xff49}}},
+ {0xff2a, {1|F|D, {0xff4a}}},
+ {0xff2b, {1|F|D, {0xff4b}}},
+ {0xff2c, {1|F|D, {0xff4c}}},
+ {0xff2d, {1|F|D, {0xff4d}}},
+ {0xff2e, {1|F|D, {0xff4e}}},
+ {0xff2f, {1|F|D, {0xff4f}}},
+ {0xff30, {1|F|D, {0xff50}}},
+ {0xff31, {1|F|D, {0xff51}}},
+ {0xff32, {1|F|D, {0xff52}}},
+ {0xff33, {1|F|D, {0xff53}}},
+ {0xff34, {1|F|D, {0xff54}}},
+ {0xff35, {1|F|D, {0xff55}}},
+ {0xff36, {1|F|D, {0xff56}}},
+ {0xff37, {1|F|D, {0xff57}}},
+ {0xff38, {1|F|D, {0xff58}}},
+ {0xff39, {1|F|D, {0xff59}}},
+ {0xff3a, {1|F|D, {0xff5a}}},
+ {0x10400, {1|F|D, {0x10428}}},
+ {0x10401, {1|F|D, {0x10429}}},
+ {0x10402, {1|F|D, {0x1042a}}},
+ {0x10403, {1|F|D, {0x1042b}}},
+ {0x10404, {1|F|D, {0x1042c}}},
+ {0x10405, {1|F|D, {0x1042d}}},
+ {0x10406, {1|F|D, {0x1042e}}},
+ {0x10407, {1|F|D, {0x1042f}}},
+ {0x10408, {1|F|D, {0x10430}}},
+ {0x10409, {1|F|D, {0x10431}}},
+ {0x1040a, {1|F|D, {0x10432}}},
+ {0x1040b, {1|F|D, {0x10433}}},
+ {0x1040c, {1|F|D, {0x10434}}},
+ {0x1040d, {1|F|D, {0x10435}}},
+ {0x1040e, {1|F|D, {0x10436}}},
+ {0x1040f, {1|F|D, {0x10437}}},
+ {0x10410, {1|F|D, {0x10438}}},
+ {0x10411, {1|F|D, {0x10439}}},
+ {0x10412, {1|F|D, {0x1043a}}},
+ {0x10413, {1|F|D, {0x1043b}}},
+ {0x10414, {1|F|D, {0x1043c}}},
+ {0x10415, {1|F|D, {0x1043d}}},
+ {0x10416, {1|F|D, {0x1043e}}},
+ {0x10417, {1|F|D, {0x1043f}}},
+ {0x10418, {1|F|D, {0x10440}}},
+ {0x10419, {1|F|D, {0x10441}}},
+ {0x1041a, {1|F|D, {0x10442}}},
+ {0x1041b, {1|F|D, {0x10443}}},
+ {0x1041c, {1|F|D, {0x10444}}},
+ {0x1041d, {1|F|D, {0x10445}}},
+ {0x1041e, {1|F|D, {0x10446}}},
+ {0x1041f, {1|F|D, {0x10447}}},
+ {0x10420, {1|F|D, {0x10448}}},
+ {0x10421, {1|F|D, {0x10449}}},
+ {0x10422, {1|F|D, {0x1044a}}},
+ {0x10423, {1|F|D, {0x1044b}}},
+ {0x10424, {1|F|D, {0x1044c}}},
+ {0x10425, {1|F|D, {0x1044d}}},
+ {0x10426, {1|F|D, {0x1044e}}},
+ {0x10427, {1|F|D, {0x1044f}}},
+ {0x104b0, {1|F|D, {0x104d8}}},
+ {0x104b1, {1|F|D, {0x104d9}}},
+ {0x104b2, {1|F|D, {0x104da}}},
+ {0x104b3, {1|F|D, {0x104db}}},
+ {0x104b4, {1|F|D, {0x104dc}}},
+ {0x104b5, {1|F|D, {0x104dd}}},
+ {0x104b6, {1|F|D, {0x104de}}},
+ {0x104b7, {1|F|D, {0x104df}}},
+ {0x104b8, {1|F|D, {0x104e0}}},
+ {0x104b9, {1|F|D, {0x104e1}}},
+ {0x104ba, {1|F|D, {0x104e2}}},
+ {0x104bb, {1|F|D, {0x104e3}}},
+ {0x104bc, {1|F|D, {0x104e4}}},
+ {0x104bd, {1|F|D, {0x104e5}}},
+ {0x104be, {1|F|D, {0x104e6}}},
+ {0x104bf, {1|F|D, {0x104e7}}},
+ {0x104c0, {1|F|D, {0x104e8}}},
+ {0x104c1, {1|F|D, {0x104e9}}},
+ {0x104c2, {1|F|D, {0x104ea}}},
+ {0x104c3, {1|F|D, {0x104eb}}},
+ {0x104c4, {1|F|D, {0x104ec}}},
+ {0x104c5, {1|F|D, {0x104ed}}},
+ {0x104c6, {1|F|D, {0x104ee}}},
+ {0x104c7, {1|F|D, {0x104ef}}},
+ {0x104c8, {1|F|D, {0x104f0}}},
+ {0x104c9, {1|F|D, {0x104f1}}},
+ {0x104ca, {1|F|D, {0x104f2}}},
+ {0x104cb, {1|F|D, {0x104f3}}},
+ {0x104cc, {1|F|D, {0x104f4}}},
+ {0x104cd, {1|F|D, {0x104f5}}},
+ {0x104ce, {1|F|D, {0x104f6}}},
+ {0x104cf, {1|F|D, {0x104f7}}},
+ {0x104d0, {1|F|D, {0x104f8}}},
+ {0x104d1, {1|F|D, {0x104f9}}},
+ {0x104d2, {1|F|D, {0x104fa}}},
+ {0x104d3, {1|F|D, {0x104fb}}},
+ {0x10570, {1|F|D, {0x10597}}},
+ {0x10571, {1|F|D, {0x10598}}},
+ {0x10572, {1|F|D, {0x10599}}},
+ {0x10573, {1|F|D, {0x1059a}}},
+ {0x10574, {1|F|D, {0x1059b}}},
+ {0x10575, {1|F|D, {0x1059c}}},
+ {0x10576, {1|F|D, {0x1059d}}},
+ {0x10577, {1|F|D, {0x1059e}}},
+ {0x10578, {1|F|D, {0x1059f}}},
+ {0x10579, {1|F|D, {0x105a0}}},
+ {0x1057a, {1|F|D, {0x105a1}}},
+ {0x1057c, {1|F|D, {0x105a3}}},
+ {0x1057d, {1|F|D, {0x105a4}}},
+ {0x1057e, {1|F|D, {0x105a5}}},
+ {0x1057f, {1|F|D, {0x105a6}}},
+ {0x10580, {1|F|D, {0x105a7}}},
+ {0x10581, {1|F|D, {0x105a8}}},
+ {0x10582, {1|F|D, {0x105a9}}},
+ {0x10583, {1|F|D, {0x105aa}}},
+ {0x10584, {1|F|D, {0x105ab}}},
+ {0x10585, {1|F|D, {0x105ac}}},
+ {0x10586, {1|F|D, {0x105ad}}},
+ {0x10587, {1|F|D, {0x105ae}}},
+ {0x10588, {1|F|D, {0x105af}}},
+ {0x10589, {1|F|D, {0x105b0}}},
+ {0x1058a, {1|F|D, {0x105b1}}},
+ {0x1058c, {1|F|D, {0x105b3}}},
+ {0x1058d, {1|F|D, {0x105b4}}},
+ {0x1058e, {1|F|D, {0x105b5}}},
+ {0x1058f, {1|F|D, {0x105b6}}},
+ {0x10590, {1|F|D, {0x105b7}}},
+ {0x10591, {1|F|D, {0x105b8}}},
+ {0x10592, {1|F|D, {0x105b9}}},
+ {0x10594, {1|F|D, {0x105bb}}},
+ {0x10595, {1|F|D, {0x105bc}}},
+ {0x10c80, {1|F|D, {0x10cc0}}},
+ {0x10c81, {1|F|D, {0x10cc1}}},
+ {0x10c82, {1|F|D, {0x10cc2}}},
+ {0x10c83, {1|F|D, {0x10cc3}}},
+ {0x10c84, {1|F|D, {0x10cc4}}},
+ {0x10c85, {1|F|D, {0x10cc5}}},
+ {0x10c86, {1|F|D, {0x10cc6}}},
+ {0x10c87, {1|F|D, {0x10cc7}}},
+ {0x10c88, {1|F|D, {0x10cc8}}},
+ {0x10c89, {1|F|D, {0x10cc9}}},
+ {0x10c8a, {1|F|D, {0x10cca}}},
+ {0x10c8b, {1|F|D, {0x10ccb}}},
+ {0x10c8c, {1|F|D, {0x10ccc}}},
+ {0x10c8d, {1|F|D, {0x10ccd}}},
+ {0x10c8e, {1|F|D, {0x10cce}}},
+ {0x10c8f, {1|F|D, {0x10ccf}}},
+ {0x10c90, {1|F|D, {0x10cd0}}},
+ {0x10c91, {1|F|D, {0x10cd1}}},
+ {0x10c92, {1|F|D, {0x10cd2}}},
+ {0x10c93, {1|F|D, {0x10cd3}}},
+ {0x10c94, {1|F|D, {0x10cd4}}},
+ {0x10c95, {1|F|D, {0x10cd5}}},
+ {0x10c96, {1|F|D, {0x10cd6}}},
+ {0x10c97, {1|F|D, {0x10cd7}}},
+ {0x10c98, {1|F|D, {0x10cd8}}},
+ {0x10c99, {1|F|D, {0x10cd9}}},
+ {0x10c9a, {1|F|D, {0x10cda}}},
+ {0x10c9b, {1|F|D, {0x10cdb}}},
+ {0x10c9c, {1|F|D, {0x10cdc}}},
+ {0x10c9d, {1|F|D, {0x10cdd}}},
+ {0x10c9e, {1|F|D, {0x10cde}}},
+ {0x10c9f, {1|F|D, {0x10cdf}}},
+ {0x10ca0, {1|F|D, {0x10ce0}}},
+ {0x10ca1, {1|F|D, {0x10ce1}}},
+ {0x10ca2, {1|F|D, {0x10ce2}}},
+ {0x10ca3, {1|F|D, {0x10ce3}}},
+ {0x10ca4, {1|F|D, {0x10ce4}}},
+ {0x10ca5, {1|F|D, {0x10ce5}}},
+ {0x10ca6, {1|F|D, {0x10ce6}}},
+ {0x10ca7, {1|F|D, {0x10ce7}}},
+ {0x10ca8, {1|F|D, {0x10ce8}}},
+ {0x10ca9, {1|F|D, {0x10ce9}}},
+ {0x10caa, {1|F|D, {0x10cea}}},
+ {0x10cab, {1|F|D, {0x10ceb}}},
+ {0x10cac, {1|F|D, {0x10cec}}},
+ {0x10cad, {1|F|D, {0x10ced}}},
+ {0x10cae, {1|F|D, {0x10cee}}},
+ {0x10caf, {1|F|D, {0x10cef}}},
+ {0x10cb0, {1|F|D, {0x10cf0}}},
+ {0x10cb1, {1|F|D, {0x10cf1}}},
+ {0x10cb2, {1|F|D, {0x10cf2}}},
+ {0x10d50, {1|F|D, {0x10d70}}},
+ {0x10d51, {1|F|D, {0x10d71}}},
+ {0x10d52, {1|F|D, {0x10d72}}},
+ {0x10d53, {1|F|D, {0x10d73}}},
+ {0x10d54, {1|F|D, {0x10d74}}},
+ {0x10d55, {1|F|D, {0x10d75}}},
+ {0x10d56, {1|F|D, {0x10d76}}},
+ {0x10d57, {1|F|D, {0x10d77}}},
+ {0x10d58, {1|F|D, {0x10d78}}},
+ {0x10d59, {1|F|D, {0x10d79}}},
+ {0x10d5a, {1|F|D, {0x10d7a}}},
+ {0x10d5b, {1|F|D, {0x10d7b}}},
+ {0x10d5c, {1|F|D, {0x10d7c}}},
+ {0x10d5d, {1|F|D, {0x10d7d}}},
+ {0x10d5e, {1|F|D, {0x10d7e}}},
+ {0x10d5f, {1|F|D, {0x10d7f}}},
+ {0x10d60, {1|F|D, {0x10d80}}},
+ {0x10d61, {1|F|D, {0x10d81}}},
+ {0x10d62, {1|F|D, {0x10d82}}},
+ {0x10d63, {1|F|D, {0x10d83}}},
+ {0x10d64, {1|F|D, {0x10d84}}},
+ {0x10d65, {1|F|D, {0x10d85}}},
+ {0x118a0, {1|F|D, {0x118c0}}},
+ {0x118a1, {1|F|D, {0x118c1}}},
+ {0x118a2, {1|F|D, {0x118c2}}},
+ {0x118a3, {1|F|D, {0x118c3}}},
+ {0x118a4, {1|F|D, {0x118c4}}},
+ {0x118a5, {1|F|D, {0x118c5}}},
+ {0x118a6, {1|F|D, {0x118c6}}},
+ {0x118a7, {1|F|D, {0x118c7}}},
+ {0x118a8, {1|F|D, {0x118c8}}},
+ {0x118a9, {1|F|D, {0x118c9}}},
+ {0x118aa, {1|F|D, {0x118ca}}},
+ {0x118ab, {1|F|D, {0x118cb}}},
+ {0x118ac, {1|F|D, {0x118cc}}},
+ {0x118ad, {1|F|D, {0x118cd}}},
+ {0x118ae, {1|F|D, {0x118ce}}},
+ {0x118af, {1|F|D, {0x118cf}}},
+ {0x118b0, {1|F|D, {0x118d0}}},
+ {0x118b1, {1|F|D, {0x118d1}}},
+ {0x118b2, {1|F|D, {0x118d2}}},
+ {0x118b3, {1|F|D, {0x118d3}}},
+ {0x118b4, {1|F|D, {0x118d4}}},
+ {0x118b5, {1|F|D, {0x118d5}}},
+ {0x118b6, {1|F|D, {0x118d6}}},
+ {0x118b7, {1|F|D, {0x118d7}}},
+ {0x118b8, {1|F|D, {0x118d8}}},
+ {0x118b9, {1|F|D, {0x118d9}}},
+ {0x118ba, {1|F|D, {0x118da}}},
+ {0x118bb, {1|F|D, {0x118db}}},
+ {0x118bc, {1|F|D, {0x118dc}}},
+ {0x118bd, {1|F|D, {0x118dd}}},
+ {0x118be, {1|F|D, {0x118de}}},
+ {0x118bf, {1|F|D, {0x118df}}},
+ {0x16e40, {1|F|D, {0x16e60}}},
+ {0x16e41, {1|F|D, {0x16e61}}},
+ {0x16e42, {1|F|D, {0x16e62}}},
+ {0x16e43, {1|F|D, {0x16e63}}},
+ {0x16e44, {1|F|D, {0x16e64}}},
+ {0x16e45, {1|F|D, {0x16e65}}},
+ {0x16e46, {1|F|D, {0x16e66}}},
+ {0x16e47, {1|F|D, {0x16e67}}},
+ {0x16e48, {1|F|D, {0x16e68}}},
+ {0x16e49, {1|F|D, {0x16e69}}},
+ {0x16e4a, {1|F|D, {0x16e6a}}},
+ {0x16e4b, {1|F|D, {0x16e6b}}},
+ {0x16e4c, {1|F|D, {0x16e6c}}},
+ {0x16e4d, {1|F|D, {0x16e6d}}},
+ {0x16e4e, {1|F|D, {0x16e6e}}},
+ {0x16e4f, {1|F|D, {0x16e6f}}},
+ {0x16e50, {1|F|D, {0x16e70}}},
+ {0x16e51, {1|F|D, {0x16e71}}},
+ {0x16e52, {1|F|D, {0x16e72}}},
+ {0x16e53, {1|F|D, {0x16e73}}},
+ {0x16e54, {1|F|D, {0x16e74}}},
+ {0x16e55, {1|F|D, {0x16e75}}},
+ {0x16e56, {1|F|D, {0x16e76}}},
+ {0x16e57, {1|F|D, {0x16e77}}},
+ {0x16e58, {1|F|D, {0x16e78}}},
+ {0x16e59, {1|F|D, {0x16e79}}},
+ {0x16e5a, {1|F|D, {0x16e7a}}},
+ {0x16e5b, {1|F|D, {0x16e7b}}},
+ {0x16e5c, {1|F|D, {0x16e7c}}},
+ {0x16e5d, {1|F|D, {0x16e7d}}},
+ {0x16e5e, {1|F|D, {0x16e7e}}},
+ {0x16e5f, {1|F|D, {0x16e7f}}},
+ {0x16ea0, {1|F|D, {0x16ebb}}},
+ {0x16ea1, {1|F|D, {0x16ebc}}},
+ {0x16ea2, {1|F|D, {0x16ebd}}},
+ {0x16ea3, {1|F|D, {0x16ebe}}},
+ {0x16ea4, {1|F|D, {0x16ebf}}},
+ {0x16ea5, {1|F|D, {0x16ec0}}},
+ {0x16ea6, {1|F|D, {0x16ec1}}},
+ {0x16ea7, {1|F|D, {0x16ec2}}},
+ {0x16ea8, {1|F|D, {0x16ec3}}},
+ {0x16ea9, {1|F|D, {0x16ec4}}},
+ {0x16eaa, {1|F|D, {0x16ec5}}},
+ {0x16eab, {1|F|D, {0x16ec6}}},
+ {0x16eac, {1|F|D, {0x16ec7}}},
+ {0x16ead, {1|F|D, {0x16ec8}}},
+ {0x16eae, {1|F|D, {0x16ec9}}},
+ {0x16eaf, {1|F|D, {0x16eca}}},
+ {0x16eb0, {1|F|D, {0x16ecb}}},
+ {0x16eb1, {1|F|D, {0x16ecc}}},
+ {0x16eb2, {1|F|D, {0x16ecd}}},
+ {0x16eb3, {1|F|D, {0x16ece}}},
+ {0x16eb4, {1|F|D, {0x16ecf}}},
+ {0x16eb5, {1|F|D, {0x16ed0}}},
+ {0x16eb6, {1|F|D, {0x16ed1}}},
+ {0x16eb7, {1|F|D, {0x16ed2}}},
+ {0x16eb8, {1|F|D, {0x16ed3}}},
+ {0x1e900, {1|F|D, {0x1e922}}},
+ {0x1e901, {1|F|D, {0x1e923}}},
+ {0x1e902, {1|F|D, {0x1e924}}},
+ {0x1e903, {1|F|D, {0x1e925}}},
+ {0x1e904, {1|F|D, {0x1e926}}},
+ {0x1e905, {1|F|D, {0x1e927}}},
+ {0x1e906, {1|F|D, {0x1e928}}},
+ {0x1e907, {1|F|D, {0x1e929}}},
+ {0x1e908, {1|F|D, {0x1e92a}}},
+ {0x1e909, {1|F|D, {0x1e92b}}},
+ {0x1e90a, {1|F|D, {0x1e92c}}},
+ {0x1e90b, {1|F|D, {0x1e92d}}},
+ {0x1e90c, {1|F|D, {0x1e92e}}},
+ {0x1e90d, {1|F|D, {0x1e92f}}},
+ {0x1e90e, {1|F|D, {0x1e930}}},
+ {0x1e90f, {1|F|D, {0x1e931}}},
+ {0x1e910, {1|F|D, {0x1e932}}},
+ {0x1e911, {1|F|D, {0x1e933}}},
+ {0x1e912, {1|F|D, {0x1e934}}},
+ {0x1e913, {1|F|D, {0x1e935}}},
+ {0x1e914, {1|F|D, {0x1e936}}},
+ {0x1e915, {1|F|D, {0x1e937}}},
+ {0x1e916, {1|F|D, {0x1e938}}},
+ {0x1e917, {1|F|D, {0x1e939}}},
+ {0x1e918, {1|F|D, {0x1e93a}}},
+ {0x1e919, {1|F|D, {0x1e93b}}},
+ {0x1e91a, {1|F|D, {0x1e93c}}},
+ {0x1e91b, {1|F|D, {0x1e93d}}},
+ {0x1e91c, {1|F|D, {0x1e93e}}},
+ {0x1e91d, {1|F|D, {0x1e93f}}},
+ {0x1e91e, {1|F|D, {0x1e940}}},
+ {0x1e91f, {1|F|D, {0x1e941}}},
+ {0x1e920, {1|F|D, {0x1e942}}},
+ {0x1e921, {1|F|D, {0x1e943}}},
+#define CaseFold_Locale (*(CaseFold_11_Type (*)[2])(CaseFold_11_Table+1583))
+ {0x0049, {1|F|D, {0x0069}}},
+ {0x0130, {2|F|D, {0x0069, 0x0307}}},
+};
+
+/* ANSI-C code produced by gperf version 3.1 */
+/* Command-line: gperf -7 -k1,2,3 -F,-1 -c -j1 -i1 -t -T -E -C -H onigenc_unicode_CaseFold_11_hash -N onigenc_unicode_CaseFold_11_lookup -n */
+
+/* maximum key range = 3756, duplicates = 0 */
+
+#ifdef __GNUC__
+__inline
+#else
+#ifdef __cplusplus
+inline
+#endif
+#endif
+/*ARGSUSED*/
+static unsigned int
+onigenc_unicode_CaseFold_11_hash(const OnigCodePoint code)
+{
+ static const unsigned short asso_values[] =
+ {
+ 2, 107, 6, 43, 1, 5, 70, 14, 5, 396,
+ 239, 925, 3763, 3763, 3763, 3763, 3763, 3763, 3763, 3763,
+ 3763, 3763, 3763, 3763, 3763, 45, 404, 3763, 3763, 3763,
+ 3763, 3763, 3763, 400, 3763, 3763, 3763, 3763, 3763, 20,
+ 3763, 3763, 3763, 3763, 3763, 3763, 3763, 3763, 3763, 472,
+ 3763, 3763, 3763, 3763, 3763, 3763, 3763, 163, 3763, 3763,
+ 311, 310, 445, 3, 3763, 3763, 482, 10, 3763, 3763,
+ 3763, 3763, 3763, 604, 3763, 3763, 315, 863, 428, 38,
+ 2198, 226, 42, 182, 240, 94, 1542, 7, 12, 24,
+ 2250, 764, 872, 684, 2182, 168, 1933, 308, 2170, 153,
+ 2106, 108, 1653, 261, 1889, 426, 1851, 484, 470, 506,
+ 2234, 286, 1417, 411, 1461, 366, 1436, 352, 60, 667,
+ 1357, 551, 1110, 611, 1440, 597, 631, 614, 1630, 691,
+ 1762, 821, 1950, 747, 1682, 542, 1752, 740, 1949, 855,
+ 1912, 845, 1840, 1230, 1928, 1106, 1572, 1003, 1323, 1223,
+ 500, 1203, 1783, 1094, 1602, 957, 1472, 1157, 2059, 1188,
+ 2140, 947, 937, 1257, 1395, 1168, 196, 1317, 258, 1246,
+ 141, 1587, 38, 1563, 3, 1663, 53, 1371, 178, 1480,
+ 41, 1745, 57, 1723, 356, 1698, 122, 1609, 77, 1726,
+ 76, 1710, 44, 1740, 2, 1815, 568, 2094, 146, 2214,
+ 340, 2126, 73, 408, 101, 1980, 149
+ };
+ return asso_values[bits_of(code, 2)+79] + asso_values[bits_of(code, 1)] + asso_values[bits_of(code, 0)];
+}
+
+static const CodePointList3 *
+onigenc_unicode_CaseFold_11_lookup(const OnigCodePoint code)
+{
+ enum
+ {
+ MIN_CODE_VALUE = 0x41,
+ MAX_CODE_VALUE = 0x1e921,
+ TOTAL_KEYWORDS = 1585,
+ MIN_WORD_LENGTH = 3,
+ MAX_WORD_LENGTH = 3,
+ MIN_HASH_VALUE = 7,
+ MAX_HASH_VALUE = 3762
+ };
+
+ static const short wordlist[] =
+ {
+ -1, -1, -1, -1, -1, -1,
+ -1,
+ /*0x1ff3*/ 856,
+ -1, -1,
+ /*0x0208*/ 194,
+ -1,
+ /*0x1f88*/ 776,
+ /*0x10408*/ 1284,
+ /*0x0408*/ 305,
+ /*0x0108*/ 61,
+ -1,
+ /*0x1f89*/ 777,
+ /*0x10409*/ 1285,
+ /*0x0409*/ 306,
+ /*0xab88*/ 1182,
+ /*0x2c08*/ 920,
+ -1,
+ /*0x0388*/ 235,
+ -1,
+ /*0xab89*/ 1183,
+ /*0x2c09*/ 921,
+ /*0x020a*/ 195,
+ /*0x0389*/ 236,
+ /*0x1f8a*/ 778,
+ /*0x1040a*/ 1286,
+ /*0x040a*/ 307,
+ /*0x010a*/ 62,
+ /*0x2c88*/ 979,
+ -1, -1, -1,
+ /*0xab8a*/ 1184,
+ /*0x2c0a*/ 922,
+ -1,
+ /*0x038a*/ 237,
+ /*0x0200*/ 190,
+ -1,
+ /*0x1f80*/ 768,
+ /*0x10400*/ 1276,
+ /*0x0400*/ 297,
+ /*0x0100*/ 57,
+ /*0x1f83*/ 771,
+ /*0x10403*/ 1279,
+ /*0x0403*/ 300,
+ /*0x2c8a*/ 980,
+ /*0xab80*/ 1174,
+ /*0x2c00*/ 912,
+ /*0x10c88*/ 1395,
+ /*0x2183*/ 885,
+ /*0xab83*/ 1177,
+ /*0x2c03*/ 915,
+ /*0x0189*/ 126,
+ /*0x10c89*/ 1396,
+ -1,
+ /*0x03f1*/ 288,
+ -1,
+ /*0x1fe7*/ 849,
+ /*0x1e908*/ 1557,
+ /*0x2c80*/ 975,
+ /*0x1fa7*/ 807,
+ /*0x10427*/ 1315,
+ /*0x0427*/ 336,
+ /*0x1e909*/ 1558,
+ /*0x018a*/ 127,
+ /*0x10c8a*/ 1397,
+ /*0x2c67*/ 964,
+ -1,
+ /*0xaba7*/ 1213,
+ /*0x2c27*/ 951,
+ -1,
+ /*0x03a7*/ 263,
+ -1,
+ /*0x1ffb*/ 863,
+ -1,
+ /*0x1e90a*/ 1559,
+ /*0x017b*/ 118,
+ /*0xa780*/ 1107,
+ -1,
+ /*0x10c80*/ 1387,
+ -1, -1, -1,
+ /*0x10c83*/ 1390,
+ /*0x01f1*/ 181,
+ /*0x2c6f*/ 969,
+ /*0x2c6d*/ 967,
+ -1, -1,
+ /*0x1e900*/ 1549,
+ /*0x13fb*/ 527,
+ -1,
+ /*0x0206*/ 193,
+ /*0x1e903*/ 1552,
+ /*0x1f86*/ 774,
+ /*0x10406*/ 1282,
+ /*0x0406*/ 303,
+ /*0x0106*/ 60,
+ /*0x2ced*/ 1026,
+ -1,
+ /*0x01a7*/ 145,
+ /*0x10ca7*/ 1426,
+ /*0xab86*/ 1180,
+ /*0x2c06*/ 918,
+ /*0x017d*/ 119,
+ /*0x0386*/ 234,
+ /*0x0216*/ 201,
+ /*0x00df*/ 56,
+ /*0x1f96*/ 790,
+ /*0x10416*/ 1298,
+ /*0x0416*/ 319,
+ /*0x0116*/ 68,
+ /*0x03fd*/ 294,
+ -1, -1,
+ /*0x2c86*/ 978,
+ /*0xab96*/ 1196,
+ /*0x2c16*/ 934,
+ /*0x13fd*/ 529,
+ /*0x0396*/ 247,
+ -1, -1,
+ /*0x1feb*/ 853,
+ -1, -1, -1, -1, -1, -1,
+ /*0x2c96*/ 986,
+ -1,
+ /*0x2c6b*/ 966,
+ -1,
+ /*0xa786*/ 1110,
+ /*0x0186*/ 124,
+ /*0x10c86*/ 1393,
+ /*0xfb00*/ 1238,
+ -1, -1, -1,
+ /*0xfb03*/ 1241,
+ /*0x1fdb*/ 844,
+ /*0x00dd*/ 54,
+ /*0x2ceb*/ 1025,
+ -1,
+ /*0x1e906*/ 1555,
+ /*0x1ff7*/ 859,
+ /*0xa796*/ 1115,
+ /*0x0196*/ 135,
+ /*0x10c96*/ 1409,
+ -1,
+ /*0x0214*/ 200,
+ /*0x017f*/ 120,
+ /*0x1f94*/ 788,
+ /*0x10414*/ 1296,
+ /*0x0414*/ 317,
+ /*0x0114*/ 67,
+ /*0x03f7*/ 291,
+ /*0x2c7f*/ 974,
+ /*0x1e916*/ 1571,
+ /*0x03ff*/ 296,
+ /*0xab94*/ 1194,
+ /*0x2c14*/ 932,
+ -1,
+ /*0x0394*/ 245,
+ -1,
+ /*0x0210*/ 198,
+ /*0x1c88*/ 538,
+ /*0x1f90*/ 784,
+ /*0x10410*/ 1292,
+ /*0x0410*/ 313,
+ /*0x0110*/ 65,
+ /*0x1c89*/ 539,
+ -1,
+ /*0x2c94*/ 985,
+ -1,
+ /*0xab90*/ 1190,
+ /*0x2c10*/ 928,
+ /*0x1fe3*/ 846,
+ /*0x0390*/ 241,
+ /*0x0204*/ 192,
+ /*0x01db*/ 170,
+ /*0x1f84*/ 772,
+ /*0x10404*/ 1280,
+ /*0x0404*/ 301,
+ /*0x0104*/ 59,
+ /*0x01f7*/ 185,
+ /*0x2c63*/ 962,
+ -1,
+ /*0x2c90*/ 983,
+ /*0xab84*/ 1178,
+ /*0x2c04*/ 916,
+ /*0xfb06*/ 1244,
+ /*0x0194*/ 134,
+ /*0x10c94*/ 1407,
+ /*0x0057*/ 21,
+ /*0x1fd7*/ 840,
+ -1,
+ /*0x1c80*/ 530,
+ -1, -1, -1,
+ /*0x1c83*/ 533,
+ /*0x2c84*/ 977,
+ /*0x1e914*/ 1569,
+ -1,
+ /*0xfb16*/ 1248,
+ /*0xa790*/ 1113,
+ /*0x0190*/ 131,
+ /*0x10c90*/ 1403,
+ -1, -1, -1, -1, -1, -1,
+ /*0x037f*/ 233,
+ -1, -1,
+ /*0x1e910*/ 1565,
+ /*0x1ca7*/ 563,
+ /*0xa784*/ 1109,
+ /*0x0184*/ 123,
+ /*0x10c84*/ 1391,
+ /*0x0202*/ 191,
+ -1,
+ /*0x1f82*/ 770,
+ /*0x10402*/ 1278,
+ /*0x0402*/ 299,
+ /*0x0102*/ 58,
+ -1, -1, -1,
+ /*0x1e904*/ 1553,
+ /*0xab82*/ 1176,
+ /*0x2c02*/ 914,
+ /*0x01d7*/ 168,
+ /*0x10573*/ 1355,
+ -1, -1,
+ /*0x1f85*/ 773,
+ /*0x10405*/ 1281,
+ /*0x0405*/ 302,
+ /*0x0508*/ 425,
+ -1,
+ /*0x00db*/ 52,
+ -1,
+ /*0x2c82*/ 976,
+ /*0xab85*/ 1179,
+ /*0x2c05*/ 917,
+ -1,
+ /*0xfb14*/ 1246,
+ -1, -1,
+ /*0x1c86*/ 536,
+ -1, -1,
+ /*0x0059*/ 23,
+ /*0x1fd9*/ 842,
+ /*0x0218*/ 202,
+ /*0x050a*/ 426,
+ /*0x1f98*/ 792,
+ /*0x10418*/ 1300,
+ /*0x0418*/ 321,
+ /*0x0118*/ 69,
+ /*0xa782*/ 1108,
+ /*0x0182*/ 122,
+ /*0x10c82*/ 1389,
+ /*0x1c96*/ 546,
+ /*0xab98*/ 1198,
+ /*0x2c18*/ 936,
+ -1,
+ /*0x0398*/ 249,
+ -1,
+ /*0x0500*/ 421,
+ -1, -1,
+ /*0x1e902*/ 1551,
+ -1,
+ /*0x10571*/ 1353,
+ /*0xfb04*/ 1242,
+ /*0x10c85*/ 1392,
+ /*0x2c98*/ 987,
+ -1,
+ /*0x0220*/ 206,
+ -1,
+ /*0x1fa0*/ 800,
+ /*0x10420*/ 1308,
+ /*0x0420*/ 329,
+ /*0x0120*/ 73,
+ -1,
+ /*0x1e905*/ 1554,
+ -1, -1,
+ /*0xaba0*/ 1206,
+ /*0x2c20*/ 944,
+ -1,
+ /*0x03a0*/ 257,
+ /*0x01d9*/ 169,
+ -1,
+ /*0xa798*/ 1116,
+ /*0x0198*/ 137,
+ /*0x10c98*/ 1411,
+ -1, -1, -1,
+ /*0x0212*/ 199,
+ /*0x2ca0*/ 991,
+ /*0x1f92*/ 786,
+ /*0x10412*/ 1294,
+ /*0x0412*/ 315,
+ /*0x0112*/ 66,
+ /*0x1e918*/ 1573,
+ /*0x1c94*/ 544,
+ /*0x1e88*/ 654,
+ /*0x1e08*/ 590,
+ /*0xab92*/ 1192,
+ /*0x2c12*/ 930,
+ -1,
+ /*0x0392*/ 243,
+ -1, -1, -1, -1,
+ /*0xfb02*/ 1240,
+ /*0xa7a0*/ 1120,
+ /*0x01a0*/ 141,
+ /*0x10ca0*/ 1419,
+ /*0x1c90*/ 540,
+ /*0x2c92*/ 984,
+ /*0x0506*/ 424,
+ /*0x1e8a*/ 655,
+ /*0x1e0a*/ 591,
+ -1, -1, -1,
+ /*0x1057d*/ 1364,
+ /*0x1e920*/ 1581,
+ /*0xfb05*/ 1243,
+ -1,
+ /*0x1ff9*/ 861,
+ -1,
+ /*0x1c84*/ 534,
+ /*0x0179*/ 117,
+ /*0x0516*/ 432,
+ /*0x1e80*/ 650,
+ /*0x1e00*/ 586,
+ /*0xa792*/ 1114,
+ -1,
+ /*0x10c92*/ 1405,
+ /*0x0226*/ 209,
+ /*0x03f9*/ 292,
+ /*0x1fa6*/ 806,
+ /*0x10426*/ 1314,
+ /*0x0426*/ 335,
+ /*0x0126*/ 76,
+ /*0x1fe9*/ 851,
+ /*0x13f9*/ 525,
+ -1,
+ /*0x1e912*/ 1567,
+ /*0xaba6*/ 1212,
+ /*0x2c26*/ 950,
+ /*0x00d9*/ 50,
+ /*0x03a6*/ 262,
+ /*0x0224*/ 208,
+ /*0x2c69*/ 965,
+ /*0x1fa4*/ 804,
+ /*0x10424*/ 1312,
+ /*0x0424*/ 333,
+ /*0x0124*/ 75,
+ -1, -1, -1,
+ /*0x2ca6*/ 994,
+ /*0xaba4*/ 1210,
+ /*0x2c24*/ 948,
+ -1,
+ /*0x03a4*/ 260,
+ -1, -1, -1,
+ /*0x10577*/ 1359,
+ -1, -1,
+ /*0x1057f*/ 1366,
+ -1,
+ /*0x1c82*/ 532,
+ /*0x2ca4*/ 993,
+ -1,
+ /*0x0514*/ 431,
+ -1,
+ /*0xa7a6*/ 1123,
+ /*0x01a6*/ 144,
+ /*0x10ca6*/ 1425,
+ -1, -1, -1, -1, -1, -1,
+ /*0x1c85*/ 535,
+ /*0x1e86*/ 653,
+ /*0x1e06*/ 589,
+ /*0x10d5f*/ 1453,
+ /*0x0510*/ 429,
+ /*0xa7a4*/ 1122,
+ /*0x01a4*/ 143,
+ /*0x10ca4*/ 1423,
+ /*0x1ffc*/ 864,
+ /*0x0222*/ 207,
+ /*0x047c*/ 359,
+ /*0x1fa2*/ 802,
+ /*0x10422*/ 1310,
+ /*0x0422*/ 331,
+ /*0x0122*/ 74,
+ /*0x1e96*/ 661,
+ /*0x1e16*/ 597,
+ /*0x048a*/ 362,
+ /*0x0504*/ 423,
+ /*0xaba2*/ 1208,
+ /*0x2c22*/ 946,
+ /*0x1c98*/ 548,
+ -1, -1,
+ /*0x021a*/ 203,
+ /*0x13fc*/ 528,
+ /*0x1f9a*/ 794,
+ /*0x1041a*/ 1302,
+ /*0x041a*/ 323,
+ /*0x011a*/ 70,
+ -1,
+ /*0x0480*/ 361,
+ /*0x2ca2*/ 992,
+ -1,
+ /*0xab9a*/ 1200,
+ /*0x2c1a*/ 938,
+ -1,
+ /*0x039a*/ 251,
+ /*0x10d5d*/ 1451,
+ -1, -1,
+ /*0x10d65*/ 1459,
+ -1, -1, -1,
+ /*0x1f5f*/ 759,
+ /*0x1ca0*/ 556,
+ /*0x2c9a*/ 988,
+ /*0x01fc*/ 188,
+ /*0x1f08*/ 716,
+ /*0xa7a2*/ 1121,
+ /*0x01a2*/ 142,
+ /*0x10ca2*/ 1421,
+ /*0x10d61*/ 1455,
+ /*0x1f09*/ 717,
+ -1, -1,
+ /*0x10a7*/ 491,
+ -1, -1,
+ /*0x1e94*/ 660,
+ /*0x1e14*/ 596,
+ /*0x0502*/ 422,
+ -1, -1,
+ /*0xa79a*/ 1117,
+ /*0x1f0a*/ 718,
+ /*0x10c9a*/ 1413,
+ /*0x1c92*/ 542,
+ -1,
+ /*0x1f9d*/ 797,
+ /*0x1041d*/ 1305,
+ /*0x041d*/ 326,
+ -1, -1,
+ /*0x1e90*/ 658,
+ /*0x1e10*/ 594,
+ /*0x1e91a*/ 1575,
+ /*0xab9d*/ 1203,
+ /*0x2c1d*/ 941,
+ /*0x1f5d*/ 758,
+ /*0x039d*/ 254,
+ /*0x021c*/ 204,
+ -1,
+ /*0x1f9c*/ 796,
+ /*0x1041c*/ 1304,
+ /*0x041c*/ 325,
+ /*0x011c*/ 71,
+ -1,
+ /*0x1e84*/ 652,
+ /*0x1e04*/ 588,
+ -1,
+ /*0xab9c*/ 1202,
+ /*0x2c1c*/ 940,
+ -1,
+ /*0x039c*/ 253,
+ -1,
+ /*0x0518*/ 433,
+ -1,
+ /*0x0047*/ 6,
+ /*0x1fc7*/ 831,
+ /*0x0496*/ 368,
+ /*0xa77b*/ 1104,
+ /*0x0147*/ 91,
+ /*0x021e*/ 205,
+ /*0x2c9c*/ 989,
+ /*0x1f9e*/ 798,
+ /*0x1041e*/ 1306,
+ /*0x041e*/ 327,
+ /*0x011e*/ 72,
+ /*0x019d*/ 139,
+ /*0x10c9d*/ 1416,
+ /*0x1ca6*/ 562,
+ -1,
+ /*0xab9e*/ 1204,
+ /*0x2c1e*/ 942,
+ -1,
+ /*0x039e*/ 255,
+ /*0x1f6f*/ 767,
+ /*0x1f6d*/ 765,
+ /*0x2165*/ 874,
+ /*0x1e91d*/ 1578,
+ /*0x0520*/ 437,
+ /*0xa79c*/ 1118,
+ /*0x019c*/ 138,
+ /*0x10c9c*/ 1415,
+ /*0x1ca4*/ 560,
+ /*0x2c9e*/ 990,
+ /*0x118a7*/ 1467,
+ -1,
+ /*0xa77d*/ 1105,
+ -1,
+ /*0x2161*/ 870,
+ /*0x1e82*/ 651,
+ /*0x1e02*/ 587,
+ /*0x1e91c*/ 1577,
+ /*0x2167*/ 876,
+ -1, -1,
+ /*0xa7c7*/ 1145,
+ /*0x01c7*/ 159,
+ /*0x10d5b*/ 1449,
+ /*0x1fb8*/ 821,
+ -1,
+ /*0x0512*/ 430,
+ /*0xa79e*/ 1119,
+ /*0x0494*/ 367,
+ /*0x10c9e*/ 1417,
+ -1,
+ /*0x022a*/ 211,
+ /*0xabb8*/ 1230,
+ /*0x1faa*/ 810,
+ -1,
+ /*0x042a*/ 339,
+ /*0x012a*/ 78,
+ /*0x216f*/ 884,
+ /*0x216d*/ 882,
+ /*0x1e91e*/ 1579,
+ -1,
+ /*0xabaa*/ 1216,
+ /*0x2c2a*/ 954,
+ /*0x0490*/ 365,
+ /*0x03aa*/ 266,
+ /*0x2cb8*/ 1003,
+ /*0x1f6b*/ 763,
+ -1, -1, -1,
+ /*0x1e98*/ 663,
+ /*0x1e18*/ 598,
+ -1,
+ /*0x1ca2*/ 558,
+ /*0x2caa*/ 996,
+ -1, -1,
+ /*0x10579*/ 1361,
+ -1,
+ /*0x2c75*/ 972,
+ /*0x10d63*/ 1457,
+ /*0x03f5*/ 290,
+ -1,
+ /*0xa7b8*/ 1136,
+ /*0x01b8*/ 155,
+ /*0x1f5b*/ 757,
+ -1, -1,
+ /*0x1c9a*/ 550,
+ -1,
+ /*0x0526*/ 440,
+ -1,
+ /*0xa7aa*/ 1125,
+ -1,
+ /*0x10caa*/ 1429,
+ /*0x1ea0*/ 668,
+ /*0x1e20*/ 602,
+ /*0x022e*/ 213,
+ /*0x10d57*/ 1445,
+ /*0x1fae*/ 814,
+ -1,
+ /*0x042e*/ 343,
+ /*0x012e*/ 80,
+ /*0x216b*/ 880,
+ /*0x0524*/ 439,
+ -1,
+ /*0x00c7*/ 33,
+ /*0xabae*/ 1220,
+ /*0x2c2e*/ 958,
+ /*0xa7f5*/ 1157,
+ -1,
+ /*0x022c*/ 212,
+ -1,
+ /*0x1fac*/ 812,
+ /*0x0230*/ 214,
+ /*0x042c*/ 341,
+ /*0x012c*/ 79,
+ /*0x1e92*/ 659,
+ /*0x1e12*/ 595,
+ /*0x0130*/ 1584,
+ /*0x2cae*/ 998,
+ /*0xabac*/ 1218,
+ /*0x2c2c*/ 956,
+ -1,
+ /*0xabb0*/ 1222,
+ -1, -1,
+ /*0x03b0*/ 268,
+ -1, -1, -1, -1,
+ /*0x1c9d*/ 553,
+ /*0x1faf*/ 815,
+ /*0x2cac*/ 997,
+ /*0x042f*/ 344,
+ -1,
+ /*0x2cb0*/ 999,
+ /*0xa7ae*/ 1129,
+ /*0x01ae*/ 148,
+ /*0x10cae*/ 1433,
+ /*0xabaf*/ 1221,
+ /*0x2c2f*/ 959,
+ -1, -1,
+ /*0x1057c*/ 1363,
+ /*0x1c9c*/ 552,
+ -1, -1,
+ /*0x0522*/ 438,
+ -1, -1,
+ /*0xa7ac*/ 1127,
+ /*0x01ac*/ 147,
+ /*0x10cac*/ 1431,
+ /*0xa7b0*/ 1130,
+ /*0x0498*/ 369,
+ /*0x10cb0*/ 1435,
+ -1,
+ /*0x2163*/ 872,
+ /*0x10d59*/ 1447,
+ /*0x1ea6*/ 671,
+ /*0x1e26*/ 605,
+ -1,
+ /*0x051a*/ 434,
+ -1, -1,
+ /*0x0228*/ 210,
+ /*0x1c9e*/ 554,
+ /*0x1fa8*/ 808,
+ -1,
+ /*0x0428*/ 337,
+ /*0x0128*/ 77,
+ /*0x01af*/ 149,
+ /*0x10caf*/ 1434,
+ /*0x1ea4*/ 670,
+ /*0x1e24*/ 604,
+ /*0xaba8*/ 1214,
+ /*0x2c28*/ 952,
+ -1,
+ /*0x03a8*/ 264,
+ /*0x04a0*/ 373,
+ -1, -1,
+ /*0x020e*/ 197,
+ /*0x10a0*/ 484,
+ /*0x1f8e*/ 782,
+ /*0x1040e*/ 1290,
+ /*0x040e*/ 311,
+ /*0x010e*/ 64,
+ /*0x2ca8*/ 995,
+ /*0x0232*/ 215,
+ -1,
+ /*0x1fb2*/ 816,
+ /*0xab8e*/ 1188,
+ /*0x2c0e*/ 926,
+ /*0x0132*/ 81,
+ /*0x038e*/ 239,
+ -1, -1, -1,
+ /*0xabb2*/ 1224,
+ /*0x1f59*/ 756,
+ /*0x0492*/ 366,
+ /*0x1cb8*/ 580,
+ /*0x1f18*/ 724,
+ -1,
+ /*0x2c8e*/ 982,
+ /*0xa7a8*/ 1124,
+ -1,
+ /*0x10ca8*/ 1427,
+ -1, -1,
+ /*0x1caa*/ 566,
+ /*0x2cb2*/ 1000,
+ -1, -1,
+ /*0x1efc*/ 714,
+ /*0x1e7c*/ 648,
+ -1,
+ /*0x1ea2*/ 669,
+ /*0x1e22*/ 603,
+ /*0x051c*/ 435,
+ -1, -1, -1,
+ /*0x018e*/ 129,
+ /*0x10c8e*/ 1401,
+ -1, -1, -1,
+ /*0xff27*/ 1256,
+ /*0xa7b2*/ 1132,
+ /*0x01b2*/ 151,
+ /*0x10cb2*/ 1437,
+ /*0x1e9a*/ 665,
+ /*0x1e1a*/ 599,
+ /*0x1e90e*/ 1563,
+ /*0x0547*/ 467,
+ -1,
+ /*0x023a*/ 216,
+ -1,
+ /*0x1fba*/ 823,
+ -1,
+ /*0x051e*/ 436,
+ -1,
+ /*0x16ea7*/ 1531,
+ /*0x04a6*/ 376,
+ -1,
+ /*0x1fb6*/ 819,
+ /*0xabba*/ 1232,
+ /*0x10a6*/ 490,
+ /*0x0136*/ 83,
+ -1, -1, -1,
+ /*0x118a0*/ 1460,
+ /*0xabb6*/ 1228,
+ -1,
+ /*0x1cae*/ 570,
+ -1,
+ /*0x04a4*/ 375,
+ -1,
+ /*0x2cba*/ 1004,
+ /*0x020c*/ 196,
+ /*0x10a4*/ 488,
+ /*0x1f8c*/ 780,
+ /*0x1040c*/ 1288,
+ /*0x040c*/ 309,
+ /*0x010c*/ 63,
+ /*0x2cb6*/ 1002,
+ /*0xa779*/ 1103,
+ -1,
+ /*0x1cac*/ 568,
+ /*0xab8c*/ 1186,
+ /*0x2c0c*/ 924,
+ /*0x1cb0*/ 572,
+ /*0x038c*/ 238,
+ -1, -1,
+ /*0x0538*/ 452,
+ /*0xa7ba*/ 1137,
+ -1,
+ /*0xa726*/ 1067,
+ -1, -1, -1,
+ /*0x2c8c*/ 981,
+ /*0xa7b6*/ 1135,
+ /*0x052a*/ 442,
+ -1, -1, -1,
+ /*0x1caf*/ 571,
+ /*0x1e1c*/ 600,
+ -1, -1,
+ /*0xa724*/ 1066,
+ -1, -1,
+ /*0x1f69*/ 761,
+ -1, -1,
+ /*0x04fc*/ 419,
+ -1,
+ /*0x10575*/ 1357,
+ /*0x04a2*/ 374,
+ /*0x10c8c*/ 1399,
+ -1, -1,
+ /*0x10a2*/ 486,
+ -1, -1, -1, -1,
+ /*0x1e9e*/ 667,
+ /*0x1e1e*/ 601,
+ /*0x1e90c*/ 1561,
+ -1, -1, -1,
+ /*0x049a*/ 370,
+ /*0x118a6*/ 1466,
+ /*0x1fb4*/ 818,
+ -1, -1,
+ /*0x0134*/ 82,
+ -1, -1,
+ /*0x1ca8*/ 564,
+ -1,
+ /*0xabb4*/ 1226,
+ -1,
+ /*0x2126*/ 865,
+ -1,
+ /*0x052e*/ 444,
+ /*0x118a4*/ 1464,
+ /*0x2169*/ 878,
+ -1, -1, -1, -1,
+ /*0xa722*/ 1065,
+ -1,
+ /*0x2cb4*/ 1001,
+ /*0x023e*/ 219,
+ -1,
+ /*0x1fbe*/ 826,
+ -1,
+ /*0x052c*/ 443,
+ -1,
+ /*0x1eb8*/ 680,
+ /*0x1e38*/ 614,
+ /*0x1cb2*/ 574,
+ -1,
+ /*0xabbe*/ 1236,
+ -1,
+ /*0x1fbc*/ 825,
+ -1, -1,
+ /*0x1eaa*/ 673,
+ /*0x1e2a*/ 607,
+ /*0xa7b4*/ 1134,
+ -1, -1,
+ /*0xabbc*/ 1234,
+ -1, -1,
+ /*0x2cbe*/ 1006,
+ -1,
+ /*0x1f1a*/ 726,
+ -1, -1,
+ /*0xa688*/ 1055,
+ /*0x1f8d*/ 781,
+ /*0x1040d*/ 1289,
+ /*0x040d*/ 310,
+ /*0x16e5f*/ 1523,
+ /*0x2cbc*/ 1005,
+ /*0x049c*/ 371,
+ -1,
+ /*0x118a2*/ 1462,
+ /*0xab8d*/ 1187,
+ /*0x2c0d*/ 925,
+ -1, -1,
+ /*0xa7be*/ 1139,
+ -1, -1, -1,
+ /*0xa68a*/ 1056,
+ -1, -1, -1,
+ /*0x104c7*/ 1339,
+ /*0x04c7*/ 393,
+ /*0xa7bc*/ 1138,
+ /*0x01bc*/ 156,
+ -1,
+ /*0x10c7*/ 522,
+ -1,
+ /*0x049e*/ 372,
+ /*0x1cba*/ 582,
+ -1,
+ /*0xa680*/ 1051,
+ /*0x0528*/ 441,
+ /*0x1eae*/ 675,
+ /*0x1e2e*/ 609,
+ -1,
+ /*0x1cb6*/ 578,
+ -1, -1,
+ /*0x16e5d*/ 1521,
+ /*0xa78d*/ 1112,
+ /*0x1f1d*/ 729,
+ /*0x10c8d*/ 1400,
+ -1, -1, -1, -1,
+ /*0x1eac*/ 674,
+ /*0x1e2c*/ 608,
+ /*0x050e*/ 428,
+ /*0x1eb0*/ 676,
+ /*0x1e30*/ 610,
+ /*0x1e90d*/ 1562,
+ -1, -1,
+ /*0x1f1c*/ 728,
+ /*0x0532*/ 446,
+ /*0x10588*/ 1375,
+ -1, -1, -1, -1,
+ /*0x10589*/ 1376,
+ /*0x104b8*/ 1324,
+ /*0x04b8*/ 385,
+ /*0x0053*/ 17,
+ /*0x1fd3*/ 838,
+ -1,
+ /*0x10b8*/ 508,
+ -1, -1, -1, -1,
+ /*0x04aa*/ 378,
+ /*0x1058a*/ 1377,
+ /*0x0052*/ 16,
+ /*0x1fd2*/ 837,
+ /*0x10aa*/ 494,
+ -1,
+ /*0x0152*/ 97,
+ -1, -1, -1, -1,
+ /*0x024c*/ 227,
+ /*0x004c*/ 10,
+ /*0x1fcc*/ 836,
+ /*0xa686*/ 1054,
+ /*0x10580*/ 1367,
+ /*0x014c*/ 94,
+ -1, -1,
+ /*0x10583*/ 1370,
+ -1, -1, -1, -1,
+ /*0x2cd2*/ 1016,
+ -1,
+ /*0x16ea0*/ 1524,
+ /*0xa738*/ 1075,
+ /*0xa696*/ 1062,
+ -1,
+ /*0x1ea8*/ 672,
+ /*0x1e28*/ 606,
+ /*0x053a*/ 454,
+ /*0x01d3*/ 166,
+ /*0x2ccc*/ 1013,
+ -1,
+ /*0xa72a*/ 1069,
+ /*0x1cb4*/ 576,
+ -1,
+ /*0x0536*/ 450,
+ /*0x1f38*/ 738,
+ -1,
+ /*0xa7d2*/ 1151,
+ -1, -1, -1,
+ /*0x04ae*/ 380,
+ /*0x1e8e*/ 657,
+ /*0x1e0e*/ 593,
+ /*0x1f2a*/ 732,
+ /*0x10ae*/ 498,
+ -1,
+ /*0xa7cc*/ 1148,
+ -1,
+ /*0x1eb2*/ 677,
+ /*0x1e32*/ 611,
+ /*0x050c*/ 427,
+ /*0x0244*/ 222,
+ /*0x0044*/ 3,
+ /*0x1fc4*/ 829,
+ /*0x04ac*/ 379,
+ /*0x1cbe*/ 584,
+ /*0x104b0*/ 1316,
+ /*0x04b0*/ 381,
+ /*0x10ac*/ 496,
+ -1,
+ /*0x118b8*/ 1484,
+ /*0x10b0*/ 500,
+ -1,
+ /*0x16e5b*/ 1519,
+ -1,
+ /*0x10586*/ 1373,
+ -1,
+ /*0xa694*/ 1061,
+ -1,
+ /*0x118aa*/ 1470,
+ -1,
+ /*0xff26*/ 1255,
+ -1, -1,
+ /*0x2cc4*/ 1009,
+ -1,
+ /*0xa72e*/ 1071,
+ -1,
+ /*0x10af*/ 499,
+ -1,
+ /*0x212a*/ 866,
+ -1,
+ /*0xa690*/ 1059,
+ -1, -1,
+ /*0xff24*/ 1253,
+ /*0x16ea6*/ 1530,
+ -1, -1,
+ /*0x1f2e*/ 736,
+ /*0xa72c*/ 1070,
+ /*0x00d3*/ 45,
+ /*0xa7c4*/ 1142,
+ /*0x01c4*/ 157,
+ -1, -1,
+ /*0xa684*/ 1053,
+ /*0x1eba*/ 681,
+ /*0x1e3a*/ 615,
+ -1,
+ /*0x16ea4*/ 1528,
+ /*0x00d2*/ 44,
+ -1,
+ /*0x1f2c*/ 734,
+ /*0x1eb6*/ 679,
+ /*0x1e36*/ 613,
+ -1,
+ /*0x0534*/ 448,
+ -1, -1,
+ /*0x04a8*/ 377,
+ /*0x00cc*/ 38,
+ -1, -1,
+ /*0x10a8*/ 492,
+ /*0x118ae*/ 1474,
+ -1, -1,
+ /*0x16e57*/ 1515,
+ -1, -1,
+ /*0x1e8c*/ 656,
+ /*0x1e0c*/ 592,
+ /*0x1f2f*/ 737,
+ /*0x10594*/ 1385,
+ -1, -1,
+ /*0x048e*/ 364,
+ -1,
+ /*0x118ac*/ 1472,
+ /*0xff22*/ 1251,
+ /*0x053e*/ 458,
+ /*0x118b0*/ 1476,
+ /*0x104b2*/ 1318,
+ /*0x04b2*/ 382,
+ -1, -1, -1,
+ /*0x10b2*/ 502,
+ /*0x10590*/ 1382,
+ /*0xa682*/ 1052,
+ /*0x053c*/ 456,
+ /*0x024a*/ 226,
+ /*0x004a*/ 8,
+ /*0x1fca*/ 834,
+ /*0x16ea2*/ 1526,
+ /*0xa728*/ 1068,
+ /*0x014a*/ 93,
+ -1,
+ /*0x118af*/ 1475,
+ -1,
+ /*0x24c7*/ 903,
+ -1,
+ /*0x10584*/ 1371,
+ -1,
+ /*0x0042*/ 1,
+ /*0x1fc2*/ 827,
+ /*0x00c4*/ 30,
+ -1,
+ /*0x1f28*/ 730,
+ /*0x1fab*/ 811,
+ -1,
+ /*0x042b*/ 340,
+ -1, -1,
+ /*0x2cca*/ 1012,
+ -1,
+ /*0x03c2*/ 269,
+ /*0xabab*/ 1217,
+ /*0x2c2b*/ 955,
+ /*0xa732*/ 1072,
+ /*0x03ab*/ 267,
+ -1, -1, -1,
+ /*0xa698*/ 1063,
+ /*0x1f0e*/ 722,
+ /*0x2cc2*/ 1008,
+ /*0x1eb4*/ 678,
+ /*0x1e34*/ 612,
+ /*0x16e59*/ 1517,
+ -1,
+ /*0x104ba*/ 1326,
+ /*0x04ba*/ 386,
+ /*0x01ca*/ 161,
+ /*0x118a8*/ 1468,
+ -1,
+ /*0x10ba*/ 510,
+ -1,
+ /*0x104b6*/ 1322,
+ /*0x04b6*/ 384,
+ -1, -1,
+ /*0x24b8*/ 888,
+ /*0x10b6*/ 506,
+ /*0xa7c2*/ 1141,
+ -1,
+ /*0x10582*/ 1369,
+ -1,
+ /*0xa7ab*/ 1126,
+ -1,
+ /*0x10cab*/ 1430,
+ /*0x1ebe*/ 683,
+ /*0x1e3e*/ 617,
+ -1,
+ /*0x024e*/ 228,
+ /*0x004e*/ 12,
+ /*0x048c*/ 363,
+ -1,
+ /*0x118b2*/ 1478,
+ /*0x014e*/ 95,
+ /*0x10585*/ 1372,
+ /*0x1ebc*/ 682,
+ /*0x1e3c*/ 616,
+ -1, -1, -1,
+ /*0x0056*/ 20,
+ /*0x1fd6*/ 839,
+ /*0xa73a*/ 1076,
+ /*0x2132*/ 868,
+ /*0x0156*/ 99,
+ /*0xa692*/ 1060,
+ /*0x0553*/ 479,
+ -1, -1,
+ /*0xa736*/ 1074,
+ -1,
+ /*0x2cce*/ 1014,
+ /*0x03d6*/ 274,
+ -1, -1,
+ /*0x1f3a*/ 740,
+ /*0x0552*/ 478,
+ -1, -1, -1,
+ /*0x0050*/ 14,
+ -1,
+ /*0x2cd6*/ 1018,
+ -1,
+ /*0x0150*/ 96,
+ -1,
+ /*0x054c*/ 472,
+ -1, -1,
+ /*0xa7ce*/ 1149,
+ -1,
+ /*0x00ca*/ 36,
+ /*0x03d0*/ 271,
+ -1,
+ /*0x0248*/ 225,
+ /*0x0048*/ 7,
+ /*0x1fc8*/ 832,
+ -1, -1,
+ /*0x1f0c*/ 720,
+ /*0xa7d6*/ 1153,
+ /*0x118ba*/ 1486,
+ /*0x2cd0*/ 1015,
+ /*0x00c2*/ 28,
+ /*0xff38*/ 1273,
+ -1,
+ /*0x104b4*/ 1320,
+ /*0x04b4*/ 383,
+ /*0x118b6*/ 1482,
+ -1, -1,
+ /*0x10b4*/ 504,
+ -1,
+ /*0xff2a*/ 1259,
+ /*0x0246*/ 224,
+ /*0x0046*/ 5,
+ /*0x1fc6*/ 830,
+ /*0x2cc8*/ 1011,
+ -1,
+ /*0x16eb8*/ 1548,
+ /*0xa7d0*/ 1150,
+ -1,
+ /*0x10592*/ 1384,
+ -1, -1, -1, -1, -1,
+ /*0x16eaa*/ 1534,
+ -1,
+ /*0x104be*/ 1330,
+ /*0x04be*/ 388,
+ /*0x0544*/ 464,
+ -1, -1,
+ /*0x10be*/ 514,
+ /*0x01c8*/ 160,
+ /*0x2cc6*/ 1010,
+ /*0x005a*/ 24,
+ /*0x1fda*/ 843,
+ /*0x104bc*/ 1328,
+ /*0x04bc*/ 387,
+ /*0x015a*/ 101,
+ /*0xa734*/ 1073,
+ /*0x2cc0*/ 1007,
+ /*0x10bc*/ 512,
+ -1,
+ /*0x1ed2*/ 693,
+ /*0x1e52*/ 627,
+ /*0x0054*/ 18,
+ /*0x03da*/ 276,
+ -1, -1,
+ /*0x0154*/ 98,
+ /*0x00ce*/ 40,
+ /*0xa7c6*/ 1144,
+ /*0xa652*/ 1037,
+ /*0x1ecc*/ 690,
+ /*0x1e4c*/ 624,
+ /*0xff2e*/ 1263,
+ /*0x2cda*/ 1020,
+ -1,
+ /*0xa7c0*/ 1140,
+ /*0x1cab*/ 567,
+ -1,
+ /*0x00d6*/ 48,
+ /*0xa64c*/ 1034,
+ /*0xa73e*/ 1078,
+ -1, -1, -1,
+ /*0x2cd4*/ 1017,
+ -1,
+ /*0xff2c*/ 1261,
+ /*0x16eae*/ 1538,
+ -1,
+ /*0xff30*/ 1265,
+ /*0xa73c*/ 1077,
+ /*0xa7da*/ 1155,
+ -1,
+ /*0x1f3e*/ 744,
+ -1,
+ /*0x118b4*/ 1480,
+ /*0xa69a*/ 1064,
+ -1,
+ /*0x00d0*/ 42,
+ -1, -1,
+ /*0x16eac*/ 1536,
+ /*0xa7d4*/ 1152,
+ /*0x1f3c*/ 742,
+ /*0x16eb0*/ 1540,
+ -1,
+ /*0xff2f*/ 1264,
+ -1, -1, -1, -1, -1, -1,
+ /*0x00c8*/ 34,
+ -1, -1,
+ /*0x1ec4*/ 686,
+ /*0x1e44*/ 620,
+ -1,
+ /*0x118be*/ 1490,
+ /*0x1f0d*/ 721,
+ /*0x16eaf*/ 1539,
+ /*0x0058*/ 22,
+ /*0x1fd8*/ 841,
+ -1,
+ /*0xa644*/ 1030,
+ /*0x0158*/ 100,
+ /*0x0245*/ 223,
+ /*0x0045*/ 4,
+ /*0x118bc*/ 1488,
+ -1, -1,
+ /*0x0145*/ 90,
+ /*0x00c6*/ 32,
+ /*0x03d8*/ 275,
+ /*0x104d3*/ 1351,
+ /*0x054a*/ 470,
+ -1, -1, -1,
+ /*0x00c0*/ 26,
+ -1,
+ /*0xff28*/ 1257,
+ /*0x10d53*/ 1441,
+ /*0x2cd8*/ 1019,
+ /*0x104d2*/ 1350,
+ /*0x04d2*/ 398,
+ /*0x24ba*/ 890,
+ /*0x0542*/ 462,
+ -1, -1, -1, -1,
+ /*0x10d52*/ 1440,
+ /*0x24b6*/ 886,
+ /*0x104cc*/ 1344,
+ /*0x00da*/ 51,
+ /*0x16ea8*/ 1532,
+ -1, -1, -1, -1,
+ /*0xa7d8*/ 1154,
+ /*0x1fa9*/ 809,
+ -1,
+ /*0x0429*/ 338,
+ /*0xff32*/ 1267,
+ /*0x00d4*/ 46,
+ /*0xa7c5*/ 1143,
+ /*0x01c5*/ 158,
+ -1,
+ /*0xaba9*/ 1215,
+ /*0x2c29*/ 953,
+ -1,
+ /*0x03a9*/ 265,
+ -1, -1,
+ /*0x1fe2*/ 845,
+ /*0x16e47*/ 1499,
+ /*0x0462*/ 346,
+ /*0x0162*/ 105,
+ /*0x16eb2*/ 1542,
+ /*0xa752*/ 1088,
+ -1, -1, -1,
+ /*0x2c62*/ 961,
+ -1,
+ /*0x03e2*/ 280,
+ -1, -1, -1,
+ /*0xa74c*/ 1085,
+ -1, -1,
+ /*0x1f52*/ 753,
+ /*0x0345*/ 229,
+ -1,
+ /*0x2ce2*/ 1024,
+ /*0x054e*/ 474,
+ /*0x0055*/ 19,
+ /*0x104c4*/ 1336,
+ -1,
+ /*0x01a9*/ 146,
+ /*0x10ca9*/ 1428,
+ /*0x1f4c*/ 750,
+ /*0x10c4*/ 520,
+ /*0x1eca*/ 689,
+ /*0x1e4a*/ 623,
+ -1,
+ /*0x0556*/ 482,
+ -1,
+ /*0x03d5*/ 273,
+ -1, -1,
+ /*0xff3a*/ 1275,
+ /*0xa64a*/ 1033,
+ /*0x01e2*/ 173,
+ -1,
+ /*0x1ec2*/ 685,
+ /*0x1e42*/ 619,
+ -1,
+ /*0xff36*/ 1271,
+ /*0x1fa1*/ 801,
+ /*0x10421*/ 1309,
+ /*0x0421*/ 330,
+ -1,
+ /*0x00d8*/ 49,
+ /*0xa642*/ 1029,
+ -1,
+ /*0x0550*/ 476,
+ /*0xaba1*/ 1207,
+ /*0x2c21*/ 945,
+ /*0x00c5*/ 31,
+ /*0x03a1*/ 258,
+ -1, -1,
+ /*0x16eb6*/ 1546,
+ /*0xa744*/ 1081,
+ -1, -1,
+ /*0x01d5*/ 167,
+ /*0x1fa5*/ 805,
+ /*0x10425*/ 1313,
+ /*0x0425*/ 334,
+ /*0x0548*/ 468,
+ /*0x1fad*/ 813,
+ -1,
+ /*0x042d*/ 342,
+ -1,
+ /*0xaba5*/ 1211,
+ /*0x2c25*/ 949,
+ /*0x24be*/ 894,
+ /*0x03a5*/ 261,
+ /*0xabad*/ 1219,
+ /*0x2c2d*/ 957,
+ -1, -1, -1, -1, -1, -1,
+ /*0x24bc*/ 892,
+ -1,
+ /*0x10ca1*/ 1420,
+ /*0x0546*/ 466,
+ -1,
+ /*0x1fa3*/ 803,
+ /*0x10423*/ 1311,
+ /*0x0423*/ 332,
+ /*0x1ece*/ 691,
+ /*0x1e4e*/ 625,
+ /*0x0540*/ 460,
+ -1,
+ /*0x1e921*/ 1582,
+ /*0xaba3*/ 1209,
+ /*0x2c23*/ 947,
+ /*0x004d*/ 11,
+ /*0x03a3*/ 259,
+ /*0xa64e*/ 1035,
+ -1,
+ /*0x1ed6*/ 695,
+ /*0x1e56*/ 629,
+ /*0x10ca5*/ 1424,
+ -1,
+ /*0xa7ad*/ 1128,
+ /*0x1fe4*/ 847,
+ /*0x10cad*/ 1432,
+ /*0x0464*/ 347,
+ /*0x0164*/ 106,
+ /*0xa656*/ 1039,
+ -1,
+ /*0x104ca*/ 1342,
+ -1, -1,
+ /*0x2c64*/ 963,
+ /*0xff34*/ 1269,
+ /*0x03e4*/ 281,
+ -1,
+ /*0x0554*/ 480,
+ -1,
+ /*0x1ed0*/ 692,
+ /*0x1e50*/ 626,
+ -1,
+ /*0x104c2*/ 1334,
+ /*0x00d5*/ 47,
+ -1, -1,
+ /*0x10ca3*/ 1422,
+ /*0x10c2*/ 518,
+ /*0xa650*/ 1036,
+ /*0x16eb4*/ 1544,
+ -1,
+ /*0x10ab*/ 495,
+ -1, -1,
+ /*0x1ec8*/ 688,
+ /*0x1e48*/ 622,
+ /*0x01cd*/ 163,
+ -1, -1, -1, -1,
+ /*0x1ca9*/ 565,
+ -1,
+ /*0xa648*/ 1032,
+ /*0x01e4*/ 174,
+ -1, -1,
+ /*0xa74a*/ 1084,
+ -1, -1, -1, -1, -1, -1,
+ /*0x1ec6*/ 687,
+ /*0x1e46*/ 621,
+ -1, -1, -1,
+ /*0xa742*/ 1080,
+ /*0x1f4a*/ 748,
+ /*0x1ec0*/ 684,
+ /*0x1e40*/ 618,
+ /*0xa646*/ 1031,
+ -1, -1,
+ /*0x1f87*/ 775,
+ /*0x10407*/ 1283,
+ /*0x0407*/ 304,
+ /*0xab73*/ 1161,
+ /*0xa640*/ 1028,
+ -1,
+ /*0xa68e*/ 1058,
+ /*0x104ce*/ 1346,
+ /*0xab87*/ 1181,
+ /*0x2c07*/ 919,
+ /*0x1f2b*/ 733,
+ /*0x1eda*/ 697,
+ /*0x1e5a*/ 631,
+ -1, -1, -1,
+ /*0x24cc*/ 908,
+ /*0x0545*/ 465,
+ -1,
+ /*0x04d6*/ 400,
+ /*0xa65a*/ 1041,
+ -1,
+ /*0x1ed4*/ 694,
+ /*0x1e54*/ 628,
+ /*0x015e*/ 103,
+ -1,
+ /*0x10d56*/ 1444,
+ -1,
+ /*0x0243*/ 221,
+ /*0x0043*/ 2,
+ /*0x1fc3*/ 828,
+ /*0xa654*/ 1038,
+ /*0x03de*/ 278,
+ /*0x0143*/ 89,
+ /*0x00cd*/ 39,
+ /*0x1ca1*/ 557,
+ /*0x118ab*/ 1471,
+ -1,
+ /*0x104d0*/ 1348,
+ /*0x04d0*/ 397,
+ /*0x0187*/ 125,
+ /*0x10c87*/ 1394,
+ /*0x2cde*/ 1022,
+ -1,
+ /*0xa74e*/ 1086,
+ /*0xab71*/ 1159,
+ /*0x10d50*/ 1438,
+ /*0x212b*/ 867,
+ /*0x015c*/ 102,
+ -1, -1,
+ /*0x1e907*/ 1556,
+ -1,
+ /*0x104c8*/ 1340,
+ /*0x1ca5*/ 561,
+ /*0xa756*/ 1090,
+ /*0x03dc*/ 277,
+ -1,
+ /*0x1cad*/ 569,
+ /*0x004b*/ 9,
+ /*0x1fcb*/ 835,
+ /*0x01de*/ 171,
+ /*0x24c4*/ 900,
+ /*0x1058e*/ 1380,
+ -1, -1,
+ /*0x2cdc*/ 1021,
+ /*0x1fec*/ 854,
+ /*0x1f56*/ 755,
+ /*0x046c*/ 351,
+ /*0x016c*/ 110,
+ -1, -1,
+ /*0x104c6*/ 1338,
+ /*0xab7b*/ 1169,
+ /*0xa750*/ 1087,
+ -1, -1,
+ /*0x03ec*/ 285,
+ /*0x1ca3*/ 559,
+ /*0x104c0*/ 1332,
+ /*0x04c0*/ 389,
+ /*0x1ed8*/ 696,
+ /*0x1e58*/ 630,
+ /*0xa7dc*/ 1156,
+ /*0x10c0*/ 516,
+ /*0xa68c*/ 1057,
+ -1,
+ /*0x1f50*/ 752,
+ /*0x0555*/ 481,
+ /*0xa748*/ 1083,
+ /*0xa658*/ 1040,
+ -1, -1, -1, -1,
+ /*0xabb1*/ 1223,
+ /*0x04da*/ 402,
+ -1,
+ /*0xa7cb*/ 1147,
+ /*0x01cb*/ 162,
+ -1,
+ /*0xab7d*/ 1171,
+ /*0x1f48*/ 746,
+ /*0x10d5a*/ 1448,
+ -1, -1,
+ /*0x01ec*/ 178,
+ /*0x04d4*/ 399,
+ -1,
+ /*0xa746*/ 1082,
+ /*0x1f97*/ 791,
+ /*0x10417*/ 1299,
+ /*0x0417*/ 320,
+ -1,
+ /*0x10d54*/ 1442,
+ -1,
+ /*0xa740*/ 1079,
+ -1,
+ /*0xab97*/ 1197,
+ /*0x2c17*/ 935,
+ -1,
+ /*0x0397*/ 248,
+ /*0x0460*/ 345,
+ /*0x0160*/ 104,
+ /*0x00de*/ 55,
+ -1,
+ /*0xa7b1*/ 1131,
+ /*0x01b1*/ 150,
+ /*0x10cb1*/ 1436,
+ /*0x2c60*/ 960,
+ -1,
+ /*0x03e0*/ 279,
+ /*0xa75a*/ 1092,
+ /*0x00c3*/ 29,
+ -1,
+ /*0x1ee2*/ 701,
+ /*0x1e62*/ 635,
+ -1, -1,
+ /*0x1fb7*/ 820,
+ -1,
+ /*0x2ce0*/ 1023,
+ /*0x1058c*/ 1378,
+ /*0xa754*/ 1089,
+ /*0xa662*/ 1045,
+ -1,
+ /*0xab77*/ 1165,
+ /*0xabb7*/ 1229,
+ /*0x00dc*/ 53,
+ /*0xab7f*/ 1173,
+ /*0x0197*/ 136,
+ /*0x10c97*/ 1410,
+ /*0x24ca*/ 906,
+ -1, -1,
+ /*0x1fea*/ 852,
+ /*0x1f54*/ 754,
+ /*0x046a*/ 350,
+ /*0x016a*/ 109,
+ /*0x1c87*/ 537,
+ /*0x01e0*/ 172,
+ /*0x1e917*/ 1572,
+ -1,
+ /*0x00cb*/ 37,
+ /*0x24c2*/ 898,
+ /*0x054d*/ 473,
+ /*0x03ea*/ 284,
+ /*0x04d8*/ 401,
+ -1,
+ /*0x0470*/ 353,
+ /*0x0170*/ 112,
+ -1,
+ /*0x104c5*/ 1337,
+ /*0x04c5*/ 392,
+ /*0x10d58*/ 1446,
+ -1,
+ /*0x2c70*/ 970,
+ /*0x10c5*/ 521,
+ /*0x03f0*/ 287,
+ /*0x01b7*/ 154,
+ /*0x1fe8*/ 850,
+ -1,
+ /*0x0468*/ 349,
+ /*0x0168*/ 108,
+ -1,
+ /*0x046e*/ 352,
+ /*0x016e*/ 111,
+ -1, -1, -1, -1,
+ /*0x03e8*/ 283,
+ /*0x2c6e*/ 968,
+ -1,
+ /*0x03ee*/ 286,
+ /*0x01ea*/ 177,
+ -1,
+ /*0x1ff2*/ 855,
+ -1,
+ /*0x0472*/ 354,
+ /*0x0172*/ 113,
+ -1,
+ /*0x1fe6*/ 848,
+ /*0xa758*/ 1091,
+ /*0x0466*/ 348,
+ /*0x0166*/ 107,
+ /*0x2c72*/ 971,
+ /*0x01f0*/ 180,
+ /*0xfb17*/ 1249,
+ /*0x1fb9*/ 822,
+ -1,
+ /*0x10a9*/ 493,
+ /*0x0139*/ 84,
+ /*0x03e6*/ 282,
+ -1,
+ /*0x24ce*/ 910,
+ -1,
+ /*0xabb9*/ 1231,
+ /*0x2cf2*/ 1027,
+ /*0x1fb3*/ 817,
+ /*0x01e8*/ 176,
+ /*0x04e2*/ 406,
+ -1,
+ /*0x01ee*/ 179,
+ -1, -1, -1,
+ /*0xabb3*/ 1225,
+ /*0x10d62*/ 1456,
+ -1, -1, -1, -1, -1,
+ /*0x0370*/ 230,
+ -1,
+ /*0xff2b*/ 1260,
+ /*0x01f2*/ 182,
+ -1,
+ /*0x0049*/ 1583,
+ /*0x1fc9*/ 833,
+ -1,
+ /*0x01e6*/ 175,
+ /*0x0149*/ 92,
+ /*0x1ee4*/ 702,
+ /*0x1e64*/ 636,
+ -1,
+ /*0x1cb1*/ 573,
+ -1, -1,
+ /*0x1058d*/ 1379,
+ /*0x16eab*/ 1535,
+ /*0x10d55*/ 1443,
+ /*0xa664*/ 1046,
+ -1, -1,
+ /*0x1f29*/ 731,
+ /*0xa762*/ 1096,
+ /*0xa7b3*/ 1133,
+ /*0x01b3*/ 152,
+ -1,
+ /*0x24c8*/ 904,
+ -1, -1,
+ /*0x0372*/ 231,
+ /*0x0543*/ 463,
+ /*0x16e53*/ 1511,
+ -1, -1, -1,
+ /*0x1c97*/ 547,
+ /*0x10a1*/ 485,
+ /*0x1ff4*/ 857,
+ -1,
+ /*0x0474*/ 355,
+ /*0x0174*/ 114,
+ /*0x16e52*/ 1510,
+ -1, -1,
+ /*0xa7c9*/ 1146,
+ -1,
+ /*0x24c6*/ 902,
+ /*0x118a9*/ 1469,
+ /*0x03f4*/ 289,
+ -1, -1,
+ /*0x16e4c*/ 1504,
+ -1,
+ /*0x24c0*/ 896,
+ -1,
+ /*0x10a5*/ 489,
+ -1, -1, -1,
+ /*0x10ad*/ 497,
+ /*0x054b*/ 471,
+ -1, -1, -1,
+ /*0x1cb7*/ 579,
+ /*0x013f*/ 87,
+ -1, -1, -1, -1,
+ /*0xabbf*/ 1237,
+ -1,
+ /*0x2162*/ 871,
+ /*0x1f9b*/ 795,
+ /*0x1041b*/ 1303,
+ /*0x041b*/ 324,
+ -1,
+ /*0x01f4*/ 183,
+ -1, -1,
+ /*0x10a3*/ 487,
+ /*0xab9b*/ 1201,
+ /*0x2c1b*/ 939,
+ -1,
+ /*0x039b*/ 252,
+ -1,
+ /*0x104cd*/ 1345,
+ /*0x04cd*/ 396,
+ /*0x0531*/ 445,
+ -1, -1,
+ /*0x10cd*/ 523,
+ /*0x1ede*/ 699,
+ /*0x1e5e*/ 633,
+ -1,
+ /*0x04e4*/ 407,
+ -1,
+ /*0x16e44*/ 1496,
+ -1, -1, -1,
+ /*0xa65e*/ 1043,
+ /*0x10d64*/ 1458,
+ -1,
+ /*0x1f2d*/ 735,
+ /*0xab79*/ 1167,
+ -1,
+ /*0x118a1*/ 1461,
+ -1,
+ /*0x00c9*/ 35,
+ -1,
+ /*0x1f99*/ 793,
+ /*0x10419*/ 1301,
+ /*0x0419*/ 322,
+ /*0x10c9b*/ 1414,
+ -1,
+ /*0x1edc*/ 698,
+ /*0x1e5c*/ 632,
+ -1,
+ /*0xab99*/ 1199,
+ /*0x2c19*/ 937,
+ -1,
+ /*0x0399*/ 250,
+ -1,
+ /*0x1e91b*/ 1576,
+ /*0xa65c*/ 1042,
+ /*0x118a5*/ 1465,
+ -1, -1, -1,
+ /*0x118ad*/ 1473,
+ /*0xa764*/ 1097,
+ /*0x023d*/ 218,
+ -1,
+ /*0x1cb9*/ 581,
+ -1,
+ /*0x1f4d*/ 751,
+ /*0x013d*/ 86,
+ /*0x1eec*/ 706,
+ /*0x1e6c*/ 640,
+ /*0x0537*/ 451,
+ -1,
+ /*0xabbd*/ 1235,
+ -1,
+ /*0x1cb3*/ 575,
+ -1,
+ /*0x24c5*/ 901,
+ /*0xa66c*/ 1050,
+ /*0x0241*/ 220,
+ /*0x0041*/ 0,
+ -1,
+ /*0x118a3*/ 1463,
+ /*0x10c99*/ 1412,
+ /*0x0141*/ 88,
+ -1,
+ /*0x1f91*/ 785,
+ /*0x10411*/ 1293,
+ /*0x0411*/ 314,
+ -1, -1, -1, -1,
+ /*0x1e919*/ 1574,
+ /*0xab91*/ 1191,
+ /*0x2c11*/ 929,
+ -1,
+ /*0x0391*/ 242,
+ /*0x10570*/ 1352,
+ -1,
+ /*0x023b*/ 217,
+ -1,
+ /*0x1fbb*/ 824,
+ -1,
+ /*0xab7c*/ 1170,
+ /*0x013b*/ 85,
+ -1, -1, -1,
+ /*0x04de*/ 404,
+ /*0xabbb*/ 1233,
+ /*0xabb5*/ 1227,
+ /*0x2164*/ 873,
+ /*0x1e97*/ 662,
+ -1, -1,
+ /*0x10d5e*/ 1452,
+ /*0x104c3*/ 1335,
+ /*0x04c3*/ 391,
+ /*0x16e4a*/ 1502,
+ -1, -1,
+ /*0x10c3*/ 519,
+ /*0x1ee0*/ 700,
+ /*0x1e60*/ 634,
+ -1,
+ /*0x0191*/ 132,
+ /*0x10c91*/ 1404,
+ /*0x10572*/ 1354,
+ -1, -1,
+ /*0x16e42*/ 1494,
+ /*0xa660*/ 1044,
+ /*0x04dc*/ 403,
+ -1,
+ /*0x047e*/ 360,
+ -1,
+ /*0x1e911*/ 1566,
+ -1, -1,
+ /*0x10d5c*/ 1450,
+ /*0x0539*/ 453,
+ /*0x2c7e*/ 973,
+ /*0x01b5*/ 153,
+ /*0x03fe*/ 295,
+ /*0xa75e*/ 1094,
+ -1,
+ /*0x104cb*/ 1343,
+ /*0x04cb*/ 395,
+ -1, -1,
+ /*0x0533*/ 447,
+ -1,
+ /*0x1cbf*/ 585,
+ -1,
+ /*0x04ec*/ 411,
+ -1, -1,
+ /*0x1eea*/ 705,
+ /*0x1e6a*/ 639,
+ -1, -1, -1, -1,
+ /*0x1c9b*/ 551,
+ -1, -1,
+ /*0xa66a*/ 1049,
+ -1,
+ /*0xa75c*/ 1093,
+ /*0x1ef0*/ 708,
+ /*0x1e70*/ 642,
+ /*0x0549*/ 469,
+ /*0x01fe*/ 189,
+ -1,
+ /*0x104b1*/ 1317,
+ -1, -1, -1,
+ /*0xff29*/ 1258,
+ /*0x10b1*/ 501,
+ -1,
+ /*0x16e4e*/ 1506,
+ /*0x1ee8*/ 704,
+ /*0x1e68*/ 638,
+ /*0x00c1*/ 27,
+ /*0x1eee*/ 707,
+ /*0x1e6e*/ 641,
+ -1, -1, -1,
+ /*0xa76c*/ 1101,
+ /*0xa668*/ 1048,
+ /*0x16e56*/ 1514,
+ /*0x16ea9*/ 1533,
+ -1, -1,
+ /*0x1f4b*/ 749,
+ -1, -1,
+ /*0x1ef2*/ 709,
+ /*0x1e72*/ 643,
+ /*0x1c99*/ 549,
+ /*0x10574*/ 1356,
+ /*0x1f6c*/ 764,
+ /*0x1ee6*/ 703,
+ /*0x1e66*/ 637,
+ /*0x00b5*/ 25,
+ -1,
+ /*0x04e0*/ 405,
+ -1,
+ /*0x004f*/ 13,
+ -1,
+ /*0x16e50*/ 1508,
+ /*0xa666*/ 1047,
+ -1,
+ /*0x10d60*/ 1454,
+ -1, -1, -1, -1, -1, -1,
+ /*0x03cf*/ 270,
+ -1,
+ /*0x1cbd*/ 583,
+ /*0x24cd*/ 909,
+ /*0x104b7*/ 1323,
+ /*0x16e48*/ 1500,
+ /*0x053f*/ 459,
+ -1, -1,
+ /*0x10b7*/ 507,
+ -1, -1, -1, -1, -1, -1,
+ /*0xff21*/ 1250,
+ -1,
+ /*0x216c*/ 881,
+ -1, -1,
+ /*0x04ea*/ 410,
+ /*0xa760*/ 1095,
+ /*0x1c91*/ 541,
+ /*0x1ff6*/ 858,
+ /*0x16e46*/ 1498,
+ /*0x0476*/ 356,
+ /*0x0176*/ 115,
+ /*0x118b1*/ 1477,
+ /*0x01cf*/ 164,
+ -1,
+ /*0x16ea1*/ 1525,
+ /*0x16e40*/ 1492,
+ /*0x04f0*/ 413,
+ -1,
+ /*0xff25*/ 1254,
+ /*0x1f95*/ 789,
+ /*0x10415*/ 1297,
+ /*0x0415*/ 318,
+ /*0xff2d*/ 1262,
+ /*0x1cb5*/ 577,
+ /*0xab75*/ 1163,
+ -1, -1,
+ /*0xab95*/ 1195,
+ /*0x2c15*/ 933,
+ /*0x04e8*/ 409,
+ /*0x0395*/ 246,
+ /*0x16e5a*/ 1518,
+ /*0x04ee*/ 412,
+ /*0x16ea5*/ 1529,
+ -1,
+ /*0x1ef4*/ 710,
+ /*0x1e74*/ 644,
+ /*0x16ead*/ 1537,
+ -1,
+ /*0x1ffa*/ 862,
+ /*0xa76a*/ 1100,
+ /*0x047a*/ 358,
+ /*0x16e54*/ 1512,
+ /*0xff23*/ 1252,
+ -1, -1,
+ /*0x04f2*/ 414,
+ /*0x01f6*/ 184,
+ -1, -1,
+ /*0x03fa*/ 293,
+ /*0x04e6*/ 408,
+ /*0x0051*/ 15,
+ /*0x1f6a*/ 762,
+ -1,
+ /*0x2160*/ 869,
+ /*0x13fa*/ 526,
+ /*0x104b9*/ 1325,
+ /*0x16ea3*/ 1527,
+ -1,
+ /*0x10c95*/ 1408,
+ /*0x053d*/ 457,
+ /*0x10b9*/ 509,
+ /*0x118b7*/ 1483,
+ /*0x03d1*/ 272,
+ /*0xa768*/ 1099,
+ -1,
+ /*0x104b3*/ 1319,
+ /*0xa76e*/ 1102,
+ -1,
+ /*0x1e915*/ 1570,
+ /*0x1e9b*/ 666,
+ /*0x10b3*/ 503,
+ -1,
+ /*0x0376*/ 232,
+ -1,
+ /*0x00cf*/ 41,
+ /*0x0541*/ 461,
+ /*0x1f68*/ 760,
+ /*0x01fa*/ 187,
+ -1,
+ /*0x1f6e*/ 766,
+ -1,
+ /*0x1f93*/ 787,
+ /*0x10413*/ 1295,
+ /*0x0413*/ 316,
+ /*0x24c3*/ 899,
+ /*0xa766*/ 1098,
+ /*0x104c9*/ 1341,
+ /*0x04c9*/ 394,
+ /*0x216a*/ 879,
+ /*0xab93*/ 1193,
+ /*0x2c13*/ 931,
+ /*0x01d1*/ 165,
+ /*0x0393*/ 244,
+ /*0x1f8f*/ 783,
+ /*0x1040f*/ 1291,
+ /*0x040f*/ 312,
+ /*0x053b*/ 455,
+ /*0x0535*/ 449,
+ -1, -1,
+ /*0x16e58*/ 1516,
+ /*0xab8f*/ 1189,
+ /*0x2c0f*/ 927,
+ -1,
+ /*0x038f*/ 240,
+ /*0x1f39*/ 739,
+ /*0x16e45*/ 1497,
+ /*0x1e99*/ 664,
+ -1,
+ /*0x1f81*/ 769,
+ /*0x10401*/ 1277,
+ /*0x0401*/ 298,
+ -1,
+ /*0x2168*/ 877,
+ /*0x24cb*/ 907,
+ /*0xfb15*/ 1247,
+ /*0x216e*/ 883,
+ /*0xab81*/ 1175,
+ /*0x2c01*/ 913,
+ /*0x04f4*/ 415,
+ -1,
+ /*0x0193*/ 133,
+ /*0x10c93*/ 1406,
+ -1, -1,
+ /*0x1ff8*/ 860,
+ /*0x1057e*/ 1365,
+ /*0x0478*/ 357,
+ /*0x0178*/ 116,
+ -1, -1,
+ /*0x118b9*/ 1485,
+ /*0x1e913*/ 1568,
+ /*0x018f*/ 130,
+ /*0x10c8f*/ 1402,
+ /*0x2166*/ 875,
+ /*0x1f49*/ 747,
+ -1, -1, -1, -1,
+ /*0x118b3*/ 1479,
+ /*0x13f8*/ 524,
+ /*0x104bf*/ 1331,
+ /*0x1e90f*/ 1564,
+ /*0x1f9f*/ 799,
+ /*0x1041f*/ 1307,
+ /*0x041f*/ 328,
+ /*0x10bf*/ 515,
+ /*0x0181*/ 121,
+ /*0x10c81*/ 1388,
+ -1, -1,
+ /*0xab9f*/ 1205,
+ /*0x2c1f*/ 943,
+ /*0x00d1*/ 43,
+ /*0x039f*/ 256,
+ -1, -1, -1,
+ /*0x1e901*/ 1550,
+ /*0x1f8b*/ 779,
+ /*0x1040b*/ 1287,
+ /*0x040b*/ 308,
+ -1,
+ /*0x01f8*/ 186,
+ -1, -1, -1,
+ /*0xab8b*/ 1185,
+ /*0x2c0b*/ 923,
+ -1, -1, -1, -1, -1, -1,
+ /*0x1c95*/ 545,
+ /*0x16e55*/ 1513,
+ /*0xfb13*/ 1245,
+ -1, -1, -1, -1, -1,
+ /*0x019f*/ 140,
+ /*0x10c9f*/ 1418,
+ -1, -1, -1, -1, -1, -1,
+ /*0x1f3f*/ 745,
+ /*0x24b7*/ 887,
+ -1,
+ /*0x1e91f*/ 1580,
+ -1,
+ /*0x1efe*/ 715,
+ /*0x1e7e*/ 649,
+ /*0xa78b*/ 1111,
+ /*0x018b*/ 128,
+ /*0x10c8b*/ 1398,
+ -1,
+ /*0x1f1b*/ 727,
+ -1,
+ /*0x054f*/ 475,
+ /*0xfb01*/ 1239,
+ -1, -1,
+ /*0xff31*/ 1266,
+ -1,
+ /*0x1e90b*/ 1560,
+ -1, -1,
+ /*0x104bd*/ 1329,
+ -1, -1, -1,
+ /*0x118bf*/ 1491,
+ /*0x10bd*/ 513,
+ -1, -1, -1, -1,
+ /*0x16eb1*/ 1541,
+ -1, -1, -1, -1, -1,
+ /*0x104c1*/ 1333,
+ /*0x04c1*/ 390,
+ -1, -1, -1,
+ /*0x10c1*/ 517,
+ -1, -1, -1,
+ /*0x10576*/ 1358,
+ /*0x1c93*/ 543,
+ /*0x1f19*/ 725,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1,
+ /*0x104bb*/ 1327,
+ /*0x104b5*/ 1321,
+ -1,
+ /*0x16e4d*/ 1505,
+ -1,
+ /*0x10bb*/ 511,
+ /*0x10b5*/ 505,
+ -1, -1, -1,
+ /*0xff37*/ 1272,
+ -1,
+ /*0x24b9*/ 889,
+ /*0x1f3d*/ 743,
+ -1, -1, -1,
+ /*0x1c81*/ 531,
+ -1, -1,
+ /*0x1057a*/ 1362,
+ -1, -1, -1, -1,
+ /*0x16eb7*/ 1547,
+ -1, -1, -1, -1, -1, -1,
+ /*0x04fe*/ 420,
+ -1, -1,
+ /*0x0551*/ 477,
+ -1, -1, -1,
+ /*0x118bd*/ 1489,
+ -1, -1, -1,
+ /*0x24c9*/ 905,
+ -1, -1, -1, -1, -1, -1,
+ /*0x1f3b*/ 741,
+ -1, -1,
+ /*0x1c9f*/ 555,
+ -1, -1, -1, -1, -1, -1,
+ /*0x1ef6*/ 711,
+ /*0x1e76*/ 645,
+ -1, -1, -1, -1, -1, -1,
+ /*0xa77e*/ 1106,
+ -1, -1, -1, -1, -1, -1,
+ -1,
+ /*0x118bb*/ 1487,
+ /*0x118b5*/ 1481,
+ -1, -1,
+ /*0xff39*/ 1274,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1,
+ /*0xff33*/ 1268,
+ -1,
+ /*0x1efa*/ 713,
+ /*0x1e7a*/ 647,
+ /*0x16e5e*/ 1522,
+ -1, -1, -1, -1, -1,
+ /*0x24bf*/ 895,
+ -1, -1,
+ /*0x16e43*/ 1495,
+ -1,
+ /*0x16eb3*/ 1543,
+ -1, -1,
+ /*0x10578*/ 1360,
+ -1,
+ /*0x104cf*/ 1347,
+ -1, -1, -1, -1, -1, -1,
+ -1,
+ /*0x16e5c*/ 1520,
+ -1, -1, -1,
+ /*0x10587*/ 1374,
+ /*0x0587*/ 483,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1,
+ /*0x16e4b*/ 1503,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ /*0x04f6*/ 416,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1,
+ /*0x24bd*/ 893,
+ -1, -1, -1, -1, -1,
+ /*0x04fa*/ 418,
+ -1,
+ /*0x1ef8*/ 712,
+ /*0x1e78*/ 646,
+ -1, -1, -1, -1, -1, -1,
+ /*0x24c1*/ 897,
+ -1, -1,
+ /*0x104d1*/ 1349,
+ -1, -1, -1, -1, -1, -1,
+ -1,
+ /*0x10d51*/ 1439,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1,
+ /*0x24bb*/ 891,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1,
+ /*0x04f8*/ 417,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1,
+ /*0xff35*/ 1270,
+ -1, -1, -1, -1,
+ /*0x1f0f*/ 723,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1,
+ /*0x16eb5*/ 1545,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1,
+ /*0x16e49*/ 1501,
+ -1, -1, -1, -1,
+ /*0x24cf*/ 911,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1,
+ /*0x1f0b*/ 719,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1,
+ /*0x16e41*/ 1493,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1,
+ /*0x10591*/ 1383,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1,
+ /*0x16e4f*/ 1507,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1,
+ /*0x16e51*/ 1509,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1,
+ /*0x10595*/ 1386,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1,
+ /*0x1058f*/ 1381,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1,
+ /*0x10581*/ 1368,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1,
+ /*0xab70*/ 1158,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1,
+ /*0xab72*/ 1160,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1,
+ /*0xab74*/ 1162,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1,
+ /*0xab7e*/ 1172,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1,
+ /*0xab76*/ 1164,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1,
+ /*0xab7a*/ 1168,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1,
+ /*0xab78*/ 1166
+ };
+
+ if (code <= MAX_CODE_VALUE && code >= MIN_CODE_VALUE)
+ {
+ register unsigned int key = onigenc_unicode_CaseFold_11_hash(code);
+
+ if (key <= MAX_HASH_VALUE)
+ {
+ register short s = wordlist[key];
+
+ if (s >= 0 && code1_equal(code, CaseFold_11_Table[s].from))
+ return &CaseFold_11_Table[s].to;
+ }
+ }
+ return 0;
+}
+
+static const CaseUnfold_11_Type CaseUnfold_11_Table[] = {
+#define CaseUnfold_11 (*(CaseUnfold_11_Type (*)[1450])(CaseUnfold_11_Table+0))
+ {0x0061, {1|U, {0x0041}}},
+ {0x0062, {1|U, {0x0042}}},
+ {0x0063, {1|U, {0x0043}}},
+ {0x0064, {1|U, {0x0044}}},
+ {0x0065, {1|U, {0x0045}}},
+ {0x0066, {1|U, {0x0046}}},
+ {0x0067, {1|U, {0x0047}}},
+ {0x0068, {1|U, {0x0048}}},
+ {0x006a, {1|U, {0x004a}}},
+ {0x006b, {2|U, {0x004b, 0x212a}}},
+ {0x006c, {1|U, {0x004c}}},
+ {0x006d, {1|U, {0x004d}}},
+ {0x006e, {1|U, {0x004e}}},
+ {0x006f, {1|U, {0x004f}}},
+ {0x0070, {1|U, {0x0050}}},
+ {0x0071, {1|U, {0x0051}}},
+ {0x0072, {1|U, {0x0052}}},
+ {0x0073, {2|U, {0x0053, 0x017f}}},
+ {0x0074, {1|U, {0x0054}}},
+ {0x0075, {1|U, {0x0055}}},
+ {0x0076, {1|U, {0x0056}}},
+ {0x0077, {1|U, {0x0057}}},
+ {0x0078, {1|U, {0x0058}}},
+ {0x0079, {1|U, {0x0059}}},
+ {0x007a, {1|U, {0x005a}}},
+ {0x00e0, {1|U, {0x00c0}}},
+ {0x00e1, {1|U, {0x00c1}}},
+ {0x00e2, {1|U, {0x00c2}}},
+ {0x00e3, {1|U, {0x00c3}}},
+ {0x00e4, {1|U, {0x00c4}}},
+ {0x00e5, {2|U, {0x00c5, 0x212b}}},
+ {0x00e6, {1|U, {0x00c6}}},
+ {0x00e7, {1|U, {0x00c7}}},
+ {0x00e8, {1|U, {0x00c8}}},
+ {0x00e9, {1|U, {0x00c9}}},
+ {0x00ea, {1|U, {0x00ca}}},
+ {0x00eb, {1|U, {0x00cb}}},
+ {0x00ec, {1|U, {0x00cc}}},
+ {0x00ed, {1|U, {0x00cd}}},
+ {0x00ee, {1|U, {0x00ce}}},
+ {0x00ef, {1|U, {0x00cf}}},
+ {0x00f0, {1|U, {0x00d0}}},
+ {0x00f1, {1|U, {0x00d1}}},
+ {0x00f2, {1|U, {0x00d2}}},
+ {0x00f3, {1|U, {0x00d3}}},
+ {0x00f4, {1|U, {0x00d4}}},
+ {0x00f5, {1|U, {0x00d5}}},
+ {0x00f6, {1|U, {0x00d6}}},
+ {0x00f8, {1|U, {0x00d8}}},
+ {0x00f9, {1|U, {0x00d9}}},
+ {0x00fa, {1|U, {0x00da}}},
+ {0x00fb, {1|U, {0x00db}}},
+ {0x00fc, {1|U, {0x00dc}}},
+ {0x00fd, {1|U, {0x00dd}}},
+ {0x00fe, {1|U, {0x00de}}},
+ {0x00ff, {1|U, {0x0178}}},
+ {0x0101, {1|U, {0x0100}}},
+ {0x0103, {1|U, {0x0102}}},
+ {0x0105, {1|U, {0x0104}}},
+ {0x0107, {1|U, {0x0106}}},
+ {0x0109, {1|U, {0x0108}}},
+ {0x010b, {1|U, {0x010a}}},
+ {0x010d, {1|U, {0x010c}}},
+ {0x010f, {1|U, {0x010e}}},
+ {0x0111, {1|U, {0x0110}}},
+ {0x0113, {1|U, {0x0112}}},
+ {0x0115, {1|U, {0x0114}}},
+ {0x0117, {1|U, {0x0116}}},
+ {0x0119, {1|U, {0x0118}}},
+ {0x011b, {1|U, {0x011a}}},
+ {0x011d, {1|U, {0x011c}}},
+ {0x011f, {1|U, {0x011e}}},
+ {0x0121, {1|U, {0x0120}}},
+ {0x0123, {1|U, {0x0122}}},
+ {0x0125, {1|U, {0x0124}}},
+ {0x0127, {1|U, {0x0126}}},
+ {0x0129, {1|U, {0x0128}}},
+ {0x012b, {1|U, {0x012a}}},
+ {0x012d, {1|U, {0x012c}}},
+ {0x012f, {1|U, {0x012e}}},
+ {0x0133, {1|U, {0x0132}}},
+ {0x0135, {1|U, {0x0134}}},
+ {0x0137, {1|U, {0x0136}}},
+ {0x013a, {1|U, {0x0139}}},
+ {0x013c, {1|U, {0x013b}}},
+ {0x013e, {1|U, {0x013d}}},
+ {0x0140, {1|U, {0x013f}}},
+ {0x0142, {1|U, {0x0141}}},
+ {0x0144, {1|U, {0x0143}}},
+ {0x0146, {1|U, {0x0145}}},
+ {0x0148, {1|U, {0x0147}}},
+ {0x014b, {1|U, {0x014a}}},
+ {0x014d, {1|U, {0x014c}}},
+ {0x014f, {1|U, {0x014e}}},
+ {0x0151, {1|U, {0x0150}}},
+ {0x0153, {1|U, {0x0152}}},
+ {0x0155, {1|U, {0x0154}}},
+ {0x0157, {1|U, {0x0156}}},
+ {0x0159, {1|U, {0x0158}}},
+ {0x015b, {1|U, {0x015a}}},
+ {0x015d, {1|U, {0x015c}}},
+ {0x015f, {1|U, {0x015e}}},
+ {0x0161, {1|U, {0x0160}}},
+ {0x0163, {1|U, {0x0162}}},
+ {0x0165, {1|U, {0x0164}}},
+ {0x0167, {1|U, {0x0166}}},
+ {0x0169, {1|U, {0x0168}}},
+ {0x016b, {1|U, {0x016a}}},
+ {0x016d, {1|U, {0x016c}}},
+ {0x016f, {1|U, {0x016e}}},
+ {0x0171, {1|U, {0x0170}}},
+ {0x0173, {1|U, {0x0172}}},
+ {0x0175, {1|U, {0x0174}}},
+ {0x0177, {1|U, {0x0176}}},
+ {0x017a, {1|U, {0x0179}}},
+ {0x017c, {1|U, {0x017b}}},
+ {0x017e, {1|U, {0x017d}}},
+ {0x0180, {1|U, {0x0243}}},
+ {0x0183, {1|U, {0x0182}}},
+ {0x0185, {1|U, {0x0184}}},
+ {0x0188, {1|U, {0x0187}}},
+ {0x018c, {1|U, {0x018b}}},
+ {0x0192, {1|U, {0x0191}}},
+ {0x0195, {1|U, {0x01f6}}},
+ {0x0199, {1|U, {0x0198}}},
+ {0x019a, {1|U, {0x023d}}},
+ {0x019b, {1|U, {0xa7dc}}},
+ {0x019e, {1|U, {0x0220}}},
+ {0x01a1, {1|U, {0x01a0}}},
+ {0x01a3, {1|U, {0x01a2}}},
+ {0x01a5, {1|U, {0x01a4}}},
+ {0x01a8, {1|U, {0x01a7}}},
+ {0x01ad, {1|U, {0x01ac}}},
+ {0x01b0, {1|U, {0x01af}}},
+ {0x01b4, {1|U, {0x01b3}}},
+ {0x01b6, {1|U, {0x01b5}}},
+ {0x01b9, {1|U, {0x01b8}}},
+ {0x01bd, {1|U, {0x01bc}}},
+ {0x01bf, {1|U, {0x01f7}}},
+ {0x01c6, {2|U|ST, {0x01c4, 0x01c5}}},
+ {0x01c9, {2|U|ST, {0x01c7, 0x01c8}}},
+ {0x01cc, {2|U|ST, {0x01ca, 0x01cb}}},
+ {0x01ce, {1|U, {0x01cd}}},
+ {0x01d0, {1|U, {0x01cf}}},
+ {0x01d2, {1|U, {0x01d1}}},
+ {0x01d4, {1|U, {0x01d3}}},
+ {0x01d6, {1|U, {0x01d5}}},
+ {0x01d8, {1|U, {0x01d7}}},
+ {0x01da, {1|U, {0x01d9}}},
+ {0x01dc, {1|U, {0x01db}}},
+ {0x01dd, {1|U, {0x018e}}},
+ {0x01df, {1|U, {0x01de}}},
+ {0x01e1, {1|U, {0x01e0}}},
+ {0x01e3, {1|U, {0x01e2}}},
+ {0x01e5, {1|U, {0x01e4}}},
+ {0x01e7, {1|U, {0x01e6}}},
+ {0x01e9, {1|U, {0x01e8}}},
+ {0x01eb, {1|U, {0x01ea}}},
+ {0x01ed, {1|U, {0x01ec}}},
+ {0x01ef, {1|U, {0x01ee}}},
+ {0x01f3, {2|U|ST, {0x01f1, 0x01f2}}},
+ {0x01f5, {1|U, {0x01f4}}},
+ {0x01f9, {1|U, {0x01f8}}},
+ {0x01fb, {1|U, {0x01fa}}},
+ {0x01fd, {1|U, {0x01fc}}},
+ {0x01ff, {1|U, {0x01fe}}},
+ {0x0201, {1|U, {0x0200}}},
+ {0x0203, {1|U, {0x0202}}},
+ {0x0205, {1|U, {0x0204}}},
+ {0x0207, {1|U, {0x0206}}},
+ {0x0209, {1|U, {0x0208}}},
+ {0x020b, {1|U, {0x020a}}},
+ {0x020d, {1|U, {0x020c}}},
+ {0x020f, {1|U, {0x020e}}},
+ {0x0211, {1|U, {0x0210}}},
+ {0x0213, {1|U, {0x0212}}},
+ {0x0215, {1|U, {0x0214}}},
+ {0x0217, {1|U, {0x0216}}},
+ {0x0219, {1|U, {0x0218}}},
+ {0x021b, {1|U, {0x021a}}},
+ {0x021d, {1|U, {0x021c}}},
+ {0x021f, {1|U, {0x021e}}},
+ {0x0223, {1|U, {0x0222}}},
+ {0x0225, {1|U, {0x0224}}},
+ {0x0227, {1|U, {0x0226}}},
+ {0x0229, {1|U, {0x0228}}},
+ {0x022b, {1|U, {0x022a}}},
+ {0x022d, {1|U, {0x022c}}},
+ {0x022f, {1|U, {0x022e}}},
+ {0x0231, {1|U, {0x0230}}},
+ {0x0233, {1|U, {0x0232}}},
+ {0x023c, {1|U, {0x023b}}},
+ {0x023f, {1|U, {0x2c7e}}},
+ {0x0240, {1|U, {0x2c7f}}},
+ {0x0242, {1|U, {0x0241}}},
+ {0x0247, {1|U, {0x0246}}},
+ {0x0249, {1|U, {0x0248}}},
+ {0x024b, {1|U, {0x024a}}},
+ {0x024d, {1|U, {0x024c}}},
+ {0x024f, {1|U, {0x024e}}},
+ {0x0250, {1|U, {0x2c6f}}},
+ {0x0251, {1|U, {0x2c6d}}},
+ {0x0252, {1|U, {0x2c70}}},
+ {0x0253, {1|U, {0x0181}}},
+ {0x0254, {1|U, {0x0186}}},
+ {0x0256, {1|U, {0x0189}}},
+ {0x0257, {1|U, {0x018a}}},
+ {0x0259, {1|U, {0x018f}}},
+ {0x025b, {1|U, {0x0190}}},
+ {0x025c, {1|U, {0xa7ab}}},
+ {0x0260, {1|U, {0x0193}}},
+ {0x0261, {1|U, {0xa7ac}}},
+ {0x0263, {1|U, {0x0194}}},
+ {0x0264, {1|U, {0xa7cb}}},
+ {0x0265, {1|U, {0xa78d}}},
+ {0x0266, {1|U, {0xa7aa}}},
+ {0x0268, {1|U, {0x0197}}},
+ {0x0269, {1|U, {0x0196}}},
+ {0x026a, {1|U, {0xa7ae}}},
+ {0x026b, {1|U, {0x2c62}}},
+ {0x026c, {1|U, {0xa7ad}}},
+ {0x026f, {1|U, {0x019c}}},
+ {0x0271, {1|U, {0x2c6e}}},
+ {0x0272, {1|U, {0x019d}}},
+ {0x0275, {1|U, {0x019f}}},
+ {0x027d, {1|U, {0x2c64}}},
+ {0x0280, {1|U, {0x01a6}}},
+ {0x0282, {1|U, {0xa7c5}}},
+ {0x0283, {1|U, {0x01a9}}},
+ {0x0287, {1|U, {0xa7b1}}},
+ {0x0288, {1|U, {0x01ae}}},
+ {0x0289, {1|U, {0x0244}}},
+ {0x028a, {1|U, {0x01b1}}},
+ {0x028b, {1|U, {0x01b2}}},
+ {0x028c, {1|U, {0x0245}}},
+ {0x0292, {1|U, {0x01b7}}},
+ {0x029d, {1|U, {0xa7b2}}},
+ {0x029e, {1|U, {0xa7b0}}},
+ {0x0371, {1|U, {0x0370}}},
+ {0x0373, {1|U, {0x0372}}},
+ {0x0377, {1|U, {0x0376}}},
+ {0x037b, {1|U, {0x03fd}}},
+ {0x037c, {1|U, {0x03fe}}},
+ {0x037d, {1|U, {0x03ff}}},
+ {0x03ac, {1|U, {0x0386}}},
+ {0x03ad, {1|U, {0x0388}}},
+ {0x03ae, {1|U, {0x0389}}},
+ {0x03af, {1|U, {0x038a}}},
+ {0x03b1, {1|U, {0x0391}}},
+ {0x03b2, {2|U, {0x0392, 0x03d0}}},
+ {0x03b3, {1|U, {0x0393}}},
+ {0x03b4, {1|U, {0x0394}}},
+ {0x03b5, {2|U, {0x0395, 0x03f5}}},
+ {0x03b6, {1|U, {0x0396}}},
+ {0x03b7, {1|U, {0x0397}}},
+ {0x03b8, {3|U, {0x0398, 0x03d1, 0x03f4}}},
+ {0x03b9, {3|U, {0x0399, 0x0345, 0x1fbe}}},
+ {0x03ba, {2|U, {0x039a, 0x03f0}}},
+ {0x03bb, {1|U, {0x039b}}},
+ {0x03bc, {2|U, {0x039c, 0x00b5}}},
+ {0x03bd, {1|U, {0x039d}}},
+ {0x03be, {1|U, {0x039e}}},
+ {0x03bf, {1|U, {0x039f}}},
+ {0x03c0, {2|U, {0x03a0, 0x03d6}}},
+ {0x03c1, {2|U, {0x03a1, 0x03f1}}},
+ {0x03c3, {2|U, {0x03a3, 0x03c2}}},
+ {0x03c4, {1|U, {0x03a4}}},
+ {0x03c5, {1|U, {0x03a5}}},
+ {0x03c6, {2|U, {0x03a6, 0x03d5}}},
+ {0x03c7, {1|U, {0x03a7}}},
+ {0x03c8, {1|U, {0x03a8}}},
+ {0x03c9, {2|U, {0x03a9, 0x2126}}},
+ {0x03ca, {1|U, {0x03aa}}},
+ {0x03cb, {1|U, {0x03ab}}},
+ {0x03cc, {1|U, {0x038c}}},
+ {0x03cd, {1|U, {0x038e}}},
+ {0x03ce, {1|U, {0x038f}}},
+ {0x03d7, {1|U, {0x03cf}}},
+ {0x03d9, {1|U, {0x03d8}}},
+ {0x03db, {1|U, {0x03da}}},
+ {0x03dd, {1|U, {0x03dc}}},
+ {0x03df, {1|U, {0x03de}}},
+ {0x03e1, {1|U, {0x03e0}}},
+ {0x03e3, {1|U, {0x03e2}}},
+ {0x03e5, {1|U, {0x03e4}}},
+ {0x03e7, {1|U, {0x03e6}}},
+ {0x03e9, {1|U, {0x03e8}}},
+ {0x03eb, {1|U, {0x03ea}}},
+ {0x03ed, {1|U, {0x03ec}}},
+ {0x03ef, {1|U, {0x03ee}}},
+ {0x03f2, {1|U, {0x03f9}}},
+ {0x03f3, {1|U, {0x037f}}},
+ {0x03f8, {1|U, {0x03f7}}},
+ {0x03fb, {1|U, {0x03fa}}},
+ {0x0430, {1|U, {0x0410}}},
+ {0x0431, {1|U, {0x0411}}},
+ {0x0432, {2|U, {0x0412, 0x1c80}}},
+ {0x0433, {1|U, {0x0413}}},
+ {0x0434, {2|U, {0x0414, 0x1c81}}},
+ {0x0435, {1|U, {0x0415}}},
+ {0x0436, {1|U, {0x0416}}},
+ {0x0437, {1|U, {0x0417}}},
+ {0x0438, {1|U, {0x0418}}},
+ {0x0439, {1|U, {0x0419}}},
+ {0x043a, {1|U, {0x041a}}},
+ {0x043b, {1|U, {0x041b}}},
+ {0x043c, {1|U, {0x041c}}},
+ {0x043d, {1|U, {0x041d}}},
+ {0x043e, {2|U, {0x041e, 0x1c82}}},
+ {0x043f, {1|U, {0x041f}}},
+ {0x0440, {1|U, {0x0420}}},
+ {0x0441, {2|U, {0x0421, 0x1c83}}},
+ {0x0442, {3|U, {0x0422, 0x1c84, 0x1c85}}},
+ {0x0443, {1|U, {0x0423}}},
+ {0x0444, {1|U, {0x0424}}},
+ {0x0445, {1|U, {0x0425}}},
+ {0x0446, {1|U, {0x0426}}},
+ {0x0447, {1|U, {0x0427}}},
+ {0x0448, {1|U, {0x0428}}},
+ {0x0449, {1|U, {0x0429}}},
+ {0x044a, {2|U, {0x042a, 0x1c86}}},
+ {0x044b, {1|U, {0x042b}}},
+ {0x044c, {1|U, {0x042c}}},
+ {0x044d, {1|U, {0x042d}}},
+ {0x044e, {1|U, {0x042e}}},
+ {0x044f, {1|U, {0x042f}}},
+ {0x0450, {1|U, {0x0400}}},
+ {0x0451, {1|U, {0x0401}}},
+ {0x0452, {1|U, {0x0402}}},
+ {0x0453, {1|U, {0x0403}}},
+ {0x0454, {1|U, {0x0404}}},
+ {0x0455, {1|U, {0x0405}}},
+ {0x0456, {1|U, {0x0406}}},
+ {0x0457, {1|U, {0x0407}}},
+ {0x0458, {1|U, {0x0408}}},
+ {0x0459, {1|U, {0x0409}}},
+ {0x045a, {1|U, {0x040a}}},
+ {0x045b, {1|U, {0x040b}}},
+ {0x045c, {1|U, {0x040c}}},
+ {0x045d, {1|U, {0x040d}}},
+ {0x045e, {1|U, {0x040e}}},
+ {0x045f, {1|U, {0x040f}}},
+ {0x0461, {1|U, {0x0460}}},
+ {0x0463, {2|U, {0x0462, 0x1c87}}},
+ {0x0465, {1|U, {0x0464}}},
+ {0x0467, {1|U, {0x0466}}},
+ {0x0469, {1|U, {0x0468}}},
+ {0x046b, {1|U, {0x046a}}},
+ {0x046d, {1|U, {0x046c}}},
+ {0x046f, {1|U, {0x046e}}},
+ {0x0471, {1|U, {0x0470}}},
+ {0x0473, {1|U, {0x0472}}},
+ {0x0475, {1|U, {0x0474}}},
+ {0x0477, {1|U, {0x0476}}},
+ {0x0479, {1|U, {0x0478}}},
+ {0x047b, {1|U, {0x047a}}},
+ {0x047d, {1|U, {0x047c}}},
+ {0x047f, {1|U, {0x047e}}},
+ {0x0481, {1|U, {0x0480}}},
+ {0x048b, {1|U, {0x048a}}},
+ {0x048d, {1|U, {0x048c}}},
+ {0x048f, {1|U, {0x048e}}},
+ {0x0491, {1|U, {0x0490}}},
+ {0x0493, {1|U, {0x0492}}},
+ {0x0495, {1|U, {0x0494}}},
+ {0x0497, {1|U, {0x0496}}},
+ {0x0499, {1|U, {0x0498}}},
+ {0x049b, {1|U, {0x049a}}},
+ {0x049d, {1|U, {0x049c}}},
+ {0x049f, {1|U, {0x049e}}},
+ {0x04a1, {1|U, {0x04a0}}},
+ {0x04a3, {1|U, {0x04a2}}},
+ {0x04a5, {1|U, {0x04a4}}},
+ {0x04a7, {1|U, {0x04a6}}},
+ {0x04a9, {1|U, {0x04a8}}},
+ {0x04ab, {1|U, {0x04aa}}},
+ {0x04ad, {1|U, {0x04ac}}},
+ {0x04af, {1|U, {0x04ae}}},
+ {0x04b1, {1|U, {0x04b0}}},
+ {0x04b3, {1|U, {0x04b2}}},
+ {0x04b5, {1|U, {0x04b4}}},
+ {0x04b7, {1|U, {0x04b6}}},
+ {0x04b9, {1|U, {0x04b8}}},
+ {0x04bb, {1|U, {0x04ba}}},
+ {0x04bd, {1|U, {0x04bc}}},
+ {0x04bf, {1|U, {0x04be}}},
+ {0x04c2, {1|U, {0x04c1}}},
+ {0x04c4, {1|U, {0x04c3}}},
+ {0x04c6, {1|U, {0x04c5}}},
+ {0x04c8, {1|U, {0x04c7}}},
+ {0x04ca, {1|U, {0x04c9}}},
+ {0x04cc, {1|U, {0x04cb}}},
+ {0x04ce, {1|U, {0x04cd}}},
+ {0x04cf, {1|U, {0x04c0}}},
+ {0x04d1, {1|U, {0x04d0}}},
+ {0x04d3, {1|U, {0x04d2}}},
+ {0x04d5, {1|U, {0x04d4}}},
+ {0x04d7, {1|U, {0x04d6}}},
+ {0x04d9, {1|U, {0x04d8}}},
+ {0x04db, {1|U, {0x04da}}},
+ {0x04dd, {1|U, {0x04dc}}},
+ {0x04df, {1|U, {0x04de}}},
+ {0x04e1, {1|U, {0x04e0}}},
+ {0x04e3, {1|U, {0x04e2}}},
+ {0x04e5, {1|U, {0x04e4}}},
+ {0x04e7, {1|U, {0x04e6}}},
+ {0x04e9, {1|U, {0x04e8}}},
+ {0x04eb, {1|U, {0x04ea}}},
+ {0x04ed, {1|U, {0x04ec}}},
+ {0x04ef, {1|U, {0x04ee}}},
+ {0x04f1, {1|U, {0x04f0}}},
+ {0x04f3, {1|U, {0x04f2}}},
+ {0x04f5, {1|U, {0x04f4}}},
+ {0x04f7, {1|U, {0x04f6}}},
+ {0x04f9, {1|U, {0x04f8}}},
+ {0x04fb, {1|U, {0x04fa}}},
+ {0x04fd, {1|U, {0x04fc}}},
+ {0x04ff, {1|U, {0x04fe}}},
+ {0x0501, {1|U, {0x0500}}},
+ {0x0503, {1|U, {0x0502}}},
+ {0x0505, {1|U, {0x0504}}},
+ {0x0507, {1|U, {0x0506}}},
+ {0x0509, {1|U, {0x0508}}},
+ {0x050b, {1|U, {0x050a}}},
+ {0x050d, {1|U, {0x050c}}},
+ {0x050f, {1|U, {0x050e}}},
+ {0x0511, {1|U, {0x0510}}},
+ {0x0513, {1|U, {0x0512}}},
+ {0x0515, {1|U, {0x0514}}},
+ {0x0517, {1|U, {0x0516}}},
+ {0x0519, {1|U, {0x0518}}},
+ {0x051b, {1|U, {0x051a}}},
+ {0x051d, {1|U, {0x051c}}},
+ {0x051f, {1|U, {0x051e}}},
+ {0x0521, {1|U, {0x0520}}},
+ {0x0523, {1|U, {0x0522}}},
+ {0x0525, {1|U, {0x0524}}},
+ {0x0527, {1|U, {0x0526}}},
+ {0x0529, {1|U, {0x0528}}},
+ {0x052b, {1|U, {0x052a}}},
+ {0x052d, {1|U, {0x052c}}},
+ {0x052f, {1|U, {0x052e}}},
+ {0x0561, {1|U, {0x0531}}},
+ {0x0562, {1|U, {0x0532}}},
+ {0x0563, {1|U, {0x0533}}},
+ {0x0564, {1|U, {0x0534}}},
+ {0x0565, {1|U, {0x0535}}},
+ {0x0566, {1|U, {0x0536}}},
+ {0x0567, {1|U, {0x0537}}},
+ {0x0568, {1|U, {0x0538}}},
+ {0x0569, {1|U, {0x0539}}},
+ {0x056a, {1|U, {0x053a}}},
+ {0x056b, {1|U, {0x053b}}},
+ {0x056c, {1|U, {0x053c}}},
+ {0x056d, {1|U, {0x053d}}},
+ {0x056e, {1|U, {0x053e}}},
+ {0x056f, {1|U, {0x053f}}},
+ {0x0570, {1|U, {0x0540}}},
+ {0x0571, {1|U, {0x0541}}},
+ {0x0572, {1|U, {0x0542}}},
+ {0x0573, {1|U, {0x0543}}},
+ {0x0574, {1|U, {0x0544}}},
+ {0x0575, {1|U, {0x0545}}},
+ {0x0576, {1|U, {0x0546}}},
+ {0x0577, {1|U, {0x0547}}},
+ {0x0578, {1|U, {0x0548}}},
+ {0x0579, {1|U, {0x0549}}},
+ {0x057a, {1|U, {0x054a}}},
+ {0x057b, {1|U, {0x054b}}},
+ {0x057c, {1|U, {0x054c}}},
+ {0x057d, {1|U, {0x054d}}},
+ {0x057e, {1|U, {0x054e}}},
+ {0x057f, {1|U, {0x054f}}},
+ {0x0580, {1|U, {0x0550}}},
+ {0x0581, {1|U, {0x0551}}},
+ {0x0582, {1|U, {0x0552}}},
+ {0x0583, {1|U, {0x0553}}},
+ {0x0584, {1|U, {0x0554}}},
+ {0x0585, {1|U, {0x0555}}},
+ {0x0586, {1|U, {0x0556}}},
+ {0x10d0, {1|U|IT, {0x1c90}}},
+ {0x10d1, {1|U|IT, {0x1c91}}},
+ {0x10d2, {1|U|IT, {0x1c92}}},
+ {0x10d3, {1|U|IT, {0x1c93}}},
+ {0x10d4, {1|U|IT, {0x1c94}}},
+ {0x10d5, {1|U|IT, {0x1c95}}},
+ {0x10d6, {1|U|IT, {0x1c96}}},
+ {0x10d7, {1|U|IT, {0x1c97}}},
+ {0x10d8, {1|U|IT, {0x1c98}}},
+ {0x10d9, {1|U|IT, {0x1c99}}},
+ {0x10da, {1|U|IT, {0x1c9a}}},
+ {0x10db, {1|U|IT, {0x1c9b}}},
+ {0x10dc, {1|U|IT, {0x1c9c}}},
+ {0x10dd, {1|U|IT, {0x1c9d}}},
+ {0x10de, {1|U|IT, {0x1c9e}}},
+ {0x10df, {1|U|IT, {0x1c9f}}},
+ {0x10e0, {1|U|IT, {0x1ca0}}},
+ {0x10e1, {1|U|IT, {0x1ca1}}},
+ {0x10e2, {1|U|IT, {0x1ca2}}},
+ {0x10e3, {1|U|IT, {0x1ca3}}},
+ {0x10e4, {1|U|IT, {0x1ca4}}},
+ {0x10e5, {1|U|IT, {0x1ca5}}},
+ {0x10e6, {1|U|IT, {0x1ca6}}},
+ {0x10e7, {1|U|IT, {0x1ca7}}},
+ {0x10e8, {1|U|IT, {0x1ca8}}},
+ {0x10e9, {1|U|IT, {0x1ca9}}},
+ {0x10ea, {1|U|IT, {0x1caa}}},
+ {0x10eb, {1|U|IT, {0x1cab}}},
+ {0x10ec, {1|U|IT, {0x1cac}}},
+ {0x10ed, {1|U|IT, {0x1cad}}},
+ {0x10ee, {1|U|IT, {0x1cae}}},
+ {0x10ef, {1|U|IT, {0x1caf}}},
+ {0x10f0, {1|U|IT, {0x1cb0}}},
+ {0x10f1, {1|U|IT, {0x1cb1}}},
+ {0x10f2, {1|U|IT, {0x1cb2}}},
+ {0x10f3, {1|U|IT, {0x1cb3}}},
+ {0x10f4, {1|U|IT, {0x1cb4}}},
+ {0x10f5, {1|U|IT, {0x1cb5}}},
+ {0x10f6, {1|U|IT, {0x1cb6}}},
+ {0x10f7, {1|U|IT, {0x1cb7}}},
+ {0x10f8, {1|U|IT, {0x1cb8}}},
+ {0x10f9, {1|U|IT, {0x1cb9}}},
+ {0x10fa, {1|U|IT, {0x1cba}}},
+ {0x10fd, {1|U|IT, {0x1cbd}}},
+ {0x10fe, {1|U|IT, {0x1cbe}}},
+ {0x10ff, {1|U|IT, {0x1cbf}}},
+ {0x13a0, {1|D, {0xab70}}},
+ {0x13a1, {1|D, {0xab71}}},
+ {0x13a2, {1|D, {0xab72}}},
+ {0x13a3, {1|D, {0xab73}}},
+ {0x13a4, {1|D, {0xab74}}},
+ {0x13a5, {1|D, {0xab75}}},
+ {0x13a6, {1|D, {0xab76}}},
+ {0x13a7, {1|D, {0xab77}}},
+ {0x13a8, {1|D, {0xab78}}},
+ {0x13a9, {1|D, {0xab79}}},
+ {0x13aa, {1|D, {0xab7a}}},
+ {0x13ab, {1|D, {0xab7b}}},
+ {0x13ac, {1|D, {0xab7c}}},
+ {0x13ad, {1|D, {0xab7d}}},
+ {0x13ae, {1|D, {0xab7e}}},
+ {0x13af, {1|D, {0xab7f}}},
+ {0x13b0, {1|D, {0xab80}}},
+ {0x13b1, {1|D, {0xab81}}},
+ {0x13b2, {1|D, {0xab82}}},
+ {0x13b3, {1|D, {0xab83}}},
+ {0x13b4, {1|D, {0xab84}}},
+ {0x13b5, {1|D, {0xab85}}},
+ {0x13b6, {1|D, {0xab86}}},
+ {0x13b7, {1|D, {0xab87}}},
+ {0x13b8, {1|D, {0xab88}}},
+ {0x13b9, {1|D, {0xab89}}},
+ {0x13ba, {1|D, {0xab8a}}},
+ {0x13bb, {1|D, {0xab8b}}},
+ {0x13bc, {1|D, {0xab8c}}},
+ {0x13bd, {1|D, {0xab8d}}},
+ {0x13be, {1|D, {0xab8e}}},
+ {0x13bf, {1|D, {0xab8f}}},
+ {0x13c0, {1|D, {0xab90}}},
+ {0x13c1, {1|D, {0xab91}}},
+ {0x13c2, {1|D, {0xab92}}},
+ {0x13c3, {1|D, {0xab93}}},
+ {0x13c4, {1|D, {0xab94}}},
+ {0x13c5, {1|D, {0xab95}}},
+ {0x13c6, {1|D, {0xab96}}},
+ {0x13c7, {1|D, {0xab97}}},
+ {0x13c8, {1|D, {0xab98}}},
+ {0x13c9, {1|D, {0xab99}}},
+ {0x13ca, {1|D, {0xab9a}}},
+ {0x13cb, {1|D, {0xab9b}}},
+ {0x13cc, {1|D, {0xab9c}}},
+ {0x13cd, {1|D, {0xab9d}}},
+ {0x13ce, {1|D, {0xab9e}}},
+ {0x13cf, {1|D, {0xab9f}}},
+ {0x13d0, {1|D, {0xaba0}}},
+ {0x13d1, {1|D, {0xaba1}}},
+ {0x13d2, {1|D, {0xaba2}}},
+ {0x13d3, {1|D, {0xaba3}}},
+ {0x13d4, {1|D, {0xaba4}}},
+ {0x13d5, {1|D, {0xaba5}}},
+ {0x13d6, {1|D, {0xaba6}}},
+ {0x13d7, {1|D, {0xaba7}}},
+ {0x13d8, {1|D, {0xaba8}}},
+ {0x13d9, {1|D, {0xaba9}}},
+ {0x13da, {1|D, {0xabaa}}},
+ {0x13db, {1|D, {0xabab}}},
+ {0x13dc, {1|D, {0xabac}}},
+ {0x13dd, {1|D, {0xabad}}},
+ {0x13de, {1|D, {0xabae}}},
+ {0x13df, {1|D, {0xabaf}}},
+ {0x13e0, {1|D, {0xabb0}}},
+ {0x13e1, {1|D, {0xabb1}}},
+ {0x13e2, {1|D, {0xabb2}}},
+ {0x13e3, {1|D, {0xabb3}}},
+ {0x13e4, {1|D, {0xabb4}}},
+ {0x13e5, {1|D, {0xabb5}}},
+ {0x13e6, {1|D, {0xabb6}}},
+ {0x13e7, {1|D, {0xabb7}}},
+ {0x13e8, {1|D, {0xabb8}}},
+ {0x13e9, {1|D, {0xabb9}}},
+ {0x13ea, {1|D, {0xabba}}},
+ {0x13eb, {1|D, {0xabbb}}},
+ {0x13ec, {1|D, {0xabbc}}},
+ {0x13ed, {1|D, {0xabbd}}},
+ {0x13ee, {1|D, {0xabbe}}},
+ {0x13ef, {1|D, {0xabbf}}},
+ {0x13f0, {1|D, {0x13f8}}},
+ {0x13f1, {1|D, {0x13f9}}},
+ {0x13f2, {1|D, {0x13fa}}},
+ {0x13f3, {1|D, {0x13fb}}},
+ {0x13f4, {1|D, {0x13fc}}},
+ {0x13f5, {1|D, {0x13fd}}},
+ {0x1c8a, {1|U, {0x1c89}}},
+ {0x1d79, {1|U, {0xa77d}}},
+ {0x1d7d, {1|U, {0x2c63}}},
+ {0x1d8e, {1|U, {0xa7c6}}},
+ {0x1e01, {1|U, {0x1e00}}},
+ {0x1e03, {1|U, {0x1e02}}},
+ {0x1e05, {1|U, {0x1e04}}},
+ {0x1e07, {1|U, {0x1e06}}},
+ {0x1e09, {1|U, {0x1e08}}},
+ {0x1e0b, {1|U, {0x1e0a}}},
+ {0x1e0d, {1|U, {0x1e0c}}},
+ {0x1e0f, {1|U, {0x1e0e}}},
+ {0x1e11, {1|U, {0x1e10}}},
+ {0x1e13, {1|U, {0x1e12}}},
+ {0x1e15, {1|U, {0x1e14}}},
+ {0x1e17, {1|U, {0x1e16}}},
+ {0x1e19, {1|U, {0x1e18}}},
+ {0x1e1b, {1|U, {0x1e1a}}},
+ {0x1e1d, {1|U, {0x1e1c}}},
+ {0x1e1f, {1|U, {0x1e1e}}},
+ {0x1e21, {1|U, {0x1e20}}},
+ {0x1e23, {1|U, {0x1e22}}},
+ {0x1e25, {1|U, {0x1e24}}},
+ {0x1e27, {1|U, {0x1e26}}},
+ {0x1e29, {1|U, {0x1e28}}},
+ {0x1e2b, {1|U, {0x1e2a}}},
+ {0x1e2d, {1|U, {0x1e2c}}},
+ {0x1e2f, {1|U, {0x1e2e}}},
+ {0x1e31, {1|U, {0x1e30}}},
+ {0x1e33, {1|U, {0x1e32}}},
+ {0x1e35, {1|U, {0x1e34}}},
+ {0x1e37, {1|U, {0x1e36}}},
+ {0x1e39, {1|U, {0x1e38}}},
+ {0x1e3b, {1|U, {0x1e3a}}},
+ {0x1e3d, {1|U, {0x1e3c}}},
+ {0x1e3f, {1|U, {0x1e3e}}},
+ {0x1e41, {1|U, {0x1e40}}},
+ {0x1e43, {1|U, {0x1e42}}},
+ {0x1e45, {1|U, {0x1e44}}},
+ {0x1e47, {1|U, {0x1e46}}},
+ {0x1e49, {1|U, {0x1e48}}},
+ {0x1e4b, {1|U, {0x1e4a}}},
+ {0x1e4d, {1|U, {0x1e4c}}},
+ {0x1e4f, {1|U, {0x1e4e}}},
+ {0x1e51, {1|U, {0x1e50}}},
+ {0x1e53, {1|U, {0x1e52}}},
+ {0x1e55, {1|U, {0x1e54}}},
+ {0x1e57, {1|U, {0x1e56}}},
+ {0x1e59, {1|U, {0x1e58}}},
+ {0x1e5b, {1|U, {0x1e5a}}},
+ {0x1e5d, {1|U, {0x1e5c}}},
+ {0x1e5f, {1|U, {0x1e5e}}},
+ {0x1e61, {2|U, {0x1e60, 0x1e9b}}},
+ {0x1e63, {1|U, {0x1e62}}},
+ {0x1e65, {1|U, {0x1e64}}},
+ {0x1e67, {1|U, {0x1e66}}},
+ {0x1e69, {1|U, {0x1e68}}},
+ {0x1e6b, {1|U, {0x1e6a}}},
+ {0x1e6d, {1|U, {0x1e6c}}},
+ {0x1e6f, {1|U, {0x1e6e}}},
+ {0x1e71, {1|U, {0x1e70}}},
+ {0x1e73, {1|U, {0x1e72}}},
+ {0x1e75, {1|U, {0x1e74}}},
+ {0x1e77, {1|U, {0x1e76}}},
+ {0x1e79, {1|U, {0x1e78}}},
+ {0x1e7b, {1|U, {0x1e7a}}},
+ {0x1e7d, {1|U, {0x1e7c}}},
+ {0x1e7f, {1|U, {0x1e7e}}},
+ {0x1e81, {1|U, {0x1e80}}},
+ {0x1e83, {1|U, {0x1e82}}},
+ {0x1e85, {1|U, {0x1e84}}},
+ {0x1e87, {1|U, {0x1e86}}},
+ {0x1e89, {1|U, {0x1e88}}},
+ {0x1e8b, {1|U, {0x1e8a}}},
+ {0x1e8d, {1|U, {0x1e8c}}},
+ {0x1e8f, {1|U, {0x1e8e}}},
+ {0x1e91, {1|U, {0x1e90}}},
+ {0x1e93, {1|U, {0x1e92}}},
+ {0x1e95, {1|U, {0x1e94}}},
+ {0x1ea1, {1|U, {0x1ea0}}},
+ {0x1ea3, {1|U, {0x1ea2}}},
+ {0x1ea5, {1|U, {0x1ea4}}},
+ {0x1ea7, {1|U, {0x1ea6}}},
+ {0x1ea9, {1|U, {0x1ea8}}},
+ {0x1eab, {1|U, {0x1eaa}}},
+ {0x1ead, {1|U, {0x1eac}}},
+ {0x1eaf, {1|U, {0x1eae}}},
+ {0x1eb1, {1|U, {0x1eb0}}},
+ {0x1eb3, {1|U, {0x1eb2}}},
+ {0x1eb5, {1|U, {0x1eb4}}},
+ {0x1eb7, {1|U, {0x1eb6}}},
+ {0x1eb9, {1|U, {0x1eb8}}},
+ {0x1ebb, {1|U, {0x1eba}}},
+ {0x1ebd, {1|U, {0x1ebc}}},
+ {0x1ebf, {1|U, {0x1ebe}}},
+ {0x1ec1, {1|U, {0x1ec0}}},
+ {0x1ec3, {1|U, {0x1ec2}}},
+ {0x1ec5, {1|U, {0x1ec4}}},
+ {0x1ec7, {1|U, {0x1ec6}}},
+ {0x1ec9, {1|U, {0x1ec8}}},
+ {0x1ecb, {1|U, {0x1eca}}},
+ {0x1ecd, {1|U, {0x1ecc}}},
+ {0x1ecf, {1|U, {0x1ece}}},
+ {0x1ed1, {1|U, {0x1ed0}}},
+ {0x1ed3, {1|U, {0x1ed2}}},
+ {0x1ed5, {1|U, {0x1ed4}}},
+ {0x1ed7, {1|U, {0x1ed6}}},
+ {0x1ed9, {1|U, {0x1ed8}}},
+ {0x1edb, {1|U, {0x1eda}}},
+ {0x1edd, {1|U, {0x1edc}}},
+ {0x1edf, {1|U, {0x1ede}}},
+ {0x1ee1, {1|U, {0x1ee0}}},
+ {0x1ee3, {1|U, {0x1ee2}}},
+ {0x1ee5, {1|U, {0x1ee4}}},
+ {0x1ee7, {1|U, {0x1ee6}}},
+ {0x1ee9, {1|U, {0x1ee8}}},
+ {0x1eeb, {1|U, {0x1eea}}},
+ {0x1eed, {1|U, {0x1eec}}},
+ {0x1eef, {1|U, {0x1eee}}},
+ {0x1ef1, {1|U, {0x1ef0}}},
+ {0x1ef3, {1|U, {0x1ef2}}},
+ {0x1ef5, {1|U, {0x1ef4}}},
+ {0x1ef7, {1|U, {0x1ef6}}},
+ {0x1ef9, {1|U, {0x1ef8}}},
+ {0x1efb, {1|U, {0x1efa}}},
+ {0x1efd, {1|U, {0x1efc}}},
+ {0x1eff, {1|U, {0x1efe}}},
+ {0x1f00, {1|U, {0x1f08}}},
+ {0x1f01, {1|U, {0x1f09}}},
+ {0x1f02, {1|U, {0x1f0a}}},
+ {0x1f03, {1|U, {0x1f0b}}},
+ {0x1f04, {1|U, {0x1f0c}}},
+ {0x1f05, {1|U, {0x1f0d}}},
+ {0x1f06, {1|U, {0x1f0e}}},
+ {0x1f07, {1|U, {0x1f0f}}},
+ {0x1f10, {1|U, {0x1f18}}},
+ {0x1f11, {1|U, {0x1f19}}},
+ {0x1f12, {1|U, {0x1f1a}}},
+ {0x1f13, {1|U, {0x1f1b}}},
+ {0x1f14, {1|U, {0x1f1c}}},
+ {0x1f15, {1|U, {0x1f1d}}},
+ {0x1f20, {1|U, {0x1f28}}},
+ {0x1f21, {1|U, {0x1f29}}},
+ {0x1f22, {1|U, {0x1f2a}}},
+ {0x1f23, {1|U, {0x1f2b}}},
+ {0x1f24, {1|U, {0x1f2c}}},
+ {0x1f25, {1|U, {0x1f2d}}},
+ {0x1f26, {1|U, {0x1f2e}}},
+ {0x1f27, {1|U, {0x1f2f}}},
+ {0x1f30, {1|U, {0x1f38}}},
+ {0x1f31, {1|U, {0x1f39}}},
+ {0x1f32, {1|U, {0x1f3a}}},
+ {0x1f33, {1|U, {0x1f3b}}},
+ {0x1f34, {1|U, {0x1f3c}}},
+ {0x1f35, {1|U, {0x1f3d}}},
+ {0x1f36, {1|U, {0x1f3e}}},
+ {0x1f37, {1|U, {0x1f3f}}},
+ {0x1f40, {1|U, {0x1f48}}},
+ {0x1f41, {1|U, {0x1f49}}},
+ {0x1f42, {1|U, {0x1f4a}}},
+ {0x1f43, {1|U, {0x1f4b}}},
+ {0x1f44, {1|U, {0x1f4c}}},
+ {0x1f45, {1|U, {0x1f4d}}},
+ {0x1f51, {1|U, {0x1f59}}},
+ {0x1f53, {1|U, {0x1f5b}}},
+ {0x1f55, {1|U, {0x1f5d}}},
+ {0x1f57, {1|U, {0x1f5f}}},
+ {0x1f60, {1|U, {0x1f68}}},
+ {0x1f61, {1|U, {0x1f69}}},
+ {0x1f62, {1|U, {0x1f6a}}},
+ {0x1f63, {1|U, {0x1f6b}}},
+ {0x1f64, {1|U, {0x1f6c}}},
+ {0x1f65, {1|U, {0x1f6d}}},
+ {0x1f66, {1|U, {0x1f6e}}},
+ {0x1f67, {1|U, {0x1f6f}}},
+ {0x1f70, {1|U, {0x1fba}}},
+ {0x1f71, {1|U, {0x1fbb}}},
+ {0x1f72, {1|U, {0x1fc8}}},
+ {0x1f73, {1|U, {0x1fc9}}},
+ {0x1f74, {1|U, {0x1fca}}},
+ {0x1f75, {1|U, {0x1fcb}}},
+ {0x1f76, {1|U, {0x1fda}}},
+ {0x1f77, {1|U, {0x1fdb}}},
+ {0x1f78, {1|U, {0x1ff8}}},
+ {0x1f79, {1|U, {0x1ff9}}},
+ {0x1f7a, {1|U, {0x1fea}}},
+ {0x1f7b, {1|U, {0x1feb}}},
+ {0x1f7c, {1|U, {0x1ffa}}},
+ {0x1f7d, {1|U, {0x1ffb}}},
+ {0x1fb0, {1|U, {0x1fb8}}},
+ {0x1fb1, {1|U, {0x1fb9}}},
+ {0x1fd0, {1|U, {0x1fd8}}},
+ {0x1fd1, {1|U, {0x1fd9}}},
+ {0x1fe0, {1|U, {0x1fe8}}},
+ {0x1fe1, {1|U, {0x1fe9}}},
+ {0x1fe5, {1|U, {0x1fec}}},
+ {0x214e, {1|U, {0x2132}}},
+ {0x2170, {1|U, {0x2160}}},
+ {0x2171, {1|U, {0x2161}}},
+ {0x2172, {1|U, {0x2162}}},
+ {0x2173, {1|U, {0x2163}}},
+ {0x2174, {1|U, {0x2164}}},
+ {0x2175, {1|U, {0x2165}}},
+ {0x2176, {1|U, {0x2166}}},
+ {0x2177, {1|U, {0x2167}}},
+ {0x2178, {1|U, {0x2168}}},
+ {0x2179, {1|U, {0x2169}}},
+ {0x217a, {1|U, {0x216a}}},
+ {0x217b, {1|U, {0x216b}}},
+ {0x217c, {1|U, {0x216c}}},
+ {0x217d, {1|U, {0x216d}}},
+ {0x217e, {1|U, {0x216e}}},
+ {0x217f, {1|U, {0x216f}}},
+ {0x2184, {1|U, {0x2183}}},
+ {0x24d0, {1|U, {0x24b6}}},
+ {0x24d1, {1|U, {0x24b7}}},
+ {0x24d2, {1|U, {0x24b8}}},
+ {0x24d3, {1|U, {0x24b9}}},
+ {0x24d4, {1|U, {0x24ba}}},
+ {0x24d5, {1|U, {0x24bb}}},
+ {0x24d6, {1|U, {0x24bc}}},
+ {0x24d7, {1|U, {0x24bd}}},
+ {0x24d8, {1|U, {0x24be}}},
+ {0x24d9, {1|U, {0x24bf}}},
+ {0x24da, {1|U, {0x24c0}}},
+ {0x24db, {1|U, {0x24c1}}},
+ {0x24dc, {1|U, {0x24c2}}},
+ {0x24dd, {1|U, {0x24c3}}},
+ {0x24de, {1|U, {0x24c4}}},
+ {0x24df, {1|U, {0x24c5}}},
+ {0x24e0, {1|U, {0x24c6}}},
+ {0x24e1, {1|U, {0x24c7}}},
+ {0x24e2, {1|U, {0x24c8}}},
+ {0x24e3, {1|U, {0x24c9}}},
+ {0x24e4, {1|U, {0x24ca}}},
+ {0x24e5, {1|U, {0x24cb}}},
+ {0x24e6, {1|U, {0x24cc}}},
+ {0x24e7, {1|U, {0x24cd}}},
+ {0x24e8, {1|U, {0x24ce}}},
+ {0x24e9, {1|U, {0x24cf}}},
+ {0x2c30, {1|U, {0x2c00}}},
+ {0x2c31, {1|U, {0x2c01}}},
+ {0x2c32, {1|U, {0x2c02}}},
+ {0x2c33, {1|U, {0x2c03}}},
+ {0x2c34, {1|U, {0x2c04}}},
+ {0x2c35, {1|U, {0x2c05}}},
+ {0x2c36, {1|U, {0x2c06}}},
+ {0x2c37, {1|U, {0x2c07}}},
+ {0x2c38, {1|U, {0x2c08}}},
+ {0x2c39, {1|U, {0x2c09}}},
+ {0x2c3a, {1|U, {0x2c0a}}},
+ {0x2c3b, {1|U, {0x2c0b}}},
+ {0x2c3c, {1|U, {0x2c0c}}},
+ {0x2c3d, {1|U, {0x2c0d}}},
+ {0x2c3e, {1|U, {0x2c0e}}},
+ {0x2c3f, {1|U, {0x2c0f}}},
+ {0x2c40, {1|U, {0x2c10}}},
+ {0x2c41, {1|U, {0x2c11}}},
+ {0x2c42, {1|U, {0x2c12}}},
+ {0x2c43, {1|U, {0x2c13}}},
+ {0x2c44, {1|U, {0x2c14}}},
+ {0x2c45, {1|U, {0x2c15}}},
+ {0x2c46, {1|U, {0x2c16}}},
+ {0x2c47, {1|U, {0x2c17}}},
+ {0x2c48, {1|U, {0x2c18}}},
+ {0x2c49, {1|U, {0x2c19}}},
+ {0x2c4a, {1|U, {0x2c1a}}},
+ {0x2c4b, {1|U, {0x2c1b}}},
+ {0x2c4c, {1|U, {0x2c1c}}},
+ {0x2c4d, {1|U, {0x2c1d}}},
+ {0x2c4e, {1|U, {0x2c1e}}},
+ {0x2c4f, {1|U, {0x2c1f}}},
+ {0x2c50, {1|U, {0x2c20}}},
+ {0x2c51, {1|U, {0x2c21}}},
+ {0x2c52, {1|U, {0x2c22}}},
+ {0x2c53, {1|U, {0x2c23}}},
+ {0x2c54, {1|U, {0x2c24}}},
+ {0x2c55, {1|U, {0x2c25}}},
+ {0x2c56, {1|U, {0x2c26}}},
+ {0x2c57, {1|U, {0x2c27}}},
+ {0x2c58, {1|U, {0x2c28}}},
+ {0x2c59, {1|U, {0x2c29}}},
+ {0x2c5a, {1|U, {0x2c2a}}},
+ {0x2c5b, {1|U, {0x2c2b}}},
+ {0x2c5c, {1|U, {0x2c2c}}},
+ {0x2c5d, {1|U, {0x2c2d}}},
+ {0x2c5e, {1|U, {0x2c2e}}},
+ {0x2c5f, {1|U, {0x2c2f}}},
+ {0x2c61, {1|U, {0x2c60}}},
+ {0x2c65, {1|U, {0x023a}}},
+ {0x2c66, {1|U, {0x023e}}},
+ {0x2c68, {1|U, {0x2c67}}},
+ {0x2c6a, {1|U, {0x2c69}}},
+ {0x2c6c, {1|U, {0x2c6b}}},
+ {0x2c73, {1|U, {0x2c72}}},
+ {0x2c76, {1|U, {0x2c75}}},
+ {0x2c81, {1|U, {0x2c80}}},
+ {0x2c83, {1|U, {0x2c82}}},
+ {0x2c85, {1|U, {0x2c84}}},
+ {0x2c87, {1|U, {0x2c86}}},
+ {0x2c89, {1|U, {0x2c88}}},
+ {0x2c8b, {1|U, {0x2c8a}}},
+ {0x2c8d, {1|U, {0x2c8c}}},
+ {0x2c8f, {1|U, {0x2c8e}}},
+ {0x2c91, {1|U, {0x2c90}}},
+ {0x2c93, {1|U, {0x2c92}}},
+ {0x2c95, {1|U, {0x2c94}}},
+ {0x2c97, {1|U, {0x2c96}}},
+ {0x2c99, {1|U, {0x2c98}}},
+ {0x2c9b, {1|U, {0x2c9a}}},
+ {0x2c9d, {1|U, {0x2c9c}}},
+ {0x2c9f, {1|U, {0x2c9e}}},
+ {0x2ca1, {1|U, {0x2ca0}}},
+ {0x2ca3, {1|U, {0x2ca2}}},
+ {0x2ca5, {1|U, {0x2ca4}}},
+ {0x2ca7, {1|U, {0x2ca6}}},
+ {0x2ca9, {1|U, {0x2ca8}}},
+ {0x2cab, {1|U, {0x2caa}}},
+ {0x2cad, {1|U, {0x2cac}}},
+ {0x2caf, {1|U, {0x2cae}}},
+ {0x2cb1, {1|U, {0x2cb0}}},
+ {0x2cb3, {1|U, {0x2cb2}}},
+ {0x2cb5, {1|U, {0x2cb4}}},
+ {0x2cb7, {1|U, {0x2cb6}}},
+ {0x2cb9, {1|U, {0x2cb8}}},
+ {0x2cbb, {1|U, {0x2cba}}},
+ {0x2cbd, {1|U, {0x2cbc}}},
+ {0x2cbf, {1|U, {0x2cbe}}},
+ {0x2cc1, {1|U, {0x2cc0}}},
+ {0x2cc3, {1|U, {0x2cc2}}},
+ {0x2cc5, {1|U, {0x2cc4}}},
+ {0x2cc7, {1|U, {0x2cc6}}},
+ {0x2cc9, {1|U, {0x2cc8}}},
+ {0x2ccb, {1|U, {0x2cca}}},
+ {0x2ccd, {1|U, {0x2ccc}}},
+ {0x2ccf, {1|U, {0x2cce}}},
+ {0x2cd1, {1|U, {0x2cd0}}},
+ {0x2cd3, {1|U, {0x2cd2}}},
+ {0x2cd5, {1|U, {0x2cd4}}},
+ {0x2cd7, {1|U, {0x2cd6}}},
+ {0x2cd9, {1|U, {0x2cd8}}},
+ {0x2cdb, {1|U, {0x2cda}}},
+ {0x2cdd, {1|U, {0x2cdc}}},
+ {0x2cdf, {1|U, {0x2cde}}},
+ {0x2ce1, {1|U, {0x2ce0}}},
+ {0x2ce3, {1|U, {0x2ce2}}},
+ {0x2cec, {1|U, {0x2ceb}}},
+ {0x2cee, {1|U, {0x2ced}}},
+ {0x2cf3, {1|U, {0x2cf2}}},
+ {0x2d00, {1|U, {0x10a0}}},
+ {0x2d01, {1|U, {0x10a1}}},
+ {0x2d02, {1|U, {0x10a2}}},
+ {0x2d03, {1|U, {0x10a3}}},
+ {0x2d04, {1|U, {0x10a4}}},
+ {0x2d05, {1|U, {0x10a5}}},
+ {0x2d06, {1|U, {0x10a6}}},
+ {0x2d07, {1|U, {0x10a7}}},
+ {0x2d08, {1|U, {0x10a8}}},
+ {0x2d09, {1|U, {0x10a9}}},
+ {0x2d0a, {1|U, {0x10aa}}},
+ {0x2d0b, {1|U, {0x10ab}}},
+ {0x2d0c, {1|U, {0x10ac}}},
+ {0x2d0d, {1|U, {0x10ad}}},
+ {0x2d0e, {1|U, {0x10ae}}},
+ {0x2d0f, {1|U, {0x10af}}},
+ {0x2d10, {1|U, {0x10b0}}},
+ {0x2d11, {1|U, {0x10b1}}},
+ {0x2d12, {1|U, {0x10b2}}},
+ {0x2d13, {1|U, {0x10b3}}},
+ {0x2d14, {1|U, {0x10b4}}},
+ {0x2d15, {1|U, {0x10b5}}},
+ {0x2d16, {1|U, {0x10b6}}},
+ {0x2d17, {1|U, {0x10b7}}},
+ {0x2d18, {1|U, {0x10b8}}},
+ {0x2d19, {1|U, {0x10b9}}},
+ {0x2d1a, {1|U, {0x10ba}}},
+ {0x2d1b, {1|U, {0x10bb}}},
+ {0x2d1c, {1|U, {0x10bc}}},
+ {0x2d1d, {1|U, {0x10bd}}},
+ {0x2d1e, {1|U, {0x10be}}},
+ {0x2d1f, {1|U, {0x10bf}}},
+ {0x2d20, {1|U, {0x10c0}}},
+ {0x2d21, {1|U, {0x10c1}}},
+ {0x2d22, {1|U, {0x10c2}}},
+ {0x2d23, {1|U, {0x10c3}}},
+ {0x2d24, {1|U, {0x10c4}}},
+ {0x2d25, {1|U, {0x10c5}}},
+ {0x2d27, {1|U, {0x10c7}}},
+ {0x2d2d, {1|U, {0x10cd}}},
+ {0xa641, {1|U, {0xa640}}},
+ {0xa643, {1|U, {0xa642}}},
+ {0xa645, {1|U, {0xa644}}},
+ {0xa647, {1|U, {0xa646}}},
+ {0xa649, {1|U, {0xa648}}},
+ {0xa64b, {2|U, {0xa64a, 0x1c88}}},
+ {0xa64d, {1|U, {0xa64c}}},
+ {0xa64f, {1|U, {0xa64e}}},
+ {0xa651, {1|U, {0xa650}}},
+ {0xa653, {1|U, {0xa652}}},
+ {0xa655, {1|U, {0xa654}}},
+ {0xa657, {1|U, {0xa656}}},
+ {0xa659, {1|U, {0xa658}}},
+ {0xa65b, {1|U, {0xa65a}}},
+ {0xa65d, {1|U, {0xa65c}}},
+ {0xa65f, {1|U, {0xa65e}}},
+ {0xa661, {1|U, {0xa660}}},
+ {0xa663, {1|U, {0xa662}}},
+ {0xa665, {1|U, {0xa664}}},
+ {0xa667, {1|U, {0xa666}}},
+ {0xa669, {1|U, {0xa668}}},
+ {0xa66b, {1|U, {0xa66a}}},
+ {0xa66d, {1|U, {0xa66c}}},
+ {0xa681, {1|U, {0xa680}}},
+ {0xa683, {1|U, {0xa682}}},
+ {0xa685, {1|U, {0xa684}}},
+ {0xa687, {1|U, {0xa686}}},
+ {0xa689, {1|U, {0xa688}}},
+ {0xa68b, {1|U, {0xa68a}}},
+ {0xa68d, {1|U, {0xa68c}}},
+ {0xa68f, {1|U, {0xa68e}}},
+ {0xa691, {1|U, {0xa690}}},
+ {0xa693, {1|U, {0xa692}}},
+ {0xa695, {1|U, {0xa694}}},
+ {0xa697, {1|U, {0xa696}}},
+ {0xa699, {1|U, {0xa698}}},
+ {0xa69b, {1|U, {0xa69a}}},
+ {0xa723, {1|U, {0xa722}}},
+ {0xa725, {1|U, {0xa724}}},
+ {0xa727, {1|U, {0xa726}}},
+ {0xa729, {1|U, {0xa728}}},
+ {0xa72b, {1|U, {0xa72a}}},
+ {0xa72d, {1|U, {0xa72c}}},
+ {0xa72f, {1|U, {0xa72e}}},
+ {0xa733, {1|U, {0xa732}}},
+ {0xa735, {1|U, {0xa734}}},
+ {0xa737, {1|U, {0xa736}}},
+ {0xa739, {1|U, {0xa738}}},
+ {0xa73b, {1|U, {0xa73a}}},
+ {0xa73d, {1|U, {0xa73c}}},
+ {0xa73f, {1|U, {0xa73e}}},
+ {0xa741, {1|U, {0xa740}}},
+ {0xa743, {1|U, {0xa742}}},
+ {0xa745, {1|U, {0xa744}}},
+ {0xa747, {1|U, {0xa746}}},
+ {0xa749, {1|U, {0xa748}}},
+ {0xa74b, {1|U, {0xa74a}}},
+ {0xa74d, {1|U, {0xa74c}}},
+ {0xa74f, {1|U, {0xa74e}}},
+ {0xa751, {1|U, {0xa750}}},
+ {0xa753, {1|U, {0xa752}}},
+ {0xa755, {1|U, {0xa754}}},
+ {0xa757, {1|U, {0xa756}}},
+ {0xa759, {1|U, {0xa758}}},
+ {0xa75b, {1|U, {0xa75a}}},
+ {0xa75d, {1|U, {0xa75c}}},
+ {0xa75f, {1|U, {0xa75e}}},
+ {0xa761, {1|U, {0xa760}}},
+ {0xa763, {1|U, {0xa762}}},
+ {0xa765, {1|U, {0xa764}}},
+ {0xa767, {1|U, {0xa766}}},
+ {0xa769, {1|U, {0xa768}}},
+ {0xa76b, {1|U, {0xa76a}}},
+ {0xa76d, {1|U, {0xa76c}}},
+ {0xa76f, {1|U, {0xa76e}}},
+ {0xa77a, {1|U, {0xa779}}},
+ {0xa77c, {1|U, {0xa77b}}},
+ {0xa77f, {1|U, {0xa77e}}},
+ {0xa781, {1|U, {0xa780}}},
+ {0xa783, {1|U, {0xa782}}},
+ {0xa785, {1|U, {0xa784}}},
+ {0xa787, {1|U, {0xa786}}},
+ {0xa78c, {1|U, {0xa78b}}},
+ {0xa791, {1|U, {0xa790}}},
+ {0xa793, {1|U, {0xa792}}},
+ {0xa794, {1|U, {0xa7c4}}},
+ {0xa797, {1|U, {0xa796}}},
+ {0xa799, {1|U, {0xa798}}},
+ {0xa79b, {1|U, {0xa79a}}},
+ {0xa79d, {1|U, {0xa79c}}},
+ {0xa79f, {1|U, {0xa79e}}},
+ {0xa7a1, {1|U, {0xa7a0}}},
+ {0xa7a3, {1|U, {0xa7a2}}},
+ {0xa7a5, {1|U, {0xa7a4}}},
+ {0xa7a7, {1|U, {0xa7a6}}},
+ {0xa7a9, {1|U, {0xa7a8}}},
+ {0xa7b5, {1|U, {0xa7b4}}},
+ {0xa7b7, {1|U, {0xa7b6}}},
+ {0xa7b9, {1|U, {0xa7b8}}},
+ {0xa7bb, {1|U, {0xa7ba}}},
+ {0xa7bd, {1|U, {0xa7bc}}},
+ {0xa7bf, {1|U, {0xa7be}}},
+ {0xa7c1, {1|U, {0xa7c0}}},
+ {0xa7c3, {1|U, {0xa7c2}}},
+ {0xa7c8, {1|U, {0xa7c7}}},
+ {0xa7ca, {1|U, {0xa7c9}}},
+ {0xa7cd, {1|U, {0xa7cc}}},
+ {0xa7cf, {1|U, {0xa7ce}}},
+ {0xa7d1, {1|U, {0xa7d0}}},
+ {0xa7d3, {1|U, {0xa7d2}}},
+ {0xa7d5, {1|U, {0xa7d4}}},
+ {0xa7d7, {1|U, {0xa7d6}}},
+ {0xa7d9, {1|U, {0xa7d8}}},
+ {0xa7db, {1|U, {0xa7da}}},
+ {0xa7f6, {1|U, {0xa7f5}}},
+ {0xab53, {1|U, {0xa7b3}}},
+ {0xff41, {1|U, {0xff21}}},
+ {0xff42, {1|U, {0xff22}}},
+ {0xff43, {1|U, {0xff23}}},
+ {0xff44, {1|U, {0xff24}}},
+ {0xff45, {1|U, {0xff25}}},
+ {0xff46, {1|U, {0xff26}}},
+ {0xff47, {1|U, {0xff27}}},
+ {0xff48, {1|U, {0xff28}}},
+ {0xff49, {1|U, {0xff29}}},
+ {0xff4a, {1|U, {0xff2a}}},
+ {0xff4b, {1|U, {0xff2b}}},
+ {0xff4c, {1|U, {0xff2c}}},
+ {0xff4d, {1|U, {0xff2d}}},
+ {0xff4e, {1|U, {0xff2e}}},
+ {0xff4f, {1|U, {0xff2f}}},
+ {0xff50, {1|U, {0xff30}}},
+ {0xff51, {1|U, {0xff31}}},
+ {0xff52, {1|U, {0xff32}}},
+ {0xff53, {1|U, {0xff33}}},
+ {0xff54, {1|U, {0xff34}}},
+ {0xff55, {1|U, {0xff35}}},
+ {0xff56, {1|U, {0xff36}}},
+ {0xff57, {1|U, {0xff37}}},
+ {0xff58, {1|U, {0xff38}}},
+ {0xff59, {1|U, {0xff39}}},
+ {0xff5a, {1|U, {0xff3a}}},
+ {0x10428, {1|U, {0x10400}}},
+ {0x10429, {1|U, {0x10401}}},
+ {0x1042a, {1|U, {0x10402}}},
+ {0x1042b, {1|U, {0x10403}}},
+ {0x1042c, {1|U, {0x10404}}},
+ {0x1042d, {1|U, {0x10405}}},
+ {0x1042e, {1|U, {0x10406}}},
+ {0x1042f, {1|U, {0x10407}}},
+ {0x10430, {1|U, {0x10408}}},
+ {0x10431, {1|U, {0x10409}}},
+ {0x10432, {1|U, {0x1040a}}},
+ {0x10433, {1|U, {0x1040b}}},
+ {0x10434, {1|U, {0x1040c}}},
+ {0x10435, {1|U, {0x1040d}}},
+ {0x10436, {1|U, {0x1040e}}},
+ {0x10437, {1|U, {0x1040f}}},
+ {0x10438, {1|U, {0x10410}}},
+ {0x10439, {1|U, {0x10411}}},
+ {0x1043a, {1|U, {0x10412}}},
+ {0x1043b, {1|U, {0x10413}}},
+ {0x1043c, {1|U, {0x10414}}},
+ {0x1043d, {1|U, {0x10415}}},
+ {0x1043e, {1|U, {0x10416}}},
+ {0x1043f, {1|U, {0x10417}}},
+ {0x10440, {1|U, {0x10418}}},
+ {0x10441, {1|U, {0x10419}}},
+ {0x10442, {1|U, {0x1041a}}},
+ {0x10443, {1|U, {0x1041b}}},
+ {0x10444, {1|U, {0x1041c}}},
+ {0x10445, {1|U, {0x1041d}}},
+ {0x10446, {1|U, {0x1041e}}},
+ {0x10447, {1|U, {0x1041f}}},
+ {0x10448, {1|U, {0x10420}}},
+ {0x10449, {1|U, {0x10421}}},
+ {0x1044a, {1|U, {0x10422}}},
+ {0x1044b, {1|U, {0x10423}}},
+ {0x1044c, {1|U, {0x10424}}},
+ {0x1044d, {1|U, {0x10425}}},
+ {0x1044e, {1|U, {0x10426}}},
+ {0x1044f, {1|U, {0x10427}}},
+ {0x104d8, {1|U, {0x104b0}}},
+ {0x104d9, {1|U, {0x104b1}}},
+ {0x104da, {1|U, {0x104b2}}},
+ {0x104db, {1|U, {0x104b3}}},
+ {0x104dc, {1|U, {0x104b4}}},
+ {0x104dd, {1|U, {0x104b5}}},
+ {0x104de, {1|U, {0x104b6}}},
+ {0x104df, {1|U, {0x104b7}}},
+ {0x104e0, {1|U, {0x104b8}}},
+ {0x104e1, {1|U, {0x104b9}}},
+ {0x104e2, {1|U, {0x104ba}}},
+ {0x104e3, {1|U, {0x104bb}}},
+ {0x104e4, {1|U, {0x104bc}}},
+ {0x104e5, {1|U, {0x104bd}}},
+ {0x104e6, {1|U, {0x104be}}},
+ {0x104e7, {1|U, {0x104bf}}},
+ {0x104e8, {1|U, {0x104c0}}},
+ {0x104e9, {1|U, {0x104c1}}},
+ {0x104ea, {1|U, {0x104c2}}},
+ {0x104eb, {1|U, {0x104c3}}},
+ {0x104ec, {1|U, {0x104c4}}},
+ {0x104ed, {1|U, {0x104c5}}},
+ {0x104ee, {1|U, {0x104c6}}},
+ {0x104ef, {1|U, {0x104c7}}},
+ {0x104f0, {1|U, {0x104c8}}},
+ {0x104f1, {1|U, {0x104c9}}},
+ {0x104f2, {1|U, {0x104ca}}},
+ {0x104f3, {1|U, {0x104cb}}},
+ {0x104f4, {1|U, {0x104cc}}},
+ {0x104f5, {1|U, {0x104cd}}},
+ {0x104f6, {1|U, {0x104ce}}},
+ {0x104f7, {1|U, {0x104cf}}},
+ {0x104f8, {1|U, {0x104d0}}},
+ {0x104f9, {1|U, {0x104d1}}},
+ {0x104fa, {1|U, {0x104d2}}},
+ {0x104fb, {1|U, {0x104d3}}},
+ {0x10597, {1|U, {0x10570}}},
+ {0x10598, {1|U, {0x10571}}},
+ {0x10599, {1|U, {0x10572}}},
+ {0x1059a, {1|U, {0x10573}}},
+ {0x1059b, {1|U, {0x10574}}},
+ {0x1059c, {1|U, {0x10575}}},
+ {0x1059d, {1|U, {0x10576}}},
+ {0x1059e, {1|U, {0x10577}}},
+ {0x1059f, {1|U, {0x10578}}},
+ {0x105a0, {1|U, {0x10579}}},
+ {0x105a1, {1|U, {0x1057a}}},
+ {0x105a3, {1|U, {0x1057c}}},
+ {0x105a4, {1|U, {0x1057d}}},
+ {0x105a5, {1|U, {0x1057e}}},
+ {0x105a6, {1|U, {0x1057f}}},
+ {0x105a7, {1|U, {0x10580}}},
+ {0x105a8, {1|U, {0x10581}}},
+ {0x105a9, {1|U, {0x10582}}},
+ {0x105aa, {1|U, {0x10583}}},
+ {0x105ab, {1|U, {0x10584}}},
+ {0x105ac, {1|U, {0x10585}}},
+ {0x105ad, {1|U, {0x10586}}},
+ {0x105ae, {1|U, {0x10587}}},
+ {0x105af, {1|U, {0x10588}}},
+ {0x105b0, {1|U, {0x10589}}},
+ {0x105b1, {1|U, {0x1058a}}},
+ {0x105b3, {1|U, {0x1058c}}},
+ {0x105b4, {1|U, {0x1058d}}},
+ {0x105b5, {1|U, {0x1058e}}},
+ {0x105b6, {1|U, {0x1058f}}},
+ {0x105b7, {1|U, {0x10590}}},
+ {0x105b8, {1|U, {0x10591}}},
+ {0x105b9, {1|U, {0x10592}}},
+ {0x105bb, {1|U, {0x10594}}},
+ {0x105bc, {1|U, {0x10595}}},
+ {0x10cc0, {1|U, {0x10c80}}},
+ {0x10cc1, {1|U, {0x10c81}}},
+ {0x10cc2, {1|U, {0x10c82}}},
+ {0x10cc3, {1|U, {0x10c83}}},
+ {0x10cc4, {1|U, {0x10c84}}},
+ {0x10cc5, {1|U, {0x10c85}}},
+ {0x10cc6, {1|U, {0x10c86}}},
+ {0x10cc7, {1|U, {0x10c87}}},
+ {0x10cc8, {1|U, {0x10c88}}},
+ {0x10cc9, {1|U, {0x10c89}}},
+ {0x10cca, {1|U, {0x10c8a}}},
+ {0x10ccb, {1|U, {0x10c8b}}},
+ {0x10ccc, {1|U, {0x10c8c}}},
+ {0x10ccd, {1|U, {0x10c8d}}},
+ {0x10cce, {1|U, {0x10c8e}}},
+ {0x10ccf, {1|U, {0x10c8f}}},
+ {0x10cd0, {1|U, {0x10c90}}},
+ {0x10cd1, {1|U, {0x10c91}}},
+ {0x10cd2, {1|U, {0x10c92}}},
+ {0x10cd3, {1|U, {0x10c93}}},
+ {0x10cd4, {1|U, {0x10c94}}},
+ {0x10cd5, {1|U, {0x10c95}}},
+ {0x10cd6, {1|U, {0x10c96}}},
+ {0x10cd7, {1|U, {0x10c97}}},
+ {0x10cd8, {1|U, {0x10c98}}},
+ {0x10cd9, {1|U, {0x10c99}}},
+ {0x10cda, {1|U, {0x10c9a}}},
+ {0x10cdb, {1|U, {0x10c9b}}},
+ {0x10cdc, {1|U, {0x10c9c}}},
+ {0x10cdd, {1|U, {0x10c9d}}},
+ {0x10cde, {1|U, {0x10c9e}}},
+ {0x10cdf, {1|U, {0x10c9f}}},
+ {0x10ce0, {1|U, {0x10ca0}}},
+ {0x10ce1, {1|U, {0x10ca1}}},
+ {0x10ce2, {1|U, {0x10ca2}}},
+ {0x10ce3, {1|U, {0x10ca3}}},
+ {0x10ce4, {1|U, {0x10ca4}}},
+ {0x10ce5, {1|U, {0x10ca5}}},
+ {0x10ce6, {1|U, {0x10ca6}}},
+ {0x10ce7, {1|U, {0x10ca7}}},
+ {0x10ce8, {1|U, {0x10ca8}}},
+ {0x10ce9, {1|U, {0x10ca9}}},
+ {0x10cea, {1|U, {0x10caa}}},
+ {0x10ceb, {1|U, {0x10cab}}},
+ {0x10cec, {1|U, {0x10cac}}},
+ {0x10ced, {1|U, {0x10cad}}},
+ {0x10cee, {1|U, {0x10cae}}},
+ {0x10cef, {1|U, {0x10caf}}},
+ {0x10cf0, {1|U, {0x10cb0}}},
+ {0x10cf1, {1|U, {0x10cb1}}},
+ {0x10cf2, {1|U, {0x10cb2}}},
+ {0x10d70, {1|U, {0x10d50}}},
+ {0x10d71, {1|U, {0x10d51}}},
+ {0x10d72, {1|U, {0x10d52}}},
+ {0x10d73, {1|U, {0x10d53}}},
+ {0x10d74, {1|U, {0x10d54}}},
+ {0x10d75, {1|U, {0x10d55}}},
+ {0x10d76, {1|U, {0x10d56}}},
+ {0x10d77, {1|U, {0x10d57}}},
+ {0x10d78, {1|U, {0x10d58}}},
+ {0x10d79, {1|U, {0x10d59}}},
+ {0x10d7a, {1|U, {0x10d5a}}},
+ {0x10d7b, {1|U, {0x10d5b}}},
+ {0x10d7c, {1|U, {0x10d5c}}},
+ {0x10d7d, {1|U, {0x10d5d}}},
+ {0x10d7e, {1|U, {0x10d5e}}},
+ {0x10d7f, {1|U, {0x10d5f}}},
+ {0x10d80, {1|U, {0x10d60}}},
+ {0x10d81, {1|U, {0x10d61}}},
+ {0x10d82, {1|U, {0x10d62}}},
+ {0x10d83, {1|U, {0x10d63}}},
+ {0x10d84, {1|U, {0x10d64}}},
+ {0x10d85, {1|U, {0x10d65}}},
+ {0x118c0, {1|U, {0x118a0}}},
+ {0x118c1, {1|U, {0x118a1}}},
+ {0x118c2, {1|U, {0x118a2}}},
+ {0x118c3, {1|U, {0x118a3}}},
+ {0x118c4, {1|U, {0x118a4}}},
+ {0x118c5, {1|U, {0x118a5}}},
+ {0x118c6, {1|U, {0x118a6}}},
+ {0x118c7, {1|U, {0x118a7}}},
+ {0x118c8, {1|U, {0x118a8}}},
+ {0x118c9, {1|U, {0x118a9}}},
+ {0x118ca, {1|U, {0x118aa}}},
+ {0x118cb, {1|U, {0x118ab}}},
+ {0x118cc, {1|U, {0x118ac}}},
+ {0x118cd, {1|U, {0x118ad}}},
+ {0x118ce, {1|U, {0x118ae}}},
+ {0x118cf, {1|U, {0x118af}}},
+ {0x118d0, {1|U, {0x118b0}}},
+ {0x118d1, {1|U, {0x118b1}}},
+ {0x118d2, {1|U, {0x118b2}}},
+ {0x118d3, {1|U, {0x118b3}}},
+ {0x118d4, {1|U, {0x118b4}}},
+ {0x118d5, {1|U, {0x118b5}}},
+ {0x118d6, {1|U, {0x118b6}}},
+ {0x118d7, {1|U, {0x118b7}}},
+ {0x118d8, {1|U, {0x118b8}}},
+ {0x118d9, {1|U, {0x118b9}}},
+ {0x118da, {1|U, {0x118ba}}},
+ {0x118db, {1|U, {0x118bb}}},
+ {0x118dc, {1|U, {0x118bc}}},
+ {0x118dd, {1|U, {0x118bd}}},
+ {0x118de, {1|U, {0x118be}}},
+ {0x118df, {1|U, {0x118bf}}},
+ {0x16e60, {1|U, {0x16e40}}},
+ {0x16e61, {1|U, {0x16e41}}},
+ {0x16e62, {1|U, {0x16e42}}},
+ {0x16e63, {1|U, {0x16e43}}},
+ {0x16e64, {1|U, {0x16e44}}},
+ {0x16e65, {1|U, {0x16e45}}},
+ {0x16e66, {1|U, {0x16e46}}},
+ {0x16e67, {1|U, {0x16e47}}},
+ {0x16e68, {1|U, {0x16e48}}},
+ {0x16e69, {1|U, {0x16e49}}},
+ {0x16e6a, {1|U, {0x16e4a}}},
+ {0x16e6b, {1|U, {0x16e4b}}},
+ {0x16e6c, {1|U, {0x16e4c}}},
+ {0x16e6d, {1|U, {0x16e4d}}},
+ {0x16e6e, {1|U, {0x16e4e}}},
+ {0x16e6f, {1|U, {0x16e4f}}},
+ {0x16e70, {1|U, {0x16e50}}},
+ {0x16e71, {1|U, {0x16e51}}},
+ {0x16e72, {1|U, {0x16e52}}},
+ {0x16e73, {1|U, {0x16e53}}},
+ {0x16e74, {1|U, {0x16e54}}},
+ {0x16e75, {1|U, {0x16e55}}},
+ {0x16e76, {1|U, {0x16e56}}},
+ {0x16e77, {1|U, {0x16e57}}},
+ {0x16e78, {1|U, {0x16e58}}},
+ {0x16e79, {1|U, {0x16e59}}},
+ {0x16e7a, {1|U, {0x16e5a}}},
+ {0x16e7b, {1|U, {0x16e5b}}},
+ {0x16e7c, {1|U, {0x16e5c}}},
+ {0x16e7d, {1|U, {0x16e5d}}},
+ {0x16e7e, {1|U, {0x16e5e}}},
+ {0x16e7f, {1|U, {0x16e5f}}},
+ {0x16ebb, {1|U, {0x16ea0}}},
+ {0x16ebc, {1|U, {0x16ea1}}},
+ {0x16ebd, {1|U, {0x16ea2}}},
+ {0x16ebe, {1|U, {0x16ea3}}},
+ {0x16ebf, {1|U, {0x16ea4}}},
+ {0x16ec0, {1|U, {0x16ea5}}},
+ {0x16ec1, {1|U, {0x16ea6}}},
+ {0x16ec2, {1|U, {0x16ea7}}},
+ {0x16ec3, {1|U, {0x16ea8}}},
+ {0x16ec4, {1|U, {0x16ea9}}},
+ {0x16ec5, {1|U, {0x16eaa}}},
+ {0x16ec6, {1|U, {0x16eab}}},
+ {0x16ec7, {1|U, {0x16eac}}},
+ {0x16ec8, {1|U, {0x16ead}}},
+ {0x16ec9, {1|U, {0x16eae}}},
+ {0x16eca, {1|U, {0x16eaf}}},
+ {0x16ecb, {1|U, {0x16eb0}}},
+ {0x16ecc, {1|U, {0x16eb1}}},
+ {0x16ecd, {1|U, {0x16eb2}}},
+ {0x16ece, {1|U, {0x16eb3}}},
+ {0x16ecf, {1|U, {0x16eb4}}},
+ {0x16ed0, {1|U, {0x16eb5}}},
+ {0x16ed1, {1|U, {0x16eb6}}},
+ {0x16ed2, {1|U, {0x16eb7}}},
+ {0x16ed3, {1|U, {0x16eb8}}},
+ {0x1e922, {1|U, {0x1e900}}},
+ {0x1e923, {1|U, {0x1e901}}},
+ {0x1e924, {1|U, {0x1e902}}},
+ {0x1e925, {1|U, {0x1e903}}},
+ {0x1e926, {1|U, {0x1e904}}},
+ {0x1e927, {1|U, {0x1e905}}},
+ {0x1e928, {1|U, {0x1e906}}},
+ {0x1e929, {1|U, {0x1e907}}},
+ {0x1e92a, {1|U, {0x1e908}}},
+ {0x1e92b, {1|U, {0x1e909}}},
+ {0x1e92c, {1|U, {0x1e90a}}},
+ {0x1e92d, {1|U, {0x1e90b}}},
+ {0x1e92e, {1|U, {0x1e90c}}},
+ {0x1e92f, {1|U, {0x1e90d}}},
+ {0x1e930, {1|U, {0x1e90e}}},
+ {0x1e931, {1|U, {0x1e90f}}},
+ {0x1e932, {1|U, {0x1e910}}},
+ {0x1e933, {1|U, {0x1e911}}},
+ {0x1e934, {1|U, {0x1e912}}},
+ {0x1e935, {1|U, {0x1e913}}},
+ {0x1e936, {1|U, {0x1e914}}},
+ {0x1e937, {1|U, {0x1e915}}},
+ {0x1e938, {1|U, {0x1e916}}},
+ {0x1e939, {1|U, {0x1e917}}},
+ {0x1e93a, {1|U, {0x1e918}}},
+ {0x1e93b, {1|U, {0x1e919}}},
+ {0x1e93c, {1|U, {0x1e91a}}},
+ {0x1e93d, {1|U, {0x1e91b}}},
+ {0x1e93e, {1|U, {0x1e91c}}},
+ {0x1e93f, {1|U, {0x1e91d}}},
+ {0x1e940, {1|U, {0x1e91e}}},
+ {0x1e941, {1|U, {0x1e91f}}},
+ {0x1e942, {1|U, {0x1e920}}},
+ {0x1e943, {1|U, {0x1e921}}},
+#define CaseUnfold_11_Locale (*(CaseUnfold_11_Type (*)[1])(CaseUnfold_11_Table+1450))
+ {0x0069, {1|U, {0x0049}}},
+};
+
+/* ANSI-C code produced by gperf version 3.1 */
+/* Command-line: gperf -7 -k1,2,3 -F,-1 -c -j1 -i1 -t -T -E -C -H onigenc_unicode_CaseUnfold_11_hash -N onigenc_unicode_CaseUnfold_11_lookup -n */
+
+/* maximum key range = 2881, duplicates = 0 */
+
+#ifdef __GNUC__
+__inline
+#else
+#ifdef __cplusplus
+inline
+#endif
+#endif
+/*ARGSUSED*/
+static unsigned int
+onigenc_unicode_CaseUnfold_11_hash(const OnigCodePoint code)
+{
+ static const unsigned short asso_values[] =
+ {
+ 1, 2884, 2, 29, 4, 134, 9, 131, 10, 229,
+ 121, 246, 2, 3, 540, 359, 2884, 2884, 2884, 2884,
+ 2884, 2884, 2884, 2884, 2884, 2884, 2884, 2884, 2884, 103,
+ 401, 111, 2884, 2884, 2884, 2884, 2884, 127, 2884, 2884,
+ 2884, 2884, 2884, 1, 2884, 2884, 2884, 2884, 2884, 2884,
+ 2884, 2884, 2884, 339, 2884, 2884, 2884, 2884, 2884, 2884,
+ 2884, 15, 9, 1, 7, 8, 341, 797, 60, 1080,
+ 101, 804, 35, 1589, 7, 1841, 17, 16, 58, 1709,
+ 216, 1040, 47, 103, 64, 1339, 219, 1539, 4, 1704,
+ 52, 1508, 344, 11, 501, 1733, 526, 347, 133, 1161,
+ 340, 913, 104, 883, 170, 743, 339, 1103, 398, 1465,
+ 376, 829, 138, 1092, 280, 967, 1876, 785, 1694, 774,
+ 1640, 721, 1852, 951, 1830, 937, 1573, 925, 1736, 666,
+ 897, 502, 693, 475, 1385, 651, 1356, 639, 1184, 532,
+ 1532, 520, 1479, 420, 1225, 203, 1248, 82, 1277, 115,
+ 1758, 289, 1673, 93, 1686, 71, 1666, 60, 1650, 256,
+ 1789, 232, 1552, 1, 1649, 27, 1489, 38, 1247, 144,
+ 1445, 49, 1624, 221, 1418, 327, 1769, 312, 1306, 584,
+ 1075, 363, 1506, 609, 1405, 1213, 1074, 1065, 1362, 1151,
+ 1556, 863, 726, 1429
+ };
+ return asso_values[bits_of(code, 2)+66] + asso_values[bits_of(code, 1)+4] + asso_values[bits_of(code, 0)];
+}
+
+static const CodePointList3 *
+onigenc_unicode_CaseUnfold_11_lookup(const OnigCodePoint code)
+{
+ enum
+ {
+ MIN_CODE_VALUE = 0x61,
+ MAX_CODE_VALUE = 0x1e943,
+ TOTAL_KEYWORDS = 1451,
+ MIN_WORD_LENGTH = 3,
+ MAX_WORD_LENGTH = 3,
+ MIN_HASH_VALUE = 3,
+ MAX_HASH_VALUE = 2883
+ };
+
+ static const short wordlist[] =
+ {
+ -1, -1, -1,
+ /*0x13e1*/ 591,
+ /*0x0461*/ 342,
+ /*0x04e1*/ 402,
+ /*0x0061*/ 0,
+ -1,
+ /*0x104e1*/ 1192,
+ /*0x1e61*/ 664,
+ /*0x1ee1*/ 723,
+ /*0x0161*/ 102,
+ /*0x0261*/ 211,
+ /*0x2ce1*/ 956,
+ -1,
+ /*0x049b*/ 367,
+ -1, -1,
+ /*0x24e1*/ 843,
+ /*0x1e1b*/ 629,
+ /*0x048b*/ 359,
+ /*0x011b*/ 69,
+ /*0x021b*/ 179,
+ /*0x2c9b*/ 921,
+ /*0x1e0b*/ 621,
+ /*0x1e8b*/ 685,
+ /*0x010b*/ 61,
+ /*0x020b*/ 171,
+ /*0x2c8b*/ 913,
+ /*0x13e3*/ 593,
+ /*0x0463*/ 343,
+ /*0x04e3*/ 403,
+ /*0x0063*/ 2,
+ /*0x1c8a*/ 612,
+ /*0x104e3*/ 1194,
+ /*0x1e63*/ 665,
+ /*0x1ee3*/ 724,
+ /*0x0163*/ 103,
+ /*0x0263*/ 212,
+ /*0x2ce3*/ 957,
+ /*0x13e5*/ 595,
+ /*0x0465*/ 344,
+ /*0x04e5*/ 404,
+ /*0x0065*/ 4,
+ /*0x24e3*/ 845,
+ /*0x104e5*/ 1196,
+ /*0x1e65*/ 666,
+ /*0x1ee5*/ 725,
+ /*0x0165*/ 104,
+ /*0x0265*/ 214,
+ /*0xa761*/ 1068,
+ /*0x13e9*/ 599,
+ /*0x0469*/ 346,
+ /*0x04e9*/ 406,
+ /*0x0069*/ 1450,
+ /*0x24e5*/ 847,
+ /*0x104e9*/ 1200,
+ /*0x1e69*/ 668,
+ /*0x1ee9*/ 727,
+ /*0x0169*/ 106,
+ /*0x0269*/ 217,
+ -1,
+ /*0x13db*/ 585,
+ /*0x045b*/ 337,
+ /*0x04db*/ 399,
+ -1,
+ /*0x24e9*/ 851,
+ /*0x104db*/ 1186,
+ /*0x1e5b*/ 661,
+ /*0x1edb*/ 720,
+ /*0x015b*/ 99,
+ /*0x025b*/ 208,
+ /*0x2cdb*/ 953,
+ /*0x13d9*/ 583,
+ /*0x0459*/ 335,
+ /*0x04d9*/ 398,
+ /*0xa763*/ 1069,
+ /*0x24db*/ 837,
+ /*0x104d9*/ 1184,
+ /*0x1e59*/ 660,
+ /*0x1ed9*/ 719,
+ /*0x0159*/ 98,
+ /*0x0259*/ 207,
+ /*0x2cd9*/ 952,
+ /*0x13d1*/ 575,
+ /*0x0451*/ 327,
+ /*0x04d1*/ 394,
+ /*0xa765*/ 1070,
+ /*0x24d9*/ 835,
+ -1,
+ /*0x1e51*/ 656,
+ /*0x1ed1*/ 715,
+ /*0x0151*/ 94,
+ /*0x0251*/ 201,
+ /*0x2cd1*/ 948,
+ /*0x13d7*/ 581,
+ /*0x0457*/ 333,
+ /*0x04d7*/ 397,
+ /*0xa769*/ 1072,
+ /*0x24d1*/ 827,
+ -1,
+ /*0x1e57*/ 659,
+ /*0x1ed7*/ 718,
+ /*0x0157*/ 97,
+ /*0x0257*/ 206,
+ /*0x2cd7*/ 951,
+ /*0x13a4*/ 530,
+ /*0x0491*/ 362,
+ /*0x10ce1*/ 1287,
+ /*0xa75b*/ 1065,
+ /*0x24d7*/ 833,
+ /*0x1e11*/ 624,
+ /*0x1e91*/ 688,
+ /*0x0111*/ 64,
+ /*0x0211*/ 174,
+ /*0x2c91*/ 916,
+ /*0xa79b*/ 1089,
+ /*0x13d3*/ 577,
+ /*0x0453*/ 329,
+ /*0x04d3*/ 395,
+ /*0xa759*/ 1064,
+ -1, -1,
+ /*0x1e53*/ 657,
+ /*0x1ed3*/ 716,
+ /*0x0153*/ 95,
+ /*0x0253*/ 203,
+ /*0x2cd3*/ 949,
+ -1,
+ /*0x10e1*/ 497,
+ -1,
+ /*0xa751*/ 1060,
+ /*0x24d3*/ 829,
+ /*0x01e1*/ 152,
+ /*0x10ce3*/ 1289,
+ /*0x13a0*/ 526,
+ /*0x00e1*/ 26,
+ -1, -1,
+ /*0x0188*/ 120,
+ /*0x13ae*/ 540,
+ -1,
+ /*0xa757*/ 1063,
+ /*0x019b*/ 126,
+ /*0x1042e*/ 1149,
+ /*0x10ce5*/ 1291,
+ /*0x13e7*/ 597,
+ /*0x0467*/ 345,
+ /*0x04e7*/ 405,
+ /*0x0067*/ 6,
+ -1,
+ /*0x104e7*/ 1198,
+ /*0x1e67*/ 667,
+ /*0x1ee7*/ 726,
+ /*0x0167*/ 105,
+ /*0x10e3*/ 499,
+ /*0x10ce9*/ 1295,
+ -1, -1,
+ /*0x01e3*/ 153,
+ -1,
+ /*0x24e7*/ 849,
+ /*0x00e3*/ 28,
+ /*0xa78c*/ 1083,
+ /*0xa753*/ 1061,
+ /*0xa7db*/ 1114,
+ /*0x10e5*/ 501,
+ /*0x10cdb*/ 1281,
+ -1,
+ /*0xab53*/ 1116,
+ /*0x01e5*/ 154,
+ -1,
+ /*0x13a6*/ 532,
+ /*0x00e5*/ 30,
+ -1,
+ /*0x10d82*/ 1323,
+ /*0xa7d9*/ 1113,
+ /*0x10e9*/ 505,
+ /*0x10cd9*/ 1279,
+ -1, -1,
+ /*0x01e9*/ 156,
+ -1, -1,
+ /*0x00e9*/ 34,
+ -1, -1,
+ /*0xa7d1*/ 1109,
+ /*0x10db*/ 491,
+ /*0x10cd1*/ 1271,
+ /*0x018c*/ 121,
+ -1, -1,
+ /*0xa767*/ 1071,
+ -1, -1,
+ /*0x0192*/ 122,
+ -1,
+ /*0xa7d7*/ 1112,
+ /*0x10d9*/ 489,
+ /*0x10cd7*/ 1277,
+ -1, -1, -1, -1,
+ /*0x13cf*/ 573,
+ /*0x044f*/ 325,
+ /*0x04cf*/ 393,
+ /*0xa791*/ 1084,
+ /*0x1044f*/ 1182,
+ /*0x10d1*/ 481,
+ /*0x1e4f*/ 655,
+ /*0x1ecf*/ 714,
+ /*0x014f*/ 93,
+ /*0x024f*/ 199,
+ /*0x2ccf*/ 947,
+ /*0x10d84*/ 1325,
+ -1,
+ /*0x1d8e*/ 615,
+ /*0xa661*/ 1017,
+ /*0xa7d3*/ 1110,
+ /*0x10d7*/ 487,
+ /*0x10cd3*/ 1273,
+ /*0x13eb*/ 601,
+ /*0x046b*/ 347,
+ /*0x04eb*/ 407,
+ /*0x006b*/ 9,
+ -1,
+ /*0x104eb*/ 1202,
+ /*0x1e6b*/ 669,
+ /*0x1eeb*/ 728,
+ /*0x016b*/ 107,
+ /*0x026b*/ 219,
+ -1,
+ /*0x13df*/ 589,
+ /*0x045f*/ 341,
+ /*0x04df*/ 401,
+ /*0x0288*/ 230,
+ -1,
+ /*0x104df*/ 1190,
+ /*0x1e5f*/ 663,
+ /*0x1edf*/ 722,
+ /*0x015f*/ 101,
+ /*0x10d3*/ 483,
+ /*0x2cdf*/ 955,
+ /*0xa663*/ 1018,
+ /*0x028b*/ 233,
+ /*0x028a*/ 232,
+ /*0x03e1*/ 282,
+ /*0x24df*/ 841,
+ -1,
+ /*0x10ce7*/ 1293,
+ /*0xa74f*/ 1059,
+ -1, -1, -1,
+ /*0xa665*/ 1019,
+ -1,
+ /*0x13dd*/ 587,
+ /*0x045d*/ 339,
+ /*0x04dd*/ 400,
+ -1, -1,
+ /*0x104dd*/ 1188,
+ /*0x1e5d*/ 662,
+ /*0x1edd*/ 721,
+ /*0x015d*/ 100,
+ /*0xa669*/ 1021,
+ /*0x2cdd*/ 954,
+ -1,
+ /*0xa76b*/ 1073,
+ -1,
+ /*0x10e7*/ 503,
+ /*0x24dd*/ 839,
+ /*0x03e3*/ 283,
+ -1,
+ /*0x01e7*/ 155,
+ -1,
+ /*0xa65b*/ 1014,
+ /*0x00e7*/ 32,
+ -1,
+ /*0xa75f*/ 1067,
+ /*0x13b0*/ 542,
+ /*0x0430*/ 294,
+ -1,
+ /*0x03e5*/ 284,
+ /*0x10430*/ 1151,
+ -1,
+ /*0x028c*/ 234,
+ /*0xa659*/ 1013,
+ /*0x0282*/ 227,
+ /*0x13d5*/ 579,
+ /*0x0455*/ 331,
+ /*0x04d5*/ 396,
+ /*0x0292*/ 235,
+ -1,
+ /*0x03e9*/ 286,
+ /*0x1e55*/ 658,
+ /*0x1ed5*/ 717,
+ /*0x0155*/ 96,
+ /*0xa651*/ 1009,
+ /*0x2cd5*/ 950,
+ -1, -1, -1,
+ /*0xa75d*/ 1066,
+ /*0x24d5*/ 831,
+ /*0x03db*/ 279,
+ /*0xa7cf*/ 1108,
+ -1,
+ /*0x10ccf*/ 1269,
+ /*0xa657*/ 1012,
+ -1, -1,
+ /*0x13ef*/ 605,
+ /*0x046f*/ 349,
+ /*0x04ef*/ 409,
+ /*0x006f*/ 13,
+ /*0x03d9*/ 278,
+ /*0x104ef*/ 1206,
+ /*0x1e6f*/ 671,
+ /*0x1eef*/ 730,
+ /*0x016f*/ 109,
+ /*0x026f*/ 221,
+ /*0xa794*/ 1086,
+ -1, -1, -1,
+ /*0x10ceb*/ 1297,
+ /*0x13ed*/ 603,
+ /*0x046d*/ 348,
+ /*0x04ed*/ 408,
+ /*0x006d*/ 11,
+ /*0xa653*/ 1010,
+ /*0x104ed*/ 1204,
+ /*0x1e6d*/ 670,
+ /*0x1eed*/ 729,
+ /*0x016d*/ 108,
+ /*0xa755*/ 1062,
+ /*0x10cdf*/ 1285,
+ /*0x03d7*/ 277,
+ /*0x13a8*/ 534,
+ /*0x13a2*/ 528,
+ /*0x1f61*/ 780,
+ -1,
+ /*0x10428*/ 1143,
+ /*0x2c61*/ 900,
+ -1, -1,
+ /*0x10eb*/ 507,
+ -1,
+ /*0x049f*/ 369,
+ -1,
+ /*0x01eb*/ 157,
+ -1,
+ /*0x1e1f*/ 631,
+ /*0x00eb*/ 36,
+ /*0x011f*/ 71,
+ /*0x021f*/ 181,
+ /*0x2c9f*/ 923,
+ /*0x10df*/ 495,
+ /*0xa76f*/ 1075,
+ /*0xa667*/ 1020,
+ /*0x10cdd*/ 1283,
+ /*0x01df*/ 151,
+ /*0x13f3*/ 609,
+ /*0x0473*/ 351,
+ /*0x04f3*/ 411,
+ /*0x0073*/ 17,
+ /*0x1f63*/ 782,
+ /*0x104f3*/ 1210,
+ /*0x1e73*/ 673,
+ /*0x1ef3*/ 732,
+ /*0x0173*/ 111,
+ /*0x1059b*/ 1223,
+ /*0x2cf3*/ 960,
+ /*0xa76d*/ 1074,
+ /*0x1f06*/ 745,
+ /*0x13ac*/ 538,
+ -1,
+ /*0x1f65*/ 784,
+ -1,
+ /*0x1042c*/ 1147,
+ /*0x2c65*/ 901,
+ /*0x10dd*/ 493,
+ /*0x03ae*/ 246,
+ -1, -1,
+ /*0x01dd*/ 150,
+ /*0x1f10*/ 747,
+ -1,
+ /*0x03e7*/ 285,
+ -1, -1,
+ /*0xa7d5*/ 1111,
+ /*0x0586*/ 479,
+ /*0x10cd5*/ 1275,
+ -1, -1, -1,
+ /*0x13aa*/ 536,
+ -1,
+ /*0x1f02*/ 741,
+ /*0x118db*/ 1354,
+ /*0x1042a*/ 1145,
+ /*0x2c5b*/ 895,
+ /*0x1f12*/ 749,
+ -1, -1, -1, -1, -1,
+ /*0x01b0*/ 133,
+ -1,
+ /*0x118d9*/ 1352,
+ /*0x10598*/ 1220,
+ /*0x2c59*/ 893,
+ /*0x10d5*/ 485,
+ -1,
+ /*0x10cef*/ 1301,
+ /*0x0582*/ 475,
+ /*0xa64f*/ 1008,
+ /*0x13cd*/ 571,
+ /*0x044d*/ 323,
+ /*0x1f51*/ 775,
+ /*0x118d1*/ 1344,
+ /*0x1044d*/ 1180,
+ /*0x2c51*/ 885,
+ /*0x1e4d*/ 654,
+ /*0x1ecd*/ 713,
+ /*0x014d*/ 92,
+ /*0x024d*/ 198,
+ /*0x2ccd*/ 946,
+ -1,
+ /*0x10ced*/ 1299,
+ /*0x1f57*/ 778,
+ /*0x118d7*/ 1350,
+ -1,
+ /*0x2c57*/ 891,
+ /*0xa66b*/ 1022,
+ /*0x10ef*/ 511,
+ -1, -1,
+ /*0x1f04*/ 743,
+ /*0x01ef*/ 159,
+ /*0x1f11*/ 748,
+ /*0x1f24*/ 757,
+ /*0x00ef*/ 40,
+ -1, -1,
+ /*0xa65f*/ 1016,
+ -1,
+ /*0xa79f*/ 1091,
+ -1,
+ /*0x1e924*/ 1418,
+ /*0x10ed*/ 509,
+ /*0x10d80*/ 1321,
+ /*0x1f53*/ 776,
+ /*0x118d3*/ 1346,
+ /*0x01ed*/ 158,
+ /*0x2c53*/ 887,
+ /*0x0584*/ 477,
+ /*0x00ed*/ 38,
+ -1, -1,
+ /*0x2173*/ 812,
+ -1,
+ /*0x105a4*/ 1231,
+ /*0x03eb*/ 287,
+ /*0xa74d*/ 1058,
+ -1,
+ /*0x01a8*/ 131,
+ -1,
+ /*0x0180*/ 117,
+ /*0xa65d*/ 1015,
+ /*0x1f20*/ 753,
+ /*0x019a*/ 125,
+ /*0x13c3*/ 561,
+ /*0x0443*/ 313,
+ /*0x03df*/ 281,
+ -1,
+ /*0x10443*/ 1170,
+ -1,
+ /*0x1e43*/ 649,
+ /*0x1ec3*/ 708,
+ /*0x0373*/ 239,
+ /*0x1f67*/ 786,
+ /*0x2cc3*/ 941,
+ /*0x1e92e*/ 1428,
+ -1, -1,
+ /*0x10f3*/ 515,
+ -1, -1, -1,
+ /*0x01f3*/ 160,
+ /*0x105a0*/ 1228,
+ -1,
+ /*0x00f3*/ 44,
+ -1, -1,
+ /*0x105ae*/ 1241,
+ -1,
+ /*0x03dd*/ 280,
+ /*0x13c1*/ 559,
+ /*0x0441*/ 311,
+ /*0x2d16*/ 983,
+ /*0xa655*/ 1011,
+ /*0x10441*/ 1168,
+ /*0x2d08*/ 969,
+ /*0x1e41*/ 648,
+ /*0x1ec1*/ 707,
+ /*0x1f26*/ 759,
+ /*0x2d1b*/ 988,
+ /*0x2cc1*/ 940,
+ -1, -1, -1,
+ /*0x2d0b*/ 972,
+ /*0x2d0a*/ 971,
+ /*0x1e926*/ 1420,
+ -1,
+ /*0x13cb*/ 569,
+ /*0x044b*/ 321,
+ /*0xa743*/ 1053,
+ /*0xa7cd*/ 1107,
+ /*0x1044b*/ 1178,
+ /*0x10ccd*/ 1267,
+ /*0x1e4b*/ 653,
+ /*0x1ecb*/ 712,
+ /*0x014b*/ 91,
+ /*0x024b*/ 197,
+ /*0x2ccb*/ 945,
+ /*0x105a6*/ 1233,
+ /*0x13c9*/ 567,
+ /*0x0449*/ 319,
+ -1,
+ /*0x2d06*/ 967,
+ /*0x10449*/ 1176,
+ -1,
+ /*0x1e49*/ 652,
+ /*0x1ec9*/ 711,
+ /*0x0561*/ 442,
+ /*0x0249*/ 196,
+ /*0x2cc9*/ 944,
+ /*0xa66d*/ 1023,
+ /*0x118cf*/ 1342,
+ -1,
+ /*0x2c4f*/ 883,
+ /*0x2d10*/ 977,
+ -1,
+ /*0xa741*/ 1052,
+ /*0x051b*/ 431,
+ -1,
+ /*0x2d18*/ 985,
+ -1, -1,
+ /*0x050b*/ 423,
+ -1,
+ /*0x03ef*/ 289,
+ /*0x2d0c*/ 973,
+ /*0x1f14*/ 751,
+ /*0x2d02*/ 963,
+ /*0x16ed1*/ 1413,
+ -1, -1,
+ /*0x2d12*/ 979,
+ -1,
+ /*0x0563*/ 444,
+ /*0xa74b*/ 1057,
+ -1,
+ /*0x0280*/ 226,
+ -1, -1,
+ /*0x03ed*/ 288,
+ /*0x118df*/ 1358,
+ -1,
+ /*0x2c5f*/ 899,
+ -1,
+ /*0x0565*/ 446,
+ /*0xa7c3*/ 1104,
+ /*0xa749*/ 1056,
+ /*0x10cc3*/ 1257,
+ -1, -1, -1,
+ /*0x13f1*/ 607,
+ /*0x0471*/ 350,
+ /*0x04f1*/ 410,
+ /*0x0071*/ 15,
+ /*0x0569*/ 450,
+ /*0x104f1*/ 1208,
+ /*0x1e71*/ 672,
+ /*0x1ef1*/ 731,
+ /*0x0171*/ 110,
+ /*0x0271*/ 222,
+ /*0x16ed3*/ 1415,
+ -1, -1,
+ /*0x118dd*/ 1356,
+ -1,
+ /*0x2c5d*/ 897,
+ -1,
+ /*0x2d04*/ 965,
+ -1,
+ /*0x2d11*/ 978,
+ /*0x2d24*/ 997,
+ /*0xa7c1*/ 1103,
+ -1,
+ /*0x10cc1*/ 1255,
+ /*0x03f3*/ 291,
+ /*0x13f5*/ 611,
+ /*0x0475*/ 352,
+ /*0x04f5*/ 412,
+ /*0x0075*/ 19,
+ -1,
+ /*0x104f5*/ 1212,
+ /*0x1e75*/ 674,
+ /*0x1ef5*/ 733,
+ /*0x0175*/ 112,
+ /*0x0275*/ 224,
+ -1,
+ /*0x1f30*/ 761,
+ /*0x03ac*/ 244,
+ -1,
+ /*0x2c30*/ 852,
+ -1,
+ /*0x10ccb*/ 1265,
+ -1, -1,
+ /*0x1e930*/ 1430,
+ /*0x1f55*/ 777,
+ /*0x118d5*/ 1348,
+ -1,
+ /*0x2c55*/ 889,
+ /*0x2d20*/ 993,
+ -1, -1,
+ /*0xa64d*/ 1007,
+ /*0x10cc9*/ 1263,
+ -1,
+ /*0x13c7*/ 565,
+ /*0x0447*/ 317,
+ /*0x105b0*/ 1243,
+ /*0x0511*/ 426,
+ /*0x10447*/ 1174,
+ -1,
+ /*0x1e47*/ 651,
+ /*0x1ec7*/ 710,
+ -1,
+ /*0x0247*/ 195,
+ /*0x2cc7*/ 943,
+ -1,
+ /*0x13c5*/ 563,
+ /*0x0445*/ 315,
+ -1, -1,
+ /*0x10445*/ 1172,
+ /*0x019e*/ 127,
+ /*0x1e45*/ 650,
+ /*0x1ec5*/ 709,
+ /*0x16e61*/ 1360,
+ -1,
+ /*0x2cc5*/ 942,
+ /*0x01c9*/ 140,
+ -1, -1,
+ /*0x03cd*/ 275,
+ /*0x13bf*/ 557,
+ /*0x043f*/ 309,
+ /*0x04bf*/ 385,
+ -1,
+ /*0x1043f*/ 1166,
+ -1,
+ /*0x1e3f*/ 647,
+ /*0x1ebf*/ 706,
+ -1,
+ /*0x023f*/ 192,
+ /*0x2cbf*/ 939,
+ -1, -1, -1,
+ /*0x1f22*/ 755,
+ /*0x1f00*/ 739,
+ /*0x16ecf*/ 1411,
+ /*0x0567*/ 448,
+ /*0x2171*/ 810,
+ /*0x16e63*/ 1362,
+ /*0xa747*/ 1055,
+ /*0x1e928*/ 1422,
+ /*0x1e922*/ 1416,
+ /*0x10cf1*/ 1303,
+ -1,
+ /*0xa643*/ 1002,
+ -1,
+ /*0x13c2*/ 560,
+ /*0x0442*/ 312,
+ /*0x04c2*/ 386,
+ /*0x16e65*/ 1364,
+ /*0x10442*/ 1169,
+ /*0xa745*/ 1054,
+ /*0x0580*/ 473,
+ /*0x105a8*/ 1235,
+ /*0x0142*/ 87,
+ /*0x0242*/ 194,
+ /*0x1f73*/ 790,
+ /*0x0371*/ 238,
+ /*0x1059a*/ 1222,
+ /*0x2c73*/ 906,
+ /*0x16e69*/ 1368,
+ /*0x1059f*/ 1227,
+ /*0x2175*/ 814,
+ /*0x10f1*/ 513,
+ -1, -1,
+ /*0xa73f*/ 1051,
+ -1, -1,
+ /*0x2d0e*/ 975,
+ /*0x00f1*/ 42,
+ /*0xa641*/ 1001,
+ /*0x2d14*/ 981,
+ /*0x03c3*/ 265,
+ /*0x13b7*/ 549,
+ /*0x0437*/ 301,
+ /*0x04b7*/ 381,
+ /*0x1e92c*/ 1426,
+ /*0x10437*/ 1158,
+ -1,
+ /*0x1e37*/ 643,
+ /*0x1eb7*/ 702,
+ /*0x0137*/ 82,
+ -1,
+ /*0x2cb7*/ 935,
+ -1, -1,
+ /*0x017e*/ 116,
+ /*0x10f5*/ 517,
+ /*0xa64b*/ 1006,
+ /*0x105ac*/ 1239,
+ -1,
+ /*0x01f5*/ 161,
+ -1, -1,
+ /*0x00f5*/ 46,
+ /*0x13a7*/ 533,
+ /*0x10cc7*/ 1261,
+ /*0x04a7*/ 373,
+ /*0x1e92a*/ 1424,
+ /*0x03c1*/ 264,
+ /*0xa649*/ 1005,
+ /*0x1e27*/ 635,
+ /*0x1ea7*/ 694,
+ /*0x0127*/ 75,
+ /*0x0227*/ 184,
+ /*0x2ca7*/ 927,
+ /*0x029e*/ 237,
+ -1,
+ /*0x10cc5*/ 1259,
+ -1, -1,
+ /*0x105aa*/ 1237,
+ /*0x056b*/ 452,
+ /*0x118cd*/ 1340,
+ -1,
+ /*0x2c4d*/ 881,
+ -1,
+ /*0x03cb*/ 273,
+ /*0x10d73*/ 1308,
+ -1,
+ /*0xa737*/ 1047,
+ /*0xa7bf*/ 1102,
+ -1, -1, -1, -1,
+ /*0x13b5*/ 547,
+ /*0x0435*/ 299,
+ /*0x04b5*/ 380,
+ /*0x03c9*/ 271,
+ /*0x10435*/ 1156,
+ -1,
+ /*0x1e35*/ 642,
+ /*0x1eb5*/ 701,
+ /*0x0135*/ 81,
+ -1,
+ /*0x2cb5*/ 934,
+ /*0x13b3*/ 545,
+ /*0x0433*/ 297,
+ /*0x04b3*/ 379,
+ -1,
+ /*0x10433*/ 1154,
+ /*0xa727*/ 1040,
+ /*0x1e33*/ 641,
+ /*0x1eb3*/ 700,
+ /*0x0133*/ 80,
+ /*0x0233*/ 190,
+ /*0x2cb3*/ 933,
+ /*0x01bf*/ 138,
+ /*0x1fe1*/ 806,
+ /*0x10cc2*/ 1256,
+ /*0x0481*/ 358,
+ -1, -1,
+ /*0x16e67*/ 1366,
+ /*0x1e01*/ 616,
+ /*0x1e81*/ 680,
+ /*0x0101*/ 56,
+ /*0x0201*/ 166,
+ /*0x2c81*/ 908,
+ -1, -1,
+ /*0x1e05*/ 618,
+ /*0x1e85*/ 682,
+ /*0x0105*/ 58,
+ /*0x0205*/ 168,
+ /*0x2c85*/ 910,
+ /*0x1f43*/ 772,
+ /*0x118c3*/ 1330,
+ -1,
+ /*0x2c43*/ 871,
+ -1, -1,
+ /*0xa735*/ 1046,
+ -1,
+ /*0x1e943*/ 1449,
+ /*0xa7b7*/ 1098,
+ -1,
+ /*0x217e*/ 823,
+ -1, -1,
+ /*0x13ad*/ 539,
+ -1,
+ /*0x04ad*/ 376,
+ /*0xa733*/ 1045,
+ /*0x1042d*/ 1148,
+ /*0x1fe5*/ 807,
+ /*0x1e2d*/ 638,
+ /*0x1ead*/ 697,
+ /*0x012d*/ 78,
+ /*0x022d*/ 187,
+ /*0x2cad*/ 930,
+ /*0x2d22*/ 995,
+ /*0x2d00*/ 961,
+ /*0x1f41*/ 770,
+ /*0x118c1*/ 1328,
+ /*0x2d1a*/ 987,
+ /*0x2c41*/ 869,
+ /*0xa7a7*/ 1095,
+ /*0x2d1f*/ 992,
+ -1, -1,
+ /*0x1e941*/ 1447,
+ /*0x056f*/ 456,
+ /*0x10fe*/ 524,
+ -1, -1,
+ /*0xa647*/ 1004,
+ -1, -1, -1,
+ /*0x00fe*/ 54,
+ -1,
+ /*0x118cb*/ 1338,
+ /*0x1059c*/ 1224,
+ /*0x2c4b*/ 879,
+ /*0x047d*/ 356,
+ /*0x04fd*/ 416,
+ /*0x056d*/ 454,
+ /*0xa645*/ 1003,
+ -1,
+ /*0x1e7d*/ 678,
+ /*0x1efd*/ 737,
+ /*0x1d7d*/ 614,
+ /*0x027d*/ 225,
+ /*0x118c9*/ 1336,
+ -1,
+ /*0x2c49*/ 877,
+ /*0xa72d*/ 1043,
+ /*0xa7b5*/ 1097,
+ /*0x1fd1*/ 804,
+ /*0x16e6b*/ 1370,
+ -1, -1, -1,
+ /*0x13a5*/ 531,
+ /*0x03c7*/ 269,
+ /*0x04a5*/ 372,
+ /*0x051f*/ 433,
+ /*0x1059e*/ 1226,
+ -1,
+ /*0x1e25*/ 634,
+ /*0x1ea5*/ 693,
+ /*0x0125*/ 74,
+ /*0x0225*/ 183,
+ /*0x2ca5*/ 926,
+ -1, -1,
+ /*0x03c5*/ 267,
+ /*0x13c0*/ 558,
+ /*0x0440*/ 310,
+ /*0x16ecd*/ 1409,
+ /*0xa781*/ 1079,
+ /*0x10440*/ 1167,
+ /*0x0573*/ 460,
+ -1,
+ /*0x2184*/ 825,
+ /*0x0140*/ 86,
+ /*0x0240*/ 193,
+ /*0xa785*/ 1081,
+ -1, -1,
+ /*0x10d81*/ 1322,
+ /*0x03bf*/ 262,
+ -1,
+ /*0x13a3*/ 529,
+ -1,
+ /*0x04a3*/ 371,
+ -1,
+ /*0x10d85*/ 1326,
+ -1,
+ /*0x1e23*/ 633,
+ /*0x1ea3*/ 692,
+ /*0x0123*/ 73,
+ /*0x0223*/ 182,
+ /*0x2ca3*/ 925,
+ /*0x1f71*/ 788,
+ /*0x13bd*/ 555,
+ /*0x043d*/ 307,
+ /*0x04bd*/ 384,
+ -1,
+ /*0x1043d*/ 1164,
+ /*0xa725*/ 1039,
+ /*0x1e3d*/ 646,
+ /*0x1ebd*/ 705,
+ -1,
+ /*0x0185*/ 119,
+ /*0x2cbd*/ 938,
+ -1,
+ /*0x13bb*/ 553,
+ /*0x043b*/ 305,
+ /*0x04bb*/ 383,
+ -1,
+ /*0x1043b*/ 1162,
+ -1,
+ /*0x1e3b*/ 645,
+ /*0x1ebb*/ 704,
+ -1, -1,
+ /*0x2cbb*/ 937,
+ -1,
+ /*0x1f75*/ 792,
+ -1,
+ /*0x13b9*/ 551,
+ /*0x0439*/ 303,
+ /*0x04b9*/ 382,
+ /*0x16ec3*/ 1399,
+ /*0x10439*/ 1160,
+ -1,
+ /*0x1e39*/ 644,
+ /*0x1eb9*/ 703,
+ /*0x01ad*/ 132,
+ /*0xa723*/ 1038,
+ /*0x2cb9*/ 936,
+ -1,
+ /*0x217d*/ 822,
+ -1, -1,
+ /*0x03b7*/ 254,
+ /*0x13b1*/ 543,
+ /*0x0431*/ 295,
+ /*0x04b1*/ 378,
+ /*0x16e6f*/ 1374,
+ /*0x10431*/ 1152,
+ /*0xa73d*/ 1050,
+ /*0x1e31*/ 640,
+ /*0x1eb1*/ 699,
+ -1,
+ /*0x0231*/ 189,
+ /*0x2cb1*/ 932,
+ -1, -1,
+ /*0x118c7*/ 1334,
+ /*0x16ec1*/ 1397,
+ /*0x2c47*/ 875,
+ /*0x037d*/ 243,
+ /*0xa73b*/ 1049,
+ /*0x16e6d*/ 1372,
+ /*0xa7a5*/ 1094,
+ /*0x10d71*/ 1306,
+ -1,
+ /*0x10fd*/ 523,
+ -1,
+ /*0x1f45*/ 774,
+ /*0x118c5*/ 1332,
+ /*0x01fd*/ 164,
+ /*0x2c45*/ 873,
+ /*0xff59*/ 1141,
+ /*0x00fd*/ 53,
+ -1,
+ /*0xa739*/ 1048,
+ /*0x16ecb*/ 1407,
+ -1,
+ /*0x2d1c*/ 989,
+ /*0x10cc0*/ 1254,
+ -1, -1, -1,
+ /*0xff51*/ 1133,
+ -1, -1,
+ /*0x2c3f*/ 867,
+ -1,
+ /*0x16ec9*/ 1405,
+ /*0x10d75*/ 1310,
+ /*0x01a5*/ 130,
+ /*0x1e93f*/ 1445,
+ -1,
+ /*0xa7a3*/ 1093,
+ /*0xff57*/ 1139,
+ -1,
+ /*0x03b5*/ 252,
+ -1,
+ /*0x16e73*/ 1378,
+ -1, -1, -1, -1,
+ /*0x2d1e*/ 991,
+ -1,
+ /*0xa7bd*/ 1101,
+ -1,
+ /*0x03b3*/ 250,
+ -1, -1,
+ /*0x1f42*/ 771,
+ /*0x118c2*/ 1329,
+ -1,
+ /*0x2c42*/ 870,
+ -1, -1,
+ /*0xff53*/ 1135,
+ /*0xa7bb*/ 1100,
+ /*0x1e942*/ 1448,
+ /*0x048f*/ 361,
+ /*0x01a3*/ 129,
+ -1, -1,
+ /*0x1e0f*/ 623,
+ /*0x1e8f*/ 687,
+ /*0x010f*/ 63,
+ /*0x020f*/ 173,
+ /*0x2c8f*/ 915,
+ /*0xa69b*/ 1037,
+ -1, -1,
+ /*0xa7b9*/ 1099,
+ /*0x01bd*/ 137,
+ /*0xa68b*/ 1029,
+ -1, -1, -1, -1,
+ /*0x1f37*/ 768,
+ -1, -1,
+ /*0x2c37*/ 859,
+ -1,
+ /*0x0479*/ 354,
+ /*0x04f9*/ 414,
+ /*0x0079*/ 23,
+ /*0x1e937*/ 1437,
+ /*0x104f9*/ 1216,
+ /*0x1e79*/ 676,
+ /*0x1ef9*/ 735,
+ /*0x1d79*/ 613,
+ /*0x03ad*/ 245,
+ /*0x13f2*/ 608,
+ /*0x1fb0*/ 801,
+ /*0x0078*/ 22,
+ /*0x0072*/ 16,
+ /*0x104f8*/ 1215,
+ /*0x104f2*/ 1209,
+ /*0x01b9*/ 136,
+ /*0x105b7*/ 1249,
+ /*0x1f27*/ 760,
+ /*0x0272*/ 223,
+ -1,
+ /*0x1e03*/ 617,
+ /*0x1e83*/ 681,
+ /*0x0103*/ 57,
+ /*0x0203*/ 167,
+ /*0x2c83*/ 909,
+ /*0x1e927*/ 1421,
+ /*0x13af*/ 541,
+ -1,
+ /*0x04af*/ 377,
+ -1,
+ /*0x1042f*/ 1150,
+ -1,
+ /*0x1e2f*/ 639,
+ /*0x1eaf*/ 698,
+ /*0x012f*/ 79,
+ /*0x022f*/ 188,
+ /*0x2caf*/ 931,
+ /*0x13a9*/ 535,
+ /*0x105a7*/ 1234,
+ /*0x04a9*/ 374,
+ -1,
+ /*0x10429*/ 1144,
+ -1,
+ /*0x1e29*/ 636,
+ /*0x1ea9*/ 695,
+ /*0x0129*/ 76,
+ /*0x0229*/ 185,
+ /*0x2ca9*/ 928,
+ /*0x1f35*/ 766,
+ -1, -1,
+ /*0x2c35*/ 857,
+ /*0x16ec7*/ 1403,
+ -1, -1, -1,
+ /*0x1e935*/ 1435,
+ /*0x0571*/ 458,
+ -1,
+ /*0x1f33*/ 764,
+ -1,
+ /*0xff4f*/ 1131,
+ /*0x2c33*/ 855,
+ /*0x10d7e*/ 1319,
+ /*0x16ec5*/ 1401,
+ -1, -1,
+ /*0x1e933*/ 1433,
+ -1,
+ /*0x105b5*/ 1247,
+ -1,
+ /*0x1f01*/ 740,
+ -1,
+ /*0xa72f*/ 1044,
+ -1, -1,
+ /*0x03c0*/ 263,
+ /*0xa691*/ 1032,
+ /*0x1f05*/ 744,
+ /*0x16ebf*/ 1395,
+ /*0x105b3*/ 1245,
+ -1,
+ /*0x0575*/ 462,
+ -1,
+ /*0xa729*/ 1041,
+ -1,
+ /*0x047b*/ 355,
+ /*0x04fb*/ 415,
+ -1,
+ /*0x0581*/ 474,
+ /*0x104fb*/ 1218,
+ /*0x1e7b*/ 677,
+ /*0x1efb*/ 736,
+ -1, -1,
+ /*0x13a1*/ 527,
+ /*0x0585*/ 478,
+ /*0x04a1*/ 370,
+ -1,
+ /*0x2179*/ 818,
+ -1,
+ /*0x1e21*/ 632,
+ /*0x1ea1*/ 691,
+ /*0x0121*/ 72,
+ /*0x03bd*/ 260,
+ /*0x2ca1*/ 924,
+ /*0x16ec2*/ 1398,
+ -1,
+ /*0x2178*/ 817,
+ /*0x2172*/ 811,
+ -1,
+ /*0x1e92d*/ 1427,
+ -1, -1,
+ /*0x10cf2*/ 1304,
+ -1,
+ /*0x03bb*/ 258,
+ /*0xa783*/ 1080,
+ /*0x13c8*/ 566,
+ /*0x0448*/ 318,
+ /*0x04c8*/ 389,
+ -1,
+ /*0x10448*/ 1175,
+ -1,
+ /*0x105ad*/ 1240,
+ /*0x10f9*/ 521,
+ /*0x0148*/ 90,
+ /*0x10d83*/ 1324,
+ -1,
+ /*0x01f9*/ 162,
+ /*0x03b9*/ 256,
+ -1,
+ /*0x00f9*/ 49,
+ -1,
+ /*0x10f8*/ 520,
+ /*0x10f2*/ 514,
+ -1,
+ /*0x1f7d*/ 800,
+ -1, -1,
+ /*0xa7a9*/ 1096,
+ /*0x00f8*/ 48,
+ /*0x00f2*/ 43,
+ -1,
+ /*0x0183*/ 118,
+ -1,
+ /*0x03b1*/ 248,
+ /*0xff55*/ 1137,
+ /*0x0477*/ 353,
+ /*0x04f7*/ 413,
+ /*0x0077*/ 21,
+ -1,
+ /*0x104f7*/ 1214,
+ /*0x1e77*/ 675,
+ /*0x1ef7*/ 734,
+ /*0x0177*/ 113,
+ -1,
+ /*0x1f25*/ 758,
+ -1,
+ /*0x13ce*/ 572,
+ /*0x044e*/ 324,
+ /*0x04ce*/ 392,
+ -1,
+ /*0x1044e*/ 1181,
+ -1,
+ /*0x1e925*/ 1419,
+ -1, -1, -1, -1, -1,
+ /*0x1f40*/ 769,
+ /*0x118c0*/ 1327,
+ -1,
+ /*0x2c40*/ 868,
+ -1,
+ /*0x16e71*/ 1376,
+ /*0x2d27*/ 999,
+ /*0x105a5*/ 1232,
+ /*0x1e940*/ 1446,
+ -1,
+ /*0x13e6*/ 596,
+ /*0x13d0*/ 574,
+ /*0x0450*/ 326,
+ /*0x0066*/ 5,
+ /*0x217b*/ 820,
+ /*0x104e6*/ 1197,
+ /*0x1f23*/ 756,
+ -1, -1,
+ /*0x0266*/ 215,
+ /*0x0250*/ 200,
+ -1, -1, -1,
+ /*0x1e923*/ 1417,
+ /*0x24e6*/ 848,
+ /*0x24d0*/ 826,
+ /*0xa7a1*/ 1092,
+ /*0x057e*/ 471,
+ /*0x10d7d*/ 1318,
+ /*0x16e75*/ 1380,
+ /*0x2c3d*/ 865,
+ -1, -1,
+ /*0x037b*/ 241,
+ -1,
+ /*0x1e93d*/ 1443,
+ /*0x105a3*/ 1230,
+ -1, -1,
+ /*0x13d2*/ 576,
+ /*0x0452*/ 328,
+ -1,
+ /*0x2c3b*/ 863,
+ /*0x01fb*/ 163,
+ /*0x0527*/ 437,
+ -1,
+ /*0x00fb*/ 51,
+ /*0x1e93b*/ 1441,
+ /*0x0252*/ 202,
+ /*0xa7c8*/ 1105,
+ -1,
+ /*0x10cc8*/ 1262,
+ -1,
+ /*0x01a1*/ 128,
+ /*0x24d2*/ 828,
+ -1,
+ /*0x2c39*/ 861,
+ -1, -1,
+ /*0x2d01*/ 962,
+ /*0x105bb*/ 1252,
+ /*0x1e939*/ 1439,
+ -1, -1, -1, -1,
+ /*0x2d05*/ 966,
+ -1,
+ /*0x13f0*/ 606,
+ /*0x1f31*/ 762,
+ /*0x0283*/ 228,
+ /*0x0070*/ 14,
+ /*0x2c31*/ 853,
+ /*0x104f0*/ 1207,
+ /*0x105b9*/ 1251,
+ /*0x2177*/ 816,
+ -1,
+ /*0x1e931*/ 1431,
+ -1, -1, -1,
+ /*0x03f8*/ 292,
+ /*0x03f2*/ 290,
+ -1, -1, -1, -1,
+ /*0x214e*/ 808,
+ -1, -1,
+ /*0x105b1*/ 1244,
+ /*0x2d2d*/ 1000,
+ /*0x10cce*/ 1268,
+ -1, -1,
+ /*0x0377*/ 240,
+ -1, -1,
+ /*0x0501*/ 418,
+ /*0x03af*/ 247,
+ -1,
+ /*0x10f7*/ 519,
+ -1,
+ /*0x0493*/ 363,
+ -1,
+ /*0x0505*/ 420,
+ /*0xff4d*/ 1129,
+ /*0x1e13*/ 625,
+ /*0x1e93*/ 689,
+ /*0x0113*/ 65,
+ /*0x0213*/ 175,
+ /*0x2c93*/ 917,
+ -1, -1,
+ /*0x10ce6*/ 1292,
+ /*0x10cd0*/ 1270,
+ -1,
+ /*0x01ce*/ 142,
+ /*0x13c6*/ 564,
+ /*0x0446*/ 316,
+ /*0x04c6*/ 388,
+ -1,
+ /*0x10446*/ 1173,
+ -1, -1, -1,
+ /*0x0146*/ 89,
+ /*0x007a*/ 24,
+ -1,
+ /*0x104fa*/ 1217,
+ /*0x052d*/ 440,
+ -1,
+ /*0x017a*/ 114,
+ -1, -1,
+ /*0x10e6*/ 502,
+ /*0x10d0*/ 480,
+ -1,
+ /*0x16ec0*/ 1396,
+ -1,
+ /*0x01d0*/ 143,
+ -1,
+ /*0x00e6*/ 31,
+ -1,
+ /*0x10cd2*/ 1272,
+ /*0x2d25*/ 998,
+ /*0x16e7e*/ 1389,
+ /*0x13c4*/ 562,
+ /*0x0444*/ 314,
+ /*0x04c4*/ 387,
+ -1,
+ /*0x10444*/ 1171,
+ -1, -1, -1,
+ /*0x0144*/ 88,
+ -1, -1,
+ /*0x03fb*/ 293,
+ -1, -1,
+ /*0xff43*/ 1119,
+ -1, -1,
+ /*0x057d*/ 470,
+ /*0x10d2*/ 482,
+ /*0x16ebd*/ 1393,
+ /*0x1f79*/ 796,
+ /*0x2170*/ 809,
+ /*0x01d2*/ 144,
+ /*0x0076*/ 20,
+ /*0xa77a*/ 1076,
+ /*0x104f6*/ 1213,
+ /*0x10cf0*/ 1302,
+ -1,
+ /*0x2d23*/ 996,
+ /*0x1f78*/ 795,
+ /*0x1f72*/ 789,
+ /*0x16ebb*/ 1391,
+ -1,
+ /*0x13ec*/ 602,
+ -1,
+ /*0x1f03*/ 742,
+ /*0x006c*/ 10,
+ /*0x0525*/ 436,
+ /*0x104ec*/ 1203,
+ -1, -1,
+ /*0xff41*/ 1117,
+ /*0x026c*/ 220,
+ /*0x2cec*/ 958,
+ /*0x03c8*/ 270,
+ /*0x047f*/ 357,
+ /*0x04ff*/ 417,
+ /*0x10f0*/ 512,
+ -1, -1,
+ /*0x1e7f*/ 679,
+ /*0x1eff*/ 738,
+ -1,
+ /*0x0583*/ 476,
+ /*0x00f0*/ 41,
+ /*0x1e92f*/ 1429,
+ -1,
+ /*0xa793*/ 1085,
+ -1,
+ /*0xff4b*/ 1127,
+ /*0x13e8*/ 598,
+ -1, -1,
+ /*0x0068*/ 7,
+ -1,
+ /*0x104e8*/ 1199,
+ /*0x1e929*/ 1423,
+ /*0x0523*/ 435,
+ /*0x105af*/ 1242,
+ /*0x0268*/ 216,
+ -1,
+ /*0xff49*/ 1125,
+ -1, -1, -1,
+ /*0x24e8*/ 850,
+ /*0x10cc6*/ 1260,
+ /*0x217a*/ 819,
+ -1,
+ /*0x105a9*/ 1236,
+ /*0x13ab*/ 537,
+ -1,
+ /*0x04ab*/ 375,
+ /*0x10d79*/ 1314,
+ /*0x1042b*/ 1146,
+ /*0x03ce*/ 276,
+ /*0x1e2b*/ 637,
+ /*0x1eab*/ 696,
+ /*0x012b*/ 77,
+ /*0x022b*/ 186,
+ /*0x2cab*/ 929,
+ /*0xa77f*/ 1078,
+ /*0x10d78*/ 1313,
+ /*0x10d72*/ 1307,
+ /*0x13cc*/ 570,
+ /*0x044c*/ 322,
+ /*0x04cc*/ 391,
+ -1,
+ /*0x1044c*/ 1179,
+ -1, -1,
+ /*0x01c6*/ 139,
+ -1,
+ /*0x10fa*/ 522,
+ /*0x13e4*/ 594,
+ /*0x10cc4*/ 1258,
+ /*0x1f7b*/ 798,
+ /*0x0064*/ 3,
+ -1,
+ /*0x104e4*/ 1195,
+ /*0x00fa*/ 50,
+ -1, -1,
+ /*0x0264*/ 213,
+ -1, -1,
+ /*0x1f21*/ 754,
+ -1, -1,
+ /*0x24e4*/ 846,
+ /*0x2176*/ 815,
+ /*0x13f4*/ 610,
+ -1,
+ /*0xa7f6*/ 1115,
+ /*0x0074*/ 18,
+ /*0x0499*/ 366,
+ /*0x104f4*/ 1211,
+ /*0xa72b*/ 1042,
+ -1,
+ /*0x1e19*/ 628,
+ -1,
+ /*0x0119*/ 68,
+ /*0x0219*/ 178,
+ /*0x2c99*/ 920,
+ -1, -1,
+ /*0x16e7d*/ 1388,
+ /*0x105a1*/ 1229,
+ /*0x10cec*/ 1298,
+ -1,
+ /*0x118c8*/ 1335,
+ -1,
+ /*0x2c48*/ 876,
+ -1,
+ /*0x217f*/ 824,
+ -1,
+ /*0x10f6*/ 518,
+ /*0x13ca*/ 568,
+ /*0x044a*/ 320,
+ /*0x04ca*/ 390,
+ -1,
+ /*0x1044a*/ 1177,
+ -1,
+ /*0x00f6*/ 47,
+ -1,
+ /*0x2d0f*/ 976,
+ /*0x0495*/ 364,
+ -1, -1,
+ /*0x10ec*/ 508,
+ /*0x1e15*/ 626,
+ /*0x1e95*/ 690,
+ /*0x0115*/ 66,
+ /*0x0215*/ 176,
+ /*0x2c95*/ 918,
+ /*0x10ce8*/ 1294,
+ /*0x00ec*/ 37,
+ /*0x13e0*/ 590,
+ /*0x1f77*/ 794,
+ /*0x10d7b*/ 1316,
+ /*0x10ff*/ 525,
+ -1,
+ /*0x104e0*/ 1191,
+ -1,
+ /*0x01ff*/ 165,
+ -1,
+ /*0x0260*/ 210,
+ /*0x00ff*/ 55,
+ /*0xff47*/ 1123,
+ /*0x017c*/ 115,
+ -1,
+ /*0x118ce*/ 1341,
+ /*0x24e0*/ 842,
+ /*0x2c4e*/ 882,
+ -1, -1,
+ /*0x10e8*/ 504,
+ -1,
+ /*0x13bc*/ 554,
+ /*0x043c*/ 306,
+ /*0xff45*/ 1121,
+ -1,
+ /*0x1043c*/ 1163,
+ /*0x00e8*/ 33,
+ /*0x050f*/ 425,
+ /*0x2d03*/ 964,
+ /*0x013c*/ 84,
+ /*0x023c*/ 191,
+ -1,
+ /*0x10ccc*/ 1266,
+ -1, -1,
+ /*0x1f66*/ 785,
+ -1,
+ /*0x118d0*/ 1343,
+ /*0x2c66*/ 902,
+ /*0x2c50*/ 884,
+ -1, -1,
+ /*0x10ce4*/ 1290,
+ /*0x1e07*/ 619,
+ /*0x1e87*/ 683,
+ /*0x0107*/ 59,
+ /*0x0207*/ 169,
+ /*0x2c87*/ 911,
+ -1,
+ /*0x03c6*/ 268,
+ -1,
+ /*0xa77c*/ 1077,
+ /*0x0579*/ 466,
+ -1,
+ /*0x2174*/ 813,
+ -1, -1,
+ /*0x01cc*/ 141,
+ -1,
+ /*0xa799*/ 1088,
+ -1,
+ /*0x0578*/ 465,
+ /*0x0572*/ 459,
+ /*0x10e4*/ 500,
+ /*0x10d77*/ 1312,
+ /*0xff42*/ 1118,
+ /*0x118d2*/ 1345,
+ /*0x0503*/ 419,
+ /*0x2c52*/ 886,
+ -1,
+ /*0x00e4*/ 29,
+ -1,
+ /*0x13ea*/ 600,
+ -1, -1,
+ /*0x006a*/ 8,
+ -1,
+ /*0x104ea*/ 1201,
+ /*0x03c4*/ 266,
+ /*0x052f*/ 441,
+ /*0x10f4*/ 516,
+ /*0x026a*/ 218,
+ -1,
+ /*0xa7ca*/ 1106,
+ -1,
+ /*0x10cca*/ 1264,
+ /*0x0199*/ 124,
+ /*0x00f4*/ 45,
+ /*0x13b6*/ 548,
+ /*0x0436*/ 300,
+ /*0x0529*/ 438,
+ -1,
+ /*0x10436*/ 1157,
+ -1,
+ /*0x1f70*/ 787,
+ -1, -1,
+ /*0x13e2*/ 592,
+ /*0x13dc*/ 586,
+ /*0x045c*/ 338,
+ /*0x0062*/ 1,
+ -1,
+ /*0x104e2*/ 1193,
+ /*0x104dc*/ 1187,
+ /*0x217c*/ 821,
+ /*0x10ce0*/ 1286,
+ -1,
+ /*0x025c*/ 209,
+ -1,
+ /*0x2d21*/ 994,
+ -1,
+ /*0x16ec8*/ 1404,
+ /*0x24e2*/ 844,
+ /*0x24dc*/ 838,
+ /*0x13da*/ 584,
+ /*0x045a*/ 336,
+ -1,
+ /*0x0195*/ 123,
+ -1,
+ /*0x104da*/ 1185,
+ -1,
+ /*0x13d6*/ 580,
+ /*0x0456*/ 332,
+ -1,
+ /*0x037c*/ 242,
+ -1,
+ /*0x10e0*/ 496,
+ /*0x1f13*/ 750,
+ -1,
+ /*0x24da*/ 836,
+ /*0x0256*/ 205,
+ -1, -1,
+ /*0x00e0*/ 25,
+ /*0x13d8*/ 582,
+ /*0x0458*/ 334,
+ /*0x24d6*/ 832,
+ /*0x00fc*/ 52,
+ /*0x057b*/ 468,
+ /*0x104d8*/ 1183,
+ /*0xa787*/ 1082,
+ -1,
+ /*0x13b4*/ 546,
+ /*0x0434*/ 298,
+ -1,
+ /*0x118c6*/ 1333,
+ /*0x10434*/ 1155,
+ /*0x2c46*/ 874,
+ /*0x0521*/ 434,
+ /*0x24d8*/ 834,
+ /*0x1f7a*/ 797,
+ -1,
+ /*0x16ece*/ 1410,
+ -1,
+ /*0x0497*/ 365,
+ -1, -1,
+ /*0x10d70*/ 1305,
+ /*0x1e17*/ 627,
+ /*0x048d*/ 360,
+ /*0x0117*/ 67,
+ /*0x0217*/ 177,
+ /*0x2c97*/ 919,
+ /*0x1e0d*/ 622,
+ /*0x1e8d*/ 686,
+ /*0x010d*/ 62,
+ /*0x020d*/ 172,
+ /*0x2c8d*/ 914,
+ -1, -1, -1,
+ /*0x16e79*/ 1384,
+ /*0x03cc*/ 274,
+ /*0x1f44*/ 773,
+ /*0x118c4*/ 1331,
+ /*0x16ed0*/ 1412,
+ /*0x2c44*/ 872,
+ /*0x10cea*/ 1296,
+ -1, -1,
+ /*0x16e78*/ 1383,
+ /*0x16e72*/ 1377,
+ -1,
+ /*0x049d*/ 368,
+ /*0x13be*/ 556,
+ /*0x043e*/ 308,
+ -1,
+ /*0x1e1d*/ 630,
+ /*0x1043e*/ 1165,
+ /*0x011d*/ 70,
+ /*0x021d*/ 180,
+ /*0x2c9d*/ 922,
+ /*0x013e*/ 85,
+ /*0x1f76*/ 793,
+ -1, -1,
+ /*0x2c76*/ 907,
+ -1,
+ /*0x10ea*/ 506,
+ -1,
+ /*0x0577*/ 464,
+ -1,
+ /*0x10ce2*/ 1288,
+ /*0x10cdc*/ 1282,
+ /*0x16ed2*/ 1414,
+ /*0x00ea*/ 35,
+ /*0x13d4*/ 578,
+ /*0x0454*/ 330,
+ -1,
+ /*0x2c6c*/ 905,
+ -1,
+ /*0x1fb1*/ 802,
+ -1,
+ /*0x10d7a*/ 1315,
+ -1,
+ /*0x0254*/ 204,
+ -1,
+ /*0x13ee*/ 604,
+ /*0x01b6*/ 135,
+ /*0x10cda*/ 1280,
+ /*0x006e*/ 12,
+ /*0x24d4*/ 830,
+ /*0x104ee*/ 1205,
+ /*0x10e2*/ 498,
+ /*0x10dc*/ 492,
+ /*0x03ca*/ 272,
+ /*0x10cd6*/ 1276,
+ /*0x2cee*/ 959,
+ /*0x01dc*/ 149,
+ -1,
+ /*0x00e2*/ 27,
+ -1, -1, -1,
+ /*0x0566*/ 447,
+ -1,
+ /*0x2c68*/ 903,
+ /*0x13de*/ 588,
+ /*0x045e*/ 340,
+ /*0x10cd8*/ 1278,
+ /*0x10da*/ 490,
+ -1,
+ /*0x104de*/ 1189,
+ -1,
+ /*0x01da*/ 148,
+ -1, -1,
+ /*0x10d6*/ 486,
+ -1, -1, -1,
+ /*0x01d6*/ 146,
+ /*0x24de*/ 840,
+ -1, -1,
+ /*0xa797*/ 1087,
+ /*0x10d76*/ 1311,
+ /*0x16e7b*/ 1386,
+ -1, -1,
+ /*0x10d8*/ 488,
+ /*0x1e92b*/ 1425,
+ -1, -1,
+ /*0x01d8*/ 147,
+ /*0x0287*/ 229,
+ /*0x03bc*/ 259,
+ -1,
+ /*0x118cc*/ 1339,
+ -1,
+ /*0x2c4c*/ 880,
+ -1,
+ /*0x01b4*/ 134,
+ -1,
+ /*0x105ab*/ 1238,
+ -1, -1,
+ /*0x1f64*/ 783,
+ /*0x13ba*/ 552,
+ /*0x043a*/ 304,
+ /*0x10d7f*/ 1320,
+ -1,
+ /*0x1043a*/ 1161,
+ /*0x16ec6*/ 1402,
+ /*0xa79d*/ 1090,
+ /*0xa681*/ 1024,
+ /*0x013a*/ 83,
+ /*0x2d13*/ 980,
+ -1, -1, -1, -1,
+ /*0xa685*/ 1026,
+ /*0x0570*/ 457,
+ /*0x1f74*/ 791,
+ /*0x1e09*/ 620,
+ /*0x1e89*/ 684,
+ /*0x0109*/ 60,
+ /*0x0209*/ 170,
+ /*0x2c89*/ 912,
+ /*0x13b8*/ 550,
+ /*0x0438*/ 302,
+ -1, -1,
+ /*0x10438*/ 1159,
+ -1, -1, -1, -1, -1, -1,
+ /*0x10cd4*/ 1274,
+ /*0x16ec4*/ 1400,
+ -1, -1, -1, -1,
+ /*0x10599*/ 1221,
+ -1,
+ /*0x16e77*/ 1382,
+ -1,
+ /*0x118ca*/ 1337,
+ /*0x10cee*/ 1300,
+ /*0x2c4a*/ 878,
+ /*0x13b2*/ 544,
+ /*0x0432*/ 296,
+ /*0x0513*/ 427,
+ /*0x1f15*/ 752,
+ /*0x10432*/ 1153,
+ -1, -1, -1,
+ /*0x10d4*/ 484,
+ /*0x03b6*/ 253,
+ -1, -1,
+ /*0x01d4*/ 145,
+ -1, -1, -1,
+ /*0x1f60*/ 779,
+ -1,
+ /*0x10cde*/ 1284,
+ /*0x10ee*/ 510,
+ /*0x1f7c*/ 799,
+ -1, -1, -1, -1,
+ /*0x057a*/ 467,
+ /*0x00ee*/ 39,
+ -1, -1,
+ /*0x16e66*/ 1365,
+ -1, -1, -1,
+ /*0x10d74*/ 1309,
+ -1, -1, -1, -1, -1,
+ /*0x10de*/ 494,
+ /*0x2c3c*/ 864,
+ -1, -1, -1, -1,
+ /*0x1e93c*/ 1442,
+ -1, -1, -1, -1, -1, -1,
+ -1,
+ /*0x1f07*/ 746,
+ -1, -1, -1, -1,
+ /*0x105bc*/ 1253,
+ -1, -1, -1, -1,
+ /*0x03b4*/ 251,
+ -1, -1, -1, -1,
+ /*0x0576*/ 463,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ /*0x056c*/ 453,
+ /*0x16ecc*/ 1408,
+ /*0x10d7c*/ 1317,
+ -1,
+ /*0x029d*/ 236,
+ -1, -1,
+ /*0x16e70*/ 1375,
+ -1, -1,
+ /*0x2c6a*/ 904,
+ /*0x057f*/ 472,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1,
+ /*0x1f36*/ 767,
+ /*0x03be*/ 261,
+ -1,
+ /*0x2c36*/ 858,
+ /*0x0568*/ 449,
+ -1, -1, -1,
+ /*0x1e936*/ 1436,
+ /*0x1f62*/ 781,
+ -1,
+ /*0x118dc*/ 1355,
+ -1,
+ /*0x2c5c*/ 896,
+ -1, -1, -1, -1, -1, -1,
+ -1,
+ /*0x105b6*/ 1248,
+ -1, -1,
+ /*0x052b*/ 439,
+ -1, -1,
+ /*0x118da*/ 1353,
+ /*0x2d19*/ 986,
+ /*0x2c5a*/ 894,
+ -1,
+ /*0x16eca*/ 1406,
+ -1, -1,
+ /*0x118d6*/ 1349,
+ -1,
+ /*0x2c56*/ 890,
+ -1, -1, -1,
+ /*0x16e7a*/ 1385,
+ -1, -1, -1, -1, -1, -1,
+ /*0x118d8*/ 1351,
+ /*0x0564*/ 445,
+ /*0x2c58*/ 892,
+ -1, -1, -1, -1,
+ /*0x1f34*/ 765,
+ -1, -1,
+ /*0x2c34*/ 856,
+ -1,
+ /*0x2d15*/ 982,
+ -1, -1,
+ /*0x1e934*/ 1434,
+ -1,
+ /*0x1fd0*/ 803,
+ /*0x0574*/ 461,
+ -1,
+ /*0x0519*/ 430,
+ -1, -1, -1, -1,
+ /*0x16ebc*/ 1392,
+ -1, -1,
+ /*0x105b4*/ 1246,
+ -1, -1, -1, -1, -1, -1,
+ -1,
+ /*0x16e76*/ 1381,
+ -1,
+ /*0x10597*/ 1219,
+ -1, -1, -1,
+ /*0x0289*/ 231,
+ -1, -1, -1, -1, -1,
+ /*0x03ba*/ 257,
+ /*0x16e6c*/ 1371,
+ -1,
+ /*0x0515*/ 428,
+ /*0x2c3e*/ 866,
+ /*0xa68f*/ 1031,
+ -1, -1, -1,
+ /*0x1e93e*/ 1444,
+ -1, -1,
+ /*0x16e7f*/ 1390,
+ -1,
+ /*0x2d07*/ 968,
+ -1, -1, -1, -1,
+ /*0x1059d*/ 1225,
+ /*0x057c*/ 469,
+ -1,
+ /*0x03b8*/ 255,
+ -1,
+ /*0x118d4*/ 1347,
+ -1,
+ /*0x2c54*/ 888,
+ -1,
+ /*0x16e68*/ 1367,
+ -1, -1, -1, -1,
+ /*0xff48*/ 1124,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1,
+ /*0xa683*/ 1025,
+ /*0x03b2*/ 249,
+ -1, -1, -1, -1, -1, -1,
+ /*0x0507*/ 421,
+ -1,
+ /*0x118de*/ 1357,
+ -1,
+ /*0x2c5e*/ 898,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1,
+ /*0x16e64*/ 1363,
+ -1,
+ /*0xff4e*/ 1130,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1,
+ /*0x056a*/ 451,
+ /*0x16e74*/ 1379,
+ -1, -1, -1, -1, -1, -1,
+ -1,
+ /*0xff50*/ 1132,
+ /*0x2c3a*/ 862,
+ -1, -1, -1, -1,
+ /*0x1e93a*/ 1440,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1,
+ /*0x0562*/ 443,
+ -1, -1, -1, -1, -1, -1,
+ /*0x2c38*/ 860,
+ -1, -1, -1, -1,
+ /*0x1e938*/ 1438,
+ /*0xff52*/ 1134,
+ -1, -1,
+ /*0x2d17*/ 984,
+ -1, -1, -1, -1,
+ /*0x2d0d*/ 974,
+ /*0x16e60*/ 1359,
+ -1, -1,
+ /*0x105b8*/ 1250,
+ /*0x16e7c*/ 1387,
+ /*0x16ebe*/ 1394,
+ /*0x1f32*/ 763,
+ -1, -1,
+ /*0x2c32*/ 854,
+ -1, -1, -1, -1,
+ /*0x1e932*/ 1432,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1,
+ /*0x2d1d*/ 990,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1,
+ /*0x0517*/ 429,
+ -1, -1, -1, -1,
+ /*0x050d*/ 424,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1,
+ /*0x051d*/ 432,
+ -1, -1, -1, -1, -1, -1,
+ -1,
+ /*0xff46*/ 1122,
+ -1,
+ /*0x16e6a*/ 1369,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ /*0x16e62*/ 1361,
+ /*0x056e*/ 455,
+ /*0xff44*/ 1120,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1,
+ /*0x2d09*/ 970,
+ -1, -1, -1, -1, -1, -1,
+ /*0x1fe0*/ 805,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ /*0xa693*/ 1033,
+ /*0x0509*/ 422,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1,
+ /*0xff4c*/ 1128,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1,
+ /*0x16e6e*/ 1373,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1,
+ /*0xff4a*/ 1126,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1,
+ /*0xa699*/ 1036,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ /*0xa695*/ 1034,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1,
+ /*0xff5a*/ 1142,
+ -1, -1, -1, -1, -1, -1,
+ /*0xff56*/ 1138,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ /*0xff58*/ 1140,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ /*0xa687*/ 1027,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1,
+ /*0xff54*/ 1136,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1,
+ /*0xa697*/ 1035,
+ -1, -1, -1, -1,
+ /*0xa68d*/ 1030,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1,
+ /*0xa689*/ 1028
+ };
+
+ if (code <= MAX_CODE_VALUE && code >= MIN_CODE_VALUE)
+ {
+ register unsigned int key = onigenc_unicode_CaseUnfold_11_hash(code);
+
+ if (key <= MAX_HASH_VALUE)
+ {
+ register short s = wordlist[key];
+
+ if (s >= 0 && code1_equal(code, CaseUnfold_11_Table[s].from))
+ return &CaseUnfold_11_Table[s].to;
+ }
+ }
+ return 0;
+}
+
+static const CaseUnfold_12_Type CaseUnfold_12_Table[] = {
+#define CaseUnfold_12 (*(CaseUnfold_12_Type (*)[58])(CaseUnfold_12_Table+0))
+ {{0x0061, 0x02be}, {1, {0x1e9a}}},
+ {{0x0066, 0x0066}, {1, {0xfb00}}},
+ {{0x0066, 0x0069}, {1, {0xfb01}}},
+ {{0x0066, 0x006c}, {1, {0xfb02}}},
+ {{0x0068, 0x0331}, {1, {0x1e96}}},
+ {{0x006a, 0x030c}, {1, {0x01f0}}},
+ {{0x0073, 0x0073}, {2, {0x00df, 0x1e9e}}},
+ {{0x0073, 0x0074}, {2, {0xfb05, 0xfb06}}},
+ {{0x0074, 0x0308}, {1, {0x1e97}}},
+ {{0x0077, 0x030a}, {1, {0x1e98}}},
+ {{0x0079, 0x030a}, {1, {0x1e99}}},
+ {{0x02bc, 0x006e}, {1, {0x0149}}},
+ {{0x03ac, 0x03b9}, {1, {0x1fb4}}},
+ {{0x03ae, 0x03b9}, {1, {0x1fc4}}},
+ {{0x03b1, 0x0342}, {1, {0x1fb6}}},
+ {{0x03b1, 0x03b9}, {2, {0x1fb3, 0x1fbc}}},
+ {{0x03b7, 0x0342}, {1, {0x1fc6}}},
+ {{0x03b7, 0x03b9}, {2, {0x1fc3, 0x1fcc}}},
+ {{0x03b9, 0x0342}, {1, {0x1fd6}}},
+ {{0x03c1, 0x0313}, {1, {0x1fe4}}},
+ {{0x03c5, 0x0313}, {1, {0x1f50}}},
+ {{0x03c5, 0x0342}, {1, {0x1fe6}}},
+ {{0x03c9, 0x0342}, {1, {0x1ff6}}},
+ {{0x03c9, 0x03b9}, {2, {0x1ff3, 0x1ffc}}},
+ {{0x03ce, 0x03b9}, {1, {0x1ff4}}},
+ {{0x0565, 0x0582}, {1, {0x0587}}},
+ {{0x0574, 0x0565}, {1, {0xfb14}}},
+ {{0x0574, 0x056b}, {1, {0xfb15}}},
+ {{0x0574, 0x056d}, {1, {0xfb17}}},
+ {{0x0574, 0x0576}, {1, {0xfb13}}},
+ {{0x057e, 0x0576}, {1, {0xfb16}}},
+ {{0x1f00, 0x03b9}, {2, {0x1f80, 0x1f88}}},
+ {{0x1f01, 0x03b9}, {2, {0x1f81, 0x1f89}}},
+ {{0x1f02, 0x03b9}, {2, {0x1f82, 0x1f8a}}},
+ {{0x1f03, 0x03b9}, {2, {0x1f83, 0x1f8b}}},
+ {{0x1f04, 0x03b9}, {2, {0x1f84, 0x1f8c}}},
+ {{0x1f05, 0x03b9}, {2, {0x1f85, 0x1f8d}}},
+ {{0x1f06, 0x03b9}, {2, {0x1f86, 0x1f8e}}},
+ {{0x1f07, 0x03b9}, {2, {0x1f87, 0x1f8f}}},
+ {{0x1f20, 0x03b9}, {2, {0x1f90, 0x1f98}}},
+ {{0x1f21, 0x03b9}, {2, {0x1f91, 0x1f99}}},
+ {{0x1f22, 0x03b9}, {2, {0x1f92, 0x1f9a}}},
+ {{0x1f23, 0x03b9}, {2, {0x1f93, 0x1f9b}}},
+ {{0x1f24, 0x03b9}, {2, {0x1f94, 0x1f9c}}},
+ {{0x1f25, 0x03b9}, {2, {0x1f95, 0x1f9d}}},
+ {{0x1f26, 0x03b9}, {2, {0x1f96, 0x1f9e}}},
+ {{0x1f27, 0x03b9}, {2, {0x1f97, 0x1f9f}}},
+ {{0x1f60, 0x03b9}, {2, {0x1fa0, 0x1fa8}}},
+ {{0x1f61, 0x03b9}, {2, {0x1fa1, 0x1fa9}}},
+ {{0x1f62, 0x03b9}, {2, {0x1fa2, 0x1faa}}},
+ {{0x1f63, 0x03b9}, {2, {0x1fa3, 0x1fab}}},
+ {{0x1f64, 0x03b9}, {2, {0x1fa4, 0x1fac}}},
+ {{0x1f65, 0x03b9}, {2, {0x1fa5, 0x1fad}}},
+ {{0x1f66, 0x03b9}, {2, {0x1fa6, 0x1fae}}},
+ {{0x1f67, 0x03b9}, {2, {0x1fa7, 0x1faf}}},
+ {{0x1f70, 0x03b9}, {1, {0x1fb2}}},
+ {{0x1f74, 0x03b9}, {1, {0x1fc2}}},
+ {{0x1f7c, 0x03b9}, {1, {0x1ff2}}},
+#define CaseUnfold_12_Locale (*(CaseUnfold_12_Type (*)[1])(CaseUnfold_12_Table+58))
+ {{0x0069, 0x0307}, {1, {0x0130}}},
+};
+
+/* ANSI-C code produced by gperf version 3.1 */
+/* Command-line: gperf -7 -k1,2,3,4,5,6 -F,-1 -c -j1 -i1 -t -T -E -C -H onigenc_unicode_CaseUnfold_12_hash -N onigenc_unicode_CaseUnfold_12_lookup -n */
+
+/* maximum key range = 71, duplicates = 0 */
+
+#ifdef __GNUC__
+__inline
+#else
+#ifdef __cplusplus
+inline
+#endif
+#endif
+/*ARGSUSED*/
+static unsigned int
+onigenc_unicode_CaseUnfold_12_hash(const OnigCodePoint *codes)
+{
+ static const unsigned char asso_values[] =
+ {
+ 3, 58, 54, 57, 56, 16, 8, 2, 43, 82,
+ 3, 1, 23, 82, 82, 82, 82, 82, 82, 4,
+ 82, 82, 82, 82, 82, 82, 82, 82, 82, 82,
+ 82, 82, 52, 51, 50, 49, 48, 47, 46, 45,
+ 82, 82, 82, 82, 43, 82, 42, 82, 82, 13,
+ 82, 82, 82, 82, 82, 11, 82, 1, 82, 82,
+ 14, 82, 1, 82, 82, 31, 3, 82, 82, 30,
+ 82, 82, 82, 10, 82, 82, 82, 82, 37, 82,
+ 82, 82, 82, 82, 82, 82, 82, 82, 82, 82,
+ 82, 82, 82, 82, 82, 82, 37, 15, 36, 35,
+ 34, 17, 1, 33, 12, 4, 23, 23, 26, 21,
+ 13, 82, 27, 82, 82, 2, 5, 82, 11, 16,
+ 82, 15, 82, 82, 23, 82, 8, 82
+ };
+ return asso_values[bits_at(codes, 5)] + asso_values[bits_at(codes, 4)] + asso_values[bits_at(codes, 3)] + asso_values[bits_at(codes, 2)] + asso_values[bits_at(codes, 1)] + asso_values[bits_at(codes, 0)];
+}
+
+static const CodePointList2 *
+onigenc_unicode_CaseUnfold_12_lookup(const OnigCodePoint *codes)
+{
+ enum
+ {
+ MIN_CODE_VALUE = 0x61,
+ MAX_CODE_VALUE = 0x1f7c,
+ TOTAL_KEYWORDS = 59,
+ MIN_WORD_LENGTH = 6,
+ MAX_WORD_LENGTH = 6,
+ MIN_HASH_VALUE = 11,
+ MAX_HASH_VALUE = 81
+ };
+
+ static const short wordlist[] =
+ {
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1,
+ /*0x1f66,0x03b9*/ 53,
+ /*0x1f07,0x03b9*/ 38,
+ /*0x1f00,0x03b9*/ 31,
+ /*0x0066,0x0066*/ 1,
+ /*0x1f74,0x03b9*/ 56,
+ /*0x0073,0x0073*/ 6,
+ /*0x0066,0x0069*/ 2,
+ /*0x1f06,0x03b9*/ 37,
+ /*0x0073,0x0074*/ 7,
+ /*0x03b9,0x0342*/ 18,
+ /*0x03c9,0x03b9*/ 23,
+ /*0x03b7,0x03b9*/ 17,
+ /*0x0069,0x0307*/ 58,
+ /*0x03b1,0x03b9*/ 15,
+ /*0x1f61,0x03b9*/ 48,
+ /*0x1f05,0x03b9*/ 36,
+ /*0x1f65,0x03b9*/ 52,
+ /*0x0574,0x0576*/ 29,
+ /*0x03c9,0x0342*/ 22,
+ /*0x03b7,0x0342*/ 16,
+ /*0x057e,0x0576*/ 30,
+ /*0x03b1,0x0342*/ 14,
+ /*0x1f7c,0x03b9*/ 57,
+ /*0x0574,0x0565*/ 26,
+ /*0x0079,0x030a*/ 10,
+ /*0x0077,0x030a*/ 9,
+ /*0x1f70,0x03b9*/ 55,
+ /*0x0574,0x056d*/ 28,
+ /*0x0066,0x006c*/ 3,
+ /*0x0574,0x056b*/ 27,
+ /*0x0061,0x02be*/ 0,
+ /*0x0068,0x0331*/ 4,
+ /*0x1f67,0x03b9*/ 54,
+ /*0x1f64,0x03b9*/ 51,
+ /*0x1f63,0x03b9*/ 50,
+ /*0x1f62,0x03b9*/ 49,
+ /*0x1f60,0x03b9*/ 47,
+ /*0x03ce,0x03b9*/ 24,
+ /*0x03c5,0x0342*/ 21,
+ /*0x03c5,0x0313*/ 20,
+ /*0x03c1,0x0313*/ 19,
+ /*0x02bc,0x006e*/ 11,
+ /*0x03ae,0x03b9*/ 13,
+ /*0x03ac,0x03b9*/ 12,
+ /*0x1f27,0x03b9*/ 46,
+ /*0x1f26,0x03b9*/ 45,
+ /*0x1f25,0x03b9*/ 44,
+ /*0x1f24,0x03b9*/ 43,
+ /*0x1f23,0x03b9*/ 42,
+ /*0x1f22,0x03b9*/ 41,
+ /*0x1f21,0x03b9*/ 40,
+ /*0x1f20,0x03b9*/ 39,
+ /*0x006a,0x030c*/ 5,
+ /*0x1f02,0x03b9*/ 33,
+ /*0x0074,0x0308*/ 8,
+ /*0x1f04,0x03b9*/ 35,
+ /*0x1f03,0x03b9*/ 34,
+ /*0x1f01,0x03b9*/ 32,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ /*0x0565,0x0582*/ 25
+ };
+
+ if (codes[0] <= MAX_CODE_VALUE && codes[0] >= MIN_CODE_VALUE &&
+ codes[1] <= MAX_CODE_VALUE && codes[1] >= MIN_CODE_VALUE)
+ {
+ register unsigned int key = onigenc_unicode_CaseUnfold_12_hash(codes);
+
+ if (key <= MAX_HASH_VALUE)
+ {
+ register short s = wordlist[key];
+
+ if (s >= 0 && code2_equal(codes, CaseUnfold_12_Table[s].from))
+ return &CaseUnfold_12_Table[s].to;
+ }
+ }
+ return 0;
+}
+
+static const CaseUnfold_13_Type CaseUnfold_13_Table[] = {
+#define CaseUnfold_13 (*(CaseUnfold_13_Type (*)[14])(CaseUnfold_13_Table+0))
+ {{0x0066, 0x0066, 0x0069}, {1, {0xfb03}}},
+ {{0x0066, 0x0066, 0x006c}, {1, {0xfb04}}},
+ {{0x03b1, 0x0342, 0x03b9}, {1, {0x1fb7}}},
+ {{0x03b7, 0x0342, 0x03b9}, {1, {0x1fc7}}},
+ {{0x03b9, 0x0308, 0x0300}, {1, {0x1fd2}}},
+ {{0x03b9, 0x0308, 0x0301}, {2, {0x0390, 0x1fd3}}},
+ {{0x03b9, 0x0308, 0x0342}, {1, {0x1fd7}}},
+ {{0x03c5, 0x0308, 0x0300}, {1, {0x1fe2}}},
+ {{0x03c5, 0x0308, 0x0301}, {2, {0x03b0, 0x1fe3}}},
+ {{0x03c5, 0x0308, 0x0342}, {1, {0x1fe7}}},
+ {{0x03c5, 0x0313, 0x0300}, {1, {0x1f52}}},
+ {{0x03c5, 0x0313, 0x0301}, {1, {0x1f54}}},
+ {{0x03c5, 0x0313, 0x0342}, {1, {0x1f56}}},
+ {{0x03c9, 0x0342, 0x03b9}, {1, {0x1ff7}}},
+};
+
+/* ANSI-C code produced by gperf version 3.1 */
+/* Command-line: gperf -7 -k1,2,3,4,5,6,7,8,9 -F,-1 -c -j1 -i1 -t -T -E -C -H onigenc_unicode_CaseUnfold_13_hash -N onigenc_unicode_CaseUnfold_13_lookup -n */
+
+/* maximum key range = 20, duplicates = 0 */
+
+#ifdef __GNUC__
+__inline
+#else
+#ifdef __cplusplus
+inline
+#endif
+#endif
+/*ARGSUSED*/
+static unsigned int
+onigenc_unicode_CaseUnfold_13_hash(const OnigCodePoint *codes)
+{
+ static const unsigned char asso_values[] =
+ {
+ 7, 4, 47, 47, 47, 47, 1, 1, 2, 47,
+ 47, 47, 47, 47, 47, 47, 47, 47, 47, 1,
+ 47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
+ 47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
+ 47, 47, 47, 47, 47, 47, 47, 47, 47, 11,
+ 47, 47, 47, 47, 47, 10, 47, 2, 47, 47,
+ 47, 47, 47, 47, 47, 47, 1, 47, 47, 1,
+ 47, 47, 47, 9, 47, 47, 47, 47, 47, 47,
+ 47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
+ 47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
+ 47, 47, 1, 47, 47, 2, 47, 47, 1, 47,
+ 47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
+ 47, 47, 47, 47, 47, 47, 47, 47
+ };
+ return asso_values[bits_at(codes, 8)] + asso_values[bits_at(codes, 7)] + asso_values[bits_at(codes, 6)] + asso_values[bits_at(codes, 5)] + asso_values[bits_at(codes, 4)] + asso_values[bits_at(codes, 3)] + asso_values[bits_at(codes, 2)] + asso_values[bits_at(codes, 1)] + asso_values[bits_at(codes, 0)];
+}
+
+static const CodePointList2 *
+onigenc_unicode_CaseUnfold_13_lookup(const OnigCodePoint *codes)
+{
+ enum
+ {
+ MIN_CODE_VALUE = 0x66,
+ MAX_CODE_VALUE = 0x3c9,
+ TOTAL_KEYWORDS = 14,
+ MIN_WORD_LENGTH = 9,
+ MAX_WORD_LENGTH = 9,
+ MIN_HASH_VALUE = 27,
+ MAX_HASH_VALUE = 46
+ };
+
+ static const short wordlist[] =
+ {
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1,
+ /*0x03c5,0x0313,0x0342*/ 12,
+ /*0x03c5,0x0308,0x0342*/ 9,
+ /*0x03b9,0x0308,0x0342*/ 6,
+ /*0x03c5,0x0313,0x0301*/ 11,
+ /*0x03c5,0x0308,0x0301*/ 8,
+ /*0x03b9,0x0308,0x0301*/ 5,
+ /*0x03c5,0x0313,0x0300*/ 10,
+ /*0x03c5,0x0308,0x0300*/ 7,
+ /*0x03b9,0x0308,0x0300*/ 4,
+ /*0x03c9,0x0342,0x03b9*/ 13,
+ /*0x03b7,0x0342,0x03b9*/ 3,
+ /*0x03b1,0x0342,0x03b9*/ 2,
+ -1, -1, -1, -1, -1, -1,
+ /*0x0066,0x0066,0x006c*/ 1,
+ /*0x0066,0x0066,0x0069*/ 0
+ };
+
+ if (codes[0] <= MAX_CODE_VALUE && codes[0] >= MIN_CODE_VALUE &&
+ codes[1] <= MAX_CODE_VALUE && codes[1] >= MIN_CODE_VALUE &&
+ codes[2] <= MAX_CODE_VALUE && codes[2] >= MIN_CODE_VALUE)
+ {
+ register unsigned int key = onigenc_unicode_CaseUnfold_13_hash(codes);
+
+ if (key <= MAX_HASH_VALUE)
+ {
+ register short s = wordlist[key];
+
+ if (s >= 0 && code3_equal(codes, CaseUnfold_13_Table[s].from))
+ return &CaseUnfold_13_Table[s].to;
+ }
+ }
+ return 0;
+}
+
+static const OnigCodePoint CaseMappingSpecials[] = {
+ L(1)|0x039C,
+ L(2)|0x0053, 0x0073, L(2)|0x0053, 0x0053,
+ L(2)|0x02BC, 0x004E,
+ L(1)|0x0053,
+ L(1)|0x01C5,
+ L(2)|0x0064, 0x017D, L(1)|0x01C4,
+ L(1)|0x01C8,
+ L(2)|0x006C, 0x004A, L(1)|0x01C7,
+ L(1)|0x01CB,
+ L(2)|0x006E, 0x004A, L(1)|0x01CA,
+ L(2)|0x004A, 0x030C,
+ L(1)|0x01F2,
+ L(2)|0x0064, 0x005A, L(1)|0x01F1,
+ L(1)|0x0399,
+ L(3)|0x0399, 0x0308, 0x0301,
+ L(3)|0x03A5, 0x0308, 0x0301,
+ L(1)|0x03A3,
+ L(1)|0x0392,
+ L(1)|0x0398,
+ L(1)|0x03A6,
+ L(1)|0x03A0,
+ L(1)|0x039A,
+ L(1)|0x03A1,
+ L(1)|0x0395,
+ L(2)|0x0535, 0x0582, L(2)|0x0535, 0x0552,
+ L(1)|0x0412,
+ L(1)|0x0414,
+ L(1)|0x041E,
+ L(1)|0x0421,
+ L(1)|0x0422,
+ L(1)|0x0422,
+ L(1)|0x042A,
+ L(1)|0x0462,
+ L(1)|0xA64A,
+ L(2)|0x0048, 0x0331,
+ L(2)|0x0054, 0x0308,
+ L(2)|0x0057, 0x030A,
+ L(2)|0x0059, 0x030A,
+ L(2)|0x0041, 0x02BE,
+ L(1)|0x1E60,
+ L(1)|0x00DF,
+ L(2)|0x03A5, 0x0313,
+ L(3)|0x03A5, 0x0313, 0x0300,
+ L(3)|0x03A5, 0x0313, 0x0301,
+ L(3)|0x03A5, 0x0313, 0x0342,
+ L(1)|0x1F88, L(2)|0x1F08, 0x0399,
+ L(1)|0x1F89, L(2)|0x1F09, 0x0399,
+ L(1)|0x1F8A, L(2)|0x1F0A, 0x0399,
+ L(1)|0x1F8B, L(2)|0x1F0B, 0x0399,
+ L(1)|0x1F8C, L(2)|0x1F0C, 0x0399,
+ L(1)|0x1F8D, L(2)|0x1F0D, 0x0399,
+ L(1)|0x1F8E, L(2)|0x1F0E, 0x0399,
+ L(1)|0x1F8F, L(2)|0x1F0F, 0x0399,
+ L(2)|0x1F00, 0x0399, L(1)|0x1F80, L(2)|0x1F08, 0x0399,
+ L(2)|0x1F01, 0x0399, L(1)|0x1F81, L(2)|0x1F09, 0x0399,
+ L(2)|0x1F02, 0x0399, L(1)|0x1F82, L(2)|0x1F0A, 0x0399,
+ L(2)|0x1F03, 0x0399, L(1)|0x1F83, L(2)|0x1F0B, 0x0399,
+ L(2)|0x1F04, 0x0399, L(1)|0x1F84, L(2)|0x1F0C, 0x0399,
+ L(2)|0x1F05, 0x0399, L(1)|0x1F85, L(2)|0x1F0D, 0x0399,
+ L(2)|0x1F06, 0x0399, L(1)|0x1F86, L(2)|0x1F0E, 0x0399,
+ L(2)|0x1F07, 0x0399, L(1)|0x1F87, L(2)|0x1F0F, 0x0399,
+ L(1)|0x1F98, L(2)|0x1F28, 0x0399,
+ L(1)|0x1F99, L(2)|0x1F29, 0x0399,
+ L(1)|0x1F9A, L(2)|0x1F2A, 0x0399,
+ L(1)|0x1F9B, L(2)|0x1F2B, 0x0399,
+ L(1)|0x1F9C, L(2)|0x1F2C, 0x0399,
+ L(1)|0x1F9D, L(2)|0x1F2D, 0x0399,
+ L(1)|0x1F9E, L(2)|0x1F2E, 0x0399,
+ L(1)|0x1F9F, L(2)|0x1F2F, 0x0399,
+ L(2)|0x1F20, 0x0399, L(1)|0x1F90, L(2)|0x1F28, 0x0399,
+ L(2)|0x1F21, 0x0399, L(1)|0x1F91, L(2)|0x1F29, 0x0399,
+ L(2)|0x1F22, 0x0399, L(1)|0x1F92, L(2)|0x1F2A, 0x0399,
+ L(2)|0x1F23, 0x0399, L(1)|0x1F93, L(2)|0x1F2B, 0x0399,
+ L(2)|0x1F24, 0x0399, L(1)|0x1F94, L(2)|0x1F2C, 0x0399,
+ L(2)|0x1F25, 0x0399, L(1)|0x1F95, L(2)|0x1F2D, 0x0399,
+ L(2)|0x1F26, 0x0399, L(1)|0x1F96, L(2)|0x1F2E, 0x0399,
+ L(2)|0x1F27, 0x0399, L(1)|0x1F97, L(2)|0x1F2F, 0x0399,
+ L(1)|0x1FA8, L(2)|0x1F68, 0x0399,
+ L(1)|0x1FA9, L(2)|0x1F69, 0x0399,
+ L(1)|0x1FAA, L(2)|0x1F6A, 0x0399,
+ L(1)|0x1FAB, L(2)|0x1F6B, 0x0399,
+ L(1)|0x1FAC, L(2)|0x1F6C, 0x0399,
+ L(1)|0x1FAD, L(2)|0x1F6D, 0x0399,
+ L(1)|0x1FAE, L(2)|0x1F6E, 0x0399,
+ L(1)|0x1FAF, L(2)|0x1F6F, 0x0399,
+ L(2)|0x1F60, 0x0399, L(1)|0x1FA0, L(2)|0x1F68, 0x0399,
+ L(2)|0x1F61, 0x0399, L(1)|0x1FA1, L(2)|0x1F69, 0x0399,
+ L(2)|0x1F62, 0x0399, L(1)|0x1FA2, L(2)|0x1F6A, 0x0399,
+ L(2)|0x1F63, 0x0399, L(1)|0x1FA3, L(2)|0x1F6B, 0x0399,
+ L(2)|0x1F64, 0x0399, L(1)|0x1FA4, L(2)|0x1F6C, 0x0399,
+ L(2)|0x1F65, 0x0399, L(1)|0x1FA5, L(2)|0x1F6D, 0x0399,
+ L(2)|0x1F66, 0x0399, L(1)|0x1FA6, L(2)|0x1F6E, 0x0399,
+ L(2)|0x1F67, 0x0399, L(1)|0x1FA7, L(2)|0x1F6F, 0x0399,
+ L(2)|0x1FBA, 0x0345, L(2)|0x1FBA, 0x0399,
+ L(1)|0x1FBC, L(2)|0x0391, 0x0399,
+ L(2)|0x0386, 0x0345, L(2)|0x0386, 0x0399,
+ L(2)|0x0391, 0x0342,
+ L(3)|0x0391, 0x0342, 0x0345, L(3)|0x0391, 0x0342, 0x0399,
+ L(2)|0x03B1, 0x0399, L(1)|0x1FB3, L(2)|0x0391, 0x0399,
+ L(1)|0x0399,
+ L(2)|0x1FCA, 0x0345, L(2)|0x1FCA, 0x0399,
+ L(1)|0x1FCC, L(2)|0x0397, 0x0399,
+ L(2)|0x0389, 0x0345, L(2)|0x0389, 0x0399,
+ L(2)|0x0397, 0x0342,
+ L(3)|0x0397, 0x0342, 0x0345, L(3)|0x0397, 0x0342, 0x0399,
+ L(2)|0x03B7, 0x0399, L(1)|0x1FC3, L(2)|0x0397, 0x0399,
+ L(3)|0x0399, 0x0308, 0x0300,
+ L(3)|0x0399, 0x0308, 0x0301,
+ L(2)|0x0399, 0x0342,
+ L(3)|0x0399, 0x0308, 0x0342,
+ L(3)|0x03A5, 0x0308, 0x0300,
+ L(3)|0x03A5, 0x0308, 0x0301,
+ L(2)|0x03A1, 0x0313,
+ L(2)|0x03A5, 0x0342,
+ L(3)|0x03A5, 0x0308, 0x0342,
+ L(2)|0x1FFA, 0x0345, L(2)|0x1FFA, 0x0399,
+ L(1)|0x1FFC, L(2)|0x03A9, 0x0399,
+ L(2)|0x038F, 0x0345, L(2)|0x038F, 0x0399,
+ L(2)|0x03A9, 0x0342,
+ L(3)|0x03A9, 0x0342, 0x0345, L(3)|0x03A9, 0x0342, 0x0399,
+ L(2)|0x03C9, 0x0399, L(1)|0x1FF3, L(2)|0x03A9, 0x0399,
+ L(2)|0x0046, 0x0066, L(2)|0x0046, 0x0046,
+ L(2)|0x0046, 0x0069, L(2)|0x0046, 0x0049,
+ L(2)|0x0046, 0x006C, L(2)|0x0046, 0x004C,
+ L(3)|0x0046, 0x0066, 0x0069, L(3)|0x0046, 0x0046, 0x0049,
+ L(3)|0x0046, 0x0066, 0x006C, L(3)|0x0046, 0x0046, 0x004C,
+ L(2)|0x0053, 0x0074, L(2)|0x0053, 0x0054,
+ L(2)|0x0053, 0x0074, L(2)|0x0053, 0x0054,
+ L(2)|0x0544, 0x0576, L(2)|0x0544, 0x0546,
+ L(2)|0x0544, 0x0565, L(2)|0x0544, 0x0535,
+ L(2)|0x0544, 0x056B, L(2)|0x0544, 0x053B,
+ L(2)|0x054E, 0x0576, L(2)|0x054E, 0x0546,
+ L(2)|0x0544, 0x056D, L(2)|0x0544, 0x053D,
+};
diff --git a/enc/unicode/17.0.0/name2ctype.h b/enc/unicode/17.0.0/name2ctype.h
new file mode 100644
index 0000000000..8c1c0659ac
--- /dev/null
+++ b/enc/unicode/17.0.0/name2ctype.h
@@ -0,0 +1,49725 @@
+/* ANSI-C code produced by gperf version 3.1 */
+/* Command-line: gperf -7 -c -j1 -i1 -t -C -P -T -H uniname2ctype_hash -Q uniname2ctype_pool -N uniname2ctype_p */
+#ifndef USE_UNICODE_PROPERTIES
+/* Computed positions: -k'1,3' */
+#else /* USE_UNICODE_PROPERTIES */
+/* Computed positions: -k'1-3,5-6,12,16,$' */
+#endif /* USE_UNICODE_PROPERTIES */
+
+#if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \
+ && ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \
+ && (')' == 41) && ('*' == 42) && ('+' == 43) && (',' == 44) \
+ && ('-' == 45) && ('.' == 46) && ('/' == 47) && ('0' == 48) \
+ && ('1' == 49) && ('2' == 50) && ('3' == 51) && ('4' == 52) \
+ && ('5' == 53) && ('6' == 54) && ('7' == 55) && ('8' == 56) \
+ && ('9' == 57) && (':' == 58) && (';' == 59) && ('<' == 60) \
+ && ('=' == 61) && ('>' == 62) && ('?' == 63) && ('A' == 65) \
+ && ('B' == 66) && ('C' == 67) && ('D' == 68) && ('E' == 69) \
+ && ('F' == 70) && ('G' == 71) && ('H' == 72) && ('I' == 73) \
+ && ('J' == 74) && ('K' == 75) && ('L' == 76) && ('M' == 77) \
+ && ('N' == 78) && ('O' == 79) && ('P' == 80) && ('Q' == 81) \
+ && ('R' == 82) && ('S' == 83) && ('T' == 84) && ('U' == 85) \
+ && ('V' == 86) && ('W' == 87) && ('X' == 88) && ('Y' == 89) \
+ && ('Z' == 90) && ('[' == 91) && ('\\' == 92) && (']' == 93) \
+ && ('^' == 94) && ('_' == 95) && ('a' == 97) && ('b' == 98) \
+ && ('c' == 99) && ('d' == 100) && ('e' == 101) && ('f' == 102) \
+ && ('g' == 103) && ('h' == 104) && ('i' == 105) && ('j' == 106) \
+ && ('k' == 107) && ('l' == 108) && ('m' == 109) && ('n' == 110) \
+ && ('o' == 111) && ('p' == 112) && ('q' == 113) && ('r' == 114) \
+ && ('s' == 115) && ('t' == 116) && ('u' == 117) && ('v' == 118) \
+ && ('w' == 119) && ('x' == 120) && ('y' == 121) && ('z' == 122) \
+ && ('{' == 123) && ('|' == 124) && ('}' == 125) && ('~' == 126))
+/* The character set is not based on ISO-646. */
+#error "gperf generated tables don't work with this execution character set. Please report a bug to <bug-gperf@gnu.org>."
+#endif
+
+
+
+/* 'NEWLINE': [[:NEWLINE:]] */
+static const OnigCodePoint CR_NEWLINE[] = {
+ 1,
+ 0x000a, 0x000a,
+}; /* CR_NEWLINE */
+
+/* 'Alpha': [[:Alpha:]] */
+static const OnigCodePoint CR_Alpha[] = {
+ 761,
+ 0x0041, 0x005a,
+ 0x0061, 0x007a,
+ 0x00aa, 0x00aa,
+ 0x00b5, 0x00b5,
+ 0x00ba, 0x00ba,
+ 0x00c0, 0x00d6,
+ 0x00d8, 0x00f6,
+ 0x00f8, 0x02c1,
+ 0x02c6, 0x02d1,
+ 0x02e0, 0x02e4,
+ 0x02ec, 0x02ec,
+ 0x02ee, 0x02ee,
+ 0x0345, 0x0345,
+ 0x0363, 0x0374,
+ 0x0376, 0x0377,
+ 0x037a, 0x037d,
+ 0x037f, 0x037f,
+ 0x0386, 0x0386,
+ 0x0388, 0x038a,
+ 0x038c, 0x038c,
+ 0x038e, 0x03a1,
+ 0x03a3, 0x03f5,
+ 0x03f7, 0x0481,
+ 0x048a, 0x052f,
+ 0x0531, 0x0556,
+ 0x0559, 0x0559,
+ 0x0560, 0x0588,
+ 0x05b0, 0x05bd,
+ 0x05bf, 0x05bf,
+ 0x05c1, 0x05c2,
+ 0x05c4, 0x05c5,
+ 0x05c7, 0x05c7,
+ 0x05d0, 0x05ea,
+ 0x05ef, 0x05f2,
+ 0x0610, 0x061a,
+ 0x0620, 0x0657,
+ 0x0659, 0x065f,
+ 0x066e, 0x06d3,
+ 0x06d5, 0x06dc,
+ 0x06e1, 0x06e8,
+ 0x06ed, 0x06ef,
+ 0x06fa, 0x06fc,
+ 0x06ff, 0x06ff,
+ 0x0710, 0x073f,
+ 0x074d, 0x07b1,
+ 0x07ca, 0x07ea,
+ 0x07f4, 0x07f5,
+ 0x07fa, 0x07fa,
+ 0x0800, 0x0817,
+ 0x081a, 0x082c,
+ 0x0840, 0x0858,
+ 0x0860, 0x086a,
+ 0x0870, 0x0887,
+ 0x0889, 0x088f,
+ 0x0897, 0x0897,
+ 0x08a0, 0x08c9,
+ 0x08d4, 0x08df,
+ 0x08e3, 0x08e9,
+ 0x08f0, 0x093b,
+ 0x093d, 0x094c,
+ 0x094e, 0x0950,
+ 0x0955, 0x0963,
+ 0x0971, 0x0983,
+ 0x0985, 0x098c,
+ 0x098f, 0x0990,
+ 0x0993, 0x09a8,
+ 0x09aa, 0x09b0,
+ 0x09b2, 0x09b2,
+ 0x09b6, 0x09b9,
+ 0x09bd, 0x09c4,
+ 0x09c7, 0x09c8,
+ 0x09cb, 0x09cc,
+ 0x09ce, 0x09ce,
+ 0x09d7, 0x09d7,
+ 0x09dc, 0x09dd,
+ 0x09df, 0x09e3,
+ 0x09f0, 0x09f1,
+ 0x09fc, 0x09fc,
+ 0x0a01, 0x0a03,
+ 0x0a05, 0x0a0a,
+ 0x0a0f, 0x0a10,
+ 0x0a13, 0x0a28,
+ 0x0a2a, 0x0a30,
+ 0x0a32, 0x0a33,
+ 0x0a35, 0x0a36,
+ 0x0a38, 0x0a39,
+ 0x0a3e, 0x0a42,
+ 0x0a47, 0x0a48,
+ 0x0a4b, 0x0a4c,
+ 0x0a51, 0x0a51,
+ 0x0a59, 0x0a5c,
+ 0x0a5e, 0x0a5e,
+ 0x0a70, 0x0a75,
+ 0x0a81, 0x0a83,
+ 0x0a85, 0x0a8d,
+ 0x0a8f, 0x0a91,
+ 0x0a93, 0x0aa8,
+ 0x0aaa, 0x0ab0,
+ 0x0ab2, 0x0ab3,
+ 0x0ab5, 0x0ab9,
+ 0x0abd, 0x0ac5,
+ 0x0ac7, 0x0ac9,
+ 0x0acb, 0x0acc,
+ 0x0ad0, 0x0ad0,
+ 0x0ae0, 0x0ae3,
+ 0x0af9, 0x0afc,
+ 0x0b01, 0x0b03,
+ 0x0b05, 0x0b0c,
+ 0x0b0f, 0x0b10,
+ 0x0b13, 0x0b28,
+ 0x0b2a, 0x0b30,
+ 0x0b32, 0x0b33,
+ 0x0b35, 0x0b39,
+ 0x0b3d, 0x0b44,
+ 0x0b47, 0x0b48,
+ 0x0b4b, 0x0b4c,
+ 0x0b56, 0x0b57,
+ 0x0b5c, 0x0b5d,
+ 0x0b5f, 0x0b63,
+ 0x0b71, 0x0b71,
+ 0x0b82, 0x0b83,
+ 0x0b85, 0x0b8a,
+ 0x0b8e, 0x0b90,
+ 0x0b92, 0x0b95,
+ 0x0b99, 0x0b9a,
+ 0x0b9c, 0x0b9c,
+ 0x0b9e, 0x0b9f,
+ 0x0ba3, 0x0ba4,
+ 0x0ba8, 0x0baa,
+ 0x0bae, 0x0bb9,
+ 0x0bbe, 0x0bc2,
+ 0x0bc6, 0x0bc8,
+ 0x0bca, 0x0bcc,
+ 0x0bd0, 0x0bd0,
+ 0x0bd7, 0x0bd7,
+ 0x0c00, 0x0c0c,
+ 0x0c0e, 0x0c10,
+ 0x0c12, 0x0c28,
+ 0x0c2a, 0x0c39,
+ 0x0c3d, 0x0c44,
+ 0x0c46, 0x0c48,
+ 0x0c4a, 0x0c4c,
+ 0x0c55, 0x0c56,
+ 0x0c58, 0x0c5a,
+ 0x0c5c, 0x0c5d,
+ 0x0c60, 0x0c63,
+ 0x0c80, 0x0c83,
+ 0x0c85, 0x0c8c,
+ 0x0c8e, 0x0c90,
+ 0x0c92, 0x0ca8,
+ 0x0caa, 0x0cb3,
+ 0x0cb5, 0x0cb9,
+ 0x0cbd, 0x0cc4,
+ 0x0cc6, 0x0cc8,
+ 0x0cca, 0x0ccc,
+ 0x0cd5, 0x0cd6,
+ 0x0cdc, 0x0cde,
+ 0x0ce0, 0x0ce3,
+ 0x0cf1, 0x0cf3,
+ 0x0d00, 0x0d0c,
+ 0x0d0e, 0x0d10,
+ 0x0d12, 0x0d3a,
+ 0x0d3d, 0x0d44,
+ 0x0d46, 0x0d48,
+ 0x0d4a, 0x0d4c,
+ 0x0d4e, 0x0d4e,
+ 0x0d54, 0x0d57,
+ 0x0d5f, 0x0d63,
+ 0x0d7a, 0x0d7f,
+ 0x0d81, 0x0d83,
+ 0x0d85, 0x0d96,
+ 0x0d9a, 0x0db1,
+ 0x0db3, 0x0dbb,
+ 0x0dbd, 0x0dbd,
+ 0x0dc0, 0x0dc6,
+ 0x0dcf, 0x0dd4,
+ 0x0dd6, 0x0dd6,
+ 0x0dd8, 0x0ddf,
+ 0x0df2, 0x0df3,
+ 0x0e01, 0x0e3a,
+ 0x0e40, 0x0e46,
+ 0x0e4d, 0x0e4d,
+ 0x0e81, 0x0e82,
+ 0x0e84, 0x0e84,
+ 0x0e86, 0x0e8a,
+ 0x0e8c, 0x0ea3,
+ 0x0ea5, 0x0ea5,
+ 0x0ea7, 0x0eb9,
+ 0x0ebb, 0x0ebd,
+ 0x0ec0, 0x0ec4,
+ 0x0ec6, 0x0ec6,
+ 0x0ecd, 0x0ecd,
+ 0x0edc, 0x0edf,
+ 0x0f00, 0x0f00,
+ 0x0f40, 0x0f47,
+ 0x0f49, 0x0f6c,
+ 0x0f71, 0x0f83,
+ 0x0f88, 0x0f97,
+ 0x0f99, 0x0fbc,
+ 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, 0x1c8a,
+ 0x1c90, 0x1cba,
+ 0x1cbd, 0x1cbf,
+ 0x1ce9, 0x1cec,
+ 0x1cee, 0x1cf3,
+ 0x1cf5, 0x1cf6,
+ 0x1cfa, 0x1cfa,
+ 0x1d00, 0x1dbf,
+ 0x1dd3, 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, 0xa7dc,
+ 0xa7f1, 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,
+ 0x105c0, 0x105f3,
+ 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,
+ 0x10940, 0x10959,
+ 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,
+ 0x10d4a, 0x10d65,
+ 0x10d69, 0x10d69,
+ 0x10d6f, 0x10d85,
+ 0x10e80, 0x10ea9,
+ 0x10eab, 0x10eac,
+ 0x10eb0, 0x10eb1,
+ 0x10ec2, 0x10ec7,
+ 0x10efa, 0x10efc,
+ 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,
+ 0x11380, 0x11389,
+ 0x1138b, 0x1138b,
+ 0x1138e, 0x1138e,
+ 0x11390, 0x113b5,
+ 0x113b7, 0x113c0,
+ 0x113c2, 0x113c2,
+ 0x113c5, 0x113c5,
+ 0x113c7, 0x113ca,
+ 0x113cc, 0x113cd,
+ 0x113d1, 0x113d1,
+ 0x113d3, 0x113d3,
+ 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,
+ 0x11b60, 0x11b67,
+ 0x11bc0, 0x11be0,
+ 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,
+ 0x11db0, 0x11ddb,
+ 0x11ee0, 0x11ef6,
+ 0x11f00, 0x11f10,
+ 0x11f12, 0x11f3a,
+ 0x11f3e, 0x11f40,
+ 0x11fb0, 0x11fb0,
+ 0x12000, 0x12399,
+ 0x12400, 0x1246e,
+ 0x12480, 0x12543,
+ 0x12f90, 0x12ff0,
+ 0x13000, 0x1342f,
+ 0x13441, 0x13446,
+ 0x13460, 0x143fa,
+ 0x14400, 0x14646,
+ 0x16100, 0x1612e,
+ 0x16800, 0x16a38,
+ 0x16a40, 0x16a5e,
+ 0x16a70, 0x16abe,
+ 0x16ad0, 0x16aed,
+ 0x16b00, 0x16b2f,
+ 0x16b40, 0x16b43,
+ 0x16b63, 0x16b77,
+ 0x16b7d, 0x16b8f,
+ 0x16d40, 0x16d6c,
+ 0x16e40, 0x16e7f,
+ 0x16ea0, 0x16eb8,
+ 0x16ebb, 0x16ed3,
+ 0x16f00, 0x16f4a,
+ 0x16f4f, 0x16f87,
+ 0x16f8f, 0x16f9f,
+ 0x16fe0, 0x16fe1,
+ 0x16fe3, 0x16fe3,
+ 0x16ff0, 0x16ff6,
+ 0x17000, 0x18cd5,
+ 0x18cff, 0x18d1e,
+ 0x18d80, 0x18df2,
+ 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,
+ 0x1e5d0, 0x1e5ed,
+ 0x1e5f0, 0x1e5f0,
+ 0x1e6c0, 0x1e6de,
+ 0x1e6e0, 0x1e6f5,
+ 0x1e6fe, 0x1e6ff,
+ 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, 0x2b81d,
+ 0x2b820, 0x2cead,
+ 0x2ceb0, 0x2ebe0,
+ 0x2ebf0, 0x2ee5d,
+ 0x2f800, 0x2fa1d,
+ 0x30000, 0x3134a,
+ 0x31350, 0x33479,
+}; /* CR_Alpha */
+
+/* 'Blank': [[:Blank:]] */
+static const OnigCodePoint CR_Blank[] = {
+ 8,
+ 0x0009, 0x0009,
+ 0x0020, 0x0020,
+ 0x00a0, 0x00a0,
+ 0x1680, 0x1680,
+ 0x2000, 0x200a,
+ 0x202f, 0x202f,
+ 0x205f, 0x205f,
+ 0x3000, 0x3000,
+}; /* CR_Blank */
+
+/* 'Cntrl': [[:Cntrl:]] */
+static const OnigCodePoint CR_Cntrl[] = {
+ 2,
+ 0x0000, 0x001f,
+ 0x007f, 0x009f,
+}; /* CR_Cntrl */
+
+/* 'Digit': [[:Digit:]] */
+static const OnigCodePoint CR_Digit[] = {
+ 72,
+ 0x0030, 0x0039,
+ 0x0660, 0x0669,
+ 0x06f0, 0x06f9,
+ 0x07c0, 0x07c9,
+ 0x0966, 0x096f,
+ 0x09e6, 0x09ef,
+ 0x0a66, 0x0a6f,
+ 0x0ae6, 0x0aef,
+ 0x0b66, 0x0b6f,
+ 0x0be6, 0x0bef,
+ 0x0c66, 0x0c6f,
+ 0x0ce6, 0x0cef,
+ 0x0d66, 0x0d6f,
+ 0x0de6, 0x0def,
+ 0x0e50, 0x0e59,
+ 0x0ed0, 0x0ed9,
+ 0x0f20, 0x0f29,
+ 0x1040, 0x1049,
+ 0x1090, 0x1099,
+ 0x17e0, 0x17e9,
+ 0x1810, 0x1819,
+ 0x1946, 0x194f,
+ 0x19d0, 0x19d9,
+ 0x1a80, 0x1a89,
+ 0x1a90, 0x1a99,
+ 0x1b50, 0x1b59,
+ 0x1bb0, 0x1bb9,
+ 0x1c40, 0x1c49,
+ 0x1c50, 0x1c59,
+ 0xa620, 0xa629,
+ 0xa8d0, 0xa8d9,
+ 0xa900, 0xa909,
+ 0xa9d0, 0xa9d9,
+ 0xa9f0, 0xa9f9,
+ 0xaa50, 0xaa59,
+ 0xabf0, 0xabf9,
+ 0xff10, 0xff19,
+ 0x104a0, 0x104a9,
+ 0x10d30, 0x10d39,
+ 0x10d40, 0x10d49,
+ 0x11066, 0x1106f,
+ 0x110f0, 0x110f9,
+ 0x11136, 0x1113f,
+ 0x111d0, 0x111d9,
+ 0x112f0, 0x112f9,
+ 0x11450, 0x11459,
+ 0x114d0, 0x114d9,
+ 0x11650, 0x11659,
+ 0x116c0, 0x116c9,
+ 0x116d0, 0x116e3,
+ 0x11730, 0x11739,
+ 0x118e0, 0x118e9,
+ 0x11950, 0x11959,
+ 0x11bf0, 0x11bf9,
+ 0x11c50, 0x11c59,
+ 0x11d50, 0x11d59,
+ 0x11da0, 0x11da9,
+ 0x11de0, 0x11de9,
+ 0x11f50, 0x11f59,
+ 0x16130, 0x16139,
+ 0x16a60, 0x16a69,
+ 0x16ac0, 0x16ac9,
+ 0x16b50, 0x16b59,
+ 0x16d70, 0x16d79,
+ 0x1ccf0, 0x1ccf9,
+ 0x1d7ce, 0x1d7ff,
+ 0x1e140, 0x1e149,
+ 0x1e2f0, 0x1e2f9,
+ 0x1e4f0, 0x1e4f9,
+ 0x1e5f1, 0x1e5fa,
+ 0x1e950, 0x1e959,
+ 0x1fbf0, 0x1fbf9,
+}; /* CR_Digit */
+
+/* 'Graph': [[:Graph:]] */
+static const OnigCodePoint CR_Graph[] = {
+ 741,
+ 0x0021, 0x007e,
+ 0x00a1, 0x0377,
+ 0x037a, 0x037f,
+ 0x0384, 0x038a,
+ 0x038c, 0x038c,
+ 0x038e, 0x03a1,
+ 0x03a3, 0x052f,
+ 0x0531, 0x0556,
+ 0x0559, 0x058a,
+ 0x058d, 0x058f,
+ 0x0591, 0x05c7,
+ 0x05d0, 0x05ea,
+ 0x05ef, 0x05f4,
+ 0x0600, 0x070d,
+ 0x070f, 0x074a,
+ 0x074d, 0x07b1,
+ 0x07c0, 0x07fa,
+ 0x07fd, 0x082d,
+ 0x0830, 0x083e,
+ 0x0840, 0x085b,
+ 0x085e, 0x085e,
+ 0x0860, 0x086a,
+ 0x0870, 0x0891,
+ 0x0897, 0x0983,
+ 0x0985, 0x098c,
+ 0x098f, 0x0990,
+ 0x0993, 0x09a8,
+ 0x09aa, 0x09b0,
+ 0x09b2, 0x09b2,
+ 0x09b6, 0x09b9,
+ 0x09bc, 0x09c4,
+ 0x09c7, 0x09c8,
+ 0x09cb, 0x09ce,
+ 0x09d7, 0x09d7,
+ 0x09dc, 0x09dd,
+ 0x09df, 0x09e3,
+ 0x09e6, 0x09fe,
+ 0x0a01, 0x0a03,
+ 0x0a05, 0x0a0a,
+ 0x0a0f, 0x0a10,
+ 0x0a13, 0x0a28,
+ 0x0a2a, 0x0a30,
+ 0x0a32, 0x0a33,
+ 0x0a35, 0x0a36,
+ 0x0a38, 0x0a39,
+ 0x0a3c, 0x0a3c,
+ 0x0a3e, 0x0a42,
+ 0x0a47, 0x0a48,
+ 0x0a4b, 0x0a4d,
+ 0x0a51, 0x0a51,
+ 0x0a59, 0x0a5c,
+ 0x0a5e, 0x0a5e,
+ 0x0a66, 0x0a76,
+ 0x0a81, 0x0a83,
+ 0x0a85, 0x0a8d,
+ 0x0a8f, 0x0a91,
+ 0x0a93, 0x0aa8,
+ 0x0aaa, 0x0ab0,
+ 0x0ab2, 0x0ab3,
+ 0x0ab5, 0x0ab9,
+ 0x0abc, 0x0ac5,
+ 0x0ac7, 0x0ac9,
+ 0x0acb, 0x0acd,
+ 0x0ad0, 0x0ad0,
+ 0x0ae0, 0x0ae3,
+ 0x0ae6, 0x0af1,
+ 0x0af9, 0x0aff,
+ 0x0b01, 0x0b03,
+ 0x0b05, 0x0b0c,
+ 0x0b0f, 0x0b10,
+ 0x0b13, 0x0b28,
+ 0x0b2a, 0x0b30,
+ 0x0b32, 0x0b33,
+ 0x0b35, 0x0b39,
+ 0x0b3c, 0x0b44,
+ 0x0b47, 0x0b48,
+ 0x0b4b, 0x0b4d,
+ 0x0b55, 0x0b57,
+ 0x0b5c, 0x0b5d,
+ 0x0b5f, 0x0b63,
+ 0x0b66, 0x0b77,
+ 0x0b82, 0x0b83,
+ 0x0b85, 0x0b8a,
+ 0x0b8e, 0x0b90,
+ 0x0b92, 0x0b95,
+ 0x0b99, 0x0b9a,
+ 0x0b9c, 0x0b9c,
+ 0x0b9e, 0x0b9f,
+ 0x0ba3, 0x0ba4,
+ 0x0ba8, 0x0baa,
+ 0x0bae, 0x0bb9,
+ 0x0bbe, 0x0bc2,
+ 0x0bc6, 0x0bc8,
+ 0x0bca, 0x0bcd,
+ 0x0bd0, 0x0bd0,
+ 0x0bd7, 0x0bd7,
+ 0x0be6, 0x0bfa,
+ 0x0c00, 0x0c0c,
+ 0x0c0e, 0x0c10,
+ 0x0c12, 0x0c28,
+ 0x0c2a, 0x0c39,
+ 0x0c3c, 0x0c44,
+ 0x0c46, 0x0c48,
+ 0x0c4a, 0x0c4d,
+ 0x0c55, 0x0c56,
+ 0x0c58, 0x0c5a,
+ 0x0c5c, 0x0c5d,
+ 0x0c60, 0x0c63,
+ 0x0c66, 0x0c6f,
+ 0x0c77, 0x0c8c,
+ 0x0c8e, 0x0c90,
+ 0x0c92, 0x0ca8,
+ 0x0caa, 0x0cb3,
+ 0x0cb5, 0x0cb9,
+ 0x0cbc, 0x0cc4,
+ 0x0cc6, 0x0cc8,
+ 0x0cca, 0x0ccd,
+ 0x0cd5, 0x0cd6,
+ 0x0cdc, 0x0cde,
+ 0x0ce0, 0x0ce3,
+ 0x0ce6, 0x0cef,
+ 0x0cf1, 0x0cf3,
+ 0x0d00, 0x0d0c,
+ 0x0d0e, 0x0d10,
+ 0x0d12, 0x0d44,
+ 0x0d46, 0x0d48,
+ 0x0d4a, 0x0d4f,
+ 0x0d54, 0x0d63,
+ 0x0d66, 0x0d7f,
+ 0x0d81, 0x0d83,
+ 0x0d85, 0x0d96,
+ 0x0d9a, 0x0db1,
+ 0x0db3, 0x0dbb,
+ 0x0dbd, 0x0dbd,
+ 0x0dc0, 0x0dc6,
+ 0x0dca, 0x0dca,
+ 0x0dcf, 0x0dd4,
+ 0x0dd6, 0x0dd6,
+ 0x0dd8, 0x0ddf,
+ 0x0de6, 0x0def,
+ 0x0df2, 0x0df4,
+ 0x0e01, 0x0e3a,
+ 0x0e3f, 0x0e5b,
+ 0x0e81, 0x0e82,
+ 0x0e84, 0x0e84,
+ 0x0e86, 0x0e8a,
+ 0x0e8c, 0x0ea3,
+ 0x0ea5, 0x0ea5,
+ 0x0ea7, 0x0ebd,
+ 0x0ec0, 0x0ec4,
+ 0x0ec6, 0x0ec6,
+ 0x0ec8, 0x0ece,
+ 0x0ed0, 0x0ed9,
+ 0x0edc, 0x0edf,
+ 0x0f00, 0x0f47,
+ 0x0f49, 0x0f6c,
+ 0x0f71, 0x0f97,
+ 0x0f99, 0x0fbc,
+ 0x0fbe, 0x0fcc,
+ 0x0fce, 0x0fda,
+ 0x1000, 0x10c5,
+ 0x10c7, 0x10c7,
+ 0x10cd, 0x10cd,
+ 0x10d0, 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,
+ 0x135d, 0x137c,
+ 0x1380, 0x1399,
+ 0x13a0, 0x13f5,
+ 0x13f8, 0x13fd,
+ 0x1400, 0x167f,
+ 0x1681, 0x169c,
+ 0x16a0, 0x16f8,
+ 0x1700, 0x1715,
+ 0x171f, 0x1736,
+ 0x1740, 0x1753,
+ 0x1760, 0x176c,
+ 0x176e, 0x1770,
+ 0x1772, 0x1773,
+ 0x1780, 0x17dd,
+ 0x17e0, 0x17e9,
+ 0x17f0, 0x17f9,
+ 0x1800, 0x1819,
+ 0x1820, 0x1878,
+ 0x1880, 0x18aa,
+ 0x18b0, 0x18f5,
+ 0x1900, 0x191e,
+ 0x1920, 0x192b,
+ 0x1930, 0x193b,
+ 0x1940, 0x1940,
+ 0x1944, 0x196d,
+ 0x1970, 0x1974,
+ 0x1980, 0x19ab,
+ 0x19b0, 0x19c9,
+ 0x19d0, 0x19da,
+ 0x19de, 0x1a1b,
+ 0x1a1e, 0x1a5e,
+ 0x1a60, 0x1a7c,
+ 0x1a7f, 0x1a89,
+ 0x1a90, 0x1a99,
+ 0x1aa0, 0x1aad,
+ 0x1ab0, 0x1add,
+ 0x1ae0, 0x1aeb,
+ 0x1b00, 0x1b4c,
+ 0x1b4e, 0x1bf3,
+ 0x1bfc, 0x1c37,
+ 0x1c3b, 0x1c49,
+ 0x1c4d, 0x1c8a,
+ 0x1c90, 0x1cba,
+ 0x1cbd, 0x1cc7,
+ 0x1cd0, 0x1cfa,
+ 0x1d00, 0x1f15,
+ 0x1f18, 0x1f1d,
+ 0x1f20, 0x1f45,
+ 0x1f48, 0x1f4d,
+ 0x1f50, 0x1f57,
+ 0x1f59, 0x1f59,
+ 0x1f5b, 0x1f5b,
+ 0x1f5d, 0x1f5d,
+ 0x1f5f, 0x1f7d,
+ 0x1f80, 0x1fb4,
+ 0x1fb6, 0x1fc4,
+ 0x1fc6, 0x1fd3,
+ 0x1fd6, 0x1fdb,
+ 0x1fdd, 0x1fef,
+ 0x1ff2, 0x1ff4,
+ 0x1ff6, 0x1ffe,
+ 0x200b, 0x2027,
+ 0x202a, 0x202e,
+ 0x2030, 0x205e,
+ 0x2060, 0x2064,
+ 0x2066, 0x2071,
+ 0x2074, 0x208e,
+ 0x2090, 0x209c,
+ 0x20a0, 0x20c1,
+ 0x20d0, 0x20f0,
+ 0x2100, 0x218b,
+ 0x2190, 0x2429,
+ 0x2440, 0x244a,
+ 0x2460, 0x2b73,
+ 0x2b76, 0x2cf3,
+ 0x2cf9, 0x2d25,
+ 0x2d27, 0x2d27,
+ 0x2d2d, 0x2d2d,
+ 0x2d30, 0x2d67,
+ 0x2d6f, 0x2d70,
+ 0x2d7f, 0x2d96,
+ 0x2da0, 0x2da6,
+ 0x2da8, 0x2dae,
+ 0x2db0, 0x2db6,
+ 0x2db8, 0x2dbe,
+ 0x2dc0, 0x2dc6,
+ 0x2dc8, 0x2dce,
+ 0x2dd0, 0x2dd6,
+ 0x2dd8, 0x2dde,
+ 0x2de0, 0x2e5d,
+ 0x2e80, 0x2e99,
+ 0x2e9b, 0x2ef3,
+ 0x2f00, 0x2fd5,
+ 0x2ff0, 0x2fff,
+ 0x3001, 0x303f,
+ 0x3041, 0x3096,
+ 0x3099, 0x30ff,
+ 0x3105, 0x312f,
+ 0x3131, 0x318e,
+ 0x3190, 0x31e5,
+ 0x31ef, 0x321e,
+ 0x3220, 0xa48c,
+ 0xa490, 0xa4c6,
+ 0xa4d0, 0xa62b,
+ 0xa640, 0xa6f7,
+ 0xa700, 0xa7dc,
+ 0xa7f1, 0xa82c,
+ 0xa830, 0xa839,
+ 0xa840, 0xa877,
+ 0xa880, 0xa8c5,
+ 0xa8ce, 0xa8d9,
+ 0xa8e0, 0xa953,
+ 0xa95f, 0xa97c,
+ 0xa980, 0xa9cd,
+ 0xa9cf, 0xa9d9,
+ 0xa9de, 0xa9fe,
+ 0xaa00, 0xaa36,
+ 0xaa40, 0xaa4d,
+ 0xaa50, 0xaa59,
+ 0xaa5c, 0xaac2,
+ 0xaadb, 0xaaf6,
+ 0xab01, 0xab06,
+ 0xab09, 0xab0e,
+ 0xab11, 0xab16,
+ 0xab20, 0xab26,
+ 0xab28, 0xab2e,
+ 0xab30, 0xab6b,
+ 0xab70, 0xabed,
+ 0xabf0, 0xabf9,
+ 0xac00, 0xd7a3,
+ 0xd7b0, 0xd7c6,
+ 0xd7cb, 0xd7fb,
+ 0xe000, 0xfa6d,
+ 0xfa70, 0xfad9,
+ 0xfb00, 0xfb06,
+ 0xfb13, 0xfb17,
+ 0xfb1d, 0xfb36,
+ 0xfb38, 0xfb3c,
+ 0xfb3e, 0xfb3e,
+ 0xfb40, 0xfb41,
+ 0xfb43, 0xfb44,
+ 0xfb46, 0xfdcf,
+ 0xfdf0, 0xfe19,
+ 0xfe20, 0xfe52,
+ 0xfe54, 0xfe66,
+ 0xfe68, 0xfe6b,
+ 0xfe70, 0xfe74,
+ 0xfe76, 0xfefc,
+ 0xfeff, 0xfeff,
+ 0xff01, 0xffbe,
+ 0xffc2, 0xffc7,
+ 0xffca, 0xffcf,
+ 0xffd2, 0xffd7,
+ 0xffda, 0xffdc,
+ 0xffe0, 0xffe6,
+ 0xffe8, 0xffee,
+ 0xfff9, 0xfffd,
+ 0x10000, 0x1000b,
+ 0x1000d, 0x10026,
+ 0x10028, 0x1003a,
+ 0x1003c, 0x1003d,
+ 0x1003f, 0x1004d,
+ 0x10050, 0x1005d,
+ 0x10080, 0x100fa,
+ 0x10100, 0x10102,
+ 0x10107, 0x10133,
+ 0x10137, 0x1018e,
+ 0x10190, 0x1019c,
+ 0x101a0, 0x101a0,
+ 0x101d0, 0x101fd,
+ 0x10280, 0x1029c,
+ 0x102a0, 0x102d0,
+ 0x102e0, 0x102fb,
+ 0x10300, 0x10323,
+ 0x1032d, 0x1034a,
+ 0x10350, 0x1037a,
+ 0x10380, 0x1039d,
+ 0x1039f, 0x103c3,
+ 0x103c8, 0x103d5,
+ 0x10400, 0x1049d,
+ 0x104a0, 0x104a9,
+ 0x104b0, 0x104d3,
+ 0x104d8, 0x104fb,
+ 0x10500, 0x10527,
+ 0x10530, 0x10563,
+ 0x1056f, 0x1057a,
+ 0x1057c, 0x1058a,
+ 0x1058c, 0x10592,
+ 0x10594, 0x10595,
+ 0x10597, 0x105a1,
+ 0x105a3, 0x105b1,
+ 0x105b3, 0x105b9,
+ 0x105bb, 0x105bc,
+ 0x105c0, 0x105f3,
+ 0x10600, 0x10736,
+ 0x10740, 0x10755,
+ 0x10760, 0x10767,
+ 0x10780, 0x10785,
+ 0x10787, 0x107b0,
+ 0x107b2, 0x107ba,
+ 0x10800, 0x10805,
+ 0x10808, 0x10808,
+ 0x1080a, 0x10835,
+ 0x10837, 0x10838,
+ 0x1083c, 0x1083c,
+ 0x1083f, 0x10855,
+ 0x10857, 0x1089e,
+ 0x108a7, 0x108af,
+ 0x108e0, 0x108f2,
+ 0x108f4, 0x108f5,
+ 0x108fb, 0x1091b,
+ 0x1091f, 0x10939,
+ 0x1093f, 0x10959,
+ 0x10980, 0x109b7,
+ 0x109bc, 0x109cf,
+ 0x109d2, 0x10a03,
+ 0x10a05, 0x10a06,
+ 0x10a0c, 0x10a13,
+ 0x10a15, 0x10a17,
+ 0x10a19, 0x10a35,
+ 0x10a38, 0x10a3a,
+ 0x10a3f, 0x10a48,
+ 0x10a50, 0x10a58,
+ 0x10a60, 0x10a9f,
+ 0x10ac0, 0x10ae6,
+ 0x10aeb, 0x10af6,
+ 0x10b00, 0x10b35,
+ 0x10b39, 0x10b55,
+ 0x10b58, 0x10b72,
+ 0x10b78, 0x10b91,
+ 0x10b99, 0x10b9c,
+ 0x10ba9, 0x10baf,
+ 0x10c00, 0x10c48,
+ 0x10c80, 0x10cb2,
+ 0x10cc0, 0x10cf2,
+ 0x10cfa, 0x10d27,
+ 0x10d30, 0x10d39,
+ 0x10d40, 0x10d65,
+ 0x10d69, 0x10d85,
+ 0x10d8e, 0x10d8f,
+ 0x10e60, 0x10e7e,
+ 0x10e80, 0x10ea9,
+ 0x10eab, 0x10ead,
+ 0x10eb0, 0x10eb1,
+ 0x10ec2, 0x10ec7,
+ 0x10ed0, 0x10ed8,
+ 0x10efa, 0x10f27,
+ 0x10f30, 0x10f59,
+ 0x10f70, 0x10f89,
+ 0x10fb0, 0x10fcb,
+ 0x10fe0, 0x10ff6,
+ 0x11000, 0x1104d,
+ 0x11052, 0x11075,
+ 0x1107f, 0x110c2,
+ 0x110cd, 0x110cd,
+ 0x110d0, 0x110e8,
+ 0x110f0, 0x110f9,
+ 0x11100, 0x11134,
+ 0x11136, 0x11147,
+ 0x11150, 0x11176,
+ 0x11180, 0x111df,
+ 0x111e1, 0x111f4,
+ 0x11200, 0x11211,
+ 0x11213, 0x11241,
+ 0x11280, 0x11286,
+ 0x11288, 0x11288,
+ 0x1128a, 0x1128d,
+ 0x1128f, 0x1129d,
+ 0x1129f, 0x112a9,
+ 0x112b0, 0x112ea,
+ 0x112f0, 0x112f9,
+ 0x11300, 0x11303,
+ 0x11305, 0x1130c,
+ 0x1130f, 0x11310,
+ 0x11313, 0x11328,
+ 0x1132a, 0x11330,
+ 0x11332, 0x11333,
+ 0x11335, 0x11339,
+ 0x1133b, 0x11344,
+ 0x11347, 0x11348,
+ 0x1134b, 0x1134d,
+ 0x11350, 0x11350,
+ 0x11357, 0x11357,
+ 0x1135d, 0x11363,
+ 0x11366, 0x1136c,
+ 0x11370, 0x11374,
+ 0x11380, 0x11389,
+ 0x1138b, 0x1138b,
+ 0x1138e, 0x1138e,
+ 0x11390, 0x113b5,
+ 0x113b7, 0x113c0,
+ 0x113c2, 0x113c2,
+ 0x113c5, 0x113c5,
+ 0x113c7, 0x113ca,
+ 0x113cc, 0x113d5,
+ 0x113d7, 0x113d8,
+ 0x113e1, 0x113e2,
+ 0x11400, 0x1145b,
+ 0x1145d, 0x11461,
+ 0x11480, 0x114c7,
+ 0x114d0, 0x114d9,
+ 0x11580, 0x115b5,
+ 0x115b8, 0x115dd,
+ 0x11600, 0x11644,
+ 0x11650, 0x11659,
+ 0x11660, 0x1166c,
+ 0x11680, 0x116b9,
+ 0x116c0, 0x116c9,
+ 0x116d0, 0x116e3,
+ 0x11700, 0x1171a,
+ 0x1171d, 0x1172b,
+ 0x11730, 0x11746,
+ 0x11800, 0x1183b,
+ 0x118a0, 0x118f2,
+ 0x118ff, 0x11906,
+ 0x11909, 0x11909,
+ 0x1190c, 0x11913,
+ 0x11915, 0x11916,
+ 0x11918, 0x11935,
+ 0x11937, 0x11938,
+ 0x1193b, 0x11946,
+ 0x11950, 0x11959,
+ 0x119a0, 0x119a7,
+ 0x119aa, 0x119d7,
+ 0x119da, 0x119e4,
+ 0x11a00, 0x11a47,
+ 0x11a50, 0x11aa2,
+ 0x11ab0, 0x11af8,
+ 0x11b00, 0x11b09,
+ 0x11b60, 0x11b67,
+ 0x11bc0, 0x11be1,
+ 0x11bf0, 0x11bf9,
+ 0x11c00, 0x11c08,
+ 0x11c0a, 0x11c36,
+ 0x11c38, 0x11c45,
+ 0x11c50, 0x11c6c,
+ 0x11c70, 0x11c8f,
+ 0x11c92, 0x11ca7,
+ 0x11ca9, 0x11cb6,
+ 0x11d00, 0x11d06,
+ 0x11d08, 0x11d09,
+ 0x11d0b, 0x11d36,
+ 0x11d3a, 0x11d3a,
+ 0x11d3c, 0x11d3d,
+ 0x11d3f, 0x11d47,
+ 0x11d50, 0x11d59,
+ 0x11d60, 0x11d65,
+ 0x11d67, 0x11d68,
+ 0x11d6a, 0x11d8e,
+ 0x11d90, 0x11d91,
+ 0x11d93, 0x11d98,
+ 0x11da0, 0x11da9,
+ 0x11db0, 0x11ddb,
+ 0x11de0, 0x11de9,
+ 0x11ee0, 0x11ef8,
+ 0x11f00, 0x11f10,
+ 0x11f12, 0x11f3a,
+ 0x11f3e, 0x11f5a,
+ 0x11fb0, 0x11fb0,
+ 0x11fc0, 0x11ff1,
+ 0x11fff, 0x12399,
+ 0x12400, 0x1246e,
+ 0x12470, 0x12474,
+ 0x12480, 0x12543,
+ 0x12f90, 0x12ff2,
+ 0x13000, 0x13455,
+ 0x13460, 0x143fa,
+ 0x14400, 0x14646,
+ 0x16100, 0x16139,
+ 0x16800, 0x16a38,
+ 0x16a40, 0x16a5e,
+ 0x16a60, 0x16a69,
+ 0x16a6e, 0x16abe,
+ 0x16ac0, 0x16ac9,
+ 0x16ad0, 0x16aed,
+ 0x16af0, 0x16af5,
+ 0x16b00, 0x16b45,
+ 0x16b50, 0x16b59,
+ 0x16b5b, 0x16b61,
+ 0x16b63, 0x16b77,
+ 0x16b7d, 0x16b8f,
+ 0x16d40, 0x16d79,
+ 0x16e40, 0x16e9a,
+ 0x16ea0, 0x16eb8,
+ 0x16ebb, 0x16ed3,
+ 0x16f00, 0x16f4a,
+ 0x16f4f, 0x16f87,
+ 0x16f8f, 0x16f9f,
+ 0x16fe0, 0x16fe4,
+ 0x16ff0, 0x16ff6,
+ 0x17000, 0x18cd5,
+ 0x18cff, 0x18d1e,
+ 0x18d80, 0x18df2,
+ 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,
+ 0x1bc9c, 0x1bca3,
+ 0x1cc00, 0x1ccfc,
+ 0x1cd00, 0x1ceb3,
+ 0x1ceba, 0x1ced0,
+ 0x1cee0, 0x1cef0,
+ 0x1cf00, 0x1cf2d,
+ 0x1cf30, 0x1cf46,
+ 0x1cf50, 0x1cfc3,
+ 0x1d000, 0x1d0f5,
+ 0x1d100, 0x1d126,
+ 0x1d129, 0x1d1ea,
+ 0x1d200, 0x1d245,
+ 0x1d2c0, 0x1d2d3,
+ 0x1d2e0, 0x1d2f3,
+ 0x1d300, 0x1d356,
+ 0x1d360, 0x1d378,
+ 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, 0x1d7cb,
+ 0x1d7ce, 0x1da8b,
+ 0x1da9b, 0x1da9f,
+ 0x1daa1, 0x1daaf,
+ 0x1df00, 0x1df1e,
+ 0x1df25, 0x1df2a,
+ 0x1e000, 0x1e006,
+ 0x1e008, 0x1e018,
+ 0x1e01b, 0x1e021,
+ 0x1e023, 0x1e024,
+ 0x1e026, 0x1e02a,
+ 0x1e030, 0x1e06d,
+ 0x1e08f, 0x1e08f,
+ 0x1e100, 0x1e12c,
+ 0x1e130, 0x1e13d,
+ 0x1e140, 0x1e149,
+ 0x1e14e, 0x1e14f,
+ 0x1e290, 0x1e2ae,
+ 0x1e2c0, 0x1e2f9,
+ 0x1e2ff, 0x1e2ff,
+ 0x1e4d0, 0x1e4f9,
+ 0x1e5d0, 0x1e5fa,
+ 0x1e5ff, 0x1e5ff,
+ 0x1e6c0, 0x1e6de,
+ 0x1e6e0, 0x1e6f5,
+ 0x1e6fe, 0x1e6ff,
+ 0x1e7e0, 0x1e7e6,
+ 0x1e7e8, 0x1e7eb,
+ 0x1e7ed, 0x1e7ee,
+ 0x1e7f0, 0x1e7fe,
+ 0x1e800, 0x1e8c4,
+ 0x1e8c7, 0x1e8d6,
+ 0x1e900, 0x1e94b,
+ 0x1e950, 0x1e959,
+ 0x1e95e, 0x1e95f,
+ 0x1ec71, 0x1ecb4,
+ 0x1ed01, 0x1ed3d,
+ 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,
+ 0x1eef0, 0x1eef1,
+ 0x1f000, 0x1f02b,
+ 0x1f030, 0x1f093,
+ 0x1f0a0, 0x1f0ae,
+ 0x1f0b1, 0x1f0bf,
+ 0x1f0c1, 0x1f0cf,
+ 0x1f0d1, 0x1f0f5,
+ 0x1f100, 0x1f1ad,
+ 0x1f1e6, 0x1f202,
+ 0x1f210, 0x1f23b,
+ 0x1f240, 0x1f248,
+ 0x1f250, 0x1f251,
+ 0x1f260, 0x1f265,
+ 0x1f300, 0x1f6d8,
+ 0x1f6dc, 0x1f6ec,
+ 0x1f6f0, 0x1f6fc,
+ 0x1f700, 0x1f7d9,
+ 0x1f7e0, 0x1f7eb,
+ 0x1f7f0, 0x1f7f0,
+ 0x1f800, 0x1f80b,
+ 0x1f810, 0x1f847,
+ 0x1f850, 0x1f859,
+ 0x1f860, 0x1f887,
+ 0x1f890, 0x1f8ad,
+ 0x1f8b0, 0x1f8bb,
+ 0x1f8c0, 0x1f8c1,
+ 0x1f8d0, 0x1f8d8,
+ 0x1f900, 0x1fa57,
+ 0x1fa60, 0x1fa6d,
+ 0x1fa70, 0x1fa7c,
+ 0x1fa80, 0x1fa8a,
+ 0x1fa8e, 0x1fac6,
+ 0x1fac8, 0x1fac8,
+ 0x1facd, 0x1fadc,
+ 0x1fadf, 0x1faea,
+ 0x1faef, 0x1faf8,
+ 0x1fb00, 0x1fb92,
+ 0x1fb94, 0x1fbfa,
+ 0x20000, 0x2a6df,
+ 0x2a700, 0x2b81d,
+ 0x2b820, 0x2cead,
+ 0x2ceb0, 0x2ebe0,
+ 0x2ebf0, 0x2ee5d,
+ 0x2f800, 0x2fa1d,
+ 0x30000, 0x3134a,
+ 0x31350, 0x33479,
+ 0xe0001, 0xe0001,
+ 0xe0020, 0xe007f,
+ 0xe0100, 0xe01ef,
+ 0xf0000, 0xffffd,
+ 0x100000, 0x10fffd,
+}; /* CR_Graph */
+
+/* 'Lower': [[:Lower:]] */
+static const OnigCodePoint CR_Lower[] = {
+ 677,
+ 0x0061, 0x007a,
+ 0x00aa, 0x00aa,
+ 0x00b5, 0x00b5,
+ 0x00ba, 0x00ba,
+ 0x00df, 0x00f6,
+ 0x00f8, 0x00ff,
+ 0x0101, 0x0101,
+ 0x0103, 0x0103,
+ 0x0105, 0x0105,
+ 0x0107, 0x0107,
+ 0x0109, 0x0109,
+ 0x010b, 0x010b,
+ 0x010d, 0x010d,
+ 0x010f, 0x010f,
+ 0x0111, 0x0111,
+ 0x0113, 0x0113,
+ 0x0115, 0x0115,
+ 0x0117, 0x0117,
+ 0x0119, 0x0119,
+ 0x011b, 0x011b,
+ 0x011d, 0x011d,
+ 0x011f, 0x011f,
+ 0x0121, 0x0121,
+ 0x0123, 0x0123,
+ 0x0125, 0x0125,
+ 0x0127, 0x0127,
+ 0x0129, 0x0129,
+ 0x012b, 0x012b,
+ 0x012d, 0x012d,
+ 0x012f, 0x012f,
+ 0x0131, 0x0131,
+ 0x0133, 0x0133,
+ 0x0135, 0x0135,
+ 0x0137, 0x0138,
+ 0x013a, 0x013a,
+ 0x013c, 0x013c,
+ 0x013e, 0x013e,
+ 0x0140, 0x0140,
+ 0x0142, 0x0142,
+ 0x0144, 0x0144,
+ 0x0146, 0x0146,
+ 0x0148, 0x0149,
+ 0x014b, 0x014b,
+ 0x014d, 0x014d,
+ 0x014f, 0x014f,
+ 0x0151, 0x0151,
+ 0x0153, 0x0153,
+ 0x0155, 0x0155,
+ 0x0157, 0x0157,
+ 0x0159, 0x0159,
+ 0x015b, 0x015b,
+ 0x015d, 0x015d,
+ 0x015f, 0x015f,
+ 0x0161, 0x0161,
+ 0x0163, 0x0163,
+ 0x0165, 0x0165,
+ 0x0167, 0x0167,
+ 0x0169, 0x0169,
+ 0x016b, 0x016b,
+ 0x016d, 0x016d,
+ 0x016f, 0x016f,
+ 0x0171, 0x0171,
+ 0x0173, 0x0173,
+ 0x0175, 0x0175,
+ 0x0177, 0x0177,
+ 0x017a, 0x017a,
+ 0x017c, 0x017c,
+ 0x017e, 0x0180,
+ 0x0183, 0x0183,
+ 0x0185, 0x0185,
+ 0x0188, 0x0188,
+ 0x018c, 0x018d,
+ 0x0192, 0x0192,
+ 0x0195, 0x0195,
+ 0x0199, 0x019b,
+ 0x019e, 0x019e,
+ 0x01a1, 0x01a1,
+ 0x01a3, 0x01a3,
+ 0x01a5, 0x01a5,
+ 0x01a8, 0x01a8,
+ 0x01aa, 0x01ab,
+ 0x01ad, 0x01ad,
+ 0x01b0, 0x01b0,
+ 0x01b4, 0x01b4,
+ 0x01b6, 0x01b6,
+ 0x01b9, 0x01ba,
+ 0x01bd, 0x01bf,
+ 0x01c6, 0x01c6,
+ 0x01c9, 0x01c9,
+ 0x01cc, 0x01cc,
+ 0x01ce, 0x01ce,
+ 0x01d0, 0x01d0,
+ 0x01d2, 0x01d2,
+ 0x01d4, 0x01d4,
+ 0x01d6, 0x01d6,
+ 0x01d8, 0x01d8,
+ 0x01da, 0x01da,
+ 0x01dc, 0x01dd,
+ 0x01df, 0x01df,
+ 0x01e1, 0x01e1,
+ 0x01e3, 0x01e3,
+ 0x01e5, 0x01e5,
+ 0x01e7, 0x01e7,
+ 0x01e9, 0x01e9,
+ 0x01eb, 0x01eb,
+ 0x01ed, 0x01ed,
+ 0x01ef, 0x01f0,
+ 0x01f3, 0x01f3,
+ 0x01f5, 0x01f5,
+ 0x01f9, 0x01f9,
+ 0x01fb, 0x01fb,
+ 0x01fd, 0x01fd,
+ 0x01ff, 0x01ff,
+ 0x0201, 0x0201,
+ 0x0203, 0x0203,
+ 0x0205, 0x0205,
+ 0x0207, 0x0207,
+ 0x0209, 0x0209,
+ 0x020b, 0x020b,
+ 0x020d, 0x020d,
+ 0x020f, 0x020f,
+ 0x0211, 0x0211,
+ 0x0213, 0x0213,
+ 0x0215, 0x0215,
+ 0x0217, 0x0217,
+ 0x0219, 0x0219,
+ 0x021b, 0x021b,
+ 0x021d, 0x021d,
+ 0x021f, 0x021f,
+ 0x0221, 0x0221,
+ 0x0223, 0x0223,
+ 0x0225, 0x0225,
+ 0x0227, 0x0227,
+ 0x0229, 0x0229,
+ 0x022b, 0x022b,
+ 0x022d, 0x022d,
+ 0x022f, 0x022f,
+ 0x0231, 0x0231,
+ 0x0233, 0x0239,
+ 0x023c, 0x023c,
+ 0x023f, 0x0240,
+ 0x0242, 0x0242,
+ 0x0247, 0x0247,
+ 0x0249, 0x0249,
+ 0x024b, 0x024b,
+ 0x024d, 0x024d,
+ 0x024f, 0x0293,
+ 0x0296, 0x02b8,
+ 0x02c0, 0x02c1,
+ 0x02e0, 0x02e4,
+ 0x0345, 0x0345,
+ 0x0371, 0x0371,
+ 0x0373, 0x0373,
+ 0x0377, 0x0377,
+ 0x037a, 0x037d,
+ 0x0390, 0x0390,
+ 0x03ac, 0x03ce,
+ 0x03d0, 0x03d1,
+ 0x03d5, 0x03d7,
+ 0x03d9, 0x03d9,
+ 0x03db, 0x03db,
+ 0x03dd, 0x03dd,
+ 0x03df, 0x03df,
+ 0x03e1, 0x03e1,
+ 0x03e3, 0x03e3,
+ 0x03e5, 0x03e5,
+ 0x03e7, 0x03e7,
+ 0x03e9, 0x03e9,
+ 0x03eb, 0x03eb,
+ 0x03ed, 0x03ed,
+ 0x03ef, 0x03f3,
+ 0x03f5, 0x03f5,
+ 0x03f8, 0x03f8,
+ 0x03fb, 0x03fc,
+ 0x0430, 0x045f,
+ 0x0461, 0x0461,
+ 0x0463, 0x0463,
+ 0x0465, 0x0465,
+ 0x0467, 0x0467,
+ 0x0469, 0x0469,
+ 0x046b, 0x046b,
+ 0x046d, 0x046d,
+ 0x046f, 0x046f,
+ 0x0471, 0x0471,
+ 0x0473, 0x0473,
+ 0x0475, 0x0475,
+ 0x0477, 0x0477,
+ 0x0479, 0x0479,
+ 0x047b, 0x047b,
+ 0x047d, 0x047d,
+ 0x047f, 0x047f,
+ 0x0481, 0x0481,
+ 0x048b, 0x048b,
+ 0x048d, 0x048d,
+ 0x048f, 0x048f,
+ 0x0491, 0x0491,
+ 0x0493, 0x0493,
+ 0x0495, 0x0495,
+ 0x0497, 0x0497,
+ 0x0499, 0x0499,
+ 0x049b, 0x049b,
+ 0x049d, 0x049d,
+ 0x049f, 0x049f,
+ 0x04a1, 0x04a1,
+ 0x04a3, 0x04a3,
+ 0x04a5, 0x04a5,
+ 0x04a7, 0x04a7,
+ 0x04a9, 0x04a9,
+ 0x04ab, 0x04ab,
+ 0x04ad, 0x04ad,
+ 0x04af, 0x04af,
+ 0x04b1, 0x04b1,
+ 0x04b3, 0x04b3,
+ 0x04b5, 0x04b5,
+ 0x04b7, 0x04b7,
+ 0x04b9, 0x04b9,
+ 0x04bb, 0x04bb,
+ 0x04bd, 0x04bd,
+ 0x04bf, 0x04bf,
+ 0x04c2, 0x04c2,
+ 0x04c4, 0x04c4,
+ 0x04c6, 0x04c6,
+ 0x04c8, 0x04c8,
+ 0x04ca, 0x04ca,
+ 0x04cc, 0x04cc,
+ 0x04ce, 0x04cf,
+ 0x04d1, 0x04d1,
+ 0x04d3, 0x04d3,
+ 0x04d5, 0x04d5,
+ 0x04d7, 0x04d7,
+ 0x04d9, 0x04d9,
+ 0x04db, 0x04db,
+ 0x04dd, 0x04dd,
+ 0x04df, 0x04df,
+ 0x04e1, 0x04e1,
+ 0x04e3, 0x04e3,
+ 0x04e5, 0x04e5,
+ 0x04e7, 0x04e7,
+ 0x04e9, 0x04e9,
+ 0x04eb, 0x04eb,
+ 0x04ed, 0x04ed,
+ 0x04ef, 0x04ef,
+ 0x04f1, 0x04f1,
+ 0x04f3, 0x04f3,
+ 0x04f5, 0x04f5,
+ 0x04f7, 0x04f7,
+ 0x04f9, 0x04f9,
+ 0x04fb, 0x04fb,
+ 0x04fd, 0x04fd,
+ 0x04ff, 0x04ff,
+ 0x0501, 0x0501,
+ 0x0503, 0x0503,
+ 0x0505, 0x0505,
+ 0x0507, 0x0507,
+ 0x0509, 0x0509,
+ 0x050b, 0x050b,
+ 0x050d, 0x050d,
+ 0x050f, 0x050f,
+ 0x0511, 0x0511,
+ 0x0513, 0x0513,
+ 0x0515, 0x0515,
+ 0x0517, 0x0517,
+ 0x0519, 0x0519,
+ 0x051b, 0x051b,
+ 0x051d, 0x051d,
+ 0x051f, 0x051f,
+ 0x0521, 0x0521,
+ 0x0523, 0x0523,
+ 0x0525, 0x0525,
+ 0x0527, 0x0527,
+ 0x0529, 0x0529,
+ 0x052b, 0x052b,
+ 0x052d, 0x052d,
+ 0x052f, 0x052f,
+ 0x0560, 0x0588,
+ 0x10d0, 0x10fa,
+ 0x10fc, 0x10ff,
+ 0x13f8, 0x13fd,
+ 0x1c80, 0x1c88,
+ 0x1c8a, 0x1c8a,
+ 0x1d00, 0x1dbf,
+ 0x1e01, 0x1e01,
+ 0x1e03, 0x1e03,
+ 0x1e05, 0x1e05,
+ 0x1e07, 0x1e07,
+ 0x1e09, 0x1e09,
+ 0x1e0b, 0x1e0b,
+ 0x1e0d, 0x1e0d,
+ 0x1e0f, 0x1e0f,
+ 0x1e11, 0x1e11,
+ 0x1e13, 0x1e13,
+ 0x1e15, 0x1e15,
+ 0x1e17, 0x1e17,
+ 0x1e19, 0x1e19,
+ 0x1e1b, 0x1e1b,
+ 0x1e1d, 0x1e1d,
+ 0x1e1f, 0x1e1f,
+ 0x1e21, 0x1e21,
+ 0x1e23, 0x1e23,
+ 0x1e25, 0x1e25,
+ 0x1e27, 0x1e27,
+ 0x1e29, 0x1e29,
+ 0x1e2b, 0x1e2b,
+ 0x1e2d, 0x1e2d,
+ 0x1e2f, 0x1e2f,
+ 0x1e31, 0x1e31,
+ 0x1e33, 0x1e33,
+ 0x1e35, 0x1e35,
+ 0x1e37, 0x1e37,
+ 0x1e39, 0x1e39,
+ 0x1e3b, 0x1e3b,
+ 0x1e3d, 0x1e3d,
+ 0x1e3f, 0x1e3f,
+ 0x1e41, 0x1e41,
+ 0x1e43, 0x1e43,
+ 0x1e45, 0x1e45,
+ 0x1e47, 0x1e47,
+ 0x1e49, 0x1e49,
+ 0x1e4b, 0x1e4b,
+ 0x1e4d, 0x1e4d,
+ 0x1e4f, 0x1e4f,
+ 0x1e51, 0x1e51,
+ 0x1e53, 0x1e53,
+ 0x1e55, 0x1e55,
+ 0x1e57, 0x1e57,
+ 0x1e59, 0x1e59,
+ 0x1e5b, 0x1e5b,
+ 0x1e5d, 0x1e5d,
+ 0x1e5f, 0x1e5f,
+ 0x1e61, 0x1e61,
+ 0x1e63, 0x1e63,
+ 0x1e65, 0x1e65,
+ 0x1e67, 0x1e67,
+ 0x1e69, 0x1e69,
+ 0x1e6b, 0x1e6b,
+ 0x1e6d, 0x1e6d,
+ 0x1e6f, 0x1e6f,
+ 0x1e71, 0x1e71,
+ 0x1e73, 0x1e73,
+ 0x1e75, 0x1e75,
+ 0x1e77, 0x1e77,
+ 0x1e79, 0x1e79,
+ 0x1e7b, 0x1e7b,
+ 0x1e7d, 0x1e7d,
+ 0x1e7f, 0x1e7f,
+ 0x1e81, 0x1e81,
+ 0x1e83, 0x1e83,
+ 0x1e85, 0x1e85,
+ 0x1e87, 0x1e87,
+ 0x1e89, 0x1e89,
+ 0x1e8b, 0x1e8b,
+ 0x1e8d, 0x1e8d,
+ 0x1e8f, 0x1e8f,
+ 0x1e91, 0x1e91,
+ 0x1e93, 0x1e93,
+ 0x1e95, 0x1e9d,
+ 0x1e9f, 0x1e9f,
+ 0x1ea1, 0x1ea1,
+ 0x1ea3, 0x1ea3,
+ 0x1ea5, 0x1ea5,
+ 0x1ea7, 0x1ea7,
+ 0x1ea9, 0x1ea9,
+ 0x1eab, 0x1eab,
+ 0x1ead, 0x1ead,
+ 0x1eaf, 0x1eaf,
+ 0x1eb1, 0x1eb1,
+ 0x1eb3, 0x1eb3,
+ 0x1eb5, 0x1eb5,
+ 0x1eb7, 0x1eb7,
+ 0x1eb9, 0x1eb9,
+ 0x1ebb, 0x1ebb,
+ 0x1ebd, 0x1ebd,
+ 0x1ebf, 0x1ebf,
+ 0x1ec1, 0x1ec1,
+ 0x1ec3, 0x1ec3,
+ 0x1ec5, 0x1ec5,
+ 0x1ec7, 0x1ec7,
+ 0x1ec9, 0x1ec9,
+ 0x1ecb, 0x1ecb,
+ 0x1ecd, 0x1ecd,
+ 0x1ecf, 0x1ecf,
+ 0x1ed1, 0x1ed1,
+ 0x1ed3, 0x1ed3,
+ 0x1ed5, 0x1ed5,
+ 0x1ed7, 0x1ed7,
+ 0x1ed9, 0x1ed9,
+ 0x1edb, 0x1edb,
+ 0x1edd, 0x1edd,
+ 0x1edf, 0x1edf,
+ 0x1ee1, 0x1ee1,
+ 0x1ee3, 0x1ee3,
+ 0x1ee5, 0x1ee5,
+ 0x1ee7, 0x1ee7,
+ 0x1ee9, 0x1ee9,
+ 0x1eeb, 0x1eeb,
+ 0x1eed, 0x1eed,
+ 0x1eef, 0x1eef,
+ 0x1ef1, 0x1ef1,
+ 0x1ef3, 0x1ef3,
+ 0x1ef5, 0x1ef5,
+ 0x1ef7, 0x1ef7,
+ 0x1ef9, 0x1ef9,
+ 0x1efb, 0x1efb,
+ 0x1efd, 0x1efd,
+ 0x1eff, 0x1f07,
+ 0x1f10, 0x1f15,
+ 0x1f20, 0x1f27,
+ 0x1f30, 0x1f37,
+ 0x1f40, 0x1f45,
+ 0x1f50, 0x1f57,
+ 0x1f60, 0x1f67,
+ 0x1f70, 0x1f7d,
+ 0x1f80, 0x1f87,
+ 0x1f90, 0x1f97,
+ 0x1fa0, 0x1fa7,
+ 0x1fb0, 0x1fb4,
+ 0x1fb6, 0x1fb7,
+ 0x1fbe, 0x1fbe,
+ 0x1fc2, 0x1fc4,
+ 0x1fc6, 0x1fc7,
+ 0x1fd0, 0x1fd3,
+ 0x1fd6, 0x1fd7,
+ 0x1fe0, 0x1fe7,
+ 0x1ff2, 0x1ff4,
+ 0x1ff6, 0x1ff7,
+ 0x2071, 0x2071,
+ 0x207f, 0x207f,
+ 0x2090, 0x209c,
+ 0x210a, 0x210a,
+ 0x210e, 0x210f,
+ 0x2113, 0x2113,
+ 0x212f, 0x212f,
+ 0x2134, 0x2134,
+ 0x2139, 0x2139,
+ 0x213c, 0x213d,
+ 0x2146, 0x2149,
+ 0x214e, 0x214e,
+ 0x2170, 0x217f,
+ 0x2184, 0x2184,
+ 0x24d0, 0x24e9,
+ 0x2c30, 0x2c5f,
+ 0x2c61, 0x2c61,
+ 0x2c65, 0x2c66,
+ 0x2c68, 0x2c68,
+ 0x2c6a, 0x2c6a,
+ 0x2c6c, 0x2c6c,
+ 0x2c71, 0x2c71,
+ 0x2c73, 0x2c74,
+ 0x2c76, 0x2c7d,
+ 0x2c81, 0x2c81,
+ 0x2c83, 0x2c83,
+ 0x2c85, 0x2c85,
+ 0x2c87, 0x2c87,
+ 0x2c89, 0x2c89,
+ 0x2c8b, 0x2c8b,
+ 0x2c8d, 0x2c8d,
+ 0x2c8f, 0x2c8f,
+ 0x2c91, 0x2c91,
+ 0x2c93, 0x2c93,
+ 0x2c95, 0x2c95,
+ 0x2c97, 0x2c97,
+ 0x2c99, 0x2c99,
+ 0x2c9b, 0x2c9b,
+ 0x2c9d, 0x2c9d,
+ 0x2c9f, 0x2c9f,
+ 0x2ca1, 0x2ca1,
+ 0x2ca3, 0x2ca3,
+ 0x2ca5, 0x2ca5,
+ 0x2ca7, 0x2ca7,
+ 0x2ca9, 0x2ca9,
+ 0x2cab, 0x2cab,
+ 0x2cad, 0x2cad,
+ 0x2caf, 0x2caf,
+ 0x2cb1, 0x2cb1,
+ 0x2cb3, 0x2cb3,
+ 0x2cb5, 0x2cb5,
+ 0x2cb7, 0x2cb7,
+ 0x2cb9, 0x2cb9,
+ 0x2cbb, 0x2cbb,
+ 0x2cbd, 0x2cbd,
+ 0x2cbf, 0x2cbf,
+ 0x2cc1, 0x2cc1,
+ 0x2cc3, 0x2cc3,
+ 0x2cc5, 0x2cc5,
+ 0x2cc7, 0x2cc7,
+ 0x2cc9, 0x2cc9,
+ 0x2ccb, 0x2ccb,
+ 0x2ccd, 0x2ccd,
+ 0x2ccf, 0x2ccf,
+ 0x2cd1, 0x2cd1,
+ 0x2cd3, 0x2cd3,
+ 0x2cd5, 0x2cd5,
+ 0x2cd7, 0x2cd7,
+ 0x2cd9, 0x2cd9,
+ 0x2cdb, 0x2cdb,
+ 0x2cdd, 0x2cdd,
+ 0x2cdf, 0x2cdf,
+ 0x2ce1, 0x2ce1,
+ 0x2ce3, 0x2ce4,
+ 0x2cec, 0x2cec,
+ 0x2cee, 0x2cee,
+ 0x2cf3, 0x2cf3,
+ 0x2d00, 0x2d25,
+ 0x2d27, 0x2d27,
+ 0x2d2d, 0x2d2d,
+ 0xa641, 0xa641,
+ 0xa643, 0xa643,
+ 0xa645, 0xa645,
+ 0xa647, 0xa647,
+ 0xa649, 0xa649,
+ 0xa64b, 0xa64b,
+ 0xa64d, 0xa64d,
+ 0xa64f, 0xa64f,
+ 0xa651, 0xa651,
+ 0xa653, 0xa653,
+ 0xa655, 0xa655,
+ 0xa657, 0xa657,
+ 0xa659, 0xa659,
+ 0xa65b, 0xa65b,
+ 0xa65d, 0xa65d,
+ 0xa65f, 0xa65f,
+ 0xa661, 0xa661,
+ 0xa663, 0xa663,
+ 0xa665, 0xa665,
+ 0xa667, 0xa667,
+ 0xa669, 0xa669,
+ 0xa66b, 0xa66b,
+ 0xa66d, 0xa66d,
+ 0xa681, 0xa681,
+ 0xa683, 0xa683,
+ 0xa685, 0xa685,
+ 0xa687, 0xa687,
+ 0xa689, 0xa689,
+ 0xa68b, 0xa68b,
+ 0xa68d, 0xa68d,
+ 0xa68f, 0xa68f,
+ 0xa691, 0xa691,
+ 0xa693, 0xa693,
+ 0xa695, 0xa695,
+ 0xa697, 0xa697,
+ 0xa699, 0xa699,
+ 0xa69b, 0xa69d,
+ 0xa723, 0xa723,
+ 0xa725, 0xa725,
+ 0xa727, 0xa727,
+ 0xa729, 0xa729,
+ 0xa72b, 0xa72b,
+ 0xa72d, 0xa72d,
+ 0xa72f, 0xa731,
+ 0xa733, 0xa733,
+ 0xa735, 0xa735,
+ 0xa737, 0xa737,
+ 0xa739, 0xa739,
+ 0xa73b, 0xa73b,
+ 0xa73d, 0xa73d,
+ 0xa73f, 0xa73f,
+ 0xa741, 0xa741,
+ 0xa743, 0xa743,
+ 0xa745, 0xa745,
+ 0xa747, 0xa747,
+ 0xa749, 0xa749,
+ 0xa74b, 0xa74b,
+ 0xa74d, 0xa74d,
+ 0xa74f, 0xa74f,
+ 0xa751, 0xa751,
+ 0xa753, 0xa753,
+ 0xa755, 0xa755,
+ 0xa757, 0xa757,
+ 0xa759, 0xa759,
+ 0xa75b, 0xa75b,
+ 0xa75d, 0xa75d,
+ 0xa75f, 0xa75f,
+ 0xa761, 0xa761,
+ 0xa763, 0xa763,
+ 0xa765, 0xa765,
+ 0xa767, 0xa767,
+ 0xa769, 0xa769,
+ 0xa76b, 0xa76b,
+ 0xa76d, 0xa76d,
+ 0xa76f, 0xa778,
+ 0xa77a, 0xa77a,
+ 0xa77c, 0xa77c,
+ 0xa77f, 0xa77f,
+ 0xa781, 0xa781,
+ 0xa783, 0xa783,
+ 0xa785, 0xa785,
+ 0xa787, 0xa787,
+ 0xa78c, 0xa78c,
+ 0xa78e, 0xa78e,
+ 0xa791, 0xa791,
+ 0xa793, 0xa795,
+ 0xa797, 0xa797,
+ 0xa799, 0xa799,
+ 0xa79b, 0xa79b,
+ 0xa79d, 0xa79d,
+ 0xa79f, 0xa79f,
+ 0xa7a1, 0xa7a1,
+ 0xa7a3, 0xa7a3,
+ 0xa7a5, 0xa7a5,
+ 0xa7a7, 0xa7a7,
+ 0xa7a9, 0xa7a9,
+ 0xa7af, 0xa7af,
+ 0xa7b5, 0xa7b5,
+ 0xa7b7, 0xa7b7,
+ 0xa7b9, 0xa7b9,
+ 0xa7bb, 0xa7bb,
+ 0xa7bd, 0xa7bd,
+ 0xa7bf, 0xa7bf,
+ 0xa7c1, 0xa7c1,
+ 0xa7c3, 0xa7c3,
+ 0xa7c8, 0xa7c8,
+ 0xa7ca, 0xa7ca,
+ 0xa7cd, 0xa7cd,
+ 0xa7cf, 0xa7cf,
+ 0xa7d1, 0xa7d1,
+ 0xa7d3, 0xa7d3,
+ 0xa7d5, 0xa7d5,
+ 0xa7d7, 0xa7d7,
+ 0xa7d9, 0xa7d9,
+ 0xa7db, 0xa7db,
+ 0xa7f1, 0xa7f4,
+ 0xa7f6, 0xa7f6,
+ 0xa7f8, 0xa7fa,
+ 0xab30, 0xab5a,
+ 0xab5c, 0xab69,
+ 0xab70, 0xabbf,
+ 0xfb00, 0xfb06,
+ 0xfb13, 0xfb17,
+ 0xff41, 0xff5a,
+ 0x10428, 0x1044f,
+ 0x104d8, 0x104fb,
+ 0x10597, 0x105a1,
+ 0x105a3, 0x105b1,
+ 0x105b3, 0x105b9,
+ 0x105bb, 0x105bc,
+ 0x10780, 0x10780,
+ 0x10783, 0x10785,
+ 0x10787, 0x107b0,
+ 0x107b2, 0x107ba,
+ 0x10cc0, 0x10cf2,
+ 0x10d70, 0x10d85,
+ 0x118c0, 0x118df,
+ 0x16e60, 0x16e7f,
+ 0x16ebb, 0x16ed3,
+ 0x1d41a, 0x1d433,
+ 0x1d44e, 0x1d454,
+ 0x1d456, 0x1d467,
+ 0x1d482, 0x1d49b,
+ 0x1d4b6, 0x1d4b9,
+ 0x1d4bb, 0x1d4bb,
+ 0x1d4bd, 0x1d4c3,
+ 0x1d4c5, 0x1d4cf,
+ 0x1d4ea, 0x1d503,
+ 0x1d51e, 0x1d537,
+ 0x1d552, 0x1d56b,
+ 0x1d586, 0x1d59f,
+ 0x1d5ba, 0x1d5d3,
+ 0x1d5ee, 0x1d607,
+ 0x1d622, 0x1d63b,
+ 0x1d656, 0x1d66f,
+ 0x1d68a, 0x1d6a5,
+ 0x1d6c2, 0x1d6da,
+ 0x1d6dc, 0x1d6e1,
+ 0x1d6fc, 0x1d714,
+ 0x1d716, 0x1d71b,
+ 0x1d736, 0x1d74e,
+ 0x1d750, 0x1d755,
+ 0x1d770, 0x1d788,
+ 0x1d78a, 0x1d78f,
+ 0x1d7aa, 0x1d7c2,
+ 0x1d7c4, 0x1d7c9,
+ 0x1d7cb, 0x1d7cb,
+ 0x1df00, 0x1df09,
+ 0x1df0b, 0x1df1e,
+ 0x1df25, 0x1df2a,
+ 0x1e030, 0x1e06d,
+ 0x1e922, 0x1e943,
+}; /* CR_Lower */
+
+/* 'Print': [[:Print:]] */
+static const OnigCodePoint CR_Print[] = {
+ 737,
+ 0x0020, 0x007e,
+ 0x00a0, 0x0377,
+ 0x037a, 0x037f,
+ 0x0384, 0x038a,
+ 0x038c, 0x038c,
+ 0x038e, 0x03a1,
+ 0x03a3, 0x052f,
+ 0x0531, 0x0556,
+ 0x0559, 0x058a,
+ 0x058d, 0x058f,
+ 0x0591, 0x05c7,
+ 0x05d0, 0x05ea,
+ 0x05ef, 0x05f4,
+ 0x0600, 0x070d,
+ 0x070f, 0x074a,
+ 0x074d, 0x07b1,
+ 0x07c0, 0x07fa,
+ 0x07fd, 0x082d,
+ 0x0830, 0x083e,
+ 0x0840, 0x085b,
+ 0x085e, 0x085e,
+ 0x0860, 0x086a,
+ 0x0870, 0x0891,
+ 0x0897, 0x0983,
+ 0x0985, 0x098c,
+ 0x098f, 0x0990,
+ 0x0993, 0x09a8,
+ 0x09aa, 0x09b0,
+ 0x09b2, 0x09b2,
+ 0x09b6, 0x09b9,
+ 0x09bc, 0x09c4,
+ 0x09c7, 0x09c8,
+ 0x09cb, 0x09ce,
+ 0x09d7, 0x09d7,
+ 0x09dc, 0x09dd,
+ 0x09df, 0x09e3,
+ 0x09e6, 0x09fe,
+ 0x0a01, 0x0a03,
+ 0x0a05, 0x0a0a,
+ 0x0a0f, 0x0a10,
+ 0x0a13, 0x0a28,
+ 0x0a2a, 0x0a30,
+ 0x0a32, 0x0a33,
+ 0x0a35, 0x0a36,
+ 0x0a38, 0x0a39,
+ 0x0a3c, 0x0a3c,
+ 0x0a3e, 0x0a42,
+ 0x0a47, 0x0a48,
+ 0x0a4b, 0x0a4d,
+ 0x0a51, 0x0a51,
+ 0x0a59, 0x0a5c,
+ 0x0a5e, 0x0a5e,
+ 0x0a66, 0x0a76,
+ 0x0a81, 0x0a83,
+ 0x0a85, 0x0a8d,
+ 0x0a8f, 0x0a91,
+ 0x0a93, 0x0aa8,
+ 0x0aaa, 0x0ab0,
+ 0x0ab2, 0x0ab3,
+ 0x0ab5, 0x0ab9,
+ 0x0abc, 0x0ac5,
+ 0x0ac7, 0x0ac9,
+ 0x0acb, 0x0acd,
+ 0x0ad0, 0x0ad0,
+ 0x0ae0, 0x0ae3,
+ 0x0ae6, 0x0af1,
+ 0x0af9, 0x0aff,
+ 0x0b01, 0x0b03,
+ 0x0b05, 0x0b0c,
+ 0x0b0f, 0x0b10,
+ 0x0b13, 0x0b28,
+ 0x0b2a, 0x0b30,
+ 0x0b32, 0x0b33,
+ 0x0b35, 0x0b39,
+ 0x0b3c, 0x0b44,
+ 0x0b47, 0x0b48,
+ 0x0b4b, 0x0b4d,
+ 0x0b55, 0x0b57,
+ 0x0b5c, 0x0b5d,
+ 0x0b5f, 0x0b63,
+ 0x0b66, 0x0b77,
+ 0x0b82, 0x0b83,
+ 0x0b85, 0x0b8a,
+ 0x0b8e, 0x0b90,
+ 0x0b92, 0x0b95,
+ 0x0b99, 0x0b9a,
+ 0x0b9c, 0x0b9c,
+ 0x0b9e, 0x0b9f,
+ 0x0ba3, 0x0ba4,
+ 0x0ba8, 0x0baa,
+ 0x0bae, 0x0bb9,
+ 0x0bbe, 0x0bc2,
+ 0x0bc6, 0x0bc8,
+ 0x0bca, 0x0bcd,
+ 0x0bd0, 0x0bd0,
+ 0x0bd7, 0x0bd7,
+ 0x0be6, 0x0bfa,
+ 0x0c00, 0x0c0c,
+ 0x0c0e, 0x0c10,
+ 0x0c12, 0x0c28,
+ 0x0c2a, 0x0c39,
+ 0x0c3c, 0x0c44,
+ 0x0c46, 0x0c48,
+ 0x0c4a, 0x0c4d,
+ 0x0c55, 0x0c56,
+ 0x0c58, 0x0c5a,
+ 0x0c5c, 0x0c5d,
+ 0x0c60, 0x0c63,
+ 0x0c66, 0x0c6f,
+ 0x0c77, 0x0c8c,
+ 0x0c8e, 0x0c90,
+ 0x0c92, 0x0ca8,
+ 0x0caa, 0x0cb3,
+ 0x0cb5, 0x0cb9,
+ 0x0cbc, 0x0cc4,
+ 0x0cc6, 0x0cc8,
+ 0x0cca, 0x0ccd,
+ 0x0cd5, 0x0cd6,
+ 0x0cdc, 0x0cde,
+ 0x0ce0, 0x0ce3,
+ 0x0ce6, 0x0cef,
+ 0x0cf1, 0x0cf3,
+ 0x0d00, 0x0d0c,
+ 0x0d0e, 0x0d10,
+ 0x0d12, 0x0d44,
+ 0x0d46, 0x0d48,
+ 0x0d4a, 0x0d4f,
+ 0x0d54, 0x0d63,
+ 0x0d66, 0x0d7f,
+ 0x0d81, 0x0d83,
+ 0x0d85, 0x0d96,
+ 0x0d9a, 0x0db1,
+ 0x0db3, 0x0dbb,
+ 0x0dbd, 0x0dbd,
+ 0x0dc0, 0x0dc6,
+ 0x0dca, 0x0dca,
+ 0x0dcf, 0x0dd4,
+ 0x0dd6, 0x0dd6,
+ 0x0dd8, 0x0ddf,
+ 0x0de6, 0x0def,
+ 0x0df2, 0x0df4,
+ 0x0e01, 0x0e3a,
+ 0x0e3f, 0x0e5b,
+ 0x0e81, 0x0e82,
+ 0x0e84, 0x0e84,
+ 0x0e86, 0x0e8a,
+ 0x0e8c, 0x0ea3,
+ 0x0ea5, 0x0ea5,
+ 0x0ea7, 0x0ebd,
+ 0x0ec0, 0x0ec4,
+ 0x0ec6, 0x0ec6,
+ 0x0ec8, 0x0ece,
+ 0x0ed0, 0x0ed9,
+ 0x0edc, 0x0edf,
+ 0x0f00, 0x0f47,
+ 0x0f49, 0x0f6c,
+ 0x0f71, 0x0f97,
+ 0x0f99, 0x0fbc,
+ 0x0fbe, 0x0fcc,
+ 0x0fce, 0x0fda,
+ 0x1000, 0x10c5,
+ 0x10c7, 0x10c7,
+ 0x10cd, 0x10cd,
+ 0x10d0, 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,
+ 0x135d, 0x137c,
+ 0x1380, 0x1399,
+ 0x13a0, 0x13f5,
+ 0x13f8, 0x13fd,
+ 0x1400, 0x169c,
+ 0x16a0, 0x16f8,
+ 0x1700, 0x1715,
+ 0x171f, 0x1736,
+ 0x1740, 0x1753,
+ 0x1760, 0x176c,
+ 0x176e, 0x1770,
+ 0x1772, 0x1773,
+ 0x1780, 0x17dd,
+ 0x17e0, 0x17e9,
+ 0x17f0, 0x17f9,
+ 0x1800, 0x1819,
+ 0x1820, 0x1878,
+ 0x1880, 0x18aa,
+ 0x18b0, 0x18f5,
+ 0x1900, 0x191e,
+ 0x1920, 0x192b,
+ 0x1930, 0x193b,
+ 0x1940, 0x1940,
+ 0x1944, 0x196d,
+ 0x1970, 0x1974,
+ 0x1980, 0x19ab,
+ 0x19b0, 0x19c9,
+ 0x19d0, 0x19da,
+ 0x19de, 0x1a1b,
+ 0x1a1e, 0x1a5e,
+ 0x1a60, 0x1a7c,
+ 0x1a7f, 0x1a89,
+ 0x1a90, 0x1a99,
+ 0x1aa0, 0x1aad,
+ 0x1ab0, 0x1add,
+ 0x1ae0, 0x1aeb,
+ 0x1b00, 0x1b4c,
+ 0x1b4e, 0x1bf3,
+ 0x1bfc, 0x1c37,
+ 0x1c3b, 0x1c49,
+ 0x1c4d, 0x1c8a,
+ 0x1c90, 0x1cba,
+ 0x1cbd, 0x1cc7,
+ 0x1cd0, 0x1cfa,
+ 0x1d00, 0x1f15,
+ 0x1f18, 0x1f1d,
+ 0x1f20, 0x1f45,
+ 0x1f48, 0x1f4d,
+ 0x1f50, 0x1f57,
+ 0x1f59, 0x1f59,
+ 0x1f5b, 0x1f5b,
+ 0x1f5d, 0x1f5d,
+ 0x1f5f, 0x1f7d,
+ 0x1f80, 0x1fb4,
+ 0x1fb6, 0x1fc4,
+ 0x1fc6, 0x1fd3,
+ 0x1fd6, 0x1fdb,
+ 0x1fdd, 0x1fef,
+ 0x1ff2, 0x1ff4,
+ 0x1ff6, 0x1ffe,
+ 0x2000, 0x2027,
+ 0x202a, 0x2064,
+ 0x2066, 0x2071,
+ 0x2074, 0x208e,
+ 0x2090, 0x209c,
+ 0x20a0, 0x20c1,
+ 0x20d0, 0x20f0,
+ 0x2100, 0x218b,
+ 0x2190, 0x2429,
+ 0x2440, 0x244a,
+ 0x2460, 0x2b73,
+ 0x2b76, 0x2cf3,
+ 0x2cf9, 0x2d25,
+ 0x2d27, 0x2d27,
+ 0x2d2d, 0x2d2d,
+ 0x2d30, 0x2d67,
+ 0x2d6f, 0x2d70,
+ 0x2d7f, 0x2d96,
+ 0x2da0, 0x2da6,
+ 0x2da8, 0x2dae,
+ 0x2db0, 0x2db6,
+ 0x2db8, 0x2dbe,
+ 0x2dc0, 0x2dc6,
+ 0x2dc8, 0x2dce,
+ 0x2dd0, 0x2dd6,
+ 0x2dd8, 0x2dde,
+ 0x2de0, 0x2e5d,
+ 0x2e80, 0x2e99,
+ 0x2e9b, 0x2ef3,
+ 0x2f00, 0x2fd5,
+ 0x2ff0, 0x303f,
+ 0x3041, 0x3096,
+ 0x3099, 0x30ff,
+ 0x3105, 0x312f,
+ 0x3131, 0x318e,
+ 0x3190, 0x31e5,
+ 0x31ef, 0x321e,
+ 0x3220, 0xa48c,
+ 0xa490, 0xa4c6,
+ 0xa4d0, 0xa62b,
+ 0xa640, 0xa6f7,
+ 0xa700, 0xa7dc,
+ 0xa7f1, 0xa82c,
+ 0xa830, 0xa839,
+ 0xa840, 0xa877,
+ 0xa880, 0xa8c5,
+ 0xa8ce, 0xa8d9,
+ 0xa8e0, 0xa953,
+ 0xa95f, 0xa97c,
+ 0xa980, 0xa9cd,
+ 0xa9cf, 0xa9d9,
+ 0xa9de, 0xa9fe,
+ 0xaa00, 0xaa36,
+ 0xaa40, 0xaa4d,
+ 0xaa50, 0xaa59,
+ 0xaa5c, 0xaac2,
+ 0xaadb, 0xaaf6,
+ 0xab01, 0xab06,
+ 0xab09, 0xab0e,
+ 0xab11, 0xab16,
+ 0xab20, 0xab26,
+ 0xab28, 0xab2e,
+ 0xab30, 0xab6b,
+ 0xab70, 0xabed,
+ 0xabf0, 0xabf9,
+ 0xac00, 0xd7a3,
+ 0xd7b0, 0xd7c6,
+ 0xd7cb, 0xd7fb,
+ 0xe000, 0xfa6d,
+ 0xfa70, 0xfad9,
+ 0xfb00, 0xfb06,
+ 0xfb13, 0xfb17,
+ 0xfb1d, 0xfb36,
+ 0xfb38, 0xfb3c,
+ 0xfb3e, 0xfb3e,
+ 0xfb40, 0xfb41,
+ 0xfb43, 0xfb44,
+ 0xfb46, 0xfdcf,
+ 0xfdf0, 0xfe19,
+ 0xfe20, 0xfe52,
+ 0xfe54, 0xfe66,
+ 0xfe68, 0xfe6b,
+ 0xfe70, 0xfe74,
+ 0xfe76, 0xfefc,
+ 0xfeff, 0xfeff,
+ 0xff01, 0xffbe,
+ 0xffc2, 0xffc7,
+ 0xffca, 0xffcf,
+ 0xffd2, 0xffd7,
+ 0xffda, 0xffdc,
+ 0xffe0, 0xffe6,
+ 0xffe8, 0xffee,
+ 0xfff9, 0xfffd,
+ 0x10000, 0x1000b,
+ 0x1000d, 0x10026,
+ 0x10028, 0x1003a,
+ 0x1003c, 0x1003d,
+ 0x1003f, 0x1004d,
+ 0x10050, 0x1005d,
+ 0x10080, 0x100fa,
+ 0x10100, 0x10102,
+ 0x10107, 0x10133,
+ 0x10137, 0x1018e,
+ 0x10190, 0x1019c,
+ 0x101a0, 0x101a0,
+ 0x101d0, 0x101fd,
+ 0x10280, 0x1029c,
+ 0x102a0, 0x102d0,
+ 0x102e0, 0x102fb,
+ 0x10300, 0x10323,
+ 0x1032d, 0x1034a,
+ 0x10350, 0x1037a,
+ 0x10380, 0x1039d,
+ 0x1039f, 0x103c3,
+ 0x103c8, 0x103d5,
+ 0x10400, 0x1049d,
+ 0x104a0, 0x104a9,
+ 0x104b0, 0x104d3,
+ 0x104d8, 0x104fb,
+ 0x10500, 0x10527,
+ 0x10530, 0x10563,
+ 0x1056f, 0x1057a,
+ 0x1057c, 0x1058a,
+ 0x1058c, 0x10592,
+ 0x10594, 0x10595,
+ 0x10597, 0x105a1,
+ 0x105a3, 0x105b1,
+ 0x105b3, 0x105b9,
+ 0x105bb, 0x105bc,
+ 0x105c0, 0x105f3,
+ 0x10600, 0x10736,
+ 0x10740, 0x10755,
+ 0x10760, 0x10767,
+ 0x10780, 0x10785,
+ 0x10787, 0x107b0,
+ 0x107b2, 0x107ba,
+ 0x10800, 0x10805,
+ 0x10808, 0x10808,
+ 0x1080a, 0x10835,
+ 0x10837, 0x10838,
+ 0x1083c, 0x1083c,
+ 0x1083f, 0x10855,
+ 0x10857, 0x1089e,
+ 0x108a7, 0x108af,
+ 0x108e0, 0x108f2,
+ 0x108f4, 0x108f5,
+ 0x108fb, 0x1091b,
+ 0x1091f, 0x10939,
+ 0x1093f, 0x10959,
+ 0x10980, 0x109b7,
+ 0x109bc, 0x109cf,
+ 0x109d2, 0x10a03,
+ 0x10a05, 0x10a06,
+ 0x10a0c, 0x10a13,
+ 0x10a15, 0x10a17,
+ 0x10a19, 0x10a35,
+ 0x10a38, 0x10a3a,
+ 0x10a3f, 0x10a48,
+ 0x10a50, 0x10a58,
+ 0x10a60, 0x10a9f,
+ 0x10ac0, 0x10ae6,
+ 0x10aeb, 0x10af6,
+ 0x10b00, 0x10b35,
+ 0x10b39, 0x10b55,
+ 0x10b58, 0x10b72,
+ 0x10b78, 0x10b91,
+ 0x10b99, 0x10b9c,
+ 0x10ba9, 0x10baf,
+ 0x10c00, 0x10c48,
+ 0x10c80, 0x10cb2,
+ 0x10cc0, 0x10cf2,
+ 0x10cfa, 0x10d27,
+ 0x10d30, 0x10d39,
+ 0x10d40, 0x10d65,
+ 0x10d69, 0x10d85,
+ 0x10d8e, 0x10d8f,
+ 0x10e60, 0x10e7e,
+ 0x10e80, 0x10ea9,
+ 0x10eab, 0x10ead,
+ 0x10eb0, 0x10eb1,
+ 0x10ec2, 0x10ec7,
+ 0x10ed0, 0x10ed8,
+ 0x10efa, 0x10f27,
+ 0x10f30, 0x10f59,
+ 0x10f70, 0x10f89,
+ 0x10fb0, 0x10fcb,
+ 0x10fe0, 0x10ff6,
+ 0x11000, 0x1104d,
+ 0x11052, 0x11075,
+ 0x1107f, 0x110c2,
+ 0x110cd, 0x110cd,
+ 0x110d0, 0x110e8,
+ 0x110f0, 0x110f9,
+ 0x11100, 0x11134,
+ 0x11136, 0x11147,
+ 0x11150, 0x11176,
+ 0x11180, 0x111df,
+ 0x111e1, 0x111f4,
+ 0x11200, 0x11211,
+ 0x11213, 0x11241,
+ 0x11280, 0x11286,
+ 0x11288, 0x11288,
+ 0x1128a, 0x1128d,
+ 0x1128f, 0x1129d,
+ 0x1129f, 0x112a9,
+ 0x112b0, 0x112ea,
+ 0x112f0, 0x112f9,
+ 0x11300, 0x11303,
+ 0x11305, 0x1130c,
+ 0x1130f, 0x11310,
+ 0x11313, 0x11328,
+ 0x1132a, 0x11330,
+ 0x11332, 0x11333,
+ 0x11335, 0x11339,
+ 0x1133b, 0x11344,
+ 0x11347, 0x11348,
+ 0x1134b, 0x1134d,
+ 0x11350, 0x11350,
+ 0x11357, 0x11357,
+ 0x1135d, 0x11363,
+ 0x11366, 0x1136c,
+ 0x11370, 0x11374,
+ 0x11380, 0x11389,
+ 0x1138b, 0x1138b,
+ 0x1138e, 0x1138e,
+ 0x11390, 0x113b5,
+ 0x113b7, 0x113c0,
+ 0x113c2, 0x113c2,
+ 0x113c5, 0x113c5,
+ 0x113c7, 0x113ca,
+ 0x113cc, 0x113d5,
+ 0x113d7, 0x113d8,
+ 0x113e1, 0x113e2,
+ 0x11400, 0x1145b,
+ 0x1145d, 0x11461,
+ 0x11480, 0x114c7,
+ 0x114d0, 0x114d9,
+ 0x11580, 0x115b5,
+ 0x115b8, 0x115dd,
+ 0x11600, 0x11644,
+ 0x11650, 0x11659,
+ 0x11660, 0x1166c,
+ 0x11680, 0x116b9,
+ 0x116c0, 0x116c9,
+ 0x116d0, 0x116e3,
+ 0x11700, 0x1171a,
+ 0x1171d, 0x1172b,
+ 0x11730, 0x11746,
+ 0x11800, 0x1183b,
+ 0x118a0, 0x118f2,
+ 0x118ff, 0x11906,
+ 0x11909, 0x11909,
+ 0x1190c, 0x11913,
+ 0x11915, 0x11916,
+ 0x11918, 0x11935,
+ 0x11937, 0x11938,
+ 0x1193b, 0x11946,
+ 0x11950, 0x11959,
+ 0x119a0, 0x119a7,
+ 0x119aa, 0x119d7,
+ 0x119da, 0x119e4,
+ 0x11a00, 0x11a47,
+ 0x11a50, 0x11aa2,
+ 0x11ab0, 0x11af8,
+ 0x11b00, 0x11b09,
+ 0x11b60, 0x11b67,
+ 0x11bc0, 0x11be1,
+ 0x11bf0, 0x11bf9,
+ 0x11c00, 0x11c08,
+ 0x11c0a, 0x11c36,
+ 0x11c38, 0x11c45,
+ 0x11c50, 0x11c6c,
+ 0x11c70, 0x11c8f,
+ 0x11c92, 0x11ca7,
+ 0x11ca9, 0x11cb6,
+ 0x11d00, 0x11d06,
+ 0x11d08, 0x11d09,
+ 0x11d0b, 0x11d36,
+ 0x11d3a, 0x11d3a,
+ 0x11d3c, 0x11d3d,
+ 0x11d3f, 0x11d47,
+ 0x11d50, 0x11d59,
+ 0x11d60, 0x11d65,
+ 0x11d67, 0x11d68,
+ 0x11d6a, 0x11d8e,
+ 0x11d90, 0x11d91,
+ 0x11d93, 0x11d98,
+ 0x11da0, 0x11da9,
+ 0x11db0, 0x11ddb,
+ 0x11de0, 0x11de9,
+ 0x11ee0, 0x11ef8,
+ 0x11f00, 0x11f10,
+ 0x11f12, 0x11f3a,
+ 0x11f3e, 0x11f5a,
+ 0x11fb0, 0x11fb0,
+ 0x11fc0, 0x11ff1,
+ 0x11fff, 0x12399,
+ 0x12400, 0x1246e,
+ 0x12470, 0x12474,
+ 0x12480, 0x12543,
+ 0x12f90, 0x12ff2,
+ 0x13000, 0x13455,
+ 0x13460, 0x143fa,
+ 0x14400, 0x14646,
+ 0x16100, 0x16139,
+ 0x16800, 0x16a38,
+ 0x16a40, 0x16a5e,
+ 0x16a60, 0x16a69,
+ 0x16a6e, 0x16abe,
+ 0x16ac0, 0x16ac9,
+ 0x16ad0, 0x16aed,
+ 0x16af0, 0x16af5,
+ 0x16b00, 0x16b45,
+ 0x16b50, 0x16b59,
+ 0x16b5b, 0x16b61,
+ 0x16b63, 0x16b77,
+ 0x16b7d, 0x16b8f,
+ 0x16d40, 0x16d79,
+ 0x16e40, 0x16e9a,
+ 0x16ea0, 0x16eb8,
+ 0x16ebb, 0x16ed3,
+ 0x16f00, 0x16f4a,
+ 0x16f4f, 0x16f87,
+ 0x16f8f, 0x16f9f,
+ 0x16fe0, 0x16fe4,
+ 0x16ff0, 0x16ff6,
+ 0x17000, 0x18cd5,
+ 0x18cff, 0x18d1e,
+ 0x18d80, 0x18df2,
+ 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,
+ 0x1bc9c, 0x1bca3,
+ 0x1cc00, 0x1ccfc,
+ 0x1cd00, 0x1ceb3,
+ 0x1ceba, 0x1ced0,
+ 0x1cee0, 0x1cef0,
+ 0x1cf00, 0x1cf2d,
+ 0x1cf30, 0x1cf46,
+ 0x1cf50, 0x1cfc3,
+ 0x1d000, 0x1d0f5,
+ 0x1d100, 0x1d126,
+ 0x1d129, 0x1d1ea,
+ 0x1d200, 0x1d245,
+ 0x1d2c0, 0x1d2d3,
+ 0x1d2e0, 0x1d2f3,
+ 0x1d300, 0x1d356,
+ 0x1d360, 0x1d378,
+ 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, 0x1d7cb,
+ 0x1d7ce, 0x1da8b,
+ 0x1da9b, 0x1da9f,
+ 0x1daa1, 0x1daaf,
+ 0x1df00, 0x1df1e,
+ 0x1df25, 0x1df2a,
+ 0x1e000, 0x1e006,
+ 0x1e008, 0x1e018,
+ 0x1e01b, 0x1e021,
+ 0x1e023, 0x1e024,
+ 0x1e026, 0x1e02a,
+ 0x1e030, 0x1e06d,
+ 0x1e08f, 0x1e08f,
+ 0x1e100, 0x1e12c,
+ 0x1e130, 0x1e13d,
+ 0x1e140, 0x1e149,
+ 0x1e14e, 0x1e14f,
+ 0x1e290, 0x1e2ae,
+ 0x1e2c0, 0x1e2f9,
+ 0x1e2ff, 0x1e2ff,
+ 0x1e4d0, 0x1e4f9,
+ 0x1e5d0, 0x1e5fa,
+ 0x1e5ff, 0x1e5ff,
+ 0x1e6c0, 0x1e6de,
+ 0x1e6e0, 0x1e6f5,
+ 0x1e6fe, 0x1e6ff,
+ 0x1e7e0, 0x1e7e6,
+ 0x1e7e8, 0x1e7eb,
+ 0x1e7ed, 0x1e7ee,
+ 0x1e7f0, 0x1e7fe,
+ 0x1e800, 0x1e8c4,
+ 0x1e8c7, 0x1e8d6,
+ 0x1e900, 0x1e94b,
+ 0x1e950, 0x1e959,
+ 0x1e95e, 0x1e95f,
+ 0x1ec71, 0x1ecb4,
+ 0x1ed01, 0x1ed3d,
+ 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,
+ 0x1eef0, 0x1eef1,
+ 0x1f000, 0x1f02b,
+ 0x1f030, 0x1f093,
+ 0x1f0a0, 0x1f0ae,
+ 0x1f0b1, 0x1f0bf,
+ 0x1f0c1, 0x1f0cf,
+ 0x1f0d1, 0x1f0f5,
+ 0x1f100, 0x1f1ad,
+ 0x1f1e6, 0x1f202,
+ 0x1f210, 0x1f23b,
+ 0x1f240, 0x1f248,
+ 0x1f250, 0x1f251,
+ 0x1f260, 0x1f265,
+ 0x1f300, 0x1f6d8,
+ 0x1f6dc, 0x1f6ec,
+ 0x1f6f0, 0x1f6fc,
+ 0x1f700, 0x1f7d9,
+ 0x1f7e0, 0x1f7eb,
+ 0x1f7f0, 0x1f7f0,
+ 0x1f800, 0x1f80b,
+ 0x1f810, 0x1f847,
+ 0x1f850, 0x1f859,
+ 0x1f860, 0x1f887,
+ 0x1f890, 0x1f8ad,
+ 0x1f8b0, 0x1f8bb,
+ 0x1f8c0, 0x1f8c1,
+ 0x1f8d0, 0x1f8d8,
+ 0x1f900, 0x1fa57,
+ 0x1fa60, 0x1fa6d,
+ 0x1fa70, 0x1fa7c,
+ 0x1fa80, 0x1fa8a,
+ 0x1fa8e, 0x1fac6,
+ 0x1fac8, 0x1fac8,
+ 0x1facd, 0x1fadc,
+ 0x1fadf, 0x1faea,
+ 0x1faef, 0x1faf8,
+ 0x1fb00, 0x1fb92,
+ 0x1fb94, 0x1fbfa,
+ 0x20000, 0x2a6df,
+ 0x2a700, 0x2b81d,
+ 0x2b820, 0x2cead,
+ 0x2ceb0, 0x2ebe0,
+ 0x2ebf0, 0x2ee5d,
+ 0x2f800, 0x2fa1d,
+ 0x30000, 0x3134a,
+ 0x31350, 0x33479,
+ 0xe0001, 0xe0001,
+ 0xe0020, 0xe007f,
+ 0xe0100, 0xe01ef,
+ 0xf0000, 0xffffd,
+ 0x100000, 0x10fffd,
+}; /* CR_Print */
+
+/* 'XPosixPunct': [[:Punct:]] */
+static const OnigCodePoint CR_XPosixPunct[] = {
+ 194,
+ 0x0021, 0x002f,
+ 0x003a, 0x0040,
+ 0x005b, 0x0060,
+ 0x007b, 0x007e,
+ 0x00a1, 0x00a1,
+ 0x00a7, 0x00a7,
+ 0x00ab, 0x00ab,
+ 0x00b6, 0x00b7,
+ 0x00bb, 0x00bb,
+ 0x00bf, 0x00bf,
+ 0x037e, 0x037e,
+ 0x0387, 0x0387,
+ 0x055a, 0x055f,
+ 0x0589, 0x058a,
+ 0x05be, 0x05be,
+ 0x05c0, 0x05c0,
+ 0x05c3, 0x05c3,
+ 0x05c6, 0x05c6,
+ 0x05f3, 0x05f4,
+ 0x0609, 0x060a,
+ 0x060c, 0x060d,
+ 0x061b, 0x061b,
+ 0x061d, 0x061f,
+ 0x066a, 0x066d,
+ 0x06d4, 0x06d4,
+ 0x0700, 0x070d,
+ 0x07f7, 0x07f9,
+ 0x0830, 0x083e,
+ 0x085e, 0x085e,
+ 0x0964, 0x0965,
+ 0x0970, 0x0970,
+ 0x09fd, 0x09fd,
+ 0x0a76, 0x0a76,
+ 0x0af0, 0x0af0,
+ 0x0c77, 0x0c77,
+ 0x0c84, 0x0c84,
+ 0x0df4, 0x0df4,
+ 0x0e4f, 0x0e4f,
+ 0x0e5a, 0x0e5b,
+ 0x0f04, 0x0f12,
+ 0x0f14, 0x0f14,
+ 0x0f3a, 0x0f3d,
+ 0x0f85, 0x0f85,
+ 0x0fd0, 0x0fd4,
+ 0x0fd9, 0x0fda,
+ 0x104a, 0x104f,
+ 0x10fb, 0x10fb,
+ 0x1360, 0x1368,
+ 0x1400, 0x1400,
+ 0x166e, 0x166e,
+ 0x169b, 0x169c,
+ 0x16eb, 0x16ed,
+ 0x1735, 0x1736,
+ 0x17d4, 0x17d6,
+ 0x17d8, 0x17da,
+ 0x1800, 0x180a,
+ 0x1944, 0x1945,
+ 0x1a1e, 0x1a1f,
+ 0x1aa0, 0x1aa6,
+ 0x1aa8, 0x1aad,
+ 0x1b4e, 0x1b4f,
+ 0x1b5a, 0x1b60,
+ 0x1b7d, 0x1b7f,
+ 0x1bfc, 0x1bff,
+ 0x1c3b, 0x1c3f,
+ 0x1c7e, 0x1c7f,
+ 0x1cc0, 0x1cc7,
+ 0x1cd3, 0x1cd3,
+ 0x2010, 0x2027,
+ 0x2030, 0x2043,
+ 0x2045, 0x2051,
+ 0x2053, 0x205e,
+ 0x207d, 0x207e,
+ 0x208d, 0x208e,
+ 0x2308, 0x230b,
+ 0x2329, 0x232a,
+ 0x2768, 0x2775,
+ 0x27c5, 0x27c6,
+ 0x27e6, 0x27ef,
+ 0x2983, 0x2998,
+ 0x29d8, 0x29db,
+ 0x29fc, 0x29fd,
+ 0x2cf9, 0x2cfc,
+ 0x2cfe, 0x2cff,
+ 0x2d70, 0x2d70,
+ 0x2e00, 0x2e2e,
+ 0x2e30, 0x2e4f,
+ 0x2e52, 0x2e5d,
+ 0x3001, 0x3003,
+ 0x3008, 0x3011,
+ 0x3014, 0x301f,
+ 0x3030, 0x3030,
+ 0x303d, 0x303d,
+ 0x30a0, 0x30a0,
+ 0x30fb, 0x30fb,
+ 0xa4fe, 0xa4ff,
+ 0xa60d, 0xa60f,
+ 0xa673, 0xa673,
+ 0xa67e, 0xa67e,
+ 0xa6f2, 0xa6f7,
+ 0xa874, 0xa877,
+ 0xa8ce, 0xa8cf,
+ 0xa8f8, 0xa8fa,
+ 0xa8fc, 0xa8fc,
+ 0xa92e, 0xa92f,
+ 0xa95f, 0xa95f,
+ 0xa9c1, 0xa9cd,
+ 0xa9de, 0xa9df,
+ 0xaa5c, 0xaa5f,
+ 0xaade, 0xaadf,
+ 0xaaf0, 0xaaf1,
+ 0xabeb, 0xabeb,
+ 0xfd3e, 0xfd3f,
+ 0xfe10, 0xfe19,
+ 0xfe30, 0xfe52,
+ 0xfe54, 0xfe61,
+ 0xfe63, 0xfe63,
+ 0xfe68, 0xfe68,
+ 0xfe6a, 0xfe6b,
+ 0xff01, 0xff03,
+ 0xff05, 0xff0a,
+ 0xff0c, 0xff0f,
+ 0xff1a, 0xff1b,
+ 0xff1f, 0xff20,
+ 0xff3b, 0xff3d,
+ 0xff3f, 0xff3f,
+ 0xff5b, 0xff5b,
+ 0xff5d, 0xff5d,
+ 0xff5f, 0xff65,
+ 0x10100, 0x10102,
+ 0x1039f, 0x1039f,
+ 0x103d0, 0x103d0,
+ 0x1056f, 0x1056f,
+ 0x10857, 0x10857,
+ 0x1091f, 0x1091f,
+ 0x1093f, 0x1093f,
+ 0x10a50, 0x10a58,
+ 0x10a7f, 0x10a7f,
+ 0x10af0, 0x10af6,
+ 0x10b39, 0x10b3f,
+ 0x10b99, 0x10b9c,
+ 0x10d6e, 0x10d6e,
+ 0x10ead, 0x10ead,
+ 0x10ed0, 0x10ed0,
+ 0x10f55, 0x10f59,
+ 0x10f86, 0x10f89,
+ 0x11047, 0x1104d,
+ 0x110bb, 0x110bc,
+ 0x110be, 0x110c1,
+ 0x11140, 0x11143,
+ 0x11174, 0x11175,
+ 0x111c5, 0x111c8,
+ 0x111cd, 0x111cd,
+ 0x111db, 0x111db,
+ 0x111dd, 0x111df,
+ 0x11238, 0x1123d,
+ 0x112a9, 0x112a9,
+ 0x113d4, 0x113d5,
+ 0x113d7, 0x113d8,
+ 0x1144b, 0x1144f,
+ 0x1145a, 0x1145b,
+ 0x1145d, 0x1145d,
+ 0x114c6, 0x114c6,
+ 0x115c1, 0x115d7,
+ 0x11641, 0x11643,
+ 0x11660, 0x1166c,
+ 0x116b9, 0x116b9,
+ 0x1173c, 0x1173e,
+ 0x1183b, 0x1183b,
+ 0x11944, 0x11946,
+ 0x119e2, 0x119e2,
+ 0x11a3f, 0x11a46,
+ 0x11a9a, 0x11a9c,
+ 0x11a9e, 0x11aa2,
+ 0x11b00, 0x11b09,
+ 0x11be1, 0x11be1,
+ 0x11c41, 0x11c45,
+ 0x11c70, 0x11c71,
+ 0x11ef7, 0x11ef8,
+ 0x11f43, 0x11f4f,
+ 0x11fff, 0x11fff,
+ 0x12470, 0x12474,
+ 0x12ff1, 0x12ff2,
+ 0x16a6e, 0x16a6f,
+ 0x16af5, 0x16af5,
+ 0x16b37, 0x16b3b,
+ 0x16b44, 0x16b44,
+ 0x16d6d, 0x16d6f,
+ 0x16e97, 0x16e9a,
+ 0x16fe2, 0x16fe2,
+ 0x1bc9f, 0x1bc9f,
+ 0x1da87, 0x1da8b,
+ 0x1e5ff, 0x1e5ff,
+ 0x1e95e, 0x1e95f,
+}; /* CR_XPosixPunct */
+
+/* 'Space': [[:Space:]] */
+static const OnigCodePoint CR_Space[] = {
+ 10,
+ 0x0009, 0x000d,
+ 0x0020, 0x0020,
+ 0x0085, 0x0085,
+ 0x00a0, 0x00a0,
+ 0x1680, 0x1680,
+ 0x2000, 0x200a,
+ 0x2028, 0x2029,
+ 0x202f, 0x202f,
+ 0x205f, 0x205f,
+ 0x3000, 0x3000,
+}; /* CR_Space */
+
+/* 'Upper': [[:Upper:]] */
+static const OnigCodePoint CR_Upper[] = {
+ 660,
+ 0x0041, 0x005a,
+ 0x00c0, 0x00d6,
+ 0x00d8, 0x00de,
+ 0x0100, 0x0100,
+ 0x0102, 0x0102,
+ 0x0104, 0x0104,
+ 0x0106, 0x0106,
+ 0x0108, 0x0108,
+ 0x010a, 0x010a,
+ 0x010c, 0x010c,
+ 0x010e, 0x010e,
+ 0x0110, 0x0110,
+ 0x0112, 0x0112,
+ 0x0114, 0x0114,
+ 0x0116, 0x0116,
+ 0x0118, 0x0118,
+ 0x011a, 0x011a,
+ 0x011c, 0x011c,
+ 0x011e, 0x011e,
+ 0x0120, 0x0120,
+ 0x0122, 0x0122,
+ 0x0124, 0x0124,
+ 0x0126, 0x0126,
+ 0x0128, 0x0128,
+ 0x012a, 0x012a,
+ 0x012c, 0x012c,
+ 0x012e, 0x012e,
+ 0x0130, 0x0130,
+ 0x0132, 0x0132,
+ 0x0134, 0x0134,
+ 0x0136, 0x0136,
+ 0x0139, 0x0139,
+ 0x013b, 0x013b,
+ 0x013d, 0x013d,
+ 0x013f, 0x013f,
+ 0x0141, 0x0141,
+ 0x0143, 0x0143,
+ 0x0145, 0x0145,
+ 0x0147, 0x0147,
+ 0x014a, 0x014a,
+ 0x014c, 0x014c,
+ 0x014e, 0x014e,
+ 0x0150, 0x0150,
+ 0x0152, 0x0152,
+ 0x0154, 0x0154,
+ 0x0156, 0x0156,
+ 0x0158, 0x0158,
+ 0x015a, 0x015a,
+ 0x015c, 0x015c,
+ 0x015e, 0x015e,
+ 0x0160, 0x0160,
+ 0x0162, 0x0162,
+ 0x0164, 0x0164,
+ 0x0166, 0x0166,
+ 0x0168, 0x0168,
+ 0x016a, 0x016a,
+ 0x016c, 0x016c,
+ 0x016e, 0x016e,
+ 0x0170, 0x0170,
+ 0x0172, 0x0172,
+ 0x0174, 0x0174,
+ 0x0176, 0x0176,
+ 0x0178, 0x0179,
+ 0x017b, 0x017b,
+ 0x017d, 0x017d,
+ 0x0181, 0x0182,
+ 0x0184, 0x0184,
+ 0x0186, 0x0187,
+ 0x0189, 0x018b,
+ 0x018e, 0x0191,
+ 0x0193, 0x0194,
+ 0x0196, 0x0198,
+ 0x019c, 0x019d,
+ 0x019f, 0x01a0,
+ 0x01a2, 0x01a2,
+ 0x01a4, 0x01a4,
+ 0x01a6, 0x01a7,
+ 0x01a9, 0x01a9,
+ 0x01ac, 0x01ac,
+ 0x01ae, 0x01af,
+ 0x01b1, 0x01b3,
+ 0x01b5, 0x01b5,
+ 0x01b7, 0x01b8,
+ 0x01bc, 0x01bc,
+ 0x01c4, 0x01c4,
+ 0x01c7, 0x01c7,
+ 0x01ca, 0x01ca,
+ 0x01cd, 0x01cd,
+ 0x01cf, 0x01cf,
+ 0x01d1, 0x01d1,
+ 0x01d3, 0x01d3,
+ 0x01d5, 0x01d5,
+ 0x01d7, 0x01d7,
+ 0x01d9, 0x01d9,
+ 0x01db, 0x01db,
+ 0x01de, 0x01de,
+ 0x01e0, 0x01e0,
+ 0x01e2, 0x01e2,
+ 0x01e4, 0x01e4,
+ 0x01e6, 0x01e6,
+ 0x01e8, 0x01e8,
+ 0x01ea, 0x01ea,
+ 0x01ec, 0x01ec,
+ 0x01ee, 0x01ee,
+ 0x01f1, 0x01f1,
+ 0x01f4, 0x01f4,
+ 0x01f6, 0x01f8,
+ 0x01fa, 0x01fa,
+ 0x01fc, 0x01fc,
+ 0x01fe, 0x01fe,
+ 0x0200, 0x0200,
+ 0x0202, 0x0202,
+ 0x0204, 0x0204,
+ 0x0206, 0x0206,
+ 0x0208, 0x0208,
+ 0x020a, 0x020a,
+ 0x020c, 0x020c,
+ 0x020e, 0x020e,
+ 0x0210, 0x0210,
+ 0x0212, 0x0212,
+ 0x0214, 0x0214,
+ 0x0216, 0x0216,
+ 0x0218, 0x0218,
+ 0x021a, 0x021a,
+ 0x021c, 0x021c,
+ 0x021e, 0x021e,
+ 0x0220, 0x0220,
+ 0x0222, 0x0222,
+ 0x0224, 0x0224,
+ 0x0226, 0x0226,
+ 0x0228, 0x0228,
+ 0x022a, 0x022a,
+ 0x022c, 0x022c,
+ 0x022e, 0x022e,
+ 0x0230, 0x0230,
+ 0x0232, 0x0232,
+ 0x023a, 0x023b,
+ 0x023d, 0x023e,
+ 0x0241, 0x0241,
+ 0x0243, 0x0246,
+ 0x0248, 0x0248,
+ 0x024a, 0x024a,
+ 0x024c, 0x024c,
+ 0x024e, 0x024e,
+ 0x0370, 0x0370,
+ 0x0372, 0x0372,
+ 0x0376, 0x0376,
+ 0x037f, 0x037f,
+ 0x0386, 0x0386,
+ 0x0388, 0x038a,
+ 0x038c, 0x038c,
+ 0x038e, 0x038f,
+ 0x0391, 0x03a1,
+ 0x03a3, 0x03ab,
+ 0x03cf, 0x03cf,
+ 0x03d2, 0x03d4,
+ 0x03d8, 0x03d8,
+ 0x03da, 0x03da,
+ 0x03dc, 0x03dc,
+ 0x03de, 0x03de,
+ 0x03e0, 0x03e0,
+ 0x03e2, 0x03e2,
+ 0x03e4, 0x03e4,
+ 0x03e6, 0x03e6,
+ 0x03e8, 0x03e8,
+ 0x03ea, 0x03ea,
+ 0x03ec, 0x03ec,
+ 0x03ee, 0x03ee,
+ 0x03f4, 0x03f4,
+ 0x03f7, 0x03f7,
+ 0x03f9, 0x03fa,
+ 0x03fd, 0x042f,
+ 0x0460, 0x0460,
+ 0x0462, 0x0462,
+ 0x0464, 0x0464,
+ 0x0466, 0x0466,
+ 0x0468, 0x0468,
+ 0x046a, 0x046a,
+ 0x046c, 0x046c,
+ 0x046e, 0x046e,
+ 0x0470, 0x0470,
+ 0x0472, 0x0472,
+ 0x0474, 0x0474,
+ 0x0476, 0x0476,
+ 0x0478, 0x0478,
+ 0x047a, 0x047a,
+ 0x047c, 0x047c,
+ 0x047e, 0x047e,
+ 0x0480, 0x0480,
+ 0x048a, 0x048a,
+ 0x048c, 0x048c,
+ 0x048e, 0x048e,
+ 0x0490, 0x0490,
+ 0x0492, 0x0492,
+ 0x0494, 0x0494,
+ 0x0496, 0x0496,
+ 0x0498, 0x0498,
+ 0x049a, 0x049a,
+ 0x049c, 0x049c,
+ 0x049e, 0x049e,
+ 0x04a0, 0x04a0,
+ 0x04a2, 0x04a2,
+ 0x04a4, 0x04a4,
+ 0x04a6, 0x04a6,
+ 0x04a8, 0x04a8,
+ 0x04aa, 0x04aa,
+ 0x04ac, 0x04ac,
+ 0x04ae, 0x04ae,
+ 0x04b0, 0x04b0,
+ 0x04b2, 0x04b2,
+ 0x04b4, 0x04b4,
+ 0x04b6, 0x04b6,
+ 0x04b8, 0x04b8,
+ 0x04ba, 0x04ba,
+ 0x04bc, 0x04bc,
+ 0x04be, 0x04be,
+ 0x04c0, 0x04c1,
+ 0x04c3, 0x04c3,
+ 0x04c5, 0x04c5,
+ 0x04c7, 0x04c7,
+ 0x04c9, 0x04c9,
+ 0x04cb, 0x04cb,
+ 0x04cd, 0x04cd,
+ 0x04d0, 0x04d0,
+ 0x04d2, 0x04d2,
+ 0x04d4, 0x04d4,
+ 0x04d6, 0x04d6,
+ 0x04d8, 0x04d8,
+ 0x04da, 0x04da,
+ 0x04dc, 0x04dc,
+ 0x04de, 0x04de,
+ 0x04e0, 0x04e0,
+ 0x04e2, 0x04e2,
+ 0x04e4, 0x04e4,
+ 0x04e6, 0x04e6,
+ 0x04e8, 0x04e8,
+ 0x04ea, 0x04ea,
+ 0x04ec, 0x04ec,
+ 0x04ee, 0x04ee,
+ 0x04f0, 0x04f0,
+ 0x04f2, 0x04f2,
+ 0x04f4, 0x04f4,
+ 0x04f6, 0x04f6,
+ 0x04f8, 0x04f8,
+ 0x04fa, 0x04fa,
+ 0x04fc, 0x04fc,
+ 0x04fe, 0x04fe,
+ 0x0500, 0x0500,
+ 0x0502, 0x0502,
+ 0x0504, 0x0504,
+ 0x0506, 0x0506,
+ 0x0508, 0x0508,
+ 0x050a, 0x050a,
+ 0x050c, 0x050c,
+ 0x050e, 0x050e,
+ 0x0510, 0x0510,
+ 0x0512, 0x0512,
+ 0x0514, 0x0514,
+ 0x0516, 0x0516,
+ 0x0518, 0x0518,
+ 0x051a, 0x051a,
+ 0x051c, 0x051c,
+ 0x051e, 0x051e,
+ 0x0520, 0x0520,
+ 0x0522, 0x0522,
+ 0x0524, 0x0524,
+ 0x0526, 0x0526,
+ 0x0528, 0x0528,
+ 0x052a, 0x052a,
+ 0x052c, 0x052c,
+ 0x052e, 0x052e,
+ 0x0531, 0x0556,
+ 0x10a0, 0x10c5,
+ 0x10c7, 0x10c7,
+ 0x10cd, 0x10cd,
+ 0x13a0, 0x13f5,
+ 0x1c89, 0x1c89,
+ 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,
+ 0x1fb8, 0x1fbb,
+ 0x1fc8, 0x1fcb,
+ 0x1fd8, 0x1fdb,
+ 0x1fe8, 0x1fec,
+ 0x1ff8, 0x1ffb,
+ 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,
+ 0xa7cb, 0xa7cc,
+ 0xa7ce, 0xa7ce,
+ 0xa7d0, 0xa7d0,
+ 0xa7d2, 0xa7d2,
+ 0xa7d4, 0xa7d4,
+ 0xa7d6, 0xa7d6,
+ 0xa7d8, 0xa7d8,
+ 0xa7da, 0xa7da,
+ 0xa7dc, 0xa7dc,
+ 0xa7f5, 0xa7f5,
+ 0xff21, 0xff3a,
+ 0x10400, 0x10427,
+ 0x104b0, 0x104d3,
+ 0x10570, 0x1057a,
+ 0x1057c, 0x1058a,
+ 0x1058c, 0x10592,
+ 0x10594, 0x10595,
+ 0x10c80, 0x10cb2,
+ 0x10d50, 0x10d65,
+ 0x118a0, 0x118bf,
+ 0x16e40, 0x16e5f,
+ 0x16ea0, 0x16eb8,
+ 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,
+}; /* CR_Upper */
+
+/* 'XDigit': [[:XDigit:]] */
+static const OnigCodePoint CR_XDigit[] = {
+ 3,
+ 0x0030, 0x0039,
+ 0x0041, 0x0046,
+ 0x0061, 0x0066,
+}; /* CR_XDigit */
+
+/* 'Word': [[:Word:]] */
+static const OnigCodePoint CR_Word[] = {
+ 802,
+ 0x0030, 0x0039,
+ 0x0041, 0x005a,
+ 0x005f, 0x005f,
+ 0x0061, 0x007a,
+ 0x00aa, 0x00aa,
+ 0x00b5, 0x00b5,
+ 0x00ba, 0x00ba,
+ 0x00c0, 0x00d6,
+ 0x00d8, 0x00f6,
+ 0x00f8, 0x02c1,
+ 0x02c6, 0x02d1,
+ 0x02e0, 0x02e4,
+ 0x02ec, 0x02ec,
+ 0x02ee, 0x02ee,
+ 0x0300, 0x0374,
+ 0x0376, 0x0377,
+ 0x037a, 0x037d,
+ 0x037f, 0x037f,
+ 0x0386, 0x0386,
+ 0x0388, 0x038a,
+ 0x038c, 0x038c,
+ 0x038e, 0x03a1,
+ 0x03a3, 0x03f5,
+ 0x03f7, 0x0481,
+ 0x0483, 0x052f,
+ 0x0531, 0x0556,
+ 0x0559, 0x0559,
+ 0x0560, 0x0588,
+ 0x0591, 0x05bd,
+ 0x05bf, 0x05bf,
+ 0x05c1, 0x05c2,
+ 0x05c4, 0x05c5,
+ 0x05c7, 0x05c7,
+ 0x05d0, 0x05ea,
+ 0x05ef, 0x05f2,
+ 0x0610, 0x061a,
+ 0x0620, 0x0669,
+ 0x066e, 0x06d3,
+ 0x06d5, 0x06dc,
+ 0x06df, 0x06e8,
+ 0x06ea, 0x06fc,
+ 0x06ff, 0x06ff,
+ 0x0710, 0x074a,
+ 0x074d, 0x07b1,
+ 0x07c0, 0x07f5,
+ 0x07fa, 0x07fa,
+ 0x07fd, 0x07fd,
+ 0x0800, 0x082d,
+ 0x0840, 0x085b,
+ 0x0860, 0x086a,
+ 0x0870, 0x0887,
+ 0x0889, 0x088f,
+ 0x0897, 0x08e1,
+ 0x08e3, 0x0963,
+ 0x0966, 0x096f,
+ 0x0971, 0x0983,
+ 0x0985, 0x098c,
+ 0x098f, 0x0990,
+ 0x0993, 0x09a8,
+ 0x09aa, 0x09b0,
+ 0x09b2, 0x09b2,
+ 0x09b6, 0x09b9,
+ 0x09bc, 0x09c4,
+ 0x09c7, 0x09c8,
+ 0x09cb, 0x09ce,
+ 0x09d7, 0x09d7,
+ 0x09dc, 0x09dd,
+ 0x09df, 0x09e3,
+ 0x09e6, 0x09f1,
+ 0x09fc, 0x09fc,
+ 0x09fe, 0x09fe,
+ 0x0a01, 0x0a03,
+ 0x0a05, 0x0a0a,
+ 0x0a0f, 0x0a10,
+ 0x0a13, 0x0a28,
+ 0x0a2a, 0x0a30,
+ 0x0a32, 0x0a33,
+ 0x0a35, 0x0a36,
+ 0x0a38, 0x0a39,
+ 0x0a3c, 0x0a3c,
+ 0x0a3e, 0x0a42,
+ 0x0a47, 0x0a48,
+ 0x0a4b, 0x0a4d,
+ 0x0a51, 0x0a51,
+ 0x0a59, 0x0a5c,
+ 0x0a5e, 0x0a5e,
+ 0x0a66, 0x0a75,
+ 0x0a81, 0x0a83,
+ 0x0a85, 0x0a8d,
+ 0x0a8f, 0x0a91,
+ 0x0a93, 0x0aa8,
+ 0x0aaa, 0x0ab0,
+ 0x0ab2, 0x0ab3,
+ 0x0ab5, 0x0ab9,
+ 0x0abc, 0x0ac5,
+ 0x0ac7, 0x0ac9,
+ 0x0acb, 0x0acd,
+ 0x0ad0, 0x0ad0,
+ 0x0ae0, 0x0ae3,
+ 0x0ae6, 0x0aef,
+ 0x0af9, 0x0aff,
+ 0x0b01, 0x0b03,
+ 0x0b05, 0x0b0c,
+ 0x0b0f, 0x0b10,
+ 0x0b13, 0x0b28,
+ 0x0b2a, 0x0b30,
+ 0x0b32, 0x0b33,
+ 0x0b35, 0x0b39,
+ 0x0b3c, 0x0b44,
+ 0x0b47, 0x0b48,
+ 0x0b4b, 0x0b4d,
+ 0x0b55, 0x0b57,
+ 0x0b5c, 0x0b5d,
+ 0x0b5f, 0x0b63,
+ 0x0b66, 0x0b6f,
+ 0x0b71, 0x0b71,
+ 0x0b82, 0x0b83,
+ 0x0b85, 0x0b8a,
+ 0x0b8e, 0x0b90,
+ 0x0b92, 0x0b95,
+ 0x0b99, 0x0b9a,
+ 0x0b9c, 0x0b9c,
+ 0x0b9e, 0x0b9f,
+ 0x0ba3, 0x0ba4,
+ 0x0ba8, 0x0baa,
+ 0x0bae, 0x0bb9,
+ 0x0bbe, 0x0bc2,
+ 0x0bc6, 0x0bc8,
+ 0x0bca, 0x0bcd,
+ 0x0bd0, 0x0bd0,
+ 0x0bd7, 0x0bd7,
+ 0x0be6, 0x0bef,
+ 0x0c00, 0x0c0c,
+ 0x0c0e, 0x0c10,
+ 0x0c12, 0x0c28,
+ 0x0c2a, 0x0c39,
+ 0x0c3c, 0x0c44,
+ 0x0c46, 0x0c48,
+ 0x0c4a, 0x0c4d,
+ 0x0c55, 0x0c56,
+ 0x0c58, 0x0c5a,
+ 0x0c5c, 0x0c5d,
+ 0x0c60, 0x0c63,
+ 0x0c66, 0x0c6f,
+ 0x0c80, 0x0c83,
+ 0x0c85, 0x0c8c,
+ 0x0c8e, 0x0c90,
+ 0x0c92, 0x0ca8,
+ 0x0caa, 0x0cb3,
+ 0x0cb5, 0x0cb9,
+ 0x0cbc, 0x0cc4,
+ 0x0cc6, 0x0cc8,
+ 0x0cca, 0x0ccd,
+ 0x0cd5, 0x0cd6,
+ 0x0cdc, 0x0cde,
+ 0x0ce0, 0x0ce3,
+ 0x0ce6, 0x0cef,
+ 0x0cf1, 0x0cf3,
+ 0x0d00, 0x0d0c,
+ 0x0d0e, 0x0d10,
+ 0x0d12, 0x0d44,
+ 0x0d46, 0x0d48,
+ 0x0d4a, 0x0d4e,
+ 0x0d54, 0x0d57,
+ 0x0d5f, 0x0d63,
+ 0x0d66, 0x0d6f,
+ 0x0d7a, 0x0d7f,
+ 0x0d81, 0x0d83,
+ 0x0d85, 0x0d96,
+ 0x0d9a, 0x0db1,
+ 0x0db3, 0x0dbb,
+ 0x0dbd, 0x0dbd,
+ 0x0dc0, 0x0dc6,
+ 0x0dca, 0x0dca,
+ 0x0dcf, 0x0dd4,
+ 0x0dd6, 0x0dd6,
+ 0x0dd8, 0x0ddf,
+ 0x0de6, 0x0def,
+ 0x0df2, 0x0df3,
+ 0x0e01, 0x0e3a,
+ 0x0e40, 0x0e4e,
+ 0x0e50, 0x0e59,
+ 0x0e81, 0x0e82,
+ 0x0e84, 0x0e84,
+ 0x0e86, 0x0e8a,
+ 0x0e8c, 0x0ea3,
+ 0x0ea5, 0x0ea5,
+ 0x0ea7, 0x0ebd,
+ 0x0ec0, 0x0ec4,
+ 0x0ec6, 0x0ec6,
+ 0x0ec8, 0x0ece,
+ 0x0ed0, 0x0ed9,
+ 0x0edc, 0x0edf,
+ 0x0f00, 0x0f00,
+ 0x0f18, 0x0f19,
+ 0x0f20, 0x0f29,
+ 0x0f35, 0x0f35,
+ 0x0f37, 0x0f37,
+ 0x0f39, 0x0f39,
+ 0x0f3e, 0x0f47,
+ 0x0f49, 0x0f6c,
+ 0x0f71, 0x0f84,
+ 0x0f86, 0x0f97,
+ 0x0f99, 0x0fbc,
+ 0x0fc6, 0x0fc6,
+ 0x1000, 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,
+ 0x135d, 0x135f,
+ 0x1380, 0x138f,
+ 0x13a0, 0x13f5,
+ 0x13f8, 0x13fd,
+ 0x1401, 0x166c,
+ 0x166f, 0x167f,
+ 0x1681, 0x169a,
+ 0x16a0, 0x16ea,
+ 0x16ee, 0x16f8,
+ 0x1700, 0x1715,
+ 0x171f, 0x1734,
+ 0x1740, 0x1753,
+ 0x1760, 0x176c,
+ 0x176e, 0x1770,
+ 0x1772, 0x1773,
+ 0x1780, 0x17d3,
+ 0x17d7, 0x17d7,
+ 0x17dc, 0x17dd,
+ 0x17e0, 0x17e9,
+ 0x180b, 0x180d,
+ 0x180f, 0x1819,
+ 0x1820, 0x1878,
+ 0x1880, 0x18aa,
+ 0x18b0, 0x18f5,
+ 0x1900, 0x191e,
+ 0x1920, 0x192b,
+ 0x1930, 0x193b,
+ 0x1946, 0x196d,
+ 0x1970, 0x1974,
+ 0x1980, 0x19ab,
+ 0x19b0, 0x19c9,
+ 0x19d0, 0x19d9,
+ 0x1a00, 0x1a1b,
+ 0x1a20, 0x1a5e,
+ 0x1a60, 0x1a7c,
+ 0x1a7f, 0x1a89,
+ 0x1a90, 0x1a99,
+ 0x1aa7, 0x1aa7,
+ 0x1ab0, 0x1add,
+ 0x1ae0, 0x1aeb,
+ 0x1b00, 0x1b4c,
+ 0x1b50, 0x1b59,
+ 0x1b6b, 0x1b73,
+ 0x1b80, 0x1bf3,
+ 0x1c00, 0x1c37,
+ 0x1c40, 0x1c49,
+ 0x1c4d, 0x1c7d,
+ 0x1c80, 0x1c8a,
+ 0x1c90, 0x1cba,
+ 0x1cbd, 0x1cbf,
+ 0x1cd0, 0x1cd2,
+ 0x1cd4, 0x1cfa,
+ 0x1d00, 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,
+ 0x200c, 0x200d,
+ 0x203f, 0x2040,
+ 0x2054, 0x2054,
+ 0x2071, 0x2071,
+ 0x207f, 0x207f,
+ 0x2090, 0x209c,
+ 0x20d0, 0x20f0,
+ 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, 0x2cf3,
+ 0x2d00, 0x2d25,
+ 0x2d27, 0x2d27,
+ 0x2d2d, 0x2d2d,
+ 0x2d30, 0x2d67,
+ 0x2d6f, 0x2d6f,
+ 0x2d7f, 0x2d96,
+ 0x2da0, 0x2da6,
+ 0x2da8, 0x2dae,
+ 0x2db0, 0x2db6,
+ 0x2db8, 0x2dbe,
+ 0x2dc0, 0x2dc6,
+ 0x2dc8, 0x2dce,
+ 0x2dd0, 0x2dd6,
+ 0x2dd8, 0x2dde,
+ 0x2de0, 0x2dff,
+ 0x2e2f, 0x2e2f,
+ 0x3005, 0x3007,
+ 0x3021, 0x302f,
+ 0x3031, 0x3035,
+ 0x3038, 0x303c,
+ 0x3041, 0x3096,
+ 0x3099, 0x309a,
+ 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, 0xa672,
+ 0xa674, 0xa67d,
+ 0xa67f, 0xa6f1,
+ 0xa717, 0xa71f,
+ 0xa722, 0xa788,
+ 0xa78b, 0xa7dc,
+ 0xa7f1, 0xa827,
+ 0xa82c, 0xa82c,
+ 0xa840, 0xa873,
+ 0xa880, 0xa8c5,
+ 0xa8d0, 0xa8d9,
+ 0xa8e0, 0xa8f7,
+ 0xa8fb, 0xa8fb,
+ 0xa8fd, 0xa92d,
+ 0xa930, 0xa953,
+ 0xa960, 0xa97c,
+ 0xa980, 0xa9c0,
+ 0xa9cf, 0xa9d9,
+ 0xa9e0, 0xa9fe,
+ 0xaa00, 0xaa36,
+ 0xaa40, 0xaa4d,
+ 0xaa50, 0xaa59,
+ 0xaa60, 0xaa76,
+ 0xaa7a, 0xaac2,
+ 0xaadb, 0xaadd,
+ 0xaae0, 0xaaef,
+ 0xaaf2, 0xaaf6,
+ 0xab01, 0xab06,
+ 0xab09, 0xab0e,
+ 0xab11, 0xab16,
+ 0xab20, 0xab26,
+ 0xab28, 0xab2e,
+ 0xab30, 0xab5a,
+ 0xab5c, 0xab69,
+ 0xab70, 0xabea,
+ 0xabec, 0xabed,
+ 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,
+ 0xfe00, 0xfe0f,
+ 0xfe20, 0xfe2f,
+ 0xfe33, 0xfe34,
+ 0xfe4d, 0xfe4f,
+ 0xfe70, 0xfe74,
+ 0xfe76, 0xfefc,
+ 0xff10, 0xff19,
+ 0xff21, 0xff3a,
+ 0xff3f, 0xff3f,
+ 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,
+ 0x101fd, 0x101fd,
+ 0x10280, 0x1029c,
+ 0x102a0, 0x102d0,
+ 0x102e0, 0x102e0,
+ 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,
+ 0x105c0, 0x105f3,
+ 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,
+ 0x10940, 0x10959,
+ 0x10980, 0x109b7,
+ 0x109be, 0x109bf,
+ 0x10a00, 0x10a03,
+ 0x10a05, 0x10a06,
+ 0x10a0c, 0x10a13,
+ 0x10a15, 0x10a17,
+ 0x10a19, 0x10a35,
+ 0x10a38, 0x10a3a,
+ 0x10a3f, 0x10a3f,
+ 0x10a60, 0x10a7c,
+ 0x10a80, 0x10a9c,
+ 0x10ac0, 0x10ac7,
+ 0x10ac9, 0x10ae6,
+ 0x10b00, 0x10b35,
+ 0x10b40, 0x10b55,
+ 0x10b60, 0x10b72,
+ 0x10b80, 0x10b91,
+ 0x10c00, 0x10c48,
+ 0x10c80, 0x10cb2,
+ 0x10cc0, 0x10cf2,
+ 0x10d00, 0x10d27,
+ 0x10d30, 0x10d39,
+ 0x10d40, 0x10d65,
+ 0x10d69, 0x10d6d,
+ 0x10d6f, 0x10d85,
+ 0x10e80, 0x10ea9,
+ 0x10eab, 0x10eac,
+ 0x10eb0, 0x10eb1,
+ 0x10ec2, 0x10ec7,
+ 0x10efa, 0x10f1c,
+ 0x10f27, 0x10f27,
+ 0x10f30, 0x10f50,
+ 0x10f70, 0x10f85,
+ 0x10fb0, 0x10fc4,
+ 0x10fe0, 0x10ff6,
+ 0x11000, 0x11046,
+ 0x11066, 0x11075,
+ 0x1107f, 0x110ba,
+ 0x110c2, 0x110c2,
+ 0x110d0, 0x110e8,
+ 0x110f0, 0x110f9,
+ 0x11100, 0x11134,
+ 0x11136, 0x1113f,
+ 0x11144, 0x11147,
+ 0x11150, 0x11173,
+ 0x11176, 0x11176,
+ 0x11180, 0x111c4,
+ 0x111c9, 0x111cc,
+ 0x111ce, 0x111da,
+ 0x111dc, 0x111dc,
+ 0x11200, 0x11211,
+ 0x11213, 0x11237,
+ 0x1123e, 0x11241,
+ 0x11280, 0x11286,
+ 0x11288, 0x11288,
+ 0x1128a, 0x1128d,
+ 0x1128f, 0x1129d,
+ 0x1129f, 0x112a8,
+ 0x112b0, 0x112ea,
+ 0x112f0, 0x112f9,
+ 0x11300, 0x11303,
+ 0x11305, 0x1130c,
+ 0x1130f, 0x11310,
+ 0x11313, 0x11328,
+ 0x1132a, 0x11330,
+ 0x11332, 0x11333,
+ 0x11335, 0x11339,
+ 0x1133b, 0x11344,
+ 0x11347, 0x11348,
+ 0x1134b, 0x1134d,
+ 0x11350, 0x11350,
+ 0x11357, 0x11357,
+ 0x1135d, 0x11363,
+ 0x11366, 0x1136c,
+ 0x11370, 0x11374,
+ 0x11380, 0x11389,
+ 0x1138b, 0x1138b,
+ 0x1138e, 0x1138e,
+ 0x11390, 0x113b5,
+ 0x113b7, 0x113c0,
+ 0x113c2, 0x113c2,
+ 0x113c5, 0x113c5,
+ 0x113c7, 0x113ca,
+ 0x113cc, 0x113d3,
+ 0x113e1, 0x113e2,
+ 0x11400, 0x1144a,
+ 0x11450, 0x11459,
+ 0x1145e, 0x11461,
+ 0x11480, 0x114c5,
+ 0x114c7, 0x114c7,
+ 0x114d0, 0x114d9,
+ 0x11580, 0x115b5,
+ 0x115b8, 0x115c0,
+ 0x115d8, 0x115dd,
+ 0x11600, 0x11640,
+ 0x11644, 0x11644,
+ 0x11650, 0x11659,
+ 0x11680, 0x116b8,
+ 0x116c0, 0x116c9,
+ 0x116d0, 0x116e3,
+ 0x11700, 0x1171a,
+ 0x1171d, 0x1172b,
+ 0x11730, 0x11739,
+ 0x11740, 0x11746,
+ 0x11800, 0x1183a,
+ 0x118a0, 0x118e9,
+ 0x118ff, 0x11906,
+ 0x11909, 0x11909,
+ 0x1190c, 0x11913,
+ 0x11915, 0x11916,
+ 0x11918, 0x11935,
+ 0x11937, 0x11938,
+ 0x1193b, 0x11943,
+ 0x11950, 0x11959,
+ 0x119a0, 0x119a7,
+ 0x119aa, 0x119d7,
+ 0x119da, 0x119e1,
+ 0x119e3, 0x119e4,
+ 0x11a00, 0x11a3e,
+ 0x11a47, 0x11a47,
+ 0x11a50, 0x11a99,
+ 0x11a9d, 0x11a9d,
+ 0x11ab0, 0x11af8,
+ 0x11b60, 0x11b67,
+ 0x11bc0, 0x11be0,
+ 0x11bf0, 0x11bf9,
+ 0x11c00, 0x11c08,
+ 0x11c0a, 0x11c36,
+ 0x11c38, 0x11c40,
+ 0x11c50, 0x11c59,
+ 0x11c72, 0x11c8f,
+ 0x11c92, 0x11ca7,
+ 0x11ca9, 0x11cb6,
+ 0x11d00, 0x11d06,
+ 0x11d08, 0x11d09,
+ 0x11d0b, 0x11d36,
+ 0x11d3a, 0x11d3a,
+ 0x11d3c, 0x11d3d,
+ 0x11d3f, 0x11d47,
+ 0x11d50, 0x11d59,
+ 0x11d60, 0x11d65,
+ 0x11d67, 0x11d68,
+ 0x11d6a, 0x11d8e,
+ 0x11d90, 0x11d91,
+ 0x11d93, 0x11d98,
+ 0x11da0, 0x11da9,
+ 0x11db0, 0x11ddb,
+ 0x11de0, 0x11de9,
+ 0x11ee0, 0x11ef6,
+ 0x11f00, 0x11f10,
+ 0x11f12, 0x11f3a,
+ 0x11f3e, 0x11f42,
+ 0x11f50, 0x11f5a,
+ 0x11fb0, 0x11fb0,
+ 0x12000, 0x12399,
+ 0x12400, 0x1246e,
+ 0x12480, 0x12543,
+ 0x12f90, 0x12ff0,
+ 0x13000, 0x1342f,
+ 0x13440, 0x13455,
+ 0x13460, 0x143fa,
+ 0x14400, 0x14646,
+ 0x16100, 0x16139,
+ 0x16800, 0x16a38,
+ 0x16a40, 0x16a5e,
+ 0x16a60, 0x16a69,
+ 0x16a70, 0x16abe,
+ 0x16ac0, 0x16ac9,
+ 0x16ad0, 0x16aed,
+ 0x16af0, 0x16af4,
+ 0x16b00, 0x16b36,
+ 0x16b40, 0x16b43,
+ 0x16b50, 0x16b59,
+ 0x16b63, 0x16b77,
+ 0x16b7d, 0x16b8f,
+ 0x16d40, 0x16d6c,
+ 0x16d70, 0x16d79,
+ 0x16e40, 0x16e7f,
+ 0x16ea0, 0x16eb8,
+ 0x16ebb, 0x16ed3,
+ 0x16f00, 0x16f4a,
+ 0x16f4f, 0x16f87,
+ 0x16f8f, 0x16f9f,
+ 0x16fe0, 0x16fe1,
+ 0x16fe3, 0x16fe4,
+ 0x16ff0, 0x16ff6,
+ 0x17000, 0x18cd5,
+ 0x18cff, 0x18d1e,
+ 0x18d80, 0x18df2,
+ 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,
+ 0x1bc9d, 0x1bc9e,
+ 0x1ccf0, 0x1ccf9,
+ 0x1cf00, 0x1cf2d,
+ 0x1cf30, 0x1cf46,
+ 0x1d165, 0x1d169,
+ 0x1d16d, 0x1d172,
+ 0x1d17b, 0x1d182,
+ 0x1d185, 0x1d18b,
+ 0x1d1aa, 0x1d1ad,
+ 0x1d242, 0x1d244,
+ 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,
+ 0x1da00, 0x1da36,
+ 0x1da3b, 0x1da6c,
+ 0x1da75, 0x1da75,
+ 0x1da84, 0x1da84,
+ 0x1da9b, 0x1da9f,
+ 0x1daa1, 0x1daaf,
+ 0x1df00, 0x1df1e,
+ 0x1df25, 0x1df2a,
+ 0x1e000, 0x1e006,
+ 0x1e008, 0x1e018,
+ 0x1e01b, 0x1e021,
+ 0x1e023, 0x1e024,
+ 0x1e026, 0x1e02a,
+ 0x1e030, 0x1e06d,
+ 0x1e08f, 0x1e08f,
+ 0x1e100, 0x1e12c,
+ 0x1e130, 0x1e13d,
+ 0x1e140, 0x1e149,
+ 0x1e14e, 0x1e14e,
+ 0x1e290, 0x1e2ae,
+ 0x1e2c0, 0x1e2f9,
+ 0x1e4d0, 0x1e4f9,
+ 0x1e5d0, 0x1e5fa,
+ 0x1e6c0, 0x1e6de,
+ 0x1e6e0, 0x1e6f5,
+ 0x1e6fe, 0x1e6ff,
+ 0x1e7e0, 0x1e7e6,
+ 0x1e7e8, 0x1e7eb,
+ 0x1e7ed, 0x1e7ee,
+ 0x1e7f0, 0x1e7fe,
+ 0x1e800, 0x1e8c4,
+ 0x1e8d0, 0x1e8d6,
+ 0x1e900, 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, 0x2b81d,
+ 0x2b820, 0x2cead,
+ 0x2ceb0, 0x2ebe0,
+ 0x2ebf0, 0x2ee5d,
+ 0x2f800, 0x2fa1d,
+ 0x30000, 0x3134a,
+ 0x31350, 0x33479,
+ 0xe0100, 0xe01ef,
+}; /* CR_Word */
+
+/* 'Alnum': [[:Alnum:]] */
+static const OnigCodePoint CR_Alnum[] = {
+ 807,
+ 0x0030, 0x0039,
+ 0x0041, 0x005a,
+ 0x0061, 0x007a,
+ 0x00aa, 0x00aa,
+ 0x00b5, 0x00b5,
+ 0x00ba, 0x00ba,
+ 0x00c0, 0x00d6,
+ 0x00d8, 0x00f6,
+ 0x00f8, 0x02c1,
+ 0x02c6, 0x02d1,
+ 0x02e0, 0x02e4,
+ 0x02ec, 0x02ec,
+ 0x02ee, 0x02ee,
+ 0x0345, 0x0345,
+ 0x0363, 0x0374,
+ 0x0376, 0x0377,
+ 0x037a, 0x037d,
+ 0x037f, 0x037f,
+ 0x0386, 0x0386,
+ 0x0388, 0x038a,
+ 0x038c, 0x038c,
+ 0x038e, 0x03a1,
+ 0x03a3, 0x03f5,
+ 0x03f7, 0x0481,
+ 0x048a, 0x052f,
+ 0x0531, 0x0556,
+ 0x0559, 0x0559,
+ 0x0560, 0x0588,
+ 0x05b0, 0x05bd,
+ 0x05bf, 0x05bf,
+ 0x05c1, 0x05c2,
+ 0x05c4, 0x05c5,
+ 0x05c7, 0x05c7,
+ 0x05d0, 0x05ea,
+ 0x05ef, 0x05f2,
+ 0x0610, 0x061a,
+ 0x0620, 0x0657,
+ 0x0659, 0x0669,
+ 0x066e, 0x06d3,
+ 0x06d5, 0x06dc,
+ 0x06e1, 0x06e8,
+ 0x06ed, 0x06fc,
+ 0x06ff, 0x06ff,
+ 0x0710, 0x073f,
+ 0x074d, 0x07b1,
+ 0x07c0, 0x07ea,
+ 0x07f4, 0x07f5,
+ 0x07fa, 0x07fa,
+ 0x0800, 0x0817,
+ 0x081a, 0x082c,
+ 0x0840, 0x0858,
+ 0x0860, 0x086a,
+ 0x0870, 0x0887,
+ 0x0889, 0x088f,
+ 0x0897, 0x0897,
+ 0x08a0, 0x08c9,
+ 0x08d4, 0x08df,
+ 0x08e3, 0x08e9,
+ 0x08f0, 0x093b,
+ 0x093d, 0x094c,
+ 0x094e, 0x0950,
+ 0x0955, 0x0963,
+ 0x0966, 0x096f,
+ 0x0971, 0x0983,
+ 0x0985, 0x098c,
+ 0x098f, 0x0990,
+ 0x0993, 0x09a8,
+ 0x09aa, 0x09b0,
+ 0x09b2, 0x09b2,
+ 0x09b6, 0x09b9,
+ 0x09bd, 0x09c4,
+ 0x09c7, 0x09c8,
+ 0x09cb, 0x09cc,
+ 0x09ce, 0x09ce,
+ 0x09d7, 0x09d7,
+ 0x09dc, 0x09dd,
+ 0x09df, 0x09e3,
+ 0x09e6, 0x09f1,
+ 0x09fc, 0x09fc,
+ 0x0a01, 0x0a03,
+ 0x0a05, 0x0a0a,
+ 0x0a0f, 0x0a10,
+ 0x0a13, 0x0a28,
+ 0x0a2a, 0x0a30,
+ 0x0a32, 0x0a33,
+ 0x0a35, 0x0a36,
+ 0x0a38, 0x0a39,
+ 0x0a3e, 0x0a42,
+ 0x0a47, 0x0a48,
+ 0x0a4b, 0x0a4c,
+ 0x0a51, 0x0a51,
+ 0x0a59, 0x0a5c,
+ 0x0a5e, 0x0a5e,
+ 0x0a66, 0x0a75,
+ 0x0a81, 0x0a83,
+ 0x0a85, 0x0a8d,
+ 0x0a8f, 0x0a91,
+ 0x0a93, 0x0aa8,
+ 0x0aaa, 0x0ab0,
+ 0x0ab2, 0x0ab3,
+ 0x0ab5, 0x0ab9,
+ 0x0abd, 0x0ac5,
+ 0x0ac7, 0x0ac9,
+ 0x0acb, 0x0acc,
+ 0x0ad0, 0x0ad0,
+ 0x0ae0, 0x0ae3,
+ 0x0ae6, 0x0aef,
+ 0x0af9, 0x0afc,
+ 0x0b01, 0x0b03,
+ 0x0b05, 0x0b0c,
+ 0x0b0f, 0x0b10,
+ 0x0b13, 0x0b28,
+ 0x0b2a, 0x0b30,
+ 0x0b32, 0x0b33,
+ 0x0b35, 0x0b39,
+ 0x0b3d, 0x0b44,
+ 0x0b47, 0x0b48,
+ 0x0b4b, 0x0b4c,
+ 0x0b56, 0x0b57,
+ 0x0b5c, 0x0b5d,
+ 0x0b5f, 0x0b63,
+ 0x0b66, 0x0b6f,
+ 0x0b71, 0x0b71,
+ 0x0b82, 0x0b83,
+ 0x0b85, 0x0b8a,
+ 0x0b8e, 0x0b90,
+ 0x0b92, 0x0b95,
+ 0x0b99, 0x0b9a,
+ 0x0b9c, 0x0b9c,
+ 0x0b9e, 0x0b9f,
+ 0x0ba3, 0x0ba4,
+ 0x0ba8, 0x0baa,
+ 0x0bae, 0x0bb9,
+ 0x0bbe, 0x0bc2,
+ 0x0bc6, 0x0bc8,
+ 0x0bca, 0x0bcc,
+ 0x0bd0, 0x0bd0,
+ 0x0bd7, 0x0bd7,
+ 0x0be6, 0x0bef,
+ 0x0c00, 0x0c0c,
+ 0x0c0e, 0x0c10,
+ 0x0c12, 0x0c28,
+ 0x0c2a, 0x0c39,
+ 0x0c3d, 0x0c44,
+ 0x0c46, 0x0c48,
+ 0x0c4a, 0x0c4c,
+ 0x0c55, 0x0c56,
+ 0x0c58, 0x0c5a,
+ 0x0c5c, 0x0c5d,
+ 0x0c60, 0x0c63,
+ 0x0c66, 0x0c6f,
+ 0x0c80, 0x0c83,
+ 0x0c85, 0x0c8c,
+ 0x0c8e, 0x0c90,
+ 0x0c92, 0x0ca8,
+ 0x0caa, 0x0cb3,
+ 0x0cb5, 0x0cb9,
+ 0x0cbd, 0x0cc4,
+ 0x0cc6, 0x0cc8,
+ 0x0cca, 0x0ccc,
+ 0x0cd5, 0x0cd6,
+ 0x0cdc, 0x0cde,
+ 0x0ce0, 0x0ce3,
+ 0x0ce6, 0x0cef,
+ 0x0cf1, 0x0cf3,
+ 0x0d00, 0x0d0c,
+ 0x0d0e, 0x0d10,
+ 0x0d12, 0x0d3a,
+ 0x0d3d, 0x0d44,
+ 0x0d46, 0x0d48,
+ 0x0d4a, 0x0d4c,
+ 0x0d4e, 0x0d4e,
+ 0x0d54, 0x0d57,
+ 0x0d5f, 0x0d63,
+ 0x0d66, 0x0d6f,
+ 0x0d7a, 0x0d7f,
+ 0x0d81, 0x0d83,
+ 0x0d85, 0x0d96,
+ 0x0d9a, 0x0db1,
+ 0x0db3, 0x0dbb,
+ 0x0dbd, 0x0dbd,
+ 0x0dc0, 0x0dc6,
+ 0x0dcf, 0x0dd4,
+ 0x0dd6, 0x0dd6,
+ 0x0dd8, 0x0ddf,
+ 0x0de6, 0x0def,
+ 0x0df2, 0x0df3,
+ 0x0e01, 0x0e3a,
+ 0x0e40, 0x0e46,
+ 0x0e4d, 0x0e4d,
+ 0x0e50, 0x0e59,
+ 0x0e81, 0x0e82,
+ 0x0e84, 0x0e84,
+ 0x0e86, 0x0e8a,
+ 0x0e8c, 0x0ea3,
+ 0x0ea5, 0x0ea5,
+ 0x0ea7, 0x0eb9,
+ 0x0ebb, 0x0ebd,
+ 0x0ec0, 0x0ec4,
+ 0x0ec6, 0x0ec6,
+ 0x0ecd, 0x0ecd,
+ 0x0ed0, 0x0ed9,
+ 0x0edc, 0x0edf,
+ 0x0f00, 0x0f00,
+ 0x0f20, 0x0f29,
+ 0x0f40, 0x0f47,
+ 0x0f49, 0x0f6c,
+ 0x0f71, 0x0f83,
+ 0x0f88, 0x0f97,
+ 0x0f99, 0x0fbc,
+ 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, 0x1c8a,
+ 0x1c90, 0x1cba,
+ 0x1cbd, 0x1cbf,
+ 0x1ce9, 0x1cec,
+ 0x1cee, 0x1cf3,
+ 0x1cf5, 0x1cf6,
+ 0x1cfa, 0x1cfa,
+ 0x1d00, 0x1dbf,
+ 0x1dd3, 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, 0xa7dc,
+ 0xa7f1, 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,
+ 0x105c0, 0x105f3,
+ 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,
+ 0x10940, 0x10959,
+ 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,
+ 0x10d40, 0x10d65,
+ 0x10d69, 0x10d69,
+ 0x10d6f, 0x10d85,
+ 0x10e80, 0x10ea9,
+ 0x10eab, 0x10eac,
+ 0x10eb0, 0x10eb1,
+ 0x10ec2, 0x10ec7,
+ 0x10efa, 0x10efc,
+ 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,
+ 0x11380, 0x11389,
+ 0x1138b, 0x1138b,
+ 0x1138e, 0x1138e,
+ 0x11390, 0x113b5,
+ 0x113b7, 0x113c0,
+ 0x113c2, 0x113c2,
+ 0x113c5, 0x113c5,
+ 0x113c7, 0x113ca,
+ 0x113cc, 0x113cd,
+ 0x113d1, 0x113d1,
+ 0x113d3, 0x113d3,
+ 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,
+ 0x116d0, 0x116e3,
+ 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,
+ 0x11b60, 0x11b67,
+ 0x11bc0, 0x11be0,
+ 0x11bf0, 0x11bf9,
+ 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,
+ 0x11db0, 0x11ddb,
+ 0x11de0, 0x11de9,
+ 0x11ee0, 0x11ef6,
+ 0x11f00, 0x11f10,
+ 0x11f12, 0x11f3a,
+ 0x11f3e, 0x11f40,
+ 0x11f50, 0x11f59,
+ 0x11fb0, 0x11fb0,
+ 0x12000, 0x12399,
+ 0x12400, 0x1246e,
+ 0x12480, 0x12543,
+ 0x12f90, 0x12ff0,
+ 0x13000, 0x1342f,
+ 0x13441, 0x13446,
+ 0x13460, 0x143fa,
+ 0x14400, 0x14646,
+ 0x16100, 0x1612e,
+ 0x16130, 0x16139,
+ 0x16800, 0x16a38,
+ 0x16a40, 0x16a5e,
+ 0x16a60, 0x16a69,
+ 0x16a70, 0x16abe,
+ 0x16ac0, 0x16ac9,
+ 0x16ad0, 0x16aed,
+ 0x16b00, 0x16b2f,
+ 0x16b40, 0x16b43,
+ 0x16b50, 0x16b59,
+ 0x16b63, 0x16b77,
+ 0x16b7d, 0x16b8f,
+ 0x16d40, 0x16d6c,
+ 0x16d70, 0x16d79,
+ 0x16e40, 0x16e7f,
+ 0x16ea0, 0x16eb8,
+ 0x16ebb, 0x16ed3,
+ 0x16f00, 0x16f4a,
+ 0x16f4f, 0x16f87,
+ 0x16f8f, 0x16f9f,
+ 0x16fe0, 0x16fe1,
+ 0x16fe3, 0x16fe3,
+ 0x16ff0, 0x16ff6,
+ 0x17000, 0x18cd5,
+ 0x18cff, 0x18d1e,
+ 0x18d80, 0x18df2,
+ 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,
+ 0x1ccf0, 0x1ccf9,
+ 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,
+ 0x1e5d0, 0x1e5ed,
+ 0x1e5f0, 0x1e5fa,
+ 0x1e6c0, 0x1e6de,
+ 0x1e6e0, 0x1e6f5,
+ 0x1e6fe, 0x1e6ff,
+ 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, 0x2b81d,
+ 0x2b820, 0x2cead,
+ 0x2ceb0, 0x2ebe0,
+ 0x2ebf0, 0x2ee5d,
+ 0x2f800, 0x2fa1d,
+ 0x30000, 0x3134a,
+ 0x31350, 0x33479,
+}; /* CR_Alnum */
+
+/* 'ASCII': [[:ASCII:]] */
+static const OnigCodePoint CR_ASCII[] = {
+ 1,
+ 0x0000, 0x007f,
+}; /* CR_ASCII */
+
+/* 'Punct': [[:Punct:]] */
+static const OnigCodePoint CR_Punct[] = {
+ 199,
+ 0x0021, 0x0023,
+ 0x0025, 0x002a,
+ 0x002c, 0x002f,
+ 0x003a, 0x003b,
+ 0x003f, 0x0040,
+ 0x005b, 0x005d,
+ 0x005f, 0x005f,
+ 0x007b, 0x007b,
+ 0x007d, 0x007d,
+ 0x00a1, 0x00a1,
+ 0x00a7, 0x00a7,
+ 0x00ab, 0x00ab,
+ 0x00b6, 0x00b7,
+ 0x00bb, 0x00bb,
+ 0x00bf, 0x00bf,
+ 0x037e, 0x037e,
+ 0x0387, 0x0387,
+ 0x055a, 0x055f,
+ 0x0589, 0x058a,
+ 0x05be, 0x05be,
+ 0x05c0, 0x05c0,
+ 0x05c3, 0x05c3,
+ 0x05c6, 0x05c6,
+ 0x05f3, 0x05f4,
+ 0x0609, 0x060a,
+ 0x060c, 0x060d,
+ 0x061b, 0x061b,
+ 0x061d, 0x061f,
+ 0x066a, 0x066d,
+ 0x06d4, 0x06d4,
+ 0x0700, 0x070d,
+ 0x07f7, 0x07f9,
+ 0x0830, 0x083e,
+ 0x085e, 0x085e,
+ 0x0964, 0x0965,
+ 0x0970, 0x0970,
+ 0x09fd, 0x09fd,
+ 0x0a76, 0x0a76,
+ 0x0af0, 0x0af0,
+ 0x0c77, 0x0c77,
+ 0x0c84, 0x0c84,
+ 0x0df4, 0x0df4,
+ 0x0e4f, 0x0e4f,
+ 0x0e5a, 0x0e5b,
+ 0x0f04, 0x0f12,
+ 0x0f14, 0x0f14,
+ 0x0f3a, 0x0f3d,
+ 0x0f85, 0x0f85,
+ 0x0fd0, 0x0fd4,
+ 0x0fd9, 0x0fda,
+ 0x104a, 0x104f,
+ 0x10fb, 0x10fb,
+ 0x1360, 0x1368,
+ 0x1400, 0x1400,
+ 0x166e, 0x166e,
+ 0x169b, 0x169c,
+ 0x16eb, 0x16ed,
+ 0x1735, 0x1736,
+ 0x17d4, 0x17d6,
+ 0x17d8, 0x17da,
+ 0x1800, 0x180a,
+ 0x1944, 0x1945,
+ 0x1a1e, 0x1a1f,
+ 0x1aa0, 0x1aa6,
+ 0x1aa8, 0x1aad,
+ 0x1b4e, 0x1b4f,
+ 0x1b5a, 0x1b60,
+ 0x1b7d, 0x1b7f,
+ 0x1bfc, 0x1bff,
+ 0x1c3b, 0x1c3f,
+ 0x1c7e, 0x1c7f,
+ 0x1cc0, 0x1cc7,
+ 0x1cd3, 0x1cd3,
+ 0x2010, 0x2027,
+ 0x2030, 0x2043,
+ 0x2045, 0x2051,
+ 0x2053, 0x205e,
+ 0x207d, 0x207e,
+ 0x208d, 0x208e,
+ 0x2308, 0x230b,
+ 0x2329, 0x232a,
+ 0x2768, 0x2775,
+ 0x27c5, 0x27c6,
+ 0x27e6, 0x27ef,
+ 0x2983, 0x2998,
+ 0x29d8, 0x29db,
+ 0x29fc, 0x29fd,
+ 0x2cf9, 0x2cfc,
+ 0x2cfe, 0x2cff,
+ 0x2d70, 0x2d70,
+ 0x2e00, 0x2e2e,
+ 0x2e30, 0x2e4f,
+ 0x2e52, 0x2e5d,
+ 0x3001, 0x3003,
+ 0x3008, 0x3011,
+ 0x3014, 0x301f,
+ 0x3030, 0x3030,
+ 0x303d, 0x303d,
+ 0x30a0, 0x30a0,
+ 0x30fb, 0x30fb,
+ 0xa4fe, 0xa4ff,
+ 0xa60d, 0xa60f,
+ 0xa673, 0xa673,
+ 0xa67e, 0xa67e,
+ 0xa6f2, 0xa6f7,
+ 0xa874, 0xa877,
+ 0xa8ce, 0xa8cf,
+ 0xa8f8, 0xa8fa,
+ 0xa8fc, 0xa8fc,
+ 0xa92e, 0xa92f,
+ 0xa95f, 0xa95f,
+ 0xa9c1, 0xa9cd,
+ 0xa9de, 0xa9df,
+ 0xaa5c, 0xaa5f,
+ 0xaade, 0xaadf,
+ 0xaaf0, 0xaaf1,
+ 0xabeb, 0xabeb,
+ 0xfd3e, 0xfd3f,
+ 0xfe10, 0xfe19,
+ 0xfe30, 0xfe52,
+ 0xfe54, 0xfe61,
+ 0xfe63, 0xfe63,
+ 0xfe68, 0xfe68,
+ 0xfe6a, 0xfe6b,
+ 0xff01, 0xff03,
+ 0xff05, 0xff0a,
+ 0xff0c, 0xff0f,
+ 0xff1a, 0xff1b,
+ 0xff1f, 0xff20,
+ 0xff3b, 0xff3d,
+ 0xff3f, 0xff3f,
+ 0xff5b, 0xff5b,
+ 0xff5d, 0xff5d,
+ 0xff5f, 0xff65,
+ 0x10100, 0x10102,
+ 0x1039f, 0x1039f,
+ 0x103d0, 0x103d0,
+ 0x1056f, 0x1056f,
+ 0x10857, 0x10857,
+ 0x1091f, 0x1091f,
+ 0x1093f, 0x1093f,
+ 0x10a50, 0x10a58,
+ 0x10a7f, 0x10a7f,
+ 0x10af0, 0x10af6,
+ 0x10b39, 0x10b3f,
+ 0x10b99, 0x10b9c,
+ 0x10d6e, 0x10d6e,
+ 0x10ead, 0x10ead,
+ 0x10ed0, 0x10ed0,
+ 0x10f55, 0x10f59,
+ 0x10f86, 0x10f89,
+ 0x11047, 0x1104d,
+ 0x110bb, 0x110bc,
+ 0x110be, 0x110c1,
+ 0x11140, 0x11143,
+ 0x11174, 0x11175,
+ 0x111c5, 0x111c8,
+ 0x111cd, 0x111cd,
+ 0x111db, 0x111db,
+ 0x111dd, 0x111df,
+ 0x11238, 0x1123d,
+ 0x112a9, 0x112a9,
+ 0x113d4, 0x113d5,
+ 0x113d7, 0x113d8,
+ 0x1144b, 0x1144f,
+ 0x1145a, 0x1145b,
+ 0x1145d, 0x1145d,
+ 0x114c6, 0x114c6,
+ 0x115c1, 0x115d7,
+ 0x11641, 0x11643,
+ 0x11660, 0x1166c,
+ 0x116b9, 0x116b9,
+ 0x1173c, 0x1173e,
+ 0x1183b, 0x1183b,
+ 0x11944, 0x11946,
+ 0x119e2, 0x119e2,
+ 0x11a3f, 0x11a46,
+ 0x11a9a, 0x11a9c,
+ 0x11a9e, 0x11aa2,
+ 0x11b00, 0x11b09,
+ 0x11be1, 0x11be1,
+ 0x11c41, 0x11c45,
+ 0x11c70, 0x11c71,
+ 0x11ef7, 0x11ef8,
+ 0x11f43, 0x11f4f,
+ 0x11fff, 0x11fff,
+ 0x12470, 0x12474,
+ 0x12ff1, 0x12ff2,
+ 0x16a6e, 0x16a6f,
+ 0x16af5, 0x16af5,
+ 0x16b37, 0x16b3b,
+ 0x16b44, 0x16b44,
+ 0x16d6d, 0x16d6f,
+ 0x16e97, 0x16e9a,
+ 0x16fe2, 0x16fe2,
+ 0x1bc9f, 0x1bc9f,
+ 0x1da87, 0x1da8b,
+ 0x1e5ff, 0x1e5ff,
+ 0x1e95e, 0x1e95f,
+}; /* CR_Punct */
+
+#ifdef USE_UNICODE_PROPERTIES
+/* 'Any': - */
+static const OnigCodePoint CR_Any[] = {
+ 1,
+ 0x0000, 0x10ffff,
+}; /* CR_Any */
+
+/* 'Assigned': - */
+static const OnigCodePoint CR_Assigned[] = {
+ 735,
+ 0x0000, 0x0377,
+ 0x037a, 0x037f,
+ 0x0384, 0x038a,
+ 0x038c, 0x038c,
+ 0x038e, 0x03a1,
+ 0x03a3, 0x052f,
+ 0x0531, 0x0556,
+ 0x0559, 0x058a,
+ 0x058d, 0x058f,
+ 0x0591, 0x05c7,
+ 0x05d0, 0x05ea,
+ 0x05ef, 0x05f4,
+ 0x0600, 0x070d,
+ 0x070f, 0x074a,
+ 0x074d, 0x07b1,
+ 0x07c0, 0x07fa,
+ 0x07fd, 0x082d,
+ 0x0830, 0x083e,
+ 0x0840, 0x085b,
+ 0x085e, 0x085e,
+ 0x0860, 0x086a,
+ 0x0870, 0x0891,
+ 0x0897, 0x0983,
+ 0x0985, 0x098c,
+ 0x098f, 0x0990,
+ 0x0993, 0x09a8,
+ 0x09aa, 0x09b0,
+ 0x09b2, 0x09b2,
+ 0x09b6, 0x09b9,
+ 0x09bc, 0x09c4,
+ 0x09c7, 0x09c8,
+ 0x09cb, 0x09ce,
+ 0x09d7, 0x09d7,
+ 0x09dc, 0x09dd,
+ 0x09df, 0x09e3,
+ 0x09e6, 0x09fe,
+ 0x0a01, 0x0a03,
+ 0x0a05, 0x0a0a,
+ 0x0a0f, 0x0a10,
+ 0x0a13, 0x0a28,
+ 0x0a2a, 0x0a30,
+ 0x0a32, 0x0a33,
+ 0x0a35, 0x0a36,
+ 0x0a38, 0x0a39,
+ 0x0a3c, 0x0a3c,
+ 0x0a3e, 0x0a42,
+ 0x0a47, 0x0a48,
+ 0x0a4b, 0x0a4d,
+ 0x0a51, 0x0a51,
+ 0x0a59, 0x0a5c,
+ 0x0a5e, 0x0a5e,
+ 0x0a66, 0x0a76,
+ 0x0a81, 0x0a83,
+ 0x0a85, 0x0a8d,
+ 0x0a8f, 0x0a91,
+ 0x0a93, 0x0aa8,
+ 0x0aaa, 0x0ab0,
+ 0x0ab2, 0x0ab3,
+ 0x0ab5, 0x0ab9,
+ 0x0abc, 0x0ac5,
+ 0x0ac7, 0x0ac9,
+ 0x0acb, 0x0acd,
+ 0x0ad0, 0x0ad0,
+ 0x0ae0, 0x0ae3,
+ 0x0ae6, 0x0af1,
+ 0x0af9, 0x0aff,
+ 0x0b01, 0x0b03,
+ 0x0b05, 0x0b0c,
+ 0x0b0f, 0x0b10,
+ 0x0b13, 0x0b28,
+ 0x0b2a, 0x0b30,
+ 0x0b32, 0x0b33,
+ 0x0b35, 0x0b39,
+ 0x0b3c, 0x0b44,
+ 0x0b47, 0x0b48,
+ 0x0b4b, 0x0b4d,
+ 0x0b55, 0x0b57,
+ 0x0b5c, 0x0b5d,
+ 0x0b5f, 0x0b63,
+ 0x0b66, 0x0b77,
+ 0x0b82, 0x0b83,
+ 0x0b85, 0x0b8a,
+ 0x0b8e, 0x0b90,
+ 0x0b92, 0x0b95,
+ 0x0b99, 0x0b9a,
+ 0x0b9c, 0x0b9c,
+ 0x0b9e, 0x0b9f,
+ 0x0ba3, 0x0ba4,
+ 0x0ba8, 0x0baa,
+ 0x0bae, 0x0bb9,
+ 0x0bbe, 0x0bc2,
+ 0x0bc6, 0x0bc8,
+ 0x0bca, 0x0bcd,
+ 0x0bd0, 0x0bd0,
+ 0x0bd7, 0x0bd7,
+ 0x0be6, 0x0bfa,
+ 0x0c00, 0x0c0c,
+ 0x0c0e, 0x0c10,
+ 0x0c12, 0x0c28,
+ 0x0c2a, 0x0c39,
+ 0x0c3c, 0x0c44,
+ 0x0c46, 0x0c48,
+ 0x0c4a, 0x0c4d,
+ 0x0c55, 0x0c56,
+ 0x0c58, 0x0c5a,
+ 0x0c5c, 0x0c5d,
+ 0x0c60, 0x0c63,
+ 0x0c66, 0x0c6f,
+ 0x0c77, 0x0c8c,
+ 0x0c8e, 0x0c90,
+ 0x0c92, 0x0ca8,
+ 0x0caa, 0x0cb3,
+ 0x0cb5, 0x0cb9,
+ 0x0cbc, 0x0cc4,
+ 0x0cc6, 0x0cc8,
+ 0x0cca, 0x0ccd,
+ 0x0cd5, 0x0cd6,
+ 0x0cdc, 0x0cde,
+ 0x0ce0, 0x0ce3,
+ 0x0ce6, 0x0cef,
+ 0x0cf1, 0x0cf3,
+ 0x0d00, 0x0d0c,
+ 0x0d0e, 0x0d10,
+ 0x0d12, 0x0d44,
+ 0x0d46, 0x0d48,
+ 0x0d4a, 0x0d4f,
+ 0x0d54, 0x0d63,
+ 0x0d66, 0x0d7f,
+ 0x0d81, 0x0d83,
+ 0x0d85, 0x0d96,
+ 0x0d9a, 0x0db1,
+ 0x0db3, 0x0dbb,
+ 0x0dbd, 0x0dbd,
+ 0x0dc0, 0x0dc6,
+ 0x0dca, 0x0dca,
+ 0x0dcf, 0x0dd4,
+ 0x0dd6, 0x0dd6,
+ 0x0dd8, 0x0ddf,
+ 0x0de6, 0x0def,
+ 0x0df2, 0x0df4,
+ 0x0e01, 0x0e3a,
+ 0x0e3f, 0x0e5b,
+ 0x0e81, 0x0e82,
+ 0x0e84, 0x0e84,
+ 0x0e86, 0x0e8a,
+ 0x0e8c, 0x0ea3,
+ 0x0ea5, 0x0ea5,
+ 0x0ea7, 0x0ebd,
+ 0x0ec0, 0x0ec4,
+ 0x0ec6, 0x0ec6,
+ 0x0ec8, 0x0ece,
+ 0x0ed0, 0x0ed9,
+ 0x0edc, 0x0edf,
+ 0x0f00, 0x0f47,
+ 0x0f49, 0x0f6c,
+ 0x0f71, 0x0f97,
+ 0x0f99, 0x0fbc,
+ 0x0fbe, 0x0fcc,
+ 0x0fce, 0x0fda,
+ 0x1000, 0x10c5,
+ 0x10c7, 0x10c7,
+ 0x10cd, 0x10cd,
+ 0x10d0, 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,
+ 0x135d, 0x137c,
+ 0x1380, 0x1399,
+ 0x13a0, 0x13f5,
+ 0x13f8, 0x13fd,
+ 0x1400, 0x169c,
+ 0x16a0, 0x16f8,
+ 0x1700, 0x1715,
+ 0x171f, 0x1736,
+ 0x1740, 0x1753,
+ 0x1760, 0x176c,
+ 0x176e, 0x1770,
+ 0x1772, 0x1773,
+ 0x1780, 0x17dd,
+ 0x17e0, 0x17e9,
+ 0x17f0, 0x17f9,
+ 0x1800, 0x1819,
+ 0x1820, 0x1878,
+ 0x1880, 0x18aa,
+ 0x18b0, 0x18f5,
+ 0x1900, 0x191e,
+ 0x1920, 0x192b,
+ 0x1930, 0x193b,
+ 0x1940, 0x1940,
+ 0x1944, 0x196d,
+ 0x1970, 0x1974,
+ 0x1980, 0x19ab,
+ 0x19b0, 0x19c9,
+ 0x19d0, 0x19da,
+ 0x19de, 0x1a1b,
+ 0x1a1e, 0x1a5e,
+ 0x1a60, 0x1a7c,
+ 0x1a7f, 0x1a89,
+ 0x1a90, 0x1a99,
+ 0x1aa0, 0x1aad,
+ 0x1ab0, 0x1add,
+ 0x1ae0, 0x1aeb,
+ 0x1b00, 0x1b4c,
+ 0x1b4e, 0x1bf3,
+ 0x1bfc, 0x1c37,
+ 0x1c3b, 0x1c49,
+ 0x1c4d, 0x1c8a,
+ 0x1c90, 0x1cba,
+ 0x1cbd, 0x1cc7,
+ 0x1cd0, 0x1cfa,
+ 0x1d00, 0x1f15,
+ 0x1f18, 0x1f1d,
+ 0x1f20, 0x1f45,
+ 0x1f48, 0x1f4d,
+ 0x1f50, 0x1f57,
+ 0x1f59, 0x1f59,
+ 0x1f5b, 0x1f5b,
+ 0x1f5d, 0x1f5d,
+ 0x1f5f, 0x1f7d,
+ 0x1f80, 0x1fb4,
+ 0x1fb6, 0x1fc4,
+ 0x1fc6, 0x1fd3,
+ 0x1fd6, 0x1fdb,
+ 0x1fdd, 0x1fef,
+ 0x1ff2, 0x1ff4,
+ 0x1ff6, 0x1ffe,
+ 0x2000, 0x2064,
+ 0x2066, 0x2071,
+ 0x2074, 0x208e,
+ 0x2090, 0x209c,
+ 0x20a0, 0x20c1,
+ 0x20d0, 0x20f0,
+ 0x2100, 0x218b,
+ 0x2190, 0x2429,
+ 0x2440, 0x244a,
+ 0x2460, 0x2b73,
+ 0x2b76, 0x2cf3,
+ 0x2cf9, 0x2d25,
+ 0x2d27, 0x2d27,
+ 0x2d2d, 0x2d2d,
+ 0x2d30, 0x2d67,
+ 0x2d6f, 0x2d70,
+ 0x2d7f, 0x2d96,
+ 0x2da0, 0x2da6,
+ 0x2da8, 0x2dae,
+ 0x2db0, 0x2db6,
+ 0x2db8, 0x2dbe,
+ 0x2dc0, 0x2dc6,
+ 0x2dc8, 0x2dce,
+ 0x2dd0, 0x2dd6,
+ 0x2dd8, 0x2dde,
+ 0x2de0, 0x2e5d,
+ 0x2e80, 0x2e99,
+ 0x2e9b, 0x2ef3,
+ 0x2f00, 0x2fd5,
+ 0x2ff0, 0x303f,
+ 0x3041, 0x3096,
+ 0x3099, 0x30ff,
+ 0x3105, 0x312f,
+ 0x3131, 0x318e,
+ 0x3190, 0x31e5,
+ 0x31ef, 0x321e,
+ 0x3220, 0xa48c,
+ 0xa490, 0xa4c6,
+ 0xa4d0, 0xa62b,
+ 0xa640, 0xa6f7,
+ 0xa700, 0xa7dc,
+ 0xa7f1, 0xa82c,
+ 0xa830, 0xa839,
+ 0xa840, 0xa877,
+ 0xa880, 0xa8c5,
+ 0xa8ce, 0xa8d9,
+ 0xa8e0, 0xa953,
+ 0xa95f, 0xa97c,
+ 0xa980, 0xa9cd,
+ 0xa9cf, 0xa9d9,
+ 0xa9de, 0xa9fe,
+ 0xaa00, 0xaa36,
+ 0xaa40, 0xaa4d,
+ 0xaa50, 0xaa59,
+ 0xaa5c, 0xaac2,
+ 0xaadb, 0xaaf6,
+ 0xab01, 0xab06,
+ 0xab09, 0xab0e,
+ 0xab11, 0xab16,
+ 0xab20, 0xab26,
+ 0xab28, 0xab2e,
+ 0xab30, 0xab6b,
+ 0xab70, 0xabed,
+ 0xabf0, 0xabf9,
+ 0xac00, 0xd7a3,
+ 0xd7b0, 0xd7c6,
+ 0xd7cb, 0xd7fb,
+ 0xd800, 0xfa6d,
+ 0xfa70, 0xfad9,
+ 0xfb00, 0xfb06,
+ 0xfb13, 0xfb17,
+ 0xfb1d, 0xfb36,
+ 0xfb38, 0xfb3c,
+ 0xfb3e, 0xfb3e,
+ 0xfb40, 0xfb41,
+ 0xfb43, 0xfb44,
+ 0xfb46, 0xfdcf,
+ 0xfdf0, 0xfe19,
+ 0xfe20, 0xfe52,
+ 0xfe54, 0xfe66,
+ 0xfe68, 0xfe6b,
+ 0xfe70, 0xfe74,
+ 0xfe76, 0xfefc,
+ 0xfeff, 0xfeff,
+ 0xff01, 0xffbe,
+ 0xffc2, 0xffc7,
+ 0xffca, 0xffcf,
+ 0xffd2, 0xffd7,
+ 0xffda, 0xffdc,
+ 0xffe0, 0xffe6,
+ 0xffe8, 0xffee,
+ 0xfff9, 0xfffd,
+ 0x10000, 0x1000b,
+ 0x1000d, 0x10026,
+ 0x10028, 0x1003a,
+ 0x1003c, 0x1003d,
+ 0x1003f, 0x1004d,
+ 0x10050, 0x1005d,
+ 0x10080, 0x100fa,
+ 0x10100, 0x10102,
+ 0x10107, 0x10133,
+ 0x10137, 0x1018e,
+ 0x10190, 0x1019c,
+ 0x101a0, 0x101a0,
+ 0x101d0, 0x101fd,
+ 0x10280, 0x1029c,
+ 0x102a0, 0x102d0,
+ 0x102e0, 0x102fb,
+ 0x10300, 0x10323,
+ 0x1032d, 0x1034a,
+ 0x10350, 0x1037a,
+ 0x10380, 0x1039d,
+ 0x1039f, 0x103c3,
+ 0x103c8, 0x103d5,
+ 0x10400, 0x1049d,
+ 0x104a0, 0x104a9,
+ 0x104b0, 0x104d3,
+ 0x104d8, 0x104fb,
+ 0x10500, 0x10527,
+ 0x10530, 0x10563,
+ 0x1056f, 0x1057a,
+ 0x1057c, 0x1058a,
+ 0x1058c, 0x10592,
+ 0x10594, 0x10595,
+ 0x10597, 0x105a1,
+ 0x105a3, 0x105b1,
+ 0x105b3, 0x105b9,
+ 0x105bb, 0x105bc,
+ 0x105c0, 0x105f3,
+ 0x10600, 0x10736,
+ 0x10740, 0x10755,
+ 0x10760, 0x10767,
+ 0x10780, 0x10785,
+ 0x10787, 0x107b0,
+ 0x107b2, 0x107ba,
+ 0x10800, 0x10805,
+ 0x10808, 0x10808,
+ 0x1080a, 0x10835,
+ 0x10837, 0x10838,
+ 0x1083c, 0x1083c,
+ 0x1083f, 0x10855,
+ 0x10857, 0x1089e,
+ 0x108a7, 0x108af,
+ 0x108e0, 0x108f2,
+ 0x108f4, 0x108f5,
+ 0x108fb, 0x1091b,
+ 0x1091f, 0x10939,
+ 0x1093f, 0x10959,
+ 0x10980, 0x109b7,
+ 0x109bc, 0x109cf,
+ 0x109d2, 0x10a03,
+ 0x10a05, 0x10a06,
+ 0x10a0c, 0x10a13,
+ 0x10a15, 0x10a17,
+ 0x10a19, 0x10a35,
+ 0x10a38, 0x10a3a,
+ 0x10a3f, 0x10a48,
+ 0x10a50, 0x10a58,
+ 0x10a60, 0x10a9f,
+ 0x10ac0, 0x10ae6,
+ 0x10aeb, 0x10af6,
+ 0x10b00, 0x10b35,
+ 0x10b39, 0x10b55,
+ 0x10b58, 0x10b72,
+ 0x10b78, 0x10b91,
+ 0x10b99, 0x10b9c,
+ 0x10ba9, 0x10baf,
+ 0x10c00, 0x10c48,
+ 0x10c80, 0x10cb2,
+ 0x10cc0, 0x10cf2,
+ 0x10cfa, 0x10d27,
+ 0x10d30, 0x10d39,
+ 0x10d40, 0x10d65,
+ 0x10d69, 0x10d85,
+ 0x10d8e, 0x10d8f,
+ 0x10e60, 0x10e7e,
+ 0x10e80, 0x10ea9,
+ 0x10eab, 0x10ead,
+ 0x10eb0, 0x10eb1,
+ 0x10ec2, 0x10ec7,
+ 0x10ed0, 0x10ed8,
+ 0x10efa, 0x10f27,
+ 0x10f30, 0x10f59,
+ 0x10f70, 0x10f89,
+ 0x10fb0, 0x10fcb,
+ 0x10fe0, 0x10ff6,
+ 0x11000, 0x1104d,
+ 0x11052, 0x11075,
+ 0x1107f, 0x110c2,
+ 0x110cd, 0x110cd,
+ 0x110d0, 0x110e8,
+ 0x110f0, 0x110f9,
+ 0x11100, 0x11134,
+ 0x11136, 0x11147,
+ 0x11150, 0x11176,
+ 0x11180, 0x111df,
+ 0x111e1, 0x111f4,
+ 0x11200, 0x11211,
+ 0x11213, 0x11241,
+ 0x11280, 0x11286,
+ 0x11288, 0x11288,
+ 0x1128a, 0x1128d,
+ 0x1128f, 0x1129d,
+ 0x1129f, 0x112a9,
+ 0x112b0, 0x112ea,
+ 0x112f0, 0x112f9,
+ 0x11300, 0x11303,
+ 0x11305, 0x1130c,
+ 0x1130f, 0x11310,
+ 0x11313, 0x11328,
+ 0x1132a, 0x11330,
+ 0x11332, 0x11333,
+ 0x11335, 0x11339,
+ 0x1133b, 0x11344,
+ 0x11347, 0x11348,
+ 0x1134b, 0x1134d,
+ 0x11350, 0x11350,
+ 0x11357, 0x11357,
+ 0x1135d, 0x11363,
+ 0x11366, 0x1136c,
+ 0x11370, 0x11374,
+ 0x11380, 0x11389,
+ 0x1138b, 0x1138b,
+ 0x1138e, 0x1138e,
+ 0x11390, 0x113b5,
+ 0x113b7, 0x113c0,
+ 0x113c2, 0x113c2,
+ 0x113c5, 0x113c5,
+ 0x113c7, 0x113ca,
+ 0x113cc, 0x113d5,
+ 0x113d7, 0x113d8,
+ 0x113e1, 0x113e2,
+ 0x11400, 0x1145b,
+ 0x1145d, 0x11461,
+ 0x11480, 0x114c7,
+ 0x114d0, 0x114d9,
+ 0x11580, 0x115b5,
+ 0x115b8, 0x115dd,
+ 0x11600, 0x11644,
+ 0x11650, 0x11659,
+ 0x11660, 0x1166c,
+ 0x11680, 0x116b9,
+ 0x116c0, 0x116c9,
+ 0x116d0, 0x116e3,
+ 0x11700, 0x1171a,
+ 0x1171d, 0x1172b,
+ 0x11730, 0x11746,
+ 0x11800, 0x1183b,
+ 0x118a0, 0x118f2,
+ 0x118ff, 0x11906,
+ 0x11909, 0x11909,
+ 0x1190c, 0x11913,
+ 0x11915, 0x11916,
+ 0x11918, 0x11935,
+ 0x11937, 0x11938,
+ 0x1193b, 0x11946,
+ 0x11950, 0x11959,
+ 0x119a0, 0x119a7,
+ 0x119aa, 0x119d7,
+ 0x119da, 0x119e4,
+ 0x11a00, 0x11a47,
+ 0x11a50, 0x11aa2,
+ 0x11ab0, 0x11af8,
+ 0x11b00, 0x11b09,
+ 0x11b60, 0x11b67,
+ 0x11bc0, 0x11be1,
+ 0x11bf0, 0x11bf9,
+ 0x11c00, 0x11c08,
+ 0x11c0a, 0x11c36,
+ 0x11c38, 0x11c45,
+ 0x11c50, 0x11c6c,
+ 0x11c70, 0x11c8f,
+ 0x11c92, 0x11ca7,
+ 0x11ca9, 0x11cb6,
+ 0x11d00, 0x11d06,
+ 0x11d08, 0x11d09,
+ 0x11d0b, 0x11d36,
+ 0x11d3a, 0x11d3a,
+ 0x11d3c, 0x11d3d,
+ 0x11d3f, 0x11d47,
+ 0x11d50, 0x11d59,
+ 0x11d60, 0x11d65,
+ 0x11d67, 0x11d68,
+ 0x11d6a, 0x11d8e,
+ 0x11d90, 0x11d91,
+ 0x11d93, 0x11d98,
+ 0x11da0, 0x11da9,
+ 0x11db0, 0x11ddb,
+ 0x11de0, 0x11de9,
+ 0x11ee0, 0x11ef8,
+ 0x11f00, 0x11f10,
+ 0x11f12, 0x11f3a,
+ 0x11f3e, 0x11f5a,
+ 0x11fb0, 0x11fb0,
+ 0x11fc0, 0x11ff1,
+ 0x11fff, 0x12399,
+ 0x12400, 0x1246e,
+ 0x12470, 0x12474,
+ 0x12480, 0x12543,
+ 0x12f90, 0x12ff2,
+ 0x13000, 0x13455,
+ 0x13460, 0x143fa,
+ 0x14400, 0x14646,
+ 0x16100, 0x16139,
+ 0x16800, 0x16a38,
+ 0x16a40, 0x16a5e,
+ 0x16a60, 0x16a69,
+ 0x16a6e, 0x16abe,
+ 0x16ac0, 0x16ac9,
+ 0x16ad0, 0x16aed,
+ 0x16af0, 0x16af5,
+ 0x16b00, 0x16b45,
+ 0x16b50, 0x16b59,
+ 0x16b5b, 0x16b61,
+ 0x16b63, 0x16b77,
+ 0x16b7d, 0x16b8f,
+ 0x16d40, 0x16d79,
+ 0x16e40, 0x16e9a,
+ 0x16ea0, 0x16eb8,
+ 0x16ebb, 0x16ed3,
+ 0x16f00, 0x16f4a,
+ 0x16f4f, 0x16f87,
+ 0x16f8f, 0x16f9f,
+ 0x16fe0, 0x16fe4,
+ 0x16ff0, 0x16ff6,
+ 0x17000, 0x18cd5,
+ 0x18cff, 0x18d1e,
+ 0x18d80, 0x18df2,
+ 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,
+ 0x1bc9c, 0x1bca3,
+ 0x1cc00, 0x1ccfc,
+ 0x1cd00, 0x1ceb3,
+ 0x1ceba, 0x1ced0,
+ 0x1cee0, 0x1cef0,
+ 0x1cf00, 0x1cf2d,
+ 0x1cf30, 0x1cf46,
+ 0x1cf50, 0x1cfc3,
+ 0x1d000, 0x1d0f5,
+ 0x1d100, 0x1d126,
+ 0x1d129, 0x1d1ea,
+ 0x1d200, 0x1d245,
+ 0x1d2c0, 0x1d2d3,
+ 0x1d2e0, 0x1d2f3,
+ 0x1d300, 0x1d356,
+ 0x1d360, 0x1d378,
+ 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, 0x1d7cb,
+ 0x1d7ce, 0x1da8b,
+ 0x1da9b, 0x1da9f,
+ 0x1daa1, 0x1daaf,
+ 0x1df00, 0x1df1e,
+ 0x1df25, 0x1df2a,
+ 0x1e000, 0x1e006,
+ 0x1e008, 0x1e018,
+ 0x1e01b, 0x1e021,
+ 0x1e023, 0x1e024,
+ 0x1e026, 0x1e02a,
+ 0x1e030, 0x1e06d,
+ 0x1e08f, 0x1e08f,
+ 0x1e100, 0x1e12c,
+ 0x1e130, 0x1e13d,
+ 0x1e140, 0x1e149,
+ 0x1e14e, 0x1e14f,
+ 0x1e290, 0x1e2ae,
+ 0x1e2c0, 0x1e2f9,
+ 0x1e2ff, 0x1e2ff,
+ 0x1e4d0, 0x1e4f9,
+ 0x1e5d0, 0x1e5fa,
+ 0x1e5ff, 0x1e5ff,
+ 0x1e6c0, 0x1e6de,
+ 0x1e6e0, 0x1e6f5,
+ 0x1e6fe, 0x1e6ff,
+ 0x1e7e0, 0x1e7e6,
+ 0x1e7e8, 0x1e7eb,
+ 0x1e7ed, 0x1e7ee,
+ 0x1e7f0, 0x1e7fe,
+ 0x1e800, 0x1e8c4,
+ 0x1e8c7, 0x1e8d6,
+ 0x1e900, 0x1e94b,
+ 0x1e950, 0x1e959,
+ 0x1e95e, 0x1e95f,
+ 0x1ec71, 0x1ecb4,
+ 0x1ed01, 0x1ed3d,
+ 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,
+ 0x1eef0, 0x1eef1,
+ 0x1f000, 0x1f02b,
+ 0x1f030, 0x1f093,
+ 0x1f0a0, 0x1f0ae,
+ 0x1f0b1, 0x1f0bf,
+ 0x1f0c1, 0x1f0cf,
+ 0x1f0d1, 0x1f0f5,
+ 0x1f100, 0x1f1ad,
+ 0x1f1e6, 0x1f202,
+ 0x1f210, 0x1f23b,
+ 0x1f240, 0x1f248,
+ 0x1f250, 0x1f251,
+ 0x1f260, 0x1f265,
+ 0x1f300, 0x1f6d8,
+ 0x1f6dc, 0x1f6ec,
+ 0x1f6f0, 0x1f6fc,
+ 0x1f700, 0x1f7d9,
+ 0x1f7e0, 0x1f7eb,
+ 0x1f7f0, 0x1f7f0,
+ 0x1f800, 0x1f80b,
+ 0x1f810, 0x1f847,
+ 0x1f850, 0x1f859,
+ 0x1f860, 0x1f887,
+ 0x1f890, 0x1f8ad,
+ 0x1f8b0, 0x1f8bb,
+ 0x1f8c0, 0x1f8c1,
+ 0x1f8d0, 0x1f8d8,
+ 0x1f900, 0x1fa57,
+ 0x1fa60, 0x1fa6d,
+ 0x1fa70, 0x1fa7c,
+ 0x1fa80, 0x1fa8a,
+ 0x1fa8e, 0x1fac6,
+ 0x1fac8, 0x1fac8,
+ 0x1facd, 0x1fadc,
+ 0x1fadf, 0x1faea,
+ 0x1faef, 0x1faf8,
+ 0x1fb00, 0x1fb92,
+ 0x1fb94, 0x1fbfa,
+ 0x20000, 0x2a6df,
+ 0x2a700, 0x2b81d,
+ 0x2b820, 0x2cead,
+ 0x2ceb0, 0x2ebe0,
+ 0x2ebf0, 0x2ee5d,
+ 0x2f800, 0x2fa1d,
+ 0x30000, 0x3134a,
+ 0x31350, 0x33479,
+ 0xe0001, 0xe0001,
+ 0xe0020, 0xe007f,
+ 0xe0100, 0xe01ef,
+ 0xf0000, 0xffffd,
+ 0x100000, 0x10fffd,
+}; /* CR_Assigned */
+
+/* 'C': Major Category */
+static const OnigCodePoint CR_C[] = {
+ 741,
+ 0x0000, 0x001f,
+ 0x007f, 0x009f,
+ 0x00ad, 0x00ad,
+ 0x0378, 0x0379,
+ 0x0380, 0x0383,
+ 0x038b, 0x038b,
+ 0x038d, 0x038d,
+ 0x03a2, 0x03a2,
+ 0x0530, 0x0530,
+ 0x0557, 0x0558,
+ 0x058b, 0x058c,
+ 0x0590, 0x0590,
+ 0x05c8, 0x05cf,
+ 0x05eb, 0x05ee,
+ 0x05f5, 0x0605,
+ 0x061c, 0x061c,
+ 0x06dd, 0x06dd,
+ 0x070e, 0x070f,
+ 0x074b, 0x074c,
+ 0x07b2, 0x07bf,
+ 0x07fb, 0x07fc,
+ 0x082e, 0x082f,
+ 0x083f, 0x083f,
+ 0x085c, 0x085d,
+ 0x085f, 0x085f,
+ 0x086b, 0x086f,
+ 0x0890, 0x0896,
+ 0x08e2, 0x08e2,
+ 0x0984, 0x0984,
+ 0x098d, 0x098e,
+ 0x0991, 0x0992,
+ 0x09a9, 0x09a9,
+ 0x09b1, 0x09b1,
+ 0x09b3, 0x09b5,
+ 0x09ba, 0x09bb,
+ 0x09c5, 0x09c6,
+ 0x09c9, 0x09ca,
+ 0x09cf, 0x09d6,
+ 0x09d8, 0x09db,
+ 0x09de, 0x09de,
+ 0x09e4, 0x09e5,
+ 0x09ff, 0x0a00,
+ 0x0a04, 0x0a04,
+ 0x0a0b, 0x0a0e,
+ 0x0a11, 0x0a12,
+ 0x0a29, 0x0a29,
+ 0x0a31, 0x0a31,
+ 0x0a34, 0x0a34,
+ 0x0a37, 0x0a37,
+ 0x0a3a, 0x0a3b,
+ 0x0a3d, 0x0a3d,
+ 0x0a43, 0x0a46,
+ 0x0a49, 0x0a4a,
+ 0x0a4e, 0x0a50,
+ 0x0a52, 0x0a58,
+ 0x0a5d, 0x0a5d,
+ 0x0a5f, 0x0a65,
+ 0x0a77, 0x0a80,
+ 0x0a84, 0x0a84,
+ 0x0a8e, 0x0a8e,
+ 0x0a92, 0x0a92,
+ 0x0aa9, 0x0aa9,
+ 0x0ab1, 0x0ab1,
+ 0x0ab4, 0x0ab4,
+ 0x0aba, 0x0abb,
+ 0x0ac6, 0x0ac6,
+ 0x0aca, 0x0aca,
+ 0x0ace, 0x0acf,
+ 0x0ad1, 0x0adf,
+ 0x0ae4, 0x0ae5,
+ 0x0af2, 0x0af8,
+ 0x0b00, 0x0b00,
+ 0x0b04, 0x0b04,
+ 0x0b0d, 0x0b0e,
+ 0x0b11, 0x0b12,
+ 0x0b29, 0x0b29,
+ 0x0b31, 0x0b31,
+ 0x0b34, 0x0b34,
+ 0x0b3a, 0x0b3b,
+ 0x0b45, 0x0b46,
+ 0x0b49, 0x0b4a,
+ 0x0b4e, 0x0b54,
+ 0x0b58, 0x0b5b,
+ 0x0b5e, 0x0b5e,
+ 0x0b64, 0x0b65,
+ 0x0b78, 0x0b81,
+ 0x0b84, 0x0b84,
+ 0x0b8b, 0x0b8d,
+ 0x0b91, 0x0b91,
+ 0x0b96, 0x0b98,
+ 0x0b9b, 0x0b9b,
+ 0x0b9d, 0x0b9d,
+ 0x0ba0, 0x0ba2,
+ 0x0ba5, 0x0ba7,
+ 0x0bab, 0x0bad,
+ 0x0bba, 0x0bbd,
+ 0x0bc3, 0x0bc5,
+ 0x0bc9, 0x0bc9,
+ 0x0bce, 0x0bcf,
+ 0x0bd1, 0x0bd6,
+ 0x0bd8, 0x0be5,
+ 0x0bfb, 0x0bff,
+ 0x0c0d, 0x0c0d,
+ 0x0c11, 0x0c11,
+ 0x0c29, 0x0c29,
+ 0x0c3a, 0x0c3b,
+ 0x0c45, 0x0c45,
+ 0x0c49, 0x0c49,
+ 0x0c4e, 0x0c54,
+ 0x0c57, 0x0c57,
+ 0x0c5b, 0x0c5b,
+ 0x0c5e, 0x0c5f,
+ 0x0c64, 0x0c65,
+ 0x0c70, 0x0c76,
+ 0x0c8d, 0x0c8d,
+ 0x0c91, 0x0c91,
+ 0x0ca9, 0x0ca9,
+ 0x0cb4, 0x0cb4,
+ 0x0cba, 0x0cbb,
+ 0x0cc5, 0x0cc5,
+ 0x0cc9, 0x0cc9,
+ 0x0cce, 0x0cd4,
+ 0x0cd7, 0x0cdb,
+ 0x0cdf, 0x0cdf,
+ 0x0ce4, 0x0ce5,
+ 0x0cf0, 0x0cf0,
+ 0x0cf4, 0x0cff,
+ 0x0d0d, 0x0d0d,
+ 0x0d11, 0x0d11,
+ 0x0d45, 0x0d45,
+ 0x0d49, 0x0d49,
+ 0x0d50, 0x0d53,
+ 0x0d64, 0x0d65,
+ 0x0d80, 0x0d80,
+ 0x0d84, 0x0d84,
+ 0x0d97, 0x0d99,
+ 0x0db2, 0x0db2,
+ 0x0dbc, 0x0dbc,
+ 0x0dbe, 0x0dbf,
+ 0x0dc7, 0x0dc9,
+ 0x0dcb, 0x0dce,
+ 0x0dd5, 0x0dd5,
+ 0x0dd7, 0x0dd7,
+ 0x0de0, 0x0de5,
+ 0x0df0, 0x0df1,
+ 0x0df5, 0x0e00,
+ 0x0e3b, 0x0e3e,
+ 0x0e5c, 0x0e80,
+ 0x0e83, 0x0e83,
+ 0x0e85, 0x0e85,
+ 0x0e8b, 0x0e8b,
+ 0x0ea4, 0x0ea4,
+ 0x0ea6, 0x0ea6,
+ 0x0ebe, 0x0ebf,
+ 0x0ec5, 0x0ec5,
+ 0x0ec7, 0x0ec7,
+ 0x0ecf, 0x0ecf,
+ 0x0eda, 0x0edb,
+ 0x0ee0, 0x0eff,
+ 0x0f48, 0x0f48,
+ 0x0f6d, 0x0f70,
+ 0x0f98, 0x0f98,
+ 0x0fbd, 0x0fbd,
+ 0x0fcd, 0x0fcd,
+ 0x0fdb, 0x0fff,
+ 0x10c6, 0x10c6,
+ 0x10c8, 0x10cc,
+ 0x10ce, 0x10cf,
+ 0x1249, 0x1249,
+ 0x124e, 0x124f,
+ 0x1257, 0x1257,
+ 0x1259, 0x1259,
+ 0x125e, 0x125f,
+ 0x1289, 0x1289,
+ 0x128e, 0x128f,
+ 0x12b1, 0x12b1,
+ 0x12b6, 0x12b7,
+ 0x12bf, 0x12bf,
+ 0x12c1, 0x12c1,
+ 0x12c6, 0x12c7,
+ 0x12d7, 0x12d7,
+ 0x1311, 0x1311,
+ 0x1316, 0x1317,
+ 0x135b, 0x135c,
+ 0x137d, 0x137f,
+ 0x139a, 0x139f,
+ 0x13f6, 0x13f7,
+ 0x13fe, 0x13ff,
+ 0x169d, 0x169f,
+ 0x16f9, 0x16ff,
+ 0x1716, 0x171e,
+ 0x1737, 0x173f,
+ 0x1754, 0x175f,
+ 0x176d, 0x176d,
+ 0x1771, 0x1771,
+ 0x1774, 0x177f,
+ 0x17de, 0x17df,
+ 0x17ea, 0x17ef,
+ 0x17fa, 0x17ff,
+ 0x180e, 0x180e,
+ 0x181a, 0x181f,
+ 0x1879, 0x187f,
+ 0x18ab, 0x18af,
+ 0x18f6, 0x18ff,
+ 0x191f, 0x191f,
+ 0x192c, 0x192f,
+ 0x193c, 0x193f,
+ 0x1941, 0x1943,
+ 0x196e, 0x196f,
+ 0x1975, 0x197f,
+ 0x19ac, 0x19af,
+ 0x19ca, 0x19cf,
+ 0x19db, 0x19dd,
+ 0x1a1c, 0x1a1d,
+ 0x1a5f, 0x1a5f,
+ 0x1a7d, 0x1a7e,
+ 0x1a8a, 0x1a8f,
+ 0x1a9a, 0x1a9f,
+ 0x1aae, 0x1aaf,
+ 0x1ade, 0x1adf,
+ 0x1aec, 0x1aff,
+ 0x1b4d, 0x1b4d,
+ 0x1bf4, 0x1bfb,
+ 0x1c38, 0x1c3a,
+ 0x1c4a, 0x1c4c,
+ 0x1c8b, 0x1c8f,
+ 0x1cbb, 0x1cbc,
+ 0x1cc8, 0x1ccf,
+ 0x1cfb, 0x1cff,
+ 0x1f16, 0x1f17,
+ 0x1f1e, 0x1f1f,
+ 0x1f46, 0x1f47,
+ 0x1f4e, 0x1f4f,
+ 0x1f58, 0x1f58,
+ 0x1f5a, 0x1f5a,
+ 0x1f5c, 0x1f5c,
+ 0x1f5e, 0x1f5e,
+ 0x1f7e, 0x1f7f,
+ 0x1fb5, 0x1fb5,
+ 0x1fc5, 0x1fc5,
+ 0x1fd4, 0x1fd5,
+ 0x1fdc, 0x1fdc,
+ 0x1ff0, 0x1ff1,
+ 0x1ff5, 0x1ff5,
+ 0x1fff, 0x1fff,
+ 0x200b, 0x200f,
+ 0x202a, 0x202e,
+ 0x2060, 0x206f,
+ 0x2072, 0x2073,
+ 0x208f, 0x208f,
+ 0x209d, 0x209f,
+ 0x20c2, 0x20cf,
+ 0x20f1, 0x20ff,
+ 0x218c, 0x218f,
+ 0x242a, 0x243f,
+ 0x244b, 0x245f,
+ 0x2b74, 0x2b75,
+ 0x2cf4, 0x2cf8,
+ 0x2d26, 0x2d26,
+ 0x2d28, 0x2d2c,
+ 0x2d2e, 0x2d2f,
+ 0x2d68, 0x2d6e,
+ 0x2d71, 0x2d7e,
+ 0x2d97, 0x2d9f,
+ 0x2da7, 0x2da7,
+ 0x2daf, 0x2daf,
+ 0x2db7, 0x2db7,
+ 0x2dbf, 0x2dbf,
+ 0x2dc7, 0x2dc7,
+ 0x2dcf, 0x2dcf,
+ 0x2dd7, 0x2dd7,
+ 0x2ddf, 0x2ddf,
+ 0x2e5e, 0x2e7f,
+ 0x2e9a, 0x2e9a,
+ 0x2ef4, 0x2eff,
+ 0x2fd6, 0x2fef,
+ 0x3040, 0x3040,
+ 0x3097, 0x3098,
+ 0x3100, 0x3104,
+ 0x3130, 0x3130,
+ 0x318f, 0x318f,
+ 0x31e6, 0x31ee,
+ 0x321f, 0x321f,
+ 0xa48d, 0xa48f,
+ 0xa4c7, 0xa4cf,
+ 0xa62c, 0xa63f,
+ 0xa6f8, 0xa6ff,
+ 0xa7dd, 0xa7f0,
+ 0xa82d, 0xa82f,
+ 0xa83a, 0xa83f,
+ 0xa878, 0xa87f,
+ 0xa8c6, 0xa8cd,
+ 0xa8da, 0xa8df,
+ 0xa954, 0xa95e,
+ 0xa97d, 0xa97f,
+ 0xa9ce, 0xa9ce,
+ 0xa9da, 0xa9dd,
+ 0xa9ff, 0xa9ff,
+ 0xaa37, 0xaa3f,
+ 0xaa4e, 0xaa4f,
+ 0xaa5a, 0xaa5b,
+ 0xaac3, 0xaada,
+ 0xaaf7, 0xab00,
+ 0xab07, 0xab08,
+ 0xab0f, 0xab10,
+ 0xab17, 0xab1f,
+ 0xab27, 0xab27,
+ 0xab2f, 0xab2f,
+ 0xab6c, 0xab6f,
+ 0xabee, 0xabef,
+ 0xabfa, 0xabff,
+ 0xd7a4, 0xd7af,
+ 0xd7c7, 0xd7ca,
+ 0xd7fc, 0xf8ff,
+ 0xfa6e, 0xfa6f,
+ 0xfada, 0xfaff,
+ 0xfb07, 0xfb12,
+ 0xfb18, 0xfb1c,
+ 0xfb37, 0xfb37,
+ 0xfb3d, 0xfb3d,
+ 0xfb3f, 0xfb3f,
+ 0xfb42, 0xfb42,
+ 0xfb45, 0xfb45,
+ 0xfdd0, 0xfdef,
+ 0xfe1a, 0xfe1f,
+ 0xfe53, 0xfe53,
+ 0xfe67, 0xfe67,
+ 0xfe6c, 0xfe6f,
+ 0xfe75, 0xfe75,
+ 0xfefd, 0xff00,
+ 0xffbf, 0xffc1,
+ 0xffc8, 0xffc9,
+ 0xffd0, 0xffd1,
+ 0xffd8, 0xffd9,
+ 0xffdd, 0xffdf,
+ 0xffe7, 0xffe7,
+ 0xffef, 0xfffb,
+ 0xfffe, 0xffff,
+ 0x1000c, 0x1000c,
+ 0x10027, 0x10027,
+ 0x1003b, 0x1003b,
+ 0x1003e, 0x1003e,
+ 0x1004e, 0x1004f,
+ 0x1005e, 0x1007f,
+ 0x100fb, 0x100ff,
+ 0x10103, 0x10106,
+ 0x10134, 0x10136,
+ 0x1018f, 0x1018f,
+ 0x1019d, 0x1019f,
+ 0x101a1, 0x101cf,
+ 0x101fe, 0x1027f,
+ 0x1029d, 0x1029f,
+ 0x102d1, 0x102df,
+ 0x102fc, 0x102ff,
+ 0x10324, 0x1032c,
+ 0x1034b, 0x1034f,
+ 0x1037b, 0x1037f,
+ 0x1039e, 0x1039e,
+ 0x103c4, 0x103c7,
+ 0x103d6, 0x103ff,
+ 0x1049e, 0x1049f,
+ 0x104aa, 0x104af,
+ 0x104d4, 0x104d7,
+ 0x104fc, 0x104ff,
+ 0x10528, 0x1052f,
+ 0x10564, 0x1056e,
+ 0x1057b, 0x1057b,
+ 0x1058b, 0x1058b,
+ 0x10593, 0x10593,
+ 0x10596, 0x10596,
+ 0x105a2, 0x105a2,
+ 0x105b2, 0x105b2,
+ 0x105ba, 0x105ba,
+ 0x105bd, 0x105bf,
+ 0x105f4, 0x105ff,
+ 0x10737, 0x1073f,
+ 0x10756, 0x1075f,
+ 0x10768, 0x1077f,
+ 0x10786, 0x10786,
+ 0x107b1, 0x107b1,
+ 0x107bb, 0x107ff,
+ 0x10806, 0x10807,
+ 0x10809, 0x10809,
+ 0x10836, 0x10836,
+ 0x10839, 0x1083b,
+ 0x1083d, 0x1083e,
+ 0x10856, 0x10856,
+ 0x1089f, 0x108a6,
+ 0x108b0, 0x108df,
+ 0x108f3, 0x108f3,
+ 0x108f6, 0x108fa,
+ 0x1091c, 0x1091e,
+ 0x1093a, 0x1093e,
+ 0x1095a, 0x1097f,
+ 0x109b8, 0x109bb,
+ 0x109d0, 0x109d1,
+ 0x10a04, 0x10a04,
+ 0x10a07, 0x10a0b,
+ 0x10a14, 0x10a14,
+ 0x10a18, 0x10a18,
+ 0x10a36, 0x10a37,
+ 0x10a3b, 0x10a3e,
+ 0x10a49, 0x10a4f,
+ 0x10a59, 0x10a5f,
+ 0x10aa0, 0x10abf,
+ 0x10ae7, 0x10aea,
+ 0x10af7, 0x10aff,
+ 0x10b36, 0x10b38,
+ 0x10b56, 0x10b57,
+ 0x10b73, 0x10b77,
+ 0x10b92, 0x10b98,
+ 0x10b9d, 0x10ba8,
+ 0x10bb0, 0x10bff,
+ 0x10c49, 0x10c7f,
+ 0x10cb3, 0x10cbf,
+ 0x10cf3, 0x10cf9,
+ 0x10d28, 0x10d2f,
+ 0x10d3a, 0x10d3f,
+ 0x10d66, 0x10d68,
+ 0x10d86, 0x10d8d,
+ 0x10d90, 0x10e5f,
+ 0x10e7f, 0x10e7f,
+ 0x10eaa, 0x10eaa,
+ 0x10eae, 0x10eaf,
+ 0x10eb2, 0x10ec1,
+ 0x10ec8, 0x10ecf,
+ 0x10ed9, 0x10ef9,
+ 0x10f28, 0x10f2f,
+ 0x10f5a, 0x10f6f,
+ 0x10f8a, 0x10faf,
+ 0x10fcc, 0x10fdf,
+ 0x10ff7, 0x10fff,
+ 0x1104e, 0x11051,
+ 0x11076, 0x1107e,
+ 0x110bd, 0x110bd,
+ 0x110c3, 0x110cf,
+ 0x110e9, 0x110ef,
+ 0x110fa, 0x110ff,
+ 0x11135, 0x11135,
+ 0x11148, 0x1114f,
+ 0x11177, 0x1117f,
+ 0x111e0, 0x111e0,
+ 0x111f5, 0x111ff,
+ 0x11212, 0x11212,
+ 0x11242, 0x1127f,
+ 0x11287, 0x11287,
+ 0x11289, 0x11289,
+ 0x1128e, 0x1128e,
+ 0x1129e, 0x1129e,
+ 0x112aa, 0x112af,
+ 0x112eb, 0x112ef,
+ 0x112fa, 0x112ff,
+ 0x11304, 0x11304,
+ 0x1130d, 0x1130e,
+ 0x11311, 0x11312,
+ 0x11329, 0x11329,
+ 0x11331, 0x11331,
+ 0x11334, 0x11334,
+ 0x1133a, 0x1133a,
+ 0x11345, 0x11346,
+ 0x11349, 0x1134a,
+ 0x1134e, 0x1134f,
+ 0x11351, 0x11356,
+ 0x11358, 0x1135c,
+ 0x11364, 0x11365,
+ 0x1136d, 0x1136f,
+ 0x11375, 0x1137f,
+ 0x1138a, 0x1138a,
+ 0x1138c, 0x1138d,
+ 0x1138f, 0x1138f,
+ 0x113b6, 0x113b6,
+ 0x113c1, 0x113c1,
+ 0x113c3, 0x113c4,
+ 0x113c6, 0x113c6,
+ 0x113cb, 0x113cb,
+ 0x113d6, 0x113d6,
+ 0x113d9, 0x113e0,
+ 0x113e3, 0x113ff,
+ 0x1145c, 0x1145c,
+ 0x11462, 0x1147f,
+ 0x114c8, 0x114cf,
+ 0x114da, 0x1157f,
+ 0x115b6, 0x115b7,
+ 0x115de, 0x115ff,
+ 0x11645, 0x1164f,
+ 0x1165a, 0x1165f,
+ 0x1166d, 0x1167f,
+ 0x116ba, 0x116bf,
+ 0x116ca, 0x116cf,
+ 0x116e4, 0x116ff,
+ 0x1171b, 0x1171c,
+ 0x1172c, 0x1172f,
+ 0x11747, 0x117ff,
+ 0x1183c, 0x1189f,
+ 0x118f3, 0x118fe,
+ 0x11907, 0x11908,
+ 0x1190a, 0x1190b,
+ 0x11914, 0x11914,
+ 0x11917, 0x11917,
+ 0x11936, 0x11936,
+ 0x11939, 0x1193a,
+ 0x11947, 0x1194f,
+ 0x1195a, 0x1199f,
+ 0x119a8, 0x119a9,
+ 0x119d8, 0x119d9,
+ 0x119e5, 0x119ff,
+ 0x11a48, 0x11a4f,
+ 0x11aa3, 0x11aaf,
+ 0x11af9, 0x11aff,
+ 0x11b0a, 0x11b5f,
+ 0x11b68, 0x11bbf,
+ 0x11be2, 0x11bef,
+ 0x11bfa, 0x11bff,
+ 0x11c09, 0x11c09,
+ 0x11c37, 0x11c37,
+ 0x11c46, 0x11c4f,
+ 0x11c6d, 0x11c6f,
+ 0x11c90, 0x11c91,
+ 0x11ca8, 0x11ca8,
+ 0x11cb7, 0x11cff,
+ 0x11d07, 0x11d07,
+ 0x11d0a, 0x11d0a,
+ 0x11d37, 0x11d39,
+ 0x11d3b, 0x11d3b,
+ 0x11d3e, 0x11d3e,
+ 0x11d48, 0x11d4f,
+ 0x11d5a, 0x11d5f,
+ 0x11d66, 0x11d66,
+ 0x11d69, 0x11d69,
+ 0x11d8f, 0x11d8f,
+ 0x11d92, 0x11d92,
+ 0x11d99, 0x11d9f,
+ 0x11daa, 0x11daf,
+ 0x11ddc, 0x11ddf,
+ 0x11dea, 0x11edf,
+ 0x11ef9, 0x11eff,
+ 0x11f11, 0x11f11,
+ 0x11f3b, 0x11f3d,
+ 0x11f5b, 0x11faf,
+ 0x11fb1, 0x11fbf,
+ 0x11ff2, 0x11ffe,
+ 0x1239a, 0x123ff,
+ 0x1246f, 0x1246f,
+ 0x12475, 0x1247f,
+ 0x12544, 0x12f8f,
+ 0x12ff3, 0x12fff,
+ 0x13430, 0x1343f,
+ 0x13456, 0x1345f,
+ 0x143fb, 0x143ff,
+ 0x14647, 0x160ff,
+ 0x1613a, 0x167ff,
+ 0x16a39, 0x16a3f,
+ 0x16a5f, 0x16a5f,
+ 0x16a6a, 0x16a6d,
+ 0x16abf, 0x16abf,
+ 0x16aca, 0x16acf,
+ 0x16aee, 0x16aef,
+ 0x16af6, 0x16aff,
+ 0x16b46, 0x16b4f,
+ 0x16b5a, 0x16b5a,
+ 0x16b62, 0x16b62,
+ 0x16b78, 0x16b7c,
+ 0x16b90, 0x16d3f,
+ 0x16d7a, 0x16e3f,
+ 0x16e9b, 0x16e9f,
+ 0x16eb9, 0x16eba,
+ 0x16ed4, 0x16eff,
+ 0x16f4b, 0x16f4e,
+ 0x16f88, 0x16f8e,
+ 0x16fa0, 0x16fdf,
+ 0x16fe5, 0x16fef,
+ 0x16ff7, 0x16fff,
+ 0x18cd6, 0x18cfe,
+ 0x18d1f, 0x18d7f,
+ 0x18df3, 0x1afef,
+ 0x1aff4, 0x1aff4,
+ 0x1affc, 0x1affc,
+ 0x1afff, 0x1afff,
+ 0x1b123, 0x1b131,
+ 0x1b133, 0x1b14f,
+ 0x1b153, 0x1b154,
+ 0x1b156, 0x1b163,
+ 0x1b168, 0x1b16f,
+ 0x1b2fc, 0x1bbff,
+ 0x1bc6b, 0x1bc6f,
+ 0x1bc7d, 0x1bc7f,
+ 0x1bc89, 0x1bc8f,
+ 0x1bc9a, 0x1bc9b,
+ 0x1bca0, 0x1cbff,
+ 0x1ccfd, 0x1ccff,
+ 0x1ceb4, 0x1ceb9,
+ 0x1ced1, 0x1cedf,
+ 0x1cef1, 0x1ceff,
+ 0x1cf2e, 0x1cf2f,
+ 0x1cf47, 0x1cf4f,
+ 0x1cfc4, 0x1cfff,
+ 0x1d0f6, 0x1d0ff,
+ 0x1d127, 0x1d128,
+ 0x1d173, 0x1d17a,
+ 0x1d1eb, 0x1d1ff,
+ 0x1d246, 0x1d2bf,
+ 0x1d2d4, 0x1d2df,
+ 0x1d2f4, 0x1d2ff,
+ 0x1d357, 0x1d35f,
+ 0x1d379, 0x1d3ff,
+ 0x1d455, 0x1d455,
+ 0x1d49d, 0x1d49d,
+ 0x1d4a0, 0x1d4a1,
+ 0x1d4a3, 0x1d4a4,
+ 0x1d4a7, 0x1d4a8,
+ 0x1d4ad, 0x1d4ad,
+ 0x1d4ba, 0x1d4ba,
+ 0x1d4bc, 0x1d4bc,
+ 0x1d4c4, 0x1d4c4,
+ 0x1d506, 0x1d506,
+ 0x1d50b, 0x1d50c,
+ 0x1d515, 0x1d515,
+ 0x1d51d, 0x1d51d,
+ 0x1d53a, 0x1d53a,
+ 0x1d53f, 0x1d53f,
+ 0x1d545, 0x1d545,
+ 0x1d547, 0x1d549,
+ 0x1d551, 0x1d551,
+ 0x1d6a6, 0x1d6a7,
+ 0x1d7cc, 0x1d7cd,
+ 0x1da8c, 0x1da9a,
+ 0x1daa0, 0x1daa0,
+ 0x1dab0, 0x1deff,
+ 0x1df1f, 0x1df24,
+ 0x1df2b, 0x1dfff,
+ 0x1e007, 0x1e007,
+ 0x1e019, 0x1e01a,
+ 0x1e022, 0x1e022,
+ 0x1e025, 0x1e025,
+ 0x1e02b, 0x1e02f,
+ 0x1e06e, 0x1e08e,
+ 0x1e090, 0x1e0ff,
+ 0x1e12d, 0x1e12f,
+ 0x1e13e, 0x1e13f,
+ 0x1e14a, 0x1e14d,
+ 0x1e150, 0x1e28f,
+ 0x1e2af, 0x1e2bf,
+ 0x1e2fa, 0x1e2fe,
+ 0x1e300, 0x1e4cf,
+ 0x1e4fa, 0x1e5cf,
+ 0x1e5fb, 0x1e5fe,
+ 0x1e600, 0x1e6bf,
+ 0x1e6df, 0x1e6df,
+ 0x1e6f6, 0x1e6fd,
+ 0x1e700, 0x1e7df,
+ 0x1e7e7, 0x1e7e7,
+ 0x1e7ec, 0x1e7ec,
+ 0x1e7ef, 0x1e7ef,
+ 0x1e7ff, 0x1e7ff,
+ 0x1e8c5, 0x1e8c6,
+ 0x1e8d7, 0x1e8ff,
+ 0x1e94c, 0x1e94f,
+ 0x1e95a, 0x1e95d,
+ 0x1e960, 0x1ec70,
+ 0x1ecb5, 0x1ed00,
+ 0x1ed3e, 0x1edff,
+ 0x1ee04, 0x1ee04,
+ 0x1ee20, 0x1ee20,
+ 0x1ee23, 0x1ee23,
+ 0x1ee25, 0x1ee26,
+ 0x1ee28, 0x1ee28,
+ 0x1ee33, 0x1ee33,
+ 0x1ee38, 0x1ee38,
+ 0x1ee3a, 0x1ee3a,
+ 0x1ee3c, 0x1ee41,
+ 0x1ee43, 0x1ee46,
+ 0x1ee48, 0x1ee48,
+ 0x1ee4a, 0x1ee4a,
+ 0x1ee4c, 0x1ee4c,
+ 0x1ee50, 0x1ee50,
+ 0x1ee53, 0x1ee53,
+ 0x1ee55, 0x1ee56,
+ 0x1ee58, 0x1ee58,
+ 0x1ee5a, 0x1ee5a,
+ 0x1ee5c, 0x1ee5c,
+ 0x1ee5e, 0x1ee5e,
+ 0x1ee60, 0x1ee60,
+ 0x1ee63, 0x1ee63,
+ 0x1ee65, 0x1ee66,
+ 0x1ee6b, 0x1ee6b,
+ 0x1ee73, 0x1ee73,
+ 0x1ee78, 0x1ee78,
+ 0x1ee7d, 0x1ee7d,
+ 0x1ee7f, 0x1ee7f,
+ 0x1ee8a, 0x1ee8a,
+ 0x1ee9c, 0x1eea0,
+ 0x1eea4, 0x1eea4,
+ 0x1eeaa, 0x1eeaa,
+ 0x1eebc, 0x1eeef,
+ 0x1eef2, 0x1efff,
+ 0x1f02c, 0x1f02f,
+ 0x1f094, 0x1f09f,
+ 0x1f0af, 0x1f0b0,
+ 0x1f0c0, 0x1f0c0,
+ 0x1f0d0, 0x1f0d0,
+ 0x1f0f6, 0x1f0ff,
+ 0x1f1ae, 0x1f1e5,
+ 0x1f203, 0x1f20f,
+ 0x1f23c, 0x1f23f,
+ 0x1f249, 0x1f24f,
+ 0x1f252, 0x1f25f,
+ 0x1f266, 0x1f2ff,
+ 0x1f6d9, 0x1f6db,
+ 0x1f6ed, 0x1f6ef,
+ 0x1f6fd, 0x1f6ff,
+ 0x1f7da, 0x1f7df,
+ 0x1f7ec, 0x1f7ef,
+ 0x1f7f1, 0x1f7ff,
+ 0x1f80c, 0x1f80f,
+ 0x1f848, 0x1f84f,
+ 0x1f85a, 0x1f85f,
+ 0x1f888, 0x1f88f,
+ 0x1f8ae, 0x1f8af,
+ 0x1f8bc, 0x1f8bf,
+ 0x1f8c2, 0x1f8cf,
+ 0x1f8d9, 0x1f8ff,
+ 0x1fa58, 0x1fa5f,
+ 0x1fa6e, 0x1fa6f,
+ 0x1fa7d, 0x1fa7f,
+ 0x1fa8b, 0x1fa8d,
+ 0x1fac7, 0x1fac7,
+ 0x1fac9, 0x1facc,
+ 0x1fadd, 0x1fade,
+ 0x1faeb, 0x1faee,
+ 0x1faf9, 0x1faff,
+ 0x1fb93, 0x1fb93,
+ 0x1fbfb, 0x1ffff,
+ 0x2a6e0, 0x2a6ff,
+ 0x2b81e, 0x2b81f,
+ 0x2ceae, 0x2ceaf,
+ 0x2ebe1, 0x2ebef,
+ 0x2ee5e, 0x2f7ff,
+ 0x2fa1e, 0x2ffff,
+ 0x3134b, 0x3134f,
+ 0x3347a, 0xe00ff,
+ 0xe01f0, 0x10ffff,
+}; /* CR_C */
+
+/* 'Cc': General Category */
+#define CR_Cc CR_Cntrl
+
+/* 'Cf': General Category */
+static const OnigCodePoint CR_Cf[] = {
+ 21,
+ 0x00ad, 0x00ad,
+ 0x0600, 0x0605,
+ 0x061c, 0x061c,
+ 0x06dd, 0x06dd,
+ 0x070f, 0x070f,
+ 0x0890, 0x0891,
+ 0x08e2, 0x08e2,
+ 0x180e, 0x180e,
+ 0x200b, 0x200f,
+ 0x202a, 0x202e,
+ 0x2060, 0x2064,
+ 0x2066, 0x206f,
+ 0xfeff, 0xfeff,
+ 0xfff9, 0xfffb,
+ 0x110bd, 0x110bd,
+ 0x110cd, 0x110cd,
+ 0x13430, 0x1343f,
+ 0x1bca0, 0x1bca3,
+ 0x1d173, 0x1d17a,
+ 0xe0001, 0xe0001,
+ 0xe0020, 0xe007f,
+}; /* CR_Cf */
+
+/* 'Cn': General Category */
+static const OnigCodePoint CR_Cn[] = {
+ 735,
+ 0x0378, 0x0379,
+ 0x0380, 0x0383,
+ 0x038b, 0x038b,
+ 0x038d, 0x038d,
+ 0x03a2, 0x03a2,
+ 0x0530, 0x0530,
+ 0x0557, 0x0558,
+ 0x058b, 0x058c,
+ 0x0590, 0x0590,
+ 0x05c8, 0x05cf,
+ 0x05eb, 0x05ee,
+ 0x05f5, 0x05ff,
+ 0x070e, 0x070e,
+ 0x074b, 0x074c,
+ 0x07b2, 0x07bf,
+ 0x07fb, 0x07fc,
+ 0x082e, 0x082f,
+ 0x083f, 0x083f,
+ 0x085c, 0x085d,
+ 0x085f, 0x085f,
+ 0x086b, 0x086f,
+ 0x0892, 0x0896,
+ 0x0984, 0x0984,
+ 0x098d, 0x098e,
+ 0x0991, 0x0992,
+ 0x09a9, 0x09a9,
+ 0x09b1, 0x09b1,
+ 0x09b3, 0x09b5,
+ 0x09ba, 0x09bb,
+ 0x09c5, 0x09c6,
+ 0x09c9, 0x09ca,
+ 0x09cf, 0x09d6,
+ 0x09d8, 0x09db,
+ 0x09de, 0x09de,
+ 0x09e4, 0x09e5,
+ 0x09ff, 0x0a00,
+ 0x0a04, 0x0a04,
+ 0x0a0b, 0x0a0e,
+ 0x0a11, 0x0a12,
+ 0x0a29, 0x0a29,
+ 0x0a31, 0x0a31,
+ 0x0a34, 0x0a34,
+ 0x0a37, 0x0a37,
+ 0x0a3a, 0x0a3b,
+ 0x0a3d, 0x0a3d,
+ 0x0a43, 0x0a46,
+ 0x0a49, 0x0a4a,
+ 0x0a4e, 0x0a50,
+ 0x0a52, 0x0a58,
+ 0x0a5d, 0x0a5d,
+ 0x0a5f, 0x0a65,
+ 0x0a77, 0x0a80,
+ 0x0a84, 0x0a84,
+ 0x0a8e, 0x0a8e,
+ 0x0a92, 0x0a92,
+ 0x0aa9, 0x0aa9,
+ 0x0ab1, 0x0ab1,
+ 0x0ab4, 0x0ab4,
+ 0x0aba, 0x0abb,
+ 0x0ac6, 0x0ac6,
+ 0x0aca, 0x0aca,
+ 0x0ace, 0x0acf,
+ 0x0ad1, 0x0adf,
+ 0x0ae4, 0x0ae5,
+ 0x0af2, 0x0af8,
+ 0x0b00, 0x0b00,
+ 0x0b04, 0x0b04,
+ 0x0b0d, 0x0b0e,
+ 0x0b11, 0x0b12,
+ 0x0b29, 0x0b29,
+ 0x0b31, 0x0b31,
+ 0x0b34, 0x0b34,
+ 0x0b3a, 0x0b3b,
+ 0x0b45, 0x0b46,
+ 0x0b49, 0x0b4a,
+ 0x0b4e, 0x0b54,
+ 0x0b58, 0x0b5b,
+ 0x0b5e, 0x0b5e,
+ 0x0b64, 0x0b65,
+ 0x0b78, 0x0b81,
+ 0x0b84, 0x0b84,
+ 0x0b8b, 0x0b8d,
+ 0x0b91, 0x0b91,
+ 0x0b96, 0x0b98,
+ 0x0b9b, 0x0b9b,
+ 0x0b9d, 0x0b9d,
+ 0x0ba0, 0x0ba2,
+ 0x0ba5, 0x0ba7,
+ 0x0bab, 0x0bad,
+ 0x0bba, 0x0bbd,
+ 0x0bc3, 0x0bc5,
+ 0x0bc9, 0x0bc9,
+ 0x0bce, 0x0bcf,
+ 0x0bd1, 0x0bd6,
+ 0x0bd8, 0x0be5,
+ 0x0bfb, 0x0bff,
+ 0x0c0d, 0x0c0d,
+ 0x0c11, 0x0c11,
+ 0x0c29, 0x0c29,
+ 0x0c3a, 0x0c3b,
+ 0x0c45, 0x0c45,
+ 0x0c49, 0x0c49,
+ 0x0c4e, 0x0c54,
+ 0x0c57, 0x0c57,
+ 0x0c5b, 0x0c5b,
+ 0x0c5e, 0x0c5f,
+ 0x0c64, 0x0c65,
+ 0x0c70, 0x0c76,
+ 0x0c8d, 0x0c8d,
+ 0x0c91, 0x0c91,
+ 0x0ca9, 0x0ca9,
+ 0x0cb4, 0x0cb4,
+ 0x0cba, 0x0cbb,
+ 0x0cc5, 0x0cc5,
+ 0x0cc9, 0x0cc9,
+ 0x0cce, 0x0cd4,
+ 0x0cd7, 0x0cdb,
+ 0x0cdf, 0x0cdf,
+ 0x0ce4, 0x0ce5,
+ 0x0cf0, 0x0cf0,
+ 0x0cf4, 0x0cff,
+ 0x0d0d, 0x0d0d,
+ 0x0d11, 0x0d11,
+ 0x0d45, 0x0d45,
+ 0x0d49, 0x0d49,
+ 0x0d50, 0x0d53,
+ 0x0d64, 0x0d65,
+ 0x0d80, 0x0d80,
+ 0x0d84, 0x0d84,
+ 0x0d97, 0x0d99,
+ 0x0db2, 0x0db2,
+ 0x0dbc, 0x0dbc,
+ 0x0dbe, 0x0dbf,
+ 0x0dc7, 0x0dc9,
+ 0x0dcb, 0x0dce,
+ 0x0dd5, 0x0dd5,
+ 0x0dd7, 0x0dd7,
+ 0x0de0, 0x0de5,
+ 0x0df0, 0x0df1,
+ 0x0df5, 0x0e00,
+ 0x0e3b, 0x0e3e,
+ 0x0e5c, 0x0e80,
+ 0x0e83, 0x0e83,
+ 0x0e85, 0x0e85,
+ 0x0e8b, 0x0e8b,
+ 0x0ea4, 0x0ea4,
+ 0x0ea6, 0x0ea6,
+ 0x0ebe, 0x0ebf,
+ 0x0ec5, 0x0ec5,
+ 0x0ec7, 0x0ec7,
+ 0x0ecf, 0x0ecf,
+ 0x0eda, 0x0edb,
+ 0x0ee0, 0x0eff,
+ 0x0f48, 0x0f48,
+ 0x0f6d, 0x0f70,
+ 0x0f98, 0x0f98,
+ 0x0fbd, 0x0fbd,
+ 0x0fcd, 0x0fcd,
+ 0x0fdb, 0x0fff,
+ 0x10c6, 0x10c6,
+ 0x10c8, 0x10cc,
+ 0x10ce, 0x10cf,
+ 0x1249, 0x1249,
+ 0x124e, 0x124f,
+ 0x1257, 0x1257,
+ 0x1259, 0x1259,
+ 0x125e, 0x125f,
+ 0x1289, 0x1289,
+ 0x128e, 0x128f,
+ 0x12b1, 0x12b1,
+ 0x12b6, 0x12b7,
+ 0x12bf, 0x12bf,
+ 0x12c1, 0x12c1,
+ 0x12c6, 0x12c7,
+ 0x12d7, 0x12d7,
+ 0x1311, 0x1311,
+ 0x1316, 0x1317,
+ 0x135b, 0x135c,
+ 0x137d, 0x137f,
+ 0x139a, 0x139f,
+ 0x13f6, 0x13f7,
+ 0x13fe, 0x13ff,
+ 0x169d, 0x169f,
+ 0x16f9, 0x16ff,
+ 0x1716, 0x171e,
+ 0x1737, 0x173f,
+ 0x1754, 0x175f,
+ 0x176d, 0x176d,
+ 0x1771, 0x1771,
+ 0x1774, 0x177f,
+ 0x17de, 0x17df,
+ 0x17ea, 0x17ef,
+ 0x17fa, 0x17ff,
+ 0x181a, 0x181f,
+ 0x1879, 0x187f,
+ 0x18ab, 0x18af,
+ 0x18f6, 0x18ff,
+ 0x191f, 0x191f,
+ 0x192c, 0x192f,
+ 0x193c, 0x193f,
+ 0x1941, 0x1943,
+ 0x196e, 0x196f,
+ 0x1975, 0x197f,
+ 0x19ac, 0x19af,
+ 0x19ca, 0x19cf,
+ 0x19db, 0x19dd,
+ 0x1a1c, 0x1a1d,
+ 0x1a5f, 0x1a5f,
+ 0x1a7d, 0x1a7e,
+ 0x1a8a, 0x1a8f,
+ 0x1a9a, 0x1a9f,
+ 0x1aae, 0x1aaf,
+ 0x1ade, 0x1adf,
+ 0x1aec, 0x1aff,
+ 0x1b4d, 0x1b4d,
+ 0x1bf4, 0x1bfb,
+ 0x1c38, 0x1c3a,
+ 0x1c4a, 0x1c4c,
+ 0x1c8b, 0x1c8f,
+ 0x1cbb, 0x1cbc,
+ 0x1cc8, 0x1ccf,
+ 0x1cfb, 0x1cff,
+ 0x1f16, 0x1f17,
+ 0x1f1e, 0x1f1f,
+ 0x1f46, 0x1f47,
+ 0x1f4e, 0x1f4f,
+ 0x1f58, 0x1f58,
+ 0x1f5a, 0x1f5a,
+ 0x1f5c, 0x1f5c,
+ 0x1f5e, 0x1f5e,
+ 0x1f7e, 0x1f7f,
+ 0x1fb5, 0x1fb5,
+ 0x1fc5, 0x1fc5,
+ 0x1fd4, 0x1fd5,
+ 0x1fdc, 0x1fdc,
+ 0x1ff0, 0x1ff1,
+ 0x1ff5, 0x1ff5,
+ 0x1fff, 0x1fff,
+ 0x2065, 0x2065,
+ 0x2072, 0x2073,
+ 0x208f, 0x208f,
+ 0x209d, 0x209f,
+ 0x20c2, 0x20cf,
+ 0x20f1, 0x20ff,
+ 0x218c, 0x218f,
+ 0x242a, 0x243f,
+ 0x244b, 0x245f,
+ 0x2b74, 0x2b75,
+ 0x2cf4, 0x2cf8,
+ 0x2d26, 0x2d26,
+ 0x2d28, 0x2d2c,
+ 0x2d2e, 0x2d2f,
+ 0x2d68, 0x2d6e,
+ 0x2d71, 0x2d7e,
+ 0x2d97, 0x2d9f,
+ 0x2da7, 0x2da7,
+ 0x2daf, 0x2daf,
+ 0x2db7, 0x2db7,
+ 0x2dbf, 0x2dbf,
+ 0x2dc7, 0x2dc7,
+ 0x2dcf, 0x2dcf,
+ 0x2dd7, 0x2dd7,
+ 0x2ddf, 0x2ddf,
+ 0x2e5e, 0x2e7f,
+ 0x2e9a, 0x2e9a,
+ 0x2ef4, 0x2eff,
+ 0x2fd6, 0x2fef,
+ 0x3040, 0x3040,
+ 0x3097, 0x3098,
+ 0x3100, 0x3104,
+ 0x3130, 0x3130,
+ 0x318f, 0x318f,
+ 0x31e6, 0x31ee,
+ 0x321f, 0x321f,
+ 0xa48d, 0xa48f,
+ 0xa4c7, 0xa4cf,
+ 0xa62c, 0xa63f,
+ 0xa6f8, 0xa6ff,
+ 0xa7dd, 0xa7f0,
+ 0xa82d, 0xa82f,
+ 0xa83a, 0xa83f,
+ 0xa878, 0xa87f,
+ 0xa8c6, 0xa8cd,
+ 0xa8da, 0xa8df,
+ 0xa954, 0xa95e,
+ 0xa97d, 0xa97f,
+ 0xa9ce, 0xa9ce,
+ 0xa9da, 0xa9dd,
+ 0xa9ff, 0xa9ff,
+ 0xaa37, 0xaa3f,
+ 0xaa4e, 0xaa4f,
+ 0xaa5a, 0xaa5b,
+ 0xaac3, 0xaada,
+ 0xaaf7, 0xab00,
+ 0xab07, 0xab08,
+ 0xab0f, 0xab10,
+ 0xab17, 0xab1f,
+ 0xab27, 0xab27,
+ 0xab2f, 0xab2f,
+ 0xab6c, 0xab6f,
+ 0xabee, 0xabef,
+ 0xabfa, 0xabff,
+ 0xd7a4, 0xd7af,
+ 0xd7c7, 0xd7ca,
+ 0xd7fc, 0xd7ff,
+ 0xfa6e, 0xfa6f,
+ 0xfada, 0xfaff,
+ 0xfb07, 0xfb12,
+ 0xfb18, 0xfb1c,
+ 0xfb37, 0xfb37,
+ 0xfb3d, 0xfb3d,
+ 0xfb3f, 0xfb3f,
+ 0xfb42, 0xfb42,
+ 0xfb45, 0xfb45,
+ 0xfdd0, 0xfdef,
+ 0xfe1a, 0xfe1f,
+ 0xfe53, 0xfe53,
+ 0xfe67, 0xfe67,
+ 0xfe6c, 0xfe6f,
+ 0xfe75, 0xfe75,
+ 0xfefd, 0xfefe,
+ 0xff00, 0xff00,
+ 0xffbf, 0xffc1,
+ 0xffc8, 0xffc9,
+ 0xffd0, 0xffd1,
+ 0xffd8, 0xffd9,
+ 0xffdd, 0xffdf,
+ 0xffe7, 0xffe7,
+ 0xffef, 0xfff8,
+ 0xfffe, 0xffff,
+ 0x1000c, 0x1000c,
+ 0x10027, 0x10027,
+ 0x1003b, 0x1003b,
+ 0x1003e, 0x1003e,
+ 0x1004e, 0x1004f,
+ 0x1005e, 0x1007f,
+ 0x100fb, 0x100ff,
+ 0x10103, 0x10106,
+ 0x10134, 0x10136,
+ 0x1018f, 0x1018f,
+ 0x1019d, 0x1019f,
+ 0x101a1, 0x101cf,
+ 0x101fe, 0x1027f,
+ 0x1029d, 0x1029f,
+ 0x102d1, 0x102df,
+ 0x102fc, 0x102ff,
+ 0x10324, 0x1032c,
+ 0x1034b, 0x1034f,
+ 0x1037b, 0x1037f,
+ 0x1039e, 0x1039e,
+ 0x103c4, 0x103c7,
+ 0x103d6, 0x103ff,
+ 0x1049e, 0x1049f,
+ 0x104aa, 0x104af,
+ 0x104d4, 0x104d7,
+ 0x104fc, 0x104ff,
+ 0x10528, 0x1052f,
+ 0x10564, 0x1056e,
+ 0x1057b, 0x1057b,
+ 0x1058b, 0x1058b,
+ 0x10593, 0x10593,
+ 0x10596, 0x10596,
+ 0x105a2, 0x105a2,
+ 0x105b2, 0x105b2,
+ 0x105ba, 0x105ba,
+ 0x105bd, 0x105bf,
+ 0x105f4, 0x105ff,
+ 0x10737, 0x1073f,
+ 0x10756, 0x1075f,
+ 0x10768, 0x1077f,
+ 0x10786, 0x10786,
+ 0x107b1, 0x107b1,
+ 0x107bb, 0x107ff,
+ 0x10806, 0x10807,
+ 0x10809, 0x10809,
+ 0x10836, 0x10836,
+ 0x10839, 0x1083b,
+ 0x1083d, 0x1083e,
+ 0x10856, 0x10856,
+ 0x1089f, 0x108a6,
+ 0x108b0, 0x108df,
+ 0x108f3, 0x108f3,
+ 0x108f6, 0x108fa,
+ 0x1091c, 0x1091e,
+ 0x1093a, 0x1093e,
+ 0x1095a, 0x1097f,
+ 0x109b8, 0x109bb,
+ 0x109d0, 0x109d1,
+ 0x10a04, 0x10a04,
+ 0x10a07, 0x10a0b,
+ 0x10a14, 0x10a14,
+ 0x10a18, 0x10a18,
+ 0x10a36, 0x10a37,
+ 0x10a3b, 0x10a3e,
+ 0x10a49, 0x10a4f,
+ 0x10a59, 0x10a5f,
+ 0x10aa0, 0x10abf,
+ 0x10ae7, 0x10aea,
+ 0x10af7, 0x10aff,
+ 0x10b36, 0x10b38,
+ 0x10b56, 0x10b57,
+ 0x10b73, 0x10b77,
+ 0x10b92, 0x10b98,
+ 0x10b9d, 0x10ba8,
+ 0x10bb0, 0x10bff,
+ 0x10c49, 0x10c7f,
+ 0x10cb3, 0x10cbf,
+ 0x10cf3, 0x10cf9,
+ 0x10d28, 0x10d2f,
+ 0x10d3a, 0x10d3f,
+ 0x10d66, 0x10d68,
+ 0x10d86, 0x10d8d,
+ 0x10d90, 0x10e5f,
+ 0x10e7f, 0x10e7f,
+ 0x10eaa, 0x10eaa,
+ 0x10eae, 0x10eaf,
+ 0x10eb2, 0x10ec1,
+ 0x10ec8, 0x10ecf,
+ 0x10ed9, 0x10ef9,
+ 0x10f28, 0x10f2f,
+ 0x10f5a, 0x10f6f,
+ 0x10f8a, 0x10faf,
+ 0x10fcc, 0x10fdf,
+ 0x10ff7, 0x10fff,
+ 0x1104e, 0x11051,
+ 0x11076, 0x1107e,
+ 0x110c3, 0x110cc,
+ 0x110ce, 0x110cf,
+ 0x110e9, 0x110ef,
+ 0x110fa, 0x110ff,
+ 0x11135, 0x11135,
+ 0x11148, 0x1114f,
+ 0x11177, 0x1117f,
+ 0x111e0, 0x111e0,
+ 0x111f5, 0x111ff,
+ 0x11212, 0x11212,
+ 0x11242, 0x1127f,
+ 0x11287, 0x11287,
+ 0x11289, 0x11289,
+ 0x1128e, 0x1128e,
+ 0x1129e, 0x1129e,
+ 0x112aa, 0x112af,
+ 0x112eb, 0x112ef,
+ 0x112fa, 0x112ff,
+ 0x11304, 0x11304,
+ 0x1130d, 0x1130e,
+ 0x11311, 0x11312,
+ 0x11329, 0x11329,
+ 0x11331, 0x11331,
+ 0x11334, 0x11334,
+ 0x1133a, 0x1133a,
+ 0x11345, 0x11346,
+ 0x11349, 0x1134a,
+ 0x1134e, 0x1134f,
+ 0x11351, 0x11356,
+ 0x11358, 0x1135c,
+ 0x11364, 0x11365,
+ 0x1136d, 0x1136f,
+ 0x11375, 0x1137f,
+ 0x1138a, 0x1138a,
+ 0x1138c, 0x1138d,
+ 0x1138f, 0x1138f,
+ 0x113b6, 0x113b6,
+ 0x113c1, 0x113c1,
+ 0x113c3, 0x113c4,
+ 0x113c6, 0x113c6,
+ 0x113cb, 0x113cb,
+ 0x113d6, 0x113d6,
+ 0x113d9, 0x113e0,
+ 0x113e3, 0x113ff,
+ 0x1145c, 0x1145c,
+ 0x11462, 0x1147f,
+ 0x114c8, 0x114cf,
+ 0x114da, 0x1157f,
+ 0x115b6, 0x115b7,
+ 0x115de, 0x115ff,
+ 0x11645, 0x1164f,
+ 0x1165a, 0x1165f,
+ 0x1166d, 0x1167f,
+ 0x116ba, 0x116bf,
+ 0x116ca, 0x116cf,
+ 0x116e4, 0x116ff,
+ 0x1171b, 0x1171c,
+ 0x1172c, 0x1172f,
+ 0x11747, 0x117ff,
+ 0x1183c, 0x1189f,
+ 0x118f3, 0x118fe,
+ 0x11907, 0x11908,
+ 0x1190a, 0x1190b,
+ 0x11914, 0x11914,
+ 0x11917, 0x11917,
+ 0x11936, 0x11936,
+ 0x11939, 0x1193a,
+ 0x11947, 0x1194f,
+ 0x1195a, 0x1199f,
+ 0x119a8, 0x119a9,
+ 0x119d8, 0x119d9,
+ 0x119e5, 0x119ff,
+ 0x11a48, 0x11a4f,
+ 0x11aa3, 0x11aaf,
+ 0x11af9, 0x11aff,
+ 0x11b0a, 0x11b5f,
+ 0x11b68, 0x11bbf,
+ 0x11be2, 0x11bef,
+ 0x11bfa, 0x11bff,
+ 0x11c09, 0x11c09,
+ 0x11c37, 0x11c37,
+ 0x11c46, 0x11c4f,
+ 0x11c6d, 0x11c6f,
+ 0x11c90, 0x11c91,
+ 0x11ca8, 0x11ca8,
+ 0x11cb7, 0x11cff,
+ 0x11d07, 0x11d07,
+ 0x11d0a, 0x11d0a,
+ 0x11d37, 0x11d39,
+ 0x11d3b, 0x11d3b,
+ 0x11d3e, 0x11d3e,
+ 0x11d48, 0x11d4f,
+ 0x11d5a, 0x11d5f,
+ 0x11d66, 0x11d66,
+ 0x11d69, 0x11d69,
+ 0x11d8f, 0x11d8f,
+ 0x11d92, 0x11d92,
+ 0x11d99, 0x11d9f,
+ 0x11daa, 0x11daf,
+ 0x11ddc, 0x11ddf,
+ 0x11dea, 0x11edf,
+ 0x11ef9, 0x11eff,
+ 0x11f11, 0x11f11,
+ 0x11f3b, 0x11f3d,
+ 0x11f5b, 0x11faf,
+ 0x11fb1, 0x11fbf,
+ 0x11ff2, 0x11ffe,
+ 0x1239a, 0x123ff,
+ 0x1246f, 0x1246f,
+ 0x12475, 0x1247f,
+ 0x12544, 0x12f8f,
+ 0x12ff3, 0x12fff,
+ 0x13456, 0x1345f,
+ 0x143fb, 0x143ff,
+ 0x14647, 0x160ff,
+ 0x1613a, 0x167ff,
+ 0x16a39, 0x16a3f,
+ 0x16a5f, 0x16a5f,
+ 0x16a6a, 0x16a6d,
+ 0x16abf, 0x16abf,
+ 0x16aca, 0x16acf,
+ 0x16aee, 0x16aef,
+ 0x16af6, 0x16aff,
+ 0x16b46, 0x16b4f,
+ 0x16b5a, 0x16b5a,
+ 0x16b62, 0x16b62,
+ 0x16b78, 0x16b7c,
+ 0x16b90, 0x16d3f,
+ 0x16d7a, 0x16e3f,
+ 0x16e9b, 0x16e9f,
+ 0x16eb9, 0x16eba,
+ 0x16ed4, 0x16eff,
+ 0x16f4b, 0x16f4e,
+ 0x16f88, 0x16f8e,
+ 0x16fa0, 0x16fdf,
+ 0x16fe5, 0x16fef,
+ 0x16ff7, 0x16fff,
+ 0x18cd6, 0x18cfe,
+ 0x18d1f, 0x18d7f,
+ 0x18df3, 0x1afef,
+ 0x1aff4, 0x1aff4,
+ 0x1affc, 0x1affc,
+ 0x1afff, 0x1afff,
+ 0x1b123, 0x1b131,
+ 0x1b133, 0x1b14f,
+ 0x1b153, 0x1b154,
+ 0x1b156, 0x1b163,
+ 0x1b168, 0x1b16f,
+ 0x1b2fc, 0x1bbff,
+ 0x1bc6b, 0x1bc6f,
+ 0x1bc7d, 0x1bc7f,
+ 0x1bc89, 0x1bc8f,
+ 0x1bc9a, 0x1bc9b,
+ 0x1bca4, 0x1cbff,
+ 0x1ccfd, 0x1ccff,
+ 0x1ceb4, 0x1ceb9,
+ 0x1ced1, 0x1cedf,
+ 0x1cef1, 0x1ceff,
+ 0x1cf2e, 0x1cf2f,
+ 0x1cf47, 0x1cf4f,
+ 0x1cfc4, 0x1cfff,
+ 0x1d0f6, 0x1d0ff,
+ 0x1d127, 0x1d128,
+ 0x1d1eb, 0x1d1ff,
+ 0x1d246, 0x1d2bf,
+ 0x1d2d4, 0x1d2df,
+ 0x1d2f4, 0x1d2ff,
+ 0x1d357, 0x1d35f,
+ 0x1d379, 0x1d3ff,
+ 0x1d455, 0x1d455,
+ 0x1d49d, 0x1d49d,
+ 0x1d4a0, 0x1d4a1,
+ 0x1d4a3, 0x1d4a4,
+ 0x1d4a7, 0x1d4a8,
+ 0x1d4ad, 0x1d4ad,
+ 0x1d4ba, 0x1d4ba,
+ 0x1d4bc, 0x1d4bc,
+ 0x1d4c4, 0x1d4c4,
+ 0x1d506, 0x1d506,
+ 0x1d50b, 0x1d50c,
+ 0x1d515, 0x1d515,
+ 0x1d51d, 0x1d51d,
+ 0x1d53a, 0x1d53a,
+ 0x1d53f, 0x1d53f,
+ 0x1d545, 0x1d545,
+ 0x1d547, 0x1d549,
+ 0x1d551, 0x1d551,
+ 0x1d6a6, 0x1d6a7,
+ 0x1d7cc, 0x1d7cd,
+ 0x1da8c, 0x1da9a,
+ 0x1daa0, 0x1daa0,
+ 0x1dab0, 0x1deff,
+ 0x1df1f, 0x1df24,
+ 0x1df2b, 0x1dfff,
+ 0x1e007, 0x1e007,
+ 0x1e019, 0x1e01a,
+ 0x1e022, 0x1e022,
+ 0x1e025, 0x1e025,
+ 0x1e02b, 0x1e02f,
+ 0x1e06e, 0x1e08e,
+ 0x1e090, 0x1e0ff,
+ 0x1e12d, 0x1e12f,
+ 0x1e13e, 0x1e13f,
+ 0x1e14a, 0x1e14d,
+ 0x1e150, 0x1e28f,
+ 0x1e2af, 0x1e2bf,
+ 0x1e2fa, 0x1e2fe,
+ 0x1e300, 0x1e4cf,
+ 0x1e4fa, 0x1e5cf,
+ 0x1e5fb, 0x1e5fe,
+ 0x1e600, 0x1e6bf,
+ 0x1e6df, 0x1e6df,
+ 0x1e6f6, 0x1e6fd,
+ 0x1e700, 0x1e7df,
+ 0x1e7e7, 0x1e7e7,
+ 0x1e7ec, 0x1e7ec,
+ 0x1e7ef, 0x1e7ef,
+ 0x1e7ff, 0x1e7ff,
+ 0x1e8c5, 0x1e8c6,
+ 0x1e8d7, 0x1e8ff,
+ 0x1e94c, 0x1e94f,
+ 0x1e95a, 0x1e95d,
+ 0x1e960, 0x1ec70,
+ 0x1ecb5, 0x1ed00,
+ 0x1ed3e, 0x1edff,
+ 0x1ee04, 0x1ee04,
+ 0x1ee20, 0x1ee20,
+ 0x1ee23, 0x1ee23,
+ 0x1ee25, 0x1ee26,
+ 0x1ee28, 0x1ee28,
+ 0x1ee33, 0x1ee33,
+ 0x1ee38, 0x1ee38,
+ 0x1ee3a, 0x1ee3a,
+ 0x1ee3c, 0x1ee41,
+ 0x1ee43, 0x1ee46,
+ 0x1ee48, 0x1ee48,
+ 0x1ee4a, 0x1ee4a,
+ 0x1ee4c, 0x1ee4c,
+ 0x1ee50, 0x1ee50,
+ 0x1ee53, 0x1ee53,
+ 0x1ee55, 0x1ee56,
+ 0x1ee58, 0x1ee58,
+ 0x1ee5a, 0x1ee5a,
+ 0x1ee5c, 0x1ee5c,
+ 0x1ee5e, 0x1ee5e,
+ 0x1ee60, 0x1ee60,
+ 0x1ee63, 0x1ee63,
+ 0x1ee65, 0x1ee66,
+ 0x1ee6b, 0x1ee6b,
+ 0x1ee73, 0x1ee73,
+ 0x1ee78, 0x1ee78,
+ 0x1ee7d, 0x1ee7d,
+ 0x1ee7f, 0x1ee7f,
+ 0x1ee8a, 0x1ee8a,
+ 0x1ee9c, 0x1eea0,
+ 0x1eea4, 0x1eea4,
+ 0x1eeaa, 0x1eeaa,
+ 0x1eebc, 0x1eeef,
+ 0x1eef2, 0x1efff,
+ 0x1f02c, 0x1f02f,
+ 0x1f094, 0x1f09f,
+ 0x1f0af, 0x1f0b0,
+ 0x1f0c0, 0x1f0c0,
+ 0x1f0d0, 0x1f0d0,
+ 0x1f0f6, 0x1f0ff,
+ 0x1f1ae, 0x1f1e5,
+ 0x1f203, 0x1f20f,
+ 0x1f23c, 0x1f23f,
+ 0x1f249, 0x1f24f,
+ 0x1f252, 0x1f25f,
+ 0x1f266, 0x1f2ff,
+ 0x1f6d9, 0x1f6db,
+ 0x1f6ed, 0x1f6ef,
+ 0x1f6fd, 0x1f6ff,
+ 0x1f7da, 0x1f7df,
+ 0x1f7ec, 0x1f7ef,
+ 0x1f7f1, 0x1f7ff,
+ 0x1f80c, 0x1f80f,
+ 0x1f848, 0x1f84f,
+ 0x1f85a, 0x1f85f,
+ 0x1f888, 0x1f88f,
+ 0x1f8ae, 0x1f8af,
+ 0x1f8bc, 0x1f8bf,
+ 0x1f8c2, 0x1f8cf,
+ 0x1f8d9, 0x1f8ff,
+ 0x1fa58, 0x1fa5f,
+ 0x1fa6e, 0x1fa6f,
+ 0x1fa7d, 0x1fa7f,
+ 0x1fa8b, 0x1fa8d,
+ 0x1fac7, 0x1fac7,
+ 0x1fac9, 0x1facc,
+ 0x1fadd, 0x1fade,
+ 0x1faeb, 0x1faee,
+ 0x1faf9, 0x1faff,
+ 0x1fb93, 0x1fb93,
+ 0x1fbfb, 0x1ffff,
+ 0x2a6e0, 0x2a6ff,
+ 0x2b81e, 0x2b81f,
+ 0x2ceae, 0x2ceaf,
+ 0x2ebe1, 0x2ebef,
+ 0x2ee5e, 0x2f7ff,
+ 0x2fa1e, 0x2ffff,
+ 0x3134b, 0x3134f,
+ 0x3347a, 0xe0000,
+ 0xe0002, 0xe001f,
+ 0xe0080, 0xe00ff,
+ 0xe01f0, 0xeffff,
+ 0xffffe, 0xfffff,
+ 0x10fffe, 0x10ffff,
+}; /* CR_Cn */
+
+/* 'Co': General Category */
+static const OnigCodePoint CR_Co[] = {
+ 3,
+ 0xe000, 0xf8ff,
+ 0xf0000, 0xffffd,
+ 0x100000, 0x10fffd,
+}; /* CR_Co */
+
+/* 'Cs': General Category */
+static const OnigCodePoint CR_Cs[] = {
+ 1,
+ 0xd800, 0xdfff,
+}; /* CR_Cs */
+
+/* 'L': Major Category */
+static const OnigCodePoint CR_L[] = {
+ 684,
+ 0x0041, 0x005a,
+ 0x0061, 0x007a,
+ 0x00aa, 0x00aa,
+ 0x00b5, 0x00b5,
+ 0x00ba, 0x00ba,
+ 0x00c0, 0x00d6,
+ 0x00d8, 0x00f6,
+ 0x00f8, 0x02c1,
+ 0x02c6, 0x02d1,
+ 0x02e0, 0x02e4,
+ 0x02ec, 0x02ec,
+ 0x02ee, 0x02ee,
+ 0x0370, 0x0374,
+ 0x0376, 0x0377,
+ 0x037a, 0x037d,
+ 0x037f, 0x037f,
+ 0x0386, 0x0386,
+ 0x0388, 0x038a,
+ 0x038c, 0x038c,
+ 0x038e, 0x03a1,
+ 0x03a3, 0x03f5,
+ 0x03f7, 0x0481,
+ 0x048a, 0x052f,
+ 0x0531, 0x0556,
+ 0x0559, 0x0559,
+ 0x0560, 0x0588,
+ 0x05d0, 0x05ea,
+ 0x05ef, 0x05f2,
+ 0x0620, 0x064a,
+ 0x066e, 0x066f,
+ 0x0671, 0x06d3,
+ 0x06d5, 0x06d5,
+ 0x06e5, 0x06e6,
+ 0x06ee, 0x06ef,
+ 0x06fa, 0x06fc,
+ 0x06ff, 0x06ff,
+ 0x0710, 0x0710,
+ 0x0712, 0x072f,
+ 0x074d, 0x07a5,
+ 0x07b1, 0x07b1,
+ 0x07ca, 0x07ea,
+ 0x07f4, 0x07f5,
+ 0x07fa, 0x07fa,
+ 0x0800, 0x0815,
+ 0x081a, 0x081a,
+ 0x0824, 0x0824,
+ 0x0828, 0x0828,
+ 0x0840, 0x0858,
+ 0x0860, 0x086a,
+ 0x0870, 0x0887,
+ 0x0889, 0x088f,
+ 0x08a0, 0x08c9,
+ 0x0904, 0x0939,
+ 0x093d, 0x093d,
+ 0x0950, 0x0950,
+ 0x0958, 0x0961,
+ 0x0971, 0x0980,
+ 0x0985, 0x098c,
+ 0x098f, 0x0990,
+ 0x0993, 0x09a8,
+ 0x09aa, 0x09b0,
+ 0x09b2, 0x09b2,
+ 0x09b6, 0x09b9,
+ 0x09bd, 0x09bd,
+ 0x09ce, 0x09ce,
+ 0x09dc, 0x09dd,
+ 0x09df, 0x09e1,
+ 0x09f0, 0x09f1,
+ 0x09fc, 0x09fc,
+ 0x0a05, 0x0a0a,
+ 0x0a0f, 0x0a10,
+ 0x0a13, 0x0a28,
+ 0x0a2a, 0x0a30,
+ 0x0a32, 0x0a33,
+ 0x0a35, 0x0a36,
+ 0x0a38, 0x0a39,
+ 0x0a59, 0x0a5c,
+ 0x0a5e, 0x0a5e,
+ 0x0a72, 0x0a74,
+ 0x0a85, 0x0a8d,
+ 0x0a8f, 0x0a91,
+ 0x0a93, 0x0aa8,
+ 0x0aaa, 0x0ab0,
+ 0x0ab2, 0x0ab3,
+ 0x0ab5, 0x0ab9,
+ 0x0abd, 0x0abd,
+ 0x0ad0, 0x0ad0,
+ 0x0ae0, 0x0ae1,
+ 0x0af9, 0x0af9,
+ 0x0b05, 0x0b0c,
+ 0x0b0f, 0x0b10,
+ 0x0b13, 0x0b28,
+ 0x0b2a, 0x0b30,
+ 0x0b32, 0x0b33,
+ 0x0b35, 0x0b39,
+ 0x0b3d, 0x0b3d,
+ 0x0b5c, 0x0b5d,
+ 0x0b5f, 0x0b61,
+ 0x0b71, 0x0b71,
+ 0x0b83, 0x0b83,
+ 0x0b85, 0x0b8a,
+ 0x0b8e, 0x0b90,
+ 0x0b92, 0x0b95,
+ 0x0b99, 0x0b9a,
+ 0x0b9c, 0x0b9c,
+ 0x0b9e, 0x0b9f,
+ 0x0ba3, 0x0ba4,
+ 0x0ba8, 0x0baa,
+ 0x0bae, 0x0bb9,
+ 0x0bd0, 0x0bd0,
+ 0x0c05, 0x0c0c,
+ 0x0c0e, 0x0c10,
+ 0x0c12, 0x0c28,
+ 0x0c2a, 0x0c39,
+ 0x0c3d, 0x0c3d,
+ 0x0c58, 0x0c5a,
+ 0x0c5c, 0x0c5d,
+ 0x0c60, 0x0c61,
+ 0x0c80, 0x0c80,
+ 0x0c85, 0x0c8c,
+ 0x0c8e, 0x0c90,
+ 0x0c92, 0x0ca8,
+ 0x0caa, 0x0cb3,
+ 0x0cb5, 0x0cb9,
+ 0x0cbd, 0x0cbd,
+ 0x0cdc, 0x0cde,
+ 0x0ce0, 0x0ce1,
+ 0x0cf1, 0x0cf2,
+ 0x0d04, 0x0d0c,
+ 0x0d0e, 0x0d10,
+ 0x0d12, 0x0d3a,
+ 0x0d3d, 0x0d3d,
+ 0x0d4e, 0x0d4e,
+ 0x0d54, 0x0d56,
+ 0x0d5f, 0x0d61,
+ 0x0d7a, 0x0d7f,
+ 0x0d85, 0x0d96,
+ 0x0d9a, 0x0db1,
+ 0x0db3, 0x0dbb,
+ 0x0dbd, 0x0dbd,
+ 0x0dc0, 0x0dc6,
+ 0x0e01, 0x0e30,
+ 0x0e32, 0x0e33,
+ 0x0e40, 0x0e46,
+ 0x0e81, 0x0e82,
+ 0x0e84, 0x0e84,
+ 0x0e86, 0x0e8a,
+ 0x0e8c, 0x0ea3,
+ 0x0ea5, 0x0ea5,
+ 0x0ea7, 0x0eb0,
+ 0x0eb2, 0x0eb3,
+ 0x0ebd, 0x0ebd,
+ 0x0ec0, 0x0ec4,
+ 0x0ec6, 0x0ec6,
+ 0x0edc, 0x0edf,
+ 0x0f00, 0x0f00,
+ 0x0f40, 0x0f47,
+ 0x0f49, 0x0f6c,
+ 0x0f88, 0x0f8c,
+ 0x1000, 0x102a,
+ 0x103f, 0x103f,
+ 0x1050, 0x1055,
+ 0x105a, 0x105d,
+ 0x1061, 0x1061,
+ 0x1065, 0x1066,
+ 0x106e, 0x1070,
+ 0x1075, 0x1081,
+ 0x108e, 0x108e,
+ 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,
+ 0x16f1, 0x16f8,
+ 0x1700, 0x1711,
+ 0x171f, 0x1731,
+ 0x1740, 0x1751,
+ 0x1760, 0x176c,
+ 0x176e, 0x1770,
+ 0x1780, 0x17b3,
+ 0x17d7, 0x17d7,
+ 0x17dc, 0x17dc,
+ 0x1820, 0x1878,
+ 0x1880, 0x1884,
+ 0x1887, 0x18a8,
+ 0x18aa, 0x18aa,
+ 0x18b0, 0x18f5,
+ 0x1900, 0x191e,
+ 0x1950, 0x196d,
+ 0x1970, 0x1974,
+ 0x1980, 0x19ab,
+ 0x19b0, 0x19c9,
+ 0x1a00, 0x1a16,
+ 0x1a20, 0x1a54,
+ 0x1aa7, 0x1aa7,
+ 0x1b05, 0x1b33,
+ 0x1b45, 0x1b4c,
+ 0x1b83, 0x1ba0,
+ 0x1bae, 0x1baf,
+ 0x1bba, 0x1be5,
+ 0x1c00, 0x1c23,
+ 0x1c4d, 0x1c4f,
+ 0x1c5a, 0x1c7d,
+ 0x1c80, 0x1c8a,
+ 0x1c90, 0x1cba,
+ 0x1cbd, 0x1cbf,
+ 0x1ce9, 0x1cec,
+ 0x1cee, 0x1cf3,
+ 0x1cf5, 0x1cf6,
+ 0x1cfa, 0x1cfa,
+ 0x1d00, 0x1dbf,
+ 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,
+ 0x2183, 0x2184,
+ 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,
+ 0x2e2f, 0x2e2f,
+ 0x3005, 0x3006,
+ 0x3031, 0x3035,
+ 0x303b, 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,
+ 0xa67f, 0xa69d,
+ 0xa6a0, 0xa6e5,
+ 0xa717, 0xa71f,
+ 0xa722, 0xa788,
+ 0xa78b, 0xa7dc,
+ 0xa7f1, 0xa801,
+ 0xa803, 0xa805,
+ 0xa807, 0xa80a,
+ 0xa80c, 0xa822,
+ 0xa840, 0xa873,
+ 0xa882, 0xa8b3,
+ 0xa8f2, 0xa8f7,
+ 0xa8fb, 0xa8fb,
+ 0xa8fd, 0xa8fe,
+ 0xa90a, 0xa925,
+ 0xa930, 0xa946,
+ 0xa960, 0xa97c,
+ 0xa984, 0xa9b2,
+ 0xa9cf, 0xa9cf,
+ 0xa9e0, 0xa9e4,
+ 0xa9e6, 0xa9ef,
+ 0xa9fa, 0xa9fe,
+ 0xaa00, 0xaa28,
+ 0xaa40, 0xaa42,
+ 0xaa44, 0xaa4b,
+ 0xaa60, 0xaa76,
+ 0xaa7a, 0xaa7a,
+ 0xaa7e, 0xaaaf,
+ 0xaab1, 0xaab1,
+ 0xaab5, 0xaab6,
+ 0xaab9, 0xaabd,
+ 0xaac0, 0xaac0,
+ 0xaac2, 0xaac2,
+ 0xaadb, 0xaadd,
+ 0xaae0, 0xaaea,
+ 0xaaf2, 0xaaf4,
+ 0xab01, 0xab06,
+ 0xab09, 0xab0e,
+ 0xab11, 0xab16,
+ 0xab20, 0xab26,
+ 0xab28, 0xab2e,
+ 0xab30, 0xab5a,
+ 0xab5c, 0xab69,
+ 0xab70, 0xabe2,
+ 0xac00, 0xd7a3,
+ 0xd7b0, 0xd7c6,
+ 0xd7cb, 0xd7fb,
+ 0xf900, 0xfa6d,
+ 0xfa70, 0xfad9,
+ 0xfb00, 0xfb06,
+ 0xfb13, 0xfb17,
+ 0xfb1d, 0xfb1d,
+ 0xfb1f, 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,
+ 0x10280, 0x1029c,
+ 0x102a0, 0x102d0,
+ 0x10300, 0x1031f,
+ 0x1032d, 0x10340,
+ 0x10342, 0x10349,
+ 0x10350, 0x10375,
+ 0x10380, 0x1039d,
+ 0x103a0, 0x103c3,
+ 0x103c8, 0x103cf,
+ 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,
+ 0x105c0, 0x105f3,
+ 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,
+ 0x10940, 0x10959,
+ 0x10980, 0x109b7,
+ 0x109be, 0x109bf,
+ 0x10a00, 0x10a00,
+ 0x10a10, 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, 0x10d23,
+ 0x10d4a, 0x10d65,
+ 0x10d6f, 0x10d85,
+ 0x10e80, 0x10ea9,
+ 0x10eb0, 0x10eb1,
+ 0x10ec2, 0x10ec7,
+ 0x10f00, 0x10f1c,
+ 0x10f27, 0x10f27,
+ 0x10f30, 0x10f45,
+ 0x10f70, 0x10f81,
+ 0x10fb0, 0x10fc4,
+ 0x10fe0, 0x10ff6,
+ 0x11003, 0x11037,
+ 0x11071, 0x11072,
+ 0x11075, 0x11075,
+ 0x11083, 0x110af,
+ 0x110d0, 0x110e8,
+ 0x11103, 0x11126,
+ 0x11144, 0x11144,
+ 0x11147, 0x11147,
+ 0x11150, 0x11172,
+ 0x11176, 0x11176,
+ 0x11183, 0x111b2,
+ 0x111c1, 0x111c4,
+ 0x111da, 0x111da,
+ 0x111dc, 0x111dc,
+ 0x11200, 0x11211,
+ 0x11213, 0x1122b,
+ 0x1123f, 0x11240,
+ 0x11280, 0x11286,
+ 0x11288, 0x11288,
+ 0x1128a, 0x1128d,
+ 0x1128f, 0x1129d,
+ 0x1129f, 0x112a8,
+ 0x112b0, 0x112de,
+ 0x11305, 0x1130c,
+ 0x1130f, 0x11310,
+ 0x11313, 0x11328,
+ 0x1132a, 0x11330,
+ 0x11332, 0x11333,
+ 0x11335, 0x11339,
+ 0x1133d, 0x1133d,
+ 0x11350, 0x11350,
+ 0x1135d, 0x11361,
+ 0x11380, 0x11389,
+ 0x1138b, 0x1138b,
+ 0x1138e, 0x1138e,
+ 0x11390, 0x113b5,
+ 0x113b7, 0x113b7,
+ 0x113d1, 0x113d1,
+ 0x113d3, 0x113d3,
+ 0x11400, 0x11434,
+ 0x11447, 0x1144a,
+ 0x1145f, 0x11461,
+ 0x11480, 0x114af,
+ 0x114c4, 0x114c5,
+ 0x114c7, 0x114c7,
+ 0x11580, 0x115ae,
+ 0x115d8, 0x115db,
+ 0x11600, 0x1162f,
+ 0x11644, 0x11644,
+ 0x11680, 0x116aa,
+ 0x116b8, 0x116b8,
+ 0x11700, 0x1171a,
+ 0x11740, 0x11746,
+ 0x11800, 0x1182b,
+ 0x118a0, 0x118df,
+ 0x118ff, 0x11906,
+ 0x11909, 0x11909,
+ 0x1190c, 0x11913,
+ 0x11915, 0x11916,
+ 0x11918, 0x1192f,
+ 0x1193f, 0x1193f,
+ 0x11941, 0x11941,
+ 0x119a0, 0x119a7,
+ 0x119aa, 0x119d0,
+ 0x119e1, 0x119e1,
+ 0x119e3, 0x119e3,
+ 0x11a00, 0x11a00,
+ 0x11a0b, 0x11a32,
+ 0x11a3a, 0x11a3a,
+ 0x11a50, 0x11a50,
+ 0x11a5c, 0x11a89,
+ 0x11a9d, 0x11a9d,
+ 0x11ab0, 0x11af8,
+ 0x11bc0, 0x11be0,
+ 0x11c00, 0x11c08,
+ 0x11c0a, 0x11c2e,
+ 0x11c40, 0x11c40,
+ 0x11c72, 0x11c8f,
+ 0x11d00, 0x11d06,
+ 0x11d08, 0x11d09,
+ 0x11d0b, 0x11d30,
+ 0x11d46, 0x11d46,
+ 0x11d60, 0x11d65,
+ 0x11d67, 0x11d68,
+ 0x11d6a, 0x11d89,
+ 0x11d98, 0x11d98,
+ 0x11db0, 0x11ddb,
+ 0x11ee0, 0x11ef2,
+ 0x11f02, 0x11f02,
+ 0x11f04, 0x11f10,
+ 0x11f12, 0x11f33,
+ 0x11fb0, 0x11fb0,
+ 0x12000, 0x12399,
+ 0x12480, 0x12543,
+ 0x12f90, 0x12ff0,
+ 0x13000, 0x1342f,
+ 0x13441, 0x13446,
+ 0x13460, 0x143fa,
+ 0x14400, 0x14646,
+ 0x16100, 0x1611d,
+ 0x16800, 0x16a38,
+ 0x16a40, 0x16a5e,
+ 0x16a70, 0x16abe,
+ 0x16ad0, 0x16aed,
+ 0x16b00, 0x16b2f,
+ 0x16b40, 0x16b43,
+ 0x16b63, 0x16b77,
+ 0x16b7d, 0x16b8f,
+ 0x16d40, 0x16d6c,
+ 0x16e40, 0x16e7f,
+ 0x16ea0, 0x16eb8,
+ 0x16ebb, 0x16ed3,
+ 0x16f00, 0x16f4a,
+ 0x16f50, 0x16f50,
+ 0x16f93, 0x16f9f,
+ 0x16fe0, 0x16fe1,
+ 0x16fe3, 0x16fe3,
+ 0x16ff2, 0x16ff3,
+ 0x17000, 0x18cd5,
+ 0x18cff, 0x18d1e,
+ 0x18d80, 0x18df2,
+ 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,
+ 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,
+ 0x1e030, 0x1e06d,
+ 0x1e100, 0x1e12c,
+ 0x1e137, 0x1e13d,
+ 0x1e14e, 0x1e14e,
+ 0x1e290, 0x1e2ad,
+ 0x1e2c0, 0x1e2eb,
+ 0x1e4d0, 0x1e4eb,
+ 0x1e5d0, 0x1e5ed,
+ 0x1e5f0, 0x1e5f0,
+ 0x1e6c0, 0x1e6de,
+ 0x1e6e0, 0x1e6e2,
+ 0x1e6e4, 0x1e6e5,
+ 0x1e6e7, 0x1e6ed,
+ 0x1e6f0, 0x1e6f4,
+ 0x1e6fe, 0x1e6ff,
+ 0x1e7e0, 0x1e7e6,
+ 0x1e7e8, 0x1e7eb,
+ 0x1e7ed, 0x1e7ee,
+ 0x1e7f0, 0x1e7fe,
+ 0x1e800, 0x1e8c4,
+ 0x1e900, 0x1e943,
+ 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,
+ 0x20000, 0x2a6df,
+ 0x2a700, 0x2b81d,
+ 0x2b820, 0x2cead,
+ 0x2ceb0, 0x2ebe0,
+ 0x2ebf0, 0x2ee5d,
+ 0x2f800, 0x2fa1d,
+ 0x30000, 0x3134a,
+ 0x31350, 0x33479,
+}; /* CR_L */
+
+/* 'LC': General Category */
+static const OnigCodePoint CR_LC[] = {
+ 144,
+ 0x0041, 0x005a,
+ 0x0061, 0x007a,
+ 0x00b5, 0x00b5,
+ 0x00c0, 0x00d6,
+ 0x00d8, 0x00f6,
+ 0x00f8, 0x01ba,
+ 0x01bc, 0x01bf,
+ 0x01c4, 0x0293,
+ 0x0296, 0x02af,
+ 0x0370, 0x0373,
+ 0x0376, 0x0377,
+ 0x037b, 0x037d,
+ 0x037f, 0x037f,
+ 0x0386, 0x0386,
+ 0x0388, 0x038a,
+ 0x038c, 0x038c,
+ 0x038e, 0x03a1,
+ 0x03a3, 0x03f5,
+ 0x03f7, 0x0481,
+ 0x048a, 0x052f,
+ 0x0531, 0x0556,
+ 0x0560, 0x0588,
+ 0x10a0, 0x10c5,
+ 0x10c7, 0x10c7,
+ 0x10cd, 0x10cd,
+ 0x10d0, 0x10fa,
+ 0x10fd, 0x10ff,
+ 0x13a0, 0x13f5,
+ 0x13f8, 0x13fd,
+ 0x1c80, 0x1c8a,
+ 0x1c90, 0x1cba,
+ 0x1cbd, 0x1cbf,
+ 0x1d00, 0x1d2b,
+ 0x1d6b, 0x1d77,
+ 0x1d79, 0x1d9a,
+ 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,
+ 0x2102, 0x2102,
+ 0x2107, 0x2107,
+ 0x210a, 0x2113,
+ 0x2115, 0x2115,
+ 0x2119, 0x211d,
+ 0x2124, 0x2124,
+ 0x2126, 0x2126,
+ 0x2128, 0x2128,
+ 0x212a, 0x212d,
+ 0x212f, 0x2134,
+ 0x2139, 0x2139,
+ 0x213c, 0x213f,
+ 0x2145, 0x2149,
+ 0x214e, 0x214e,
+ 0x2183, 0x2184,
+ 0x2c00, 0x2c7b,
+ 0x2c7e, 0x2ce4,
+ 0x2ceb, 0x2cee,
+ 0x2cf2, 0x2cf3,
+ 0x2d00, 0x2d25,
+ 0x2d27, 0x2d27,
+ 0x2d2d, 0x2d2d,
+ 0xa640, 0xa66d,
+ 0xa680, 0xa69b,
+ 0xa722, 0xa76f,
+ 0xa771, 0xa787,
+ 0xa78b, 0xa78e,
+ 0xa790, 0xa7dc,
+ 0xa7f5, 0xa7f6,
+ 0xa7fa, 0xa7fa,
+ 0xab30, 0xab5a,
+ 0xab60, 0xab68,
+ 0xab70, 0xabbf,
+ 0xfb00, 0xfb06,
+ 0xfb13, 0xfb17,
+ 0xff21, 0xff3a,
+ 0xff41, 0xff5a,
+ 0x10400, 0x1044f,
+ 0x104b0, 0x104d3,
+ 0x104d8, 0x104fb,
+ 0x10570, 0x1057a,
+ 0x1057c, 0x1058a,
+ 0x1058c, 0x10592,
+ 0x10594, 0x10595,
+ 0x10597, 0x105a1,
+ 0x105a3, 0x105b1,
+ 0x105b3, 0x105b9,
+ 0x105bb, 0x105bc,
+ 0x10c80, 0x10cb2,
+ 0x10cc0, 0x10cf2,
+ 0x10d50, 0x10d65,
+ 0x10d70, 0x10d85,
+ 0x118a0, 0x118df,
+ 0x16e40, 0x16e7f,
+ 0x16ea0, 0x16eb8,
+ 0x16ebb, 0x16ed3,
+ 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, 0x1df09,
+ 0x1df0b, 0x1df1e,
+ 0x1df25, 0x1df2a,
+ 0x1e900, 0x1e943,
+}; /* CR_LC */
+
+/* 'Ll': General Category */
+static const OnigCodePoint CR_Ll[] = {
+ 664,
+ 0x0061, 0x007a,
+ 0x00b5, 0x00b5,
+ 0x00df, 0x00f6,
+ 0x00f8, 0x00ff,
+ 0x0101, 0x0101,
+ 0x0103, 0x0103,
+ 0x0105, 0x0105,
+ 0x0107, 0x0107,
+ 0x0109, 0x0109,
+ 0x010b, 0x010b,
+ 0x010d, 0x010d,
+ 0x010f, 0x010f,
+ 0x0111, 0x0111,
+ 0x0113, 0x0113,
+ 0x0115, 0x0115,
+ 0x0117, 0x0117,
+ 0x0119, 0x0119,
+ 0x011b, 0x011b,
+ 0x011d, 0x011d,
+ 0x011f, 0x011f,
+ 0x0121, 0x0121,
+ 0x0123, 0x0123,
+ 0x0125, 0x0125,
+ 0x0127, 0x0127,
+ 0x0129, 0x0129,
+ 0x012b, 0x012b,
+ 0x012d, 0x012d,
+ 0x012f, 0x012f,
+ 0x0131, 0x0131,
+ 0x0133, 0x0133,
+ 0x0135, 0x0135,
+ 0x0137, 0x0138,
+ 0x013a, 0x013a,
+ 0x013c, 0x013c,
+ 0x013e, 0x013e,
+ 0x0140, 0x0140,
+ 0x0142, 0x0142,
+ 0x0144, 0x0144,
+ 0x0146, 0x0146,
+ 0x0148, 0x0149,
+ 0x014b, 0x014b,
+ 0x014d, 0x014d,
+ 0x014f, 0x014f,
+ 0x0151, 0x0151,
+ 0x0153, 0x0153,
+ 0x0155, 0x0155,
+ 0x0157, 0x0157,
+ 0x0159, 0x0159,
+ 0x015b, 0x015b,
+ 0x015d, 0x015d,
+ 0x015f, 0x015f,
+ 0x0161, 0x0161,
+ 0x0163, 0x0163,
+ 0x0165, 0x0165,
+ 0x0167, 0x0167,
+ 0x0169, 0x0169,
+ 0x016b, 0x016b,
+ 0x016d, 0x016d,
+ 0x016f, 0x016f,
+ 0x0171, 0x0171,
+ 0x0173, 0x0173,
+ 0x0175, 0x0175,
+ 0x0177, 0x0177,
+ 0x017a, 0x017a,
+ 0x017c, 0x017c,
+ 0x017e, 0x0180,
+ 0x0183, 0x0183,
+ 0x0185, 0x0185,
+ 0x0188, 0x0188,
+ 0x018c, 0x018d,
+ 0x0192, 0x0192,
+ 0x0195, 0x0195,
+ 0x0199, 0x019b,
+ 0x019e, 0x019e,
+ 0x01a1, 0x01a1,
+ 0x01a3, 0x01a3,
+ 0x01a5, 0x01a5,
+ 0x01a8, 0x01a8,
+ 0x01aa, 0x01ab,
+ 0x01ad, 0x01ad,
+ 0x01b0, 0x01b0,
+ 0x01b4, 0x01b4,
+ 0x01b6, 0x01b6,
+ 0x01b9, 0x01ba,
+ 0x01bd, 0x01bf,
+ 0x01c6, 0x01c6,
+ 0x01c9, 0x01c9,
+ 0x01cc, 0x01cc,
+ 0x01ce, 0x01ce,
+ 0x01d0, 0x01d0,
+ 0x01d2, 0x01d2,
+ 0x01d4, 0x01d4,
+ 0x01d6, 0x01d6,
+ 0x01d8, 0x01d8,
+ 0x01da, 0x01da,
+ 0x01dc, 0x01dd,
+ 0x01df, 0x01df,
+ 0x01e1, 0x01e1,
+ 0x01e3, 0x01e3,
+ 0x01e5, 0x01e5,
+ 0x01e7, 0x01e7,
+ 0x01e9, 0x01e9,
+ 0x01eb, 0x01eb,
+ 0x01ed, 0x01ed,
+ 0x01ef, 0x01f0,
+ 0x01f3, 0x01f3,
+ 0x01f5, 0x01f5,
+ 0x01f9, 0x01f9,
+ 0x01fb, 0x01fb,
+ 0x01fd, 0x01fd,
+ 0x01ff, 0x01ff,
+ 0x0201, 0x0201,
+ 0x0203, 0x0203,
+ 0x0205, 0x0205,
+ 0x0207, 0x0207,
+ 0x0209, 0x0209,
+ 0x020b, 0x020b,
+ 0x020d, 0x020d,
+ 0x020f, 0x020f,
+ 0x0211, 0x0211,
+ 0x0213, 0x0213,
+ 0x0215, 0x0215,
+ 0x0217, 0x0217,
+ 0x0219, 0x0219,
+ 0x021b, 0x021b,
+ 0x021d, 0x021d,
+ 0x021f, 0x021f,
+ 0x0221, 0x0221,
+ 0x0223, 0x0223,
+ 0x0225, 0x0225,
+ 0x0227, 0x0227,
+ 0x0229, 0x0229,
+ 0x022b, 0x022b,
+ 0x022d, 0x022d,
+ 0x022f, 0x022f,
+ 0x0231, 0x0231,
+ 0x0233, 0x0239,
+ 0x023c, 0x023c,
+ 0x023f, 0x0240,
+ 0x0242, 0x0242,
+ 0x0247, 0x0247,
+ 0x0249, 0x0249,
+ 0x024b, 0x024b,
+ 0x024d, 0x024d,
+ 0x024f, 0x0293,
+ 0x0296, 0x02af,
+ 0x0371, 0x0371,
+ 0x0373, 0x0373,
+ 0x0377, 0x0377,
+ 0x037b, 0x037d,
+ 0x0390, 0x0390,
+ 0x03ac, 0x03ce,
+ 0x03d0, 0x03d1,
+ 0x03d5, 0x03d7,
+ 0x03d9, 0x03d9,
+ 0x03db, 0x03db,
+ 0x03dd, 0x03dd,
+ 0x03df, 0x03df,
+ 0x03e1, 0x03e1,
+ 0x03e3, 0x03e3,
+ 0x03e5, 0x03e5,
+ 0x03e7, 0x03e7,
+ 0x03e9, 0x03e9,
+ 0x03eb, 0x03eb,
+ 0x03ed, 0x03ed,
+ 0x03ef, 0x03f3,
+ 0x03f5, 0x03f5,
+ 0x03f8, 0x03f8,
+ 0x03fb, 0x03fc,
+ 0x0430, 0x045f,
+ 0x0461, 0x0461,
+ 0x0463, 0x0463,
+ 0x0465, 0x0465,
+ 0x0467, 0x0467,
+ 0x0469, 0x0469,
+ 0x046b, 0x046b,
+ 0x046d, 0x046d,
+ 0x046f, 0x046f,
+ 0x0471, 0x0471,
+ 0x0473, 0x0473,
+ 0x0475, 0x0475,
+ 0x0477, 0x0477,
+ 0x0479, 0x0479,
+ 0x047b, 0x047b,
+ 0x047d, 0x047d,
+ 0x047f, 0x047f,
+ 0x0481, 0x0481,
+ 0x048b, 0x048b,
+ 0x048d, 0x048d,
+ 0x048f, 0x048f,
+ 0x0491, 0x0491,
+ 0x0493, 0x0493,
+ 0x0495, 0x0495,
+ 0x0497, 0x0497,
+ 0x0499, 0x0499,
+ 0x049b, 0x049b,
+ 0x049d, 0x049d,
+ 0x049f, 0x049f,
+ 0x04a1, 0x04a1,
+ 0x04a3, 0x04a3,
+ 0x04a5, 0x04a5,
+ 0x04a7, 0x04a7,
+ 0x04a9, 0x04a9,
+ 0x04ab, 0x04ab,
+ 0x04ad, 0x04ad,
+ 0x04af, 0x04af,
+ 0x04b1, 0x04b1,
+ 0x04b3, 0x04b3,
+ 0x04b5, 0x04b5,
+ 0x04b7, 0x04b7,
+ 0x04b9, 0x04b9,
+ 0x04bb, 0x04bb,
+ 0x04bd, 0x04bd,
+ 0x04bf, 0x04bf,
+ 0x04c2, 0x04c2,
+ 0x04c4, 0x04c4,
+ 0x04c6, 0x04c6,
+ 0x04c8, 0x04c8,
+ 0x04ca, 0x04ca,
+ 0x04cc, 0x04cc,
+ 0x04ce, 0x04cf,
+ 0x04d1, 0x04d1,
+ 0x04d3, 0x04d3,
+ 0x04d5, 0x04d5,
+ 0x04d7, 0x04d7,
+ 0x04d9, 0x04d9,
+ 0x04db, 0x04db,
+ 0x04dd, 0x04dd,
+ 0x04df, 0x04df,
+ 0x04e1, 0x04e1,
+ 0x04e3, 0x04e3,
+ 0x04e5, 0x04e5,
+ 0x04e7, 0x04e7,
+ 0x04e9, 0x04e9,
+ 0x04eb, 0x04eb,
+ 0x04ed, 0x04ed,
+ 0x04ef, 0x04ef,
+ 0x04f1, 0x04f1,
+ 0x04f3, 0x04f3,
+ 0x04f5, 0x04f5,
+ 0x04f7, 0x04f7,
+ 0x04f9, 0x04f9,
+ 0x04fb, 0x04fb,
+ 0x04fd, 0x04fd,
+ 0x04ff, 0x04ff,
+ 0x0501, 0x0501,
+ 0x0503, 0x0503,
+ 0x0505, 0x0505,
+ 0x0507, 0x0507,
+ 0x0509, 0x0509,
+ 0x050b, 0x050b,
+ 0x050d, 0x050d,
+ 0x050f, 0x050f,
+ 0x0511, 0x0511,
+ 0x0513, 0x0513,
+ 0x0515, 0x0515,
+ 0x0517, 0x0517,
+ 0x0519, 0x0519,
+ 0x051b, 0x051b,
+ 0x051d, 0x051d,
+ 0x051f, 0x051f,
+ 0x0521, 0x0521,
+ 0x0523, 0x0523,
+ 0x0525, 0x0525,
+ 0x0527, 0x0527,
+ 0x0529, 0x0529,
+ 0x052b, 0x052b,
+ 0x052d, 0x052d,
+ 0x052f, 0x052f,
+ 0x0560, 0x0588,
+ 0x10d0, 0x10fa,
+ 0x10fd, 0x10ff,
+ 0x13f8, 0x13fd,
+ 0x1c80, 0x1c88,
+ 0x1c8a, 0x1c8a,
+ 0x1d00, 0x1d2b,
+ 0x1d6b, 0x1d77,
+ 0x1d79, 0x1d9a,
+ 0x1e01, 0x1e01,
+ 0x1e03, 0x1e03,
+ 0x1e05, 0x1e05,
+ 0x1e07, 0x1e07,
+ 0x1e09, 0x1e09,
+ 0x1e0b, 0x1e0b,
+ 0x1e0d, 0x1e0d,
+ 0x1e0f, 0x1e0f,
+ 0x1e11, 0x1e11,
+ 0x1e13, 0x1e13,
+ 0x1e15, 0x1e15,
+ 0x1e17, 0x1e17,
+ 0x1e19, 0x1e19,
+ 0x1e1b, 0x1e1b,
+ 0x1e1d, 0x1e1d,
+ 0x1e1f, 0x1e1f,
+ 0x1e21, 0x1e21,
+ 0x1e23, 0x1e23,
+ 0x1e25, 0x1e25,
+ 0x1e27, 0x1e27,
+ 0x1e29, 0x1e29,
+ 0x1e2b, 0x1e2b,
+ 0x1e2d, 0x1e2d,
+ 0x1e2f, 0x1e2f,
+ 0x1e31, 0x1e31,
+ 0x1e33, 0x1e33,
+ 0x1e35, 0x1e35,
+ 0x1e37, 0x1e37,
+ 0x1e39, 0x1e39,
+ 0x1e3b, 0x1e3b,
+ 0x1e3d, 0x1e3d,
+ 0x1e3f, 0x1e3f,
+ 0x1e41, 0x1e41,
+ 0x1e43, 0x1e43,
+ 0x1e45, 0x1e45,
+ 0x1e47, 0x1e47,
+ 0x1e49, 0x1e49,
+ 0x1e4b, 0x1e4b,
+ 0x1e4d, 0x1e4d,
+ 0x1e4f, 0x1e4f,
+ 0x1e51, 0x1e51,
+ 0x1e53, 0x1e53,
+ 0x1e55, 0x1e55,
+ 0x1e57, 0x1e57,
+ 0x1e59, 0x1e59,
+ 0x1e5b, 0x1e5b,
+ 0x1e5d, 0x1e5d,
+ 0x1e5f, 0x1e5f,
+ 0x1e61, 0x1e61,
+ 0x1e63, 0x1e63,
+ 0x1e65, 0x1e65,
+ 0x1e67, 0x1e67,
+ 0x1e69, 0x1e69,
+ 0x1e6b, 0x1e6b,
+ 0x1e6d, 0x1e6d,
+ 0x1e6f, 0x1e6f,
+ 0x1e71, 0x1e71,
+ 0x1e73, 0x1e73,
+ 0x1e75, 0x1e75,
+ 0x1e77, 0x1e77,
+ 0x1e79, 0x1e79,
+ 0x1e7b, 0x1e7b,
+ 0x1e7d, 0x1e7d,
+ 0x1e7f, 0x1e7f,
+ 0x1e81, 0x1e81,
+ 0x1e83, 0x1e83,
+ 0x1e85, 0x1e85,
+ 0x1e87, 0x1e87,
+ 0x1e89, 0x1e89,
+ 0x1e8b, 0x1e8b,
+ 0x1e8d, 0x1e8d,
+ 0x1e8f, 0x1e8f,
+ 0x1e91, 0x1e91,
+ 0x1e93, 0x1e93,
+ 0x1e95, 0x1e9d,
+ 0x1e9f, 0x1e9f,
+ 0x1ea1, 0x1ea1,
+ 0x1ea3, 0x1ea3,
+ 0x1ea5, 0x1ea5,
+ 0x1ea7, 0x1ea7,
+ 0x1ea9, 0x1ea9,
+ 0x1eab, 0x1eab,
+ 0x1ead, 0x1ead,
+ 0x1eaf, 0x1eaf,
+ 0x1eb1, 0x1eb1,
+ 0x1eb3, 0x1eb3,
+ 0x1eb5, 0x1eb5,
+ 0x1eb7, 0x1eb7,
+ 0x1eb9, 0x1eb9,
+ 0x1ebb, 0x1ebb,
+ 0x1ebd, 0x1ebd,
+ 0x1ebf, 0x1ebf,
+ 0x1ec1, 0x1ec1,
+ 0x1ec3, 0x1ec3,
+ 0x1ec5, 0x1ec5,
+ 0x1ec7, 0x1ec7,
+ 0x1ec9, 0x1ec9,
+ 0x1ecb, 0x1ecb,
+ 0x1ecd, 0x1ecd,
+ 0x1ecf, 0x1ecf,
+ 0x1ed1, 0x1ed1,
+ 0x1ed3, 0x1ed3,
+ 0x1ed5, 0x1ed5,
+ 0x1ed7, 0x1ed7,
+ 0x1ed9, 0x1ed9,
+ 0x1edb, 0x1edb,
+ 0x1edd, 0x1edd,
+ 0x1edf, 0x1edf,
+ 0x1ee1, 0x1ee1,
+ 0x1ee3, 0x1ee3,
+ 0x1ee5, 0x1ee5,
+ 0x1ee7, 0x1ee7,
+ 0x1ee9, 0x1ee9,
+ 0x1eeb, 0x1eeb,
+ 0x1eed, 0x1eed,
+ 0x1eef, 0x1eef,
+ 0x1ef1, 0x1ef1,
+ 0x1ef3, 0x1ef3,
+ 0x1ef5, 0x1ef5,
+ 0x1ef7, 0x1ef7,
+ 0x1ef9, 0x1ef9,
+ 0x1efb, 0x1efb,
+ 0x1efd, 0x1efd,
+ 0x1eff, 0x1f07,
+ 0x1f10, 0x1f15,
+ 0x1f20, 0x1f27,
+ 0x1f30, 0x1f37,
+ 0x1f40, 0x1f45,
+ 0x1f50, 0x1f57,
+ 0x1f60, 0x1f67,
+ 0x1f70, 0x1f7d,
+ 0x1f80, 0x1f87,
+ 0x1f90, 0x1f97,
+ 0x1fa0, 0x1fa7,
+ 0x1fb0, 0x1fb4,
+ 0x1fb6, 0x1fb7,
+ 0x1fbe, 0x1fbe,
+ 0x1fc2, 0x1fc4,
+ 0x1fc6, 0x1fc7,
+ 0x1fd0, 0x1fd3,
+ 0x1fd6, 0x1fd7,
+ 0x1fe0, 0x1fe7,
+ 0x1ff2, 0x1ff4,
+ 0x1ff6, 0x1ff7,
+ 0x210a, 0x210a,
+ 0x210e, 0x210f,
+ 0x2113, 0x2113,
+ 0x212f, 0x212f,
+ 0x2134, 0x2134,
+ 0x2139, 0x2139,
+ 0x213c, 0x213d,
+ 0x2146, 0x2149,
+ 0x214e, 0x214e,
+ 0x2184, 0x2184,
+ 0x2c30, 0x2c5f,
+ 0x2c61, 0x2c61,
+ 0x2c65, 0x2c66,
+ 0x2c68, 0x2c68,
+ 0x2c6a, 0x2c6a,
+ 0x2c6c, 0x2c6c,
+ 0x2c71, 0x2c71,
+ 0x2c73, 0x2c74,
+ 0x2c76, 0x2c7b,
+ 0x2c81, 0x2c81,
+ 0x2c83, 0x2c83,
+ 0x2c85, 0x2c85,
+ 0x2c87, 0x2c87,
+ 0x2c89, 0x2c89,
+ 0x2c8b, 0x2c8b,
+ 0x2c8d, 0x2c8d,
+ 0x2c8f, 0x2c8f,
+ 0x2c91, 0x2c91,
+ 0x2c93, 0x2c93,
+ 0x2c95, 0x2c95,
+ 0x2c97, 0x2c97,
+ 0x2c99, 0x2c99,
+ 0x2c9b, 0x2c9b,
+ 0x2c9d, 0x2c9d,
+ 0x2c9f, 0x2c9f,
+ 0x2ca1, 0x2ca1,
+ 0x2ca3, 0x2ca3,
+ 0x2ca5, 0x2ca5,
+ 0x2ca7, 0x2ca7,
+ 0x2ca9, 0x2ca9,
+ 0x2cab, 0x2cab,
+ 0x2cad, 0x2cad,
+ 0x2caf, 0x2caf,
+ 0x2cb1, 0x2cb1,
+ 0x2cb3, 0x2cb3,
+ 0x2cb5, 0x2cb5,
+ 0x2cb7, 0x2cb7,
+ 0x2cb9, 0x2cb9,
+ 0x2cbb, 0x2cbb,
+ 0x2cbd, 0x2cbd,
+ 0x2cbf, 0x2cbf,
+ 0x2cc1, 0x2cc1,
+ 0x2cc3, 0x2cc3,
+ 0x2cc5, 0x2cc5,
+ 0x2cc7, 0x2cc7,
+ 0x2cc9, 0x2cc9,
+ 0x2ccb, 0x2ccb,
+ 0x2ccd, 0x2ccd,
+ 0x2ccf, 0x2ccf,
+ 0x2cd1, 0x2cd1,
+ 0x2cd3, 0x2cd3,
+ 0x2cd5, 0x2cd5,
+ 0x2cd7, 0x2cd7,
+ 0x2cd9, 0x2cd9,
+ 0x2cdb, 0x2cdb,
+ 0x2cdd, 0x2cdd,
+ 0x2cdf, 0x2cdf,
+ 0x2ce1, 0x2ce1,
+ 0x2ce3, 0x2ce4,
+ 0x2cec, 0x2cec,
+ 0x2cee, 0x2cee,
+ 0x2cf3, 0x2cf3,
+ 0x2d00, 0x2d25,
+ 0x2d27, 0x2d27,
+ 0x2d2d, 0x2d2d,
+ 0xa641, 0xa641,
+ 0xa643, 0xa643,
+ 0xa645, 0xa645,
+ 0xa647, 0xa647,
+ 0xa649, 0xa649,
+ 0xa64b, 0xa64b,
+ 0xa64d, 0xa64d,
+ 0xa64f, 0xa64f,
+ 0xa651, 0xa651,
+ 0xa653, 0xa653,
+ 0xa655, 0xa655,
+ 0xa657, 0xa657,
+ 0xa659, 0xa659,
+ 0xa65b, 0xa65b,
+ 0xa65d, 0xa65d,
+ 0xa65f, 0xa65f,
+ 0xa661, 0xa661,
+ 0xa663, 0xa663,
+ 0xa665, 0xa665,
+ 0xa667, 0xa667,
+ 0xa669, 0xa669,
+ 0xa66b, 0xa66b,
+ 0xa66d, 0xa66d,
+ 0xa681, 0xa681,
+ 0xa683, 0xa683,
+ 0xa685, 0xa685,
+ 0xa687, 0xa687,
+ 0xa689, 0xa689,
+ 0xa68b, 0xa68b,
+ 0xa68d, 0xa68d,
+ 0xa68f, 0xa68f,
+ 0xa691, 0xa691,
+ 0xa693, 0xa693,
+ 0xa695, 0xa695,
+ 0xa697, 0xa697,
+ 0xa699, 0xa699,
+ 0xa69b, 0xa69b,
+ 0xa723, 0xa723,
+ 0xa725, 0xa725,
+ 0xa727, 0xa727,
+ 0xa729, 0xa729,
+ 0xa72b, 0xa72b,
+ 0xa72d, 0xa72d,
+ 0xa72f, 0xa731,
+ 0xa733, 0xa733,
+ 0xa735, 0xa735,
+ 0xa737, 0xa737,
+ 0xa739, 0xa739,
+ 0xa73b, 0xa73b,
+ 0xa73d, 0xa73d,
+ 0xa73f, 0xa73f,
+ 0xa741, 0xa741,
+ 0xa743, 0xa743,
+ 0xa745, 0xa745,
+ 0xa747, 0xa747,
+ 0xa749, 0xa749,
+ 0xa74b, 0xa74b,
+ 0xa74d, 0xa74d,
+ 0xa74f, 0xa74f,
+ 0xa751, 0xa751,
+ 0xa753, 0xa753,
+ 0xa755, 0xa755,
+ 0xa757, 0xa757,
+ 0xa759, 0xa759,
+ 0xa75b, 0xa75b,
+ 0xa75d, 0xa75d,
+ 0xa75f, 0xa75f,
+ 0xa761, 0xa761,
+ 0xa763, 0xa763,
+ 0xa765, 0xa765,
+ 0xa767, 0xa767,
+ 0xa769, 0xa769,
+ 0xa76b, 0xa76b,
+ 0xa76d, 0xa76d,
+ 0xa76f, 0xa76f,
+ 0xa771, 0xa778,
+ 0xa77a, 0xa77a,
+ 0xa77c, 0xa77c,
+ 0xa77f, 0xa77f,
+ 0xa781, 0xa781,
+ 0xa783, 0xa783,
+ 0xa785, 0xa785,
+ 0xa787, 0xa787,
+ 0xa78c, 0xa78c,
+ 0xa78e, 0xa78e,
+ 0xa791, 0xa791,
+ 0xa793, 0xa795,
+ 0xa797, 0xa797,
+ 0xa799, 0xa799,
+ 0xa79b, 0xa79b,
+ 0xa79d, 0xa79d,
+ 0xa79f, 0xa79f,
+ 0xa7a1, 0xa7a1,
+ 0xa7a3, 0xa7a3,
+ 0xa7a5, 0xa7a5,
+ 0xa7a7, 0xa7a7,
+ 0xa7a9, 0xa7a9,
+ 0xa7af, 0xa7af,
+ 0xa7b5, 0xa7b5,
+ 0xa7b7, 0xa7b7,
+ 0xa7b9, 0xa7b9,
+ 0xa7bb, 0xa7bb,
+ 0xa7bd, 0xa7bd,
+ 0xa7bf, 0xa7bf,
+ 0xa7c1, 0xa7c1,
+ 0xa7c3, 0xa7c3,
+ 0xa7c8, 0xa7c8,
+ 0xa7ca, 0xa7ca,
+ 0xa7cd, 0xa7cd,
+ 0xa7cf, 0xa7cf,
+ 0xa7d1, 0xa7d1,
+ 0xa7d3, 0xa7d3,
+ 0xa7d5, 0xa7d5,
+ 0xa7d7, 0xa7d7,
+ 0xa7d9, 0xa7d9,
+ 0xa7db, 0xa7db,
+ 0xa7f6, 0xa7f6,
+ 0xa7fa, 0xa7fa,
+ 0xab30, 0xab5a,
+ 0xab60, 0xab68,
+ 0xab70, 0xabbf,
+ 0xfb00, 0xfb06,
+ 0xfb13, 0xfb17,
+ 0xff41, 0xff5a,
+ 0x10428, 0x1044f,
+ 0x104d8, 0x104fb,
+ 0x10597, 0x105a1,
+ 0x105a3, 0x105b1,
+ 0x105b3, 0x105b9,
+ 0x105bb, 0x105bc,
+ 0x10cc0, 0x10cf2,
+ 0x10d70, 0x10d85,
+ 0x118c0, 0x118df,
+ 0x16e60, 0x16e7f,
+ 0x16ebb, 0x16ed3,
+ 0x1d41a, 0x1d433,
+ 0x1d44e, 0x1d454,
+ 0x1d456, 0x1d467,
+ 0x1d482, 0x1d49b,
+ 0x1d4b6, 0x1d4b9,
+ 0x1d4bb, 0x1d4bb,
+ 0x1d4bd, 0x1d4c3,
+ 0x1d4c5, 0x1d4cf,
+ 0x1d4ea, 0x1d503,
+ 0x1d51e, 0x1d537,
+ 0x1d552, 0x1d56b,
+ 0x1d586, 0x1d59f,
+ 0x1d5ba, 0x1d5d3,
+ 0x1d5ee, 0x1d607,
+ 0x1d622, 0x1d63b,
+ 0x1d656, 0x1d66f,
+ 0x1d68a, 0x1d6a5,
+ 0x1d6c2, 0x1d6da,
+ 0x1d6dc, 0x1d6e1,
+ 0x1d6fc, 0x1d714,
+ 0x1d716, 0x1d71b,
+ 0x1d736, 0x1d74e,
+ 0x1d750, 0x1d755,
+ 0x1d770, 0x1d788,
+ 0x1d78a, 0x1d78f,
+ 0x1d7aa, 0x1d7c2,
+ 0x1d7c4, 0x1d7c9,
+ 0x1d7cb, 0x1d7cb,
+ 0x1df00, 0x1df09,
+ 0x1df0b, 0x1df1e,
+ 0x1df25, 0x1df2a,
+ 0x1e922, 0x1e943,
+}; /* CR_Ll */
+
+/* 'Lm': General Category */
+static const OnigCodePoint CR_Lm[] = {
+ 79,
+ 0x02b0, 0x02c1,
+ 0x02c6, 0x02d1,
+ 0x02e0, 0x02e4,
+ 0x02ec, 0x02ec,
+ 0x02ee, 0x02ee,
+ 0x0374, 0x0374,
+ 0x037a, 0x037a,
+ 0x0559, 0x0559,
+ 0x0640, 0x0640,
+ 0x06e5, 0x06e6,
+ 0x07f4, 0x07f5,
+ 0x07fa, 0x07fa,
+ 0x081a, 0x081a,
+ 0x0824, 0x0824,
+ 0x0828, 0x0828,
+ 0x08c9, 0x08c9,
+ 0x0971, 0x0971,
+ 0x0e46, 0x0e46,
+ 0x0ec6, 0x0ec6,
+ 0x10fc, 0x10fc,
+ 0x17d7, 0x17d7,
+ 0x1843, 0x1843,
+ 0x1aa7, 0x1aa7,
+ 0x1c78, 0x1c7d,
+ 0x1d2c, 0x1d6a,
+ 0x1d78, 0x1d78,
+ 0x1d9b, 0x1dbf,
+ 0x2071, 0x2071,
+ 0x207f, 0x207f,
+ 0x2090, 0x209c,
+ 0x2c7c, 0x2c7d,
+ 0x2d6f, 0x2d6f,
+ 0x2e2f, 0x2e2f,
+ 0x3005, 0x3005,
+ 0x3031, 0x3035,
+ 0x303b, 0x303b,
+ 0x309d, 0x309e,
+ 0x30fc, 0x30fe,
+ 0xa015, 0xa015,
+ 0xa4f8, 0xa4fd,
+ 0xa60c, 0xa60c,
+ 0xa67f, 0xa67f,
+ 0xa69c, 0xa69d,
+ 0xa717, 0xa71f,
+ 0xa770, 0xa770,
+ 0xa788, 0xa788,
+ 0xa7f1, 0xa7f4,
+ 0xa7f8, 0xa7f9,
+ 0xa9cf, 0xa9cf,
+ 0xa9e6, 0xa9e6,
+ 0xaa70, 0xaa70,
+ 0xaadd, 0xaadd,
+ 0xaaf3, 0xaaf4,
+ 0xab5c, 0xab5f,
+ 0xab69, 0xab69,
+ 0xff70, 0xff70,
+ 0xff9e, 0xff9f,
+ 0x10780, 0x10785,
+ 0x10787, 0x107b0,
+ 0x107b2, 0x107ba,
+ 0x10d4e, 0x10d4e,
+ 0x10d6f, 0x10d6f,
+ 0x10ec5, 0x10ec5,
+ 0x11dd9, 0x11dd9,
+ 0x16b40, 0x16b43,
+ 0x16d40, 0x16d42,
+ 0x16d6b, 0x16d6c,
+ 0x16f93, 0x16f9f,
+ 0x16fe0, 0x16fe1,
+ 0x16fe3, 0x16fe3,
+ 0x16ff2, 0x16ff3,
+ 0x1aff0, 0x1aff3,
+ 0x1aff5, 0x1affb,
+ 0x1affd, 0x1affe,
+ 0x1e030, 0x1e06d,
+ 0x1e137, 0x1e13d,
+ 0x1e4eb, 0x1e4eb,
+ 0x1e6ff, 0x1e6ff,
+ 0x1e94b, 0x1e94b,
+}; /* CR_Lm */
+
+/* 'Lo': General Category */
+static const OnigCodePoint CR_Lo[] = {
+ 537,
+ 0x00aa, 0x00aa,
+ 0x00ba, 0x00ba,
+ 0x01bb, 0x01bb,
+ 0x01c0, 0x01c3,
+ 0x0294, 0x0295,
+ 0x05d0, 0x05ea,
+ 0x05ef, 0x05f2,
+ 0x0620, 0x063f,
+ 0x0641, 0x064a,
+ 0x066e, 0x066f,
+ 0x0671, 0x06d3,
+ 0x06d5, 0x06d5,
+ 0x06ee, 0x06ef,
+ 0x06fa, 0x06fc,
+ 0x06ff, 0x06ff,
+ 0x0710, 0x0710,
+ 0x0712, 0x072f,
+ 0x074d, 0x07a5,
+ 0x07b1, 0x07b1,
+ 0x07ca, 0x07ea,
+ 0x0800, 0x0815,
+ 0x0840, 0x0858,
+ 0x0860, 0x086a,
+ 0x0870, 0x0887,
+ 0x0889, 0x088f,
+ 0x08a0, 0x08c8,
+ 0x0904, 0x0939,
+ 0x093d, 0x093d,
+ 0x0950, 0x0950,
+ 0x0958, 0x0961,
+ 0x0972, 0x0980,
+ 0x0985, 0x098c,
+ 0x098f, 0x0990,
+ 0x0993, 0x09a8,
+ 0x09aa, 0x09b0,
+ 0x09b2, 0x09b2,
+ 0x09b6, 0x09b9,
+ 0x09bd, 0x09bd,
+ 0x09ce, 0x09ce,
+ 0x09dc, 0x09dd,
+ 0x09df, 0x09e1,
+ 0x09f0, 0x09f1,
+ 0x09fc, 0x09fc,
+ 0x0a05, 0x0a0a,
+ 0x0a0f, 0x0a10,
+ 0x0a13, 0x0a28,
+ 0x0a2a, 0x0a30,
+ 0x0a32, 0x0a33,
+ 0x0a35, 0x0a36,
+ 0x0a38, 0x0a39,
+ 0x0a59, 0x0a5c,
+ 0x0a5e, 0x0a5e,
+ 0x0a72, 0x0a74,
+ 0x0a85, 0x0a8d,
+ 0x0a8f, 0x0a91,
+ 0x0a93, 0x0aa8,
+ 0x0aaa, 0x0ab0,
+ 0x0ab2, 0x0ab3,
+ 0x0ab5, 0x0ab9,
+ 0x0abd, 0x0abd,
+ 0x0ad0, 0x0ad0,
+ 0x0ae0, 0x0ae1,
+ 0x0af9, 0x0af9,
+ 0x0b05, 0x0b0c,
+ 0x0b0f, 0x0b10,
+ 0x0b13, 0x0b28,
+ 0x0b2a, 0x0b30,
+ 0x0b32, 0x0b33,
+ 0x0b35, 0x0b39,
+ 0x0b3d, 0x0b3d,
+ 0x0b5c, 0x0b5d,
+ 0x0b5f, 0x0b61,
+ 0x0b71, 0x0b71,
+ 0x0b83, 0x0b83,
+ 0x0b85, 0x0b8a,
+ 0x0b8e, 0x0b90,
+ 0x0b92, 0x0b95,
+ 0x0b99, 0x0b9a,
+ 0x0b9c, 0x0b9c,
+ 0x0b9e, 0x0b9f,
+ 0x0ba3, 0x0ba4,
+ 0x0ba8, 0x0baa,
+ 0x0bae, 0x0bb9,
+ 0x0bd0, 0x0bd0,
+ 0x0c05, 0x0c0c,
+ 0x0c0e, 0x0c10,
+ 0x0c12, 0x0c28,
+ 0x0c2a, 0x0c39,
+ 0x0c3d, 0x0c3d,
+ 0x0c58, 0x0c5a,
+ 0x0c5c, 0x0c5d,
+ 0x0c60, 0x0c61,
+ 0x0c80, 0x0c80,
+ 0x0c85, 0x0c8c,
+ 0x0c8e, 0x0c90,
+ 0x0c92, 0x0ca8,
+ 0x0caa, 0x0cb3,
+ 0x0cb5, 0x0cb9,
+ 0x0cbd, 0x0cbd,
+ 0x0cdc, 0x0cde,
+ 0x0ce0, 0x0ce1,
+ 0x0cf1, 0x0cf2,
+ 0x0d04, 0x0d0c,
+ 0x0d0e, 0x0d10,
+ 0x0d12, 0x0d3a,
+ 0x0d3d, 0x0d3d,
+ 0x0d4e, 0x0d4e,
+ 0x0d54, 0x0d56,
+ 0x0d5f, 0x0d61,
+ 0x0d7a, 0x0d7f,
+ 0x0d85, 0x0d96,
+ 0x0d9a, 0x0db1,
+ 0x0db3, 0x0dbb,
+ 0x0dbd, 0x0dbd,
+ 0x0dc0, 0x0dc6,
+ 0x0e01, 0x0e30,
+ 0x0e32, 0x0e33,
+ 0x0e40, 0x0e45,
+ 0x0e81, 0x0e82,
+ 0x0e84, 0x0e84,
+ 0x0e86, 0x0e8a,
+ 0x0e8c, 0x0ea3,
+ 0x0ea5, 0x0ea5,
+ 0x0ea7, 0x0eb0,
+ 0x0eb2, 0x0eb3,
+ 0x0ebd, 0x0ebd,
+ 0x0ec0, 0x0ec4,
+ 0x0edc, 0x0edf,
+ 0x0f00, 0x0f00,
+ 0x0f40, 0x0f47,
+ 0x0f49, 0x0f6c,
+ 0x0f88, 0x0f8c,
+ 0x1000, 0x102a,
+ 0x103f, 0x103f,
+ 0x1050, 0x1055,
+ 0x105a, 0x105d,
+ 0x1061, 0x1061,
+ 0x1065, 0x1066,
+ 0x106e, 0x1070,
+ 0x1075, 0x1081,
+ 0x108e, 0x108e,
+ 0x1100, 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,
+ 0x1401, 0x166c,
+ 0x166f, 0x167f,
+ 0x1681, 0x169a,
+ 0x16a0, 0x16ea,
+ 0x16f1, 0x16f8,
+ 0x1700, 0x1711,
+ 0x171f, 0x1731,
+ 0x1740, 0x1751,
+ 0x1760, 0x176c,
+ 0x176e, 0x1770,
+ 0x1780, 0x17b3,
+ 0x17dc, 0x17dc,
+ 0x1820, 0x1842,
+ 0x1844, 0x1878,
+ 0x1880, 0x1884,
+ 0x1887, 0x18a8,
+ 0x18aa, 0x18aa,
+ 0x18b0, 0x18f5,
+ 0x1900, 0x191e,
+ 0x1950, 0x196d,
+ 0x1970, 0x1974,
+ 0x1980, 0x19ab,
+ 0x19b0, 0x19c9,
+ 0x1a00, 0x1a16,
+ 0x1a20, 0x1a54,
+ 0x1b05, 0x1b33,
+ 0x1b45, 0x1b4c,
+ 0x1b83, 0x1ba0,
+ 0x1bae, 0x1baf,
+ 0x1bba, 0x1be5,
+ 0x1c00, 0x1c23,
+ 0x1c4d, 0x1c4f,
+ 0x1c5a, 0x1c77,
+ 0x1ce9, 0x1cec,
+ 0x1cee, 0x1cf3,
+ 0x1cf5, 0x1cf6,
+ 0x1cfa, 0x1cfa,
+ 0x2135, 0x2138,
+ 0x2d30, 0x2d67,
+ 0x2d80, 0x2d96,
+ 0x2da0, 0x2da6,
+ 0x2da8, 0x2dae,
+ 0x2db0, 0x2db6,
+ 0x2db8, 0x2dbe,
+ 0x2dc0, 0x2dc6,
+ 0x2dc8, 0x2dce,
+ 0x2dd0, 0x2dd6,
+ 0x2dd8, 0x2dde,
+ 0x3006, 0x3006,
+ 0x303c, 0x303c,
+ 0x3041, 0x3096,
+ 0x309f, 0x309f,
+ 0x30a1, 0x30fa,
+ 0x30ff, 0x30ff,
+ 0x3105, 0x312f,
+ 0x3131, 0x318e,
+ 0x31a0, 0x31bf,
+ 0x31f0, 0x31ff,
+ 0x3400, 0x4dbf,
+ 0x4e00, 0xa014,
+ 0xa016, 0xa48c,
+ 0xa4d0, 0xa4f7,
+ 0xa500, 0xa60b,
+ 0xa610, 0xa61f,
+ 0xa62a, 0xa62b,
+ 0xa66e, 0xa66e,
+ 0xa6a0, 0xa6e5,
+ 0xa78f, 0xa78f,
+ 0xa7f7, 0xa7f7,
+ 0xa7fb, 0xa801,
+ 0xa803, 0xa805,
+ 0xa807, 0xa80a,
+ 0xa80c, 0xa822,
+ 0xa840, 0xa873,
+ 0xa882, 0xa8b3,
+ 0xa8f2, 0xa8f7,
+ 0xa8fb, 0xa8fb,
+ 0xa8fd, 0xa8fe,
+ 0xa90a, 0xa925,
+ 0xa930, 0xa946,
+ 0xa960, 0xa97c,
+ 0xa984, 0xa9b2,
+ 0xa9e0, 0xa9e4,
+ 0xa9e7, 0xa9ef,
+ 0xa9fa, 0xa9fe,
+ 0xaa00, 0xaa28,
+ 0xaa40, 0xaa42,
+ 0xaa44, 0xaa4b,
+ 0xaa60, 0xaa6f,
+ 0xaa71, 0xaa76,
+ 0xaa7a, 0xaa7a,
+ 0xaa7e, 0xaaaf,
+ 0xaab1, 0xaab1,
+ 0xaab5, 0xaab6,
+ 0xaab9, 0xaabd,
+ 0xaac0, 0xaac0,
+ 0xaac2, 0xaac2,
+ 0xaadb, 0xaadc,
+ 0xaae0, 0xaaea,
+ 0xaaf2, 0xaaf2,
+ 0xab01, 0xab06,
+ 0xab09, 0xab0e,
+ 0xab11, 0xab16,
+ 0xab20, 0xab26,
+ 0xab28, 0xab2e,
+ 0xabc0, 0xabe2,
+ 0xac00, 0xd7a3,
+ 0xd7b0, 0xd7c6,
+ 0xd7cb, 0xd7fb,
+ 0xf900, 0xfa6d,
+ 0xfa70, 0xfad9,
+ 0xfb1d, 0xfb1d,
+ 0xfb1f, 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,
+ 0xff66, 0xff6f,
+ 0xff71, 0xff9d,
+ 0xffa0, 0xffbe,
+ 0xffc2, 0xffc7,
+ 0xffca, 0xffcf,
+ 0xffd2, 0xffd7,
+ 0xffda, 0xffdc,
+ 0x10000, 0x1000b,
+ 0x1000d, 0x10026,
+ 0x10028, 0x1003a,
+ 0x1003c, 0x1003d,
+ 0x1003f, 0x1004d,
+ 0x10050, 0x1005d,
+ 0x10080, 0x100fa,
+ 0x10280, 0x1029c,
+ 0x102a0, 0x102d0,
+ 0x10300, 0x1031f,
+ 0x1032d, 0x10340,
+ 0x10342, 0x10349,
+ 0x10350, 0x10375,
+ 0x10380, 0x1039d,
+ 0x103a0, 0x103c3,
+ 0x103c8, 0x103cf,
+ 0x10450, 0x1049d,
+ 0x10500, 0x10527,
+ 0x10530, 0x10563,
+ 0x105c0, 0x105f3,
+ 0x10600, 0x10736,
+ 0x10740, 0x10755,
+ 0x10760, 0x10767,
+ 0x10800, 0x10805,
+ 0x10808, 0x10808,
+ 0x1080a, 0x10835,
+ 0x10837, 0x10838,
+ 0x1083c, 0x1083c,
+ 0x1083f, 0x10855,
+ 0x10860, 0x10876,
+ 0x10880, 0x1089e,
+ 0x108e0, 0x108f2,
+ 0x108f4, 0x108f5,
+ 0x10900, 0x10915,
+ 0x10920, 0x10939,
+ 0x10940, 0x10959,
+ 0x10980, 0x109b7,
+ 0x109be, 0x109bf,
+ 0x10a00, 0x10a00,
+ 0x10a10, 0x10a13,
+ 0x10a15, 0x10a17,
+ 0x10a19, 0x10a35,
+ 0x10a60, 0x10a7c,
+ 0x10a80, 0x10a9c,
+ 0x10ac0, 0x10ac7,
+ 0x10ac9, 0x10ae4,
+ 0x10b00, 0x10b35,
+ 0x10b40, 0x10b55,
+ 0x10b60, 0x10b72,
+ 0x10b80, 0x10b91,
+ 0x10c00, 0x10c48,
+ 0x10d00, 0x10d23,
+ 0x10d4a, 0x10d4d,
+ 0x10d4f, 0x10d4f,
+ 0x10e80, 0x10ea9,
+ 0x10eb0, 0x10eb1,
+ 0x10ec2, 0x10ec4,
+ 0x10ec6, 0x10ec7,
+ 0x10f00, 0x10f1c,
+ 0x10f27, 0x10f27,
+ 0x10f30, 0x10f45,
+ 0x10f70, 0x10f81,
+ 0x10fb0, 0x10fc4,
+ 0x10fe0, 0x10ff6,
+ 0x11003, 0x11037,
+ 0x11071, 0x11072,
+ 0x11075, 0x11075,
+ 0x11083, 0x110af,
+ 0x110d0, 0x110e8,
+ 0x11103, 0x11126,
+ 0x11144, 0x11144,
+ 0x11147, 0x11147,
+ 0x11150, 0x11172,
+ 0x11176, 0x11176,
+ 0x11183, 0x111b2,
+ 0x111c1, 0x111c4,
+ 0x111da, 0x111da,
+ 0x111dc, 0x111dc,
+ 0x11200, 0x11211,
+ 0x11213, 0x1122b,
+ 0x1123f, 0x11240,
+ 0x11280, 0x11286,
+ 0x11288, 0x11288,
+ 0x1128a, 0x1128d,
+ 0x1128f, 0x1129d,
+ 0x1129f, 0x112a8,
+ 0x112b0, 0x112de,
+ 0x11305, 0x1130c,
+ 0x1130f, 0x11310,
+ 0x11313, 0x11328,
+ 0x1132a, 0x11330,
+ 0x11332, 0x11333,
+ 0x11335, 0x11339,
+ 0x1133d, 0x1133d,
+ 0x11350, 0x11350,
+ 0x1135d, 0x11361,
+ 0x11380, 0x11389,
+ 0x1138b, 0x1138b,
+ 0x1138e, 0x1138e,
+ 0x11390, 0x113b5,
+ 0x113b7, 0x113b7,
+ 0x113d1, 0x113d1,
+ 0x113d3, 0x113d3,
+ 0x11400, 0x11434,
+ 0x11447, 0x1144a,
+ 0x1145f, 0x11461,
+ 0x11480, 0x114af,
+ 0x114c4, 0x114c5,
+ 0x114c7, 0x114c7,
+ 0x11580, 0x115ae,
+ 0x115d8, 0x115db,
+ 0x11600, 0x1162f,
+ 0x11644, 0x11644,
+ 0x11680, 0x116aa,
+ 0x116b8, 0x116b8,
+ 0x11700, 0x1171a,
+ 0x11740, 0x11746,
+ 0x11800, 0x1182b,
+ 0x118ff, 0x11906,
+ 0x11909, 0x11909,
+ 0x1190c, 0x11913,
+ 0x11915, 0x11916,
+ 0x11918, 0x1192f,
+ 0x1193f, 0x1193f,
+ 0x11941, 0x11941,
+ 0x119a0, 0x119a7,
+ 0x119aa, 0x119d0,
+ 0x119e1, 0x119e1,
+ 0x119e3, 0x119e3,
+ 0x11a00, 0x11a00,
+ 0x11a0b, 0x11a32,
+ 0x11a3a, 0x11a3a,
+ 0x11a50, 0x11a50,
+ 0x11a5c, 0x11a89,
+ 0x11a9d, 0x11a9d,
+ 0x11ab0, 0x11af8,
+ 0x11bc0, 0x11be0,
+ 0x11c00, 0x11c08,
+ 0x11c0a, 0x11c2e,
+ 0x11c40, 0x11c40,
+ 0x11c72, 0x11c8f,
+ 0x11d00, 0x11d06,
+ 0x11d08, 0x11d09,
+ 0x11d0b, 0x11d30,
+ 0x11d46, 0x11d46,
+ 0x11d60, 0x11d65,
+ 0x11d67, 0x11d68,
+ 0x11d6a, 0x11d89,
+ 0x11d98, 0x11d98,
+ 0x11db0, 0x11dd8,
+ 0x11dda, 0x11ddb,
+ 0x11ee0, 0x11ef2,
+ 0x11f02, 0x11f02,
+ 0x11f04, 0x11f10,
+ 0x11f12, 0x11f33,
+ 0x11fb0, 0x11fb0,
+ 0x12000, 0x12399,
+ 0x12480, 0x12543,
+ 0x12f90, 0x12ff0,
+ 0x13000, 0x1342f,
+ 0x13441, 0x13446,
+ 0x13460, 0x143fa,
+ 0x14400, 0x14646,
+ 0x16100, 0x1611d,
+ 0x16800, 0x16a38,
+ 0x16a40, 0x16a5e,
+ 0x16a70, 0x16abe,
+ 0x16ad0, 0x16aed,
+ 0x16b00, 0x16b2f,
+ 0x16b63, 0x16b77,
+ 0x16b7d, 0x16b8f,
+ 0x16d43, 0x16d6a,
+ 0x16f00, 0x16f4a,
+ 0x16f50, 0x16f50,
+ 0x17000, 0x18cd5,
+ 0x18cff, 0x18d1e,
+ 0x18d80, 0x18df2,
+ 0x1b000, 0x1b122,
+ 0x1b132, 0x1b132,
+ 0x1b150, 0x1b152,
+ 0x1b155, 0x1b155,
+ 0x1b164, 0x1b167,
+ 0x1b170, 0x1b2fb,
+ 0x1bc00, 0x1bc6a,
+ 0x1bc70, 0x1bc7c,
+ 0x1bc80, 0x1bc88,
+ 0x1bc90, 0x1bc99,
+ 0x1df0a, 0x1df0a,
+ 0x1e100, 0x1e12c,
+ 0x1e14e, 0x1e14e,
+ 0x1e290, 0x1e2ad,
+ 0x1e2c0, 0x1e2eb,
+ 0x1e4d0, 0x1e4ea,
+ 0x1e5d0, 0x1e5ed,
+ 0x1e5f0, 0x1e5f0,
+ 0x1e6c0, 0x1e6de,
+ 0x1e6e0, 0x1e6e2,
+ 0x1e6e4, 0x1e6e5,
+ 0x1e6e7, 0x1e6ed,
+ 0x1e6f0, 0x1e6f4,
+ 0x1e6fe, 0x1e6fe,
+ 0x1e7e0, 0x1e7e6,
+ 0x1e7e8, 0x1e7eb,
+ 0x1e7ed, 0x1e7ee,
+ 0x1e7f0, 0x1e7fe,
+ 0x1e800, 0x1e8c4,
+ 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,
+ 0x20000, 0x2a6df,
+ 0x2a700, 0x2b81d,
+ 0x2b820, 0x2cead,
+ 0x2ceb0, 0x2ebe0,
+ 0x2ebf0, 0x2ee5d,
+ 0x2f800, 0x2fa1d,
+ 0x30000, 0x3134a,
+ 0x31350, 0x33479,
+}; /* CR_Lo */
+
+/* 'Lt': General Category */
+static const OnigCodePoint CR_Lt[] = {
+ 10,
+ 0x01c5, 0x01c5,
+ 0x01c8, 0x01c8,
+ 0x01cb, 0x01cb,
+ 0x01f2, 0x01f2,
+ 0x1f88, 0x1f8f,
+ 0x1f98, 0x1f9f,
+ 0x1fa8, 0x1faf,
+ 0x1fbc, 0x1fbc,
+ 0x1fcc, 0x1fcc,
+ 0x1ffc, 0x1ffc,
+}; /* CR_Lt */
+
+/* 'Lu': General Category */
+static const OnigCodePoint CR_Lu[] = {
+ 655,
+ 0x0041, 0x005a,
+ 0x00c0, 0x00d6,
+ 0x00d8, 0x00de,
+ 0x0100, 0x0100,
+ 0x0102, 0x0102,
+ 0x0104, 0x0104,
+ 0x0106, 0x0106,
+ 0x0108, 0x0108,
+ 0x010a, 0x010a,
+ 0x010c, 0x010c,
+ 0x010e, 0x010e,
+ 0x0110, 0x0110,
+ 0x0112, 0x0112,
+ 0x0114, 0x0114,
+ 0x0116, 0x0116,
+ 0x0118, 0x0118,
+ 0x011a, 0x011a,
+ 0x011c, 0x011c,
+ 0x011e, 0x011e,
+ 0x0120, 0x0120,
+ 0x0122, 0x0122,
+ 0x0124, 0x0124,
+ 0x0126, 0x0126,
+ 0x0128, 0x0128,
+ 0x012a, 0x012a,
+ 0x012c, 0x012c,
+ 0x012e, 0x012e,
+ 0x0130, 0x0130,
+ 0x0132, 0x0132,
+ 0x0134, 0x0134,
+ 0x0136, 0x0136,
+ 0x0139, 0x0139,
+ 0x013b, 0x013b,
+ 0x013d, 0x013d,
+ 0x013f, 0x013f,
+ 0x0141, 0x0141,
+ 0x0143, 0x0143,
+ 0x0145, 0x0145,
+ 0x0147, 0x0147,
+ 0x014a, 0x014a,
+ 0x014c, 0x014c,
+ 0x014e, 0x014e,
+ 0x0150, 0x0150,
+ 0x0152, 0x0152,
+ 0x0154, 0x0154,
+ 0x0156, 0x0156,
+ 0x0158, 0x0158,
+ 0x015a, 0x015a,
+ 0x015c, 0x015c,
+ 0x015e, 0x015e,
+ 0x0160, 0x0160,
+ 0x0162, 0x0162,
+ 0x0164, 0x0164,
+ 0x0166, 0x0166,
+ 0x0168, 0x0168,
+ 0x016a, 0x016a,
+ 0x016c, 0x016c,
+ 0x016e, 0x016e,
+ 0x0170, 0x0170,
+ 0x0172, 0x0172,
+ 0x0174, 0x0174,
+ 0x0176, 0x0176,
+ 0x0178, 0x0179,
+ 0x017b, 0x017b,
+ 0x017d, 0x017d,
+ 0x0181, 0x0182,
+ 0x0184, 0x0184,
+ 0x0186, 0x0187,
+ 0x0189, 0x018b,
+ 0x018e, 0x0191,
+ 0x0193, 0x0194,
+ 0x0196, 0x0198,
+ 0x019c, 0x019d,
+ 0x019f, 0x01a0,
+ 0x01a2, 0x01a2,
+ 0x01a4, 0x01a4,
+ 0x01a6, 0x01a7,
+ 0x01a9, 0x01a9,
+ 0x01ac, 0x01ac,
+ 0x01ae, 0x01af,
+ 0x01b1, 0x01b3,
+ 0x01b5, 0x01b5,
+ 0x01b7, 0x01b8,
+ 0x01bc, 0x01bc,
+ 0x01c4, 0x01c4,
+ 0x01c7, 0x01c7,
+ 0x01ca, 0x01ca,
+ 0x01cd, 0x01cd,
+ 0x01cf, 0x01cf,
+ 0x01d1, 0x01d1,
+ 0x01d3, 0x01d3,
+ 0x01d5, 0x01d5,
+ 0x01d7, 0x01d7,
+ 0x01d9, 0x01d9,
+ 0x01db, 0x01db,
+ 0x01de, 0x01de,
+ 0x01e0, 0x01e0,
+ 0x01e2, 0x01e2,
+ 0x01e4, 0x01e4,
+ 0x01e6, 0x01e6,
+ 0x01e8, 0x01e8,
+ 0x01ea, 0x01ea,
+ 0x01ec, 0x01ec,
+ 0x01ee, 0x01ee,
+ 0x01f1, 0x01f1,
+ 0x01f4, 0x01f4,
+ 0x01f6, 0x01f8,
+ 0x01fa, 0x01fa,
+ 0x01fc, 0x01fc,
+ 0x01fe, 0x01fe,
+ 0x0200, 0x0200,
+ 0x0202, 0x0202,
+ 0x0204, 0x0204,
+ 0x0206, 0x0206,
+ 0x0208, 0x0208,
+ 0x020a, 0x020a,
+ 0x020c, 0x020c,
+ 0x020e, 0x020e,
+ 0x0210, 0x0210,
+ 0x0212, 0x0212,
+ 0x0214, 0x0214,
+ 0x0216, 0x0216,
+ 0x0218, 0x0218,
+ 0x021a, 0x021a,
+ 0x021c, 0x021c,
+ 0x021e, 0x021e,
+ 0x0220, 0x0220,
+ 0x0222, 0x0222,
+ 0x0224, 0x0224,
+ 0x0226, 0x0226,
+ 0x0228, 0x0228,
+ 0x022a, 0x022a,
+ 0x022c, 0x022c,
+ 0x022e, 0x022e,
+ 0x0230, 0x0230,
+ 0x0232, 0x0232,
+ 0x023a, 0x023b,
+ 0x023d, 0x023e,
+ 0x0241, 0x0241,
+ 0x0243, 0x0246,
+ 0x0248, 0x0248,
+ 0x024a, 0x024a,
+ 0x024c, 0x024c,
+ 0x024e, 0x024e,
+ 0x0370, 0x0370,
+ 0x0372, 0x0372,
+ 0x0376, 0x0376,
+ 0x037f, 0x037f,
+ 0x0386, 0x0386,
+ 0x0388, 0x038a,
+ 0x038c, 0x038c,
+ 0x038e, 0x038f,
+ 0x0391, 0x03a1,
+ 0x03a3, 0x03ab,
+ 0x03cf, 0x03cf,
+ 0x03d2, 0x03d4,
+ 0x03d8, 0x03d8,
+ 0x03da, 0x03da,
+ 0x03dc, 0x03dc,
+ 0x03de, 0x03de,
+ 0x03e0, 0x03e0,
+ 0x03e2, 0x03e2,
+ 0x03e4, 0x03e4,
+ 0x03e6, 0x03e6,
+ 0x03e8, 0x03e8,
+ 0x03ea, 0x03ea,
+ 0x03ec, 0x03ec,
+ 0x03ee, 0x03ee,
+ 0x03f4, 0x03f4,
+ 0x03f7, 0x03f7,
+ 0x03f9, 0x03fa,
+ 0x03fd, 0x042f,
+ 0x0460, 0x0460,
+ 0x0462, 0x0462,
+ 0x0464, 0x0464,
+ 0x0466, 0x0466,
+ 0x0468, 0x0468,
+ 0x046a, 0x046a,
+ 0x046c, 0x046c,
+ 0x046e, 0x046e,
+ 0x0470, 0x0470,
+ 0x0472, 0x0472,
+ 0x0474, 0x0474,
+ 0x0476, 0x0476,
+ 0x0478, 0x0478,
+ 0x047a, 0x047a,
+ 0x047c, 0x047c,
+ 0x047e, 0x047e,
+ 0x0480, 0x0480,
+ 0x048a, 0x048a,
+ 0x048c, 0x048c,
+ 0x048e, 0x048e,
+ 0x0490, 0x0490,
+ 0x0492, 0x0492,
+ 0x0494, 0x0494,
+ 0x0496, 0x0496,
+ 0x0498, 0x0498,
+ 0x049a, 0x049a,
+ 0x049c, 0x049c,
+ 0x049e, 0x049e,
+ 0x04a0, 0x04a0,
+ 0x04a2, 0x04a2,
+ 0x04a4, 0x04a4,
+ 0x04a6, 0x04a6,
+ 0x04a8, 0x04a8,
+ 0x04aa, 0x04aa,
+ 0x04ac, 0x04ac,
+ 0x04ae, 0x04ae,
+ 0x04b0, 0x04b0,
+ 0x04b2, 0x04b2,
+ 0x04b4, 0x04b4,
+ 0x04b6, 0x04b6,
+ 0x04b8, 0x04b8,
+ 0x04ba, 0x04ba,
+ 0x04bc, 0x04bc,
+ 0x04be, 0x04be,
+ 0x04c0, 0x04c1,
+ 0x04c3, 0x04c3,
+ 0x04c5, 0x04c5,
+ 0x04c7, 0x04c7,
+ 0x04c9, 0x04c9,
+ 0x04cb, 0x04cb,
+ 0x04cd, 0x04cd,
+ 0x04d0, 0x04d0,
+ 0x04d2, 0x04d2,
+ 0x04d4, 0x04d4,
+ 0x04d6, 0x04d6,
+ 0x04d8, 0x04d8,
+ 0x04da, 0x04da,
+ 0x04dc, 0x04dc,
+ 0x04de, 0x04de,
+ 0x04e0, 0x04e0,
+ 0x04e2, 0x04e2,
+ 0x04e4, 0x04e4,
+ 0x04e6, 0x04e6,
+ 0x04e8, 0x04e8,
+ 0x04ea, 0x04ea,
+ 0x04ec, 0x04ec,
+ 0x04ee, 0x04ee,
+ 0x04f0, 0x04f0,
+ 0x04f2, 0x04f2,
+ 0x04f4, 0x04f4,
+ 0x04f6, 0x04f6,
+ 0x04f8, 0x04f8,
+ 0x04fa, 0x04fa,
+ 0x04fc, 0x04fc,
+ 0x04fe, 0x04fe,
+ 0x0500, 0x0500,
+ 0x0502, 0x0502,
+ 0x0504, 0x0504,
+ 0x0506, 0x0506,
+ 0x0508, 0x0508,
+ 0x050a, 0x050a,
+ 0x050c, 0x050c,
+ 0x050e, 0x050e,
+ 0x0510, 0x0510,
+ 0x0512, 0x0512,
+ 0x0514, 0x0514,
+ 0x0516, 0x0516,
+ 0x0518, 0x0518,
+ 0x051a, 0x051a,
+ 0x051c, 0x051c,
+ 0x051e, 0x051e,
+ 0x0520, 0x0520,
+ 0x0522, 0x0522,
+ 0x0524, 0x0524,
+ 0x0526, 0x0526,
+ 0x0528, 0x0528,
+ 0x052a, 0x052a,
+ 0x052c, 0x052c,
+ 0x052e, 0x052e,
+ 0x0531, 0x0556,
+ 0x10a0, 0x10c5,
+ 0x10c7, 0x10c7,
+ 0x10cd, 0x10cd,
+ 0x13a0, 0x13f5,
+ 0x1c89, 0x1c89,
+ 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,
+ 0x1fb8, 0x1fbb,
+ 0x1fc8, 0x1fcb,
+ 0x1fd8, 0x1fdb,
+ 0x1fe8, 0x1fec,
+ 0x1ff8, 0x1ffb,
+ 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,
+ 0x2183, 0x2183,
+ 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,
+ 0xa7cb, 0xa7cc,
+ 0xa7ce, 0xa7ce,
+ 0xa7d0, 0xa7d0,
+ 0xa7d2, 0xa7d2,
+ 0xa7d4, 0xa7d4,
+ 0xa7d6, 0xa7d6,
+ 0xa7d8, 0xa7d8,
+ 0xa7da, 0xa7da,
+ 0xa7dc, 0xa7dc,
+ 0xa7f5, 0xa7f5,
+ 0xff21, 0xff3a,
+ 0x10400, 0x10427,
+ 0x104b0, 0x104d3,
+ 0x10570, 0x1057a,
+ 0x1057c, 0x1058a,
+ 0x1058c, 0x10592,
+ 0x10594, 0x10595,
+ 0x10c80, 0x10cb2,
+ 0x10d50, 0x10d65,
+ 0x118a0, 0x118bf,
+ 0x16e40, 0x16e5f,
+ 0x16ea0, 0x16eb8,
+ 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,
+}; /* CR_Lu */
+
+/* 'M': Major Category */
+static const OnigCodePoint CR_M[] = {
+ 327,
+ 0x0300, 0x036f,
+ 0x0483, 0x0489,
+ 0x0591, 0x05bd,
+ 0x05bf, 0x05bf,
+ 0x05c1, 0x05c2,
+ 0x05c4, 0x05c5,
+ 0x05c7, 0x05c7,
+ 0x0610, 0x061a,
+ 0x064b, 0x065f,
+ 0x0670, 0x0670,
+ 0x06d6, 0x06dc,
+ 0x06df, 0x06e4,
+ 0x06e7, 0x06e8,
+ 0x06ea, 0x06ed,
+ 0x0711, 0x0711,
+ 0x0730, 0x074a,
+ 0x07a6, 0x07b0,
+ 0x07eb, 0x07f3,
+ 0x07fd, 0x07fd,
+ 0x0816, 0x0819,
+ 0x081b, 0x0823,
+ 0x0825, 0x0827,
+ 0x0829, 0x082d,
+ 0x0859, 0x085b,
+ 0x0897, 0x089f,
+ 0x08ca, 0x08e1,
+ 0x08e3, 0x0903,
+ 0x093a, 0x093c,
+ 0x093e, 0x094f,
+ 0x0951, 0x0957,
+ 0x0962, 0x0963,
+ 0x0981, 0x0983,
+ 0x09bc, 0x09bc,
+ 0x09be, 0x09c4,
+ 0x09c7, 0x09c8,
+ 0x09cb, 0x09cd,
+ 0x09d7, 0x09d7,
+ 0x09e2, 0x09e3,
+ 0x09fe, 0x09fe,
+ 0x0a01, 0x0a03,
+ 0x0a3c, 0x0a3c,
+ 0x0a3e, 0x0a42,
+ 0x0a47, 0x0a48,
+ 0x0a4b, 0x0a4d,
+ 0x0a51, 0x0a51,
+ 0x0a70, 0x0a71,
+ 0x0a75, 0x0a75,
+ 0x0a81, 0x0a83,
+ 0x0abc, 0x0abc,
+ 0x0abe, 0x0ac5,
+ 0x0ac7, 0x0ac9,
+ 0x0acb, 0x0acd,
+ 0x0ae2, 0x0ae3,
+ 0x0afa, 0x0aff,
+ 0x0b01, 0x0b03,
+ 0x0b3c, 0x0b3c,
+ 0x0b3e, 0x0b44,
+ 0x0b47, 0x0b48,
+ 0x0b4b, 0x0b4d,
+ 0x0b55, 0x0b57,
+ 0x0b62, 0x0b63,
+ 0x0b82, 0x0b82,
+ 0x0bbe, 0x0bc2,
+ 0x0bc6, 0x0bc8,
+ 0x0bca, 0x0bcd,
+ 0x0bd7, 0x0bd7,
+ 0x0c00, 0x0c04,
+ 0x0c3c, 0x0c3c,
+ 0x0c3e, 0x0c44,
+ 0x0c46, 0x0c48,
+ 0x0c4a, 0x0c4d,
+ 0x0c55, 0x0c56,
+ 0x0c62, 0x0c63,
+ 0x0c81, 0x0c83,
+ 0x0cbc, 0x0cbc,
+ 0x0cbe, 0x0cc4,
+ 0x0cc6, 0x0cc8,
+ 0x0cca, 0x0ccd,
+ 0x0cd5, 0x0cd6,
+ 0x0ce2, 0x0ce3,
+ 0x0cf3, 0x0cf3,
+ 0x0d00, 0x0d03,
+ 0x0d3b, 0x0d3c,
+ 0x0d3e, 0x0d44,
+ 0x0d46, 0x0d48,
+ 0x0d4a, 0x0d4d,
+ 0x0d57, 0x0d57,
+ 0x0d62, 0x0d63,
+ 0x0d81, 0x0d83,
+ 0x0dca, 0x0dca,
+ 0x0dcf, 0x0dd4,
+ 0x0dd6, 0x0dd6,
+ 0x0dd8, 0x0ddf,
+ 0x0df2, 0x0df3,
+ 0x0e31, 0x0e31,
+ 0x0e34, 0x0e3a,
+ 0x0e47, 0x0e4e,
+ 0x0eb1, 0x0eb1,
+ 0x0eb4, 0x0ebc,
+ 0x0ec8, 0x0ece,
+ 0x0f18, 0x0f19,
+ 0x0f35, 0x0f35,
+ 0x0f37, 0x0f37,
+ 0x0f39, 0x0f39,
+ 0x0f3e, 0x0f3f,
+ 0x0f71, 0x0f84,
+ 0x0f86, 0x0f87,
+ 0x0f8d, 0x0f97,
+ 0x0f99, 0x0fbc,
+ 0x0fc6, 0x0fc6,
+ 0x102b, 0x103e,
+ 0x1056, 0x1059,
+ 0x105e, 0x1060,
+ 0x1062, 0x1064,
+ 0x1067, 0x106d,
+ 0x1071, 0x1074,
+ 0x1082, 0x108d,
+ 0x108f, 0x108f,
+ 0x109a, 0x109d,
+ 0x135d, 0x135f,
+ 0x1712, 0x1715,
+ 0x1732, 0x1734,
+ 0x1752, 0x1753,
+ 0x1772, 0x1773,
+ 0x17b4, 0x17d3,
+ 0x17dd, 0x17dd,
+ 0x180b, 0x180d,
+ 0x180f, 0x180f,
+ 0x1885, 0x1886,
+ 0x18a9, 0x18a9,
+ 0x1920, 0x192b,
+ 0x1930, 0x193b,
+ 0x1a17, 0x1a1b,
+ 0x1a55, 0x1a5e,
+ 0x1a60, 0x1a7c,
+ 0x1a7f, 0x1a7f,
+ 0x1ab0, 0x1add,
+ 0x1ae0, 0x1aeb,
+ 0x1b00, 0x1b04,
+ 0x1b34, 0x1b44,
+ 0x1b6b, 0x1b73,
+ 0x1b80, 0x1b82,
+ 0x1ba1, 0x1bad,
+ 0x1be6, 0x1bf3,
+ 0x1c24, 0x1c37,
+ 0x1cd0, 0x1cd2,
+ 0x1cd4, 0x1ce8,
+ 0x1ced, 0x1ced,
+ 0x1cf4, 0x1cf4,
+ 0x1cf7, 0x1cf9,
+ 0x1dc0, 0x1dff,
+ 0x20d0, 0x20f0,
+ 0x2cef, 0x2cf1,
+ 0x2d7f, 0x2d7f,
+ 0x2de0, 0x2dff,
+ 0x302a, 0x302f,
+ 0x3099, 0x309a,
+ 0xa66f, 0xa672,
+ 0xa674, 0xa67d,
+ 0xa69e, 0xa69f,
+ 0xa6f0, 0xa6f1,
+ 0xa802, 0xa802,
+ 0xa806, 0xa806,
+ 0xa80b, 0xa80b,
+ 0xa823, 0xa827,
+ 0xa82c, 0xa82c,
+ 0xa880, 0xa881,
+ 0xa8b4, 0xa8c5,
+ 0xa8e0, 0xa8f1,
+ 0xa8ff, 0xa8ff,
+ 0xa926, 0xa92d,
+ 0xa947, 0xa953,
+ 0xa980, 0xa983,
+ 0xa9b3, 0xa9c0,
+ 0xa9e5, 0xa9e5,
+ 0xaa29, 0xaa36,
+ 0xaa43, 0xaa43,
+ 0xaa4c, 0xaa4d,
+ 0xaa7b, 0xaa7d,
+ 0xaab0, 0xaab0,
+ 0xaab2, 0xaab4,
+ 0xaab7, 0xaab8,
+ 0xaabe, 0xaabf,
+ 0xaac1, 0xaac1,
+ 0xaaeb, 0xaaef,
+ 0xaaf5, 0xaaf6,
+ 0xabe3, 0xabea,
+ 0xabec, 0xabed,
+ 0xfb1e, 0xfb1e,
+ 0xfe00, 0xfe0f,
+ 0xfe20, 0xfe2f,
+ 0x101fd, 0x101fd,
+ 0x102e0, 0x102e0,
+ 0x10376, 0x1037a,
+ 0x10a01, 0x10a03,
+ 0x10a05, 0x10a06,
+ 0x10a0c, 0x10a0f,
+ 0x10a38, 0x10a3a,
+ 0x10a3f, 0x10a3f,
+ 0x10ae5, 0x10ae6,
+ 0x10d24, 0x10d27,
+ 0x10d69, 0x10d6d,
+ 0x10eab, 0x10eac,
+ 0x10efa, 0x10eff,
+ 0x10f46, 0x10f50,
+ 0x10f82, 0x10f85,
+ 0x11000, 0x11002,
+ 0x11038, 0x11046,
+ 0x11070, 0x11070,
+ 0x11073, 0x11074,
+ 0x1107f, 0x11082,
+ 0x110b0, 0x110ba,
+ 0x110c2, 0x110c2,
+ 0x11100, 0x11102,
+ 0x11127, 0x11134,
+ 0x11145, 0x11146,
+ 0x11173, 0x11173,
+ 0x11180, 0x11182,
+ 0x111b3, 0x111c0,
+ 0x111c9, 0x111cc,
+ 0x111ce, 0x111cf,
+ 0x1122c, 0x11237,
+ 0x1123e, 0x1123e,
+ 0x11241, 0x11241,
+ 0x112df, 0x112ea,
+ 0x11300, 0x11303,
+ 0x1133b, 0x1133c,
+ 0x1133e, 0x11344,
+ 0x11347, 0x11348,
+ 0x1134b, 0x1134d,
+ 0x11357, 0x11357,
+ 0x11362, 0x11363,
+ 0x11366, 0x1136c,
+ 0x11370, 0x11374,
+ 0x113b8, 0x113c0,
+ 0x113c2, 0x113c2,
+ 0x113c5, 0x113c5,
+ 0x113c7, 0x113ca,
+ 0x113cc, 0x113d0,
+ 0x113d2, 0x113d2,
+ 0x113e1, 0x113e2,
+ 0x11435, 0x11446,
+ 0x1145e, 0x1145e,
+ 0x114b0, 0x114c3,
+ 0x115af, 0x115b5,
+ 0x115b8, 0x115c0,
+ 0x115dc, 0x115dd,
+ 0x11630, 0x11640,
+ 0x116ab, 0x116b7,
+ 0x1171d, 0x1172b,
+ 0x1182c, 0x1183a,
+ 0x11930, 0x11935,
+ 0x11937, 0x11938,
+ 0x1193b, 0x1193e,
+ 0x11940, 0x11940,
+ 0x11942, 0x11943,
+ 0x119d1, 0x119d7,
+ 0x119da, 0x119e0,
+ 0x119e4, 0x119e4,
+ 0x11a01, 0x11a0a,
+ 0x11a33, 0x11a39,
+ 0x11a3b, 0x11a3e,
+ 0x11a47, 0x11a47,
+ 0x11a51, 0x11a5b,
+ 0x11a8a, 0x11a99,
+ 0x11b60, 0x11b67,
+ 0x11c2f, 0x11c36,
+ 0x11c38, 0x11c3f,
+ 0x11c92, 0x11ca7,
+ 0x11ca9, 0x11cb6,
+ 0x11d31, 0x11d36,
+ 0x11d3a, 0x11d3a,
+ 0x11d3c, 0x11d3d,
+ 0x11d3f, 0x11d45,
+ 0x11d47, 0x11d47,
+ 0x11d8a, 0x11d8e,
+ 0x11d90, 0x11d91,
+ 0x11d93, 0x11d97,
+ 0x11ef3, 0x11ef6,
+ 0x11f00, 0x11f01,
+ 0x11f03, 0x11f03,
+ 0x11f34, 0x11f3a,
+ 0x11f3e, 0x11f42,
+ 0x11f5a, 0x11f5a,
+ 0x13440, 0x13440,
+ 0x13447, 0x13455,
+ 0x1611e, 0x1612f,
+ 0x16af0, 0x16af4,
+ 0x16b30, 0x16b36,
+ 0x16f4f, 0x16f4f,
+ 0x16f51, 0x16f87,
+ 0x16f8f, 0x16f92,
+ 0x16fe4, 0x16fe4,
+ 0x16ff0, 0x16ff1,
+ 0x1bc9d, 0x1bc9e,
+ 0x1cf00, 0x1cf2d,
+ 0x1cf30, 0x1cf46,
+ 0x1d165, 0x1d169,
+ 0x1d16d, 0x1d172,
+ 0x1d17b, 0x1d182,
+ 0x1d185, 0x1d18b,
+ 0x1d1aa, 0x1d1ad,
+ 0x1d242, 0x1d244,
+ 0x1da00, 0x1da36,
+ 0x1da3b, 0x1da6c,
+ 0x1da75, 0x1da75,
+ 0x1da84, 0x1da84,
+ 0x1da9b, 0x1da9f,
+ 0x1daa1, 0x1daaf,
+ 0x1e000, 0x1e006,
+ 0x1e008, 0x1e018,
+ 0x1e01b, 0x1e021,
+ 0x1e023, 0x1e024,
+ 0x1e026, 0x1e02a,
+ 0x1e08f, 0x1e08f,
+ 0x1e130, 0x1e136,
+ 0x1e2ae, 0x1e2ae,
+ 0x1e2ec, 0x1e2ef,
+ 0x1e4ec, 0x1e4ef,
+ 0x1e5ee, 0x1e5ef,
+ 0x1e6e3, 0x1e6e3,
+ 0x1e6e6, 0x1e6e6,
+ 0x1e6ee, 0x1e6ef,
+ 0x1e6f5, 0x1e6f5,
+ 0x1e8d0, 0x1e8d6,
+ 0x1e944, 0x1e94a,
+ 0xe0100, 0xe01ef,
+}; /* CR_M */
+
+/* 'Mc': General Category */
+static const OnigCodePoint CR_Mc[] = {
+ 193,
+ 0x0903, 0x0903,
+ 0x093b, 0x093b,
+ 0x093e, 0x0940,
+ 0x0949, 0x094c,
+ 0x094e, 0x094f,
+ 0x0982, 0x0983,
+ 0x09be, 0x09c0,
+ 0x09c7, 0x09c8,
+ 0x09cb, 0x09cc,
+ 0x09d7, 0x09d7,
+ 0x0a03, 0x0a03,
+ 0x0a3e, 0x0a40,
+ 0x0a83, 0x0a83,
+ 0x0abe, 0x0ac0,
+ 0x0ac9, 0x0ac9,
+ 0x0acb, 0x0acc,
+ 0x0b02, 0x0b03,
+ 0x0b3e, 0x0b3e,
+ 0x0b40, 0x0b40,
+ 0x0b47, 0x0b48,
+ 0x0b4b, 0x0b4c,
+ 0x0b57, 0x0b57,
+ 0x0bbe, 0x0bbf,
+ 0x0bc1, 0x0bc2,
+ 0x0bc6, 0x0bc8,
+ 0x0bca, 0x0bcc,
+ 0x0bd7, 0x0bd7,
+ 0x0c01, 0x0c03,
+ 0x0c41, 0x0c44,
+ 0x0c82, 0x0c83,
+ 0x0cbe, 0x0cbe,
+ 0x0cc0, 0x0cc4,
+ 0x0cc7, 0x0cc8,
+ 0x0cca, 0x0ccb,
+ 0x0cd5, 0x0cd6,
+ 0x0cf3, 0x0cf3,
+ 0x0d02, 0x0d03,
+ 0x0d3e, 0x0d40,
+ 0x0d46, 0x0d48,
+ 0x0d4a, 0x0d4c,
+ 0x0d57, 0x0d57,
+ 0x0d82, 0x0d83,
+ 0x0dcf, 0x0dd1,
+ 0x0dd8, 0x0ddf,
+ 0x0df2, 0x0df3,
+ 0x0f3e, 0x0f3f,
+ 0x0f7f, 0x0f7f,
+ 0x102b, 0x102c,
+ 0x1031, 0x1031,
+ 0x1038, 0x1038,
+ 0x103b, 0x103c,
+ 0x1056, 0x1057,
+ 0x1062, 0x1064,
+ 0x1067, 0x106d,
+ 0x1083, 0x1084,
+ 0x1087, 0x108c,
+ 0x108f, 0x108f,
+ 0x109a, 0x109c,
+ 0x1715, 0x1715,
+ 0x1734, 0x1734,
+ 0x17b6, 0x17b6,
+ 0x17be, 0x17c5,
+ 0x17c7, 0x17c8,
+ 0x1923, 0x1926,
+ 0x1929, 0x192b,
+ 0x1930, 0x1931,
+ 0x1933, 0x1938,
+ 0x1a19, 0x1a1a,
+ 0x1a55, 0x1a55,
+ 0x1a57, 0x1a57,
+ 0x1a61, 0x1a61,
+ 0x1a63, 0x1a64,
+ 0x1a6d, 0x1a72,
+ 0x1b04, 0x1b04,
+ 0x1b35, 0x1b35,
+ 0x1b3b, 0x1b3b,
+ 0x1b3d, 0x1b41,
+ 0x1b43, 0x1b44,
+ 0x1b82, 0x1b82,
+ 0x1ba1, 0x1ba1,
+ 0x1ba6, 0x1ba7,
+ 0x1baa, 0x1baa,
+ 0x1be7, 0x1be7,
+ 0x1bea, 0x1bec,
+ 0x1bee, 0x1bee,
+ 0x1bf2, 0x1bf3,
+ 0x1c24, 0x1c2b,
+ 0x1c34, 0x1c35,
+ 0x1ce1, 0x1ce1,
+ 0x1cf7, 0x1cf7,
+ 0x302e, 0x302f,
+ 0xa823, 0xa824,
+ 0xa827, 0xa827,
+ 0xa880, 0xa881,
+ 0xa8b4, 0xa8c3,
+ 0xa952, 0xa953,
+ 0xa983, 0xa983,
+ 0xa9b4, 0xa9b5,
+ 0xa9ba, 0xa9bb,
+ 0xa9be, 0xa9c0,
+ 0xaa2f, 0xaa30,
+ 0xaa33, 0xaa34,
+ 0xaa4d, 0xaa4d,
+ 0xaa7b, 0xaa7b,
+ 0xaa7d, 0xaa7d,
+ 0xaaeb, 0xaaeb,
+ 0xaaee, 0xaaef,
+ 0xaaf5, 0xaaf5,
+ 0xabe3, 0xabe4,
+ 0xabe6, 0xabe7,
+ 0xabe9, 0xabea,
+ 0xabec, 0xabec,
+ 0x11000, 0x11000,
+ 0x11002, 0x11002,
+ 0x11082, 0x11082,
+ 0x110b0, 0x110b2,
+ 0x110b7, 0x110b8,
+ 0x1112c, 0x1112c,
+ 0x11145, 0x11146,
+ 0x11182, 0x11182,
+ 0x111b3, 0x111b5,
+ 0x111bf, 0x111c0,
+ 0x111ce, 0x111ce,
+ 0x1122c, 0x1122e,
+ 0x11232, 0x11233,
+ 0x11235, 0x11235,
+ 0x112e0, 0x112e2,
+ 0x11302, 0x11303,
+ 0x1133e, 0x1133f,
+ 0x11341, 0x11344,
+ 0x11347, 0x11348,
+ 0x1134b, 0x1134d,
+ 0x11357, 0x11357,
+ 0x11362, 0x11363,
+ 0x113b8, 0x113ba,
+ 0x113c2, 0x113c2,
+ 0x113c5, 0x113c5,
+ 0x113c7, 0x113ca,
+ 0x113cc, 0x113cd,
+ 0x113cf, 0x113cf,
+ 0x11435, 0x11437,
+ 0x11440, 0x11441,
+ 0x11445, 0x11445,
+ 0x114b0, 0x114b2,
+ 0x114b9, 0x114b9,
+ 0x114bb, 0x114be,
+ 0x114c1, 0x114c1,
+ 0x115af, 0x115b1,
+ 0x115b8, 0x115bb,
+ 0x115be, 0x115be,
+ 0x11630, 0x11632,
+ 0x1163b, 0x1163c,
+ 0x1163e, 0x1163e,
+ 0x116ac, 0x116ac,
+ 0x116ae, 0x116af,
+ 0x116b6, 0x116b6,
+ 0x1171e, 0x1171e,
+ 0x11720, 0x11721,
+ 0x11726, 0x11726,
+ 0x1182c, 0x1182e,
+ 0x11838, 0x11838,
+ 0x11930, 0x11935,
+ 0x11937, 0x11938,
+ 0x1193d, 0x1193d,
+ 0x11940, 0x11940,
+ 0x11942, 0x11942,
+ 0x119d1, 0x119d3,
+ 0x119dc, 0x119df,
+ 0x119e4, 0x119e4,
+ 0x11a39, 0x11a39,
+ 0x11a57, 0x11a58,
+ 0x11a97, 0x11a97,
+ 0x11b61, 0x11b61,
+ 0x11b65, 0x11b65,
+ 0x11b67, 0x11b67,
+ 0x11c2f, 0x11c2f,
+ 0x11c3e, 0x11c3e,
+ 0x11ca9, 0x11ca9,
+ 0x11cb1, 0x11cb1,
+ 0x11cb4, 0x11cb4,
+ 0x11d8a, 0x11d8e,
+ 0x11d93, 0x11d94,
+ 0x11d96, 0x11d96,
+ 0x11ef5, 0x11ef6,
+ 0x11f03, 0x11f03,
+ 0x11f34, 0x11f35,
+ 0x11f3e, 0x11f3f,
+ 0x11f41, 0x11f41,
+ 0x1612a, 0x1612c,
+ 0x16f51, 0x16f87,
+ 0x16ff0, 0x16ff1,
+ 0x1d165, 0x1d166,
+ 0x1d16d, 0x1d172,
+}; /* CR_Mc */
+
+/* 'Me': General Category */
+static const OnigCodePoint CR_Me[] = {
+ 5,
+ 0x0488, 0x0489,
+ 0x1abe, 0x1abe,
+ 0x20dd, 0x20e0,
+ 0x20e2, 0x20e4,
+ 0xa670, 0xa672,
+}; /* CR_Me */
+
+/* 'Mn': General Category */
+static const OnigCodePoint CR_Mn[] = {
+ 365,
+ 0x0300, 0x036f,
+ 0x0483, 0x0487,
+ 0x0591, 0x05bd,
+ 0x05bf, 0x05bf,
+ 0x05c1, 0x05c2,
+ 0x05c4, 0x05c5,
+ 0x05c7, 0x05c7,
+ 0x0610, 0x061a,
+ 0x064b, 0x065f,
+ 0x0670, 0x0670,
+ 0x06d6, 0x06dc,
+ 0x06df, 0x06e4,
+ 0x06e7, 0x06e8,
+ 0x06ea, 0x06ed,
+ 0x0711, 0x0711,
+ 0x0730, 0x074a,
+ 0x07a6, 0x07b0,
+ 0x07eb, 0x07f3,
+ 0x07fd, 0x07fd,
+ 0x0816, 0x0819,
+ 0x081b, 0x0823,
+ 0x0825, 0x0827,
+ 0x0829, 0x082d,
+ 0x0859, 0x085b,
+ 0x0897, 0x089f,
+ 0x08ca, 0x08e1,
+ 0x08e3, 0x0902,
+ 0x093a, 0x093a,
+ 0x093c, 0x093c,
+ 0x0941, 0x0948,
+ 0x094d, 0x094d,
+ 0x0951, 0x0957,
+ 0x0962, 0x0963,
+ 0x0981, 0x0981,
+ 0x09bc, 0x09bc,
+ 0x09c1, 0x09c4,
+ 0x09cd, 0x09cd,
+ 0x09e2, 0x09e3,
+ 0x09fe, 0x09fe,
+ 0x0a01, 0x0a02,
+ 0x0a3c, 0x0a3c,
+ 0x0a41, 0x0a42,
+ 0x0a47, 0x0a48,
+ 0x0a4b, 0x0a4d,
+ 0x0a51, 0x0a51,
+ 0x0a70, 0x0a71,
+ 0x0a75, 0x0a75,
+ 0x0a81, 0x0a82,
+ 0x0abc, 0x0abc,
+ 0x0ac1, 0x0ac5,
+ 0x0ac7, 0x0ac8,
+ 0x0acd, 0x0acd,
+ 0x0ae2, 0x0ae3,
+ 0x0afa, 0x0aff,
+ 0x0b01, 0x0b01,
+ 0x0b3c, 0x0b3c,
+ 0x0b3f, 0x0b3f,
+ 0x0b41, 0x0b44,
+ 0x0b4d, 0x0b4d,
+ 0x0b55, 0x0b56,
+ 0x0b62, 0x0b63,
+ 0x0b82, 0x0b82,
+ 0x0bc0, 0x0bc0,
+ 0x0bcd, 0x0bcd,
+ 0x0c00, 0x0c00,
+ 0x0c04, 0x0c04,
+ 0x0c3c, 0x0c3c,
+ 0x0c3e, 0x0c40,
+ 0x0c46, 0x0c48,
+ 0x0c4a, 0x0c4d,
+ 0x0c55, 0x0c56,
+ 0x0c62, 0x0c63,
+ 0x0c81, 0x0c81,
+ 0x0cbc, 0x0cbc,
+ 0x0cbf, 0x0cbf,
+ 0x0cc6, 0x0cc6,
+ 0x0ccc, 0x0ccd,
+ 0x0ce2, 0x0ce3,
+ 0x0d00, 0x0d01,
+ 0x0d3b, 0x0d3c,
+ 0x0d41, 0x0d44,
+ 0x0d4d, 0x0d4d,
+ 0x0d62, 0x0d63,
+ 0x0d81, 0x0d81,
+ 0x0dca, 0x0dca,
+ 0x0dd2, 0x0dd4,
+ 0x0dd6, 0x0dd6,
+ 0x0e31, 0x0e31,
+ 0x0e34, 0x0e3a,
+ 0x0e47, 0x0e4e,
+ 0x0eb1, 0x0eb1,
+ 0x0eb4, 0x0ebc,
+ 0x0ec8, 0x0ece,
+ 0x0f18, 0x0f19,
+ 0x0f35, 0x0f35,
+ 0x0f37, 0x0f37,
+ 0x0f39, 0x0f39,
+ 0x0f71, 0x0f7e,
+ 0x0f80, 0x0f84,
+ 0x0f86, 0x0f87,
+ 0x0f8d, 0x0f97,
+ 0x0f99, 0x0fbc,
+ 0x0fc6, 0x0fc6,
+ 0x102d, 0x1030,
+ 0x1032, 0x1037,
+ 0x1039, 0x103a,
+ 0x103d, 0x103e,
+ 0x1058, 0x1059,
+ 0x105e, 0x1060,
+ 0x1071, 0x1074,
+ 0x1082, 0x1082,
+ 0x1085, 0x1086,
+ 0x108d, 0x108d,
+ 0x109d, 0x109d,
+ 0x135d, 0x135f,
+ 0x1712, 0x1714,
+ 0x1732, 0x1733,
+ 0x1752, 0x1753,
+ 0x1772, 0x1773,
+ 0x17b4, 0x17b5,
+ 0x17b7, 0x17bd,
+ 0x17c6, 0x17c6,
+ 0x17c9, 0x17d3,
+ 0x17dd, 0x17dd,
+ 0x180b, 0x180d,
+ 0x180f, 0x180f,
+ 0x1885, 0x1886,
+ 0x18a9, 0x18a9,
+ 0x1920, 0x1922,
+ 0x1927, 0x1928,
+ 0x1932, 0x1932,
+ 0x1939, 0x193b,
+ 0x1a17, 0x1a18,
+ 0x1a1b, 0x1a1b,
+ 0x1a56, 0x1a56,
+ 0x1a58, 0x1a5e,
+ 0x1a60, 0x1a60,
+ 0x1a62, 0x1a62,
+ 0x1a65, 0x1a6c,
+ 0x1a73, 0x1a7c,
+ 0x1a7f, 0x1a7f,
+ 0x1ab0, 0x1abd,
+ 0x1abf, 0x1add,
+ 0x1ae0, 0x1aeb,
+ 0x1b00, 0x1b03,
+ 0x1b34, 0x1b34,
+ 0x1b36, 0x1b3a,
+ 0x1b3c, 0x1b3c,
+ 0x1b42, 0x1b42,
+ 0x1b6b, 0x1b73,
+ 0x1b80, 0x1b81,
+ 0x1ba2, 0x1ba5,
+ 0x1ba8, 0x1ba9,
+ 0x1bab, 0x1bad,
+ 0x1be6, 0x1be6,
+ 0x1be8, 0x1be9,
+ 0x1bed, 0x1bed,
+ 0x1bef, 0x1bf1,
+ 0x1c2c, 0x1c33,
+ 0x1c36, 0x1c37,
+ 0x1cd0, 0x1cd2,
+ 0x1cd4, 0x1ce0,
+ 0x1ce2, 0x1ce8,
+ 0x1ced, 0x1ced,
+ 0x1cf4, 0x1cf4,
+ 0x1cf8, 0x1cf9,
+ 0x1dc0, 0x1dff,
+ 0x20d0, 0x20dc,
+ 0x20e1, 0x20e1,
+ 0x20e5, 0x20f0,
+ 0x2cef, 0x2cf1,
+ 0x2d7f, 0x2d7f,
+ 0x2de0, 0x2dff,
+ 0x302a, 0x302d,
+ 0x3099, 0x309a,
+ 0xa66f, 0xa66f,
+ 0xa674, 0xa67d,
+ 0xa69e, 0xa69f,
+ 0xa6f0, 0xa6f1,
+ 0xa802, 0xa802,
+ 0xa806, 0xa806,
+ 0xa80b, 0xa80b,
+ 0xa825, 0xa826,
+ 0xa82c, 0xa82c,
+ 0xa8c4, 0xa8c5,
+ 0xa8e0, 0xa8f1,
+ 0xa8ff, 0xa8ff,
+ 0xa926, 0xa92d,
+ 0xa947, 0xa951,
+ 0xa980, 0xa982,
+ 0xa9b3, 0xa9b3,
+ 0xa9b6, 0xa9b9,
+ 0xa9bc, 0xa9bd,
+ 0xa9e5, 0xa9e5,
+ 0xaa29, 0xaa2e,
+ 0xaa31, 0xaa32,
+ 0xaa35, 0xaa36,
+ 0xaa43, 0xaa43,
+ 0xaa4c, 0xaa4c,
+ 0xaa7c, 0xaa7c,
+ 0xaab0, 0xaab0,
+ 0xaab2, 0xaab4,
+ 0xaab7, 0xaab8,
+ 0xaabe, 0xaabf,
+ 0xaac1, 0xaac1,
+ 0xaaec, 0xaaed,
+ 0xaaf6, 0xaaf6,
+ 0xabe5, 0xabe5,
+ 0xabe8, 0xabe8,
+ 0xabed, 0xabed,
+ 0xfb1e, 0xfb1e,
+ 0xfe00, 0xfe0f,
+ 0xfe20, 0xfe2f,
+ 0x101fd, 0x101fd,
+ 0x102e0, 0x102e0,
+ 0x10376, 0x1037a,
+ 0x10a01, 0x10a03,
+ 0x10a05, 0x10a06,
+ 0x10a0c, 0x10a0f,
+ 0x10a38, 0x10a3a,
+ 0x10a3f, 0x10a3f,
+ 0x10ae5, 0x10ae6,
+ 0x10d24, 0x10d27,
+ 0x10d69, 0x10d6d,
+ 0x10eab, 0x10eac,
+ 0x10efa, 0x10eff,
+ 0x10f46, 0x10f50,
+ 0x10f82, 0x10f85,
+ 0x11001, 0x11001,
+ 0x11038, 0x11046,
+ 0x11070, 0x11070,
+ 0x11073, 0x11074,
+ 0x1107f, 0x11081,
+ 0x110b3, 0x110b6,
+ 0x110b9, 0x110ba,
+ 0x110c2, 0x110c2,
+ 0x11100, 0x11102,
+ 0x11127, 0x1112b,
+ 0x1112d, 0x11134,
+ 0x11173, 0x11173,
+ 0x11180, 0x11181,
+ 0x111b6, 0x111be,
+ 0x111c9, 0x111cc,
+ 0x111cf, 0x111cf,
+ 0x1122f, 0x11231,
+ 0x11234, 0x11234,
+ 0x11236, 0x11237,
+ 0x1123e, 0x1123e,
+ 0x11241, 0x11241,
+ 0x112df, 0x112df,
+ 0x112e3, 0x112ea,
+ 0x11300, 0x11301,
+ 0x1133b, 0x1133c,
+ 0x11340, 0x11340,
+ 0x11366, 0x1136c,
+ 0x11370, 0x11374,
+ 0x113bb, 0x113c0,
+ 0x113ce, 0x113ce,
+ 0x113d0, 0x113d0,
+ 0x113d2, 0x113d2,
+ 0x113e1, 0x113e2,
+ 0x11438, 0x1143f,
+ 0x11442, 0x11444,
+ 0x11446, 0x11446,
+ 0x1145e, 0x1145e,
+ 0x114b3, 0x114b8,
+ 0x114ba, 0x114ba,
+ 0x114bf, 0x114c0,
+ 0x114c2, 0x114c3,
+ 0x115b2, 0x115b5,
+ 0x115bc, 0x115bd,
+ 0x115bf, 0x115c0,
+ 0x115dc, 0x115dd,
+ 0x11633, 0x1163a,
+ 0x1163d, 0x1163d,
+ 0x1163f, 0x11640,
+ 0x116ab, 0x116ab,
+ 0x116ad, 0x116ad,
+ 0x116b0, 0x116b5,
+ 0x116b7, 0x116b7,
+ 0x1171d, 0x1171d,
+ 0x1171f, 0x1171f,
+ 0x11722, 0x11725,
+ 0x11727, 0x1172b,
+ 0x1182f, 0x11837,
+ 0x11839, 0x1183a,
+ 0x1193b, 0x1193c,
+ 0x1193e, 0x1193e,
+ 0x11943, 0x11943,
+ 0x119d4, 0x119d7,
+ 0x119da, 0x119db,
+ 0x119e0, 0x119e0,
+ 0x11a01, 0x11a0a,
+ 0x11a33, 0x11a38,
+ 0x11a3b, 0x11a3e,
+ 0x11a47, 0x11a47,
+ 0x11a51, 0x11a56,
+ 0x11a59, 0x11a5b,
+ 0x11a8a, 0x11a96,
+ 0x11a98, 0x11a99,
+ 0x11b60, 0x11b60,
+ 0x11b62, 0x11b64,
+ 0x11b66, 0x11b66,
+ 0x11c30, 0x11c36,
+ 0x11c38, 0x11c3d,
+ 0x11c3f, 0x11c3f,
+ 0x11c92, 0x11ca7,
+ 0x11caa, 0x11cb0,
+ 0x11cb2, 0x11cb3,
+ 0x11cb5, 0x11cb6,
+ 0x11d31, 0x11d36,
+ 0x11d3a, 0x11d3a,
+ 0x11d3c, 0x11d3d,
+ 0x11d3f, 0x11d45,
+ 0x11d47, 0x11d47,
+ 0x11d90, 0x11d91,
+ 0x11d95, 0x11d95,
+ 0x11d97, 0x11d97,
+ 0x11ef3, 0x11ef4,
+ 0x11f00, 0x11f01,
+ 0x11f36, 0x11f3a,
+ 0x11f40, 0x11f40,
+ 0x11f42, 0x11f42,
+ 0x11f5a, 0x11f5a,
+ 0x13440, 0x13440,
+ 0x13447, 0x13455,
+ 0x1611e, 0x16129,
+ 0x1612d, 0x1612f,
+ 0x16af0, 0x16af4,
+ 0x16b30, 0x16b36,
+ 0x16f4f, 0x16f4f,
+ 0x16f8f, 0x16f92,
+ 0x16fe4, 0x16fe4,
+ 0x1bc9d, 0x1bc9e,
+ 0x1cf00, 0x1cf2d,
+ 0x1cf30, 0x1cf46,
+ 0x1d167, 0x1d169,
+ 0x1d17b, 0x1d182,
+ 0x1d185, 0x1d18b,
+ 0x1d1aa, 0x1d1ad,
+ 0x1d242, 0x1d244,
+ 0x1da00, 0x1da36,
+ 0x1da3b, 0x1da6c,
+ 0x1da75, 0x1da75,
+ 0x1da84, 0x1da84,
+ 0x1da9b, 0x1da9f,
+ 0x1daa1, 0x1daaf,
+ 0x1e000, 0x1e006,
+ 0x1e008, 0x1e018,
+ 0x1e01b, 0x1e021,
+ 0x1e023, 0x1e024,
+ 0x1e026, 0x1e02a,
+ 0x1e08f, 0x1e08f,
+ 0x1e130, 0x1e136,
+ 0x1e2ae, 0x1e2ae,
+ 0x1e2ec, 0x1e2ef,
+ 0x1e4ec, 0x1e4ef,
+ 0x1e5ee, 0x1e5ef,
+ 0x1e6e3, 0x1e6e3,
+ 0x1e6e6, 0x1e6e6,
+ 0x1e6ee, 0x1e6ef,
+ 0x1e6f5, 0x1e6f5,
+ 0x1e8d0, 0x1e8d6,
+ 0x1e944, 0x1e94a,
+ 0xe0100, 0xe01ef,
+}; /* CR_Mn */
+
+/* 'N': Major Category */
+static const OnigCodePoint CR_N[] = {
+ 146,
+ 0x0030, 0x0039,
+ 0x00b2, 0x00b3,
+ 0x00b9, 0x00b9,
+ 0x00bc, 0x00be,
+ 0x0660, 0x0669,
+ 0x06f0, 0x06f9,
+ 0x07c0, 0x07c9,
+ 0x0966, 0x096f,
+ 0x09e6, 0x09ef,
+ 0x09f4, 0x09f9,
+ 0x0a66, 0x0a6f,
+ 0x0ae6, 0x0aef,
+ 0x0b66, 0x0b6f,
+ 0x0b72, 0x0b77,
+ 0x0be6, 0x0bf2,
+ 0x0c66, 0x0c6f,
+ 0x0c78, 0x0c7e,
+ 0x0ce6, 0x0cef,
+ 0x0d58, 0x0d5e,
+ 0x0d66, 0x0d78,
+ 0x0de6, 0x0def,
+ 0x0e50, 0x0e59,
+ 0x0ed0, 0x0ed9,
+ 0x0f20, 0x0f33,
+ 0x1040, 0x1049,
+ 0x1090, 0x1099,
+ 0x1369, 0x137c,
+ 0x16ee, 0x16f0,
+ 0x17e0, 0x17e9,
+ 0x17f0, 0x17f9,
+ 0x1810, 0x1819,
+ 0x1946, 0x194f,
+ 0x19d0, 0x19da,
+ 0x1a80, 0x1a89,
+ 0x1a90, 0x1a99,
+ 0x1b50, 0x1b59,
+ 0x1bb0, 0x1bb9,
+ 0x1c40, 0x1c49,
+ 0x1c50, 0x1c59,
+ 0x2070, 0x2070,
+ 0x2074, 0x2079,
+ 0x2080, 0x2089,
+ 0x2150, 0x2182,
+ 0x2185, 0x2189,
+ 0x2460, 0x249b,
+ 0x24ea, 0x24ff,
+ 0x2776, 0x2793,
+ 0x2cfd, 0x2cfd,
+ 0x3007, 0x3007,
+ 0x3021, 0x3029,
+ 0x3038, 0x303a,
+ 0x3192, 0x3195,
+ 0x3220, 0x3229,
+ 0x3248, 0x324f,
+ 0x3251, 0x325f,
+ 0x3280, 0x3289,
+ 0x32b1, 0x32bf,
+ 0xa620, 0xa629,
+ 0xa6e6, 0xa6ef,
+ 0xa830, 0xa835,
+ 0xa8d0, 0xa8d9,
+ 0xa900, 0xa909,
+ 0xa9d0, 0xa9d9,
+ 0xa9f0, 0xa9f9,
+ 0xaa50, 0xaa59,
+ 0xabf0, 0xabf9,
+ 0xff10, 0xff19,
+ 0x10107, 0x10133,
+ 0x10140, 0x10178,
+ 0x1018a, 0x1018b,
+ 0x102e1, 0x102fb,
+ 0x10320, 0x10323,
+ 0x10341, 0x10341,
+ 0x1034a, 0x1034a,
+ 0x103d1, 0x103d5,
+ 0x104a0, 0x104a9,
+ 0x10858, 0x1085f,
+ 0x10879, 0x1087f,
+ 0x108a7, 0x108af,
+ 0x108fb, 0x108ff,
+ 0x10916, 0x1091b,
+ 0x109bc, 0x109bd,
+ 0x109c0, 0x109cf,
+ 0x109d2, 0x109ff,
+ 0x10a40, 0x10a48,
+ 0x10a7d, 0x10a7e,
+ 0x10a9d, 0x10a9f,
+ 0x10aeb, 0x10aef,
+ 0x10b58, 0x10b5f,
+ 0x10b78, 0x10b7f,
+ 0x10ba9, 0x10baf,
+ 0x10cfa, 0x10cff,
+ 0x10d30, 0x10d39,
+ 0x10d40, 0x10d49,
+ 0x10e60, 0x10e7e,
+ 0x10f1d, 0x10f26,
+ 0x10f51, 0x10f54,
+ 0x10fc5, 0x10fcb,
+ 0x11052, 0x1106f,
+ 0x110f0, 0x110f9,
+ 0x11136, 0x1113f,
+ 0x111d0, 0x111d9,
+ 0x111e1, 0x111f4,
+ 0x112f0, 0x112f9,
+ 0x11450, 0x11459,
+ 0x114d0, 0x114d9,
+ 0x11650, 0x11659,
+ 0x116c0, 0x116c9,
+ 0x116d0, 0x116e3,
+ 0x11730, 0x1173b,
+ 0x118e0, 0x118f2,
+ 0x11950, 0x11959,
+ 0x11bf0, 0x11bf9,
+ 0x11c50, 0x11c6c,
+ 0x11d50, 0x11d59,
+ 0x11da0, 0x11da9,
+ 0x11de0, 0x11de9,
+ 0x11f50, 0x11f59,
+ 0x11fc0, 0x11fd4,
+ 0x12400, 0x1246e,
+ 0x16130, 0x16139,
+ 0x16a60, 0x16a69,
+ 0x16ac0, 0x16ac9,
+ 0x16b50, 0x16b59,
+ 0x16b5b, 0x16b61,
+ 0x16d70, 0x16d79,
+ 0x16e80, 0x16e96,
+ 0x16ff4, 0x16ff6,
+ 0x1ccf0, 0x1ccf9,
+ 0x1d2c0, 0x1d2d3,
+ 0x1d2e0, 0x1d2f3,
+ 0x1d360, 0x1d378,
+ 0x1d7ce, 0x1d7ff,
+ 0x1e140, 0x1e149,
+ 0x1e2f0, 0x1e2f9,
+ 0x1e4f0, 0x1e4f9,
+ 0x1e5f1, 0x1e5fa,
+ 0x1e8c7, 0x1e8cf,
+ 0x1e950, 0x1e959,
+ 0x1ec71, 0x1ecab,
+ 0x1ecad, 0x1ecaf,
+ 0x1ecb1, 0x1ecb4,
+ 0x1ed01, 0x1ed2d,
+ 0x1ed2f, 0x1ed3d,
+ 0x1f100, 0x1f10c,
+ 0x1fbf0, 0x1fbf9,
+}; /* CR_N */
+
+/* 'Nd': General Category */
+#define CR_Nd CR_Digit
+
+/* 'Nl': General Category */
+static const OnigCodePoint CR_Nl[] = {
+ 13,
+ 0x16ee, 0x16f0,
+ 0x2160, 0x2182,
+ 0x2185, 0x2188,
+ 0x3007, 0x3007,
+ 0x3021, 0x3029,
+ 0x3038, 0x303a,
+ 0xa6e6, 0xa6ef,
+ 0x10140, 0x10174,
+ 0x10341, 0x10341,
+ 0x1034a, 0x1034a,
+ 0x103d1, 0x103d5,
+ 0x12400, 0x1246e,
+ 0x16ff4, 0x16ff6,
+}; /* CR_Nl */
+
+/* 'No': General Category */
+static const OnigCodePoint CR_No[] = {
+ 72,
+ 0x00b2, 0x00b3,
+ 0x00b9, 0x00b9,
+ 0x00bc, 0x00be,
+ 0x09f4, 0x09f9,
+ 0x0b72, 0x0b77,
+ 0x0bf0, 0x0bf2,
+ 0x0c78, 0x0c7e,
+ 0x0d58, 0x0d5e,
+ 0x0d70, 0x0d78,
+ 0x0f2a, 0x0f33,
+ 0x1369, 0x137c,
+ 0x17f0, 0x17f9,
+ 0x19da, 0x19da,
+ 0x2070, 0x2070,
+ 0x2074, 0x2079,
+ 0x2080, 0x2089,
+ 0x2150, 0x215f,
+ 0x2189, 0x2189,
+ 0x2460, 0x249b,
+ 0x24ea, 0x24ff,
+ 0x2776, 0x2793,
+ 0x2cfd, 0x2cfd,
+ 0x3192, 0x3195,
+ 0x3220, 0x3229,
+ 0x3248, 0x324f,
+ 0x3251, 0x325f,
+ 0x3280, 0x3289,
+ 0x32b1, 0x32bf,
+ 0xa830, 0xa835,
+ 0x10107, 0x10133,
+ 0x10175, 0x10178,
+ 0x1018a, 0x1018b,
+ 0x102e1, 0x102fb,
+ 0x10320, 0x10323,
+ 0x10858, 0x1085f,
+ 0x10879, 0x1087f,
+ 0x108a7, 0x108af,
+ 0x108fb, 0x108ff,
+ 0x10916, 0x1091b,
+ 0x109bc, 0x109bd,
+ 0x109c0, 0x109cf,
+ 0x109d2, 0x109ff,
+ 0x10a40, 0x10a48,
+ 0x10a7d, 0x10a7e,
+ 0x10a9d, 0x10a9f,
+ 0x10aeb, 0x10aef,
+ 0x10b58, 0x10b5f,
+ 0x10b78, 0x10b7f,
+ 0x10ba9, 0x10baf,
+ 0x10cfa, 0x10cff,
+ 0x10e60, 0x10e7e,
+ 0x10f1d, 0x10f26,
+ 0x10f51, 0x10f54,
+ 0x10fc5, 0x10fcb,
+ 0x11052, 0x11065,
+ 0x111e1, 0x111f4,
+ 0x1173a, 0x1173b,
+ 0x118ea, 0x118f2,
+ 0x11c5a, 0x11c6c,
+ 0x11fc0, 0x11fd4,
+ 0x16b5b, 0x16b61,
+ 0x16e80, 0x16e96,
+ 0x1d2c0, 0x1d2d3,
+ 0x1d2e0, 0x1d2f3,
+ 0x1d360, 0x1d378,
+ 0x1e8c7, 0x1e8cf,
+ 0x1ec71, 0x1ecab,
+ 0x1ecad, 0x1ecaf,
+ 0x1ecb1, 0x1ecb4,
+ 0x1ed01, 0x1ed2d,
+ 0x1ed2f, 0x1ed3d,
+ 0x1f100, 0x1f10c,
+}; /* CR_No */
+
+/* 'P': Major Category */
+#define CR_P CR_Punct
+
+/* 'Pc': General Category */
+static const OnigCodePoint CR_Pc[] = {
+ 6,
+ 0x005f, 0x005f,
+ 0x203f, 0x2040,
+ 0x2054, 0x2054,
+ 0xfe33, 0xfe34,
+ 0xfe4d, 0xfe4f,
+ 0xff3f, 0xff3f,
+}; /* CR_Pc */
+
+/* 'Pd': General Category */
+static const OnigCodePoint CR_Pd[] = {
+ 20,
+ 0x002d, 0x002d,
+ 0x058a, 0x058a,
+ 0x05be, 0x05be,
+ 0x1400, 0x1400,
+ 0x1806, 0x1806,
+ 0x2010, 0x2015,
+ 0x2e17, 0x2e17,
+ 0x2e1a, 0x2e1a,
+ 0x2e3a, 0x2e3b,
+ 0x2e40, 0x2e40,
+ 0x2e5d, 0x2e5d,
+ 0x301c, 0x301c,
+ 0x3030, 0x3030,
+ 0x30a0, 0x30a0,
+ 0xfe31, 0xfe32,
+ 0xfe58, 0xfe58,
+ 0xfe63, 0xfe63,
+ 0xff0d, 0xff0d,
+ 0x10d6e, 0x10d6e,
+ 0x10ead, 0x10ead,
+}; /* CR_Pd */
+
+/* 'Pe': General Category */
+static const OnigCodePoint CR_Pe[] = {
+ 76,
+ 0x0029, 0x0029,
+ 0x005d, 0x005d,
+ 0x007d, 0x007d,
+ 0x0f3b, 0x0f3b,
+ 0x0f3d, 0x0f3d,
+ 0x169c, 0x169c,
+ 0x2046, 0x2046,
+ 0x207e, 0x207e,
+ 0x208e, 0x208e,
+ 0x2309, 0x2309,
+ 0x230b, 0x230b,
+ 0x232a, 0x232a,
+ 0x2769, 0x2769,
+ 0x276b, 0x276b,
+ 0x276d, 0x276d,
+ 0x276f, 0x276f,
+ 0x2771, 0x2771,
+ 0x2773, 0x2773,
+ 0x2775, 0x2775,
+ 0x27c6, 0x27c6,
+ 0x27e7, 0x27e7,
+ 0x27e9, 0x27e9,
+ 0x27eb, 0x27eb,
+ 0x27ed, 0x27ed,
+ 0x27ef, 0x27ef,
+ 0x2984, 0x2984,
+ 0x2986, 0x2986,
+ 0x2988, 0x2988,
+ 0x298a, 0x298a,
+ 0x298c, 0x298c,
+ 0x298e, 0x298e,
+ 0x2990, 0x2990,
+ 0x2992, 0x2992,
+ 0x2994, 0x2994,
+ 0x2996, 0x2996,
+ 0x2998, 0x2998,
+ 0x29d9, 0x29d9,
+ 0x29db, 0x29db,
+ 0x29fd, 0x29fd,
+ 0x2e23, 0x2e23,
+ 0x2e25, 0x2e25,
+ 0x2e27, 0x2e27,
+ 0x2e29, 0x2e29,
+ 0x2e56, 0x2e56,
+ 0x2e58, 0x2e58,
+ 0x2e5a, 0x2e5a,
+ 0x2e5c, 0x2e5c,
+ 0x3009, 0x3009,
+ 0x300b, 0x300b,
+ 0x300d, 0x300d,
+ 0x300f, 0x300f,
+ 0x3011, 0x3011,
+ 0x3015, 0x3015,
+ 0x3017, 0x3017,
+ 0x3019, 0x3019,
+ 0x301b, 0x301b,
+ 0x301e, 0x301f,
+ 0xfd3e, 0xfd3e,
+ 0xfe18, 0xfe18,
+ 0xfe36, 0xfe36,
+ 0xfe38, 0xfe38,
+ 0xfe3a, 0xfe3a,
+ 0xfe3c, 0xfe3c,
+ 0xfe3e, 0xfe3e,
+ 0xfe40, 0xfe40,
+ 0xfe42, 0xfe42,
+ 0xfe44, 0xfe44,
+ 0xfe48, 0xfe48,
+ 0xfe5a, 0xfe5a,
+ 0xfe5c, 0xfe5c,
+ 0xfe5e, 0xfe5e,
+ 0xff09, 0xff09,
+ 0xff3d, 0xff3d,
+ 0xff5d, 0xff5d,
+ 0xff60, 0xff60,
+ 0xff63, 0xff63,
+}; /* CR_Pe */
+
+/* 'Pf': General Category */
+static const OnigCodePoint CR_Pf[] = {
+ 10,
+ 0x00bb, 0x00bb,
+ 0x2019, 0x2019,
+ 0x201d, 0x201d,
+ 0x203a, 0x203a,
+ 0x2e03, 0x2e03,
+ 0x2e05, 0x2e05,
+ 0x2e0a, 0x2e0a,
+ 0x2e0d, 0x2e0d,
+ 0x2e1d, 0x2e1d,
+ 0x2e21, 0x2e21,
+}; /* CR_Pf */
+
+/* 'Pi': General Category */
+static const OnigCodePoint CR_Pi[] = {
+ 11,
+ 0x00ab, 0x00ab,
+ 0x2018, 0x2018,
+ 0x201b, 0x201c,
+ 0x201f, 0x201f,
+ 0x2039, 0x2039,
+ 0x2e02, 0x2e02,
+ 0x2e04, 0x2e04,
+ 0x2e09, 0x2e09,
+ 0x2e0c, 0x2e0c,
+ 0x2e1c, 0x2e1c,
+ 0x2e20, 0x2e20,
+}; /* CR_Pi */
+
+/* 'Po': General Category */
+static const OnigCodePoint CR_Po[] = {
+ 194,
+ 0x0021, 0x0023,
+ 0x0025, 0x0027,
+ 0x002a, 0x002a,
+ 0x002c, 0x002c,
+ 0x002e, 0x002f,
+ 0x003a, 0x003b,
+ 0x003f, 0x0040,
+ 0x005c, 0x005c,
+ 0x00a1, 0x00a1,
+ 0x00a7, 0x00a7,
+ 0x00b6, 0x00b7,
+ 0x00bf, 0x00bf,
+ 0x037e, 0x037e,
+ 0x0387, 0x0387,
+ 0x055a, 0x055f,
+ 0x0589, 0x0589,
+ 0x05c0, 0x05c0,
+ 0x05c3, 0x05c3,
+ 0x05c6, 0x05c6,
+ 0x05f3, 0x05f4,
+ 0x0609, 0x060a,
+ 0x060c, 0x060d,
+ 0x061b, 0x061b,
+ 0x061d, 0x061f,
+ 0x066a, 0x066d,
+ 0x06d4, 0x06d4,
+ 0x0700, 0x070d,
+ 0x07f7, 0x07f9,
+ 0x0830, 0x083e,
+ 0x085e, 0x085e,
+ 0x0964, 0x0965,
+ 0x0970, 0x0970,
+ 0x09fd, 0x09fd,
+ 0x0a76, 0x0a76,
+ 0x0af0, 0x0af0,
+ 0x0c77, 0x0c77,
+ 0x0c84, 0x0c84,
+ 0x0df4, 0x0df4,
+ 0x0e4f, 0x0e4f,
+ 0x0e5a, 0x0e5b,
+ 0x0f04, 0x0f12,
+ 0x0f14, 0x0f14,
+ 0x0f85, 0x0f85,
+ 0x0fd0, 0x0fd4,
+ 0x0fd9, 0x0fda,
+ 0x104a, 0x104f,
+ 0x10fb, 0x10fb,
+ 0x1360, 0x1368,
+ 0x166e, 0x166e,
+ 0x16eb, 0x16ed,
+ 0x1735, 0x1736,
+ 0x17d4, 0x17d6,
+ 0x17d8, 0x17da,
+ 0x1800, 0x1805,
+ 0x1807, 0x180a,
+ 0x1944, 0x1945,
+ 0x1a1e, 0x1a1f,
+ 0x1aa0, 0x1aa6,
+ 0x1aa8, 0x1aad,
+ 0x1b4e, 0x1b4f,
+ 0x1b5a, 0x1b60,
+ 0x1b7d, 0x1b7f,
+ 0x1bfc, 0x1bff,
+ 0x1c3b, 0x1c3f,
+ 0x1c7e, 0x1c7f,
+ 0x1cc0, 0x1cc7,
+ 0x1cd3, 0x1cd3,
+ 0x2016, 0x2017,
+ 0x2020, 0x2027,
+ 0x2030, 0x2038,
+ 0x203b, 0x203e,
+ 0x2041, 0x2043,
+ 0x2047, 0x2051,
+ 0x2053, 0x2053,
+ 0x2055, 0x205e,
+ 0x2cf9, 0x2cfc,
+ 0x2cfe, 0x2cff,
+ 0x2d70, 0x2d70,
+ 0x2e00, 0x2e01,
+ 0x2e06, 0x2e08,
+ 0x2e0b, 0x2e0b,
+ 0x2e0e, 0x2e16,
+ 0x2e18, 0x2e19,
+ 0x2e1b, 0x2e1b,
+ 0x2e1e, 0x2e1f,
+ 0x2e2a, 0x2e2e,
+ 0x2e30, 0x2e39,
+ 0x2e3c, 0x2e3f,
+ 0x2e41, 0x2e41,
+ 0x2e43, 0x2e4f,
+ 0x2e52, 0x2e54,
+ 0x3001, 0x3003,
+ 0x303d, 0x303d,
+ 0x30fb, 0x30fb,
+ 0xa4fe, 0xa4ff,
+ 0xa60d, 0xa60f,
+ 0xa673, 0xa673,
+ 0xa67e, 0xa67e,
+ 0xa6f2, 0xa6f7,
+ 0xa874, 0xa877,
+ 0xa8ce, 0xa8cf,
+ 0xa8f8, 0xa8fa,
+ 0xa8fc, 0xa8fc,
+ 0xa92e, 0xa92f,
+ 0xa95f, 0xa95f,
+ 0xa9c1, 0xa9cd,
+ 0xa9de, 0xa9df,
+ 0xaa5c, 0xaa5f,
+ 0xaade, 0xaadf,
+ 0xaaf0, 0xaaf1,
+ 0xabeb, 0xabeb,
+ 0xfe10, 0xfe16,
+ 0xfe19, 0xfe19,
+ 0xfe30, 0xfe30,
+ 0xfe45, 0xfe46,
+ 0xfe49, 0xfe4c,
+ 0xfe50, 0xfe52,
+ 0xfe54, 0xfe57,
+ 0xfe5f, 0xfe61,
+ 0xfe68, 0xfe68,
+ 0xfe6a, 0xfe6b,
+ 0xff01, 0xff03,
+ 0xff05, 0xff07,
+ 0xff0a, 0xff0a,
+ 0xff0c, 0xff0c,
+ 0xff0e, 0xff0f,
+ 0xff1a, 0xff1b,
+ 0xff1f, 0xff20,
+ 0xff3c, 0xff3c,
+ 0xff61, 0xff61,
+ 0xff64, 0xff65,
+ 0x10100, 0x10102,
+ 0x1039f, 0x1039f,
+ 0x103d0, 0x103d0,
+ 0x1056f, 0x1056f,
+ 0x10857, 0x10857,
+ 0x1091f, 0x1091f,
+ 0x1093f, 0x1093f,
+ 0x10a50, 0x10a58,
+ 0x10a7f, 0x10a7f,
+ 0x10af0, 0x10af6,
+ 0x10b39, 0x10b3f,
+ 0x10b99, 0x10b9c,
+ 0x10ed0, 0x10ed0,
+ 0x10f55, 0x10f59,
+ 0x10f86, 0x10f89,
+ 0x11047, 0x1104d,
+ 0x110bb, 0x110bc,
+ 0x110be, 0x110c1,
+ 0x11140, 0x11143,
+ 0x11174, 0x11175,
+ 0x111c5, 0x111c8,
+ 0x111cd, 0x111cd,
+ 0x111db, 0x111db,
+ 0x111dd, 0x111df,
+ 0x11238, 0x1123d,
+ 0x112a9, 0x112a9,
+ 0x113d4, 0x113d5,
+ 0x113d7, 0x113d8,
+ 0x1144b, 0x1144f,
+ 0x1145a, 0x1145b,
+ 0x1145d, 0x1145d,
+ 0x114c6, 0x114c6,
+ 0x115c1, 0x115d7,
+ 0x11641, 0x11643,
+ 0x11660, 0x1166c,
+ 0x116b9, 0x116b9,
+ 0x1173c, 0x1173e,
+ 0x1183b, 0x1183b,
+ 0x11944, 0x11946,
+ 0x119e2, 0x119e2,
+ 0x11a3f, 0x11a46,
+ 0x11a9a, 0x11a9c,
+ 0x11a9e, 0x11aa2,
+ 0x11b00, 0x11b09,
+ 0x11be1, 0x11be1,
+ 0x11c41, 0x11c45,
+ 0x11c70, 0x11c71,
+ 0x11ef7, 0x11ef8,
+ 0x11f43, 0x11f4f,
+ 0x11fff, 0x11fff,
+ 0x12470, 0x12474,
+ 0x12ff1, 0x12ff2,
+ 0x16a6e, 0x16a6f,
+ 0x16af5, 0x16af5,
+ 0x16b37, 0x16b3b,
+ 0x16b44, 0x16b44,
+ 0x16d6d, 0x16d6f,
+ 0x16e97, 0x16e9a,
+ 0x16fe2, 0x16fe2,
+ 0x1bc9f, 0x1bc9f,
+ 0x1da87, 0x1da8b,
+ 0x1e5ff, 0x1e5ff,
+ 0x1e95e, 0x1e95f,
+}; /* CR_Po */
+
+/* 'Ps': General Category */
+static const OnigCodePoint CR_Ps[] = {
+ 79,
+ 0x0028, 0x0028,
+ 0x005b, 0x005b,
+ 0x007b, 0x007b,
+ 0x0f3a, 0x0f3a,
+ 0x0f3c, 0x0f3c,
+ 0x169b, 0x169b,
+ 0x201a, 0x201a,
+ 0x201e, 0x201e,
+ 0x2045, 0x2045,
+ 0x207d, 0x207d,
+ 0x208d, 0x208d,
+ 0x2308, 0x2308,
+ 0x230a, 0x230a,
+ 0x2329, 0x2329,
+ 0x2768, 0x2768,
+ 0x276a, 0x276a,
+ 0x276c, 0x276c,
+ 0x276e, 0x276e,
+ 0x2770, 0x2770,
+ 0x2772, 0x2772,
+ 0x2774, 0x2774,
+ 0x27c5, 0x27c5,
+ 0x27e6, 0x27e6,
+ 0x27e8, 0x27e8,
+ 0x27ea, 0x27ea,
+ 0x27ec, 0x27ec,
+ 0x27ee, 0x27ee,
+ 0x2983, 0x2983,
+ 0x2985, 0x2985,
+ 0x2987, 0x2987,
+ 0x2989, 0x2989,
+ 0x298b, 0x298b,
+ 0x298d, 0x298d,
+ 0x298f, 0x298f,
+ 0x2991, 0x2991,
+ 0x2993, 0x2993,
+ 0x2995, 0x2995,
+ 0x2997, 0x2997,
+ 0x29d8, 0x29d8,
+ 0x29da, 0x29da,
+ 0x29fc, 0x29fc,
+ 0x2e22, 0x2e22,
+ 0x2e24, 0x2e24,
+ 0x2e26, 0x2e26,
+ 0x2e28, 0x2e28,
+ 0x2e42, 0x2e42,
+ 0x2e55, 0x2e55,
+ 0x2e57, 0x2e57,
+ 0x2e59, 0x2e59,
+ 0x2e5b, 0x2e5b,
+ 0x3008, 0x3008,
+ 0x300a, 0x300a,
+ 0x300c, 0x300c,
+ 0x300e, 0x300e,
+ 0x3010, 0x3010,
+ 0x3014, 0x3014,
+ 0x3016, 0x3016,
+ 0x3018, 0x3018,
+ 0x301a, 0x301a,
+ 0x301d, 0x301d,
+ 0xfd3f, 0xfd3f,
+ 0xfe17, 0xfe17,
+ 0xfe35, 0xfe35,
+ 0xfe37, 0xfe37,
+ 0xfe39, 0xfe39,
+ 0xfe3b, 0xfe3b,
+ 0xfe3d, 0xfe3d,
+ 0xfe3f, 0xfe3f,
+ 0xfe41, 0xfe41,
+ 0xfe43, 0xfe43,
+ 0xfe47, 0xfe47,
+ 0xfe59, 0xfe59,
+ 0xfe5b, 0xfe5b,
+ 0xfe5d, 0xfe5d,
+ 0xff08, 0xff08,
+ 0xff3b, 0xff3b,
+ 0xff5b, 0xff5b,
+ 0xff5f, 0xff5f,
+ 0xff62, 0xff62,
+}; /* CR_Ps */
+
+/* 'S': Major Category */
+static const OnigCodePoint CR_S[] = {
+ 242,
+ 0x0024, 0x0024,
+ 0x002b, 0x002b,
+ 0x003c, 0x003e,
+ 0x005e, 0x005e,
+ 0x0060, 0x0060,
+ 0x007c, 0x007c,
+ 0x007e, 0x007e,
+ 0x00a2, 0x00a6,
+ 0x00a8, 0x00a9,
+ 0x00ac, 0x00ac,
+ 0x00ae, 0x00b1,
+ 0x00b4, 0x00b4,
+ 0x00b8, 0x00b8,
+ 0x00d7, 0x00d7,
+ 0x00f7, 0x00f7,
+ 0x02c2, 0x02c5,
+ 0x02d2, 0x02df,
+ 0x02e5, 0x02eb,
+ 0x02ed, 0x02ed,
+ 0x02ef, 0x02ff,
+ 0x0375, 0x0375,
+ 0x0384, 0x0385,
+ 0x03f6, 0x03f6,
+ 0x0482, 0x0482,
+ 0x058d, 0x058f,
+ 0x0606, 0x0608,
+ 0x060b, 0x060b,
+ 0x060e, 0x060f,
+ 0x06de, 0x06de,
+ 0x06e9, 0x06e9,
+ 0x06fd, 0x06fe,
+ 0x07f6, 0x07f6,
+ 0x07fe, 0x07ff,
+ 0x0888, 0x0888,
+ 0x09f2, 0x09f3,
+ 0x09fa, 0x09fb,
+ 0x0af1, 0x0af1,
+ 0x0b70, 0x0b70,
+ 0x0bf3, 0x0bfa,
+ 0x0c7f, 0x0c7f,
+ 0x0d4f, 0x0d4f,
+ 0x0d79, 0x0d79,
+ 0x0e3f, 0x0e3f,
+ 0x0f01, 0x0f03,
+ 0x0f13, 0x0f13,
+ 0x0f15, 0x0f17,
+ 0x0f1a, 0x0f1f,
+ 0x0f34, 0x0f34,
+ 0x0f36, 0x0f36,
+ 0x0f38, 0x0f38,
+ 0x0fbe, 0x0fc5,
+ 0x0fc7, 0x0fcc,
+ 0x0fce, 0x0fcf,
+ 0x0fd5, 0x0fd8,
+ 0x109e, 0x109f,
+ 0x1390, 0x1399,
+ 0x166d, 0x166d,
+ 0x17db, 0x17db,
+ 0x1940, 0x1940,
+ 0x19de, 0x19ff,
+ 0x1b61, 0x1b6a,
+ 0x1b74, 0x1b7c,
+ 0x1fbd, 0x1fbd,
+ 0x1fbf, 0x1fc1,
+ 0x1fcd, 0x1fcf,
+ 0x1fdd, 0x1fdf,
+ 0x1fed, 0x1fef,
+ 0x1ffd, 0x1ffe,
+ 0x2044, 0x2044,
+ 0x2052, 0x2052,
+ 0x207a, 0x207c,
+ 0x208a, 0x208c,
+ 0x20a0, 0x20c1,
+ 0x2100, 0x2101,
+ 0x2103, 0x2106,
+ 0x2108, 0x2109,
+ 0x2114, 0x2114,
+ 0x2116, 0x2118,
+ 0x211e, 0x2123,
+ 0x2125, 0x2125,
+ 0x2127, 0x2127,
+ 0x2129, 0x2129,
+ 0x212e, 0x212e,
+ 0x213a, 0x213b,
+ 0x2140, 0x2144,
+ 0x214a, 0x214d,
+ 0x214f, 0x214f,
+ 0x218a, 0x218b,
+ 0x2190, 0x2307,
+ 0x230c, 0x2328,
+ 0x232b, 0x2429,
+ 0x2440, 0x244a,
+ 0x249c, 0x24e9,
+ 0x2500, 0x2767,
+ 0x2794, 0x27c4,
+ 0x27c7, 0x27e5,
+ 0x27f0, 0x2982,
+ 0x2999, 0x29d7,
+ 0x29dc, 0x29fb,
+ 0x29fe, 0x2b73,
+ 0x2b76, 0x2bff,
+ 0x2ce5, 0x2cea,
+ 0x2e50, 0x2e51,
+ 0x2e80, 0x2e99,
+ 0x2e9b, 0x2ef3,
+ 0x2f00, 0x2fd5,
+ 0x2ff0, 0x2fff,
+ 0x3004, 0x3004,
+ 0x3012, 0x3013,
+ 0x3020, 0x3020,
+ 0x3036, 0x3037,
+ 0x303e, 0x303f,
+ 0x309b, 0x309c,
+ 0x3190, 0x3191,
+ 0x3196, 0x319f,
+ 0x31c0, 0x31e5,
+ 0x31ef, 0x31ef,
+ 0x3200, 0x321e,
+ 0x322a, 0x3247,
+ 0x3250, 0x3250,
+ 0x3260, 0x327f,
+ 0x328a, 0x32b0,
+ 0x32c0, 0x33ff,
+ 0x4dc0, 0x4dff,
+ 0xa490, 0xa4c6,
+ 0xa700, 0xa716,
+ 0xa720, 0xa721,
+ 0xa789, 0xa78a,
+ 0xa828, 0xa82b,
+ 0xa836, 0xa839,
+ 0xaa77, 0xaa79,
+ 0xab5b, 0xab5b,
+ 0xab6a, 0xab6b,
+ 0xfb29, 0xfb29,
+ 0xfbb2, 0xfbd2,
+ 0xfd40, 0xfd4f,
+ 0xfd90, 0xfd91,
+ 0xfdc8, 0xfdcf,
+ 0xfdfc, 0xfdff,
+ 0xfe62, 0xfe62,
+ 0xfe64, 0xfe66,
+ 0xfe69, 0xfe69,
+ 0xff04, 0xff04,
+ 0xff0b, 0xff0b,
+ 0xff1c, 0xff1e,
+ 0xff3e, 0xff3e,
+ 0xff40, 0xff40,
+ 0xff5c, 0xff5c,
+ 0xff5e, 0xff5e,
+ 0xffe0, 0xffe6,
+ 0xffe8, 0xffee,
+ 0xfffc, 0xfffd,
+ 0x10137, 0x1013f,
+ 0x10179, 0x10189,
+ 0x1018c, 0x1018e,
+ 0x10190, 0x1019c,
+ 0x101a0, 0x101a0,
+ 0x101d0, 0x101fc,
+ 0x10877, 0x10878,
+ 0x10ac8, 0x10ac8,
+ 0x10d8e, 0x10d8f,
+ 0x10ed1, 0x10ed8,
+ 0x1173f, 0x1173f,
+ 0x11fd5, 0x11ff1,
+ 0x16b3c, 0x16b3f,
+ 0x16b45, 0x16b45,
+ 0x1bc9c, 0x1bc9c,
+ 0x1cc00, 0x1ccef,
+ 0x1ccfa, 0x1ccfc,
+ 0x1cd00, 0x1ceb3,
+ 0x1ceba, 0x1ced0,
+ 0x1cee0, 0x1cef0,
+ 0x1cf50, 0x1cfc3,
+ 0x1d000, 0x1d0f5,
+ 0x1d100, 0x1d126,
+ 0x1d129, 0x1d164,
+ 0x1d16a, 0x1d16c,
+ 0x1d183, 0x1d184,
+ 0x1d18c, 0x1d1a9,
+ 0x1d1ae, 0x1d1ea,
+ 0x1d200, 0x1d241,
+ 0x1d245, 0x1d245,
+ 0x1d300, 0x1d356,
+ 0x1d6c1, 0x1d6c1,
+ 0x1d6db, 0x1d6db,
+ 0x1d6fb, 0x1d6fb,
+ 0x1d715, 0x1d715,
+ 0x1d735, 0x1d735,
+ 0x1d74f, 0x1d74f,
+ 0x1d76f, 0x1d76f,
+ 0x1d789, 0x1d789,
+ 0x1d7a9, 0x1d7a9,
+ 0x1d7c3, 0x1d7c3,
+ 0x1d800, 0x1d9ff,
+ 0x1da37, 0x1da3a,
+ 0x1da6d, 0x1da74,
+ 0x1da76, 0x1da83,
+ 0x1da85, 0x1da86,
+ 0x1e14f, 0x1e14f,
+ 0x1e2ff, 0x1e2ff,
+ 0x1ecac, 0x1ecac,
+ 0x1ecb0, 0x1ecb0,
+ 0x1ed2e, 0x1ed2e,
+ 0x1eef0, 0x1eef1,
+ 0x1f000, 0x1f02b,
+ 0x1f030, 0x1f093,
+ 0x1f0a0, 0x1f0ae,
+ 0x1f0b1, 0x1f0bf,
+ 0x1f0c1, 0x1f0cf,
+ 0x1f0d1, 0x1f0f5,
+ 0x1f10d, 0x1f1ad,
+ 0x1f1e6, 0x1f202,
+ 0x1f210, 0x1f23b,
+ 0x1f240, 0x1f248,
+ 0x1f250, 0x1f251,
+ 0x1f260, 0x1f265,
+ 0x1f300, 0x1f6d8,
+ 0x1f6dc, 0x1f6ec,
+ 0x1f6f0, 0x1f6fc,
+ 0x1f700, 0x1f7d9,
+ 0x1f7e0, 0x1f7eb,
+ 0x1f7f0, 0x1f7f0,
+ 0x1f800, 0x1f80b,
+ 0x1f810, 0x1f847,
+ 0x1f850, 0x1f859,
+ 0x1f860, 0x1f887,
+ 0x1f890, 0x1f8ad,
+ 0x1f8b0, 0x1f8bb,
+ 0x1f8c0, 0x1f8c1,
+ 0x1f8d0, 0x1f8d8,
+ 0x1f900, 0x1fa57,
+ 0x1fa60, 0x1fa6d,
+ 0x1fa70, 0x1fa7c,
+ 0x1fa80, 0x1fa8a,
+ 0x1fa8e, 0x1fac6,
+ 0x1fac8, 0x1fac8,
+ 0x1facd, 0x1fadc,
+ 0x1fadf, 0x1faea,
+ 0x1faef, 0x1faf8,
+ 0x1fb00, 0x1fb92,
+ 0x1fb94, 0x1fbef,
+ 0x1fbfa, 0x1fbfa,
+}; /* CR_S */
+
+/* 'Sc': General Category */
+static const OnigCodePoint CR_Sc[] = {
+ 21,
+ 0x0024, 0x0024,
+ 0x00a2, 0x00a5,
+ 0x058f, 0x058f,
+ 0x060b, 0x060b,
+ 0x07fe, 0x07ff,
+ 0x09f2, 0x09f3,
+ 0x09fb, 0x09fb,
+ 0x0af1, 0x0af1,
+ 0x0bf9, 0x0bf9,
+ 0x0e3f, 0x0e3f,
+ 0x17db, 0x17db,
+ 0x20a0, 0x20c1,
+ 0xa838, 0xa838,
+ 0xfdfc, 0xfdfc,
+ 0xfe69, 0xfe69,
+ 0xff04, 0xff04,
+ 0xffe0, 0xffe1,
+ 0xffe5, 0xffe6,
+ 0x11fdd, 0x11fe0,
+ 0x1e2ff, 0x1e2ff,
+ 0x1ecb0, 0x1ecb0,
+}; /* CR_Sc */
+
+/* 'Sk': General Category */
+static const OnigCodePoint CR_Sk[] = {
+ 31,
+ 0x005e, 0x005e,
+ 0x0060, 0x0060,
+ 0x00a8, 0x00a8,
+ 0x00af, 0x00af,
+ 0x00b4, 0x00b4,
+ 0x00b8, 0x00b8,
+ 0x02c2, 0x02c5,
+ 0x02d2, 0x02df,
+ 0x02e5, 0x02eb,
+ 0x02ed, 0x02ed,
+ 0x02ef, 0x02ff,
+ 0x0375, 0x0375,
+ 0x0384, 0x0385,
+ 0x0888, 0x0888,
+ 0x1fbd, 0x1fbd,
+ 0x1fbf, 0x1fc1,
+ 0x1fcd, 0x1fcf,
+ 0x1fdd, 0x1fdf,
+ 0x1fed, 0x1fef,
+ 0x1ffd, 0x1ffe,
+ 0x309b, 0x309c,
+ 0xa700, 0xa716,
+ 0xa720, 0xa721,
+ 0xa789, 0xa78a,
+ 0xab5b, 0xab5b,
+ 0xab6a, 0xab6b,
+ 0xfbb2, 0xfbc2,
+ 0xff3e, 0xff3e,
+ 0xff40, 0xff40,
+ 0xffe3, 0xffe3,
+ 0x1f3fb, 0x1f3ff,
+}; /* CR_Sk */
+
+/* 'Sm': General Category */
+static const OnigCodePoint CR_Sm[] = {
+ 67,
+ 0x002b, 0x002b,
+ 0x003c, 0x003e,
+ 0x007c, 0x007c,
+ 0x007e, 0x007e,
+ 0x00ac, 0x00ac,
+ 0x00b1, 0x00b1,
+ 0x00d7, 0x00d7,
+ 0x00f7, 0x00f7,
+ 0x03f6, 0x03f6,
+ 0x0606, 0x0608,
+ 0x2044, 0x2044,
+ 0x2052, 0x2052,
+ 0x207a, 0x207c,
+ 0x208a, 0x208c,
+ 0x2118, 0x2118,
+ 0x2140, 0x2144,
+ 0x214b, 0x214b,
+ 0x2190, 0x2194,
+ 0x219a, 0x219b,
+ 0x21a0, 0x21a0,
+ 0x21a3, 0x21a3,
+ 0x21a6, 0x21a6,
+ 0x21ae, 0x21ae,
+ 0x21ce, 0x21cf,
+ 0x21d2, 0x21d2,
+ 0x21d4, 0x21d4,
+ 0x21f4, 0x22ff,
+ 0x2320, 0x2321,
+ 0x237c, 0x237c,
+ 0x239b, 0x23b3,
+ 0x23dc, 0x23e1,
+ 0x25b7, 0x25b7,
+ 0x25c1, 0x25c1,
+ 0x25f8, 0x25ff,
+ 0x266f, 0x266f,
+ 0x27c0, 0x27c4,
+ 0x27c7, 0x27e5,
+ 0x27f0, 0x27ff,
+ 0x2900, 0x2982,
+ 0x2999, 0x29d7,
+ 0x29dc, 0x29fb,
+ 0x29fe, 0x2aff,
+ 0x2b30, 0x2b44,
+ 0x2b47, 0x2b4c,
+ 0xfb29, 0xfb29,
+ 0xfe62, 0xfe62,
+ 0xfe64, 0xfe66,
+ 0xff0b, 0xff0b,
+ 0xff1c, 0xff1e,
+ 0xff5c, 0xff5c,
+ 0xff5e, 0xff5e,
+ 0xffe2, 0xffe2,
+ 0xffe9, 0xffec,
+ 0x10d8e, 0x10d8f,
+ 0x1cef0, 0x1cef0,
+ 0x1d6c1, 0x1d6c1,
+ 0x1d6db, 0x1d6db,
+ 0x1d6fb, 0x1d6fb,
+ 0x1d715, 0x1d715,
+ 0x1d735, 0x1d735,
+ 0x1d74f, 0x1d74f,
+ 0x1d76f, 0x1d76f,
+ 0x1d789, 0x1d789,
+ 0x1d7a9, 0x1d7a9,
+ 0x1d7c3, 0x1d7c3,
+ 0x1eef0, 0x1eef1,
+ 0x1f8d0, 0x1f8d8,
+}; /* CR_Sm */
+
+/* 'So': General Category */
+static const OnigCodePoint CR_So[] = {
+ 193,
+ 0x00a6, 0x00a6,
+ 0x00a9, 0x00a9,
+ 0x00ae, 0x00ae,
+ 0x00b0, 0x00b0,
+ 0x0482, 0x0482,
+ 0x058d, 0x058e,
+ 0x060e, 0x060f,
+ 0x06de, 0x06de,
+ 0x06e9, 0x06e9,
+ 0x06fd, 0x06fe,
+ 0x07f6, 0x07f6,
+ 0x09fa, 0x09fa,
+ 0x0b70, 0x0b70,
+ 0x0bf3, 0x0bf8,
+ 0x0bfa, 0x0bfa,
+ 0x0c7f, 0x0c7f,
+ 0x0d4f, 0x0d4f,
+ 0x0d79, 0x0d79,
+ 0x0f01, 0x0f03,
+ 0x0f13, 0x0f13,
+ 0x0f15, 0x0f17,
+ 0x0f1a, 0x0f1f,
+ 0x0f34, 0x0f34,
+ 0x0f36, 0x0f36,
+ 0x0f38, 0x0f38,
+ 0x0fbe, 0x0fc5,
+ 0x0fc7, 0x0fcc,
+ 0x0fce, 0x0fcf,
+ 0x0fd5, 0x0fd8,
+ 0x109e, 0x109f,
+ 0x1390, 0x1399,
+ 0x166d, 0x166d,
+ 0x1940, 0x1940,
+ 0x19de, 0x19ff,
+ 0x1b61, 0x1b6a,
+ 0x1b74, 0x1b7c,
+ 0x2100, 0x2101,
+ 0x2103, 0x2106,
+ 0x2108, 0x2109,
+ 0x2114, 0x2114,
+ 0x2116, 0x2117,
+ 0x211e, 0x2123,
+ 0x2125, 0x2125,
+ 0x2127, 0x2127,
+ 0x2129, 0x2129,
+ 0x212e, 0x212e,
+ 0x213a, 0x213b,
+ 0x214a, 0x214a,
+ 0x214c, 0x214d,
+ 0x214f, 0x214f,
+ 0x218a, 0x218b,
+ 0x2195, 0x2199,
+ 0x219c, 0x219f,
+ 0x21a1, 0x21a2,
+ 0x21a4, 0x21a5,
+ 0x21a7, 0x21ad,
+ 0x21af, 0x21cd,
+ 0x21d0, 0x21d1,
+ 0x21d3, 0x21d3,
+ 0x21d5, 0x21f3,
+ 0x2300, 0x2307,
+ 0x230c, 0x231f,
+ 0x2322, 0x2328,
+ 0x232b, 0x237b,
+ 0x237d, 0x239a,
+ 0x23b4, 0x23db,
+ 0x23e2, 0x2429,
+ 0x2440, 0x244a,
+ 0x249c, 0x24e9,
+ 0x2500, 0x25b6,
+ 0x25b8, 0x25c0,
+ 0x25c2, 0x25f7,
+ 0x2600, 0x266e,
+ 0x2670, 0x2767,
+ 0x2794, 0x27bf,
+ 0x2800, 0x28ff,
+ 0x2b00, 0x2b2f,
+ 0x2b45, 0x2b46,
+ 0x2b4d, 0x2b73,
+ 0x2b76, 0x2bff,
+ 0x2ce5, 0x2cea,
+ 0x2e50, 0x2e51,
+ 0x2e80, 0x2e99,
+ 0x2e9b, 0x2ef3,
+ 0x2f00, 0x2fd5,
+ 0x2ff0, 0x2fff,
+ 0x3004, 0x3004,
+ 0x3012, 0x3013,
+ 0x3020, 0x3020,
+ 0x3036, 0x3037,
+ 0x303e, 0x303f,
+ 0x3190, 0x3191,
+ 0x3196, 0x319f,
+ 0x31c0, 0x31e5,
+ 0x31ef, 0x31ef,
+ 0x3200, 0x321e,
+ 0x322a, 0x3247,
+ 0x3250, 0x3250,
+ 0x3260, 0x327f,
+ 0x328a, 0x32b0,
+ 0x32c0, 0x33ff,
+ 0x4dc0, 0x4dff,
+ 0xa490, 0xa4c6,
+ 0xa828, 0xa82b,
+ 0xa836, 0xa837,
+ 0xa839, 0xa839,
+ 0xaa77, 0xaa79,
+ 0xfbc3, 0xfbd2,
+ 0xfd40, 0xfd4f,
+ 0xfd90, 0xfd91,
+ 0xfdc8, 0xfdcf,
+ 0xfdfd, 0xfdff,
+ 0xffe4, 0xffe4,
+ 0xffe8, 0xffe8,
+ 0xffed, 0xffee,
+ 0xfffc, 0xfffd,
+ 0x10137, 0x1013f,
+ 0x10179, 0x10189,
+ 0x1018c, 0x1018e,
+ 0x10190, 0x1019c,
+ 0x101a0, 0x101a0,
+ 0x101d0, 0x101fc,
+ 0x10877, 0x10878,
+ 0x10ac8, 0x10ac8,
+ 0x10ed1, 0x10ed8,
+ 0x1173f, 0x1173f,
+ 0x11fd5, 0x11fdc,
+ 0x11fe1, 0x11ff1,
+ 0x16b3c, 0x16b3f,
+ 0x16b45, 0x16b45,
+ 0x1bc9c, 0x1bc9c,
+ 0x1cc00, 0x1ccef,
+ 0x1ccfa, 0x1ccfc,
+ 0x1cd00, 0x1ceb3,
+ 0x1ceba, 0x1ced0,
+ 0x1cee0, 0x1ceef,
+ 0x1cf50, 0x1cfc3,
+ 0x1d000, 0x1d0f5,
+ 0x1d100, 0x1d126,
+ 0x1d129, 0x1d164,
+ 0x1d16a, 0x1d16c,
+ 0x1d183, 0x1d184,
+ 0x1d18c, 0x1d1a9,
+ 0x1d1ae, 0x1d1ea,
+ 0x1d200, 0x1d241,
+ 0x1d245, 0x1d245,
+ 0x1d300, 0x1d356,
+ 0x1d800, 0x1d9ff,
+ 0x1da37, 0x1da3a,
+ 0x1da6d, 0x1da74,
+ 0x1da76, 0x1da83,
+ 0x1da85, 0x1da86,
+ 0x1e14f, 0x1e14f,
+ 0x1ecac, 0x1ecac,
+ 0x1ed2e, 0x1ed2e,
+ 0x1f000, 0x1f02b,
+ 0x1f030, 0x1f093,
+ 0x1f0a0, 0x1f0ae,
+ 0x1f0b1, 0x1f0bf,
+ 0x1f0c1, 0x1f0cf,
+ 0x1f0d1, 0x1f0f5,
+ 0x1f10d, 0x1f1ad,
+ 0x1f1e6, 0x1f202,
+ 0x1f210, 0x1f23b,
+ 0x1f240, 0x1f248,
+ 0x1f250, 0x1f251,
+ 0x1f260, 0x1f265,
+ 0x1f300, 0x1f3fa,
+ 0x1f400, 0x1f6d8,
+ 0x1f6dc, 0x1f6ec,
+ 0x1f6f0, 0x1f6fc,
+ 0x1f700, 0x1f7d9,
+ 0x1f7e0, 0x1f7eb,
+ 0x1f7f0, 0x1f7f0,
+ 0x1f800, 0x1f80b,
+ 0x1f810, 0x1f847,
+ 0x1f850, 0x1f859,
+ 0x1f860, 0x1f887,
+ 0x1f890, 0x1f8ad,
+ 0x1f8b0, 0x1f8bb,
+ 0x1f8c0, 0x1f8c1,
+ 0x1f900, 0x1fa57,
+ 0x1fa60, 0x1fa6d,
+ 0x1fa70, 0x1fa7c,
+ 0x1fa80, 0x1fa8a,
+ 0x1fa8e, 0x1fac6,
+ 0x1fac8, 0x1fac8,
+ 0x1facd, 0x1fadc,
+ 0x1fadf, 0x1faea,
+ 0x1faef, 0x1faf8,
+ 0x1fb00, 0x1fb92,
+ 0x1fb94, 0x1fbef,
+ 0x1fbfa, 0x1fbfa,
+}; /* CR_So */
+
+/* 'Z': Major Category */
+static const OnigCodePoint CR_Z[] = {
+ 8,
+ 0x0020, 0x0020,
+ 0x00a0, 0x00a0,
+ 0x1680, 0x1680,
+ 0x2000, 0x200a,
+ 0x2028, 0x2029,
+ 0x202f, 0x202f,
+ 0x205f, 0x205f,
+ 0x3000, 0x3000,
+}; /* CR_Z */
+
+/* 'Zl': General Category */
+static const OnigCodePoint CR_Zl[] = {
+ 1,
+ 0x2028, 0x2028,
+}; /* CR_Zl */
+
+/* 'Zp': General Category */
+static const OnigCodePoint CR_Zp[] = {
+ 1,
+ 0x2029, 0x2029,
+}; /* CR_Zp */
+
+/* 'Zs': General Category */
+static const OnigCodePoint CR_Zs[] = {
+ 7,
+ 0x0020, 0x0020,
+ 0x00a0, 0x00a0,
+ 0x1680, 0x1680,
+ 0x2000, 0x200a,
+ 0x202f, 0x202f,
+ 0x205f, 0x205f,
+ 0x3000, 0x3000,
+}; /* CR_Zs */
+
+/* 'Math': Derived Property */
+static const OnigCodePoint CR_Math[] = {
+ 141,
+ 0x002b, 0x002b,
+ 0x003c, 0x003e,
+ 0x005e, 0x005e,
+ 0x007c, 0x007c,
+ 0x007e, 0x007e,
+ 0x00ac, 0x00ac,
+ 0x00b1, 0x00b1,
+ 0x00d7, 0x00d7,
+ 0x00f7, 0x00f7,
+ 0x03d0, 0x03d2,
+ 0x03d5, 0x03d5,
+ 0x03f0, 0x03f1,
+ 0x03f4, 0x03f6,
+ 0x0606, 0x0608,
+ 0x2016, 0x2016,
+ 0x2032, 0x2034,
+ 0x2040, 0x2040,
+ 0x2044, 0x2044,
+ 0x2052, 0x2052,
+ 0x2061, 0x2064,
+ 0x207a, 0x207e,
+ 0x208a, 0x208e,
+ 0x20d0, 0x20dc,
+ 0x20e1, 0x20e1,
+ 0x20e5, 0x20e6,
+ 0x20eb, 0x20ef,
+ 0x2102, 0x2102,
+ 0x2107, 0x2107,
+ 0x210a, 0x2113,
+ 0x2115, 0x2115,
+ 0x2118, 0x211d,
+ 0x2124, 0x2124,
+ 0x2128, 0x2129,
+ 0x212c, 0x212d,
+ 0x212f, 0x2131,
+ 0x2133, 0x2138,
+ 0x213c, 0x2149,
+ 0x214b, 0x214b,
+ 0x2190, 0x21a7,
+ 0x21a9, 0x21ae,
+ 0x21b0, 0x21b1,
+ 0x21b6, 0x21b7,
+ 0x21bc, 0x21db,
+ 0x21dd, 0x21dd,
+ 0x21e4, 0x21e5,
+ 0x21f4, 0x22ff,
+ 0x2308, 0x230b,
+ 0x2320, 0x2321,
+ 0x237c, 0x237c,
+ 0x239b, 0x23b5,
+ 0x23b7, 0x23b7,
+ 0x23d0, 0x23d0,
+ 0x23dc, 0x23e2,
+ 0x25a0, 0x25a1,
+ 0x25ae, 0x25b7,
+ 0x25bc, 0x25c1,
+ 0x25c6, 0x25c7,
+ 0x25ca, 0x25cb,
+ 0x25cf, 0x25d3,
+ 0x25e2, 0x25e2,
+ 0x25e4, 0x25e4,
+ 0x25e7, 0x25ec,
+ 0x25f8, 0x25ff,
+ 0x2605, 0x2606,
+ 0x2640, 0x2640,
+ 0x2642, 0x2642,
+ 0x2660, 0x2663,
+ 0x266d, 0x266f,
+ 0x27c0, 0x27ff,
+ 0x2900, 0x2aff,
+ 0x2b30, 0x2b44,
+ 0x2b47, 0x2b4c,
+ 0xfb29, 0xfb29,
+ 0xfe61, 0xfe66,
+ 0xfe68, 0xfe68,
+ 0xff0b, 0xff0b,
+ 0xff1c, 0xff1e,
+ 0xff3c, 0xff3c,
+ 0xff3e, 0xff3e,
+ 0xff5c, 0xff5c,
+ 0xff5e, 0xff5e,
+ 0xffe2, 0xffe2,
+ 0xffe9, 0xffec,
+ 0x10d8e, 0x10d8f,
+ 0x1cef0, 0x1cef0,
+ 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, 0x1d7cb,
+ 0x1d7ce, 0x1d7ff,
+ 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,
+ 0x1eef0, 0x1eef1,
+ 0x1f8d0, 0x1f8d8,
+}; /* CR_Math */
+
+/* 'Alphabetic': Derived Property */
+#define CR_Alphabetic CR_Alpha
+
+/* 'Lowercase': Derived Property */
+#define CR_Lowercase CR_Lower
+
+/* 'Uppercase': Derived Property */
+#define CR_Uppercase CR_Upper
+
+/* 'Cased': Derived Property */
+static const OnigCodePoint CR_Cased[] = {
+ 158,
+ 0x0041, 0x005a,
+ 0x0061, 0x007a,
+ 0x00aa, 0x00aa,
+ 0x00b5, 0x00b5,
+ 0x00ba, 0x00ba,
+ 0x00c0, 0x00d6,
+ 0x00d8, 0x00f6,
+ 0x00f8, 0x01ba,
+ 0x01bc, 0x01bf,
+ 0x01c4, 0x0293,
+ 0x0296, 0x02b8,
+ 0x02c0, 0x02c1,
+ 0x02e0, 0x02e4,
+ 0x0345, 0x0345,
+ 0x0370, 0x0373,
+ 0x0376, 0x0377,
+ 0x037a, 0x037d,
+ 0x037f, 0x037f,
+ 0x0386, 0x0386,
+ 0x0388, 0x038a,
+ 0x038c, 0x038c,
+ 0x038e, 0x03a1,
+ 0x03a3, 0x03f5,
+ 0x03f7, 0x0481,
+ 0x048a, 0x052f,
+ 0x0531, 0x0556,
+ 0x0560, 0x0588,
+ 0x10a0, 0x10c5,
+ 0x10c7, 0x10c7,
+ 0x10cd, 0x10cd,
+ 0x10d0, 0x10fa,
+ 0x10fc, 0x10ff,
+ 0x13a0, 0x13f5,
+ 0x13f8, 0x13fd,
+ 0x1c80, 0x1c8a,
+ 0x1c90, 0x1cba,
+ 0x1cbd, 0x1cbf,
+ 0x1d00, 0x1dbf,
+ 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, 0x2134,
+ 0x2139, 0x2139,
+ 0x213c, 0x213f,
+ 0x2145, 0x2149,
+ 0x214e, 0x214e,
+ 0x2160, 0x217f,
+ 0x2183, 0x2184,
+ 0x24b6, 0x24e9,
+ 0x2c00, 0x2ce4,
+ 0x2ceb, 0x2cee,
+ 0x2cf2, 0x2cf3,
+ 0x2d00, 0x2d25,
+ 0x2d27, 0x2d27,
+ 0x2d2d, 0x2d2d,
+ 0xa640, 0xa66d,
+ 0xa680, 0xa69d,
+ 0xa722, 0xa787,
+ 0xa78b, 0xa78e,
+ 0xa790, 0xa7dc,
+ 0xa7f1, 0xa7f6,
+ 0xa7f8, 0xa7fa,
+ 0xab30, 0xab5a,
+ 0xab5c, 0xab69,
+ 0xab70, 0xabbf,
+ 0xfb00, 0xfb06,
+ 0xfb13, 0xfb17,
+ 0xff21, 0xff3a,
+ 0xff41, 0xff5a,
+ 0x10400, 0x1044f,
+ 0x104b0, 0x104d3,
+ 0x104d8, 0x104fb,
+ 0x10570, 0x1057a,
+ 0x1057c, 0x1058a,
+ 0x1058c, 0x10592,
+ 0x10594, 0x10595,
+ 0x10597, 0x105a1,
+ 0x105a3, 0x105b1,
+ 0x105b3, 0x105b9,
+ 0x105bb, 0x105bc,
+ 0x10780, 0x10780,
+ 0x10783, 0x10785,
+ 0x10787, 0x107b0,
+ 0x107b2, 0x107ba,
+ 0x10c80, 0x10cb2,
+ 0x10cc0, 0x10cf2,
+ 0x10d50, 0x10d65,
+ 0x10d70, 0x10d85,
+ 0x118a0, 0x118df,
+ 0x16e40, 0x16e7f,
+ 0x16ea0, 0x16eb8,
+ 0x16ebb, 0x16ed3,
+ 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, 0x1df09,
+ 0x1df0b, 0x1df1e,
+ 0x1df25, 0x1df2a,
+ 0x1e030, 0x1e06d,
+ 0x1e900, 0x1e943,
+ 0x1f130, 0x1f149,
+ 0x1f150, 0x1f169,
+ 0x1f170, 0x1f189,
+}; /* CR_Cased */
+
+/* 'Case_Ignorable': Derived Property */
+static const OnigCodePoint CR_Case_Ignorable[] = {
+ 464,
+ 0x0027, 0x0027,
+ 0x002e, 0x002e,
+ 0x003a, 0x003a,
+ 0x005e, 0x005e,
+ 0x0060, 0x0060,
+ 0x00a8, 0x00a8,
+ 0x00ad, 0x00ad,
+ 0x00af, 0x00af,
+ 0x00b4, 0x00b4,
+ 0x00b7, 0x00b8,
+ 0x02b0, 0x036f,
+ 0x0374, 0x0375,
+ 0x037a, 0x037a,
+ 0x0384, 0x0385,
+ 0x0387, 0x0387,
+ 0x0483, 0x0489,
+ 0x0559, 0x0559,
+ 0x055f, 0x055f,
+ 0x0591, 0x05bd,
+ 0x05bf, 0x05bf,
+ 0x05c1, 0x05c2,
+ 0x05c4, 0x05c5,
+ 0x05c7, 0x05c7,
+ 0x05f4, 0x05f4,
+ 0x0600, 0x0605,
+ 0x0610, 0x061a,
+ 0x061c, 0x061c,
+ 0x0640, 0x0640,
+ 0x064b, 0x065f,
+ 0x0670, 0x0670,
+ 0x06d6, 0x06dd,
+ 0x06df, 0x06e8,
+ 0x06ea, 0x06ed,
+ 0x070f, 0x070f,
+ 0x0711, 0x0711,
+ 0x0730, 0x074a,
+ 0x07a6, 0x07b0,
+ 0x07eb, 0x07f5,
+ 0x07fa, 0x07fa,
+ 0x07fd, 0x07fd,
+ 0x0816, 0x082d,
+ 0x0859, 0x085b,
+ 0x0888, 0x0888,
+ 0x0890, 0x0891,
+ 0x0897, 0x089f,
+ 0x08c9, 0x0902,
+ 0x093a, 0x093a,
+ 0x093c, 0x093c,
+ 0x0941, 0x0948,
+ 0x094d, 0x094d,
+ 0x0951, 0x0957,
+ 0x0962, 0x0963,
+ 0x0971, 0x0971,
+ 0x0981, 0x0981,
+ 0x09bc, 0x09bc,
+ 0x09c1, 0x09c4,
+ 0x09cd, 0x09cd,
+ 0x09e2, 0x09e3,
+ 0x09fe, 0x09fe,
+ 0x0a01, 0x0a02,
+ 0x0a3c, 0x0a3c,
+ 0x0a41, 0x0a42,
+ 0x0a47, 0x0a48,
+ 0x0a4b, 0x0a4d,
+ 0x0a51, 0x0a51,
+ 0x0a70, 0x0a71,
+ 0x0a75, 0x0a75,
+ 0x0a81, 0x0a82,
+ 0x0abc, 0x0abc,
+ 0x0ac1, 0x0ac5,
+ 0x0ac7, 0x0ac8,
+ 0x0acd, 0x0acd,
+ 0x0ae2, 0x0ae3,
+ 0x0afa, 0x0aff,
+ 0x0b01, 0x0b01,
+ 0x0b3c, 0x0b3c,
+ 0x0b3f, 0x0b3f,
+ 0x0b41, 0x0b44,
+ 0x0b4d, 0x0b4d,
+ 0x0b55, 0x0b56,
+ 0x0b62, 0x0b63,
+ 0x0b82, 0x0b82,
+ 0x0bc0, 0x0bc0,
+ 0x0bcd, 0x0bcd,
+ 0x0c00, 0x0c00,
+ 0x0c04, 0x0c04,
+ 0x0c3c, 0x0c3c,
+ 0x0c3e, 0x0c40,
+ 0x0c46, 0x0c48,
+ 0x0c4a, 0x0c4d,
+ 0x0c55, 0x0c56,
+ 0x0c62, 0x0c63,
+ 0x0c81, 0x0c81,
+ 0x0cbc, 0x0cbc,
+ 0x0cbf, 0x0cbf,
+ 0x0cc6, 0x0cc6,
+ 0x0ccc, 0x0ccd,
+ 0x0ce2, 0x0ce3,
+ 0x0d00, 0x0d01,
+ 0x0d3b, 0x0d3c,
+ 0x0d41, 0x0d44,
+ 0x0d4d, 0x0d4d,
+ 0x0d62, 0x0d63,
+ 0x0d81, 0x0d81,
+ 0x0dca, 0x0dca,
+ 0x0dd2, 0x0dd4,
+ 0x0dd6, 0x0dd6,
+ 0x0e31, 0x0e31,
+ 0x0e34, 0x0e3a,
+ 0x0e46, 0x0e4e,
+ 0x0eb1, 0x0eb1,
+ 0x0eb4, 0x0ebc,
+ 0x0ec6, 0x0ec6,
+ 0x0ec8, 0x0ece,
+ 0x0f18, 0x0f19,
+ 0x0f35, 0x0f35,
+ 0x0f37, 0x0f37,
+ 0x0f39, 0x0f39,
+ 0x0f71, 0x0f7e,
+ 0x0f80, 0x0f84,
+ 0x0f86, 0x0f87,
+ 0x0f8d, 0x0f97,
+ 0x0f99, 0x0fbc,
+ 0x0fc6, 0x0fc6,
+ 0x102d, 0x1030,
+ 0x1032, 0x1037,
+ 0x1039, 0x103a,
+ 0x103d, 0x103e,
+ 0x1058, 0x1059,
+ 0x105e, 0x1060,
+ 0x1071, 0x1074,
+ 0x1082, 0x1082,
+ 0x1085, 0x1086,
+ 0x108d, 0x108d,
+ 0x109d, 0x109d,
+ 0x10fc, 0x10fc,
+ 0x135d, 0x135f,
+ 0x1712, 0x1714,
+ 0x1732, 0x1733,
+ 0x1752, 0x1753,
+ 0x1772, 0x1773,
+ 0x17b4, 0x17b5,
+ 0x17b7, 0x17bd,
+ 0x17c6, 0x17c6,
+ 0x17c9, 0x17d3,
+ 0x17d7, 0x17d7,
+ 0x17dd, 0x17dd,
+ 0x180b, 0x180f,
+ 0x1843, 0x1843,
+ 0x1885, 0x1886,
+ 0x18a9, 0x18a9,
+ 0x1920, 0x1922,
+ 0x1927, 0x1928,
+ 0x1932, 0x1932,
+ 0x1939, 0x193b,
+ 0x1a17, 0x1a18,
+ 0x1a1b, 0x1a1b,
+ 0x1a56, 0x1a56,
+ 0x1a58, 0x1a5e,
+ 0x1a60, 0x1a60,
+ 0x1a62, 0x1a62,
+ 0x1a65, 0x1a6c,
+ 0x1a73, 0x1a7c,
+ 0x1a7f, 0x1a7f,
+ 0x1aa7, 0x1aa7,
+ 0x1ab0, 0x1add,
+ 0x1ae0, 0x1aeb,
+ 0x1b00, 0x1b03,
+ 0x1b34, 0x1b34,
+ 0x1b36, 0x1b3a,
+ 0x1b3c, 0x1b3c,
+ 0x1b42, 0x1b42,
+ 0x1b6b, 0x1b73,
+ 0x1b80, 0x1b81,
+ 0x1ba2, 0x1ba5,
+ 0x1ba8, 0x1ba9,
+ 0x1bab, 0x1bad,
+ 0x1be6, 0x1be6,
+ 0x1be8, 0x1be9,
+ 0x1bed, 0x1bed,
+ 0x1bef, 0x1bf1,
+ 0x1c2c, 0x1c33,
+ 0x1c36, 0x1c37,
+ 0x1c78, 0x1c7d,
+ 0x1cd0, 0x1cd2,
+ 0x1cd4, 0x1ce0,
+ 0x1ce2, 0x1ce8,
+ 0x1ced, 0x1ced,
+ 0x1cf4, 0x1cf4,
+ 0x1cf8, 0x1cf9,
+ 0x1d2c, 0x1d6a,
+ 0x1d78, 0x1d78,
+ 0x1d9b, 0x1dff,
+ 0x1fbd, 0x1fbd,
+ 0x1fbf, 0x1fc1,
+ 0x1fcd, 0x1fcf,
+ 0x1fdd, 0x1fdf,
+ 0x1fed, 0x1fef,
+ 0x1ffd, 0x1ffe,
+ 0x200b, 0x200f,
+ 0x2018, 0x2019,
+ 0x2024, 0x2024,
+ 0x2027, 0x2027,
+ 0x202a, 0x202e,
+ 0x2060, 0x2064,
+ 0x2066, 0x206f,
+ 0x2071, 0x2071,
+ 0x207f, 0x207f,
+ 0x2090, 0x209c,
+ 0x20d0, 0x20f0,
+ 0x2c7c, 0x2c7d,
+ 0x2cef, 0x2cf1,
+ 0x2d6f, 0x2d6f,
+ 0x2d7f, 0x2d7f,
+ 0x2de0, 0x2dff,
+ 0x2e2f, 0x2e2f,
+ 0x3005, 0x3005,
+ 0x302a, 0x302d,
+ 0x3031, 0x3035,
+ 0x303b, 0x303b,
+ 0x3099, 0x309e,
+ 0x30fc, 0x30fe,
+ 0xa015, 0xa015,
+ 0xa4f8, 0xa4fd,
+ 0xa60c, 0xa60c,
+ 0xa66f, 0xa672,
+ 0xa674, 0xa67d,
+ 0xa67f, 0xa67f,
+ 0xa69c, 0xa69f,
+ 0xa6f0, 0xa6f1,
+ 0xa700, 0xa721,
+ 0xa770, 0xa770,
+ 0xa788, 0xa78a,
+ 0xa7f1, 0xa7f4,
+ 0xa7f8, 0xa7f9,
+ 0xa802, 0xa802,
+ 0xa806, 0xa806,
+ 0xa80b, 0xa80b,
+ 0xa825, 0xa826,
+ 0xa82c, 0xa82c,
+ 0xa8c4, 0xa8c5,
+ 0xa8e0, 0xa8f1,
+ 0xa8ff, 0xa8ff,
+ 0xa926, 0xa92d,
+ 0xa947, 0xa951,
+ 0xa980, 0xa982,
+ 0xa9b3, 0xa9b3,
+ 0xa9b6, 0xa9b9,
+ 0xa9bc, 0xa9bd,
+ 0xa9cf, 0xa9cf,
+ 0xa9e5, 0xa9e6,
+ 0xaa29, 0xaa2e,
+ 0xaa31, 0xaa32,
+ 0xaa35, 0xaa36,
+ 0xaa43, 0xaa43,
+ 0xaa4c, 0xaa4c,
+ 0xaa70, 0xaa70,
+ 0xaa7c, 0xaa7c,
+ 0xaab0, 0xaab0,
+ 0xaab2, 0xaab4,
+ 0xaab7, 0xaab8,
+ 0xaabe, 0xaabf,
+ 0xaac1, 0xaac1,
+ 0xaadd, 0xaadd,
+ 0xaaec, 0xaaed,
+ 0xaaf3, 0xaaf4,
+ 0xaaf6, 0xaaf6,
+ 0xab5b, 0xab5f,
+ 0xab69, 0xab6b,
+ 0xabe5, 0xabe5,
+ 0xabe8, 0xabe8,
+ 0xabed, 0xabed,
+ 0xfb1e, 0xfb1e,
+ 0xfbb2, 0xfbc2,
+ 0xfe00, 0xfe0f,
+ 0xfe13, 0xfe13,
+ 0xfe20, 0xfe2f,
+ 0xfe52, 0xfe52,
+ 0xfe55, 0xfe55,
+ 0xfeff, 0xfeff,
+ 0xff07, 0xff07,
+ 0xff0e, 0xff0e,
+ 0xff1a, 0xff1a,
+ 0xff3e, 0xff3e,
+ 0xff40, 0xff40,
+ 0xff70, 0xff70,
+ 0xff9e, 0xff9f,
+ 0xffe3, 0xffe3,
+ 0xfff9, 0xfffb,
+ 0x101fd, 0x101fd,
+ 0x102e0, 0x102e0,
+ 0x10376, 0x1037a,
+ 0x10780, 0x10785,
+ 0x10787, 0x107b0,
+ 0x107b2, 0x107ba,
+ 0x10a01, 0x10a03,
+ 0x10a05, 0x10a06,
+ 0x10a0c, 0x10a0f,
+ 0x10a38, 0x10a3a,
+ 0x10a3f, 0x10a3f,
+ 0x10ae5, 0x10ae6,
+ 0x10d24, 0x10d27,
+ 0x10d4e, 0x10d4e,
+ 0x10d69, 0x10d6d,
+ 0x10d6f, 0x10d6f,
+ 0x10eab, 0x10eac,
+ 0x10ec5, 0x10ec5,
+ 0x10efa, 0x10eff,
+ 0x10f46, 0x10f50,
+ 0x10f82, 0x10f85,
+ 0x11001, 0x11001,
+ 0x11038, 0x11046,
+ 0x11070, 0x11070,
+ 0x11073, 0x11074,
+ 0x1107f, 0x11081,
+ 0x110b3, 0x110b6,
+ 0x110b9, 0x110ba,
+ 0x110bd, 0x110bd,
+ 0x110c2, 0x110c2,
+ 0x110cd, 0x110cd,
+ 0x11100, 0x11102,
+ 0x11127, 0x1112b,
+ 0x1112d, 0x11134,
+ 0x11173, 0x11173,
+ 0x11180, 0x11181,
+ 0x111b6, 0x111be,
+ 0x111c9, 0x111cc,
+ 0x111cf, 0x111cf,
+ 0x1122f, 0x11231,
+ 0x11234, 0x11234,
+ 0x11236, 0x11237,
+ 0x1123e, 0x1123e,
+ 0x11241, 0x11241,
+ 0x112df, 0x112df,
+ 0x112e3, 0x112ea,
+ 0x11300, 0x11301,
+ 0x1133b, 0x1133c,
+ 0x11340, 0x11340,
+ 0x11366, 0x1136c,
+ 0x11370, 0x11374,
+ 0x113bb, 0x113c0,
+ 0x113ce, 0x113ce,
+ 0x113d0, 0x113d0,
+ 0x113d2, 0x113d2,
+ 0x113e1, 0x113e2,
+ 0x11438, 0x1143f,
+ 0x11442, 0x11444,
+ 0x11446, 0x11446,
+ 0x1145e, 0x1145e,
+ 0x114b3, 0x114b8,
+ 0x114ba, 0x114ba,
+ 0x114bf, 0x114c0,
+ 0x114c2, 0x114c3,
+ 0x115b2, 0x115b5,
+ 0x115bc, 0x115bd,
+ 0x115bf, 0x115c0,
+ 0x115dc, 0x115dd,
+ 0x11633, 0x1163a,
+ 0x1163d, 0x1163d,
+ 0x1163f, 0x11640,
+ 0x116ab, 0x116ab,
+ 0x116ad, 0x116ad,
+ 0x116b0, 0x116b5,
+ 0x116b7, 0x116b7,
+ 0x1171d, 0x1171d,
+ 0x1171f, 0x1171f,
+ 0x11722, 0x11725,
+ 0x11727, 0x1172b,
+ 0x1182f, 0x11837,
+ 0x11839, 0x1183a,
+ 0x1193b, 0x1193c,
+ 0x1193e, 0x1193e,
+ 0x11943, 0x11943,
+ 0x119d4, 0x119d7,
+ 0x119da, 0x119db,
+ 0x119e0, 0x119e0,
+ 0x11a01, 0x11a0a,
+ 0x11a33, 0x11a38,
+ 0x11a3b, 0x11a3e,
+ 0x11a47, 0x11a47,
+ 0x11a51, 0x11a56,
+ 0x11a59, 0x11a5b,
+ 0x11a8a, 0x11a96,
+ 0x11a98, 0x11a99,
+ 0x11b60, 0x11b60,
+ 0x11b62, 0x11b64,
+ 0x11b66, 0x11b66,
+ 0x11c30, 0x11c36,
+ 0x11c38, 0x11c3d,
+ 0x11c3f, 0x11c3f,
+ 0x11c92, 0x11ca7,
+ 0x11caa, 0x11cb0,
+ 0x11cb2, 0x11cb3,
+ 0x11cb5, 0x11cb6,
+ 0x11d31, 0x11d36,
+ 0x11d3a, 0x11d3a,
+ 0x11d3c, 0x11d3d,
+ 0x11d3f, 0x11d45,
+ 0x11d47, 0x11d47,
+ 0x11d90, 0x11d91,
+ 0x11d95, 0x11d95,
+ 0x11d97, 0x11d97,
+ 0x11dd9, 0x11dd9,
+ 0x11ef3, 0x11ef4,
+ 0x11f00, 0x11f01,
+ 0x11f36, 0x11f3a,
+ 0x11f40, 0x11f40,
+ 0x11f42, 0x11f42,
+ 0x11f5a, 0x11f5a,
+ 0x13430, 0x13440,
+ 0x13447, 0x13455,
+ 0x1611e, 0x16129,
+ 0x1612d, 0x1612f,
+ 0x16af0, 0x16af4,
+ 0x16b30, 0x16b36,
+ 0x16b40, 0x16b43,
+ 0x16d40, 0x16d42,
+ 0x16d6b, 0x16d6c,
+ 0x16f4f, 0x16f4f,
+ 0x16f8f, 0x16f9f,
+ 0x16fe0, 0x16fe1,
+ 0x16fe3, 0x16fe4,
+ 0x16ff2, 0x16ff3,
+ 0x1aff0, 0x1aff3,
+ 0x1aff5, 0x1affb,
+ 0x1affd, 0x1affe,
+ 0x1bc9d, 0x1bc9e,
+ 0x1bca0, 0x1bca3,
+ 0x1cf00, 0x1cf2d,
+ 0x1cf30, 0x1cf46,
+ 0x1d167, 0x1d169,
+ 0x1d173, 0x1d182,
+ 0x1d185, 0x1d18b,
+ 0x1d1aa, 0x1d1ad,
+ 0x1d242, 0x1d244,
+ 0x1da00, 0x1da36,
+ 0x1da3b, 0x1da6c,
+ 0x1da75, 0x1da75,
+ 0x1da84, 0x1da84,
+ 0x1da9b, 0x1da9f,
+ 0x1daa1, 0x1daaf,
+ 0x1e000, 0x1e006,
+ 0x1e008, 0x1e018,
+ 0x1e01b, 0x1e021,
+ 0x1e023, 0x1e024,
+ 0x1e026, 0x1e02a,
+ 0x1e030, 0x1e06d,
+ 0x1e08f, 0x1e08f,
+ 0x1e130, 0x1e13d,
+ 0x1e2ae, 0x1e2ae,
+ 0x1e2ec, 0x1e2ef,
+ 0x1e4eb, 0x1e4ef,
+ 0x1e5ee, 0x1e5ef,
+ 0x1e6e3, 0x1e6e3,
+ 0x1e6e6, 0x1e6e6,
+ 0x1e6ee, 0x1e6ef,
+ 0x1e6f5, 0x1e6f5,
+ 0x1e6ff, 0x1e6ff,
+ 0x1e8d0, 0x1e8d6,
+ 0x1e944, 0x1e94b,
+ 0x1f3fb, 0x1f3ff,
+ 0xe0001, 0xe0001,
+ 0xe0020, 0xe007f,
+ 0xe0100, 0xe01ef,
+}; /* CR_Case_Ignorable */
+
+/* 'Changes_When_Lowercased': Derived Property */
+static const OnigCodePoint CR_Changes_When_Lowercased[] = {
+ 618,
+ 0x0041, 0x005a,
+ 0x00c0, 0x00d6,
+ 0x00d8, 0x00de,
+ 0x0100, 0x0100,
+ 0x0102, 0x0102,
+ 0x0104, 0x0104,
+ 0x0106, 0x0106,
+ 0x0108, 0x0108,
+ 0x010a, 0x010a,
+ 0x010c, 0x010c,
+ 0x010e, 0x010e,
+ 0x0110, 0x0110,
+ 0x0112, 0x0112,
+ 0x0114, 0x0114,
+ 0x0116, 0x0116,
+ 0x0118, 0x0118,
+ 0x011a, 0x011a,
+ 0x011c, 0x011c,
+ 0x011e, 0x011e,
+ 0x0120, 0x0120,
+ 0x0122, 0x0122,
+ 0x0124, 0x0124,
+ 0x0126, 0x0126,
+ 0x0128, 0x0128,
+ 0x012a, 0x012a,
+ 0x012c, 0x012c,
+ 0x012e, 0x012e,
+ 0x0130, 0x0130,
+ 0x0132, 0x0132,
+ 0x0134, 0x0134,
+ 0x0136, 0x0136,
+ 0x0139, 0x0139,
+ 0x013b, 0x013b,
+ 0x013d, 0x013d,
+ 0x013f, 0x013f,
+ 0x0141, 0x0141,
+ 0x0143, 0x0143,
+ 0x0145, 0x0145,
+ 0x0147, 0x0147,
+ 0x014a, 0x014a,
+ 0x014c, 0x014c,
+ 0x014e, 0x014e,
+ 0x0150, 0x0150,
+ 0x0152, 0x0152,
+ 0x0154, 0x0154,
+ 0x0156, 0x0156,
+ 0x0158, 0x0158,
+ 0x015a, 0x015a,
+ 0x015c, 0x015c,
+ 0x015e, 0x015e,
+ 0x0160, 0x0160,
+ 0x0162, 0x0162,
+ 0x0164, 0x0164,
+ 0x0166, 0x0166,
+ 0x0168, 0x0168,
+ 0x016a, 0x016a,
+ 0x016c, 0x016c,
+ 0x016e, 0x016e,
+ 0x0170, 0x0170,
+ 0x0172, 0x0172,
+ 0x0174, 0x0174,
+ 0x0176, 0x0176,
+ 0x0178, 0x0179,
+ 0x017b, 0x017b,
+ 0x017d, 0x017d,
+ 0x0181, 0x0182,
+ 0x0184, 0x0184,
+ 0x0186, 0x0187,
+ 0x0189, 0x018b,
+ 0x018e, 0x0191,
+ 0x0193, 0x0194,
+ 0x0196, 0x0198,
+ 0x019c, 0x019d,
+ 0x019f, 0x01a0,
+ 0x01a2, 0x01a2,
+ 0x01a4, 0x01a4,
+ 0x01a6, 0x01a7,
+ 0x01a9, 0x01a9,
+ 0x01ac, 0x01ac,
+ 0x01ae, 0x01af,
+ 0x01b1, 0x01b3,
+ 0x01b5, 0x01b5,
+ 0x01b7, 0x01b8,
+ 0x01bc, 0x01bc,
+ 0x01c4, 0x01c5,
+ 0x01c7, 0x01c8,
+ 0x01ca, 0x01cb,
+ 0x01cd, 0x01cd,
+ 0x01cf, 0x01cf,
+ 0x01d1, 0x01d1,
+ 0x01d3, 0x01d3,
+ 0x01d5, 0x01d5,
+ 0x01d7, 0x01d7,
+ 0x01d9, 0x01d9,
+ 0x01db, 0x01db,
+ 0x01de, 0x01de,
+ 0x01e0, 0x01e0,
+ 0x01e2, 0x01e2,
+ 0x01e4, 0x01e4,
+ 0x01e6, 0x01e6,
+ 0x01e8, 0x01e8,
+ 0x01ea, 0x01ea,
+ 0x01ec, 0x01ec,
+ 0x01ee, 0x01ee,
+ 0x01f1, 0x01f2,
+ 0x01f4, 0x01f4,
+ 0x01f6, 0x01f8,
+ 0x01fa, 0x01fa,
+ 0x01fc, 0x01fc,
+ 0x01fe, 0x01fe,
+ 0x0200, 0x0200,
+ 0x0202, 0x0202,
+ 0x0204, 0x0204,
+ 0x0206, 0x0206,
+ 0x0208, 0x0208,
+ 0x020a, 0x020a,
+ 0x020c, 0x020c,
+ 0x020e, 0x020e,
+ 0x0210, 0x0210,
+ 0x0212, 0x0212,
+ 0x0214, 0x0214,
+ 0x0216, 0x0216,
+ 0x0218, 0x0218,
+ 0x021a, 0x021a,
+ 0x021c, 0x021c,
+ 0x021e, 0x021e,
+ 0x0220, 0x0220,
+ 0x0222, 0x0222,
+ 0x0224, 0x0224,
+ 0x0226, 0x0226,
+ 0x0228, 0x0228,
+ 0x022a, 0x022a,
+ 0x022c, 0x022c,
+ 0x022e, 0x022e,
+ 0x0230, 0x0230,
+ 0x0232, 0x0232,
+ 0x023a, 0x023b,
+ 0x023d, 0x023e,
+ 0x0241, 0x0241,
+ 0x0243, 0x0246,
+ 0x0248, 0x0248,
+ 0x024a, 0x024a,
+ 0x024c, 0x024c,
+ 0x024e, 0x024e,
+ 0x0370, 0x0370,
+ 0x0372, 0x0372,
+ 0x0376, 0x0376,
+ 0x037f, 0x037f,
+ 0x0386, 0x0386,
+ 0x0388, 0x038a,
+ 0x038c, 0x038c,
+ 0x038e, 0x038f,
+ 0x0391, 0x03a1,
+ 0x03a3, 0x03ab,
+ 0x03cf, 0x03cf,
+ 0x03d8, 0x03d8,
+ 0x03da, 0x03da,
+ 0x03dc, 0x03dc,
+ 0x03de, 0x03de,
+ 0x03e0, 0x03e0,
+ 0x03e2, 0x03e2,
+ 0x03e4, 0x03e4,
+ 0x03e6, 0x03e6,
+ 0x03e8, 0x03e8,
+ 0x03ea, 0x03ea,
+ 0x03ec, 0x03ec,
+ 0x03ee, 0x03ee,
+ 0x03f4, 0x03f4,
+ 0x03f7, 0x03f7,
+ 0x03f9, 0x03fa,
+ 0x03fd, 0x042f,
+ 0x0460, 0x0460,
+ 0x0462, 0x0462,
+ 0x0464, 0x0464,
+ 0x0466, 0x0466,
+ 0x0468, 0x0468,
+ 0x046a, 0x046a,
+ 0x046c, 0x046c,
+ 0x046e, 0x046e,
+ 0x0470, 0x0470,
+ 0x0472, 0x0472,
+ 0x0474, 0x0474,
+ 0x0476, 0x0476,
+ 0x0478, 0x0478,
+ 0x047a, 0x047a,
+ 0x047c, 0x047c,
+ 0x047e, 0x047e,
+ 0x0480, 0x0480,
+ 0x048a, 0x048a,
+ 0x048c, 0x048c,
+ 0x048e, 0x048e,
+ 0x0490, 0x0490,
+ 0x0492, 0x0492,
+ 0x0494, 0x0494,
+ 0x0496, 0x0496,
+ 0x0498, 0x0498,
+ 0x049a, 0x049a,
+ 0x049c, 0x049c,
+ 0x049e, 0x049e,
+ 0x04a0, 0x04a0,
+ 0x04a2, 0x04a2,
+ 0x04a4, 0x04a4,
+ 0x04a6, 0x04a6,
+ 0x04a8, 0x04a8,
+ 0x04aa, 0x04aa,
+ 0x04ac, 0x04ac,
+ 0x04ae, 0x04ae,
+ 0x04b0, 0x04b0,
+ 0x04b2, 0x04b2,
+ 0x04b4, 0x04b4,
+ 0x04b6, 0x04b6,
+ 0x04b8, 0x04b8,
+ 0x04ba, 0x04ba,
+ 0x04bc, 0x04bc,
+ 0x04be, 0x04be,
+ 0x04c0, 0x04c1,
+ 0x04c3, 0x04c3,
+ 0x04c5, 0x04c5,
+ 0x04c7, 0x04c7,
+ 0x04c9, 0x04c9,
+ 0x04cb, 0x04cb,
+ 0x04cd, 0x04cd,
+ 0x04d0, 0x04d0,
+ 0x04d2, 0x04d2,
+ 0x04d4, 0x04d4,
+ 0x04d6, 0x04d6,
+ 0x04d8, 0x04d8,
+ 0x04da, 0x04da,
+ 0x04dc, 0x04dc,
+ 0x04de, 0x04de,
+ 0x04e0, 0x04e0,
+ 0x04e2, 0x04e2,
+ 0x04e4, 0x04e4,
+ 0x04e6, 0x04e6,
+ 0x04e8, 0x04e8,
+ 0x04ea, 0x04ea,
+ 0x04ec, 0x04ec,
+ 0x04ee, 0x04ee,
+ 0x04f0, 0x04f0,
+ 0x04f2, 0x04f2,
+ 0x04f4, 0x04f4,
+ 0x04f6, 0x04f6,
+ 0x04f8, 0x04f8,
+ 0x04fa, 0x04fa,
+ 0x04fc, 0x04fc,
+ 0x04fe, 0x04fe,
+ 0x0500, 0x0500,
+ 0x0502, 0x0502,
+ 0x0504, 0x0504,
+ 0x0506, 0x0506,
+ 0x0508, 0x0508,
+ 0x050a, 0x050a,
+ 0x050c, 0x050c,
+ 0x050e, 0x050e,
+ 0x0510, 0x0510,
+ 0x0512, 0x0512,
+ 0x0514, 0x0514,
+ 0x0516, 0x0516,
+ 0x0518, 0x0518,
+ 0x051a, 0x051a,
+ 0x051c, 0x051c,
+ 0x051e, 0x051e,
+ 0x0520, 0x0520,
+ 0x0522, 0x0522,
+ 0x0524, 0x0524,
+ 0x0526, 0x0526,
+ 0x0528, 0x0528,
+ 0x052a, 0x052a,
+ 0x052c, 0x052c,
+ 0x052e, 0x052e,
+ 0x0531, 0x0556,
+ 0x10a0, 0x10c5,
+ 0x10c7, 0x10c7,
+ 0x10cd, 0x10cd,
+ 0x13a0, 0x13f5,
+ 0x1c89, 0x1c89,
+ 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,
+ 0x2126, 0x2126,
+ 0x212a, 0x212b,
+ 0x2132, 0x2132,
+ 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,
+ 0xa7cb, 0xa7cc,
+ 0xa7ce, 0xa7ce,
+ 0xa7d0, 0xa7d0,
+ 0xa7d2, 0xa7d2,
+ 0xa7d4, 0xa7d4,
+ 0xa7d6, 0xa7d6,
+ 0xa7d8, 0xa7d8,
+ 0xa7da, 0xa7da,
+ 0xa7dc, 0xa7dc,
+ 0xa7f5, 0xa7f5,
+ 0xff21, 0xff3a,
+ 0x10400, 0x10427,
+ 0x104b0, 0x104d3,
+ 0x10570, 0x1057a,
+ 0x1057c, 0x1058a,
+ 0x1058c, 0x10592,
+ 0x10594, 0x10595,
+ 0x10c80, 0x10cb2,
+ 0x10d50, 0x10d65,
+ 0x118a0, 0x118bf,
+ 0x16e40, 0x16e5f,
+ 0x16ea0, 0x16eb8,
+ 0x1e900, 0x1e921,
+}; /* CR_Changes_When_Lowercased */
+
+/* 'Changes_When_Uppercased': Derived Property */
+static const OnigCodePoint CR_Changes_When_Uppercased[] = {
+ 634,
+ 0x0061, 0x007a,
+ 0x00b5, 0x00b5,
+ 0x00df, 0x00f6,
+ 0x00f8, 0x00ff,
+ 0x0101, 0x0101,
+ 0x0103, 0x0103,
+ 0x0105, 0x0105,
+ 0x0107, 0x0107,
+ 0x0109, 0x0109,
+ 0x010b, 0x010b,
+ 0x010d, 0x010d,
+ 0x010f, 0x010f,
+ 0x0111, 0x0111,
+ 0x0113, 0x0113,
+ 0x0115, 0x0115,
+ 0x0117, 0x0117,
+ 0x0119, 0x0119,
+ 0x011b, 0x011b,
+ 0x011d, 0x011d,
+ 0x011f, 0x011f,
+ 0x0121, 0x0121,
+ 0x0123, 0x0123,
+ 0x0125, 0x0125,
+ 0x0127, 0x0127,
+ 0x0129, 0x0129,
+ 0x012b, 0x012b,
+ 0x012d, 0x012d,
+ 0x012f, 0x012f,
+ 0x0131, 0x0131,
+ 0x0133, 0x0133,
+ 0x0135, 0x0135,
+ 0x0137, 0x0137,
+ 0x013a, 0x013a,
+ 0x013c, 0x013c,
+ 0x013e, 0x013e,
+ 0x0140, 0x0140,
+ 0x0142, 0x0142,
+ 0x0144, 0x0144,
+ 0x0146, 0x0146,
+ 0x0148, 0x0149,
+ 0x014b, 0x014b,
+ 0x014d, 0x014d,
+ 0x014f, 0x014f,
+ 0x0151, 0x0151,
+ 0x0153, 0x0153,
+ 0x0155, 0x0155,
+ 0x0157, 0x0157,
+ 0x0159, 0x0159,
+ 0x015b, 0x015b,
+ 0x015d, 0x015d,
+ 0x015f, 0x015f,
+ 0x0161, 0x0161,
+ 0x0163, 0x0163,
+ 0x0165, 0x0165,
+ 0x0167, 0x0167,
+ 0x0169, 0x0169,
+ 0x016b, 0x016b,
+ 0x016d, 0x016d,
+ 0x016f, 0x016f,
+ 0x0171, 0x0171,
+ 0x0173, 0x0173,
+ 0x0175, 0x0175,
+ 0x0177, 0x0177,
+ 0x017a, 0x017a,
+ 0x017c, 0x017c,
+ 0x017e, 0x0180,
+ 0x0183, 0x0183,
+ 0x0185, 0x0185,
+ 0x0188, 0x0188,
+ 0x018c, 0x018c,
+ 0x0192, 0x0192,
+ 0x0195, 0x0195,
+ 0x0199, 0x019b,
+ 0x019e, 0x019e,
+ 0x01a1, 0x01a1,
+ 0x01a3, 0x01a3,
+ 0x01a5, 0x01a5,
+ 0x01a8, 0x01a8,
+ 0x01ad, 0x01ad,
+ 0x01b0, 0x01b0,
+ 0x01b4, 0x01b4,
+ 0x01b6, 0x01b6,
+ 0x01b9, 0x01b9,
+ 0x01bd, 0x01bd,
+ 0x01bf, 0x01bf,
+ 0x01c5, 0x01c6,
+ 0x01c8, 0x01c9,
+ 0x01cb, 0x01cc,
+ 0x01ce, 0x01ce,
+ 0x01d0, 0x01d0,
+ 0x01d2, 0x01d2,
+ 0x01d4, 0x01d4,
+ 0x01d6, 0x01d6,
+ 0x01d8, 0x01d8,
+ 0x01da, 0x01da,
+ 0x01dc, 0x01dd,
+ 0x01df, 0x01df,
+ 0x01e1, 0x01e1,
+ 0x01e3, 0x01e3,
+ 0x01e5, 0x01e5,
+ 0x01e7, 0x01e7,
+ 0x01e9, 0x01e9,
+ 0x01eb, 0x01eb,
+ 0x01ed, 0x01ed,
+ 0x01ef, 0x01f0,
+ 0x01f2, 0x01f3,
+ 0x01f5, 0x01f5,
+ 0x01f9, 0x01f9,
+ 0x01fb, 0x01fb,
+ 0x01fd, 0x01fd,
+ 0x01ff, 0x01ff,
+ 0x0201, 0x0201,
+ 0x0203, 0x0203,
+ 0x0205, 0x0205,
+ 0x0207, 0x0207,
+ 0x0209, 0x0209,
+ 0x020b, 0x020b,
+ 0x020d, 0x020d,
+ 0x020f, 0x020f,
+ 0x0211, 0x0211,
+ 0x0213, 0x0213,
+ 0x0215, 0x0215,
+ 0x0217, 0x0217,
+ 0x0219, 0x0219,
+ 0x021b, 0x021b,
+ 0x021d, 0x021d,
+ 0x021f, 0x021f,
+ 0x0223, 0x0223,
+ 0x0225, 0x0225,
+ 0x0227, 0x0227,
+ 0x0229, 0x0229,
+ 0x022b, 0x022b,
+ 0x022d, 0x022d,
+ 0x022f, 0x022f,
+ 0x0231, 0x0231,
+ 0x0233, 0x0233,
+ 0x023c, 0x023c,
+ 0x023f, 0x0240,
+ 0x0242, 0x0242,
+ 0x0247, 0x0247,
+ 0x0249, 0x0249,
+ 0x024b, 0x024b,
+ 0x024d, 0x024d,
+ 0x024f, 0x0254,
+ 0x0256, 0x0257,
+ 0x0259, 0x0259,
+ 0x025b, 0x025c,
+ 0x0260, 0x0261,
+ 0x0263, 0x0266,
+ 0x0268, 0x026c,
+ 0x026f, 0x026f,
+ 0x0271, 0x0272,
+ 0x0275, 0x0275,
+ 0x027d, 0x027d,
+ 0x0280, 0x0280,
+ 0x0282, 0x0283,
+ 0x0287, 0x028c,
+ 0x0292, 0x0292,
+ 0x029d, 0x029e,
+ 0x0345, 0x0345,
+ 0x0371, 0x0371,
+ 0x0373, 0x0373,
+ 0x0377, 0x0377,
+ 0x037b, 0x037d,
+ 0x0390, 0x0390,
+ 0x03ac, 0x03ce,
+ 0x03d0, 0x03d1,
+ 0x03d5, 0x03d7,
+ 0x03d9, 0x03d9,
+ 0x03db, 0x03db,
+ 0x03dd, 0x03dd,
+ 0x03df, 0x03df,
+ 0x03e1, 0x03e1,
+ 0x03e3, 0x03e3,
+ 0x03e5, 0x03e5,
+ 0x03e7, 0x03e7,
+ 0x03e9, 0x03e9,
+ 0x03eb, 0x03eb,
+ 0x03ed, 0x03ed,
+ 0x03ef, 0x03f3,
+ 0x03f5, 0x03f5,
+ 0x03f8, 0x03f8,
+ 0x03fb, 0x03fb,
+ 0x0430, 0x045f,
+ 0x0461, 0x0461,
+ 0x0463, 0x0463,
+ 0x0465, 0x0465,
+ 0x0467, 0x0467,
+ 0x0469, 0x0469,
+ 0x046b, 0x046b,
+ 0x046d, 0x046d,
+ 0x046f, 0x046f,
+ 0x0471, 0x0471,
+ 0x0473, 0x0473,
+ 0x0475, 0x0475,
+ 0x0477, 0x0477,
+ 0x0479, 0x0479,
+ 0x047b, 0x047b,
+ 0x047d, 0x047d,
+ 0x047f, 0x047f,
+ 0x0481, 0x0481,
+ 0x048b, 0x048b,
+ 0x048d, 0x048d,
+ 0x048f, 0x048f,
+ 0x0491, 0x0491,
+ 0x0493, 0x0493,
+ 0x0495, 0x0495,
+ 0x0497, 0x0497,
+ 0x0499, 0x0499,
+ 0x049b, 0x049b,
+ 0x049d, 0x049d,
+ 0x049f, 0x049f,
+ 0x04a1, 0x04a1,
+ 0x04a3, 0x04a3,
+ 0x04a5, 0x04a5,
+ 0x04a7, 0x04a7,
+ 0x04a9, 0x04a9,
+ 0x04ab, 0x04ab,
+ 0x04ad, 0x04ad,
+ 0x04af, 0x04af,
+ 0x04b1, 0x04b1,
+ 0x04b3, 0x04b3,
+ 0x04b5, 0x04b5,
+ 0x04b7, 0x04b7,
+ 0x04b9, 0x04b9,
+ 0x04bb, 0x04bb,
+ 0x04bd, 0x04bd,
+ 0x04bf, 0x04bf,
+ 0x04c2, 0x04c2,
+ 0x04c4, 0x04c4,
+ 0x04c6, 0x04c6,
+ 0x04c8, 0x04c8,
+ 0x04ca, 0x04ca,
+ 0x04cc, 0x04cc,
+ 0x04ce, 0x04cf,
+ 0x04d1, 0x04d1,
+ 0x04d3, 0x04d3,
+ 0x04d5, 0x04d5,
+ 0x04d7, 0x04d7,
+ 0x04d9, 0x04d9,
+ 0x04db, 0x04db,
+ 0x04dd, 0x04dd,
+ 0x04df, 0x04df,
+ 0x04e1, 0x04e1,
+ 0x04e3, 0x04e3,
+ 0x04e5, 0x04e5,
+ 0x04e7, 0x04e7,
+ 0x04e9, 0x04e9,
+ 0x04eb, 0x04eb,
+ 0x04ed, 0x04ed,
+ 0x04ef, 0x04ef,
+ 0x04f1, 0x04f1,
+ 0x04f3, 0x04f3,
+ 0x04f5, 0x04f5,
+ 0x04f7, 0x04f7,
+ 0x04f9, 0x04f9,
+ 0x04fb, 0x04fb,
+ 0x04fd, 0x04fd,
+ 0x04ff, 0x04ff,
+ 0x0501, 0x0501,
+ 0x0503, 0x0503,
+ 0x0505, 0x0505,
+ 0x0507, 0x0507,
+ 0x0509, 0x0509,
+ 0x050b, 0x050b,
+ 0x050d, 0x050d,
+ 0x050f, 0x050f,
+ 0x0511, 0x0511,
+ 0x0513, 0x0513,
+ 0x0515, 0x0515,
+ 0x0517, 0x0517,
+ 0x0519, 0x0519,
+ 0x051b, 0x051b,
+ 0x051d, 0x051d,
+ 0x051f, 0x051f,
+ 0x0521, 0x0521,
+ 0x0523, 0x0523,
+ 0x0525, 0x0525,
+ 0x0527, 0x0527,
+ 0x0529, 0x0529,
+ 0x052b, 0x052b,
+ 0x052d, 0x052d,
+ 0x052f, 0x052f,
+ 0x0561, 0x0587,
+ 0x10d0, 0x10fa,
+ 0x10fd, 0x10ff,
+ 0x13f8, 0x13fd,
+ 0x1c80, 0x1c88,
+ 0x1c8a, 0x1c8a,
+ 0x1d79, 0x1d79,
+ 0x1d7d, 0x1d7d,
+ 0x1d8e, 0x1d8e,
+ 0x1e01, 0x1e01,
+ 0x1e03, 0x1e03,
+ 0x1e05, 0x1e05,
+ 0x1e07, 0x1e07,
+ 0x1e09, 0x1e09,
+ 0x1e0b, 0x1e0b,
+ 0x1e0d, 0x1e0d,
+ 0x1e0f, 0x1e0f,
+ 0x1e11, 0x1e11,
+ 0x1e13, 0x1e13,
+ 0x1e15, 0x1e15,
+ 0x1e17, 0x1e17,
+ 0x1e19, 0x1e19,
+ 0x1e1b, 0x1e1b,
+ 0x1e1d, 0x1e1d,
+ 0x1e1f, 0x1e1f,
+ 0x1e21, 0x1e21,
+ 0x1e23, 0x1e23,
+ 0x1e25, 0x1e25,
+ 0x1e27, 0x1e27,
+ 0x1e29, 0x1e29,
+ 0x1e2b, 0x1e2b,
+ 0x1e2d, 0x1e2d,
+ 0x1e2f, 0x1e2f,
+ 0x1e31, 0x1e31,
+ 0x1e33, 0x1e33,
+ 0x1e35, 0x1e35,
+ 0x1e37, 0x1e37,
+ 0x1e39, 0x1e39,
+ 0x1e3b, 0x1e3b,
+ 0x1e3d, 0x1e3d,
+ 0x1e3f, 0x1e3f,
+ 0x1e41, 0x1e41,
+ 0x1e43, 0x1e43,
+ 0x1e45, 0x1e45,
+ 0x1e47, 0x1e47,
+ 0x1e49, 0x1e49,
+ 0x1e4b, 0x1e4b,
+ 0x1e4d, 0x1e4d,
+ 0x1e4f, 0x1e4f,
+ 0x1e51, 0x1e51,
+ 0x1e53, 0x1e53,
+ 0x1e55, 0x1e55,
+ 0x1e57, 0x1e57,
+ 0x1e59, 0x1e59,
+ 0x1e5b, 0x1e5b,
+ 0x1e5d, 0x1e5d,
+ 0x1e5f, 0x1e5f,
+ 0x1e61, 0x1e61,
+ 0x1e63, 0x1e63,
+ 0x1e65, 0x1e65,
+ 0x1e67, 0x1e67,
+ 0x1e69, 0x1e69,
+ 0x1e6b, 0x1e6b,
+ 0x1e6d, 0x1e6d,
+ 0x1e6f, 0x1e6f,
+ 0x1e71, 0x1e71,
+ 0x1e73, 0x1e73,
+ 0x1e75, 0x1e75,
+ 0x1e77, 0x1e77,
+ 0x1e79, 0x1e79,
+ 0x1e7b, 0x1e7b,
+ 0x1e7d, 0x1e7d,
+ 0x1e7f, 0x1e7f,
+ 0x1e81, 0x1e81,
+ 0x1e83, 0x1e83,
+ 0x1e85, 0x1e85,
+ 0x1e87, 0x1e87,
+ 0x1e89, 0x1e89,
+ 0x1e8b, 0x1e8b,
+ 0x1e8d, 0x1e8d,
+ 0x1e8f, 0x1e8f,
+ 0x1e91, 0x1e91,
+ 0x1e93, 0x1e93,
+ 0x1e95, 0x1e9b,
+ 0x1ea1, 0x1ea1,
+ 0x1ea3, 0x1ea3,
+ 0x1ea5, 0x1ea5,
+ 0x1ea7, 0x1ea7,
+ 0x1ea9, 0x1ea9,
+ 0x1eab, 0x1eab,
+ 0x1ead, 0x1ead,
+ 0x1eaf, 0x1eaf,
+ 0x1eb1, 0x1eb1,
+ 0x1eb3, 0x1eb3,
+ 0x1eb5, 0x1eb5,
+ 0x1eb7, 0x1eb7,
+ 0x1eb9, 0x1eb9,
+ 0x1ebb, 0x1ebb,
+ 0x1ebd, 0x1ebd,
+ 0x1ebf, 0x1ebf,
+ 0x1ec1, 0x1ec1,
+ 0x1ec3, 0x1ec3,
+ 0x1ec5, 0x1ec5,
+ 0x1ec7, 0x1ec7,
+ 0x1ec9, 0x1ec9,
+ 0x1ecb, 0x1ecb,
+ 0x1ecd, 0x1ecd,
+ 0x1ecf, 0x1ecf,
+ 0x1ed1, 0x1ed1,
+ 0x1ed3, 0x1ed3,
+ 0x1ed5, 0x1ed5,
+ 0x1ed7, 0x1ed7,
+ 0x1ed9, 0x1ed9,
+ 0x1edb, 0x1edb,
+ 0x1edd, 0x1edd,
+ 0x1edf, 0x1edf,
+ 0x1ee1, 0x1ee1,
+ 0x1ee3, 0x1ee3,
+ 0x1ee5, 0x1ee5,
+ 0x1ee7, 0x1ee7,
+ 0x1ee9, 0x1ee9,
+ 0x1eeb, 0x1eeb,
+ 0x1eed, 0x1eed,
+ 0x1eef, 0x1eef,
+ 0x1ef1, 0x1ef1,
+ 0x1ef3, 0x1ef3,
+ 0x1ef5, 0x1ef5,
+ 0x1ef7, 0x1ef7,
+ 0x1ef9, 0x1ef9,
+ 0x1efb, 0x1efb,
+ 0x1efd, 0x1efd,
+ 0x1eff, 0x1f07,
+ 0x1f10, 0x1f15,
+ 0x1f20, 0x1f27,
+ 0x1f30, 0x1f37,
+ 0x1f40, 0x1f45,
+ 0x1f50, 0x1f57,
+ 0x1f60, 0x1f67,
+ 0x1f70, 0x1f7d,
+ 0x1f80, 0x1fb4,
+ 0x1fb6, 0x1fb7,
+ 0x1fbc, 0x1fbc,
+ 0x1fbe, 0x1fbe,
+ 0x1fc2, 0x1fc4,
+ 0x1fc6, 0x1fc7,
+ 0x1fcc, 0x1fcc,
+ 0x1fd0, 0x1fd3,
+ 0x1fd6, 0x1fd7,
+ 0x1fe0, 0x1fe7,
+ 0x1ff2, 0x1ff4,
+ 0x1ff6, 0x1ff7,
+ 0x1ffc, 0x1ffc,
+ 0x214e, 0x214e,
+ 0x2170, 0x217f,
+ 0x2184, 0x2184,
+ 0x24d0, 0x24e9,
+ 0x2c30, 0x2c5f,
+ 0x2c61, 0x2c61,
+ 0x2c65, 0x2c66,
+ 0x2c68, 0x2c68,
+ 0x2c6a, 0x2c6a,
+ 0x2c6c, 0x2c6c,
+ 0x2c73, 0x2c73,
+ 0x2c76, 0x2c76,
+ 0x2c81, 0x2c81,
+ 0x2c83, 0x2c83,
+ 0x2c85, 0x2c85,
+ 0x2c87, 0x2c87,
+ 0x2c89, 0x2c89,
+ 0x2c8b, 0x2c8b,
+ 0x2c8d, 0x2c8d,
+ 0x2c8f, 0x2c8f,
+ 0x2c91, 0x2c91,
+ 0x2c93, 0x2c93,
+ 0x2c95, 0x2c95,
+ 0x2c97, 0x2c97,
+ 0x2c99, 0x2c99,
+ 0x2c9b, 0x2c9b,
+ 0x2c9d, 0x2c9d,
+ 0x2c9f, 0x2c9f,
+ 0x2ca1, 0x2ca1,
+ 0x2ca3, 0x2ca3,
+ 0x2ca5, 0x2ca5,
+ 0x2ca7, 0x2ca7,
+ 0x2ca9, 0x2ca9,
+ 0x2cab, 0x2cab,
+ 0x2cad, 0x2cad,
+ 0x2caf, 0x2caf,
+ 0x2cb1, 0x2cb1,
+ 0x2cb3, 0x2cb3,
+ 0x2cb5, 0x2cb5,
+ 0x2cb7, 0x2cb7,
+ 0x2cb9, 0x2cb9,
+ 0x2cbb, 0x2cbb,
+ 0x2cbd, 0x2cbd,
+ 0x2cbf, 0x2cbf,
+ 0x2cc1, 0x2cc1,
+ 0x2cc3, 0x2cc3,
+ 0x2cc5, 0x2cc5,
+ 0x2cc7, 0x2cc7,
+ 0x2cc9, 0x2cc9,
+ 0x2ccb, 0x2ccb,
+ 0x2ccd, 0x2ccd,
+ 0x2ccf, 0x2ccf,
+ 0x2cd1, 0x2cd1,
+ 0x2cd3, 0x2cd3,
+ 0x2cd5, 0x2cd5,
+ 0x2cd7, 0x2cd7,
+ 0x2cd9, 0x2cd9,
+ 0x2cdb, 0x2cdb,
+ 0x2cdd, 0x2cdd,
+ 0x2cdf, 0x2cdf,
+ 0x2ce1, 0x2ce1,
+ 0x2ce3, 0x2ce3,
+ 0x2cec, 0x2cec,
+ 0x2cee, 0x2cee,
+ 0x2cf3, 0x2cf3,
+ 0x2d00, 0x2d25,
+ 0x2d27, 0x2d27,
+ 0x2d2d, 0x2d2d,
+ 0xa641, 0xa641,
+ 0xa643, 0xa643,
+ 0xa645, 0xa645,
+ 0xa647, 0xa647,
+ 0xa649, 0xa649,
+ 0xa64b, 0xa64b,
+ 0xa64d, 0xa64d,
+ 0xa64f, 0xa64f,
+ 0xa651, 0xa651,
+ 0xa653, 0xa653,
+ 0xa655, 0xa655,
+ 0xa657, 0xa657,
+ 0xa659, 0xa659,
+ 0xa65b, 0xa65b,
+ 0xa65d, 0xa65d,
+ 0xa65f, 0xa65f,
+ 0xa661, 0xa661,
+ 0xa663, 0xa663,
+ 0xa665, 0xa665,
+ 0xa667, 0xa667,
+ 0xa669, 0xa669,
+ 0xa66b, 0xa66b,
+ 0xa66d, 0xa66d,
+ 0xa681, 0xa681,
+ 0xa683, 0xa683,
+ 0xa685, 0xa685,
+ 0xa687, 0xa687,
+ 0xa689, 0xa689,
+ 0xa68b, 0xa68b,
+ 0xa68d, 0xa68d,
+ 0xa68f, 0xa68f,
+ 0xa691, 0xa691,
+ 0xa693, 0xa693,
+ 0xa695, 0xa695,
+ 0xa697, 0xa697,
+ 0xa699, 0xa699,
+ 0xa69b, 0xa69b,
+ 0xa723, 0xa723,
+ 0xa725, 0xa725,
+ 0xa727, 0xa727,
+ 0xa729, 0xa729,
+ 0xa72b, 0xa72b,
+ 0xa72d, 0xa72d,
+ 0xa72f, 0xa72f,
+ 0xa733, 0xa733,
+ 0xa735, 0xa735,
+ 0xa737, 0xa737,
+ 0xa739, 0xa739,
+ 0xa73b, 0xa73b,
+ 0xa73d, 0xa73d,
+ 0xa73f, 0xa73f,
+ 0xa741, 0xa741,
+ 0xa743, 0xa743,
+ 0xa745, 0xa745,
+ 0xa747, 0xa747,
+ 0xa749, 0xa749,
+ 0xa74b, 0xa74b,
+ 0xa74d, 0xa74d,
+ 0xa74f, 0xa74f,
+ 0xa751, 0xa751,
+ 0xa753, 0xa753,
+ 0xa755, 0xa755,
+ 0xa757, 0xa757,
+ 0xa759, 0xa759,
+ 0xa75b, 0xa75b,
+ 0xa75d, 0xa75d,
+ 0xa75f, 0xa75f,
+ 0xa761, 0xa761,
+ 0xa763, 0xa763,
+ 0xa765, 0xa765,
+ 0xa767, 0xa767,
+ 0xa769, 0xa769,
+ 0xa76b, 0xa76b,
+ 0xa76d, 0xa76d,
+ 0xa76f, 0xa76f,
+ 0xa77a, 0xa77a,
+ 0xa77c, 0xa77c,
+ 0xa77f, 0xa77f,
+ 0xa781, 0xa781,
+ 0xa783, 0xa783,
+ 0xa785, 0xa785,
+ 0xa787, 0xa787,
+ 0xa78c, 0xa78c,
+ 0xa791, 0xa791,
+ 0xa793, 0xa794,
+ 0xa797, 0xa797,
+ 0xa799, 0xa799,
+ 0xa79b, 0xa79b,
+ 0xa79d, 0xa79d,
+ 0xa79f, 0xa79f,
+ 0xa7a1, 0xa7a1,
+ 0xa7a3, 0xa7a3,
+ 0xa7a5, 0xa7a5,
+ 0xa7a7, 0xa7a7,
+ 0xa7a9, 0xa7a9,
+ 0xa7b5, 0xa7b5,
+ 0xa7b7, 0xa7b7,
+ 0xa7b9, 0xa7b9,
+ 0xa7bb, 0xa7bb,
+ 0xa7bd, 0xa7bd,
+ 0xa7bf, 0xa7bf,
+ 0xa7c1, 0xa7c1,
+ 0xa7c3, 0xa7c3,
+ 0xa7c8, 0xa7c8,
+ 0xa7ca, 0xa7ca,
+ 0xa7cd, 0xa7cd,
+ 0xa7cf, 0xa7cf,
+ 0xa7d1, 0xa7d1,
+ 0xa7d3, 0xa7d3,
+ 0xa7d5, 0xa7d5,
+ 0xa7d7, 0xa7d7,
+ 0xa7d9, 0xa7d9,
+ 0xa7db, 0xa7db,
+ 0xa7f6, 0xa7f6,
+ 0xab53, 0xab53,
+ 0xab70, 0xabbf,
+ 0xfb00, 0xfb06,
+ 0xfb13, 0xfb17,
+ 0xff41, 0xff5a,
+ 0x10428, 0x1044f,
+ 0x104d8, 0x104fb,
+ 0x10597, 0x105a1,
+ 0x105a3, 0x105b1,
+ 0x105b3, 0x105b9,
+ 0x105bb, 0x105bc,
+ 0x10cc0, 0x10cf2,
+ 0x10d70, 0x10d85,
+ 0x118c0, 0x118df,
+ 0x16e60, 0x16e7f,
+ 0x16ebb, 0x16ed3,
+ 0x1e922, 0x1e943,
+}; /* CR_Changes_When_Uppercased */
+
+/* 'Changes_When_Titlecased': Derived Property */
+static const OnigCodePoint CR_Changes_When_Titlecased[] = {
+ 633,
+ 0x0061, 0x007a,
+ 0x00b5, 0x00b5,
+ 0x00df, 0x00f6,
+ 0x00f8, 0x00ff,
+ 0x0101, 0x0101,
+ 0x0103, 0x0103,
+ 0x0105, 0x0105,
+ 0x0107, 0x0107,
+ 0x0109, 0x0109,
+ 0x010b, 0x010b,
+ 0x010d, 0x010d,
+ 0x010f, 0x010f,
+ 0x0111, 0x0111,
+ 0x0113, 0x0113,
+ 0x0115, 0x0115,
+ 0x0117, 0x0117,
+ 0x0119, 0x0119,
+ 0x011b, 0x011b,
+ 0x011d, 0x011d,
+ 0x011f, 0x011f,
+ 0x0121, 0x0121,
+ 0x0123, 0x0123,
+ 0x0125, 0x0125,
+ 0x0127, 0x0127,
+ 0x0129, 0x0129,
+ 0x012b, 0x012b,
+ 0x012d, 0x012d,
+ 0x012f, 0x012f,
+ 0x0131, 0x0131,
+ 0x0133, 0x0133,
+ 0x0135, 0x0135,
+ 0x0137, 0x0137,
+ 0x013a, 0x013a,
+ 0x013c, 0x013c,
+ 0x013e, 0x013e,
+ 0x0140, 0x0140,
+ 0x0142, 0x0142,
+ 0x0144, 0x0144,
+ 0x0146, 0x0146,
+ 0x0148, 0x0149,
+ 0x014b, 0x014b,
+ 0x014d, 0x014d,
+ 0x014f, 0x014f,
+ 0x0151, 0x0151,
+ 0x0153, 0x0153,
+ 0x0155, 0x0155,
+ 0x0157, 0x0157,
+ 0x0159, 0x0159,
+ 0x015b, 0x015b,
+ 0x015d, 0x015d,
+ 0x015f, 0x015f,
+ 0x0161, 0x0161,
+ 0x0163, 0x0163,
+ 0x0165, 0x0165,
+ 0x0167, 0x0167,
+ 0x0169, 0x0169,
+ 0x016b, 0x016b,
+ 0x016d, 0x016d,
+ 0x016f, 0x016f,
+ 0x0171, 0x0171,
+ 0x0173, 0x0173,
+ 0x0175, 0x0175,
+ 0x0177, 0x0177,
+ 0x017a, 0x017a,
+ 0x017c, 0x017c,
+ 0x017e, 0x0180,
+ 0x0183, 0x0183,
+ 0x0185, 0x0185,
+ 0x0188, 0x0188,
+ 0x018c, 0x018c,
+ 0x0192, 0x0192,
+ 0x0195, 0x0195,
+ 0x0199, 0x019b,
+ 0x019e, 0x019e,
+ 0x01a1, 0x01a1,
+ 0x01a3, 0x01a3,
+ 0x01a5, 0x01a5,
+ 0x01a8, 0x01a8,
+ 0x01ad, 0x01ad,
+ 0x01b0, 0x01b0,
+ 0x01b4, 0x01b4,
+ 0x01b6, 0x01b6,
+ 0x01b9, 0x01b9,
+ 0x01bd, 0x01bd,
+ 0x01bf, 0x01bf,
+ 0x01c4, 0x01c4,
+ 0x01c6, 0x01c7,
+ 0x01c9, 0x01ca,
+ 0x01cc, 0x01cc,
+ 0x01ce, 0x01ce,
+ 0x01d0, 0x01d0,
+ 0x01d2, 0x01d2,
+ 0x01d4, 0x01d4,
+ 0x01d6, 0x01d6,
+ 0x01d8, 0x01d8,
+ 0x01da, 0x01da,
+ 0x01dc, 0x01dd,
+ 0x01df, 0x01df,
+ 0x01e1, 0x01e1,
+ 0x01e3, 0x01e3,
+ 0x01e5, 0x01e5,
+ 0x01e7, 0x01e7,
+ 0x01e9, 0x01e9,
+ 0x01eb, 0x01eb,
+ 0x01ed, 0x01ed,
+ 0x01ef, 0x01f1,
+ 0x01f3, 0x01f3,
+ 0x01f5, 0x01f5,
+ 0x01f9, 0x01f9,
+ 0x01fb, 0x01fb,
+ 0x01fd, 0x01fd,
+ 0x01ff, 0x01ff,
+ 0x0201, 0x0201,
+ 0x0203, 0x0203,
+ 0x0205, 0x0205,
+ 0x0207, 0x0207,
+ 0x0209, 0x0209,
+ 0x020b, 0x020b,
+ 0x020d, 0x020d,
+ 0x020f, 0x020f,
+ 0x0211, 0x0211,
+ 0x0213, 0x0213,
+ 0x0215, 0x0215,
+ 0x0217, 0x0217,
+ 0x0219, 0x0219,
+ 0x021b, 0x021b,
+ 0x021d, 0x021d,
+ 0x021f, 0x021f,
+ 0x0223, 0x0223,
+ 0x0225, 0x0225,
+ 0x0227, 0x0227,
+ 0x0229, 0x0229,
+ 0x022b, 0x022b,
+ 0x022d, 0x022d,
+ 0x022f, 0x022f,
+ 0x0231, 0x0231,
+ 0x0233, 0x0233,
+ 0x023c, 0x023c,
+ 0x023f, 0x0240,
+ 0x0242, 0x0242,
+ 0x0247, 0x0247,
+ 0x0249, 0x0249,
+ 0x024b, 0x024b,
+ 0x024d, 0x024d,
+ 0x024f, 0x0254,
+ 0x0256, 0x0257,
+ 0x0259, 0x0259,
+ 0x025b, 0x025c,
+ 0x0260, 0x0261,
+ 0x0263, 0x0266,
+ 0x0268, 0x026c,
+ 0x026f, 0x026f,
+ 0x0271, 0x0272,
+ 0x0275, 0x0275,
+ 0x027d, 0x027d,
+ 0x0280, 0x0280,
+ 0x0282, 0x0283,
+ 0x0287, 0x028c,
+ 0x0292, 0x0292,
+ 0x029d, 0x029e,
+ 0x0345, 0x0345,
+ 0x0371, 0x0371,
+ 0x0373, 0x0373,
+ 0x0377, 0x0377,
+ 0x037b, 0x037d,
+ 0x0390, 0x0390,
+ 0x03ac, 0x03ce,
+ 0x03d0, 0x03d1,
+ 0x03d5, 0x03d7,
+ 0x03d9, 0x03d9,
+ 0x03db, 0x03db,
+ 0x03dd, 0x03dd,
+ 0x03df, 0x03df,
+ 0x03e1, 0x03e1,
+ 0x03e3, 0x03e3,
+ 0x03e5, 0x03e5,
+ 0x03e7, 0x03e7,
+ 0x03e9, 0x03e9,
+ 0x03eb, 0x03eb,
+ 0x03ed, 0x03ed,
+ 0x03ef, 0x03f3,
+ 0x03f5, 0x03f5,
+ 0x03f8, 0x03f8,
+ 0x03fb, 0x03fb,
+ 0x0430, 0x045f,
+ 0x0461, 0x0461,
+ 0x0463, 0x0463,
+ 0x0465, 0x0465,
+ 0x0467, 0x0467,
+ 0x0469, 0x0469,
+ 0x046b, 0x046b,
+ 0x046d, 0x046d,
+ 0x046f, 0x046f,
+ 0x0471, 0x0471,
+ 0x0473, 0x0473,
+ 0x0475, 0x0475,
+ 0x0477, 0x0477,
+ 0x0479, 0x0479,
+ 0x047b, 0x047b,
+ 0x047d, 0x047d,
+ 0x047f, 0x047f,
+ 0x0481, 0x0481,
+ 0x048b, 0x048b,
+ 0x048d, 0x048d,
+ 0x048f, 0x048f,
+ 0x0491, 0x0491,
+ 0x0493, 0x0493,
+ 0x0495, 0x0495,
+ 0x0497, 0x0497,
+ 0x0499, 0x0499,
+ 0x049b, 0x049b,
+ 0x049d, 0x049d,
+ 0x049f, 0x049f,
+ 0x04a1, 0x04a1,
+ 0x04a3, 0x04a3,
+ 0x04a5, 0x04a5,
+ 0x04a7, 0x04a7,
+ 0x04a9, 0x04a9,
+ 0x04ab, 0x04ab,
+ 0x04ad, 0x04ad,
+ 0x04af, 0x04af,
+ 0x04b1, 0x04b1,
+ 0x04b3, 0x04b3,
+ 0x04b5, 0x04b5,
+ 0x04b7, 0x04b7,
+ 0x04b9, 0x04b9,
+ 0x04bb, 0x04bb,
+ 0x04bd, 0x04bd,
+ 0x04bf, 0x04bf,
+ 0x04c2, 0x04c2,
+ 0x04c4, 0x04c4,
+ 0x04c6, 0x04c6,
+ 0x04c8, 0x04c8,
+ 0x04ca, 0x04ca,
+ 0x04cc, 0x04cc,
+ 0x04ce, 0x04cf,
+ 0x04d1, 0x04d1,
+ 0x04d3, 0x04d3,
+ 0x04d5, 0x04d5,
+ 0x04d7, 0x04d7,
+ 0x04d9, 0x04d9,
+ 0x04db, 0x04db,
+ 0x04dd, 0x04dd,
+ 0x04df, 0x04df,
+ 0x04e1, 0x04e1,
+ 0x04e3, 0x04e3,
+ 0x04e5, 0x04e5,
+ 0x04e7, 0x04e7,
+ 0x04e9, 0x04e9,
+ 0x04eb, 0x04eb,
+ 0x04ed, 0x04ed,
+ 0x04ef, 0x04ef,
+ 0x04f1, 0x04f1,
+ 0x04f3, 0x04f3,
+ 0x04f5, 0x04f5,
+ 0x04f7, 0x04f7,
+ 0x04f9, 0x04f9,
+ 0x04fb, 0x04fb,
+ 0x04fd, 0x04fd,
+ 0x04ff, 0x04ff,
+ 0x0501, 0x0501,
+ 0x0503, 0x0503,
+ 0x0505, 0x0505,
+ 0x0507, 0x0507,
+ 0x0509, 0x0509,
+ 0x050b, 0x050b,
+ 0x050d, 0x050d,
+ 0x050f, 0x050f,
+ 0x0511, 0x0511,
+ 0x0513, 0x0513,
+ 0x0515, 0x0515,
+ 0x0517, 0x0517,
+ 0x0519, 0x0519,
+ 0x051b, 0x051b,
+ 0x051d, 0x051d,
+ 0x051f, 0x051f,
+ 0x0521, 0x0521,
+ 0x0523, 0x0523,
+ 0x0525, 0x0525,
+ 0x0527, 0x0527,
+ 0x0529, 0x0529,
+ 0x052b, 0x052b,
+ 0x052d, 0x052d,
+ 0x052f, 0x052f,
+ 0x0561, 0x0587,
+ 0x13f8, 0x13fd,
+ 0x1c80, 0x1c88,
+ 0x1c8a, 0x1c8a,
+ 0x1d79, 0x1d79,
+ 0x1d7d, 0x1d7d,
+ 0x1d8e, 0x1d8e,
+ 0x1e01, 0x1e01,
+ 0x1e03, 0x1e03,
+ 0x1e05, 0x1e05,
+ 0x1e07, 0x1e07,
+ 0x1e09, 0x1e09,
+ 0x1e0b, 0x1e0b,
+ 0x1e0d, 0x1e0d,
+ 0x1e0f, 0x1e0f,
+ 0x1e11, 0x1e11,
+ 0x1e13, 0x1e13,
+ 0x1e15, 0x1e15,
+ 0x1e17, 0x1e17,
+ 0x1e19, 0x1e19,
+ 0x1e1b, 0x1e1b,
+ 0x1e1d, 0x1e1d,
+ 0x1e1f, 0x1e1f,
+ 0x1e21, 0x1e21,
+ 0x1e23, 0x1e23,
+ 0x1e25, 0x1e25,
+ 0x1e27, 0x1e27,
+ 0x1e29, 0x1e29,
+ 0x1e2b, 0x1e2b,
+ 0x1e2d, 0x1e2d,
+ 0x1e2f, 0x1e2f,
+ 0x1e31, 0x1e31,
+ 0x1e33, 0x1e33,
+ 0x1e35, 0x1e35,
+ 0x1e37, 0x1e37,
+ 0x1e39, 0x1e39,
+ 0x1e3b, 0x1e3b,
+ 0x1e3d, 0x1e3d,
+ 0x1e3f, 0x1e3f,
+ 0x1e41, 0x1e41,
+ 0x1e43, 0x1e43,
+ 0x1e45, 0x1e45,
+ 0x1e47, 0x1e47,
+ 0x1e49, 0x1e49,
+ 0x1e4b, 0x1e4b,
+ 0x1e4d, 0x1e4d,
+ 0x1e4f, 0x1e4f,
+ 0x1e51, 0x1e51,
+ 0x1e53, 0x1e53,
+ 0x1e55, 0x1e55,
+ 0x1e57, 0x1e57,
+ 0x1e59, 0x1e59,
+ 0x1e5b, 0x1e5b,
+ 0x1e5d, 0x1e5d,
+ 0x1e5f, 0x1e5f,
+ 0x1e61, 0x1e61,
+ 0x1e63, 0x1e63,
+ 0x1e65, 0x1e65,
+ 0x1e67, 0x1e67,
+ 0x1e69, 0x1e69,
+ 0x1e6b, 0x1e6b,
+ 0x1e6d, 0x1e6d,
+ 0x1e6f, 0x1e6f,
+ 0x1e71, 0x1e71,
+ 0x1e73, 0x1e73,
+ 0x1e75, 0x1e75,
+ 0x1e77, 0x1e77,
+ 0x1e79, 0x1e79,
+ 0x1e7b, 0x1e7b,
+ 0x1e7d, 0x1e7d,
+ 0x1e7f, 0x1e7f,
+ 0x1e81, 0x1e81,
+ 0x1e83, 0x1e83,
+ 0x1e85, 0x1e85,
+ 0x1e87, 0x1e87,
+ 0x1e89, 0x1e89,
+ 0x1e8b, 0x1e8b,
+ 0x1e8d, 0x1e8d,
+ 0x1e8f, 0x1e8f,
+ 0x1e91, 0x1e91,
+ 0x1e93, 0x1e93,
+ 0x1e95, 0x1e9b,
+ 0x1ea1, 0x1ea1,
+ 0x1ea3, 0x1ea3,
+ 0x1ea5, 0x1ea5,
+ 0x1ea7, 0x1ea7,
+ 0x1ea9, 0x1ea9,
+ 0x1eab, 0x1eab,
+ 0x1ead, 0x1ead,
+ 0x1eaf, 0x1eaf,
+ 0x1eb1, 0x1eb1,
+ 0x1eb3, 0x1eb3,
+ 0x1eb5, 0x1eb5,
+ 0x1eb7, 0x1eb7,
+ 0x1eb9, 0x1eb9,
+ 0x1ebb, 0x1ebb,
+ 0x1ebd, 0x1ebd,
+ 0x1ebf, 0x1ebf,
+ 0x1ec1, 0x1ec1,
+ 0x1ec3, 0x1ec3,
+ 0x1ec5, 0x1ec5,
+ 0x1ec7, 0x1ec7,
+ 0x1ec9, 0x1ec9,
+ 0x1ecb, 0x1ecb,
+ 0x1ecd, 0x1ecd,
+ 0x1ecf, 0x1ecf,
+ 0x1ed1, 0x1ed1,
+ 0x1ed3, 0x1ed3,
+ 0x1ed5, 0x1ed5,
+ 0x1ed7, 0x1ed7,
+ 0x1ed9, 0x1ed9,
+ 0x1edb, 0x1edb,
+ 0x1edd, 0x1edd,
+ 0x1edf, 0x1edf,
+ 0x1ee1, 0x1ee1,
+ 0x1ee3, 0x1ee3,
+ 0x1ee5, 0x1ee5,
+ 0x1ee7, 0x1ee7,
+ 0x1ee9, 0x1ee9,
+ 0x1eeb, 0x1eeb,
+ 0x1eed, 0x1eed,
+ 0x1eef, 0x1eef,
+ 0x1ef1, 0x1ef1,
+ 0x1ef3, 0x1ef3,
+ 0x1ef5, 0x1ef5,
+ 0x1ef7, 0x1ef7,
+ 0x1ef9, 0x1ef9,
+ 0x1efb, 0x1efb,
+ 0x1efd, 0x1efd,
+ 0x1eff, 0x1f07,
+ 0x1f10, 0x1f15,
+ 0x1f20, 0x1f27,
+ 0x1f30, 0x1f37,
+ 0x1f40, 0x1f45,
+ 0x1f50, 0x1f57,
+ 0x1f60, 0x1f67,
+ 0x1f70, 0x1f7d,
+ 0x1f80, 0x1f87,
+ 0x1f90, 0x1f97,
+ 0x1fa0, 0x1fa7,
+ 0x1fb0, 0x1fb4,
+ 0x1fb6, 0x1fb7,
+ 0x1fbe, 0x1fbe,
+ 0x1fc2, 0x1fc4,
+ 0x1fc6, 0x1fc7,
+ 0x1fd0, 0x1fd3,
+ 0x1fd6, 0x1fd7,
+ 0x1fe0, 0x1fe7,
+ 0x1ff2, 0x1ff4,
+ 0x1ff6, 0x1ff7,
+ 0x214e, 0x214e,
+ 0x2170, 0x217f,
+ 0x2184, 0x2184,
+ 0x24d0, 0x24e9,
+ 0x2c30, 0x2c5f,
+ 0x2c61, 0x2c61,
+ 0x2c65, 0x2c66,
+ 0x2c68, 0x2c68,
+ 0x2c6a, 0x2c6a,
+ 0x2c6c, 0x2c6c,
+ 0x2c73, 0x2c73,
+ 0x2c76, 0x2c76,
+ 0x2c81, 0x2c81,
+ 0x2c83, 0x2c83,
+ 0x2c85, 0x2c85,
+ 0x2c87, 0x2c87,
+ 0x2c89, 0x2c89,
+ 0x2c8b, 0x2c8b,
+ 0x2c8d, 0x2c8d,
+ 0x2c8f, 0x2c8f,
+ 0x2c91, 0x2c91,
+ 0x2c93, 0x2c93,
+ 0x2c95, 0x2c95,
+ 0x2c97, 0x2c97,
+ 0x2c99, 0x2c99,
+ 0x2c9b, 0x2c9b,
+ 0x2c9d, 0x2c9d,
+ 0x2c9f, 0x2c9f,
+ 0x2ca1, 0x2ca1,
+ 0x2ca3, 0x2ca3,
+ 0x2ca5, 0x2ca5,
+ 0x2ca7, 0x2ca7,
+ 0x2ca9, 0x2ca9,
+ 0x2cab, 0x2cab,
+ 0x2cad, 0x2cad,
+ 0x2caf, 0x2caf,
+ 0x2cb1, 0x2cb1,
+ 0x2cb3, 0x2cb3,
+ 0x2cb5, 0x2cb5,
+ 0x2cb7, 0x2cb7,
+ 0x2cb9, 0x2cb9,
+ 0x2cbb, 0x2cbb,
+ 0x2cbd, 0x2cbd,
+ 0x2cbf, 0x2cbf,
+ 0x2cc1, 0x2cc1,
+ 0x2cc3, 0x2cc3,
+ 0x2cc5, 0x2cc5,
+ 0x2cc7, 0x2cc7,
+ 0x2cc9, 0x2cc9,
+ 0x2ccb, 0x2ccb,
+ 0x2ccd, 0x2ccd,
+ 0x2ccf, 0x2ccf,
+ 0x2cd1, 0x2cd1,
+ 0x2cd3, 0x2cd3,
+ 0x2cd5, 0x2cd5,
+ 0x2cd7, 0x2cd7,
+ 0x2cd9, 0x2cd9,
+ 0x2cdb, 0x2cdb,
+ 0x2cdd, 0x2cdd,
+ 0x2cdf, 0x2cdf,
+ 0x2ce1, 0x2ce1,
+ 0x2ce3, 0x2ce3,
+ 0x2cec, 0x2cec,
+ 0x2cee, 0x2cee,
+ 0x2cf3, 0x2cf3,
+ 0x2d00, 0x2d25,
+ 0x2d27, 0x2d27,
+ 0x2d2d, 0x2d2d,
+ 0xa641, 0xa641,
+ 0xa643, 0xa643,
+ 0xa645, 0xa645,
+ 0xa647, 0xa647,
+ 0xa649, 0xa649,
+ 0xa64b, 0xa64b,
+ 0xa64d, 0xa64d,
+ 0xa64f, 0xa64f,
+ 0xa651, 0xa651,
+ 0xa653, 0xa653,
+ 0xa655, 0xa655,
+ 0xa657, 0xa657,
+ 0xa659, 0xa659,
+ 0xa65b, 0xa65b,
+ 0xa65d, 0xa65d,
+ 0xa65f, 0xa65f,
+ 0xa661, 0xa661,
+ 0xa663, 0xa663,
+ 0xa665, 0xa665,
+ 0xa667, 0xa667,
+ 0xa669, 0xa669,
+ 0xa66b, 0xa66b,
+ 0xa66d, 0xa66d,
+ 0xa681, 0xa681,
+ 0xa683, 0xa683,
+ 0xa685, 0xa685,
+ 0xa687, 0xa687,
+ 0xa689, 0xa689,
+ 0xa68b, 0xa68b,
+ 0xa68d, 0xa68d,
+ 0xa68f, 0xa68f,
+ 0xa691, 0xa691,
+ 0xa693, 0xa693,
+ 0xa695, 0xa695,
+ 0xa697, 0xa697,
+ 0xa699, 0xa699,
+ 0xa69b, 0xa69b,
+ 0xa723, 0xa723,
+ 0xa725, 0xa725,
+ 0xa727, 0xa727,
+ 0xa729, 0xa729,
+ 0xa72b, 0xa72b,
+ 0xa72d, 0xa72d,
+ 0xa72f, 0xa72f,
+ 0xa733, 0xa733,
+ 0xa735, 0xa735,
+ 0xa737, 0xa737,
+ 0xa739, 0xa739,
+ 0xa73b, 0xa73b,
+ 0xa73d, 0xa73d,
+ 0xa73f, 0xa73f,
+ 0xa741, 0xa741,
+ 0xa743, 0xa743,
+ 0xa745, 0xa745,
+ 0xa747, 0xa747,
+ 0xa749, 0xa749,
+ 0xa74b, 0xa74b,
+ 0xa74d, 0xa74d,
+ 0xa74f, 0xa74f,
+ 0xa751, 0xa751,
+ 0xa753, 0xa753,
+ 0xa755, 0xa755,
+ 0xa757, 0xa757,
+ 0xa759, 0xa759,
+ 0xa75b, 0xa75b,
+ 0xa75d, 0xa75d,
+ 0xa75f, 0xa75f,
+ 0xa761, 0xa761,
+ 0xa763, 0xa763,
+ 0xa765, 0xa765,
+ 0xa767, 0xa767,
+ 0xa769, 0xa769,
+ 0xa76b, 0xa76b,
+ 0xa76d, 0xa76d,
+ 0xa76f, 0xa76f,
+ 0xa77a, 0xa77a,
+ 0xa77c, 0xa77c,
+ 0xa77f, 0xa77f,
+ 0xa781, 0xa781,
+ 0xa783, 0xa783,
+ 0xa785, 0xa785,
+ 0xa787, 0xa787,
+ 0xa78c, 0xa78c,
+ 0xa791, 0xa791,
+ 0xa793, 0xa794,
+ 0xa797, 0xa797,
+ 0xa799, 0xa799,
+ 0xa79b, 0xa79b,
+ 0xa79d, 0xa79d,
+ 0xa79f, 0xa79f,
+ 0xa7a1, 0xa7a1,
+ 0xa7a3, 0xa7a3,
+ 0xa7a5, 0xa7a5,
+ 0xa7a7, 0xa7a7,
+ 0xa7a9, 0xa7a9,
+ 0xa7b5, 0xa7b5,
+ 0xa7b7, 0xa7b7,
+ 0xa7b9, 0xa7b9,
+ 0xa7bb, 0xa7bb,
+ 0xa7bd, 0xa7bd,
+ 0xa7bf, 0xa7bf,
+ 0xa7c1, 0xa7c1,
+ 0xa7c3, 0xa7c3,
+ 0xa7c8, 0xa7c8,
+ 0xa7ca, 0xa7ca,
+ 0xa7cd, 0xa7cd,
+ 0xa7cf, 0xa7cf,
+ 0xa7d1, 0xa7d1,
+ 0xa7d3, 0xa7d3,
+ 0xa7d5, 0xa7d5,
+ 0xa7d7, 0xa7d7,
+ 0xa7d9, 0xa7d9,
+ 0xa7db, 0xa7db,
+ 0xa7f6, 0xa7f6,
+ 0xab53, 0xab53,
+ 0xab70, 0xabbf,
+ 0xfb00, 0xfb06,
+ 0xfb13, 0xfb17,
+ 0xff41, 0xff5a,
+ 0x10428, 0x1044f,
+ 0x104d8, 0x104fb,
+ 0x10597, 0x105a1,
+ 0x105a3, 0x105b1,
+ 0x105b3, 0x105b9,
+ 0x105bb, 0x105bc,
+ 0x10cc0, 0x10cf2,
+ 0x10d70, 0x10d85,
+ 0x118c0, 0x118df,
+ 0x16e60, 0x16e7f,
+ 0x16ebb, 0x16ed3,
+ 0x1e922, 0x1e943,
+}; /* CR_Changes_When_Titlecased */
+
+/* 'Changes_When_Casefolded': Derived Property */
+static const OnigCodePoint CR_Changes_When_Casefolded[] = {
+ 630,
+ 0x0041, 0x005a,
+ 0x00b5, 0x00b5,
+ 0x00c0, 0x00d6,
+ 0x00d8, 0x00df,
+ 0x0100, 0x0100,
+ 0x0102, 0x0102,
+ 0x0104, 0x0104,
+ 0x0106, 0x0106,
+ 0x0108, 0x0108,
+ 0x010a, 0x010a,
+ 0x010c, 0x010c,
+ 0x010e, 0x010e,
+ 0x0110, 0x0110,
+ 0x0112, 0x0112,
+ 0x0114, 0x0114,
+ 0x0116, 0x0116,
+ 0x0118, 0x0118,
+ 0x011a, 0x011a,
+ 0x011c, 0x011c,
+ 0x011e, 0x011e,
+ 0x0120, 0x0120,
+ 0x0122, 0x0122,
+ 0x0124, 0x0124,
+ 0x0126, 0x0126,
+ 0x0128, 0x0128,
+ 0x012a, 0x012a,
+ 0x012c, 0x012c,
+ 0x012e, 0x012e,
+ 0x0130, 0x0130,
+ 0x0132, 0x0132,
+ 0x0134, 0x0134,
+ 0x0136, 0x0136,
+ 0x0139, 0x0139,
+ 0x013b, 0x013b,
+ 0x013d, 0x013d,
+ 0x013f, 0x013f,
+ 0x0141, 0x0141,
+ 0x0143, 0x0143,
+ 0x0145, 0x0145,
+ 0x0147, 0x0147,
+ 0x0149, 0x014a,
+ 0x014c, 0x014c,
+ 0x014e, 0x014e,
+ 0x0150, 0x0150,
+ 0x0152, 0x0152,
+ 0x0154, 0x0154,
+ 0x0156, 0x0156,
+ 0x0158, 0x0158,
+ 0x015a, 0x015a,
+ 0x015c, 0x015c,
+ 0x015e, 0x015e,
+ 0x0160, 0x0160,
+ 0x0162, 0x0162,
+ 0x0164, 0x0164,
+ 0x0166, 0x0166,
+ 0x0168, 0x0168,
+ 0x016a, 0x016a,
+ 0x016c, 0x016c,
+ 0x016e, 0x016e,
+ 0x0170, 0x0170,
+ 0x0172, 0x0172,
+ 0x0174, 0x0174,
+ 0x0176, 0x0176,
+ 0x0178, 0x0179,
+ 0x017b, 0x017b,
+ 0x017d, 0x017d,
+ 0x017f, 0x017f,
+ 0x0181, 0x0182,
+ 0x0184, 0x0184,
+ 0x0186, 0x0187,
+ 0x0189, 0x018b,
+ 0x018e, 0x0191,
+ 0x0193, 0x0194,
+ 0x0196, 0x0198,
+ 0x019c, 0x019d,
+ 0x019f, 0x01a0,
+ 0x01a2, 0x01a2,
+ 0x01a4, 0x01a4,
+ 0x01a6, 0x01a7,
+ 0x01a9, 0x01a9,
+ 0x01ac, 0x01ac,
+ 0x01ae, 0x01af,
+ 0x01b1, 0x01b3,
+ 0x01b5, 0x01b5,
+ 0x01b7, 0x01b8,
+ 0x01bc, 0x01bc,
+ 0x01c4, 0x01c5,
+ 0x01c7, 0x01c8,
+ 0x01ca, 0x01cb,
+ 0x01cd, 0x01cd,
+ 0x01cf, 0x01cf,
+ 0x01d1, 0x01d1,
+ 0x01d3, 0x01d3,
+ 0x01d5, 0x01d5,
+ 0x01d7, 0x01d7,
+ 0x01d9, 0x01d9,
+ 0x01db, 0x01db,
+ 0x01de, 0x01de,
+ 0x01e0, 0x01e0,
+ 0x01e2, 0x01e2,
+ 0x01e4, 0x01e4,
+ 0x01e6, 0x01e6,
+ 0x01e8, 0x01e8,
+ 0x01ea, 0x01ea,
+ 0x01ec, 0x01ec,
+ 0x01ee, 0x01ee,
+ 0x01f1, 0x01f2,
+ 0x01f4, 0x01f4,
+ 0x01f6, 0x01f8,
+ 0x01fa, 0x01fa,
+ 0x01fc, 0x01fc,
+ 0x01fe, 0x01fe,
+ 0x0200, 0x0200,
+ 0x0202, 0x0202,
+ 0x0204, 0x0204,
+ 0x0206, 0x0206,
+ 0x0208, 0x0208,
+ 0x020a, 0x020a,
+ 0x020c, 0x020c,
+ 0x020e, 0x020e,
+ 0x0210, 0x0210,
+ 0x0212, 0x0212,
+ 0x0214, 0x0214,
+ 0x0216, 0x0216,
+ 0x0218, 0x0218,
+ 0x021a, 0x021a,
+ 0x021c, 0x021c,
+ 0x021e, 0x021e,
+ 0x0220, 0x0220,
+ 0x0222, 0x0222,
+ 0x0224, 0x0224,
+ 0x0226, 0x0226,
+ 0x0228, 0x0228,
+ 0x022a, 0x022a,
+ 0x022c, 0x022c,
+ 0x022e, 0x022e,
+ 0x0230, 0x0230,
+ 0x0232, 0x0232,
+ 0x023a, 0x023b,
+ 0x023d, 0x023e,
+ 0x0241, 0x0241,
+ 0x0243, 0x0246,
+ 0x0248, 0x0248,
+ 0x024a, 0x024a,
+ 0x024c, 0x024c,
+ 0x024e, 0x024e,
+ 0x0345, 0x0345,
+ 0x0370, 0x0370,
+ 0x0372, 0x0372,
+ 0x0376, 0x0376,
+ 0x037f, 0x037f,
+ 0x0386, 0x0386,
+ 0x0388, 0x038a,
+ 0x038c, 0x038c,
+ 0x038e, 0x038f,
+ 0x0391, 0x03a1,
+ 0x03a3, 0x03ab,
+ 0x03c2, 0x03c2,
+ 0x03cf, 0x03d1,
+ 0x03d5, 0x03d6,
+ 0x03d8, 0x03d8,
+ 0x03da, 0x03da,
+ 0x03dc, 0x03dc,
+ 0x03de, 0x03de,
+ 0x03e0, 0x03e0,
+ 0x03e2, 0x03e2,
+ 0x03e4, 0x03e4,
+ 0x03e6, 0x03e6,
+ 0x03e8, 0x03e8,
+ 0x03ea, 0x03ea,
+ 0x03ec, 0x03ec,
+ 0x03ee, 0x03ee,
+ 0x03f0, 0x03f1,
+ 0x03f4, 0x03f5,
+ 0x03f7, 0x03f7,
+ 0x03f9, 0x03fa,
+ 0x03fd, 0x042f,
+ 0x0460, 0x0460,
+ 0x0462, 0x0462,
+ 0x0464, 0x0464,
+ 0x0466, 0x0466,
+ 0x0468, 0x0468,
+ 0x046a, 0x046a,
+ 0x046c, 0x046c,
+ 0x046e, 0x046e,
+ 0x0470, 0x0470,
+ 0x0472, 0x0472,
+ 0x0474, 0x0474,
+ 0x0476, 0x0476,
+ 0x0478, 0x0478,
+ 0x047a, 0x047a,
+ 0x047c, 0x047c,
+ 0x047e, 0x047e,
+ 0x0480, 0x0480,
+ 0x048a, 0x048a,
+ 0x048c, 0x048c,
+ 0x048e, 0x048e,
+ 0x0490, 0x0490,
+ 0x0492, 0x0492,
+ 0x0494, 0x0494,
+ 0x0496, 0x0496,
+ 0x0498, 0x0498,
+ 0x049a, 0x049a,
+ 0x049c, 0x049c,
+ 0x049e, 0x049e,
+ 0x04a0, 0x04a0,
+ 0x04a2, 0x04a2,
+ 0x04a4, 0x04a4,
+ 0x04a6, 0x04a6,
+ 0x04a8, 0x04a8,
+ 0x04aa, 0x04aa,
+ 0x04ac, 0x04ac,
+ 0x04ae, 0x04ae,
+ 0x04b0, 0x04b0,
+ 0x04b2, 0x04b2,
+ 0x04b4, 0x04b4,
+ 0x04b6, 0x04b6,
+ 0x04b8, 0x04b8,
+ 0x04ba, 0x04ba,
+ 0x04bc, 0x04bc,
+ 0x04be, 0x04be,
+ 0x04c0, 0x04c1,
+ 0x04c3, 0x04c3,
+ 0x04c5, 0x04c5,
+ 0x04c7, 0x04c7,
+ 0x04c9, 0x04c9,
+ 0x04cb, 0x04cb,
+ 0x04cd, 0x04cd,
+ 0x04d0, 0x04d0,
+ 0x04d2, 0x04d2,
+ 0x04d4, 0x04d4,
+ 0x04d6, 0x04d6,
+ 0x04d8, 0x04d8,
+ 0x04da, 0x04da,
+ 0x04dc, 0x04dc,
+ 0x04de, 0x04de,
+ 0x04e0, 0x04e0,
+ 0x04e2, 0x04e2,
+ 0x04e4, 0x04e4,
+ 0x04e6, 0x04e6,
+ 0x04e8, 0x04e8,
+ 0x04ea, 0x04ea,
+ 0x04ec, 0x04ec,
+ 0x04ee, 0x04ee,
+ 0x04f0, 0x04f0,
+ 0x04f2, 0x04f2,
+ 0x04f4, 0x04f4,
+ 0x04f6, 0x04f6,
+ 0x04f8, 0x04f8,
+ 0x04fa, 0x04fa,
+ 0x04fc, 0x04fc,
+ 0x04fe, 0x04fe,
+ 0x0500, 0x0500,
+ 0x0502, 0x0502,
+ 0x0504, 0x0504,
+ 0x0506, 0x0506,
+ 0x0508, 0x0508,
+ 0x050a, 0x050a,
+ 0x050c, 0x050c,
+ 0x050e, 0x050e,
+ 0x0510, 0x0510,
+ 0x0512, 0x0512,
+ 0x0514, 0x0514,
+ 0x0516, 0x0516,
+ 0x0518, 0x0518,
+ 0x051a, 0x051a,
+ 0x051c, 0x051c,
+ 0x051e, 0x051e,
+ 0x0520, 0x0520,
+ 0x0522, 0x0522,
+ 0x0524, 0x0524,
+ 0x0526, 0x0526,
+ 0x0528, 0x0528,
+ 0x052a, 0x052a,
+ 0x052c, 0x052c,
+ 0x052e, 0x052e,
+ 0x0531, 0x0556,
+ 0x0587, 0x0587,
+ 0x10a0, 0x10c5,
+ 0x10c7, 0x10c7,
+ 0x10cd, 0x10cd,
+ 0x13f8, 0x13fd,
+ 0x1c80, 0x1c89,
+ 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,
+ 0x1e9a, 0x1e9b,
+ 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,
+ 0x1f80, 0x1faf,
+ 0x1fb2, 0x1fb4,
+ 0x1fb7, 0x1fbc,
+ 0x1fc2, 0x1fc4,
+ 0x1fc7, 0x1fcc,
+ 0x1fd8, 0x1fdb,
+ 0x1fe8, 0x1fec,
+ 0x1ff2, 0x1ff4,
+ 0x1ff7, 0x1ffc,
+ 0x2126, 0x2126,
+ 0x212a, 0x212b,
+ 0x2132, 0x2132,
+ 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,
+ 0xa7cb, 0xa7cc,
+ 0xa7ce, 0xa7ce,
+ 0xa7d0, 0xa7d0,
+ 0xa7d2, 0xa7d2,
+ 0xa7d4, 0xa7d4,
+ 0xa7d6, 0xa7d6,
+ 0xa7d8, 0xa7d8,
+ 0xa7da, 0xa7da,
+ 0xa7dc, 0xa7dc,
+ 0xa7f5, 0xa7f5,
+ 0xab70, 0xabbf,
+ 0xfb00, 0xfb06,
+ 0xfb13, 0xfb17,
+ 0xff21, 0xff3a,
+ 0x10400, 0x10427,
+ 0x104b0, 0x104d3,
+ 0x10570, 0x1057a,
+ 0x1057c, 0x1058a,
+ 0x1058c, 0x10592,
+ 0x10594, 0x10595,
+ 0x10c80, 0x10cb2,
+ 0x10d50, 0x10d65,
+ 0x118a0, 0x118bf,
+ 0x16e40, 0x16e5f,
+ 0x16ea0, 0x16eb8,
+ 0x1e900, 0x1e921,
+}; /* CR_Changes_When_Casefolded */
+
+/* 'Changes_When_Casemapped': Derived Property */
+static const OnigCodePoint CR_Changes_When_Casemapped[] = {
+ 131,
+ 0x0041, 0x005a,
+ 0x0061, 0x007a,
+ 0x00b5, 0x00b5,
+ 0x00c0, 0x00d6,
+ 0x00d8, 0x00f6,
+ 0x00f8, 0x0137,
+ 0x0139, 0x018c,
+ 0x018e, 0x01a9,
+ 0x01ac, 0x01b9,
+ 0x01bc, 0x01bd,
+ 0x01bf, 0x01bf,
+ 0x01c4, 0x0220,
+ 0x0222, 0x0233,
+ 0x023a, 0x0254,
+ 0x0256, 0x0257,
+ 0x0259, 0x0259,
+ 0x025b, 0x025c,
+ 0x0260, 0x0261,
+ 0x0263, 0x0266,
+ 0x0268, 0x026c,
+ 0x026f, 0x026f,
+ 0x0271, 0x0272,
+ 0x0275, 0x0275,
+ 0x027d, 0x027d,
+ 0x0280, 0x0280,
+ 0x0282, 0x0283,
+ 0x0287, 0x028c,
+ 0x0292, 0x0292,
+ 0x029d, 0x029e,
+ 0x0345, 0x0345,
+ 0x0370, 0x0373,
+ 0x0376, 0x0377,
+ 0x037b, 0x037d,
+ 0x037f, 0x037f,
+ 0x0386, 0x0386,
+ 0x0388, 0x038a,
+ 0x038c, 0x038c,
+ 0x038e, 0x03a1,
+ 0x03a3, 0x03d1,
+ 0x03d5, 0x03f5,
+ 0x03f7, 0x03fb,
+ 0x03fd, 0x0481,
+ 0x048a, 0x052f,
+ 0x0531, 0x0556,
+ 0x0561, 0x0587,
+ 0x10a0, 0x10c5,
+ 0x10c7, 0x10c7,
+ 0x10cd, 0x10cd,
+ 0x10d0, 0x10fa,
+ 0x10fd, 0x10ff,
+ 0x13a0, 0x13f5,
+ 0x13f8, 0x13fd,
+ 0x1c80, 0x1c8a,
+ 0x1c90, 0x1cba,
+ 0x1cbd, 0x1cbf,
+ 0x1d79, 0x1d79,
+ 0x1d7d, 0x1d7d,
+ 0x1d8e, 0x1d8e,
+ 0x1e00, 0x1e9b,
+ 0x1e9e, 0x1e9e,
+ 0x1ea0, 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,
+ 0x2126, 0x2126,
+ 0x212a, 0x212b,
+ 0x2132, 0x2132,
+ 0x214e, 0x214e,
+ 0x2160, 0x217f,
+ 0x2183, 0x2184,
+ 0x24b6, 0x24e9,
+ 0x2c00, 0x2c70,
+ 0x2c72, 0x2c73,
+ 0x2c75, 0x2c76,
+ 0x2c7e, 0x2ce3,
+ 0x2ceb, 0x2cee,
+ 0x2cf2, 0x2cf3,
+ 0x2d00, 0x2d25,
+ 0x2d27, 0x2d27,
+ 0x2d2d, 0x2d2d,
+ 0xa640, 0xa66d,
+ 0xa680, 0xa69b,
+ 0xa722, 0xa72f,
+ 0xa732, 0xa76f,
+ 0xa779, 0xa787,
+ 0xa78b, 0xa78d,
+ 0xa790, 0xa794,
+ 0xa796, 0xa7ae,
+ 0xa7b0, 0xa7dc,
+ 0xa7f5, 0xa7f6,
+ 0xab53, 0xab53,
+ 0xab70, 0xabbf,
+ 0xfb00, 0xfb06,
+ 0xfb13, 0xfb17,
+ 0xff21, 0xff3a,
+ 0xff41, 0xff5a,
+ 0x10400, 0x1044f,
+ 0x104b0, 0x104d3,
+ 0x104d8, 0x104fb,
+ 0x10570, 0x1057a,
+ 0x1057c, 0x1058a,
+ 0x1058c, 0x10592,
+ 0x10594, 0x10595,
+ 0x10597, 0x105a1,
+ 0x105a3, 0x105b1,
+ 0x105b3, 0x105b9,
+ 0x105bb, 0x105bc,
+ 0x10c80, 0x10cb2,
+ 0x10cc0, 0x10cf2,
+ 0x10d50, 0x10d65,
+ 0x10d70, 0x10d85,
+ 0x118a0, 0x118df,
+ 0x16e40, 0x16e7f,
+ 0x16ea0, 0x16eb8,
+ 0x16ebb, 0x16ed3,
+ 0x1e900, 0x1e943,
+}; /* CR_Changes_When_Casemapped */
+
+/* 'ID_Start': Derived Property */
+static const OnigCodePoint CR_ID_Start[] = {
+ 684,
+ 0x0041, 0x005a,
+ 0x0061, 0x007a,
+ 0x00aa, 0x00aa,
+ 0x00b5, 0x00b5,
+ 0x00ba, 0x00ba,
+ 0x00c0, 0x00d6,
+ 0x00d8, 0x00f6,
+ 0x00f8, 0x02c1,
+ 0x02c6, 0x02d1,
+ 0x02e0, 0x02e4,
+ 0x02ec, 0x02ec,
+ 0x02ee, 0x02ee,
+ 0x0370, 0x0374,
+ 0x0376, 0x0377,
+ 0x037a, 0x037d,
+ 0x037f, 0x037f,
+ 0x0386, 0x0386,
+ 0x0388, 0x038a,
+ 0x038c, 0x038c,
+ 0x038e, 0x03a1,
+ 0x03a3, 0x03f5,
+ 0x03f7, 0x0481,
+ 0x048a, 0x052f,
+ 0x0531, 0x0556,
+ 0x0559, 0x0559,
+ 0x0560, 0x0588,
+ 0x05d0, 0x05ea,
+ 0x05ef, 0x05f2,
+ 0x0620, 0x064a,
+ 0x066e, 0x066f,
+ 0x0671, 0x06d3,
+ 0x06d5, 0x06d5,
+ 0x06e5, 0x06e6,
+ 0x06ee, 0x06ef,
+ 0x06fa, 0x06fc,
+ 0x06ff, 0x06ff,
+ 0x0710, 0x0710,
+ 0x0712, 0x072f,
+ 0x074d, 0x07a5,
+ 0x07b1, 0x07b1,
+ 0x07ca, 0x07ea,
+ 0x07f4, 0x07f5,
+ 0x07fa, 0x07fa,
+ 0x0800, 0x0815,
+ 0x081a, 0x081a,
+ 0x0824, 0x0824,
+ 0x0828, 0x0828,
+ 0x0840, 0x0858,
+ 0x0860, 0x086a,
+ 0x0870, 0x0887,
+ 0x0889, 0x088f,
+ 0x08a0, 0x08c9,
+ 0x0904, 0x0939,
+ 0x093d, 0x093d,
+ 0x0950, 0x0950,
+ 0x0958, 0x0961,
+ 0x0971, 0x0980,
+ 0x0985, 0x098c,
+ 0x098f, 0x0990,
+ 0x0993, 0x09a8,
+ 0x09aa, 0x09b0,
+ 0x09b2, 0x09b2,
+ 0x09b6, 0x09b9,
+ 0x09bd, 0x09bd,
+ 0x09ce, 0x09ce,
+ 0x09dc, 0x09dd,
+ 0x09df, 0x09e1,
+ 0x09f0, 0x09f1,
+ 0x09fc, 0x09fc,
+ 0x0a05, 0x0a0a,
+ 0x0a0f, 0x0a10,
+ 0x0a13, 0x0a28,
+ 0x0a2a, 0x0a30,
+ 0x0a32, 0x0a33,
+ 0x0a35, 0x0a36,
+ 0x0a38, 0x0a39,
+ 0x0a59, 0x0a5c,
+ 0x0a5e, 0x0a5e,
+ 0x0a72, 0x0a74,
+ 0x0a85, 0x0a8d,
+ 0x0a8f, 0x0a91,
+ 0x0a93, 0x0aa8,
+ 0x0aaa, 0x0ab0,
+ 0x0ab2, 0x0ab3,
+ 0x0ab5, 0x0ab9,
+ 0x0abd, 0x0abd,
+ 0x0ad0, 0x0ad0,
+ 0x0ae0, 0x0ae1,
+ 0x0af9, 0x0af9,
+ 0x0b05, 0x0b0c,
+ 0x0b0f, 0x0b10,
+ 0x0b13, 0x0b28,
+ 0x0b2a, 0x0b30,
+ 0x0b32, 0x0b33,
+ 0x0b35, 0x0b39,
+ 0x0b3d, 0x0b3d,
+ 0x0b5c, 0x0b5d,
+ 0x0b5f, 0x0b61,
+ 0x0b71, 0x0b71,
+ 0x0b83, 0x0b83,
+ 0x0b85, 0x0b8a,
+ 0x0b8e, 0x0b90,
+ 0x0b92, 0x0b95,
+ 0x0b99, 0x0b9a,
+ 0x0b9c, 0x0b9c,
+ 0x0b9e, 0x0b9f,
+ 0x0ba3, 0x0ba4,
+ 0x0ba8, 0x0baa,
+ 0x0bae, 0x0bb9,
+ 0x0bd0, 0x0bd0,
+ 0x0c05, 0x0c0c,
+ 0x0c0e, 0x0c10,
+ 0x0c12, 0x0c28,
+ 0x0c2a, 0x0c39,
+ 0x0c3d, 0x0c3d,
+ 0x0c58, 0x0c5a,
+ 0x0c5c, 0x0c5d,
+ 0x0c60, 0x0c61,
+ 0x0c80, 0x0c80,
+ 0x0c85, 0x0c8c,
+ 0x0c8e, 0x0c90,
+ 0x0c92, 0x0ca8,
+ 0x0caa, 0x0cb3,
+ 0x0cb5, 0x0cb9,
+ 0x0cbd, 0x0cbd,
+ 0x0cdc, 0x0cde,
+ 0x0ce0, 0x0ce1,
+ 0x0cf1, 0x0cf2,
+ 0x0d04, 0x0d0c,
+ 0x0d0e, 0x0d10,
+ 0x0d12, 0x0d3a,
+ 0x0d3d, 0x0d3d,
+ 0x0d4e, 0x0d4e,
+ 0x0d54, 0x0d56,
+ 0x0d5f, 0x0d61,
+ 0x0d7a, 0x0d7f,
+ 0x0d85, 0x0d96,
+ 0x0d9a, 0x0db1,
+ 0x0db3, 0x0dbb,
+ 0x0dbd, 0x0dbd,
+ 0x0dc0, 0x0dc6,
+ 0x0e01, 0x0e30,
+ 0x0e32, 0x0e33,
+ 0x0e40, 0x0e46,
+ 0x0e81, 0x0e82,
+ 0x0e84, 0x0e84,
+ 0x0e86, 0x0e8a,
+ 0x0e8c, 0x0ea3,
+ 0x0ea5, 0x0ea5,
+ 0x0ea7, 0x0eb0,
+ 0x0eb2, 0x0eb3,
+ 0x0ebd, 0x0ebd,
+ 0x0ec0, 0x0ec4,
+ 0x0ec6, 0x0ec6,
+ 0x0edc, 0x0edf,
+ 0x0f00, 0x0f00,
+ 0x0f40, 0x0f47,
+ 0x0f49, 0x0f6c,
+ 0x0f88, 0x0f8c,
+ 0x1000, 0x102a,
+ 0x103f, 0x103f,
+ 0x1050, 0x1055,
+ 0x105a, 0x105d,
+ 0x1061, 0x1061,
+ 0x1065, 0x1066,
+ 0x106e, 0x1070,
+ 0x1075, 0x1081,
+ 0x108e, 0x108e,
+ 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, 0x1711,
+ 0x171f, 0x1731,
+ 0x1740, 0x1751,
+ 0x1760, 0x176c,
+ 0x176e, 0x1770,
+ 0x1780, 0x17b3,
+ 0x17d7, 0x17d7,
+ 0x17dc, 0x17dc,
+ 0x1820, 0x1878,
+ 0x1880, 0x18a8,
+ 0x18aa, 0x18aa,
+ 0x18b0, 0x18f5,
+ 0x1900, 0x191e,
+ 0x1950, 0x196d,
+ 0x1970, 0x1974,
+ 0x1980, 0x19ab,
+ 0x19b0, 0x19c9,
+ 0x1a00, 0x1a16,
+ 0x1a20, 0x1a54,
+ 0x1aa7, 0x1aa7,
+ 0x1b05, 0x1b33,
+ 0x1b45, 0x1b4c,
+ 0x1b83, 0x1ba0,
+ 0x1bae, 0x1baf,
+ 0x1bba, 0x1be5,
+ 0x1c00, 0x1c23,
+ 0x1c4d, 0x1c4f,
+ 0x1c5a, 0x1c7d,
+ 0x1c80, 0x1c8a,
+ 0x1c90, 0x1cba,
+ 0x1cbd, 0x1cbf,
+ 0x1ce9, 0x1cec,
+ 0x1cee, 0x1cf3,
+ 0x1cf5, 0x1cf6,
+ 0x1cfa, 0x1cfa,
+ 0x1d00, 0x1dbf,
+ 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,
+ 0x2118, 0x211d,
+ 0x2124, 0x2124,
+ 0x2126, 0x2126,
+ 0x2128, 0x2128,
+ 0x212a, 0x2139,
+ 0x213c, 0x213f,
+ 0x2145, 0x2149,
+ 0x214e, 0x214e,
+ 0x2160, 0x2188,
+ 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,
+ 0x3005, 0x3007,
+ 0x3021, 0x3029,
+ 0x3031, 0x3035,
+ 0x3038, 0x303c,
+ 0x3041, 0x3096,
+ 0x309b, 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,
+ 0xa67f, 0xa69d,
+ 0xa6a0, 0xa6ef,
+ 0xa717, 0xa71f,
+ 0xa722, 0xa788,
+ 0xa78b, 0xa7dc,
+ 0xa7f1, 0xa801,
+ 0xa803, 0xa805,
+ 0xa807, 0xa80a,
+ 0xa80c, 0xa822,
+ 0xa840, 0xa873,
+ 0xa882, 0xa8b3,
+ 0xa8f2, 0xa8f7,
+ 0xa8fb, 0xa8fb,
+ 0xa8fd, 0xa8fe,
+ 0xa90a, 0xa925,
+ 0xa930, 0xa946,
+ 0xa960, 0xa97c,
+ 0xa984, 0xa9b2,
+ 0xa9cf, 0xa9cf,
+ 0xa9e0, 0xa9e4,
+ 0xa9e6, 0xa9ef,
+ 0xa9fa, 0xa9fe,
+ 0xaa00, 0xaa28,
+ 0xaa40, 0xaa42,
+ 0xaa44, 0xaa4b,
+ 0xaa60, 0xaa76,
+ 0xaa7a, 0xaa7a,
+ 0xaa7e, 0xaaaf,
+ 0xaab1, 0xaab1,
+ 0xaab5, 0xaab6,
+ 0xaab9, 0xaabd,
+ 0xaac0, 0xaac0,
+ 0xaac2, 0xaac2,
+ 0xaadb, 0xaadd,
+ 0xaae0, 0xaaea,
+ 0xaaf2, 0xaaf4,
+ 0xab01, 0xab06,
+ 0xab09, 0xab0e,
+ 0xab11, 0xab16,
+ 0xab20, 0xab26,
+ 0xab28, 0xab2e,
+ 0xab30, 0xab5a,
+ 0xab5c, 0xab69,
+ 0xab70, 0xabe2,
+ 0xac00, 0xd7a3,
+ 0xd7b0, 0xd7c6,
+ 0xd7cb, 0xd7fb,
+ 0xf900, 0xfa6d,
+ 0xfa70, 0xfad9,
+ 0xfb00, 0xfb06,
+ 0xfb13, 0xfb17,
+ 0xfb1d, 0xfb1d,
+ 0xfb1f, 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, 0x10375,
+ 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,
+ 0x105c0, 0x105f3,
+ 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,
+ 0x10940, 0x10959,
+ 0x10980, 0x109b7,
+ 0x109be, 0x109bf,
+ 0x10a00, 0x10a00,
+ 0x10a10, 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, 0x10d23,
+ 0x10d4a, 0x10d65,
+ 0x10d6f, 0x10d85,
+ 0x10e80, 0x10ea9,
+ 0x10eb0, 0x10eb1,
+ 0x10ec2, 0x10ec7,
+ 0x10f00, 0x10f1c,
+ 0x10f27, 0x10f27,
+ 0x10f30, 0x10f45,
+ 0x10f70, 0x10f81,
+ 0x10fb0, 0x10fc4,
+ 0x10fe0, 0x10ff6,
+ 0x11003, 0x11037,
+ 0x11071, 0x11072,
+ 0x11075, 0x11075,
+ 0x11083, 0x110af,
+ 0x110d0, 0x110e8,
+ 0x11103, 0x11126,
+ 0x11144, 0x11144,
+ 0x11147, 0x11147,
+ 0x11150, 0x11172,
+ 0x11176, 0x11176,
+ 0x11183, 0x111b2,
+ 0x111c1, 0x111c4,
+ 0x111da, 0x111da,
+ 0x111dc, 0x111dc,
+ 0x11200, 0x11211,
+ 0x11213, 0x1122b,
+ 0x1123f, 0x11240,
+ 0x11280, 0x11286,
+ 0x11288, 0x11288,
+ 0x1128a, 0x1128d,
+ 0x1128f, 0x1129d,
+ 0x1129f, 0x112a8,
+ 0x112b0, 0x112de,
+ 0x11305, 0x1130c,
+ 0x1130f, 0x11310,
+ 0x11313, 0x11328,
+ 0x1132a, 0x11330,
+ 0x11332, 0x11333,
+ 0x11335, 0x11339,
+ 0x1133d, 0x1133d,
+ 0x11350, 0x11350,
+ 0x1135d, 0x11361,
+ 0x11380, 0x11389,
+ 0x1138b, 0x1138b,
+ 0x1138e, 0x1138e,
+ 0x11390, 0x113b5,
+ 0x113b7, 0x113b7,
+ 0x113d1, 0x113d1,
+ 0x113d3, 0x113d3,
+ 0x11400, 0x11434,
+ 0x11447, 0x1144a,
+ 0x1145f, 0x11461,
+ 0x11480, 0x114af,
+ 0x114c4, 0x114c5,
+ 0x114c7, 0x114c7,
+ 0x11580, 0x115ae,
+ 0x115d8, 0x115db,
+ 0x11600, 0x1162f,
+ 0x11644, 0x11644,
+ 0x11680, 0x116aa,
+ 0x116b8, 0x116b8,
+ 0x11700, 0x1171a,
+ 0x11740, 0x11746,
+ 0x11800, 0x1182b,
+ 0x118a0, 0x118df,
+ 0x118ff, 0x11906,
+ 0x11909, 0x11909,
+ 0x1190c, 0x11913,
+ 0x11915, 0x11916,
+ 0x11918, 0x1192f,
+ 0x1193f, 0x1193f,
+ 0x11941, 0x11941,
+ 0x119a0, 0x119a7,
+ 0x119aa, 0x119d0,
+ 0x119e1, 0x119e1,
+ 0x119e3, 0x119e3,
+ 0x11a00, 0x11a00,
+ 0x11a0b, 0x11a32,
+ 0x11a3a, 0x11a3a,
+ 0x11a50, 0x11a50,
+ 0x11a5c, 0x11a89,
+ 0x11a9d, 0x11a9d,
+ 0x11ab0, 0x11af8,
+ 0x11bc0, 0x11be0,
+ 0x11c00, 0x11c08,
+ 0x11c0a, 0x11c2e,
+ 0x11c40, 0x11c40,
+ 0x11c72, 0x11c8f,
+ 0x11d00, 0x11d06,
+ 0x11d08, 0x11d09,
+ 0x11d0b, 0x11d30,
+ 0x11d46, 0x11d46,
+ 0x11d60, 0x11d65,
+ 0x11d67, 0x11d68,
+ 0x11d6a, 0x11d89,
+ 0x11d98, 0x11d98,
+ 0x11db0, 0x11ddb,
+ 0x11ee0, 0x11ef2,
+ 0x11f02, 0x11f02,
+ 0x11f04, 0x11f10,
+ 0x11f12, 0x11f33,
+ 0x11fb0, 0x11fb0,
+ 0x12000, 0x12399,
+ 0x12400, 0x1246e,
+ 0x12480, 0x12543,
+ 0x12f90, 0x12ff0,
+ 0x13000, 0x1342f,
+ 0x13441, 0x13446,
+ 0x13460, 0x143fa,
+ 0x14400, 0x14646,
+ 0x16100, 0x1611d,
+ 0x16800, 0x16a38,
+ 0x16a40, 0x16a5e,
+ 0x16a70, 0x16abe,
+ 0x16ad0, 0x16aed,
+ 0x16b00, 0x16b2f,
+ 0x16b40, 0x16b43,
+ 0x16b63, 0x16b77,
+ 0x16b7d, 0x16b8f,
+ 0x16d40, 0x16d6c,
+ 0x16e40, 0x16e7f,
+ 0x16ea0, 0x16eb8,
+ 0x16ebb, 0x16ed3,
+ 0x16f00, 0x16f4a,
+ 0x16f50, 0x16f50,
+ 0x16f93, 0x16f9f,
+ 0x16fe0, 0x16fe1,
+ 0x16fe3, 0x16fe3,
+ 0x16ff2, 0x16ff6,
+ 0x17000, 0x18cd5,
+ 0x18cff, 0x18d1e,
+ 0x18d80, 0x18df2,
+ 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,
+ 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,
+ 0x1e030, 0x1e06d,
+ 0x1e100, 0x1e12c,
+ 0x1e137, 0x1e13d,
+ 0x1e14e, 0x1e14e,
+ 0x1e290, 0x1e2ad,
+ 0x1e2c0, 0x1e2eb,
+ 0x1e4d0, 0x1e4eb,
+ 0x1e5d0, 0x1e5ed,
+ 0x1e5f0, 0x1e5f0,
+ 0x1e6c0, 0x1e6de,
+ 0x1e6e0, 0x1e6e2,
+ 0x1e6e4, 0x1e6e5,
+ 0x1e6e7, 0x1e6ed,
+ 0x1e6f0, 0x1e6f4,
+ 0x1e6fe, 0x1e6ff,
+ 0x1e7e0, 0x1e7e6,
+ 0x1e7e8, 0x1e7eb,
+ 0x1e7ed, 0x1e7ee,
+ 0x1e7f0, 0x1e7fe,
+ 0x1e800, 0x1e8c4,
+ 0x1e900, 0x1e943,
+ 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,
+ 0x20000, 0x2a6df,
+ 0x2a700, 0x2b81d,
+ 0x2b820, 0x2cead,
+ 0x2ceb0, 0x2ebe0,
+ 0x2ebf0, 0x2ee5d,
+ 0x2f800, 0x2fa1d,
+ 0x30000, 0x3134a,
+ 0x31350, 0x33479,
+}; /* CR_ID_Start */
+
+/* 'ID_Continue': Derived Property */
+static const OnigCodePoint CR_ID_Continue[] = {
+ 799,
+ 0x0030, 0x0039,
+ 0x0041, 0x005a,
+ 0x005f, 0x005f,
+ 0x0061, 0x007a,
+ 0x00aa, 0x00aa,
+ 0x00b5, 0x00b5,
+ 0x00b7, 0x00b7,
+ 0x00ba, 0x00ba,
+ 0x00c0, 0x00d6,
+ 0x00d8, 0x00f6,
+ 0x00f8, 0x02c1,
+ 0x02c6, 0x02d1,
+ 0x02e0, 0x02e4,
+ 0x02ec, 0x02ec,
+ 0x02ee, 0x02ee,
+ 0x0300, 0x0374,
+ 0x0376, 0x0377,
+ 0x037a, 0x037d,
+ 0x037f, 0x037f,
+ 0x0386, 0x038a,
+ 0x038c, 0x038c,
+ 0x038e, 0x03a1,
+ 0x03a3, 0x03f5,
+ 0x03f7, 0x0481,
+ 0x0483, 0x0487,
+ 0x048a, 0x052f,
+ 0x0531, 0x0556,
+ 0x0559, 0x0559,
+ 0x0560, 0x0588,
+ 0x0591, 0x05bd,
+ 0x05bf, 0x05bf,
+ 0x05c1, 0x05c2,
+ 0x05c4, 0x05c5,
+ 0x05c7, 0x05c7,
+ 0x05d0, 0x05ea,
+ 0x05ef, 0x05f2,
+ 0x0610, 0x061a,
+ 0x0620, 0x0669,
+ 0x066e, 0x06d3,
+ 0x06d5, 0x06dc,
+ 0x06df, 0x06e8,
+ 0x06ea, 0x06fc,
+ 0x06ff, 0x06ff,
+ 0x0710, 0x074a,
+ 0x074d, 0x07b1,
+ 0x07c0, 0x07f5,
+ 0x07fa, 0x07fa,
+ 0x07fd, 0x07fd,
+ 0x0800, 0x082d,
+ 0x0840, 0x085b,
+ 0x0860, 0x086a,
+ 0x0870, 0x0887,
+ 0x0889, 0x088f,
+ 0x0897, 0x08e1,
+ 0x08e3, 0x0963,
+ 0x0966, 0x096f,
+ 0x0971, 0x0983,
+ 0x0985, 0x098c,
+ 0x098f, 0x0990,
+ 0x0993, 0x09a8,
+ 0x09aa, 0x09b0,
+ 0x09b2, 0x09b2,
+ 0x09b6, 0x09b9,
+ 0x09bc, 0x09c4,
+ 0x09c7, 0x09c8,
+ 0x09cb, 0x09ce,
+ 0x09d7, 0x09d7,
+ 0x09dc, 0x09dd,
+ 0x09df, 0x09e3,
+ 0x09e6, 0x09f1,
+ 0x09fc, 0x09fc,
+ 0x09fe, 0x09fe,
+ 0x0a01, 0x0a03,
+ 0x0a05, 0x0a0a,
+ 0x0a0f, 0x0a10,
+ 0x0a13, 0x0a28,
+ 0x0a2a, 0x0a30,
+ 0x0a32, 0x0a33,
+ 0x0a35, 0x0a36,
+ 0x0a38, 0x0a39,
+ 0x0a3c, 0x0a3c,
+ 0x0a3e, 0x0a42,
+ 0x0a47, 0x0a48,
+ 0x0a4b, 0x0a4d,
+ 0x0a51, 0x0a51,
+ 0x0a59, 0x0a5c,
+ 0x0a5e, 0x0a5e,
+ 0x0a66, 0x0a75,
+ 0x0a81, 0x0a83,
+ 0x0a85, 0x0a8d,
+ 0x0a8f, 0x0a91,
+ 0x0a93, 0x0aa8,
+ 0x0aaa, 0x0ab0,
+ 0x0ab2, 0x0ab3,
+ 0x0ab5, 0x0ab9,
+ 0x0abc, 0x0ac5,
+ 0x0ac7, 0x0ac9,
+ 0x0acb, 0x0acd,
+ 0x0ad0, 0x0ad0,
+ 0x0ae0, 0x0ae3,
+ 0x0ae6, 0x0aef,
+ 0x0af9, 0x0aff,
+ 0x0b01, 0x0b03,
+ 0x0b05, 0x0b0c,
+ 0x0b0f, 0x0b10,
+ 0x0b13, 0x0b28,
+ 0x0b2a, 0x0b30,
+ 0x0b32, 0x0b33,
+ 0x0b35, 0x0b39,
+ 0x0b3c, 0x0b44,
+ 0x0b47, 0x0b48,
+ 0x0b4b, 0x0b4d,
+ 0x0b55, 0x0b57,
+ 0x0b5c, 0x0b5d,
+ 0x0b5f, 0x0b63,
+ 0x0b66, 0x0b6f,
+ 0x0b71, 0x0b71,
+ 0x0b82, 0x0b83,
+ 0x0b85, 0x0b8a,
+ 0x0b8e, 0x0b90,
+ 0x0b92, 0x0b95,
+ 0x0b99, 0x0b9a,
+ 0x0b9c, 0x0b9c,
+ 0x0b9e, 0x0b9f,
+ 0x0ba3, 0x0ba4,
+ 0x0ba8, 0x0baa,
+ 0x0bae, 0x0bb9,
+ 0x0bbe, 0x0bc2,
+ 0x0bc6, 0x0bc8,
+ 0x0bca, 0x0bcd,
+ 0x0bd0, 0x0bd0,
+ 0x0bd7, 0x0bd7,
+ 0x0be6, 0x0bef,
+ 0x0c00, 0x0c0c,
+ 0x0c0e, 0x0c10,
+ 0x0c12, 0x0c28,
+ 0x0c2a, 0x0c39,
+ 0x0c3c, 0x0c44,
+ 0x0c46, 0x0c48,
+ 0x0c4a, 0x0c4d,
+ 0x0c55, 0x0c56,
+ 0x0c58, 0x0c5a,
+ 0x0c5c, 0x0c5d,
+ 0x0c60, 0x0c63,
+ 0x0c66, 0x0c6f,
+ 0x0c80, 0x0c83,
+ 0x0c85, 0x0c8c,
+ 0x0c8e, 0x0c90,
+ 0x0c92, 0x0ca8,
+ 0x0caa, 0x0cb3,
+ 0x0cb5, 0x0cb9,
+ 0x0cbc, 0x0cc4,
+ 0x0cc6, 0x0cc8,
+ 0x0cca, 0x0ccd,
+ 0x0cd5, 0x0cd6,
+ 0x0cdc, 0x0cde,
+ 0x0ce0, 0x0ce3,
+ 0x0ce6, 0x0cef,
+ 0x0cf1, 0x0cf3,
+ 0x0d00, 0x0d0c,
+ 0x0d0e, 0x0d10,
+ 0x0d12, 0x0d44,
+ 0x0d46, 0x0d48,
+ 0x0d4a, 0x0d4e,
+ 0x0d54, 0x0d57,
+ 0x0d5f, 0x0d63,
+ 0x0d66, 0x0d6f,
+ 0x0d7a, 0x0d7f,
+ 0x0d81, 0x0d83,
+ 0x0d85, 0x0d96,
+ 0x0d9a, 0x0db1,
+ 0x0db3, 0x0dbb,
+ 0x0dbd, 0x0dbd,
+ 0x0dc0, 0x0dc6,
+ 0x0dca, 0x0dca,
+ 0x0dcf, 0x0dd4,
+ 0x0dd6, 0x0dd6,
+ 0x0dd8, 0x0ddf,
+ 0x0de6, 0x0def,
+ 0x0df2, 0x0df3,
+ 0x0e01, 0x0e3a,
+ 0x0e40, 0x0e4e,
+ 0x0e50, 0x0e59,
+ 0x0e81, 0x0e82,
+ 0x0e84, 0x0e84,
+ 0x0e86, 0x0e8a,
+ 0x0e8c, 0x0ea3,
+ 0x0ea5, 0x0ea5,
+ 0x0ea7, 0x0ebd,
+ 0x0ec0, 0x0ec4,
+ 0x0ec6, 0x0ec6,
+ 0x0ec8, 0x0ece,
+ 0x0ed0, 0x0ed9,
+ 0x0edc, 0x0edf,
+ 0x0f00, 0x0f00,
+ 0x0f18, 0x0f19,
+ 0x0f20, 0x0f29,
+ 0x0f35, 0x0f35,
+ 0x0f37, 0x0f37,
+ 0x0f39, 0x0f39,
+ 0x0f3e, 0x0f47,
+ 0x0f49, 0x0f6c,
+ 0x0f71, 0x0f84,
+ 0x0f86, 0x0f97,
+ 0x0f99, 0x0fbc,
+ 0x0fc6, 0x0fc6,
+ 0x1000, 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,
+ 0x135d, 0x135f,
+ 0x1369, 0x1371,
+ 0x1380, 0x138f,
+ 0x13a0, 0x13f5,
+ 0x13f8, 0x13fd,
+ 0x1401, 0x166c,
+ 0x166f, 0x167f,
+ 0x1681, 0x169a,
+ 0x16a0, 0x16ea,
+ 0x16ee, 0x16f8,
+ 0x1700, 0x1715,
+ 0x171f, 0x1734,
+ 0x1740, 0x1753,
+ 0x1760, 0x176c,
+ 0x176e, 0x1770,
+ 0x1772, 0x1773,
+ 0x1780, 0x17d3,
+ 0x17d7, 0x17d7,
+ 0x17dc, 0x17dd,
+ 0x17e0, 0x17e9,
+ 0x180b, 0x180d,
+ 0x180f, 0x1819,
+ 0x1820, 0x1878,
+ 0x1880, 0x18aa,
+ 0x18b0, 0x18f5,
+ 0x1900, 0x191e,
+ 0x1920, 0x192b,
+ 0x1930, 0x193b,
+ 0x1946, 0x196d,
+ 0x1970, 0x1974,
+ 0x1980, 0x19ab,
+ 0x19b0, 0x19c9,
+ 0x19d0, 0x19da,
+ 0x1a00, 0x1a1b,
+ 0x1a20, 0x1a5e,
+ 0x1a60, 0x1a7c,
+ 0x1a7f, 0x1a89,
+ 0x1a90, 0x1a99,
+ 0x1aa7, 0x1aa7,
+ 0x1ab0, 0x1abd,
+ 0x1abf, 0x1add,
+ 0x1ae0, 0x1aeb,
+ 0x1b00, 0x1b4c,
+ 0x1b50, 0x1b59,
+ 0x1b6b, 0x1b73,
+ 0x1b80, 0x1bf3,
+ 0x1c00, 0x1c37,
+ 0x1c40, 0x1c49,
+ 0x1c4d, 0x1c7d,
+ 0x1c80, 0x1c8a,
+ 0x1c90, 0x1cba,
+ 0x1cbd, 0x1cbf,
+ 0x1cd0, 0x1cd2,
+ 0x1cd4, 0x1cfa,
+ 0x1d00, 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,
+ 0x200c, 0x200d,
+ 0x203f, 0x2040,
+ 0x2054, 0x2054,
+ 0x2071, 0x2071,
+ 0x207f, 0x207f,
+ 0x2090, 0x209c,
+ 0x20d0, 0x20dc,
+ 0x20e1, 0x20e1,
+ 0x20e5, 0x20f0,
+ 0x2102, 0x2102,
+ 0x2107, 0x2107,
+ 0x210a, 0x2113,
+ 0x2115, 0x2115,
+ 0x2118, 0x211d,
+ 0x2124, 0x2124,
+ 0x2126, 0x2126,
+ 0x2128, 0x2128,
+ 0x212a, 0x2139,
+ 0x213c, 0x213f,
+ 0x2145, 0x2149,
+ 0x214e, 0x214e,
+ 0x2160, 0x2188,
+ 0x2c00, 0x2ce4,
+ 0x2ceb, 0x2cf3,
+ 0x2d00, 0x2d25,
+ 0x2d27, 0x2d27,
+ 0x2d2d, 0x2d2d,
+ 0x2d30, 0x2d67,
+ 0x2d6f, 0x2d6f,
+ 0x2d7f, 0x2d96,
+ 0x2da0, 0x2da6,
+ 0x2da8, 0x2dae,
+ 0x2db0, 0x2db6,
+ 0x2db8, 0x2dbe,
+ 0x2dc0, 0x2dc6,
+ 0x2dc8, 0x2dce,
+ 0x2dd0, 0x2dd6,
+ 0x2dd8, 0x2dde,
+ 0x2de0, 0x2dff,
+ 0x3005, 0x3007,
+ 0x3021, 0x302f,
+ 0x3031, 0x3035,
+ 0x3038, 0x303c,
+ 0x3041, 0x3096,
+ 0x3099, 0x309f,
+ 0x30a1, 0x30ff,
+ 0x3105, 0x312f,
+ 0x3131, 0x318e,
+ 0x31a0, 0x31bf,
+ 0x31f0, 0x31ff,
+ 0x3400, 0x4dbf,
+ 0x4e00, 0xa48c,
+ 0xa4d0, 0xa4fd,
+ 0xa500, 0xa60c,
+ 0xa610, 0xa62b,
+ 0xa640, 0xa66f,
+ 0xa674, 0xa67d,
+ 0xa67f, 0xa6f1,
+ 0xa717, 0xa71f,
+ 0xa722, 0xa788,
+ 0xa78b, 0xa7dc,
+ 0xa7f1, 0xa827,
+ 0xa82c, 0xa82c,
+ 0xa840, 0xa873,
+ 0xa880, 0xa8c5,
+ 0xa8d0, 0xa8d9,
+ 0xa8e0, 0xa8f7,
+ 0xa8fb, 0xa8fb,
+ 0xa8fd, 0xa92d,
+ 0xa930, 0xa953,
+ 0xa960, 0xa97c,
+ 0xa980, 0xa9c0,
+ 0xa9cf, 0xa9d9,
+ 0xa9e0, 0xa9fe,
+ 0xaa00, 0xaa36,
+ 0xaa40, 0xaa4d,
+ 0xaa50, 0xaa59,
+ 0xaa60, 0xaa76,
+ 0xaa7a, 0xaac2,
+ 0xaadb, 0xaadd,
+ 0xaae0, 0xaaef,
+ 0xaaf2, 0xaaf6,
+ 0xab01, 0xab06,
+ 0xab09, 0xab0e,
+ 0xab11, 0xab16,
+ 0xab20, 0xab26,
+ 0xab28, 0xab2e,
+ 0xab30, 0xab5a,
+ 0xab5c, 0xab69,
+ 0xab70, 0xabea,
+ 0xabec, 0xabed,
+ 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,
+ 0xfe00, 0xfe0f,
+ 0xfe20, 0xfe2f,
+ 0xfe33, 0xfe34,
+ 0xfe4d, 0xfe4f,
+ 0xfe70, 0xfe74,
+ 0xfe76, 0xfefc,
+ 0xff10, 0xff19,
+ 0xff21, 0xff3a,
+ 0xff3f, 0xff3f,
+ 0xff41, 0xff5a,
+ 0xff65, 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,
+ 0x101fd, 0x101fd,
+ 0x10280, 0x1029c,
+ 0x102a0, 0x102d0,
+ 0x102e0, 0x102e0,
+ 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,
+ 0x105c0, 0x105f3,
+ 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,
+ 0x10940, 0x10959,
+ 0x10980, 0x109b7,
+ 0x109be, 0x109bf,
+ 0x10a00, 0x10a03,
+ 0x10a05, 0x10a06,
+ 0x10a0c, 0x10a13,
+ 0x10a15, 0x10a17,
+ 0x10a19, 0x10a35,
+ 0x10a38, 0x10a3a,
+ 0x10a3f, 0x10a3f,
+ 0x10a60, 0x10a7c,
+ 0x10a80, 0x10a9c,
+ 0x10ac0, 0x10ac7,
+ 0x10ac9, 0x10ae6,
+ 0x10b00, 0x10b35,
+ 0x10b40, 0x10b55,
+ 0x10b60, 0x10b72,
+ 0x10b80, 0x10b91,
+ 0x10c00, 0x10c48,
+ 0x10c80, 0x10cb2,
+ 0x10cc0, 0x10cf2,
+ 0x10d00, 0x10d27,
+ 0x10d30, 0x10d39,
+ 0x10d40, 0x10d65,
+ 0x10d69, 0x10d6d,
+ 0x10d6f, 0x10d85,
+ 0x10e80, 0x10ea9,
+ 0x10eab, 0x10eac,
+ 0x10eb0, 0x10eb1,
+ 0x10ec2, 0x10ec7,
+ 0x10efa, 0x10f1c,
+ 0x10f27, 0x10f27,
+ 0x10f30, 0x10f50,
+ 0x10f70, 0x10f85,
+ 0x10fb0, 0x10fc4,
+ 0x10fe0, 0x10ff6,
+ 0x11000, 0x11046,
+ 0x11066, 0x11075,
+ 0x1107f, 0x110ba,
+ 0x110c2, 0x110c2,
+ 0x110d0, 0x110e8,
+ 0x110f0, 0x110f9,
+ 0x11100, 0x11134,
+ 0x11136, 0x1113f,
+ 0x11144, 0x11147,
+ 0x11150, 0x11173,
+ 0x11176, 0x11176,
+ 0x11180, 0x111c4,
+ 0x111c9, 0x111cc,
+ 0x111ce, 0x111da,
+ 0x111dc, 0x111dc,
+ 0x11200, 0x11211,
+ 0x11213, 0x11237,
+ 0x1123e, 0x11241,
+ 0x11280, 0x11286,
+ 0x11288, 0x11288,
+ 0x1128a, 0x1128d,
+ 0x1128f, 0x1129d,
+ 0x1129f, 0x112a8,
+ 0x112b0, 0x112ea,
+ 0x112f0, 0x112f9,
+ 0x11300, 0x11303,
+ 0x11305, 0x1130c,
+ 0x1130f, 0x11310,
+ 0x11313, 0x11328,
+ 0x1132a, 0x11330,
+ 0x11332, 0x11333,
+ 0x11335, 0x11339,
+ 0x1133b, 0x11344,
+ 0x11347, 0x11348,
+ 0x1134b, 0x1134d,
+ 0x11350, 0x11350,
+ 0x11357, 0x11357,
+ 0x1135d, 0x11363,
+ 0x11366, 0x1136c,
+ 0x11370, 0x11374,
+ 0x11380, 0x11389,
+ 0x1138b, 0x1138b,
+ 0x1138e, 0x1138e,
+ 0x11390, 0x113b5,
+ 0x113b7, 0x113c0,
+ 0x113c2, 0x113c2,
+ 0x113c5, 0x113c5,
+ 0x113c7, 0x113ca,
+ 0x113cc, 0x113d3,
+ 0x113e1, 0x113e2,
+ 0x11400, 0x1144a,
+ 0x11450, 0x11459,
+ 0x1145e, 0x11461,
+ 0x11480, 0x114c5,
+ 0x114c7, 0x114c7,
+ 0x114d0, 0x114d9,
+ 0x11580, 0x115b5,
+ 0x115b8, 0x115c0,
+ 0x115d8, 0x115dd,
+ 0x11600, 0x11640,
+ 0x11644, 0x11644,
+ 0x11650, 0x11659,
+ 0x11680, 0x116b8,
+ 0x116c0, 0x116c9,
+ 0x116d0, 0x116e3,
+ 0x11700, 0x1171a,
+ 0x1171d, 0x1172b,
+ 0x11730, 0x11739,
+ 0x11740, 0x11746,
+ 0x11800, 0x1183a,
+ 0x118a0, 0x118e9,
+ 0x118ff, 0x11906,
+ 0x11909, 0x11909,
+ 0x1190c, 0x11913,
+ 0x11915, 0x11916,
+ 0x11918, 0x11935,
+ 0x11937, 0x11938,
+ 0x1193b, 0x11943,
+ 0x11950, 0x11959,
+ 0x119a0, 0x119a7,
+ 0x119aa, 0x119d7,
+ 0x119da, 0x119e1,
+ 0x119e3, 0x119e4,
+ 0x11a00, 0x11a3e,
+ 0x11a47, 0x11a47,
+ 0x11a50, 0x11a99,
+ 0x11a9d, 0x11a9d,
+ 0x11ab0, 0x11af8,
+ 0x11b60, 0x11b67,
+ 0x11bc0, 0x11be0,
+ 0x11bf0, 0x11bf9,
+ 0x11c00, 0x11c08,
+ 0x11c0a, 0x11c36,
+ 0x11c38, 0x11c40,
+ 0x11c50, 0x11c59,
+ 0x11c72, 0x11c8f,
+ 0x11c92, 0x11ca7,
+ 0x11ca9, 0x11cb6,
+ 0x11d00, 0x11d06,
+ 0x11d08, 0x11d09,
+ 0x11d0b, 0x11d36,
+ 0x11d3a, 0x11d3a,
+ 0x11d3c, 0x11d3d,
+ 0x11d3f, 0x11d47,
+ 0x11d50, 0x11d59,
+ 0x11d60, 0x11d65,
+ 0x11d67, 0x11d68,
+ 0x11d6a, 0x11d8e,
+ 0x11d90, 0x11d91,
+ 0x11d93, 0x11d98,
+ 0x11da0, 0x11da9,
+ 0x11db0, 0x11ddb,
+ 0x11de0, 0x11de9,
+ 0x11ee0, 0x11ef6,
+ 0x11f00, 0x11f10,
+ 0x11f12, 0x11f3a,
+ 0x11f3e, 0x11f42,
+ 0x11f50, 0x11f5a,
+ 0x11fb0, 0x11fb0,
+ 0x12000, 0x12399,
+ 0x12400, 0x1246e,
+ 0x12480, 0x12543,
+ 0x12f90, 0x12ff0,
+ 0x13000, 0x1342f,
+ 0x13440, 0x13455,
+ 0x13460, 0x143fa,
+ 0x14400, 0x14646,
+ 0x16100, 0x16139,
+ 0x16800, 0x16a38,
+ 0x16a40, 0x16a5e,
+ 0x16a60, 0x16a69,
+ 0x16a70, 0x16abe,
+ 0x16ac0, 0x16ac9,
+ 0x16ad0, 0x16aed,
+ 0x16af0, 0x16af4,
+ 0x16b00, 0x16b36,
+ 0x16b40, 0x16b43,
+ 0x16b50, 0x16b59,
+ 0x16b63, 0x16b77,
+ 0x16b7d, 0x16b8f,
+ 0x16d40, 0x16d6c,
+ 0x16d70, 0x16d79,
+ 0x16e40, 0x16e7f,
+ 0x16ea0, 0x16eb8,
+ 0x16ebb, 0x16ed3,
+ 0x16f00, 0x16f4a,
+ 0x16f4f, 0x16f87,
+ 0x16f8f, 0x16f9f,
+ 0x16fe0, 0x16fe1,
+ 0x16fe3, 0x16fe4,
+ 0x16ff0, 0x16ff6,
+ 0x17000, 0x18cd5,
+ 0x18cff, 0x18d1e,
+ 0x18d80, 0x18df2,
+ 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,
+ 0x1bc9d, 0x1bc9e,
+ 0x1ccf0, 0x1ccf9,
+ 0x1cf00, 0x1cf2d,
+ 0x1cf30, 0x1cf46,
+ 0x1d165, 0x1d169,
+ 0x1d16d, 0x1d172,
+ 0x1d17b, 0x1d182,
+ 0x1d185, 0x1d18b,
+ 0x1d1aa, 0x1d1ad,
+ 0x1d242, 0x1d244,
+ 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,
+ 0x1da00, 0x1da36,
+ 0x1da3b, 0x1da6c,
+ 0x1da75, 0x1da75,
+ 0x1da84, 0x1da84,
+ 0x1da9b, 0x1da9f,
+ 0x1daa1, 0x1daaf,
+ 0x1df00, 0x1df1e,
+ 0x1df25, 0x1df2a,
+ 0x1e000, 0x1e006,
+ 0x1e008, 0x1e018,
+ 0x1e01b, 0x1e021,
+ 0x1e023, 0x1e024,
+ 0x1e026, 0x1e02a,
+ 0x1e030, 0x1e06d,
+ 0x1e08f, 0x1e08f,
+ 0x1e100, 0x1e12c,
+ 0x1e130, 0x1e13d,
+ 0x1e140, 0x1e149,
+ 0x1e14e, 0x1e14e,
+ 0x1e290, 0x1e2ae,
+ 0x1e2c0, 0x1e2f9,
+ 0x1e4d0, 0x1e4f9,
+ 0x1e5d0, 0x1e5fa,
+ 0x1e6c0, 0x1e6de,
+ 0x1e6e0, 0x1e6f5,
+ 0x1e6fe, 0x1e6ff,
+ 0x1e7e0, 0x1e7e6,
+ 0x1e7e8, 0x1e7eb,
+ 0x1e7ed, 0x1e7ee,
+ 0x1e7f0, 0x1e7fe,
+ 0x1e800, 0x1e8c4,
+ 0x1e8d0, 0x1e8d6,
+ 0x1e900, 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,
+ 0x1fbf0, 0x1fbf9,
+ 0x20000, 0x2a6df,
+ 0x2a700, 0x2b81d,
+ 0x2b820, 0x2cead,
+ 0x2ceb0, 0x2ebe0,
+ 0x2ebf0, 0x2ee5d,
+ 0x2f800, 0x2fa1d,
+ 0x30000, 0x3134a,
+ 0x31350, 0x33479,
+ 0xe0100, 0xe01ef,
+}; /* CR_ID_Continue */
+
+/* 'XID_Start': Derived Property */
+static const OnigCodePoint CR_XID_Start[] = {
+ 691,
+ 0x0041, 0x005a,
+ 0x0061, 0x007a,
+ 0x00aa, 0x00aa,
+ 0x00b5, 0x00b5,
+ 0x00ba, 0x00ba,
+ 0x00c0, 0x00d6,
+ 0x00d8, 0x00f6,
+ 0x00f8, 0x02c1,
+ 0x02c6, 0x02d1,
+ 0x02e0, 0x02e4,
+ 0x02ec, 0x02ec,
+ 0x02ee, 0x02ee,
+ 0x0370, 0x0374,
+ 0x0376, 0x0377,
+ 0x037b, 0x037d,
+ 0x037f, 0x037f,
+ 0x0386, 0x0386,
+ 0x0388, 0x038a,
+ 0x038c, 0x038c,
+ 0x038e, 0x03a1,
+ 0x03a3, 0x03f5,
+ 0x03f7, 0x0481,
+ 0x048a, 0x052f,
+ 0x0531, 0x0556,
+ 0x0559, 0x0559,
+ 0x0560, 0x0588,
+ 0x05d0, 0x05ea,
+ 0x05ef, 0x05f2,
+ 0x0620, 0x064a,
+ 0x066e, 0x066f,
+ 0x0671, 0x06d3,
+ 0x06d5, 0x06d5,
+ 0x06e5, 0x06e6,
+ 0x06ee, 0x06ef,
+ 0x06fa, 0x06fc,
+ 0x06ff, 0x06ff,
+ 0x0710, 0x0710,
+ 0x0712, 0x072f,
+ 0x074d, 0x07a5,
+ 0x07b1, 0x07b1,
+ 0x07ca, 0x07ea,
+ 0x07f4, 0x07f5,
+ 0x07fa, 0x07fa,
+ 0x0800, 0x0815,
+ 0x081a, 0x081a,
+ 0x0824, 0x0824,
+ 0x0828, 0x0828,
+ 0x0840, 0x0858,
+ 0x0860, 0x086a,
+ 0x0870, 0x0887,
+ 0x0889, 0x088f,
+ 0x08a0, 0x08c9,
+ 0x0904, 0x0939,
+ 0x093d, 0x093d,
+ 0x0950, 0x0950,
+ 0x0958, 0x0961,
+ 0x0971, 0x0980,
+ 0x0985, 0x098c,
+ 0x098f, 0x0990,
+ 0x0993, 0x09a8,
+ 0x09aa, 0x09b0,
+ 0x09b2, 0x09b2,
+ 0x09b6, 0x09b9,
+ 0x09bd, 0x09bd,
+ 0x09ce, 0x09ce,
+ 0x09dc, 0x09dd,
+ 0x09df, 0x09e1,
+ 0x09f0, 0x09f1,
+ 0x09fc, 0x09fc,
+ 0x0a05, 0x0a0a,
+ 0x0a0f, 0x0a10,
+ 0x0a13, 0x0a28,
+ 0x0a2a, 0x0a30,
+ 0x0a32, 0x0a33,
+ 0x0a35, 0x0a36,
+ 0x0a38, 0x0a39,
+ 0x0a59, 0x0a5c,
+ 0x0a5e, 0x0a5e,
+ 0x0a72, 0x0a74,
+ 0x0a85, 0x0a8d,
+ 0x0a8f, 0x0a91,
+ 0x0a93, 0x0aa8,
+ 0x0aaa, 0x0ab0,
+ 0x0ab2, 0x0ab3,
+ 0x0ab5, 0x0ab9,
+ 0x0abd, 0x0abd,
+ 0x0ad0, 0x0ad0,
+ 0x0ae0, 0x0ae1,
+ 0x0af9, 0x0af9,
+ 0x0b05, 0x0b0c,
+ 0x0b0f, 0x0b10,
+ 0x0b13, 0x0b28,
+ 0x0b2a, 0x0b30,
+ 0x0b32, 0x0b33,
+ 0x0b35, 0x0b39,
+ 0x0b3d, 0x0b3d,
+ 0x0b5c, 0x0b5d,
+ 0x0b5f, 0x0b61,
+ 0x0b71, 0x0b71,
+ 0x0b83, 0x0b83,
+ 0x0b85, 0x0b8a,
+ 0x0b8e, 0x0b90,
+ 0x0b92, 0x0b95,
+ 0x0b99, 0x0b9a,
+ 0x0b9c, 0x0b9c,
+ 0x0b9e, 0x0b9f,
+ 0x0ba3, 0x0ba4,
+ 0x0ba8, 0x0baa,
+ 0x0bae, 0x0bb9,
+ 0x0bd0, 0x0bd0,
+ 0x0c05, 0x0c0c,
+ 0x0c0e, 0x0c10,
+ 0x0c12, 0x0c28,
+ 0x0c2a, 0x0c39,
+ 0x0c3d, 0x0c3d,
+ 0x0c58, 0x0c5a,
+ 0x0c5c, 0x0c5d,
+ 0x0c60, 0x0c61,
+ 0x0c80, 0x0c80,
+ 0x0c85, 0x0c8c,
+ 0x0c8e, 0x0c90,
+ 0x0c92, 0x0ca8,
+ 0x0caa, 0x0cb3,
+ 0x0cb5, 0x0cb9,
+ 0x0cbd, 0x0cbd,
+ 0x0cdc, 0x0cde,
+ 0x0ce0, 0x0ce1,
+ 0x0cf1, 0x0cf2,
+ 0x0d04, 0x0d0c,
+ 0x0d0e, 0x0d10,
+ 0x0d12, 0x0d3a,
+ 0x0d3d, 0x0d3d,
+ 0x0d4e, 0x0d4e,
+ 0x0d54, 0x0d56,
+ 0x0d5f, 0x0d61,
+ 0x0d7a, 0x0d7f,
+ 0x0d85, 0x0d96,
+ 0x0d9a, 0x0db1,
+ 0x0db3, 0x0dbb,
+ 0x0dbd, 0x0dbd,
+ 0x0dc0, 0x0dc6,
+ 0x0e01, 0x0e30,
+ 0x0e32, 0x0e32,
+ 0x0e40, 0x0e46,
+ 0x0e81, 0x0e82,
+ 0x0e84, 0x0e84,
+ 0x0e86, 0x0e8a,
+ 0x0e8c, 0x0ea3,
+ 0x0ea5, 0x0ea5,
+ 0x0ea7, 0x0eb0,
+ 0x0eb2, 0x0eb2,
+ 0x0ebd, 0x0ebd,
+ 0x0ec0, 0x0ec4,
+ 0x0ec6, 0x0ec6,
+ 0x0edc, 0x0edf,
+ 0x0f00, 0x0f00,
+ 0x0f40, 0x0f47,
+ 0x0f49, 0x0f6c,
+ 0x0f88, 0x0f8c,
+ 0x1000, 0x102a,
+ 0x103f, 0x103f,
+ 0x1050, 0x1055,
+ 0x105a, 0x105d,
+ 0x1061, 0x1061,
+ 0x1065, 0x1066,
+ 0x106e, 0x1070,
+ 0x1075, 0x1081,
+ 0x108e, 0x108e,
+ 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, 0x1711,
+ 0x171f, 0x1731,
+ 0x1740, 0x1751,
+ 0x1760, 0x176c,
+ 0x176e, 0x1770,
+ 0x1780, 0x17b3,
+ 0x17d7, 0x17d7,
+ 0x17dc, 0x17dc,
+ 0x1820, 0x1878,
+ 0x1880, 0x18a8,
+ 0x18aa, 0x18aa,
+ 0x18b0, 0x18f5,
+ 0x1900, 0x191e,
+ 0x1950, 0x196d,
+ 0x1970, 0x1974,
+ 0x1980, 0x19ab,
+ 0x19b0, 0x19c9,
+ 0x1a00, 0x1a16,
+ 0x1a20, 0x1a54,
+ 0x1aa7, 0x1aa7,
+ 0x1b05, 0x1b33,
+ 0x1b45, 0x1b4c,
+ 0x1b83, 0x1ba0,
+ 0x1bae, 0x1baf,
+ 0x1bba, 0x1be5,
+ 0x1c00, 0x1c23,
+ 0x1c4d, 0x1c4f,
+ 0x1c5a, 0x1c7d,
+ 0x1c80, 0x1c8a,
+ 0x1c90, 0x1cba,
+ 0x1cbd, 0x1cbf,
+ 0x1ce9, 0x1cec,
+ 0x1cee, 0x1cf3,
+ 0x1cf5, 0x1cf6,
+ 0x1cfa, 0x1cfa,
+ 0x1d00, 0x1dbf,
+ 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,
+ 0x2118, 0x211d,
+ 0x2124, 0x2124,
+ 0x2126, 0x2126,
+ 0x2128, 0x2128,
+ 0x212a, 0x2139,
+ 0x213c, 0x213f,
+ 0x2145, 0x2149,
+ 0x214e, 0x214e,
+ 0x2160, 0x2188,
+ 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,
+ 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,
+ 0xa67f, 0xa69d,
+ 0xa6a0, 0xa6ef,
+ 0xa717, 0xa71f,
+ 0xa722, 0xa788,
+ 0xa78b, 0xa7dc,
+ 0xa7f1, 0xa801,
+ 0xa803, 0xa805,
+ 0xa807, 0xa80a,
+ 0xa80c, 0xa822,
+ 0xa840, 0xa873,
+ 0xa882, 0xa8b3,
+ 0xa8f2, 0xa8f7,
+ 0xa8fb, 0xa8fb,
+ 0xa8fd, 0xa8fe,
+ 0xa90a, 0xa925,
+ 0xa930, 0xa946,
+ 0xa960, 0xa97c,
+ 0xa984, 0xa9b2,
+ 0xa9cf, 0xa9cf,
+ 0xa9e0, 0xa9e4,
+ 0xa9e6, 0xa9ef,
+ 0xa9fa, 0xa9fe,
+ 0xaa00, 0xaa28,
+ 0xaa40, 0xaa42,
+ 0xaa44, 0xaa4b,
+ 0xaa60, 0xaa76,
+ 0xaa7a, 0xaa7a,
+ 0xaa7e, 0xaaaf,
+ 0xaab1, 0xaab1,
+ 0xaab5, 0xaab6,
+ 0xaab9, 0xaabd,
+ 0xaac0, 0xaac0,
+ 0xaac2, 0xaac2,
+ 0xaadb, 0xaadd,
+ 0xaae0, 0xaaea,
+ 0xaaf2, 0xaaf4,
+ 0xab01, 0xab06,
+ 0xab09, 0xab0e,
+ 0xab11, 0xab16,
+ 0xab20, 0xab26,
+ 0xab28, 0xab2e,
+ 0xab30, 0xab5a,
+ 0xab5c, 0xab69,
+ 0xab70, 0xabe2,
+ 0xac00, 0xd7a3,
+ 0xd7b0, 0xd7c6,
+ 0xd7cb, 0xd7fb,
+ 0xf900, 0xfa6d,
+ 0xfa70, 0xfad9,
+ 0xfb00, 0xfb06,
+ 0xfb13, 0xfb17,
+ 0xfb1d, 0xfb1d,
+ 0xfb1f, 0xfb28,
+ 0xfb2a, 0xfb36,
+ 0xfb38, 0xfb3c,
+ 0xfb3e, 0xfb3e,
+ 0xfb40, 0xfb41,
+ 0xfb43, 0xfb44,
+ 0xfb46, 0xfbb1,
+ 0xfbd3, 0xfc5d,
+ 0xfc64, 0xfd3d,
+ 0xfd50, 0xfd8f,
+ 0xfd92, 0xfdc7,
+ 0xfdf0, 0xfdf9,
+ 0xfe71, 0xfe71,
+ 0xfe73, 0xfe73,
+ 0xfe77, 0xfe77,
+ 0xfe79, 0xfe79,
+ 0xfe7b, 0xfe7b,
+ 0xfe7d, 0xfe7d,
+ 0xfe7f, 0xfefc,
+ 0xff21, 0xff3a,
+ 0xff41, 0xff5a,
+ 0xff66, 0xff9d,
+ 0xffa0, 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, 0x10375,
+ 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,
+ 0x105c0, 0x105f3,
+ 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,
+ 0x10940, 0x10959,
+ 0x10980, 0x109b7,
+ 0x109be, 0x109bf,
+ 0x10a00, 0x10a00,
+ 0x10a10, 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, 0x10d23,
+ 0x10d4a, 0x10d65,
+ 0x10d6f, 0x10d85,
+ 0x10e80, 0x10ea9,
+ 0x10eb0, 0x10eb1,
+ 0x10ec2, 0x10ec7,
+ 0x10f00, 0x10f1c,
+ 0x10f27, 0x10f27,
+ 0x10f30, 0x10f45,
+ 0x10f70, 0x10f81,
+ 0x10fb0, 0x10fc4,
+ 0x10fe0, 0x10ff6,
+ 0x11003, 0x11037,
+ 0x11071, 0x11072,
+ 0x11075, 0x11075,
+ 0x11083, 0x110af,
+ 0x110d0, 0x110e8,
+ 0x11103, 0x11126,
+ 0x11144, 0x11144,
+ 0x11147, 0x11147,
+ 0x11150, 0x11172,
+ 0x11176, 0x11176,
+ 0x11183, 0x111b2,
+ 0x111c1, 0x111c4,
+ 0x111da, 0x111da,
+ 0x111dc, 0x111dc,
+ 0x11200, 0x11211,
+ 0x11213, 0x1122b,
+ 0x1123f, 0x11240,
+ 0x11280, 0x11286,
+ 0x11288, 0x11288,
+ 0x1128a, 0x1128d,
+ 0x1128f, 0x1129d,
+ 0x1129f, 0x112a8,
+ 0x112b0, 0x112de,
+ 0x11305, 0x1130c,
+ 0x1130f, 0x11310,
+ 0x11313, 0x11328,
+ 0x1132a, 0x11330,
+ 0x11332, 0x11333,
+ 0x11335, 0x11339,
+ 0x1133d, 0x1133d,
+ 0x11350, 0x11350,
+ 0x1135d, 0x11361,
+ 0x11380, 0x11389,
+ 0x1138b, 0x1138b,
+ 0x1138e, 0x1138e,
+ 0x11390, 0x113b5,
+ 0x113b7, 0x113b7,
+ 0x113d1, 0x113d1,
+ 0x113d3, 0x113d3,
+ 0x11400, 0x11434,
+ 0x11447, 0x1144a,
+ 0x1145f, 0x11461,
+ 0x11480, 0x114af,
+ 0x114c4, 0x114c5,
+ 0x114c7, 0x114c7,
+ 0x11580, 0x115ae,
+ 0x115d8, 0x115db,
+ 0x11600, 0x1162f,
+ 0x11644, 0x11644,
+ 0x11680, 0x116aa,
+ 0x116b8, 0x116b8,
+ 0x11700, 0x1171a,
+ 0x11740, 0x11746,
+ 0x11800, 0x1182b,
+ 0x118a0, 0x118df,
+ 0x118ff, 0x11906,
+ 0x11909, 0x11909,
+ 0x1190c, 0x11913,
+ 0x11915, 0x11916,
+ 0x11918, 0x1192f,
+ 0x1193f, 0x1193f,
+ 0x11941, 0x11941,
+ 0x119a0, 0x119a7,
+ 0x119aa, 0x119d0,
+ 0x119e1, 0x119e1,
+ 0x119e3, 0x119e3,
+ 0x11a00, 0x11a00,
+ 0x11a0b, 0x11a32,
+ 0x11a3a, 0x11a3a,
+ 0x11a50, 0x11a50,
+ 0x11a5c, 0x11a89,
+ 0x11a9d, 0x11a9d,
+ 0x11ab0, 0x11af8,
+ 0x11bc0, 0x11be0,
+ 0x11c00, 0x11c08,
+ 0x11c0a, 0x11c2e,
+ 0x11c40, 0x11c40,
+ 0x11c72, 0x11c8f,
+ 0x11d00, 0x11d06,
+ 0x11d08, 0x11d09,
+ 0x11d0b, 0x11d30,
+ 0x11d46, 0x11d46,
+ 0x11d60, 0x11d65,
+ 0x11d67, 0x11d68,
+ 0x11d6a, 0x11d89,
+ 0x11d98, 0x11d98,
+ 0x11db0, 0x11ddb,
+ 0x11ee0, 0x11ef2,
+ 0x11f02, 0x11f02,
+ 0x11f04, 0x11f10,
+ 0x11f12, 0x11f33,
+ 0x11fb0, 0x11fb0,
+ 0x12000, 0x12399,
+ 0x12400, 0x1246e,
+ 0x12480, 0x12543,
+ 0x12f90, 0x12ff0,
+ 0x13000, 0x1342f,
+ 0x13441, 0x13446,
+ 0x13460, 0x143fa,
+ 0x14400, 0x14646,
+ 0x16100, 0x1611d,
+ 0x16800, 0x16a38,
+ 0x16a40, 0x16a5e,
+ 0x16a70, 0x16abe,
+ 0x16ad0, 0x16aed,
+ 0x16b00, 0x16b2f,
+ 0x16b40, 0x16b43,
+ 0x16b63, 0x16b77,
+ 0x16b7d, 0x16b8f,
+ 0x16d40, 0x16d6c,
+ 0x16e40, 0x16e7f,
+ 0x16ea0, 0x16eb8,
+ 0x16ebb, 0x16ed3,
+ 0x16f00, 0x16f4a,
+ 0x16f50, 0x16f50,
+ 0x16f93, 0x16f9f,
+ 0x16fe0, 0x16fe1,
+ 0x16fe3, 0x16fe3,
+ 0x16ff2, 0x16ff6,
+ 0x17000, 0x18cd5,
+ 0x18cff, 0x18d1e,
+ 0x18d80, 0x18df2,
+ 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,
+ 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,
+ 0x1e030, 0x1e06d,
+ 0x1e100, 0x1e12c,
+ 0x1e137, 0x1e13d,
+ 0x1e14e, 0x1e14e,
+ 0x1e290, 0x1e2ad,
+ 0x1e2c0, 0x1e2eb,
+ 0x1e4d0, 0x1e4eb,
+ 0x1e5d0, 0x1e5ed,
+ 0x1e5f0, 0x1e5f0,
+ 0x1e6c0, 0x1e6de,
+ 0x1e6e0, 0x1e6e2,
+ 0x1e6e4, 0x1e6e5,
+ 0x1e6e7, 0x1e6ed,
+ 0x1e6f0, 0x1e6f4,
+ 0x1e6fe, 0x1e6ff,
+ 0x1e7e0, 0x1e7e6,
+ 0x1e7e8, 0x1e7eb,
+ 0x1e7ed, 0x1e7ee,
+ 0x1e7f0, 0x1e7fe,
+ 0x1e800, 0x1e8c4,
+ 0x1e900, 0x1e943,
+ 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,
+ 0x20000, 0x2a6df,
+ 0x2a700, 0x2b81d,
+ 0x2b820, 0x2cead,
+ 0x2ceb0, 0x2ebe0,
+ 0x2ebf0, 0x2ee5d,
+ 0x2f800, 0x2fa1d,
+ 0x30000, 0x3134a,
+ 0x31350, 0x33479,
+}; /* CR_XID_Start */
+
+/* 'XID_Continue': Derived Property */
+static const OnigCodePoint CR_XID_Continue[] = {
+ 806,
+ 0x0030, 0x0039,
+ 0x0041, 0x005a,
+ 0x005f, 0x005f,
+ 0x0061, 0x007a,
+ 0x00aa, 0x00aa,
+ 0x00b5, 0x00b5,
+ 0x00b7, 0x00b7,
+ 0x00ba, 0x00ba,
+ 0x00c0, 0x00d6,
+ 0x00d8, 0x00f6,
+ 0x00f8, 0x02c1,
+ 0x02c6, 0x02d1,
+ 0x02e0, 0x02e4,
+ 0x02ec, 0x02ec,
+ 0x02ee, 0x02ee,
+ 0x0300, 0x0374,
+ 0x0376, 0x0377,
+ 0x037b, 0x037d,
+ 0x037f, 0x037f,
+ 0x0386, 0x038a,
+ 0x038c, 0x038c,
+ 0x038e, 0x03a1,
+ 0x03a3, 0x03f5,
+ 0x03f7, 0x0481,
+ 0x0483, 0x0487,
+ 0x048a, 0x052f,
+ 0x0531, 0x0556,
+ 0x0559, 0x0559,
+ 0x0560, 0x0588,
+ 0x0591, 0x05bd,
+ 0x05bf, 0x05bf,
+ 0x05c1, 0x05c2,
+ 0x05c4, 0x05c5,
+ 0x05c7, 0x05c7,
+ 0x05d0, 0x05ea,
+ 0x05ef, 0x05f2,
+ 0x0610, 0x061a,
+ 0x0620, 0x0669,
+ 0x066e, 0x06d3,
+ 0x06d5, 0x06dc,
+ 0x06df, 0x06e8,
+ 0x06ea, 0x06fc,
+ 0x06ff, 0x06ff,
+ 0x0710, 0x074a,
+ 0x074d, 0x07b1,
+ 0x07c0, 0x07f5,
+ 0x07fa, 0x07fa,
+ 0x07fd, 0x07fd,
+ 0x0800, 0x082d,
+ 0x0840, 0x085b,
+ 0x0860, 0x086a,
+ 0x0870, 0x0887,
+ 0x0889, 0x088f,
+ 0x0897, 0x08e1,
+ 0x08e3, 0x0963,
+ 0x0966, 0x096f,
+ 0x0971, 0x0983,
+ 0x0985, 0x098c,
+ 0x098f, 0x0990,
+ 0x0993, 0x09a8,
+ 0x09aa, 0x09b0,
+ 0x09b2, 0x09b2,
+ 0x09b6, 0x09b9,
+ 0x09bc, 0x09c4,
+ 0x09c7, 0x09c8,
+ 0x09cb, 0x09ce,
+ 0x09d7, 0x09d7,
+ 0x09dc, 0x09dd,
+ 0x09df, 0x09e3,
+ 0x09e6, 0x09f1,
+ 0x09fc, 0x09fc,
+ 0x09fe, 0x09fe,
+ 0x0a01, 0x0a03,
+ 0x0a05, 0x0a0a,
+ 0x0a0f, 0x0a10,
+ 0x0a13, 0x0a28,
+ 0x0a2a, 0x0a30,
+ 0x0a32, 0x0a33,
+ 0x0a35, 0x0a36,
+ 0x0a38, 0x0a39,
+ 0x0a3c, 0x0a3c,
+ 0x0a3e, 0x0a42,
+ 0x0a47, 0x0a48,
+ 0x0a4b, 0x0a4d,
+ 0x0a51, 0x0a51,
+ 0x0a59, 0x0a5c,
+ 0x0a5e, 0x0a5e,
+ 0x0a66, 0x0a75,
+ 0x0a81, 0x0a83,
+ 0x0a85, 0x0a8d,
+ 0x0a8f, 0x0a91,
+ 0x0a93, 0x0aa8,
+ 0x0aaa, 0x0ab0,
+ 0x0ab2, 0x0ab3,
+ 0x0ab5, 0x0ab9,
+ 0x0abc, 0x0ac5,
+ 0x0ac7, 0x0ac9,
+ 0x0acb, 0x0acd,
+ 0x0ad0, 0x0ad0,
+ 0x0ae0, 0x0ae3,
+ 0x0ae6, 0x0aef,
+ 0x0af9, 0x0aff,
+ 0x0b01, 0x0b03,
+ 0x0b05, 0x0b0c,
+ 0x0b0f, 0x0b10,
+ 0x0b13, 0x0b28,
+ 0x0b2a, 0x0b30,
+ 0x0b32, 0x0b33,
+ 0x0b35, 0x0b39,
+ 0x0b3c, 0x0b44,
+ 0x0b47, 0x0b48,
+ 0x0b4b, 0x0b4d,
+ 0x0b55, 0x0b57,
+ 0x0b5c, 0x0b5d,
+ 0x0b5f, 0x0b63,
+ 0x0b66, 0x0b6f,
+ 0x0b71, 0x0b71,
+ 0x0b82, 0x0b83,
+ 0x0b85, 0x0b8a,
+ 0x0b8e, 0x0b90,
+ 0x0b92, 0x0b95,
+ 0x0b99, 0x0b9a,
+ 0x0b9c, 0x0b9c,
+ 0x0b9e, 0x0b9f,
+ 0x0ba3, 0x0ba4,
+ 0x0ba8, 0x0baa,
+ 0x0bae, 0x0bb9,
+ 0x0bbe, 0x0bc2,
+ 0x0bc6, 0x0bc8,
+ 0x0bca, 0x0bcd,
+ 0x0bd0, 0x0bd0,
+ 0x0bd7, 0x0bd7,
+ 0x0be6, 0x0bef,
+ 0x0c00, 0x0c0c,
+ 0x0c0e, 0x0c10,
+ 0x0c12, 0x0c28,
+ 0x0c2a, 0x0c39,
+ 0x0c3c, 0x0c44,
+ 0x0c46, 0x0c48,
+ 0x0c4a, 0x0c4d,
+ 0x0c55, 0x0c56,
+ 0x0c58, 0x0c5a,
+ 0x0c5c, 0x0c5d,
+ 0x0c60, 0x0c63,
+ 0x0c66, 0x0c6f,
+ 0x0c80, 0x0c83,
+ 0x0c85, 0x0c8c,
+ 0x0c8e, 0x0c90,
+ 0x0c92, 0x0ca8,
+ 0x0caa, 0x0cb3,
+ 0x0cb5, 0x0cb9,
+ 0x0cbc, 0x0cc4,
+ 0x0cc6, 0x0cc8,
+ 0x0cca, 0x0ccd,
+ 0x0cd5, 0x0cd6,
+ 0x0cdc, 0x0cde,
+ 0x0ce0, 0x0ce3,
+ 0x0ce6, 0x0cef,
+ 0x0cf1, 0x0cf3,
+ 0x0d00, 0x0d0c,
+ 0x0d0e, 0x0d10,
+ 0x0d12, 0x0d44,
+ 0x0d46, 0x0d48,
+ 0x0d4a, 0x0d4e,
+ 0x0d54, 0x0d57,
+ 0x0d5f, 0x0d63,
+ 0x0d66, 0x0d6f,
+ 0x0d7a, 0x0d7f,
+ 0x0d81, 0x0d83,
+ 0x0d85, 0x0d96,
+ 0x0d9a, 0x0db1,
+ 0x0db3, 0x0dbb,
+ 0x0dbd, 0x0dbd,
+ 0x0dc0, 0x0dc6,
+ 0x0dca, 0x0dca,
+ 0x0dcf, 0x0dd4,
+ 0x0dd6, 0x0dd6,
+ 0x0dd8, 0x0ddf,
+ 0x0de6, 0x0def,
+ 0x0df2, 0x0df3,
+ 0x0e01, 0x0e3a,
+ 0x0e40, 0x0e4e,
+ 0x0e50, 0x0e59,
+ 0x0e81, 0x0e82,
+ 0x0e84, 0x0e84,
+ 0x0e86, 0x0e8a,
+ 0x0e8c, 0x0ea3,
+ 0x0ea5, 0x0ea5,
+ 0x0ea7, 0x0ebd,
+ 0x0ec0, 0x0ec4,
+ 0x0ec6, 0x0ec6,
+ 0x0ec8, 0x0ece,
+ 0x0ed0, 0x0ed9,
+ 0x0edc, 0x0edf,
+ 0x0f00, 0x0f00,
+ 0x0f18, 0x0f19,
+ 0x0f20, 0x0f29,
+ 0x0f35, 0x0f35,
+ 0x0f37, 0x0f37,
+ 0x0f39, 0x0f39,
+ 0x0f3e, 0x0f47,
+ 0x0f49, 0x0f6c,
+ 0x0f71, 0x0f84,
+ 0x0f86, 0x0f97,
+ 0x0f99, 0x0fbc,
+ 0x0fc6, 0x0fc6,
+ 0x1000, 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,
+ 0x135d, 0x135f,
+ 0x1369, 0x1371,
+ 0x1380, 0x138f,
+ 0x13a0, 0x13f5,
+ 0x13f8, 0x13fd,
+ 0x1401, 0x166c,
+ 0x166f, 0x167f,
+ 0x1681, 0x169a,
+ 0x16a0, 0x16ea,
+ 0x16ee, 0x16f8,
+ 0x1700, 0x1715,
+ 0x171f, 0x1734,
+ 0x1740, 0x1753,
+ 0x1760, 0x176c,
+ 0x176e, 0x1770,
+ 0x1772, 0x1773,
+ 0x1780, 0x17d3,
+ 0x17d7, 0x17d7,
+ 0x17dc, 0x17dd,
+ 0x17e0, 0x17e9,
+ 0x180b, 0x180d,
+ 0x180f, 0x1819,
+ 0x1820, 0x1878,
+ 0x1880, 0x18aa,
+ 0x18b0, 0x18f5,
+ 0x1900, 0x191e,
+ 0x1920, 0x192b,
+ 0x1930, 0x193b,
+ 0x1946, 0x196d,
+ 0x1970, 0x1974,
+ 0x1980, 0x19ab,
+ 0x19b0, 0x19c9,
+ 0x19d0, 0x19da,
+ 0x1a00, 0x1a1b,
+ 0x1a20, 0x1a5e,
+ 0x1a60, 0x1a7c,
+ 0x1a7f, 0x1a89,
+ 0x1a90, 0x1a99,
+ 0x1aa7, 0x1aa7,
+ 0x1ab0, 0x1abd,
+ 0x1abf, 0x1add,
+ 0x1ae0, 0x1aeb,
+ 0x1b00, 0x1b4c,
+ 0x1b50, 0x1b59,
+ 0x1b6b, 0x1b73,
+ 0x1b80, 0x1bf3,
+ 0x1c00, 0x1c37,
+ 0x1c40, 0x1c49,
+ 0x1c4d, 0x1c7d,
+ 0x1c80, 0x1c8a,
+ 0x1c90, 0x1cba,
+ 0x1cbd, 0x1cbf,
+ 0x1cd0, 0x1cd2,
+ 0x1cd4, 0x1cfa,
+ 0x1d00, 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,
+ 0x200c, 0x200d,
+ 0x203f, 0x2040,
+ 0x2054, 0x2054,
+ 0x2071, 0x2071,
+ 0x207f, 0x207f,
+ 0x2090, 0x209c,
+ 0x20d0, 0x20dc,
+ 0x20e1, 0x20e1,
+ 0x20e5, 0x20f0,
+ 0x2102, 0x2102,
+ 0x2107, 0x2107,
+ 0x210a, 0x2113,
+ 0x2115, 0x2115,
+ 0x2118, 0x211d,
+ 0x2124, 0x2124,
+ 0x2126, 0x2126,
+ 0x2128, 0x2128,
+ 0x212a, 0x2139,
+ 0x213c, 0x213f,
+ 0x2145, 0x2149,
+ 0x214e, 0x214e,
+ 0x2160, 0x2188,
+ 0x2c00, 0x2ce4,
+ 0x2ceb, 0x2cf3,
+ 0x2d00, 0x2d25,
+ 0x2d27, 0x2d27,
+ 0x2d2d, 0x2d2d,
+ 0x2d30, 0x2d67,
+ 0x2d6f, 0x2d6f,
+ 0x2d7f, 0x2d96,
+ 0x2da0, 0x2da6,
+ 0x2da8, 0x2dae,
+ 0x2db0, 0x2db6,
+ 0x2db8, 0x2dbe,
+ 0x2dc0, 0x2dc6,
+ 0x2dc8, 0x2dce,
+ 0x2dd0, 0x2dd6,
+ 0x2dd8, 0x2dde,
+ 0x2de0, 0x2dff,
+ 0x3005, 0x3007,
+ 0x3021, 0x302f,
+ 0x3031, 0x3035,
+ 0x3038, 0x303c,
+ 0x3041, 0x3096,
+ 0x3099, 0x309a,
+ 0x309d, 0x309f,
+ 0x30a1, 0x30ff,
+ 0x3105, 0x312f,
+ 0x3131, 0x318e,
+ 0x31a0, 0x31bf,
+ 0x31f0, 0x31ff,
+ 0x3400, 0x4dbf,
+ 0x4e00, 0xa48c,
+ 0xa4d0, 0xa4fd,
+ 0xa500, 0xa60c,
+ 0xa610, 0xa62b,
+ 0xa640, 0xa66f,
+ 0xa674, 0xa67d,
+ 0xa67f, 0xa6f1,
+ 0xa717, 0xa71f,
+ 0xa722, 0xa788,
+ 0xa78b, 0xa7dc,
+ 0xa7f1, 0xa827,
+ 0xa82c, 0xa82c,
+ 0xa840, 0xa873,
+ 0xa880, 0xa8c5,
+ 0xa8d0, 0xa8d9,
+ 0xa8e0, 0xa8f7,
+ 0xa8fb, 0xa8fb,
+ 0xa8fd, 0xa92d,
+ 0xa930, 0xa953,
+ 0xa960, 0xa97c,
+ 0xa980, 0xa9c0,
+ 0xa9cf, 0xa9d9,
+ 0xa9e0, 0xa9fe,
+ 0xaa00, 0xaa36,
+ 0xaa40, 0xaa4d,
+ 0xaa50, 0xaa59,
+ 0xaa60, 0xaa76,
+ 0xaa7a, 0xaac2,
+ 0xaadb, 0xaadd,
+ 0xaae0, 0xaaef,
+ 0xaaf2, 0xaaf6,
+ 0xab01, 0xab06,
+ 0xab09, 0xab0e,
+ 0xab11, 0xab16,
+ 0xab20, 0xab26,
+ 0xab28, 0xab2e,
+ 0xab30, 0xab5a,
+ 0xab5c, 0xab69,
+ 0xab70, 0xabea,
+ 0xabec, 0xabed,
+ 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, 0xfc5d,
+ 0xfc64, 0xfd3d,
+ 0xfd50, 0xfd8f,
+ 0xfd92, 0xfdc7,
+ 0xfdf0, 0xfdf9,
+ 0xfe00, 0xfe0f,
+ 0xfe20, 0xfe2f,
+ 0xfe33, 0xfe34,
+ 0xfe4d, 0xfe4f,
+ 0xfe71, 0xfe71,
+ 0xfe73, 0xfe73,
+ 0xfe77, 0xfe77,
+ 0xfe79, 0xfe79,
+ 0xfe7b, 0xfe7b,
+ 0xfe7d, 0xfe7d,
+ 0xfe7f, 0xfefc,
+ 0xff10, 0xff19,
+ 0xff21, 0xff3a,
+ 0xff3f, 0xff3f,
+ 0xff41, 0xff5a,
+ 0xff65, 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,
+ 0x101fd, 0x101fd,
+ 0x10280, 0x1029c,
+ 0x102a0, 0x102d0,
+ 0x102e0, 0x102e0,
+ 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,
+ 0x105c0, 0x105f3,
+ 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,
+ 0x10940, 0x10959,
+ 0x10980, 0x109b7,
+ 0x109be, 0x109bf,
+ 0x10a00, 0x10a03,
+ 0x10a05, 0x10a06,
+ 0x10a0c, 0x10a13,
+ 0x10a15, 0x10a17,
+ 0x10a19, 0x10a35,
+ 0x10a38, 0x10a3a,
+ 0x10a3f, 0x10a3f,
+ 0x10a60, 0x10a7c,
+ 0x10a80, 0x10a9c,
+ 0x10ac0, 0x10ac7,
+ 0x10ac9, 0x10ae6,
+ 0x10b00, 0x10b35,
+ 0x10b40, 0x10b55,
+ 0x10b60, 0x10b72,
+ 0x10b80, 0x10b91,
+ 0x10c00, 0x10c48,
+ 0x10c80, 0x10cb2,
+ 0x10cc0, 0x10cf2,
+ 0x10d00, 0x10d27,
+ 0x10d30, 0x10d39,
+ 0x10d40, 0x10d65,
+ 0x10d69, 0x10d6d,
+ 0x10d6f, 0x10d85,
+ 0x10e80, 0x10ea9,
+ 0x10eab, 0x10eac,
+ 0x10eb0, 0x10eb1,
+ 0x10ec2, 0x10ec7,
+ 0x10efa, 0x10f1c,
+ 0x10f27, 0x10f27,
+ 0x10f30, 0x10f50,
+ 0x10f70, 0x10f85,
+ 0x10fb0, 0x10fc4,
+ 0x10fe0, 0x10ff6,
+ 0x11000, 0x11046,
+ 0x11066, 0x11075,
+ 0x1107f, 0x110ba,
+ 0x110c2, 0x110c2,
+ 0x110d0, 0x110e8,
+ 0x110f0, 0x110f9,
+ 0x11100, 0x11134,
+ 0x11136, 0x1113f,
+ 0x11144, 0x11147,
+ 0x11150, 0x11173,
+ 0x11176, 0x11176,
+ 0x11180, 0x111c4,
+ 0x111c9, 0x111cc,
+ 0x111ce, 0x111da,
+ 0x111dc, 0x111dc,
+ 0x11200, 0x11211,
+ 0x11213, 0x11237,
+ 0x1123e, 0x11241,
+ 0x11280, 0x11286,
+ 0x11288, 0x11288,
+ 0x1128a, 0x1128d,
+ 0x1128f, 0x1129d,
+ 0x1129f, 0x112a8,
+ 0x112b0, 0x112ea,
+ 0x112f0, 0x112f9,
+ 0x11300, 0x11303,
+ 0x11305, 0x1130c,
+ 0x1130f, 0x11310,
+ 0x11313, 0x11328,
+ 0x1132a, 0x11330,
+ 0x11332, 0x11333,
+ 0x11335, 0x11339,
+ 0x1133b, 0x11344,
+ 0x11347, 0x11348,
+ 0x1134b, 0x1134d,
+ 0x11350, 0x11350,
+ 0x11357, 0x11357,
+ 0x1135d, 0x11363,
+ 0x11366, 0x1136c,
+ 0x11370, 0x11374,
+ 0x11380, 0x11389,
+ 0x1138b, 0x1138b,
+ 0x1138e, 0x1138e,
+ 0x11390, 0x113b5,
+ 0x113b7, 0x113c0,
+ 0x113c2, 0x113c2,
+ 0x113c5, 0x113c5,
+ 0x113c7, 0x113ca,
+ 0x113cc, 0x113d3,
+ 0x113e1, 0x113e2,
+ 0x11400, 0x1144a,
+ 0x11450, 0x11459,
+ 0x1145e, 0x11461,
+ 0x11480, 0x114c5,
+ 0x114c7, 0x114c7,
+ 0x114d0, 0x114d9,
+ 0x11580, 0x115b5,
+ 0x115b8, 0x115c0,
+ 0x115d8, 0x115dd,
+ 0x11600, 0x11640,
+ 0x11644, 0x11644,
+ 0x11650, 0x11659,
+ 0x11680, 0x116b8,
+ 0x116c0, 0x116c9,
+ 0x116d0, 0x116e3,
+ 0x11700, 0x1171a,
+ 0x1171d, 0x1172b,
+ 0x11730, 0x11739,
+ 0x11740, 0x11746,
+ 0x11800, 0x1183a,
+ 0x118a0, 0x118e9,
+ 0x118ff, 0x11906,
+ 0x11909, 0x11909,
+ 0x1190c, 0x11913,
+ 0x11915, 0x11916,
+ 0x11918, 0x11935,
+ 0x11937, 0x11938,
+ 0x1193b, 0x11943,
+ 0x11950, 0x11959,
+ 0x119a0, 0x119a7,
+ 0x119aa, 0x119d7,
+ 0x119da, 0x119e1,
+ 0x119e3, 0x119e4,
+ 0x11a00, 0x11a3e,
+ 0x11a47, 0x11a47,
+ 0x11a50, 0x11a99,
+ 0x11a9d, 0x11a9d,
+ 0x11ab0, 0x11af8,
+ 0x11b60, 0x11b67,
+ 0x11bc0, 0x11be0,
+ 0x11bf0, 0x11bf9,
+ 0x11c00, 0x11c08,
+ 0x11c0a, 0x11c36,
+ 0x11c38, 0x11c40,
+ 0x11c50, 0x11c59,
+ 0x11c72, 0x11c8f,
+ 0x11c92, 0x11ca7,
+ 0x11ca9, 0x11cb6,
+ 0x11d00, 0x11d06,
+ 0x11d08, 0x11d09,
+ 0x11d0b, 0x11d36,
+ 0x11d3a, 0x11d3a,
+ 0x11d3c, 0x11d3d,
+ 0x11d3f, 0x11d47,
+ 0x11d50, 0x11d59,
+ 0x11d60, 0x11d65,
+ 0x11d67, 0x11d68,
+ 0x11d6a, 0x11d8e,
+ 0x11d90, 0x11d91,
+ 0x11d93, 0x11d98,
+ 0x11da0, 0x11da9,
+ 0x11db0, 0x11ddb,
+ 0x11de0, 0x11de9,
+ 0x11ee0, 0x11ef6,
+ 0x11f00, 0x11f10,
+ 0x11f12, 0x11f3a,
+ 0x11f3e, 0x11f42,
+ 0x11f50, 0x11f5a,
+ 0x11fb0, 0x11fb0,
+ 0x12000, 0x12399,
+ 0x12400, 0x1246e,
+ 0x12480, 0x12543,
+ 0x12f90, 0x12ff0,
+ 0x13000, 0x1342f,
+ 0x13440, 0x13455,
+ 0x13460, 0x143fa,
+ 0x14400, 0x14646,
+ 0x16100, 0x16139,
+ 0x16800, 0x16a38,
+ 0x16a40, 0x16a5e,
+ 0x16a60, 0x16a69,
+ 0x16a70, 0x16abe,
+ 0x16ac0, 0x16ac9,
+ 0x16ad0, 0x16aed,
+ 0x16af0, 0x16af4,
+ 0x16b00, 0x16b36,
+ 0x16b40, 0x16b43,
+ 0x16b50, 0x16b59,
+ 0x16b63, 0x16b77,
+ 0x16b7d, 0x16b8f,
+ 0x16d40, 0x16d6c,
+ 0x16d70, 0x16d79,
+ 0x16e40, 0x16e7f,
+ 0x16ea0, 0x16eb8,
+ 0x16ebb, 0x16ed3,
+ 0x16f00, 0x16f4a,
+ 0x16f4f, 0x16f87,
+ 0x16f8f, 0x16f9f,
+ 0x16fe0, 0x16fe1,
+ 0x16fe3, 0x16fe4,
+ 0x16ff0, 0x16ff6,
+ 0x17000, 0x18cd5,
+ 0x18cff, 0x18d1e,
+ 0x18d80, 0x18df2,
+ 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,
+ 0x1bc9d, 0x1bc9e,
+ 0x1ccf0, 0x1ccf9,
+ 0x1cf00, 0x1cf2d,
+ 0x1cf30, 0x1cf46,
+ 0x1d165, 0x1d169,
+ 0x1d16d, 0x1d172,
+ 0x1d17b, 0x1d182,
+ 0x1d185, 0x1d18b,
+ 0x1d1aa, 0x1d1ad,
+ 0x1d242, 0x1d244,
+ 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,
+ 0x1da00, 0x1da36,
+ 0x1da3b, 0x1da6c,
+ 0x1da75, 0x1da75,
+ 0x1da84, 0x1da84,
+ 0x1da9b, 0x1da9f,
+ 0x1daa1, 0x1daaf,
+ 0x1df00, 0x1df1e,
+ 0x1df25, 0x1df2a,
+ 0x1e000, 0x1e006,
+ 0x1e008, 0x1e018,
+ 0x1e01b, 0x1e021,
+ 0x1e023, 0x1e024,
+ 0x1e026, 0x1e02a,
+ 0x1e030, 0x1e06d,
+ 0x1e08f, 0x1e08f,
+ 0x1e100, 0x1e12c,
+ 0x1e130, 0x1e13d,
+ 0x1e140, 0x1e149,
+ 0x1e14e, 0x1e14e,
+ 0x1e290, 0x1e2ae,
+ 0x1e2c0, 0x1e2f9,
+ 0x1e4d0, 0x1e4f9,
+ 0x1e5d0, 0x1e5fa,
+ 0x1e6c0, 0x1e6de,
+ 0x1e6e0, 0x1e6f5,
+ 0x1e6fe, 0x1e6ff,
+ 0x1e7e0, 0x1e7e6,
+ 0x1e7e8, 0x1e7eb,
+ 0x1e7ed, 0x1e7ee,
+ 0x1e7f0, 0x1e7fe,
+ 0x1e800, 0x1e8c4,
+ 0x1e8d0, 0x1e8d6,
+ 0x1e900, 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,
+ 0x1fbf0, 0x1fbf9,
+ 0x20000, 0x2a6df,
+ 0x2a700, 0x2b81d,
+ 0x2b820, 0x2cead,
+ 0x2ceb0, 0x2ebe0,
+ 0x2ebf0, 0x2ee5d,
+ 0x2f800, 0x2fa1d,
+ 0x30000, 0x3134a,
+ 0x31350, 0x33479,
+ 0xe0100, 0xe01ef,
+}; /* CR_XID_Continue */
+
+/* 'Default_Ignorable_Code_Point': Derived Property */
+static const OnigCodePoint CR_Default_Ignorable_Code_Point[] = {
+ 17,
+ 0x00ad, 0x00ad,
+ 0x034f, 0x034f,
+ 0x061c, 0x061c,
+ 0x115f, 0x1160,
+ 0x17b4, 0x17b5,
+ 0x180b, 0x180f,
+ 0x200b, 0x200f,
+ 0x202a, 0x202e,
+ 0x2060, 0x206f,
+ 0x3164, 0x3164,
+ 0xfe00, 0xfe0f,
+ 0xfeff, 0xfeff,
+ 0xffa0, 0xffa0,
+ 0xfff0, 0xfff8,
+ 0x1bca0, 0x1bca3,
+ 0x1d173, 0x1d17a,
+ 0xe0000, 0xe0fff,
+}; /* CR_Default_Ignorable_Code_Point */
+
+/* 'Grapheme_Extend': Derived Property */
+static const OnigCodePoint CR_Grapheme_Extend[] = {
+ 383,
+ 0x0300, 0x036f,
+ 0x0483, 0x0489,
+ 0x0591, 0x05bd,
+ 0x05bf, 0x05bf,
+ 0x05c1, 0x05c2,
+ 0x05c4, 0x05c5,
+ 0x05c7, 0x05c7,
+ 0x0610, 0x061a,
+ 0x064b, 0x065f,
+ 0x0670, 0x0670,
+ 0x06d6, 0x06dc,
+ 0x06df, 0x06e4,
+ 0x06e7, 0x06e8,
+ 0x06ea, 0x06ed,
+ 0x0711, 0x0711,
+ 0x0730, 0x074a,
+ 0x07a6, 0x07b0,
+ 0x07eb, 0x07f3,
+ 0x07fd, 0x07fd,
+ 0x0816, 0x0819,
+ 0x081b, 0x0823,
+ 0x0825, 0x0827,
+ 0x0829, 0x082d,
+ 0x0859, 0x085b,
+ 0x0897, 0x089f,
+ 0x08ca, 0x08e1,
+ 0x08e3, 0x0902,
+ 0x093a, 0x093a,
+ 0x093c, 0x093c,
+ 0x0941, 0x0948,
+ 0x094d, 0x094d,
+ 0x0951, 0x0957,
+ 0x0962, 0x0963,
+ 0x0981, 0x0981,
+ 0x09bc, 0x09bc,
+ 0x09be, 0x09be,
+ 0x09c1, 0x09c4,
+ 0x09cd, 0x09cd,
+ 0x09d7, 0x09d7,
+ 0x09e2, 0x09e3,
+ 0x09fe, 0x09fe,
+ 0x0a01, 0x0a02,
+ 0x0a3c, 0x0a3c,
+ 0x0a41, 0x0a42,
+ 0x0a47, 0x0a48,
+ 0x0a4b, 0x0a4d,
+ 0x0a51, 0x0a51,
+ 0x0a70, 0x0a71,
+ 0x0a75, 0x0a75,
+ 0x0a81, 0x0a82,
+ 0x0abc, 0x0abc,
+ 0x0ac1, 0x0ac5,
+ 0x0ac7, 0x0ac8,
+ 0x0acd, 0x0acd,
+ 0x0ae2, 0x0ae3,
+ 0x0afa, 0x0aff,
+ 0x0b01, 0x0b01,
+ 0x0b3c, 0x0b3c,
+ 0x0b3e, 0x0b3f,
+ 0x0b41, 0x0b44,
+ 0x0b4d, 0x0b4d,
+ 0x0b55, 0x0b57,
+ 0x0b62, 0x0b63,
+ 0x0b82, 0x0b82,
+ 0x0bbe, 0x0bbe,
+ 0x0bc0, 0x0bc0,
+ 0x0bcd, 0x0bcd,
+ 0x0bd7, 0x0bd7,
+ 0x0c00, 0x0c00,
+ 0x0c04, 0x0c04,
+ 0x0c3c, 0x0c3c,
+ 0x0c3e, 0x0c40,
+ 0x0c46, 0x0c48,
+ 0x0c4a, 0x0c4d,
+ 0x0c55, 0x0c56,
+ 0x0c62, 0x0c63,
+ 0x0c81, 0x0c81,
+ 0x0cbc, 0x0cbc,
+ 0x0cbf, 0x0cc0,
+ 0x0cc2, 0x0cc2,
+ 0x0cc6, 0x0cc8,
+ 0x0cca, 0x0ccd,
+ 0x0cd5, 0x0cd6,
+ 0x0ce2, 0x0ce3,
+ 0x0d00, 0x0d01,
+ 0x0d3b, 0x0d3c,
+ 0x0d3e, 0x0d3e,
+ 0x0d41, 0x0d44,
+ 0x0d4d, 0x0d4d,
+ 0x0d57, 0x0d57,
+ 0x0d62, 0x0d63,
+ 0x0d81, 0x0d81,
+ 0x0dca, 0x0dca,
+ 0x0dcf, 0x0dcf,
+ 0x0dd2, 0x0dd4,
+ 0x0dd6, 0x0dd6,
+ 0x0ddf, 0x0ddf,
+ 0x0e31, 0x0e31,
+ 0x0e34, 0x0e3a,
+ 0x0e47, 0x0e4e,
+ 0x0eb1, 0x0eb1,
+ 0x0eb4, 0x0ebc,
+ 0x0ec8, 0x0ece,
+ 0x0f18, 0x0f19,
+ 0x0f35, 0x0f35,
+ 0x0f37, 0x0f37,
+ 0x0f39, 0x0f39,
+ 0x0f71, 0x0f7e,
+ 0x0f80, 0x0f84,
+ 0x0f86, 0x0f87,
+ 0x0f8d, 0x0f97,
+ 0x0f99, 0x0fbc,
+ 0x0fc6, 0x0fc6,
+ 0x102d, 0x1030,
+ 0x1032, 0x1037,
+ 0x1039, 0x103a,
+ 0x103d, 0x103e,
+ 0x1058, 0x1059,
+ 0x105e, 0x1060,
+ 0x1071, 0x1074,
+ 0x1082, 0x1082,
+ 0x1085, 0x1086,
+ 0x108d, 0x108d,
+ 0x109d, 0x109d,
+ 0x135d, 0x135f,
+ 0x1712, 0x1715,
+ 0x1732, 0x1734,
+ 0x1752, 0x1753,
+ 0x1772, 0x1773,
+ 0x17b4, 0x17b5,
+ 0x17b7, 0x17bd,
+ 0x17c6, 0x17c6,
+ 0x17c9, 0x17d3,
+ 0x17dd, 0x17dd,
+ 0x180b, 0x180d,
+ 0x180f, 0x180f,
+ 0x1885, 0x1886,
+ 0x18a9, 0x18a9,
+ 0x1920, 0x1922,
+ 0x1927, 0x1928,
+ 0x1932, 0x1932,
+ 0x1939, 0x193b,
+ 0x1a17, 0x1a18,
+ 0x1a1b, 0x1a1b,
+ 0x1a56, 0x1a56,
+ 0x1a58, 0x1a5e,
+ 0x1a60, 0x1a60,
+ 0x1a62, 0x1a62,
+ 0x1a65, 0x1a6c,
+ 0x1a73, 0x1a7c,
+ 0x1a7f, 0x1a7f,
+ 0x1ab0, 0x1add,
+ 0x1ae0, 0x1aeb,
+ 0x1b00, 0x1b03,
+ 0x1b34, 0x1b3d,
+ 0x1b42, 0x1b44,
+ 0x1b6b, 0x1b73,
+ 0x1b80, 0x1b81,
+ 0x1ba2, 0x1ba5,
+ 0x1ba8, 0x1bad,
+ 0x1be6, 0x1be6,
+ 0x1be8, 0x1be9,
+ 0x1bed, 0x1bed,
+ 0x1bef, 0x1bf3,
+ 0x1c2c, 0x1c33,
+ 0x1c36, 0x1c37,
+ 0x1cd0, 0x1cd2,
+ 0x1cd4, 0x1ce0,
+ 0x1ce2, 0x1ce8,
+ 0x1ced, 0x1ced,
+ 0x1cf4, 0x1cf4,
+ 0x1cf8, 0x1cf9,
+ 0x1dc0, 0x1dff,
+ 0x200c, 0x200c,
+ 0x20d0, 0x20f0,
+ 0x2cef, 0x2cf1,
+ 0x2d7f, 0x2d7f,
+ 0x2de0, 0x2dff,
+ 0x302a, 0x302f,
+ 0x3099, 0x309a,
+ 0xa66f, 0xa672,
+ 0xa674, 0xa67d,
+ 0xa69e, 0xa69f,
+ 0xa6f0, 0xa6f1,
+ 0xa802, 0xa802,
+ 0xa806, 0xa806,
+ 0xa80b, 0xa80b,
+ 0xa825, 0xa826,
+ 0xa82c, 0xa82c,
+ 0xa8c4, 0xa8c5,
+ 0xa8e0, 0xa8f1,
+ 0xa8ff, 0xa8ff,
+ 0xa926, 0xa92d,
+ 0xa947, 0xa951,
+ 0xa953, 0xa953,
+ 0xa980, 0xa982,
+ 0xa9b3, 0xa9b3,
+ 0xa9b6, 0xa9b9,
+ 0xa9bc, 0xa9bd,
+ 0xa9c0, 0xa9c0,
+ 0xa9e5, 0xa9e5,
+ 0xaa29, 0xaa2e,
+ 0xaa31, 0xaa32,
+ 0xaa35, 0xaa36,
+ 0xaa43, 0xaa43,
+ 0xaa4c, 0xaa4c,
+ 0xaa7c, 0xaa7c,
+ 0xaab0, 0xaab0,
+ 0xaab2, 0xaab4,
+ 0xaab7, 0xaab8,
+ 0xaabe, 0xaabf,
+ 0xaac1, 0xaac1,
+ 0xaaec, 0xaaed,
+ 0xaaf6, 0xaaf6,
+ 0xabe5, 0xabe5,
+ 0xabe8, 0xabe8,
+ 0xabed, 0xabed,
+ 0xfb1e, 0xfb1e,
+ 0xfe00, 0xfe0f,
+ 0xfe20, 0xfe2f,
+ 0xff9e, 0xff9f,
+ 0x101fd, 0x101fd,
+ 0x102e0, 0x102e0,
+ 0x10376, 0x1037a,
+ 0x10a01, 0x10a03,
+ 0x10a05, 0x10a06,
+ 0x10a0c, 0x10a0f,
+ 0x10a38, 0x10a3a,
+ 0x10a3f, 0x10a3f,
+ 0x10ae5, 0x10ae6,
+ 0x10d24, 0x10d27,
+ 0x10d69, 0x10d6d,
+ 0x10eab, 0x10eac,
+ 0x10efa, 0x10eff,
+ 0x10f46, 0x10f50,
+ 0x10f82, 0x10f85,
+ 0x11001, 0x11001,
+ 0x11038, 0x11046,
+ 0x11070, 0x11070,
+ 0x11073, 0x11074,
+ 0x1107f, 0x11081,
+ 0x110b3, 0x110b6,
+ 0x110b9, 0x110ba,
+ 0x110c2, 0x110c2,
+ 0x11100, 0x11102,
+ 0x11127, 0x1112b,
+ 0x1112d, 0x11134,
+ 0x11173, 0x11173,
+ 0x11180, 0x11181,
+ 0x111b6, 0x111be,
+ 0x111c0, 0x111c0,
+ 0x111c9, 0x111cc,
+ 0x111cf, 0x111cf,
+ 0x1122f, 0x11231,
+ 0x11234, 0x11237,
+ 0x1123e, 0x1123e,
+ 0x11241, 0x11241,
+ 0x112df, 0x112df,
+ 0x112e3, 0x112ea,
+ 0x11300, 0x11301,
+ 0x1133b, 0x1133c,
+ 0x1133e, 0x1133e,
+ 0x11340, 0x11340,
+ 0x1134d, 0x1134d,
+ 0x11357, 0x11357,
+ 0x11366, 0x1136c,
+ 0x11370, 0x11374,
+ 0x113b8, 0x113b8,
+ 0x113bb, 0x113c0,
+ 0x113c2, 0x113c2,
+ 0x113c5, 0x113c5,
+ 0x113c7, 0x113c9,
+ 0x113ce, 0x113d0,
+ 0x113d2, 0x113d2,
+ 0x113e1, 0x113e2,
+ 0x11438, 0x1143f,
+ 0x11442, 0x11444,
+ 0x11446, 0x11446,
+ 0x1145e, 0x1145e,
+ 0x114b0, 0x114b0,
+ 0x114b3, 0x114b8,
+ 0x114ba, 0x114ba,
+ 0x114bd, 0x114bd,
+ 0x114bf, 0x114c0,
+ 0x114c2, 0x114c3,
+ 0x115af, 0x115af,
+ 0x115b2, 0x115b5,
+ 0x115bc, 0x115bd,
+ 0x115bf, 0x115c0,
+ 0x115dc, 0x115dd,
+ 0x11633, 0x1163a,
+ 0x1163d, 0x1163d,
+ 0x1163f, 0x11640,
+ 0x116ab, 0x116ab,
+ 0x116ad, 0x116ad,
+ 0x116b0, 0x116b7,
+ 0x1171d, 0x1171d,
+ 0x1171f, 0x1171f,
+ 0x11722, 0x11725,
+ 0x11727, 0x1172b,
+ 0x1182f, 0x11837,
+ 0x11839, 0x1183a,
+ 0x11930, 0x11930,
+ 0x1193b, 0x1193e,
+ 0x11943, 0x11943,
+ 0x119d4, 0x119d7,
+ 0x119da, 0x119db,
+ 0x119e0, 0x119e0,
+ 0x11a01, 0x11a0a,
+ 0x11a33, 0x11a38,
+ 0x11a3b, 0x11a3e,
+ 0x11a47, 0x11a47,
+ 0x11a51, 0x11a56,
+ 0x11a59, 0x11a5b,
+ 0x11a8a, 0x11a96,
+ 0x11a98, 0x11a99,
+ 0x11b60, 0x11b60,
+ 0x11b62, 0x11b64,
+ 0x11b66, 0x11b66,
+ 0x11c30, 0x11c36,
+ 0x11c38, 0x11c3d,
+ 0x11c3f, 0x11c3f,
+ 0x11c92, 0x11ca7,
+ 0x11caa, 0x11cb0,
+ 0x11cb2, 0x11cb3,
+ 0x11cb5, 0x11cb6,
+ 0x11d31, 0x11d36,
+ 0x11d3a, 0x11d3a,
+ 0x11d3c, 0x11d3d,
+ 0x11d3f, 0x11d45,
+ 0x11d47, 0x11d47,
+ 0x11d90, 0x11d91,
+ 0x11d95, 0x11d95,
+ 0x11d97, 0x11d97,
+ 0x11ef3, 0x11ef4,
+ 0x11f00, 0x11f01,
+ 0x11f36, 0x11f3a,
+ 0x11f40, 0x11f42,
+ 0x11f5a, 0x11f5a,
+ 0x13440, 0x13440,
+ 0x13447, 0x13455,
+ 0x1611e, 0x16129,
+ 0x1612d, 0x1612f,
+ 0x16af0, 0x16af4,
+ 0x16b30, 0x16b36,
+ 0x16f4f, 0x16f4f,
+ 0x16f8f, 0x16f92,
+ 0x16fe4, 0x16fe4,
+ 0x16ff0, 0x16ff1,
+ 0x1bc9d, 0x1bc9e,
+ 0x1cf00, 0x1cf2d,
+ 0x1cf30, 0x1cf46,
+ 0x1d165, 0x1d169,
+ 0x1d16d, 0x1d172,
+ 0x1d17b, 0x1d182,
+ 0x1d185, 0x1d18b,
+ 0x1d1aa, 0x1d1ad,
+ 0x1d242, 0x1d244,
+ 0x1da00, 0x1da36,
+ 0x1da3b, 0x1da6c,
+ 0x1da75, 0x1da75,
+ 0x1da84, 0x1da84,
+ 0x1da9b, 0x1da9f,
+ 0x1daa1, 0x1daaf,
+ 0x1e000, 0x1e006,
+ 0x1e008, 0x1e018,
+ 0x1e01b, 0x1e021,
+ 0x1e023, 0x1e024,
+ 0x1e026, 0x1e02a,
+ 0x1e08f, 0x1e08f,
+ 0x1e130, 0x1e136,
+ 0x1e2ae, 0x1e2ae,
+ 0x1e2ec, 0x1e2ef,
+ 0x1e4ec, 0x1e4ef,
+ 0x1e5ee, 0x1e5ef,
+ 0x1e6e3, 0x1e6e3,
+ 0x1e6e6, 0x1e6e6,
+ 0x1e6ee, 0x1e6ef,
+ 0x1e6f5, 0x1e6f5,
+ 0x1e8d0, 0x1e8d6,
+ 0x1e944, 0x1e94a,
+ 0xe0020, 0xe007f,
+ 0xe0100, 0xe01ef,
+}; /* CR_Grapheme_Extend */
+
+/* 'Grapheme_Base': Derived Property */
+static const OnigCodePoint CR_Grapheme_Base[] = {
+ 904,
+ 0x0020, 0x007e,
+ 0x00a0, 0x00ac,
+ 0x00ae, 0x02ff,
+ 0x0370, 0x0377,
+ 0x037a, 0x037f,
+ 0x0384, 0x038a,
+ 0x038c, 0x038c,
+ 0x038e, 0x03a1,
+ 0x03a3, 0x0482,
+ 0x048a, 0x052f,
+ 0x0531, 0x0556,
+ 0x0559, 0x058a,
+ 0x058d, 0x058f,
+ 0x05be, 0x05be,
+ 0x05c0, 0x05c0,
+ 0x05c3, 0x05c3,
+ 0x05c6, 0x05c6,
+ 0x05d0, 0x05ea,
+ 0x05ef, 0x05f4,
+ 0x0606, 0x060f,
+ 0x061b, 0x061b,
+ 0x061d, 0x064a,
+ 0x0660, 0x066f,
+ 0x0671, 0x06d5,
+ 0x06de, 0x06de,
+ 0x06e5, 0x06e6,
+ 0x06e9, 0x06e9,
+ 0x06ee, 0x070d,
+ 0x0710, 0x0710,
+ 0x0712, 0x072f,
+ 0x074d, 0x07a5,
+ 0x07b1, 0x07b1,
+ 0x07c0, 0x07ea,
+ 0x07f4, 0x07fa,
+ 0x07fe, 0x0815,
+ 0x081a, 0x081a,
+ 0x0824, 0x0824,
+ 0x0828, 0x0828,
+ 0x0830, 0x083e,
+ 0x0840, 0x0858,
+ 0x085e, 0x085e,
+ 0x0860, 0x086a,
+ 0x0870, 0x088f,
+ 0x08a0, 0x08c9,
+ 0x0903, 0x0939,
+ 0x093b, 0x093b,
+ 0x093d, 0x0940,
+ 0x0949, 0x094c,
+ 0x094e, 0x0950,
+ 0x0958, 0x0961,
+ 0x0964, 0x0980,
+ 0x0982, 0x0983,
+ 0x0985, 0x098c,
+ 0x098f, 0x0990,
+ 0x0993, 0x09a8,
+ 0x09aa, 0x09b0,
+ 0x09b2, 0x09b2,
+ 0x09b6, 0x09b9,
+ 0x09bd, 0x09bd,
+ 0x09bf, 0x09c0,
+ 0x09c7, 0x09c8,
+ 0x09cb, 0x09cc,
+ 0x09ce, 0x09ce,
+ 0x09dc, 0x09dd,
+ 0x09df, 0x09e1,
+ 0x09e6, 0x09fd,
+ 0x0a03, 0x0a03,
+ 0x0a05, 0x0a0a,
+ 0x0a0f, 0x0a10,
+ 0x0a13, 0x0a28,
+ 0x0a2a, 0x0a30,
+ 0x0a32, 0x0a33,
+ 0x0a35, 0x0a36,
+ 0x0a38, 0x0a39,
+ 0x0a3e, 0x0a40,
+ 0x0a59, 0x0a5c,
+ 0x0a5e, 0x0a5e,
+ 0x0a66, 0x0a6f,
+ 0x0a72, 0x0a74,
+ 0x0a76, 0x0a76,
+ 0x0a83, 0x0a83,
+ 0x0a85, 0x0a8d,
+ 0x0a8f, 0x0a91,
+ 0x0a93, 0x0aa8,
+ 0x0aaa, 0x0ab0,
+ 0x0ab2, 0x0ab3,
+ 0x0ab5, 0x0ab9,
+ 0x0abd, 0x0ac0,
+ 0x0ac9, 0x0ac9,
+ 0x0acb, 0x0acc,
+ 0x0ad0, 0x0ad0,
+ 0x0ae0, 0x0ae1,
+ 0x0ae6, 0x0af1,
+ 0x0af9, 0x0af9,
+ 0x0b02, 0x0b03,
+ 0x0b05, 0x0b0c,
+ 0x0b0f, 0x0b10,
+ 0x0b13, 0x0b28,
+ 0x0b2a, 0x0b30,
+ 0x0b32, 0x0b33,
+ 0x0b35, 0x0b39,
+ 0x0b3d, 0x0b3d,
+ 0x0b40, 0x0b40,
+ 0x0b47, 0x0b48,
+ 0x0b4b, 0x0b4c,
+ 0x0b5c, 0x0b5d,
+ 0x0b5f, 0x0b61,
+ 0x0b66, 0x0b77,
+ 0x0b83, 0x0b83,
+ 0x0b85, 0x0b8a,
+ 0x0b8e, 0x0b90,
+ 0x0b92, 0x0b95,
+ 0x0b99, 0x0b9a,
+ 0x0b9c, 0x0b9c,
+ 0x0b9e, 0x0b9f,
+ 0x0ba3, 0x0ba4,
+ 0x0ba8, 0x0baa,
+ 0x0bae, 0x0bb9,
+ 0x0bbf, 0x0bbf,
+ 0x0bc1, 0x0bc2,
+ 0x0bc6, 0x0bc8,
+ 0x0bca, 0x0bcc,
+ 0x0bd0, 0x0bd0,
+ 0x0be6, 0x0bfa,
+ 0x0c01, 0x0c03,
+ 0x0c05, 0x0c0c,
+ 0x0c0e, 0x0c10,
+ 0x0c12, 0x0c28,
+ 0x0c2a, 0x0c39,
+ 0x0c3d, 0x0c3d,
+ 0x0c41, 0x0c44,
+ 0x0c58, 0x0c5a,
+ 0x0c5c, 0x0c5d,
+ 0x0c60, 0x0c61,
+ 0x0c66, 0x0c6f,
+ 0x0c77, 0x0c80,
+ 0x0c82, 0x0c8c,
+ 0x0c8e, 0x0c90,
+ 0x0c92, 0x0ca8,
+ 0x0caa, 0x0cb3,
+ 0x0cb5, 0x0cb9,
+ 0x0cbd, 0x0cbe,
+ 0x0cc1, 0x0cc1,
+ 0x0cc3, 0x0cc4,
+ 0x0cdc, 0x0cde,
+ 0x0ce0, 0x0ce1,
+ 0x0ce6, 0x0cef,
+ 0x0cf1, 0x0cf3,
+ 0x0d02, 0x0d0c,
+ 0x0d0e, 0x0d10,
+ 0x0d12, 0x0d3a,
+ 0x0d3d, 0x0d3d,
+ 0x0d3f, 0x0d40,
+ 0x0d46, 0x0d48,
+ 0x0d4a, 0x0d4c,
+ 0x0d4e, 0x0d4f,
+ 0x0d54, 0x0d56,
+ 0x0d58, 0x0d61,
+ 0x0d66, 0x0d7f,
+ 0x0d82, 0x0d83,
+ 0x0d85, 0x0d96,
+ 0x0d9a, 0x0db1,
+ 0x0db3, 0x0dbb,
+ 0x0dbd, 0x0dbd,
+ 0x0dc0, 0x0dc6,
+ 0x0dd0, 0x0dd1,
+ 0x0dd8, 0x0dde,
+ 0x0de6, 0x0def,
+ 0x0df2, 0x0df4,
+ 0x0e01, 0x0e30,
+ 0x0e32, 0x0e33,
+ 0x0e3f, 0x0e46,
+ 0x0e4f, 0x0e5b,
+ 0x0e81, 0x0e82,
+ 0x0e84, 0x0e84,
+ 0x0e86, 0x0e8a,
+ 0x0e8c, 0x0ea3,
+ 0x0ea5, 0x0ea5,
+ 0x0ea7, 0x0eb0,
+ 0x0eb2, 0x0eb3,
+ 0x0ebd, 0x0ebd,
+ 0x0ec0, 0x0ec4,
+ 0x0ec6, 0x0ec6,
+ 0x0ed0, 0x0ed9,
+ 0x0edc, 0x0edf,
+ 0x0f00, 0x0f17,
+ 0x0f1a, 0x0f34,
+ 0x0f36, 0x0f36,
+ 0x0f38, 0x0f38,
+ 0x0f3a, 0x0f47,
+ 0x0f49, 0x0f6c,
+ 0x0f7f, 0x0f7f,
+ 0x0f85, 0x0f85,
+ 0x0f88, 0x0f8c,
+ 0x0fbe, 0x0fc5,
+ 0x0fc7, 0x0fcc,
+ 0x0fce, 0x0fda,
+ 0x1000, 0x102c,
+ 0x1031, 0x1031,
+ 0x1038, 0x1038,
+ 0x103b, 0x103c,
+ 0x103f, 0x1057,
+ 0x105a, 0x105d,
+ 0x1061, 0x1070,
+ 0x1075, 0x1081,
+ 0x1083, 0x1084,
+ 0x1087, 0x108c,
+ 0x108e, 0x109c,
+ 0x109e, 0x10c5,
+ 0x10c7, 0x10c7,
+ 0x10cd, 0x10cd,
+ 0x10d0, 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,
+ 0x1360, 0x137c,
+ 0x1380, 0x1399,
+ 0x13a0, 0x13f5,
+ 0x13f8, 0x13fd,
+ 0x1400, 0x169c,
+ 0x16a0, 0x16f8,
+ 0x1700, 0x1711,
+ 0x171f, 0x1731,
+ 0x1735, 0x1736,
+ 0x1740, 0x1751,
+ 0x1760, 0x176c,
+ 0x176e, 0x1770,
+ 0x1780, 0x17b3,
+ 0x17b6, 0x17b6,
+ 0x17be, 0x17c5,
+ 0x17c7, 0x17c8,
+ 0x17d4, 0x17dc,
+ 0x17e0, 0x17e9,
+ 0x17f0, 0x17f9,
+ 0x1800, 0x180a,
+ 0x1810, 0x1819,
+ 0x1820, 0x1878,
+ 0x1880, 0x1884,
+ 0x1887, 0x18a8,
+ 0x18aa, 0x18aa,
+ 0x18b0, 0x18f5,
+ 0x1900, 0x191e,
+ 0x1923, 0x1926,
+ 0x1929, 0x192b,
+ 0x1930, 0x1931,
+ 0x1933, 0x1938,
+ 0x1940, 0x1940,
+ 0x1944, 0x196d,
+ 0x1970, 0x1974,
+ 0x1980, 0x19ab,
+ 0x19b0, 0x19c9,
+ 0x19d0, 0x19da,
+ 0x19de, 0x1a16,
+ 0x1a19, 0x1a1a,
+ 0x1a1e, 0x1a55,
+ 0x1a57, 0x1a57,
+ 0x1a61, 0x1a61,
+ 0x1a63, 0x1a64,
+ 0x1a6d, 0x1a72,
+ 0x1a80, 0x1a89,
+ 0x1a90, 0x1a99,
+ 0x1aa0, 0x1aad,
+ 0x1b04, 0x1b33,
+ 0x1b3e, 0x1b41,
+ 0x1b45, 0x1b4c,
+ 0x1b4e, 0x1b6a,
+ 0x1b74, 0x1b7f,
+ 0x1b82, 0x1ba1,
+ 0x1ba6, 0x1ba7,
+ 0x1bae, 0x1be5,
+ 0x1be7, 0x1be7,
+ 0x1bea, 0x1bec,
+ 0x1bee, 0x1bee,
+ 0x1bfc, 0x1c2b,
+ 0x1c34, 0x1c35,
+ 0x1c3b, 0x1c49,
+ 0x1c4d, 0x1c8a,
+ 0x1c90, 0x1cba,
+ 0x1cbd, 0x1cc7,
+ 0x1cd3, 0x1cd3,
+ 0x1ce1, 0x1ce1,
+ 0x1ce9, 0x1cec,
+ 0x1cee, 0x1cf3,
+ 0x1cf5, 0x1cf7,
+ 0x1cfa, 0x1cfa,
+ 0x1d00, 0x1dbf,
+ 0x1e00, 0x1f15,
+ 0x1f18, 0x1f1d,
+ 0x1f20, 0x1f45,
+ 0x1f48, 0x1f4d,
+ 0x1f50, 0x1f57,
+ 0x1f59, 0x1f59,
+ 0x1f5b, 0x1f5b,
+ 0x1f5d, 0x1f5d,
+ 0x1f5f, 0x1f7d,
+ 0x1f80, 0x1fb4,
+ 0x1fb6, 0x1fc4,
+ 0x1fc6, 0x1fd3,
+ 0x1fd6, 0x1fdb,
+ 0x1fdd, 0x1fef,
+ 0x1ff2, 0x1ff4,
+ 0x1ff6, 0x1ffe,
+ 0x2000, 0x200a,
+ 0x2010, 0x2027,
+ 0x202f, 0x205f,
+ 0x2070, 0x2071,
+ 0x2074, 0x208e,
+ 0x2090, 0x209c,
+ 0x20a0, 0x20c1,
+ 0x2100, 0x218b,
+ 0x2190, 0x2429,
+ 0x2440, 0x244a,
+ 0x2460, 0x2b73,
+ 0x2b76, 0x2cee,
+ 0x2cf2, 0x2cf3,
+ 0x2cf9, 0x2d25,
+ 0x2d27, 0x2d27,
+ 0x2d2d, 0x2d2d,
+ 0x2d30, 0x2d67,
+ 0x2d6f, 0x2d70,
+ 0x2d80, 0x2d96,
+ 0x2da0, 0x2da6,
+ 0x2da8, 0x2dae,
+ 0x2db0, 0x2db6,
+ 0x2db8, 0x2dbe,
+ 0x2dc0, 0x2dc6,
+ 0x2dc8, 0x2dce,
+ 0x2dd0, 0x2dd6,
+ 0x2dd8, 0x2dde,
+ 0x2e00, 0x2e5d,
+ 0x2e80, 0x2e99,
+ 0x2e9b, 0x2ef3,
+ 0x2f00, 0x2fd5,
+ 0x2ff0, 0x3029,
+ 0x3030, 0x303f,
+ 0x3041, 0x3096,
+ 0x309b, 0x30ff,
+ 0x3105, 0x312f,
+ 0x3131, 0x318e,
+ 0x3190, 0x31e5,
+ 0x31ef, 0x321e,
+ 0x3220, 0xa48c,
+ 0xa490, 0xa4c6,
+ 0xa4d0, 0xa62b,
+ 0xa640, 0xa66e,
+ 0xa673, 0xa673,
+ 0xa67e, 0xa69d,
+ 0xa6a0, 0xa6ef,
+ 0xa6f2, 0xa6f7,
+ 0xa700, 0xa7dc,
+ 0xa7f1, 0xa801,
+ 0xa803, 0xa805,
+ 0xa807, 0xa80a,
+ 0xa80c, 0xa824,
+ 0xa827, 0xa82b,
+ 0xa830, 0xa839,
+ 0xa840, 0xa877,
+ 0xa880, 0xa8c3,
+ 0xa8ce, 0xa8d9,
+ 0xa8f2, 0xa8fe,
+ 0xa900, 0xa925,
+ 0xa92e, 0xa946,
+ 0xa952, 0xa952,
+ 0xa95f, 0xa97c,
+ 0xa983, 0xa9b2,
+ 0xa9b4, 0xa9b5,
+ 0xa9ba, 0xa9bb,
+ 0xa9be, 0xa9bf,
+ 0xa9c1, 0xa9cd,
+ 0xa9cf, 0xa9d9,
+ 0xa9de, 0xa9e4,
+ 0xa9e6, 0xa9fe,
+ 0xaa00, 0xaa28,
+ 0xaa2f, 0xaa30,
+ 0xaa33, 0xaa34,
+ 0xaa40, 0xaa42,
+ 0xaa44, 0xaa4b,
+ 0xaa4d, 0xaa4d,
+ 0xaa50, 0xaa59,
+ 0xaa5c, 0xaa7b,
+ 0xaa7d, 0xaaaf,
+ 0xaab1, 0xaab1,
+ 0xaab5, 0xaab6,
+ 0xaab9, 0xaabd,
+ 0xaac0, 0xaac0,
+ 0xaac2, 0xaac2,
+ 0xaadb, 0xaaeb,
+ 0xaaee, 0xaaf5,
+ 0xab01, 0xab06,
+ 0xab09, 0xab0e,
+ 0xab11, 0xab16,
+ 0xab20, 0xab26,
+ 0xab28, 0xab2e,
+ 0xab30, 0xab6b,
+ 0xab70, 0xabe4,
+ 0xabe6, 0xabe7,
+ 0xabe9, 0xabec,
+ 0xabf0, 0xabf9,
+ 0xac00, 0xd7a3,
+ 0xd7b0, 0xd7c6,
+ 0xd7cb, 0xd7fb,
+ 0xf900, 0xfa6d,
+ 0xfa70, 0xfad9,
+ 0xfb00, 0xfb06,
+ 0xfb13, 0xfb17,
+ 0xfb1d, 0xfb1d,
+ 0xfb1f, 0xfb36,
+ 0xfb38, 0xfb3c,
+ 0xfb3e, 0xfb3e,
+ 0xfb40, 0xfb41,
+ 0xfb43, 0xfb44,
+ 0xfb46, 0xfdcf,
+ 0xfdf0, 0xfdff,
+ 0xfe10, 0xfe19,
+ 0xfe30, 0xfe52,
+ 0xfe54, 0xfe66,
+ 0xfe68, 0xfe6b,
+ 0xfe70, 0xfe74,
+ 0xfe76, 0xfefc,
+ 0xff01, 0xff9d,
+ 0xffa0, 0xffbe,
+ 0xffc2, 0xffc7,
+ 0xffca, 0xffcf,
+ 0xffd2, 0xffd7,
+ 0xffda, 0xffdc,
+ 0xffe0, 0xffe6,
+ 0xffe8, 0xffee,
+ 0xfffc, 0xfffd,
+ 0x10000, 0x1000b,
+ 0x1000d, 0x10026,
+ 0x10028, 0x1003a,
+ 0x1003c, 0x1003d,
+ 0x1003f, 0x1004d,
+ 0x10050, 0x1005d,
+ 0x10080, 0x100fa,
+ 0x10100, 0x10102,
+ 0x10107, 0x10133,
+ 0x10137, 0x1018e,
+ 0x10190, 0x1019c,
+ 0x101a0, 0x101a0,
+ 0x101d0, 0x101fc,
+ 0x10280, 0x1029c,
+ 0x102a0, 0x102d0,
+ 0x102e1, 0x102fb,
+ 0x10300, 0x10323,
+ 0x1032d, 0x1034a,
+ 0x10350, 0x10375,
+ 0x10380, 0x1039d,
+ 0x1039f, 0x103c3,
+ 0x103c8, 0x103d5,
+ 0x10400, 0x1049d,
+ 0x104a0, 0x104a9,
+ 0x104b0, 0x104d3,
+ 0x104d8, 0x104fb,
+ 0x10500, 0x10527,
+ 0x10530, 0x10563,
+ 0x1056f, 0x1057a,
+ 0x1057c, 0x1058a,
+ 0x1058c, 0x10592,
+ 0x10594, 0x10595,
+ 0x10597, 0x105a1,
+ 0x105a3, 0x105b1,
+ 0x105b3, 0x105b9,
+ 0x105bb, 0x105bc,
+ 0x105c0, 0x105f3,
+ 0x10600, 0x10736,
+ 0x10740, 0x10755,
+ 0x10760, 0x10767,
+ 0x10780, 0x10785,
+ 0x10787, 0x107b0,
+ 0x107b2, 0x107ba,
+ 0x10800, 0x10805,
+ 0x10808, 0x10808,
+ 0x1080a, 0x10835,
+ 0x10837, 0x10838,
+ 0x1083c, 0x1083c,
+ 0x1083f, 0x10855,
+ 0x10857, 0x1089e,
+ 0x108a7, 0x108af,
+ 0x108e0, 0x108f2,
+ 0x108f4, 0x108f5,
+ 0x108fb, 0x1091b,
+ 0x1091f, 0x10939,
+ 0x1093f, 0x10959,
+ 0x10980, 0x109b7,
+ 0x109bc, 0x109cf,
+ 0x109d2, 0x10a00,
+ 0x10a10, 0x10a13,
+ 0x10a15, 0x10a17,
+ 0x10a19, 0x10a35,
+ 0x10a40, 0x10a48,
+ 0x10a50, 0x10a58,
+ 0x10a60, 0x10a9f,
+ 0x10ac0, 0x10ae4,
+ 0x10aeb, 0x10af6,
+ 0x10b00, 0x10b35,
+ 0x10b39, 0x10b55,
+ 0x10b58, 0x10b72,
+ 0x10b78, 0x10b91,
+ 0x10b99, 0x10b9c,
+ 0x10ba9, 0x10baf,
+ 0x10c00, 0x10c48,
+ 0x10c80, 0x10cb2,
+ 0x10cc0, 0x10cf2,
+ 0x10cfa, 0x10d23,
+ 0x10d30, 0x10d39,
+ 0x10d40, 0x10d65,
+ 0x10d6e, 0x10d85,
+ 0x10d8e, 0x10d8f,
+ 0x10e60, 0x10e7e,
+ 0x10e80, 0x10ea9,
+ 0x10ead, 0x10ead,
+ 0x10eb0, 0x10eb1,
+ 0x10ec2, 0x10ec7,
+ 0x10ed0, 0x10ed8,
+ 0x10f00, 0x10f27,
+ 0x10f30, 0x10f45,
+ 0x10f51, 0x10f59,
+ 0x10f70, 0x10f81,
+ 0x10f86, 0x10f89,
+ 0x10fb0, 0x10fcb,
+ 0x10fe0, 0x10ff6,
+ 0x11000, 0x11000,
+ 0x11002, 0x11037,
+ 0x11047, 0x1104d,
+ 0x11052, 0x1106f,
+ 0x11071, 0x11072,
+ 0x11075, 0x11075,
+ 0x11082, 0x110b2,
+ 0x110b7, 0x110b8,
+ 0x110bb, 0x110bc,
+ 0x110be, 0x110c1,
+ 0x110d0, 0x110e8,
+ 0x110f0, 0x110f9,
+ 0x11103, 0x11126,
+ 0x1112c, 0x1112c,
+ 0x11136, 0x11147,
+ 0x11150, 0x11172,
+ 0x11174, 0x11176,
+ 0x11182, 0x111b5,
+ 0x111bf, 0x111bf,
+ 0x111c1, 0x111c8,
+ 0x111cd, 0x111ce,
+ 0x111d0, 0x111df,
+ 0x111e1, 0x111f4,
+ 0x11200, 0x11211,
+ 0x11213, 0x1122e,
+ 0x11232, 0x11233,
+ 0x11238, 0x1123d,
+ 0x1123f, 0x11240,
+ 0x11280, 0x11286,
+ 0x11288, 0x11288,
+ 0x1128a, 0x1128d,
+ 0x1128f, 0x1129d,
+ 0x1129f, 0x112a9,
+ 0x112b0, 0x112de,
+ 0x112e0, 0x112e2,
+ 0x112f0, 0x112f9,
+ 0x11302, 0x11303,
+ 0x11305, 0x1130c,
+ 0x1130f, 0x11310,
+ 0x11313, 0x11328,
+ 0x1132a, 0x11330,
+ 0x11332, 0x11333,
+ 0x11335, 0x11339,
+ 0x1133d, 0x1133d,
+ 0x1133f, 0x1133f,
+ 0x11341, 0x11344,
+ 0x11347, 0x11348,
+ 0x1134b, 0x1134c,
+ 0x11350, 0x11350,
+ 0x1135d, 0x11363,
+ 0x11380, 0x11389,
+ 0x1138b, 0x1138b,
+ 0x1138e, 0x1138e,
+ 0x11390, 0x113b5,
+ 0x113b7, 0x113b7,
+ 0x113b9, 0x113ba,
+ 0x113ca, 0x113ca,
+ 0x113cc, 0x113cd,
+ 0x113d1, 0x113d1,
+ 0x113d3, 0x113d5,
+ 0x113d7, 0x113d8,
+ 0x11400, 0x11437,
+ 0x11440, 0x11441,
+ 0x11445, 0x11445,
+ 0x11447, 0x1145b,
+ 0x1145d, 0x1145d,
+ 0x1145f, 0x11461,
+ 0x11480, 0x114af,
+ 0x114b1, 0x114b2,
+ 0x114b9, 0x114b9,
+ 0x114bb, 0x114bc,
+ 0x114be, 0x114be,
+ 0x114c1, 0x114c1,
+ 0x114c4, 0x114c7,
+ 0x114d0, 0x114d9,
+ 0x11580, 0x115ae,
+ 0x115b0, 0x115b1,
+ 0x115b8, 0x115bb,
+ 0x115be, 0x115be,
+ 0x115c1, 0x115db,
+ 0x11600, 0x11632,
+ 0x1163b, 0x1163c,
+ 0x1163e, 0x1163e,
+ 0x11641, 0x11644,
+ 0x11650, 0x11659,
+ 0x11660, 0x1166c,
+ 0x11680, 0x116aa,
+ 0x116ac, 0x116ac,
+ 0x116ae, 0x116af,
+ 0x116b8, 0x116b9,
+ 0x116c0, 0x116c9,
+ 0x116d0, 0x116e3,
+ 0x11700, 0x1171a,
+ 0x1171e, 0x1171e,
+ 0x11720, 0x11721,
+ 0x11726, 0x11726,
+ 0x11730, 0x11746,
+ 0x11800, 0x1182e,
+ 0x11838, 0x11838,
+ 0x1183b, 0x1183b,
+ 0x118a0, 0x118f2,
+ 0x118ff, 0x11906,
+ 0x11909, 0x11909,
+ 0x1190c, 0x11913,
+ 0x11915, 0x11916,
+ 0x11918, 0x1192f,
+ 0x11931, 0x11935,
+ 0x11937, 0x11938,
+ 0x1193f, 0x11942,
+ 0x11944, 0x11946,
+ 0x11950, 0x11959,
+ 0x119a0, 0x119a7,
+ 0x119aa, 0x119d3,
+ 0x119dc, 0x119df,
+ 0x119e1, 0x119e4,
+ 0x11a00, 0x11a00,
+ 0x11a0b, 0x11a32,
+ 0x11a39, 0x11a3a,
+ 0x11a3f, 0x11a46,
+ 0x11a50, 0x11a50,
+ 0x11a57, 0x11a58,
+ 0x11a5c, 0x11a89,
+ 0x11a97, 0x11a97,
+ 0x11a9a, 0x11aa2,
+ 0x11ab0, 0x11af8,
+ 0x11b00, 0x11b09,
+ 0x11b61, 0x11b61,
+ 0x11b65, 0x11b65,
+ 0x11b67, 0x11b67,
+ 0x11bc0, 0x11be1,
+ 0x11bf0, 0x11bf9,
+ 0x11c00, 0x11c08,
+ 0x11c0a, 0x11c2f,
+ 0x11c3e, 0x11c3e,
+ 0x11c40, 0x11c45,
+ 0x11c50, 0x11c6c,
+ 0x11c70, 0x11c8f,
+ 0x11ca9, 0x11ca9,
+ 0x11cb1, 0x11cb1,
+ 0x11cb4, 0x11cb4,
+ 0x11d00, 0x11d06,
+ 0x11d08, 0x11d09,
+ 0x11d0b, 0x11d30,
+ 0x11d46, 0x11d46,
+ 0x11d50, 0x11d59,
+ 0x11d60, 0x11d65,
+ 0x11d67, 0x11d68,
+ 0x11d6a, 0x11d8e,
+ 0x11d93, 0x11d94,
+ 0x11d96, 0x11d96,
+ 0x11d98, 0x11d98,
+ 0x11da0, 0x11da9,
+ 0x11db0, 0x11ddb,
+ 0x11de0, 0x11de9,
+ 0x11ee0, 0x11ef2,
+ 0x11ef5, 0x11ef8,
+ 0x11f02, 0x11f10,
+ 0x11f12, 0x11f35,
+ 0x11f3e, 0x11f3f,
+ 0x11f43, 0x11f59,
+ 0x11fb0, 0x11fb0,
+ 0x11fc0, 0x11ff1,
+ 0x11fff, 0x12399,
+ 0x12400, 0x1246e,
+ 0x12470, 0x12474,
+ 0x12480, 0x12543,
+ 0x12f90, 0x12ff2,
+ 0x13000, 0x1342f,
+ 0x13441, 0x13446,
+ 0x13460, 0x143fa,
+ 0x14400, 0x14646,
+ 0x16100, 0x1611d,
+ 0x1612a, 0x1612c,
+ 0x16130, 0x16139,
+ 0x16800, 0x16a38,
+ 0x16a40, 0x16a5e,
+ 0x16a60, 0x16a69,
+ 0x16a6e, 0x16abe,
+ 0x16ac0, 0x16ac9,
+ 0x16ad0, 0x16aed,
+ 0x16af5, 0x16af5,
+ 0x16b00, 0x16b2f,
+ 0x16b37, 0x16b45,
+ 0x16b50, 0x16b59,
+ 0x16b5b, 0x16b61,
+ 0x16b63, 0x16b77,
+ 0x16b7d, 0x16b8f,
+ 0x16d40, 0x16d79,
+ 0x16e40, 0x16e9a,
+ 0x16ea0, 0x16eb8,
+ 0x16ebb, 0x16ed3,
+ 0x16f00, 0x16f4a,
+ 0x16f50, 0x16f87,
+ 0x16f93, 0x16f9f,
+ 0x16fe0, 0x16fe3,
+ 0x16ff2, 0x16ff6,
+ 0x17000, 0x18cd5,
+ 0x18cff, 0x18d1e,
+ 0x18d80, 0x18df2,
+ 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,
+ 0x1bc9c, 0x1bc9c,
+ 0x1bc9f, 0x1bc9f,
+ 0x1cc00, 0x1ccfc,
+ 0x1cd00, 0x1ceb3,
+ 0x1ceba, 0x1ced0,
+ 0x1cee0, 0x1cef0,
+ 0x1cf50, 0x1cfc3,
+ 0x1d000, 0x1d0f5,
+ 0x1d100, 0x1d126,
+ 0x1d129, 0x1d164,
+ 0x1d16a, 0x1d16c,
+ 0x1d183, 0x1d184,
+ 0x1d18c, 0x1d1a9,
+ 0x1d1ae, 0x1d1ea,
+ 0x1d200, 0x1d241,
+ 0x1d245, 0x1d245,
+ 0x1d2c0, 0x1d2d3,
+ 0x1d2e0, 0x1d2f3,
+ 0x1d300, 0x1d356,
+ 0x1d360, 0x1d378,
+ 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, 0x1d7cb,
+ 0x1d7ce, 0x1d9ff,
+ 0x1da37, 0x1da3a,
+ 0x1da6d, 0x1da74,
+ 0x1da76, 0x1da83,
+ 0x1da85, 0x1da8b,
+ 0x1df00, 0x1df1e,
+ 0x1df25, 0x1df2a,
+ 0x1e030, 0x1e06d,
+ 0x1e100, 0x1e12c,
+ 0x1e137, 0x1e13d,
+ 0x1e140, 0x1e149,
+ 0x1e14e, 0x1e14f,
+ 0x1e290, 0x1e2ad,
+ 0x1e2c0, 0x1e2eb,
+ 0x1e2f0, 0x1e2f9,
+ 0x1e2ff, 0x1e2ff,
+ 0x1e4d0, 0x1e4eb,
+ 0x1e4f0, 0x1e4f9,
+ 0x1e5d0, 0x1e5ed,
+ 0x1e5f0, 0x1e5fa,
+ 0x1e5ff, 0x1e5ff,
+ 0x1e6c0, 0x1e6de,
+ 0x1e6e0, 0x1e6e2,
+ 0x1e6e4, 0x1e6e5,
+ 0x1e6e7, 0x1e6ed,
+ 0x1e6f0, 0x1e6f4,
+ 0x1e6fe, 0x1e6ff,
+ 0x1e7e0, 0x1e7e6,
+ 0x1e7e8, 0x1e7eb,
+ 0x1e7ed, 0x1e7ee,
+ 0x1e7f0, 0x1e7fe,
+ 0x1e800, 0x1e8c4,
+ 0x1e8c7, 0x1e8cf,
+ 0x1e900, 0x1e943,
+ 0x1e94b, 0x1e94b,
+ 0x1e950, 0x1e959,
+ 0x1e95e, 0x1e95f,
+ 0x1ec71, 0x1ecb4,
+ 0x1ed01, 0x1ed3d,
+ 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,
+ 0x1eef0, 0x1eef1,
+ 0x1f000, 0x1f02b,
+ 0x1f030, 0x1f093,
+ 0x1f0a0, 0x1f0ae,
+ 0x1f0b1, 0x1f0bf,
+ 0x1f0c1, 0x1f0cf,
+ 0x1f0d1, 0x1f0f5,
+ 0x1f100, 0x1f1ad,
+ 0x1f1e6, 0x1f202,
+ 0x1f210, 0x1f23b,
+ 0x1f240, 0x1f248,
+ 0x1f250, 0x1f251,
+ 0x1f260, 0x1f265,
+ 0x1f300, 0x1f6d8,
+ 0x1f6dc, 0x1f6ec,
+ 0x1f6f0, 0x1f6fc,
+ 0x1f700, 0x1f7d9,
+ 0x1f7e0, 0x1f7eb,
+ 0x1f7f0, 0x1f7f0,
+ 0x1f800, 0x1f80b,
+ 0x1f810, 0x1f847,
+ 0x1f850, 0x1f859,
+ 0x1f860, 0x1f887,
+ 0x1f890, 0x1f8ad,
+ 0x1f8b0, 0x1f8bb,
+ 0x1f8c0, 0x1f8c1,
+ 0x1f8d0, 0x1f8d8,
+ 0x1f900, 0x1fa57,
+ 0x1fa60, 0x1fa6d,
+ 0x1fa70, 0x1fa7c,
+ 0x1fa80, 0x1fa8a,
+ 0x1fa8e, 0x1fac6,
+ 0x1fac8, 0x1fac8,
+ 0x1facd, 0x1fadc,
+ 0x1fadf, 0x1faea,
+ 0x1faef, 0x1faf8,
+ 0x1fb00, 0x1fb92,
+ 0x1fb94, 0x1fbfa,
+ 0x20000, 0x2a6df,
+ 0x2a700, 0x2b81d,
+ 0x2b820, 0x2cead,
+ 0x2ceb0, 0x2ebe0,
+ 0x2ebf0, 0x2ee5d,
+ 0x2f800, 0x2fa1d,
+ 0x30000, 0x3134a,
+ 0x31350, 0x33479,
+}; /* CR_Grapheme_Base */
+
+/* 'Grapheme_Link': Derived Property */
+static const OnigCodePoint CR_Grapheme_Link[] = {
+ 58,
+ 0x094d, 0x094d,
+ 0x09cd, 0x09cd,
+ 0x0a4d, 0x0a4d,
+ 0x0acd, 0x0acd,
+ 0x0b4d, 0x0b4d,
+ 0x0bcd, 0x0bcd,
+ 0x0c4d, 0x0c4d,
+ 0x0ccd, 0x0ccd,
+ 0x0d3b, 0x0d3c,
+ 0x0d4d, 0x0d4d,
+ 0x0dca, 0x0dca,
+ 0x0e3a, 0x0e3a,
+ 0x0eba, 0x0eba,
+ 0x0f84, 0x0f84,
+ 0x1039, 0x103a,
+ 0x1714, 0x1715,
+ 0x1734, 0x1734,
+ 0x17d2, 0x17d2,
+ 0x1a60, 0x1a60,
+ 0x1b44, 0x1b44,
+ 0x1baa, 0x1bab,
+ 0x1bf2, 0x1bf3,
+ 0x2d7f, 0x2d7f,
+ 0xa806, 0xa806,
+ 0xa82c, 0xa82c,
+ 0xa8c4, 0xa8c4,
+ 0xa953, 0xa953,
+ 0xa9c0, 0xa9c0,
+ 0xaaf6, 0xaaf6,
+ 0xabed, 0xabed,
+ 0x10a3f, 0x10a3f,
+ 0x11046, 0x11046,
+ 0x11070, 0x11070,
+ 0x1107f, 0x1107f,
+ 0x110b9, 0x110b9,
+ 0x11133, 0x11134,
+ 0x111c0, 0x111c0,
+ 0x11235, 0x11235,
+ 0x112ea, 0x112ea,
+ 0x1134d, 0x1134d,
+ 0x113ce, 0x113d0,
+ 0x11442, 0x11442,
+ 0x114c2, 0x114c2,
+ 0x115bf, 0x115bf,
+ 0x1163f, 0x1163f,
+ 0x116b6, 0x116b6,
+ 0x1172b, 0x1172b,
+ 0x11839, 0x11839,
+ 0x1193d, 0x1193e,
+ 0x119e0, 0x119e0,
+ 0x11a34, 0x11a34,
+ 0x11a47, 0x11a47,
+ 0x11a99, 0x11a99,
+ 0x11c3f, 0x11c3f,
+ 0x11d44, 0x11d45,
+ 0x11d97, 0x11d97,
+ 0x11f41, 0x11f42,
+ 0x1612f, 0x1612f,
+}; /* CR_Grapheme_Link */
+
+/* 'InCB_Linker': Derived Property */
+static const OnigCodePoint CR_InCB_Linker[] = {
+ 20,
+ 0x094d, 0x094d,
+ 0x09cd, 0x09cd,
+ 0x0acd, 0x0acd,
+ 0x0b4d, 0x0b4d,
+ 0x0c4d, 0x0c4d,
+ 0x0d4d, 0x0d4d,
+ 0x1039, 0x1039,
+ 0x17d2, 0x17d2,
+ 0x1a60, 0x1a60,
+ 0x1b44, 0x1b44,
+ 0x1bab, 0x1bab,
+ 0xa9c0, 0xa9c0,
+ 0xaaf6, 0xaaf6,
+ 0x10a3f, 0x10a3f,
+ 0x11133, 0x11133,
+ 0x113d0, 0x113d0,
+ 0x1193e, 0x1193e,
+ 0x11a47, 0x11a47,
+ 0x11a99, 0x11a99,
+ 0x11f42, 0x11f42,
+}; /* CR_InCB_Linker */
+
+/* 'InCB_Consonant': Derived Property */
+static const OnigCodePoint CR_InCB_Consonant[] = {
+ 76,
+ 0x0915, 0x0939,
+ 0x0958, 0x095f,
+ 0x0978, 0x097f,
+ 0x0995, 0x09a8,
+ 0x09aa, 0x09b0,
+ 0x09b2, 0x09b2,
+ 0x09b6, 0x09b9,
+ 0x09dc, 0x09dd,
+ 0x09df, 0x09df,
+ 0x09f0, 0x09f1,
+ 0x0a95, 0x0aa8,
+ 0x0aaa, 0x0ab0,
+ 0x0ab2, 0x0ab3,
+ 0x0ab5, 0x0ab9,
+ 0x0af9, 0x0af9,
+ 0x0b15, 0x0b28,
+ 0x0b2a, 0x0b30,
+ 0x0b32, 0x0b33,
+ 0x0b35, 0x0b39,
+ 0x0b5c, 0x0b5d,
+ 0x0b5f, 0x0b5f,
+ 0x0b71, 0x0b71,
+ 0x0c15, 0x0c28,
+ 0x0c2a, 0x0c39,
+ 0x0c58, 0x0c5a,
+ 0x0d15, 0x0d3a,
+ 0x1000, 0x102a,
+ 0x103f, 0x103f,
+ 0x1050, 0x1055,
+ 0x105a, 0x105d,
+ 0x1061, 0x1061,
+ 0x1065, 0x1066,
+ 0x106e, 0x1070,
+ 0x1075, 0x1081,
+ 0x108e, 0x108e,
+ 0x1780, 0x17b3,
+ 0x1a20, 0x1a54,
+ 0x1b0b, 0x1b0c,
+ 0x1b13, 0x1b33,
+ 0x1b45, 0x1b4c,
+ 0x1b83, 0x1ba0,
+ 0x1bae, 0x1baf,
+ 0x1bbb, 0x1bbd,
+ 0xa989, 0xa98b,
+ 0xa98f, 0xa9b2,
+ 0xa9e0, 0xa9e4,
+ 0xa9e7, 0xa9ef,
+ 0xa9fa, 0xa9fe,
+ 0xaa60, 0xaa6f,
+ 0xaa71, 0xaa73,
+ 0xaa7a, 0xaa7a,
+ 0xaa7e, 0xaa7f,
+ 0xaae0, 0xaaea,
+ 0xabc0, 0xabda,
+ 0x10a00, 0x10a00,
+ 0x10a10, 0x10a13,
+ 0x10a15, 0x10a17,
+ 0x10a19, 0x10a35,
+ 0x11103, 0x11126,
+ 0x11144, 0x11144,
+ 0x11147, 0x11147,
+ 0x11380, 0x11389,
+ 0x1138b, 0x1138b,
+ 0x1138e, 0x1138e,
+ 0x11390, 0x113b5,
+ 0x11900, 0x11906,
+ 0x11909, 0x11909,
+ 0x1190c, 0x11913,
+ 0x11915, 0x11916,
+ 0x11918, 0x1192f,
+ 0x11a00, 0x11a00,
+ 0x11a0b, 0x11a32,
+ 0x11a50, 0x11a50,
+ 0x11a5c, 0x11a83,
+ 0x11f04, 0x11f10,
+ 0x11f12, 0x11f33,
+}; /* CR_InCB_Consonant */
+
+/* 'InCB_Extend': Derived Property */
+static const OnigCodePoint CR_InCB_Extend[] = {
+ 377,
+ 0x0300, 0x036f,
+ 0x0483, 0x0489,
+ 0x0591, 0x05bd,
+ 0x05bf, 0x05bf,
+ 0x05c1, 0x05c2,
+ 0x05c4, 0x05c5,
+ 0x05c7, 0x05c7,
+ 0x0610, 0x061a,
+ 0x064b, 0x065f,
+ 0x0670, 0x0670,
+ 0x06d6, 0x06dc,
+ 0x06df, 0x06e4,
+ 0x06e7, 0x06e8,
+ 0x06ea, 0x06ed,
+ 0x0711, 0x0711,
+ 0x0730, 0x074a,
+ 0x07a6, 0x07b0,
+ 0x07eb, 0x07f3,
+ 0x07fd, 0x07fd,
+ 0x0816, 0x0819,
+ 0x081b, 0x0823,
+ 0x0825, 0x0827,
+ 0x0829, 0x082d,
+ 0x0859, 0x085b,
+ 0x0897, 0x089f,
+ 0x08ca, 0x08e1,
+ 0x08e3, 0x0902,
+ 0x093a, 0x093a,
+ 0x093c, 0x093c,
+ 0x0941, 0x0948,
+ 0x0951, 0x0957,
+ 0x0962, 0x0963,
+ 0x0981, 0x0981,
+ 0x09bc, 0x09bc,
+ 0x09be, 0x09be,
+ 0x09c1, 0x09c4,
+ 0x09d7, 0x09d7,
+ 0x09e2, 0x09e3,
+ 0x09fe, 0x09fe,
+ 0x0a01, 0x0a02,
+ 0x0a3c, 0x0a3c,
+ 0x0a41, 0x0a42,
+ 0x0a47, 0x0a48,
+ 0x0a4b, 0x0a4d,
+ 0x0a51, 0x0a51,
+ 0x0a70, 0x0a71,
+ 0x0a75, 0x0a75,
+ 0x0a81, 0x0a82,
+ 0x0abc, 0x0abc,
+ 0x0ac1, 0x0ac5,
+ 0x0ac7, 0x0ac8,
+ 0x0ae2, 0x0ae3,
+ 0x0afa, 0x0aff,
+ 0x0b01, 0x0b01,
+ 0x0b3c, 0x0b3c,
+ 0x0b3e, 0x0b3f,
+ 0x0b41, 0x0b44,
+ 0x0b55, 0x0b57,
+ 0x0b62, 0x0b63,
+ 0x0b82, 0x0b82,
+ 0x0bbe, 0x0bbe,
+ 0x0bc0, 0x0bc0,
+ 0x0bcd, 0x0bcd,
+ 0x0bd7, 0x0bd7,
+ 0x0c00, 0x0c00,
+ 0x0c04, 0x0c04,
+ 0x0c3c, 0x0c3c,
+ 0x0c3e, 0x0c40,
+ 0x0c46, 0x0c48,
+ 0x0c4a, 0x0c4c,
+ 0x0c55, 0x0c56,
+ 0x0c62, 0x0c63,
+ 0x0c81, 0x0c81,
+ 0x0cbc, 0x0cbc,
+ 0x0cbf, 0x0cc0,
+ 0x0cc2, 0x0cc2,
+ 0x0cc6, 0x0cc8,
+ 0x0cca, 0x0ccd,
+ 0x0cd5, 0x0cd6,
+ 0x0ce2, 0x0ce3,
+ 0x0d00, 0x0d01,
+ 0x0d3b, 0x0d3c,
+ 0x0d3e, 0x0d3e,
+ 0x0d41, 0x0d44,
+ 0x0d57, 0x0d57,
+ 0x0d62, 0x0d63,
+ 0x0d81, 0x0d81,
+ 0x0dca, 0x0dca,
+ 0x0dcf, 0x0dcf,
+ 0x0dd2, 0x0dd4,
+ 0x0dd6, 0x0dd6,
+ 0x0ddf, 0x0ddf,
+ 0x0e31, 0x0e31,
+ 0x0e34, 0x0e3a,
+ 0x0e47, 0x0e4e,
+ 0x0eb1, 0x0eb1,
+ 0x0eb4, 0x0ebc,
+ 0x0ec8, 0x0ece,
+ 0x0f18, 0x0f19,
+ 0x0f35, 0x0f35,
+ 0x0f37, 0x0f37,
+ 0x0f39, 0x0f39,
+ 0x0f71, 0x0f7e,
+ 0x0f80, 0x0f84,
+ 0x0f86, 0x0f87,
+ 0x0f8d, 0x0f97,
+ 0x0f99, 0x0fbc,
+ 0x0fc6, 0x0fc6,
+ 0x102d, 0x1030,
+ 0x1032, 0x1037,
+ 0x103a, 0x103a,
+ 0x103d, 0x103e,
+ 0x1058, 0x1059,
+ 0x105e, 0x1060,
+ 0x1071, 0x1074,
+ 0x1082, 0x1082,
+ 0x1085, 0x1086,
+ 0x108d, 0x108d,
+ 0x109d, 0x109d,
+ 0x135d, 0x135f,
+ 0x1712, 0x1715,
+ 0x1732, 0x1734,
+ 0x1752, 0x1753,
+ 0x1772, 0x1773,
+ 0x17b4, 0x17b5,
+ 0x17b7, 0x17bd,
+ 0x17c6, 0x17c6,
+ 0x17c9, 0x17d1,
+ 0x17d3, 0x17d3,
+ 0x17dd, 0x17dd,
+ 0x180b, 0x180d,
+ 0x180f, 0x180f,
+ 0x1885, 0x1886,
+ 0x18a9, 0x18a9,
+ 0x1920, 0x1922,
+ 0x1927, 0x1928,
+ 0x1932, 0x1932,
+ 0x1939, 0x193b,
+ 0x1a17, 0x1a18,
+ 0x1a1b, 0x1a1b,
+ 0x1a56, 0x1a56,
+ 0x1a58, 0x1a5e,
+ 0x1a62, 0x1a62,
+ 0x1a65, 0x1a6c,
+ 0x1a73, 0x1a7c,
+ 0x1a7f, 0x1a7f,
+ 0x1ab0, 0x1add,
+ 0x1ae0, 0x1aeb,
+ 0x1b00, 0x1b03,
+ 0x1b34, 0x1b3d,
+ 0x1b42, 0x1b43,
+ 0x1b6b, 0x1b73,
+ 0x1b80, 0x1b81,
+ 0x1ba2, 0x1ba5,
+ 0x1ba8, 0x1baa,
+ 0x1bac, 0x1bad,
+ 0x1be6, 0x1be6,
+ 0x1be8, 0x1be9,
+ 0x1bed, 0x1bed,
+ 0x1bef, 0x1bf3,
+ 0x1c2c, 0x1c33,
+ 0x1c36, 0x1c37,
+ 0x1cd0, 0x1cd2,
+ 0x1cd4, 0x1ce0,
+ 0x1ce2, 0x1ce8,
+ 0x1ced, 0x1ced,
+ 0x1cf4, 0x1cf4,
+ 0x1cf8, 0x1cf9,
+ 0x1dc0, 0x1dff,
+ 0x200d, 0x200d,
+ 0x20d0, 0x20f0,
+ 0x2cef, 0x2cf1,
+ 0x2d7f, 0x2d7f,
+ 0x2de0, 0x2dff,
+ 0x302a, 0x302f,
+ 0x3099, 0x309a,
+ 0xa66f, 0xa672,
+ 0xa674, 0xa67d,
+ 0xa69e, 0xa69f,
+ 0xa6f0, 0xa6f1,
+ 0xa802, 0xa802,
+ 0xa806, 0xa806,
+ 0xa80b, 0xa80b,
+ 0xa825, 0xa826,
+ 0xa82c, 0xa82c,
+ 0xa8c4, 0xa8c5,
+ 0xa8e0, 0xa8f1,
+ 0xa8ff, 0xa8ff,
+ 0xa926, 0xa92d,
+ 0xa947, 0xa951,
+ 0xa953, 0xa953,
+ 0xa980, 0xa982,
+ 0xa9b3, 0xa9b3,
+ 0xa9b6, 0xa9b9,
+ 0xa9bc, 0xa9bd,
+ 0xa9e5, 0xa9e5,
+ 0xaa29, 0xaa2e,
+ 0xaa31, 0xaa32,
+ 0xaa35, 0xaa36,
+ 0xaa43, 0xaa43,
+ 0xaa4c, 0xaa4c,
+ 0xaa7c, 0xaa7c,
+ 0xaab0, 0xaab0,
+ 0xaab2, 0xaab4,
+ 0xaab7, 0xaab8,
+ 0xaabe, 0xaabf,
+ 0xaac1, 0xaac1,
+ 0xaaec, 0xaaed,
+ 0xabe5, 0xabe5,
+ 0xabe8, 0xabe8,
+ 0xabed, 0xabed,
+ 0xfb1e, 0xfb1e,
+ 0xfe00, 0xfe0f,
+ 0xfe20, 0xfe2f,
+ 0xff9e, 0xff9f,
+ 0x101fd, 0x101fd,
+ 0x102e0, 0x102e0,
+ 0x10376, 0x1037a,
+ 0x10a01, 0x10a03,
+ 0x10a05, 0x10a06,
+ 0x10a0c, 0x10a0f,
+ 0x10a38, 0x10a3a,
+ 0x10ae5, 0x10ae6,
+ 0x10d24, 0x10d27,
+ 0x10d69, 0x10d6d,
+ 0x10eab, 0x10eac,
+ 0x10efa, 0x10eff,
+ 0x10f46, 0x10f50,
+ 0x10f82, 0x10f85,
+ 0x11001, 0x11001,
+ 0x11038, 0x11046,
+ 0x11070, 0x11070,
+ 0x11073, 0x11074,
+ 0x1107f, 0x11081,
+ 0x110b3, 0x110b6,
+ 0x110b9, 0x110ba,
+ 0x110c2, 0x110c2,
+ 0x11100, 0x11102,
+ 0x11127, 0x1112b,
+ 0x1112d, 0x11132,
+ 0x11134, 0x11134,
+ 0x11173, 0x11173,
+ 0x11180, 0x11181,
+ 0x111b6, 0x111be,
+ 0x111c0, 0x111c0,
+ 0x111c9, 0x111cc,
+ 0x111cf, 0x111cf,
+ 0x1122f, 0x11231,
+ 0x11234, 0x11237,
+ 0x1123e, 0x1123e,
+ 0x11241, 0x11241,
+ 0x112df, 0x112df,
+ 0x112e3, 0x112ea,
+ 0x11300, 0x11301,
+ 0x1133b, 0x1133c,
+ 0x1133e, 0x1133e,
+ 0x11340, 0x11340,
+ 0x1134d, 0x1134d,
+ 0x11357, 0x11357,
+ 0x11366, 0x1136c,
+ 0x11370, 0x11374,
+ 0x113b8, 0x113b8,
+ 0x113bb, 0x113c0,
+ 0x113c2, 0x113c2,
+ 0x113c5, 0x113c5,
+ 0x113c7, 0x113c9,
+ 0x113ce, 0x113cf,
+ 0x113d2, 0x113d2,
+ 0x113e1, 0x113e2,
+ 0x11438, 0x1143f,
+ 0x11442, 0x11444,
+ 0x11446, 0x11446,
+ 0x1145e, 0x1145e,
+ 0x114b0, 0x114b0,
+ 0x114b3, 0x114b8,
+ 0x114ba, 0x114ba,
+ 0x114bd, 0x114bd,
+ 0x114bf, 0x114c0,
+ 0x114c2, 0x114c3,
+ 0x115af, 0x115af,
+ 0x115b2, 0x115b5,
+ 0x115bc, 0x115bd,
+ 0x115bf, 0x115c0,
+ 0x115dc, 0x115dd,
+ 0x11633, 0x1163a,
+ 0x1163d, 0x1163d,
+ 0x1163f, 0x11640,
+ 0x116ab, 0x116ab,
+ 0x116ad, 0x116ad,
+ 0x116b0, 0x116b7,
+ 0x1171d, 0x1171d,
+ 0x1171f, 0x1171f,
+ 0x11722, 0x11725,
+ 0x11727, 0x1172b,
+ 0x1182f, 0x11837,
+ 0x11839, 0x1183a,
+ 0x11930, 0x11930,
+ 0x1193b, 0x1193d,
+ 0x11943, 0x11943,
+ 0x119d4, 0x119d7,
+ 0x119da, 0x119db,
+ 0x119e0, 0x119e0,
+ 0x11a01, 0x11a0a,
+ 0x11a33, 0x11a38,
+ 0x11a3b, 0x11a3e,
+ 0x11a51, 0x11a56,
+ 0x11a59, 0x11a5b,
+ 0x11a8a, 0x11a96,
+ 0x11a98, 0x11a98,
+ 0x11b60, 0x11b60,
+ 0x11b62, 0x11b64,
+ 0x11b66, 0x11b66,
+ 0x11c30, 0x11c36,
+ 0x11c38, 0x11c3d,
+ 0x11c3f, 0x11c3f,
+ 0x11c92, 0x11ca7,
+ 0x11caa, 0x11cb0,
+ 0x11cb2, 0x11cb3,
+ 0x11cb5, 0x11cb6,
+ 0x11d31, 0x11d36,
+ 0x11d3a, 0x11d3a,
+ 0x11d3c, 0x11d3d,
+ 0x11d3f, 0x11d45,
+ 0x11d47, 0x11d47,
+ 0x11d90, 0x11d91,
+ 0x11d95, 0x11d95,
+ 0x11d97, 0x11d97,
+ 0x11ef3, 0x11ef4,
+ 0x11f00, 0x11f01,
+ 0x11f36, 0x11f3a,
+ 0x11f40, 0x11f41,
+ 0x11f5a, 0x11f5a,
+ 0x13440, 0x13440,
+ 0x13447, 0x13455,
+ 0x1611e, 0x16129,
+ 0x1612d, 0x1612f,
+ 0x16af0, 0x16af4,
+ 0x16b30, 0x16b36,
+ 0x16f4f, 0x16f4f,
+ 0x16f8f, 0x16f92,
+ 0x16fe4, 0x16fe4,
+ 0x16ff0, 0x16ff1,
+ 0x1bc9d, 0x1bc9e,
+ 0x1cf00, 0x1cf2d,
+ 0x1cf30, 0x1cf46,
+ 0x1d165, 0x1d169,
+ 0x1d16d, 0x1d172,
+ 0x1d17b, 0x1d182,
+ 0x1d185, 0x1d18b,
+ 0x1d1aa, 0x1d1ad,
+ 0x1d242, 0x1d244,
+ 0x1da00, 0x1da36,
+ 0x1da3b, 0x1da6c,
+ 0x1da75, 0x1da75,
+ 0x1da84, 0x1da84,
+ 0x1da9b, 0x1da9f,
+ 0x1daa1, 0x1daaf,
+ 0x1e000, 0x1e006,
+ 0x1e008, 0x1e018,
+ 0x1e01b, 0x1e021,
+ 0x1e023, 0x1e024,
+ 0x1e026, 0x1e02a,
+ 0x1e08f, 0x1e08f,
+ 0x1e130, 0x1e136,
+ 0x1e2ae, 0x1e2ae,
+ 0x1e2ec, 0x1e2ef,
+ 0x1e4ec, 0x1e4ef,
+ 0x1e5ee, 0x1e5ef,
+ 0x1e6e3, 0x1e6e3,
+ 0x1e6e6, 0x1e6e6,
+ 0x1e6ee, 0x1e6ef,
+ 0x1e6f5, 0x1e6f5,
+ 0x1e8d0, 0x1e8d6,
+ 0x1e944, 0x1e94a,
+ 0x1f3fb, 0x1f3ff,
+ 0xe0020, 0xe007f,
+ 0xe0100, 0xe01ef,
+}; /* CR_InCB_Extend */
+
+/* 'Common': Script */
+static const OnigCodePoint CR_Common[] = {
+ 176,
+ 0x0000, 0x0040,
+ 0x005b, 0x0060,
+ 0x007b, 0x00a9,
+ 0x00ab, 0x00b9,
+ 0x00bb, 0x00bf,
+ 0x00d7, 0x00d7,
+ 0x00f7, 0x00f7,
+ 0x02b9, 0x02df,
+ 0x02e5, 0x02e9,
+ 0x02ec, 0x02ff,
+ 0x0374, 0x0374,
+ 0x037e, 0x037e,
+ 0x0385, 0x0385,
+ 0x0387, 0x0387,
+ 0x0605, 0x0605,
+ 0x060c, 0x060c,
+ 0x061b, 0x061b,
+ 0x061f, 0x061f,
+ 0x0640, 0x0640,
+ 0x06dd, 0x06dd,
+ 0x08e2, 0x08e2,
+ 0x0964, 0x0965,
+ 0x0e3f, 0x0e3f,
+ 0x0fd5, 0x0fd8,
+ 0x10fb, 0x10fb,
+ 0x16eb, 0x16ed,
+ 0x1735, 0x1736,
+ 0x1802, 0x1803,
+ 0x1805, 0x1805,
+ 0x1cd3, 0x1cd3,
+ 0x1ce1, 0x1ce1,
+ 0x1ce9, 0x1cec,
+ 0x1cee, 0x1cf3,
+ 0x1cf5, 0x1cf7,
+ 0x1cfa, 0x1cfa,
+ 0x2000, 0x200b,
+ 0x200e, 0x2064,
+ 0x2066, 0x2070,
+ 0x2074, 0x207e,
+ 0x2080, 0x208e,
+ 0x20a0, 0x20c1,
+ 0x2100, 0x2125,
+ 0x2127, 0x2129,
+ 0x212c, 0x2131,
+ 0x2133, 0x214d,
+ 0x214f, 0x215f,
+ 0x2189, 0x218b,
+ 0x2190, 0x2429,
+ 0x2440, 0x244a,
+ 0x2460, 0x27ff,
+ 0x2900, 0x2b73,
+ 0x2b76, 0x2bff,
+ 0x2e00, 0x2e5d,
+ 0x2ff0, 0x3004,
+ 0x3006, 0x3006,
+ 0x3008, 0x3020,
+ 0x3030, 0x3037,
+ 0x303c, 0x303f,
+ 0x309b, 0x309c,
+ 0x30a0, 0x30a0,
+ 0x30fb, 0x30fc,
+ 0x3190, 0x319f,
+ 0x31c0, 0x31e5,
+ 0x31ef, 0x31ef,
+ 0x3220, 0x325f,
+ 0x327f, 0x32cf,
+ 0x32ff, 0x32ff,
+ 0x3358, 0x33ff,
+ 0x4dc0, 0x4dff,
+ 0xa700, 0xa721,
+ 0xa788, 0xa78a,
+ 0xa830, 0xa839,
+ 0xa92e, 0xa92e,
+ 0xa9cf, 0xa9cf,
+ 0xab5b, 0xab5b,
+ 0xab6a, 0xab6b,
+ 0xfd3e, 0xfd3f,
+ 0xfe10, 0xfe19,
+ 0xfe30, 0xfe52,
+ 0xfe54, 0xfe66,
+ 0xfe68, 0xfe6b,
+ 0xfeff, 0xfeff,
+ 0xff01, 0xff20,
+ 0xff3b, 0xff40,
+ 0xff5b, 0xff65,
+ 0xff70, 0xff70,
+ 0xff9e, 0xff9f,
+ 0xffe0, 0xffe6,
+ 0xffe8, 0xffee,
+ 0xfff9, 0xfffd,
+ 0x10100, 0x10102,
+ 0x10107, 0x10133,
+ 0x10137, 0x1013f,
+ 0x10190, 0x1019c,
+ 0x101d0, 0x101fc,
+ 0x102e1, 0x102fb,
+ 0x1bca0, 0x1bca3,
+ 0x1cc00, 0x1ccfc,
+ 0x1cd00, 0x1ceb3,
+ 0x1ceba, 0x1ced0,
+ 0x1cee0, 0x1cef0,
+ 0x1cf50, 0x1cfc3,
+ 0x1d000, 0x1d0f5,
+ 0x1d100, 0x1d126,
+ 0x1d129, 0x1d166,
+ 0x1d16a, 0x1d17a,
+ 0x1d183, 0x1d184,
+ 0x1d18c, 0x1d1a9,
+ 0x1d1ae, 0x1d1ea,
+ 0x1d2c0, 0x1d2d3,
+ 0x1d2e0, 0x1d2f3,
+ 0x1d300, 0x1d356,
+ 0x1d360, 0x1d378,
+ 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, 0x1d7cb,
+ 0x1d7ce, 0x1d7ff,
+ 0x1ec71, 0x1ecb4,
+ 0x1ed01, 0x1ed3d,
+ 0x1f000, 0x1f02b,
+ 0x1f030, 0x1f093,
+ 0x1f0a0, 0x1f0ae,
+ 0x1f0b1, 0x1f0bf,
+ 0x1f0c1, 0x1f0cf,
+ 0x1f0d1, 0x1f0f5,
+ 0x1f100, 0x1f1ad,
+ 0x1f1e6, 0x1f1ff,
+ 0x1f201, 0x1f202,
+ 0x1f210, 0x1f23b,
+ 0x1f240, 0x1f248,
+ 0x1f250, 0x1f251,
+ 0x1f260, 0x1f265,
+ 0x1f300, 0x1f6d8,
+ 0x1f6dc, 0x1f6ec,
+ 0x1f6f0, 0x1f6fc,
+ 0x1f700, 0x1f7d9,
+ 0x1f7e0, 0x1f7eb,
+ 0x1f7f0, 0x1f7f0,
+ 0x1f800, 0x1f80b,
+ 0x1f810, 0x1f847,
+ 0x1f850, 0x1f859,
+ 0x1f860, 0x1f887,
+ 0x1f890, 0x1f8ad,
+ 0x1f8b0, 0x1f8bb,
+ 0x1f8c0, 0x1f8c1,
+ 0x1f8d0, 0x1f8d8,
+ 0x1f900, 0x1fa57,
+ 0x1fa60, 0x1fa6d,
+ 0x1fa70, 0x1fa7c,
+ 0x1fa80, 0x1fa8a,
+ 0x1fa8e, 0x1fac6,
+ 0x1fac8, 0x1fac8,
+ 0x1facd, 0x1fadc,
+ 0x1fadf, 0x1faea,
+ 0x1faef, 0x1faf8,
+ 0x1fb00, 0x1fb92,
+ 0x1fb94, 0x1fbfa,
+ 0xe0001, 0xe0001,
+ 0xe0020, 0xe007f,
+}; /* CR_Common */
+
+/* 'Latin': Script */
+static const OnigCodePoint CR_Latin[] = {
+ 36,
+ 0x0041, 0x005a,
+ 0x0061, 0x007a,
+ 0x00aa, 0x00aa,
+ 0x00ba, 0x00ba,
+ 0x00c0, 0x00d6,
+ 0x00d8, 0x00f6,
+ 0x00f8, 0x02b8,
+ 0x02e0, 0x02e4,
+ 0x1d00, 0x1d25,
+ 0x1d2c, 0x1d5c,
+ 0x1d62, 0x1d65,
+ 0x1d6b, 0x1d77,
+ 0x1d79, 0x1dbe,
+ 0x1e00, 0x1eff,
+ 0x2071, 0x2071,
+ 0x207f, 0x207f,
+ 0x2090, 0x209c,
+ 0x212a, 0x212b,
+ 0x2132, 0x2132,
+ 0x214e, 0x214e,
+ 0x2160, 0x2188,
+ 0x2c60, 0x2c7f,
+ 0xa722, 0xa787,
+ 0xa78b, 0xa7dc,
+ 0xa7f1, 0xa7ff,
+ 0xab30, 0xab5a,
+ 0xab5c, 0xab64,
+ 0xab66, 0xab69,
+ 0xfb00, 0xfb06,
+ 0xff21, 0xff3a,
+ 0xff41, 0xff5a,
+ 0x10780, 0x10785,
+ 0x10787, 0x107b0,
+ 0x107b2, 0x107ba,
+ 0x1df00, 0x1df1e,
+ 0x1df25, 0x1df2a,
+}; /* CR_Latin */
+
+/* 'Greek': Script */
+static const OnigCodePoint CR_Greek[] = {
+ 36,
+ 0x0370, 0x0373,
+ 0x0375, 0x0377,
+ 0x037a, 0x037d,
+ 0x037f, 0x037f,
+ 0x0384, 0x0384,
+ 0x0386, 0x0386,
+ 0x0388, 0x038a,
+ 0x038c, 0x038c,
+ 0x038e, 0x03a1,
+ 0x03a3, 0x03e1,
+ 0x03f0, 0x03ff,
+ 0x1d26, 0x1d2a,
+ 0x1d5d, 0x1d61,
+ 0x1d66, 0x1d6a,
+ 0x1dbf, 0x1dbf,
+ 0x1f00, 0x1f15,
+ 0x1f18, 0x1f1d,
+ 0x1f20, 0x1f45,
+ 0x1f48, 0x1f4d,
+ 0x1f50, 0x1f57,
+ 0x1f59, 0x1f59,
+ 0x1f5b, 0x1f5b,
+ 0x1f5d, 0x1f5d,
+ 0x1f5f, 0x1f7d,
+ 0x1f80, 0x1fb4,
+ 0x1fb6, 0x1fc4,
+ 0x1fc6, 0x1fd3,
+ 0x1fd6, 0x1fdb,
+ 0x1fdd, 0x1fef,
+ 0x1ff2, 0x1ff4,
+ 0x1ff6, 0x1ffe,
+ 0x2126, 0x2126,
+ 0xab65, 0xab65,
+ 0x10140, 0x1018e,
+ 0x101a0, 0x101a0,
+ 0x1d200, 0x1d245,
+}; /* CR_Greek */
+
+/* 'Cyrillic': Script */
+static const OnigCodePoint CR_Cyrillic[] = {
+ 10,
+ 0x0400, 0x0484,
+ 0x0487, 0x052f,
+ 0x1c80, 0x1c8a,
+ 0x1d2b, 0x1d2b,
+ 0x1d78, 0x1d78,
+ 0x2de0, 0x2dff,
+ 0xa640, 0xa69f,
+ 0xfe2e, 0xfe2f,
+ 0x1e030, 0x1e06d,
+ 0x1e08f, 0x1e08f,
+}; /* CR_Cyrillic */
+
+/* 'Armenian': Script */
+static const OnigCodePoint CR_Armenian[] = {
+ 4,
+ 0x0531, 0x0556,
+ 0x0559, 0x058a,
+ 0x058d, 0x058f,
+ 0xfb13, 0xfb17,
+}; /* CR_Armenian */
+
+/* 'Hebrew': Script */
+static const OnigCodePoint CR_Hebrew[] = {
+ 9,
+ 0x0591, 0x05c7,
+ 0x05d0, 0x05ea,
+ 0x05ef, 0x05f4,
+ 0xfb1d, 0xfb36,
+ 0xfb38, 0xfb3c,
+ 0xfb3e, 0xfb3e,
+ 0xfb40, 0xfb41,
+ 0xfb43, 0xfb44,
+ 0xfb46, 0xfb4f,
+}; /* CR_Hebrew */
+
+/* 'Arabic': Script */
+static const OnigCodePoint CR_Arabic[] = {
+ 56,
+ 0x0600, 0x0604,
+ 0x0606, 0x060b,
+ 0x060d, 0x061a,
+ 0x061c, 0x061e,
+ 0x0620, 0x063f,
+ 0x0641, 0x064a,
+ 0x0656, 0x066f,
+ 0x0671, 0x06dc,
+ 0x06de, 0x06ff,
+ 0x0750, 0x077f,
+ 0x0870, 0x0891,
+ 0x0897, 0x08e1,
+ 0x08e3, 0x08ff,
+ 0xfb50, 0xfd3d,
+ 0xfd40, 0xfdcf,
+ 0xfdf0, 0xfdff,
+ 0xfe70, 0xfe74,
+ 0xfe76, 0xfefc,
+ 0x10e60, 0x10e7e,
+ 0x10ec2, 0x10ec7,
+ 0x10ed0, 0x10ed8,
+ 0x10efa, 0x10eff,
+ 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,
+ 0x1eef0, 0x1eef1,
+}; /* CR_Arabic */
+
+/* 'Syriac': Script */
+static const OnigCodePoint CR_Syriac[] = {
+ 4,
+ 0x0700, 0x070d,
+ 0x070f, 0x074a,
+ 0x074d, 0x074f,
+ 0x0860, 0x086a,
+}; /* CR_Syriac */
+
+/* 'Thaana': Script */
+static const OnigCodePoint CR_Thaana[] = {
+ 1,
+ 0x0780, 0x07b1,
+}; /* CR_Thaana */
+
+/* 'Devanagari': Script */
+static const OnigCodePoint CR_Devanagari[] = {
+ 5,
+ 0x0900, 0x0950,
+ 0x0955, 0x0963,
+ 0x0966, 0x097f,
+ 0xa8e0, 0xa8ff,
+ 0x11b00, 0x11b09,
+}; /* CR_Devanagari */
+
+/* 'Bengali': Script */
+static const OnigCodePoint CR_Bengali[] = {
+ 14,
+ 0x0980, 0x0983,
+ 0x0985, 0x098c,
+ 0x098f, 0x0990,
+ 0x0993, 0x09a8,
+ 0x09aa, 0x09b0,
+ 0x09b2, 0x09b2,
+ 0x09b6, 0x09b9,
+ 0x09bc, 0x09c4,
+ 0x09c7, 0x09c8,
+ 0x09cb, 0x09ce,
+ 0x09d7, 0x09d7,
+ 0x09dc, 0x09dd,
+ 0x09df, 0x09e3,
+ 0x09e6, 0x09fe,
+}; /* CR_Bengali */
+
+/* 'Gurmukhi': Script */
+static const OnigCodePoint CR_Gurmukhi[] = {
+ 16,
+ 0x0a01, 0x0a03,
+ 0x0a05, 0x0a0a,
+ 0x0a0f, 0x0a10,
+ 0x0a13, 0x0a28,
+ 0x0a2a, 0x0a30,
+ 0x0a32, 0x0a33,
+ 0x0a35, 0x0a36,
+ 0x0a38, 0x0a39,
+ 0x0a3c, 0x0a3c,
+ 0x0a3e, 0x0a42,
+ 0x0a47, 0x0a48,
+ 0x0a4b, 0x0a4d,
+ 0x0a51, 0x0a51,
+ 0x0a59, 0x0a5c,
+ 0x0a5e, 0x0a5e,
+ 0x0a66, 0x0a76,
+}; /* CR_Gurmukhi */
+
+/* 'Gujarati': Script */
+static const OnigCodePoint CR_Gujarati[] = {
+ 14,
+ 0x0a81, 0x0a83,
+ 0x0a85, 0x0a8d,
+ 0x0a8f, 0x0a91,
+ 0x0a93, 0x0aa8,
+ 0x0aaa, 0x0ab0,
+ 0x0ab2, 0x0ab3,
+ 0x0ab5, 0x0ab9,
+ 0x0abc, 0x0ac5,
+ 0x0ac7, 0x0ac9,
+ 0x0acb, 0x0acd,
+ 0x0ad0, 0x0ad0,
+ 0x0ae0, 0x0ae3,
+ 0x0ae6, 0x0af1,
+ 0x0af9, 0x0aff,
+}; /* CR_Gujarati */
+
+/* 'Oriya': Script */
+static const OnigCodePoint CR_Oriya[] = {
+ 14,
+ 0x0b01, 0x0b03,
+ 0x0b05, 0x0b0c,
+ 0x0b0f, 0x0b10,
+ 0x0b13, 0x0b28,
+ 0x0b2a, 0x0b30,
+ 0x0b32, 0x0b33,
+ 0x0b35, 0x0b39,
+ 0x0b3c, 0x0b44,
+ 0x0b47, 0x0b48,
+ 0x0b4b, 0x0b4d,
+ 0x0b55, 0x0b57,
+ 0x0b5c, 0x0b5d,
+ 0x0b5f, 0x0b63,
+ 0x0b66, 0x0b77,
+}; /* CR_Oriya */
+
+/* 'Tamil': Script */
+static const OnigCodePoint CR_Tamil[] = {
+ 18,
+ 0x0b82, 0x0b83,
+ 0x0b85, 0x0b8a,
+ 0x0b8e, 0x0b90,
+ 0x0b92, 0x0b95,
+ 0x0b99, 0x0b9a,
+ 0x0b9c, 0x0b9c,
+ 0x0b9e, 0x0b9f,
+ 0x0ba3, 0x0ba4,
+ 0x0ba8, 0x0baa,
+ 0x0bae, 0x0bb9,
+ 0x0bbe, 0x0bc2,
+ 0x0bc6, 0x0bc8,
+ 0x0bca, 0x0bcd,
+ 0x0bd0, 0x0bd0,
+ 0x0bd7, 0x0bd7,
+ 0x0be6, 0x0bfa,
+ 0x11fc0, 0x11ff1,
+ 0x11fff, 0x11fff,
+}; /* CR_Tamil */
+
+/* 'Telugu': Script */
+static const OnigCodePoint CR_Telugu[] = {
+ 13,
+ 0x0c00, 0x0c0c,
+ 0x0c0e, 0x0c10,
+ 0x0c12, 0x0c28,
+ 0x0c2a, 0x0c39,
+ 0x0c3c, 0x0c44,
+ 0x0c46, 0x0c48,
+ 0x0c4a, 0x0c4d,
+ 0x0c55, 0x0c56,
+ 0x0c58, 0x0c5a,
+ 0x0c5c, 0x0c5d,
+ 0x0c60, 0x0c63,
+ 0x0c66, 0x0c6f,
+ 0x0c77, 0x0c7f,
+}; /* CR_Telugu */
+
+/* 'Kannada': Script */
+static const OnigCodePoint CR_Kannada[] = {
+ 13,
+ 0x0c80, 0x0c8c,
+ 0x0c8e, 0x0c90,
+ 0x0c92, 0x0ca8,
+ 0x0caa, 0x0cb3,
+ 0x0cb5, 0x0cb9,
+ 0x0cbc, 0x0cc4,
+ 0x0cc6, 0x0cc8,
+ 0x0cca, 0x0ccd,
+ 0x0cd5, 0x0cd6,
+ 0x0cdc, 0x0cde,
+ 0x0ce0, 0x0ce3,
+ 0x0ce6, 0x0cef,
+ 0x0cf1, 0x0cf3,
+}; /* CR_Kannada */
+
+/* 'Malayalam': Script */
+static const OnigCodePoint CR_Malayalam[] = {
+ 7,
+ 0x0d00, 0x0d0c,
+ 0x0d0e, 0x0d10,
+ 0x0d12, 0x0d44,
+ 0x0d46, 0x0d48,
+ 0x0d4a, 0x0d4f,
+ 0x0d54, 0x0d63,
+ 0x0d66, 0x0d7f,
+}; /* CR_Malayalam */
+
+/* 'Sinhala': Script */
+static const OnigCodePoint CR_Sinhala[] = {
+ 13,
+ 0x0d81, 0x0d83,
+ 0x0d85, 0x0d96,
+ 0x0d9a, 0x0db1,
+ 0x0db3, 0x0dbb,
+ 0x0dbd, 0x0dbd,
+ 0x0dc0, 0x0dc6,
+ 0x0dca, 0x0dca,
+ 0x0dcf, 0x0dd4,
+ 0x0dd6, 0x0dd6,
+ 0x0dd8, 0x0ddf,
+ 0x0de6, 0x0def,
+ 0x0df2, 0x0df4,
+ 0x111e1, 0x111f4,
+}; /* CR_Sinhala */
+
+/* 'Thai': Script */
+static const OnigCodePoint CR_Thai[] = {
+ 2,
+ 0x0e01, 0x0e3a,
+ 0x0e40, 0x0e5b,
+}; /* CR_Thai */
+
+/* 'Lao': Script */
+static const OnigCodePoint CR_Lao[] = {
+ 11,
+ 0x0e81, 0x0e82,
+ 0x0e84, 0x0e84,
+ 0x0e86, 0x0e8a,
+ 0x0e8c, 0x0ea3,
+ 0x0ea5, 0x0ea5,
+ 0x0ea7, 0x0ebd,
+ 0x0ec0, 0x0ec4,
+ 0x0ec6, 0x0ec6,
+ 0x0ec8, 0x0ece,
+ 0x0ed0, 0x0ed9,
+ 0x0edc, 0x0edf,
+}; /* CR_Lao */
+
+/* 'Tibetan': Script */
+static const OnigCodePoint CR_Tibetan[] = {
+ 7,
+ 0x0f00, 0x0f47,
+ 0x0f49, 0x0f6c,
+ 0x0f71, 0x0f97,
+ 0x0f99, 0x0fbc,
+ 0x0fbe, 0x0fcc,
+ 0x0fce, 0x0fd4,
+ 0x0fd9, 0x0fda,
+}; /* CR_Tibetan */
+
+/* 'Myanmar': Script */
+static const OnigCodePoint CR_Myanmar[] = {
+ 4,
+ 0x1000, 0x109f,
+ 0xa9e0, 0xa9fe,
+ 0xaa60, 0xaa7f,
+ 0x116d0, 0x116e3,
+}; /* CR_Myanmar */
+
+/* 'Georgian': Script */
+static const OnigCodePoint CR_Georgian[] = {
+ 10,
+ 0x10a0, 0x10c5,
+ 0x10c7, 0x10c7,
+ 0x10cd, 0x10cd,
+ 0x10d0, 0x10fa,
+ 0x10fc, 0x10ff,
+ 0x1c90, 0x1cba,
+ 0x1cbd, 0x1cbf,
+ 0x2d00, 0x2d25,
+ 0x2d27, 0x2d27,
+ 0x2d2d, 0x2d2d,
+}; /* CR_Georgian */
+
+/* 'Hangul': Script */
+static const OnigCodePoint CR_Hangul[] = {
+ 14,
+ 0x1100, 0x11ff,
+ 0x302e, 0x302f,
+ 0x3131, 0x318e,
+ 0x3200, 0x321e,
+ 0x3260, 0x327e,
+ 0xa960, 0xa97c,
+ 0xac00, 0xd7a3,
+ 0xd7b0, 0xd7c6,
+ 0xd7cb, 0xd7fb,
+ 0xffa0, 0xffbe,
+ 0xffc2, 0xffc7,
+ 0xffca, 0xffcf,
+ 0xffd2, 0xffd7,
+ 0xffda, 0xffdc,
+}; /* CR_Hangul */
+
+/* 'Ethiopic': Script */
+static const OnigCodePoint CR_Ethiopic[] = {
+ 36,
+ 0x1200, 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,
+ 0x135d, 0x137c,
+ 0x1380, 0x1399,
+ 0x2d80, 0x2d96,
+ 0x2da0, 0x2da6,
+ 0x2da8, 0x2dae,
+ 0x2db0, 0x2db6,
+ 0x2db8, 0x2dbe,
+ 0x2dc0, 0x2dc6,
+ 0x2dc8, 0x2dce,
+ 0x2dd0, 0x2dd6,
+ 0x2dd8, 0x2dde,
+ 0xab01, 0xab06,
+ 0xab09, 0xab0e,
+ 0xab11, 0xab16,
+ 0xab20, 0xab26,
+ 0xab28, 0xab2e,
+ 0x1e7e0, 0x1e7e6,
+ 0x1e7e8, 0x1e7eb,
+ 0x1e7ed, 0x1e7ee,
+ 0x1e7f0, 0x1e7fe,
+}; /* CR_Ethiopic */
+
+/* 'Cherokee': Script */
+static const OnigCodePoint CR_Cherokee[] = {
+ 3,
+ 0x13a0, 0x13f5,
+ 0x13f8, 0x13fd,
+ 0xab70, 0xabbf,
+}; /* CR_Cherokee */
+
+/* 'Canadian_Aboriginal': Script */
+static const OnigCodePoint CR_Canadian_Aboriginal[] = {
+ 3,
+ 0x1400, 0x167f,
+ 0x18b0, 0x18f5,
+ 0x11ab0, 0x11abf,
+}; /* CR_Canadian_Aboriginal */
+
+/* 'Ogham': Script */
+static const OnigCodePoint CR_Ogham[] = {
+ 1,
+ 0x1680, 0x169c,
+}; /* CR_Ogham */
+
+/* 'Runic': Script */
+static const OnigCodePoint CR_Runic[] = {
+ 2,
+ 0x16a0, 0x16ea,
+ 0x16ee, 0x16f8,
+}; /* CR_Runic */
+
+/* 'Khmer': Script */
+static const OnigCodePoint CR_Khmer[] = {
+ 4,
+ 0x1780, 0x17dd,
+ 0x17e0, 0x17e9,
+ 0x17f0, 0x17f9,
+ 0x19e0, 0x19ff,
+}; /* CR_Khmer */
+
+/* 'Mongolian': Script */
+static const OnigCodePoint CR_Mongolian[] = {
+ 6,
+ 0x1800, 0x1801,
+ 0x1804, 0x1804,
+ 0x1806, 0x1819,
+ 0x1820, 0x1878,
+ 0x1880, 0x18aa,
+ 0x11660, 0x1166c,
+}; /* CR_Mongolian */
+
+/* 'Hiragana': Script */
+static const OnigCodePoint CR_Hiragana[] = {
+ 6,
+ 0x3041, 0x3096,
+ 0x309d, 0x309f,
+ 0x1b001, 0x1b11f,
+ 0x1b132, 0x1b132,
+ 0x1b150, 0x1b152,
+ 0x1f200, 0x1f200,
+}; /* CR_Hiragana */
+
+/* 'Katakana': Script */
+static const OnigCodePoint CR_Katakana[] = {
+ 14,
+ 0x30a1, 0x30fa,
+ 0x30fd, 0x30ff,
+ 0x31f0, 0x31ff,
+ 0x32d0, 0x32fe,
+ 0x3300, 0x3357,
+ 0xff66, 0xff6f,
+ 0xff71, 0xff9d,
+ 0x1aff0, 0x1aff3,
+ 0x1aff5, 0x1affb,
+ 0x1affd, 0x1affe,
+ 0x1b000, 0x1b000,
+ 0x1b120, 0x1b122,
+ 0x1b155, 0x1b155,
+ 0x1b164, 0x1b167,
+}; /* CR_Katakana */
+
+/* 'Bopomofo': Script */
+static const OnigCodePoint CR_Bopomofo[] = {
+ 3,
+ 0x02ea, 0x02eb,
+ 0x3105, 0x312f,
+ 0x31a0, 0x31bf,
+}; /* CR_Bopomofo */
+
+/* 'Han': Script */
+static const OnigCodePoint CR_Han[] = {
+ 21,
+ 0x2e80, 0x2e99,
+ 0x2e9b, 0x2ef3,
+ 0x2f00, 0x2fd5,
+ 0x3005, 0x3005,
+ 0x3007, 0x3007,
+ 0x3021, 0x3029,
+ 0x3038, 0x303b,
+ 0x3400, 0x4dbf,
+ 0x4e00, 0x9fff,
+ 0xf900, 0xfa6d,
+ 0xfa70, 0xfad9,
+ 0x16fe2, 0x16fe3,
+ 0x16ff0, 0x16ff6,
+ 0x20000, 0x2a6df,
+ 0x2a700, 0x2b81d,
+ 0x2b820, 0x2cead,
+ 0x2ceb0, 0x2ebe0,
+ 0x2ebf0, 0x2ee5d,
+ 0x2f800, 0x2fa1d,
+ 0x30000, 0x3134a,
+ 0x31350, 0x33479,
+}; /* CR_Han */
+
+/* 'Yi': Script */
+static const OnigCodePoint CR_Yi[] = {
+ 2,
+ 0xa000, 0xa48c,
+ 0xa490, 0xa4c6,
+}; /* CR_Yi */
+
+/* 'Old_Italic': Script */
+static const OnigCodePoint CR_Old_Italic[] = {
+ 2,
+ 0x10300, 0x10323,
+ 0x1032d, 0x1032f,
+}; /* CR_Old_Italic */
+
+/* 'Gothic': Script */
+static const OnigCodePoint CR_Gothic[] = {
+ 1,
+ 0x10330, 0x1034a,
+}; /* CR_Gothic */
+
+/* 'Deseret': Script */
+static const OnigCodePoint CR_Deseret[] = {
+ 1,
+ 0x10400, 0x1044f,
+}; /* CR_Deseret */
+
+/* 'Inherited': Script */
+static const OnigCodePoint CR_Inherited[] = {
+ 30,
+ 0x0300, 0x036f,
+ 0x0485, 0x0486,
+ 0x064b, 0x0655,
+ 0x0670, 0x0670,
+ 0x0951, 0x0954,
+ 0x1ab0, 0x1add,
+ 0x1ae0, 0x1aeb,
+ 0x1cd0, 0x1cd2,
+ 0x1cd4, 0x1ce0,
+ 0x1ce2, 0x1ce8,
+ 0x1ced, 0x1ced,
+ 0x1cf4, 0x1cf4,
+ 0x1cf8, 0x1cf9,
+ 0x1dc0, 0x1dff,
+ 0x200c, 0x200d,
+ 0x20d0, 0x20f0,
+ 0x302a, 0x302d,
+ 0x3099, 0x309a,
+ 0xfe00, 0xfe0f,
+ 0xfe20, 0xfe2d,
+ 0x101fd, 0x101fd,
+ 0x102e0, 0x102e0,
+ 0x1133b, 0x1133b,
+ 0x1cf00, 0x1cf2d,
+ 0x1cf30, 0x1cf46,
+ 0x1d167, 0x1d169,
+ 0x1d17b, 0x1d182,
+ 0x1d185, 0x1d18b,
+ 0x1d1aa, 0x1d1ad,
+ 0xe0100, 0xe01ef,
+}; /* CR_Inherited */
+
+/* 'Tagalog': Script */
+static const OnigCodePoint CR_Tagalog[] = {
+ 2,
+ 0x1700, 0x1715,
+ 0x171f, 0x171f,
+}; /* CR_Tagalog */
+
+/* 'Hanunoo': Script */
+static const OnigCodePoint CR_Hanunoo[] = {
+ 1,
+ 0x1720, 0x1734,
+}; /* CR_Hanunoo */
+
+/* 'Buhid': Script */
+static const OnigCodePoint CR_Buhid[] = {
+ 1,
+ 0x1740, 0x1753,
+}; /* CR_Buhid */
+
+/* 'Tagbanwa': Script */
+static const OnigCodePoint CR_Tagbanwa[] = {
+ 3,
+ 0x1760, 0x176c,
+ 0x176e, 0x1770,
+ 0x1772, 0x1773,
+}; /* CR_Tagbanwa */
+
+/* 'Limbu': Script */
+static const OnigCodePoint CR_Limbu[] = {
+ 5,
+ 0x1900, 0x191e,
+ 0x1920, 0x192b,
+ 0x1930, 0x193b,
+ 0x1940, 0x1940,
+ 0x1944, 0x194f,
+}; /* CR_Limbu */
+
+/* 'Tai_Le': Script */
+static const OnigCodePoint CR_Tai_Le[] = {
+ 2,
+ 0x1950, 0x196d,
+ 0x1970, 0x1974,
+}; /* CR_Tai_Le */
+
+/* 'Linear_B': Script */
+static const OnigCodePoint CR_Linear_B[] = {
+ 7,
+ 0x10000, 0x1000b,
+ 0x1000d, 0x10026,
+ 0x10028, 0x1003a,
+ 0x1003c, 0x1003d,
+ 0x1003f, 0x1004d,
+ 0x10050, 0x1005d,
+ 0x10080, 0x100fa,
+}; /* CR_Linear_B */
+
+/* 'Ugaritic': Script */
+static const OnigCodePoint CR_Ugaritic[] = {
+ 2,
+ 0x10380, 0x1039d,
+ 0x1039f, 0x1039f,
+}; /* CR_Ugaritic */
+
+/* 'Shavian': Script */
+static const OnigCodePoint CR_Shavian[] = {
+ 1,
+ 0x10450, 0x1047f,
+}; /* CR_Shavian */
+
+/* 'Osmanya': Script */
+static const OnigCodePoint CR_Osmanya[] = {
+ 2,
+ 0x10480, 0x1049d,
+ 0x104a0, 0x104a9,
+}; /* CR_Osmanya */
+
+/* 'Cypriot': Script */
+static const OnigCodePoint CR_Cypriot[] = {
+ 6,
+ 0x10800, 0x10805,
+ 0x10808, 0x10808,
+ 0x1080a, 0x10835,
+ 0x10837, 0x10838,
+ 0x1083c, 0x1083c,
+ 0x1083f, 0x1083f,
+}; /* CR_Cypriot */
+
+/* 'Braille': Script */
+static const OnigCodePoint CR_Braille[] = {
+ 1,
+ 0x2800, 0x28ff,
+}; /* CR_Braille */
+
+/* 'Buginese': Script */
+static const OnigCodePoint CR_Buginese[] = {
+ 2,
+ 0x1a00, 0x1a1b,
+ 0x1a1e, 0x1a1f,
+}; /* CR_Buginese */
+
+/* 'Coptic': Script */
+static const OnigCodePoint CR_Coptic[] = {
+ 3,
+ 0x03e2, 0x03ef,
+ 0x2c80, 0x2cf3,
+ 0x2cf9, 0x2cff,
+}; /* CR_Coptic */
+
+/* 'New_Tai_Lue': Script */
+static const OnigCodePoint CR_New_Tai_Lue[] = {
+ 4,
+ 0x1980, 0x19ab,
+ 0x19b0, 0x19c9,
+ 0x19d0, 0x19da,
+ 0x19de, 0x19df,
+}; /* CR_New_Tai_Lue */
+
+/* 'Glagolitic': Script */
+static const OnigCodePoint CR_Glagolitic[] = {
+ 6,
+ 0x2c00, 0x2c5f,
+ 0x1e000, 0x1e006,
+ 0x1e008, 0x1e018,
+ 0x1e01b, 0x1e021,
+ 0x1e023, 0x1e024,
+ 0x1e026, 0x1e02a,
+}; /* CR_Glagolitic */
+
+/* 'Tifinagh': Script */
+static const OnigCodePoint CR_Tifinagh[] = {
+ 3,
+ 0x2d30, 0x2d67,
+ 0x2d6f, 0x2d70,
+ 0x2d7f, 0x2d7f,
+}; /* CR_Tifinagh */
+
+/* 'Syloti_Nagri': Script */
+static const OnigCodePoint CR_Syloti_Nagri[] = {
+ 1,
+ 0xa800, 0xa82c,
+}; /* CR_Syloti_Nagri */
+
+/* 'Old_Persian': Script */
+static const OnigCodePoint CR_Old_Persian[] = {
+ 2,
+ 0x103a0, 0x103c3,
+ 0x103c8, 0x103d5,
+}; /* CR_Old_Persian */
+
+/* 'Kharoshthi': Script */
+static const OnigCodePoint CR_Kharoshthi[] = {
+ 8,
+ 0x10a00, 0x10a03,
+ 0x10a05, 0x10a06,
+ 0x10a0c, 0x10a13,
+ 0x10a15, 0x10a17,
+ 0x10a19, 0x10a35,
+ 0x10a38, 0x10a3a,
+ 0x10a3f, 0x10a48,
+ 0x10a50, 0x10a58,
+}; /* CR_Kharoshthi */
+
+/* 'Balinese': Script */
+static const OnigCodePoint CR_Balinese[] = {
+ 2,
+ 0x1b00, 0x1b4c,
+ 0x1b4e, 0x1b7f,
+}; /* CR_Balinese */
+
+/* 'Cuneiform': Script */
+static const OnigCodePoint CR_Cuneiform[] = {
+ 4,
+ 0x12000, 0x12399,
+ 0x12400, 0x1246e,
+ 0x12470, 0x12474,
+ 0x12480, 0x12543,
+}; /* CR_Cuneiform */
+
+/* 'Phoenician': Script */
+static const OnigCodePoint CR_Phoenician[] = {
+ 2,
+ 0x10900, 0x1091b,
+ 0x1091f, 0x1091f,
+}; /* CR_Phoenician */
+
+/* 'Phags_Pa': Script */
+static const OnigCodePoint CR_Phags_Pa[] = {
+ 1,
+ 0xa840, 0xa877,
+}; /* CR_Phags_Pa */
+
+/* 'Nko': Script */
+static const OnigCodePoint CR_Nko[] = {
+ 2,
+ 0x07c0, 0x07fa,
+ 0x07fd, 0x07ff,
+}; /* CR_Nko */
+
+/* 'Sundanese': Script */
+static const OnigCodePoint CR_Sundanese[] = {
+ 2,
+ 0x1b80, 0x1bbf,
+ 0x1cc0, 0x1cc7,
+}; /* CR_Sundanese */
+
+/* 'Lepcha': Script */
+static const OnigCodePoint CR_Lepcha[] = {
+ 3,
+ 0x1c00, 0x1c37,
+ 0x1c3b, 0x1c49,
+ 0x1c4d, 0x1c4f,
+}; /* CR_Lepcha */
+
+/* 'Ol_Chiki': Script */
+static const OnigCodePoint CR_Ol_Chiki[] = {
+ 1,
+ 0x1c50, 0x1c7f,
+}; /* CR_Ol_Chiki */
+
+/* 'Vai': Script */
+static const OnigCodePoint CR_Vai[] = {
+ 1,
+ 0xa500, 0xa62b,
+}; /* CR_Vai */
+
+/* 'Saurashtra': Script */
+static const OnigCodePoint CR_Saurashtra[] = {
+ 2,
+ 0xa880, 0xa8c5,
+ 0xa8ce, 0xa8d9,
+}; /* CR_Saurashtra */
+
+/* 'Kayah_Li': Script */
+static const OnigCodePoint CR_Kayah_Li[] = {
+ 2,
+ 0xa900, 0xa92d,
+ 0xa92f, 0xa92f,
+}; /* CR_Kayah_Li */
+
+/* 'Rejang': Script */
+static const OnigCodePoint CR_Rejang[] = {
+ 2,
+ 0xa930, 0xa953,
+ 0xa95f, 0xa95f,
+}; /* CR_Rejang */
+
+/* 'Lycian': Script */
+static const OnigCodePoint CR_Lycian[] = {
+ 1,
+ 0x10280, 0x1029c,
+}; /* CR_Lycian */
+
+/* 'Carian': Script */
+static const OnigCodePoint CR_Carian[] = {
+ 1,
+ 0x102a0, 0x102d0,
+}; /* CR_Carian */
+
+/* 'Lydian': Script */
+static const OnigCodePoint CR_Lydian[] = {
+ 2,
+ 0x10920, 0x10939,
+ 0x1093f, 0x1093f,
+}; /* CR_Lydian */
+
+/* 'Cham': Script */
+static const OnigCodePoint CR_Cham[] = {
+ 4,
+ 0xaa00, 0xaa36,
+ 0xaa40, 0xaa4d,
+ 0xaa50, 0xaa59,
+ 0xaa5c, 0xaa5f,
+}; /* CR_Cham */
+
+/* 'Tai_Tham': Script */
+static const OnigCodePoint CR_Tai_Tham[] = {
+ 5,
+ 0x1a20, 0x1a5e,
+ 0x1a60, 0x1a7c,
+ 0x1a7f, 0x1a89,
+ 0x1a90, 0x1a99,
+ 0x1aa0, 0x1aad,
+}; /* CR_Tai_Tham */
+
+/* 'Tai_Viet': Script */
+static const OnigCodePoint CR_Tai_Viet[] = {
+ 2,
+ 0xaa80, 0xaac2,
+ 0xaadb, 0xaadf,
+}; /* CR_Tai_Viet */
+
+/* 'Avestan': Script */
+static const OnigCodePoint CR_Avestan[] = {
+ 2,
+ 0x10b00, 0x10b35,
+ 0x10b39, 0x10b3f,
+}; /* CR_Avestan */
+
+/* 'Egyptian_Hieroglyphs': Script */
+static const OnigCodePoint CR_Egyptian_Hieroglyphs[] = {
+ 2,
+ 0x13000, 0x13455,
+ 0x13460, 0x143fa,
+}; /* CR_Egyptian_Hieroglyphs */
+
+/* 'Samaritan': Script */
+static const OnigCodePoint CR_Samaritan[] = {
+ 2,
+ 0x0800, 0x082d,
+ 0x0830, 0x083e,
+}; /* CR_Samaritan */
+
+/* 'Lisu': Script */
+static const OnigCodePoint CR_Lisu[] = {
+ 2,
+ 0xa4d0, 0xa4ff,
+ 0x11fb0, 0x11fb0,
+}; /* CR_Lisu */
+
+/* 'Bamum': Script */
+static const OnigCodePoint CR_Bamum[] = {
+ 2,
+ 0xa6a0, 0xa6f7,
+ 0x16800, 0x16a38,
+}; /* CR_Bamum */
+
+/* 'Javanese': Script */
+static const OnigCodePoint CR_Javanese[] = {
+ 3,
+ 0xa980, 0xa9cd,
+ 0xa9d0, 0xa9d9,
+ 0xa9de, 0xa9df,
+}; /* CR_Javanese */
+
+/* 'Meetei_Mayek': Script */
+static const OnigCodePoint CR_Meetei_Mayek[] = {
+ 3,
+ 0xaae0, 0xaaf6,
+ 0xabc0, 0xabed,
+ 0xabf0, 0xabf9,
+}; /* CR_Meetei_Mayek */
+
+/* 'Imperial_Aramaic': Script */
+static const OnigCodePoint CR_Imperial_Aramaic[] = {
+ 2,
+ 0x10840, 0x10855,
+ 0x10857, 0x1085f,
+}; /* CR_Imperial_Aramaic */
+
+/* 'Old_South_Arabian': Script */
+static const OnigCodePoint CR_Old_South_Arabian[] = {
+ 1,
+ 0x10a60, 0x10a7f,
+}; /* CR_Old_South_Arabian */
+
+/* 'Inscriptional_Parthian': Script */
+static const OnigCodePoint CR_Inscriptional_Parthian[] = {
+ 2,
+ 0x10b40, 0x10b55,
+ 0x10b58, 0x10b5f,
+}; /* CR_Inscriptional_Parthian */
+
+/* 'Inscriptional_Pahlavi': Script */
+static const OnigCodePoint CR_Inscriptional_Pahlavi[] = {
+ 2,
+ 0x10b60, 0x10b72,
+ 0x10b78, 0x10b7f,
+}; /* CR_Inscriptional_Pahlavi */
+
+/* 'Old_Turkic': Script */
+static const OnigCodePoint CR_Old_Turkic[] = {
+ 1,
+ 0x10c00, 0x10c48,
+}; /* CR_Old_Turkic */
+
+/* 'Kaithi': Script */
+static const OnigCodePoint CR_Kaithi[] = {
+ 2,
+ 0x11080, 0x110c2,
+ 0x110cd, 0x110cd,
+}; /* CR_Kaithi */
+
+/* 'Batak': Script */
+static const OnigCodePoint CR_Batak[] = {
+ 2,
+ 0x1bc0, 0x1bf3,
+ 0x1bfc, 0x1bff,
+}; /* CR_Batak */
+
+/* 'Brahmi': Script */
+static const OnigCodePoint CR_Brahmi[] = {
+ 3,
+ 0x11000, 0x1104d,
+ 0x11052, 0x11075,
+ 0x1107f, 0x1107f,
+}; /* CR_Brahmi */
+
+/* 'Mandaic': Script */
+static const OnigCodePoint CR_Mandaic[] = {
+ 2,
+ 0x0840, 0x085b,
+ 0x085e, 0x085e,
+}; /* CR_Mandaic */
+
+/* 'Chakma': Script */
+static const OnigCodePoint CR_Chakma[] = {
+ 2,
+ 0x11100, 0x11134,
+ 0x11136, 0x11147,
+}; /* CR_Chakma */
+
+/* 'Meroitic_Cursive': Script */
+static const OnigCodePoint CR_Meroitic_Cursive[] = {
+ 3,
+ 0x109a0, 0x109b7,
+ 0x109bc, 0x109cf,
+ 0x109d2, 0x109ff,
+}; /* CR_Meroitic_Cursive */
+
+/* 'Meroitic_Hieroglyphs': Script */
+static const OnigCodePoint CR_Meroitic_Hieroglyphs[] = {
+ 1,
+ 0x10980, 0x1099f,
+}; /* CR_Meroitic_Hieroglyphs */
+
+/* 'Miao': Script */
+static const OnigCodePoint CR_Miao[] = {
+ 3,
+ 0x16f00, 0x16f4a,
+ 0x16f4f, 0x16f87,
+ 0x16f8f, 0x16f9f,
+}; /* CR_Miao */
+
+/* 'Sharada': Script */
+static const OnigCodePoint CR_Sharada[] = {
+ 2,
+ 0x11180, 0x111df,
+ 0x11b60, 0x11b67,
+}; /* CR_Sharada */
+
+/* 'Sora_Sompeng': Script */
+static const OnigCodePoint CR_Sora_Sompeng[] = {
+ 2,
+ 0x110d0, 0x110e8,
+ 0x110f0, 0x110f9,
+}; /* CR_Sora_Sompeng */
+
+/* 'Takri': Script */
+static const OnigCodePoint CR_Takri[] = {
+ 2,
+ 0x11680, 0x116b9,
+ 0x116c0, 0x116c9,
+}; /* CR_Takri */
+
+/* 'Caucasian_Albanian': Script */
+static const OnigCodePoint CR_Caucasian_Albanian[] = {
+ 2,
+ 0x10530, 0x10563,
+ 0x1056f, 0x1056f,
+}; /* CR_Caucasian_Albanian */
+
+/* 'Bassa_Vah': Script */
+static const OnigCodePoint CR_Bassa_Vah[] = {
+ 2,
+ 0x16ad0, 0x16aed,
+ 0x16af0, 0x16af5,
+}; /* CR_Bassa_Vah */
+
+/* 'Duployan': Script */
+static const OnigCodePoint CR_Duployan[] = {
+ 5,
+ 0x1bc00, 0x1bc6a,
+ 0x1bc70, 0x1bc7c,
+ 0x1bc80, 0x1bc88,
+ 0x1bc90, 0x1bc99,
+ 0x1bc9c, 0x1bc9f,
+}; /* CR_Duployan */
+
+/* 'Elbasan': Script */
+static const OnigCodePoint CR_Elbasan[] = {
+ 1,
+ 0x10500, 0x10527,
+}; /* CR_Elbasan */
+
+/* 'Grantha': Script */
+static const OnigCodePoint CR_Grantha[] = {
+ 15,
+ 0x11300, 0x11303,
+ 0x11305, 0x1130c,
+ 0x1130f, 0x11310,
+ 0x11313, 0x11328,
+ 0x1132a, 0x11330,
+ 0x11332, 0x11333,
+ 0x11335, 0x11339,
+ 0x1133c, 0x11344,
+ 0x11347, 0x11348,
+ 0x1134b, 0x1134d,
+ 0x11350, 0x11350,
+ 0x11357, 0x11357,
+ 0x1135d, 0x11363,
+ 0x11366, 0x1136c,
+ 0x11370, 0x11374,
+}; /* CR_Grantha */
+
+/* 'Pahawh_Hmong': Script */
+static const OnigCodePoint CR_Pahawh_Hmong[] = {
+ 5,
+ 0x16b00, 0x16b45,
+ 0x16b50, 0x16b59,
+ 0x16b5b, 0x16b61,
+ 0x16b63, 0x16b77,
+ 0x16b7d, 0x16b8f,
+}; /* CR_Pahawh_Hmong */
+
+/* 'Khojki': Script */
+static const OnigCodePoint CR_Khojki[] = {
+ 2,
+ 0x11200, 0x11211,
+ 0x11213, 0x11241,
+}; /* CR_Khojki */
+
+/* 'Linear_A': Script */
+static const OnigCodePoint CR_Linear_A[] = {
+ 3,
+ 0x10600, 0x10736,
+ 0x10740, 0x10755,
+ 0x10760, 0x10767,
+}; /* CR_Linear_A */
+
+/* 'Mahajani': Script */
+static const OnigCodePoint CR_Mahajani[] = {
+ 1,
+ 0x11150, 0x11176,
+}; /* CR_Mahajani */
+
+/* 'Manichaean': Script */
+static const OnigCodePoint CR_Manichaean[] = {
+ 2,
+ 0x10ac0, 0x10ae6,
+ 0x10aeb, 0x10af6,
+}; /* CR_Manichaean */
+
+/* 'Mende_Kikakui': Script */
+static const OnigCodePoint CR_Mende_Kikakui[] = {
+ 2,
+ 0x1e800, 0x1e8c4,
+ 0x1e8c7, 0x1e8d6,
+}; /* CR_Mende_Kikakui */
+
+/* 'Modi': Script */
+static const OnigCodePoint CR_Modi[] = {
+ 2,
+ 0x11600, 0x11644,
+ 0x11650, 0x11659,
+}; /* CR_Modi */
+
+/* 'Mro': Script */
+static const OnigCodePoint CR_Mro[] = {
+ 3,
+ 0x16a40, 0x16a5e,
+ 0x16a60, 0x16a69,
+ 0x16a6e, 0x16a6f,
+}; /* CR_Mro */
+
+/* 'Old_North_Arabian': Script */
+static const OnigCodePoint CR_Old_North_Arabian[] = {
+ 1,
+ 0x10a80, 0x10a9f,
+}; /* CR_Old_North_Arabian */
+
+/* 'Nabataean': Script */
+static const OnigCodePoint CR_Nabataean[] = {
+ 2,
+ 0x10880, 0x1089e,
+ 0x108a7, 0x108af,
+}; /* CR_Nabataean */
+
+/* 'Palmyrene': Script */
+static const OnigCodePoint CR_Palmyrene[] = {
+ 1,
+ 0x10860, 0x1087f,
+}; /* CR_Palmyrene */
+
+/* 'Pau_Cin_Hau': Script */
+static const OnigCodePoint CR_Pau_Cin_Hau[] = {
+ 1,
+ 0x11ac0, 0x11af8,
+}; /* CR_Pau_Cin_Hau */
+
+/* 'Old_Permic': Script */
+static const OnigCodePoint CR_Old_Permic[] = {
+ 1,
+ 0x10350, 0x1037a,
+}; /* CR_Old_Permic */
+
+/* 'Psalter_Pahlavi': Script */
+static const OnigCodePoint CR_Psalter_Pahlavi[] = {
+ 3,
+ 0x10b80, 0x10b91,
+ 0x10b99, 0x10b9c,
+ 0x10ba9, 0x10baf,
+}; /* CR_Psalter_Pahlavi */
+
+/* 'Siddham': Script */
+static const OnigCodePoint CR_Siddham[] = {
+ 2,
+ 0x11580, 0x115b5,
+ 0x115b8, 0x115dd,
+}; /* CR_Siddham */
+
+/* 'Khudawadi': Script */
+static const OnigCodePoint CR_Khudawadi[] = {
+ 2,
+ 0x112b0, 0x112ea,
+ 0x112f0, 0x112f9,
+}; /* CR_Khudawadi */
+
+/* 'Tirhuta': Script */
+static const OnigCodePoint CR_Tirhuta[] = {
+ 2,
+ 0x11480, 0x114c7,
+ 0x114d0, 0x114d9,
+}; /* CR_Tirhuta */
+
+/* 'Warang_Citi': Script */
+static const OnigCodePoint CR_Warang_Citi[] = {
+ 2,
+ 0x118a0, 0x118f2,
+ 0x118ff, 0x118ff,
+}; /* CR_Warang_Citi */
+
+/* 'Ahom': Script */
+static const OnigCodePoint CR_Ahom[] = {
+ 3,
+ 0x11700, 0x1171a,
+ 0x1171d, 0x1172b,
+ 0x11730, 0x11746,
+}; /* CR_Ahom */
+
+/* 'Anatolian_Hieroglyphs': Script */
+static const OnigCodePoint CR_Anatolian_Hieroglyphs[] = {
+ 1,
+ 0x14400, 0x14646,
+}; /* CR_Anatolian_Hieroglyphs */
+
+/* 'Hatran': Script */
+static const OnigCodePoint CR_Hatran[] = {
+ 3,
+ 0x108e0, 0x108f2,
+ 0x108f4, 0x108f5,
+ 0x108fb, 0x108ff,
+}; /* CR_Hatran */
+
+/* 'Multani': Script */
+static const OnigCodePoint CR_Multani[] = {
+ 5,
+ 0x11280, 0x11286,
+ 0x11288, 0x11288,
+ 0x1128a, 0x1128d,
+ 0x1128f, 0x1129d,
+ 0x1129f, 0x112a9,
+}; /* CR_Multani */
+
+/* 'Old_Hungarian': Script */
+static const OnigCodePoint CR_Old_Hungarian[] = {
+ 3,
+ 0x10c80, 0x10cb2,
+ 0x10cc0, 0x10cf2,
+ 0x10cfa, 0x10cff,
+}; /* CR_Old_Hungarian */
+
+/* 'SignWriting': Script */
+static const OnigCodePoint CR_SignWriting[] = {
+ 3,
+ 0x1d800, 0x1da8b,
+ 0x1da9b, 0x1da9f,
+ 0x1daa1, 0x1daaf,
+}; /* CR_SignWriting */
+
+/* 'Adlam': Script */
+static const OnigCodePoint CR_Adlam[] = {
+ 3,
+ 0x1e900, 0x1e94b,
+ 0x1e950, 0x1e959,
+ 0x1e95e, 0x1e95f,
+}; /* CR_Adlam */
+
+/* 'Bhaiksuki': Script */
+static const OnigCodePoint CR_Bhaiksuki[] = {
+ 4,
+ 0x11c00, 0x11c08,
+ 0x11c0a, 0x11c36,
+ 0x11c38, 0x11c45,
+ 0x11c50, 0x11c6c,
+}; /* CR_Bhaiksuki */
+
+/* 'Marchen': Script */
+static const OnigCodePoint CR_Marchen[] = {
+ 3,
+ 0x11c70, 0x11c8f,
+ 0x11c92, 0x11ca7,
+ 0x11ca9, 0x11cb6,
+}; /* CR_Marchen */
+
+/* 'Newa': Script */
+static const OnigCodePoint CR_Newa[] = {
+ 2,
+ 0x11400, 0x1145b,
+ 0x1145d, 0x11461,
+}; /* CR_Newa */
+
+/* 'Osage': Script */
+static const OnigCodePoint CR_Osage[] = {
+ 2,
+ 0x104b0, 0x104d3,
+ 0x104d8, 0x104fb,
+}; /* CR_Osage */
+
+/* 'Tangut': Script */
+static const OnigCodePoint CR_Tangut[] = {
+ 4,
+ 0x16fe0, 0x16fe0,
+ 0x17000, 0x18aff,
+ 0x18d00, 0x18d1e,
+ 0x18d80, 0x18df2,
+}; /* CR_Tangut */
+
+/* 'Masaram_Gondi': Script */
+static const OnigCodePoint CR_Masaram_Gondi[] = {
+ 7,
+ 0x11d00, 0x11d06,
+ 0x11d08, 0x11d09,
+ 0x11d0b, 0x11d36,
+ 0x11d3a, 0x11d3a,
+ 0x11d3c, 0x11d3d,
+ 0x11d3f, 0x11d47,
+ 0x11d50, 0x11d59,
+}; /* CR_Masaram_Gondi */
+
+/* 'Nushu': Script */
+static const OnigCodePoint CR_Nushu[] = {
+ 2,
+ 0x16fe1, 0x16fe1,
+ 0x1b170, 0x1b2fb,
+}; /* CR_Nushu */
+
+/* 'Soyombo': Script */
+static const OnigCodePoint CR_Soyombo[] = {
+ 1,
+ 0x11a50, 0x11aa2,
+}; /* CR_Soyombo */
+
+/* 'Zanabazar_Square': Script */
+static const OnigCodePoint CR_Zanabazar_Square[] = {
+ 1,
+ 0x11a00, 0x11a47,
+}; /* CR_Zanabazar_Square */
+
+/* 'Dogra': Script */
+static const OnigCodePoint CR_Dogra[] = {
+ 1,
+ 0x11800, 0x1183b,
+}; /* CR_Dogra */
+
+/* 'Gunjala_Gondi': Script */
+static const OnigCodePoint CR_Gunjala_Gondi[] = {
+ 6,
+ 0x11d60, 0x11d65,
+ 0x11d67, 0x11d68,
+ 0x11d6a, 0x11d8e,
+ 0x11d90, 0x11d91,
+ 0x11d93, 0x11d98,
+ 0x11da0, 0x11da9,
+}; /* CR_Gunjala_Gondi */
+
+/* 'Makasar': Script */
+static const OnigCodePoint CR_Makasar[] = {
+ 1,
+ 0x11ee0, 0x11ef8,
+}; /* CR_Makasar */
+
+/* 'Medefaidrin': Script */
+static const OnigCodePoint CR_Medefaidrin[] = {
+ 1,
+ 0x16e40, 0x16e9a,
+}; /* CR_Medefaidrin */
+
+/* 'Hanifi_Rohingya': Script */
+static const OnigCodePoint CR_Hanifi_Rohingya[] = {
+ 2,
+ 0x10d00, 0x10d27,
+ 0x10d30, 0x10d39,
+}; /* CR_Hanifi_Rohingya */
+
+/* 'Sogdian': Script */
+static const OnigCodePoint CR_Sogdian[] = {
+ 1,
+ 0x10f30, 0x10f59,
+}; /* CR_Sogdian */
+
+/* 'Old_Sogdian': Script */
+static const OnigCodePoint CR_Old_Sogdian[] = {
+ 1,
+ 0x10f00, 0x10f27,
+}; /* CR_Old_Sogdian */
+
+/* 'Elymaic': Script */
+static const OnigCodePoint CR_Elymaic[] = {
+ 1,
+ 0x10fe0, 0x10ff6,
+}; /* CR_Elymaic */
+
+/* 'Nandinagari': Script */
+static const OnigCodePoint CR_Nandinagari[] = {
+ 3,
+ 0x119a0, 0x119a7,
+ 0x119aa, 0x119d7,
+ 0x119da, 0x119e4,
+}; /* CR_Nandinagari */
+
+/* 'Nyiakeng_Puachue_Hmong': Script */
+static const OnigCodePoint CR_Nyiakeng_Puachue_Hmong[] = {
+ 4,
+ 0x1e100, 0x1e12c,
+ 0x1e130, 0x1e13d,
+ 0x1e140, 0x1e149,
+ 0x1e14e, 0x1e14f,
+}; /* CR_Nyiakeng_Puachue_Hmong */
+
+/* 'Wancho': Script */
+static const OnigCodePoint CR_Wancho[] = {
+ 2,
+ 0x1e2c0, 0x1e2f9,
+ 0x1e2ff, 0x1e2ff,
+}; /* CR_Wancho */
+
+/* 'Chorasmian': Script */
+static const OnigCodePoint CR_Chorasmian[] = {
+ 1,
+ 0x10fb0, 0x10fcb,
+}; /* CR_Chorasmian */
+
+/* 'Dives_Akuru': Script */
+static const OnigCodePoint CR_Dives_Akuru[] = {
+ 8,
+ 0x11900, 0x11906,
+ 0x11909, 0x11909,
+ 0x1190c, 0x11913,
+ 0x11915, 0x11916,
+ 0x11918, 0x11935,
+ 0x11937, 0x11938,
+ 0x1193b, 0x11946,
+ 0x11950, 0x11959,
+}; /* CR_Dives_Akuru */
+
+/* 'Khitan_Small_Script': Script */
+static const OnigCodePoint CR_Khitan_Small_Script[] = {
+ 3,
+ 0x16fe4, 0x16fe4,
+ 0x18b00, 0x18cd5,
+ 0x18cff, 0x18cff,
+}; /* CR_Khitan_Small_Script */
+
+/* 'Yezidi': Script */
+static const OnigCodePoint CR_Yezidi[] = {
+ 3,
+ 0x10e80, 0x10ea9,
+ 0x10eab, 0x10ead,
+ 0x10eb0, 0x10eb1,
+}; /* CR_Yezidi */
+
+/* 'Cypro_Minoan': Script */
+static const OnigCodePoint CR_Cypro_Minoan[] = {
+ 1,
+ 0x12f90, 0x12ff2,
+}; /* CR_Cypro_Minoan */
+
+/* 'Old_Uyghur': Script */
+static const OnigCodePoint CR_Old_Uyghur[] = {
+ 1,
+ 0x10f70, 0x10f89,
+}; /* CR_Old_Uyghur */
+
+/* 'Tangsa': Script */
+static const OnigCodePoint CR_Tangsa[] = {
+ 2,
+ 0x16a70, 0x16abe,
+ 0x16ac0, 0x16ac9,
+}; /* CR_Tangsa */
+
+/* 'Toto': Script */
+static const OnigCodePoint CR_Toto[] = {
+ 1,
+ 0x1e290, 0x1e2ae,
+}; /* CR_Toto */
+
+/* 'Vithkuqi': Script */
+static const OnigCodePoint CR_Vithkuqi[] = {
+ 8,
+ 0x10570, 0x1057a,
+ 0x1057c, 0x1058a,
+ 0x1058c, 0x10592,
+ 0x10594, 0x10595,
+ 0x10597, 0x105a1,
+ 0x105a3, 0x105b1,
+ 0x105b3, 0x105b9,
+ 0x105bb, 0x105bc,
+}; /* CR_Vithkuqi */
+
+/* 'Kawi': Script */
+static const OnigCodePoint CR_Kawi[] = {
+ 3,
+ 0x11f00, 0x11f10,
+ 0x11f12, 0x11f3a,
+ 0x11f3e, 0x11f5a,
+}; /* CR_Kawi */
+
+/* 'Nag_Mundari': Script */
+static const OnigCodePoint CR_Nag_Mundari[] = {
+ 1,
+ 0x1e4d0, 0x1e4f9,
+}; /* CR_Nag_Mundari */
+
+/* 'Garay': Script */
+static const OnigCodePoint CR_Garay[] = {
+ 3,
+ 0x10d40, 0x10d65,
+ 0x10d69, 0x10d85,
+ 0x10d8e, 0x10d8f,
+}; /* CR_Garay */
+
+/* 'Gurung_Khema': Script */
+static const OnigCodePoint CR_Gurung_Khema[] = {
+ 1,
+ 0x16100, 0x16139,
+}; /* CR_Gurung_Khema */
+
+/* 'Kirat_Rai': Script */
+static const OnigCodePoint CR_Kirat_Rai[] = {
+ 1,
+ 0x16d40, 0x16d79,
+}; /* CR_Kirat_Rai */
+
+/* 'Ol_Onal': Script */
+static const OnigCodePoint CR_Ol_Onal[] = {
+ 2,
+ 0x1e5d0, 0x1e5fa,
+ 0x1e5ff, 0x1e5ff,
+}; /* CR_Ol_Onal */
+
+/* 'Sunuwar': Script */
+static const OnigCodePoint CR_Sunuwar[] = {
+ 2,
+ 0x11bc0, 0x11be1,
+ 0x11bf0, 0x11bf9,
+}; /* CR_Sunuwar */
+
+/* 'Todhri': Script */
+static const OnigCodePoint CR_Todhri[] = {
+ 1,
+ 0x105c0, 0x105f3,
+}; /* CR_Todhri */
+
+/* 'Tulu_Tigalari': Script */
+static const OnigCodePoint CR_Tulu_Tigalari[] = {
+ 11,
+ 0x11380, 0x11389,
+ 0x1138b, 0x1138b,
+ 0x1138e, 0x1138e,
+ 0x11390, 0x113b5,
+ 0x113b7, 0x113c0,
+ 0x113c2, 0x113c2,
+ 0x113c5, 0x113c5,
+ 0x113c7, 0x113ca,
+ 0x113cc, 0x113d5,
+ 0x113d7, 0x113d8,
+ 0x113e1, 0x113e2,
+}; /* CR_Tulu_Tigalari */
+
+/* 'Sidetic': Script */
+static const OnigCodePoint CR_Sidetic[] = {
+ 1,
+ 0x10940, 0x10959,
+}; /* CR_Sidetic */
+
+/* 'Tai_Yo': Script */
+static const OnigCodePoint CR_Tai_Yo[] = {
+ 3,
+ 0x1e6c0, 0x1e6de,
+ 0x1e6e0, 0x1e6f5,
+ 0x1e6fe, 0x1e6ff,
+}; /* CR_Tai_Yo */
+
+/* 'Tolong_Siki': Script */
+static const OnigCodePoint CR_Tolong_Siki[] = {
+ 2,
+ 0x11db0, 0x11ddb,
+ 0x11de0, 0x11de9,
+}; /* CR_Tolong_Siki */
+
+/* 'Beria_Erfe': Script */
+static const OnigCodePoint CR_Beria_Erfe[] = {
+ 2,
+ 0x16ea0, 0x16eb8,
+ 0x16ebb, 0x16ed3,
+}; /* CR_Beria_Erfe */
+
+/* 'White_Space': Binary Property */
+#define CR_White_Space CR_Space
+
+/* 'Bidi_Control': Binary Property */
+static const OnigCodePoint CR_Bidi_Control[] = {
+ 4,
+ 0x061c, 0x061c,
+ 0x200e, 0x200f,
+ 0x202a, 0x202e,
+ 0x2066, 0x2069,
+}; /* CR_Bidi_Control */
+
+/* 'Join_Control': Binary Property */
+static const OnigCodePoint CR_Join_Control[] = {
+ 1,
+ 0x200c, 0x200d,
+}; /* CR_Join_Control */
+
+/* 'Dash': Binary Property */
+static const OnigCodePoint CR_Dash[] = {
+ 24,
+ 0x002d, 0x002d,
+ 0x058a, 0x058a,
+ 0x05be, 0x05be,
+ 0x1400, 0x1400,
+ 0x1806, 0x1806,
+ 0x2010, 0x2015,
+ 0x2053, 0x2053,
+ 0x207b, 0x207b,
+ 0x208b, 0x208b,
+ 0x2212, 0x2212,
+ 0x2e17, 0x2e17,
+ 0x2e1a, 0x2e1a,
+ 0x2e3a, 0x2e3b,
+ 0x2e40, 0x2e40,
+ 0x2e5d, 0x2e5d,
+ 0x301c, 0x301c,
+ 0x3030, 0x3030,
+ 0x30a0, 0x30a0,
+ 0xfe31, 0xfe32,
+ 0xfe58, 0xfe58,
+ 0xfe63, 0xfe63,
+ 0xff0d, 0xff0d,
+ 0x10d6e, 0x10d6e,
+ 0x10ead, 0x10ead,
+}; /* CR_Dash */
+
+/* 'Hyphen': Binary Property */
+static const OnigCodePoint CR_Hyphen[] = {
+ 10,
+ 0x002d, 0x002d,
+ 0x00ad, 0x00ad,
+ 0x058a, 0x058a,
+ 0x1806, 0x1806,
+ 0x2010, 0x2011,
+ 0x2e17, 0x2e17,
+ 0x30fb, 0x30fb,
+ 0xfe63, 0xfe63,
+ 0xff0d, 0xff0d,
+ 0xff65, 0xff65,
+}; /* CR_Hyphen */
+
+/* 'Quotation_Mark': Binary Property */
+static const OnigCodePoint CR_Quotation_Mark[] = {
+ 13,
+ 0x0022, 0x0022,
+ 0x0027, 0x0027,
+ 0x00ab, 0x00ab,
+ 0x00bb, 0x00bb,
+ 0x2018, 0x201f,
+ 0x2039, 0x203a,
+ 0x2e42, 0x2e42,
+ 0x300c, 0x300f,
+ 0x301d, 0x301f,
+ 0xfe41, 0xfe44,
+ 0xff02, 0xff02,
+ 0xff07, 0xff07,
+ 0xff62, 0xff63,
+}; /* CR_Quotation_Mark */
+
+/* 'Terminal_Punctuation': Binary Property */
+static const OnigCodePoint CR_Terminal_Punctuation[] = {
+ 116,
+ 0x0021, 0x0021,
+ 0x002c, 0x002c,
+ 0x002e, 0x002e,
+ 0x003a, 0x003b,
+ 0x003f, 0x003f,
+ 0x037e, 0x037e,
+ 0x0387, 0x0387,
+ 0x0589, 0x0589,
+ 0x05c3, 0x05c3,
+ 0x060c, 0x060c,
+ 0x061b, 0x061b,
+ 0x061d, 0x061f,
+ 0x06d4, 0x06d4,
+ 0x0700, 0x070a,
+ 0x070c, 0x070c,
+ 0x07f8, 0x07f9,
+ 0x0830, 0x0835,
+ 0x0837, 0x083e,
+ 0x085e, 0x085e,
+ 0x0964, 0x0965,
+ 0x0e5a, 0x0e5b,
+ 0x0f08, 0x0f08,
+ 0x0f0d, 0x0f12,
+ 0x104a, 0x104b,
+ 0x1361, 0x1368,
+ 0x166e, 0x166e,
+ 0x16eb, 0x16ed,
+ 0x1735, 0x1736,
+ 0x17d4, 0x17d6,
+ 0x17da, 0x17da,
+ 0x1802, 0x1805,
+ 0x1808, 0x1809,
+ 0x1944, 0x1945,
+ 0x1aa8, 0x1aab,
+ 0x1b4e, 0x1b4f,
+ 0x1b5a, 0x1b5b,
+ 0x1b5d, 0x1b5f,
+ 0x1b7d, 0x1b7f,
+ 0x1c3b, 0x1c3f,
+ 0x1c7e, 0x1c7f,
+ 0x2024, 0x2024,
+ 0x203c, 0x203d,
+ 0x2047, 0x2049,
+ 0x2cf9, 0x2cfb,
+ 0x2e2e, 0x2e2e,
+ 0x2e3c, 0x2e3c,
+ 0x2e41, 0x2e41,
+ 0x2e4c, 0x2e4c,
+ 0x2e4e, 0x2e4f,
+ 0x2e53, 0x2e54,
+ 0x3001, 0x3002,
+ 0xa4fe, 0xa4ff,
+ 0xa60d, 0xa60f,
+ 0xa6f3, 0xa6f7,
+ 0xa876, 0xa877,
+ 0xa8ce, 0xa8cf,
+ 0xa92f, 0xa92f,
+ 0xa9c7, 0xa9c9,
+ 0xaa5d, 0xaa5f,
+ 0xaadf, 0xaadf,
+ 0xaaf0, 0xaaf1,
+ 0xabeb, 0xabeb,
+ 0xfe12, 0xfe12,
+ 0xfe15, 0xfe16,
+ 0xfe50, 0xfe52,
+ 0xfe54, 0xfe57,
+ 0xff01, 0xff01,
+ 0xff0c, 0xff0c,
+ 0xff0e, 0xff0e,
+ 0xff1a, 0xff1b,
+ 0xff1f, 0xff1f,
+ 0xff61, 0xff61,
+ 0xff64, 0xff64,
+ 0x1039f, 0x1039f,
+ 0x103d0, 0x103d0,
+ 0x10857, 0x10857,
+ 0x1091f, 0x1091f,
+ 0x10a56, 0x10a57,
+ 0x10af0, 0x10af5,
+ 0x10b3a, 0x10b3f,
+ 0x10b99, 0x10b9c,
+ 0x10f55, 0x10f59,
+ 0x10f86, 0x10f89,
+ 0x11047, 0x1104d,
+ 0x110be, 0x110c1,
+ 0x11141, 0x11143,
+ 0x111c5, 0x111c6,
+ 0x111cd, 0x111cd,
+ 0x111de, 0x111df,
+ 0x11238, 0x1123c,
+ 0x112a9, 0x112a9,
+ 0x113d4, 0x113d5,
+ 0x1144b, 0x1144d,
+ 0x1145a, 0x1145b,
+ 0x115c2, 0x115c5,
+ 0x115c9, 0x115d7,
+ 0x11641, 0x11642,
+ 0x1173c, 0x1173e,
+ 0x11944, 0x11944,
+ 0x11946, 0x11946,
+ 0x11a42, 0x11a43,
+ 0x11a9b, 0x11a9c,
+ 0x11aa1, 0x11aa2,
+ 0x11c41, 0x11c43,
+ 0x11c71, 0x11c71,
+ 0x11ef7, 0x11ef8,
+ 0x11f43, 0x11f44,
+ 0x12470, 0x12474,
+ 0x16a6e, 0x16a6f,
+ 0x16af5, 0x16af5,
+ 0x16b37, 0x16b39,
+ 0x16b44, 0x16b44,
+ 0x16d6e, 0x16d6f,
+ 0x16e97, 0x16e98,
+ 0x1bc9f, 0x1bc9f,
+ 0x1da87, 0x1da8a,
+}; /* CR_Terminal_Punctuation */
+
+/* 'Other_Math': Binary Property */
+static const OnigCodePoint CR_Other_Math[] = {
+ 134,
+ 0x005e, 0x005e,
+ 0x03d0, 0x03d2,
+ 0x03d5, 0x03d5,
+ 0x03f0, 0x03f1,
+ 0x03f4, 0x03f5,
+ 0x2016, 0x2016,
+ 0x2032, 0x2034,
+ 0x2040, 0x2040,
+ 0x2061, 0x2064,
+ 0x207d, 0x207e,
+ 0x208d, 0x208e,
+ 0x20d0, 0x20dc,
+ 0x20e1, 0x20e1,
+ 0x20e5, 0x20e6,
+ 0x20eb, 0x20ef,
+ 0x2102, 0x2102,
+ 0x2107, 0x2107,
+ 0x210a, 0x2113,
+ 0x2115, 0x2115,
+ 0x2119, 0x211d,
+ 0x2124, 0x2124,
+ 0x2128, 0x2129,
+ 0x212c, 0x212d,
+ 0x212f, 0x2131,
+ 0x2133, 0x2138,
+ 0x213c, 0x213f,
+ 0x2145, 0x2149,
+ 0x2195, 0x2199,
+ 0x219c, 0x219f,
+ 0x21a1, 0x21a2,
+ 0x21a4, 0x21a5,
+ 0x21a7, 0x21a7,
+ 0x21a9, 0x21ad,
+ 0x21b0, 0x21b1,
+ 0x21b6, 0x21b7,
+ 0x21bc, 0x21cd,
+ 0x21d0, 0x21d1,
+ 0x21d3, 0x21d3,
+ 0x21d5, 0x21db,
+ 0x21dd, 0x21dd,
+ 0x21e4, 0x21e5,
+ 0x2308, 0x230b,
+ 0x23b4, 0x23b5,
+ 0x23b7, 0x23b7,
+ 0x23d0, 0x23d0,
+ 0x23e2, 0x23e2,
+ 0x25a0, 0x25a1,
+ 0x25ae, 0x25b6,
+ 0x25bc, 0x25c0,
+ 0x25c6, 0x25c7,
+ 0x25ca, 0x25cb,
+ 0x25cf, 0x25d3,
+ 0x25e2, 0x25e2,
+ 0x25e4, 0x25e4,
+ 0x25e7, 0x25ec,
+ 0x2605, 0x2606,
+ 0x2640, 0x2640,
+ 0x2642, 0x2642,
+ 0x2660, 0x2663,
+ 0x266d, 0x266e,
+ 0x27c5, 0x27c6,
+ 0x27e6, 0x27ef,
+ 0x2983, 0x2998,
+ 0x29d8, 0x29db,
+ 0x29fc, 0x29fd,
+ 0xfe61, 0xfe61,
+ 0xfe63, 0xfe63,
+ 0xfe68, 0xfe68,
+ 0xff3c, 0xff3c,
+ 0xff3e, 0xff3e,
+ 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,
+ 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,
+}; /* CR_Other_Math */
+
+/* 'Hex_Digit': Binary Property */
+static const OnigCodePoint CR_Hex_Digit[] = {
+ 6,
+ 0x0030, 0x0039,
+ 0x0041, 0x0046,
+ 0x0061, 0x0066,
+ 0xff10, 0xff19,
+ 0xff21, 0xff26,
+ 0xff41, 0xff46,
+}; /* CR_Hex_Digit */
+
+/* 'ASCII_Hex_Digit': Binary Property */
+#define CR_ASCII_Hex_Digit CR_XDigit
+
+/* 'Other_Alphabetic': Binary Property */
+static const OnigCodePoint CR_Other_Alphabetic[] = {
+ 255,
+ 0x0345, 0x0345,
+ 0x0363, 0x036f,
+ 0x05b0, 0x05bd,
+ 0x05bf, 0x05bf,
+ 0x05c1, 0x05c2,
+ 0x05c4, 0x05c5,
+ 0x05c7, 0x05c7,
+ 0x0610, 0x061a,
+ 0x064b, 0x0657,
+ 0x0659, 0x065f,
+ 0x0670, 0x0670,
+ 0x06d6, 0x06dc,
+ 0x06e1, 0x06e4,
+ 0x06e7, 0x06e8,
+ 0x06ed, 0x06ed,
+ 0x0711, 0x0711,
+ 0x0730, 0x073f,
+ 0x07a6, 0x07b0,
+ 0x0816, 0x0817,
+ 0x081b, 0x0823,
+ 0x0825, 0x0827,
+ 0x0829, 0x082c,
+ 0x0897, 0x0897,
+ 0x08d4, 0x08df,
+ 0x08e3, 0x08e9,
+ 0x08f0, 0x0903,
+ 0x093a, 0x093b,
+ 0x093e, 0x094c,
+ 0x094e, 0x094f,
+ 0x0955, 0x0957,
+ 0x0962, 0x0963,
+ 0x0981, 0x0983,
+ 0x09be, 0x09c4,
+ 0x09c7, 0x09c8,
+ 0x09cb, 0x09cc,
+ 0x09d7, 0x09d7,
+ 0x09e2, 0x09e3,
+ 0x0a01, 0x0a03,
+ 0x0a3e, 0x0a42,
+ 0x0a47, 0x0a48,
+ 0x0a4b, 0x0a4c,
+ 0x0a51, 0x0a51,
+ 0x0a70, 0x0a71,
+ 0x0a75, 0x0a75,
+ 0x0a81, 0x0a83,
+ 0x0abe, 0x0ac5,
+ 0x0ac7, 0x0ac9,
+ 0x0acb, 0x0acc,
+ 0x0ae2, 0x0ae3,
+ 0x0afa, 0x0afc,
+ 0x0b01, 0x0b03,
+ 0x0b3e, 0x0b44,
+ 0x0b47, 0x0b48,
+ 0x0b4b, 0x0b4c,
+ 0x0b56, 0x0b57,
+ 0x0b62, 0x0b63,
+ 0x0b82, 0x0b82,
+ 0x0bbe, 0x0bc2,
+ 0x0bc6, 0x0bc8,
+ 0x0bca, 0x0bcc,
+ 0x0bd7, 0x0bd7,
+ 0x0c00, 0x0c04,
+ 0x0c3e, 0x0c44,
+ 0x0c46, 0x0c48,
+ 0x0c4a, 0x0c4c,
+ 0x0c55, 0x0c56,
+ 0x0c62, 0x0c63,
+ 0x0c81, 0x0c83,
+ 0x0cbe, 0x0cc4,
+ 0x0cc6, 0x0cc8,
+ 0x0cca, 0x0ccc,
+ 0x0cd5, 0x0cd6,
+ 0x0ce2, 0x0ce3,
+ 0x0cf3, 0x0cf3,
+ 0x0d00, 0x0d03,
+ 0x0d3e, 0x0d44,
+ 0x0d46, 0x0d48,
+ 0x0d4a, 0x0d4c,
+ 0x0d57, 0x0d57,
+ 0x0d62, 0x0d63,
+ 0x0d81, 0x0d83,
+ 0x0dcf, 0x0dd4,
+ 0x0dd6, 0x0dd6,
+ 0x0dd8, 0x0ddf,
+ 0x0df2, 0x0df3,
+ 0x0e31, 0x0e31,
+ 0x0e34, 0x0e3a,
+ 0x0e4d, 0x0e4d,
+ 0x0eb1, 0x0eb1,
+ 0x0eb4, 0x0eb9,
+ 0x0ebb, 0x0ebc,
+ 0x0ecd, 0x0ecd,
+ 0x0f71, 0x0f83,
+ 0x0f8d, 0x0f97,
+ 0x0f99, 0x0fbc,
+ 0x102b, 0x1036,
+ 0x1038, 0x1038,
+ 0x103b, 0x103e,
+ 0x1056, 0x1059,
+ 0x105e, 0x1060,
+ 0x1062, 0x1064,
+ 0x1067, 0x106d,
+ 0x1071, 0x1074,
+ 0x1082, 0x108d,
+ 0x108f, 0x108f,
+ 0x109a, 0x109d,
+ 0x1712, 0x1713,
+ 0x1732, 0x1733,
+ 0x1752, 0x1753,
+ 0x1772, 0x1773,
+ 0x17b6, 0x17c8,
+ 0x1885, 0x1886,
+ 0x18a9, 0x18a9,
+ 0x1920, 0x192b,
+ 0x1930, 0x1938,
+ 0x1a17, 0x1a1b,
+ 0x1a55, 0x1a5e,
+ 0x1a61, 0x1a74,
+ 0x1abf, 0x1ac0,
+ 0x1acc, 0x1ace,
+ 0x1b00, 0x1b04,
+ 0x1b35, 0x1b43,
+ 0x1b80, 0x1b82,
+ 0x1ba1, 0x1ba9,
+ 0x1bac, 0x1bad,
+ 0x1be7, 0x1bf1,
+ 0x1c24, 0x1c36,
+ 0x1dd3, 0x1df4,
+ 0x24b6, 0x24e9,
+ 0x2de0, 0x2dff,
+ 0xa674, 0xa67b,
+ 0xa69e, 0xa69f,
+ 0xa802, 0xa802,
+ 0xa80b, 0xa80b,
+ 0xa823, 0xa827,
+ 0xa880, 0xa881,
+ 0xa8b4, 0xa8c3,
+ 0xa8c5, 0xa8c5,
+ 0xa8ff, 0xa8ff,
+ 0xa926, 0xa92a,
+ 0xa947, 0xa952,
+ 0xa980, 0xa983,
+ 0xa9b4, 0xa9bf,
+ 0xa9e5, 0xa9e5,
+ 0xaa29, 0xaa36,
+ 0xaa43, 0xaa43,
+ 0xaa4c, 0xaa4d,
+ 0xaa7b, 0xaa7d,
+ 0xaab0, 0xaab0,
+ 0xaab2, 0xaab4,
+ 0xaab7, 0xaab8,
+ 0xaabe, 0xaabe,
+ 0xaaeb, 0xaaef,
+ 0xaaf5, 0xaaf5,
+ 0xabe3, 0xabea,
+ 0xfb1e, 0xfb1e,
+ 0x10376, 0x1037a,
+ 0x10a01, 0x10a03,
+ 0x10a05, 0x10a06,
+ 0x10a0c, 0x10a0f,
+ 0x10d24, 0x10d27,
+ 0x10d69, 0x10d69,
+ 0x10eab, 0x10eac,
+ 0x10efa, 0x10efc,
+ 0x11000, 0x11002,
+ 0x11038, 0x11045,
+ 0x11073, 0x11074,
+ 0x11080, 0x11082,
+ 0x110b0, 0x110b8,
+ 0x110c2, 0x110c2,
+ 0x11100, 0x11102,
+ 0x11127, 0x11132,
+ 0x11145, 0x11146,
+ 0x11180, 0x11182,
+ 0x111b3, 0x111bf,
+ 0x111ce, 0x111cf,
+ 0x1122c, 0x11234,
+ 0x11237, 0x11237,
+ 0x1123e, 0x1123e,
+ 0x11241, 0x11241,
+ 0x112df, 0x112e8,
+ 0x11300, 0x11303,
+ 0x1133e, 0x11344,
+ 0x11347, 0x11348,
+ 0x1134b, 0x1134c,
+ 0x11357, 0x11357,
+ 0x11362, 0x11363,
+ 0x113b8, 0x113c0,
+ 0x113c2, 0x113c2,
+ 0x113c5, 0x113c5,
+ 0x113c7, 0x113ca,
+ 0x113cc, 0x113cd,
+ 0x11435, 0x11441,
+ 0x11443, 0x11445,
+ 0x114b0, 0x114c1,
+ 0x115af, 0x115b5,
+ 0x115b8, 0x115be,
+ 0x115dc, 0x115dd,
+ 0x11630, 0x1163e,
+ 0x11640, 0x11640,
+ 0x116ab, 0x116b5,
+ 0x1171d, 0x1172a,
+ 0x1182c, 0x11838,
+ 0x11930, 0x11935,
+ 0x11937, 0x11938,
+ 0x1193b, 0x1193c,
+ 0x11940, 0x11940,
+ 0x11942, 0x11942,
+ 0x119d1, 0x119d7,
+ 0x119da, 0x119df,
+ 0x119e4, 0x119e4,
+ 0x11a01, 0x11a0a,
+ 0x11a35, 0x11a39,
+ 0x11a3b, 0x11a3e,
+ 0x11a51, 0x11a5b,
+ 0x11a8a, 0x11a97,
+ 0x11b60, 0x11b67,
+ 0x11c2f, 0x11c36,
+ 0x11c38, 0x11c3e,
+ 0x11c92, 0x11ca7,
+ 0x11ca9, 0x11cb6,
+ 0x11d31, 0x11d36,
+ 0x11d3a, 0x11d3a,
+ 0x11d3c, 0x11d3d,
+ 0x11d3f, 0x11d41,
+ 0x11d43, 0x11d43,
+ 0x11d47, 0x11d47,
+ 0x11d8a, 0x11d8e,
+ 0x11d90, 0x11d91,
+ 0x11d93, 0x11d96,
+ 0x11ef3, 0x11ef6,
+ 0x11f00, 0x11f01,
+ 0x11f03, 0x11f03,
+ 0x11f34, 0x11f3a,
+ 0x11f3e, 0x11f40,
+ 0x1611e, 0x1612e,
+ 0x16f4f, 0x16f4f,
+ 0x16f51, 0x16f87,
+ 0x16f8f, 0x16f92,
+ 0x16ff0, 0x16ff1,
+ 0x1bc9e, 0x1bc9e,
+ 0x1e000, 0x1e006,
+ 0x1e008, 0x1e018,
+ 0x1e01b, 0x1e021,
+ 0x1e023, 0x1e024,
+ 0x1e026, 0x1e02a,
+ 0x1e08f, 0x1e08f,
+ 0x1e6e3, 0x1e6e3,
+ 0x1e6e6, 0x1e6e6,
+ 0x1e6ee, 0x1e6ef,
+ 0x1e6f5, 0x1e6f5,
+ 0x1e947, 0x1e947,
+ 0x1f130, 0x1f149,
+ 0x1f150, 0x1f169,
+ 0x1f170, 0x1f189,
+}; /* CR_Other_Alphabetic */
+
+/* 'Ideographic': Binary Property */
+static const OnigCodePoint CR_Ideographic[] = {
+ 21,
+ 0x3006, 0x3007,
+ 0x3021, 0x3029,
+ 0x3038, 0x303a,
+ 0x3400, 0x4dbf,
+ 0x4e00, 0x9fff,
+ 0xf900, 0xfa6d,
+ 0xfa70, 0xfad9,
+ 0x16fe4, 0x16fe4,
+ 0x16ff2, 0x16ff6,
+ 0x17000, 0x18cd5,
+ 0x18cff, 0x18d1e,
+ 0x18d80, 0x18df2,
+ 0x1b170, 0x1b2fb,
+ 0x20000, 0x2a6df,
+ 0x2a700, 0x2b81d,
+ 0x2b820, 0x2cead,
+ 0x2ceb0, 0x2ebe0,
+ 0x2ebf0, 0x2ee5d,
+ 0x2f800, 0x2fa1d,
+ 0x30000, 0x3134a,
+ 0x31350, 0x33479,
+}; /* CR_Ideographic */
+
+/* 'Diacritic': Binary Property */
+static const OnigCodePoint CR_Diacritic[] = {
+ 220,
+ 0x005e, 0x005e,
+ 0x0060, 0x0060,
+ 0x00a8, 0x00a8,
+ 0x00af, 0x00af,
+ 0x00b4, 0x00b4,
+ 0x00b7, 0x00b8,
+ 0x02b0, 0x034e,
+ 0x0350, 0x0357,
+ 0x035d, 0x0362,
+ 0x0374, 0x0375,
+ 0x037a, 0x037a,
+ 0x0384, 0x0385,
+ 0x0483, 0x0487,
+ 0x0559, 0x0559,
+ 0x0591, 0x05bd,
+ 0x05bf, 0x05bf,
+ 0x05c1, 0x05c2,
+ 0x05c4, 0x05c5,
+ 0x05c7, 0x05c7,
+ 0x064b, 0x0652,
+ 0x0657, 0x0658,
+ 0x06df, 0x06e0,
+ 0x06e5, 0x06e6,
+ 0x06ea, 0x06ec,
+ 0x0730, 0x074a,
+ 0x07a6, 0x07b0,
+ 0x07eb, 0x07f5,
+ 0x0818, 0x0819,
+ 0x0898, 0x089f,
+ 0x08c9, 0x08d2,
+ 0x08e3, 0x08fe,
+ 0x093c, 0x093c,
+ 0x094d, 0x094d,
+ 0x0951, 0x0954,
+ 0x0971, 0x0971,
+ 0x09bc, 0x09bc,
+ 0x09cd, 0x09cd,
+ 0x0a3c, 0x0a3c,
+ 0x0a4d, 0x0a4d,
+ 0x0abc, 0x0abc,
+ 0x0acd, 0x0acd,
+ 0x0afd, 0x0aff,
+ 0x0b3c, 0x0b3c,
+ 0x0b4d, 0x0b4d,
+ 0x0b55, 0x0b55,
+ 0x0bcd, 0x0bcd,
+ 0x0c3c, 0x0c3c,
+ 0x0c4d, 0x0c4d,
+ 0x0cbc, 0x0cbc,
+ 0x0ccd, 0x0ccd,
+ 0x0d3b, 0x0d3c,
+ 0x0d4d, 0x0d4d,
+ 0x0dca, 0x0dca,
+ 0x0e3a, 0x0e3a,
+ 0x0e47, 0x0e4c,
+ 0x0e4e, 0x0e4e,
+ 0x0eba, 0x0eba,
+ 0x0ec8, 0x0ecc,
+ 0x0f18, 0x0f19,
+ 0x0f35, 0x0f35,
+ 0x0f37, 0x0f37,
+ 0x0f39, 0x0f39,
+ 0x0f3e, 0x0f3f,
+ 0x0f82, 0x0f84,
+ 0x0f86, 0x0f87,
+ 0x0fc6, 0x0fc6,
+ 0x1037, 0x1037,
+ 0x1039, 0x103a,
+ 0x1063, 0x1064,
+ 0x1069, 0x106d,
+ 0x1087, 0x108d,
+ 0x108f, 0x108f,
+ 0x109a, 0x109b,
+ 0x135d, 0x135f,
+ 0x1714, 0x1715,
+ 0x1734, 0x1734,
+ 0x17c9, 0x17d3,
+ 0x17dd, 0x17dd,
+ 0x1939, 0x193b,
+ 0x1a60, 0x1a60,
+ 0x1a75, 0x1a7c,
+ 0x1a7f, 0x1a7f,
+ 0x1ab0, 0x1abe,
+ 0x1ac1, 0x1acb,
+ 0x1acf, 0x1add,
+ 0x1ae0, 0x1aeb,
+ 0x1b34, 0x1b34,
+ 0x1b44, 0x1b44,
+ 0x1b6b, 0x1b73,
+ 0x1baa, 0x1bab,
+ 0x1be6, 0x1be6,
+ 0x1bf2, 0x1bf3,
+ 0x1c36, 0x1c37,
+ 0x1c78, 0x1c7d,
+ 0x1cd0, 0x1ce8,
+ 0x1ced, 0x1ced,
+ 0x1cf4, 0x1cf4,
+ 0x1cf7, 0x1cf9,
+ 0x1d2c, 0x1d6a,
+ 0x1d9b, 0x1dbe,
+ 0x1dc4, 0x1dcf,
+ 0x1df5, 0x1dff,
+ 0x1fbd, 0x1fbd,
+ 0x1fbf, 0x1fc1,
+ 0x1fcd, 0x1fcf,
+ 0x1fdd, 0x1fdf,
+ 0x1fed, 0x1fef,
+ 0x1ffd, 0x1ffe,
+ 0x2cef, 0x2cf1,
+ 0x2e2f, 0x2e2f,
+ 0x302a, 0x302f,
+ 0x3099, 0x309c,
+ 0x30fc, 0x30fc,
+ 0xa66f, 0xa66f,
+ 0xa67c, 0xa67d,
+ 0xa67f, 0xa67f,
+ 0xa69c, 0xa69d,
+ 0xa6f0, 0xa6f1,
+ 0xa700, 0xa721,
+ 0xa788, 0xa78a,
+ 0xa7f1, 0xa7f1,
+ 0xa7f8, 0xa7f9,
+ 0xa806, 0xa806,
+ 0xa82c, 0xa82c,
+ 0xa8c4, 0xa8c4,
+ 0xa8e0, 0xa8f1,
+ 0xa92b, 0xa92e,
+ 0xa953, 0xa953,
+ 0xa9b3, 0xa9b3,
+ 0xa9c0, 0xa9c0,
+ 0xa9e5, 0xa9e5,
+ 0xaa7b, 0xaa7d,
+ 0xaabf, 0xaac2,
+ 0xaaf6, 0xaaf6,
+ 0xab5b, 0xab5f,
+ 0xab69, 0xab6b,
+ 0xabec, 0xabed,
+ 0xfb1e, 0xfb1e,
+ 0xfe20, 0xfe2f,
+ 0xff3e, 0xff3e,
+ 0xff40, 0xff40,
+ 0xff70, 0xff70,
+ 0xff9e, 0xff9f,
+ 0xffe3, 0xffe3,
+ 0x102e0, 0x102e0,
+ 0x10780, 0x10785,
+ 0x10787, 0x107b0,
+ 0x107b2, 0x107ba,
+ 0x10a38, 0x10a3a,
+ 0x10a3f, 0x10a3f,
+ 0x10ae5, 0x10ae6,
+ 0x10d22, 0x10d27,
+ 0x10d4e, 0x10d4e,
+ 0x10d69, 0x10d6d,
+ 0x10efa, 0x10efa,
+ 0x10efd, 0x10eff,
+ 0x10f46, 0x10f50,
+ 0x10f82, 0x10f85,
+ 0x11046, 0x11046,
+ 0x11070, 0x11070,
+ 0x110b9, 0x110ba,
+ 0x11133, 0x11134,
+ 0x11173, 0x11173,
+ 0x111c0, 0x111c0,
+ 0x111ca, 0x111cc,
+ 0x11235, 0x11236,
+ 0x112e9, 0x112ea,
+ 0x1133b, 0x1133c,
+ 0x1134d, 0x1134d,
+ 0x11366, 0x1136c,
+ 0x11370, 0x11374,
+ 0x113ce, 0x113d0,
+ 0x113d2, 0x113d3,
+ 0x113e1, 0x113e2,
+ 0x11442, 0x11442,
+ 0x11446, 0x11446,
+ 0x114c2, 0x114c3,
+ 0x115bf, 0x115c0,
+ 0x1163f, 0x1163f,
+ 0x116b6, 0x116b7,
+ 0x1172b, 0x1172b,
+ 0x11839, 0x1183a,
+ 0x1193d, 0x1193e,
+ 0x11943, 0x11943,
+ 0x119e0, 0x119e0,
+ 0x11a34, 0x11a34,
+ 0x11a47, 0x11a47,
+ 0x11a99, 0x11a99,
+ 0x11c3f, 0x11c3f,
+ 0x11d42, 0x11d42,
+ 0x11d44, 0x11d45,
+ 0x11d97, 0x11d97,
+ 0x11dd9, 0x11dd9,
+ 0x11f41, 0x11f42,
+ 0x11f5a, 0x11f5a,
+ 0x13447, 0x13455,
+ 0x1612f, 0x1612f,
+ 0x16af0, 0x16af4,
+ 0x16b30, 0x16b36,
+ 0x16d6b, 0x16d6c,
+ 0x16f8f, 0x16f9f,
+ 0x16ff0, 0x16ff1,
+ 0x1aff0, 0x1aff3,
+ 0x1aff5, 0x1affb,
+ 0x1affd, 0x1affe,
+ 0x1cf00, 0x1cf2d,
+ 0x1cf30, 0x1cf46,
+ 0x1d167, 0x1d169,
+ 0x1d16d, 0x1d172,
+ 0x1d17b, 0x1d182,
+ 0x1d185, 0x1d18b,
+ 0x1d1aa, 0x1d1ad,
+ 0x1e030, 0x1e06d,
+ 0x1e130, 0x1e136,
+ 0x1e2ae, 0x1e2ae,
+ 0x1e2ec, 0x1e2ef,
+ 0x1e5ee, 0x1e5ef,
+ 0x1e8d0, 0x1e8d6,
+ 0x1e944, 0x1e946,
+ 0x1e948, 0x1e94a,
+}; /* CR_Diacritic */
+
+/* 'Extender': Binary Property */
+static const OnigCodePoint CR_Extender[] = {
+ 43,
+ 0x00b7, 0x00b7,
+ 0x02d0, 0x02d1,
+ 0x0640, 0x0640,
+ 0x07fa, 0x07fa,
+ 0x0a71, 0x0a71,
+ 0x0afb, 0x0afb,
+ 0x0b55, 0x0b55,
+ 0x0e46, 0x0e46,
+ 0x0ec6, 0x0ec6,
+ 0x180a, 0x180a,
+ 0x1843, 0x1843,
+ 0x1aa7, 0x1aa7,
+ 0x1c36, 0x1c36,
+ 0x1c7b, 0x1c7b,
+ 0x3005, 0x3005,
+ 0x3031, 0x3035,
+ 0x309d, 0x309e,
+ 0x30fc, 0x30fe,
+ 0xa015, 0xa015,
+ 0xa60c, 0xa60c,
+ 0xa9cf, 0xa9cf,
+ 0xa9e6, 0xa9e6,
+ 0xaa70, 0xaa70,
+ 0xaadd, 0xaadd,
+ 0xaaf3, 0xaaf4,
+ 0xff70, 0xff70,
+ 0x10781, 0x10782,
+ 0x10d4e, 0x10d4e,
+ 0x10d6a, 0x10d6a,
+ 0x10d6f, 0x10d6f,
+ 0x11237, 0x11237,
+ 0x1135d, 0x1135d,
+ 0x113d2, 0x113d3,
+ 0x115c6, 0x115c8,
+ 0x11a98, 0x11a98,
+ 0x11dd9, 0x11dd9,
+ 0x16b42, 0x16b43,
+ 0x16fe0, 0x16fe1,
+ 0x16fe3, 0x16fe3,
+ 0x16ff2, 0x16ff3,
+ 0x1e13c, 0x1e13d,
+ 0x1e5ef, 0x1e5ef,
+ 0x1e944, 0x1e946,
+}; /* CR_Extender */
+
+/* 'Other_Lowercase': Binary Property */
+static const OnigCodePoint CR_Other_Lowercase[] = {
+ 28,
+ 0x00aa, 0x00aa,
+ 0x00ba, 0x00ba,
+ 0x02b0, 0x02b8,
+ 0x02c0, 0x02c1,
+ 0x02e0, 0x02e4,
+ 0x0345, 0x0345,
+ 0x037a, 0x037a,
+ 0x10fc, 0x10fc,
+ 0x1d2c, 0x1d6a,
+ 0x1d78, 0x1d78,
+ 0x1d9b, 0x1dbf,
+ 0x2071, 0x2071,
+ 0x207f, 0x207f,
+ 0x2090, 0x209c,
+ 0x2170, 0x217f,
+ 0x24d0, 0x24e9,
+ 0x2c7c, 0x2c7d,
+ 0xa69c, 0xa69d,
+ 0xa770, 0xa770,
+ 0xa7f1, 0xa7f4,
+ 0xa7f8, 0xa7f9,
+ 0xab5c, 0xab5f,
+ 0xab69, 0xab69,
+ 0x10780, 0x10780,
+ 0x10783, 0x10785,
+ 0x10787, 0x107b0,
+ 0x107b2, 0x107ba,
+ 0x1e030, 0x1e06d,
+}; /* CR_Other_Lowercase */
+
+/* 'Other_Uppercase': Binary Property */
+static const OnigCodePoint CR_Other_Uppercase[] = {
+ 5,
+ 0x2160, 0x216f,
+ 0x24b6, 0x24cf,
+ 0x1f130, 0x1f149,
+ 0x1f150, 0x1f169,
+ 0x1f170, 0x1f189,
+}; /* CR_Other_Uppercase */
+
+/* 'Noncharacter_Code_Point': Binary Property */
+static const OnigCodePoint CR_Noncharacter_Code_Point[] = {
+ 18,
+ 0xfdd0, 0xfdef,
+ 0xfffe, 0xffff,
+ 0x1fffe, 0x1ffff,
+ 0x2fffe, 0x2ffff,
+ 0x3fffe, 0x3ffff,
+ 0x4fffe, 0x4ffff,
+ 0x5fffe, 0x5ffff,
+ 0x6fffe, 0x6ffff,
+ 0x7fffe, 0x7ffff,
+ 0x8fffe, 0x8ffff,
+ 0x9fffe, 0x9ffff,
+ 0xafffe, 0xaffff,
+ 0xbfffe, 0xbffff,
+ 0xcfffe, 0xcffff,
+ 0xdfffe, 0xdffff,
+ 0xefffe, 0xeffff,
+ 0xffffe, 0xfffff,
+ 0x10fffe, 0x10ffff,
+}; /* CR_Noncharacter_Code_Point */
+
+/* 'Other_Grapheme_Extend': Binary Property */
+static const OnigCodePoint CR_Other_Grapheme_Extend[] = {
+ 49,
+ 0x09be, 0x09be,
+ 0x09d7, 0x09d7,
+ 0x0b3e, 0x0b3e,
+ 0x0b57, 0x0b57,
+ 0x0bbe, 0x0bbe,
+ 0x0bd7, 0x0bd7,
+ 0x0cc0, 0x0cc0,
+ 0x0cc2, 0x0cc2,
+ 0x0cc7, 0x0cc8,
+ 0x0cca, 0x0ccb,
+ 0x0cd5, 0x0cd6,
+ 0x0d3e, 0x0d3e,
+ 0x0d57, 0x0d57,
+ 0x0dcf, 0x0dcf,
+ 0x0ddf, 0x0ddf,
+ 0x1715, 0x1715,
+ 0x1734, 0x1734,
+ 0x1b35, 0x1b35,
+ 0x1b3b, 0x1b3b,
+ 0x1b3d, 0x1b3d,
+ 0x1b43, 0x1b44,
+ 0x1baa, 0x1baa,
+ 0x1bf2, 0x1bf3,
+ 0x200c, 0x200c,
+ 0x302e, 0x302f,
+ 0xa953, 0xa953,
+ 0xa9c0, 0xa9c0,
+ 0xff9e, 0xff9f,
+ 0x111c0, 0x111c0,
+ 0x11235, 0x11235,
+ 0x1133e, 0x1133e,
+ 0x1134d, 0x1134d,
+ 0x11357, 0x11357,
+ 0x113b8, 0x113b8,
+ 0x113c2, 0x113c2,
+ 0x113c5, 0x113c5,
+ 0x113c7, 0x113c9,
+ 0x113cf, 0x113cf,
+ 0x114b0, 0x114b0,
+ 0x114bd, 0x114bd,
+ 0x115af, 0x115af,
+ 0x116b6, 0x116b6,
+ 0x11930, 0x11930,
+ 0x1193d, 0x1193d,
+ 0x11f41, 0x11f41,
+ 0x16ff0, 0x16ff1,
+ 0x1d165, 0x1d166,
+ 0x1d16d, 0x1d172,
+ 0xe0020, 0xe007f,
+}; /* CR_Other_Grapheme_Extend */
+
+/* 'IDS_Binary_Operator': Binary Property */
+static const OnigCodePoint CR_IDS_Binary_Operator[] = {
+ 3,
+ 0x2ff0, 0x2ff1,
+ 0x2ff4, 0x2ffd,
+ 0x31ef, 0x31ef,
+}; /* CR_IDS_Binary_Operator */
+
+/* 'IDS_Trinary_Operator': Binary Property */
+static const OnigCodePoint CR_IDS_Trinary_Operator[] = {
+ 1,
+ 0x2ff2, 0x2ff3,
+}; /* CR_IDS_Trinary_Operator */
+
+/* 'IDS_Unary_Operator': Binary Property */
+static const OnigCodePoint CR_IDS_Unary_Operator[] = {
+ 1,
+ 0x2ffe, 0x2fff,
+}; /* CR_IDS_Unary_Operator */
+
+/* 'Radical': Binary Property */
+static const OnigCodePoint CR_Radical[] = {
+ 3,
+ 0x2e80, 0x2e99,
+ 0x2e9b, 0x2ef3,
+ 0x2f00, 0x2fd5,
+}; /* CR_Radical */
+
+/* 'Unified_Ideograph': Binary Property */
+static const OnigCodePoint CR_Unified_Ideograph[] = {
+ 16,
+ 0x3400, 0x4dbf,
+ 0x4e00, 0x9fff,
+ 0xfa0e, 0xfa0f,
+ 0xfa11, 0xfa11,
+ 0xfa13, 0xfa14,
+ 0xfa1f, 0xfa1f,
+ 0xfa21, 0xfa21,
+ 0xfa23, 0xfa24,
+ 0xfa27, 0xfa29,
+ 0x20000, 0x2a6df,
+ 0x2a700, 0x2b81d,
+ 0x2b820, 0x2cead,
+ 0x2ceb0, 0x2ebe0,
+ 0x2ebf0, 0x2ee5d,
+ 0x30000, 0x3134a,
+ 0x31350, 0x33479,
+}; /* CR_Unified_Ideograph */
+
+/* 'Other_Default_Ignorable_Code_Point': Binary Property */
+static const OnigCodePoint CR_Other_Default_Ignorable_Code_Point[] = {
+ 11,
+ 0x034f, 0x034f,
+ 0x115f, 0x1160,
+ 0x17b4, 0x17b5,
+ 0x2065, 0x2065,
+ 0x3164, 0x3164,
+ 0xffa0, 0xffa0,
+ 0xfff0, 0xfff8,
+ 0xe0000, 0xe0000,
+ 0xe0002, 0xe001f,
+ 0xe0080, 0xe00ff,
+ 0xe01f0, 0xe0fff,
+}; /* CR_Other_Default_Ignorable_Code_Point */
+
+/* 'Deprecated': Binary Property */
+static const OnigCodePoint CR_Deprecated[] = {
+ 8,
+ 0x0149, 0x0149,
+ 0x0673, 0x0673,
+ 0x0f77, 0x0f77,
+ 0x0f79, 0x0f79,
+ 0x17a3, 0x17a4,
+ 0x206a, 0x206f,
+ 0x2329, 0x232a,
+ 0xe0001, 0xe0001,
+}; /* CR_Deprecated */
+
+/* 'Soft_Dotted': Binary Property */
+static const OnigCodePoint CR_Soft_Dotted[] = {
+ 34,
+ 0x0069, 0x006a,
+ 0x012f, 0x012f,
+ 0x0249, 0x0249,
+ 0x0268, 0x0268,
+ 0x029d, 0x029d,
+ 0x02b2, 0x02b2,
+ 0x03f3, 0x03f3,
+ 0x0456, 0x0456,
+ 0x0458, 0x0458,
+ 0x1d62, 0x1d62,
+ 0x1d96, 0x1d96,
+ 0x1da4, 0x1da4,
+ 0x1da8, 0x1da8,
+ 0x1e2d, 0x1e2d,
+ 0x1ecb, 0x1ecb,
+ 0x2071, 0x2071,
+ 0x2148, 0x2149,
+ 0x2c7c, 0x2c7c,
+ 0x1d422, 0x1d423,
+ 0x1d456, 0x1d457,
+ 0x1d48a, 0x1d48b,
+ 0x1d4be, 0x1d4bf,
+ 0x1d4f2, 0x1d4f3,
+ 0x1d526, 0x1d527,
+ 0x1d55a, 0x1d55b,
+ 0x1d58e, 0x1d58f,
+ 0x1d5c2, 0x1d5c3,
+ 0x1d5f6, 0x1d5f7,
+ 0x1d62a, 0x1d62b,
+ 0x1d65e, 0x1d65f,
+ 0x1d692, 0x1d693,
+ 0x1df1a, 0x1df1a,
+ 0x1e04c, 0x1e04d,
+ 0x1e068, 0x1e068,
+}; /* CR_Soft_Dotted */
+
+/* 'Logical_Order_Exception': Binary Property */
+static const OnigCodePoint CR_Logical_Order_Exception[] = {
+ 7,
+ 0x0e40, 0x0e44,
+ 0x0ec0, 0x0ec4,
+ 0x19b5, 0x19b7,
+ 0x19ba, 0x19ba,
+ 0xaab5, 0xaab6,
+ 0xaab9, 0xaab9,
+ 0xaabb, 0xaabc,
+}; /* CR_Logical_Order_Exception */
+
+/* 'Other_ID_Start': Binary Property */
+static const OnigCodePoint CR_Other_ID_Start[] = {
+ 4,
+ 0x1885, 0x1886,
+ 0x2118, 0x2118,
+ 0x212e, 0x212e,
+ 0x309b, 0x309c,
+}; /* CR_Other_ID_Start */
+
+/* 'Other_ID_Continue': Binary Property */
+static const OnigCodePoint CR_Other_ID_Continue[] = {
+ 7,
+ 0x00b7, 0x00b7,
+ 0x0387, 0x0387,
+ 0x1369, 0x1371,
+ 0x19da, 0x19da,
+ 0x200c, 0x200d,
+ 0x30fb, 0x30fb,
+ 0xff65, 0xff65,
+}; /* CR_Other_ID_Continue */
+
+/* 'ID_Compat_Math_Continue': Binary Property */
+static const OnigCodePoint CR_ID_Compat_Math_Continue[] = {
+ 18,
+ 0x00b2, 0x00b3,
+ 0x00b9, 0x00b9,
+ 0x2070, 0x2070,
+ 0x2074, 0x207e,
+ 0x2080, 0x208e,
+ 0x2202, 0x2202,
+ 0x2207, 0x2207,
+ 0x221e, 0x221e,
+ 0x1d6c1, 0x1d6c1,
+ 0x1d6db, 0x1d6db,
+ 0x1d6fb, 0x1d6fb,
+ 0x1d715, 0x1d715,
+ 0x1d735, 0x1d735,
+ 0x1d74f, 0x1d74f,
+ 0x1d76f, 0x1d76f,
+ 0x1d789, 0x1d789,
+ 0x1d7a9, 0x1d7a9,
+ 0x1d7c3, 0x1d7c3,
+}; /* CR_ID_Compat_Math_Continue */
+
+/* 'ID_Compat_Math_Start': Binary Property */
+static const OnigCodePoint CR_ID_Compat_Math_Start[] = {
+ 13,
+ 0x2202, 0x2202,
+ 0x2207, 0x2207,
+ 0x221e, 0x221e,
+ 0x1d6c1, 0x1d6c1,
+ 0x1d6db, 0x1d6db,
+ 0x1d6fb, 0x1d6fb,
+ 0x1d715, 0x1d715,
+ 0x1d735, 0x1d735,
+ 0x1d74f, 0x1d74f,
+ 0x1d76f, 0x1d76f,
+ 0x1d789, 0x1d789,
+ 0x1d7a9, 0x1d7a9,
+ 0x1d7c3, 0x1d7c3,
+}; /* CR_ID_Compat_Math_Start */
+
+/* 'Sentence_Terminal': Binary Property */
+static const OnigCodePoint CR_Sentence_Terminal[] = {
+ 88,
+ 0x0021, 0x0021,
+ 0x002e, 0x002e,
+ 0x003f, 0x003f,
+ 0x0589, 0x0589,
+ 0x061d, 0x061f,
+ 0x06d4, 0x06d4,
+ 0x0700, 0x0702,
+ 0x07f9, 0x07f9,
+ 0x0837, 0x0837,
+ 0x0839, 0x0839,
+ 0x083d, 0x083e,
+ 0x0964, 0x0965,
+ 0x104a, 0x104b,
+ 0x1362, 0x1362,
+ 0x1367, 0x1368,
+ 0x166e, 0x166e,
+ 0x1735, 0x1736,
+ 0x17d4, 0x17d5,
+ 0x1803, 0x1803,
+ 0x1809, 0x1809,
+ 0x1944, 0x1945,
+ 0x1aa8, 0x1aab,
+ 0x1b4e, 0x1b4f,
+ 0x1b5a, 0x1b5b,
+ 0x1b5e, 0x1b5f,
+ 0x1b7d, 0x1b7f,
+ 0x1c3b, 0x1c3c,
+ 0x1c7e, 0x1c7f,
+ 0x2024, 0x2024,
+ 0x203c, 0x203d,
+ 0x2047, 0x2049,
+ 0x2cf9, 0x2cfb,
+ 0x2e2e, 0x2e2e,
+ 0x2e3c, 0x2e3c,
+ 0x2e53, 0x2e54,
+ 0x3002, 0x3002,
+ 0xa4ff, 0xa4ff,
+ 0xa60e, 0xa60f,
+ 0xa6f3, 0xa6f3,
+ 0xa6f7, 0xa6f7,
+ 0xa876, 0xa877,
+ 0xa8ce, 0xa8cf,
+ 0xa92f, 0xa92f,
+ 0xa9c8, 0xa9c9,
+ 0xaa5d, 0xaa5f,
+ 0xaaf0, 0xaaf1,
+ 0xabeb, 0xabeb,
+ 0xfe12, 0xfe12,
+ 0xfe15, 0xfe16,
+ 0xfe52, 0xfe52,
+ 0xfe56, 0xfe57,
+ 0xff01, 0xff01,
+ 0xff0e, 0xff0e,
+ 0xff1f, 0xff1f,
+ 0xff61, 0xff61,
+ 0x10a56, 0x10a57,
+ 0x10f55, 0x10f59,
+ 0x10f86, 0x10f89,
+ 0x11047, 0x11048,
+ 0x110be, 0x110c1,
+ 0x11141, 0x11143,
+ 0x111c5, 0x111c6,
+ 0x111cd, 0x111cd,
+ 0x111de, 0x111df,
+ 0x11238, 0x11239,
+ 0x1123b, 0x1123c,
+ 0x112a9, 0x112a9,
+ 0x113d4, 0x113d5,
+ 0x1144b, 0x1144c,
+ 0x115c2, 0x115c3,
+ 0x115c9, 0x115d7,
+ 0x11641, 0x11642,
+ 0x1173c, 0x1173e,
+ 0x11944, 0x11944,
+ 0x11946, 0x11946,
+ 0x11a42, 0x11a43,
+ 0x11a9b, 0x11a9c,
+ 0x11c41, 0x11c42,
+ 0x11ef7, 0x11ef8,
+ 0x11f43, 0x11f44,
+ 0x16a6e, 0x16a6f,
+ 0x16af5, 0x16af5,
+ 0x16b37, 0x16b38,
+ 0x16b44, 0x16b44,
+ 0x16d6e, 0x16d6f,
+ 0x16e98, 0x16e98,
+ 0x1bc9f, 0x1bc9f,
+ 0x1da88, 0x1da88,
+}; /* CR_Sentence_Terminal */
+
+/* 'Variation_Selector': Binary Property */
+static const OnigCodePoint CR_Variation_Selector[] = {
+ 4,
+ 0x180b, 0x180d,
+ 0x180f, 0x180f,
+ 0xfe00, 0xfe0f,
+ 0xe0100, 0xe01ef,
+}; /* CR_Variation_Selector */
+
+/* 'Pattern_White_Space': Binary Property */
+static const OnigCodePoint CR_Pattern_White_Space[] = {
+ 5,
+ 0x0009, 0x000d,
+ 0x0020, 0x0020,
+ 0x0085, 0x0085,
+ 0x200e, 0x200f,
+ 0x2028, 0x2029,
+}; /* CR_Pattern_White_Space */
+
+/* 'Pattern_Syntax': Binary Property */
+static const OnigCodePoint CR_Pattern_Syntax[] = {
+ 28,
+ 0x0021, 0x002f,
+ 0x003a, 0x0040,
+ 0x005b, 0x005e,
+ 0x0060, 0x0060,
+ 0x007b, 0x007e,
+ 0x00a1, 0x00a7,
+ 0x00a9, 0x00a9,
+ 0x00ab, 0x00ac,
+ 0x00ae, 0x00ae,
+ 0x00b0, 0x00b1,
+ 0x00b6, 0x00b6,
+ 0x00bb, 0x00bb,
+ 0x00bf, 0x00bf,
+ 0x00d7, 0x00d7,
+ 0x00f7, 0x00f7,
+ 0x2010, 0x2027,
+ 0x2030, 0x203e,
+ 0x2041, 0x2053,
+ 0x2055, 0x205e,
+ 0x2190, 0x245f,
+ 0x2500, 0x2775,
+ 0x2794, 0x2bff,
+ 0x2e00, 0x2e7f,
+ 0x3001, 0x3003,
+ 0x3008, 0x3020,
+ 0x3030, 0x3030,
+ 0xfd3e, 0xfd3f,
+ 0xfe45, 0xfe46,
+}; /* CR_Pattern_Syntax */
+
+/* 'Prepended_Concatenation_Mark': Binary Property */
+static const OnigCodePoint CR_Prepended_Concatenation_Mark[] = {
+ 7,
+ 0x0600, 0x0605,
+ 0x06dd, 0x06dd,
+ 0x070f, 0x070f,
+ 0x0890, 0x0891,
+ 0x08e2, 0x08e2,
+ 0x110bd, 0x110bd,
+ 0x110cd, 0x110cd,
+}; /* CR_Prepended_Concatenation_Mark */
+
+/* 'Regional_Indicator': Binary Property */
+static const OnigCodePoint CR_Regional_Indicator[] = {
+ 1,
+ 0x1f1e6, 0x1f1ff,
+}; /* CR_Regional_Indicator */
+
+/* 'Modifier_Combining_Mark': Binary Property */
+static const OnigCodePoint CR_Modifier_Combining_Mark[] = {
+ 9,
+ 0x0654, 0x0655,
+ 0x0658, 0x0658,
+ 0x06dc, 0x06dc,
+ 0x06e3, 0x06e3,
+ 0x06e7, 0x06e8,
+ 0x08ca, 0x08cb,
+ 0x08cd, 0x08cf,
+ 0x08d3, 0x08d3,
+ 0x08f3, 0x08f3,
+}; /* CR_Modifier_Combining_Mark */
+
+/* 'Emoji': Emoji */
+static const OnigCodePoint CR_Emoji[] = {
+ 151,
+ 0x0023, 0x0023,
+ 0x002a, 0x002a,
+ 0x0030, 0x0039,
+ 0x00a9, 0x00a9,
+ 0x00ae, 0x00ae,
+ 0x203c, 0x203c,
+ 0x2049, 0x2049,
+ 0x2122, 0x2122,
+ 0x2139, 0x2139,
+ 0x2194, 0x2199,
+ 0x21a9, 0x21aa,
+ 0x231a, 0x231b,
+ 0x2328, 0x2328,
+ 0x23cf, 0x23cf,
+ 0x23e9, 0x23f3,
+ 0x23f8, 0x23fa,
+ 0x24c2, 0x24c2,
+ 0x25aa, 0x25ab,
+ 0x25b6, 0x25b6,
+ 0x25c0, 0x25c0,
+ 0x25fb, 0x25fe,
+ 0x2600, 0x2604,
+ 0x260e, 0x260e,
+ 0x2611, 0x2611,
+ 0x2614, 0x2615,
+ 0x2618, 0x2618,
+ 0x261d, 0x261d,
+ 0x2620, 0x2620,
+ 0x2622, 0x2623,
+ 0x2626, 0x2626,
+ 0x262a, 0x262a,
+ 0x262e, 0x262f,
+ 0x2638, 0x263a,
+ 0x2640, 0x2640,
+ 0x2642, 0x2642,
+ 0x2648, 0x2653,
+ 0x265f, 0x2660,
+ 0x2663, 0x2663,
+ 0x2665, 0x2666,
+ 0x2668, 0x2668,
+ 0x267b, 0x267b,
+ 0x267e, 0x267f,
+ 0x2692, 0x2697,
+ 0x2699, 0x2699,
+ 0x269b, 0x269c,
+ 0x26a0, 0x26a1,
+ 0x26a7, 0x26a7,
+ 0x26aa, 0x26ab,
+ 0x26b0, 0x26b1,
+ 0x26bd, 0x26be,
+ 0x26c4, 0x26c5,
+ 0x26c8, 0x26c8,
+ 0x26ce, 0x26cf,
+ 0x26d1, 0x26d1,
+ 0x26d3, 0x26d4,
+ 0x26e9, 0x26ea,
+ 0x26f0, 0x26f5,
+ 0x26f7, 0x26fa,
+ 0x26fd, 0x26fd,
+ 0x2702, 0x2702,
+ 0x2705, 0x2705,
+ 0x2708, 0x270d,
+ 0x270f, 0x270f,
+ 0x2712, 0x2712,
+ 0x2714, 0x2714,
+ 0x2716, 0x2716,
+ 0x271d, 0x271d,
+ 0x2721, 0x2721,
+ 0x2728, 0x2728,
+ 0x2733, 0x2734,
+ 0x2744, 0x2744,
+ 0x2747, 0x2747,
+ 0x274c, 0x274c,
+ 0x274e, 0x274e,
+ 0x2753, 0x2755,
+ 0x2757, 0x2757,
+ 0x2763, 0x2764,
+ 0x2795, 0x2797,
+ 0x27a1, 0x27a1,
+ 0x27b0, 0x27b0,
+ 0x27bf, 0x27bf,
+ 0x2934, 0x2935,
+ 0x2b05, 0x2b07,
+ 0x2b1b, 0x2b1c,
+ 0x2b50, 0x2b50,
+ 0x2b55, 0x2b55,
+ 0x3030, 0x3030,
+ 0x303d, 0x303d,
+ 0x3297, 0x3297,
+ 0x3299, 0x3299,
+ 0x1f004, 0x1f004,
+ 0x1f0cf, 0x1f0cf,
+ 0x1f170, 0x1f171,
+ 0x1f17e, 0x1f17f,
+ 0x1f18e, 0x1f18e,
+ 0x1f191, 0x1f19a,
+ 0x1f1e6, 0x1f1ff,
+ 0x1f201, 0x1f202,
+ 0x1f21a, 0x1f21a,
+ 0x1f22f, 0x1f22f,
+ 0x1f232, 0x1f23a,
+ 0x1f250, 0x1f251,
+ 0x1f300, 0x1f321,
+ 0x1f324, 0x1f393,
+ 0x1f396, 0x1f397,
+ 0x1f399, 0x1f39b,
+ 0x1f39e, 0x1f3f0,
+ 0x1f3f3, 0x1f3f5,
+ 0x1f3f7, 0x1f4fd,
+ 0x1f4ff, 0x1f53d,
+ 0x1f549, 0x1f54e,
+ 0x1f550, 0x1f567,
+ 0x1f56f, 0x1f570,
+ 0x1f573, 0x1f57a,
+ 0x1f587, 0x1f587,
+ 0x1f58a, 0x1f58d,
+ 0x1f590, 0x1f590,
+ 0x1f595, 0x1f596,
+ 0x1f5a4, 0x1f5a5,
+ 0x1f5a8, 0x1f5a8,
+ 0x1f5b1, 0x1f5b2,
+ 0x1f5bc, 0x1f5bc,
+ 0x1f5c2, 0x1f5c4,
+ 0x1f5d1, 0x1f5d3,
+ 0x1f5dc, 0x1f5de,
+ 0x1f5e1, 0x1f5e1,
+ 0x1f5e3, 0x1f5e3,
+ 0x1f5e8, 0x1f5e8,
+ 0x1f5ef, 0x1f5ef,
+ 0x1f5f3, 0x1f5f3,
+ 0x1f5fa, 0x1f64f,
+ 0x1f680, 0x1f6c5,
+ 0x1f6cb, 0x1f6d2,
+ 0x1f6d5, 0x1f6d8,
+ 0x1f6dc, 0x1f6e5,
+ 0x1f6e9, 0x1f6e9,
+ 0x1f6eb, 0x1f6ec,
+ 0x1f6f0, 0x1f6f0,
+ 0x1f6f3, 0x1f6fc,
+ 0x1f7e0, 0x1f7eb,
+ 0x1f7f0, 0x1f7f0,
+ 0x1f90c, 0x1f93a,
+ 0x1f93c, 0x1f945,
+ 0x1f947, 0x1f9ff,
+ 0x1fa70, 0x1fa7c,
+ 0x1fa80, 0x1fa8a,
+ 0x1fa8e, 0x1fac6,
+ 0x1fac8, 0x1fac8,
+ 0x1facd, 0x1fadc,
+ 0x1fadf, 0x1faea,
+ 0x1faef, 0x1faf8,
+}; /* CR_Emoji */
+
+/* 'Emoji_Presentation': Emoji */
+static const OnigCodePoint CR_Emoji_Presentation[] = {
+ 81,
+ 0x231a, 0x231b,
+ 0x23e9, 0x23ec,
+ 0x23f0, 0x23f0,
+ 0x23f3, 0x23f3,
+ 0x25fd, 0x25fe,
+ 0x2614, 0x2615,
+ 0x2648, 0x2653,
+ 0x267f, 0x267f,
+ 0x2693, 0x2693,
+ 0x26a1, 0x26a1,
+ 0x26aa, 0x26ab,
+ 0x26bd, 0x26be,
+ 0x26c4, 0x26c5,
+ 0x26ce, 0x26ce,
+ 0x26d4, 0x26d4,
+ 0x26ea, 0x26ea,
+ 0x26f2, 0x26f3,
+ 0x26f5, 0x26f5,
+ 0x26fa, 0x26fa,
+ 0x26fd, 0x26fd,
+ 0x2705, 0x2705,
+ 0x270a, 0x270b,
+ 0x2728, 0x2728,
+ 0x274c, 0x274c,
+ 0x274e, 0x274e,
+ 0x2753, 0x2755,
+ 0x2757, 0x2757,
+ 0x2795, 0x2797,
+ 0x27b0, 0x27b0,
+ 0x27bf, 0x27bf,
+ 0x2b1b, 0x2b1c,
+ 0x2b50, 0x2b50,
+ 0x2b55, 0x2b55,
+ 0x1f004, 0x1f004,
+ 0x1f0cf, 0x1f0cf,
+ 0x1f18e, 0x1f18e,
+ 0x1f191, 0x1f19a,
+ 0x1f1e6, 0x1f1ff,
+ 0x1f201, 0x1f201,
+ 0x1f21a, 0x1f21a,
+ 0x1f22f, 0x1f22f,
+ 0x1f232, 0x1f236,
+ 0x1f238, 0x1f23a,
+ 0x1f250, 0x1f251,
+ 0x1f300, 0x1f320,
+ 0x1f32d, 0x1f335,
+ 0x1f337, 0x1f37c,
+ 0x1f37e, 0x1f393,
+ 0x1f3a0, 0x1f3ca,
+ 0x1f3cf, 0x1f3d3,
+ 0x1f3e0, 0x1f3f0,
+ 0x1f3f4, 0x1f3f4,
+ 0x1f3f8, 0x1f43e,
+ 0x1f440, 0x1f440,
+ 0x1f442, 0x1f4fc,
+ 0x1f4ff, 0x1f53d,
+ 0x1f54b, 0x1f54e,
+ 0x1f550, 0x1f567,
+ 0x1f57a, 0x1f57a,
+ 0x1f595, 0x1f596,
+ 0x1f5a4, 0x1f5a4,
+ 0x1f5fb, 0x1f64f,
+ 0x1f680, 0x1f6c5,
+ 0x1f6cc, 0x1f6cc,
+ 0x1f6d0, 0x1f6d2,
+ 0x1f6d5, 0x1f6d8,
+ 0x1f6dc, 0x1f6df,
+ 0x1f6eb, 0x1f6ec,
+ 0x1f6f4, 0x1f6fc,
+ 0x1f7e0, 0x1f7eb,
+ 0x1f7f0, 0x1f7f0,
+ 0x1f90c, 0x1f93a,
+ 0x1f93c, 0x1f945,
+ 0x1f947, 0x1f9ff,
+ 0x1fa70, 0x1fa7c,
+ 0x1fa80, 0x1fa8a,
+ 0x1fa8e, 0x1fac6,
+ 0x1fac8, 0x1fac8,
+ 0x1facd, 0x1fadc,
+ 0x1fadf, 0x1faea,
+ 0x1faef, 0x1faf8,
+}; /* CR_Emoji_Presentation */
+
+/* 'Emoji_Modifier': Emoji */
+static const OnigCodePoint CR_Emoji_Modifier[] = {
+ 1,
+ 0x1f3fb, 0x1f3ff,
+}; /* CR_Emoji_Modifier */
+
+/* 'Emoji_Modifier_Base': Emoji */
+static const OnigCodePoint CR_Emoji_Modifier_Base[] = {
+ 40,
+ 0x261d, 0x261d,
+ 0x26f9, 0x26f9,
+ 0x270a, 0x270d,
+ 0x1f385, 0x1f385,
+ 0x1f3c2, 0x1f3c4,
+ 0x1f3c7, 0x1f3c7,
+ 0x1f3ca, 0x1f3cc,
+ 0x1f442, 0x1f443,
+ 0x1f446, 0x1f450,
+ 0x1f466, 0x1f478,
+ 0x1f47c, 0x1f47c,
+ 0x1f481, 0x1f483,
+ 0x1f485, 0x1f487,
+ 0x1f48f, 0x1f48f,
+ 0x1f491, 0x1f491,
+ 0x1f4aa, 0x1f4aa,
+ 0x1f574, 0x1f575,
+ 0x1f57a, 0x1f57a,
+ 0x1f590, 0x1f590,
+ 0x1f595, 0x1f596,
+ 0x1f645, 0x1f647,
+ 0x1f64b, 0x1f64f,
+ 0x1f6a3, 0x1f6a3,
+ 0x1f6b4, 0x1f6b6,
+ 0x1f6c0, 0x1f6c0,
+ 0x1f6cc, 0x1f6cc,
+ 0x1f90c, 0x1f90c,
+ 0x1f90f, 0x1f90f,
+ 0x1f918, 0x1f91f,
+ 0x1f926, 0x1f926,
+ 0x1f930, 0x1f939,
+ 0x1f93c, 0x1f93e,
+ 0x1f977, 0x1f977,
+ 0x1f9b5, 0x1f9b6,
+ 0x1f9b8, 0x1f9b9,
+ 0x1f9bb, 0x1f9bb,
+ 0x1f9cd, 0x1f9cf,
+ 0x1f9d1, 0x1f9dd,
+ 0x1fac3, 0x1fac5,
+ 0x1faf0, 0x1faf8,
+}; /* CR_Emoji_Modifier_Base */
+
+/* 'Emoji_Component': Emoji */
+static const OnigCodePoint CR_Emoji_Component[] = {
+ 10,
+ 0x0023, 0x0023,
+ 0x002a, 0x002a,
+ 0x0030, 0x0039,
+ 0x200d, 0x200d,
+ 0x20e3, 0x20e3,
+ 0xfe0f, 0xfe0f,
+ 0x1f1e6, 0x1f1ff,
+ 0x1f3fb, 0x1f3ff,
+ 0x1f9b0, 0x1f9b3,
+ 0xe0020, 0xe007f,
+}; /* CR_Emoji_Component */
+
+/* 'Extended_Pictographic': Emoji */
+static const OnigCodePoint CR_Extended_Pictographic[] = {
+ 156,
+ 0x00a9, 0x00a9,
+ 0x00ae, 0x00ae,
+ 0x203c, 0x203c,
+ 0x2049, 0x2049,
+ 0x2122, 0x2122,
+ 0x2139, 0x2139,
+ 0x2194, 0x2199,
+ 0x21a9, 0x21aa,
+ 0x231a, 0x231b,
+ 0x2328, 0x2328,
+ 0x23cf, 0x23cf,
+ 0x23e9, 0x23f3,
+ 0x23f8, 0x23fa,
+ 0x24c2, 0x24c2,
+ 0x25aa, 0x25ab,
+ 0x25b6, 0x25b6,
+ 0x25c0, 0x25c0,
+ 0x25fb, 0x25fe,
+ 0x2600, 0x2604,
+ 0x260e, 0x260e,
+ 0x2611, 0x2611,
+ 0x2614, 0x2615,
+ 0x2618, 0x2618,
+ 0x261d, 0x261d,
+ 0x2620, 0x2620,
+ 0x2622, 0x2623,
+ 0x2626, 0x2626,
+ 0x262a, 0x262a,
+ 0x262e, 0x262f,
+ 0x2638, 0x263a,
+ 0x2640, 0x2640,
+ 0x2642, 0x2642,
+ 0x2648, 0x2653,
+ 0x265f, 0x2660,
+ 0x2663, 0x2663,
+ 0x2665, 0x2666,
+ 0x2668, 0x2668,
+ 0x267b, 0x267b,
+ 0x267e, 0x267f,
+ 0x2692, 0x2697,
+ 0x2699, 0x2699,
+ 0x269b, 0x269c,
+ 0x26a0, 0x26a1,
+ 0x26a7, 0x26a7,
+ 0x26aa, 0x26ab,
+ 0x26b0, 0x26b1,
+ 0x26bd, 0x26be,
+ 0x26c4, 0x26c5,
+ 0x26c8, 0x26c8,
+ 0x26ce, 0x26cf,
+ 0x26d1, 0x26d1,
+ 0x26d3, 0x26d4,
+ 0x26e9, 0x26ea,
+ 0x26f0, 0x26f5,
+ 0x26f7, 0x26fa,
+ 0x26fd, 0x26fd,
+ 0x2702, 0x2702,
+ 0x2705, 0x2705,
+ 0x2708, 0x270d,
+ 0x270f, 0x270f,
+ 0x2712, 0x2712,
+ 0x2714, 0x2714,
+ 0x2716, 0x2716,
+ 0x271d, 0x271d,
+ 0x2721, 0x2721,
+ 0x2728, 0x2728,
+ 0x2733, 0x2734,
+ 0x2744, 0x2744,
+ 0x2747, 0x2747,
+ 0x274c, 0x274c,
+ 0x274e, 0x274e,
+ 0x2753, 0x2755,
+ 0x2757, 0x2757,
+ 0x2763, 0x2764,
+ 0x2795, 0x2797,
+ 0x27a1, 0x27a1,
+ 0x27b0, 0x27b0,
+ 0x27bf, 0x27bf,
+ 0x2934, 0x2935,
+ 0x2b05, 0x2b07,
+ 0x2b1b, 0x2b1c,
+ 0x2b50, 0x2b50,
+ 0x2b55, 0x2b55,
+ 0x3030, 0x3030,
+ 0x303d, 0x303d,
+ 0x3297, 0x3297,
+ 0x3299, 0x3299,
+ 0x1f004, 0x1f004,
+ 0x1f02c, 0x1f02f,
+ 0x1f094, 0x1f09f,
+ 0x1f0af, 0x1f0b0,
+ 0x1f0c0, 0x1f0c0,
+ 0x1f0cf, 0x1f0d0,
+ 0x1f0f6, 0x1f0ff,
+ 0x1f170, 0x1f171,
+ 0x1f17e, 0x1f17f,
+ 0x1f18e, 0x1f18e,
+ 0x1f191, 0x1f19a,
+ 0x1f1ae, 0x1f1e5,
+ 0x1f201, 0x1f20f,
+ 0x1f21a, 0x1f21a,
+ 0x1f22f, 0x1f22f,
+ 0x1f232, 0x1f23a,
+ 0x1f23c, 0x1f23f,
+ 0x1f249, 0x1f25f,
+ 0x1f266, 0x1f321,
+ 0x1f324, 0x1f393,
+ 0x1f396, 0x1f397,
+ 0x1f399, 0x1f39b,
+ 0x1f39e, 0x1f3f0,
+ 0x1f3f3, 0x1f3f5,
+ 0x1f3f7, 0x1f3fa,
+ 0x1f400, 0x1f4fd,
+ 0x1f4ff, 0x1f53d,
+ 0x1f549, 0x1f54e,
+ 0x1f550, 0x1f567,
+ 0x1f56f, 0x1f570,
+ 0x1f573, 0x1f57a,
+ 0x1f587, 0x1f587,
+ 0x1f58a, 0x1f58d,
+ 0x1f590, 0x1f590,
+ 0x1f595, 0x1f596,
+ 0x1f5a4, 0x1f5a5,
+ 0x1f5a8, 0x1f5a8,
+ 0x1f5b1, 0x1f5b2,
+ 0x1f5bc, 0x1f5bc,
+ 0x1f5c2, 0x1f5c4,
+ 0x1f5d1, 0x1f5d3,
+ 0x1f5dc, 0x1f5de,
+ 0x1f5e1, 0x1f5e1,
+ 0x1f5e3, 0x1f5e3,
+ 0x1f5e8, 0x1f5e8,
+ 0x1f5ef, 0x1f5ef,
+ 0x1f5f3, 0x1f5f3,
+ 0x1f5fa, 0x1f64f,
+ 0x1f680, 0x1f6c5,
+ 0x1f6cb, 0x1f6d2,
+ 0x1f6d5, 0x1f6e5,
+ 0x1f6e9, 0x1f6e9,
+ 0x1f6eb, 0x1f6f0,
+ 0x1f6f3, 0x1f6ff,
+ 0x1f7da, 0x1f7ff,
+ 0x1f80c, 0x1f80f,
+ 0x1f848, 0x1f84f,
+ 0x1f85a, 0x1f85f,
+ 0x1f888, 0x1f88f,
+ 0x1f8ae, 0x1f8af,
+ 0x1f8bc, 0x1f8bf,
+ 0x1f8c2, 0x1f8cf,
+ 0x1f8d9, 0x1f8ff,
+ 0x1f90c, 0x1f93a,
+ 0x1f93c, 0x1f945,
+ 0x1f947, 0x1f9ff,
+ 0x1fa58, 0x1fa5f,
+ 0x1fa6e, 0x1faff,
+ 0x1fc00, 0x1fffd,
+}; /* CR_Extended_Pictographic */
+
+/* 'Unknown': Script */
+static const OnigCodePoint CR_Unknown[] = {
+ 733,
+ 0x0378, 0x0379,
+ 0x0380, 0x0383,
+ 0x038b, 0x038b,
+ 0x038d, 0x038d,
+ 0x03a2, 0x03a2,
+ 0x0530, 0x0530,
+ 0x0557, 0x0558,
+ 0x058b, 0x058c,
+ 0x0590, 0x0590,
+ 0x05c8, 0x05cf,
+ 0x05eb, 0x05ee,
+ 0x05f5, 0x05ff,
+ 0x070e, 0x070e,
+ 0x074b, 0x074c,
+ 0x07b2, 0x07bf,
+ 0x07fb, 0x07fc,
+ 0x082e, 0x082f,
+ 0x083f, 0x083f,
+ 0x085c, 0x085d,
+ 0x085f, 0x085f,
+ 0x086b, 0x086f,
+ 0x0892, 0x0896,
+ 0x0984, 0x0984,
+ 0x098d, 0x098e,
+ 0x0991, 0x0992,
+ 0x09a9, 0x09a9,
+ 0x09b1, 0x09b1,
+ 0x09b3, 0x09b5,
+ 0x09ba, 0x09bb,
+ 0x09c5, 0x09c6,
+ 0x09c9, 0x09ca,
+ 0x09cf, 0x09d6,
+ 0x09d8, 0x09db,
+ 0x09de, 0x09de,
+ 0x09e4, 0x09e5,
+ 0x09ff, 0x0a00,
+ 0x0a04, 0x0a04,
+ 0x0a0b, 0x0a0e,
+ 0x0a11, 0x0a12,
+ 0x0a29, 0x0a29,
+ 0x0a31, 0x0a31,
+ 0x0a34, 0x0a34,
+ 0x0a37, 0x0a37,
+ 0x0a3a, 0x0a3b,
+ 0x0a3d, 0x0a3d,
+ 0x0a43, 0x0a46,
+ 0x0a49, 0x0a4a,
+ 0x0a4e, 0x0a50,
+ 0x0a52, 0x0a58,
+ 0x0a5d, 0x0a5d,
+ 0x0a5f, 0x0a65,
+ 0x0a77, 0x0a80,
+ 0x0a84, 0x0a84,
+ 0x0a8e, 0x0a8e,
+ 0x0a92, 0x0a92,
+ 0x0aa9, 0x0aa9,
+ 0x0ab1, 0x0ab1,
+ 0x0ab4, 0x0ab4,
+ 0x0aba, 0x0abb,
+ 0x0ac6, 0x0ac6,
+ 0x0aca, 0x0aca,
+ 0x0ace, 0x0acf,
+ 0x0ad1, 0x0adf,
+ 0x0ae4, 0x0ae5,
+ 0x0af2, 0x0af8,
+ 0x0b00, 0x0b00,
+ 0x0b04, 0x0b04,
+ 0x0b0d, 0x0b0e,
+ 0x0b11, 0x0b12,
+ 0x0b29, 0x0b29,
+ 0x0b31, 0x0b31,
+ 0x0b34, 0x0b34,
+ 0x0b3a, 0x0b3b,
+ 0x0b45, 0x0b46,
+ 0x0b49, 0x0b4a,
+ 0x0b4e, 0x0b54,
+ 0x0b58, 0x0b5b,
+ 0x0b5e, 0x0b5e,
+ 0x0b64, 0x0b65,
+ 0x0b78, 0x0b81,
+ 0x0b84, 0x0b84,
+ 0x0b8b, 0x0b8d,
+ 0x0b91, 0x0b91,
+ 0x0b96, 0x0b98,
+ 0x0b9b, 0x0b9b,
+ 0x0b9d, 0x0b9d,
+ 0x0ba0, 0x0ba2,
+ 0x0ba5, 0x0ba7,
+ 0x0bab, 0x0bad,
+ 0x0bba, 0x0bbd,
+ 0x0bc3, 0x0bc5,
+ 0x0bc9, 0x0bc9,
+ 0x0bce, 0x0bcf,
+ 0x0bd1, 0x0bd6,
+ 0x0bd8, 0x0be5,
+ 0x0bfb, 0x0bff,
+ 0x0c0d, 0x0c0d,
+ 0x0c11, 0x0c11,
+ 0x0c29, 0x0c29,
+ 0x0c3a, 0x0c3b,
+ 0x0c45, 0x0c45,
+ 0x0c49, 0x0c49,
+ 0x0c4e, 0x0c54,
+ 0x0c57, 0x0c57,
+ 0x0c5b, 0x0c5b,
+ 0x0c5e, 0x0c5f,
+ 0x0c64, 0x0c65,
+ 0x0c70, 0x0c76,
+ 0x0c8d, 0x0c8d,
+ 0x0c91, 0x0c91,
+ 0x0ca9, 0x0ca9,
+ 0x0cb4, 0x0cb4,
+ 0x0cba, 0x0cbb,
+ 0x0cc5, 0x0cc5,
+ 0x0cc9, 0x0cc9,
+ 0x0cce, 0x0cd4,
+ 0x0cd7, 0x0cdb,
+ 0x0cdf, 0x0cdf,
+ 0x0ce4, 0x0ce5,
+ 0x0cf0, 0x0cf0,
+ 0x0cf4, 0x0cff,
+ 0x0d0d, 0x0d0d,
+ 0x0d11, 0x0d11,
+ 0x0d45, 0x0d45,
+ 0x0d49, 0x0d49,
+ 0x0d50, 0x0d53,
+ 0x0d64, 0x0d65,
+ 0x0d80, 0x0d80,
+ 0x0d84, 0x0d84,
+ 0x0d97, 0x0d99,
+ 0x0db2, 0x0db2,
+ 0x0dbc, 0x0dbc,
+ 0x0dbe, 0x0dbf,
+ 0x0dc7, 0x0dc9,
+ 0x0dcb, 0x0dce,
+ 0x0dd5, 0x0dd5,
+ 0x0dd7, 0x0dd7,
+ 0x0de0, 0x0de5,
+ 0x0df0, 0x0df1,
+ 0x0df5, 0x0e00,
+ 0x0e3b, 0x0e3e,
+ 0x0e5c, 0x0e80,
+ 0x0e83, 0x0e83,
+ 0x0e85, 0x0e85,
+ 0x0e8b, 0x0e8b,
+ 0x0ea4, 0x0ea4,
+ 0x0ea6, 0x0ea6,
+ 0x0ebe, 0x0ebf,
+ 0x0ec5, 0x0ec5,
+ 0x0ec7, 0x0ec7,
+ 0x0ecf, 0x0ecf,
+ 0x0eda, 0x0edb,
+ 0x0ee0, 0x0eff,
+ 0x0f48, 0x0f48,
+ 0x0f6d, 0x0f70,
+ 0x0f98, 0x0f98,
+ 0x0fbd, 0x0fbd,
+ 0x0fcd, 0x0fcd,
+ 0x0fdb, 0x0fff,
+ 0x10c6, 0x10c6,
+ 0x10c8, 0x10cc,
+ 0x10ce, 0x10cf,
+ 0x1249, 0x1249,
+ 0x124e, 0x124f,
+ 0x1257, 0x1257,
+ 0x1259, 0x1259,
+ 0x125e, 0x125f,
+ 0x1289, 0x1289,
+ 0x128e, 0x128f,
+ 0x12b1, 0x12b1,
+ 0x12b6, 0x12b7,
+ 0x12bf, 0x12bf,
+ 0x12c1, 0x12c1,
+ 0x12c6, 0x12c7,
+ 0x12d7, 0x12d7,
+ 0x1311, 0x1311,
+ 0x1316, 0x1317,
+ 0x135b, 0x135c,
+ 0x137d, 0x137f,
+ 0x139a, 0x139f,
+ 0x13f6, 0x13f7,
+ 0x13fe, 0x13ff,
+ 0x169d, 0x169f,
+ 0x16f9, 0x16ff,
+ 0x1716, 0x171e,
+ 0x1737, 0x173f,
+ 0x1754, 0x175f,
+ 0x176d, 0x176d,
+ 0x1771, 0x1771,
+ 0x1774, 0x177f,
+ 0x17de, 0x17df,
+ 0x17ea, 0x17ef,
+ 0x17fa, 0x17ff,
+ 0x181a, 0x181f,
+ 0x1879, 0x187f,
+ 0x18ab, 0x18af,
+ 0x18f6, 0x18ff,
+ 0x191f, 0x191f,
+ 0x192c, 0x192f,
+ 0x193c, 0x193f,
+ 0x1941, 0x1943,
+ 0x196e, 0x196f,
+ 0x1975, 0x197f,
+ 0x19ac, 0x19af,
+ 0x19ca, 0x19cf,
+ 0x19db, 0x19dd,
+ 0x1a1c, 0x1a1d,
+ 0x1a5f, 0x1a5f,
+ 0x1a7d, 0x1a7e,
+ 0x1a8a, 0x1a8f,
+ 0x1a9a, 0x1a9f,
+ 0x1aae, 0x1aaf,
+ 0x1ade, 0x1adf,
+ 0x1aec, 0x1aff,
+ 0x1b4d, 0x1b4d,
+ 0x1bf4, 0x1bfb,
+ 0x1c38, 0x1c3a,
+ 0x1c4a, 0x1c4c,
+ 0x1c8b, 0x1c8f,
+ 0x1cbb, 0x1cbc,
+ 0x1cc8, 0x1ccf,
+ 0x1cfb, 0x1cff,
+ 0x1f16, 0x1f17,
+ 0x1f1e, 0x1f1f,
+ 0x1f46, 0x1f47,
+ 0x1f4e, 0x1f4f,
+ 0x1f58, 0x1f58,
+ 0x1f5a, 0x1f5a,
+ 0x1f5c, 0x1f5c,
+ 0x1f5e, 0x1f5e,
+ 0x1f7e, 0x1f7f,
+ 0x1fb5, 0x1fb5,
+ 0x1fc5, 0x1fc5,
+ 0x1fd4, 0x1fd5,
+ 0x1fdc, 0x1fdc,
+ 0x1ff0, 0x1ff1,
+ 0x1ff5, 0x1ff5,
+ 0x1fff, 0x1fff,
+ 0x2065, 0x2065,
+ 0x2072, 0x2073,
+ 0x208f, 0x208f,
+ 0x209d, 0x209f,
+ 0x20c2, 0x20cf,
+ 0x20f1, 0x20ff,
+ 0x218c, 0x218f,
+ 0x242a, 0x243f,
+ 0x244b, 0x245f,
+ 0x2b74, 0x2b75,
+ 0x2cf4, 0x2cf8,
+ 0x2d26, 0x2d26,
+ 0x2d28, 0x2d2c,
+ 0x2d2e, 0x2d2f,
+ 0x2d68, 0x2d6e,
+ 0x2d71, 0x2d7e,
+ 0x2d97, 0x2d9f,
+ 0x2da7, 0x2da7,
+ 0x2daf, 0x2daf,
+ 0x2db7, 0x2db7,
+ 0x2dbf, 0x2dbf,
+ 0x2dc7, 0x2dc7,
+ 0x2dcf, 0x2dcf,
+ 0x2dd7, 0x2dd7,
+ 0x2ddf, 0x2ddf,
+ 0x2e5e, 0x2e7f,
+ 0x2e9a, 0x2e9a,
+ 0x2ef4, 0x2eff,
+ 0x2fd6, 0x2fef,
+ 0x3040, 0x3040,
+ 0x3097, 0x3098,
+ 0x3100, 0x3104,
+ 0x3130, 0x3130,
+ 0x318f, 0x318f,
+ 0x31e6, 0x31ee,
+ 0x321f, 0x321f,
+ 0xa48d, 0xa48f,
+ 0xa4c7, 0xa4cf,
+ 0xa62c, 0xa63f,
+ 0xa6f8, 0xa6ff,
+ 0xa7dd, 0xa7f0,
+ 0xa82d, 0xa82f,
+ 0xa83a, 0xa83f,
+ 0xa878, 0xa87f,
+ 0xa8c6, 0xa8cd,
+ 0xa8da, 0xa8df,
+ 0xa954, 0xa95e,
+ 0xa97d, 0xa97f,
+ 0xa9ce, 0xa9ce,
+ 0xa9da, 0xa9dd,
+ 0xa9ff, 0xa9ff,
+ 0xaa37, 0xaa3f,
+ 0xaa4e, 0xaa4f,
+ 0xaa5a, 0xaa5b,
+ 0xaac3, 0xaada,
+ 0xaaf7, 0xab00,
+ 0xab07, 0xab08,
+ 0xab0f, 0xab10,
+ 0xab17, 0xab1f,
+ 0xab27, 0xab27,
+ 0xab2f, 0xab2f,
+ 0xab6c, 0xab6f,
+ 0xabee, 0xabef,
+ 0xabfa, 0xabff,
+ 0xd7a4, 0xd7af,
+ 0xd7c7, 0xd7ca,
+ 0xd7fc, 0xf8ff,
+ 0xfa6e, 0xfa6f,
+ 0xfada, 0xfaff,
+ 0xfb07, 0xfb12,
+ 0xfb18, 0xfb1c,
+ 0xfb37, 0xfb37,
+ 0xfb3d, 0xfb3d,
+ 0xfb3f, 0xfb3f,
+ 0xfb42, 0xfb42,
+ 0xfb45, 0xfb45,
+ 0xfdd0, 0xfdef,
+ 0xfe1a, 0xfe1f,
+ 0xfe53, 0xfe53,
+ 0xfe67, 0xfe67,
+ 0xfe6c, 0xfe6f,
+ 0xfe75, 0xfe75,
+ 0xfefd, 0xfefe,
+ 0xff00, 0xff00,
+ 0xffbf, 0xffc1,
+ 0xffc8, 0xffc9,
+ 0xffd0, 0xffd1,
+ 0xffd8, 0xffd9,
+ 0xffdd, 0xffdf,
+ 0xffe7, 0xffe7,
+ 0xffef, 0xfff8,
+ 0xfffe, 0xffff,
+ 0x1000c, 0x1000c,
+ 0x10027, 0x10027,
+ 0x1003b, 0x1003b,
+ 0x1003e, 0x1003e,
+ 0x1004e, 0x1004f,
+ 0x1005e, 0x1007f,
+ 0x100fb, 0x100ff,
+ 0x10103, 0x10106,
+ 0x10134, 0x10136,
+ 0x1018f, 0x1018f,
+ 0x1019d, 0x1019f,
+ 0x101a1, 0x101cf,
+ 0x101fe, 0x1027f,
+ 0x1029d, 0x1029f,
+ 0x102d1, 0x102df,
+ 0x102fc, 0x102ff,
+ 0x10324, 0x1032c,
+ 0x1034b, 0x1034f,
+ 0x1037b, 0x1037f,
+ 0x1039e, 0x1039e,
+ 0x103c4, 0x103c7,
+ 0x103d6, 0x103ff,
+ 0x1049e, 0x1049f,
+ 0x104aa, 0x104af,
+ 0x104d4, 0x104d7,
+ 0x104fc, 0x104ff,
+ 0x10528, 0x1052f,
+ 0x10564, 0x1056e,
+ 0x1057b, 0x1057b,
+ 0x1058b, 0x1058b,
+ 0x10593, 0x10593,
+ 0x10596, 0x10596,
+ 0x105a2, 0x105a2,
+ 0x105b2, 0x105b2,
+ 0x105ba, 0x105ba,
+ 0x105bd, 0x105bf,
+ 0x105f4, 0x105ff,
+ 0x10737, 0x1073f,
+ 0x10756, 0x1075f,
+ 0x10768, 0x1077f,
+ 0x10786, 0x10786,
+ 0x107b1, 0x107b1,
+ 0x107bb, 0x107ff,
+ 0x10806, 0x10807,
+ 0x10809, 0x10809,
+ 0x10836, 0x10836,
+ 0x10839, 0x1083b,
+ 0x1083d, 0x1083e,
+ 0x10856, 0x10856,
+ 0x1089f, 0x108a6,
+ 0x108b0, 0x108df,
+ 0x108f3, 0x108f3,
+ 0x108f6, 0x108fa,
+ 0x1091c, 0x1091e,
+ 0x1093a, 0x1093e,
+ 0x1095a, 0x1097f,
+ 0x109b8, 0x109bb,
+ 0x109d0, 0x109d1,
+ 0x10a04, 0x10a04,
+ 0x10a07, 0x10a0b,
+ 0x10a14, 0x10a14,
+ 0x10a18, 0x10a18,
+ 0x10a36, 0x10a37,
+ 0x10a3b, 0x10a3e,
+ 0x10a49, 0x10a4f,
+ 0x10a59, 0x10a5f,
+ 0x10aa0, 0x10abf,
+ 0x10ae7, 0x10aea,
+ 0x10af7, 0x10aff,
+ 0x10b36, 0x10b38,
+ 0x10b56, 0x10b57,
+ 0x10b73, 0x10b77,
+ 0x10b92, 0x10b98,
+ 0x10b9d, 0x10ba8,
+ 0x10bb0, 0x10bff,
+ 0x10c49, 0x10c7f,
+ 0x10cb3, 0x10cbf,
+ 0x10cf3, 0x10cf9,
+ 0x10d28, 0x10d2f,
+ 0x10d3a, 0x10d3f,
+ 0x10d66, 0x10d68,
+ 0x10d86, 0x10d8d,
+ 0x10d90, 0x10e5f,
+ 0x10e7f, 0x10e7f,
+ 0x10eaa, 0x10eaa,
+ 0x10eae, 0x10eaf,
+ 0x10eb2, 0x10ec1,
+ 0x10ec8, 0x10ecf,
+ 0x10ed9, 0x10ef9,
+ 0x10f28, 0x10f2f,
+ 0x10f5a, 0x10f6f,
+ 0x10f8a, 0x10faf,
+ 0x10fcc, 0x10fdf,
+ 0x10ff7, 0x10fff,
+ 0x1104e, 0x11051,
+ 0x11076, 0x1107e,
+ 0x110c3, 0x110cc,
+ 0x110ce, 0x110cf,
+ 0x110e9, 0x110ef,
+ 0x110fa, 0x110ff,
+ 0x11135, 0x11135,
+ 0x11148, 0x1114f,
+ 0x11177, 0x1117f,
+ 0x111e0, 0x111e0,
+ 0x111f5, 0x111ff,
+ 0x11212, 0x11212,
+ 0x11242, 0x1127f,
+ 0x11287, 0x11287,
+ 0x11289, 0x11289,
+ 0x1128e, 0x1128e,
+ 0x1129e, 0x1129e,
+ 0x112aa, 0x112af,
+ 0x112eb, 0x112ef,
+ 0x112fa, 0x112ff,
+ 0x11304, 0x11304,
+ 0x1130d, 0x1130e,
+ 0x11311, 0x11312,
+ 0x11329, 0x11329,
+ 0x11331, 0x11331,
+ 0x11334, 0x11334,
+ 0x1133a, 0x1133a,
+ 0x11345, 0x11346,
+ 0x11349, 0x1134a,
+ 0x1134e, 0x1134f,
+ 0x11351, 0x11356,
+ 0x11358, 0x1135c,
+ 0x11364, 0x11365,
+ 0x1136d, 0x1136f,
+ 0x11375, 0x1137f,
+ 0x1138a, 0x1138a,
+ 0x1138c, 0x1138d,
+ 0x1138f, 0x1138f,
+ 0x113b6, 0x113b6,
+ 0x113c1, 0x113c1,
+ 0x113c3, 0x113c4,
+ 0x113c6, 0x113c6,
+ 0x113cb, 0x113cb,
+ 0x113d6, 0x113d6,
+ 0x113d9, 0x113e0,
+ 0x113e3, 0x113ff,
+ 0x1145c, 0x1145c,
+ 0x11462, 0x1147f,
+ 0x114c8, 0x114cf,
+ 0x114da, 0x1157f,
+ 0x115b6, 0x115b7,
+ 0x115de, 0x115ff,
+ 0x11645, 0x1164f,
+ 0x1165a, 0x1165f,
+ 0x1166d, 0x1167f,
+ 0x116ba, 0x116bf,
+ 0x116ca, 0x116cf,
+ 0x116e4, 0x116ff,
+ 0x1171b, 0x1171c,
+ 0x1172c, 0x1172f,
+ 0x11747, 0x117ff,
+ 0x1183c, 0x1189f,
+ 0x118f3, 0x118fe,
+ 0x11907, 0x11908,
+ 0x1190a, 0x1190b,
+ 0x11914, 0x11914,
+ 0x11917, 0x11917,
+ 0x11936, 0x11936,
+ 0x11939, 0x1193a,
+ 0x11947, 0x1194f,
+ 0x1195a, 0x1199f,
+ 0x119a8, 0x119a9,
+ 0x119d8, 0x119d9,
+ 0x119e5, 0x119ff,
+ 0x11a48, 0x11a4f,
+ 0x11aa3, 0x11aaf,
+ 0x11af9, 0x11aff,
+ 0x11b0a, 0x11b5f,
+ 0x11b68, 0x11bbf,
+ 0x11be2, 0x11bef,
+ 0x11bfa, 0x11bff,
+ 0x11c09, 0x11c09,
+ 0x11c37, 0x11c37,
+ 0x11c46, 0x11c4f,
+ 0x11c6d, 0x11c6f,
+ 0x11c90, 0x11c91,
+ 0x11ca8, 0x11ca8,
+ 0x11cb7, 0x11cff,
+ 0x11d07, 0x11d07,
+ 0x11d0a, 0x11d0a,
+ 0x11d37, 0x11d39,
+ 0x11d3b, 0x11d3b,
+ 0x11d3e, 0x11d3e,
+ 0x11d48, 0x11d4f,
+ 0x11d5a, 0x11d5f,
+ 0x11d66, 0x11d66,
+ 0x11d69, 0x11d69,
+ 0x11d8f, 0x11d8f,
+ 0x11d92, 0x11d92,
+ 0x11d99, 0x11d9f,
+ 0x11daa, 0x11daf,
+ 0x11ddc, 0x11ddf,
+ 0x11dea, 0x11edf,
+ 0x11ef9, 0x11eff,
+ 0x11f11, 0x11f11,
+ 0x11f3b, 0x11f3d,
+ 0x11f5b, 0x11faf,
+ 0x11fb1, 0x11fbf,
+ 0x11ff2, 0x11ffe,
+ 0x1239a, 0x123ff,
+ 0x1246f, 0x1246f,
+ 0x12475, 0x1247f,
+ 0x12544, 0x12f8f,
+ 0x12ff3, 0x12fff,
+ 0x13456, 0x1345f,
+ 0x143fb, 0x143ff,
+ 0x14647, 0x160ff,
+ 0x1613a, 0x167ff,
+ 0x16a39, 0x16a3f,
+ 0x16a5f, 0x16a5f,
+ 0x16a6a, 0x16a6d,
+ 0x16abf, 0x16abf,
+ 0x16aca, 0x16acf,
+ 0x16aee, 0x16aef,
+ 0x16af6, 0x16aff,
+ 0x16b46, 0x16b4f,
+ 0x16b5a, 0x16b5a,
+ 0x16b62, 0x16b62,
+ 0x16b78, 0x16b7c,
+ 0x16b90, 0x16d3f,
+ 0x16d7a, 0x16e3f,
+ 0x16e9b, 0x16e9f,
+ 0x16eb9, 0x16eba,
+ 0x16ed4, 0x16eff,
+ 0x16f4b, 0x16f4e,
+ 0x16f88, 0x16f8e,
+ 0x16fa0, 0x16fdf,
+ 0x16fe5, 0x16fef,
+ 0x16ff7, 0x16fff,
+ 0x18cd6, 0x18cfe,
+ 0x18d1f, 0x18d7f,
+ 0x18df3, 0x1afef,
+ 0x1aff4, 0x1aff4,
+ 0x1affc, 0x1affc,
+ 0x1afff, 0x1afff,
+ 0x1b123, 0x1b131,
+ 0x1b133, 0x1b14f,
+ 0x1b153, 0x1b154,
+ 0x1b156, 0x1b163,
+ 0x1b168, 0x1b16f,
+ 0x1b2fc, 0x1bbff,
+ 0x1bc6b, 0x1bc6f,
+ 0x1bc7d, 0x1bc7f,
+ 0x1bc89, 0x1bc8f,
+ 0x1bc9a, 0x1bc9b,
+ 0x1bca4, 0x1cbff,
+ 0x1ccfd, 0x1ccff,
+ 0x1ceb4, 0x1ceb9,
+ 0x1ced1, 0x1cedf,
+ 0x1cef1, 0x1ceff,
+ 0x1cf2e, 0x1cf2f,
+ 0x1cf47, 0x1cf4f,
+ 0x1cfc4, 0x1cfff,
+ 0x1d0f6, 0x1d0ff,
+ 0x1d127, 0x1d128,
+ 0x1d1eb, 0x1d1ff,
+ 0x1d246, 0x1d2bf,
+ 0x1d2d4, 0x1d2df,
+ 0x1d2f4, 0x1d2ff,
+ 0x1d357, 0x1d35f,
+ 0x1d379, 0x1d3ff,
+ 0x1d455, 0x1d455,
+ 0x1d49d, 0x1d49d,
+ 0x1d4a0, 0x1d4a1,
+ 0x1d4a3, 0x1d4a4,
+ 0x1d4a7, 0x1d4a8,
+ 0x1d4ad, 0x1d4ad,
+ 0x1d4ba, 0x1d4ba,
+ 0x1d4bc, 0x1d4bc,
+ 0x1d4c4, 0x1d4c4,
+ 0x1d506, 0x1d506,
+ 0x1d50b, 0x1d50c,
+ 0x1d515, 0x1d515,
+ 0x1d51d, 0x1d51d,
+ 0x1d53a, 0x1d53a,
+ 0x1d53f, 0x1d53f,
+ 0x1d545, 0x1d545,
+ 0x1d547, 0x1d549,
+ 0x1d551, 0x1d551,
+ 0x1d6a6, 0x1d6a7,
+ 0x1d7cc, 0x1d7cd,
+ 0x1da8c, 0x1da9a,
+ 0x1daa0, 0x1daa0,
+ 0x1dab0, 0x1deff,
+ 0x1df1f, 0x1df24,
+ 0x1df2b, 0x1dfff,
+ 0x1e007, 0x1e007,
+ 0x1e019, 0x1e01a,
+ 0x1e022, 0x1e022,
+ 0x1e025, 0x1e025,
+ 0x1e02b, 0x1e02f,
+ 0x1e06e, 0x1e08e,
+ 0x1e090, 0x1e0ff,
+ 0x1e12d, 0x1e12f,
+ 0x1e13e, 0x1e13f,
+ 0x1e14a, 0x1e14d,
+ 0x1e150, 0x1e28f,
+ 0x1e2af, 0x1e2bf,
+ 0x1e2fa, 0x1e2fe,
+ 0x1e300, 0x1e4cf,
+ 0x1e4fa, 0x1e5cf,
+ 0x1e5fb, 0x1e5fe,
+ 0x1e600, 0x1e6bf,
+ 0x1e6df, 0x1e6df,
+ 0x1e6f6, 0x1e6fd,
+ 0x1e700, 0x1e7df,
+ 0x1e7e7, 0x1e7e7,
+ 0x1e7ec, 0x1e7ec,
+ 0x1e7ef, 0x1e7ef,
+ 0x1e7ff, 0x1e7ff,
+ 0x1e8c5, 0x1e8c6,
+ 0x1e8d7, 0x1e8ff,
+ 0x1e94c, 0x1e94f,
+ 0x1e95a, 0x1e95d,
+ 0x1e960, 0x1ec70,
+ 0x1ecb5, 0x1ed00,
+ 0x1ed3e, 0x1edff,
+ 0x1ee04, 0x1ee04,
+ 0x1ee20, 0x1ee20,
+ 0x1ee23, 0x1ee23,
+ 0x1ee25, 0x1ee26,
+ 0x1ee28, 0x1ee28,
+ 0x1ee33, 0x1ee33,
+ 0x1ee38, 0x1ee38,
+ 0x1ee3a, 0x1ee3a,
+ 0x1ee3c, 0x1ee41,
+ 0x1ee43, 0x1ee46,
+ 0x1ee48, 0x1ee48,
+ 0x1ee4a, 0x1ee4a,
+ 0x1ee4c, 0x1ee4c,
+ 0x1ee50, 0x1ee50,
+ 0x1ee53, 0x1ee53,
+ 0x1ee55, 0x1ee56,
+ 0x1ee58, 0x1ee58,
+ 0x1ee5a, 0x1ee5a,
+ 0x1ee5c, 0x1ee5c,
+ 0x1ee5e, 0x1ee5e,
+ 0x1ee60, 0x1ee60,
+ 0x1ee63, 0x1ee63,
+ 0x1ee65, 0x1ee66,
+ 0x1ee6b, 0x1ee6b,
+ 0x1ee73, 0x1ee73,
+ 0x1ee78, 0x1ee78,
+ 0x1ee7d, 0x1ee7d,
+ 0x1ee7f, 0x1ee7f,
+ 0x1ee8a, 0x1ee8a,
+ 0x1ee9c, 0x1eea0,
+ 0x1eea4, 0x1eea4,
+ 0x1eeaa, 0x1eeaa,
+ 0x1eebc, 0x1eeef,
+ 0x1eef2, 0x1efff,
+ 0x1f02c, 0x1f02f,
+ 0x1f094, 0x1f09f,
+ 0x1f0af, 0x1f0b0,
+ 0x1f0c0, 0x1f0c0,
+ 0x1f0d0, 0x1f0d0,
+ 0x1f0f6, 0x1f0ff,
+ 0x1f1ae, 0x1f1e5,
+ 0x1f203, 0x1f20f,
+ 0x1f23c, 0x1f23f,
+ 0x1f249, 0x1f24f,
+ 0x1f252, 0x1f25f,
+ 0x1f266, 0x1f2ff,
+ 0x1f6d9, 0x1f6db,
+ 0x1f6ed, 0x1f6ef,
+ 0x1f6fd, 0x1f6ff,
+ 0x1f7da, 0x1f7df,
+ 0x1f7ec, 0x1f7ef,
+ 0x1f7f1, 0x1f7ff,
+ 0x1f80c, 0x1f80f,
+ 0x1f848, 0x1f84f,
+ 0x1f85a, 0x1f85f,
+ 0x1f888, 0x1f88f,
+ 0x1f8ae, 0x1f8af,
+ 0x1f8bc, 0x1f8bf,
+ 0x1f8c2, 0x1f8cf,
+ 0x1f8d9, 0x1f8ff,
+ 0x1fa58, 0x1fa5f,
+ 0x1fa6e, 0x1fa6f,
+ 0x1fa7d, 0x1fa7f,
+ 0x1fa8b, 0x1fa8d,
+ 0x1fac7, 0x1fac7,
+ 0x1fac9, 0x1facc,
+ 0x1fadd, 0x1fade,
+ 0x1faeb, 0x1faee,
+ 0x1faf9, 0x1faff,
+ 0x1fb93, 0x1fb93,
+ 0x1fbfb, 0x1ffff,
+ 0x2a6e0, 0x2a6ff,
+ 0x2b81e, 0x2b81f,
+ 0x2ceae, 0x2ceaf,
+ 0x2ebe1, 0x2ebef,
+ 0x2ee5e, 0x2f7ff,
+ 0x2fa1e, 0x2ffff,
+ 0x3134b, 0x3134f,
+ 0x3347a, 0xe0000,
+ 0xe0002, 0xe001f,
+ 0xe0080, 0xe00ff,
+ 0xe01f0, 0x10ffff,
+}; /* CR_Unknown */
+
+#ifdef USE_UNICODE_AGE_PROPERTIES
+/* 'Age_1_1': Derived Age 1.1 */
+static const OnigCodePoint CR_Age_1_1[] = {
+ 288,
+ 0x0000, 0x01f5,
+ 0x01fa, 0x0217,
+ 0x0250, 0x02a8,
+ 0x02b0, 0x02de,
+ 0x02e0, 0x02e9,
+ 0x0300, 0x0345,
+ 0x0360, 0x0361,
+ 0x0374, 0x0375,
+ 0x037a, 0x037a,
+ 0x037e, 0x037e,
+ 0x0384, 0x038a,
+ 0x038c, 0x038c,
+ 0x038e, 0x03a1,
+ 0x03a3, 0x03ce,
+ 0x03d0, 0x03d6,
+ 0x03da, 0x03da,
+ 0x03dc, 0x03dc,
+ 0x03de, 0x03de,
+ 0x03e0, 0x03e0,
+ 0x03e2, 0x03f3,
+ 0x0401, 0x040c,
+ 0x040e, 0x044f,
+ 0x0451, 0x045c,
+ 0x045e, 0x0486,
+ 0x0490, 0x04c4,
+ 0x04c7, 0x04c8,
+ 0x04cb, 0x04cc,
+ 0x04d0, 0x04eb,
+ 0x04ee, 0x04f5,
+ 0x04f8, 0x04f9,
+ 0x0531, 0x0556,
+ 0x0559, 0x055f,
+ 0x0561, 0x0587,
+ 0x0589, 0x0589,
+ 0x05b0, 0x05b9,
+ 0x05bb, 0x05c3,
+ 0x05d0, 0x05ea,
+ 0x05f0, 0x05f4,
+ 0x060c, 0x060c,
+ 0x061b, 0x061b,
+ 0x061f, 0x061f,
+ 0x0621, 0x063a,
+ 0x0640, 0x0652,
+ 0x0660, 0x066d,
+ 0x0670, 0x06b7,
+ 0x06ba, 0x06be,
+ 0x06c0, 0x06ce,
+ 0x06d0, 0x06ed,
+ 0x06f0, 0x06f9,
+ 0x0901, 0x0903,
+ 0x0905, 0x0939,
+ 0x093c, 0x094d,
+ 0x0950, 0x0954,
+ 0x0958, 0x0970,
+ 0x0981, 0x0983,
+ 0x0985, 0x098c,
+ 0x098f, 0x0990,
+ 0x0993, 0x09a8,
+ 0x09aa, 0x09b0,
+ 0x09b2, 0x09b2,
+ 0x09b6, 0x09b9,
+ 0x09bc, 0x09bc,
+ 0x09be, 0x09c4,
+ 0x09c7, 0x09c8,
+ 0x09cb, 0x09cd,
+ 0x09d7, 0x09d7,
+ 0x09dc, 0x09dd,
+ 0x09df, 0x09e3,
+ 0x09e6, 0x09fa,
+ 0x0a02, 0x0a02,
+ 0x0a05, 0x0a0a,
+ 0x0a0f, 0x0a10,
+ 0x0a13, 0x0a28,
+ 0x0a2a, 0x0a30,
+ 0x0a32, 0x0a33,
+ 0x0a35, 0x0a36,
+ 0x0a38, 0x0a39,
+ 0x0a3c, 0x0a3c,
+ 0x0a3e, 0x0a42,
+ 0x0a47, 0x0a48,
+ 0x0a4b, 0x0a4d,
+ 0x0a59, 0x0a5c,
+ 0x0a5e, 0x0a5e,
+ 0x0a66, 0x0a74,
+ 0x0a81, 0x0a83,
+ 0x0a85, 0x0a8b,
+ 0x0a8d, 0x0a8d,
+ 0x0a8f, 0x0a91,
+ 0x0a93, 0x0aa8,
+ 0x0aaa, 0x0ab0,
+ 0x0ab2, 0x0ab3,
+ 0x0ab5, 0x0ab9,
+ 0x0abc, 0x0ac5,
+ 0x0ac7, 0x0ac9,
+ 0x0acb, 0x0acd,
+ 0x0ad0, 0x0ad0,
+ 0x0ae0, 0x0ae0,
+ 0x0ae6, 0x0aef,
+ 0x0b01, 0x0b03,
+ 0x0b05, 0x0b0c,
+ 0x0b0f, 0x0b10,
+ 0x0b13, 0x0b28,
+ 0x0b2a, 0x0b30,
+ 0x0b32, 0x0b33,
+ 0x0b36, 0x0b39,
+ 0x0b3c, 0x0b43,
+ 0x0b47, 0x0b48,
+ 0x0b4b, 0x0b4d,
+ 0x0b56, 0x0b57,
+ 0x0b5c, 0x0b5d,
+ 0x0b5f, 0x0b61,
+ 0x0b66, 0x0b70,
+ 0x0b82, 0x0b83,
+ 0x0b85, 0x0b8a,
+ 0x0b8e, 0x0b90,
+ 0x0b92, 0x0b95,
+ 0x0b99, 0x0b9a,
+ 0x0b9c, 0x0b9c,
+ 0x0b9e, 0x0b9f,
+ 0x0ba3, 0x0ba4,
+ 0x0ba8, 0x0baa,
+ 0x0bae, 0x0bb5,
+ 0x0bb7, 0x0bb9,
+ 0x0bbe, 0x0bc2,
+ 0x0bc6, 0x0bc8,
+ 0x0bca, 0x0bcd,
+ 0x0bd7, 0x0bd7,
+ 0x0be7, 0x0bf2,
+ 0x0c01, 0x0c03,
+ 0x0c05, 0x0c0c,
+ 0x0c0e, 0x0c10,
+ 0x0c12, 0x0c28,
+ 0x0c2a, 0x0c33,
+ 0x0c35, 0x0c39,
+ 0x0c3e, 0x0c44,
+ 0x0c46, 0x0c48,
+ 0x0c4a, 0x0c4d,
+ 0x0c55, 0x0c56,
+ 0x0c60, 0x0c61,
+ 0x0c66, 0x0c6f,
+ 0x0c82, 0x0c83,
+ 0x0c85, 0x0c8c,
+ 0x0c8e, 0x0c90,
+ 0x0c92, 0x0ca8,
+ 0x0caa, 0x0cb3,
+ 0x0cb5, 0x0cb9,
+ 0x0cbe, 0x0cc4,
+ 0x0cc6, 0x0cc8,
+ 0x0cca, 0x0ccd,
+ 0x0cd5, 0x0cd6,
+ 0x0cde, 0x0cde,
+ 0x0ce0, 0x0ce1,
+ 0x0ce6, 0x0cef,
+ 0x0d02, 0x0d03,
+ 0x0d05, 0x0d0c,
+ 0x0d0e, 0x0d10,
+ 0x0d12, 0x0d28,
+ 0x0d2a, 0x0d39,
+ 0x0d3e, 0x0d43,
+ 0x0d46, 0x0d48,
+ 0x0d4a, 0x0d4d,
+ 0x0d57, 0x0d57,
+ 0x0d60, 0x0d61,
+ 0x0d66, 0x0d6f,
+ 0x0e01, 0x0e3a,
+ 0x0e3f, 0x0e5b,
+ 0x0e81, 0x0e82,
+ 0x0e84, 0x0e84,
+ 0x0e87, 0x0e88,
+ 0x0e8a, 0x0e8a,
+ 0x0e8d, 0x0e8d,
+ 0x0e94, 0x0e97,
+ 0x0e99, 0x0e9f,
+ 0x0ea1, 0x0ea3,
+ 0x0ea5, 0x0ea5,
+ 0x0ea7, 0x0ea7,
+ 0x0eaa, 0x0eab,
+ 0x0ead, 0x0eb9,
+ 0x0ebb, 0x0ebd,
+ 0x0ec0, 0x0ec4,
+ 0x0ec6, 0x0ec6,
+ 0x0ec8, 0x0ecd,
+ 0x0ed0, 0x0ed9,
+ 0x0edc, 0x0edd,
+ 0x10a0, 0x10c5,
+ 0x10d0, 0x10f6,
+ 0x10fb, 0x10fb,
+ 0x1100, 0x1159,
+ 0x115f, 0x11a2,
+ 0x11a8, 0x11f9,
+ 0x1e00, 0x1e9a,
+ 0x1ea0, 0x1ef9,
+ 0x1f00, 0x1f15,
+ 0x1f18, 0x1f1d,
+ 0x1f20, 0x1f45,
+ 0x1f48, 0x1f4d,
+ 0x1f50, 0x1f57,
+ 0x1f59, 0x1f59,
+ 0x1f5b, 0x1f5b,
+ 0x1f5d, 0x1f5d,
+ 0x1f5f, 0x1f7d,
+ 0x1f80, 0x1fb4,
+ 0x1fb6, 0x1fc4,
+ 0x1fc6, 0x1fd3,
+ 0x1fd6, 0x1fdb,
+ 0x1fdd, 0x1fef,
+ 0x1ff2, 0x1ff4,
+ 0x1ff6, 0x1ffe,
+ 0x2000, 0x202e,
+ 0x2030, 0x2046,
+ 0x206a, 0x2070,
+ 0x2074, 0x208e,
+ 0x20a0, 0x20aa,
+ 0x20d0, 0x20e1,
+ 0x2100, 0x2138,
+ 0x2153, 0x2182,
+ 0x2190, 0x21ea,
+ 0x2200, 0x22f1,
+ 0x2300, 0x2300,
+ 0x2302, 0x237a,
+ 0x2400, 0x2424,
+ 0x2440, 0x244a,
+ 0x2460, 0x24ea,
+ 0x2500, 0x2595,
+ 0x25a0, 0x25ef,
+ 0x2600, 0x2613,
+ 0x261a, 0x266f,
+ 0x2701, 0x2704,
+ 0x2706, 0x2709,
+ 0x270c, 0x2727,
+ 0x2729, 0x274b,
+ 0x274d, 0x274d,
+ 0x274f, 0x2752,
+ 0x2756, 0x2756,
+ 0x2758, 0x275e,
+ 0x2761, 0x2767,
+ 0x2776, 0x2794,
+ 0x2798, 0x27af,
+ 0x27b1, 0x27be,
+ 0x3000, 0x3037,
+ 0x303f, 0x303f,
+ 0x3041, 0x3094,
+ 0x3099, 0x309e,
+ 0x30a1, 0x30fe,
+ 0x3105, 0x312c,
+ 0x3131, 0x318e,
+ 0x3190, 0x319f,
+ 0x3200, 0x321c,
+ 0x3220, 0x3243,
+ 0x3260, 0x327b,
+ 0x327f, 0x32b0,
+ 0x32c0, 0x32cb,
+ 0x32d0, 0x32fe,
+ 0x3300, 0x3376,
+ 0x337b, 0x33dd,
+ 0x33e0, 0x33fe,
+ 0x4e00, 0x9fa5,
+ 0xe000, 0xfa2d,
+ 0xfb00, 0xfb06,
+ 0xfb13, 0xfb17,
+ 0xfb1e, 0xfb36,
+ 0xfb38, 0xfb3c,
+ 0xfb3e, 0xfb3e,
+ 0xfb40, 0xfb41,
+ 0xfb43, 0xfb44,
+ 0xfb46, 0xfbb1,
+ 0xfbd3, 0xfd3f,
+ 0xfd50, 0xfd8f,
+ 0xfd92, 0xfdc7,
+ 0xfdf0, 0xfdfb,
+ 0xfe20, 0xfe23,
+ 0xfe30, 0xfe44,
+ 0xfe49, 0xfe52,
+ 0xfe54, 0xfe66,
+ 0xfe68, 0xfe6b,
+ 0xfe70, 0xfe72,
+ 0xfe74, 0xfe74,
+ 0xfe76, 0xfefc,
+ 0xfeff, 0xfeff,
+ 0xff01, 0xff5e,
+ 0xff61, 0xffbe,
+ 0xffc2, 0xffc7,
+ 0xffca, 0xffcf,
+ 0xffd2, 0xffd7,
+ 0xffda, 0xffdc,
+ 0xffe0, 0xffe6,
+ 0xffe8, 0xffee,
+ 0xfffd, 0xffff,
+}; /* CR_Age_1_1 */
+
+/* 'Age_2_0': Derived Age 2.0 */
+static const OnigCodePoint CR_Age_2_0[] = {
+ 312,
+ 0x0000, 0x01f5,
+ 0x01fa, 0x0217,
+ 0x0250, 0x02a8,
+ 0x02b0, 0x02de,
+ 0x02e0, 0x02e9,
+ 0x0300, 0x0345,
+ 0x0360, 0x0361,
+ 0x0374, 0x0375,
+ 0x037a, 0x037a,
+ 0x037e, 0x037e,
+ 0x0384, 0x038a,
+ 0x038c, 0x038c,
+ 0x038e, 0x03a1,
+ 0x03a3, 0x03ce,
+ 0x03d0, 0x03d6,
+ 0x03da, 0x03da,
+ 0x03dc, 0x03dc,
+ 0x03de, 0x03de,
+ 0x03e0, 0x03e0,
+ 0x03e2, 0x03f3,
+ 0x0401, 0x040c,
+ 0x040e, 0x044f,
+ 0x0451, 0x045c,
+ 0x045e, 0x0486,
+ 0x0490, 0x04c4,
+ 0x04c7, 0x04c8,
+ 0x04cb, 0x04cc,
+ 0x04d0, 0x04eb,
+ 0x04ee, 0x04f5,
+ 0x04f8, 0x04f9,
+ 0x0531, 0x0556,
+ 0x0559, 0x055f,
+ 0x0561, 0x0587,
+ 0x0589, 0x0589,
+ 0x0591, 0x05a1,
+ 0x05a3, 0x05b9,
+ 0x05bb, 0x05c4,
+ 0x05d0, 0x05ea,
+ 0x05f0, 0x05f4,
+ 0x060c, 0x060c,
+ 0x061b, 0x061b,
+ 0x061f, 0x061f,
+ 0x0621, 0x063a,
+ 0x0640, 0x0652,
+ 0x0660, 0x066d,
+ 0x0670, 0x06b7,
+ 0x06ba, 0x06be,
+ 0x06c0, 0x06ce,
+ 0x06d0, 0x06ed,
+ 0x06f0, 0x06f9,
+ 0x0901, 0x0903,
+ 0x0905, 0x0939,
+ 0x093c, 0x094d,
+ 0x0950, 0x0954,
+ 0x0958, 0x0970,
+ 0x0981, 0x0983,
+ 0x0985, 0x098c,
+ 0x098f, 0x0990,
+ 0x0993, 0x09a8,
+ 0x09aa, 0x09b0,
+ 0x09b2, 0x09b2,
+ 0x09b6, 0x09b9,
+ 0x09bc, 0x09bc,
+ 0x09be, 0x09c4,
+ 0x09c7, 0x09c8,
+ 0x09cb, 0x09cd,
+ 0x09d7, 0x09d7,
+ 0x09dc, 0x09dd,
+ 0x09df, 0x09e3,
+ 0x09e6, 0x09fa,
+ 0x0a02, 0x0a02,
+ 0x0a05, 0x0a0a,
+ 0x0a0f, 0x0a10,
+ 0x0a13, 0x0a28,
+ 0x0a2a, 0x0a30,
+ 0x0a32, 0x0a33,
+ 0x0a35, 0x0a36,
+ 0x0a38, 0x0a39,
+ 0x0a3c, 0x0a3c,
+ 0x0a3e, 0x0a42,
+ 0x0a47, 0x0a48,
+ 0x0a4b, 0x0a4d,
+ 0x0a59, 0x0a5c,
+ 0x0a5e, 0x0a5e,
+ 0x0a66, 0x0a74,
+ 0x0a81, 0x0a83,
+ 0x0a85, 0x0a8b,
+ 0x0a8d, 0x0a8d,
+ 0x0a8f, 0x0a91,
+ 0x0a93, 0x0aa8,
+ 0x0aaa, 0x0ab0,
+ 0x0ab2, 0x0ab3,
+ 0x0ab5, 0x0ab9,
+ 0x0abc, 0x0ac5,
+ 0x0ac7, 0x0ac9,
+ 0x0acb, 0x0acd,
+ 0x0ad0, 0x0ad0,
+ 0x0ae0, 0x0ae0,
+ 0x0ae6, 0x0aef,
+ 0x0b01, 0x0b03,
+ 0x0b05, 0x0b0c,
+ 0x0b0f, 0x0b10,
+ 0x0b13, 0x0b28,
+ 0x0b2a, 0x0b30,
+ 0x0b32, 0x0b33,
+ 0x0b36, 0x0b39,
+ 0x0b3c, 0x0b43,
+ 0x0b47, 0x0b48,
+ 0x0b4b, 0x0b4d,
+ 0x0b56, 0x0b57,
+ 0x0b5c, 0x0b5d,
+ 0x0b5f, 0x0b61,
+ 0x0b66, 0x0b70,
+ 0x0b82, 0x0b83,
+ 0x0b85, 0x0b8a,
+ 0x0b8e, 0x0b90,
+ 0x0b92, 0x0b95,
+ 0x0b99, 0x0b9a,
+ 0x0b9c, 0x0b9c,
+ 0x0b9e, 0x0b9f,
+ 0x0ba3, 0x0ba4,
+ 0x0ba8, 0x0baa,
+ 0x0bae, 0x0bb5,
+ 0x0bb7, 0x0bb9,
+ 0x0bbe, 0x0bc2,
+ 0x0bc6, 0x0bc8,
+ 0x0bca, 0x0bcd,
+ 0x0bd7, 0x0bd7,
+ 0x0be7, 0x0bf2,
+ 0x0c01, 0x0c03,
+ 0x0c05, 0x0c0c,
+ 0x0c0e, 0x0c10,
+ 0x0c12, 0x0c28,
+ 0x0c2a, 0x0c33,
+ 0x0c35, 0x0c39,
+ 0x0c3e, 0x0c44,
+ 0x0c46, 0x0c48,
+ 0x0c4a, 0x0c4d,
+ 0x0c55, 0x0c56,
+ 0x0c60, 0x0c61,
+ 0x0c66, 0x0c6f,
+ 0x0c82, 0x0c83,
+ 0x0c85, 0x0c8c,
+ 0x0c8e, 0x0c90,
+ 0x0c92, 0x0ca8,
+ 0x0caa, 0x0cb3,
+ 0x0cb5, 0x0cb9,
+ 0x0cbe, 0x0cc4,
+ 0x0cc6, 0x0cc8,
+ 0x0cca, 0x0ccd,
+ 0x0cd5, 0x0cd6,
+ 0x0cde, 0x0cde,
+ 0x0ce0, 0x0ce1,
+ 0x0ce6, 0x0cef,
+ 0x0d02, 0x0d03,
+ 0x0d05, 0x0d0c,
+ 0x0d0e, 0x0d10,
+ 0x0d12, 0x0d28,
+ 0x0d2a, 0x0d39,
+ 0x0d3e, 0x0d43,
+ 0x0d46, 0x0d48,
+ 0x0d4a, 0x0d4d,
+ 0x0d57, 0x0d57,
+ 0x0d60, 0x0d61,
+ 0x0d66, 0x0d6f,
+ 0x0e01, 0x0e3a,
+ 0x0e3f, 0x0e5b,
+ 0x0e81, 0x0e82,
+ 0x0e84, 0x0e84,
+ 0x0e87, 0x0e88,
+ 0x0e8a, 0x0e8a,
+ 0x0e8d, 0x0e8d,
+ 0x0e94, 0x0e97,
+ 0x0e99, 0x0e9f,
+ 0x0ea1, 0x0ea3,
+ 0x0ea5, 0x0ea5,
+ 0x0ea7, 0x0ea7,
+ 0x0eaa, 0x0eab,
+ 0x0ead, 0x0eb9,
+ 0x0ebb, 0x0ebd,
+ 0x0ec0, 0x0ec4,
+ 0x0ec6, 0x0ec6,
+ 0x0ec8, 0x0ecd,
+ 0x0ed0, 0x0ed9,
+ 0x0edc, 0x0edd,
+ 0x0f00, 0x0f47,
+ 0x0f49, 0x0f69,
+ 0x0f71, 0x0f8b,
+ 0x0f90, 0x0f95,
+ 0x0f97, 0x0f97,
+ 0x0f99, 0x0fad,
+ 0x0fb1, 0x0fb7,
+ 0x0fb9, 0x0fb9,
+ 0x10a0, 0x10c5,
+ 0x10d0, 0x10f6,
+ 0x10fb, 0x10fb,
+ 0x1100, 0x1159,
+ 0x115f, 0x11a2,
+ 0x11a8, 0x11f9,
+ 0x1e00, 0x1e9b,
+ 0x1ea0, 0x1ef9,
+ 0x1f00, 0x1f15,
+ 0x1f18, 0x1f1d,
+ 0x1f20, 0x1f45,
+ 0x1f48, 0x1f4d,
+ 0x1f50, 0x1f57,
+ 0x1f59, 0x1f59,
+ 0x1f5b, 0x1f5b,
+ 0x1f5d, 0x1f5d,
+ 0x1f5f, 0x1f7d,
+ 0x1f80, 0x1fb4,
+ 0x1fb6, 0x1fc4,
+ 0x1fc6, 0x1fd3,
+ 0x1fd6, 0x1fdb,
+ 0x1fdd, 0x1fef,
+ 0x1ff2, 0x1ff4,
+ 0x1ff6, 0x1ffe,
+ 0x2000, 0x202e,
+ 0x2030, 0x2046,
+ 0x206a, 0x2070,
+ 0x2074, 0x208e,
+ 0x20a0, 0x20ab,
+ 0x20d0, 0x20e1,
+ 0x2100, 0x2138,
+ 0x2153, 0x2182,
+ 0x2190, 0x21ea,
+ 0x2200, 0x22f1,
+ 0x2300, 0x2300,
+ 0x2302, 0x237a,
+ 0x2400, 0x2424,
+ 0x2440, 0x244a,
+ 0x2460, 0x24ea,
+ 0x2500, 0x2595,
+ 0x25a0, 0x25ef,
+ 0x2600, 0x2613,
+ 0x261a, 0x266f,
+ 0x2701, 0x2704,
+ 0x2706, 0x2709,
+ 0x270c, 0x2727,
+ 0x2729, 0x274b,
+ 0x274d, 0x274d,
+ 0x274f, 0x2752,
+ 0x2756, 0x2756,
+ 0x2758, 0x275e,
+ 0x2761, 0x2767,
+ 0x2776, 0x2794,
+ 0x2798, 0x27af,
+ 0x27b1, 0x27be,
+ 0x3000, 0x3037,
+ 0x303f, 0x303f,
+ 0x3041, 0x3094,
+ 0x3099, 0x309e,
+ 0x30a1, 0x30fe,
+ 0x3105, 0x312c,
+ 0x3131, 0x318e,
+ 0x3190, 0x319f,
+ 0x3200, 0x321c,
+ 0x3220, 0x3243,
+ 0x3260, 0x327b,
+ 0x327f, 0x32b0,
+ 0x32c0, 0x32cb,
+ 0x32d0, 0x32fe,
+ 0x3300, 0x3376,
+ 0x337b, 0x33dd,
+ 0x33e0, 0x33fe,
+ 0x4e00, 0x9fa5,
+ 0xac00, 0xd7a3,
+ 0xd800, 0xfa2d,
+ 0xfb00, 0xfb06,
+ 0xfb13, 0xfb17,
+ 0xfb1e, 0xfb36,
+ 0xfb38, 0xfb3c,
+ 0xfb3e, 0xfb3e,
+ 0xfb40, 0xfb41,
+ 0xfb43, 0xfb44,
+ 0xfb46, 0xfbb1,
+ 0xfbd3, 0xfd3f,
+ 0xfd50, 0xfd8f,
+ 0xfd92, 0xfdc7,
+ 0xfdf0, 0xfdfb,
+ 0xfe20, 0xfe23,
+ 0xfe30, 0xfe44,
+ 0xfe49, 0xfe52,
+ 0xfe54, 0xfe66,
+ 0xfe68, 0xfe6b,
+ 0xfe70, 0xfe72,
+ 0xfe74, 0xfe74,
+ 0xfe76, 0xfefc,
+ 0xfeff, 0xfeff,
+ 0xff01, 0xff5e,
+ 0xff61, 0xffbe,
+ 0xffc2, 0xffc7,
+ 0xffca, 0xffcf,
+ 0xffd2, 0xffd7,
+ 0xffda, 0xffdc,
+ 0xffe0, 0xffe6,
+ 0xffe8, 0xffee,
+ 0xfffd, 0xffff,
+ 0x1fffe, 0x1ffff,
+ 0x2fffe, 0x2ffff,
+ 0x3fffe, 0x3ffff,
+ 0x4fffe, 0x4ffff,
+ 0x5fffe, 0x5ffff,
+ 0x6fffe, 0x6ffff,
+ 0x7fffe, 0x7ffff,
+ 0x8fffe, 0x8ffff,
+ 0x9fffe, 0x9ffff,
+ 0xafffe, 0xaffff,
+ 0xbfffe, 0xbffff,
+ 0xcfffe, 0xcffff,
+ 0xdfffe, 0xdffff,
+ 0xefffe, 0x10ffff,
+}; /* CR_Age_2_0 */
+
+/* 'Age_2_1': Derived Age 2.1 */
+static const OnigCodePoint CR_Age_2_1[] = {
+ 312,
+ 0x0000, 0x01f5,
+ 0x01fa, 0x0217,
+ 0x0250, 0x02a8,
+ 0x02b0, 0x02de,
+ 0x02e0, 0x02e9,
+ 0x0300, 0x0345,
+ 0x0360, 0x0361,
+ 0x0374, 0x0375,
+ 0x037a, 0x037a,
+ 0x037e, 0x037e,
+ 0x0384, 0x038a,
+ 0x038c, 0x038c,
+ 0x038e, 0x03a1,
+ 0x03a3, 0x03ce,
+ 0x03d0, 0x03d6,
+ 0x03da, 0x03da,
+ 0x03dc, 0x03dc,
+ 0x03de, 0x03de,
+ 0x03e0, 0x03e0,
+ 0x03e2, 0x03f3,
+ 0x0401, 0x040c,
+ 0x040e, 0x044f,
+ 0x0451, 0x045c,
+ 0x045e, 0x0486,
+ 0x0490, 0x04c4,
+ 0x04c7, 0x04c8,
+ 0x04cb, 0x04cc,
+ 0x04d0, 0x04eb,
+ 0x04ee, 0x04f5,
+ 0x04f8, 0x04f9,
+ 0x0531, 0x0556,
+ 0x0559, 0x055f,
+ 0x0561, 0x0587,
+ 0x0589, 0x0589,
+ 0x0591, 0x05a1,
+ 0x05a3, 0x05b9,
+ 0x05bb, 0x05c4,
+ 0x05d0, 0x05ea,
+ 0x05f0, 0x05f4,
+ 0x060c, 0x060c,
+ 0x061b, 0x061b,
+ 0x061f, 0x061f,
+ 0x0621, 0x063a,
+ 0x0640, 0x0652,
+ 0x0660, 0x066d,
+ 0x0670, 0x06b7,
+ 0x06ba, 0x06be,
+ 0x06c0, 0x06ce,
+ 0x06d0, 0x06ed,
+ 0x06f0, 0x06f9,
+ 0x0901, 0x0903,
+ 0x0905, 0x0939,
+ 0x093c, 0x094d,
+ 0x0950, 0x0954,
+ 0x0958, 0x0970,
+ 0x0981, 0x0983,
+ 0x0985, 0x098c,
+ 0x098f, 0x0990,
+ 0x0993, 0x09a8,
+ 0x09aa, 0x09b0,
+ 0x09b2, 0x09b2,
+ 0x09b6, 0x09b9,
+ 0x09bc, 0x09bc,
+ 0x09be, 0x09c4,
+ 0x09c7, 0x09c8,
+ 0x09cb, 0x09cd,
+ 0x09d7, 0x09d7,
+ 0x09dc, 0x09dd,
+ 0x09df, 0x09e3,
+ 0x09e6, 0x09fa,
+ 0x0a02, 0x0a02,
+ 0x0a05, 0x0a0a,
+ 0x0a0f, 0x0a10,
+ 0x0a13, 0x0a28,
+ 0x0a2a, 0x0a30,
+ 0x0a32, 0x0a33,
+ 0x0a35, 0x0a36,
+ 0x0a38, 0x0a39,
+ 0x0a3c, 0x0a3c,
+ 0x0a3e, 0x0a42,
+ 0x0a47, 0x0a48,
+ 0x0a4b, 0x0a4d,
+ 0x0a59, 0x0a5c,
+ 0x0a5e, 0x0a5e,
+ 0x0a66, 0x0a74,
+ 0x0a81, 0x0a83,
+ 0x0a85, 0x0a8b,
+ 0x0a8d, 0x0a8d,
+ 0x0a8f, 0x0a91,
+ 0x0a93, 0x0aa8,
+ 0x0aaa, 0x0ab0,
+ 0x0ab2, 0x0ab3,
+ 0x0ab5, 0x0ab9,
+ 0x0abc, 0x0ac5,
+ 0x0ac7, 0x0ac9,
+ 0x0acb, 0x0acd,
+ 0x0ad0, 0x0ad0,
+ 0x0ae0, 0x0ae0,
+ 0x0ae6, 0x0aef,
+ 0x0b01, 0x0b03,
+ 0x0b05, 0x0b0c,
+ 0x0b0f, 0x0b10,
+ 0x0b13, 0x0b28,
+ 0x0b2a, 0x0b30,
+ 0x0b32, 0x0b33,
+ 0x0b36, 0x0b39,
+ 0x0b3c, 0x0b43,
+ 0x0b47, 0x0b48,
+ 0x0b4b, 0x0b4d,
+ 0x0b56, 0x0b57,
+ 0x0b5c, 0x0b5d,
+ 0x0b5f, 0x0b61,
+ 0x0b66, 0x0b70,
+ 0x0b82, 0x0b83,
+ 0x0b85, 0x0b8a,
+ 0x0b8e, 0x0b90,
+ 0x0b92, 0x0b95,
+ 0x0b99, 0x0b9a,
+ 0x0b9c, 0x0b9c,
+ 0x0b9e, 0x0b9f,
+ 0x0ba3, 0x0ba4,
+ 0x0ba8, 0x0baa,
+ 0x0bae, 0x0bb5,
+ 0x0bb7, 0x0bb9,
+ 0x0bbe, 0x0bc2,
+ 0x0bc6, 0x0bc8,
+ 0x0bca, 0x0bcd,
+ 0x0bd7, 0x0bd7,
+ 0x0be7, 0x0bf2,
+ 0x0c01, 0x0c03,
+ 0x0c05, 0x0c0c,
+ 0x0c0e, 0x0c10,
+ 0x0c12, 0x0c28,
+ 0x0c2a, 0x0c33,
+ 0x0c35, 0x0c39,
+ 0x0c3e, 0x0c44,
+ 0x0c46, 0x0c48,
+ 0x0c4a, 0x0c4d,
+ 0x0c55, 0x0c56,
+ 0x0c60, 0x0c61,
+ 0x0c66, 0x0c6f,
+ 0x0c82, 0x0c83,
+ 0x0c85, 0x0c8c,
+ 0x0c8e, 0x0c90,
+ 0x0c92, 0x0ca8,
+ 0x0caa, 0x0cb3,
+ 0x0cb5, 0x0cb9,
+ 0x0cbe, 0x0cc4,
+ 0x0cc6, 0x0cc8,
+ 0x0cca, 0x0ccd,
+ 0x0cd5, 0x0cd6,
+ 0x0cde, 0x0cde,
+ 0x0ce0, 0x0ce1,
+ 0x0ce6, 0x0cef,
+ 0x0d02, 0x0d03,
+ 0x0d05, 0x0d0c,
+ 0x0d0e, 0x0d10,
+ 0x0d12, 0x0d28,
+ 0x0d2a, 0x0d39,
+ 0x0d3e, 0x0d43,
+ 0x0d46, 0x0d48,
+ 0x0d4a, 0x0d4d,
+ 0x0d57, 0x0d57,
+ 0x0d60, 0x0d61,
+ 0x0d66, 0x0d6f,
+ 0x0e01, 0x0e3a,
+ 0x0e3f, 0x0e5b,
+ 0x0e81, 0x0e82,
+ 0x0e84, 0x0e84,
+ 0x0e87, 0x0e88,
+ 0x0e8a, 0x0e8a,
+ 0x0e8d, 0x0e8d,
+ 0x0e94, 0x0e97,
+ 0x0e99, 0x0e9f,
+ 0x0ea1, 0x0ea3,
+ 0x0ea5, 0x0ea5,
+ 0x0ea7, 0x0ea7,
+ 0x0eaa, 0x0eab,
+ 0x0ead, 0x0eb9,
+ 0x0ebb, 0x0ebd,
+ 0x0ec0, 0x0ec4,
+ 0x0ec6, 0x0ec6,
+ 0x0ec8, 0x0ecd,
+ 0x0ed0, 0x0ed9,
+ 0x0edc, 0x0edd,
+ 0x0f00, 0x0f47,
+ 0x0f49, 0x0f69,
+ 0x0f71, 0x0f8b,
+ 0x0f90, 0x0f95,
+ 0x0f97, 0x0f97,
+ 0x0f99, 0x0fad,
+ 0x0fb1, 0x0fb7,
+ 0x0fb9, 0x0fb9,
+ 0x10a0, 0x10c5,
+ 0x10d0, 0x10f6,
+ 0x10fb, 0x10fb,
+ 0x1100, 0x1159,
+ 0x115f, 0x11a2,
+ 0x11a8, 0x11f9,
+ 0x1e00, 0x1e9b,
+ 0x1ea0, 0x1ef9,
+ 0x1f00, 0x1f15,
+ 0x1f18, 0x1f1d,
+ 0x1f20, 0x1f45,
+ 0x1f48, 0x1f4d,
+ 0x1f50, 0x1f57,
+ 0x1f59, 0x1f59,
+ 0x1f5b, 0x1f5b,
+ 0x1f5d, 0x1f5d,
+ 0x1f5f, 0x1f7d,
+ 0x1f80, 0x1fb4,
+ 0x1fb6, 0x1fc4,
+ 0x1fc6, 0x1fd3,
+ 0x1fd6, 0x1fdb,
+ 0x1fdd, 0x1fef,
+ 0x1ff2, 0x1ff4,
+ 0x1ff6, 0x1ffe,
+ 0x2000, 0x202e,
+ 0x2030, 0x2046,
+ 0x206a, 0x2070,
+ 0x2074, 0x208e,
+ 0x20a0, 0x20ac,
+ 0x20d0, 0x20e1,
+ 0x2100, 0x2138,
+ 0x2153, 0x2182,
+ 0x2190, 0x21ea,
+ 0x2200, 0x22f1,
+ 0x2300, 0x2300,
+ 0x2302, 0x237a,
+ 0x2400, 0x2424,
+ 0x2440, 0x244a,
+ 0x2460, 0x24ea,
+ 0x2500, 0x2595,
+ 0x25a0, 0x25ef,
+ 0x2600, 0x2613,
+ 0x261a, 0x266f,
+ 0x2701, 0x2704,
+ 0x2706, 0x2709,
+ 0x270c, 0x2727,
+ 0x2729, 0x274b,
+ 0x274d, 0x274d,
+ 0x274f, 0x2752,
+ 0x2756, 0x2756,
+ 0x2758, 0x275e,
+ 0x2761, 0x2767,
+ 0x2776, 0x2794,
+ 0x2798, 0x27af,
+ 0x27b1, 0x27be,
+ 0x3000, 0x3037,
+ 0x303f, 0x303f,
+ 0x3041, 0x3094,
+ 0x3099, 0x309e,
+ 0x30a1, 0x30fe,
+ 0x3105, 0x312c,
+ 0x3131, 0x318e,
+ 0x3190, 0x319f,
+ 0x3200, 0x321c,
+ 0x3220, 0x3243,
+ 0x3260, 0x327b,
+ 0x327f, 0x32b0,
+ 0x32c0, 0x32cb,
+ 0x32d0, 0x32fe,
+ 0x3300, 0x3376,
+ 0x337b, 0x33dd,
+ 0x33e0, 0x33fe,
+ 0x4e00, 0x9fa5,
+ 0xac00, 0xd7a3,
+ 0xd800, 0xfa2d,
+ 0xfb00, 0xfb06,
+ 0xfb13, 0xfb17,
+ 0xfb1e, 0xfb36,
+ 0xfb38, 0xfb3c,
+ 0xfb3e, 0xfb3e,
+ 0xfb40, 0xfb41,
+ 0xfb43, 0xfb44,
+ 0xfb46, 0xfbb1,
+ 0xfbd3, 0xfd3f,
+ 0xfd50, 0xfd8f,
+ 0xfd92, 0xfdc7,
+ 0xfdf0, 0xfdfb,
+ 0xfe20, 0xfe23,
+ 0xfe30, 0xfe44,
+ 0xfe49, 0xfe52,
+ 0xfe54, 0xfe66,
+ 0xfe68, 0xfe6b,
+ 0xfe70, 0xfe72,
+ 0xfe74, 0xfe74,
+ 0xfe76, 0xfefc,
+ 0xfeff, 0xfeff,
+ 0xff01, 0xff5e,
+ 0xff61, 0xffbe,
+ 0xffc2, 0xffc7,
+ 0xffca, 0xffcf,
+ 0xffd2, 0xffd7,
+ 0xffda, 0xffdc,
+ 0xffe0, 0xffe6,
+ 0xffe8, 0xffee,
+ 0xfffc, 0xffff,
+ 0x1fffe, 0x1ffff,
+ 0x2fffe, 0x2ffff,
+ 0x3fffe, 0x3ffff,
+ 0x4fffe, 0x4ffff,
+ 0x5fffe, 0x5ffff,
+ 0x6fffe, 0x6ffff,
+ 0x7fffe, 0x7ffff,
+ 0x8fffe, 0x8ffff,
+ 0x9fffe, 0x9ffff,
+ 0xafffe, 0xaffff,
+ 0xbfffe, 0xbffff,
+ 0xcfffe, 0xcffff,
+ 0xdfffe, 0xdffff,
+ 0xefffe, 0x10ffff,
+}; /* CR_Age_2_1 */
+
+/* 'Age_3_0': Derived Age 3.0 */
+static const OnigCodePoint CR_Age_3_0[] = {
+ 369,
+ 0x0000, 0x021f,
+ 0x0222, 0x0233,
+ 0x0250, 0x02ad,
+ 0x02b0, 0x02ee,
+ 0x0300, 0x034e,
+ 0x0360, 0x0362,
+ 0x0374, 0x0375,
+ 0x037a, 0x037a,
+ 0x037e, 0x037e,
+ 0x0384, 0x038a,
+ 0x038c, 0x038c,
+ 0x038e, 0x03a1,
+ 0x03a3, 0x03ce,
+ 0x03d0, 0x03d7,
+ 0x03da, 0x03f3,
+ 0x0400, 0x0486,
+ 0x0488, 0x0489,
+ 0x048c, 0x04c4,
+ 0x04c7, 0x04c8,
+ 0x04cb, 0x04cc,
+ 0x04d0, 0x04f5,
+ 0x04f8, 0x04f9,
+ 0x0531, 0x0556,
+ 0x0559, 0x055f,
+ 0x0561, 0x0587,
+ 0x0589, 0x058a,
+ 0x0591, 0x05a1,
+ 0x05a3, 0x05b9,
+ 0x05bb, 0x05c4,
+ 0x05d0, 0x05ea,
+ 0x05f0, 0x05f4,
+ 0x060c, 0x060c,
+ 0x061b, 0x061b,
+ 0x061f, 0x061f,
+ 0x0621, 0x063a,
+ 0x0640, 0x0655,
+ 0x0660, 0x066d,
+ 0x0670, 0x06ed,
+ 0x06f0, 0x06fe,
+ 0x0700, 0x070d,
+ 0x070f, 0x072c,
+ 0x0730, 0x074a,
+ 0x0780, 0x07b0,
+ 0x0901, 0x0903,
+ 0x0905, 0x0939,
+ 0x093c, 0x094d,
+ 0x0950, 0x0954,
+ 0x0958, 0x0970,
+ 0x0981, 0x0983,
+ 0x0985, 0x098c,
+ 0x098f, 0x0990,
+ 0x0993, 0x09a8,
+ 0x09aa, 0x09b0,
+ 0x09b2, 0x09b2,
+ 0x09b6, 0x09b9,
+ 0x09bc, 0x09bc,
+ 0x09be, 0x09c4,
+ 0x09c7, 0x09c8,
+ 0x09cb, 0x09cd,
+ 0x09d7, 0x09d7,
+ 0x09dc, 0x09dd,
+ 0x09df, 0x09e3,
+ 0x09e6, 0x09fa,
+ 0x0a02, 0x0a02,
+ 0x0a05, 0x0a0a,
+ 0x0a0f, 0x0a10,
+ 0x0a13, 0x0a28,
+ 0x0a2a, 0x0a30,
+ 0x0a32, 0x0a33,
+ 0x0a35, 0x0a36,
+ 0x0a38, 0x0a39,
+ 0x0a3c, 0x0a3c,
+ 0x0a3e, 0x0a42,
+ 0x0a47, 0x0a48,
+ 0x0a4b, 0x0a4d,
+ 0x0a59, 0x0a5c,
+ 0x0a5e, 0x0a5e,
+ 0x0a66, 0x0a74,
+ 0x0a81, 0x0a83,
+ 0x0a85, 0x0a8b,
+ 0x0a8d, 0x0a8d,
+ 0x0a8f, 0x0a91,
+ 0x0a93, 0x0aa8,
+ 0x0aaa, 0x0ab0,
+ 0x0ab2, 0x0ab3,
+ 0x0ab5, 0x0ab9,
+ 0x0abc, 0x0ac5,
+ 0x0ac7, 0x0ac9,
+ 0x0acb, 0x0acd,
+ 0x0ad0, 0x0ad0,
+ 0x0ae0, 0x0ae0,
+ 0x0ae6, 0x0aef,
+ 0x0b01, 0x0b03,
+ 0x0b05, 0x0b0c,
+ 0x0b0f, 0x0b10,
+ 0x0b13, 0x0b28,
+ 0x0b2a, 0x0b30,
+ 0x0b32, 0x0b33,
+ 0x0b36, 0x0b39,
+ 0x0b3c, 0x0b43,
+ 0x0b47, 0x0b48,
+ 0x0b4b, 0x0b4d,
+ 0x0b56, 0x0b57,
+ 0x0b5c, 0x0b5d,
+ 0x0b5f, 0x0b61,
+ 0x0b66, 0x0b70,
+ 0x0b82, 0x0b83,
+ 0x0b85, 0x0b8a,
+ 0x0b8e, 0x0b90,
+ 0x0b92, 0x0b95,
+ 0x0b99, 0x0b9a,
+ 0x0b9c, 0x0b9c,
+ 0x0b9e, 0x0b9f,
+ 0x0ba3, 0x0ba4,
+ 0x0ba8, 0x0baa,
+ 0x0bae, 0x0bb5,
+ 0x0bb7, 0x0bb9,
+ 0x0bbe, 0x0bc2,
+ 0x0bc6, 0x0bc8,
+ 0x0bca, 0x0bcd,
+ 0x0bd7, 0x0bd7,
+ 0x0be7, 0x0bf2,
+ 0x0c01, 0x0c03,
+ 0x0c05, 0x0c0c,
+ 0x0c0e, 0x0c10,
+ 0x0c12, 0x0c28,
+ 0x0c2a, 0x0c33,
+ 0x0c35, 0x0c39,
+ 0x0c3e, 0x0c44,
+ 0x0c46, 0x0c48,
+ 0x0c4a, 0x0c4d,
+ 0x0c55, 0x0c56,
+ 0x0c60, 0x0c61,
+ 0x0c66, 0x0c6f,
+ 0x0c82, 0x0c83,
+ 0x0c85, 0x0c8c,
+ 0x0c8e, 0x0c90,
+ 0x0c92, 0x0ca8,
+ 0x0caa, 0x0cb3,
+ 0x0cb5, 0x0cb9,
+ 0x0cbe, 0x0cc4,
+ 0x0cc6, 0x0cc8,
+ 0x0cca, 0x0ccd,
+ 0x0cd5, 0x0cd6,
+ 0x0cde, 0x0cde,
+ 0x0ce0, 0x0ce1,
+ 0x0ce6, 0x0cef,
+ 0x0d02, 0x0d03,
+ 0x0d05, 0x0d0c,
+ 0x0d0e, 0x0d10,
+ 0x0d12, 0x0d28,
+ 0x0d2a, 0x0d39,
+ 0x0d3e, 0x0d43,
+ 0x0d46, 0x0d48,
+ 0x0d4a, 0x0d4d,
+ 0x0d57, 0x0d57,
+ 0x0d60, 0x0d61,
+ 0x0d66, 0x0d6f,
+ 0x0d82, 0x0d83,
+ 0x0d85, 0x0d96,
+ 0x0d9a, 0x0db1,
+ 0x0db3, 0x0dbb,
+ 0x0dbd, 0x0dbd,
+ 0x0dc0, 0x0dc6,
+ 0x0dca, 0x0dca,
+ 0x0dcf, 0x0dd4,
+ 0x0dd6, 0x0dd6,
+ 0x0dd8, 0x0ddf,
+ 0x0df2, 0x0df4,
+ 0x0e01, 0x0e3a,
+ 0x0e3f, 0x0e5b,
+ 0x0e81, 0x0e82,
+ 0x0e84, 0x0e84,
+ 0x0e87, 0x0e88,
+ 0x0e8a, 0x0e8a,
+ 0x0e8d, 0x0e8d,
+ 0x0e94, 0x0e97,
+ 0x0e99, 0x0e9f,
+ 0x0ea1, 0x0ea3,
+ 0x0ea5, 0x0ea5,
+ 0x0ea7, 0x0ea7,
+ 0x0eaa, 0x0eab,
+ 0x0ead, 0x0eb9,
+ 0x0ebb, 0x0ebd,
+ 0x0ec0, 0x0ec4,
+ 0x0ec6, 0x0ec6,
+ 0x0ec8, 0x0ecd,
+ 0x0ed0, 0x0ed9,
+ 0x0edc, 0x0edd,
+ 0x0f00, 0x0f47,
+ 0x0f49, 0x0f6a,
+ 0x0f71, 0x0f8b,
+ 0x0f90, 0x0f97,
+ 0x0f99, 0x0fbc,
+ 0x0fbe, 0x0fcc,
+ 0x0fcf, 0x0fcf,
+ 0x1000, 0x1021,
+ 0x1023, 0x1027,
+ 0x1029, 0x102a,
+ 0x102c, 0x1032,
+ 0x1036, 0x1039,
+ 0x1040, 0x1059,
+ 0x10a0, 0x10c5,
+ 0x10d0, 0x10f6,
+ 0x10fb, 0x10fb,
+ 0x1100, 0x1159,
+ 0x115f, 0x11a2,
+ 0x11a8, 0x11f9,
+ 0x1200, 0x1206,
+ 0x1208, 0x1246,
+ 0x1248, 0x1248,
+ 0x124a, 0x124d,
+ 0x1250, 0x1256,
+ 0x1258, 0x1258,
+ 0x125a, 0x125d,
+ 0x1260, 0x1286,
+ 0x1288, 0x1288,
+ 0x128a, 0x128d,
+ 0x1290, 0x12ae,
+ 0x12b0, 0x12b0,
+ 0x12b2, 0x12b5,
+ 0x12b8, 0x12be,
+ 0x12c0, 0x12c0,
+ 0x12c2, 0x12c5,
+ 0x12c8, 0x12ce,
+ 0x12d0, 0x12d6,
+ 0x12d8, 0x12ee,
+ 0x12f0, 0x130e,
+ 0x1310, 0x1310,
+ 0x1312, 0x1315,
+ 0x1318, 0x131e,
+ 0x1320, 0x1346,
+ 0x1348, 0x135a,
+ 0x1361, 0x137c,
+ 0x13a0, 0x13f4,
+ 0x1401, 0x1676,
+ 0x1680, 0x169c,
+ 0x16a0, 0x16f0,
+ 0x1780, 0x17dc,
+ 0x17e0, 0x17e9,
+ 0x1800, 0x180e,
+ 0x1810, 0x1819,
+ 0x1820, 0x1877,
+ 0x1880, 0x18a9,
+ 0x1e00, 0x1e9b,
+ 0x1ea0, 0x1ef9,
+ 0x1f00, 0x1f15,
+ 0x1f18, 0x1f1d,
+ 0x1f20, 0x1f45,
+ 0x1f48, 0x1f4d,
+ 0x1f50, 0x1f57,
+ 0x1f59, 0x1f59,
+ 0x1f5b, 0x1f5b,
+ 0x1f5d, 0x1f5d,
+ 0x1f5f, 0x1f7d,
+ 0x1f80, 0x1fb4,
+ 0x1fb6, 0x1fc4,
+ 0x1fc6, 0x1fd3,
+ 0x1fd6, 0x1fdb,
+ 0x1fdd, 0x1fef,
+ 0x1ff2, 0x1ff4,
+ 0x1ff6, 0x1ffe,
+ 0x2000, 0x2046,
+ 0x2048, 0x204d,
+ 0x206a, 0x2070,
+ 0x2074, 0x208e,
+ 0x20a0, 0x20af,
+ 0x20d0, 0x20e3,
+ 0x2100, 0x213a,
+ 0x2153, 0x2183,
+ 0x2190, 0x21f3,
+ 0x2200, 0x22f1,
+ 0x2300, 0x237b,
+ 0x237d, 0x239a,
+ 0x2400, 0x2426,
+ 0x2440, 0x244a,
+ 0x2460, 0x24ea,
+ 0x2500, 0x2595,
+ 0x25a0, 0x25f7,
+ 0x2600, 0x2613,
+ 0x2619, 0x2671,
+ 0x2701, 0x2704,
+ 0x2706, 0x2709,
+ 0x270c, 0x2727,
+ 0x2729, 0x274b,
+ 0x274d, 0x274d,
+ 0x274f, 0x2752,
+ 0x2756, 0x2756,
+ 0x2758, 0x275e,
+ 0x2761, 0x2767,
+ 0x2776, 0x2794,
+ 0x2798, 0x27af,
+ 0x27b1, 0x27be,
+ 0x2800, 0x28ff,
+ 0x2e80, 0x2e99,
+ 0x2e9b, 0x2ef3,
+ 0x2f00, 0x2fd5,
+ 0x2ff0, 0x2ffb,
+ 0x3000, 0x303a,
+ 0x303e, 0x303f,
+ 0x3041, 0x3094,
+ 0x3099, 0x309e,
+ 0x30a1, 0x30fe,
+ 0x3105, 0x312c,
+ 0x3131, 0x318e,
+ 0x3190, 0x31b7,
+ 0x3200, 0x321c,
+ 0x3220, 0x3243,
+ 0x3260, 0x327b,
+ 0x327f, 0x32b0,
+ 0x32c0, 0x32cb,
+ 0x32d0, 0x32fe,
+ 0x3300, 0x3376,
+ 0x337b, 0x33dd,
+ 0x33e0, 0x33fe,
+ 0x3400, 0x4db5,
+ 0x4e00, 0x9fa5,
+ 0xa000, 0xa48c,
+ 0xa490, 0xa4a1,
+ 0xa4a4, 0xa4b3,
+ 0xa4b5, 0xa4c0,
+ 0xa4c2, 0xa4c4,
+ 0xa4c6, 0xa4c6,
+ 0xac00, 0xd7a3,
+ 0xd800, 0xfa2d,
+ 0xfb00, 0xfb06,
+ 0xfb13, 0xfb17,
+ 0xfb1d, 0xfb36,
+ 0xfb38, 0xfb3c,
+ 0xfb3e, 0xfb3e,
+ 0xfb40, 0xfb41,
+ 0xfb43, 0xfb44,
+ 0xfb46, 0xfbb1,
+ 0xfbd3, 0xfd3f,
+ 0xfd50, 0xfd8f,
+ 0xfd92, 0xfdc7,
+ 0xfdf0, 0xfdfb,
+ 0xfe20, 0xfe23,
+ 0xfe30, 0xfe44,
+ 0xfe49, 0xfe52,
+ 0xfe54, 0xfe66,
+ 0xfe68, 0xfe6b,
+ 0xfe70, 0xfe72,
+ 0xfe74, 0xfe74,
+ 0xfe76, 0xfefc,
+ 0xfeff, 0xfeff,
+ 0xff01, 0xff5e,
+ 0xff61, 0xffbe,
+ 0xffc2, 0xffc7,
+ 0xffca, 0xffcf,
+ 0xffd2, 0xffd7,
+ 0xffda, 0xffdc,
+ 0xffe0, 0xffe6,
+ 0xffe8, 0xffee,
+ 0xfff9, 0xffff,
+ 0x1fffe, 0x1ffff,
+ 0x2fffe, 0x2ffff,
+ 0x3fffe, 0x3ffff,
+ 0x4fffe, 0x4ffff,
+ 0x5fffe, 0x5ffff,
+ 0x6fffe, 0x6ffff,
+ 0x7fffe, 0x7ffff,
+ 0x8fffe, 0x8ffff,
+ 0x9fffe, 0x9ffff,
+ 0xafffe, 0xaffff,
+ 0xbfffe, 0xbffff,
+ 0xcfffe, 0xcffff,
+ 0xdfffe, 0xdffff,
+ 0xefffe, 0x10ffff,
+}; /* CR_Age_3_0 */
+
+/* 'Age_3_1': Derived Age 3.1 */
+static const OnigCodePoint CR_Age_3_1[] = {
+ 402,
+ 0x0000, 0x021f,
+ 0x0222, 0x0233,
+ 0x0250, 0x02ad,
+ 0x02b0, 0x02ee,
+ 0x0300, 0x034e,
+ 0x0360, 0x0362,
+ 0x0374, 0x0375,
+ 0x037a, 0x037a,
+ 0x037e, 0x037e,
+ 0x0384, 0x038a,
+ 0x038c, 0x038c,
+ 0x038e, 0x03a1,
+ 0x03a3, 0x03ce,
+ 0x03d0, 0x03d7,
+ 0x03da, 0x03f5,
+ 0x0400, 0x0486,
+ 0x0488, 0x0489,
+ 0x048c, 0x04c4,
+ 0x04c7, 0x04c8,
+ 0x04cb, 0x04cc,
+ 0x04d0, 0x04f5,
+ 0x04f8, 0x04f9,
+ 0x0531, 0x0556,
+ 0x0559, 0x055f,
+ 0x0561, 0x0587,
+ 0x0589, 0x058a,
+ 0x0591, 0x05a1,
+ 0x05a3, 0x05b9,
+ 0x05bb, 0x05c4,
+ 0x05d0, 0x05ea,
+ 0x05f0, 0x05f4,
+ 0x060c, 0x060c,
+ 0x061b, 0x061b,
+ 0x061f, 0x061f,
+ 0x0621, 0x063a,
+ 0x0640, 0x0655,
+ 0x0660, 0x066d,
+ 0x0670, 0x06ed,
+ 0x06f0, 0x06fe,
+ 0x0700, 0x070d,
+ 0x070f, 0x072c,
+ 0x0730, 0x074a,
+ 0x0780, 0x07b0,
+ 0x0901, 0x0903,
+ 0x0905, 0x0939,
+ 0x093c, 0x094d,
+ 0x0950, 0x0954,
+ 0x0958, 0x0970,
+ 0x0981, 0x0983,
+ 0x0985, 0x098c,
+ 0x098f, 0x0990,
+ 0x0993, 0x09a8,
+ 0x09aa, 0x09b0,
+ 0x09b2, 0x09b2,
+ 0x09b6, 0x09b9,
+ 0x09bc, 0x09bc,
+ 0x09be, 0x09c4,
+ 0x09c7, 0x09c8,
+ 0x09cb, 0x09cd,
+ 0x09d7, 0x09d7,
+ 0x09dc, 0x09dd,
+ 0x09df, 0x09e3,
+ 0x09e6, 0x09fa,
+ 0x0a02, 0x0a02,
+ 0x0a05, 0x0a0a,
+ 0x0a0f, 0x0a10,
+ 0x0a13, 0x0a28,
+ 0x0a2a, 0x0a30,
+ 0x0a32, 0x0a33,
+ 0x0a35, 0x0a36,
+ 0x0a38, 0x0a39,
+ 0x0a3c, 0x0a3c,
+ 0x0a3e, 0x0a42,
+ 0x0a47, 0x0a48,
+ 0x0a4b, 0x0a4d,
+ 0x0a59, 0x0a5c,
+ 0x0a5e, 0x0a5e,
+ 0x0a66, 0x0a74,
+ 0x0a81, 0x0a83,
+ 0x0a85, 0x0a8b,
+ 0x0a8d, 0x0a8d,
+ 0x0a8f, 0x0a91,
+ 0x0a93, 0x0aa8,
+ 0x0aaa, 0x0ab0,
+ 0x0ab2, 0x0ab3,
+ 0x0ab5, 0x0ab9,
+ 0x0abc, 0x0ac5,
+ 0x0ac7, 0x0ac9,
+ 0x0acb, 0x0acd,
+ 0x0ad0, 0x0ad0,
+ 0x0ae0, 0x0ae0,
+ 0x0ae6, 0x0aef,
+ 0x0b01, 0x0b03,
+ 0x0b05, 0x0b0c,
+ 0x0b0f, 0x0b10,
+ 0x0b13, 0x0b28,
+ 0x0b2a, 0x0b30,
+ 0x0b32, 0x0b33,
+ 0x0b36, 0x0b39,
+ 0x0b3c, 0x0b43,
+ 0x0b47, 0x0b48,
+ 0x0b4b, 0x0b4d,
+ 0x0b56, 0x0b57,
+ 0x0b5c, 0x0b5d,
+ 0x0b5f, 0x0b61,
+ 0x0b66, 0x0b70,
+ 0x0b82, 0x0b83,
+ 0x0b85, 0x0b8a,
+ 0x0b8e, 0x0b90,
+ 0x0b92, 0x0b95,
+ 0x0b99, 0x0b9a,
+ 0x0b9c, 0x0b9c,
+ 0x0b9e, 0x0b9f,
+ 0x0ba3, 0x0ba4,
+ 0x0ba8, 0x0baa,
+ 0x0bae, 0x0bb5,
+ 0x0bb7, 0x0bb9,
+ 0x0bbe, 0x0bc2,
+ 0x0bc6, 0x0bc8,
+ 0x0bca, 0x0bcd,
+ 0x0bd7, 0x0bd7,
+ 0x0be7, 0x0bf2,
+ 0x0c01, 0x0c03,
+ 0x0c05, 0x0c0c,
+ 0x0c0e, 0x0c10,
+ 0x0c12, 0x0c28,
+ 0x0c2a, 0x0c33,
+ 0x0c35, 0x0c39,
+ 0x0c3e, 0x0c44,
+ 0x0c46, 0x0c48,
+ 0x0c4a, 0x0c4d,
+ 0x0c55, 0x0c56,
+ 0x0c60, 0x0c61,
+ 0x0c66, 0x0c6f,
+ 0x0c82, 0x0c83,
+ 0x0c85, 0x0c8c,
+ 0x0c8e, 0x0c90,
+ 0x0c92, 0x0ca8,
+ 0x0caa, 0x0cb3,
+ 0x0cb5, 0x0cb9,
+ 0x0cbe, 0x0cc4,
+ 0x0cc6, 0x0cc8,
+ 0x0cca, 0x0ccd,
+ 0x0cd5, 0x0cd6,
+ 0x0cde, 0x0cde,
+ 0x0ce0, 0x0ce1,
+ 0x0ce6, 0x0cef,
+ 0x0d02, 0x0d03,
+ 0x0d05, 0x0d0c,
+ 0x0d0e, 0x0d10,
+ 0x0d12, 0x0d28,
+ 0x0d2a, 0x0d39,
+ 0x0d3e, 0x0d43,
+ 0x0d46, 0x0d48,
+ 0x0d4a, 0x0d4d,
+ 0x0d57, 0x0d57,
+ 0x0d60, 0x0d61,
+ 0x0d66, 0x0d6f,
+ 0x0d82, 0x0d83,
+ 0x0d85, 0x0d96,
+ 0x0d9a, 0x0db1,
+ 0x0db3, 0x0dbb,
+ 0x0dbd, 0x0dbd,
+ 0x0dc0, 0x0dc6,
+ 0x0dca, 0x0dca,
+ 0x0dcf, 0x0dd4,
+ 0x0dd6, 0x0dd6,
+ 0x0dd8, 0x0ddf,
+ 0x0df2, 0x0df4,
+ 0x0e01, 0x0e3a,
+ 0x0e3f, 0x0e5b,
+ 0x0e81, 0x0e82,
+ 0x0e84, 0x0e84,
+ 0x0e87, 0x0e88,
+ 0x0e8a, 0x0e8a,
+ 0x0e8d, 0x0e8d,
+ 0x0e94, 0x0e97,
+ 0x0e99, 0x0e9f,
+ 0x0ea1, 0x0ea3,
+ 0x0ea5, 0x0ea5,
+ 0x0ea7, 0x0ea7,
+ 0x0eaa, 0x0eab,
+ 0x0ead, 0x0eb9,
+ 0x0ebb, 0x0ebd,
+ 0x0ec0, 0x0ec4,
+ 0x0ec6, 0x0ec6,
+ 0x0ec8, 0x0ecd,
+ 0x0ed0, 0x0ed9,
+ 0x0edc, 0x0edd,
+ 0x0f00, 0x0f47,
+ 0x0f49, 0x0f6a,
+ 0x0f71, 0x0f8b,
+ 0x0f90, 0x0f97,
+ 0x0f99, 0x0fbc,
+ 0x0fbe, 0x0fcc,
+ 0x0fcf, 0x0fcf,
+ 0x1000, 0x1021,
+ 0x1023, 0x1027,
+ 0x1029, 0x102a,
+ 0x102c, 0x1032,
+ 0x1036, 0x1039,
+ 0x1040, 0x1059,
+ 0x10a0, 0x10c5,
+ 0x10d0, 0x10f6,
+ 0x10fb, 0x10fb,
+ 0x1100, 0x1159,
+ 0x115f, 0x11a2,
+ 0x11a8, 0x11f9,
+ 0x1200, 0x1206,
+ 0x1208, 0x1246,
+ 0x1248, 0x1248,
+ 0x124a, 0x124d,
+ 0x1250, 0x1256,
+ 0x1258, 0x1258,
+ 0x125a, 0x125d,
+ 0x1260, 0x1286,
+ 0x1288, 0x1288,
+ 0x128a, 0x128d,
+ 0x1290, 0x12ae,
+ 0x12b0, 0x12b0,
+ 0x12b2, 0x12b5,
+ 0x12b8, 0x12be,
+ 0x12c0, 0x12c0,
+ 0x12c2, 0x12c5,
+ 0x12c8, 0x12ce,
+ 0x12d0, 0x12d6,
+ 0x12d8, 0x12ee,
+ 0x12f0, 0x130e,
+ 0x1310, 0x1310,
+ 0x1312, 0x1315,
+ 0x1318, 0x131e,
+ 0x1320, 0x1346,
+ 0x1348, 0x135a,
+ 0x1361, 0x137c,
+ 0x13a0, 0x13f4,
+ 0x1401, 0x1676,
+ 0x1680, 0x169c,
+ 0x16a0, 0x16f0,
+ 0x1780, 0x17dc,
+ 0x17e0, 0x17e9,
+ 0x1800, 0x180e,
+ 0x1810, 0x1819,
+ 0x1820, 0x1877,
+ 0x1880, 0x18a9,
+ 0x1e00, 0x1e9b,
+ 0x1ea0, 0x1ef9,
+ 0x1f00, 0x1f15,
+ 0x1f18, 0x1f1d,
+ 0x1f20, 0x1f45,
+ 0x1f48, 0x1f4d,
+ 0x1f50, 0x1f57,
+ 0x1f59, 0x1f59,
+ 0x1f5b, 0x1f5b,
+ 0x1f5d, 0x1f5d,
+ 0x1f5f, 0x1f7d,
+ 0x1f80, 0x1fb4,
+ 0x1fb6, 0x1fc4,
+ 0x1fc6, 0x1fd3,
+ 0x1fd6, 0x1fdb,
+ 0x1fdd, 0x1fef,
+ 0x1ff2, 0x1ff4,
+ 0x1ff6, 0x1ffe,
+ 0x2000, 0x2046,
+ 0x2048, 0x204d,
+ 0x206a, 0x2070,
+ 0x2074, 0x208e,
+ 0x20a0, 0x20af,
+ 0x20d0, 0x20e3,
+ 0x2100, 0x213a,
+ 0x2153, 0x2183,
+ 0x2190, 0x21f3,
+ 0x2200, 0x22f1,
+ 0x2300, 0x237b,
+ 0x237d, 0x239a,
+ 0x2400, 0x2426,
+ 0x2440, 0x244a,
+ 0x2460, 0x24ea,
+ 0x2500, 0x2595,
+ 0x25a0, 0x25f7,
+ 0x2600, 0x2613,
+ 0x2619, 0x2671,
+ 0x2701, 0x2704,
+ 0x2706, 0x2709,
+ 0x270c, 0x2727,
+ 0x2729, 0x274b,
+ 0x274d, 0x274d,
+ 0x274f, 0x2752,
+ 0x2756, 0x2756,
+ 0x2758, 0x275e,
+ 0x2761, 0x2767,
+ 0x2776, 0x2794,
+ 0x2798, 0x27af,
+ 0x27b1, 0x27be,
+ 0x2800, 0x28ff,
+ 0x2e80, 0x2e99,
+ 0x2e9b, 0x2ef3,
+ 0x2f00, 0x2fd5,
+ 0x2ff0, 0x2ffb,
+ 0x3000, 0x303a,
+ 0x303e, 0x303f,
+ 0x3041, 0x3094,
+ 0x3099, 0x309e,
+ 0x30a1, 0x30fe,
+ 0x3105, 0x312c,
+ 0x3131, 0x318e,
+ 0x3190, 0x31b7,
+ 0x3200, 0x321c,
+ 0x3220, 0x3243,
+ 0x3260, 0x327b,
+ 0x327f, 0x32b0,
+ 0x32c0, 0x32cb,
+ 0x32d0, 0x32fe,
+ 0x3300, 0x3376,
+ 0x337b, 0x33dd,
+ 0x33e0, 0x33fe,
+ 0x3400, 0x4db5,
+ 0x4e00, 0x9fa5,
+ 0xa000, 0xa48c,
+ 0xa490, 0xa4a1,
+ 0xa4a4, 0xa4b3,
+ 0xa4b5, 0xa4c0,
+ 0xa4c2, 0xa4c4,
+ 0xa4c6, 0xa4c6,
+ 0xac00, 0xd7a3,
+ 0xd800, 0xfa2d,
+ 0xfb00, 0xfb06,
+ 0xfb13, 0xfb17,
+ 0xfb1d, 0xfb36,
+ 0xfb38, 0xfb3c,
+ 0xfb3e, 0xfb3e,
+ 0xfb40, 0xfb41,
+ 0xfb43, 0xfb44,
+ 0xfb46, 0xfbb1,
+ 0xfbd3, 0xfd3f,
+ 0xfd50, 0xfd8f,
+ 0xfd92, 0xfdc7,
+ 0xfdd0, 0xfdfb,
+ 0xfe20, 0xfe23,
+ 0xfe30, 0xfe44,
+ 0xfe49, 0xfe52,
+ 0xfe54, 0xfe66,
+ 0xfe68, 0xfe6b,
+ 0xfe70, 0xfe72,
+ 0xfe74, 0xfe74,
+ 0xfe76, 0xfefc,
+ 0xfeff, 0xfeff,
+ 0xff01, 0xff5e,
+ 0xff61, 0xffbe,
+ 0xffc2, 0xffc7,
+ 0xffca, 0xffcf,
+ 0xffd2, 0xffd7,
+ 0xffda, 0xffdc,
+ 0xffe0, 0xffe6,
+ 0xffe8, 0xffee,
+ 0xfff9, 0xffff,
+ 0x10300, 0x1031e,
+ 0x10320, 0x10323,
+ 0x10330, 0x1034a,
+ 0x10400, 0x10425,
+ 0x10428, 0x1044d,
+ 0x1d000, 0x1d0f5,
+ 0x1d100, 0x1d126,
+ 0x1d12a, 0x1d1dd,
+ 0x1d400, 0x1d454,
+ 0x1d456, 0x1d49c,
+ 0x1d49e, 0x1d49f,
+ 0x1d4a2, 0x1d4a2,
+ 0x1d4a5, 0x1d4a6,
+ 0x1d4a9, 0x1d4ac,
+ 0x1d4ae, 0x1d4b9,
+ 0x1d4bb, 0x1d4bb,
+ 0x1d4bd, 0x1d4c0,
+ 0x1d4c2, 0x1d4c3,
+ 0x1d4c5, 0x1d505,
+ 0x1d507, 0x1d50a,
+ 0x1d50d, 0x1d514,
+ 0x1d516, 0x1d51c,
+ 0x1d51e, 0x1d539,
+ 0x1d53b, 0x1d53e,
+ 0x1d540, 0x1d544,
+ 0x1d546, 0x1d546,
+ 0x1d54a, 0x1d550,
+ 0x1d552, 0x1d6a3,
+ 0x1d6a8, 0x1d7c9,
+ 0x1d7ce, 0x1d7ff,
+ 0x1fffe, 0x2a6d6,
+ 0x2f800, 0x2fa1d,
+ 0x2fffe, 0x2ffff,
+ 0x3fffe, 0x3ffff,
+ 0x4fffe, 0x4ffff,
+ 0x5fffe, 0x5ffff,
+ 0x6fffe, 0x6ffff,
+ 0x7fffe, 0x7ffff,
+ 0x8fffe, 0x8ffff,
+ 0x9fffe, 0x9ffff,
+ 0xafffe, 0xaffff,
+ 0xbfffe, 0xbffff,
+ 0xcfffe, 0xcffff,
+ 0xdfffe, 0xdffff,
+ 0xe0001, 0xe0001,
+ 0xe0020, 0xe007f,
+ 0xefffe, 0x10ffff,
+}; /* CR_Age_3_1 */
+
+/* 'Age_3_2': Derived Age 3.2 */
+static const OnigCodePoint CR_Age_3_2[] = {
+ 397,
+ 0x0000, 0x0220,
+ 0x0222, 0x0233,
+ 0x0250, 0x02ad,
+ 0x02b0, 0x02ee,
+ 0x0300, 0x034f,
+ 0x0360, 0x036f,
+ 0x0374, 0x0375,
+ 0x037a, 0x037a,
+ 0x037e, 0x037e,
+ 0x0384, 0x038a,
+ 0x038c, 0x038c,
+ 0x038e, 0x03a1,
+ 0x03a3, 0x03ce,
+ 0x03d0, 0x03f6,
+ 0x0400, 0x0486,
+ 0x0488, 0x04ce,
+ 0x04d0, 0x04f5,
+ 0x04f8, 0x04f9,
+ 0x0500, 0x050f,
+ 0x0531, 0x0556,
+ 0x0559, 0x055f,
+ 0x0561, 0x0587,
+ 0x0589, 0x058a,
+ 0x0591, 0x05a1,
+ 0x05a3, 0x05b9,
+ 0x05bb, 0x05c4,
+ 0x05d0, 0x05ea,
+ 0x05f0, 0x05f4,
+ 0x060c, 0x060c,
+ 0x061b, 0x061b,
+ 0x061f, 0x061f,
+ 0x0621, 0x063a,
+ 0x0640, 0x0655,
+ 0x0660, 0x06ed,
+ 0x06f0, 0x06fe,
+ 0x0700, 0x070d,
+ 0x070f, 0x072c,
+ 0x0730, 0x074a,
+ 0x0780, 0x07b1,
+ 0x0901, 0x0903,
+ 0x0905, 0x0939,
+ 0x093c, 0x094d,
+ 0x0950, 0x0954,
+ 0x0958, 0x0970,
+ 0x0981, 0x0983,
+ 0x0985, 0x098c,
+ 0x098f, 0x0990,
+ 0x0993, 0x09a8,
+ 0x09aa, 0x09b0,
+ 0x09b2, 0x09b2,
+ 0x09b6, 0x09b9,
+ 0x09bc, 0x09bc,
+ 0x09be, 0x09c4,
+ 0x09c7, 0x09c8,
+ 0x09cb, 0x09cd,
+ 0x09d7, 0x09d7,
+ 0x09dc, 0x09dd,
+ 0x09df, 0x09e3,
+ 0x09e6, 0x09fa,
+ 0x0a02, 0x0a02,
+ 0x0a05, 0x0a0a,
+ 0x0a0f, 0x0a10,
+ 0x0a13, 0x0a28,
+ 0x0a2a, 0x0a30,
+ 0x0a32, 0x0a33,
+ 0x0a35, 0x0a36,
+ 0x0a38, 0x0a39,
+ 0x0a3c, 0x0a3c,
+ 0x0a3e, 0x0a42,
+ 0x0a47, 0x0a48,
+ 0x0a4b, 0x0a4d,
+ 0x0a59, 0x0a5c,
+ 0x0a5e, 0x0a5e,
+ 0x0a66, 0x0a74,
+ 0x0a81, 0x0a83,
+ 0x0a85, 0x0a8b,
+ 0x0a8d, 0x0a8d,
+ 0x0a8f, 0x0a91,
+ 0x0a93, 0x0aa8,
+ 0x0aaa, 0x0ab0,
+ 0x0ab2, 0x0ab3,
+ 0x0ab5, 0x0ab9,
+ 0x0abc, 0x0ac5,
+ 0x0ac7, 0x0ac9,
+ 0x0acb, 0x0acd,
+ 0x0ad0, 0x0ad0,
+ 0x0ae0, 0x0ae0,
+ 0x0ae6, 0x0aef,
+ 0x0b01, 0x0b03,
+ 0x0b05, 0x0b0c,
+ 0x0b0f, 0x0b10,
+ 0x0b13, 0x0b28,
+ 0x0b2a, 0x0b30,
+ 0x0b32, 0x0b33,
+ 0x0b36, 0x0b39,
+ 0x0b3c, 0x0b43,
+ 0x0b47, 0x0b48,
+ 0x0b4b, 0x0b4d,
+ 0x0b56, 0x0b57,
+ 0x0b5c, 0x0b5d,
+ 0x0b5f, 0x0b61,
+ 0x0b66, 0x0b70,
+ 0x0b82, 0x0b83,
+ 0x0b85, 0x0b8a,
+ 0x0b8e, 0x0b90,
+ 0x0b92, 0x0b95,
+ 0x0b99, 0x0b9a,
+ 0x0b9c, 0x0b9c,
+ 0x0b9e, 0x0b9f,
+ 0x0ba3, 0x0ba4,
+ 0x0ba8, 0x0baa,
+ 0x0bae, 0x0bb5,
+ 0x0bb7, 0x0bb9,
+ 0x0bbe, 0x0bc2,
+ 0x0bc6, 0x0bc8,
+ 0x0bca, 0x0bcd,
+ 0x0bd7, 0x0bd7,
+ 0x0be7, 0x0bf2,
+ 0x0c01, 0x0c03,
+ 0x0c05, 0x0c0c,
+ 0x0c0e, 0x0c10,
+ 0x0c12, 0x0c28,
+ 0x0c2a, 0x0c33,
+ 0x0c35, 0x0c39,
+ 0x0c3e, 0x0c44,
+ 0x0c46, 0x0c48,
+ 0x0c4a, 0x0c4d,
+ 0x0c55, 0x0c56,
+ 0x0c60, 0x0c61,
+ 0x0c66, 0x0c6f,
+ 0x0c82, 0x0c83,
+ 0x0c85, 0x0c8c,
+ 0x0c8e, 0x0c90,
+ 0x0c92, 0x0ca8,
+ 0x0caa, 0x0cb3,
+ 0x0cb5, 0x0cb9,
+ 0x0cbe, 0x0cc4,
+ 0x0cc6, 0x0cc8,
+ 0x0cca, 0x0ccd,
+ 0x0cd5, 0x0cd6,
+ 0x0cde, 0x0cde,
+ 0x0ce0, 0x0ce1,
+ 0x0ce6, 0x0cef,
+ 0x0d02, 0x0d03,
+ 0x0d05, 0x0d0c,
+ 0x0d0e, 0x0d10,
+ 0x0d12, 0x0d28,
+ 0x0d2a, 0x0d39,
+ 0x0d3e, 0x0d43,
+ 0x0d46, 0x0d48,
+ 0x0d4a, 0x0d4d,
+ 0x0d57, 0x0d57,
+ 0x0d60, 0x0d61,
+ 0x0d66, 0x0d6f,
+ 0x0d82, 0x0d83,
+ 0x0d85, 0x0d96,
+ 0x0d9a, 0x0db1,
+ 0x0db3, 0x0dbb,
+ 0x0dbd, 0x0dbd,
+ 0x0dc0, 0x0dc6,
+ 0x0dca, 0x0dca,
+ 0x0dcf, 0x0dd4,
+ 0x0dd6, 0x0dd6,
+ 0x0dd8, 0x0ddf,
+ 0x0df2, 0x0df4,
+ 0x0e01, 0x0e3a,
+ 0x0e3f, 0x0e5b,
+ 0x0e81, 0x0e82,
+ 0x0e84, 0x0e84,
+ 0x0e87, 0x0e88,
+ 0x0e8a, 0x0e8a,
+ 0x0e8d, 0x0e8d,
+ 0x0e94, 0x0e97,
+ 0x0e99, 0x0e9f,
+ 0x0ea1, 0x0ea3,
+ 0x0ea5, 0x0ea5,
+ 0x0ea7, 0x0ea7,
+ 0x0eaa, 0x0eab,
+ 0x0ead, 0x0eb9,
+ 0x0ebb, 0x0ebd,
+ 0x0ec0, 0x0ec4,
+ 0x0ec6, 0x0ec6,
+ 0x0ec8, 0x0ecd,
+ 0x0ed0, 0x0ed9,
+ 0x0edc, 0x0edd,
+ 0x0f00, 0x0f47,
+ 0x0f49, 0x0f6a,
+ 0x0f71, 0x0f8b,
+ 0x0f90, 0x0f97,
+ 0x0f99, 0x0fbc,
+ 0x0fbe, 0x0fcc,
+ 0x0fcf, 0x0fcf,
+ 0x1000, 0x1021,
+ 0x1023, 0x1027,
+ 0x1029, 0x102a,
+ 0x102c, 0x1032,
+ 0x1036, 0x1039,
+ 0x1040, 0x1059,
+ 0x10a0, 0x10c5,
+ 0x10d0, 0x10f8,
+ 0x10fb, 0x10fb,
+ 0x1100, 0x1159,
+ 0x115f, 0x11a2,
+ 0x11a8, 0x11f9,
+ 0x1200, 0x1206,
+ 0x1208, 0x1246,
+ 0x1248, 0x1248,
+ 0x124a, 0x124d,
+ 0x1250, 0x1256,
+ 0x1258, 0x1258,
+ 0x125a, 0x125d,
+ 0x1260, 0x1286,
+ 0x1288, 0x1288,
+ 0x128a, 0x128d,
+ 0x1290, 0x12ae,
+ 0x12b0, 0x12b0,
+ 0x12b2, 0x12b5,
+ 0x12b8, 0x12be,
+ 0x12c0, 0x12c0,
+ 0x12c2, 0x12c5,
+ 0x12c8, 0x12ce,
+ 0x12d0, 0x12d6,
+ 0x12d8, 0x12ee,
+ 0x12f0, 0x130e,
+ 0x1310, 0x1310,
+ 0x1312, 0x1315,
+ 0x1318, 0x131e,
+ 0x1320, 0x1346,
+ 0x1348, 0x135a,
+ 0x1361, 0x137c,
+ 0x13a0, 0x13f4,
+ 0x1401, 0x1676,
+ 0x1680, 0x169c,
+ 0x16a0, 0x16f0,
+ 0x1700, 0x170c,
+ 0x170e, 0x1714,
+ 0x1720, 0x1736,
+ 0x1740, 0x1753,
+ 0x1760, 0x176c,
+ 0x176e, 0x1770,
+ 0x1772, 0x1773,
+ 0x1780, 0x17dc,
+ 0x17e0, 0x17e9,
+ 0x1800, 0x180e,
+ 0x1810, 0x1819,
+ 0x1820, 0x1877,
+ 0x1880, 0x18a9,
+ 0x1e00, 0x1e9b,
+ 0x1ea0, 0x1ef9,
+ 0x1f00, 0x1f15,
+ 0x1f18, 0x1f1d,
+ 0x1f20, 0x1f45,
+ 0x1f48, 0x1f4d,
+ 0x1f50, 0x1f57,
+ 0x1f59, 0x1f59,
+ 0x1f5b, 0x1f5b,
+ 0x1f5d, 0x1f5d,
+ 0x1f5f, 0x1f7d,
+ 0x1f80, 0x1fb4,
+ 0x1fb6, 0x1fc4,
+ 0x1fc6, 0x1fd3,
+ 0x1fd6, 0x1fdb,
+ 0x1fdd, 0x1fef,
+ 0x1ff2, 0x1ff4,
+ 0x1ff6, 0x1ffe,
+ 0x2000, 0x2052,
+ 0x2057, 0x2057,
+ 0x205f, 0x2063,
+ 0x206a, 0x2071,
+ 0x2074, 0x208e,
+ 0x20a0, 0x20b1,
+ 0x20d0, 0x20ea,
+ 0x2100, 0x213a,
+ 0x213d, 0x214b,
+ 0x2153, 0x2183,
+ 0x2190, 0x23ce,
+ 0x2400, 0x2426,
+ 0x2440, 0x244a,
+ 0x2460, 0x24fe,
+ 0x2500, 0x2613,
+ 0x2616, 0x2617,
+ 0x2619, 0x267d,
+ 0x2680, 0x2689,
+ 0x2701, 0x2704,
+ 0x2706, 0x2709,
+ 0x270c, 0x2727,
+ 0x2729, 0x274b,
+ 0x274d, 0x274d,
+ 0x274f, 0x2752,
+ 0x2756, 0x2756,
+ 0x2758, 0x275e,
+ 0x2761, 0x2794,
+ 0x2798, 0x27af,
+ 0x27b1, 0x27be,
+ 0x27d0, 0x27eb,
+ 0x27f0, 0x2aff,
+ 0x2e80, 0x2e99,
+ 0x2e9b, 0x2ef3,
+ 0x2f00, 0x2fd5,
+ 0x2ff0, 0x2ffb,
+ 0x3000, 0x303f,
+ 0x3041, 0x3096,
+ 0x3099, 0x30ff,
+ 0x3105, 0x312c,
+ 0x3131, 0x318e,
+ 0x3190, 0x31b7,
+ 0x31f0, 0x321c,
+ 0x3220, 0x3243,
+ 0x3251, 0x327b,
+ 0x327f, 0x32cb,
+ 0x32d0, 0x32fe,
+ 0x3300, 0x3376,
+ 0x337b, 0x33dd,
+ 0x33e0, 0x33fe,
+ 0x3400, 0x4db5,
+ 0x4e00, 0x9fa5,
+ 0xa000, 0xa48c,
+ 0xa490, 0xa4c6,
+ 0xac00, 0xd7a3,
+ 0xd800, 0xfa2d,
+ 0xfa30, 0xfa6a,
+ 0xfb00, 0xfb06,
+ 0xfb13, 0xfb17,
+ 0xfb1d, 0xfb36,
+ 0xfb38, 0xfb3c,
+ 0xfb3e, 0xfb3e,
+ 0xfb40, 0xfb41,
+ 0xfb43, 0xfb44,
+ 0xfb46, 0xfbb1,
+ 0xfbd3, 0xfd3f,
+ 0xfd50, 0xfd8f,
+ 0xfd92, 0xfdc7,
+ 0xfdd0, 0xfdfc,
+ 0xfe00, 0xfe0f,
+ 0xfe20, 0xfe23,
+ 0xfe30, 0xfe46,
+ 0xfe49, 0xfe52,
+ 0xfe54, 0xfe66,
+ 0xfe68, 0xfe6b,
+ 0xfe70, 0xfe74,
+ 0xfe76, 0xfefc,
+ 0xfeff, 0xfeff,
+ 0xff01, 0xffbe,
+ 0xffc2, 0xffc7,
+ 0xffca, 0xffcf,
+ 0xffd2, 0xffd7,
+ 0xffda, 0xffdc,
+ 0xffe0, 0xffe6,
+ 0xffe8, 0xffee,
+ 0xfff9, 0xffff,
+ 0x10300, 0x1031e,
+ 0x10320, 0x10323,
+ 0x10330, 0x1034a,
+ 0x10400, 0x10425,
+ 0x10428, 0x1044d,
+ 0x1d000, 0x1d0f5,
+ 0x1d100, 0x1d126,
+ 0x1d12a, 0x1d1dd,
+ 0x1d400, 0x1d454,
+ 0x1d456, 0x1d49c,
+ 0x1d49e, 0x1d49f,
+ 0x1d4a2, 0x1d4a2,
+ 0x1d4a5, 0x1d4a6,
+ 0x1d4a9, 0x1d4ac,
+ 0x1d4ae, 0x1d4b9,
+ 0x1d4bb, 0x1d4bb,
+ 0x1d4bd, 0x1d4c0,
+ 0x1d4c2, 0x1d4c3,
+ 0x1d4c5, 0x1d505,
+ 0x1d507, 0x1d50a,
+ 0x1d50d, 0x1d514,
+ 0x1d516, 0x1d51c,
+ 0x1d51e, 0x1d539,
+ 0x1d53b, 0x1d53e,
+ 0x1d540, 0x1d544,
+ 0x1d546, 0x1d546,
+ 0x1d54a, 0x1d550,
+ 0x1d552, 0x1d6a3,
+ 0x1d6a8, 0x1d7c9,
+ 0x1d7ce, 0x1d7ff,
+ 0x1fffe, 0x2a6d6,
+ 0x2f800, 0x2fa1d,
+ 0x2fffe, 0x2ffff,
+ 0x3fffe, 0x3ffff,
+ 0x4fffe, 0x4ffff,
+ 0x5fffe, 0x5ffff,
+ 0x6fffe, 0x6ffff,
+ 0x7fffe, 0x7ffff,
+ 0x8fffe, 0x8ffff,
+ 0x9fffe, 0x9ffff,
+ 0xafffe, 0xaffff,
+ 0xbfffe, 0xbffff,
+ 0xcfffe, 0xcffff,
+ 0xdfffe, 0xdffff,
+ 0xe0001, 0xe0001,
+ 0xe0020, 0xe007f,
+ 0xefffe, 0x10ffff,
+}; /* CR_Age_3_2 */
+
+/* 'Age_4_0': Derived Age 4.0 */
+static const OnigCodePoint CR_Age_4_0[] = {
+ 412,
+ 0x0000, 0x0236,
+ 0x0250, 0x0357,
+ 0x035d, 0x036f,
+ 0x0374, 0x0375,
+ 0x037a, 0x037a,
+ 0x037e, 0x037e,
+ 0x0384, 0x038a,
+ 0x038c, 0x038c,
+ 0x038e, 0x03a1,
+ 0x03a3, 0x03ce,
+ 0x03d0, 0x03fb,
+ 0x0400, 0x0486,
+ 0x0488, 0x04ce,
+ 0x04d0, 0x04f5,
+ 0x04f8, 0x04f9,
+ 0x0500, 0x050f,
+ 0x0531, 0x0556,
+ 0x0559, 0x055f,
+ 0x0561, 0x0587,
+ 0x0589, 0x058a,
+ 0x0591, 0x05a1,
+ 0x05a3, 0x05b9,
+ 0x05bb, 0x05c4,
+ 0x05d0, 0x05ea,
+ 0x05f0, 0x05f4,
+ 0x0600, 0x0603,
+ 0x060c, 0x0615,
+ 0x061b, 0x061b,
+ 0x061f, 0x061f,
+ 0x0621, 0x063a,
+ 0x0640, 0x0658,
+ 0x0660, 0x070d,
+ 0x070f, 0x074a,
+ 0x074d, 0x074f,
+ 0x0780, 0x07b1,
+ 0x0901, 0x0939,
+ 0x093c, 0x094d,
+ 0x0950, 0x0954,
+ 0x0958, 0x0970,
+ 0x0981, 0x0983,
+ 0x0985, 0x098c,
+ 0x098f, 0x0990,
+ 0x0993, 0x09a8,
+ 0x09aa, 0x09b0,
+ 0x09b2, 0x09b2,
+ 0x09b6, 0x09b9,
+ 0x09bc, 0x09c4,
+ 0x09c7, 0x09c8,
+ 0x09cb, 0x09cd,
+ 0x09d7, 0x09d7,
+ 0x09dc, 0x09dd,
+ 0x09df, 0x09e3,
+ 0x09e6, 0x09fa,
+ 0x0a01, 0x0a03,
+ 0x0a05, 0x0a0a,
+ 0x0a0f, 0x0a10,
+ 0x0a13, 0x0a28,
+ 0x0a2a, 0x0a30,
+ 0x0a32, 0x0a33,
+ 0x0a35, 0x0a36,
+ 0x0a38, 0x0a39,
+ 0x0a3c, 0x0a3c,
+ 0x0a3e, 0x0a42,
+ 0x0a47, 0x0a48,
+ 0x0a4b, 0x0a4d,
+ 0x0a59, 0x0a5c,
+ 0x0a5e, 0x0a5e,
+ 0x0a66, 0x0a74,
+ 0x0a81, 0x0a83,
+ 0x0a85, 0x0a8d,
+ 0x0a8f, 0x0a91,
+ 0x0a93, 0x0aa8,
+ 0x0aaa, 0x0ab0,
+ 0x0ab2, 0x0ab3,
+ 0x0ab5, 0x0ab9,
+ 0x0abc, 0x0ac5,
+ 0x0ac7, 0x0ac9,
+ 0x0acb, 0x0acd,
+ 0x0ad0, 0x0ad0,
+ 0x0ae0, 0x0ae3,
+ 0x0ae6, 0x0aef,
+ 0x0af1, 0x0af1,
+ 0x0b01, 0x0b03,
+ 0x0b05, 0x0b0c,
+ 0x0b0f, 0x0b10,
+ 0x0b13, 0x0b28,
+ 0x0b2a, 0x0b30,
+ 0x0b32, 0x0b33,
+ 0x0b35, 0x0b39,
+ 0x0b3c, 0x0b43,
+ 0x0b47, 0x0b48,
+ 0x0b4b, 0x0b4d,
+ 0x0b56, 0x0b57,
+ 0x0b5c, 0x0b5d,
+ 0x0b5f, 0x0b61,
+ 0x0b66, 0x0b71,
+ 0x0b82, 0x0b83,
+ 0x0b85, 0x0b8a,
+ 0x0b8e, 0x0b90,
+ 0x0b92, 0x0b95,
+ 0x0b99, 0x0b9a,
+ 0x0b9c, 0x0b9c,
+ 0x0b9e, 0x0b9f,
+ 0x0ba3, 0x0ba4,
+ 0x0ba8, 0x0baa,
+ 0x0bae, 0x0bb5,
+ 0x0bb7, 0x0bb9,
+ 0x0bbe, 0x0bc2,
+ 0x0bc6, 0x0bc8,
+ 0x0bca, 0x0bcd,
+ 0x0bd7, 0x0bd7,
+ 0x0be7, 0x0bfa,
+ 0x0c01, 0x0c03,
+ 0x0c05, 0x0c0c,
+ 0x0c0e, 0x0c10,
+ 0x0c12, 0x0c28,
+ 0x0c2a, 0x0c33,
+ 0x0c35, 0x0c39,
+ 0x0c3e, 0x0c44,
+ 0x0c46, 0x0c48,
+ 0x0c4a, 0x0c4d,
+ 0x0c55, 0x0c56,
+ 0x0c60, 0x0c61,
+ 0x0c66, 0x0c6f,
+ 0x0c82, 0x0c83,
+ 0x0c85, 0x0c8c,
+ 0x0c8e, 0x0c90,
+ 0x0c92, 0x0ca8,
+ 0x0caa, 0x0cb3,
+ 0x0cb5, 0x0cb9,
+ 0x0cbc, 0x0cc4,
+ 0x0cc6, 0x0cc8,
+ 0x0cca, 0x0ccd,
+ 0x0cd5, 0x0cd6,
+ 0x0cde, 0x0cde,
+ 0x0ce0, 0x0ce1,
+ 0x0ce6, 0x0cef,
+ 0x0d02, 0x0d03,
+ 0x0d05, 0x0d0c,
+ 0x0d0e, 0x0d10,
+ 0x0d12, 0x0d28,
+ 0x0d2a, 0x0d39,
+ 0x0d3e, 0x0d43,
+ 0x0d46, 0x0d48,
+ 0x0d4a, 0x0d4d,
+ 0x0d57, 0x0d57,
+ 0x0d60, 0x0d61,
+ 0x0d66, 0x0d6f,
+ 0x0d82, 0x0d83,
+ 0x0d85, 0x0d96,
+ 0x0d9a, 0x0db1,
+ 0x0db3, 0x0dbb,
+ 0x0dbd, 0x0dbd,
+ 0x0dc0, 0x0dc6,
+ 0x0dca, 0x0dca,
+ 0x0dcf, 0x0dd4,
+ 0x0dd6, 0x0dd6,
+ 0x0dd8, 0x0ddf,
+ 0x0df2, 0x0df4,
+ 0x0e01, 0x0e3a,
+ 0x0e3f, 0x0e5b,
+ 0x0e81, 0x0e82,
+ 0x0e84, 0x0e84,
+ 0x0e87, 0x0e88,
+ 0x0e8a, 0x0e8a,
+ 0x0e8d, 0x0e8d,
+ 0x0e94, 0x0e97,
+ 0x0e99, 0x0e9f,
+ 0x0ea1, 0x0ea3,
+ 0x0ea5, 0x0ea5,
+ 0x0ea7, 0x0ea7,
+ 0x0eaa, 0x0eab,
+ 0x0ead, 0x0eb9,
+ 0x0ebb, 0x0ebd,
+ 0x0ec0, 0x0ec4,
+ 0x0ec6, 0x0ec6,
+ 0x0ec8, 0x0ecd,
+ 0x0ed0, 0x0ed9,
+ 0x0edc, 0x0edd,
+ 0x0f00, 0x0f47,
+ 0x0f49, 0x0f6a,
+ 0x0f71, 0x0f8b,
+ 0x0f90, 0x0f97,
+ 0x0f99, 0x0fbc,
+ 0x0fbe, 0x0fcc,
+ 0x0fcf, 0x0fcf,
+ 0x1000, 0x1021,
+ 0x1023, 0x1027,
+ 0x1029, 0x102a,
+ 0x102c, 0x1032,
+ 0x1036, 0x1039,
+ 0x1040, 0x1059,
+ 0x10a0, 0x10c5,
+ 0x10d0, 0x10f8,
+ 0x10fb, 0x10fb,
+ 0x1100, 0x1159,
+ 0x115f, 0x11a2,
+ 0x11a8, 0x11f9,
+ 0x1200, 0x1206,
+ 0x1208, 0x1246,
+ 0x1248, 0x1248,
+ 0x124a, 0x124d,
+ 0x1250, 0x1256,
+ 0x1258, 0x1258,
+ 0x125a, 0x125d,
+ 0x1260, 0x1286,
+ 0x1288, 0x1288,
+ 0x128a, 0x128d,
+ 0x1290, 0x12ae,
+ 0x12b0, 0x12b0,
+ 0x12b2, 0x12b5,
+ 0x12b8, 0x12be,
+ 0x12c0, 0x12c0,
+ 0x12c2, 0x12c5,
+ 0x12c8, 0x12ce,
+ 0x12d0, 0x12d6,
+ 0x12d8, 0x12ee,
+ 0x12f0, 0x130e,
+ 0x1310, 0x1310,
+ 0x1312, 0x1315,
+ 0x1318, 0x131e,
+ 0x1320, 0x1346,
+ 0x1348, 0x135a,
+ 0x1361, 0x137c,
+ 0x13a0, 0x13f4,
+ 0x1401, 0x1676,
+ 0x1680, 0x169c,
+ 0x16a0, 0x16f0,
+ 0x1700, 0x170c,
+ 0x170e, 0x1714,
+ 0x1720, 0x1736,
+ 0x1740, 0x1753,
+ 0x1760, 0x176c,
+ 0x176e, 0x1770,
+ 0x1772, 0x1773,
+ 0x1780, 0x17dd,
+ 0x17e0, 0x17e9,
+ 0x17f0, 0x17f9,
+ 0x1800, 0x180e,
+ 0x1810, 0x1819,
+ 0x1820, 0x1877,
+ 0x1880, 0x18a9,
+ 0x1900, 0x191c,
+ 0x1920, 0x192b,
+ 0x1930, 0x193b,
+ 0x1940, 0x1940,
+ 0x1944, 0x196d,
+ 0x1970, 0x1974,
+ 0x19e0, 0x19ff,
+ 0x1d00, 0x1d6b,
+ 0x1e00, 0x1e9b,
+ 0x1ea0, 0x1ef9,
+ 0x1f00, 0x1f15,
+ 0x1f18, 0x1f1d,
+ 0x1f20, 0x1f45,
+ 0x1f48, 0x1f4d,
+ 0x1f50, 0x1f57,
+ 0x1f59, 0x1f59,
+ 0x1f5b, 0x1f5b,
+ 0x1f5d, 0x1f5d,
+ 0x1f5f, 0x1f7d,
+ 0x1f80, 0x1fb4,
+ 0x1fb6, 0x1fc4,
+ 0x1fc6, 0x1fd3,
+ 0x1fd6, 0x1fdb,
+ 0x1fdd, 0x1fef,
+ 0x1ff2, 0x1ff4,
+ 0x1ff6, 0x1ffe,
+ 0x2000, 0x2054,
+ 0x2057, 0x2057,
+ 0x205f, 0x2063,
+ 0x206a, 0x2071,
+ 0x2074, 0x208e,
+ 0x20a0, 0x20b1,
+ 0x20d0, 0x20ea,
+ 0x2100, 0x213b,
+ 0x213d, 0x214b,
+ 0x2153, 0x2183,
+ 0x2190, 0x23d0,
+ 0x2400, 0x2426,
+ 0x2440, 0x244a,
+ 0x2460, 0x2617,
+ 0x2619, 0x267d,
+ 0x2680, 0x2691,
+ 0x26a0, 0x26a1,
+ 0x2701, 0x2704,
+ 0x2706, 0x2709,
+ 0x270c, 0x2727,
+ 0x2729, 0x274b,
+ 0x274d, 0x274d,
+ 0x274f, 0x2752,
+ 0x2756, 0x2756,
+ 0x2758, 0x275e,
+ 0x2761, 0x2794,
+ 0x2798, 0x27af,
+ 0x27b1, 0x27be,
+ 0x27d0, 0x27eb,
+ 0x27f0, 0x2b0d,
+ 0x2e80, 0x2e99,
+ 0x2e9b, 0x2ef3,
+ 0x2f00, 0x2fd5,
+ 0x2ff0, 0x2ffb,
+ 0x3000, 0x303f,
+ 0x3041, 0x3096,
+ 0x3099, 0x30ff,
+ 0x3105, 0x312c,
+ 0x3131, 0x318e,
+ 0x3190, 0x31b7,
+ 0x31f0, 0x321e,
+ 0x3220, 0x3243,
+ 0x3250, 0x327d,
+ 0x327f, 0x32fe,
+ 0x3300, 0x4db5,
+ 0x4dc0, 0x9fa5,
+ 0xa000, 0xa48c,
+ 0xa490, 0xa4c6,
+ 0xac00, 0xd7a3,
+ 0xd800, 0xfa2d,
+ 0xfa30, 0xfa6a,
+ 0xfb00, 0xfb06,
+ 0xfb13, 0xfb17,
+ 0xfb1d, 0xfb36,
+ 0xfb38, 0xfb3c,
+ 0xfb3e, 0xfb3e,
+ 0xfb40, 0xfb41,
+ 0xfb43, 0xfb44,
+ 0xfb46, 0xfbb1,
+ 0xfbd3, 0xfd3f,
+ 0xfd50, 0xfd8f,
+ 0xfd92, 0xfdc7,
+ 0xfdd0, 0xfdfd,
+ 0xfe00, 0xfe0f,
+ 0xfe20, 0xfe23,
+ 0xfe30, 0xfe52,
+ 0xfe54, 0xfe66,
+ 0xfe68, 0xfe6b,
+ 0xfe70, 0xfe74,
+ 0xfe76, 0xfefc,
+ 0xfeff, 0xfeff,
+ 0xff01, 0xffbe,
+ 0xffc2, 0xffc7,
+ 0xffca, 0xffcf,
+ 0xffd2, 0xffd7,
+ 0xffda, 0xffdc,
+ 0xffe0, 0xffe6,
+ 0xffe8, 0xffee,
+ 0xfff9, 0x1000b,
+ 0x1000d, 0x10026,
+ 0x10028, 0x1003a,
+ 0x1003c, 0x1003d,
+ 0x1003f, 0x1004d,
+ 0x10050, 0x1005d,
+ 0x10080, 0x100fa,
+ 0x10100, 0x10102,
+ 0x10107, 0x10133,
+ 0x10137, 0x1013f,
+ 0x10300, 0x1031e,
+ 0x10320, 0x10323,
+ 0x10330, 0x1034a,
+ 0x10380, 0x1039d,
+ 0x1039f, 0x1039f,
+ 0x10400, 0x1049d,
+ 0x104a0, 0x104a9,
+ 0x10800, 0x10805,
+ 0x10808, 0x10808,
+ 0x1080a, 0x10835,
+ 0x10837, 0x10838,
+ 0x1083c, 0x1083c,
+ 0x1083f, 0x1083f,
+ 0x1d000, 0x1d0f5,
+ 0x1d100, 0x1d126,
+ 0x1d12a, 0x1d1dd,
+ 0x1d300, 0x1d356,
+ 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, 0x1d6a3,
+ 0x1d6a8, 0x1d7c9,
+ 0x1d7ce, 0x1d7ff,
+ 0x1fffe, 0x2a6d6,
+ 0x2f800, 0x2fa1d,
+ 0x2fffe, 0x2ffff,
+ 0x3fffe, 0x3ffff,
+ 0x4fffe, 0x4ffff,
+ 0x5fffe, 0x5ffff,
+ 0x6fffe, 0x6ffff,
+ 0x7fffe, 0x7ffff,
+ 0x8fffe, 0x8ffff,
+ 0x9fffe, 0x9ffff,
+ 0xafffe, 0xaffff,
+ 0xbfffe, 0xbffff,
+ 0xcfffe, 0xcffff,
+ 0xdfffe, 0xdffff,
+ 0xe0001, 0xe0001,
+ 0xe0020, 0xe007f,
+ 0xe0100, 0xe01ef,
+ 0xefffe, 0x10ffff,
+}; /* CR_Age_4_0 */
+
+/* 'Age_4_1': Derived Age 4.1 */
+static const OnigCodePoint CR_Age_4_1[] = {
+ 430,
+ 0x0000, 0x0241,
+ 0x0250, 0x036f,
+ 0x0374, 0x0375,
+ 0x037a, 0x037a,
+ 0x037e, 0x037e,
+ 0x0384, 0x038a,
+ 0x038c, 0x038c,
+ 0x038e, 0x03a1,
+ 0x03a3, 0x03ce,
+ 0x03d0, 0x0486,
+ 0x0488, 0x04ce,
+ 0x04d0, 0x04f9,
+ 0x0500, 0x050f,
+ 0x0531, 0x0556,
+ 0x0559, 0x055f,
+ 0x0561, 0x0587,
+ 0x0589, 0x058a,
+ 0x0591, 0x05b9,
+ 0x05bb, 0x05c7,
+ 0x05d0, 0x05ea,
+ 0x05f0, 0x05f4,
+ 0x0600, 0x0603,
+ 0x060b, 0x0615,
+ 0x061b, 0x061b,
+ 0x061e, 0x061f,
+ 0x0621, 0x063a,
+ 0x0640, 0x065e,
+ 0x0660, 0x070d,
+ 0x070f, 0x074a,
+ 0x074d, 0x076d,
+ 0x0780, 0x07b1,
+ 0x0901, 0x0939,
+ 0x093c, 0x094d,
+ 0x0950, 0x0954,
+ 0x0958, 0x0970,
+ 0x097d, 0x097d,
+ 0x0981, 0x0983,
+ 0x0985, 0x098c,
+ 0x098f, 0x0990,
+ 0x0993, 0x09a8,
+ 0x09aa, 0x09b0,
+ 0x09b2, 0x09b2,
+ 0x09b6, 0x09b9,
+ 0x09bc, 0x09c4,
+ 0x09c7, 0x09c8,
+ 0x09cb, 0x09ce,
+ 0x09d7, 0x09d7,
+ 0x09dc, 0x09dd,
+ 0x09df, 0x09e3,
+ 0x09e6, 0x09fa,
+ 0x0a01, 0x0a03,
+ 0x0a05, 0x0a0a,
+ 0x0a0f, 0x0a10,
+ 0x0a13, 0x0a28,
+ 0x0a2a, 0x0a30,
+ 0x0a32, 0x0a33,
+ 0x0a35, 0x0a36,
+ 0x0a38, 0x0a39,
+ 0x0a3c, 0x0a3c,
+ 0x0a3e, 0x0a42,
+ 0x0a47, 0x0a48,
+ 0x0a4b, 0x0a4d,
+ 0x0a59, 0x0a5c,
+ 0x0a5e, 0x0a5e,
+ 0x0a66, 0x0a74,
+ 0x0a81, 0x0a83,
+ 0x0a85, 0x0a8d,
+ 0x0a8f, 0x0a91,
+ 0x0a93, 0x0aa8,
+ 0x0aaa, 0x0ab0,
+ 0x0ab2, 0x0ab3,
+ 0x0ab5, 0x0ab9,
+ 0x0abc, 0x0ac5,
+ 0x0ac7, 0x0ac9,
+ 0x0acb, 0x0acd,
+ 0x0ad0, 0x0ad0,
+ 0x0ae0, 0x0ae3,
+ 0x0ae6, 0x0aef,
+ 0x0af1, 0x0af1,
+ 0x0b01, 0x0b03,
+ 0x0b05, 0x0b0c,
+ 0x0b0f, 0x0b10,
+ 0x0b13, 0x0b28,
+ 0x0b2a, 0x0b30,
+ 0x0b32, 0x0b33,
+ 0x0b35, 0x0b39,
+ 0x0b3c, 0x0b43,
+ 0x0b47, 0x0b48,
+ 0x0b4b, 0x0b4d,
+ 0x0b56, 0x0b57,
+ 0x0b5c, 0x0b5d,
+ 0x0b5f, 0x0b61,
+ 0x0b66, 0x0b71,
+ 0x0b82, 0x0b83,
+ 0x0b85, 0x0b8a,
+ 0x0b8e, 0x0b90,
+ 0x0b92, 0x0b95,
+ 0x0b99, 0x0b9a,
+ 0x0b9c, 0x0b9c,
+ 0x0b9e, 0x0b9f,
+ 0x0ba3, 0x0ba4,
+ 0x0ba8, 0x0baa,
+ 0x0bae, 0x0bb9,
+ 0x0bbe, 0x0bc2,
+ 0x0bc6, 0x0bc8,
+ 0x0bca, 0x0bcd,
+ 0x0bd7, 0x0bd7,
+ 0x0be6, 0x0bfa,
+ 0x0c01, 0x0c03,
+ 0x0c05, 0x0c0c,
+ 0x0c0e, 0x0c10,
+ 0x0c12, 0x0c28,
+ 0x0c2a, 0x0c33,
+ 0x0c35, 0x0c39,
+ 0x0c3e, 0x0c44,
+ 0x0c46, 0x0c48,
+ 0x0c4a, 0x0c4d,
+ 0x0c55, 0x0c56,
+ 0x0c60, 0x0c61,
+ 0x0c66, 0x0c6f,
+ 0x0c82, 0x0c83,
+ 0x0c85, 0x0c8c,
+ 0x0c8e, 0x0c90,
+ 0x0c92, 0x0ca8,
+ 0x0caa, 0x0cb3,
+ 0x0cb5, 0x0cb9,
+ 0x0cbc, 0x0cc4,
+ 0x0cc6, 0x0cc8,
+ 0x0cca, 0x0ccd,
+ 0x0cd5, 0x0cd6,
+ 0x0cde, 0x0cde,
+ 0x0ce0, 0x0ce1,
+ 0x0ce6, 0x0cef,
+ 0x0d02, 0x0d03,
+ 0x0d05, 0x0d0c,
+ 0x0d0e, 0x0d10,
+ 0x0d12, 0x0d28,
+ 0x0d2a, 0x0d39,
+ 0x0d3e, 0x0d43,
+ 0x0d46, 0x0d48,
+ 0x0d4a, 0x0d4d,
+ 0x0d57, 0x0d57,
+ 0x0d60, 0x0d61,
+ 0x0d66, 0x0d6f,
+ 0x0d82, 0x0d83,
+ 0x0d85, 0x0d96,
+ 0x0d9a, 0x0db1,
+ 0x0db3, 0x0dbb,
+ 0x0dbd, 0x0dbd,
+ 0x0dc0, 0x0dc6,
+ 0x0dca, 0x0dca,
+ 0x0dcf, 0x0dd4,
+ 0x0dd6, 0x0dd6,
+ 0x0dd8, 0x0ddf,
+ 0x0df2, 0x0df4,
+ 0x0e01, 0x0e3a,
+ 0x0e3f, 0x0e5b,
+ 0x0e81, 0x0e82,
+ 0x0e84, 0x0e84,
+ 0x0e87, 0x0e88,
+ 0x0e8a, 0x0e8a,
+ 0x0e8d, 0x0e8d,
+ 0x0e94, 0x0e97,
+ 0x0e99, 0x0e9f,
+ 0x0ea1, 0x0ea3,
+ 0x0ea5, 0x0ea5,
+ 0x0ea7, 0x0ea7,
+ 0x0eaa, 0x0eab,
+ 0x0ead, 0x0eb9,
+ 0x0ebb, 0x0ebd,
+ 0x0ec0, 0x0ec4,
+ 0x0ec6, 0x0ec6,
+ 0x0ec8, 0x0ecd,
+ 0x0ed0, 0x0ed9,
+ 0x0edc, 0x0edd,
+ 0x0f00, 0x0f47,
+ 0x0f49, 0x0f6a,
+ 0x0f71, 0x0f8b,
+ 0x0f90, 0x0f97,
+ 0x0f99, 0x0fbc,
+ 0x0fbe, 0x0fcc,
+ 0x0fcf, 0x0fd1,
+ 0x1000, 0x1021,
+ 0x1023, 0x1027,
+ 0x1029, 0x102a,
+ 0x102c, 0x1032,
+ 0x1036, 0x1039,
+ 0x1040, 0x1059,
+ 0x10a0, 0x10c5,
+ 0x10d0, 0x10fc,
+ 0x1100, 0x1159,
+ 0x115f, 0x11a2,
+ 0x11a8, 0x11f9,
+ 0x1200, 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,
+ 0x135f, 0x137c,
+ 0x1380, 0x1399,
+ 0x13a0, 0x13f4,
+ 0x1401, 0x1676,
+ 0x1680, 0x169c,
+ 0x16a0, 0x16f0,
+ 0x1700, 0x170c,
+ 0x170e, 0x1714,
+ 0x1720, 0x1736,
+ 0x1740, 0x1753,
+ 0x1760, 0x176c,
+ 0x176e, 0x1770,
+ 0x1772, 0x1773,
+ 0x1780, 0x17dd,
+ 0x17e0, 0x17e9,
+ 0x17f0, 0x17f9,
+ 0x1800, 0x180e,
+ 0x1810, 0x1819,
+ 0x1820, 0x1877,
+ 0x1880, 0x18a9,
+ 0x1900, 0x191c,
+ 0x1920, 0x192b,
+ 0x1930, 0x193b,
+ 0x1940, 0x1940,
+ 0x1944, 0x196d,
+ 0x1970, 0x1974,
+ 0x1980, 0x19a9,
+ 0x19b0, 0x19c9,
+ 0x19d0, 0x19d9,
+ 0x19de, 0x1a1b,
+ 0x1a1e, 0x1a1f,
+ 0x1d00, 0x1dc3,
+ 0x1e00, 0x1e9b,
+ 0x1ea0, 0x1ef9,
+ 0x1f00, 0x1f15,
+ 0x1f18, 0x1f1d,
+ 0x1f20, 0x1f45,
+ 0x1f48, 0x1f4d,
+ 0x1f50, 0x1f57,
+ 0x1f59, 0x1f59,
+ 0x1f5b, 0x1f5b,
+ 0x1f5d, 0x1f5d,
+ 0x1f5f, 0x1f7d,
+ 0x1f80, 0x1fb4,
+ 0x1fb6, 0x1fc4,
+ 0x1fc6, 0x1fd3,
+ 0x1fd6, 0x1fdb,
+ 0x1fdd, 0x1fef,
+ 0x1ff2, 0x1ff4,
+ 0x1ff6, 0x1ffe,
+ 0x2000, 0x2063,
+ 0x206a, 0x2071,
+ 0x2074, 0x208e,
+ 0x2090, 0x2094,
+ 0x20a0, 0x20b5,
+ 0x20d0, 0x20eb,
+ 0x2100, 0x214c,
+ 0x2153, 0x2183,
+ 0x2190, 0x23db,
+ 0x2400, 0x2426,
+ 0x2440, 0x244a,
+ 0x2460, 0x269c,
+ 0x26a0, 0x26b1,
+ 0x2701, 0x2704,
+ 0x2706, 0x2709,
+ 0x270c, 0x2727,
+ 0x2729, 0x274b,
+ 0x274d, 0x274d,
+ 0x274f, 0x2752,
+ 0x2756, 0x2756,
+ 0x2758, 0x275e,
+ 0x2761, 0x2794,
+ 0x2798, 0x27af,
+ 0x27b1, 0x27be,
+ 0x27c0, 0x27c6,
+ 0x27d0, 0x27eb,
+ 0x27f0, 0x2b13,
+ 0x2c00, 0x2c2e,
+ 0x2c30, 0x2c5e,
+ 0x2c80, 0x2cea,
+ 0x2cf9, 0x2d25,
+ 0x2d30, 0x2d65,
+ 0x2d6f, 0x2d6f,
+ 0x2d80, 0x2d96,
+ 0x2da0, 0x2da6,
+ 0x2da8, 0x2dae,
+ 0x2db0, 0x2db6,
+ 0x2db8, 0x2dbe,
+ 0x2dc0, 0x2dc6,
+ 0x2dc8, 0x2dce,
+ 0x2dd0, 0x2dd6,
+ 0x2dd8, 0x2dde,
+ 0x2e00, 0x2e17,
+ 0x2e1c, 0x2e1d,
+ 0x2e80, 0x2e99,
+ 0x2e9b, 0x2ef3,
+ 0x2f00, 0x2fd5,
+ 0x2ff0, 0x2ffb,
+ 0x3000, 0x303f,
+ 0x3041, 0x3096,
+ 0x3099, 0x30ff,
+ 0x3105, 0x312c,
+ 0x3131, 0x318e,
+ 0x3190, 0x31b7,
+ 0x31c0, 0x31cf,
+ 0x31f0, 0x321e,
+ 0x3220, 0x3243,
+ 0x3250, 0x32fe,
+ 0x3300, 0x4db5,
+ 0x4dc0, 0x9fbb,
+ 0xa000, 0xa48c,
+ 0xa490, 0xa4c6,
+ 0xa700, 0xa716,
+ 0xa800, 0xa82b,
+ 0xac00, 0xd7a3,
+ 0xd800, 0xfa2d,
+ 0xfa30, 0xfa6a,
+ 0xfa70, 0xfad9,
+ 0xfb00, 0xfb06,
+ 0xfb13, 0xfb17,
+ 0xfb1d, 0xfb36,
+ 0xfb38, 0xfb3c,
+ 0xfb3e, 0xfb3e,
+ 0xfb40, 0xfb41,
+ 0xfb43, 0xfb44,
+ 0xfb46, 0xfbb1,
+ 0xfbd3, 0xfd3f,
+ 0xfd50, 0xfd8f,
+ 0xfd92, 0xfdc7,
+ 0xfdd0, 0xfdfd,
+ 0xfe00, 0xfe19,
+ 0xfe20, 0xfe23,
+ 0xfe30, 0xfe52,
+ 0xfe54, 0xfe66,
+ 0xfe68, 0xfe6b,
+ 0xfe70, 0xfe74,
+ 0xfe76, 0xfefc,
+ 0xfeff, 0xfeff,
+ 0xff01, 0xffbe,
+ 0xffc2, 0xffc7,
+ 0xffca, 0xffcf,
+ 0xffd2, 0xffd7,
+ 0xffda, 0xffdc,
+ 0xffe0, 0xffe6,
+ 0xffe8, 0xffee,
+ 0xfff9, 0x1000b,
+ 0x1000d, 0x10026,
+ 0x10028, 0x1003a,
+ 0x1003c, 0x1003d,
+ 0x1003f, 0x1004d,
+ 0x10050, 0x1005d,
+ 0x10080, 0x100fa,
+ 0x10100, 0x10102,
+ 0x10107, 0x10133,
+ 0x10137, 0x1018a,
+ 0x10300, 0x1031e,
+ 0x10320, 0x10323,
+ 0x10330, 0x1034a,
+ 0x10380, 0x1039d,
+ 0x1039f, 0x103c3,
+ 0x103c8, 0x103d5,
+ 0x10400, 0x1049d,
+ 0x104a0, 0x104a9,
+ 0x10800, 0x10805,
+ 0x10808, 0x10808,
+ 0x1080a, 0x10835,
+ 0x10837, 0x10838,
+ 0x1083c, 0x1083c,
+ 0x1083f, 0x1083f,
+ 0x10a00, 0x10a03,
+ 0x10a05, 0x10a06,
+ 0x10a0c, 0x10a13,
+ 0x10a15, 0x10a17,
+ 0x10a19, 0x10a33,
+ 0x10a38, 0x10a3a,
+ 0x10a3f, 0x10a47,
+ 0x10a50, 0x10a58,
+ 0x1d000, 0x1d0f5,
+ 0x1d100, 0x1d126,
+ 0x1d12a, 0x1d1dd,
+ 0x1d200, 0x1d245,
+ 0x1d300, 0x1d356,
+ 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, 0x1d7c9,
+ 0x1d7ce, 0x1d7ff,
+ 0x1fffe, 0x2a6d6,
+ 0x2f800, 0x2fa1d,
+ 0x2fffe, 0x2ffff,
+ 0x3fffe, 0x3ffff,
+ 0x4fffe, 0x4ffff,
+ 0x5fffe, 0x5ffff,
+ 0x6fffe, 0x6ffff,
+ 0x7fffe, 0x7ffff,
+ 0x8fffe, 0x8ffff,
+ 0x9fffe, 0x9ffff,
+ 0xafffe, 0xaffff,
+ 0xbfffe, 0xbffff,
+ 0xcfffe, 0xcffff,
+ 0xdfffe, 0xdffff,
+ 0xe0001, 0xe0001,
+ 0xe0020, 0xe007f,
+ 0xe0100, 0xe01ef,
+ 0xefffe, 0x10ffff,
+}; /* CR_Age_4_1 */
+
+/* 'Age_5_0': Derived Age 5.0 */
+static const OnigCodePoint CR_Age_5_0[] = {
+ 440,
+ 0x0000, 0x036f,
+ 0x0374, 0x0375,
+ 0x037a, 0x037e,
+ 0x0384, 0x038a,
+ 0x038c, 0x038c,
+ 0x038e, 0x03a1,
+ 0x03a3, 0x03ce,
+ 0x03d0, 0x0486,
+ 0x0488, 0x0513,
+ 0x0531, 0x0556,
+ 0x0559, 0x055f,
+ 0x0561, 0x0587,
+ 0x0589, 0x058a,
+ 0x0591, 0x05c7,
+ 0x05d0, 0x05ea,
+ 0x05f0, 0x05f4,
+ 0x0600, 0x0603,
+ 0x060b, 0x0615,
+ 0x061b, 0x061b,
+ 0x061e, 0x061f,
+ 0x0621, 0x063a,
+ 0x0640, 0x065e,
+ 0x0660, 0x070d,
+ 0x070f, 0x074a,
+ 0x074d, 0x076d,
+ 0x0780, 0x07b1,
+ 0x07c0, 0x07fa,
+ 0x0901, 0x0939,
+ 0x093c, 0x094d,
+ 0x0950, 0x0954,
+ 0x0958, 0x0970,
+ 0x097b, 0x097f,
+ 0x0981, 0x0983,
+ 0x0985, 0x098c,
+ 0x098f, 0x0990,
+ 0x0993, 0x09a8,
+ 0x09aa, 0x09b0,
+ 0x09b2, 0x09b2,
+ 0x09b6, 0x09b9,
+ 0x09bc, 0x09c4,
+ 0x09c7, 0x09c8,
+ 0x09cb, 0x09ce,
+ 0x09d7, 0x09d7,
+ 0x09dc, 0x09dd,
+ 0x09df, 0x09e3,
+ 0x09e6, 0x09fa,
+ 0x0a01, 0x0a03,
+ 0x0a05, 0x0a0a,
+ 0x0a0f, 0x0a10,
+ 0x0a13, 0x0a28,
+ 0x0a2a, 0x0a30,
+ 0x0a32, 0x0a33,
+ 0x0a35, 0x0a36,
+ 0x0a38, 0x0a39,
+ 0x0a3c, 0x0a3c,
+ 0x0a3e, 0x0a42,
+ 0x0a47, 0x0a48,
+ 0x0a4b, 0x0a4d,
+ 0x0a59, 0x0a5c,
+ 0x0a5e, 0x0a5e,
+ 0x0a66, 0x0a74,
+ 0x0a81, 0x0a83,
+ 0x0a85, 0x0a8d,
+ 0x0a8f, 0x0a91,
+ 0x0a93, 0x0aa8,
+ 0x0aaa, 0x0ab0,
+ 0x0ab2, 0x0ab3,
+ 0x0ab5, 0x0ab9,
+ 0x0abc, 0x0ac5,
+ 0x0ac7, 0x0ac9,
+ 0x0acb, 0x0acd,
+ 0x0ad0, 0x0ad0,
+ 0x0ae0, 0x0ae3,
+ 0x0ae6, 0x0aef,
+ 0x0af1, 0x0af1,
+ 0x0b01, 0x0b03,
+ 0x0b05, 0x0b0c,
+ 0x0b0f, 0x0b10,
+ 0x0b13, 0x0b28,
+ 0x0b2a, 0x0b30,
+ 0x0b32, 0x0b33,
+ 0x0b35, 0x0b39,
+ 0x0b3c, 0x0b43,
+ 0x0b47, 0x0b48,
+ 0x0b4b, 0x0b4d,
+ 0x0b56, 0x0b57,
+ 0x0b5c, 0x0b5d,
+ 0x0b5f, 0x0b61,
+ 0x0b66, 0x0b71,
+ 0x0b82, 0x0b83,
+ 0x0b85, 0x0b8a,
+ 0x0b8e, 0x0b90,
+ 0x0b92, 0x0b95,
+ 0x0b99, 0x0b9a,
+ 0x0b9c, 0x0b9c,
+ 0x0b9e, 0x0b9f,
+ 0x0ba3, 0x0ba4,
+ 0x0ba8, 0x0baa,
+ 0x0bae, 0x0bb9,
+ 0x0bbe, 0x0bc2,
+ 0x0bc6, 0x0bc8,
+ 0x0bca, 0x0bcd,
+ 0x0bd7, 0x0bd7,
+ 0x0be6, 0x0bfa,
+ 0x0c01, 0x0c03,
+ 0x0c05, 0x0c0c,
+ 0x0c0e, 0x0c10,
+ 0x0c12, 0x0c28,
+ 0x0c2a, 0x0c33,
+ 0x0c35, 0x0c39,
+ 0x0c3e, 0x0c44,
+ 0x0c46, 0x0c48,
+ 0x0c4a, 0x0c4d,
+ 0x0c55, 0x0c56,
+ 0x0c60, 0x0c61,
+ 0x0c66, 0x0c6f,
+ 0x0c82, 0x0c83,
+ 0x0c85, 0x0c8c,
+ 0x0c8e, 0x0c90,
+ 0x0c92, 0x0ca8,
+ 0x0caa, 0x0cb3,
+ 0x0cb5, 0x0cb9,
+ 0x0cbc, 0x0cc4,
+ 0x0cc6, 0x0cc8,
+ 0x0cca, 0x0ccd,
+ 0x0cd5, 0x0cd6,
+ 0x0cde, 0x0cde,
+ 0x0ce0, 0x0ce3,
+ 0x0ce6, 0x0cef,
+ 0x0cf1, 0x0cf2,
+ 0x0d02, 0x0d03,
+ 0x0d05, 0x0d0c,
+ 0x0d0e, 0x0d10,
+ 0x0d12, 0x0d28,
+ 0x0d2a, 0x0d39,
+ 0x0d3e, 0x0d43,
+ 0x0d46, 0x0d48,
+ 0x0d4a, 0x0d4d,
+ 0x0d57, 0x0d57,
+ 0x0d60, 0x0d61,
+ 0x0d66, 0x0d6f,
+ 0x0d82, 0x0d83,
+ 0x0d85, 0x0d96,
+ 0x0d9a, 0x0db1,
+ 0x0db3, 0x0dbb,
+ 0x0dbd, 0x0dbd,
+ 0x0dc0, 0x0dc6,
+ 0x0dca, 0x0dca,
+ 0x0dcf, 0x0dd4,
+ 0x0dd6, 0x0dd6,
+ 0x0dd8, 0x0ddf,
+ 0x0df2, 0x0df4,
+ 0x0e01, 0x0e3a,
+ 0x0e3f, 0x0e5b,
+ 0x0e81, 0x0e82,
+ 0x0e84, 0x0e84,
+ 0x0e87, 0x0e88,
+ 0x0e8a, 0x0e8a,
+ 0x0e8d, 0x0e8d,
+ 0x0e94, 0x0e97,
+ 0x0e99, 0x0e9f,
+ 0x0ea1, 0x0ea3,
+ 0x0ea5, 0x0ea5,
+ 0x0ea7, 0x0ea7,
+ 0x0eaa, 0x0eab,
+ 0x0ead, 0x0eb9,
+ 0x0ebb, 0x0ebd,
+ 0x0ec0, 0x0ec4,
+ 0x0ec6, 0x0ec6,
+ 0x0ec8, 0x0ecd,
+ 0x0ed0, 0x0ed9,
+ 0x0edc, 0x0edd,
+ 0x0f00, 0x0f47,
+ 0x0f49, 0x0f6a,
+ 0x0f71, 0x0f8b,
+ 0x0f90, 0x0f97,
+ 0x0f99, 0x0fbc,
+ 0x0fbe, 0x0fcc,
+ 0x0fcf, 0x0fd1,
+ 0x1000, 0x1021,
+ 0x1023, 0x1027,
+ 0x1029, 0x102a,
+ 0x102c, 0x1032,
+ 0x1036, 0x1039,
+ 0x1040, 0x1059,
+ 0x10a0, 0x10c5,
+ 0x10d0, 0x10fc,
+ 0x1100, 0x1159,
+ 0x115f, 0x11a2,
+ 0x11a8, 0x11f9,
+ 0x1200, 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,
+ 0x135f, 0x137c,
+ 0x1380, 0x1399,
+ 0x13a0, 0x13f4,
+ 0x1401, 0x1676,
+ 0x1680, 0x169c,
+ 0x16a0, 0x16f0,
+ 0x1700, 0x170c,
+ 0x170e, 0x1714,
+ 0x1720, 0x1736,
+ 0x1740, 0x1753,
+ 0x1760, 0x176c,
+ 0x176e, 0x1770,
+ 0x1772, 0x1773,
+ 0x1780, 0x17dd,
+ 0x17e0, 0x17e9,
+ 0x17f0, 0x17f9,
+ 0x1800, 0x180e,
+ 0x1810, 0x1819,
+ 0x1820, 0x1877,
+ 0x1880, 0x18a9,
+ 0x1900, 0x191c,
+ 0x1920, 0x192b,
+ 0x1930, 0x193b,
+ 0x1940, 0x1940,
+ 0x1944, 0x196d,
+ 0x1970, 0x1974,
+ 0x1980, 0x19a9,
+ 0x19b0, 0x19c9,
+ 0x19d0, 0x19d9,
+ 0x19de, 0x1a1b,
+ 0x1a1e, 0x1a1f,
+ 0x1b00, 0x1b4b,
+ 0x1b50, 0x1b7c,
+ 0x1d00, 0x1dca,
+ 0x1dfe, 0x1e9b,
+ 0x1ea0, 0x1ef9,
+ 0x1f00, 0x1f15,
+ 0x1f18, 0x1f1d,
+ 0x1f20, 0x1f45,
+ 0x1f48, 0x1f4d,
+ 0x1f50, 0x1f57,
+ 0x1f59, 0x1f59,
+ 0x1f5b, 0x1f5b,
+ 0x1f5d, 0x1f5d,
+ 0x1f5f, 0x1f7d,
+ 0x1f80, 0x1fb4,
+ 0x1fb6, 0x1fc4,
+ 0x1fc6, 0x1fd3,
+ 0x1fd6, 0x1fdb,
+ 0x1fdd, 0x1fef,
+ 0x1ff2, 0x1ff4,
+ 0x1ff6, 0x1ffe,
+ 0x2000, 0x2063,
+ 0x206a, 0x2071,
+ 0x2074, 0x208e,
+ 0x2090, 0x2094,
+ 0x20a0, 0x20b5,
+ 0x20d0, 0x20ef,
+ 0x2100, 0x214e,
+ 0x2153, 0x2184,
+ 0x2190, 0x23e7,
+ 0x2400, 0x2426,
+ 0x2440, 0x244a,
+ 0x2460, 0x269c,
+ 0x26a0, 0x26b2,
+ 0x2701, 0x2704,
+ 0x2706, 0x2709,
+ 0x270c, 0x2727,
+ 0x2729, 0x274b,
+ 0x274d, 0x274d,
+ 0x274f, 0x2752,
+ 0x2756, 0x2756,
+ 0x2758, 0x275e,
+ 0x2761, 0x2794,
+ 0x2798, 0x27af,
+ 0x27b1, 0x27be,
+ 0x27c0, 0x27ca,
+ 0x27d0, 0x27eb,
+ 0x27f0, 0x2b1a,
+ 0x2b20, 0x2b23,
+ 0x2c00, 0x2c2e,
+ 0x2c30, 0x2c5e,
+ 0x2c60, 0x2c6c,
+ 0x2c74, 0x2c77,
+ 0x2c80, 0x2cea,
+ 0x2cf9, 0x2d25,
+ 0x2d30, 0x2d65,
+ 0x2d6f, 0x2d6f,
+ 0x2d80, 0x2d96,
+ 0x2da0, 0x2da6,
+ 0x2da8, 0x2dae,
+ 0x2db0, 0x2db6,
+ 0x2db8, 0x2dbe,
+ 0x2dc0, 0x2dc6,
+ 0x2dc8, 0x2dce,
+ 0x2dd0, 0x2dd6,
+ 0x2dd8, 0x2dde,
+ 0x2e00, 0x2e17,
+ 0x2e1c, 0x2e1d,
+ 0x2e80, 0x2e99,
+ 0x2e9b, 0x2ef3,
+ 0x2f00, 0x2fd5,
+ 0x2ff0, 0x2ffb,
+ 0x3000, 0x303f,
+ 0x3041, 0x3096,
+ 0x3099, 0x30ff,
+ 0x3105, 0x312c,
+ 0x3131, 0x318e,
+ 0x3190, 0x31b7,
+ 0x31c0, 0x31cf,
+ 0x31f0, 0x321e,
+ 0x3220, 0x3243,
+ 0x3250, 0x32fe,
+ 0x3300, 0x4db5,
+ 0x4dc0, 0x9fbb,
+ 0xa000, 0xa48c,
+ 0xa490, 0xa4c6,
+ 0xa700, 0xa71a,
+ 0xa720, 0xa721,
+ 0xa800, 0xa82b,
+ 0xa840, 0xa877,
+ 0xac00, 0xd7a3,
+ 0xd800, 0xfa2d,
+ 0xfa30, 0xfa6a,
+ 0xfa70, 0xfad9,
+ 0xfb00, 0xfb06,
+ 0xfb13, 0xfb17,
+ 0xfb1d, 0xfb36,
+ 0xfb38, 0xfb3c,
+ 0xfb3e, 0xfb3e,
+ 0xfb40, 0xfb41,
+ 0xfb43, 0xfb44,
+ 0xfb46, 0xfbb1,
+ 0xfbd3, 0xfd3f,
+ 0xfd50, 0xfd8f,
+ 0xfd92, 0xfdc7,
+ 0xfdd0, 0xfdfd,
+ 0xfe00, 0xfe19,
+ 0xfe20, 0xfe23,
+ 0xfe30, 0xfe52,
+ 0xfe54, 0xfe66,
+ 0xfe68, 0xfe6b,
+ 0xfe70, 0xfe74,
+ 0xfe76, 0xfefc,
+ 0xfeff, 0xfeff,
+ 0xff01, 0xffbe,
+ 0xffc2, 0xffc7,
+ 0xffca, 0xffcf,
+ 0xffd2, 0xffd7,
+ 0xffda, 0xffdc,
+ 0xffe0, 0xffe6,
+ 0xffe8, 0xffee,
+ 0xfff9, 0x1000b,
+ 0x1000d, 0x10026,
+ 0x10028, 0x1003a,
+ 0x1003c, 0x1003d,
+ 0x1003f, 0x1004d,
+ 0x10050, 0x1005d,
+ 0x10080, 0x100fa,
+ 0x10100, 0x10102,
+ 0x10107, 0x10133,
+ 0x10137, 0x1018a,
+ 0x10300, 0x1031e,
+ 0x10320, 0x10323,
+ 0x10330, 0x1034a,
+ 0x10380, 0x1039d,
+ 0x1039f, 0x103c3,
+ 0x103c8, 0x103d5,
+ 0x10400, 0x1049d,
+ 0x104a0, 0x104a9,
+ 0x10800, 0x10805,
+ 0x10808, 0x10808,
+ 0x1080a, 0x10835,
+ 0x10837, 0x10838,
+ 0x1083c, 0x1083c,
+ 0x1083f, 0x1083f,
+ 0x10900, 0x10919,
+ 0x1091f, 0x1091f,
+ 0x10a00, 0x10a03,
+ 0x10a05, 0x10a06,
+ 0x10a0c, 0x10a13,
+ 0x10a15, 0x10a17,
+ 0x10a19, 0x10a33,
+ 0x10a38, 0x10a3a,
+ 0x10a3f, 0x10a47,
+ 0x10a50, 0x10a58,
+ 0x12000, 0x1236e,
+ 0x12400, 0x12462,
+ 0x12470, 0x12473,
+ 0x1d000, 0x1d0f5,
+ 0x1d100, 0x1d126,
+ 0x1d12a, 0x1d1dd,
+ 0x1d200, 0x1d245,
+ 0x1d300, 0x1d356,
+ 0x1d360, 0x1d371,
+ 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, 0x1d7cb,
+ 0x1d7ce, 0x1d7ff,
+ 0x1fffe, 0x2a6d6,
+ 0x2f800, 0x2fa1d,
+ 0x2fffe, 0x2ffff,
+ 0x3fffe, 0x3ffff,
+ 0x4fffe, 0x4ffff,
+ 0x5fffe, 0x5ffff,
+ 0x6fffe, 0x6ffff,
+ 0x7fffe, 0x7ffff,
+ 0x8fffe, 0x8ffff,
+ 0x9fffe, 0x9ffff,
+ 0xafffe, 0xaffff,
+ 0xbfffe, 0xbffff,
+ 0xcfffe, 0xcffff,
+ 0xdfffe, 0xdffff,
+ 0xe0001, 0xe0001,
+ 0xe0020, 0xe007f,
+ 0xe0100, 0xe01ef,
+ 0xefffe, 0x10ffff,
+}; /* CR_Age_5_0 */
+
+/* 'Age_5_1': Derived Age 5.1 */
+static const OnigCodePoint CR_Age_5_1[] = {
+ 455,
+ 0x0000, 0x0377,
+ 0x037a, 0x037e,
+ 0x0384, 0x038a,
+ 0x038c, 0x038c,
+ 0x038e, 0x03a1,
+ 0x03a3, 0x0523,
+ 0x0531, 0x0556,
+ 0x0559, 0x055f,
+ 0x0561, 0x0587,
+ 0x0589, 0x058a,
+ 0x0591, 0x05c7,
+ 0x05d0, 0x05ea,
+ 0x05f0, 0x05f4,
+ 0x0600, 0x0603,
+ 0x0606, 0x061b,
+ 0x061e, 0x061f,
+ 0x0621, 0x065e,
+ 0x0660, 0x070d,
+ 0x070f, 0x074a,
+ 0x074d, 0x07b1,
+ 0x07c0, 0x07fa,
+ 0x0901, 0x0939,
+ 0x093c, 0x094d,
+ 0x0950, 0x0954,
+ 0x0958, 0x0972,
+ 0x097b, 0x097f,
+ 0x0981, 0x0983,
+ 0x0985, 0x098c,
+ 0x098f, 0x0990,
+ 0x0993, 0x09a8,
+ 0x09aa, 0x09b0,
+ 0x09b2, 0x09b2,
+ 0x09b6, 0x09b9,
+ 0x09bc, 0x09c4,
+ 0x09c7, 0x09c8,
+ 0x09cb, 0x09ce,
+ 0x09d7, 0x09d7,
+ 0x09dc, 0x09dd,
+ 0x09df, 0x09e3,
+ 0x09e6, 0x09fa,
+ 0x0a01, 0x0a03,
+ 0x0a05, 0x0a0a,
+ 0x0a0f, 0x0a10,
+ 0x0a13, 0x0a28,
+ 0x0a2a, 0x0a30,
+ 0x0a32, 0x0a33,
+ 0x0a35, 0x0a36,
+ 0x0a38, 0x0a39,
+ 0x0a3c, 0x0a3c,
+ 0x0a3e, 0x0a42,
+ 0x0a47, 0x0a48,
+ 0x0a4b, 0x0a4d,
+ 0x0a51, 0x0a51,
+ 0x0a59, 0x0a5c,
+ 0x0a5e, 0x0a5e,
+ 0x0a66, 0x0a75,
+ 0x0a81, 0x0a83,
+ 0x0a85, 0x0a8d,
+ 0x0a8f, 0x0a91,
+ 0x0a93, 0x0aa8,
+ 0x0aaa, 0x0ab0,
+ 0x0ab2, 0x0ab3,
+ 0x0ab5, 0x0ab9,
+ 0x0abc, 0x0ac5,
+ 0x0ac7, 0x0ac9,
+ 0x0acb, 0x0acd,
+ 0x0ad0, 0x0ad0,
+ 0x0ae0, 0x0ae3,
+ 0x0ae6, 0x0aef,
+ 0x0af1, 0x0af1,
+ 0x0b01, 0x0b03,
+ 0x0b05, 0x0b0c,
+ 0x0b0f, 0x0b10,
+ 0x0b13, 0x0b28,
+ 0x0b2a, 0x0b30,
+ 0x0b32, 0x0b33,
+ 0x0b35, 0x0b39,
+ 0x0b3c, 0x0b44,
+ 0x0b47, 0x0b48,
+ 0x0b4b, 0x0b4d,
+ 0x0b56, 0x0b57,
+ 0x0b5c, 0x0b5d,
+ 0x0b5f, 0x0b63,
+ 0x0b66, 0x0b71,
+ 0x0b82, 0x0b83,
+ 0x0b85, 0x0b8a,
+ 0x0b8e, 0x0b90,
+ 0x0b92, 0x0b95,
+ 0x0b99, 0x0b9a,
+ 0x0b9c, 0x0b9c,
+ 0x0b9e, 0x0b9f,
+ 0x0ba3, 0x0ba4,
+ 0x0ba8, 0x0baa,
+ 0x0bae, 0x0bb9,
+ 0x0bbe, 0x0bc2,
+ 0x0bc6, 0x0bc8,
+ 0x0bca, 0x0bcd,
+ 0x0bd0, 0x0bd0,
+ 0x0bd7, 0x0bd7,
+ 0x0be6, 0x0bfa,
+ 0x0c01, 0x0c03,
+ 0x0c05, 0x0c0c,
+ 0x0c0e, 0x0c10,
+ 0x0c12, 0x0c28,
+ 0x0c2a, 0x0c33,
+ 0x0c35, 0x0c39,
+ 0x0c3d, 0x0c44,
+ 0x0c46, 0x0c48,
+ 0x0c4a, 0x0c4d,
+ 0x0c55, 0x0c56,
+ 0x0c58, 0x0c59,
+ 0x0c60, 0x0c63,
+ 0x0c66, 0x0c6f,
+ 0x0c78, 0x0c7f,
+ 0x0c82, 0x0c83,
+ 0x0c85, 0x0c8c,
+ 0x0c8e, 0x0c90,
+ 0x0c92, 0x0ca8,
+ 0x0caa, 0x0cb3,
+ 0x0cb5, 0x0cb9,
+ 0x0cbc, 0x0cc4,
+ 0x0cc6, 0x0cc8,
+ 0x0cca, 0x0ccd,
+ 0x0cd5, 0x0cd6,
+ 0x0cde, 0x0cde,
+ 0x0ce0, 0x0ce3,
+ 0x0ce6, 0x0cef,
+ 0x0cf1, 0x0cf2,
+ 0x0d02, 0x0d03,
+ 0x0d05, 0x0d0c,
+ 0x0d0e, 0x0d10,
+ 0x0d12, 0x0d28,
+ 0x0d2a, 0x0d39,
+ 0x0d3d, 0x0d44,
+ 0x0d46, 0x0d48,
+ 0x0d4a, 0x0d4d,
+ 0x0d57, 0x0d57,
+ 0x0d60, 0x0d63,
+ 0x0d66, 0x0d75,
+ 0x0d79, 0x0d7f,
+ 0x0d82, 0x0d83,
+ 0x0d85, 0x0d96,
+ 0x0d9a, 0x0db1,
+ 0x0db3, 0x0dbb,
+ 0x0dbd, 0x0dbd,
+ 0x0dc0, 0x0dc6,
+ 0x0dca, 0x0dca,
+ 0x0dcf, 0x0dd4,
+ 0x0dd6, 0x0dd6,
+ 0x0dd8, 0x0ddf,
+ 0x0df2, 0x0df4,
+ 0x0e01, 0x0e3a,
+ 0x0e3f, 0x0e5b,
+ 0x0e81, 0x0e82,
+ 0x0e84, 0x0e84,
+ 0x0e87, 0x0e88,
+ 0x0e8a, 0x0e8a,
+ 0x0e8d, 0x0e8d,
+ 0x0e94, 0x0e97,
+ 0x0e99, 0x0e9f,
+ 0x0ea1, 0x0ea3,
+ 0x0ea5, 0x0ea5,
+ 0x0ea7, 0x0ea7,
+ 0x0eaa, 0x0eab,
+ 0x0ead, 0x0eb9,
+ 0x0ebb, 0x0ebd,
+ 0x0ec0, 0x0ec4,
+ 0x0ec6, 0x0ec6,
+ 0x0ec8, 0x0ecd,
+ 0x0ed0, 0x0ed9,
+ 0x0edc, 0x0edd,
+ 0x0f00, 0x0f47,
+ 0x0f49, 0x0f6c,
+ 0x0f71, 0x0f8b,
+ 0x0f90, 0x0f97,
+ 0x0f99, 0x0fbc,
+ 0x0fbe, 0x0fcc,
+ 0x0fce, 0x0fd4,
+ 0x1000, 0x1099,
+ 0x109e, 0x10c5,
+ 0x10d0, 0x10fc,
+ 0x1100, 0x1159,
+ 0x115f, 0x11a2,
+ 0x11a8, 0x11f9,
+ 0x1200, 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,
+ 0x135f, 0x137c,
+ 0x1380, 0x1399,
+ 0x13a0, 0x13f4,
+ 0x1401, 0x1676,
+ 0x1680, 0x169c,
+ 0x16a0, 0x16f0,
+ 0x1700, 0x170c,
+ 0x170e, 0x1714,
+ 0x1720, 0x1736,
+ 0x1740, 0x1753,
+ 0x1760, 0x176c,
+ 0x176e, 0x1770,
+ 0x1772, 0x1773,
+ 0x1780, 0x17dd,
+ 0x17e0, 0x17e9,
+ 0x17f0, 0x17f9,
+ 0x1800, 0x180e,
+ 0x1810, 0x1819,
+ 0x1820, 0x1877,
+ 0x1880, 0x18aa,
+ 0x1900, 0x191c,
+ 0x1920, 0x192b,
+ 0x1930, 0x193b,
+ 0x1940, 0x1940,
+ 0x1944, 0x196d,
+ 0x1970, 0x1974,
+ 0x1980, 0x19a9,
+ 0x19b0, 0x19c9,
+ 0x19d0, 0x19d9,
+ 0x19de, 0x1a1b,
+ 0x1a1e, 0x1a1f,
+ 0x1b00, 0x1b4b,
+ 0x1b50, 0x1b7c,
+ 0x1b80, 0x1baa,
+ 0x1bae, 0x1bb9,
+ 0x1c00, 0x1c37,
+ 0x1c3b, 0x1c49,
+ 0x1c4d, 0x1c7f,
+ 0x1d00, 0x1de6,
+ 0x1dfe, 0x1f15,
+ 0x1f18, 0x1f1d,
+ 0x1f20, 0x1f45,
+ 0x1f48, 0x1f4d,
+ 0x1f50, 0x1f57,
+ 0x1f59, 0x1f59,
+ 0x1f5b, 0x1f5b,
+ 0x1f5d, 0x1f5d,
+ 0x1f5f, 0x1f7d,
+ 0x1f80, 0x1fb4,
+ 0x1fb6, 0x1fc4,
+ 0x1fc6, 0x1fd3,
+ 0x1fd6, 0x1fdb,
+ 0x1fdd, 0x1fef,
+ 0x1ff2, 0x1ff4,
+ 0x1ff6, 0x1ffe,
+ 0x2000, 0x2064,
+ 0x206a, 0x2071,
+ 0x2074, 0x208e,
+ 0x2090, 0x2094,
+ 0x20a0, 0x20b5,
+ 0x20d0, 0x20f0,
+ 0x2100, 0x214f,
+ 0x2153, 0x2188,
+ 0x2190, 0x23e7,
+ 0x2400, 0x2426,
+ 0x2440, 0x244a,
+ 0x2460, 0x269d,
+ 0x26a0, 0x26bc,
+ 0x26c0, 0x26c3,
+ 0x2701, 0x2704,
+ 0x2706, 0x2709,
+ 0x270c, 0x2727,
+ 0x2729, 0x274b,
+ 0x274d, 0x274d,
+ 0x274f, 0x2752,
+ 0x2756, 0x2756,
+ 0x2758, 0x275e,
+ 0x2761, 0x2794,
+ 0x2798, 0x27af,
+ 0x27b1, 0x27be,
+ 0x27c0, 0x27ca,
+ 0x27cc, 0x27cc,
+ 0x27d0, 0x2b4c,
+ 0x2b50, 0x2b54,
+ 0x2c00, 0x2c2e,
+ 0x2c30, 0x2c5e,
+ 0x2c60, 0x2c6f,
+ 0x2c71, 0x2c7d,
+ 0x2c80, 0x2cea,
+ 0x2cf9, 0x2d25,
+ 0x2d30, 0x2d65,
+ 0x2d6f, 0x2d6f,
+ 0x2d80, 0x2d96,
+ 0x2da0, 0x2da6,
+ 0x2da8, 0x2dae,
+ 0x2db0, 0x2db6,
+ 0x2db8, 0x2dbe,
+ 0x2dc0, 0x2dc6,
+ 0x2dc8, 0x2dce,
+ 0x2dd0, 0x2dd6,
+ 0x2dd8, 0x2dde,
+ 0x2de0, 0x2e30,
+ 0x2e80, 0x2e99,
+ 0x2e9b, 0x2ef3,
+ 0x2f00, 0x2fd5,
+ 0x2ff0, 0x2ffb,
+ 0x3000, 0x303f,
+ 0x3041, 0x3096,
+ 0x3099, 0x30ff,
+ 0x3105, 0x312d,
+ 0x3131, 0x318e,
+ 0x3190, 0x31b7,
+ 0x31c0, 0x31e3,
+ 0x31f0, 0x321e,
+ 0x3220, 0x3243,
+ 0x3250, 0x32fe,
+ 0x3300, 0x4db5,
+ 0x4dc0, 0x9fc3,
+ 0xa000, 0xa48c,
+ 0xa490, 0xa4c6,
+ 0xa500, 0xa62b,
+ 0xa640, 0xa65f,
+ 0xa662, 0xa673,
+ 0xa67c, 0xa697,
+ 0xa700, 0xa78c,
+ 0xa7fb, 0xa82b,
+ 0xa840, 0xa877,
+ 0xa880, 0xa8c4,
+ 0xa8ce, 0xa8d9,
+ 0xa900, 0xa953,
+ 0xa95f, 0xa95f,
+ 0xaa00, 0xaa36,
+ 0xaa40, 0xaa4d,
+ 0xaa50, 0xaa59,
+ 0xaa5c, 0xaa5f,
+ 0xac00, 0xd7a3,
+ 0xd800, 0xfa2d,
+ 0xfa30, 0xfa6a,
+ 0xfa70, 0xfad9,
+ 0xfb00, 0xfb06,
+ 0xfb13, 0xfb17,
+ 0xfb1d, 0xfb36,
+ 0xfb38, 0xfb3c,
+ 0xfb3e, 0xfb3e,
+ 0xfb40, 0xfb41,
+ 0xfb43, 0xfb44,
+ 0xfb46, 0xfbb1,
+ 0xfbd3, 0xfd3f,
+ 0xfd50, 0xfd8f,
+ 0xfd92, 0xfdc7,
+ 0xfdd0, 0xfdfd,
+ 0xfe00, 0xfe19,
+ 0xfe20, 0xfe26,
+ 0xfe30, 0xfe52,
+ 0xfe54, 0xfe66,
+ 0xfe68, 0xfe6b,
+ 0xfe70, 0xfe74,
+ 0xfe76, 0xfefc,
+ 0xfeff, 0xfeff,
+ 0xff01, 0xffbe,
+ 0xffc2, 0xffc7,
+ 0xffca, 0xffcf,
+ 0xffd2, 0xffd7,
+ 0xffda, 0xffdc,
+ 0xffe0, 0xffe6,
+ 0xffe8, 0xffee,
+ 0xfff9, 0x1000b,
+ 0x1000d, 0x10026,
+ 0x10028, 0x1003a,
+ 0x1003c, 0x1003d,
+ 0x1003f, 0x1004d,
+ 0x10050, 0x1005d,
+ 0x10080, 0x100fa,
+ 0x10100, 0x10102,
+ 0x10107, 0x10133,
+ 0x10137, 0x1018a,
+ 0x10190, 0x1019b,
+ 0x101d0, 0x101fd,
+ 0x10280, 0x1029c,
+ 0x102a0, 0x102d0,
+ 0x10300, 0x1031e,
+ 0x10320, 0x10323,
+ 0x10330, 0x1034a,
+ 0x10380, 0x1039d,
+ 0x1039f, 0x103c3,
+ 0x103c8, 0x103d5,
+ 0x10400, 0x1049d,
+ 0x104a0, 0x104a9,
+ 0x10800, 0x10805,
+ 0x10808, 0x10808,
+ 0x1080a, 0x10835,
+ 0x10837, 0x10838,
+ 0x1083c, 0x1083c,
+ 0x1083f, 0x1083f,
+ 0x10900, 0x10919,
+ 0x1091f, 0x10939,
+ 0x1093f, 0x1093f,
+ 0x10a00, 0x10a03,
+ 0x10a05, 0x10a06,
+ 0x10a0c, 0x10a13,
+ 0x10a15, 0x10a17,
+ 0x10a19, 0x10a33,
+ 0x10a38, 0x10a3a,
+ 0x10a3f, 0x10a47,
+ 0x10a50, 0x10a58,
+ 0x12000, 0x1236e,
+ 0x12400, 0x12462,
+ 0x12470, 0x12473,
+ 0x1d000, 0x1d0f5,
+ 0x1d100, 0x1d126,
+ 0x1d129, 0x1d1dd,
+ 0x1d200, 0x1d245,
+ 0x1d300, 0x1d356,
+ 0x1d360, 0x1d371,
+ 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, 0x1d7cb,
+ 0x1d7ce, 0x1d7ff,
+ 0x1f000, 0x1f02b,
+ 0x1f030, 0x1f093,
+ 0x1fffe, 0x2a6d6,
+ 0x2f800, 0x2fa1d,
+ 0x2fffe, 0x2ffff,
+ 0x3fffe, 0x3ffff,
+ 0x4fffe, 0x4ffff,
+ 0x5fffe, 0x5ffff,
+ 0x6fffe, 0x6ffff,
+ 0x7fffe, 0x7ffff,
+ 0x8fffe, 0x8ffff,
+ 0x9fffe, 0x9ffff,
+ 0xafffe, 0xaffff,
+ 0xbfffe, 0xbffff,
+ 0xcfffe, 0xcffff,
+ 0xdfffe, 0xdffff,
+ 0xe0001, 0xe0001,
+ 0xe0020, 0xe007f,
+ 0xe0100, 0xe01ef,
+ 0xefffe, 0x10ffff,
+}; /* CR_Age_5_1 */
+
+/* 'Age_5_2': Derived Age 5.2 */
+static const OnigCodePoint CR_Age_5_2[] = {
+ 495,
+ 0x0000, 0x0377,
+ 0x037a, 0x037e,
+ 0x0384, 0x038a,
+ 0x038c, 0x038c,
+ 0x038e, 0x03a1,
+ 0x03a3, 0x0525,
+ 0x0531, 0x0556,
+ 0x0559, 0x055f,
+ 0x0561, 0x0587,
+ 0x0589, 0x058a,
+ 0x0591, 0x05c7,
+ 0x05d0, 0x05ea,
+ 0x05f0, 0x05f4,
+ 0x0600, 0x0603,
+ 0x0606, 0x061b,
+ 0x061e, 0x061f,
+ 0x0621, 0x065e,
+ 0x0660, 0x070d,
+ 0x070f, 0x074a,
+ 0x074d, 0x07b1,
+ 0x07c0, 0x07fa,
+ 0x0800, 0x082d,
+ 0x0830, 0x083e,
+ 0x0900, 0x0939,
+ 0x093c, 0x094e,
+ 0x0950, 0x0955,
+ 0x0958, 0x0972,
+ 0x0979, 0x097f,
+ 0x0981, 0x0983,
+ 0x0985, 0x098c,
+ 0x098f, 0x0990,
+ 0x0993, 0x09a8,
+ 0x09aa, 0x09b0,
+ 0x09b2, 0x09b2,
+ 0x09b6, 0x09b9,
+ 0x09bc, 0x09c4,
+ 0x09c7, 0x09c8,
+ 0x09cb, 0x09ce,
+ 0x09d7, 0x09d7,
+ 0x09dc, 0x09dd,
+ 0x09df, 0x09e3,
+ 0x09e6, 0x09fb,
+ 0x0a01, 0x0a03,
+ 0x0a05, 0x0a0a,
+ 0x0a0f, 0x0a10,
+ 0x0a13, 0x0a28,
+ 0x0a2a, 0x0a30,
+ 0x0a32, 0x0a33,
+ 0x0a35, 0x0a36,
+ 0x0a38, 0x0a39,
+ 0x0a3c, 0x0a3c,
+ 0x0a3e, 0x0a42,
+ 0x0a47, 0x0a48,
+ 0x0a4b, 0x0a4d,
+ 0x0a51, 0x0a51,
+ 0x0a59, 0x0a5c,
+ 0x0a5e, 0x0a5e,
+ 0x0a66, 0x0a75,
+ 0x0a81, 0x0a83,
+ 0x0a85, 0x0a8d,
+ 0x0a8f, 0x0a91,
+ 0x0a93, 0x0aa8,
+ 0x0aaa, 0x0ab0,
+ 0x0ab2, 0x0ab3,
+ 0x0ab5, 0x0ab9,
+ 0x0abc, 0x0ac5,
+ 0x0ac7, 0x0ac9,
+ 0x0acb, 0x0acd,
+ 0x0ad0, 0x0ad0,
+ 0x0ae0, 0x0ae3,
+ 0x0ae6, 0x0aef,
+ 0x0af1, 0x0af1,
+ 0x0b01, 0x0b03,
+ 0x0b05, 0x0b0c,
+ 0x0b0f, 0x0b10,
+ 0x0b13, 0x0b28,
+ 0x0b2a, 0x0b30,
+ 0x0b32, 0x0b33,
+ 0x0b35, 0x0b39,
+ 0x0b3c, 0x0b44,
+ 0x0b47, 0x0b48,
+ 0x0b4b, 0x0b4d,
+ 0x0b56, 0x0b57,
+ 0x0b5c, 0x0b5d,
+ 0x0b5f, 0x0b63,
+ 0x0b66, 0x0b71,
+ 0x0b82, 0x0b83,
+ 0x0b85, 0x0b8a,
+ 0x0b8e, 0x0b90,
+ 0x0b92, 0x0b95,
+ 0x0b99, 0x0b9a,
+ 0x0b9c, 0x0b9c,
+ 0x0b9e, 0x0b9f,
+ 0x0ba3, 0x0ba4,
+ 0x0ba8, 0x0baa,
+ 0x0bae, 0x0bb9,
+ 0x0bbe, 0x0bc2,
+ 0x0bc6, 0x0bc8,
+ 0x0bca, 0x0bcd,
+ 0x0bd0, 0x0bd0,
+ 0x0bd7, 0x0bd7,
+ 0x0be6, 0x0bfa,
+ 0x0c01, 0x0c03,
+ 0x0c05, 0x0c0c,
+ 0x0c0e, 0x0c10,
+ 0x0c12, 0x0c28,
+ 0x0c2a, 0x0c33,
+ 0x0c35, 0x0c39,
+ 0x0c3d, 0x0c44,
+ 0x0c46, 0x0c48,
+ 0x0c4a, 0x0c4d,
+ 0x0c55, 0x0c56,
+ 0x0c58, 0x0c59,
+ 0x0c60, 0x0c63,
+ 0x0c66, 0x0c6f,
+ 0x0c78, 0x0c7f,
+ 0x0c82, 0x0c83,
+ 0x0c85, 0x0c8c,
+ 0x0c8e, 0x0c90,
+ 0x0c92, 0x0ca8,
+ 0x0caa, 0x0cb3,
+ 0x0cb5, 0x0cb9,
+ 0x0cbc, 0x0cc4,
+ 0x0cc6, 0x0cc8,
+ 0x0cca, 0x0ccd,
+ 0x0cd5, 0x0cd6,
+ 0x0cde, 0x0cde,
+ 0x0ce0, 0x0ce3,
+ 0x0ce6, 0x0cef,
+ 0x0cf1, 0x0cf2,
+ 0x0d02, 0x0d03,
+ 0x0d05, 0x0d0c,
+ 0x0d0e, 0x0d10,
+ 0x0d12, 0x0d28,
+ 0x0d2a, 0x0d39,
+ 0x0d3d, 0x0d44,
+ 0x0d46, 0x0d48,
+ 0x0d4a, 0x0d4d,
+ 0x0d57, 0x0d57,
+ 0x0d60, 0x0d63,
+ 0x0d66, 0x0d75,
+ 0x0d79, 0x0d7f,
+ 0x0d82, 0x0d83,
+ 0x0d85, 0x0d96,
+ 0x0d9a, 0x0db1,
+ 0x0db3, 0x0dbb,
+ 0x0dbd, 0x0dbd,
+ 0x0dc0, 0x0dc6,
+ 0x0dca, 0x0dca,
+ 0x0dcf, 0x0dd4,
+ 0x0dd6, 0x0dd6,
+ 0x0dd8, 0x0ddf,
+ 0x0df2, 0x0df4,
+ 0x0e01, 0x0e3a,
+ 0x0e3f, 0x0e5b,
+ 0x0e81, 0x0e82,
+ 0x0e84, 0x0e84,
+ 0x0e87, 0x0e88,
+ 0x0e8a, 0x0e8a,
+ 0x0e8d, 0x0e8d,
+ 0x0e94, 0x0e97,
+ 0x0e99, 0x0e9f,
+ 0x0ea1, 0x0ea3,
+ 0x0ea5, 0x0ea5,
+ 0x0ea7, 0x0ea7,
+ 0x0eaa, 0x0eab,
+ 0x0ead, 0x0eb9,
+ 0x0ebb, 0x0ebd,
+ 0x0ec0, 0x0ec4,
+ 0x0ec6, 0x0ec6,
+ 0x0ec8, 0x0ecd,
+ 0x0ed0, 0x0ed9,
+ 0x0edc, 0x0edd,
+ 0x0f00, 0x0f47,
+ 0x0f49, 0x0f6c,
+ 0x0f71, 0x0f8b,
+ 0x0f90, 0x0f97,
+ 0x0f99, 0x0fbc,
+ 0x0fbe, 0x0fcc,
+ 0x0fce, 0x0fd8,
+ 0x1000, 0x10c5,
+ 0x10d0, 0x10fc,
+ 0x1100, 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,
+ 0x135f, 0x137c,
+ 0x1380, 0x1399,
+ 0x13a0, 0x13f4,
+ 0x1400, 0x169c,
+ 0x16a0, 0x16f0,
+ 0x1700, 0x170c,
+ 0x170e, 0x1714,
+ 0x1720, 0x1736,
+ 0x1740, 0x1753,
+ 0x1760, 0x176c,
+ 0x176e, 0x1770,
+ 0x1772, 0x1773,
+ 0x1780, 0x17dd,
+ 0x17e0, 0x17e9,
+ 0x17f0, 0x17f9,
+ 0x1800, 0x180e,
+ 0x1810, 0x1819,
+ 0x1820, 0x1877,
+ 0x1880, 0x18aa,
+ 0x18b0, 0x18f5,
+ 0x1900, 0x191c,
+ 0x1920, 0x192b,
+ 0x1930, 0x193b,
+ 0x1940, 0x1940,
+ 0x1944, 0x196d,
+ 0x1970, 0x1974,
+ 0x1980, 0x19ab,
+ 0x19b0, 0x19c9,
+ 0x19d0, 0x19da,
+ 0x19de, 0x1a1b,
+ 0x1a1e, 0x1a5e,
+ 0x1a60, 0x1a7c,
+ 0x1a7f, 0x1a89,
+ 0x1a90, 0x1a99,
+ 0x1aa0, 0x1aad,
+ 0x1b00, 0x1b4b,
+ 0x1b50, 0x1b7c,
+ 0x1b80, 0x1baa,
+ 0x1bae, 0x1bb9,
+ 0x1c00, 0x1c37,
+ 0x1c3b, 0x1c49,
+ 0x1c4d, 0x1c7f,
+ 0x1cd0, 0x1cf2,
+ 0x1d00, 0x1de6,
+ 0x1dfd, 0x1f15,
+ 0x1f18, 0x1f1d,
+ 0x1f20, 0x1f45,
+ 0x1f48, 0x1f4d,
+ 0x1f50, 0x1f57,
+ 0x1f59, 0x1f59,
+ 0x1f5b, 0x1f5b,
+ 0x1f5d, 0x1f5d,
+ 0x1f5f, 0x1f7d,
+ 0x1f80, 0x1fb4,
+ 0x1fb6, 0x1fc4,
+ 0x1fc6, 0x1fd3,
+ 0x1fd6, 0x1fdb,
+ 0x1fdd, 0x1fef,
+ 0x1ff2, 0x1ff4,
+ 0x1ff6, 0x1ffe,
+ 0x2000, 0x2064,
+ 0x206a, 0x2071,
+ 0x2074, 0x208e,
+ 0x2090, 0x2094,
+ 0x20a0, 0x20b8,
+ 0x20d0, 0x20f0,
+ 0x2100, 0x2189,
+ 0x2190, 0x23e8,
+ 0x2400, 0x2426,
+ 0x2440, 0x244a,
+ 0x2460, 0x26cd,
+ 0x26cf, 0x26e1,
+ 0x26e3, 0x26e3,
+ 0x26e8, 0x26ff,
+ 0x2701, 0x2704,
+ 0x2706, 0x2709,
+ 0x270c, 0x2727,
+ 0x2729, 0x274b,
+ 0x274d, 0x274d,
+ 0x274f, 0x2752,
+ 0x2756, 0x275e,
+ 0x2761, 0x2794,
+ 0x2798, 0x27af,
+ 0x27b1, 0x27be,
+ 0x27c0, 0x27ca,
+ 0x27cc, 0x27cc,
+ 0x27d0, 0x2b4c,
+ 0x2b50, 0x2b59,
+ 0x2c00, 0x2c2e,
+ 0x2c30, 0x2c5e,
+ 0x2c60, 0x2cf1,
+ 0x2cf9, 0x2d25,
+ 0x2d30, 0x2d65,
+ 0x2d6f, 0x2d6f,
+ 0x2d80, 0x2d96,
+ 0x2da0, 0x2da6,
+ 0x2da8, 0x2dae,
+ 0x2db0, 0x2db6,
+ 0x2db8, 0x2dbe,
+ 0x2dc0, 0x2dc6,
+ 0x2dc8, 0x2dce,
+ 0x2dd0, 0x2dd6,
+ 0x2dd8, 0x2dde,
+ 0x2de0, 0x2e31,
+ 0x2e80, 0x2e99,
+ 0x2e9b, 0x2ef3,
+ 0x2f00, 0x2fd5,
+ 0x2ff0, 0x2ffb,
+ 0x3000, 0x303f,
+ 0x3041, 0x3096,
+ 0x3099, 0x30ff,
+ 0x3105, 0x312d,
+ 0x3131, 0x318e,
+ 0x3190, 0x31b7,
+ 0x31c0, 0x31e3,
+ 0x31f0, 0x321e,
+ 0x3220, 0x32fe,
+ 0x3300, 0x4db5,
+ 0x4dc0, 0x9fcb,
+ 0xa000, 0xa48c,
+ 0xa490, 0xa4c6,
+ 0xa4d0, 0xa62b,
+ 0xa640, 0xa65f,
+ 0xa662, 0xa673,
+ 0xa67c, 0xa697,
+ 0xa6a0, 0xa6f7,
+ 0xa700, 0xa78c,
+ 0xa7fb, 0xa82b,
+ 0xa830, 0xa839,
+ 0xa840, 0xa877,
+ 0xa880, 0xa8c4,
+ 0xa8ce, 0xa8d9,
+ 0xa8e0, 0xa8fb,
+ 0xa900, 0xa953,
+ 0xa95f, 0xa97c,
+ 0xa980, 0xa9cd,
+ 0xa9cf, 0xa9d9,
+ 0xa9de, 0xa9df,
+ 0xaa00, 0xaa36,
+ 0xaa40, 0xaa4d,
+ 0xaa50, 0xaa59,
+ 0xaa5c, 0xaa7b,
+ 0xaa80, 0xaac2,
+ 0xaadb, 0xaadf,
+ 0xabc0, 0xabed,
+ 0xabf0, 0xabf9,
+ 0xac00, 0xd7a3,
+ 0xd7b0, 0xd7c6,
+ 0xd7cb, 0xd7fb,
+ 0xd800, 0xfa2d,
+ 0xfa30, 0xfa6d,
+ 0xfa70, 0xfad9,
+ 0xfb00, 0xfb06,
+ 0xfb13, 0xfb17,
+ 0xfb1d, 0xfb36,
+ 0xfb38, 0xfb3c,
+ 0xfb3e, 0xfb3e,
+ 0xfb40, 0xfb41,
+ 0xfb43, 0xfb44,
+ 0xfb46, 0xfbb1,
+ 0xfbd3, 0xfd3f,
+ 0xfd50, 0xfd8f,
+ 0xfd92, 0xfdc7,
+ 0xfdd0, 0xfdfd,
+ 0xfe00, 0xfe19,
+ 0xfe20, 0xfe26,
+ 0xfe30, 0xfe52,
+ 0xfe54, 0xfe66,
+ 0xfe68, 0xfe6b,
+ 0xfe70, 0xfe74,
+ 0xfe76, 0xfefc,
+ 0xfeff, 0xfeff,
+ 0xff01, 0xffbe,
+ 0xffc2, 0xffc7,
+ 0xffca, 0xffcf,
+ 0xffd2, 0xffd7,
+ 0xffda, 0xffdc,
+ 0xffe0, 0xffe6,
+ 0xffe8, 0xffee,
+ 0xfff9, 0x1000b,
+ 0x1000d, 0x10026,
+ 0x10028, 0x1003a,
+ 0x1003c, 0x1003d,
+ 0x1003f, 0x1004d,
+ 0x10050, 0x1005d,
+ 0x10080, 0x100fa,
+ 0x10100, 0x10102,
+ 0x10107, 0x10133,
+ 0x10137, 0x1018a,
+ 0x10190, 0x1019b,
+ 0x101d0, 0x101fd,
+ 0x10280, 0x1029c,
+ 0x102a0, 0x102d0,
+ 0x10300, 0x1031e,
+ 0x10320, 0x10323,
+ 0x10330, 0x1034a,
+ 0x10380, 0x1039d,
+ 0x1039f, 0x103c3,
+ 0x103c8, 0x103d5,
+ 0x10400, 0x1049d,
+ 0x104a0, 0x104a9,
+ 0x10800, 0x10805,
+ 0x10808, 0x10808,
+ 0x1080a, 0x10835,
+ 0x10837, 0x10838,
+ 0x1083c, 0x1083c,
+ 0x1083f, 0x10855,
+ 0x10857, 0x1085f,
+ 0x10900, 0x1091b,
+ 0x1091f, 0x10939,
+ 0x1093f, 0x1093f,
+ 0x10a00, 0x10a03,
+ 0x10a05, 0x10a06,
+ 0x10a0c, 0x10a13,
+ 0x10a15, 0x10a17,
+ 0x10a19, 0x10a33,
+ 0x10a38, 0x10a3a,
+ 0x10a3f, 0x10a47,
+ 0x10a50, 0x10a58,
+ 0x10a60, 0x10a7f,
+ 0x10b00, 0x10b35,
+ 0x10b39, 0x10b55,
+ 0x10b58, 0x10b72,
+ 0x10b78, 0x10b7f,
+ 0x10c00, 0x10c48,
+ 0x10e60, 0x10e7e,
+ 0x11080, 0x110c1,
+ 0x12000, 0x1236e,
+ 0x12400, 0x12462,
+ 0x12470, 0x12473,
+ 0x13000, 0x1342e,
+ 0x1d000, 0x1d0f5,
+ 0x1d100, 0x1d126,
+ 0x1d129, 0x1d1dd,
+ 0x1d200, 0x1d245,
+ 0x1d300, 0x1d356,
+ 0x1d360, 0x1d371,
+ 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, 0x1d7cb,
+ 0x1d7ce, 0x1d7ff,
+ 0x1f000, 0x1f02b,
+ 0x1f030, 0x1f093,
+ 0x1f100, 0x1f10a,
+ 0x1f110, 0x1f12e,
+ 0x1f131, 0x1f131,
+ 0x1f13d, 0x1f13d,
+ 0x1f13f, 0x1f13f,
+ 0x1f142, 0x1f142,
+ 0x1f146, 0x1f146,
+ 0x1f14a, 0x1f14e,
+ 0x1f157, 0x1f157,
+ 0x1f15f, 0x1f15f,
+ 0x1f179, 0x1f179,
+ 0x1f17b, 0x1f17c,
+ 0x1f17f, 0x1f17f,
+ 0x1f18a, 0x1f18d,
+ 0x1f190, 0x1f190,
+ 0x1f200, 0x1f200,
+ 0x1f210, 0x1f231,
+ 0x1f240, 0x1f248,
+ 0x1fffe, 0x2a6d6,
+ 0x2a700, 0x2b734,
+ 0x2f800, 0x2fa1d,
+ 0x2fffe, 0x2ffff,
+ 0x3fffe, 0x3ffff,
+ 0x4fffe, 0x4ffff,
+ 0x5fffe, 0x5ffff,
+ 0x6fffe, 0x6ffff,
+ 0x7fffe, 0x7ffff,
+ 0x8fffe, 0x8ffff,
+ 0x9fffe, 0x9ffff,
+ 0xafffe, 0xaffff,
+ 0xbfffe, 0xbffff,
+ 0xcfffe, 0xcffff,
+ 0xdfffe, 0xdffff,
+ 0xe0001, 0xe0001,
+ 0xe0020, 0xe007f,
+ 0xe0100, 0xe01ef,
+ 0xefffe, 0x10ffff,
+}; /* CR_Age_5_2 */
+
+/* 'Age_6_0': Derived Age 6.0 */
+static const OnigCodePoint CR_Age_6_0[] = {
+ 511,
+ 0x0000, 0x0377,
+ 0x037a, 0x037e,
+ 0x0384, 0x038a,
+ 0x038c, 0x038c,
+ 0x038e, 0x03a1,
+ 0x03a3, 0x0527,
+ 0x0531, 0x0556,
+ 0x0559, 0x055f,
+ 0x0561, 0x0587,
+ 0x0589, 0x058a,
+ 0x0591, 0x05c7,
+ 0x05d0, 0x05ea,
+ 0x05f0, 0x05f4,
+ 0x0600, 0x0603,
+ 0x0606, 0x061b,
+ 0x061e, 0x070d,
+ 0x070f, 0x074a,
+ 0x074d, 0x07b1,
+ 0x07c0, 0x07fa,
+ 0x0800, 0x082d,
+ 0x0830, 0x083e,
+ 0x0840, 0x085b,
+ 0x085e, 0x085e,
+ 0x0900, 0x0977,
+ 0x0979, 0x097f,
+ 0x0981, 0x0983,
+ 0x0985, 0x098c,
+ 0x098f, 0x0990,
+ 0x0993, 0x09a8,
+ 0x09aa, 0x09b0,
+ 0x09b2, 0x09b2,
+ 0x09b6, 0x09b9,
+ 0x09bc, 0x09c4,
+ 0x09c7, 0x09c8,
+ 0x09cb, 0x09ce,
+ 0x09d7, 0x09d7,
+ 0x09dc, 0x09dd,
+ 0x09df, 0x09e3,
+ 0x09e6, 0x09fb,
+ 0x0a01, 0x0a03,
+ 0x0a05, 0x0a0a,
+ 0x0a0f, 0x0a10,
+ 0x0a13, 0x0a28,
+ 0x0a2a, 0x0a30,
+ 0x0a32, 0x0a33,
+ 0x0a35, 0x0a36,
+ 0x0a38, 0x0a39,
+ 0x0a3c, 0x0a3c,
+ 0x0a3e, 0x0a42,
+ 0x0a47, 0x0a48,
+ 0x0a4b, 0x0a4d,
+ 0x0a51, 0x0a51,
+ 0x0a59, 0x0a5c,
+ 0x0a5e, 0x0a5e,
+ 0x0a66, 0x0a75,
+ 0x0a81, 0x0a83,
+ 0x0a85, 0x0a8d,
+ 0x0a8f, 0x0a91,
+ 0x0a93, 0x0aa8,
+ 0x0aaa, 0x0ab0,
+ 0x0ab2, 0x0ab3,
+ 0x0ab5, 0x0ab9,
+ 0x0abc, 0x0ac5,
+ 0x0ac7, 0x0ac9,
+ 0x0acb, 0x0acd,
+ 0x0ad0, 0x0ad0,
+ 0x0ae0, 0x0ae3,
+ 0x0ae6, 0x0aef,
+ 0x0af1, 0x0af1,
+ 0x0b01, 0x0b03,
+ 0x0b05, 0x0b0c,
+ 0x0b0f, 0x0b10,
+ 0x0b13, 0x0b28,
+ 0x0b2a, 0x0b30,
+ 0x0b32, 0x0b33,
+ 0x0b35, 0x0b39,
+ 0x0b3c, 0x0b44,
+ 0x0b47, 0x0b48,
+ 0x0b4b, 0x0b4d,
+ 0x0b56, 0x0b57,
+ 0x0b5c, 0x0b5d,
+ 0x0b5f, 0x0b63,
+ 0x0b66, 0x0b77,
+ 0x0b82, 0x0b83,
+ 0x0b85, 0x0b8a,
+ 0x0b8e, 0x0b90,
+ 0x0b92, 0x0b95,
+ 0x0b99, 0x0b9a,
+ 0x0b9c, 0x0b9c,
+ 0x0b9e, 0x0b9f,
+ 0x0ba3, 0x0ba4,
+ 0x0ba8, 0x0baa,
+ 0x0bae, 0x0bb9,
+ 0x0bbe, 0x0bc2,
+ 0x0bc6, 0x0bc8,
+ 0x0bca, 0x0bcd,
+ 0x0bd0, 0x0bd0,
+ 0x0bd7, 0x0bd7,
+ 0x0be6, 0x0bfa,
+ 0x0c01, 0x0c03,
+ 0x0c05, 0x0c0c,
+ 0x0c0e, 0x0c10,
+ 0x0c12, 0x0c28,
+ 0x0c2a, 0x0c33,
+ 0x0c35, 0x0c39,
+ 0x0c3d, 0x0c44,
+ 0x0c46, 0x0c48,
+ 0x0c4a, 0x0c4d,
+ 0x0c55, 0x0c56,
+ 0x0c58, 0x0c59,
+ 0x0c60, 0x0c63,
+ 0x0c66, 0x0c6f,
+ 0x0c78, 0x0c7f,
+ 0x0c82, 0x0c83,
+ 0x0c85, 0x0c8c,
+ 0x0c8e, 0x0c90,
+ 0x0c92, 0x0ca8,
+ 0x0caa, 0x0cb3,
+ 0x0cb5, 0x0cb9,
+ 0x0cbc, 0x0cc4,
+ 0x0cc6, 0x0cc8,
+ 0x0cca, 0x0ccd,
+ 0x0cd5, 0x0cd6,
+ 0x0cde, 0x0cde,
+ 0x0ce0, 0x0ce3,
+ 0x0ce6, 0x0cef,
+ 0x0cf1, 0x0cf2,
+ 0x0d02, 0x0d03,
+ 0x0d05, 0x0d0c,
+ 0x0d0e, 0x0d10,
+ 0x0d12, 0x0d3a,
+ 0x0d3d, 0x0d44,
+ 0x0d46, 0x0d48,
+ 0x0d4a, 0x0d4e,
+ 0x0d57, 0x0d57,
+ 0x0d60, 0x0d63,
+ 0x0d66, 0x0d75,
+ 0x0d79, 0x0d7f,
+ 0x0d82, 0x0d83,
+ 0x0d85, 0x0d96,
+ 0x0d9a, 0x0db1,
+ 0x0db3, 0x0dbb,
+ 0x0dbd, 0x0dbd,
+ 0x0dc0, 0x0dc6,
+ 0x0dca, 0x0dca,
+ 0x0dcf, 0x0dd4,
+ 0x0dd6, 0x0dd6,
+ 0x0dd8, 0x0ddf,
+ 0x0df2, 0x0df4,
+ 0x0e01, 0x0e3a,
+ 0x0e3f, 0x0e5b,
+ 0x0e81, 0x0e82,
+ 0x0e84, 0x0e84,
+ 0x0e87, 0x0e88,
+ 0x0e8a, 0x0e8a,
+ 0x0e8d, 0x0e8d,
+ 0x0e94, 0x0e97,
+ 0x0e99, 0x0e9f,
+ 0x0ea1, 0x0ea3,
+ 0x0ea5, 0x0ea5,
+ 0x0ea7, 0x0ea7,
+ 0x0eaa, 0x0eab,
+ 0x0ead, 0x0eb9,
+ 0x0ebb, 0x0ebd,
+ 0x0ec0, 0x0ec4,
+ 0x0ec6, 0x0ec6,
+ 0x0ec8, 0x0ecd,
+ 0x0ed0, 0x0ed9,
+ 0x0edc, 0x0edd,
+ 0x0f00, 0x0f47,
+ 0x0f49, 0x0f6c,
+ 0x0f71, 0x0f97,
+ 0x0f99, 0x0fbc,
+ 0x0fbe, 0x0fcc,
+ 0x0fce, 0x0fda,
+ 0x1000, 0x10c5,
+ 0x10d0, 0x10fc,
+ 0x1100, 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,
+ 0x135d, 0x137c,
+ 0x1380, 0x1399,
+ 0x13a0, 0x13f4,
+ 0x1400, 0x169c,
+ 0x16a0, 0x16f0,
+ 0x1700, 0x170c,
+ 0x170e, 0x1714,
+ 0x1720, 0x1736,
+ 0x1740, 0x1753,
+ 0x1760, 0x176c,
+ 0x176e, 0x1770,
+ 0x1772, 0x1773,
+ 0x1780, 0x17dd,
+ 0x17e0, 0x17e9,
+ 0x17f0, 0x17f9,
+ 0x1800, 0x180e,
+ 0x1810, 0x1819,
+ 0x1820, 0x1877,
+ 0x1880, 0x18aa,
+ 0x18b0, 0x18f5,
+ 0x1900, 0x191c,
+ 0x1920, 0x192b,
+ 0x1930, 0x193b,
+ 0x1940, 0x1940,
+ 0x1944, 0x196d,
+ 0x1970, 0x1974,
+ 0x1980, 0x19ab,
+ 0x19b0, 0x19c9,
+ 0x19d0, 0x19da,
+ 0x19de, 0x1a1b,
+ 0x1a1e, 0x1a5e,
+ 0x1a60, 0x1a7c,
+ 0x1a7f, 0x1a89,
+ 0x1a90, 0x1a99,
+ 0x1aa0, 0x1aad,
+ 0x1b00, 0x1b4b,
+ 0x1b50, 0x1b7c,
+ 0x1b80, 0x1baa,
+ 0x1bae, 0x1bb9,
+ 0x1bc0, 0x1bf3,
+ 0x1bfc, 0x1c37,
+ 0x1c3b, 0x1c49,
+ 0x1c4d, 0x1c7f,
+ 0x1cd0, 0x1cf2,
+ 0x1d00, 0x1de6,
+ 0x1dfc, 0x1f15,
+ 0x1f18, 0x1f1d,
+ 0x1f20, 0x1f45,
+ 0x1f48, 0x1f4d,
+ 0x1f50, 0x1f57,
+ 0x1f59, 0x1f59,
+ 0x1f5b, 0x1f5b,
+ 0x1f5d, 0x1f5d,
+ 0x1f5f, 0x1f7d,
+ 0x1f80, 0x1fb4,
+ 0x1fb6, 0x1fc4,
+ 0x1fc6, 0x1fd3,
+ 0x1fd6, 0x1fdb,
+ 0x1fdd, 0x1fef,
+ 0x1ff2, 0x1ff4,
+ 0x1ff6, 0x1ffe,
+ 0x2000, 0x2064,
+ 0x206a, 0x2071,
+ 0x2074, 0x208e,
+ 0x2090, 0x209c,
+ 0x20a0, 0x20b9,
+ 0x20d0, 0x20f0,
+ 0x2100, 0x2189,
+ 0x2190, 0x23f3,
+ 0x2400, 0x2426,
+ 0x2440, 0x244a,
+ 0x2460, 0x26ff,
+ 0x2701, 0x27ca,
+ 0x27cc, 0x27cc,
+ 0x27ce, 0x2b4c,
+ 0x2b50, 0x2b59,
+ 0x2c00, 0x2c2e,
+ 0x2c30, 0x2c5e,
+ 0x2c60, 0x2cf1,
+ 0x2cf9, 0x2d25,
+ 0x2d30, 0x2d65,
+ 0x2d6f, 0x2d70,
+ 0x2d7f, 0x2d96,
+ 0x2da0, 0x2da6,
+ 0x2da8, 0x2dae,
+ 0x2db0, 0x2db6,
+ 0x2db8, 0x2dbe,
+ 0x2dc0, 0x2dc6,
+ 0x2dc8, 0x2dce,
+ 0x2dd0, 0x2dd6,
+ 0x2dd8, 0x2dde,
+ 0x2de0, 0x2e31,
+ 0x2e80, 0x2e99,
+ 0x2e9b, 0x2ef3,
+ 0x2f00, 0x2fd5,
+ 0x2ff0, 0x2ffb,
+ 0x3000, 0x303f,
+ 0x3041, 0x3096,
+ 0x3099, 0x30ff,
+ 0x3105, 0x312d,
+ 0x3131, 0x318e,
+ 0x3190, 0x31ba,
+ 0x31c0, 0x31e3,
+ 0x31f0, 0x321e,
+ 0x3220, 0x32fe,
+ 0x3300, 0x4db5,
+ 0x4dc0, 0x9fcb,
+ 0xa000, 0xa48c,
+ 0xa490, 0xa4c6,
+ 0xa4d0, 0xa62b,
+ 0xa640, 0xa673,
+ 0xa67c, 0xa697,
+ 0xa6a0, 0xa6f7,
+ 0xa700, 0xa78e,
+ 0xa790, 0xa791,
+ 0xa7a0, 0xa7a9,
+ 0xa7fa, 0xa82b,
+ 0xa830, 0xa839,
+ 0xa840, 0xa877,
+ 0xa880, 0xa8c4,
+ 0xa8ce, 0xa8d9,
+ 0xa8e0, 0xa8fb,
+ 0xa900, 0xa953,
+ 0xa95f, 0xa97c,
+ 0xa980, 0xa9cd,
+ 0xa9cf, 0xa9d9,
+ 0xa9de, 0xa9df,
+ 0xaa00, 0xaa36,
+ 0xaa40, 0xaa4d,
+ 0xaa50, 0xaa59,
+ 0xaa5c, 0xaa7b,
+ 0xaa80, 0xaac2,
+ 0xaadb, 0xaadf,
+ 0xab01, 0xab06,
+ 0xab09, 0xab0e,
+ 0xab11, 0xab16,
+ 0xab20, 0xab26,
+ 0xab28, 0xab2e,
+ 0xabc0, 0xabed,
+ 0xabf0, 0xabf9,
+ 0xac00, 0xd7a3,
+ 0xd7b0, 0xd7c6,
+ 0xd7cb, 0xd7fb,
+ 0xd800, 0xfa2d,
+ 0xfa30, 0xfa6d,
+ 0xfa70, 0xfad9,
+ 0xfb00, 0xfb06,
+ 0xfb13, 0xfb17,
+ 0xfb1d, 0xfb36,
+ 0xfb38, 0xfb3c,
+ 0xfb3e, 0xfb3e,
+ 0xfb40, 0xfb41,
+ 0xfb43, 0xfb44,
+ 0xfb46, 0xfbc1,
+ 0xfbd3, 0xfd3f,
+ 0xfd50, 0xfd8f,
+ 0xfd92, 0xfdc7,
+ 0xfdd0, 0xfdfd,
+ 0xfe00, 0xfe19,
+ 0xfe20, 0xfe26,
+ 0xfe30, 0xfe52,
+ 0xfe54, 0xfe66,
+ 0xfe68, 0xfe6b,
+ 0xfe70, 0xfe74,
+ 0xfe76, 0xfefc,
+ 0xfeff, 0xfeff,
+ 0xff01, 0xffbe,
+ 0xffc2, 0xffc7,
+ 0xffca, 0xffcf,
+ 0xffd2, 0xffd7,
+ 0xffda, 0xffdc,
+ 0xffe0, 0xffe6,
+ 0xffe8, 0xffee,
+ 0xfff9, 0x1000b,
+ 0x1000d, 0x10026,
+ 0x10028, 0x1003a,
+ 0x1003c, 0x1003d,
+ 0x1003f, 0x1004d,
+ 0x10050, 0x1005d,
+ 0x10080, 0x100fa,
+ 0x10100, 0x10102,
+ 0x10107, 0x10133,
+ 0x10137, 0x1018a,
+ 0x10190, 0x1019b,
+ 0x101d0, 0x101fd,
+ 0x10280, 0x1029c,
+ 0x102a0, 0x102d0,
+ 0x10300, 0x1031e,
+ 0x10320, 0x10323,
+ 0x10330, 0x1034a,
+ 0x10380, 0x1039d,
+ 0x1039f, 0x103c3,
+ 0x103c8, 0x103d5,
+ 0x10400, 0x1049d,
+ 0x104a0, 0x104a9,
+ 0x10800, 0x10805,
+ 0x10808, 0x10808,
+ 0x1080a, 0x10835,
+ 0x10837, 0x10838,
+ 0x1083c, 0x1083c,
+ 0x1083f, 0x10855,
+ 0x10857, 0x1085f,
+ 0x10900, 0x1091b,
+ 0x1091f, 0x10939,
+ 0x1093f, 0x1093f,
+ 0x10a00, 0x10a03,
+ 0x10a05, 0x10a06,
+ 0x10a0c, 0x10a13,
+ 0x10a15, 0x10a17,
+ 0x10a19, 0x10a33,
+ 0x10a38, 0x10a3a,
+ 0x10a3f, 0x10a47,
+ 0x10a50, 0x10a58,
+ 0x10a60, 0x10a7f,
+ 0x10b00, 0x10b35,
+ 0x10b39, 0x10b55,
+ 0x10b58, 0x10b72,
+ 0x10b78, 0x10b7f,
+ 0x10c00, 0x10c48,
+ 0x10e60, 0x10e7e,
+ 0x11000, 0x1104d,
+ 0x11052, 0x1106f,
+ 0x11080, 0x110c1,
+ 0x12000, 0x1236e,
+ 0x12400, 0x12462,
+ 0x12470, 0x12473,
+ 0x13000, 0x1342e,
+ 0x16800, 0x16a38,
+ 0x1b000, 0x1b001,
+ 0x1d000, 0x1d0f5,
+ 0x1d100, 0x1d126,
+ 0x1d129, 0x1d1dd,
+ 0x1d200, 0x1d245,
+ 0x1d300, 0x1d356,
+ 0x1d360, 0x1d371,
+ 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, 0x1d7cb,
+ 0x1d7ce, 0x1d7ff,
+ 0x1f000, 0x1f02b,
+ 0x1f030, 0x1f093,
+ 0x1f0a0, 0x1f0ae,
+ 0x1f0b1, 0x1f0be,
+ 0x1f0c1, 0x1f0cf,
+ 0x1f0d1, 0x1f0df,
+ 0x1f100, 0x1f10a,
+ 0x1f110, 0x1f12e,
+ 0x1f130, 0x1f169,
+ 0x1f170, 0x1f19a,
+ 0x1f1e6, 0x1f202,
+ 0x1f210, 0x1f23a,
+ 0x1f240, 0x1f248,
+ 0x1f250, 0x1f251,
+ 0x1f300, 0x1f320,
+ 0x1f330, 0x1f335,
+ 0x1f337, 0x1f37c,
+ 0x1f380, 0x1f393,
+ 0x1f3a0, 0x1f3c4,
+ 0x1f3c6, 0x1f3ca,
+ 0x1f3e0, 0x1f3f0,
+ 0x1f400, 0x1f43e,
+ 0x1f440, 0x1f440,
+ 0x1f442, 0x1f4f7,
+ 0x1f4f9, 0x1f4fc,
+ 0x1f500, 0x1f53d,
+ 0x1f550, 0x1f567,
+ 0x1f5fb, 0x1f5ff,
+ 0x1f601, 0x1f610,
+ 0x1f612, 0x1f614,
+ 0x1f616, 0x1f616,
+ 0x1f618, 0x1f618,
+ 0x1f61a, 0x1f61a,
+ 0x1f61c, 0x1f61e,
+ 0x1f620, 0x1f625,
+ 0x1f628, 0x1f62b,
+ 0x1f62d, 0x1f62d,
+ 0x1f630, 0x1f633,
+ 0x1f635, 0x1f640,
+ 0x1f645, 0x1f64f,
+ 0x1f680, 0x1f6c5,
+ 0x1f700, 0x1f773,
+ 0x1fffe, 0x2a6d6,
+ 0x2a700, 0x2b734,
+ 0x2b740, 0x2b81d,
+ 0x2f800, 0x2fa1d,
+ 0x2fffe, 0x2ffff,
+ 0x3fffe, 0x3ffff,
+ 0x4fffe, 0x4ffff,
+ 0x5fffe, 0x5ffff,
+ 0x6fffe, 0x6ffff,
+ 0x7fffe, 0x7ffff,
+ 0x8fffe, 0x8ffff,
+ 0x9fffe, 0x9ffff,
+ 0xafffe, 0xaffff,
+ 0xbfffe, 0xbffff,
+ 0xcfffe, 0xcffff,
+ 0xdfffe, 0xdffff,
+ 0xe0001, 0xe0001,
+ 0xe0020, 0xe007f,
+ 0xe0100, 0xe01ef,
+ 0xefffe, 0x10ffff,
+}; /* CR_Age_6_0 */
+
+/* 'Age_6_1': Derived Age 6.1 */
+static const OnigCodePoint CR_Age_6_1[] = {
+ 549,
+ 0x0000, 0x0377,
+ 0x037a, 0x037e,
+ 0x0384, 0x038a,
+ 0x038c, 0x038c,
+ 0x038e, 0x03a1,
+ 0x03a3, 0x0527,
+ 0x0531, 0x0556,
+ 0x0559, 0x055f,
+ 0x0561, 0x0587,
+ 0x0589, 0x058a,
+ 0x058f, 0x058f,
+ 0x0591, 0x05c7,
+ 0x05d0, 0x05ea,
+ 0x05f0, 0x05f4,
+ 0x0600, 0x0604,
+ 0x0606, 0x061b,
+ 0x061e, 0x070d,
+ 0x070f, 0x074a,
+ 0x074d, 0x07b1,
+ 0x07c0, 0x07fa,
+ 0x0800, 0x082d,
+ 0x0830, 0x083e,
+ 0x0840, 0x085b,
+ 0x085e, 0x085e,
+ 0x08a0, 0x08a0,
+ 0x08a2, 0x08ac,
+ 0x08e4, 0x08fe,
+ 0x0900, 0x0977,
+ 0x0979, 0x097f,
+ 0x0981, 0x0983,
+ 0x0985, 0x098c,
+ 0x098f, 0x0990,
+ 0x0993, 0x09a8,
+ 0x09aa, 0x09b0,
+ 0x09b2, 0x09b2,
+ 0x09b6, 0x09b9,
+ 0x09bc, 0x09c4,
+ 0x09c7, 0x09c8,
+ 0x09cb, 0x09ce,
+ 0x09d7, 0x09d7,
+ 0x09dc, 0x09dd,
+ 0x09df, 0x09e3,
+ 0x09e6, 0x09fb,
+ 0x0a01, 0x0a03,
+ 0x0a05, 0x0a0a,
+ 0x0a0f, 0x0a10,
+ 0x0a13, 0x0a28,
+ 0x0a2a, 0x0a30,
+ 0x0a32, 0x0a33,
+ 0x0a35, 0x0a36,
+ 0x0a38, 0x0a39,
+ 0x0a3c, 0x0a3c,
+ 0x0a3e, 0x0a42,
+ 0x0a47, 0x0a48,
+ 0x0a4b, 0x0a4d,
+ 0x0a51, 0x0a51,
+ 0x0a59, 0x0a5c,
+ 0x0a5e, 0x0a5e,
+ 0x0a66, 0x0a75,
+ 0x0a81, 0x0a83,
+ 0x0a85, 0x0a8d,
+ 0x0a8f, 0x0a91,
+ 0x0a93, 0x0aa8,
+ 0x0aaa, 0x0ab0,
+ 0x0ab2, 0x0ab3,
+ 0x0ab5, 0x0ab9,
+ 0x0abc, 0x0ac5,
+ 0x0ac7, 0x0ac9,
+ 0x0acb, 0x0acd,
+ 0x0ad0, 0x0ad0,
+ 0x0ae0, 0x0ae3,
+ 0x0ae6, 0x0af1,
+ 0x0b01, 0x0b03,
+ 0x0b05, 0x0b0c,
+ 0x0b0f, 0x0b10,
+ 0x0b13, 0x0b28,
+ 0x0b2a, 0x0b30,
+ 0x0b32, 0x0b33,
+ 0x0b35, 0x0b39,
+ 0x0b3c, 0x0b44,
+ 0x0b47, 0x0b48,
+ 0x0b4b, 0x0b4d,
+ 0x0b56, 0x0b57,
+ 0x0b5c, 0x0b5d,
+ 0x0b5f, 0x0b63,
+ 0x0b66, 0x0b77,
+ 0x0b82, 0x0b83,
+ 0x0b85, 0x0b8a,
+ 0x0b8e, 0x0b90,
+ 0x0b92, 0x0b95,
+ 0x0b99, 0x0b9a,
+ 0x0b9c, 0x0b9c,
+ 0x0b9e, 0x0b9f,
+ 0x0ba3, 0x0ba4,
+ 0x0ba8, 0x0baa,
+ 0x0bae, 0x0bb9,
+ 0x0bbe, 0x0bc2,
+ 0x0bc6, 0x0bc8,
+ 0x0bca, 0x0bcd,
+ 0x0bd0, 0x0bd0,
+ 0x0bd7, 0x0bd7,
+ 0x0be6, 0x0bfa,
+ 0x0c01, 0x0c03,
+ 0x0c05, 0x0c0c,
+ 0x0c0e, 0x0c10,
+ 0x0c12, 0x0c28,
+ 0x0c2a, 0x0c33,
+ 0x0c35, 0x0c39,
+ 0x0c3d, 0x0c44,
+ 0x0c46, 0x0c48,
+ 0x0c4a, 0x0c4d,
+ 0x0c55, 0x0c56,
+ 0x0c58, 0x0c59,
+ 0x0c60, 0x0c63,
+ 0x0c66, 0x0c6f,
+ 0x0c78, 0x0c7f,
+ 0x0c82, 0x0c83,
+ 0x0c85, 0x0c8c,
+ 0x0c8e, 0x0c90,
+ 0x0c92, 0x0ca8,
+ 0x0caa, 0x0cb3,
+ 0x0cb5, 0x0cb9,
+ 0x0cbc, 0x0cc4,
+ 0x0cc6, 0x0cc8,
+ 0x0cca, 0x0ccd,
+ 0x0cd5, 0x0cd6,
+ 0x0cde, 0x0cde,
+ 0x0ce0, 0x0ce3,
+ 0x0ce6, 0x0cef,
+ 0x0cf1, 0x0cf2,
+ 0x0d02, 0x0d03,
+ 0x0d05, 0x0d0c,
+ 0x0d0e, 0x0d10,
+ 0x0d12, 0x0d3a,
+ 0x0d3d, 0x0d44,
+ 0x0d46, 0x0d48,
+ 0x0d4a, 0x0d4e,
+ 0x0d57, 0x0d57,
+ 0x0d60, 0x0d63,
+ 0x0d66, 0x0d75,
+ 0x0d79, 0x0d7f,
+ 0x0d82, 0x0d83,
+ 0x0d85, 0x0d96,
+ 0x0d9a, 0x0db1,
+ 0x0db3, 0x0dbb,
+ 0x0dbd, 0x0dbd,
+ 0x0dc0, 0x0dc6,
+ 0x0dca, 0x0dca,
+ 0x0dcf, 0x0dd4,
+ 0x0dd6, 0x0dd6,
+ 0x0dd8, 0x0ddf,
+ 0x0df2, 0x0df4,
+ 0x0e01, 0x0e3a,
+ 0x0e3f, 0x0e5b,
+ 0x0e81, 0x0e82,
+ 0x0e84, 0x0e84,
+ 0x0e87, 0x0e88,
+ 0x0e8a, 0x0e8a,
+ 0x0e8d, 0x0e8d,
+ 0x0e94, 0x0e97,
+ 0x0e99, 0x0e9f,
+ 0x0ea1, 0x0ea3,
+ 0x0ea5, 0x0ea5,
+ 0x0ea7, 0x0ea7,
+ 0x0eaa, 0x0eab,
+ 0x0ead, 0x0eb9,
+ 0x0ebb, 0x0ebd,
+ 0x0ec0, 0x0ec4,
+ 0x0ec6, 0x0ec6,
+ 0x0ec8, 0x0ecd,
+ 0x0ed0, 0x0ed9,
+ 0x0edc, 0x0edf,
+ 0x0f00, 0x0f47,
+ 0x0f49, 0x0f6c,
+ 0x0f71, 0x0f97,
+ 0x0f99, 0x0fbc,
+ 0x0fbe, 0x0fcc,
+ 0x0fce, 0x0fda,
+ 0x1000, 0x10c5,
+ 0x10c7, 0x10c7,
+ 0x10cd, 0x10cd,
+ 0x10d0, 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,
+ 0x135d, 0x137c,
+ 0x1380, 0x1399,
+ 0x13a0, 0x13f4,
+ 0x1400, 0x169c,
+ 0x16a0, 0x16f0,
+ 0x1700, 0x170c,
+ 0x170e, 0x1714,
+ 0x1720, 0x1736,
+ 0x1740, 0x1753,
+ 0x1760, 0x176c,
+ 0x176e, 0x1770,
+ 0x1772, 0x1773,
+ 0x1780, 0x17dd,
+ 0x17e0, 0x17e9,
+ 0x17f0, 0x17f9,
+ 0x1800, 0x180e,
+ 0x1810, 0x1819,
+ 0x1820, 0x1877,
+ 0x1880, 0x18aa,
+ 0x18b0, 0x18f5,
+ 0x1900, 0x191c,
+ 0x1920, 0x192b,
+ 0x1930, 0x193b,
+ 0x1940, 0x1940,
+ 0x1944, 0x196d,
+ 0x1970, 0x1974,
+ 0x1980, 0x19ab,
+ 0x19b0, 0x19c9,
+ 0x19d0, 0x19da,
+ 0x19de, 0x1a1b,
+ 0x1a1e, 0x1a5e,
+ 0x1a60, 0x1a7c,
+ 0x1a7f, 0x1a89,
+ 0x1a90, 0x1a99,
+ 0x1aa0, 0x1aad,
+ 0x1b00, 0x1b4b,
+ 0x1b50, 0x1b7c,
+ 0x1b80, 0x1bf3,
+ 0x1bfc, 0x1c37,
+ 0x1c3b, 0x1c49,
+ 0x1c4d, 0x1c7f,
+ 0x1cc0, 0x1cc7,
+ 0x1cd0, 0x1cf6,
+ 0x1d00, 0x1de6,
+ 0x1dfc, 0x1f15,
+ 0x1f18, 0x1f1d,
+ 0x1f20, 0x1f45,
+ 0x1f48, 0x1f4d,
+ 0x1f50, 0x1f57,
+ 0x1f59, 0x1f59,
+ 0x1f5b, 0x1f5b,
+ 0x1f5d, 0x1f5d,
+ 0x1f5f, 0x1f7d,
+ 0x1f80, 0x1fb4,
+ 0x1fb6, 0x1fc4,
+ 0x1fc6, 0x1fd3,
+ 0x1fd6, 0x1fdb,
+ 0x1fdd, 0x1fef,
+ 0x1ff2, 0x1ff4,
+ 0x1ff6, 0x1ffe,
+ 0x2000, 0x2064,
+ 0x206a, 0x2071,
+ 0x2074, 0x208e,
+ 0x2090, 0x209c,
+ 0x20a0, 0x20b9,
+ 0x20d0, 0x20f0,
+ 0x2100, 0x2189,
+ 0x2190, 0x23f3,
+ 0x2400, 0x2426,
+ 0x2440, 0x244a,
+ 0x2460, 0x26ff,
+ 0x2701, 0x2b4c,
+ 0x2b50, 0x2b59,
+ 0x2c00, 0x2c2e,
+ 0x2c30, 0x2c5e,
+ 0x2c60, 0x2cf3,
+ 0x2cf9, 0x2d25,
+ 0x2d27, 0x2d27,
+ 0x2d2d, 0x2d2d,
+ 0x2d30, 0x2d67,
+ 0x2d6f, 0x2d70,
+ 0x2d7f, 0x2d96,
+ 0x2da0, 0x2da6,
+ 0x2da8, 0x2dae,
+ 0x2db0, 0x2db6,
+ 0x2db8, 0x2dbe,
+ 0x2dc0, 0x2dc6,
+ 0x2dc8, 0x2dce,
+ 0x2dd0, 0x2dd6,
+ 0x2dd8, 0x2dde,
+ 0x2de0, 0x2e3b,
+ 0x2e80, 0x2e99,
+ 0x2e9b, 0x2ef3,
+ 0x2f00, 0x2fd5,
+ 0x2ff0, 0x2ffb,
+ 0x3000, 0x303f,
+ 0x3041, 0x3096,
+ 0x3099, 0x30ff,
+ 0x3105, 0x312d,
+ 0x3131, 0x318e,
+ 0x3190, 0x31ba,
+ 0x31c0, 0x31e3,
+ 0x31f0, 0x321e,
+ 0x3220, 0x32fe,
+ 0x3300, 0x4db5,
+ 0x4dc0, 0x9fcc,
+ 0xa000, 0xa48c,
+ 0xa490, 0xa4c6,
+ 0xa4d0, 0xa62b,
+ 0xa640, 0xa697,
+ 0xa69f, 0xa6f7,
+ 0xa700, 0xa78e,
+ 0xa790, 0xa793,
+ 0xa7a0, 0xa7aa,
+ 0xa7f8, 0xa82b,
+ 0xa830, 0xa839,
+ 0xa840, 0xa877,
+ 0xa880, 0xa8c4,
+ 0xa8ce, 0xa8d9,
+ 0xa8e0, 0xa8fb,
+ 0xa900, 0xa953,
+ 0xa95f, 0xa97c,
+ 0xa980, 0xa9cd,
+ 0xa9cf, 0xa9d9,
+ 0xa9de, 0xa9df,
+ 0xaa00, 0xaa36,
+ 0xaa40, 0xaa4d,
+ 0xaa50, 0xaa59,
+ 0xaa5c, 0xaa7b,
+ 0xaa80, 0xaac2,
+ 0xaadb, 0xaaf6,
+ 0xab01, 0xab06,
+ 0xab09, 0xab0e,
+ 0xab11, 0xab16,
+ 0xab20, 0xab26,
+ 0xab28, 0xab2e,
+ 0xabc0, 0xabed,
+ 0xabf0, 0xabf9,
+ 0xac00, 0xd7a3,
+ 0xd7b0, 0xd7c6,
+ 0xd7cb, 0xd7fb,
+ 0xd800, 0xfa6d,
+ 0xfa70, 0xfad9,
+ 0xfb00, 0xfb06,
+ 0xfb13, 0xfb17,
+ 0xfb1d, 0xfb36,
+ 0xfb38, 0xfb3c,
+ 0xfb3e, 0xfb3e,
+ 0xfb40, 0xfb41,
+ 0xfb43, 0xfb44,
+ 0xfb46, 0xfbc1,
+ 0xfbd3, 0xfd3f,
+ 0xfd50, 0xfd8f,
+ 0xfd92, 0xfdc7,
+ 0xfdd0, 0xfdfd,
+ 0xfe00, 0xfe19,
+ 0xfe20, 0xfe26,
+ 0xfe30, 0xfe52,
+ 0xfe54, 0xfe66,
+ 0xfe68, 0xfe6b,
+ 0xfe70, 0xfe74,
+ 0xfe76, 0xfefc,
+ 0xfeff, 0xfeff,
+ 0xff01, 0xffbe,
+ 0xffc2, 0xffc7,
+ 0xffca, 0xffcf,
+ 0xffd2, 0xffd7,
+ 0xffda, 0xffdc,
+ 0xffe0, 0xffe6,
+ 0xffe8, 0xffee,
+ 0xfff9, 0x1000b,
+ 0x1000d, 0x10026,
+ 0x10028, 0x1003a,
+ 0x1003c, 0x1003d,
+ 0x1003f, 0x1004d,
+ 0x10050, 0x1005d,
+ 0x10080, 0x100fa,
+ 0x10100, 0x10102,
+ 0x10107, 0x10133,
+ 0x10137, 0x1018a,
+ 0x10190, 0x1019b,
+ 0x101d0, 0x101fd,
+ 0x10280, 0x1029c,
+ 0x102a0, 0x102d0,
+ 0x10300, 0x1031e,
+ 0x10320, 0x10323,
+ 0x10330, 0x1034a,
+ 0x10380, 0x1039d,
+ 0x1039f, 0x103c3,
+ 0x103c8, 0x103d5,
+ 0x10400, 0x1049d,
+ 0x104a0, 0x104a9,
+ 0x10800, 0x10805,
+ 0x10808, 0x10808,
+ 0x1080a, 0x10835,
+ 0x10837, 0x10838,
+ 0x1083c, 0x1083c,
+ 0x1083f, 0x10855,
+ 0x10857, 0x1085f,
+ 0x10900, 0x1091b,
+ 0x1091f, 0x10939,
+ 0x1093f, 0x1093f,
+ 0x10980, 0x109b7,
+ 0x109be, 0x109bf,
+ 0x10a00, 0x10a03,
+ 0x10a05, 0x10a06,
+ 0x10a0c, 0x10a13,
+ 0x10a15, 0x10a17,
+ 0x10a19, 0x10a33,
+ 0x10a38, 0x10a3a,
+ 0x10a3f, 0x10a47,
+ 0x10a50, 0x10a58,
+ 0x10a60, 0x10a7f,
+ 0x10b00, 0x10b35,
+ 0x10b39, 0x10b55,
+ 0x10b58, 0x10b72,
+ 0x10b78, 0x10b7f,
+ 0x10c00, 0x10c48,
+ 0x10e60, 0x10e7e,
+ 0x11000, 0x1104d,
+ 0x11052, 0x1106f,
+ 0x11080, 0x110c1,
+ 0x110d0, 0x110e8,
+ 0x110f0, 0x110f9,
+ 0x11100, 0x11134,
+ 0x11136, 0x11143,
+ 0x11180, 0x111c8,
+ 0x111d0, 0x111d9,
+ 0x11680, 0x116b7,
+ 0x116c0, 0x116c9,
+ 0x12000, 0x1236e,
+ 0x12400, 0x12462,
+ 0x12470, 0x12473,
+ 0x13000, 0x1342e,
+ 0x16800, 0x16a38,
+ 0x16f00, 0x16f44,
+ 0x16f50, 0x16f7e,
+ 0x16f8f, 0x16f9f,
+ 0x1b000, 0x1b001,
+ 0x1d000, 0x1d0f5,
+ 0x1d100, 0x1d126,
+ 0x1d129, 0x1d1dd,
+ 0x1d200, 0x1d245,
+ 0x1d300, 0x1d356,
+ 0x1d360, 0x1d371,
+ 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, 0x1d7cb,
+ 0x1d7ce, 0x1d7ff,
+ 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,
+ 0x1eef0, 0x1eef1,
+ 0x1f000, 0x1f02b,
+ 0x1f030, 0x1f093,
+ 0x1f0a0, 0x1f0ae,
+ 0x1f0b1, 0x1f0be,
+ 0x1f0c1, 0x1f0cf,
+ 0x1f0d1, 0x1f0df,
+ 0x1f100, 0x1f10a,
+ 0x1f110, 0x1f12e,
+ 0x1f130, 0x1f16b,
+ 0x1f170, 0x1f19a,
+ 0x1f1e6, 0x1f202,
+ 0x1f210, 0x1f23a,
+ 0x1f240, 0x1f248,
+ 0x1f250, 0x1f251,
+ 0x1f300, 0x1f320,
+ 0x1f330, 0x1f335,
+ 0x1f337, 0x1f37c,
+ 0x1f380, 0x1f393,
+ 0x1f3a0, 0x1f3c4,
+ 0x1f3c6, 0x1f3ca,
+ 0x1f3e0, 0x1f3f0,
+ 0x1f400, 0x1f43e,
+ 0x1f440, 0x1f440,
+ 0x1f442, 0x1f4f7,
+ 0x1f4f9, 0x1f4fc,
+ 0x1f500, 0x1f53d,
+ 0x1f540, 0x1f543,
+ 0x1f550, 0x1f567,
+ 0x1f5fb, 0x1f640,
+ 0x1f645, 0x1f64f,
+ 0x1f680, 0x1f6c5,
+ 0x1f700, 0x1f773,
+ 0x1fffe, 0x2a6d6,
+ 0x2a700, 0x2b734,
+ 0x2b740, 0x2b81d,
+ 0x2f800, 0x2fa1d,
+ 0x2fffe, 0x2ffff,
+ 0x3fffe, 0x3ffff,
+ 0x4fffe, 0x4ffff,
+ 0x5fffe, 0x5ffff,
+ 0x6fffe, 0x6ffff,
+ 0x7fffe, 0x7ffff,
+ 0x8fffe, 0x8ffff,
+ 0x9fffe, 0x9ffff,
+ 0xafffe, 0xaffff,
+ 0xbfffe, 0xbffff,
+ 0xcfffe, 0xcffff,
+ 0xdfffe, 0xdffff,
+ 0xe0001, 0xe0001,
+ 0xe0020, 0xe007f,
+ 0xe0100, 0xe01ef,
+ 0xefffe, 0x10ffff,
+}; /* CR_Age_6_1 */
+
+/* 'Age_6_2': Derived Age 6.2 */
+static const OnigCodePoint CR_Age_6_2[] = {
+ 549,
+ 0x0000, 0x0377,
+ 0x037a, 0x037e,
+ 0x0384, 0x038a,
+ 0x038c, 0x038c,
+ 0x038e, 0x03a1,
+ 0x03a3, 0x0527,
+ 0x0531, 0x0556,
+ 0x0559, 0x055f,
+ 0x0561, 0x0587,
+ 0x0589, 0x058a,
+ 0x058f, 0x058f,
+ 0x0591, 0x05c7,
+ 0x05d0, 0x05ea,
+ 0x05f0, 0x05f4,
+ 0x0600, 0x0604,
+ 0x0606, 0x061b,
+ 0x061e, 0x070d,
+ 0x070f, 0x074a,
+ 0x074d, 0x07b1,
+ 0x07c0, 0x07fa,
+ 0x0800, 0x082d,
+ 0x0830, 0x083e,
+ 0x0840, 0x085b,
+ 0x085e, 0x085e,
+ 0x08a0, 0x08a0,
+ 0x08a2, 0x08ac,
+ 0x08e4, 0x08fe,
+ 0x0900, 0x0977,
+ 0x0979, 0x097f,
+ 0x0981, 0x0983,
+ 0x0985, 0x098c,
+ 0x098f, 0x0990,
+ 0x0993, 0x09a8,
+ 0x09aa, 0x09b0,
+ 0x09b2, 0x09b2,
+ 0x09b6, 0x09b9,
+ 0x09bc, 0x09c4,
+ 0x09c7, 0x09c8,
+ 0x09cb, 0x09ce,
+ 0x09d7, 0x09d7,
+ 0x09dc, 0x09dd,
+ 0x09df, 0x09e3,
+ 0x09e6, 0x09fb,
+ 0x0a01, 0x0a03,
+ 0x0a05, 0x0a0a,
+ 0x0a0f, 0x0a10,
+ 0x0a13, 0x0a28,
+ 0x0a2a, 0x0a30,
+ 0x0a32, 0x0a33,
+ 0x0a35, 0x0a36,
+ 0x0a38, 0x0a39,
+ 0x0a3c, 0x0a3c,
+ 0x0a3e, 0x0a42,
+ 0x0a47, 0x0a48,
+ 0x0a4b, 0x0a4d,
+ 0x0a51, 0x0a51,
+ 0x0a59, 0x0a5c,
+ 0x0a5e, 0x0a5e,
+ 0x0a66, 0x0a75,
+ 0x0a81, 0x0a83,
+ 0x0a85, 0x0a8d,
+ 0x0a8f, 0x0a91,
+ 0x0a93, 0x0aa8,
+ 0x0aaa, 0x0ab0,
+ 0x0ab2, 0x0ab3,
+ 0x0ab5, 0x0ab9,
+ 0x0abc, 0x0ac5,
+ 0x0ac7, 0x0ac9,
+ 0x0acb, 0x0acd,
+ 0x0ad0, 0x0ad0,
+ 0x0ae0, 0x0ae3,
+ 0x0ae6, 0x0af1,
+ 0x0b01, 0x0b03,
+ 0x0b05, 0x0b0c,
+ 0x0b0f, 0x0b10,
+ 0x0b13, 0x0b28,
+ 0x0b2a, 0x0b30,
+ 0x0b32, 0x0b33,
+ 0x0b35, 0x0b39,
+ 0x0b3c, 0x0b44,
+ 0x0b47, 0x0b48,
+ 0x0b4b, 0x0b4d,
+ 0x0b56, 0x0b57,
+ 0x0b5c, 0x0b5d,
+ 0x0b5f, 0x0b63,
+ 0x0b66, 0x0b77,
+ 0x0b82, 0x0b83,
+ 0x0b85, 0x0b8a,
+ 0x0b8e, 0x0b90,
+ 0x0b92, 0x0b95,
+ 0x0b99, 0x0b9a,
+ 0x0b9c, 0x0b9c,
+ 0x0b9e, 0x0b9f,
+ 0x0ba3, 0x0ba4,
+ 0x0ba8, 0x0baa,
+ 0x0bae, 0x0bb9,
+ 0x0bbe, 0x0bc2,
+ 0x0bc6, 0x0bc8,
+ 0x0bca, 0x0bcd,
+ 0x0bd0, 0x0bd0,
+ 0x0bd7, 0x0bd7,
+ 0x0be6, 0x0bfa,
+ 0x0c01, 0x0c03,
+ 0x0c05, 0x0c0c,
+ 0x0c0e, 0x0c10,
+ 0x0c12, 0x0c28,
+ 0x0c2a, 0x0c33,
+ 0x0c35, 0x0c39,
+ 0x0c3d, 0x0c44,
+ 0x0c46, 0x0c48,
+ 0x0c4a, 0x0c4d,
+ 0x0c55, 0x0c56,
+ 0x0c58, 0x0c59,
+ 0x0c60, 0x0c63,
+ 0x0c66, 0x0c6f,
+ 0x0c78, 0x0c7f,
+ 0x0c82, 0x0c83,
+ 0x0c85, 0x0c8c,
+ 0x0c8e, 0x0c90,
+ 0x0c92, 0x0ca8,
+ 0x0caa, 0x0cb3,
+ 0x0cb5, 0x0cb9,
+ 0x0cbc, 0x0cc4,
+ 0x0cc6, 0x0cc8,
+ 0x0cca, 0x0ccd,
+ 0x0cd5, 0x0cd6,
+ 0x0cde, 0x0cde,
+ 0x0ce0, 0x0ce3,
+ 0x0ce6, 0x0cef,
+ 0x0cf1, 0x0cf2,
+ 0x0d02, 0x0d03,
+ 0x0d05, 0x0d0c,
+ 0x0d0e, 0x0d10,
+ 0x0d12, 0x0d3a,
+ 0x0d3d, 0x0d44,
+ 0x0d46, 0x0d48,
+ 0x0d4a, 0x0d4e,
+ 0x0d57, 0x0d57,
+ 0x0d60, 0x0d63,
+ 0x0d66, 0x0d75,
+ 0x0d79, 0x0d7f,
+ 0x0d82, 0x0d83,
+ 0x0d85, 0x0d96,
+ 0x0d9a, 0x0db1,
+ 0x0db3, 0x0dbb,
+ 0x0dbd, 0x0dbd,
+ 0x0dc0, 0x0dc6,
+ 0x0dca, 0x0dca,
+ 0x0dcf, 0x0dd4,
+ 0x0dd6, 0x0dd6,
+ 0x0dd8, 0x0ddf,
+ 0x0df2, 0x0df4,
+ 0x0e01, 0x0e3a,
+ 0x0e3f, 0x0e5b,
+ 0x0e81, 0x0e82,
+ 0x0e84, 0x0e84,
+ 0x0e87, 0x0e88,
+ 0x0e8a, 0x0e8a,
+ 0x0e8d, 0x0e8d,
+ 0x0e94, 0x0e97,
+ 0x0e99, 0x0e9f,
+ 0x0ea1, 0x0ea3,
+ 0x0ea5, 0x0ea5,
+ 0x0ea7, 0x0ea7,
+ 0x0eaa, 0x0eab,
+ 0x0ead, 0x0eb9,
+ 0x0ebb, 0x0ebd,
+ 0x0ec0, 0x0ec4,
+ 0x0ec6, 0x0ec6,
+ 0x0ec8, 0x0ecd,
+ 0x0ed0, 0x0ed9,
+ 0x0edc, 0x0edf,
+ 0x0f00, 0x0f47,
+ 0x0f49, 0x0f6c,
+ 0x0f71, 0x0f97,
+ 0x0f99, 0x0fbc,
+ 0x0fbe, 0x0fcc,
+ 0x0fce, 0x0fda,
+ 0x1000, 0x10c5,
+ 0x10c7, 0x10c7,
+ 0x10cd, 0x10cd,
+ 0x10d0, 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,
+ 0x135d, 0x137c,
+ 0x1380, 0x1399,
+ 0x13a0, 0x13f4,
+ 0x1400, 0x169c,
+ 0x16a0, 0x16f0,
+ 0x1700, 0x170c,
+ 0x170e, 0x1714,
+ 0x1720, 0x1736,
+ 0x1740, 0x1753,
+ 0x1760, 0x176c,
+ 0x176e, 0x1770,
+ 0x1772, 0x1773,
+ 0x1780, 0x17dd,
+ 0x17e0, 0x17e9,
+ 0x17f0, 0x17f9,
+ 0x1800, 0x180e,
+ 0x1810, 0x1819,
+ 0x1820, 0x1877,
+ 0x1880, 0x18aa,
+ 0x18b0, 0x18f5,
+ 0x1900, 0x191c,
+ 0x1920, 0x192b,
+ 0x1930, 0x193b,
+ 0x1940, 0x1940,
+ 0x1944, 0x196d,
+ 0x1970, 0x1974,
+ 0x1980, 0x19ab,
+ 0x19b0, 0x19c9,
+ 0x19d0, 0x19da,
+ 0x19de, 0x1a1b,
+ 0x1a1e, 0x1a5e,
+ 0x1a60, 0x1a7c,
+ 0x1a7f, 0x1a89,
+ 0x1a90, 0x1a99,
+ 0x1aa0, 0x1aad,
+ 0x1b00, 0x1b4b,
+ 0x1b50, 0x1b7c,
+ 0x1b80, 0x1bf3,
+ 0x1bfc, 0x1c37,
+ 0x1c3b, 0x1c49,
+ 0x1c4d, 0x1c7f,
+ 0x1cc0, 0x1cc7,
+ 0x1cd0, 0x1cf6,
+ 0x1d00, 0x1de6,
+ 0x1dfc, 0x1f15,
+ 0x1f18, 0x1f1d,
+ 0x1f20, 0x1f45,
+ 0x1f48, 0x1f4d,
+ 0x1f50, 0x1f57,
+ 0x1f59, 0x1f59,
+ 0x1f5b, 0x1f5b,
+ 0x1f5d, 0x1f5d,
+ 0x1f5f, 0x1f7d,
+ 0x1f80, 0x1fb4,
+ 0x1fb6, 0x1fc4,
+ 0x1fc6, 0x1fd3,
+ 0x1fd6, 0x1fdb,
+ 0x1fdd, 0x1fef,
+ 0x1ff2, 0x1ff4,
+ 0x1ff6, 0x1ffe,
+ 0x2000, 0x2064,
+ 0x206a, 0x2071,
+ 0x2074, 0x208e,
+ 0x2090, 0x209c,
+ 0x20a0, 0x20ba,
+ 0x20d0, 0x20f0,
+ 0x2100, 0x2189,
+ 0x2190, 0x23f3,
+ 0x2400, 0x2426,
+ 0x2440, 0x244a,
+ 0x2460, 0x26ff,
+ 0x2701, 0x2b4c,
+ 0x2b50, 0x2b59,
+ 0x2c00, 0x2c2e,
+ 0x2c30, 0x2c5e,
+ 0x2c60, 0x2cf3,
+ 0x2cf9, 0x2d25,
+ 0x2d27, 0x2d27,
+ 0x2d2d, 0x2d2d,
+ 0x2d30, 0x2d67,
+ 0x2d6f, 0x2d70,
+ 0x2d7f, 0x2d96,
+ 0x2da0, 0x2da6,
+ 0x2da8, 0x2dae,
+ 0x2db0, 0x2db6,
+ 0x2db8, 0x2dbe,
+ 0x2dc0, 0x2dc6,
+ 0x2dc8, 0x2dce,
+ 0x2dd0, 0x2dd6,
+ 0x2dd8, 0x2dde,
+ 0x2de0, 0x2e3b,
+ 0x2e80, 0x2e99,
+ 0x2e9b, 0x2ef3,
+ 0x2f00, 0x2fd5,
+ 0x2ff0, 0x2ffb,
+ 0x3000, 0x303f,
+ 0x3041, 0x3096,
+ 0x3099, 0x30ff,
+ 0x3105, 0x312d,
+ 0x3131, 0x318e,
+ 0x3190, 0x31ba,
+ 0x31c0, 0x31e3,
+ 0x31f0, 0x321e,
+ 0x3220, 0x32fe,
+ 0x3300, 0x4db5,
+ 0x4dc0, 0x9fcc,
+ 0xa000, 0xa48c,
+ 0xa490, 0xa4c6,
+ 0xa4d0, 0xa62b,
+ 0xa640, 0xa697,
+ 0xa69f, 0xa6f7,
+ 0xa700, 0xa78e,
+ 0xa790, 0xa793,
+ 0xa7a0, 0xa7aa,
+ 0xa7f8, 0xa82b,
+ 0xa830, 0xa839,
+ 0xa840, 0xa877,
+ 0xa880, 0xa8c4,
+ 0xa8ce, 0xa8d9,
+ 0xa8e0, 0xa8fb,
+ 0xa900, 0xa953,
+ 0xa95f, 0xa97c,
+ 0xa980, 0xa9cd,
+ 0xa9cf, 0xa9d9,
+ 0xa9de, 0xa9df,
+ 0xaa00, 0xaa36,
+ 0xaa40, 0xaa4d,
+ 0xaa50, 0xaa59,
+ 0xaa5c, 0xaa7b,
+ 0xaa80, 0xaac2,
+ 0xaadb, 0xaaf6,
+ 0xab01, 0xab06,
+ 0xab09, 0xab0e,
+ 0xab11, 0xab16,
+ 0xab20, 0xab26,
+ 0xab28, 0xab2e,
+ 0xabc0, 0xabed,
+ 0xabf0, 0xabf9,
+ 0xac00, 0xd7a3,
+ 0xd7b0, 0xd7c6,
+ 0xd7cb, 0xd7fb,
+ 0xd800, 0xfa6d,
+ 0xfa70, 0xfad9,
+ 0xfb00, 0xfb06,
+ 0xfb13, 0xfb17,
+ 0xfb1d, 0xfb36,
+ 0xfb38, 0xfb3c,
+ 0xfb3e, 0xfb3e,
+ 0xfb40, 0xfb41,
+ 0xfb43, 0xfb44,
+ 0xfb46, 0xfbc1,
+ 0xfbd3, 0xfd3f,
+ 0xfd50, 0xfd8f,
+ 0xfd92, 0xfdc7,
+ 0xfdd0, 0xfdfd,
+ 0xfe00, 0xfe19,
+ 0xfe20, 0xfe26,
+ 0xfe30, 0xfe52,
+ 0xfe54, 0xfe66,
+ 0xfe68, 0xfe6b,
+ 0xfe70, 0xfe74,
+ 0xfe76, 0xfefc,
+ 0xfeff, 0xfeff,
+ 0xff01, 0xffbe,
+ 0xffc2, 0xffc7,
+ 0xffca, 0xffcf,
+ 0xffd2, 0xffd7,
+ 0xffda, 0xffdc,
+ 0xffe0, 0xffe6,
+ 0xffe8, 0xffee,
+ 0xfff9, 0x1000b,
+ 0x1000d, 0x10026,
+ 0x10028, 0x1003a,
+ 0x1003c, 0x1003d,
+ 0x1003f, 0x1004d,
+ 0x10050, 0x1005d,
+ 0x10080, 0x100fa,
+ 0x10100, 0x10102,
+ 0x10107, 0x10133,
+ 0x10137, 0x1018a,
+ 0x10190, 0x1019b,
+ 0x101d0, 0x101fd,
+ 0x10280, 0x1029c,
+ 0x102a0, 0x102d0,
+ 0x10300, 0x1031e,
+ 0x10320, 0x10323,
+ 0x10330, 0x1034a,
+ 0x10380, 0x1039d,
+ 0x1039f, 0x103c3,
+ 0x103c8, 0x103d5,
+ 0x10400, 0x1049d,
+ 0x104a0, 0x104a9,
+ 0x10800, 0x10805,
+ 0x10808, 0x10808,
+ 0x1080a, 0x10835,
+ 0x10837, 0x10838,
+ 0x1083c, 0x1083c,
+ 0x1083f, 0x10855,
+ 0x10857, 0x1085f,
+ 0x10900, 0x1091b,
+ 0x1091f, 0x10939,
+ 0x1093f, 0x1093f,
+ 0x10980, 0x109b7,
+ 0x109be, 0x109bf,
+ 0x10a00, 0x10a03,
+ 0x10a05, 0x10a06,
+ 0x10a0c, 0x10a13,
+ 0x10a15, 0x10a17,
+ 0x10a19, 0x10a33,
+ 0x10a38, 0x10a3a,
+ 0x10a3f, 0x10a47,
+ 0x10a50, 0x10a58,
+ 0x10a60, 0x10a7f,
+ 0x10b00, 0x10b35,
+ 0x10b39, 0x10b55,
+ 0x10b58, 0x10b72,
+ 0x10b78, 0x10b7f,
+ 0x10c00, 0x10c48,
+ 0x10e60, 0x10e7e,
+ 0x11000, 0x1104d,
+ 0x11052, 0x1106f,
+ 0x11080, 0x110c1,
+ 0x110d0, 0x110e8,
+ 0x110f0, 0x110f9,
+ 0x11100, 0x11134,
+ 0x11136, 0x11143,
+ 0x11180, 0x111c8,
+ 0x111d0, 0x111d9,
+ 0x11680, 0x116b7,
+ 0x116c0, 0x116c9,
+ 0x12000, 0x1236e,
+ 0x12400, 0x12462,
+ 0x12470, 0x12473,
+ 0x13000, 0x1342e,
+ 0x16800, 0x16a38,
+ 0x16f00, 0x16f44,
+ 0x16f50, 0x16f7e,
+ 0x16f8f, 0x16f9f,
+ 0x1b000, 0x1b001,
+ 0x1d000, 0x1d0f5,
+ 0x1d100, 0x1d126,
+ 0x1d129, 0x1d1dd,
+ 0x1d200, 0x1d245,
+ 0x1d300, 0x1d356,
+ 0x1d360, 0x1d371,
+ 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, 0x1d7cb,
+ 0x1d7ce, 0x1d7ff,
+ 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,
+ 0x1eef0, 0x1eef1,
+ 0x1f000, 0x1f02b,
+ 0x1f030, 0x1f093,
+ 0x1f0a0, 0x1f0ae,
+ 0x1f0b1, 0x1f0be,
+ 0x1f0c1, 0x1f0cf,
+ 0x1f0d1, 0x1f0df,
+ 0x1f100, 0x1f10a,
+ 0x1f110, 0x1f12e,
+ 0x1f130, 0x1f16b,
+ 0x1f170, 0x1f19a,
+ 0x1f1e6, 0x1f202,
+ 0x1f210, 0x1f23a,
+ 0x1f240, 0x1f248,
+ 0x1f250, 0x1f251,
+ 0x1f300, 0x1f320,
+ 0x1f330, 0x1f335,
+ 0x1f337, 0x1f37c,
+ 0x1f380, 0x1f393,
+ 0x1f3a0, 0x1f3c4,
+ 0x1f3c6, 0x1f3ca,
+ 0x1f3e0, 0x1f3f0,
+ 0x1f400, 0x1f43e,
+ 0x1f440, 0x1f440,
+ 0x1f442, 0x1f4f7,
+ 0x1f4f9, 0x1f4fc,
+ 0x1f500, 0x1f53d,
+ 0x1f540, 0x1f543,
+ 0x1f550, 0x1f567,
+ 0x1f5fb, 0x1f640,
+ 0x1f645, 0x1f64f,
+ 0x1f680, 0x1f6c5,
+ 0x1f700, 0x1f773,
+ 0x1fffe, 0x2a6d6,
+ 0x2a700, 0x2b734,
+ 0x2b740, 0x2b81d,
+ 0x2f800, 0x2fa1d,
+ 0x2fffe, 0x2ffff,
+ 0x3fffe, 0x3ffff,
+ 0x4fffe, 0x4ffff,
+ 0x5fffe, 0x5ffff,
+ 0x6fffe, 0x6ffff,
+ 0x7fffe, 0x7ffff,
+ 0x8fffe, 0x8ffff,
+ 0x9fffe, 0x9ffff,
+ 0xafffe, 0xaffff,
+ 0xbfffe, 0xbffff,
+ 0xcfffe, 0xcffff,
+ 0xdfffe, 0xdffff,
+ 0xe0001, 0xe0001,
+ 0xe0020, 0xe007f,
+ 0xe0100, 0xe01ef,
+ 0xefffe, 0x10ffff,
+}; /* CR_Age_6_2 */
+
+/* 'Age_6_3': Derived Age 6.3 */
+static const OnigCodePoint CR_Age_6_3[] = {
+ 549,
+ 0x0000, 0x0377,
+ 0x037a, 0x037e,
+ 0x0384, 0x038a,
+ 0x038c, 0x038c,
+ 0x038e, 0x03a1,
+ 0x03a3, 0x0527,
+ 0x0531, 0x0556,
+ 0x0559, 0x055f,
+ 0x0561, 0x0587,
+ 0x0589, 0x058a,
+ 0x058f, 0x058f,
+ 0x0591, 0x05c7,
+ 0x05d0, 0x05ea,
+ 0x05f0, 0x05f4,
+ 0x0600, 0x0604,
+ 0x0606, 0x061c,
+ 0x061e, 0x070d,
+ 0x070f, 0x074a,
+ 0x074d, 0x07b1,
+ 0x07c0, 0x07fa,
+ 0x0800, 0x082d,
+ 0x0830, 0x083e,
+ 0x0840, 0x085b,
+ 0x085e, 0x085e,
+ 0x08a0, 0x08a0,
+ 0x08a2, 0x08ac,
+ 0x08e4, 0x08fe,
+ 0x0900, 0x0977,
+ 0x0979, 0x097f,
+ 0x0981, 0x0983,
+ 0x0985, 0x098c,
+ 0x098f, 0x0990,
+ 0x0993, 0x09a8,
+ 0x09aa, 0x09b0,
+ 0x09b2, 0x09b2,
+ 0x09b6, 0x09b9,
+ 0x09bc, 0x09c4,
+ 0x09c7, 0x09c8,
+ 0x09cb, 0x09ce,
+ 0x09d7, 0x09d7,
+ 0x09dc, 0x09dd,
+ 0x09df, 0x09e3,
+ 0x09e6, 0x09fb,
+ 0x0a01, 0x0a03,
+ 0x0a05, 0x0a0a,
+ 0x0a0f, 0x0a10,
+ 0x0a13, 0x0a28,
+ 0x0a2a, 0x0a30,
+ 0x0a32, 0x0a33,
+ 0x0a35, 0x0a36,
+ 0x0a38, 0x0a39,
+ 0x0a3c, 0x0a3c,
+ 0x0a3e, 0x0a42,
+ 0x0a47, 0x0a48,
+ 0x0a4b, 0x0a4d,
+ 0x0a51, 0x0a51,
+ 0x0a59, 0x0a5c,
+ 0x0a5e, 0x0a5e,
+ 0x0a66, 0x0a75,
+ 0x0a81, 0x0a83,
+ 0x0a85, 0x0a8d,
+ 0x0a8f, 0x0a91,
+ 0x0a93, 0x0aa8,
+ 0x0aaa, 0x0ab0,
+ 0x0ab2, 0x0ab3,
+ 0x0ab5, 0x0ab9,
+ 0x0abc, 0x0ac5,
+ 0x0ac7, 0x0ac9,
+ 0x0acb, 0x0acd,
+ 0x0ad0, 0x0ad0,
+ 0x0ae0, 0x0ae3,
+ 0x0ae6, 0x0af1,
+ 0x0b01, 0x0b03,
+ 0x0b05, 0x0b0c,
+ 0x0b0f, 0x0b10,
+ 0x0b13, 0x0b28,
+ 0x0b2a, 0x0b30,
+ 0x0b32, 0x0b33,
+ 0x0b35, 0x0b39,
+ 0x0b3c, 0x0b44,
+ 0x0b47, 0x0b48,
+ 0x0b4b, 0x0b4d,
+ 0x0b56, 0x0b57,
+ 0x0b5c, 0x0b5d,
+ 0x0b5f, 0x0b63,
+ 0x0b66, 0x0b77,
+ 0x0b82, 0x0b83,
+ 0x0b85, 0x0b8a,
+ 0x0b8e, 0x0b90,
+ 0x0b92, 0x0b95,
+ 0x0b99, 0x0b9a,
+ 0x0b9c, 0x0b9c,
+ 0x0b9e, 0x0b9f,
+ 0x0ba3, 0x0ba4,
+ 0x0ba8, 0x0baa,
+ 0x0bae, 0x0bb9,
+ 0x0bbe, 0x0bc2,
+ 0x0bc6, 0x0bc8,
+ 0x0bca, 0x0bcd,
+ 0x0bd0, 0x0bd0,
+ 0x0bd7, 0x0bd7,
+ 0x0be6, 0x0bfa,
+ 0x0c01, 0x0c03,
+ 0x0c05, 0x0c0c,
+ 0x0c0e, 0x0c10,
+ 0x0c12, 0x0c28,
+ 0x0c2a, 0x0c33,
+ 0x0c35, 0x0c39,
+ 0x0c3d, 0x0c44,
+ 0x0c46, 0x0c48,
+ 0x0c4a, 0x0c4d,
+ 0x0c55, 0x0c56,
+ 0x0c58, 0x0c59,
+ 0x0c60, 0x0c63,
+ 0x0c66, 0x0c6f,
+ 0x0c78, 0x0c7f,
+ 0x0c82, 0x0c83,
+ 0x0c85, 0x0c8c,
+ 0x0c8e, 0x0c90,
+ 0x0c92, 0x0ca8,
+ 0x0caa, 0x0cb3,
+ 0x0cb5, 0x0cb9,
+ 0x0cbc, 0x0cc4,
+ 0x0cc6, 0x0cc8,
+ 0x0cca, 0x0ccd,
+ 0x0cd5, 0x0cd6,
+ 0x0cde, 0x0cde,
+ 0x0ce0, 0x0ce3,
+ 0x0ce6, 0x0cef,
+ 0x0cf1, 0x0cf2,
+ 0x0d02, 0x0d03,
+ 0x0d05, 0x0d0c,
+ 0x0d0e, 0x0d10,
+ 0x0d12, 0x0d3a,
+ 0x0d3d, 0x0d44,
+ 0x0d46, 0x0d48,
+ 0x0d4a, 0x0d4e,
+ 0x0d57, 0x0d57,
+ 0x0d60, 0x0d63,
+ 0x0d66, 0x0d75,
+ 0x0d79, 0x0d7f,
+ 0x0d82, 0x0d83,
+ 0x0d85, 0x0d96,
+ 0x0d9a, 0x0db1,
+ 0x0db3, 0x0dbb,
+ 0x0dbd, 0x0dbd,
+ 0x0dc0, 0x0dc6,
+ 0x0dca, 0x0dca,
+ 0x0dcf, 0x0dd4,
+ 0x0dd6, 0x0dd6,
+ 0x0dd8, 0x0ddf,
+ 0x0df2, 0x0df4,
+ 0x0e01, 0x0e3a,
+ 0x0e3f, 0x0e5b,
+ 0x0e81, 0x0e82,
+ 0x0e84, 0x0e84,
+ 0x0e87, 0x0e88,
+ 0x0e8a, 0x0e8a,
+ 0x0e8d, 0x0e8d,
+ 0x0e94, 0x0e97,
+ 0x0e99, 0x0e9f,
+ 0x0ea1, 0x0ea3,
+ 0x0ea5, 0x0ea5,
+ 0x0ea7, 0x0ea7,
+ 0x0eaa, 0x0eab,
+ 0x0ead, 0x0eb9,
+ 0x0ebb, 0x0ebd,
+ 0x0ec0, 0x0ec4,
+ 0x0ec6, 0x0ec6,
+ 0x0ec8, 0x0ecd,
+ 0x0ed0, 0x0ed9,
+ 0x0edc, 0x0edf,
+ 0x0f00, 0x0f47,
+ 0x0f49, 0x0f6c,
+ 0x0f71, 0x0f97,
+ 0x0f99, 0x0fbc,
+ 0x0fbe, 0x0fcc,
+ 0x0fce, 0x0fda,
+ 0x1000, 0x10c5,
+ 0x10c7, 0x10c7,
+ 0x10cd, 0x10cd,
+ 0x10d0, 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,
+ 0x135d, 0x137c,
+ 0x1380, 0x1399,
+ 0x13a0, 0x13f4,
+ 0x1400, 0x169c,
+ 0x16a0, 0x16f0,
+ 0x1700, 0x170c,
+ 0x170e, 0x1714,
+ 0x1720, 0x1736,
+ 0x1740, 0x1753,
+ 0x1760, 0x176c,
+ 0x176e, 0x1770,
+ 0x1772, 0x1773,
+ 0x1780, 0x17dd,
+ 0x17e0, 0x17e9,
+ 0x17f0, 0x17f9,
+ 0x1800, 0x180e,
+ 0x1810, 0x1819,
+ 0x1820, 0x1877,
+ 0x1880, 0x18aa,
+ 0x18b0, 0x18f5,
+ 0x1900, 0x191c,
+ 0x1920, 0x192b,
+ 0x1930, 0x193b,
+ 0x1940, 0x1940,
+ 0x1944, 0x196d,
+ 0x1970, 0x1974,
+ 0x1980, 0x19ab,
+ 0x19b0, 0x19c9,
+ 0x19d0, 0x19da,
+ 0x19de, 0x1a1b,
+ 0x1a1e, 0x1a5e,
+ 0x1a60, 0x1a7c,
+ 0x1a7f, 0x1a89,
+ 0x1a90, 0x1a99,
+ 0x1aa0, 0x1aad,
+ 0x1b00, 0x1b4b,
+ 0x1b50, 0x1b7c,
+ 0x1b80, 0x1bf3,
+ 0x1bfc, 0x1c37,
+ 0x1c3b, 0x1c49,
+ 0x1c4d, 0x1c7f,
+ 0x1cc0, 0x1cc7,
+ 0x1cd0, 0x1cf6,
+ 0x1d00, 0x1de6,
+ 0x1dfc, 0x1f15,
+ 0x1f18, 0x1f1d,
+ 0x1f20, 0x1f45,
+ 0x1f48, 0x1f4d,
+ 0x1f50, 0x1f57,
+ 0x1f59, 0x1f59,
+ 0x1f5b, 0x1f5b,
+ 0x1f5d, 0x1f5d,
+ 0x1f5f, 0x1f7d,
+ 0x1f80, 0x1fb4,
+ 0x1fb6, 0x1fc4,
+ 0x1fc6, 0x1fd3,
+ 0x1fd6, 0x1fdb,
+ 0x1fdd, 0x1fef,
+ 0x1ff2, 0x1ff4,
+ 0x1ff6, 0x1ffe,
+ 0x2000, 0x2064,
+ 0x2066, 0x2071,
+ 0x2074, 0x208e,
+ 0x2090, 0x209c,
+ 0x20a0, 0x20ba,
+ 0x20d0, 0x20f0,
+ 0x2100, 0x2189,
+ 0x2190, 0x23f3,
+ 0x2400, 0x2426,
+ 0x2440, 0x244a,
+ 0x2460, 0x26ff,
+ 0x2701, 0x2b4c,
+ 0x2b50, 0x2b59,
+ 0x2c00, 0x2c2e,
+ 0x2c30, 0x2c5e,
+ 0x2c60, 0x2cf3,
+ 0x2cf9, 0x2d25,
+ 0x2d27, 0x2d27,
+ 0x2d2d, 0x2d2d,
+ 0x2d30, 0x2d67,
+ 0x2d6f, 0x2d70,
+ 0x2d7f, 0x2d96,
+ 0x2da0, 0x2da6,
+ 0x2da8, 0x2dae,
+ 0x2db0, 0x2db6,
+ 0x2db8, 0x2dbe,
+ 0x2dc0, 0x2dc6,
+ 0x2dc8, 0x2dce,
+ 0x2dd0, 0x2dd6,
+ 0x2dd8, 0x2dde,
+ 0x2de0, 0x2e3b,
+ 0x2e80, 0x2e99,
+ 0x2e9b, 0x2ef3,
+ 0x2f00, 0x2fd5,
+ 0x2ff0, 0x2ffb,
+ 0x3000, 0x303f,
+ 0x3041, 0x3096,
+ 0x3099, 0x30ff,
+ 0x3105, 0x312d,
+ 0x3131, 0x318e,
+ 0x3190, 0x31ba,
+ 0x31c0, 0x31e3,
+ 0x31f0, 0x321e,
+ 0x3220, 0x32fe,
+ 0x3300, 0x4db5,
+ 0x4dc0, 0x9fcc,
+ 0xa000, 0xa48c,
+ 0xa490, 0xa4c6,
+ 0xa4d0, 0xa62b,
+ 0xa640, 0xa697,
+ 0xa69f, 0xa6f7,
+ 0xa700, 0xa78e,
+ 0xa790, 0xa793,
+ 0xa7a0, 0xa7aa,
+ 0xa7f8, 0xa82b,
+ 0xa830, 0xa839,
+ 0xa840, 0xa877,
+ 0xa880, 0xa8c4,
+ 0xa8ce, 0xa8d9,
+ 0xa8e0, 0xa8fb,
+ 0xa900, 0xa953,
+ 0xa95f, 0xa97c,
+ 0xa980, 0xa9cd,
+ 0xa9cf, 0xa9d9,
+ 0xa9de, 0xa9df,
+ 0xaa00, 0xaa36,
+ 0xaa40, 0xaa4d,
+ 0xaa50, 0xaa59,
+ 0xaa5c, 0xaa7b,
+ 0xaa80, 0xaac2,
+ 0xaadb, 0xaaf6,
+ 0xab01, 0xab06,
+ 0xab09, 0xab0e,
+ 0xab11, 0xab16,
+ 0xab20, 0xab26,
+ 0xab28, 0xab2e,
+ 0xabc0, 0xabed,
+ 0xabf0, 0xabf9,
+ 0xac00, 0xd7a3,
+ 0xd7b0, 0xd7c6,
+ 0xd7cb, 0xd7fb,
+ 0xd800, 0xfa6d,
+ 0xfa70, 0xfad9,
+ 0xfb00, 0xfb06,
+ 0xfb13, 0xfb17,
+ 0xfb1d, 0xfb36,
+ 0xfb38, 0xfb3c,
+ 0xfb3e, 0xfb3e,
+ 0xfb40, 0xfb41,
+ 0xfb43, 0xfb44,
+ 0xfb46, 0xfbc1,
+ 0xfbd3, 0xfd3f,
+ 0xfd50, 0xfd8f,
+ 0xfd92, 0xfdc7,
+ 0xfdd0, 0xfdfd,
+ 0xfe00, 0xfe19,
+ 0xfe20, 0xfe26,
+ 0xfe30, 0xfe52,
+ 0xfe54, 0xfe66,
+ 0xfe68, 0xfe6b,
+ 0xfe70, 0xfe74,
+ 0xfe76, 0xfefc,
+ 0xfeff, 0xfeff,
+ 0xff01, 0xffbe,
+ 0xffc2, 0xffc7,
+ 0xffca, 0xffcf,
+ 0xffd2, 0xffd7,
+ 0xffda, 0xffdc,
+ 0xffe0, 0xffe6,
+ 0xffe8, 0xffee,
+ 0xfff9, 0x1000b,
+ 0x1000d, 0x10026,
+ 0x10028, 0x1003a,
+ 0x1003c, 0x1003d,
+ 0x1003f, 0x1004d,
+ 0x10050, 0x1005d,
+ 0x10080, 0x100fa,
+ 0x10100, 0x10102,
+ 0x10107, 0x10133,
+ 0x10137, 0x1018a,
+ 0x10190, 0x1019b,
+ 0x101d0, 0x101fd,
+ 0x10280, 0x1029c,
+ 0x102a0, 0x102d0,
+ 0x10300, 0x1031e,
+ 0x10320, 0x10323,
+ 0x10330, 0x1034a,
+ 0x10380, 0x1039d,
+ 0x1039f, 0x103c3,
+ 0x103c8, 0x103d5,
+ 0x10400, 0x1049d,
+ 0x104a0, 0x104a9,
+ 0x10800, 0x10805,
+ 0x10808, 0x10808,
+ 0x1080a, 0x10835,
+ 0x10837, 0x10838,
+ 0x1083c, 0x1083c,
+ 0x1083f, 0x10855,
+ 0x10857, 0x1085f,
+ 0x10900, 0x1091b,
+ 0x1091f, 0x10939,
+ 0x1093f, 0x1093f,
+ 0x10980, 0x109b7,
+ 0x109be, 0x109bf,
+ 0x10a00, 0x10a03,
+ 0x10a05, 0x10a06,
+ 0x10a0c, 0x10a13,
+ 0x10a15, 0x10a17,
+ 0x10a19, 0x10a33,
+ 0x10a38, 0x10a3a,
+ 0x10a3f, 0x10a47,
+ 0x10a50, 0x10a58,
+ 0x10a60, 0x10a7f,
+ 0x10b00, 0x10b35,
+ 0x10b39, 0x10b55,
+ 0x10b58, 0x10b72,
+ 0x10b78, 0x10b7f,
+ 0x10c00, 0x10c48,
+ 0x10e60, 0x10e7e,
+ 0x11000, 0x1104d,
+ 0x11052, 0x1106f,
+ 0x11080, 0x110c1,
+ 0x110d0, 0x110e8,
+ 0x110f0, 0x110f9,
+ 0x11100, 0x11134,
+ 0x11136, 0x11143,
+ 0x11180, 0x111c8,
+ 0x111d0, 0x111d9,
+ 0x11680, 0x116b7,
+ 0x116c0, 0x116c9,
+ 0x12000, 0x1236e,
+ 0x12400, 0x12462,
+ 0x12470, 0x12473,
+ 0x13000, 0x1342e,
+ 0x16800, 0x16a38,
+ 0x16f00, 0x16f44,
+ 0x16f50, 0x16f7e,
+ 0x16f8f, 0x16f9f,
+ 0x1b000, 0x1b001,
+ 0x1d000, 0x1d0f5,
+ 0x1d100, 0x1d126,
+ 0x1d129, 0x1d1dd,
+ 0x1d200, 0x1d245,
+ 0x1d300, 0x1d356,
+ 0x1d360, 0x1d371,
+ 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, 0x1d7cb,
+ 0x1d7ce, 0x1d7ff,
+ 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,
+ 0x1eef0, 0x1eef1,
+ 0x1f000, 0x1f02b,
+ 0x1f030, 0x1f093,
+ 0x1f0a0, 0x1f0ae,
+ 0x1f0b1, 0x1f0be,
+ 0x1f0c1, 0x1f0cf,
+ 0x1f0d1, 0x1f0df,
+ 0x1f100, 0x1f10a,
+ 0x1f110, 0x1f12e,
+ 0x1f130, 0x1f16b,
+ 0x1f170, 0x1f19a,
+ 0x1f1e6, 0x1f202,
+ 0x1f210, 0x1f23a,
+ 0x1f240, 0x1f248,
+ 0x1f250, 0x1f251,
+ 0x1f300, 0x1f320,
+ 0x1f330, 0x1f335,
+ 0x1f337, 0x1f37c,
+ 0x1f380, 0x1f393,
+ 0x1f3a0, 0x1f3c4,
+ 0x1f3c6, 0x1f3ca,
+ 0x1f3e0, 0x1f3f0,
+ 0x1f400, 0x1f43e,
+ 0x1f440, 0x1f440,
+ 0x1f442, 0x1f4f7,
+ 0x1f4f9, 0x1f4fc,
+ 0x1f500, 0x1f53d,
+ 0x1f540, 0x1f543,
+ 0x1f550, 0x1f567,
+ 0x1f5fb, 0x1f640,
+ 0x1f645, 0x1f64f,
+ 0x1f680, 0x1f6c5,
+ 0x1f700, 0x1f773,
+ 0x1fffe, 0x2a6d6,
+ 0x2a700, 0x2b734,
+ 0x2b740, 0x2b81d,
+ 0x2f800, 0x2fa1d,
+ 0x2fffe, 0x2ffff,
+ 0x3fffe, 0x3ffff,
+ 0x4fffe, 0x4ffff,
+ 0x5fffe, 0x5ffff,
+ 0x6fffe, 0x6ffff,
+ 0x7fffe, 0x7ffff,
+ 0x8fffe, 0x8ffff,
+ 0x9fffe, 0x9ffff,
+ 0xafffe, 0xaffff,
+ 0xbfffe, 0xbffff,
+ 0xcfffe, 0xcffff,
+ 0xdfffe, 0xdffff,
+ 0xe0001, 0xe0001,
+ 0xe0020, 0xe007f,
+ 0xe0100, 0xe01ef,
+ 0xefffe, 0x10ffff,
+}; /* CR_Age_6_3 */
+
+/* 'Age_7_0': Derived Age 7.0 */
+static const OnigCodePoint CR_Age_7_0[] = {
+ 610,
+ 0x0000, 0x0377,
+ 0x037a, 0x037f,
+ 0x0384, 0x038a,
+ 0x038c, 0x038c,
+ 0x038e, 0x03a1,
+ 0x03a3, 0x052f,
+ 0x0531, 0x0556,
+ 0x0559, 0x055f,
+ 0x0561, 0x0587,
+ 0x0589, 0x058a,
+ 0x058d, 0x058f,
+ 0x0591, 0x05c7,
+ 0x05d0, 0x05ea,
+ 0x05f0, 0x05f4,
+ 0x0600, 0x061c,
+ 0x061e, 0x070d,
+ 0x070f, 0x074a,
+ 0x074d, 0x07b1,
+ 0x07c0, 0x07fa,
+ 0x0800, 0x082d,
+ 0x0830, 0x083e,
+ 0x0840, 0x085b,
+ 0x085e, 0x085e,
+ 0x08a0, 0x08b2,
+ 0x08e4, 0x0983,
+ 0x0985, 0x098c,
+ 0x098f, 0x0990,
+ 0x0993, 0x09a8,
+ 0x09aa, 0x09b0,
+ 0x09b2, 0x09b2,
+ 0x09b6, 0x09b9,
+ 0x09bc, 0x09c4,
+ 0x09c7, 0x09c8,
+ 0x09cb, 0x09ce,
+ 0x09d7, 0x09d7,
+ 0x09dc, 0x09dd,
+ 0x09df, 0x09e3,
+ 0x09e6, 0x09fb,
+ 0x0a01, 0x0a03,
+ 0x0a05, 0x0a0a,
+ 0x0a0f, 0x0a10,
+ 0x0a13, 0x0a28,
+ 0x0a2a, 0x0a30,
+ 0x0a32, 0x0a33,
+ 0x0a35, 0x0a36,
+ 0x0a38, 0x0a39,
+ 0x0a3c, 0x0a3c,
+ 0x0a3e, 0x0a42,
+ 0x0a47, 0x0a48,
+ 0x0a4b, 0x0a4d,
+ 0x0a51, 0x0a51,
+ 0x0a59, 0x0a5c,
+ 0x0a5e, 0x0a5e,
+ 0x0a66, 0x0a75,
+ 0x0a81, 0x0a83,
+ 0x0a85, 0x0a8d,
+ 0x0a8f, 0x0a91,
+ 0x0a93, 0x0aa8,
+ 0x0aaa, 0x0ab0,
+ 0x0ab2, 0x0ab3,
+ 0x0ab5, 0x0ab9,
+ 0x0abc, 0x0ac5,
+ 0x0ac7, 0x0ac9,
+ 0x0acb, 0x0acd,
+ 0x0ad0, 0x0ad0,
+ 0x0ae0, 0x0ae3,
+ 0x0ae6, 0x0af1,
+ 0x0b01, 0x0b03,
+ 0x0b05, 0x0b0c,
+ 0x0b0f, 0x0b10,
+ 0x0b13, 0x0b28,
+ 0x0b2a, 0x0b30,
+ 0x0b32, 0x0b33,
+ 0x0b35, 0x0b39,
+ 0x0b3c, 0x0b44,
+ 0x0b47, 0x0b48,
+ 0x0b4b, 0x0b4d,
+ 0x0b56, 0x0b57,
+ 0x0b5c, 0x0b5d,
+ 0x0b5f, 0x0b63,
+ 0x0b66, 0x0b77,
+ 0x0b82, 0x0b83,
+ 0x0b85, 0x0b8a,
+ 0x0b8e, 0x0b90,
+ 0x0b92, 0x0b95,
+ 0x0b99, 0x0b9a,
+ 0x0b9c, 0x0b9c,
+ 0x0b9e, 0x0b9f,
+ 0x0ba3, 0x0ba4,
+ 0x0ba8, 0x0baa,
+ 0x0bae, 0x0bb9,
+ 0x0bbe, 0x0bc2,
+ 0x0bc6, 0x0bc8,
+ 0x0bca, 0x0bcd,
+ 0x0bd0, 0x0bd0,
+ 0x0bd7, 0x0bd7,
+ 0x0be6, 0x0bfa,
+ 0x0c00, 0x0c03,
+ 0x0c05, 0x0c0c,
+ 0x0c0e, 0x0c10,
+ 0x0c12, 0x0c28,
+ 0x0c2a, 0x0c39,
+ 0x0c3d, 0x0c44,
+ 0x0c46, 0x0c48,
+ 0x0c4a, 0x0c4d,
+ 0x0c55, 0x0c56,
+ 0x0c58, 0x0c59,
+ 0x0c60, 0x0c63,
+ 0x0c66, 0x0c6f,
+ 0x0c78, 0x0c7f,
+ 0x0c81, 0x0c83,
+ 0x0c85, 0x0c8c,
+ 0x0c8e, 0x0c90,
+ 0x0c92, 0x0ca8,
+ 0x0caa, 0x0cb3,
+ 0x0cb5, 0x0cb9,
+ 0x0cbc, 0x0cc4,
+ 0x0cc6, 0x0cc8,
+ 0x0cca, 0x0ccd,
+ 0x0cd5, 0x0cd6,
+ 0x0cde, 0x0cde,
+ 0x0ce0, 0x0ce3,
+ 0x0ce6, 0x0cef,
+ 0x0cf1, 0x0cf2,
+ 0x0d01, 0x0d03,
+ 0x0d05, 0x0d0c,
+ 0x0d0e, 0x0d10,
+ 0x0d12, 0x0d3a,
+ 0x0d3d, 0x0d44,
+ 0x0d46, 0x0d48,
+ 0x0d4a, 0x0d4e,
+ 0x0d57, 0x0d57,
+ 0x0d60, 0x0d63,
+ 0x0d66, 0x0d75,
+ 0x0d79, 0x0d7f,
+ 0x0d82, 0x0d83,
+ 0x0d85, 0x0d96,
+ 0x0d9a, 0x0db1,
+ 0x0db3, 0x0dbb,
+ 0x0dbd, 0x0dbd,
+ 0x0dc0, 0x0dc6,
+ 0x0dca, 0x0dca,
+ 0x0dcf, 0x0dd4,
+ 0x0dd6, 0x0dd6,
+ 0x0dd8, 0x0ddf,
+ 0x0de6, 0x0def,
+ 0x0df2, 0x0df4,
+ 0x0e01, 0x0e3a,
+ 0x0e3f, 0x0e5b,
+ 0x0e81, 0x0e82,
+ 0x0e84, 0x0e84,
+ 0x0e87, 0x0e88,
+ 0x0e8a, 0x0e8a,
+ 0x0e8d, 0x0e8d,
+ 0x0e94, 0x0e97,
+ 0x0e99, 0x0e9f,
+ 0x0ea1, 0x0ea3,
+ 0x0ea5, 0x0ea5,
+ 0x0ea7, 0x0ea7,
+ 0x0eaa, 0x0eab,
+ 0x0ead, 0x0eb9,
+ 0x0ebb, 0x0ebd,
+ 0x0ec0, 0x0ec4,
+ 0x0ec6, 0x0ec6,
+ 0x0ec8, 0x0ecd,
+ 0x0ed0, 0x0ed9,
+ 0x0edc, 0x0edf,
+ 0x0f00, 0x0f47,
+ 0x0f49, 0x0f6c,
+ 0x0f71, 0x0f97,
+ 0x0f99, 0x0fbc,
+ 0x0fbe, 0x0fcc,
+ 0x0fce, 0x0fda,
+ 0x1000, 0x10c5,
+ 0x10c7, 0x10c7,
+ 0x10cd, 0x10cd,
+ 0x10d0, 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,
+ 0x135d, 0x137c,
+ 0x1380, 0x1399,
+ 0x13a0, 0x13f4,
+ 0x1400, 0x169c,
+ 0x16a0, 0x16f8,
+ 0x1700, 0x170c,
+ 0x170e, 0x1714,
+ 0x1720, 0x1736,
+ 0x1740, 0x1753,
+ 0x1760, 0x176c,
+ 0x176e, 0x1770,
+ 0x1772, 0x1773,
+ 0x1780, 0x17dd,
+ 0x17e0, 0x17e9,
+ 0x17f0, 0x17f9,
+ 0x1800, 0x180e,
+ 0x1810, 0x1819,
+ 0x1820, 0x1877,
+ 0x1880, 0x18aa,
+ 0x18b0, 0x18f5,
+ 0x1900, 0x191e,
+ 0x1920, 0x192b,
+ 0x1930, 0x193b,
+ 0x1940, 0x1940,
+ 0x1944, 0x196d,
+ 0x1970, 0x1974,
+ 0x1980, 0x19ab,
+ 0x19b0, 0x19c9,
+ 0x19d0, 0x19da,
+ 0x19de, 0x1a1b,
+ 0x1a1e, 0x1a5e,
+ 0x1a60, 0x1a7c,
+ 0x1a7f, 0x1a89,
+ 0x1a90, 0x1a99,
+ 0x1aa0, 0x1aad,
+ 0x1ab0, 0x1abe,
+ 0x1b00, 0x1b4b,
+ 0x1b50, 0x1b7c,
+ 0x1b80, 0x1bf3,
+ 0x1bfc, 0x1c37,
+ 0x1c3b, 0x1c49,
+ 0x1c4d, 0x1c7f,
+ 0x1cc0, 0x1cc7,
+ 0x1cd0, 0x1cf6,
+ 0x1cf8, 0x1cf9,
+ 0x1d00, 0x1df5,
+ 0x1dfc, 0x1f15,
+ 0x1f18, 0x1f1d,
+ 0x1f20, 0x1f45,
+ 0x1f48, 0x1f4d,
+ 0x1f50, 0x1f57,
+ 0x1f59, 0x1f59,
+ 0x1f5b, 0x1f5b,
+ 0x1f5d, 0x1f5d,
+ 0x1f5f, 0x1f7d,
+ 0x1f80, 0x1fb4,
+ 0x1fb6, 0x1fc4,
+ 0x1fc6, 0x1fd3,
+ 0x1fd6, 0x1fdb,
+ 0x1fdd, 0x1fef,
+ 0x1ff2, 0x1ff4,
+ 0x1ff6, 0x1ffe,
+ 0x2000, 0x2064,
+ 0x2066, 0x2071,
+ 0x2074, 0x208e,
+ 0x2090, 0x209c,
+ 0x20a0, 0x20bd,
+ 0x20d0, 0x20f0,
+ 0x2100, 0x2189,
+ 0x2190, 0x23fa,
+ 0x2400, 0x2426,
+ 0x2440, 0x244a,
+ 0x2460, 0x2b73,
+ 0x2b76, 0x2b95,
+ 0x2b98, 0x2bb9,
+ 0x2bbd, 0x2bc8,
+ 0x2bca, 0x2bd1,
+ 0x2c00, 0x2c2e,
+ 0x2c30, 0x2c5e,
+ 0x2c60, 0x2cf3,
+ 0x2cf9, 0x2d25,
+ 0x2d27, 0x2d27,
+ 0x2d2d, 0x2d2d,
+ 0x2d30, 0x2d67,
+ 0x2d6f, 0x2d70,
+ 0x2d7f, 0x2d96,
+ 0x2da0, 0x2da6,
+ 0x2da8, 0x2dae,
+ 0x2db0, 0x2db6,
+ 0x2db8, 0x2dbe,
+ 0x2dc0, 0x2dc6,
+ 0x2dc8, 0x2dce,
+ 0x2dd0, 0x2dd6,
+ 0x2dd8, 0x2dde,
+ 0x2de0, 0x2e42,
+ 0x2e80, 0x2e99,
+ 0x2e9b, 0x2ef3,
+ 0x2f00, 0x2fd5,
+ 0x2ff0, 0x2ffb,
+ 0x3000, 0x303f,
+ 0x3041, 0x3096,
+ 0x3099, 0x30ff,
+ 0x3105, 0x312d,
+ 0x3131, 0x318e,
+ 0x3190, 0x31ba,
+ 0x31c0, 0x31e3,
+ 0x31f0, 0x321e,
+ 0x3220, 0x32fe,
+ 0x3300, 0x4db5,
+ 0x4dc0, 0x9fcc,
+ 0xa000, 0xa48c,
+ 0xa490, 0xa4c6,
+ 0xa4d0, 0xa62b,
+ 0xa640, 0xa69d,
+ 0xa69f, 0xa6f7,
+ 0xa700, 0xa78e,
+ 0xa790, 0xa7ad,
+ 0xa7b0, 0xa7b1,
+ 0xa7f7, 0xa82b,
+ 0xa830, 0xa839,
+ 0xa840, 0xa877,
+ 0xa880, 0xa8c4,
+ 0xa8ce, 0xa8d9,
+ 0xa8e0, 0xa8fb,
+ 0xa900, 0xa953,
+ 0xa95f, 0xa97c,
+ 0xa980, 0xa9cd,
+ 0xa9cf, 0xa9d9,
+ 0xa9de, 0xa9fe,
+ 0xaa00, 0xaa36,
+ 0xaa40, 0xaa4d,
+ 0xaa50, 0xaa59,
+ 0xaa5c, 0xaac2,
+ 0xaadb, 0xaaf6,
+ 0xab01, 0xab06,
+ 0xab09, 0xab0e,
+ 0xab11, 0xab16,
+ 0xab20, 0xab26,
+ 0xab28, 0xab2e,
+ 0xab30, 0xab5f,
+ 0xab64, 0xab65,
+ 0xabc0, 0xabed,
+ 0xabf0, 0xabf9,
+ 0xac00, 0xd7a3,
+ 0xd7b0, 0xd7c6,
+ 0xd7cb, 0xd7fb,
+ 0xd800, 0xfa6d,
+ 0xfa70, 0xfad9,
+ 0xfb00, 0xfb06,
+ 0xfb13, 0xfb17,
+ 0xfb1d, 0xfb36,
+ 0xfb38, 0xfb3c,
+ 0xfb3e, 0xfb3e,
+ 0xfb40, 0xfb41,
+ 0xfb43, 0xfb44,
+ 0xfb46, 0xfbc1,
+ 0xfbd3, 0xfd3f,
+ 0xfd50, 0xfd8f,
+ 0xfd92, 0xfdc7,
+ 0xfdd0, 0xfdfd,
+ 0xfe00, 0xfe19,
+ 0xfe20, 0xfe2d,
+ 0xfe30, 0xfe52,
+ 0xfe54, 0xfe66,
+ 0xfe68, 0xfe6b,
+ 0xfe70, 0xfe74,
+ 0xfe76, 0xfefc,
+ 0xfeff, 0xfeff,
+ 0xff01, 0xffbe,
+ 0xffc2, 0xffc7,
+ 0xffca, 0xffcf,
+ 0xffd2, 0xffd7,
+ 0xffda, 0xffdc,
+ 0xffe0, 0xffe6,
+ 0xffe8, 0xffee,
+ 0xfff9, 0x1000b,
+ 0x1000d, 0x10026,
+ 0x10028, 0x1003a,
+ 0x1003c, 0x1003d,
+ 0x1003f, 0x1004d,
+ 0x10050, 0x1005d,
+ 0x10080, 0x100fa,
+ 0x10100, 0x10102,
+ 0x10107, 0x10133,
+ 0x10137, 0x1018c,
+ 0x10190, 0x1019b,
+ 0x101a0, 0x101a0,
+ 0x101d0, 0x101fd,
+ 0x10280, 0x1029c,
+ 0x102a0, 0x102d0,
+ 0x102e0, 0x102fb,
+ 0x10300, 0x10323,
+ 0x10330, 0x1034a,
+ 0x10350, 0x1037a,
+ 0x10380, 0x1039d,
+ 0x1039f, 0x103c3,
+ 0x103c8, 0x103d5,
+ 0x10400, 0x1049d,
+ 0x104a0, 0x104a9,
+ 0x10500, 0x10527,
+ 0x10530, 0x10563,
+ 0x1056f, 0x1056f,
+ 0x10600, 0x10736,
+ 0x10740, 0x10755,
+ 0x10760, 0x10767,
+ 0x10800, 0x10805,
+ 0x10808, 0x10808,
+ 0x1080a, 0x10835,
+ 0x10837, 0x10838,
+ 0x1083c, 0x1083c,
+ 0x1083f, 0x10855,
+ 0x10857, 0x1089e,
+ 0x108a7, 0x108af,
+ 0x10900, 0x1091b,
+ 0x1091f, 0x10939,
+ 0x1093f, 0x1093f,
+ 0x10980, 0x109b7,
+ 0x109be, 0x109bf,
+ 0x10a00, 0x10a03,
+ 0x10a05, 0x10a06,
+ 0x10a0c, 0x10a13,
+ 0x10a15, 0x10a17,
+ 0x10a19, 0x10a33,
+ 0x10a38, 0x10a3a,
+ 0x10a3f, 0x10a47,
+ 0x10a50, 0x10a58,
+ 0x10a60, 0x10a9f,
+ 0x10ac0, 0x10ae6,
+ 0x10aeb, 0x10af6,
+ 0x10b00, 0x10b35,
+ 0x10b39, 0x10b55,
+ 0x10b58, 0x10b72,
+ 0x10b78, 0x10b91,
+ 0x10b99, 0x10b9c,
+ 0x10ba9, 0x10baf,
+ 0x10c00, 0x10c48,
+ 0x10e60, 0x10e7e,
+ 0x11000, 0x1104d,
+ 0x11052, 0x1106f,
+ 0x1107f, 0x110c1,
+ 0x110d0, 0x110e8,
+ 0x110f0, 0x110f9,
+ 0x11100, 0x11134,
+ 0x11136, 0x11143,
+ 0x11150, 0x11176,
+ 0x11180, 0x111c8,
+ 0x111cd, 0x111cd,
+ 0x111d0, 0x111da,
+ 0x111e1, 0x111f4,
+ 0x11200, 0x11211,
+ 0x11213, 0x1123d,
+ 0x112b0, 0x112ea,
+ 0x112f0, 0x112f9,
+ 0x11301, 0x11303,
+ 0x11305, 0x1130c,
+ 0x1130f, 0x11310,
+ 0x11313, 0x11328,
+ 0x1132a, 0x11330,
+ 0x11332, 0x11333,
+ 0x11335, 0x11339,
+ 0x1133c, 0x11344,
+ 0x11347, 0x11348,
+ 0x1134b, 0x1134d,
+ 0x11357, 0x11357,
+ 0x1135d, 0x11363,
+ 0x11366, 0x1136c,
+ 0x11370, 0x11374,
+ 0x11480, 0x114c7,
+ 0x114d0, 0x114d9,
+ 0x11580, 0x115b5,
+ 0x115b8, 0x115c9,
+ 0x11600, 0x11644,
+ 0x11650, 0x11659,
+ 0x11680, 0x116b7,
+ 0x116c0, 0x116c9,
+ 0x118a0, 0x118f2,
+ 0x118ff, 0x118ff,
+ 0x11ac0, 0x11af8,
+ 0x12000, 0x12398,
+ 0x12400, 0x1246e,
+ 0x12470, 0x12474,
+ 0x13000, 0x1342e,
+ 0x16800, 0x16a38,
+ 0x16a40, 0x16a5e,
+ 0x16a60, 0x16a69,
+ 0x16a6e, 0x16a6f,
+ 0x16ad0, 0x16aed,
+ 0x16af0, 0x16af5,
+ 0x16b00, 0x16b45,
+ 0x16b50, 0x16b59,
+ 0x16b5b, 0x16b61,
+ 0x16b63, 0x16b77,
+ 0x16b7d, 0x16b8f,
+ 0x16f00, 0x16f44,
+ 0x16f50, 0x16f7e,
+ 0x16f8f, 0x16f9f,
+ 0x1b000, 0x1b001,
+ 0x1bc00, 0x1bc6a,
+ 0x1bc70, 0x1bc7c,
+ 0x1bc80, 0x1bc88,
+ 0x1bc90, 0x1bc99,
+ 0x1bc9c, 0x1bca3,
+ 0x1d000, 0x1d0f5,
+ 0x1d100, 0x1d126,
+ 0x1d129, 0x1d1dd,
+ 0x1d200, 0x1d245,
+ 0x1d300, 0x1d356,
+ 0x1d360, 0x1d371,
+ 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, 0x1d7cb,
+ 0x1d7ce, 0x1d7ff,
+ 0x1e800, 0x1e8c4,
+ 0x1e8c7, 0x1e8d6,
+ 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,
+ 0x1eef0, 0x1eef1,
+ 0x1f000, 0x1f02b,
+ 0x1f030, 0x1f093,
+ 0x1f0a0, 0x1f0ae,
+ 0x1f0b1, 0x1f0bf,
+ 0x1f0c1, 0x1f0cf,
+ 0x1f0d1, 0x1f0f5,
+ 0x1f100, 0x1f10c,
+ 0x1f110, 0x1f12e,
+ 0x1f130, 0x1f16b,
+ 0x1f170, 0x1f19a,
+ 0x1f1e6, 0x1f202,
+ 0x1f210, 0x1f23a,
+ 0x1f240, 0x1f248,
+ 0x1f250, 0x1f251,
+ 0x1f300, 0x1f32c,
+ 0x1f330, 0x1f37d,
+ 0x1f380, 0x1f3ce,
+ 0x1f3d4, 0x1f3f7,
+ 0x1f400, 0x1f4fe,
+ 0x1f500, 0x1f54a,
+ 0x1f550, 0x1f579,
+ 0x1f57b, 0x1f5a3,
+ 0x1f5a5, 0x1f642,
+ 0x1f645, 0x1f6cf,
+ 0x1f6e0, 0x1f6ec,
+ 0x1f6f0, 0x1f6f3,
+ 0x1f700, 0x1f773,
+ 0x1f780, 0x1f7d4,
+ 0x1f800, 0x1f80b,
+ 0x1f810, 0x1f847,
+ 0x1f850, 0x1f859,
+ 0x1f860, 0x1f887,
+ 0x1f890, 0x1f8ad,
+ 0x1fffe, 0x2a6d6,
+ 0x2a700, 0x2b734,
+ 0x2b740, 0x2b81d,
+ 0x2f800, 0x2fa1d,
+ 0x2fffe, 0x2ffff,
+ 0x3fffe, 0x3ffff,
+ 0x4fffe, 0x4ffff,
+ 0x5fffe, 0x5ffff,
+ 0x6fffe, 0x6ffff,
+ 0x7fffe, 0x7ffff,
+ 0x8fffe, 0x8ffff,
+ 0x9fffe, 0x9ffff,
+ 0xafffe, 0xaffff,
+ 0xbfffe, 0xbffff,
+ 0xcfffe, 0xcffff,
+ 0xdfffe, 0xdffff,
+ 0xe0001, 0xe0001,
+ 0xe0020, 0xe007f,
+ 0xe0100, 0xe01ef,
+ 0xefffe, 0x10ffff,
+}; /* CR_Age_7_0 */
+
+/* 'Age_8_0': Derived Age 8.0 */
+static const OnigCodePoint CR_Age_8_0[] = {
+ 623,
+ 0x0000, 0x0377,
+ 0x037a, 0x037f,
+ 0x0384, 0x038a,
+ 0x038c, 0x038c,
+ 0x038e, 0x03a1,
+ 0x03a3, 0x052f,
+ 0x0531, 0x0556,
+ 0x0559, 0x055f,
+ 0x0561, 0x0587,
+ 0x0589, 0x058a,
+ 0x058d, 0x058f,
+ 0x0591, 0x05c7,
+ 0x05d0, 0x05ea,
+ 0x05f0, 0x05f4,
+ 0x0600, 0x061c,
+ 0x061e, 0x070d,
+ 0x070f, 0x074a,
+ 0x074d, 0x07b1,
+ 0x07c0, 0x07fa,
+ 0x0800, 0x082d,
+ 0x0830, 0x083e,
+ 0x0840, 0x085b,
+ 0x085e, 0x085e,
+ 0x08a0, 0x08b4,
+ 0x08e3, 0x0983,
+ 0x0985, 0x098c,
+ 0x098f, 0x0990,
+ 0x0993, 0x09a8,
+ 0x09aa, 0x09b0,
+ 0x09b2, 0x09b2,
+ 0x09b6, 0x09b9,
+ 0x09bc, 0x09c4,
+ 0x09c7, 0x09c8,
+ 0x09cb, 0x09ce,
+ 0x09d7, 0x09d7,
+ 0x09dc, 0x09dd,
+ 0x09df, 0x09e3,
+ 0x09e6, 0x09fb,
+ 0x0a01, 0x0a03,
+ 0x0a05, 0x0a0a,
+ 0x0a0f, 0x0a10,
+ 0x0a13, 0x0a28,
+ 0x0a2a, 0x0a30,
+ 0x0a32, 0x0a33,
+ 0x0a35, 0x0a36,
+ 0x0a38, 0x0a39,
+ 0x0a3c, 0x0a3c,
+ 0x0a3e, 0x0a42,
+ 0x0a47, 0x0a48,
+ 0x0a4b, 0x0a4d,
+ 0x0a51, 0x0a51,
+ 0x0a59, 0x0a5c,
+ 0x0a5e, 0x0a5e,
+ 0x0a66, 0x0a75,
+ 0x0a81, 0x0a83,
+ 0x0a85, 0x0a8d,
+ 0x0a8f, 0x0a91,
+ 0x0a93, 0x0aa8,
+ 0x0aaa, 0x0ab0,
+ 0x0ab2, 0x0ab3,
+ 0x0ab5, 0x0ab9,
+ 0x0abc, 0x0ac5,
+ 0x0ac7, 0x0ac9,
+ 0x0acb, 0x0acd,
+ 0x0ad0, 0x0ad0,
+ 0x0ae0, 0x0ae3,
+ 0x0ae6, 0x0af1,
+ 0x0af9, 0x0af9,
+ 0x0b01, 0x0b03,
+ 0x0b05, 0x0b0c,
+ 0x0b0f, 0x0b10,
+ 0x0b13, 0x0b28,
+ 0x0b2a, 0x0b30,
+ 0x0b32, 0x0b33,
+ 0x0b35, 0x0b39,
+ 0x0b3c, 0x0b44,
+ 0x0b47, 0x0b48,
+ 0x0b4b, 0x0b4d,
+ 0x0b56, 0x0b57,
+ 0x0b5c, 0x0b5d,
+ 0x0b5f, 0x0b63,
+ 0x0b66, 0x0b77,
+ 0x0b82, 0x0b83,
+ 0x0b85, 0x0b8a,
+ 0x0b8e, 0x0b90,
+ 0x0b92, 0x0b95,
+ 0x0b99, 0x0b9a,
+ 0x0b9c, 0x0b9c,
+ 0x0b9e, 0x0b9f,
+ 0x0ba3, 0x0ba4,
+ 0x0ba8, 0x0baa,
+ 0x0bae, 0x0bb9,
+ 0x0bbe, 0x0bc2,
+ 0x0bc6, 0x0bc8,
+ 0x0bca, 0x0bcd,
+ 0x0bd0, 0x0bd0,
+ 0x0bd7, 0x0bd7,
+ 0x0be6, 0x0bfa,
+ 0x0c00, 0x0c03,
+ 0x0c05, 0x0c0c,
+ 0x0c0e, 0x0c10,
+ 0x0c12, 0x0c28,
+ 0x0c2a, 0x0c39,
+ 0x0c3d, 0x0c44,
+ 0x0c46, 0x0c48,
+ 0x0c4a, 0x0c4d,
+ 0x0c55, 0x0c56,
+ 0x0c58, 0x0c5a,
+ 0x0c60, 0x0c63,
+ 0x0c66, 0x0c6f,
+ 0x0c78, 0x0c7f,
+ 0x0c81, 0x0c83,
+ 0x0c85, 0x0c8c,
+ 0x0c8e, 0x0c90,
+ 0x0c92, 0x0ca8,
+ 0x0caa, 0x0cb3,
+ 0x0cb5, 0x0cb9,
+ 0x0cbc, 0x0cc4,
+ 0x0cc6, 0x0cc8,
+ 0x0cca, 0x0ccd,
+ 0x0cd5, 0x0cd6,
+ 0x0cde, 0x0cde,
+ 0x0ce0, 0x0ce3,
+ 0x0ce6, 0x0cef,
+ 0x0cf1, 0x0cf2,
+ 0x0d01, 0x0d03,
+ 0x0d05, 0x0d0c,
+ 0x0d0e, 0x0d10,
+ 0x0d12, 0x0d3a,
+ 0x0d3d, 0x0d44,
+ 0x0d46, 0x0d48,
+ 0x0d4a, 0x0d4e,
+ 0x0d57, 0x0d57,
+ 0x0d5f, 0x0d63,
+ 0x0d66, 0x0d75,
+ 0x0d79, 0x0d7f,
+ 0x0d82, 0x0d83,
+ 0x0d85, 0x0d96,
+ 0x0d9a, 0x0db1,
+ 0x0db3, 0x0dbb,
+ 0x0dbd, 0x0dbd,
+ 0x0dc0, 0x0dc6,
+ 0x0dca, 0x0dca,
+ 0x0dcf, 0x0dd4,
+ 0x0dd6, 0x0dd6,
+ 0x0dd8, 0x0ddf,
+ 0x0de6, 0x0def,
+ 0x0df2, 0x0df4,
+ 0x0e01, 0x0e3a,
+ 0x0e3f, 0x0e5b,
+ 0x0e81, 0x0e82,
+ 0x0e84, 0x0e84,
+ 0x0e87, 0x0e88,
+ 0x0e8a, 0x0e8a,
+ 0x0e8d, 0x0e8d,
+ 0x0e94, 0x0e97,
+ 0x0e99, 0x0e9f,
+ 0x0ea1, 0x0ea3,
+ 0x0ea5, 0x0ea5,
+ 0x0ea7, 0x0ea7,
+ 0x0eaa, 0x0eab,
+ 0x0ead, 0x0eb9,
+ 0x0ebb, 0x0ebd,
+ 0x0ec0, 0x0ec4,
+ 0x0ec6, 0x0ec6,
+ 0x0ec8, 0x0ecd,
+ 0x0ed0, 0x0ed9,
+ 0x0edc, 0x0edf,
+ 0x0f00, 0x0f47,
+ 0x0f49, 0x0f6c,
+ 0x0f71, 0x0f97,
+ 0x0f99, 0x0fbc,
+ 0x0fbe, 0x0fcc,
+ 0x0fce, 0x0fda,
+ 0x1000, 0x10c5,
+ 0x10c7, 0x10c7,
+ 0x10cd, 0x10cd,
+ 0x10d0, 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,
+ 0x135d, 0x137c,
+ 0x1380, 0x1399,
+ 0x13a0, 0x13f5,
+ 0x13f8, 0x13fd,
+ 0x1400, 0x169c,
+ 0x16a0, 0x16f8,
+ 0x1700, 0x170c,
+ 0x170e, 0x1714,
+ 0x1720, 0x1736,
+ 0x1740, 0x1753,
+ 0x1760, 0x176c,
+ 0x176e, 0x1770,
+ 0x1772, 0x1773,
+ 0x1780, 0x17dd,
+ 0x17e0, 0x17e9,
+ 0x17f0, 0x17f9,
+ 0x1800, 0x180e,
+ 0x1810, 0x1819,
+ 0x1820, 0x1877,
+ 0x1880, 0x18aa,
+ 0x18b0, 0x18f5,
+ 0x1900, 0x191e,
+ 0x1920, 0x192b,
+ 0x1930, 0x193b,
+ 0x1940, 0x1940,
+ 0x1944, 0x196d,
+ 0x1970, 0x1974,
+ 0x1980, 0x19ab,
+ 0x19b0, 0x19c9,
+ 0x19d0, 0x19da,
+ 0x19de, 0x1a1b,
+ 0x1a1e, 0x1a5e,
+ 0x1a60, 0x1a7c,
+ 0x1a7f, 0x1a89,
+ 0x1a90, 0x1a99,
+ 0x1aa0, 0x1aad,
+ 0x1ab0, 0x1abe,
+ 0x1b00, 0x1b4b,
+ 0x1b50, 0x1b7c,
+ 0x1b80, 0x1bf3,
+ 0x1bfc, 0x1c37,
+ 0x1c3b, 0x1c49,
+ 0x1c4d, 0x1c7f,
+ 0x1cc0, 0x1cc7,
+ 0x1cd0, 0x1cf6,
+ 0x1cf8, 0x1cf9,
+ 0x1d00, 0x1df5,
+ 0x1dfc, 0x1f15,
+ 0x1f18, 0x1f1d,
+ 0x1f20, 0x1f45,
+ 0x1f48, 0x1f4d,
+ 0x1f50, 0x1f57,
+ 0x1f59, 0x1f59,
+ 0x1f5b, 0x1f5b,
+ 0x1f5d, 0x1f5d,
+ 0x1f5f, 0x1f7d,
+ 0x1f80, 0x1fb4,
+ 0x1fb6, 0x1fc4,
+ 0x1fc6, 0x1fd3,
+ 0x1fd6, 0x1fdb,
+ 0x1fdd, 0x1fef,
+ 0x1ff2, 0x1ff4,
+ 0x1ff6, 0x1ffe,
+ 0x2000, 0x2064,
+ 0x2066, 0x2071,
+ 0x2074, 0x208e,
+ 0x2090, 0x209c,
+ 0x20a0, 0x20be,
+ 0x20d0, 0x20f0,
+ 0x2100, 0x218b,
+ 0x2190, 0x23fa,
+ 0x2400, 0x2426,
+ 0x2440, 0x244a,
+ 0x2460, 0x2b73,
+ 0x2b76, 0x2b95,
+ 0x2b98, 0x2bb9,
+ 0x2bbd, 0x2bc8,
+ 0x2bca, 0x2bd1,
+ 0x2bec, 0x2bef,
+ 0x2c00, 0x2c2e,
+ 0x2c30, 0x2c5e,
+ 0x2c60, 0x2cf3,
+ 0x2cf9, 0x2d25,
+ 0x2d27, 0x2d27,
+ 0x2d2d, 0x2d2d,
+ 0x2d30, 0x2d67,
+ 0x2d6f, 0x2d70,
+ 0x2d7f, 0x2d96,
+ 0x2da0, 0x2da6,
+ 0x2da8, 0x2dae,
+ 0x2db0, 0x2db6,
+ 0x2db8, 0x2dbe,
+ 0x2dc0, 0x2dc6,
+ 0x2dc8, 0x2dce,
+ 0x2dd0, 0x2dd6,
+ 0x2dd8, 0x2dde,
+ 0x2de0, 0x2e42,
+ 0x2e80, 0x2e99,
+ 0x2e9b, 0x2ef3,
+ 0x2f00, 0x2fd5,
+ 0x2ff0, 0x2ffb,
+ 0x3000, 0x303f,
+ 0x3041, 0x3096,
+ 0x3099, 0x30ff,
+ 0x3105, 0x312d,
+ 0x3131, 0x318e,
+ 0x3190, 0x31ba,
+ 0x31c0, 0x31e3,
+ 0x31f0, 0x321e,
+ 0x3220, 0x32fe,
+ 0x3300, 0x4db5,
+ 0x4dc0, 0x9fd5,
+ 0xa000, 0xa48c,
+ 0xa490, 0xa4c6,
+ 0xa4d0, 0xa62b,
+ 0xa640, 0xa6f7,
+ 0xa700, 0xa7ad,
+ 0xa7b0, 0xa7b7,
+ 0xa7f7, 0xa82b,
+ 0xa830, 0xa839,
+ 0xa840, 0xa877,
+ 0xa880, 0xa8c4,
+ 0xa8ce, 0xa8d9,
+ 0xa8e0, 0xa8fd,
+ 0xa900, 0xa953,
+ 0xa95f, 0xa97c,
+ 0xa980, 0xa9cd,
+ 0xa9cf, 0xa9d9,
+ 0xa9de, 0xa9fe,
+ 0xaa00, 0xaa36,
+ 0xaa40, 0xaa4d,
+ 0xaa50, 0xaa59,
+ 0xaa5c, 0xaac2,
+ 0xaadb, 0xaaf6,
+ 0xab01, 0xab06,
+ 0xab09, 0xab0e,
+ 0xab11, 0xab16,
+ 0xab20, 0xab26,
+ 0xab28, 0xab2e,
+ 0xab30, 0xab65,
+ 0xab70, 0xabed,
+ 0xabf0, 0xabf9,
+ 0xac00, 0xd7a3,
+ 0xd7b0, 0xd7c6,
+ 0xd7cb, 0xd7fb,
+ 0xd800, 0xfa6d,
+ 0xfa70, 0xfad9,
+ 0xfb00, 0xfb06,
+ 0xfb13, 0xfb17,
+ 0xfb1d, 0xfb36,
+ 0xfb38, 0xfb3c,
+ 0xfb3e, 0xfb3e,
+ 0xfb40, 0xfb41,
+ 0xfb43, 0xfb44,
+ 0xfb46, 0xfbc1,
+ 0xfbd3, 0xfd3f,
+ 0xfd50, 0xfd8f,
+ 0xfd92, 0xfdc7,
+ 0xfdd0, 0xfdfd,
+ 0xfe00, 0xfe19,
+ 0xfe20, 0xfe52,
+ 0xfe54, 0xfe66,
+ 0xfe68, 0xfe6b,
+ 0xfe70, 0xfe74,
+ 0xfe76, 0xfefc,
+ 0xfeff, 0xfeff,
+ 0xff01, 0xffbe,
+ 0xffc2, 0xffc7,
+ 0xffca, 0xffcf,
+ 0xffd2, 0xffd7,
+ 0xffda, 0xffdc,
+ 0xffe0, 0xffe6,
+ 0xffe8, 0xffee,
+ 0xfff9, 0x1000b,
+ 0x1000d, 0x10026,
+ 0x10028, 0x1003a,
+ 0x1003c, 0x1003d,
+ 0x1003f, 0x1004d,
+ 0x10050, 0x1005d,
+ 0x10080, 0x100fa,
+ 0x10100, 0x10102,
+ 0x10107, 0x10133,
+ 0x10137, 0x1018c,
+ 0x10190, 0x1019b,
+ 0x101a0, 0x101a0,
+ 0x101d0, 0x101fd,
+ 0x10280, 0x1029c,
+ 0x102a0, 0x102d0,
+ 0x102e0, 0x102fb,
+ 0x10300, 0x10323,
+ 0x10330, 0x1034a,
+ 0x10350, 0x1037a,
+ 0x10380, 0x1039d,
+ 0x1039f, 0x103c3,
+ 0x103c8, 0x103d5,
+ 0x10400, 0x1049d,
+ 0x104a0, 0x104a9,
+ 0x10500, 0x10527,
+ 0x10530, 0x10563,
+ 0x1056f, 0x1056f,
+ 0x10600, 0x10736,
+ 0x10740, 0x10755,
+ 0x10760, 0x10767,
+ 0x10800, 0x10805,
+ 0x10808, 0x10808,
+ 0x1080a, 0x10835,
+ 0x10837, 0x10838,
+ 0x1083c, 0x1083c,
+ 0x1083f, 0x10855,
+ 0x10857, 0x1089e,
+ 0x108a7, 0x108af,
+ 0x108e0, 0x108f2,
+ 0x108f4, 0x108f5,
+ 0x108fb, 0x1091b,
+ 0x1091f, 0x10939,
+ 0x1093f, 0x1093f,
+ 0x10980, 0x109b7,
+ 0x109bc, 0x109cf,
+ 0x109d2, 0x10a03,
+ 0x10a05, 0x10a06,
+ 0x10a0c, 0x10a13,
+ 0x10a15, 0x10a17,
+ 0x10a19, 0x10a33,
+ 0x10a38, 0x10a3a,
+ 0x10a3f, 0x10a47,
+ 0x10a50, 0x10a58,
+ 0x10a60, 0x10a9f,
+ 0x10ac0, 0x10ae6,
+ 0x10aeb, 0x10af6,
+ 0x10b00, 0x10b35,
+ 0x10b39, 0x10b55,
+ 0x10b58, 0x10b72,
+ 0x10b78, 0x10b91,
+ 0x10b99, 0x10b9c,
+ 0x10ba9, 0x10baf,
+ 0x10c00, 0x10c48,
+ 0x10c80, 0x10cb2,
+ 0x10cc0, 0x10cf2,
+ 0x10cfa, 0x10cff,
+ 0x10e60, 0x10e7e,
+ 0x11000, 0x1104d,
+ 0x11052, 0x1106f,
+ 0x1107f, 0x110c1,
+ 0x110d0, 0x110e8,
+ 0x110f0, 0x110f9,
+ 0x11100, 0x11134,
+ 0x11136, 0x11143,
+ 0x11150, 0x11176,
+ 0x11180, 0x111cd,
+ 0x111d0, 0x111df,
+ 0x111e1, 0x111f4,
+ 0x11200, 0x11211,
+ 0x11213, 0x1123d,
+ 0x11280, 0x11286,
+ 0x11288, 0x11288,
+ 0x1128a, 0x1128d,
+ 0x1128f, 0x1129d,
+ 0x1129f, 0x112a9,
+ 0x112b0, 0x112ea,
+ 0x112f0, 0x112f9,
+ 0x11300, 0x11303,
+ 0x11305, 0x1130c,
+ 0x1130f, 0x11310,
+ 0x11313, 0x11328,
+ 0x1132a, 0x11330,
+ 0x11332, 0x11333,
+ 0x11335, 0x11339,
+ 0x1133c, 0x11344,
+ 0x11347, 0x11348,
+ 0x1134b, 0x1134d,
+ 0x11350, 0x11350,
+ 0x11357, 0x11357,
+ 0x1135d, 0x11363,
+ 0x11366, 0x1136c,
+ 0x11370, 0x11374,
+ 0x11480, 0x114c7,
+ 0x114d0, 0x114d9,
+ 0x11580, 0x115b5,
+ 0x115b8, 0x115dd,
+ 0x11600, 0x11644,
+ 0x11650, 0x11659,
+ 0x11680, 0x116b7,
+ 0x116c0, 0x116c9,
+ 0x11700, 0x11719,
+ 0x1171d, 0x1172b,
+ 0x11730, 0x1173f,
+ 0x118a0, 0x118f2,
+ 0x118ff, 0x118ff,
+ 0x11ac0, 0x11af8,
+ 0x12000, 0x12399,
+ 0x12400, 0x1246e,
+ 0x12470, 0x12474,
+ 0x12480, 0x12543,
+ 0x13000, 0x1342e,
+ 0x14400, 0x14646,
+ 0x16800, 0x16a38,
+ 0x16a40, 0x16a5e,
+ 0x16a60, 0x16a69,
+ 0x16a6e, 0x16a6f,
+ 0x16ad0, 0x16aed,
+ 0x16af0, 0x16af5,
+ 0x16b00, 0x16b45,
+ 0x16b50, 0x16b59,
+ 0x16b5b, 0x16b61,
+ 0x16b63, 0x16b77,
+ 0x16b7d, 0x16b8f,
+ 0x16f00, 0x16f44,
+ 0x16f50, 0x16f7e,
+ 0x16f8f, 0x16f9f,
+ 0x1b000, 0x1b001,
+ 0x1bc00, 0x1bc6a,
+ 0x1bc70, 0x1bc7c,
+ 0x1bc80, 0x1bc88,
+ 0x1bc90, 0x1bc99,
+ 0x1bc9c, 0x1bca3,
+ 0x1d000, 0x1d0f5,
+ 0x1d100, 0x1d126,
+ 0x1d129, 0x1d1e8,
+ 0x1d200, 0x1d245,
+ 0x1d300, 0x1d356,
+ 0x1d360, 0x1d371,
+ 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, 0x1d7cb,
+ 0x1d7ce, 0x1da8b,
+ 0x1da9b, 0x1da9f,
+ 0x1daa1, 0x1daaf,
+ 0x1e800, 0x1e8c4,
+ 0x1e8c7, 0x1e8d6,
+ 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,
+ 0x1eef0, 0x1eef1,
+ 0x1f000, 0x1f02b,
+ 0x1f030, 0x1f093,
+ 0x1f0a0, 0x1f0ae,
+ 0x1f0b1, 0x1f0bf,
+ 0x1f0c1, 0x1f0cf,
+ 0x1f0d1, 0x1f0f5,
+ 0x1f100, 0x1f10c,
+ 0x1f110, 0x1f12e,
+ 0x1f130, 0x1f16b,
+ 0x1f170, 0x1f19a,
+ 0x1f1e6, 0x1f202,
+ 0x1f210, 0x1f23a,
+ 0x1f240, 0x1f248,
+ 0x1f250, 0x1f251,
+ 0x1f300, 0x1f579,
+ 0x1f57b, 0x1f5a3,
+ 0x1f5a5, 0x1f6d0,
+ 0x1f6e0, 0x1f6ec,
+ 0x1f6f0, 0x1f6f3,
+ 0x1f700, 0x1f773,
+ 0x1f780, 0x1f7d4,
+ 0x1f800, 0x1f80b,
+ 0x1f810, 0x1f847,
+ 0x1f850, 0x1f859,
+ 0x1f860, 0x1f887,
+ 0x1f890, 0x1f8ad,
+ 0x1f910, 0x1f918,
+ 0x1f980, 0x1f984,
+ 0x1f9c0, 0x1f9c0,
+ 0x1fffe, 0x2a6d6,
+ 0x2a700, 0x2b734,
+ 0x2b740, 0x2b81d,
+ 0x2b820, 0x2cea1,
+ 0x2f800, 0x2fa1d,
+ 0x2fffe, 0x2ffff,
+ 0x3fffe, 0x3ffff,
+ 0x4fffe, 0x4ffff,
+ 0x5fffe, 0x5ffff,
+ 0x6fffe, 0x6ffff,
+ 0x7fffe, 0x7ffff,
+ 0x8fffe, 0x8ffff,
+ 0x9fffe, 0x9ffff,
+ 0xafffe, 0xaffff,
+ 0xbfffe, 0xbffff,
+ 0xcfffe, 0xcffff,
+ 0xdfffe, 0xdffff,
+ 0xe0001, 0xe0001,
+ 0xe0020, 0xe007f,
+ 0xe0100, 0xe01ef,
+ 0xefffe, 0x10ffff,
+}; /* CR_Age_8_0 */
+
+/* 'Age_9_0': Derived Age 9.0 */
+static const OnigCodePoint CR_Age_9_0[] = {
+ 648,
+ 0x0000, 0x0377,
+ 0x037a, 0x037f,
+ 0x0384, 0x038a,
+ 0x038c, 0x038c,
+ 0x038e, 0x03a1,
+ 0x03a3, 0x052f,
+ 0x0531, 0x0556,
+ 0x0559, 0x055f,
+ 0x0561, 0x0587,
+ 0x0589, 0x058a,
+ 0x058d, 0x058f,
+ 0x0591, 0x05c7,
+ 0x05d0, 0x05ea,
+ 0x05f0, 0x05f4,
+ 0x0600, 0x061c,
+ 0x061e, 0x070d,
+ 0x070f, 0x074a,
+ 0x074d, 0x07b1,
+ 0x07c0, 0x07fa,
+ 0x0800, 0x082d,
+ 0x0830, 0x083e,
+ 0x0840, 0x085b,
+ 0x085e, 0x085e,
+ 0x08a0, 0x08b4,
+ 0x08b6, 0x08bd,
+ 0x08d4, 0x0983,
+ 0x0985, 0x098c,
+ 0x098f, 0x0990,
+ 0x0993, 0x09a8,
+ 0x09aa, 0x09b0,
+ 0x09b2, 0x09b2,
+ 0x09b6, 0x09b9,
+ 0x09bc, 0x09c4,
+ 0x09c7, 0x09c8,
+ 0x09cb, 0x09ce,
+ 0x09d7, 0x09d7,
+ 0x09dc, 0x09dd,
+ 0x09df, 0x09e3,
+ 0x09e6, 0x09fb,
+ 0x0a01, 0x0a03,
+ 0x0a05, 0x0a0a,
+ 0x0a0f, 0x0a10,
+ 0x0a13, 0x0a28,
+ 0x0a2a, 0x0a30,
+ 0x0a32, 0x0a33,
+ 0x0a35, 0x0a36,
+ 0x0a38, 0x0a39,
+ 0x0a3c, 0x0a3c,
+ 0x0a3e, 0x0a42,
+ 0x0a47, 0x0a48,
+ 0x0a4b, 0x0a4d,
+ 0x0a51, 0x0a51,
+ 0x0a59, 0x0a5c,
+ 0x0a5e, 0x0a5e,
+ 0x0a66, 0x0a75,
+ 0x0a81, 0x0a83,
+ 0x0a85, 0x0a8d,
+ 0x0a8f, 0x0a91,
+ 0x0a93, 0x0aa8,
+ 0x0aaa, 0x0ab0,
+ 0x0ab2, 0x0ab3,
+ 0x0ab5, 0x0ab9,
+ 0x0abc, 0x0ac5,
+ 0x0ac7, 0x0ac9,
+ 0x0acb, 0x0acd,
+ 0x0ad0, 0x0ad0,
+ 0x0ae0, 0x0ae3,
+ 0x0ae6, 0x0af1,
+ 0x0af9, 0x0af9,
+ 0x0b01, 0x0b03,
+ 0x0b05, 0x0b0c,
+ 0x0b0f, 0x0b10,
+ 0x0b13, 0x0b28,
+ 0x0b2a, 0x0b30,
+ 0x0b32, 0x0b33,
+ 0x0b35, 0x0b39,
+ 0x0b3c, 0x0b44,
+ 0x0b47, 0x0b48,
+ 0x0b4b, 0x0b4d,
+ 0x0b56, 0x0b57,
+ 0x0b5c, 0x0b5d,
+ 0x0b5f, 0x0b63,
+ 0x0b66, 0x0b77,
+ 0x0b82, 0x0b83,
+ 0x0b85, 0x0b8a,
+ 0x0b8e, 0x0b90,
+ 0x0b92, 0x0b95,
+ 0x0b99, 0x0b9a,
+ 0x0b9c, 0x0b9c,
+ 0x0b9e, 0x0b9f,
+ 0x0ba3, 0x0ba4,
+ 0x0ba8, 0x0baa,
+ 0x0bae, 0x0bb9,
+ 0x0bbe, 0x0bc2,
+ 0x0bc6, 0x0bc8,
+ 0x0bca, 0x0bcd,
+ 0x0bd0, 0x0bd0,
+ 0x0bd7, 0x0bd7,
+ 0x0be6, 0x0bfa,
+ 0x0c00, 0x0c03,
+ 0x0c05, 0x0c0c,
+ 0x0c0e, 0x0c10,
+ 0x0c12, 0x0c28,
+ 0x0c2a, 0x0c39,
+ 0x0c3d, 0x0c44,
+ 0x0c46, 0x0c48,
+ 0x0c4a, 0x0c4d,
+ 0x0c55, 0x0c56,
+ 0x0c58, 0x0c5a,
+ 0x0c60, 0x0c63,
+ 0x0c66, 0x0c6f,
+ 0x0c78, 0x0c83,
+ 0x0c85, 0x0c8c,
+ 0x0c8e, 0x0c90,
+ 0x0c92, 0x0ca8,
+ 0x0caa, 0x0cb3,
+ 0x0cb5, 0x0cb9,
+ 0x0cbc, 0x0cc4,
+ 0x0cc6, 0x0cc8,
+ 0x0cca, 0x0ccd,
+ 0x0cd5, 0x0cd6,
+ 0x0cde, 0x0cde,
+ 0x0ce0, 0x0ce3,
+ 0x0ce6, 0x0cef,
+ 0x0cf1, 0x0cf2,
+ 0x0d01, 0x0d03,
+ 0x0d05, 0x0d0c,
+ 0x0d0e, 0x0d10,
+ 0x0d12, 0x0d3a,
+ 0x0d3d, 0x0d44,
+ 0x0d46, 0x0d48,
+ 0x0d4a, 0x0d4f,
+ 0x0d54, 0x0d63,
+ 0x0d66, 0x0d7f,
+ 0x0d82, 0x0d83,
+ 0x0d85, 0x0d96,
+ 0x0d9a, 0x0db1,
+ 0x0db3, 0x0dbb,
+ 0x0dbd, 0x0dbd,
+ 0x0dc0, 0x0dc6,
+ 0x0dca, 0x0dca,
+ 0x0dcf, 0x0dd4,
+ 0x0dd6, 0x0dd6,
+ 0x0dd8, 0x0ddf,
+ 0x0de6, 0x0def,
+ 0x0df2, 0x0df4,
+ 0x0e01, 0x0e3a,
+ 0x0e3f, 0x0e5b,
+ 0x0e81, 0x0e82,
+ 0x0e84, 0x0e84,
+ 0x0e87, 0x0e88,
+ 0x0e8a, 0x0e8a,
+ 0x0e8d, 0x0e8d,
+ 0x0e94, 0x0e97,
+ 0x0e99, 0x0e9f,
+ 0x0ea1, 0x0ea3,
+ 0x0ea5, 0x0ea5,
+ 0x0ea7, 0x0ea7,
+ 0x0eaa, 0x0eab,
+ 0x0ead, 0x0eb9,
+ 0x0ebb, 0x0ebd,
+ 0x0ec0, 0x0ec4,
+ 0x0ec6, 0x0ec6,
+ 0x0ec8, 0x0ecd,
+ 0x0ed0, 0x0ed9,
+ 0x0edc, 0x0edf,
+ 0x0f00, 0x0f47,
+ 0x0f49, 0x0f6c,
+ 0x0f71, 0x0f97,
+ 0x0f99, 0x0fbc,
+ 0x0fbe, 0x0fcc,
+ 0x0fce, 0x0fda,
+ 0x1000, 0x10c5,
+ 0x10c7, 0x10c7,
+ 0x10cd, 0x10cd,
+ 0x10d0, 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,
+ 0x135d, 0x137c,
+ 0x1380, 0x1399,
+ 0x13a0, 0x13f5,
+ 0x13f8, 0x13fd,
+ 0x1400, 0x169c,
+ 0x16a0, 0x16f8,
+ 0x1700, 0x170c,
+ 0x170e, 0x1714,
+ 0x1720, 0x1736,
+ 0x1740, 0x1753,
+ 0x1760, 0x176c,
+ 0x176e, 0x1770,
+ 0x1772, 0x1773,
+ 0x1780, 0x17dd,
+ 0x17e0, 0x17e9,
+ 0x17f0, 0x17f9,
+ 0x1800, 0x180e,
+ 0x1810, 0x1819,
+ 0x1820, 0x1877,
+ 0x1880, 0x18aa,
+ 0x18b0, 0x18f5,
+ 0x1900, 0x191e,
+ 0x1920, 0x192b,
+ 0x1930, 0x193b,
+ 0x1940, 0x1940,
+ 0x1944, 0x196d,
+ 0x1970, 0x1974,
+ 0x1980, 0x19ab,
+ 0x19b0, 0x19c9,
+ 0x19d0, 0x19da,
+ 0x19de, 0x1a1b,
+ 0x1a1e, 0x1a5e,
+ 0x1a60, 0x1a7c,
+ 0x1a7f, 0x1a89,
+ 0x1a90, 0x1a99,
+ 0x1aa0, 0x1aad,
+ 0x1ab0, 0x1abe,
+ 0x1b00, 0x1b4b,
+ 0x1b50, 0x1b7c,
+ 0x1b80, 0x1bf3,
+ 0x1bfc, 0x1c37,
+ 0x1c3b, 0x1c49,
+ 0x1c4d, 0x1c88,
+ 0x1cc0, 0x1cc7,
+ 0x1cd0, 0x1cf6,
+ 0x1cf8, 0x1cf9,
+ 0x1d00, 0x1df5,
+ 0x1dfb, 0x1f15,
+ 0x1f18, 0x1f1d,
+ 0x1f20, 0x1f45,
+ 0x1f48, 0x1f4d,
+ 0x1f50, 0x1f57,
+ 0x1f59, 0x1f59,
+ 0x1f5b, 0x1f5b,
+ 0x1f5d, 0x1f5d,
+ 0x1f5f, 0x1f7d,
+ 0x1f80, 0x1fb4,
+ 0x1fb6, 0x1fc4,
+ 0x1fc6, 0x1fd3,
+ 0x1fd6, 0x1fdb,
+ 0x1fdd, 0x1fef,
+ 0x1ff2, 0x1ff4,
+ 0x1ff6, 0x1ffe,
+ 0x2000, 0x2064,
+ 0x2066, 0x2071,
+ 0x2074, 0x208e,
+ 0x2090, 0x209c,
+ 0x20a0, 0x20be,
+ 0x20d0, 0x20f0,
+ 0x2100, 0x218b,
+ 0x2190, 0x23fe,
+ 0x2400, 0x2426,
+ 0x2440, 0x244a,
+ 0x2460, 0x2b73,
+ 0x2b76, 0x2b95,
+ 0x2b98, 0x2bb9,
+ 0x2bbd, 0x2bc8,
+ 0x2bca, 0x2bd1,
+ 0x2bec, 0x2bef,
+ 0x2c00, 0x2c2e,
+ 0x2c30, 0x2c5e,
+ 0x2c60, 0x2cf3,
+ 0x2cf9, 0x2d25,
+ 0x2d27, 0x2d27,
+ 0x2d2d, 0x2d2d,
+ 0x2d30, 0x2d67,
+ 0x2d6f, 0x2d70,
+ 0x2d7f, 0x2d96,
+ 0x2da0, 0x2da6,
+ 0x2da8, 0x2dae,
+ 0x2db0, 0x2db6,
+ 0x2db8, 0x2dbe,
+ 0x2dc0, 0x2dc6,
+ 0x2dc8, 0x2dce,
+ 0x2dd0, 0x2dd6,
+ 0x2dd8, 0x2dde,
+ 0x2de0, 0x2e44,
+ 0x2e80, 0x2e99,
+ 0x2e9b, 0x2ef3,
+ 0x2f00, 0x2fd5,
+ 0x2ff0, 0x2ffb,
+ 0x3000, 0x303f,
+ 0x3041, 0x3096,
+ 0x3099, 0x30ff,
+ 0x3105, 0x312d,
+ 0x3131, 0x318e,
+ 0x3190, 0x31ba,
+ 0x31c0, 0x31e3,
+ 0x31f0, 0x321e,
+ 0x3220, 0x32fe,
+ 0x3300, 0x4db5,
+ 0x4dc0, 0x9fd5,
+ 0xa000, 0xa48c,
+ 0xa490, 0xa4c6,
+ 0xa4d0, 0xa62b,
+ 0xa640, 0xa6f7,
+ 0xa700, 0xa7ae,
+ 0xa7b0, 0xa7b7,
+ 0xa7f7, 0xa82b,
+ 0xa830, 0xa839,
+ 0xa840, 0xa877,
+ 0xa880, 0xa8c5,
+ 0xa8ce, 0xa8d9,
+ 0xa8e0, 0xa8fd,
+ 0xa900, 0xa953,
+ 0xa95f, 0xa97c,
+ 0xa980, 0xa9cd,
+ 0xa9cf, 0xa9d9,
+ 0xa9de, 0xa9fe,
+ 0xaa00, 0xaa36,
+ 0xaa40, 0xaa4d,
+ 0xaa50, 0xaa59,
+ 0xaa5c, 0xaac2,
+ 0xaadb, 0xaaf6,
+ 0xab01, 0xab06,
+ 0xab09, 0xab0e,
+ 0xab11, 0xab16,
+ 0xab20, 0xab26,
+ 0xab28, 0xab2e,
+ 0xab30, 0xab65,
+ 0xab70, 0xabed,
+ 0xabf0, 0xabf9,
+ 0xac00, 0xd7a3,
+ 0xd7b0, 0xd7c6,
+ 0xd7cb, 0xd7fb,
+ 0xd800, 0xfa6d,
+ 0xfa70, 0xfad9,
+ 0xfb00, 0xfb06,
+ 0xfb13, 0xfb17,
+ 0xfb1d, 0xfb36,
+ 0xfb38, 0xfb3c,
+ 0xfb3e, 0xfb3e,
+ 0xfb40, 0xfb41,
+ 0xfb43, 0xfb44,
+ 0xfb46, 0xfbc1,
+ 0xfbd3, 0xfd3f,
+ 0xfd50, 0xfd8f,
+ 0xfd92, 0xfdc7,
+ 0xfdd0, 0xfdfd,
+ 0xfe00, 0xfe19,
+ 0xfe20, 0xfe52,
+ 0xfe54, 0xfe66,
+ 0xfe68, 0xfe6b,
+ 0xfe70, 0xfe74,
+ 0xfe76, 0xfefc,
+ 0xfeff, 0xfeff,
+ 0xff01, 0xffbe,
+ 0xffc2, 0xffc7,
+ 0xffca, 0xffcf,
+ 0xffd2, 0xffd7,
+ 0xffda, 0xffdc,
+ 0xffe0, 0xffe6,
+ 0xffe8, 0xffee,
+ 0xfff9, 0x1000b,
+ 0x1000d, 0x10026,
+ 0x10028, 0x1003a,
+ 0x1003c, 0x1003d,
+ 0x1003f, 0x1004d,
+ 0x10050, 0x1005d,
+ 0x10080, 0x100fa,
+ 0x10100, 0x10102,
+ 0x10107, 0x10133,
+ 0x10137, 0x1018e,
+ 0x10190, 0x1019b,
+ 0x101a0, 0x101a0,
+ 0x101d0, 0x101fd,
+ 0x10280, 0x1029c,
+ 0x102a0, 0x102d0,
+ 0x102e0, 0x102fb,
+ 0x10300, 0x10323,
+ 0x10330, 0x1034a,
+ 0x10350, 0x1037a,
+ 0x10380, 0x1039d,
+ 0x1039f, 0x103c3,
+ 0x103c8, 0x103d5,
+ 0x10400, 0x1049d,
+ 0x104a0, 0x104a9,
+ 0x104b0, 0x104d3,
+ 0x104d8, 0x104fb,
+ 0x10500, 0x10527,
+ 0x10530, 0x10563,
+ 0x1056f, 0x1056f,
+ 0x10600, 0x10736,
+ 0x10740, 0x10755,
+ 0x10760, 0x10767,
+ 0x10800, 0x10805,
+ 0x10808, 0x10808,
+ 0x1080a, 0x10835,
+ 0x10837, 0x10838,
+ 0x1083c, 0x1083c,
+ 0x1083f, 0x10855,
+ 0x10857, 0x1089e,
+ 0x108a7, 0x108af,
+ 0x108e0, 0x108f2,
+ 0x108f4, 0x108f5,
+ 0x108fb, 0x1091b,
+ 0x1091f, 0x10939,
+ 0x1093f, 0x1093f,
+ 0x10980, 0x109b7,
+ 0x109bc, 0x109cf,
+ 0x109d2, 0x10a03,
+ 0x10a05, 0x10a06,
+ 0x10a0c, 0x10a13,
+ 0x10a15, 0x10a17,
+ 0x10a19, 0x10a33,
+ 0x10a38, 0x10a3a,
+ 0x10a3f, 0x10a47,
+ 0x10a50, 0x10a58,
+ 0x10a60, 0x10a9f,
+ 0x10ac0, 0x10ae6,
+ 0x10aeb, 0x10af6,
+ 0x10b00, 0x10b35,
+ 0x10b39, 0x10b55,
+ 0x10b58, 0x10b72,
+ 0x10b78, 0x10b91,
+ 0x10b99, 0x10b9c,
+ 0x10ba9, 0x10baf,
+ 0x10c00, 0x10c48,
+ 0x10c80, 0x10cb2,
+ 0x10cc0, 0x10cf2,
+ 0x10cfa, 0x10cff,
+ 0x10e60, 0x10e7e,
+ 0x11000, 0x1104d,
+ 0x11052, 0x1106f,
+ 0x1107f, 0x110c1,
+ 0x110d0, 0x110e8,
+ 0x110f0, 0x110f9,
+ 0x11100, 0x11134,
+ 0x11136, 0x11143,
+ 0x11150, 0x11176,
+ 0x11180, 0x111cd,
+ 0x111d0, 0x111df,
+ 0x111e1, 0x111f4,
+ 0x11200, 0x11211,
+ 0x11213, 0x1123e,
+ 0x11280, 0x11286,
+ 0x11288, 0x11288,
+ 0x1128a, 0x1128d,
+ 0x1128f, 0x1129d,
+ 0x1129f, 0x112a9,
+ 0x112b0, 0x112ea,
+ 0x112f0, 0x112f9,
+ 0x11300, 0x11303,
+ 0x11305, 0x1130c,
+ 0x1130f, 0x11310,
+ 0x11313, 0x11328,
+ 0x1132a, 0x11330,
+ 0x11332, 0x11333,
+ 0x11335, 0x11339,
+ 0x1133c, 0x11344,
+ 0x11347, 0x11348,
+ 0x1134b, 0x1134d,
+ 0x11350, 0x11350,
+ 0x11357, 0x11357,
+ 0x1135d, 0x11363,
+ 0x11366, 0x1136c,
+ 0x11370, 0x11374,
+ 0x11400, 0x11459,
+ 0x1145b, 0x1145b,
+ 0x1145d, 0x1145d,
+ 0x11480, 0x114c7,
+ 0x114d0, 0x114d9,
+ 0x11580, 0x115b5,
+ 0x115b8, 0x115dd,
+ 0x11600, 0x11644,
+ 0x11650, 0x11659,
+ 0x11660, 0x1166c,
+ 0x11680, 0x116b7,
+ 0x116c0, 0x116c9,
+ 0x11700, 0x11719,
+ 0x1171d, 0x1172b,
+ 0x11730, 0x1173f,
+ 0x118a0, 0x118f2,
+ 0x118ff, 0x118ff,
+ 0x11ac0, 0x11af8,
+ 0x11c00, 0x11c08,
+ 0x11c0a, 0x11c36,
+ 0x11c38, 0x11c45,
+ 0x11c50, 0x11c6c,
+ 0x11c70, 0x11c8f,
+ 0x11c92, 0x11ca7,
+ 0x11ca9, 0x11cb6,
+ 0x12000, 0x12399,
+ 0x12400, 0x1246e,
+ 0x12470, 0x12474,
+ 0x12480, 0x12543,
+ 0x13000, 0x1342e,
+ 0x14400, 0x14646,
+ 0x16800, 0x16a38,
+ 0x16a40, 0x16a5e,
+ 0x16a60, 0x16a69,
+ 0x16a6e, 0x16a6f,
+ 0x16ad0, 0x16aed,
+ 0x16af0, 0x16af5,
+ 0x16b00, 0x16b45,
+ 0x16b50, 0x16b59,
+ 0x16b5b, 0x16b61,
+ 0x16b63, 0x16b77,
+ 0x16b7d, 0x16b8f,
+ 0x16f00, 0x16f44,
+ 0x16f50, 0x16f7e,
+ 0x16f8f, 0x16f9f,
+ 0x16fe0, 0x16fe0,
+ 0x17000, 0x187ec,
+ 0x18800, 0x18af2,
+ 0x1b000, 0x1b001,
+ 0x1bc00, 0x1bc6a,
+ 0x1bc70, 0x1bc7c,
+ 0x1bc80, 0x1bc88,
+ 0x1bc90, 0x1bc99,
+ 0x1bc9c, 0x1bca3,
+ 0x1d000, 0x1d0f5,
+ 0x1d100, 0x1d126,
+ 0x1d129, 0x1d1e8,
+ 0x1d200, 0x1d245,
+ 0x1d300, 0x1d356,
+ 0x1d360, 0x1d371,
+ 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, 0x1d7cb,
+ 0x1d7ce, 0x1da8b,
+ 0x1da9b, 0x1da9f,
+ 0x1daa1, 0x1daaf,
+ 0x1e000, 0x1e006,
+ 0x1e008, 0x1e018,
+ 0x1e01b, 0x1e021,
+ 0x1e023, 0x1e024,
+ 0x1e026, 0x1e02a,
+ 0x1e800, 0x1e8c4,
+ 0x1e8c7, 0x1e8d6,
+ 0x1e900, 0x1e94a,
+ 0x1e950, 0x1e959,
+ 0x1e95e, 0x1e95f,
+ 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,
+ 0x1eef0, 0x1eef1,
+ 0x1f000, 0x1f02b,
+ 0x1f030, 0x1f093,
+ 0x1f0a0, 0x1f0ae,
+ 0x1f0b1, 0x1f0bf,
+ 0x1f0c1, 0x1f0cf,
+ 0x1f0d1, 0x1f0f5,
+ 0x1f100, 0x1f10c,
+ 0x1f110, 0x1f12e,
+ 0x1f130, 0x1f16b,
+ 0x1f170, 0x1f1ac,
+ 0x1f1e6, 0x1f202,
+ 0x1f210, 0x1f23b,
+ 0x1f240, 0x1f248,
+ 0x1f250, 0x1f251,
+ 0x1f300, 0x1f6d2,
+ 0x1f6e0, 0x1f6ec,
+ 0x1f6f0, 0x1f6f6,
+ 0x1f700, 0x1f773,
+ 0x1f780, 0x1f7d4,
+ 0x1f800, 0x1f80b,
+ 0x1f810, 0x1f847,
+ 0x1f850, 0x1f859,
+ 0x1f860, 0x1f887,
+ 0x1f890, 0x1f8ad,
+ 0x1f910, 0x1f91e,
+ 0x1f920, 0x1f927,
+ 0x1f930, 0x1f930,
+ 0x1f933, 0x1f93e,
+ 0x1f940, 0x1f94b,
+ 0x1f950, 0x1f95e,
+ 0x1f980, 0x1f991,
+ 0x1f9c0, 0x1f9c0,
+ 0x1fffe, 0x2a6d6,
+ 0x2a700, 0x2b734,
+ 0x2b740, 0x2b81d,
+ 0x2b820, 0x2cea1,
+ 0x2f800, 0x2fa1d,
+ 0x2fffe, 0x2ffff,
+ 0x3fffe, 0x3ffff,
+ 0x4fffe, 0x4ffff,
+ 0x5fffe, 0x5ffff,
+ 0x6fffe, 0x6ffff,
+ 0x7fffe, 0x7ffff,
+ 0x8fffe, 0x8ffff,
+ 0x9fffe, 0x9ffff,
+ 0xafffe, 0xaffff,
+ 0xbfffe, 0xbffff,
+ 0xcfffe, 0xcffff,
+ 0xdfffe, 0xdffff,
+ 0xe0001, 0xe0001,
+ 0xe0020, 0xe007f,
+ 0xe0100, 0xe01ef,
+ 0xefffe, 0x10ffff,
+}; /* CR_Age_9_0 */
+
+/* 'Age_10_0': Derived Age 10.0 */
+static const OnigCodePoint CR_Age_10_0[] = {
+ 659,
+ 0x0000, 0x0377,
+ 0x037a, 0x037f,
+ 0x0384, 0x038a,
+ 0x038c, 0x038c,
+ 0x038e, 0x03a1,
+ 0x03a3, 0x052f,
+ 0x0531, 0x0556,
+ 0x0559, 0x055f,
+ 0x0561, 0x0587,
+ 0x0589, 0x058a,
+ 0x058d, 0x058f,
+ 0x0591, 0x05c7,
+ 0x05d0, 0x05ea,
+ 0x05f0, 0x05f4,
+ 0x0600, 0x061c,
+ 0x061e, 0x070d,
+ 0x070f, 0x074a,
+ 0x074d, 0x07b1,
+ 0x07c0, 0x07fa,
+ 0x0800, 0x082d,
+ 0x0830, 0x083e,
+ 0x0840, 0x085b,
+ 0x085e, 0x085e,
+ 0x0860, 0x086a,
+ 0x08a0, 0x08b4,
+ 0x08b6, 0x08bd,
+ 0x08d4, 0x0983,
+ 0x0985, 0x098c,
+ 0x098f, 0x0990,
+ 0x0993, 0x09a8,
+ 0x09aa, 0x09b0,
+ 0x09b2, 0x09b2,
+ 0x09b6, 0x09b9,
+ 0x09bc, 0x09c4,
+ 0x09c7, 0x09c8,
+ 0x09cb, 0x09ce,
+ 0x09d7, 0x09d7,
+ 0x09dc, 0x09dd,
+ 0x09df, 0x09e3,
+ 0x09e6, 0x09fd,
+ 0x0a01, 0x0a03,
+ 0x0a05, 0x0a0a,
+ 0x0a0f, 0x0a10,
+ 0x0a13, 0x0a28,
+ 0x0a2a, 0x0a30,
+ 0x0a32, 0x0a33,
+ 0x0a35, 0x0a36,
+ 0x0a38, 0x0a39,
+ 0x0a3c, 0x0a3c,
+ 0x0a3e, 0x0a42,
+ 0x0a47, 0x0a48,
+ 0x0a4b, 0x0a4d,
+ 0x0a51, 0x0a51,
+ 0x0a59, 0x0a5c,
+ 0x0a5e, 0x0a5e,
+ 0x0a66, 0x0a75,
+ 0x0a81, 0x0a83,
+ 0x0a85, 0x0a8d,
+ 0x0a8f, 0x0a91,
+ 0x0a93, 0x0aa8,
+ 0x0aaa, 0x0ab0,
+ 0x0ab2, 0x0ab3,
+ 0x0ab5, 0x0ab9,
+ 0x0abc, 0x0ac5,
+ 0x0ac7, 0x0ac9,
+ 0x0acb, 0x0acd,
+ 0x0ad0, 0x0ad0,
+ 0x0ae0, 0x0ae3,
+ 0x0ae6, 0x0af1,
+ 0x0af9, 0x0aff,
+ 0x0b01, 0x0b03,
+ 0x0b05, 0x0b0c,
+ 0x0b0f, 0x0b10,
+ 0x0b13, 0x0b28,
+ 0x0b2a, 0x0b30,
+ 0x0b32, 0x0b33,
+ 0x0b35, 0x0b39,
+ 0x0b3c, 0x0b44,
+ 0x0b47, 0x0b48,
+ 0x0b4b, 0x0b4d,
+ 0x0b56, 0x0b57,
+ 0x0b5c, 0x0b5d,
+ 0x0b5f, 0x0b63,
+ 0x0b66, 0x0b77,
+ 0x0b82, 0x0b83,
+ 0x0b85, 0x0b8a,
+ 0x0b8e, 0x0b90,
+ 0x0b92, 0x0b95,
+ 0x0b99, 0x0b9a,
+ 0x0b9c, 0x0b9c,
+ 0x0b9e, 0x0b9f,
+ 0x0ba3, 0x0ba4,
+ 0x0ba8, 0x0baa,
+ 0x0bae, 0x0bb9,
+ 0x0bbe, 0x0bc2,
+ 0x0bc6, 0x0bc8,
+ 0x0bca, 0x0bcd,
+ 0x0bd0, 0x0bd0,
+ 0x0bd7, 0x0bd7,
+ 0x0be6, 0x0bfa,
+ 0x0c00, 0x0c03,
+ 0x0c05, 0x0c0c,
+ 0x0c0e, 0x0c10,
+ 0x0c12, 0x0c28,
+ 0x0c2a, 0x0c39,
+ 0x0c3d, 0x0c44,
+ 0x0c46, 0x0c48,
+ 0x0c4a, 0x0c4d,
+ 0x0c55, 0x0c56,
+ 0x0c58, 0x0c5a,
+ 0x0c60, 0x0c63,
+ 0x0c66, 0x0c6f,
+ 0x0c78, 0x0c83,
+ 0x0c85, 0x0c8c,
+ 0x0c8e, 0x0c90,
+ 0x0c92, 0x0ca8,
+ 0x0caa, 0x0cb3,
+ 0x0cb5, 0x0cb9,
+ 0x0cbc, 0x0cc4,
+ 0x0cc6, 0x0cc8,
+ 0x0cca, 0x0ccd,
+ 0x0cd5, 0x0cd6,
+ 0x0cde, 0x0cde,
+ 0x0ce0, 0x0ce3,
+ 0x0ce6, 0x0cef,
+ 0x0cf1, 0x0cf2,
+ 0x0d00, 0x0d03,
+ 0x0d05, 0x0d0c,
+ 0x0d0e, 0x0d10,
+ 0x0d12, 0x0d44,
+ 0x0d46, 0x0d48,
+ 0x0d4a, 0x0d4f,
+ 0x0d54, 0x0d63,
+ 0x0d66, 0x0d7f,
+ 0x0d82, 0x0d83,
+ 0x0d85, 0x0d96,
+ 0x0d9a, 0x0db1,
+ 0x0db3, 0x0dbb,
+ 0x0dbd, 0x0dbd,
+ 0x0dc0, 0x0dc6,
+ 0x0dca, 0x0dca,
+ 0x0dcf, 0x0dd4,
+ 0x0dd6, 0x0dd6,
+ 0x0dd8, 0x0ddf,
+ 0x0de6, 0x0def,
+ 0x0df2, 0x0df4,
+ 0x0e01, 0x0e3a,
+ 0x0e3f, 0x0e5b,
+ 0x0e81, 0x0e82,
+ 0x0e84, 0x0e84,
+ 0x0e87, 0x0e88,
+ 0x0e8a, 0x0e8a,
+ 0x0e8d, 0x0e8d,
+ 0x0e94, 0x0e97,
+ 0x0e99, 0x0e9f,
+ 0x0ea1, 0x0ea3,
+ 0x0ea5, 0x0ea5,
+ 0x0ea7, 0x0ea7,
+ 0x0eaa, 0x0eab,
+ 0x0ead, 0x0eb9,
+ 0x0ebb, 0x0ebd,
+ 0x0ec0, 0x0ec4,
+ 0x0ec6, 0x0ec6,
+ 0x0ec8, 0x0ecd,
+ 0x0ed0, 0x0ed9,
+ 0x0edc, 0x0edf,
+ 0x0f00, 0x0f47,
+ 0x0f49, 0x0f6c,
+ 0x0f71, 0x0f97,
+ 0x0f99, 0x0fbc,
+ 0x0fbe, 0x0fcc,
+ 0x0fce, 0x0fda,
+ 0x1000, 0x10c5,
+ 0x10c7, 0x10c7,
+ 0x10cd, 0x10cd,
+ 0x10d0, 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,
+ 0x135d, 0x137c,
+ 0x1380, 0x1399,
+ 0x13a0, 0x13f5,
+ 0x13f8, 0x13fd,
+ 0x1400, 0x169c,
+ 0x16a0, 0x16f8,
+ 0x1700, 0x170c,
+ 0x170e, 0x1714,
+ 0x1720, 0x1736,
+ 0x1740, 0x1753,
+ 0x1760, 0x176c,
+ 0x176e, 0x1770,
+ 0x1772, 0x1773,
+ 0x1780, 0x17dd,
+ 0x17e0, 0x17e9,
+ 0x17f0, 0x17f9,
+ 0x1800, 0x180e,
+ 0x1810, 0x1819,
+ 0x1820, 0x1877,
+ 0x1880, 0x18aa,
+ 0x18b0, 0x18f5,
+ 0x1900, 0x191e,
+ 0x1920, 0x192b,
+ 0x1930, 0x193b,
+ 0x1940, 0x1940,
+ 0x1944, 0x196d,
+ 0x1970, 0x1974,
+ 0x1980, 0x19ab,
+ 0x19b0, 0x19c9,
+ 0x19d0, 0x19da,
+ 0x19de, 0x1a1b,
+ 0x1a1e, 0x1a5e,
+ 0x1a60, 0x1a7c,
+ 0x1a7f, 0x1a89,
+ 0x1a90, 0x1a99,
+ 0x1aa0, 0x1aad,
+ 0x1ab0, 0x1abe,
+ 0x1b00, 0x1b4b,
+ 0x1b50, 0x1b7c,
+ 0x1b80, 0x1bf3,
+ 0x1bfc, 0x1c37,
+ 0x1c3b, 0x1c49,
+ 0x1c4d, 0x1c88,
+ 0x1cc0, 0x1cc7,
+ 0x1cd0, 0x1cf9,
+ 0x1d00, 0x1df9,
+ 0x1dfb, 0x1f15,
+ 0x1f18, 0x1f1d,
+ 0x1f20, 0x1f45,
+ 0x1f48, 0x1f4d,
+ 0x1f50, 0x1f57,
+ 0x1f59, 0x1f59,
+ 0x1f5b, 0x1f5b,
+ 0x1f5d, 0x1f5d,
+ 0x1f5f, 0x1f7d,
+ 0x1f80, 0x1fb4,
+ 0x1fb6, 0x1fc4,
+ 0x1fc6, 0x1fd3,
+ 0x1fd6, 0x1fdb,
+ 0x1fdd, 0x1fef,
+ 0x1ff2, 0x1ff4,
+ 0x1ff6, 0x1ffe,
+ 0x2000, 0x2064,
+ 0x2066, 0x2071,
+ 0x2074, 0x208e,
+ 0x2090, 0x209c,
+ 0x20a0, 0x20bf,
+ 0x20d0, 0x20f0,
+ 0x2100, 0x218b,
+ 0x2190, 0x2426,
+ 0x2440, 0x244a,
+ 0x2460, 0x2b73,
+ 0x2b76, 0x2b95,
+ 0x2b98, 0x2bb9,
+ 0x2bbd, 0x2bc8,
+ 0x2bca, 0x2bd2,
+ 0x2bec, 0x2bef,
+ 0x2c00, 0x2c2e,
+ 0x2c30, 0x2c5e,
+ 0x2c60, 0x2cf3,
+ 0x2cf9, 0x2d25,
+ 0x2d27, 0x2d27,
+ 0x2d2d, 0x2d2d,
+ 0x2d30, 0x2d67,
+ 0x2d6f, 0x2d70,
+ 0x2d7f, 0x2d96,
+ 0x2da0, 0x2da6,
+ 0x2da8, 0x2dae,
+ 0x2db0, 0x2db6,
+ 0x2db8, 0x2dbe,
+ 0x2dc0, 0x2dc6,
+ 0x2dc8, 0x2dce,
+ 0x2dd0, 0x2dd6,
+ 0x2dd8, 0x2dde,
+ 0x2de0, 0x2e49,
+ 0x2e80, 0x2e99,
+ 0x2e9b, 0x2ef3,
+ 0x2f00, 0x2fd5,
+ 0x2ff0, 0x2ffb,
+ 0x3000, 0x303f,
+ 0x3041, 0x3096,
+ 0x3099, 0x30ff,
+ 0x3105, 0x312e,
+ 0x3131, 0x318e,
+ 0x3190, 0x31ba,
+ 0x31c0, 0x31e3,
+ 0x31f0, 0x321e,
+ 0x3220, 0x32fe,
+ 0x3300, 0x4db5,
+ 0x4dc0, 0x9fea,
+ 0xa000, 0xa48c,
+ 0xa490, 0xa4c6,
+ 0xa4d0, 0xa62b,
+ 0xa640, 0xa6f7,
+ 0xa700, 0xa7ae,
+ 0xa7b0, 0xa7b7,
+ 0xa7f7, 0xa82b,
+ 0xa830, 0xa839,
+ 0xa840, 0xa877,
+ 0xa880, 0xa8c5,
+ 0xa8ce, 0xa8d9,
+ 0xa8e0, 0xa8fd,
+ 0xa900, 0xa953,
+ 0xa95f, 0xa97c,
+ 0xa980, 0xa9cd,
+ 0xa9cf, 0xa9d9,
+ 0xa9de, 0xa9fe,
+ 0xaa00, 0xaa36,
+ 0xaa40, 0xaa4d,
+ 0xaa50, 0xaa59,
+ 0xaa5c, 0xaac2,
+ 0xaadb, 0xaaf6,
+ 0xab01, 0xab06,
+ 0xab09, 0xab0e,
+ 0xab11, 0xab16,
+ 0xab20, 0xab26,
+ 0xab28, 0xab2e,
+ 0xab30, 0xab65,
+ 0xab70, 0xabed,
+ 0xabf0, 0xabf9,
+ 0xac00, 0xd7a3,
+ 0xd7b0, 0xd7c6,
+ 0xd7cb, 0xd7fb,
+ 0xd800, 0xfa6d,
+ 0xfa70, 0xfad9,
+ 0xfb00, 0xfb06,
+ 0xfb13, 0xfb17,
+ 0xfb1d, 0xfb36,
+ 0xfb38, 0xfb3c,
+ 0xfb3e, 0xfb3e,
+ 0xfb40, 0xfb41,
+ 0xfb43, 0xfb44,
+ 0xfb46, 0xfbc1,
+ 0xfbd3, 0xfd3f,
+ 0xfd50, 0xfd8f,
+ 0xfd92, 0xfdc7,
+ 0xfdd0, 0xfdfd,
+ 0xfe00, 0xfe19,
+ 0xfe20, 0xfe52,
+ 0xfe54, 0xfe66,
+ 0xfe68, 0xfe6b,
+ 0xfe70, 0xfe74,
+ 0xfe76, 0xfefc,
+ 0xfeff, 0xfeff,
+ 0xff01, 0xffbe,
+ 0xffc2, 0xffc7,
+ 0xffca, 0xffcf,
+ 0xffd2, 0xffd7,
+ 0xffda, 0xffdc,
+ 0xffe0, 0xffe6,
+ 0xffe8, 0xffee,
+ 0xfff9, 0x1000b,
+ 0x1000d, 0x10026,
+ 0x10028, 0x1003a,
+ 0x1003c, 0x1003d,
+ 0x1003f, 0x1004d,
+ 0x10050, 0x1005d,
+ 0x10080, 0x100fa,
+ 0x10100, 0x10102,
+ 0x10107, 0x10133,
+ 0x10137, 0x1018e,
+ 0x10190, 0x1019b,
+ 0x101a0, 0x101a0,
+ 0x101d0, 0x101fd,
+ 0x10280, 0x1029c,
+ 0x102a0, 0x102d0,
+ 0x102e0, 0x102fb,
+ 0x10300, 0x10323,
+ 0x1032d, 0x1034a,
+ 0x10350, 0x1037a,
+ 0x10380, 0x1039d,
+ 0x1039f, 0x103c3,
+ 0x103c8, 0x103d5,
+ 0x10400, 0x1049d,
+ 0x104a0, 0x104a9,
+ 0x104b0, 0x104d3,
+ 0x104d8, 0x104fb,
+ 0x10500, 0x10527,
+ 0x10530, 0x10563,
+ 0x1056f, 0x1056f,
+ 0x10600, 0x10736,
+ 0x10740, 0x10755,
+ 0x10760, 0x10767,
+ 0x10800, 0x10805,
+ 0x10808, 0x10808,
+ 0x1080a, 0x10835,
+ 0x10837, 0x10838,
+ 0x1083c, 0x1083c,
+ 0x1083f, 0x10855,
+ 0x10857, 0x1089e,
+ 0x108a7, 0x108af,
+ 0x108e0, 0x108f2,
+ 0x108f4, 0x108f5,
+ 0x108fb, 0x1091b,
+ 0x1091f, 0x10939,
+ 0x1093f, 0x1093f,
+ 0x10980, 0x109b7,
+ 0x109bc, 0x109cf,
+ 0x109d2, 0x10a03,
+ 0x10a05, 0x10a06,
+ 0x10a0c, 0x10a13,
+ 0x10a15, 0x10a17,
+ 0x10a19, 0x10a33,
+ 0x10a38, 0x10a3a,
+ 0x10a3f, 0x10a47,
+ 0x10a50, 0x10a58,
+ 0x10a60, 0x10a9f,
+ 0x10ac0, 0x10ae6,
+ 0x10aeb, 0x10af6,
+ 0x10b00, 0x10b35,
+ 0x10b39, 0x10b55,
+ 0x10b58, 0x10b72,
+ 0x10b78, 0x10b91,
+ 0x10b99, 0x10b9c,
+ 0x10ba9, 0x10baf,
+ 0x10c00, 0x10c48,
+ 0x10c80, 0x10cb2,
+ 0x10cc0, 0x10cf2,
+ 0x10cfa, 0x10cff,
+ 0x10e60, 0x10e7e,
+ 0x11000, 0x1104d,
+ 0x11052, 0x1106f,
+ 0x1107f, 0x110c1,
+ 0x110d0, 0x110e8,
+ 0x110f0, 0x110f9,
+ 0x11100, 0x11134,
+ 0x11136, 0x11143,
+ 0x11150, 0x11176,
+ 0x11180, 0x111cd,
+ 0x111d0, 0x111df,
+ 0x111e1, 0x111f4,
+ 0x11200, 0x11211,
+ 0x11213, 0x1123e,
+ 0x11280, 0x11286,
+ 0x11288, 0x11288,
+ 0x1128a, 0x1128d,
+ 0x1128f, 0x1129d,
+ 0x1129f, 0x112a9,
+ 0x112b0, 0x112ea,
+ 0x112f0, 0x112f9,
+ 0x11300, 0x11303,
+ 0x11305, 0x1130c,
+ 0x1130f, 0x11310,
+ 0x11313, 0x11328,
+ 0x1132a, 0x11330,
+ 0x11332, 0x11333,
+ 0x11335, 0x11339,
+ 0x1133c, 0x11344,
+ 0x11347, 0x11348,
+ 0x1134b, 0x1134d,
+ 0x11350, 0x11350,
+ 0x11357, 0x11357,
+ 0x1135d, 0x11363,
+ 0x11366, 0x1136c,
+ 0x11370, 0x11374,
+ 0x11400, 0x11459,
+ 0x1145b, 0x1145b,
+ 0x1145d, 0x1145d,
+ 0x11480, 0x114c7,
+ 0x114d0, 0x114d9,
+ 0x11580, 0x115b5,
+ 0x115b8, 0x115dd,
+ 0x11600, 0x11644,
+ 0x11650, 0x11659,
+ 0x11660, 0x1166c,
+ 0x11680, 0x116b7,
+ 0x116c0, 0x116c9,
+ 0x11700, 0x11719,
+ 0x1171d, 0x1172b,
+ 0x11730, 0x1173f,
+ 0x118a0, 0x118f2,
+ 0x118ff, 0x118ff,
+ 0x11a00, 0x11a47,
+ 0x11a50, 0x11a83,
+ 0x11a86, 0x11a9c,
+ 0x11a9e, 0x11aa2,
+ 0x11ac0, 0x11af8,
+ 0x11c00, 0x11c08,
+ 0x11c0a, 0x11c36,
+ 0x11c38, 0x11c45,
+ 0x11c50, 0x11c6c,
+ 0x11c70, 0x11c8f,
+ 0x11c92, 0x11ca7,
+ 0x11ca9, 0x11cb6,
+ 0x11d00, 0x11d06,
+ 0x11d08, 0x11d09,
+ 0x11d0b, 0x11d36,
+ 0x11d3a, 0x11d3a,
+ 0x11d3c, 0x11d3d,
+ 0x11d3f, 0x11d47,
+ 0x11d50, 0x11d59,
+ 0x12000, 0x12399,
+ 0x12400, 0x1246e,
+ 0x12470, 0x12474,
+ 0x12480, 0x12543,
+ 0x13000, 0x1342e,
+ 0x14400, 0x14646,
+ 0x16800, 0x16a38,
+ 0x16a40, 0x16a5e,
+ 0x16a60, 0x16a69,
+ 0x16a6e, 0x16a6f,
+ 0x16ad0, 0x16aed,
+ 0x16af0, 0x16af5,
+ 0x16b00, 0x16b45,
+ 0x16b50, 0x16b59,
+ 0x16b5b, 0x16b61,
+ 0x16b63, 0x16b77,
+ 0x16b7d, 0x16b8f,
+ 0x16f00, 0x16f44,
+ 0x16f50, 0x16f7e,
+ 0x16f8f, 0x16f9f,
+ 0x16fe0, 0x16fe1,
+ 0x17000, 0x187ec,
+ 0x18800, 0x18af2,
+ 0x1b000, 0x1b11e,
+ 0x1b170, 0x1b2fb,
+ 0x1bc00, 0x1bc6a,
+ 0x1bc70, 0x1bc7c,
+ 0x1bc80, 0x1bc88,
+ 0x1bc90, 0x1bc99,
+ 0x1bc9c, 0x1bca3,
+ 0x1d000, 0x1d0f5,
+ 0x1d100, 0x1d126,
+ 0x1d129, 0x1d1e8,
+ 0x1d200, 0x1d245,
+ 0x1d300, 0x1d356,
+ 0x1d360, 0x1d371,
+ 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, 0x1d7cb,
+ 0x1d7ce, 0x1da8b,
+ 0x1da9b, 0x1da9f,
+ 0x1daa1, 0x1daaf,
+ 0x1e000, 0x1e006,
+ 0x1e008, 0x1e018,
+ 0x1e01b, 0x1e021,
+ 0x1e023, 0x1e024,
+ 0x1e026, 0x1e02a,
+ 0x1e800, 0x1e8c4,
+ 0x1e8c7, 0x1e8d6,
+ 0x1e900, 0x1e94a,
+ 0x1e950, 0x1e959,
+ 0x1e95e, 0x1e95f,
+ 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,
+ 0x1eef0, 0x1eef1,
+ 0x1f000, 0x1f02b,
+ 0x1f030, 0x1f093,
+ 0x1f0a0, 0x1f0ae,
+ 0x1f0b1, 0x1f0bf,
+ 0x1f0c1, 0x1f0cf,
+ 0x1f0d1, 0x1f0f5,
+ 0x1f100, 0x1f10c,
+ 0x1f110, 0x1f12e,
+ 0x1f130, 0x1f16b,
+ 0x1f170, 0x1f1ac,
+ 0x1f1e6, 0x1f202,
+ 0x1f210, 0x1f23b,
+ 0x1f240, 0x1f248,
+ 0x1f250, 0x1f251,
+ 0x1f260, 0x1f265,
+ 0x1f300, 0x1f6d4,
+ 0x1f6e0, 0x1f6ec,
+ 0x1f6f0, 0x1f6f8,
+ 0x1f700, 0x1f773,
+ 0x1f780, 0x1f7d4,
+ 0x1f800, 0x1f80b,
+ 0x1f810, 0x1f847,
+ 0x1f850, 0x1f859,
+ 0x1f860, 0x1f887,
+ 0x1f890, 0x1f8ad,
+ 0x1f900, 0x1f90b,
+ 0x1f910, 0x1f93e,
+ 0x1f940, 0x1f94c,
+ 0x1f950, 0x1f96b,
+ 0x1f980, 0x1f997,
+ 0x1f9c0, 0x1f9c0,
+ 0x1f9d0, 0x1f9e6,
+ 0x1fffe, 0x2a6d6,
+ 0x2a700, 0x2b734,
+ 0x2b740, 0x2b81d,
+ 0x2b820, 0x2cea1,
+ 0x2ceb0, 0x2ebe0,
+ 0x2f800, 0x2fa1d,
+ 0x2fffe, 0x2ffff,
+ 0x3fffe, 0x3ffff,
+ 0x4fffe, 0x4ffff,
+ 0x5fffe, 0x5ffff,
+ 0x6fffe, 0x6ffff,
+ 0x7fffe, 0x7ffff,
+ 0x8fffe, 0x8ffff,
+ 0x9fffe, 0x9ffff,
+ 0xafffe, 0xaffff,
+ 0xbfffe, 0xbffff,
+ 0xcfffe, 0xcffff,
+ 0xdfffe, 0xdffff,
+ 0xe0001, 0xe0001,
+ 0xe0020, 0xe007f,
+ 0xe0100, 0xe01ef,
+ 0xefffe, 0x10ffff,
+}; /* CR_Age_10_0 */
+
+/* 'Age_11_0': Derived Age 11.0 */
+static const OnigCodePoint CR_Age_11_0[] = {
+ 668,
+ 0x0000, 0x0377,
+ 0x037a, 0x037f,
+ 0x0384, 0x038a,
+ 0x038c, 0x038c,
+ 0x038e, 0x03a1,
+ 0x03a3, 0x052f,
+ 0x0531, 0x0556,
+ 0x0559, 0x058a,
+ 0x058d, 0x058f,
+ 0x0591, 0x05c7,
+ 0x05d0, 0x05ea,
+ 0x05ef, 0x05f4,
+ 0x0600, 0x061c,
+ 0x061e, 0x070d,
+ 0x070f, 0x074a,
+ 0x074d, 0x07b1,
+ 0x07c0, 0x07fa,
+ 0x07fd, 0x082d,
+ 0x0830, 0x083e,
+ 0x0840, 0x085b,
+ 0x085e, 0x085e,
+ 0x0860, 0x086a,
+ 0x08a0, 0x08b4,
+ 0x08b6, 0x08bd,
+ 0x08d3, 0x0983,
+ 0x0985, 0x098c,
+ 0x098f, 0x0990,
+ 0x0993, 0x09a8,
+ 0x09aa, 0x09b0,
+ 0x09b2, 0x09b2,
+ 0x09b6, 0x09b9,
+ 0x09bc, 0x09c4,
+ 0x09c7, 0x09c8,
+ 0x09cb, 0x09ce,
+ 0x09d7, 0x09d7,
+ 0x09dc, 0x09dd,
+ 0x09df, 0x09e3,
+ 0x09e6, 0x09fe,
+ 0x0a01, 0x0a03,
+ 0x0a05, 0x0a0a,
+ 0x0a0f, 0x0a10,
+ 0x0a13, 0x0a28,
+ 0x0a2a, 0x0a30,
+ 0x0a32, 0x0a33,
+ 0x0a35, 0x0a36,
+ 0x0a38, 0x0a39,
+ 0x0a3c, 0x0a3c,
+ 0x0a3e, 0x0a42,
+ 0x0a47, 0x0a48,
+ 0x0a4b, 0x0a4d,
+ 0x0a51, 0x0a51,
+ 0x0a59, 0x0a5c,
+ 0x0a5e, 0x0a5e,
+ 0x0a66, 0x0a76,
+ 0x0a81, 0x0a83,
+ 0x0a85, 0x0a8d,
+ 0x0a8f, 0x0a91,
+ 0x0a93, 0x0aa8,
+ 0x0aaa, 0x0ab0,
+ 0x0ab2, 0x0ab3,
+ 0x0ab5, 0x0ab9,
+ 0x0abc, 0x0ac5,
+ 0x0ac7, 0x0ac9,
+ 0x0acb, 0x0acd,
+ 0x0ad0, 0x0ad0,
+ 0x0ae0, 0x0ae3,
+ 0x0ae6, 0x0af1,
+ 0x0af9, 0x0aff,
+ 0x0b01, 0x0b03,
+ 0x0b05, 0x0b0c,
+ 0x0b0f, 0x0b10,
+ 0x0b13, 0x0b28,
+ 0x0b2a, 0x0b30,
+ 0x0b32, 0x0b33,
+ 0x0b35, 0x0b39,
+ 0x0b3c, 0x0b44,
+ 0x0b47, 0x0b48,
+ 0x0b4b, 0x0b4d,
+ 0x0b56, 0x0b57,
+ 0x0b5c, 0x0b5d,
+ 0x0b5f, 0x0b63,
+ 0x0b66, 0x0b77,
+ 0x0b82, 0x0b83,
+ 0x0b85, 0x0b8a,
+ 0x0b8e, 0x0b90,
+ 0x0b92, 0x0b95,
+ 0x0b99, 0x0b9a,
+ 0x0b9c, 0x0b9c,
+ 0x0b9e, 0x0b9f,
+ 0x0ba3, 0x0ba4,
+ 0x0ba8, 0x0baa,
+ 0x0bae, 0x0bb9,
+ 0x0bbe, 0x0bc2,
+ 0x0bc6, 0x0bc8,
+ 0x0bca, 0x0bcd,
+ 0x0bd0, 0x0bd0,
+ 0x0bd7, 0x0bd7,
+ 0x0be6, 0x0bfa,
+ 0x0c00, 0x0c0c,
+ 0x0c0e, 0x0c10,
+ 0x0c12, 0x0c28,
+ 0x0c2a, 0x0c39,
+ 0x0c3d, 0x0c44,
+ 0x0c46, 0x0c48,
+ 0x0c4a, 0x0c4d,
+ 0x0c55, 0x0c56,
+ 0x0c58, 0x0c5a,
+ 0x0c60, 0x0c63,
+ 0x0c66, 0x0c6f,
+ 0x0c78, 0x0c8c,
+ 0x0c8e, 0x0c90,
+ 0x0c92, 0x0ca8,
+ 0x0caa, 0x0cb3,
+ 0x0cb5, 0x0cb9,
+ 0x0cbc, 0x0cc4,
+ 0x0cc6, 0x0cc8,
+ 0x0cca, 0x0ccd,
+ 0x0cd5, 0x0cd6,
+ 0x0cde, 0x0cde,
+ 0x0ce0, 0x0ce3,
+ 0x0ce6, 0x0cef,
+ 0x0cf1, 0x0cf2,
+ 0x0d00, 0x0d03,
+ 0x0d05, 0x0d0c,
+ 0x0d0e, 0x0d10,
+ 0x0d12, 0x0d44,
+ 0x0d46, 0x0d48,
+ 0x0d4a, 0x0d4f,
+ 0x0d54, 0x0d63,
+ 0x0d66, 0x0d7f,
+ 0x0d82, 0x0d83,
+ 0x0d85, 0x0d96,
+ 0x0d9a, 0x0db1,
+ 0x0db3, 0x0dbb,
+ 0x0dbd, 0x0dbd,
+ 0x0dc0, 0x0dc6,
+ 0x0dca, 0x0dca,
+ 0x0dcf, 0x0dd4,
+ 0x0dd6, 0x0dd6,
+ 0x0dd8, 0x0ddf,
+ 0x0de6, 0x0def,
+ 0x0df2, 0x0df4,
+ 0x0e01, 0x0e3a,
+ 0x0e3f, 0x0e5b,
+ 0x0e81, 0x0e82,
+ 0x0e84, 0x0e84,
+ 0x0e87, 0x0e88,
+ 0x0e8a, 0x0e8a,
+ 0x0e8d, 0x0e8d,
+ 0x0e94, 0x0e97,
+ 0x0e99, 0x0e9f,
+ 0x0ea1, 0x0ea3,
+ 0x0ea5, 0x0ea5,
+ 0x0ea7, 0x0ea7,
+ 0x0eaa, 0x0eab,
+ 0x0ead, 0x0eb9,
+ 0x0ebb, 0x0ebd,
+ 0x0ec0, 0x0ec4,
+ 0x0ec6, 0x0ec6,
+ 0x0ec8, 0x0ecd,
+ 0x0ed0, 0x0ed9,
+ 0x0edc, 0x0edf,
+ 0x0f00, 0x0f47,
+ 0x0f49, 0x0f6c,
+ 0x0f71, 0x0f97,
+ 0x0f99, 0x0fbc,
+ 0x0fbe, 0x0fcc,
+ 0x0fce, 0x0fda,
+ 0x1000, 0x10c5,
+ 0x10c7, 0x10c7,
+ 0x10cd, 0x10cd,
+ 0x10d0, 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,
+ 0x135d, 0x137c,
+ 0x1380, 0x1399,
+ 0x13a0, 0x13f5,
+ 0x13f8, 0x13fd,
+ 0x1400, 0x169c,
+ 0x16a0, 0x16f8,
+ 0x1700, 0x170c,
+ 0x170e, 0x1714,
+ 0x1720, 0x1736,
+ 0x1740, 0x1753,
+ 0x1760, 0x176c,
+ 0x176e, 0x1770,
+ 0x1772, 0x1773,
+ 0x1780, 0x17dd,
+ 0x17e0, 0x17e9,
+ 0x17f0, 0x17f9,
+ 0x1800, 0x180e,
+ 0x1810, 0x1819,
+ 0x1820, 0x1878,
+ 0x1880, 0x18aa,
+ 0x18b0, 0x18f5,
+ 0x1900, 0x191e,
+ 0x1920, 0x192b,
+ 0x1930, 0x193b,
+ 0x1940, 0x1940,
+ 0x1944, 0x196d,
+ 0x1970, 0x1974,
+ 0x1980, 0x19ab,
+ 0x19b0, 0x19c9,
+ 0x19d0, 0x19da,
+ 0x19de, 0x1a1b,
+ 0x1a1e, 0x1a5e,
+ 0x1a60, 0x1a7c,
+ 0x1a7f, 0x1a89,
+ 0x1a90, 0x1a99,
+ 0x1aa0, 0x1aad,
+ 0x1ab0, 0x1abe,
+ 0x1b00, 0x1b4b,
+ 0x1b50, 0x1b7c,
+ 0x1b80, 0x1bf3,
+ 0x1bfc, 0x1c37,
+ 0x1c3b, 0x1c49,
+ 0x1c4d, 0x1c88,
+ 0x1c90, 0x1cba,
+ 0x1cbd, 0x1cc7,
+ 0x1cd0, 0x1cf9,
+ 0x1d00, 0x1df9,
+ 0x1dfb, 0x1f15,
+ 0x1f18, 0x1f1d,
+ 0x1f20, 0x1f45,
+ 0x1f48, 0x1f4d,
+ 0x1f50, 0x1f57,
+ 0x1f59, 0x1f59,
+ 0x1f5b, 0x1f5b,
+ 0x1f5d, 0x1f5d,
+ 0x1f5f, 0x1f7d,
+ 0x1f80, 0x1fb4,
+ 0x1fb6, 0x1fc4,
+ 0x1fc6, 0x1fd3,
+ 0x1fd6, 0x1fdb,
+ 0x1fdd, 0x1fef,
+ 0x1ff2, 0x1ff4,
+ 0x1ff6, 0x1ffe,
+ 0x2000, 0x2064,
+ 0x2066, 0x2071,
+ 0x2074, 0x208e,
+ 0x2090, 0x209c,
+ 0x20a0, 0x20bf,
+ 0x20d0, 0x20f0,
+ 0x2100, 0x218b,
+ 0x2190, 0x2426,
+ 0x2440, 0x244a,
+ 0x2460, 0x2b73,
+ 0x2b76, 0x2b95,
+ 0x2b98, 0x2bc8,
+ 0x2bca, 0x2bfe,
+ 0x2c00, 0x2c2e,
+ 0x2c30, 0x2c5e,
+ 0x2c60, 0x2cf3,
+ 0x2cf9, 0x2d25,
+ 0x2d27, 0x2d27,
+ 0x2d2d, 0x2d2d,
+ 0x2d30, 0x2d67,
+ 0x2d6f, 0x2d70,
+ 0x2d7f, 0x2d96,
+ 0x2da0, 0x2da6,
+ 0x2da8, 0x2dae,
+ 0x2db0, 0x2db6,
+ 0x2db8, 0x2dbe,
+ 0x2dc0, 0x2dc6,
+ 0x2dc8, 0x2dce,
+ 0x2dd0, 0x2dd6,
+ 0x2dd8, 0x2dde,
+ 0x2de0, 0x2e4e,
+ 0x2e80, 0x2e99,
+ 0x2e9b, 0x2ef3,
+ 0x2f00, 0x2fd5,
+ 0x2ff0, 0x2ffb,
+ 0x3000, 0x303f,
+ 0x3041, 0x3096,
+ 0x3099, 0x30ff,
+ 0x3105, 0x312f,
+ 0x3131, 0x318e,
+ 0x3190, 0x31ba,
+ 0x31c0, 0x31e3,
+ 0x31f0, 0x321e,
+ 0x3220, 0x32fe,
+ 0x3300, 0x4db5,
+ 0x4dc0, 0x9fef,
+ 0xa000, 0xa48c,
+ 0xa490, 0xa4c6,
+ 0xa4d0, 0xa62b,
+ 0xa640, 0xa6f7,
+ 0xa700, 0xa7b9,
+ 0xa7f7, 0xa82b,
+ 0xa830, 0xa839,
+ 0xa840, 0xa877,
+ 0xa880, 0xa8c5,
+ 0xa8ce, 0xa8d9,
+ 0xa8e0, 0xa953,
+ 0xa95f, 0xa97c,
+ 0xa980, 0xa9cd,
+ 0xa9cf, 0xa9d9,
+ 0xa9de, 0xa9fe,
+ 0xaa00, 0xaa36,
+ 0xaa40, 0xaa4d,
+ 0xaa50, 0xaa59,
+ 0xaa5c, 0xaac2,
+ 0xaadb, 0xaaf6,
+ 0xab01, 0xab06,
+ 0xab09, 0xab0e,
+ 0xab11, 0xab16,
+ 0xab20, 0xab26,
+ 0xab28, 0xab2e,
+ 0xab30, 0xab65,
+ 0xab70, 0xabed,
+ 0xabf0, 0xabf9,
+ 0xac00, 0xd7a3,
+ 0xd7b0, 0xd7c6,
+ 0xd7cb, 0xd7fb,
+ 0xd800, 0xfa6d,
+ 0xfa70, 0xfad9,
+ 0xfb00, 0xfb06,
+ 0xfb13, 0xfb17,
+ 0xfb1d, 0xfb36,
+ 0xfb38, 0xfb3c,
+ 0xfb3e, 0xfb3e,
+ 0xfb40, 0xfb41,
+ 0xfb43, 0xfb44,
+ 0xfb46, 0xfbc1,
+ 0xfbd3, 0xfd3f,
+ 0xfd50, 0xfd8f,
+ 0xfd92, 0xfdc7,
+ 0xfdd0, 0xfdfd,
+ 0xfe00, 0xfe19,
+ 0xfe20, 0xfe52,
+ 0xfe54, 0xfe66,
+ 0xfe68, 0xfe6b,
+ 0xfe70, 0xfe74,
+ 0xfe76, 0xfefc,
+ 0xfeff, 0xfeff,
+ 0xff01, 0xffbe,
+ 0xffc2, 0xffc7,
+ 0xffca, 0xffcf,
+ 0xffd2, 0xffd7,
+ 0xffda, 0xffdc,
+ 0xffe0, 0xffe6,
+ 0xffe8, 0xffee,
+ 0xfff9, 0x1000b,
+ 0x1000d, 0x10026,
+ 0x10028, 0x1003a,
+ 0x1003c, 0x1003d,
+ 0x1003f, 0x1004d,
+ 0x10050, 0x1005d,
+ 0x10080, 0x100fa,
+ 0x10100, 0x10102,
+ 0x10107, 0x10133,
+ 0x10137, 0x1018e,
+ 0x10190, 0x1019b,
+ 0x101a0, 0x101a0,
+ 0x101d0, 0x101fd,
+ 0x10280, 0x1029c,
+ 0x102a0, 0x102d0,
+ 0x102e0, 0x102fb,
+ 0x10300, 0x10323,
+ 0x1032d, 0x1034a,
+ 0x10350, 0x1037a,
+ 0x10380, 0x1039d,
+ 0x1039f, 0x103c3,
+ 0x103c8, 0x103d5,
+ 0x10400, 0x1049d,
+ 0x104a0, 0x104a9,
+ 0x104b0, 0x104d3,
+ 0x104d8, 0x104fb,
+ 0x10500, 0x10527,
+ 0x10530, 0x10563,
+ 0x1056f, 0x1056f,
+ 0x10600, 0x10736,
+ 0x10740, 0x10755,
+ 0x10760, 0x10767,
+ 0x10800, 0x10805,
+ 0x10808, 0x10808,
+ 0x1080a, 0x10835,
+ 0x10837, 0x10838,
+ 0x1083c, 0x1083c,
+ 0x1083f, 0x10855,
+ 0x10857, 0x1089e,
+ 0x108a7, 0x108af,
+ 0x108e0, 0x108f2,
+ 0x108f4, 0x108f5,
+ 0x108fb, 0x1091b,
+ 0x1091f, 0x10939,
+ 0x1093f, 0x1093f,
+ 0x10980, 0x109b7,
+ 0x109bc, 0x109cf,
+ 0x109d2, 0x10a03,
+ 0x10a05, 0x10a06,
+ 0x10a0c, 0x10a13,
+ 0x10a15, 0x10a17,
+ 0x10a19, 0x10a35,
+ 0x10a38, 0x10a3a,
+ 0x10a3f, 0x10a48,
+ 0x10a50, 0x10a58,
+ 0x10a60, 0x10a9f,
+ 0x10ac0, 0x10ae6,
+ 0x10aeb, 0x10af6,
+ 0x10b00, 0x10b35,
+ 0x10b39, 0x10b55,
+ 0x10b58, 0x10b72,
+ 0x10b78, 0x10b91,
+ 0x10b99, 0x10b9c,
+ 0x10ba9, 0x10baf,
+ 0x10c00, 0x10c48,
+ 0x10c80, 0x10cb2,
+ 0x10cc0, 0x10cf2,
+ 0x10cfa, 0x10d27,
+ 0x10d30, 0x10d39,
+ 0x10e60, 0x10e7e,
+ 0x10f00, 0x10f27,
+ 0x10f30, 0x10f59,
+ 0x11000, 0x1104d,
+ 0x11052, 0x1106f,
+ 0x1107f, 0x110c1,
+ 0x110cd, 0x110cd,
+ 0x110d0, 0x110e8,
+ 0x110f0, 0x110f9,
+ 0x11100, 0x11134,
+ 0x11136, 0x11146,
+ 0x11150, 0x11176,
+ 0x11180, 0x111cd,
+ 0x111d0, 0x111df,
+ 0x111e1, 0x111f4,
+ 0x11200, 0x11211,
+ 0x11213, 0x1123e,
+ 0x11280, 0x11286,
+ 0x11288, 0x11288,
+ 0x1128a, 0x1128d,
+ 0x1128f, 0x1129d,
+ 0x1129f, 0x112a9,
+ 0x112b0, 0x112ea,
+ 0x112f0, 0x112f9,
+ 0x11300, 0x11303,
+ 0x11305, 0x1130c,
+ 0x1130f, 0x11310,
+ 0x11313, 0x11328,
+ 0x1132a, 0x11330,
+ 0x11332, 0x11333,
+ 0x11335, 0x11339,
+ 0x1133b, 0x11344,
+ 0x11347, 0x11348,
+ 0x1134b, 0x1134d,
+ 0x11350, 0x11350,
+ 0x11357, 0x11357,
+ 0x1135d, 0x11363,
+ 0x11366, 0x1136c,
+ 0x11370, 0x11374,
+ 0x11400, 0x11459,
+ 0x1145b, 0x1145b,
+ 0x1145d, 0x1145e,
+ 0x11480, 0x114c7,
+ 0x114d0, 0x114d9,
+ 0x11580, 0x115b5,
+ 0x115b8, 0x115dd,
+ 0x11600, 0x11644,
+ 0x11650, 0x11659,
+ 0x11660, 0x1166c,
+ 0x11680, 0x116b7,
+ 0x116c0, 0x116c9,
+ 0x11700, 0x1171a,
+ 0x1171d, 0x1172b,
+ 0x11730, 0x1173f,
+ 0x11800, 0x1183b,
+ 0x118a0, 0x118f2,
+ 0x118ff, 0x118ff,
+ 0x11a00, 0x11a47,
+ 0x11a50, 0x11a83,
+ 0x11a86, 0x11aa2,
+ 0x11ac0, 0x11af8,
+ 0x11c00, 0x11c08,
+ 0x11c0a, 0x11c36,
+ 0x11c38, 0x11c45,
+ 0x11c50, 0x11c6c,
+ 0x11c70, 0x11c8f,
+ 0x11c92, 0x11ca7,
+ 0x11ca9, 0x11cb6,
+ 0x11d00, 0x11d06,
+ 0x11d08, 0x11d09,
+ 0x11d0b, 0x11d36,
+ 0x11d3a, 0x11d3a,
+ 0x11d3c, 0x11d3d,
+ 0x11d3f, 0x11d47,
+ 0x11d50, 0x11d59,
+ 0x11d60, 0x11d65,
+ 0x11d67, 0x11d68,
+ 0x11d6a, 0x11d8e,
+ 0x11d90, 0x11d91,
+ 0x11d93, 0x11d98,
+ 0x11da0, 0x11da9,
+ 0x11ee0, 0x11ef8,
+ 0x12000, 0x12399,
+ 0x12400, 0x1246e,
+ 0x12470, 0x12474,
+ 0x12480, 0x12543,
+ 0x13000, 0x1342e,
+ 0x14400, 0x14646,
+ 0x16800, 0x16a38,
+ 0x16a40, 0x16a5e,
+ 0x16a60, 0x16a69,
+ 0x16a6e, 0x16a6f,
+ 0x16ad0, 0x16aed,
+ 0x16af0, 0x16af5,
+ 0x16b00, 0x16b45,
+ 0x16b50, 0x16b59,
+ 0x16b5b, 0x16b61,
+ 0x16b63, 0x16b77,
+ 0x16b7d, 0x16b8f,
+ 0x16e40, 0x16e9a,
+ 0x16f00, 0x16f44,
+ 0x16f50, 0x16f7e,
+ 0x16f8f, 0x16f9f,
+ 0x16fe0, 0x16fe1,
+ 0x17000, 0x187f1,
+ 0x18800, 0x18af2,
+ 0x1b000, 0x1b11e,
+ 0x1b170, 0x1b2fb,
+ 0x1bc00, 0x1bc6a,
+ 0x1bc70, 0x1bc7c,
+ 0x1bc80, 0x1bc88,
+ 0x1bc90, 0x1bc99,
+ 0x1bc9c, 0x1bca3,
+ 0x1d000, 0x1d0f5,
+ 0x1d100, 0x1d126,
+ 0x1d129, 0x1d1e8,
+ 0x1d200, 0x1d245,
+ 0x1d2e0, 0x1d2f3,
+ 0x1d300, 0x1d356,
+ 0x1d360, 0x1d378,
+ 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, 0x1d7cb,
+ 0x1d7ce, 0x1da8b,
+ 0x1da9b, 0x1da9f,
+ 0x1daa1, 0x1daaf,
+ 0x1e000, 0x1e006,
+ 0x1e008, 0x1e018,
+ 0x1e01b, 0x1e021,
+ 0x1e023, 0x1e024,
+ 0x1e026, 0x1e02a,
+ 0x1e800, 0x1e8c4,
+ 0x1e8c7, 0x1e8d6,
+ 0x1e900, 0x1e94a,
+ 0x1e950, 0x1e959,
+ 0x1e95e, 0x1e95f,
+ 0x1ec71, 0x1ecb4,
+ 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,
+ 0x1eef0, 0x1eef1,
+ 0x1f000, 0x1f02b,
+ 0x1f030, 0x1f093,
+ 0x1f0a0, 0x1f0ae,
+ 0x1f0b1, 0x1f0bf,
+ 0x1f0c1, 0x1f0cf,
+ 0x1f0d1, 0x1f0f5,
+ 0x1f100, 0x1f10c,
+ 0x1f110, 0x1f16b,
+ 0x1f170, 0x1f1ac,
+ 0x1f1e6, 0x1f202,
+ 0x1f210, 0x1f23b,
+ 0x1f240, 0x1f248,
+ 0x1f250, 0x1f251,
+ 0x1f260, 0x1f265,
+ 0x1f300, 0x1f6d4,
+ 0x1f6e0, 0x1f6ec,
+ 0x1f6f0, 0x1f6f9,
+ 0x1f700, 0x1f773,
+ 0x1f780, 0x1f7d8,
+ 0x1f800, 0x1f80b,
+ 0x1f810, 0x1f847,
+ 0x1f850, 0x1f859,
+ 0x1f860, 0x1f887,
+ 0x1f890, 0x1f8ad,
+ 0x1f900, 0x1f90b,
+ 0x1f910, 0x1f93e,
+ 0x1f940, 0x1f970,
+ 0x1f973, 0x1f976,
+ 0x1f97a, 0x1f97a,
+ 0x1f97c, 0x1f9a2,
+ 0x1f9b0, 0x1f9b9,
+ 0x1f9c0, 0x1f9c2,
+ 0x1f9d0, 0x1f9ff,
+ 0x1fa60, 0x1fa6d,
+ 0x1fffe, 0x2a6d6,
+ 0x2a700, 0x2b734,
+ 0x2b740, 0x2b81d,
+ 0x2b820, 0x2cea1,
+ 0x2ceb0, 0x2ebe0,
+ 0x2f800, 0x2fa1d,
+ 0x2fffe, 0x2ffff,
+ 0x3fffe, 0x3ffff,
+ 0x4fffe, 0x4ffff,
+ 0x5fffe, 0x5ffff,
+ 0x6fffe, 0x6ffff,
+ 0x7fffe, 0x7ffff,
+ 0x8fffe, 0x8ffff,
+ 0x9fffe, 0x9ffff,
+ 0xafffe, 0xaffff,
+ 0xbfffe, 0xbffff,
+ 0xcfffe, 0xcffff,
+ 0xdfffe, 0xdffff,
+ 0xe0001, 0xe0001,
+ 0xe0020, 0xe007f,
+ 0xe0100, 0xe01ef,
+ 0xefffe, 0x10ffff,
+}; /* CR_Age_11_0 */
+
+/* 'Age_12_0': Derived Age 12.0 */
+static const OnigCodePoint CR_Age_12_0[] = {
+ 677,
+ 0x0000, 0x0377,
+ 0x037a, 0x037f,
+ 0x0384, 0x038a,
+ 0x038c, 0x038c,
+ 0x038e, 0x03a1,
+ 0x03a3, 0x052f,
+ 0x0531, 0x0556,
+ 0x0559, 0x058a,
+ 0x058d, 0x058f,
+ 0x0591, 0x05c7,
+ 0x05d0, 0x05ea,
+ 0x05ef, 0x05f4,
+ 0x0600, 0x061c,
+ 0x061e, 0x070d,
+ 0x070f, 0x074a,
+ 0x074d, 0x07b1,
+ 0x07c0, 0x07fa,
+ 0x07fd, 0x082d,
+ 0x0830, 0x083e,
+ 0x0840, 0x085b,
+ 0x085e, 0x085e,
+ 0x0860, 0x086a,
+ 0x08a0, 0x08b4,
+ 0x08b6, 0x08bd,
+ 0x08d3, 0x0983,
+ 0x0985, 0x098c,
+ 0x098f, 0x0990,
+ 0x0993, 0x09a8,
+ 0x09aa, 0x09b0,
+ 0x09b2, 0x09b2,
+ 0x09b6, 0x09b9,
+ 0x09bc, 0x09c4,
+ 0x09c7, 0x09c8,
+ 0x09cb, 0x09ce,
+ 0x09d7, 0x09d7,
+ 0x09dc, 0x09dd,
+ 0x09df, 0x09e3,
+ 0x09e6, 0x09fe,
+ 0x0a01, 0x0a03,
+ 0x0a05, 0x0a0a,
+ 0x0a0f, 0x0a10,
+ 0x0a13, 0x0a28,
+ 0x0a2a, 0x0a30,
+ 0x0a32, 0x0a33,
+ 0x0a35, 0x0a36,
+ 0x0a38, 0x0a39,
+ 0x0a3c, 0x0a3c,
+ 0x0a3e, 0x0a42,
+ 0x0a47, 0x0a48,
+ 0x0a4b, 0x0a4d,
+ 0x0a51, 0x0a51,
+ 0x0a59, 0x0a5c,
+ 0x0a5e, 0x0a5e,
+ 0x0a66, 0x0a76,
+ 0x0a81, 0x0a83,
+ 0x0a85, 0x0a8d,
+ 0x0a8f, 0x0a91,
+ 0x0a93, 0x0aa8,
+ 0x0aaa, 0x0ab0,
+ 0x0ab2, 0x0ab3,
+ 0x0ab5, 0x0ab9,
+ 0x0abc, 0x0ac5,
+ 0x0ac7, 0x0ac9,
+ 0x0acb, 0x0acd,
+ 0x0ad0, 0x0ad0,
+ 0x0ae0, 0x0ae3,
+ 0x0ae6, 0x0af1,
+ 0x0af9, 0x0aff,
+ 0x0b01, 0x0b03,
+ 0x0b05, 0x0b0c,
+ 0x0b0f, 0x0b10,
+ 0x0b13, 0x0b28,
+ 0x0b2a, 0x0b30,
+ 0x0b32, 0x0b33,
+ 0x0b35, 0x0b39,
+ 0x0b3c, 0x0b44,
+ 0x0b47, 0x0b48,
+ 0x0b4b, 0x0b4d,
+ 0x0b56, 0x0b57,
+ 0x0b5c, 0x0b5d,
+ 0x0b5f, 0x0b63,
+ 0x0b66, 0x0b77,
+ 0x0b82, 0x0b83,
+ 0x0b85, 0x0b8a,
+ 0x0b8e, 0x0b90,
+ 0x0b92, 0x0b95,
+ 0x0b99, 0x0b9a,
+ 0x0b9c, 0x0b9c,
+ 0x0b9e, 0x0b9f,
+ 0x0ba3, 0x0ba4,
+ 0x0ba8, 0x0baa,
+ 0x0bae, 0x0bb9,
+ 0x0bbe, 0x0bc2,
+ 0x0bc6, 0x0bc8,
+ 0x0bca, 0x0bcd,
+ 0x0bd0, 0x0bd0,
+ 0x0bd7, 0x0bd7,
+ 0x0be6, 0x0bfa,
+ 0x0c00, 0x0c0c,
+ 0x0c0e, 0x0c10,
+ 0x0c12, 0x0c28,
+ 0x0c2a, 0x0c39,
+ 0x0c3d, 0x0c44,
+ 0x0c46, 0x0c48,
+ 0x0c4a, 0x0c4d,
+ 0x0c55, 0x0c56,
+ 0x0c58, 0x0c5a,
+ 0x0c60, 0x0c63,
+ 0x0c66, 0x0c6f,
+ 0x0c77, 0x0c8c,
+ 0x0c8e, 0x0c90,
+ 0x0c92, 0x0ca8,
+ 0x0caa, 0x0cb3,
+ 0x0cb5, 0x0cb9,
+ 0x0cbc, 0x0cc4,
+ 0x0cc6, 0x0cc8,
+ 0x0cca, 0x0ccd,
+ 0x0cd5, 0x0cd6,
+ 0x0cde, 0x0cde,
+ 0x0ce0, 0x0ce3,
+ 0x0ce6, 0x0cef,
+ 0x0cf1, 0x0cf2,
+ 0x0d00, 0x0d03,
+ 0x0d05, 0x0d0c,
+ 0x0d0e, 0x0d10,
+ 0x0d12, 0x0d44,
+ 0x0d46, 0x0d48,
+ 0x0d4a, 0x0d4f,
+ 0x0d54, 0x0d63,
+ 0x0d66, 0x0d7f,
+ 0x0d82, 0x0d83,
+ 0x0d85, 0x0d96,
+ 0x0d9a, 0x0db1,
+ 0x0db3, 0x0dbb,
+ 0x0dbd, 0x0dbd,
+ 0x0dc0, 0x0dc6,
+ 0x0dca, 0x0dca,
+ 0x0dcf, 0x0dd4,
+ 0x0dd6, 0x0dd6,
+ 0x0dd8, 0x0ddf,
+ 0x0de6, 0x0def,
+ 0x0df2, 0x0df4,
+ 0x0e01, 0x0e3a,
+ 0x0e3f, 0x0e5b,
+ 0x0e81, 0x0e82,
+ 0x0e84, 0x0e84,
+ 0x0e86, 0x0e8a,
+ 0x0e8c, 0x0ea3,
+ 0x0ea5, 0x0ea5,
+ 0x0ea7, 0x0ebd,
+ 0x0ec0, 0x0ec4,
+ 0x0ec6, 0x0ec6,
+ 0x0ec8, 0x0ecd,
+ 0x0ed0, 0x0ed9,
+ 0x0edc, 0x0edf,
+ 0x0f00, 0x0f47,
+ 0x0f49, 0x0f6c,
+ 0x0f71, 0x0f97,
+ 0x0f99, 0x0fbc,
+ 0x0fbe, 0x0fcc,
+ 0x0fce, 0x0fda,
+ 0x1000, 0x10c5,
+ 0x10c7, 0x10c7,
+ 0x10cd, 0x10cd,
+ 0x10d0, 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,
+ 0x135d, 0x137c,
+ 0x1380, 0x1399,
+ 0x13a0, 0x13f5,
+ 0x13f8, 0x13fd,
+ 0x1400, 0x169c,
+ 0x16a0, 0x16f8,
+ 0x1700, 0x170c,
+ 0x170e, 0x1714,
+ 0x1720, 0x1736,
+ 0x1740, 0x1753,
+ 0x1760, 0x176c,
+ 0x176e, 0x1770,
+ 0x1772, 0x1773,
+ 0x1780, 0x17dd,
+ 0x17e0, 0x17e9,
+ 0x17f0, 0x17f9,
+ 0x1800, 0x180e,
+ 0x1810, 0x1819,
+ 0x1820, 0x1878,
+ 0x1880, 0x18aa,
+ 0x18b0, 0x18f5,
+ 0x1900, 0x191e,
+ 0x1920, 0x192b,
+ 0x1930, 0x193b,
+ 0x1940, 0x1940,
+ 0x1944, 0x196d,
+ 0x1970, 0x1974,
+ 0x1980, 0x19ab,
+ 0x19b0, 0x19c9,
+ 0x19d0, 0x19da,
+ 0x19de, 0x1a1b,
+ 0x1a1e, 0x1a5e,
+ 0x1a60, 0x1a7c,
+ 0x1a7f, 0x1a89,
+ 0x1a90, 0x1a99,
+ 0x1aa0, 0x1aad,
+ 0x1ab0, 0x1abe,
+ 0x1b00, 0x1b4b,
+ 0x1b50, 0x1b7c,
+ 0x1b80, 0x1bf3,
+ 0x1bfc, 0x1c37,
+ 0x1c3b, 0x1c49,
+ 0x1c4d, 0x1c88,
+ 0x1c90, 0x1cba,
+ 0x1cbd, 0x1cc7,
+ 0x1cd0, 0x1cfa,
+ 0x1d00, 0x1df9,
+ 0x1dfb, 0x1f15,
+ 0x1f18, 0x1f1d,
+ 0x1f20, 0x1f45,
+ 0x1f48, 0x1f4d,
+ 0x1f50, 0x1f57,
+ 0x1f59, 0x1f59,
+ 0x1f5b, 0x1f5b,
+ 0x1f5d, 0x1f5d,
+ 0x1f5f, 0x1f7d,
+ 0x1f80, 0x1fb4,
+ 0x1fb6, 0x1fc4,
+ 0x1fc6, 0x1fd3,
+ 0x1fd6, 0x1fdb,
+ 0x1fdd, 0x1fef,
+ 0x1ff2, 0x1ff4,
+ 0x1ff6, 0x1ffe,
+ 0x2000, 0x2064,
+ 0x2066, 0x2071,
+ 0x2074, 0x208e,
+ 0x2090, 0x209c,
+ 0x20a0, 0x20bf,
+ 0x20d0, 0x20f0,
+ 0x2100, 0x218b,
+ 0x2190, 0x2426,
+ 0x2440, 0x244a,
+ 0x2460, 0x2b73,
+ 0x2b76, 0x2b95,
+ 0x2b98, 0x2c2e,
+ 0x2c30, 0x2c5e,
+ 0x2c60, 0x2cf3,
+ 0x2cf9, 0x2d25,
+ 0x2d27, 0x2d27,
+ 0x2d2d, 0x2d2d,
+ 0x2d30, 0x2d67,
+ 0x2d6f, 0x2d70,
+ 0x2d7f, 0x2d96,
+ 0x2da0, 0x2da6,
+ 0x2da8, 0x2dae,
+ 0x2db0, 0x2db6,
+ 0x2db8, 0x2dbe,
+ 0x2dc0, 0x2dc6,
+ 0x2dc8, 0x2dce,
+ 0x2dd0, 0x2dd6,
+ 0x2dd8, 0x2dde,
+ 0x2de0, 0x2e4f,
+ 0x2e80, 0x2e99,
+ 0x2e9b, 0x2ef3,
+ 0x2f00, 0x2fd5,
+ 0x2ff0, 0x2ffb,
+ 0x3000, 0x303f,
+ 0x3041, 0x3096,
+ 0x3099, 0x30ff,
+ 0x3105, 0x312f,
+ 0x3131, 0x318e,
+ 0x3190, 0x31ba,
+ 0x31c0, 0x31e3,
+ 0x31f0, 0x321e,
+ 0x3220, 0x32fe,
+ 0x3300, 0x4db5,
+ 0x4dc0, 0x9fef,
+ 0xa000, 0xa48c,
+ 0xa490, 0xa4c6,
+ 0xa4d0, 0xa62b,
+ 0xa640, 0xa6f7,
+ 0xa700, 0xa7bf,
+ 0xa7c2, 0xa7c6,
+ 0xa7f7, 0xa82b,
+ 0xa830, 0xa839,
+ 0xa840, 0xa877,
+ 0xa880, 0xa8c5,
+ 0xa8ce, 0xa8d9,
+ 0xa8e0, 0xa953,
+ 0xa95f, 0xa97c,
+ 0xa980, 0xa9cd,
+ 0xa9cf, 0xa9d9,
+ 0xa9de, 0xa9fe,
+ 0xaa00, 0xaa36,
+ 0xaa40, 0xaa4d,
+ 0xaa50, 0xaa59,
+ 0xaa5c, 0xaac2,
+ 0xaadb, 0xaaf6,
+ 0xab01, 0xab06,
+ 0xab09, 0xab0e,
+ 0xab11, 0xab16,
+ 0xab20, 0xab26,
+ 0xab28, 0xab2e,
+ 0xab30, 0xab67,
+ 0xab70, 0xabed,
+ 0xabf0, 0xabf9,
+ 0xac00, 0xd7a3,
+ 0xd7b0, 0xd7c6,
+ 0xd7cb, 0xd7fb,
+ 0xd800, 0xfa6d,
+ 0xfa70, 0xfad9,
+ 0xfb00, 0xfb06,
+ 0xfb13, 0xfb17,
+ 0xfb1d, 0xfb36,
+ 0xfb38, 0xfb3c,
+ 0xfb3e, 0xfb3e,
+ 0xfb40, 0xfb41,
+ 0xfb43, 0xfb44,
+ 0xfb46, 0xfbc1,
+ 0xfbd3, 0xfd3f,
+ 0xfd50, 0xfd8f,
+ 0xfd92, 0xfdc7,
+ 0xfdd0, 0xfdfd,
+ 0xfe00, 0xfe19,
+ 0xfe20, 0xfe52,
+ 0xfe54, 0xfe66,
+ 0xfe68, 0xfe6b,
+ 0xfe70, 0xfe74,
+ 0xfe76, 0xfefc,
+ 0xfeff, 0xfeff,
+ 0xff01, 0xffbe,
+ 0xffc2, 0xffc7,
+ 0xffca, 0xffcf,
+ 0xffd2, 0xffd7,
+ 0xffda, 0xffdc,
+ 0xffe0, 0xffe6,
+ 0xffe8, 0xffee,
+ 0xfff9, 0x1000b,
+ 0x1000d, 0x10026,
+ 0x10028, 0x1003a,
+ 0x1003c, 0x1003d,
+ 0x1003f, 0x1004d,
+ 0x10050, 0x1005d,
+ 0x10080, 0x100fa,
+ 0x10100, 0x10102,
+ 0x10107, 0x10133,
+ 0x10137, 0x1018e,
+ 0x10190, 0x1019b,
+ 0x101a0, 0x101a0,
+ 0x101d0, 0x101fd,
+ 0x10280, 0x1029c,
+ 0x102a0, 0x102d0,
+ 0x102e0, 0x102fb,
+ 0x10300, 0x10323,
+ 0x1032d, 0x1034a,
+ 0x10350, 0x1037a,
+ 0x10380, 0x1039d,
+ 0x1039f, 0x103c3,
+ 0x103c8, 0x103d5,
+ 0x10400, 0x1049d,
+ 0x104a0, 0x104a9,
+ 0x104b0, 0x104d3,
+ 0x104d8, 0x104fb,
+ 0x10500, 0x10527,
+ 0x10530, 0x10563,
+ 0x1056f, 0x1056f,
+ 0x10600, 0x10736,
+ 0x10740, 0x10755,
+ 0x10760, 0x10767,
+ 0x10800, 0x10805,
+ 0x10808, 0x10808,
+ 0x1080a, 0x10835,
+ 0x10837, 0x10838,
+ 0x1083c, 0x1083c,
+ 0x1083f, 0x10855,
+ 0x10857, 0x1089e,
+ 0x108a7, 0x108af,
+ 0x108e0, 0x108f2,
+ 0x108f4, 0x108f5,
+ 0x108fb, 0x1091b,
+ 0x1091f, 0x10939,
+ 0x1093f, 0x1093f,
+ 0x10980, 0x109b7,
+ 0x109bc, 0x109cf,
+ 0x109d2, 0x10a03,
+ 0x10a05, 0x10a06,
+ 0x10a0c, 0x10a13,
+ 0x10a15, 0x10a17,
+ 0x10a19, 0x10a35,
+ 0x10a38, 0x10a3a,
+ 0x10a3f, 0x10a48,
+ 0x10a50, 0x10a58,
+ 0x10a60, 0x10a9f,
+ 0x10ac0, 0x10ae6,
+ 0x10aeb, 0x10af6,
+ 0x10b00, 0x10b35,
+ 0x10b39, 0x10b55,
+ 0x10b58, 0x10b72,
+ 0x10b78, 0x10b91,
+ 0x10b99, 0x10b9c,
+ 0x10ba9, 0x10baf,
+ 0x10c00, 0x10c48,
+ 0x10c80, 0x10cb2,
+ 0x10cc0, 0x10cf2,
+ 0x10cfa, 0x10d27,
+ 0x10d30, 0x10d39,
+ 0x10e60, 0x10e7e,
+ 0x10f00, 0x10f27,
+ 0x10f30, 0x10f59,
+ 0x10fe0, 0x10ff6,
+ 0x11000, 0x1104d,
+ 0x11052, 0x1106f,
+ 0x1107f, 0x110c1,
+ 0x110cd, 0x110cd,
+ 0x110d0, 0x110e8,
+ 0x110f0, 0x110f9,
+ 0x11100, 0x11134,
+ 0x11136, 0x11146,
+ 0x11150, 0x11176,
+ 0x11180, 0x111cd,
+ 0x111d0, 0x111df,
+ 0x111e1, 0x111f4,
+ 0x11200, 0x11211,
+ 0x11213, 0x1123e,
+ 0x11280, 0x11286,
+ 0x11288, 0x11288,
+ 0x1128a, 0x1128d,
+ 0x1128f, 0x1129d,
+ 0x1129f, 0x112a9,
+ 0x112b0, 0x112ea,
+ 0x112f0, 0x112f9,
+ 0x11300, 0x11303,
+ 0x11305, 0x1130c,
+ 0x1130f, 0x11310,
+ 0x11313, 0x11328,
+ 0x1132a, 0x11330,
+ 0x11332, 0x11333,
+ 0x11335, 0x11339,
+ 0x1133b, 0x11344,
+ 0x11347, 0x11348,
+ 0x1134b, 0x1134d,
+ 0x11350, 0x11350,
+ 0x11357, 0x11357,
+ 0x1135d, 0x11363,
+ 0x11366, 0x1136c,
+ 0x11370, 0x11374,
+ 0x11400, 0x11459,
+ 0x1145b, 0x1145b,
+ 0x1145d, 0x1145f,
+ 0x11480, 0x114c7,
+ 0x114d0, 0x114d9,
+ 0x11580, 0x115b5,
+ 0x115b8, 0x115dd,
+ 0x11600, 0x11644,
+ 0x11650, 0x11659,
+ 0x11660, 0x1166c,
+ 0x11680, 0x116b8,
+ 0x116c0, 0x116c9,
+ 0x11700, 0x1171a,
+ 0x1171d, 0x1172b,
+ 0x11730, 0x1173f,
+ 0x11800, 0x1183b,
+ 0x118a0, 0x118f2,
+ 0x118ff, 0x118ff,
+ 0x119a0, 0x119a7,
+ 0x119aa, 0x119d7,
+ 0x119da, 0x119e4,
+ 0x11a00, 0x11a47,
+ 0x11a50, 0x11aa2,
+ 0x11ac0, 0x11af8,
+ 0x11c00, 0x11c08,
+ 0x11c0a, 0x11c36,
+ 0x11c38, 0x11c45,
+ 0x11c50, 0x11c6c,
+ 0x11c70, 0x11c8f,
+ 0x11c92, 0x11ca7,
+ 0x11ca9, 0x11cb6,
+ 0x11d00, 0x11d06,
+ 0x11d08, 0x11d09,
+ 0x11d0b, 0x11d36,
+ 0x11d3a, 0x11d3a,
+ 0x11d3c, 0x11d3d,
+ 0x11d3f, 0x11d47,
+ 0x11d50, 0x11d59,
+ 0x11d60, 0x11d65,
+ 0x11d67, 0x11d68,
+ 0x11d6a, 0x11d8e,
+ 0x11d90, 0x11d91,
+ 0x11d93, 0x11d98,
+ 0x11da0, 0x11da9,
+ 0x11ee0, 0x11ef8,
+ 0x11fc0, 0x11ff1,
+ 0x11fff, 0x12399,
+ 0x12400, 0x1246e,
+ 0x12470, 0x12474,
+ 0x12480, 0x12543,
+ 0x13000, 0x1342e,
+ 0x13430, 0x13438,
+ 0x14400, 0x14646,
+ 0x16800, 0x16a38,
+ 0x16a40, 0x16a5e,
+ 0x16a60, 0x16a69,
+ 0x16a6e, 0x16a6f,
+ 0x16ad0, 0x16aed,
+ 0x16af0, 0x16af5,
+ 0x16b00, 0x16b45,
+ 0x16b50, 0x16b59,
+ 0x16b5b, 0x16b61,
+ 0x16b63, 0x16b77,
+ 0x16b7d, 0x16b8f,
+ 0x16e40, 0x16e9a,
+ 0x16f00, 0x16f4a,
+ 0x16f4f, 0x16f87,
+ 0x16f8f, 0x16f9f,
+ 0x16fe0, 0x16fe3,
+ 0x17000, 0x187f7,
+ 0x18800, 0x18af2,
+ 0x1b000, 0x1b11e,
+ 0x1b150, 0x1b152,
+ 0x1b164, 0x1b167,
+ 0x1b170, 0x1b2fb,
+ 0x1bc00, 0x1bc6a,
+ 0x1bc70, 0x1bc7c,
+ 0x1bc80, 0x1bc88,
+ 0x1bc90, 0x1bc99,
+ 0x1bc9c, 0x1bca3,
+ 0x1d000, 0x1d0f5,
+ 0x1d100, 0x1d126,
+ 0x1d129, 0x1d1e8,
+ 0x1d200, 0x1d245,
+ 0x1d2e0, 0x1d2f3,
+ 0x1d300, 0x1d356,
+ 0x1d360, 0x1d378,
+ 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, 0x1d7cb,
+ 0x1d7ce, 0x1da8b,
+ 0x1da9b, 0x1da9f,
+ 0x1daa1, 0x1daaf,
+ 0x1e000, 0x1e006,
+ 0x1e008, 0x1e018,
+ 0x1e01b, 0x1e021,
+ 0x1e023, 0x1e024,
+ 0x1e026, 0x1e02a,
+ 0x1e100, 0x1e12c,
+ 0x1e130, 0x1e13d,
+ 0x1e140, 0x1e149,
+ 0x1e14e, 0x1e14f,
+ 0x1e2c0, 0x1e2f9,
+ 0x1e2ff, 0x1e2ff,
+ 0x1e800, 0x1e8c4,
+ 0x1e8c7, 0x1e8d6,
+ 0x1e900, 0x1e94b,
+ 0x1e950, 0x1e959,
+ 0x1e95e, 0x1e95f,
+ 0x1ec71, 0x1ecb4,
+ 0x1ed01, 0x1ed3d,
+ 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,
+ 0x1eef0, 0x1eef1,
+ 0x1f000, 0x1f02b,
+ 0x1f030, 0x1f093,
+ 0x1f0a0, 0x1f0ae,
+ 0x1f0b1, 0x1f0bf,
+ 0x1f0c1, 0x1f0cf,
+ 0x1f0d1, 0x1f0f5,
+ 0x1f100, 0x1f10c,
+ 0x1f110, 0x1f16c,
+ 0x1f170, 0x1f1ac,
+ 0x1f1e6, 0x1f202,
+ 0x1f210, 0x1f23b,
+ 0x1f240, 0x1f248,
+ 0x1f250, 0x1f251,
+ 0x1f260, 0x1f265,
+ 0x1f300, 0x1f6d5,
+ 0x1f6e0, 0x1f6ec,
+ 0x1f6f0, 0x1f6fa,
+ 0x1f700, 0x1f773,
+ 0x1f780, 0x1f7d8,
+ 0x1f7e0, 0x1f7eb,
+ 0x1f800, 0x1f80b,
+ 0x1f810, 0x1f847,
+ 0x1f850, 0x1f859,
+ 0x1f860, 0x1f887,
+ 0x1f890, 0x1f8ad,
+ 0x1f900, 0x1f90b,
+ 0x1f90d, 0x1f971,
+ 0x1f973, 0x1f976,
+ 0x1f97a, 0x1f9a2,
+ 0x1f9a5, 0x1f9aa,
+ 0x1f9ae, 0x1f9ca,
+ 0x1f9cd, 0x1fa53,
+ 0x1fa60, 0x1fa6d,
+ 0x1fa70, 0x1fa73,
+ 0x1fa78, 0x1fa7a,
+ 0x1fa80, 0x1fa82,
+ 0x1fa90, 0x1fa95,
+ 0x1fffe, 0x2a6d6,
+ 0x2a700, 0x2b734,
+ 0x2b740, 0x2b81d,
+ 0x2b820, 0x2cea1,
+ 0x2ceb0, 0x2ebe0,
+ 0x2f800, 0x2fa1d,
+ 0x2fffe, 0x2ffff,
+ 0x3fffe, 0x3ffff,
+ 0x4fffe, 0x4ffff,
+ 0x5fffe, 0x5ffff,
+ 0x6fffe, 0x6ffff,
+ 0x7fffe, 0x7ffff,
+ 0x8fffe, 0x8ffff,
+ 0x9fffe, 0x9ffff,
+ 0xafffe, 0xaffff,
+ 0xbfffe, 0xbffff,
+ 0xcfffe, 0xcffff,
+ 0xdfffe, 0xdffff,
+ 0xe0001, 0xe0001,
+ 0xe0020, 0xe007f,
+ 0xe0100, 0xe01ef,
+ 0xefffe, 0x10ffff,
+}; /* CR_Age_12_0 */
+
+/* 'Age_12_1': Derived Age 12.1 */
+static const OnigCodePoint CR_Age_12_1[] = {
+ 676,
+ 0x0000, 0x0377,
+ 0x037a, 0x037f,
+ 0x0384, 0x038a,
+ 0x038c, 0x038c,
+ 0x038e, 0x03a1,
+ 0x03a3, 0x052f,
+ 0x0531, 0x0556,
+ 0x0559, 0x058a,
+ 0x058d, 0x058f,
+ 0x0591, 0x05c7,
+ 0x05d0, 0x05ea,
+ 0x05ef, 0x05f4,
+ 0x0600, 0x061c,
+ 0x061e, 0x070d,
+ 0x070f, 0x074a,
+ 0x074d, 0x07b1,
+ 0x07c0, 0x07fa,
+ 0x07fd, 0x082d,
+ 0x0830, 0x083e,
+ 0x0840, 0x085b,
+ 0x085e, 0x085e,
+ 0x0860, 0x086a,
+ 0x08a0, 0x08b4,
+ 0x08b6, 0x08bd,
+ 0x08d3, 0x0983,
+ 0x0985, 0x098c,
+ 0x098f, 0x0990,
+ 0x0993, 0x09a8,
+ 0x09aa, 0x09b0,
+ 0x09b2, 0x09b2,
+ 0x09b6, 0x09b9,
+ 0x09bc, 0x09c4,
+ 0x09c7, 0x09c8,
+ 0x09cb, 0x09ce,
+ 0x09d7, 0x09d7,
+ 0x09dc, 0x09dd,
+ 0x09df, 0x09e3,
+ 0x09e6, 0x09fe,
+ 0x0a01, 0x0a03,
+ 0x0a05, 0x0a0a,
+ 0x0a0f, 0x0a10,
+ 0x0a13, 0x0a28,
+ 0x0a2a, 0x0a30,
+ 0x0a32, 0x0a33,
+ 0x0a35, 0x0a36,
+ 0x0a38, 0x0a39,
+ 0x0a3c, 0x0a3c,
+ 0x0a3e, 0x0a42,
+ 0x0a47, 0x0a48,
+ 0x0a4b, 0x0a4d,
+ 0x0a51, 0x0a51,
+ 0x0a59, 0x0a5c,
+ 0x0a5e, 0x0a5e,
+ 0x0a66, 0x0a76,
+ 0x0a81, 0x0a83,
+ 0x0a85, 0x0a8d,
+ 0x0a8f, 0x0a91,
+ 0x0a93, 0x0aa8,
+ 0x0aaa, 0x0ab0,
+ 0x0ab2, 0x0ab3,
+ 0x0ab5, 0x0ab9,
+ 0x0abc, 0x0ac5,
+ 0x0ac7, 0x0ac9,
+ 0x0acb, 0x0acd,
+ 0x0ad0, 0x0ad0,
+ 0x0ae0, 0x0ae3,
+ 0x0ae6, 0x0af1,
+ 0x0af9, 0x0aff,
+ 0x0b01, 0x0b03,
+ 0x0b05, 0x0b0c,
+ 0x0b0f, 0x0b10,
+ 0x0b13, 0x0b28,
+ 0x0b2a, 0x0b30,
+ 0x0b32, 0x0b33,
+ 0x0b35, 0x0b39,
+ 0x0b3c, 0x0b44,
+ 0x0b47, 0x0b48,
+ 0x0b4b, 0x0b4d,
+ 0x0b56, 0x0b57,
+ 0x0b5c, 0x0b5d,
+ 0x0b5f, 0x0b63,
+ 0x0b66, 0x0b77,
+ 0x0b82, 0x0b83,
+ 0x0b85, 0x0b8a,
+ 0x0b8e, 0x0b90,
+ 0x0b92, 0x0b95,
+ 0x0b99, 0x0b9a,
+ 0x0b9c, 0x0b9c,
+ 0x0b9e, 0x0b9f,
+ 0x0ba3, 0x0ba4,
+ 0x0ba8, 0x0baa,
+ 0x0bae, 0x0bb9,
+ 0x0bbe, 0x0bc2,
+ 0x0bc6, 0x0bc8,
+ 0x0bca, 0x0bcd,
+ 0x0bd0, 0x0bd0,
+ 0x0bd7, 0x0bd7,
+ 0x0be6, 0x0bfa,
+ 0x0c00, 0x0c0c,
+ 0x0c0e, 0x0c10,
+ 0x0c12, 0x0c28,
+ 0x0c2a, 0x0c39,
+ 0x0c3d, 0x0c44,
+ 0x0c46, 0x0c48,
+ 0x0c4a, 0x0c4d,
+ 0x0c55, 0x0c56,
+ 0x0c58, 0x0c5a,
+ 0x0c60, 0x0c63,
+ 0x0c66, 0x0c6f,
+ 0x0c77, 0x0c8c,
+ 0x0c8e, 0x0c90,
+ 0x0c92, 0x0ca8,
+ 0x0caa, 0x0cb3,
+ 0x0cb5, 0x0cb9,
+ 0x0cbc, 0x0cc4,
+ 0x0cc6, 0x0cc8,
+ 0x0cca, 0x0ccd,
+ 0x0cd5, 0x0cd6,
+ 0x0cde, 0x0cde,
+ 0x0ce0, 0x0ce3,
+ 0x0ce6, 0x0cef,
+ 0x0cf1, 0x0cf2,
+ 0x0d00, 0x0d03,
+ 0x0d05, 0x0d0c,
+ 0x0d0e, 0x0d10,
+ 0x0d12, 0x0d44,
+ 0x0d46, 0x0d48,
+ 0x0d4a, 0x0d4f,
+ 0x0d54, 0x0d63,
+ 0x0d66, 0x0d7f,
+ 0x0d82, 0x0d83,
+ 0x0d85, 0x0d96,
+ 0x0d9a, 0x0db1,
+ 0x0db3, 0x0dbb,
+ 0x0dbd, 0x0dbd,
+ 0x0dc0, 0x0dc6,
+ 0x0dca, 0x0dca,
+ 0x0dcf, 0x0dd4,
+ 0x0dd6, 0x0dd6,
+ 0x0dd8, 0x0ddf,
+ 0x0de6, 0x0def,
+ 0x0df2, 0x0df4,
+ 0x0e01, 0x0e3a,
+ 0x0e3f, 0x0e5b,
+ 0x0e81, 0x0e82,
+ 0x0e84, 0x0e84,
+ 0x0e86, 0x0e8a,
+ 0x0e8c, 0x0ea3,
+ 0x0ea5, 0x0ea5,
+ 0x0ea7, 0x0ebd,
+ 0x0ec0, 0x0ec4,
+ 0x0ec6, 0x0ec6,
+ 0x0ec8, 0x0ecd,
+ 0x0ed0, 0x0ed9,
+ 0x0edc, 0x0edf,
+ 0x0f00, 0x0f47,
+ 0x0f49, 0x0f6c,
+ 0x0f71, 0x0f97,
+ 0x0f99, 0x0fbc,
+ 0x0fbe, 0x0fcc,
+ 0x0fce, 0x0fda,
+ 0x1000, 0x10c5,
+ 0x10c7, 0x10c7,
+ 0x10cd, 0x10cd,
+ 0x10d0, 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,
+ 0x135d, 0x137c,
+ 0x1380, 0x1399,
+ 0x13a0, 0x13f5,
+ 0x13f8, 0x13fd,
+ 0x1400, 0x169c,
+ 0x16a0, 0x16f8,
+ 0x1700, 0x170c,
+ 0x170e, 0x1714,
+ 0x1720, 0x1736,
+ 0x1740, 0x1753,
+ 0x1760, 0x176c,
+ 0x176e, 0x1770,
+ 0x1772, 0x1773,
+ 0x1780, 0x17dd,
+ 0x17e0, 0x17e9,
+ 0x17f0, 0x17f9,
+ 0x1800, 0x180e,
+ 0x1810, 0x1819,
+ 0x1820, 0x1878,
+ 0x1880, 0x18aa,
+ 0x18b0, 0x18f5,
+ 0x1900, 0x191e,
+ 0x1920, 0x192b,
+ 0x1930, 0x193b,
+ 0x1940, 0x1940,
+ 0x1944, 0x196d,
+ 0x1970, 0x1974,
+ 0x1980, 0x19ab,
+ 0x19b0, 0x19c9,
+ 0x19d0, 0x19da,
+ 0x19de, 0x1a1b,
+ 0x1a1e, 0x1a5e,
+ 0x1a60, 0x1a7c,
+ 0x1a7f, 0x1a89,
+ 0x1a90, 0x1a99,
+ 0x1aa0, 0x1aad,
+ 0x1ab0, 0x1abe,
+ 0x1b00, 0x1b4b,
+ 0x1b50, 0x1b7c,
+ 0x1b80, 0x1bf3,
+ 0x1bfc, 0x1c37,
+ 0x1c3b, 0x1c49,
+ 0x1c4d, 0x1c88,
+ 0x1c90, 0x1cba,
+ 0x1cbd, 0x1cc7,
+ 0x1cd0, 0x1cfa,
+ 0x1d00, 0x1df9,
+ 0x1dfb, 0x1f15,
+ 0x1f18, 0x1f1d,
+ 0x1f20, 0x1f45,
+ 0x1f48, 0x1f4d,
+ 0x1f50, 0x1f57,
+ 0x1f59, 0x1f59,
+ 0x1f5b, 0x1f5b,
+ 0x1f5d, 0x1f5d,
+ 0x1f5f, 0x1f7d,
+ 0x1f80, 0x1fb4,
+ 0x1fb6, 0x1fc4,
+ 0x1fc6, 0x1fd3,
+ 0x1fd6, 0x1fdb,
+ 0x1fdd, 0x1fef,
+ 0x1ff2, 0x1ff4,
+ 0x1ff6, 0x1ffe,
+ 0x2000, 0x2064,
+ 0x2066, 0x2071,
+ 0x2074, 0x208e,
+ 0x2090, 0x209c,
+ 0x20a0, 0x20bf,
+ 0x20d0, 0x20f0,
+ 0x2100, 0x218b,
+ 0x2190, 0x2426,
+ 0x2440, 0x244a,
+ 0x2460, 0x2b73,
+ 0x2b76, 0x2b95,
+ 0x2b98, 0x2c2e,
+ 0x2c30, 0x2c5e,
+ 0x2c60, 0x2cf3,
+ 0x2cf9, 0x2d25,
+ 0x2d27, 0x2d27,
+ 0x2d2d, 0x2d2d,
+ 0x2d30, 0x2d67,
+ 0x2d6f, 0x2d70,
+ 0x2d7f, 0x2d96,
+ 0x2da0, 0x2da6,
+ 0x2da8, 0x2dae,
+ 0x2db0, 0x2db6,
+ 0x2db8, 0x2dbe,
+ 0x2dc0, 0x2dc6,
+ 0x2dc8, 0x2dce,
+ 0x2dd0, 0x2dd6,
+ 0x2dd8, 0x2dde,
+ 0x2de0, 0x2e4f,
+ 0x2e80, 0x2e99,
+ 0x2e9b, 0x2ef3,
+ 0x2f00, 0x2fd5,
+ 0x2ff0, 0x2ffb,
+ 0x3000, 0x303f,
+ 0x3041, 0x3096,
+ 0x3099, 0x30ff,
+ 0x3105, 0x312f,
+ 0x3131, 0x318e,
+ 0x3190, 0x31ba,
+ 0x31c0, 0x31e3,
+ 0x31f0, 0x321e,
+ 0x3220, 0x4db5,
+ 0x4dc0, 0x9fef,
+ 0xa000, 0xa48c,
+ 0xa490, 0xa4c6,
+ 0xa4d0, 0xa62b,
+ 0xa640, 0xa6f7,
+ 0xa700, 0xa7bf,
+ 0xa7c2, 0xa7c6,
+ 0xa7f7, 0xa82b,
+ 0xa830, 0xa839,
+ 0xa840, 0xa877,
+ 0xa880, 0xa8c5,
+ 0xa8ce, 0xa8d9,
+ 0xa8e0, 0xa953,
+ 0xa95f, 0xa97c,
+ 0xa980, 0xa9cd,
+ 0xa9cf, 0xa9d9,
+ 0xa9de, 0xa9fe,
+ 0xaa00, 0xaa36,
+ 0xaa40, 0xaa4d,
+ 0xaa50, 0xaa59,
+ 0xaa5c, 0xaac2,
+ 0xaadb, 0xaaf6,
+ 0xab01, 0xab06,
+ 0xab09, 0xab0e,
+ 0xab11, 0xab16,
+ 0xab20, 0xab26,
+ 0xab28, 0xab2e,
+ 0xab30, 0xab67,
+ 0xab70, 0xabed,
+ 0xabf0, 0xabf9,
+ 0xac00, 0xd7a3,
+ 0xd7b0, 0xd7c6,
+ 0xd7cb, 0xd7fb,
+ 0xd800, 0xfa6d,
+ 0xfa70, 0xfad9,
+ 0xfb00, 0xfb06,
+ 0xfb13, 0xfb17,
+ 0xfb1d, 0xfb36,
+ 0xfb38, 0xfb3c,
+ 0xfb3e, 0xfb3e,
+ 0xfb40, 0xfb41,
+ 0xfb43, 0xfb44,
+ 0xfb46, 0xfbc1,
+ 0xfbd3, 0xfd3f,
+ 0xfd50, 0xfd8f,
+ 0xfd92, 0xfdc7,
+ 0xfdd0, 0xfdfd,
+ 0xfe00, 0xfe19,
+ 0xfe20, 0xfe52,
+ 0xfe54, 0xfe66,
+ 0xfe68, 0xfe6b,
+ 0xfe70, 0xfe74,
+ 0xfe76, 0xfefc,
+ 0xfeff, 0xfeff,
+ 0xff01, 0xffbe,
+ 0xffc2, 0xffc7,
+ 0xffca, 0xffcf,
+ 0xffd2, 0xffd7,
+ 0xffda, 0xffdc,
+ 0xffe0, 0xffe6,
+ 0xffe8, 0xffee,
+ 0xfff9, 0x1000b,
+ 0x1000d, 0x10026,
+ 0x10028, 0x1003a,
+ 0x1003c, 0x1003d,
+ 0x1003f, 0x1004d,
+ 0x10050, 0x1005d,
+ 0x10080, 0x100fa,
+ 0x10100, 0x10102,
+ 0x10107, 0x10133,
+ 0x10137, 0x1018e,
+ 0x10190, 0x1019b,
+ 0x101a0, 0x101a0,
+ 0x101d0, 0x101fd,
+ 0x10280, 0x1029c,
+ 0x102a0, 0x102d0,
+ 0x102e0, 0x102fb,
+ 0x10300, 0x10323,
+ 0x1032d, 0x1034a,
+ 0x10350, 0x1037a,
+ 0x10380, 0x1039d,
+ 0x1039f, 0x103c3,
+ 0x103c8, 0x103d5,
+ 0x10400, 0x1049d,
+ 0x104a0, 0x104a9,
+ 0x104b0, 0x104d3,
+ 0x104d8, 0x104fb,
+ 0x10500, 0x10527,
+ 0x10530, 0x10563,
+ 0x1056f, 0x1056f,
+ 0x10600, 0x10736,
+ 0x10740, 0x10755,
+ 0x10760, 0x10767,
+ 0x10800, 0x10805,
+ 0x10808, 0x10808,
+ 0x1080a, 0x10835,
+ 0x10837, 0x10838,
+ 0x1083c, 0x1083c,
+ 0x1083f, 0x10855,
+ 0x10857, 0x1089e,
+ 0x108a7, 0x108af,
+ 0x108e0, 0x108f2,
+ 0x108f4, 0x108f5,
+ 0x108fb, 0x1091b,
+ 0x1091f, 0x10939,
+ 0x1093f, 0x1093f,
+ 0x10980, 0x109b7,
+ 0x109bc, 0x109cf,
+ 0x109d2, 0x10a03,
+ 0x10a05, 0x10a06,
+ 0x10a0c, 0x10a13,
+ 0x10a15, 0x10a17,
+ 0x10a19, 0x10a35,
+ 0x10a38, 0x10a3a,
+ 0x10a3f, 0x10a48,
+ 0x10a50, 0x10a58,
+ 0x10a60, 0x10a9f,
+ 0x10ac0, 0x10ae6,
+ 0x10aeb, 0x10af6,
+ 0x10b00, 0x10b35,
+ 0x10b39, 0x10b55,
+ 0x10b58, 0x10b72,
+ 0x10b78, 0x10b91,
+ 0x10b99, 0x10b9c,
+ 0x10ba9, 0x10baf,
+ 0x10c00, 0x10c48,
+ 0x10c80, 0x10cb2,
+ 0x10cc0, 0x10cf2,
+ 0x10cfa, 0x10d27,
+ 0x10d30, 0x10d39,
+ 0x10e60, 0x10e7e,
+ 0x10f00, 0x10f27,
+ 0x10f30, 0x10f59,
+ 0x10fe0, 0x10ff6,
+ 0x11000, 0x1104d,
+ 0x11052, 0x1106f,
+ 0x1107f, 0x110c1,
+ 0x110cd, 0x110cd,
+ 0x110d0, 0x110e8,
+ 0x110f0, 0x110f9,
+ 0x11100, 0x11134,
+ 0x11136, 0x11146,
+ 0x11150, 0x11176,
+ 0x11180, 0x111cd,
+ 0x111d0, 0x111df,
+ 0x111e1, 0x111f4,
+ 0x11200, 0x11211,
+ 0x11213, 0x1123e,
+ 0x11280, 0x11286,
+ 0x11288, 0x11288,
+ 0x1128a, 0x1128d,
+ 0x1128f, 0x1129d,
+ 0x1129f, 0x112a9,
+ 0x112b0, 0x112ea,
+ 0x112f0, 0x112f9,
+ 0x11300, 0x11303,
+ 0x11305, 0x1130c,
+ 0x1130f, 0x11310,
+ 0x11313, 0x11328,
+ 0x1132a, 0x11330,
+ 0x11332, 0x11333,
+ 0x11335, 0x11339,
+ 0x1133b, 0x11344,
+ 0x11347, 0x11348,
+ 0x1134b, 0x1134d,
+ 0x11350, 0x11350,
+ 0x11357, 0x11357,
+ 0x1135d, 0x11363,
+ 0x11366, 0x1136c,
+ 0x11370, 0x11374,
+ 0x11400, 0x11459,
+ 0x1145b, 0x1145b,
+ 0x1145d, 0x1145f,
+ 0x11480, 0x114c7,
+ 0x114d0, 0x114d9,
+ 0x11580, 0x115b5,
+ 0x115b8, 0x115dd,
+ 0x11600, 0x11644,
+ 0x11650, 0x11659,
+ 0x11660, 0x1166c,
+ 0x11680, 0x116b8,
+ 0x116c0, 0x116c9,
+ 0x11700, 0x1171a,
+ 0x1171d, 0x1172b,
+ 0x11730, 0x1173f,
+ 0x11800, 0x1183b,
+ 0x118a0, 0x118f2,
+ 0x118ff, 0x118ff,
+ 0x119a0, 0x119a7,
+ 0x119aa, 0x119d7,
+ 0x119da, 0x119e4,
+ 0x11a00, 0x11a47,
+ 0x11a50, 0x11aa2,
+ 0x11ac0, 0x11af8,
+ 0x11c00, 0x11c08,
+ 0x11c0a, 0x11c36,
+ 0x11c38, 0x11c45,
+ 0x11c50, 0x11c6c,
+ 0x11c70, 0x11c8f,
+ 0x11c92, 0x11ca7,
+ 0x11ca9, 0x11cb6,
+ 0x11d00, 0x11d06,
+ 0x11d08, 0x11d09,
+ 0x11d0b, 0x11d36,
+ 0x11d3a, 0x11d3a,
+ 0x11d3c, 0x11d3d,
+ 0x11d3f, 0x11d47,
+ 0x11d50, 0x11d59,
+ 0x11d60, 0x11d65,
+ 0x11d67, 0x11d68,
+ 0x11d6a, 0x11d8e,
+ 0x11d90, 0x11d91,
+ 0x11d93, 0x11d98,
+ 0x11da0, 0x11da9,
+ 0x11ee0, 0x11ef8,
+ 0x11fc0, 0x11ff1,
+ 0x11fff, 0x12399,
+ 0x12400, 0x1246e,
+ 0x12470, 0x12474,
+ 0x12480, 0x12543,
+ 0x13000, 0x1342e,
+ 0x13430, 0x13438,
+ 0x14400, 0x14646,
+ 0x16800, 0x16a38,
+ 0x16a40, 0x16a5e,
+ 0x16a60, 0x16a69,
+ 0x16a6e, 0x16a6f,
+ 0x16ad0, 0x16aed,
+ 0x16af0, 0x16af5,
+ 0x16b00, 0x16b45,
+ 0x16b50, 0x16b59,
+ 0x16b5b, 0x16b61,
+ 0x16b63, 0x16b77,
+ 0x16b7d, 0x16b8f,
+ 0x16e40, 0x16e9a,
+ 0x16f00, 0x16f4a,
+ 0x16f4f, 0x16f87,
+ 0x16f8f, 0x16f9f,
+ 0x16fe0, 0x16fe3,
+ 0x17000, 0x187f7,
+ 0x18800, 0x18af2,
+ 0x1b000, 0x1b11e,
+ 0x1b150, 0x1b152,
+ 0x1b164, 0x1b167,
+ 0x1b170, 0x1b2fb,
+ 0x1bc00, 0x1bc6a,
+ 0x1bc70, 0x1bc7c,
+ 0x1bc80, 0x1bc88,
+ 0x1bc90, 0x1bc99,
+ 0x1bc9c, 0x1bca3,
+ 0x1d000, 0x1d0f5,
+ 0x1d100, 0x1d126,
+ 0x1d129, 0x1d1e8,
+ 0x1d200, 0x1d245,
+ 0x1d2e0, 0x1d2f3,
+ 0x1d300, 0x1d356,
+ 0x1d360, 0x1d378,
+ 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, 0x1d7cb,
+ 0x1d7ce, 0x1da8b,
+ 0x1da9b, 0x1da9f,
+ 0x1daa1, 0x1daaf,
+ 0x1e000, 0x1e006,
+ 0x1e008, 0x1e018,
+ 0x1e01b, 0x1e021,
+ 0x1e023, 0x1e024,
+ 0x1e026, 0x1e02a,
+ 0x1e100, 0x1e12c,
+ 0x1e130, 0x1e13d,
+ 0x1e140, 0x1e149,
+ 0x1e14e, 0x1e14f,
+ 0x1e2c0, 0x1e2f9,
+ 0x1e2ff, 0x1e2ff,
+ 0x1e800, 0x1e8c4,
+ 0x1e8c7, 0x1e8d6,
+ 0x1e900, 0x1e94b,
+ 0x1e950, 0x1e959,
+ 0x1e95e, 0x1e95f,
+ 0x1ec71, 0x1ecb4,
+ 0x1ed01, 0x1ed3d,
+ 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,
+ 0x1eef0, 0x1eef1,
+ 0x1f000, 0x1f02b,
+ 0x1f030, 0x1f093,
+ 0x1f0a0, 0x1f0ae,
+ 0x1f0b1, 0x1f0bf,
+ 0x1f0c1, 0x1f0cf,
+ 0x1f0d1, 0x1f0f5,
+ 0x1f100, 0x1f10c,
+ 0x1f110, 0x1f16c,
+ 0x1f170, 0x1f1ac,
+ 0x1f1e6, 0x1f202,
+ 0x1f210, 0x1f23b,
+ 0x1f240, 0x1f248,
+ 0x1f250, 0x1f251,
+ 0x1f260, 0x1f265,
+ 0x1f300, 0x1f6d5,
+ 0x1f6e0, 0x1f6ec,
+ 0x1f6f0, 0x1f6fa,
+ 0x1f700, 0x1f773,
+ 0x1f780, 0x1f7d8,
+ 0x1f7e0, 0x1f7eb,
+ 0x1f800, 0x1f80b,
+ 0x1f810, 0x1f847,
+ 0x1f850, 0x1f859,
+ 0x1f860, 0x1f887,
+ 0x1f890, 0x1f8ad,
+ 0x1f900, 0x1f90b,
+ 0x1f90d, 0x1f971,
+ 0x1f973, 0x1f976,
+ 0x1f97a, 0x1f9a2,
+ 0x1f9a5, 0x1f9aa,
+ 0x1f9ae, 0x1f9ca,
+ 0x1f9cd, 0x1fa53,
+ 0x1fa60, 0x1fa6d,
+ 0x1fa70, 0x1fa73,
+ 0x1fa78, 0x1fa7a,
+ 0x1fa80, 0x1fa82,
+ 0x1fa90, 0x1fa95,
+ 0x1fffe, 0x2a6d6,
+ 0x2a700, 0x2b734,
+ 0x2b740, 0x2b81d,
+ 0x2b820, 0x2cea1,
+ 0x2ceb0, 0x2ebe0,
+ 0x2f800, 0x2fa1d,
+ 0x2fffe, 0x2ffff,
+ 0x3fffe, 0x3ffff,
+ 0x4fffe, 0x4ffff,
+ 0x5fffe, 0x5ffff,
+ 0x6fffe, 0x6ffff,
+ 0x7fffe, 0x7ffff,
+ 0x8fffe, 0x8ffff,
+ 0x9fffe, 0x9ffff,
+ 0xafffe, 0xaffff,
+ 0xbfffe, 0xbffff,
+ 0xcfffe, 0xcffff,
+ 0xdfffe, 0xdffff,
+ 0xe0001, 0xe0001,
+ 0xe0020, 0xe007f,
+ 0xe0100, 0xe01ef,
+ 0xefffe, 0x10ffff,
+}; /* CR_Age_12_1 */
+
+/* 'Age_13_0': Derived Age 13.0 */
+static const OnigCodePoint CR_Age_13_0[] = {
+ 686,
+ 0x0000, 0x0377,
+ 0x037a, 0x037f,
+ 0x0384, 0x038a,
+ 0x038c, 0x038c,
+ 0x038e, 0x03a1,
+ 0x03a3, 0x052f,
+ 0x0531, 0x0556,
+ 0x0559, 0x058a,
+ 0x058d, 0x058f,
+ 0x0591, 0x05c7,
+ 0x05d0, 0x05ea,
+ 0x05ef, 0x05f4,
+ 0x0600, 0x061c,
+ 0x061e, 0x070d,
+ 0x070f, 0x074a,
+ 0x074d, 0x07b1,
+ 0x07c0, 0x07fa,
+ 0x07fd, 0x082d,
+ 0x0830, 0x083e,
+ 0x0840, 0x085b,
+ 0x085e, 0x085e,
+ 0x0860, 0x086a,
+ 0x08a0, 0x08b4,
+ 0x08b6, 0x08c7,
+ 0x08d3, 0x0983,
+ 0x0985, 0x098c,
+ 0x098f, 0x0990,
+ 0x0993, 0x09a8,
+ 0x09aa, 0x09b0,
+ 0x09b2, 0x09b2,
+ 0x09b6, 0x09b9,
+ 0x09bc, 0x09c4,
+ 0x09c7, 0x09c8,
+ 0x09cb, 0x09ce,
+ 0x09d7, 0x09d7,
+ 0x09dc, 0x09dd,
+ 0x09df, 0x09e3,
+ 0x09e6, 0x09fe,
+ 0x0a01, 0x0a03,
+ 0x0a05, 0x0a0a,
+ 0x0a0f, 0x0a10,
+ 0x0a13, 0x0a28,
+ 0x0a2a, 0x0a30,
+ 0x0a32, 0x0a33,
+ 0x0a35, 0x0a36,
+ 0x0a38, 0x0a39,
+ 0x0a3c, 0x0a3c,
+ 0x0a3e, 0x0a42,
+ 0x0a47, 0x0a48,
+ 0x0a4b, 0x0a4d,
+ 0x0a51, 0x0a51,
+ 0x0a59, 0x0a5c,
+ 0x0a5e, 0x0a5e,
+ 0x0a66, 0x0a76,
+ 0x0a81, 0x0a83,
+ 0x0a85, 0x0a8d,
+ 0x0a8f, 0x0a91,
+ 0x0a93, 0x0aa8,
+ 0x0aaa, 0x0ab0,
+ 0x0ab2, 0x0ab3,
+ 0x0ab5, 0x0ab9,
+ 0x0abc, 0x0ac5,
+ 0x0ac7, 0x0ac9,
+ 0x0acb, 0x0acd,
+ 0x0ad0, 0x0ad0,
+ 0x0ae0, 0x0ae3,
+ 0x0ae6, 0x0af1,
+ 0x0af9, 0x0aff,
+ 0x0b01, 0x0b03,
+ 0x0b05, 0x0b0c,
+ 0x0b0f, 0x0b10,
+ 0x0b13, 0x0b28,
+ 0x0b2a, 0x0b30,
+ 0x0b32, 0x0b33,
+ 0x0b35, 0x0b39,
+ 0x0b3c, 0x0b44,
+ 0x0b47, 0x0b48,
+ 0x0b4b, 0x0b4d,
+ 0x0b55, 0x0b57,
+ 0x0b5c, 0x0b5d,
+ 0x0b5f, 0x0b63,
+ 0x0b66, 0x0b77,
+ 0x0b82, 0x0b83,
+ 0x0b85, 0x0b8a,
+ 0x0b8e, 0x0b90,
+ 0x0b92, 0x0b95,
+ 0x0b99, 0x0b9a,
+ 0x0b9c, 0x0b9c,
+ 0x0b9e, 0x0b9f,
+ 0x0ba3, 0x0ba4,
+ 0x0ba8, 0x0baa,
+ 0x0bae, 0x0bb9,
+ 0x0bbe, 0x0bc2,
+ 0x0bc6, 0x0bc8,
+ 0x0bca, 0x0bcd,
+ 0x0bd0, 0x0bd0,
+ 0x0bd7, 0x0bd7,
+ 0x0be6, 0x0bfa,
+ 0x0c00, 0x0c0c,
+ 0x0c0e, 0x0c10,
+ 0x0c12, 0x0c28,
+ 0x0c2a, 0x0c39,
+ 0x0c3d, 0x0c44,
+ 0x0c46, 0x0c48,
+ 0x0c4a, 0x0c4d,
+ 0x0c55, 0x0c56,
+ 0x0c58, 0x0c5a,
+ 0x0c60, 0x0c63,
+ 0x0c66, 0x0c6f,
+ 0x0c77, 0x0c8c,
+ 0x0c8e, 0x0c90,
+ 0x0c92, 0x0ca8,
+ 0x0caa, 0x0cb3,
+ 0x0cb5, 0x0cb9,
+ 0x0cbc, 0x0cc4,
+ 0x0cc6, 0x0cc8,
+ 0x0cca, 0x0ccd,
+ 0x0cd5, 0x0cd6,
+ 0x0cde, 0x0cde,
+ 0x0ce0, 0x0ce3,
+ 0x0ce6, 0x0cef,
+ 0x0cf1, 0x0cf2,
+ 0x0d00, 0x0d0c,
+ 0x0d0e, 0x0d10,
+ 0x0d12, 0x0d44,
+ 0x0d46, 0x0d48,
+ 0x0d4a, 0x0d4f,
+ 0x0d54, 0x0d63,
+ 0x0d66, 0x0d7f,
+ 0x0d81, 0x0d83,
+ 0x0d85, 0x0d96,
+ 0x0d9a, 0x0db1,
+ 0x0db3, 0x0dbb,
+ 0x0dbd, 0x0dbd,
+ 0x0dc0, 0x0dc6,
+ 0x0dca, 0x0dca,
+ 0x0dcf, 0x0dd4,
+ 0x0dd6, 0x0dd6,
+ 0x0dd8, 0x0ddf,
+ 0x0de6, 0x0def,
+ 0x0df2, 0x0df4,
+ 0x0e01, 0x0e3a,
+ 0x0e3f, 0x0e5b,
+ 0x0e81, 0x0e82,
+ 0x0e84, 0x0e84,
+ 0x0e86, 0x0e8a,
+ 0x0e8c, 0x0ea3,
+ 0x0ea5, 0x0ea5,
+ 0x0ea7, 0x0ebd,
+ 0x0ec0, 0x0ec4,
+ 0x0ec6, 0x0ec6,
+ 0x0ec8, 0x0ecd,
+ 0x0ed0, 0x0ed9,
+ 0x0edc, 0x0edf,
+ 0x0f00, 0x0f47,
+ 0x0f49, 0x0f6c,
+ 0x0f71, 0x0f97,
+ 0x0f99, 0x0fbc,
+ 0x0fbe, 0x0fcc,
+ 0x0fce, 0x0fda,
+ 0x1000, 0x10c5,
+ 0x10c7, 0x10c7,
+ 0x10cd, 0x10cd,
+ 0x10d0, 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,
+ 0x135d, 0x137c,
+ 0x1380, 0x1399,
+ 0x13a0, 0x13f5,
+ 0x13f8, 0x13fd,
+ 0x1400, 0x169c,
+ 0x16a0, 0x16f8,
+ 0x1700, 0x170c,
+ 0x170e, 0x1714,
+ 0x1720, 0x1736,
+ 0x1740, 0x1753,
+ 0x1760, 0x176c,
+ 0x176e, 0x1770,
+ 0x1772, 0x1773,
+ 0x1780, 0x17dd,
+ 0x17e0, 0x17e9,
+ 0x17f0, 0x17f9,
+ 0x1800, 0x180e,
+ 0x1810, 0x1819,
+ 0x1820, 0x1878,
+ 0x1880, 0x18aa,
+ 0x18b0, 0x18f5,
+ 0x1900, 0x191e,
+ 0x1920, 0x192b,
+ 0x1930, 0x193b,
+ 0x1940, 0x1940,
+ 0x1944, 0x196d,
+ 0x1970, 0x1974,
+ 0x1980, 0x19ab,
+ 0x19b0, 0x19c9,
+ 0x19d0, 0x19da,
+ 0x19de, 0x1a1b,
+ 0x1a1e, 0x1a5e,
+ 0x1a60, 0x1a7c,
+ 0x1a7f, 0x1a89,
+ 0x1a90, 0x1a99,
+ 0x1aa0, 0x1aad,
+ 0x1ab0, 0x1ac0,
+ 0x1b00, 0x1b4b,
+ 0x1b50, 0x1b7c,
+ 0x1b80, 0x1bf3,
+ 0x1bfc, 0x1c37,
+ 0x1c3b, 0x1c49,
+ 0x1c4d, 0x1c88,
+ 0x1c90, 0x1cba,
+ 0x1cbd, 0x1cc7,
+ 0x1cd0, 0x1cfa,
+ 0x1d00, 0x1df9,
+ 0x1dfb, 0x1f15,
+ 0x1f18, 0x1f1d,
+ 0x1f20, 0x1f45,
+ 0x1f48, 0x1f4d,
+ 0x1f50, 0x1f57,
+ 0x1f59, 0x1f59,
+ 0x1f5b, 0x1f5b,
+ 0x1f5d, 0x1f5d,
+ 0x1f5f, 0x1f7d,
+ 0x1f80, 0x1fb4,
+ 0x1fb6, 0x1fc4,
+ 0x1fc6, 0x1fd3,
+ 0x1fd6, 0x1fdb,
+ 0x1fdd, 0x1fef,
+ 0x1ff2, 0x1ff4,
+ 0x1ff6, 0x1ffe,
+ 0x2000, 0x2064,
+ 0x2066, 0x2071,
+ 0x2074, 0x208e,
+ 0x2090, 0x209c,
+ 0x20a0, 0x20bf,
+ 0x20d0, 0x20f0,
+ 0x2100, 0x218b,
+ 0x2190, 0x2426,
+ 0x2440, 0x244a,
+ 0x2460, 0x2b73,
+ 0x2b76, 0x2b95,
+ 0x2b97, 0x2c2e,
+ 0x2c30, 0x2c5e,
+ 0x2c60, 0x2cf3,
+ 0x2cf9, 0x2d25,
+ 0x2d27, 0x2d27,
+ 0x2d2d, 0x2d2d,
+ 0x2d30, 0x2d67,
+ 0x2d6f, 0x2d70,
+ 0x2d7f, 0x2d96,
+ 0x2da0, 0x2da6,
+ 0x2da8, 0x2dae,
+ 0x2db0, 0x2db6,
+ 0x2db8, 0x2dbe,
+ 0x2dc0, 0x2dc6,
+ 0x2dc8, 0x2dce,
+ 0x2dd0, 0x2dd6,
+ 0x2dd8, 0x2dde,
+ 0x2de0, 0x2e52,
+ 0x2e80, 0x2e99,
+ 0x2e9b, 0x2ef3,
+ 0x2f00, 0x2fd5,
+ 0x2ff0, 0x2ffb,
+ 0x3000, 0x303f,
+ 0x3041, 0x3096,
+ 0x3099, 0x30ff,
+ 0x3105, 0x312f,
+ 0x3131, 0x318e,
+ 0x3190, 0x31e3,
+ 0x31f0, 0x321e,
+ 0x3220, 0x9ffc,
+ 0xa000, 0xa48c,
+ 0xa490, 0xa4c6,
+ 0xa4d0, 0xa62b,
+ 0xa640, 0xa6f7,
+ 0xa700, 0xa7bf,
+ 0xa7c2, 0xa7ca,
+ 0xa7f5, 0xa82c,
+ 0xa830, 0xa839,
+ 0xa840, 0xa877,
+ 0xa880, 0xa8c5,
+ 0xa8ce, 0xa8d9,
+ 0xa8e0, 0xa953,
+ 0xa95f, 0xa97c,
+ 0xa980, 0xa9cd,
+ 0xa9cf, 0xa9d9,
+ 0xa9de, 0xa9fe,
+ 0xaa00, 0xaa36,
+ 0xaa40, 0xaa4d,
+ 0xaa50, 0xaa59,
+ 0xaa5c, 0xaac2,
+ 0xaadb, 0xaaf6,
+ 0xab01, 0xab06,
+ 0xab09, 0xab0e,
+ 0xab11, 0xab16,
+ 0xab20, 0xab26,
+ 0xab28, 0xab2e,
+ 0xab30, 0xab6b,
+ 0xab70, 0xabed,
+ 0xabf0, 0xabf9,
+ 0xac00, 0xd7a3,
+ 0xd7b0, 0xd7c6,
+ 0xd7cb, 0xd7fb,
+ 0xd800, 0xfa6d,
+ 0xfa70, 0xfad9,
+ 0xfb00, 0xfb06,
+ 0xfb13, 0xfb17,
+ 0xfb1d, 0xfb36,
+ 0xfb38, 0xfb3c,
+ 0xfb3e, 0xfb3e,
+ 0xfb40, 0xfb41,
+ 0xfb43, 0xfb44,
+ 0xfb46, 0xfbc1,
+ 0xfbd3, 0xfd3f,
+ 0xfd50, 0xfd8f,
+ 0xfd92, 0xfdc7,
+ 0xfdd0, 0xfdfd,
+ 0xfe00, 0xfe19,
+ 0xfe20, 0xfe52,
+ 0xfe54, 0xfe66,
+ 0xfe68, 0xfe6b,
+ 0xfe70, 0xfe74,
+ 0xfe76, 0xfefc,
+ 0xfeff, 0xfeff,
+ 0xff01, 0xffbe,
+ 0xffc2, 0xffc7,
+ 0xffca, 0xffcf,
+ 0xffd2, 0xffd7,
+ 0xffda, 0xffdc,
+ 0xffe0, 0xffe6,
+ 0xffe8, 0xffee,
+ 0xfff9, 0x1000b,
+ 0x1000d, 0x10026,
+ 0x10028, 0x1003a,
+ 0x1003c, 0x1003d,
+ 0x1003f, 0x1004d,
+ 0x10050, 0x1005d,
+ 0x10080, 0x100fa,
+ 0x10100, 0x10102,
+ 0x10107, 0x10133,
+ 0x10137, 0x1018e,
+ 0x10190, 0x1019c,
+ 0x101a0, 0x101a0,
+ 0x101d0, 0x101fd,
+ 0x10280, 0x1029c,
+ 0x102a0, 0x102d0,
+ 0x102e0, 0x102fb,
+ 0x10300, 0x10323,
+ 0x1032d, 0x1034a,
+ 0x10350, 0x1037a,
+ 0x10380, 0x1039d,
+ 0x1039f, 0x103c3,
+ 0x103c8, 0x103d5,
+ 0x10400, 0x1049d,
+ 0x104a0, 0x104a9,
+ 0x104b0, 0x104d3,
+ 0x104d8, 0x104fb,
+ 0x10500, 0x10527,
+ 0x10530, 0x10563,
+ 0x1056f, 0x1056f,
+ 0x10600, 0x10736,
+ 0x10740, 0x10755,
+ 0x10760, 0x10767,
+ 0x10800, 0x10805,
+ 0x10808, 0x10808,
+ 0x1080a, 0x10835,
+ 0x10837, 0x10838,
+ 0x1083c, 0x1083c,
+ 0x1083f, 0x10855,
+ 0x10857, 0x1089e,
+ 0x108a7, 0x108af,
+ 0x108e0, 0x108f2,
+ 0x108f4, 0x108f5,
+ 0x108fb, 0x1091b,
+ 0x1091f, 0x10939,
+ 0x1093f, 0x1093f,
+ 0x10980, 0x109b7,
+ 0x109bc, 0x109cf,
+ 0x109d2, 0x10a03,
+ 0x10a05, 0x10a06,
+ 0x10a0c, 0x10a13,
+ 0x10a15, 0x10a17,
+ 0x10a19, 0x10a35,
+ 0x10a38, 0x10a3a,
+ 0x10a3f, 0x10a48,
+ 0x10a50, 0x10a58,
+ 0x10a60, 0x10a9f,
+ 0x10ac0, 0x10ae6,
+ 0x10aeb, 0x10af6,
+ 0x10b00, 0x10b35,
+ 0x10b39, 0x10b55,
+ 0x10b58, 0x10b72,
+ 0x10b78, 0x10b91,
+ 0x10b99, 0x10b9c,
+ 0x10ba9, 0x10baf,
+ 0x10c00, 0x10c48,
+ 0x10c80, 0x10cb2,
+ 0x10cc0, 0x10cf2,
+ 0x10cfa, 0x10d27,
+ 0x10d30, 0x10d39,
+ 0x10e60, 0x10e7e,
+ 0x10e80, 0x10ea9,
+ 0x10eab, 0x10ead,
+ 0x10eb0, 0x10eb1,
+ 0x10f00, 0x10f27,
+ 0x10f30, 0x10f59,
+ 0x10fb0, 0x10fcb,
+ 0x10fe0, 0x10ff6,
+ 0x11000, 0x1104d,
+ 0x11052, 0x1106f,
+ 0x1107f, 0x110c1,
+ 0x110cd, 0x110cd,
+ 0x110d0, 0x110e8,
+ 0x110f0, 0x110f9,
+ 0x11100, 0x11134,
+ 0x11136, 0x11147,
+ 0x11150, 0x11176,
+ 0x11180, 0x111df,
+ 0x111e1, 0x111f4,
+ 0x11200, 0x11211,
+ 0x11213, 0x1123e,
+ 0x11280, 0x11286,
+ 0x11288, 0x11288,
+ 0x1128a, 0x1128d,
+ 0x1128f, 0x1129d,
+ 0x1129f, 0x112a9,
+ 0x112b0, 0x112ea,
+ 0x112f0, 0x112f9,
+ 0x11300, 0x11303,
+ 0x11305, 0x1130c,
+ 0x1130f, 0x11310,
+ 0x11313, 0x11328,
+ 0x1132a, 0x11330,
+ 0x11332, 0x11333,
+ 0x11335, 0x11339,
+ 0x1133b, 0x11344,
+ 0x11347, 0x11348,
+ 0x1134b, 0x1134d,
+ 0x11350, 0x11350,
+ 0x11357, 0x11357,
+ 0x1135d, 0x11363,
+ 0x11366, 0x1136c,
+ 0x11370, 0x11374,
+ 0x11400, 0x1145b,
+ 0x1145d, 0x11461,
+ 0x11480, 0x114c7,
+ 0x114d0, 0x114d9,
+ 0x11580, 0x115b5,
+ 0x115b8, 0x115dd,
+ 0x11600, 0x11644,
+ 0x11650, 0x11659,
+ 0x11660, 0x1166c,
+ 0x11680, 0x116b8,
+ 0x116c0, 0x116c9,
+ 0x11700, 0x1171a,
+ 0x1171d, 0x1172b,
+ 0x11730, 0x1173f,
+ 0x11800, 0x1183b,
+ 0x118a0, 0x118f2,
+ 0x118ff, 0x11906,
+ 0x11909, 0x11909,
+ 0x1190c, 0x11913,
+ 0x11915, 0x11916,
+ 0x11918, 0x11935,
+ 0x11937, 0x11938,
+ 0x1193b, 0x11946,
+ 0x11950, 0x11959,
+ 0x119a0, 0x119a7,
+ 0x119aa, 0x119d7,
+ 0x119da, 0x119e4,
+ 0x11a00, 0x11a47,
+ 0x11a50, 0x11aa2,
+ 0x11ac0, 0x11af8,
+ 0x11c00, 0x11c08,
+ 0x11c0a, 0x11c36,
+ 0x11c38, 0x11c45,
+ 0x11c50, 0x11c6c,
+ 0x11c70, 0x11c8f,
+ 0x11c92, 0x11ca7,
+ 0x11ca9, 0x11cb6,
+ 0x11d00, 0x11d06,
+ 0x11d08, 0x11d09,
+ 0x11d0b, 0x11d36,
+ 0x11d3a, 0x11d3a,
+ 0x11d3c, 0x11d3d,
+ 0x11d3f, 0x11d47,
+ 0x11d50, 0x11d59,
+ 0x11d60, 0x11d65,
+ 0x11d67, 0x11d68,
+ 0x11d6a, 0x11d8e,
+ 0x11d90, 0x11d91,
+ 0x11d93, 0x11d98,
+ 0x11da0, 0x11da9,
+ 0x11ee0, 0x11ef8,
+ 0x11fb0, 0x11fb0,
+ 0x11fc0, 0x11ff1,
+ 0x11fff, 0x12399,
+ 0x12400, 0x1246e,
+ 0x12470, 0x12474,
+ 0x12480, 0x12543,
+ 0x13000, 0x1342e,
+ 0x13430, 0x13438,
+ 0x14400, 0x14646,
+ 0x16800, 0x16a38,
+ 0x16a40, 0x16a5e,
+ 0x16a60, 0x16a69,
+ 0x16a6e, 0x16a6f,
+ 0x16ad0, 0x16aed,
+ 0x16af0, 0x16af5,
+ 0x16b00, 0x16b45,
+ 0x16b50, 0x16b59,
+ 0x16b5b, 0x16b61,
+ 0x16b63, 0x16b77,
+ 0x16b7d, 0x16b8f,
+ 0x16e40, 0x16e9a,
+ 0x16f00, 0x16f4a,
+ 0x16f4f, 0x16f87,
+ 0x16f8f, 0x16f9f,
+ 0x16fe0, 0x16fe4,
+ 0x16ff0, 0x16ff1,
+ 0x17000, 0x187f7,
+ 0x18800, 0x18cd5,
+ 0x18d00, 0x18d08,
+ 0x1b000, 0x1b11e,
+ 0x1b150, 0x1b152,
+ 0x1b164, 0x1b167,
+ 0x1b170, 0x1b2fb,
+ 0x1bc00, 0x1bc6a,
+ 0x1bc70, 0x1bc7c,
+ 0x1bc80, 0x1bc88,
+ 0x1bc90, 0x1bc99,
+ 0x1bc9c, 0x1bca3,
+ 0x1d000, 0x1d0f5,
+ 0x1d100, 0x1d126,
+ 0x1d129, 0x1d1e8,
+ 0x1d200, 0x1d245,
+ 0x1d2e0, 0x1d2f3,
+ 0x1d300, 0x1d356,
+ 0x1d360, 0x1d378,
+ 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, 0x1d7cb,
+ 0x1d7ce, 0x1da8b,
+ 0x1da9b, 0x1da9f,
+ 0x1daa1, 0x1daaf,
+ 0x1e000, 0x1e006,
+ 0x1e008, 0x1e018,
+ 0x1e01b, 0x1e021,
+ 0x1e023, 0x1e024,
+ 0x1e026, 0x1e02a,
+ 0x1e100, 0x1e12c,
+ 0x1e130, 0x1e13d,
+ 0x1e140, 0x1e149,
+ 0x1e14e, 0x1e14f,
+ 0x1e2c0, 0x1e2f9,
+ 0x1e2ff, 0x1e2ff,
+ 0x1e800, 0x1e8c4,
+ 0x1e8c7, 0x1e8d6,
+ 0x1e900, 0x1e94b,
+ 0x1e950, 0x1e959,
+ 0x1e95e, 0x1e95f,
+ 0x1ec71, 0x1ecb4,
+ 0x1ed01, 0x1ed3d,
+ 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,
+ 0x1eef0, 0x1eef1,
+ 0x1f000, 0x1f02b,
+ 0x1f030, 0x1f093,
+ 0x1f0a0, 0x1f0ae,
+ 0x1f0b1, 0x1f0bf,
+ 0x1f0c1, 0x1f0cf,
+ 0x1f0d1, 0x1f0f5,
+ 0x1f100, 0x1f1ad,
+ 0x1f1e6, 0x1f202,
+ 0x1f210, 0x1f23b,
+ 0x1f240, 0x1f248,
+ 0x1f250, 0x1f251,
+ 0x1f260, 0x1f265,
+ 0x1f300, 0x1f6d7,
+ 0x1f6e0, 0x1f6ec,
+ 0x1f6f0, 0x1f6fc,
+ 0x1f700, 0x1f773,
+ 0x1f780, 0x1f7d8,
+ 0x1f7e0, 0x1f7eb,
+ 0x1f800, 0x1f80b,
+ 0x1f810, 0x1f847,
+ 0x1f850, 0x1f859,
+ 0x1f860, 0x1f887,
+ 0x1f890, 0x1f8ad,
+ 0x1f8b0, 0x1f8b1,
+ 0x1f900, 0x1f978,
+ 0x1f97a, 0x1f9cb,
+ 0x1f9cd, 0x1fa53,
+ 0x1fa60, 0x1fa6d,
+ 0x1fa70, 0x1fa74,
+ 0x1fa78, 0x1fa7a,
+ 0x1fa80, 0x1fa86,
+ 0x1fa90, 0x1faa8,
+ 0x1fab0, 0x1fab6,
+ 0x1fac0, 0x1fac2,
+ 0x1fad0, 0x1fad6,
+ 0x1fb00, 0x1fb92,
+ 0x1fb94, 0x1fbca,
+ 0x1fbf0, 0x1fbf9,
+ 0x1fffe, 0x2a6dd,
+ 0x2a700, 0x2b734,
+ 0x2b740, 0x2b81d,
+ 0x2b820, 0x2cea1,
+ 0x2ceb0, 0x2ebe0,
+ 0x2f800, 0x2fa1d,
+ 0x2fffe, 0x3134a,
+ 0x3fffe, 0x3ffff,
+ 0x4fffe, 0x4ffff,
+ 0x5fffe, 0x5ffff,
+ 0x6fffe, 0x6ffff,
+ 0x7fffe, 0x7ffff,
+ 0x8fffe, 0x8ffff,
+ 0x9fffe, 0x9ffff,
+ 0xafffe, 0xaffff,
+ 0xbfffe, 0xbffff,
+ 0xcfffe, 0xcffff,
+ 0xdfffe, 0xdffff,
+ 0xe0001, 0xe0001,
+ 0xe0020, 0xe007f,
+ 0xe0100, 0xe01ef,
+ 0xefffe, 0x10ffff,
+}; /* CR_Age_13_0 */
+
+/* 'Age_14_0': Derived Age 14.0 */
+static const OnigCodePoint CR_Age_14_0[] = {
+ 706,
+ 0x0000, 0x0377,
+ 0x037a, 0x037f,
+ 0x0384, 0x038a,
+ 0x038c, 0x038c,
+ 0x038e, 0x03a1,
+ 0x03a3, 0x052f,
+ 0x0531, 0x0556,
+ 0x0559, 0x058a,
+ 0x058d, 0x058f,
+ 0x0591, 0x05c7,
+ 0x05d0, 0x05ea,
+ 0x05ef, 0x05f4,
+ 0x0600, 0x070d,
+ 0x070f, 0x074a,
+ 0x074d, 0x07b1,
+ 0x07c0, 0x07fa,
+ 0x07fd, 0x082d,
+ 0x0830, 0x083e,
+ 0x0840, 0x085b,
+ 0x085e, 0x085e,
+ 0x0860, 0x086a,
+ 0x0870, 0x088e,
+ 0x0890, 0x0891,
+ 0x0898, 0x0983,
+ 0x0985, 0x098c,
+ 0x098f, 0x0990,
+ 0x0993, 0x09a8,
+ 0x09aa, 0x09b0,
+ 0x09b2, 0x09b2,
+ 0x09b6, 0x09b9,
+ 0x09bc, 0x09c4,
+ 0x09c7, 0x09c8,
+ 0x09cb, 0x09ce,
+ 0x09d7, 0x09d7,
+ 0x09dc, 0x09dd,
+ 0x09df, 0x09e3,
+ 0x09e6, 0x09fe,
+ 0x0a01, 0x0a03,
+ 0x0a05, 0x0a0a,
+ 0x0a0f, 0x0a10,
+ 0x0a13, 0x0a28,
+ 0x0a2a, 0x0a30,
+ 0x0a32, 0x0a33,
+ 0x0a35, 0x0a36,
+ 0x0a38, 0x0a39,
+ 0x0a3c, 0x0a3c,
+ 0x0a3e, 0x0a42,
+ 0x0a47, 0x0a48,
+ 0x0a4b, 0x0a4d,
+ 0x0a51, 0x0a51,
+ 0x0a59, 0x0a5c,
+ 0x0a5e, 0x0a5e,
+ 0x0a66, 0x0a76,
+ 0x0a81, 0x0a83,
+ 0x0a85, 0x0a8d,
+ 0x0a8f, 0x0a91,
+ 0x0a93, 0x0aa8,
+ 0x0aaa, 0x0ab0,
+ 0x0ab2, 0x0ab3,
+ 0x0ab5, 0x0ab9,
+ 0x0abc, 0x0ac5,
+ 0x0ac7, 0x0ac9,
+ 0x0acb, 0x0acd,
+ 0x0ad0, 0x0ad0,
+ 0x0ae0, 0x0ae3,
+ 0x0ae6, 0x0af1,
+ 0x0af9, 0x0aff,
+ 0x0b01, 0x0b03,
+ 0x0b05, 0x0b0c,
+ 0x0b0f, 0x0b10,
+ 0x0b13, 0x0b28,
+ 0x0b2a, 0x0b30,
+ 0x0b32, 0x0b33,
+ 0x0b35, 0x0b39,
+ 0x0b3c, 0x0b44,
+ 0x0b47, 0x0b48,
+ 0x0b4b, 0x0b4d,
+ 0x0b55, 0x0b57,
+ 0x0b5c, 0x0b5d,
+ 0x0b5f, 0x0b63,
+ 0x0b66, 0x0b77,
+ 0x0b82, 0x0b83,
+ 0x0b85, 0x0b8a,
+ 0x0b8e, 0x0b90,
+ 0x0b92, 0x0b95,
+ 0x0b99, 0x0b9a,
+ 0x0b9c, 0x0b9c,
+ 0x0b9e, 0x0b9f,
+ 0x0ba3, 0x0ba4,
+ 0x0ba8, 0x0baa,
+ 0x0bae, 0x0bb9,
+ 0x0bbe, 0x0bc2,
+ 0x0bc6, 0x0bc8,
+ 0x0bca, 0x0bcd,
+ 0x0bd0, 0x0bd0,
+ 0x0bd7, 0x0bd7,
+ 0x0be6, 0x0bfa,
+ 0x0c00, 0x0c0c,
+ 0x0c0e, 0x0c10,
+ 0x0c12, 0x0c28,
+ 0x0c2a, 0x0c39,
+ 0x0c3c, 0x0c44,
+ 0x0c46, 0x0c48,
+ 0x0c4a, 0x0c4d,
+ 0x0c55, 0x0c56,
+ 0x0c58, 0x0c5a,
+ 0x0c5d, 0x0c5d,
+ 0x0c60, 0x0c63,
+ 0x0c66, 0x0c6f,
+ 0x0c77, 0x0c8c,
+ 0x0c8e, 0x0c90,
+ 0x0c92, 0x0ca8,
+ 0x0caa, 0x0cb3,
+ 0x0cb5, 0x0cb9,
+ 0x0cbc, 0x0cc4,
+ 0x0cc6, 0x0cc8,
+ 0x0cca, 0x0ccd,
+ 0x0cd5, 0x0cd6,
+ 0x0cdd, 0x0cde,
+ 0x0ce0, 0x0ce3,
+ 0x0ce6, 0x0cef,
+ 0x0cf1, 0x0cf2,
+ 0x0d00, 0x0d0c,
+ 0x0d0e, 0x0d10,
+ 0x0d12, 0x0d44,
+ 0x0d46, 0x0d48,
+ 0x0d4a, 0x0d4f,
+ 0x0d54, 0x0d63,
+ 0x0d66, 0x0d7f,
+ 0x0d81, 0x0d83,
+ 0x0d85, 0x0d96,
+ 0x0d9a, 0x0db1,
+ 0x0db3, 0x0dbb,
+ 0x0dbd, 0x0dbd,
+ 0x0dc0, 0x0dc6,
+ 0x0dca, 0x0dca,
+ 0x0dcf, 0x0dd4,
+ 0x0dd6, 0x0dd6,
+ 0x0dd8, 0x0ddf,
+ 0x0de6, 0x0def,
+ 0x0df2, 0x0df4,
+ 0x0e01, 0x0e3a,
+ 0x0e3f, 0x0e5b,
+ 0x0e81, 0x0e82,
+ 0x0e84, 0x0e84,
+ 0x0e86, 0x0e8a,
+ 0x0e8c, 0x0ea3,
+ 0x0ea5, 0x0ea5,
+ 0x0ea7, 0x0ebd,
+ 0x0ec0, 0x0ec4,
+ 0x0ec6, 0x0ec6,
+ 0x0ec8, 0x0ecd,
+ 0x0ed0, 0x0ed9,
+ 0x0edc, 0x0edf,
+ 0x0f00, 0x0f47,
+ 0x0f49, 0x0f6c,
+ 0x0f71, 0x0f97,
+ 0x0f99, 0x0fbc,
+ 0x0fbe, 0x0fcc,
+ 0x0fce, 0x0fda,
+ 0x1000, 0x10c5,
+ 0x10c7, 0x10c7,
+ 0x10cd, 0x10cd,
+ 0x10d0, 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,
+ 0x135d, 0x137c,
+ 0x1380, 0x1399,
+ 0x13a0, 0x13f5,
+ 0x13f8, 0x13fd,
+ 0x1400, 0x169c,
+ 0x16a0, 0x16f8,
+ 0x1700, 0x1715,
+ 0x171f, 0x1736,
+ 0x1740, 0x1753,
+ 0x1760, 0x176c,
+ 0x176e, 0x1770,
+ 0x1772, 0x1773,
+ 0x1780, 0x17dd,
+ 0x17e0, 0x17e9,
+ 0x17f0, 0x17f9,
+ 0x1800, 0x1819,
+ 0x1820, 0x1878,
+ 0x1880, 0x18aa,
+ 0x18b0, 0x18f5,
+ 0x1900, 0x191e,
+ 0x1920, 0x192b,
+ 0x1930, 0x193b,
+ 0x1940, 0x1940,
+ 0x1944, 0x196d,
+ 0x1970, 0x1974,
+ 0x1980, 0x19ab,
+ 0x19b0, 0x19c9,
+ 0x19d0, 0x19da,
+ 0x19de, 0x1a1b,
+ 0x1a1e, 0x1a5e,
+ 0x1a60, 0x1a7c,
+ 0x1a7f, 0x1a89,
+ 0x1a90, 0x1a99,
+ 0x1aa0, 0x1aad,
+ 0x1ab0, 0x1ace,
+ 0x1b00, 0x1b4c,
+ 0x1b50, 0x1b7e,
+ 0x1b80, 0x1bf3,
+ 0x1bfc, 0x1c37,
+ 0x1c3b, 0x1c49,
+ 0x1c4d, 0x1c88,
+ 0x1c90, 0x1cba,
+ 0x1cbd, 0x1cc7,
+ 0x1cd0, 0x1cfa,
+ 0x1d00, 0x1f15,
+ 0x1f18, 0x1f1d,
+ 0x1f20, 0x1f45,
+ 0x1f48, 0x1f4d,
+ 0x1f50, 0x1f57,
+ 0x1f59, 0x1f59,
+ 0x1f5b, 0x1f5b,
+ 0x1f5d, 0x1f5d,
+ 0x1f5f, 0x1f7d,
+ 0x1f80, 0x1fb4,
+ 0x1fb6, 0x1fc4,
+ 0x1fc6, 0x1fd3,
+ 0x1fd6, 0x1fdb,
+ 0x1fdd, 0x1fef,
+ 0x1ff2, 0x1ff4,
+ 0x1ff6, 0x1ffe,
+ 0x2000, 0x2064,
+ 0x2066, 0x2071,
+ 0x2074, 0x208e,
+ 0x2090, 0x209c,
+ 0x20a0, 0x20c0,
+ 0x20d0, 0x20f0,
+ 0x2100, 0x218b,
+ 0x2190, 0x2426,
+ 0x2440, 0x244a,
+ 0x2460, 0x2b73,
+ 0x2b76, 0x2b95,
+ 0x2b97, 0x2cf3,
+ 0x2cf9, 0x2d25,
+ 0x2d27, 0x2d27,
+ 0x2d2d, 0x2d2d,
+ 0x2d30, 0x2d67,
+ 0x2d6f, 0x2d70,
+ 0x2d7f, 0x2d96,
+ 0x2da0, 0x2da6,
+ 0x2da8, 0x2dae,
+ 0x2db0, 0x2db6,
+ 0x2db8, 0x2dbe,
+ 0x2dc0, 0x2dc6,
+ 0x2dc8, 0x2dce,
+ 0x2dd0, 0x2dd6,
+ 0x2dd8, 0x2dde,
+ 0x2de0, 0x2e5d,
+ 0x2e80, 0x2e99,
+ 0x2e9b, 0x2ef3,
+ 0x2f00, 0x2fd5,
+ 0x2ff0, 0x2ffb,
+ 0x3000, 0x303f,
+ 0x3041, 0x3096,
+ 0x3099, 0x30ff,
+ 0x3105, 0x312f,
+ 0x3131, 0x318e,
+ 0x3190, 0x31e3,
+ 0x31f0, 0x321e,
+ 0x3220, 0xa48c,
+ 0xa490, 0xa4c6,
+ 0xa4d0, 0xa62b,
+ 0xa640, 0xa6f7,
+ 0xa700, 0xa7ca,
+ 0xa7d0, 0xa7d1,
+ 0xa7d3, 0xa7d3,
+ 0xa7d5, 0xa7d9,
+ 0xa7f2, 0xa82c,
+ 0xa830, 0xa839,
+ 0xa840, 0xa877,
+ 0xa880, 0xa8c5,
+ 0xa8ce, 0xa8d9,
+ 0xa8e0, 0xa953,
+ 0xa95f, 0xa97c,
+ 0xa980, 0xa9cd,
+ 0xa9cf, 0xa9d9,
+ 0xa9de, 0xa9fe,
+ 0xaa00, 0xaa36,
+ 0xaa40, 0xaa4d,
+ 0xaa50, 0xaa59,
+ 0xaa5c, 0xaac2,
+ 0xaadb, 0xaaf6,
+ 0xab01, 0xab06,
+ 0xab09, 0xab0e,
+ 0xab11, 0xab16,
+ 0xab20, 0xab26,
+ 0xab28, 0xab2e,
+ 0xab30, 0xab6b,
+ 0xab70, 0xabed,
+ 0xabf0, 0xabf9,
+ 0xac00, 0xd7a3,
+ 0xd7b0, 0xd7c6,
+ 0xd7cb, 0xd7fb,
+ 0xd800, 0xfa6d,
+ 0xfa70, 0xfad9,
+ 0xfb00, 0xfb06,
+ 0xfb13, 0xfb17,
+ 0xfb1d, 0xfb36,
+ 0xfb38, 0xfb3c,
+ 0xfb3e, 0xfb3e,
+ 0xfb40, 0xfb41,
+ 0xfb43, 0xfb44,
+ 0xfb46, 0xfbc2,
+ 0xfbd3, 0xfd8f,
+ 0xfd92, 0xfdc7,
+ 0xfdcf, 0xfe19,
+ 0xfe20, 0xfe52,
+ 0xfe54, 0xfe66,
+ 0xfe68, 0xfe6b,
+ 0xfe70, 0xfe74,
+ 0xfe76, 0xfefc,
+ 0xfeff, 0xfeff,
+ 0xff01, 0xffbe,
+ 0xffc2, 0xffc7,
+ 0xffca, 0xffcf,
+ 0xffd2, 0xffd7,
+ 0xffda, 0xffdc,
+ 0xffe0, 0xffe6,
+ 0xffe8, 0xffee,
+ 0xfff9, 0x1000b,
+ 0x1000d, 0x10026,
+ 0x10028, 0x1003a,
+ 0x1003c, 0x1003d,
+ 0x1003f, 0x1004d,
+ 0x10050, 0x1005d,
+ 0x10080, 0x100fa,
+ 0x10100, 0x10102,
+ 0x10107, 0x10133,
+ 0x10137, 0x1018e,
+ 0x10190, 0x1019c,
+ 0x101a0, 0x101a0,
+ 0x101d0, 0x101fd,
+ 0x10280, 0x1029c,
+ 0x102a0, 0x102d0,
+ 0x102e0, 0x102fb,
+ 0x10300, 0x10323,
+ 0x1032d, 0x1034a,
+ 0x10350, 0x1037a,
+ 0x10380, 0x1039d,
+ 0x1039f, 0x103c3,
+ 0x103c8, 0x103d5,
+ 0x10400, 0x1049d,
+ 0x104a0, 0x104a9,
+ 0x104b0, 0x104d3,
+ 0x104d8, 0x104fb,
+ 0x10500, 0x10527,
+ 0x10530, 0x10563,
+ 0x1056f, 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,
+ 0x10857, 0x1089e,
+ 0x108a7, 0x108af,
+ 0x108e0, 0x108f2,
+ 0x108f4, 0x108f5,
+ 0x108fb, 0x1091b,
+ 0x1091f, 0x10939,
+ 0x1093f, 0x1093f,
+ 0x10980, 0x109b7,
+ 0x109bc, 0x109cf,
+ 0x109d2, 0x10a03,
+ 0x10a05, 0x10a06,
+ 0x10a0c, 0x10a13,
+ 0x10a15, 0x10a17,
+ 0x10a19, 0x10a35,
+ 0x10a38, 0x10a3a,
+ 0x10a3f, 0x10a48,
+ 0x10a50, 0x10a58,
+ 0x10a60, 0x10a9f,
+ 0x10ac0, 0x10ae6,
+ 0x10aeb, 0x10af6,
+ 0x10b00, 0x10b35,
+ 0x10b39, 0x10b55,
+ 0x10b58, 0x10b72,
+ 0x10b78, 0x10b91,
+ 0x10b99, 0x10b9c,
+ 0x10ba9, 0x10baf,
+ 0x10c00, 0x10c48,
+ 0x10c80, 0x10cb2,
+ 0x10cc0, 0x10cf2,
+ 0x10cfa, 0x10d27,
+ 0x10d30, 0x10d39,
+ 0x10e60, 0x10e7e,
+ 0x10e80, 0x10ea9,
+ 0x10eab, 0x10ead,
+ 0x10eb0, 0x10eb1,
+ 0x10f00, 0x10f27,
+ 0x10f30, 0x10f59,
+ 0x10f70, 0x10f89,
+ 0x10fb0, 0x10fcb,
+ 0x10fe0, 0x10ff6,
+ 0x11000, 0x1104d,
+ 0x11052, 0x11075,
+ 0x1107f, 0x110c2,
+ 0x110cd, 0x110cd,
+ 0x110d0, 0x110e8,
+ 0x110f0, 0x110f9,
+ 0x11100, 0x11134,
+ 0x11136, 0x11147,
+ 0x11150, 0x11176,
+ 0x11180, 0x111df,
+ 0x111e1, 0x111f4,
+ 0x11200, 0x11211,
+ 0x11213, 0x1123e,
+ 0x11280, 0x11286,
+ 0x11288, 0x11288,
+ 0x1128a, 0x1128d,
+ 0x1128f, 0x1129d,
+ 0x1129f, 0x112a9,
+ 0x112b0, 0x112ea,
+ 0x112f0, 0x112f9,
+ 0x11300, 0x11303,
+ 0x11305, 0x1130c,
+ 0x1130f, 0x11310,
+ 0x11313, 0x11328,
+ 0x1132a, 0x11330,
+ 0x11332, 0x11333,
+ 0x11335, 0x11339,
+ 0x1133b, 0x11344,
+ 0x11347, 0x11348,
+ 0x1134b, 0x1134d,
+ 0x11350, 0x11350,
+ 0x11357, 0x11357,
+ 0x1135d, 0x11363,
+ 0x11366, 0x1136c,
+ 0x11370, 0x11374,
+ 0x11400, 0x1145b,
+ 0x1145d, 0x11461,
+ 0x11480, 0x114c7,
+ 0x114d0, 0x114d9,
+ 0x11580, 0x115b5,
+ 0x115b8, 0x115dd,
+ 0x11600, 0x11644,
+ 0x11650, 0x11659,
+ 0x11660, 0x1166c,
+ 0x11680, 0x116b9,
+ 0x116c0, 0x116c9,
+ 0x11700, 0x1171a,
+ 0x1171d, 0x1172b,
+ 0x11730, 0x11746,
+ 0x11800, 0x1183b,
+ 0x118a0, 0x118f2,
+ 0x118ff, 0x11906,
+ 0x11909, 0x11909,
+ 0x1190c, 0x11913,
+ 0x11915, 0x11916,
+ 0x11918, 0x11935,
+ 0x11937, 0x11938,
+ 0x1193b, 0x11946,
+ 0x11950, 0x11959,
+ 0x119a0, 0x119a7,
+ 0x119aa, 0x119d7,
+ 0x119da, 0x119e4,
+ 0x11a00, 0x11a47,
+ 0x11a50, 0x11aa2,
+ 0x11ab0, 0x11af8,
+ 0x11c00, 0x11c08,
+ 0x11c0a, 0x11c36,
+ 0x11c38, 0x11c45,
+ 0x11c50, 0x11c6c,
+ 0x11c70, 0x11c8f,
+ 0x11c92, 0x11ca7,
+ 0x11ca9, 0x11cb6,
+ 0x11d00, 0x11d06,
+ 0x11d08, 0x11d09,
+ 0x11d0b, 0x11d36,
+ 0x11d3a, 0x11d3a,
+ 0x11d3c, 0x11d3d,
+ 0x11d3f, 0x11d47,
+ 0x11d50, 0x11d59,
+ 0x11d60, 0x11d65,
+ 0x11d67, 0x11d68,
+ 0x11d6a, 0x11d8e,
+ 0x11d90, 0x11d91,
+ 0x11d93, 0x11d98,
+ 0x11da0, 0x11da9,
+ 0x11ee0, 0x11ef8,
+ 0x11fb0, 0x11fb0,
+ 0x11fc0, 0x11ff1,
+ 0x11fff, 0x12399,
+ 0x12400, 0x1246e,
+ 0x12470, 0x12474,
+ 0x12480, 0x12543,
+ 0x12f90, 0x12ff2,
+ 0x13000, 0x1342e,
+ 0x13430, 0x13438,
+ 0x14400, 0x14646,
+ 0x16800, 0x16a38,
+ 0x16a40, 0x16a5e,
+ 0x16a60, 0x16a69,
+ 0x16a6e, 0x16abe,
+ 0x16ac0, 0x16ac9,
+ 0x16ad0, 0x16aed,
+ 0x16af0, 0x16af5,
+ 0x16b00, 0x16b45,
+ 0x16b50, 0x16b59,
+ 0x16b5b, 0x16b61,
+ 0x16b63, 0x16b77,
+ 0x16b7d, 0x16b8f,
+ 0x16e40, 0x16e9a,
+ 0x16f00, 0x16f4a,
+ 0x16f4f, 0x16f87,
+ 0x16f8f, 0x16f9f,
+ 0x16fe0, 0x16fe4,
+ 0x16ff0, 0x16ff1,
+ 0x17000, 0x187f7,
+ 0x18800, 0x18cd5,
+ 0x18d00, 0x18d08,
+ 0x1aff0, 0x1aff3,
+ 0x1aff5, 0x1affb,
+ 0x1affd, 0x1affe,
+ 0x1b000, 0x1b122,
+ 0x1b150, 0x1b152,
+ 0x1b164, 0x1b167,
+ 0x1b170, 0x1b2fb,
+ 0x1bc00, 0x1bc6a,
+ 0x1bc70, 0x1bc7c,
+ 0x1bc80, 0x1bc88,
+ 0x1bc90, 0x1bc99,
+ 0x1bc9c, 0x1bca3,
+ 0x1cf00, 0x1cf2d,
+ 0x1cf30, 0x1cf46,
+ 0x1cf50, 0x1cfc3,
+ 0x1d000, 0x1d0f5,
+ 0x1d100, 0x1d126,
+ 0x1d129, 0x1d1ea,
+ 0x1d200, 0x1d245,
+ 0x1d2e0, 0x1d2f3,
+ 0x1d300, 0x1d356,
+ 0x1d360, 0x1d378,
+ 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, 0x1d7cb,
+ 0x1d7ce, 0x1da8b,
+ 0x1da9b, 0x1da9f,
+ 0x1daa1, 0x1daaf,
+ 0x1df00, 0x1df1e,
+ 0x1e000, 0x1e006,
+ 0x1e008, 0x1e018,
+ 0x1e01b, 0x1e021,
+ 0x1e023, 0x1e024,
+ 0x1e026, 0x1e02a,
+ 0x1e100, 0x1e12c,
+ 0x1e130, 0x1e13d,
+ 0x1e140, 0x1e149,
+ 0x1e14e, 0x1e14f,
+ 0x1e290, 0x1e2ae,
+ 0x1e2c0, 0x1e2f9,
+ 0x1e2ff, 0x1e2ff,
+ 0x1e7e0, 0x1e7e6,
+ 0x1e7e8, 0x1e7eb,
+ 0x1e7ed, 0x1e7ee,
+ 0x1e7f0, 0x1e7fe,
+ 0x1e800, 0x1e8c4,
+ 0x1e8c7, 0x1e8d6,
+ 0x1e900, 0x1e94b,
+ 0x1e950, 0x1e959,
+ 0x1e95e, 0x1e95f,
+ 0x1ec71, 0x1ecb4,
+ 0x1ed01, 0x1ed3d,
+ 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,
+ 0x1eef0, 0x1eef1,
+ 0x1f000, 0x1f02b,
+ 0x1f030, 0x1f093,
+ 0x1f0a0, 0x1f0ae,
+ 0x1f0b1, 0x1f0bf,
+ 0x1f0c1, 0x1f0cf,
+ 0x1f0d1, 0x1f0f5,
+ 0x1f100, 0x1f1ad,
+ 0x1f1e6, 0x1f202,
+ 0x1f210, 0x1f23b,
+ 0x1f240, 0x1f248,
+ 0x1f250, 0x1f251,
+ 0x1f260, 0x1f265,
+ 0x1f300, 0x1f6d7,
+ 0x1f6dd, 0x1f6ec,
+ 0x1f6f0, 0x1f6fc,
+ 0x1f700, 0x1f773,
+ 0x1f780, 0x1f7d8,
+ 0x1f7e0, 0x1f7eb,
+ 0x1f7f0, 0x1f7f0,
+ 0x1f800, 0x1f80b,
+ 0x1f810, 0x1f847,
+ 0x1f850, 0x1f859,
+ 0x1f860, 0x1f887,
+ 0x1f890, 0x1f8ad,
+ 0x1f8b0, 0x1f8b1,
+ 0x1f900, 0x1fa53,
+ 0x1fa60, 0x1fa6d,
+ 0x1fa70, 0x1fa74,
+ 0x1fa78, 0x1fa7c,
+ 0x1fa80, 0x1fa86,
+ 0x1fa90, 0x1faac,
+ 0x1fab0, 0x1faba,
+ 0x1fac0, 0x1fac5,
+ 0x1fad0, 0x1fad9,
+ 0x1fae0, 0x1fae7,
+ 0x1faf0, 0x1faf6,
+ 0x1fb00, 0x1fb92,
+ 0x1fb94, 0x1fbca,
+ 0x1fbf0, 0x1fbf9,
+ 0x1fffe, 0x2a6df,
+ 0x2a700, 0x2b738,
+ 0x2b740, 0x2b81d,
+ 0x2b820, 0x2cea1,
+ 0x2ceb0, 0x2ebe0,
+ 0x2f800, 0x2fa1d,
+ 0x2fffe, 0x3134a,
+ 0x3fffe, 0x3ffff,
+ 0x4fffe, 0x4ffff,
+ 0x5fffe, 0x5ffff,
+ 0x6fffe, 0x6ffff,
+ 0x7fffe, 0x7ffff,
+ 0x8fffe, 0x8ffff,
+ 0x9fffe, 0x9ffff,
+ 0xafffe, 0xaffff,
+ 0xbfffe, 0xbffff,
+ 0xcfffe, 0xcffff,
+ 0xdfffe, 0xdffff,
+ 0xe0001, 0xe0001,
+ 0xe0020, 0xe007f,
+ 0xe0100, 0xe01ef,
+ 0xefffe, 0x10ffff,
+}; /* CR_Age_14_0 */
+
+/* 'Age_15_0': Derived Age 15.0 */
+static const OnigCodePoint CR_Age_15_0[] = {
+ 715,
+ 0x0000, 0x0377,
+ 0x037a, 0x037f,
+ 0x0384, 0x038a,
+ 0x038c, 0x038c,
+ 0x038e, 0x03a1,
+ 0x03a3, 0x052f,
+ 0x0531, 0x0556,
+ 0x0559, 0x058a,
+ 0x058d, 0x058f,
+ 0x0591, 0x05c7,
+ 0x05d0, 0x05ea,
+ 0x05ef, 0x05f4,
+ 0x0600, 0x070d,
+ 0x070f, 0x074a,
+ 0x074d, 0x07b1,
+ 0x07c0, 0x07fa,
+ 0x07fd, 0x082d,
+ 0x0830, 0x083e,
+ 0x0840, 0x085b,
+ 0x085e, 0x085e,
+ 0x0860, 0x086a,
+ 0x0870, 0x088e,
+ 0x0890, 0x0891,
+ 0x0898, 0x0983,
+ 0x0985, 0x098c,
+ 0x098f, 0x0990,
+ 0x0993, 0x09a8,
+ 0x09aa, 0x09b0,
+ 0x09b2, 0x09b2,
+ 0x09b6, 0x09b9,
+ 0x09bc, 0x09c4,
+ 0x09c7, 0x09c8,
+ 0x09cb, 0x09ce,
+ 0x09d7, 0x09d7,
+ 0x09dc, 0x09dd,
+ 0x09df, 0x09e3,
+ 0x09e6, 0x09fe,
+ 0x0a01, 0x0a03,
+ 0x0a05, 0x0a0a,
+ 0x0a0f, 0x0a10,
+ 0x0a13, 0x0a28,
+ 0x0a2a, 0x0a30,
+ 0x0a32, 0x0a33,
+ 0x0a35, 0x0a36,
+ 0x0a38, 0x0a39,
+ 0x0a3c, 0x0a3c,
+ 0x0a3e, 0x0a42,
+ 0x0a47, 0x0a48,
+ 0x0a4b, 0x0a4d,
+ 0x0a51, 0x0a51,
+ 0x0a59, 0x0a5c,
+ 0x0a5e, 0x0a5e,
+ 0x0a66, 0x0a76,
+ 0x0a81, 0x0a83,
+ 0x0a85, 0x0a8d,
+ 0x0a8f, 0x0a91,
+ 0x0a93, 0x0aa8,
+ 0x0aaa, 0x0ab0,
+ 0x0ab2, 0x0ab3,
+ 0x0ab5, 0x0ab9,
+ 0x0abc, 0x0ac5,
+ 0x0ac7, 0x0ac9,
+ 0x0acb, 0x0acd,
+ 0x0ad0, 0x0ad0,
+ 0x0ae0, 0x0ae3,
+ 0x0ae6, 0x0af1,
+ 0x0af9, 0x0aff,
+ 0x0b01, 0x0b03,
+ 0x0b05, 0x0b0c,
+ 0x0b0f, 0x0b10,
+ 0x0b13, 0x0b28,
+ 0x0b2a, 0x0b30,
+ 0x0b32, 0x0b33,
+ 0x0b35, 0x0b39,
+ 0x0b3c, 0x0b44,
+ 0x0b47, 0x0b48,
+ 0x0b4b, 0x0b4d,
+ 0x0b55, 0x0b57,
+ 0x0b5c, 0x0b5d,
+ 0x0b5f, 0x0b63,
+ 0x0b66, 0x0b77,
+ 0x0b82, 0x0b83,
+ 0x0b85, 0x0b8a,
+ 0x0b8e, 0x0b90,
+ 0x0b92, 0x0b95,
+ 0x0b99, 0x0b9a,
+ 0x0b9c, 0x0b9c,
+ 0x0b9e, 0x0b9f,
+ 0x0ba3, 0x0ba4,
+ 0x0ba8, 0x0baa,
+ 0x0bae, 0x0bb9,
+ 0x0bbe, 0x0bc2,
+ 0x0bc6, 0x0bc8,
+ 0x0bca, 0x0bcd,
+ 0x0bd0, 0x0bd0,
+ 0x0bd7, 0x0bd7,
+ 0x0be6, 0x0bfa,
+ 0x0c00, 0x0c0c,
+ 0x0c0e, 0x0c10,
+ 0x0c12, 0x0c28,
+ 0x0c2a, 0x0c39,
+ 0x0c3c, 0x0c44,
+ 0x0c46, 0x0c48,
+ 0x0c4a, 0x0c4d,
+ 0x0c55, 0x0c56,
+ 0x0c58, 0x0c5a,
+ 0x0c5d, 0x0c5d,
+ 0x0c60, 0x0c63,
+ 0x0c66, 0x0c6f,
+ 0x0c77, 0x0c8c,
+ 0x0c8e, 0x0c90,
+ 0x0c92, 0x0ca8,
+ 0x0caa, 0x0cb3,
+ 0x0cb5, 0x0cb9,
+ 0x0cbc, 0x0cc4,
+ 0x0cc6, 0x0cc8,
+ 0x0cca, 0x0ccd,
+ 0x0cd5, 0x0cd6,
+ 0x0cdd, 0x0cde,
+ 0x0ce0, 0x0ce3,
+ 0x0ce6, 0x0cef,
+ 0x0cf1, 0x0cf3,
+ 0x0d00, 0x0d0c,
+ 0x0d0e, 0x0d10,
+ 0x0d12, 0x0d44,
+ 0x0d46, 0x0d48,
+ 0x0d4a, 0x0d4f,
+ 0x0d54, 0x0d63,
+ 0x0d66, 0x0d7f,
+ 0x0d81, 0x0d83,
+ 0x0d85, 0x0d96,
+ 0x0d9a, 0x0db1,
+ 0x0db3, 0x0dbb,
+ 0x0dbd, 0x0dbd,
+ 0x0dc0, 0x0dc6,
+ 0x0dca, 0x0dca,
+ 0x0dcf, 0x0dd4,
+ 0x0dd6, 0x0dd6,
+ 0x0dd8, 0x0ddf,
+ 0x0de6, 0x0def,
+ 0x0df2, 0x0df4,
+ 0x0e01, 0x0e3a,
+ 0x0e3f, 0x0e5b,
+ 0x0e81, 0x0e82,
+ 0x0e84, 0x0e84,
+ 0x0e86, 0x0e8a,
+ 0x0e8c, 0x0ea3,
+ 0x0ea5, 0x0ea5,
+ 0x0ea7, 0x0ebd,
+ 0x0ec0, 0x0ec4,
+ 0x0ec6, 0x0ec6,
+ 0x0ec8, 0x0ece,
+ 0x0ed0, 0x0ed9,
+ 0x0edc, 0x0edf,
+ 0x0f00, 0x0f47,
+ 0x0f49, 0x0f6c,
+ 0x0f71, 0x0f97,
+ 0x0f99, 0x0fbc,
+ 0x0fbe, 0x0fcc,
+ 0x0fce, 0x0fda,
+ 0x1000, 0x10c5,
+ 0x10c7, 0x10c7,
+ 0x10cd, 0x10cd,
+ 0x10d0, 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,
+ 0x135d, 0x137c,
+ 0x1380, 0x1399,
+ 0x13a0, 0x13f5,
+ 0x13f8, 0x13fd,
+ 0x1400, 0x169c,
+ 0x16a0, 0x16f8,
+ 0x1700, 0x1715,
+ 0x171f, 0x1736,
+ 0x1740, 0x1753,
+ 0x1760, 0x176c,
+ 0x176e, 0x1770,
+ 0x1772, 0x1773,
+ 0x1780, 0x17dd,
+ 0x17e0, 0x17e9,
+ 0x17f0, 0x17f9,
+ 0x1800, 0x1819,
+ 0x1820, 0x1878,
+ 0x1880, 0x18aa,
+ 0x18b0, 0x18f5,
+ 0x1900, 0x191e,
+ 0x1920, 0x192b,
+ 0x1930, 0x193b,
+ 0x1940, 0x1940,
+ 0x1944, 0x196d,
+ 0x1970, 0x1974,
+ 0x1980, 0x19ab,
+ 0x19b0, 0x19c9,
+ 0x19d0, 0x19da,
+ 0x19de, 0x1a1b,
+ 0x1a1e, 0x1a5e,
+ 0x1a60, 0x1a7c,
+ 0x1a7f, 0x1a89,
+ 0x1a90, 0x1a99,
+ 0x1aa0, 0x1aad,
+ 0x1ab0, 0x1ace,
+ 0x1b00, 0x1b4c,
+ 0x1b50, 0x1b7e,
+ 0x1b80, 0x1bf3,
+ 0x1bfc, 0x1c37,
+ 0x1c3b, 0x1c49,
+ 0x1c4d, 0x1c88,
+ 0x1c90, 0x1cba,
+ 0x1cbd, 0x1cc7,
+ 0x1cd0, 0x1cfa,
+ 0x1d00, 0x1f15,
+ 0x1f18, 0x1f1d,
+ 0x1f20, 0x1f45,
+ 0x1f48, 0x1f4d,
+ 0x1f50, 0x1f57,
+ 0x1f59, 0x1f59,
+ 0x1f5b, 0x1f5b,
+ 0x1f5d, 0x1f5d,
+ 0x1f5f, 0x1f7d,
+ 0x1f80, 0x1fb4,
+ 0x1fb6, 0x1fc4,
+ 0x1fc6, 0x1fd3,
+ 0x1fd6, 0x1fdb,
+ 0x1fdd, 0x1fef,
+ 0x1ff2, 0x1ff4,
+ 0x1ff6, 0x1ffe,
+ 0x2000, 0x2064,
+ 0x2066, 0x2071,
+ 0x2074, 0x208e,
+ 0x2090, 0x209c,
+ 0x20a0, 0x20c0,
+ 0x20d0, 0x20f0,
+ 0x2100, 0x218b,
+ 0x2190, 0x2426,
+ 0x2440, 0x244a,
+ 0x2460, 0x2b73,
+ 0x2b76, 0x2b95,
+ 0x2b97, 0x2cf3,
+ 0x2cf9, 0x2d25,
+ 0x2d27, 0x2d27,
+ 0x2d2d, 0x2d2d,
+ 0x2d30, 0x2d67,
+ 0x2d6f, 0x2d70,
+ 0x2d7f, 0x2d96,
+ 0x2da0, 0x2da6,
+ 0x2da8, 0x2dae,
+ 0x2db0, 0x2db6,
+ 0x2db8, 0x2dbe,
+ 0x2dc0, 0x2dc6,
+ 0x2dc8, 0x2dce,
+ 0x2dd0, 0x2dd6,
+ 0x2dd8, 0x2dde,
+ 0x2de0, 0x2e5d,
+ 0x2e80, 0x2e99,
+ 0x2e9b, 0x2ef3,
+ 0x2f00, 0x2fd5,
+ 0x2ff0, 0x2ffb,
+ 0x3000, 0x303f,
+ 0x3041, 0x3096,
+ 0x3099, 0x30ff,
+ 0x3105, 0x312f,
+ 0x3131, 0x318e,
+ 0x3190, 0x31e3,
+ 0x31f0, 0x321e,
+ 0x3220, 0xa48c,
+ 0xa490, 0xa4c6,
+ 0xa4d0, 0xa62b,
+ 0xa640, 0xa6f7,
+ 0xa700, 0xa7ca,
+ 0xa7d0, 0xa7d1,
+ 0xa7d3, 0xa7d3,
+ 0xa7d5, 0xa7d9,
+ 0xa7f2, 0xa82c,
+ 0xa830, 0xa839,
+ 0xa840, 0xa877,
+ 0xa880, 0xa8c5,
+ 0xa8ce, 0xa8d9,
+ 0xa8e0, 0xa953,
+ 0xa95f, 0xa97c,
+ 0xa980, 0xa9cd,
+ 0xa9cf, 0xa9d9,
+ 0xa9de, 0xa9fe,
+ 0xaa00, 0xaa36,
+ 0xaa40, 0xaa4d,
+ 0xaa50, 0xaa59,
+ 0xaa5c, 0xaac2,
+ 0xaadb, 0xaaf6,
+ 0xab01, 0xab06,
+ 0xab09, 0xab0e,
+ 0xab11, 0xab16,
+ 0xab20, 0xab26,
+ 0xab28, 0xab2e,
+ 0xab30, 0xab6b,
+ 0xab70, 0xabed,
+ 0xabf0, 0xabf9,
+ 0xac00, 0xd7a3,
+ 0xd7b0, 0xd7c6,
+ 0xd7cb, 0xd7fb,
+ 0xd800, 0xfa6d,
+ 0xfa70, 0xfad9,
+ 0xfb00, 0xfb06,
+ 0xfb13, 0xfb17,
+ 0xfb1d, 0xfb36,
+ 0xfb38, 0xfb3c,
+ 0xfb3e, 0xfb3e,
+ 0xfb40, 0xfb41,
+ 0xfb43, 0xfb44,
+ 0xfb46, 0xfbc2,
+ 0xfbd3, 0xfd8f,
+ 0xfd92, 0xfdc7,
+ 0xfdcf, 0xfe19,
+ 0xfe20, 0xfe52,
+ 0xfe54, 0xfe66,
+ 0xfe68, 0xfe6b,
+ 0xfe70, 0xfe74,
+ 0xfe76, 0xfefc,
+ 0xfeff, 0xfeff,
+ 0xff01, 0xffbe,
+ 0xffc2, 0xffc7,
+ 0xffca, 0xffcf,
+ 0xffd2, 0xffd7,
+ 0xffda, 0xffdc,
+ 0xffe0, 0xffe6,
+ 0xffe8, 0xffee,
+ 0xfff9, 0x1000b,
+ 0x1000d, 0x10026,
+ 0x10028, 0x1003a,
+ 0x1003c, 0x1003d,
+ 0x1003f, 0x1004d,
+ 0x10050, 0x1005d,
+ 0x10080, 0x100fa,
+ 0x10100, 0x10102,
+ 0x10107, 0x10133,
+ 0x10137, 0x1018e,
+ 0x10190, 0x1019c,
+ 0x101a0, 0x101a0,
+ 0x101d0, 0x101fd,
+ 0x10280, 0x1029c,
+ 0x102a0, 0x102d0,
+ 0x102e0, 0x102fb,
+ 0x10300, 0x10323,
+ 0x1032d, 0x1034a,
+ 0x10350, 0x1037a,
+ 0x10380, 0x1039d,
+ 0x1039f, 0x103c3,
+ 0x103c8, 0x103d5,
+ 0x10400, 0x1049d,
+ 0x104a0, 0x104a9,
+ 0x104b0, 0x104d3,
+ 0x104d8, 0x104fb,
+ 0x10500, 0x10527,
+ 0x10530, 0x10563,
+ 0x1056f, 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,
+ 0x10857, 0x1089e,
+ 0x108a7, 0x108af,
+ 0x108e0, 0x108f2,
+ 0x108f4, 0x108f5,
+ 0x108fb, 0x1091b,
+ 0x1091f, 0x10939,
+ 0x1093f, 0x1093f,
+ 0x10980, 0x109b7,
+ 0x109bc, 0x109cf,
+ 0x109d2, 0x10a03,
+ 0x10a05, 0x10a06,
+ 0x10a0c, 0x10a13,
+ 0x10a15, 0x10a17,
+ 0x10a19, 0x10a35,
+ 0x10a38, 0x10a3a,
+ 0x10a3f, 0x10a48,
+ 0x10a50, 0x10a58,
+ 0x10a60, 0x10a9f,
+ 0x10ac0, 0x10ae6,
+ 0x10aeb, 0x10af6,
+ 0x10b00, 0x10b35,
+ 0x10b39, 0x10b55,
+ 0x10b58, 0x10b72,
+ 0x10b78, 0x10b91,
+ 0x10b99, 0x10b9c,
+ 0x10ba9, 0x10baf,
+ 0x10c00, 0x10c48,
+ 0x10c80, 0x10cb2,
+ 0x10cc0, 0x10cf2,
+ 0x10cfa, 0x10d27,
+ 0x10d30, 0x10d39,
+ 0x10e60, 0x10e7e,
+ 0x10e80, 0x10ea9,
+ 0x10eab, 0x10ead,
+ 0x10eb0, 0x10eb1,
+ 0x10efd, 0x10f27,
+ 0x10f30, 0x10f59,
+ 0x10f70, 0x10f89,
+ 0x10fb0, 0x10fcb,
+ 0x10fe0, 0x10ff6,
+ 0x11000, 0x1104d,
+ 0x11052, 0x11075,
+ 0x1107f, 0x110c2,
+ 0x110cd, 0x110cd,
+ 0x110d0, 0x110e8,
+ 0x110f0, 0x110f9,
+ 0x11100, 0x11134,
+ 0x11136, 0x11147,
+ 0x11150, 0x11176,
+ 0x11180, 0x111df,
+ 0x111e1, 0x111f4,
+ 0x11200, 0x11211,
+ 0x11213, 0x11241,
+ 0x11280, 0x11286,
+ 0x11288, 0x11288,
+ 0x1128a, 0x1128d,
+ 0x1128f, 0x1129d,
+ 0x1129f, 0x112a9,
+ 0x112b0, 0x112ea,
+ 0x112f0, 0x112f9,
+ 0x11300, 0x11303,
+ 0x11305, 0x1130c,
+ 0x1130f, 0x11310,
+ 0x11313, 0x11328,
+ 0x1132a, 0x11330,
+ 0x11332, 0x11333,
+ 0x11335, 0x11339,
+ 0x1133b, 0x11344,
+ 0x11347, 0x11348,
+ 0x1134b, 0x1134d,
+ 0x11350, 0x11350,
+ 0x11357, 0x11357,
+ 0x1135d, 0x11363,
+ 0x11366, 0x1136c,
+ 0x11370, 0x11374,
+ 0x11400, 0x1145b,
+ 0x1145d, 0x11461,
+ 0x11480, 0x114c7,
+ 0x114d0, 0x114d9,
+ 0x11580, 0x115b5,
+ 0x115b8, 0x115dd,
+ 0x11600, 0x11644,
+ 0x11650, 0x11659,
+ 0x11660, 0x1166c,
+ 0x11680, 0x116b9,
+ 0x116c0, 0x116c9,
+ 0x11700, 0x1171a,
+ 0x1171d, 0x1172b,
+ 0x11730, 0x11746,
+ 0x11800, 0x1183b,
+ 0x118a0, 0x118f2,
+ 0x118ff, 0x11906,
+ 0x11909, 0x11909,
+ 0x1190c, 0x11913,
+ 0x11915, 0x11916,
+ 0x11918, 0x11935,
+ 0x11937, 0x11938,
+ 0x1193b, 0x11946,
+ 0x11950, 0x11959,
+ 0x119a0, 0x119a7,
+ 0x119aa, 0x119d7,
+ 0x119da, 0x119e4,
+ 0x11a00, 0x11a47,
+ 0x11a50, 0x11aa2,
+ 0x11ab0, 0x11af8,
+ 0x11b00, 0x11b09,
+ 0x11c00, 0x11c08,
+ 0x11c0a, 0x11c36,
+ 0x11c38, 0x11c45,
+ 0x11c50, 0x11c6c,
+ 0x11c70, 0x11c8f,
+ 0x11c92, 0x11ca7,
+ 0x11ca9, 0x11cb6,
+ 0x11d00, 0x11d06,
+ 0x11d08, 0x11d09,
+ 0x11d0b, 0x11d36,
+ 0x11d3a, 0x11d3a,
+ 0x11d3c, 0x11d3d,
+ 0x11d3f, 0x11d47,
+ 0x11d50, 0x11d59,
+ 0x11d60, 0x11d65,
+ 0x11d67, 0x11d68,
+ 0x11d6a, 0x11d8e,
+ 0x11d90, 0x11d91,
+ 0x11d93, 0x11d98,
+ 0x11da0, 0x11da9,
+ 0x11ee0, 0x11ef8,
+ 0x11f00, 0x11f10,
+ 0x11f12, 0x11f3a,
+ 0x11f3e, 0x11f59,
+ 0x11fb0, 0x11fb0,
+ 0x11fc0, 0x11ff1,
+ 0x11fff, 0x12399,
+ 0x12400, 0x1246e,
+ 0x12470, 0x12474,
+ 0x12480, 0x12543,
+ 0x12f90, 0x12ff2,
+ 0x13000, 0x13455,
+ 0x14400, 0x14646,
+ 0x16800, 0x16a38,
+ 0x16a40, 0x16a5e,
+ 0x16a60, 0x16a69,
+ 0x16a6e, 0x16abe,
+ 0x16ac0, 0x16ac9,
+ 0x16ad0, 0x16aed,
+ 0x16af0, 0x16af5,
+ 0x16b00, 0x16b45,
+ 0x16b50, 0x16b59,
+ 0x16b5b, 0x16b61,
+ 0x16b63, 0x16b77,
+ 0x16b7d, 0x16b8f,
+ 0x16e40, 0x16e9a,
+ 0x16f00, 0x16f4a,
+ 0x16f4f, 0x16f87,
+ 0x16f8f, 0x16f9f,
+ 0x16fe0, 0x16fe4,
+ 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,
+ 0x1bc9c, 0x1bca3,
+ 0x1cf00, 0x1cf2d,
+ 0x1cf30, 0x1cf46,
+ 0x1cf50, 0x1cfc3,
+ 0x1d000, 0x1d0f5,
+ 0x1d100, 0x1d126,
+ 0x1d129, 0x1d1ea,
+ 0x1d200, 0x1d245,
+ 0x1d2c0, 0x1d2d3,
+ 0x1d2e0, 0x1d2f3,
+ 0x1d300, 0x1d356,
+ 0x1d360, 0x1d378,
+ 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, 0x1d7cb,
+ 0x1d7ce, 0x1da8b,
+ 0x1da9b, 0x1da9f,
+ 0x1daa1, 0x1daaf,
+ 0x1df00, 0x1df1e,
+ 0x1df25, 0x1df2a,
+ 0x1e000, 0x1e006,
+ 0x1e008, 0x1e018,
+ 0x1e01b, 0x1e021,
+ 0x1e023, 0x1e024,
+ 0x1e026, 0x1e02a,
+ 0x1e030, 0x1e06d,
+ 0x1e08f, 0x1e08f,
+ 0x1e100, 0x1e12c,
+ 0x1e130, 0x1e13d,
+ 0x1e140, 0x1e149,
+ 0x1e14e, 0x1e14f,
+ 0x1e290, 0x1e2ae,
+ 0x1e2c0, 0x1e2f9,
+ 0x1e2ff, 0x1e2ff,
+ 0x1e4d0, 0x1e4f9,
+ 0x1e7e0, 0x1e7e6,
+ 0x1e7e8, 0x1e7eb,
+ 0x1e7ed, 0x1e7ee,
+ 0x1e7f0, 0x1e7fe,
+ 0x1e800, 0x1e8c4,
+ 0x1e8c7, 0x1e8d6,
+ 0x1e900, 0x1e94b,
+ 0x1e950, 0x1e959,
+ 0x1e95e, 0x1e95f,
+ 0x1ec71, 0x1ecb4,
+ 0x1ed01, 0x1ed3d,
+ 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,
+ 0x1eef0, 0x1eef1,
+ 0x1f000, 0x1f02b,
+ 0x1f030, 0x1f093,
+ 0x1f0a0, 0x1f0ae,
+ 0x1f0b1, 0x1f0bf,
+ 0x1f0c1, 0x1f0cf,
+ 0x1f0d1, 0x1f0f5,
+ 0x1f100, 0x1f1ad,
+ 0x1f1e6, 0x1f202,
+ 0x1f210, 0x1f23b,
+ 0x1f240, 0x1f248,
+ 0x1f250, 0x1f251,
+ 0x1f260, 0x1f265,
+ 0x1f300, 0x1f6d7,
+ 0x1f6dc, 0x1f6ec,
+ 0x1f6f0, 0x1f6fc,
+ 0x1f700, 0x1f776,
+ 0x1f77b, 0x1f7d9,
+ 0x1f7e0, 0x1f7eb,
+ 0x1f7f0, 0x1f7f0,
+ 0x1f800, 0x1f80b,
+ 0x1f810, 0x1f847,
+ 0x1f850, 0x1f859,
+ 0x1f860, 0x1f887,
+ 0x1f890, 0x1f8ad,
+ 0x1f8b0, 0x1f8b1,
+ 0x1f900, 0x1fa53,
+ 0x1fa60, 0x1fa6d,
+ 0x1fa70, 0x1fa7c,
+ 0x1fa80, 0x1fa88,
+ 0x1fa90, 0x1fabd,
+ 0x1fabf, 0x1fac5,
+ 0x1face, 0x1fadb,
+ 0x1fae0, 0x1fae8,
+ 0x1faf0, 0x1faf8,
+ 0x1fb00, 0x1fb92,
+ 0x1fb94, 0x1fbca,
+ 0x1fbf0, 0x1fbf9,
+ 0x1fffe, 0x2a6df,
+ 0x2a700, 0x2b739,
+ 0x2b740, 0x2b81d,
+ 0x2b820, 0x2cea1,
+ 0x2ceb0, 0x2ebe0,
+ 0x2f800, 0x2fa1d,
+ 0x2fffe, 0x3134a,
+ 0x31350, 0x323af,
+ 0x3fffe, 0x3ffff,
+ 0x4fffe, 0x4ffff,
+ 0x5fffe, 0x5ffff,
+ 0x6fffe, 0x6ffff,
+ 0x7fffe, 0x7ffff,
+ 0x8fffe, 0x8ffff,
+ 0x9fffe, 0x9ffff,
+ 0xafffe, 0xaffff,
+ 0xbfffe, 0xbffff,
+ 0xcfffe, 0xcffff,
+ 0xdfffe, 0xdffff,
+ 0xe0001, 0xe0001,
+ 0xe0020, 0xe007f,
+ 0xe0100, 0xe01ef,
+ 0xefffe, 0x10ffff,
+}; /* CR_Age_15_0 */
+
+/* 'Age_15_1': Derived Age 15.1 */
+static const OnigCodePoint CR_Age_15_1[] = {
+ 715,
+ 0x0000, 0x0377,
+ 0x037a, 0x037f,
+ 0x0384, 0x038a,
+ 0x038c, 0x038c,
+ 0x038e, 0x03a1,
+ 0x03a3, 0x052f,
+ 0x0531, 0x0556,
+ 0x0559, 0x058a,
+ 0x058d, 0x058f,
+ 0x0591, 0x05c7,
+ 0x05d0, 0x05ea,
+ 0x05ef, 0x05f4,
+ 0x0600, 0x070d,
+ 0x070f, 0x074a,
+ 0x074d, 0x07b1,
+ 0x07c0, 0x07fa,
+ 0x07fd, 0x082d,
+ 0x0830, 0x083e,
+ 0x0840, 0x085b,
+ 0x085e, 0x085e,
+ 0x0860, 0x086a,
+ 0x0870, 0x088e,
+ 0x0890, 0x0891,
+ 0x0898, 0x0983,
+ 0x0985, 0x098c,
+ 0x098f, 0x0990,
+ 0x0993, 0x09a8,
+ 0x09aa, 0x09b0,
+ 0x09b2, 0x09b2,
+ 0x09b6, 0x09b9,
+ 0x09bc, 0x09c4,
+ 0x09c7, 0x09c8,
+ 0x09cb, 0x09ce,
+ 0x09d7, 0x09d7,
+ 0x09dc, 0x09dd,
+ 0x09df, 0x09e3,
+ 0x09e6, 0x09fe,
+ 0x0a01, 0x0a03,
+ 0x0a05, 0x0a0a,
+ 0x0a0f, 0x0a10,
+ 0x0a13, 0x0a28,
+ 0x0a2a, 0x0a30,
+ 0x0a32, 0x0a33,
+ 0x0a35, 0x0a36,
+ 0x0a38, 0x0a39,
+ 0x0a3c, 0x0a3c,
+ 0x0a3e, 0x0a42,
+ 0x0a47, 0x0a48,
+ 0x0a4b, 0x0a4d,
+ 0x0a51, 0x0a51,
+ 0x0a59, 0x0a5c,
+ 0x0a5e, 0x0a5e,
+ 0x0a66, 0x0a76,
+ 0x0a81, 0x0a83,
+ 0x0a85, 0x0a8d,
+ 0x0a8f, 0x0a91,
+ 0x0a93, 0x0aa8,
+ 0x0aaa, 0x0ab0,
+ 0x0ab2, 0x0ab3,
+ 0x0ab5, 0x0ab9,
+ 0x0abc, 0x0ac5,
+ 0x0ac7, 0x0ac9,
+ 0x0acb, 0x0acd,
+ 0x0ad0, 0x0ad0,
+ 0x0ae0, 0x0ae3,
+ 0x0ae6, 0x0af1,
+ 0x0af9, 0x0aff,
+ 0x0b01, 0x0b03,
+ 0x0b05, 0x0b0c,
+ 0x0b0f, 0x0b10,
+ 0x0b13, 0x0b28,
+ 0x0b2a, 0x0b30,
+ 0x0b32, 0x0b33,
+ 0x0b35, 0x0b39,
+ 0x0b3c, 0x0b44,
+ 0x0b47, 0x0b48,
+ 0x0b4b, 0x0b4d,
+ 0x0b55, 0x0b57,
+ 0x0b5c, 0x0b5d,
+ 0x0b5f, 0x0b63,
+ 0x0b66, 0x0b77,
+ 0x0b82, 0x0b83,
+ 0x0b85, 0x0b8a,
+ 0x0b8e, 0x0b90,
+ 0x0b92, 0x0b95,
+ 0x0b99, 0x0b9a,
+ 0x0b9c, 0x0b9c,
+ 0x0b9e, 0x0b9f,
+ 0x0ba3, 0x0ba4,
+ 0x0ba8, 0x0baa,
+ 0x0bae, 0x0bb9,
+ 0x0bbe, 0x0bc2,
+ 0x0bc6, 0x0bc8,
+ 0x0bca, 0x0bcd,
+ 0x0bd0, 0x0bd0,
+ 0x0bd7, 0x0bd7,
+ 0x0be6, 0x0bfa,
+ 0x0c00, 0x0c0c,
+ 0x0c0e, 0x0c10,
+ 0x0c12, 0x0c28,
+ 0x0c2a, 0x0c39,
+ 0x0c3c, 0x0c44,
+ 0x0c46, 0x0c48,
+ 0x0c4a, 0x0c4d,
+ 0x0c55, 0x0c56,
+ 0x0c58, 0x0c5a,
+ 0x0c5d, 0x0c5d,
+ 0x0c60, 0x0c63,
+ 0x0c66, 0x0c6f,
+ 0x0c77, 0x0c8c,
+ 0x0c8e, 0x0c90,
+ 0x0c92, 0x0ca8,
+ 0x0caa, 0x0cb3,
+ 0x0cb5, 0x0cb9,
+ 0x0cbc, 0x0cc4,
+ 0x0cc6, 0x0cc8,
+ 0x0cca, 0x0ccd,
+ 0x0cd5, 0x0cd6,
+ 0x0cdd, 0x0cde,
+ 0x0ce0, 0x0ce3,
+ 0x0ce6, 0x0cef,
+ 0x0cf1, 0x0cf3,
+ 0x0d00, 0x0d0c,
+ 0x0d0e, 0x0d10,
+ 0x0d12, 0x0d44,
+ 0x0d46, 0x0d48,
+ 0x0d4a, 0x0d4f,
+ 0x0d54, 0x0d63,
+ 0x0d66, 0x0d7f,
+ 0x0d81, 0x0d83,
+ 0x0d85, 0x0d96,
+ 0x0d9a, 0x0db1,
+ 0x0db3, 0x0dbb,
+ 0x0dbd, 0x0dbd,
+ 0x0dc0, 0x0dc6,
+ 0x0dca, 0x0dca,
+ 0x0dcf, 0x0dd4,
+ 0x0dd6, 0x0dd6,
+ 0x0dd8, 0x0ddf,
+ 0x0de6, 0x0def,
+ 0x0df2, 0x0df4,
+ 0x0e01, 0x0e3a,
+ 0x0e3f, 0x0e5b,
+ 0x0e81, 0x0e82,
+ 0x0e84, 0x0e84,
+ 0x0e86, 0x0e8a,
+ 0x0e8c, 0x0ea3,
+ 0x0ea5, 0x0ea5,
+ 0x0ea7, 0x0ebd,
+ 0x0ec0, 0x0ec4,
+ 0x0ec6, 0x0ec6,
+ 0x0ec8, 0x0ece,
+ 0x0ed0, 0x0ed9,
+ 0x0edc, 0x0edf,
+ 0x0f00, 0x0f47,
+ 0x0f49, 0x0f6c,
+ 0x0f71, 0x0f97,
+ 0x0f99, 0x0fbc,
+ 0x0fbe, 0x0fcc,
+ 0x0fce, 0x0fda,
+ 0x1000, 0x10c5,
+ 0x10c7, 0x10c7,
+ 0x10cd, 0x10cd,
+ 0x10d0, 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,
+ 0x135d, 0x137c,
+ 0x1380, 0x1399,
+ 0x13a0, 0x13f5,
+ 0x13f8, 0x13fd,
+ 0x1400, 0x169c,
+ 0x16a0, 0x16f8,
+ 0x1700, 0x1715,
+ 0x171f, 0x1736,
+ 0x1740, 0x1753,
+ 0x1760, 0x176c,
+ 0x176e, 0x1770,
+ 0x1772, 0x1773,
+ 0x1780, 0x17dd,
+ 0x17e0, 0x17e9,
+ 0x17f0, 0x17f9,
+ 0x1800, 0x1819,
+ 0x1820, 0x1878,
+ 0x1880, 0x18aa,
+ 0x18b0, 0x18f5,
+ 0x1900, 0x191e,
+ 0x1920, 0x192b,
+ 0x1930, 0x193b,
+ 0x1940, 0x1940,
+ 0x1944, 0x196d,
+ 0x1970, 0x1974,
+ 0x1980, 0x19ab,
+ 0x19b0, 0x19c9,
+ 0x19d0, 0x19da,
+ 0x19de, 0x1a1b,
+ 0x1a1e, 0x1a5e,
+ 0x1a60, 0x1a7c,
+ 0x1a7f, 0x1a89,
+ 0x1a90, 0x1a99,
+ 0x1aa0, 0x1aad,
+ 0x1ab0, 0x1ace,
+ 0x1b00, 0x1b4c,
+ 0x1b50, 0x1b7e,
+ 0x1b80, 0x1bf3,
+ 0x1bfc, 0x1c37,
+ 0x1c3b, 0x1c49,
+ 0x1c4d, 0x1c88,
+ 0x1c90, 0x1cba,
+ 0x1cbd, 0x1cc7,
+ 0x1cd0, 0x1cfa,
+ 0x1d00, 0x1f15,
+ 0x1f18, 0x1f1d,
+ 0x1f20, 0x1f45,
+ 0x1f48, 0x1f4d,
+ 0x1f50, 0x1f57,
+ 0x1f59, 0x1f59,
+ 0x1f5b, 0x1f5b,
+ 0x1f5d, 0x1f5d,
+ 0x1f5f, 0x1f7d,
+ 0x1f80, 0x1fb4,
+ 0x1fb6, 0x1fc4,
+ 0x1fc6, 0x1fd3,
+ 0x1fd6, 0x1fdb,
+ 0x1fdd, 0x1fef,
+ 0x1ff2, 0x1ff4,
+ 0x1ff6, 0x1ffe,
+ 0x2000, 0x2064,
+ 0x2066, 0x2071,
+ 0x2074, 0x208e,
+ 0x2090, 0x209c,
+ 0x20a0, 0x20c0,
+ 0x20d0, 0x20f0,
+ 0x2100, 0x218b,
+ 0x2190, 0x2426,
+ 0x2440, 0x244a,
+ 0x2460, 0x2b73,
+ 0x2b76, 0x2b95,
+ 0x2b97, 0x2cf3,
+ 0x2cf9, 0x2d25,
+ 0x2d27, 0x2d27,
+ 0x2d2d, 0x2d2d,
+ 0x2d30, 0x2d67,
+ 0x2d6f, 0x2d70,
+ 0x2d7f, 0x2d96,
+ 0x2da0, 0x2da6,
+ 0x2da8, 0x2dae,
+ 0x2db0, 0x2db6,
+ 0x2db8, 0x2dbe,
+ 0x2dc0, 0x2dc6,
+ 0x2dc8, 0x2dce,
+ 0x2dd0, 0x2dd6,
+ 0x2dd8, 0x2dde,
+ 0x2de0, 0x2e5d,
+ 0x2e80, 0x2e99,
+ 0x2e9b, 0x2ef3,
+ 0x2f00, 0x2fd5,
+ 0x2ff0, 0x303f,
+ 0x3041, 0x3096,
+ 0x3099, 0x30ff,
+ 0x3105, 0x312f,
+ 0x3131, 0x318e,
+ 0x3190, 0x31e3,
+ 0x31ef, 0x321e,
+ 0x3220, 0xa48c,
+ 0xa490, 0xa4c6,
+ 0xa4d0, 0xa62b,
+ 0xa640, 0xa6f7,
+ 0xa700, 0xa7ca,
+ 0xa7d0, 0xa7d1,
+ 0xa7d3, 0xa7d3,
+ 0xa7d5, 0xa7d9,
+ 0xa7f2, 0xa82c,
+ 0xa830, 0xa839,
+ 0xa840, 0xa877,
+ 0xa880, 0xa8c5,
+ 0xa8ce, 0xa8d9,
+ 0xa8e0, 0xa953,
+ 0xa95f, 0xa97c,
+ 0xa980, 0xa9cd,
+ 0xa9cf, 0xa9d9,
+ 0xa9de, 0xa9fe,
+ 0xaa00, 0xaa36,
+ 0xaa40, 0xaa4d,
+ 0xaa50, 0xaa59,
+ 0xaa5c, 0xaac2,
+ 0xaadb, 0xaaf6,
+ 0xab01, 0xab06,
+ 0xab09, 0xab0e,
+ 0xab11, 0xab16,
+ 0xab20, 0xab26,
+ 0xab28, 0xab2e,
+ 0xab30, 0xab6b,
+ 0xab70, 0xabed,
+ 0xabf0, 0xabf9,
+ 0xac00, 0xd7a3,
+ 0xd7b0, 0xd7c6,
+ 0xd7cb, 0xd7fb,
+ 0xd800, 0xfa6d,
+ 0xfa70, 0xfad9,
+ 0xfb00, 0xfb06,
+ 0xfb13, 0xfb17,
+ 0xfb1d, 0xfb36,
+ 0xfb38, 0xfb3c,
+ 0xfb3e, 0xfb3e,
+ 0xfb40, 0xfb41,
+ 0xfb43, 0xfb44,
+ 0xfb46, 0xfbc2,
+ 0xfbd3, 0xfd8f,
+ 0xfd92, 0xfdc7,
+ 0xfdcf, 0xfe19,
+ 0xfe20, 0xfe52,
+ 0xfe54, 0xfe66,
+ 0xfe68, 0xfe6b,
+ 0xfe70, 0xfe74,
+ 0xfe76, 0xfefc,
+ 0xfeff, 0xfeff,
+ 0xff01, 0xffbe,
+ 0xffc2, 0xffc7,
+ 0xffca, 0xffcf,
+ 0xffd2, 0xffd7,
+ 0xffda, 0xffdc,
+ 0xffe0, 0xffe6,
+ 0xffe8, 0xffee,
+ 0xfff9, 0x1000b,
+ 0x1000d, 0x10026,
+ 0x10028, 0x1003a,
+ 0x1003c, 0x1003d,
+ 0x1003f, 0x1004d,
+ 0x10050, 0x1005d,
+ 0x10080, 0x100fa,
+ 0x10100, 0x10102,
+ 0x10107, 0x10133,
+ 0x10137, 0x1018e,
+ 0x10190, 0x1019c,
+ 0x101a0, 0x101a0,
+ 0x101d0, 0x101fd,
+ 0x10280, 0x1029c,
+ 0x102a0, 0x102d0,
+ 0x102e0, 0x102fb,
+ 0x10300, 0x10323,
+ 0x1032d, 0x1034a,
+ 0x10350, 0x1037a,
+ 0x10380, 0x1039d,
+ 0x1039f, 0x103c3,
+ 0x103c8, 0x103d5,
+ 0x10400, 0x1049d,
+ 0x104a0, 0x104a9,
+ 0x104b0, 0x104d3,
+ 0x104d8, 0x104fb,
+ 0x10500, 0x10527,
+ 0x10530, 0x10563,
+ 0x1056f, 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,
+ 0x10857, 0x1089e,
+ 0x108a7, 0x108af,
+ 0x108e0, 0x108f2,
+ 0x108f4, 0x108f5,
+ 0x108fb, 0x1091b,
+ 0x1091f, 0x10939,
+ 0x1093f, 0x1093f,
+ 0x10980, 0x109b7,
+ 0x109bc, 0x109cf,
+ 0x109d2, 0x10a03,
+ 0x10a05, 0x10a06,
+ 0x10a0c, 0x10a13,
+ 0x10a15, 0x10a17,
+ 0x10a19, 0x10a35,
+ 0x10a38, 0x10a3a,
+ 0x10a3f, 0x10a48,
+ 0x10a50, 0x10a58,
+ 0x10a60, 0x10a9f,
+ 0x10ac0, 0x10ae6,
+ 0x10aeb, 0x10af6,
+ 0x10b00, 0x10b35,
+ 0x10b39, 0x10b55,
+ 0x10b58, 0x10b72,
+ 0x10b78, 0x10b91,
+ 0x10b99, 0x10b9c,
+ 0x10ba9, 0x10baf,
+ 0x10c00, 0x10c48,
+ 0x10c80, 0x10cb2,
+ 0x10cc0, 0x10cf2,
+ 0x10cfa, 0x10d27,
+ 0x10d30, 0x10d39,
+ 0x10e60, 0x10e7e,
+ 0x10e80, 0x10ea9,
+ 0x10eab, 0x10ead,
+ 0x10eb0, 0x10eb1,
+ 0x10efd, 0x10f27,
+ 0x10f30, 0x10f59,
+ 0x10f70, 0x10f89,
+ 0x10fb0, 0x10fcb,
+ 0x10fe0, 0x10ff6,
+ 0x11000, 0x1104d,
+ 0x11052, 0x11075,
+ 0x1107f, 0x110c2,
+ 0x110cd, 0x110cd,
+ 0x110d0, 0x110e8,
+ 0x110f0, 0x110f9,
+ 0x11100, 0x11134,
+ 0x11136, 0x11147,
+ 0x11150, 0x11176,
+ 0x11180, 0x111df,
+ 0x111e1, 0x111f4,
+ 0x11200, 0x11211,
+ 0x11213, 0x11241,
+ 0x11280, 0x11286,
+ 0x11288, 0x11288,
+ 0x1128a, 0x1128d,
+ 0x1128f, 0x1129d,
+ 0x1129f, 0x112a9,
+ 0x112b0, 0x112ea,
+ 0x112f0, 0x112f9,
+ 0x11300, 0x11303,
+ 0x11305, 0x1130c,
+ 0x1130f, 0x11310,
+ 0x11313, 0x11328,
+ 0x1132a, 0x11330,
+ 0x11332, 0x11333,
+ 0x11335, 0x11339,
+ 0x1133b, 0x11344,
+ 0x11347, 0x11348,
+ 0x1134b, 0x1134d,
+ 0x11350, 0x11350,
+ 0x11357, 0x11357,
+ 0x1135d, 0x11363,
+ 0x11366, 0x1136c,
+ 0x11370, 0x11374,
+ 0x11400, 0x1145b,
+ 0x1145d, 0x11461,
+ 0x11480, 0x114c7,
+ 0x114d0, 0x114d9,
+ 0x11580, 0x115b5,
+ 0x115b8, 0x115dd,
+ 0x11600, 0x11644,
+ 0x11650, 0x11659,
+ 0x11660, 0x1166c,
+ 0x11680, 0x116b9,
+ 0x116c0, 0x116c9,
+ 0x11700, 0x1171a,
+ 0x1171d, 0x1172b,
+ 0x11730, 0x11746,
+ 0x11800, 0x1183b,
+ 0x118a0, 0x118f2,
+ 0x118ff, 0x11906,
+ 0x11909, 0x11909,
+ 0x1190c, 0x11913,
+ 0x11915, 0x11916,
+ 0x11918, 0x11935,
+ 0x11937, 0x11938,
+ 0x1193b, 0x11946,
+ 0x11950, 0x11959,
+ 0x119a0, 0x119a7,
+ 0x119aa, 0x119d7,
+ 0x119da, 0x119e4,
+ 0x11a00, 0x11a47,
+ 0x11a50, 0x11aa2,
+ 0x11ab0, 0x11af8,
+ 0x11b00, 0x11b09,
+ 0x11c00, 0x11c08,
+ 0x11c0a, 0x11c36,
+ 0x11c38, 0x11c45,
+ 0x11c50, 0x11c6c,
+ 0x11c70, 0x11c8f,
+ 0x11c92, 0x11ca7,
+ 0x11ca9, 0x11cb6,
+ 0x11d00, 0x11d06,
+ 0x11d08, 0x11d09,
+ 0x11d0b, 0x11d36,
+ 0x11d3a, 0x11d3a,
+ 0x11d3c, 0x11d3d,
+ 0x11d3f, 0x11d47,
+ 0x11d50, 0x11d59,
+ 0x11d60, 0x11d65,
+ 0x11d67, 0x11d68,
+ 0x11d6a, 0x11d8e,
+ 0x11d90, 0x11d91,
+ 0x11d93, 0x11d98,
+ 0x11da0, 0x11da9,
+ 0x11ee0, 0x11ef8,
+ 0x11f00, 0x11f10,
+ 0x11f12, 0x11f3a,
+ 0x11f3e, 0x11f59,
+ 0x11fb0, 0x11fb0,
+ 0x11fc0, 0x11ff1,
+ 0x11fff, 0x12399,
+ 0x12400, 0x1246e,
+ 0x12470, 0x12474,
+ 0x12480, 0x12543,
+ 0x12f90, 0x12ff2,
+ 0x13000, 0x13455,
+ 0x14400, 0x14646,
+ 0x16800, 0x16a38,
+ 0x16a40, 0x16a5e,
+ 0x16a60, 0x16a69,
+ 0x16a6e, 0x16abe,
+ 0x16ac0, 0x16ac9,
+ 0x16ad0, 0x16aed,
+ 0x16af0, 0x16af5,
+ 0x16b00, 0x16b45,
+ 0x16b50, 0x16b59,
+ 0x16b5b, 0x16b61,
+ 0x16b63, 0x16b77,
+ 0x16b7d, 0x16b8f,
+ 0x16e40, 0x16e9a,
+ 0x16f00, 0x16f4a,
+ 0x16f4f, 0x16f87,
+ 0x16f8f, 0x16f9f,
+ 0x16fe0, 0x16fe4,
+ 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,
+ 0x1bc9c, 0x1bca3,
+ 0x1cf00, 0x1cf2d,
+ 0x1cf30, 0x1cf46,
+ 0x1cf50, 0x1cfc3,
+ 0x1d000, 0x1d0f5,
+ 0x1d100, 0x1d126,
+ 0x1d129, 0x1d1ea,
+ 0x1d200, 0x1d245,
+ 0x1d2c0, 0x1d2d3,
+ 0x1d2e0, 0x1d2f3,
+ 0x1d300, 0x1d356,
+ 0x1d360, 0x1d378,
+ 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, 0x1d7cb,
+ 0x1d7ce, 0x1da8b,
+ 0x1da9b, 0x1da9f,
+ 0x1daa1, 0x1daaf,
+ 0x1df00, 0x1df1e,
+ 0x1df25, 0x1df2a,
+ 0x1e000, 0x1e006,
+ 0x1e008, 0x1e018,
+ 0x1e01b, 0x1e021,
+ 0x1e023, 0x1e024,
+ 0x1e026, 0x1e02a,
+ 0x1e030, 0x1e06d,
+ 0x1e08f, 0x1e08f,
+ 0x1e100, 0x1e12c,
+ 0x1e130, 0x1e13d,
+ 0x1e140, 0x1e149,
+ 0x1e14e, 0x1e14f,
+ 0x1e290, 0x1e2ae,
+ 0x1e2c0, 0x1e2f9,
+ 0x1e2ff, 0x1e2ff,
+ 0x1e4d0, 0x1e4f9,
+ 0x1e7e0, 0x1e7e6,
+ 0x1e7e8, 0x1e7eb,
+ 0x1e7ed, 0x1e7ee,
+ 0x1e7f0, 0x1e7fe,
+ 0x1e800, 0x1e8c4,
+ 0x1e8c7, 0x1e8d6,
+ 0x1e900, 0x1e94b,
+ 0x1e950, 0x1e959,
+ 0x1e95e, 0x1e95f,
+ 0x1ec71, 0x1ecb4,
+ 0x1ed01, 0x1ed3d,
+ 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,
+ 0x1eef0, 0x1eef1,
+ 0x1f000, 0x1f02b,
+ 0x1f030, 0x1f093,
+ 0x1f0a0, 0x1f0ae,
+ 0x1f0b1, 0x1f0bf,
+ 0x1f0c1, 0x1f0cf,
+ 0x1f0d1, 0x1f0f5,
+ 0x1f100, 0x1f1ad,
+ 0x1f1e6, 0x1f202,
+ 0x1f210, 0x1f23b,
+ 0x1f240, 0x1f248,
+ 0x1f250, 0x1f251,
+ 0x1f260, 0x1f265,
+ 0x1f300, 0x1f6d7,
+ 0x1f6dc, 0x1f6ec,
+ 0x1f6f0, 0x1f6fc,
+ 0x1f700, 0x1f776,
+ 0x1f77b, 0x1f7d9,
+ 0x1f7e0, 0x1f7eb,
+ 0x1f7f0, 0x1f7f0,
+ 0x1f800, 0x1f80b,
+ 0x1f810, 0x1f847,
+ 0x1f850, 0x1f859,
+ 0x1f860, 0x1f887,
+ 0x1f890, 0x1f8ad,
+ 0x1f8b0, 0x1f8b1,
+ 0x1f900, 0x1fa53,
+ 0x1fa60, 0x1fa6d,
+ 0x1fa70, 0x1fa7c,
+ 0x1fa80, 0x1fa88,
+ 0x1fa90, 0x1fabd,
+ 0x1fabf, 0x1fac5,
+ 0x1face, 0x1fadb,
+ 0x1fae0, 0x1fae8,
+ 0x1faf0, 0x1faf8,
+ 0x1fb00, 0x1fb92,
+ 0x1fb94, 0x1fbca,
+ 0x1fbf0, 0x1fbf9,
+ 0x1fffe, 0x2a6df,
+ 0x2a700, 0x2b739,
+ 0x2b740, 0x2b81d,
+ 0x2b820, 0x2cea1,
+ 0x2ceb0, 0x2ebe0,
+ 0x2ebf0, 0x2ee5d,
+ 0x2f800, 0x2fa1d,
+ 0x2fffe, 0x3134a,
+ 0x31350, 0x323af,
+ 0x3fffe, 0x3ffff,
+ 0x4fffe, 0x4ffff,
+ 0x5fffe, 0x5ffff,
+ 0x6fffe, 0x6ffff,
+ 0x7fffe, 0x7ffff,
+ 0x8fffe, 0x8ffff,
+ 0x9fffe, 0x9ffff,
+ 0xafffe, 0xaffff,
+ 0xbfffe, 0xbffff,
+ 0xcfffe, 0xcffff,
+ 0xdfffe, 0xdffff,
+ 0xe0001, 0xe0001,
+ 0xe0020, 0xe007f,
+ 0xe0100, 0xe01ef,
+ 0xefffe, 0x10ffff,
+}; /* CR_Age_15_1 */
+
+/* 'Age_16_0': Derived Age 16.0 */
+static const OnigCodePoint CR_Age_16_0[] = {
+ 739,
+ 0x0000, 0x0377,
+ 0x037a, 0x037f,
+ 0x0384, 0x038a,
+ 0x038c, 0x038c,
+ 0x038e, 0x03a1,
+ 0x03a3, 0x052f,
+ 0x0531, 0x0556,
+ 0x0559, 0x058a,
+ 0x058d, 0x058f,
+ 0x0591, 0x05c7,
+ 0x05d0, 0x05ea,
+ 0x05ef, 0x05f4,
+ 0x0600, 0x070d,
+ 0x070f, 0x074a,
+ 0x074d, 0x07b1,
+ 0x07c0, 0x07fa,
+ 0x07fd, 0x082d,
+ 0x0830, 0x083e,
+ 0x0840, 0x085b,
+ 0x085e, 0x085e,
+ 0x0860, 0x086a,
+ 0x0870, 0x088e,
+ 0x0890, 0x0891,
+ 0x0897, 0x0983,
+ 0x0985, 0x098c,
+ 0x098f, 0x0990,
+ 0x0993, 0x09a8,
+ 0x09aa, 0x09b0,
+ 0x09b2, 0x09b2,
+ 0x09b6, 0x09b9,
+ 0x09bc, 0x09c4,
+ 0x09c7, 0x09c8,
+ 0x09cb, 0x09ce,
+ 0x09d7, 0x09d7,
+ 0x09dc, 0x09dd,
+ 0x09df, 0x09e3,
+ 0x09e6, 0x09fe,
+ 0x0a01, 0x0a03,
+ 0x0a05, 0x0a0a,
+ 0x0a0f, 0x0a10,
+ 0x0a13, 0x0a28,
+ 0x0a2a, 0x0a30,
+ 0x0a32, 0x0a33,
+ 0x0a35, 0x0a36,
+ 0x0a38, 0x0a39,
+ 0x0a3c, 0x0a3c,
+ 0x0a3e, 0x0a42,
+ 0x0a47, 0x0a48,
+ 0x0a4b, 0x0a4d,
+ 0x0a51, 0x0a51,
+ 0x0a59, 0x0a5c,
+ 0x0a5e, 0x0a5e,
+ 0x0a66, 0x0a76,
+ 0x0a81, 0x0a83,
+ 0x0a85, 0x0a8d,
+ 0x0a8f, 0x0a91,
+ 0x0a93, 0x0aa8,
+ 0x0aaa, 0x0ab0,
+ 0x0ab2, 0x0ab3,
+ 0x0ab5, 0x0ab9,
+ 0x0abc, 0x0ac5,
+ 0x0ac7, 0x0ac9,
+ 0x0acb, 0x0acd,
+ 0x0ad0, 0x0ad0,
+ 0x0ae0, 0x0ae3,
+ 0x0ae6, 0x0af1,
+ 0x0af9, 0x0aff,
+ 0x0b01, 0x0b03,
+ 0x0b05, 0x0b0c,
+ 0x0b0f, 0x0b10,
+ 0x0b13, 0x0b28,
+ 0x0b2a, 0x0b30,
+ 0x0b32, 0x0b33,
+ 0x0b35, 0x0b39,
+ 0x0b3c, 0x0b44,
+ 0x0b47, 0x0b48,
+ 0x0b4b, 0x0b4d,
+ 0x0b55, 0x0b57,
+ 0x0b5c, 0x0b5d,
+ 0x0b5f, 0x0b63,
+ 0x0b66, 0x0b77,
+ 0x0b82, 0x0b83,
+ 0x0b85, 0x0b8a,
+ 0x0b8e, 0x0b90,
+ 0x0b92, 0x0b95,
+ 0x0b99, 0x0b9a,
+ 0x0b9c, 0x0b9c,
+ 0x0b9e, 0x0b9f,
+ 0x0ba3, 0x0ba4,
+ 0x0ba8, 0x0baa,
+ 0x0bae, 0x0bb9,
+ 0x0bbe, 0x0bc2,
+ 0x0bc6, 0x0bc8,
+ 0x0bca, 0x0bcd,
+ 0x0bd0, 0x0bd0,
+ 0x0bd7, 0x0bd7,
+ 0x0be6, 0x0bfa,
+ 0x0c00, 0x0c0c,
+ 0x0c0e, 0x0c10,
+ 0x0c12, 0x0c28,
+ 0x0c2a, 0x0c39,
+ 0x0c3c, 0x0c44,
+ 0x0c46, 0x0c48,
+ 0x0c4a, 0x0c4d,
+ 0x0c55, 0x0c56,
+ 0x0c58, 0x0c5a,
+ 0x0c5d, 0x0c5d,
+ 0x0c60, 0x0c63,
+ 0x0c66, 0x0c6f,
+ 0x0c77, 0x0c8c,
+ 0x0c8e, 0x0c90,
+ 0x0c92, 0x0ca8,
+ 0x0caa, 0x0cb3,
+ 0x0cb5, 0x0cb9,
+ 0x0cbc, 0x0cc4,
+ 0x0cc6, 0x0cc8,
+ 0x0cca, 0x0ccd,
+ 0x0cd5, 0x0cd6,
+ 0x0cdd, 0x0cde,
+ 0x0ce0, 0x0ce3,
+ 0x0ce6, 0x0cef,
+ 0x0cf1, 0x0cf3,
+ 0x0d00, 0x0d0c,
+ 0x0d0e, 0x0d10,
+ 0x0d12, 0x0d44,
+ 0x0d46, 0x0d48,
+ 0x0d4a, 0x0d4f,
+ 0x0d54, 0x0d63,
+ 0x0d66, 0x0d7f,
+ 0x0d81, 0x0d83,
+ 0x0d85, 0x0d96,
+ 0x0d9a, 0x0db1,
+ 0x0db3, 0x0dbb,
+ 0x0dbd, 0x0dbd,
+ 0x0dc0, 0x0dc6,
+ 0x0dca, 0x0dca,
+ 0x0dcf, 0x0dd4,
+ 0x0dd6, 0x0dd6,
+ 0x0dd8, 0x0ddf,
+ 0x0de6, 0x0def,
+ 0x0df2, 0x0df4,
+ 0x0e01, 0x0e3a,
+ 0x0e3f, 0x0e5b,
+ 0x0e81, 0x0e82,
+ 0x0e84, 0x0e84,
+ 0x0e86, 0x0e8a,
+ 0x0e8c, 0x0ea3,
+ 0x0ea5, 0x0ea5,
+ 0x0ea7, 0x0ebd,
+ 0x0ec0, 0x0ec4,
+ 0x0ec6, 0x0ec6,
+ 0x0ec8, 0x0ece,
+ 0x0ed0, 0x0ed9,
+ 0x0edc, 0x0edf,
+ 0x0f00, 0x0f47,
+ 0x0f49, 0x0f6c,
+ 0x0f71, 0x0f97,
+ 0x0f99, 0x0fbc,
+ 0x0fbe, 0x0fcc,
+ 0x0fce, 0x0fda,
+ 0x1000, 0x10c5,
+ 0x10c7, 0x10c7,
+ 0x10cd, 0x10cd,
+ 0x10d0, 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,
+ 0x135d, 0x137c,
+ 0x1380, 0x1399,
+ 0x13a0, 0x13f5,
+ 0x13f8, 0x13fd,
+ 0x1400, 0x169c,
+ 0x16a0, 0x16f8,
+ 0x1700, 0x1715,
+ 0x171f, 0x1736,
+ 0x1740, 0x1753,
+ 0x1760, 0x176c,
+ 0x176e, 0x1770,
+ 0x1772, 0x1773,
+ 0x1780, 0x17dd,
+ 0x17e0, 0x17e9,
+ 0x17f0, 0x17f9,
+ 0x1800, 0x1819,
+ 0x1820, 0x1878,
+ 0x1880, 0x18aa,
+ 0x18b0, 0x18f5,
+ 0x1900, 0x191e,
+ 0x1920, 0x192b,
+ 0x1930, 0x193b,
+ 0x1940, 0x1940,
+ 0x1944, 0x196d,
+ 0x1970, 0x1974,
+ 0x1980, 0x19ab,
+ 0x19b0, 0x19c9,
+ 0x19d0, 0x19da,
+ 0x19de, 0x1a1b,
+ 0x1a1e, 0x1a5e,
+ 0x1a60, 0x1a7c,
+ 0x1a7f, 0x1a89,
+ 0x1a90, 0x1a99,
+ 0x1aa0, 0x1aad,
+ 0x1ab0, 0x1ace,
+ 0x1b00, 0x1b4c,
+ 0x1b4e, 0x1bf3,
+ 0x1bfc, 0x1c37,
+ 0x1c3b, 0x1c49,
+ 0x1c4d, 0x1c8a,
+ 0x1c90, 0x1cba,
+ 0x1cbd, 0x1cc7,
+ 0x1cd0, 0x1cfa,
+ 0x1d00, 0x1f15,
+ 0x1f18, 0x1f1d,
+ 0x1f20, 0x1f45,
+ 0x1f48, 0x1f4d,
+ 0x1f50, 0x1f57,
+ 0x1f59, 0x1f59,
+ 0x1f5b, 0x1f5b,
+ 0x1f5d, 0x1f5d,
+ 0x1f5f, 0x1f7d,
+ 0x1f80, 0x1fb4,
+ 0x1fb6, 0x1fc4,
+ 0x1fc6, 0x1fd3,
+ 0x1fd6, 0x1fdb,
+ 0x1fdd, 0x1fef,
+ 0x1ff2, 0x1ff4,
+ 0x1ff6, 0x1ffe,
+ 0x2000, 0x2064,
+ 0x2066, 0x2071,
+ 0x2074, 0x208e,
+ 0x2090, 0x209c,
+ 0x20a0, 0x20c0,
+ 0x20d0, 0x20f0,
+ 0x2100, 0x218b,
+ 0x2190, 0x2429,
+ 0x2440, 0x244a,
+ 0x2460, 0x2b73,
+ 0x2b76, 0x2b95,
+ 0x2b97, 0x2cf3,
+ 0x2cf9, 0x2d25,
+ 0x2d27, 0x2d27,
+ 0x2d2d, 0x2d2d,
+ 0x2d30, 0x2d67,
+ 0x2d6f, 0x2d70,
+ 0x2d7f, 0x2d96,
+ 0x2da0, 0x2da6,
+ 0x2da8, 0x2dae,
+ 0x2db0, 0x2db6,
+ 0x2db8, 0x2dbe,
+ 0x2dc0, 0x2dc6,
+ 0x2dc8, 0x2dce,
+ 0x2dd0, 0x2dd6,
+ 0x2dd8, 0x2dde,
+ 0x2de0, 0x2e5d,
+ 0x2e80, 0x2e99,
+ 0x2e9b, 0x2ef3,
+ 0x2f00, 0x2fd5,
+ 0x2ff0, 0x303f,
+ 0x3041, 0x3096,
+ 0x3099, 0x30ff,
+ 0x3105, 0x312f,
+ 0x3131, 0x318e,
+ 0x3190, 0x31e5,
+ 0x31ef, 0x321e,
+ 0x3220, 0xa48c,
+ 0xa490, 0xa4c6,
+ 0xa4d0, 0xa62b,
+ 0xa640, 0xa6f7,
+ 0xa700, 0xa7cd,
+ 0xa7d0, 0xa7d1,
+ 0xa7d3, 0xa7d3,
+ 0xa7d5, 0xa7dc,
+ 0xa7f2, 0xa82c,
+ 0xa830, 0xa839,
+ 0xa840, 0xa877,
+ 0xa880, 0xa8c5,
+ 0xa8ce, 0xa8d9,
+ 0xa8e0, 0xa953,
+ 0xa95f, 0xa97c,
+ 0xa980, 0xa9cd,
+ 0xa9cf, 0xa9d9,
+ 0xa9de, 0xa9fe,
+ 0xaa00, 0xaa36,
+ 0xaa40, 0xaa4d,
+ 0xaa50, 0xaa59,
+ 0xaa5c, 0xaac2,
+ 0xaadb, 0xaaf6,
+ 0xab01, 0xab06,
+ 0xab09, 0xab0e,
+ 0xab11, 0xab16,
+ 0xab20, 0xab26,
+ 0xab28, 0xab2e,
+ 0xab30, 0xab6b,
+ 0xab70, 0xabed,
+ 0xabf0, 0xabf9,
+ 0xac00, 0xd7a3,
+ 0xd7b0, 0xd7c6,
+ 0xd7cb, 0xd7fb,
+ 0xd800, 0xfa6d,
+ 0xfa70, 0xfad9,
+ 0xfb00, 0xfb06,
+ 0xfb13, 0xfb17,
+ 0xfb1d, 0xfb36,
+ 0xfb38, 0xfb3c,
+ 0xfb3e, 0xfb3e,
+ 0xfb40, 0xfb41,
+ 0xfb43, 0xfb44,
+ 0xfb46, 0xfbc2,
+ 0xfbd3, 0xfd8f,
+ 0xfd92, 0xfdc7,
+ 0xfdcf, 0xfe19,
+ 0xfe20, 0xfe52,
+ 0xfe54, 0xfe66,
+ 0xfe68, 0xfe6b,
+ 0xfe70, 0xfe74,
+ 0xfe76, 0xfefc,
+ 0xfeff, 0xfeff,
+ 0xff01, 0xffbe,
+ 0xffc2, 0xffc7,
+ 0xffca, 0xffcf,
+ 0xffd2, 0xffd7,
+ 0xffda, 0xffdc,
+ 0xffe0, 0xffe6,
+ 0xffe8, 0xffee,
+ 0xfff9, 0x1000b,
+ 0x1000d, 0x10026,
+ 0x10028, 0x1003a,
+ 0x1003c, 0x1003d,
+ 0x1003f, 0x1004d,
+ 0x10050, 0x1005d,
+ 0x10080, 0x100fa,
+ 0x10100, 0x10102,
+ 0x10107, 0x10133,
+ 0x10137, 0x1018e,
+ 0x10190, 0x1019c,
+ 0x101a0, 0x101a0,
+ 0x101d0, 0x101fd,
+ 0x10280, 0x1029c,
+ 0x102a0, 0x102d0,
+ 0x102e0, 0x102fb,
+ 0x10300, 0x10323,
+ 0x1032d, 0x1034a,
+ 0x10350, 0x1037a,
+ 0x10380, 0x1039d,
+ 0x1039f, 0x103c3,
+ 0x103c8, 0x103d5,
+ 0x10400, 0x1049d,
+ 0x104a0, 0x104a9,
+ 0x104b0, 0x104d3,
+ 0x104d8, 0x104fb,
+ 0x10500, 0x10527,
+ 0x10530, 0x10563,
+ 0x1056f, 0x1057a,
+ 0x1057c, 0x1058a,
+ 0x1058c, 0x10592,
+ 0x10594, 0x10595,
+ 0x10597, 0x105a1,
+ 0x105a3, 0x105b1,
+ 0x105b3, 0x105b9,
+ 0x105bb, 0x105bc,
+ 0x105c0, 0x105f3,
+ 0x10600, 0x10736,
+ 0x10740, 0x10755,
+ 0x10760, 0x10767,
+ 0x10780, 0x10785,
+ 0x10787, 0x107b0,
+ 0x107b2, 0x107ba,
+ 0x10800, 0x10805,
+ 0x10808, 0x10808,
+ 0x1080a, 0x10835,
+ 0x10837, 0x10838,
+ 0x1083c, 0x1083c,
+ 0x1083f, 0x10855,
+ 0x10857, 0x1089e,
+ 0x108a7, 0x108af,
+ 0x108e0, 0x108f2,
+ 0x108f4, 0x108f5,
+ 0x108fb, 0x1091b,
+ 0x1091f, 0x10939,
+ 0x1093f, 0x1093f,
+ 0x10980, 0x109b7,
+ 0x109bc, 0x109cf,
+ 0x109d2, 0x10a03,
+ 0x10a05, 0x10a06,
+ 0x10a0c, 0x10a13,
+ 0x10a15, 0x10a17,
+ 0x10a19, 0x10a35,
+ 0x10a38, 0x10a3a,
+ 0x10a3f, 0x10a48,
+ 0x10a50, 0x10a58,
+ 0x10a60, 0x10a9f,
+ 0x10ac0, 0x10ae6,
+ 0x10aeb, 0x10af6,
+ 0x10b00, 0x10b35,
+ 0x10b39, 0x10b55,
+ 0x10b58, 0x10b72,
+ 0x10b78, 0x10b91,
+ 0x10b99, 0x10b9c,
+ 0x10ba9, 0x10baf,
+ 0x10c00, 0x10c48,
+ 0x10c80, 0x10cb2,
+ 0x10cc0, 0x10cf2,
+ 0x10cfa, 0x10d27,
+ 0x10d30, 0x10d39,
+ 0x10d40, 0x10d65,
+ 0x10d69, 0x10d85,
+ 0x10d8e, 0x10d8f,
+ 0x10e60, 0x10e7e,
+ 0x10e80, 0x10ea9,
+ 0x10eab, 0x10ead,
+ 0x10eb0, 0x10eb1,
+ 0x10ec2, 0x10ec4,
+ 0x10efc, 0x10f27,
+ 0x10f30, 0x10f59,
+ 0x10f70, 0x10f89,
+ 0x10fb0, 0x10fcb,
+ 0x10fe0, 0x10ff6,
+ 0x11000, 0x1104d,
+ 0x11052, 0x11075,
+ 0x1107f, 0x110c2,
+ 0x110cd, 0x110cd,
+ 0x110d0, 0x110e8,
+ 0x110f0, 0x110f9,
+ 0x11100, 0x11134,
+ 0x11136, 0x11147,
+ 0x11150, 0x11176,
+ 0x11180, 0x111df,
+ 0x111e1, 0x111f4,
+ 0x11200, 0x11211,
+ 0x11213, 0x11241,
+ 0x11280, 0x11286,
+ 0x11288, 0x11288,
+ 0x1128a, 0x1128d,
+ 0x1128f, 0x1129d,
+ 0x1129f, 0x112a9,
+ 0x112b0, 0x112ea,
+ 0x112f0, 0x112f9,
+ 0x11300, 0x11303,
+ 0x11305, 0x1130c,
+ 0x1130f, 0x11310,
+ 0x11313, 0x11328,
+ 0x1132a, 0x11330,
+ 0x11332, 0x11333,
+ 0x11335, 0x11339,
+ 0x1133b, 0x11344,
+ 0x11347, 0x11348,
+ 0x1134b, 0x1134d,
+ 0x11350, 0x11350,
+ 0x11357, 0x11357,
+ 0x1135d, 0x11363,
+ 0x11366, 0x1136c,
+ 0x11370, 0x11374,
+ 0x11380, 0x11389,
+ 0x1138b, 0x1138b,
+ 0x1138e, 0x1138e,
+ 0x11390, 0x113b5,
+ 0x113b7, 0x113c0,
+ 0x113c2, 0x113c2,
+ 0x113c5, 0x113c5,
+ 0x113c7, 0x113ca,
+ 0x113cc, 0x113d5,
+ 0x113d7, 0x113d8,
+ 0x113e1, 0x113e2,
+ 0x11400, 0x1145b,
+ 0x1145d, 0x11461,
+ 0x11480, 0x114c7,
+ 0x114d0, 0x114d9,
+ 0x11580, 0x115b5,
+ 0x115b8, 0x115dd,
+ 0x11600, 0x11644,
+ 0x11650, 0x11659,
+ 0x11660, 0x1166c,
+ 0x11680, 0x116b9,
+ 0x116c0, 0x116c9,
+ 0x116d0, 0x116e3,
+ 0x11700, 0x1171a,
+ 0x1171d, 0x1172b,
+ 0x11730, 0x11746,
+ 0x11800, 0x1183b,
+ 0x118a0, 0x118f2,
+ 0x118ff, 0x11906,
+ 0x11909, 0x11909,
+ 0x1190c, 0x11913,
+ 0x11915, 0x11916,
+ 0x11918, 0x11935,
+ 0x11937, 0x11938,
+ 0x1193b, 0x11946,
+ 0x11950, 0x11959,
+ 0x119a0, 0x119a7,
+ 0x119aa, 0x119d7,
+ 0x119da, 0x119e4,
+ 0x11a00, 0x11a47,
+ 0x11a50, 0x11aa2,
+ 0x11ab0, 0x11af8,
+ 0x11b00, 0x11b09,
+ 0x11bc0, 0x11be1,
+ 0x11bf0, 0x11bf9,
+ 0x11c00, 0x11c08,
+ 0x11c0a, 0x11c36,
+ 0x11c38, 0x11c45,
+ 0x11c50, 0x11c6c,
+ 0x11c70, 0x11c8f,
+ 0x11c92, 0x11ca7,
+ 0x11ca9, 0x11cb6,
+ 0x11d00, 0x11d06,
+ 0x11d08, 0x11d09,
+ 0x11d0b, 0x11d36,
+ 0x11d3a, 0x11d3a,
+ 0x11d3c, 0x11d3d,
+ 0x11d3f, 0x11d47,
+ 0x11d50, 0x11d59,
+ 0x11d60, 0x11d65,
+ 0x11d67, 0x11d68,
+ 0x11d6a, 0x11d8e,
+ 0x11d90, 0x11d91,
+ 0x11d93, 0x11d98,
+ 0x11da0, 0x11da9,
+ 0x11ee0, 0x11ef8,
+ 0x11f00, 0x11f10,
+ 0x11f12, 0x11f3a,
+ 0x11f3e, 0x11f5a,
+ 0x11fb0, 0x11fb0,
+ 0x11fc0, 0x11ff1,
+ 0x11fff, 0x12399,
+ 0x12400, 0x1246e,
+ 0x12470, 0x12474,
+ 0x12480, 0x12543,
+ 0x12f90, 0x12ff2,
+ 0x13000, 0x13455,
+ 0x13460, 0x143fa,
+ 0x14400, 0x14646,
+ 0x16100, 0x16139,
+ 0x16800, 0x16a38,
+ 0x16a40, 0x16a5e,
+ 0x16a60, 0x16a69,
+ 0x16a6e, 0x16abe,
+ 0x16ac0, 0x16ac9,
+ 0x16ad0, 0x16aed,
+ 0x16af0, 0x16af5,
+ 0x16b00, 0x16b45,
+ 0x16b50, 0x16b59,
+ 0x16b5b, 0x16b61,
+ 0x16b63, 0x16b77,
+ 0x16b7d, 0x16b8f,
+ 0x16d40, 0x16d79,
+ 0x16e40, 0x16e9a,
+ 0x16f00, 0x16f4a,
+ 0x16f4f, 0x16f87,
+ 0x16f8f, 0x16f9f,
+ 0x16fe0, 0x16fe4,
+ 0x16ff0, 0x16ff1,
+ 0x17000, 0x187f7,
+ 0x18800, 0x18cd5,
+ 0x18cff, 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,
+ 0x1bc9c, 0x1bca3,
+ 0x1cc00, 0x1ccf9,
+ 0x1cd00, 0x1ceb3,
+ 0x1cf00, 0x1cf2d,
+ 0x1cf30, 0x1cf46,
+ 0x1cf50, 0x1cfc3,
+ 0x1d000, 0x1d0f5,
+ 0x1d100, 0x1d126,
+ 0x1d129, 0x1d1ea,
+ 0x1d200, 0x1d245,
+ 0x1d2c0, 0x1d2d3,
+ 0x1d2e0, 0x1d2f3,
+ 0x1d300, 0x1d356,
+ 0x1d360, 0x1d378,
+ 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, 0x1d7cb,
+ 0x1d7ce, 0x1da8b,
+ 0x1da9b, 0x1da9f,
+ 0x1daa1, 0x1daaf,
+ 0x1df00, 0x1df1e,
+ 0x1df25, 0x1df2a,
+ 0x1e000, 0x1e006,
+ 0x1e008, 0x1e018,
+ 0x1e01b, 0x1e021,
+ 0x1e023, 0x1e024,
+ 0x1e026, 0x1e02a,
+ 0x1e030, 0x1e06d,
+ 0x1e08f, 0x1e08f,
+ 0x1e100, 0x1e12c,
+ 0x1e130, 0x1e13d,
+ 0x1e140, 0x1e149,
+ 0x1e14e, 0x1e14f,
+ 0x1e290, 0x1e2ae,
+ 0x1e2c0, 0x1e2f9,
+ 0x1e2ff, 0x1e2ff,
+ 0x1e4d0, 0x1e4f9,
+ 0x1e5d0, 0x1e5fa,
+ 0x1e5ff, 0x1e5ff,
+ 0x1e7e0, 0x1e7e6,
+ 0x1e7e8, 0x1e7eb,
+ 0x1e7ed, 0x1e7ee,
+ 0x1e7f0, 0x1e7fe,
+ 0x1e800, 0x1e8c4,
+ 0x1e8c7, 0x1e8d6,
+ 0x1e900, 0x1e94b,
+ 0x1e950, 0x1e959,
+ 0x1e95e, 0x1e95f,
+ 0x1ec71, 0x1ecb4,
+ 0x1ed01, 0x1ed3d,
+ 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,
+ 0x1eef0, 0x1eef1,
+ 0x1f000, 0x1f02b,
+ 0x1f030, 0x1f093,
+ 0x1f0a0, 0x1f0ae,
+ 0x1f0b1, 0x1f0bf,
+ 0x1f0c1, 0x1f0cf,
+ 0x1f0d1, 0x1f0f5,
+ 0x1f100, 0x1f1ad,
+ 0x1f1e6, 0x1f202,
+ 0x1f210, 0x1f23b,
+ 0x1f240, 0x1f248,
+ 0x1f250, 0x1f251,
+ 0x1f260, 0x1f265,
+ 0x1f300, 0x1f6d7,
+ 0x1f6dc, 0x1f6ec,
+ 0x1f6f0, 0x1f6fc,
+ 0x1f700, 0x1f776,
+ 0x1f77b, 0x1f7d9,
+ 0x1f7e0, 0x1f7eb,
+ 0x1f7f0, 0x1f7f0,
+ 0x1f800, 0x1f80b,
+ 0x1f810, 0x1f847,
+ 0x1f850, 0x1f859,
+ 0x1f860, 0x1f887,
+ 0x1f890, 0x1f8ad,
+ 0x1f8b0, 0x1f8bb,
+ 0x1f8c0, 0x1f8c1,
+ 0x1f900, 0x1fa53,
+ 0x1fa60, 0x1fa6d,
+ 0x1fa70, 0x1fa7c,
+ 0x1fa80, 0x1fa89,
+ 0x1fa8f, 0x1fac6,
+ 0x1face, 0x1fadc,
+ 0x1fadf, 0x1fae9,
+ 0x1faf0, 0x1faf8,
+ 0x1fb00, 0x1fb92,
+ 0x1fb94, 0x1fbf9,
+ 0x1fffe, 0x2a6df,
+ 0x2a700, 0x2b739,
+ 0x2b740, 0x2b81d,
+ 0x2b820, 0x2cea1,
+ 0x2ceb0, 0x2ebe0,
+ 0x2ebf0, 0x2ee5d,
+ 0x2f800, 0x2fa1d,
+ 0x2fffe, 0x3134a,
+ 0x31350, 0x323af,
+ 0x3fffe, 0x3ffff,
+ 0x4fffe, 0x4ffff,
+ 0x5fffe, 0x5ffff,
+ 0x6fffe, 0x6ffff,
+ 0x7fffe, 0x7ffff,
+ 0x8fffe, 0x8ffff,
+ 0x9fffe, 0x9ffff,
+ 0xafffe, 0xaffff,
+ 0xbfffe, 0xbffff,
+ 0xcfffe, 0xcffff,
+ 0xdfffe, 0xdffff,
+ 0xe0001, 0xe0001,
+ 0xe0020, 0xe007f,
+ 0xe0100, 0xe01ef,
+ 0xefffe, 0x10ffff,
+}; /* CR_Age_16_0 */
+
+/* 'Age_17_0': Derived Age 17.0 */
+static const OnigCodePoint CR_Age_17_0[] = {
+ 743,
+ 0x0000, 0x0377,
+ 0x037a, 0x037f,
+ 0x0384, 0x038a,
+ 0x038c, 0x038c,
+ 0x038e, 0x03a1,
+ 0x03a3, 0x052f,
+ 0x0531, 0x0556,
+ 0x0559, 0x058a,
+ 0x058d, 0x058f,
+ 0x0591, 0x05c7,
+ 0x05d0, 0x05ea,
+ 0x05ef, 0x05f4,
+ 0x0600, 0x070d,
+ 0x070f, 0x074a,
+ 0x074d, 0x07b1,
+ 0x07c0, 0x07fa,
+ 0x07fd, 0x082d,
+ 0x0830, 0x083e,
+ 0x0840, 0x085b,
+ 0x085e, 0x085e,
+ 0x0860, 0x086a,
+ 0x0870, 0x0891,
+ 0x0897, 0x0983,
+ 0x0985, 0x098c,
+ 0x098f, 0x0990,
+ 0x0993, 0x09a8,
+ 0x09aa, 0x09b0,
+ 0x09b2, 0x09b2,
+ 0x09b6, 0x09b9,
+ 0x09bc, 0x09c4,
+ 0x09c7, 0x09c8,
+ 0x09cb, 0x09ce,
+ 0x09d7, 0x09d7,
+ 0x09dc, 0x09dd,
+ 0x09df, 0x09e3,
+ 0x09e6, 0x09fe,
+ 0x0a01, 0x0a03,
+ 0x0a05, 0x0a0a,
+ 0x0a0f, 0x0a10,
+ 0x0a13, 0x0a28,
+ 0x0a2a, 0x0a30,
+ 0x0a32, 0x0a33,
+ 0x0a35, 0x0a36,
+ 0x0a38, 0x0a39,
+ 0x0a3c, 0x0a3c,
+ 0x0a3e, 0x0a42,
+ 0x0a47, 0x0a48,
+ 0x0a4b, 0x0a4d,
+ 0x0a51, 0x0a51,
+ 0x0a59, 0x0a5c,
+ 0x0a5e, 0x0a5e,
+ 0x0a66, 0x0a76,
+ 0x0a81, 0x0a83,
+ 0x0a85, 0x0a8d,
+ 0x0a8f, 0x0a91,
+ 0x0a93, 0x0aa8,
+ 0x0aaa, 0x0ab0,
+ 0x0ab2, 0x0ab3,
+ 0x0ab5, 0x0ab9,
+ 0x0abc, 0x0ac5,
+ 0x0ac7, 0x0ac9,
+ 0x0acb, 0x0acd,
+ 0x0ad0, 0x0ad0,
+ 0x0ae0, 0x0ae3,
+ 0x0ae6, 0x0af1,
+ 0x0af9, 0x0aff,
+ 0x0b01, 0x0b03,
+ 0x0b05, 0x0b0c,
+ 0x0b0f, 0x0b10,
+ 0x0b13, 0x0b28,
+ 0x0b2a, 0x0b30,
+ 0x0b32, 0x0b33,
+ 0x0b35, 0x0b39,
+ 0x0b3c, 0x0b44,
+ 0x0b47, 0x0b48,
+ 0x0b4b, 0x0b4d,
+ 0x0b55, 0x0b57,
+ 0x0b5c, 0x0b5d,
+ 0x0b5f, 0x0b63,
+ 0x0b66, 0x0b77,
+ 0x0b82, 0x0b83,
+ 0x0b85, 0x0b8a,
+ 0x0b8e, 0x0b90,
+ 0x0b92, 0x0b95,
+ 0x0b99, 0x0b9a,
+ 0x0b9c, 0x0b9c,
+ 0x0b9e, 0x0b9f,
+ 0x0ba3, 0x0ba4,
+ 0x0ba8, 0x0baa,
+ 0x0bae, 0x0bb9,
+ 0x0bbe, 0x0bc2,
+ 0x0bc6, 0x0bc8,
+ 0x0bca, 0x0bcd,
+ 0x0bd0, 0x0bd0,
+ 0x0bd7, 0x0bd7,
+ 0x0be6, 0x0bfa,
+ 0x0c00, 0x0c0c,
+ 0x0c0e, 0x0c10,
+ 0x0c12, 0x0c28,
+ 0x0c2a, 0x0c39,
+ 0x0c3c, 0x0c44,
+ 0x0c46, 0x0c48,
+ 0x0c4a, 0x0c4d,
+ 0x0c55, 0x0c56,
+ 0x0c58, 0x0c5a,
+ 0x0c5c, 0x0c5d,
+ 0x0c60, 0x0c63,
+ 0x0c66, 0x0c6f,
+ 0x0c77, 0x0c8c,
+ 0x0c8e, 0x0c90,
+ 0x0c92, 0x0ca8,
+ 0x0caa, 0x0cb3,
+ 0x0cb5, 0x0cb9,
+ 0x0cbc, 0x0cc4,
+ 0x0cc6, 0x0cc8,
+ 0x0cca, 0x0ccd,
+ 0x0cd5, 0x0cd6,
+ 0x0cdc, 0x0cde,
+ 0x0ce0, 0x0ce3,
+ 0x0ce6, 0x0cef,
+ 0x0cf1, 0x0cf3,
+ 0x0d00, 0x0d0c,
+ 0x0d0e, 0x0d10,
+ 0x0d12, 0x0d44,
+ 0x0d46, 0x0d48,
+ 0x0d4a, 0x0d4f,
+ 0x0d54, 0x0d63,
+ 0x0d66, 0x0d7f,
+ 0x0d81, 0x0d83,
+ 0x0d85, 0x0d96,
+ 0x0d9a, 0x0db1,
+ 0x0db3, 0x0dbb,
+ 0x0dbd, 0x0dbd,
+ 0x0dc0, 0x0dc6,
+ 0x0dca, 0x0dca,
+ 0x0dcf, 0x0dd4,
+ 0x0dd6, 0x0dd6,
+ 0x0dd8, 0x0ddf,
+ 0x0de6, 0x0def,
+ 0x0df2, 0x0df4,
+ 0x0e01, 0x0e3a,
+ 0x0e3f, 0x0e5b,
+ 0x0e81, 0x0e82,
+ 0x0e84, 0x0e84,
+ 0x0e86, 0x0e8a,
+ 0x0e8c, 0x0ea3,
+ 0x0ea5, 0x0ea5,
+ 0x0ea7, 0x0ebd,
+ 0x0ec0, 0x0ec4,
+ 0x0ec6, 0x0ec6,
+ 0x0ec8, 0x0ece,
+ 0x0ed0, 0x0ed9,
+ 0x0edc, 0x0edf,
+ 0x0f00, 0x0f47,
+ 0x0f49, 0x0f6c,
+ 0x0f71, 0x0f97,
+ 0x0f99, 0x0fbc,
+ 0x0fbe, 0x0fcc,
+ 0x0fce, 0x0fda,
+ 0x1000, 0x10c5,
+ 0x10c7, 0x10c7,
+ 0x10cd, 0x10cd,
+ 0x10d0, 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,
+ 0x135d, 0x137c,
+ 0x1380, 0x1399,
+ 0x13a0, 0x13f5,
+ 0x13f8, 0x13fd,
+ 0x1400, 0x169c,
+ 0x16a0, 0x16f8,
+ 0x1700, 0x1715,
+ 0x171f, 0x1736,
+ 0x1740, 0x1753,
+ 0x1760, 0x176c,
+ 0x176e, 0x1770,
+ 0x1772, 0x1773,
+ 0x1780, 0x17dd,
+ 0x17e0, 0x17e9,
+ 0x17f0, 0x17f9,
+ 0x1800, 0x1819,
+ 0x1820, 0x1878,
+ 0x1880, 0x18aa,
+ 0x18b0, 0x18f5,
+ 0x1900, 0x191e,
+ 0x1920, 0x192b,
+ 0x1930, 0x193b,
+ 0x1940, 0x1940,
+ 0x1944, 0x196d,
+ 0x1970, 0x1974,
+ 0x1980, 0x19ab,
+ 0x19b0, 0x19c9,
+ 0x19d0, 0x19da,
+ 0x19de, 0x1a1b,
+ 0x1a1e, 0x1a5e,
+ 0x1a60, 0x1a7c,
+ 0x1a7f, 0x1a89,
+ 0x1a90, 0x1a99,
+ 0x1aa0, 0x1aad,
+ 0x1ab0, 0x1add,
+ 0x1ae0, 0x1aeb,
+ 0x1b00, 0x1b4c,
+ 0x1b4e, 0x1bf3,
+ 0x1bfc, 0x1c37,
+ 0x1c3b, 0x1c49,
+ 0x1c4d, 0x1c8a,
+ 0x1c90, 0x1cba,
+ 0x1cbd, 0x1cc7,
+ 0x1cd0, 0x1cfa,
+ 0x1d00, 0x1f15,
+ 0x1f18, 0x1f1d,
+ 0x1f20, 0x1f45,
+ 0x1f48, 0x1f4d,
+ 0x1f50, 0x1f57,
+ 0x1f59, 0x1f59,
+ 0x1f5b, 0x1f5b,
+ 0x1f5d, 0x1f5d,
+ 0x1f5f, 0x1f7d,
+ 0x1f80, 0x1fb4,
+ 0x1fb6, 0x1fc4,
+ 0x1fc6, 0x1fd3,
+ 0x1fd6, 0x1fdb,
+ 0x1fdd, 0x1fef,
+ 0x1ff2, 0x1ff4,
+ 0x1ff6, 0x1ffe,
+ 0x2000, 0x2064,
+ 0x2066, 0x2071,
+ 0x2074, 0x208e,
+ 0x2090, 0x209c,
+ 0x20a0, 0x20c1,
+ 0x20d0, 0x20f0,
+ 0x2100, 0x218b,
+ 0x2190, 0x2429,
+ 0x2440, 0x244a,
+ 0x2460, 0x2b73,
+ 0x2b76, 0x2cf3,
+ 0x2cf9, 0x2d25,
+ 0x2d27, 0x2d27,
+ 0x2d2d, 0x2d2d,
+ 0x2d30, 0x2d67,
+ 0x2d6f, 0x2d70,
+ 0x2d7f, 0x2d96,
+ 0x2da0, 0x2da6,
+ 0x2da8, 0x2dae,
+ 0x2db0, 0x2db6,
+ 0x2db8, 0x2dbe,
+ 0x2dc0, 0x2dc6,
+ 0x2dc8, 0x2dce,
+ 0x2dd0, 0x2dd6,
+ 0x2dd8, 0x2dde,
+ 0x2de0, 0x2e5d,
+ 0x2e80, 0x2e99,
+ 0x2e9b, 0x2ef3,
+ 0x2f00, 0x2fd5,
+ 0x2ff0, 0x303f,
+ 0x3041, 0x3096,
+ 0x3099, 0x30ff,
+ 0x3105, 0x312f,
+ 0x3131, 0x318e,
+ 0x3190, 0x31e5,
+ 0x31ef, 0x321e,
+ 0x3220, 0xa48c,
+ 0xa490, 0xa4c6,
+ 0xa4d0, 0xa62b,
+ 0xa640, 0xa6f7,
+ 0xa700, 0xa7dc,
+ 0xa7f1, 0xa82c,
+ 0xa830, 0xa839,
+ 0xa840, 0xa877,
+ 0xa880, 0xa8c5,
+ 0xa8ce, 0xa8d9,
+ 0xa8e0, 0xa953,
+ 0xa95f, 0xa97c,
+ 0xa980, 0xa9cd,
+ 0xa9cf, 0xa9d9,
+ 0xa9de, 0xa9fe,
+ 0xaa00, 0xaa36,
+ 0xaa40, 0xaa4d,
+ 0xaa50, 0xaa59,
+ 0xaa5c, 0xaac2,
+ 0xaadb, 0xaaf6,
+ 0xab01, 0xab06,
+ 0xab09, 0xab0e,
+ 0xab11, 0xab16,
+ 0xab20, 0xab26,
+ 0xab28, 0xab2e,
+ 0xab30, 0xab6b,
+ 0xab70, 0xabed,
+ 0xabf0, 0xabf9,
+ 0xac00, 0xd7a3,
+ 0xd7b0, 0xd7c6,
+ 0xd7cb, 0xd7fb,
+ 0xd800, 0xfa6d,
+ 0xfa70, 0xfad9,
+ 0xfb00, 0xfb06,
+ 0xfb13, 0xfb17,
+ 0xfb1d, 0xfb36,
+ 0xfb38, 0xfb3c,
+ 0xfb3e, 0xfb3e,
+ 0xfb40, 0xfb41,
+ 0xfb43, 0xfb44,
+ 0xfb46, 0xfe19,
+ 0xfe20, 0xfe52,
+ 0xfe54, 0xfe66,
+ 0xfe68, 0xfe6b,
+ 0xfe70, 0xfe74,
+ 0xfe76, 0xfefc,
+ 0xfeff, 0xfeff,
+ 0xff01, 0xffbe,
+ 0xffc2, 0xffc7,
+ 0xffca, 0xffcf,
+ 0xffd2, 0xffd7,
+ 0xffda, 0xffdc,
+ 0xffe0, 0xffe6,
+ 0xffe8, 0xffee,
+ 0xfff9, 0x1000b,
+ 0x1000d, 0x10026,
+ 0x10028, 0x1003a,
+ 0x1003c, 0x1003d,
+ 0x1003f, 0x1004d,
+ 0x10050, 0x1005d,
+ 0x10080, 0x100fa,
+ 0x10100, 0x10102,
+ 0x10107, 0x10133,
+ 0x10137, 0x1018e,
+ 0x10190, 0x1019c,
+ 0x101a0, 0x101a0,
+ 0x101d0, 0x101fd,
+ 0x10280, 0x1029c,
+ 0x102a0, 0x102d0,
+ 0x102e0, 0x102fb,
+ 0x10300, 0x10323,
+ 0x1032d, 0x1034a,
+ 0x10350, 0x1037a,
+ 0x10380, 0x1039d,
+ 0x1039f, 0x103c3,
+ 0x103c8, 0x103d5,
+ 0x10400, 0x1049d,
+ 0x104a0, 0x104a9,
+ 0x104b0, 0x104d3,
+ 0x104d8, 0x104fb,
+ 0x10500, 0x10527,
+ 0x10530, 0x10563,
+ 0x1056f, 0x1057a,
+ 0x1057c, 0x1058a,
+ 0x1058c, 0x10592,
+ 0x10594, 0x10595,
+ 0x10597, 0x105a1,
+ 0x105a3, 0x105b1,
+ 0x105b3, 0x105b9,
+ 0x105bb, 0x105bc,
+ 0x105c0, 0x105f3,
+ 0x10600, 0x10736,
+ 0x10740, 0x10755,
+ 0x10760, 0x10767,
+ 0x10780, 0x10785,
+ 0x10787, 0x107b0,
+ 0x107b2, 0x107ba,
+ 0x10800, 0x10805,
+ 0x10808, 0x10808,
+ 0x1080a, 0x10835,
+ 0x10837, 0x10838,
+ 0x1083c, 0x1083c,
+ 0x1083f, 0x10855,
+ 0x10857, 0x1089e,
+ 0x108a7, 0x108af,
+ 0x108e0, 0x108f2,
+ 0x108f4, 0x108f5,
+ 0x108fb, 0x1091b,
+ 0x1091f, 0x10939,
+ 0x1093f, 0x10959,
+ 0x10980, 0x109b7,
+ 0x109bc, 0x109cf,
+ 0x109d2, 0x10a03,
+ 0x10a05, 0x10a06,
+ 0x10a0c, 0x10a13,
+ 0x10a15, 0x10a17,
+ 0x10a19, 0x10a35,
+ 0x10a38, 0x10a3a,
+ 0x10a3f, 0x10a48,
+ 0x10a50, 0x10a58,
+ 0x10a60, 0x10a9f,
+ 0x10ac0, 0x10ae6,
+ 0x10aeb, 0x10af6,
+ 0x10b00, 0x10b35,
+ 0x10b39, 0x10b55,
+ 0x10b58, 0x10b72,
+ 0x10b78, 0x10b91,
+ 0x10b99, 0x10b9c,
+ 0x10ba9, 0x10baf,
+ 0x10c00, 0x10c48,
+ 0x10c80, 0x10cb2,
+ 0x10cc0, 0x10cf2,
+ 0x10cfa, 0x10d27,
+ 0x10d30, 0x10d39,
+ 0x10d40, 0x10d65,
+ 0x10d69, 0x10d85,
+ 0x10d8e, 0x10d8f,
+ 0x10e60, 0x10e7e,
+ 0x10e80, 0x10ea9,
+ 0x10eab, 0x10ead,
+ 0x10eb0, 0x10eb1,
+ 0x10ec2, 0x10ec7,
+ 0x10ed0, 0x10ed8,
+ 0x10efa, 0x10f27,
+ 0x10f30, 0x10f59,
+ 0x10f70, 0x10f89,
+ 0x10fb0, 0x10fcb,
+ 0x10fe0, 0x10ff6,
+ 0x11000, 0x1104d,
+ 0x11052, 0x11075,
+ 0x1107f, 0x110c2,
+ 0x110cd, 0x110cd,
+ 0x110d0, 0x110e8,
+ 0x110f0, 0x110f9,
+ 0x11100, 0x11134,
+ 0x11136, 0x11147,
+ 0x11150, 0x11176,
+ 0x11180, 0x111df,
+ 0x111e1, 0x111f4,
+ 0x11200, 0x11211,
+ 0x11213, 0x11241,
+ 0x11280, 0x11286,
+ 0x11288, 0x11288,
+ 0x1128a, 0x1128d,
+ 0x1128f, 0x1129d,
+ 0x1129f, 0x112a9,
+ 0x112b0, 0x112ea,
+ 0x112f0, 0x112f9,
+ 0x11300, 0x11303,
+ 0x11305, 0x1130c,
+ 0x1130f, 0x11310,
+ 0x11313, 0x11328,
+ 0x1132a, 0x11330,
+ 0x11332, 0x11333,
+ 0x11335, 0x11339,
+ 0x1133b, 0x11344,
+ 0x11347, 0x11348,
+ 0x1134b, 0x1134d,
+ 0x11350, 0x11350,
+ 0x11357, 0x11357,
+ 0x1135d, 0x11363,
+ 0x11366, 0x1136c,
+ 0x11370, 0x11374,
+ 0x11380, 0x11389,
+ 0x1138b, 0x1138b,
+ 0x1138e, 0x1138e,
+ 0x11390, 0x113b5,
+ 0x113b7, 0x113c0,
+ 0x113c2, 0x113c2,
+ 0x113c5, 0x113c5,
+ 0x113c7, 0x113ca,
+ 0x113cc, 0x113d5,
+ 0x113d7, 0x113d8,
+ 0x113e1, 0x113e2,
+ 0x11400, 0x1145b,
+ 0x1145d, 0x11461,
+ 0x11480, 0x114c7,
+ 0x114d0, 0x114d9,
+ 0x11580, 0x115b5,
+ 0x115b8, 0x115dd,
+ 0x11600, 0x11644,
+ 0x11650, 0x11659,
+ 0x11660, 0x1166c,
+ 0x11680, 0x116b9,
+ 0x116c0, 0x116c9,
+ 0x116d0, 0x116e3,
+ 0x11700, 0x1171a,
+ 0x1171d, 0x1172b,
+ 0x11730, 0x11746,
+ 0x11800, 0x1183b,
+ 0x118a0, 0x118f2,
+ 0x118ff, 0x11906,
+ 0x11909, 0x11909,
+ 0x1190c, 0x11913,
+ 0x11915, 0x11916,
+ 0x11918, 0x11935,
+ 0x11937, 0x11938,
+ 0x1193b, 0x11946,
+ 0x11950, 0x11959,
+ 0x119a0, 0x119a7,
+ 0x119aa, 0x119d7,
+ 0x119da, 0x119e4,
+ 0x11a00, 0x11a47,
+ 0x11a50, 0x11aa2,
+ 0x11ab0, 0x11af8,
+ 0x11b00, 0x11b09,
+ 0x11b60, 0x11b67,
+ 0x11bc0, 0x11be1,
+ 0x11bf0, 0x11bf9,
+ 0x11c00, 0x11c08,
+ 0x11c0a, 0x11c36,
+ 0x11c38, 0x11c45,
+ 0x11c50, 0x11c6c,
+ 0x11c70, 0x11c8f,
+ 0x11c92, 0x11ca7,
+ 0x11ca9, 0x11cb6,
+ 0x11d00, 0x11d06,
+ 0x11d08, 0x11d09,
+ 0x11d0b, 0x11d36,
+ 0x11d3a, 0x11d3a,
+ 0x11d3c, 0x11d3d,
+ 0x11d3f, 0x11d47,
+ 0x11d50, 0x11d59,
+ 0x11d60, 0x11d65,
+ 0x11d67, 0x11d68,
+ 0x11d6a, 0x11d8e,
+ 0x11d90, 0x11d91,
+ 0x11d93, 0x11d98,
+ 0x11da0, 0x11da9,
+ 0x11db0, 0x11ddb,
+ 0x11de0, 0x11de9,
+ 0x11ee0, 0x11ef8,
+ 0x11f00, 0x11f10,
+ 0x11f12, 0x11f3a,
+ 0x11f3e, 0x11f5a,
+ 0x11fb0, 0x11fb0,
+ 0x11fc0, 0x11ff1,
+ 0x11fff, 0x12399,
+ 0x12400, 0x1246e,
+ 0x12470, 0x12474,
+ 0x12480, 0x12543,
+ 0x12f90, 0x12ff2,
+ 0x13000, 0x13455,
+ 0x13460, 0x143fa,
+ 0x14400, 0x14646,
+ 0x16100, 0x16139,
+ 0x16800, 0x16a38,
+ 0x16a40, 0x16a5e,
+ 0x16a60, 0x16a69,
+ 0x16a6e, 0x16abe,
+ 0x16ac0, 0x16ac9,
+ 0x16ad0, 0x16aed,
+ 0x16af0, 0x16af5,
+ 0x16b00, 0x16b45,
+ 0x16b50, 0x16b59,
+ 0x16b5b, 0x16b61,
+ 0x16b63, 0x16b77,
+ 0x16b7d, 0x16b8f,
+ 0x16d40, 0x16d79,
+ 0x16e40, 0x16e9a,
+ 0x16ea0, 0x16eb8,
+ 0x16ebb, 0x16ed3,
+ 0x16f00, 0x16f4a,
+ 0x16f4f, 0x16f87,
+ 0x16f8f, 0x16f9f,
+ 0x16fe0, 0x16fe4,
+ 0x16ff0, 0x16ff6,
+ 0x17000, 0x18cd5,
+ 0x18cff, 0x18d1e,
+ 0x18d80, 0x18df2,
+ 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,
+ 0x1bc9c, 0x1bca3,
+ 0x1cc00, 0x1ccfc,
+ 0x1cd00, 0x1ceb3,
+ 0x1ceba, 0x1ced0,
+ 0x1cee0, 0x1cef0,
+ 0x1cf00, 0x1cf2d,
+ 0x1cf30, 0x1cf46,
+ 0x1cf50, 0x1cfc3,
+ 0x1d000, 0x1d0f5,
+ 0x1d100, 0x1d126,
+ 0x1d129, 0x1d1ea,
+ 0x1d200, 0x1d245,
+ 0x1d2c0, 0x1d2d3,
+ 0x1d2e0, 0x1d2f3,
+ 0x1d300, 0x1d356,
+ 0x1d360, 0x1d378,
+ 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, 0x1d7cb,
+ 0x1d7ce, 0x1da8b,
+ 0x1da9b, 0x1da9f,
+ 0x1daa1, 0x1daaf,
+ 0x1df00, 0x1df1e,
+ 0x1df25, 0x1df2a,
+ 0x1e000, 0x1e006,
+ 0x1e008, 0x1e018,
+ 0x1e01b, 0x1e021,
+ 0x1e023, 0x1e024,
+ 0x1e026, 0x1e02a,
+ 0x1e030, 0x1e06d,
+ 0x1e08f, 0x1e08f,
+ 0x1e100, 0x1e12c,
+ 0x1e130, 0x1e13d,
+ 0x1e140, 0x1e149,
+ 0x1e14e, 0x1e14f,
+ 0x1e290, 0x1e2ae,
+ 0x1e2c0, 0x1e2f9,
+ 0x1e2ff, 0x1e2ff,
+ 0x1e4d0, 0x1e4f9,
+ 0x1e5d0, 0x1e5fa,
+ 0x1e5ff, 0x1e5ff,
+ 0x1e6c0, 0x1e6de,
+ 0x1e6e0, 0x1e6f5,
+ 0x1e6fe, 0x1e6ff,
+ 0x1e7e0, 0x1e7e6,
+ 0x1e7e8, 0x1e7eb,
+ 0x1e7ed, 0x1e7ee,
+ 0x1e7f0, 0x1e7fe,
+ 0x1e800, 0x1e8c4,
+ 0x1e8c7, 0x1e8d6,
+ 0x1e900, 0x1e94b,
+ 0x1e950, 0x1e959,
+ 0x1e95e, 0x1e95f,
+ 0x1ec71, 0x1ecb4,
+ 0x1ed01, 0x1ed3d,
+ 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,
+ 0x1eef0, 0x1eef1,
+ 0x1f000, 0x1f02b,
+ 0x1f030, 0x1f093,
+ 0x1f0a0, 0x1f0ae,
+ 0x1f0b1, 0x1f0bf,
+ 0x1f0c1, 0x1f0cf,
+ 0x1f0d1, 0x1f0f5,
+ 0x1f100, 0x1f1ad,
+ 0x1f1e6, 0x1f202,
+ 0x1f210, 0x1f23b,
+ 0x1f240, 0x1f248,
+ 0x1f250, 0x1f251,
+ 0x1f260, 0x1f265,
+ 0x1f300, 0x1f6d8,
+ 0x1f6dc, 0x1f6ec,
+ 0x1f6f0, 0x1f6fc,
+ 0x1f700, 0x1f7d9,
+ 0x1f7e0, 0x1f7eb,
+ 0x1f7f0, 0x1f7f0,
+ 0x1f800, 0x1f80b,
+ 0x1f810, 0x1f847,
+ 0x1f850, 0x1f859,
+ 0x1f860, 0x1f887,
+ 0x1f890, 0x1f8ad,
+ 0x1f8b0, 0x1f8bb,
+ 0x1f8c0, 0x1f8c1,
+ 0x1f8d0, 0x1f8d8,
+ 0x1f900, 0x1fa57,
+ 0x1fa60, 0x1fa6d,
+ 0x1fa70, 0x1fa7c,
+ 0x1fa80, 0x1fa8a,
+ 0x1fa8e, 0x1fac6,
+ 0x1fac8, 0x1fac8,
+ 0x1facd, 0x1fadc,
+ 0x1fadf, 0x1faea,
+ 0x1faef, 0x1faf8,
+ 0x1fb00, 0x1fb92,
+ 0x1fb94, 0x1fbfa,
+ 0x1fffe, 0x2a6df,
+ 0x2a700, 0x2b81d,
+ 0x2b820, 0x2cead,
+ 0x2ceb0, 0x2ebe0,
+ 0x2ebf0, 0x2ee5d,
+ 0x2f800, 0x2fa1d,
+ 0x2fffe, 0x3134a,
+ 0x31350, 0x33479,
+ 0x3fffe, 0x3ffff,
+ 0x4fffe, 0x4ffff,
+ 0x5fffe, 0x5ffff,
+ 0x6fffe, 0x6ffff,
+ 0x7fffe, 0x7ffff,
+ 0x8fffe, 0x8ffff,
+ 0x9fffe, 0x9ffff,
+ 0xafffe, 0xaffff,
+ 0xbfffe, 0xbffff,
+ 0xcfffe, 0xcffff,
+ 0xdfffe, 0xdffff,
+ 0xe0001, 0xe0001,
+ 0xe0020, 0xe007f,
+ 0xe0100, 0xe01ef,
+ 0xefffe, 0x10ffff,
+}; /* CR_Age_17_0 */
+
+#endif /* USE_UNICODE_AGE_PROPERTIES */
+/* 'Grapheme_Cluster_Break_Prepend': Grapheme_Cluster_Break=Prepend */
+static const OnigCodePoint CR_Grapheme_Cluster_Break_Prepend[] = {
+ 15,
+ 0x0600, 0x0605,
+ 0x06dd, 0x06dd,
+ 0x070f, 0x070f,
+ 0x0890, 0x0891,
+ 0x08e2, 0x08e2,
+ 0x0d4e, 0x0d4e,
+ 0x110bd, 0x110bd,
+ 0x110cd, 0x110cd,
+ 0x111c2, 0x111c3,
+ 0x113d1, 0x113d1,
+ 0x1193f, 0x1193f,
+ 0x11941, 0x11941,
+ 0x11a84, 0x11a89,
+ 0x11d46, 0x11d46,
+ 0x11f02, 0x11f02,
+}; /* CR_Grapheme_Cluster_Break_Prepend */
+
+/* 'Grapheme_Cluster_Break_CR': Grapheme_Cluster_Break=CR */
+static const OnigCodePoint CR_Grapheme_Cluster_Break_CR[] = {
+ 1,
+ 0x000d, 0x000d,
+}; /* CR_Grapheme_Cluster_Break_CR */
+
+/* 'Grapheme_Cluster_Break_LF': Grapheme_Cluster_Break=LF */
+#define CR_Grapheme_Cluster_Break_LF CR_NEWLINE
+
+/* 'Grapheme_Cluster_Break_Control': Grapheme_Cluster_Break=Control */
+static const OnigCodePoint CR_Grapheme_Cluster_Break_Control[] = {
+ 19,
+ 0x0000, 0x0009,
+ 0x000b, 0x000c,
+ 0x000e, 0x001f,
+ 0x007f, 0x009f,
+ 0x00ad, 0x00ad,
+ 0x061c, 0x061c,
+ 0x180e, 0x180e,
+ 0x200b, 0x200b,
+ 0x200e, 0x200f,
+ 0x2028, 0x202e,
+ 0x2060, 0x206f,
+ 0xfeff, 0xfeff,
+ 0xfff0, 0xfffb,
+ 0x13430, 0x1343f,
+ 0x1bca0, 0x1bca3,
+ 0x1d173, 0x1d17a,
+ 0xe0000, 0xe001f,
+ 0xe0080, 0xe00ff,
+ 0xe01f0, 0xe0fff,
+}; /* CR_Grapheme_Cluster_Break_Control */
+
+/* 'Grapheme_Cluster_Break_Extend': Grapheme_Cluster_Break=Extend */
+static const OnigCodePoint CR_Grapheme_Cluster_Break_Extend[] = {
+ 384,
+ 0x0300, 0x036f,
+ 0x0483, 0x0489,
+ 0x0591, 0x05bd,
+ 0x05bf, 0x05bf,
+ 0x05c1, 0x05c2,
+ 0x05c4, 0x05c5,
+ 0x05c7, 0x05c7,
+ 0x0610, 0x061a,
+ 0x064b, 0x065f,
+ 0x0670, 0x0670,
+ 0x06d6, 0x06dc,
+ 0x06df, 0x06e4,
+ 0x06e7, 0x06e8,
+ 0x06ea, 0x06ed,
+ 0x0711, 0x0711,
+ 0x0730, 0x074a,
+ 0x07a6, 0x07b0,
+ 0x07eb, 0x07f3,
+ 0x07fd, 0x07fd,
+ 0x0816, 0x0819,
+ 0x081b, 0x0823,
+ 0x0825, 0x0827,
+ 0x0829, 0x082d,
+ 0x0859, 0x085b,
+ 0x0897, 0x089f,
+ 0x08ca, 0x08e1,
+ 0x08e3, 0x0902,
+ 0x093a, 0x093a,
+ 0x093c, 0x093c,
+ 0x0941, 0x0948,
+ 0x094d, 0x094d,
+ 0x0951, 0x0957,
+ 0x0962, 0x0963,
+ 0x0981, 0x0981,
+ 0x09bc, 0x09bc,
+ 0x09be, 0x09be,
+ 0x09c1, 0x09c4,
+ 0x09cd, 0x09cd,
+ 0x09d7, 0x09d7,
+ 0x09e2, 0x09e3,
+ 0x09fe, 0x09fe,
+ 0x0a01, 0x0a02,
+ 0x0a3c, 0x0a3c,
+ 0x0a41, 0x0a42,
+ 0x0a47, 0x0a48,
+ 0x0a4b, 0x0a4d,
+ 0x0a51, 0x0a51,
+ 0x0a70, 0x0a71,
+ 0x0a75, 0x0a75,
+ 0x0a81, 0x0a82,
+ 0x0abc, 0x0abc,
+ 0x0ac1, 0x0ac5,
+ 0x0ac7, 0x0ac8,
+ 0x0acd, 0x0acd,
+ 0x0ae2, 0x0ae3,
+ 0x0afa, 0x0aff,
+ 0x0b01, 0x0b01,
+ 0x0b3c, 0x0b3c,
+ 0x0b3e, 0x0b3f,
+ 0x0b41, 0x0b44,
+ 0x0b4d, 0x0b4d,
+ 0x0b55, 0x0b57,
+ 0x0b62, 0x0b63,
+ 0x0b82, 0x0b82,
+ 0x0bbe, 0x0bbe,
+ 0x0bc0, 0x0bc0,
+ 0x0bcd, 0x0bcd,
+ 0x0bd7, 0x0bd7,
+ 0x0c00, 0x0c00,
+ 0x0c04, 0x0c04,
+ 0x0c3c, 0x0c3c,
+ 0x0c3e, 0x0c40,
+ 0x0c46, 0x0c48,
+ 0x0c4a, 0x0c4d,
+ 0x0c55, 0x0c56,
+ 0x0c62, 0x0c63,
+ 0x0c81, 0x0c81,
+ 0x0cbc, 0x0cbc,
+ 0x0cbf, 0x0cc0,
+ 0x0cc2, 0x0cc2,
+ 0x0cc6, 0x0cc8,
+ 0x0cca, 0x0ccd,
+ 0x0cd5, 0x0cd6,
+ 0x0ce2, 0x0ce3,
+ 0x0d00, 0x0d01,
+ 0x0d3b, 0x0d3c,
+ 0x0d3e, 0x0d3e,
+ 0x0d41, 0x0d44,
+ 0x0d4d, 0x0d4d,
+ 0x0d57, 0x0d57,
+ 0x0d62, 0x0d63,
+ 0x0d81, 0x0d81,
+ 0x0dca, 0x0dca,
+ 0x0dcf, 0x0dcf,
+ 0x0dd2, 0x0dd4,
+ 0x0dd6, 0x0dd6,
+ 0x0ddf, 0x0ddf,
+ 0x0e31, 0x0e31,
+ 0x0e34, 0x0e3a,
+ 0x0e47, 0x0e4e,
+ 0x0eb1, 0x0eb1,
+ 0x0eb4, 0x0ebc,
+ 0x0ec8, 0x0ece,
+ 0x0f18, 0x0f19,
+ 0x0f35, 0x0f35,
+ 0x0f37, 0x0f37,
+ 0x0f39, 0x0f39,
+ 0x0f71, 0x0f7e,
+ 0x0f80, 0x0f84,
+ 0x0f86, 0x0f87,
+ 0x0f8d, 0x0f97,
+ 0x0f99, 0x0fbc,
+ 0x0fc6, 0x0fc6,
+ 0x102d, 0x1030,
+ 0x1032, 0x1037,
+ 0x1039, 0x103a,
+ 0x103d, 0x103e,
+ 0x1058, 0x1059,
+ 0x105e, 0x1060,
+ 0x1071, 0x1074,
+ 0x1082, 0x1082,
+ 0x1085, 0x1086,
+ 0x108d, 0x108d,
+ 0x109d, 0x109d,
+ 0x135d, 0x135f,
+ 0x1712, 0x1715,
+ 0x1732, 0x1734,
+ 0x1752, 0x1753,
+ 0x1772, 0x1773,
+ 0x17b4, 0x17b5,
+ 0x17b7, 0x17bd,
+ 0x17c6, 0x17c6,
+ 0x17c9, 0x17d3,
+ 0x17dd, 0x17dd,
+ 0x180b, 0x180d,
+ 0x180f, 0x180f,
+ 0x1885, 0x1886,
+ 0x18a9, 0x18a9,
+ 0x1920, 0x1922,
+ 0x1927, 0x1928,
+ 0x1932, 0x1932,
+ 0x1939, 0x193b,
+ 0x1a17, 0x1a18,
+ 0x1a1b, 0x1a1b,
+ 0x1a56, 0x1a56,
+ 0x1a58, 0x1a5e,
+ 0x1a60, 0x1a60,
+ 0x1a62, 0x1a62,
+ 0x1a65, 0x1a6c,
+ 0x1a73, 0x1a7c,
+ 0x1a7f, 0x1a7f,
+ 0x1ab0, 0x1add,
+ 0x1ae0, 0x1aeb,
+ 0x1b00, 0x1b03,
+ 0x1b34, 0x1b3d,
+ 0x1b42, 0x1b44,
+ 0x1b6b, 0x1b73,
+ 0x1b80, 0x1b81,
+ 0x1ba2, 0x1ba5,
+ 0x1ba8, 0x1bad,
+ 0x1be6, 0x1be6,
+ 0x1be8, 0x1be9,
+ 0x1bed, 0x1bed,
+ 0x1bef, 0x1bf3,
+ 0x1c2c, 0x1c33,
+ 0x1c36, 0x1c37,
+ 0x1cd0, 0x1cd2,
+ 0x1cd4, 0x1ce0,
+ 0x1ce2, 0x1ce8,
+ 0x1ced, 0x1ced,
+ 0x1cf4, 0x1cf4,
+ 0x1cf8, 0x1cf9,
+ 0x1dc0, 0x1dff,
+ 0x200c, 0x200c,
+ 0x20d0, 0x20f0,
+ 0x2cef, 0x2cf1,
+ 0x2d7f, 0x2d7f,
+ 0x2de0, 0x2dff,
+ 0x302a, 0x302f,
+ 0x3099, 0x309a,
+ 0xa66f, 0xa672,
+ 0xa674, 0xa67d,
+ 0xa69e, 0xa69f,
+ 0xa6f0, 0xa6f1,
+ 0xa802, 0xa802,
+ 0xa806, 0xa806,
+ 0xa80b, 0xa80b,
+ 0xa825, 0xa826,
+ 0xa82c, 0xa82c,
+ 0xa8c4, 0xa8c5,
+ 0xa8e0, 0xa8f1,
+ 0xa8ff, 0xa8ff,
+ 0xa926, 0xa92d,
+ 0xa947, 0xa951,
+ 0xa953, 0xa953,
+ 0xa980, 0xa982,
+ 0xa9b3, 0xa9b3,
+ 0xa9b6, 0xa9b9,
+ 0xa9bc, 0xa9bd,
+ 0xa9c0, 0xa9c0,
+ 0xa9e5, 0xa9e5,
+ 0xaa29, 0xaa2e,
+ 0xaa31, 0xaa32,
+ 0xaa35, 0xaa36,
+ 0xaa43, 0xaa43,
+ 0xaa4c, 0xaa4c,
+ 0xaa7c, 0xaa7c,
+ 0xaab0, 0xaab0,
+ 0xaab2, 0xaab4,
+ 0xaab7, 0xaab8,
+ 0xaabe, 0xaabf,
+ 0xaac1, 0xaac1,
+ 0xaaec, 0xaaed,
+ 0xaaf6, 0xaaf6,
+ 0xabe5, 0xabe5,
+ 0xabe8, 0xabe8,
+ 0xabed, 0xabed,
+ 0xfb1e, 0xfb1e,
+ 0xfe00, 0xfe0f,
+ 0xfe20, 0xfe2f,
+ 0xff9e, 0xff9f,
+ 0x101fd, 0x101fd,
+ 0x102e0, 0x102e0,
+ 0x10376, 0x1037a,
+ 0x10a01, 0x10a03,
+ 0x10a05, 0x10a06,
+ 0x10a0c, 0x10a0f,
+ 0x10a38, 0x10a3a,
+ 0x10a3f, 0x10a3f,
+ 0x10ae5, 0x10ae6,
+ 0x10d24, 0x10d27,
+ 0x10d69, 0x10d6d,
+ 0x10eab, 0x10eac,
+ 0x10efa, 0x10eff,
+ 0x10f46, 0x10f50,
+ 0x10f82, 0x10f85,
+ 0x11001, 0x11001,
+ 0x11038, 0x11046,
+ 0x11070, 0x11070,
+ 0x11073, 0x11074,
+ 0x1107f, 0x11081,
+ 0x110b3, 0x110b6,
+ 0x110b9, 0x110ba,
+ 0x110c2, 0x110c2,
+ 0x11100, 0x11102,
+ 0x11127, 0x1112b,
+ 0x1112d, 0x11134,
+ 0x11173, 0x11173,
+ 0x11180, 0x11181,
+ 0x111b6, 0x111be,
+ 0x111c0, 0x111c0,
+ 0x111c9, 0x111cc,
+ 0x111cf, 0x111cf,
+ 0x1122f, 0x11231,
+ 0x11234, 0x11237,
+ 0x1123e, 0x1123e,
+ 0x11241, 0x11241,
+ 0x112df, 0x112df,
+ 0x112e3, 0x112ea,
+ 0x11300, 0x11301,
+ 0x1133b, 0x1133c,
+ 0x1133e, 0x1133e,
+ 0x11340, 0x11340,
+ 0x1134d, 0x1134d,
+ 0x11357, 0x11357,
+ 0x11366, 0x1136c,
+ 0x11370, 0x11374,
+ 0x113b8, 0x113b8,
+ 0x113bb, 0x113c0,
+ 0x113c2, 0x113c2,
+ 0x113c5, 0x113c5,
+ 0x113c7, 0x113c9,
+ 0x113ce, 0x113d0,
+ 0x113d2, 0x113d2,
+ 0x113e1, 0x113e2,
+ 0x11438, 0x1143f,
+ 0x11442, 0x11444,
+ 0x11446, 0x11446,
+ 0x1145e, 0x1145e,
+ 0x114b0, 0x114b0,
+ 0x114b3, 0x114b8,
+ 0x114ba, 0x114ba,
+ 0x114bd, 0x114bd,
+ 0x114bf, 0x114c0,
+ 0x114c2, 0x114c3,
+ 0x115af, 0x115af,
+ 0x115b2, 0x115b5,
+ 0x115bc, 0x115bd,
+ 0x115bf, 0x115c0,
+ 0x115dc, 0x115dd,
+ 0x11633, 0x1163a,
+ 0x1163d, 0x1163d,
+ 0x1163f, 0x11640,
+ 0x116ab, 0x116ab,
+ 0x116ad, 0x116ad,
+ 0x116b0, 0x116b7,
+ 0x1171d, 0x1171d,
+ 0x1171f, 0x1171f,
+ 0x11722, 0x11725,
+ 0x11727, 0x1172b,
+ 0x1182f, 0x11837,
+ 0x11839, 0x1183a,
+ 0x11930, 0x11930,
+ 0x1193b, 0x1193e,
+ 0x11943, 0x11943,
+ 0x119d4, 0x119d7,
+ 0x119da, 0x119db,
+ 0x119e0, 0x119e0,
+ 0x11a01, 0x11a0a,
+ 0x11a33, 0x11a38,
+ 0x11a3b, 0x11a3e,
+ 0x11a47, 0x11a47,
+ 0x11a51, 0x11a56,
+ 0x11a59, 0x11a5b,
+ 0x11a8a, 0x11a96,
+ 0x11a98, 0x11a99,
+ 0x11b60, 0x11b60,
+ 0x11b62, 0x11b64,
+ 0x11b66, 0x11b66,
+ 0x11c30, 0x11c36,
+ 0x11c38, 0x11c3d,
+ 0x11c3f, 0x11c3f,
+ 0x11c92, 0x11ca7,
+ 0x11caa, 0x11cb0,
+ 0x11cb2, 0x11cb3,
+ 0x11cb5, 0x11cb6,
+ 0x11d31, 0x11d36,
+ 0x11d3a, 0x11d3a,
+ 0x11d3c, 0x11d3d,
+ 0x11d3f, 0x11d45,
+ 0x11d47, 0x11d47,
+ 0x11d90, 0x11d91,
+ 0x11d95, 0x11d95,
+ 0x11d97, 0x11d97,
+ 0x11ef3, 0x11ef4,
+ 0x11f00, 0x11f01,
+ 0x11f36, 0x11f3a,
+ 0x11f40, 0x11f42,
+ 0x11f5a, 0x11f5a,
+ 0x13440, 0x13440,
+ 0x13447, 0x13455,
+ 0x1611e, 0x16129,
+ 0x1612d, 0x1612f,
+ 0x16af0, 0x16af4,
+ 0x16b30, 0x16b36,
+ 0x16f4f, 0x16f4f,
+ 0x16f8f, 0x16f92,
+ 0x16fe4, 0x16fe4,
+ 0x16ff0, 0x16ff1,
+ 0x1bc9d, 0x1bc9e,
+ 0x1cf00, 0x1cf2d,
+ 0x1cf30, 0x1cf46,
+ 0x1d165, 0x1d169,
+ 0x1d16d, 0x1d172,
+ 0x1d17b, 0x1d182,
+ 0x1d185, 0x1d18b,
+ 0x1d1aa, 0x1d1ad,
+ 0x1d242, 0x1d244,
+ 0x1da00, 0x1da36,
+ 0x1da3b, 0x1da6c,
+ 0x1da75, 0x1da75,
+ 0x1da84, 0x1da84,
+ 0x1da9b, 0x1da9f,
+ 0x1daa1, 0x1daaf,
+ 0x1e000, 0x1e006,
+ 0x1e008, 0x1e018,
+ 0x1e01b, 0x1e021,
+ 0x1e023, 0x1e024,
+ 0x1e026, 0x1e02a,
+ 0x1e08f, 0x1e08f,
+ 0x1e130, 0x1e136,
+ 0x1e2ae, 0x1e2ae,
+ 0x1e2ec, 0x1e2ef,
+ 0x1e4ec, 0x1e4ef,
+ 0x1e5ee, 0x1e5ef,
+ 0x1e6e3, 0x1e6e3,
+ 0x1e6e6, 0x1e6e6,
+ 0x1e6ee, 0x1e6ef,
+ 0x1e6f5, 0x1e6f5,
+ 0x1e8d0, 0x1e8d6,
+ 0x1e944, 0x1e94a,
+ 0x1f3fb, 0x1f3ff,
+ 0xe0020, 0xe007f,
+ 0xe0100, 0xe01ef,
+}; /* CR_Grapheme_Cluster_Break_Extend */
+
+/* 'Grapheme_Cluster_Break_Regional_Indicator': Grapheme_Cluster_Break=Regional_Indicator */
+#define CR_Grapheme_Cluster_Break_Regional_Indicator CR_Regional_Indicator
+
+/* 'Grapheme_Cluster_Break_SpacingMark': Grapheme_Cluster_Break=SpacingMark */
+static const OnigCodePoint CR_Grapheme_Cluster_Break_SpacingMark[] = {
+ 158,
+ 0x0903, 0x0903,
+ 0x093b, 0x093b,
+ 0x093e, 0x0940,
+ 0x0949, 0x094c,
+ 0x094e, 0x094f,
+ 0x0982, 0x0983,
+ 0x09bf, 0x09c0,
+ 0x09c7, 0x09c8,
+ 0x09cb, 0x09cc,
+ 0x0a03, 0x0a03,
+ 0x0a3e, 0x0a40,
+ 0x0a83, 0x0a83,
+ 0x0abe, 0x0ac0,
+ 0x0ac9, 0x0ac9,
+ 0x0acb, 0x0acc,
+ 0x0b02, 0x0b03,
+ 0x0b40, 0x0b40,
+ 0x0b47, 0x0b48,
+ 0x0b4b, 0x0b4c,
+ 0x0bbf, 0x0bbf,
+ 0x0bc1, 0x0bc2,
+ 0x0bc6, 0x0bc8,
+ 0x0bca, 0x0bcc,
+ 0x0c01, 0x0c03,
+ 0x0c41, 0x0c44,
+ 0x0c82, 0x0c83,
+ 0x0cbe, 0x0cbe,
+ 0x0cc1, 0x0cc1,
+ 0x0cc3, 0x0cc4,
+ 0x0cf3, 0x0cf3,
+ 0x0d02, 0x0d03,
+ 0x0d3f, 0x0d40,
+ 0x0d46, 0x0d48,
+ 0x0d4a, 0x0d4c,
+ 0x0d82, 0x0d83,
+ 0x0dd0, 0x0dd1,
+ 0x0dd8, 0x0dde,
+ 0x0df2, 0x0df3,
+ 0x0e33, 0x0e33,
+ 0x0eb3, 0x0eb3,
+ 0x0f3e, 0x0f3f,
+ 0x0f7f, 0x0f7f,
+ 0x1031, 0x1031,
+ 0x103b, 0x103c,
+ 0x1056, 0x1057,
+ 0x1084, 0x1084,
+ 0x17b6, 0x17b6,
+ 0x17be, 0x17c5,
+ 0x17c7, 0x17c8,
+ 0x1923, 0x1926,
+ 0x1929, 0x192b,
+ 0x1930, 0x1931,
+ 0x1933, 0x1938,
+ 0x1a19, 0x1a1a,
+ 0x1a55, 0x1a55,
+ 0x1a57, 0x1a57,
+ 0x1a6d, 0x1a72,
+ 0x1b04, 0x1b04,
+ 0x1b3e, 0x1b41,
+ 0x1b82, 0x1b82,
+ 0x1ba1, 0x1ba1,
+ 0x1ba6, 0x1ba7,
+ 0x1be7, 0x1be7,
+ 0x1bea, 0x1bec,
+ 0x1bee, 0x1bee,
+ 0x1c24, 0x1c2b,
+ 0x1c34, 0x1c35,
+ 0x1ce1, 0x1ce1,
+ 0x1cf7, 0x1cf7,
+ 0xa823, 0xa824,
+ 0xa827, 0xa827,
+ 0xa880, 0xa881,
+ 0xa8b4, 0xa8c3,
+ 0xa952, 0xa952,
+ 0xa983, 0xa983,
+ 0xa9b4, 0xa9b5,
+ 0xa9ba, 0xa9bb,
+ 0xa9be, 0xa9bf,
+ 0xaa2f, 0xaa30,
+ 0xaa33, 0xaa34,
+ 0xaa4d, 0xaa4d,
+ 0xaaeb, 0xaaeb,
+ 0xaaee, 0xaaef,
+ 0xaaf5, 0xaaf5,
+ 0xabe3, 0xabe4,
+ 0xabe6, 0xabe7,
+ 0xabe9, 0xabea,
+ 0xabec, 0xabec,
+ 0x11000, 0x11000,
+ 0x11002, 0x11002,
+ 0x11082, 0x11082,
+ 0x110b0, 0x110b2,
+ 0x110b7, 0x110b8,
+ 0x1112c, 0x1112c,
+ 0x11145, 0x11146,
+ 0x11182, 0x11182,
+ 0x111b3, 0x111b5,
+ 0x111bf, 0x111bf,
+ 0x111ce, 0x111ce,
+ 0x1122c, 0x1122e,
+ 0x11232, 0x11233,
+ 0x112e0, 0x112e2,
+ 0x11302, 0x11303,
+ 0x1133f, 0x1133f,
+ 0x11341, 0x11344,
+ 0x11347, 0x11348,
+ 0x1134b, 0x1134c,
+ 0x11362, 0x11363,
+ 0x113b9, 0x113ba,
+ 0x113ca, 0x113ca,
+ 0x113cc, 0x113cd,
+ 0x11435, 0x11437,
+ 0x11440, 0x11441,
+ 0x11445, 0x11445,
+ 0x114b1, 0x114b2,
+ 0x114b9, 0x114b9,
+ 0x114bb, 0x114bc,
+ 0x114be, 0x114be,
+ 0x114c1, 0x114c1,
+ 0x115b0, 0x115b1,
+ 0x115b8, 0x115bb,
+ 0x115be, 0x115be,
+ 0x11630, 0x11632,
+ 0x1163b, 0x1163c,
+ 0x1163e, 0x1163e,
+ 0x116ac, 0x116ac,
+ 0x116ae, 0x116af,
+ 0x1171e, 0x1171e,
+ 0x11726, 0x11726,
+ 0x1182c, 0x1182e,
+ 0x11838, 0x11838,
+ 0x11931, 0x11935,
+ 0x11937, 0x11938,
+ 0x11940, 0x11940,
+ 0x11942, 0x11942,
+ 0x119d1, 0x119d3,
+ 0x119dc, 0x119df,
+ 0x119e4, 0x119e4,
+ 0x11a39, 0x11a39,
+ 0x11a57, 0x11a58,
+ 0x11a97, 0x11a97,
+ 0x11b61, 0x11b61,
+ 0x11b65, 0x11b65,
+ 0x11b67, 0x11b67,
+ 0x11c2f, 0x11c2f,
+ 0x11c3e, 0x11c3e,
+ 0x11ca9, 0x11ca9,
+ 0x11cb1, 0x11cb1,
+ 0x11cb4, 0x11cb4,
+ 0x11d8a, 0x11d8e,
+ 0x11d93, 0x11d94,
+ 0x11d96, 0x11d96,
+ 0x11ef5, 0x11ef6,
+ 0x11f03, 0x11f03,
+ 0x11f34, 0x11f35,
+ 0x11f3e, 0x11f3f,
+ 0x1612a, 0x1612c,
+ 0x16f51, 0x16f87,
+}; /* CR_Grapheme_Cluster_Break_SpacingMark */
+
+/* 'Grapheme_Cluster_Break_L': Grapheme_Cluster_Break=L */
+static const OnigCodePoint CR_Grapheme_Cluster_Break_L[] = {
+ 2,
+ 0x1100, 0x115f,
+ 0xa960, 0xa97c,
+}; /* CR_Grapheme_Cluster_Break_L */
+
+/* 'Grapheme_Cluster_Break_V': Grapheme_Cluster_Break=V */
+static const OnigCodePoint CR_Grapheme_Cluster_Break_V[] = {
+ 4,
+ 0x1160, 0x11a7,
+ 0xd7b0, 0xd7c6,
+ 0x16d63, 0x16d63,
+ 0x16d67, 0x16d6a,
+}; /* CR_Grapheme_Cluster_Break_V */
+
+/* 'Grapheme_Cluster_Break_T': Grapheme_Cluster_Break=T */
+static const OnigCodePoint CR_Grapheme_Cluster_Break_T[] = {
+ 2,
+ 0x11a8, 0x11ff,
+ 0xd7cb, 0xd7fb,
+}; /* CR_Grapheme_Cluster_Break_T */
+
+/* 'Grapheme_Cluster_Break_LV': Grapheme_Cluster_Break=LV */
+static const OnigCodePoint CR_Grapheme_Cluster_Break_LV[] = {
+ 399,
+ 0xac00, 0xac00,
+ 0xac1c, 0xac1c,
+ 0xac38, 0xac38,
+ 0xac54, 0xac54,
+ 0xac70, 0xac70,
+ 0xac8c, 0xac8c,
+ 0xaca8, 0xaca8,
+ 0xacc4, 0xacc4,
+ 0xace0, 0xace0,
+ 0xacfc, 0xacfc,
+ 0xad18, 0xad18,
+ 0xad34, 0xad34,
+ 0xad50, 0xad50,
+ 0xad6c, 0xad6c,
+ 0xad88, 0xad88,
+ 0xada4, 0xada4,
+ 0xadc0, 0xadc0,
+ 0xaddc, 0xaddc,
+ 0xadf8, 0xadf8,
+ 0xae14, 0xae14,
+ 0xae30, 0xae30,
+ 0xae4c, 0xae4c,
+ 0xae68, 0xae68,
+ 0xae84, 0xae84,
+ 0xaea0, 0xaea0,
+ 0xaebc, 0xaebc,
+ 0xaed8, 0xaed8,
+ 0xaef4, 0xaef4,
+ 0xaf10, 0xaf10,
+ 0xaf2c, 0xaf2c,
+ 0xaf48, 0xaf48,
+ 0xaf64, 0xaf64,
+ 0xaf80, 0xaf80,
+ 0xaf9c, 0xaf9c,
+ 0xafb8, 0xafb8,
+ 0xafd4, 0xafd4,
+ 0xaff0, 0xaff0,
+ 0xb00c, 0xb00c,
+ 0xb028, 0xb028,
+ 0xb044, 0xb044,
+ 0xb060, 0xb060,
+ 0xb07c, 0xb07c,
+ 0xb098, 0xb098,
+ 0xb0b4, 0xb0b4,
+ 0xb0d0, 0xb0d0,
+ 0xb0ec, 0xb0ec,
+ 0xb108, 0xb108,
+ 0xb124, 0xb124,
+ 0xb140, 0xb140,
+ 0xb15c, 0xb15c,
+ 0xb178, 0xb178,
+ 0xb194, 0xb194,
+ 0xb1b0, 0xb1b0,
+ 0xb1cc, 0xb1cc,
+ 0xb1e8, 0xb1e8,
+ 0xb204, 0xb204,
+ 0xb220, 0xb220,
+ 0xb23c, 0xb23c,
+ 0xb258, 0xb258,
+ 0xb274, 0xb274,
+ 0xb290, 0xb290,
+ 0xb2ac, 0xb2ac,
+ 0xb2c8, 0xb2c8,
+ 0xb2e4, 0xb2e4,
+ 0xb300, 0xb300,
+ 0xb31c, 0xb31c,
+ 0xb338, 0xb338,
+ 0xb354, 0xb354,
+ 0xb370, 0xb370,
+ 0xb38c, 0xb38c,
+ 0xb3a8, 0xb3a8,
+ 0xb3c4, 0xb3c4,
+ 0xb3e0, 0xb3e0,
+ 0xb3fc, 0xb3fc,
+ 0xb418, 0xb418,
+ 0xb434, 0xb434,
+ 0xb450, 0xb450,
+ 0xb46c, 0xb46c,
+ 0xb488, 0xb488,
+ 0xb4a4, 0xb4a4,
+ 0xb4c0, 0xb4c0,
+ 0xb4dc, 0xb4dc,
+ 0xb4f8, 0xb4f8,
+ 0xb514, 0xb514,
+ 0xb530, 0xb530,
+ 0xb54c, 0xb54c,
+ 0xb568, 0xb568,
+ 0xb584, 0xb584,
+ 0xb5a0, 0xb5a0,
+ 0xb5bc, 0xb5bc,
+ 0xb5d8, 0xb5d8,
+ 0xb5f4, 0xb5f4,
+ 0xb610, 0xb610,
+ 0xb62c, 0xb62c,
+ 0xb648, 0xb648,
+ 0xb664, 0xb664,
+ 0xb680, 0xb680,
+ 0xb69c, 0xb69c,
+ 0xb6b8, 0xb6b8,
+ 0xb6d4, 0xb6d4,
+ 0xb6f0, 0xb6f0,
+ 0xb70c, 0xb70c,
+ 0xb728, 0xb728,
+ 0xb744, 0xb744,
+ 0xb760, 0xb760,
+ 0xb77c, 0xb77c,
+ 0xb798, 0xb798,
+ 0xb7b4, 0xb7b4,
+ 0xb7d0, 0xb7d0,
+ 0xb7ec, 0xb7ec,
+ 0xb808, 0xb808,
+ 0xb824, 0xb824,
+ 0xb840, 0xb840,
+ 0xb85c, 0xb85c,
+ 0xb878, 0xb878,
+ 0xb894, 0xb894,
+ 0xb8b0, 0xb8b0,
+ 0xb8cc, 0xb8cc,
+ 0xb8e8, 0xb8e8,
+ 0xb904, 0xb904,
+ 0xb920, 0xb920,
+ 0xb93c, 0xb93c,
+ 0xb958, 0xb958,
+ 0xb974, 0xb974,
+ 0xb990, 0xb990,
+ 0xb9ac, 0xb9ac,
+ 0xb9c8, 0xb9c8,
+ 0xb9e4, 0xb9e4,
+ 0xba00, 0xba00,
+ 0xba1c, 0xba1c,
+ 0xba38, 0xba38,
+ 0xba54, 0xba54,
+ 0xba70, 0xba70,
+ 0xba8c, 0xba8c,
+ 0xbaa8, 0xbaa8,
+ 0xbac4, 0xbac4,
+ 0xbae0, 0xbae0,
+ 0xbafc, 0xbafc,
+ 0xbb18, 0xbb18,
+ 0xbb34, 0xbb34,
+ 0xbb50, 0xbb50,
+ 0xbb6c, 0xbb6c,
+ 0xbb88, 0xbb88,
+ 0xbba4, 0xbba4,
+ 0xbbc0, 0xbbc0,
+ 0xbbdc, 0xbbdc,
+ 0xbbf8, 0xbbf8,
+ 0xbc14, 0xbc14,
+ 0xbc30, 0xbc30,
+ 0xbc4c, 0xbc4c,
+ 0xbc68, 0xbc68,
+ 0xbc84, 0xbc84,
+ 0xbca0, 0xbca0,
+ 0xbcbc, 0xbcbc,
+ 0xbcd8, 0xbcd8,
+ 0xbcf4, 0xbcf4,
+ 0xbd10, 0xbd10,
+ 0xbd2c, 0xbd2c,
+ 0xbd48, 0xbd48,
+ 0xbd64, 0xbd64,
+ 0xbd80, 0xbd80,
+ 0xbd9c, 0xbd9c,
+ 0xbdb8, 0xbdb8,
+ 0xbdd4, 0xbdd4,
+ 0xbdf0, 0xbdf0,
+ 0xbe0c, 0xbe0c,
+ 0xbe28, 0xbe28,
+ 0xbe44, 0xbe44,
+ 0xbe60, 0xbe60,
+ 0xbe7c, 0xbe7c,
+ 0xbe98, 0xbe98,
+ 0xbeb4, 0xbeb4,
+ 0xbed0, 0xbed0,
+ 0xbeec, 0xbeec,
+ 0xbf08, 0xbf08,
+ 0xbf24, 0xbf24,
+ 0xbf40, 0xbf40,
+ 0xbf5c, 0xbf5c,
+ 0xbf78, 0xbf78,
+ 0xbf94, 0xbf94,
+ 0xbfb0, 0xbfb0,
+ 0xbfcc, 0xbfcc,
+ 0xbfe8, 0xbfe8,
+ 0xc004, 0xc004,
+ 0xc020, 0xc020,
+ 0xc03c, 0xc03c,
+ 0xc058, 0xc058,
+ 0xc074, 0xc074,
+ 0xc090, 0xc090,
+ 0xc0ac, 0xc0ac,
+ 0xc0c8, 0xc0c8,
+ 0xc0e4, 0xc0e4,
+ 0xc100, 0xc100,
+ 0xc11c, 0xc11c,
+ 0xc138, 0xc138,
+ 0xc154, 0xc154,
+ 0xc170, 0xc170,
+ 0xc18c, 0xc18c,
+ 0xc1a8, 0xc1a8,
+ 0xc1c4, 0xc1c4,
+ 0xc1e0, 0xc1e0,
+ 0xc1fc, 0xc1fc,
+ 0xc218, 0xc218,
+ 0xc234, 0xc234,
+ 0xc250, 0xc250,
+ 0xc26c, 0xc26c,
+ 0xc288, 0xc288,
+ 0xc2a4, 0xc2a4,
+ 0xc2c0, 0xc2c0,
+ 0xc2dc, 0xc2dc,
+ 0xc2f8, 0xc2f8,
+ 0xc314, 0xc314,
+ 0xc330, 0xc330,
+ 0xc34c, 0xc34c,
+ 0xc368, 0xc368,
+ 0xc384, 0xc384,
+ 0xc3a0, 0xc3a0,
+ 0xc3bc, 0xc3bc,
+ 0xc3d8, 0xc3d8,
+ 0xc3f4, 0xc3f4,
+ 0xc410, 0xc410,
+ 0xc42c, 0xc42c,
+ 0xc448, 0xc448,
+ 0xc464, 0xc464,
+ 0xc480, 0xc480,
+ 0xc49c, 0xc49c,
+ 0xc4b8, 0xc4b8,
+ 0xc4d4, 0xc4d4,
+ 0xc4f0, 0xc4f0,
+ 0xc50c, 0xc50c,
+ 0xc528, 0xc528,
+ 0xc544, 0xc544,
+ 0xc560, 0xc560,
+ 0xc57c, 0xc57c,
+ 0xc598, 0xc598,
+ 0xc5b4, 0xc5b4,
+ 0xc5d0, 0xc5d0,
+ 0xc5ec, 0xc5ec,
+ 0xc608, 0xc608,
+ 0xc624, 0xc624,
+ 0xc640, 0xc640,
+ 0xc65c, 0xc65c,
+ 0xc678, 0xc678,
+ 0xc694, 0xc694,
+ 0xc6b0, 0xc6b0,
+ 0xc6cc, 0xc6cc,
+ 0xc6e8, 0xc6e8,
+ 0xc704, 0xc704,
+ 0xc720, 0xc720,
+ 0xc73c, 0xc73c,
+ 0xc758, 0xc758,
+ 0xc774, 0xc774,
+ 0xc790, 0xc790,
+ 0xc7ac, 0xc7ac,
+ 0xc7c8, 0xc7c8,
+ 0xc7e4, 0xc7e4,
+ 0xc800, 0xc800,
+ 0xc81c, 0xc81c,
+ 0xc838, 0xc838,
+ 0xc854, 0xc854,
+ 0xc870, 0xc870,
+ 0xc88c, 0xc88c,
+ 0xc8a8, 0xc8a8,
+ 0xc8c4, 0xc8c4,
+ 0xc8e0, 0xc8e0,
+ 0xc8fc, 0xc8fc,
+ 0xc918, 0xc918,
+ 0xc934, 0xc934,
+ 0xc950, 0xc950,
+ 0xc96c, 0xc96c,
+ 0xc988, 0xc988,
+ 0xc9a4, 0xc9a4,
+ 0xc9c0, 0xc9c0,
+ 0xc9dc, 0xc9dc,
+ 0xc9f8, 0xc9f8,
+ 0xca14, 0xca14,
+ 0xca30, 0xca30,
+ 0xca4c, 0xca4c,
+ 0xca68, 0xca68,
+ 0xca84, 0xca84,
+ 0xcaa0, 0xcaa0,
+ 0xcabc, 0xcabc,
+ 0xcad8, 0xcad8,
+ 0xcaf4, 0xcaf4,
+ 0xcb10, 0xcb10,
+ 0xcb2c, 0xcb2c,
+ 0xcb48, 0xcb48,
+ 0xcb64, 0xcb64,
+ 0xcb80, 0xcb80,
+ 0xcb9c, 0xcb9c,
+ 0xcbb8, 0xcbb8,
+ 0xcbd4, 0xcbd4,
+ 0xcbf0, 0xcbf0,
+ 0xcc0c, 0xcc0c,
+ 0xcc28, 0xcc28,
+ 0xcc44, 0xcc44,
+ 0xcc60, 0xcc60,
+ 0xcc7c, 0xcc7c,
+ 0xcc98, 0xcc98,
+ 0xccb4, 0xccb4,
+ 0xccd0, 0xccd0,
+ 0xccec, 0xccec,
+ 0xcd08, 0xcd08,
+ 0xcd24, 0xcd24,
+ 0xcd40, 0xcd40,
+ 0xcd5c, 0xcd5c,
+ 0xcd78, 0xcd78,
+ 0xcd94, 0xcd94,
+ 0xcdb0, 0xcdb0,
+ 0xcdcc, 0xcdcc,
+ 0xcde8, 0xcde8,
+ 0xce04, 0xce04,
+ 0xce20, 0xce20,
+ 0xce3c, 0xce3c,
+ 0xce58, 0xce58,
+ 0xce74, 0xce74,
+ 0xce90, 0xce90,
+ 0xceac, 0xceac,
+ 0xcec8, 0xcec8,
+ 0xcee4, 0xcee4,
+ 0xcf00, 0xcf00,
+ 0xcf1c, 0xcf1c,
+ 0xcf38, 0xcf38,
+ 0xcf54, 0xcf54,
+ 0xcf70, 0xcf70,
+ 0xcf8c, 0xcf8c,
+ 0xcfa8, 0xcfa8,
+ 0xcfc4, 0xcfc4,
+ 0xcfe0, 0xcfe0,
+ 0xcffc, 0xcffc,
+ 0xd018, 0xd018,
+ 0xd034, 0xd034,
+ 0xd050, 0xd050,
+ 0xd06c, 0xd06c,
+ 0xd088, 0xd088,
+ 0xd0a4, 0xd0a4,
+ 0xd0c0, 0xd0c0,
+ 0xd0dc, 0xd0dc,
+ 0xd0f8, 0xd0f8,
+ 0xd114, 0xd114,
+ 0xd130, 0xd130,
+ 0xd14c, 0xd14c,
+ 0xd168, 0xd168,
+ 0xd184, 0xd184,
+ 0xd1a0, 0xd1a0,
+ 0xd1bc, 0xd1bc,
+ 0xd1d8, 0xd1d8,
+ 0xd1f4, 0xd1f4,
+ 0xd210, 0xd210,
+ 0xd22c, 0xd22c,
+ 0xd248, 0xd248,
+ 0xd264, 0xd264,
+ 0xd280, 0xd280,
+ 0xd29c, 0xd29c,
+ 0xd2b8, 0xd2b8,
+ 0xd2d4, 0xd2d4,
+ 0xd2f0, 0xd2f0,
+ 0xd30c, 0xd30c,
+ 0xd328, 0xd328,
+ 0xd344, 0xd344,
+ 0xd360, 0xd360,
+ 0xd37c, 0xd37c,
+ 0xd398, 0xd398,
+ 0xd3b4, 0xd3b4,
+ 0xd3d0, 0xd3d0,
+ 0xd3ec, 0xd3ec,
+ 0xd408, 0xd408,
+ 0xd424, 0xd424,
+ 0xd440, 0xd440,
+ 0xd45c, 0xd45c,
+ 0xd478, 0xd478,
+ 0xd494, 0xd494,
+ 0xd4b0, 0xd4b0,
+ 0xd4cc, 0xd4cc,
+ 0xd4e8, 0xd4e8,
+ 0xd504, 0xd504,
+ 0xd520, 0xd520,
+ 0xd53c, 0xd53c,
+ 0xd558, 0xd558,
+ 0xd574, 0xd574,
+ 0xd590, 0xd590,
+ 0xd5ac, 0xd5ac,
+ 0xd5c8, 0xd5c8,
+ 0xd5e4, 0xd5e4,
+ 0xd600, 0xd600,
+ 0xd61c, 0xd61c,
+ 0xd638, 0xd638,
+ 0xd654, 0xd654,
+ 0xd670, 0xd670,
+ 0xd68c, 0xd68c,
+ 0xd6a8, 0xd6a8,
+ 0xd6c4, 0xd6c4,
+ 0xd6e0, 0xd6e0,
+ 0xd6fc, 0xd6fc,
+ 0xd718, 0xd718,
+ 0xd734, 0xd734,
+ 0xd750, 0xd750,
+ 0xd76c, 0xd76c,
+ 0xd788, 0xd788,
+}; /* CR_Grapheme_Cluster_Break_LV */
+
+/* 'Grapheme_Cluster_Break_LVT': Grapheme_Cluster_Break=LVT */
+static const OnigCodePoint CR_Grapheme_Cluster_Break_LVT[] = {
+ 399,
+ 0xac01, 0xac1b,
+ 0xac1d, 0xac37,
+ 0xac39, 0xac53,
+ 0xac55, 0xac6f,
+ 0xac71, 0xac8b,
+ 0xac8d, 0xaca7,
+ 0xaca9, 0xacc3,
+ 0xacc5, 0xacdf,
+ 0xace1, 0xacfb,
+ 0xacfd, 0xad17,
+ 0xad19, 0xad33,
+ 0xad35, 0xad4f,
+ 0xad51, 0xad6b,
+ 0xad6d, 0xad87,
+ 0xad89, 0xada3,
+ 0xada5, 0xadbf,
+ 0xadc1, 0xaddb,
+ 0xaddd, 0xadf7,
+ 0xadf9, 0xae13,
+ 0xae15, 0xae2f,
+ 0xae31, 0xae4b,
+ 0xae4d, 0xae67,
+ 0xae69, 0xae83,
+ 0xae85, 0xae9f,
+ 0xaea1, 0xaebb,
+ 0xaebd, 0xaed7,
+ 0xaed9, 0xaef3,
+ 0xaef5, 0xaf0f,
+ 0xaf11, 0xaf2b,
+ 0xaf2d, 0xaf47,
+ 0xaf49, 0xaf63,
+ 0xaf65, 0xaf7f,
+ 0xaf81, 0xaf9b,
+ 0xaf9d, 0xafb7,
+ 0xafb9, 0xafd3,
+ 0xafd5, 0xafef,
+ 0xaff1, 0xb00b,
+ 0xb00d, 0xb027,
+ 0xb029, 0xb043,
+ 0xb045, 0xb05f,
+ 0xb061, 0xb07b,
+ 0xb07d, 0xb097,
+ 0xb099, 0xb0b3,
+ 0xb0b5, 0xb0cf,
+ 0xb0d1, 0xb0eb,
+ 0xb0ed, 0xb107,
+ 0xb109, 0xb123,
+ 0xb125, 0xb13f,
+ 0xb141, 0xb15b,
+ 0xb15d, 0xb177,
+ 0xb179, 0xb193,
+ 0xb195, 0xb1af,
+ 0xb1b1, 0xb1cb,
+ 0xb1cd, 0xb1e7,
+ 0xb1e9, 0xb203,
+ 0xb205, 0xb21f,
+ 0xb221, 0xb23b,
+ 0xb23d, 0xb257,
+ 0xb259, 0xb273,
+ 0xb275, 0xb28f,
+ 0xb291, 0xb2ab,
+ 0xb2ad, 0xb2c7,
+ 0xb2c9, 0xb2e3,
+ 0xb2e5, 0xb2ff,
+ 0xb301, 0xb31b,
+ 0xb31d, 0xb337,
+ 0xb339, 0xb353,
+ 0xb355, 0xb36f,
+ 0xb371, 0xb38b,
+ 0xb38d, 0xb3a7,
+ 0xb3a9, 0xb3c3,
+ 0xb3c5, 0xb3df,
+ 0xb3e1, 0xb3fb,
+ 0xb3fd, 0xb417,
+ 0xb419, 0xb433,
+ 0xb435, 0xb44f,
+ 0xb451, 0xb46b,
+ 0xb46d, 0xb487,
+ 0xb489, 0xb4a3,
+ 0xb4a5, 0xb4bf,
+ 0xb4c1, 0xb4db,
+ 0xb4dd, 0xb4f7,
+ 0xb4f9, 0xb513,
+ 0xb515, 0xb52f,
+ 0xb531, 0xb54b,
+ 0xb54d, 0xb567,
+ 0xb569, 0xb583,
+ 0xb585, 0xb59f,
+ 0xb5a1, 0xb5bb,
+ 0xb5bd, 0xb5d7,
+ 0xb5d9, 0xb5f3,
+ 0xb5f5, 0xb60f,
+ 0xb611, 0xb62b,
+ 0xb62d, 0xb647,
+ 0xb649, 0xb663,
+ 0xb665, 0xb67f,
+ 0xb681, 0xb69b,
+ 0xb69d, 0xb6b7,
+ 0xb6b9, 0xb6d3,
+ 0xb6d5, 0xb6ef,
+ 0xb6f1, 0xb70b,
+ 0xb70d, 0xb727,
+ 0xb729, 0xb743,
+ 0xb745, 0xb75f,
+ 0xb761, 0xb77b,
+ 0xb77d, 0xb797,
+ 0xb799, 0xb7b3,
+ 0xb7b5, 0xb7cf,
+ 0xb7d1, 0xb7eb,
+ 0xb7ed, 0xb807,
+ 0xb809, 0xb823,
+ 0xb825, 0xb83f,
+ 0xb841, 0xb85b,
+ 0xb85d, 0xb877,
+ 0xb879, 0xb893,
+ 0xb895, 0xb8af,
+ 0xb8b1, 0xb8cb,
+ 0xb8cd, 0xb8e7,
+ 0xb8e9, 0xb903,
+ 0xb905, 0xb91f,
+ 0xb921, 0xb93b,
+ 0xb93d, 0xb957,
+ 0xb959, 0xb973,
+ 0xb975, 0xb98f,
+ 0xb991, 0xb9ab,
+ 0xb9ad, 0xb9c7,
+ 0xb9c9, 0xb9e3,
+ 0xb9e5, 0xb9ff,
+ 0xba01, 0xba1b,
+ 0xba1d, 0xba37,
+ 0xba39, 0xba53,
+ 0xba55, 0xba6f,
+ 0xba71, 0xba8b,
+ 0xba8d, 0xbaa7,
+ 0xbaa9, 0xbac3,
+ 0xbac5, 0xbadf,
+ 0xbae1, 0xbafb,
+ 0xbafd, 0xbb17,
+ 0xbb19, 0xbb33,
+ 0xbb35, 0xbb4f,
+ 0xbb51, 0xbb6b,
+ 0xbb6d, 0xbb87,
+ 0xbb89, 0xbba3,
+ 0xbba5, 0xbbbf,
+ 0xbbc1, 0xbbdb,
+ 0xbbdd, 0xbbf7,
+ 0xbbf9, 0xbc13,
+ 0xbc15, 0xbc2f,
+ 0xbc31, 0xbc4b,
+ 0xbc4d, 0xbc67,
+ 0xbc69, 0xbc83,
+ 0xbc85, 0xbc9f,
+ 0xbca1, 0xbcbb,
+ 0xbcbd, 0xbcd7,
+ 0xbcd9, 0xbcf3,
+ 0xbcf5, 0xbd0f,
+ 0xbd11, 0xbd2b,
+ 0xbd2d, 0xbd47,
+ 0xbd49, 0xbd63,
+ 0xbd65, 0xbd7f,
+ 0xbd81, 0xbd9b,
+ 0xbd9d, 0xbdb7,
+ 0xbdb9, 0xbdd3,
+ 0xbdd5, 0xbdef,
+ 0xbdf1, 0xbe0b,
+ 0xbe0d, 0xbe27,
+ 0xbe29, 0xbe43,
+ 0xbe45, 0xbe5f,
+ 0xbe61, 0xbe7b,
+ 0xbe7d, 0xbe97,
+ 0xbe99, 0xbeb3,
+ 0xbeb5, 0xbecf,
+ 0xbed1, 0xbeeb,
+ 0xbeed, 0xbf07,
+ 0xbf09, 0xbf23,
+ 0xbf25, 0xbf3f,
+ 0xbf41, 0xbf5b,
+ 0xbf5d, 0xbf77,
+ 0xbf79, 0xbf93,
+ 0xbf95, 0xbfaf,
+ 0xbfb1, 0xbfcb,
+ 0xbfcd, 0xbfe7,
+ 0xbfe9, 0xc003,
+ 0xc005, 0xc01f,
+ 0xc021, 0xc03b,
+ 0xc03d, 0xc057,
+ 0xc059, 0xc073,
+ 0xc075, 0xc08f,
+ 0xc091, 0xc0ab,
+ 0xc0ad, 0xc0c7,
+ 0xc0c9, 0xc0e3,
+ 0xc0e5, 0xc0ff,
+ 0xc101, 0xc11b,
+ 0xc11d, 0xc137,
+ 0xc139, 0xc153,
+ 0xc155, 0xc16f,
+ 0xc171, 0xc18b,
+ 0xc18d, 0xc1a7,
+ 0xc1a9, 0xc1c3,
+ 0xc1c5, 0xc1df,
+ 0xc1e1, 0xc1fb,
+ 0xc1fd, 0xc217,
+ 0xc219, 0xc233,
+ 0xc235, 0xc24f,
+ 0xc251, 0xc26b,
+ 0xc26d, 0xc287,
+ 0xc289, 0xc2a3,
+ 0xc2a5, 0xc2bf,
+ 0xc2c1, 0xc2db,
+ 0xc2dd, 0xc2f7,
+ 0xc2f9, 0xc313,
+ 0xc315, 0xc32f,
+ 0xc331, 0xc34b,
+ 0xc34d, 0xc367,
+ 0xc369, 0xc383,
+ 0xc385, 0xc39f,
+ 0xc3a1, 0xc3bb,
+ 0xc3bd, 0xc3d7,
+ 0xc3d9, 0xc3f3,
+ 0xc3f5, 0xc40f,
+ 0xc411, 0xc42b,
+ 0xc42d, 0xc447,
+ 0xc449, 0xc463,
+ 0xc465, 0xc47f,
+ 0xc481, 0xc49b,
+ 0xc49d, 0xc4b7,
+ 0xc4b9, 0xc4d3,
+ 0xc4d5, 0xc4ef,
+ 0xc4f1, 0xc50b,
+ 0xc50d, 0xc527,
+ 0xc529, 0xc543,
+ 0xc545, 0xc55f,
+ 0xc561, 0xc57b,
+ 0xc57d, 0xc597,
+ 0xc599, 0xc5b3,
+ 0xc5b5, 0xc5cf,
+ 0xc5d1, 0xc5eb,
+ 0xc5ed, 0xc607,
+ 0xc609, 0xc623,
+ 0xc625, 0xc63f,
+ 0xc641, 0xc65b,
+ 0xc65d, 0xc677,
+ 0xc679, 0xc693,
+ 0xc695, 0xc6af,
+ 0xc6b1, 0xc6cb,
+ 0xc6cd, 0xc6e7,
+ 0xc6e9, 0xc703,
+ 0xc705, 0xc71f,
+ 0xc721, 0xc73b,
+ 0xc73d, 0xc757,
+ 0xc759, 0xc773,
+ 0xc775, 0xc78f,
+ 0xc791, 0xc7ab,
+ 0xc7ad, 0xc7c7,
+ 0xc7c9, 0xc7e3,
+ 0xc7e5, 0xc7ff,
+ 0xc801, 0xc81b,
+ 0xc81d, 0xc837,
+ 0xc839, 0xc853,
+ 0xc855, 0xc86f,
+ 0xc871, 0xc88b,
+ 0xc88d, 0xc8a7,
+ 0xc8a9, 0xc8c3,
+ 0xc8c5, 0xc8df,
+ 0xc8e1, 0xc8fb,
+ 0xc8fd, 0xc917,
+ 0xc919, 0xc933,
+ 0xc935, 0xc94f,
+ 0xc951, 0xc96b,
+ 0xc96d, 0xc987,
+ 0xc989, 0xc9a3,
+ 0xc9a5, 0xc9bf,
+ 0xc9c1, 0xc9db,
+ 0xc9dd, 0xc9f7,
+ 0xc9f9, 0xca13,
+ 0xca15, 0xca2f,
+ 0xca31, 0xca4b,
+ 0xca4d, 0xca67,
+ 0xca69, 0xca83,
+ 0xca85, 0xca9f,
+ 0xcaa1, 0xcabb,
+ 0xcabd, 0xcad7,
+ 0xcad9, 0xcaf3,
+ 0xcaf5, 0xcb0f,
+ 0xcb11, 0xcb2b,
+ 0xcb2d, 0xcb47,
+ 0xcb49, 0xcb63,
+ 0xcb65, 0xcb7f,
+ 0xcb81, 0xcb9b,
+ 0xcb9d, 0xcbb7,
+ 0xcbb9, 0xcbd3,
+ 0xcbd5, 0xcbef,
+ 0xcbf1, 0xcc0b,
+ 0xcc0d, 0xcc27,
+ 0xcc29, 0xcc43,
+ 0xcc45, 0xcc5f,
+ 0xcc61, 0xcc7b,
+ 0xcc7d, 0xcc97,
+ 0xcc99, 0xccb3,
+ 0xccb5, 0xcccf,
+ 0xccd1, 0xcceb,
+ 0xcced, 0xcd07,
+ 0xcd09, 0xcd23,
+ 0xcd25, 0xcd3f,
+ 0xcd41, 0xcd5b,
+ 0xcd5d, 0xcd77,
+ 0xcd79, 0xcd93,
+ 0xcd95, 0xcdaf,
+ 0xcdb1, 0xcdcb,
+ 0xcdcd, 0xcde7,
+ 0xcde9, 0xce03,
+ 0xce05, 0xce1f,
+ 0xce21, 0xce3b,
+ 0xce3d, 0xce57,
+ 0xce59, 0xce73,
+ 0xce75, 0xce8f,
+ 0xce91, 0xceab,
+ 0xcead, 0xcec7,
+ 0xcec9, 0xcee3,
+ 0xcee5, 0xceff,
+ 0xcf01, 0xcf1b,
+ 0xcf1d, 0xcf37,
+ 0xcf39, 0xcf53,
+ 0xcf55, 0xcf6f,
+ 0xcf71, 0xcf8b,
+ 0xcf8d, 0xcfa7,
+ 0xcfa9, 0xcfc3,
+ 0xcfc5, 0xcfdf,
+ 0xcfe1, 0xcffb,
+ 0xcffd, 0xd017,
+ 0xd019, 0xd033,
+ 0xd035, 0xd04f,
+ 0xd051, 0xd06b,
+ 0xd06d, 0xd087,
+ 0xd089, 0xd0a3,
+ 0xd0a5, 0xd0bf,
+ 0xd0c1, 0xd0db,
+ 0xd0dd, 0xd0f7,
+ 0xd0f9, 0xd113,
+ 0xd115, 0xd12f,
+ 0xd131, 0xd14b,
+ 0xd14d, 0xd167,
+ 0xd169, 0xd183,
+ 0xd185, 0xd19f,
+ 0xd1a1, 0xd1bb,
+ 0xd1bd, 0xd1d7,
+ 0xd1d9, 0xd1f3,
+ 0xd1f5, 0xd20f,
+ 0xd211, 0xd22b,
+ 0xd22d, 0xd247,
+ 0xd249, 0xd263,
+ 0xd265, 0xd27f,
+ 0xd281, 0xd29b,
+ 0xd29d, 0xd2b7,
+ 0xd2b9, 0xd2d3,
+ 0xd2d5, 0xd2ef,
+ 0xd2f1, 0xd30b,
+ 0xd30d, 0xd327,
+ 0xd329, 0xd343,
+ 0xd345, 0xd35f,
+ 0xd361, 0xd37b,
+ 0xd37d, 0xd397,
+ 0xd399, 0xd3b3,
+ 0xd3b5, 0xd3cf,
+ 0xd3d1, 0xd3eb,
+ 0xd3ed, 0xd407,
+ 0xd409, 0xd423,
+ 0xd425, 0xd43f,
+ 0xd441, 0xd45b,
+ 0xd45d, 0xd477,
+ 0xd479, 0xd493,
+ 0xd495, 0xd4af,
+ 0xd4b1, 0xd4cb,
+ 0xd4cd, 0xd4e7,
+ 0xd4e9, 0xd503,
+ 0xd505, 0xd51f,
+ 0xd521, 0xd53b,
+ 0xd53d, 0xd557,
+ 0xd559, 0xd573,
+ 0xd575, 0xd58f,
+ 0xd591, 0xd5ab,
+ 0xd5ad, 0xd5c7,
+ 0xd5c9, 0xd5e3,
+ 0xd5e5, 0xd5ff,
+ 0xd601, 0xd61b,
+ 0xd61d, 0xd637,
+ 0xd639, 0xd653,
+ 0xd655, 0xd66f,
+ 0xd671, 0xd68b,
+ 0xd68d, 0xd6a7,
+ 0xd6a9, 0xd6c3,
+ 0xd6c5, 0xd6df,
+ 0xd6e1, 0xd6fb,
+ 0xd6fd, 0xd717,
+ 0xd719, 0xd733,
+ 0xd735, 0xd74f,
+ 0xd751, 0xd76b,
+ 0xd76d, 0xd787,
+ 0xd789, 0xd7a3,
+}; /* CR_Grapheme_Cluster_Break_LVT */
+
+/* 'Grapheme_Cluster_Break_ZWJ': Grapheme_Cluster_Break=ZWJ */
+static const OnigCodePoint CR_Grapheme_Cluster_Break_ZWJ[] = {
+ 1,
+ 0x200d, 0x200d,
+}; /* CR_Grapheme_Cluster_Break_ZWJ */
+
+/* 'In_Basic_Latin': Block */
+#define CR_In_Basic_Latin CR_ASCII
+
+/* 'In_Latin_1_Supplement': Block */
+static const OnigCodePoint CR_In_Latin_1_Supplement[] = {
+ 1,
+ 0x0080, 0x00ff,
+}; /* CR_In_Latin_1_Supplement */
+
+/* 'In_Latin_Extended_A': Block */
+static const OnigCodePoint CR_In_Latin_Extended_A[] = {
+ 1,
+ 0x0100, 0x017f,
+}; /* CR_In_Latin_Extended_A */
+
+/* 'In_Latin_Extended_B': Block */
+static const OnigCodePoint CR_In_Latin_Extended_B[] = {
+ 1,
+ 0x0180, 0x024f,
+}; /* CR_In_Latin_Extended_B */
+
+/* 'In_IPA_Extensions': Block */
+static const OnigCodePoint CR_In_IPA_Extensions[] = {
+ 1,
+ 0x0250, 0x02af,
+}; /* CR_In_IPA_Extensions */
+
+/* 'In_Spacing_Modifier_Letters': Block */
+static const OnigCodePoint CR_In_Spacing_Modifier_Letters[] = {
+ 1,
+ 0x02b0, 0x02ff,
+}; /* CR_In_Spacing_Modifier_Letters */
+
+/* 'In_Combining_Diacritical_Marks': Block */
+static const OnigCodePoint CR_In_Combining_Diacritical_Marks[] = {
+ 1,
+ 0x0300, 0x036f,
+}; /* CR_In_Combining_Diacritical_Marks */
+
+/* 'In_Greek_and_Coptic': Block */
+static const OnigCodePoint CR_In_Greek_and_Coptic[] = {
+ 1,
+ 0x0370, 0x03ff,
+}; /* CR_In_Greek_and_Coptic */
+
+/* 'In_Cyrillic': Block */
+static const OnigCodePoint CR_In_Cyrillic[] = {
+ 1,
+ 0x0400, 0x04ff,
+}; /* CR_In_Cyrillic */
+
+/* 'In_Cyrillic_Supplement': Block */
+static const OnigCodePoint CR_In_Cyrillic_Supplement[] = {
+ 1,
+ 0x0500, 0x052f,
+}; /* CR_In_Cyrillic_Supplement */
+
+/* 'In_Armenian': Block */
+static const OnigCodePoint CR_In_Armenian[] = {
+ 1,
+ 0x0530, 0x058f,
+}; /* CR_In_Armenian */
+
+/* 'In_Hebrew': Block */
+static const OnigCodePoint CR_In_Hebrew[] = {
+ 1,
+ 0x0590, 0x05ff,
+}; /* CR_In_Hebrew */
+
+/* 'In_Arabic': Block */
+static const OnigCodePoint CR_In_Arabic[] = {
+ 1,
+ 0x0600, 0x06ff,
+}; /* CR_In_Arabic */
+
+/* 'In_Syriac': Block */
+static const OnigCodePoint CR_In_Syriac[] = {
+ 1,
+ 0x0700, 0x074f,
+}; /* CR_In_Syriac */
+
+/* 'In_Arabic_Supplement': Block */
+static const OnigCodePoint CR_In_Arabic_Supplement[] = {
+ 1,
+ 0x0750, 0x077f,
+}; /* CR_In_Arabic_Supplement */
+
+/* 'In_Thaana': Block */
+static const OnigCodePoint CR_In_Thaana[] = {
+ 1,
+ 0x0780, 0x07bf,
+}; /* CR_In_Thaana */
+
+/* 'In_NKo': Block */
+static const OnigCodePoint CR_In_NKo[] = {
+ 1,
+ 0x07c0, 0x07ff,
+}; /* CR_In_NKo */
+
+/* 'In_Samaritan': Block */
+static const OnigCodePoint CR_In_Samaritan[] = {
+ 1,
+ 0x0800, 0x083f,
+}; /* CR_In_Samaritan */
+
+/* 'In_Mandaic': Block */
+static const OnigCodePoint CR_In_Mandaic[] = {
+ 1,
+ 0x0840, 0x085f,
+}; /* CR_In_Mandaic */
+
+/* 'In_Syriac_Supplement': Block */
+static const OnigCodePoint CR_In_Syriac_Supplement[] = {
+ 1,
+ 0x0860, 0x086f,
+}; /* CR_In_Syriac_Supplement */
+
+/* 'In_Arabic_Extended_B': Block */
+static const OnigCodePoint CR_In_Arabic_Extended_B[] = {
+ 1,
+ 0x0870, 0x089f,
+}; /* CR_In_Arabic_Extended_B */
+
+/* 'In_Arabic_Extended_A': Block */
+static const OnigCodePoint CR_In_Arabic_Extended_A[] = {
+ 1,
+ 0x08a0, 0x08ff,
+}; /* CR_In_Arabic_Extended_A */
+
+/* 'In_Devanagari': Block */
+static const OnigCodePoint CR_In_Devanagari[] = {
+ 1,
+ 0x0900, 0x097f,
+}; /* CR_In_Devanagari */
+
+/* 'In_Bengali': Block */
+static const OnigCodePoint CR_In_Bengali[] = {
+ 1,
+ 0x0980, 0x09ff,
+}; /* CR_In_Bengali */
+
+/* 'In_Gurmukhi': Block */
+static const OnigCodePoint CR_In_Gurmukhi[] = {
+ 1,
+ 0x0a00, 0x0a7f,
+}; /* CR_In_Gurmukhi */
+
+/* 'In_Gujarati': Block */
+static const OnigCodePoint CR_In_Gujarati[] = {
+ 1,
+ 0x0a80, 0x0aff,
+}; /* CR_In_Gujarati */
+
+/* 'In_Oriya': Block */
+static const OnigCodePoint CR_In_Oriya[] = {
+ 1,
+ 0x0b00, 0x0b7f,
+}; /* CR_In_Oriya */
+
+/* 'In_Tamil': Block */
+static const OnigCodePoint CR_In_Tamil[] = {
+ 1,
+ 0x0b80, 0x0bff,
+}; /* CR_In_Tamil */
+
+/* 'In_Telugu': Block */
+static const OnigCodePoint CR_In_Telugu[] = {
+ 1,
+ 0x0c00, 0x0c7f,
+}; /* CR_In_Telugu */
+
+/* 'In_Kannada': Block */
+static const OnigCodePoint CR_In_Kannada[] = {
+ 1,
+ 0x0c80, 0x0cff,
+}; /* CR_In_Kannada */
+
+/* 'In_Malayalam': Block */
+static const OnigCodePoint CR_In_Malayalam[] = {
+ 1,
+ 0x0d00, 0x0d7f,
+}; /* CR_In_Malayalam */
+
+/* 'In_Sinhala': Block */
+static const OnigCodePoint CR_In_Sinhala[] = {
+ 1,
+ 0x0d80, 0x0dff,
+}; /* CR_In_Sinhala */
+
+/* 'In_Thai': Block */
+static const OnigCodePoint CR_In_Thai[] = {
+ 1,
+ 0x0e00, 0x0e7f,
+}; /* CR_In_Thai */
+
+/* 'In_Lao': Block */
+static const OnigCodePoint CR_In_Lao[] = {
+ 1,
+ 0x0e80, 0x0eff,
+}; /* CR_In_Lao */
+
+/* 'In_Tibetan': Block */
+static const OnigCodePoint CR_In_Tibetan[] = {
+ 1,
+ 0x0f00, 0x0fff,
+}; /* CR_In_Tibetan */
+
+/* 'In_Myanmar': Block */
+static const OnigCodePoint CR_In_Myanmar[] = {
+ 1,
+ 0x1000, 0x109f,
+}; /* CR_In_Myanmar */
+
+/* 'In_Georgian': Block */
+static const OnigCodePoint CR_In_Georgian[] = {
+ 1,
+ 0x10a0, 0x10ff,
+}; /* CR_In_Georgian */
+
+/* 'In_Hangul_Jamo': Block */
+static const OnigCodePoint CR_In_Hangul_Jamo[] = {
+ 1,
+ 0x1100, 0x11ff,
+}; /* CR_In_Hangul_Jamo */
+
+/* 'In_Ethiopic': Block */
+static const OnigCodePoint CR_In_Ethiopic[] = {
+ 1,
+ 0x1200, 0x137f,
+}; /* CR_In_Ethiopic */
+
+/* 'In_Ethiopic_Supplement': Block */
+static const OnigCodePoint CR_In_Ethiopic_Supplement[] = {
+ 1,
+ 0x1380, 0x139f,
+}; /* CR_In_Ethiopic_Supplement */
+
+/* 'In_Cherokee': Block */
+static const OnigCodePoint CR_In_Cherokee[] = {
+ 1,
+ 0x13a0, 0x13ff,
+}; /* CR_In_Cherokee */
+
+/* 'In_Unified_Canadian_Aboriginal_Syllabics': Block */
+static const OnigCodePoint CR_In_Unified_Canadian_Aboriginal_Syllabics[] = {
+ 1,
+ 0x1400, 0x167f,
+}; /* CR_In_Unified_Canadian_Aboriginal_Syllabics */
+
+/* 'In_Ogham': Block */
+static const OnigCodePoint CR_In_Ogham[] = {
+ 1,
+ 0x1680, 0x169f,
+}; /* CR_In_Ogham */
+
+/* 'In_Runic': Block */
+static const OnigCodePoint CR_In_Runic[] = {
+ 1,
+ 0x16a0, 0x16ff,
+}; /* CR_In_Runic */
+
+/* 'In_Tagalog': Block */
+static const OnigCodePoint CR_In_Tagalog[] = {
+ 1,
+ 0x1700, 0x171f,
+}; /* CR_In_Tagalog */
+
+/* 'In_Hanunoo': Block */
+static const OnigCodePoint CR_In_Hanunoo[] = {
+ 1,
+ 0x1720, 0x173f,
+}; /* CR_In_Hanunoo */
+
+/* 'In_Buhid': Block */
+static const OnigCodePoint CR_In_Buhid[] = {
+ 1,
+ 0x1740, 0x175f,
+}; /* CR_In_Buhid */
+
+/* 'In_Tagbanwa': Block */
+static const OnigCodePoint CR_In_Tagbanwa[] = {
+ 1,
+ 0x1760, 0x177f,
+}; /* CR_In_Tagbanwa */
+
+/* 'In_Khmer': Block */
+static const OnigCodePoint CR_In_Khmer[] = {
+ 1,
+ 0x1780, 0x17ff,
+}; /* CR_In_Khmer */
+
+/* 'In_Mongolian': Block */
+static const OnigCodePoint CR_In_Mongolian[] = {
+ 1,
+ 0x1800, 0x18af,
+}; /* CR_In_Mongolian */
+
+/* 'In_Unified_Canadian_Aboriginal_Syllabics_Extended': Block */
+static const OnigCodePoint CR_In_Unified_Canadian_Aboriginal_Syllabics_Extended[] = {
+ 1,
+ 0x18b0, 0x18ff,
+}; /* CR_In_Unified_Canadian_Aboriginal_Syllabics_Extended */
+
+/* 'In_Limbu': Block */
+static const OnigCodePoint CR_In_Limbu[] = {
+ 1,
+ 0x1900, 0x194f,
+}; /* CR_In_Limbu */
+
+/* 'In_Tai_Le': Block */
+static const OnigCodePoint CR_In_Tai_Le[] = {
+ 1,
+ 0x1950, 0x197f,
+}; /* CR_In_Tai_Le */
+
+/* 'In_New_Tai_Lue': Block */
+static const OnigCodePoint CR_In_New_Tai_Lue[] = {
+ 1,
+ 0x1980, 0x19df,
+}; /* CR_In_New_Tai_Lue */
+
+/* 'In_Khmer_Symbols': Block */
+static const OnigCodePoint CR_In_Khmer_Symbols[] = {
+ 1,
+ 0x19e0, 0x19ff,
+}; /* CR_In_Khmer_Symbols */
+
+/* 'In_Buginese': Block */
+static const OnigCodePoint CR_In_Buginese[] = {
+ 1,
+ 0x1a00, 0x1a1f,
+}; /* CR_In_Buginese */
+
+/* 'In_Tai_Tham': Block */
+static const OnigCodePoint CR_In_Tai_Tham[] = {
+ 1,
+ 0x1a20, 0x1aaf,
+}; /* CR_In_Tai_Tham */
+
+/* 'In_Combining_Diacritical_Marks_Extended': Block */
+static const OnigCodePoint CR_In_Combining_Diacritical_Marks_Extended[] = {
+ 1,
+ 0x1ab0, 0x1aff,
+}; /* CR_In_Combining_Diacritical_Marks_Extended */
+
+/* 'In_Balinese': Block */
+static const OnigCodePoint CR_In_Balinese[] = {
+ 1,
+ 0x1b00, 0x1b7f,
+}; /* CR_In_Balinese */
+
+/* 'In_Sundanese': Block */
+static const OnigCodePoint CR_In_Sundanese[] = {
+ 1,
+ 0x1b80, 0x1bbf,
+}; /* CR_In_Sundanese */
+
+/* 'In_Batak': Block */
+static const OnigCodePoint CR_In_Batak[] = {
+ 1,
+ 0x1bc0, 0x1bff,
+}; /* CR_In_Batak */
+
+/* 'In_Lepcha': Block */
+static const OnigCodePoint CR_In_Lepcha[] = {
+ 1,
+ 0x1c00, 0x1c4f,
+}; /* CR_In_Lepcha */
+
+/* 'In_Ol_Chiki': Block */
+#define CR_In_Ol_Chiki CR_Ol_Chiki
+
+/* 'In_Cyrillic_Extended_C': Block */
+static const OnigCodePoint CR_In_Cyrillic_Extended_C[] = {
+ 1,
+ 0x1c80, 0x1c8f,
+}; /* CR_In_Cyrillic_Extended_C */
+
+/* 'In_Georgian_Extended': Block */
+static const OnigCodePoint CR_In_Georgian_Extended[] = {
+ 1,
+ 0x1c90, 0x1cbf,
+}; /* CR_In_Georgian_Extended */
+
+/* 'In_Sundanese_Supplement': Block */
+static const OnigCodePoint CR_In_Sundanese_Supplement[] = {
+ 1,
+ 0x1cc0, 0x1ccf,
+}; /* CR_In_Sundanese_Supplement */
+
+/* 'In_Vedic_Extensions': Block */
+static const OnigCodePoint CR_In_Vedic_Extensions[] = {
+ 1,
+ 0x1cd0, 0x1cff,
+}; /* CR_In_Vedic_Extensions */
+
+/* 'In_Phonetic_Extensions': Block */
+static const OnigCodePoint CR_In_Phonetic_Extensions[] = {
+ 1,
+ 0x1d00, 0x1d7f,
+}; /* CR_In_Phonetic_Extensions */
+
+/* 'In_Phonetic_Extensions_Supplement': Block */
+static const OnigCodePoint CR_In_Phonetic_Extensions_Supplement[] = {
+ 1,
+ 0x1d80, 0x1dbf,
+}; /* CR_In_Phonetic_Extensions_Supplement */
+
+/* 'In_Combining_Diacritical_Marks_Supplement': Block */
+static const OnigCodePoint CR_In_Combining_Diacritical_Marks_Supplement[] = {
+ 1,
+ 0x1dc0, 0x1dff,
+}; /* CR_In_Combining_Diacritical_Marks_Supplement */
+
+/* 'In_Latin_Extended_Additional': Block */
+static const OnigCodePoint CR_In_Latin_Extended_Additional[] = {
+ 1,
+ 0x1e00, 0x1eff,
+}; /* CR_In_Latin_Extended_Additional */
+
+/* 'In_Greek_Extended': Block */
+static const OnigCodePoint CR_In_Greek_Extended[] = {
+ 1,
+ 0x1f00, 0x1fff,
+}; /* CR_In_Greek_Extended */
+
+/* 'In_General_Punctuation': Block */
+static const OnigCodePoint CR_In_General_Punctuation[] = {
+ 1,
+ 0x2000, 0x206f,
+}; /* CR_In_General_Punctuation */
+
+/* 'In_Superscripts_and_Subscripts': Block */
+static const OnigCodePoint CR_In_Superscripts_and_Subscripts[] = {
+ 1,
+ 0x2070, 0x209f,
+}; /* CR_In_Superscripts_and_Subscripts */
+
+/* 'In_Currency_Symbols': Block */
+static const OnigCodePoint CR_In_Currency_Symbols[] = {
+ 1,
+ 0x20a0, 0x20cf,
+}; /* CR_In_Currency_Symbols */
+
+/* 'In_Combining_Diacritical_Marks_for_Symbols': Block */
+static const OnigCodePoint CR_In_Combining_Diacritical_Marks_for_Symbols[] = {
+ 1,
+ 0x20d0, 0x20ff,
+}; /* CR_In_Combining_Diacritical_Marks_for_Symbols */
+
+/* 'In_Letterlike_Symbols': Block */
+static const OnigCodePoint CR_In_Letterlike_Symbols[] = {
+ 1,
+ 0x2100, 0x214f,
+}; /* CR_In_Letterlike_Symbols */
+
+/* 'In_Number_Forms': Block */
+static const OnigCodePoint CR_In_Number_Forms[] = {
+ 1,
+ 0x2150, 0x218f,
+}; /* CR_In_Number_Forms */
+
+/* 'In_Arrows': Block */
+static const OnigCodePoint CR_In_Arrows[] = {
+ 1,
+ 0x2190, 0x21ff,
+}; /* CR_In_Arrows */
+
+/* 'In_Mathematical_Operators': Block */
+static const OnigCodePoint CR_In_Mathematical_Operators[] = {
+ 1,
+ 0x2200, 0x22ff,
+}; /* CR_In_Mathematical_Operators */
+
+/* 'In_Miscellaneous_Technical': Block */
+static const OnigCodePoint CR_In_Miscellaneous_Technical[] = {
+ 1,
+ 0x2300, 0x23ff,
+}; /* CR_In_Miscellaneous_Technical */
+
+/* 'In_Control_Pictures': Block */
+static const OnigCodePoint CR_In_Control_Pictures[] = {
+ 1,
+ 0x2400, 0x243f,
+}; /* CR_In_Control_Pictures */
+
+/* 'In_Optical_Character_Recognition': Block */
+static const OnigCodePoint CR_In_Optical_Character_Recognition[] = {
+ 1,
+ 0x2440, 0x245f,
+}; /* CR_In_Optical_Character_Recognition */
+
+/* 'In_Enclosed_Alphanumerics': Block */
+static const OnigCodePoint CR_In_Enclosed_Alphanumerics[] = {
+ 1,
+ 0x2460, 0x24ff,
+}; /* CR_In_Enclosed_Alphanumerics */
+
+/* 'In_Box_Drawing': Block */
+static const OnigCodePoint CR_In_Box_Drawing[] = {
+ 1,
+ 0x2500, 0x257f,
+}; /* CR_In_Box_Drawing */
+
+/* 'In_Block_Elements': Block */
+static const OnigCodePoint CR_In_Block_Elements[] = {
+ 1,
+ 0x2580, 0x259f,
+}; /* CR_In_Block_Elements */
+
+/* 'In_Geometric_Shapes': Block */
+static const OnigCodePoint CR_In_Geometric_Shapes[] = {
+ 1,
+ 0x25a0, 0x25ff,
+}; /* CR_In_Geometric_Shapes */
+
+/* 'In_Miscellaneous_Symbols': Block */
+static const OnigCodePoint CR_In_Miscellaneous_Symbols[] = {
+ 1,
+ 0x2600, 0x26ff,
+}; /* CR_In_Miscellaneous_Symbols */
+
+/* 'In_Dingbats': Block */
+static const OnigCodePoint CR_In_Dingbats[] = {
+ 1,
+ 0x2700, 0x27bf,
+}; /* CR_In_Dingbats */
+
+/* 'In_Miscellaneous_Mathematical_Symbols_A': Block */
+static const OnigCodePoint CR_In_Miscellaneous_Mathematical_Symbols_A[] = {
+ 1,
+ 0x27c0, 0x27ef,
+}; /* CR_In_Miscellaneous_Mathematical_Symbols_A */
+
+/* 'In_Supplemental_Arrows_A': Block */
+static const OnigCodePoint CR_In_Supplemental_Arrows_A[] = {
+ 1,
+ 0x27f0, 0x27ff,
+}; /* CR_In_Supplemental_Arrows_A */
+
+/* 'In_Braille_Patterns': Block */
+#define CR_In_Braille_Patterns CR_Braille
+
+/* 'In_Supplemental_Arrows_B': Block */
+static const OnigCodePoint CR_In_Supplemental_Arrows_B[] = {
+ 1,
+ 0x2900, 0x297f,
+}; /* CR_In_Supplemental_Arrows_B */
+
+/* 'In_Miscellaneous_Mathematical_Symbols_B': Block */
+static const OnigCodePoint CR_In_Miscellaneous_Mathematical_Symbols_B[] = {
+ 1,
+ 0x2980, 0x29ff,
+}; /* CR_In_Miscellaneous_Mathematical_Symbols_B */
+
+/* 'In_Supplemental_Mathematical_Operators': Block */
+static const OnigCodePoint CR_In_Supplemental_Mathematical_Operators[] = {
+ 1,
+ 0x2a00, 0x2aff,
+}; /* CR_In_Supplemental_Mathematical_Operators */
+
+/* 'In_Miscellaneous_Symbols_and_Arrows': Block */
+static const OnigCodePoint CR_In_Miscellaneous_Symbols_and_Arrows[] = {
+ 1,
+ 0x2b00, 0x2bff,
+}; /* CR_In_Miscellaneous_Symbols_and_Arrows */
+
+/* 'In_Glagolitic': Block */
+static const OnigCodePoint CR_In_Glagolitic[] = {
+ 1,
+ 0x2c00, 0x2c5f,
+}; /* CR_In_Glagolitic */
+
+/* 'In_Latin_Extended_C': Block */
+static const OnigCodePoint CR_In_Latin_Extended_C[] = {
+ 1,
+ 0x2c60, 0x2c7f,
+}; /* CR_In_Latin_Extended_C */
+
+/* 'In_Coptic': Block */
+static const OnigCodePoint CR_In_Coptic[] = {
+ 1,
+ 0x2c80, 0x2cff,
+}; /* CR_In_Coptic */
+
+/* 'In_Georgian_Supplement': Block */
+static const OnigCodePoint CR_In_Georgian_Supplement[] = {
+ 1,
+ 0x2d00, 0x2d2f,
+}; /* CR_In_Georgian_Supplement */
+
+/* 'In_Tifinagh': Block */
+static const OnigCodePoint CR_In_Tifinagh[] = {
+ 1,
+ 0x2d30, 0x2d7f,
+}; /* CR_In_Tifinagh */
+
+/* 'In_Ethiopic_Extended': Block */
+static const OnigCodePoint CR_In_Ethiopic_Extended[] = {
+ 1,
+ 0x2d80, 0x2ddf,
+}; /* CR_In_Ethiopic_Extended */
+
+/* 'In_Cyrillic_Extended_A': Block */
+static const OnigCodePoint CR_In_Cyrillic_Extended_A[] = {
+ 1,
+ 0x2de0, 0x2dff,
+}; /* CR_In_Cyrillic_Extended_A */
+
+/* 'In_Supplemental_Punctuation': Block */
+static const OnigCodePoint CR_In_Supplemental_Punctuation[] = {
+ 1,
+ 0x2e00, 0x2e7f,
+}; /* CR_In_Supplemental_Punctuation */
+
+/* 'In_CJK_Radicals_Supplement': Block */
+static const OnigCodePoint CR_In_CJK_Radicals_Supplement[] = {
+ 1,
+ 0x2e80, 0x2eff,
+}; /* CR_In_CJK_Radicals_Supplement */
+
+/* 'In_Kangxi_Radicals': Block */
+static const OnigCodePoint CR_In_Kangxi_Radicals[] = {
+ 1,
+ 0x2f00, 0x2fdf,
+}; /* CR_In_Kangxi_Radicals */
+
+/* 'In_Ideographic_Description_Characters': Block */
+static const OnigCodePoint CR_In_Ideographic_Description_Characters[] = {
+ 1,
+ 0x2ff0, 0x2fff,
+}; /* CR_In_Ideographic_Description_Characters */
+
+/* 'In_CJK_Symbols_and_Punctuation': Block */
+static const OnigCodePoint CR_In_CJK_Symbols_and_Punctuation[] = {
+ 1,
+ 0x3000, 0x303f,
+}; /* CR_In_CJK_Symbols_and_Punctuation */
+
+/* 'In_Hiragana': Block */
+static const OnigCodePoint CR_In_Hiragana[] = {
+ 1,
+ 0x3040, 0x309f,
+}; /* CR_In_Hiragana */
+
+/* 'In_Katakana': Block */
+static const OnigCodePoint CR_In_Katakana[] = {
+ 1,
+ 0x30a0, 0x30ff,
+}; /* CR_In_Katakana */
+
+/* 'In_Bopomofo': Block */
+static const OnigCodePoint CR_In_Bopomofo[] = {
+ 1,
+ 0x3100, 0x312f,
+}; /* CR_In_Bopomofo */
+
+/* 'In_Hangul_Compatibility_Jamo': Block */
+static const OnigCodePoint CR_In_Hangul_Compatibility_Jamo[] = {
+ 1,
+ 0x3130, 0x318f,
+}; /* CR_In_Hangul_Compatibility_Jamo */
+
+/* 'In_Kanbun': Block */
+static const OnigCodePoint CR_In_Kanbun[] = {
+ 1,
+ 0x3190, 0x319f,
+}; /* CR_In_Kanbun */
+
+/* 'In_Bopomofo_Extended': Block */
+static const OnigCodePoint CR_In_Bopomofo_Extended[] = {
+ 1,
+ 0x31a0, 0x31bf,
+}; /* CR_In_Bopomofo_Extended */
+
+/* 'In_CJK_Strokes': Block */
+static const OnigCodePoint CR_In_CJK_Strokes[] = {
+ 1,
+ 0x31c0, 0x31ef,
+}; /* CR_In_CJK_Strokes */
+
+/* 'In_Katakana_Phonetic_Extensions': Block */
+static const OnigCodePoint CR_In_Katakana_Phonetic_Extensions[] = {
+ 1,
+ 0x31f0, 0x31ff,
+}; /* CR_In_Katakana_Phonetic_Extensions */
+
+/* 'In_Enclosed_CJK_Letters_and_Months': Block */
+static const OnigCodePoint CR_In_Enclosed_CJK_Letters_and_Months[] = {
+ 1,
+ 0x3200, 0x32ff,
+}; /* CR_In_Enclosed_CJK_Letters_and_Months */
+
+/* 'In_CJK_Compatibility': Block */
+static const OnigCodePoint CR_In_CJK_Compatibility[] = {
+ 1,
+ 0x3300, 0x33ff,
+}; /* CR_In_CJK_Compatibility */
+
+/* 'In_CJK_Unified_Ideographs_Extension_A': Block */
+static const OnigCodePoint CR_In_CJK_Unified_Ideographs_Extension_A[] = {
+ 1,
+ 0x3400, 0x4dbf,
+}; /* CR_In_CJK_Unified_Ideographs_Extension_A */
+
+/* 'In_Yijing_Hexagram_Symbols': Block */
+static const OnigCodePoint CR_In_Yijing_Hexagram_Symbols[] = {
+ 1,
+ 0x4dc0, 0x4dff,
+}; /* CR_In_Yijing_Hexagram_Symbols */
+
+/* 'In_CJK_Unified_Ideographs': Block */
+static const OnigCodePoint CR_In_CJK_Unified_Ideographs[] = {
+ 1,
+ 0x4e00, 0x9fff,
+}; /* CR_In_CJK_Unified_Ideographs */
+
+/* 'In_Yi_Syllables': Block */
+static const OnigCodePoint CR_In_Yi_Syllables[] = {
+ 1,
+ 0xa000, 0xa48f,
+}; /* CR_In_Yi_Syllables */
+
+/* 'In_Yi_Radicals': Block */
+static const OnigCodePoint CR_In_Yi_Radicals[] = {
+ 1,
+ 0xa490, 0xa4cf,
+}; /* CR_In_Yi_Radicals */
+
+/* 'In_Lisu': Block */
+static const OnigCodePoint CR_In_Lisu[] = {
+ 1,
+ 0xa4d0, 0xa4ff,
+}; /* CR_In_Lisu */
+
+/* 'In_Vai': Block */
+static const OnigCodePoint CR_In_Vai[] = {
+ 1,
+ 0xa500, 0xa63f,
+}; /* CR_In_Vai */
+
+/* 'In_Cyrillic_Extended_B': Block */
+static const OnigCodePoint CR_In_Cyrillic_Extended_B[] = {
+ 1,
+ 0xa640, 0xa69f,
+}; /* CR_In_Cyrillic_Extended_B */
+
+/* 'In_Bamum': Block */
+static const OnigCodePoint CR_In_Bamum[] = {
+ 1,
+ 0xa6a0, 0xa6ff,
+}; /* CR_In_Bamum */
+
+/* 'In_Modifier_Tone_Letters': Block */
+static const OnigCodePoint CR_In_Modifier_Tone_Letters[] = {
+ 1,
+ 0xa700, 0xa71f,
+}; /* CR_In_Modifier_Tone_Letters */
+
+/* 'In_Latin_Extended_D': Block */
+static const OnigCodePoint CR_In_Latin_Extended_D[] = {
+ 1,
+ 0xa720, 0xa7ff,
+}; /* CR_In_Latin_Extended_D */
+
+/* 'In_Syloti_Nagri': Block */
+static const OnigCodePoint CR_In_Syloti_Nagri[] = {
+ 1,
+ 0xa800, 0xa82f,
+}; /* CR_In_Syloti_Nagri */
+
+/* 'In_Common_Indic_Number_Forms': Block */
+static const OnigCodePoint CR_In_Common_Indic_Number_Forms[] = {
+ 1,
+ 0xa830, 0xa83f,
+}; /* CR_In_Common_Indic_Number_Forms */
+
+/* 'In_Phags_pa': Block */
+static const OnigCodePoint CR_In_Phags_pa[] = {
+ 1,
+ 0xa840, 0xa87f,
+}; /* CR_In_Phags_pa */
+
+/* 'In_Saurashtra': Block */
+static const OnigCodePoint CR_In_Saurashtra[] = {
+ 1,
+ 0xa880, 0xa8df,
+}; /* CR_In_Saurashtra */
+
+/* 'In_Devanagari_Extended': Block */
+static const OnigCodePoint CR_In_Devanagari_Extended[] = {
+ 1,
+ 0xa8e0, 0xa8ff,
+}; /* CR_In_Devanagari_Extended */
+
+/* 'In_Kayah_Li': Block */
+static const OnigCodePoint CR_In_Kayah_Li[] = {
+ 1,
+ 0xa900, 0xa92f,
+}; /* CR_In_Kayah_Li */
+
+/* 'In_Rejang': Block */
+static const OnigCodePoint CR_In_Rejang[] = {
+ 1,
+ 0xa930, 0xa95f,
+}; /* CR_In_Rejang */
+
+/* 'In_Hangul_Jamo_Extended_A': Block */
+static const OnigCodePoint CR_In_Hangul_Jamo_Extended_A[] = {
+ 1,
+ 0xa960, 0xa97f,
+}; /* CR_In_Hangul_Jamo_Extended_A */
+
+/* 'In_Javanese': Block */
+static const OnigCodePoint CR_In_Javanese[] = {
+ 1,
+ 0xa980, 0xa9df,
+}; /* CR_In_Javanese */
+
+/* 'In_Myanmar_Extended_B': Block */
+static const OnigCodePoint CR_In_Myanmar_Extended_B[] = {
+ 1,
+ 0xa9e0, 0xa9ff,
+}; /* CR_In_Myanmar_Extended_B */
+
+/* 'In_Cham': Block */
+static const OnigCodePoint CR_In_Cham[] = {
+ 1,
+ 0xaa00, 0xaa5f,
+}; /* CR_In_Cham */
+
+/* 'In_Myanmar_Extended_A': Block */
+static const OnigCodePoint CR_In_Myanmar_Extended_A[] = {
+ 1,
+ 0xaa60, 0xaa7f,
+}; /* CR_In_Myanmar_Extended_A */
+
+/* 'In_Tai_Viet': Block */
+static const OnigCodePoint CR_In_Tai_Viet[] = {
+ 1,
+ 0xaa80, 0xaadf,
+}; /* CR_In_Tai_Viet */
+
+/* 'In_Meetei_Mayek_Extensions': Block */
+static const OnigCodePoint CR_In_Meetei_Mayek_Extensions[] = {
+ 1,
+ 0xaae0, 0xaaff,
+}; /* CR_In_Meetei_Mayek_Extensions */
+
+/* 'In_Ethiopic_Extended_A': Block */
+static const OnigCodePoint CR_In_Ethiopic_Extended_A[] = {
+ 1,
+ 0xab00, 0xab2f,
+}; /* CR_In_Ethiopic_Extended_A */
+
+/* 'In_Latin_Extended_E': Block */
+static const OnigCodePoint CR_In_Latin_Extended_E[] = {
+ 1,
+ 0xab30, 0xab6f,
+}; /* CR_In_Latin_Extended_E */
+
+/* 'In_Cherokee_Supplement': Block */
+static const OnigCodePoint CR_In_Cherokee_Supplement[] = {
+ 1,
+ 0xab70, 0xabbf,
+}; /* CR_In_Cherokee_Supplement */
+
+/* 'In_Meetei_Mayek': Block */
+static const OnigCodePoint CR_In_Meetei_Mayek[] = {
+ 1,
+ 0xabc0, 0xabff,
+}; /* CR_In_Meetei_Mayek */
+
+/* 'In_Hangul_Syllables': Block */
+static const OnigCodePoint CR_In_Hangul_Syllables[] = {
+ 1,
+ 0xac00, 0xd7af,
+}; /* CR_In_Hangul_Syllables */
+
+/* 'In_Hangul_Jamo_Extended_B': Block */
+static const OnigCodePoint CR_In_Hangul_Jamo_Extended_B[] = {
+ 1,
+ 0xd7b0, 0xd7ff,
+}; /* CR_In_Hangul_Jamo_Extended_B */
+
+/* 'In_High_Surrogates': Block */
+static const OnigCodePoint CR_In_High_Surrogates[] = {
+ 1,
+ 0xd800, 0xdb7f,
+}; /* CR_In_High_Surrogates */
+
+/* 'In_High_Private_Use_Surrogates': Block */
+static const OnigCodePoint CR_In_High_Private_Use_Surrogates[] = {
+ 1,
+ 0xdb80, 0xdbff,
+}; /* CR_In_High_Private_Use_Surrogates */
+
+/* 'In_Low_Surrogates': Block */
+static const OnigCodePoint CR_In_Low_Surrogates[] = {
+ 1,
+ 0xdc00, 0xdfff,
+}; /* CR_In_Low_Surrogates */
+
+/* 'In_Private_Use_Area': Block */
+static const OnigCodePoint CR_In_Private_Use_Area[] = {
+ 1,
+ 0xe000, 0xf8ff,
+}; /* CR_In_Private_Use_Area */
+
+/* 'In_CJK_Compatibility_Ideographs': Block */
+static const OnigCodePoint CR_In_CJK_Compatibility_Ideographs[] = {
+ 1,
+ 0xf900, 0xfaff,
+}; /* CR_In_CJK_Compatibility_Ideographs */
+
+/* 'In_Alphabetic_Presentation_Forms': Block */
+static const OnigCodePoint CR_In_Alphabetic_Presentation_Forms[] = {
+ 1,
+ 0xfb00, 0xfb4f,
+}; /* CR_In_Alphabetic_Presentation_Forms */
+
+/* 'In_Arabic_Presentation_Forms_A': Block */
+static const OnigCodePoint CR_In_Arabic_Presentation_Forms_A[] = {
+ 1,
+ 0xfb50, 0xfdff,
+}; /* CR_In_Arabic_Presentation_Forms_A */
+
+/* 'In_Variation_Selectors': Block */
+static const OnigCodePoint CR_In_Variation_Selectors[] = {
+ 1,
+ 0xfe00, 0xfe0f,
+}; /* CR_In_Variation_Selectors */
+
+/* 'In_Vertical_Forms': Block */
+static const OnigCodePoint CR_In_Vertical_Forms[] = {
+ 1,
+ 0xfe10, 0xfe1f,
+}; /* CR_In_Vertical_Forms */
+
+/* 'In_Combining_Half_Marks': Block */
+static const OnigCodePoint CR_In_Combining_Half_Marks[] = {
+ 1,
+ 0xfe20, 0xfe2f,
+}; /* CR_In_Combining_Half_Marks */
+
+/* 'In_CJK_Compatibility_Forms': Block */
+static const OnigCodePoint CR_In_CJK_Compatibility_Forms[] = {
+ 1,
+ 0xfe30, 0xfe4f,
+}; /* CR_In_CJK_Compatibility_Forms */
+
+/* 'In_Small_Form_Variants': Block */
+static const OnigCodePoint CR_In_Small_Form_Variants[] = {
+ 1,
+ 0xfe50, 0xfe6f,
+}; /* CR_In_Small_Form_Variants */
+
+/* 'In_Arabic_Presentation_Forms_B': Block */
+static const OnigCodePoint CR_In_Arabic_Presentation_Forms_B[] = {
+ 1,
+ 0xfe70, 0xfeff,
+}; /* CR_In_Arabic_Presentation_Forms_B */
+
+/* 'In_Halfwidth_and_Fullwidth_Forms': Block */
+static const OnigCodePoint CR_In_Halfwidth_and_Fullwidth_Forms[] = {
+ 1,
+ 0xff00, 0xffef,
+}; /* CR_In_Halfwidth_and_Fullwidth_Forms */
+
+/* 'In_Specials': Block */
+static const OnigCodePoint CR_In_Specials[] = {
+ 1,
+ 0xfff0, 0xffff,
+}; /* CR_In_Specials */
+
+/* 'In_Linear_B_Syllabary': Block */
+static const OnigCodePoint CR_In_Linear_B_Syllabary[] = {
+ 1,
+ 0x10000, 0x1007f,
+}; /* CR_In_Linear_B_Syllabary */
+
+/* 'In_Linear_B_Ideograms': Block */
+static const OnigCodePoint CR_In_Linear_B_Ideograms[] = {
+ 1,
+ 0x10080, 0x100ff,
+}; /* CR_In_Linear_B_Ideograms */
+
+/* 'In_Aegean_Numbers': Block */
+static const OnigCodePoint CR_In_Aegean_Numbers[] = {
+ 1,
+ 0x10100, 0x1013f,
+}; /* CR_In_Aegean_Numbers */
+
+/* 'In_Ancient_Greek_Numbers': Block */
+static const OnigCodePoint CR_In_Ancient_Greek_Numbers[] = {
+ 1,
+ 0x10140, 0x1018f,
+}; /* CR_In_Ancient_Greek_Numbers */
+
+/* 'In_Ancient_Symbols': Block */
+static const OnigCodePoint CR_In_Ancient_Symbols[] = {
+ 1,
+ 0x10190, 0x101cf,
+}; /* CR_In_Ancient_Symbols */
+
+/* 'In_Phaistos_Disc': Block */
+static const OnigCodePoint CR_In_Phaistos_Disc[] = {
+ 1,
+ 0x101d0, 0x101ff,
+}; /* CR_In_Phaistos_Disc */
+
+/* 'In_Lycian': Block */
+static const OnigCodePoint CR_In_Lycian[] = {
+ 1,
+ 0x10280, 0x1029f,
+}; /* CR_In_Lycian */
+
+/* 'In_Carian': Block */
+static const OnigCodePoint CR_In_Carian[] = {
+ 1,
+ 0x102a0, 0x102df,
+}; /* CR_In_Carian */
+
+/* 'In_Coptic_Epact_Numbers': Block */
+static const OnigCodePoint CR_In_Coptic_Epact_Numbers[] = {
+ 1,
+ 0x102e0, 0x102ff,
+}; /* CR_In_Coptic_Epact_Numbers */
+
+/* 'In_Old_Italic': Block */
+static const OnigCodePoint CR_In_Old_Italic[] = {
+ 1,
+ 0x10300, 0x1032f,
+}; /* CR_In_Old_Italic */
+
+/* 'In_Gothic': Block */
+static const OnigCodePoint CR_In_Gothic[] = {
+ 1,
+ 0x10330, 0x1034f,
+}; /* CR_In_Gothic */
+
+/* 'In_Old_Permic': Block */
+static const OnigCodePoint CR_In_Old_Permic[] = {
+ 1,
+ 0x10350, 0x1037f,
+}; /* CR_In_Old_Permic */
+
+/* 'In_Ugaritic': Block */
+static const OnigCodePoint CR_In_Ugaritic[] = {
+ 1,
+ 0x10380, 0x1039f,
+}; /* CR_In_Ugaritic */
+
+/* 'In_Old_Persian': Block */
+static const OnigCodePoint CR_In_Old_Persian[] = {
+ 1,
+ 0x103a0, 0x103df,
+}; /* CR_In_Old_Persian */
+
+/* 'In_Deseret': Block */
+#define CR_In_Deseret CR_Deseret
+
+/* 'In_Shavian': Block */
+#define CR_In_Shavian CR_Shavian
+
+/* 'In_Osmanya': Block */
+static const OnigCodePoint CR_In_Osmanya[] = {
+ 1,
+ 0x10480, 0x104af,
+}; /* CR_In_Osmanya */
+
+/* 'In_Osage': Block */
+static const OnigCodePoint CR_In_Osage[] = {
+ 1,
+ 0x104b0, 0x104ff,
+}; /* CR_In_Osage */
+
+/* 'In_Elbasan': Block */
+static const OnigCodePoint CR_In_Elbasan[] = {
+ 1,
+ 0x10500, 0x1052f,
+}; /* CR_In_Elbasan */
+
+/* 'In_Caucasian_Albanian': Block */
+static const OnigCodePoint CR_In_Caucasian_Albanian[] = {
+ 1,
+ 0x10530, 0x1056f,
+}; /* CR_In_Caucasian_Albanian */
+
+/* 'In_Vithkuqi': Block */
+static const OnigCodePoint CR_In_Vithkuqi[] = {
+ 1,
+ 0x10570, 0x105bf,
+}; /* CR_In_Vithkuqi */
+
+/* 'In_Todhri': Block */
+static const OnigCodePoint CR_In_Todhri[] = {
+ 1,
+ 0x105c0, 0x105ff,
+}; /* CR_In_Todhri */
+
+/* 'In_Linear_A': Block */
+static const OnigCodePoint CR_In_Linear_A[] = {
+ 1,
+ 0x10600, 0x1077f,
+}; /* CR_In_Linear_A */
+
+/* 'In_Latin_Extended_F': Block */
+static const OnigCodePoint CR_In_Latin_Extended_F[] = {
+ 1,
+ 0x10780, 0x107bf,
+}; /* CR_In_Latin_Extended_F */
+
+/* 'In_Cypriot_Syllabary': Block */
+static const OnigCodePoint CR_In_Cypriot_Syllabary[] = {
+ 1,
+ 0x10800, 0x1083f,
+}; /* CR_In_Cypriot_Syllabary */
+
+/* 'In_Imperial_Aramaic': Block */
+static const OnigCodePoint CR_In_Imperial_Aramaic[] = {
+ 1,
+ 0x10840, 0x1085f,
+}; /* CR_In_Imperial_Aramaic */
+
+/* 'In_Palmyrene': Block */
+#define CR_In_Palmyrene CR_Palmyrene
+
+/* 'In_Nabataean': Block */
+static const OnigCodePoint CR_In_Nabataean[] = {
+ 1,
+ 0x10880, 0x108af,
+}; /* CR_In_Nabataean */
+
+/* 'In_Hatran': Block */
+static const OnigCodePoint CR_In_Hatran[] = {
+ 1,
+ 0x108e0, 0x108ff,
+}; /* CR_In_Hatran */
+
+/* 'In_Phoenician': Block */
+static const OnigCodePoint CR_In_Phoenician[] = {
+ 1,
+ 0x10900, 0x1091f,
+}; /* CR_In_Phoenician */
+
+/* 'In_Lydian': Block */
+static const OnigCodePoint CR_In_Lydian[] = {
+ 1,
+ 0x10920, 0x1093f,
+}; /* CR_In_Lydian */
+
+/* 'In_Sidetic': Block */
+static const OnigCodePoint CR_In_Sidetic[] = {
+ 1,
+ 0x10940, 0x1095f,
+}; /* CR_In_Sidetic */
+
+/* 'In_Meroitic_Hieroglyphs': Block */
+#define CR_In_Meroitic_Hieroglyphs CR_Meroitic_Hieroglyphs
+
+/* 'In_Meroitic_Cursive': Block */
+static const OnigCodePoint CR_In_Meroitic_Cursive[] = {
+ 1,
+ 0x109a0, 0x109ff,
+}; /* CR_In_Meroitic_Cursive */
+
+/* 'In_Kharoshthi': Block */
+static const OnigCodePoint CR_In_Kharoshthi[] = {
+ 1,
+ 0x10a00, 0x10a5f,
+}; /* CR_In_Kharoshthi */
+
+/* 'In_Old_South_Arabian': Block */
+#define CR_In_Old_South_Arabian CR_Old_South_Arabian
+
+/* 'In_Old_North_Arabian': Block */
+#define CR_In_Old_North_Arabian CR_Old_North_Arabian
+
+/* 'In_Manichaean': Block */
+static const OnigCodePoint CR_In_Manichaean[] = {
+ 1,
+ 0x10ac0, 0x10aff,
+}; /* CR_In_Manichaean */
+
+/* 'In_Avestan': Block */
+static const OnigCodePoint CR_In_Avestan[] = {
+ 1,
+ 0x10b00, 0x10b3f,
+}; /* CR_In_Avestan */
+
+/* 'In_Inscriptional_Parthian': Block */
+static const OnigCodePoint CR_In_Inscriptional_Parthian[] = {
+ 1,
+ 0x10b40, 0x10b5f,
+}; /* CR_In_Inscriptional_Parthian */
+
+/* 'In_Inscriptional_Pahlavi': Block */
+static const OnigCodePoint CR_In_Inscriptional_Pahlavi[] = {
+ 1,
+ 0x10b60, 0x10b7f,
+}; /* CR_In_Inscriptional_Pahlavi */
+
+/* 'In_Psalter_Pahlavi': Block */
+static const OnigCodePoint CR_In_Psalter_Pahlavi[] = {
+ 1,
+ 0x10b80, 0x10baf,
+}; /* CR_In_Psalter_Pahlavi */
+
+/* 'In_Old_Turkic': Block */
+static const OnigCodePoint CR_In_Old_Turkic[] = {
+ 1,
+ 0x10c00, 0x10c4f,
+}; /* CR_In_Old_Turkic */
+
+/* 'In_Old_Hungarian': Block */
+static const OnigCodePoint CR_In_Old_Hungarian[] = {
+ 1,
+ 0x10c80, 0x10cff,
+}; /* CR_In_Old_Hungarian */
+
+/* 'In_Hanifi_Rohingya': Block */
+static const OnigCodePoint CR_In_Hanifi_Rohingya[] = {
+ 1,
+ 0x10d00, 0x10d3f,
+}; /* CR_In_Hanifi_Rohingya */
+
+/* 'In_Garay': Block */
+static const OnigCodePoint CR_In_Garay[] = {
+ 1,
+ 0x10d40, 0x10d8f,
+}; /* CR_In_Garay */
+
+/* 'In_Rumi_Numeral_Symbols': Block */
+static const OnigCodePoint CR_In_Rumi_Numeral_Symbols[] = {
+ 1,
+ 0x10e60, 0x10e7f,
+}; /* CR_In_Rumi_Numeral_Symbols */
+
+/* 'In_Yezidi': Block */
+static const OnigCodePoint CR_In_Yezidi[] = {
+ 1,
+ 0x10e80, 0x10ebf,
+}; /* CR_In_Yezidi */
+
+/* 'In_Arabic_Extended_C': Block */
+static const OnigCodePoint CR_In_Arabic_Extended_C[] = {
+ 1,
+ 0x10ec0, 0x10eff,
+}; /* CR_In_Arabic_Extended_C */
+
+/* 'In_Old_Sogdian': Block */
+static const OnigCodePoint CR_In_Old_Sogdian[] = {
+ 1,
+ 0x10f00, 0x10f2f,
+}; /* CR_In_Old_Sogdian */
+
+/* 'In_Sogdian': Block */
+static const OnigCodePoint CR_In_Sogdian[] = {
+ 1,
+ 0x10f30, 0x10f6f,
+}; /* CR_In_Sogdian */
+
+/* 'In_Old_Uyghur': Block */
+static const OnigCodePoint CR_In_Old_Uyghur[] = {
+ 1,
+ 0x10f70, 0x10faf,
+}; /* CR_In_Old_Uyghur */
+
+/* 'In_Chorasmian': Block */
+static const OnigCodePoint CR_In_Chorasmian[] = {
+ 1,
+ 0x10fb0, 0x10fdf,
+}; /* CR_In_Chorasmian */
+
+/* 'In_Elymaic': Block */
+static const OnigCodePoint CR_In_Elymaic[] = {
+ 1,
+ 0x10fe0, 0x10fff,
+}; /* CR_In_Elymaic */
+
+/* 'In_Brahmi': Block */
+static const OnigCodePoint CR_In_Brahmi[] = {
+ 1,
+ 0x11000, 0x1107f,
+}; /* CR_In_Brahmi */
+
+/* 'In_Kaithi': Block */
+static const OnigCodePoint CR_In_Kaithi[] = {
+ 1,
+ 0x11080, 0x110cf,
+}; /* CR_In_Kaithi */
+
+/* 'In_Sora_Sompeng': Block */
+static const OnigCodePoint CR_In_Sora_Sompeng[] = {
+ 1,
+ 0x110d0, 0x110ff,
+}; /* CR_In_Sora_Sompeng */
+
+/* 'In_Chakma': Block */
+static const OnigCodePoint CR_In_Chakma[] = {
+ 1,
+ 0x11100, 0x1114f,
+}; /* CR_In_Chakma */
+
+/* 'In_Mahajani': Block */
+static const OnigCodePoint CR_In_Mahajani[] = {
+ 1,
+ 0x11150, 0x1117f,
+}; /* CR_In_Mahajani */
+
+/* 'In_Sharada': Block */
+static const OnigCodePoint CR_In_Sharada[] = {
+ 1,
+ 0x11180, 0x111df,
+}; /* CR_In_Sharada */
+
+/* 'In_Sinhala_Archaic_Numbers': Block */
+static const OnigCodePoint CR_In_Sinhala_Archaic_Numbers[] = {
+ 1,
+ 0x111e0, 0x111ff,
+}; /* CR_In_Sinhala_Archaic_Numbers */
+
+/* 'In_Khojki': Block */
+static const OnigCodePoint CR_In_Khojki[] = {
+ 1,
+ 0x11200, 0x1124f,
+}; /* CR_In_Khojki */
+
+/* 'In_Multani': Block */
+static const OnigCodePoint CR_In_Multani[] = {
+ 1,
+ 0x11280, 0x112af,
+}; /* CR_In_Multani */
+
+/* 'In_Khudawadi': Block */
+static const OnigCodePoint CR_In_Khudawadi[] = {
+ 1,
+ 0x112b0, 0x112ff,
+}; /* CR_In_Khudawadi */
+
+/* 'In_Grantha': Block */
+static const OnigCodePoint CR_In_Grantha[] = {
+ 1,
+ 0x11300, 0x1137f,
+}; /* CR_In_Grantha */
+
+/* 'In_Tulu_Tigalari': Block */
+static const OnigCodePoint CR_In_Tulu_Tigalari[] = {
+ 1,
+ 0x11380, 0x113ff,
+}; /* CR_In_Tulu_Tigalari */
+
+/* 'In_Newa': Block */
+static const OnigCodePoint CR_In_Newa[] = {
+ 1,
+ 0x11400, 0x1147f,
+}; /* CR_In_Newa */
+
+/* 'In_Tirhuta': Block */
+static const OnigCodePoint CR_In_Tirhuta[] = {
+ 1,
+ 0x11480, 0x114df,
+}; /* CR_In_Tirhuta */
+
+/* 'In_Siddham': Block */
+static const OnigCodePoint CR_In_Siddham[] = {
+ 1,
+ 0x11580, 0x115ff,
+}; /* CR_In_Siddham */
+
+/* 'In_Modi': Block */
+static const OnigCodePoint CR_In_Modi[] = {
+ 1,
+ 0x11600, 0x1165f,
+}; /* CR_In_Modi */
+
+/* 'In_Mongolian_Supplement': Block */
+static const OnigCodePoint CR_In_Mongolian_Supplement[] = {
+ 1,
+ 0x11660, 0x1167f,
+}; /* CR_In_Mongolian_Supplement */
+
+/* 'In_Takri': Block */
+static const OnigCodePoint CR_In_Takri[] = {
+ 1,
+ 0x11680, 0x116cf,
+}; /* CR_In_Takri */
+
+/* 'In_Myanmar_Extended_C': Block */
+static const OnigCodePoint CR_In_Myanmar_Extended_C[] = {
+ 1,
+ 0x116d0, 0x116ff,
+}; /* CR_In_Myanmar_Extended_C */
+
+/* 'In_Ahom': Block */
+static const OnigCodePoint CR_In_Ahom[] = {
+ 1,
+ 0x11700, 0x1174f,
+}; /* CR_In_Ahom */
+
+/* 'In_Dogra': Block */
+static const OnigCodePoint CR_In_Dogra[] = {
+ 1,
+ 0x11800, 0x1184f,
+}; /* CR_In_Dogra */
+
+/* 'In_Warang_Citi': Block */
+static const OnigCodePoint CR_In_Warang_Citi[] = {
+ 1,
+ 0x118a0, 0x118ff,
+}; /* CR_In_Warang_Citi */
+
+/* 'In_Dives_Akuru': Block */
+static const OnigCodePoint CR_In_Dives_Akuru[] = {
+ 1,
+ 0x11900, 0x1195f,
+}; /* CR_In_Dives_Akuru */
+
+/* 'In_Nandinagari': Block */
+static const OnigCodePoint CR_In_Nandinagari[] = {
+ 1,
+ 0x119a0, 0x119ff,
+}; /* CR_In_Nandinagari */
+
+/* 'In_Zanabazar_Square': Block */
+static const OnigCodePoint CR_In_Zanabazar_Square[] = {
+ 1,
+ 0x11a00, 0x11a4f,
+}; /* CR_In_Zanabazar_Square */
+
+/* 'In_Soyombo': Block */
+static const OnigCodePoint CR_In_Soyombo[] = {
+ 1,
+ 0x11a50, 0x11aaf,
+}; /* CR_In_Soyombo */
+
+/* 'In_Unified_Canadian_Aboriginal_Syllabics_Extended_A': Block */
+static const OnigCodePoint CR_In_Unified_Canadian_Aboriginal_Syllabics_Extended_A[] = {
+ 1,
+ 0x11ab0, 0x11abf,
+}; /* CR_In_Unified_Canadian_Aboriginal_Syllabics_Extended_A */
+
+/* 'In_Pau_Cin_Hau': Block */
+static const OnigCodePoint CR_In_Pau_Cin_Hau[] = {
+ 1,
+ 0x11ac0, 0x11aff,
+}; /* CR_In_Pau_Cin_Hau */
+
+/* 'In_Devanagari_Extended_A': Block */
+static const OnigCodePoint CR_In_Devanagari_Extended_A[] = {
+ 1,
+ 0x11b00, 0x11b5f,
+}; /* CR_In_Devanagari_Extended_A */
+
+/* 'In_Sharada_Supplement': Block */
+static const OnigCodePoint CR_In_Sharada_Supplement[] = {
+ 1,
+ 0x11b60, 0x11b7f,
+}; /* CR_In_Sharada_Supplement */
+
+/* 'In_Sunuwar': Block */
+static const OnigCodePoint CR_In_Sunuwar[] = {
+ 1,
+ 0x11bc0, 0x11bff,
+}; /* CR_In_Sunuwar */
+
+/* 'In_Bhaiksuki': Block */
+static const OnigCodePoint CR_In_Bhaiksuki[] = {
+ 1,
+ 0x11c00, 0x11c6f,
+}; /* CR_In_Bhaiksuki */
+
+/* 'In_Marchen': Block */
+static const OnigCodePoint CR_In_Marchen[] = {
+ 1,
+ 0x11c70, 0x11cbf,
+}; /* CR_In_Marchen */
+
+/* 'In_Masaram_Gondi': Block */
+static const OnigCodePoint CR_In_Masaram_Gondi[] = {
+ 1,
+ 0x11d00, 0x11d5f,
+}; /* CR_In_Masaram_Gondi */
+
+/* 'In_Gunjala_Gondi': Block */
+static const OnigCodePoint CR_In_Gunjala_Gondi[] = {
+ 1,
+ 0x11d60, 0x11daf,
+}; /* CR_In_Gunjala_Gondi */
+
+/* 'In_Tolong_Siki': Block */
+static const OnigCodePoint CR_In_Tolong_Siki[] = {
+ 1,
+ 0x11db0, 0x11def,
+}; /* CR_In_Tolong_Siki */
+
+/* 'In_Makasar': Block */
+static const OnigCodePoint CR_In_Makasar[] = {
+ 1,
+ 0x11ee0, 0x11eff,
+}; /* CR_In_Makasar */
+
+/* 'In_Kawi': Block */
+static const OnigCodePoint CR_In_Kawi[] = {
+ 1,
+ 0x11f00, 0x11f5f,
+}; /* CR_In_Kawi */
+
+/* 'In_Lisu_Supplement': Block */
+static const OnigCodePoint CR_In_Lisu_Supplement[] = {
+ 1,
+ 0x11fb0, 0x11fbf,
+}; /* CR_In_Lisu_Supplement */
+
+/* 'In_Tamil_Supplement': Block */
+static const OnigCodePoint CR_In_Tamil_Supplement[] = {
+ 1,
+ 0x11fc0, 0x11fff,
+}; /* CR_In_Tamil_Supplement */
+
+/* 'In_Cuneiform': Block */
+static const OnigCodePoint CR_In_Cuneiform[] = {
+ 1,
+ 0x12000, 0x123ff,
+}; /* CR_In_Cuneiform */
+
+/* 'In_Cuneiform_Numbers_and_Punctuation': Block */
+static const OnigCodePoint CR_In_Cuneiform_Numbers_and_Punctuation[] = {
+ 1,
+ 0x12400, 0x1247f,
+}; /* CR_In_Cuneiform_Numbers_and_Punctuation */
+
+/* 'In_Early_Dynastic_Cuneiform': Block */
+static const OnigCodePoint CR_In_Early_Dynastic_Cuneiform[] = {
+ 1,
+ 0x12480, 0x1254f,
+}; /* CR_In_Early_Dynastic_Cuneiform */
+
+/* 'In_Cypro_Minoan': Block */
+static const OnigCodePoint CR_In_Cypro_Minoan[] = {
+ 1,
+ 0x12f90, 0x12fff,
+}; /* CR_In_Cypro_Minoan */
+
+/* 'In_Egyptian_Hieroglyphs': Block */
+static const OnigCodePoint CR_In_Egyptian_Hieroglyphs[] = {
+ 1,
+ 0x13000, 0x1342f,
+}; /* CR_In_Egyptian_Hieroglyphs */
+
+/* 'In_Egyptian_Hieroglyph_Format_Controls': Block */
+static const OnigCodePoint CR_In_Egyptian_Hieroglyph_Format_Controls[] = {
+ 1,
+ 0x13430, 0x1345f,
+}; /* CR_In_Egyptian_Hieroglyph_Format_Controls */
+
+/* 'In_Egyptian_Hieroglyphs_Extended_A': Block */
+static const OnigCodePoint CR_In_Egyptian_Hieroglyphs_Extended_A[] = {
+ 1,
+ 0x13460, 0x143ff,
+}; /* CR_In_Egyptian_Hieroglyphs_Extended_A */
+
+/* 'In_Anatolian_Hieroglyphs': Block */
+static const OnigCodePoint CR_In_Anatolian_Hieroglyphs[] = {
+ 1,
+ 0x14400, 0x1467f,
+}; /* CR_In_Anatolian_Hieroglyphs */
+
+/* 'In_Gurung_Khema': Block */
+static const OnigCodePoint CR_In_Gurung_Khema[] = {
+ 1,
+ 0x16100, 0x1613f,
+}; /* CR_In_Gurung_Khema */
+
+/* 'In_Bamum_Supplement': Block */
+static const OnigCodePoint CR_In_Bamum_Supplement[] = {
+ 1,
+ 0x16800, 0x16a3f,
+}; /* CR_In_Bamum_Supplement */
+
+/* 'In_Mro': Block */
+static const OnigCodePoint CR_In_Mro[] = {
+ 1,
+ 0x16a40, 0x16a6f,
+}; /* CR_In_Mro */
+
+/* 'In_Tangsa': Block */
+static const OnigCodePoint CR_In_Tangsa[] = {
+ 1,
+ 0x16a70, 0x16acf,
+}; /* CR_In_Tangsa */
+
+/* 'In_Bassa_Vah': Block */
+static const OnigCodePoint CR_In_Bassa_Vah[] = {
+ 1,
+ 0x16ad0, 0x16aff,
+}; /* CR_In_Bassa_Vah */
+
+/* 'In_Pahawh_Hmong': Block */
+static const OnigCodePoint CR_In_Pahawh_Hmong[] = {
+ 1,
+ 0x16b00, 0x16b8f,
+}; /* CR_In_Pahawh_Hmong */
+
+/* 'In_Kirat_Rai': Block */
+static const OnigCodePoint CR_In_Kirat_Rai[] = {
+ 1,
+ 0x16d40, 0x16d7f,
+}; /* CR_In_Kirat_Rai */
+
+/* 'In_Medefaidrin': Block */
+static const OnigCodePoint CR_In_Medefaidrin[] = {
+ 1,
+ 0x16e40, 0x16e9f,
+}; /* CR_In_Medefaidrin */
+
+/* 'In_Beria_Erfe': Block */
+static const OnigCodePoint CR_In_Beria_Erfe[] = {
+ 1,
+ 0x16ea0, 0x16edf,
+}; /* CR_In_Beria_Erfe */
+
+/* 'In_Miao': Block */
+static const OnigCodePoint CR_In_Miao[] = {
+ 1,
+ 0x16f00, 0x16f9f,
+}; /* CR_In_Miao */
+
+/* 'In_Ideographic_Symbols_and_Punctuation': Block */
+static const OnigCodePoint CR_In_Ideographic_Symbols_and_Punctuation[] = {
+ 1,
+ 0x16fe0, 0x16fff,
+}; /* CR_In_Ideographic_Symbols_and_Punctuation */
+
+/* 'In_Tangut': Block */
+static const OnigCodePoint CR_In_Tangut[] = {
+ 1,
+ 0x17000, 0x187ff,
+}; /* CR_In_Tangut */
+
+/* 'In_Tangut_Components': Block */
+static const OnigCodePoint CR_In_Tangut_Components[] = {
+ 1,
+ 0x18800, 0x18aff,
+}; /* CR_In_Tangut_Components */
+
+/* 'In_Khitan_Small_Script': Block */
+static const OnigCodePoint CR_In_Khitan_Small_Script[] = {
+ 1,
+ 0x18b00, 0x18cff,
+}; /* CR_In_Khitan_Small_Script */
+
+/* 'In_Tangut_Supplement': Block */
+static const OnigCodePoint CR_In_Tangut_Supplement[] = {
+ 1,
+ 0x18d00, 0x18d7f,
+}; /* CR_In_Tangut_Supplement */
+
+/* 'In_Tangut_Components_Supplement': Block */
+static const OnigCodePoint CR_In_Tangut_Components_Supplement[] = {
+ 1,
+ 0x18d80, 0x18dff,
+}; /* CR_In_Tangut_Components_Supplement */
+
+/* 'In_Kana_Extended_B': Block */
+static const OnigCodePoint CR_In_Kana_Extended_B[] = {
+ 1,
+ 0x1aff0, 0x1afff,
+}; /* CR_In_Kana_Extended_B */
+
+/* 'In_Kana_Supplement': Block */
+static const OnigCodePoint CR_In_Kana_Supplement[] = {
+ 1,
+ 0x1b000, 0x1b0ff,
+}; /* CR_In_Kana_Supplement */
+
+/* 'In_Kana_Extended_A': Block */
+static const OnigCodePoint CR_In_Kana_Extended_A[] = {
+ 1,
+ 0x1b100, 0x1b12f,
+}; /* CR_In_Kana_Extended_A */
+
+/* 'In_Small_Kana_Extension': Block */
+static const OnigCodePoint CR_In_Small_Kana_Extension[] = {
+ 1,
+ 0x1b130, 0x1b16f,
+}; /* CR_In_Small_Kana_Extension */
+
+/* 'In_Nushu': Block */
+static const OnigCodePoint CR_In_Nushu[] = {
+ 1,
+ 0x1b170, 0x1b2ff,
+}; /* CR_In_Nushu */
+
+/* 'In_Duployan': Block */
+static const OnigCodePoint CR_In_Duployan[] = {
+ 1,
+ 0x1bc00, 0x1bc9f,
+}; /* CR_In_Duployan */
+
+/* 'In_Shorthand_Format_Controls': Block */
+static const OnigCodePoint CR_In_Shorthand_Format_Controls[] = {
+ 1,
+ 0x1bca0, 0x1bcaf,
+}; /* CR_In_Shorthand_Format_Controls */
+
+/* 'In_Symbols_for_Legacy_Computing_Supplement': Block */
+static const OnigCodePoint CR_In_Symbols_for_Legacy_Computing_Supplement[] = {
+ 1,
+ 0x1cc00, 0x1cebf,
+}; /* CR_In_Symbols_for_Legacy_Computing_Supplement */
+
+/* 'In_Miscellaneous_Symbols_Supplement': Block */
+static const OnigCodePoint CR_In_Miscellaneous_Symbols_Supplement[] = {
+ 1,
+ 0x1cec0, 0x1ceff,
+}; /* CR_In_Miscellaneous_Symbols_Supplement */
+
+/* 'In_Znamenny_Musical_Notation': Block */
+static const OnigCodePoint CR_In_Znamenny_Musical_Notation[] = {
+ 1,
+ 0x1cf00, 0x1cfcf,
+}; /* CR_In_Znamenny_Musical_Notation */
+
+/* 'In_Byzantine_Musical_Symbols': Block */
+static const OnigCodePoint CR_In_Byzantine_Musical_Symbols[] = {
+ 1,
+ 0x1d000, 0x1d0ff,
+}; /* CR_In_Byzantine_Musical_Symbols */
+
+/* 'In_Musical_Symbols': Block */
+static const OnigCodePoint CR_In_Musical_Symbols[] = {
+ 1,
+ 0x1d100, 0x1d1ff,
+}; /* CR_In_Musical_Symbols */
+
+/* 'In_Ancient_Greek_Musical_Notation': Block */
+static const OnigCodePoint CR_In_Ancient_Greek_Musical_Notation[] = {
+ 1,
+ 0x1d200, 0x1d24f,
+}; /* CR_In_Ancient_Greek_Musical_Notation */
+
+/* 'In_Kaktovik_Numerals': Block */
+static const OnigCodePoint CR_In_Kaktovik_Numerals[] = {
+ 1,
+ 0x1d2c0, 0x1d2df,
+}; /* CR_In_Kaktovik_Numerals */
+
+/* 'In_Mayan_Numerals': Block */
+static const OnigCodePoint CR_In_Mayan_Numerals[] = {
+ 1,
+ 0x1d2e0, 0x1d2ff,
+}; /* CR_In_Mayan_Numerals */
+
+/* 'In_Tai_Xuan_Jing_Symbols': Block */
+static const OnigCodePoint CR_In_Tai_Xuan_Jing_Symbols[] = {
+ 1,
+ 0x1d300, 0x1d35f,
+}; /* CR_In_Tai_Xuan_Jing_Symbols */
+
+/* 'In_Counting_Rod_Numerals': Block */
+static const OnigCodePoint CR_In_Counting_Rod_Numerals[] = {
+ 1,
+ 0x1d360, 0x1d37f,
+}; /* CR_In_Counting_Rod_Numerals */
+
+/* 'In_Mathematical_Alphanumeric_Symbols': Block */
+static const OnigCodePoint CR_In_Mathematical_Alphanumeric_Symbols[] = {
+ 1,
+ 0x1d400, 0x1d7ff,
+}; /* CR_In_Mathematical_Alphanumeric_Symbols */
+
+/* 'In_Sutton_SignWriting': Block */
+static const OnigCodePoint CR_In_Sutton_SignWriting[] = {
+ 1,
+ 0x1d800, 0x1daaf,
+}; /* CR_In_Sutton_SignWriting */
+
+/* 'In_Latin_Extended_G': Block */
+static const OnigCodePoint CR_In_Latin_Extended_G[] = {
+ 1,
+ 0x1df00, 0x1dfff,
+}; /* CR_In_Latin_Extended_G */
+
+/* 'In_Glagolitic_Supplement': Block */
+static const OnigCodePoint CR_In_Glagolitic_Supplement[] = {
+ 1,
+ 0x1e000, 0x1e02f,
+}; /* CR_In_Glagolitic_Supplement */
+
+/* 'In_Cyrillic_Extended_D': Block */
+static const OnigCodePoint CR_In_Cyrillic_Extended_D[] = {
+ 1,
+ 0x1e030, 0x1e08f,
+}; /* CR_In_Cyrillic_Extended_D */
+
+/* 'In_Nyiakeng_Puachue_Hmong': Block */
+static const OnigCodePoint CR_In_Nyiakeng_Puachue_Hmong[] = {
+ 1,
+ 0x1e100, 0x1e14f,
+}; /* CR_In_Nyiakeng_Puachue_Hmong */
+
+/* 'In_Toto': Block */
+static const OnigCodePoint CR_In_Toto[] = {
+ 1,
+ 0x1e290, 0x1e2bf,
+}; /* CR_In_Toto */
+
+/* 'In_Wancho': Block */
+static const OnigCodePoint CR_In_Wancho[] = {
+ 1,
+ 0x1e2c0, 0x1e2ff,
+}; /* CR_In_Wancho */
+
+/* 'In_Nag_Mundari': Block */
+static const OnigCodePoint CR_In_Nag_Mundari[] = {
+ 1,
+ 0x1e4d0, 0x1e4ff,
+}; /* CR_In_Nag_Mundari */
+
+/* 'In_Ol_Onal': Block */
+static const OnigCodePoint CR_In_Ol_Onal[] = {
+ 1,
+ 0x1e5d0, 0x1e5ff,
+}; /* CR_In_Ol_Onal */
+
+/* 'In_Tai_Yo': Block */
+static const OnigCodePoint CR_In_Tai_Yo[] = {
+ 1,
+ 0x1e6c0, 0x1e6ff,
+}; /* CR_In_Tai_Yo */
+
+/* 'In_Ethiopic_Extended_B': Block */
+static const OnigCodePoint CR_In_Ethiopic_Extended_B[] = {
+ 1,
+ 0x1e7e0, 0x1e7ff,
+}; /* CR_In_Ethiopic_Extended_B */
+
+/* 'In_Mende_Kikakui': Block */
+static const OnigCodePoint CR_In_Mende_Kikakui[] = {
+ 1,
+ 0x1e800, 0x1e8df,
+}; /* CR_In_Mende_Kikakui */
+
+/* 'In_Adlam': Block */
+static const OnigCodePoint CR_In_Adlam[] = {
+ 1,
+ 0x1e900, 0x1e95f,
+}; /* CR_In_Adlam */
+
+/* 'In_Indic_Siyaq_Numbers': Block */
+static const OnigCodePoint CR_In_Indic_Siyaq_Numbers[] = {
+ 1,
+ 0x1ec70, 0x1ecbf,
+}; /* CR_In_Indic_Siyaq_Numbers */
+
+/* 'In_Ottoman_Siyaq_Numbers': Block */
+static const OnigCodePoint CR_In_Ottoman_Siyaq_Numbers[] = {
+ 1,
+ 0x1ed00, 0x1ed4f,
+}; /* CR_In_Ottoman_Siyaq_Numbers */
+
+/* 'In_Arabic_Mathematical_Alphabetic_Symbols': Block */
+static const OnigCodePoint CR_In_Arabic_Mathematical_Alphabetic_Symbols[] = {
+ 1,
+ 0x1ee00, 0x1eeff,
+}; /* CR_In_Arabic_Mathematical_Alphabetic_Symbols */
+
+/* 'In_Mahjong_Tiles': Block */
+static const OnigCodePoint CR_In_Mahjong_Tiles[] = {
+ 1,
+ 0x1f000, 0x1f02f,
+}; /* CR_In_Mahjong_Tiles */
+
+/* 'In_Domino_Tiles': Block */
+static const OnigCodePoint CR_In_Domino_Tiles[] = {
+ 1,
+ 0x1f030, 0x1f09f,
+}; /* CR_In_Domino_Tiles */
+
+/* 'In_Playing_Cards': Block */
+static const OnigCodePoint CR_In_Playing_Cards[] = {
+ 1,
+ 0x1f0a0, 0x1f0ff,
+}; /* CR_In_Playing_Cards */
+
+/* 'In_Enclosed_Alphanumeric_Supplement': Block */
+static const OnigCodePoint CR_In_Enclosed_Alphanumeric_Supplement[] = {
+ 1,
+ 0x1f100, 0x1f1ff,
+}; /* CR_In_Enclosed_Alphanumeric_Supplement */
+
+/* 'In_Enclosed_Ideographic_Supplement': Block */
+static const OnigCodePoint CR_In_Enclosed_Ideographic_Supplement[] = {
+ 1,
+ 0x1f200, 0x1f2ff,
+}; /* CR_In_Enclosed_Ideographic_Supplement */
+
+/* 'In_Miscellaneous_Symbols_and_Pictographs': Block */
+static const OnigCodePoint CR_In_Miscellaneous_Symbols_and_Pictographs[] = {
+ 1,
+ 0x1f300, 0x1f5ff,
+}; /* CR_In_Miscellaneous_Symbols_and_Pictographs */
+
+/* 'In_Emoticons': Block */
+static const OnigCodePoint CR_In_Emoticons[] = {
+ 1,
+ 0x1f600, 0x1f64f,
+}; /* CR_In_Emoticons */
+
+/* 'In_Ornamental_Dingbats': Block */
+static const OnigCodePoint CR_In_Ornamental_Dingbats[] = {
+ 1,
+ 0x1f650, 0x1f67f,
+}; /* CR_In_Ornamental_Dingbats */
+
+/* 'In_Transport_and_Map_Symbols': Block */
+static const OnigCodePoint CR_In_Transport_and_Map_Symbols[] = {
+ 1,
+ 0x1f680, 0x1f6ff,
+}; /* CR_In_Transport_and_Map_Symbols */
+
+/* 'In_Alchemical_Symbols': Block */
+static const OnigCodePoint CR_In_Alchemical_Symbols[] = {
+ 1,
+ 0x1f700, 0x1f77f,
+}; /* CR_In_Alchemical_Symbols */
+
+/* 'In_Geometric_Shapes_Extended': Block */
+static const OnigCodePoint CR_In_Geometric_Shapes_Extended[] = {
+ 1,
+ 0x1f780, 0x1f7ff,
+}; /* CR_In_Geometric_Shapes_Extended */
+
+/* 'In_Supplemental_Arrows_C': Block */
+static const OnigCodePoint CR_In_Supplemental_Arrows_C[] = {
+ 1,
+ 0x1f800, 0x1f8ff,
+}; /* CR_In_Supplemental_Arrows_C */
+
+/* 'In_Supplemental_Symbols_and_Pictographs': Block */
+static const OnigCodePoint CR_In_Supplemental_Symbols_and_Pictographs[] = {
+ 1,
+ 0x1f900, 0x1f9ff,
+}; /* CR_In_Supplemental_Symbols_and_Pictographs */
+
+/* 'In_Chess_Symbols': Block */
+static const OnigCodePoint CR_In_Chess_Symbols[] = {
+ 1,
+ 0x1fa00, 0x1fa6f,
+}; /* CR_In_Chess_Symbols */
+
+/* 'In_Symbols_and_Pictographs_Extended_A': Block */
+static const OnigCodePoint CR_In_Symbols_and_Pictographs_Extended_A[] = {
+ 1,
+ 0x1fa70, 0x1faff,
+}; /* CR_In_Symbols_and_Pictographs_Extended_A */
+
+/* 'In_Symbols_for_Legacy_Computing': Block */
+static const OnigCodePoint CR_In_Symbols_for_Legacy_Computing[] = {
+ 1,
+ 0x1fb00, 0x1fbff,
+}; /* CR_In_Symbols_for_Legacy_Computing */
+
+/* 'In_CJK_Unified_Ideographs_Extension_B': Block */
+static const OnigCodePoint CR_In_CJK_Unified_Ideographs_Extension_B[] = {
+ 1,
+ 0x20000, 0x2a6df,
+}; /* CR_In_CJK_Unified_Ideographs_Extension_B */
+
+/* 'In_CJK_Unified_Ideographs_Extension_C': Block */
+static const OnigCodePoint CR_In_CJK_Unified_Ideographs_Extension_C[] = {
+ 1,
+ 0x2a700, 0x2b73f,
+}; /* CR_In_CJK_Unified_Ideographs_Extension_C */
+
+/* 'In_CJK_Unified_Ideographs_Extension_D': Block */
+static const OnigCodePoint CR_In_CJK_Unified_Ideographs_Extension_D[] = {
+ 1,
+ 0x2b740, 0x2b81f,
+}; /* CR_In_CJK_Unified_Ideographs_Extension_D */
+
+/* 'In_CJK_Unified_Ideographs_Extension_E': Block */
+static const OnigCodePoint CR_In_CJK_Unified_Ideographs_Extension_E[] = {
+ 1,
+ 0x2b820, 0x2ceaf,
+}; /* CR_In_CJK_Unified_Ideographs_Extension_E */
+
+/* 'In_CJK_Unified_Ideographs_Extension_F': Block */
+static const OnigCodePoint CR_In_CJK_Unified_Ideographs_Extension_F[] = {
+ 1,
+ 0x2ceb0, 0x2ebef,
+}; /* CR_In_CJK_Unified_Ideographs_Extension_F */
+
+/* 'In_CJK_Unified_Ideographs_Extension_I': Block */
+static const OnigCodePoint CR_In_CJK_Unified_Ideographs_Extension_I[] = {
+ 1,
+ 0x2ebf0, 0x2ee5f,
+}; /* CR_In_CJK_Unified_Ideographs_Extension_I */
+
+/* 'In_CJK_Compatibility_Ideographs_Supplement': Block */
+static const OnigCodePoint CR_In_CJK_Compatibility_Ideographs_Supplement[] = {
+ 1,
+ 0x2f800, 0x2fa1f,
+}; /* CR_In_CJK_Compatibility_Ideographs_Supplement */
+
+/* 'In_CJK_Unified_Ideographs_Extension_G': Block */
+static const OnigCodePoint CR_In_CJK_Unified_Ideographs_Extension_G[] = {
+ 1,
+ 0x30000, 0x3134f,
+}; /* CR_In_CJK_Unified_Ideographs_Extension_G */
+
+/* 'In_CJK_Unified_Ideographs_Extension_H': Block */
+static const OnigCodePoint CR_In_CJK_Unified_Ideographs_Extension_H[] = {
+ 1,
+ 0x31350, 0x323af,
+}; /* CR_In_CJK_Unified_Ideographs_Extension_H */
+
+/* 'In_CJK_Unified_Ideographs_Extension_J': Block */
+static const OnigCodePoint CR_In_CJK_Unified_Ideographs_Extension_J[] = {
+ 1,
+ 0x323b0, 0x3347f,
+}; /* CR_In_CJK_Unified_Ideographs_Extension_J */
+
+/* 'In_Tags': Block */
+static const OnigCodePoint CR_In_Tags[] = {
+ 1,
+ 0xe0000, 0xe007f,
+}; /* CR_In_Tags */
+
+/* 'In_Variation_Selectors_Supplement': Block */
+static const OnigCodePoint CR_In_Variation_Selectors_Supplement[] = {
+ 1,
+ 0xe0100, 0xe01ef,
+}; /* CR_In_Variation_Selectors_Supplement */
+
+/* 'In_Supplementary_Private_Use_Area_A': Block */
+static const OnigCodePoint CR_In_Supplementary_Private_Use_Area_A[] = {
+ 1,
+ 0xf0000, 0xfffff,
+}; /* CR_In_Supplementary_Private_Use_Area_A */
+
+/* 'In_Supplementary_Private_Use_Area_B': Block */
+static const OnigCodePoint CR_In_Supplementary_Private_Use_Area_B[] = {
+ 1,
+ 0x100000, 0x10ffff,
+}; /* CR_In_Supplementary_Private_Use_Area_B */
+
+/* 'In_No_Block': Block */
+static const OnigCodePoint CR_In_No_Block[] = {
+ 51,
+ 0x2fe0, 0x2fef,
+ 0x10200, 0x1027f,
+ 0x103e0, 0x103ff,
+ 0x107c0, 0x107ff,
+ 0x108b0, 0x108df,
+ 0x10960, 0x1097f,
+ 0x10aa0, 0x10abf,
+ 0x10bb0, 0x10bff,
+ 0x10c50, 0x10c7f,
+ 0x10d90, 0x10e5f,
+ 0x11250, 0x1127f,
+ 0x114e0, 0x1157f,
+ 0x11750, 0x117ff,
+ 0x11850, 0x1189f,
+ 0x11960, 0x1199f,
+ 0x11b80, 0x11bbf,
+ 0x11cc0, 0x11cff,
+ 0x11df0, 0x11edf,
+ 0x11f60, 0x11faf,
+ 0x12550, 0x12f8f,
+ 0x14680, 0x160ff,
+ 0x16140, 0x167ff,
+ 0x16b90, 0x16d3f,
+ 0x16d80, 0x16e3f,
+ 0x16ee0, 0x16eff,
+ 0x16fa0, 0x16fdf,
+ 0x18e00, 0x1afef,
+ 0x1b300, 0x1bbff,
+ 0x1bcb0, 0x1cbff,
+ 0x1cfd0, 0x1cfff,
+ 0x1d250, 0x1d2bf,
+ 0x1d380, 0x1d3ff,
+ 0x1dab0, 0x1deff,
+ 0x1e090, 0x1e0ff,
+ 0x1e150, 0x1e28f,
+ 0x1e300, 0x1e4cf,
+ 0x1e500, 0x1e5cf,
+ 0x1e600, 0x1e6bf,
+ 0x1e700, 0x1e7df,
+ 0x1e8e0, 0x1e8ff,
+ 0x1e960, 0x1ec6f,
+ 0x1ecc0, 0x1ecff,
+ 0x1ed50, 0x1edff,
+ 0x1ef00, 0x1efff,
+ 0x1fc00, 0x1ffff,
+ 0x2a6e0, 0x2a6ff,
+ 0x2ee60, 0x2f7ff,
+ 0x2fa20, 0x2ffff,
+ 0x33480, 0xdffff,
+ 0xe0080, 0xe00ff,
+ 0xe01f0, 0xeffff,
+}; /* CR_In_No_Block */
+
+#endif /* USE_UNICODE_PROPERTIES */
+static const OnigCodePoint* const CodeRanges[] = {
+ CR_NEWLINE,
+ CR_Alpha,
+ CR_Blank,
+ CR_Cntrl,
+ CR_Digit,
+ CR_Graph,
+ CR_Lower,
+ CR_Print,
+ CR_XPosixPunct,
+ CR_Space,
+ CR_Upper,
+ CR_XDigit,
+ CR_Word,
+ CR_Alnum,
+ CR_ASCII,
+ CR_Punct,
+#ifdef USE_UNICODE_PROPERTIES
+ CR_Any,
+ CR_Assigned,
+ CR_C,
+ CR_Cc,
+ CR_Cf,
+ CR_Cn,
+ CR_Co,
+ CR_Cs,
+ CR_L,
+ CR_LC,
+ CR_Ll,
+ CR_Lm,
+ CR_Lo,
+ CR_Lt,
+ CR_Lu,
+ CR_M,
+ CR_Mc,
+ CR_Me,
+ CR_Mn,
+ CR_N,
+ CR_Nd,
+ CR_Nl,
+ CR_No,
+ CR_P,
+ CR_Pc,
+ CR_Pd,
+ CR_Pe,
+ CR_Pf,
+ CR_Pi,
+ CR_Po,
+ CR_Ps,
+ CR_S,
+ CR_Sc,
+ CR_Sk,
+ CR_Sm,
+ CR_So,
+ CR_Z,
+ CR_Zl,
+ CR_Zp,
+ CR_Zs,
+ CR_Math,
+ CR_Alphabetic,
+ CR_Lowercase,
+ CR_Uppercase,
+ CR_Cased,
+ CR_Case_Ignorable,
+ CR_Changes_When_Lowercased,
+ CR_Changes_When_Uppercased,
+ CR_Changes_When_Titlecased,
+ CR_Changes_When_Casefolded,
+ CR_Changes_When_Casemapped,
+ CR_ID_Start,
+ CR_ID_Continue,
+ CR_XID_Start,
+ CR_XID_Continue,
+ CR_Default_Ignorable_Code_Point,
+ CR_Grapheme_Extend,
+ CR_Grapheme_Base,
+ CR_Grapheme_Link,
+ CR_InCB_Linker,
+ CR_InCB_Consonant,
+ CR_InCB_Extend,
+ CR_Common,
+ CR_Latin,
+ CR_Greek,
+ CR_Cyrillic,
+ CR_Armenian,
+ CR_Hebrew,
+ CR_Arabic,
+ CR_Syriac,
+ CR_Thaana,
+ CR_Devanagari,
+ CR_Bengali,
+ CR_Gurmukhi,
+ CR_Gujarati,
+ CR_Oriya,
+ CR_Tamil,
+ CR_Telugu,
+ CR_Kannada,
+ CR_Malayalam,
+ CR_Sinhala,
+ CR_Thai,
+ CR_Lao,
+ CR_Tibetan,
+ CR_Myanmar,
+ CR_Georgian,
+ CR_Hangul,
+ CR_Ethiopic,
+ CR_Cherokee,
+ CR_Canadian_Aboriginal,
+ CR_Ogham,
+ CR_Runic,
+ CR_Khmer,
+ CR_Mongolian,
+ CR_Hiragana,
+ CR_Katakana,
+ CR_Bopomofo,
+ CR_Han,
+ CR_Yi,
+ CR_Old_Italic,
+ CR_Gothic,
+ CR_Deseret,
+ CR_Inherited,
+ CR_Tagalog,
+ CR_Hanunoo,
+ CR_Buhid,
+ CR_Tagbanwa,
+ CR_Limbu,
+ CR_Tai_Le,
+ CR_Linear_B,
+ CR_Ugaritic,
+ CR_Shavian,
+ CR_Osmanya,
+ CR_Cypriot,
+ CR_Braille,
+ CR_Buginese,
+ CR_Coptic,
+ CR_New_Tai_Lue,
+ CR_Glagolitic,
+ CR_Tifinagh,
+ CR_Syloti_Nagri,
+ CR_Old_Persian,
+ CR_Kharoshthi,
+ CR_Balinese,
+ CR_Cuneiform,
+ CR_Phoenician,
+ CR_Phags_Pa,
+ CR_Nko,
+ CR_Sundanese,
+ CR_Lepcha,
+ CR_Ol_Chiki,
+ CR_Vai,
+ CR_Saurashtra,
+ CR_Kayah_Li,
+ CR_Rejang,
+ CR_Lycian,
+ CR_Carian,
+ CR_Lydian,
+ CR_Cham,
+ CR_Tai_Tham,
+ CR_Tai_Viet,
+ CR_Avestan,
+ CR_Egyptian_Hieroglyphs,
+ CR_Samaritan,
+ CR_Lisu,
+ CR_Bamum,
+ CR_Javanese,
+ CR_Meetei_Mayek,
+ CR_Imperial_Aramaic,
+ CR_Old_South_Arabian,
+ CR_Inscriptional_Parthian,
+ CR_Inscriptional_Pahlavi,
+ CR_Old_Turkic,
+ CR_Kaithi,
+ CR_Batak,
+ CR_Brahmi,
+ CR_Mandaic,
+ CR_Chakma,
+ CR_Meroitic_Cursive,
+ CR_Meroitic_Hieroglyphs,
+ CR_Miao,
+ CR_Sharada,
+ CR_Sora_Sompeng,
+ CR_Takri,
+ CR_Caucasian_Albanian,
+ CR_Bassa_Vah,
+ CR_Duployan,
+ CR_Elbasan,
+ CR_Grantha,
+ CR_Pahawh_Hmong,
+ CR_Khojki,
+ CR_Linear_A,
+ CR_Mahajani,
+ CR_Manichaean,
+ CR_Mende_Kikakui,
+ CR_Modi,
+ CR_Mro,
+ CR_Old_North_Arabian,
+ CR_Nabataean,
+ CR_Palmyrene,
+ CR_Pau_Cin_Hau,
+ CR_Old_Permic,
+ CR_Psalter_Pahlavi,
+ CR_Siddham,
+ CR_Khudawadi,
+ CR_Tirhuta,
+ CR_Warang_Citi,
+ CR_Ahom,
+ CR_Anatolian_Hieroglyphs,
+ CR_Hatran,
+ CR_Multani,
+ CR_Old_Hungarian,
+ CR_SignWriting,
+ CR_Adlam,
+ CR_Bhaiksuki,
+ CR_Marchen,
+ CR_Newa,
+ CR_Osage,
+ CR_Tangut,
+ CR_Masaram_Gondi,
+ CR_Nushu,
+ CR_Soyombo,
+ CR_Zanabazar_Square,
+ CR_Dogra,
+ CR_Gunjala_Gondi,
+ CR_Makasar,
+ CR_Medefaidrin,
+ CR_Hanifi_Rohingya,
+ CR_Sogdian,
+ CR_Old_Sogdian,
+ CR_Elymaic,
+ CR_Nandinagari,
+ CR_Nyiakeng_Puachue_Hmong,
+ CR_Wancho,
+ CR_Chorasmian,
+ CR_Dives_Akuru,
+ CR_Khitan_Small_Script,
+ CR_Yezidi,
+ CR_Cypro_Minoan,
+ CR_Old_Uyghur,
+ CR_Tangsa,
+ CR_Toto,
+ CR_Vithkuqi,
+ CR_Kawi,
+ CR_Nag_Mundari,
+ CR_Garay,
+ CR_Gurung_Khema,
+ CR_Kirat_Rai,
+ CR_Ol_Onal,
+ CR_Sunuwar,
+ CR_Todhri,
+ CR_Tulu_Tigalari,
+ CR_Sidetic,
+ CR_Tai_Yo,
+ CR_Tolong_Siki,
+ CR_Beria_Erfe,
+ CR_White_Space,
+ CR_Bidi_Control,
+ CR_Join_Control,
+ CR_Dash,
+ CR_Hyphen,
+ CR_Quotation_Mark,
+ CR_Terminal_Punctuation,
+ CR_Other_Math,
+ CR_Hex_Digit,
+ CR_ASCII_Hex_Digit,
+ CR_Other_Alphabetic,
+ CR_Ideographic,
+ CR_Diacritic,
+ CR_Extender,
+ CR_Other_Lowercase,
+ CR_Other_Uppercase,
+ CR_Noncharacter_Code_Point,
+ CR_Other_Grapheme_Extend,
+ CR_IDS_Binary_Operator,
+ CR_IDS_Trinary_Operator,
+ CR_IDS_Unary_Operator,
+ CR_Radical,
+ CR_Unified_Ideograph,
+ CR_Other_Default_Ignorable_Code_Point,
+ CR_Deprecated,
+ CR_Soft_Dotted,
+ CR_Logical_Order_Exception,
+ CR_Other_ID_Start,
+ CR_Other_ID_Continue,
+ CR_ID_Compat_Math_Continue,
+ CR_ID_Compat_Math_Start,
+ CR_Sentence_Terminal,
+ CR_Variation_Selector,
+ CR_Pattern_White_Space,
+ CR_Pattern_Syntax,
+ CR_Prepended_Concatenation_Mark,
+ CR_Regional_Indicator,
+ CR_Modifier_Combining_Mark,
+ CR_Emoji,
+ CR_Emoji_Presentation,
+ CR_Emoji_Modifier,
+ CR_Emoji_Modifier_Base,
+ CR_Emoji_Component,
+ CR_Extended_Pictographic,
+ CR_Unknown,
+#ifdef USE_UNICODE_AGE_PROPERTIES
+ CR_Age_1_1,
+ CR_Age_2_0,
+ CR_Age_2_1,
+ CR_Age_3_0,
+ CR_Age_3_1,
+ CR_Age_3_2,
+ CR_Age_4_0,
+ CR_Age_4_1,
+ CR_Age_5_0,
+ CR_Age_5_1,
+ CR_Age_5_2,
+ CR_Age_6_0,
+ CR_Age_6_1,
+ CR_Age_6_2,
+ CR_Age_6_3,
+ CR_Age_7_0,
+ CR_Age_8_0,
+ CR_Age_9_0,
+ CR_Age_10_0,
+ CR_Age_11_0,
+ CR_Age_12_0,
+ CR_Age_12_1,
+ CR_Age_13_0,
+ CR_Age_14_0,
+ CR_Age_15_0,
+ CR_Age_15_1,
+ CR_Age_16_0,
+ CR_Age_17_0,
+#endif /* USE_UNICODE_AGE_PROPERTIES */
+ CR_Grapheme_Cluster_Break_Prepend,
+ CR_Grapheme_Cluster_Break_CR,
+ CR_Grapheme_Cluster_Break_LF,
+ CR_Grapheme_Cluster_Break_Control,
+ CR_Grapheme_Cluster_Break_Extend,
+ CR_Grapheme_Cluster_Break_Regional_Indicator,
+ CR_Grapheme_Cluster_Break_SpacingMark,
+ CR_Grapheme_Cluster_Break_L,
+ CR_Grapheme_Cluster_Break_V,
+ CR_Grapheme_Cluster_Break_T,
+ CR_Grapheme_Cluster_Break_LV,
+ CR_Grapheme_Cluster_Break_LVT,
+ CR_Grapheme_Cluster_Break_ZWJ,
+ CR_In_Basic_Latin,
+ CR_In_Latin_1_Supplement,
+ CR_In_Latin_Extended_A,
+ CR_In_Latin_Extended_B,
+ CR_In_IPA_Extensions,
+ CR_In_Spacing_Modifier_Letters,
+ CR_In_Combining_Diacritical_Marks,
+ CR_In_Greek_and_Coptic,
+ CR_In_Cyrillic,
+ CR_In_Cyrillic_Supplement,
+ CR_In_Armenian,
+ CR_In_Hebrew,
+ CR_In_Arabic,
+ CR_In_Syriac,
+ CR_In_Arabic_Supplement,
+ CR_In_Thaana,
+ CR_In_NKo,
+ CR_In_Samaritan,
+ CR_In_Mandaic,
+ CR_In_Syriac_Supplement,
+ CR_In_Arabic_Extended_B,
+ CR_In_Arabic_Extended_A,
+ CR_In_Devanagari,
+ CR_In_Bengali,
+ CR_In_Gurmukhi,
+ CR_In_Gujarati,
+ CR_In_Oriya,
+ CR_In_Tamil,
+ CR_In_Telugu,
+ CR_In_Kannada,
+ CR_In_Malayalam,
+ CR_In_Sinhala,
+ CR_In_Thai,
+ CR_In_Lao,
+ CR_In_Tibetan,
+ CR_In_Myanmar,
+ CR_In_Georgian,
+ CR_In_Hangul_Jamo,
+ CR_In_Ethiopic,
+ CR_In_Ethiopic_Supplement,
+ CR_In_Cherokee,
+ CR_In_Unified_Canadian_Aboriginal_Syllabics,
+ CR_In_Ogham,
+ CR_In_Runic,
+ CR_In_Tagalog,
+ CR_In_Hanunoo,
+ CR_In_Buhid,
+ CR_In_Tagbanwa,
+ CR_In_Khmer,
+ CR_In_Mongolian,
+ CR_In_Unified_Canadian_Aboriginal_Syllabics_Extended,
+ CR_In_Limbu,
+ CR_In_Tai_Le,
+ CR_In_New_Tai_Lue,
+ CR_In_Khmer_Symbols,
+ CR_In_Buginese,
+ CR_In_Tai_Tham,
+ CR_In_Combining_Diacritical_Marks_Extended,
+ CR_In_Balinese,
+ CR_In_Sundanese,
+ CR_In_Batak,
+ CR_In_Lepcha,
+ CR_In_Ol_Chiki,
+ CR_In_Cyrillic_Extended_C,
+ CR_In_Georgian_Extended,
+ CR_In_Sundanese_Supplement,
+ CR_In_Vedic_Extensions,
+ CR_In_Phonetic_Extensions,
+ CR_In_Phonetic_Extensions_Supplement,
+ CR_In_Combining_Diacritical_Marks_Supplement,
+ CR_In_Latin_Extended_Additional,
+ CR_In_Greek_Extended,
+ CR_In_General_Punctuation,
+ CR_In_Superscripts_and_Subscripts,
+ CR_In_Currency_Symbols,
+ CR_In_Combining_Diacritical_Marks_for_Symbols,
+ CR_In_Letterlike_Symbols,
+ CR_In_Number_Forms,
+ CR_In_Arrows,
+ CR_In_Mathematical_Operators,
+ CR_In_Miscellaneous_Technical,
+ CR_In_Control_Pictures,
+ CR_In_Optical_Character_Recognition,
+ CR_In_Enclosed_Alphanumerics,
+ CR_In_Box_Drawing,
+ CR_In_Block_Elements,
+ CR_In_Geometric_Shapes,
+ CR_In_Miscellaneous_Symbols,
+ CR_In_Dingbats,
+ CR_In_Miscellaneous_Mathematical_Symbols_A,
+ CR_In_Supplemental_Arrows_A,
+ CR_In_Braille_Patterns,
+ CR_In_Supplemental_Arrows_B,
+ CR_In_Miscellaneous_Mathematical_Symbols_B,
+ CR_In_Supplemental_Mathematical_Operators,
+ CR_In_Miscellaneous_Symbols_and_Arrows,
+ CR_In_Glagolitic,
+ CR_In_Latin_Extended_C,
+ CR_In_Coptic,
+ CR_In_Georgian_Supplement,
+ CR_In_Tifinagh,
+ CR_In_Ethiopic_Extended,
+ CR_In_Cyrillic_Extended_A,
+ CR_In_Supplemental_Punctuation,
+ CR_In_CJK_Radicals_Supplement,
+ CR_In_Kangxi_Radicals,
+ CR_In_Ideographic_Description_Characters,
+ CR_In_CJK_Symbols_and_Punctuation,
+ CR_In_Hiragana,
+ CR_In_Katakana,
+ CR_In_Bopomofo,
+ CR_In_Hangul_Compatibility_Jamo,
+ CR_In_Kanbun,
+ CR_In_Bopomofo_Extended,
+ CR_In_CJK_Strokes,
+ CR_In_Katakana_Phonetic_Extensions,
+ CR_In_Enclosed_CJK_Letters_and_Months,
+ CR_In_CJK_Compatibility,
+ CR_In_CJK_Unified_Ideographs_Extension_A,
+ CR_In_Yijing_Hexagram_Symbols,
+ CR_In_CJK_Unified_Ideographs,
+ CR_In_Yi_Syllables,
+ CR_In_Yi_Radicals,
+ CR_In_Lisu,
+ CR_In_Vai,
+ CR_In_Cyrillic_Extended_B,
+ CR_In_Bamum,
+ CR_In_Modifier_Tone_Letters,
+ CR_In_Latin_Extended_D,
+ CR_In_Syloti_Nagri,
+ CR_In_Common_Indic_Number_Forms,
+ CR_In_Phags_pa,
+ CR_In_Saurashtra,
+ CR_In_Devanagari_Extended,
+ CR_In_Kayah_Li,
+ CR_In_Rejang,
+ CR_In_Hangul_Jamo_Extended_A,
+ CR_In_Javanese,
+ CR_In_Myanmar_Extended_B,
+ CR_In_Cham,
+ CR_In_Myanmar_Extended_A,
+ CR_In_Tai_Viet,
+ CR_In_Meetei_Mayek_Extensions,
+ CR_In_Ethiopic_Extended_A,
+ CR_In_Latin_Extended_E,
+ CR_In_Cherokee_Supplement,
+ CR_In_Meetei_Mayek,
+ CR_In_Hangul_Syllables,
+ CR_In_Hangul_Jamo_Extended_B,
+ CR_In_High_Surrogates,
+ CR_In_High_Private_Use_Surrogates,
+ CR_In_Low_Surrogates,
+ CR_In_Private_Use_Area,
+ CR_In_CJK_Compatibility_Ideographs,
+ CR_In_Alphabetic_Presentation_Forms,
+ CR_In_Arabic_Presentation_Forms_A,
+ CR_In_Variation_Selectors,
+ CR_In_Vertical_Forms,
+ CR_In_Combining_Half_Marks,
+ CR_In_CJK_Compatibility_Forms,
+ CR_In_Small_Form_Variants,
+ CR_In_Arabic_Presentation_Forms_B,
+ CR_In_Halfwidth_and_Fullwidth_Forms,
+ CR_In_Specials,
+ CR_In_Linear_B_Syllabary,
+ CR_In_Linear_B_Ideograms,
+ CR_In_Aegean_Numbers,
+ CR_In_Ancient_Greek_Numbers,
+ CR_In_Ancient_Symbols,
+ CR_In_Phaistos_Disc,
+ CR_In_Lycian,
+ CR_In_Carian,
+ CR_In_Coptic_Epact_Numbers,
+ CR_In_Old_Italic,
+ CR_In_Gothic,
+ CR_In_Old_Permic,
+ CR_In_Ugaritic,
+ CR_In_Old_Persian,
+ CR_In_Deseret,
+ CR_In_Shavian,
+ CR_In_Osmanya,
+ CR_In_Osage,
+ CR_In_Elbasan,
+ CR_In_Caucasian_Albanian,
+ CR_In_Vithkuqi,
+ CR_In_Todhri,
+ CR_In_Linear_A,
+ CR_In_Latin_Extended_F,
+ CR_In_Cypriot_Syllabary,
+ CR_In_Imperial_Aramaic,
+ CR_In_Palmyrene,
+ CR_In_Nabataean,
+ CR_In_Hatran,
+ CR_In_Phoenician,
+ CR_In_Lydian,
+ CR_In_Sidetic,
+ CR_In_Meroitic_Hieroglyphs,
+ CR_In_Meroitic_Cursive,
+ CR_In_Kharoshthi,
+ CR_In_Old_South_Arabian,
+ CR_In_Old_North_Arabian,
+ CR_In_Manichaean,
+ CR_In_Avestan,
+ CR_In_Inscriptional_Parthian,
+ CR_In_Inscriptional_Pahlavi,
+ CR_In_Psalter_Pahlavi,
+ CR_In_Old_Turkic,
+ CR_In_Old_Hungarian,
+ CR_In_Hanifi_Rohingya,
+ CR_In_Garay,
+ CR_In_Rumi_Numeral_Symbols,
+ CR_In_Yezidi,
+ CR_In_Arabic_Extended_C,
+ CR_In_Old_Sogdian,
+ CR_In_Sogdian,
+ CR_In_Old_Uyghur,
+ CR_In_Chorasmian,
+ CR_In_Elymaic,
+ CR_In_Brahmi,
+ CR_In_Kaithi,
+ CR_In_Sora_Sompeng,
+ CR_In_Chakma,
+ CR_In_Mahajani,
+ CR_In_Sharada,
+ CR_In_Sinhala_Archaic_Numbers,
+ CR_In_Khojki,
+ CR_In_Multani,
+ CR_In_Khudawadi,
+ CR_In_Grantha,
+ CR_In_Tulu_Tigalari,
+ CR_In_Newa,
+ CR_In_Tirhuta,
+ CR_In_Siddham,
+ CR_In_Modi,
+ CR_In_Mongolian_Supplement,
+ CR_In_Takri,
+ CR_In_Myanmar_Extended_C,
+ CR_In_Ahom,
+ CR_In_Dogra,
+ CR_In_Warang_Citi,
+ CR_In_Dives_Akuru,
+ CR_In_Nandinagari,
+ CR_In_Zanabazar_Square,
+ CR_In_Soyombo,
+ CR_In_Unified_Canadian_Aboriginal_Syllabics_Extended_A,
+ CR_In_Pau_Cin_Hau,
+ CR_In_Devanagari_Extended_A,
+ CR_In_Sharada_Supplement,
+ CR_In_Sunuwar,
+ CR_In_Bhaiksuki,
+ CR_In_Marchen,
+ CR_In_Masaram_Gondi,
+ CR_In_Gunjala_Gondi,
+ CR_In_Tolong_Siki,
+ CR_In_Makasar,
+ CR_In_Kawi,
+ CR_In_Lisu_Supplement,
+ CR_In_Tamil_Supplement,
+ CR_In_Cuneiform,
+ CR_In_Cuneiform_Numbers_and_Punctuation,
+ CR_In_Early_Dynastic_Cuneiform,
+ CR_In_Cypro_Minoan,
+ CR_In_Egyptian_Hieroglyphs,
+ CR_In_Egyptian_Hieroglyph_Format_Controls,
+ CR_In_Egyptian_Hieroglyphs_Extended_A,
+ CR_In_Anatolian_Hieroglyphs,
+ CR_In_Gurung_Khema,
+ CR_In_Bamum_Supplement,
+ CR_In_Mro,
+ CR_In_Tangsa,
+ CR_In_Bassa_Vah,
+ CR_In_Pahawh_Hmong,
+ CR_In_Kirat_Rai,
+ CR_In_Medefaidrin,
+ CR_In_Beria_Erfe,
+ CR_In_Miao,
+ CR_In_Ideographic_Symbols_and_Punctuation,
+ CR_In_Tangut,
+ CR_In_Tangut_Components,
+ CR_In_Khitan_Small_Script,
+ CR_In_Tangut_Supplement,
+ CR_In_Tangut_Components_Supplement,
+ CR_In_Kana_Extended_B,
+ CR_In_Kana_Supplement,
+ CR_In_Kana_Extended_A,
+ CR_In_Small_Kana_Extension,
+ CR_In_Nushu,
+ CR_In_Duployan,
+ CR_In_Shorthand_Format_Controls,
+ CR_In_Symbols_for_Legacy_Computing_Supplement,
+ CR_In_Miscellaneous_Symbols_Supplement,
+ CR_In_Znamenny_Musical_Notation,
+ CR_In_Byzantine_Musical_Symbols,
+ CR_In_Musical_Symbols,
+ CR_In_Ancient_Greek_Musical_Notation,
+ CR_In_Kaktovik_Numerals,
+ CR_In_Mayan_Numerals,
+ CR_In_Tai_Xuan_Jing_Symbols,
+ CR_In_Counting_Rod_Numerals,
+ CR_In_Mathematical_Alphanumeric_Symbols,
+ CR_In_Sutton_SignWriting,
+ CR_In_Latin_Extended_G,
+ CR_In_Glagolitic_Supplement,
+ CR_In_Cyrillic_Extended_D,
+ CR_In_Nyiakeng_Puachue_Hmong,
+ CR_In_Toto,
+ CR_In_Wancho,
+ CR_In_Nag_Mundari,
+ CR_In_Ol_Onal,
+ CR_In_Tai_Yo,
+ CR_In_Ethiopic_Extended_B,
+ CR_In_Mende_Kikakui,
+ CR_In_Adlam,
+ CR_In_Indic_Siyaq_Numbers,
+ CR_In_Ottoman_Siyaq_Numbers,
+ CR_In_Arabic_Mathematical_Alphabetic_Symbols,
+ CR_In_Mahjong_Tiles,
+ CR_In_Domino_Tiles,
+ CR_In_Playing_Cards,
+ CR_In_Enclosed_Alphanumeric_Supplement,
+ CR_In_Enclosed_Ideographic_Supplement,
+ CR_In_Miscellaneous_Symbols_and_Pictographs,
+ CR_In_Emoticons,
+ CR_In_Ornamental_Dingbats,
+ CR_In_Transport_and_Map_Symbols,
+ CR_In_Alchemical_Symbols,
+ CR_In_Geometric_Shapes_Extended,
+ CR_In_Supplemental_Arrows_C,
+ CR_In_Supplemental_Symbols_and_Pictographs,
+ CR_In_Chess_Symbols,
+ CR_In_Symbols_and_Pictographs_Extended_A,
+ CR_In_Symbols_for_Legacy_Computing,
+ CR_In_CJK_Unified_Ideographs_Extension_B,
+ CR_In_CJK_Unified_Ideographs_Extension_C,
+ CR_In_CJK_Unified_Ideographs_Extension_D,
+ CR_In_CJK_Unified_Ideographs_Extension_E,
+ CR_In_CJK_Unified_Ideographs_Extension_F,
+ CR_In_CJK_Unified_Ideographs_Extension_I,
+ CR_In_CJK_Compatibility_Ideographs_Supplement,
+ CR_In_CJK_Unified_Ideographs_Extension_G,
+ CR_In_CJK_Unified_Ideographs_Extension_H,
+ CR_In_CJK_Unified_Ideographs_Extension_J,
+ CR_In_Tags,
+ CR_In_Variation_Selectors_Supplement,
+ CR_In_Supplementary_Private_Use_Area_A,
+ CR_In_Supplementary_Private_Use_Area_B,
+ CR_In_No_Block,
+#endif /* USE_UNICODE_PROPERTIES */
+};
+struct uniname2ctype_struct {
+ short name;
+ unsigned short ctype;
+};
+#define uniname2ctype_offset(str) offsetof(struct uniname2ctype_pool_t, uniname2ctype_pool_##str)
+
+static const struct uniname2ctype_struct *uniname2ctype_p(register const char *str, register size_t len);
+
+#ifndef USE_UNICODE_PROPERTIES
+#define TOTAL_KEYWORDS 15
+#define MIN_WORD_LENGTH 4
+#define MAX_WORD_LENGTH 11
+#define MIN_HASH_VALUE 6
+#define MAX_HASH_VALUE 20
+/* maximum key range = 15, duplicates = 0 */
+#else /* USE_UNICODE_PROPERTIES */
+#ifndef USE_UNICODE_AGE_PROPERTIES
+#define TOTAL_KEYWORDS 916
+#else /* USE_UNICODE_AGE_PROPERTIES */
+#define TOTAL_KEYWORDS 944
+#endif /* USE_UNICODE_AGE_PROPERTIES */
+#define MIN_WORD_LENGTH 1
+#define MAX_WORD_LENGTH 45
+#define MIN_HASH_VALUE 10
+#define MAX_HASH_VALUE 6068
+/* maximum key range = 6059, duplicates = 0 */
+#endif /* USE_UNICODE_PROPERTIES */
+
+#ifdef __GNUC__
+__inline
+#else
+#ifdef __cplusplus
+inline
+#endif
+#endif
+static unsigned int
+uniname2ctype_hash (register const char *str, register size_t len)
+{
+#ifndef USE_UNICODE_PROPERTIES
+ static const unsigned char asso_values[] =
+#else /* USE_UNICODE_PROPERTIES */
+ static const unsigned short asso_values[] =
+#endif /* USE_UNICODE_PROPERTIES */
+ {
+#ifndef USE_UNICODE_PROPERTIES
+ 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,
+ 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,
+ 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,
+ 21, 21, 21, 21, 21, 21, 21, 3, 12, 5,
+ 4, 21, 21, 10, 21, 1, 21, 21, 11, 21,
+ 2, 1, 1, 21, 1, 7, 4, 6, 21, 1,
+ 4, 21, 21, 21, 21, 21, 21, 21
+#else /* USE_UNICODE_PROPERTIES */
+ 6069, 6069, 6069, 6069, 6069, 6069, 6069, 6069, 6069, 6069,
+ 6069, 6069, 6069, 6069, 6069, 6069, 6069, 6069, 6069, 6069,
+ 6069, 6069, 6069, 6069, 6069, 6069, 6069, 6069, 6069, 6069,
+ 6069, 6069, 6069, 6069, 6069, 6069, 6069, 6069, 6069, 6069,
+#ifndef USE_UNICODE_AGE_PROPERTIES
+ 6069, 6069, 6069, 6069, 6069, 6069, 6069, 6069, 6069, 6069,
+ 6069, 6069, 6069, 6069, 6069, 6069, 6069, 6069, 6069, 6069,
+#else /* USE_UNICODE_AGE_PROPERTIES */
+ 6069, 6069, 6069, 6069, 6069, 6069, 8, 6069, 2, 1,
+ 4, 31, 11, 20, 27, 15, 23, 17, 6069, 6069,
+#endif /* USE_UNICODE_AGE_PROPERTIES */
+ 6069, 1, 6069, 6069, 6069, 6069, 6069, 6069, 6069, 6069,
+ 6069, 6069, 6069, 6069, 6069, 6069, 6069, 6069, 6069, 6069,
+ 6069, 6069, 6069, 6069, 6069, 6069, 6069, 6069, 6069, 6069,
+ 6069, 6069, 6069, 6069, 6069, 6069, 6069, 22, 28, 165,
+ 250, 131, 1160, 1288, 949, 4, 12, 1918, 452, 7,
+ 8, 1, 756, 2041, 623, 20, 68, 1025, 1509, 246,
+ 1475, 944, 814, 2, 6069, 6069, 6069, 6069, 6069
+#endif /* USE_UNICODE_PROPERTIES */
+ };
+#ifndef USE_UNICODE_PROPERTIES
+ return len + asso_values[(unsigned char)str[2]] + asso_values[(unsigned char)str[0]];
+#else /* USE_UNICODE_PROPERTIES */
+ register unsigned int hval = (unsigned int)len;
+
+ switch (hval)
+ {
+ default:
+ hval += asso_values[(unsigned char)str[15]];
+ /*FALLTHROUGH*/
+ case 15:
+ case 14:
+ case 13:
+ case 12:
+ hval += asso_values[(unsigned char)str[11]];
+ /*FALLTHROUGH*/
+ case 11:
+ case 10:
+ case 9:
+ case 8:
+ case 7:
+ case 6:
+ hval += asso_values[(unsigned char)str[5]];
+ /*FALLTHROUGH*/
+ case 5:
+ hval += asso_values[(unsigned char)str[4]];
+ /*FALLTHROUGH*/
+ case 4:
+ case 3:
+ hval += asso_values[(unsigned char)str[2]];
+ /*FALLTHROUGH*/
+ case 2:
+ hval += asso_values[(unsigned char)str[1]+1];
+ /*FALLTHROUGH*/
+ case 1:
+ hval += asso_values[(unsigned char)str[0]+1];
+ break;
+ }
+ return hval + asso_values[(unsigned char)str[len - 1]];
+#endif /* USE_UNICODE_PROPERTIES */
+}
+
+struct uniname2ctype_pool_t
+ {
+#ifndef USE_UNICODE_PROPERTIES
+ char uniname2ctype_pool_str6[sizeof("word")];
+ char uniname2ctype_pool_str7[sizeof("print")];
+ char uniname2ctype_pool_str8[sizeof("punct")];
+ char uniname2ctype_pool_str9[sizeof("alpha")];
+ char uniname2ctype_pool_str10[sizeof("alnum")];
+ char uniname2ctype_pool_str11[sizeof("xdigit")];
+ char uniname2ctype_pool_str12[sizeof("upper")];
+ char uniname2ctype_pool_str13[sizeof("ascii")];
+ char uniname2ctype_pool_str14[sizeof("cntrl")];
+ char uniname2ctype_pool_str15[sizeof("space")];
+ char uniname2ctype_pool_str16[sizeof("xposixpunct")];
+ char uniname2ctype_pool_str17[sizeof("lower")];
+ char uniname2ctype_pool_str18[sizeof("graph")];
+ char uniname2ctype_pool_str19[sizeof("digit")];
+ char uniname2ctype_pool_str20[sizeof("blank")];
+#else /* USE_UNICODE_PROPERTIES */
+ char uniname2ctype_pool_str10[sizeof("n")];
+ char uniname2ctype_pool_str16[sizeof("m")];
+ char uniname2ctype_pool_str19[sizeof("mn")];
+ char uniname2ctype_pool_str24[sizeof("lm")];
+ char uniname2ctype_pool_str27[sizeof("inmro")];
+ char uniname2ctype_pool_str28[sizeof("innko")];
+ char uniname2ctype_pool_str33[sizeof("mro")];
+ char uniname2ctype_pool_str34[sizeof("mroo")];
+ char uniname2ctype_pool_str38[sizeof("ri")];
+ char uniname2ctype_pool_str40[sizeof("lao")];
+ char uniname2ctype_pool_str41[sizeof("laoo")];
+ char uniname2ctype_pool_str44[sizeof("ahom")];
+ char uniname2ctype_pool_str45[sizeof("hano")];
+ char uniname2ctype_pool_str47[sizeof("miao")];
+ char uniname2ctype_pool_str48[sizeof("hani")];
+ char uniname2ctype_pool_str50[sizeof("inmiao")];
+ char uniname2ctype_pool_str51[sizeof("han")];
+ char uniname2ctype_pool_str52[sizeof("mani")];
+ char uniname2ctype_pool_str53[sizeof("lina")];
+ char uniname2ctype_pool_str56[sizeof("inahom")];
+ char uniname2ctype_pool_str57[sizeof("hanunoo")];
+ char uniname2ctype_pool_str58[sizeof("limb")];
+ char uniname2ctype_pool_str59[sizeof("linb")];
+ char uniname2ctype_pool_str60[sizeof("inmanichaean")];
+ char uniname2ctype_pool_str62[sizeof("alnum")];
+ char uniname2ctype_pool_str63[sizeof("armi")];
+ char uniname2ctype_pool_str64[sizeof("nandinagari")];
+ char uniname2ctype_pool_str67[sizeof("armn")];
+ char uniname2ctype_pool_str69[sizeof("lana")];
+ char uniname2ctype_pool_str70[sizeof("zanb")];
+ char uniname2ctype_pool_str74[sizeof("inosmanya")];
+ char uniname2ctype_pool_str81[sizeof("insamaritan")];
+ char uniname2ctype_pool_str82[sizeof("inbhaiksuki")];
+ char uniname2ctype_pool_str83[sizeof("armenian")];
+ char uniname2ctype_pool_str85[sizeof("sm")];
+ char uniname2ctype_pool_str88[sizeof("inmasaramgondi")];
+ char uniname2ctype_pool_str89[sizeof("s")];
+ char uniname2ctype_pool_str90[sizeof("innabataean")];
+ char uniname2ctype_pool_str92[sizeof("zs")];
+ char uniname2ctype_pool_str93[sizeof("inbasiclatin")];
+ char uniname2ctype_pool_str96[sizeof("innumberforms")];
+ char uniname2ctype_pool_str102[sizeof("arab")];
+ char uniname2ctype_pool_str107[sizeof("inmusicalsymbols")];
+ char uniname2ctype_pool_str115[sizeof("latn")];
+ char uniname2ctype_pool_str117[sizeof("inthai")];
+ char uniname2ctype_pool_str124[sizeof("latin")];
+ char uniname2ctype_pool_str135[sizeof("shavian")];
+ char uniname2ctype_pool_str141[sizeof("initialpunctuation")];
+ char uniname2ctype_pool_str144[sizeof("hatran")];
+ char uniname2ctype_pool_str149[sizeof("di")];
+ char uniname2ctype_pool_str155[sizeof("inthaana")];
+ char uniname2ctype_pool_str157[sizeof("intoto")];
+ char uniname2ctype_pool_str164[sizeof("nabataean")];
+ char uniname2ctype_pool_str169[sizeof("intaitham")];
+ char uniname2ctype_pool_str175[sizeof("inarabicpresentationformsa")];
+ char uniname2ctype_pool_str180[sizeof("inbraillepatterns")];
+ char uniname2ctype_pool_str181[sizeof("inarabicpresentationformsb")];
+ char uniname2ctype_pool_str186[sizeof("ids")];
+ char uniname2ctype_pool_str190[sizeof("dia")];
+ char uniname2ctype_pool_str191[sizeof("inarmenian")];
+ char uniname2ctype_pool_str195[sizeof("idsb")];
+ char uniname2ctype_pool_str199[sizeof("intransportandmapsymbols")];
+ char uniname2ctype_pool_str202[sizeof("inideographicsymbolsandpunctuation")];
+ char uniname2ctype_pool_str203[sizeof("inavestan")];
+ char uniname2ctype_pool_str209[sizeof("inipaextensions")];
+ char uniname2ctype_pool_str211[sizeof("inelbasan")];
+ char uniname2ctype_pool_str213[sizeof("inopticalcharacterrecognition")];
+ char uniname2ctype_pool_str215[sizeof("brai")];
+ char uniname2ctype_pool_str219[sizeof("bamum")];
+ char uniname2ctype_pool_str220[sizeof("incham")];
+ char uniname2ctype_pool_str227[sizeof("inideographicdescriptioncharacters")];
+ char uniname2ctype_pool_str228[sizeof("brahmi")];
+ char uniname2ctype_pool_str235[sizeof("idst")];
+ char uniname2ctype_pool_str237[sizeof("bass")];
+ char uniname2ctype_pool_str242[sizeof("mandaic")];
+ char uniname2ctype_pool_str244[sizeof("inemoticons")];
+ char uniname2ctype_pool_str247[sizeof("incommonindicnumberforms")];
+ char uniname2ctype_pool_str257[sizeof("intibetan")];
+ char uniname2ctype_pool_str258[sizeof("inarabic")];
+ char uniname2ctype_pool_str260[sizeof("nbat")];
+ char uniname2ctype_pool_str261[sizeof("cn")];
+ char uniname2ctype_pool_str267[sizeof("inancientsymbols")];
+ char uniname2ctype_pool_str268[sizeof("ci")];
+ char uniname2ctype_pool_str274[sizeof("ascii")];
+ char uniname2ctype_pool_str275[sizeof("mcm")];
+ char uniname2ctype_pool_str279[sizeof("ideo")];
+ char uniname2ctype_pool_str284[sizeof("inmodi")];
+ char uniname2ctype_pool_str285[sizeof("vai")];
+ char uniname2ctype_pool_str286[sizeof("vaii")];
+ char uniname2ctype_pool_str287[sizeof("cham")];
+ char uniname2ctype_pool_str289[sizeof("inmyanmarextendeda")];
+ char uniname2ctype_pool_str291[sizeof("nand")];
+ char uniname2ctype_pool_str295[sizeof("inmyanmarextendedb")];
+ char uniname2ctype_pool_str298[sizeof("mand")];
+ char uniname2ctype_pool_str310[sizeof("cans")];
+ char uniname2ctype_pool_str312[sizeof("inoldsogdian")];
+ char uniname2ctype_pool_str315[sizeof("chorasmian")];
+ char uniname2ctype_pool_str317[sizeof("innewa")];
+ char uniname2ctype_pool_str333[sizeof("chakma")];
+ char uniname2ctype_pool_str335[sizeof("incuneiform")];
+ char uniname2ctype_pool_str336[sizeof("vs")];
+ char uniname2ctype_pool_str340[sizeof("cs")];
+ char uniname2ctype_pool_str342[sizeof("sind")];
+ char uniname2ctype_pool_str344[sizeof("shaw")];
+ char uniname2ctype_pool_str359[sizeof("inspecials")];
+ char uniname2ctype_pool_str364[sizeof("inchesssymbols")];
+ char uniname2ctype_pool_str366[sizeof("avst")];
+ char uniname2ctype_pool_str373[sizeof("inblockelements")];
+ char uniname2ctype_pool_str384[sizeof("nd")];
+ char uniname2ctype_pool_str395[sizeof("sharada")];
+ char uniname2ctype_pool_str398[sizeof("inmiscellaneoussymbols")];
+ char uniname2ctype_pool_str400[sizeof("inmiscellaneousmathematicalsymbolsa")];
+ char uniname2ctype_pool_str402[sizeof("sidt")];
+ char uniname2ctype_pool_str406[sizeof("inmiscellaneousmathematicalsymbolsb")];
+ char uniname2ctype_pool_str407[sizeof("inmiscellaneoussymbolsandarrows")];
+ char uniname2ctype_pool_str410[sizeof("arabic")];
+ char uniname2ctype_pool_str412[sizeof("inmiscellaneoussymbolsandpictographs")];
+ char uniname2ctype_pool_str416[sizeof("c")];
+ char uniname2ctype_pool_str424[sizeof("lc")];
+ char uniname2ctype_pool_str425[sizeof("mc")];
+ char uniname2ctype_pool_str426[sizeof("inmedefaidrin")];
+ char uniname2ctype_pool_str432[sizeof("inmyanmarextendedc")];
+ char uniname2ctype_pool_str433[sizeof("insundanese")];
+ char uniname2ctype_pool_str438[sizeof("indominotiles")];
+ char uniname2ctype_pool_str440[sizeof("insymbolsandpictographsextendeda")];
+ char uniname2ctype_pool_str441[sizeof("inwancho")];
+ char uniname2ctype_pool_str444[sizeof("inolditalic")];
+ char uniname2ctype_pool_str447[sizeof("inmodifiertoneletters")];
+ char uniname2ctype_pool_str448[sizeof("incb=consonant")];
+ char uniname2ctype_pool_str451[sizeof("sd")];
+ char uniname2ctype_pool_str452[sizeof("inmandaic")];
+ char uniname2ctype_pool_str456[sizeof("inmiscellaneoussymbolssupplement")];
+ char uniname2ctype_pool_str458[sizeof("nko")];
+ char uniname2ctype_pool_str459[sizeof("nkoo")];
+ char uniname2ctype_pool_str460[sizeof("l")];
+ char uniname2ctype_pool_str461[sizeof("inmeeteimayekextensions")];
+ char uniname2ctype_pool_str462[sizeof("nl")];
+ char uniname2ctype_pool_str463[sizeof("zl")];
+ char uniname2ctype_pool_str468[sizeof("ll")];
+ char uniname2ctype_pool_str472[sizeof("inlao")];
+ char uniname2ctype_pool_str473[sizeof("khoj")];
+ char uniname2ctype_pool_str476[sizeof("idc")];
+ char uniname2ctype_pool_str477[sizeof("innewtailue")];
+ char uniname2ctype_pool_str483[sizeof("inolonal")];
+ char uniname2ctype_pool_str485[sizeof("sc")];
+ char uniname2ctype_pool_str491[sizeof("indeseret")];
+ char uniname2ctype_pool_str496[sizeof("incuneiformnumbersandpunctuation")];
+ char uniname2ctype_pool_str502[sizeof("krai")];
+ char uniname2ctype_pool_str505[sizeof("inarabicextendeda")];
+ char uniname2ctype_pool_str508[sizeof("inoldturkic")];
+ char uniname2ctype_pool_str510[sizeof("avestan")];
+ char uniname2ctype_pool_str511[sizeof("inarabicextendedb")];
+ char uniname2ctype_pool_str512[sizeof("inmalayalam")];
+ char uniname2ctype_pool_str513[sizeof("kharoshthi")];
+ char uniname2ctype_pool_str514[sizeof("kana")];
+ char uniname2ctype_pool_str523[sizeof("inadlam")];
+ char uniname2ctype_pool_str525[sizeof("idcontinue")];
+ char uniname2ctype_pool_str549[sizeof("insiddham")];
+ char uniname2ctype_pool_str551[sizeof("intamil")];
+ char uniname2ctype_pool_str553[sizeof("inmultani")];
+ char uniname2ctype_pool_str554[sizeof("intolongsiki")];
+ char uniname2ctype_pool_str556[sizeof("kits")];
+ char uniname2ctype_pool_str571[sizeof("incb=extend")];
+ char uniname2ctype_pool_str574[sizeof("sidetic")];
+ char uniname2ctype_pool_str584[sizeof("sidd")];
+ char uniname2ctype_pool_str587[sizeof("incontrolpictures")];
+ char uniname2ctype_pool_str588[sizeof("insidetic")];
+ char uniname2ctype_pool_str591[sizeof("sinhala")];
+ char uniname2ctype_pool_str605[sizeof("inlatinextendeda")];
+ char uniname2ctype_pool_str617[sizeof("inlatinextendedb")];
+ char uniname2ctype_pool_str622[sizeof("adlm")];
+ char uniname2ctype_pool_str630[sizeof("adlam")];
+ char uniname2ctype_pool_str635[sizeof("inlineara")];
+ char uniname2ctype_pool_str637[sizeof("intamilsupplement")];
+ char uniname2ctype_pool_str638[sizeof("inbalinese")];
+ char uniname2ctype_pool_str645[sizeof("inspacingmodifierletters")];
+ char uniname2ctype_pool_str648[sizeof("inarabicextendedc")];
+ char uniname2ctype_pool_str650[sizeof("inlycian")];
+ char uniname2ctype_pool_str653[sizeof("bali")];
+ char uniname2ctype_pool_str665[sizeof("hira")];
+ char uniname2ctype_pool_str667[sizeof("cc")];
+ char uniname2ctype_pool_str674[sizeof("insmallkanaextension")];
+ char uniname2ctype_pool_str675[sizeof("intaile")];
+ char uniname2ctype_pool_str681[sizeof("qaai")];
+ char uniname2ctype_pool_str682[sizeof("inmyanmar")];
+ char uniname2ctype_pool_str684[sizeof("narb")];
+ char uniname2ctype_pool_str687[sizeof("inarrows")];
+ char uniname2ctype_pool_str701[sizeof("lineara")];
+ char uniname2ctype_pool_str707[sizeof("linearb")];
+ char uniname2ctype_pool_str709[sizeof("insharada")];
+ char uniname2ctype_pool_str716[sizeof("inruminumeralsymbols")];
+ char uniname2ctype_pool_str721[sizeof("masaramgondi")];
+ char uniname2ctype_pool_str727[sizeof("hatr")];
+ char uniname2ctype_pool_str729[sizeof("knda")];
+ char uniname2ctype_pool_str730[sizeof("samr")];
+ char uniname2ctype_pool_str734[sizeof("kawi")];
+ char uniname2ctype_pool_str735[sizeof("inlydian")];
+ char uniname2ctype_pool_str747[sizeof("samaritan")];
+ char uniname2ctype_pool_str751[sizeof("sarb")];
+ char uniname2ctype_pool_str760[sizeof("no")];
+ char uniname2ctype_pool_str762[sizeof("bidic")];
+ char uniname2ctype_pool_str766[sizeof("lo")];
+ char uniname2ctype_pool_str780[sizeof("hmnp")];
+ char uniname2ctype_pool_str784[sizeof("onao")];
+ char uniname2ctype_pool_str788[sizeof("inlowsurrogates")];
+ char uniname2ctype_pool_str789[sizeof("kannada")];
+ char uniname2ctype_pool_str795[sizeof("inlinearbideograms")];
+ char uniname2ctype_pool_str799[sizeof("inletterlikesymbols")];
+ char uniname2ctype_pool_str803[sizeof("cased")];
+ char uniname2ctype_pool_str809[sizeof("inbopomofo")];
+ char uniname2ctype_pool_str810[sizeof("inberiaerfe")];
+ char uniname2ctype_pool_str815[sizeof("lineseparator")];
+ char uniname2ctype_pool_str817[sizeof("z")];
+ char uniname2ctype_pool_str818[sizeof("insymbolsforlegacycomputingsupplement")];
+ char uniname2ctype_pool_str820[sizeof("inrunic")];
+ char uniname2ctype_pool_str821[sizeof("incarian")];
+ char uniname2ctype_pool_str823[sizeof("inlatinextendede")];
+ char uniname2ctype_pool_str825[sizeof("inmarchen")];
+ char uniname2ctype_pool_str827[sizeof("so")];
+ char uniname2ctype_pool_str828[sizeof("marc")];
+ char uniname2ctype_pool_str829[sizeof("oriya")];
+ char uniname2ctype_pool_str830[sizeof("inchorasmian")];
+ char uniname2ctype_pool_str832[sizeof("yi")];
+ char uniname2ctype_pool_str833[sizeof("insyriac")];
+ char uniname2ctype_pool_str838[sizeof("yiii")];
+ char uniname2ctype_pool_str840[sizeof("alpha")];
+ char uniname2ctype_pool_str842[sizeof("qaac")];
+ char uniname2ctype_pool_str852[sizeof("insundanesesupplement")];
+ char uniname2ctype_pool_str857[sizeof("osma")];
+ char uniname2ctype_pool_str880[sizeof("inmiscellaneoustechnical")];
+ char uniname2ctype_pool_str883[sizeof("idstart")];
+ char uniname2ctype_pool_str890[sizeof("inenclosedcjklettersandmonths")];
+ char uniname2ctype_pool_str891[sizeof("inlatinextendedc")];
+ char uniname2ctype_pool_str894[sizeof("dsrt")];
+ char uniname2ctype_pool_str898[sizeof("odi")];
+ char uniname2ctype_pool_str901[sizeof("chrs")];
+ char uniname2ctype_pool_str909[sizeof("cari")];
+ char uniname2ctype_pool_str919[sizeof("innandinagari")];
+ char uniname2ctype_pool_str923[sizeof("balinese")];
+ char uniname2ctype_pool_str924[sizeof("inwarangciti")];
+ char uniname2ctype_pool_str929[sizeof("inphoenician")];
+ char uniname2ctype_pool_str940[sizeof("kali")];
+ char uniname2ctype_pool_str942[sizeof("inoldnortharabian")];
+ char uniname2ctype_pool_str944[sizeof("radical")];
+ char uniname2ctype_pool_str945[sizeof("carian")];
+ char uniname2ctype_pool_str947[sizeof("idsbinaryoperator")];
+ char uniname2ctype_pool_str949[sizeof("shrd")];
+ char uniname2ctype_pool_str954[sizeof("inoldsoutharabian")];
+ char uniname2ctype_pool_str966[sizeof("diacritic")];
+ char uniname2ctype_pool_str970[sizeof("mlym")];
+ char uniname2ctype_pool_str975[sizeof("zinh")];
+ char uniname2ctype_pool_str978[sizeof("inphaistosdisc")];
+ char uniname2ctype_pool_str980[sizeof("incyrillic")];
+ char uniname2ctype_pool_str985[sizeof("ininscriptionalpahlavi")];
+ char uniname2ctype_pool_str988[sizeof("insoyombo")];
+ char uniname2ctype_pool_str990[sizeof("ininscriptionalparthian")];
+ char uniname2ctype_pool_str991[sizeof("inoriya")];
+ char uniname2ctype_pool_str994[sizeof("lyci")];
+ char uniname2ctype_pool_str999[sizeof("inogham")];
+ char uniname2ctype_pool_str1001[sizeof("mahj")];
+ char uniname2ctype_pool_str1003[sizeof("gran")];
+ char uniname2ctype_pool_str1005[sizeof("inmahajani")];
+ char uniname2ctype_pool_str1009[sizeof("co")];
+ char uniname2ctype_pool_str1012[sizeof("cher")];
+ char uniname2ctype_pool_str1016[sizeof("alphabetic")];
+ char uniname2ctype_pool_str1021[sizeof("insinhala")];
+ char uniname2ctype_pool_str1022[sizeof("modi")];
+ char uniname2ctype_pool_str1024[sizeof("inbrahmi")];
+ char uniname2ctype_pool_str1028[sizeof("loe")];
+ char uniname2ctype_pool_str1030[sizeof("lycian")];
+ char uniname2ctype_pool_str1031[sizeof("mahajani")];
+ char uniname2ctype_pool_str1036[sizeof("common")];
+ char uniname2ctype_pool_str1037[sizeof("intaiyo")];
+ char uniname2ctype_pool_str1038[sizeof("inhanifirohingya")];
+ char uniname2ctype_pool_str1040[sizeof("inbassavah")];
+ char uniname2ctype_pool_str1041[sizeof("sinh")];
+ char uniname2ctype_pool_str1042[sizeof("oids")];
+ char uniname2ctype_pool_str1044[sizeof("inlatinextendedadditional")];
+ char uniname2ctype_pool_str1045[sizeof("inyijinghexagramsymbols")];
+ char uniname2ctype_pool_str1048[sizeof("inoldpersian")];
+ char uniname2ctype_pool_str1056[sizeof("bidicontrol")];
+ char uniname2ctype_pool_str1057[sizeof("math")];
+ char uniname2ctype_pool_str1058[sizeof("inarabicsupplement")];
+ char uniname2ctype_pool_str1059[sizeof("thai")];
+ char uniname2ctype_pool_str1061[sizeof("inlatinextendedd")];
+ char uniname2ctype_pool_str1064[sizeof("taiyo")];
+ char uniname2ctype_pool_str1068[sizeof("lisu")];
+ char uniname2ctype_pool_str1072[sizeof("tnsa")];
+ char uniname2ctype_pool_str1073[sizeof("incherokee")];
+ char uniname2ctype_pool_str1077[sizeof("thaa")];
+ char uniname2ctype_pool_str1079[sizeof("lydi")];
+ char uniname2ctype_pool_str1087[sizeof("inbamum")];
+ char uniname2ctype_pool_str1090[sizeof("khmr")];
+ char uniname2ctype_pool_str1094[sizeof("inbyzantinemusicalsymbols")];
+ char uniname2ctype_pool_str1102[sizeof("lt")];
+ char uniname2ctype_pool_str1105[sizeof("khar")];
+ char uniname2ctype_pool_str1109[sizeof("thaana")];
+ char uniname2ctype_pool_str1113[sizeof("osage")];
+ char uniname2ctype_pool_str1115[sizeof("lydian")];
+ char uniname2ctype_pool_str1117[sizeof("inanatolianhieroglyphs")];
+#ifdef USE_UNICODE_AGE_PROPERTIES
+ char uniname2ctype_pool_str1120[sizeof("age=11.0")];
+ char uniname2ctype_pool_str1121[sizeof("age=10.0")];
+ char uniname2ctype_pool_str1122[sizeof("age=12.1")];
+ char uniname2ctype_pool_str1123[sizeof("age=12.0")];
+ char uniname2ctype_pool_str1125[sizeof("age=1.1")];
+#endif /* USE_UNICODE_AGE_PROPERTIES */
+ char uniname2ctype_pool_str1126[sizeof("insylotinagri")];
+ char uniname2ctype_pool_str1127[sizeof("anatolianhieroglyphs")];
+#ifdef USE_UNICODE_AGE_PROPERTIES
+ char uniname2ctype_pool_str1128[sizeof("age=2.1")];
+ char uniname2ctype_pool_str1129[sizeof("age=2.0")];
+ char uniname2ctype_pool_str1130[sizeof("age=14.0")];
+#endif /* USE_UNICODE_AGE_PROPERTIES */
+ char uniname2ctype_pool_str1131[sizeof("tangsa")];
+ char uniname2ctype_pool_str1132[sizeof("dash")];
+ char uniname2ctype_pool_str1133[sizeof("incombiningdiacriticalmarks")];
+#ifdef USE_UNICODE_AGE_PROPERTIES
+ char uniname2ctype_pool_str1134[sizeof("age=17.0")];
+ char uniname2ctype_pool_str1135[sizeof("age=4.1")];
+ char uniname2ctype_pool_str1136[sizeof("age=4.0")];
+#endif /* USE_UNICODE_AGE_PROPERTIES */
+ char uniname2ctype_pool_str1137[sizeof("tibt")];
+#ifdef USE_UNICODE_AGE_PROPERTIES
+ char uniname2ctype_pool_str1138[sizeof("age=15.1")];
+ char uniname2ctype_pool_str1139[sizeof("age=15.0")];
+ char uniname2ctype_pool_str1140[sizeof("age=7.0")];
+#endif /* USE_UNICODE_AGE_PROPERTIES */
+ char uniname2ctype_pool_str1141[sizeof("inolchiki")];
+#ifdef USE_UNICODE_AGE_PROPERTIES
+ char uniname2ctype_pool_str1142[sizeof("age=9.0")];
+#endif /* USE_UNICODE_AGE_PROPERTIES */
+ char uniname2ctype_pool_str1143[sizeof("incombiningdiacriticalmarksforsymbols")];
+#ifdef USE_UNICODE_AGE_PROPERTIES
+ char uniname2ctype_pool_str1144[sizeof("age=5.1")];
+ char uniname2ctype_pool_str1145[sizeof("age=5.0")];
+ char uniname2ctype_pool_str1146[sizeof("age=16.0")];
+ char uniname2ctype_pool_str1147[sizeof("age=5.2")];
+ char uniname2ctype_pool_str1148[sizeof("age=8.0")];
+ char uniname2ctype_pool_str1150[sizeof("age=13.0")];
+ char uniname2ctype_pool_str1151[sizeof("age=6.1")];
+ char uniname2ctype_pool_str1152[sizeof("age=6.0")];
+ char uniname2ctype_pool_str1154[sizeof("age=6.2")];
+ char uniname2ctype_pool_str1155[sizeof("age=3.1")];
+ char uniname2ctype_pool_str1156[sizeof("age=3.0")];
+ char uniname2ctype_pool_str1158[sizeof("age=3.2")];
+#endif /* USE_UNICODE_AGE_PROPERTIES */
+ char uniname2ctype_pool_str1159[sizeof("inarabicmathematicalalphabeticsymbols")];
+ char uniname2ctype_pool_str1160[sizeof("brah")];
+ char uniname2ctype_pool_str1170[sizeof("tibetan")];
+ char uniname2ctype_pool_str1172[sizeof("mtei")];
+ char uniname2ctype_pool_str1175[sizeof("incoptic")];
+ char uniname2ctype_pool_str1176[sizeof("manichaean")];
+#ifdef USE_UNICODE_AGE_PROPERTIES
+ char uniname2ctype_pool_str1181[sizeof("age=6.3")];
+#endif /* USE_UNICODE_AGE_PROPERTIES */
+ char uniname2ctype_pool_str1182[sizeof("emoji")];
+ char uniname2ctype_pool_str1187[sizeof("oidc")];
+ char uniname2ctype_pool_str1191[sizeof("incombiningdiacriticalmarkssupplement")];
+ char uniname2ctype_pool_str1192[sizeof("idsu")];
+ char uniname2ctype_pool_str1195[sizeof("saurashtra")];
+ char uniname2ctype_pool_str1196[sizeof("inoldpermic")];
+ char uniname2ctype_pool_str1199[sizeof("closepunctuation")];
+ char uniname2ctype_pool_str1209[sizeof("incombininghalfmarks")];
+ char uniname2ctype_pool_str1214[sizeof("incopticepactnumbers")];
+ char uniname2ctype_pool_str1221[sizeof("elba")];
+ char uniname2ctype_pool_str1225[sizeof("xdigit")];
+ char uniname2ctype_pool_str1228[sizeof("cntrl")];
+ char uniname2ctype_pool_str1229[sizeof("bamu")];
+ char uniname2ctype_pool_str1230[sizeof("xids")];
+ char uniname2ctype_pool_str1239[sizeof("inoldhungarian")];
+ char uniname2ctype_pool_str1241[sizeof("grext")];
+ char uniname2ctype_pool_str1242[sizeof("mongolian")];
+ char uniname2ctype_pool_str1243[sizeof("sterm")];
+ char uniname2ctype_pool_str1249[sizeof("braille")];
+ char uniname2ctype_pool_str1251[sizeof("inbuhid")];
+ char uniname2ctype_pool_str1252[sizeof("elbasan")];
+ char uniname2ctype_pool_str1259[sizeof("zanabazarsquare")];
+ char uniname2ctype_pool_str1260[sizeof("incountingrodnumerals")];
+ char uniname2ctype_pool_str1264[sizeof("inenclosedalphanumerics")];
+ char uniname2ctype_pool_str1265[sizeof("incb=linker")];
+ char uniname2ctype_pool_str1267[sizeof("taiviet")];
+ char uniname2ctype_pool_str1269[sizeof("inelymaic")];
+ char uniname2ctype_pool_str1272[sizeof("inethiopic")];
+ char uniname2ctype_pool_str1275[sizeof("sgnw")];
+ char uniname2ctype_pool_str1277[sizeof("olditalic")];
+ char uniname2ctype_pool_str1279[sizeof("vith")];
+ char uniname2ctype_pool_str1285[sizeof("grbase")];
+ char uniname2ctype_pool_str1286[sizeof("hluw")];
+ char uniname2ctype_pool_str1292[sizeof("intodhri")];
+ char uniname2ctype_pool_str1299[sizeof("asciihexdigit")];
+ char uniname2ctype_pool_str1301[sizeof("me")];
+ char uniname2ctype_pool_str1312[sizeof("hmng")];
+ char uniname2ctype_pool_str1315[sizeof("siddham")];
+ char uniname2ctype_pool_str1321[sizeof("inenclosedalphanumericsupplement")];
+ char uniname2ctype_pool_str1324[sizeof("taile")];
+ char uniname2ctype_pool_str1328[sizeof("nagm")];
+ char uniname2ctype_pool_str1332[sizeof("hang")];
+ char uniname2ctype_pool_str1334[sizeof("inscriptionalparthian")];
+ char uniname2ctype_pool_str1335[sizeof("inmongolian")];
+ char uniname2ctype_pool_str1336[sizeof("innagmundari")];
+ char uniname2ctype_pool_str1339[sizeof("sylo")];
+ char uniname2ctype_pool_str1347[sizeof("ingunjalagondi")];
+ char uniname2ctype_pool_str1349[sizeof("ingujarati")];
+ char uniname2ctype_pool_str1350[sizeof("inbengali")];
+ char uniname2ctype_pool_str1351[sizeof("khitansmallscript")];
+ char uniname2ctype_pool_str1357[sizeof("xidcontinue")];
+ char uniname2ctype_pool_str1362[sizeof("ingrantha")];
+ char uniname2ctype_pool_str1363[sizeof("insinhalaarchaicnumbers")];
+ char uniname2ctype_pool_str1368[sizeof("connectorpunctuation")];
+ char uniname2ctype_pool_str1370[sizeof("inpalmyrene")];
+ char uniname2ctype_pool_str1371[sizeof("incombiningdiacriticalmarksextended")];
+ char uniname2ctype_pool_str1372[sizeof("xidstart")];
+ char uniname2ctype_pool_str1375[sizeof("xidc")];
+ char uniname2ctype_pool_str1397[sizeof("inancientgreekmusicalnotation")];
+ char uniname2ctype_pool_str1401[sizeof("inancientgreeknumbers")];
+ char uniname2ctype_pool_str1407[sizeof("intangsa")];
+ char uniname2ctype_pool_str1415[sizeof("intags")];
+ char uniname2ctype_pool_str1416[sizeof("inlepcha")];
+ char uniname2ctype_pool_str1420[sizeof("caucasianalbanian")];
+ char uniname2ctype_pool_str1421[sizeof("sylotinagri")];
+ char uniname2ctype_pool_str1423[sizeof("emod")];
+ char uniname2ctype_pool_str1425[sizeof("incaucasianalbanian")];
+ char uniname2ctype_pool_str1429[sizeof("intagbanwa")];
+ char uniname2ctype_pool_str1430[sizeof("mend")];
+ char uniname2ctype_pool_str1433[sizeof("newa")];
+ char uniname2ctype_pool_str1435[sizeof("inearlydynasticcuneiform")];
+ char uniname2ctype_pool_str1447[sizeof("kaithi")];
+ char uniname2ctype_pool_str1453[sizeof("intangut")];
+ char uniname2ctype_pool_str1456[sizeof("mymr")];
+ char uniname2ctype_pool_str1462[sizeof("inosage")];
+ char uniname2ctype_pool_str1467[sizeof("inmahjongtiles")];
+ char uniname2ctype_pool_str1470[sizeof("malayalam")];
+ char uniname2ctype_pool_str1473[sizeof("sora")];
+ char uniname2ctype_pool_str1474[sizeof("inbuginese")];
+ char uniname2ctype_pool_str1479[sizeof("emojimodifierbase")];
+ char uniname2ctype_pool_str1489[sizeof("induployan")];
+ char uniname2ctype_pool_str1497[sizeof("ingeometricshapes")];
+ char uniname2ctype_pool_str1498[sizeof("ingeneralpunctuation")];
+ char uniname2ctype_pool_str1503[sizeof("myanmar")];
+ char uniname2ctype_pool_str1510[sizeof("inlatin1supplement")];
+ char uniname2ctype_pool_str1515[sizeof("ital")];
+ char uniname2ctype_pool_str1516[sizeof("taml")];
+ char uniname2ctype_pool_str1517[sizeof("inaegeannumbers")];
+ char uniname2ctype_pool_str1528[sizeof("insharadasupplement")];
+ char uniname2ctype_pool_str1530[sizeof("mathsymbol")];
+ char uniname2ctype_pool_str1532[sizeof("inlimbu")];
+ char uniname2ctype_pool_str1535[sizeof("invai")];
+ char uniname2ctype_pool_str1551[sizeof("emojicomponent")];
+ char uniname2ctype_pool_str1552[sizeof("insuttonsignwriting")];
+ char uniname2ctype_pool_str1572[sizeof("digit")];
+ char uniname2ctype_pool_str1573[sizeof("newtailue")];
+ char uniname2ctype_pool_str1581[sizeof("inshavian")];
+ char uniname2ctype_pool_str1588[sizeof("insogdian")];
+ char uniname2ctype_pool_str1589[sizeof("indingbats")];
+ char uniname2ctype_pool_str1590[sizeof("imperialaramaic")];
+ char uniname2ctype_pool_str1598[sizeof("intulutigalari")];
+ char uniname2ctype_pool_str1600[sizeof("incyprominoan")];
+ char uniname2ctype_pool_str1606[sizeof("glagolitic")];
+ char uniname2ctype_pool_str1614[sizeof("ebase")];
+ char uniname2ctype_pool_str1615[sizeof("intaixuanjingsymbols")];
+ char uniname2ctype_pool_str1618[sizeof("inbamumsupplement")];
+ char uniname2ctype_pool_str1626[sizeof("gara")];
+ char uniname2ctype_pool_str1633[sizeof("insyriacsupplement")];
+ char uniname2ctype_pool_str1634[sizeof("casedletter")];
+ char uniname2ctype_pool_str1636[sizeof("zzzz")];
+ char uniname2ctype_pool_str1639[sizeof("inhiragana")];
+ char uniname2ctype_pool_str1640[sizeof("tale")];
+ char uniname2ctype_pool_str1641[sizeof("canadianaboriginal")];
+ char uniname2ctype_pool_str1642[sizeof("ahex")];
+ char uniname2ctype_pool_str1644[sizeof("inmayannumerals")];
+ char uniname2ctype_pool_str1648[sizeof("inzanabazarsquare")];
+ char uniname2ctype_pool_str1654[sizeof("inyiradicals")];
+ char uniname2ctype_pool_str1655[sizeof("inscriptionalpahlavi")];
+ char uniname2ctype_pool_str1668[sizeof("inalchemicalsymbols")];
+ char uniname2ctype_pool_str1669[sizeof("inhatran")];
+ char uniname2ctype_pool_str1670[sizeof("assigned")];
+ char uniname2ctype_pool_str1671[sizeof("intaiviet")];
+ char uniname2ctype_pool_str1674[sizeof("syrc")];
+ char uniname2ctype_pool_str1682[sizeof("bopo")];
+ char uniname2ctype_pool_str1684[sizeof("intirhuta")];
+ char uniname2ctype_pool_str1688[sizeof("oldnortharabian")];
+ char uniname2ctype_pool_str1690[sizeof("insupplementalmathematicaloperators")];
+ char uniname2ctype_pool_str1694[sizeof("bopomofo")];
+ char uniname2ctype_pool_str1696[sizeof("olonal")];
+ char uniname2ctype_pool_str1697[sizeof("injavanese")];
+ char uniname2ctype_pool_str1698[sizeof("insunuwar")];
+ char uniname2ctype_pool_str1707[sizeof("inmathematicalalphanumericsymbols")];
+ char uniname2ctype_pool_str1713[sizeof("inimperialaramaic")];
+ char uniname2ctype_pool_str1714[sizeof("khmer")];
+ char uniname2ctype_pool_str1724[sizeof("gonm")];
+ char uniname2ctype_pool_str1727[sizeof("hyphen")];
+ char uniname2ctype_pool_str1731[sizeof("insuperscriptsandsubscripts")];
+ char uniname2ctype_pool_str1733[sizeof("inenclosedideographicsupplement")];
+ char uniname2ctype_pool_str1735[sizeof("ingeometricshapesextended")];
+ char uniname2ctype_pool_str1737[sizeof("insaurashtra")];
+ char uniname2ctype_pool_str1738[sizeof("ogam")];
+ char uniname2ctype_pool_str1746[sizeof("orya")];
+ char uniname2ctype_pool_str1748[sizeof("saur")];
+ char uniname2ctype_pool_str1754[sizeof("marchen")];
+ char uniname2ctype_pool_str1755[sizeof("sundanese")];
+ char uniname2ctype_pool_str1762[sizeof("khudawadi")];
+ char uniname2ctype_pool_str1773[sizeof("soyo")];
+ char uniname2ctype_pool_str1775[sizeof("whitespace")];
+ char uniname2ctype_pool_str1778[sizeof("uideo")];
+ char uniname2ctype_pool_str1785[sizeof("oldpersian")];
+ char uniname2ctype_pool_str1787[sizeof("inyezidi")];
+ char uniname2ctype_pool_str1790[sizeof("kiratrai")];
+ char uniname2ctype_pool_str1793[sizeof("inlisusupplement")];
+ char uniname2ctype_pool_str1796[sizeof("mero")];
+ char uniname2ctype_pool_str1800[sizeof("symbol")];
+ char uniname2ctype_pool_str1811[sizeof("soyombo")];
+ char uniname2ctype_pool_str1812[sizeof("osmanya")];
+ char uniname2ctype_pool_str1814[sizeof("indevanagari")];
+ char uniname2ctype_pool_str1816[sizeof("unassigned")];
+ char uniname2ctype_pool_str1818[sizeof("bengali")];
+ char uniname2ctype_pool_str1819[sizeof("hebr")];
+ char uniname2ctype_pool_str1821[sizeof("hebrew")];
+ char uniname2ctype_pool_str1824[sizeof("inornamentaldingbats")];
+ char uniname2ctype_pool_str1829[sizeof("invedicextensions")];
+ char uniname2ctype_pool_str1834[sizeof("copt")];
+ char uniname2ctype_pool_str1836[sizeof("ingreekextended")];
+ char uniname2ctype_pool_str1839[sizeof("sund")];
+ char uniname2ctype_pool_str1847[sizeof("cyprominoan")];
+ char uniname2ctype_pool_str1848[sizeof("inherited")];
+ char uniname2ctype_pool_str1854[sizeof("toto")];
+ char uniname2ctype_pool_str1858[sizeof("inugaritic")];
+ char uniname2ctype_pool_str1863[sizeof("syriac")];
+ char uniname2ctype_pool_str1864[sizeof("cwt")];
+ char uniname2ctype_pool_str1867[sizeof("inhebrew")];
+ char uniname2ctype_pool_str1872[sizeof("runic")];
+ char uniname2ctype_pool_str1877[sizeof("inmongoliansupplement")];
+ char uniname2ctype_pool_str1884[sizeof("inshorthandformatcontrols")];
+ char uniname2ctype_pool_str1900[sizeof("cypriot")];
+ char uniname2ctype_pool_str1901[sizeof("cwcm")];
+ char uniname2ctype_pool_str1910[sizeof("ingreekandcoptic")];
+ char uniname2ctype_pool_str1920[sizeof("any")];
+ char uniname2ctype_pool_str1923[sizeof("inolduyghur")];
+ char uniname2ctype_pool_str1936[sizeof("inznamennymusicalnotation")];
+ char uniname2ctype_pool_str1937[sizeof("lowercase")];
+ char uniname2ctype_pool_str1941[sizeof("oldpermic")];
+ char uniname2ctype_pool_str1943[sizeof("ingeorgian")];
+ char uniname2ctype_pool_str1945[sizeof("ingurmukhi")];
+ char uniname2ctype_pool_str1947[sizeof("emojimodifier")];
+ char uniname2ctype_pool_str1956[sizeof("inkhojki")];
+ char uniname2ctype_pool_str1958[sizeof("aghb")];
+ char uniname2ctype_pool_str1960[sizeof("merc")];
+ char uniname2ctype_pool_str1966[sizeof("inrejang")];
+ char uniname2ctype_pool_str1969[sizeof("tamil")];
+ char uniname2ctype_pool_str1972[sizeof("indevanagariextendeda")];
+ char uniname2ctype_pool_str1974[sizeof("inalphabeticpresentationforms")];
+ char uniname2ctype_pool_str1975[sizeof("hangul")];
+ char uniname2ctype_pool_str1977[sizeof("inmeroitichieroglyphs")];
+ char uniname2ctype_pool_str1978[sizeof("inkannada")];
+ char uniname2ctype_pool_str1979[sizeof("hiragana")];
+ char uniname2ctype_pool_str1980[sizeof("maka")];
+ char uniname2ctype_pool_str1983[sizeof("inkanbun")];
+ char uniname2ctype_pool_str1987[sizeof("insorasompeng")];
+ char uniname2ctype_pool_str2001[sizeof("inmathematicaloperators")];
+ char uniname2ctype_pool_str2002[sizeof("tayo")];
+ char uniname2ctype_pool_str2005[sizeof("inhanunoo")];
+ char uniname2ctype_pool_str2010[sizeof("multani")];
+ char uniname2ctype_pool_str2015[sizeof("inkaithi")];
+ char uniname2ctype_pool_str2022[sizeof("innushu")];
+ char uniname2ctype_pool_str2023[sizeof("emojipresentation")];
+ char uniname2ctype_pool_str2028[sizeof("insymbolsforlegacycomputing")];
+ char uniname2ctype_pool_str2029[sizeof("meroiticcursive")];
+ char uniname2ctype_pool_str2037[sizeof("grantha")];
+ char uniname2ctype_pool_str2040[sizeof("inlinearbsyllabary")];
+ char uniname2ctype_pool_str2041[sizeof("mult")];
+ char uniname2ctype_pool_str2042[sizeof("taitham")];
+ char uniname2ctype_pool_str2047[sizeof("nshu")];
+ char uniname2ctype_pool_str2049[sizeof("incyrillicsupplement")];
+ char uniname2ctype_pool_str2051[sizeof("dashpunctuation")];
+ char uniname2ctype_pool_str2053[sizeof("inkatakana")];
+ char uniname2ctype_pool_str2056[sizeof("inbatak")];
+ char uniname2ctype_pool_str2059[sizeof("pi")];
+ char uniname2ctype_pool_str2064[sizeof("mong")];
+ char uniname2ctype_pool_str2074[sizeof("oldhungarian")];
+ char uniname2ctype_pool_str2076[sizeof("phoenician")];
+ char uniname2ctype_pool_str2077[sizeof("insmallformvariants")];
+ char uniname2ctype_pool_str2078[sizeof("idsunaryoperator")];
+ char uniname2ctype_pool_str2080[sizeof("variationselector")];
+ char uniname2ctype_pool_str2081[sizeof("limbu")];
+ char uniname2ctype_pool_str2085[sizeof("inyisyllables")];
+ char uniname2ctype_pool_str2087[sizeof("diak")];
+ char uniname2ctype_pool_str2090[sizeof("oldsoutharabian")];
+ char uniname2ctype_pool_str2092[sizeof("lepc")];
+ char uniname2ctype_pool_str2093[sizeof("inottomansiyaqnumbers")];
+ char uniname2ctype_pool_str2097[sizeof("control")];
+ char uniname2ctype_pool_str2102[sizeof("coptic")];
+ char uniname2ctype_pool_str2104[sizeof("inkhmersymbols")];
+ char uniname2ctype_pool_str2107[sizeof("titlecaseletter")];
+ char uniname2ctype_pool_str2110[sizeof("inphagspa")];
+ char uniname2ctype_pool_str2111[sizeof("bhks")];
+ char uniname2ctype_pool_str2113[sizeof("gothic")];
+ char uniname2ctype_pool_str2117[sizeof("sogo")];
+ char uniname2ctype_pool_str2122[sizeof("elym")];
+ char uniname2ctype_pool_str2131[sizeof("ps")];
+ char uniname2ctype_pool_str2137[sizeof("prti")];
+ char uniname2ctype_pool_str2138[sizeof("changeswhencasemapped")];
+ char uniname2ctype_pool_str2140[sizeof("deseret")];
+ char uniname2ctype_pool_str2142[sizeof("bhaiksuki")];
+ char uniname2ctype_pool_str2143[sizeof("cyrl")];
+ char uniname2ctype_pool_str2147[sizeof("olower")];
+ char uniname2ctype_pool_str2148[sizeof("inchakma")];
+ char uniname2ctype_pool_str2152[sizeof("wara")];
+ char uniname2ctype_pool_str2153[sizeof("sogdian")];
+ char uniname2ctype_pool_str2155[sizeof("graphemeclusterbreak=zwj")];
+ char uniname2ctype_pool_str2164[sizeof("runr")];
+ char uniname2ctype_pool_str2165[sizeof("changeswhentitlecased")];
+ char uniname2ctype_pool_str2168[sizeof("incjkstrokes")];
+ char uniname2ctype_pool_str2176[sizeof("incherokeesupplement")];
+ char uniname2ctype_pool_str2179[sizeof("intangutcomponents")];
+ char uniname2ctype_pool_str2182[sizeof("patws")];
+ char uniname2ctype_pool_str2183[sizeof("batk")];
+ char uniname2ctype_pool_str2186[sizeof("caseignorable")];
+ char uniname2ctype_pool_str2191[sizeof("inkawi")];
+ char uniname2ctype_pool_str2199[sizeof("indevanagariextended")];
+ char uniname2ctype_pool_str2203[sizeof("indogra")];
+ char uniname2ctype_pool_str2204[sizeof("intifinagh")];
+ char uniname2ctype_pool_str2206[sizeof("print")];
+ char uniname2ctype_pool_str2207[sizeof("cakm")];
+ char uniname2ctype_pool_str2209[sizeof("graphemeclusterbreak=t")];
+ char uniname2ctype_pool_str2211[sizeof("graphemeclusterbreak=lvt")];
+ char uniname2ctype_pool_str2214[sizeof("inmendekikakui")];
+ char uniname2ctype_pool_str2216[sizeof("inpsalterpahlavi")];
+ char uniname2ctype_pool_str2224[sizeof("dogra")];
+ char uniname2ctype_pool_str2228[sizeof("tangut")];
+ char uniname2ctype_pool_str2235[sizeof("oalpha")];
+ char uniname2ctype_pool_str2237[sizeof("intangutcomponentssupplement")];
+ char uniname2ctype_pool_str2239[sizeof("idcompatmathcontinue")];
+ char uniname2ctype_pool_str2241[sizeof("beriaerfe")];
+ char uniname2ctype_pool_str2243[sizeof("ext")];
+ char uniname2ctype_pool_str2244[sizeof("inkanasupplement")];
+ char uniname2ctype_pool_str2247[sizeof("osge")];
+ char uniname2ctype_pool_str2248[sizeof("inkanaextendeda")];
+ char uniname2ctype_pool_str2249[sizeof("inverticalforms")];
+ char uniname2ctype_pool_str2252[sizeof("decimalnumber")];
+ char uniname2ctype_pool_str2254[sizeof("inkanaextendedb")];
+ char uniname2ctype_pool_str2255[sizeof("idstrinaryoperator")];
+ char uniname2ctype_pool_str2257[sizeof("tols")];
+ char uniname2ctype_pool_str2260[sizeof("lower")];
+ char uniname2ctype_pool_str2270[sizeof("glag")];
+ char uniname2ctype_pool_str2272[sizeof("inhanguljamo")];
+ char uniname2ctype_pool_str2279[sizeof("insupplementalarrowsa")];
+ char uniname2ctype_pool_str2281[sizeof("inmeeteimayek")];
+ char uniname2ctype_pool_str2285[sizeof("insupplementalarrowsb")];
+ char uniname2ctype_pool_str2288[sizeof("inunifiedcanadianaboriginalsyllabics")];
+ char uniname2ctype_pool_str2296[sizeof("privateuse")];
+ char uniname2ctype_pool_str2299[sizeof("inunifiedcanadianaboriginalsyllabicsextendeda")];
+ char uniname2ctype_pool_str2302[sizeof("sentenceterminal")];
+ char uniname2ctype_pool_str2308[sizeof("pcm")];
+ char uniname2ctype_pool_str2309[sizeof("elymaic")];
+ char uniname2ctype_pool_str2310[sizeof("cpmn")];
+ char uniname2ctype_pool_str2312[sizeof("incjkcompatibilityforms")];
+ char uniname2ctype_pool_str2313[sizeof("inphoneticextensions")];
+ char uniname2ctype_pool_str2317[sizeof("incjkcompatibilityideographs")];
+ char uniname2ctype_pool_str2320[sizeof("oldsogdian")];
+ char uniname2ctype_pool_str2341[sizeof("inethiopicsupplement")];
+ char uniname2ctype_pool_str2345[sizeof("graphemebase")];
+ char uniname2ctype_pool_str2350[sizeof("intangutsupplement")];
+ char uniname2ctype_pool_str2353[sizeof("tang")];
+ char uniname2ctype_pool_str2361[sizeof("ideographic")];
+ char uniname2ctype_pool_str2364[sizeof("nagmundari")];
+ char uniname2ctype_pool_str2366[sizeof("sogd")];
+ char uniname2ctype_pool_str2370[sizeof("psalterpahlavi")];
+ char uniname2ctype_pool_str2371[sizeof("inphoneticextensionssupplement")];
+ char uniname2ctype_pool_str2373[sizeof("tagb")];
+ char uniname2ctype_pool_str2374[sizeof("invariationselectors")];
+ char uniname2ctype_pool_str2375[sizeof("incjkcompatibilityideographssupplement")];
+ char uniname2ctype_pool_str2379[sizeof("inindicsiyaqnumbers")];
+ char uniname2ctype_pool_str2389[sizeof("khojki")];
+ char uniname2ctype_pool_str2392[sizeof("inplayingcards")];
+ char uniname2ctype_pool_str2396[sizeof("graphemeclusterbreak=extend")];
+ char uniname2ctype_pool_str2397[sizeof("graphemeclusterbreak=prepend")];
+ char uniname2ctype_pool_str2398[sizeof("space")];
+ char uniname2ctype_pool_str2401[sizeof("tagbanwa")];
+ char uniname2ctype_pool_str2416[sizeof("extpict")];
+ char uniname2ctype_pool_str2421[sizeof("insupplementaryprivateuseareaa")];
+ char uniname2ctype_pool_str2422[sizeof("insupplementalarrowsc")];
+ char uniname2ctype_pool_str2424[sizeof("pd")];
+ char uniname2ctype_pool_str2427[sizeof("insupplementaryprivateuseareab")];
+ char uniname2ctype_pool_str2428[sizeof("innoblock")];
+ char uniname2ctype_pool_str2432[sizeof("invariationselectorssupplement")];
+ char uniname2ctype_pool_str2433[sizeof("inhanguljamoextendeda")];
+ char uniname2ctype_pool_str2434[sizeof("kthi")];
+ char uniname2ctype_pool_str2439[sizeof("inhanguljamoextendedb")];
+ char uniname2ctype_pool_str2440[sizeof("sk")];
+ char uniname2ctype_pool_str2443[sizeof("cherokee")];
+ char uniname2ctype_pool_str2451[sizeof("nchar")];
+ char uniname2ctype_pool_str2458[sizeof("pc")];
+ char uniname2ctype_pool_str2466[sizeof("graphemeextend")];
+ char uniname2ctype_pool_str2468[sizeof("wancho")];
+ char uniname2ctype_pool_str2473[sizeof("inprivateusearea")];
+ char uniname2ctype_pool_str2483[sizeof("sunuwar")];
+ char uniname2ctype_pool_str2491[sizeof("ingothic")];
+ char uniname2ctype_pool_str2495[sizeof("softdotted")];
+ char uniname2ctype_pool_str2503[sizeof("lowercaseletter")];
+ char uniname2ctype_pool_str2505[sizeof("phli")];
+ char uniname2ctype_pool_str2518[sizeof("katakana")];
+ char uniname2ctype_pool_str2526[sizeof("inunifiedcanadianaboriginalsyllabicsextended")];
+ char uniname2ctype_pool_str2528[sizeof("hanifirohingya")];
+ char uniname2ctype_pool_str2532[sizeof("palm")];
+ char uniname2ctype_pool_str2534[sizeof("talu")];
+ char uniname2ctype_pool_str2541[sizeof("inlisu")];
+ char uniname2ctype_pool_str2543[sizeof("lu")];
+ char uniname2ctype_pool_str2553[sizeof("invithkuqi")];
+ char uniname2ctype_pool_str2570[sizeof("finalpunctuation")];
+ char uniname2ctype_pool_str2571[sizeof("incyrillicextendeda")];
+ char uniname2ctype_pool_str2577[sizeof("incyrillicextendedb")];
+ char uniname2ctype_pool_str2579[sizeof("noncharactercodepoint")];
+ char uniname2ctype_pool_str2581[sizeof("mark")];
+ char uniname2ctype_pool_str2582[sizeof("medf")];
+ char uniname2ctype_pool_str2590[sizeof("inkiratrai")];
+ char uniname2ctype_pool_str2591[sizeof("intelugu")];
+ char uniname2ctype_pool_str2592[sizeof("inmakasar")];
+ char uniname2ctype_pool_str2593[sizeof("graphemeclusterbreak=l")];
+ char uniname2ctype_pool_str2596[sizeof("inkharoshthi")];
+ char uniname2ctype_pool_str2599[sizeof("graphemeclusterbreak=control")];
+ char uniname2ctype_pool_str2603[sizeof("deprecated")];
+ char uniname2ctype_pool_str2612[sizeof("insupplementalsymbolsandpictographs")];
+ char uniname2ctype_pool_str2613[sizeof("tirh")];
+ char uniname2ctype_pool_str2614[sizeof("sunu")];
+ char uniname2ctype_pool_str2618[sizeof("letter")];
+ char uniname2ctype_pool_str2619[sizeof("medefaidrin")];
+ char uniname2ctype_pool_str2625[sizeof("beng")];
+ char uniname2ctype_pool_str2626[sizeof("makasar")];
+ char uniname2ctype_pool_str2632[sizeof("cwl")];
+ char uniname2ctype_pool_str2633[sizeof("intakri")];
+ char uniname2ctype_pool_str2634[sizeof("tavt")];
+ char uniname2ctype_pool_str2658[sizeof("todr")];
+ char uniname2ctype_pool_str2668[sizeof("todhri")];
+ char uniname2ctype_pool_str2671[sizeof("insupplementalpunctuation")];
+ char uniname2ctype_pool_str2672[sizeof("modifiersymbol")];
+ char uniname2ctype_pool_str2673[sizeof("ogham")];
+ char uniname2ctype_pool_str2679[sizeof("wcho")];
+ char uniname2ctype_pool_str2688[sizeof("intagalog")];
+ char uniname2ctype_pool_str2689[sizeof("omath")];
+ char uniname2ctype_pool_str2699[sizeof("inkhmer")];
+ char uniname2ctype_pool_str2700[sizeof("cf")];
+ char uniname2ctype_pool_str2701[sizeof("bassavah")];
+ char uniname2ctype_pool_str2705[sizeof("extendedpictographic")];
+ char uniname2ctype_pool_str2708[sizeof("zyyy")];
+ char uniname2ctype_pool_str2714[sizeof("incyrillicextendedc")];
+ char uniname2ctype_pool_str2725[sizeof("ugaritic")];
+ char uniname2ctype_pool_str2726[sizeof("goth")];
+ char uniname2ctype_pool_str2728[sizeof("idcompatmathstart")];
+ char uniname2ctype_pool_str2729[sizeof("divesakuru")];
+ char uniname2ctype_pool_str2732[sizeof("wspace")];
+ char uniname2ctype_pool_str2737[sizeof("geor")];
+ char uniname2ctype_pool_str2764[sizeof("cyrillic")];
+ char uniname2ctype_pool_str2765[sizeof("graphemeclusterbreak=cr")];
+ char uniname2ctype_pool_str2767[sizeof("sorasompeng")];
+ char uniname2ctype_pool_str2780[sizeof("graphemeclusterbreak=regionalindicator")];
+ char uniname2ctype_pool_str2782[sizeof("tirhuta")];
+ char uniname2ctype_pool_str2791[sizeof("inbopomofoextended")];
+ char uniname2ctype_pool_str2796[sizeof("yezi")];
+ char uniname2ctype_pool_str2798[sizeof("p")];
+ char uniname2ctype_pool_str2799[sizeof("incyrillicextendedd")];
+ char uniname2ctype_pool_str2800[sizeof("po")];
+ char uniname2ctype_pool_str2801[sizeof("zp")];
+ char uniname2ctype_pool_str2802[sizeof("dogr")];
+ char uniname2ctype_pool_str2806[sizeof("dep")];
+ char uniname2ctype_pool_str2813[sizeof("hung")];
+ char uniname2ctype_pool_str2819[sizeof("term")];
+ char uniname2ctype_pool_str2826[sizeof("deva")];
+ char uniname2ctype_pool_str2831[sizeof("format")];
+ char uniname2ctype_pool_str2835[sizeof("oldturkic")];
+ char uniname2ctype_pool_str2836[sizeof("kayahli")];
+ char uniname2ctype_pool_str2844[sizeof("devanagari")];
+ char uniname2ctype_pool_str2850[sizeof("olck")];
+ char uniname2ctype_pool_str2852[sizeof("dupl")];
+ char uniname2ctype_pool_str2857[sizeof("incurrencysymbols")];
+ char uniname2ctype_pool_str2861[sizeof("olchiki")];
+ char uniname2ctype_pool_str2863[sizeof("inethiopicextendeda")];
+ char uniname2ctype_pool_str2869[sizeof("inethiopicextendedb")];
+ char uniname2ctype_pool_str2872[sizeof("phagspa")];
+ char uniname2ctype_pool_str2877[sizeof("buhd")];
+ char uniname2ctype_pool_str2878[sizeof("inhangulsyllables")];
+ char uniname2ctype_pool_str2881[sizeof("inlatinextendedf")];
+ char uniname2ctype_pool_str2883[sizeof("modifierletter")];
+ char uniname2ctype_pool_str2894[sizeof("graph")];
+ char uniname2ctype_pool_str2897[sizeof("ingaray")];
+ char uniname2ctype_pool_str2900[sizeof("number")];
+ char uniname2ctype_pool_str2910[sizeof("inkayahli")];
+ char uniname2ctype_pool_str2922[sizeof("lepcha")];
+ char uniname2ctype_pool_str2925[sizeof("plrd")];
+ char uniname2ctype_pool_str2926[sizeof("incjksymbolsandpunctuation")];
+ char uniname2ctype_pool_str2928[sizeof("ecomp")];
+ char uniname2ctype_pool_str2947[sizeof("cuneiform")];
+ char uniname2ctype_pool_str2953[sizeof("inglagolitic")];
+ char uniname2ctype_pool_str2960[sizeof("gunjalagondi")];
+ char uniname2ctype_pool_str2970[sizeof("bugi")];
+ char uniname2ctype_pool_str2984[sizeof("takri")];
+ char uniname2ctype_pool_str2986[sizeof("cprt")];
+ char uniname2ctype_pool_str2987[sizeof("spaceseparator")];
+ char uniname2ctype_pool_str2991[sizeof("ingurungkhema")];
+ char uniname2ctype_pool_str2993[sizeof("incypriotsyllabary")];
+ char uniname2ctype_pool_str2995[sizeof("inpaucinhau")];
+ char uniname2ctype_pool_str3005[sizeof("gong")];
+ char uniname2ctype_pool_str3013[sizeof("joinc")];
+ char uniname2ctype_pool_str3015[sizeof("currencysymbol")];
+ char uniname2ctype_pool_str3017[sizeof("rohg")];
+ char uniname2ctype_pool_str3021[sizeof("logicalorderexception")];
+ char uniname2ctype_pool_str3022[sizeof("grek")];
+ char uniname2ctype_pool_str3041[sizeof("changeswhenlowercased")];
+ char uniname2ctype_pool_str3049[sizeof("inpahawhhmong")];
+ char uniname2ctype_pool_str3052[sizeof("yezidi")];
+ char uniname2ctype_pool_str3054[sizeof("cwcf")];
+ char uniname2ctype_pool_str3061[sizeof("extender")];
+ char uniname2ctype_pool_str3068[sizeof("inhangulcompatibilityjamo")];
+ char uniname2ctype_pool_str3078[sizeof("tulutigalari")];
+ char uniname2ctype_pool_str3080[sizeof("terminalpunctuation")];
+ char uniname2ctype_pool_str3086[sizeof("inkatakanaphoneticextensions")];
+ char uniname2ctype_pool_str3090[sizeof("inethiopicextended")];
+ char uniname2ctype_pool_str3097[sizeof("gujr")];
+ char uniname2ctype_pool_str3103[sizeof("patsyn")];
+ char uniname2ctype_pool_str3107[sizeof("ugar")];
+ char uniname2ctype_pool_str3108[sizeof("word")];
+ char uniname2ctype_pool_str3112[sizeof("berf")];
+ char uniname2ctype_pool_str3121[sizeof("xpeo")];
+ char uniname2ctype_pool_str3122[sizeof("regionalindicator")];
+ char uniname2ctype_pool_str3127[sizeof("gujarati")];
+ char uniname2ctype_pool_str3128[sizeof("buhid")];
+ char uniname2ctype_pool_str3137[sizeof("inlatinextendedg")];
+ char uniname2ctype_pool_str3142[sizeof("ethi")];
+ char uniname2ctype_pool_str3165[sizeof("inkhitansmallscript")];
+ char uniname2ctype_pool_str3169[sizeof("ingeorgiansupplement")];
+ char uniname2ctype_pool_str3177[sizeof("inegyptianhieroglyphs")];
+ char uniname2ctype_pool_str3184[sizeof("tifinagh")];
+ char uniname2ctype_pool_str3188[sizeof("inegyptianhieroglyphsextendeda")];
+ char uniname2ctype_pool_str3190[sizeof("inegyptianhieroglyphformatcontrols")];
+ char uniname2ctype_pool_str3221[sizeof("inkhudawadi")];
+ char uniname2ctype_pool_str3231[sizeof("incjkcompatibility")];
+ char uniname2ctype_pool_str3238[sizeof("rjng")];
+ char uniname2ctype_pool_str3240[sizeof("buginese")];
+ char uniname2ctype_pool_str3245[sizeof("mendekikakui")];
+ char uniname2ctype_pool_str3247[sizeof("letternumber")];
+ char uniname2ctype_pool_str3257[sizeof("phlp")];
+ char uniname2ctype_pool_str3261[sizeof("separator")];
+ char uniname2ctype_pool_str3263[sizeof("pauc")];
+ char uniname2ctype_pool_str3281[sizeof("vithkuqi")];
+ char uniname2ctype_pool_str3287[sizeof("inkangxiradicals")];
+ char uniname2ctype_pool_str3291[sizeof("changeswhencasefolded")];
+ char uniname2ctype_pool_str3302[sizeof("graphemeclusterbreak=lf")];
+ char uniname2ctype_pool_str3307[sizeof("joincontrol")];
+ char uniname2ctype_pool_str3326[sizeof("inmeroiticcursive")];
+ char uniname2ctype_pool_str3334[sizeof("pe")];
+ char uniname2ctype_pool_str3335[sizeof("patternwhitespace")];
+ char uniname2ctype_pool_str3357[sizeof("duployan")];
+ char uniname2ctype_pool_str3359[sizeof("phag")];
+ char uniname2ctype_pool_str3363[sizeof("meeteimayek")];
+ char uniname2ctype_pool_str3407[sizeof("innyiakengpuachuehmong")];
+ char uniname2ctype_pool_str3408[sizeof("incjkunifiedideographsextensioni")];
+ char uniname2ctype_pool_str3414[sizeof("incjkunifiedideographs")];
+ char uniname2ctype_pool_str3416[sizeof("incjkunifiedideographsextensionj")];
+ char uniname2ctype_pool_str3418[sizeof("georgian")];
+ char uniname2ctype_pool_str3426[sizeof("incjkunifiedideographsextensiona")];
+ char uniname2ctype_pool_str3432[sizeof("incjkunifiedideographsextensionb")];
+ char uniname2ctype_pool_str3436[sizeof("warangciti")];
+ char uniname2ctype_pool_str3444[sizeof("inhighprivateusesurrogates")];
+ char uniname2ctype_pool_str3469[sizeof("meroitichieroglyphs")];
+ char uniname2ctype_pool_str3481[sizeof("java")];
+ char uniname2ctype_pool_str3493[sizeof("garay")];
+ char uniname2ctype_pool_str3497[sizeof("nonspacingmark")];
+ char uniname2ctype_pool_str3505[sizeof("otheridstart")];
+ char uniname2ctype_pool_str3507[sizeof("otheridcontinue")];
+ char uniname2ctype_pool_str3516[sizeof("xsux")];
+ char uniname2ctype_pool_str3532[sizeof("phnx")];
+ char uniname2ctype_pool_str3535[sizeof("incjkunifiedideographsextensione")];
+ char uniname2ctype_pool_str3536[sizeof("signwriting")];
+ char uniname2ctype_pool_str3543[sizeof("tolongsiki")];
+ char uniname2ctype_pool_str3569[sizeof("incjkunifiedideographsextensionc")];
+ char uniname2ctype_pool_str3579[sizeof("combiningmark")];
+ char uniname2ctype_pool_str3585[sizeof("nushu")];
+ char uniname2ctype_pool_str3598[sizeof("takr")];
+ char uniname2ctype_pool_str3613[sizeof("tfng")];
+ char uniname2ctype_pool_str3614[sizeof("changeswhenuppercased")];
+ char uniname2ctype_pool_str3622[sizeof("inglagoliticsupplement")];
+ char uniname2ctype_pool_str3629[sizeof("surrogate")];
+ char uniname2ctype_pool_str3647[sizeof("orkh")];
+ char uniname2ctype_pool_str3650[sizeof("graphemeclusterbreak=v")];
+ char uniname2ctype_pool_str3651[sizeof("graphemeclusterbreak=lv")];
+ char uniname2ctype_pool_str3654[sizeof("incjkunifiedideographsextensiond")];
+ char uniname2ctype_pool_str3666[sizeof("telu")];
+ char uniname2ctype_pool_str3669[sizeof("inhalfwidthandfullwidthforms")];
+ char uniname2ctype_pool_str3686[sizeof("otheralphabetic")];
+ char uniname2ctype_pool_str3690[sizeof("unknown")];
+ char uniname2ctype_pool_str3699[sizeof("punct")];
+ char uniname2ctype_pool_str3718[sizeof("tglg")];
+ char uniname2ctype_pool_str3733[sizeof("javanese")];
+ char uniname2ctype_pool_str3770[sizeof("otherdefaultignorablecodepoint")];
+ char uniname2ctype_pool_str3778[sizeof("cwu")];
+ char uniname2ctype_pool_str3782[sizeof("rejang")];
+ char uniname2ctype_pool_str3813[sizeof("egyp")];
+ char uniname2ctype_pool_str3835[sizeof("perm")];
+ char uniname2ctype_pool_str3836[sizeof("othersymbol")];
+ char uniname2ctype_pool_str3869[sizeof("epres")];
+ char uniname2ctype_pool_str3877[sizeof("olduyghur")];
+ char uniname2ctype_pool_str3894[sizeof("tutg")];
+ char uniname2ctype_pool_str3901[sizeof("enclosingmark")];
+ char uniname2ctype_pool_str3918[sizeof("ingeorgianextended")];
+ char uniname2ctype_pool_str3945[sizeof("ogrext")];
+ char uniname2ctype_pool_str3965[sizeof("indivesakuru")];
+ char uniname2ctype_pool_str3972[sizeof("otherlowercase")];
+ char uniname2ctype_pool_str3981[sizeof("other")];
+ char uniname2ctype_pool_str3995[sizeof("othernumber")];
+ char uniname2ctype_pool_str4007[sizeof("hexdigit")];
+ char uniname2ctype_pool_str4018[sizeof("incjkradicalssupplement")];
+ char uniname2ctype_pool_str4035[sizeof("blank")];
+ char uniname2ctype_pool_str4064[sizeof("ethiopic")];
+ char uniname2ctype_pool_str4069[sizeof("graphemeclusterbreak=spacingmark")];
+ char uniname2ctype_pool_str4072[sizeof("spacingmark")];
+ char uniname2ctype_pool_str4089[sizeof("tagalog")];
+ char uniname2ctype_pool_str4102[sizeof("batak")];
+ char uniname2ctype_pool_str4110[sizeof("guru")];
+ char uniname2ctype_pool_str4117[sizeof("hex")];
+ char uniname2ctype_pool_str4140[sizeof("paucinhau")];
+ char uniname2ctype_pool_str4153[sizeof("modifiercombiningmark")];
+ char uniname2ctype_pool_str4163[sizeof("otherpunctuation")];
+ char uniname2ctype_pool_str4180[sizeof("ougr")];
+ char uniname2ctype_pool_str4228[sizeof("palmyrene")];
+ char uniname2ctype_pool_str4318[sizeof("othermath")];
+ char uniname2ctype_pool_str4353[sizeof("incjkunifiedideographsextensionh")];
+ char uniname2ctype_pool_str4354[sizeof("inboxdrawing")];
+ char uniname2ctype_pool_str4401[sizeof("patternsyntax")];
+ char uniname2ctype_pool_str4404[sizeof("oupper")];
+ char uniname2ctype_pool_str4410[sizeof("gurungkhema")];
+ char uniname2ctype_pool_str4414[sizeof("prependedconcatenationmark")];
+ char uniname2ctype_pool_str4439[sizeof("otherletter")];
+ char uniname2ctype_pool_str4491[sizeof("pf")];
+ char uniname2ctype_pool_str4494[sizeof("qmark")];
+ char uniname2ctype_pool_str4543[sizeof("inhighsurrogates")];
+ char uniname2ctype_pool_str4544[sizeof("xposixpunct")];
+ char uniname2ctype_pool_str4545[sizeof("otheruppercase")];
+ char uniname2ctype_pool_str4564[sizeof("incjkunifiedideographsextensionf")];
+ char uniname2ctype_pool_str4670[sizeof("punctuation")];
+ char uniname2ctype_pool_str4692[sizeof("incjkunifiedideographsextensiong")];
+ char uniname2ctype_pool_str4731[sizeof("egyptianhieroglyphs")];
+ char uniname2ctype_pool_str4775[sizeof("defaultignorablecodepoint")];
+ char uniname2ctype_pool_str4777[sizeof("quotationmark")];
+ char uniname2ctype_pool_str4800[sizeof("openpunctuation")];
+ char uniname2ctype_pool_str4851[sizeof("unifiedideograph")];
+ char uniname2ctype_pool_str4941[sizeof("greek")];
+ char uniname2ctype_pool_str4985[sizeof("othergraphemeextend")];
+ char uniname2ctype_pool_str5002[sizeof("inkaktoviknumerals")];
+ char uniname2ctype_pool_str5234[sizeof("uppercase")];
+ char uniname2ctype_pool_str5271[sizeof("grlink")];
+ char uniname2ctype_pool_str5290[sizeof("nyiakengpuachuehmong")];
+ char uniname2ctype_pool_str5329[sizeof("gukh")];
+ char uniname2ctype_pool_str5512[sizeof("pahawhhmong")];
+ char uniname2ctype_pool_str5557[sizeof("upper")];
+ char uniname2ctype_pool_str5800[sizeof("uppercaseletter")];
+ char uniname2ctype_pool_str5919[sizeof("graphemelink")];
+ char uniname2ctype_pool_str5981[sizeof("telugu")];
+ char uniname2ctype_pool_str6036[sizeof("gurmukhi")];
+ char uniname2ctype_pool_str6068[sizeof("paragraphseparator")];
+#endif /* USE_UNICODE_PROPERTIES */
+ };
+static const struct uniname2ctype_pool_t uniname2ctype_pool_contents =
+ {
+#ifndef USE_UNICODE_PROPERTIES
+ "word",
+ "print",
+ "punct",
+ "alpha",
+#else /* USE_UNICODE_PROPERTIES */
+ "n",
+ "m",
+ "mn",
+ "lm",
+ "inmro",
+ "innko",
+ "mro",
+ "mroo",
+ "ri",
+ "lao",
+ "laoo",
+ "ahom",
+ "hano",
+ "miao",
+ "hani",
+ "inmiao",
+ "han",
+ "mani",
+ "lina",
+ "inahom",
+ "hanunoo",
+ "limb",
+ "linb",
+ "inmanichaean",
+#endif /* USE_UNICODE_PROPERTIES */
+ "alnum",
+#ifndef USE_UNICODE_PROPERTIES
+ "xdigit",
+ "upper",
+#else /* USE_UNICODE_PROPERTIES */
+ "armi",
+ "nandinagari",
+ "armn",
+ "lana",
+ "zanb",
+ "inosmanya",
+ "insamaritan",
+ "inbhaiksuki",
+ "armenian",
+ "sm",
+ "inmasaramgondi",
+ "s",
+ "innabataean",
+ "zs",
+ "inbasiclatin",
+ "innumberforms",
+ "arab",
+ "inmusicalsymbols",
+ "latn",
+ "inthai",
+ "latin",
+ "shavian",
+ "initialpunctuation",
+ "hatran",
+ "di",
+ "inthaana",
+ "intoto",
+ "nabataean",
+ "intaitham",
+ "inarabicpresentationformsa",
+ "inbraillepatterns",
+ "inarabicpresentationformsb",
+ "ids",
+ "dia",
+ "inarmenian",
+ "idsb",
+ "intransportandmapsymbols",
+ "inideographicsymbolsandpunctuation",
+ "inavestan",
+ "inipaextensions",
+ "inelbasan",
+ "inopticalcharacterrecognition",
+ "brai",
+ "bamum",
+ "incham",
+ "inideographicdescriptioncharacters",
+ "brahmi",
+ "idst",
+ "bass",
+ "mandaic",
+ "inemoticons",
+ "incommonindicnumberforms",
+ "intibetan",
+ "inarabic",
+ "nbat",
+ "cn",
+ "inancientsymbols",
+ "ci",
+#endif /* USE_UNICODE_PROPERTIES */
+ "ascii",
+#ifdef USE_UNICODE_PROPERTIES
+ "mcm",
+ "ideo",
+ "inmodi",
+ "vai",
+ "vaii",
+ "cham",
+ "inmyanmarextendeda",
+ "nand",
+ "inmyanmarextendedb",
+ "mand",
+ "cans",
+ "inoldsogdian",
+ "chorasmian",
+ "innewa",
+ "chakma",
+ "incuneiform",
+ "vs",
+ "cs",
+ "sind",
+ "shaw",
+ "inspecials",
+ "inchesssymbols",
+ "avst",
+ "inblockelements",
+ "nd",
+ "sharada",
+ "inmiscellaneoussymbols",
+ "inmiscellaneousmathematicalsymbolsa",
+ "sidt",
+ "inmiscellaneousmathematicalsymbolsb",
+ "inmiscellaneoussymbolsandarrows",
+ "arabic",
+ "inmiscellaneoussymbolsandpictographs",
+ "c",
+ "lc",
+ "mc",
+ "inmedefaidrin",
+ "inmyanmarextendedc",
+ "insundanese",
+ "indominotiles",
+ "insymbolsandpictographsextendeda",
+ "inwancho",
+ "inolditalic",
+ "inmodifiertoneletters",
+ "incb=consonant",
+ "sd",
+ "inmandaic",
+ "inmiscellaneoussymbolssupplement",
+ "nko",
+ "nkoo",
+ "l",
+ "inmeeteimayekextensions",
+ "nl",
+ "zl",
+ "ll",
+ "inlao",
+ "khoj",
+ "idc",
+ "innewtailue",
+ "inolonal",
+ "sc",
+ "indeseret",
+ "incuneiformnumbersandpunctuation",
+ "krai",
+ "inarabicextendeda",
+ "inoldturkic",
+ "avestan",
+ "inarabicextendedb",
+ "inmalayalam",
+ "kharoshthi",
+ "kana",
+ "inadlam",
+ "idcontinue",
+ "insiddham",
+ "intamil",
+ "inmultani",
+ "intolongsiki",
+ "kits",
+ "incb=extend",
+ "sidetic",
+ "sidd",
+ "incontrolpictures",
+ "insidetic",
+ "sinhala",
+ "inlatinextendeda",
+ "inlatinextendedb",
+ "adlm",
+ "adlam",
+ "inlineara",
+ "intamilsupplement",
+ "inbalinese",
+ "inspacingmodifierletters",
+ "inarabicextendedc",
+ "inlycian",
+ "bali",
+ "hira",
+ "cc",
+ "insmallkanaextension",
+ "intaile",
+ "qaai",
+ "inmyanmar",
+ "narb",
+ "inarrows",
+ "lineara",
+ "linearb",
+ "insharada",
+ "inruminumeralsymbols",
+ "masaramgondi",
+ "hatr",
+ "knda",
+ "samr",
+ "kawi",
+ "inlydian",
+ "samaritan",
+ "sarb",
+ "no",
+ "bidic",
+ "lo",
+ "hmnp",
+ "onao",
+ "inlowsurrogates",
+ "kannada",
+ "inlinearbideograms",
+ "inletterlikesymbols",
+ "cased",
+ "inbopomofo",
+ "inberiaerfe",
+ "lineseparator",
+ "z",
+ "insymbolsforlegacycomputingsupplement",
+ "inrunic",
+ "incarian",
+ "inlatinextendede",
+ "inmarchen",
+ "so",
+ "marc",
+ "oriya",
+ "inchorasmian",
+ "yi",
+ "insyriac",
+ "yiii",
+ "alpha",
+ "qaac",
+ "insundanesesupplement",
+ "osma",
+ "inmiscellaneoustechnical",
+ "idstart",
+ "inenclosedcjklettersandmonths",
+ "inlatinextendedc",
+ "dsrt",
+ "odi",
+ "chrs",
+ "cari",
+ "innandinagari",
+ "balinese",
+ "inwarangciti",
+ "inphoenician",
+ "kali",
+ "inoldnortharabian",
+ "radical",
+ "carian",
+ "idsbinaryoperator",
+ "shrd",
+ "inoldsoutharabian",
+ "diacritic",
+ "mlym",
+ "zinh",
+ "inphaistosdisc",
+ "incyrillic",
+ "ininscriptionalpahlavi",
+ "insoyombo",
+ "ininscriptionalparthian",
+ "inoriya",
+ "lyci",
+ "inogham",
+ "mahj",
+ "gran",
+ "inmahajani",
+ "co",
+ "cher",
+ "alphabetic",
+ "insinhala",
+ "modi",
+ "inbrahmi",
+ "loe",
+ "lycian",
+ "mahajani",
+ "common",
+ "intaiyo",
+ "inhanifirohingya",
+ "inbassavah",
+ "sinh",
+ "oids",
+ "inlatinextendedadditional",
+ "inyijinghexagramsymbols",
+ "inoldpersian",
+ "bidicontrol",
+ "math",
+ "inarabicsupplement",
+ "thai",
+ "inlatinextendedd",
+ "taiyo",
+ "lisu",
+ "tnsa",
+ "incherokee",
+ "thaa",
+ "lydi",
+ "inbamum",
+ "khmr",
+ "inbyzantinemusicalsymbols",
+ "lt",
+ "khar",
+ "thaana",
+ "osage",
+ "lydian",
+ "inanatolianhieroglyphs",
+#ifdef USE_UNICODE_AGE_PROPERTIES
+ "age=11.0",
+ "age=10.0",
+ "age=12.1",
+ "age=12.0",
+ "age=1.1",
+#endif /* USE_UNICODE_AGE_PROPERTIES */
+ "insylotinagri",
+ "anatolianhieroglyphs",
+#ifdef USE_UNICODE_AGE_PROPERTIES
+ "age=2.1",
+ "age=2.0",
+ "age=14.0",
+#endif /* USE_UNICODE_AGE_PROPERTIES */
+ "tangsa",
+ "dash",
+ "incombiningdiacriticalmarks",
+#ifdef USE_UNICODE_AGE_PROPERTIES
+ "age=17.0",
+ "age=4.1",
+ "age=4.0",
+#endif /* USE_UNICODE_AGE_PROPERTIES */
+ "tibt",
+#ifdef USE_UNICODE_AGE_PROPERTIES
+ "age=15.1",
+ "age=15.0",
+ "age=7.0",
+#endif /* USE_UNICODE_AGE_PROPERTIES */
+ "inolchiki",
+#ifdef USE_UNICODE_AGE_PROPERTIES
+ "age=9.0",
+#endif /* USE_UNICODE_AGE_PROPERTIES */
+ "incombiningdiacriticalmarksforsymbols",
+#ifdef USE_UNICODE_AGE_PROPERTIES
+ "age=5.1",
+ "age=5.0",
+ "age=16.0",
+ "age=5.2",
+ "age=8.0",
+ "age=13.0",
+ "age=6.1",
+ "age=6.0",
+ "age=6.2",
+ "age=3.1",
+ "age=3.0",
+ "age=3.2",
+#endif /* USE_UNICODE_AGE_PROPERTIES */
+ "inarabicmathematicalalphabeticsymbols",
+ "brah",
+ "tibetan",
+ "mtei",
+ "incoptic",
+ "manichaean",
+#ifdef USE_UNICODE_AGE_PROPERTIES
+ "age=6.3",
+#endif /* USE_UNICODE_AGE_PROPERTIES */
+ "emoji",
+ "oidc",
+ "incombiningdiacriticalmarkssupplement",
+ "idsu",
+ "saurashtra",
+ "inoldpermic",
+ "closepunctuation",
+ "incombininghalfmarks",
+ "incopticepactnumbers",
+ "elba",
+ "xdigit",
+#endif /* USE_UNICODE_PROPERTIES */
+ "cntrl",
+#ifndef USE_UNICODE_PROPERTIES
+ "space",
+ "xposixpunct",
+#else /* USE_UNICODE_PROPERTIES */
+ "bamu",
+ "xids",
+ "inoldhungarian",
+ "grext",
+ "mongolian",
+ "sterm",
+ "braille",
+ "inbuhid",
+ "elbasan",
+ "zanabazarsquare",
+ "incountingrodnumerals",
+ "inenclosedalphanumerics",
+ "incb=linker",
+ "taiviet",
+ "inelymaic",
+ "inethiopic",
+ "sgnw",
+ "olditalic",
+ "vith",
+ "grbase",
+ "hluw",
+ "intodhri",
+ "asciihexdigit",
+ "me",
+ "hmng",
+ "siddham",
+ "inenclosedalphanumericsupplement",
+ "taile",
+ "nagm",
+ "hang",
+ "inscriptionalparthian",
+ "inmongolian",
+ "innagmundari",
+ "sylo",
+ "ingunjalagondi",
+ "ingujarati",
+ "inbengali",
+ "khitansmallscript",
+ "xidcontinue",
+ "ingrantha",
+ "insinhalaarchaicnumbers",
+ "connectorpunctuation",
+ "inpalmyrene",
+ "incombiningdiacriticalmarksextended",
+ "xidstart",
+ "xidc",
+ "inancientgreekmusicalnotation",
+ "inancientgreeknumbers",
+ "intangsa",
+ "intags",
+ "inlepcha",
+ "caucasianalbanian",
+ "sylotinagri",
+ "emod",
+ "incaucasianalbanian",
+ "intagbanwa",
+ "mend",
+ "newa",
+ "inearlydynasticcuneiform",
+ "kaithi",
+ "intangut",
+ "mymr",
+ "inosage",
+ "inmahjongtiles",
+ "malayalam",
+ "sora",
+ "inbuginese",
+ "emojimodifierbase",
+ "induployan",
+ "ingeometricshapes",
+ "ingeneralpunctuation",
+ "myanmar",
+ "inlatin1supplement",
+ "ital",
+ "taml",
+ "inaegeannumbers",
+ "insharadasupplement",
+ "mathsymbol",
+ "inlimbu",
+ "invai",
+ "emojicomponent",
+ "insuttonsignwriting",
+ "digit",
+ "newtailue",
+ "inshavian",
+ "insogdian",
+ "indingbats",
+ "imperialaramaic",
+ "intulutigalari",
+ "incyprominoan",
+ "glagolitic",
+ "ebase",
+ "intaixuanjingsymbols",
+ "inbamumsupplement",
+ "gara",
+ "insyriacsupplement",
+ "casedletter",
+ "zzzz",
+ "inhiragana",
+ "tale",
+ "canadianaboriginal",
+ "ahex",
+ "inmayannumerals",
+ "inzanabazarsquare",
+ "inyiradicals",
+ "inscriptionalpahlavi",
+ "inalchemicalsymbols",
+ "inhatran",
+ "assigned",
+ "intaiviet",
+ "syrc",
+ "bopo",
+ "intirhuta",
+ "oldnortharabian",
+ "insupplementalmathematicaloperators",
+ "bopomofo",
+ "olonal",
+ "injavanese",
+ "insunuwar",
+ "inmathematicalalphanumericsymbols",
+ "inimperialaramaic",
+ "khmer",
+ "gonm",
+ "hyphen",
+ "insuperscriptsandsubscripts",
+ "inenclosedideographicsupplement",
+ "ingeometricshapesextended",
+ "insaurashtra",
+ "ogam",
+ "orya",
+ "saur",
+ "marchen",
+ "sundanese",
+ "khudawadi",
+ "soyo",
+ "whitespace",
+ "uideo",
+ "oldpersian",
+ "inyezidi",
+ "kiratrai",
+ "inlisusupplement",
+ "mero",
+ "symbol",
+ "soyombo",
+ "osmanya",
+ "indevanagari",
+ "unassigned",
+ "bengali",
+ "hebr",
+ "hebrew",
+ "inornamentaldingbats",
+ "invedicextensions",
+ "copt",
+ "ingreekextended",
+ "sund",
+ "cyprominoan",
+ "inherited",
+ "toto",
+ "inugaritic",
+ "syriac",
+ "cwt",
+ "inhebrew",
+ "runic",
+ "inmongoliansupplement",
+ "inshorthandformatcontrols",
+ "cypriot",
+ "cwcm",
+ "ingreekandcoptic",
+ "any",
+ "inolduyghur",
+ "inznamennymusicalnotation",
+ "lowercase",
+ "oldpermic",
+ "ingeorgian",
+ "ingurmukhi",
+ "emojimodifier",
+ "inkhojki",
+ "aghb",
+ "merc",
+ "inrejang",
+ "tamil",
+ "indevanagariextendeda",
+ "inalphabeticpresentationforms",
+ "hangul",
+ "inmeroitichieroglyphs",
+ "inkannada",
+ "hiragana",
+ "maka",
+ "inkanbun",
+ "insorasompeng",
+ "inmathematicaloperators",
+ "tayo",
+ "inhanunoo",
+ "multani",
+ "inkaithi",
+ "innushu",
+ "emojipresentation",
+ "insymbolsforlegacycomputing",
+ "meroiticcursive",
+ "grantha",
+ "inlinearbsyllabary",
+ "mult",
+ "taitham",
+ "nshu",
+ "incyrillicsupplement",
+ "dashpunctuation",
+ "inkatakana",
+ "inbatak",
+ "pi",
+ "mong",
+ "oldhungarian",
+ "phoenician",
+ "insmallformvariants",
+ "idsunaryoperator",
+ "variationselector",
+ "limbu",
+ "inyisyllables",
+ "diak",
+ "oldsoutharabian",
+ "lepc",
+ "inottomansiyaqnumbers",
+ "control",
+ "coptic",
+ "inkhmersymbols",
+ "titlecaseletter",
+ "inphagspa",
+ "bhks",
+ "gothic",
+ "sogo",
+ "elym",
+ "ps",
+ "prti",
+ "changeswhencasemapped",
+ "deseret",
+ "bhaiksuki",
+ "cyrl",
+ "olower",
+ "inchakma",
+ "wara",
+ "sogdian",
+ "graphemeclusterbreak=zwj",
+ "runr",
+ "changeswhentitlecased",
+ "incjkstrokes",
+ "incherokeesupplement",
+ "intangutcomponents",
+ "patws",
+ "batk",
+ "caseignorable",
+ "inkawi",
+ "indevanagariextended",
+ "indogra",
+ "intifinagh",
+ "print",
+ "cakm",
+ "graphemeclusterbreak=t",
+ "graphemeclusterbreak=lvt",
+ "inmendekikakui",
+ "inpsalterpahlavi",
+ "dogra",
+ "tangut",
+ "oalpha",
+ "intangutcomponentssupplement",
+ "idcompatmathcontinue",
+ "beriaerfe",
+ "ext",
+ "inkanasupplement",
+ "osge",
+ "inkanaextendeda",
+ "inverticalforms",
+ "decimalnumber",
+ "inkanaextendedb",
+ "idstrinaryoperator",
+ "tols",
+#endif /* USE_UNICODE_PROPERTIES */
+ "lower",
+#ifdef USE_UNICODE_PROPERTIES
+ "glag",
+ "inhanguljamo",
+ "insupplementalarrowsa",
+ "inmeeteimayek",
+ "insupplementalarrowsb",
+ "inunifiedcanadianaboriginalsyllabics",
+ "privateuse",
+ "inunifiedcanadianaboriginalsyllabicsextendeda",
+ "sentenceterminal",
+ "pcm",
+ "elymaic",
+ "cpmn",
+ "incjkcompatibilityforms",
+ "inphoneticextensions",
+ "incjkcompatibilityideographs",
+ "oldsogdian",
+ "inethiopicsupplement",
+ "graphemebase",
+ "intangutsupplement",
+ "tang",
+ "ideographic",
+ "nagmundari",
+ "sogd",
+ "psalterpahlavi",
+ "inphoneticextensionssupplement",
+ "tagb",
+ "invariationselectors",
+ "incjkcompatibilityideographssupplement",
+ "inindicsiyaqnumbers",
+ "khojki",
+ "inplayingcards",
+ "graphemeclusterbreak=extend",
+ "graphemeclusterbreak=prepend",
+ "space",
+ "tagbanwa",
+ "extpict",
+ "insupplementaryprivateuseareaa",
+ "insupplementalarrowsc",
+ "pd",
+ "insupplementaryprivateuseareab",
+ "innoblock",
+ "invariationselectorssupplement",
+ "inhanguljamoextendeda",
+ "kthi",
+ "inhanguljamoextendedb",
+ "sk",
+ "cherokee",
+ "nchar",
+ "pc",
+ "graphemeextend",
+ "wancho",
+ "inprivateusearea",
+ "sunuwar",
+ "ingothic",
+ "softdotted",
+ "lowercaseletter",
+ "phli",
+ "katakana",
+ "inunifiedcanadianaboriginalsyllabicsextended",
+ "hanifirohingya",
+ "palm",
+ "talu",
+ "inlisu",
+ "lu",
+ "invithkuqi",
+ "finalpunctuation",
+ "incyrillicextendeda",
+ "incyrillicextendedb",
+ "noncharactercodepoint",
+ "mark",
+ "medf",
+ "inkiratrai",
+ "intelugu",
+ "inmakasar",
+ "graphemeclusterbreak=l",
+ "inkharoshthi",
+ "graphemeclusterbreak=control",
+ "deprecated",
+ "insupplementalsymbolsandpictographs",
+ "tirh",
+ "sunu",
+ "letter",
+ "medefaidrin",
+ "beng",
+ "makasar",
+ "cwl",
+ "intakri",
+ "tavt",
+ "todr",
+ "todhri",
+ "insupplementalpunctuation",
+ "modifiersymbol",
+ "ogham",
+ "wcho",
+ "intagalog",
+ "omath",
+ "inkhmer",
+ "cf",
+ "bassavah",
+ "extendedpictographic",
+ "zyyy",
+ "incyrillicextendedc",
+ "ugaritic",
+ "goth",
+ "idcompatmathstart",
+ "divesakuru",
+ "wspace",
+ "geor",
+ "cyrillic",
+ "graphemeclusterbreak=cr",
+ "sorasompeng",
+ "graphemeclusterbreak=regionalindicator",
+ "tirhuta",
+ "inbopomofoextended",
+ "yezi",
+ "p",
+ "incyrillicextendedd",
+ "po",
+ "zp",
+ "dogr",
+ "dep",
+ "hung",
+ "term",
+ "deva",
+ "format",
+ "oldturkic",
+ "kayahli",
+ "devanagari",
+ "olck",
+ "dupl",
+ "incurrencysymbols",
+ "olchiki",
+ "inethiopicextendeda",
+ "inethiopicextendedb",
+ "phagspa",
+ "buhd",
+ "inhangulsyllables",
+ "inlatinextendedf",
+ "modifierletter",
+#endif /* USE_UNICODE_PROPERTIES */
+ "graph",
+#ifndef USE_UNICODE_PROPERTIES
+ "digit",
+ "blank"
+#else /* USE_UNICODE_PROPERTIES */
+ "ingaray",
+ "number",
+ "inkayahli",
+ "lepcha",
+ "plrd",
+ "incjksymbolsandpunctuation",
+ "ecomp",
+ "cuneiform",
+ "inglagolitic",
+ "gunjalagondi",
+ "bugi",
+ "takri",
+ "cprt",
+ "spaceseparator",
+ "ingurungkhema",
+ "incypriotsyllabary",
+ "inpaucinhau",
+ "gong",
+ "joinc",
+ "currencysymbol",
+ "rohg",
+ "logicalorderexception",
+ "grek",
+ "changeswhenlowercased",
+ "inpahawhhmong",
+ "yezidi",
+ "cwcf",
+ "extender",
+ "inhangulcompatibilityjamo",
+ "tulutigalari",
+ "terminalpunctuation",
+ "inkatakanaphoneticextensions",
+ "inethiopicextended",
+ "gujr",
+ "patsyn",
+ "ugar",
+ "word",
+ "berf",
+ "xpeo",
+ "regionalindicator",
+ "gujarati",
+ "buhid",
+ "inlatinextendedg",
+ "ethi",
+ "inkhitansmallscript",
+ "ingeorgiansupplement",
+ "inegyptianhieroglyphs",
+ "tifinagh",
+ "inegyptianhieroglyphsextendeda",
+ "inegyptianhieroglyphformatcontrols",
+ "inkhudawadi",
+ "incjkcompatibility",
+ "rjng",
+ "buginese",
+ "mendekikakui",
+ "letternumber",
+ "phlp",
+ "separator",
+ "pauc",
+ "vithkuqi",
+ "inkangxiradicals",
+ "changeswhencasefolded",
+ "graphemeclusterbreak=lf",
+ "joincontrol",
+ "inmeroiticcursive",
+ "pe",
+ "patternwhitespace",
+ "duployan",
+ "phag",
+ "meeteimayek",
+ "innyiakengpuachuehmong",
+ "incjkunifiedideographsextensioni",
+ "incjkunifiedideographs",
+ "incjkunifiedideographsextensionj",
+ "georgian",
+ "incjkunifiedideographsextensiona",
+ "incjkunifiedideographsextensionb",
+ "warangciti",
+ "inhighprivateusesurrogates",
+ "meroitichieroglyphs",
+ "java",
+ "garay",
+ "nonspacingmark",
+ "otheridstart",
+ "otheridcontinue",
+ "xsux",
+ "phnx",
+ "incjkunifiedideographsextensione",
+ "signwriting",
+ "tolongsiki",
+ "incjkunifiedideographsextensionc",
+ "combiningmark",
+ "nushu",
+ "takr",
+ "tfng",
+ "changeswhenuppercased",
+ "inglagoliticsupplement",
+ "surrogate",
+ "orkh",
+ "graphemeclusterbreak=v",
+ "graphemeclusterbreak=lv",
+ "incjkunifiedideographsextensiond",
+ "telu",
+ "inhalfwidthandfullwidthforms",
+ "otheralphabetic",
+ "unknown",
+ "punct",
+ "tglg",
+ "javanese",
+ "otherdefaultignorablecodepoint",
+ "cwu",
+ "rejang",
+ "egyp",
+ "perm",
+ "othersymbol",
+ "epres",
+ "olduyghur",
+ "tutg",
+ "enclosingmark",
+ "ingeorgianextended",
+ "ogrext",
+ "indivesakuru",
+ "otherlowercase",
+ "other",
+ "othernumber",
+ "hexdigit",
+ "incjkradicalssupplement",
+ "blank",
+ "ethiopic",
+ "graphemeclusterbreak=spacingmark",
+ "spacingmark",
+ "tagalog",
+ "batak",
+ "guru",
+ "hex",
+ "paucinhau",
+ "modifiercombiningmark",
+ "otherpunctuation",
+ "ougr",
+ "palmyrene",
+ "othermath",
+ "incjkunifiedideographsextensionh",
+ "inboxdrawing",
+ "patternsyntax",
+ "oupper",
+ "gurungkhema",
+ "prependedconcatenationmark",
+ "otherletter",
+ "pf",
+ "qmark",
+ "inhighsurrogates",
+ "xposixpunct",
+ "otheruppercase",
+ "incjkunifiedideographsextensionf",
+ "punctuation",
+ "incjkunifiedideographsextensiong",
+ "egyptianhieroglyphs",
+ "defaultignorablecodepoint",
+ "quotationmark",
+ "openpunctuation",
+ "unifiedideograph",
+ "greek",
+ "othergraphemeextend",
+ "inkaktoviknumerals",
+ "uppercase",
+ "grlink",
+ "nyiakengpuachuehmong",
+ "gukh",
+ "pahawhhmong",
+ "upper",
+ "uppercaseletter",
+ "graphemelink",
+ "telugu",
+ "gurmukhi",
+ "paragraphseparator"
+#endif /* USE_UNICODE_PROPERTIES */
+ };
+#define uniname2ctype_pool ((const char *) &uniname2ctype_pool_contents)
+const struct uniname2ctype_struct *
+uniname2ctype_p (register const char *str, register size_t len)
+{
+ static const struct uniname2ctype_struct wordlist[] =
+ {
+#ifdef USE_UNICODE_PROPERTIES
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1},
+ {uniname2ctype_offset(str10), 35},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str16), 31},
+ {-1}, {-1},
+ {uniname2ctype_offset(str19), 34},
+ {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str24), 27},
+ {-1}, {-1},
+ {uniname2ctype_offset(str27), 606},
+ {uniname2ctype_offset(str28), 354},
+ {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str33), 192},
+ {uniname2ctype_offset(str34), 192},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str38), 288},
+ {-1},
+ {uniname2ctype_offset(str40), 98},
+ {uniname2ctype_offset(str41), 98},
+ {-1}, {-1},
+ {uniname2ctype_offset(str44), 203},
+ {uniname2ctype_offset(str45), 120},
+ {-1},
+ {uniname2ctype_offset(str47), 176},
+ {uniname2ctype_offset(str48), 113},
+ {-1},
+ {uniname2ctype_offset(str50), 613},
+ {uniname2ctype_offset(str51), 113},
+ {uniname2ctype_offset(str52), 189},
+ {uniname2ctype_offset(str53), 187},
+ {-1}, {-1},
+ {uniname2ctype_offset(str56), 575},
+ {uniname2ctype_offset(str57), 120},
+ {uniname2ctype_offset(str58), 123},
+ {uniname2ctype_offset(str59), 125},
+ {uniname2ctype_offset(str60), 539},
+ {-1},
+ {uniname2ctype_offset(str62), 13},
+ {uniname2ctype_offset(str63), 164},
+ {uniname2ctype_offset(str64), 227},
+ {-1}, {-1},
+ {uniname2ctype_offset(str67), 82},
+ {-1},
+ {uniname2ctype_offset(str69), 155},
+ {uniname2ctype_offset(str70), 218},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str74), 518},
+#endif /* USE_UNICODE_PROPERTIES */
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+#ifndef USE_UNICODE_PROPERTIES
+ {uniname2ctype_offset(str6), 12},
+ {uniname2ctype_offset(str7), 7},
+ {uniname2ctype_offset(str8), 15},
+ {uniname2ctype_offset(str9), 1},
+ {uniname2ctype_offset(str10), 13},
+ {uniname2ctype_offset(str11), 11},
+ {uniname2ctype_offset(str12), 10},
+ {uniname2ctype_offset(str13), 14},
+ {uniname2ctype_offset(str14), 3},
+ {uniname2ctype_offset(str15), 9},
+ {uniname2ctype_offset(str16), 8},
+ {uniname2ctype_offset(str17), 6},
+ {uniname2ctype_offset(str18), 5},
+ {uniname2ctype_offset(str19), 4},
+ {uniname2ctype_offset(str20), 2}
+#else /* USE_UNICODE_PROPERTIES */
+ {uniname2ctype_offset(str81), 355},
+ {uniname2ctype_offset(str82), 587},
+ {uniname2ctype_offset(str83), 82},
+ {-1},
+ {uniname2ctype_offset(str85), 50},
+ {-1}, {-1},
+ {uniname2ctype_offset(str88), 589},
+ {uniname2ctype_offset(str89), 47},
+ {uniname2ctype_offset(str90), 529},
+ {-1},
+ {uniname2ctype_offset(str92), 55},
+ {uniname2ctype_offset(str93), 338},
+ {-1}, {-1},
+ {uniname2ctype_offset(str96), 415},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str102), 84},
+ {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str107), 631},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str115), 79},
+ {-1},
+ {uniname2ctype_offset(str117), 370},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str124), 79},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1},
+ {uniname2ctype_offset(str135), 127},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str141), 44},
+ {-1}, {-1},
+ {uniname2ctype_offset(str144), 205},
+ {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str149), 71},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str155), 353},
+ {-1},
+ {uniname2ctype_offset(str157), 643},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str164), 194},
+ {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str169), 394},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str175), 493},
+ {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str180), 429},
+ {uniname2ctype_offset(str181), 499},
+ {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str186), 67},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str190), 264},
+ {uniname2ctype_offset(str191), 348},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str195), 270},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str199), 662},
+ {-1}, {-1},
+ {uniname2ctype_offset(str202), 614},
+ {uniname2ctype_offset(str203), 540},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str209), 342},
+ {-1},
+ {uniname2ctype_offset(str211), 520},
+ {-1},
+ {uniname2ctype_offset(str213), 420},
+ {-1},
+ {uniname2ctype_offset(str215), 130},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str219), 161},
+ {uniname2ctype_offset(str220), 477},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str227), 444},
+ {uniname2ctype_offset(str228), 171},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str235), 271},
+ {-1},
+ {uniname2ctype_offset(str237), 181},
+ {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str242), 172},
+ {-1},
+ {uniname2ctype_offset(str244), 660},
+ {-1}, {-1},
+ {uniname2ctype_offset(str247), 468},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str257), 372},
+ {uniname2ctype_offset(str258), 350},
+ {-1},
+ {uniname2ctype_offset(str260), 194},
+ {uniname2ctype_offset(str261), 21},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str267), 506},
+ {uniname2ctype_offset(str268), 61},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str274), 14},
+ {uniname2ctype_offset(str275), 289},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str279), 263},
+ {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str284), 571},
+ {uniname2ctype_offset(str285), 147},
+ {uniname2ctype_offset(str286), 147},
+ {uniname2ctype_offset(str287), 154},
+ {-1},
+ {uniname2ctype_offset(str289), 478},
+ {-1},
+ {uniname2ctype_offset(str291), 227},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str295), 476},
+ {-1}, {-1},
+ {uniname2ctype_offset(str298), 172},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1},
+ {uniname2ctype_offset(str310), 105},
+ {-1},
+ {uniname2ctype_offset(str312), 551},
+ {-1}, {-1},
+ {uniname2ctype_offset(str315), 230},
+ {-1},
+ {uniname2ctype_offset(str317), 568},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str333), 173},
+ {-1},
+ {uniname2ctype_offset(str335), 596},
+ {uniname2ctype_offset(str336), 284},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str340), 23},
+ {-1},
+ {uniname2ctype_offset(str342), 200},
+ {-1},
+ {uniname2ctype_offset(str344), 127},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str359), 501},
+ {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str364), 667},
+ {-1},
+ {uniname2ctype_offset(str366), 157},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str373), 423},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1},
+ {uniname2ctype_offset(str384), 36},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1},
+ {uniname2ctype_offset(str395), 177},
+ {-1}, {-1},
+ {uniname2ctype_offset(str398), 425},
+ {-1},
+ {uniname2ctype_offset(str400), 427},
+ {-1},
+ {uniname2ctype_offset(str402), 248},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str406), 431},
+ {uniname2ctype_offset(str407), 433},
+ {-1}, {-1},
+ {uniname2ctype_offset(str410), 84},
+ {-1},
+ {uniname2ctype_offset(str412), 659},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str416), 18},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str424), 25},
+ {uniname2ctype_offset(str425), 32},
+ {uniname2ctype_offset(str426), 611},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str432), 574},
+ {uniname2ctype_offset(str433), 397},
+ {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str438), 655},
+ {-1},
+ {uniname2ctype_offset(str440), 668},
+ {uniname2ctype_offset(str441), 644},
+ {-1}, {-1},
+ {uniname2ctype_offset(str444), 511},
+ {-1}, {-1},
+ {uniname2ctype_offset(str447), 465},
+ {uniname2ctype_offset(str448), 76},
+ {-1}, {-1},
+ {uniname2ctype_offset(str451), 277},
+ {uniname2ctype_offset(str452), 356},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str456), 628},
+ {-1},
+ {uniname2ctype_offset(str458), 143},
+ {uniname2ctype_offset(str459), 143},
+ {uniname2ctype_offset(str460), 24},
+ {uniname2ctype_offset(str461), 480},
+ {uniname2ctype_offset(str462), 37},
+ {uniname2ctype_offset(str463), 53},
+ {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str468), 26},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str472), 371},
+ {uniname2ctype_offset(str473), 186},
+ {-1}, {-1},
+ {uniname2ctype_offset(str476), 68},
+ {uniname2ctype_offset(str477), 391},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str483), 646},
+ {-1},
+ {uniname2ctype_offset(str485), 48},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str491), 516},
+ {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str496), 597},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str502), 243},
+ {-1}, {-1},
+ {uniname2ctype_offset(str505), 359},
+ {-1}, {-1},
+ {uniname2ctype_offset(str508), 544},
+ {-1},
+ {uniname2ctype_offset(str510), 157},
+ {uniname2ctype_offset(str511), 358},
+ {uniname2ctype_offset(str512), 368},
+ {uniname2ctype_offset(str513), 138},
+ {uniname2ctype_offset(str514), 111},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str523), 650},
+ {-1},
+ {uniname2ctype_offset(str525), 68},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str549), 570},
+ {-1},
+ {uniname2ctype_offset(str551), 365},
+ {-1},
+ {uniname2ctype_offset(str553), 564},
+ {uniname2ctype_offset(str554), 591},
+ {-1},
+ {uniname2ctype_offset(str556), 232},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str571), 77},
+ {-1}, {-1},
+ {uniname2ctype_offset(str574), 248},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str584), 199},
+ {-1}, {-1},
+ {uniname2ctype_offset(str587), 419},
+ {uniname2ctype_offset(str588), 533},
+ {-1}, {-1},
+ {uniname2ctype_offset(str591), 96},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str605), 340},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1},
+ {uniname2ctype_offset(str617), 341},
+ {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str622), 209},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str630), 209},
+ {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str635), 524},
+ {-1},
+ {uniname2ctype_offset(str637), 595},
+ {uniname2ctype_offset(str638), 396},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str645), 343},
+ {-1}, {-1},
+ {uniname2ctype_offset(str648), 550},
+ {-1},
+ {uniname2ctype_offset(str650), 508},
+ {-1}, {-1},
+ {uniname2ctype_offset(str653), 139},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1},
+ {uniname2ctype_offset(str665), 110},
+ {-1},
+ {uniname2ctype_offset(str667), 19},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str674), 623},
+ {uniname2ctype_offset(str675), 390},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str681), 118},
+ {uniname2ctype_offset(str682), 373},
+ {-1},
+ {uniname2ctype_offset(str684), 193},
+ {-1}, {-1},
+ {uniname2ctype_offset(str687), 416},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str701), 187},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str707), 125},
+ {-1},
+ {uniname2ctype_offset(str709), 561},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str716), 548},
+ {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str721), 215},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str727), 205},
+ {-1},
+ {uniname2ctype_offset(str729), 94},
+ {uniname2ctype_offset(str730), 159},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str734), 239},
+ {uniname2ctype_offset(str735), 532},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1},
+ {uniname2ctype_offset(str747), 159},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str751), 165},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str760), 38},
+ {-1},
+ {uniname2ctype_offset(str762), 253},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str766), 28},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str780), 228},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str784), 244},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str788), 489},
+ {uniname2ctype_offset(str789), 94},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str795), 503},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str799), 414},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str803), 60},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str809), 448},
+ {uniname2ctype_offset(str810), 612},
+ {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str815), 53},
+ {-1},
+ {uniname2ctype_offset(str817), 52},
+ {uniname2ctype_offset(str818), 627},
+ {-1},
+ {uniname2ctype_offset(str820), 381},
+ {uniname2ctype_offset(str821), 509},
+ {-1},
+ {uniname2ctype_offset(str823), 482},
+ {-1},
+ {uniname2ctype_offset(str825), 588},
+ {-1},
+ {uniname2ctype_offset(str827), 51},
+ {uniname2ctype_offset(str828), 211},
+ {uniname2ctype_offset(str829), 91},
+ {uniname2ctype_offset(str830), 554},
+ {-1},
+ {uniname2ctype_offset(str832), 114},
+ {uniname2ctype_offset(str833), 351},
+ {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str838), 114},
+ {-1},
+ {uniname2ctype_offset(str840), 1},
+ {-1},
+ {uniname2ctype_offset(str842), 132},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str852), 403},
+ {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str857), 128},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str880), 418},
+ {-1}, {-1},
+ {uniname2ctype_offset(str883), 67},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str890), 454},
+ {uniname2ctype_offset(str891), 435},
+ {-1}, {-1},
+ {uniname2ctype_offset(str894), 117},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str898), 275},
+ {-1}, {-1},
+ {uniname2ctype_offset(str901), 230},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str909), 152},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str919), 579},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str923), 139},
+ {uniname2ctype_offset(str924), 577},
+ {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str929), 531},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1},
+ {uniname2ctype_offset(str940), 149},
+ {-1},
+ {uniname2ctype_offset(str942), 538},
+ {-1},
+ {uniname2ctype_offset(str944), 273},
+ {uniname2ctype_offset(str945), 152},
+ {-1},
+ {uniname2ctype_offset(str947), 270},
+ {-1},
+ {uniname2ctype_offset(str949), 177},
+ {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str954), 537},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1},
+ {uniname2ctype_offset(str966), 264},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str970), 95},
+ {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str975), 118},
+ {-1}, {-1},
+ {uniname2ctype_offset(str978), 507},
+ {-1},
+ {uniname2ctype_offset(str980), 346},
+ {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str985), 542},
+ {-1}, {-1},
+ {uniname2ctype_offset(str988), 581},
+ {-1},
+ {uniname2ctype_offset(str990), 541},
+ {uniname2ctype_offset(str991), 364},
+ {-1}, {-1},
+ {uniname2ctype_offset(str994), 151},
+ {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str999), 380},
+ {-1},
+ {uniname2ctype_offset(str1001), 188},
+ {-1},
+ {uniname2ctype_offset(str1003), 184},
+ {-1},
+ {uniname2ctype_offset(str1005), 560},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1009), 22},
+ {-1}, {-1},
+ {uniname2ctype_offset(str1012), 104},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1016), 57},
+ {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1021), 369},
+ {uniname2ctype_offset(str1022), 191},
+ {-1},
+ {uniname2ctype_offset(str1024), 556},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1028), 278},
+ {-1},
+ {uniname2ctype_offset(str1030), 151},
+ {uniname2ctype_offset(str1031), 188},
+ {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1036), 78},
+ {uniname2ctype_offset(str1037), 647},
+ {uniname2ctype_offset(str1038), 546},
+ {-1},
+ {uniname2ctype_offset(str1040), 608},
+ {uniname2ctype_offset(str1041), 96},
+ {uniname2ctype_offset(str1042), 279},
+ {-1},
+ {uniname2ctype_offset(str1044), 408},
+ {uniname2ctype_offset(str1045), 457},
+ {-1}, {-1},
+ {uniname2ctype_offset(str1048), 515},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1056), 253},
+ {uniname2ctype_offset(str1057), 56},
+ {uniname2ctype_offset(str1058), 352},
+ {uniname2ctype_offset(str1059), 97},
+ {-1},
+ {uniname2ctype_offset(str1061), 466},
+ {-1}, {-1},
+ {uniname2ctype_offset(str1064), 249},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1068), 160},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1072), 236},
+ {uniname2ctype_offset(str1073), 378},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1077), 86},
+ {-1},
+ {uniname2ctype_offset(str1079), 153},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1087), 464},
+ {-1}, {-1},
+ {uniname2ctype_offset(str1090), 108},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1094), 630},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1102), 29},
+ {-1}, {-1},
+ {uniname2ctype_offset(str1105), 138},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1109), 86},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1113), 213},
+ {-1},
+ {uniname2ctype_offset(str1115), 153},
+ {-1},
+ {uniname2ctype_offset(str1117), 603},
+#ifndef USE_UNICODE_AGE_PROPERTIES
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+#else /* USE_UNICODE_AGE_PROPERTIES */
+ {-1}, {-1},
+ {uniname2ctype_offset(str1120), 316},
+ {uniname2ctype_offset(str1121), 315},
+ {uniname2ctype_offset(str1122), 318},
+ {uniname2ctype_offset(str1123), 317},
+ {-1},
+ {uniname2ctype_offset(str1125), 297},
+#endif /* USE_UNICODE_AGE_PROPERTIES */
+ {uniname2ctype_offset(str1126), 467},
+ {uniname2ctype_offset(str1127), 204},
+#ifndef USE_UNICODE_AGE_PROPERTIES
+ {-1}, {-1}, {-1},
+#else /* USE_UNICODE_AGE_PROPERTIES */
+ {uniname2ctype_offset(str1128), 299},
+ {uniname2ctype_offset(str1129), 298},
+ {uniname2ctype_offset(str1130), 320},
+#endif /* USE_UNICODE_AGE_PROPERTIES */
+ {uniname2ctype_offset(str1131), 236},
+ {uniname2ctype_offset(str1132), 255},
+ {uniname2ctype_offset(str1133), 344},
+#ifndef USE_UNICODE_AGE_PROPERTIES
+ {-1}, {-1}, {-1},
+#else /* USE_UNICODE_AGE_PROPERTIES */
+ {uniname2ctype_offset(str1134), 324},
+ {uniname2ctype_offset(str1135), 304},
+ {uniname2ctype_offset(str1136), 303},
+#endif /* USE_UNICODE_AGE_PROPERTIES */
+ {uniname2ctype_offset(str1137), 99},
+#ifndef USE_UNICODE_AGE_PROPERTIES
+ {-1}, {-1}, {-1},
+#else /* USE_UNICODE_AGE_PROPERTIES */
+ {uniname2ctype_offset(str1138), 322},
+ {uniname2ctype_offset(str1139), 321},
+ {uniname2ctype_offset(str1140), 312},
+#endif /* USE_UNICODE_AGE_PROPERTIES */
+ {uniname2ctype_offset(str1141), 400},
+#ifndef USE_UNICODE_AGE_PROPERTIES
+ {-1},
+#else /* USE_UNICODE_AGE_PROPERTIES */
+ {uniname2ctype_offset(str1142), 314},
+#endif /* USE_UNICODE_AGE_PROPERTIES */
+ {uniname2ctype_offset(str1143), 413},
+#ifndef USE_UNICODE_AGE_PROPERTIES
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+#else /* USE_UNICODE_AGE_PROPERTIES */
+ {uniname2ctype_offset(str1144), 306},
+ {uniname2ctype_offset(str1145), 305},
+ {uniname2ctype_offset(str1146), 323},
+ {uniname2ctype_offset(str1147), 307},
+ {uniname2ctype_offset(str1148), 313},
+ {-1},
+ {uniname2ctype_offset(str1150), 319},
+ {uniname2ctype_offset(str1151), 309},
+ {uniname2ctype_offset(str1152), 308},
+ {-1},
+ {uniname2ctype_offset(str1154), 310},
+ {uniname2ctype_offset(str1155), 301},
+ {uniname2ctype_offset(str1156), 300},
+ {-1},
+ {uniname2ctype_offset(str1158), 302},
+#endif /* USE_UNICODE_AGE_PROPERTIES */
+ {uniname2ctype_offset(str1159), 653},
+ {uniname2ctype_offset(str1160), 171},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1170), 99},
+ {-1},
+ {uniname2ctype_offset(str1172), 163},
+ {-1}, {-1},
+ {uniname2ctype_offset(str1175), 436},
+ {uniname2ctype_offset(str1176), 189},
+#ifndef USE_UNICODE_AGE_PROPERTIES
+ {-1}, {-1}, {-1}, {-1}, {-1},
+#else /* USE_UNICODE_AGE_PROPERTIES */
+ {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1181), 311},
+#endif /* USE_UNICODE_AGE_PROPERTIES */
+ {uniname2ctype_offset(str1182), 290},
+ {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1187), 280},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1191), 407},
+ {uniname2ctype_offset(str1192), 272},
+ {-1}, {-1},
+ {uniname2ctype_offset(str1195), 148},
+ {uniname2ctype_offset(str1196), 513},
+ {-1}, {-1},
+ {uniname2ctype_offset(str1199), 42},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1209), 496},
+ {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1214), 510},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1221), 183},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1225), 11},
+ {-1}, {-1},
+ {uniname2ctype_offset(str1228), 3},
+ {uniname2ctype_offset(str1229), 161},
+ {uniname2ctype_offset(str1230), 69},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1239), 545},
+ {-1},
+ {uniname2ctype_offset(str1241), 72},
+ {uniname2ctype_offset(str1242), 109},
+ {uniname2ctype_offset(str1243), 283},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1249), 130},
+ {-1},
+ {uniname2ctype_offset(str1251), 384},
+ {uniname2ctype_offset(str1252), 183},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1259), 218},
+ {uniname2ctype_offset(str1260), 636},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1264), 421},
+ {uniname2ctype_offset(str1265), 75},
+ {-1},
+ {uniname2ctype_offset(str1267), 156},
+ {-1},
+ {uniname2ctype_offset(str1269), 555},
+ {-1}, {-1},
+ {uniname2ctype_offset(str1272), 376},
+ {-1}, {-1},
+ {uniname2ctype_offset(str1275), 208},
+ {-1},
+ {uniname2ctype_offset(str1277), 115},
+ {-1},
+ {uniname2ctype_offset(str1279), 238},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1285), 73},
+ {uniname2ctype_offset(str1286), 204},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1292), 523},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1299), 261},
+ {-1},
+ {uniname2ctype_offset(str1301), 33},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1},
+ {uniname2ctype_offset(str1312), 185},
+ {-1}, {-1},
+ {uniname2ctype_offset(str1315), 199},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1321), 657},
+ {-1}, {-1},
+ {uniname2ctype_offset(str1324), 124},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1328), 240},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1332), 102},
+ {-1},
+ {uniname2ctype_offset(str1334), 166},
+ {uniname2ctype_offset(str1335), 387},
+ {uniname2ctype_offset(str1336), 645},
+ {-1}, {-1},
+ {uniname2ctype_offset(str1339), 136},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1347), 590},
+ {-1},
+ {uniname2ctype_offset(str1349), 363},
+ {uniname2ctype_offset(str1350), 361},
+ {uniname2ctype_offset(str1351), 232},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1357), 70},
+ {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1362), 566},
+ {uniname2ctype_offset(str1363), 562},
+ {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1368), 40},
+ {-1},
+ {uniname2ctype_offset(str1370), 528},
+ {uniname2ctype_offset(str1371), 395},
+ {uniname2ctype_offset(str1372), 69},
+ {-1}, {-1},
+ {uniname2ctype_offset(str1375), 70},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1397), 632},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1401), 505},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1407), 607},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1415), 680},
+ {uniname2ctype_offset(str1416), 399},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1420), 180},
+ {uniname2ctype_offset(str1421), 136},
+ {-1},
+ {uniname2ctype_offset(str1423), 292},
+ {-1},
+ {uniname2ctype_offset(str1425), 521},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1429), 385},
+ {uniname2ctype_offset(str1430), 190},
+ {-1}, {-1},
+ {uniname2ctype_offset(str1433), 212},
+ {-1},
+ {uniname2ctype_offset(str1435), 598},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1},
+ {uniname2ctype_offset(str1447), 169},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1453), 615},
+ {-1}, {-1},
+ {uniname2ctype_offset(str1456), 100},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1462), 519},
+ {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1467), 654},
+ {-1}, {-1},
+ {uniname2ctype_offset(str1470), 95},
+ {-1}, {-1},
+ {uniname2ctype_offset(str1473), 178},
+ {uniname2ctype_offset(str1474), 393},
+ {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1479), 293},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1489), 625},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1497), 424},
+ {uniname2ctype_offset(str1498), 410},
+ {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1503), 100},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1510), 339},
+ {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1515), 115},
+ {uniname2ctype_offset(str1516), 92},
+ {uniname2ctype_offset(str1517), 504},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1},
+ {uniname2ctype_offset(str1528), 585},
+ {-1},
+ {uniname2ctype_offset(str1530), 50},
+ {-1},
+ {uniname2ctype_offset(str1532), 389},
+ {-1}, {-1},
+ {uniname2ctype_offset(str1535), 462},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1551), 294},
+ {uniname2ctype_offset(str1552), 638},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1},
+ {uniname2ctype_offset(str1572), 4},
+ {uniname2ctype_offset(str1573), 133},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1581), 517},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1588), 552},
+ {uniname2ctype_offset(str1589), 426},
+ {uniname2ctype_offset(str1590), 164},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1598), 567},
+ {-1},
+ {uniname2ctype_offset(str1600), 599},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1606), 134},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1614), 293},
+ {uniname2ctype_offset(str1615), 635},
+ {-1}, {-1},
+ {uniname2ctype_offset(str1618), 605},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1626), 241},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1633), 357},
+ {uniname2ctype_offset(str1634), 25},
+ {-1},
+ {uniname2ctype_offset(str1636), 296},
+ {-1}, {-1},
+ {uniname2ctype_offset(str1639), 446},
+ {uniname2ctype_offset(str1640), 124},
+ {uniname2ctype_offset(str1641), 105},
+ {uniname2ctype_offset(str1642), 261},
+ {-1},
+ {uniname2ctype_offset(str1644), 634},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1648), 580},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1654), 460},
+ {uniname2ctype_offset(str1655), 167},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1668), 663},
+ {uniname2ctype_offset(str1669), 530},
+ {uniname2ctype_offset(str1670), 17},
+ {uniname2ctype_offset(str1671), 479},
+ {-1}, {-1},
+ {uniname2ctype_offset(str1674), 85},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1682), 112},
+ {-1},
+ {uniname2ctype_offset(str1684), 569},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1688), 193},
+ {-1},
+ {uniname2ctype_offset(str1690), 432},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1694), 112},
+ {-1},
+ {uniname2ctype_offset(str1696), 244},
+ {uniname2ctype_offset(str1697), 475},
+ {uniname2ctype_offset(str1698), 586},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1707), 637},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1713), 527},
+ {uniname2ctype_offset(str1714), 108},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1724), 215},
+ {-1}, {-1},
+ {uniname2ctype_offset(str1727), 256},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1731), 411},
+ {-1},
+ {uniname2ctype_offset(str1733), 658},
+ {-1},
+ {uniname2ctype_offset(str1735), 664},
+ {-1},
+ {uniname2ctype_offset(str1737), 470},
+ {uniname2ctype_offset(str1738), 106},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1746), 91},
+ {-1},
+ {uniname2ctype_offset(str1748), 148},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1754), 211},
+ {uniname2ctype_offset(str1755), 144},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1762), 200},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1},
+ {uniname2ctype_offset(str1773), 217},
+ {-1},
+ {uniname2ctype_offset(str1775), 252},
+ {-1}, {-1},
+ {uniname2ctype_offset(str1778), 274},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1785), 137},
+ {-1},
+ {uniname2ctype_offset(str1787), 549},
+ {-1}, {-1},
+ {uniname2ctype_offset(str1790), 243},
+ {-1}, {-1},
+ {uniname2ctype_offset(str1793), 594},
+ {-1}, {-1},
+ {uniname2ctype_offset(str1796), 175},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1800), 47},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1},
+ {uniname2ctype_offset(str1811), 217},
+ {uniname2ctype_offset(str1812), 128},
+ {-1},
+ {uniname2ctype_offset(str1814), 360},
+ {-1},
+ {uniname2ctype_offset(str1816), 21},
+ {-1},
+ {uniname2ctype_offset(str1818), 88},
+ {uniname2ctype_offset(str1819), 83},
+ {-1},
+ {uniname2ctype_offset(str1821), 83},
+ {-1}, {-1},
+ {uniname2ctype_offset(str1824), 661},
+ {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1829), 404},
+ {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1834), 132},
+ {-1},
+ {uniname2ctype_offset(str1836), 409},
+ {-1}, {-1},
+ {uniname2ctype_offset(str1839), 144},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1847), 234},
+ {uniname2ctype_offset(str1848), 118},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1854), 237},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1858), 514},
+ {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1863), 85},
+ {uniname2ctype_offset(str1864), 64},
+ {-1}, {-1},
+ {uniname2ctype_offset(str1867), 349},
+ {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1872), 107},
+ {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1877), 572},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1884), 626},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1900), 129},
+ {uniname2ctype_offset(str1901), 66},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1910), 345},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1920), 16},
+ {-1}, {-1},
+ {uniname2ctype_offset(str1923), 553},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1936), 629},
+ {uniname2ctype_offset(str1937), 58},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1941), 197},
+ {-1},
+ {uniname2ctype_offset(str1943), 374},
+ {-1},
+ {uniname2ctype_offset(str1945), 362},
+ {-1},
+ {uniname2ctype_offset(str1947), 292},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1956), 563},
+ {-1},
+ {uniname2ctype_offset(str1958), 180},
+ {-1},
+ {uniname2ctype_offset(str1960), 174},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1966), 473},
+ {-1}, {-1},
+ {uniname2ctype_offset(str1969), 92},
+ {-1}, {-1},
+ {uniname2ctype_offset(str1972), 584},
+ {-1},
+ {uniname2ctype_offset(str1974), 492},
+ {uniname2ctype_offset(str1975), 102},
+ {-1},
+ {uniname2ctype_offset(str1977), 534},
+ {uniname2ctype_offset(str1978), 367},
+ {uniname2ctype_offset(str1979), 110},
+ {uniname2ctype_offset(str1980), 221},
+ {-1}, {-1},
+ {uniname2ctype_offset(str1983), 450},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1987), 558},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2001), 417},
+ {uniname2ctype_offset(str2002), 249},
+ {-1}, {-1},
+ {uniname2ctype_offset(str2005), 383},
+ {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2010), 206},
+ {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2015), 557},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2022), 624},
+ {uniname2ctype_offset(str2023), 291},
+ {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2028), 669},
+ {uniname2ctype_offset(str2029), 174},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2037), 184},
+ {-1}, {-1},
+ {uniname2ctype_offset(str2040), 502},
+ {uniname2ctype_offset(str2041), 206},
+ {uniname2ctype_offset(str2042), 155},
+ {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2047), 216},
+ {-1},
+ {uniname2ctype_offset(str2049), 347},
+ {-1},
+ {uniname2ctype_offset(str2051), 41},
+ {-1},
+ {uniname2ctype_offset(str2053), 447},
+ {-1}, {-1},
+ {uniname2ctype_offset(str2056), 398},
+ {-1}, {-1},
+ {uniname2ctype_offset(str2059), 44},
+ {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2064), 109},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2074), 207},
+ {-1},
+ {uniname2ctype_offset(str2076), 141},
+ {uniname2ctype_offset(str2077), 498},
+ {uniname2ctype_offset(str2078), 272},
+ {-1},
+ {uniname2ctype_offset(str2080), 284},
+ {uniname2ctype_offset(str2081), 123},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2085), 459},
+ {-1},
+ {uniname2ctype_offset(str2087), 231},
+ {-1}, {-1},
+ {uniname2ctype_offset(str2090), 165},
+ {-1},
+ {uniname2ctype_offset(str2092), 145},
+ {uniname2ctype_offset(str2093), 652},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2097), 19},
+ {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2102), 132},
+ {-1},
+ {uniname2ctype_offset(str2104), 392},
+ {-1}, {-1},
+ {uniname2ctype_offset(str2107), 29},
+ {-1}, {-1},
+ {uniname2ctype_offset(str2110), 469},
+ {uniname2ctype_offset(str2111), 210},
+ {-1},
+ {uniname2ctype_offset(str2113), 116},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2117), 225},
+ {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2122), 226},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2131), 46},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2137), 166},
+ {uniname2ctype_offset(str2138), 66},
+ {-1},
+ {uniname2ctype_offset(str2140), 117},
+ {-1},
+ {uniname2ctype_offset(str2142), 210},
+ {uniname2ctype_offset(str2143), 81},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2147), 266},
+ {uniname2ctype_offset(str2148), 559},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2152), 202},
+ {uniname2ctype_offset(str2153), 224},
+ {-1},
+ {uniname2ctype_offset(str2155), 337},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2164), 107},
+ {uniname2ctype_offset(str2165), 64},
+ {-1}, {-1},
+ {uniname2ctype_offset(str2168), 452},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2176), 483},
+ {-1}, {-1},
+ {uniname2ctype_offset(str2179), 616},
+ {-1}, {-1},
+ {uniname2ctype_offset(str2182), 285},
+ {uniname2ctype_offset(str2183), 170},
+ {-1}, {-1},
+ {uniname2ctype_offset(str2186), 61},
+ {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2191), 593},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2199), 471},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2203), 576},
+ {uniname2ctype_offset(str2204), 438},
+ {-1},
+ {uniname2ctype_offset(str2206), 7},
+ {uniname2ctype_offset(str2207), 173},
+ {-1},
+ {uniname2ctype_offset(str2209), 334},
+ {-1},
+ {uniname2ctype_offset(str2211), 336},
+ {-1}, {-1},
+ {uniname2ctype_offset(str2214), 649},
+ {-1},
+ {uniname2ctype_offset(str2216), 543},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2224), 219},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2228), 214},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2235), 262},
+ {-1},
+ {uniname2ctype_offset(str2237), 619},
+ {-1},
+ {uniname2ctype_offset(str2239), 281},
+ {-1},
+ {uniname2ctype_offset(str2241), 251},
+ {-1},
+ {uniname2ctype_offset(str2243), 265},
+ {uniname2ctype_offset(str2244), 621},
+ {-1}, {-1},
+ {uniname2ctype_offset(str2247), 213},
+ {uniname2ctype_offset(str2248), 622},
+ {uniname2ctype_offset(str2249), 495},
+ {-1}, {-1},
+ {uniname2ctype_offset(str2252), 36},
+ {-1},
+ {uniname2ctype_offset(str2254), 620},
+ {uniname2ctype_offset(str2255), 271},
+ {-1},
+ {uniname2ctype_offset(str2257), 250},
+ {-1}, {-1},
+ {uniname2ctype_offset(str2260), 6},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2270), 134},
+ {-1},
+ {uniname2ctype_offset(str2272), 375},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2279), 428},
+ {-1},
+ {uniname2ctype_offset(str2281), 484},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2285), 430},
+ {-1}, {-1},
+ {uniname2ctype_offset(str2288), 379},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2296), 22},
+ {-1}, {-1},
+ {uniname2ctype_offset(str2299), 582},
+ {-1}, {-1},
+ {uniname2ctype_offset(str2302), 283},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2308), 287},
+ {uniname2ctype_offset(str2309), 226},
+ {uniname2ctype_offset(str2310), 234},
+ {-1},
+ {uniname2ctype_offset(str2312), 497},
+ {uniname2ctype_offset(str2313), 405},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2317), 491},
+ {-1}, {-1},
+ {uniname2ctype_offset(str2320), 225},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1},
+ {uniname2ctype_offset(str2341), 377},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2345), 73},
+ {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2350), 618},
+ {-1}, {-1},
+ {uniname2ctype_offset(str2353), 214},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2361), 263},
+ {-1}, {-1},
+ {uniname2ctype_offset(str2364), 240},
+ {-1},
+ {uniname2ctype_offset(str2366), 224},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2370), 198},
+ {uniname2ctype_offset(str2371), 406},
+ {-1},
+ {uniname2ctype_offset(str2373), 122},
+ {uniname2ctype_offset(str2374), 494},
+ {uniname2ctype_offset(str2375), 676},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2379), 651},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2389), 186},
+ {-1}, {-1},
+ {uniname2ctype_offset(str2392), 656},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2396), 329},
+ {uniname2ctype_offset(str2397), 325},
+ {uniname2ctype_offset(str2398), 9},
+ {-1}, {-1},
+ {uniname2ctype_offset(str2401), 122},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2416), 295},
+ {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2421), 682},
+ {uniname2ctype_offset(str2422), 665},
+ {-1},
+ {uniname2ctype_offset(str2424), 41},
+ {-1}, {-1},
+ {uniname2ctype_offset(str2427), 683},
+ {uniname2ctype_offset(str2428), 684},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2432), 681},
+ {uniname2ctype_offset(str2433), 474},
+ {uniname2ctype_offset(str2434), 169},
+ {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2439), 486},
+ {uniname2ctype_offset(str2440), 49},
+ {-1}, {-1},
+ {uniname2ctype_offset(str2443), 104},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2451), 268},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2458), 40},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2466), 72},
+ {-1},
+ {uniname2ctype_offset(str2468), 229},
+ {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2473), 490},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2483), 245},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2491), 512},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2495), 277},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2503), 26},
+ {-1},
+ {uniname2ctype_offset(str2505), 167},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2518), 111},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2526), 388},
+ {-1},
+ {uniname2ctype_offset(str2528), 223},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2532), 195},
+ {-1},
+ {uniname2ctype_offset(str2534), 133},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2541), 461},
+ {-1},
+ {uniname2ctype_offset(str2543), 30},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2553), 522},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2570), 43},
+ {uniname2ctype_offset(str2571), 440},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2577), 463},
+ {-1},
+ {uniname2ctype_offset(str2579), 268},
+ {-1},
+ {uniname2ctype_offset(str2581), 31},
+ {uniname2ctype_offset(str2582), 222},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2590), 610},
+ {uniname2ctype_offset(str2591), 366},
+ {uniname2ctype_offset(str2592), 592},
+ {uniname2ctype_offset(str2593), 332},
+ {-1}, {-1},
+ {uniname2ctype_offset(str2596), 536},
+ {-1}, {-1},
+ {uniname2ctype_offset(str2599), 328},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2603), 276},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2612), 666},
+ {uniname2ctype_offset(str2613), 201},
+ {uniname2ctype_offset(str2614), 245},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2618), 24},
+ {uniname2ctype_offset(str2619), 222},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2625), 88},
+ {uniname2ctype_offset(str2626), 221},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2632), 62},
+ {uniname2ctype_offset(str2633), 573},
+ {uniname2ctype_offset(str2634), 156},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2658), 246},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2668), 246},
+ {-1}, {-1},
+ {uniname2ctype_offset(str2671), 441},
+ {uniname2ctype_offset(str2672), 49},
+ {uniname2ctype_offset(str2673), 106},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2679), 229},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2688), 382},
+ {uniname2ctype_offset(str2689), 259},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2699), 386},
+ {uniname2ctype_offset(str2700), 20},
+ {uniname2ctype_offset(str2701), 181},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2705), 295},
+ {-1}, {-1},
+ {uniname2ctype_offset(str2708), 78},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2714), 401},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1},
+ {uniname2ctype_offset(str2725), 126},
+ {uniname2ctype_offset(str2726), 116},
+ {-1},
+ {uniname2ctype_offset(str2728), 282},
+ {uniname2ctype_offset(str2729), 231},
+ {-1}, {-1},
+ {uniname2ctype_offset(str2732), 252},
+ {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2737), 101},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2764), 81},
+ {uniname2ctype_offset(str2765), 326},
+ {-1},
+ {uniname2ctype_offset(str2767), 178},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2780), 330},
+ {-1},
+ {uniname2ctype_offset(str2782), 201},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2791), 451},
+ {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2796), 233},
+ {-1},
+ {uniname2ctype_offset(str2798), 39},
+ {uniname2ctype_offset(str2799), 641},
+ {uniname2ctype_offset(str2800), 45},
+ {uniname2ctype_offset(str2801), 54},
+ {uniname2ctype_offset(str2802), 219},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2806), 276},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2813), 207},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2819), 258},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2826), 87},
+ {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2831), 20},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2835), 168},
+ {uniname2ctype_offset(str2836), 149},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2844), 87},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2850), 146},
+ {-1},
+ {uniname2ctype_offset(str2852), 182},
+ {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2857), 412},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2861), 146},
+ {-1},
+ {uniname2ctype_offset(str2863), 481},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2869), 648},
+ {-1}, {-1},
+ {uniname2ctype_offset(str2872), 142},
+ {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2877), 121},
+ {uniname2ctype_offset(str2878), 485},
+ {-1}, {-1},
+ {uniname2ctype_offset(str2881), 525},
+ {-1},
+ {uniname2ctype_offset(str2883), 27},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1},
+ {uniname2ctype_offset(str2894), 5},
+ {-1}, {-1},
+ {uniname2ctype_offset(str2897), 547},
+ {-1}, {-1},
+ {uniname2ctype_offset(str2900), 35},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2910), 472},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1},
+ {uniname2ctype_offset(str2922), 145},
+ {-1}, {-1},
+ {uniname2ctype_offset(str2925), 176},
+ {uniname2ctype_offset(str2926), 445},
+ {-1},
+ {uniname2ctype_offset(str2928), 294},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2947), 140},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2953), 434},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2960), 220},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2970), 131},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2984), 179},
+ {-1},
+ {uniname2ctype_offset(str2986), 129},
+ {uniname2ctype_offset(str2987), 55},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2991), 604},
+ {-1},
+ {uniname2ctype_offset(str2993), 526},
+ {-1},
+ {uniname2ctype_offset(str2995), 583},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3005), 220},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3013), 254},
+ {-1},
+ {uniname2ctype_offset(str3015), 48},
+ {-1},
+ {uniname2ctype_offset(str3017), 223},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3021), 278},
+ {uniname2ctype_offset(str3022), 80},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3041), 62},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3049), 609},
+ {-1}, {-1},
+ {uniname2ctype_offset(str3052), 233},
+ {-1},
+ {uniname2ctype_offset(str3054), 65},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3061), 265},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3068), 449},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3078), 247},
+ {-1},
+ {uniname2ctype_offset(str3080), 258},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3086), 453},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3090), 439},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3097), 90},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3103), 286},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3107), 126},
+ {uniname2ctype_offset(str3108), 12},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3112), 251},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3121), 137},
+ {uniname2ctype_offset(str3122), 288},
+ {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3127), 90},
+ {uniname2ctype_offset(str3128), 121},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3137), 639},
+ {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3142), 103},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3165), 617},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3169), 437},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3177), 600},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3184), 135},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3188), 602},
+ {-1},
+ {uniname2ctype_offset(str3190), 601},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3221), 565},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3231), 455},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3238), 150},
+ {-1},
+ {uniname2ctype_offset(str3240), 131},
+ {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3245), 190},
+ {-1},
+ {uniname2ctype_offset(str3247), 37},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3257), 198},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3261), 52},
+ {-1},
+ {uniname2ctype_offset(str3263), 196},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3281), 238},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3287), 443},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3291), 65},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1},
+ {uniname2ctype_offset(str3302), 327},
+ {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3307), 254},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3326), 535},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3334), 42},
+ {uniname2ctype_offset(str3335), 285},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3357), 182},
+ {-1},
+ {uniname2ctype_offset(str3359), 142},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3363), 163},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3407), 642},
+ {uniname2ctype_offset(str3408), 675},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3414), 458},
+ {-1},
+ {uniname2ctype_offset(str3416), 679},
+ {-1},
+ {uniname2ctype_offset(str3418), 101},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3426), 456},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3432), 670},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3436), 202},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3444), 488},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3469), 175},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1},
+ {uniname2ctype_offset(str3481), 162},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1},
+ {uniname2ctype_offset(str3493), 241},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3497), 34},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3505), 279},
+ {-1},
+ {uniname2ctype_offset(str3507), 280},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3516), 140},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3532), 141},
+ {-1}, {-1},
+ {uniname2ctype_offset(str3535), 673},
+ {uniname2ctype_offset(str3536), 208},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3543), 250},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3569), 671},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3579), 31},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3585), 216},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3598), 179},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3613), 135},
+ {uniname2ctype_offset(str3614), 63},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3622), 640},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3629), 23},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3647), 168},
+ {-1}, {-1},
+ {uniname2ctype_offset(str3650), 333},
+ {uniname2ctype_offset(str3651), 335},
+ {-1}, {-1},
+ {uniname2ctype_offset(str3654), 672},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1},
+ {uniname2ctype_offset(str3666), 93},
+ {-1}, {-1},
+ {uniname2ctype_offset(str3669), 500},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3686), 262},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3690), 296},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3699), 15},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3718), 119},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3733), 162},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3770), 275},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3778), 63},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3782), 150},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3813), 158},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3835), 197},
+ {uniname2ctype_offset(str3836), 51},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3869), 291},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3877), 235},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3894), 247},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3901), 33},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3918), 402},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3945), 269},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1},
+ {uniname2ctype_offset(str3965), 578},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3972), 266},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3981), 18},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3995), 38},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1},
+ {uniname2ctype_offset(str4007), 260},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1},
+ {uniname2ctype_offset(str4018), 442},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str4035), 2},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1},
+ {uniname2ctype_offset(str4064), 103},
+ {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str4069), 331},
+ {-1}, {-1},
+ {uniname2ctype_offset(str4072), 32},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str4089), 119},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str4102), 170},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str4110), 89},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str4117), 260},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str4140), 196},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str4153), 289},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str4163), 45},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str4180), 235},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1},
+ {uniname2ctype_offset(str4228), 195},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str4318), 259},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str4353), 678},
+ {uniname2ctype_offset(str4354), 422},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1},
+ {uniname2ctype_offset(str4401), 286},
+ {-1}, {-1},
+ {uniname2ctype_offset(str4404), 267},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str4410), 242},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str4414), 287},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str4439), 28},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str4491), 43},
+ {-1}, {-1},
+ {uniname2ctype_offset(str4494), 257},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str4543), 487},
+ {uniname2ctype_offset(str4544), 8},
+ {uniname2ctype_offset(str4545), 267},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str4564), 674},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str4670), 39},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str4692), 677},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1},
+ {uniname2ctype_offset(str4731), 158},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str4775), 71},
+ {-1},
+ {uniname2ctype_offset(str4777), 257},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str4800), 46},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str4851), 274},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str4941), 80},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str4985), 269},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str5002), 633},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str5234), 59},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str5271), 74},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str5290), 228},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1},
+ {uniname2ctype_offset(str5329), 242},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1},
+ {uniname2ctype_offset(str5512), 185},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str5557), 10},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str5800), 30},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1},
+ {uniname2ctype_offset(str5919), 74},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str5981), 93},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str6036), 89},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str6068), 54}
+#endif /* USE_UNICODE_PROPERTIES */
+ };
+
+ if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
+ {
+ register unsigned int key = uniname2ctype_hash (str, len);
+
+ if (key <= MAX_HASH_VALUE)
+ {
+ register int o = wordlist[key].name;
+ if (o >= 0)
+ {
+ register const char *s = o + uniname2ctype_pool;
+
+ if (*str == *s && !strncmp (str + 1, s + 1, len - 1) && s[len] == '\0')
+ return &wordlist[key];
+ }
+ }
+ }
+ return 0;
+}
+
+static int
+uniname2ctype(const UChar *name, unsigned int len)
+{
+ const struct uniname2ctype_struct *p = uniname2ctype_p((const char *)name, len);
+ if (p) return p->ctype;
+ return -1;
+}
+#if defined ONIG_UNICODE_VERSION_STRING && !( \
+ ONIG_UNICODE_VERSION_MAJOR == 17 && \
+ ONIG_UNICODE_VERSION_MINOR == 0 && \
+ ONIG_UNICODE_VERSION_TEENY == 0 && \
+ 1)
+# error ONIG_UNICODE_VERSION_STRING mismatch
+#endif
+#define ONIG_UNICODE_VERSION_STRING "17.0.0"
+#define ONIG_UNICODE_VERSION_MAJOR 17
+#define ONIG_UNICODE_VERSION_MINOR 0
+#define ONIG_UNICODE_VERSION_TEENY 0
+#if defined ONIG_UNICODE_EMOJI_VERSION_STRING && !( \
+ ONIG_UNICODE_EMOJI_VERSION_MAJOR == 17 && \
+ ONIG_UNICODE_EMOJI_VERSION_MINOR == 0 && \
+ 1)
+# error ONIG_UNICODE_EMOJI_VERSION_STRING mismatch
+#endif
+#define ONIG_UNICODE_EMOJI_VERSION_STRING "17.0"
+#define ONIG_UNICODE_EMOJI_VERSION_MAJOR 17
+#define ONIG_UNICODE_EMOJI_VERSION_MINOR 0
diff --git a/enc/us_ascii.c b/enc/us_ascii.c
index 08f9072c43..253ee69572 100644
--- a/enc/us_ascii.c
+++ b/enc/us_ascii.c
@@ -32,7 +32,11 @@ OnigEncodingDefine(us_ascii, US_ASCII) = {
onigenc_not_support_get_ctype_code_range,
onigenc_single_byte_left_adjust_char_head,
onigenc_always_true_is_allowed_reverse_match,
+#ifdef USE_CASE_MAP_API
onigenc_single_byte_ascii_only_case_map,
+#else
+ NULL,
+#endif
ENCINDEX_US_ASCII,
ONIGENC_FLAG_NONE,
};
diff --git a/enc/utf_16be.c b/enc/utf_16be.c
index f9dd7119d6..0086040b5d 100644
--- a/enc/utf_16be.c
+++ b/enc/utf_16be.c
@@ -249,7 +249,11 @@ OnigEncodingDefine(utf_16be, UTF_16BE) = {
onigenc_utf16_32_get_ctype_code_range,
utf16be_left_adjust_char_head,
onigenc_always_false_is_allowed_reverse_match,
+#ifdef USE_CASE_MAP_API
onigenc_unicode_case_map,
+#else
+ NULL,
+#endif
0,
ONIGENC_FLAG_UNICODE,
};
diff --git a/enc/utf_16le.c b/enc/utf_16le.c
index 2c8438d0be..ca0fce5387 100644
--- a/enc/utf_16le.c
+++ b/enc/utf_16le.c
@@ -242,7 +242,11 @@ OnigEncodingDefine(utf_16le, UTF_16LE) = {
onigenc_utf16_32_get_ctype_code_range,
utf16le_left_adjust_char_head,
onigenc_always_false_is_allowed_reverse_match,
+#ifdef USE_CASE_MAP_API
onigenc_unicode_case_map,
+#else
+ NULL,
+#endif
0,
ONIGENC_FLAG_UNICODE,
};
diff --git a/enc/utf_32be.c b/enc/utf_32be.c
index 17841e52a4..e05cfaf1b2 100644
--- a/enc/utf_32be.c
+++ b/enc/utf_32be.c
@@ -199,7 +199,11 @@ OnigEncodingDefine(utf_32be, UTF_32BE) = {
onigenc_utf16_32_get_ctype_code_range,
utf32be_left_adjust_char_head,
onigenc_always_false_is_allowed_reverse_match,
+#ifdef USE_CASE_MAP_API
onigenc_unicode_case_map,
+#else
+ NULL,
+#endif
0,
ONIGENC_FLAG_UNICODE,
};
diff --git a/enc/utf_32le.c b/enc/utf_32le.c
index 18b798f102..651efdcec5 100644
--- a/enc/utf_32le.c
+++ b/enc/utf_32le.c
@@ -199,7 +199,11 @@ OnigEncodingDefine(utf_32le, UTF_32LE) = {
onigenc_utf16_32_get_ctype_code_range,
utf32le_left_adjust_char_head,
onigenc_always_false_is_allowed_reverse_match,
+#ifdef USE_CASE_MAP_API
onigenc_unicode_case_map,
+#else
+ NULL,
+#endif
0,
ONIGENC_FLAG_UNICODE,
};
diff --git a/enc/utf_8.c b/enc/utf_8.c
index cdf2510d84..ae7c98469d 100644
--- a/enc/utf_8.c
+++ b/enc/utf_8.c
@@ -431,7 +431,11 @@ OnigEncodingDefine(utf_8, UTF_8) = {
get_ctype_code_range,
left_adjust_char_head,
onigenc_always_true_is_allowed_reverse_match,
+#ifdef USE_CASE_MAP_API
onigenc_unicode_case_map,
+#else
+ NULL,
+#endif
ENCINDEX_UTF_8,
ONIGENC_FLAG_UNICODE,
};
diff --git a/enc/windows_1250.c b/enc/windows_1250.c
index daf23e9d1e..d38d50a01d 100644
--- a/enc/windows_1250.c
+++ b/enc/windows_1250.c
@@ -190,6 +190,7 @@ cp1250_get_case_fold_codes_by_str(OnigCaseFoldType flag,
flag, p, end, items);
}
+#ifdef USE_CASE_MAP_API
static int
case_map(OnigCaseFoldType* flagP, const OnigUChar** pp,
const OnigUChar* end, OnigUChar* to, OnigUChar* to_end,
@@ -239,6 +240,7 @@ case_map(OnigCaseFoldType* flagP, const OnigUChar** pp,
*flagP = flags;
return (int )(to - to_start);
}
+#endif
OnigEncodingDefine(windows_1250, Windows_1250) = {
onigenc_single_byte_mbc_enc_len,
@@ -257,7 +259,11 @@ OnigEncodingDefine(windows_1250, Windows_1250) = {
onigenc_not_support_get_ctype_code_range,
onigenc_single_byte_left_adjust_char_head,
onigenc_always_true_is_allowed_reverse_match,
+#ifdef USE_CASE_MAP_API
case_map,
+#else
+ NULL,
+#endif
0,
ONIGENC_FLAG_NONE,
};
diff --git a/enc/windows_1251.c b/enc/windows_1251.c
index 6c892c1b8c..81641d0337 100644
--- a/enc/windows_1251.c
+++ b/enc/windows_1251.c
@@ -180,6 +180,7 @@ cp1251_get_case_fold_codes_by_str(OnigCaseFoldType flag,
flag, p, end, items);
}
+#ifdef USE_CASE_MAP_API
static int
case_map(OnigCaseFoldType* flagP, const OnigUChar** pp,
const OnigUChar* end, OnigUChar* to, OnigUChar* to_end,
@@ -221,6 +222,7 @@ case_map(OnigCaseFoldType* flagP, const OnigUChar** pp,
*flagP = flags;
return (int )(to - to_start);
}
+#endif
OnigEncodingDefine(windows_1251, Windows_1251) = {
onigenc_single_byte_mbc_enc_len,
@@ -239,7 +241,11 @@ OnigEncodingDefine(windows_1251, Windows_1251) = {
onigenc_not_support_get_ctype_code_range,
onigenc_single_byte_left_adjust_char_head,
onigenc_always_true_is_allowed_reverse_match,
+#ifdef USE_CASE_MAP_API
case_map,
+#else
+ NULL,
+#endif
0,
ONIGENC_FLAG_NONE,
};
diff --git a/enc/windows_1252.c b/enc/windows_1252.c
index b685878d3f..6aece95c0a 100644
--- a/enc/windows_1252.c
+++ b/enc/windows_1252.c
@@ -181,6 +181,7 @@ cp1252_get_case_fold_codes_by_str(OnigCaseFoldType flag,
flag, p, end, items);
}
+#ifdef USE_CASE_MAP_API
static int
case_map(OnigCaseFoldType* flagP, const OnigUChar** pp,
const OnigUChar* end, OnigUChar* to, OnigUChar* to_end,
@@ -228,6 +229,7 @@ case_map(OnigCaseFoldType* flagP, const OnigUChar** pp,
*flagP = flags;
return (int )(to - to_start);
}
+#endif
OnigEncodingDefine(windows_1252, Windows_1252) = {
onigenc_single_byte_mbc_enc_len,
@@ -246,7 +248,11 @@ OnigEncodingDefine(windows_1252, Windows_1252) = {
onigenc_not_support_get_ctype_code_range,
onigenc_single_byte_left_adjust_char_head,
onigenc_always_true_is_allowed_reverse_match,
+#ifdef USE_CASE_MAP_API
case_map,
+#else
+ NULL,
+#endif
0,
ONIGENC_FLAG_NONE,
};
diff --git a/enc/windows_1253.c b/enc/windows_1253.c
index b2a43581c3..c95ea3f41c 100644
--- a/enc/windows_1253.c
+++ b/enc/windows_1253.c
@@ -213,6 +213,7 @@ get_case_fold_codes_by_str(OnigCaseFoldType flag,
flag, p, end, items);
}
+#ifdef USE_CASE_MAP_API
static int
case_map(OnigCaseFoldType* flagP, const OnigUChar** pp,
const OnigUChar* end, OnigUChar* to, OnigUChar* to_end,
@@ -272,6 +273,7 @@ case_map(OnigCaseFoldType* flagP, const OnigUChar** pp,
*flagP = flags;
return (int )(to - to_start);
}
+#endif
OnigEncodingDefine(windows_1253, Windows_1253) = {
onigenc_single_byte_mbc_enc_len,
@@ -290,7 +292,11 @@ OnigEncodingDefine(windows_1253, Windows_1253) = {
onigenc_not_support_get_ctype_code_range,
onigenc_single_byte_left_adjust_char_head,
onigenc_always_true_is_allowed_reverse_match,
+#ifdef USE_CASE_MAP_API
case_map,
+#else
+ NULL,
+#endif
0,
ONIGENC_FLAG_NONE,
};
diff --git a/enc/windows_1254.c b/enc/windows_1254.c
index 5e6d92d3d2..c8d5991686 100644
--- a/enc/windows_1254.c
+++ b/enc/windows_1254.c
@@ -221,6 +221,7 @@ get_case_fold_codes_by_str(OnigCaseFoldType flag,
flag, p, end, items);
}
+#ifdef USE_CASE_MAP_API
#define DOTLESS_i (0xFD)
#define I_WITH_DOT_ABOVE (0xDD)
static int
@@ -277,6 +278,7 @@ case_map(OnigCaseFoldType* flagP, const OnigUChar** pp,
*flagP = flags;
return (int )(to - to_start);
}
+#endif
OnigEncodingDefine(windows_1254, Windows_1254) = {
onigenc_single_byte_mbc_enc_len,
@@ -295,7 +297,11 @@ OnigEncodingDefine(windows_1254, Windows_1254) = {
onigenc_not_support_get_ctype_code_range,
onigenc_single_byte_left_adjust_char_head,
onigenc_always_true_is_allowed_reverse_match,
+#ifdef USE_CASE_MAP_API
case_map,
+#else
+ NULL,
+#endif
0,
ONIGENC_FLAG_NONE,
};
diff --git a/enc/windows_1257.c b/enc/windows_1257.c
index ada03b72bf..def13c8c49 100644
--- a/enc/windows_1257.c
+++ b/enc/windows_1257.c
@@ -225,6 +225,7 @@ get_case_fold_codes_by_str(OnigCaseFoldType flag,
flag, p, end, items);
}
+#ifdef USE_CASE_MAP_API
#define DOTLESS_i (0xB9)
#define I_WITH_DOT_ABOVE (0xA9)
static int
@@ -279,6 +280,7 @@ case_map(OnigCaseFoldType* flagP, const OnigUChar** pp,
*flagP = flags;
return (int )(to - to_start);
}
+#endif
OnigEncodingDefine(windows_1257, Windows_1257) = {
onigenc_single_byte_mbc_enc_len,
@@ -297,7 +299,11 @@ OnigEncodingDefine(windows_1257, Windows_1257) = {
onigenc_not_support_get_ctype_code_range,
onigenc_single_byte_left_adjust_char_head,
onigenc_always_true_is_allowed_reverse_match,
+#ifdef USE_CASE_MAP_API
case_map,
+#else
+ NULL,
+#endif
0,
ONIGENC_FLAG_NONE,
};
diff --git a/enc/windows_31j.c b/enc/windows_31j.c
index 1eb859596a..cd8bd83fdd 100644
--- a/enc/windows_31j.c
+++ b/enc/windows_31j.c
@@ -48,7 +48,11 @@ OnigEncodingDefine(windows_31j, Windows_31J) = {
get_ctype_code_range,
left_adjust_char_head,
is_allowed_reverse_match,
+#ifdef USE_CASE_MAP_API
onigenc_ascii_only_case_map,
+#else
+ NULL,
+#endif
0,
ONIGENC_FLAG_NONE,
};
diff --git a/encoding.c b/encoding.c
index 2416acecea..c17f118eef 100644
--- a/encoding.c
+++ b/encoding.c
@@ -27,6 +27,7 @@
#include "ruby/atomic.h"
#include "ruby/encoding.h"
#include "ruby/util.h"
+#include "ruby/ractor.h"
#include "ruby_assert.h"
#include "vm_sync.h"
#include "ruby_atomic.h"
@@ -55,7 +56,7 @@ int rb_encdb_alias(const char *alias, const char *orig);
#pragma GCC visibility pop
#endif
-static ID id_encoding;
+static ID id_encoding, id_i_name;
VALUE rb_cEncoding;
#define ENCODING_LIST_CAPA 256
@@ -96,6 +97,9 @@ static rb_encoding *global_enc_ascii,
*global_enc_utf_8,
*global_enc_us_ascii;
+static int filesystem_encindex = ENCINDEX_ASCII_8BIT;
+static rb_atomic_t locale_alias_registered;
+
#define GLOBAL_ENC_TABLE_LOCKING(tbl) \
for (struct enc_table *tbl = &global_enc_table, **locking = &tbl; \
locking; \
@@ -122,8 +126,9 @@ static const rb_data_type_t encoding_data_type = {
0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED
};
-#define is_data_encoding(obj) (RTYPEDDATA_P(obj) && RTYPEDDATA_TYPE(obj) == &encoding_data_type)
-#define is_obj_encoding(obj) (RB_TYPE_P((obj), T_DATA) && is_data_encoding(obj))
+#define is_encoding_type(obj) (RTYPEDDATA_TYPE(obj) == &encoding_data_type)
+#define is_data_encoding(obj) is_encoding_type(obj)
+#define is_obj_encoding(obj) (rbimpl_obj_typeddata_p(obj) && is_encoding_type(obj))
int
rb_data_is_encoding(VALUE obj)
@@ -135,8 +140,8 @@ static VALUE
enc_new(rb_encoding *encoding)
{
VALUE enc = TypedData_Wrap_Struct(rb_cEncoding, &encoding_data_type, (void *)encoding);
- rb_obj_freeze(enc);
- FL_SET_RAW(enc, RUBY_FL_SHAREABLE);
+ rb_ivar_set(enc, id_i_name, rb_fstring_cstr(encoding->name));
+ RB_OBJ_SET_FROZEN_SHAREABLE(enc);
return enc;
}
@@ -152,6 +157,8 @@ enc_list_update(int index, rb_raw_encoding *encoding)
RBASIC_CLEAR_CLASS(new_list);
/* initialize encoding data */
rb_ary_store(new_list, index, enc_new(encoding));
+ rb_ary_freeze(new_list);
+ FL_SET_RAW(new_list, RUBY_FL_SHAREABLE);
RUBY_ATOMIC_VALUE_SET(rb_encoding_list, new_list);
}
}
@@ -220,7 +227,7 @@ enc_check_encoding(VALUE obj)
if (!is_obj_encoding(obj)) {
return -1;
}
- return check_encoding(RDATA(obj)->data);
+ return check_encoding(RTYPEDDATA_GET_DATA(obj));
}
NORETURN(static void not_encoding(VALUE enc));
@@ -238,7 +245,7 @@ must_encoding(VALUE enc)
if (index < 0) {
not_encoding(enc);
}
- return DATA_PTR(enc);
+ return RTYPEDDATA_GET_DATA(enc);
}
static rb_encoding *
@@ -326,7 +333,7 @@ str_to_encoding(VALUE enc)
rb_encoding *
rb_to_encoding(VALUE enc)
{
- if (enc_check_encoding(enc) >= 0) return RDATA(enc)->data;
+ if (enc_check_encoding(enc) >= 0) return RTYPEDDATA_GET_DATA(enc);
return str_to_encoding(enc);
}
@@ -334,7 +341,7 @@ rb_encoding *
rb_find_encoding(VALUE enc)
{
int idx;
- if (enc_check_encoding(enc) >= 0) return RDATA(enc)->data;
+ if (enc_check_encoding(enc) >= 0) return RTYPEDDATA_GET_DATA(enc);
idx = str_find_encindex(enc);
if (idx < 0) return NULL;
return rb_enc_from_index(idx);
@@ -349,6 +356,35 @@ enc_table_expand(struct enc_table *enc_table, int newsize)
return newsize;
}
+/* Load an encoding using the values from base_encoding */
+static void
+enc_load_from_base(struct enc_table *enc_table, int index, rb_encoding *base_encoding)
+{
+ ASSERT_vm_locking();
+
+ struct rb_encoding_entry *ent = &enc_table->list[index];
+
+ if (ent->loaded) {
+ return;
+ }
+
+ rb_raw_encoding *encoding = (rb_raw_encoding *)ent->enc;
+ RUBY_ASSERT(encoding);
+
+ // FIXME: Before the base is loaded, the encoding may be accessed
+ // concurrently by other Ractors.
+ // We're copying all fields from base_encoding except name and
+ // ruby_encoding_index which we preserve from the original. Since these are
+ // the only fields other threads should read it is likely safe despite
+ // technically being a data race.
+ rb_raw_encoding tmp_encoding = *base_encoding;
+ tmp_encoding.name = encoding->name;
+ tmp_encoding.ruby_encoding_index = encoding->ruby_encoding_index;
+ *encoding = tmp_encoding;
+
+ RUBY_ATOMIC_SET(ent->loaded, encoding->max_enc_len);
+}
+
static int
enc_register_at(struct enc_table *enc_table, int index, const char *name, rb_encoding *base_encoding)
{
@@ -357,33 +393,33 @@ enc_register_at(struct enc_table *enc_table, int index, const char *name, rb_enc
struct rb_encoding_entry *ent = &enc_table->list[index];
rb_raw_encoding *encoding;
- if (!valid_encoding_name_p(name)) return -1;
- if (!ent->name) {
- ent->name = name = strdup(name);
- }
- else if (STRCASECMP(name, ent->name)) {
- return -1;
- }
- encoding = (rb_raw_encoding *)ent->enc;
- if (!encoding) {
- encoding = xmalloc(sizeof(rb_encoding));
- }
+ RUBY_ASSERT(!ent->loaded);
+ RUBY_ASSERT(!ent->name);
+ RUBY_ASSERT(!ent->enc);
+ RUBY_ASSERT(!ent->base);
- if (base_encoding) {
- *encoding = *base_encoding;
- }
- else {
- memset(encoding, 0, sizeof(*ent->enc));
- }
+ RUBY_ASSERT(valid_encoding_name_p(name));
+
+ ent->name = name = strdup(name);
+
+ encoding = ZALLOC(rb_raw_encoding);
encoding->name = name;
encoding->ruby_encoding_index = index;
ent->enc = encoding;
- st_insert(enc_table->names, (st_data_t)name, (st_data_t)index);
+
+ if (st_insert(enc_table->names, (st_data_t)name, (st_data_t)index)) {
+ rb_bug("encoding name was somehow registered twice");
+ }
enc_list_update(index, encoding);
- // max_enc_len is used to mark a fully loaded encoding.
- RUBY_ATOMIC_SET(ent->loaded, encoding->max_enc_len);
+ if (base_encoding) {
+ enc_load_from_base(enc_table, index, base_encoding);
+ }
+ else {
+ /* it should not be loaded yet */
+ RUBY_ASSERT(!encoding->max_enc_len);
+ }
return index;
}
@@ -393,6 +429,8 @@ enc_register(struct enc_table *enc_table, const char *name, rb_encoding *encodin
{
ASSERT_vm_locking();
+ if (!valid_encoding_name_p(name)) return -1;
+
int index = enc_table->count;
enc_table->count = enc_table_expand(enc_table, index + 1);
@@ -408,7 +446,9 @@ enc_from_index(struct enc_table *enc_table, int index)
if (UNLIKELY(index < 0 || enc_table->count <= (index &= ENC_INDEX_MASK))) {
return 0;
}
- return enc_table->list[index].enc;
+ rb_encoding *enc = enc_table->list[index].enc;
+ RUBY_ASSERT(ENC_TO_ENCINDEX(enc) == index);
+ return enc;
}
rb_encoding *
@@ -431,7 +471,7 @@ rb_enc_register(const char *name, rb_encoding *encoding)
index = enc_register(enc_table, name, encoding);
}
else if (rb_enc_autoload_p(oldenc) || !ENC_DUMMY_P(oldenc)) {
- enc_register_at(enc_table, index, name, encoding);
+ enc_load_from_base(enc_table, index, encoding);
}
else {
rb_raise(rb_eArgError, "encoding %s is already registered", name);
@@ -548,7 +588,7 @@ enc_replicate_with_index(struct enc_table *enc_table, const char *name, rb_encod
idx = enc_register(enc_table, name, origenc);
}
else {
- idx = enc_register_at(enc_table, idx, name, origenc);
+ enc_load_from_base(enc_table, idx, origenc);
}
if (idx >= 0) {
set_base_encoding(enc_table, idx, origenc);
@@ -802,41 +842,28 @@ enc_autoload_body(rb_encoding *enc)
GLOBAL_ENC_TABLE_LOCKING(enc_table) {
base = enc_table->list[ENC_TO_ENCINDEX(enc)].base;
- if (base) {
- do {
- if (i >= enc_table->count) {
- i = -1;
- break;
- }
- } while (enc_table->list[i].enc != base && (++i, 1));
- }
}
-
- if (i != -1) {
- if (base) {
- bool do_register = true;
- if (rb_enc_autoload_p(base)) {
- if (rb_enc_autoload(base) < 0) {
- do_register = false;
- i = -1;
- }
+ if (base) {
+ bool do_register = true;
+ if (rb_enc_autoload_p(base)) {
+ if (rb_enc_autoload(base) < 0) {
+ do_register = false;
+ i = -1;
}
+ }
- if (do_register) {
- GLOBAL_ENC_TABLE_LOCKING(enc_table) {
- i = enc->ruby_encoding_index;
- enc_register_at(enc_table, i & ENC_INDEX_MASK, rb_enc_name(enc), base);
- ((rb_raw_encoding *)enc)->ruby_encoding_index = i;
- }
+ if (do_register) {
+ GLOBAL_ENC_TABLE_LOCKING(enc_table) {
+ i = ENC_TO_ENCINDEX(enc);
+ enc_load_from_base(enc_table, i, base);
+ RUBY_ASSERT(((rb_raw_encoding *)enc)->ruby_encoding_index == i);
}
-
- i &= ENC_INDEX_MASK;
- }
- else {
- i = -2;
}
}
+ else {
+ i = -2;
+ }
return i;
}
@@ -1320,10 +1347,10 @@ enc_inspect(VALUE self)
{
rb_encoding *enc;
- if (!is_data_encoding(self)) {
+ if (!is_obj_encoding(self)) { /* do not resolve autoload */
not_encoding(self);
}
- if (!(enc = DATA_PTR(self)) || rb_enc_from_index(rb_enc_to_index(enc)) != enc) {
+ if (!(enc = RTYPEDDATA_GET_DATA(self)) || rb_enc_from_index(rb_enc_to_index(enc)) != enc) {
rb_raise(rb_eTypeError, "broken Encoding");
}
@@ -1334,20 +1361,6 @@ enc_inspect(VALUE self)
rb_enc_autoload_p(enc) ? " (autoload)" : "");
}
-/*
- * call-seq:
- * enc.name -> string
- * enc.to_s -> string
- *
- * Returns the name of the encoding.
- *
- * Encoding::UTF_8.name #=> "UTF-8"
- */
-static VALUE
-enc_name(VALUE self)
-{
- return rb_fstring_cstr(rb_enc_name((rb_encoding*)DATA_PTR(self)));
-}
static int
enc_names_i(st_data_t name, st_data_t idx, st_data_t args)
@@ -1491,7 +1504,7 @@ static VALUE
enc_dump(int argc, VALUE *argv, VALUE self)
{
rb_check_arity(argc, 0, 1);
- return enc_name(self);
+ return rb_attr_get(self, id_i_name);
}
/* :nodoc: */
@@ -1556,15 +1569,16 @@ rb_locale_encindex(void)
if (idx < 0) idx = ENCINDEX_UTF_8;
- GLOBAL_ENC_TABLE_LOCKING(enc_table) {
- if (enc_registered(enc_table, "locale") < 0) {
+ if (!RUBY_ATOMIC_LOAD(locale_alias_registered)) {
+ GLOBAL_ENC_TABLE_LOCKING(enc_table) {
+ if (enc_registered(enc_table, "locale") < 0) {
# if defined _WIN32
- void Init_w32_codepage(void);
- Init_w32_codepage();
+ void Init_w32_codepage(void);
+ Init_w32_codepage();
# endif
- GLOBAL_ENC_TABLE_LOCKING(enc_table) {
enc_alias_internal(enc_table, "locale", idx);
}
+ RUBY_ATOMIC_SET(locale_alias_registered, 1);
}
}
@@ -1580,12 +1594,7 @@ rb_locale_encoding(void)
int
rb_filesystem_encindex(void)
{
- int idx;
- GLOBAL_ENC_TABLE_LOCKING(enc_table) {
- idx = enc_registered(enc_table, "filesystem");
- }
- if (idx < 0) idx = ENCINDEX_ASCII_8BIT;
- return idx;
+ return filesystem_encindex;
}
rb_encoding *
@@ -1637,7 +1646,9 @@ enc_set_default_encoding(struct default_encoding *def, VALUE encoding, const cha
}
if (def == &default_external) {
- enc_alias_internal(enc_table, "filesystem", Init_enc_set_filesystem_encoding());
+ int fs_idx = Init_enc_set_filesystem_encoding();
+ enc_alias_internal(enc_table, "filesystem", fs_idx);
+ filesystem_encindex = fs_idx;
}
}
@@ -1980,12 +1991,19 @@ Init_Encoding(void)
VALUE list;
int i;
+ id_i_name = rb_intern_const("@name");
rb_cEncoding = rb_define_class("Encoding", rb_cObject);
rb_define_alloc_func(rb_cEncoding, enc_s_alloc);
rb_undef_method(CLASS_OF(rb_cEncoding), "new");
- rb_define_method(rb_cEncoding, "to_s", enc_name, 0);
+
+ /* The name of the encoding.
+ *
+ * Encoding::UTF_8.name #=> "UTF-8"
+ */
+ rb_attr(rb_cEncoding, rb_intern("name"), TRUE, FALSE, Qfalse);
+ rb_define_alias(rb_cEncoding, "to_s", "name");
+
rb_define_method(rb_cEncoding, "inspect", enc_inspect, 0);
- rb_define_method(rb_cEncoding, "name", enc_name, 0);
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);
diff --git a/enum.c b/enum.c
index cbf74df484..a2941dd7dd 100644
--- a/enum.c
+++ b/enum.c
@@ -127,7 +127,7 @@ static VALUE
enum_grep0(VALUE obj, VALUE pat, VALUE test)
{
VALUE ary = rb_ary_new();
- struct MEMO *memo = MEMO_NEW(pat, ary, test);
+ struct MEMO *memo = rb_imemo_memo_new_value(pat, ary, test);
rb_block_call_func_t fn;
if (rb_block_given_p()) {
fn = grep_iter_i;
@@ -207,27 +207,32 @@ enum_grep_v(VALUE obj, VALUE pat)
return enum_grep0(obj, pat, Qfalse);
}
-#define COUNT_BIGNUM IMEMO_FL_USER0
-#define MEMO_V3_SET(m, v) RB_OBJ_WRITE((m), &(m)->u3.value, (v))
+static inline void
+MEMO_V3_SET(struct MEMO *m, VALUE v)
+{
+ RB_OBJ_WRITE(m, &m->u3.value, v);
+ m->flags |= MEMO_U3_IS_VALUE;
+}
static void
imemo_count_up(struct MEMO *memo)
{
- if (memo->flags & COUNT_BIGNUM) {
+ if (memo->flags & MEMO_U3_IS_VALUE) {
+ RUBY_ASSERT(RB_TYPE_P(memo->u3.value, T_BIGNUM));
MEMO_V3_SET(memo, rb_int_succ(memo->u3.value));
}
else if (++memo->u3.cnt == 0) {
/* overflow */
unsigned long buf[2] = {0, 1};
MEMO_V3_SET(memo, rb_big_unpack(buf, 2));
- memo->flags |= COUNT_BIGNUM;
}
}
static VALUE
imemo_count_value(struct MEMO *memo)
{
- if (memo->flags & COUNT_BIGNUM) {
+ if (memo->flags & MEMO_U3_IS_VALUE) {
+ RUBY_ASSERT(RB_TYPE_P(memo->u3.value, T_BIGNUM));
return memo->u3.value;
}
else {
@@ -317,7 +322,7 @@ enum_count(int argc, VALUE *argv, VALUE obj)
func = count_i;
}
- memo = MEMO_NEW(item, 0, 0);
+ memo = rb_imemo_memo_new(item, 0, 0);
rb_block_call(obj, id_each, 0, 0, func, (VALUE)memo);
return imemo_count_value(memo);
}
@@ -382,7 +387,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);
+ memo = rb_imemo_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
@@ -467,7 +472,7 @@ enum_find_index(int argc, VALUE *argv, VALUE obj)
func = find_index_i;
}
- memo = MEMO_NEW(Qnil, condition_value, 0);
+ memo = rb_imemo_memo_new(Qnil, condition_value, 0);
rb_block_call(obj, id_each, 0, 0, func, (VALUE)memo);
return memo->v1;
}
@@ -1084,7 +1089,7 @@ enum_inject(int argc, VALUE *argv, VALUE obj)
return ary_inject_op(obj, init, op);
}
- memo = MEMO_NEW(init, Qnil, op);
+ memo = rb_imemo_memo_new_value(init, Qnil, op);
rb_block_call(obj, id_each, 0, 0, iter, (VALUE)memo);
if (UNDEF_P(memo->v1)) return Qnil;
return memo->v1;
@@ -1142,7 +1147,7 @@ enum_partition(VALUE obj)
RETURN_SIZED_ENUMERATOR(obj, 0, 0, enum_size);
- memo = MEMO_NEW(rb_ary_new(), rb_ary_new(), 0);
+ memo = rb_imemo_memo_new(rb_ary_new(), rb_ary_new(), 0);
rb_block_call(obj, id_each, 0, 0, partition_i, (VALUE)memo);
return rb_assoc_new(memo->v1, memo->v2);
@@ -1345,7 +1350,7 @@ enum_first(int argc, VALUE *argv, VALUE obj)
return enum_take(obj, argv[0]);
}
else {
- memo = MEMO_NEW(Qnil, 0, 0);
+ memo = rb_imemo_memo_new(Qnil, 0, 0);
rb_block_call(obj, id_each, 0, 0, first_i, (VALUE)memo);
return memo->v1;
}
@@ -1722,7 +1727,7 @@ enum_sort_by(VALUE obj)
RBASIC_CLEAR_CLASS(ary);
buf = rb_ary_hidden_new(SORT_BY_BUFSIZE*2);
rb_ary_store(buf, SORT_BY_BUFSIZE*2-1, Qnil);
- memo = MEMO_NEW(0, 0, 0);
+ memo = rb_imemo_memo_new(0, 0, 0);
data = (struct sort_by_data *)&memo->v1;
RB_OBJ_WRITE(memo, &data->ary, ary);
RB_OBJ_WRITE(memo, &data->buf, buf);
@@ -1766,7 +1771,7 @@ enum_sort_by(VALUE obj)
#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 MEMO_ENUM_NEW(v1) (rb_check_arity(argc, 0, 1), rb_imemo_memo_new((v1), (argc ? *argv : 0), 0))
#define DEFINE_ENUMFUNCS(name) \
static VALUE enum_##name##_func(VALUE result, struct MEMO *memo); \
@@ -2754,7 +2759,7 @@ enum_min_by(int argc, VALUE *argv, VALUE obj)
if (argc && !NIL_P(num = argv[0]))
return rb_nmin_run(obj, num, 1, 0, 0);
- memo = MEMO_NEW(Qundef, Qnil, 0);
+ memo = rb_imemo_memo_new(Qundef, Qnil, 0);
rb_block_call(obj, id_each, 0, 0, min_by_i, (VALUE)memo);
return memo->v2;
}
@@ -2828,7 +2833,7 @@ enum_max_by(int argc, VALUE *argv, VALUE obj)
if (argc && !NIL_P(num = argv[0]))
return rb_nmin_run(obj, num, 1, 1, 0);
- memo = MEMO_NEW(Qundef, Qnil, 0);
+ memo = rb_imemo_memo_new(Qundef, Qnil, 0);
rb_block_call(obj, id_each, 0, 0, max_by_i, (VALUE)memo);
return memo->v2;
}
@@ -2979,7 +2984,7 @@ member_i(RB_BLOCK_CALL_FUNC_ARGLIST(iter, args))
static VALUE
enum_member(VALUE obj, VALUE val)
{
- struct MEMO *memo = MEMO_NEW(val, Qfalse, 0);
+ struct MEMO *memo = rb_imemo_memo_new(val, Qfalse, 0);
rb_block_call(obj, id_each, 0, 0, member_i, (VALUE)memo);
return memo->v2;
@@ -3231,7 +3236,7 @@ enum_each_slice(VALUE obj, VALUE n)
size = limit_by_enum_size(obj, size);
ary = rb_ary_new2(size);
arity = rb_block_arity();
- memo = MEMO_NEW(ary, dont_recycle_block_arg(arity), size);
+ memo = rb_imemo_memo_new(ary, dont_recycle_block_arg(arity), size);
rb_block_call(obj, id_each, 0, 0, each_slice_i, (VALUE)memo);
ary = memo->v1;
if (RARRAY_LEN(ary) > 0) rb_yield(ary);
@@ -3307,7 +3312,7 @@ enum_each_cons(VALUE obj, VALUE n)
RETURN_SIZED_ENUMERATOR(obj, 1, &n, enum_each_cons_size);
arity = rb_block_arity();
if (enum_size_over_p(obj, size)) return obj;
- memo = MEMO_NEW(rb_ary_new2(size), dont_recycle_block_arg(arity), size);
+ memo = rb_imemo_memo_new(rb_ary_new2(size), dont_recycle_block_arg(arity), size);
rb_block_call(obj, id_each, 0, 0, each_cons_i, (VALUE)memo);
return obj;
@@ -3536,7 +3541,7 @@ enum_zip(int argc, VALUE *argv, VALUE obj)
}
/* TODO: use NODE_DOT2 as memo(v, v, -) */
- memo = MEMO_NEW(result, args, 0);
+ memo = rb_imemo_memo_new(result, args, 0);
rb_block_call(obj, id_each, 0, 0, allary ? zip_ary : zip_i, (VALUE)memo);
return result;
@@ -3579,7 +3584,7 @@ enum_take(VALUE obj, VALUE n)
if (len == 0) return rb_ary_new2(0);
result = rb_ary_new2(len);
- memo = MEMO_NEW(result, 0, len);
+ memo = rb_imemo_memo_new(result, 0, len);
rb_block_call(obj, id_each, 0, 0, take_i, (VALUE)memo);
return result;
}
@@ -3667,7 +3672,7 @@ enum_drop(VALUE obj, VALUE n)
}
result = rb_ary_new();
- memo = MEMO_NEW(result, 0, len);
+ memo = rb_imemo_memo_new(result, 0, len);
rb_block_call(obj, id_each, 0, 0, drop_i, (VALUE)memo);
return result;
}
@@ -3726,7 +3731,7 @@ enum_drop_while(VALUE obj)
RETURN_ENUMERATOR(obj, 0, 0);
result = rb_ary_new();
- memo = MEMO_NEW(result, 0, FALSE);
+ memo = rb_imemo_memo_new(result, 0, FALSE);
rb_block_call(obj, id_each, 0, 0, drop_while_i, (VALUE)memo);
return result;
}
@@ -3946,7 +3951,7 @@ chunk_i(RB_BLOCK_CALL_FUNC_ARGLIST(yielder, enumerator))
* ["F", 6860]
*
* You can use the special symbol <tt>:_alone</tt> to force an element
- * into its own separate chuck:
+ * into its own separate chunk:
*
* a = [0, 0, 1, 1]
* e = a.chunk{|i| i.even? ? :_alone : true }
@@ -5142,7 +5147,7 @@ enum_compact(VALUE obj)
* end
*
* The result of the size function should represent the number of iterations
- * (i.e., the number of times Enumerator::Yielder#yield is called).
+ * (i.e., the number of times you yield to the block argument).
* In the above example, the block calls #yield three times, and
* the size function, +-> { 3 }+, returns 3 accordingly.
* The result of the size function can be an integer, +Float::INFINITY+,
diff --git a/enumerator.c b/enumerator.c
index 0d54058215..69c96b2d8f 100644
--- a/enumerator.c
+++ b/enumerator.c
@@ -18,6 +18,7 @@
#include <float.h>
#endif
+#include <limits.h>
#include "id.h"
#include "internal.h"
#include "internal/class.h"
@@ -33,79 +34,93 @@
/*
* Document-class: Enumerator
*
- * A class which allows both internal and external iteration.
+ * \Class \Enumerator supports:
*
- * An Enumerator can be created by the following methods.
- * - Object#to_enum
- * - Object#enum_for
- * - Enumerator.new
+ * - {External iteration}[rdoc-ref:Enumerator@External+Iteration].
+ * - {Internal iteration}[rdoc-ref:Enumerator@Internal+Iteration].
*
- * Most methods have two forms: a block form where the contents
- * are evaluated for each item in the enumeration, and a non-block form
- * which returns a new Enumerator wrapping the iteration.
+ * An \Enumerator may be created by the following methods:
*
- * enumerator = %w(one two three).each
- * puts enumerator.class # => Enumerator
+ * - Object#to_enum.
+ * - Object#enum_for.
+ * - Enumerator.new.
*
- * enumerator.each_with_object("foo") do |item, obj|
- * puts "#{obj}: #{item}"
- * end
+ * In addition, certain Ruby methods return \Enumerator objects:
+ * a Ruby iterator method that accepts a block
+ * may return an \Enumerator if no block is given.
+ * There are many such methods, for example, in classes Array and Hash.
+ * (In the documentation for those classes, search for `new_enumerator`.)
*
- * # foo: one
- * # foo: two
- * # foo: three
+ * == Internal Iteration
*
- * enum_with_obj = enumerator.each_with_object("foo")
- * puts enum_with_obj.class # => Enumerator
+ * In _internal iteration_, an iterator method drives the iteration
+ * and the caller's block handles the processing;
+ * this example uses method #each_with_index:
*
- * enum_with_obj.each do |item, obj|
- * puts "#{obj}: #{item}"
- * end
+ * words = %w[foo bar baz] # => ["foo", "bar", "baz"]
+ * enumerator = words.each # => #<Enumerator: ...>
+ * enumerator.each_with_index {|word, i| puts "#{i}: #{word}" }
+ * 0: foo
+ * 1: bar
+ * 2: baz
*
- * # foo: one
- * # foo: two
- * # foo: three
+ * Iterator methods in class \Enumerator include:
*
- * This allows you to chain Enumerators together. For example, you
- * can map a list's elements to strings containing the index
- * and the element as a string via:
+ * - #each:
+ * passes each item to the block.
+ * - #each_with_index:
+ * passes each item and its index to the block.
+ * - #each_with_object (aliased as #with_object):
+ * passes each item and a given object to the block.
+ * - #with_index:
+ * like #each_with_index, but starting at a given offset (instead of zero).
*
- * puts %w[foo bar baz].map.with_index { |w, i| "#{i}:#{w}" }
- * # => ["0:foo", "1:bar", "2:baz"]
+ * \Class \Enumerator includes module Enumerable,
+ * which provides many more iterator methods.
*
* == External Iteration
*
- * An Enumerator can also be used as an external iterator.
- * For example, Enumerator#next returns the next value of the iterator
- * or raises StopIteration if the Enumerator is at the end.
- *
- * e = [1,2,3].each # returns an enumerator object.
- * puts e.next # => 1
- * puts e.next # => 2
- * 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).
- *
- * 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
+ * In _external iteration_, the user's program both drives the iteration
+ * and handles the processing in stream-like fashion;
+ * this example uses method #next:
+ *
+ * words = %w[foo bar baz]
+ * enumerator = words.each
+ * enumerator.next # => "foo"
+ * enumerator.next # => "bar"
+ * enumerator.next # => "baz"
+ * enumerator.next # Raises StopIteration: iteration reached an end
+ *
+ * External iteration methods in class \Enumerator include:
+ *
+ * - #feed:
+ * sets the value that is next to be returned.
+ * - #next:
+ * returns the next value and increments the position.
+ * - #next_values:
+ * returns the next value in a 1-element array and increments the position.
+ * - #peek:
+ * returns the next value but does not increment the position.
+ * - #peek_values:
+ * returns the next value in a 1-element array but does not increment the position.
+ * - #rewind:
+ * sets the position to zero.
+ *
+ * Each of these methods raises FrozenError if called from a frozen \Enumerator.
+ *
+ * == External Iteration and \Fiber
+ *
+ * External iteration that uses Fiber differs *significantly* from internal iteration:
+ *
+ * - Using \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:
@@ -125,7 +140,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
+ * == Converting External Iteration to Internal Iteration
*
* You can use an external iterator to implement an internal iterator as follows:
*
@@ -221,6 +236,7 @@ struct yielder {
struct producer {
VALUE init;
VALUE proc;
+ VALUE size;
};
typedef struct MEMO *lazyenum_proc_func(VALUE, struct MEMO *, VALUE, long);
@@ -443,28 +459,31 @@ convert_to_feasible_size_value(VALUE obj)
/*
* call-seq:
- * Enumerator.new(size = nil) { |yielder| ... }
+ * Enumerator.new(size = nil) {|yielder| ... }
*
- * Creates a new Enumerator object, which can be used as an
- * Enumerable.
+ * Returns a new \Enumerator object that can be used for iteration.
*
- * Iteration is defined by the given block, in
- * which a "yielder" object, given as block parameter, can be used to
- * yield a value by calling the +yield+ method (aliased as <code><<</code>):
+ * The given block defines the iteration;
+ * it is called with a "yielder" object that can yield an object
+ * via a call to method <tt>yielder.yield</tt>:
*
- * fib = Enumerator.new do |y|
- * a = b = 1
- * loop do
- * y << a
- * a, b = b, a + b
+ * fib = Enumerator.new do |yielder|
+ * n = next_n = 1
+ * while true do
+ * yielder.yield(n)
+ * n, next_n = next_n, n + next_n
* end
* end
*
* fib.take(10) # => [1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
*
- * The optional parameter can be used to specify how to calculate the size
- * in a lazy fashion (see Enumerator#size). It can either be a value or
- * a callable object.
+ * Parameter +size+ specifies how the size is to be calculated (see #size);
+ * it can either be a value or a callable object:
+ *
+ * Enumerator.new{}.size # => nil
+ * Enumerator.new(42){}.size # => 42
+ * Enumerator.new(-> {42}){}.size # => 42
+ *
*/
static VALUE
enumerator_initialize(int argc, VALUE *argv, VALUE obj)
@@ -670,7 +689,7 @@ enumerator_with_index(int argc, VALUE *argv, VALUE obj)
rb_check_arity(argc, 0, 1);
RETURN_SIZED_ENUMERATOR(obj, argc, argv, enumerator_enum_size);
memo = (!argc || NIL_P(memo = argv[0])) ? INT2FIX(0) : rb_to_int(memo);
- return enumerator_block_call(obj, enumerator_with_index_i, (VALUE)MEMO_NEW(memo, 0, 0));
+ return enumerator_block_call(obj, enumerator_with_index_i, (VALUE)rb_imemo_memo_new(memo, 0, 0));
}
/*
@@ -1084,6 +1103,7 @@ enumerator_rewind(VALUE obj)
static struct generator *generator_ptr(VALUE obj);
static VALUE append_method(VALUE obj, VALUE str, ID default_method, VALUE default_args);
+static VALUE append_method_args(VALUE obj, VALUE str, VALUE default_args);
static VALUE
inspect_enumerator(VALUE obj, VALUE dummy, int recur)
@@ -1156,7 +1176,7 @@ kwd_append(VALUE key, VALUE val, VALUE str)
static VALUE
append_method(VALUE obj, VALUE str, ID default_method, VALUE default_args)
{
- VALUE method, eargs;
+ VALUE method;
method = rb_attr_get(obj, id_method);
if (method != Qfalse) {
@@ -1170,6 +1190,13 @@ append_method(VALUE obj, VALUE str, ID default_method, VALUE default_args)
rb_str_buf_cat2(str, ":");
rb_str_buf_append(str, method);
}
+ return append_method_args(obj, str, default_args);
+}
+
+static VALUE
+append_method_args(VALUE obj, VALUE str, VALUE default_args)
+{
+ VALUE eargs;
eargs = rb_attr_get(obj, id_arguments);
if (NIL_P(eargs)) {
@@ -1199,10 +1226,11 @@ append_method(VALUE obj, VALUE str, ID default_method, VALUE default_args)
if (!NIL_P(kwds)) {
rb_hash_foreach(kwds, kwd_append, str);
}
- rb_str_set_len(str, RSTRING_LEN(str)-2);
+ rb_str_set_len(str, RSTRING_LEN(str)-2); /* drop the last ", " */
rb_str_buf_cat2(str, ")");
}
}
+ RB_GC_GUARD(eargs);
return str;
}
@@ -1229,6 +1257,24 @@ enumerator_inspect(VALUE obj)
* (1..100).to_a.permutation(4).size # => 94109400
* loop.size # => Float::INFINITY
* (1..100).drop_while.size # => nil
+ *
+ * Note that enumerator size might be inaccurate, and should be rather treated as a hint.
+ * For example, there is no check that the size provided to ::new is accurate:
+ *
+ * e = Enumerator.new(5) { |y| 2.times { y << it} }
+ * e.size # => 5
+ * e.to_a.size # => 2
+ *
+ * Another example is an enumerator created by ::produce without a +size+ argument.
+ * Such enumerators return +Infinity+ for size, but this is inaccurate if the passed
+ * block raises StopIteration:
+ *
+ * e = Enumerator.produce(1) { it + 1 }
+ * e.size # => Infinity
+ *
+ * e = Enumerator.produce(1) { it > 3 ? raise(StopIteration) : it + 1 }
+ * e.size # => Infinity
+ * e.to_a.size # => 4
*/
static VALUE
@@ -1594,7 +1640,7 @@ lazy_init_yielder(RB_BLOCK_CALL_FUNC_ARGLIST(_, m))
VALUE memos = rb_attr_get(yielder, id_memo);
struct MEMO *result;
- result = MEMO_NEW(m, rb_enum_values_pack(argc, argv),
+ result = rb_imemo_memo_new(m, rb_enum_values_pack(argc, argv),
argc > 1 ? LAZY_MEMO_PACKED : 0);
return lazy_yielder_result(result, yielder, procs_array, memos, 0);
}
@@ -2734,6 +2780,52 @@ lazy_with_index(int argc, VALUE *argv, VALUE obj)
return lazy_add_method(obj, 0, 0, memo, rb_ary_new_from_values(1, &memo), &lazy_with_index_funcs);
}
+static struct MEMO *
+lazy_tap_each_proc(VALUE proc_entry, struct MEMO *result, VALUE memos, long memo_index)
+{
+ struct proc_entry *entry = proc_entry_ptr(proc_entry);
+
+ rb_proc_call_with_block(entry->proc, 1, &result->memo_value, Qnil);
+
+ return result;
+}
+
+static const lazyenum_funcs lazy_tap_each_funcs = {
+ lazy_tap_each_proc, 0,
+};
+
+/*
+ * call-seq:
+ * lazy.tap_each { |item| ... } -> lazy_enumerator
+ *
+ * Passes each element through to the block for side effects only,
+ * without modifying the element or affecting the enumeration.
+ * Returns a new lazy enumerator.
+ *
+ * This is useful for debugging or logging inside lazy chains,
+ * without breaking laziness or misusing +map+.
+ *
+ * (1..).lazy
+ * .tap_each { |x| puts "got #{x}" }
+ * .select(&:even?)
+ * .first(3)
+ * # prints: got 1, got 2, ..., got 6
+ * # returns: [2, 4, 6]
+ *
+ * Similar in intent to Java's Stream#peek.
+ */
+
+static VALUE
+lazy_tap_each(VALUE obj)
+{
+ if (!rb_block_given_p())
+ {
+ rb_raise(rb_eArgError, "tried to call lazy tap_each without a block");
+ }
+
+ return lazy_add_method(obj, 0, 0, Qnil, Qnil, &lazy_tap_each_funcs);
+}
+
#if 0 /* for RDoc */
/*
@@ -2876,6 +2968,7 @@ producer_mark_and_move(void *p)
struct producer *ptr = p;
rb_gc_mark_and_move(&ptr->init);
rb_gc_mark_and_move(&ptr->proc);
+ rb_gc_mark_and_move(&ptr->size);
}
#define producer_free RUBY_TYPED_DEFAULT_FREE
@@ -2919,12 +3012,13 @@ producer_allocate(VALUE klass)
obj = TypedData_Make_Struct(klass, struct producer, &producer_data_type, ptr);
ptr->init = Qundef;
ptr->proc = Qundef;
+ ptr->size = Qnil;
return obj;
}
static VALUE
-producer_init(VALUE obj, VALUE init, VALUE proc)
+producer_init(VALUE obj, VALUE init, VALUE proc, VALUE size)
{
struct producer *ptr;
@@ -2936,6 +3030,7 @@ producer_init(VALUE obj, VALUE init, VALUE proc)
RB_OBJ_WRITE(obj, &ptr->init, init);
RB_OBJ_WRITE(obj, &ptr->proc, proc);
+ RB_OBJ_WRITE(obj, &ptr->size, size);
return obj;
}
@@ -2986,12 +3081,18 @@ producer_each(VALUE obj)
static VALUE
producer_size(VALUE obj, VALUE args, VALUE eobj)
{
- return DBL2NUM(HUGE_VAL);
+ struct producer *ptr = producer_ptr(obj);
+ VALUE size = ptr->size;
+
+ if (NIL_P(size)) return Qnil;
+ if (RB_INTEGER_TYPE_P(size) || RB_FLOAT_TYPE_P(size)) return size;
+
+ return rb_funcall(size, id_call, 0);
}
/*
* call-seq:
- * Enumerator.produce(initial = nil) { |prev| block } -> enumerator
+ * Enumerator.produce(initial = nil, size: nil) { |prev| block } -> enumerator
*
* Creates an infinite enumerator from any block, just called over and
* over. The result of the previous iteration is passed to the next one.
@@ -3023,19 +3124,50 @@ producer_size(VALUE obj, VALUE args, VALUE eobj)
* PATTERN = %r{\d+|[-/+*]}
* Enumerator.produce { scanner.scan(PATTERN) }.slice_after { scanner.eos? }.first
* # => ["7", "+", "38", "/", "6"]
+ *
+ * The optional +size+ keyword argument specifies the size of the enumerator,
+ * which can be retrieved by Enumerator#size. It can be an integer,
+ * +Float::INFINITY+, a callable object (such as a lambda), or +nil+ to
+ * indicate unknown size. When not specified, the size defaults to
+ * +Float::INFINITY+.
+ *
+ * # Infinite enumerator
+ * enum = Enumerator.produce(1, size: Float::INFINITY, &:succ)
+ * enum.size # => Float::INFINITY
+ *
+ * # Finite enumerator with known/computable size
+ * abs_dir = File.expand_path("./baz") # => "/foo/bar/baz"
+ * traverser = Enumerator.produce(abs_dir, size: -> { abs_dir.count("/") + 1 }) {
+ * raise StopIteration if it == "/"
+ * File.dirname(it)
+ * }
+ * traverser.size # => 4
+ *
+ * # Finite enumerator with unknown size
+ * calendar = Enumerator.produce(Date.today, size: nil) {
+ * it.monday? ? raise(StopIteration) : it + 1
+ * }
+ * calendar.size # => nil
*/
static VALUE
enumerator_s_produce(int argc, VALUE *argv, VALUE klass)
{
- VALUE init, producer;
+ VALUE init, producer, opts, size;
+ ID keyword_ids[1];
if (!rb_block_given_p()) rb_raise(rb_eArgError, "no block given");
- if (rb_scan_args(argc, argv, "01", &init) == 0) {
+ keyword_ids[0] = rb_intern("size");
+ rb_scan_args_kw(RB_SCAN_ARGS_LAST_HASH_KEYWORDS, argc, argv, "01:", &init, &opts);
+ rb_get_kwargs(opts, keyword_ids, 0, 1, &size);
+
+ size = UNDEF_P(size) ? DBL2NUM(HUGE_VAL) : convert_to_feasible_size_value(size);
+
+ if (argc == 0 || (argc == 1 && !NIL_P(opts))) {
init = Qundef;
}
- producer = producer_init(producer_allocate(rb_cEnumProducer), init, rb_block_proc());
+ producer = producer_init(producer_allocate(rb_cEnumProducer), init, rb_block_proc(), size);
return rb_enumeratorize_with_size_kw(producer, sym_each, 0, 0, producer_size, RB_NO_KEYWORDS);
}
@@ -3522,9 +3654,9 @@ enum_product_enum_size(VALUE obj, VALUE args, VALUE eobj)
struct product_state {
VALUE obj;
VALUE block;
+ int index;
int argc;
VALUE *argv;
- int index;
};
static VALUE product_each(VALUE, struct product_state *);
@@ -3563,15 +3695,23 @@ enum_product_run(VALUE obj, VALUE block)
{
struct enum_product *ptr = enum_product_ptr(obj);
int argc = RARRAY_LENINT(ptr->enums);
+ if (argc == 0) { /* no need to allocate state.argv */
+ rb_funcall(block, id_call, 1, rb_ary_new());
+ return obj;
+ }
+
+ VALUE argsbuf = 0;
struct product_state state = {
.obj = obj,
.block = block,
.index = 0,
.argc = argc,
- .argv = ALLOCA_N(VALUE, argc),
+ .argv = ALLOCV_N(VALUE, argsbuf, argc),
};
- return product_each(obj, &state);
+ VALUE ret = product_each(obj, &state);
+ ALLOCV_END(argsbuf);
+ return ret;
}
/*
@@ -3941,7 +4081,7 @@ arith_seq_take(VALUE self, VALUE num)
ary = rb_ary_new_capa((n < len) ? n : len);
while (n > 0 && i < end) {
rb_ary_push(ary, LONG2FIX(i));
- if (i + unit < i) break;
+ if (i > LONG_MAX - unit) break;
i += unit;
--n;
}
@@ -3954,7 +4094,7 @@ arith_seq_take(VALUE self, VALUE num)
ary = rb_ary_new_capa((n < len) ? n : len);
while (n > 0 && i > end) {
rb_ary_push(ary, LONG2FIX(i));
- if (i + unit > i) break;
+ if (i < LONG_MIN - unit) break;
i += unit;
--n;
}
@@ -4209,7 +4349,7 @@ static VALUE
arith_seq_inspect(VALUE self)
{
struct enumerator *e;
- VALUE eobj, str, eargs;
+ VALUE eobj, str;
int range_p;
TypedData_Get_Struct(self, struct enumerator, &enumerator_data_type, e);
@@ -4223,39 +4363,7 @@ arith_seq_inspect(VALUE self)
str = rb_sprintf("(%s%"PRIsVALUE"%s.", range_p ? "(" : "", eobj, range_p ? ")" : "");
rb_str_buf_append(str, rb_id2str(e->meth));
-
- eargs = rb_attr_get(eobj, id_arguments);
- if (NIL_P(eargs)) {
- eargs = e->args;
- }
- if (eargs != Qfalse) {
- long argc = RARRAY_LEN(eargs);
- const VALUE *argv = RARRAY_CONST_PTR(eargs); /* WB: no new reference */
-
- if (argc > 0) {
- VALUE kwds = Qnil;
-
- rb_str_buf_cat2(str, "(");
-
- if (RB_TYPE_P(argv[argc-1], T_HASH)) {
- int all_key = TRUE;
- rb_hash_foreach(argv[argc-1], key_symbol_p, (VALUE)&all_key);
- if (all_key) kwds = argv[--argc];
- }
-
- while (argc--) {
- VALUE arg = *argv++;
-
- rb_str_append(str, rb_inspect(arg));
- rb_str_buf_cat2(str, ", ");
- }
- if (!NIL_P(kwds)) {
- rb_hash_foreach(kwds, kwd_append, str);
- }
- rb_str_set_len(str, RSTRING_LEN(str)-2); /* drop the last ", " */
- rb_str_buf_cat2(str, ")");
- }
- }
+ append_method_args(eobj, str, e->args);
rb_str_buf_cat2(str, ")");
@@ -4561,6 +4669,7 @@ InitVM_Enumerator(void)
rb_define_method(rb_cLazy, "uniq", lazy_uniq, 0);
rb_define_method(rb_cLazy, "compact", lazy_compact, 0);
rb_define_method(rb_cLazy, "with_index", lazy_with_index, -1);
+ rb_define_method(rb_cLazy, "tap_each", lazy_tap_each, 0);
lazy_use_super_method = rb_hash_new_with_size(18);
rb_hash_aset(lazy_use_super_method, sym("map"), sym("_enumerable_map"));
@@ -4597,7 +4706,7 @@ InitVM_Enumerator(void)
rb_eStopIteration = rb_define_class("StopIteration", rb_eIndexError);
rb_define_method(rb_eStopIteration, "result", stop_result, 0);
- /* Generator */
+ /* :nodoc: Generator */
rb_cGenerator = rb_define_class_under(rb_cEnumerator, "Generator", rb_cObject);
rb_include_module(rb_cGenerator, rb_mEnumerable);
rb_define_alloc_func(rb_cGenerator, generator_allocate);
@@ -4605,7 +4714,7 @@ InitVM_Enumerator(void)
rb_define_method(rb_cGenerator, "initialize_copy", generator_init_copy, 1);
rb_define_method(rb_cGenerator, "each", generator_each, -1);
- /* Yielder */
+ /* :nodoc: Yielder */
rb_cYielder = rb_define_class_under(rb_cEnumerator, "Yielder", rb_cObject);
rb_define_alloc_func(rb_cYielder, yielder_allocate);
rb_define_method(rb_cYielder, "initialize", yielder_initialize, 0);
@@ -4613,7 +4722,7 @@ InitVM_Enumerator(void)
rb_define_method(rb_cYielder, "<<", yielder_yield_push, 1);
rb_define_method(rb_cYielder, "to_proc", yielder_to_proc, 0);
- /* Producer */
+ /* :nodoc: Producer */
rb_cEnumProducer = rb_define_class_under(rb_cEnumerator, "Producer", rb_cObject);
rb_define_alloc_func(rb_cEnumProducer, producer_allocate);
rb_define_method(rb_cEnumProducer, "each", producer_each, 0);
diff --git a/error.c b/error.c
index e07c99e6df..7a08fd2b9e 100644
--- a/error.c
+++ b/error.c
@@ -50,6 +50,7 @@
#include "ruby_assert.h"
#include "vm_core.h"
#include "yjit.h"
+#include "zjit.h"
#include "builtin.h"
@@ -908,6 +909,10 @@ bug_report_file(const char *file, int line, rb_pid_t *pid)
int len = err_position_0(buf, sizeof(buf), file, line);
if (out) {
+ /* Disable buffering so crash report output is not lost if
+ * rb_vm_bugreport() triggers a secondary crash (e.g. SIGSEGV
+ * while walking JIT frames). */
+ setvbuf(out, NULL, _IONBF, 0);
if ((ssize_t)fwrite(buf, 1, len, out) == (ssize_t)len) return out;
fclose(out);
}
@@ -1077,9 +1082,14 @@ static void
die(void)
{
#if defined(_WIN32) && defined(RUBY_MSVCRT_VERSION) && RUBY_MSVCRT_VERSION >= 80
+ /* mingw32 declares in stdlib.h but does not provide. */
_set_abort_behavior( 0, _CALL_REPORTFAULT);
#endif
+ /* Reset SIGABRT to default so that abort() does not trigger our custom
+ * handler (sigabrt), which would re-open the crash report file with "w"
+ * and truncate the report already written by rb_bug(). */
+ signal(SIGABRT, SIG_DFL);
abort();
}
@@ -1090,7 +1100,7 @@ rb_bug_without_die_internal(const char *fmt, va_list args)
const char *file = NULL;
int line = 0;
- if (GET_EC()) {
+ if (rb_current_execution_context(false)) {
file = rb_source_location_cstr(&line);
}
@@ -1123,7 +1133,7 @@ rb_bug_for_fatal_signal(ruby_sighandler_t default_sighandler, int sig, const voi
const char *file = NULL;
int line = 0;
- if (GET_EC()) {
+ if (rb_current_execution_context(false)) {
file = rb_source_location_cstr(&line);
}
@@ -1312,6 +1322,20 @@ rb_builtin_class_name(VALUE x)
COLDFUNC NORETURN(static void unexpected_type(VALUE, int, int));
#define UNDEF_LEAKED "undef leaked to the Ruby space"
+void
+rb_unexpected_typeddata(const rb_data_type_t *actual, const rb_data_type_t *expected)
+{
+ rb_raise(rb_eTypeError, "wrong argument type %s (expected %s)",
+ actual->wrap_struct_name, expected->wrap_struct_name);
+}
+
+void
+rb_unexpected_object_type(VALUE obj, const char *expected)
+{
+ rb_raise(rb_eTypeError, "wrong argument type %"PRIsVALUE" (expected %s)",
+ displaying_class_of(obj), expected);
+}
+
static void
unexpected_type(VALUE x, int xt, int t)
{
@@ -1319,9 +1343,7 @@ unexpected_type(VALUE x, int xt, int t)
VALUE mesg, exc = rb_eFatal;
if (tname) {
- mesg = rb_sprintf("wrong argument type %"PRIsVALUE" (expected %s)",
- displaying_class_of(x), tname);
- exc = rb_eTypeError;
+ rb_unexpected_object_type(x, tname);
}
else if (xt > T_MASK && xt <= 0x3f) {
mesg = rb_sprintf("unknown type 0x%x (0x%x given, probably comes"
@@ -1342,8 +1364,7 @@ rb_check_type(VALUE x, int t)
rb_bug(UNDEF_LEAKED);
}
- xt = TYPE(x);
- if (xt != t || (xt == T_DATA && rbimpl_rtypeddata_p(x))) {
+ if (t == T_DATA) {
/*
* Typed data is not simple `T_DATA`, but in a sense an
* extension of `struct RVALUE`, which are incompatible with
@@ -1352,6 +1373,10 @@ rb_check_type(VALUE x, int t)
* So it is not enough to just check `T_DATA`, it must be
* identified by its `type` using `Check_TypedStruct` instead.
*/
+ rb_unexpected_object_type(x, builtin_types[t]);
+ }
+ xt = TYPE(x);
+ if (xt != t) {
unexpected_type(x, xt, t);
}
}
@@ -1366,24 +1391,18 @@ rb_unexpected_type(VALUE x, int t)
unexpected_type(x, TYPE(x), t);
}
+#undef rb_typeddata_inherited_p
int
rb_typeddata_inherited_p(const rb_data_type_t *child, const rb_data_type_t *parent)
{
- while (child) {
- if (child == parent) return 1;
- child = child->parent;
- }
- return 0;
+ return rbimpl_typeddata_inherited_p_inline(child, parent);
}
+#undef rb_typeddata_is_kind_of
int
rb_typeddata_is_kind_of(VALUE obj, const rb_data_type_t *data_type)
{
- if (!RB_TYPE_P(obj, T_DATA) ||
- !RTYPEDDATA_P(obj) || !rb_typeddata_inherited_p(RTYPEDDATA_TYPE(obj), data_type)) {
- return 0;
- }
- return 1;
+ return rbimpl_typeddata_is_kind_of_inline(obj, data_type);
}
#undef rb_typeddata_is_instance_of
@@ -1396,26 +1415,7 @@ rb_typeddata_is_instance_of(VALUE obj, const rb_data_type_t *data_type)
void *
rb_check_typeddata(VALUE obj, const rb_data_type_t *data_type)
{
- VALUE actual;
-
- if (!RB_TYPE_P(obj, T_DATA)) {
- actual = displaying_class_of(obj);
- }
- else if (!RTYPEDDATA_P(obj)) {
- actual = displaying_class_of(obj);
- }
- else if (!rb_typeddata_inherited_p(RTYPEDDATA_TYPE(obj), data_type)) {
- const char *name = RTYPEDDATA_TYPE(obj)->wrap_struct_name;
- actual = rb_str_new_cstr(name); /* or rb_fstring_cstr? not sure... */
- }
- else {
- return RTYPEDDATA_GET_DATA(obj);
- }
-
- const char *expected = data_type->wrap_struct_name;
- rb_raise(rb_eTypeError, "wrong argument type %"PRIsVALUE" (expected %s)",
- actual, expected);
- UNREACHABLE_RETURN(NULL);
+ return rbimpl_check_typeddata(obj, data_type);
}
/* exception classes */
@@ -1536,7 +1536,7 @@ exc_initialize(int argc, VALUE *argv, VALUE exc)
*
* x0 = StandardError.new('Boom') # => #<StandardError: Boom>
* x1 = x0.exception # => #<StandardError: Boom>
- * x0.__id__ == x1.__id__ # => true
+ * x0.equal?(x1) # => true
*
* With {string-convertible object}[rdoc-ref:implicit_conversion.rdoc@String-Convertible+Objects]
* +message+ (even the same as the original message),
@@ -1544,7 +1544,7 @@ exc_initialize(int argc, VALUE *argv, VALUE exc)
* and whose message is the given +message+:
*
* x1 = x0.exception('Boom') # => #<StandardError: Boom>
- * x0..equal?(x1) # => false
+ * x0.equal?(x1) # => false
*
*/
@@ -1686,7 +1686,7 @@ check_order_keyword(VALUE opt)
* - 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.
+ * lists the error message the innermost entry last.
*
* Example:
*
@@ -2171,9 +2171,9 @@ try_convert_to_exception(VALUE obj)
/*
* call-seq:
- * self == object -> true or false
+ * self == other -> true or false
*
- * Returns whether +object+ is the same class as +self+
+ * Returns whether +other+ is the same class as +self+
* and its #message and #backtrace are equal to those of +self+.
*
*/
@@ -2379,7 +2379,7 @@ name_err_init_attr(VALUE exc, VALUE recv, VALUE method)
rb_ivar_set(exc, id_name, method);
err_init_recv(exc, recv);
if (cfp && VM_FRAME_TYPE(cfp) != VM_FRAME_MAGIC_DUMMY) {
- rb_ivar_set(exc, id_iseq, rb_iseqw_new(cfp->iseq));
+ rb_ivar_set(exc, id_iseq, rb_iseqw_new(CFP_ISEQ(cfp)));
}
return exc;
}
@@ -2619,7 +2619,7 @@ name_err_mesg_to_str(VALUE obj)
VALUE mesg = ptr->mesg;
if (NIL_P(mesg)) return Qnil;
else {
- struct RString s_str, c_str, d_str;
+ struct RString s_str = {RBASIC_INIT}, c_str = {RBASIC_INIT}, d_str = {RBASIC_INIT};
VALUE c, s, d = 0, args[4], c2;
int state = 0;
rb_encoding *usascii = rb_usascii_encoding();
@@ -2770,6 +2770,68 @@ nometh_err_private_call_p(VALUE self)
return rb_attr_get(self, id_private_call_p);
}
+static const char *
+type_err_cname(VALUE val)
+{
+ if (NIL_P(val)) {
+ return "nil";
+ }
+ else if (val == Qtrue) {
+ return "true";
+ }
+ else if (val == Qfalse) {
+ return "false";
+ }
+ return NULL;
+}
+
+NORETURN(static void type_err_raise(VALUE val, const char *tname, const char *msg));
+static void
+type_err_raise(VALUE val, const char *tname, const char *msg)
+{
+ const char *cname = type_err_cname(val);
+ rb_encoding *enc = rb_utf8_encoding();
+ if (cname) {
+ rb_enc_raise(enc, rb_eTypeError, "%s %s into %s", msg, cname, tname);
+ }
+ rb_enc_raise(enc, rb_eTypeError, "%s %"PRIsVALUE" into %s", msg, rb_obj_class(val), tname);
+}
+
+NORETURN(void rb_no_implicit_conversion(VALUE val, const char *tname));
+void
+rb_no_implicit_conversion(VALUE val, const char *tname)
+{
+ type_err_raise(val, tname, "no implicit conversion of");
+}
+
+NORETURN(void rb_cant_convert(VALUE val, const char *tname));
+void
+rb_cant_convert(VALUE val, const char *tname)
+{
+ type_err_raise(val, tname, "can't convert");
+}
+
+NORETURN(void rb_cant_convert_invalid_return(VALUE val, const char *tname, const char *method_name, VALUE ret));
+void
+rb_cant_convert_invalid_return(VALUE val, const char *tname, const char *method_name, VALUE ret)
+{
+ const char *cname = type_err_cname(val);
+ rb_encoding *enc = rb_utf8_encoding();
+ if (cname) {
+ rb_enc_raise(
+ enc, rb_eTypeError, "can't convert %s into %s (%s#%s gives %s)",
+ cname, tname, cname, method_name, type_err_cname(ret));
+ }
+ VALUE klass = rb_obj_class(val);
+ const char *retname = type_err_cname(ret);
+ if (!retname) {
+ retname = rb_obj_classname(ret);
+ }
+ rb_enc_raise(
+ enc, rb_eTypeError, "can't convert %"PRIsVALUE" into %s (%"PRIsVALUE"#%s gives %s)",
+ klass, tname, klass, method_name, retname);
+}
+
void
rb_invalid_str(const char *str, const char *type)
{
@@ -4162,7 +4224,7 @@ rb_error_frozen_object(VALUE frozen_obj)
rb_yjit_lazy_push_frame(GET_EC()->cfp->pc);
VALUE mesg = rb_sprintf("can't modify frozen %"PRIsVALUE": ",
- CLASS_OF(frozen_obj));
+ rb_obj_class(frozen_obj));
VALUE exc = rb_exc_new_str(rb_eFrozenError, mesg);
rb_ivar_set(exc, id_recv, frozen_obj);
diff --git a/eval.c b/eval.c
index 019a2d19a2..b6fedf11f3 100644
--- a/eval.c
+++ b/eval.c
@@ -37,6 +37,7 @@
#include "ruby/vm.h"
#include "vm_core.h"
#include "ractor_core.h"
+#include "zjit.h"
NORETURN(static void rb_raise_jump(VALUE, VALUE));
void rb_ec_clear_current_thread_trace_func(const rb_execution_context_t *ec);
@@ -78,8 +79,9 @@ ruby_setup(void)
#endif
Init_BareVM();
rb_vm_encoded_insn_data_table_init();
- Init_enable_namespace();
+ Init_enable_box();
Init_vm_objects();
+ Init_master_box();
Init_fstring_table();
EC_PUSH_TAG(GET_EC());
@@ -328,17 +330,24 @@ ruby_exec_node(void *n)
/*
* call-seq:
- * Module.nesting -> array
- *
- * Returns the list of +Modules+ nested at the point of call.
+ * Module.nesting -> array
+ *
+ * Returns nested module as an array of Module objects:
+ *
+ * module M0
+ * def self.speak = Module.nesting
+ * module M1
+ * def self.speak = Module.nesting
+ * module M2
+ * def self.speak = Module.nesting
+ * end
+ * end
+ * end
+ * M0.speak # => [M0]
+ * M0.speak.first.class # => Module
+ * M0::M1.speak # => [M0::M1, M0]
+ * M0::M1::M2.speak # => [M0::M1::M2, M0::M1, M0]
*
- * module M1
- * module M2
- * $a = Module.nesting
- * end
- * end
- * $a #=> [M1::M2, M1]
- * $a[0].name #=> "M1::M2"
*/
static VALUE
@@ -427,40 +436,10 @@ rb_class_modify_check(VALUE klass)
rb_class_set_initialized(klass);
}
if (OBJ_FROZEN(klass)) {
- const char *desc;
-
if (RCLASS_SINGLETON_P(klass)) {
- desc = "object";
klass = RCLASS_ATTACHED_OBJECT(klass);
- if (!SPECIAL_CONST_P(klass)) {
- switch (BUILTIN_TYPE(klass)) {
- case T_MODULE:
- case T_ICLASS:
- desc = "Module";
- break;
- case T_CLASS:
- desc = "Class";
- break;
- default:
- break;
- }
- }
- }
- else {
- switch (BUILTIN_TYPE(klass)) {
- case T_MODULE:
- case T_ICLASS:
- desc = "module";
- break;
- case T_CLASS:
- desc = "class";
- break;
- default:
- Check_Type(klass, T_CLASS);
- UNREACHABLE;
- }
}
- rb_frozen_error_raise(klass, "can't modify frozen %s: %"PRIsVALUE, desc, klass);
+ rb_error_frozen_object(klass);
}
}
@@ -951,6 +930,9 @@ rb_f_raise(int argc, VALUE *argv)
* With argument +exception+ not given,
* argument +message+ and keyword argument +cause+ may be given,
* but argument +backtrace+ may not be given.
+ *
+ * +cause+ can not be given as an only argument.
+ *
*/
static VALUE
@@ -1162,12 +1144,11 @@ rb_protect(VALUE (* proc) (VALUE), VALUE data, int *pstate)
}
VALUE
-rb_ensure(VALUE (*b_proc)(VALUE), VALUE data1, VALUE (*e_proc)(VALUE), VALUE data2)
+rb_ec_ensure(rb_execution_context_t *ec, VALUE (*b_proc)(VALUE), VALUE data1, VALUE (*e_proc)(VALUE), VALUE data2)
{
enum ruby_tag_type state;
volatile VALUE result = Qnil;
VALUE errinfo;
- rb_execution_context_t * volatile ec = GET_EC();
EC_PUSH_TAG(ec);
if ((state = EC_EXEC_TAG()) == TAG_NONE) {
result = (*b_proc) (data1);
@@ -1184,6 +1165,12 @@ rb_ensure(VALUE (*b_proc)(VALUE), VALUE data1, VALUE (*e_proc)(VALUE), VALUE dat
return result;
}
+VALUE
+rb_ensure(VALUE (*b_proc)(VALUE), VALUE data1, VALUE (*e_proc)(VALUE), VALUE data2)
+{
+ return rb_ec_ensure(GET_EC(), b_proc, data1, e_proc, data2);
+}
+
static ID
frame_func_id(const rb_control_frame_t *cfp)
{
@@ -1450,6 +1437,8 @@ rb_using_refinement(rb_cref_t *cref, VALUE klass, VALUE module)
RCLASS_WRITE_M_TBL(c, RCLASS_M_TBL(module));
+ rb_class_subclass_add(klass, iclass);
+
rb_hash_aset(CREF_REFINEMENTS(cref), klass, iclass);
}
@@ -1550,10 +1539,12 @@ add_activated_refinement(VALUE activated_refinements,
superclass = refinement_superclass(superclass);
c = iclass = rb_include_class_new(refinement, superclass);
RCLASS_SET_REFINED_CLASS(c, klass);
+ rb_class_subclass_add(klass, iclass);
refinement = RCLASS_SUPER(refinement);
while (refinement && refinement != klass) {
c = rb_class_set_super(c, rb_include_class_new(refinement, RCLASS_SUPER(c)));
RCLASS_SET_REFINED_CLASS(c, klass);
+ rb_class_subclass_add(klass, c);
refinement = RCLASS_SUPER(refinement);
}
rb_hash_aset(activated_refinements, klass, iclass);
@@ -2020,10 +2011,10 @@ errinfo_place(const rb_execution_context_t *ec)
while (RUBY_VM_VALID_CONTROL_FRAME_P(cfp, end_cfp)) {
if (VM_FRAME_RUBYFRAME_P(cfp)) {
- if (ISEQ_BODY(cfp->iseq)->type == ISEQ_TYPE_RESCUE) {
+ if (ISEQ_BODY(CFP_ISEQ(cfp))->type == ISEQ_TYPE_RESCUE) {
return &cfp->ep[VM_ENV_INDEX_LAST_LVAR];
}
- else if (ISEQ_BODY(cfp->iseq)->type == ISEQ_TYPE_ENSURE &&
+ else if (ISEQ_BODY(CFP_ISEQ(cfp))->type == ISEQ_TYPE_ENSURE &&
!THROW_DATA_P(cfp->ep[VM_ENV_INDEX_LAST_LVAR]) &&
!FIXNUM_P(cfp->ep[VM_ENV_INDEX_LAST_LVAR])) {
return &cfp->ep[VM_ENV_INDEX_LAST_LVAR];
@@ -2233,6 +2224,9 @@ Init_eval(void)
rb_gvar_ractor_local("$@");
rb_gvar_ractor_local("$!");
+ rb_gvar_box_dynamic("$@");
+ rb_gvar_box_dynamic("$!");
+
rb_define_global_function("raise", f_raise, -1);
rb_define_global_function("fail", f_raise, -1);
diff --git a/eval_intern.h b/eval_intern.h
index 2c244aa5e0..954ba6a184 100644
--- a/eval_intern.h
+++ b/eval_intern.h
@@ -3,6 +3,7 @@
#include "ruby/ruby.h"
#include "vm_core.h"
+#include "zjit.h"
static inline void
vm_passed_block_handler_set(rb_execution_context_t *ec, VALUE block_handler)
@@ -102,8 +103,18 @@ 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); \
+ EC_SAVE_TAG_CFP(_tag, _ec); \
rb_vm_tag_jmpbuf_init(&_tag.buf); \
+// Remember the CFP as of EC_PUSH_TAG so that ZJIT can materialize frames
+// only up to longjmp's target CFP. When a C method does longjmp inside it,
+// the target CFP may not be equal to the VM_FRAME_FLAG_FINISH frame.
+#if USE_ZJIT
+# define EC_SAVE_TAG_CFP(_tag, _ec) _tag.cfp = _ec->cfp
+#else
+# define EC_SAVE_TAG_CFP(_tag, _ec)
+#endif
+
#define EC_POP_TAG() \
_ec->tag = _tag.prev; \
rb_vm_tag_jmpbuf_deinit(&_tag.buf); \
@@ -155,6 +166,9 @@ 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);
+#if USE_ZJIT
+ rb_zjit_materialize_frames(ec, ec->cfp);
+#endif
ec->tag->state = st;
ruby_longjmp(RB_VM_TAG_JMPBUF_GET(ec->tag->buf), 1);
}
@@ -172,9 +186,10 @@ rb_ec_tag_jump(const rb_execution_context_t *ec, enum ruby_tag_type st)
/* CREF operators */
-#define CREF_FL_PUSHED_BY_EVAL IMEMO_FL_USER1
-#define CREF_FL_OMOD_SHARED IMEMO_FL_USER2
-#define CREF_FL_SINGLETON IMEMO_FL_USER3
+#define CREF_FL_PUSHED_BY_EVAL IMEMO_FL_USER1
+#define CREF_FL_OMOD_SHARED IMEMO_FL_USER2
+#define CREF_FL_SINGLETON IMEMO_FL_USER3
+#define CREF_FL_DYNAMIC_CREF IMEMO_FL_USER4
static inline int CREF_SINGLETON(const rb_cref_t *cref);
@@ -260,6 +275,18 @@ CREF_OMOD_SHARED_SET(rb_cref_t *cref)
cref->flags |= CREF_FL_OMOD_SHARED;
}
+static inline int
+CREF_DYNAMIC(const rb_cref_t *cref)
+{
+ return cref->flags & CREF_FL_DYNAMIC_CREF;
+}
+
+static inline void
+CREF_DYNAMIC_SET(rb_cref_t *cref)
+{
+ cref->flags |= CREF_FL_DYNAMIC_CREF;
+}
+
static inline void
CREF_OMOD_SHARED_UNSET(rb_cref_t *cref)
{
@@ -296,7 +323,11 @@ VALUE rb_vm_make_jump_tag_but_local_jump(enum ruby_tag_type 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);
-VALUE rb_vm_call_cfunc2(VALUE recv, VALUE (*func)(VALUE, VALUE), VALUE arg1, VALUE arg2, VALUE block_handler, VALUE filename);
+VALUE rb_vm_call_cfunc_in_box(VALUE recv, VALUE (*func)(VALUE, VALUE), VALUE arg1, VALUE arg2, VALUE filename, const rb_box_t *box);
+void rb_vm_frame_flag_set_box_require(const rb_execution_context_t *ec);
+const rb_box_t *rb_vm_current_box(const rb_execution_context_t *ec);
+const rb_box_t *rb_vm_caller_box(const rb_execution_context_t *ec);
+const rb_box_t *rb_vm_loading_box(const rb_execution_context_t *ec);
void rb_vm_set_progname(VALUE filename);
VALUE rb_vm_cbase(void);
diff --git a/eval_jump.c b/eval_jump.c
index 7593a35e36..6ee8ff4a6f 100644
--- a/eval_jump.c
+++ b/eval_jump.c
@@ -101,7 +101,7 @@ exec_end_procs_chain(struct end_proc_data *volatile *procs, VALUE *errp)
while ((link = *procs) != 0) {
*procs = link->next;
endproc = *link;
- xfree(link);
+ SIZED_FREE(link);
(*endproc.func) (endproc.data);
*errp = errinfo;
}
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/depend b/ext/-test-/asan/depend
deleted file mode 100644
index 93cdc739ec..0000000000
--- a/ext/-test-/asan/depend
+++ /dev/null
@@ -1,162 +0,0 @@
-# AUTOGENERATED DEPENDENCIES START
-asan.o: $(RUBY_EXTCONF_H)
-asan.o: $(arch_hdrdir)/ruby/config.h
-asan.o: $(hdrdir)/ruby/assert.h
-asan.o: $(hdrdir)/ruby/backward.h
-asan.o: $(hdrdir)/ruby/backward/2/assume.h
-asan.o: $(hdrdir)/ruby/backward/2/attributes.h
-asan.o: $(hdrdir)/ruby/backward/2/bool.h
-asan.o: $(hdrdir)/ruby/backward/2/inttypes.h
-asan.o: $(hdrdir)/ruby/backward/2/limits.h
-asan.o: $(hdrdir)/ruby/backward/2/long_long.h
-asan.o: $(hdrdir)/ruby/backward/2/stdalign.h
-asan.o: $(hdrdir)/ruby/backward/2/stdarg.h
-asan.o: $(hdrdir)/ruby/defines.h
-asan.o: $(hdrdir)/ruby/intern.h
-asan.o: $(hdrdir)/ruby/internal/abi.h
-asan.o: $(hdrdir)/ruby/internal/anyargs.h
-asan.o: $(hdrdir)/ruby/internal/arithmetic.h
-asan.o: $(hdrdir)/ruby/internal/arithmetic/char.h
-asan.o: $(hdrdir)/ruby/internal/arithmetic/double.h
-asan.o: $(hdrdir)/ruby/internal/arithmetic/fixnum.h
-asan.o: $(hdrdir)/ruby/internal/arithmetic/gid_t.h
-asan.o: $(hdrdir)/ruby/internal/arithmetic/int.h
-asan.o: $(hdrdir)/ruby/internal/arithmetic/intptr_t.h
-asan.o: $(hdrdir)/ruby/internal/arithmetic/long.h
-asan.o: $(hdrdir)/ruby/internal/arithmetic/long_long.h
-asan.o: $(hdrdir)/ruby/internal/arithmetic/mode_t.h
-asan.o: $(hdrdir)/ruby/internal/arithmetic/off_t.h
-asan.o: $(hdrdir)/ruby/internal/arithmetic/pid_t.h
-asan.o: $(hdrdir)/ruby/internal/arithmetic/short.h
-asan.o: $(hdrdir)/ruby/internal/arithmetic/size_t.h
-asan.o: $(hdrdir)/ruby/internal/arithmetic/st_data_t.h
-asan.o: $(hdrdir)/ruby/internal/arithmetic/uid_t.h
-asan.o: $(hdrdir)/ruby/internal/assume.h
-asan.o: $(hdrdir)/ruby/internal/attr/alloc_size.h
-asan.o: $(hdrdir)/ruby/internal/attr/artificial.h
-asan.o: $(hdrdir)/ruby/internal/attr/cold.h
-asan.o: $(hdrdir)/ruby/internal/attr/const.h
-asan.o: $(hdrdir)/ruby/internal/attr/constexpr.h
-asan.o: $(hdrdir)/ruby/internal/attr/deprecated.h
-asan.o: $(hdrdir)/ruby/internal/attr/diagnose_if.h
-asan.o: $(hdrdir)/ruby/internal/attr/enum_extensibility.h
-asan.o: $(hdrdir)/ruby/internal/attr/error.h
-asan.o: $(hdrdir)/ruby/internal/attr/flag_enum.h
-asan.o: $(hdrdir)/ruby/internal/attr/forceinline.h
-asan.o: $(hdrdir)/ruby/internal/attr/format.h
-asan.o: $(hdrdir)/ruby/internal/attr/maybe_unused.h
-asan.o: $(hdrdir)/ruby/internal/attr/noalias.h
-asan.o: $(hdrdir)/ruby/internal/attr/nodiscard.h
-asan.o: $(hdrdir)/ruby/internal/attr/noexcept.h
-asan.o: $(hdrdir)/ruby/internal/attr/noinline.h
-asan.o: $(hdrdir)/ruby/internal/attr/nonnull.h
-asan.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-asan.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
-asan.o: $(hdrdir)/ruby/internal/attr/pure.h
-asan.o: $(hdrdir)/ruby/internal/attr/restrict.h
-asan.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
-asan.o: $(hdrdir)/ruby/internal/attr/warning.h
-asan.o: $(hdrdir)/ruby/internal/attr/weakref.h
-asan.o: $(hdrdir)/ruby/internal/cast.h
-asan.o: $(hdrdir)/ruby/internal/compiler_is.h
-asan.o: $(hdrdir)/ruby/internal/compiler_is/apple.h
-asan.o: $(hdrdir)/ruby/internal/compiler_is/clang.h
-asan.o: $(hdrdir)/ruby/internal/compiler_is/gcc.h
-asan.o: $(hdrdir)/ruby/internal/compiler_is/intel.h
-asan.o: $(hdrdir)/ruby/internal/compiler_is/msvc.h
-asan.o: $(hdrdir)/ruby/internal/compiler_is/sunpro.h
-asan.o: $(hdrdir)/ruby/internal/compiler_since.h
-asan.o: $(hdrdir)/ruby/internal/config.h
-asan.o: $(hdrdir)/ruby/internal/constant_p.h
-asan.o: $(hdrdir)/ruby/internal/core.h
-asan.o: $(hdrdir)/ruby/internal/core/rarray.h
-asan.o: $(hdrdir)/ruby/internal/core/rbasic.h
-asan.o: $(hdrdir)/ruby/internal/core/rbignum.h
-asan.o: $(hdrdir)/ruby/internal/core/rclass.h
-asan.o: $(hdrdir)/ruby/internal/core/rdata.h
-asan.o: $(hdrdir)/ruby/internal/core/rfile.h
-asan.o: $(hdrdir)/ruby/internal/core/rhash.h
-asan.o: $(hdrdir)/ruby/internal/core/robject.h
-asan.o: $(hdrdir)/ruby/internal/core/rregexp.h
-asan.o: $(hdrdir)/ruby/internal/core/rstring.h
-asan.o: $(hdrdir)/ruby/internal/core/rstruct.h
-asan.o: $(hdrdir)/ruby/internal/core/rtypeddata.h
-asan.o: $(hdrdir)/ruby/internal/ctype.h
-asan.o: $(hdrdir)/ruby/internal/dllexport.h
-asan.o: $(hdrdir)/ruby/internal/dosish.h
-asan.o: $(hdrdir)/ruby/internal/error.h
-asan.o: $(hdrdir)/ruby/internal/eval.h
-asan.o: $(hdrdir)/ruby/internal/event.h
-asan.o: $(hdrdir)/ruby/internal/fl_type.h
-asan.o: $(hdrdir)/ruby/internal/gc.h
-asan.o: $(hdrdir)/ruby/internal/glob.h
-asan.o: $(hdrdir)/ruby/internal/globals.h
-asan.o: $(hdrdir)/ruby/internal/has/attribute.h
-asan.o: $(hdrdir)/ruby/internal/has/builtin.h
-asan.o: $(hdrdir)/ruby/internal/has/c_attribute.h
-asan.o: $(hdrdir)/ruby/internal/has/cpp_attribute.h
-asan.o: $(hdrdir)/ruby/internal/has/declspec_attribute.h
-asan.o: $(hdrdir)/ruby/internal/has/extension.h
-asan.o: $(hdrdir)/ruby/internal/has/feature.h
-asan.o: $(hdrdir)/ruby/internal/has/warning.h
-asan.o: $(hdrdir)/ruby/internal/intern/array.h
-asan.o: $(hdrdir)/ruby/internal/intern/bignum.h
-asan.o: $(hdrdir)/ruby/internal/intern/class.h
-asan.o: $(hdrdir)/ruby/internal/intern/compar.h
-asan.o: $(hdrdir)/ruby/internal/intern/complex.h
-asan.o: $(hdrdir)/ruby/internal/intern/cont.h
-asan.o: $(hdrdir)/ruby/internal/intern/dir.h
-asan.o: $(hdrdir)/ruby/internal/intern/enum.h
-asan.o: $(hdrdir)/ruby/internal/intern/enumerator.h
-asan.o: $(hdrdir)/ruby/internal/intern/error.h
-asan.o: $(hdrdir)/ruby/internal/intern/eval.h
-asan.o: $(hdrdir)/ruby/internal/intern/file.h
-asan.o: $(hdrdir)/ruby/internal/intern/hash.h
-asan.o: $(hdrdir)/ruby/internal/intern/io.h
-asan.o: $(hdrdir)/ruby/internal/intern/load.h
-asan.o: $(hdrdir)/ruby/internal/intern/marshal.h
-asan.o: $(hdrdir)/ruby/internal/intern/numeric.h
-asan.o: $(hdrdir)/ruby/internal/intern/object.h
-asan.o: $(hdrdir)/ruby/internal/intern/parse.h
-asan.o: $(hdrdir)/ruby/internal/intern/proc.h
-asan.o: $(hdrdir)/ruby/internal/intern/process.h
-asan.o: $(hdrdir)/ruby/internal/intern/random.h
-asan.o: $(hdrdir)/ruby/internal/intern/range.h
-asan.o: $(hdrdir)/ruby/internal/intern/rational.h
-asan.o: $(hdrdir)/ruby/internal/intern/re.h
-asan.o: $(hdrdir)/ruby/internal/intern/ruby.h
-asan.o: $(hdrdir)/ruby/internal/intern/select.h
-asan.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
-asan.o: $(hdrdir)/ruby/internal/intern/set.h
-asan.o: $(hdrdir)/ruby/internal/intern/signal.h
-asan.o: $(hdrdir)/ruby/internal/intern/sprintf.h
-asan.o: $(hdrdir)/ruby/internal/intern/string.h
-asan.o: $(hdrdir)/ruby/internal/intern/struct.h
-asan.o: $(hdrdir)/ruby/internal/intern/thread.h
-asan.o: $(hdrdir)/ruby/internal/intern/time.h
-asan.o: $(hdrdir)/ruby/internal/intern/variable.h
-asan.o: $(hdrdir)/ruby/internal/intern/vm.h
-asan.o: $(hdrdir)/ruby/internal/interpreter.h
-asan.o: $(hdrdir)/ruby/internal/iterator.h
-asan.o: $(hdrdir)/ruby/internal/memory.h
-asan.o: $(hdrdir)/ruby/internal/method.h
-asan.o: $(hdrdir)/ruby/internal/module.h
-asan.o: $(hdrdir)/ruby/internal/newobj.h
-asan.o: $(hdrdir)/ruby/internal/scan_args.h
-asan.o: $(hdrdir)/ruby/internal/special_consts.h
-asan.o: $(hdrdir)/ruby/internal/static_assert.h
-asan.o: $(hdrdir)/ruby/internal/stdalign.h
-asan.o: $(hdrdir)/ruby/internal/stdbool.h
-asan.o: $(hdrdir)/ruby/internal/stdckdint.h
-asan.o: $(hdrdir)/ruby/internal/symbol.h
-asan.o: $(hdrdir)/ruby/internal/value.h
-asan.o: $(hdrdir)/ruby/internal/value_type.h
-asan.o: $(hdrdir)/ruby/internal/variable.h
-asan.o: $(hdrdir)/ruby/internal/warning_push.h
-asan.o: $(hdrdir)/ruby/internal/xmalloc.h
-asan.o: $(hdrdir)/ruby/missing.h
-asan.o: $(hdrdir)/ruby/ruby.h
-asan.o: $(hdrdir)/ruby/st.h
-asan.o: $(hdrdir)/ruby/subst.h
-asan.o: asan.c
-# AUTOGENERATED DEPENDENCIES END
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 049f0c7b52..82972f1032 100644
--- a/ext/-test-/bignum/depend
+++ b/ext/-test-/bignum/depend
@@ -6,6 +6,7 @@ big2str.o: $(hdrdir)/ruby/backward.h
big2str.o: $(hdrdir)/ruby/backward/2/assume.h
big2str.o: $(hdrdir)/ruby/backward/2/attributes.h
big2str.o: $(hdrdir)/ruby/backward/2/bool.h
+big2str.o: $(hdrdir)/ruby/backward/2/gcc_version_since.h
big2str.o: $(hdrdir)/ruby/backward/2/inttypes.h
big2str.o: $(hdrdir)/ruby/backward/2/limits.h
big2str.o: $(hdrdir)/ruby/backward/2/long_long.h
@@ -159,6 +160,7 @@ big2str.o: $(hdrdir)/ruby/ruby.h
big2str.o: $(hdrdir)/ruby/st.h
big2str.o: $(hdrdir)/ruby/subst.h
big2str.o: $(top_srcdir)/internal/bignum.h
+big2str.o: $(top_srcdir)/internal/compilers.h
big2str.o: big2str.c
bigzero.o: $(RUBY_EXTCONF_H)
bigzero.o: $(arch_hdrdir)/ruby/config.h
@@ -167,6 +169,7 @@ bigzero.o: $(hdrdir)/ruby/backward.h
bigzero.o: $(hdrdir)/ruby/backward/2/assume.h
bigzero.o: $(hdrdir)/ruby/backward/2/attributes.h
bigzero.o: $(hdrdir)/ruby/backward/2/bool.h
+bigzero.o: $(hdrdir)/ruby/backward/2/gcc_version_since.h
bigzero.o: $(hdrdir)/ruby/backward/2/inttypes.h
bigzero.o: $(hdrdir)/ruby/backward/2/limits.h
bigzero.o: $(hdrdir)/ruby/backward/2/long_long.h
@@ -320,6 +323,7 @@ bigzero.o: $(hdrdir)/ruby/ruby.h
bigzero.o: $(hdrdir)/ruby/st.h
bigzero.o: $(hdrdir)/ruby/subst.h
bigzero.o: $(top_srcdir)/internal/bignum.h
+bigzero.o: $(top_srcdir)/internal/compilers.h
bigzero.o: bigzero.c
div.o: $(RUBY_EXTCONF_H)
div.o: $(arch_hdrdir)/ruby/config.h
@@ -328,6 +332,7 @@ div.o: $(hdrdir)/ruby/backward.h
div.o: $(hdrdir)/ruby/backward/2/assume.h
div.o: $(hdrdir)/ruby/backward/2/attributes.h
div.o: $(hdrdir)/ruby/backward/2/bool.h
+div.o: $(hdrdir)/ruby/backward/2/gcc_version_since.h
div.o: $(hdrdir)/ruby/backward/2/inttypes.h
div.o: $(hdrdir)/ruby/backward/2/limits.h
div.o: $(hdrdir)/ruby/backward/2/long_long.h
@@ -481,6 +486,7 @@ div.o: $(hdrdir)/ruby/ruby.h
div.o: $(hdrdir)/ruby/st.h
div.o: $(hdrdir)/ruby/subst.h
div.o: $(top_srcdir)/internal/bignum.h
+div.o: $(top_srcdir)/internal/compilers.h
div.o: div.c
init.o: $(RUBY_EXTCONF_H)
init.o: $(arch_hdrdir)/ruby/config.h
@@ -650,6 +656,7 @@ intpack.o: $(hdrdir)/ruby/backward.h
intpack.o: $(hdrdir)/ruby/backward/2/assume.h
intpack.o: $(hdrdir)/ruby/backward/2/attributes.h
intpack.o: $(hdrdir)/ruby/backward/2/bool.h
+intpack.o: $(hdrdir)/ruby/backward/2/gcc_version_since.h
intpack.o: $(hdrdir)/ruby/backward/2/inttypes.h
intpack.o: $(hdrdir)/ruby/backward/2/limits.h
intpack.o: $(hdrdir)/ruby/backward/2/long_long.h
@@ -803,6 +810,7 @@ intpack.o: $(hdrdir)/ruby/ruby.h
intpack.o: $(hdrdir)/ruby/st.h
intpack.o: $(hdrdir)/ruby/subst.h
intpack.o: $(top_srcdir)/internal/bignum.h
+intpack.o: $(top_srcdir)/internal/compilers.h
intpack.o: intpack.c
mul.o: $(RUBY_EXTCONF_H)
mul.o: $(arch_hdrdir)/ruby/config.h
@@ -811,6 +819,7 @@ mul.o: $(hdrdir)/ruby/backward.h
mul.o: $(hdrdir)/ruby/backward/2/assume.h
mul.o: $(hdrdir)/ruby/backward/2/attributes.h
mul.o: $(hdrdir)/ruby/backward/2/bool.h
+mul.o: $(hdrdir)/ruby/backward/2/gcc_version_since.h
mul.o: $(hdrdir)/ruby/backward/2/inttypes.h
mul.o: $(hdrdir)/ruby/backward/2/limits.h
mul.o: $(hdrdir)/ruby/backward/2/long_long.h
@@ -964,6 +973,7 @@ mul.o: $(hdrdir)/ruby/ruby.h
mul.o: $(hdrdir)/ruby/st.h
mul.o: $(hdrdir)/ruby/subst.h
mul.o: $(top_srcdir)/internal/bignum.h
+mul.o: $(top_srcdir)/internal/compilers.h
mul.o: mul.c
str2big.o: $(RUBY_EXTCONF_H)
str2big.o: $(arch_hdrdir)/ruby/config.h
@@ -972,6 +982,7 @@ str2big.o: $(hdrdir)/ruby/backward.h
str2big.o: $(hdrdir)/ruby/backward/2/assume.h
str2big.o: $(hdrdir)/ruby/backward/2/attributes.h
str2big.o: $(hdrdir)/ruby/backward/2/bool.h
+str2big.o: $(hdrdir)/ruby/backward/2/gcc_version_since.h
str2big.o: $(hdrdir)/ruby/backward/2/inttypes.h
str2big.o: $(hdrdir)/ruby/backward/2/limits.h
str2big.o: $(hdrdir)/ruby/backward/2/long_long.h
@@ -1125,5 +1136,6 @@ str2big.o: $(hdrdir)/ruby/ruby.h
str2big.o: $(hdrdir)/ruby/st.h
str2big.o: $(hdrdir)/ruby/subst.h
str2big.o: $(top_srcdir)/internal/bignum.h
+str2big.o: $(top_srcdir)/internal/compilers.h
str2big.o: str2big.c
# AUTOGENERATED DEPENDENCIES END
diff --git a/ext/-test-/box/yay1/extconf.rb b/ext/-test-/box/yay1/extconf.rb
new file mode 100644
index 0000000000..54387cedf1
--- /dev/null
+++ b/ext/-test-/box/yay1/extconf.rb
@@ -0,0 +1 @@
+create_makefile('-test-/box/yay1')
diff --git a/ext/-test-/namespace/yay1/yay1.c b/ext/-test-/box/yay1/yay1.c
index 564a221c8c..564a221c8c 100644
--- a/ext/-test-/namespace/yay1/yay1.c
+++ b/ext/-test-/box/yay1/yay1.c
diff --git a/ext/-test-/namespace/yay1/yay1.def b/ext/-test-/box/yay1/yay1.def
index 510fbe7017..510fbe7017 100644
--- a/ext/-test-/namespace/yay1/yay1.def
+++ b/ext/-test-/box/yay1/yay1.def
diff --git a/ext/-test-/namespace/yay1/yay1.h b/ext/-test-/box/yay1/yay1.h
index c4dade928a..c4dade928a 100644
--- a/ext/-test-/namespace/yay1/yay1.h
+++ b/ext/-test-/box/yay1/yay1.h
diff --git a/ext/-test-/box/yay2/extconf.rb b/ext/-test-/box/yay2/extconf.rb
new file mode 100644
index 0000000000..850ef3edc9
--- /dev/null
+++ b/ext/-test-/box/yay2/extconf.rb
@@ -0,0 +1 @@
+create_makefile('-test-/box/yay2')
diff --git a/ext/-test-/namespace/yay2/yay2.c b/ext/-test-/box/yay2/yay2.c
index b632ae8495..b632ae8495 100644
--- a/ext/-test-/namespace/yay2/yay2.c
+++ b/ext/-test-/box/yay2/yay2.c
diff --git a/ext/-test-/namespace/yay2/yay2.def b/ext/-test-/box/yay2/yay2.def
index 163fc44c04..163fc44c04 100644
--- a/ext/-test-/namespace/yay2/yay2.def
+++ b/ext/-test-/box/yay2/yay2.def
diff --git a/ext/-test-/namespace/yay2/yay2.h b/ext/-test-/box/yay2/yay2.h
index c4dade928a..c4dade928a 100644
--- a/ext/-test-/namespace/yay2/yay2.h
+++ b/ext/-test-/box/yay2/yay2.h
diff --git a/ext/-test-/cxxanyargs/cxxanyargs.cpp b/ext/-test-/cxxanyargs/cxxanyargs.cpp
index eded13e2ee..c7df7f9038 100644
--- a/ext/-test-/cxxanyargs/cxxanyargs.cpp
+++ b/ext/-test-/cxxanyargs/cxxanyargs.cpp
@@ -97,31 +97,6 @@ struct test_rb_define_hooked_variable {
};
VALUE test_rb_define_hooked_variable::v = Qundef;
-namespace test_rb_iterate {
- VALUE
- iter(VALUE self)
- {
- return rb_funcall(self, rb_intern("yield"), 0);
- }
-
- VALUE
- block(RB_BLOCK_CALL_FUNC_ARGLIST(arg, param))
- {
- return rb_funcall(arg, rb_intern("=="), 1, param);
- }
-
- VALUE
- test(VALUE self)
- {
-#ifdef HAVE_NULLPTR
- rb_iterate(iter, self, nullptr, self);
-#endif
-
- rb_iterate(iter, self, RUBY_METHOD_FUNC(block), self); // old
- return rb_iterate(iter, self, block, self); // new
- }
-}
-
namespace test_rb_block_call {
VALUE
block(RB_BLOCK_CALL_FUNC_ARGLIST(arg, param))
@@ -936,7 +911,6 @@ Init_cxxanyargs(void)
test(rb_define_virtual_variable);
test(rb_define_hooked_variable);
- test(rb_iterate);
test(rb_block_call);
test(rb_rescue);
test(rb_rescue2);
diff --git a/ext/-test-/fatal/invalid.c b/ext/-test-/fatal/invalid.c
index 393465416a..6fd970b181 100644
--- a/ext/-test-/fatal/invalid.c
+++ b/ext/-test-/fatal/invalid.c
@@ -1,11 +1,5 @@
#include <ruby.h>
-#if SIZEOF_LONG == SIZEOF_VOIDP
-# define NUM2PTR(x) NUM2ULONG(x)
-#elif SIZEOF_LONG_LONG == SIZEOF_VOIDP
-# define NUM2PTR(x) NUM2ULL(x)
-#endif
-
static VALUE
invalid_call(VALUE obj, VALUE address)
{
diff --git a/ext/-test-/integer/depend b/ext/-test-/integer/depend
index 0ea007e814..d0589b5e5d 100644
--- a/ext/-test-/integer/depend
+++ b/ext/-test-/integer/depend
@@ -159,8 +159,11 @@ core_ext.o: $(hdrdir)/ruby/missing.h
core_ext.o: $(hdrdir)/ruby/ruby.h
core_ext.o: $(hdrdir)/ruby/st.h
core_ext.o: $(hdrdir)/ruby/subst.h
+core_ext.o: $(top_srcdir)/internal.h
+core_ext.o: $(top_srcdir)/internal/basic_operators.h
core_ext.o: $(top_srcdir)/internal/bignum.h
core_ext.o: $(top_srcdir)/internal/bits.h
+core_ext.o: $(top_srcdir)/internal/compar.h
core_ext.o: $(top_srcdir)/internal/compilers.h
core_ext.o: $(top_srcdir)/internal/fixnum.h
core_ext.o: $(top_srcdir)/internal/numeric.h
diff --git a/ext/-test-/namespace/yay1/extconf.rb b/ext/-test-/namespace/yay1/extconf.rb
deleted file mode 100644
index 539e99ab09..0000000000
--- a/ext/-test-/namespace/yay1/extconf.rb
+++ /dev/null
@@ -1 +0,0 @@
-create_makefile('-test-/namespace/yay1')
diff --git a/ext/-test-/namespace/yay2/extconf.rb b/ext/-test-/namespace/yay2/extconf.rb
deleted file mode 100644
index 2027a42860..0000000000
--- a/ext/-test-/namespace/yay2/extconf.rb
+++ /dev/null
@@ -1 +0,0 @@
-create_makefile('-test-/namespace/yay2')
diff --git a/ext/-test-/postponed_job/postponed_job.c b/ext/-test-/postponed_job/postponed_job.c
index 9ac866ae77..4426fc3104 100644
--- a/ext/-test-/postponed_job/postponed_job.c
+++ b/ext/-test-/postponed_job/postponed_job.c
@@ -36,38 +36,6 @@ pjob_callback(void *data)
}
static VALUE
-pjob_register(VALUE self, VALUE obj)
-{
- counter = 0;
- rb_postponed_job_register(0, pjob_callback, (void *)obj);
- rb_gc_start();
- counter++;
- rb_gc_start();
- counter++;
- rb_gc_start();
- counter++;
- return self;
-}
-
-static void
-pjob_one_callback(void *data)
-{
- VALUE ary = (VALUE)data;
- Check_Type(ary, T_ARRAY);
-
- rb_ary_push(ary, INT2FIX(1));
-}
-
-static VALUE
-pjob_register_one(VALUE self, VALUE obj)
-{
- rb_postponed_job_register_one(0, pjob_one_callback, (void *)obj);
- rb_postponed_job_register_one(0, pjob_one_callback, (void *)obj);
- rb_postponed_job_register_one(0, pjob_one_callback, (void *)obj);
- return self;
-}
-
-static VALUE
pjob_call_direct(VALUE self, VALUE obj)
{
counter = 0;
@@ -83,48 +51,6 @@ pjob_call_direct(VALUE self, VALUE obj)
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>
-
-static void *
-pjob_register_in_c_thread_i(void *obj)
-{
- rb_postponed_job_register_one(0, pjob_one_callback, (void *)obj);
- rb_postponed_job_register_one(0, pjob_one_callback, (void *)obj);
- rb_postponed_job_register_one(0, pjob_one_callback, (void *)obj);
- return NULL;
-}
-
-static VALUE
-pjob_register_in_c_thread(VALUE self, VALUE obj)
-{
- pthread_t thread;
- if (pthread_create(&thread, NULL, pjob_register_in_c_thread_i, (void *)obj)) {
- return Qfalse;
- }
-
- if (pthread_join(thread, NULL)) {
- return Qfalse;
- }
-
- return Qtrue;
-}
-#endif
-
static void
pjob_preregistered_callback(void *data)
{
@@ -216,13 +142,7 @@ void
Init_postponed_job(VALUE self)
{
VALUE mBug = rb_define_module("Bug");
- 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);
diff --git a/ext/-test-/rational/depend b/ext/-test-/rational/depend
index 56d6ab77d6..d949fca66b 100644
--- a/ext/-test-/rational/depend
+++ b/ext/-test-/rational/depend
@@ -163,8 +163,11 @@ rat.o: $(hdrdir)/ruby/missing.h
rat.o: $(hdrdir)/ruby/ruby.h
rat.o: $(hdrdir)/ruby/st.h
rat.o: $(hdrdir)/ruby/subst.h
+rat.o: $(top_srcdir)/internal.h
+rat.o: $(top_srcdir)/internal/basic_operators.h
rat.o: $(top_srcdir)/internal/bignum.h
rat.o: $(top_srcdir)/internal/bits.h
+rat.o: $(top_srcdir)/internal/compar.h
rat.o: $(top_srcdir)/internal/compilers.h
rat.o: $(top_srcdir)/internal/fixnum.h
rat.o: $(top_srcdir)/internal/gc.h
diff --git a/ext/-test-/sanitizers/depend b/ext/-test-/sanitizers/depend
new file mode 100644
index 0000000000..0e6e632803
--- /dev/null
+++ b/ext/-test-/sanitizers/depend
@@ -0,0 +1,162 @@
+# AUTOGENERATED DEPENDENCIES START
+sanitizers.o: $(RUBY_EXTCONF_H)
+sanitizers.o: $(arch_hdrdir)/ruby/config.h
+sanitizers.o: $(hdrdir)/ruby/assert.h
+sanitizers.o: $(hdrdir)/ruby/backward.h
+sanitizers.o: $(hdrdir)/ruby/backward/2/assume.h
+sanitizers.o: $(hdrdir)/ruby/backward/2/attributes.h
+sanitizers.o: $(hdrdir)/ruby/backward/2/bool.h
+sanitizers.o: $(hdrdir)/ruby/backward/2/inttypes.h
+sanitizers.o: $(hdrdir)/ruby/backward/2/limits.h
+sanitizers.o: $(hdrdir)/ruby/backward/2/long_long.h
+sanitizers.o: $(hdrdir)/ruby/backward/2/stdalign.h
+sanitizers.o: $(hdrdir)/ruby/backward/2/stdarg.h
+sanitizers.o: $(hdrdir)/ruby/defines.h
+sanitizers.o: $(hdrdir)/ruby/intern.h
+sanitizers.o: $(hdrdir)/ruby/internal/abi.h
+sanitizers.o: $(hdrdir)/ruby/internal/anyargs.h
+sanitizers.o: $(hdrdir)/ruby/internal/arithmetic.h
+sanitizers.o: $(hdrdir)/ruby/internal/arithmetic/char.h
+sanitizers.o: $(hdrdir)/ruby/internal/arithmetic/double.h
+sanitizers.o: $(hdrdir)/ruby/internal/arithmetic/fixnum.h
+sanitizers.o: $(hdrdir)/ruby/internal/arithmetic/gid_t.h
+sanitizers.o: $(hdrdir)/ruby/internal/arithmetic/int.h
+sanitizers.o: $(hdrdir)/ruby/internal/arithmetic/intptr_t.h
+sanitizers.o: $(hdrdir)/ruby/internal/arithmetic/long.h
+sanitizers.o: $(hdrdir)/ruby/internal/arithmetic/long_long.h
+sanitizers.o: $(hdrdir)/ruby/internal/arithmetic/mode_t.h
+sanitizers.o: $(hdrdir)/ruby/internal/arithmetic/off_t.h
+sanitizers.o: $(hdrdir)/ruby/internal/arithmetic/pid_t.h
+sanitizers.o: $(hdrdir)/ruby/internal/arithmetic/short.h
+sanitizers.o: $(hdrdir)/ruby/internal/arithmetic/size_t.h
+sanitizers.o: $(hdrdir)/ruby/internal/arithmetic/st_data_t.h
+sanitizers.o: $(hdrdir)/ruby/internal/arithmetic/uid_t.h
+sanitizers.o: $(hdrdir)/ruby/internal/assume.h
+sanitizers.o: $(hdrdir)/ruby/internal/attr/alloc_size.h
+sanitizers.o: $(hdrdir)/ruby/internal/attr/artificial.h
+sanitizers.o: $(hdrdir)/ruby/internal/attr/cold.h
+sanitizers.o: $(hdrdir)/ruby/internal/attr/const.h
+sanitizers.o: $(hdrdir)/ruby/internal/attr/constexpr.h
+sanitizers.o: $(hdrdir)/ruby/internal/attr/deprecated.h
+sanitizers.o: $(hdrdir)/ruby/internal/attr/diagnose_if.h
+sanitizers.o: $(hdrdir)/ruby/internal/attr/enum_extensibility.h
+sanitizers.o: $(hdrdir)/ruby/internal/attr/error.h
+sanitizers.o: $(hdrdir)/ruby/internal/attr/flag_enum.h
+sanitizers.o: $(hdrdir)/ruby/internal/attr/forceinline.h
+sanitizers.o: $(hdrdir)/ruby/internal/attr/format.h
+sanitizers.o: $(hdrdir)/ruby/internal/attr/maybe_unused.h
+sanitizers.o: $(hdrdir)/ruby/internal/attr/noalias.h
+sanitizers.o: $(hdrdir)/ruby/internal/attr/nodiscard.h
+sanitizers.o: $(hdrdir)/ruby/internal/attr/noexcept.h
+sanitizers.o: $(hdrdir)/ruby/internal/attr/noinline.h
+sanitizers.o: $(hdrdir)/ruby/internal/attr/nonnull.h
+sanitizers.o: $(hdrdir)/ruby/internal/attr/noreturn.h
+sanitizers.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
+sanitizers.o: $(hdrdir)/ruby/internal/attr/pure.h
+sanitizers.o: $(hdrdir)/ruby/internal/attr/restrict.h
+sanitizers.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
+sanitizers.o: $(hdrdir)/ruby/internal/attr/warning.h
+sanitizers.o: $(hdrdir)/ruby/internal/attr/weakref.h
+sanitizers.o: $(hdrdir)/ruby/internal/cast.h
+sanitizers.o: $(hdrdir)/ruby/internal/compiler_is.h
+sanitizers.o: $(hdrdir)/ruby/internal/compiler_is/apple.h
+sanitizers.o: $(hdrdir)/ruby/internal/compiler_is/clang.h
+sanitizers.o: $(hdrdir)/ruby/internal/compiler_is/gcc.h
+sanitizers.o: $(hdrdir)/ruby/internal/compiler_is/intel.h
+sanitizers.o: $(hdrdir)/ruby/internal/compiler_is/msvc.h
+sanitizers.o: $(hdrdir)/ruby/internal/compiler_is/sunpro.h
+sanitizers.o: $(hdrdir)/ruby/internal/compiler_since.h
+sanitizers.o: $(hdrdir)/ruby/internal/config.h
+sanitizers.o: $(hdrdir)/ruby/internal/constant_p.h
+sanitizers.o: $(hdrdir)/ruby/internal/core.h
+sanitizers.o: $(hdrdir)/ruby/internal/core/rarray.h
+sanitizers.o: $(hdrdir)/ruby/internal/core/rbasic.h
+sanitizers.o: $(hdrdir)/ruby/internal/core/rbignum.h
+sanitizers.o: $(hdrdir)/ruby/internal/core/rclass.h
+sanitizers.o: $(hdrdir)/ruby/internal/core/rdata.h
+sanitizers.o: $(hdrdir)/ruby/internal/core/rfile.h
+sanitizers.o: $(hdrdir)/ruby/internal/core/rhash.h
+sanitizers.o: $(hdrdir)/ruby/internal/core/robject.h
+sanitizers.o: $(hdrdir)/ruby/internal/core/rregexp.h
+sanitizers.o: $(hdrdir)/ruby/internal/core/rstring.h
+sanitizers.o: $(hdrdir)/ruby/internal/core/rstruct.h
+sanitizers.o: $(hdrdir)/ruby/internal/core/rtypeddata.h
+sanitizers.o: $(hdrdir)/ruby/internal/ctype.h
+sanitizers.o: $(hdrdir)/ruby/internal/dllexport.h
+sanitizers.o: $(hdrdir)/ruby/internal/dosish.h
+sanitizers.o: $(hdrdir)/ruby/internal/error.h
+sanitizers.o: $(hdrdir)/ruby/internal/eval.h
+sanitizers.o: $(hdrdir)/ruby/internal/event.h
+sanitizers.o: $(hdrdir)/ruby/internal/fl_type.h
+sanitizers.o: $(hdrdir)/ruby/internal/gc.h
+sanitizers.o: $(hdrdir)/ruby/internal/glob.h
+sanitizers.o: $(hdrdir)/ruby/internal/globals.h
+sanitizers.o: $(hdrdir)/ruby/internal/has/attribute.h
+sanitizers.o: $(hdrdir)/ruby/internal/has/builtin.h
+sanitizers.o: $(hdrdir)/ruby/internal/has/c_attribute.h
+sanitizers.o: $(hdrdir)/ruby/internal/has/cpp_attribute.h
+sanitizers.o: $(hdrdir)/ruby/internal/has/declspec_attribute.h
+sanitizers.o: $(hdrdir)/ruby/internal/has/extension.h
+sanitizers.o: $(hdrdir)/ruby/internal/has/feature.h
+sanitizers.o: $(hdrdir)/ruby/internal/has/warning.h
+sanitizers.o: $(hdrdir)/ruby/internal/intern/array.h
+sanitizers.o: $(hdrdir)/ruby/internal/intern/bignum.h
+sanitizers.o: $(hdrdir)/ruby/internal/intern/class.h
+sanitizers.o: $(hdrdir)/ruby/internal/intern/compar.h
+sanitizers.o: $(hdrdir)/ruby/internal/intern/complex.h
+sanitizers.o: $(hdrdir)/ruby/internal/intern/cont.h
+sanitizers.o: $(hdrdir)/ruby/internal/intern/dir.h
+sanitizers.o: $(hdrdir)/ruby/internal/intern/enum.h
+sanitizers.o: $(hdrdir)/ruby/internal/intern/enumerator.h
+sanitizers.o: $(hdrdir)/ruby/internal/intern/error.h
+sanitizers.o: $(hdrdir)/ruby/internal/intern/eval.h
+sanitizers.o: $(hdrdir)/ruby/internal/intern/file.h
+sanitizers.o: $(hdrdir)/ruby/internal/intern/hash.h
+sanitizers.o: $(hdrdir)/ruby/internal/intern/io.h
+sanitizers.o: $(hdrdir)/ruby/internal/intern/load.h
+sanitizers.o: $(hdrdir)/ruby/internal/intern/marshal.h
+sanitizers.o: $(hdrdir)/ruby/internal/intern/numeric.h
+sanitizers.o: $(hdrdir)/ruby/internal/intern/object.h
+sanitizers.o: $(hdrdir)/ruby/internal/intern/parse.h
+sanitizers.o: $(hdrdir)/ruby/internal/intern/proc.h
+sanitizers.o: $(hdrdir)/ruby/internal/intern/process.h
+sanitizers.o: $(hdrdir)/ruby/internal/intern/random.h
+sanitizers.o: $(hdrdir)/ruby/internal/intern/range.h
+sanitizers.o: $(hdrdir)/ruby/internal/intern/rational.h
+sanitizers.o: $(hdrdir)/ruby/internal/intern/re.h
+sanitizers.o: $(hdrdir)/ruby/internal/intern/ruby.h
+sanitizers.o: $(hdrdir)/ruby/internal/intern/select.h
+sanitizers.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+sanitizers.o: $(hdrdir)/ruby/internal/intern/set.h
+sanitizers.o: $(hdrdir)/ruby/internal/intern/signal.h
+sanitizers.o: $(hdrdir)/ruby/internal/intern/sprintf.h
+sanitizers.o: $(hdrdir)/ruby/internal/intern/string.h
+sanitizers.o: $(hdrdir)/ruby/internal/intern/struct.h
+sanitizers.o: $(hdrdir)/ruby/internal/intern/thread.h
+sanitizers.o: $(hdrdir)/ruby/internal/intern/time.h
+sanitizers.o: $(hdrdir)/ruby/internal/intern/variable.h
+sanitizers.o: $(hdrdir)/ruby/internal/intern/vm.h
+sanitizers.o: $(hdrdir)/ruby/internal/interpreter.h
+sanitizers.o: $(hdrdir)/ruby/internal/iterator.h
+sanitizers.o: $(hdrdir)/ruby/internal/memory.h
+sanitizers.o: $(hdrdir)/ruby/internal/method.h
+sanitizers.o: $(hdrdir)/ruby/internal/module.h
+sanitizers.o: $(hdrdir)/ruby/internal/newobj.h
+sanitizers.o: $(hdrdir)/ruby/internal/scan_args.h
+sanitizers.o: $(hdrdir)/ruby/internal/special_consts.h
+sanitizers.o: $(hdrdir)/ruby/internal/static_assert.h
+sanitizers.o: $(hdrdir)/ruby/internal/stdalign.h
+sanitizers.o: $(hdrdir)/ruby/internal/stdbool.h
+sanitizers.o: $(hdrdir)/ruby/internal/stdckdint.h
+sanitizers.o: $(hdrdir)/ruby/internal/symbol.h
+sanitizers.o: $(hdrdir)/ruby/internal/value.h
+sanitizers.o: $(hdrdir)/ruby/internal/value_type.h
+sanitizers.o: $(hdrdir)/ruby/internal/variable.h
+sanitizers.o: $(hdrdir)/ruby/internal/warning_push.h
+sanitizers.o: $(hdrdir)/ruby/internal/xmalloc.h
+sanitizers.o: $(hdrdir)/ruby/missing.h
+sanitizers.o: $(hdrdir)/ruby/ruby.h
+sanitizers.o: $(hdrdir)/ruby/st.h
+sanitizers.o: $(hdrdir)/ruby/subst.h
+sanitizers.o: sanitizers.c
+# AUTOGENERATED DEPENDENCIES END
diff --git a/ext/-test-/sanitizers/extconf.rb b/ext/-test-/sanitizers/extconf.rb
new file mode 100644
index 0000000000..c94a96de6c
--- /dev/null
+++ b/ext/-test-/sanitizers/extconf.rb
@@ -0,0 +1,2 @@
+require 'mkmf'
+create_makefile('-test-/sanitizers')
diff --git a/ext/-test-/sanitizers/sanitizers.c b/ext/-test-/sanitizers/sanitizers.c
new file mode 100644
index 0000000000..97a85b26ef
--- /dev/null
+++ b/ext/-test-/sanitizers/sanitizers.c
@@ -0,0 +1,36 @@
+#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
+}
+
+static VALUE
+lsan_enabled_p(VALUE self)
+{
+#if defined(__has_feature)
+ /* clang uses __has_feature for determining LSAN */
+ return __has_feature(leak_sanitizer) ? Qtrue : Qfalse;
+#else
+ return Qfalse;
+#endif
+}
+
+void
+Init_sanitizers(void)
+{
+ VALUE m = rb_define_module("Test");
+ VALUE c = rb_define_class_under(m, "Sanitizers", rb_cObject);
+ rb_define_singleton_method(c, "asan_enabled?", asan_enabled_p, 0);
+ rb_define_singleton_method(c, "lsan_enabled?", lsan_enabled_p, 0);
+}
+
diff --git a/ext/-test-/scheduler/extconf.rb b/ext/-test-/scheduler/extconf.rb
new file mode 100644
index 0000000000..159699bd8e
--- /dev/null
+++ b/ext/-test-/scheduler/extconf.rb
@@ -0,0 +1,2 @@
+# frozen_string_literal: false
+create_makefile("-test-/scheduler")
diff --git a/ext/-test-/scheduler/scheduler.c b/ext/-test-/scheduler/scheduler.c
new file mode 100644
index 0000000000..b742a5573b
--- /dev/null
+++ b/ext/-test-/scheduler/scheduler.c
@@ -0,0 +1,92 @@
+#include "ruby/ruby.h"
+#include "ruby/thread.h"
+#include "ruby/io.h"
+#include "ruby/fiber/scheduler.h"
+
+/*
+ * Test extension for reproducing the gRPC interrupt handling bug.
+ *
+ * This reproduces the exact issue from grpc/grpc commit 69f229e (June 2025):
+ * https://github.com/grpc/grpc/commit/69f229edd1d79ab7a7dfda98e3aef6fd807adcad
+ *
+ * The bug occurs when:
+ * 1. A fiber scheduler uses Thread.handle_interrupt(::SignalException => :never)
+ * (like Async::Scheduler does)
+ * 2. Native code uses rb_thread_call_without_gvl in a retry loop that checks
+ * the interrupted flag and retries (like gRPC's completion queue)
+ * 3. A signal (SIGINT/SIGTERM) is sent
+ * 4. The unblock_func sets interrupted=1, but Thread.handle_interrupt defers the signal
+ * 5. The loop sees interrupted=1 and retries without yielding to the scheduler
+ * 6. The deferred interrupt never gets processed -> infinite hang
+ *
+ * The fix is in vm_check_ints_blocking() in thread.c, which should yield to
+ * the fiber scheduler when interrupts are pending, allowing the scheduler to
+ * detect Thread.pending_interrupt? and exit its run loop.
+ */
+
+struct blocking_state {
+ int notify_descriptor;
+ volatile int interrupted;
+};
+
+static void
+unblock_callback(void *argument)
+{
+ struct blocking_state *blocking_state = (struct blocking_state *)argument;
+ blocking_state->interrupted = 1;
+}
+
+static void *
+blocking_operation(void *argument)
+{
+ struct blocking_state *blocking_state = (struct blocking_state *)argument;
+
+ ssize_t ret = write(blocking_state->notify_descriptor, "x", 1);
+ (void)ret; // ignore the result for now
+
+ while (!blocking_state->interrupted) {
+ struct timeval tv = {1, 0}; // 1 second timeout.
+ int result = select(0, NULL, NULL, NULL, &tv);
+
+ if (result == -1 && errno == EINTR) {
+ blocking_state->interrupted = 1;
+ }
+
+ // Otherwise, timeout -> loop again.
+ }
+
+ return NULL;
+}
+
+static VALUE
+scheduler_blocking_loop(VALUE self, VALUE notify)
+{
+ struct blocking_state blocking_state = {
+ .notify_descriptor = rb_io_descriptor(notify),
+ .interrupted = 0,
+ };
+
+ while (true) {
+ blocking_state.interrupted = 0;
+
+ rb_thread_call_without_gvl(
+ blocking_operation, &blocking_state,
+ unblock_callback, &blocking_state
+ );
+
+ // The bug: When interrupted, loop retries without yielding to scheduler.
+ // With Thread.handle_interrupt(:never), this causes an infinite hang,
+ // because the deferred interrupt never gets a chance to be processed.
+ } while (blocking_state.interrupted);
+
+ return Qnil;
+}
+
+void
+Init_scheduler(void)
+{
+ VALUE mBug = rb_define_module("Bug");
+ VALUE mScheduler = rb_define_module_under(mBug, "Scheduler");
+
+ rb_define_module_function(mScheduler, "blocking_loop", scheduler_blocking_loop, 1);
+}
diff --git a/ext/-test-/st/foreach/foreach.c b/ext/-test-/st/foreach/foreach.c
index 7fbf064694..5c1bfd1631 100644
--- a/ext/-test-/st/foreach/foreach.c
+++ b/ext/-test-/st/foreach/foreach.c
@@ -14,13 +14,9 @@ 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");
-
/* 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 (key != c->nr) {
@@ -84,8 +80,6 @@ unp_fec(VALUE self, VALUE test)
st_add_direct(tbl, 0, 0);
- if (tbl->bins != NULL) rb_bug("should still be packed");
-
st_foreach_check(tbl, unp_fec_i, (st_data_t)&c, -1);
if (c.test == ID2SYM(rb_intern("delete2"))) {
@@ -98,8 +92,6 @@ unp_fec(VALUE self, VALUE test)
(VALUE)c.nr, (VALUE)expect_size);
}
- if (tbl->bins == NULL) rb_bug("should be unpacked");
-
st_free_table(tbl);
return Qnil;
@@ -145,8 +137,6 @@ unp_fe(VALUE self, VALUE test)
st_add_direct(tbl, 0, 0);
- if (tbl->bins != NULL) rb_bug("should still be packed");
-
st_foreach(tbl, unp_fe_i, (st_data_t)&c);
if (c.test == ID2SYM(rb_intern("unpack_delete"))) {
@@ -159,8 +149,6 @@ unp_fe(VALUE self, VALUE test)
(VALUE)c.nr, (VALUE)expect_size);
}
- if (tbl->bins == NULL) rb_bug("should be unpacked");
-
st_free_table(tbl);
return Qnil;
diff --git a/ext/-test-/stack/depend b/ext/-test-/stack/depend
index 31571c882e..77e93bb201 100644
--- a/ext/-test-/stack/depend
+++ b/ext/-test-/stack/depend
@@ -172,6 +172,7 @@ stack.o: $(hdrdir)/ruby/oniguruma.h
stack.o: $(hdrdir)/ruby/ruby.h
stack.o: $(hdrdir)/ruby/st.h
stack.o: $(hdrdir)/ruby/subst.h
+stack.o: $(top_srcdir)/encindex.h
stack.o: $(top_srcdir)/internal/compilers.h
stack.o: $(top_srcdir)/internal/string.h
stack.o: stack.c
diff --git a/ext/-test-/stack/stack.c b/ext/-test-/stack/stack.c
index 8ff32f9737..f0e65e74b2 100644
--- a/ext/-test-/stack/stack.c
+++ b/ext/-test-/stack/stack.c
@@ -2,7 +2,7 @@
#include "internal/string.h"
static VALUE
-stack_alloca_overflow(VALUE self)
+stack_overflow(VALUE self)
{
size_t i = 0;
@@ -30,6 +30,6 @@ asan_p(VALUE klass)
void
Init_stack(VALUE klass)
{
- rb_define_singleton_method(rb_cThread, "alloca_overflow", stack_alloca_overflow, 0);
+ rb_define_singleton_method(rb_cThread, "stack_overflow", stack_overflow, 0);
rb_define_singleton_method(rb_cThread, "asan?", asan_p, 0);
}
diff --git a/ext/-test-/string/cstr.c b/ext/-test-/string/cstr.c
index b0b1ef5374..931220b46b 100644
--- a/ext/-test-/string/cstr.c
+++ b/ext/-test-/string/cstr.c
@@ -111,9 +111,10 @@ bug_str_s_cstr_noembed(VALUE self, VALUE str)
FL_SET((str2), STR_NOEMBED);
memcpy(buf, RSTRING_PTR(str), capacity);
RBASIC(str2)->flags &= ~(STR_SHARED | FL_USER5 | FL_USER6);
- RSTRING(str2)->as.heap.aux.capa = capacity;
+ RSTRING(str2)->as.heap.aux.capa = RSTRING_LEN(str);
RSTRING(str2)->as.heap.ptr = buf;
RSTRING(str2)->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 de6e775acc..478ae3b82b 100644
--- a/ext/-test-/string/depend
+++ b/ext/-test-/string/depend
@@ -172,6 +172,7 @@ capacity.o: $(hdrdir)/ruby/oniguruma.h
capacity.o: $(hdrdir)/ruby/ruby.h
capacity.o: $(hdrdir)/ruby/st.h
capacity.o: $(hdrdir)/ruby/subst.h
+capacity.o: $(top_srcdir)/encindex.h
capacity.o: $(top_srcdir)/internal/compilers.h
capacity.o: $(top_srcdir)/internal/string.h
capacity.o: capacity.c
@@ -679,6 +680,7 @@ cstr.o: $(hdrdir)/ruby/oniguruma.h
cstr.o: $(hdrdir)/ruby/ruby.h
cstr.o: $(hdrdir)/ruby/st.h
cstr.o: $(hdrdir)/ruby/subst.h
+cstr.o: $(top_srcdir)/encindex.h
cstr.o: $(top_srcdir)/internal.h
cstr.o: $(top_srcdir)/internal/compilers.h
cstr.o: $(top_srcdir)/internal/string.h
@@ -1535,6 +1537,7 @@ 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)/encindex.h
fstring.o: $(top_srcdir)/internal/compilers.h
fstring.o: $(top_srcdir)/internal/string.h
fstring.o: fstring.c
diff --git a/ext/-test-/string/fstring.c b/ext/-test-/string/fstring.c
index 71c4b7f97e..0b5940f28c 100644
--- a/ext/-test-/string/fstring.c
+++ b/ext/-test-/string/fstring.c
@@ -12,20 +12,20 @@ VALUE
bug_s_fstring_fake_str(VALUE self)
{
static const char literal[] = "abcdefghijklmnopqrstuvwxyz";
- struct RString fake_str;
+ struct RString fake_str = {RBASIC_INIT};
return rb_str_to_interned_str(rb_setup_fake_str(&fake_str, literal, sizeof(literal) - 1, 0));
}
VALUE
bug_s_rb_enc_interned_str(VALUE self, VALUE encoding)
{
- return rb_enc_interned_str("foo", 3, NIL_P(encoding) ? NULL : RDATA(encoding)->data);
+ return rb_enc_interned_str("foo", 3, NIL_P(encoding) ? NULL : RTYPEDDATA_GET_DATA(encoding));
}
VALUE
bug_s_rb_enc_str_new(VALUE self, VALUE encoding)
{
- return rb_enc_str_new("foo", 3, NIL_P(encoding) ? NULL : RDATA(encoding)->data);
+ return rb_enc_str_new("foo", 3, NIL_P(encoding) ? NULL : RTYPEDDATA_GET_DATA(encoding));
}
void
diff --git a/ext/-test-/time/leap_second.c b/ext/-test-/time/leap_second.c
deleted file mode 100644
index ee7011fa97..0000000000
--- a/ext/-test-/time/leap_second.c
+++ /dev/null
@@ -1,15 +0,0 @@
-#include "ruby.h"
-#include "internal/time.h"
-
-static VALUE
-bug_time_s_reset_leap_second_info(VALUE klass)
-{
- ruby_reset_leap_second_info();
- return Qnil;
-}
-
-void
-Init_time_leap_second(VALUE klass)
-{
- rb_define_singleton_method(klass, "reset_leap_second_info", bug_time_s_reset_leap_second_info, 0);
-}
diff --git a/ext/-test-/tracepoint/gc_hook.c b/ext/-test-/tracepoint/gc_hook.c
index 54c06c54a5..525be6da63 100644
--- a/ext/-test-/tracepoint/gc_hook.c
+++ b/ext/-test-/tracepoint/gc_hook.c
@@ -2,6 +2,7 @@
#include "ruby/debug.h"
static int invoking; /* TODO: should not be global variable */
+extern VALUE tp_mBug;
static VALUE
invoke_proc_ensure(VALUE _)
@@ -17,9 +18,9 @@ invoke_proc_begin(VALUE proc)
}
static void
-invoke_proc(void *data)
+invoke_proc(void *ivar_name)
{
- VALUE proc = (VALUE)data;
+ VALUE proc = rb_ivar_get(tp_mBug, rb_intern(ivar_name));
invoking += 1;
rb_ensure(invoke_proc_begin, proc, invoke_proc_ensure, 0);
}
@@ -40,16 +41,16 @@ gc_start_end_i(VALUE tpval, void *data)
}
static VALUE
-set_gc_hook(VALUE module, VALUE proc, rb_event_flag_t event, const char *tp_str, const char *proc_str)
+set_gc_hook(VALUE proc, rb_event_flag_t event, const char *tp_str, const char *proc_str)
{
VALUE tpval;
ID tp_key = rb_intern(tp_str);
/* disable previous keys */
- if (rb_ivar_defined(module, tp_key) != 0 &&
- RTEST(tpval = rb_ivar_get(module, tp_key))) {
+ if (rb_ivar_defined(tp_mBug, tp_key) != 0 &&
+ RTEST(tpval = rb_ivar_get(tp_mBug, tp_key))) {
rb_tracepoint_disable(tpval);
- rb_ivar_set(module, tp_key, Qnil);
+ rb_ivar_set(tp_mBug, tp_key, Qnil);
}
if (RTEST(proc)) {
@@ -57,8 +58,9 @@ set_gc_hook(VALUE module, VALUE proc, rb_event_flag_t event, const char *tp_str,
rb_raise(rb_eTypeError, "trace_func needs to be Proc");
}
- tpval = rb_tracepoint_new(0, event, gc_start_end_i, (void *)proc);
- rb_ivar_set(module, tp_key, tpval);
+ rb_ivar_set(tp_mBug, rb_intern(proc_str), proc);
+ tpval = rb_tracepoint_new(0, event, gc_start_end_i, (void *)proc_str);
+ rb_ivar_set(tp_mBug, tp_key, tpval);
rb_tracepoint_enable(tpval);
}
@@ -66,16 +68,16 @@ set_gc_hook(VALUE module, VALUE proc, rb_event_flag_t event, const char *tp_str,
}
static VALUE
-set_after_gc_start(VALUE module, VALUE proc)
+set_after_gc_start(VALUE _self, VALUE proc)
{
- return set_gc_hook(module, proc, RUBY_INTERNAL_EVENT_GC_START,
+ return set_gc_hook(proc, RUBY_INTERNAL_EVENT_GC_START,
"__set_after_gc_start_tpval__", "__set_after_gc_start_proc__");
}
static VALUE
-start_after_gc_exit(VALUE module, VALUE proc)
+start_after_gc_exit(VALUE _self, VALUE proc)
{
- return set_gc_hook(module, proc, RUBY_INTERNAL_EVENT_GC_EXIT,
+ return set_gc_hook(proc, RUBY_INTERNAL_EVENT_GC_EXIT,
"__set_after_gc_exit_tpval__", "__set_after_gc_exit_proc__");
}
diff --git a/ext/-test-/tracepoint/tracepoint.c b/ext/-test-/tracepoint/tracepoint.c
index 2826cc038c..001d9513b2 100644
--- a/ext/-test-/tracepoint/tracepoint.c
+++ b/ext/-test-/tracepoint/tracepoint.c
@@ -1,6 +1,8 @@
#include "ruby/ruby.h"
#include "ruby/debug.h"
+VALUE tp_mBug;
+
struct tracepoint_track {
size_t newobj_count;
size_t free_count;
@@ -89,8 +91,8 @@ void Init_gc_hook(VALUE);
void
Init_tracepoint(void)
{
- VALUE mBug = rb_define_module("Bug");
- Init_gc_hook(mBug);
- rb_define_module_function(mBug, "tracepoint_track_objspace_events", tracepoint_track_objspace_events, 0);
- rb_define_module_function(mBug, "tracepoint_specify_normal_and_internal_events", tracepoint_specify_normal_and_internal_events, 0);
+ tp_mBug = rb_define_module("Bug"); // GC root
+ Init_gc_hook(tp_mBug);
+ rb_define_module_function(tp_mBug, "tracepoint_track_objspace_events", tracepoint_track_objspace_events, 0);
+ rb_define_module_function(tp_mBug, "tracepoint_specify_normal_and_internal_events", tracepoint_specify_normal_and_internal_events, 0);
}
diff --git a/ext/.document b/ext/.document
index 0d6c97ff73..d75c5c3d35 100644
--- a/ext/.document
+++ b/ext/.document
@@ -1,7 +1,5 @@
# Add files to this as they become documented
-bigdecimal/bigdecimal.c
-bigdecimal/lib
cgi/escape/escape.c
continuation/continuation.c
coverage/coverage.c
@@ -21,24 +19,12 @@ digest/sha2/sha2init.c
digest/sha2/lib
etc/etc.c
fcntl/fcntl.c
-fiddle/closure.c
-fiddle/conversions.c
-fiddle/fiddle.c
-fiddle/function.c
-fiddle/pinned.c
-fiddle/pointer.c
-fiddle/handle.c
-fiddle/lib
io/console/
io/nonblock/nonblock.c
io/wait/wait.c
json/generator/generator.c
json/lib
json/parser/parser.c
-monitor/lib
-monitor/monitor.c
-nkf/lib
-nkf/nkf.c
objspace/objspace.c
objspace/objspace_dump.c
objspace/object_tracing.c
@@ -84,17 +70,12 @@ psych/psych_to_ruby.c
psych/psych_yaml_tree.c
pty/lib
pty/pty.c
-racc/cparse/cparse.c
rbconfig/sizeof/*.c
-readline/readline.c
ripper/lib
socket
stringio/stringio.c
+strscan/lib
strscan/strscan.c
-syslog/syslog.c
-syslog/lib
win32/lib
win32/resolv/*.c
-win32ole/lib
-win32ole/*.c
zlib/zlib.c
diff --git a/ext/Setup b/ext/Setup
index 9c3e2f48fe..5cd4e95e27 100644
--- a/ext/Setup
+++ b/ext/Setup
@@ -1,39 +1,34 @@
#option nodynamic
-#bigdecimal
#cgi/escape
#continuation
#coverage
#date
-#digest/bubblebabble
#digest
+#digest/bubblebabble
#digest/md5
#digest/rmd160
#digest/sha1
#digest/sha2
+#erb/escape
#etc
#fcntl
-#fiddle
#io/console
#io/nonblock
#io/wait
#json
#json/generator
#json/parser
-#nkf
#objspace
#openssl
-#pathname
#psych
#pty
-#racc/cparse
#rbconfig/sizeof
-#readline
#ripper
+#rubyvm
#socket
#stringio
#strscan
-#syslog
#win32
-#win32ole
+#win32/resolv
#zlib
diff --git a/ext/Setup.atheos b/ext/Setup.atheos
index 91f73f32f9..73c8d5d5a8 100644
--- a/ext/Setup.atheos
+++ b/ext/Setup.atheos
@@ -1,24 +1,23 @@
option nodynamic
-bigdecimal
cgi/escape
-digest
-digest/md5
-digest/rmd160
-digest/sha1
-digest/sha2
+continuation
+coverage
+date
+digest/*
+erb/escape
etc
fcntl
-io/wait
-nkf
+io/*
+json
+json/*
+objspace
#openssl
pty
-#racc/cparse
-readline
+rbconfig/sizeof
ripper
socket
stringio
strscan
syslog
-#win32ole
zlib
diff --git a/ext/Setup.nt b/ext/Setup.nt
index 1278f183e4..a9e87249d3 100644
--- a/ext/Setup.nt
+++ b/ext/Setup.nt
@@ -1,25 +1,23 @@
#option platform cygwin|mingw|mswin
#option nodynamic
-bigdecimal
cgi/escape
-digest
-digest/md5
-digest/rmd160
-digest/sha1
-digest/sha2
+continuation
+coverage
+date
+digest/*
+erb/escape
etc
fcntl
-#io/wait
-nkf
+io/*
+json
+json/*
+objspace
#openssl
-#pty
-#racc/cparse
-#readline
+rbconfig/sizeof
#ripper
socket
stringio
strscan
#syslog
-win32ole
#zlib
diff --git a/ext/cgi/escape/escape.c b/ext/cgi/escape/escape.c
index 6b00bc37c1..4773186603 100644
--- a/ext/cgi/escape/escape.c
+++ b/ext/cgi/escape/escape.c
@@ -45,6 +45,7 @@ escaped_length(VALUE str)
static VALUE
optimized_escape_html(VALUE str)
{
+ VALUE escaped;
VALUE vbuf;
char *buf = ALLOCV_N(char, vbuf, escaped_length(str));
const char *cstr = RSTRING_PTR(str);
@@ -63,7 +64,6 @@ optimized_escape_html(VALUE str)
}
}
- VALUE escaped;
if (RSTRING_LEN(str) < (dest - buf)) {
escaped = rb_str_new(buf, dest - buf);
preserve_original_state(str, escaped);
diff --git a/ext/coverage/coverage.c b/ext/coverage/coverage.c
index 1519b559cd..1b0280b460 100644
--- a/ext/coverage/coverage.c
+++ b/ext/coverage/coverage.c
@@ -52,17 +52,29 @@ rb_coverage_supported(VALUE self, VALUE _mode)
/*
* call-seq:
- * Coverage.setup => nil
- * Coverage.setup(:all) => nil
- * Coverage.setup(lines: bool, branches: bool, methods: bool, eval: bool) => nil
- * Coverage.setup(oneshot_lines: true) => nil
+ * Coverage.setup -> nil
+ * Coverage.setup(type) -> nil
+ * Coverage.setup(lines: false, branches: false, methods: false, eval: false, oneshot_lines: false) -> nil
*
- * Set up the coverage measurement.
+ * Performs setup for coverage measurement, but does not start coverage measurement.
+ * To start coverage measurement, use Coverage.resume.
*
- * Note that this method does not start the measurement itself.
- * Use Coverage.resume to start the measurement.
+ * To perform both setup and start coverage measurement, Coverage.start can be used.
*
- * You may want to use Coverage.start to setup and then start the measurement.
+ * With argument +type+ given and +type+ is symbol +:all+, enables all types of coverage
+ * (lines, branches, methods, and eval).
+ *
+ * Keyword arguments or hash +type+ can be given with each of the following keys:
+ *
+ * - +lines+: Enables line coverage that records the number of times each line was executed.
+ * If +lines+ is enabled, +oneshot_lines+ cannot be enabled.
+ * See {Lines Coverage}[rdoc-ref:Coverage@Lines+Coverage].
+ * - +branches+: Enables branch coverage that records the number of times each
+ * branch in each conditional was executed. See {Branches Coverage}[rdoc-ref:Coverage@Branches+Coverage].
+ * - +methods+: Enables method coverage that records the number of times each method was exectued.
+ * See {Methods Coverage}[rdoc-ref:Coverage@Methods+Coverage].
+ * - +eval+: Enables coverage for evaluations (e.g. Kernel#eval, Module#class_eval).
+ * See {Eval Coverage}[rdoc-ref:Coverage@Eval+Coverage].
*/
static VALUE
rb_coverage_setup(int argc, VALUE *argv, VALUE klass)
@@ -152,14 +164,14 @@ rb_coverage_resume(VALUE klass)
/*
* call-seq:
- * Coverage.start => nil
- * Coverage.start(:all) => nil
- * Coverage.start(lines: bool, branches: bool, methods: bool, eval: bool) => nil
- * Coverage.start(oneshot_lines: true) => nil
- *
- * Enables the coverage measurement.
- * See the documentation of Coverage class in detail.
- * This is equivalent to Coverage.setup and Coverage.resume.
+ * Coverage.start -> nil
+ * Coverage.start(type) -> nil
+ * Coverage.start(lines: false, branches: false, methods: false, eval: false, oneshot_lines: false) -> nil
+ *
+ * Enables coverage measurement.
+ * This method is equivalent to calling Coverage.setup with the arguments provided,
+ * and then calling Coverage.resume. See their respective documentation for more
+ * details.
*/
static VALUE
rb_coverage_start(int argc, VALUE *argv, VALUE klass)
@@ -337,7 +349,7 @@ coverage_peek_result_i(st_data_t key, st_data_t val, st_data_t h)
* Coverage.peek_result => hash
*
* Returns a hash that contains filename as key and coverage array as value.
- * This is the same as `Coverage.result(stop: false, clear: false)`.
+ * This is the same as <tt>Coverage.result(stop: false, clear: false)</tt>.
*
* {
* "file.rb" => [1, 2, nil],
@@ -352,7 +364,6 @@ rb_coverage_peek_result(VALUE klass)
if (!RTEST(coverages)) {
rb_raise(rb_eRuntimeError, "coverage measurement is not enabled");
}
- OBJ_WB_UNPROTECT(coverages);
rb_hash_foreach(coverages, coverage_peek_result_i, ncoverages);
@@ -468,151 +479,217 @@ rb_coverage_running(VALUE klass)
return current_state == RUNNING ? Qtrue : Qfalse;
}
-/* Coverage provides coverage measurement feature for Ruby.
- * This feature is experimental, so these APIs may be changed in future.
+/* \Coverage provides coverage measurement feature for Ruby.
*
- * Caveat: Currently, only process-global coverage measurement is supported.
- * You cannot measure per-thread coverage.
+ * Only process-global coverage measurement is supported, meaning
+ * that coverage cannot be measure on a per-thread basis.
*
- * = Usage
+ * = Quick Start
*
- * 1. require "coverage"
- * 2. do Coverage.start
- * 3. require or load Ruby source file
- * 4. Coverage.result will return a hash that contains filename as key and
- * coverage array as value. A coverage array gives, for each line, the
- * number of line execution by the interpreter. A +nil+ value means
- * coverage is disabled for this line (lines like +else+ and +end+).
+ * 1. Load coverage using <tt>require "coverage"</tt>.
+ * 2. Call Coverage.start to set up and begin coverage measurement.
+ * 3. All Ruby code loaded following the call to Coverage.start will have
+ * coverage measurement.
+ * 4. Coverage results can be fetched by calling Coverage.result, which returns a
+ * hash that contains filenames as the keys and coverage arrays as the values.
+ * Each element of the coverage array gives the number of times each line was
+ * executed. A +nil+ value means coverage was disabled for that line (e.g.
+ * lines like +else+ and +end+).
*
* = Examples
*
- * [foo.rb]
- * s = 0
- * 10.times do |x|
- * s += x
- * end
+ * In file +fib.rb+:
*
- * if s == 45
- * p :ok
- * else
- * p :ng
+ * def fibonacci(n)
+ * if n == 0
+ * 0
+ * elsif n == 1
+ * 1
+ * else
+ * fibonacci(n - 1) + fibonacci(n - 2)
+ * end
* end
- * [EOF]
+ *
+ * puts fibonacci(10)
+ *
+ * In another file, coverage can be measured:
*
* require "coverage"
* Coverage.start
- * require "foo.rb"
- * p Coverage.result #=> {"foo.rb"=>[1, 1, 10, nil, nil, 1, 1, nil, 0, nil]}
+ * require "fib.rb"
+ * Coverage.result # => {"fib.rb" => [1, 177, 34, 143, 55, nil, 88, nil, nil, nil, 1]}
*
- * == Lines Coverage
+ * == Lines \Coverage
*
- * If a coverage mode is not explicitly specified when starting coverage, lines
- * coverage is what will run. It reports the number of line executions for each
- * line.
+ * Lines coverage reports the number of line executions for each line.
+ * If the coverage mode is not explicitly specified when starting coverage,
+ * lines coverage is used as the default.
*
* require "coverage"
* Coverage.start(lines: true)
- * require "foo.rb"
- * p Coverage.result #=> {"foo.rb"=>{:lines=>[1, 1, 10, nil, nil, 1, 1, nil, 0, nil]}}
+ * require "fib"
+ * Coverage.result # => {"fib.rb" => {lines: [1, 177, 34, 143, 55, nil, 88, nil, nil, nil, 1]}}
+ *
+ * The returned hash differs depending on how Coverage.setup or Coverage.start
+ * was executed.
+ *
+ * If Coverage.start or Coverage.setup was called with no arguments, it returns a
+ * hash which contains filenames as the keys and coverage arrays as the values.
*
- * The value of the lines coverage result is an array containing how many times
- * each line was executed. Order in this array is important. For example, the
- * first item in this array, at index 0, reports how many times line 1 of this
- * file was executed while coverage was run (which, in this example, is one
- * time).
+ * If Coverage.start or Coverage.setup was called with <tt>line: true</tt>, it
+ * returns a hash which contains filenames as the keys and hashes as the values.
+ * The value hash has a key +:lines+ where the value is a coverage array.
*
- * A +nil+ value means coverage is disabled for this line (lines like +else+
- * and +end+).
+ * Each element of the coverage array gives the number of times the line was
+ * executed. A +nil+ value in the coverage array means coverage was disabled
+ * for that line (e.g. lines like +else+ and +end+).
*
- * == Oneshot Lines Coverage
+ * == Oneshot Lines \Coverage
*
- * Oneshot lines coverage tracks and reports on the executed lines while
- * coverage is running. It will not report how many times a line was executed,
- * only that it was executed.
+ * Oneshot lines coverage is similar to lines coverage, but instead of reporting
+ * the number of times a line was executed, it only reports the lines that were
+ * executed.
*
* require "coverage"
* Coverage.start(oneshot_lines: true)
- * require "foo.rb"
- * p Coverage.result #=> {"foo.rb"=>{:oneshot_lines=>[1, 2, 3, 6, 7]}}
+ * require "fib"
+ * Coverage.result # => {"fib.rb" => {oneshot_lines: [1, 11, 2, 4, 7, 5, 3]}}
*
* The value of the oneshot lines coverage result is an array containing the
* line numbers that were executed.
*
- * == Branches Coverage
+ * == Branches \Coverage
*
- * Branches coverage reports how many times each branch within each conditional
+ * Branches coverage reports the number of times each branch within each conditional
* was executed.
*
* require "coverage"
* Coverage.start(branches: true)
- * require "foo.rb"
- * p Coverage.result #=> {"foo.rb"=>{:branches=>{[:if, 0, 6, 0, 10, 3]=>{[:then, 1, 7, 2, 7, 7]=>1, [:else, 2, 9, 2, 9, 7]=>0}}}}
+ * require "fib"
+ * Coverage.result
+ * # => {"fib.rb" => {
+ * # branches: {
+ * # [:if, 0, 2, 2, 8, 5] => {
+ * # [:then, 1, 3, 4, 3, 5] => 34,
+ * # [:else, 2, 4, 2, 8, 5] => 143},
+ * # [:if, 3, 4, 2, 8, 5] => {
+ * # [:then, 4, 5, 4, 5, 5] => 55,
+ * # [:else, 5, 7, 4, 7, 39] => 88}}}}
*
* Each entry within the branches hash is a conditional, the value of which is
- * another hash where each entry is a branch in that conditional. The values
- * are the number of times the method was executed, and the keys are identifying
- * information about the branch.
+ * another hash where each entry is a branch in that conditional. The keys are
+ * arrays containing information about the branch and the values are the number
+ * of times the branch was executed.
*
- * The information that makes up each key identifying branches or conditionals
- * is the following, from left to right:
+ * The information that makes up the array that are the keys for conditional or
+ * branches are the following, from left to right:
*
- * 1. A label for the type of branch or conditional.
+ * 1. A label for the type of branch or conditional (e.g. +:if+, +:then+, +:else+).
* 2. A unique identifier.
- * 3. The starting line number it appears on in the file.
- * 4. The starting column number it appears on in the file.
- * 5. The ending line number it appears on in the file.
- * 6. The ending column number it appears on in the file.
+ * 3. Starting line number.
+ * 4. Starting column number.
+ * 5. Ending line number.
+ * 6. Ending column number.
*
- * == Methods Coverage
+ * == Methods \Coverage
*
* Methods coverage reports how many times each method was executed.
*
- * [foo_method.rb]
- * class Greeter
- * def greet
- * "welcome!"
- * end
- * end
- *
- * def hello
- * "Hi"
- * end
- *
- * hello()
- * Greeter.new.greet()
- * [EOF]
- *
* require "coverage"
* Coverage.start(methods: true)
- * require "foo_method.rb"
- * p Coverage.result #=> {"foo_method.rb"=>{:methods=>{[Object, :hello, 7, 0, 9, 3]=>1, [Greeter, :greet, 2, 2, 4, 5]=>1}}}
+ * require "fib"
+ * p Coverage.result #=> {"fib.rb" => {methods: {[Object, :fibonacci, 1, 0, 9, 3] => 177}}}
*
- * Each entry within the methods hash represents a method. The values in this
- * hash are the number of times the method was executed, and the keys are
+ * Each entry within the methods hash represents a method. The keys are arrays
+ * containing hash are the number of times the method was executed, and the keys are
* identifying information about the method.
*
* The information that makes up each key identifying a method is the following,
* from left to right:
*
- * 1. The class.
- * 2. The method name.
- * 3. The starting line number the method appears on in the file.
- * 4. The starting column number the method appears on in the file.
- * 5. The ending line number the method appears on in the file.
- * 6. The ending column number the method appears on in the file.
+ * 1. Class that the method was defined in.
+ * 2. Method name as a Symbol.
+ * 3. Starting line number of the method.
+ * 4. Starting column number of the method.
+ * 5. Ending line number of the method.
+ * 6. Ending column number of the method.
*
- * == All Coverage Modes
+ * == Eval \Coverage
*
- * You can also run all modes of coverage simultaneously with this shortcut.
- * Note that running all coverage modes does not run both lines and oneshot
- * lines. Those modes cannot be run simultaneously. Lines coverage is run in
- * this case, because you can still use it to determine whether or not a line
- * was executed.
+ * Eval coverage can be combined with the coverage types above to track
+ * coverage for eval.
+ *
+ * require "coverage"
+ * Coverage.start(eval: true, lines: true)
+ *
+ * eval(<<~RUBY, nil, "eval 1")
+ * ary = []
+ * 10.times do |i|
+ * ary << "hello" * i
+ * end
+ * RUBY
+ *
+ * Coverage.result # => {"eval 1" => {lines: [1, 1, 10, nil]}}
+ *
+ * Note that the eval must have a filename assigned, otherwise coverage
+ * will not be measured.
+ *
+ * require "coverage"
+ * Coverage.start(eval: true, lines: true)
+ *
+ * eval(<<~RUBY)
+ * ary = []
+ * 10.times do |i|
+ * ary << "hello" * i
+ * end
+ * RUBY
+ *
+ * Coverage.result # => {"(eval)" => {lines: [nil, nil, nil, nil]}}
+ *
+ * Also note that if a line number is assigned to the eval and it is not 1,
+ * then the resulting coverage will be padded with +nil+ if the line number is
+ * greater than 1, and truncated if the line number is less than 1.
+ *
+ * require "coverage"
+ * Coverage.start(eval: true, lines: true)
+ *
+ * eval(<<~RUBY, nil, "eval 1", 3)
+ * ary = []
+ * 10.times do |i|
+ * ary << "hello" * i
+ * end
+ * RUBY
+ *
+ * eval(<<~RUBY, nil, "eval 2", -1)
+ * ary = []
+ * 10.times do |i|
+ * ary << "hello" * i
+ * end
+ * RUBY
+ *
+ * Coverage.result
+ * # => {"eval 1" => {lines: [nil, nil, 1, 1, 10, nil]}, "eval 2" => {lines: [10, nil]}}
+ *
+ * == All \Coverage Modes
+ *
+ * All modes of coverage can be enabled simultaneously using the Symbol +:all+.
+ * However, note that this mode runs lines coverage and not oneshot lines since
+ * they cannot be ran simultaneously.
*
* require "coverage"
* Coverage.start(:all)
- * require "foo.rb"
- * p Coverage.result #=> {"foo.rb"=>{:lines=>[1, 1, 10, nil, nil, 1, 1, nil, 0, nil], :branches=>{[:if, 0, 6, 0, 10, 3]=>{[:then, 1, 7, 2, 7, 7]=>1, [:else, 2, 9, 2, 9, 7]=>0}}, :methods=>{}}}
+ * require "fib"
+ * Coverage.result
+ * # => {"fib.rb" => {
+ * # lines: [1, 177, 34, 143, 55, nil, 88, nil, nil, nil, 1],
+ * # branches: {
+ * # [:if, 0, 2, 2, 8, 5] => {
+ * # [:then, 1, 3, 4, 3, 5] => 34,
+ * # [:else, 2, 4, 2, 8, 5] => 143},
+ * # [:if, 3, 4, 2, 8, 5] => {
+ * # [:then, 4, 5, 4, 5, 5] => 55,
+ * # [:else, 5, 7, 4, 7, 39] => 88}}}},
+ * # methods: {[Object, :fibonacci, 1, 0, 9, 3] => 177}}}
*/
void
Init_coverage(void)
diff --git a/ext/coverage/depend b/ext/coverage/depend
index e042bac7c4..fb7f9a95af 100644
--- a/ext/coverage/depend
+++ b/ext/coverage/depend
@@ -183,11 +183,11 @@ coverage.o: $(top_srcdir)/id_table.h
coverage.o: $(top_srcdir)/internal.h
coverage.o: $(top_srcdir)/internal/array.h
coverage.o: $(top_srcdir)/internal/basic_operators.h
+coverage.o: $(top_srcdir)/internal/box.h
coverage.o: $(top_srcdir)/internal/compilers.h
coverage.o: $(top_srcdir)/internal/gc.h
coverage.o: $(top_srcdir)/internal/hash.h
coverage.o: $(top_srcdir)/internal/imemo.h
-coverage.o: $(top_srcdir)/internal/namespace.h
coverage.o: $(top_srcdir)/internal/sanitizers.h
coverage.o: $(top_srcdir)/internal/serial.h
coverage.o: $(top_srcdir)/internal/set_table.h
diff --git a/ext/coverage/lib/coverage.rb b/ext/coverage/lib/coverage.rb
index f1923ef366..4bd20e22cb 100644
--- a/ext/coverage/lib/coverage.rb
+++ b/ext/coverage/lib/coverage.rb
@@ -1,6 +1,11 @@
require "coverage.so"
module Coverage
+ # call-seq:
+ # line_stub(file) -> array
+ #
+ # A simple helper function that creates the "stub" of line coverage
+ # from a given source code.
def self.line_stub(file)
lines = File.foreach(file).map { nil }
iseqs = [RubyVM::InstructionSequence.compile_file(file)]
diff --git a/ext/date/date_core.c b/ext/date/date_core.c
index dbee067f6b..72d697c8ea 100644
--- a/ext/date/date_core.c
+++ b/ext/date/date_core.c
@@ -27,7 +27,7 @@ static VALUE eDateError;
static VALUE half_days_in_day, day_in_nanoseconds;
static double positive_inf, negative_inf;
-// used by deconstruct_keys
+/* used by deconstruct_keys */
static VALUE sym_year, sym_month, sym_day, sym_yday, sym_wday;
static VALUE sym_hour, sym_min, sym_sec, sym_sec_fraction, sym_zone;
@@ -452,11 +452,43 @@ do {\
static int c_valid_civil_p(int, int, int, double,
int *, int *, int *, int *);
+/* Check if using pure Gregorian calendar (sg == -Infinity) */
+#define c_gregorian_only_p(sg) (isinf(sg) && (sg) < 0)
+
+/*
+ * Fast path macros for pure Gregorian calendar.
+ * Sets *rjd to the JD value, *ns to 1 (new style), and returns.
+ */
+#define GREGORIAN_JD_FAST_PATH_RET(sg, jd_expr, rjd, ns) \
+ if (c_gregorian_only_p(sg)) { \
+ *(rjd) = (jd_expr); \
+ *(ns) = 1; \
+ return 1; \
+ }
+
+#define GREGORIAN_JD_FAST_PATH(sg, jd_expr, rjd, ns) \
+ if (c_gregorian_only_p(sg)) { \
+ *(rjd) = (jd_expr); \
+ *(ns) = 1; \
+ return; \
+ }
+
+/* Forward declarations for Neri-Schneider optimized functions */
+static int c_gregorian_civil_to_jd(int y, int m, int d);
+static void c_gregorian_jd_to_civil(int jd, int *ry, int *rm, int *rd);
+static int c_gregorian_fdoy(int y);
+static int c_gregorian_ldoy(int y);
+static int c_gregorian_ldom_jd(int y, int m);
+static int ns_jd_in_range(int jd);
+
static int
c_find_fdoy(int y, double sg, int *rjd, int *ns)
{
int d, rm, rd;
+ GREGORIAN_JD_FAST_PATH_RET(sg, c_gregorian_fdoy(y), rjd, ns);
+
+ /* Keep existing loop for Julian/reform period */
for (d = 1; d < 31; d++)
if (c_valid_civil_p(y, 1, d, sg, &rm, &rd, rjd, ns))
return 1;
@@ -468,6 +500,9 @@ c_find_ldoy(int y, double sg, int *rjd, int *ns)
{
int i, rm, rd;
+ GREGORIAN_JD_FAST_PATH_RET(sg, c_gregorian_ldoy(y), rjd, ns);
+
+ /* Keep existing loop for Julian/reform period */
for (i = 0; i < 30; i++)
if (c_valid_civil_p(y, 12, 31 - i, sg, &rm, &rd, rjd, ns))
return 1;
@@ -493,6 +528,9 @@ c_find_ldom(int y, int m, double sg, int *rjd, int *ns)
{
int i, rm, rd;
+ GREGORIAN_JD_FAST_PATH_RET(sg, c_gregorian_ldom_jd(y, m), rjd, ns);
+
+ /* Keep existing loop for Julian/reform period */
for (i = 0; i < 30; i++)
if (c_valid_civil_p(y, m, 31 - i, sg, &rm, &rd, rjd, ns))
return 1;
@@ -502,55 +540,69 @@ c_find_ldom(int y, int m, double sg, int *rjd, int *ns)
static void
c_civil_to_jd(int y, int m, int d, double sg, int *rjd, int *ns)
{
- double a, b, jd;
+ int jd;
+
+ GREGORIAN_JD_FAST_PATH(sg, c_gregorian_civil_to_jd(y, m, d), rjd, ns);
+
+ /* Calculate Gregorian JD using optimized algorithm */
+ jd = c_gregorian_civil_to_jd(y, m, d);
- if (m <= 2) {
- y -= 1;
- m += 12;
- }
- a = floor(y / 100.0);
- b = 2 - a + floor(a / 4.0);
- jd = floor(365.25 * (y + 4716)) +
- floor(30.6001 * (m + 1)) +
- d + b - 1524;
if (jd < sg) {
- jd -= b;
+ /* Before Gregorian switchover - use Julian calendar */
+ int y2 = y, m2 = m;
+ if (m2 <= 2) {
+ y2 -= 1;
+ m2 += 12;
+ }
+ jd = (int)(floor(365.25 * (y2 + 4716)) +
+ floor(30.6001 * (m2 + 1)) +
+ d - 1524);
*ns = 0;
}
- else
+ else {
*ns = 1;
+ }
- *rjd = (int)jd;
+ *rjd = jd;
}
static void
c_jd_to_civil(int jd, double sg, int *ry, int *rm, int *rdom)
{
- double x, a, b, c, d, e, y, m, dom;
-
- if (jd < sg)
- a = jd;
- else {
- x = floor((jd - 1867216.25) / 36524.25);
- a = jd + 1 + x - floor(x / 4.0);
- }
- b = a + 1524;
- c = floor((b - 122.1) / 365.25);
- d = floor(365.25 * c);
- e = floor((b - d) / 30.6001);
- dom = b - d - floor(30.6001 * e);
- if (e <= 13) {
- m = e - 1;
- y = c - 4716;
- }
- else {
- m = e - 13;
- y = c - 4715;
+ /* Fast path: pure Gregorian or date after switchover, within safe range */
+ if ((c_gregorian_only_p(sg) || jd >= sg) && ns_jd_in_range(jd)) {
+ c_gregorian_jd_to_civil(jd, ry, rm, rdom);
+ return;
}
- *ry = (int)y;
- *rm = (int)m;
- *rdom = (int)dom;
+ /* Original algorithm for Julian calendar or extreme dates */
+ {
+ double x, a, b, c, d, e, y, m, dom;
+
+ if (jd < sg)
+ a = jd;
+ else {
+ x = floor((jd - 1867216.25) / 36524.25);
+ a = jd + 1 + x - floor(x / 4.0);
+ }
+ b = a + 1524;
+ c = floor((b - 122.1) / 365.25);
+ d = floor(365.25 * c);
+ e = floor((b - d) / 30.6001);
+ dom = b - d - floor(30.6001 * e);
+ if (e <= 13) {
+ m = e - 1;
+ y = c - 4716;
+ }
+ else {
+ m = e - 13;
+ y = c - 4715;
+ }
+
+ *ry = (int)y;
+ *rm = (int)m;
+ *rdom = (int)dom;
+ }
}
static void
@@ -725,6 +777,147 @@ c_gregorian_last_day_of_month(int y, int m)
return monthtab[c_gregorian_leap_p(y) ? 1 : 0][m];
}
+/*
+ * Neri-Schneider algorithm for optimized Gregorian date conversion.
+ * Reference: Neri & Schneider, "Euclidean Affine Functions and Applications
+ * to Calendar Algorithms", Software: Practice and Experience, 2023.
+ * https://arxiv.org/abs/2102.06959
+ *
+ * This algorithm provides ~2-3x speedup over traditional floating-point
+ * implementations by using pure integer arithmetic with multiplication
+ * and bit-shifts instead of expensive division operations.
+ */
+
+/* JDN of March 1, Year 0 in proleptic Gregorian calendar */
+#define NS_EPOCH 1721120
+
+/* Days in a 4-year cycle (3 normal years + 1 leap year) */
+#define NS_DAYS_IN_4_YEARS 1461
+
+/* Days in a 400-year Gregorian cycle (97 leap years in 400 years) */
+#define NS_DAYS_IN_400_YEARS 146097
+
+/* Years per century */
+#define NS_YEARS_PER_CENTURY 100
+
+/*
+ * Multiplier for extracting year within century using fixed-point arithmetic.
+ * This is ceil(2^32 / NS_DAYS_IN_4_YEARS) for the Euclidean affine function.
+ */
+#define NS_YEAR_MULTIPLIER 2939745
+
+/*
+ * Coefficients for month calculation from day-of-year.
+ * Maps day-of-year to month using: month = (NS_MONTH_COEFF * doy + NS_MONTH_OFFSET) >> 16
+ */
+#define NS_MONTH_COEFF 2141
+#define NS_MONTH_OFFSET 197913
+
+/*
+ * Coefficients for civil date to JDN month contribution.
+ * Maps month to accumulated days: days = (NS_CIVIL_MONTH_COEFF * m - NS_CIVIL_MONTH_OFFSET) / 32
+ */
+#define NS_CIVIL_MONTH_COEFF 979
+#define NS_CIVIL_MONTH_OFFSET 2919
+#define NS_CIVIL_MONTH_DIVISOR 32
+
+/* Days from March 1 to December 31 (for Jan/Feb year adjustment) */
+#define NS_DAYS_BEFORE_NEW_YEAR 306
+
+/*
+ * Safe bounds for Neri-Schneider algorithm to avoid integer overflow.
+ * These correspond to approximately years -1,000,000 to +1,000,000.
+ */
+#define NS_JD_MIN -364000000
+#define NS_JD_MAX 538000000
+
+inline static int
+ns_jd_in_range(int jd)
+{
+ return jd >= NS_JD_MIN && jd <= NS_JD_MAX;
+}
+
+/* Optimized: Gregorian date -> Julian Day Number */
+static int
+c_gregorian_civil_to_jd(int y, int m, int d)
+{
+ /* Shift epoch to March 1 of year 0 (Jan/Feb belong to previous year) */
+ int j = (m < 3) ? 1 : 0;
+ int y0 = y - j;
+ int m0 = j ? m + 12 : m;
+ int d0 = d - 1;
+
+ /* Calculate year contribution with leap year correction */
+ int q1 = DIV(y0, NS_YEARS_PER_CENTURY);
+ int yc = DIV(NS_DAYS_IN_4_YEARS * y0, 4) - q1 + DIV(q1, 4);
+
+ /* Calculate month contribution using integer arithmetic */
+ int mc = (NS_CIVIL_MONTH_COEFF * m0 - NS_CIVIL_MONTH_OFFSET) / NS_CIVIL_MONTH_DIVISOR;
+
+ /* Combine and add epoch offset to get JDN */
+ return yc + mc + d0 + NS_EPOCH;
+}
+
+/* Optimized: Julian Day Number -> Gregorian date */
+static void
+c_gregorian_jd_to_civil(int jd, int *ry, int *rm, int *rd)
+{
+ int r0, n1, q1, r1, n2, q2, r2, n3, q3, r3, y0, j;
+ uint64_t u2;
+
+ /* Convert JDN to rata die (March 1, Year 0 epoch) */
+ r0 = jd - NS_EPOCH;
+
+ /* Extract century and day within 400-year cycle */
+ /* Use Euclidean (floor) division for negative values */
+ n1 = 4 * r0 + 3;
+ q1 = DIV(n1, NS_DAYS_IN_400_YEARS);
+ r1 = MOD(n1, NS_DAYS_IN_400_YEARS) / 4;
+
+ /* Calculate year within century and day of year */
+ n2 = 4 * r1 + 3;
+ /* Use 64-bit arithmetic to avoid overflow */
+ u2 = (uint64_t)NS_YEAR_MULTIPLIER * (uint64_t)n2;
+ q2 = (int)(u2 >> 32);
+ r2 = (int)((uint32_t)u2 / NS_YEAR_MULTIPLIER / 4);
+
+ /* Calculate month and day using integer arithmetic */
+ n3 = NS_MONTH_COEFF * r2 + NS_MONTH_OFFSET;
+ q3 = n3 >> 16;
+ r3 = (n3 & 0xFFFF) / NS_MONTH_COEFF;
+
+ /* Combine century and year */
+ y0 = NS_YEARS_PER_CENTURY * q1 + q2;
+
+ /* Adjust for January/February (shift from fiscal year) */
+ j = (r2 >= NS_DAYS_BEFORE_NEW_YEAR) ? 1 : 0;
+
+ *ry = y0 + j;
+ *rm = j ? q3 - 12 : q3;
+ *rd = r3 + 1;
+}
+
+/* O(1) first day of year for Gregorian calendar */
+inline static int
+c_gregorian_fdoy(int y)
+{
+ return c_gregorian_civil_to_jd(y, 1, 1);
+}
+
+/* O(1) last day of year for Gregorian calendar */
+inline static int
+c_gregorian_ldoy(int y)
+{
+ return c_gregorian_civil_to_jd(y, 12, 31);
+}
+
+/* O(1) last day of month (JDN) for Gregorian calendar */
+inline static int
+c_gregorian_ldom_jd(int y, int m)
+{
+ return c_gregorian_civil_to_jd(y, m, c_gregorian_last_day_of_month(y, m));
+}
+
static int
c_valid_julian_p(int y, int m, int d, int *rm, int *rd)
{
@@ -2498,7 +2691,7 @@ date_s__valid_jd_p(int argc, VALUE *argv, VALUE klass)
*
* Date.valid_jd?(2451944) # => true
*
- * See argument {start}[rdoc-ref:date/calendars.rdoc@Argument+start].
+ * See argument {start}[rdoc-ref:language/calendars.rdoc@Argument+start].
*
* Related: Date.jd.
*/
@@ -2592,7 +2785,7 @@ date_s__valid_civil_p(int argc, VALUE *argv, VALUE klass)
* Date.valid_date?(2001, 2, 29) # => false
* Date.valid_date?(2001, 2, -1) # => true
*
- * See argument {start}[rdoc-ref:date/calendars.rdoc@Argument+start].
+ * See argument {start}[rdoc-ref:language/calendars.rdoc@Argument+start].
*
* Related: Date.jd, Date.new.
*/
@@ -2680,7 +2873,7 @@ date_s__valid_ordinal_p(int argc, VALUE *argv, VALUE klass)
* Date.valid_ordinal?(2001, 34) # => true
* Date.valid_ordinal?(2001, 366) # => false
*
- * See argument {start}[rdoc-ref:date/calendars.rdoc@Argument+start].
+ * See argument {start}[rdoc-ref:language/calendars.rdoc@Argument+start].
*
* Related: Date.jd, Date.ordinal.
*/
@@ -2770,7 +2963,7 @@ date_s__valid_commercial_p(int argc, VALUE *argv, VALUE klass)
*
* See Date.commercial.
*
- * See argument {start}[rdoc-ref:date/calendars.rdoc@Argument+start].
+ * See argument {start}[rdoc-ref:language/calendars.rdoc@Argument+start].
*
* Related: Date.jd, Date.commercial.
*/
@@ -3350,7 +3543,7 @@ static VALUE d_lite_plus(VALUE, VALUE);
*
* Date.jd(Date::ITALY - 1).julian? # => true
*
- * See argument {start}[rdoc-ref:date/calendars.rdoc@Argument+start].
+ * See argument {start}[rdoc-ref:language/calendars.rdoc@Argument+start].
*
* Related: Date.new.
*/
@@ -3415,7 +3608,7 @@ date_s_jd(int argc, VALUE *argv, VALUE klass)
*
* Raises an exception if +yday+ is zero or out of range.
*
- * See argument {start}[rdoc-ref:date/calendars.rdoc@Argument+start].
+ * See argument {start}[rdoc-ref:language/calendars.rdoc@Argument+start].
*
* Related: Date.jd, Date.new.
*/
@@ -3492,7 +3685,7 @@ date_s_civil(int argc, VALUE *argv, VALUE klass)
* where +n+ is the number of days in the month;
* when the argument is negative, counts backward from the end of the month.
*
- * See argument {start}[rdoc-ref:date/calendars.rdoc@Argument+start].
+ * See argument {start}[rdoc-ref:language/calendars.rdoc@Argument+start].
*
* Related: Date.jd.
*/
@@ -3598,7 +3791,7 @@ date_initialize(int argc, VALUE *argv, VALUE self)
* Date.commercial(2020, 1, 1).to_s # => "2019-12-30"
Date.commercial(2020, 1, 7).to_s # => "2020-01-05"
*
- * See argument {start}[rdoc-ref:date/calendars.rdoc@Argument+start].
+ * See argument {start}[rdoc-ref:language/calendars.rdoc@Argument+start].
*
* Related: Date.jd, Date.new, Date.ordinal.
*/
@@ -3783,7 +3976,7 @@ static void set_sg(union DateData *, double);
*
* Date.today.to_s # => "2022-07-06"
*
- * See argument {start}[rdoc-ref:date/calendars.rdoc@Argument+start].
+ * See argument {start}[rdoc-ref:language/calendars.rdoc@Argument+start].
*
*/
static VALUE
@@ -3974,7 +4167,7 @@ rt_complete_frags(VALUE klass, VALUE hash)
rb_gc_register_mark_object(tab);
}
- k = Qnil;
+ k = a = Qnil;
{
long i, eno = 0;
@@ -4335,6 +4528,7 @@ date_s__strptime_internal(int argc, VALUE *argv, VALUE klass,
rb_scan_args(argc, argv, "11", &vstr, &vfmt);
StringValue(vstr);
+ if (argc > 1) StringValue(vfmt);
if (!rb_enc_str_asciicompat_p(vstr))
rb_raise(rb_eArgError,
"string should have ASCII compatible encoding");
@@ -4345,7 +4539,6 @@ date_s__strptime_internal(int argc, VALUE *argv, VALUE klass,
flen = strlen(default_fmt);
}
else {
- StringValue(vfmt);
if (!rb_enc_str_asciicompat_p(vfmt))
rb_raise(rb_eArgError,
"format should have ASCII compatible encoding");
@@ -4383,7 +4576,7 @@ date_s__strptime_internal(int argc, VALUE *argv, VALUE klass,
* Date._strptime('2001-02-03', '%Y-%m-%d') # => {:year=>2001, :mon=>2, :mday=>3}
*
* For other formats, see
- * {Formats for Dates and Times}[rdoc-ref:strftime_formatting.rdoc].
+ * {Formats for Dates and Times}[rdoc-ref:language/strftime_formatting.rdoc].
* (Unlike Date.strftime, does not support flags and width.)
*
* See also {strptime(3)}[https://man7.org/linux/man-pages/man3/strptime.3.html].
@@ -4412,10 +4605,10 @@ date_s__strptime(int argc, VALUE *argv, VALUE klass)
* Date.strptime('sat3feb01', '%a%d%b%y') # => #<Date: 2001-02-03>
*
* For other formats, see
- * {Formats for Dates and Times}[rdoc-ref:strftime_formatting.rdoc].
+ * {Formats for Dates and Times}[rdoc-ref:language/strftime_formatting.rdoc].
* (Unlike Date.strftime, does not support flags and width.)
*
- * See argument {start}[rdoc-ref:date/calendars.rdoc@Argument+start].
+ * See argument {start}[rdoc-ref:language/calendars.rdoc@Argument+start].
*
* See also {strptime(3)}[https://man7.org/linux/man-pages/man3/strptime.3.html].
*
@@ -4464,11 +4657,10 @@ get_limit(VALUE opt)
#define rb_category_warn(category, fmt) rb_warn(fmt)
#endif
-static void
+static VALUE
check_limit(VALUE str, VALUE opt)
{
size_t slen, limit;
- if (NIL_P(str)) return;
StringValue(str);
slen = RSTRING_LEN(str);
limit = get_limit(opt);
@@ -4476,6 +4668,7 @@ check_limit(VALUE str, VALUE opt)
rb_raise(rb_eArgError,
"string length (%"PRI_SIZE_PREFIX"u) exceeds the limit %"PRI_SIZE_PREFIX"u", slen, limit);
}
+ return str;
}
static VALUE
@@ -4484,8 +4677,7 @@ date_s__parse_internal(int argc, VALUE *argv, VALUE klass)
VALUE vstr, vcomp, hash, opt;
argc = rb_scan_args(argc, argv, "11:", &vstr, &vcomp, &opt);
- check_limit(vstr, opt);
- StringValue(vstr);
+ vstr = check_limit(vstr, opt);
if (!rb_enc_str_asciicompat_p(vstr))
rb_raise(rb_eArgError,
"string should have ASCII compatible encoding");
@@ -4505,7 +4697,7 @@ date_s__parse_internal(int argc, VALUE *argv, VALUE klass)
* This method recognizes many forms in +string+,
* but it is not a validator.
* For formats, see
- * {"Specialized Format Strings" in Formats for Dates and Times}[rdoc-ref:strftime_formatting.rdoc@Specialized+Format+Strings]
+ * {"Specialized Format Strings" in Formats for Dates and Times}[rdoc-ref:language/strftime_formatting.rdoc@Specialized+Format+Strings]
*
* If +string+ does not specify a valid date,
* the result is unpredictable;
@@ -4540,7 +4732,7 @@ date_s__parse(int argc, VALUE *argv, VALUE klass)
* This method recognizes many forms in +string+,
* but it is not a validator.
* For formats, see
- * {"Specialized Format Strings" in Formats for Dates and Times}[rdoc-ref:strftime_formatting.rdoc@Specialized+Format+Strings]
+ * {"Specialized Format Strings" in Formats for Dates and Times}[rdoc-ref:language/strftime_formatting.rdoc@Specialized+Format+Strings]
* If +string+ does not specify a valid date,
* the result is unpredictable;
* consider using Date._strptime instead.
@@ -4560,7 +4752,7 @@ date_s__parse(int argc, VALUE *argv, VALUE klass)
*
* See:
*
- * - Argument {start}[rdoc-ref:date/calendars.rdoc@Argument+start].
+ * - Argument {start}[rdoc-ref:language/calendars.rdoc@Argument+start].
* - Argument {limit}[rdoc-ref:Date@Argument+limit].
*
* Related: Date._parse (returns a hash).
@@ -4604,7 +4796,7 @@ VALUE date__jisx0301(VALUE);
* Date._iso8601(string, limit: 128) -> hash
*
* Returns a hash of values parsed from +string+, which should contain
- * an {ISO 8601 formatted date}[rdoc-ref:strftime_formatting.rdoc@ISO+8601+Format+Specifications]:
+ * an {ISO 8601 formatted date}[rdoc-ref:language/strftime_formatting.rdoc@ISO+8601+Format+Specifications]:
*
* d = Date.new(2001, 2, 3)
* s = d.iso8601 # => "2001-02-03"
@@ -4620,7 +4812,7 @@ date_s__iso8601(int argc, VALUE *argv, VALUE klass)
VALUE str, opt;
rb_scan_args(argc, argv, "1:", &str, &opt);
- check_limit(str, opt);
+ if (!NIL_P(str)) str = check_limit(str, opt);
return date__iso8601(str);
}
@@ -4631,7 +4823,7 @@ date_s__iso8601(int argc, VALUE *argv, VALUE klass)
*
* Returns a new \Date object with values parsed from +string+,
* which should contain
- * an {ISO 8601 formatted date}[rdoc-ref:strftime_formatting.rdoc@ISO+8601+Format+Specifications]:
+ * an {ISO 8601 formatted date}[rdoc-ref:language/strftime_formatting.rdoc@ISO+8601+Format+Specifications]:
*
* d = Date.new(2001, 2, 3)
* s = d.iso8601 # => "2001-02-03"
@@ -4639,7 +4831,7 @@ date_s__iso8601(int argc, VALUE *argv, VALUE klass)
*
* See:
*
- * - Argument {start}[rdoc-ref:date/calendars.rdoc@Argument+start].
+ * - Argument {start}[rdoc-ref:language/calendars.rdoc@Argument+start].
* - Argument {limit}[rdoc-ref:Date@Argument+limit].
*
* Related: Date._iso8601 (returns a hash).
@@ -4673,7 +4865,7 @@ date_s_iso8601(int argc, VALUE *argv, VALUE klass)
* Date._rfc3339(string, limit: 128) -> hash
*
* Returns a hash of values parsed from +string+, which should be a valid
- * {RFC 3339 format}[rdoc-ref:strftime_formatting.rdoc@RFC+3339+Format]:
+ * {RFC 3339 format}[rdoc-ref:language/strftime_formatting.rdoc@RFC+3339+Format]:
*
* d = Date.new(2001, 2, 3)
* s = d.rfc3339 # => "2001-02-03T00:00:00+00:00"
@@ -4690,7 +4882,7 @@ date_s__rfc3339(int argc, VALUE *argv, VALUE klass)
VALUE str, opt;
rb_scan_args(argc, argv, "1:", &str, &opt);
- check_limit(str, opt);
+ if (!NIL_P(str)) str = check_limit(str, opt);
return date__rfc3339(str);
}
@@ -4701,7 +4893,7 @@ date_s__rfc3339(int argc, VALUE *argv, VALUE klass)
*
* Returns a new \Date object with values parsed from +string+,
* which should be a valid
- * {RFC 3339 format}[rdoc-ref:strftime_formatting.rdoc@RFC+3339+Format]:
+ * {RFC 3339 format}[rdoc-ref:language/strftime_formatting.rdoc@RFC+3339+Format]:
*
* d = Date.new(2001, 2, 3)
* s = d.rfc3339 # => "2001-02-03T00:00:00+00:00"
@@ -4709,7 +4901,7 @@ date_s__rfc3339(int argc, VALUE *argv, VALUE klass)
*
* See:
*
- * - Argument {start}[rdoc-ref:date/calendars.rdoc@Argument+start].
+ * - Argument {start}[rdoc-ref:language/calendars.rdoc@Argument+start].
* - Argument {limit}[rdoc-ref:Date@Argument+limit].
*
* Related: Date._rfc3339 (returns a hash).
@@ -4759,7 +4951,7 @@ date_s__xmlschema(int argc, VALUE *argv, VALUE klass)
VALUE str, opt;
rb_scan_args(argc, argv, "1:", &str, &opt);
- check_limit(str, opt);
+ if (!NIL_P(str)) str = check_limit(str, opt);
return date__xmlschema(str);
}
@@ -4777,7 +4969,7 @@ date_s__xmlschema(int argc, VALUE *argv, VALUE klass)
*
* See:
*
- * - Argument {start}[rdoc-ref:date/calendars.rdoc@Argument+start].
+ * - Argument {start}[rdoc-ref:language/calendars.rdoc@Argument+start].
* - Argument {limit}[rdoc-ref:Date@Argument+limit].
*
* Related: Date._xmlschema (returns a hash).
@@ -4811,7 +5003,7 @@ date_s_xmlschema(int argc, VALUE *argv, VALUE klass)
* Date._rfc2822(string, limit: 128) -> hash
*
* Returns a hash of values parsed from +string+, which should be a valid
- * {RFC 2822 date format}[rdoc-ref:strftime_formatting.rdoc@RFC+2822+Format]:
+ * {RFC 2822 date format}[rdoc-ref:language/strftime_formatting.rdoc@RFC+2822+Format]:
*
* d = Date.new(2001, 2, 3)
* s = d.rfc2822 # => "Sat, 3 Feb 2001 00:00:00 +0000"
@@ -4828,7 +5020,7 @@ date_s__rfc2822(int argc, VALUE *argv, VALUE klass)
VALUE str, opt;
rb_scan_args(argc, argv, "1:", &str, &opt);
- check_limit(str, opt);
+ if (!NIL_P(str)) str = check_limit(str, opt);
return date__rfc2822(str);
}
@@ -4839,7 +5031,7 @@ date_s__rfc2822(int argc, VALUE *argv, VALUE klass)
*
* Returns a new \Date object with values parsed from +string+,
* which should be a valid
- * {RFC 2822 date format}[rdoc-ref:strftime_formatting.rdoc@RFC+2822+Format]:
+ * {RFC 2822 date format}[rdoc-ref:language/strftime_formatting.rdoc@RFC+2822+Format]:
*
* d = Date.new(2001, 2, 3)
* s = d.rfc2822 # => "Sat, 3 Feb 2001 00:00:00 +0000"
@@ -4847,7 +5039,7 @@ date_s__rfc2822(int argc, VALUE *argv, VALUE klass)
*
* See:
*
- * - Argument {start}[rdoc-ref:date/calendars.rdoc@Argument+start].
+ * - Argument {start}[rdoc-ref:language/calendars.rdoc@Argument+start].
* - Argument {limit}[rdoc-ref:Date@Argument+limit].
*
* Related: Date._rfc2822 (returns a hash).
@@ -4881,7 +5073,7 @@ date_s_rfc2822(int argc, VALUE *argv, VALUE klass)
* Date._httpdate(string, limit: 128) -> hash
*
* Returns a hash of values parsed from +string+, which should be a valid
- * {HTTP date format}[rdoc-ref:strftime_formatting.rdoc@HTTP+Format]:
+ * {HTTP date format}[rdoc-ref:language/strftime_formatting.rdoc@HTTP+Format]:
*
* d = Date.new(2001, 2, 3)
* s = d.httpdate # => "Sat, 03 Feb 2001 00:00:00 GMT"
@@ -4896,7 +5088,7 @@ date_s__httpdate(int argc, VALUE *argv, VALUE klass)
VALUE str, opt;
rb_scan_args(argc, argv, "1:", &str, &opt);
- check_limit(str, opt);
+ if (!NIL_P(str)) str = check_limit(str, opt);
return date__httpdate(str);
}
@@ -4907,7 +5099,7 @@ date_s__httpdate(int argc, VALUE *argv, VALUE klass)
*
* Returns a new \Date object with values parsed from +string+,
* which should be a valid
- * {HTTP date format}[rdoc-ref:strftime_formatting.rdoc@HTTP+Format]:
+ * {HTTP date format}[rdoc-ref:language/strftime_formatting.rdoc@HTTP+Format]:
*
* d = Date.new(2001, 2, 3)
s = d.httpdate # => "Sat, 03 Feb 2001 00:00:00 GMT"
@@ -4915,7 +5107,7 @@ date_s__httpdate(int argc, VALUE *argv, VALUE klass)
*
* See:
*
- * - Argument {start}[rdoc-ref:date/calendars.rdoc@Argument+start].
+ * - Argument {start}[rdoc-ref:language/calendars.rdoc@Argument+start].
* - Argument {limit}[rdoc-ref:Date@Argument+limit].
*
* Related: Date._httpdate (returns a hash).
@@ -4949,7 +5141,7 @@ date_s_httpdate(int argc, VALUE *argv, VALUE klass)
* Date._jisx0301(string, limit: 128) -> hash
*
* Returns a hash of values parsed from +string+, which should be a valid
- * {JIS X 0301 date format}[rdoc-ref:strftime_formatting.rdoc@JIS+X+0301+Format]:
+ * {JIS X 0301 date format}[rdoc-ref:language/strftime_formatting.rdoc@JIS+X+0301+Format]:
*
* d = Date.new(2001, 2, 3)
* s = d.jisx0301 # => "H13.02.03"
@@ -4965,7 +5157,7 @@ date_s__jisx0301(int argc, VALUE *argv, VALUE klass)
VALUE str, opt;
rb_scan_args(argc, argv, "1:", &str, &opt);
- check_limit(str, opt);
+ if (!NIL_P(str)) str = check_limit(str, opt);
return date__jisx0301(str);
}
@@ -4975,7 +5167,7 @@ date_s__jisx0301(int argc, VALUE *argv, VALUE klass)
* Date.jisx0301(string = '-4712-01-01', start = Date::ITALY, limit: 128) -> date
*
* Returns a new \Date object with values parsed from +string+,
- * which should be a valid {JIS X 0301 format}[rdoc-ref:strftime_formatting.rdoc@JIS+X+0301+Format]:
+ * which should be a valid {JIS X 0301 format}[rdoc-ref:language/strftime_formatting.rdoc@JIS+X+0301+Format]:
*
* d = Date.new(2001, 2, 3)
* s = d.jisx0301 # => "H13.02.03"
@@ -4987,7 +5179,7 @@ date_s__jisx0301(int argc, VALUE *argv, VALUE klass)
*
* See:
*
- * - Argument {start}[rdoc-ref:date/calendars.rdoc@Argument+start].
+ * - Argument {start}[rdoc-ref:language/calendars.rdoc@Argument+start].
* - Argument {limit}[rdoc-ref:Date@Argument+limit].
*
* Related: Date._jisx0301 (returns a hash).
@@ -5745,7 +5937,7 @@ d_lite_leap_p(VALUE self)
* Date.new(2001, 2, 3, Date::GREGORIAN).start # => -Infinity
* Date.new(2001, 2, 3, Date::JULIAN).start # => Infinity
*
- * See argument {start}[rdoc-ref:date/calendars.rdoc@Argument+start].
+ * See argument {start}[rdoc-ref:language/calendars.rdoc@Argument+start].
*
*/
static VALUE
@@ -5811,7 +6003,7 @@ dup_obj_with_new_start(VALUE obj, double sg)
/*
* call-seq:
- * new_start(start = Date::ITALY]) -> new_date
+ * new_start(start = Date::ITALY) -> new_date
*
* Returns a copy of +self+ with the given +start+ value:
*
@@ -5820,7 +6012,7 @@ dup_obj_with_new_start(VALUE obj, double sg)
* d1 = d0.new_start(Date::JULIAN)
* d1.julian? # => true
*
- * See argument {start}[rdoc-ref:date/calendars.rdoc@Argument+start].
+ * See argument {start}[rdoc-ref:language/calendars.rdoc@Argument+start].
*
*/
static VALUE
@@ -6968,7 +7160,7 @@ static VALUE strftimev(const char *, VALUE,
* to_s -> string
*
* Returns a string representation of the date in +self+
- * in {ISO 8601 extended date format}[rdoc-ref:strftime_formatting.rdoc@ISO+8601+Format+Specifications]
+ * in {ISO 8601 extended date format}[rdoc-ref:language/strftime_formatting.rdoc@ISO+8601+Format+Specifications]
* (<tt>'%Y-%m-%d'</tt>):
*
* Date.new(2001, 2, 3).to_s # => "2001-02-03"
@@ -7249,7 +7441,7 @@ date_strftime_internal(int argc, VALUE *argv, VALUE self,
* Date.new(2001, 2, 3).strftime # => "2001-02-03"
*
* For other formats, see
- * {Formats for Dates and Times}[rdoc-ref:strftime_formatting.rdoc].
+ * {Formats for Dates and Times}[rdoc-ref:language/strftime_formatting.rdoc].
*
*/
static VALUE
@@ -7281,12 +7473,12 @@ strftimev(const char *fmt, VALUE self,
* asctime -> string
*
* Equivalent to #strftime with argument <tt>'%a %b %e %T %Y'</tt>
- * (or its {shorthand form}[rdoc-ref:strftime_formatting.rdoc@Shorthand+Conversion+Specifiers]
+ * (or its {shorthand form}[rdoc-ref:language/strftime_formatting.rdoc@Shorthand+Conversion+Specifiers]
* <tt>'%c'</tt>):
*
* Date.new(2001, 2, 3).asctime # => "Sat Feb 3 00:00:00 2001"
*
- * See {asctime}[https://linux.die.net/man/3/asctime].
+ * See {asctime}[https://man7.org/linux/man-pages/man3/asctime.3p.html].
*
*/
static VALUE
@@ -7300,7 +7492,7 @@ d_lite_asctime(VALUE self)
* iso8601 -> string
*
* Equivalent to #strftime with argument <tt>'%Y-%m-%d'</tt>
- * (or its {shorthand form}[rdoc-ref:strftime_formatting.rdoc@Shorthand+Conversion+Specifiers]
+ * (or its {shorthand form}[rdoc-ref:language/strftime_formatting.rdoc@Shorthand+Conversion+Specifiers]
* <tt>'%F'</tt>);
*
* Date.new(2001, 2, 3).iso8601 # => "2001-02-03"
@@ -7317,7 +7509,7 @@ d_lite_iso8601(VALUE self)
* rfc3339 -> string
*
* Equivalent to #strftime with argument <tt>'%FT%T%:z'</tt>;
- * see {Formats for Dates and Times}[rdoc-ref:strftime_formatting.rdoc]:
+ * see {Formats for Dates and Times}[rdoc-ref:language/strftime_formatting.rdoc]:
*
* Date.new(2001, 2, 3).rfc3339 # => "2001-02-03T00:00:00+00:00"
*
@@ -7333,7 +7525,7 @@ d_lite_rfc3339(VALUE self)
* rfc2822 -> string
*
* Equivalent to #strftime with argument <tt>'%a, %-d %b %Y %T %z'</tt>;
- * see {Formats for Dates and Times}[rdoc-ref:strftime_formatting.rdoc]:
+ * see {Formats for Dates and Times}[rdoc-ref:language/strftime_formatting.rdoc]:
*
* Date.new(2001, 2, 3).rfc2822 # => "Sat, 3 Feb 2001 00:00:00 +0000"
*
@@ -7349,7 +7541,7 @@ d_lite_rfc2822(VALUE self)
* httpdate -> string
*
* Equivalent to #strftime with argument <tt>'%a, %d %b %Y %T GMT'</tt>;
- * see {Formats for Dates and Times}[rdoc-ref:strftime_formatting.rdoc]:
+ * see {Formats for Dates and Times}[rdoc-ref:language/strftime_formatting.rdoc]:
*
* Date.new(2001, 2, 3).httpdate # => "Sat, 03 Feb 2001 00:00:00 GMT"
*
@@ -8718,7 +8910,7 @@ 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]:
+ * see {Formats for Dates and Times}[rdoc-ref:language/strftime_formatting.rdoc]:
*
*/
static VALUE
@@ -9497,6 +9689,7 @@ Init_date_core(void)
sym_zone = ID2SYM(rb_intern_const("zone"));
half_days_in_day = rb_rational_new2(INT2FIX(1), INT2FIX(2));
+ rb_gc_register_mark_object(half_days_in_day);
#if (LONG_MAX / DAY_IN_SECONDS) > SECOND_IN_NANOSECONDS
day_in_nanoseconds = LONG2NUM((long)DAY_IN_SECONDS *
@@ -9508,8 +9701,6 @@ Init_date_core(void)
day_in_nanoseconds = f_mul(INT2FIX(DAY_IN_SECONDS),
INT2FIX(SECOND_IN_NANOSECONDS));
#endif
-
- rb_gc_register_mark_object(half_days_in_day);
rb_gc_register_mark_object(day_in_nanoseconds);
positive_inf = +INFINITY;
@@ -9525,7 +9716,7 @@ Init_date_core(void)
*
* - You need both dates and times; \Date handles only dates.
* - You need only Gregorian dates (and not Julian dates);
- * see {Julian and Gregorian Calendars}[rdoc-ref:date/calendars.rdoc].
+ * see {Julian and Gregorian Calendars}[rdoc-ref:language/calendars.rdoc].
*
* A \Date object, once created, is immutable, and cannot be modified.
*
@@ -9572,7 +9763,7 @@ Init_date_core(void)
* Date.strptime('fri31dec99', '%a%d%b%y') # => #<Date: 1999-12-31>
*
* See also the specialized methods in
- * {"Specialized Format Strings" in Formats for Dates and Times}[rdoc-ref:strftime_formatting.rdoc@Specialized+Format+Strings]
+ * {"Specialized Format Strings" in Formats for Dates and Times}[rdoc-ref:language/strftime_formatting.rdoc@Specialized+Format+Strings]
*
* == Argument +limit+
*
diff --git a/ext/date/date_strptime.c b/ext/date/date_strptime.c
index f1c8201de8..1dde5fa3ec 100644
--- a/ext/date/date_strptime.c
+++ b/ext/date/date_strptime.c
@@ -661,6 +661,9 @@ date__strptime(const char *str, size_t slen,
si = date__strptime_internal(str, slen, fmt, flen, hash);
+ if (fail_p())
+ return Qnil;
+
if (slen > si) {
VALUE s;
@@ -668,9 +671,6 @@ date__strptime(const char *str, size_t slen,
set_hash("leftover", s);
}
- if (fail_p())
- return Qnil;
-
cent = del_hash("_cent");
if (!NIL_P(cent)) {
VALUE year;
diff --git a/ext/date/lib/date.rb b/ext/date/lib/date.rb
index aa630eb6d1..0cb763017f 100644
--- a/ext/date/lib/date.rb
+++ b/ext/date/lib/date.rb
@@ -4,7 +4,7 @@
require 'date_core'
class Date
- VERSION = "3.4.1" # :nodoc:
+ VERSION = "3.5.1" # :nodoc:
# call-seq:
# infinite? -> false
diff --git a/ext/digest/digest.c b/ext/digest/digest.c
index bd8d3e815f..28f6022754 100644
--- a/ext/digest/digest.c
+++ b/ext/digest/digest.c
@@ -571,7 +571,7 @@ static rb_digest_metadata_t *
get_digest_base_metadata(VALUE klass)
{
VALUE p;
- VALUE obj;
+ VALUE obj = Qnil;
rb_digest_metadata_t *algo;
for (p = klass; !NIL_P(p); p = rb_class_superclass(p)) {
diff --git a/ext/digest/lib/digest/version.rb b/ext/digest/lib/digest/version.rb
index 854106165c..a56e80c54e 100644
--- a/ext/digest/lib/digest/version.rb
+++ b/ext/digest/lib/digest/version.rb
@@ -1,5 +1,6 @@
# frozen_string_literal: true
module Digest
- VERSION = "3.2.0"
+ # The version string
+ VERSION = "3.2.1"
end
diff --git a/ext/digest/sha1/sha1.c b/ext/digest/sha1/sha1.c
index ce200270b7..003c87d224 100644
--- a/ext/digest/sha1/sha1.c
+++ b/ext/digest/sha1/sha1.c
@@ -220,14 +220,16 @@ int SHA1_Init(SHA1_CTX *context)
*/
void SHA1_Update(SHA1_CTX *context, const uint8_t *data, size_t len)
{
- uint32_t i, j;
+ size_t i;
+ uint32_t j;
_DIAGASSERT(context != 0);
_DIAGASSERT(data != 0);
j = context->count[0];
if ((context->count[0] += len << 3) < j)
- context->count[1] += (len>>29)+1;
+ context->count[1]++;
+ context->count[1] += (uint32_t)(len >> 29);
j = (j >> 3) & 63;
if ((j + len) > 63) {
(void)memcpy(&context->buffer[j], data, (i = 64-j));
diff --git a/ext/erb/escape/escape.c b/ext/erb/escape/escape.c
index 2a5903c3b7..1794fc30eb 100644
--- a/ext/erb/escape/escape.c
+++ b/ext/erb/escape/escape.c
@@ -39,29 +39,41 @@ static VALUE
optimized_escape_html(VALUE str)
{
VALUE vbuf;
- char *buf = ALLOCV_N(char, vbuf, escaped_length(str));
+ char *buf = NULL;
const char *cstr = RSTRING_PTR(str);
const char *end = cstr + RSTRING_LEN(str);
- char *dest = buf;
+ const char *segment_start = cstr;
+ char *dest = NULL;
while (cstr < end) {
const unsigned char c = *cstr++;
uint8_t len = html_escape_table[c].len;
if (len) {
+ size_t segment_len = cstr - segment_start - 1;
+ if (!buf) {
+ buf = ALLOCV_N(char, vbuf, escaped_length(str));
+ dest = buf;
+ }
+ if (segment_len) {
+ memcpy(dest, segment_start, segment_len);
+ dest += segment_len;
+ }
+ segment_start = cstr;
memcpy(dest, html_escape_table[c].str, len);
dest += len;
}
- else {
- *dest++ = c;
- }
}
-
VALUE escaped = str;
- if (RSTRING_LEN(str) < (dest - buf)) {
+ if (buf) {
+ size_t segment_len = cstr - segment_start;
+ if (segment_len) {
+ memcpy(dest, segment_start, segment_len);
+ dest += segment_len;
+ }
escaped = rb_str_new(buf, dest - buf);
preserve_original_state(str, escaped);
+ ALLOCV_END(vbuf);
}
- ALLOCV_END(vbuf);
return escaped;
}
diff --git a/ext/etc/etc.c b/ext/etc/etc.c
index 66ef8fc9a4..8d50a96a62 100644
--- a/ext/etc/etc.c
+++ b/ext/etc/etc.c
@@ -832,11 +832,7 @@ etc_uname(VALUE obj)
rb_w32_conv_from_wchar(v.szCSDVersion, rb_utf8_encoding()));
rb_hash_aset(result, SYMBOL_LIT("version"), version);
-# if defined _MSC_VER && _MSC_VER < 1300
-# define GET_COMPUTER_NAME(ptr, plen) GetComputerNameW(ptr, plen)
-# else
# define GET_COMPUTER_NAME(ptr, plen) GetComputerNameExW(ComputerNameDnsFullyQualified, ptr, plen)
-# endif
GET_COMPUTER_NAME(NULL, &len);
buf = ALLOCV_N(WCHAR, vbuf, len);
if (GET_COMPUTER_NAME(buf, &len)) {
diff --git a/ext/etc/etc.gemspec b/ext/etc/etc.gemspec
index 3facc74866..0e9803dc62 100644
--- a/ext/etc/etc.gemspec
+++ b/ext/etc/etc.gemspec
@@ -40,5 +40,5 @@ Gem::Specification.new do |spec|
spec.require_paths = ["lib"]
spec.extensions = %w{ext/etc/extconf.rb}
- spec.required_ruby_version = ">= 2.6.0"
+ spec.required_ruby_version = ">= 2.7.0"
end
diff --git a/ext/extmk.rb b/ext/extmk.rb
index 39cbce1bc9..f5244f72c8 100755
--- a/ext/extmk.rb
+++ b/ext/extmk.rb
@@ -8,8 +8,6 @@ module Gem
RbConfig::CONFIG
end
end
-# only needs Gem::Platform
-require 'rubygems/platform'
# :stopdoc:
$extension = nil
@@ -36,13 +34,16 @@ DUMMY_SIGNATURE = "***DUMMY MAKEFILE***"
srcdir = File.dirname(File.dirname(__FILE__))
unless defined?(CROSS_COMPILING) and CROSS_COMPILING
- $:.replace([File.expand_path("lib", srcdir), Dir.pwd])
+ $:.replace([Dir.pwd, File.expand_path("lib", srcdir)])
end
-$:.unshift(srcdir)
require 'rbconfig'
+# only needs Gem::Platform
+require 'rubygems/platform'
+
$topdir = "."
$top_srcdir = srcdir
+$extmk = true
inplace = File.identical?($top_srcdir, $topdir)
$" << "mkmf.rb"
@@ -138,14 +139,6 @@ def extract_makefile(makefile, keep = true)
true
end
-def create_makefile(target, srcprefix = nil)
- if $static and target.include?("/")
- base = File.basename(target)
- $defs << "-DInit_#{base}=Init_#{target.tr('/', '_')}"
- end
- super
-end
-
def extmake(target, basedir = 'ext', maybestatic = true)
FileUtils.mkpath target unless File.directory?(target)
begin
@@ -566,6 +559,7 @@ extend Module.new {
if $static and (target = args.first).include?("/")
base = File.basename(target)
$defs << "-DInit_#{base}=Init_#{target.tr('/', '_')}"
+ $defs << "-DInitVM_#{base}=InitVM_#{target.tr('/', '_')}"
end
return super
end
@@ -598,6 +592,7 @@ gem = #{@gemname}
build_complete = $(TARGET_GEM_DIR)/gem.build_complete
install-so: build_complete
clean-so:: clean-build_complete
+$(build_complete) $(OBJS): $(TARGET_SO_DIR_TIMESTAMP)
build_complete: $(build_complete)
$(build_complete): $(TARGET_SO)
diff --git a/ext/fcntl/fcntl.c b/ext/fcntl/fcntl.c
index 86bee5fb45..b987e237dd 100644
--- a/ext/fcntl/fcntl.c
+++ b/ext/fcntl/fcntl.c
@@ -65,7 +65,7 @@ pack up your own arguments to pass as args for locking functions, etc.
*
*/
-#define FCNTL_VERSION "1.2.0"
+#define FCNTL_VERSION "1.3.0"
void
Init_fcntl(void)
@@ -251,4 +251,50 @@ Init_fcntl(void)
*/
rb_define_const(mFcntl, "F_DUP2FD_CLOEXEC", INT2NUM(F_DUP2FD_CLOEXEC));
#endif
+
+#ifdef F_PREALLOCATE
+ /*
+ * macOS specific flag used for preallocating file space.
+ */
+ rb_define_const(mFcntl, "F_PREALLOCATE", INT2NUM(F_PREALLOCATE));
+#endif
+
+#ifdef F_ALLOCATECONTIG
+ /*
+ * macOS specific flag used with F_PREALLOCATE for allocating contiguous
+ * space.
+ */
+ rb_define_const(mFcntl, "F_ALLOCATECONTIG", INT2NUM(F_ALLOCATECONTIG));
+#endif
+
+#ifdef F_ALLOCATEALL
+ /*
+ * macOS specific flag used with F_PREALLOCATE for allocating all contiguous
+ * space or no space.
+ */
+ rb_define_const(mFcntl, "F_ALLOCATEALL", INT2NUM(F_ALLOCATEALL));
+#endif
+
+#ifdef F_ALLOCATEPERSIST
+ /*
+ * macOS specific flag used with F_PREALLOCATE. Allocate space that is not
+ * freed when close is called.
+ */
+ rb_define_const(mFcntl, "F_ALLOCATEPERSIST", INT2NUM(F_ALLOCATEPERSIST));
+#endif
+
+#ifdef F_PEOFPOSMODE
+ /*
+ * macOS specific flag used with F_PREALLOCATE. Allocate from the physical
+ * end of file
+ */
+ rb_define_const(mFcntl, "F_PEOFPOSMODE", INT2NUM(F_PEOFPOSMODE));
+#endif
+
+#ifdef F_VOLPOSMODE
+ /*
+ * macOS specific flag used with F_PREALLOCATE. Allocate from the volume offset.
+ */
+ rb_define_const(mFcntl, "F_VOLPOSMODE", INT2NUM(F_VOLPOSMODE));
+#endif
}
diff --git a/ext/io/console/console.c b/ext/io/console/console.c
index 3c8bb82083..5f3c9478f7 100644
--- a/ext/io/console/console.c
+++ b/ext/io/console/console.c
@@ -4,7 +4,7 @@
*/
static const char *const
-IO_CONSOLE_VERSION = "0.8.1";
+IO_CONSOLE_VERSION = "0.8.2";
#include "ruby.h"
#include "ruby/io.h"
@@ -840,6 +840,9 @@ console_winsize(VALUE io)
return rb_assoc_new(INT2NUM(winsize_row(&ws)), INT2NUM(winsize_col(&ws)));
}
+static VALUE console_scroll(VALUE io, int line);
+static VALUE console_goto(VALUE io, VALUE y, VALUE x);
+
/*
* call-seq:
* io.winsize = [rows, columns]
@@ -856,7 +859,8 @@ console_set_winsize(VALUE io, VALUE size)
#if defined _WIN32
HANDLE wh;
int newrow, newcol;
- BOOL ret;
+ COORD oldsize;
+ SMALL_RECT oldwindow;
#endif
VALUE row, col, xpixel, ypixel;
const VALUE *sz;
@@ -891,18 +895,62 @@ console_set_winsize(VALUE io, VALUE size)
if (!GetConsoleScreenBufferInfo(wh, &ws)) {
rb_syserr_fail(LAST_ERROR, "GetConsoleScreenBufferInfo");
}
+ oldsize = ws.dwSize;
+ oldwindow = ws.srWindow;
+ if (ws.srWindow.Right + 1 < newcol) {
+ ws.dwSize.X = newcol;
+ }
+ if (ws.dwSize.Y < newrow) {
+ ws.dwSize.Y = newrow;
+ }
+ /* expand screen buffer first if needed */
+ if (!SetConsoleScreenBufferSize(wh, ws.dwSize)) {
+ rb_syserr_fail(LAST_ERROR, "SetConsoleScreenBufferInfo");
+ }
+ /* refresh ws for new dwMaximumWindowSize */
+ if (!GetConsoleScreenBufferInfo(wh, &ws)) {
+ rb_syserr_fail(LAST_ERROR, "GetConsoleScreenBufferInfo");
+ }
+ /* check new size before modifying buffer content */
+ if (newrow <= 0 || newcol <= 0 ||
+ newrow > ws.dwMaximumWindowSize.Y ||
+ newcol > ws.dwMaximumWindowSize.X) {
+ SetConsoleScreenBufferSize(wh, oldsize);
+ /* remove scrollbar if possible */
+ SetConsoleWindowInfo(wh, TRUE, &oldwindow);
+ rb_raise(rb_eArgError, "out of range winsize: [%d, %d]", newrow, newcol);
+ }
+ /* shrink screen buffer width */
ws.dwSize.X = newcol;
- ret = SetConsoleScreenBufferSize(wh, ws.dwSize);
+ /* shrink screen buffer height if window height were the same */
+ if (oldsize.Y == ws.srWindow.Bottom - ws.srWindow.Top + 1) {
+ ws.dwSize.Y = newrow;
+ }
ws.srWindow.Left = 0;
- ws.srWindow.Top = 0;
- ws.srWindow.Right = newcol-1;
- ws.srWindow.Bottom = newrow-1;
+ ws.srWindow.Right = newcol - 1;
+ ws.srWindow.Bottom = ws.srWindow.Top + newrow -1;
+ if (ws.dwCursorPosition.Y > ws.srWindow.Bottom) {
+ console_scroll(io, ws.dwCursorPosition.Y - ws.srWindow.Bottom);
+ ws.dwCursorPosition.Y = ws.srWindow.Bottom;
+ console_goto(io, INT2FIX(ws.dwCursorPosition.Y), INT2FIX(ws.dwCursorPosition.X));
+ }
+ if (ws.srWindow.Bottom > ws.dwSize.Y - 1) {
+ console_scroll(io, ws.srWindow.Bottom - (ws.dwSize.Y - 1));
+ ws.dwCursorPosition.Y -= ws.srWindow.Bottom - (ws.dwSize.Y - 1);
+ console_goto(io, INT2FIX(ws.dwCursorPosition.Y), INT2FIX(ws.dwCursorPosition.X));
+ ws.srWindow.Bottom = ws.dwSize.Y - 1;
+ }
+ ws.srWindow.Top = ws.srWindow.Bottom - (newrow - 1);
+ /* perform changes to winsize */
if (!SetConsoleWindowInfo(wh, TRUE, &ws.srWindow)) {
- rb_syserr_fail(LAST_ERROR, "SetConsoleWindowInfo");
+ int last_error = LAST_ERROR;
+ SetConsoleScreenBufferSize(wh, oldsize);
+ rb_syserr_fail(last_error, "SetConsoleWindowInfo");
}
- /* retry when shrinking buffer after shrunk window */
- if (!ret && !SetConsoleScreenBufferSize(wh, ws.dwSize)) {
- rb_syserr_fail(LAST_ERROR, "SetConsoleScreenBufferInfo");
+ /* perform screen buffer shrinking if necessary */
+ if ((ws.dwSize.Y < oldsize.Y || ws.dwSize.X < oldsize.X) &&
+ !SetConsoleScreenBufferSize(wh, ws.dwSize)) {
+ rb_syserr_fail(LAST_ERROR, "SetConsoleScreenBufferInfo");
}
/* remove scrollbar if possible */
if (!SetConsoleWindowInfo(wh, TRUE, &ws.srWindow)) {
@@ -1221,7 +1269,7 @@ console_cursor_pos(VALUE 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));
+ return rb_assoc_new(UINT2NUM(ws.dwCursorPosition.Y - ws.srWindow.Top), UINT2NUM(ws.dwCursorPosition.X));
#else
static const struct query_args query = {"\033[6n", 0};
VALUE resp = console_vt_response(0, 0, io, &query);
@@ -1254,11 +1302,17 @@ 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)) {
+ 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 = NUM2UINT(x);
+ pos->Y = ws.srWindow.Top + NUM2UINT(y);
+ if (!SetConsoleCursorPosition(h, *pos)) {
rb_syserr_fail(LAST_ERROR, 0);
}
#else
@@ -1651,13 +1705,11 @@ console_dev(int argc, VALUE *argv, VALUE klass)
VALUE con = 0;
VALUE sym = 0;
- rb_check_arity(argc, 0, UNLIMITED_ARGUMENTS);
-
if (argc) {
Check_Type(sym = argv[0], T_SYMBOL);
}
- // Force the class to be File.
+ /* Force the class to be File. */
if (klass == rb_cIO) klass = rb_cFile;
if (console_dev_get(klass, &con)) {
@@ -1948,14 +2000,13 @@ InitVM_console(void)
rb_define_method(rb_cIO, "ttyname", console_ttyname, 0);
rb_define_singleton_method(rb_cIO, "console", console_dev, -1);
{
- /* :stopdoc: */
+ /* :nodoc: */
VALUE mReadable = rb_define_module_under(rb_cIO, "generic_readable");
- /* :startdoc: */
rb_define_method(mReadable, "getch", io_getch, -1);
rb_define_method(mReadable, "getpass", io_getpass, -1);
}
{
- /* :stopdoc: */
+ /* :nodoc: */
cConmode = rb_define_class_under(rb_cIO, "ConsoleMode", rb_cObject);
rb_define_const(cConmode, "VERSION", rb_obj_freeze(rb_str_new_cstr(IO_CONSOLE_VERSION)));
rb_define_alloc_func(cConmode, conmode_alloc);
@@ -1964,6 +2015,5 @@ InitVM_console(void)
rb_define_method(cConmode, "echo=", conmode_set_echo, 1);
rb_define_method(cConmode, "raw!", conmode_set_raw, -1);
rb_define_method(cConmode, "raw", conmode_raw_new, -1);
- /* :startdoc: */
}
}
diff --git a/ext/io/wait/extconf.rb b/ext/io/wait/extconf.rb
index e97efa179d..00c455a45c 100644
--- a/ext/io/wait/extconf.rb
+++ b/ext/io/wait/extconf.rb
@@ -1,21 +1,4 @@
# frozen_string_literal: false
require 'mkmf'
-target = "io/wait"
-have_func("rb_io_wait", "ruby/io.h")
-have_func("rb_io_descriptor", "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|
- have_macro("FIONREAD", [h, ioctl_h].compact)
- end
- if fionread
- $defs << "-DFIONREAD_HEADER=\"<#{fionread}>\""
- create_makefile(target)
- end
-else
- if have_func("rb_w32_ioctlsocket", "ruby.h")
- have_func("rb_w32_is_socket", "ruby.h")
- create_makefile(target)
- end
-end
+create_makefile("io/wait")
diff --git a/ext/io/wait/io-wait.gemspec b/ext/io/wait/io-wait.gemspec
index 1554dcdb30..c1c6172589 100644
--- a/ext/io/wait/io-wait.gemspec
+++ b/ext/io/wait/io-wait.gemspec
@@ -1,4 +1,4 @@
-_VERSION = "0.3.2"
+_VERSION = "0.4.0"
Gem::Specification.new do |spec|
spec.name = "io-wait"
@@ -10,25 +10,25 @@ Gem::Specification.new do |spec|
spec.description = %q{Waits until IO is readable or writable without blocking.}
spec.homepage = "https://github.com/ruby/io-wait"
spec.licenses = ["Ruby", "BSD-2-Clause"]
- spec.required_ruby_version = Gem::Requirement.new(">= 3.0")
+ spec.required_ruby_version = Gem::Requirement.new(">= 3.2")
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 do |f|
- File.identical?(f, __FILE__) || f.match(%r{\A(?:(?:bin|test|spec|features|rakelib)/|\.(?:git|travis|circleci)|appveyor|Rakefile)})
- end
- end
+ jruby = true if Gem::Platform.new('java') =~ spec.platform or RUBY_ENGINE == 'jruby'
+ dir, gemspec = File.split(__FILE__)
+ excludes = [
+ *%w[:^/.git* :^/Gemfile* :^/Rakefile* :^/bin/ :^/test/ :^/rakelib/ :^*.java],
+ *(jruby ? %w[:^/ext/io] : %w[:^/ext/java]),
+ ":(exclude,literal,top)#{gemspec}"
+ ]
+ files = IO.popen(%w[git ls-files -z --] + excludes, chdir: dir, &:read).split("\x0")
+
+ spec.files = files
spec.bindir = "exe"
spec.executables = []
spec.require_paths = ["lib"]
- jruby = true if Gem::Platform.new('java') =~ spec.platform or RUBY_ENGINE == 'jruby'
- spec.files.delete_if do |f|
- f.end_with?(".java") or
- f.start_with?("ext/") && (jruby ^ f.start_with?("ext/java/"))
- end
if jruby
spec.platform = 'java'
spec.files << "lib/io/wait.jar"
diff --git a/ext/io/wait/wait.c b/ext/io/wait/wait.c
index 88e6dd2af1..f7575191fe 100644
--- a/ext/io/wait/wait.c
+++ b/ext/io/wait/wait.c
@@ -11,427 +11,13 @@
**********************************************************************/
-#include "ruby.h"
-#include "ruby/io.h"
-
-#include <sys/types.h>
-#if defined(HAVE_UNISTD_H) && (defined(__sun))
-#include <unistd.h>
-#endif
-#if defined(HAVE_SYS_IOCTL_H)
-#include <sys/ioctl.h>
-#endif
-#if defined(FIONREAD_HEADER)
-#include FIONREAD_HEADER
-#endif
-
-#ifdef HAVE_RB_W32_IOCTLSOCKET
-#define ioctl ioctlsocket
-#define ioctl_arg u_long
-#define ioctl_arg2num(i) ULONG2NUM(i)
-#else
-#define ioctl_arg int
-#define ioctl_arg2num(i) INT2NUM(i)
-#endif
-
-#ifdef HAVE_RB_W32_IS_SOCKET
-#define FIONREAD_POSSIBLE_P(fd) rb_w32_is_socket(fd)
-#else
-#define FIONREAD_POSSIBLE_P(fd) ((void)(fd),Qtrue)
-#endif
-
-#ifndef HAVE_RB_IO_WAIT
-static struct timeval *
-get_timeout(int argc, VALUE *argv, struct timeval *timerec)
-{
- VALUE timeout = Qnil;
- rb_check_arity(argc, 0, 1);
- if (!argc || NIL_P(timeout = argv[0])) {
- return NULL;
- }
- else {
- *timerec = rb_time_interval(timeout);
- return timerec;
- }
-}
-
-static int
-wait_for_single_fd(rb_io_t *fptr, int events, struct timeval *tv)
-{
- int i = rb_wait_for_single_fd(fptr->fd, events, tv);
- if (i < 0)
- rb_sys_fail(0);
- rb_io_check_closed(fptr);
- return (i & events);
-}
-#endif
-
-/*
- * call-seq:
- * io.nread -> int
- *
- * Returns number of bytes that can be read without blocking.
- * Returns zero if no information available.
- *
- * You must require 'io/wait' to use this method.
- */
-
-static VALUE
-io_nread(VALUE io)
-{
- rb_io_t *fptr;
- int len;
- ioctl_arg n;
-
- GetOpenFile(io, fptr);
- 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 (n > 0) return ioctl_arg2num(n);
- return INT2FIX(0);
-}
-
-#ifdef HAVE_RB_IO_WAIT
-static VALUE
-io_wait_event(VALUE io, int event, VALUE timeout, int return_io)
-{
- VALUE result = rb_io_wait(io, RB_INT2NUM(event), timeout);
-
- if (!RB_TEST(result)) {
- return Qnil;
- }
-
- int mask = RB_NUM2INT(result);
-
- if (mask & event) {
- if (return_io)
- return io;
- else
- return result;
- }
- else {
- return Qfalse;
- }
-}
-#endif
-
-/*
- * call-seq:
- * io.ready? -> truthy or falsy
- *
- * Returns a truthy value if input available without blocking, or a
- * falsy value.
- *
- * You must require 'io/wait' to use this method.
- */
-
-static VALUE
-io_ready_p(VALUE io)
-{
- rb_io_t *fptr;
-#ifndef HAVE_RB_IO_WAIT
- struct timeval tv = {0, 0};
-#endif
-
- GetOpenFile(io, fptr);
- rb_io_check_readable(fptr);
- if (rb_io_read_pending(fptr)) return Qtrue;
-
-#ifndef HAVE_RB_IO_WAIT
- return wait_for_single_fd(fptr, RB_WAITFD_IN, &tv) ? Qtrue : Qfalse;
-#else
- return io_wait_event(io, RUBY_IO_READABLE, RB_INT2NUM(0), 1);
-#endif
-}
-
-/* Ruby 3.2+ can define these methods. This macro indicates that case. */
-#ifndef RUBY_IO_WAIT_METHODS
-
-/*
- * call-seq:
- * io.wait_readable -> truthy or falsy
- * io.wait_readable(timeout) -> truthy or falsy
- *
- * Waits until IO is readable and returns a truthy value, or a falsy
- * value when times out. Returns a truthy value immediately when
- * buffered data is available.
- *
- * You must require 'io/wait' to use this method.
- */
-
-static VALUE
-io_wait_readable(int argc, VALUE *argv, VALUE io)
-{
- rb_io_t *fptr;
-#ifndef HAVE_RB_IO_WAIT
- struct timeval timerec;
- struct timeval *tv;
-#endif
-
- GetOpenFile(io, fptr);
- rb_io_check_readable(fptr);
-
-#ifndef HAVE_RB_IO_WAIT
- tv = get_timeout(argc, argv, &timerec);
-#endif
- if (rb_io_read_pending(fptr)) return Qtrue;
-
-#ifndef HAVE_RB_IO_WAIT
- if (wait_for_single_fd(fptr, RB_WAITFD_IN, tv)) {
- return io;
- }
- return Qnil;
-#else
- rb_check_arity(argc, 0, 1);
- VALUE timeout = (argc == 1 ? argv[0] : Qnil);
-
- return io_wait_event(io, RUBY_IO_READABLE, timeout, 1);
-#endif
-}
+#include "ruby.h" /* abi_version */
/*
- * call-seq:
- * io.wait_writable -> truthy or falsy
- * io.wait_writable(timeout) -> truthy or falsy
- *
- * Waits until IO is writable and returns a truthy value or a falsy
- * value when times out.
- *
- * You must require 'io/wait' to use this method.
- */
-static VALUE
-io_wait_writable(int argc, VALUE *argv, VALUE io)
-{
- rb_io_t *fptr;
-#ifndef HAVE_RB_IO_WAIT
- struct timeval timerec;
- struct timeval *tv;
-#endif
-
- GetOpenFile(io, fptr);
- rb_io_check_writable(fptr);
-
-#ifndef HAVE_RB_IO_WAIT
- tv = get_timeout(argc, argv, &timerec);
- if (wait_for_single_fd(fptr, RB_WAITFD_OUT, tv)) {
- return io;
- }
- return Qnil;
-#else
- rb_check_arity(argc, 0, 1);
- VALUE timeout = (argc == 1 ? argv[0] : Qnil);
-
- return io_wait_event(io, RUBY_IO_WRITABLE, timeout, 1);
-#endif
-}
-
-#ifdef HAVE_RB_IO_WAIT
-/*
- * call-seq:
- * io.wait_priority -> truthy or falsy
- * io.wait_priority(timeout) -> truthy or falsy
- *
- * Waits until IO is priority and returns a truthy value or a falsy
- * value when times out. Priority data is sent and received using
- * the Socket::MSG_OOB flag and is typically limited to streams.
- *
- * You must require 'io/wait' to use this method.
- */
-static VALUE
-io_wait_priority(int argc, VALUE *argv, VALUE io)
-{
- rb_io_t *fptr = NULL;
-
- RB_IO_POINTER(io, fptr);
- rb_io_check_readable(fptr);
-
- if (rb_io_read_pending(fptr)) return Qtrue;
-
- rb_check_arity(argc, 0, 1);
- VALUE timeout = argc == 1 ? argv[0] : Qnil;
-
- return io_wait_event(io, RUBY_IO_PRIORITY, timeout, 1);
-}
-#endif
-
-static int
-wait_mode_sym(VALUE mode)
-{
- if (mode == ID2SYM(rb_intern("r"))) {
- return RB_WAITFD_IN;
- }
- if (mode == ID2SYM(rb_intern("read"))) {
- return RB_WAITFD_IN;
- }
- if (mode == ID2SYM(rb_intern("readable"))) {
- return RB_WAITFD_IN;
- }
- if (mode == ID2SYM(rb_intern("w"))) {
- return RB_WAITFD_OUT;
- }
- if (mode == ID2SYM(rb_intern("write"))) {
- return RB_WAITFD_OUT;
- }
- if (mode == ID2SYM(rb_intern("writable"))) {
- return RB_WAITFD_OUT;
- }
- if (mode == ID2SYM(rb_intern("rw"))) {
- return RB_WAITFD_IN|RB_WAITFD_OUT;
- }
- if (mode == ID2SYM(rb_intern("read_write"))) {
- return RB_WAITFD_IN|RB_WAITFD_OUT;
- }
- if (mode == ID2SYM(rb_intern("readable_writable"))) {
- return RB_WAITFD_IN|RB_WAITFD_OUT;
- }
- rb_raise(rb_eArgError, "unsupported mode: %"PRIsVALUE, mode);
- return 0;
-}
-
-#ifdef HAVE_RB_IO_WAIT
-static inline rb_io_event_t
-io_event_from_value(VALUE value)
-{
- int events = RB_NUM2INT(value);
-
- if (events <= 0) rb_raise(rb_eArgError, "Events must be positive integer!");
-
- return events;
-}
-#endif
-
-/*
- * call-seq:
- * io.wait(events, timeout) -> event mask, false or nil
- * io.wait(*event_symbols[, timeout]) -> self, true, or false
- *
- * Waits until the IO becomes ready for the specified events and returns the
- * subset of events that become ready, or a falsy value when times out.
- *
- * The events can be a bit mask of +IO::READABLE+, +IO::WRITABLE+ or
- * +IO::PRIORITY+.
- *
- * Returns an event mask (truthy value) immediately when buffered data is
- * available.
- *
- * The second form: if one or more event symbols (+:read+, +:write+, or
- * +:read_write+) are passed, the event mask is the bit OR of the bitmask
- * corresponding to those symbols. In this form, +timeout+ is optional, the
- * order of the arguments is arbitrary, and returns +io+ if any of the
- * events is ready.
- *
- * You must require 'io/wait' to use this method.
- */
-
-static VALUE
-io_wait(int argc, VALUE *argv, VALUE io)
-{
-#ifndef HAVE_RB_IO_WAIT
- rb_io_t *fptr;
- struct timeval timerec;
- struct timeval *tv = NULL;
- int event = 0;
- int i;
-
- GetOpenFile(io, fptr);
- for (i = 0; i < argc; ++i) {
- if (SYMBOL_P(argv[i])) {
- event |= wait_mode_sym(argv[i]);
- }
- else {
- *(tv = &timerec) = rb_time_interval(argv[i]);
- }
- }
- /* rb_time_interval() and might_mode() might convert the argument */
- rb_io_check_closed(fptr);
- if (!event) event = RB_WAITFD_IN;
- if ((event & RB_WAITFD_IN) && rb_io_read_pending(fptr))
- return Qtrue;
- if (wait_for_single_fd(fptr, event, tv))
- return io;
- return Qnil;
-#else
- VALUE timeout = Qundef;
- rb_io_event_t events = 0;
- int i, return_io = 0;
-
- if (argc != 2 || (RB_SYMBOL_P(argv[0]) || RB_SYMBOL_P(argv[1]))) {
- /* We'd prefer to return the actual mask, but this form would return the io itself: */
- return_io = 1;
-
- /* Slow/messy path: */
- for (i = 0; i < argc; i += 1) {
- if (RB_SYMBOL_P(argv[i])) {
- events |= wait_mode_sym(argv[i]);
- }
- else if (timeout == Qundef) {
- rb_time_interval(timeout = argv[i]);
- }
- else {
- rb_raise(rb_eArgError, "timeout given more than once");
- }
- }
-
- if (timeout == Qundef) timeout = Qnil;
-
- if (events == 0) {
- events = RUBY_IO_READABLE;
- }
- }
- else /* argc == 2 and neither are symbols */ {
- /* This is the fast path: */
- events = io_event_from_value(argv[0]);
- timeout = argv[1];
- }
-
- if (events & RUBY_IO_READABLE) {
- rb_io_t *fptr = NULL;
- RB_IO_POINTER(io, fptr);
-
- if (rb_io_read_pending(fptr)) {
- /* This was the original behaviour: */
- if (return_io) return Qtrue;
- /* New behaviour always returns an event mask: */
- else return RB_INT2NUM(RUBY_IO_READABLE);
- }
- }
-
- return io_wait_event(io, events, timeout, return_io);
-#endif
-}
-
-#endif /* RUBY_IO_WAIT_METHODS */
-
-/*
- * IO wait methods
+ * IO wait methods are built in ruby now, just for backward compatibility.
*/
void
Init_wait(void)
{
-#ifdef HAVE_RB_EXT_RACTOR_SAFE
- RB_EXT_RACTOR_SAFE(true);
-#endif
-
- rb_define_method(rb_cIO, "nread", io_nread, 0);
- rb_define_method(rb_cIO, "ready?", io_ready_p, 0);
-
-#ifndef RUBY_IO_WAIT_METHODS
- rb_define_method(rb_cIO, "wait", io_wait, -1);
-
- rb_define_method(rb_cIO, "wait_readable", io_wait_readable, -1);
- rb_define_method(rb_cIO, "wait_writable", io_wait_writable, -1);
-#ifdef HAVE_RB_IO_WAIT
- rb_define_method(rb_cIO, "wait_priority", io_wait_priority, -1);
-#endif
-#endif
}
diff --git a/ext/json/fbuffer/fbuffer.h b/ext/json/fbuffer/fbuffer.h
index d32371476c..b4f5266ca5 100644
--- a/ext/json/fbuffer/fbuffer.h
+++ b/ext/json/fbuffer/fbuffer.h
@@ -1,47 +1,9 @@
#ifndef _FBUFFER_H_
#define _FBUFFER_H_
-#include "ruby.h"
-#include "ruby/encoding.h"
+#include "../json.h"
#include "../vendor/jeaiii-ltoa.h"
-/* shims */
-/* This is the fallback definition from Ruby 3.4 */
-
-#ifndef RBIMPL_STDBOOL_H
-#if defined(__cplusplus)
-# if defined(HAVE_STDBOOL_H) && (__cplusplus >= 201103L)
-# include <cstdbool>
-# endif
-#elif defined(HAVE_STDBOOL_H)
-# include <stdbool.h>
-#elif !defined(HAVE__BOOL)
-typedef unsigned char _Bool;
-# define bool _Bool
-# define true ((_Bool)+1)
-# define false ((_Bool)+0)
-# define __bool_true_false_are_defined
-#endif
-#endif
-
-#ifndef RB_UNLIKELY
-#define RB_UNLIKELY(expr) expr
-#endif
-
-#ifndef RB_LIKELY
-#define RB_LIKELY(expr) expr
-#endif
-
-#ifndef MAYBE_UNUSED
-# define MAYBE_UNUSED(x) x
-#endif
-
-#ifdef RUBY_DEBUG
-#ifndef JSON_DEBUG
-#define JSON_DEBUG RUBY_DEBUG
-#endif
-#endif
-
enum fbuffer_type {
FBUFFER_HEAP_ALLOCATED = 0,
FBUFFER_STACK_ALLOCATED = 1,
@@ -49,11 +11,11 @@ enum fbuffer_type {
typedef struct FBufferStruct {
enum fbuffer_type type;
- unsigned long initial_length;
- unsigned long len;
- unsigned long capa;
-#ifdef JSON_DEBUG
- unsigned long requested;
+ size_t initial_length;
+ size_t len;
+ size_t capa;
+#if JSON_DEBUG
+ size_t requested;
#endif
char *ptr;
VALUE io;
@@ -70,12 +32,12 @@ typedef struct FBufferStruct {
static void fbuffer_free(FBuffer *fb);
static void fbuffer_clear(FBuffer *fb);
-static void fbuffer_append(FBuffer *fb, const char *newstr, unsigned long len);
+static void fbuffer_append(FBuffer *fb, const char *newstr, size_t len);
static void fbuffer_append_long(FBuffer *fb, long number);
static inline void fbuffer_append_char(FBuffer *fb, char newchr);
static VALUE fbuffer_finalize(FBuffer *fb);
-static void fbuffer_stack_init(FBuffer *fb, unsigned long initial_length, char *stack_buffer, long stack_buffer_size)
+static void fbuffer_stack_init(FBuffer *fb, size_t initial_length, char *stack_buffer, size_t stack_buffer_size)
{
fb->initial_length = (initial_length > 0) ? initial_length : FBUFFER_INITIAL_LENGTH_DEFAULT;
if (stack_buffer) {
@@ -83,14 +45,14 @@ static void fbuffer_stack_init(FBuffer *fb, unsigned long initial_length, char *
fb->ptr = stack_buffer;
fb->capa = stack_buffer_size;
}
-#ifdef JSON_DEBUG
+#if JSON_DEBUG
fb->requested = 0;
#endif
}
-static inline void fbuffer_consumed(FBuffer *fb, unsigned long consumed)
+static inline void fbuffer_consumed(FBuffer *fb, size_t consumed)
{
-#ifdef JSON_DEBUG
+#if JSON_DEBUG
if (consumed > fb->requested) {
rb_bug("fbuffer: Out of bound write");
}
@@ -102,7 +64,7 @@ static inline void fbuffer_consumed(FBuffer *fb, unsigned long consumed)
static void fbuffer_free(FBuffer *fb)
{
if (fb->ptr && fb->type == FBUFFER_HEAP_ALLOCATED) {
- ruby_xfree(fb->ptr);
+ JSON_SIZED_FREE_N(fb->ptr, fb->capa);
}
}
@@ -117,7 +79,7 @@ static void fbuffer_flush(FBuffer *fb)
fbuffer_clear(fb);
}
-static void fbuffer_realloc(FBuffer *fb, unsigned long required)
+static void fbuffer_realloc(FBuffer *fb, size_t required)
{
if (required > fb->capa) {
if (fb->type == FBUFFER_STACK_ALLOCATED) {
@@ -126,13 +88,13 @@ static void fbuffer_realloc(FBuffer *fb, unsigned long required)
fb->type = FBUFFER_HEAP_ALLOCATED;
MEMCPY(fb->ptr, old_buffer, char, fb->len);
} else {
- REALLOC_N(fb->ptr, char, required);
+ JSON_SIZED_REALLOC_N(fb->ptr, char, required, fb->capa);
}
fb->capa = required;
}
}
-static void fbuffer_do_inc_capa(FBuffer *fb, unsigned long requested)
+static void fbuffer_do_inc_capa(FBuffer *fb, size_t requested)
{
if (RB_UNLIKELY(fb->io)) {
if (fb->capa < FBUFFER_IO_BUFFER_SIZE) {
@@ -146,7 +108,7 @@ static void fbuffer_do_inc_capa(FBuffer *fb, unsigned long requested)
}
}
- unsigned long required;
+ size_t required;
if (RB_UNLIKELY(!fb->ptr)) {
fb->ptr = ALLOC_N(char, fb->initial_length);
@@ -158,9 +120,9 @@ static void fbuffer_do_inc_capa(FBuffer *fb, unsigned long requested)
fbuffer_realloc(fb, required);
}
-static inline void fbuffer_inc_capa(FBuffer *fb, unsigned long requested)
+static inline void fbuffer_inc_capa(FBuffer *fb, size_t requested)
{
-#ifdef JSON_DEBUG
+#if JSON_DEBUG
fb->requested = requested;
#endif
@@ -169,19 +131,33 @@ static inline void fbuffer_inc_capa(FBuffer *fb, unsigned long requested)
}
}
-static void fbuffer_append(FBuffer *fb, const char *newstr, unsigned long len)
+static inline size_t fbuffer_size_mul_or_raise(size_t a, size_t b)
+{
+ size_t result = a * b;
+ if (RB_UNLIKELY(a != 0 && (result / a) != b)) {
+ rb_raise(rb_eArgError, "Buffer overflow, the resulting document is too large to be generated");
+ }
+ return result;
+}
+
+static inline void fbuffer_append_reserved(FBuffer *fb, const char *newstr, size_t len)
+{
+ MEMCPY(fb->ptr + fb->len, newstr, char, len);
+ fbuffer_consumed(fb, len);
+}
+
+static inline void fbuffer_append(FBuffer *fb, const char *newstr, size_t len)
{
if (len > 0) {
fbuffer_inc_capa(fb, len);
- MEMCPY(fb->ptr + fb->len, newstr, char, len);
- fbuffer_consumed(fb, len);
+ fbuffer_append_reserved(fb, newstr, len);
}
}
/* Appends a character into a buffer. The buffer needs to have sufficient capacity, via fbuffer_inc_capa(...). */
static inline void fbuffer_append_reserved_char(FBuffer *fb, char chr)
{
-#ifdef JSON_DEBUG
+#if JSON_DEBUG
if (fb->requested < 1) {
rb_bug("fbuffer: unreserved write");
}
@@ -194,12 +170,29 @@ static inline void fbuffer_append_reserved_char(FBuffer *fb, char chr)
static void fbuffer_append_str(FBuffer *fb, VALUE str)
{
- const char *newstr = StringValuePtr(str);
- unsigned long len = RSTRING_LEN(str);
+ const char *ptr;
+ size_t len;
+ RSTRING_GETMEM(str, ptr, len);
+ fbuffer_append(fb, ptr, len);
RB_GC_GUARD(str);
+}
- fbuffer_append(fb, newstr, len);
+static void fbuffer_append_str_repeat(FBuffer *fb, VALUE str, size_t repeat)
+{
+ const char *ptr;
+ size_t len;
+ RSTRING_GETMEM(str, ptr, len);
+
+ fbuffer_inc_capa(fb, fbuffer_size_mul_or_raise(repeat, len));
+ while (repeat) {
+#if JSON_DEBUG
+ fb->requested = len;
+#endif
+ fbuffer_append_reserved(fb, ptr, len);
+ repeat--;
+ }
+ RB_GC_GUARD(str);
}
static inline void fbuffer_append_char(FBuffer *fb, char newchr)
@@ -257,14 +250,11 @@ static VALUE fbuffer_finalize(FBuffer *fb)
{
if (fb->io) {
fbuffer_flush(fb);
- fbuffer_free(fb);
rb_io_flush(fb->io);
return fb->io;
} else {
- VALUE result = rb_utf8_str_new(FBUFFER_PTR(fb), FBUFFER_LEN(fb));
- fbuffer_free(fb);
- return result;
+ return rb_utf8_str_new(FBUFFER_PTR(fb), FBUFFER_LEN(fb));
}
}
-#endif
+#endif // _FBUFFER_H_
diff --git a/ext/json/generator/depend b/ext/json/generator/depend
index aee4ab94eb..3ba4acfdd2 100644
--- a/ext/json/generator/depend
+++ b/ext/json/generator/depend
@@ -178,6 +178,7 @@ generator.o: $(hdrdir)/ruby/ruby.h
generator.o: $(hdrdir)/ruby/st.h
generator.o: $(hdrdir)/ruby/subst.h
generator.o: $(srcdir)/../fbuffer/fbuffer.h
+generator.o: $(srcdir)/../json.h
generator.o: $(srcdir)/../simd/simd.h
generator.o: $(srcdir)/../vendor/fpconv.c
generator.o: $(srcdir)/../vendor/jeaiii-ltoa.h
diff --git a/ext/json/generator/extconf.rb b/ext/json/generator/extconf.rb
index fb9afd07f7..33af03ea30 100644
--- a/ext/json/generator/extconf.rb
+++ b/ext/json/generator/extconf.rb
@@ -5,8 +5,11 @@ if RUBY_ENGINE == 'truffleruby'
File.write('Makefile', dummy_makefile("").join)
else
append_cflags("-std=c99")
+ have_const("RUBY_TYPED_EMBEDDABLE", "ruby.h") # RUBY_VERSION >= 3.3
+ have_func("ruby_xfree_sized", "ruby.h") # RUBY_VERSION >= 4.1
+
$defs << "-DJSON_GENERATOR"
- $defs << "-DJSON_DEBUG" if ENV["JSON_DEBUG"]
+ $defs << "-DJSON_DEBUG" if ENV.fetch("JSON_DEBUG", "0") != "0"
if enable_config('generator-use-simd', default=!ENV["JSON_DISABLE_SIMD"])
load __dir__ + "/../simd/conf.rb"
diff --git a/ext/json/generator/generator.c b/ext/json/generator/generator.c
index 9c6ed93049..82853633ba 100644
--- a/ext/json/generator/generator.c
+++ b/ext/json/generator/generator.c
@@ -1,4 +1,4 @@
-#include "ruby.h"
+#include "../json.h"
#include "../fbuffer/fbuffer.h"
#include "../vendor/fpconv.c"
@@ -9,6 +9,12 @@
/* ruby api and some helpers */
+enum duplicate_key_action {
+ JSON_DEPRECATED = 0,
+ JSON_IGNORE,
+ JSON_RAISE,
+};
+
typedef struct JSON_Generator_StateStruct {
VALUE indent;
VALUE space;
@@ -21,20 +27,19 @@ typedef struct JSON_Generator_StateStruct {
long depth;
long buffer_initial_length;
+ enum duplicate_key_action on_duplicate_key;
+
+ bool as_json_single_arg;
bool allow_nan;
bool ascii_only;
bool script_safe;
bool strict;
} JSON_Generator_State;
-#ifndef RB_UNLIKELY
-#define RB_UNLIKELY(cond) (cond)
-#endif
-
static VALUE mJSON, cState, cFragment, eGeneratorError, eNestingError, Encoding_UTF_8;
-static ID i_to_s, i_to_json, i_new, i_pack, i_unpack, i_create_id, i_extend, i_encode;
-static VALUE sym_indent, sym_space, sym_space_before, sym_object_nl, sym_array_nl, sym_max_nesting, sym_allow_nan,
+static ID i_to_s, i_to_json, i_new, i_encode;
+static VALUE sym_indent, sym_space, sym_space_before, sym_object_nl, sym_array_nl, sym_max_nesting, sym_allow_nan, sym_allow_duplicate_key,
sym_ascii_only, sym_depth, sym_buffer_initial_length, sym_script_safe, sym_escape_slash, sym_strict, sym_as_json;
@@ -55,8 +60,11 @@ struct generate_json_data {
JSON_Generator_State *state;
VALUE obj;
generator_func func;
+ long depth;
};
+static SIMD_Implementation simd_impl;
+
static VALUE cState_from_state_s(VALUE self, VALUE opts);
static VALUE cState_partial_generate(VALUE self, VALUE obj, generator_func, VALUE io);
static void generate_json(FBuffer *buffer, struct generate_json_data *data, VALUE obj);
@@ -66,9 +74,6 @@ static void generate_json_string(FBuffer *buffer, struct generate_json_data *dat
static void generate_json_null(FBuffer *buffer, struct generate_json_data *data, VALUE obj);
static void generate_json_false(FBuffer *buffer, struct generate_json_data *data, VALUE obj);
static void generate_json_true(FBuffer *buffer, struct generate_json_data *data, VALUE obj);
-#ifdef RUBY_INTEGER_UNIFICATION
-static void generate_json_integer(FBuffer *buffer, struct generate_json_data *data, VALUE obj);
-#endif
static void generate_json_fixnum(FBuffer *buffer, struct generate_json_data *data, VALUE obj);
static void generate_json_bignum(FBuffer *buffer, struct generate_json_data *data, VALUE obj);
static void generate_json_float(FBuffer *buffer, struct generate_json_data *data, VALUE obj);
@@ -76,23 +81,18 @@ static void generate_json_fragment(FBuffer *buffer, struct generate_json_data *d
static int usascii_encindex, utf8_encindex, binary_encindex;
-#ifdef RBIMPL_ATTR_NORETURN
-RBIMPL_ATTR_NORETURN()
-#endif
-static void raise_generator_error_str(VALUE invalid_object, VALUE str)
+NORETURN(static void) raise_generator_error_str(VALUE invalid_object, VALUE str)
{
+ rb_enc_associate_index(str, utf8_encindex);
VALUE exc = rb_exc_new_str(eGeneratorError, str);
rb_ivar_set(exc, rb_intern("@invalid_object"), invalid_object);
rb_exc_raise(exc);
}
-#ifdef RBIMPL_ATTR_NORETURN
-RBIMPL_ATTR_NORETURN()
-#endif
#ifdef RBIMPL_ATTR_FORMAT
RBIMPL_ATTR_FORMAT(RBIMPL_PRINTF_FORMAT, 2, 3)
#endif
-static void raise_generator_error(VALUE invalid_object, const char *fmt, ...)
+NORETURN(static void) raise_generator_error(VALUE invalid_object, const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
@@ -127,13 +127,7 @@ typedef struct _search_state {
#endif /* HAVE_SIMD */
} search_state;
-#if (defined(__GNUC__ ) || defined(__clang__))
-#define FORCE_INLINE __attribute__((always_inline))
-#else
-#define FORCE_INLINE
-#endif
-
-static inline FORCE_INLINE void search_flush(search_state *search)
+ALWAYS_INLINE(static) void search_flush(search_state *search)
{
// Do not remove this conditional without profiling, specifically escape-heavy text.
// escape_UTF8_char_basic will advance search->ptr and search->cursor (effectively a search_flush).
@@ -160,8 +154,6 @@ static const unsigned char escape_table_basic[256] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
};
-static unsigned char (*search_escape_basic_impl)(search_state *);
-
static inline unsigned char search_escape_basic(search_state *search)
{
while (search->ptr < search->end) {
@@ -176,7 +168,7 @@ static inline unsigned char search_escape_basic(search_state *search)
return 0;
}
-static inline FORCE_INLINE void escape_UTF8_char_basic(search_state *search)
+ALWAYS_INLINE(static) void escape_UTF8_char_basic(search_state *search)
{
const unsigned char ch = (unsigned char)*search->ptr;
switch (ch) {
@@ -217,11 +209,39 @@ static inline FORCE_INLINE void escape_UTF8_char_basic(search_state *search)
* Everything else (should be UTF-8) is just passed through and
* appended to the result.
*/
+
+
+#if defined(HAVE_SIMD_NEON)
+static inline unsigned char search_escape_basic_neon(search_state *search);
+#elif defined(HAVE_SIMD_SSE2)
+static inline unsigned char search_escape_basic_sse2(search_state *search);
+#endif
+
+static inline unsigned char search_escape_basic(search_state *search);
+
static inline void convert_UTF8_to_JSON(search_state *search)
{
- while (search_escape_basic_impl(search)) {
+#ifdef HAVE_SIMD
+#if defined(HAVE_SIMD_NEON)
+ while (search_escape_basic_neon(search)) {
+ escape_UTF8_char_basic(search);
+ }
+#elif defined(HAVE_SIMD_SSE2)
+ if (simd_impl == SIMD_SSE2) {
+ while (search_escape_basic_sse2(search)) {
+ escape_UTF8_char_basic(search);
+ }
+ return;
+ }
+ while (search_escape_basic(search)) {
+ escape_UTF8_char_basic(search);
+ }
+#endif
+#else
+ while (search_escape_basic(search)) {
escape_UTF8_char_basic(search);
}
+#endif /* HAVE_SIMD */
}
static inline void escape_UTF8_char(search_state *search, unsigned char ch_len)
@@ -263,8 +283,10 @@ static inline void escape_UTF8_char(search_state *search, unsigned char ch_len)
#ifdef HAVE_SIMD
-static inline FORCE_INLINE char *copy_remaining_bytes(search_state *search, unsigned long vec_len, unsigned long len)
+ALWAYS_INLINE(static) char *copy_remaining_bytes(search_state *search, unsigned long vec_len, unsigned long len)
{
+ RBIMPL_ASSERT_OR_ASSUME(len < vec_len);
+
// Flush the buffer so everything up until the last 'len' characters are unflushed.
search_flush(search);
@@ -274,19 +296,25 @@ static inline FORCE_INLINE char *copy_remaining_bytes(search_state *search, unsi
char *s = (buf->ptr + buf->len);
// Pad the buffer with dummy characters that won't need escaping.
- // This seem wateful at first sight, but memset of vector length is very fast.
- memset(s, 'X', vec_len);
+ // This seem wasteful at first sight, but memset of vector length is very fast.
+ // This is a space as it can be directly represented as an immediate on AArch64.
+ memset(s, ' ', vec_len);
// Optimistically copy the remaining 'len' characters to the output FBuffer. If there are no characters
// to escape, then everything ends up in the correct spot. Otherwise it was convenient temporary storage.
- MEMCPY(s, search->ptr, char, len);
+ if (vec_len == 16) {
+ RBIMPL_ASSERT_OR_ASSUME(len >= SIMD_MINIMUM_THRESHOLD);
+ json_fast_memcpy16(s, search->ptr, len);
+ } else {
+ MEMCPY(s, search->ptr, char, len);
+ }
return s;
}
#ifdef HAVE_SIMD_NEON
-static inline FORCE_INLINE unsigned char neon_next_match(search_state *search)
+ALWAYS_INLINE(static) unsigned char neon_next_match(search_state *search)
{
uint64_t mask = search->matches_mask;
uint32_t index = trailing_zeros64(mask) >> 2;
@@ -400,7 +428,7 @@ static inline unsigned char search_escape_basic_neon(search_state *search)
#ifdef HAVE_SIMD_SSE2
-static inline FORCE_INLINE unsigned char sse2_next_match(search_state *search)
+ALWAYS_INLINE(static) unsigned char sse2_next_match(search_state *search)
{
int mask = search->matches_mask;
int index = trailing_zeros(mask);
@@ -424,7 +452,7 @@ static inline FORCE_INLINE unsigned char sse2_next_match(search_state *search)
#define TARGET_SSE2
#endif
-static inline TARGET_SSE2 FORCE_INLINE unsigned char search_escape_basic_sse2(search_state *search)
+ALWAYS_INLINE(static) TARGET_SSE2 unsigned char search_escape_basic_sse2(search_state *search)
{
if (RB_UNLIKELY(search->has_matches)) {
// There are more matches if search->matches_mask > 0.
@@ -672,233 +700,6 @@ static void convert_UTF8_to_ASCII_only_JSON(search_state *search, const unsigned
}
}
-/*
- * Document-module: JSON::Ext::Generator
- *
- * This is the JSON generator implemented as a C extension. It can be
- * configured to be used by setting
- *
- * JSON.generator = JSON::Ext::Generator
- *
- * with the method generator= in JSON.
- *
- */
-
-/* Explanation of the following: that's the only way to not pollute
- * standard library's docs with GeneratorMethods::<ClassName> which
- * are uninformative and take a large place in a list of classes
- */
-
-/*
- * Document-module: JSON::Ext::Generator::GeneratorMethods
- * :nodoc:
- */
-
-/*
- * Document-module: JSON::Ext::Generator::GeneratorMethods::Array
- * :nodoc:
- */
-
-/*
- * Document-module: JSON::Ext::Generator::GeneratorMethods::Bignum
- * :nodoc:
- */
-
-/*
- * Document-module: JSON::Ext::Generator::GeneratorMethods::FalseClass
- * :nodoc:
- */
-
-/*
- * Document-module: JSON::Ext::Generator::GeneratorMethods::Fixnum
- * :nodoc:
- */
-
-/*
- * Document-module: JSON::Ext::Generator::GeneratorMethods::Float
- * :nodoc:
- */
-
-/*
- * Document-module: JSON::Ext::Generator::GeneratorMethods::Hash
- * :nodoc:
- */
-
-/*
- * Document-module: JSON::Ext::Generator::GeneratorMethods::Integer
- * :nodoc:
- */
-
-/*
- * Document-module: JSON::Ext::Generator::GeneratorMethods::NilClass
- * :nodoc:
- */
-
-/*
- * Document-module: JSON::Ext::Generator::GeneratorMethods::Object
- * :nodoc:
- */
-
-/*
- * Document-module: JSON::Ext::Generator::GeneratorMethods::String
- * :nodoc:
- */
-
-/*
- * Document-module: JSON::Ext::Generator::GeneratorMethods::String::Extend
- * :nodoc:
- */
-
-/*
- * Document-module: JSON::Ext::Generator::GeneratorMethods::TrueClass
- * :nodoc:
- */
-
-/*
- * call-seq: to_json(state = nil)
- *
- * Returns a JSON string containing a JSON object, that is generated from
- * this Hash instance.
- * _state_ is a JSON::State object, that can also be used to configure the
- * produced JSON string output further.
- */
-static VALUE mHash_to_json(int argc, VALUE *argv, VALUE self)
-{
- rb_check_arity(argc, 0, 1);
- VALUE Vstate = cState_from_state_s(cState, argc == 1 ? argv[0] : Qnil);
- return cState_partial_generate(Vstate, self, generate_json_object, Qfalse);
-}
-
-/*
- * call-seq: to_json(state = nil)
- *
- * Returns a JSON string containing a JSON array, that is generated from
- * this Array instance.
- * _state_ is a JSON::State object, that can also be used to configure the
- * produced JSON string output further.
- */
-static VALUE mArray_to_json(int argc, VALUE *argv, VALUE self)
-{
- rb_check_arity(argc, 0, 1);
- VALUE Vstate = cState_from_state_s(cState, argc == 1 ? argv[0] : Qnil);
- return cState_partial_generate(Vstate, self, generate_json_array, Qfalse);
-}
-
-#ifdef RUBY_INTEGER_UNIFICATION
-/*
- * call-seq: to_json(*)
- *
- * Returns a JSON string representation for this Integer number.
- */
-static VALUE mInteger_to_json(int argc, VALUE *argv, VALUE self)
-{
- rb_check_arity(argc, 0, 1);
- VALUE Vstate = cState_from_state_s(cState, argc == 1 ? argv[0] : Qnil);
- return cState_partial_generate(Vstate, self, generate_json_integer, Qfalse);
-}
-
-#else
-/*
- * call-seq: to_json(*)
- *
- * Returns a JSON string representation for this Integer number.
- */
-static VALUE mFixnum_to_json(int argc, VALUE *argv, VALUE self)
-{
- rb_check_arity(argc, 0, 1);
- VALUE Vstate = cState_from_state_s(cState, argc == 1 ? argv[0] : Qnil);
- return cState_partial_generate(Vstate, self, generate_json_fixnum, Qfalse);
-}
-
-/*
- * call-seq: to_json(*)
- *
- * Returns a JSON string representation for this Integer number.
- */
-static VALUE mBignum_to_json(int argc, VALUE *argv, VALUE self)
-{
- rb_check_arity(argc, 0, 1);
- VALUE Vstate = cState_from_state_s(cState, argc == 1 ? argv[0] : Qnil);
- return cState_partial_generate(Vstate, self, generate_json_bignum, Qfalse);
-}
-#endif
-
-/*
- * call-seq: to_json(*)
- *
- * Returns a JSON string representation for this Float number.
- */
-static VALUE mFloat_to_json(int argc, VALUE *argv, VALUE self)
-{
- rb_check_arity(argc, 0, 1);
- VALUE Vstate = cState_from_state_s(cState, argc == 1 ? argv[0] : Qnil);
- return cState_partial_generate(Vstate, self, generate_json_float, Qfalse);
-}
-
-/*
- * call-seq: to_json(*)
- *
- * This string should be encoded with UTF-8 A call to this method
- * returns a JSON string encoded with UTF16 big endian characters as
- * \u????.
- */
-static VALUE mString_to_json(int argc, VALUE *argv, VALUE self)
-{
- rb_check_arity(argc, 0, 1);
- VALUE Vstate = cState_from_state_s(cState, argc == 1 ? argv[0] : Qnil);
- return cState_partial_generate(Vstate, self, generate_json_string, Qfalse);
-}
-
-/*
- * call-seq: to_json(*)
- *
- * Returns a JSON string for true: 'true'.
- */
-static VALUE mTrueClass_to_json(int argc, VALUE *argv, VALUE self)
-{
- rb_check_arity(argc, 0, 1);
- return rb_utf8_str_new("true", 4);
-}
-
-/*
- * call-seq: to_json(*)
- *
- * Returns a JSON string for false: 'false'.
- */
-static VALUE mFalseClass_to_json(int argc, VALUE *argv, VALUE self)
-{
- rb_check_arity(argc, 0, 1);
- return rb_utf8_str_new("false", 5);
-}
-
-/*
- * call-seq: to_json(*)
- *
- * Returns a JSON string for nil: 'null'.
- */
-static VALUE mNilClass_to_json(int argc, VALUE *argv, VALUE self)
-{
- rb_check_arity(argc, 0, 1);
- return rb_utf8_str_new("null", 4);
-}
-
-/*
- * call-seq: to_json(*)
- *
- * Converts this object to a string (calling #to_s), converts
- * it to a JSON string, and returns the result. This is a fallback, if no
- * special method #to_json was defined for some object.
- */
-static VALUE mObject_to_json(int argc, VALUE *argv, VALUE self)
-{
- VALUE state;
- VALUE string = rb_funcall(self, i_to_s, 0);
- rb_scan_args(argc, argv, "01", &state);
- Check_Type(string, T_STRING);
- state = cState_from_state_s(cState, state);
- return cState_partial_generate(state, string, generate_json_string, Qfalse);
-}
-
static void State_mark(void *ptr)
{
JSON_Generator_State *state = ptr;
@@ -921,32 +722,24 @@ static void State_compact(void *ptr)
state->as_json = rb_gc_location(state->as_json);
}
-static void State_free(void *ptr)
-{
- JSON_Generator_State *state = ptr;
- ruby_xfree(state);
-}
-
static size_t State_memsize(const void *ptr)
{
+#ifdef HAVE_RUBY_TYPED_EMBEDDABLE
+ return 0;
+#else
return sizeof(JSON_Generator_State);
-}
-
-#ifndef HAVE_RB_EXT_RACTOR_SAFE
-# undef RUBY_TYPED_FROZEN_SHAREABLE
-# define RUBY_TYPED_FROZEN_SHAREABLE 0
#endif
+}
static const rb_data_type_t JSON_Generator_State_type = {
- "JSON/Generator/State",
- {
+ .wrap_struct_name = "JSON/Generator/State",
+ .function = {
.dmark = State_mark,
- .dfree = State_free,
+ .dfree = RUBY_DEFAULT_FREE,
.dsize = State_memsize,
.dcompact = State_compact,
},
- 0, 0,
- RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_FROZEN_SHAREABLE,
+ .flags = RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_FROZEN_SHAREABLE | RUBY_TYPED_EMBEDDABLE,
};
static void state_init(JSON_Generator_State *state)
@@ -978,18 +771,24 @@ static void vstate_spill(struct generate_json_data *data)
RB_OBJ_WRITTEN(vstate, Qundef, state->as_json);
}
-static inline VALUE vstate_get(struct generate_json_data *data)
+static inline VALUE json_call_to_json(struct generate_json_data *data, VALUE obj)
{
if (RB_UNLIKELY(!data->vstate)) {
vstate_spill(data);
}
- return data->vstate;
+ GET_STATE(data->vstate);
+ state->depth = data->depth;
+ VALUE tmp = rb_funcall(obj, i_to_json, 1, data->vstate);
+ // no need to restore state->depth, vstate is just a temporary State
+ return tmp;
}
-struct hash_foreach_arg {
- struct generate_json_data *data;
- int iter;
-};
+static VALUE
+json_call_as_json(JSON_Generator_State *state, VALUE object, VALUE is_key)
+{
+ VALUE proc_args[2] = {object, is_key};
+ return rb_proc_call_with_block(state->as_json, 2, proc_args, Qnil);
+}
static VALUE
convert_string_subclass(VALUE key)
@@ -1006,6 +805,159 @@ convert_string_subclass(VALUE key)
return key_to_s;
}
+static bool enc_utf8_compatible_p(int enc_idx)
+{
+ if (enc_idx == usascii_encindex) return true;
+ if (enc_idx == utf8_encindex) return true;
+ return false;
+}
+
+static VALUE encode_json_string_try(VALUE str)
+{
+ return rb_funcall(str, i_encode, 1, Encoding_UTF_8);
+}
+
+static VALUE encode_json_string_rescue(VALUE str, VALUE exception)
+{
+ raise_generator_error_str(str, rb_funcall(exception, rb_intern("message"), 0));
+ return Qundef;
+}
+
+static inline int json_str_coderange(VALUE str) {
+ int coderange = RB_ENC_CODERANGE(str);
+ if (coderange == RUBY_ENC_CODERANGE_UNKNOWN) {
+ coderange = rb_enc_str_coderange(str);
+ }
+ return coderange;
+}
+
+static inline bool valid_json_string_p(VALUE str)
+{
+ int coderange = json_str_coderange(str);
+
+ if (RB_LIKELY(coderange == ENC_CODERANGE_7BIT)) {
+ return true;
+ }
+
+ if (RB_LIKELY(coderange == ENC_CODERANGE_VALID)) {
+ return enc_utf8_compatible_p(RB_ENCODING_GET_INLINED(str));
+ }
+
+ return false;
+}
+
+NOINLINE(static) VALUE convert_invalid_encoding(struct generate_json_data *data, VALUE str, bool as_json_called, bool is_key)
+{
+ if (!as_json_called && data->state->strict && RTEST(data->state->as_json)) {
+ VALUE coerced_str = json_call_as_json(data->state, str, Qfalse);
+ if (coerced_str != str) {
+ if (RB_TYPE_P(coerced_str, T_STRING)) {
+ if (!valid_json_string_p(coerced_str)) {
+ raise_generator_error(str, "source sequence is illegal/malformed utf-8");
+ }
+ } else {
+ // as_json could return another type than T_STRING
+ if (is_key) {
+ raise_generator_error(coerced_str, "%"PRIsVALUE" not allowed as object key in JSON", CLASS_OF(coerced_str));
+ }
+ }
+
+ return coerced_str;
+ }
+ }
+
+ if (RB_ENCODING_GET_INLINED(str) == binary_encindex) {
+ VALUE utf8_string = rb_enc_associate_index(rb_str_dup(str), utf8_encindex);
+ switch (rb_enc_str_coderange(utf8_string)) {
+ case ENC_CODERANGE_7BIT:
+ return utf8_string;
+ case ENC_CODERANGE_VALID:
+ // For historical reason, we silently reinterpret binary strings as UTF-8 if it would work.
+ // TODO: Raise in 3.0.0
+ rb_warn("JSON.generate: UTF-8 string passed as BINARY, this will raise an encoding error in json 3.0");
+ return utf8_string;
+ break;
+ }
+ }
+
+ return rb_rescue(encode_json_string_try, str, encode_json_string_rescue, str);
+}
+
+ALWAYS_INLINE(static) VALUE ensure_valid_encoding(struct generate_json_data *data, VALUE str, bool as_json_called, bool is_key)
+{
+ if (RB_LIKELY(valid_json_string_p(str))) {
+ return str;
+ }
+ else {
+ return convert_invalid_encoding(data, str, as_json_called, is_key);
+ }
+}
+
+static void raw_generate_json_string(FBuffer *buffer, struct generate_json_data *data, VALUE obj)
+{
+ fbuffer_append_char(buffer, '"');
+
+ long len;
+ search_state search;
+ search.buffer = buffer;
+ RSTRING_GETMEM(obj, search.ptr, len);
+ search.cursor = search.ptr;
+ search.end = search.ptr + len;
+
+#ifdef HAVE_SIMD
+ search.matches_mask = 0;
+ search.has_matches = false;
+ search.chunk_base = NULL;
+ search.chunk_end = NULL;
+#endif /* HAVE_SIMD */
+
+ switch (json_str_coderange(obj)) {
+ case ENC_CODERANGE_7BIT:
+ case ENC_CODERANGE_VALID:
+ if (RB_UNLIKELY(data->state->ascii_only)) {
+ convert_UTF8_to_ASCII_only_JSON(&search, data->state->script_safe ? script_safe_escape_table : ascii_only_escape_table);
+ } else if (RB_UNLIKELY(data->state->script_safe)) {
+ convert_UTF8_to_script_safe_JSON(&search);
+ } else {
+ convert_UTF8_to_JSON(&search);
+ }
+ break;
+ default:
+ raise_generator_error(obj, "source sequence is illegal/malformed utf-8");
+ break;
+ }
+ fbuffer_append_char(buffer, '"');
+}
+
+static void generate_json_string(FBuffer *buffer, struct generate_json_data *data, VALUE obj)
+{
+ obj = ensure_valid_encoding(data, obj, false, false);
+ raw_generate_json_string(buffer, data, obj);
+}
+
+struct hash_foreach_arg {
+ VALUE hash;
+ struct generate_json_data *data;
+ int first_key_type;
+ bool first;
+ bool mixed_keys_encountered;
+};
+
+NOINLINE(static) void
+json_inspect_hash_with_mixed_keys(struct hash_foreach_arg *arg)
+{
+ if (arg->mixed_keys_encountered) {
+ return;
+ }
+ arg->mixed_keys_encountered = true;
+
+ JSON_Generator_State *state = arg->data->state;
+ if (state->on_duplicate_key != JSON_IGNORE) {
+ VALUE do_raise = state->on_duplicate_key == JSON_RAISE ? Qtrue : Qfalse;
+ rb_funcall(mJSON, rb_intern("on_mixed_keys_hash"), 2, arg->hash, do_raise);
+ }
+}
+
static int
json_object_i(VALUE key, VALUE val, VALUE _arg)
{
@@ -1015,22 +967,34 @@ json_object_i(VALUE key, VALUE val, VALUE _arg)
FBuffer *buffer = data->buffer;
JSON_Generator_State *state = data->state;
- long depth = state->depth;
- int j;
+ long depth = data->depth;
+ int key_type = rb_type(key);
+
+ if (arg->first) {
+ arg->first = false;
+ arg->first_key_type = key_type;
+ }
+ else {
+ fbuffer_append_char(buffer, ',');
+ }
- if (arg->iter > 0) fbuffer_append_char(buffer, ',');
if (RB_UNLIKELY(data->state->object_nl)) {
fbuffer_append_str(buffer, data->state->object_nl);
}
if (RB_UNLIKELY(data->state->indent)) {
- for (j = 0; j < depth; j++) {
- fbuffer_append_str(buffer, data->state->indent);
- }
+ fbuffer_append_str_repeat(buffer, data->state->indent, depth);
}
VALUE key_to_s;
- switch (rb_type(key)) {
+ bool as_json_called = false;
+
+ start:
+ switch (key_type) {
case T_STRING:
+ if (RB_UNLIKELY(arg->first_key_type != T_STRING)) {
+ json_inspect_hash_with_mixed_keys(arg);
+ }
+
if (RB_LIKELY(RBASIC_CLASS(key) == rb_cString)) {
key_to_s = key;
} else {
@@ -1038,15 +1002,31 @@ json_object_i(VALUE key, VALUE val, VALUE _arg)
}
break;
case T_SYMBOL:
+ if (RB_UNLIKELY(arg->first_key_type != T_SYMBOL)) {
+ json_inspect_hash_with_mixed_keys(arg);
+ }
+
key_to_s = rb_sym2str(key);
break;
default:
+ if (data->state->strict) {
+ if (RTEST(data->state->as_json) && !as_json_called) {
+ key = json_call_as_json(data->state, key, Qtrue);
+ key_type = rb_type(key);
+ as_json_called = true;
+ goto start;
+ } else {
+ raise_generator_error(key, "%"PRIsVALUE" not allowed as object key in JSON", CLASS_OF(key));
+ }
+ }
key_to_s = rb_convert_type(key, T_STRING, "String", "to_s");
break;
}
+ key_to_s = ensure_valid_encoding(data, key_to_s, as_json_called, true);
+
if (RB_LIKELY(RBASIC_CLASS(key_to_s) == rb_cString)) {
- generate_json_string(buffer, data, key_to_s);
+ raw_generate_json_string(buffer, data, key_to_s);
} else {
generate_json(buffer, data, key_to_s);
}
@@ -1055,46 +1035,43 @@ json_object_i(VALUE key, VALUE val, VALUE _arg)
if (RB_UNLIKELY(state->space)) fbuffer_append_str(buffer, data->state->space);
generate_json(buffer, data, val);
- arg->iter++;
return ST_CONTINUE;
}
static inline long increase_depth(struct generate_json_data *data)
{
JSON_Generator_State *state = data->state;
- long depth = ++state->depth;
+ long depth = ++data->depth;
if (RB_UNLIKELY(depth > state->max_nesting && state->max_nesting)) {
- rb_raise(eNestingError, "nesting of %ld is too deep", --state->depth);
+ rb_raise(eNestingError, "nesting of %ld is too deep. Did you try to serialize objects with circular references?", --data->depth);
}
return depth;
}
static void generate_json_object(FBuffer *buffer, struct generate_json_data *data, VALUE obj)
{
- int j;
long depth = increase_depth(data);
if (RHASH_SIZE(obj) == 0) {
fbuffer_append(buffer, "{}", 2);
- --data->state->depth;
+ --data->depth;
return;
}
fbuffer_append_char(buffer, '{');
struct hash_foreach_arg arg = {
+ .hash = obj,
.data = data,
- .iter = 0,
+ .first = true,
};
rb_hash_foreach(obj, json_object_i, (VALUE)&arg);
- depth = --data->state->depth;
+ depth = --data->depth;
if (RB_UNLIKELY(data->state->object_nl)) {
fbuffer_append_str(buffer, data->state->object_nl);
if (RB_UNLIKELY(data->state->indent)) {
- for (j = 0; j < depth; j++) {
- fbuffer_append_str(buffer, data->state->indent);
- }
+ fbuffer_append_str_repeat(buffer, data->state->indent, depth);
}
}
fbuffer_append_char(buffer, '}');
@@ -1102,125 +1079,41 @@ static void generate_json_object(FBuffer *buffer, struct generate_json_data *dat
static void generate_json_array(FBuffer *buffer, struct generate_json_data *data, VALUE obj)
{
- int i, j;
long depth = increase_depth(data);
if (RARRAY_LEN(obj) == 0) {
fbuffer_append(buffer, "[]", 2);
- --data->state->depth;
+ --data->depth;
return;
}
fbuffer_append_char(buffer, '[');
if (RB_UNLIKELY(data->state->array_nl)) fbuffer_append_str(buffer, data->state->array_nl);
- for (i = 0; i < RARRAY_LEN(obj); i++) {
+ for (int i = 0; i < RARRAY_LEN(obj); i++) {
if (i > 0) {
fbuffer_append_char(buffer, ',');
if (RB_UNLIKELY(data->state->array_nl)) fbuffer_append_str(buffer, data->state->array_nl);
}
if (RB_UNLIKELY(data->state->indent)) {
- for (j = 0; j < depth; j++) {
- fbuffer_append_str(buffer, data->state->indent);
- }
+ fbuffer_append_str_repeat(buffer, data->state->indent, depth);
}
generate_json(buffer, data, RARRAY_AREF(obj, i));
}
- data->state->depth = --depth;
+ data->depth = --depth;
if (RB_UNLIKELY(data->state->array_nl)) {
fbuffer_append_str(buffer, data->state->array_nl);
if (RB_UNLIKELY(data->state->indent)) {
- for (j = 0; j < depth; j++) {
- fbuffer_append_str(buffer, data->state->indent);
- }
+ fbuffer_append_str_repeat(buffer, data->state->indent, depth);
}
}
fbuffer_append_char(buffer, ']');
}
-static inline int enc_utf8_compatible_p(int enc_idx)
-{
- if (enc_idx == usascii_encindex) return 1;
- if (enc_idx == utf8_encindex) return 1;
- return 0;
-}
-
-static VALUE encode_json_string_try(VALUE str)
-{
- return rb_funcall(str, i_encode, 1, Encoding_UTF_8);
-}
-
-static VALUE encode_json_string_rescue(VALUE str, VALUE exception)
-{
- raise_generator_error_str(str, rb_funcall(exception, rb_intern("message"), 0));
- return Qundef;
-}
-
-static inline VALUE ensure_valid_encoding(VALUE str)
-{
- int encindex = RB_ENCODING_GET(str);
- VALUE utf8_string;
- if (RB_UNLIKELY(!enc_utf8_compatible_p(encindex))) {
- if (encindex == binary_encindex) {
- utf8_string = rb_enc_associate_index(rb_str_dup(str), utf8_encindex);
- switch (rb_enc_str_coderange(utf8_string)) {
- case ENC_CODERANGE_7BIT:
- return utf8_string;
- case ENC_CODERANGE_VALID:
- // For historical reason, we silently reinterpret binary strings as UTF-8 if it would work.
- // TODO: Raise in 3.0.0
- rb_warn("JSON.generate: UTF-8 string passed as BINARY, this will raise an encoding error in json 3.0");
- return utf8_string;
- break;
- }
- }
-
- str = rb_rescue(encode_json_string_try, str, encode_json_string_rescue, str);
- }
- return str;
-}
-
-static void generate_json_string(FBuffer *buffer, struct generate_json_data *data, VALUE obj)
-{
- obj = ensure_valid_encoding(obj);
-
- fbuffer_append_char(buffer, '"');
-
- long len;
- search_state search;
- search.buffer = buffer;
- RSTRING_GETMEM(obj, search.ptr, len);
- search.cursor = search.ptr;
- search.end = search.ptr + len;
-
-#ifdef HAVE_SIMD
- search.matches_mask = 0;
- search.has_matches = false;
- search.chunk_base = NULL;
-#endif /* HAVE_SIMD */
-
- switch (rb_enc_str_coderange(obj)) {
- case ENC_CODERANGE_7BIT:
- case ENC_CODERANGE_VALID:
- if (RB_UNLIKELY(data->state->ascii_only)) {
- convert_UTF8_to_ASCII_only_JSON(&search, data->state->script_safe ? script_safe_escape_table : ascii_only_escape_table);
- } else if (RB_UNLIKELY(data->state->script_safe)) {
- convert_UTF8_to_script_safe_JSON(&search);
- } else {
- convert_UTF8_to_JSON(&search);
- }
- break;
- default:
- raise_generator_error(obj, "source sequence is illegal/malformed utf-8");
- break;
- }
- fbuffer_append_char(buffer, '"');
-}
-
static void generate_json_fallback(FBuffer *buffer, struct generate_json_data *data, VALUE obj)
{
VALUE tmp;
if (rb_respond_to(obj, i_to_json)) {
- tmp = rb_funcall(obj, i_to_json, 1, vstate_get(data));
+ tmp = json_call_to_json(data, obj);
Check_Type(tmp, T_STRING);
fbuffer_append_str(buffer, tmp);
} else {
@@ -1262,19 +1155,9 @@ static void generate_json_fixnum(FBuffer *buffer, struct generate_json_data *dat
static void generate_json_bignum(FBuffer *buffer, struct generate_json_data *data, VALUE obj)
{
VALUE tmp = rb_funcall(obj, i_to_s, 0);
- fbuffer_append_str(buffer, tmp);
+ fbuffer_append_str(buffer, StringValue(tmp));
}
-#ifdef RUBY_INTEGER_UNIFICATION
-static void generate_json_integer(FBuffer *buffer, struct generate_json_data *data, VALUE obj)
-{
- if (FIXNUM_P(obj))
- generate_json_fixnum(buffer, data, obj);
- else
- generate_json_bignum(buffer, data, obj);
-}
-#endif
-
static void generate_json_float(FBuffer *buffer, struct generate_json_data *data, VALUE obj)
{
double value = RFLOAT_VALUE(obj);
@@ -1283,11 +1166,11 @@ static void generate_json_float(FBuffer *buffer, struct generate_json_data *data
/* for NaN and Infinity values we either raise an error or rely on Float#to_s. */
if (!allow_nan) {
if (data->state->strict && data->state->as_json) {
- VALUE casted_obj = rb_proc_call_with_block(data->state->as_json, 1, &obj, Qnil);
+ VALUE casted_obj = json_call_as_json(data->state, obj, Qfalse);
if (casted_obj != obj) {
increase_depth(data);
generate_json(buffer, data, casted_obj);
- data->state->depth--;
+ data->depth--;
return;
}
}
@@ -1300,12 +1183,11 @@ static void generate_json_float(FBuffer *buffer, struct generate_json_data *data
}
/* This implementation writes directly into the buffer. We reserve
- * the 28 characters that fpconv_dtoa states as its maximum.
+ * the 32 characters that fpconv_dtoa states as its maximum.
*/
- fbuffer_inc_capa(buffer, 28);
+ fbuffer_inc_capa(buffer, 32);
char* d = buffer->ptr + buffer->len;
int len = fpconv_dtoa(value, d);
-
/* fpconv_dtoa converts a float to its shortest string representation,
* but it adds a ".0" if this is a plain integer.
*/
@@ -1319,7 +1201,7 @@ static void generate_json_fragment(FBuffer *buffer, struct generate_json_data *d
fbuffer_append_str(buffer, fragment);
}
-static void generate_json(FBuffer *buffer, struct generate_json_data *data, VALUE obj)
+static inline void generate_json_general(FBuffer *buffer, struct generate_json_data *data, VALUE obj, bool fallback)
{
bool as_json_called = false;
start:
@@ -1346,22 +1228,31 @@ start:
generate_json_bignum(buffer, data, obj);
break;
case T_HASH:
- if (klass != rb_cHash) goto general;
+ if (fallback && klass != rb_cHash) goto general;
generate_json_object(buffer, data, obj);
break;
case T_ARRAY:
- if (klass != rb_cArray) goto general;
+ if (fallback && klass != rb_cArray) goto general;
generate_json_array(buffer, data, obj);
break;
case T_STRING:
- if (klass != rb_cString) goto general;
- generate_json_string(buffer, data, obj);
+ if (fallback && klass != rb_cString) goto general;
+
+ if (RB_LIKELY(valid_json_string_p(obj))) {
+ raw_generate_json_string(buffer, data, obj);
+ } else if (as_json_called) {
+ raise_generator_error(obj, "source sequence is illegal/malformed utf-8");
+ } else {
+ obj = ensure_valid_encoding(data, obj, false, false);
+ as_json_called = true;
+ goto start;
+ }
break;
case T_SYMBOL:
generate_json_symbol(buffer, data, obj);
break;
case T_FLOAT:
- if (klass != rb_cFloat) goto general;
+ if (fallback && klass != rb_cFloat) goto general;
generate_json_float(buffer, data, obj);
break;
case T_STRUCT:
@@ -1372,7 +1263,7 @@ start:
general:
if (data->state->strict) {
if (RTEST(data->state->as_json) && !as_json_called) {
- obj = rb_proc_call_with_block(data->state->as_json, 1, &obj, Qnil);
+ obj = json_call_as_json(data->state, obj, Qfalse);
as_json_called = true;
goto start;
} else {
@@ -1385,26 +1276,34 @@ start:
}
}
+static void generate_json(FBuffer *buffer, struct generate_json_data *data, VALUE obj)
+{
+ generate_json_general(buffer, data, obj, true);
+}
+
+static void generate_json_no_fallback(FBuffer *buffer, struct generate_json_data *data, VALUE obj)
+{
+ generate_json_general(buffer, data, obj, false);
+}
+
static VALUE generate_json_try(VALUE d)
{
struct generate_json_data *data = (struct generate_json_data *)d;
data->func(data->buffer, data, data->obj);
- return Qnil;
+ return fbuffer_finalize(data->buffer);
}
-static VALUE generate_json_rescue(VALUE d, VALUE exc)
+static VALUE generate_json_ensure(VALUE d)
{
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, generator_func func, VALUE io)
+static inline VALUE cState_partial_generate(VALUE self, VALUE obj, generator_func func, VALUE io)
{
GET_STATE(self);
@@ -1416,14 +1315,13 @@ static VALUE cState_partial_generate(VALUE self, VALUE obj, generator_func func,
struct generate_json_data data = {
.buffer = &buffer,
- .vstate = self,
+ .vstate = Qfalse, // don't use self as it may be frozen and its depth is mutated when calling to_json
.state = state,
+ .depth = state->depth,
.obj = obj,
.func = func
};
- rb_rescue(generate_json_try, (VALUE)&data, generate_json_rescue, (VALUE)&data);
-
- return fbuffer_finalize(&buffer);
+ return rb_ensure(generate_json_try, (VALUE)&data, generate_json_ensure, (VALUE)&data);
}
/* call-seq:
@@ -1439,10 +1337,16 @@ static VALUE cState_generate(int argc, VALUE *argv, VALUE self)
rb_check_arity(argc, 1, 2);
VALUE obj = argv[0];
VALUE io = argc > 1 ? argv[1] : Qnil;
- VALUE result = cState_partial_generate(self, obj, generate_json, io);
- GET_STATE(self);
- (void)state;
- return result;
+ return cState_partial_generate(self, obj, generate_json, io);
+}
+
+/* :nodoc: */
+static VALUE cState_generate_no_fallback(int argc, VALUE *argv, VALUE self)
+{
+ rb_check_arity(argc, 1, 2);
+ VALUE obj = argv[0];
+ VALUE io = argc > 1 ? argv[1] : Qnil;
+ return cState_partial_generate(self, obj, generate_json_no_fallback, io);
}
static VALUE cState_initialize(int argc, VALUE *argv, VALUE self)
@@ -1467,12 +1371,14 @@ static VALUE cState_init_copy(VALUE obj, VALUE orig)
if (!objState) rb_raise(rb_eArgError, "unallocated JSON::State");
MEMCPY(objState, origState, JSON_Generator_State, 1);
- objState->indent = origState->indent;
- objState->space = origState->space;
- objState->space_before = origState->space_before;
- objState->object_nl = origState->object_nl;
- objState->array_nl = origState->array_nl;
- objState->as_json = origState->as_json;
+
+ RB_OBJ_WRITTEN(obj, Qundef, objState->indent);
+ RB_OBJ_WRITTEN(obj, Qundef, objState->space);
+ RB_OBJ_WRITTEN(obj, Qundef, objState->space_before);
+ RB_OBJ_WRITTEN(obj, Qundef, objState->object_nl);
+ RB_OBJ_WRITTEN(obj, Qundef, objState->array_nl);
+ RB_OBJ_WRITTEN(obj, Qundef, objState->as_json);
+
return obj;
}
@@ -1523,6 +1429,7 @@ static VALUE string_config(VALUE config)
*/
static VALUE cState_indent_set(VALUE self, VALUE indent)
{
+ rb_check_frozen(self);
GET_STATE(self);
RB_OBJ_WRITE(self, &state->indent, string_config(indent));
return Qnil;
@@ -1548,6 +1455,7 @@ static VALUE cState_space(VALUE self)
*/
static VALUE cState_space_set(VALUE self, VALUE space)
{
+ rb_check_frozen(self);
GET_STATE(self);
RB_OBJ_WRITE(self, &state->space, string_config(space));
return Qnil;
@@ -1571,6 +1479,7 @@ static VALUE cState_space_before(VALUE self)
*/
static VALUE cState_space_before_set(VALUE self, VALUE space_before)
{
+ rb_check_frozen(self);
GET_STATE(self);
RB_OBJ_WRITE(self, &state->space_before, string_config(space_before));
return Qnil;
@@ -1596,6 +1505,7 @@ static VALUE cState_object_nl(VALUE self)
*/
static VALUE cState_object_nl_set(VALUE self, VALUE object_nl)
{
+ rb_check_frozen(self);
GET_STATE(self);
RB_OBJ_WRITE(self, &state->object_nl, string_config(object_nl));
return Qnil;
@@ -1619,6 +1529,7 @@ static VALUE cState_array_nl(VALUE self)
*/
static VALUE cState_array_nl_set(VALUE self, VALUE array_nl)
{
+ rb_check_frozen(self);
GET_STATE(self);
RB_OBJ_WRITE(self, &state->array_nl, string_config(array_nl));
return Qnil;
@@ -1642,6 +1553,7 @@ static VALUE cState_as_json(VALUE self)
*/
static VALUE cState_as_json_set(VALUE self, VALUE as_json)
{
+ rb_check_frozen(self);
GET_STATE(self);
RB_OBJ_WRITE(self, &state->as_json, rb_convert_type(as_json, T_DATA, "Proc", "to_proc"));
return Qnil;
@@ -1673,7 +1585,21 @@ static VALUE cState_max_nesting(VALUE self)
static long long_config(VALUE num)
{
- return RTEST(num) ? FIX2LONG(num) : 0;
+ return RTEST(num) ? NUM2LONG(num) : 0;
+}
+
+// depth must never be negative; reject early with a clear error.
+static long depth_config(VALUE num)
+{
+ if (!RTEST(num)) return 0;
+ long d = NUM2LONG(num);
+ if (RB_UNLIKELY(d < 0)) {
+ rb_raise(rb_eArgError, "depth must be >= 0 (got %ld)", d);
+ }
+ if (RB_UNLIKELY(d > INT_MAX)) {
+ rb_raise(rb_eArgError, "depth is too large (got %ld)", d);
+ }
+ return d;
}
/*
@@ -1684,6 +1610,7 @@ static long long_config(VALUE num)
*/
static VALUE cState_max_nesting_set(VALUE self, VALUE depth)
{
+ rb_check_frozen(self);
GET_STATE(self);
state->max_nesting = long_config(depth);
return Qnil;
@@ -1709,6 +1636,7 @@ static VALUE cState_script_safe(VALUE self)
*/
static VALUE cState_script_safe_set(VALUE self, VALUE enable)
{
+ rb_check_frozen(self);
GET_STATE(self);
state->script_safe = RTEST(enable);
return Qnil;
@@ -1740,6 +1668,7 @@ static VALUE cState_strict(VALUE self)
*/
static VALUE cState_strict_set(VALUE self, VALUE enable)
{
+ rb_check_frozen(self);
GET_STATE(self);
state->strict = RTEST(enable);
return Qnil;
@@ -1764,6 +1693,7 @@ static VALUE cState_allow_nan_p(VALUE self)
*/
static VALUE cState_allow_nan_set(VALUE self, VALUE enable)
{
+ rb_check_frozen(self);
GET_STATE(self);
state->allow_nan = RTEST(enable);
return Qnil;
@@ -1788,11 +1718,25 @@ static VALUE cState_ascii_only_p(VALUE self)
*/
static VALUE cState_ascii_only_set(VALUE self, VALUE enable)
{
+ rb_check_frozen(self);
GET_STATE(self);
state->ascii_only = RTEST(enable);
return Qnil;
}
+static VALUE cState_allow_duplicate_key_p(VALUE self)
+{
+ GET_STATE(self);
+ switch (state->on_duplicate_key) {
+ case JSON_IGNORE:
+ return Qtrue;
+ case JSON_DEPRECATED:
+ return Qnil;
+ default:
+ return Qfalse;
+ }
+}
+
/*
* call-seq: depth
*
@@ -1812,8 +1756,9 @@ static VALUE cState_depth(VALUE self)
*/
static VALUE cState_depth_set(VALUE self, VALUE depth)
{
+ rb_check_frozen(self);
GET_STATE(self);
- state->depth = long_config(depth);
+ state->depth = depth_config(depth);
return Qnil;
}
@@ -1845,6 +1790,7 @@ static void buffer_initial_length_set(JSON_Generator_State *state, VALUE buffer_
*/
static VALUE cState_buffer_initial_length_set(VALUE self, VALUE buffer_initial_length)
{
+ rb_check_frozen(self);
GET_STATE(self);
buffer_initial_length_set(state, buffer_initial_length);
return Qnil;
@@ -1877,13 +1823,15 @@ static int configure_state_i(VALUE key, VALUE val, VALUE _arg)
else if (key == sym_max_nesting) { state->max_nesting = long_config(val); }
else if (key == sym_allow_nan) { state->allow_nan = RTEST(val); }
else if (key == sym_ascii_only) { state->ascii_only = RTEST(val); }
- else if (key == sym_depth) { state->depth = long_config(val); }
+ else if (key == sym_depth) { state->depth = depth_config(val); }
else if (key == sym_buffer_initial_length) { buffer_initial_length_set(state, val); }
else if (key == sym_script_safe) { state->script_safe = RTEST(val); }
else if (key == sym_escape_slash) { state->script_safe = RTEST(val); }
else if (key == sym_strict) { state->strict = RTEST(val); }
+ else if (key == sym_allow_duplicate_key) { state->on_duplicate_key = RTEST(val) ? JSON_IGNORE : JSON_RAISE; }
else if (key == sym_as_json) {
VALUE proc = RTEST(val) ? rb_convert_type(val, T_DATA, "Proc", "to_proc") : Qfalse;
+ state->as_json_single_arg = proc && rb_proc_arity(proc) == 1;
state_write_value(data, &state->as_json, proc);
}
return ST_CONTINUE;
@@ -1909,12 +1857,13 @@ static void configure_state(JSON_Generator_State *state, VALUE vstate, VALUE con
static VALUE cState_configure(VALUE self, VALUE opts)
{
+ rb_check_frozen(self);
GET_STATE(self);
configure_state(state, self, opts);
return self;
}
-static VALUE cState_m_generate(VALUE klass, VALUE obj, VALUE opts, VALUE io)
+static VALUE cState_m_do_generate(VALUE klass, VALUE obj, VALUE opts, VALUE io, generator_func func)
{
JSON_Generator_State state = {0};
state_init(&state);
@@ -1930,17 +1879,23 @@ static VALUE cState_m_generate(VALUE klass, VALUE obj, VALUE opts, VALUE io)
.buffer = &buffer,
.vstate = Qfalse,
.state = &state,
+ .depth = state.depth,
.obj = obj,
- .func = generate_json,
+ .func = func,
};
- rb_rescue(generate_json_try, (VALUE)&data, generate_json_rescue, (VALUE)&data);
+ return rb_ensure(generate_json_try, (VALUE)&data, generate_json_ensure, (VALUE)&data);
+}
- return fbuffer_finalize(&buffer);
+static VALUE cState_m_generate(VALUE klass, VALUE obj, VALUE opts, VALUE io)
+{
+ return cState_m_do_generate(klass, obj, opts, io, generate_json);
+}
+
+static VALUE cState_m_generate_no_fallback(VALUE klass, VALUE obj, VALUE opts, VALUE io)
+{
+ return cState_m_do_generate(klass, obj, opts, io, generate_json_no_fallback);
}
-/*
- *
- */
void Init_generator(void)
{
#ifdef HAVE_RB_EXT_RACTOR_SAFE
@@ -2005,45 +1960,12 @@ void Init_generator(void)
rb_define_method(cState, "buffer_initial_length", cState_buffer_initial_length, 0);
rb_define_method(cState, "buffer_initial_length=", cState_buffer_initial_length_set, 1);
rb_define_method(cState, "generate", cState_generate, -1);
- rb_define_alias(cState, "generate_new", "generate"); // :nodoc:
+ rb_define_method(cState, "_generate_no_fallback", cState_generate_no_fallback, -1);
- rb_define_singleton_method(cState, "generate", cState_m_generate, 3);
-
- VALUE mGeneratorMethods = rb_define_module_under(mGenerator, "GeneratorMethods");
-
- VALUE mObject = rb_define_module_under(mGeneratorMethods, "Object");
- rb_define_method(mObject, "to_json", mObject_to_json, -1);
-
- VALUE mHash = rb_define_module_under(mGeneratorMethods, "Hash");
- rb_define_method(mHash, "to_json", mHash_to_json, -1);
-
- VALUE mArray = rb_define_module_under(mGeneratorMethods, "Array");
- rb_define_method(mArray, "to_json", mArray_to_json, -1);
-
-#ifdef RUBY_INTEGER_UNIFICATION
- VALUE mInteger = rb_define_module_under(mGeneratorMethods, "Integer");
- rb_define_method(mInteger, "to_json", mInteger_to_json, -1);
-#else
- VALUE mFixnum = rb_define_module_under(mGeneratorMethods, "Fixnum");
- rb_define_method(mFixnum, "to_json", mFixnum_to_json, -1);
+ rb_define_private_method(cState, "allow_duplicate_key?", cState_allow_duplicate_key_p, 0);
- VALUE mBignum = rb_define_module_under(mGeneratorMethods, "Bignum");
- rb_define_method(mBignum, "to_json", mBignum_to_json, -1);
-#endif
- VALUE mFloat = rb_define_module_under(mGeneratorMethods, "Float");
- rb_define_method(mFloat, "to_json", mFloat_to_json, -1);
-
- VALUE mString = rb_define_module_under(mGeneratorMethods, "String");
- rb_define_method(mString, "to_json", mString_to_json, -1);
-
- VALUE mTrueClass = rb_define_module_under(mGeneratorMethods, "TrueClass");
- rb_define_method(mTrueClass, "to_json", mTrueClass_to_json, -1);
-
- VALUE mFalseClass = rb_define_module_under(mGeneratorMethods, "FalseClass");
- rb_define_method(mFalseClass, "to_json", mFalseClass_to_json, -1);
-
- VALUE mNilClass = rb_define_module_under(mGeneratorMethods, "NilClass");
- rb_define_method(mNilClass, "to_json", mNilClass_to_json, -1);
+ rb_define_singleton_method(cState, "generate", cState_m_generate, 3);
+ rb_define_singleton_method(cState, "_generate_no_fallback", cState_m_generate_no_fallback, 3);
rb_global_variable(&Encoding_UTF_8);
Encoding_UTF_8 = rb_const_get(rb_path2class("Encoding"), rb_intern("UTF_8"));
@@ -2051,10 +1973,6 @@ void Init_generator(void)
i_to_s = rb_intern("to_s");
i_to_json = rb_intern("to_json");
i_new = rb_intern("new");
- i_pack = rb_intern("pack");
- i_unpack = rb_intern("unpack");
- i_create_id = rb_intern("create_id");
- i_extend = rb_intern("extend");
i_encode = rb_intern("encode");
sym_indent = ID2SYM(rb_intern("indent"));
@@ -2071,6 +1989,7 @@ void Init_generator(void)
sym_escape_slash = ID2SYM(rb_intern("escape_slash"));
sym_strict = ID2SYM(rb_intern("strict"));
sym_as_json = ID2SYM(rb_intern("as_json"));
+ sym_allow_duplicate_key = ID2SYM(rb_intern("allow_duplicate_key"));
usascii_encindex = rb_usascii_encindex();
utf8_encindex = rb_utf8_encindex();
@@ -2078,22 +1997,5 @@ void Init_generator(void)
rb_require("json/ext/generator/state");
-
- switch (find_simd_implementation()) {
-#ifdef HAVE_SIMD
-#ifdef HAVE_SIMD_NEON
- case SIMD_NEON:
- search_escape_basic_impl = search_escape_basic_neon;
- break;
-#endif /* HAVE_SIMD_NEON */
-#ifdef HAVE_SIMD_SSE2
- case SIMD_SSE2:
- search_escape_basic_impl = search_escape_basic_sse2;
- break;
-#endif /* HAVE_SIMD_SSE2 */
-#endif /* HAVE_SIMD */
- default:
- search_escape_basic_impl = search_escape_basic;
- break;
- }
+ simd_impl = find_simd_implementation();
}
diff --git a/ext/json/json.h b/ext/json/json.h
new file mode 100644
index 0000000000..cf9420d4dd
--- /dev/null
+++ b/ext/json/json.h
@@ -0,0 +1,134 @@
+#ifndef _JSON_H_
+#define _JSON_H_
+
+#include "ruby.h"
+#include "ruby/encoding.h"
+#include <stdint.h>
+
+#ifndef RBIMPL_ASSERT_OR_ASSUME
+# define RBIMPL_ASSERT_OR_ASSUME(x)
+#endif
+
+#if defined(RUBY_DEBUG) && RUBY_DEBUG
+# define JSON_ASSERT RUBY_ASSERT
+#else
+# ifdef JSON_DEBUG
+# include <assert.h>
+# define JSON_ASSERT(x) assert(x)
+# else
+# define JSON_ASSERT(x)
+# endif
+#endif
+
+/* shims */
+
+#if SIZEOF_UINT64_T == SIZEOF_LONG_LONG
+# define INT64T2NUM(x) LL2NUM(x)
+# define UINT64T2NUM(x) ULL2NUM(x)
+#elif SIZEOF_UINT64_T == SIZEOF_LONG
+# define INT64T2NUM(x) LONG2NUM(x)
+# define UINT64T2NUM(x) ULONG2NUM(x)
+#else
+# error No uint64_t conversion
+#endif
+
+/* This is the fallback definition from Ruby 3.4 */
+#ifndef RBIMPL_STDBOOL_H
+#if defined(__cplusplus)
+# if defined(HAVE_STDBOOL_H) && (__cplusplus >= 201103L)
+# include <cstdbool>
+# endif
+#elif defined(HAVE_STDBOOL_H)
+# include <stdbool.h>
+#elif !defined(HAVE__BOOL)
+typedef unsigned char _Bool;
+# define bool _Bool
+# define true ((_Bool)+1)
+# define false ((_Bool)+0)
+# define __bool_true_false_are_defined
+#endif
+#endif
+
+#ifndef HAVE_RUBY_XFREE_SIZED
+static inline void ruby_xfree_sized(void *ptr, size_t oldsize)
+{
+ ruby_xfree(ptr);
+}
+
+static inline void *ruby_xrealloc2_sized(void *ptr, size_t new_elems, size_t elem_size, size_t old_elems)
+{
+ return ruby_xrealloc2(ptr, new_elems, elem_size);
+}
+#endif
+
+# define JSON_SIZED_REALLOC_N(v, T, m, n) \
+ ((v) = (T *)ruby_xrealloc2_sized((void *)(v), (m), sizeof(T), (n)))
+
+# define JSON_SIZED_FREE(v) ruby_xfree_sized((void *)(v), sizeof(*(v)))
+# define JSON_SIZED_FREE_N(v, n) ruby_xfree_sized((void *)(v), sizeof(*(v)) * (n))
+
+#ifndef HAVE_RB_EXT_RACTOR_SAFE
+# undef RUBY_TYPED_FROZEN_SHAREABLE
+# define RUBY_TYPED_FROZEN_SHAREABLE 0
+#endif
+
+#ifdef RUBY_TYPED_EMBEDDABLE
+# define HAVE_RUBY_TYPED_EMBEDDABLE 1
+#else
+# ifdef HAVE_CONST_RUBY_TYPED_EMBEDDABLE
+# define RUBY_TYPED_EMBEDDABLE RUBY_TYPED_EMBEDDABLE
+# define HAVE_RUBY_TYPED_EMBEDDABLE 1
+# else
+# define RUBY_TYPED_EMBEDDABLE 0
+# endif
+#endif
+
+#ifndef NORETURN
+#if defined(__has_attribute) && __has_attribute(noreturn)
+#define NORETURN(x) __attribute__((noreturn)) x
+#else
+#define NORETURN(x) x
+#endif
+#endif
+
+#ifndef NOINLINE
+#if defined(__has_attribute) && __has_attribute(noinline)
+#define NOINLINE(x) __attribute__((noinline)) x
+#else
+#define NOINLINE(x) x
+#endif
+#endif
+
+#ifndef ALWAYS_INLINE
+#if defined(__has_attribute) && __has_attribute(always_inline)
+#define ALWAYS_INLINE(x) inline __attribute__((always_inline)) x
+#else
+#define ALWAYS_INLINE(x) inline x
+#endif
+#endif
+
+#ifndef RB_UNLIKELY
+#define RB_UNLIKELY(expr) expr
+#endif
+
+#ifndef RB_LIKELY
+#define RB_LIKELY(expr) expr
+#endif
+
+#ifndef MAYBE_UNUSED
+# define MAYBE_UNUSED(x) x
+#endif
+
+#ifdef RUBY_DEBUG
+#ifndef JSON_DEBUG
+#define JSON_DEBUG RUBY_DEBUG
+#endif
+#endif
+
+#if defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ && INTPTR_MAX == INT64_MAX
+#define JSON_CPU_LITTLE_ENDIAN_64BITS 1
+#else
+#define JSON_CPU_LITTLE_ENDIAN_64BITS 0
+#endif
+
+#endif // _JSON_H_
diff --git a/ext/json/lib/json.rb b/ext/json/lib/json.rb
index 0ebff2f948..26d601926f 100644
--- a/ext/json/lib/json.rb
+++ b/ext/json/lib/json.rb
@@ -6,6 +6,15 @@ require 'json/common'
#
# \JSON is a lightweight data-interchange format.
#
+# \JSON is easy for us humans to read and write,
+# and equally simple for machines to read (parse) and write (generate).
+#
+# \JSON is language-independent, making it an ideal interchange format
+# for applications in differing programming languages
+# and on differing operating systems.
+#
+# == \JSON Values
+#
# A \JSON value is one of the following:
# - Double-quoted text: <tt>"foo"</tt>.
# - Number: +1+, +1.0+, +2.0e2+.
@@ -173,6 +182,30 @@ require 'json/common'
# When enabled:
# JSON.parse('[1,]', allow_trailing_comma: true) # => [1]
#
+# ---
+#
+# Option +allow_control_characters+ (boolean) specifies whether to allow
+# unescaped ASCII control characters, such as newlines, in strings;
+# defaults to +false+.
+#
+# With the default, +false+:
+# JSON.parse(%{"Hello\nWorld"}) # invalid ASCII control character in string (JSON::ParserError)
+#
+# When enabled:
+# JSON.parse(%{"Hello\nWorld"}, allow_control_characters: true) # => "Hello\nWorld"
+#
+# ---
+#
+# Option +allow_invalid_escape+ (boolean) specifies whether to ignore backslahes that are followed
+# by an invalid escape character in strings;
+# defaults to +false+.
+#
+# With the default, +false+:
+# JSON.parse('"Hell\o"') # invalid escape character in string (JSON::ParserError)
+#
+# When enabled:
+# JSON.parse('"Hell\o"', allow_invalid_escape: true) # => "Hello"
+#
# ====== Output Options
#
# Option +freeze+ (boolean) specifies whether the returned objects will be frozen;
@@ -302,8 +335,27 @@ require 'json/common'
# JSON.generate(JSON::MinusInfinity)
#
# Allow:
-# ruby = [Float::NaN, Float::Infinity, Float::MinusInfinity]
-# JSON.generate(ruby, allow_nan: true) # => '[NaN,Infinity,-Infinity]'
+# ruby = [Float::NAN, Float::INFINITY, JSON::NaN, JSON::Infinity, JSON::MinusInfinity]
+# JSON.generate(ruby, allow_nan: true) # => '[NaN,Infinity,NaN,Infinity,-Infinity]'
+#
+# ---
+#
+# Option +allow_duplicate_key+ (boolean) specifies whether
+# hashes with duplicate keys should be allowed or produce an error.
+# defaults to emit a deprecation warning.
+#
+# With the default, (not set):
+# Warning[:deprecated] = true
+# JSON.generate({ foo: 1, "foo" => 2 })
+# # warning: detected duplicate key "foo" in {foo: 1, "foo" => 2}.
+# # This will raise an error in json 3.0 unless enabled via `allow_duplicate_key: true`
+# # => '{"foo":1,"foo":2}'
+#
+# With <tt>false</tt>
+# JSON.generate({ foo: 1, "foo" => 2 }, allow_duplicate_key: false)
+# # detected duplicate key "foo" in {foo: 1, "foo" => 2} (JSON::GeneratorError)
+#
+# In version 3.0, <tt>false</tt> will become the default.
#
# ---
#
@@ -384,6 +436,9 @@ require 'json/common'
#
# == \JSON Additions
#
+# Note that JSON Additions must only be used with trusted data, and is
+# deprecated.
+#
# When you "round trip" a non-\String object from Ruby to \JSON and back,
# you have a new \String, instead of the object you began with:
# ruby0 = Range.new(0, 2)
diff --git a/ext/json/lib/json/common.rb b/ext/json/lib/json/common.rb
index e99d152a88..230bf08012 100644
--- a/ext/json/lib/json/common.rb
+++ b/ext/json/lib/json/common.rb
@@ -71,9 +71,14 @@ module JSON
end
when object_class
if opts[:create_additions] != false
- if class_name = object[JSON.create_id]
- klass = JSON.deep_const_get(class_name)
- if (klass.respond_to?(:json_creatable?) && klass.json_creatable?) || klass.respond_to?(:json_create)
+ if class_path = object[JSON.create_id]
+ klass = begin
+ Object.const_get(class_path)
+ rescue NameError => e
+ raise ArgumentError, "can't get const #{class_path}: #{e}"
+ end
+
+ if klass.respond_to?(:json_creatable?) ? klass.json_creatable? : klass.respond_to?(:json_create)
create_additions_warning if create_additions.nil?
object = klass.json_create(object)
end
@@ -97,7 +102,7 @@ module JSON
class << self
def deprecation_warning(message, uplevel = 3) # :nodoc:
- gem_root = File.expand_path("../../../", __FILE__) + "/"
+ gem_root = File.expand_path("..", __dir__) + "/"
caller_locations(uplevel, 10).each do |frame|
if frame.path.nil? || frame.path.start_with?(gem_root) || frame.path.end_with?("/truffle/cext_ruby.rb", ".c")
uplevel += 1
@@ -147,29 +152,21 @@ module JSON
const_set :Parser, parser
end
- # Return the constant located at _path_. The format of _path_ has to be
- # either ::A::B::C or A::B::C. In any case, A has to be located at the top
- # level (absolute namespace path?). If there doesn't exist a constant at
- # the given path, an ArgumentError is raised.
- def deep_const_get(path) # :nodoc:
- Object.const_get(path)
- rescue NameError => e
- raise ArgumentError, "can't get const #{path}: #{e}"
- end
-
# Set the module _generator_ to be used by JSON.
def generator=(generator) # :nodoc:
old, $VERBOSE = $VERBOSE, nil
@generator = generator
- generator_methods = generator::GeneratorMethods
- for const in generator_methods.constants
- klass = const_get(const)
- modul = generator_methods.const_get(const)
- klass.class_eval do
- instance_methods(false).each do |m|
- m.to_s == 'to_json' and remove_method m
+ if generator.const_defined?(:GeneratorMethods)
+ generator_methods = generator::GeneratorMethods
+ for const in generator_methods.constants
+ klass = const_get(const)
+ modul = generator_methods.const_get(const)
+ klass.class_eval do
+ instance_methods(false).each do |m|
+ m.to_s == 'to_json' and remove_method m
+ end
+ include modul
end
- include modul
end
end
self.state = generator::State
@@ -186,6 +183,25 @@ module JSON
private
+ # Called from the extension when a hash has both string and symbol keys
+ def on_mixed_keys_hash(hash, do_raise)
+ set = {}
+ hash.each_key do |key|
+ key_str = key.to_s
+
+ if set[key_str]
+ message = "detected duplicate key #{key_str.inspect} in #{hash.inspect}"
+ if do_raise
+ raise GeneratorError, message
+ else
+ deprecation_warning("#{message}.\nThis will raise an error in json 3.0 unless enabled via `allow_duplicate_key: true`")
+ end
+ else
+ set[key_str] = true
+ end
+ end
+ end
+
def deprecated_singleton_attr_accessor(*attrs)
args = RUBY_VERSION >= "3.0" ? ", category: :deprecated" : ""
attrs.each do |attr|
@@ -391,7 +407,7 @@ module JSON
#
# Returns a \String containing the generated \JSON data.
#
- # See also JSON.fast_generate, JSON.pretty_generate.
+ # See also JSON.pretty_generate.
#
# Argument +obj+ is the Ruby object to be converted to \JSON.
#
@@ -536,6 +552,7 @@ module JSON
:create_additions => nil,
}
# :call-seq:
+ # JSON.unsafe_load(source, options = {}) -> object
# JSON.unsafe_load(source, proc = nil, options = {}) -> object
#
# Returns the Ruby objects created by parsing the given +source+.
@@ -643,6 +660,7 @@ module JSON
# when Array
# obj.map! {|v| deserialize_obj v }
# end
+ # obj
# })
# pp ruby
# Output:
@@ -666,7 +684,12 @@ module JSON
#
def unsafe_load(source, proc = nil, options = nil)
opts = if options.nil?
- _unsafe_load_default_options
+ if proc && proc.is_a?(Hash)
+ options, proc = proc, nil
+ options
+ else
+ _unsafe_load_default_options
+ end
else
_unsafe_load_default_options.merge(options)
end
@@ -684,12 +707,17 @@ module JSON
if opts[:allow_blank] && (source.nil? || source.empty?)
source = 'null'
end
- result = parse(source, opts)
- recurse_proc(result, &proc) if proc
- result
+
+ if proc
+ opts = opts.dup
+ opts[:on_load] = proc.to_proc
+ end
+
+ parse(source, opts)
end
# :call-seq:
+ # JSON.load(source, options = {}) -> object
# JSON.load(source, proc = nil, options = {}) -> object
#
# Returns the Ruby objects created by parsing the given +source+.
@@ -803,6 +831,7 @@ module JSON
# when Array
# obj.map! {|v| deserialize_obj v }
# end
+ # obj
# })
# pp ruby
# Output:
@@ -825,8 +854,18 @@ module JSON
# @attributes={"type"=>"Admin", "password"=>"0wn3d"}>}
#
def load(source, proc = nil, options = nil)
+ if proc && options.nil? && proc.is_a?(Hash)
+ options = proc
+ proc = nil
+ end
+
opts = if options.nil?
- _load_default_options
+ if proc && proc.is_a?(Hash)
+ options, proc = proc, nil
+ options
+ else
+ _load_default_options
+ end
else
_load_default_options.merge(options)
end
@@ -841,7 +880,7 @@ module JSON
end
end
- if opts[:allow_blank] && (source.nil? || source.empty?)
+ if opts[:allow_blank] && (source.nil? || (String === source && source.empty?))
source = 'null'
end
@@ -999,7 +1038,8 @@ module JSON
# JSON.new(options = nil, &block)
#
# Argument +options+, if given, contains a \Hash of options for both parsing and generating.
- # See {Parsing Options}[#module-JSON-label-Parsing+Options], and {Generating Options}[#module-JSON-label-Generating+Options].
+ # See {Parsing Options}[rdoc-ref:JSON@Parsing+Options],
+ # and {Generating Options}[rdoc-ref:JSON@Generating+Options].
#
# For generation, the <tt>strict: true</tt> option is always set. When a Ruby object with no native \JSON counterpart is
# encountered, the block provided to the initialize method is invoked, and must return a Ruby object that has a native
@@ -1028,7 +1068,7 @@ module JSON
options[:as_json] = as_json if as_json
@state = State.new(options).freeze
- @parser_config = Ext::Parser::Config.new(ParserOptions.prepare(options))
+ @parser_config = Ext::Parser::Config.new(ParserOptions.prepare(options)).freeze
end
# call-seq:
@@ -1037,7 +1077,7 @@ module JSON
#
# Serialize the given object into a \JSON document.
def dump(object, io = nil)
- @state.generate_new(object, io)
+ @state.generate(object, io)
end
alias_method :generate, :dump
@@ -1058,6 +1098,30 @@ module JSON
load(File.read(path, encoding: Encoding::UTF_8))
end
end
+
+ module GeneratorMethods
+ # call-seq: to_json(*)
+ #
+ # Converts this object into a JSON string.
+ # If this object doesn't directly maps to a JSON native type,
+ # first convert it to a string (calling #to_s), then converts
+ # it to a JSON string, and returns the result.
+ # This is a fallback, if no special method #to_json was defined for some object.
+ def to_json(state = nil, *)
+ obj = case self
+ when nil, false, true, Integer, Float, Array, Hash
+ self
+ else
+ "#{self}"
+ end
+
+ if state.nil?
+ JSON::State._generate_no_fallback(obj, nil, nil)
+ else
+ JSON::State.from_state(state)._generate_no_fallback(obj)
+ end
+ end
+ end
end
module ::Kernel
@@ -1103,3 +1167,7 @@ module ::Kernel
JSON[object, opts]
end
end
+
+class Object
+ include JSON::GeneratorMethods
+end
diff --git a/ext/json/lib/json/ext/generator/state.rb b/ext/json/lib/json/ext/generator/state.rb
index d40c3b5ec3..e4f425af6a 100644
--- a/ext/json/lib/json/ext/generator/state.rb
+++ b/ext/json/lib/json/ext/generator/state.rb
@@ -8,20 +8,8 @@ module JSON
#
# Instantiates a new State object, configured by _opts_.
#
- # _opts_ can have the following keys:
- #
- # * *indent*: a string used to indent levels (default: ''),
- # * *space*: a string that is put after, a : or , delimiter (default: ''),
- # * *space_before*: a string that is put before a : pair delimiter (default: ''),
- # * *object_nl*: a string that is put at the end of a JSON object (default: ''),
- # * *array_nl*: a string that is put at the end of a JSON array (default: ''),
- # * *allow_nan*: true if NaN, Infinity, and -Infinity should be
- # generated, otherwise an exception is thrown, if these values are
- # encountered. This options defaults to false.
- # * *ascii_only*: true if only ASCII characters should be generated. This
- # option defaults to false.
- # * *buffer_initial_length*: sets the initial length of the generator's
- # internal buffer.
+ # Argument +opts+, if given, contains a \Hash of options for the generation.
+ # See {Generating Options}[rdoc-ref:JSON@Generating+Options].
def initialize(opts = nil)
if opts && !opts.empty?
configure(opts)
@@ -68,6 +56,11 @@ module JSON
buffer_initial_length: buffer_initial_length,
}
+ allow_duplicate_key = allow_duplicate_key?
+ unless allow_duplicate_key.nil?
+ result[:allow_duplicate_key] = allow_duplicate_key
+ end
+
instance_variables.each do |iv|
iv = iv.to_s[1..-1]
result[iv.to_sym] = self[iv]
@@ -82,6 +75,8 @@ module JSON
#
# Returns the value returned by method +name+.
def [](name)
+ ::JSON.deprecation_warning("JSON::State#[] is deprecated and will be removed in json 3.0.0")
+
if respond_to?(name)
__send__(name)
else
@@ -94,6 +89,8 @@ module JSON
#
# Sets the attribute name to value.
def []=(name, value)
+ ::JSON.deprecation_warning("JSON::State#[]= is deprecated and will be removed in json 3.0.0")
+
if respond_to?(name_writer = "#{name}=")
__send__ name_writer, value
else
diff --git a/ext/json/lib/json/generic_object.rb b/ext/json/lib/json/generic_object.rb
index ec5aa9dcb2..5c8ace354b 100644
--- a/ext/json/lib/json/generic_object.rb
+++ b/ext/json/lib/json/generic_object.rb
@@ -52,14 +52,6 @@ module JSON
table
end
- def [](name)
- __send__(name)
- end unless method_defined?(:[])
-
- def []=(name, value)
- __send__("#{name}=", value)
- end unless method_defined?(:[]=)
-
def |(other)
self.class[other.to_hash.merge(to_hash)]
end
diff --git a/ext/json/lib/json/version.rb b/ext/json/lib/json/version.rb
index f9ac3e17a9..30c0a71d2f 100644
--- a/ext/json/lib/json/version.rb
+++ b/ext/json/lib/json/version.rb
@@ -1,5 +1,5 @@
# frozen_string_literal: true
module JSON
- VERSION = '2.13.2'
+ VERSION = '2.19.8'
end
diff --git a/ext/json/parser/depend b/ext/json/parser/depend
index 1bb03d3517..d4737b1dfb 100644
--- a/ext/json/parser/depend
+++ b/ext/json/parser/depend
@@ -175,6 +175,8 @@ parser.o: $(hdrdir)/ruby/ruby.h
parser.o: $(hdrdir)/ruby/st.h
parser.o: $(hdrdir)/ruby/subst.h
parser.o: $(srcdir)/../fbuffer/fbuffer.h
+parser.o: $(srcdir)/../json.h
parser.o: $(srcdir)/../simd/simd.h
+parser.o: $(srcdir)/../vendor/ryu.h
parser.o: parser.c
# AUTOGENERATED DEPENDENCIES END
diff --git a/ext/json/parser/extconf.rb b/ext/json/parser/extconf.rb
index de5d5758b4..a9d740c755 100644
--- a/ext/json/parser/extconf.rb
+++ b/ext/json/parser/extconf.rb
@@ -1,10 +1,16 @@
# frozen_string_literal: true
require 'mkmf'
+$defs << "-DJSON_DEBUG" if ENV.fetch("JSON_DEBUG", "0") != "0"
have_func("rb_enc_interned_str", "ruby/encoding.h") # RUBY_VERSION >= 3.0
+have_func("rb_str_to_interned_str", "ruby.h") # RUBY_VERSION >= 3.0
have_func("rb_hash_new_capa", "ruby.h") # RUBY_VERSION >= 3.2
have_func("rb_hash_bulk_insert", "ruby.h") # Missing on TruffleRuby
-have_func("strnlen", "string.h") # Missing on Solaris 10
+have_func("ruby_xfree_sized", "ruby.h") # RUBY_VERSION >= 4.1
+
+if RUBY_ENGINE == "ruby"
+ have_const("RUBY_TYPED_EMBEDDABLE", "ruby.h") # RUBY_VERSION >= 3.3
+end
append_cflags("-std=c99")
diff --git a/ext/json/parser/parser.c b/ext/json/parser/parser.c
index 1e6ee753f0..c0631728c3 100644
--- a/ext/json/parser/parser.c
+++ b/ext/json/parser/parser.c
@@ -1,50 +1,22 @@
-#include "ruby.h"
-#include "ruby/encoding.h"
-
-/* shims */
-/* This is the fallback definition from Ruby 3.4 */
-
-#ifndef RBIMPL_STDBOOL_H
-#if defined(__cplusplus)
-# if defined(HAVE_STDBOOL_H) && (__cplusplus >= 201103L)
-# include <cstdbool>
-# endif
-#elif defined(HAVE_STDBOOL_H)
-# include <stdbool.h>
-#elif !defined(HAVE__BOOL)
-typedef unsigned char _Bool;
-# define bool _Bool
-# define true ((_Bool)+1)
-# define false ((_Bool)+0)
-# define __bool_true_false_are_defined
-#endif
-#endif
-
+#include "../json.h"
+#include "../vendor/ryu.h"
#include "../simd/simd.h"
-#ifndef RB_UNLIKELY
-#define RB_UNLIKELY(expr) expr
-#endif
-
-#ifndef RB_LIKELY
-#define RB_LIKELY(expr) expr
-#endif
-
static VALUE mJSON, eNestingError, Encoding_UTF_8;
static VALUE CNaN, CInfinity, CMinusInfinity;
-static ID i_chr, i_aset, i_aref,
- i_leftshift, i_new, i_try_convert, i_uminus, i_encode;
+static ID i_new, i_try_convert, i_uminus, i_encode;
-static VALUE sym_max_nesting, sym_allow_nan, sym_allow_trailing_comma, sym_symbolize_names, sym_freeze,
- sym_decimal_class, sym_on_load, sym_allow_duplicate_key;
+static VALUE sym_max_nesting, sym_allow_nan, sym_allow_trailing_comma, sym_allow_control_characters,
+ sym_allow_invalid_escape, sym_symbolize_names, sym_freeze, sym_decimal_class, sym_on_load,
+ sym_allow_duplicate_key;
static int binary_encindex;
static int utf8_encindex;
#ifndef HAVE_RB_HASH_BULK_INSERT
// For TruffleRuby
-void
+static void
rb_hash_bulk_insert(long count, const VALUE *pairs, VALUE hash)
{
long index = 0;
@@ -61,6 +33,12 @@ rb_hash_bulk_insert(long count, const VALUE *pairs, VALUE hash)
#define rb_hash_new_capa(n) rb_hash_new()
#endif
+#ifndef HAVE_RB_STR_TO_INTERNED_STR
+static VALUE rb_str_to_interned_str(VALUE str)
+{
+ return rb_funcall(rb_str_freeze(str), i_uminus, 0);
+}
+#endif
/* name cache */
@@ -106,116 +84,104 @@ static void rvalue_cache_insert_at(rvalue_cache *cache, int index, VALUE rstring
cache->entries[index] = rstring;
}
-static inline int rstring_cache_cmp(const char *str, const long length, VALUE rstring)
+#define rstring_cache_memcmp memcmp
+
+#if JSON_CPU_LITTLE_ENDIAN_64BITS
+#if __has_builtin(__builtin_bswap64)
+#undef rstring_cache_memcmp
+ALWAYS_INLINE(static) int rstring_cache_memcmp(const char *str, const char *rptr, const long length)
{
- long rstring_length = RSTRING_LEN(rstring);
- if (length == rstring_length) {
- return memcmp(str, RSTRING_PTR(rstring), length);
- } else {
- return (int)(length - rstring_length);
+ // The libc memcmp has numerous complex optimizations, but in this particular case,
+ // we know the string is small (JSON_RVALUE_CACHE_MAX_ENTRY_LENGTH), so being able to
+ // inline a simpler memcmp outperforms calling the libc version.
+ long i = 0;
+
+ for (; i + 8 <= length; i += 8) {
+ uint64_t a, b;
+ memcpy(&a, str + i, 8);
+ memcpy(&b, rptr + i, 8);
+ if (a != b) {
+ a = __builtin_bswap64(a);
+ b = __builtin_bswap64(b);
+ return (a < b) ? -1 : 1;
+ }
}
+
+ for (; i < length; i++) {
+ if (str[i] != rptr[i]) {
+ return (str[i] < rptr[i]) ? -1 : 1;
+ }
+ }
+
+ return 0;
}
+#endif
+#endif
-static VALUE rstring_cache_fetch(rvalue_cache *cache, const char *str, const long length)
+ALWAYS_INLINE(static) int rstring_cache_cmp(const char *str, const long length, VALUE rstring)
{
- if (RB_UNLIKELY(length > JSON_RVALUE_CACHE_MAX_ENTRY_LENGTH)) {
- // Common names aren't likely to be very long. So we just don't
- // cache names above an arbitrary threshold.
- return Qfalse;
- }
+ const char *rstring_ptr;
+ long rstring_length;
- if (RB_UNLIKELY(!isalpha((unsigned char)str[0]))) {
- // Simple heuristic, if the first character isn't a letter,
- // we're much less likely to see this string again.
- // We mostly want to cache strings that are likely to be repeated.
- return Qfalse;
+ RSTRING_GETMEM(rstring, rstring_ptr, rstring_length);
+
+ if (length == rstring_length) {
+ return rstring_cache_memcmp(str, rstring_ptr, length);
+ } else {
+ return (int)(length - rstring_length);
}
+}
+ALWAYS_INLINE(static) VALUE rstring_cache_fetch(rvalue_cache *cache, const char *str, const long length)
+{
int low = 0;
int high = cache->length - 1;
- int mid = 0;
- int last_cmp = 0;
while (low <= high) {
- mid = (high + low) >> 1;
+ int mid = (high + low) >> 1;
VALUE entry = cache->entries[mid];
- last_cmp = rstring_cache_cmp(str, length, entry);
+ int cmp = rstring_cache_cmp(str, length, entry);
- if (last_cmp == 0) {
+ if (cmp == 0) {
return entry;
- } else if (last_cmp > 0) {
+ } else if (cmp > 0) {
low = mid + 1;
} else {
high = mid - 1;
}
}
- if (RB_UNLIKELY(memchr(str, '\\', length))) {
- // We assume the overwhelming majority of names don't need to be escaped.
- // But if they do, we have to fallback to the slow path.
- return Qfalse;
- }
-
VALUE rstring = build_interned_string(str, length);
if (cache->length < JSON_RVALUE_CACHE_CAPA) {
- if (last_cmp > 0) {
- mid += 1;
- }
-
- rvalue_cache_insert_at(cache, mid, rstring);
+ rvalue_cache_insert_at(cache, low, rstring);
}
return rstring;
}
static VALUE rsymbol_cache_fetch(rvalue_cache *cache, const char *str, const long length)
{
- if (RB_UNLIKELY(length > JSON_RVALUE_CACHE_MAX_ENTRY_LENGTH)) {
- // Common names aren't likely to be very long. So we just don't
- // cache names above an arbitrary threshold.
- return Qfalse;
- }
-
- if (RB_UNLIKELY(!isalpha((unsigned char)str[0]))) {
- // Simple heuristic, if the first character isn't a letter,
- // we're much less likely to see this string again.
- // We mostly want to cache strings that are likely to be repeated.
- return Qfalse;
- }
-
int low = 0;
int high = cache->length - 1;
- int mid = 0;
- int last_cmp = 0;
while (low <= high) {
- mid = (high + low) >> 1;
+ int mid = (high + low) >> 1;
VALUE entry = cache->entries[mid];
- last_cmp = rstring_cache_cmp(str, length, rb_sym2str(entry));
+ int cmp = rstring_cache_cmp(str, length, rb_sym2str(entry));
- if (last_cmp == 0) {
+ if (cmp == 0) {
return entry;
- } else if (last_cmp > 0) {
+ } else if (cmp > 0) {
low = mid + 1;
} else {
high = mid - 1;
}
}
- if (RB_UNLIKELY(memchr(str, '\\', length))) {
- // We assume the overwhelming majority of names don't need to be escaped.
- // But if they do, we have to fallback to the slow path.
- return Qfalse;
- }
-
VALUE rsymbol = build_symbol(str, length);
if (cache->length < JSON_RVALUE_CACHE_CAPA) {
- if (last_cmp > 0) {
- mid += 1;
- }
-
- rvalue_cache_insert_at(cache, mid, rsymbol);
+ rvalue_cache_insert_at(cache, low, rsymbol);
}
return rsymbol;
}
@@ -245,7 +211,7 @@ static rvalue_stack *rvalue_stack_grow(rvalue_stack *stack, VALUE *handle, rvalu
if (stack->type == RVALUE_STACK_STACK_ALLOCATED) {
stack = rvalue_stack_spill(stack, handle, stack_ref);
} else {
- REALLOC_N(stack->ptr, VALUE, required);
+ JSON_SIZED_REALLOC_N(stack->ptr, VALUE, required, stack->capa);
stack->capa = required;
}
return stack;
@@ -275,35 +241,62 @@ static void rvalue_stack_mark(void *ptr)
{
rvalue_stack *stack = (rvalue_stack *)ptr;
long index;
- for (index = 0; index < stack->head; index++) {
- rb_gc_mark(stack->ptr[index]);
+ if (stack && stack->ptr) {
+ for (index = 0; index < stack->head; index++) {
+ rb_gc_mark_movable(stack->ptr[index]);
+ }
}
}
+static void rvalue_stack_free_buffer(rvalue_stack *stack)
+{
+ JSON_SIZED_FREE_N(stack->ptr, stack->capa);
+ stack->ptr = NULL;
+}
+
static void rvalue_stack_free(void *ptr)
{
rvalue_stack *stack = (rvalue_stack *)ptr;
if (stack) {
- ruby_xfree(stack->ptr);
- ruby_xfree(stack);
+ rvalue_stack_free_buffer(stack);
+#ifndef HAVE_RUBY_TYPED_EMBEDDABLE
+ JSON_SIZED_FREE(stack);
+#endif
}
}
static size_t rvalue_stack_memsize(const void *ptr)
{
const rvalue_stack *stack = (const rvalue_stack *)ptr;
- return sizeof(rvalue_stack) + sizeof(VALUE) * stack->capa;
+ size_t memsize = sizeof(VALUE) * stack->capa;
+#ifndef HAVE_RUBY_TYPED_EMBEDDABLE
+ memsize += sizeof(rvalue_stack);
+#endif
+ return memsize;
+}
+
+static void rvalue_stack_compact(void *ptr)
+{
+ rvalue_stack *stack = (rvalue_stack *)ptr;
+ long index;
+ if (stack && stack->ptr) {
+ for (index = 0; index < stack->head; index++) {
+ stack->ptr[index] = rb_gc_location(stack->ptr[index]);
+ }
+ }
}
static const rb_data_type_t JSON_Parser_rvalue_stack_type = {
- "JSON::Ext::Parser/rvalue_stack",
- {
+ .wrap_struct_name = "JSON::Ext::Parser/rvalue_stack",
+ .function = {
.dmark = rvalue_stack_mark,
.dfree = rvalue_stack_free,
.dsize = rvalue_stack_memsize,
+ .dcompact = rvalue_stack_compact,
},
- 0, 0,
- RUBY_TYPED_FREE_IMMEDIATELY,
+ // We deliberately don't declare rvalue_stack as RUBY_TYPED_WB_PROTECTED
+ // because it churns a lot of values so trigering write barriers every time is very costly.
+ .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_EMBEDDABLE,
};
static rvalue_stack *rvalue_stack_spill(rvalue_stack *old_stack, VALUE *handle, rvalue_stack **stack_ref)
@@ -325,19 +318,206 @@ static void rvalue_stack_eagerly_release(VALUE handle)
if (handle) {
rvalue_stack *stack;
TypedData_Get_Struct(handle, rvalue_stack, &JSON_Parser_rvalue_stack_type, stack);
- RTYPEDDATA_DATA(handle) = NULL;
+#ifdef HAVE_RUBY_TYPED_EMBEDDABLE
+ rvalue_stack_free_buffer(stack);
+#else
rvalue_stack_free(stack);
+ RTYPEDDATA_DATA(handle) = NULL;
+#endif
+ }
+}
+
+/* frame stack */
+
+// Iterative (non-recursive) parsing keeps an explicit stack of the containers
+// currently being built, instead of relying on the C call stack. Each frame
+// only needs enough bookkeeping to close its container: which kind it is, the
+// rvalue_stack position where its children start (so we know how many to pop),
+// and the cursor at its opening brace (used to rewind for duplicate key
+// errors). Frames hold no VALUEs, so this stack needs no GC marking; it reuses
+// the same stack-allocated-with-heap-spill strategy as the rvalue_stack so that
+// it's freed even if parsing raises.
+//
+// The lifecycle helpers below (grow/push/peek/pop/spill/free/eagerly_release
+// and the rb_data_type_t) deliberately mirror their rvalue_stack counterparts
+// -- the element type and the absence of a mark function are the only real
+// differences. Keep the two in sync: a fix to the spill/release or
+// HAVE_RUBY_TYPED_EMBEDDABLE handling in one almost certainly belongs in the
+// other.
+#define JSON_FRAME_STACK_INITIAL_CAPA 32
+
+enum json_frame_type {
+ JSON_FRAME_ROOT, // == JSON_PHASE_DONE
+ JSON_FRAME_ARRAY, // == JSON_PHASE_ARRAY_COMMA
+ JSON_FRAME_OBJECT, // = JSON_PHASE_OBJECT_COMMA
+};
+
+// Where a frame is within its container's grammar. This is the entirety of the
+// parser's "what to do next" state: json_parse_any dispatches on the top
+// frame's phase and holds no resume state in C locals, so a parse can stop at
+// any value boundary and be resumed purely from the (persistable) frame stack.
+//
+// The first three phases are deliberately equal to the corresponding json_frame_type
+// to simplify the transition of phase in json_value_completed.
+enum json_frame_phase {
+ JSON_PHASE_DONE = JSON_FRAME_ROOT, // root only: the document value has been parsed
+ JSON_PHASE_ARRAY_COMMA = JSON_FRAME_ARRAY, // after a value: expecting ',' or the closing ']'
+ JSON_PHASE_OBJECT_COMMA = JSON_FRAME_OBJECT, // after a value: expecting ',' or the closing '}'
+ JSON_PHASE_VALUE, // expecting a value (document root, array element, or object value after ':')
+ JSON_PHASE_OBJECT_KEY, // expecting a '"' key (after '{' or ',')
+ JSON_PHASE_OBJECT_COLON, // object only: after a key, expecting ':'
+};
+
+typedef struct json_frame_struct {
+ enum json_frame_type type;
+ enum json_frame_phase phase;
+ long value_stack_head; // rvalue_stack->head when this container opened
+ const char *start_cursor; // object frames only (the '{'); NULL otherwise
+} json_frame;
+
+typedef struct json_frame_stack_struct {
+ enum rvalue_stack_type type; // shared with rvalue_stack: is ptr stack- or heap-allocated
+ long capa;
+ long head;
+ json_frame *ptr;
+} json_frame_stack;
+
+enum duplicate_key_action {
+ JSON_DEPRECATED = 0,
+ JSON_IGNORE,
+ JSON_RAISE,
+};
+
+typedef struct JSON_ParserStruct {
+ VALUE on_load_proc;
+ VALUE decimal_class;
+ ID decimal_method_id;
+ enum duplicate_key_action on_duplicate_key;
+ int max_nesting;
+ bool allow_nan;
+ bool allow_trailing_comma;
+ bool allow_control_characters;
+ bool allow_invalid_escape;
+ bool symbolize_names;
+ bool freeze;
+} JSON_ParserConfig;
+
+typedef struct JSON_ParserStateStruct {
+ VALUE *value_stack_handle;
+ VALUE *frame_stack_handle;
+ const char *start;
+ const char *cursor;
+ const char *end;
+ rvalue_stack *value_stack;
+ json_frame_stack *frames;
+ rvalue_cache name_cache;
+ int in_array;
+ int current_nesting;
+ unsigned int emitted_deprecations;
+} JSON_ParserState;
+
+static json_frame_stack *json_frame_stack_spill(json_frame_stack *old_stack, VALUE *handle, json_frame_stack **stack_ref);
+
+static json_frame_stack *json_frame_stack_grow(json_frame_stack *stack, VALUE *handle, json_frame_stack **stack_ref)
+{
+ long required = stack->capa * 2;
+
+ if (stack->type == RVALUE_STACK_STACK_ALLOCATED) {
+ stack = json_frame_stack_spill(stack, handle, stack_ref);
+ } else {
+ JSON_SIZED_REALLOC_N(stack->ptr, json_frame, required, stack->capa);
+ stack->capa = required;
}
+ return stack;
}
+static json_frame *json_frame_stack_push(JSON_ParserState *state, json_frame frame)
+{
+ json_frame_stack *stack = state->frames;
+ if (RB_UNLIKELY(stack->head >= stack->capa)) {
+ stack = json_frame_stack_grow(stack, state->frame_stack_handle, &state->frames);
+ }
+
+ json_frame *frame_ptr = &stack->ptr[stack->head++];
+ *frame_ptr = frame;
+ return frame_ptr;
+}
-#ifndef HAVE_STRNLEN
-static size_t strnlen(const char *s, size_t maxlen)
+static inline json_frame *json_frame_stack_peek(json_frame_stack *stack)
{
- char *p;
- return ((p = memchr(s, '\0', maxlen)) ? p - s : maxlen);
+ return &stack->ptr[stack->head - 1];
}
+
+static inline void json_frame_stack_pop(json_frame_stack *stack)
+{
+ stack->head--;
+}
+
+static void json_frame_stack_free_buffer(json_frame_stack *stack)
+{
+ JSON_SIZED_FREE_N(stack->ptr, stack->capa);
+ stack->ptr = NULL;
+}
+
+static void json_frame_stack_free(void *ptr)
+{
+ json_frame_stack *stack = (json_frame_stack *)ptr;
+ if (stack) {
+ json_frame_stack_free_buffer(stack);
+#ifndef HAVE_RUBY_TYPED_EMBEDDABLE
+ JSON_SIZED_FREE(stack);
#endif
+ }
+}
+
+static size_t json_frame_stack_memsize(const void *ptr)
+{
+ const json_frame_stack *stack = (const json_frame_stack *)ptr;
+
+ size_t memsize = sizeof(json_frame) * stack->capa;
+#ifndef HAVE_RUBY_TYPED_EMBEDDABLE
+ memsize += sizeof(json_frame_stack);
+#endif
+ return memsize;
+}
+
+static const rb_data_type_t JSON_Parser_frame_stack_type = {
+ .wrap_struct_name = "JSON::Ext::Parser/frame_stack",
+ .function = {
+ .dmark = NULL,
+ .dfree = json_frame_stack_free,
+ .dsize = json_frame_stack_memsize,
+ },
+ .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_EMBEDDABLE,
+};
+
+static json_frame_stack *json_frame_stack_spill(json_frame_stack *old_stack, VALUE *handle, json_frame_stack **stack_ref)
+{
+ json_frame_stack *stack;
+ *handle = TypedData_Make_Struct(0, json_frame_stack, &JSON_Parser_frame_stack_type, stack);
+ *stack_ref = stack;
+ MEMCPY(stack, old_stack, json_frame_stack, 1);
+
+ stack->capa = old_stack->capa << 1;
+ stack->ptr = ALLOC_N(json_frame, stack->capa);
+ stack->type = RVALUE_STACK_HEAP_ALLOCATED;
+ MEMCPY(stack->ptr, old_stack->ptr, json_frame, old_stack->head);
+ return stack;
+}
+
+static void json_frame_stack_eagerly_release(VALUE handle)
+{
+ if (handle) {
+ json_frame_stack *stack;
+ TypedData_Get_Struct(handle, json_frame_stack, &JSON_Parser_frame_stack_type, stack);
+#ifdef HAVE_RUBY_TYPED_EMBEDDABLE
+ json_frame_stack_free_buffer(stack);
+#else
+ json_frame_stack_free(stack);
+ RTYPEDDATA_DATA(handle) = NULL;
+#endif
+ }
+}
static int convert_UTF32_to_UTF8(char *buf, uint32_t ch)
{
@@ -365,38 +545,31 @@ static int convert_UTF32_to_UTF8(char *buf, uint32_t ch)
return len;
}
-enum duplicate_key_action {
- JSON_DEPRECATED = 0,
- JSON_IGNORE,
- JSON_RAISE,
-};
+static inline size_t rest(JSON_ParserState *state) {
+ return state->end - state->cursor;
+}
-typedef struct JSON_ParserStruct {
- VALUE on_load_proc;
- VALUE decimal_class;
- ID decimal_method_id;
- enum duplicate_key_action on_duplicate_key;
- int max_nesting;
- bool allow_nan;
- bool allow_trailing_comma;
- bool parsing_name;
- bool symbolize_names;
- bool freeze;
-} JSON_ParserConfig;
+static inline bool eos(JSON_ParserState *state) {
+ return state->cursor >= state->end;
+}
-typedef struct JSON_ParserStateStruct {
- VALUE stack_handle;
- const char *start;
- const char *cursor;
- const char *end;
- rvalue_stack *stack;
- rvalue_cache name_cache;
- int in_array;
- int current_nesting;
-} JSON_ParserState;
+static inline char peek(JSON_ParserState *state)
+{
+ if (RB_UNLIKELY(eos(state))) {
+ return 0;
+ }
+ return *state->cursor;
+}
static void cursor_position(JSON_ParserState *state, long *line_out, long *column_out)
{
+ JSON_ASSERT(state->cursor <= state->end);
+
+ // Redundant but helpful for hardening
+ if (RB_UNLIKELY(state->cursor > state->end)) {
+ state->cursor = state->end;
+ }
+
const char *cursor = state->cursor;
long column = 0;
long line = 1;
@@ -428,14 +601,9 @@ static void emit_parse_warning(const char *message, JSON_ParserState *state)
#define PARSE_ERROR_FRAGMENT_LEN 32
-#ifdef RBIMPL_ATTR_NORETURN
-RBIMPL_ATTR_NORETURN()
-#endif
-static void raise_parse_error(const char *format, JSON_ParserState *state)
+static VALUE build_parse_error_message(const char *format, JSON_ParserState *state, long line, long column)
{
unsigned char buffer[PARSE_ERROR_FRAGMENT_LEN + 3];
- long line, column;
- cursor_position(state, &line, &column);
const char *ptr = "EOF";
if (state->cursor && state->cursor < state->end) {
@@ -467,20 +635,28 @@ static void raise_parse_error(const char *format, JSON_ParserState *state)
}
}
- VALUE msg = rb_sprintf(format, ptr);
- VALUE message = rb_enc_sprintf(enc_utf8, "%s at line %ld column %ld", RSTRING_PTR(msg), line, column);
- RB_GC_GUARD(msg);
+ VALUE message = rb_enc_sprintf(enc_utf8, format, ptr);
+ rb_str_catf(message, " at line %ld column %ld", line, column);
+ return message;
+}
+static VALUE parse_error_new(VALUE message, long line, long column)
+{
VALUE exc = rb_exc_new_str(rb_path2class("JSON::ParserError"), message);
rb_ivar_set(exc, rb_intern("@line"), LONG2NUM(line));
rb_ivar_set(exc, rb_intern("@column"), LONG2NUM(column));
- rb_exc_raise(exc);
+ return exc;
}
-#ifdef RBIMPL_ATTR_NORETURN
-RBIMPL_ATTR_NORETURN()
-#endif
-static void raise_parse_error_at(const char *format, JSON_ParserState *state, const char *at)
+NORETURN(static) void raise_parse_error(const char *format, JSON_ParserState *state)
+{
+ long line, column;
+ cursor_position(state, &line, &column);
+ VALUE message = build_parse_error_message(format, state, line, column);
+ rb_exc_raise(parse_error_new(message, line, column));
+}
+
+NORETURN(static) void raise_parse_error_at(const char *format, JSON_ParserState *state, const char *at)
{
state->cursor = at;
raise_parse_error(format, state);
@@ -505,23 +681,24 @@ static const signed char digit_values[256] = {
-1, -1, -1, -1, -1, -1, -1
};
-static uint32_t unescape_unicode(JSON_ParserState *state, const unsigned char *p)
-{
- signed char b;
- uint32_t result = 0;
- b = digit_values[p[0]];
- if (b < 0) raise_parse_error_at("incomplete unicode character escape sequence at %s", state, (char *)p - 2);
- result = (result << 4) | (unsigned char)b;
- b = digit_values[p[1]];
- if (b < 0) raise_parse_error_at("incomplete unicode character escape sequence at %s", state, (char *)p - 2);
- result = (result << 4) | (unsigned char)b;
- b = digit_values[p[2]];
- if (b < 0) raise_parse_error_at("incomplete unicode character escape sequence at %s", state, (char *)p - 2);
- result = (result << 4) | (unsigned char)b;
- b = digit_values[p[3]];
- if (b < 0) raise_parse_error_at("incomplete unicode character escape sequence at %s", state, (char *)p - 2);
- result = (result << 4) | (unsigned char)b;
- return result;
+static uint32_t unescape_unicode(JSON_ParserState *state, const char *sp, const char *spe)
+{
+ if (RB_UNLIKELY(sp > spe - 4)) {
+ raise_parse_error_at("incomplete unicode character escape sequence at %s", state, sp - 2);
+ }
+
+ const unsigned char *p = (const unsigned char *)sp;
+
+ const signed char b0 = digit_values[p[0]];
+ const signed char b1 = digit_values[p[1]];
+ const signed char b2 = digit_values[p[2]];
+ const signed char b3 = digit_values[p[3]];
+
+ if (RB_UNLIKELY((signed char)(b0 | b1 | b2 | b3) < 0)) {
+ raise_parse_error_at("incomplete unicode character escape sequence at %s", state, sp - 2);
+ }
+
+ return ((uint32_t)b0 << 12) | ((uint32_t)b1 << 8) | ((uint32_t)b2 << 4) | (uint32_t)b3;
}
#define GET_PARSER_CONFIG \
@@ -530,61 +707,82 @@ static uint32_t unescape_unicode(JSON_ParserState *state, const unsigned char *p
static const rb_data_type_t JSON_ParserConfig_type;
-static const bool whitespace[256] = {
- [' '] = 1,
- ['\t'] = 1,
- ['\n'] = 1,
- ['\r'] = 1,
- ['/'] = 1,
-};
-
-static void
+NOINLINE(static) void
json_eat_comments(JSON_ParserState *state)
{
- if (state->cursor + 1 < state->end) {
- switch (state->cursor[1]) {
- case '/': {
- state->cursor = memchr(state->cursor, '\n', state->end - state->cursor);
- if (!state->cursor) {
- state->cursor = state->end;
- } else {
- state->cursor++;
- }
- break;
+ const char *start = state->cursor;
+ state->cursor++;
+
+ switch (peek(state)) {
+ case '/': {
+ state->cursor = memchr(state->cursor, '\n', state->end - state->cursor);
+ if (!state->cursor) {
+ state->cursor = state->end;
+ } else {
+ state->cursor++;
}
- case '*': {
- state->cursor += 2;
- while (true) {
- state->cursor = memchr(state->cursor, '*', state->end - state->cursor);
- if (!state->cursor) {
- raise_parse_error_at("unexpected end of input, expected closing '*/'", state, state->end);
- } else {
- state->cursor++;
- if (state->cursor < state->end && *state->cursor == '/') {
- state->cursor++;
- break;
- }
- }
+ break;
+ }
+ case '*': {
+ state->cursor++;
+
+ while (true) {
+ const char *next_match = memchr(state->cursor, '*', state->end - state->cursor);
+ if (!next_match) {
+ raise_parse_error_at("unterminated comment, expected closing '*/'", state, start);
+ }
+
+ state->cursor = next_match + 1;
+ if (peek(state) == '/') {
+ state->cursor++;
+ break;
}
- break;
}
- default:
- raise_parse_error("unexpected token %s", state);
- break;
+ break;
}
- } else {
- raise_parse_error("unexpected token %s", state);
+ default:
+ raise_parse_error_at("unexpected token %s", state, start);
+ break;
}
}
-static inline void
+ALWAYS_INLINE(static) void
json_eat_whitespace(JSON_ParserState *state)
{
- while (state->cursor < state->end && RB_UNLIKELY(whitespace[(unsigned char)*state->cursor])) {
- if (RB_LIKELY(*state->cursor != '/')) {
- state->cursor++;
- } else {
- json_eat_comments(state);
+ while (true) {
+ switch (peek(state)) {
+ case ' ':
+ state->cursor++;
+ break;
+ case '\n':
+ state->cursor++;
+
+ // Heuristic: if we see a newline, there is likely consecutive spaces after it.
+#if JSON_CPU_LITTLE_ENDIAN_64BITS
+ while (rest(state) > 8) {
+ uint64_t chunk;
+ memcpy(&chunk, state->cursor, sizeof(uint64_t));
+ if (chunk == 0x2020202020202020) {
+ state->cursor += 8;
+ continue;
+ }
+
+ uint32_t consecutive_spaces = trailing_zeros64(chunk ^ 0x2020202020202020) / CHAR_BIT;
+ state->cursor += consecutive_spaces;
+ break;
+ }
+#endif
+ break;
+ case '\t':
+ case '\r':
+ state->cursor++;
+ break;
+ case '/':
+ json_eat_comments(state);
+ break;
+
+ default:
+ return;
}
}
}
@@ -615,11 +813,22 @@ static inline VALUE build_string(const char *start, const char *end, bool intern
return result;
}
-static inline VALUE json_string_fastpath(JSON_ParserState *state, const char *string, const char *stringEnd, bool is_name, bool intern, bool symbolize)
+static inline bool json_string_cacheable_p(const char *string, size_t length)
{
+ // We mostly want to cache strings that are likely to be repeated.
+ // Simple heuristics:
+ // - Common names aren't likely to be very long. So we just don't cache names above an arbitrary threshold.
+ // - If the first character isn't a letter, we're much less likely to see this string again.
+ return length <= JSON_RVALUE_CACHE_MAX_ENTRY_LENGTH && rb_isalpha(string[0]);
+}
+
+static inline VALUE json_string_fastpath(JSON_ParserState *state, JSON_ParserConfig *config, const char *string, const char *stringEnd, bool is_name)
+{
+ bool intern = is_name || config->freeze;
+ bool symbolize = is_name && config->symbolize_names;
size_t bufferSize = stringEnd - string;
- if (is_name && state->in_array) {
+ if (is_name && state->in_array && RB_LIKELY(json_string_cacheable_p(string, bufferSize))) {
VALUE cached_key;
if (RB_UNLIKELY(symbolize)) {
cached_key = rsymbol_cache_fetch(&state->name_cache, string, bufferSize);
@@ -635,104 +844,129 @@ static inline VALUE json_string_fastpath(JSON_ParserState *state, const char *st
return build_string(string, stringEnd, intern, symbolize);
}
-static VALUE json_string_unescape(JSON_ParserState *state, const char *string, const char *stringEnd, bool is_name, bool intern, bool symbolize)
-{
- size_t bufferSize = stringEnd - string;
- const char *p = string, *pe = string, *unescape, *bufferStart;
- char *buffer;
- int unescape_len;
- char buf[4];
+#define JSON_MAX_UNESCAPE_POSITIONS 16
+typedef struct _json_unescape_positions {
+ long size;
+ const char **positions;
+ unsigned long additional_backslashes;
+} JSON_UnescapePositions;
- if (is_name && state->in_array) {
- VALUE cached_key;
- if (RB_UNLIKELY(symbolize)) {
- cached_key = rsymbol_cache_fetch(&state->name_cache, string, bufferSize);
- } else {
- cached_key = rstring_cache_fetch(&state->name_cache, string, bufferSize);
+static inline const char *json_next_backslash(const char *pe, const char *stringEnd, JSON_UnescapePositions *positions)
+{
+ while (positions->size) {
+ positions->size--;
+ const char *next_position = positions->positions[0];
+ positions->positions++;
+ if (next_position >= pe) {
+ return next_position;
}
+ }
- if (RB_LIKELY(cached_key)) {
- return cached_key;
- }
+ if (positions->additional_backslashes) {
+ positions->additional_backslashes--;
+ return memchr(pe, '\\', stringEnd - pe);
}
+ return NULL;
+}
+
+NOINLINE(static) VALUE json_string_unescape(JSON_ParserState *state, JSON_ParserConfig *config, const char *string, const char *stringEnd, bool is_name, JSON_UnescapePositions *positions)
+{
+ bool intern = is_name || config->freeze;
+ bool symbolize = is_name && config->symbolize_names;
+ size_t bufferSize = stringEnd - string;
+ const char *p = string, *pe = string, *bufferStart;
+ char *buffer;
+
VALUE result = rb_str_buf_new(bufferSize);
rb_enc_associate_index(result, utf8_encindex);
buffer = RSTRING_PTR(result);
bufferStart = buffer;
- while (pe < stringEnd && (pe = memchr(pe, '\\', stringEnd - pe))) {
- unescape = (char *) "?";
- unescape_len = 1;
+#define APPEND_CHAR(chr) *buffer++ = chr; p = ++pe;
+
+ while (pe < stringEnd && (pe = json_next_backslash(pe, stringEnd, positions))) {
if (pe > p) {
MEMCPY(buffer, p, char, pe - p);
buffer += pe - p;
}
switch (*++pe) {
+ case '"':
+ case '/':
+ p = pe; // nothing to unescape just need to skip the backslash
+ break;
+ case '\\':
+ APPEND_CHAR('\\');
+ break;
case 'n':
- unescape = (char *) "\n";
+ APPEND_CHAR('\n');
break;
case 'r':
- unescape = (char *) "\r";
+ APPEND_CHAR('\r');
break;
case 't':
- unescape = (char *) "\t";
- break;
- case '"':
- unescape = (char *) "\"";
- break;
- case '\\':
- unescape = (char *) "\\";
+ APPEND_CHAR('\t');
break;
case 'b':
- unescape = (char *) "\b";
+ APPEND_CHAR('\b');
break;
case 'f':
- unescape = (char *) "\f";
+ APPEND_CHAR('\f');
break;
- case 'u':
- if (pe > stringEnd - 5) {
- raise_parse_error_at("incomplete unicode character escape sequence at %s", state, p);
- } else {
- uint32_t ch = unescape_unicode(state, (unsigned char *) ++pe);
- pe += 3;
- /* To handle values above U+FFFF, we take a sequence of
- * \uXXXX escapes in the U+D800..U+DBFF then
- * U+DC00..U+DFFF ranges, take the low 10 bits from each
- * to make a 20-bit number, then add 0x10000 to get the
- * final codepoint.
- *
- * See Unicode 15: 3.8 "Surrogates", 5.3 "Handling
- * Surrogate Pairs in UTF-16", and 23.6 "Surrogates
- * Area".
- */
- if ((ch & 0xFC00) == 0xD800) {
- pe++;
- if (pe > stringEnd - 6) {
- raise_parse_error_at("incomplete surrogate pair at %s", state, p);
- }
- if (pe[0] == '\\' && pe[1] == 'u') {
- uint32_t sur = unescape_unicode(state, (unsigned char *) pe + 2);
- ch = (((ch & 0x3F) << 10) | ((((ch >> 6) & 0xF) + 1) << 16)
- | (sur & 0x3FF));
- pe += 5;
- } else {
- unescape = (char *) "?";
- break;
+ case 'u': {
+ uint32_t ch = unescape_unicode(state, ++pe, stringEnd);
+ pe += 3;
+ /* To handle values above U+FFFF, we take a sequence of
+ * \uXXXX escapes in the U+D800..U+DBFF then
+ * U+DC00..U+DFFF ranges, take the low 10 bits from each
+ * to make a 20-bit number, then add 0x10000 to get the
+ * final codepoint.
+ *
+ * See Unicode 15: 3.8 "Surrogates", 5.3 "Handling
+ * Surrogate Pairs in UTF-16", and 23.6 "Surrogates
+ * Area".
+ */
+ if ((ch & 0xFC00) == 0xD800) {
+ pe++;
+ if (RB_LIKELY((pe <= stringEnd - 6) && memcmp(pe, "\\u", 2) == 0)) {
+ uint32_t sur = unescape_unicode(state, pe + 2, stringEnd);
+
+ if (RB_UNLIKELY((sur & 0xFC00) != 0xDC00)) {
+ raise_parse_error_at("invalid surrogate pair at %s", state, p);
}
+
+ ch = (((ch & 0x3F) << 10) | ((((ch >> 6) & 0xF) + 1) << 16) | (sur & 0x3FF));
+ pe += 5;
+ } else {
+ raise_parse_error_at("incomplete surrogate pair at %s", state, p);
+ break;
}
- unescape_len = convert_UTF32_to_UTF8(buf, ch);
- unescape = buf;
}
+
+ int unescape_len = convert_UTF32_to_UTF8(buffer, ch);
+ buffer += unescape_len;
+ p = ++pe;
break;
+ }
default:
- p = pe;
- continue;
+ if ((unsigned char)*pe < 0x20) {
+ if (!config->allow_control_characters) {
+ if (*pe == '\n') {
+ raise_parse_error_at("Invalid unescaped newline character (\\n) in string: %s", state, pe - 1);
+ }
+ raise_parse_error_at("invalid ASCII control character in string: %s", state, pe - 1);
+ }
+ }
+
+ if (config->allow_invalid_escape) {
+ APPEND_CHAR(*pe);
+ } else {
+ raise_parse_error_at("invalid escape character in string: %s", state, pe - 1);
+ }
+ break;
}
- MEMCPY(buffer, unescape, char, unescape_len);
- buffer += unescape_len;
- p = ++pe;
}
+#undef APPEND_CHAR
if (stringEnd > p) {
MEMCPY(buffer, p, char, stringEnd - p);
@@ -743,87 +977,99 @@ static VALUE json_string_unescape(JSON_ParserState *state, const char *string, c
if (symbolize) {
result = rb_str_intern(result);
} else if (intern) {
- result = rb_funcall(rb_str_freeze(result), i_uminus, 0);
+ result = rb_str_to_interned_str(result);
}
return result;
}
#define MAX_FAST_INTEGER_SIZE 18
-static inline VALUE fast_decode_integer(const char *p, const char *pe)
-{
- bool negative = false;
- if (*p == '-') {
- negative = true;
- p++;
- }
+#define MAX_NUMBER_STACK_BUFFER 128
- long long memo = 0;
- while (p < pe) {
- memo *= 10;
- memo += *p - '0';
- p++;
- }
+typedef VALUE (*json_number_decode_func_t)(const char *ptr);
- if (negative) {
- memo = -memo;
+static inline VALUE json_decode_large_number(const char *start, long len, json_number_decode_func_t func)
+{
+ if (RB_LIKELY(len < MAX_NUMBER_STACK_BUFFER)) {
+ char buffer[MAX_NUMBER_STACK_BUFFER];
+ MEMCPY(buffer, start, char, len);
+ buffer[len] = '\0';
+ return func(buffer);
+ } else {
+ VALUE buffer_v = rb_str_tmp_new(len);
+ char *buffer = RSTRING_PTR(buffer_v);
+ MEMCPY(buffer, start, char, len);
+ buffer[len] = '\0';
+ VALUE number = func(buffer);
+ RB_GC_GUARD(buffer_v);
+ return number;
}
- return LL2NUM(memo);
}
-static VALUE json_decode_large_integer(const char *start, long len)
+static VALUE json_decode_inum(const char *buffer)
+{
+ return rb_cstr2inum(buffer, 10);
+}
+
+NOINLINE(static) VALUE json_decode_large_integer(const char *start, long len)
{
- VALUE buffer_v;
- char *buffer = RB_ALLOCV_N(char, buffer_v, len + 1);
- MEMCPY(buffer, start, char, len);
- buffer[len] = '\0';
- VALUE number = rb_cstr2inum(buffer, 10);
- RB_ALLOCV_END(buffer_v);
- return number;
+ return json_decode_large_number(start, len, json_decode_inum);
}
-static inline VALUE
-json_decode_integer(const char *start, const char *end)
+static inline VALUE json_decode_integer(uint64_t mantissa, int mantissa_digits, bool negative, const char *start, const char *end)
{
- long len = end - start;
- if (RB_LIKELY(len < MAX_FAST_INTEGER_SIZE)) {
- return fast_decode_integer(start, end);
+ if (RB_LIKELY(mantissa_digits < MAX_FAST_INTEGER_SIZE)) {
+ if (negative) {
+ return INT64T2NUM(-((int64_t)mantissa));
}
- return json_decode_large_integer(start, len);
+ return UINT64T2NUM(mantissa);
+ }
+
+ return json_decode_large_integer(start, end - start);
}
-static VALUE json_decode_large_float(const char *start, long len)
+static VALUE json_decode_dnum(const char *buffer)
{
- VALUE buffer_v;
- char *buffer = RB_ALLOCV_N(char, buffer_v, len + 1);
- MEMCPY(buffer, start, char, len);
- buffer[len] = '\0';
- VALUE number = DBL2NUM(rb_cstr_to_dbl(buffer, 1));
- RB_ALLOCV_END(buffer_v);
- return number;
+ return DBL2NUM(rb_cstr_to_dbl(buffer, 1));
}
-static VALUE json_decode_float(JSON_ParserConfig *config, const char *start, const char *end)
+NOINLINE(static) VALUE json_decode_large_float(const char *start, long len)
{
- long len = end - start;
+ return json_decode_large_number(start, len, json_decode_dnum);
+}
+/* Ruby JSON optimized float decoder using vendored Ryu algorithm
+ * Accepts pre-extracted mantissa and exponent from first-pass validation
+ */
+static inline VALUE json_decode_float(JSON_ParserConfig *config, uint64_t mantissa, int mantissa_digits, int64_t exponent, bool negative,
+ const char *start, const char *end)
+{
if (RB_UNLIKELY(config->decimal_class)) {
- VALUE text = rb_str_new(start, len);
+ VALUE text = rb_str_new(start, end - start);
return rb_funcallv(config->decimal_class, config->decimal_method_id, 1, &text);
- } else if (RB_LIKELY(len < 64)) {
- char buffer[64];
- MEMCPY(buffer, start, char, len);
- buffer[len] = '\0';
- return DBL2NUM(rb_cstr_to_dbl(buffer, 1));
- } else {
- return json_decode_large_float(start, len);
}
+
+ if (RB_UNLIKELY(exponent > INT32_MAX)) {
+ return negative ? CMinusInfinity : CInfinity;
+ }
+
+ if (RB_UNLIKELY(exponent < INT32_MIN)) {
+ return rb_float_new(negative ? -0.0 : 0.0);
+ }
+
+ // Fall back to rb_cstr_to_dbl for potential subnormals (rare edge case)
+ // Ryu has rounding issues with subnormals around 1e-310 (< 2.225e-308)
+ if (RB_UNLIKELY(mantissa_digits > 17 || mantissa_digits + exponent < -307)) {
+ return json_decode_large_float(start, end - start);
+ }
+
+ return DBL2NUM(ryu_s2d_from_parts(mantissa, mantissa_digits, (int32_t)exponent, negative));
}
static inline VALUE json_decode_array(JSON_ParserState *state, JSON_ParserConfig *config, long count)
{
- VALUE array = rb_ary_new_from_values(count, rvalue_stack_peek(state->stack, count));
- rvalue_stack_pop(state->stack, count);
+ VALUE array = rb_ary_new_from_values(count, rvalue_stack_peek(state->value_stack, count));
+ rvalue_stack_pop(state->value_stack, count);
if (config->freeze) {
RB_OBJ_FREEZE(array);
@@ -849,7 +1095,7 @@ static VALUE json_find_duplicated_key(size_t count, const VALUE *pairs)
return Qfalse;
}
-static void emit_duplicate_key_warning(JSON_ParserState *state, VALUE duplicate_key)
+NOINLINE(static) void emit_duplicate_key_warning(JSON_ParserState *state, VALUE duplicate_key)
{
VALUE message = rb_sprintf(
"detected duplicate key %"PRIsVALUE" in JSON object. This will raise an error in json 3.0 unless enabled via `allow_duplicate_key: true`",
@@ -860,41 +1106,52 @@ static void emit_duplicate_key_warning(JSON_ParserState *state, VALUE duplicate_
RB_GC_GUARD(message);
}
-#ifdef RBIMPL_ATTR_NORETURN
-RBIMPL_ATTR_NORETURN()
-#endif
-static void raise_duplicate_key_error(JSON_ParserState *state, VALUE duplicate_key)
+NORETURN(static) void raise_duplicate_key_error(JSON_ParserState *state, VALUE duplicate_key)
{
VALUE message = rb_sprintf(
"duplicate key %"PRIsVALUE,
rb_inspect(duplicate_key)
);
- raise_parse_error(RSTRING_PTR(message), state);
- RB_GC_GUARD(message);
+ long line, column;
+ cursor_position(state, &line, &column);
+ rb_str_concat(message, build_parse_error_message("", state, line, column)) ;
+ rb_exc_raise(parse_error_new(message, line, column));
+}
+
+NOINLINE(static) void json_on_duplicate_key(JSON_ParserState *state, JSON_ParserConfig *config, size_t count, const VALUE *pairs)
+{
+ switch (config->on_duplicate_key) {
+ case JSON_IGNORE:
+ return;
+
+ case JSON_DEPRECATED:
+ // Only emit the first few deprecations to avoid spamming.
+ if (state->emitted_deprecations < 5) {
+ emit_duplicate_key_warning(state, json_find_duplicated_key(count, pairs));
+ state->emitted_deprecations++;
+ }
+ return;
+
+ case JSON_RAISE:
+ raise_duplicate_key_error(state, json_find_duplicated_key(count, pairs));
+ return;
+ }
+ UNREACHABLE;
}
static inline VALUE json_decode_object(JSON_ParserState *state, JSON_ParserConfig *config, size_t count)
{
size_t entries_count = count / 2;
VALUE object = rb_hash_new_capa(entries_count);
- const VALUE *pairs = rvalue_stack_peek(state->stack, count);
+ const VALUE *pairs = rvalue_stack_peek(state->value_stack, count);
rb_hash_bulk_insert(count, pairs, object);
if (RB_UNLIKELY(RHASH_SIZE(object) < entries_count)) {
- switch (config->on_duplicate_key) {
- case JSON_IGNORE:
- break;
- case JSON_DEPRECATED:
- emit_duplicate_key_warning(state, json_find_duplicated_key(count, pairs));
- break;
- case JSON_RAISE:
- raise_duplicate_key_error(state, json_find_duplicated_key(count, pairs));
- break;
- }
+ json_on_duplicate_key(state, config, count, pairs);
}
- rvalue_stack_pop(state->stack, count);
+ rvalue_stack_pop(state->value_stack, count);
if (config->freeze) {
RB_OBJ_FREEZE(object);
@@ -903,26 +1160,12 @@ static inline VALUE json_decode_object(JSON_ParserState *state, JSON_ParserConfi
return object;
}
-static inline VALUE json_decode_string(JSON_ParserState *state, JSON_ParserConfig *config, const char *start, const char *end, bool escaped, bool is_name)
-{
- VALUE string;
- bool intern = is_name || config->freeze;
- bool symbolize = is_name && config->symbolize_names;
- if (escaped) {
- string = json_string_unescape(state, start, end, is_name, intern, symbolize);
- } else {
- string = json_string_fastpath(state, start, end, is_name, intern, symbolize);
- }
-
- return string;
-}
-
static inline VALUE json_push_value(JSON_ParserState *state, JSON_ParserConfig *config, VALUE value)
{
if (RB_UNLIKELY(config->on_load_proc)) {
value = rb_proc_call_with_block(config->on_load_proc, 1, &value, Qnil);
}
- rvalue_stack_push(state->stack, value, &state->stack_handle, &state->stack);
+ rvalue_stack_push(state->value_stack, value, state->value_stack_handle, &state->value_stack);
return value;
}
@@ -939,17 +1182,11 @@ static const bool string_scan_table[256] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
};
-#if (defined(__GNUC__ ) || defined(__clang__))
-#define FORCE_INLINE __attribute__((always_inline))
-#else
-#define FORCE_INLINE
-#endif
-
#ifdef HAVE_SIMD
static SIMD_Implementation simd_impl = SIMD_NONE;
#endif /* HAVE_SIMD */
-static inline bool FORCE_INLINE string_scan(JSON_ParserState *state)
+ALWAYS_INLINE(static) bool string_scan(JSON_ParserState *state)
{
#ifdef HAVE_SIMD
#if defined(HAVE_SIMD_NEON)
@@ -957,7 +1194,7 @@ static inline bool FORCE_INLINE string_scan(JSON_ParserState *state)
uint64_t mask = 0;
if (string_scan_simd_neon(&state->cursor, state->end, &mask)) {
state->cursor += trailing_zeros64(mask) >> 2;
- return 1;
+ return true;
}
#elif defined(HAVE_SIMD_SSE2)
@@ -965,313 +1202,574 @@ static inline bool FORCE_INLINE string_scan(JSON_ParserState *state)
int mask = 0;
if (string_scan_simd_sse2(&state->cursor, state->end, &mask)) {
state->cursor += trailing_zeros(mask);
- return 1;
+ return true;
}
}
#endif /* HAVE_SIMD_NEON or HAVE_SIMD_SSE2 */
#endif /* HAVE_SIMD */
- while (state->cursor < state->end) {
+ while (!eos(state)) {
if (RB_UNLIKELY(string_scan_table[(unsigned char)*state->cursor])) {
- return 1;
+ return true;
}
- *state->cursor++;
+ state->cursor++;
}
- return 0;
+
+ // If the string ended with an unterminated escape sequence, we might
+ // have gone past the end.
+ if (RB_UNLIKELY(state->cursor > state->end)) {
+ state->cursor = state->end;
+ }
+
+ return false;
}
-static inline VALUE json_parse_string(JSON_ParserState *state, JSON_ParserConfig *config, bool is_name)
+static VALUE json_parse_escaped_string(JSON_ParserState *state, JSON_ParserConfig *config, bool is_name, const char *start)
{
- state->cursor++;
- const char *start = state->cursor;
- bool escaped = false;
+ const char *backslashes[JSON_MAX_UNESCAPE_POSITIONS];
+ JSON_UnescapePositions positions = {
+ .size = 0,
+ .positions = backslashes,
+ .additional_backslashes = 0,
+ };
- while (RB_UNLIKELY(string_scan(state))) {
+ do {
switch (*state->cursor) {
case '"': {
- VALUE string = json_decode_string(state, config, start, state->cursor, escaped, is_name);
+ VALUE string = json_string_unescape(state, config, start, state->cursor, is_name, &positions);
state->cursor++;
- return json_push_value(state, config, string);
+ return string;
}
case '\\': {
- state->cursor++;
- escaped = true;
- if ((unsigned char)*state->cursor < 0x20) {
- raise_parse_error("invalid ASCII control character in string: %s", state);
+ if (RB_LIKELY(positions.size < JSON_MAX_UNESCAPE_POSITIONS)) {
+ backslashes[positions.size] = state->cursor;
+ positions.size++;
+ } else {
+ positions.additional_backslashes++;
}
+ state->cursor++;
break;
}
default:
- raise_parse_error("invalid ASCII control character in string: %s", state);
+ if (!config->allow_control_characters) {
+ raise_parse_error("invalid ASCII control character in string: %s", state);
+ }
break;
}
state->cursor++;
- }
+ } while (string_scan(state));
raise_parse_error("unexpected end of input, expected closing \"", state);
return Qfalse;
}
-static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
+ALWAYS_INLINE(static) VALUE json_parse_string(JSON_ParserState *state, JSON_ParserConfig *config, bool is_name)
{
- json_eat_whitespace(state);
- if (state->cursor >= state->end) {
- raise_parse_error("unexpected end of input", state);
+ state->cursor++;
+ const char *start = state->cursor;
+
+ if (RB_UNLIKELY(!string_scan(state))) {
+ raise_parse_error("unexpected end of input, expected closing \"", state);
}
- switch (*state->cursor) {
- case 'n':
- if ((state->end - state->cursor >= 4) && (memcmp(state->cursor, "null", 4) == 0)) {
- state->cursor += 4;
- return json_push_value(state, config, Qnil);
- }
+ VALUE string;
+ if (RB_LIKELY(*state->cursor == '"')) {
+ string = json_string_fastpath(state, config, start, state->cursor, is_name);
+ state->cursor++;
+ }
+ else {
+ string = json_parse_escaped_string(state, config, is_name, start);
+ }
- raise_parse_error("unexpected token %s", state);
- break;
- case 't':
- if ((state->end - state->cursor >= 4) && (memcmp(state->cursor, "true", 4) == 0)) {
- state->cursor += 4;
- return json_push_value(state, config, Qtrue);
- }
+ return string;
+}
- raise_parse_error("unexpected token %s", state);
- break;
- case 'f':
- // Note: memcmp with a small power of two compile to an integer comparison
- if ((state->end - state->cursor >= 5) && (memcmp(state->cursor + 1, "alse", 4) == 0)) {
- state->cursor += 5;
- return json_push_value(state, config, Qfalse);
- }
+#if JSON_CPU_LITTLE_ENDIAN_64BITS
+// From: https://lemire.me/blog/2022/01/21/swar-explained-parsing-eight-digits/
+// Additional References:
+// https://johnnylee-sde.github.io/Fast-numeric-string-to-int/
+// http://0x80.pl/notesen/2014-10-12-parsing-decimal-numbers-part-1-swar.html
+static inline uint64_t decode_8digits_unrolled(uint64_t val) {
+ const uint64_t mask = 0x000000FF000000FF;
+ const uint64_t mul1 = 0x000F424000000064; // 100 + (1000000ULL << 32)
+ const uint64_t mul2 = 0x0000271000000001; // 1 + (10000ULL << 32)
+ val -= 0x3030303030303030;
+ val = (val * 10) + (val >> 8); // val = (val * 2561) >> 8;
+ val = (((val & mask) * mul1) + (((val >> 16) & mask) * mul2)) >> 32;
+ return val;
+}
- raise_parse_error("unexpected token %s", state);
- break;
- case 'N':
- // Note: memcmp with a small power of two compile to an integer comparison
- if (config->allow_nan && (state->end - state->cursor >= 3) && (memcmp(state->cursor + 1, "aN", 2) == 0)) {
- state->cursor += 3;
- return json_push_value(state, config, CNaN);
- }
+static inline uint64_t decode_4digits_unrolled(uint32_t val) {
+ const uint32_t mask = 0x000000FF;
+ const uint32_t mul1 = 100;
+ val -= 0x30303030;
+ val = (val * 10) + (val >> 8); // val = (val * 2561) >> 8;
+ val = ((val & mask) * mul1) + (((val >> 16) & mask));
+ return val;
+}
+#endif
- raise_parse_error("unexpected token %s", state);
- break;
- case 'I':
- if (config->allow_nan && (state->end - state->cursor >= 8) && (memcmp(state->cursor, "Infinity", 8) == 0)) {
- state->cursor += 8;
- return json_push_value(state, config, CInfinity);
- }
+static inline int json_parse_digits(JSON_ParserState *state, uint64_t *accumulator)
+{
+ const char *start = state->cursor;
- raise_parse_error("unexpected token %s", state);
- break;
- case '-':
- // Note: memcmp with a small power of two compile to an integer comparison
- if ((state->end - state->cursor >= 9) && (memcmp(state->cursor + 1, "Infinity", 8) == 0)) {
- if (config->allow_nan) {
- state->cursor += 9;
- return json_push_value(state, config, CMinusInfinity);
- } else {
- raise_parse_error("unexpected token %s", state);
- }
- }
- // Fallthrough
- case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': {
- bool integer = true;
+#if JSON_CPU_LITTLE_ENDIAN_64BITS
+ while (rest(state) >= sizeof(uint64_t)) {
+ uint64_t next_8bytes;
+ memcpy(&next_8bytes, state->cursor, sizeof(uint64_t));
+
+ // From: https://github.com/simdjson/simdjson/blob/32b301893c13d058095a07d9868edaaa42ee07aa/include/simdjson/generic/numberparsing.h#L333
+ // Branchless version of: http://0x80.pl/articles/swar-digits-validate.html
+ uint64_t match = (next_8bytes & 0xF0F0F0F0F0F0F0F0) | (((next_8bytes + 0x0606060606060606) & 0xF0F0F0F0F0F0F0F0) >> 4);
+
+ if (match == 0x3333333333333333) { // 8 consecutive digits
+ *accumulator = (*accumulator * 100000000) + decode_8digits_unrolled(next_8bytes);
+ state->cursor += 8;
+ continue;
+ }
+
+ uint32_t consecutive_digits = trailing_zeros64(match ^ 0x3333333333333333) / CHAR_BIT;
- // /\A-?(0|[1-9]\d*)(\.\d+)?([Ee][-+]?\d+)?/
- const char *start = state->cursor;
+ if (consecutive_digits >= 4) {
+ *accumulator = (*accumulator * 10000) + decode_4digits_unrolled((uint32_t)next_8bytes);
+ state->cursor += 4;
+ consecutive_digits -= 4;
+ }
+
+ while (consecutive_digits) {
+ *accumulator = *accumulator * 10 + (*state->cursor - '0');
+ consecutive_digits--;
state->cursor++;
+ }
- while ((state->cursor < state->end) && (*state->cursor >= '0') && (*state->cursor <= '9')) {
- state->cursor++;
- }
+ return (int)(state->cursor - start);
+ }
+#endif
+
+ char next_char;
+ while (rb_isdigit(next_char = peek(state))) {
+ *accumulator = *accumulator * 10 + (next_char - '0');
+ state->cursor++;
+ }
+ return (int)(state->cursor - start);
+}
- long integer_length = state->cursor - start;
+static inline VALUE json_parse_number(JSON_ParserState *state, JSON_ParserConfig *config, bool negative, const char *start)
+{
+ bool integer = true;
+ const char first_digit = *state->cursor;
- if (RB_UNLIKELY(start[0] == '0' && integer_length > 1)) {
- raise_parse_error_at("invalid number: %s", state, start);
- } else if (RB_UNLIKELY(integer_length > 2 && start[0] == '-' && start[1] == '0')) {
- raise_parse_error_at("invalid number: %s", state, start);
- } else if (RB_UNLIKELY(integer_length == 1 && start[0] == '-')) {
- raise_parse_error_at("invalid number: %s", state, start);
- }
+ // Variables for Ryu optimization - extract digits during parsing
+ int64_t exponent = 0;
+ int decimal_point_pos = -1;
+ uint64_t mantissa = 0;
- if ((state->cursor < state->end) && (*state->cursor == '.')) {
- integer = false;
- state->cursor++;
+ // Parse integer part and extract mantissa digits
+ int mantissa_digits = json_parse_digits(state, &mantissa);
+
+ if (RB_UNLIKELY((first_digit == '0' && mantissa_digits > 1) || (negative && mantissa_digits == 0))) {
+ raise_parse_error_at("invalid number: %s", state, start);
+ }
+
+ // Parse fractional part
+ if (peek(state) == '.') {
+ integer = false;
+ decimal_point_pos = mantissa_digits; // Remember position of decimal point
+ state->cursor++;
+
+ int fractional_digits = json_parse_digits(state, &mantissa);
+ mantissa_digits += fractional_digits;
+
+ if (RB_UNLIKELY(!fractional_digits)) {
+ raise_parse_error_at("invalid number: %s", state, start);
+ }
+ }
+
+ // Parse exponent
+ if (rb_tolower(peek(state)) == 'e') {
+ integer = false;
+ state->cursor++;
+
+ bool negative_exponent = false;
+ const char next_char = peek(state);
+ if (next_char == '-' || next_char == '+') {
+ negative_exponent = next_char == '-';
+ state->cursor++;
+ }
+
+ uint64_t abs_exponent = 0;
+ int exponent_digits = json_parse_digits(state, &abs_exponent);
+
+ if (RB_UNLIKELY(!exponent_digits)) {
+ raise_parse_error_at("invalid number: %s", state, start);
+ }
+
+ if (RB_UNLIKELY(exponent_digits >= 20 || abs_exponent > (uint64_t)INT64_MAX)) {
+ exponent = negative_exponent ? INT64_MIN : INT64_MAX;
+ } else {
+ exponent = negative_exponent ? -(int64_t)abs_exponent : (int64_t)abs_exponent;
+ }
+ }
+
+ if (integer) {
+ return json_decode_integer(mantissa, mantissa_digits, negative, start, state->cursor);
+ }
+
+ // Adjust exponent based on decimal point position
+ if (decimal_point_pos >= 0) {
+ exponent -= (mantissa_digits - decimal_point_pos);
+ }
+
+ return json_decode_float(config, mantissa, mantissa_digits, exponent, negative, start, state->cursor);
+}
+
+static inline VALUE json_parse_positive_number(JSON_ParserState *state, JSON_ParserConfig *config)
+{
+ return json_parse_number(state, config, false, state->cursor);
+}
+
+static inline VALUE json_parse_negative_number(JSON_ParserState *state, JSON_ParserConfig *config)
+{
+ return json_parse_number(state, config, true, state->cursor - 1);
+}
- if (state->cursor == state->end || *state->cursor < '0' || *state->cursor > '9') {
- raise_parse_error("invalid number: %s", state);
+// How many values (array elements, or interleaved object keys+values) have been
+// pushed onto the rvalue stack since this container opened. Used to size the
+// bulk decode on close, and to tell the first key/colon from later ones.
+static inline long json_frame_entry_count(const json_frame *frame, const rvalue_stack *value_stack)
+{
+ return value_stack->head - frame->value_stack_head;
+}
+
+// A complete value now sits on top of the rvalue stack. Advance the frame that
+// was waiting for it: the root document is done, or the enclosing container
+// moves on to expecting a ',' or its closing bracket. The caller passes the
+// frame it already has in hand -- the one that was expecting the value -- which
+// after a container close is the freshly re-exposed parent.
+static inline void json_value_completed(json_frame *frame)
+{
+ JSON_ASSERT((int)JSON_PHASE_DONE == (int)JSON_FRAME_ROOT);
+ JSON_ASSERT((int)JSON_PHASE_ARRAY_COMMA == (int)JSON_FRAME_ARRAY);
+ JSON_ASSERT((int)JSON_PHASE_OBJECT_COMMA == (int)JSON_FRAME_OBJECT);
+
+ frame->phase = (enum json_frame_phase) frame->type;
+}
+
+ALWAYS_INLINE(static) bool json_match_keyword(JSON_ParserState *state, const char *keyword, size_t offset)
+{
+ // It is assumed that since `keyword` is always a literal, the compiler is able to constantize this
+ // `strlen` and several other computations in that routine, such as eliminating the `if (resumable)` branch.
+
+ size_t len = strlen(keyword);
+
+ // Note: memcmp with a small power of two and a literal string compile to an integer comparison /
+ // That's why we sometime compare starting from the first byte and sometimes from the second.
+ if (rest(state) >= len && (memcmp(state->cursor + offset, keyword + offset, len - offset) == 0)) {
+ state->cursor += len;
+ return true;
+ }
+ return false;
+}
+
+// Parse an arbitrary JSON value iteratively. This is a state machine driven
+// entirely by the top frame's phase so it can stop at any value boundary and
+// resume purely from the frame stack. A JSON_FRAME_ROOT frame sits at the
+// bottom of the stack, so the stack is never empty mid-parse and the document
+// itself is just another frame whose value, once parsed, leaves its phase DONE.
+static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
+{
+ json_frame *frame = json_frame_stack_peek(state->frames);
+
+ switch (frame->phase) {
+ case JSON_PHASE_DONE: goto JSON_PHASE_DONE;
+ case JSON_PHASE_ARRAY_COMMA: goto JSON_PHASE_ARRAY_COMMA;
+ case JSON_PHASE_OBJECT_COMMA: goto JSON_PHASE_OBJECT_COMMA;
+ case JSON_PHASE_VALUE: goto JSON_PHASE_VALUE;
+ case JSON_PHASE_OBJECT_KEY: goto JSON_PHASE_OBJECT_KEY;
+ case JSON_PHASE_OBJECT_COLON: goto JSON_PHASE_OBJECT_COLON;
+ }
+ UNREACHABLE_RETURN(Qundef);
+
+ JSON_PHASE_DONE: {
+ // The root document value is parsed; it is the lone survivor on
+ // the rvalue stack.
+ return *rvalue_stack_peek(state->value_stack, 1);
+ }
+
+ JSON_PHASE_VALUE: {
+ json_eat_whitespace(state);
+
+ VALUE value;
+ switch (peek(state)) {
+ case 'n':
+ if (json_match_keyword(state, "null", 0)) {
+ value = Qnil;
+ break;
}
+ raise_parse_error("unexpected token %s", state);
- while ((state->cursor < state->end) && (*state->cursor >= '0') && (*state->cursor <= '9')) {
- state->cursor++;
+ case 't':
+ if (json_match_keyword(state, "true", 0)) {
+ value = Qtrue;
+ break;
}
- }
+ raise_parse_error("unexpected token %s", state);
- if ((state->cursor < state->end) && ((*state->cursor == 'e') || (*state->cursor == 'E'))) {
- integer = false;
- state->cursor++;
- if ((state->cursor < state->end) && ((*state->cursor == '+') || (*state->cursor == '-'))) {
- state->cursor++;
+ case 'f':
+ if (json_match_keyword(state, "false", 1)) {
+ value = Qfalse;
+ break;
}
+ raise_parse_error("unexpected token %s", state);
- if (state->cursor == state->end || *state->cursor < '0' || *state->cursor > '9') {
- raise_parse_error("invalid number: %s", state);
+ case 'N':
+ // Note: memcmp with a small power of two compile to an integer comparison
+ if (config->allow_nan && json_match_keyword(state, "NaN", 1)) {
+ value = CNaN;
+ break;
}
+ raise_parse_error("unexpected token %s", state);
- while ((state->cursor < state->end) && (*state->cursor >= '0') && (*state->cursor <= '9')) {
- state->cursor++;
+ case 'I':
+ if (config->allow_nan && json_match_keyword(state, "Infinity", 0)) {
+ value = CInfinity;
+ break;
}
- }
+ raise_parse_error("unexpected token %s", state);
- if (integer) {
- return json_push_value(state, config, json_decode_integer(start, state->cursor));
+ case '-': {
+ state->cursor++;
+ if (config->allow_nan && json_match_keyword(state, "Infinity", 0)) {
+ value = CMinusInfinity;
+ } else {
+ value = json_parse_negative_number(state, config);
+ }
+ break;
}
- return json_push_value(state, config, json_decode_float(config, start, state->cursor));
- }
- case '"': {
- // %r{\A"[^"\\\t\n\x00]*(?:\\[bfnrtu\\/"][^"\\]*)*"}
- return json_parse_string(state, config, false);
- break;
- }
- case '[': {
- state->cursor++;
- json_eat_whitespace(state);
- long stack_head = state->stack->head;
- if ((state->cursor < state->end) && (*state->cursor == ']')) {
+ case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9':
+ value = json_parse_positive_number(state, config);
+ break;
+
+ case '"':
+ // %r{\A"[^"\\\t\n\x00]*(?:\\[bfnrtu\\/"][^"\\]*)*"}
+ value = json_parse_string(state, config, false);
+ break;
+
+ case '[': {
state->cursor++;
- return json_push_value(state, config, json_decode_array(state, config, 0));
- } else {
+ json_eat_whitespace(state);
+
+ if (peek(state) == ']') {
+ state->cursor++;
+ value = json_decode_array(state, config, 0);
+ break;
+ }
+
state->current_nesting++;
if (RB_UNLIKELY(config->max_nesting && (config->max_nesting < state->current_nesting))) {
rb_raise(eNestingError, "nesting of %d is too deep", state->current_nesting);
}
state->in_array++;
- json_parse_any(state, config);
+
+ // Phase stays VALUE: the next iteration reads the first element.
+ frame = json_frame_stack_push(state, (json_frame){
+ .type = JSON_FRAME_ARRAY,
+ .phase = JSON_PHASE_VALUE,
+ .value_stack_head = state->value_stack->head,
+ });
+ goto JSON_PHASE_VALUE;
}
+ case '{': {
+ const char *object_start_cursor = state->cursor;
- while (true) {
+ state->cursor++;
json_eat_whitespace(state);
- if (state->cursor < state->end) {
- if (*state->cursor == ']') {
- state->cursor++;
- long count = state->stack->head - stack_head;
- state->current_nesting--;
- state->in_array--;
- return json_push_value(state, config, json_decode_array(state, config, count));
- }
+ if (peek(state) == '}') {
+ state->cursor++;
+ value = json_decode_object(state, config, 0);
+ break;
+ }
- if (*state->cursor == ',') {
- state->cursor++;
- if (config->allow_trailing_comma) {
- json_eat_whitespace(state);
- if ((state->cursor < state->end) && (*state->cursor == ']')) {
- continue;
- }
- }
- json_parse_any(state, config);
- continue;
- }
+ state->current_nesting++;
+ if (RB_UNLIKELY(config->max_nesting && (config->max_nesting < state->current_nesting))) {
+ rb_raise(eNestingError, "nesting of %d is too deep", state->current_nesting);
}
- raise_parse_error("expected ',' or ']' after array value", state);
+ // Phase KEY: the next iteration reads the first key.
+ frame = json_frame_stack_push(state, (json_frame){
+ .type = JSON_FRAME_OBJECT,
+ .phase = JSON_PHASE_OBJECT_KEY,
+ .value_stack_head = state->value_stack->head,
+ .start_cursor = object_start_cursor,
+ });
+ goto JSON_PHASE_OBJECT_KEY;
}
- break;
+
+ case 0:
+ raise_parse_error("unexpected end of input", state);
+
+ default:
+ raise_parse_error("unexpected character: %s", state);
}
- case '{': {
- const char *object_start_cursor = state->cursor;
- state->cursor++;
- json_eat_whitespace(state);
- long stack_head = state->stack->head;
+ json_push_value(state, config, value);
+ json_value_completed(frame);
- if ((state->cursor < state->end) && (*state->cursor == '}')) {
- state->cursor++;
- return json_push_value(state, config, json_decode_object(state, config, 0));
- } else {
- state->current_nesting++;
- if (RB_UNLIKELY(config->max_nesting && (config->max_nesting < state->current_nesting))) {
- rb_raise(eNestingError, "nesting of %d is too deep", state->current_nesting);
- }
+ switch (frame->phase) {
+ case JSON_PHASE_DONE: goto JSON_PHASE_DONE;
+ case JSON_PHASE_ARRAY_COMMA: goto JSON_PHASE_ARRAY_COMMA;
+ case JSON_PHASE_OBJECT_COMMA: goto JSON_PHASE_OBJECT_COMMA;
+ case JSON_PHASE_VALUE: goto JSON_PHASE_VALUE;
+ case JSON_PHASE_OBJECT_KEY: UNREACHABLE_RETURN(Qundef);
+ case JSON_PHASE_OBJECT_COLON: goto JSON_PHASE_OBJECT_COLON;
+ }
+ UNREACHABLE_RETURN(Qundef);
+ }
- if (*state->cursor != '"') {
- raise_parse_error("expected object key, got %s", state);
- }
- json_parse_string(state, config, true);
+ JSON_PHASE_OBJECT_KEY: {
+ JSON_ASSERT(frame->type == JSON_FRAME_OBJECT);
- json_eat_whitespace(state);
- if ((state->cursor >= state->end) || (*state->cursor != ':')) {
- raise_parse_error("expected ':' after object key", state);
- }
- state->cursor++;
+ json_eat_whitespace(state);
- json_parse_any(state, config);
+ if (RB_LIKELY(peek(state) == '"')) {
+ json_push_value(state, config, json_parse_string(state, config, true));
+ frame->phase = JSON_PHASE_OBJECT_COLON;
+ goto JSON_PHASE_OBJECT_COLON;
+ } else {
+ // The message differs for the first key vs. a key after a
+ // ',': the first is the only one reached with nothing pushed
+ // for this object yet.
+ if (json_frame_entry_count(frame, state->value_stack) == 0) {
+ raise_parse_error("expected object key, got %s", state);
+ } else {
+ raise_parse_error("expected object key, got: %s", state);
}
+ }
+ UNREACHABLE_RETURN(Qundef);
+ }
- while (true) {
- json_eat_whitespace(state);
+ JSON_PHASE_OBJECT_COLON: {
+ JSON_ASSERT(frame->type == JSON_FRAME_OBJECT);
- if (state->cursor < state->end) {
- if (*state->cursor == '}') {
- state->cursor++;
- state->current_nesting--;
- size_t count = state->stack->head - stack_head;
+ json_eat_whitespace(state);
- // Temporary rewind cursor in case an error is raised
- const char *final_cursor = state->cursor;
- state->cursor = object_start_cursor;
- VALUE object = json_decode_object(state, config, count);
- state->cursor = final_cursor;
+ if (RB_LIKELY(peek(state) == ':')) {
+ state->cursor++;
+ frame->phase = JSON_PHASE_VALUE;
+ goto JSON_PHASE_VALUE;
+ } else {
+ // First colon (only the first pair's key is pushed, nothing
+ // else) vs. a later one.
+ if (json_frame_entry_count(frame, state->value_stack) == 1) {
+ raise_parse_error("expected ':' after object key", state);
+ } else {
+ raise_parse_error("expected ':' after object key, got: %s", state);
+ }
+ }
+ UNREACHABLE_RETURN(Qundef);
+ }
- return json_push_value(state, config, object);
- }
+ JSON_PHASE_ARRAY_COMMA: {
+ JSON_ASSERT(frame->type == JSON_FRAME_ARRAY);
- if (*state->cursor == ',') {
- state->cursor++;
- json_eat_whitespace(state);
+ json_eat_whitespace(state);
- if (config->allow_trailing_comma) {
- if ((state->cursor < state->end) && (*state->cursor == '}')) {
- continue;
- }
- }
+ const char next_char = peek(state);
- if (*state->cursor != '"') {
- raise_parse_error("expected object key, got: %s", state);
- }
- json_parse_string(state, config, true);
+ if (RB_LIKELY(next_char == ',')) {
+ state->cursor++;
+ if (config->allow_trailing_comma) {
+ json_eat_whitespace(state);
+ if (peek(state) == ']') {
+ // Trailing comma: stay in COMMA to close on the next iteration.
+ goto JSON_PHASE_ARRAY_COMMA;
+ }
+ }
+ frame->phase = JSON_PHASE_VALUE;
+ goto JSON_PHASE_VALUE;
+ } else if (next_char == ']') {
+ state->cursor++;
+ long count = json_frame_entry_count(frame, state->value_stack);
+ state->current_nesting--;
+ state->in_array--;
+ json_frame_stack_pop(state->frames);
+ json_push_value(state, config, json_decode_array(state, config, count));
+ frame = json_frame_stack_peek(state->frames);
+ json_value_completed(frame);
+
+ switch (frame->phase) {
+ case JSON_PHASE_DONE: goto JSON_PHASE_DONE;
+ case JSON_PHASE_ARRAY_COMMA: goto JSON_PHASE_ARRAY_COMMA;
+ case JSON_PHASE_OBJECT_COMMA: goto JSON_PHASE_OBJECT_COMMA;
+ case JSON_PHASE_VALUE: goto JSON_PHASE_VALUE;
+ case JSON_PHASE_OBJECT_KEY: UNREACHABLE_RETURN(Qundef);
+ case JSON_PHASE_OBJECT_COLON: goto JSON_PHASE_OBJECT_COLON;
+ }
+ } else {
+ raise_parse_error("expected ',' or ']' after array value", state);
+ }
+ UNREACHABLE_RETURN(Qundef);
+ }
- json_eat_whitespace(state);
- if ((state->cursor >= state->end) || (*state->cursor != ':')) {
- raise_parse_error("expected ':' after object key, got: %s", state);
- }
- state->cursor++;
+ JSON_PHASE_OBJECT_COMMA: {
+ JSON_ASSERT(frame->type == JSON_FRAME_OBJECT);
- json_parse_any(state, config);
+ json_eat_whitespace(state);
+ const char next_char = peek(state);
- continue;
- }
+ if (RB_LIKELY(next_char == ',')) {
+ state->cursor++;
+
+ if (config->allow_trailing_comma) {
+ json_eat_whitespace(state);
+ if (peek(state) == '}') {
+ // Trailing comma: stay in COMMA to close on the next iteration.
+ goto JSON_PHASE_OBJECT_COMMA;
}
+ }
- raise_parse_error("expected ',' or '}' after object value, got: %s", state);
+ frame->phase = JSON_PHASE_OBJECT_KEY;
+ goto JSON_PHASE_OBJECT_KEY;
+ } else if (next_char == '}') {
+ state->cursor++;
+ state->current_nesting--;
+ size_t count = json_frame_entry_count(frame, state->value_stack);
+
+ // Temporary rewind cursor in case an error is raised
+ const char *final_cursor = state->cursor;
+ state->cursor = frame->start_cursor;
+ VALUE object = json_decode_object(state, config, count);
+ state->cursor = final_cursor;
+
+ json_push_value(state, config, object);
+ json_frame_stack_pop(state->frames);
+ frame = json_frame_stack_peek(state->frames);
+ json_value_completed(frame);
+
+ switch (frame->phase) {
+ case JSON_PHASE_DONE: goto JSON_PHASE_DONE;
+ case JSON_PHASE_ARRAY_COMMA: goto JSON_PHASE_ARRAY_COMMA;
+ case JSON_PHASE_OBJECT_COMMA: goto JSON_PHASE_OBJECT_COMMA;
+ case JSON_PHASE_VALUE: goto JSON_PHASE_VALUE;
+ case JSON_PHASE_OBJECT_KEY: UNREACHABLE_RETURN(Qundef);
+ case JSON_PHASE_OBJECT_COLON: goto JSON_PHASE_OBJECT_COLON;
}
- break;
+ } else {
+ raise_parse_error("expected ',' or '}' after object value, got: %s", state);
}
-
- default:
- raise_parse_error("unexpected character: %s", state);
- break;
+ UNREACHABLE_RETURN(Qundef);
}
- raise_parse_error("unreachable: %s", state);
+ UNREACHABLE_RETURN(Qundef);
}
static void json_ensure_eof(JSON_ParserState *state)
{
json_eat_whitespace(state);
- if (state->cursor != state->end) {
+ if (!eos(state)) {
raise_parse_error("unexpected token at end of stream %s", state);
}
}
@@ -1290,38 +1788,56 @@ static void json_ensure_eof(JSON_ParserState *state)
static VALUE convert_encoding(VALUE source)
{
- int encindex = RB_ENCODING_GET(source);
+ StringValue(source);
+ int encindex = RB_ENCODING_GET(source);
- if (RB_LIKELY(encindex == utf8_encindex)) {
+ if (RB_LIKELY(encindex == utf8_encindex)) {
+ return source;
+ }
+
+ if (encindex == binary_encindex) {
+ // For historical reason, we silently reinterpret binary strings as UTF-8
+ return rb_enc_associate_index(rb_str_dup(source), utf8_encindex);
+ }
+
+ source = rb_funcall(source, i_encode, 1, Encoding_UTF_8);
+ StringValue(source);
return source;
- }
+}
- if (encindex == binary_encindex) {
- // For historical reason, we silently reinterpret binary strings as UTF-8
- return rb_enc_associate_index(rb_str_dup(source), utf8_encindex);
- }
+struct parser_config_init_args {
+ JSON_ParserConfig *config;
+ VALUE self;
+};
- return rb_funcall(source, i_encode, 1, Encoding_UTF_8);
+static void parser_config_wb_write(VALUE self, VALUE *dest, VALUE val)
+{
+ *dest = val;
+ if (self) RB_OBJ_WRITTEN(self, Qundef, val);
}
static int parser_config_init_i(VALUE key, VALUE val, VALUE data)
{
- JSON_ParserConfig *config = (JSON_ParserConfig *)data;
-
- if (key == sym_max_nesting) { config->max_nesting = RTEST(val) ? FIX2INT(val) : 0; }
- else if (key == sym_allow_nan) { config->allow_nan = RTEST(val); }
- else if (key == sym_allow_trailing_comma) { config->allow_trailing_comma = RTEST(val); }
- else if (key == sym_symbolize_names) { config->symbolize_names = RTEST(val); }
- else if (key == sym_freeze) { config->freeze = RTEST(val); }
- else if (key == sym_on_load) { config->on_load_proc = RTEST(val) ? val : Qfalse; }
- else if (key == sym_allow_duplicate_key) { config->on_duplicate_key = RTEST(val) ? JSON_IGNORE : JSON_RAISE; }
- else if (key == sym_decimal_class) {
+ struct parser_config_init_args *args = (struct parser_config_init_args *)data;
+ JSON_ParserConfig *config = args->config;
+ VALUE self = args->self;
+
+ if (key == sym_max_nesting) { config->max_nesting = RTEST(val) ? FIX2INT(val) : 0; }
+ else if (key == sym_allow_nan) { config->allow_nan = RTEST(val); }
+ else if (key == sym_allow_trailing_comma) { config->allow_trailing_comma = RTEST(val); }
+ else if (key == sym_allow_control_characters) { config->allow_control_characters = RTEST(val); }
+ else if (key == sym_allow_invalid_escape) { config->allow_invalid_escape = RTEST(val); }
+ else if (key == sym_symbolize_names) { config->symbolize_names = RTEST(val); }
+ else if (key == sym_freeze) { config->freeze = RTEST(val); }
+ else if (key == sym_on_load) { parser_config_wb_write(self, &config->on_load_proc, RTEST(val) ? val : Qfalse); }
+ else if (key == sym_allow_duplicate_key) { config->on_duplicate_key = RTEST(val) ? JSON_IGNORE : JSON_RAISE; }
+ else if (key == sym_decimal_class) {
if (RTEST(val)) {
if (rb_respond_to(val, i_try_convert)) {
- config->decimal_class = val;
+ parser_config_wb_write(self, &config->decimal_class, val);
config->decimal_method_id = i_try_convert;
} else if (rb_respond_to(val, i_new)) {
- config->decimal_class = val;
+ parser_config_wb_write(self, &config->decimal_class, val);
config->decimal_method_id = i_new;
} else if (RB_TYPE_P(val, T_CLASS)) {
VALUE name = rb_class_name(val);
@@ -1330,7 +1846,7 @@ static int parser_config_init_i(VALUE key, VALUE val, VALUE data)
if (last_colon) {
const char *mod_path_end = last_colon - 1;
VALUE mod_path = rb_str_substr(name, 0, mod_path_end - name_cstr);
- config->decimal_class = rb_path_to_class(mod_path);
+ parser_config_wb_write(self, &config->decimal_class, rb_path_to_class(mod_path));
const char *method_name_beg = last_colon + 1;
long before_len = method_name_beg - name_cstr;
@@ -1338,7 +1854,7 @@ static int parser_config_init_i(VALUE key, VALUE val, VALUE data)
VALUE method_name = rb_str_substr(name, before_len, len);
config->decimal_method_id = SYM2ID(rb_str_intern(method_name));
} else {
- config->decimal_class = rb_mKernel;
+ parser_config_wb_write(self, &config->decimal_class, rb_mKernel);
config->decimal_method_id = SYM2ID(rb_str_intern(name));
}
}
@@ -1348,16 +1864,21 @@ static int parser_config_init_i(VALUE key, VALUE val, VALUE data)
return ST_CONTINUE;
}
-static void parser_config_init(JSON_ParserConfig *config, VALUE opts)
+static void parser_config_init(JSON_ParserConfig *config, VALUE opts, VALUE self)
{
config->max_nesting = 100;
+ struct parser_config_init_args args = {
+ .config = config,
+ .self = self,
+ };
+
if (!NIL_P(opts)) {
Check_Type(opts, T_HASH);
if (RHASH_SIZE(opts) > 0) {
// We assume in most cases few keys are set so it's faster to go over
// the provided keys than to check all possible keys.
- rb_hash_foreach(opts, parser_config_init_i, (VALUE)config);
+ rb_hash_foreach(opts, parser_config_init_i, (VALUE)&args);
}
}
@@ -1388,36 +1909,62 @@ static void parser_config_init(JSON_ParserConfig *config, VALUE opts)
*/
static VALUE cParserConfig_initialize(VALUE self, VALUE opts)
{
+ rb_check_frozen(self);
GET_PARSER_CONFIG;
- parser_config_init(config, opts);
-
- RB_OBJ_WRITTEN(self, Qundef, config->decimal_class);
+ parser_config_init(config, opts, self);
return self;
}
-static VALUE cParser_parse(JSON_ParserConfig *config, VALUE Vsource)
+static VALUE cParser_parse(JSON_ParserConfig *config, VALUE src)
{
- Vsource = convert_encoding(StringValue(Vsource));
- StringValue(Vsource);
+ VALUE Vsource = convert_encoding(src);
+
+ // Ensure the string isn't mutated under us.
+ // The classic API to use is `rb_str_locktmp`, but then we'd
+ // need to use `rb_protect` to make sure we always unlock.
+ if (Vsource == src) {
+ Vsource = rb_str_new_frozen(Vsource);
+ }
VALUE rvalue_stack_buffer[RVALUE_STACK_INITIAL_CAPA];
- rvalue_stack stack = {
+ rvalue_stack value_stack = {
.type = RVALUE_STACK_STACK_ALLOCATED,
.ptr = rvalue_stack_buffer,
.capa = RVALUE_STACK_INITIAL_CAPA,
};
+ // Seed the frame stack with the root frame, establishing the invariant that
+ // json_parse_any always has a top frame to dispatch on (so the stack is never
+ // empty mid-parse).
+ json_frame frame_stack_buffer[JSON_FRAME_STACK_INITIAL_CAPA];
+ frame_stack_buffer[0] = (json_frame){
+ .type = JSON_FRAME_ROOT,
+ .phase = JSON_PHASE_VALUE,
+ };
+ json_frame_stack frames = {
+ .type = RVALUE_STACK_STACK_ALLOCATED,
+ .ptr = frame_stack_buffer,
+ .capa = JSON_FRAME_STACK_INITIAL_CAPA,
+ .head = 1,
+ };
+
long len;
const char *start;
+
RSTRING_GETMEM(Vsource, start, len);
+ VALUE value_stack_handle = 0;
+ VALUE frame_stack_handle = 0;
JSON_ParserState _state = {
.start = start,
.cursor = start,
.end = start + len,
- .stack = &stack,
+ .value_stack = &value_stack,
+ .value_stack_handle = &value_stack_handle,
+ .frames = &frames,
+ .frame_stack_handle = &frame_stack_handle,
};
JSON_ParserState *state = &_state;
@@ -1425,8 +1972,11 @@ static VALUE cParser_parse(JSON_ParserConfig *config, VALUE Vsource)
// This may be skipped in case of exception, but
// it won't cause a leak.
- rvalue_stack_eagerly_release(state->stack_handle);
-
+ rvalue_stack_eagerly_release(value_stack_handle);
+ json_frame_stack_eagerly_release(frame_stack_handle);
+ RB_GC_GUARD(value_stack_handle);
+ RB_GC_GUARD(frame_stack_handle);
+ RB_GC_GUARD(Vsource);
json_ensure_eof(state);
return result;
@@ -1447,12 +1997,9 @@ static VALUE cParserConfig_parse(VALUE self, VALUE Vsource)
static VALUE cParser_m_parse(VALUE klass, VALUE Vsource, VALUE opts)
{
- Vsource = convert_encoding(StringValue(Vsource));
- StringValue(Vsource);
-
JSON_ParserConfig _config = {0};
JSON_ParserConfig *config = &_config;
- parser_config_init(config, opts);
+ parser_config_init(config, opts, false);
return cParser_parse(config, Vsource);
}
@@ -1460,30 +2007,35 @@ static VALUE cParser_m_parse(VALUE klass, VALUE Vsource, VALUE opts)
static void JSON_ParserConfig_mark(void *ptr)
{
JSON_ParserConfig *config = ptr;
- rb_gc_mark(config->on_load_proc);
- rb_gc_mark(config->decimal_class);
+ rb_gc_mark_movable(config->on_load_proc);
+ rb_gc_mark_movable(config->decimal_class);
}
-static void JSON_ParserConfig_free(void *ptr)
+static size_t JSON_ParserConfig_memsize(const void *ptr)
{
- JSON_ParserConfig *config = ptr;
- ruby_xfree(config);
+#ifdef HAVE_RUBY_TYPED_EMBEDDABLE
+ return 0;
+#else
+ return sizeof(JSON_ParserConfig);
+#endif
}
-static size_t JSON_ParserConfig_memsize(const void *ptr)
+static void JSON_ParserConfig_compact(void *ptr)
{
- return sizeof(JSON_ParserConfig);
+ JSON_ParserConfig *config = ptr;
+ config->on_load_proc = rb_gc_location(config->on_load_proc);
+ config->decimal_class = rb_gc_location(config->decimal_class);
}
static const rb_data_type_t JSON_ParserConfig_type = {
- "JSON::Ext::Parser/ParserConfig",
- {
- JSON_ParserConfig_mark,
- JSON_ParserConfig_free,
- JSON_ParserConfig_memsize,
+ .wrap_struct_name = "JSON::Ext::Parser/ParserConfig",
+ .function = {
+ .dmark = JSON_ParserConfig_mark,
+ .dfree = RUBY_DEFAULT_FREE,
+ .dsize = JSON_ParserConfig_memsize,
+ .dcompact = JSON_ParserConfig_compact,
},
- 0, 0,
- RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
+ .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FROZEN_SHAREABLE | RUBY_TYPED_EMBEDDABLE,
};
static VALUE cJSON_parser_s_allocate(VALUE klass)
@@ -1527,16 +2079,14 @@ void Init_parser(void)
sym_max_nesting = ID2SYM(rb_intern("max_nesting"));
sym_allow_nan = ID2SYM(rb_intern("allow_nan"));
sym_allow_trailing_comma = ID2SYM(rb_intern("allow_trailing_comma"));
+ sym_allow_control_characters = ID2SYM(rb_intern("allow_control_characters"));
+ sym_allow_invalid_escape = ID2SYM(rb_intern("allow_invalid_escape"));
sym_symbolize_names = ID2SYM(rb_intern("symbolize_names"));
sym_freeze = ID2SYM(rb_intern("freeze"));
sym_on_load = ID2SYM(rb_intern("on_load"));
sym_decimal_class = ID2SYM(rb_intern("decimal_class"));
sym_allow_duplicate_key = ID2SYM(rb_intern("allow_duplicate_key"));
- i_chr = rb_intern("chr");
- 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_uminus = rb_intern("-@");
diff --git a/ext/json/simd/simd.h b/ext/json/simd/simd.h
index 3abbdb0209..611b41b066 100644
--- a/ext/json/simd/simd.h
+++ b/ext/json/simd/simd.h
@@ -1,10 +1,14 @@
+#include "../json.h"
+
typedef enum {
SIMD_NONE,
SIMD_NEON,
SIMD_SSE2
} SIMD_Implementation;
-#ifdef JSON_ENABLE_SIMD
+#ifndef __has_builtin // Optional of course.
+ #define __has_builtin(x) 0 // Compatibility with non-clang compilers.
+#endif
#ifdef __clang__
# if __has_builtin(__builtin_ctzll)
@@ -20,6 +24,8 @@ typedef enum {
static inline uint32_t trailing_zeros64(uint64_t input)
{
+ JSON_ASSERT(input > 0); // __builtin_ctz(0) is undefined behavior
+
#if HAVE_BUILTIN_CTZLL
return __builtin_ctzll(input);
#else
@@ -35,6 +41,8 @@ static inline uint32_t trailing_zeros64(uint64_t input)
static inline int trailing_zeros(int input)
{
+ JSON_ASSERT(input > 0); // __builtin_ctz(0) is undefined behavior
+
#if HAVE_BUILTIN_CTZLL
return __builtin_ctz(input);
#else
@@ -48,14 +56,36 @@ static inline int trailing_zeros(int input)
#endif
}
-#if (defined(__GNUC__ ) || defined(__clang__))
-#define FORCE_INLINE __attribute__((always_inline))
-#else
-#define FORCE_INLINE
-#endif
+#ifdef JSON_ENABLE_SIMD
+#define SIMD_MINIMUM_THRESHOLD 4
-#define SIMD_MINIMUM_THRESHOLD 6
+ALWAYS_INLINE(static) void json_fast_memcpy16(char *dst, const char *src, size_t len)
+{
+ RBIMPL_ASSERT_OR_ASSUME(len < 16);
+ RBIMPL_ASSERT_OR_ASSUME(len >= SIMD_MINIMUM_THRESHOLD); // 4
+#if defined(__has_builtin) && __has_builtin(__builtin_memcpy)
+ // If __builtin_memcpy is available, use it to copy between SIMD_MINIMUM_THRESHOLD (4) and vec_len-1 (15) bytes.
+ // These copies overlap. The first copy will copy the first 8 (or 4) bytes. The second copy will copy
+ // the last 8 (or 4) bytes but overlap with the first copy. The overlapping bytes will be in the correct
+ // position in both copies.
+
+ // Please do not attempt to replace __builtin_memcpy with memcpy without profiling and/or looking at the
+ // generated assembly. On clang-specifically (tested on Apple clang version 17.0.0 (clang-1700.0.13.3)),
+ // when using memcpy, the compiler will notice the only difference is a 4 or 8 and generate a conditional
+ // select instruction instead of direct loads and stores with a branch. This ends up slower than the branch
+ // plus two loads and stores generated when using __builtin_memcpy.
+ if (len >= 8) {
+ __builtin_memcpy(dst, src, 8);
+ __builtin_memcpy(dst + len - 8, src + len - 8, 8);
+ } else {
+ __builtin_memcpy(dst, src, 4);
+ __builtin_memcpy(dst + len - 4, src + len - 4, 4);
+ }
+#else
+ MEMCPY(dst, src, char, len);
+#endif
+}
#if defined(__ARM_NEON) || defined(__ARM_NEON__) || defined(__aarch64__) || defined(_M_ARM64)
#include <arm_neon.h>
@@ -70,14 +100,14 @@ static inline SIMD_Implementation find_simd_implementation(void)
#define HAVE_SIMD_NEON 1
// See: https://community.arm.com/arm-community-blogs/b/servers-and-cloud-computing-blog/posts/porting-x86-vector-bitmask-optimizations-to-arm-neon
-static inline FORCE_INLINE uint64_t neon_match_mask(uint8x16_t matches)
+ALWAYS_INLINE(static) uint64_t neon_match_mask(uint8x16_t matches)
{
const uint8x8_t res = vshrn_n_u16(vreinterpretq_u16_u8(matches), 4);
const uint64_t mask = vget_lane_u64(vreinterpret_u64_u8(res), 0);
return mask & 0x8888888888888888ull;
}
-static inline FORCE_INLINE uint64_t compute_chunk_mask_neon(const char *ptr)
+ALWAYS_INLINE(static) uint64_t compute_chunk_mask_neon(const char *ptr)
{
uint8x16_t chunk = vld1q_u8((const unsigned char *)ptr);
@@ -90,7 +120,7 @@ static inline FORCE_INLINE uint64_t compute_chunk_mask_neon(const char *ptr)
return neon_match_mask(needs_escape);
}
-static inline FORCE_INLINE int string_scan_simd_neon(const char **ptr, const char *end, uint64_t *mask)
+ALWAYS_INLINE(static) int string_scan_simd_neon(const char **ptr, const char *end, uint64_t *mask)
{
while (*ptr + sizeof(uint8x16_t) <= end) {
uint64_t chunk_mask = compute_chunk_mask_neon(*ptr);
@@ -103,16 +133,6 @@ static inline FORCE_INLINE int string_scan_simd_neon(const char **ptr, const cha
return 0;
}
-static inline uint8x16x4_t load_uint8x16_4(const unsigned char *table)
-{
- uint8x16x4_t tab;
- tab.val[0] = vld1q_u8(table);
- tab.val[1] = vld1q_u8(table+16);
- tab.val[2] = vld1q_u8(table+32);
- tab.val[3] = vld1q_u8(table+48);
- return tab;
-}
-
#endif /* ARM Neon Support.*/
#if defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64) || defined(_M_X64) || defined(_M_AMD64)
@@ -137,7 +157,7 @@ static inline uint8x16x4_t load_uint8x16_4(const unsigned char *table)
#define _mm_cmpgt_epu8(a, b) _mm_xor_si128(_mm_cmple_epu8(a, b), _mm_set1_epi8(-1))
#define _mm_cmplt_epu8(a, b) _mm_cmpgt_epu8(b, a)
-static inline TARGET_SSE2 FORCE_INLINE int compute_chunk_mask_sse2(const char *ptr)
+ALWAYS_INLINE(static) TARGET_SSE2 int compute_chunk_mask_sse2(const char *ptr)
{
__m128i chunk = _mm_loadu_si128((__m128i const*)ptr);
// Trick: c < 32 || c == 34 can be factored as c ^ 2 < 33
@@ -148,7 +168,7 @@ static inline TARGET_SSE2 FORCE_INLINE int compute_chunk_mask_sse2(const char *p
return _mm_movemask_epi8(needs_escape);
}
-static inline TARGET_SSE2 FORCE_INLINE int string_scan_simd_sse2(const char **ptr, const char *end, int *mask)
+ALWAYS_INLINE(static) TARGET_SSE2 int string_scan_simd_sse2(const char **ptr, const char *end, int *mask)
{
while (*ptr + sizeof(__m128i) <= end) {
int chunk_mask = compute_chunk_mask_sse2(*ptr);
diff --git a/ext/json/vendor/fpconv.c b/ext/json/vendor/fpconv.c
index 75efd46f11..6c9bc2c103 100644
--- a/ext/json/vendor/fpconv.c
+++ b/ext/json/vendor/fpconv.c
@@ -29,6 +29,10 @@
#include <string.h>
#include <stdint.h>
+#if JSON_DEBUG
+#include <assert.h>
+#endif
+
#define npowers 87
#define steppowers 8
#define firstpower -348 /* 10 ^ -348 */
@@ -320,15 +324,7 @@ static int emit_digits(char* digits, int ndigits, char* dest, int K, bool neg)
{
int exp = absv(K + ndigits - 1);
- int max_trailing_zeros = 7;
-
- if(neg) {
- max_trailing_zeros -= 1;
- }
-
- /* write plain integer */
- if(K >= 0 && (exp < (ndigits + max_trailing_zeros))) {
-
+ if(K >= 0 && exp < 15) {
memcpy(dest, digits, ndigits);
memset(dest + ndigits, '0', K);
@@ -432,10 +428,12 @@ static int filter_special(double fp, char* dest)
*
* Input:
* fp -> the double to convert, dest -> destination buffer.
- * The generated string will never be longer than 28 characters.
- * Make sure to pass a pointer to at least 28 bytes of memory.
+ * The generated string will never be longer than 32 characters.
+ * Make sure to pass a pointer to at least 32 bytes of memory.
* The emitted string will not be null terminated.
*
+ *
+ *
* Output:
* The number of written characters.
*
@@ -451,7 +449,7 @@ static int filter_special(double fp, char* dest)
* }
*
*/
-static int fpconv_dtoa(double d, char dest[28])
+static int fpconv_dtoa(double d, char dest[32])
{
char digits[18];
@@ -474,6 +472,9 @@ static int fpconv_dtoa(double d, char dest[28])
int ndigits = grisu2(d, digits, &K);
str_len += emit_digits(digits, ndigits, dest + str_len, K, neg);
+#if JSON_DEBUG
+ assert(str_len <= 32);
+#endif
return str_len;
}
diff --git a/ext/json/vendor/ryu.h b/ext/json/vendor/ryu.h
new file mode 100644
index 0000000000..f06ec814b4
--- /dev/null
+++ b/ext/json/vendor/ryu.h
@@ -0,0 +1,819 @@
+// Copyright 2018 Ulf Adams
+//
+// The contents of this file may be used under the terms of the Apache License,
+// Version 2.0.
+//
+// Alternatively, the contents of this file may be used under the terms of
+// the Boost Software License, Version 1.0.
+//
+// Unless required by applicable law or agreed to in writing, this software
+// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.
+//
+// ---
+//
+// Apache License
+// Version 2.0, January 2004
+// http://www.apache.org/licenses/
+//
+// TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+//
+// 1. Definitions.
+//
+// "License" shall mean the terms and conditions for use, reproduction,
+// and distribution as defined by Sections 1 through 9 of this document.
+//
+// "Licensor" shall mean the copyright owner or entity authorized by
+// the copyright owner that is granting the License.
+//
+// "Legal Entity" shall mean the union of the acting entity and all
+// other entities that control, are controlled by, or are under common
+// control with that entity. For the purposes of this definition,
+// "control" means (i) the power, direct or indirect, to cause the
+// direction or management of such entity, whether by contract or
+// otherwise, or (ii) ownership of fifty percent (50%) or more of the
+// outstanding shares, or (iii) beneficial ownership of such entity.
+//
+// "You" (or "Your") shall mean an individual or Legal Entity
+// exercising permissions granted by this License.
+//
+// "Source" form shall mean the preferred form for making modifications,
+// including but not limited to software source code, documentation
+// source, and configuration files.
+//
+// "Object" form shall mean any form resulting from mechanical
+// transformation or translation of a Source form, including but
+// not limited to compiled object code, generated documentation,
+// and conversions to other media types.
+//
+// "Work" shall mean the work of authorship, whether in Source or
+// Object form, made available under the License, as indicated by a
+// copyright notice that is included in or attached to the work
+// (an example is provided in the Appendix below).
+//
+// "Derivative Works" shall mean any work, whether in Source or Object
+// form, that is based on (or derived from) the Work and for which the
+// editorial revisions, annotations, elaborations, or other modifications
+// represent, as a whole, an original work of authorship. For the purposes
+// of this License, Derivative Works shall not include works that remain
+// separable from, or merely link (or bind by name) to the interfaces of,
+// the Work and Derivative Works thereof.
+//
+// "Contribution" shall mean any work of authorship, including
+// the original version of the Work and any modifications or additions
+// to that Work or Derivative Works thereof, that is intentionally
+// submitted to Licensor for inclusion in the Work by the copyright owner
+// or by an individual or Legal Entity authorized to submit on behalf of
+// the copyright owner. For the purposes of this definition, "submitted"
+// means any form of electronic, verbal, or written communication sent
+// to the Licensor or its representatives, including but not limited to
+// communication on electronic mailing lists, source code control systems,
+// and issue tracking systems that are managed by, or on behalf of, the
+// Licensor for the purpose of discussing and improving the Work, but
+// excluding communication that is conspicuously marked or otherwise
+// designated in writing by the copyright owner as "Not a Contribution."
+//
+// "Contributor" shall mean Licensor and any individual or Legal Entity
+// on behalf of whom a Contribution has been received by Licensor and
+// subsequently incorporated within the Work.
+//
+// 2. Grant of Copyright License. Subject to the terms and conditions of
+// this License, each Contributor hereby grants to You a perpetual,
+// worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+// copyright license to reproduce, prepare Derivative Works of,
+// publicly display, publicly perform, sublicense, and distribute the
+// Work and such Derivative Works in Source or Object form.
+//
+// 3. Grant of Patent License. Subject to the terms and conditions of
+// this License, each Contributor hereby grants to You a perpetual,
+// worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+// (except as stated in this section) patent license to make, have made,
+// use, offer to sell, sell, import, and otherwise transfer the Work,
+// where such license applies only to those patent claims licensable
+// by such Contributor that are necessarily infringed by their
+// Contribution(s) alone or by combination of their Contribution(s)
+// with the Work to which such Contribution(s) was submitted. If You
+// institute patent litigation against any entity (including a
+// cross-claim or counterclaim in a lawsuit) alleging that the Work
+// or a Contribution incorporated within the Work constitutes direct
+// or contributory patent infringement, then any patent licenses
+// granted to You under this License for that Work shall terminate
+// as of the date such litigation is filed.
+//
+// 4. Redistribution. You may reproduce and distribute copies of the
+// Work or Derivative Works thereof in any medium, with or without
+// modifications, and in Source or Object form, provided that You
+// meet the following conditions:
+//
+// (a) You must give any other recipients of the Work or
+// Derivative Works a copy of this License; and
+//
+// (b) You must cause any modified files to carry prominent notices
+// stating that You changed the files; and
+//
+// (c) You must retain, in the Source form of any Derivative Works
+// that You distribute, all copyright, patent, trademark, and
+// attribution notices from the Source form of the Work,
+// excluding those notices that do not pertain to any part of
+// the Derivative Works; and
+//
+// (d) If the Work includes a "NOTICE" text file as part of its
+// distribution, then any Derivative Works that You distribute must
+// include a readable copy of the attribution notices contained
+// within such NOTICE file, excluding those notices that do not
+// pertain to any part of the Derivative Works, in at least one
+// of the following places: within a NOTICE text file distributed
+// as part of the Derivative Works; within the Source form or
+// documentation, if provided along with the Derivative Works; or,
+// within a display generated by the Derivative Works, if and
+// wherever such third-party notices normally appear. The contents
+// of the NOTICE file are for informational purposes only and
+// do not modify the License. You may add Your own attribution
+// notices within Derivative Works that You distribute, alongside
+// or as an addendum to the NOTICE text from the Work, provided
+// that such additional attribution notices cannot be construed
+// as modifying the License.
+//
+// You may add Your own copyright statement to Your modifications and
+// may provide additional or different license terms and conditions
+// for use, reproduction, or distribution of Your modifications, or
+// for any such Derivative Works as a whole, provided Your use,
+// reproduction, and distribution of the Work otherwise complies with
+// the conditions stated in this License.
+//
+// 5. Submission of Contributions. Unless You explicitly state otherwise,
+// any Contribution intentionally submitted for inclusion in the Work
+// by You to the Licensor shall be under the terms and conditions of
+// this License, without any additional terms or conditions.
+// Notwithstanding the above, nothing herein shall supersede or modify
+// the terms of any separate license agreement you may have executed
+// with Licensor regarding such Contributions.
+//
+// 6. Trademarks. This License does not grant permission to use the trade
+// names, trademarks, service marks, or product names of the Licensor,
+// except as required for reasonable and customary use in describing the
+// origin of the Work and reproducing the content of the NOTICE file.
+//
+// 7. Disclaimer of Warranty. Unless required by applicable law or
+// agreed to in writing, Licensor provides the Work (and each
+// Contributor provides its Contributions) on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+// implied, including, without limitation, any warranties or conditions
+// of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+// PARTICULAR PURPOSE. You are solely responsible for determining the
+// appropriateness of using or redistributing the Work and assume any
+// risks associated with Your exercise of permissions under this License.
+//
+// 8. Limitation of Liability. In no event and under no legal theory,
+// whether in tort (including negligence), contract, or otherwise,
+// unless required by applicable law (such as deliberate and grossly
+// negligent acts) or agreed to in writing, shall any Contributor be
+// liable to You for damages, including any direct, indirect, special,
+// incidental, or consequential damages of any character arising as a
+// result of this License or out of the use or inability to use the
+// Work (including but not limited to damages for loss of goodwill,
+// work stoppage, computer failure or malfunction, or any and all
+// other commercial damages or losses), even if such Contributor
+// has been advised of the possibility of such damages.
+//
+// 9. Accepting Warranty or Additional Liability. While redistributing
+// the Work or Derivative Works thereof, You may choose to offer,
+// and charge a fee for, acceptance of support, warranty, indemnity,
+// or other liability obligations and/or rights consistent with this
+// License. However, in accepting such obligations, You may act only
+// on Your own behalf and on Your sole responsibility, not on behalf
+// of any other Contributor, and only if You agree to indemnify,
+// defend, and hold each Contributor harmless for any liability
+// incurred by, or claims asserted against, such Contributor by reason
+// of your accepting any such warranty or additional liability.
+//
+// END OF TERMS AND CONDITIONS
+//
+// APPENDIX: How to apply the Apache License to your work.
+//
+// To apply the Apache License to your work, attach the following
+// boilerplate notice, with the fields enclosed by brackets "[]"
+// replaced with your own identifying information. (Don't include
+// the brackets!) The text should be enclosed in the appropriate
+// comment syntax for the file format. We also recommend that a
+// file or class name and description of purpose be included on the
+// same "printed page" as the copyright notice for easier
+// identification within third-party archives.
+//
+// Copyright [yyyy] [name of copyright owner]
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// ---
+//
+// Boost Software License - Version 1.0 - August 17th, 2003
+//
+// Permission is hereby granted, free of charge, to any person or organization
+// obtaining a copy of the software and accompanying documentation covered by
+// this license (the "Software") to use, reproduce, display, distribute,
+// execute, and transmit the Software, and to prepare derivative works of the
+// Software, and to permit third-parties to whom the Software is furnished to
+// do so, all subject to the following:
+//
+// The copyright notices in the Software and this entire statement, including
+// the above license grant, this restriction and the following disclaimer,
+// must be included in all copies of the Software, in whole or in part, and
+// all derivative works of the Software, unless such copies or derivative
+// works are solely in the form of machine-executable object code generated by
+// a source language processor.
+//
+// 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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// ---
+// Minimal Ryu implementation adapted for Ruby JSON gem by Josef Šimánek
+// Optimized for pre-extracted mantissa/exponent from JSON parsing
+// This is a stripped-down version containing only what's needed for
+// converting decimal mantissa+exponent to IEEE 754 double precision.
+
+#ifndef RYU_H
+#define RYU_H
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <string.h>
+
+// Detect __builtin_clzll availability (for floor_log2)
+// Note: MSVC doesn't have __builtin_clzll, so we provide a fallback
+#ifdef __clang__
+ #if __has_builtin(__builtin_clzll)
+ #define RYU_HAVE_BUILTIN_CLZLL 1
+ #else
+ #define RYU_HAVE_BUILTIN_CLZLL 0
+ #endif
+#elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3))
+ #define RYU_HAVE_BUILTIN_CLZLL 1
+#else
+ #define RYU_HAVE_BUILTIN_CLZLL 0
+#endif
+
+// Count leading zeros (for floor_log2)
+static inline uint32_t ryu_leading_zeros64(uint64_t input)
+{
+#if RYU_HAVE_BUILTIN_CLZLL
+ return __builtin_clzll(input);
+#else
+ // Fallback: binary search for the highest set bit
+ // This works on MSVC and other compilers without __builtin_clzll
+ if (input == 0) return 64;
+ uint32_t n = 0;
+ if (input <= 0x00000000FFFFFFFFULL) { n += 32; input <<= 32; }
+ if (input <= 0x0000FFFFFFFFFFFFULL) { n += 16; input <<= 16; }
+ if (input <= 0x00FFFFFFFFFFFFFFULL) { n += 8; input <<= 8; }
+ if (input <= 0x0FFFFFFFFFFFFFFFULL) { n += 4; input <<= 4; }
+ if (input <= 0x3FFFFFFFFFFFFFFFULL) { n += 2; input <<= 2; }
+ if (input <= 0x7FFFFFFFFFFFFFFFULL) { n += 1; }
+ return n;
+#endif
+}
+
+// These tables are generated by PrintDoubleLookupTable.
+#define DOUBLE_POW5_INV_BITCOUNT 125
+#define DOUBLE_POW5_BITCOUNT 125
+
+#define DOUBLE_POW5_INV_TABLE_SIZE 342
+#define DOUBLE_POW5_TABLE_SIZE 326
+
+static const uint64_t DOUBLE_POW5_INV_SPLIT[DOUBLE_POW5_INV_TABLE_SIZE][2] = {
+ { 1u, 2305843009213693952u }, { 11068046444225730970u, 1844674407370955161u },
+ { 5165088340638674453u, 1475739525896764129u }, { 7821419487252849886u, 1180591620717411303u },
+ { 8824922364862649494u, 1888946593147858085u }, { 7059937891890119595u, 1511157274518286468u },
+ { 13026647942995916322u, 1208925819614629174u }, { 9774590264567735146u, 1934281311383406679u },
+ { 11509021026396098440u, 1547425049106725343u }, { 16585914450600699399u, 1237940039285380274u },
+ { 15469416676735388068u, 1980704062856608439u }, { 16064882156130220778u, 1584563250285286751u },
+ { 9162556910162266299u, 1267650600228229401u }, { 7281393426775805432u, 2028240960365167042u },
+ { 16893161185646375315u, 1622592768292133633u }, { 2446482504291369283u, 1298074214633706907u },
+ { 7603720821608101175u, 2076918743413931051u }, { 2393627842544570617u, 1661534994731144841u },
+ { 16672297533003297786u, 1329227995784915872u }, { 11918280793837635165u, 2126764793255865396u },
+ { 5845275820328197809u, 1701411834604692317u }, { 15744267100488289217u, 1361129467683753853u },
+ { 3054734472329800808u, 2177807148294006166u }, { 17201182836831481939u, 1742245718635204932u },
+ { 6382248639981364905u, 1393796574908163946u }, { 2832900194486363201u, 2230074519853062314u },
+ { 5955668970331000884u, 1784059615882449851u }, { 1075186361522890384u, 1427247692705959881u },
+ { 12788344622662355584u, 2283596308329535809u }, { 13920024512871794791u, 1826877046663628647u },
+ { 3757321980813615186u, 1461501637330902918u }, { 10384555214134712795u, 1169201309864722334u },
+ { 5547241898389809503u, 1870722095783555735u }, { 4437793518711847602u, 1496577676626844588u },
+ { 10928932444453298728u, 1197262141301475670u }, { 17486291911125277965u, 1915619426082361072u },
+ { 6610335899416401726u, 1532495540865888858u }, { 12666966349016942027u, 1225996432692711086u },
+ { 12888448528943286597u, 1961594292308337738u }, { 17689456452638449924u, 1569275433846670190u },
+ { 14151565162110759939u, 1255420347077336152u }, { 7885109000409574610u, 2008672555323737844u },
+ { 9997436015069570011u, 1606938044258990275u }, { 7997948812055656009u, 1285550435407192220u },
+ { 12796718099289049614u, 2056880696651507552u }, { 2858676849947419045u, 1645504557321206042u },
+ { 13354987924183666206u, 1316403645856964833u }, { 17678631863951955605u, 2106245833371143733u },
+ { 3074859046935833515u, 1684996666696914987u }, { 13527933681774397782u, 1347997333357531989u },
+ { 10576647446613305481u, 2156795733372051183u }, { 15840015586774465031u, 1725436586697640946u },
+ { 8982663654677661702u, 1380349269358112757u }, { 18061610662226169046u, 2208558830972980411u },
+ { 10759939715039024913u, 1766847064778384329u }, { 12297300586773130254u, 1413477651822707463u },
+ { 15986332124095098083u, 2261564242916331941u }, { 9099716884534168143u, 1809251394333065553u },
+ { 14658471137111155161u, 1447401115466452442u }, { 4348079280205103483u, 1157920892373161954u },
+ { 14335624477811986218u, 1852673427797059126u }, { 7779150767507678651u, 1482138742237647301u },
+ { 2533971799264232598u, 1185710993790117841u }, { 15122401323048503126u, 1897137590064188545u },
+ { 12097921058438802501u, 1517710072051350836u }, { 5988988032009131678u, 1214168057641080669u },
+ { 16961078480698431330u, 1942668892225729070u }, { 13568862784558745064u, 1554135113780583256u },
+ { 7165741412905085728u, 1243308091024466605u }, { 11465186260648137165u, 1989292945639146568u },
+ { 16550846638002330379u, 1591434356511317254u }, { 16930026125143774626u, 1273147485209053803u },
+ { 4951948911778577463u, 2037035976334486086u }, { 272210314680951647u, 1629628781067588869u },
+ { 3907117066486671641u, 1303703024854071095u }, { 6251387306378674625u, 2085924839766513752u },
+ { 16069156289328670670u, 1668739871813211001u }, { 9165976216721026213u, 1334991897450568801u },
+ { 7286864317269821294u, 2135987035920910082u }, { 16897537898041588005u, 1708789628736728065u },
+ { 13518030318433270404u, 1367031702989382452u }, { 6871453250525591353u, 2187250724783011924u },
+ { 9186511415162383406u, 1749800579826409539u }, { 11038557946871817048u, 1399840463861127631u },
+ { 10282995085511086630u, 2239744742177804210u }, { 8226396068408869304u, 1791795793742243368u },
+ { 13959814484210916090u, 1433436634993794694u }, { 11267656730511734774u, 2293498615990071511u },
+ { 5324776569667477496u, 1834798892792057209u }, { 7949170070475892320u, 1467839114233645767u },
+ { 17427382500606444826u, 1174271291386916613u }, { 5747719112518849781u, 1878834066219066582u },
+ { 15666221734240810795u, 1503067252975253265u }, { 12532977387392648636u, 1202453802380202612u },
+ { 5295368560860596524u, 1923926083808324180u }, { 4236294848688477220u, 1539140867046659344u },
+ { 7078384693692692099u, 1231312693637327475u }, { 11325415509908307358u, 1970100309819723960u },
+ { 9060332407926645887u, 1576080247855779168u }, { 14626963555825137356u, 1260864198284623334u },
+ { 12335095245094488799u, 2017382717255397335u }, { 9868076196075591040u, 1613906173804317868u },
+ { 15273158586344293478u, 1291124939043454294u }, { 13369007293925138595u, 2065799902469526871u },
+ { 7005857020398200553u, 1652639921975621497u }, { 16672732060544291412u, 1322111937580497197u },
+ { 11918976037903224966u, 2115379100128795516u }, { 5845832015580669650u, 1692303280103036413u },
+ { 12055363241948356366u, 1353842624082429130u }, { 841837113407818570u, 2166148198531886609u },
+ { 4362818505468165179u, 1732918558825509287u }, { 14558301248600263113u, 1386334847060407429u },
+ { 12225235553534690011u, 2218135755296651887u }, { 2401490813343931363u, 1774508604237321510u },
+ { 1921192650675145090u, 1419606883389857208u }, { 17831303500047873437u, 2271371013423771532u },
+ { 6886345170554478103u, 1817096810739017226u }, { 1819727321701672159u, 1453677448591213781u },
+ { 16213177116328979020u, 1162941958872971024u }, { 14873036941900635463u, 1860707134196753639u },
+ { 15587778368262418694u, 1488565707357402911u }, { 8780873879868024632u, 1190852565885922329u },
+ { 2981351763563108441u, 1905364105417475727u }, { 13453127855076217722u, 1524291284333980581u },
+ { 7073153469319063855u, 1219433027467184465u }, { 11317045550910502167u, 1951092843947495144u },
+ { 12742985255470312057u, 1560874275157996115u }, { 10194388204376249646u, 1248699420126396892u },
+ { 1553625868034358140u, 1997919072202235028u }, { 8621598323911307159u, 1598335257761788022u },
+ { 17965325103354776697u, 1278668206209430417u }, { 13987124906400001422u, 2045869129935088668u },
+ { 121653480894270168u, 1636695303948070935u }, { 97322784715416134u, 1309356243158456748u },
+ { 14913111714512307107u, 2094969989053530796u }, { 8241140556867935363u, 1675975991242824637u },
+ { 17660958889720079260u, 1340780792994259709u }, { 17189487779326395846u, 2145249268790815535u },
+ { 13751590223461116677u, 1716199415032652428u }, { 18379969808252713988u, 1372959532026121942u },
+ { 14650556434236701088u, 2196735251241795108u }, { 652398703163629901u, 1757388200993436087u },
+ { 11589965406756634890u, 1405910560794748869u }, { 7475898206584884855u, 2249456897271598191u },
+ { 2291369750525997561u, 1799565517817278553u }, { 9211793429904618695u, 1439652414253822842u },
+ { 18428218302589300235u, 2303443862806116547u }, { 7363877012587619542u, 1842755090244893238u },
+ { 13269799239553916280u, 1474204072195914590u }, { 10615839391643133024u, 1179363257756731672u },
+ { 2227947767661371545u, 1886981212410770676u }, { 16539753473096738529u, 1509584969928616540u },
+ { 13231802778477390823u, 1207667975942893232u }, { 6413489186596184024u, 1932268761508629172u },
+ { 16198837793502678189u, 1545815009206903337u }, { 5580372605318321905u, 1236652007365522670u },
+ { 8928596168509315048u, 1978643211784836272u }, { 18210923379033183008u, 1582914569427869017u },
+ { 7190041073742725760u, 1266331655542295214u }, { 436019273762630246u, 2026130648867672343u },
+ { 7727513048493924843u, 1620904519094137874u }, { 9871359253537050198u, 1296723615275310299u },
+ { 4726128361433549347u, 2074757784440496479u }, { 7470251503888749801u, 1659806227552397183u },
+ { 13354898832594820487u, 1327844982041917746u }, { 13989140502667892133u, 2124551971267068394u },
+ { 14880661216876224029u, 1699641577013654715u }, { 11904528973500979224u, 1359713261610923772u },
+ { 4289851098633925465u, 2175541218577478036u }, { 18189276137874781665u, 1740432974861982428u },
+ { 3483374466074094362u, 1392346379889585943u }, { 1884050330976640656u, 2227754207823337509u },
+ { 5196589079523222848u, 1782203366258670007u }, { 15225317707844309248u, 1425762693006936005u },
+ { 5913764258841343181u, 2281220308811097609u }, { 8420360221814984868u, 1824976247048878087u },
+ { 17804334621677718864u, 1459980997639102469u }, { 17932816512084085415u, 1167984798111281975u },
+ { 10245762345624985047u, 1868775676978051161u }, { 4507261061758077715u, 1495020541582440929u },
+ { 7295157664148372495u, 1196016433265952743u }, { 7982903447895485668u, 1913626293225524389u },
+ { 10075671573058298858u, 1530901034580419511u }, { 4371188443704728763u, 1224720827664335609u },
+ { 14372599139411386667u, 1959553324262936974u }, { 15187428126271019657u, 1567642659410349579u },
+ { 15839291315758726049u, 1254114127528279663u }, { 3206773216762499739u, 2006582604045247462u },
+ { 13633465017635730761u, 1605266083236197969u }, { 14596120828850494932u, 1284212866588958375u },
+ { 4907049252451240275u, 2054740586542333401u }, { 236290587219081897u, 1643792469233866721u },
+ { 14946427728742906810u, 1315033975387093376u }, { 16535586736504830250u, 2104054360619349402u },
+ { 5849771759720043554u, 1683243488495479522u }, { 15747863852001765813u, 1346594790796383617u },
+ { 10439186904235184007u, 2154551665274213788u }, { 15730047152871967852u, 1723641332219371030u },
+ { 12584037722297574282u, 1378913065775496824u }, { 9066413911450387881u, 2206260905240794919u },
+ { 10942479943902220628u, 1765008724192635935u }, { 8753983955121776503u, 1412006979354108748u },
+ { 10317025513452932081u, 2259211166966573997u }, { 874922781278525018u, 1807368933573259198u },
+ { 8078635854506640661u, 1445895146858607358u }, { 13841606313089133175u, 1156716117486885886u },
+ { 14767872471458792434u, 1850745787979017418u }, { 746251532941302978u, 1480596630383213935u },
+ { 597001226353042382u, 1184477304306571148u }, { 15712597221132509104u, 1895163686890513836u },
+ { 8880728962164096960u, 1516130949512411069u }, { 10793931984473187891u, 1212904759609928855u },
+ { 17270291175157100626u, 1940647615375886168u }, { 2748186495899949531u, 1552518092300708935u },
+ { 2198549196719959625u, 1242014473840567148u }, { 18275073973719576693u, 1987223158144907436u },
+ { 10930710364233751031u, 1589778526515925949u }, { 12433917106128911148u, 1271822821212740759u },
+ { 8826220925580526867u, 2034916513940385215u }, { 7060976740464421494u, 1627933211152308172u },
+ { 16716827836597268165u, 1302346568921846537u }, { 11989529279587987770u, 2083754510274954460u },
+ { 9591623423670390216u, 1667003608219963568u }, { 15051996368420132820u, 1333602886575970854u },
+ { 13015147745246481542u, 2133764618521553367u }, { 3033420566713364587u, 1707011694817242694u },
+ { 6116085268112601993u, 1365609355853794155u }, { 9785736428980163188u, 2184974969366070648u },
+ { 15207286772667951197u, 1747979975492856518u }, { 1097782973908629988u, 1398383980394285215u },
+ { 1756452758253807981u, 2237414368630856344u }, { 5094511021344956708u, 1789931494904685075u },
+ { 4075608817075965366u, 1431945195923748060u }, { 6520974107321544586u, 2291112313477996896u },
+ { 1527430471115325346u, 1832889850782397517u }, { 12289990821117991246u, 1466311880625918013u },
+ { 17210690286378213644u, 1173049504500734410u }, { 9090360384495590213u, 1876879207201175057u },
+ { 18340334751822203140u, 1501503365760940045u }, { 14672267801457762512u, 1201202692608752036u },
+ { 16096930852848599373u, 1921924308174003258u }, { 1809498238053148529u, 1537539446539202607u },
+ { 12515645034668249793u, 1230031557231362085u }, { 1578287981759648052u, 1968050491570179337u },
+ { 12330676829633449412u, 1574440393256143469u }, { 13553890278448669853u, 1259552314604914775u },
+ { 3239480371808320148u, 2015283703367863641u }, { 17348979556414297411u, 1612226962694290912u },
+ { 6500486015647617283u, 1289781570155432730u }, { 10400777625036187652u, 2063650512248692368u },
+ { 15699319729512770768u, 1650920409798953894u }, { 16248804598352126938u, 1320736327839163115u },
+ { 7551343283653851484u, 2113178124542660985u }, { 6041074626923081187u, 1690542499634128788u },
+ { 12211557331022285596u, 1352433999707303030u }, { 1091747655926105338u, 2163894399531684849u },
+ { 4562746939482794594u, 1731115519625347879u }, { 7339546366328145998u, 1384892415700278303u },
+ { 8053925371383123274u, 2215827865120445285u }, { 6443140297106498619u, 1772662292096356228u },
+ { 12533209867169019542u, 1418129833677084982u }, { 5295740528502789974u, 2269007733883335972u },
+ { 15304638867027962949u, 1815206187106668777u }, { 4865013464138549713u, 1452164949685335022u },
+ { 14960057215536570740u, 1161731959748268017u }, { 9178696285890871890u, 1858771135597228828u },
+ { 14721654658196518159u, 1487016908477783062u }, { 4398626097073393881u, 1189613526782226450u },
+ { 7037801755317430209u, 1903381642851562320u }, { 5630241404253944167u, 1522705314281249856u },
+ { 814844308661245011u, 1218164251424999885u }, { 1303750893857992017u, 1949062802279999816u },
+ { 15800395974054034906u, 1559250241823999852u }, { 5261619149759407279u, 1247400193459199882u },
+ { 12107939454356961969u, 1995840309534719811u }, { 5997002748743659252u, 1596672247627775849u },
+ { 8486951013736837725u, 1277337798102220679u }, { 2511075177753209390u, 2043740476963553087u },
+ { 13076906586428298482u, 1634992381570842469u }, { 14150874083884549109u, 1307993905256673975u },
+ { 4194654460505726958u, 2092790248410678361u }, { 18113118827372222859u, 1674232198728542688u },
+ { 3422448617672047318u, 1339385758982834151u }, { 16543964232501006678u, 2143017214372534641u },
+ { 9545822571258895019u, 1714413771498027713u }, { 15015355686490936662u, 1371531017198422170u },
+ { 5577825024675947042u, 2194449627517475473u }, { 11840957649224578280u, 1755559702013980378u },
+ { 16851463748863483271u, 1404447761611184302u }, { 12204946739213931940u, 2247116418577894884u },
+ { 13453306206113055875u, 1797693134862315907u }, { 3383947335406624054u, 1438154507889852726u },
+ { 16482362180876329456u, 2301047212623764361u }, { 9496540929959153242u, 1840837770099011489u },
+ { 11286581558709232917u, 1472670216079209191u }, { 5339916432225476010u, 1178136172863367353u },
+ { 4854517476818851293u, 1885017876581387765u }, { 3883613981455081034u, 1508014301265110212u },
+ { 14174937629389795797u, 1206411441012088169u }, { 11611853762797942306u, 1930258305619341071u },
+ { 5600134195496443521u, 1544206644495472857u }, { 15548153800622885787u, 1235365315596378285u },
+ { 6430302007287065643u, 1976584504954205257u }, { 16212288050055383484u, 1581267603963364205u },
+ { 12969830440044306787u, 1265014083170691364u }, { 9683682259845159889u, 2024022533073106183u },
+ { 15125643437359948558u, 1619218026458484946u }, { 8411165935146048523u, 1295374421166787957u },
+ { 17147214310975587960u, 2072599073866860731u }, { 10028422634038560045u, 1658079259093488585u },
+ { 8022738107230848036u, 1326463407274790868u }, { 9147032156827446534u, 2122341451639665389u },
+ { 11006974540203867551u, 1697873161311732311u }, { 5116230817421183718u, 1358298529049385849u },
+ { 15564666937357714594u, 2173277646479017358u }, { 1383687105660440706u, 1738622117183213887u },
+ { 12174996128754083534u, 1390897693746571109u }, { 8411947361780802685u, 2225436309994513775u },
+ { 6729557889424642148u, 1780349047995611020u }, { 5383646311539713719u, 1424279238396488816u },
+ { 1235136468979721303u, 2278846781434382106u }, { 15745504434151418335u, 1823077425147505684u },
+ { 16285752362063044992u, 1458461940118004547u }, { 5649904260166615347u, 1166769552094403638u },
+ { 5350498001524674232u, 1866831283351045821u }, { 591049586477829062u, 1493465026680836657u },
+ { 11540886113407994219u, 1194772021344669325u }, { 18673707743239135u, 1911635234151470921u },
+ { 14772334225162232601u, 1529308187321176736u }, { 8128518565387875758u, 1223446549856941389u },
+ { 1937583260394870242u, 1957514479771106223u }, { 8928764237799716840u, 1566011583816884978u },
+ { 14521709019723594119u, 1252809267053507982u }, { 8477339172590109297u, 2004494827285612772u },
+ { 17849917782297818407u, 1603595861828490217u }, { 6901236596354434079u, 1282876689462792174u },
+ { 18420676183650915173u, 2052602703140467478u }, { 3668494502695001169u, 1642082162512373983u },
+ { 10313493231639821582u, 1313665730009899186u }, { 9122891541139893884u, 2101865168015838698u },
+ { 14677010862395735754u, 1681492134412670958u }, { 673562245690857633u, 1345193707530136767u }
+};
+
+static const uint64_t DOUBLE_POW5_SPLIT[DOUBLE_POW5_TABLE_SIZE][2] = {
+ { 0u, 1152921504606846976u }, { 0u, 1441151880758558720u },
+ { 0u, 1801439850948198400u }, { 0u, 2251799813685248000u },
+ { 0u, 1407374883553280000u }, { 0u, 1759218604441600000u },
+ { 0u, 2199023255552000000u }, { 0u, 1374389534720000000u },
+ { 0u, 1717986918400000000u }, { 0u, 2147483648000000000u },
+ { 0u, 1342177280000000000u }, { 0u, 1677721600000000000u },
+ { 0u, 2097152000000000000u }, { 0u, 1310720000000000000u },
+ { 0u, 1638400000000000000u }, { 0u, 2048000000000000000u },
+ { 0u, 1280000000000000000u }, { 0u, 1600000000000000000u },
+ { 0u, 2000000000000000000u }, { 0u, 1250000000000000000u },
+ { 0u, 1562500000000000000u }, { 0u, 1953125000000000000u },
+ { 0u, 1220703125000000000u }, { 0u, 1525878906250000000u },
+ { 0u, 1907348632812500000u }, { 0u, 1192092895507812500u },
+ { 0u, 1490116119384765625u }, { 4611686018427387904u, 1862645149230957031u },
+ { 9799832789158199296u, 1164153218269348144u }, { 12249790986447749120u, 1455191522836685180u },
+ { 15312238733059686400u, 1818989403545856475u }, { 14528612397897220096u, 2273736754432320594u },
+ { 13692068767113150464u, 1421085471520200371u }, { 12503399940464050176u, 1776356839400250464u },
+ { 15629249925580062720u, 2220446049250313080u }, { 9768281203487539200u, 1387778780781445675u },
+ { 7598665485932036096u, 1734723475976807094u }, { 274959820560269312u, 2168404344971008868u },
+ { 9395221924704944128u, 1355252715606880542u }, { 2520655369026404352u, 1694065894508600678u },
+ { 12374191248137781248u, 2117582368135750847u }, { 14651398557727195136u, 1323488980084844279u },
+ { 13702562178731606016u, 1654361225106055349u }, { 3293144668132343808u, 2067951531382569187u },
+ { 18199116482078572544u, 1292469707114105741u }, { 8913837547316051968u, 1615587133892632177u },
+ { 15753982952572452864u, 2019483917365790221u }, { 12152082354571476992u, 1262177448353618888u },
+ { 15190102943214346240u, 1577721810442023610u }, { 9764256642163156992u, 1972152263052529513u },
+ { 17631875447420442880u, 1232595164407830945u }, { 8204786253993389888u, 1540743955509788682u },
+ { 1032610780636961552u, 1925929944387235853u }, { 2951224747111794922u, 1203706215242022408u },
+ { 3689030933889743652u, 1504632769052528010u }, { 13834660704216955373u, 1880790961315660012u },
+ { 17870034976990372916u, 1175494350822287507u }, { 17725857702810578241u, 1469367938527859384u },
+ { 3710578054803671186u, 1836709923159824231u }, { 26536550077201078u, 2295887403949780289u },
+ { 11545800389866720434u, 1434929627468612680u }, { 14432250487333400542u, 1793662034335765850u },
+ { 8816941072311974870u, 2242077542919707313u }, { 17039803216263454053u, 1401298464324817070u },
+ { 12076381983474541759u, 1751623080406021338u }, { 5872105442488401391u, 2189528850507526673u },
+ { 15199280947623720629u, 1368455531567204170u }, { 9775729147674874978u, 1710569414459005213u },
+ { 16831347453020981627u, 2138211768073756516u }, { 1296220121283337709u, 1336382355046097823u },
+ { 15455333206886335848u, 1670477943807622278u }, { 10095794471753144002u, 2088097429759527848u },
+ { 6309871544845715001u, 1305060893599704905u }, { 12499025449484531656u, 1631326116999631131u },
+ { 11012095793428276666u, 2039157646249538914u }, { 11494245889320060820u, 1274473528905961821u },
+ { 532749306367912313u, 1593091911132452277u }, { 5277622651387278295u, 1991364888915565346u },
+ { 7910200175544436838u, 1244603055572228341u }, { 14499436237857933952u, 1555753819465285426u },
+ { 8900923260467641632u, 1944692274331606783u }, { 12480606065433357876u, 1215432671457254239u },
+ { 10989071563364309441u, 1519290839321567799u }, { 9124653435777998898u, 1899113549151959749u },
+ { 8008751406574943263u, 1186945968219974843u }, { 5399253239791291175u, 1483682460274968554u },
+ { 15972438586593889776u, 1854603075343710692u }, { 759402079766405302u, 1159126922089819183u },
+ { 14784310654990170340u, 1448908652612273978u }, { 9257016281882937117u, 1811135815765342473u },
+ { 16182956370781059300u, 2263919769706678091u }, { 7808504722524468110u, 1414949856066673807u },
+ { 5148944884728197234u, 1768687320083342259u }, { 1824495087482858639u, 2210859150104177824u },
+ { 1140309429676786649u, 1381786968815111140u }, { 1425386787095983311u, 1727233711018888925u },
+ { 6393419502297367043u, 2159042138773611156u }, { 13219259225790630210u, 1349401336733506972u },
+ { 16524074032238287762u, 1686751670916883715u }, { 16043406521870471799u, 2108439588646104644u },
+ { 803757039314269066u, 1317774742903815403u }, { 14839754354425000045u, 1647218428629769253u },
+ { 4714634887749086344u, 2059023035787211567u }, { 9864175832484260821u, 1286889397367007229u },
+ { 16941905809032713930u, 1608611746708759036u }, { 2730638187581340797u, 2010764683385948796u },
+ { 10930020904093113806u, 1256727927116217997u }, { 18274212148543780162u, 1570909908895272496u },
+ { 4396021111970173586u, 1963637386119090621u }, { 5053356204195052443u, 1227273366324431638u },
+ { 15540067292098591362u, 1534091707905539547u }, { 14813398096695851299u, 1917614634881924434u },
+ { 13870059828862294966u, 1198509146801202771u }, { 12725888767650480803u, 1498136433501503464u },
+ { 15907360959563101004u, 1872670541876879330u }, { 14553786618154326031u, 1170419088673049581u },
+ { 4357175217410743827u, 1463023860841311977u }, { 10058155040190817688u, 1828779826051639971u },
+ { 7961007781811134206u, 2285974782564549964u }, { 14199001900486734687u, 1428734239102843727u },
+ { 13137066357181030455u, 1785917798878554659u }, { 11809646928048900164u, 2232397248598193324u },
+ { 16604401366885338411u, 1395248280373870827u }, { 16143815690179285109u, 1744060350467338534u },
+ { 10956397575869330579u, 2180075438084173168u }, { 6847748484918331612u, 1362547148802608230u },
+ { 17783057643002690323u, 1703183936003260287u }, { 17617136035325974999u, 2128979920004075359u },
+ { 17928239049719816230u, 1330612450002547099u }, { 17798612793722382384u, 1663265562503183874u },
+ { 13024893955298202172u, 2079081953128979843u }, { 5834715712847682405u, 1299426220705612402u },
+ { 16516766677914378815u, 1624282775882015502u }, { 11422586310538197711u, 2030353469852519378u },
+ { 11750802462513761473u, 1268970918657824611u }, { 10076817059714813937u, 1586213648322280764u },
+ { 12596021324643517422u, 1982767060402850955u }, { 5566670318688504437u, 1239229412751781847u },
+ { 2346651879933242642u, 1549036765939727309u }, { 7545000868343941206u, 1936295957424659136u },
+ { 4715625542714963254u, 1210184973390411960u }, { 5894531928393704067u, 1512731216738014950u },
+ { 16591536947346905892u, 1890914020922518687u }, { 17287239619732898039u, 1181821263076574179u },
+ { 16997363506238734644u, 1477276578845717724u }, { 2799960309088866689u, 1846595723557147156u },
+ { 10973347230035317489u, 1154122327223216972u }, { 13716684037544146861u, 1442652909029021215u },
+ { 12534169028502795672u, 1803316136286276519u }, { 11056025267201106687u, 2254145170357845649u },
+ { 18439230838069161439u, 1408840731473653530u }, { 13825666510731675991u, 1761050914342066913u },
+ { 3447025083132431277u, 2201313642927583642u }, { 6766076695385157452u, 1375821026829739776u },
+ { 8457595869231446815u, 1719776283537174720u }, { 10571994836539308519u, 2149720354421468400u },
+ { 6607496772837067824u, 1343575221513417750u }, { 17482743002901110588u, 1679469026891772187u },
+ { 17241742735199000331u, 2099336283614715234u }, { 15387775227926763111u, 1312085177259197021u },
+ { 5399660979626290177u, 1640106471573996277u }, { 11361262242960250625u, 2050133089467495346u },
+ { 11712474920277544544u, 1281333180917184591u }, { 10028907631919542777u, 1601666476146480739u },
+ { 7924448521472040567u, 2002083095183100924u }, { 14176152362774801162u, 1251301934489438077u },
+ { 3885132398186337741u, 1564127418111797597u }, { 9468101516160310080u, 1955159272639746996u },
+ { 15140935484454969608u, 1221974545399841872u }, { 479425281859160394u, 1527468181749802341u },
+ { 5210967620751338397u, 1909335227187252926u }, { 17091912818251750210u, 1193334516992033078u },
+ { 12141518985959911954u, 1491668146240041348u }, { 15176898732449889943u, 1864585182800051685u },
+ { 11791404716994875166u, 1165365739250032303u }, { 10127569877816206054u, 1456707174062540379u },
+ { 8047776328842869663u, 1820883967578175474u }, { 836348374198811271u, 2276104959472719343u },
+ { 7440246761515338900u, 1422565599670449589u }, { 13911994470321561530u, 1778206999588061986u },
+ { 8166621051047176104u, 2222758749485077483u }, { 2798295147690791113u, 1389224218428173427u },
+ { 17332926989895652603u, 1736530273035216783u }, { 17054472718942177850u, 2170662841294020979u },
+ { 8353202440125167204u, 1356664275808763112u }, { 10441503050156459005u, 1695830344760953890u },
+ { 3828506775840797949u, 2119787930951192363u }, { 86973725686804766u, 1324867456844495227u },
+ { 13943775212390669669u, 1656084321055619033u }, { 3594660960206173375u, 2070105401319523792u },
+ { 2246663100128858359u, 1293815875824702370u }, { 12031700912015848757u, 1617269844780877962u },
+ { 5816254103165035138u, 2021587305976097453u }, { 5941001823691840913u, 1263492066235060908u },
+ { 7426252279614801142u, 1579365082793826135u }, { 4671129331091113523u, 1974206353492282669u },
+ { 5225298841145639904u, 1233878970932676668u }, { 6531623551432049880u, 1542348713665845835u },
+ { 3552843420862674446u, 1927935892082307294u }, { 16055585193321335241u, 1204959932551442058u },
+ { 10846109454796893243u, 1506199915689302573u }, { 18169322836923504458u, 1882749894611628216u },
+ { 11355826773077190286u, 1176718684132267635u }, { 9583097447919099954u, 1470898355165334544u },
+ { 11978871809898874942u, 1838622943956668180u }, { 14973589762373593678u, 2298278679945835225u },
+ { 2440964573842414192u, 1436424174966147016u }, { 3051205717303017741u, 1795530218707683770u },
+ { 13037379183483547984u, 2244412773384604712u }, { 8148361989677217490u, 1402757983365377945u },
+ { 14797138505523909766u, 1753447479206722431u }, { 13884737113477499304u, 2191809349008403039u },
+ { 15595489723564518921u, 1369880843130251899u }, { 14882676136028260747u, 1712351053912814874u },
+ { 9379973133180550126u, 2140438817391018593u }, { 17391698254306313589u, 1337774260869386620u },
+ { 3292878744173340370u, 1672217826086733276u }, { 4116098430216675462u, 2090272282608416595u },
+ { 266718509671728212u, 1306420176630260372u }, { 333398137089660265u, 1633025220787825465u },
+ { 5028433689789463235u, 2041281525984781831u }, { 10060300083759496378u, 1275800953740488644u },
+ { 12575375104699370472u, 1594751192175610805u }, { 1884160825592049379u, 1993438990219513507u },
+ { 17318501580490888525u, 1245899368887195941u }, { 7813068920331446945u, 1557374211108994927u },
+ { 5154650131986920777u, 1946717763886243659u }, { 915813323278131534u, 1216698602428902287u },
+ { 14979824709379828129u, 1520873253036127858u }, { 9501408849870009354u, 1901091566295159823u },
+ { 12855909558809837702u, 1188182228934474889u }, { 2234828893230133415u, 1485227786168093612u },
+ { 2793536116537666769u, 1856534732710117015u }, { 8663489100477123587u, 1160334207943823134u },
+ { 1605989338741628675u, 1450417759929778918u }, { 11230858710281811652u, 1813022199912223647u },
+ { 9426887369424876662u, 2266277749890279559u }, { 12809333633531629769u, 1416423593681424724u },
+ { 16011667041914537212u, 1770529492101780905u }, { 6179525747111007803u, 2213161865127226132u },
+ { 13085575628799155685u, 1383226165704516332u }, { 16356969535998944606u, 1729032707130645415u },
+ { 15834525901571292854u, 2161290883913306769u }, { 2979049660840976177u, 1350806802445816731u },
+ { 17558870131333383934u, 1688508503057270913u }, { 8113529608884566205u, 2110635628821588642u },
+ { 9682642023980241782u, 1319147268013492901u }, { 16714988548402690132u, 1648934085016866126u },
+ { 11670363648648586857u, 2061167606271082658u }, { 11905663298832754689u, 1288229753919426661u },
+ { 1047021068258779650u, 1610287192399283327u }, { 15143834390605638274u, 2012858990499104158u },
+ { 4853210475701136017u, 1258036869061940099u }, { 1454827076199032118u, 1572546086327425124u },
+ { 1818533845248790147u, 1965682607909281405u }, { 3442426662494187794u, 1228551629943300878u },
+ { 13526405364972510550u, 1535689537429126097u }, { 3072948650933474476u, 1919611921786407622u },
+ { 15755650962115585259u, 1199757451116504763u }, { 15082877684217093670u, 1499696813895630954u },
+ { 9630225068416591280u, 1874621017369538693u }, { 8324733676974063502u, 1171638135855961683u },
+ { 5794231077790191473u, 1464547669819952104u }, { 7242788847237739342u, 1830684587274940130u },
+ { 18276858095901949986u, 2288355734093675162u }, { 16034722328366106645u, 1430222333808546976u },
+ { 1596658836748081690u, 1787777917260683721u }, { 6607509564362490017u, 2234722396575854651u },
+ { 1823850468512862308u, 1396701497859909157u }, { 6891499104068465790u, 1745876872324886446u },
+ { 17837745916940358045u, 2182346090406108057u }, { 4231062170446641922u, 1363966306503817536u },
+ { 5288827713058302403u, 1704957883129771920u }, { 6611034641322878003u, 2131197353912214900u },
+ { 13355268687681574560u, 1331998346195134312u }, { 16694085859601968200u, 1664997932743917890u },
+ { 11644235287647684442u, 2081247415929897363u }, { 4971804045566108824u, 1300779634956185852u },
+ { 6214755056957636030u, 1625974543695232315u }, { 3156757802769657134u, 2032468179619040394u },
+ { 6584659645158423613u, 1270292612261900246u }, { 17454196593302805324u, 1587865765327375307u },
+ { 17206059723201118751u, 1984832206659219134u }, { 6142101308573311315u, 1240520129162011959u },
+ { 3065940617289251240u, 1550650161452514949u }, { 8444111790038951954u, 1938312701815643686u },
+ { 665883850346957067u, 1211445438634777304u }, { 832354812933696334u, 1514306798293471630u },
+ { 10263815553021896226u, 1892883497866839537u }, { 17944099766707154901u, 1183052186166774710u },
+ { 13206752671529167818u, 1478815232708468388u }, { 16508440839411459773u, 1848519040885585485u },
+ { 12623618533845856310u, 1155324400553490928u }, { 15779523167307320387u, 1444155500691863660u },
+ { 1277659885424598868u, 1805194375864829576u }, { 1597074856780748586u, 2256492969831036970u },
+ { 5609857803915355770u, 1410308106144398106u }, { 16235694291748970521u, 1762885132680497632u },
+ { 1847873790976661535u, 2203606415850622041u }, { 12684136165428883219u, 1377254009906638775u },
+ { 11243484188358716120u, 1721567512383298469u }, { 219297180166231438u, 2151959390479123087u },
+ { 7054589765244976505u, 1344974619049451929u }, { 13429923224983608535u, 1681218273811814911u },
+ { 12175718012802122765u, 2101522842264768639u }, { 14527352785642408584u, 1313451776415480399u },
+ { 13547504963625622826u, 1641814720519350499u }, { 12322695186104640628u, 2052268400649188124u },
+ { 16925056528170176201u, 1282667750405742577u }, { 7321262604930556539u, 1603334688007178222u },
+ { 18374950293017971482u, 2004168360008972777u }, { 4566814905495150320u, 1252605225005607986u },
+ { 14931890668723713708u, 1565756531257009982u }, { 9441491299049866327u, 1957195664071262478u },
+ { 1289246043478778550u, 1223247290044539049u }, { 6223243572775861092u, 1529059112555673811u },
+ { 3167368447542438461u, 1911323890694592264u }, { 1979605279714024038u, 1194577431684120165u },
+ { 7086192618069917952u, 1493221789605150206u }, { 18081112809442173248u, 1866527237006437757u },
+ { 13606538515115052232u, 1166579523129023598u }, { 7784801107039039482u, 1458224403911279498u },
+ { 507629346944023544u, 1822780504889099373u }, { 5246222702107417334u, 2278475631111374216u },
+ { 3278889188817135834u, 1424047269444608885u }, { 8710297504448807696u, 1780059086805761106u }
+};
+
+// IEEE 754 double precision constants
+#define DOUBLE_MANTISSA_BITS 52
+#define DOUBLE_EXPONENT_BITS 11
+#define DOUBLE_EXPONENT_BIAS 1023
+
+// Helper: floor(log2(value)) using ryu_leading_zeros64
+static inline uint32_t floor_log2(const uint64_t value) {
+ return 63 - ryu_leading_zeros64(value);
+}
+
+// Helper: log2(5^e) approximation
+static inline int32_t log2pow5(const int32_t e) {
+ return (int32_t) ((((uint32_t) e) * 1217359) >> 19);
+}
+
+// Helper: ceil(log2(5^e))
+static inline int32_t ceil_log2pow5(const int32_t e) {
+ return log2pow5(e) + 1;
+}
+
+// Helper: max of two int32
+static inline int32_t max32(int32_t a, int32_t b) {
+ return a < b ? b : a;
+}
+
+// Helper: convert uint64 bits to double
+static inline double int64Bits2Double(uint64_t bits) {
+ double f;
+ memcpy(&f, &bits, sizeof(double));
+ return f;
+}
+
+// Check if value is multiple of 2^p
+static inline bool multipleOfPowerOf2(const uint64_t value, const uint32_t p) {
+ return (value & ((1ull << p) - 1)) == 0;
+}
+
+// Count how many times value is divisible by 5
+// Uses modular inverse to avoid expensive division
+static inline uint32_t pow5Factor(uint64_t value) {
+ const uint64_t m_inv_5 = 14757395258967641293u; // 5 * m_inv_5 = 1 (mod 2^64)
+ const uint64_t n_div_5 = 3689348814741910323u; // 2^64 / 5
+ uint32_t count = 0;
+ for (;;) {
+ value *= m_inv_5;
+ if (value > n_div_5)
+ break;
+ ++count;
+ }
+ return count;
+}
+
+// Check if value is multiple of 5^p
+// Optimized: uses modular inverse instead of division
+static inline bool multipleOfPowerOf5(const uint64_t value, const uint32_t p) {
+ return pow5Factor(value) >= p;
+}
+
+// 128-bit multiplication with shift
+// This is the core operation for converting decimal to binary
+#if defined(__SIZEOF_INT128__)
+// Use native 128-bit integers if available (GCC/Clang)
+static inline uint64_t mulShift64(const uint64_t m, const uint64_t* const mul, const int32_t j) {
+ const unsigned __int128 b0 = ((unsigned __int128) m) * mul[0];
+ const unsigned __int128 b2 = ((unsigned __int128) m) * mul[1];
+ return (uint64_t) (((b0 >> 64) + b2) >> (j - 64));
+}
+#else
+// Fallback for systems without 128-bit integers
+static inline uint64_t umul128(const uint64_t a, const uint64_t b, uint64_t* const productHi) {
+ const uint32_t aLo = (uint32_t)a;
+ const uint32_t aHi = (uint32_t)(a >> 32);
+ const uint32_t bLo = (uint32_t)b;
+ const uint32_t bHi = (uint32_t)(b >> 32);
+
+ const uint64_t b00 = (uint64_t)aLo * bLo;
+ const uint64_t b01 = (uint64_t)aLo * bHi;
+ const uint64_t b10 = (uint64_t)aHi * bLo;
+ const uint64_t b11 = (uint64_t)aHi * bHi;
+
+ const uint32_t b00Lo = (uint32_t)b00;
+ const uint32_t b00Hi = (uint32_t)(b00 >> 32);
+
+ const uint64_t mid1 = b10 + b00Hi;
+ const uint32_t mid1Lo = (uint32_t)(mid1);
+ const uint32_t mid1Hi = (uint32_t)(mid1 >> 32);
+
+ const uint64_t mid2 = b01 + mid1Lo;
+ const uint32_t mid2Lo = (uint32_t)(mid2);
+ const uint32_t mid2Hi = (uint32_t)(mid2 >> 32);
+
+ const uint64_t pHi = b11 + mid1Hi + mid2Hi;
+ const uint64_t pLo = ((uint64_t)mid2Lo << 32) | b00Lo;
+
+ *productHi = pHi;
+ return pLo;
+}
+
+static inline uint64_t shiftright128(const uint64_t lo, const uint64_t hi, const uint32_t dist) {
+ return (hi << (64 - dist)) | (lo >> dist);
+}
+
+static inline uint64_t mulShift64(const uint64_t m, const uint64_t* const mul, const int32_t j) {
+ uint64_t high1;
+ const uint64_t low1 = umul128(m, mul[1], &high1);
+ uint64_t high0;
+ umul128(m, mul[0], &high0);
+ const uint64_t sum = high0 + low1;
+ if (sum < high0) {
+ ++high1;
+ }
+ return shiftright128(sum, high1, j - 64);
+}
+#endif
+
+// Main conversion function: decimal mantissa+exponent to IEEE 754 double
+// Optimized for JSON parsing with fast paths for edge cases
+static inline double ryu_s2d_from_parts(uint64_t m10, int m10digits, int32_t e10, bool signedM) {
+ // Fast path: handle zero explicitly (e.g., "0.0", "0e0")
+ if (m10 == 0) {
+ return int64Bits2Double(((uint64_t) signedM) << 63);
+ }
+
+ // Fast path: handle overflow/underflow early
+ if (m10digits + e10 <= -324) {
+ // Underflow to zero
+ return int64Bits2Double(((uint64_t) signedM) << 63);
+ }
+
+ if (m10digits + e10 >= 310) {
+ // Overflow to infinity
+ return int64Bits2Double((((uint64_t) signedM) << 63) | 0x7ff0000000000000ULL);
+ }
+
+ // Convert decimal to binary: m10 * 10^e10 = m2 * 2^e2
+ int32_t e2;
+ uint64_t m2;
+ bool trailingZeros;
+
+ if (e10 >= 0) {
+ // Positive exponent: multiply by 5^e10 and adjust binary exponent
+ e2 = floor_log2(m10) + e10 + log2pow5(e10) - (DOUBLE_MANTISSA_BITS + 1);
+ int j = e2 - e10 - ceil_log2pow5(e10) + DOUBLE_POW5_BITCOUNT;
+ m2 = mulShift64(m10, DOUBLE_POW5_SPLIT[e10], j);
+ trailingZeros = e2 < e10 || (e2 - e10 < 64 && multipleOfPowerOf2(m10, e2 - e10));
+ } else {
+ // Negative exponent: divide by 5^(-e10)
+ e2 = floor_log2(m10) + e10 - ceil_log2pow5(-e10) - (DOUBLE_MANTISSA_BITS + 1);
+ int j = e2 - e10 + ceil_log2pow5(-e10) - 1 + DOUBLE_POW5_INV_BITCOUNT;
+ m2 = mulShift64(m10, DOUBLE_POW5_INV_SPLIT[-e10], j);
+ trailingZeros = multipleOfPowerOf5(m10, -e10);
+ }
+
+ // Compute IEEE 754 exponent
+ uint32_t ieee_e2 = (uint32_t) max32(0, e2 + DOUBLE_EXPONENT_BIAS + floor_log2(m2));
+
+ if (ieee_e2 > 0x7fe) {
+ // Overflow to infinity
+ return int64Bits2Double((((uint64_t) signedM) << 63) | 0x7ff0000000000000ULL);
+ }
+
+ // Compute shift amount for rounding
+ int32_t shift = (ieee_e2 == 0 ? 1 : ieee_e2) - e2 - DOUBLE_EXPONENT_BIAS - DOUBLE_MANTISSA_BITS;
+
+ // IEEE 754 round-to-even (banker's rounding)
+ trailingZeros &= (m2 & ((1ull << (shift - 1)) - 1)) == 0;
+ uint64_t lastRemovedBit = (m2 >> (shift - 1)) & 1;
+ bool roundUp = (lastRemovedBit != 0) && (!trailingZeros || (((m2 >> shift) & 1) != 0));
+
+ uint64_t ieee_m2 = (m2 >> shift) + roundUp;
+ ieee_m2 &= (1ull << DOUBLE_MANTISSA_BITS) - 1;
+
+ if (ieee_m2 == 0 && roundUp) {
+ ieee_e2++;
+ }
+
+ // Pack sign, exponent, and mantissa into IEEE 754 format
+ // Match original Ryu: group sign+exponent, then shift and add mantissa
+ uint64_t ieee = (((((uint64_t) signedM) << DOUBLE_EXPONENT_BITS) | (uint64_t)ieee_e2) << DOUBLE_MANTISSA_BITS) | ieee_m2;
+ return int64Bits2Double(ieee);
+}
+
+#endif // RYU_H
diff --git a/ext/monitor/depend b/ext/monitor/depend
deleted file mode 100644
index 0c7d54afc8..0000000000
--- a/ext/monitor/depend
+++ /dev/null
@@ -1,162 +0,0 @@
-# AUTOGENERATED DEPENDENCIES START
-monitor.o: $(RUBY_EXTCONF_H)
-monitor.o: $(arch_hdrdir)/ruby/config.h
-monitor.o: $(hdrdir)/ruby/assert.h
-monitor.o: $(hdrdir)/ruby/backward.h
-monitor.o: $(hdrdir)/ruby/backward/2/assume.h
-monitor.o: $(hdrdir)/ruby/backward/2/attributes.h
-monitor.o: $(hdrdir)/ruby/backward/2/bool.h
-monitor.o: $(hdrdir)/ruby/backward/2/inttypes.h
-monitor.o: $(hdrdir)/ruby/backward/2/limits.h
-monitor.o: $(hdrdir)/ruby/backward/2/long_long.h
-monitor.o: $(hdrdir)/ruby/backward/2/stdalign.h
-monitor.o: $(hdrdir)/ruby/backward/2/stdarg.h
-monitor.o: $(hdrdir)/ruby/defines.h
-monitor.o: $(hdrdir)/ruby/intern.h
-monitor.o: $(hdrdir)/ruby/internal/abi.h
-monitor.o: $(hdrdir)/ruby/internal/anyargs.h
-monitor.o: $(hdrdir)/ruby/internal/arithmetic.h
-monitor.o: $(hdrdir)/ruby/internal/arithmetic/char.h
-monitor.o: $(hdrdir)/ruby/internal/arithmetic/double.h
-monitor.o: $(hdrdir)/ruby/internal/arithmetic/fixnum.h
-monitor.o: $(hdrdir)/ruby/internal/arithmetic/gid_t.h
-monitor.o: $(hdrdir)/ruby/internal/arithmetic/int.h
-monitor.o: $(hdrdir)/ruby/internal/arithmetic/intptr_t.h
-monitor.o: $(hdrdir)/ruby/internal/arithmetic/long.h
-monitor.o: $(hdrdir)/ruby/internal/arithmetic/long_long.h
-monitor.o: $(hdrdir)/ruby/internal/arithmetic/mode_t.h
-monitor.o: $(hdrdir)/ruby/internal/arithmetic/off_t.h
-monitor.o: $(hdrdir)/ruby/internal/arithmetic/pid_t.h
-monitor.o: $(hdrdir)/ruby/internal/arithmetic/short.h
-monitor.o: $(hdrdir)/ruby/internal/arithmetic/size_t.h
-monitor.o: $(hdrdir)/ruby/internal/arithmetic/st_data_t.h
-monitor.o: $(hdrdir)/ruby/internal/arithmetic/uid_t.h
-monitor.o: $(hdrdir)/ruby/internal/assume.h
-monitor.o: $(hdrdir)/ruby/internal/attr/alloc_size.h
-monitor.o: $(hdrdir)/ruby/internal/attr/artificial.h
-monitor.o: $(hdrdir)/ruby/internal/attr/cold.h
-monitor.o: $(hdrdir)/ruby/internal/attr/const.h
-monitor.o: $(hdrdir)/ruby/internal/attr/constexpr.h
-monitor.o: $(hdrdir)/ruby/internal/attr/deprecated.h
-monitor.o: $(hdrdir)/ruby/internal/attr/diagnose_if.h
-monitor.o: $(hdrdir)/ruby/internal/attr/enum_extensibility.h
-monitor.o: $(hdrdir)/ruby/internal/attr/error.h
-monitor.o: $(hdrdir)/ruby/internal/attr/flag_enum.h
-monitor.o: $(hdrdir)/ruby/internal/attr/forceinline.h
-monitor.o: $(hdrdir)/ruby/internal/attr/format.h
-monitor.o: $(hdrdir)/ruby/internal/attr/maybe_unused.h
-monitor.o: $(hdrdir)/ruby/internal/attr/noalias.h
-monitor.o: $(hdrdir)/ruby/internal/attr/nodiscard.h
-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
-monitor.o: $(hdrdir)/ruby/internal/attr/warning.h
-monitor.o: $(hdrdir)/ruby/internal/attr/weakref.h
-monitor.o: $(hdrdir)/ruby/internal/cast.h
-monitor.o: $(hdrdir)/ruby/internal/compiler_is.h
-monitor.o: $(hdrdir)/ruby/internal/compiler_is/apple.h
-monitor.o: $(hdrdir)/ruby/internal/compiler_is/clang.h
-monitor.o: $(hdrdir)/ruby/internal/compiler_is/gcc.h
-monitor.o: $(hdrdir)/ruby/internal/compiler_is/intel.h
-monitor.o: $(hdrdir)/ruby/internal/compiler_is/msvc.h
-monitor.o: $(hdrdir)/ruby/internal/compiler_is/sunpro.h
-monitor.o: $(hdrdir)/ruby/internal/compiler_since.h
-monitor.o: $(hdrdir)/ruby/internal/config.h
-monitor.o: $(hdrdir)/ruby/internal/constant_p.h
-monitor.o: $(hdrdir)/ruby/internal/core.h
-monitor.o: $(hdrdir)/ruby/internal/core/rarray.h
-monitor.o: $(hdrdir)/ruby/internal/core/rbasic.h
-monitor.o: $(hdrdir)/ruby/internal/core/rbignum.h
-monitor.o: $(hdrdir)/ruby/internal/core/rclass.h
-monitor.o: $(hdrdir)/ruby/internal/core/rdata.h
-monitor.o: $(hdrdir)/ruby/internal/core/rfile.h
-monitor.o: $(hdrdir)/ruby/internal/core/rhash.h
-monitor.o: $(hdrdir)/ruby/internal/core/robject.h
-monitor.o: $(hdrdir)/ruby/internal/core/rregexp.h
-monitor.o: $(hdrdir)/ruby/internal/core/rstring.h
-monitor.o: $(hdrdir)/ruby/internal/core/rstruct.h
-monitor.o: $(hdrdir)/ruby/internal/core/rtypeddata.h
-monitor.o: $(hdrdir)/ruby/internal/ctype.h
-monitor.o: $(hdrdir)/ruby/internal/dllexport.h
-monitor.o: $(hdrdir)/ruby/internal/dosish.h
-monitor.o: $(hdrdir)/ruby/internal/error.h
-monitor.o: $(hdrdir)/ruby/internal/eval.h
-monitor.o: $(hdrdir)/ruby/internal/event.h
-monitor.o: $(hdrdir)/ruby/internal/fl_type.h
-monitor.o: $(hdrdir)/ruby/internal/gc.h
-monitor.o: $(hdrdir)/ruby/internal/glob.h
-monitor.o: $(hdrdir)/ruby/internal/globals.h
-monitor.o: $(hdrdir)/ruby/internal/has/attribute.h
-monitor.o: $(hdrdir)/ruby/internal/has/builtin.h
-monitor.o: $(hdrdir)/ruby/internal/has/c_attribute.h
-monitor.o: $(hdrdir)/ruby/internal/has/cpp_attribute.h
-monitor.o: $(hdrdir)/ruby/internal/has/declspec_attribute.h
-monitor.o: $(hdrdir)/ruby/internal/has/extension.h
-monitor.o: $(hdrdir)/ruby/internal/has/feature.h
-monitor.o: $(hdrdir)/ruby/internal/has/warning.h
-monitor.o: $(hdrdir)/ruby/internal/intern/array.h
-monitor.o: $(hdrdir)/ruby/internal/intern/bignum.h
-monitor.o: $(hdrdir)/ruby/internal/intern/class.h
-monitor.o: $(hdrdir)/ruby/internal/intern/compar.h
-monitor.o: $(hdrdir)/ruby/internal/intern/complex.h
-monitor.o: $(hdrdir)/ruby/internal/intern/cont.h
-monitor.o: $(hdrdir)/ruby/internal/intern/dir.h
-monitor.o: $(hdrdir)/ruby/internal/intern/enum.h
-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/hash.h
-monitor.o: $(hdrdir)/ruby/internal/intern/io.h
-monitor.o: $(hdrdir)/ruby/internal/intern/load.h
-monitor.o: $(hdrdir)/ruby/internal/intern/marshal.h
-monitor.o: $(hdrdir)/ruby/internal/intern/numeric.h
-monitor.o: $(hdrdir)/ruby/internal/intern/object.h
-monitor.o: $(hdrdir)/ruby/internal/intern/parse.h
-monitor.o: $(hdrdir)/ruby/internal/intern/proc.h
-monitor.o: $(hdrdir)/ruby/internal/intern/process.h
-monitor.o: $(hdrdir)/ruby/internal/intern/random.h
-monitor.o: $(hdrdir)/ruby/internal/intern/range.h
-monitor.o: $(hdrdir)/ruby/internal/intern/rational.h
-monitor.o: $(hdrdir)/ruby/internal/intern/re.h
-monitor.o: $(hdrdir)/ruby/internal/intern/ruby.h
-monitor.o: $(hdrdir)/ruby/internal/intern/select.h
-monitor.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
-monitor.o: $(hdrdir)/ruby/internal/intern/set.h
-monitor.o: $(hdrdir)/ruby/internal/intern/signal.h
-monitor.o: $(hdrdir)/ruby/internal/intern/sprintf.h
-monitor.o: $(hdrdir)/ruby/internal/intern/string.h
-monitor.o: $(hdrdir)/ruby/internal/intern/struct.h
-monitor.o: $(hdrdir)/ruby/internal/intern/thread.h
-monitor.o: $(hdrdir)/ruby/internal/intern/time.h
-monitor.o: $(hdrdir)/ruby/internal/intern/variable.h
-monitor.o: $(hdrdir)/ruby/internal/intern/vm.h
-monitor.o: $(hdrdir)/ruby/internal/interpreter.h
-monitor.o: $(hdrdir)/ruby/internal/iterator.h
-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/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
-monitor.o: $(hdrdir)/ruby/internal/variable.h
-monitor.o: $(hdrdir)/ruby/internal/warning_push.h
-monitor.o: $(hdrdir)/ruby/internal/xmalloc.h
-monitor.o: $(hdrdir)/ruby/missing.h
-monitor.o: $(hdrdir)/ruby/ruby.h
-monitor.o: $(hdrdir)/ruby/st.h
-monitor.o: $(hdrdir)/ruby/subst.h
-monitor.o: monitor.c
-# AUTOGENERATED DEPENDENCIES END
diff --git a/ext/monitor/extconf.rb b/ext/monitor/extconf.rb
deleted file mode 100644
index 78c53fa0c5..0000000000
--- a/ext/monitor/extconf.rb
+++ /dev/null
@@ -1,2 +0,0 @@
-require 'mkmf'
-create_makefile('monitor')
diff --git a/ext/monitor/lib/monitor.rb b/ext/monitor/lib/monitor.rb
deleted file mode 100644
index 82d0a75c56..0000000000
--- a/ext/monitor/lib/monitor.rb
+++ /dev/null
@@ -1,289 +0,0 @@
-# frozen_string_literal: false
-# = monitor.rb
-#
-# Copyright (C) 2001 Shugo Maeda <shugo@ruby-lang.org>
-#
-# This library is distributed under the terms of the Ruby license.
-# 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
-# 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].
-#
-# == Examples
-#
-# === Simple object.extend
-#
-# require 'monitor.rb'
-#
-# buf = []
-# buf.extend(MonitorMixin)
-# empty_cond = buf.new_cond
-#
-# # consumer
-# Thread.start do
-# loop do
-# buf.synchronize do
-# empty_cond.wait_while { buf.empty? }
-# print buf.shift
-# end
-# end
-# end
-#
-# # producer
-# while line = ARGF.gets
-# buf.synchronize do
-# buf.push(line)
-# empty_cond.signal
-# end
-# 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
-# line from ARGF and pushes it into buf then calls <tt>empty_cond.signal</tt>
-# to notify the consumer thread of new data.
-#
-# === Simple Class include
-#
-# require 'monitor'
-#
-# class SynchronizedArray < Array
-#
-# include MonitorMixin
-#
-# def initialize(*args)
-# super(*args)
-# end
-#
-# alias :old_shift :shift
-# alias :old_unshift :unshift
-#
-# def shift(n=1)
-# self.synchronize do
-# self.old_shift(n)
-# end
-# end
-#
-# def unshift(item)
-# self.synchronize do
-# self.old_unshift(item)
-# end
-# end
-#
-# # other methods ...
-# end
-#
-# +SynchronizedArray+ implements an Array with synchronized access to items.
-# This Class is implemented as subclass of Array which includes the
-# MonitorMixin module.
-#
-module MonitorMixin
- #
- # FIXME: This isn't documented in Nutshell.
- #
- # Since MonitorMixin.new_cond returns a ConditionVariable, and the example
- # above calls while_wait and signal, this class should be documented.
- #
- class ConditionVariable
- #
- # Releases the lock held in the associated monitor and waits; reacquires the lock on wakeup.
- #
- # If +timeout+ is given, this method returns after +timeout+ seconds passed,
- # even if no other thread doesn't signal.
- #
- def wait(timeout = nil)
- @monitor.mon_check_owner
- @monitor.wait_for_cond(@cond, timeout)
- end
-
- #
- # Calls wait repeatedly while the given block yields a truthy value.
- #
- def wait_while
- while yield
- wait
- end
- end
-
- #
- # Calls wait repeatedly until the given block yields a truthy value.
- #
- def wait_until
- until yield
- wait
- end
- end
-
- #
- # Wakes up the first thread in line waiting for this lock.
- #
- def signal
- @monitor.mon_check_owner
- @cond.signal
- end
-
- #
- # Wakes up all threads waiting for this lock.
- #
- def broadcast
- @monitor.mon_check_owner
- @cond.broadcast
- end
-
- private
-
- def initialize(monitor) # :nodoc:
- @monitor = monitor
- @cond = Thread::ConditionVariable.new
- end
- end
-
- def self.extend_object(obj) # :nodoc:
- super(obj)
- obj.__send__(:mon_initialize)
- end
-
- #
- # Attempts to enter exclusive section. Returns +false+ if lock fails.
- #
- def mon_try_enter
- @mon_data.try_enter
- end
- # For backward compatibility
- alias try_mon_enter mon_try_enter
-
- #
- # Enters exclusive section.
- #
- def mon_enter
- @mon_data.enter
- end
-
- #
- # Leaves exclusive section.
- #
- def mon_exit
- mon_check_owner
- @mon_data.exit
- end
-
- #
- # Returns true if this monitor is locked by any thread
- #
- def mon_locked?
- @mon_data.mon_locked?
- end
-
- #
- # Returns true if this monitor is locked by current thread.
- #
- def mon_owned?
- @mon_data.mon_owned?
- end
-
- #
- # Enters exclusive section and executes the block. Leaves the exclusive
- # section automatically when the block exits. See example under
- # +MonitorMixin+.
- #
- def mon_synchronize(&b)
- @mon_data.synchronize(&b)
- end
- alias synchronize mon_synchronize
-
- #
- # Creates a new MonitorMixin::ConditionVariable associated with the
- # Monitor object.
- #
- def new_cond
- unless defined?(@mon_data)
- mon_initialize
- @mon_initialized_by_new_cond = true
- end
- return ConditionVariable.new(@mon_data)
- end
-
- private
-
- # Use <tt>extend MonitorMixin</tt> or <tt>include MonitorMixin</tt> instead
- # of this constructor. Have look at the examples above to understand how to
- # use this module.
- def initialize(...)
- super
- mon_initialize
- end
-
- # Initializes the MonitorMixin after being included in a class or when an
- # object has been extended with the MonitorMixin
- def mon_initialize
- if defined?(@mon_data)
- if defined?(@mon_initialized_by_new_cond)
- return # already initialized.
- elsif @mon_data_owner_object_id == self.object_id
- raise ThreadError, "already initialized"
- end
- end
- @mon_data = ::Monitor.new
- @mon_data_owner_object_id = self.object_id
- end
-
- # Ensures that the MonitorMixin is owned by the current thread,
- # otherwise raises an exception.
- def mon_check_owner
- @mon_data.mon_check_owner
- end
-end
-
-# Use the Monitor class when you want to have a lock object for blocks with
-# mutual exclusion.
-#
-# require 'monitor'
-#
-# lock = Monitor.new
-# lock.synchronize do
-# # exclusive access
-# end
-#
-class Monitor
- #
- # Creates a new MonitorMixin::ConditionVariable associated with the
- # Monitor object.
- #
- def new_cond
- ::MonitorMixin::ConditionVariable.new(self)
- end
-
- # for compatibility
- alias try_mon_enter try_enter
- alias mon_try_enter try_enter
- alias mon_enter enter
- alias mon_exit exit
- alias mon_synchronize synchronize
-end
-
-# Documentation comments:
-# - All documentation comes from Nutshell.
-# - MonitorMixin.new_cond appears in the example, but is not documented in
-# Nutshell.
-# - All the internals (internal modules Accessible and Initializable, class
-# ConditionVariable) appear in RDoc. It might be good to hide them, by
-# making them private, or marking them :nodoc:, etc.
-# - RDoc doesn't recognise aliases, so we have mon_synchronize documented, but
-# not synchronize.
-# - mon_owner is in Nutshell, but appears as an accessor in a separate module
-# here, so is hard/impossible to RDoc. Some other useful accessors
-# (mon_count and some queue stuff) are also in this module, and don't appear
-# directly in the RDoc output.
-# - in short, it may be worth changing the code layout in this file to make the
-# documentation easier
diff --git a/ext/monitor/monitor.c b/ext/monitor/monitor.c
deleted file mode 100644
index 819c6e7699..0000000000
--- a/ext/monitor/monitor.c
+++ /dev/null
@@ -1,255 +0,0 @@
-#include "ruby/ruby.h"
-
-/* Thread::Monitor */
-
-struct rb_monitor {
- long count;
- const VALUE owner;
- const VALUE mutex;
-};
-
-static void
-monitor_mark(void *ptr)
-{
- struct rb_monitor *mc = ptr;
- rb_gc_mark(mc->owner);
- rb_gc_mark(mc->mutex);
-}
-
-static size_t
-monitor_memsize(const void *ptr)
-{
- return sizeof(struct rb_monitor);
-}
-
-static const rb_data_type_t monitor_data_type = {
- "monitor",
- {monitor_mark, RUBY_TYPED_DEFAULT_FREE, monitor_memsize,},
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY|RUBY_TYPED_WB_PROTECTED
-};
-
-static VALUE
-monitor_alloc(VALUE klass)
-{
- struct rb_monitor *mc;
- VALUE obj;
-
- obj = TypedData_Make_Struct(klass, struct rb_monitor, &monitor_data_type, mc);
- RB_OBJ_WRITE(obj, &mc->mutex, rb_mutex_new());
- RB_OBJ_WRITE(obj, &mc->owner, Qnil);
- mc->count = 0;
-
- return obj;
-}
-
-static struct rb_monitor *
-monitor_ptr(VALUE monitor)
-{
- struct rb_monitor *mc;
- TypedData_Get_Struct(monitor, struct rb_monitor, &monitor_data_type, mc);
- return mc;
-}
-
-static int
-mc_owner_p(struct rb_monitor *mc)
-{
- return mc->owner == rb_fiber_current();
-}
-
-/*
- * call-seq:
- * try_enter -> true or false
- *
- * Attempts to enter exclusive section. Returns +false+ if lock fails.
- */
-static VALUE
-monitor_try_enter(VALUE monitor)
-{
- struct rb_monitor *mc = monitor_ptr(monitor);
-
- if (!mc_owner_p(mc)) {
- if (!rb_mutex_trylock(mc->mutex)) {
- return Qfalse;
- }
- RB_OBJ_WRITE(monitor, &mc->owner, rb_fiber_current());
- mc->count = 0;
- }
- mc->count += 1;
- return Qtrue;
-}
-
-/*
- * call-seq:
- * enter -> nil
- *
- * Enters exclusive section.
- */
-static VALUE
-monitor_enter(VALUE monitor)
-{
- struct rb_monitor *mc = monitor_ptr(monitor);
- if (!mc_owner_p(mc)) {
- rb_mutex_lock(mc->mutex);
- RB_OBJ_WRITE(monitor, &mc->owner, rb_fiber_current());
- mc->count = 0;
- }
- mc->count++;
- return Qnil;
-}
-
-/* :nodoc: */
-static VALUE
-monitor_check_owner(VALUE monitor)
-{
- struct rb_monitor *mc = monitor_ptr(monitor);
- if (!mc_owner_p(mc)) {
- rb_raise(rb_eThreadError, "current fiber not owner");
- }
- return Qnil;
-}
-
-/*
- * call-seq:
- * exit -> nil
- *
- * Leaves exclusive section.
- */
-static VALUE
-monitor_exit(VALUE monitor)
-{
- monitor_check_owner(monitor);
-
- struct rb_monitor *mc = monitor_ptr(monitor);
-
- if (mc->count <= 0) rb_bug("monitor_exit: count:%d", (int)mc->count);
- mc->count--;
-
- if (mc->count == 0) {
- RB_OBJ_WRITE(monitor, &mc->owner, Qnil);
- rb_mutex_unlock(mc->mutex);
- }
- return Qnil;
-}
-
-/* :nodoc: */
-static VALUE
-monitor_locked_p(VALUE monitor)
-{
- struct rb_monitor *mc = monitor_ptr(monitor);
- return rb_mutex_locked_p(mc->mutex);
-}
-
-/* :nodoc: */
-static VALUE
-monitor_owned_p(VALUE monitor)
-{
- struct rb_monitor *mc = monitor_ptr(monitor);
- return (rb_mutex_locked_p(mc->mutex) && mc_owner_p(mc)) ? Qtrue : Qfalse;
-}
-
-static VALUE
-monitor_exit_for_cond(VALUE monitor)
-{
- struct rb_monitor *mc = monitor_ptr(monitor);
- long cnt = mc->count;
- RB_OBJ_WRITE(monitor, &mc->owner, Qnil);
- mc->count = 0;
- return LONG2NUM(cnt);
-}
-
-struct wait_for_cond_data {
- VALUE monitor;
- VALUE cond;
- VALUE timeout;
- VALUE count;
-};
-
-static VALUE
-monitor_wait_for_cond_body(VALUE v)
-{
- struct wait_for_cond_data *data = (struct wait_for_cond_data *)v;
- struct rb_monitor *mc = monitor_ptr(data->monitor);
- // cond.wait(monitor.mutex, timeout)
- VALUE signaled = rb_funcall(data->cond, rb_intern("wait"), 2, mc->mutex, data->timeout);
- return RTEST(signaled) ? Qtrue : Qfalse;
-}
-
-static VALUE
-monitor_enter_for_cond(VALUE v)
-{
- // assert(rb_mutex_owned_p(mc->mutex) == Qtrue)
- // but rb_mutex_owned_p is not exported...
-
- struct wait_for_cond_data *data = (struct wait_for_cond_data *)v;
- struct rb_monitor *mc = monitor_ptr(data->monitor);
- RB_OBJ_WRITE(data->monitor, &mc->owner, rb_fiber_current());
- mc->count = NUM2LONG(data->count);
- return Qnil;
-}
-
-/* :nodoc: */
-static VALUE
-monitor_wait_for_cond(VALUE monitor, VALUE cond, VALUE timeout)
-{
- VALUE count = monitor_exit_for_cond(monitor);
- struct wait_for_cond_data data = {
- monitor,
- cond,
- timeout,
- count,
- };
-
- return rb_ensure(monitor_wait_for_cond_body, (VALUE)&data,
- monitor_enter_for_cond, (VALUE)&data);
-}
-
-static VALUE
-monitor_sync_body(VALUE monitor)
-{
- return rb_yield_values(0);
-}
-
-static VALUE
-monitor_sync_ensure(VALUE monitor)
-{
- return monitor_exit(monitor);
-}
-
-/*
- * call-seq:
- * synchronize { } -> result of the block
- *
- * Enters exclusive section and executes the block. Leaves the exclusive
- * section automatically when the block exits. See example under
- * +MonitorMixin+.
- */
-static VALUE
-monitor_synchronize(VALUE monitor)
-{
- monitor_enter(monitor);
- return rb_ensure(monitor_sync_body, monitor, monitor_sync_ensure, monitor);
-}
-
-void
-Init_monitor(void)
-{
-#ifdef HAVE_RB_EXT_RACTOR_SAFE
- rb_ext_ractor_safe(true);
-#endif
-
- VALUE rb_cMonitor = rb_define_class("Monitor", rb_cObject);
- rb_define_alloc_func(rb_cMonitor, monitor_alloc);
-
- rb_define_method(rb_cMonitor, "try_enter", monitor_try_enter, 0);
- rb_define_method(rb_cMonitor, "enter", monitor_enter, 0);
- rb_define_method(rb_cMonitor, "exit", monitor_exit, 0);
- rb_define_method(rb_cMonitor, "synchronize", monitor_synchronize, 0);
-
- /* internal methods for MonitorMixin */
- rb_define_method(rb_cMonitor, "mon_locked?", monitor_locked_p, 0);
- rb_define_method(rb_cMonitor, "mon_check_owner", monitor_check_owner, 0);
- rb_define_method(rb_cMonitor, "mon_owned?", monitor_owned_p, 0);
-
- /* internal methods for MonitorMixin::ConditionVariable */
- rb_define_method(rb_cMonitor, "wait_for_cond", monitor_wait_for_cond, 2);
-}
diff --git a/ext/objspace/depend b/ext/objspace/depend
index 3c11511575..d9dfc0c42b 100644
--- a/ext/objspace/depend
+++ b/ext/objspace/depend
@@ -182,10 +182,10 @@ object_tracing.o: $(top_srcdir)/id_table.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/box.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/namespace.h
object_tracing.o: $(top_srcdir)/internal/sanitizers.h
object_tracing.o: $(top_srcdir)/internal/serial.h
object_tracing.o: $(top_srcdir)/internal/set_table.h
@@ -391,16 +391,17 @@ objspace.o: $(top_srcdir)/id_table.h
objspace.o: $(top_srcdir)/internal.h
objspace.o: $(top_srcdir)/internal/array.h
objspace.o: $(top_srcdir)/internal/basic_operators.h
+objspace.o: $(top_srcdir)/internal/box.h
objspace.o: $(top_srcdir)/internal/class.h
objspace.o: $(top_srcdir)/internal/compilers.h
objspace.o: $(top_srcdir)/internal/gc.h
objspace.o: $(top_srcdir)/internal/hash.h
objspace.o: $(top_srcdir)/internal/imemo.h
-objspace.o: $(top_srcdir)/internal/namespace.h
objspace.o: $(top_srcdir)/internal/sanitizers.h
objspace.o: $(top_srcdir)/internal/serial.h
objspace.o: $(top_srcdir)/internal/set_table.h
objspace.o: $(top_srcdir)/internal/static_assert.h
+objspace.o: $(top_srcdir)/internal/struct.h
objspace.o: $(top_srcdir)/internal/variable.h
objspace.o: $(top_srcdir)/internal/vm.h
objspace.o: $(top_srcdir)/internal/warnings.h
@@ -601,22 +602,24 @@ 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)/encindex.h
objspace_dump.o: $(top_srcdir)/id_table.h
objspace_dump.o: $(top_srcdir)/internal.h
objspace_dump.o: $(top_srcdir)/internal/array.h
objspace_dump.o: $(top_srcdir)/internal/basic_operators.h
+objspace_dump.o: $(top_srcdir)/internal/box.h
objspace_dump.o: $(top_srcdir)/internal/class.h
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/namespace.h
objspace_dump.o: $(top_srcdir)/internal/sanitizers.h
objspace_dump.o: $(top_srcdir)/internal/serial.h
objspace_dump.o: $(top_srcdir)/internal/set_table.h
objspace_dump.o: $(top_srcdir)/internal/static_assert.h
objspace_dump.o: $(top_srcdir)/internal/string.h
+objspace_dump.o: $(top_srcdir)/internal/struct.h
objspace_dump.o: $(top_srcdir)/internal/variable.h
objspace_dump.o: $(top_srcdir)/internal/vm.h
objspace_dump.o: $(top_srcdir)/internal/warnings.h
diff --git a/ext/objspace/object_tracing.c b/ext/objspace/object_tracing.c
index 0156642ef2..74d793a6e2 100644
--- a/ext/objspace/object_tracing.c
+++ b/ext/objspace/object_tracing.c
@@ -22,7 +22,6 @@ struct traceobj_arg {
int running;
int keep_remains;
VALUE newobj_trace;
- VALUE freeobj_trace;
st_table *object_table; /* obj (VALUE) -> allocation_info */
st_table *str_table; /* cstr -> refcount */
struct traceobj_arg *prev_traceobj_arg;
@@ -91,18 +90,16 @@ newobj_i(VALUE tpval, void *data)
VALUE klass = rb_tracearg_defined_class(tparg);
struct allocation_info *info;
const char *path_cstr = RTEST(path) ? make_unique_str(arg->str_table, RSTRING_PTR(path), RSTRING_LEN(path)) : 0;
- VALUE class_path = (RTEST(klass) && !OBJ_FROZEN(klass)) ? rb_class_path_cached(klass) : Qnil;
+ VALUE class_path = (RTEST(klass) && !OBJ_FROZEN(klass)) ? rb_mod_name(klass) : Qnil;
const char *class_path_cstr = RTEST(class_path) ? make_unique_str(arg->str_table, RSTRING_PTR(class_path), RSTRING_LEN(class_path)) : 0;
st_data_t v;
if (st_lookup(arg->object_table, (st_data_t)obj, &v)) {
+ /* keep_remains kept this slot's entry after its object was freed. The
+ * allocator has now reused that address, so recycle the dead entry's
+ * info. A living entry here would mean two live objects at one address. */
info = (struct allocation_info *)v;
- if (arg->keep_remains) {
- if (info->living) {
- /* do nothing. there is possibility to keep living if FREEOBJ events while suppressing tracing */
- }
- }
- /* reuse info */
+ assert(!info->living);
delete_unique_str(arg->str_table, info->path);
delete_unique_str(arg->str_table, info->class_path);
}
@@ -121,37 +118,6 @@ newobj_i(VALUE tpval, void *data)
st_insert(arg->object_table, (st_data_t)obj, (st_data_t)info);
}
-static void
-freeobj_i(VALUE tpval, void *data)
-{
- struct traceobj_arg *arg = (struct traceobj_arg *)data;
- rb_trace_arg_t *tparg = rb_tracearg_from_tracepoint(tpval);
- st_data_t obj = (st_data_t)rb_tracearg_object(tparg);
- st_data_t v;
- struct allocation_info *info;
-
- /* Modifying the st table can cause allocations, which can trigger GC.
- * Since freeobj_i is called during GC, it must not trigger another GC. */
- VALUE gc_disabled = rb_gc_disable_no_rest();
-
- if (arg->keep_remains) {
- if (st_lookup(arg->object_table, obj, &v)) {
- info = (struct allocation_info *)v;
- info->living = 0;
- }
- }
- else {
- if (st_delete(arg->object_table, &obj, &v)) {
- info = (struct allocation_info *)v;
- delete_unique_str(arg->str_table, info->path);
- delete_unique_str(arg->str_table, info->class_path);
- ruby_xfree(info);
- }
- }
-
- if (gc_disabled == Qfalse) rb_gc_enable();
-}
-
static int
free_keys_i(st_data_t key, st_data_t value, st_data_t data)
{
@@ -171,7 +137,6 @@ allocation_info_tracer_mark(void *ptr)
{
struct traceobj_arg *trace_arg = (struct traceobj_arg *)ptr;
rb_gc_mark(trace_arg->newobj_trace);
- rb_gc_mark(trace_arg->freeobj_trace);
}
static void
@@ -198,12 +163,46 @@ allocation_info_tracer_memsize(const void *ptr)
}
static int
+allocation_info_tracer_weak_reference_i(st_data_t key, st_data_t value, st_data_t data)
+{
+ struct traceobj_arg *arg = (struct traceobj_arg *)data;
+ struct allocation_info *info = (struct allocation_info *)value;
+
+ if (rb_gc_handle_weak_references_alive_p((VALUE)key)) {
+ return ST_CONTINUE;
+ }
+
+ /* Object was collected. keep_remains keeps the dead entry for reporting. */
+ if (arg->keep_remains) {
+ info->living = 0;
+ return ST_CONTINUE;
+ }
+ else {
+ delete_unique_str(arg->str_table, info->path);
+ delete_unique_str(arg->str_table, info->class_path);
+ ruby_xfree(info);
+ return ST_DELETE;
+ }
+}
+
+static void
+allocation_info_tracer_weak_reference(void *ptr)
+{
+ struct traceobj_arg *arg = (struct traceobj_arg *)ptr;
+
+ st_foreach(arg->object_table, allocation_info_tracer_weak_reference_i, (st_data_t)arg);
+}
+
+static int
allocation_info_tracer_compact_update_object_table_i(st_data_t key, st_data_t value, st_data_t data)
{
st_table *table = (st_table *)data;
+ struct allocation_info *info = (struct allocation_info *)value;
- if (!rb_gc_pointer_to_heap_p(key)) {
- return ST_DELETE;
+ /* In keep_remains mode the table keeps entries for freed objects. Their keys
+ * are dangling, so skip them instead of passing them to rb_gc_location. */
+ if (!info->living) {
+ return ST_CONTINUE;
}
if (key != rb_gc_location(key)) {
@@ -240,6 +239,7 @@ static const rb_data_type_t allocation_info_tracer_type = {
allocation_info_tracer_free, /* Never called because global */
allocation_info_tracer_memsize,
allocation_info_tracer_compact,
+ allocation_info_tracer_weak_reference,
},
0, 0, RUBY_TYPED_FREE_IMMEDIATELY
};
@@ -258,9 +258,10 @@ get_traceobj_arg(void)
tmp_trace_arg->running = 0;
tmp_trace_arg->keep_remains = tmp_keep_remains;
tmp_trace_arg->newobj_trace = 0;
- tmp_trace_arg->freeobj_trace = 0;
tmp_trace_arg->object_table = st_init_numtable();
tmp_trace_arg->str_table = st_init_strtable();
+
+ rb_gc_declare_weak_references(obj);
}
return tmp_trace_arg;
}
@@ -282,10 +283,8 @@ trace_object_allocations_start(VALUE self)
else {
if (arg->newobj_trace == 0) {
arg->newobj_trace = rb_tracepoint_new(0, RUBY_INTERNAL_EVENT_NEWOBJ, newobj_i, arg);
- arg->freeobj_trace = rb_tracepoint_new(0, RUBY_INTERNAL_EVENT_FREEOBJ, freeobj_i, arg);
}
rb_tracepoint_enable(arg->newobj_trace);
- rb_tracepoint_enable(arg->freeobj_trace);
}
return Qnil;
@@ -313,9 +312,6 @@ trace_object_allocations_stop(VALUE self)
if (arg->newobj_trace != 0) {
rb_tracepoint_disable(arg->newobj_trace);
}
- if (arg->freeobj_trace != 0) {
- rb_tracepoint_disable(arg->freeobj_trace);
- }
}
return Qnil;
@@ -411,6 +407,13 @@ object_allocations_reporter(FILE *out, void *ptr)
fprintf(out, "== object_allocations_reporter: END\n");
}
+/*
+ * call-seq: trace_object_allocations_debug_start
+ *
+ * Starts tracing object allocations 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.
+ */
static VALUE
trace_object_allocations_debug_start(VALUE self)
{
diff --git a/ext/objspace/objspace.c b/ext/objspace/objspace.c
index 8b3045fda3..20eab820a1 100644
--- a/ext/objspace/objspace.c
+++ b/ext/objspace/objspace.c
@@ -30,19 +30,33 @@
/*
* call-seq:
- * ObjectSpace.memsize_of(obj) -> Integer
+ * ObjectSpace.memsize_of(obj) -> integer
*
- * Return consuming memory size of obj in bytes.
+ * Returns the amount of memory in bytes consumed by +obj+.
*
- * Note that the return size is incomplete. You need to deal with this
- * information as only a *HINT*. Especially, the size of +T_DATA+ may not be
- * correct.
+ * The returned size includes the slot that +obj+ occupies plus any memory
+ * that +obj+ allocates outside of that slot, such as the storage backing a
+ * large String, Array, or Hash:
*
- * This method is only expected to work with CRuby.
+ * require 'objspace'
+ *
+ * ObjectSpace.memsize_of("small") # => 40
+ * ObjectSpace.memsize_of("a" * 1000) # => 1041
+ * ObjectSpace.memsize_of([1, 2, 3]) # => 40
+ * ObjectSpace.memsize_of(Array.new(100)) # => 840
+ *
+ * Special constants such as +true+, +false+, +nil+, small integers, and some
+ * symbols do not occupy a slot, so their size is reported as +0+:
+ *
+ * ObjectSpace.memsize_of(true) # => 0
+ * ObjectSpace.memsize_of(42) # => 0
*
- * From Ruby 3.2 with Variable Width Allocation, it returns the actual slot
- * size used plus any additional memory allocated outside the slot (such
- * as external strings, arrays, or hash tables).
+ * The returned size is only a hint and may be an underestimate, since it does
+ * not account for all of the memory that +obj+ references. In particular, the
+ * size of a +T_DATA+ object (an object implemented in C, such as one defined
+ * by a C extension) may not be reported correctly.
+ *
+ * This method is only expected to work with CRuby.
*/
static VALUE
@@ -108,28 +122,24 @@ each_object_with_flags(each_obj_with_flags cb, void *ctx)
/*
* call-seq:
- * ObjectSpace.memsize_of_all([klass]) -> Integer
- *
- * Return consuming memory size of all living objects in bytes.
+ * ObjectSpace.memsize_of_all(klass = nil) -> integer
*
- * If +klass+ (should be Class object) is given, return the total memory size
- * of instances of the given class.
+ * Returns the total memory size of all living objects in bytes.
*
- * Note that the returned size is incomplete. You need to deal with this
- * information as only a *HINT*. Especially, the size of +T_DATA+ may not be
- * correct.
+ * ObjectSpace.memsize_of_all # => 12502001
*
- * Note that this method does *NOT* return total malloc'ed memory size.
+ * If +klass+ is given (which must be a Class or Module), returns the total
+ * memory size of objects whose class is, or is a subclass, of +klass+.
*
- * This method can be defined by the following Ruby code:
+ * class MyClass; end
+ * ObjectSpace.memsize_of_all(MyClass) # => 0
+ * o = MyClass.new
+ * ObjectSpace.memsize_of_all(MyClass) # => 40
*
- * def memsize_of_all klass = false
- * total = 0
- * ObjectSpace.each_object{|e|
- * total += ObjectSpace.memsize_of(e) if klass == false || e.kind_of?(klass)
- * }
- * total
- * end
+ * Note that the value returned may be an underestimate of the actual amount
+ * of memory used. Therefore, the value returned should only be used as a hint,
+ * rather than a source of truth. In particular, the size of +T_DATA+ objects may
+ * not be correct.
*
* This method is only expected to work with C Ruby.
*/
@@ -141,6 +151,7 @@ memsize_of_all_m(int argc, VALUE *argv, VALUE self)
if (argc > 0) {
rb_scan_args(argc, argv, "01", &data.klass);
+ if (!NIL_P(data.klass)) rb_obj_is_kind_of(Qnil, data.klass);
}
each_object_with_flags(total_i, &data);
@@ -224,23 +235,26 @@ type2sym(enum ruby_value_type i)
/*
* call-seq:
- * ObjectSpace.count_objects_size([result_hash]) -> hash
+ * ObjectSpace.count_objects_size(result_hash = {}) -> result_hash
*
* Counts objects size (in bytes) for each type.
*
- * Note that this information is incomplete. You need to deal with
- * this information as only a *HINT*. Especially, total size of
- * T_DATA may be wrong.
+ * Note that the returned size may not be accurate, so it should only
+ * be used as a hint. Specifically, the size for +T_DATA+ may be
+ * inaccurate because these are custom objects defined in Ruby and
+ * native extensions and so they may not accurately report their
+ * memory size.
*
- * It returns a hash as:
- * {:TOTAL=>1461154, :T_CLASS=>158280, :T_MODULE=>20672, :T_STRING=>527249, ...}
+ * It returns a hash that looks like:
*
- * If the optional argument, result_hash, is given,
- * it is overwritten and returned.
- * This is intended to avoid probe effect.
+ * {TOTAL: 1461154, T_CLASS: 158280, T_MODULE: 20672, T_STRING: 527249, ...}
+ *
+ * The contents of the returned hash are implementation specific and
+ * may be changed in future versions without notice.
*
- * The contents of the returned hash is implementation defined.
- * It may be changed in future.
+ * If the optional argument, +result_hash+, is given,
+ * it is overwritten and returned.
+ * This is intended to avoid the probe effect.
*
* This method is only expected to work with C Ruby.
*/
@@ -295,28 +309,27 @@ size_t rb_sym_immortal_count(void);
/*
* call-seq:
- * ObjectSpace.count_symbols([result_hash]) -> hash
+ * ObjectSpace.count_symbols(result_hash = nil) -> hash
*
- * Counts symbols for each Symbol type.
+ * Returns a hash containing the number of objects for each Symbol type.
*
- * This method is only for MRI developers interested in performance and memory
- * usage of Ruby programs.
+ * The types of Symbols are the following:
*
- * If the optional argument, result_hash, is given, it is overwritten and
- * returned. This is intended to avoid probe effect.
+ * - +mortal_dynamic_symbol+: Symbols that are garbage collectable.
+ * - +immortal_dynamic_symbol+: Symbols that are objects allocated from the
+ * garbage collector, but are not garbage collectable.
+ * - +immortal_static_symbol+: Symbols that are not allocated from the
+ * garbage collector, and are thus not garbage collectable.
+ * - +immortal_symbol+: the sum of +immortal_dynamic_symbol+ and +immortal_static_symbol+.
*
- * Note:
- * The contents of the returned hash is implementation defined.
- * It may be changed in future.
+ * If the optional argument +result_hash+ is given, it is overwritten and
+ * returned. This is intended to avoid the probe effect.
*
- * This method is only expected to work with C Ruby.
+ * This method is intended for developers interested in performance and memory
+ * usage of Ruby programs. The contents of the returned hash is implementation
+ * specific and may change in the future.
*
- * On this version of MRI, they have 3 types of Symbols (and 1 total counts).
- *
- * * mortal_dynamic_symbol: GC target symbols (collected by GC)
- * * immortal_dynamic_symbol: Immortal symbols promoted from dynamic symbols (do not collected by GC)
- * * immortal_static_symbol: Immortal symbols (do not collected by GC)
- * * immortal_symbol: total immortal symbols (immortal_dynamic_symbol+immortal_static_symbol)
+ * This method is only expected to work with C Ruby.
*/
static VALUE
@@ -336,35 +349,6 @@ count_symbols(int argc, VALUE *argv, VALUE os)
return hash;
}
-/*
- * call-seq:
- * ObjectSpace.count_nodes([result_hash]) -> hash
- *
- * Counts nodes for each node type.
- *
- * This method is only for MRI developers interested in performance and memory
- * usage of Ruby programs.
- *
- * It returns a hash as:
- *
- * {:NODE_METHOD=>2027, :NODE_FBODY=>1927, :NODE_CFUNC=>1798, ...}
- *
- * If the optional argument, result_hash, is given, it is overwritten and
- * returned. This is intended to avoid probe effect.
- *
- * Note:
- * The contents of the returned hash is implementation defined.
- * It may be changed in future.
- *
- * This method is only expected to work with C Ruby.
- */
-
-static VALUE
-count_nodes(int argc, VALUE *argv, VALUE os)
-{
- return setup_hash(argc, argv);
-}
-
static void
cto_i(VALUE v, void *data)
{
@@ -394,32 +378,22 @@ cto_i(VALUE v, void *data)
/*
* call-seq:
- * ObjectSpace.count_tdata_objects([result_hash]) -> hash
- *
- * Counts objects for each +T_DATA+ type.
- *
- * This method is only for MRI developers interested in performance and memory
- * usage of Ruby programs.
- *
- * It returns a hash as:
+ * ObjectSpace.count_tdata_objects(result_hash = nil) -> hash
*
- * {RubyVM::InstructionSequence=>504, :parser=>5, :barrier=>6,
- * :mutex=>6, Proc=>60, RubyVM::Env=>57, Mutex=>1, Encoding=>99,
- * ThreadGroup=>1, Binding=>1, Thread=>1, RubyVM=>1, :iseq=>1,
- * Random=>1, ARGF.class=>1, Data=>1, :autoload=>3, Time=>2}
- * # T_DATA objects existing at startup on r32276.
+ * Returns a hash containing the number of objects for each +T_DATA+ type.
+ * The keys are Class objects when the +T_DATA+ object has an associated class,
+ * or Symbol objects of the name defined in the +rb_data_type_struct+ for internal
+ * +T_DATA+ objects.
*
- * If the optional argument, result_hash, is given, it is overwritten and
- * returned. This is intended to avoid probe effect.
+ * ObjectSpace.count_tdata_objects
+ * # => {RBS::Location => 39255, marshal_compat_table: 1, Encoding => 103, mutex: 1, ... }
*
- * The contents of the returned hash is implementation specific and may change
- * in the future.
+ * If the optional argument +result_hash+ is given, it is overwritten and
+ * returned. This is intended to avoid the probe effect.
*
- * In this version, keys are Class object or Symbol object.
- *
- * If object is kind of normal (accessible) object, the key is Class object.
- * If object is not a kind of normal (internal) object, the key is symbol
- * name, registered by rb_data_type_struct.
+ * This method is intended for developers interested in performance and memory
+ * usage of Ruby programs. The contents of the returned hash is implementation
+ * specific and may change in the future.
*
* This method is only expected to work with C Ruby.
*/
@@ -458,28 +432,22 @@ count_imemo_objects_i(VALUE v, void *data)
/*
* call-seq:
- * ObjectSpace.count_imemo_objects([result_hash]) -> hash
- *
- * Counts objects for each +T_IMEMO+ type.
- *
- * This method is only for MRI developers interested in performance and memory
- * usage of Ruby programs.
+ * ObjectSpace.count_imemo_objects(result_hash = nil) -> hash
*
- * It returns a hash as:
+ * Returns a hash containing the number of objects for each +T_IMEMO+ type.
+ * The keys are Symbol objects of the +T_IMEMO+ type name.
+ * +T_IMEMO+ objects are Ruby internal objects that are not visible to Ruby
+ * programs.
*
- * {:imemo_ifunc=>8,
- * :imemo_svar=>7,
- * :imemo_cref=>509,
- * :imemo_memo=>1,
- * :imemo_throw_data=>1}
+ * ObjectSpace.count_imemo_objects
+ * # => {imemo_callcache: 5482, imemo_constcache: 1258, imemo_ment: 13906, ... }
*
- * If the optional argument, result_hash, is given, it is overwritten and
- * returned. This is intended to avoid probe effect.
+ * If the optional argument +result_hash+ is given, it is overwritten and
+ * returned. This is intended to avoid the probe effect.
*
- * The contents of the returned hash is implementation specific and may change
- * in the future.
- *
- * In this version, keys are symbol objects.
+ * This method is intended for developers interested in performance and memory
+ * usage of Ruby programs. The contents of the returned hash is implementation
+ * specific and may change in the future.
*
* This method is only expected to work with C Ruby.
*/
@@ -500,10 +468,13 @@ count_imemo_objects(int argc, VALUE *argv, VALUE self)
INIT_IMEMO_TYPE_ID(imemo_ment);
INIT_IMEMO_TYPE_ID(imemo_iseq);
INIT_IMEMO_TYPE_ID(imemo_tmpbuf);
+ INIT_IMEMO_TYPE_ID(imemo_cvar_entry);
INIT_IMEMO_TYPE_ID(imemo_callinfo);
INIT_IMEMO_TYPE_ID(imemo_callcache);
INIT_IMEMO_TYPE_ID(imemo_constcache);
INIT_IMEMO_TYPE_ID(imemo_fields);
+ INIT_IMEMO_TYPE_ID(imemo_subclasses);
+ INIT_IMEMO_TYPE_ID(imemo_cdhash);
#undef INIT_IMEMO_TYPE_ID
}
@@ -602,42 +573,37 @@ collect_values(st_data_t key, st_data_t value, st_data_t data)
* call-seq:
* ObjectSpace.reachable_objects_from(obj) -> array or nil
*
- * [MRI specific feature] Return all reachable objects from `obj'.
- *
- * This method returns all reachable objects from `obj'.
+ * Returns all reachable objects from +obj+ as an array:
*
- * If `obj' has two or more references to the same object `x', then returned
- * array only includes one `x' object.
+ * ObjectSpace.reachable_objects_from(['a', 'b', 'c'])
+ * #=> [Array, 'a', 'b', 'c']
*
- * If `obj' is a non-markable (non-heap management) object such as true,
- * false, nil, symbols and Fixnums (and Flonum) then it simply returns nil.
+ * The returned array is deduplicated, meaning that if +obj+ refers
+ * to another object more than once, it will only be added to the array
+ * once:
*
- * If `obj' has references to an internal object, then it returns instances of
- * ObjectSpace::InternalObjectWrapper class. This object contains a reference
- * to an internal object and you can check the type of internal object with
- * `type' method.
+ * ObjectSpace.reachable_objects_from([v = 'a', v, v])
+ * #=> [Array, 'a']
*
- * If `obj' is instance of ObjectSpace::InternalObjectWrapper class, then this
- * method returns all reachable object from an internal object, which is
- * pointed by `obj'.
+ * Returns +nil+ if +obj+ is not a markable object (i.e. non-heap
+ * managed) object. Non-markable objects include +true+, +false+,
+ * +nil+, certain symbols, small integers, and floats:
*
- * With this method, you can find memory leaks.
- *
- * This method is only expected to work with C Ruby.
+ * ObjectSpace.reachable_objects_from(1)
+ * #=> nil
*
- * Example:
- * ObjectSpace.reachable_objects_from(['a', 'b', 'c'])
- * #=> [Array, 'a', 'b', 'c']
+ * All references to internal objects in the returned array are wrapped
+ * using ObjectSpace::InternalObjectWrapper objects. This object contains
+ * a reference to the internal object and the type of the object can
+ * be accessed using the ObjectSpace::InternalObjectWrapper#type method.
*
- * ObjectSpace.reachable_objects_from(['a', 'a', 'a'])
- * #=> [Array, 'a', 'a', 'a'] # all 'a' strings have different object id
+ * If +obj+ is instance of ObjectSpace::InternalObjectWrapper, then this
+ * method returns all reachable object from the internal object.
*
- * ObjectSpace.reachable_objects_from([v = 'a', v, v])
- * #=> [Array, 'a']
- *
- * ObjectSpace.reachable_objects_from(1)
- * #=> nil # 1 is not markable (heap managed) object
+ * This method is useful for debugging purposes, such as finding
+ * memory leaks.
*
+ * This method is only expected to work with C Ruby.
*/
static VALUE
@@ -713,7 +679,30 @@ collect_values_of_values(VALUE category, VALUE category_objects, VALUE categorie
* call-seq:
* ObjectSpace.reachable_objects_from_root -> hash
*
- * [MRI specific feature] Return all reachable objects from root.
+ * Returns a hash of objects directly reachable from the VM roots,
+ * grouped by the root that reaches them.
+ *
+ * The roots are the entry points the garbage collector starts from when it
+ * marks live objects, such as the virtual machine and the global variable
+ * table. The keys of the returned hash are strings naming each root, and each
+ * value is an array of the objects reachable from that root:
+ *
+ * require 'objspace'
+ *
+ * reachable = ObjectSpace.reachable_objects_from_root
+ * reachable.keys # => ["vm", "global_tbl", "machine_context", "global_symbols"]
+ * reachable.values.first # => [#<Ractor:#1 running>, ...]
+ *
+ * The returned hash compares its keys by identity, so it cannot be indexed
+ * with a string literal; iterate over it (or over its #values) instead.
+ *
+ * Any reference to an internal object is wrapped in an
+ * ObjectSpace::InternalObjectWrapper object.
+ *
+ * This method is useful for debugging the object graph, for example when
+ * tracking down the cause of a memory leak.
+ *
+ * This method is only expected to work with C Ruby.
*/
static VALUE
reachable_objects_from_root(VALUE self)
@@ -745,12 +734,28 @@ wrap_klass_iow(VALUE klass)
/*
* call-seq:
- * ObjectSpace.internal_class_of(obj) -> Class or Module
+ * ObjectSpace.internal_class_of(obj) -> class or module
*
- * [MRI specific feature] Return internal class of obj.
- * obj can be an instance of InternalObjectWrapper.
+ * Returns the real class of +obj+, which may differ from the class returned
+ * by Object#class.
+ *
+ * Ruby inserts hidden classes into an object's ancestry, such as a singleton
+ * class or an included module's iclass. Object#class skips over these, but
+ * this method returns the first one, including any hidden class:
+ *
+ * require 'objspace'
+ *
+ * s = "x"
+ * def s.foo; end # gives +s+ a singleton class
+ * s.class # => String
+ * ObjectSpace.internal_class_of(s) # => #<Class:#<String:0x000000012574c1f8>>
+ *
+ * +obj+ may be an ObjectSpace::InternalObjectWrapper, in which case the class
+ * of the wrapped internal object is returned.
*
* Note that you should not use this method in your application.
+ *
+ * This method is only expected to work with C Ruby.
*/
static VALUE
objspace_internal_class_of(VALUE self, VALUE obj)
@@ -834,7 +839,6 @@ Init_objspace(void)
rb_define_module_function(rb_mObjSpace, "count_objects_size", count_objects_size, -1);
rb_define_module_function(rb_mObjSpace, "count_symbols", count_symbols, -1);
- rb_define_module_function(rb_mObjSpace, "count_nodes", count_nodes, -1);
rb_define_module_function(rb_mObjSpace, "count_tdata_objects", count_tdata_objects, -1);
rb_define_module_function(rb_mObjSpace, "count_imemo_objects", count_imemo_objects, -1);
diff --git a/ext/objspace/objspace_dump.c b/ext/objspace/objspace_dump.c
index 94a9d43f98..68ada01af3 100644
--- a/ext/objspace/objspace_dump.c
+++ b/ext/objspace/objspace_dump.c
@@ -29,7 +29,7 @@
#include "ruby/util.h"
#include "ruby/io.h"
#include "vm_callinfo.h"
-#include "vm_core.h"
+#include "vm_sync.h"
RUBY_EXTERN const char ruby_hexdigits[];
@@ -573,10 +573,15 @@ dump_object(VALUE obj, struct dump_config *dc)
break;
case T_DATA:
- if (RTYPEDDATA_P(obj)) {
+ {
+ const rb_data_type_t *type = RTYPEDDATA_TYPE(obj);
dump_append(dc, ", \"struct\":\"");
- dump_append(dc, RTYPEDDATA_TYPE(obj)->wrap_struct_name);
+ dump_append(dc, type->wrap_struct_name);
dump_append(dc, "\"");
+ if (!(type->flags & RUBY_TYPED_FREE_IMMEDIATELY) &&
+ type->function.dfree != RUBY_DEFAULT_FREE) {
+ dump_append(dc, ", \"free_immediately\":false");
+ }
}
break;
@@ -587,14 +592,14 @@ dump_object(VALUE obj, struct dump_config *dc)
break;
case T_OBJECT:
- if (FL_TEST(obj, ROBJECT_EMBED)) {
+ if (!FL_TEST_RAW(obj, ROBJECT_HEAP)) {
dump_append(dc, ", \"embedded\":true");
}
dump_append(dc, ", \"ivars\":");
dump_append_lu(dc, ROBJECT_FIELDS_COUNT(obj));
- if (rb_shape_obj_too_complex_p(obj)) {
- dump_append(dc, ", \"too_complex_shape\":true");
+ if (rb_obj_shape_complex_p(obj)) {
+ dump_append(dc, ", \"complex_shape\":true");
}
break;
@@ -771,15 +776,16 @@ dump_result(struct dump_config *dc)
return dc->given_output;
}
-/* :nodoc: */
static VALUE
-objspace_dump(VALUE os, VALUE obj, VALUE output)
+dump_locked(void *args_p)
{
struct dump_config dc = {0,};
+ VALUE obj = ((VALUE*)args_p)[0];
+ VALUE output = ((VALUE*)args_p)[1];
+
if (!RB_SPECIAL_CONST_P(obj)) {
dc.cur_page_slot_size = rb_gc_obj_slot_size(obj);
}
-
dump_output(&dc, output, Qnil, Qnil, Qnil);
dump_object(obj, &dc);
@@ -787,6 +793,16 @@ objspace_dump(VALUE os, VALUE obj, VALUE output)
return dump_result(&dc);
}
+/* :nodoc: */
+static VALUE
+objspace_dump(VALUE os, VALUE obj, VALUE output)
+{
+ VALUE args[2];
+ args[0] = obj;
+ args[1] = output;
+ return rb_vm_lock_with_barrier(dump_locked, (void*)args);
+}
+
static void
shape_id_i(shape_id_t shape_id, void *data)
{
@@ -804,7 +820,7 @@ shape_id_i(shape_id_t shape_id, void *data)
if (RSHAPE_TYPE(shape_id) != SHAPE_ROOT) {
dump_append(dc, ", \"parent_id\":");
- dump_append_lu(dc, RSHAPE_PARENT_RAW_ID(shape_id));
+ dump_append_lu(dc, RSHAPE_PARENT_OFFSET(shape_id));
}
dump_append(dc, ", \"depth\":");
@@ -835,11 +851,15 @@ shape_id_i(shape_id_t shape_id, void *data)
dump_append(dc, "}\n");
}
-/* :nodoc: */
static VALUE
-objspace_dump_all(VALUE os, VALUE output, VALUE full, VALUE since, VALUE shapes)
+dump_all_locked(void *args_p)
{
struct dump_config dc = {0,};
+ VALUE output = ((VALUE*)args_p)[0];
+ VALUE full = ((VALUE*)args_p)[1];
+ VALUE since = ((VALUE*)args_p)[2];
+ VALUE shapes = ((VALUE*)args_p)[3];
+
dump_output(&dc, output, full, since, shapes);
if (!dc.partial_dump || dc.since == 0) {
@@ -860,9 +880,23 @@ objspace_dump_all(VALUE os, VALUE output, VALUE full, VALUE since, VALUE shapes)
/* :nodoc: */
static VALUE
-objspace_dump_shapes(VALUE os, VALUE output, VALUE shapes)
+objspace_dump_all(VALUE os, VALUE output, VALUE full, VALUE since, VALUE shapes)
+{
+ VALUE args[4];
+ args[0] = output;
+ args[1] = full;
+ args[2] = since;
+ args[3] = shapes;
+ return rb_vm_lock_with_barrier(dump_all_locked, (void*)args);
+}
+
+static VALUE
+dump_shapes_locked(void *args_p)
{
struct dump_config dc = {0,};
+ VALUE output = ((VALUE*)args_p)[0];
+ VALUE shapes = ((VALUE*)args_p)[1];
+
dump_output(&dc, output, Qfalse, Qnil, shapes);
if (RTEST(shapes)) {
@@ -871,6 +905,16 @@ objspace_dump_shapes(VALUE os, VALUE output, VALUE shapes)
return dump_result(&dc);
}
+/* :nodoc: */
+static VALUE
+objspace_dump_shapes(VALUE os, VALUE output, VALUE shapes)
+{
+ VALUE args[2];
+ args[0] = output;
+ args[1] = shapes;
+ return rb_vm_lock_with_barrier(dump_shapes_locked, (void*)args);
+}
+
void
Init_objspace_dump(VALUE rb_mObjSpace)
{
@@ -878,6 +922,9 @@ Init_objspace_dump(VALUE rb_mObjSpace)
#if 0
rb_mObjSpace = rb_define_module("ObjectSpace"); /* let rdoc know */
#endif
+#ifdef HAVE_RB_EXT_RACTOR_SAFE
+ RB_EXT_RACTOR_SAFE(true);
+#endif
rb_define_module_function(rb_mObjSpace, "_dump", objspace_dump, 2);
rb_define_module_function(rb_mObjSpace, "_dump_all", objspace_dump_all, 4);
diff --git a/ext/openssl/History.md b/ext/openssl/History.md
index ad3417f9d0..ce01b3e0f2 100644
--- a/ext/openssl/History.md
+++ b/ext/openssl/History.md
@@ -1,3 +1,132 @@
+Version 4.0.2
+=============
+
+Merged changes in 3.2.4 and 3.3.3.
+
+
+Version 4.0.1
+=============
+
+Notable changes
+---------------
+
+* Add `sync_close` keyword argument to `OpenSSL::SSL::SSLSocket.new` as a
+ short-hand for setting `sync_close` attribute on the created `SSLSocket`
+ instance.
+ [[GitHub #955]](https://github.com/ruby/openssl/issues/955)
+ [[GitHub #996]](https://github.com/ruby/openssl/pull/996)
+
+
+Bug fixes
+---------
+
+* Fix uninitialized variables in `OpenSSL::OCSP::BasicResponse#status`.
+ [[GitHub #1004]](https://github.com/ruby/openssl/pull/1004)
+
+
+Version 4.0.0
+=============
+
+Compatibility
+-------------
+
+* Ruby >= 2.7
+* OpenSSL >= 1.1.1, LibreSSL >= 3.9, and AWS-LC 1.66.0
+ - Removed support for OpenSSL 1.0.2-1.1.0 and LibreSSL 3.1-3.8.
+ [[GitHub #835]](https://github.com/ruby/openssl/issues/835)
+ - Added support for AWS-LC.
+ [[GitHub #833]](https://github.com/ruby/openssl/issues/833)
+
+
+Notable changes
+---------------
+
+* `OpenSSL::SSL`
+ - Reduce overhead when writing to `OpenSSL::SSL::SSLSocket`. `#syswrite` no
+ longer creates a temporary String object.
+ [[GitHub #831]](https://github.com/ruby/openssl/pull/831)
+ - Make `OpenSSL::SSL::SSLContext#min_version=` and `#max_version=` wrap the
+ corresponding OpenSSL APIs directly, and remove the fallback to SSL options.
+ [[GitHub #849]](https://github.com/ruby/openssl/pull/849)
+ - Add `OpenSSL::SSL::SSLContext#sigalgs=` and `#client_sigalgs=` for
+ specifying signature algorithms to use for connections.
+ [[GitHub #895]](https://github.com/ruby/openssl/pull/895)
+ - Rename `OpenSSL::SSL::SSLContext#ecdh_curves=` to `#groups=` following
+ the underlying OpenSSL API rename. This method is no longer specific to
+ ECDHE. The old method remains as an alias.
+ [[GitHub #900]](https://github.com/ruby/openssl/pull/900)
+ - Add `OpenSSL::SSL::SSLSocket#sigalg`, `#peer_sigalg`, and `#group` for
+ getting the signature algorithm and the key agreement group used in the
+ current connection.
+ [[GitHub #908]](https://github.com/ruby/openssl/pull/908)
+ - Enable `SSL_CTX_set_dh_auto()` for servers by default.
+ [[GitHub #924]](https://github.com/ruby/openssl/pull/924)
+ - Improve Ractor compatibility. Note that the internal-use constant
+ `OpenSSL::SSL::SSLContext::DEFAULT_PARAMS` is now frozen.
+ [[GitHub #925]](https://github.com/ruby/openssl/pull/925)
+* `OpenSSL::PKey`
+ - Remove `OpenSSL::PKey::EC::Point#mul` support with array arguments. The
+ underlying OpenSSL API has been removed, and the method has been deprecated
+ since ruby/openssl v3.0.0.
+ [[GitHub #843]](https://github.com/ruby/openssl/pull/843)
+ - `OpenSSL::PKey::{RSA,DSA,DH}#params` uses `nil` to indicate missing fields
+ instead of the number `0`.
+ [[GitHub #774]](https://github.com/ruby/openssl/pull/774)
+ - Unify `OpenSSL::PKey::PKeyError` classes. The former subclasses
+ `OpenSSL::PKey::DHError`, `OpenSSL::PKey::DSAError`,
+ `OpenSSL::PKey::ECError`, and `OpenSSL::PKey::RSAError` have been merged
+ into a single class.
+ [[GitHub #929]](https://github.com/ruby/openssl/pull/929)
+* `OpenSSL::Cipher`
+ - `OpenSSL::Cipher#encrypt` and `#decrypt` no longer accept arguments.
+ Passing passwords has been deprecated since Ruby 1.8.2 (released in 2004).
+ [[GitHub #887]](https://github.com/ruby/openssl/pull/887)
+ - `OpenSSL::Cipher#final` raises `OpenSSL::Cipher::AuthTagError` when the
+ integrity check fails for AEAD ciphers. `OpenSSL::Cipher::AuthTagError` is a
+ new subclass of `OpenSSL::Cipher::CipherError`, which was previously raised.
+ [[GitHub #939]](https://github.com/ruby/openssl/pull/939)
+ - `OpenSSL::Cipher.new` now raises `OpenSSL::Cipher::CipherError` instead of
+ `RuntimeError` when OpenSSL does not recognize the algorithm.
+ [[GitHub #958]](https://github.com/ruby/openssl/pull/958)
+ - Add support for "fetched" cipher algorithms with OpenSSL 3.0 or later.
+ [[GitHub #958]](https://github.com/ruby/openssl/pull/958)
+* `OpenSSL::Digest`
+ - `OpenSSL::Digest.new` now raises `OpenSSL::Digest::DigestError` instead of
+ `RuntimeError` when OpenSSL does not recognize the algorithm.
+ [[GitHub #958]](https://github.com/ruby/openssl/pull/958)
+ - Add support for "fetched" digest algorithms with OpenSSL 3.0 or later.
+ [[GitHub #958]](https://github.com/ruby/openssl/pull/958)
+* `OpenSSL::ASN1.decode` now assumes a 1950-2049 year range for `UTCTime`
+ according to RFC 5280. It previously used a 1969-2068 range. The encoder
+ has always used the 1950-2049 range.
+ [[GitHub #909]](https://github.com/ruby/openssl/pull/909)
+* `OpenSSL::OpenSSLError`, the base class for all ruby/openssl errors, carry
+ an additional attribute `#errors` to keep the content of OpenSSL's error
+ queue. Also, add `#detailed_message` for Ruby 3.2 or later.
+ [[GitHub #976]](https://github.com/ruby/openssl/pull/976)
+* `OpenSSL::PKCS7.new` raises `OpenSSL::PKCS7::PKCS7Error` instead of
+ `ArgumentError` on error to be consistent with other constructors.
+ [[GitHub #983]](https://github.com/ruby/openssl/pull/983)
+
+
+Version 3.3.3
+=============
+
+Merged changes in 3.2.4.
+
+
+Version 3.3.2
+=============
+
+Merged changes in 3.1.3 and 3.2.3.
+
+
+Version 3.3.1
+=============
+
+Merged changes in 3.1.2 and 3.2.2.
+
+
Version 3.3.0
=============
@@ -74,6 +203,28 @@ And various non-user-visible changes and bug fixes. Please see the commit
history for more details.
+Version 3.2.4
+=============
+
+Notable changes
+---------------
+
+* Add support for OpenSSL 4.0.
+ [[GitHub #1051]](https://github.com/ruby/openssl/pull/1051)
+
+
+Version 3.2.3
+=============
+
+Merged changes in 3.1.3.
+
+
+Version 3.2.2
+=============
+
+Merged changes in 3.1.2.
+
+
Version 3.2.1
=============
@@ -120,6 +271,33 @@ Notable changes
[[GitHub #141]](https://github.com/ruby/openssl/pull/141)
+Version 3.1.3
+=============
+
+Bug fixes
+---------
+
+* Fix missing NULL check for `EVP_PKEY_get0()` functions with OpenSSL 3.x.
+ [[GitHub #957]](https://github.com/ruby/openssl/pull/957)
+
+
+Version 3.1.2
+=============
+
+Bug fixes
+---------
+
+* Fix crash when attempting to export an incomplete `OpenSSL::PKey::DSA` key.
+ [[GitHub #845]](https://github.com/ruby/openssl/issues/845)
+ [[GitHub #847]](https://github.com/ruby/openssl/pull/847)
+* Remove the `OpenSSL::X509::V_FLAG_CRL_CHECK_ALL` flag from the default store
+ used by `OpenSSL::SSL::SSLContext#set_params`. It causes certificate
+ verification to fail with OpenSSL 3.6.0. It has no effect with any other
+ OpenSSL versions.
+ [[GitHub #949]](https://github.com/ruby/openssl/issues/949)
+ [[GitHub #950]](https://github.com/ruby/openssl/pull/950)
+
+
Version 3.1.1
=============
diff --git a/ext/openssl/extconf.rb b/ext/openssl/extconf.rb
index 8aac52ef47..1f32980940 100644
--- a/ext/openssl/extconf.rb
+++ b/ext/openssl/extconf.rb
@@ -38,8 +38,12 @@ Logging::message "=== OpenSSL for Ruby configurator ===\n"
$defs.push("-D""OPENSSL_SUPPRESS_DEPRECATED")
+# Missing in TruffleRuby
+have_func("rb_call_super_kw(0, NULL, 0)", "ruby.h")
+# Ruby 3.1
have_func("rb_io_descriptor", "ruby/io.h")
-have_func("rb_io_maybe_wait(0, Qnil, Qnil, Qnil)", "ruby/io.h") # Ruby 3.1
+have_func("rb_io_maybe_wait(0, Qnil, Qnil, Qnil)", "ruby/io.h")
+# Ruby 3.2
have_func("rb_io_timeout", "ruby/io.h")
Logging::message "=== Checking for system dependent stuff... ===\n"
@@ -131,6 +135,7 @@ Logging::message "=== Checking for OpenSSL features... ===\n"
evp_h = "openssl/evp.h".freeze
ts_h = "openssl/ts.h".freeze
ssl_h = "openssl/ssl.h".freeze
+stack_h = "openssl/stack.h".freeze
# compile options
have_func("RAND_egd()", "openssl/rand.h")
@@ -146,8 +151,11 @@ have_func("EVP_PBE_scrypt(\"\", 0, (unsigned char *)\"\", 0, 0, 0, 0, 0, NULL, 0
# added in OpenSSL 1.1.1 and LibreSSL 3.5.0, then removed in LibreSSL 4.0.0
have_func("EVP_PKEY_check(NULL)", evp_h)
+# added in OpenSSL 1.1.1, currently not in LibreSSL
+have_func("OPENSSL_sk_new_reserve(NULL, 0)", stack_h)
+
# added in 3.0.0
-have_func("SSL_set0_tmp_dh_pkey(NULL, NULL)", ssl_h)
+have_func("SSL_CTX_set0_tmp_dh_pkey(NULL, NULL)", ssl_h)
have_func("ERR_get_error_all(NULL, NULL, NULL, NULL, NULL)", "openssl/err.h")
have_func("SSL_CTX_load_verify_file(NULL, \"\")", ssl_h)
have_func("BN_check_prime(NULL, NULL, NULL)", "openssl/bn.h")
@@ -165,6 +173,9 @@ have_func("TS_VERIFY_CTX_set0_certs(NULL, NULL)", ts_h)
# added in 3.5.0
have_func("SSL_get0_peer_signature_name(NULL, NULL)", ssl_h)
+# added in 4.0.0
+have_func("ASN1_BIT_STRING_set1(NULL, NULL, 0, 0)", "openssl/asn1.h")
+
Logging::message "=== Checking done. ===\n"
# Append flags from environment variables.
diff --git a/ext/openssl/lib/openssl.rb b/ext/openssl/lib/openssl.rb
index 48f88dcbba..98fa8d39f2 100644
--- a/ext/openssl/lib/openssl.rb
+++ b/ext/openssl/lib/openssl.rb
@@ -12,7 +12,6 @@
require 'openssl.so'
-require_relative 'openssl/asn1'
require_relative 'openssl/bn'
require_relative 'openssl/cipher'
require_relative 'openssl/digest'
@@ -24,12 +23,16 @@ require_relative 'openssl/version'
require_relative 'openssl/x509'
module OpenSSL
- # call-seq:
- # OpenSSL.secure_compare(string, string) -> boolean
+ # :call-seq:
+ # OpenSSL.secure_compare(string, string) -> true or false
#
# Constant time memory comparison. Inputs are hashed using SHA-256 to mask
# the length of the secret. Returns +true+ if the strings are identical,
# +false+ otherwise.
+ #
+ # This method is expensive due to the SHA-256 hashing. In most cases, where
+ # the input lengths are known to be equal or are not sensitive,
+ # OpenSSL.fixed_length_secure_compare should be used instead.
def self.secure_compare(a, b)
hashed_a = OpenSSL::Digest.digest('SHA256', a)
hashed_b = OpenSSL::Digest.digest('SHA256', b)
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/digest.rb b/ext/openssl/lib/openssl/digest.rb
index 5cda1e931c..4e6dea8d03 100644
--- a/ext/openssl/lib/openssl/digest.rb
+++ b/ext/openssl/lib/openssl/digest.rb
@@ -27,17 +27,21 @@ module OpenSSL
end
%w(MD4 MD5 RIPEMD160 SHA1 SHA224 SHA256 SHA384 SHA512).each do |name|
- klass = Class.new(self) {
- define_method(:initialize, ->(data = nil) {super(name, data)})
- }
-
- singleton = (class << klass; self; end)
-
- singleton.class_eval{
- define_method(:digest) {|data| new.digest(data)}
- define_method(:hexdigest) {|data| new.hexdigest(data)}
- }
+ klass = Class.new(self)
+ klass.class_eval <<-RUBY, __FILE__, __LINE__ + 1
+ def initialize(data = nil)
+ super("#{name}", data)
+ end
+ RUBY
+ klass.singleton_class.class_eval <<-RUBY, __FILE__, __LINE__ + 1
+ def digest(data)
+ new.digest(data)
+ end
+ def hexdigest(data)
+ new.hexdigest(data)
+ end
+ RUBY
const_set(name.tr('-', '_'), klass)
end
@@ -57,7 +61,7 @@ module OpenSSL
# OpenSSL::Digest("MD5")
# # => OpenSSL::Digest::MD5
#
- # Digest("Foo")
+ # OpenSSL::Digest("Foo")
# # => NameError: wrong constant name Foo
def Digest(name)
diff --git a/ext/openssl/lib/openssl/pkey.rb b/ext/openssl/lib/openssl/pkey.rb
index 3d1e8885ca..39871e15dd 100644
--- a/ext/openssl/lib/openssl/pkey.rb
+++ b/ext/openssl/lib/openssl/pkey.rb
@@ -7,6 +7,9 @@
require_relative 'marshal'
module OpenSSL::PKey
+ # Alias of PKeyError. Before version 4.0.0, this was a subclass of PKeyError.
+ DHError = PKeyError
+
class DH
include OpenSSL::Marshal
@@ -102,7 +105,7 @@ module OpenSSL::PKey
# puts dh0.pub_key == dh.pub_key #=> false
def generate_key!
if OpenSSL::OPENSSL_VERSION_NUMBER >= 0x30000000
- raise DHError, "OpenSSL::PKey::DH is immutable on OpenSSL 3.0; " \
+ raise PKeyError, "OpenSSL::PKey::DH is immutable on OpenSSL 3.0; " \
"use OpenSSL::PKey.generate_key instead"
end
@@ -147,6 +150,9 @@ module OpenSSL::PKey
end
end
+ # Alias of PKeyError. Before version 4.0.0, this was a subclass of PKeyError.
+ DSAError = PKeyError
+
class DSA
include OpenSSL::Marshal
@@ -242,13 +248,9 @@ module OpenSSL::PKey
# sig = dsa.sign_raw(nil, digest)
# p dsa.verify_raw(nil, sig, digest) #=> true
def syssign(string)
- q or raise OpenSSL::PKey::DSAError, "incomplete DSA"
- private? or raise OpenSSL::PKey::DSAError, "Private DSA key needed!"
- begin
- sign_raw(nil, string)
- rescue OpenSSL::PKey::PKeyError
- raise OpenSSL::PKey::DSAError, $!.message
- end
+ q or raise PKeyError, "incomplete DSA"
+ private? or raise PKeyError, "Private DSA key needed!"
+ sign_raw(nil, string)
end
# :call-seq:
@@ -266,12 +268,13 @@ module OpenSSL::PKey
# A \DSA signature value.
def sysverify(digest, sig)
verify_raw(nil, sig, digest)
- rescue OpenSSL::PKey::PKeyError
- raise OpenSSL::PKey::DSAError, $!.message
end
end
if defined?(EC)
+ # Alias of PKeyError. Before version 4.0.0, this was a subclass of PKeyError.
+ ECError = PKeyError
+
class EC
include OpenSSL::Marshal
@@ -282,8 +285,6 @@ module OpenSSL::PKey
# Consider using PKey::PKey#sign_raw and PKey::PKey#verify_raw instead.
def dsa_sign_asn1(data)
sign_raw(nil, data)
- rescue OpenSSL::PKey::PKeyError
- raise OpenSSL::PKey::ECError, $!.message
end
# :call-seq:
@@ -293,8 +294,6 @@ module OpenSSL::PKey
# Consider using PKey::PKey#sign_raw and PKey::PKey#verify_raw instead.
def dsa_verify_asn1(data, sig)
verify_raw(nil, sig, data)
- rescue OpenSSL::PKey::PKeyError
- raise OpenSSL::PKey::ECError, $!.message
end
# :call-seq:
@@ -334,6 +333,9 @@ module OpenSSL::PKey
end
end
+ # Alias of PKeyError. Before version 4.0.0, this was a subclass of PKeyError.
+ RSAError = PKeyError
+
class RSA
include OpenSSL::Marshal
@@ -407,15 +409,11 @@ module OpenSSL::PKey
# Consider using PKey::PKey#sign_raw and PKey::PKey#verify_raw, and
# PKey::PKey#verify_recover instead.
def private_encrypt(string, padding = PKCS1_PADDING)
- n or raise OpenSSL::PKey::RSAError, "incomplete RSA"
- private? or raise OpenSSL::PKey::RSAError, "private key needed."
- begin
- sign_raw(nil, string, {
- "rsa_padding_mode" => translate_padding_mode(padding),
- })
- rescue OpenSSL::PKey::PKeyError
- raise OpenSSL::PKey::RSAError, $!.message
- end
+ n or raise PKeyError, "incomplete RSA"
+ private? or raise PKeyError, "private key needed."
+ sign_raw(nil, string, {
+ "rsa_padding_mode" => translate_padding_mode(padding),
+ })
end
# :call-seq:
@@ -430,14 +428,10 @@ module OpenSSL::PKey
# Consider using PKey::PKey#sign_raw and PKey::PKey#verify_raw, and
# PKey::PKey#verify_recover instead.
def public_decrypt(string, padding = PKCS1_PADDING)
- n or raise OpenSSL::PKey::RSAError, "incomplete RSA"
- begin
- verify_recover(nil, string, {
- "rsa_padding_mode" => translate_padding_mode(padding),
- })
- rescue OpenSSL::PKey::PKeyError
- raise OpenSSL::PKey::RSAError, $!.message
- end
+ n or raise PKeyError, "incomplete RSA"
+ verify_recover(nil, string, {
+ "rsa_padding_mode" => translate_padding_mode(padding),
+ })
end
# :call-seq:
@@ -452,14 +446,10 @@ module OpenSSL::PKey
# <b>Deprecated in version 3.0</b>.
# Consider using PKey::PKey#encrypt and PKey::PKey#decrypt instead.
def public_encrypt(data, padding = PKCS1_PADDING)
- n or raise OpenSSL::PKey::RSAError, "incomplete RSA"
- begin
- encrypt(data, {
- "rsa_padding_mode" => translate_padding_mode(padding),
- })
- rescue OpenSSL::PKey::PKeyError
- raise OpenSSL::PKey::RSAError, $!.message
- end
+ n or raise PKeyError, "incomplete RSA"
+ encrypt(data, {
+ "rsa_padding_mode" => translate_padding_mode(padding),
+ })
end
# :call-seq:
@@ -473,15 +463,11 @@ module OpenSSL::PKey
# <b>Deprecated in version 3.0</b>.
# Consider using PKey::PKey#encrypt and PKey::PKey#decrypt instead.
def private_decrypt(data, padding = PKCS1_PADDING)
- n or raise OpenSSL::PKey::RSAError, "incomplete RSA"
- private? or raise OpenSSL::PKey::RSAError, "private key needed."
- begin
- decrypt(data, {
- "rsa_padding_mode" => translate_padding_mode(padding),
- })
- rescue OpenSSL::PKey::PKeyError
- raise OpenSSL::PKey::RSAError, $!.message
- end
+ n or raise PKeyError, "incomplete RSA"
+ private? or raise PKeyError, "private key needed."
+ decrypt(data, {
+ "rsa_padding_mode" => translate_padding_mode(padding),
+ })
end
PKCS1_PADDING = 1
@@ -500,7 +486,7 @@ module OpenSSL::PKey
when PKCS1_OAEP_PADDING
"oaep"
else
- raise OpenSSL::PKey::PKeyError, "unsupported padding mode"
+ raise PKeyError, "unsupported padding mode"
end
end
end
diff --git a/ext/openssl/lib/openssl/ssl.rb b/ext/openssl/lib/openssl/ssl.rb
index a0ad5dc3a6..3268c126b9 100644
--- a/ext/openssl/lib/openssl/ssl.rb
+++ b/ext/openssl/lib/openssl/ssl.rb
@@ -32,25 +32,6 @@ module OpenSSL
}.call
}
- if defined?(OpenSSL::PKey::DH)
- DH_ffdhe2048 = 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==
------END DH PARAMETERS-----
- _end_of_pem_
- private_constant :DH_ffdhe2048
-
- DEFAULT_TMP_DH_CALLBACK = lambda { |ctx, is_export, keylen| # :nodoc:
- warn "using default DH parameters." if $VERBOSE
- DH_ffdhe2048
- }
- end
-
if !OpenSSL::OPENSSL_VERSION.start_with?("OpenSSL")
DEFAULT_PARAMS.merge!(
min_version: OpenSSL::SSL::TLS1_VERSION,
@@ -85,26 +66,13 @@ ssbzSibBsu/6iGtCOGEoXJf//////////wIBAg==
AES256-SHA256
AES128-SHA
AES256-SHA
- }.join(":"),
+ }.join(":").freeze,
)
end
+ DEFAULT_PARAMS.freeze
DEFAULT_CERT_STORE = OpenSSL::X509::Store.new # :nodoc:
DEFAULT_CERT_STORE.set_default_paths
- DEFAULT_CERT_STORE.flags = OpenSSL::X509::V_FLAG_CRL_CHECK_ALL
-
- # A callback invoked when DH parameters are required for ephemeral DH key
- # exchange.
- #
- # The callback is invoked with the SSLSocket, a
- # flag indicating the use of an export cipher and the keylength
- # required.
- #
- # The callback must return an OpenSSL::PKey::DH instance of the correct
- # key length.
- #
- # <b>Deprecated in version 3.0.</b> Use #tmp_dh= instead.
- attr_accessor :tmp_dh_callback
# A callback invoked at connect time to distinguish between multiple
# server names.
@@ -147,7 +115,14 @@ ssbzSibBsu/6iGtCOGEoXJf//////////wIBAg==
params.each{|name, value| self.__send__("#{name}=", value) }
if self.verify_mode != OpenSSL::SSL::VERIFY_NONE
unless self.ca_file or self.ca_path or self.cert_store
- self.cert_store = DEFAULT_CERT_STORE
+ if not defined?(Ractor) or Ractor.current == Ractor.main
+ self.cert_store = DEFAULT_CERT_STORE
+ else
+ self.cert_store = Ractor.current[:__openssl_default_store__] ||=
+ OpenSSL::X509::Store.new.tap { |store|
+ store.set_default_paths
+ }
+ end
end
end
return params
@@ -457,10 +432,6 @@ ssbzSibBsu/6iGtCOGEoXJf//////////wIBAg==
@context.client_cert_cb
end
- def tmp_dh_callback
- @context.tmp_dh_callback || OpenSSL::SSL::SSLContext::DEFAULT_TMP_DH_CALLBACK
- end
-
def session_new_cb
@context.session_new_cb
end
diff --git a/ext/openssl/lib/openssl/version.rb b/ext/openssl/lib/openssl/version.rb
index 3398fe39cc..395a720a31 100644
--- a/ext/openssl/lib/openssl/version.rb
+++ b/ext/openssl/lib/openssl/version.rb
@@ -1,5 +1,6 @@
# frozen_string_literal: true
module OpenSSL
- VERSION = "3.3.0"
+ # The version string of Ruby/OpenSSL.
+ VERSION = "4.0.2"
end
diff --git a/ext/openssl/lib/openssl/x509.rb b/ext/openssl/lib/openssl/x509.rb
index 6459d37b12..66765ffeab 100644
--- a/ext/openssl/lib/openssl/x509.rb
+++ b/ext/openssl/lib/openssl/x509.rb
@@ -346,6 +346,15 @@ module OpenSSL
include Extension::CRLDistributionPoints
include Extension::AuthorityInfoAccess
+ def inspect
+ "#<#{self.class}: " \
+ "subject=#{subject.inspect}, " \
+ "issuer=#{issuer.inspect}, " \
+ "serial=#{serial.inspect}, " \
+ "not_before=#{not_before.inspect rescue "(error)"}, " \
+ "not_after=#{not_after.inspect rescue "(error)"}>"
+ end
+
def pretty_print(q)
q.object_group(self) {
q.breakable
diff --git a/ext/openssl/openssl.gemspec b/ext/openssl/openssl.gemspec
index 2ec1551885..af1775e3b0 100644
--- a/ext/openssl/openssl.gemspec
+++ b/ext/openssl/openssl.gemspec
@@ -1,6 +1,6 @@
Gem::Specification.new do |spec|
spec.name = "openssl"
- spec.version = "3.3.0"
+ spec.version = "4.0.2"
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}
diff --git a/ext/openssl/openssl_missing.h b/ext/openssl/openssl_missing.h
index 6592f9ccea..ed3b5b7c0f 100644
--- a/ext/openssl/openssl_missing.h
+++ b/ext/openssl/openssl_missing.h
@@ -29,4 +29,27 @@
# define EVP_PKEY_eq(a, b) EVP_PKEY_cmp(a, b)
#endif
+/* added in 4.0.0 */
+#ifndef HAVE_ASN1_BIT_STRING_SET1
+static inline int
+ASN1_BIT_STRING_set1(ASN1_BIT_STRING *bitstr, const uint8_t *data,
+ size_t length, int unused_bits)
+{
+ if (length > INT_MAX || !ASN1_STRING_set(bitstr, data, (int)length))
+ return 0;
+ bitstr->flags &= ~(ASN1_STRING_FLAG_BITS_LEFT | 0x07);
+ bitstr->flags |= ASN1_STRING_FLAG_BITS_LEFT | unused_bits;
+ return 1;
+}
+
+static inline int
+ASN1_BIT_STRING_get_length(const ASN1_BIT_STRING *bitstr, size_t *length,
+ int *unused_bits)
+{
+ *length = bitstr->length;
+ *unused_bits = bitstr->flags & 0x07;
+ return 1;
+}
+#endif
+
#endif /* _OSSL_OPENSSL_MISSING_H_ */
diff --git a/ext/openssl/ossl.c b/ext/openssl/ossl.c
index 60780790b0..5716e6f100 100644
--- a/ext/openssl/ossl.c
+++ b/ext/openssl/ossl.c
@@ -13,71 +13,75 @@
/*
* Data Conversion
*/
-#define OSSL_IMPL_ARY2SK(name, type, expected_class, dup) \
-VALUE \
-ossl_##name##_ary2sk0(VALUE ary) \
-{ \
- STACK_OF(type) *sk; \
- VALUE val; \
- type *x; \
- int i; \
- \
- Check_Type(ary, T_ARRAY); \
- sk = sk_##type##_new_null(); \
- if (!sk) ossl_raise(eOSSLError, NULL); \
- \
- for (i = 0; i < RARRAY_LEN(ary); i++) { \
- val = rb_ary_entry(ary, i); \
- if (!rb_obj_is_kind_of(val, expected_class)) { \
- sk_##type##_pop_free(sk, type##_free); \
- ossl_raise(eOSSLError, "object in array not" \
- " of class ##type##"); \
- } \
- x = dup(val); /* NEED TO DUP */ \
- sk_##type##_push(sk, x); \
- } \
- return (VALUE)sk; \
-} \
- \
-STACK_OF(type) * \
-ossl_protect_##name##_ary2sk(VALUE ary, int *status) \
-{ \
- return (STACK_OF(type)*)rb_protect( \
- (VALUE (*)(VALUE))ossl_##name##_ary2sk0, \
- ary, \
- status); \
-} \
- \
-STACK_OF(type) * \
-ossl_##name##_ary2sk(VALUE ary) \
-{ \
- STACK_OF(type) *sk; \
- int status = 0; \
- \
- sk = ossl_protect_##name##_ary2sk(ary, &status); \
- if (status) rb_jump_tag(status); \
- \
- return sk; \
+#define OSSL_IMPL_ARY2SK(name, type, expected_class, dup) \
+VALUE \
+ossl_##name##_ary2sk0(VALUE ary) \
+{ \
+ STACK_OF(type) *sk; \
+ VALUE val; \
+ type *x; \
+ int i; \
+ \
+ Check_Type(ary, T_ARRAY); \
+ sk = sk_##type##_new_null(); \
+ if (!sk) ossl_raise(eOSSLError, NULL); \
+ \
+ for (i = 0; i < RARRAY_LEN(ary); i++) { \
+ val = rb_ary_entry(ary, i); \
+ if (!rb_obj_is_kind_of(val, expected_class)) { \
+ sk_##type##_pop_free(sk, type##_free); \
+ ossl_raise(eOSSLError, "object in array not" \
+ " of class ##type##"); \
+ } \
+ x = dup(val); /* NEED TO DUP */ \
+ if (!sk_##type##_push(sk, x)) { \
+ type##_free(x); \
+ sk_##type##_pop_free(sk, type##_free); \
+ ossl_raise(eOSSLError, NULL); \
+ } \
+ } \
+ return (VALUE)sk; \
+} \
+ \
+STACK_OF(type) * \
+ossl_protect_##name##_ary2sk(VALUE ary, int *status) \
+{ \
+ return (STACK_OF(type)*)rb_protect( \
+ (VALUE (*)(VALUE))ossl_##name##_ary2sk0, \
+ ary, \
+ status); \
+} \
+ \
+STACK_OF(type) * \
+ossl_##name##_ary2sk(VALUE ary) \
+{ \
+ STACK_OF(type) *sk; \
+ int status = 0; \
+ \
+ sk = ossl_protect_##name##_ary2sk(ary, &status); \
+ if (status) rb_jump_tag(status); \
+ \
+ return sk; \
}
OSSL_IMPL_ARY2SK(x509, X509, cX509Cert, DupX509CertPtr)
-#define OSSL_IMPL_SK2ARY(name, type) \
-VALUE \
-ossl_##name##_sk2ary(const STACK_OF(type) *sk) \
-{ \
- type *t; \
- int i, num; \
- VALUE ary; \
- \
- RUBY_ASSERT(sk != NULL); \
- num = sk_##type##_num(sk); \
- ary = rb_ary_new_capa(num); \
- \
- for (i=0; i<num; i++) { \
- t = sk_##type##_value(sk, i); \
- rb_ary_push(ary, ossl_##name##_new(t)); \
- } \
- return ary; \
+#define OSSL_IMPL_SK2ARY(name, type) \
+VALUE \
+ossl_##name##_sk2ary(const STACK_OF(type) *sk) \
+{ \
+ type *t; \
+ int i, num; \
+ VALUE ary; \
+ \
+ RUBY_ASSERT(sk != NULL); \
+ num = sk_##type##_num(sk); \
+ ary = rb_ary_new_capa(num); \
+ \
+ for (i=0; i<num; i++) { \
+ t = sk_##type##_value(sk, i); \
+ rb_ary_push(ary, ossl_##name##_new(t)); \
+ } \
+ return ary; \
}
OSSL_IMPL_SK2ARY(x509, X509)
OSSL_IMPL_SK2ARY(x509crl, X509_CRL)
@@ -97,14 +101,14 @@ ossl_str_new(const char *ptr, long len, int *pstate)
str = rb_protect(ossl_str_new_i, len, &state);
if (pstate)
- *pstate = state;
+ *pstate = state;
if (state) {
- if (!pstate)
- rb_set_errinfo(Qnil);
- return Qnil;
+ if (!pstate)
+ rb_set_errinfo(Qnil);
+ return Qnil;
}
if (ptr)
- memcpy(RSTRING_PTR(str), ptr, len);
+ memcpy(RSTRING_PTR(str), ptr, len);
return str;
}
@@ -117,22 +121,22 @@ ossl_buf2str(char *buf, int len)
str = ossl_str_new(buf, len, &state);
OPENSSL_free(buf);
if (state)
- rb_jump_tag(state);
+ rb_jump_tag(state);
return str;
}
void
-ossl_bin2hex(unsigned char *in, char *out, size_t inlen)
+ossl_bin2hex(const unsigned char *in, char *out, size_t inlen)
{
const char *hex = "0123456789abcdef";
size_t i;
assert(inlen <= LONG_MAX / 2);
for (i = 0; i < inlen; i++) {
- unsigned char p = in[i];
+ unsigned char p = in[i];
- out[i * 2 + 0] = hex[p >> 4];
- out[i * 2 + 1] = hex[p & 0x0f];
+ out[i * 2 + 0] = hex[p >> 4];
+ out[i * 2 + 1] = hex[p & 0x0f];
}
}
@@ -143,14 +147,14 @@ VALUE
ossl_pem_passwd_value(VALUE pass)
{
if (NIL_P(pass))
- return Qnil;
+ return Qnil;
StringValue(pass);
/* PEM_BUFSIZE is currently used as the second argument of pem_password_cb,
* that is +max_len+ of ossl_pem_passwd_cb() */
if (RSTRING_LEN(pass) > PEM_BUFSIZE)
- ossl_raise(eOSSLError, "password must not be longer than %d bytes", PEM_BUFSIZE);
+ ossl_raise(eOSSLError, "password must not be longer than %d bytes", PEM_BUFSIZE);
return pass;
}
@@ -160,7 +164,7 @@ ossl_pem_passwd_cb0(VALUE flag)
{
VALUE pass = rb_yield(flag);
if (NIL_P(pass))
- return Qnil;
+ return Qnil;
StringValue(pass);
return pass;
}
@@ -173,46 +177,46 @@ ossl_pem_passwd_cb(char *buf, int max_len, int flag, void *pwd_)
VALUE rflag, pass = (VALUE)pwd_;
if (RTEST(pass)) {
- /* PEM_def_callback(buf, max_len, flag, StringValueCStr(pass)) does not
- * work because it does not allow NUL characters and truncates to 1024
- * bytes silently if the input is over 1024 bytes */
- if (RB_TYPE_P(pass, T_STRING)) {
- len = RSTRING_LEN(pass);
- if (len <= max_len) {
- memcpy(buf, RSTRING_PTR(pass), len);
- return (int)len;
- }
- }
- OSSL_Debug("passed data is not valid String???");
- return -1;
+ /* PEM_def_callback(buf, max_len, flag, StringValueCStr(pass)) does not
+ * work because it does not allow NUL characters and truncates to 1024
+ * bytes silently if the input is over 1024 bytes */
+ if (RB_TYPE_P(pass, T_STRING)) {
+ len = RSTRING_LEN(pass);
+ if (len <= max_len) {
+ memcpy(buf, RSTRING_PTR(pass), len);
+ return (int)len;
+ }
+ }
+ OSSL_Debug("passed data is not valid String???");
+ return -1;
}
if (!rb_block_given_p()) {
- return PEM_def_callback(buf, max_len, flag, NULL);
+ return PEM_def_callback(buf, max_len, flag, NULL);
}
while (1) {
- /*
- * when the flag is nonzero, this password
- * will be used to perform encryption; otherwise it will
- * be used to perform decryption.
- */
- rflag = flag ? Qtrue : Qfalse;
- pass = rb_protect(ossl_pem_passwd_cb0, rflag, &status);
- if (status) {
- /* ignore an exception raised. */
- rb_set_errinfo(Qnil);
- return -1;
- }
- if (NIL_P(pass))
- return -1;
- len = RSTRING_LEN(pass);
- if (len > max_len) {
- rb_warning("password must not be longer than %d bytes", max_len);
- continue;
- }
- memcpy(buf, RSTRING_PTR(pass), len);
- break;
+ /*
+ * when the flag is nonzero, this password
+ * will be used to perform encryption; otherwise it will
+ * be used to perform decryption.
+ */
+ rflag = flag ? Qtrue : Qfalse;
+ pass = rb_protect(ossl_pem_passwd_cb0, rflag, &status);
+ if (status) {
+ /* ignore an exception raised. */
+ rb_set_errinfo(Qnil);
+ return -1;
+ }
+ if (NIL_P(pass))
+ return -1;
+ len = RSTRING_LEN(pass);
+ if (len > max_len) {
+ rb_warning("password must not be longer than %d bytes", max_len);
+ continue;
+ }
+ memcpy(buf, RSTRING_PTR(pass), len);
+ break;
}
return (int)len;
}
@@ -247,19 +251,24 @@ VALUE
ossl_to_der_if_possible(VALUE obj)
{
if(rb_respond_to(obj, ossl_s_to_der))
- return ossl_to_der(obj);
+ return ossl_to_der(obj);
return obj;
}
/*
* Errors
*/
+static ID id_i_errors;
+
+static void collect_errors_into(VALUE ary);
+
VALUE
ossl_make_error(VALUE exc, VALUE str)
{
unsigned long e;
const char *data;
int flags;
+ VALUE errors = rb_ary_new();
if (NIL_P(str))
str = rb_str_new(NULL, 0);
@@ -276,10 +285,12 @@ ossl_make_error(VALUE exc, VALUE str)
rb_str_cat_cstr(str, msg ? msg : "(null)");
if (flags & ERR_TXT_STRING && data)
rb_str_catf(str, " (%s)", data);
- ossl_clear_error();
+ collect_errors_into(errors);
}
- return rb_exc_new_str(exc, str);
+ VALUE obj = rb_exc_new_str(exc, str);
+ rb_ivar_set(obj, id_i_errors, errors);
+ return obj;
}
void
@@ -289,24 +300,23 @@ ossl_raise(VALUE exc, const char *fmt, ...)
VALUE err;
if (fmt) {
- va_start(args, fmt);
- err = rb_vsprintf(fmt, args);
- va_end(args);
+ va_start(args, fmt);
+ err = rb_vsprintf(fmt, args);
+ va_end(args);
}
else {
- err = Qnil;
+ err = Qnil;
}
rb_exc_raise(ossl_make_error(exc, err));
}
-void
-ossl_clear_error(void)
+static void
+collect_errors_into(VALUE ary)
{
- if (dOSSL == Qtrue) {
+ if (dOSSL == Qtrue || !NIL_P(ary)) {
unsigned long e;
const char *file, *data, *func, *lib, *reason;
- char append[256] = "";
int line, flags;
#ifdef HAVE_ERR_GET_ERROR_ALL
@@ -318,13 +328,18 @@ ossl_clear_error(void)
lib = ERR_lib_error_string(e);
reason = ERR_reason_error_string(e);
+ VALUE str = rb_sprintf("error:%08lX:%s:%s:%s", e, lib ? lib : "",
+ func ? func : "", reason ? reason : "");
if (flags & ERR_TXT_STRING) {
if (!data)
data = "(null)";
- snprintf(append, sizeof(append), " (%s)", data);
+ rb_str_catf(str, " (%s)", data);
}
- rb_warn("error on stack: error:%08lX:%s:%s:%s%s", e, lib ? lib : "",
- func ? func : "", reason ? reason : "", append);
+
+ if (dOSSL == Qtrue)
+ rb_warn("error on stack: %"PRIsVALUE, str);
+ if (!NIL_P(ary))
+ rb_ary_push(ary, str);
}
}
else {
@@ -332,14 +347,59 @@ ossl_clear_error(void)
}
}
+void
+ossl_clear_error(void)
+{
+ collect_errors_into(Qnil);
+}
+
+/*
+ * call-seq:
+ * ossl_error.detailed_message(**) -> string
+ *
+ * Returns the exception message decorated with the captured \OpenSSL error
+ * queue entries.
+ */
+static VALUE
+osslerror_detailed_message(int argc, VALUE *argv, VALUE self)
+{
+ VALUE str;
+#ifdef HAVE_RB_CALL_SUPER_KW
+ // Ruby >= 3.2
+ if (RTEST(rb_funcall(rb_eException, rb_intern("method_defined?"), 1,
+ ID2SYM(rb_intern("detailed_message")))))
+ str = rb_call_super_kw(argc, argv, RB_PASS_CALLED_KEYWORDS);
+ else
+#endif
+ str = rb_funcall(self, rb_intern("message"), 0);
+ VALUE errors = rb_attr_get(self, id_i_errors);
+
+ // OpenSSLError was not created by ossl_make_error()
+ if (!RB_TYPE_P(errors, T_ARRAY))
+ return str;
+
+ str = rb_str_resurrect(str);
+ rb_str_catf(str, "\nOpenSSL error queue reported %ld errors:",
+ RARRAY_LEN(errors));
+ for (long i = 0; i < RARRAY_LEN(errors); i++) {
+ VALUE err = RARRAY_AREF(errors, i);
+ rb_str_catf(str, "\n%"PRIsVALUE, err);
+ }
+ return str;
+}
+
/*
* call-seq:
* OpenSSL.errors -> [String...]
*
- * See any remaining errors held in queue.
+ * Returns any remaining errors held in the \OpenSSL thread-local error queue
+ * and clears the queue. This should normally return an empty array.
+ *
+ * This is intended for debugging Ruby/OpenSSL. If you see any errors here,
+ * it likely indicates a bug in the extension. Please file an issue at
+ * https://github.com/ruby/openssl.
*
- * Any errors you see here are probably due to a bug in Ruby's OpenSSL
- * implementation.
+ * For debugging your program, OpenSSL.debug= may be useful.
*/
static VALUE
ossl_get_errors(VALUE _)
@@ -363,6 +423,8 @@ VALUE dOSSL;
/*
* call-seq:
* OpenSSL.debug -> true | false
+ *
+ * Returns whether Ruby/OpenSSL's debug mode is currently enabled.
*/
static VALUE
ossl_debug_get(VALUE self)
@@ -372,9 +434,9 @@ ossl_debug_get(VALUE self)
/*
* call-seq:
- * OpenSSL.debug = boolean -> boolean
+ * OpenSSL.debug = boolean
*
- * Turns on or off debug mode. With debug mode, all errors added to the OpenSSL
+ * Turns on or off debug mode. With debug mode, all errors added to the \OpenSSL
* error queue will be printed to stderr.
*/
static VALUE
@@ -388,6 +450,8 @@ ossl_debug_set(VALUE self, VALUE val)
/*
* call-seq:
* OpenSSL.fips_mode -> true | false
+ *
+ * Returns whether the FIPS mode is currently enabled.
*/
static VALUE
ossl_fips_mode_get(VALUE self)
@@ -408,10 +472,10 @@ ossl_fips_mode_get(VALUE self)
/*
* call-seq:
- * OpenSSL.fips_mode = boolean -> boolean
+ * OpenSSL.fips_mode = boolean
*
* Turns FIPS mode on or off. Turning on FIPS mode will obviously only have an
- * effect for FIPS-capable installations of the OpenSSL library. Trying to do
+ * effect for FIPS-capable installations of the \OpenSSL library. Trying to do
* so otherwise will result in an error.
*
* === Examples
@@ -434,52 +498,60 @@ ossl_fips_mode_set(VALUE self, VALUE enabled)
return enabled;
#elif defined(OPENSSL_FIPS) || defined(OPENSSL_IS_AWSLC)
if (RTEST(enabled)) {
- int mode = FIPS_mode();
- if(!mode && !FIPS_mode_set(1)) /* turning on twice leads to an error */
- ossl_raise(eOSSLError, "Turning on FIPS mode failed");
+ int mode = FIPS_mode();
+ if(!mode && !FIPS_mode_set(1)) /* turning on twice leads to an error */
+ ossl_raise(eOSSLError, "Turning on FIPS mode failed");
} else {
- if(!FIPS_mode_set(0)) /* turning off twice is OK */
- ossl_raise(eOSSLError, "Turning off FIPS mode failed");
+ if(!FIPS_mode_set(0)) /* turning off twice is OK */
+ ossl_raise(eOSSLError, "Turning off FIPS mode failed");
}
return enabled;
#else
if (RTEST(enabled))
- ossl_raise(eOSSLError, "This version of OpenSSL does not support FIPS mode");
+ ossl_raise(eOSSLError, "This version of OpenSSL does not support FIPS mode");
return enabled;
#endif
}
/*
* call-seq:
- * OpenSSL.fixed_length_secure_compare(string, string) -> boolean
+ * OpenSSL.fixed_length_secure_compare(string, string) -> true or false
*
* Constant time memory comparison for fixed length strings, such as results
- * of HMAC calculations.
+ * of \HMAC calculations.
*
* Returns +true+ if the strings are identical, +false+ if they are of the same
- * length but not identical. If the length is different, +ArgumentError+ is
+ * length but not identical. If the length is different, ArgumentError is
* raised.
*/
static VALUE
ossl_crypto_fixed_length_secure_compare(VALUE dummy, VALUE str1, VALUE str2)
{
- const unsigned char *p1 = (const unsigned char *)StringValuePtr(str1);
- const unsigned char *p2 = (const unsigned char *)StringValuePtr(str2);
- long len1 = RSTRING_LEN(str1);
- long len2 = RSTRING_LEN(str2);
+ const unsigned char *p1;
+ const unsigned char *p2;
+ long len1;
+ long len2;
+
+ StringValue(str1);
+ StringValue(str2);
+
+ p1 = (const unsigned char *)RSTRING_PTR(str1);
+ p2 = (const unsigned char *)RSTRING_PTR(str2);
+ len1 = RSTRING_LEN(str1);
+ len2 = RSTRING_LEN(str2);
if (len1 != len2) {
ossl_raise(rb_eArgError, "inputs must be of equal length");
}
switch (CRYPTO_memcmp(p1, p2, len1)) {
- case 0: return Qtrue;
- default: return Qfalse;
+ case 0: return Qtrue;
+ default: return Qfalse;
}
}
/*
- * OpenSSL provides SSL, TLS and general purpose cryptography. It wraps the
+ * OpenSSL provides \SSL, TLS and general purpose cryptography. It wraps the
* OpenSSL[https://www.openssl.org/] library.
*
* = Examples
@@ -534,7 +606,7 @@ 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.
+ * \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
* loading the key:
*
@@ -597,7 +669,7 @@ ossl_crypto_fixed_length_secure_compare(VALUE dummy, VALUE str1, VALUE str2)
*
* == PBKDF2 Password-based Encryption
*
- * If supported by the underlying OpenSSL version used, Password-based
+ * If supported by the underlying \OpenSSL version used, Password-based
* Encryption should use the features of PKCS5. If not supported or if
* required by legacy applications, the older, less secure methods specified
* in RFC 2898 are also supported (see below).
@@ -656,7 +728,7 @@ ossl_crypto_fixed_length_secure_compare(VALUE dummy, VALUE str1, VALUE str2)
* decrypted = cipher.update encrypted
* decrypted << cipher.final
*
- * == X509 Certificates
+ * == \X509 Certificates
*
* === Creating a Certificate
*
@@ -693,7 +765,7 @@ ossl_crypto_fixed_length_secure_compare(VALUE dummy, VALUE str1, VALUE str2)
* extension_factory.create_extension('subjectKeyIdentifier', 'hash')
*
* The list of supported extensions (and in some cases their possible values)
- * can be derived from the "objects.h" file in the OpenSSL source code.
+ * can be derived from the "objects.h" file in the \OpenSSL source code.
*
* === Signing a Certificate
*
@@ -847,23 +919,23 @@ ossl_crypto_fixed_length_secure_compare(VALUE dummy, VALUE str1, VALUE str2)
* io.write csr_cert.to_pem
* end
*
- * == SSL and TLS Connections
+ * == \SSL and TLS Connections
*
- * Using our created key and certificate we can create an SSL or TLS connection.
- * An SSLContext is used to set up an SSL session.
+ * Using our created key and certificate we can create an \SSL or TLS
+ * connection. An OpenSSL::SSL::SSLContext is used to set up an \SSL session.
*
* context = OpenSSL::SSL::SSLContext.new
*
- * === SSL Server
+ * === \SSL Server
*
- * An SSL server requires the certificate and private key to communicate
+ * An \SSL server requires the certificate and private key to communicate
* securely with its clients:
*
* context.cert = cert
* context.key = key
*
- * Then create an SSLServer with a TCP server socket and the context. Use the
- * SSLServer like an ordinary TCP server.
+ * Then create an OpenSSL::SSL::SSLServer with a TCP server socket and the
+ * context. Use the SSLServer like an ordinary TCP server.
*
* require 'socket'
*
@@ -882,14 +954,15 @@ ossl_crypto_fixed_length_secure_compare(VALUE dummy, VALUE str1, VALUE str2)
* ssl_connection.close
* end
*
- * === SSL client
+ * === \SSL client
*
- * An SSL client is created with a TCP socket and the context.
- * SSLSocket#connect must be called to initiate the SSL handshake and start
- * encryption. A key and certificate are not required for the client socket.
+ * An \SSL client is created with a TCP socket and the context.
+ * OpenSSL::SSL::SSLSocket#connect must be called to initiate the \SSL handshake
+ * and start encryption. A key and certificate are not required for the client
+ * socket.
*
- * Note that SSLSocket#close doesn't close the underlying socket by default. Set
- * SSLSocket#sync_close to true if you want.
+ * Note that OpenSSL::SSL::SSLSocket#close doesn't close the underlying socket
+ * by default. Set OpenSSL::SSL::SSLSocket#sync_close to true if you want.
*
* require 'socket'
*
@@ -905,7 +978,7 @@ ossl_crypto_fixed_length_secure_compare(VALUE dummy, VALUE str1, VALUE str2)
*
* === Peer Verification
*
- * An unverified SSL connection does not provide much security. For enhanced
+ * An unverified \SSL connection does not provide much security. For enhanced
* security the client or server can verify the certificate of its peer.
*
* The client can be modified to verify the server's certificate against the
@@ -956,22 +1029,34 @@ Init_openssl(void)
rb_define_singleton_method(mOSSL, "fixed_length_secure_compare", ossl_crypto_fixed_length_secure_compare, 2);
/*
- * Version of OpenSSL the ruby OpenSSL extension was built with
+ * \OpenSSL library version string used to compile the Ruby/OpenSSL
+ * extension. This may differ from the version used at runtime.
*/
- rb_define_const(mOSSL, "OPENSSL_VERSION", rb_str_new2(OPENSSL_VERSION_TEXT));
+ rb_define_const(mOSSL, "OPENSSL_VERSION",
+ rb_obj_freeze(rb_str_new_cstr(OPENSSL_VERSION_TEXT)));
/*
- * Version of OpenSSL the ruby OpenSSL extension is running with
+ * \OpenSSL library version string currently used at runtime.
*/
- rb_define_const(mOSSL, "OPENSSL_LIBRARY_VERSION", rb_str_new2(OpenSSL_version(OPENSSL_VERSION)));
+ rb_define_const(
+ mOSSL,
+ "OPENSSL_LIBRARY_VERSION",
+ rb_obj_freeze(rb_str_new_cstr(OpenSSL_version(OPENSSL_VERSION)))
+ );
/*
- * Version number of OpenSSL the ruby OpenSSL extension was built with
- * (base 16). The formats are below.
+ * \OpenSSL library version number used to compile the Ruby/OpenSSL
+ * extension. This may differ from the version used at runtime.
+ *
+ * The version number is encoded into a single integer value. The number
+ * follows the format:
*
- * [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>
+ * [\OpenSSL 3.0.0 or later]
+ * <tt>0xMNN00PP0</tt> (major minor 00 patch 0)
+ * [\OpenSSL 1.1.1 or earlier]
+ * <tt>0xMNNFFPPS</tt> (major minor fix patch status)
+ * [LibreSSL]
+ * <tt>0x20000000</tt> (a fixed value)
*
* See also the man page OPENSSL_VERSION_NUMBER(3).
*/
@@ -979,9 +1064,12 @@ Init_openssl(void)
#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.
+ * LibreSSL library version number used to compile the Ruby/OpenSSL
+ * extension. This may differ from the version used at runtime.
+ *
+ * This constant is only defined if the extension was compiled against
+ * LibreSSL. The number follows the format:
+ * <tt>0xMNNFF00f</tt> (major minor fix 00 status).
*
* See also the man page LIBRESSL_VERSION_NUMBER(3).
*/
@@ -989,30 +1077,50 @@ Init_openssl(void)
#endif
/*
- * Boolean indicating whether OpenSSL is FIPS-capable or not
+ * Boolean indicating whether the \OpenSSL library is FIPS-capable or not.
+ * Always <tt>true</tt> for \OpenSSL 3.0 and later.
+ *
+ * This is obsolete and will be removed in the future.
+ * See also OpenSSL.fips_mode.
*/
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)
- Qtrue
+ Qtrue
#elif defined(OPENSSL_IS_AWSLC) // AWS-LC FIPS can only be enabled during compile time.
- FIPS_mode() ? Qtrue : Qfalse
+ FIPS_mode() ? Qtrue : Qfalse
#else
- Qfalse
+ Qfalse
#endif
- );
+ );
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
+ * Generic error class for OpenSSL. All error classes in this library
+ * inherit from this class.
+ *
+ * This class indicates that an error was reported by the underlying
+ * \OpenSSL library.
+ */
+ eOSSLError = rb_define_class_under(mOSSL, "OpenSSLError", rb_eStandardError);
+ /*
+ * \OpenSSL error queue entries captured at the time the exception was
+ * raised. The same information is printed to stderr if OpenSSL.debug is
+ * set to +true+.
+ *
+ * This is an array of zero or more strings, ordered from the oldest to the
+ * newest. The format of the strings is not stable and may vary across
+ * versions of \OpenSSL or versions of this Ruby extension.
+ *
+ * See also the man page ERR_get_error(3).
*/
- eOSSLError = rb_define_class_under(mOSSL,"OpenSSLError",rb_eStandardError);
+ rb_attr(eOSSLError, rb_intern_const("errors"), 1, 0, 0);
+ rb_define_method(eOSSLError, "detailed_message", osslerror_detailed_message, -1);
/*
* Init debug core
@@ -1028,6 +1136,7 @@ Init_openssl(void)
* Get ID of to_der
*/
ossl_s_to_der = rb_intern("to_der");
+ id_i_errors = rb_intern("@errors");
/*
* Init components
diff --git a/ext/openssl/ossl.h b/ext/openssl/ossl.h
index 22471d2085..0b479a7200 100644
--- a/ext/openssl/ossl.h
+++ b/ext/openssl/ossl.h
@@ -74,6 +74,10 @@
# include <openssl/provider.h>
#endif
+#if OSSL_OPENSSL_PREREQ(3, 0, 0)
+# define OSSL_HAVE_IMMUTABLE_PKEY
+#endif
+
/*
* Common Module
*/
@@ -88,10 +92,10 @@ extern VALUE eOSSLError;
* CheckTypes
*/
#define OSSL_Check_Kind(obj, klass) do {\
- if (!rb_obj_is_kind_of((obj), (klass))) {\
- ossl_raise(rb_eTypeError, "wrong argument (%"PRIsVALUE")! (Expected kind of %"PRIsVALUE")",\
- rb_obj_class(obj), (klass));\
- }\
+ if (!rb_obj_is_kind_of((obj), (klass))) {\
+ ossl_raise(rb_eTypeError, "wrong argument (%"PRIsVALUE")! (Expected kind of %"PRIsVALUE")",\
+ rb_obj_class(obj), (klass));\
+ }\
} while (0)
/*
@@ -127,7 +131,7 @@ do{\
* Convert binary string to hex string. The caller is responsible for
* ensuring out has (2 * len) bytes of capacity.
*/
-void ossl_bin2hex(unsigned char *in, char *out, size_t len);
+void ossl_bin2hex(const unsigned char *in, char *out, size_t len);
/*
* Our default PEM callback
@@ -170,11 +174,11 @@ VALUE ossl_to_der_if_possible(VALUE);
extern VALUE dOSSL;
#define OSSL_Debug(...) do { \
- if (dOSSL == Qtrue) { \
- fprintf(stderr, "OSSL_DEBUG: "); \
- fprintf(stderr, __VA_ARGS__); \
- fprintf(stderr, " [%s:%d]\n", __FILE__, __LINE__); \
- } \
+ if (dOSSL == Qtrue) { \
+ fprintf(stderr, "OSSL_DEBUG: "); \
+ fprintf(stderr, __VA_ARGS__); \
+ fprintf(stderr, " [%s:%d]\n", __FILE__, __LINE__); \
+ } \
} while (0)
/*
diff --git a/ext/openssl/ossl_asn1.c b/ext/openssl/ossl_asn1.c
index 186679da4c..517212b4d5 100644
--- a/ext/openssl/ossl_asn1.c
+++ b/ext/openssl/ossl_asn1.c
@@ -9,63 +9,81 @@
*/
#include "ossl.h"
-static VALUE ossl_asn1_decode0(unsigned char **pp, long length, long *offset,
- int depth, int yield, long *num_read);
+/********/
+/*
+ * ASN1 module
+ */
+#define ossl_asn1_get_value(o) rb_attr_get((o),sivVALUE)
+#define ossl_asn1_get_tag(o) rb_attr_get((o),sivTAG)
+#define ossl_asn1_get_tagging(o) rb_attr_get((o),sivTAGGING)
+#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;
+static VALUE eASN1Error;
+
+VALUE cASN1Data;
+static VALUE cASN1Primitive;
+static VALUE cASN1Constructive;
+
+static VALUE cASN1EndOfContent;
+static VALUE cASN1Boolean; /* BOOLEAN */
+static VALUE cASN1Integer, cASN1Enumerated; /* INTEGER */
+static VALUE cASN1BitString; /* BIT STRING */
+static VALUE cASN1OctetString, cASN1UTF8String; /* STRINGs */
+static VALUE cASN1NumericString, cASN1PrintableString;
+static VALUE cASN1T61String, cASN1VideotexString;
+static VALUE cASN1IA5String, cASN1GraphicString;
+static VALUE cASN1ISO64String, cASN1GeneralString;
+static VALUE cASN1UniversalString, cASN1BMPString;
+static VALUE cASN1Null; /* NULL */
+static VALUE cASN1ObjectId; /* OBJECT IDENTIFIER */
+static VALUE cASN1UTCTime, cASN1GeneralizedTime; /* TIME */
+static 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;
/*
* DATE conversion
*/
+static VALUE
+time_utc_new(VALUE args)
+{
+ return rb_funcallv(rb_cTime, rb_intern("utc"), 6, (VALUE *)args);
+}
+
+static VALUE
+time_utc_new_rescue(VALUE args, VALUE exc)
+{
+ rb_raise(eASN1Error, "invalid time");
+}
+
VALUE
asn1time_to_time(const ASN1_TIME *time)
{
struct tm tm;
- VALUE argv[6];
- int count;
-
- memset(&tm, 0, sizeof(struct tm));
-
- switch (time->type) {
- case V_ASN1_UTCTIME:
- count = sscanf((const char *)time->data, "%2d%2d%2d%2d%2d%2dZ",
- &tm.tm_year, &tm.tm_mon, &tm.tm_mday, &tm.tm_hour, &tm.tm_min,
- &tm.tm_sec);
-
- if (count == 5) {
- tm.tm_sec = 0;
- } else if (count != 6) {
- ossl_raise(rb_eTypeError, "bad UTCTIME format: \"%s\"",
- time->data);
- }
- if (tm.tm_year < 50) {
- tm.tm_year += 2000;
- } else {
- tm.tm_year += 1900;
- }
- break;
- case V_ASN1_GENERALIZEDTIME:
- count = sscanf((const char *)time->data, "%4d%2d%2d%2d%2d%2dZ",
- &tm.tm_year, &tm.tm_mon, &tm.tm_mday, &tm.tm_hour, &tm.tm_min,
- &tm.tm_sec);
- if (count == 5) {
- tm.tm_sec = 0;
- }
- else if (count != 6) {
- ossl_raise(rb_eTypeError, "bad GENERALIZEDTIME format: \"%s\"",
- time->data);
- }
- break;
- default:
- rb_warning("unknown time format");
- return Qnil;
- }
- argv[0] = INT2NUM(tm.tm_year);
- argv[1] = INT2NUM(tm.tm_mon);
- argv[2] = INT2NUM(tm.tm_mday);
- argv[3] = INT2NUM(tm.tm_hour);
- argv[4] = INT2NUM(tm.tm_min);
- argv[5] = INT2NUM(tm.tm_sec);
-
- return rb_funcall2(rb_cTime, rb_intern("utc"), 6, argv);
+ if (!ASN1_TIME_to_tm(time, &tm))
+ ossl_raise(eASN1Error, "ASN1_TIME_to_tm");
+
+ VALUE args[] = {
+ INT2NUM(tm.tm_year + 1900),
+ INT2NUM(tm.tm_mon + 1),
+ INT2NUM(tm.tm_mday),
+ INT2NUM(tm.tm_hour),
+ INT2NUM(tm.tm_min),
+ INT2NUM(tm.tm_sec),
+ };
+ return rb_rescue2(time_utc_new, (VALUE)args, time_utc_new_rescue, Qnil,
+ rb_eArgError, 0);
}
static VALUE
@@ -80,13 +98,13 @@ ossl_time_split(VALUE time, time_t *sec, int *days)
VALUE num = rb_Integer(time);
if (FIXNUM_P(num)) {
- time_t t = FIX2LONG(num);
- *sec = t % 86400;
- *days = rb_long2int(t / 86400);
+ time_t t = FIX2LONG(num);
+ *sec = t % 86400;
+ *days = rb_long2int(t / 86400);
}
else {
- *days = NUM2INT(rb_funcall(num, rb_intern("/"), 1, INT2FIX(86400)));
- *sec = NUM2TIMET(rb_funcall(num, rb_intern("%"), 1, INT2FIX(86400)));
+ *days = NUM2INT(rb_funcall(num, rb_intern("/"), 1, INT2FIX(86400)));
+ *sec = NUM2TIMET(rb_funcall(num, rb_intern("%"), 1, INT2FIX(86400)));
}
}
@@ -96,7 +114,8 @@ ossl_time_split(VALUE time, time_t *sec, int *days)
VALUE
asn1str_to_str(const ASN1_STRING *str)
{
- return rb_str_new((const char *)str->data, str->length);
+ return rb_str_new((const char *)ASN1_STRING_get0_data(str),
+ ASN1_STRING_length(str));
}
/*
@@ -109,18 +128,19 @@ asn1integer_to_num(const ASN1_INTEGER *ai)
VALUE num;
if (!ai) {
- ossl_raise(rb_eTypeError, "ASN1_INTEGER is NULL!");
+ ossl_raise(rb_eTypeError, "ASN1_INTEGER is NULL!");
}
- if (ai->type == V_ASN1_ENUMERATED)
- /* const_cast: workaround for old OpenSSL */
- bn = ASN1_ENUMERATED_to_BN((ASN1_ENUMERATED *)ai, NULL);
+
+ num = ossl_bn_new(BN_value_one());
+ bn = GetBNPtr(num);
+
+ if (ASN1_STRING_type(ai) == V_ASN1_ENUMERATED)
+ bn = ASN1_ENUMERATED_to_BN(ai, bn);
else
- bn = ASN1_INTEGER_to_BN(ai, NULL);
+ bn = ASN1_INTEGER_to_BN(ai, bn);
if (!bn)
- ossl_raise(eOSSLError, NULL);
- num = ossl_bn_new(bn);
- BN_free(bn);
+ ossl_raise(eOSSLError, NULL);
return num;
}
@@ -131,12 +151,12 @@ num_to_asn1integer(VALUE obj, ASN1_INTEGER *ai)
BIGNUM *bn;
if (NIL_P(obj))
- ossl_raise(rb_eTypeError, "Can't convert nil into Integer");
+ ossl_raise(rb_eTypeError, "Can't convert nil into Integer");
bn = GetBNPtr(obj);
if (!(ai = BN_to_ASN1_INTEGER(bn, ai)))
- ossl_raise(eOSSLError, NULL);
+ ossl_raise(eOSSLError, NULL);
return ai;
}
@@ -147,43 +167,47 @@ asn1integer_to_num_i(VALUE arg)
return asn1integer_to_num((ASN1_INTEGER *)arg);
}
-/********/
/*
- * ASN1 module
+ * ASN1_OBJECT conversions
*/
-#define ossl_asn1_get_value(o) rb_attr_get((o),sivVALUE)
-#define ossl_asn1_get_tag(o) rb_attr_get((o),sivTAG)
-#define ossl_asn1_get_tagging(o) rb_attr_get((o),sivTAGGING)
-#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_indefinite_length(o,v) rb_ivar_set((o),sivINDEFINITE_LENGTH,(v))
-
-VALUE mASN1;
-VALUE eASN1Error;
+VALUE
+ossl_asn1obj_to_string_oid(const ASN1_OBJECT *a1obj)
+{
+ VALUE str;
+ int len;
-VALUE cASN1Data;
-static VALUE cASN1Primitive;
-static VALUE cASN1Constructive;
+ str = rb_usascii_str_new(NULL, 127);
+ len = OBJ_obj2txt(RSTRING_PTR(str), RSTRING_LENINT(str), a1obj, 1);
+ if (len <= 0 || len == INT_MAX)
+ ossl_raise(eOSSLError, "OBJ_obj2txt");
+ if (len > RSTRING_LEN(str)) {
+ /* +1 is for the \0 terminator added by OBJ_obj2txt() */
+ rb_str_resize(str, len + 1);
+ len = OBJ_obj2txt(RSTRING_PTR(str), len + 1, a1obj, 1);
+ if (len <= 0)
+ ossl_raise(eOSSLError, "OBJ_obj2txt");
+ }
+ rb_str_set_len(str, len);
+ return str;
+}
-static VALUE cASN1EndOfContent;
-static VALUE cASN1Boolean; /* BOOLEAN */
-static VALUE cASN1Integer, cASN1Enumerated; /* INTEGER */
-static VALUE cASN1BitString; /* BIT STRING */
-static VALUE cASN1OctetString, cASN1UTF8String; /* STRINGs */
-static VALUE cASN1NumericString, cASN1PrintableString;
-static VALUE cASN1T61String, cASN1VideotexString;
-static VALUE cASN1IA5String, cASN1GraphicString;
-static VALUE cASN1ISO64String, cASN1GeneralString;
-static VALUE cASN1UniversalString, cASN1BMPString;
-static VALUE cASN1Null; /* NULL */
-static VALUE cASN1ObjectId; /* OBJECT IDENTIFIER */
-static VALUE cASN1UTCTime, cASN1GeneralizedTime; /* TIME */
-static VALUE cASN1Sequence, cASN1Set; /* CONSTRUCTIVE */
+VALUE
+ossl_asn1obj_to_string(const ASN1_OBJECT *obj)
+{
+ int nid = OBJ_obj2nid(obj);
+ if (nid != NID_undef)
+ return rb_str_new_cstr(OBJ_nid2sn(nid));
+ return ossl_asn1obj_to_string_oid(obj);
+}
-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;
+VALUE
+ossl_asn1obj_to_string_long_name(const ASN1_OBJECT *obj)
+{
+ int nid = OBJ_obj2nid(obj);
+ if (nid != NID_undef)
+ return rb_str_new_cstr(OBJ_nid2ln(nid));
+ return ossl_asn1obj_to_string_oid(obj);
+}
/*
* Ruby to ASN1 converters
@@ -192,9 +216,9 @@ static ASN1_BOOLEAN
obj_to_asn1bool(VALUE obj)
{
if (NIL_P(obj))
- ossl_raise(rb_eTypeError, "Can't convert nil into Boolean");
+ ossl_raise(rb_eTypeError, "Can't convert nil into Boolean");
- return RTEST(obj) ? 0xff : 0x0;
+ return RTEST(obj) ? 0xff : 0x0;
}
static ASN1_INTEGER*
@@ -204,19 +228,19 @@ obj_to_asn1int(VALUE obj)
}
static ASN1_BIT_STRING*
-obj_to_asn1bstr(VALUE obj, long unused_bits)
+obj_to_asn1bstr(VALUE obj, int unused_bits)
{
ASN1_BIT_STRING *bstr;
if (unused_bits < 0 || unused_bits > 7)
- ossl_raise(eASN1Error, "unused_bits for a bitstring value must be in "\
- "the range 0 to 7");
+ ossl_raise(eASN1Error, "unused_bits for a bitstring value must be in "\
+ "the range 0 to 7");
StringValue(obj);
- if(!(bstr = ASN1_BIT_STRING_new()))
- ossl_raise(eASN1Error, NULL);
- ASN1_BIT_STRING_set(bstr, (unsigned char *)RSTRING_PTR(obj), RSTRING_LENINT(obj));
- bstr->flags &= ~(ASN1_STRING_FLAG_BITS_LEFT|0x07); /* clear */
- bstr->flags |= ASN1_STRING_FLAG_BITS_LEFT | unused_bits;
+ if (!(bstr = ASN1_BIT_STRING_new()))
+ ossl_raise(eASN1Error, "ASN1_BIT_STRING_new");
+ if (!ASN1_BIT_STRING_set1(bstr, (uint8_t *)RSTRING_PTR(obj),
+ RSTRING_LEN(obj), unused_bits))
+ ossl_raise(eASN1Error, "ASN1_BIT_STRING_set1");
return bstr;
}
@@ -228,8 +252,11 @@ obj_to_asn1str(VALUE obj)
StringValue(obj);
if(!(str = ASN1_STRING_new()))
- ossl_raise(eASN1Error, NULL);
- ASN1_STRING_set(str, RSTRING_PTR(obj), RSTRING_LENINT(obj));
+ ossl_raise(eASN1Error, NULL);
+ if(!ASN1_STRING_set(str, RSTRING_PTR(obj), RSTRING_LENINT(obj))) {
+ ASN1_STRING_free(str);
+ ossl_raise(eASN1Error, NULL);
+ }
return str;
}
@@ -240,15 +267,15 @@ obj_to_asn1null(VALUE obj)
ASN1_NULL *null;
if(!NIL_P(obj))
- ossl_raise(eASN1Error, "nil expected");
+ ossl_raise(eASN1Error, "nil expected");
if(!(null = ASN1_NULL_new()))
- ossl_raise(eASN1Error, NULL);
+ ossl_raise(eASN1Error, NULL);
return null;
}
-static ASN1_OBJECT*
-obj_to_asn1obj(VALUE obj)
+ASN1_OBJECT *
+ossl_to_asn1obj(VALUE obj)
{
ASN1_OBJECT *a1obj;
@@ -270,7 +297,7 @@ obj_to_asn1utime(VALUE time)
ossl_time_split(time, &sec, &off_days);
if (!(t = ASN1_UTCTIME_adj(NULL, sec, off_days, 0)))
- ossl_raise(eASN1Error, NULL);
+ ossl_raise(eASN1Error, NULL);
return t;
}
@@ -285,7 +312,7 @@ obj_to_asn1gtime(VALUE time)
ossl_time_split(time, &sec, &off_days);
if (!(t = ASN1_GENERALIZEDTIME_adj(NULL, sec, off_days, 0)))
- ossl_raise(eASN1Error, NULL);
+ ossl_raise(eASN1Error, NULL);
return t;
}
@@ -298,8 +325,11 @@ obj_to_asn1derstr(VALUE obj)
str = ossl_to_der(obj);
if(!(a1str = ASN1_STRING_new()))
- ossl_raise(eASN1Error, NULL);
- ASN1_STRING_set(a1str, RSTRING_PTR(str), RSTRING_LENINT(str));
+ ossl_raise(eASN1Error, NULL);
+ if(!ASN1_STRING_set(a1str, RSTRING_PTR(str), RSTRING_LENINT(str))) {
+ ASN1_STRING_free(a1str);
+ ossl_raise(eASN1Error, NULL);
+ }
return a1str;
}
@@ -313,9 +343,9 @@ decode_bool(unsigned char* der, long length)
const unsigned char *p = der;
if (length != 3)
- ossl_raise(eASN1Error, "invalid length for BOOLEAN");
+ ossl_raise(eASN1Error, "invalid length for BOOLEAN");
if (p[0] != 1 || p[1] != 1)
- ossl_raise(eASN1Error, "invalid BOOLEAN");
+ ossl_raise(eASN1Error, "invalid BOOLEAN");
return p[2] ? Qtrue : Qfalse;
}
@@ -330,9 +360,9 @@ decode_int(unsigned char* der, long length)
p = der;
if(!(ai = d2i_ASN1_INTEGER(NULL, &p, length)))
- ossl_raise(eASN1Error, NULL);
+ ossl_raise(eASN1Error, NULL);
ret = rb_protect(asn1integer_to_num_i,
- (VALUE)ai, &status);
+ (VALUE)ai, &status);
ASN1_INTEGER_free(ai);
if(status) rb_jump_tag(status);
@@ -340,22 +370,25 @@ decode_int(unsigned char* der, long length)
}
static VALUE
-decode_bstr(unsigned char* der, long length, long *unused_bits)
+decode_bstr(unsigned char* der, long length, int *unused_bits)
{
ASN1_BIT_STRING *bstr;
const unsigned char *p;
- long len;
+ size_t len;
VALUE ret;
+ int state;
p = der;
- if(!(bstr = d2i_ASN1_BIT_STRING(NULL, &p, length)))
- ossl_raise(eASN1Error, NULL);
- len = bstr->length;
- *unused_bits = 0;
- if(bstr->flags & ASN1_STRING_FLAG_BITS_LEFT)
- *unused_bits = bstr->flags & 0x07;
- ret = rb_str_new((const char *)bstr->data, len);
+ if (!(bstr = d2i_ASN1_BIT_STRING(NULL, &p, length)))
+ ossl_raise(eASN1Error, "d2i_ASN1_BIT_STRING");
+ if (!ASN1_BIT_STRING_get_length(bstr, &len, unused_bits)) {
+ ASN1_BIT_STRING_free(bstr);
+ ossl_raise(eASN1Error, "ASN1_BIT_STRING_get_length");
+ }
+ ret = ossl_str_new((const char *)ASN1_STRING_get0_data(bstr), len, &state);
ASN1_BIT_STRING_free(bstr);
+ if (state)
+ rb_jump_tag(state);
return ret;
}
@@ -370,9 +403,9 @@ decode_enum(unsigned char* der, long length)
p = der;
if(!(ai = d2i_ASN1_ENUMERATED(NULL, &p, length)))
- ossl_raise(eASN1Error, NULL);
+ ossl_raise(eASN1Error, NULL);
ret = rb_protect(asn1integer_to_num_i,
- (VALUE)ai, &status);
+ (VALUE)ai, &status);
ASN1_ENUMERATED_free(ai);
if(status) rb_jump_tag(status);
@@ -387,38 +420,33 @@ decode_null(unsigned char* der, long length)
p = der;
if(!(null = d2i_ASN1_NULL(NULL, &p, length)))
- ossl_raise(eASN1Error, NULL);
+ ossl_raise(eASN1Error, NULL);
ASN1_NULL_free(null);
return Qnil;
}
+VALUE
+asn1obj_to_string_i(VALUE arg)
+{
+ return ossl_asn1obj_to_string((const ASN1_OBJECT *)arg);
+}
+
static VALUE
decode_obj(unsigned char* der, long length)
{
ASN1_OBJECT *obj;
const unsigned char *p;
VALUE ret;
- int nid;
- BIO *bio;
+ int state;
p = der;
- if(!(obj = d2i_ASN1_OBJECT(NULL, &p, length)))
- ossl_raise(eASN1Error, NULL);
- if((nid = OBJ_obj2nid(obj)) != NID_undef){
- ASN1_OBJECT_free(obj);
- ret = rb_str_new2(OBJ_nid2sn(nid));
- }
- else{
- if(!(bio = BIO_new(BIO_s_mem()))){
- ASN1_OBJECT_free(obj);
- ossl_raise(eASN1Error, NULL);
- }
- i2a_ASN1_OBJECT(bio, obj);
- ASN1_OBJECT_free(obj);
- ret = ossl_membio2str(bio);
- }
-
+ if (!(obj = d2i_ASN1_OBJECT(NULL, &p, length)))
+ ossl_raise(eASN1Error, "d2i_ASN1_OBJECT");
+ ret = rb_protect(asn1obj_to_string_i, (VALUE)obj, &state);
+ ASN1_OBJECT_free(obj);
+ if (state)
+ rb_jump_tag(state);
return ret;
}
@@ -432,9 +460,9 @@ decode_time(unsigned char* der, long length)
p = der;
if(!(time = d2i_ASN1_TIME(NULL, &p, length)))
- ossl_raise(eASN1Error, NULL);
+ ossl_raise(eASN1Error, NULL);
ret = rb_protect(asn1time_to_time_i,
- (VALUE)time, &status);
+ (VALUE)time, &status);
ASN1_TIME_free(time);
if(status) rb_jump_tag(status);
@@ -445,7 +473,7 @@ static VALUE
decode_eoc(unsigned char *der, long length)
{
if (length != 2 || !(der[0] == 0x00 && der[1] == 0x00))
- ossl_raise(eASN1Error, NULL);
+ ossl_raise(eASN1Error, NULL);
return rb_str_new("", 0);
}
@@ -510,62 +538,62 @@ ossl_asn1_get_asn1type(VALUE obj)
tag = ossl_asn1_default_tag(obj);
value = ossl_asn1_get_value(obj);
switch(tag){
- case V_ASN1_BOOLEAN:
- ptr = (void*)(VALUE)obj_to_asn1bool(value);
- free_func = NULL;
- break;
- case V_ASN1_INTEGER: /* FALLTHROUGH */
- case V_ASN1_ENUMERATED:
- ptr = obj_to_asn1int(value);
- free_func = (free_func_type *)ASN1_INTEGER_free;
- break;
- case V_ASN1_BIT_STRING:
+ case V_ASN1_BOOLEAN:
+ ptr = (void*)(VALUE)obj_to_asn1bool(value);
+ free_func = NULL;
+ break;
+ case V_ASN1_INTEGER: /* FALLTHROUGH */
+ case V_ASN1_ENUMERATED:
+ ptr = obj_to_asn1int(value);
+ free_func = (free_func_type *)ASN1_INTEGER_free;
+ break;
+ case V_ASN1_BIT_STRING:
rflag = rb_attr_get(obj, sivUNUSED_BITS);
- ptr = obj_to_asn1bstr(value, NUM2INT(rflag));
- free_func = (free_func_type *)ASN1_BIT_STRING_free;
- break;
- case V_ASN1_NULL:
- ptr = obj_to_asn1null(value);
- free_func = (free_func_type *)ASN1_NULL_free;
- break;
- case V_ASN1_OCTET_STRING: /* FALLTHROUGH */
- case V_ASN1_UTF8STRING: /* FALLTHROUGH */
- case V_ASN1_NUMERICSTRING: /* FALLTHROUGH */
- case V_ASN1_PRINTABLESTRING: /* FALLTHROUGH */
- case V_ASN1_T61STRING: /* FALLTHROUGH */
- case V_ASN1_VIDEOTEXSTRING: /* FALLTHROUGH */
- case V_ASN1_IA5STRING: /* FALLTHROUGH */
- case V_ASN1_GRAPHICSTRING: /* FALLTHROUGH */
- case V_ASN1_ISO64STRING: /* FALLTHROUGH */
- case V_ASN1_GENERALSTRING: /* FALLTHROUGH */
- case V_ASN1_UNIVERSALSTRING: /* FALLTHROUGH */
- case V_ASN1_BMPSTRING:
- ptr = obj_to_asn1str(value);
- free_func = (free_func_type *)ASN1_STRING_free;
- break;
- case V_ASN1_OBJECT:
- ptr = obj_to_asn1obj(value);
- free_func = (free_func_type *)ASN1_OBJECT_free;
- break;
- case V_ASN1_UTCTIME:
- ptr = obj_to_asn1utime(value);
- free_func = (free_func_type *)ASN1_TIME_free;
- break;
- case V_ASN1_GENERALIZEDTIME:
- ptr = obj_to_asn1gtime(value);
- free_func = (free_func_type *)ASN1_TIME_free;
- break;
- case V_ASN1_SET: /* FALLTHROUGH */
- case V_ASN1_SEQUENCE:
- ptr = obj_to_asn1derstr(obj);
- free_func = (free_func_type *)ASN1_STRING_free;
- break;
- default:
- ossl_raise(eASN1Error, "unsupported ASN.1 type");
+ ptr = obj_to_asn1bstr(value, NUM2INT(rflag));
+ free_func = (free_func_type *)ASN1_BIT_STRING_free;
+ break;
+ case V_ASN1_NULL:
+ ptr = obj_to_asn1null(value);
+ free_func = (free_func_type *)ASN1_NULL_free;
+ break;
+ case V_ASN1_OCTET_STRING: /* FALLTHROUGH */
+ case V_ASN1_UTF8STRING: /* FALLTHROUGH */
+ case V_ASN1_NUMERICSTRING: /* FALLTHROUGH */
+ case V_ASN1_PRINTABLESTRING: /* FALLTHROUGH */
+ case V_ASN1_T61STRING: /* FALLTHROUGH */
+ case V_ASN1_VIDEOTEXSTRING: /* FALLTHROUGH */
+ case V_ASN1_IA5STRING: /* FALLTHROUGH */
+ case V_ASN1_GRAPHICSTRING: /* FALLTHROUGH */
+ case V_ASN1_ISO64STRING: /* FALLTHROUGH */
+ case V_ASN1_GENERALSTRING: /* FALLTHROUGH */
+ case V_ASN1_UNIVERSALSTRING: /* FALLTHROUGH */
+ case V_ASN1_BMPSTRING:
+ ptr = obj_to_asn1str(value);
+ free_func = (free_func_type *)ASN1_STRING_free;
+ break;
+ case V_ASN1_OBJECT:
+ ptr = ossl_to_asn1obj(value);
+ free_func = (free_func_type *)ASN1_OBJECT_free;
+ break;
+ case V_ASN1_UTCTIME:
+ ptr = obj_to_asn1utime(value);
+ free_func = (free_func_type *)ASN1_TIME_free;
+ break;
+ case V_ASN1_GENERALIZEDTIME:
+ ptr = obj_to_asn1gtime(value);
+ free_func = (free_func_type *)ASN1_TIME_free;
+ break;
+ case V_ASN1_SET: /* FALLTHROUGH */
+ case V_ASN1_SEQUENCE:
+ ptr = obj_to_asn1derstr(obj);
+ free_func = (free_func_type *)ASN1_STRING_free;
+ break;
+ default:
+ ossl_raise(eASN1Error, "unsupported ASN.1 type");
}
if(!(ret = OPENSSL_malloc(sizeof(ASN1_TYPE)))){
- if(free_func) free_func(ptr);
- ossl_raise(eASN1Error, "ASN1_TYPE alloc failure");
+ if(free_func) free_func(ptr);
+ ossl_raise(eASN1Error, "ASN1_TYPE alloc failure");
}
memset(ret, 0, sizeof(ASN1_TYPE));
ASN1_TYPE_set(ret, tag, ptr);
@@ -580,10 +608,10 @@ ossl_asn1_default_tag(VALUE obj)
tmp_class = CLASS_OF(obj);
while (!NIL_P(tmp_class)) {
- tag = rb_hash_lookup(class_tag_map, tmp_class);
- if (tag != Qnil)
- return NUM2INT(tag);
- tmp_class = rb_class_superclass(tmp_class);
+ tag = rb_hash_lookup(class_tag_map, tmp_class);
+ if (tag != Qnil)
+ return NUM2INT(tag);
+ tmp_class = rb_class_superclass(tmp_class);
}
return -1;
@@ -596,7 +624,7 @@ ossl_asn1_tag(VALUE obj)
tag = ossl_asn1_get_tag(obj);
if(NIL_P(tag))
- ossl_raise(eASN1Error, "tag number not specified");
+ ossl_raise(eASN1Error, "tag number not specified");
return NUM2INT(tag);
}
@@ -608,28 +636,57 @@ ossl_asn1_tag_class(VALUE obj)
s = ossl_asn1_get_tag_class(obj);
if (NIL_P(s) || s == sym_UNIVERSAL)
- return V_ASN1_UNIVERSAL;
+ return V_ASN1_UNIVERSAL;
else if (s == sym_APPLICATION)
- return V_ASN1_APPLICATION;
+ return V_ASN1_APPLICATION;
else if (s == sym_CONTEXT_SPECIFIC)
- return V_ASN1_CONTEXT_SPECIFIC;
+ return V_ASN1_CONTEXT_SPECIFIC;
else if (s == sym_PRIVATE)
- return V_ASN1_PRIVATE;
+ return V_ASN1_PRIVATE;
else
- ossl_raise(eASN1Error, "invalid tag class");
+ ossl_raise(eASN1Error, "invalid tag class");
}
static VALUE
ossl_asn1_class2sym(int tc)
{
if((tc & V_ASN1_PRIVATE) == V_ASN1_PRIVATE)
- return sym_PRIVATE;
+ return sym_PRIVATE;
else if((tc & V_ASN1_CONTEXT_SPECIFIC) == V_ASN1_CONTEXT_SPECIFIC)
- return sym_CONTEXT_SPECIFIC;
+ return sym_CONTEXT_SPECIFIC;
else if((tc & V_ASN1_APPLICATION) == V_ASN1_APPLICATION)
- return sym_APPLICATION;
+ return sym_APPLICATION;
else
- return sym_UNIVERSAL;
+ 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
@@ -645,35 +702,35 @@ to_der_internal(VALUE self, int constructed, int indef_len, VALUE body)
body_length = RSTRING_LENINT(body);
if (ossl_asn1_get_tagging(self) == sym_EXPLICIT) {
- int inner_length, e_encoding = indef_len ? 2 : 1;
-
- if (default_tag_number == -1)
- ossl_raise(eASN1Error, "explicit tagging of unknown tag");
-
- inner_length = ASN1_object_size(encoding, body_length, default_tag_number);
- total_length = ASN1_object_size(e_encoding, inner_length, tag_number);
- str = rb_str_new(NULL, total_length);
- p = (unsigned char *)RSTRING_PTR(str);
- /* Put explicit tag */
- ASN1_put_object(&p, e_encoding, inner_length, tag_number, tag_class);
- /* Append inner object */
- ASN1_put_object(&p, encoding, body_length, default_tag_number, V_ASN1_UNIVERSAL);
- memcpy(p, RSTRING_PTR(body), body_length);
- p += body_length;
- if (indef_len) {
- ASN1_put_eoc(&p); /* For inner object */
- ASN1_put_eoc(&p); /* For wrapper object */
- }
+ int inner_length, e_encoding = indef_len ? 2 : 1;
+
+ if (default_tag_number == -1)
+ ossl_raise(eASN1Error, "explicit tagging of unknown tag");
+
+ inner_length = ASN1_object_size(encoding, body_length, default_tag_number);
+ total_length = ASN1_object_size(e_encoding, inner_length, tag_number);
+ str = rb_str_new(NULL, total_length);
+ p = (unsigned char *)RSTRING_PTR(str);
+ /* Put explicit tag */
+ ASN1_put_object(&p, e_encoding, inner_length, tag_number, tag_class);
+ /* Append inner object */
+ ASN1_put_object(&p, encoding, body_length, default_tag_number, V_ASN1_UNIVERSAL);
+ memcpy(p, RSTRING_PTR(body), body_length);
+ p += body_length;
+ if (indef_len) {
+ ASN1_put_eoc(&p); /* For inner object */
+ ASN1_put_eoc(&p); /* For wrapper object */
+ }
}
else {
- total_length = ASN1_object_size(encoding, body_length, tag_number);
- str = rb_str_new(NULL, total_length);
- p = (unsigned char *)RSTRING_PTR(str);
- ASN1_put_object(&p, encoding, body_length, tag_number, tag_class);
- memcpy(p, RSTRING_PTR(body), body_length);
- p += body_length;
- if (indef_len)
- ASN1_put_eoc(&p);
+ total_length = ASN1_object_size(encoding, body_length, tag_number);
+ str = rb_str_new(NULL, total_length);
+ p = (unsigned char *)RSTRING_PTR(str);
+ ASN1_put_object(&p, encoding, body_length, tag_number, tag_class);
+ memcpy(p, RSTRING_PTR(body), body_length);
+ p += body_length;
+ if (indef_len)
+ ASN1_put_eoc(&p);
}
assert(p - (unsigned char *)RSTRING_PTR(str) == total_length);
return str;
@@ -696,83 +753,88 @@ ossl_asn1data_to_der(VALUE self)
VALUE value = ossl_asn1_get_value(self);
if (rb_obj_is_kind_of(value, rb_cArray))
- return ossl_asn1cons_to_der(self);
+ return ossl_asn1cons_to_der(self);
else {
- if (RTEST(ossl_asn1_get_indefinite_length(self)))
- ossl_raise(eASN1Error, "indefinite length form cannot be used " \
- "with primitive encoding");
- return ossl_asn1prim_to_der(self);
+ if (RTEST(ossl_asn1_get_indefinite_length(self)))
+ ossl_raise(eASN1Error, "indefinite length form cannot be used " \
+ "with primitive encoding");
+ return ossl_asn1prim_to_der(self);
}
}
+static VALUE ossl_asn1_initialize(int argc, VALUE *argv, VALUE self);
+static VALUE ossl_asn1_decode0(unsigned char **pp, long length, long *offset,
+ int depth, int yield, long *num_read);
+
static VALUE
int_ossl_asn1_decode0_prim(unsigned char **pp, long length, long hlen, int tag,
- VALUE tc, long *num_read)
+ VALUE tc, long *num_read)
{
VALUE value, asn1data;
unsigned char *p;
- long flag = 0;
+ int flag = 0;
p = *pp;
if(tc == sym_UNIVERSAL && tag < ossl_asn1_info_size) {
- switch(tag){
- case V_ASN1_EOC:
- value = decode_eoc(p, hlen+length);
- break;
- case V_ASN1_BOOLEAN:
- value = decode_bool(p, hlen+length);
- break;
- case V_ASN1_INTEGER:
- value = decode_int(p, hlen+length);
- break;
- case V_ASN1_BIT_STRING:
- value = decode_bstr(p, hlen+length, &flag);
- break;
- case V_ASN1_NULL:
- value = decode_null(p, hlen+length);
- break;
- case V_ASN1_ENUMERATED:
- value = decode_enum(p, hlen+length);
- break;
- case V_ASN1_OBJECT:
- value = decode_obj(p, hlen+length);
- break;
- case V_ASN1_UTCTIME: /* FALLTHROUGH */
- case V_ASN1_GENERALIZEDTIME:
- value = decode_time(p, hlen+length);
- break;
- default:
- /* use original value */
- p += hlen;
- value = rb_str_new((const char *)p, length);
- break;
- }
+ switch(tag){
+ case V_ASN1_EOC:
+ value = decode_eoc(p, hlen+length);
+ break;
+ case V_ASN1_BOOLEAN:
+ value = decode_bool(p, hlen+length);
+ break;
+ case V_ASN1_INTEGER:
+ value = decode_int(p, hlen+length);
+ break;
+ case V_ASN1_BIT_STRING:
+ value = decode_bstr(p, hlen+length, &flag);
+ break;
+ case V_ASN1_NULL:
+ value = decode_null(p, hlen+length);
+ break;
+ case V_ASN1_ENUMERATED:
+ value = decode_enum(p, hlen+length);
+ break;
+ case V_ASN1_OBJECT:
+ value = decode_obj(p, hlen+length);
+ break;
+ case V_ASN1_UTCTIME: /* FALLTHROUGH */
+ case V_ASN1_GENERALIZEDTIME:
+ value = decode_time(p, hlen+length);
+ break;
+ default:
+ /* use original value */
+ p += hlen;
+ value = rb_str_new((const char *)p, length);
+ break;
+ }
}
else {
- p += hlen;
- value = rb_str_new((const char *)p, length);
+ p += hlen;
+ value = rb_str_new((const char *)p, length);
}
*pp += hlen + length;
*num_read = hlen + length;
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);
- }
- if(tag == V_ASN1_BIT_STRING){
- rb_ivar_set(asn1data, sivUNUSED_BITS, LONG2NUM(flag));
- }
+ tag < ossl_asn1_info_size && ossl_asn1_info[tag].klass) {
+ VALUE klass = *ossl_asn1_info[tag].klass;
+ 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, INT2NUM(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;
@@ -780,8 +842,8 @@ int_ossl_asn1_decode0_prim(unsigned char **pp, long length, long hlen, int tag,
static VALUE
int_ossl_asn1_decode0_cons(unsigned char **pp, long max_len, long length,
- long *offset, int depth, int yield, int j,
- int tag, VALUE tc, long *num_read)
+ long *offset, int depth, int yield, int j,
+ int tag, VALUE tc, long *num_read)
{
VALUE value, asn1data, ary;
int indefinite;
@@ -792,50 +854,52 @@ int_ossl_asn1_decode0_cons(unsigned char **pp, long max_len, long length,
available_len = indefinite ? max_len : length;
while (available_len > 0) {
- long inner_read = 0;
- value = ossl_asn1_decode0(pp, available_len, &off, depth + 1, yield, &inner_read);
- *num_read += inner_read;
- available_len -= inner_read;
+ long inner_read = 0;
+ value = ossl_asn1_decode0(pp, available_len, &off, depth + 1, yield, &inner_read);
+ *num_read += inner_read;
+ available_len -= inner_read;
- if (indefinite) {
+ if (indefinite) {
if (ossl_asn1_tag(value) == V_ASN1_EOC &&
ossl_asn1_get_tag_class(value) == sym_UNIVERSAL)
break;
if (available_len == 0)
ossl_raise(eASN1Error, "EOC missing in indefinite length encoding");
- }
- rb_ary_push(ary, value);
+ }
+ rb_ary_push(ary, value);
}
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)
- ossl_asn1_set_indefinite_length(asn1data, Qtrue);
+ ossl_asn1_set_indefinite_length(asn1data, Qtrue);
else
- ossl_asn1_set_indefinite_length(asn1data, Qfalse);
+ ossl_asn1_set_indefinite_length(asn1data, Qfalse);
*offset = off;
return asn1data;
}
+#define MAX_NESTING_DEPTH 200
+
static VALUE
ossl_asn1_decode0(unsigned char **pp, long length, long *offset, int depth,
- int yield, long *num_read)
+ int yield, long *num_read)
{
unsigned char *start, *p;
const unsigned char *p0;
@@ -843,6 +907,10 @@ ossl_asn1_decode0(unsigned char **pp, long length, long *offset, int depth,
int tag, tc, j;
VALUE asn1data, tag_class;
+ if (depth > MAX_NESTING_DEPTH) {
+ ossl_raise(eASN1Error, "nesting depth %d exceeds limit", depth);
+ }
+
p = *pp;
start = p;
p0 = p;
@@ -851,46 +919,46 @@ ossl_asn1_decode0(unsigned char **pp, long length, long *offset, int depth,
if(j & 0x80) ossl_raise(eASN1Error, NULL);
if(len > length) ossl_raise(eASN1Error, "value is too short");
if((tc & V_ASN1_PRIVATE) == V_ASN1_PRIVATE)
- tag_class = sym_PRIVATE;
+ tag_class = sym_PRIVATE;
else if((tc & V_ASN1_CONTEXT_SPECIFIC) == V_ASN1_CONTEXT_SPECIFIC)
- tag_class = sym_CONTEXT_SPECIFIC;
+ tag_class = sym_CONTEXT_SPECIFIC;
else if((tc & V_ASN1_APPLICATION) == V_ASN1_APPLICATION)
- tag_class = sym_APPLICATION;
+ tag_class = sym_APPLICATION;
else
- tag_class = sym_UNIVERSAL;
+ tag_class = sym_UNIVERSAL;
hlen = p - start;
if(yield) {
- VALUE arg = rb_ary_new();
- rb_ary_push(arg, LONG2NUM(depth));
- rb_ary_push(arg, LONG2NUM(*offset));
- rb_ary_push(arg, LONG2NUM(hlen));
- rb_ary_push(arg, LONG2NUM(len));
- rb_ary_push(arg, (j & V_ASN1_CONSTRUCTED) ? Qtrue : Qfalse);
- rb_ary_push(arg, ossl_asn1_class2sym(tc));
- rb_ary_push(arg, INT2NUM(tag));
- rb_yield(arg);
+ VALUE arg = rb_ary_new();
+ rb_ary_push(arg, LONG2NUM(depth));
+ rb_ary_push(arg, LONG2NUM(*offset));
+ rb_ary_push(arg, LONG2NUM(hlen));
+ rb_ary_push(arg, LONG2NUM(len));
+ rb_ary_push(arg, (j & V_ASN1_CONSTRUCTED) ? Qtrue : Qfalse);
+ rb_ary_push(arg, ossl_asn1_class2sym(tc));
+ rb_ary_push(arg, INT2NUM(tag));
+ rb_yield(arg);
}
if(j & V_ASN1_CONSTRUCTED) {
- *pp += hlen;
- off += hlen;
- asn1data = int_ossl_asn1_decode0_cons(pp, length - hlen, len, &off, depth, yield, j, tag, tag_class, &inner_read);
- inner_read += hlen;
+ *pp += hlen;
+ off += hlen;
+ asn1data = int_ossl_asn1_decode0_cons(pp, length - hlen, len, &off, depth, yield, j, tag, tag_class, &inner_read);
+ inner_read += hlen;
}
else {
- if ((j & 0x01) && (len == 0))
- ossl_raise(eASN1Error, "indefinite length for primitive value");
- asn1data = int_ossl_asn1_decode0_prim(pp, len, hlen, tag, tag_class, &inner_read);
- off += hlen + len;
+ if ((j & 0x01) && (len == 0))
+ ossl_raise(eASN1Error, "indefinite length for primitive value");
+ asn1data = int_ossl_asn1_decode0_prim(pp, len, hlen, tag, tag_class, &inner_read);
+ off += hlen + len;
}
if (num_read)
- *num_read = inner_read;
+ *num_read = inner_read;
if (len != 0 && inner_read != hlen + len) {
- ossl_raise(eASN1Error,
- "Type mismatch. Bytes read: %ld Bytes available: %ld",
- inner_read, hlen + len);
+ ossl_raise(eASN1Error,
+ "Type mismatch. Bytes read: %ld Bytes available: %ld",
+ inner_read, hlen + len);
}
*offset = off;
@@ -901,9 +969,9 @@ static void
int_ossl_decode_sanity_check(long len, long read, long offset)
{
if (len != 0 && (read != len || offset != len)) {
- ossl_raise(eASN1Error,
- "Type mismatch. Total bytes read: %ld Bytes available: %ld Offset: %ld",
- read, len, offset);
+ ossl_raise(eASN1Error,
+ "Type mismatch. Total bytes read: %ld Bytes available: %ld Offset: %ld",
+ read, len, offset);
}
}
@@ -1003,17 +1071,94 @@ ossl_asn1_decode_all(VALUE self, VALUE obj)
tmp_len = len;
ary = rb_ary_new();
while (tmp_len > 0) {
- long tmp_read = 0;
- val = ossl_asn1_decode0(&p, tmp_len, &offset, 0, 0, &tmp_read);
- rb_ary_push(ary, val);
- read += tmp_read;
- tmp_len -= tmp_read;
+ long tmp_read = 0;
+ val = ossl_asn1_decode0(&p, tmp_len, &offset, 0, 0, &tmp_read);
+ rb_ary_push(ary, val);
+ read += tmp_read;
+ tmp_len -= tmp_read;
}
RB_GC_GUARD(tmp);
int_ossl_decode_sanity_check(len, read, offset);
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)
{
@@ -1036,20 +1181,20 @@ ossl_asn1prim_to_der(VALUE self)
VALUE str;
if (ossl_asn1_default_tag(self) == -1) {
- str = ossl_asn1_get_value(self);
- return to_der_internal(self, 0, 0, StringValue(str));
+ str = ossl_asn1_get_value(self);
+ return to_der_internal(self, 0, 0, StringValue(str));
}
asn1 = ossl_asn1_get_asn1type(self);
alllen = i2d_ASN1_TYPE(asn1, NULL);
if (alllen < 0) {
- ASN1_TYPE_free(asn1);
- ossl_raise(eASN1Error, "i2d_ASN1_TYPE");
+ ASN1_TYPE_free(asn1);
+ ossl_raise(eASN1Error, "i2d_ASN1_TYPE");
}
str = ossl_str_new(NULL, alllen, &state);
if (state) {
- ASN1_TYPE_free(asn1);
- rb_jump_tag(state);
+ ASN1_TYPE_free(asn1);
+ rb_jump_tag(state);
}
p0 = p1 = (unsigned char *)RSTRING_PTR(str);
if (i2d_ASN1_TYPE(asn1, &p0) < 0) {
@@ -1062,7 +1207,7 @@ ossl_asn1prim_to_der(VALUE self)
/* Strip header since to_der_internal() wants only the payload */
j = ASN1_get_object((const unsigned char **)&p1, &bodylen, &tag, &tc, alllen);
if (j & 0x80)
- ossl_raise(eASN1Error, "ASN1_get_object"); /* should not happen */
+ ossl_raise(eASN1Error, "ASN1_get_object"); /* should not happen */
return to_der_internal(self, 0, 0, rb_str_drop_bytes(str, alllen - bodylen));
}
@@ -1084,22 +1229,22 @@ ossl_asn1cons_to_der(VALUE self)
ary = rb_convert_type(ossl_asn1_get_value(self), T_ARRAY, "Array", "to_a");
str = rb_str_new(NULL, 0);
for (i = 0; i < RARRAY_LEN(ary); i++) {
- VALUE item = RARRAY_AREF(ary, i);
-
- if (indef_len && rb_obj_is_kind_of(item, cASN1EndOfContent)) {
- if (i != RARRAY_LEN(ary) - 1)
- ossl_raise(eASN1Error, "illegal EOC octets in value");
-
- /*
- * EOC is not really part of the content, but we required to add one
- * at the end in the past.
- */
- break;
- }
-
- item = ossl_to_der_if_possible(item);
- StringValue(item);
- rb_str_append(str, item);
+ VALUE item = RARRAY_AREF(ary, i);
+
+ if (indef_len && rb_obj_is_kind_of(item, cASN1EndOfContent)) {
+ if (i != RARRAY_LEN(ary) - 1)
+ ossl_raise(eASN1Error, "illegal EOC octets in value");
+
+ /*
+ * EOC is not really part of the content, but we required to add one
+ * at the end in the past.
+ */
+ break;
+ }
+
+ item = ossl_to_der_if_possible(item);
+ StringValue(item);
+ rb_str_append(str, item);
}
return to_der_internal(self, 1, indef_len, str);
@@ -1107,6 +1252,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
@@ -1124,7 +1290,7 @@ ossl_asn1obj_s_register(VALUE self, VALUE oid, VALUE sn, VALUE ln)
StringValueCStr(ln);
if(!OBJ_create(RSTRING_PTR(oid), RSTRING_PTR(sn), RSTRING_PTR(ln)))
- ossl_raise(eASN1Error, NULL);
+ ossl_raise(eASN1Error, NULL);
return Qtrue;
}
@@ -1144,7 +1310,7 @@ ossl_asn1obj_get_sn(VALUE self)
val = ossl_asn1_get_value(self);
if ((nid = OBJ_txt2nid(StringValueCStr(val))) != NID_undef)
- ret = rb_str_new2(OBJ_nid2sn(nid));
+ ret = rb_str_new2(OBJ_nid2sn(nid));
return ret;
}
@@ -1164,7 +1330,7 @@ ossl_asn1obj_get_ln(VALUE self)
val = ossl_asn1_get_value(self);
if ((nid = OBJ_txt2nid(StringValueCStr(val))) != NID_undef)
- ret = rb_str_new2(OBJ_nid2ln(nid));
+ ret = rb_str_new2(OBJ_nid2ln(nid));
return ret;
}
@@ -1172,23 +1338,7 @@ ossl_asn1obj_get_ln(VALUE self)
static VALUE
asn1obj_get_oid_i(VALUE vobj)
{
- ASN1_OBJECT *a1obj = (void *)vobj;
- VALUE str;
- int len;
-
- str = rb_usascii_str_new(NULL, 127);
- len = OBJ_obj2txt(RSTRING_PTR(str), RSTRING_LENINT(str), a1obj, 1);
- if (len <= 0 || len == INT_MAX)
- ossl_raise(eASN1Error, "OBJ_obj2txt");
- if (len > RSTRING_LEN(str)) {
- /* +1 is for the \0 terminator added by OBJ_obj2txt() */
- rb_str_resize(str, len + 1);
- len = OBJ_obj2txt(RSTRING_PTR(str), len + 1, a1obj, 1);
- if (len <= 0)
- ossl_raise(eASN1Error, "OBJ_obj2txt");
- }
- rb_str_set_len(str, len);
- return str;
+ return ossl_asn1obj_to_string_oid((const ASN1_OBJECT *)vobj);
}
/*
@@ -1205,11 +1355,11 @@ ossl_asn1obj_get_oid(VALUE self)
ASN1_OBJECT *a1obj;
int state;
- a1obj = obj_to_asn1obj(ossl_asn1_get_value(self));
+ a1obj = ossl_to_asn1obj(ossl_asn1_get_value(self));
str = rb_protect(asn1obj_get_oid_i, (VALUE)a1obj, &state);
ASN1_OBJECT_free(a1obj);
if (state)
- rb_jump_tag(state);
+ rb_jump_tag(state);
return str;
}
@@ -1234,7 +1384,7 @@ ossl_asn1obj_eq(VALUE self, VALUE other)
#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)
@@ -1264,13 +1414,6 @@ void
Init_ossl_asn1(void)
{
#undef rb_intern
- VALUE ary;
- int i;
-
-#if 0
- mOSSL = rb_define_module("OpenSSL");
- eOSSLError = rb_define_class_under(mOSSL, "OpenSSLError", rb_eStandardError);
-#endif
sym_UNIVERSAL = ID2SYM(rb_intern_const("UNIVERSAL"));
sym_CONTEXT_SPECIFIC = ID2SYM(rb_intern_const("CONTEXT_SPECIFIC"));
@@ -1420,17 +1563,20 @@ Init_ossl_asn1(void)
rb_define_module_function(mASN1, "traverse", ossl_asn1_traverse, 1);
rb_define_module_function(mASN1, "decode", ossl_asn1_decode, 1);
rb_define_module_function(mASN1, "decode_all", ossl_asn1_decode_all, 1);
- ary = rb_ary_new();
+ VALUE ary = rb_ary_new_capa(ossl_asn1_info_size);
+ for (int i = 0; i < ossl_asn1_info_size; i++) {
+ const char *name = ossl_asn1_info[i].name;
+ if (name[0] == '[')
+ continue;
+ rb_define_const(mASN1, name, INT2NUM(i));
+ rb_ary_store(ary, i, rb_obj_freeze(rb_str_new_cstr(name)));
+ }
+ rb_obj_freeze(ary);
/*
* Array storing tag names at the tag's index.
*/
rb_define_const(mASN1, "UNIVERSAL_TAG_NAME", ary);
- for(i = 0; i < ossl_asn1_info_size; i++){
- if(ossl_asn1_info[i].name[0] == '[') continue;
- rb_define_const(mASN1, ossl_asn1_info[i].name, INT2NUM(i));
- rb_ary_store(ary, i, rb_str_new2(ossl_asn1_info[i].name));
- }
/* Document-class: OpenSSL::ASN1::ASN1Data
*
@@ -1520,6 +1666,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
@@ -1587,6 +1769,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
@@ -1617,7 +1809,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{\
@@ -1666,10 +1868,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));
@@ -1693,5 +1898,7 @@ 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);
+ rb_obj_freeze(class_tag_map);
+
+ id_each = rb_intern_const("each");
}
diff --git a/ext/openssl/ossl_asn1.h b/ext/openssl/ossl_asn1.h
index 3b689c0ee7..b605df8f3f 100644
--- a/ext/openssl/ossl_asn1.h
+++ b/ext/openssl/ossl_asn1.h
@@ -32,10 +32,24 @@ VALUE asn1integer_to_num(const ASN1_INTEGER *);
ASN1_INTEGER *num_to_asn1integer(VALUE, ASN1_INTEGER *);
/*
+ * ASN1_OBJECT conversions
+ */
+ASN1_OBJECT *ossl_to_asn1obj(VALUE obj);
+/*
+ * Returns the short name if available, the dotted decimal notation otherwise.
+ * This is the most common way to return ASN1_OBJECT to Ruby.
+ */
+VALUE ossl_asn1obj_to_string(const ASN1_OBJECT *a1obj);
+/*
+ * However, some places use long names instead. This is likely unintentional,
+ * but we keep the current behavior in existing methods.
+ */
+VALUE ossl_asn1obj_to_string_long_name(const ASN1_OBJECT *a1obj);
+
+/*
* ASN1 module
*/
extern VALUE mASN1;
-extern VALUE eASN1Error;
extern VALUE cASN1Data;
diff --git a/ext/openssl/ossl_bio.c b/ext/openssl/ossl_bio.c
index 2ef2080507..cc03c5d5f7 100644
--- a/ext/openssl/ossl_bio.c
+++ b/ext/openssl/ossl_bio.c
@@ -16,11 +16,11 @@ ossl_obj2bio(volatile VALUE *pobj)
BIO *bio;
if (RB_TYPE_P(obj, T_FILE))
- obj = rb_funcallv(obj, rb_intern("read"), 0, NULL);
+ obj = rb_funcallv(obj, rb_intern("read"), 0, NULL);
StringValue(obj);
bio = BIO_new_mem_buf(RSTRING_PTR(obj), RSTRING_LENINT(obj));
if (!bio)
- ossl_raise(eOSSLError, "BIO_new_mem_buf");
+ ossl_raise(eOSSLError, "BIO_new_mem_buf");
*pobj = obj;
return bio;
}
@@ -32,11 +32,15 @@ ossl_membio2str(BIO *bio)
int state;
BUF_MEM *buf;
- BIO_get_mem_ptr(bio, &buf);
+ if (BIO_get_mem_ptr(bio, &buf) <= 0) {
+ BIO_free(bio);
+ ossl_raise(eOSSLError, "BIO_get_mem_ptr");
+ }
+
ret = ossl_str_new(buf->data, buf->length, &state);
BIO_free(bio);
if (state)
- rb_jump_tag(state);
+ rb_jump_tag(state);
return ret;
}
diff --git a/ext/openssl/ossl_bn.c b/ext/openssl/ossl_bn.c
index a6fa2c1dab..9014f2df2b 100644
--- a/ext/openssl/ossl_bn.c
+++ b/ext/openssl/ossl_bn.c
@@ -11,19 +11,19 @@
#include "ossl.h"
#define NewBN(klass) \
- TypedData_Wrap_Struct((klass), &ossl_bn_type, 0)
+ TypedData_Wrap_Struct((klass), &ossl_bn_type, 0)
#define SetBN(obj, bn) do { \
- if (!(bn)) { \
- ossl_raise(rb_eRuntimeError, "BN wasn't initialized!"); \
- } \
- RTYPEDDATA_DATA(obj) = (bn); \
+ if (!(bn)) { \
+ ossl_raise(rb_eRuntimeError, "BN wasn't initialized!"); \
+ } \
+ RTYPEDDATA_DATA(obj) = (bn); \
} while (0)
#define GetBN(obj, bn) do { \
- TypedData_Get_Struct((obj), BIGNUM, &ossl_bn_type, (bn)); \
- if (!(bn)) { \
- ossl_raise(rb_eRuntimeError, "BN wasn't initialized!"); \
- } \
+ TypedData_Get_Struct((obj), BIGNUM, &ossl_bn_type, (bn)); \
+ if (!(bn)) { \
+ ossl_raise(rb_eRuntimeError, "BN wasn't initialized!"); \
+ } \
} while (0)
static void
@@ -35,7 +35,7 @@ ossl_bn_free(void *ptr)
static const rb_data_type_t ossl_bn_type = {
"OpenSSL/BN",
{
- 0, ossl_bn_free,
+ 0, ossl_bn_free,
},
0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FROZEN_SHAREABLE,
};
@@ -75,40 +75,40 @@ integer_to_bnptr(VALUE obj, BIGNUM *orig)
BIGNUM *bn;
if (FIXNUM_P(obj)) {
- long i;
- unsigned char bin[sizeof(long)];
- long n = FIX2LONG(obj);
- unsigned long un = labs(n);
-
- for (i = sizeof(long) - 1; 0 <= i; i--) {
- bin[i] = un & 0xff;
- un >>= 8;
- }
-
- bn = BN_bin2bn(bin, sizeof(bin), orig);
- if (!bn)
- ossl_raise(eBNError, "BN_bin2bn");
- if (n < 0)
- BN_set_negative(bn, 1);
+ long i;
+ unsigned char bin[sizeof(long)];
+ long n = FIX2LONG(obj);
+ unsigned long un = labs(n);
+
+ for (i = sizeof(long) - 1; 0 <= i; i--) {
+ bin[i] = un & 0xff;
+ un >>= 8;
+ }
+
+ bn = BN_bin2bn(bin, sizeof(bin), orig);
+ if (!bn)
+ ossl_raise(eBNError, "BN_bin2bn");
+ if (n < 0)
+ BN_set_negative(bn, 1);
}
else { /* assuming Bignum */
- size_t len = rb_absint_size(obj, NULL);
- unsigned char *bin;
- VALUE buf;
- int sign;
-
- if (INT_MAX < len) {
- rb_raise(eBNError, "bignum too long");
- }
- bin = (unsigned char*)ALLOCV_N(unsigned char, buf, len);
- sign = rb_integer_pack(obj, bin, len, 1, 0, INTEGER_PACK_BIG_ENDIAN);
-
- bn = BN_bin2bn(bin, (int)len, orig);
- ALLOCV_END(buf);
- if (!bn)
- ossl_raise(eBNError, "BN_bin2bn");
- if (sign < 0)
- BN_set_negative(bn, 1);
+ size_t len = rb_absint_size(obj, NULL);
+ unsigned char *bin;
+ VALUE buf;
+ int sign;
+
+ if (INT_MAX < len) {
+ rb_raise(eBNError, "bignum too long");
+ }
+ bin = (unsigned char*)ALLOCV_N(unsigned char, buf, len);
+ sign = rb_integer_pack(obj, bin, len, 1, 0, INTEGER_PACK_BIG_ENDIAN);
+
+ bn = BN_bin2bn(bin, (int)len, orig);
+ ALLOCV_END(buf);
+ if (!bn)
+ ossl_raise(eBNError, "BN_bin2bn");
+ if (sign < 0)
+ BN_set_negative(bn, 1);
}
return bn;
@@ -121,11 +121,11 @@ try_convert_to_bn(VALUE obj)
VALUE newobj = Qnil;
if (rb_obj_is_kind_of(obj, cBN))
- return obj;
+ return obj;
if (RB_INTEGER_TYPE_P(obj)) {
- newobj = NewBN(cBN); /* Handle potential mem leaks */
- bn = integer_to_bnptr(obj, NULL);
- SetBN(newobj, bn);
+ newobj = NewBN(cBN); /* Handle potential mem leaks */
+ bn = integer_to_bnptr(obj, NULL);
+ SetBN(newobj, bn);
}
return newobj;
@@ -139,7 +139,7 @@ ossl_bn_value_ptr(volatile VALUE *ptr)
tmp = try_convert_to_bn(*ptr);
if (NIL_P(tmp))
- ossl_raise(rb_eTypeError, "Cannot convert into OpenSSL::BN");
+ ossl_raise(rb_eTypeError, "Cannot convert into OpenSSL::BN");
GetBN(tmp, bn);
*ptr = tmp;
@@ -209,7 +209,7 @@ ossl_bn_alloc(VALUE klass)
VALUE obj = NewBN(klass);
if (!(bn = BN_new())) {
- ossl_raise(eBNError, NULL);
+ ossl_raise(eBNError, NULL);
}
SetBN(obj, bn);
@@ -251,7 +251,7 @@ ossl_bn_initialize(int argc, VALUE *argv, VALUE self)
char *ptr;
if (rb_scan_args(argc, argv, "11", &str, &bs) == 2) {
- base = NUM2INT(bs);
+ base = NUM2INT(bs);
}
if (NIL_P(str)) {
@@ -260,49 +260,49 @@ ossl_bn_initialize(int argc, VALUE *argv, VALUE self)
rb_check_frozen(self);
if (RB_INTEGER_TYPE_P(str)) {
- GetBN(self, bn);
- integer_to_bnptr(str, bn);
+ GetBN(self, bn);
+ integer_to_bnptr(str, bn);
- return self;
+ return self;
}
if (RTEST(rb_obj_is_kind_of(str, cBN))) {
- BIGNUM *other;
-
- GetBN(self, bn);
- GetBN(str, other); /* Safe - we checked kind_of? above */
- if (!BN_copy(bn, other)) {
- ossl_raise(eBNError, NULL);
- }
- return self;
+ BIGNUM *other;
+
+ GetBN(self, bn);
+ GetBN(str, other); /* Safe - we checked kind_of? above */
+ if (!BN_copy(bn, other)) {
+ ossl_raise(eBNError, NULL);
+ }
+ return self;
}
GetBN(self, bn);
switch (base) {
- case 0:
+ case 0:
ptr = StringValuePtr(str);
if (!BN_mpi2bn((unsigned char *)ptr, RSTRING_LENINT(str), bn)) {
- ossl_raise(eBNError, NULL);
- }
- break;
- case 2:
+ ossl_raise(eBNError, NULL);
+ }
+ break;
+ case 2:
ptr = StringValuePtr(str);
if (!BN_bin2bn((unsigned char *)ptr, RSTRING_LENINT(str), bn)) {
- ossl_raise(eBNError, NULL);
- }
- break;
- case 10:
- if (!BN_dec2bn(&bn, StringValueCStr(str))) {
- ossl_raise(eBNError, NULL);
- }
- break;
- case 16:
- if (!BN_hex2bn(&bn, StringValueCStr(str))) {
- ossl_raise(eBNError, NULL);
- }
- break;
- default:
- ossl_raise(rb_eArgError, "invalid radix %d", base);
+ ossl_raise(eBNError, NULL);
+ }
+ break;
+ case 10:
+ if (!BN_dec2bn(&bn, StringValueCStr(str))) {
+ ossl_raise(eBNError, NULL);
+ }
+ break;
+ case 16:
+ if (!BN_hex2bn(&bn, StringValueCStr(str))) {
+ ossl_raise(eBNError, NULL);
+ }
+ break;
+ default:
+ ossl_raise(rb_eArgError, "invalid radix %d", base);
}
return self;
}
@@ -334,32 +334,32 @@ ossl_bn_to_s(int argc, VALUE *argv, VALUE self)
char *buf;
if (rb_scan_args(argc, argv, "01", &bs) == 1) {
- base = NUM2INT(bs);
+ base = NUM2INT(bs);
}
GetBN(self, bn);
switch (base) {
- case 0:
- len = BN_bn2mpi(bn, NULL);
+ case 0:
+ len = BN_bn2mpi(bn, NULL);
str = rb_str_new(0, len);
- if (BN_bn2mpi(bn, (unsigned char *)RSTRING_PTR(str)) != len)
- ossl_raise(eBNError, NULL);
- break;
- case 2:
- len = BN_num_bytes(bn);
+ if (BN_bn2mpi(bn, (unsigned char *)RSTRING_PTR(str)) != len)
+ ossl_raise(eBNError, NULL);
+ break;
+ case 2:
+ len = BN_num_bytes(bn);
str = rb_str_new(0, len);
- if (BN_bn2bin(bn, (unsigned char *)RSTRING_PTR(str)) != len)
- ossl_raise(eBNError, NULL);
- break;
- case 10:
- if (!(buf = BN_bn2dec(bn))) ossl_raise(eBNError, NULL);
- str = ossl_buf2str(buf, rb_long2int(strlen(buf)));
- break;
- case 16:
- if (!(buf = BN_bn2hex(bn))) ossl_raise(eBNError, NULL);
- str = ossl_buf2str(buf, rb_long2int(strlen(buf)));
- break;
- default:
- ossl_raise(rb_eArgError, "invalid radix %d", base);
+ if (BN_bn2bin(bn, (unsigned char *)RSTRING_PTR(str)) != len)
+ ossl_raise(eBNError, NULL);
+ break;
+ case 10:
+ if (!(buf = BN_bn2dec(bn))) ossl_raise(eBNError, NULL);
+ str = ossl_buf2str(buf, rb_long2int(strlen(buf)));
+ break;
+ case 16:
+ if (!(buf = BN_bn2hex(bn))) ossl_raise(eBNError, NULL);
+ str = ossl_buf2str(buf, rb_long2int(strlen(buf)));
+ break;
+ default:
+ ossl_raise(rb_eArgError, "invalid radix %d", base);
}
return str;
@@ -379,7 +379,7 @@ ossl_bn_to_i(VALUE self)
GetBN(self, bn);
if (!(txt = BN_bn2hex(bn))) {
- ossl_raise(eBNError, NULL);
+ ossl_raise(eBNError, NULL);
}
num = rb_cstr_to_inum(txt, 16, Qtrue);
OPENSSL_free(txt);
@@ -397,31 +397,31 @@ static VALUE
ossl_bn_coerce(VALUE self, VALUE other)
{
switch(TYPE(other)) {
- case T_STRING:
- self = ossl_bn_to_s(0, NULL, self);
- break;
- case T_FIXNUM:
- case T_BIGNUM:
- self = ossl_bn_to_i(self);
- break;
- default:
- if (!RTEST(rb_obj_is_kind_of(other, cBN))) {
- ossl_raise(rb_eTypeError, "Don't know how to coerce");
- }
+ case T_STRING:
+ self = ossl_bn_to_s(0, NULL, self);
+ break;
+ case T_FIXNUM:
+ case T_BIGNUM:
+ self = ossl_bn_to_i(self);
+ break;
+ default:
+ if (!RTEST(rb_obj_is_kind_of(other, cBN))) {
+ ossl_raise(rb_eTypeError, "Don't know how to coerce");
+ }
}
return rb_assoc_new(other, self);
}
-#define BIGNUM_BOOL1(func) \
- static VALUE \
- ossl_bn_##func(VALUE self) \
- { \
- BIGNUM *bn; \
- GetBN(self, bn); \
- if (BN_##func(bn)) { \
- return Qtrue; \
- } \
- return Qfalse; \
+#define BIGNUM_BOOL1(func) \
+ static VALUE \
+ ossl_bn_##func(VALUE self) \
+ { \
+ BIGNUM *bn; \
+ GetBN(self, bn); \
+ if (BN_##func(bn)) { \
+ return Qtrue; \
+ } \
+ return Qfalse; \
}
/*
@@ -456,27 +456,27 @@ ossl_bn_is_negative(VALUE self)
GetBN(self, bn);
if (BN_is_zero(bn))
- return Qfalse;
+ return Qfalse;
return BN_is_negative(bn) ? Qtrue : Qfalse;
}
-#define BIGNUM_1c(func) \
- static VALUE \
- ossl_bn_##func(VALUE self) \
- { \
- BIGNUM *bn, *result; \
- VALUE obj; \
- GetBN(self, bn); \
- obj = NewBN(rb_obj_class(self)); \
- if (!(result = BN_new())) { \
- ossl_raise(eBNError, NULL); \
- } \
- if (BN_##func(result, bn, ossl_bn_ctx) <= 0) { \
- BN_free(result); \
- ossl_raise(eBNError, NULL); \
- } \
- SetBN(obj, result); \
- return obj; \
+#define BIGNUM_1c(func) \
+ static VALUE \
+ ossl_bn_##func(VALUE self) \
+ { \
+ BIGNUM *bn, *result; \
+ VALUE obj; \
+ GetBN(self, bn); \
+ obj = NewBN(rb_obj_class(self)); \
+ if (!(result = BN_new())) { \
+ ossl_raise(eBNError, NULL); \
+ } \
+ if (BN_##func(result, bn, ossl_bn_ctx) <= 0) { \
+ BN_free(result); \
+ ossl_raise(eBNError, NULL); \
+ } \
+ SetBN(obj, result); \
+ return obj; \
}
/*
@@ -486,23 +486,23 @@ ossl_bn_is_negative(VALUE self)
*/
BIGNUM_1c(sqr)
-#define BIGNUM_2(func) \
- static VALUE \
- ossl_bn_##func(VALUE self, VALUE other) \
- { \
- BIGNUM *bn1, *bn2 = GetBNPtr(other), *result; \
- VALUE obj; \
- GetBN(self, bn1); \
- obj = NewBN(rb_obj_class(self)); \
- if (!(result = BN_new())) { \
- ossl_raise(eBNError, NULL); \
- } \
- if (BN_##func(result, bn1, bn2) <= 0) { \
- BN_free(result); \
- ossl_raise(eBNError, NULL); \
- } \
- SetBN(obj, result); \
- return obj; \
+#define BIGNUM_2(func) \
+ static VALUE \
+ ossl_bn_##func(VALUE self, VALUE other) \
+ { \
+ BIGNUM *bn1, *bn2 = GetBNPtr(other), *result; \
+ VALUE obj; \
+ GetBN(self, bn1); \
+ obj = NewBN(rb_obj_class(self)); \
+ if (!(result = BN_new())) { \
+ ossl_raise(eBNError, NULL); \
+ } \
+ if (BN_##func(result, bn1, bn2) <= 0) { \
+ BN_free(result); \
+ ossl_raise(eBNError, NULL); \
+ } \
+ SetBN(obj, result); \
+ return obj; \
}
/*
@@ -519,23 +519,23 @@ BIGNUM_2(add)
*/
BIGNUM_2(sub)
-#define BIGNUM_2c(func) \
- static VALUE \
- ossl_bn_##func(VALUE self, VALUE other) \
- { \
- BIGNUM *bn1, *bn2 = GetBNPtr(other), *result; \
- VALUE obj; \
- GetBN(self, bn1); \
- obj = NewBN(rb_obj_class(self)); \
- if (!(result = BN_new())) { \
- ossl_raise(eBNError, NULL); \
- } \
- if (BN_##func(result, bn1, bn2, ossl_bn_ctx) <= 0) { \
- BN_free(result); \
- ossl_raise(eBNError, NULL); \
- } \
- SetBN(obj, result); \
- return obj; \
+#define BIGNUM_2c(func) \
+ static VALUE \
+ ossl_bn_##func(VALUE self, VALUE other) \
+ { \
+ BIGNUM *bn1, *bn2 = GetBNPtr(other), *result; \
+ VALUE obj; \
+ GetBN(self, bn1); \
+ obj = NewBN(rb_obj_class(self)); \
+ if (!(result = BN_new())) { \
+ ossl_raise(eBNError, NULL); \
+ } \
+ if (BN_##func(result, bn1, bn2, ossl_bn_ctx) <= 0) { \
+ BN_free(result); \
+ ossl_raise(eBNError, NULL); \
+ } \
+ SetBN(obj, result); \
+ return obj; \
}
/*
@@ -573,18 +573,18 @@ BIGNUM_2c(gcd)
*/
BIGNUM_2c(mod_sqr)
-#define BIGNUM_2cr(func) \
- static VALUE \
- ossl_bn_##func(VALUE self, VALUE other) \
- { \
- BIGNUM *bn1, *bn2 = GetBNPtr(other), *result; \
- VALUE obj; \
- GetBN(self, bn1); \
- obj = NewBN(rb_obj_class(self)); \
- if (!(result = BN_##func(NULL, bn1, bn2, ossl_bn_ctx))) \
- ossl_raise(eBNError, NULL); \
- SetBN(obj, result); \
- return obj; \
+#define BIGNUM_2cr(func) \
+ static VALUE \
+ ossl_bn_##func(VALUE self, VALUE other) \
+ { \
+ BIGNUM *bn1, *bn2 = GetBNPtr(other), *result; \
+ VALUE obj; \
+ GetBN(self, bn1); \
+ obj = NewBN(rb_obj_class(self)); \
+ if (!(result = BN_##func(NULL, bn1, bn2, ossl_bn_ctx))) \
+ ossl_raise(eBNError, NULL); \
+ SetBN(obj, result); \
+ return obj; \
}
/*
@@ -619,16 +619,16 @@ ossl_bn_div(VALUE self, VALUE other)
obj1 = NewBN(klass);
obj2 = NewBN(klass);
if (!(r1 = BN_new())) {
- ossl_raise(eBNError, NULL);
+ ossl_raise(eBNError, NULL);
}
if (!(r2 = BN_new())) {
- BN_free(r1);
- ossl_raise(eBNError, NULL);
+ BN_free(r1);
+ ossl_raise(eBNError, NULL);
}
if (!BN_div(r1, r2, bn1, bn2, ossl_bn_ctx)) {
- BN_free(r1);
- BN_free(r2);
- ossl_raise(eBNError, NULL);
+ BN_free(r1);
+ BN_free(r2);
+ ossl_raise(eBNError, NULL);
}
SetBN(obj1, r1);
SetBN(obj2, r2);
@@ -636,24 +636,24 @@ ossl_bn_div(VALUE self, VALUE other)
return rb_ary_new3(2, obj1, obj2);
}
-#define BIGNUM_3c(func) \
- static VALUE \
- ossl_bn_##func(VALUE self, VALUE other1, VALUE other2) \
- { \
- BIGNUM *bn1, *bn2 = GetBNPtr(other1); \
- BIGNUM *bn3 = GetBNPtr(other2), *result; \
- VALUE obj; \
- GetBN(self, bn1); \
- obj = NewBN(rb_obj_class(self)); \
- if (!(result = BN_new())) { \
- ossl_raise(eBNError, NULL); \
- } \
- if (BN_##func(result, bn1, bn2, bn3, ossl_bn_ctx) <= 0) { \
- BN_free(result); \
- ossl_raise(eBNError, NULL); \
- } \
- SetBN(obj, result); \
- return obj; \
+#define BIGNUM_3c(func) \
+ static VALUE \
+ ossl_bn_##func(VALUE self, VALUE other1, VALUE other2) \
+ { \
+ BIGNUM *bn1, *bn2 = GetBNPtr(other1); \
+ BIGNUM *bn3 = GetBNPtr(other2), *result; \
+ VALUE obj; \
+ GetBN(self, bn1); \
+ obj = NewBN(rb_obj_class(self)); \
+ if (!(result = BN_new())) { \
+ ossl_raise(eBNError, NULL); \
+ } \
+ if (BN_##func(result, bn1, bn2, bn3, ossl_bn_ctx) <= 0) { \
+ BN_free(result); \
+ ossl_raise(eBNError, NULL); \
+ } \
+ SetBN(obj, result); \
+ return obj; \
}
/*
@@ -684,17 +684,17 @@ BIGNUM_3c(mod_mul)
*/
BIGNUM_3c(mod_exp)
-#define BIGNUM_BIT(func) \
- static VALUE \
- ossl_bn_##func(VALUE self, VALUE bit) \
- { \
- BIGNUM *bn; \
- rb_check_frozen(self); \
- GetBN(self, bn); \
- if (BN_##func(bn, NUM2INT(bit)) <= 0) { \
- ossl_raise(eBNError, NULL); \
- } \
- return self; \
+#define BIGNUM_BIT(func) \
+ static VALUE \
+ ossl_bn_##func(VALUE self, VALUE bit) \
+ { \
+ BIGNUM *bn; \
+ rb_check_frozen(self); \
+ GetBN(self, bn); \
+ if (BN_##func(bn, NUM2INT(bit)) <= 0) { \
+ ossl_raise(eBNError, NULL); \
+ } \
+ return self; \
}
/*
@@ -733,30 +733,30 @@ ossl_bn_is_bit_set(VALUE self, VALUE bit)
b = NUM2INT(bit);
GetBN(self, bn);
if (BN_is_bit_set(bn, b)) {
- return Qtrue;
+ return Qtrue;
}
return Qfalse;
}
-#define BIGNUM_SHIFT(func) \
- static VALUE \
- ossl_bn_##func(VALUE self, VALUE bits) \
- { \
- BIGNUM *bn, *result; \
- int b; \
- VALUE obj; \
- b = NUM2INT(bits); \
- GetBN(self, bn); \
- obj = NewBN(rb_obj_class(self)); \
- if (!(result = BN_new())) { \
- ossl_raise(eBNError, NULL); \
- } \
- if (BN_##func(result, bn, b) <= 0) { \
- BN_free(result); \
- ossl_raise(eBNError, NULL); \
- } \
- SetBN(obj, result); \
- return obj; \
+#define BIGNUM_SHIFT(func) \
+ static VALUE \
+ ossl_bn_##func(VALUE self, VALUE bits) \
+ { \
+ BIGNUM *bn, *result; \
+ int b; \
+ VALUE obj; \
+ b = NUM2INT(bits); \
+ GetBN(self, bn); \
+ obj = NewBN(rb_obj_class(self)); \
+ if (!(result = BN_new())) { \
+ ossl_raise(eBNError, NULL); \
+ } \
+ if (BN_##func(result, bn, b) <= 0) { \
+ BN_free(result); \
+ ossl_raise(eBNError, NULL); \
+ } \
+ SetBN(obj, result); \
+ return obj; \
}
/*
@@ -773,18 +773,18 @@ BIGNUM_SHIFT(lshift)
*/
BIGNUM_SHIFT(rshift)
-#define BIGNUM_SELF_SHIFT(func) \
- static VALUE \
- ossl_bn_self_##func(VALUE self, VALUE bits) \
- { \
- BIGNUM *bn; \
- int b; \
- rb_check_frozen(self); \
- b = NUM2INT(bits); \
- GetBN(self, bn); \
- if (BN_##func(bn, bn, b) <= 0) \
- ossl_raise(eBNError, NULL); \
- return self; \
+#define BIGNUM_SELF_SHIFT(func) \
+ static VALUE \
+ ossl_bn_self_##func(VALUE self, VALUE bits) \
+ { \
+ BIGNUM *bn; \
+ int b; \
+ rb_check_frozen(self); \
+ b = NUM2INT(bits); \
+ GetBN(self, bn); \
+ if (BN_##func(bn, bn, b) <= 0) \
+ ossl_raise(eBNError, NULL); \
+ return self; \
}
/*
@@ -886,32 +886,32 @@ ossl_bn_s_generate_prime(int argc, VALUE *argv, VALUE klass)
num = NUM2INT(vnum);
if (vsafe == Qfalse) {
- safe = 0;
+ safe = 0;
}
if (!NIL_P(vadd)) {
- add = GetBNPtr(vadd);
- rem = NIL_P(vrem) ? NULL : GetBNPtr(vrem);
+ add = GetBNPtr(vadd);
+ rem = NIL_P(vrem) ? NULL : GetBNPtr(vrem);
}
obj = NewBN(klass);
if (!(result = BN_new())) {
- ossl_raise(eBNError, NULL);
+ ossl_raise(eBNError, NULL);
}
if (!BN_generate_prime_ex(result, num, safe, add, rem, NULL)) {
- BN_free(result);
- ossl_raise(eBNError, NULL);
+ BN_free(result);
+ ossl_raise(eBNError, NULL);
}
SetBN(obj, result);
return obj;
}
-#define BIGNUM_NUM(func) \
- static VALUE \
- ossl_bn_##func(VALUE self) \
- { \
- BIGNUM *bn; \
- GetBN(self, bn); \
- return INT2NUM(BN_##func(bn)); \
+#define BIGNUM_NUM(func) \
+ static VALUE \
+ ossl_bn_##func(VALUE self) \
+ { \
+ BIGNUM *bn; \
+ GetBN(self, bn); \
+ return INT2NUM(BN_##func(bn)); \
}
/*
@@ -942,7 +942,7 @@ ossl_bn_copy(VALUE self, VALUE other)
bn2 = GetBNPtr(other);
if (!BN_copy(bn1, bn2)) {
- ossl_raise(eBNError, NULL);
+ ossl_raise(eBNError, NULL);
}
return self;
}
@@ -961,7 +961,7 @@ ossl_bn_uplus(VALUE self)
obj = NewBN(cBN);
bn2 = BN_dup(bn1);
if (!bn2)
- ossl_raise(eBNError, "BN_dup");
+ ossl_raise(eBNError, "BN_dup");
SetBN(obj, bn2);
return obj;
@@ -981,7 +981,7 @@ ossl_bn_uminus(VALUE self)
obj = NewBN(cBN);
bn2 = BN_dup(bn1);
if (!bn2)
- ossl_raise(eBNError, "BN_dup");
+ ossl_raise(eBNError, "BN_dup");
SetBN(obj, bn2);
BN_set_negative(bn2, !BN_is_negative(bn2));
@@ -1006,13 +1006,13 @@ ossl_bn_abs(VALUE self)
}
}
-#define BIGNUM_CMP(func) \
- static VALUE \
- ossl_bn_##func(VALUE self, VALUE other) \
- { \
- BIGNUM *bn1, *bn2 = GetBNPtr(other); \
- GetBN(self, bn1); \
- return INT2NUM(BN_##func(bn1, bn2)); \
+#define BIGNUM_CMP(func) \
+ static VALUE \
+ ossl_bn_##func(VALUE self, VALUE other) \
+ { \
+ BIGNUM *bn1, *bn2 = GetBNPtr(other); \
+ GetBN(self, bn1); \
+ return INT2NUM(BN_##func(bn1, bn2)); \
}
/*
@@ -1049,11 +1049,11 @@ ossl_bn_eq(VALUE self, VALUE other)
GetBN(self, bn1);
other = try_convert_to_bn(other);
if (NIL_P(other))
- return Qfalse;
+ return Qfalse;
GetBN(other, bn2);
if (!BN_cmp(bn1, bn2)) {
- return Qtrue;
+ return Qtrue;
}
return Qfalse;
}
@@ -1072,7 +1072,7 @@ ossl_bn_eql(VALUE self, VALUE other)
BIGNUM *bn1, *bn2;
if (!rb_obj_is_kind_of(other, cBN))
- return Qfalse;
+ return Qfalse;
GetBN(self, bn1);
GetBN(other, bn2);
@@ -1099,8 +1099,8 @@ ossl_bn_hash(VALUE self)
len = BN_num_bytes(bn);
buf = ALLOCV(tmp, len);
if (BN_bn2bin(bn, buf) != len) {
- ALLOCV_END(tmp);
- ossl_raise(eBNError, "BN_bn2bin");
+ ALLOCV_END(tmp);
+ ossl_raise(eBNError, "BN_bn2bin");
}
hash = ST2FIX(rb_memhash(buf, len));
@@ -1202,11 +1202,6 @@ ossl_bn_set_flags(VALUE self, VALUE arg)
void
Init_ossl_bn(void)
{
-#if 0
- mOSSL = rb_define_module("OpenSSL");
- eOSSLError = rb_define_class_under(mOSSL, "OpenSSLError", rb_eStandardError);
-#endif
-
#ifdef HAVE_RB_EXT_RACTOR_SAFE
ossl_bn_ctx_key = rb_ractor_local_storage_ptr_newkey(&ossl_bn_ctx_key_type);
#else
diff --git a/ext/openssl/ossl_cipher.c b/ext/openssl/ossl_cipher.c
index 07e651335d..e9dcd943e3 100644
--- a/ext/openssl/ossl_cipher.c
+++ b/ext/openssl/ossl_cipher.c
@@ -14,7 +14,7 @@
#define AllocCipher(obj, ctx) do { \
(ctx) = EVP_CIPHER_CTX_new(); \
if (!(ctx)) \
- ossl_raise(rb_eRuntimeError, NULL); \
+ ossl_raise(rb_eRuntimeError, NULL); \
RTYPEDDATA_DATA(obj) = (ctx); \
} while (0)
#define GetCipherInit(obj, ctx) do { \
@@ -23,7 +23,7 @@
#define GetCipher(obj, ctx) do { \
GetCipherInit((obj), (ctx)); \
if (!(ctx)) { \
- ossl_raise(rb_eRuntimeError, "Cipher not initialized!"); \
+ ossl_raise(rb_eRuntimeError, "Cipher not initialized!"); \
} \
} while (0)
@@ -32,7 +32,8 @@
*/
static VALUE cCipher;
static VALUE eCipherError;
-static ID id_auth_tag_len, id_key_set;
+static VALUE eAuthTagError;
+static ID id_auth_tag_len, id_key_set, id_cipher_holder;
static VALUE ossl_cipher_alloc(VALUE klass);
static void ossl_cipher_free(void *ptr);
@@ -40,35 +41,63 @@ static void ossl_cipher_free(void *ptr);
static const rb_data_type_t ossl_cipher_type = {
"OpenSSL/Cipher",
{
- 0, ossl_cipher_free,
+ 0, ossl_cipher_free,
},
0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
};
+#ifdef OSSL_USE_PROVIDER
+static void
+ossl_evp_cipher_free(void *ptr)
+{
+ // This is safe to call against const EVP_CIPHER * returned by
+ // EVP_get_cipherbyname()
+ EVP_CIPHER_free(ptr);
+}
+
+static const rb_data_type_t ossl_evp_cipher_holder_type = {
+ "OpenSSL/EVP_CIPHER",
+ {
+ .dfree = ossl_evp_cipher_free,
+ },
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
+};
+#endif
+
/*
* PUBLIC
*/
const EVP_CIPHER *
-ossl_evp_get_cipherbyname(VALUE obj)
+ossl_evp_cipher_fetch(VALUE obj, volatile VALUE *holder)
{
+ *holder = Qnil;
if (rb_obj_is_kind_of(obj, cCipher)) {
- EVP_CIPHER_CTX *ctx;
-
- GetCipher(obj, ctx);
-
- return EVP_CIPHER_CTX_cipher(ctx);
+ EVP_CIPHER_CTX *ctx;
+ GetCipher(obj, ctx);
+ EVP_CIPHER *cipher = (EVP_CIPHER *)EVP_CIPHER_CTX_cipher(ctx);
+#ifdef OSSL_USE_PROVIDER
+ *holder = TypedData_Wrap_Struct(0, &ossl_evp_cipher_holder_type, NULL);
+ if (!EVP_CIPHER_up_ref(cipher))
+ ossl_raise(eCipherError, "EVP_CIPHER_up_ref");
+ RTYPEDDATA_DATA(*holder) = cipher;
+#endif
+ return cipher;
}
- else {
- const EVP_CIPHER *cipher;
-
- StringValueCStr(obj);
- cipher = EVP_get_cipherbyname(RSTRING_PTR(obj));
- if (!cipher)
- ossl_raise(rb_eArgError,
- "unsupported cipher algorithm: %"PRIsVALUE, obj);
- return cipher;
+ const char *name = StringValueCStr(obj);
+ EVP_CIPHER *cipher = (EVP_CIPHER *)EVP_get_cipherbyname(name);
+#ifdef OSSL_USE_PROVIDER
+ if (!cipher) {
+ ossl_clear_error();
+ *holder = TypedData_Wrap_Struct(0, &ossl_evp_cipher_holder_type, NULL);
+ cipher = EVP_CIPHER_fetch(NULL, name, NULL);
+ RTYPEDDATA_DATA(*holder) = cipher;
}
+#endif
+ if (!cipher)
+ ossl_raise(eCipherError, "unsupported cipher algorithm: %"PRIsVALUE,
+ obj);
+ return cipher;
}
VALUE
@@ -77,10 +106,13 @@ ossl_cipher_new(const EVP_CIPHER *cipher)
VALUE ret;
EVP_CIPHER_CTX *ctx;
+ // NOTE: This does not set id_cipher_holder because this function should
+ // only be called from ossl_engine.c, which will not use any
+ // reference-counted ciphers.
ret = ossl_cipher_alloc(cCipher);
AllocCipher(ret, ctx);
if (EVP_CipherInit_ex(ctx, cipher, NULL, NULL, NULL, -1) != 1)
- ossl_raise(eCipherError, NULL);
+ ossl_raise(eCipherError, NULL);
return ret;
}
@@ -113,19 +145,17 @@ ossl_cipher_initialize(VALUE self, VALUE str)
{
EVP_CIPHER_CTX *ctx;
const EVP_CIPHER *cipher;
- char *name;
+ VALUE cipher_holder;
- name = StringValueCStr(str);
GetCipherInit(self, ctx);
if (ctx) {
- ossl_raise(rb_eRuntimeError, "Cipher already initialized!");
+ ossl_raise(rb_eRuntimeError, "Cipher already initialized!");
}
+ cipher = ossl_evp_cipher_fetch(str, &cipher_holder);
AllocCipher(self, ctx);
- if (!(cipher = EVP_get_cipherbyname(name))) {
- ossl_raise(rb_eRuntimeError, "unsupported cipher algorithm (%"PRIsVALUE")", str);
- }
if (EVP_CipherInit_ex(ctx, cipher, NULL, NULL, NULL, -1) != 1)
- ossl_raise(eCipherError, NULL);
+ ossl_raise(eCipherError, "EVP_CipherInit_ex");
+ rb_ivar_set(self, id_cipher_holder, cipher_holder);
return self;
}
@@ -141,11 +171,11 @@ ossl_cipher_copy(VALUE self, VALUE other)
GetCipherInit(self, ctx1);
if (!ctx1) {
- AllocCipher(self, ctx1);
+ AllocCipher(self, ctx1);
}
GetCipher(other, ctx2);
if (EVP_CIPHER_CTX_copy(ctx1, ctx2) != 1)
- ossl_raise(eCipherError, NULL);
+ ossl_raise(eCipherError, NULL);
return self;
}
@@ -170,8 +200,8 @@ ossl_s_ciphers(VALUE self)
ary = rb_ary_new();
OBJ_NAME_do_all_sorted(OBJ_NAME_TYPE_CIPHER_METH,
- add_cipher_name_to_ary,
- (void*)ary);
+ add_cipher_name_to_ary,
+ (void*)ary);
return ary;
}
@@ -192,7 +222,7 @@ ossl_cipher_reset(VALUE self)
GetCipher(self, ctx);
if (EVP_CipherInit_ex(ctx, NULL, NULL, NULL, NULL, -1) != 1)
- ossl_raise(eCipherError, NULL);
+ ossl_raise(eCipherError, NULL);
return self;
}
@@ -218,9 +248,8 @@ ossl_cipher_init(VALUE self, int enc)
*
* Initializes the Cipher for encryption.
*
- * Make sure to call Cipher#encrypt or Cipher#decrypt before using any of the
- * following methods:
- * * [#key=, #iv=, #random_key, #random_iv, #pkcs5_keyivgen]
+ * Make sure to call either #encrypt or #decrypt before using the Cipher for
+ * any operation or setting any parameters.
*
* Internally calls EVP_CipherInit_ex(ctx, NULL, NULL, NULL, NULL, 1).
*/
@@ -236,9 +265,8 @@ ossl_cipher_encrypt(VALUE self)
*
* Initializes the Cipher for decryption.
*
- * Make sure to call Cipher#encrypt or Cipher#decrypt before using any of the
- * following methods:
- * * [#key=, #iv=, #random_key, #random_iv, #pkcs5_keyivgen]
+ * Make sure to call either #encrypt or #decrypt before using the Cipher for
+ * any operation or setting any parameters.
*
* Internally calls EVP_CipherInit_ex(ctx, NULL, NULL, NULL, NULL, 0).
*/
@@ -254,46 +282,42 @@ ossl_cipher_decrypt(VALUE self)
*
* Generates and sets the key/IV based on a password.
*
- * *WARNING*: This method is only PKCS5 v1.5 compliant when using RC2, RC4-40,
- * or DES with MD5 or SHA1. Using anything else (like AES) will generate the
- * key/iv using an OpenSSL specific method. This method is deprecated and
- * should no longer be used. Use a PKCS5 v2 key generation method from
- * OpenSSL::PKCS5 instead.
+ * *WARNING*: This method is deprecated and should not be used. This method
+ * corresponds to EVP_BytesToKey(), a non-standard OpenSSL extension of the
+ * legacy PKCS #5 v1.5 key derivation function. See OpenSSL::KDF for other
+ * options to derive keys from passwords.
*
* === Parameters
* * _salt_ must be an 8 byte string if provided.
* * _iterations_ is an integer with a default of 2048.
* * _digest_ is a Digest object that defaults to 'MD5'
- *
- * A minimum of 1000 iterations is recommended.
- *
*/
static VALUE
ossl_cipher_pkcs5_keyivgen(int argc, VALUE *argv, VALUE self)
{
EVP_CIPHER_CTX *ctx;
const EVP_MD *digest;
- VALUE vpass, vsalt, viter, vdigest;
+ VALUE vpass, vsalt, viter, vdigest, md_holder;
unsigned char key[EVP_MAX_KEY_LENGTH], iv[EVP_MAX_IV_LENGTH], *salt = NULL;
int iter;
rb_scan_args(argc, argv, "13", &vpass, &vsalt, &viter, &vdigest);
StringValue(vpass);
if(!NIL_P(vsalt)){
- StringValue(vsalt);
- if(RSTRING_LEN(vsalt) != PKCS5_SALT_LEN)
- ossl_raise(eCipherError, "salt must be an 8-octet string");
- salt = (unsigned char *)RSTRING_PTR(vsalt);
+ StringValue(vsalt);
+ if(RSTRING_LEN(vsalt) != PKCS5_SALT_LEN)
+ ossl_raise(eCipherError, "salt must be an 8-octet string");
+ salt = (unsigned char *)RSTRING_PTR(vsalt);
}
iter = NIL_P(viter) ? 2048 : NUM2INT(viter);
if (iter <= 0)
- rb_raise(rb_eArgError, "iterations must be a positive integer");
- digest = NIL_P(vdigest) ? EVP_md5() : ossl_evp_get_digestbyname(vdigest);
+ rb_raise(rb_eArgError, "iterations must be a positive integer");
+ digest = NIL_P(vdigest) ? EVP_md5() : ossl_evp_md_fetch(vdigest, &md_holder);
GetCipher(self, ctx);
EVP_BytesToKey(EVP_CIPHER_CTX_cipher(ctx), digest, salt,
- (unsigned char *)RSTRING_PTR(vpass), RSTRING_LENINT(vpass), iter, key, iv);
+ (unsigned char *)RSTRING_PTR(vpass), RSTRING_LENINT(vpass), iter, key, iv);
if (EVP_CipherInit_ex(ctx, NULL, NULL, key, iv, -1) != 1)
- ossl_raise(eCipherError, NULL);
+ ossl_raise(eCipherError, NULL);
OPENSSL_cleanse(key, sizeof key);
OPENSSL_cleanse(iv, sizeof iv);
@@ -304,25 +328,25 @@ ossl_cipher_pkcs5_keyivgen(int argc, VALUE *argv, VALUE self)
static int
ossl_cipher_update_long(EVP_CIPHER_CTX *ctx, unsigned char *out, long *out_len_ptr,
- const unsigned char *in, long in_len)
+ const unsigned char *in, long in_len)
{
int out_part_len;
int limit = INT_MAX / 2 + 1;
long out_len = 0;
do {
- int in_part_len = in_len > limit ? limit : (int)in_len;
+ int in_part_len = in_len > limit ? limit : (int)in_len;
- if (!EVP_CipherUpdate(ctx, out ? (out + out_len) : 0,
- &out_part_len, in, in_part_len))
- return 0;
+ if (!EVP_CipherUpdate(ctx, out ? (out + out_len) : 0,
+ &out_part_len, in, in_part_len))
+ return 0;
- out_len += out_part_len;
- in += in_part_len;
+ out_len += out_part_len;
+ in += in_part_len;
} while ((in_len -= limit) > 0);
if (out_len_ptr)
- *out_len_ptr = out_len;
+ *out_len_ptr = out_len;
return 1;
}
@@ -338,6 +362,9 @@ ossl_cipher_update_long(EVP_CIPHER_CTX *ctx, unsigned char *out, long *out_len_p
*
* If _buffer_ is given, the encryption/decryption result will be written to
* it. _buffer_ will be resized automatically.
+ *
+ * *NOTE*: When decrypting using an AEAD cipher, the integrity of the output
+ * is not verified until #final has been called.
*/
static VALUE
ossl_cipher_update(int argc, VALUE *argv, VALUE self)
@@ -350,7 +377,7 @@ ossl_cipher_update(int argc, VALUE *argv, VALUE self)
rb_scan_args(argc, argv, "11", &data, &str);
if (!RTEST(rb_attr_get(self, id_key_set)))
- ossl_raise(eCipherError, "key not set");
+ ossl_raise(eCipherError, "key not set");
StringValue(data);
in = (unsigned char *)RSTRING_PTR(data);
@@ -369,14 +396,14 @@ ossl_cipher_update(int argc, VALUE *argv, VALUE self)
* currently implemented in OpenSSL, but this can change in the future.
*/
if (in_len > LONG_MAX - EVP_MAX_BLOCK_LENGTH) {
- ossl_raise(rb_eRangeError,
- "data too big to make output buffer: %ld bytes", in_len);
+ 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);
- } else {
+ if (NIL_P(str))
+ str = rb_str_buf_new(out_len);
+ else {
StringValue(str);
if ((long)rb_str_capacity(str) >= out_len)
rb_str_modify(str);
@@ -384,9 +411,9 @@ ossl_cipher_update(int argc, VALUE *argv, VALUE self)
rb_str_modify_expand(str, out_len - RSTRING_LEN(str));
}
- 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));
+ if (!ossl_cipher_update_long(ctx, (unsigned char *)RSTRING_PTR(str),
+ &out_len, in, in_len))
+ ossl_raise(eCipherError, "EVP_CipherUpdate");
rb_str_set_len(str, out_len);
return str;
@@ -397,14 +424,17 @@ ossl_cipher_update(int argc, VALUE *argv, VALUE self)
* cipher.final -> string
*
* Returns the remaining data held in the cipher object. Further calls to
- * Cipher#update or Cipher#final will return garbage. This call should always
+ * Cipher#update or Cipher#final are invalid. This call should always
* be made as the last call of an encryption or decryption operation, after
* having fed the entire plaintext or ciphertext to the Cipher instance.
*
- * If an authenticated cipher was used, a CipherError is raised if the tag
- * could not be authenticated successfully. Only call this method after
- * setting the authentication tag and passing the entire contents of the
- * ciphertext into the cipher.
+ * When encrypting using an AEAD cipher, the authentication tag can be
+ * retrieved by #auth_tag after #final has been called.
+ *
+ * When decrypting using an AEAD cipher, this method will verify the integrity
+ * of the ciphertext and the associated data with the authentication tag,
+ * which must be set by #auth_tag= prior to calling this method.
+ * If the verification fails, CipherError will be raised.
*/
static VALUE
ossl_cipher_final(VALUE self)
@@ -415,9 +445,17 @@ ossl_cipher_final(VALUE self)
GetCipher(self, ctx);
str = rb_str_new(0, EVP_CIPHER_CTX_block_size(ctx));
- if (!EVP_CipherFinal_ex(ctx, (unsigned char *)RSTRING_PTR(str), &out_len))
- ossl_raise(eCipherError, NULL);
- assert(out_len <= RSTRING_LEN(str));
+ if (!EVP_CipherFinal_ex(ctx, (unsigned char *)RSTRING_PTR(str), &out_len)) {
+ /* For AEAD ciphers, this is likely an authentication failure */
+ if (EVP_CIPHER_flags(EVP_CIPHER_CTX_cipher(ctx)) & EVP_CIPH_FLAG_AEAD_CIPHER) {
+ /* For AEAD ciphers, EVP_CipherFinal_ex failures are authentication tag verification failures */
+ ossl_raise(eAuthTagError, "AEAD authentication tag verification failed");
+ }
+ else {
+ /* For non-AEAD ciphers */
+ ossl_raise(eCipherError, "cipher final failed");
+ }
+ }
rb_str_set_len(str, out_len);
return str;
@@ -442,7 +480,7 @@ ossl_cipher_name(VALUE self)
/*
* call-seq:
- * cipher.key = string -> string
+ * cipher.key = string
*
* Sets the cipher key. To generate a key, you should either use a secure
* random byte string or, if the key is to be derived from a password, you
@@ -450,6 +488,8 @@ ossl_cipher_name(VALUE self)
* generate a secure random-based key, Cipher#random_key may be used.
*
* Only call this method after calling Cipher#encrypt or Cipher#decrypt.
+ *
+ * See also the man page EVP_CipherInit_ex(3).
*/
static VALUE
ossl_cipher_set_key(VALUE self, VALUE key)
@@ -462,10 +502,10 @@ ossl_cipher_set_key(VALUE self, VALUE key)
key_len = EVP_CIPHER_CTX_key_length(ctx);
if (RSTRING_LEN(key) != key_len)
- ossl_raise(rb_eArgError, "key must be %d bytes", key_len);
+ ossl_raise(rb_eArgError, "key must be %d bytes", key_len);
if (EVP_CipherInit_ex(ctx, NULL, NULL, (unsigned char *)RSTRING_PTR(key), NULL, -1) != 1)
- ossl_raise(eCipherError, NULL);
+ ossl_raise(eCipherError, NULL);
rb_ivar_set(self, id_key_set, Qtrue);
@@ -474,15 +514,21 @@ ossl_cipher_set_key(VALUE self, VALUE key)
/*
* call-seq:
- * cipher.iv = string -> string
+ * cipher.iv = string
*
* Sets the cipher IV. Please note that since you should never be using ECB
* mode, an IV is always explicitly required and should be set prior to
- * encryption. The IV itself can be safely transmitted in public, but it
- * should be unpredictable to prevent certain kinds of attacks. You may use
- * Cipher#random_iv to create a secure random IV.
+ * encryption. The IV itself can be safely transmitted in public.
*
- * Only call this method after calling Cipher#encrypt or Cipher#decrypt.
+ * This method expects the String to have the length equal to #iv_len. To use
+ * a different IV length with an AEAD cipher, #iv_len= must be set prior to
+ * calling this method.
+ *
+ * *NOTE*: In OpenSSL API conventions, the IV value may correspond to the
+ * "nonce" instead in some cipher modes. Refer to the OpenSSL man pages for
+ * details.
+ *
+ * See also the man page EVP_CipherInit_ex(3).
*/
static VALUE
ossl_cipher_set_iv(VALUE self, VALUE iv)
@@ -494,14 +540,14 @@ ossl_cipher_set_iv(VALUE self, VALUE iv)
GetCipher(self, ctx);
if (EVP_CIPHER_flags(EVP_CIPHER_CTX_cipher(ctx)) & EVP_CIPH_FLAG_AEAD_CIPHER)
- iv_len = (int)(VALUE)EVP_CIPHER_CTX_get_app_data(ctx);
+ iv_len = (int)(VALUE)EVP_CIPHER_CTX_get_app_data(ctx);
if (!iv_len)
- iv_len = EVP_CIPHER_CTX_iv_length(ctx);
+ iv_len = EVP_CIPHER_CTX_iv_length(ctx);
if (RSTRING_LEN(iv) != iv_len)
- ossl_raise(rb_eArgError, "iv must be %d bytes", iv_len);
+ ossl_raise(rb_eArgError, "iv must be %d bytes", iv_len);
if (EVP_CipherInit_ex(ctx, NULL, NULL, NULL, (unsigned char *)RSTRING_PTR(iv), -1) != 1)
- ossl_raise(eCipherError, NULL);
+ ossl_raise(eCipherError, NULL);
return iv;
}
@@ -510,8 +556,7 @@ ossl_cipher_set_iv(VALUE self, VALUE iv)
* call-seq:
* cipher.authenticated? -> true | false
*
- * Indicated whether this Cipher instance uses an Authenticated Encryption
- * mode.
+ * Indicates whether this Cipher instance uses an AEAD mode.
*/
static VALUE
ossl_cipher_is_authenticated(VALUE self)
@@ -525,21 +570,23 @@ ossl_cipher_is_authenticated(VALUE self)
/*
* call-seq:
- * cipher.auth_data = string -> string
+ * cipher.auth_data = string
+ *
+ * Sets additional authenticated data (AAD), also called associated data, for
+ * this Cipher. This method is available for AEAD ciphers.
*
- * Sets the cipher's additional authenticated data. This field must be
- * set when using AEAD cipher modes such as GCM or CCM. If no associated
- * data shall be used, this method must *still* be called with a value of "".
* The contents of this field should be non-sensitive data which will be
* added to the ciphertext to generate the authentication tag which validates
* the contents of the ciphertext.
*
- * The AAD must be set prior to encryption or decryption. In encryption mode,
- * it must be set after calling Cipher#encrypt and setting Cipher#key= and
- * Cipher#iv=. When decrypting, the authenticated data must be set after key,
- * iv and especially *after* the authentication tag has been set. I.e. set it
- * only after calling Cipher#decrypt, Cipher#key=, Cipher#iv= and
- * Cipher#auth_tag= first.
+ * This method must be called after #key= and #iv= have been set, but before
+ * starting actual encryption or decryption with #update. In some cipher modes,
+ * #auth_tag_len= and #ccm_data_len= may also need to be called before this
+ * method.
+ *
+ * See also the "AEAD Interface" section of the man page EVP_EncryptInit(3).
+ * This method internally calls EVP_CipherUpdate() with the output buffer
+ * set to NULL.
*/
static VALUE
ossl_cipher_set_auth_data(VALUE self, VALUE data)
@@ -555,7 +602,7 @@ ossl_cipher_set_auth_data(VALUE self, VALUE data)
GetCipher(self, ctx);
if (!(EVP_CIPHER_flags(EVP_CIPHER_CTX_cipher(ctx)) & EVP_CIPH_FLAG_AEAD_CIPHER))
- ossl_raise(eCipherError, "AEAD not supported by this cipher");
+ ossl_raise(eCipherError, "AEAD not supported by this cipher");
if (!ossl_cipher_update_long(ctx, NULL, &out_len, in, in_len))
ossl_raise(eCipherError, "couldn't set additional authenticated data");
@@ -567,16 +614,17 @@ ossl_cipher_set_auth_data(VALUE self, VALUE data)
* call-seq:
* cipher.auth_tag(tag_len = 16) -> String
*
- * Gets the authentication tag generated by Authenticated Encryption Cipher
- * modes (GCM for example). This tag may be stored along with the ciphertext,
- * then set on the decryption cipher to authenticate the contents of the
- * ciphertext against changes. If the optional integer parameter _tag_len_ is
- * given, the returned tag will be _tag_len_ bytes long. If the parameter is
- * omitted, the default length of 16 bytes or the length previously set by
- * #auth_tag_len= will be used. For maximum security, the longest possible
- * should be chosen.
+ * Gets the generated authentication tag. This method is available for AEAD
+ * ciphers, and should be called after encryption has been finalized by calling
+ * #final.
+ *
+ * The returned tag will be _tag_len_ bytes long. Some cipher modes require
+ * the desired length in advance using a separate call to #auth_tag_len=,
+ * before starting encryption.
*
- * The tag may only be retrieved after calling Cipher#final.
+ * See also the "AEAD Interface" section of the man page EVP_EncryptInit(3).
+ * This method internally calls EVP_CIPHER_CTX_ctrl() with
+ * EVP_CTRL_AEAD_GET_TAG.
*/
static VALUE
ossl_cipher_get_auth_tag(int argc, VALUE *argv, VALUE self)
@@ -587,34 +635,42 @@ ossl_cipher_get_auth_tag(int argc, VALUE *argv, VALUE self)
rb_scan_args(argc, argv, "01", &vtag_len);
if (NIL_P(vtag_len))
- vtag_len = rb_attr_get(self, id_auth_tag_len);
+ vtag_len = rb_attr_get(self, id_auth_tag_len);
if (!NIL_P(vtag_len))
- tag_len = NUM2INT(vtag_len);
+ tag_len = NUM2INT(vtag_len);
GetCipher(self, ctx);
if (!(EVP_CIPHER_flags(EVP_CIPHER_CTX_cipher(ctx)) & EVP_CIPH_FLAG_AEAD_CIPHER))
- ossl_raise(eCipherError, "authentication tag not supported by this cipher");
+ ossl_raise(eCipherError, "authentication tag not supported by this cipher");
ret = rb_str_new(NULL, tag_len);
- if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_GET_TAG, tag_len, RSTRING_PTR(ret)))
- ossl_raise(eCipherError, "retrieving the authentication tag failed");
+ if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_GET_TAG, tag_len, RSTRING_PTR(ret)) <= 0)
+ ossl_raise(eCipherError, "retrieving the authentication tag failed");
return ret;
}
/*
* call-seq:
- * cipher.auth_tag = string -> string
+ * cipher.auth_tag = string
*
* Sets the authentication tag to verify the integrity of the ciphertext.
- * This can be called only when the cipher supports AE. The tag must be set
- * after calling Cipher#decrypt, Cipher#key= and Cipher#iv=, but before
- * calling Cipher#final. After all decryption is performed, the tag is
- * verified automatically in the call to Cipher#final.
*
- * For OCB mode, the tag length must be supplied with #auth_tag_len=
- * beforehand.
+ * The authentication tag must be set before #final is called. The tag is
+ * verified during the #final call.
+ *
+ * Note that, for CCM mode and OCB mode, the expected length of the tag must
+ * be set before starting decryption by a separate call to #auth_tag_len=.
+ * The content of the tag can be provided at any time before #final is called.
+ *
+ * *NOTE*: The caller must ensure that the String passed to this method has
+ * the desired length. Some cipher modes support variable tag lengths, and
+ * this method may accept a truncated tag without raising an exception.
+ *
+ * See also the "AEAD Interface" section of the man page EVP_EncryptInit(3).
+ * This method internally calls EVP_CIPHER_CTX_ctrl() with
+ * EVP_CTRL_AEAD_SET_TAG.
*/
static VALUE
ossl_cipher_set_auth_tag(VALUE self, VALUE vtag)
@@ -629,24 +685,27 @@ ossl_cipher_set_auth_tag(VALUE self, VALUE vtag)
GetCipher(self, ctx);
if (!(EVP_CIPHER_flags(EVP_CIPHER_CTX_cipher(ctx)) & EVP_CIPH_FLAG_AEAD_CIPHER))
- ossl_raise(eCipherError, "authentication tag not supported by this cipher");
+ ossl_raise(eCipherError, "authentication tag not supported by this cipher");
- if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, tag_len, tag))
- ossl_raise(eCipherError, "unable to set AEAD tag");
+ if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, tag_len, tag) <= 0)
+ ossl_raise(eCipherError, "unable to set AEAD tag");
return vtag;
}
/*
* call-seq:
- * cipher.auth_tag_len = Integer -> Integer
+ * cipher.auth_tag_len = integer
+ *
+ * Sets the length of the expected authentication tag for this Cipher. This
+ * method is available for some of AEAD ciphers that require the length to be
+ * set before starting encryption or decryption, such as CCM mode or OCB mode.
*
- * Sets the length of the authentication tag to be generated or to be given for
- * AEAD ciphers that requires it as in input parameter. Note that not all AEAD
- * ciphers support this method.
+ * For CCM mode and OCB mode, the tag length must be set before #iv= is set.
*
- * In OCB mode, the length must be supplied both when encrypting and when
- * decrypting, and must be before specifying an IV.
+ * See also the "AEAD Interface" section of the man page EVP_EncryptInit(3).
+ * This method internally calls EVP_CIPHER_CTX_ctrl() with
+ * EVP_CTRL_AEAD_SET_TAG and a NULL buffer.
*/
static VALUE
ossl_cipher_set_auth_tag_len(VALUE self, VALUE vlen)
@@ -656,10 +715,10 @@ ossl_cipher_set_auth_tag_len(VALUE self, VALUE vlen)
GetCipher(self, ctx);
if (!(EVP_CIPHER_flags(EVP_CIPHER_CTX_cipher(ctx)) & EVP_CIPH_FLAG_AEAD_CIPHER))
- ossl_raise(eCipherError, "AEAD not supported by this cipher");
+ ossl_raise(eCipherError, "AEAD not supported by this cipher");
- if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, tag_len, NULL))
- ossl_raise(eCipherError, "unable to set authentication tag length");
+ if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, tag_len, NULL) <= 0)
+ ossl_raise(eCipherError, "unable to set authentication tag length");
/* for #auth_tag */
rb_ivar_set(self, id_auth_tag_len, INT2NUM(tag_len));
@@ -669,11 +728,16 @@ ossl_cipher_set_auth_tag_len(VALUE self, VALUE vlen)
/*
* call-seq:
- * cipher.iv_len = integer -> integer
+ * cipher.iv_len = integer
*
- * Sets the IV/nonce length of the Cipher. Normally block ciphers don't allow
- * changing the IV length, but some make use of IV for 'nonce'. You may need
- * this for interoperability with other applications.
+ * Sets the IV/nonce length for this Cipher. This method is available for AEAD
+ * ciphers that support variable IV lengths. This method can be called if a
+ * different IV length than OpenSSL's default is desired, prior to calling
+ * #iv=.
+ *
+ * See also the "AEAD Interface" section of the man page EVP_EncryptInit(3).
+ * This method internally calls EVP_CIPHER_CTX_ctrl() with
+ * EVP_CTRL_AEAD_SET_IVLEN.
*/
static VALUE
ossl_cipher_set_iv_length(VALUE self, VALUE iv_length)
@@ -683,10 +747,10 @@ ossl_cipher_set_iv_length(VALUE self, VALUE iv_length)
GetCipher(self, ctx);
if (!(EVP_CIPHER_flags(EVP_CIPHER_CTX_cipher(ctx)) & EVP_CIPH_FLAG_AEAD_CIPHER))
- ossl_raise(eCipherError, "cipher does not support AEAD");
+ ossl_raise(eCipherError, "cipher does not support AEAD");
- if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_IVLEN, len, NULL))
- ossl_raise(eCipherError, "unable to set IV length");
+ if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_IVLEN, len, NULL) <= 0)
+ ossl_raise(eCipherError, "unable to set IV length");
/*
* EVP_CIPHER_CTX_iv_length() returns the default length. So we need to save
@@ -699,13 +763,14 @@ ossl_cipher_set_iv_length(VALUE self, VALUE iv_length)
/*
* call-seq:
- * cipher.key_len = integer -> integer
+ * cipher.key_len = integer
*
* Sets the key length of the cipher. If the cipher is a fixed length cipher
* then attempting to set the key length to any value other than the fixed
* value is an error.
*
- * Under normal circumstances you do not need to call this method (and probably shouldn't).
+ * Under normal circumstances you do not need to call this method (and
+ * probably shouldn't).
*
* See EVP_CIPHER_CTX_set_key_length for further information.
*/
@@ -722,13 +787,16 @@ ossl_cipher_set_key_length(VALUE self, VALUE key_length)
return key_length;
}
+// TODO: Should #padding= take a boolean value instead?
/*
* call-seq:
- * cipher.padding = integer -> integer
+ * cipher.padding = 1 or 0
*
- * Enables or disables padding. By default encryption operations are padded using standard block padding and the
- * padding is checked and removed when decrypting. If the pad parameter is zero then no padding is performed, the
- * total amount of data encrypted or decrypted must then be a multiple of the block size or an error will occur.
+ * Enables or disables padding. By default encryption operations are padded
+ * using standard block padding and the padding is checked and removed when
+ * decrypting. If the pad parameter is zero then no padding is performed, the
+ * total amount of data encrypted or decrypted must then be a multiple of the
+ * block size or an error will occur.
*
* See EVP_CIPHER_CTX_set_padding for further information.
*/
@@ -740,7 +808,7 @@ ossl_cipher_set_padding(VALUE self, VALUE padding)
GetCipher(self, ctx);
if (EVP_CIPHER_CTX_set_padding(ctx, pad) != 1)
- ossl_raise(eCipherError, NULL);
+ ossl_raise(eCipherError, NULL);
return padding;
}
@@ -774,9 +842,9 @@ ossl_cipher_iv_length(VALUE self)
GetCipher(self, ctx);
if (EVP_CIPHER_flags(EVP_CIPHER_CTX_cipher(ctx)) & EVP_CIPH_FLAG_AEAD_CIPHER)
- len = (int)(VALUE)EVP_CIPHER_CTX_get_app_data(ctx);
+ len = (int)(VALUE)EVP_CIPHER_CTX_get_app_data(ctx);
if (!len)
- len = EVP_CIPHER_CTX_iv_length(ctx);
+ len = EVP_CIPHER_CTX_iv_length(ctx);
return INT2NUM(len);
}
@@ -799,13 +867,17 @@ ossl_cipher_block_size(VALUE self)
/*
* call-seq:
- * cipher.ccm_data_len = integer -> integer
+ * cipher.ccm_data_len = integer
*
- * Sets the length of the plaintext / ciphertext message that will be
- * processed in CCM mode. Make sure to call this method after #key= and
- * #iv= have been set, and before #auth_data=.
+ * Sets the total length of the plaintext / ciphertext message that will be
+ * processed by #update in CCM mode.
*
- * Only call this method after calling Cipher#encrypt or Cipher#decrypt.
+ * Make sure to call this method after #key= and #iv= have been set, and
+ * before #auth_data= or #update are called.
+ *
+ * This method is only available for CCM mode ciphers.
+ *
+ * See also the "AEAD Interface" section of the man page EVP_EncryptInit(3).
*/
static VALUE
ossl_cipher_set_ccm_data_len(VALUE self, VALUE data_len)
@@ -828,11 +900,6 @@ ossl_cipher_set_ccm_data_len(VALUE self, VALUE data_len)
void
Init_ossl_cipher(void)
{
-#if 0
- mOSSL = rb_define_module("OpenSSL");
- eOSSLError = rb_define_class_under(mOSSL, "OpenSSLError", rb_eStandardError);
-#endif
-
/* Document-class: OpenSSL::Cipher
*
* Provides symmetric algorithms for encryption and decryption. The
@@ -988,24 +1055,28 @@ Init_ossl_cipher(void)
* could otherwise be exploited to modify ciphertexts in ways beneficial to
* potential attackers.
*
- * An associated data is used where there is additional information, such as
+ * Associated data, also called additional authenticated data (AAD), is
+ * optionally used where there is additional information, such as
* headers or some metadata, that must be also authenticated but not
- * necessarily need to be encrypted. If no associated data is needed for
- * encryption and later decryption, the OpenSSL library still requires a
- * value to be set - "" may be used in case none is available.
+ * necessarily need to be encrypted.
*
* An example using the GCM (Galois/Counter Mode). You have 16 bytes _key_,
* 12 bytes (96 bits) _nonce_ and the associated data _auth_data_. Be sure
* not to reuse the _key_ and _nonce_ pair. Reusing an nonce ruins the
* security guarantees of GCM mode.
*
+ * key = OpenSSL::Random.random_bytes(16)
+ * nonce = OpenSSL::Random.random_bytes(12)
+ * auth_data = "authenticated but unencrypted data"
+ * data = "encrypted data"
+ *
* cipher = OpenSSL::Cipher.new('aes-128-gcm').encrypt
* cipher.key = key
* cipher.iv = nonce
* cipher.auth_data = auth_data
*
* encrypted = cipher.update(data) + cipher.final
- * tag = cipher.auth_tag # produces 16 bytes tag by default
+ * tag = cipher.auth_tag(16)
*
* Now you are the receiver. You know the _key_ and have received _nonce_,
* _auth_data_, _encrypted_ and _tag_ through an untrusted network. Note
@@ -1018,15 +1089,21 @@ Init_ossl_cipher(void)
* decipher = OpenSSL::Cipher.new('aes-128-gcm').decrypt
* decipher.key = key
* decipher.iv = nonce
- * decipher.auth_tag = tag
+ * decipher.auth_tag = tag # could be called at any time before #final
* decipher.auth_data = auth_data
*
* decrypted = decipher.update(encrypted) + decipher.final
*
* puts data == decrypted #=> true
+ *
+ * Note that other AEAD ciphers may require additional steps, such as
+ * setting the expected tag length (#auth_tag_len=) or the total data
+ * length (#ccm_data_len=) in advance. Make sure to read the relevant man
+ * page for details.
*/
cCipher = rb_define_class_under(mOSSL, "Cipher", rb_cObject);
eCipherError = rb_define_class_under(cCipher, "CipherError", eOSSLError);
+ eAuthTagError = rb_define_class_under(cCipher, "AuthTagError", eCipherError);
rb_define_alloc_func(cCipher, ossl_cipher_alloc);
rb_define_method(cCipher, "initialize_copy", ossl_cipher_copy, 1);
@@ -1056,4 +1133,5 @@ Init_ossl_cipher(void)
id_auth_tag_len = rb_intern_const("auth_tag_len");
id_key_set = rb_intern_const("key_set");
+ id_cipher_holder = rb_intern_const("EVP_CIPHER_holder");
}
diff --git a/ext/openssl/ossl_cipher.h b/ext/openssl/ossl_cipher.h
index 12da68ca3e..fba63a140f 100644
--- a/ext/openssl/ossl_cipher.h
+++ b/ext/openssl/ossl_cipher.h
@@ -10,7 +10,16 @@
#if !defined(_OSSL_CIPHER_H_)
#define _OSSL_CIPHER_H_
-const EVP_CIPHER *ossl_evp_get_cipherbyname(VALUE);
+/*
+ * Gets EVP_CIPHER from a String or an OpenSSL::Digest instance (discouraged,
+ * but still supported for compatibility). A holder object is created if the
+ * EVP_CIPHER is a "fetched" algorithm.
+ */
+const EVP_CIPHER *ossl_evp_cipher_fetch(VALUE obj, volatile VALUE *holder);
+/*
+ * This is meant for OpenSSL::Engine#cipher. EVP_CIPHER must not be a fetched
+ * one.
+ */
VALUE ossl_cipher_new(const EVP_CIPHER *);
void Init_ossl_cipher(void);
diff --git a/ext/openssl/ossl_config.c b/ext/openssl/ossl_config.c
index ee2ff6786f..274875a978 100644
--- a/ext/openssl/ossl_config.c
+++ b/ext/openssl/ossl_config.c
@@ -413,11 +413,6 @@ Init_ossl_config(void)
char *path;
VALUE path_str;
-#if 0
- mOSSL = rb_define_module("OpenSSL");
- eOSSLError = rb_define_class_under(mOSSL, "OpenSSLError", rb_eStandardError);
-#endif
-
/* Document-class: OpenSSL::Config
*
* Configuration for the openssl library.
@@ -426,7 +421,7 @@ Init_ossl_config(void)
* configuration. See the value of OpenSSL::Config::DEFAULT_CONFIG_FILE for
* the location of the file for your host.
*
- * See also http://www.openssl.org/docs/apps/config.html
+ * See also https://docs.openssl.org/master/man5/config/
*/
cConfig = rb_define_class_under(mOSSL, "Config", rb_cObject);
diff --git a/ext/openssl/ossl_digest.c b/ext/openssl/ossl_digest.c
index 329de6c1ba..e23968b1e3 100644
--- a/ext/openssl/ossl_digest.c
+++ b/ext/openssl/ossl_digest.c
@@ -12,7 +12,7 @@
#define GetDigest(obj, ctx) do { \
TypedData_Get_Struct((obj), EVP_MD_CTX, &ossl_digest_type, (ctx)); \
if (!(ctx)) { \
- ossl_raise(rb_eRuntimeError, "Digest CTX wasn't initialized!"); \
+ ossl_raise(rb_eRuntimeError, "Digest CTX wasn't initialized!"); \
} \
} while (0)
@@ -21,6 +21,7 @@
*/
static VALUE cDigest;
static VALUE eDigestError;
+static ID id_md_holder;
static VALUE ossl_digest_alloc(VALUE klass);
@@ -33,39 +34,67 @@ ossl_digest_free(void *ctx)
static const rb_data_type_t ossl_digest_type = {
"OpenSSL/Digest",
{
- 0, ossl_digest_free,
+ 0, ossl_digest_free,
},
0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
};
+#ifdef OSSL_USE_PROVIDER
+static void
+ossl_evp_md_free(void *ptr)
+{
+ // This is safe to call against const EVP_MD * returned by
+ // EVP_get_digestbyname()
+ EVP_MD_free(ptr);
+}
+
+static const rb_data_type_t ossl_evp_md_holder_type = {
+ "OpenSSL/EVP_MD",
+ {
+ .dfree = ossl_evp_md_free,
+ },
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
+};
+#endif
+
/*
* Public
*/
const EVP_MD *
-ossl_evp_get_digestbyname(VALUE obj)
+ossl_evp_md_fetch(VALUE obj, volatile VALUE *holder)
{
- const EVP_MD *md;
- ASN1_OBJECT *oid = NULL;
-
- if (RB_TYPE_P(obj, T_STRING)) {
- const char *name = StringValueCStr(obj);
-
- md = EVP_get_digestbyname(name);
- if (!md) {
- oid = OBJ_txt2obj(name, 0);
- md = EVP_get_digestbyobj(oid);
- ASN1_OBJECT_free(oid);
- }
- if(!md)
- ossl_raise(rb_eRuntimeError, "Unsupported digest algorithm (%"PRIsVALUE").", obj);
- } else {
+ *holder = Qnil;
+ if (rb_obj_is_kind_of(obj, cDigest)) {
EVP_MD_CTX *ctx;
-
GetDigest(obj, ctx);
-
- md = EVP_MD_CTX_get0_md(ctx);
+ EVP_MD *md = (EVP_MD *)EVP_MD_CTX_get0_md(ctx);
+#ifdef OSSL_USE_PROVIDER
+ *holder = TypedData_Wrap_Struct(0, &ossl_evp_md_holder_type, NULL);
+ if (!EVP_MD_up_ref(md))
+ ossl_raise(eDigestError, "EVP_MD_up_ref");
+ RTYPEDDATA_DATA(*holder) = md;
+#endif
+ return md;
}
+ const char *name = StringValueCStr(obj);
+ EVP_MD *md = (EVP_MD *)EVP_get_digestbyname(name);
+ if (!md) {
+ ASN1_OBJECT *oid = OBJ_txt2obj(name, 0);
+ md = (EVP_MD *)EVP_get_digestbyobj(oid);
+ ASN1_OBJECT_free(oid);
+ }
+#ifdef OSSL_USE_PROVIDER
+ if (!md) {
+ ossl_clear_error();
+ *holder = TypedData_Wrap_Struct(0, &ossl_evp_md_holder_type, NULL);
+ md = EVP_MD_fetch(NULL, name, NULL);
+ RTYPEDDATA_DATA(*holder) = md;
+ }
+#endif
+ if (!md)
+ ossl_raise(eDigestError, "unsupported digest algorithm: %"PRIsVALUE,
+ obj);
return md;
}
@@ -75,14 +104,17 @@ ossl_digest_new(const EVP_MD *md)
VALUE ret;
EVP_MD_CTX *ctx;
+ // NOTE: This does not set id_md_holder because this function should
+ // only be called from ossl_engine.c, which will not use any
+ // reference-counted digests.
ret = ossl_digest_alloc(cDigest);
ctx = EVP_MD_CTX_new();
if (!ctx)
- ossl_raise(eDigestError, "EVP_MD_CTX_new");
+ ossl_raise(eDigestError, "EVP_MD_CTX_new");
RTYPEDDATA_DATA(ret) = ctx;
if (!EVP_DigestInit_ex(ctx, md, NULL))
- ossl_raise(eDigestError, "Digest initialization failed");
+ ossl_raise(eDigestError, "Digest initialization failed");
return ret;
}
@@ -121,21 +153,22 @@ ossl_digest_initialize(int argc, VALUE *argv, VALUE self)
{
EVP_MD_CTX *ctx;
const EVP_MD *md;
- VALUE type, data;
+ VALUE type, data, md_holder;
rb_scan_args(argc, argv, "11", &type, &data);
- md = ossl_evp_get_digestbyname(type);
+ md = ossl_evp_md_fetch(type, &md_holder);
if (!NIL_P(data)) StringValue(data);
TypedData_Get_Struct(self, EVP_MD_CTX, &ossl_digest_type, ctx);
if (!ctx) {
- RTYPEDDATA_DATA(self) = ctx = EVP_MD_CTX_new();
- if (!ctx)
- ossl_raise(eDigestError, "EVP_MD_CTX_new");
+ RTYPEDDATA_DATA(self) = ctx = EVP_MD_CTX_new();
+ if (!ctx)
+ ossl_raise(eDigestError, "EVP_MD_CTX_new");
}
if (!EVP_DigestInit_ex(ctx, md, NULL))
- ossl_raise(eDigestError, "Digest initialization failed");
+ ossl_raise(eDigestError, "Digest initialization failed");
+ rb_ivar_set(self, id_md_holder, md_holder);
if (!NIL_P(data)) return ossl_digest_update(self, data);
return self;
@@ -152,14 +185,14 @@ ossl_digest_copy(VALUE self, VALUE other)
TypedData_Get_Struct(self, EVP_MD_CTX, &ossl_digest_type, ctx1);
if (!ctx1) {
- RTYPEDDATA_DATA(self) = ctx1 = EVP_MD_CTX_new();
- if (!ctx1)
- ossl_raise(eDigestError, "EVP_MD_CTX_new");
+ RTYPEDDATA_DATA(self) = ctx1 = EVP_MD_CTX_new();
+ if (!ctx1)
+ ossl_raise(eDigestError, "EVP_MD_CTX_new");
}
GetDigest(other, ctx2);
if (!EVP_MD_CTX_copy(ctx1, ctx2)) {
- ossl_raise(eDigestError, NULL);
+ ossl_raise(eDigestError, NULL);
}
return self;
}
@@ -184,8 +217,8 @@ ossl_s_digests(VALUE self)
ary = rb_ary_new();
OBJ_NAME_do_all_sorted(OBJ_NAME_TYPE_MD_METH,
- add_digest_name_to_ary,
- (void*)ary);
+ add_digest_name_to_ary,
+ (void*)ary);
return ary;
}
@@ -205,7 +238,7 @@ ossl_digest_reset(VALUE self)
GetDigest(self, ctx);
if (EVP_DigestInit_ex(ctx, EVP_MD_CTX_get0_md(ctx), NULL) != 1) {
- ossl_raise(eDigestError, "Digest initialization failed.");
+ ossl_raise(eDigestError, "Digest initialization failed.");
}
return self;
@@ -235,7 +268,7 @@ ossl_digest_update(VALUE self, VALUE data)
GetDigest(self, ctx);
if (!EVP_DigestUpdate(ctx, RSTRING_PTR(data), RSTRING_LEN(data)))
- ossl_raise(eDigestError, "EVP_DigestUpdate");
+ ossl_raise(eDigestError, "EVP_DigestUpdate");
return self;
}
@@ -254,7 +287,7 @@ ossl_digest_finish(VALUE self)
GetDigest(self, ctx);
str = rb_str_new(NULL, EVP_MD_CTX_size(ctx));
if (!EVP_DigestFinal_ex(ctx, (unsigned char *)RSTRING_PTR(str), NULL))
- ossl_raise(eDigestError, "EVP_DigestFinal_ex");
+ ossl_raise(eDigestError, "EVP_DigestFinal_ex");
return str;
}
@@ -332,11 +365,6 @@ ossl_digest_block_length(VALUE self)
void
Init_ossl_digest(void)
{
-#if 0
- mOSSL = rb_define_module("OpenSSL");
- eOSSLError = rb_define_class_under(mOSSL, "OpenSSLError", rb_eStandardError);
-#endif
-
/* Document-class: OpenSSL::Digest
*
* OpenSSL::Digest allows you to compute message digests (sometimes
@@ -442,4 +470,6 @@ Init_ossl_digest(void)
rb_define_method(cDigest, "block_length", ossl_digest_block_length, 0);
rb_define_method(cDigest, "name", ossl_digest_name, 0);
+
+ id_md_holder = rb_intern_const("EVP_MD_holder");
}
diff --git a/ext/openssl/ossl_digest.h b/ext/openssl/ossl_digest.h
index 588a0c6f57..9c3bb2b149 100644
--- a/ext/openssl/ossl_digest.h
+++ b/ext/openssl/ossl_digest.h
@@ -10,7 +10,15 @@
#if !defined(_OSSL_DIGEST_H_)
#define _OSSL_DIGEST_H_
-const EVP_MD *ossl_evp_get_digestbyname(VALUE);
+/*
+ * Gets EVP_MD from a String or an OpenSSL::Digest instance (discouraged, but
+ * still supported for compatibility). A holder object is created if the EVP_MD
+ * is a "fetched" algorithm.
+ */
+const EVP_MD *ossl_evp_md_fetch(VALUE obj, volatile VALUE *holder);
+/*
+ * This is meant for OpenSSL::Engine#digest. EVP_MD must not be a fetched one.
+ */
VALUE ossl_digest_new(const EVP_MD *);
void Init_ossl_digest(void);
diff --git a/ext/openssl/ossl_engine.c b/ext/openssl/ossl_engine.c
index 1565068743..a2bcb07ea4 100644
--- a/ext/openssl/ossl_engine.c
+++ b/ext/openssl/ossl_engine.c
@@ -16,7 +16,7 @@
TypedData_Wrap_Struct((klass), &ossl_engine_type, 0)
#define SetEngine(obj, engine) do { \
if (!(engine)) { \
- ossl_raise(rb_eRuntimeError, "ENGINE wasn't initialized."); \
+ ossl_raise(rb_eRuntimeError, "ENGINE wasn't initialized."); \
} \
RTYPEDDATA_DATA(obj) = (engine); \
} while(0)
@@ -49,12 +49,12 @@ static VALUE eEngineError;
*/
#define OSSL_ENGINE_LOAD_IF_MATCH(engine_name, x) \
do{\
- if(!strcmp(#engine_name, RSTRING_PTR(name))){\
- if (OPENSSL_init_crypto(OPENSSL_INIT_ENGINE_##x, NULL))\
- return Qtrue;\
- else\
- ossl_raise(eEngineError, "OPENSSL_init_crypto"); \
- }\
+ if(!strcmp(#engine_name, RSTRING_PTR(name))){\
+ if (OPENSSL_init_crypto(OPENSSL_INIT_ENGINE_##x, NULL))\
+ return Qtrue;\
+ else\
+ ossl_raise(eEngineError, "OPENSSL_init_crypto"); \
+ }\
}while(0)
static void
@@ -66,7 +66,7 @@ ossl_engine_free(void *engine)
static const rb_data_type_t ossl_engine_type = {
"OpenSSL/Engine",
{
- 0, ossl_engine_free,
+ 0, ossl_engine_free,
},
0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
};
@@ -130,12 +130,12 @@ ossl_engine_s_engines(VALUE klass)
ary = rb_ary_new();
for(e = ENGINE_get_first(); e; e = ENGINE_get_next(e)){
- obj = NewEngine(klass);
- /* Need a ref count of two here because of ENGINE_free being
- * called internally by OpenSSL when moving to the next ENGINE
- * and by us when releasing the ENGINE reference */
- ENGINE_up_ref(e);
- SetEngine(obj, e);
+ obj = NewEngine(klass);
+ /* Need a ref count of two here because of ENGINE_free being
+ * called internally by OpenSSL when moving to the next ENGINE
+ * and by us when releasing the ENGINE reference */
+ ENGINE_up_ref(e);
+ SetEngine(obj, e);
rb_ary_push(ary, obj);
}
@@ -163,13 +163,13 @@ ossl_engine_s_by_id(VALUE klass, VALUE id)
ossl_engine_s_load(1, &id, klass);
obj = NewEngine(klass);
if(!(e = ENGINE_by_id(RSTRING_PTR(id))))
- ossl_raise(eEngineError, NULL);
+ ossl_raise(eEngineError, NULL);
SetEngine(obj, e);
if(rb_block_given_p()) rb_yield(obj);
if(!ENGINE_init(e))
- ossl_raise(eEngineError, NULL);
+ ossl_raise(eEngineError, NULL);
ENGINE_ctrl(e, ENGINE_CTRL_SET_PASSWORD_CALLBACK,
- 0, NULL, (void(*)(void))ossl_pem_passwd_cb);
+ 0, NULL, (void(*)(void))ossl_pem_passwd_cb);
ossl_clear_error();
return obj;
@@ -184,7 +184,7 @@ ossl_engine_s_by_id(VALUE klass, VALUE id)
* OpenSSL::Engine.load
* OpenSSL::Engine.engines #=> [#<OpenSSL::Engine#>, ...]
* OpenSSL::Engine.engines.first.id
- * #=> "rsax"
+ * #=> "rsax"
*/
static VALUE
ossl_engine_get_id(VALUE self)
@@ -203,7 +203,7 @@ ossl_engine_get_id(VALUE self)
* OpenSSL::Engine.load
* OpenSSL::Engine.engines #=> [#<OpenSSL::Engine#>, ...]
* OpenSSL::Engine.engines.first.name
- * #=> "RSAX engine support"
+ * #=> "RSAX engine support"
*
*/
static VALUE
@@ -274,11 +274,11 @@ ossl_engine_get_cipher(VALUE self, VALUE name)
* Will raise an EngineError if the digest is unavailable.
*
* e = OpenSSL::Engine.by_id("openssl")
- * #=> #<OpenSSL::Engine id="openssl" name="Software engine support">
+ * #=> #<OpenSSL::Engine id="openssl" name="Software engine support">
* e.digest("SHA1")
- * #=> #<OpenSSL::Digest: da39a3ee5e6b4b0d3255bfef95601890afd80709>
+ * #=> #<OpenSSL::Digest: da39a3ee5e6b4b0d3255bfef95601890afd80709>
* e.digest("zomg")
- * #=> OpenSSL::Engine::EngineError: no such digest `zomg'
+ * #=> OpenSSL::Engine::EngineError: no such digest `zomg'
*/
static VALUE
ossl_engine_get_digest(VALUE self, VALUE name)
@@ -365,7 +365,7 @@ ossl_engine_load_pubkey(int argc, VALUE *argv, VALUE self)
* your OS.
*
* [All flags] 0xFFFF
- * [No flags] 0x0000
+ * [No flags] 0x0000
*
* See also <openssl/engine.h>
*/
@@ -399,7 +399,7 @@ ossl_engine_ctrl_cmd(int argc, VALUE *argv, VALUE self)
GetEngine(self, e);
rb_scan_args(argc, argv, "11", &cmd, &val);
ret = ENGINE_ctrl_cmd_string(e, StringValueCStr(cmd),
- NIL_P(val) ? NULL : StringValueCStr(val), 0);
+ NIL_P(val) ? NULL : StringValueCStr(val), 0);
if (!ret) ossl_raise(eEngineError, NULL);
return self;
@@ -409,11 +409,11 @@ static VALUE
ossl_engine_cmd_flag_to_name(int flag)
{
switch(flag){
- case ENGINE_CMD_FLAG_NUMERIC: return rb_str_new2("NUMERIC");
- case ENGINE_CMD_FLAG_STRING: return rb_str_new2("STRING");
- case ENGINE_CMD_FLAG_NO_INPUT: return rb_str_new2("NO_INPUT");
- case ENGINE_CMD_FLAG_INTERNAL: return rb_str_new2("INTERNAL");
- default: return rb_str_new2("UNKNOWN");
+ case ENGINE_CMD_FLAG_NUMERIC: return rb_str_new2("NUMERIC");
+ case ENGINE_CMD_FLAG_STRING: return rb_str_new2("STRING");
+ case ENGINE_CMD_FLAG_NO_INPUT: return rb_str_new2("NO_INPUT");
+ case ENGINE_CMD_FLAG_INTERNAL: return rb_str_new2("INTERNAL");
+ default: return rb_str_new2("UNKNOWN");
}
}
@@ -433,13 +433,13 @@ ossl_engine_get_cmds(VALUE self)
GetEngine(self, e);
ary = rb_ary_new();
if ((defn = ENGINE_get_cmd_defns(e)) != NULL){
- for (p = defn; p->cmd_num > 0; p++){
- tmp = rb_ary_new();
- rb_ary_push(tmp, rb_str_new2(p->cmd_name));
- rb_ary_push(tmp, rb_str_new2(p->cmd_desc));
- rb_ary_push(tmp, ossl_engine_cmd_flag_to_name(p->cmd_flags));
- rb_ary_push(ary, tmp);
- }
+ for (p = defn; p->cmd_num > 0; p++){
+ tmp = rb_ary_new();
+ rb_ary_push(tmp, rb_str_new2(p->cmd_name));
+ rb_ary_push(tmp, rb_str_new2(p->cmd_desc));
+ rb_ary_push(tmp, ossl_engine_cmd_flag_to_name(p->cmd_flags));
+ rb_ary_push(ary, tmp);
+ }
}
return ary;
@@ -458,7 +458,7 @@ ossl_engine_inspect(VALUE self)
GetEngine(self, e);
return rb_sprintf("#<%"PRIsVALUE" id=\"%s\" name=\"%s\">",
- rb_obj_class(self), ENGINE_get_id(e), ENGINE_get_name(e));
+ rb_obj_class(self), ENGINE_get_id(e), ENGINE_get_name(e));
}
#define DefEngineConst(x) rb_define_const(cEngine, #x, INT2NUM(ENGINE_##x))
@@ -466,11 +466,6 @@ ossl_engine_inspect(VALUE self)
void
Init_ossl_engine(void)
{
-#if 0
- mOSSL = rb_define_module("OpenSSL");
- eOSSLError = rb_define_class_under(mOSSL, "OpenSSLError", rb_eStandardError);
-#endif
-
cEngine = rb_define_class_under(mOSSL, "Engine", rb_cObject);
eEngineError = rb_define_class_under(cEngine, "EngineError", eOSSLError);
diff --git a/ext/openssl/ossl_hmac.c b/ext/openssl/ossl_hmac.c
index b304827579..ddcc6a5f8d 100644
--- a/ext/openssl/ossl_hmac.c
+++ b/ext/openssl/ossl_hmac.c
@@ -14,7 +14,7 @@
#define GetHMAC(obj, ctx) do { \
TypedData_Get_Struct((obj), EVP_MD_CTX, &ossl_hmac_type, (ctx)); \
if (!(ctx)) { \
- ossl_raise(rb_eRuntimeError, "HMAC wasn't initialized"); \
+ ossl_raise(rb_eRuntimeError, "HMAC wasn't initialized"); \
} \
} while (0)
@@ -23,6 +23,7 @@
*/
static VALUE cHMAC;
static VALUE eHMACError;
+static ID id_md_holder;
/*
* Public
@@ -40,7 +41,7 @@ ossl_hmac_free(void *ctx)
static const rb_data_type_t ossl_hmac_type = {
"OpenSSL/HMAC",
{
- 0, ossl_hmac_free,
+ 0, ossl_hmac_free,
},
0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
};
@@ -73,17 +74,17 @@ ossl_hmac_alloc(VALUE klass)
*
* === Example
*
- * key = 'key'
- * instance = OpenSSL::HMAC.new(key, 'SHA1')
- * #=> f42bb0eeb018ebbd4597ae7213711ec60760843f
- * instance.class
- * #=> OpenSSL::HMAC
+ * key = 'key'
+ * instance = OpenSSL::HMAC.new(key, 'SHA1')
+ * #=> f42bb0eeb018ebbd4597ae7213711ec60760843f
+ * instance.class
+ * #=> OpenSSL::HMAC
*
* === A note about comparisons
*
* Two instances can be securely compared with #== in constant time:
*
- * other_instance = OpenSSL::HMAC.new('key', 'SHA1')
+ * other_instance = OpenSSL::HMAC.new('key', 'SHA1')
* #=> f42bb0eeb018ebbd4597ae7213711ec60760843f
* instance == other_instance
* #=> true
@@ -94,19 +95,22 @@ ossl_hmac_initialize(VALUE self, VALUE key, VALUE digest)
{
EVP_MD_CTX *ctx;
EVP_PKEY *pkey;
+ const EVP_MD *md;
+ VALUE md_holder;
GetHMAC(self, ctx);
StringValue(key);
+ md = ossl_evp_md_fetch(digest, &md_holder);
pkey = EVP_PKEY_new_raw_private_key(EVP_PKEY_HMAC, NULL,
(unsigned char *)RSTRING_PTR(key),
RSTRING_LENINT(key));
if (!pkey)
ossl_raise(eHMACError, "EVP_PKEY_new_raw_private_key");
- if (EVP_DigestSignInit(ctx, NULL, ossl_evp_get_digestbyname(digest),
- NULL, pkey) != 1) {
+ if (EVP_DigestSignInit(ctx, NULL, md, NULL, pkey) != 1) {
EVP_PKEY_free(pkey);
ossl_raise(eHMACError, "EVP_DigestSignInit");
}
+ rb_ivar_set(self, id_md_holder, md_holder);
/* Decrement reference counter; EVP_MD_CTX still keeps it */
EVP_PKEY_free(pkey);
@@ -138,13 +142,13 @@ ossl_hmac_copy(VALUE self, VALUE other)
*
* === Example
*
- * first_chunk = 'The quick brown fox jumps '
- * second_chunk = 'over the lazy dog'
+ * first_chunk = 'The quick brown fox jumps '
+ * second_chunk = 'over the lazy dog'
*
- * instance.update(first_chunk)
- * #=> 5b9a8038a65d571076d97fe783989e52278a492a
- * instance.update(second_chunk)
- * #=> de7c9b85b8b78aa6bc8a7a36f70a90701c9db4d9
+ * instance.update(first_chunk)
+ * #=> 5b9a8038a65d571076d97fe783989e52278a492a
+ * instance.update(second_chunk)
+ * #=> de7c9b85b8b78aa6bc8a7a36f70a90701c9db4d9
*
*/
static VALUE
@@ -222,14 +226,14 @@ ossl_hmac_hexdigest(VALUE self)
*
* === Example
*
- * data = "The quick brown fox jumps over the lazy dog"
- * instance = OpenSSL::HMAC.new('key', 'SHA1')
- * #=> f42bb0eeb018ebbd4597ae7213711ec60760843f
+ * data = "The quick brown fox jumps over the lazy dog"
+ * instance = OpenSSL::HMAC.new('key', 'SHA1')
+ * #=> f42bb0eeb018ebbd4597ae7213711ec60760843f
*
- * instance.update(data)
- * #=> de7c9b85b8b78aa6bc8a7a36f70a90701c9db4d9
- * instance.reset
- * #=> f42bb0eeb018ebbd4597ae7213711ec60760843f
+ * instance.update(data)
+ * #=> de7c9b85b8b78aa6bc8a7a36f70a90701c9db4d9
+ * instance.reset
+ * #=> f42bb0eeb018ebbd4597ae7213711ec60760843f
*
*/
static VALUE
@@ -252,11 +256,6 @@ ossl_hmac_reset(VALUE self)
void
Init_ossl_hmac(void)
{
-#if 0
- mOSSL = rb_define_module("OpenSSL");
- eOSSLError = rb_define_class_under(mOSSL, "OpenSSLError", rb_eStandardError);
-#endif
-
/*
* Document-class: OpenSSL::HMAC
*
@@ -300,4 +299,6 @@ Init_ossl_hmac(void)
rb_define_method(cHMAC, "hexdigest", ossl_hmac_hexdigest, 0);
rb_define_alias(cHMAC, "inspect", "hexdigest");
rb_define_alias(cHMAC, "to_s", "hexdigest");
+
+ id_md_holder = rb_intern_const("EVP_MD_holder");
}
diff --git a/ext/openssl/ossl_kdf.c b/ext/openssl/ossl_kdf.c
index f349939a80..99a3589b39 100644
--- a/ext/openssl/ossl_kdf.c
+++ b/ext/openssl/ossl_kdf.c
@@ -7,6 +7,27 @@
static VALUE mKDF, eKDF;
+struct pbkdf2_hmac_args {
+ char *pass;
+ int passlen;
+ unsigned char *salt;
+ int saltlen;
+ int iters;
+ const EVP_MD *md;
+ int len;
+ unsigned char *out;
+};
+
+static void *
+pbkdf2_hmac_nogvl(void *args_)
+{
+ struct pbkdf2_hmac_args *args = (struct pbkdf2_hmac_args *)args_;
+ int ret = PKCS5_PBKDF2_HMAC(args->pass, args->passlen, args->salt,
+ args->saltlen, args->iters, args->md,
+ args->len, args->out);
+ return (void *)(uintptr_t)ret;
+}
+
/*
* call-seq:
* KDF.pbkdf2_hmac(pass, salt:, iterations:, length:, hash:) -> aString
@@ -18,6 +39,10 @@ static VALUE mKDF, eKDF;
* For more information about PBKDF2, see RFC 2898 Section 5.2
* (https://www.rfc-editor.org/rfc/rfc2898#section-5.2).
*
+ * *NOTE*: This method cannot be interrupted by Timeout.timeout from the
+ * "timeout" library. Do not take parameters from untrusted sources without
+ * enforcing reasonable limits.
+ *
* === Parameters
* pass :: The password.
* salt :: The salt. Salts prevent attacks based on dictionaries of common
@@ -35,16 +60,16 @@ static VALUE mKDF, eKDF;
static VALUE
kdf_pbkdf2_hmac(int argc, VALUE *argv, VALUE self)
{
- VALUE pass, salt, opts, kwargs[4], str;
+ VALUE pass, salt, opts, kwargs[4], str, md_holder, pass_tmp, salt_tmp;
static ID kwargs_ids[4];
- int iters, len;
+ int passlen, saltlen, iters, len;
const EVP_MD *md;
if (!kwargs_ids[0]) {
- kwargs_ids[0] = rb_intern_const("salt");
- kwargs_ids[1] = rb_intern_const("iterations");
- kwargs_ids[2] = rb_intern_const("length");
- kwargs_ids[3] = rb_intern_const("hash");
+ kwargs_ids[0] = rb_intern_const("salt");
+ kwargs_ids[1] = rb_intern_const("iterations");
+ kwargs_ids[2] = rb_intern_const("length");
+ kwargs_ids[3] = rb_intern_const("hash");
}
rb_scan_args(argc, argv, "1:", &pass, &opts);
rb_get_kwargs(opts, kwargs_ids, 4, 0, kwargs);
@@ -53,19 +78,57 @@ kdf_pbkdf2_hmac(int argc, VALUE *argv, VALUE self)
salt = StringValue(kwargs[0]);
iters = NUM2INT(kwargs[1]);
len = NUM2INT(kwargs[2]);
- md = ossl_evp_get_digestbyname(kwargs[3]);
-
- str = rb_str_new(0, len);
- if (!PKCS5_PBKDF2_HMAC(RSTRING_PTR(pass), RSTRING_LENINT(pass),
- (unsigned char *)RSTRING_PTR(salt),
- RSTRING_LENINT(salt), iters, md, len,
- (unsigned char *)RSTRING_PTR(str)))
- ossl_raise(eKDF, "PKCS5_PBKDF2_HMAC");
-
+ md = ossl_evp_md_fetch(kwargs[3], &md_holder);
+ passlen = RSTRING_LENINT(pass);
+ saltlen = RSTRING_LENINT(salt);
+ str = rb_str_new(NULL, len);
+ struct pbkdf2_hmac_args args = {
+ .pass = ALLOCV(pass_tmp, passlen),
+ .passlen = passlen,
+ .salt = ALLOCV(salt_tmp, saltlen),
+ .saltlen = saltlen,
+ .iters = iters,
+ .md = md,
+ .len = len,
+ .out = (unsigned char *)RSTRING_PTR(str),
+ };
+ memcpy(args.pass, RSTRING_PTR(pass), passlen);
+ memcpy(args.salt, RSTRING_PTR(salt), saltlen);
+ if (!rb_thread_call_without_gvl(pbkdf2_hmac_nogvl, &args, NULL, NULL))
+ ossl_raise(eKDF, "PKCS5_PBKDF2_HMAC");
+ OPENSSL_cleanse(args.pass, passlen);
+ ALLOCV_END(pass_tmp);
+ ALLOCV_END(salt_tmp);
return str;
}
#if defined(HAVE_EVP_PBE_SCRYPT)
+struct scrypt_args {
+ char *pass;
+ size_t passlen;
+ unsigned char *salt;
+ size_t saltlen;
+ uint64_t N, r, p;
+ size_t len;
+ unsigned char *out;
+};
+
+static void *
+scrypt_nogvl(void *args_)
+{
+ struct scrypt_args *args = (struct scrypt_args *)args_;
+ /*
+ * OpenSSL uses 32MB by default (if zero is specified), which is too
+ * small. Let's not limit memory consumption but just let malloc() fail
+ * inside OpenSSL. The amount is controllable by other parameters.
+ */
+ uint64_t maxmem = UINT64_MAX;
+ int ret = EVP_PBE_scrypt(args->pass, args->passlen,
+ args->salt, args->saltlen, args->N, args->r,
+ args->p, maxmem, args->out, args->len);
+ return (void *)(uintptr_t)ret;
+}
+
/*
* call-seq:
* KDF.scrypt(pass, salt:, N:, r:, p:, length:) -> aString
@@ -84,6 +147,10 @@ kdf_pbkdf2_hmac(int argc, VALUE *argv, VALUE self)
*
* See RFC 7914 (https://www.rfc-editor.org/rfc/rfc7914) for more information.
*
+ * *NOTE*: This method cannot be interrupted by Timeout.timeout from the
+ * "timeout" library. Do not take parameters from untrusted sources without
+ * enforcing reasonable limits.
+ *
* === Parameters
* pass :: Passphrase.
* salt :: Salt.
@@ -101,17 +168,18 @@ kdf_pbkdf2_hmac(int argc, VALUE *argv, VALUE self)
static VALUE
kdf_scrypt(int argc, VALUE *argv, VALUE self)
{
- VALUE pass, salt, opts, kwargs[5], str;
+ VALUE pass, salt, opts, kwargs[5], str, pass_tmp, salt_tmp;
static ID kwargs_ids[5];
- size_t len;
- uint64_t N, r, p, maxmem;
+ size_t passlen, saltlen;
+ long len;
+ uint64_t N, r, p;
if (!kwargs_ids[0]) {
- kwargs_ids[0] = rb_intern_const("salt");
- kwargs_ids[1] = rb_intern_const("N");
- kwargs_ids[2] = rb_intern_const("r");
- kwargs_ids[3] = rb_intern_const("p");
- kwargs_ids[4] = rb_intern_const("length");
+ kwargs_ids[0] = rb_intern_const("salt");
+ kwargs_ids[1] = rb_intern_const("N");
+ kwargs_ids[2] = rb_intern_const("r");
+ kwargs_ids[3] = rb_intern_const("p");
+ kwargs_ids[4] = rb_intern_const("length");
}
rb_scan_args(argc, argv, "1:", &pass, &opts);
rb_get_kwargs(opts, kwargs_ids, 5, 0, kwargs);
@@ -122,19 +190,27 @@ kdf_scrypt(int argc, VALUE *argv, VALUE self)
r = NUM2UINT64T(kwargs[2]);
p = NUM2UINT64T(kwargs[3]);
len = NUM2LONG(kwargs[4]);
- /*
- * OpenSSL uses 32MB by default (if zero is specified), which is too small.
- * Let's not limit memory consumption but just let malloc() fail inside
- * OpenSSL. The amount is controllable by other parameters.
- */
- maxmem = SIZE_MAX;
-
- str = rb_str_new(0, len);
- if (!EVP_PBE_scrypt(RSTRING_PTR(pass), RSTRING_LEN(pass),
- (unsigned char *)RSTRING_PTR(salt), RSTRING_LEN(salt),
- N, r, p, maxmem, (unsigned char *)RSTRING_PTR(str), len))
- ossl_raise(eKDF, "EVP_PBE_scrypt");
-
+ passlen = RSTRING_LEN(pass);
+ saltlen = RSTRING_LEN(salt);
+ str = rb_str_new(NULL, len);
+ struct scrypt_args args = {
+ .pass = ALLOCV(pass_tmp, passlen),
+ .passlen = passlen,
+ .salt = ALLOCV(salt_tmp, saltlen),
+ .saltlen = saltlen,
+ .N = N,
+ .r = r,
+ .p = p,
+ .len = len,
+ .out = (unsigned char *)RSTRING_PTR(str),
+ };
+ memcpy(args.pass, RSTRING_PTR(pass), passlen);
+ memcpy(args.salt, RSTRING_PTR(salt), saltlen);
+ if (!rb_thread_call_without_gvl(scrypt_nogvl, &args, NULL, NULL))
+ ossl_raise(eKDF, "EVP_PBE_scrypt");
+ OPENSSL_cleanse(args.pass, passlen);
+ ALLOCV_END(pass_tmp);
+ ALLOCV_END(salt_tmp);
return str;
}
#endif
@@ -172,7 +248,7 @@ kdf_scrypt(int argc, VALUE *argv, VALUE self)
static VALUE
kdf_hkdf(int argc, VALUE *argv, VALUE self)
{
- VALUE ikm, salt, info, opts, kwargs[4], str;
+ VALUE ikm, salt, info, opts, kwargs[4], str, md_holder;
static ID kwargs_ids[4];
int saltlen, ikmlen, infolen;
size_t len;
@@ -180,10 +256,10 @@ kdf_hkdf(int argc, VALUE *argv, VALUE self)
EVP_PKEY_CTX *pctx;
if (!kwargs_ids[0]) {
- kwargs_ids[0] = rb_intern_const("salt");
- kwargs_ids[1] = rb_intern_const("info");
- kwargs_ids[2] = rb_intern_const("length");
- kwargs_ids[3] = rb_intern_const("hash");
+ kwargs_ids[0] = rb_intern_const("salt");
+ kwargs_ids[1] = rb_intern_const("info");
+ kwargs_ids[2] = rb_intern_const("length");
+ kwargs_ids[3] = rb_intern_const("hash");
}
rb_scan_args(argc, argv, "1:", &ikm, &opts);
rb_get_kwargs(opts, kwargs_ids, 4, 0, kwargs);
@@ -196,39 +272,39 @@ kdf_hkdf(int argc, VALUE *argv, VALUE self)
infolen = RSTRING_LENINT(info);
len = (size_t)NUM2LONG(kwargs[2]);
if (len > LONG_MAX)
- rb_raise(rb_eArgError, "length must be non-negative");
- md = ossl_evp_get_digestbyname(kwargs[3]);
+ rb_raise(rb_eArgError, "length must be non-negative");
+ md = ossl_evp_md_fetch(kwargs[3], &md_holder);
str = rb_str_new(NULL, (long)len);
pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_HKDF, NULL);
if (!pctx)
- ossl_raise(eKDF, "EVP_PKEY_CTX_new_id");
+ ossl_raise(eKDF, "EVP_PKEY_CTX_new_id");
if (EVP_PKEY_derive_init(pctx) <= 0) {
- EVP_PKEY_CTX_free(pctx);
- ossl_raise(eKDF, "EVP_PKEY_derive_init");
+ EVP_PKEY_CTX_free(pctx);
+ ossl_raise(eKDF, "EVP_PKEY_derive_init");
}
if (EVP_PKEY_CTX_set_hkdf_md(pctx, md) <= 0) {
- EVP_PKEY_CTX_free(pctx);
- ossl_raise(eKDF, "EVP_PKEY_CTX_set_hkdf_md");
+ EVP_PKEY_CTX_free(pctx);
+ ossl_raise(eKDF, "EVP_PKEY_CTX_set_hkdf_md");
}
if (EVP_PKEY_CTX_set1_hkdf_salt(pctx, (unsigned char *)RSTRING_PTR(salt),
- saltlen) <= 0) {
- EVP_PKEY_CTX_free(pctx);
- ossl_raise(eKDF, "EVP_PKEY_CTX_set_hkdf_salt");
+ saltlen) <= 0) {
+ EVP_PKEY_CTX_free(pctx);
+ ossl_raise(eKDF, "EVP_PKEY_CTX_set_hkdf_salt");
}
if (EVP_PKEY_CTX_set1_hkdf_key(pctx, (unsigned char *)RSTRING_PTR(ikm),
- ikmlen) <= 0) {
- EVP_PKEY_CTX_free(pctx);
- ossl_raise(eKDF, "EVP_PKEY_CTX_set_hkdf_key");
+ ikmlen) <= 0) {
+ EVP_PKEY_CTX_free(pctx);
+ ossl_raise(eKDF, "EVP_PKEY_CTX_set_hkdf_key");
}
if (EVP_PKEY_CTX_add1_hkdf_info(pctx, (unsigned char *)RSTRING_PTR(info),
- infolen) <= 0) {
- EVP_PKEY_CTX_free(pctx);
- ossl_raise(eKDF, "EVP_PKEY_CTX_set_hkdf_info");
+ infolen) <= 0) {
+ EVP_PKEY_CTX_free(pctx);
+ ossl_raise(eKDF, "EVP_PKEY_CTX_set_hkdf_info");
}
if (EVP_PKEY_derive(pctx, (unsigned char *)RSTRING_PTR(str), &len) <= 0) {
- EVP_PKEY_CTX_free(pctx);
- ossl_raise(eKDF, "EVP_PKEY_derive");
+ EVP_PKEY_CTX_free(pctx);
+ ossl_raise(eKDF, "EVP_PKEY_derive");
}
rb_str_set_len(str, (long)len);
EVP_PKEY_CTX_free(pctx);
@@ -239,11 +315,6 @@ kdf_hkdf(int argc, VALUE *argv, VALUE self)
void
Init_ossl_kdf(void)
{
-#if 0
- mOSSL = rb_define_module("OpenSSL");
- eOSSLError = rb_define_class_under(mOSSL, "OpenSSLError", rb_eStandardError);
-#endif
-
/*
* Document-module: OpenSSL::KDF
*
diff --git a/ext/openssl/ossl_ns_spki.c b/ext/openssl/ossl_ns_spki.c
index ffed3a64a6..8440c2ee82 100644
--- a/ext/openssl/ossl_ns_spki.c
+++ b/ext/openssl/ossl_ns_spki.c
@@ -13,14 +13,14 @@
TypedData_Wrap_Struct((klass), &ossl_netscape_spki_type, 0)
#define SetSPKI(obj, spki) do { \
if (!(spki)) { \
- ossl_raise(rb_eRuntimeError, "SPKI wasn't initialized!"); \
+ ossl_raise(rb_eRuntimeError, "SPKI wasn't initialized!"); \
} \
RTYPEDDATA_DATA(obj) = (spki); \
} while (0)
#define GetSPKI(obj, spki) do { \
TypedData_Get_Struct((obj), NETSCAPE_SPKI, &ossl_netscape_spki_type, (spki)); \
if (!(spki)) { \
- ossl_raise(rb_eRuntimeError, "SPKI wasn't initialized!"); \
+ ossl_raise(rb_eRuntimeError, "SPKI wasn't initialized!"); \
} \
} while (0)
@@ -48,7 +48,7 @@ ossl_netscape_spki_free(void *spki)
static const rb_data_type_t ossl_netscape_spki_type = {
"OpenSSL/NETSCAPE_SPKI",
{
- 0, ossl_netscape_spki_free,
+ 0, ossl_netscape_spki_free,
},
0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
};
@@ -61,7 +61,7 @@ ossl_spki_alloc(VALUE klass)
obj = NewSPKI(klass);
if (!(spki = NETSCAPE_SPKI_new())) {
- ossl_raise(eSPKIError, NULL);
+ ossl_raise(eSPKIError, NULL);
}
SetSPKI(obj, spki);
@@ -83,15 +83,15 @@ ossl_spki_initialize(int argc, VALUE *argv, VALUE self)
const unsigned char *p;
if (rb_scan_args(argc, argv, "01", &buffer) == 0) {
- return self;
+ return self;
}
StringValue(buffer);
if (!(spki = NETSCAPE_SPKI_b64_decode(RSTRING_PTR(buffer), RSTRING_LENINT(buffer)))) {
- ossl_clear_error();
- p = (unsigned char *)RSTRING_PTR(buffer);
- if (!(spki = d2i_NETSCAPE_SPKI(NULL, &p, RSTRING_LEN(buffer)))) {
- ossl_raise(eSPKIError, NULL);
- }
+ ossl_clear_error();
+ p = (unsigned char *)RSTRING_PTR(buffer);
+ if (!(spki = d2i_NETSCAPE_SPKI(NULL, &p, RSTRING_LEN(buffer)))) {
+ ossl_raise(eSPKIError, NULL);
+ }
}
NETSCAPE_SPKI_free(DATA_PTR(self));
SetSPKI(self, spki);
@@ -140,7 +140,7 @@ ossl_spki_to_pem(VALUE self)
GetSPKI(self, spki);
if (!(data = NETSCAPE_SPKI_b64_encode(spki))) {
- ossl_raise(eSPKIError, NULL);
+ ossl_raise(eSPKIError, NULL);
}
str = ossl_buf2str(data, rb_long2int(strlen(data)));
@@ -162,11 +162,11 @@ ossl_spki_print(VALUE self)
GetSPKI(self, spki);
if (!(out = BIO_new(BIO_s_mem()))) {
- ossl_raise(eSPKIError, NULL);
+ ossl_raise(eSPKIError, NULL);
}
if (!NETSCAPE_SPKI_print(out, spki)) {
- BIO_free(out);
- ossl_raise(eSPKIError, NULL);
+ BIO_free(out);
+ ossl_raise(eSPKIError, NULL);
}
return ossl_membio2str(out);
@@ -187,7 +187,7 @@ ossl_spki_get_public_key(VALUE self)
GetSPKI(self, spki);
if (!(pkey = NETSCAPE_SPKI_get_pubkey(spki))) { /* adds an reference */
- ossl_raise(eSPKIError, NULL);
+ ossl_raise(eSPKIError, NULL);
}
return ossl_pkey_wrap(pkey);
@@ -214,7 +214,7 @@ ossl_spki_set_public_key(VALUE self, VALUE key)
pkey = GetPKeyPtr(key);
ossl_pkey_check_public_key(pkey);
if (!NETSCAPE_SPKI_set_pubkey(spki, pkey))
- ossl_raise(eSPKIError, "NETSCAPE_SPKI_set_pubkey");
+ ossl_raise(eSPKIError, "NETSCAPE_SPKI_set_pubkey");
return key;
}
@@ -230,13 +230,12 @@ ossl_spki_get_challenge(VALUE self)
NETSCAPE_SPKI *spki;
GetSPKI(self, spki);
- if (spki->spkac->challenge->length <= 0) {
- OSSL_Debug("Challenge.length <= 0?");
- return rb_str_new(0, 0);
+ if (ASN1_STRING_length(spki->spkac->challenge) <= 0) {
+ OSSL_Debug("Challenge.length <= 0?");
+ return rb_str_new(0, 0);
}
- return rb_str_new((const char *)spki->spkac->challenge->data,
- spki->spkac->challenge->length);
+ return asn1str_to_str(spki->spkac->challenge);
}
/*
@@ -257,8 +256,8 @@ ossl_spki_set_challenge(VALUE self, VALUE str)
StringValue(str);
GetSPKI(self, spki);
if (!ASN1_STRING_set(spki->spkac->challenge, RSTRING_PTR(str),
- RSTRING_LENINT(str))) {
- ossl_raise(eSPKIError, NULL);
+ RSTRING_LENINT(str))) {
+ ossl_raise(eSPKIError, NULL);
}
return str;
@@ -283,13 +282,13 @@ ossl_spki_sign(VALUE self, VALUE key, VALUE digest)
NETSCAPE_SPKI *spki;
EVP_PKEY *pkey;
const EVP_MD *md;
+ VALUE md_holder;
pkey = GetPrivPKeyPtr(key); /* NO NEED TO DUP */
- md = ossl_evp_get_digestbyname(digest);
+ md = ossl_evp_md_fetch(digest, &md_holder);
GetSPKI(self, spki);
- if (!NETSCAPE_SPKI_sign(spki, pkey, md)) {
- ossl_raise(eSPKIError, NULL);
- }
+ if (!NETSCAPE_SPKI_sign(spki, pkey, md))
+ ossl_raise(eSPKIError, "NETSCAPE_SPKI_sign");
return self;
}
@@ -315,12 +314,12 @@ ossl_spki_verify(VALUE self, VALUE key)
ossl_pkey_check_public_key(pkey);
switch (NETSCAPE_SPKI_verify(spki, pkey)) {
case 0:
- ossl_clear_error();
- return Qfalse;
+ ossl_clear_error();
+ return Qfalse;
case 1:
- return Qtrue;
+ return Qtrue;
default:
- ossl_raise(eSPKIError, "NETSCAPE_SPKI_verify");
+ ossl_raise(eSPKIError, "NETSCAPE_SPKI_verify");
}
}
@@ -378,11 +377,6 @@ ossl_spki_verify(VALUE self, VALUE key)
void
Init_ossl_ns_spki(void)
{
-#if 0
- mOSSL = rb_define_module("OpenSSL");
- eOSSLError = rb_define_class_under(mOSSL, "OpenSSLError", rb_eStandardError);
-#endif
-
mNetscape = rb_define_module_under(mOSSL, "Netscape");
eSPKIError = rb_define_class_under(mNetscape, "SPKIError", eOSSLError);
diff --git a/ext/openssl/ossl_ocsp.c b/ext/openssl/ossl_ocsp.c
index 5a3a71cae0..9dd4b466d2 100644
--- a/ext/openssl/ossl_ocsp.c
+++ b/ext/openssl/ossl_ocsp.c
@@ -84,7 +84,7 @@ ossl_ocsp_request_free(void *ptr)
static const rb_data_type_t ossl_ocsp_request_type = {
"OpenSSL/OCSP/REQUEST",
{
- 0, ossl_ocsp_request_free,
+ 0, ossl_ocsp_request_free,
},
0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
};
@@ -98,7 +98,7 @@ ossl_ocsp_response_free(void *ptr)
static const rb_data_type_t ossl_ocsp_response_type = {
"OpenSSL/OCSP/RESPONSE",
{
- 0, ossl_ocsp_response_free,
+ 0, ossl_ocsp_response_free,
},
0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
};
@@ -112,7 +112,7 @@ ossl_ocsp_basicresp_free(void *ptr)
static const rb_data_type_t ossl_ocsp_basicresp_type = {
"OpenSSL/OCSP/BASICRESP",
{
- 0, ossl_ocsp_basicresp_free,
+ 0, ossl_ocsp_basicresp_free,
},
0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
};
@@ -126,7 +126,7 @@ ossl_ocsp_singleresp_free(void *ptr)
static const rb_data_type_t ossl_ocsp_singleresp_type = {
"OpenSSL/OCSP/SINGLERESP",
{
- 0, ossl_ocsp_singleresp_free,
+ 0, ossl_ocsp_singleresp_free,
},
0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
};
@@ -140,7 +140,7 @@ ossl_ocsp_certid_free(void *ptr)
static const rb_data_type_t ossl_ocsp_certid_type = {
"OpenSSL/OCSP/CERTID",
{
- 0, ossl_ocsp_certid_free,
+ 0, ossl_ocsp_certid_free,
},
0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
};
@@ -171,7 +171,7 @@ ossl_ocspreq_alloc(VALUE klass)
obj = NewOCSPReq(klass);
if (!(req = OCSP_REQUEST_new()))
- ossl_raise(eOCSPError, NULL);
+ ossl_raise(eOCSPError, NULL);
SetOCSPReq(obj, req);
return obj;
@@ -189,7 +189,7 @@ ossl_ocspreq_initialize_copy(VALUE self, VALUE other)
req_new = ASN1_item_dup(ASN1_ITEM_rptr(OCSP_REQUEST), req);
if (!req_new)
- ossl_raise(eOCSPError, "ASN1_item_dup");
+ ossl_raise(eOCSPError, "ASN1_item_dup");
SetOCSPReq(self, req_new);
OCSP_REQUEST_free(req_old);
@@ -215,15 +215,15 @@ ossl_ocspreq_initialize(int argc, VALUE *argv, VALUE self)
rb_scan_args(argc, argv, "01", &arg);
if(!NIL_P(arg)){
- GetOCSPReq(self, req);
- arg = ossl_to_der_if_possible(arg);
- StringValue(arg);
- p = (unsigned char *)RSTRING_PTR(arg);
- req_new = d2i_OCSP_REQUEST(NULL, &p, RSTRING_LEN(arg));
- if (!req_new)
- ossl_raise(eOCSPError, "d2i_OCSP_REQUEST");
- SetOCSPReq(self, req_new);
- OCSP_REQUEST_free(req);
+ GetOCSPReq(self, req);
+ arg = ossl_to_der_if_possible(arg);
+ StringValue(arg);
+ p = (unsigned char *)RSTRING_PTR(arg);
+ req_new = d2i_OCSP_REQUEST(NULL, &p, RSTRING_LEN(arg));
+ if (!req_new)
+ ossl_raise(eOCSPError, "d2i_OCSP_REQUEST");
+ SetOCSPReq(self, req_new);
+ OCSP_REQUEST_free(req);
}
return self;
@@ -249,13 +249,13 @@ ossl_ocspreq_add_nonce(int argc, VALUE *argv, VALUE self)
rb_scan_args(argc, argv, "01", &val);
if(NIL_P(val)) {
- GetOCSPReq(self, req);
- ret = OCSP_request_add1_nonce(req, NULL, -1);
+ GetOCSPReq(self, req);
+ ret = OCSP_request_add1_nonce(req, NULL, -1);
}
else{
- StringValue(val);
- GetOCSPReq(self, req);
- ret = OCSP_request_add1_nonce(req, (unsigned char *)RSTRING_PTR(val), RSTRING_LENINT(val));
+ StringValue(val);
+ GetOCSPReq(self, req);
+ ret = OCSP_request_add1_nonce(req, (unsigned char *)RSTRING_PTR(val), RSTRING_LENINT(val));
}
if(!ret) ossl_raise(eOCSPError, NULL);
@@ -312,10 +312,10 @@ ossl_ocspreq_add_certid(VALUE self, VALUE certid)
GetOCSPCertId(certid, id);
if (!(id_new = OCSP_CERTID_dup(id)))
- ossl_raise(eOCSPError, "OCSP_CERTID_dup");
+ ossl_raise(eOCSPError, "OCSP_CERTID_dup");
if (!OCSP_request_add0_id(req, id_new)) {
- OCSP_CERTID_free(id_new);
- ossl_raise(eOCSPError, "OCSP_request_add0_id");
+ OCSP_CERTID_free(id_new);
+ ossl_raise(eOCSPError, "OCSP_request_add0_id");
}
return self;
@@ -369,7 +369,7 @@ ossl_ocspreq_get_certid(VALUE self)
static VALUE
ossl_ocspreq_sign(int argc, VALUE *argv, VALUE self)
{
- VALUE signer_cert, signer_key, certs, flags, digest;
+ VALUE signer_cert, signer_key, certs, flags, digest, md_holder;
OCSP_REQUEST *req;
X509 *signer;
EVP_PKEY *key;
@@ -383,19 +383,17 @@ ossl_ocspreq_sign(int argc, VALUE *argv, VALUE self)
signer = GetX509CertPtr(signer_cert);
key = GetPrivPKeyPtr(signer_key);
if (!NIL_P(flags))
- flg = NUM2INT(flags);
- if (NIL_P(digest))
- md = NULL;
- else
- md = ossl_evp_get_digestbyname(digest);
+ flg = NUM2INT(flags);
+ md = NIL_P(digest) ? NULL : ossl_evp_md_fetch(digest, &md_holder);
if (NIL_P(certs))
- flg |= OCSP_NOCERTS;
+ flg |= OCSP_NOCERTS;
else
- x509s = ossl_x509_ary2sk(certs);
+ x509s = ossl_x509_ary2sk(certs);
ret = OCSP_request_sign(req, signer, key, md, x509s, flg);
sk_X509_pop_free(x509s, X509_free);
- if (!ret) ossl_raise(eOCSPError, NULL);
+ if (!ret)
+ ossl_raise(eOCSPError, "OCSP_request_sign");
return self;
}
@@ -429,7 +427,7 @@ ossl_ocspreq_verify(int argc, VALUE *argv, VALUE self)
result = OCSP_request_verify(req, x509s, x509st, flg);
sk_X509_pop_free(x509s, X509_free);
if (result <= 0)
- ossl_clear_error();
+ ossl_clear_error();
return result > 0 ? Qtrue : Qfalse;
}
@@ -448,11 +446,11 @@ ossl_ocspreq_to_der(VALUE self)
GetOCSPReq(self, req);
if((len = i2d_OCSP_REQUEST(req, NULL)) <= 0)
- ossl_raise(eOCSPError, NULL);
+ ossl_raise(eOCSPError, NULL);
str = rb_str_new(0, len);
p = (unsigned char *)RSTRING_PTR(str);
if(i2d_OCSP_REQUEST(req, &p) <= 0)
- ossl_raise(eOCSPError, NULL);
+ ossl_raise(eOCSPError, NULL);
ossl_str_adjust(str, p);
return str;
@@ -496,7 +494,7 @@ ossl_ocspres_s_create(VALUE klass, VALUE status, VALUE basic_resp)
else GetOCSPBasicRes(basic_resp, bs); /* NO NEED TO DUP */
obj = NewOCSPRes(klass);
if(!(res = OCSP_response_create(st, bs)))
- ossl_raise(eOCSPError, NULL);
+ ossl_raise(eOCSPError, NULL);
SetOCSPRes(obj, res);
return obj;
@@ -510,7 +508,7 @@ ossl_ocspres_alloc(VALUE klass)
obj = NewOCSPRes(klass);
if(!(res = OCSP_RESPONSE_new()))
- ossl_raise(eOCSPError, NULL);
+ ossl_raise(eOCSPError, NULL);
SetOCSPRes(obj, res);
return obj;
@@ -528,7 +526,7 @@ ossl_ocspres_initialize_copy(VALUE self, VALUE other)
res_new = ASN1_item_dup(ASN1_ITEM_rptr(OCSP_RESPONSE), res);
if (!res_new)
- ossl_raise(eOCSPError, "ASN1_item_dup");
+ ossl_raise(eOCSPError, "ASN1_item_dup");
SetOCSPRes(self, res_new);
OCSP_RESPONSE_free(res_old);
@@ -554,15 +552,15 @@ ossl_ocspres_initialize(int argc, VALUE *argv, VALUE self)
rb_scan_args(argc, argv, "01", &arg);
if(!NIL_P(arg)){
- GetOCSPRes(self, res);
- arg = ossl_to_der_if_possible(arg);
- StringValue(arg);
- p = (unsigned char *)RSTRING_PTR(arg);
- res_new = d2i_OCSP_RESPONSE(NULL, &p, RSTRING_LEN(arg));
- if (!res_new)
- ossl_raise(eOCSPError, "d2i_OCSP_RESPONSE");
- SetOCSPRes(self, res_new);
- OCSP_RESPONSE_free(res);
+ GetOCSPRes(self, res);
+ arg = ossl_to_der_if_possible(arg);
+ StringValue(arg);
+ p = (unsigned char *)RSTRING_PTR(arg);
+ res_new = d2i_OCSP_RESPONSE(NULL, &p, RSTRING_LEN(arg));
+ if (!res_new)
+ ossl_raise(eOCSPError, "d2i_OCSP_RESPONSE");
+ SetOCSPRes(self, res_new);
+ OCSP_RESPONSE_free(res);
}
return self;
@@ -623,7 +621,7 @@ ossl_ocspres_get_basic(VALUE self)
GetOCSPRes(self, res);
ret = NewOCSPBasicRes(cOCSPBasicRes);
if(!(bs = OCSP_response_get1_basic(res)))
- return Qnil;
+ return Qnil;
SetOCSPBasicRes(ret, bs);
return ret;
@@ -646,11 +644,11 @@ ossl_ocspres_to_der(VALUE self)
GetOCSPRes(self, res);
if((len = i2d_OCSP_RESPONSE(res, NULL)) <= 0)
- ossl_raise(eOCSPError, NULL);
+ ossl_raise(eOCSPError, NULL);
str = rb_str_new(0, len);
p = (unsigned char *)RSTRING_PTR(str);
if(i2d_OCSP_RESPONSE(res, &p) <= 0)
- ossl_raise(eOCSPError, NULL);
+ ossl_raise(eOCSPError, NULL);
ossl_str_adjust(str, p);
return str;
@@ -667,7 +665,7 @@ ossl_ocspbres_alloc(VALUE klass)
obj = NewOCSPBasicRes(klass);
if(!(bs = OCSP_BASICRESP_new()))
- ossl_raise(eOCSPError, NULL);
+ ossl_raise(eOCSPError, NULL);
SetOCSPBasicRes(obj, bs);
return obj;
@@ -685,7 +683,7 @@ ossl_ocspbres_initialize_copy(VALUE self, VALUE other)
bs_new = ASN1_item_dup(ASN1_ITEM_rptr(OCSP_BASICRESP), bs);
if (!bs_new)
- ossl_raise(eOCSPError, "ASN1_item_dup");
+ ossl_raise(eOCSPError, "ASN1_item_dup");
SetOCSPBasicRes(self, bs_new);
OCSP_BASICRESP_free(bs_old);
@@ -710,15 +708,15 @@ ossl_ocspbres_initialize(int argc, VALUE *argv, VALUE self)
rb_scan_args(argc, argv, "01", &arg);
if (!NIL_P(arg)) {
- GetOCSPBasicRes(self, res);
- arg = ossl_to_der_if_possible(arg);
- StringValue(arg);
- p = (unsigned char *)RSTRING_PTR(arg);
- res_new = d2i_OCSP_BASICRESP(NULL, &p, RSTRING_LEN(arg));
- if (!res_new)
- ossl_raise(eOCSPError, "d2i_OCSP_BASICRESP");
- SetOCSPBasicRes(self, res_new);
- OCSP_BASICRESP_free(res);
+ GetOCSPBasicRes(self, res);
+ arg = ossl_to_der_if_possible(arg);
+ StringValue(arg);
+ p = (unsigned char *)RSTRING_PTR(arg);
+ res_new = d2i_OCSP_BASICRESP(NULL, &p, RSTRING_LEN(arg));
+ if (!res_new)
+ ossl_raise(eOCSPError, "d2i_OCSP_BASICRESP");
+ SetOCSPBasicRes(self, res_new);
+ OCSP_BASICRESP_free(res);
}
return self;
@@ -763,13 +761,13 @@ ossl_ocspbres_add_nonce(int argc, VALUE *argv, VALUE self)
rb_scan_args(argc, argv, "01", &val);
if(NIL_P(val)) {
- GetOCSPBasicRes(self, bs);
- ret = OCSP_basic_add1_nonce(bs, NULL, -1);
+ GetOCSPBasicRes(self, bs);
+ ret = OCSP_basic_add1_nonce(bs, NULL, -1);
}
else{
- StringValue(val);
- GetOCSPBasicRes(self, bs);
- ret = OCSP_basic_add1_nonce(bs, (unsigned char *)RSTRING_PTR(val), RSTRING_LENINT(val));
+ StringValue(val);
+ GetOCSPBasicRes(self, bs);
+ ret = OCSP_basic_add1_nonce(bs, (unsigned char *)RSTRING_PTR(val), RSTRING_LENINT(val));
}
if(!ret) ossl_raise(eOCSPError, NULL);
@@ -782,12 +780,12 @@ add_status_convert_time(VALUE obj)
ASN1_TIME *time;
if (RB_INTEGER_TYPE_P(obj))
- time = X509_gmtime_adj(NULL, NUM2INT(obj));
+ time = X509_gmtime_adj(NULL, NUM2INT(obj));
else
- time = ossl_x509_time_adjust(NULL, obj);
+ time = ossl_x509_time_adjust(NULL, obj);
if (!time)
- ossl_raise(eOCSPError, NULL);
+ ossl_raise(eOCSPError, NULL);
return (VALUE)time;
}
@@ -821,8 +819,8 @@ add_status_convert_time(VALUE obj)
*/
static VALUE
ossl_ocspbres_add_status(VALUE self, VALUE cid, VALUE status,
- VALUE reason, VALUE revtime,
- VALUE thisupd, VALUE nextupd, VALUE ext)
+ VALUE reason, VALUE revtime,
+ VALUE thisupd, VALUE nextupd, VALUE ext)
{
OCSP_BASICRESP *bs;
OCSP_SINGLERESP *single;
@@ -836,16 +834,16 @@ ossl_ocspbres_add_status(VALUE self, VALUE cid, VALUE status,
GetOCSPCertId(cid, id);
st = NUM2INT(status);
if (!NIL_P(ext)) { /* All ext's members must be X509::Extension */
- ext = rb_check_array_type(ext);
- for (i = 0; i < RARRAY_LEN(ext); i++)
- OSSL_Check_Kind(RARRAY_AREF(ext, i), cX509Ext);
+ ext = rb_check_array_type(ext);
+ for (i = 0; i < RARRAY_LEN(ext); i++)
+ OSSL_Check_Kind(RARRAY_AREF(ext, i), cX509Ext);
}
if (st == V_OCSP_CERTSTATUS_REVOKED) {
- rsn = NUM2INT(reason);
- tmp = rb_protect(add_status_convert_time, revtime, &rstatus);
- if (rstatus) goto err;
- rev = (ASN1_TIME *)tmp;
+ rsn = NUM2INT(reason);
+ tmp = rb_protect(add_status_convert_time, revtime, &rstatus);
+ if (rstatus) goto err;
+ rev = (ASN1_TIME *)tmp;
}
tmp = rb_protect(add_status_convert_time, thisupd, &rstatus);
@@ -853,29 +851,29 @@ ossl_ocspbres_add_status(VALUE self, VALUE cid, VALUE status,
ths = (ASN1_TIME *)tmp;
if (!NIL_P(nextupd)) {
- tmp = rb_protect(add_status_convert_time, nextupd, &rstatus);
- if (rstatus) goto err;
- nxt = (ASN1_TIME *)tmp;
+ tmp = rb_protect(add_status_convert_time, nextupd, &rstatus);
+ if (rstatus) goto err;
+ nxt = (ASN1_TIME *)tmp;
}
if(!(single = OCSP_basic_add1_status(bs, id, st, rsn, rev, ths, nxt))){
- error = 1;
- goto err;
+ error = 1;
+ goto err;
}
if(!NIL_P(ext)){
- X509_EXTENSION *x509ext;
-
- for(i = 0; i < RARRAY_LEN(ext); i++){
- x509ext = GetX509ExtPtr(RARRAY_AREF(ext, i));
- if(!OCSP_SINGLERESP_add_ext(single, x509ext, -1)){
- error = 1;
- goto err;
- }
- }
+ X509_EXTENSION *x509ext;
+
+ for(i = 0; i < RARRAY_LEN(ext); i++){
+ x509ext = GetX509ExtPtr(RARRAY_AREF(ext, i));
+ if(!OCSP_SINGLERESP_add_ext(single, x509ext, -1)){
+ error = 1;
+ goto err;
+ }
+ }
}
- err:
+ err:
ASN1_TIME_free(ths);
ASN1_TIME_free(nxt);
ASN1_TIME_free(rev);
@@ -907,8 +905,8 @@ ossl_ocspbres_get_status(VALUE self)
int count = OCSP_resp_count(bs);
for (int i = 0; i < count; i++) {
OCSP_SINGLERESP *single = OCSP_resp_get0(bs, i);
- ASN1_TIME *revtime, *thisupd, *nextupd;
- int reason;
+ ASN1_TIME *revtime = NULL, *thisupd = NULL, *nextupd = NULL;
+ int reason = -1;
int status = OCSP_single_get0_status(single, &reason, &revtime, &thisupd, &nextupd);
if (status < 0)
@@ -924,7 +922,7 @@ ossl_ocspbres_get_status(VALUE self)
VALUE ext = rb_ary_new();
int ext_count = OCSP_SINGLERESP_get_ext_count(single);
for (int j = 0; j < ext_count; j++) {
- X509_EXTENSION *x509ext = OCSP_SINGLERESP_get_ext(single, j);
+ const X509_EXTENSION *x509ext = OCSP_SINGLERESP_get_ext(single, j);
rb_ary_push(ext, ossl_x509ext_new(x509ext));
}
rb_ary_push(ary, ext);
@@ -980,7 +978,7 @@ ossl_ocspbres_find_response(VALUE self, VALUE target)
GetOCSPBasicRes(self, bs);
if ((n = OCSP_resp_find(bs, id, -1)) == -1)
- return Qnil;
+ return Qnil;
return ossl_ocspsres_new(OCSP_resp_get0(bs, n));
}
@@ -1000,7 +998,7 @@ ossl_ocspbres_find_response(VALUE self, VALUE target)
static VALUE
ossl_ocspbres_sign(int argc, VALUE *argv, VALUE self)
{
- VALUE signer_cert, signer_key, certs, flags, digest;
+ VALUE signer_cert, signer_key, certs, flags, digest, md_holder;
OCSP_BASICRESP *bs;
X509 *signer;
EVP_PKEY *key;
@@ -1014,19 +1012,17 @@ ossl_ocspbres_sign(int argc, VALUE *argv, VALUE self)
signer = GetX509CertPtr(signer_cert);
key = GetPrivPKeyPtr(signer_key);
if (!NIL_P(flags))
- flg = NUM2INT(flags);
- if (NIL_P(digest))
- md = NULL;
- else
- md = ossl_evp_get_digestbyname(digest);
+ flg = NUM2INT(flags);
+ md = NIL_P(digest) ? NULL : ossl_evp_md_fetch(digest, &md_holder);
if (NIL_P(certs))
- flg |= OCSP_NOCERTS;
+ flg |= OCSP_NOCERTS;
else
- x509s = ossl_x509_ary2sk(certs);
+ x509s = ossl_x509_ary2sk(certs);
ret = OCSP_basic_sign(bs, signer, key, md, x509s, flg);
sk_X509_pop_free(x509s, X509_free);
- if (!ret) ossl_raise(eOCSPError, NULL);
+ if (!ret)
+ ossl_raise(eOCSPError, "OCSP_basic_sign");
return self;
}
@@ -1055,7 +1051,7 @@ ossl_ocspbres_verify(int argc, VALUE *argv, VALUE self)
result = OCSP_basic_verify(bs, x509s, x509st, flg);
sk_X509_pop_free(x509s, X509_free);
if (result <= 0)
- ossl_clear_error();
+ ossl_clear_error();
return result > 0 ? Qtrue : Qfalse;
}
@@ -1076,11 +1072,11 @@ ossl_ocspbres_to_der(VALUE self)
GetOCSPBasicRes(self, res);
if ((len = i2d_OCSP_BASICRESP(res, NULL)) <= 0)
- ossl_raise(eOCSPError, NULL);
+ ossl_raise(eOCSPError, NULL);
str = rb_str_new(0, len);
p = (unsigned char *)RSTRING_PTR(str);
if (i2d_OCSP_BASICRESP(res, &p) <= 0)
- ossl_raise(eOCSPError, NULL);
+ ossl_raise(eOCSPError, NULL);
ossl_str_adjust(str, p);
return str;
@@ -1114,7 +1110,7 @@ ossl_ocspsres_alloc(VALUE klass)
obj = NewOCSPSingleRes(klass);
if (!(sres = OCSP_SINGLERESP_new()))
- ossl_raise(eOCSPError, NULL);
+ ossl_raise(eOCSPError, NULL);
SetOCSPSingleRes(obj, sres);
return obj;
@@ -1139,7 +1135,7 @@ ossl_ocspsres_initialize(VALUE self, VALUE arg)
p = (unsigned char*)RSTRING_PTR(arg);
res_new = d2i_OCSP_SINGLERESP(NULL, &p, RSTRING_LEN(arg));
if (!res_new)
- ossl_raise(eOCSPError, "d2i_OCSP_SINGLERESP");
+ ossl_raise(eOCSPError, "d2i_OCSP_SINGLERESP");
SetOCSPSingleRes(self, res_new);
OCSP_SINGLERESP_free(res);
@@ -1158,7 +1154,7 @@ ossl_ocspsres_initialize_copy(VALUE self, VALUE other)
sres_new = ASN1_item_dup(ASN1_ITEM_rptr(OCSP_SINGLERESP), sres);
if (!sres_new)
- ossl_raise(eOCSPError, "ASN1_item_dup");
+ ossl_raise(eOCSPError, "ASN1_item_dup");
SetOCSPSingleRes(self, sres_new);
OCSP_SINGLERESP_free(sres_old);
@@ -1197,15 +1193,15 @@ ossl_ocspsres_check_validity(int argc, VALUE *argv, VALUE self)
GetOCSPSingleRes(self, sres);
status = OCSP_single_get0_status(sres, NULL, NULL, &this_update, &next_update);
if (status < 0)
- ossl_raise(eOCSPError, "OCSP_single_get0_status");
+ ossl_raise(eOCSPError, "OCSP_single_get0_status");
ret = OCSP_check_validity(this_update, next_update, nsec, maxsec);
if (ret)
- return Qtrue;
+ return Qtrue;
else {
- ossl_clear_error();
- return Qfalse;
+ ossl_clear_error();
+ return Qfalse;
}
}
@@ -1247,7 +1243,7 @@ ossl_ocspsres_get_cert_status(VALUE self)
GetOCSPSingleRes(self, sres);
status = OCSP_single_get0_status(sres, NULL, NULL, NULL, NULL);
if (status < 0)
- ossl_raise(eOCSPError, "OCSP_single_get0_status");
+ ossl_raise(eOCSPError, "OCSP_single_get0_status");
return INT2NUM(status);
}
@@ -1266,9 +1262,9 @@ ossl_ocspsres_get_this_update(VALUE self)
GetOCSPSingleRes(self, sres);
status = OCSP_single_get0_status(sres, NULL, NULL, &time, NULL);
if (status < 0)
- ossl_raise(eOCSPError, "OCSP_single_get0_status");
+ ossl_raise(eOCSPError, "OCSP_single_get0_status");
if (!time)
- return Qnil;
+ return Qnil;
return asn1time_to_time(time);
}
@@ -1287,9 +1283,9 @@ ossl_ocspsres_get_next_update(VALUE self)
GetOCSPSingleRes(self, sres);
status = OCSP_single_get0_status(sres, NULL, NULL, NULL, &time);
if (status < 0)
- ossl_raise(eOCSPError, "OCSP_single_get0_status");
+ ossl_raise(eOCSPError, "OCSP_single_get0_status");
if (!time)
- return Qnil;
+ return Qnil;
return asn1time_to_time(time);
}
@@ -1308,11 +1304,11 @@ ossl_ocspsres_get_revocation_time(VALUE self)
GetOCSPSingleRes(self, sres);
status = OCSP_single_get0_status(sres, NULL, &time, NULL, NULL);
if (status < 0)
- ossl_raise(eOCSPError, "OCSP_single_get0_status");
+ ossl_raise(eOCSPError, "OCSP_single_get0_status");
if (status != V_OCSP_CERTSTATUS_REVOKED)
- ossl_raise(eOCSPError, "certificate is not revoked");
+ ossl_raise(eOCSPError, "certificate is not revoked");
if (!time)
- return Qnil;
+ return Qnil;
return asn1time_to_time(time);
}
@@ -1330,9 +1326,9 @@ ossl_ocspsres_get_revocation_reason(VALUE self)
GetOCSPSingleRes(self, sres);
status = OCSP_single_get0_status(sres, &reason, NULL, NULL, NULL);
if (status < 0)
- ossl_raise(eOCSPError, "OCSP_single_get0_status");
+ ossl_raise(eOCSPError, "OCSP_single_get0_status");
if (status != V_OCSP_CERTSTATUS_REVOKED)
- ossl_raise(eOCSPError, "certificate is not revoked");
+ ossl_raise(eOCSPError, "certificate is not revoked");
return INT2NUM(reason);
}
@@ -1345,7 +1341,6 @@ static VALUE
ossl_ocspsres_get_extensions(VALUE self)
{
OCSP_SINGLERESP *sres;
- X509_EXTENSION *ext;
int count, i;
VALUE ary;
@@ -1354,8 +1349,8 @@ ossl_ocspsres_get_extensions(VALUE self)
count = OCSP_SINGLERESP_get_ext_count(sres);
ary = rb_ary_new2(count);
for (i = 0; i < count; i++) {
- ext = OCSP_SINGLERESP_get_ext(sres, i);
- rb_ary_push(ary, ossl_x509ext_new(ext)); /* will dup */
+ const X509_EXTENSION *ext = OCSP_SINGLERESP_get_ext(sres, i);
+ rb_ary_push(ary, ossl_x509ext_new(ext)); /* will dup */
}
return ary;
@@ -1377,11 +1372,11 @@ ossl_ocspsres_to_der(VALUE self)
GetOCSPSingleRes(self, sres);
if ((len = i2d_OCSP_SINGLERESP(sres, NULL)) <= 0)
- ossl_raise(eOCSPError, NULL);
+ ossl_raise(eOCSPError, NULL);
str = rb_str_new(0, len);
p = (unsigned char *)RSTRING_PTR(str);
if (i2d_OCSP_SINGLERESP(sres, &p) <= 0)
- ossl_raise(eOCSPError, NULL);
+ ossl_raise(eOCSPError, NULL);
ossl_str_adjust(str, p);
return str;
@@ -1399,7 +1394,7 @@ ossl_ocspcid_alloc(VALUE klass)
obj = NewOCSPCertId(klass);
if(!(id = OCSP_CERTID_new()))
- ossl_raise(eOCSPError, NULL);
+ ossl_raise(eOCSPError, NULL);
SetOCSPCertId(obj, id);
return obj;
@@ -1417,7 +1412,7 @@ ossl_ocspcid_initialize_copy(VALUE self, VALUE other)
cid_new = OCSP_CERTID_dup(cid);
if (!cid_new)
- ossl_raise(eOCSPError, "OCSP_CERTID_dup");
+ ossl_raise(eOCSPError, "OCSP_CERTID_dup");
SetOCSPCertId(self, cid_new);
OCSP_CERTID_free(cid_old);
@@ -1447,27 +1442,28 @@ ossl_ocspcid_initialize(int argc, VALUE *argv, VALUE self)
GetOCSPCertId(self, id);
if (rb_scan_args(argc, argv, "12", &subject, &issuer, &digest) == 1) {
- VALUE arg;
- const unsigned char *p;
-
- arg = ossl_to_der_if_possible(subject);
- StringValue(arg);
- p = (unsigned char *)RSTRING_PTR(arg);
- newid = d2i_OCSP_CERTID(NULL, &p, RSTRING_LEN(arg));
- if (!newid)
- ossl_raise(eOCSPError, "d2i_OCSP_CERTID");
+ VALUE arg;
+ const unsigned char *p;
+
+ arg = ossl_to_der_if_possible(subject);
+ StringValue(arg);
+ p = (unsigned char *)RSTRING_PTR(arg);
+ newid = d2i_OCSP_CERTID(NULL, &p, RSTRING_LEN(arg));
+ if (!newid)
+ ossl_raise(eOCSPError, "d2i_OCSP_CERTID");
}
else {
- X509 *x509s, *x509i;
- const EVP_MD *md;
+ X509 *x509s, *x509i;
+ const EVP_MD *md;
+ VALUE md_holder;
- x509s = GetX509CertPtr(subject); /* NO NEED TO DUP */
- x509i = GetX509CertPtr(issuer); /* NO NEED TO DUP */
- md = !NIL_P(digest) ? ossl_evp_get_digestbyname(digest) : NULL;
+ x509s = GetX509CertPtr(subject); /* NO NEED TO DUP */
+ x509i = GetX509CertPtr(issuer); /* NO NEED TO DUP */
+ md = NIL_P(digest) ? NULL : ossl_evp_md_fetch(digest, &md_holder);
- newid = OCSP_cert_to_id(md, x509s, x509i);
- if (!newid)
- ossl_raise(eOCSPError, "OCSP_cert_to_id");
+ newid = OCSP_cert_to_id(md, x509s, x509i);
+ if (!newid)
+ ossl_raise(eOCSPError, "OCSP_cert_to_id");
}
SetOCSPCertId(self, newid);
@@ -1553,8 +1549,9 @@ ossl_ocspcid_get_issuer_name_hash(VALUE self)
GetOCSPCertId(self, id);
OCSP_id_get0_info(&name_hash, NULL, NULL, NULL, id);
- ret = rb_str_new(NULL, name_hash->length * 2);
- ossl_bin2hex(name_hash->data, RSTRING_PTR(ret), name_hash->length);
+ ret = rb_str_new(NULL, ASN1_STRING_length(name_hash) * 2);
+ ossl_bin2hex(ASN1_STRING_get0_data(name_hash), RSTRING_PTR(ret),
+ ASN1_STRING_length(name_hash));
return ret;
}
@@ -1576,8 +1573,9 @@ ossl_ocspcid_get_issuer_key_hash(VALUE self)
GetOCSPCertId(self, id);
OCSP_id_get0_info(NULL, NULL, &key_hash, NULL, id);
- ret = rb_str_new(NULL, key_hash->length * 2);
- ossl_bin2hex(key_hash->data, RSTRING_PTR(ret), key_hash->length);
+ ret = rb_str_new(NULL, ASN1_STRING_length(key_hash) * 2);
+ ossl_bin2hex(ASN1_STRING_get0_data(key_hash), RSTRING_PTR(ret),
+ ASN1_STRING_length(key_hash));
return ret;
}
@@ -1594,19 +1592,10 @@ ossl_ocspcid_get_hash_algorithm(VALUE self)
{
OCSP_CERTID *id;
ASN1_OBJECT *oid;
- BIO *out;
GetOCSPCertId(self, id);
OCSP_id_get0_info(NULL, &oid, NULL, NULL, id);
-
- if (!(out = BIO_new(BIO_s_mem())))
- ossl_raise(eOCSPError, "BIO_new");
-
- if (!i2a_ASN1_OBJECT(out, oid)) {
- BIO_free(out);
- ossl_raise(eOCSPError, "i2a_ASN1_OBJECT");
- }
- return ossl_membio2str(out);
+ return ossl_asn1obj_to_string_long_name(oid);
}
/*
@@ -1625,11 +1614,11 @@ ossl_ocspcid_to_der(VALUE self)
GetOCSPCertId(self, id);
if ((len = i2d_OCSP_CERTID(id, NULL)) <= 0)
- ossl_raise(eOCSPError, NULL);
+ ossl_raise(eOCSPError, NULL);
str = rb_str_new(0, len);
p = (unsigned char *)RSTRING_PTR(str);
if (i2d_OCSP_CERTID(id, &p) <= 0)
- ossl_raise(eOCSPError, NULL);
+ ossl_raise(eOCSPError, NULL);
ossl_str_adjust(str, p);
return str;
@@ -1638,11 +1627,6 @@ ossl_ocspcid_to_der(VALUE self)
void
Init_ossl_ocsp(void)
{
-#if 0
- mOSSL = rb_define_module("OpenSSL");
- eOSSLError = rb_define_class_under(mOSSL, "OpenSSLError", rb_eStandardError);
-#endif
-
/*
* OpenSSL::OCSP implements Online Certificate Status Protocol requests
* and responses.
diff --git a/ext/openssl/ossl_pkcs12.c b/ext/openssl/ossl_pkcs12.c
index 0b7469e673..a47c81354c 100644
--- a/ext/openssl/ossl_pkcs12.c
+++ b/ext/openssl/ossl_pkcs12.c
@@ -42,7 +42,7 @@ ossl_pkcs12_free(void *ptr)
static const rb_data_type_t ossl_pkcs12_type = {
"OpenSSL/PKCS12",
{
- 0, ossl_pkcs12_free,
+ 0, ossl_pkcs12_free,
},
0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
};
@@ -72,7 +72,7 @@ ossl_pkcs12_initialize_copy(VALUE self, VALUE other)
p12_new = ASN1_dup((i2d_of_void *)i2d_PKCS12, (d2i_of_void *)d2i_PKCS12, (char *)p12);
if (!p12_new)
- ossl_raise(ePKCS12Error, "ASN1_dup");
+ ossl_raise(ePKCS12Error, "ASN1_dup");
SetPKCS12(self, p12_new);
PKCS12_free(p12_old);
@@ -122,11 +122,11 @@ ossl_pkcs12_s_create(int argc, VALUE *argv, VALUE self)
/* TODO: make a VALUE to nid function */
if (!NIL_P(key_nid)) {
if ((nkey = OBJ_txt2nid(StringValueCStr(key_nid))) == NID_undef)
- ossl_raise(rb_eArgError, "Unknown PBE algorithm %"PRIsVALUE, key_nid);
+ ossl_raise(rb_eArgError, "Unknown PBE algorithm %"PRIsVALUE, key_nid);
}
if (!NIL_P(cert_nid)) {
if ((ncert = OBJ_txt2nid(StringValueCStr(cert_nid))) == NID_undef)
- ossl_raise(rb_eArgError, "Unknown PBE algorithm %"PRIsVALUE, cert_nid);
+ ossl_raise(rb_eArgError, "Unknown PBE algorithm %"PRIsVALUE, cert_nid);
}
if (!NIL_P(key_iter))
kiter = NUM2INT(key_iter);
@@ -191,6 +191,7 @@ ossl_x509_sk2ary_i(VALUE arg)
static VALUE
ossl_pkcs12_initialize(int argc, VALUE *argv, VALUE self)
{
+ PKCS12 *p12, *p12_orig = DATA_PTR(self);
BIO *in;
VALUE arg, pass, pkey, cert, ca;
char *passphrase;
@@ -198,29 +199,31 @@ ossl_pkcs12_initialize(int argc, VALUE *argv, VALUE self)
X509 *x509;
STACK_OF(X509) *x509s = NULL;
int st = 0;
- PKCS12 *pkcs = DATA_PTR(self);
if(rb_scan_args(argc, argv, "02", &arg, &pass) == 0) return self;
passphrase = NIL_P(pass) ? NULL : StringValueCStr(pass);
in = ossl_obj2bio(&arg);
- d2i_PKCS12_bio(in, &pkcs);
- DATA_PTR(self) = pkcs;
+ p12 = d2i_PKCS12_bio(in, NULL);
BIO_free(in);
+ if (!p12)
+ ossl_raise(ePKCS12Error, "d2i_PKCS12_bio");
+ PKCS12_free(p12_orig);
+ RTYPEDDATA_DATA(self) = p12;
pkey = cert = ca = Qnil;
- if(!PKCS12_parse(pkcs, passphrase, &key, &x509, &x509s))
- ossl_raise(ePKCS12Error, "PKCS12_parse");
+ if (!PKCS12_parse(p12, passphrase, &key, &x509, &x509s))
+ ossl_raise(ePKCS12Error, "PKCS12_parse");
if (key) {
- pkey = rb_protect(ossl_pkey_wrap_i, (VALUE)key, &st);
- if (st) goto err;
+ pkey = rb_protect(ossl_pkey_wrap_i, (VALUE)key, &st);
+ if (st) goto err;
}
if (x509) {
- cert = rb_protect(ossl_x509_new_i, (VALUE)x509, &st);
- if (st) goto err;
+ cert = rb_protect(ossl_x509_new_i, (VALUE)x509, &st);
+ if (st) goto err;
}
if (x509s) {
- ca = rb_protect(ossl_x509_sk2ary_i, (VALUE)x509s, &st);
- if (st) goto err;
+ ca = rb_protect(ossl_x509_sk2ary_i, (VALUE)x509s, &st);
+ if (st) goto err;
}
err:
@@ -244,11 +247,11 @@ ossl_pkcs12_to_der(VALUE self)
GetPKCS12(self, p12);
if((len = i2d_PKCS12(p12, NULL)) <= 0)
- ossl_raise(ePKCS12Error, NULL);
+ ossl_raise(ePKCS12Error, NULL);
str = rb_str_new(0, len);
p = (unsigned char *)RSTRING_PTR(str);
if(i2d_PKCS12(p12, &p) <= 0)
- ossl_raise(ePKCS12Error, NULL);
+ ossl_raise(ePKCS12Error, NULL);
ossl_str_adjust(str, p);
return str;
@@ -271,7 +274,7 @@ static VALUE
pkcs12_set_mac(int argc, VALUE *argv, VALUE self)
{
PKCS12 *p12;
- VALUE pass, salt, iter, md_name;
+ VALUE pass, salt, iter, md_name, md_holder = Qnil;
int iter_i = 0;
const EVP_MD *md_type = NULL;
@@ -285,7 +288,7 @@ pkcs12_set_mac(int argc, VALUE *argv, VALUE self)
if (!NIL_P(iter))
iter_i = NUM2INT(iter);
if (!NIL_P(md_name))
- md_type = ossl_evp_get_digestbyname(md_name);
+ md_type = ossl_evp_md_fetch(md_name, &md_holder);
if (!PKCS12_set_mac(p12, RSTRING_PTR(pass), RSTRING_LENINT(pass),
!NIL_P(salt) ? (unsigned char *)RSTRING_PTR(salt) : NULL,
@@ -300,11 +303,6 @@ void
Init_ossl_pkcs12(void)
{
#undef rb_intern
-#if 0
- mOSSL = rb_define_module("OpenSSL");
- eOSSLError = rb_define_class_under(mOSSL, "OpenSSLError", rb_eStandardError);
-#endif
-
/*
* Defines a file format commonly used to store private keys with
* accompanying public key certificates, protected with a password-based
diff --git a/ext/openssl/ossl_pkcs7.c b/ext/openssl/ossl_pkcs7.c
index 910ef9665c..44e8cb305b 100644
--- a/ext/openssl/ossl_pkcs7.c
+++ b/ext/openssl/ossl_pkcs7.c
@@ -28,14 +28,14 @@
TypedData_Wrap_Struct((klass), &ossl_pkcs7_signer_info_type, 0)
#define SetPKCS7si(obj, p7si) do { \
if (!(p7si)) { \
- ossl_raise(rb_eRuntimeError, "PKCS7si wasn't initialized."); \
+ ossl_raise(rb_eRuntimeError, "PKCS7si wasn't initialized."); \
} \
RTYPEDDATA_DATA(obj) = (p7si); \
} while (0)
#define GetPKCS7si(obj, p7si) do { \
TypedData_Get_Struct((obj), PKCS7_SIGNER_INFO, &ossl_pkcs7_signer_info_type, (p7si)); \
if (!(p7si)) { \
- ossl_raise(rb_eRuntimeError, "PKCS7si wasn't initialized."); \
+ ossl_raise(rb_eRuntimeError, "PKCS7si wasn't initialized."); \
} \
} while (0)
@@ -43,14 +43,14 @@
TypedData_Wrap_Struct((klass), &ossl_pkcs7_recip_info_type, 0)
#define SetPKCS7ri(obj, p7ri) do { \
if (!(p7ri)) { \
- ossl_raise(rb_eRuntimeError, "PKCS7ri wasn't initialized."); \
+ ossl_raise(rb_eRuntimeError, "PKCS7ri wasn't initialized."); \
} \
RTYPEDDATA_DATA(obj) = (p7ri); \
} while (0)
#define GetPKCS7ri(obj, p7ri) do { \
TypedData_Get_Struct((obj), PKCS7_RECIP_INFO, &ossl_pkcs7_recip_info_type, (p7ri)); \
if (!(p7ri)) { \
- ossl_raise(rb_eRuntimeError, "PKCS7ri wasn't initialized."); \
+ ossl_raise(rb_eRuntimeError, "PKCS7ri wasn't initialized."); \
} \
} while (0)
@@ -68,6 +68,7 @@ static VALUE cPKCS7;
static VALUE cPKCS7Signer;
static VALUE cPKCS7Recipient;
static VALUE ePKCS7Error;
+static ID id_md_holder, id_cipher_holder;
static void
ossl_pkcs7_free(void *ptr)
@@ -78,7 +79,7 @@ ossl_pkcs7_free(void *ptr)
static const rb_data_type_t ossl_pkcs7_type = {
"OpenSSL/PKCS7",
{
- 0, ossl_pkcs7_free,
+ 0, ossl_pkcs7_free,
},
0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
};
@@ -106,7 +107,7 @@ ossl_pkcs7_signer_info_free(void *ptr)
static const rb_data_type_t ossl_pkcs7_signer_info_type = {
"OpenSSL/PKCS7/SIGNER_INFO",
{
- 0, ossl_pkcs7_signer_info_free,
+ 0, ossl_pkcs7_signer_info_free,
},
0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
};
@@ -120,7 +121,7 @@ ossl_pkcs7_recip_info_free(void *ptr)
static const rb_data_type_t ossl_pkcs7_recip_info_type = {
"OpenSSL/PKCS7/RECIP_INFO",
{
- 0, ossl_pkcs7_recip_info_free,
+ 0, ossl_pkcs7_recip_info_free,
},
0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
};
@@ -237,7 +238,7 @@ ossl_pkcs7_s_write_smime(int argc, VALUE *argv, VALUE klass)
if(NIL_P(data)) data = ossl_pkcs7_get_data(pkcs7);
GetPKCS7(pkcs7, p7);
if(!NIL_P(data) && PKCS7_is_detached(p7))
- flg |= PKCS7_DETACHED;
+ flg |= PKCS7_DETACHED;
in = NIL_P(data) ? NULL : ossl_obj2bio(&data);
if(!(out = BIO_new(BIO_s_mem()))){
BIO_free(in);
@@ -278,16 +279,16 @@ ossl_pkcs7_s_sign(int argc, VALUE *argv, VALUE klass)
in = ossl_obj2bio(&data);
if(NIL_P(certs)) x509s = NULL;
else{
- x509s = ossl_protect_x509_ary2sk(certs, &status);
- if(status){
- BIO_free(in);
- rb_jump_tag(status);
- }
+ x509s = ossl_protect_x509_ary2sk(certs, &status);
+ if(status){
+ BIO_free(in);
+ rb_jump_tag(status);
+ }
}
if(!(pkcs7 = PKCS7_sign(x509, pkey, x509s, in, flg))){
- BIO_free(in);
- sk_X509_pop_free(x509s, X509_free);
- ossl_raise(ePKCS7Error, NULL);
+ BIO_free(in);
+ sk_X509_pop_free(x509s, X509_free);
+ ossl_raise(ePKCS7Error, NULL);
}
SetPKCS7(ret, pkcs7);
ossl_pkcs7_set_data(ret, data);
@@ -312,7 +313,7 @@ ossl_pkcs7_s_sign(int argc, VALUE *argv, VALUE klass)
static VALUE
ossl_pkcs7_s_encrypt(int argc, VALUE *argv, VALUE klass)
{
- VALUE certs, data, cipher, flags;
+ VALUE certs, data, cipher, flags, cipher_holder;
STACK_OF(X509) *x509s;
BIO *in;
const EVP_CIPHER *ciph;
@@ -326,23 +327,24 @@ ossl_pkcs7_s_encrypt(int argc, VALUE *argv, VALUE klass)
"cipher must be specified. Before version 3.3, " \
"the default cipher was RC2-40-CBC.");
}
- ciph = ossl_evp_get_cipherbyname(cipher);
+ ciph = ossl_evp_cipher_fetch(cipher, &cipher_holder);
flg = NIL_P(flags) ? 0 : NUM2INT(flags);
ret = NewPKCS7(cPKCS7);
in = ossl_obj2bio(&data);
x509s = ossl_protect_x509_ary2sk(certs, &status);
if(status){
- BIO_free(in);
- rb_jump_tag(status);
+ BIO_free(in);
+ rb_jump_tag(status);
}
if (!(p7 = PKCS7_encrypt(x509s, in, ciph, flg))) {
- BIO_free(in);
- sk_X509_pop_free(x509s, X509_free);
- ossl_raise(ePKCS7Error, NULL);
+ BIO_free(in);
+ sk_X509_pop_free(x509s, X509_free);
+ ossl_raise(ePKCS7Error, NULL);
}
BIO_free(in);
SetPKCS7(ret, p7);
ossl_pkcs7_set_data(ret, data);
+ rb_ivar_set(ret, id_cipher_holder, cipher_holder);
sk_X509_pop_free(x509s, X509_free);
return ret;
@@ -356,7 +358,7 @@ ossl_pkcs7_alloc(VALUE klass)
obj = NewPKCS7(klass);
if (!(pkcs7 = PKCS7_new())) {
- ossl_raise(ePKCS7Error, NULL);
+ ossl_raise(ePKCS7Error, NULL);
}
SetPKCS7(obj, pkcs7);
@@ -378,7 +380,7 @@ ossl_pkcs7_initialize(int argc, VALUE *argv, VALUE self)
VALUE arg;
if(rb_scan_args(argc, argv, "01", &arg) == 0)
- return self;
+ return self;
arg = ossl_to_der_if_possible(arg);
in = ossl_obj2bio(&arg);
p7 = d2i_PKCS7_bio(in, NULL);
@@ -388,10 +390,10 @@ ossl_pkcs7_initialize(int argc, VALUE *argv, VALUE self)
}
BIO_free(in);
if (!p7)
- ossl_raise(rb_eArgError, "Could not parse the PKCS7");
+ ossl_raise(ePKCS7Error, "Could not parse the PKCS7");
if (!p7->d.ptr) {
PKCS7_free(p7);
- ossl_raise(rb_eArgError, "No content in PKCS7");
+ ossl_raise(ePKCS7Error, "No content in PKCS7");
}
RTYPEDDATA_DATA(self) = p7;
@@ -416,7 +418,7 @@ ossl_pkcs7_copy(VALUE self, VALUE other)
pkcs7 = PKCS7_dup(b);
if (!pkcs7) {
- ossl_raise(ePKCS7Error, NULL);
+ ossl_raise(ePKCS7Error, NULL);
}
DATA_PTR(self) = pkcs7;
PKCS7_free(a);
@@ -448,13 +450,13 @@ ossl_pkcs7_sym2typeid(VALUE sym)
RSTRING_GETMEM(sym, s, l);
for(i = 0; ; i++){
- if(i == numberof(p7_type_tab))
- ossl_raise(ePKCS7Error, "unknown type \"%"PRIsVALUE"\"", sym);
- if(strlen(p7_type_tab[i].name) != l) continue;
- if(strcmp(p7_type_tab[i].name, s) == 0){
- ret = p7_type_tab[i].nid;
- break;
- }
+ if(i == numberof(p7_type_tab))
+ ossl_raise(ePKCS7Error, "unknown type \"%"PRIsVALUE"\"", sym);
+ if(strlen(p7_type_tab[i].name) != l) continue;
+ if(memcmp(p7_type_tab[i].name, s, l) == 0){
+ ret = p7_type_tab[i].nid;
+ break;
+ }
}
return ret;
@@ -471,7 +473,7 @@ ossl_pkcs7_set_type(VALUE self, VALUE type)
GetPKCS7(self, p7);
if(!PKCS7_set_type(p7, ossl_pkcs7_sym2typeid(type)))
- ossl_raise(ePKCS7Error, NULL);
+ ossl_raise(ePKCS7Error, NULL);
return type;
}
@@ -487,15 +489,15 @@ ossl_pkcs7_get_type(VALUE self)
GetPKCS7(self, p7);
if(PKCS7_type_is_signed(p7))
- return ID2SYM(rb_intern("signed"));
+ return ID2SYM(rb_intern("signed"));
if(PKCS7_type_is_encrypted(p7))
- return ID2SYM(rb_intern("encrypted"));
+ return ID2SYM(rb_intern("encrypted"));
if(PKCS7_type_is_enveloped(p7))
- return ID2SYM(rb_intern("enveloped"));
+ return ID2SYM(rb_intern("enveloped"));
if(PKCS7_type_is_signedAndEnveloped(p7))
- return ID2SYM(rb_intern("signedAndEnveloped"));
+ return ID2SYM(rb_intern("signedAndEnveloped"));
if(PKCS7_type_is_data(p7))
- return ID2SYM(rb_intern("data"));
+ return ID2SYM(rb_intern("data"));
return Qnil;
}
@@ -506,9 +508,9 @@ ossl_pkcs7_set_detached(VALUE self, VALUE flag)
GetPKCS7(self, p7);
if(flag != Qtrue && flag != Qfalse)
- ossl_raise(ePKCS7Error, "must specify a boolean");
+ ossl_raise(ePKCS7Error, "must specify a boolean");
if(!PKCS7_set_detached(p7, flag == Qtrue ? 1 : 0))
- ossl_raise(ePKCS7Error, NULL);
+ ossl_raise(ePKCS7Error, NULL);
return flag;
}
@@ -535,11 +537,14 @@ static VALUE
ossl_pkcs7_set_cipher(VALUE self, VALUE cipher)
{
PKCS7 *pkcs7;
+ const EVP_CIPHER *ciph;
+ VALUE cipher_holder;
GetPKCS7(self, pkcs7);
- if (!PKCS7_set_cipher(pkcs7, ossl_evp_get_cipherbyname(cipher))) {
- ossl_raise(ePKCS7Error, NULL);
- }
+ ciph = ossl_evp_cipher_fetch(cipher, &cipher_holder);
+ if (!PKCS7_set_cipher(pkcs7, ciph))
+ ossl_raise(ePKCS7Error, "PKCS7_set_cipher");
+ rb_ivar_set(self, id_cipher_holder, cipher_holder);
return cipher;
}
@@ -579,8 +584,8 @@ ossl_pkcs7_get_signer(VALUE self)
num = sk_PKCS7_SIGNER_INFO_num(sk);
ary = rb_ary_new_capa(num);
for (i=0; i<num; i++) {
- PKCS7_SIGNER_INFO *si = sk_PKCS7_SIGNER_INFO_value(sk, i);
- rb_ary_push(ary, ossl_pkcs7si_new(si));
+ PKCS7_SIGNER_INFO *si = sk_PKCS7_SIGNER_INFO_value(sk, i);
+ rb_ary_push(ary, ossl_pkcs7si_new(si));
}
return ary;
@@ -617,9 +622,9 @@ ossl_pkcs7_get_recipient(VALUE self)
GetPKCS7(self, pkcs7);
if (PKCS7_type_is_enveloped(pkcs7))
- sk = pkcs7->d.enveloped->recipientinfo;
+ sk = pkcs7->d.enveloped->recipientinfo;
else if (PKCS7_type_is_signedAndEnveloped(pkcs7))
- sk = pkcs7->d.signed_and_enveloped->recipientinfo;
+ sk = pkcs7->d.signed_and_enveloped->recipientinfo;
else sk = NULL;
if (!sk) return rb_ary_new();
num = sk_PKCS7_RECIP_INFO_num(sk);
@@ -641,7 +646,7 @@ ossl_pkcs7_add_certificate(VALUE self, VALUE cert)
GetPKCS7(self, pkcs7);
x509 = GetX509CertPtr(cert); /* NO NEED TO DUP */
if (!PKCS7_add_certificate(pkcs7, x509)){
- ossl_raise(ePKCS7Error, NULL);
+ ossl_raise(ePKCS7Error, NULL);
}
return self;
@@ -657,13 +662,13 @@ pkcs7_get_certs(VALUE self)
GetPKCS7(self, pkcs7);
i = OBJ_obj2nid(pkcs7->type);
switch(i){
- case NID_pkcs7_signed:
+ case NID_pkcs7_signed:
certs = pkcs7->d.sign->cert;
break;
- case NID_pkcs7_signedAndEnveloped:
+ case NID_pkcs7_signedAndEnveloped:
certs = pkcs7->d.signed_and_enveloped->cert;
break;
- default:
+ default:
certs = NULL;
}
@@ -680,13 +685,13 @@ pkcs7_get_crls(VALUE self)
GetPKCS7(self, pkcs7);
i = OBJ_obj2nid(pkcs7->type);
switch(i){
- case NID_pkcs7_signed:
+ case NID_pkcs7_signed:
crls = pkcs7->d.sign->crl;
break;
- case NID_pkcs7_signedAndEnveloped:
+ case NID_pkcs7_signedAndEnveloped:
crls = pkcs7->d.signed_and_enveloped->crl;
break;
- default:
+ default:
crls = NULL;
}
@@ -733,7 +738,7 @@ ossl_pkcs7_add_crl(VALUE self, VALUE crl)
GetPKCS7(self, pkcs7); /* NO DUP needed! */
x509crl = GetX509CRLPtr(crl);
if (!PKCS7_add_crl(pkcs7, x509crl)) {
- ossl_raise(ePKCS7Error, NULL);
+ ossl_raise(ePKCS7Error, NULL);
}
return self;
@@ -789,16 +794,16 @@ ossl_pkcs7_verify(int argc, VALUE *argv, VALUE self)
in = NIL_P(indata) ? NULL : ossl_obj2bio(&indata);
if(NIL_P(certs)) x509s = NULL;
else{
- x509s = ossl_protect_x509_ary2sk(certs, &status);
- if(status){
- BIO_free(in);
- rb_jump_tag(status);
- }
+ x509s = ossl_protect_x509_ary2sk(certs, &status);
+ if(status){
+ BIO_free(in);
+ rb_jump_tag(status);
+ }
}
if(!(out = BIO_new(BIO_s_mem()))){
- BIO_free(in);
- sk_X509_pop_free(x509s, X509_free);
- ossl_raise(ePKCS7Error, NULL);
+ BIO_free(in);
+ sk_X509_pop_free(x509s, X509_free);
+ ossl_raise(ePKCS7Error, NULL);
}
ok = PKCS7_verify(p7, x509s, x509st, in, out, flg);
BIO_free(in);
@@ -832,10 +837,10 @@ ossl_pkcs7_decrypt(int argc, VALUE *argv, VALUE self)
flg = NIL_P(flags) ? 0 : NUM2INT(flags);
GetPKCS7(self, p7);
if(!(out = BIO_new(BIO_s_mem())))
- ossl_raise(ePKCS7Error, NULL);
+ ossl_raise(ePKCS7Error, NULL);
if(!PKCS7_decrypt(p7, key, x509, out, flg)){
- BIO_free(out);
- ossl_raise(ePKCS7Error, NULL);
+ BIO_free(out);
+ ossl_raise(ePKCS7Error, NULL);
}
str = ossl_membio2str(out); /* out will be free */
@@ -894,11 +899,11 @@ ossl_pkcs7_to_der(VALUE self)
GetPKCS7(self, pkcs7);
if((len = i2d_PKCS7(pkcs7, NULL)) <= 0)
- ossl_raise(ePKCS7Error, NULL);
+ ossl_raise(ePKCS7Error, NULL);
str = rb_str_new(0, len);
p = (unsigned char *)RSTRING_PTR(str);
if(i2d_PKCS7(pkcs7, &p) <= 0)
- ossl_raise(ePKCS7Error, NULL);
+ ossl_raise(ePKCS7Error, NULL);
ossl_str_adjust(str, p);
return str;
@@ -932,11 +937,11 @@ ossl_pkcs7_to_pem(VALUE self)
GetPKCS7(self, pkcs7);
if (!(out = BIO_new(BIO_s_mem()))) {
- ossl_raise(ePKCS7Error, NULL);
+ ossl_raise(ePKCS7Error, NULL);
}
if (!PEM_write_bio_PKCS7(out, pkcs7)) {
- BIO_free(out);
- ossl_raise(ePKCS7Error, NULL);
+ BIO_free(out);
+ ossl_raise(ePKCS7Error, NULL);
}
str = ossl_membio2str(out);
@@ -954,7 +959,7 @@ ossl_pkcs7si_alloc(VALUE klass)
obj = NewPKCS7si(klass);
if (!(p7si = PKCS7_SIGNER_INFO_new())) {
- ossl_raise(ePKCS7Error, NULL);
+ ossl_raise(ePKCS7Error, NULL);
}
SetPKCS7si(obj, p7si);
@@ -968,14 +973,15 @@ ossl_pkcs7si_initialize(VALUE self, VALUE cert, VALUE key, VALUE digest)
EVP_PKEY *pkey;
X509 *x509;
const EVP_MD *md;
+ VALUE md_holder;
pkey = GetPrivPKeyPtr(key); /* NO NEED TO DUP */
x509 = GetX509CertPtr(cert); /* NO NEED TO DUP */
- md = ossl_evp_get_digestbyname(digest);
+ md = ossl_evp_md_fetch(digest, &md_holder);
GetPKCS7si(self, p7si);
- if (!(PKCS7_SIGNER_INFO_set(p7si, x509, pkey, md))) {
- ossl_raise(ePKCS7Error, NULL);
- }
+ if (PKCS7_SIGNER_INFO_set(p7si, x509, pkey, md) <= 0)
+ ossl_raise(ePKCS7Error, "PKCS7_SIGNER_INFO_set");
+ rb_ivar_set(self, id_md_holder, md_holder);
return self;
}
@@ -1004,15 +1010,15 @@ static VALUE
ossl_pkcs7si_get_signed_time(VALUE self)
{
PKCS7_SIGNER_INFO *p7si;
- ASN1_TYPE *asn1obj;
+ const ASN1_TYPE *asn1obj;
GetPKCS7si(self, p7si);
if (!(asn1obj = PKCS7_get_signed_attribute(p7si, NID_pkcs9_signingTime))) {
- ossl_raise(ePKCS7Error, NULL);
+ ossl_raise(ePKCS7Error, NULL);
}
if (asn1obj->type == V_ASN1_UTCTIME) {
- return asn1time_to_time(asn1obj->value.utctime);
+ return asn1time_to_time(asn1obj->value.utctime);
}
/*
* OR
@@ -1034,7 +1040,7 @@ ossl_pkcs7ri_alloc(VALUE klass)
obj = NewPKCS7ri(klass);
if (!(p7ri = PKCS7_RECIP_INFO_new())) {
- ossl_raise(ePKCS7Error, NULL);
+ ossl_raise(ePKCS7Error, NULL);
}
SetPKCS7ri(obj, p7ri);
@@ -1049,8 +1055,8 @@ ossl_pkcs7ri_initialize(VALUE self, VALUE cert)
x509 = GetX509CertPtr(cert); /* NO NEED TO DUP */
GetPKCS7ri(self, p7ri);
- if (!PKCS7_RECIP_INFO_set(p7ri, x509)) {
- ossl_raise(ePKCS7Error, NULL);
+ if (PKCS7_RECIP_INFO_set(p7ri, x509) <= 0) {
+ ossl_raise(ePKCS7Error, NULL);
}
return self;
@@ -1093,11 +1099,6 @@ void
Init_ossl_pkcs7(void)
{
#undef rb_intern
-#if 0
- mOSSL = rb_define_module("OpenSSL");
- eOSSLError = rb_define_class_under(mOSSL, "OpenSSLError", rb_eStandardError);
-#endif
-
cPKCS7 = rb_define_class_under(mOSSL, "PKCS7", rb_cObject);
ePKCS7Error = rb_define_class_under(cPKCS7, "PKCS7Error", eOSSLError);
rb_define_singleton_method(cPKCS7, "read_smime", ossl_pkcs7_s_read_smime, 1);
@@ -1161,4 +1162,7 @@ Init_ossl_pkcs7(void)
DefPKCS7Const(BINARY);
DefPKCS7Const(NOATTR);
DefPKCS7Const(NOSMIMECAP);
+
+ id_md_holder = rb_intern_const("EVP_MD_holder");
+ id_cipher_holder = rb_intern_const("EVP_CIPHER_holder");
}
diff --git a/ext/openssl/ossl_pkey.c b/ext/openssl/ossl_pkey.c
index e88074ddf2..a53332b17e 100644
--- a/ext/openssl/ossl_pkey.c
+++ b/ext/openssl/ossl_pkey.c
@@ -33,7 +33,7 @@ ossl_evp_pkey_free(void *ptr)
const rb_data_type_t ossl_evp_pkey_type = {
"OpenSSL/EVP_PKEY",
{
- 0, ossl_evp_pkey_free,
+ 0, ossl_evp_pkey_free,
},
0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
};
@@ -72,8 +72,8 @@ ossl_pkey_wrap(EVP_PKEY *pkey)
obj = rb_protect(pkey_wrap0, (VALUE)pkey, &status);
if (status) {
- EVP_PKEY_free(pkey);
- rb_jump_tag(status);
+ EVP_PKEY_free(pkey);
+ rb_jump_tag(status);
}
return obj;
@@ -94,7 +94,8 @@ ossl_pkey_read(BIO *bio, const char *input_type, int selection, VALUE pass)
selection, NULL, NULL);
if (!dctx)
goto out;
- if (OSSL_DECODER_CTX_set_pem_password_cb(dctx, ossl_pem_passwd_cb,
+ if (selection == EVP_PKEY_KEYPAIR &&
+ OSSL_DECODER_CTX_set_pem_password_cb(dctx, ossl_pem_passwd_cb,
ppass) != 1)
goto out;
while (1) {
@@ -187,23 +188,23 @@ ossl_pkey_read_generic(BIO *bio, VALUE pass)
EVP_PKEY *pkey;
if ((pkey = d2i_PrivateKey_bio(bio, NULL)))
- goto out;
+ goto out;
OSSL_BIO_reset(bio);
if ((pkey = d2i_PKCS8PrivateKey_bio(bio, NULL, ossl_pem_passwd_cb, ppass)))
- goto out;
+ goto out;
OSSL_BIO_reset(bio);
if ((pkey = d2i_PUBKEY_bio(bio, NULL)))
- goto out;
+ goto out;
OSSL_BIO_reset(bio);
/* PEM_read_bio_PrivateKey() also parses PKCS #8 formats */
if ((pkey = PEM_read_bio_PrivateKey(bio, NULL, ossl_pem_passwd_cb, ppass)))
- goto out;
+ goto out;
OSSL_BIO_reset(bio);
if ((pkey = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL)))
- goto out;
+ goto out;
OSSL_BIO_reset(bio);
if ((pkey = PEM_read_bio_Parameters(bio, NULL)))
- goto out;
+ goto out;
out:
return pkey;
@@ -238,7 +239,7 @@ ossl_pkey_new_from_data(int argc, VALUE *argv, VALUE self)
pkey = ossl_pkey_read_generic(bio, ossl_pem_passwd_value(pass));
BIO_free(bio);
if (!pkey)
- ossl_raise(ePKeyError, "Could not parse PKey");
+ ossl_raise(ePKeyError, "Could not parse PKey");
return ossl_pkey_wrap(pkey);
}
@@ -507,7 +508,7 @@ ossl_pkey_s_generate_key(int argc, VALUE *argv, VALUE self)
void
ossl_pkey_check_public_key(const EVP_PKEY *pkey)
{
-#if OSSL_OPENSSL_PREREQ(3, 0, 0)
+#ifdef OSSL_HAVE_IMMUTABLE_PKEY
if (EVP_PKEY_missing_parameters(pkey))
ossl_raise(ePKeyError, "parameters missing");
#else
@@ -515,34 +516,34 @@ ossl_pkey_check_public_key(const EVP_PKEY *pkey)
const BIGNUM *n, *e, *pubkey;
if (EVP_PKEY_missing_parameters(pkey))
- ossl_raise(ePKeyError, "parameters missing");
+ ossl_raise(ePKeyError, "parameters missing");
ptr = EVP_PKEY_get0(pkey);
switch (EVP_PKEY_base_id(pkey)) {
case EVP_PKEY_RSA:
- RSA_get0_key(ptr, &n, &e, NULL);
- if (n && e)
- return;
- break;
+ RSA_get0_key(ptr, &n, &e, NULL);
+ if (n && e)
+ return;
+ break;
case EVP_PKEY_DSA:
- DSA_get0_key(ptr, &pubkey, NULL);
- if (pubkey)
- return;
- break;
+ DSA_get0_key(ptr, &pubkey, NULL);
+ if (pubkey)
+ return;
+ break;
case EVP_PKEY_DH:
- DH_get0_key(ptr, &pubkey, NULL);
- if (pubkey)
- return;
- break;
+ DH_get0_key(ptr, &pubkey, NULL);
+ if (pubkey)
+ return;
+ break;
#if !defined(OPENSSL_NO_EC)
case EVP_PKEY_EC:
- if (EC_KEY_get0_public_key(ptr))
- return;
- break;
+ if (EC_KEY_get0_public_key(ptr))
+ return;
+ break;
#endif
default:
- /* unsupported type; assuming ok */
- return;
+ /* unsupported type; assuming ok */
+ return;
}
ossl_raise(ePKeyError, "public key missing");
#endif
@@ -609,7 +610,7 @@ static VALUE
ossl_pkey_initialize(VALUE self)
{
if (rb_obj_is_instance_of(self, cPKey)) {
- ossl_raise(rb_eTypeError, "OpenSSL::PKey::PKey can't be instantiated directly");
+ ossl_raise(rb_eTypeError, "OpenSSL::PKey::PKey can't be instantiated directly");
}
return self;
}
@@ -813,33 +814,33 @@ VALUE
ossl_pkey_export_traditional(int argc, VALUE *argv, VALUE self, int to_der)
{
EVP_PKEY *pkey;
- VALUE cipher, pass;
+ VALUE cipher, pass, cipher_holder;
const EVP_CIPHER *enc = NULL;
BIO *bio;
GetPKey(self, pkey);
rb_scan_args(argc, argv, "02", &cipher, &pass);
if (!NIL_P(cipher)) {
- enc = ossl_evp_get_cipherbyname(cipher);
- pass = ossl_pem_passwd_value(pass);
+ enc = ossl_evp_cipher_fetch(cipher, &cipher_holder);
+ pass = ossl_pem_passwd_value(pass);
}
bio = BIO_new(BIO_s_mem());
if (!bio)
- ossl_raise(ePKeyError, "BIO_new");
+ ossl_raise(ePKeyError, "BIO_new");
if (to_der) {
- if (!i2d_PrivateKey_bio(bio, pkey)) {
- BIO_free(bio);
- ossl_raise(ePKeyError, "i2d_PrivateKey_bio");
- }
+ if (!i2d_PrivateKey_bio(bio, pkey)) {
+ BIO_free(bio);
+ ossl_raise(ePKeyError, "i2d_PrivateKey_bio");
+ }
}
else {
- if (!PEM_write_bio_PrivateKey_traditional(bio, pkey, enc, NULL, 0,
- ossl_pem_passwd_cb,
- (void *)pass)) {
- BIO_free(bio);
- ossl_raise(ePKeyError, "PEM_write_bio_PrivateKey_traditional");
- }
+ if (!PEM_write_bio_PrivateKey_traditional(bio, pkey, enc, NULL, 0,
+ ossl_pem_passwd_cb,
+ (void *)pass)) {
+ BIO_free(bio);
+ ossl_raise(ePKeyError, "PEM_write_bio_PrivateKey_traditional");
+ }
}
return ossl_membio2str(bio);
}
@@ -848,37 +849,37 @@ static VALUE
do_pkcs8_export(int argc, VALUE *argv, VALUE self, int to_der)
{
EVP_PKEY *pkey;
- VALUE cipher, pass;
+ VALUE cipher, pass, cipher_holder;
const EVP_CIPHER *enc = NULL;
BIO *bio;
GetPKey(self, pkey);
rb_scan_args(argc, argv, "02", &cipher, &pass);
if (argc > 0) {
- /*
- * TODO: EncryptedPrivateKeyInfo actually has more options.
- * Should they be exposed?
- */
- enc = ossl_evp_get_cipherbyname(cipher);
- pass = ossl_pem_passwd_value(pass);
+ /*
+ * TODO: EncryptedPrivateKeyInfo actually has more options.
+ * Should they be exposed?
+ */
+ enc = ossl_evp_cipher_fetch(cipher, &cipher_holder);
+ pass = ossl_pem_passwd_value(pass);
}
bio = BIO_new(BIO_s_mem());
if (!bio)
- ossl_raise(ePKeyError, "BIO_new");
+ ossl_raise(ePKeyError, "BIO_new");
if (to_der) {
- if (!i2d_PKCS8PrivateKey_bio(bio, pkey, enc, NULL, 0,
- ossl_pem_passwd_cb, (void *)pass)) {
- BIO_free(bio);
- ossl_raise(ePKeyError, "i2d_PKCS8PrivateKey_bio");
- }
+ if (!i2d_PKCS8PrivateKey_bio(bio, pkey, enc, NULL, 0,
+ ossl_pem_passwd_cb, (void *)pass)) {
+ BIO_free(bio);
+ ossl_raise(ePKeyError, "i2d_PKCS8PrivateKey_bio");
+ }
}
else {
- if (!PEM_write_bio_PKCS8PrivateKey(bio, pkey, enc, NULL, 0,
- ossl_pem_passwd_cb, (void *)pass)) {
- BIO_free(bio);
- ossl_raise(ePKeyError, "PEM_write_bio_PKCS8PrivateKey");
- }
+ if (!PEM_write_bio_PKCS8PrivateKey(bio, pkey, enc, NULL, 0,
+ ossl_pem_passwd_cb, (void *)pass)) {
+ BIO_free(bio);
+ ossl_raise(ePKeyError, "PEM_write_bio_PKCS8PrivateKey");
+ }
}
return ossl_membio2str(bio);
}
@@ -962,18 +963,18 @@ ossl_pkey_export_spki(VALUE self, int to_der)
ossl_pkey_check_public_key(pkey);
bio = BIO_new(BIO_s_mem());
if (!bio)
- ossl_raise(ePKeyError, "BIO_new");
+ ossl_raise(ePKeyError, "BIO_new");
if (to_der) {
- if (!i2d_PUBKEY_bio(bio, pkey)) {
- BIO_free(bio);
- ossl_raise(ePKeyError, "i2d_PUBKEY_bio");
- }
+ if (!i2d_PUBKEY_bio(bio, pkey)) {
+ BIO_free(bio);
+ ossl_raise(ePKeyError, "i2d_PUBKEY_bio");
+ }
}
else {
- if (!PEM_write_bio_PUBKEY(bio, pkey)) {
- BIO_free(bio);
- ossl_raise(ePKeyError, "PEM_write_bio_PUBKEY");
- }
+ if (!PEM_write_bio_PUBKEY(bio, pkey)) {
+ BIO_free(bio);
+ ossl_raise(ePKeyError, "PEM_write_bio_PUBKEY");
+ }
}
return ossl_membio2str(bio);
}
@@ -1110,7 +1111,7 @@ static VALUE
ossl_pkey_sign(int argc, VALUE *argv, VALUE self)
{
EVP_PKEY *pkey;
- VALUE digest, data, options, sig;
+ VALUE digest, data, options, sig, md_holder;
const EVP_MD *md = NULL;
EVP_MD_CTX *ctx;
EVP_PKEY_CTX *pctx;
@@ -1120,7 +1121,7 @@ ossl_pkey_sign(int argc, VALUE *argv, VALUE self)
pkey = GetPrivPKeyPtr(self);
rb_scan_args(argc, argv, "21", &digest, &data, &options);
if (!NIL_P(digest))
- md = ossl_evp_get_digestbyname(digest);
+ md = ossl_evp_md_fetch(digest, &md_holder);
StringValue(data);
ctx = EVP_MD_CTX_new();
@@ -1189,7 +1190,7 @@ static VALUE
ossl_pkey_verify(int argc, VALUE *argv, VALUE self)
{
EVP_PKEY *pkey;
- VALUE digest, sig, data, options;
+ VALUE digest, sig, data, options, md_holder;
const EVP_MD *md = NULL;
EVP_MD_CTX *ctx;
EVP_PKEY_CTX *pctx;
@@ -1199,7 +1200,7 @@ ossl_pkey_verify(int argc, VALUE *argv, VALUE self)
rb_scan_args(argc, argv, "31", &digest, &sig, &data, &options);
ossl_pkey_check_public_key(pkey);
if (!NIL_P(digest))
- md = ossl_evp_get_digestbyname(digest);
+ md = ossl_evp_md_fetch(digest, &md_holder);
StringValue(sig);
StringValue(data);
@@ -1268,7 +1269,7 @@ static VALUE
ossl_pkey_sign_raw(int argc, VALUE *argv, VALUE self)
{
EVP_PKEY *pkey;
- VALUE digest, data, options, sig;
+ VALUE digest, data, options, sig, md_holder;
const EVP_MD *md = NULL;
EVP_PKEY_CTX *ctx;
size_t outlen;
@@ -1277,7 +1278,7 @@ ossl_pkey_sign_raw(int argc, VALUE *argv, VALUE self)
GetPKey(self, pkey);
rb_scan_args(argc, argv, "21", &digest, &data, &options);
if (!NIL_P(digest))
- md = ossl_evp_get_digestbyname(digest);
+ md = ossl_evp_md_fetch(digest, &md_holder);
StringValue(data);
ctx = EVP_PKEY_CTX_new(pkey, /* engine */NULL);
@@ -1344,7 +1345,7 @@ static VALUE
ossl_pkey_verify_raw(int argc, VALUE *argv, VALUE self)
{
EVP_PKEY *pkey;
- VALUE digest, sig, data, options;
+ VALUE digest, sig, data, options, md_holder;
const EVP_MD *md = NULL;
EVP_PKEY_CTX *ctx;
int state, ret;
@@ -1353,7 +1354,7 @@ ossl_pkey_verify_raw(int argc, VALUE *argv, VALUE self)
rb_scan_args(argc, argv, "31", &digest, &sig, &data, &options);
ossl_pkey_check_public_key(pkey);
if (!NIL_P(digest))
- md = ossl_evp_get_digestbyname(digest);
+ md = ossl_evp_md_fetch(digest, &md_holder);
StringValue(sig);
StringValue(data);
@@ -1407,7 +1408,7 @@ static VALUE
ossl_pkey_verify_recover(int argc, VALUE *argv, VALUE self)
{
EVP_PKEY *pkey;
- VALUE digest, sig, options, out;
+ VALUE digest, sig, options, out, md_holder;
const EVP_MD *md = NULL;
EVP_PKEY_CTX *ctx;
int state;
@@ -1417,7 +1418,7 @@ ossl_pkey_verify_recover(int argc, VALUE *argv, VALUE self)
rb_scan_args(argc, argv, "21", &digest, &sig, &options);
ossl_pkey_check_public_key(pkey);
if (!NIL_P(digest))
- md = ossl_evp_get_digestbyname(digest);
+ md = ossl_evp_md_fetch(digest, &md_holder);
StringValue(sig);
ctx = EVP_PKEY_CTX_new(pkey, /* engine */NULL);
@@ -1495,8 +1496,10 @@ ossl_pkey_derive(int argc, VALUE *argv, VALUE self)
EVP_PKEY_CTX_free(ctx);
ossl_raise(ePKeyError, "EVP_PKEY_derive");
}
- if (keylen > LONG_MAX)
+ if (keylen > LONG_MAX) {
+ EVP_PKEY_CTX_free(ctx);
rb_raise(ePKeyError, "derived key would be too large");
+ }
str = ossl_str_new(NULL, (long)keylen, &state);
if (state) {
EVP_PKEY_CTX_free(ctx);
@@ -1657,11 +1660,6 @@ void
Init_ossl_pkey(void)
{
#undef rb_intern
-#if 0
- mOSSL = rb_define_module("OpenSSL");
- eOSSLError = rb_define_class_under(mOSSL, "OpenSSLError", rb_eStandardError);
-#endif
-
/* Document-module: OpenSSL::PKey
*
* == Asymmetric Public Key Algorithms
@@ -1717,7 +1715,16 @@ Init_ossl_pkey(void)
/* Document-class: OpenSSL::PKey::PKeyError
*
- *Raised when errors occur during PKey#sign or PKey#verify.
+ * Raised when errors occur during PKey#sign or PKey#verify.
+ *
+ * Before version 4.0.0, OpenSSL::PKey::PKeyError had the following
+ * subclasses. These subclasses have been removed and the constants are
+ * now defined as aliases of OpenSSL::PKey::PKeyError.
+ *
+ * * OpenSSL::PKey::DHError
+ * * OpenSSL::PKey::DSAError
+ * * OpenSSL::PKey::ECError
+ * * OpenSSL::PKey::RSAError
*/
ePKeyError = rb_define_class_under(mPKey, "PKeyError", eOSSLError);
diff --git a/ext/openssl/ossl_pkey.h b/ext/openssl/ossl_pkey.h
index 6778381210..efba33b752 100644
--- a/ext/openssl/ossl_pkey.h
+++ b/ext/openssl/ossl_pkey.h
@@ -22,7 +22,7 @@ extern const rb_data_type_t ossl_evp_pkey_type;
#define GetPKey(obj, pkey) do {\
TypedData_Get_Struct((obj), EVP_PKEY, &ossl_evp_pkey_type, (pkey)); \
if (!(pkey)) { \
- rb_raise(rb_eRuntimeError, "PKEY wasn't initialized!");\
+ rb_raise(rb_eRuntimeError, "PKEY wasn't initialized!");\
} \
} while (0)
@@ -45,7 +45,7 @@ VALUE ossl_pkey_export_spki(VALUE self, int to_der);
* #to_der.
*/
VALUE ossl_pkey_export_traditional(int argc, VALUE *argv, VALUE self,
- int to_der);
+ int to_der);
void Init_ossl_pkey(void);
@@ -71,123 +71,122 @@ void Init_ossl_dh(void);
* EC
*/
extern VALUE cEC;
-VALUE ossl_ec_new(EVP_PKEY *);
void Init_ossl_ec(void);
-#define OSSL_PKEY_BN_DEF_GETTER0(_keytype, _type, _name, _get) \
-/* \
- * call-seq: \
- * _keytype##.##_name -> aBN \
- */ \
-static VALUE ossl_##_keytype##_get_##_name(VALUE self) \
-{ \
- const _type *obj; \
- const BIGNUM *bn; \
- \
- Get##_type(self, obj); \
- _get; \
- if (bn == NULL) \
- return Qnil; \
- return ossl_bn_new(bn); \
+#define OSSL_PKEY_BN_DEF_GETTER0(_keytype, _type, _name, _get) \
+/* \
+ * call-seq: \
+ * _keytype##.##_name -> aBN \
+ */ \
+static VALUE ossl_##_keytype##_get_##_name(VALUE self) \
+{ \
+ const _type *obj; \
+ const BIGNUM *bn; \
+ \
+ Get##_type(self, obj); \
+ _get; \
+ if (bn == NULL) \
+ return Qnil; \
+ return ossl_bn_new(bn); \
}
-#define OSSL_PKEY_BN_DEF_GETTER3(_keytype, _type, _group, a1, a2, a3) \
- OSSL_PKEY_BN_DEF_GETTER0(_keytype, _type, a1, \
- _type##_get0_##_group(obj, &bn, NULL, NULL)) \
- OSSL_PKEY_BN_DEF_GETTER0(_keytype, _type, a2, \
- _type##_get0_##_group(obj, NULL, &bn, NULL)) \
- OSSL_PKEY_BN_DEF_GETTER0(_keytype, _type, a3, \
- _type##_get0_##_group(obj, NULL, NULL, &bn))
-
-#define OSSL_PKEY_BN_DEF_GETTER2(_keytype, _type, _group, a1, a2) \
- OSSL_PKEY_BN_DEF_GETTER0(_keytype, _type, a1, \
- _type##_get0_##_group(obj, &bn, NULL)) \
- OSSL_PKEY_BN_DEF_GETTER0(_keytype, _type, a2, \
- _type##_get0_##_group(obj, NULL, &bn))
-
-#if !OSSL_OPENSSL_PREREQ(3, 0, 0)
-#define OSSL_PKEY_BN_DEF_SETTER3(_keytype, _type, _group, a1, a2, a3) \
-/* \
- * call-seq: \
- * _keytype##.set_##_group(a1, a2, a3) -> self \
- */ \
+#define OSSL_PKEY_BN_DEF_GETTER3(_keytype, _type, _group, a1, a2, a3) \
+ OSSL_PKEY_BN_DEF_GETTER0(_keytype, _type, a1, \
+ _type##_get0_##_group(obj, &bn, NULL, NULL)) \
+ OSSL_PKEY_BN_DEF_GETTER0(_keytype, _type, a2, \
+ _type##_get0_##_group(obj, NULL, &bn, NULL)) \
+ OSSL_PKEY_BN_DEF_GETTER0(_keytype, _type, a3, \
+ _type##_get0_##_group(obj, NULL, NULL, &bn))
+
+#define OSSL_PKEY_BN_DEF_GETTER2(_keytype, _type, _group, a1, a2) \
+ OSSL_PKEY_BN_DEF_GETTER0(_keytype, _type, a1, \
+ _type##_get0_##_group(obj, &bn, NULL)) \
+ OSSL_PKEY_BN_DEF_GETTER0(_keytype, _type, a2, \
+ _type##_get0_##_group(obj, NULL, &bn))
+
+#ifndef OSSL_HAVE_IMMUTABLE_PKEY
+#define OSSL_PKEY_BN_DEF_SETTER3(_keytype, _type, _group, a1, a2, a3) \
+/* \
+ * call-seq: \
+ * _keytype##.set_##_group(a1, a2, a3) -> self \
+ */ \
static VALUE ossl_##_keytype##_set_##_group(VALUE self, VALUE v1, VALUE v2, VALUE v3) \
-{ \
- _type *obj; \
- BIGNUM *bn1 = NULL, *orig_bn1 = NIL_P(v1) ? NULL : GetBNPtr(v1);\
- BIGNUM *bn2 = NULL, *orig_bn2 = NIL_P(v2) ? NULL : GetBNPtr(v2);\
- BIGNUM *bn3 = NULL, *orig_bn3 = NIL_P(v3) ? NULL : GetBNPtr(v3);\
- \
- Get##_type(self, obj); \
- if ((orig_bn1 && !(bn1 = BN_dup(orig_bn1))) || \
- (orig_bn2 && !(bn2 = BN_dup(orig_bn2))) || \
- (orig_bn3 && !(bn3 = BN_dup(orig_bn3)))) { \
- BN_clear_free(bn1); \
- BN_clear_free(bn2); \
- BN_clear_free(bn3); \
- ossl_raise(ePKeyError, "BN_dup"); \
- } \
- \
- if (!_type##_set0_##_group(obj, bn1, bn2, bn3)) { \
- BN_clear_free(bn1); \
- BN_clear_free(bn2); \
- BN_clear_free(bn3); \
- ossl_raise(ePKeyError, #_type"_set0_"#_group); \
- } \
- return self; \
+{ \
+ _type *obj; \
+ BIGNUM *bn1 = NULL, *orig_bn1 = NIL_P(v1) ? NULL : GetBNPtr(v1);\
+ BIGNUM *bn2 = NULL, *orig_bn2 = NIL_P(v2) ? NULL : GetBNPtr(v2);\
+ BIGNUM *bn3 = NULL, *orig_bn3 = NIL_P(v3) ? NULL : GetBNPtr(v3);\
+ \
+ Get##_type(self, obj); \
+ if ((orig_bn1 && !(bn1 = BN_dup(orig_bn1))) || \
+ (orig_bn2 && !(bn2 = BN_dup(orig_bn2))) || \
+ (orig_bn3 && !(bn3 = BN_dup(orig_bn3)))) { \
+ BN_clear_free(bn1); \
+ BN_clear_free(bn2); \
+ BN_clear_free(bn3); \
+ ossl_raise(ePKeyError, "BN_dup"); \
+ } \
+ \
+ if (!_type##_set0_##_group(obj, bn1, bn2, bn3)) { \
+ BN_clear_free(bn1); \
+ BN_clear_free(bn2); \
+ BN_clear_free(bn3); \
+ ossl_raise(ePKeyError, #_type"_set0_"#_group); \
+ } \
+ return self; \
}
-#define OSSL_PKEY_BN_DEF_SETTER2(_keytype, _type, _group, a1, a2) \
-/* \
- * call-seq: \
- * _keytype##.set_##_group(a1, a2) -> self \
- */ \
+#define OSSL_PKEY_BN_DEF_SETTER2(_keytype, _type, _group, a1, a2) \
+/* \
+ * call-seq: \
+ * _keytype##.set_##_group(a1, a2) -> self \
+ */ \
static VALUE ossl_##_keytype##_set_##_group(VALUE self, VALUE v1, VALUE v2) \
-{ \
- _type *obj; \
- BIGNUM *bn1 = NULL, *orig_bn1 = NIL_P(v1) ? NULL : GetBNPtr(v1);\
- BIGNUM *bn2 = NULL, *orig_bn2 = NIL_P(v2) ? NULL : GetBNPtr(v2);\
- \
- Get##_type(self, obj); \
- if ((orig_bn1 && !(bn1 = BN_dup(orig_bn1))) || \
- (orig_bn2 && !(bn2 = BN_dup(orig_bn2)))) { \
- BN_clear_free(bn1); \
- BN_clear_free(bn2); \
- ossl_raise(ePKeyError, "BN_dup"); \
- } \
- \
- if (!_type##_set0_##_group(obj, bn1, bn2)) { \
- BN_clear_free(bn1); \
- BN_clear_free(bn2); \
- ossl_raise(ePKeyError, #_type"_set0_"#_group); \
- } \
- return self; \
+{ \
+ _type *obj; \
+ BIGNUM *bn1 = NULL, *orig_bn1 = NIL_P(v1) ? NULL : GetBNPtr(v1);\
+ BIGNUM *bn2 = NULL, *orig_bn2 = NIL_P(v2) ? NULL : GetBNPtr(v2);\
+ \
+ Get##_type(self, obj); \
+ if ((orig_bn1 && !(bn1 = BN_dup(orig_bn1))) || \
+ (orig_bn2 && !(bn2 = BN_dup(orig_bn2)))) { \
+ BN_clear_free(bn1); \
+ BN_clear_free(bn2); \
+ ossl_raise(ePKeyError, "BN_dup"); \
+ } \
+ \
+ if (!_type##_set0_##_group(obj, bn1, bn2)) { \
+ BN_clear_free(bn1); \
+ BN_clear_free(bn2); \
+ ossl_raise(ePKeyError, #_type"_set0_"#_group); \
+ } \
+ return self; \
}
#else
-#define OSSL_PKEY_BN_DEF_SETTER3(_keytype, _type, _group, a1, a2, a3) \
+#define OSSL_PKEY_BN_DEF_SETTER3(_keytype, _type, _group, a1, a2, a3) \
static VALUE ossl_##_keytype##_set_##_group(VALUE self, VALUE v1, VALUE v2, VALUE v3) \
-{ \
- rb_raise(ePKeyError, \
+{ \
+ rb_raise(ePKeyError, \
#_keytype"#set_"#_group"= is incompatible with OpenSSL 3.0"); \
}
-#define OSSL_PKEY_BN_DEF_SETTER2(_keytype, _type, _group, a1, a2) \
+#define OSSL_PKEY_BN_DEF_SETTER2(_keytype, _type, _group, a1, a2) \
static VALUE ossl_##_keytype##_set_##_group(VALUE self, VALUE v1, VALUE v2) \
-{ \
- rb_raise(ePKeyError, \
+{ \
+ rb_raise(ePKeyError, \
#_keytype"#set_"#_group"= is incompatible with OpenSSL 3.0"); \
}
#endif
-#define OSSL_PKEY_BN_DEF3(_keytype, _type, _group, a1, a2, a3) \
- OSSL_PKEY_BN_DEF_GETTER3(_keytype, _type, _group, a1, a2, a3) \
- OSSL_PKEY_BN_DEF_SETTER3(_keytype, _type, _group, a1, a2, a3)
+#define OSSL_PKEY_BN_DEF3(_keytype, _type, _group, a1, a2, a3) \
+ OSSL_PKEY_BN_DEF_GETTER3(_keytype, _type, _group, a1, a2, a3) \
+ OSSL_PKEY_BN_DEF_SETTER3(_keytype, _type, _group, a1, a2, a3)
-#define OSSL_PKEY_BN_DEF2(_keytype, _type, _group, a1, a2) \
- OSSL_PKEY_BN_DEF_GETTER2(_keytype, _type, _group, a1, a2) \
- OSSL_PKEY_BN_DEF_SETTER2(_keytype, _type, _group, a1, a2)
+#define OSSL_PKEY_BN_DEF2(_keytype, _type, _group, a1, a2) \
+ OSSL_PKEY_BN_DEF_GETTER2(_keytype, _type, _group, a1, a2) \
+ OSSL_PKEY_BN_DEF_SETTER2(_keytype, _type, _group, a1, a2)
-#define DEF_OSSL_PKEY_BN(class, keytype, name) \
- rb_define_method((class), #name, ossl_##keytype##_get_##name, 0)
+#define DEF_OSSL_PKEY_BN(class, keytype, name) \
+ rb_define_method((class), #name, ossl_##keytype##_get_##name, 0)
#endif /* OSSL_PKEY_H */
diff --git a/ext/openssl/ossl_pkey_dh.c b/ext/openssl/ossl_pkey_dh.c
index 118d29f04f..3f2975c5a3 100644
--- a/ext/openssl/ossl_pkey_dh.c
+++ b/ext/openssl/ossl_pkey_dh.c
@@ -14,20 +14,21 @@
#define GetPKeyDH(obj, pkey) do { \
GetPKey((obj), (pkey)); \
if (EVP_PKEY_base_id(pkey) != EVP_PKEY_DH) { /* PARANOIA? */ \
- ossl_raise(rb_eRuntimeError, "THIS IS NOT A DH!") ; \
+ ossl_raise(rb_eRuntimeError, "THIS IS NOT A DH!") ; \
} \
} while (0)
#define GetDH(obj, dh) do { \
EVP_PKEY *_pkey; \
GetPKeyDH((obj), _pkey); \
(dh) = EVP_PKEY_get0_DH(_pkey); \
+ if ((dh) == NULL) \
+ ossl_raise(ePKeyError, "failed to get DH from EVP_PKEY"); \
} while (0)
/*
* Classes
*/
VALUE cDH;
-static VALUE eDHError;
/*
* Private
@@ -43,6 +44,7 @@ static VALUE eDHError;
* If called without arguments, an empty instance without any parameter or key
* components is created. Use #set_pqg to manually set the parameters afterwards
* (and optionally #set_key to set private and public key components).
+ * This form is not compatible with OpenSSL 3.0 or later.
*
* If a String is given, tries to parse it as a DER- or PEM- encoded parameters.
* See also OpenSSL::PKey.read which can parse keys of any kinds.
@@ -58,14 +60,15 @@ static VALUE eDHError;
*
* Examples:
* # Creating an instance from scratch
- * # Note that this is deprecated and will not work on OpenSSL 3.0 or later.
+ * # Note that this is deprecated and will result in ArgumentError when
+ * # using OpenSSL 3.0 or later.
* dh = OpenSSL::PKey::DH.new
* dh.set_pqg(bn_p, nil, bn_g)
*
* # Generating a parameters and a key pair
* dh = OpenSSL::PKey::DH.new(2048) # An alias of OpenSSL::PKey::DH.generate(2048)
*
- * # Reading DH parameters
+ * # Reading DH parameters from a PEM-encoded string
* dh_params = OpenSSL::PKey::DH.new(File.read('parameters.pem')) # loads parameters only
* dh = OpenSSL::PKey.generate_key(dh_params) # generates a key pair
*/
@@ -84,10 +87,15 @@ ossl_dh_initialize(int argc, VALUE *argv, VALUE self)
/* The DH.new(size, generator) form is handled by lib/openssl/pkey.rb */
if (rb_scan_args(argc, argv, "01", &arg) == 0) {
+#ifdef OSSL_HAVE_IMMUTABLE_PKEY
+ rb_raise(rb_eArgError, "OpenSSL::PKey::DH.new cannot be called " \
+ "without arguments; pkeys are immutable with OpenSSL 3.0");
+#else
dh = DH_new();
if (!dh)
- ossl_raise(eDHError, "DH_new");
+ ossl_raise(ePKeyError, "DH_new");
goto legacy;
+#endif
}
arg = ossl_to_der_if_possible(arg);
@@ -105,12 +113,12 @@ ossl_dh_initialize(int argc, VALUE *argv, VALUE self)
pkey = ossl_pkey_read_generic(in, Qnil);
BIO_free(in);
if (!pkey)
- ossl_raise(eDHError, "could not parse pkey");
+ ossl_raise(ePKeyError, "could not parse pkey");
type = EVP_PKEY_base_id(pkey);
if (type != EVP_PKEY_DH) {
EVP_PKEY_free(pkey);
- rb_raise(eDHError, "incorrect pkey type: %s", OBJ_nid2sn(type));
+ rb_raise(ePKeyError, "incorrect pkey type: %s", OBJ_nid2sn(type));
}
RTYPEDDATA_DATA(self) = pkey;
return self;
@@ -121,7 +129,7 @@ ossl_dh_initialize(int argc, VALUE *argv, VALUE self)
if (!pkey || EVP_PKEY_assign_DH(pkey, dh) != 1) {
EVP_PKEY_free(pkey);
DH_free(dh);
- ossl_raise(eDHError, "EVP_PKEY_assign_DH");
+ ossl_raise(ePKeyError, "EVP_PKEY_assign_DH");
}
RTYPEDDATA_DATA(self) = pkey;
return self;
@@ -143,26 +151,26 @@ ossl_dh_initialize_copy(VALUE self, VALUE other)
dh = DHparams_dup(dh_other);
if (!dh)
- ossl_raise(eDHError, "DHparams_dup");
+ ossl_raise(ePKeyError, "DHparams_dup");
DH_get0_key(dh_other, &pub, &priv);
if (pub) {
- BIGNUM *pub2 = BN_dup(pub);
- BIGNUM *priv2 = BN_dup(priv);
+ BIGNUM *pub2 = BN_dup(pub);
+ BIGNUM *priv2 = BN_dup(priv);
if (!pub2 || (priv && !priv2)) {
- BN_clear_free(pub2);
- BN_clear_free(priv2);
- ossl_raise(eDHError, "BN_dup");
- }
- DH_set0_key(dh, pub2, priv2);
+ BN_clear_free(pub2);
+ BN_clear_free(priv2);
+ ossl_raise(ePKeyError, "BN_dup");
+ }
+ DH_set0_key(dh, pub2, priv2);
}
pkey = EVP_PKEY_new();
if (!pkey || EVP_PKEY_assign_DH(pkey, dh) != 1) {
EVP_PKEY_free(pkey);
DH_free(dh);
- ossl_raise(eDHError, "EVP_PKEY_assign_DH");
+ ossl_raise(ePKeyError, "EVP_PKEY_assign_DH");
}
RTYPEDDATA_DATA(self) = pkey;
return self;
@@ -241,11 +249,11 @@ ossl_dh_export(VALUE self)
GetDH(self, dh);
if (!(out = BIO_new(BIO_s_mem()))) {
- ossl_raise(eDHError, NULL);
+ ossl_raise(ePKeyError, NULL);
}
if (!PEM_write_bio_DHparams(out, dh)) {
- BIO_free(out);
- ossl_raise(eDHError, NULL);
+ BIO_free(out);
+ ossl_raise(ePKeyError, NULL);
}
str = ossl_membio2str(out);
@@ -275,11 +283,11 @@ ossl_dh_to_der(VALUE self)
GetDH(self, dh);
if((len = i2d_DHparams(dh, NULL)) <= 0)
- ossl_raise(eDHError, NULL);
+ ossl_raise(ePKeyError, NULL);
str = rb_str_new(0, len);
p = (unsigned char *)RSTRING_PTR(str);
if(i2d_DHparams(dh, &p) < 0)
- ossl_raise(eDHError, NULL);
+ ossl_raise(ePKeyError, NULL);
ossl_str_adjust(str, p);
return str;
@@ -306,7 +314,7 @@ ossl_dh_check_params(VALUE self)
GetPKey(self, pkey);
pctx = EVP_PKEY_CTX_new(pkey, /* engine */NULL);
if (!pctx)
- ossl_raise(eDHError, "EVP_PKEY_CTX_new");
+ ossl_raise(ePKeyError, "EVP_PKEY_CTX_new");
ret = EVP_PKEY_param_check(pctx);
EVP_PKEY_CTX_free(pctx);
#else
@@ -349,19 +357,6 @@ OSSL_PKEY_BN_DEF2(dh, DH, key, pub_key, priv_key)
void
Init_ossl_dh(void)
{
-#if 0
- mPKey = rb_define_module_under(mOSSL, "PKey");
- cPKey = rb_define_class_under(mPKey, "PKey", rb_cObject);
- ePKeyError = rb_define_class_under(mPKey, "PKeyError", eOSSLError);
-#endif
-
- /* Document-class: OpenSSL::PKey::DHError
- *
- * Generic exception that is raised if an operation on a DH PKey
- * fails unexpectedly or in case an instantiation of an instance of DH
- * fails due to non-conformant input data.
- */
- eDHError = rb_define_class_under(mPKey, "DHError", ePKeyError);
/* Document-class: OpenSSL::PKey::DH
*
* An implementation of the Diffie-Hellman key exchange protocol based on
diff --git a/ext/openssl/ossl_pkey_dsa.c b/ext/openssl/ossl_pkey_dsa.c
index 9f4f012cfe..041646a058 100644
--- a/ext/openssl/ossl_pkey_dsa.c
+++ b/ext/openssl/ossl_pkey_dsa.c
@@ -14,13 +14,15 @@
#define GetPKeyDSA(obj, pkey) do { \
GetPKey((obj), (pkey)); \
if (EVP_PKEY_base_id(pkey) != EVP_PKEY_DSA) { /* PARANOIA? */ \
- ossl_raise(rb_eRuntimeError, "THIS IS NOT A DSA!"); \
+ ossl_raise(rb_eRuntimeError, "THIS IS NOT A DSA!"); \
} \
} while (0)
#define GetDSA(obj, dsa) do { \
EVP_PKEY *_pkey; \
GetPKeyDSA((obj), _pkey); \
(dsa) = EVP_PKEY_get0_DSA(_pkey); \
+ if ((dsa) == NULL) \
+ ossl_raise(ePKeyError, "failed to get DSA from EVP_PKEY"); \
} while (0)
static inline int
@@ -41,7 +43,6 @@ DSA_PRIVATE(VALUE obj, OSSL_3_const DSA *dsa)
* Classes
*/
VALUE cDSA;
-static VALUE eDSAError;
/*
* Private
@@ -56,6 +57,7 @@ static VALUE eDSAError;
*
* If called without arguments, creates a new instance with no key components
* set. They can be set individually by #set_pqg and #set_key.
+ * This form is not compatible with OpenSSL 3.0 or later.
*
* If called with a String, tries to parse as DER or PEM encoding of a \DSA key.
* See also OpenSSL::PKey.read which can parse keys of any kinds.
@@ -96,10 +98,15 @@ ossl_dsa_initialize(int argc, VALUE *argv, VALUE self)
/* The DSA.new(size, generator) form is handled by lib/openssl/pkey.rb */
rb_scan_args(argc, argv, "02", &arg, &pass);
if (argc == 0) {
+#ifdef OSSL_HAVE_IMMUTABLE_PKEY
+ rb_raise(rb_eArgError, "OpenSSL::PKey::DSA.new cannot be called " \
+ "without arguments; pkeys are immutable with OpenSSL 3.0");
+#else
dsa = DSA_new();
if (!dsa)
- ossl_raise(eDSAError, "DSA_new");
+ ossl_raise(ePKeyError, "DSA_new");
goto legacy;
+#endif
}
pass = ossl_pem_passwd_value(pass);
@@ -117,12 +124,12 @@ ossl_dsa_initialize(int argc, VALUE *argv, VALUE self)
pkey = ossl_pkey_read_generic(in, pass);
BIO_free(in);
if (!pkey)
- ossl_raise(eDSAError, "Neither PUB key nor PRIV key");
+ ossl_raise(ePKeyError, "Neither PUB key nor PRIV key");
type = EVP_PKEY_base_id(pkey);
if (type != EVP_PKEY_DSA) {
EVP_PKEY_free(pkey);
- rb_raise(eDSAError, "incorrect pkey type: %s", OBJ_nid2sn(type));
+ rb_raise(ePKeyError, "incorrect pkey type: %s", OBJ_nid2sn(type));
}
RTYPEDDATA_DATA(self) = pkey;
return self;
@@ -133,7 +140,7 @@ ossl_dsa_initialize(int argc, VALUE *argv, VALUE self)
if (!pkey || EVP_PKEY_assign_DSA(pkey, dsa) != 1) {
EVP_PKEY_free(pkey);
DSA_free(dsa);
- ossl_raise(eDSAError, "EVP_PKEY_assign_DSA");
+ ossl_raise(ePKeyError, "EVP_PKEY_assign_DSA");
}
RTYPEDDATA_DATA(self) = pkey;
return self;
@@ -156,13 +163,13 @@ ossl_dsa_initialize_copy(VALUE self, VALUE other)
(d2i_of_void *)d2i_DSAPrivateKey,
(char *)dsa);
if (!dsa_new)
- ossl_raise(eDSAError, "ASN1_dup");
+ ossl_raise(ePKeyError, "ASN1_dup");
pkey = EVP_PKEY_new();
if (!pkey || EVP_PKEY_assign_DSA(pkey, dsa_new) != 1) {
EVP_PKEY_free(pkey);
DSA_free(dsa_new);
- ossl_raise(eDSAError, "EVP_PKEY_assign_DSA");
+ ossl_raise(ePKeyError, "EVP_PKEY_assign_DSA");
}
RTYPEDDATA_DATA(self) = pkey;
@@ -327,20 +334,6 @@ OSSL_PKEY_BN_DEF2(dsa, DSA, key, pub_key, priv_key)
void
Init_ossl_dsa(void)
{
-#if 0
- mPKey = rb_define_module_under(mOSSL, "PKey");
- cPKey = rb_define_class_under(mPKey, "PKey", rb_cObject);
- ePKeyError = rb_define_class_under(mPKey, "PKeyError", eOSSLError);
-#endif
-
- /* Document-class: OpenSSL::PKey::DSAError
- *
- * Generic exception that is raised if an operation on a DSA PKey
- * fails unexpectedly or in case an instantiation of an instance of DSA
- * fails due to non-conformant input data.
- */
- eDSAError = rb_define_class_under(mPKey, "DSAError", ePKeyError);
-
/* Document-class: OpenSSL::PKey::DSA
*
* DSA, the Digital Signature Algorithm, is specified in NIST's
diff --git a/ext/openssl/ossl_pkey_ec.c b/ext/openssl/ossl_pkey_ec.c
index 1d20f63e0c..35f031819d 100644
--- a/ext/openssl/ossl_pkey_ec.c
+++ b/ext/openssl/ossl_pkey_ec.c
@@ -15,25 +15,27 @@ static const rb_data_type_t ossl_ec_point_type;
#define GetPKeyEC(obj, pkey) do { \
GetPKey((obj), (pkey)); \
if (EVP_PKEY_base_id(pkey) != EVP_PKEY_EC) { \
- ossl_raise(rb_eRuntimeError, "THIS IS NOT A EC PKEY!"); \
+ ossl_raise(rb_eRuntimeError, "THIS IS NOT A EC PKEY!"); \
} \
} while (0)
#define GetEC(obj, key) do { \
EVP_PKEY *_pkey; \
GetPKeyEC(obj, _pkey); \
(key) = EVP_PKEY_get0_EC_KEY(_pkey); \
+ if ((key) == NULL) \
+ ossl_raise(ePKeyError, "failed to get EC_KEY from EVP_PKEY"); \
} while (0)
#define GetECGroup(obj, group) do { \
TypedData_Get_Struct(obj, EC_GROUP, &ossl_ec_group_type, group); \
if ((group) == NULL) \
- ossl_raise(eEC_GROUP, "EC_GROUP is not initialized"); \
+ ossl_raise(eEC_GROUP, "EC_GROUP is not initialized"); \
} while (0)
#define GetECPoint(obj, point) do { \
TypedData_Get_Struct(obj, EC_POINT, &ossl_ec_point_type, point); \
if ((point) == NULL) \
- ossl_raise(eEC_POINT, "EC_POINT is not initialized"); \
+ ossl_raise(eEC_POINT, "EC_POINT is not initialized"); \
} while (0)
#define GetECPointGroup(obj, group) do { \
VALUE _group = rb_attr_get(obj, id_i_group); \
@@ -41,7 +43,6 @@ static const rb_data_type_t ossl_ec_point_type;
} while (0)
VALUE cEC;
-static VALUE eECError;
static VALUE cEC_GROUP;
static VALUE eEC_GROUP;
static VALUE cEC_POINT;
@@ -65,27 +66,27 @@ ec_key_new_from_group(VALUE arg)
EC_KEY *ec;
if (rb_obj_is_kind_of(arg, cEC_GROUP)) {
- EC_GROUP *group;
+ EC_GROUP *group;
- GetECGroup(arg, group);
- if (!(ec = EC_KEY_new()))
- ossl_raise(eECError, NULL);
+ GetECGroup(arg, group);
+ if (!(ec = EC_KEY_new()))
+ ossl_raise(ePKeyError, NULL);
- if (!EC_KEY_set_group(ec, group)) {
- EC_KEY_free(ec);
- ossl_raise(eECError, NULL);
- }
+ if (!EC_KEY_set_group(ec, group)) {
+ EC_KEY_free(ec);
+ ossl_raise(ePKeyError, NULL);
+ }
} else {
- int nid = OBJ_sn2nid(StringValueCStr(arg));
+ int nid = OBJ_sn2nid(StringValueCStr(arg));
- if (nid == NID_undef)
- ossl_raise(eECError, "invalid curve name");
+ if (nid == NID_undef)
+ ossl_raise(ePKeyError, "invalid curve name");
- if (!(ec = EC_KEY_new_by_curve_name(nid)))
- ossl_raise(eECError, NULL);
+ if (!(ec = EC_KEY_new_by_curve_name(nid)))
+ ossl_raise(ePKeyError, NULL);
- EC_KEY_set_asn1_flag(ec, OPENSSL_EC_NAMED_CURVE);
- EC_KEY_set_conv_form(ec, POINT_CONVERSION_UNCOMPRESSED);
+ EC_KEY_set_asn1_flag(ec, OPENSSL_EC_NAMED_CURVE);
+ EC_KEY_set_conv_form(ec, POINT_CONVERSION_UNCOMPRESSED);
}
return ec;
@@ -112,12 +113,12 @@ ossl_ec_key_s_generate(VALUE klass, VALUE arg)
if (!pkey || EVP_PKEY_assign_EC_KEY(pkey, ec) != 1) {
EVP_PKEY_free(pkey);
EC_KEY_free(ec);
- ossl_raise(eECError, "EVP_PKEY_assign_EC_KEY");
+ ossl_raise(ePKeyError, "EVP_PKEY_assign_EC_KEY");
}
RTYPEDDATA_DATA(obj) = pkey;
if (!EC_KEY_generate_key(ec))
- ossl_raise(eECError, "EC_KEY_generate_key");
+ ossl_raise(ePKeyError, "EC_KEY_generate_key");
return obj;
}
@@ -147,9 +148,14 @@ static VALUE ossl_ec_key_initialize(int argc, VALUE *argv, VALUE self)
rb_scan_args(argc, argv, "02", &arg, &pass);
if (NIL_P(arg)) {
+#ifdef OSSL_HAVE_IMMUTABLE_PKEY
+ rb_raise(rb_eArgError, "OpenSSL::PKey::EC.new cannot be called " \
+ "without arguments; pkeys are immutable with OpenSSL 3.0");
+#else
if (!(ec = EC_KEY_new()))
- ossl_raise(eECError, "EC_KEY_new");
+ ossl_raise(ePKeyError, "EC_KEY_new");
goto legacy;
+#endif
}
else if (rb_obj_is_kind_of(arg, cEC_GROUP)) {
ec = ec_key_new_from_group(arg);
@@ -171,7 +177,7 @@ static VALUE ossl_ec_key_initialize(int argc, VALUE *argv, VALUE self)
type = EVP_PKEY_base_id(pkey);
if (type != EVP_PKEY_EC) {
EVP_PKEY_free(pkey);
- rb_raise(eECError, "incorrect pkey type: %s", OBJ_nid2sn(type));
+ rb_raise(ePKeyError, "incorrect pkey type: %s", OBJ_nid2sn(type));
}
RTYPEDDATA_DATA(self) = pkey;
return self;
@@ -181,7 +187,7 @@ static VALUE ossl_ec_key_initialize(int argc, VALUE *argv, VALUE self)
if (!pkey || EVP_PKEY_assign_EC_KEY(pkey, ec) != 1) {
EVP_PKEY_free(pkey);
EC_KEY_free(ec);
- ossl_raise(eECError, "EVP_PKEY_assign_EC_KEY");
+ ossl_raise(ePKeyError, "EVP_PKEY_assign_EC_KEY");
}
RTYPEDDATA_DATA(self) = pkey;
return self;
@@ -202,12 +208,12 @@ ossl_ec_key_initialize_copy(VALUE self, VALUE other)
ec_new = EC_KEY_dup(ec);
if (!ec_new)
- ossl_raise(eECError, "EC_KEY_dup");
+ ossl_raise(ePKeyError, "EC_KEY_dup");
pkey = EVP_PKEY_new();
if (!pkey || EVP_PKEY_assign_EC_KEY(pkey, ec_new) != 1) {
EC_KEY_free(ec_new);
- ossl_raise(eECError, "EVP_PKEY_assign_EC_KEY");
+ ossl_raise(ePKeyError, "EVP_PKEY_assign_EC_KEY");
}
RTYPEDDATA_DATA(self) = pkey;
@@ -231,7 +237,7 @@ ossl_ec_key_get_group(VALUE self)
GetEC(self, ec);
group = EC_KEY_get0_group(ec);
if (!group)
- return Qnil;
+ return Qnil;
return ec_group_new(group);
}
@@ -246,7 +252,7 @@ ossl_ec_key_get_group(VALUE self)
static VALUE
ossl_ec_key_set_group(VALUE self, VALUE group_v)
{
-#if OSSL_OPENSSL_PREREQ(3, 0, 0)
+#ifdef OSSL_HAVE_IMMUTABLE_PKEY
rb_raise(ePKeyError, "pkeys are immutable on OpenSSL 3.0");
#else
EC_KEY *ec;
@@ -256,7 +262,7 @@ ossl_ec_key_set_group(VALUE self, VALUE group_v)
GetECGroup(group_v, group);
if (EC_KEY_set_group(ec, group) != 1)
- ossl_raise(eECError, "EC_KEY_set_group");
+ ossl_raise(ePKeyError, "EC_KEY_set_group");
return group_v;
#endif
@@ -288,7 +294,7 @@ static VALUE ossl_ec_key_get_private_key(VALUE self)
*/
static VALUE ossl_ec_key_set_private_key(VALUE self, VALUE private_key)
{
-#if OSSL_OPENSSL_PREREQ(3, 0, 0)
+#ifdef OSSL_HAVE_IMMUTABLE_PKEY
rb_raise(ePKeyError, "pkeys are immutable on OpenSSL 3.0");
#else
EC_KEY *ec;
@@ -299,14 +305,14 @@ static VALUE ossl_ec_key_set_private_key(VALUE self, VALUE private_key)
bn = GetBNPtr(private_key);
switch (EC_KEY_set_private_key(ec, bn)) {
- case 1:
+ case 1:
break;
- case 0:
+ case 0:
if (bn == NULL)
break;
- /* fallthrough */
- default:
- ossl_raise(eECError, "EC_KEY_set_private_key");
+ /* fallthrough */
+ default:
+ ossl_raise(ePKeyError, "EC_KEY_set_private_key");
}
return private_key;
@@ -339,7 +345,7 @@ static VALUE ossl_ec_key_get_public_key(VALUE self)
*/
static VALUE ossl_ec_key_set_public_key(VALUE self, VALUE public_key)
{
-#if OSSL_OPENSSL_PREREQ(3, 0, 0)
+#ifdef OSSL_HAVE_IMMUTABLE_PKEY
rb_raise(ePKeyError, "pkeys are immutable on OpenSSL 3.0");
#else
EC_KEY *ec;
@@ -350,14 +356,14 @@ static VALUE ossl_ec_key_set_public_key(VALUE self, VALUE public_key)
GetECPoint(public_key, point);
switch (EC_KEY_set_public_key(ec, point)) {
- case 1:
+ case 1:
break;
- case 0:
+ case 0:
if (point == NULL)
break;
- /* fallthrough */
- default:
- ossl_raise(eECError, "EC_KEY_set_public_key");
+ /* fallthrough */
+ default:
+ ossl_raise(ePKeyError, "EC_KEY_set_public_key");
}
return public_key;
@@ -461,7 +467,7 @@ ossl_ec_key_export(int argc, VALUE *argv, VALUE self)
GetEC(self, ec);
if (EC_KEY_get0_public_key(ec) == NULL)
- ossl_raise(eECError, "can't export - no public key set");
+ ossl_raise(ePKeyError, "can't export - no public key set");
if (EC_KEY_get0_private_key(ec))
return ossl_pkey_export_traditional(argc, argv, self, 0);
else
@@ -489,7 +495,7 @@ ossl_ec_key_to_der(VALUE self)
GetEC(self, ec);
if (EC_KEY_get0_public_key(ec) == NULL)
- ossl_raise(eECError, "can't export - no public key set");
+ ossl_raise(ePKeyError, "can't export - no public key set");
if (EC_KEY_get0_private_key(ec))
return ossl_pkey_export_traditional(0, NULL, self, 1);
else
@@ -511,14 +517,14 @@ ossl_ec_key_to_der(VALUE self)
*/
static VALUE ossl_ec_key_generate_key(VALUE self)
{
-#if OSSL_OPENSSL_PREREQ(3, 0, 0)
+#ifdef OSSL_HAVE_IMMUTABLE_PKEY
rb_raise(ePKeyError, "pkeys are immutable on OpenSSL 3.0");
#else
EC_KEY *ec;
GetEC(self, ec);
if (EC_KEY_generate_key(ec) != 1)
- ossl_raise(eECError, "EC_KEY_generate_key");
+ ossl_raise(ePKeyError, "EC_KEY_generate_key");
return self;
#endif
@@ -543,18 +549,18 @@ static VALUE ossl_ec_key_check_key(VALUE self)
GetEC(self, ec);
pctx = EVP_PKEY_CTX_new(pkey, /* engine */NULL);
if (!pctx)
- ossl_raise(eECError, "EVP_PKEY_CTX_new");
+ ossl_raise(ePKeyError, "EVP_PKEY_CTX_new");
if (EC_KEY_get0_private_key(ec) != NULL) {
if (EVP_PKEY_check(pctx) != 1) {
EVP_PKEY_CTX_free(pctx);
- ossl_raise(eECError, "EVP_PKEY_check");
+ ossl_raise(ePKeyError, "EVP_PKEY_check");
}
}
else {
if (EVP_PKEY_public_check(pctx) != 1) {
EVP_PKEY_CTX_free(pctx);
- ossl_raise(eECError, "EVP_PKEY_public_check");
+ ossl_raise(ePKeyError, "EVP_PKEY_public_check");
}
}
@@ -564,7 +570,7 @@ static VALUE ossl_ec_key_check_key(VALUE self)
GetEC(self, ec);
if (EC_KEY_check_key(ec) != 1)
- ossl_raise(eECError, "EC_KEY_check_key");
+ ossl_raise(ePKeyError, "EC_KEY_check_key");
#endif
return Qtrue;
@@ -582,7 +588,7 @@ ossl_ec_group_free(void *ptr)
static const rb_data_type_t ossl_ec_group_type = {
"OpenSSL/ec_group",
{
- 0, ossl_ec_group_free,
+ 0, ossl_ec_group_free,
},
0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
};
@@ -602,7 +608,7 @@ ec_group_new(const EC_GROUP *group)
obj = ossl_ec_group_alloc(cEC_GROUP);
group_new = EC_GROUP_dup(group);
if (!group_new)
- ossl_raise(eEC_GROUP, "EC_GROUP_dup");
+ ossl_raise(eEC_GROUP, "EC_GROUP_dup");
RTYPEDDATA_DATA(obj) = group_new;
return obj;
@@ -630,7 +636,7 @@ static VALUE ossl_ec_group_initialize(int argc, VALUE *argv, VALUE self)
ossl_raise(rb_eRuntimeError, "EC_GROUP is already initialized");
switch (rb_scan_args(argc, argv, "13", &arg1, &arg2, &arg3, &arg4)) {
- case 1:
+ case 1:
if (rb_obj_is_kind_of(arg1, cEC_GROUP)) {
const EC_GROUP *arg1_group;
@@ -642,7 +648,7 @@ static VALUE ossl_ec_group_initialize(int argc, VALUE *argv, VALUE self)
group = PEM_read_bio_ECPKParameters(in, NULL, NULL, NULL);
if (!group) {
- OSSL_BIO_reset(in);
+ OSSL_BIO_reset(in);
group = d2i_ECPKParameters_bio(in, NULL);
}
@@ -652,7 +658,7 @@ static VALUE ossl_ec_group_initialize(int argc, VALUE *argv, VALUE self)
const char *name = StringValueCStr(arg1);
int nid = OBJ_sn2nid(name);
- ossl_clear_error(); /* ignore errors in d2i_ECPKParameters_bio() */
+ ossl_clear_error(); /* ignore errors in d2i_ECPKParameters_bio() */
if (nid == NID_undef)
ossl_raise(eEC_GROUP, "unknown curve name (%"PRIsVALUE")", arg1);
#if !defined(OPENSSL_IS_AWSLC)
@@ -669,7 +675,7 @@ static VALUE ossl_ec_group_initialize(int argc, VALUE *argv, VALUE self)
}
break;
- case 4:
+ case 4:
if (SYMBOL_P(arg1)) {
EC_GROUP *(*new_curve)(const BIGNUM *, const BIGNUM *, const BIGNUM *, BN_CTX *) = NULL;
const BIGNUM *p = GetBNPtr(arg2);
@@ -691,12 +697,12 @@ static VALUE ossl_ec_group_initialize(int argc, VALUE *argv, VALUE self)
if ((group = new_curve(p, a, b, ossl_bn_ctx)) == NULL)
ossl_raise(eEC_GROUP, "EC_GROUP_new_by_GF*");
} else {
- ossl_raise(rb_eArgError, "unknown argument, must be :GFp or :GF2m");
+ ossl_raise(rb_eArgError, "unknown argument, must be :GFp or :GF2m");
}
break;
- default:
- ossl_raise(rb_eArgError, "wrong number of arguments");
+ default:
+ ossl_raise(rb_eArgError, "wrong number of arguments (given %d, expected 1 or 4)", argc);
}
ASSUME(group);
@@ -713,12 +719,12 @@ ossl_ec_group_initialize_copy(VALUE self, VALUE other)
TypedData_Get_Struct(self, EC_GROUP, &ossl_ec_group_type, group_new);
if (group_new)
- ossl_raise(eEC_GROUP, "EC::Group already initialized");
+ ossl_raise(eEC_GROUP, "EC::Group already initialized");
GetECGroup(other, group);
group_new = EC_GROUP_dup(group);
if (!group_new)
- ossl_raise(eEC_GROUP, "EC_GROUP_dup");
+ ossl_raise(eEC_GROUP, "EC_GROUP_dup");
RTYPEDDATA_DATA(self) = group_new;
return self;
@@ -740,9 +746,9 @@ static VALUE ossl_ec_group_eql(VALUE a, VALUE b)
GetECGroup(b, group2);
switch (EC_GROUP_cmp(group1, group2, ossl_bn_ctx)) {
- case 0: return Qtrue;
- case 1: return Qfalse;
- default: ossl_raise(eEC_GROUP, "EC_GROUP_cmp");
+ case 0: return Qtrue;
+ case 1: return Qfalse;
+ default: ossl_raise(eEC_GROUP, "EC_GROUP_cmp");
}
}
@@ -762,7 +768,7 @@ static VALUE ossl_ec_group_get_generator(VALUE self)
GetECGroup(self, group);
generator = EC_GROUP_get0_generator(group);
if (!generator)
- return Qnil;
+ return Qnil;
return ec_point_new(generator, group);
}
@@ -843,25 +849,23 @@ static VALUE ossl_ec_group_get_cofactor(VALUE self)
/*
* call-seq:
- * group.curve_name => String
+ * group.curve_name -> string or nil
*
- * Returns the curve name (sn).
+ * Returns the curve name (short name) corresponding to this group, or +nil+
+ * if \OpenSSL does not have an OID associated with the group.
*
* See the OpenSSL documentation for EC_GROUP_get_curve_name()
*/
static VALUE ossl_ec_group_get_curve_name(VALUE self)
{
- EC_GROUP *group = NULL;
+ EC_GROUP *group;
int nid;
GetECGroup(self, group);
- if (group == NULL)
- return Qnil;
-
nid = EC_GROUP_get_curve_name(group);
-
-/* BUG: an nid or asn1 object should be returned, maybe. */
- return rb_str_new2(OBJ_nid2sn(nid));
+ if (nid == NID_undef)
+ return Qnil;
+ return rb_str_new_cstr(OBJ_nid2sn(nid));
}
/*
@@ -977,11 +981,11 @@ static point_conversion_form_t
parse_point_conversion_form_symbol(VALUE sym)
{
if (sym == sym_uncompressed)
- return POINT_CONVERSION_UNCOMPRESSED;
+ return POINT_CONVERSION_UNCOMPRESSED;
if (sym == sym_compressed)
- return POINT_CONVERSION_COMPRESSED;
+ return POINT_CONVERSION_COMPRESSED;
if (sym == sym_hybrid)
- return POINT_CONVERSION_HYBRID;
+ return POINT_CONVERSION_HYBRID;
ossl_raise(rb_eArgError, "unsupported point conversion form %+"PRIsVALUE
" (expected :compressed, :uncompressed, or :hybrid)", sym);
}
@@ -1088,20 +1092,20 @@ static VALUE ossl_ec_group_to_string(VALUE self, int format)
ossl_raise(eEC_GROUP, "BIO_new(BIO_s_mem())");
switch(format) {
- case EXPORT_PEM:
+ case EXPORT_PEM:
i = PEM_write_bio_ECPKParameters(out, group);
- break;
- case EXPORT_DER:
+ break;
+ case EXPORT_DER:
i = i2d_ECPKParameters_bio(out, group);
- break;
- default:
+ break;
+ default:
BIO_free(out);
- ossl_raise(rb_eRuntimeError, "unknown format (internal error)");
+ ossl_raise(rb_eRuntimeError, "unknown format (internal error)");
}
if (i != 1) {
BIO_free(out);
- ossl_raise(eECError, NULL);
+ ossl_raise(ePKeyError, NULL);
}
str = ossl_membio2str(out);
@@ -1145,11 +1149,11 @@ static VALUE ossl_ec_group_to_text(VALUE self)
GetECGroup(self, group);
if (!(out = BIO_new(BIO_s_mem()))) {
- ossl_raise(eEC_GROUP, "BIO_new(BIO_s_mem())");
+ ossl_raise(eEC_GROUP, "BIO_new(BIO_s_mem())");
}
if (!ECPKParameters_print(out, group, 0)) {
- BIO_free(out);
- ossl_raise(eEC_GROUP, NULL);
+ BIO_free(out);
+ ossl_raise(eEC_GROUP, NULL);
}
str = ossl_membio2str(out);
@@ -1169,7 +1173,7 @@ ossl_ec_point_free(void *ptr)
static const rb_data_type_t ossl_ec_point_type = {
"OpenSSL/EC_POINT",
{
- 0, ossl_ec_point_free,
+ 0, ossl_ec_point_free,
},
0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
};
@@ -1189,7 +1193,7 @@ ec_point_new(const EC_POINT *point, const EC_GROUP *group)
obj = ossl_ec_point_alloc(cEC_POINT);
point_new = EC_POINT_dup(point, group);
if (!point_new)
- ossl_raise(eEC_POINT, "EC_POINT_dup");
+ ossl_raise(eEC_POINT, "EC_POINT_dup");
RTYPEDDATA_DATA(obj) = point_new;
rb_ivar_set(obj, id_i_group, ec_group_new(group));
@@ -1217,39 +1221,39 @@ static VALUE ossl_ec_point_initialize(int argc, VALUE *argv, VALUE self)
TypedData_Get_Struct(self, EC_POINT, &ossl_ec_point_type, point);
if (point)
- rb_raise(eEC_POINT, "EC_POINT already initialized");
+ rb_raise(eEC_POINT, "EC_POINT already initialized");
rb_scan_args(argc, argv, "11", &group_v, &arg2);
if (rb_obj_is_kind_of(group_v, cEC_POINT)) {
- if (argc != 1)
- rb_raise(rb_eArgError, "invalid second argument");
- return ossl_ec_point_initialize_copy(self, group_v);
+ if (argc != 1)
+ rb_raise(rb_eArgError, "invalid second argument");
+ return ossl_ec_point_initialize_copy(self, group_v);
}
GetECGroup(group_v, group);
if (argc == 1) {
- point = EC_POINT_new(group);
- if (!point)
- ossl_raise(eEC_POINT, "EC_POINT_new");
+ point = EC_POINT_new(group);
+ if (!point)
+ ossl_raise(eEC_POINT, "EC_POINT_new");
}
else {
- if (rb_obj_is_kind_of(arg2, cBN)) {
- point = EC_POINT_bn2point(group, GetBNPtr(arg2), NULL, ossl_bn_ctx);
- if (!point)
- ossl_raise(eEC_POINT, "EC_POINT_bn2point");
- }
- else {
- StringValue(arg2);
- point = EC_POINT_new(group);
- if (!point)
- ossl_raise(eEC_POINT, "EC_POINT_new");
- if (!EC_POINT_oct2point(group, point,
- (unsigned char *)RSTRING_PTR(arg2),
- RSTRING_LEN(arg2), ossl_bn_ctx)) {
- EC_POINT_free(point);
- ossl_raise(eEC_POINT, "EC_POINT_oct2point");
- }
- }
+ if (rb_obj_is_kind_of(arg2, cBN)) {
+ point = EC_POINT_bn2point(group, GetBNPtr(arg2), NULL, ossl_bn_ctx);
+ if (!point)
+ ossl_raise(eEC_POINT, "EC_POINT_bn2point");
+ }
+ else {
+ StringValue(arg2);
+ point = EC_POINT_new(group);
+ if (!point)
+ ossl_raise(eEC_POINT, "EC_POINT_new");
+ if (!EC_POINT_oct2point(group, point,
+ (unsigned char *)RSTRING_PTR(arg2),
+ RSTRING_LEN(arg2), ossl_bn_ctx)) {
+ EC_POINT_free(point);
+ ossl_raise(eEC_POINT, "EC_POINT_oct2point");
+ }
+ }
}
RTYPEDDATA_DATA(self) = point;
@@ -1268,7 +1272,7 @@ ossl_ec_point_initialize_copy(VALUE self, VALUE other)
TypedData_Get_Struct(self, EC_POINT, &ossl_ec_point_type, point_new);
if (point_new)
- ossl_raise(eEC_POINT, "EC::Point already initialized");
+ ossl_raise(eEC_POINT, "EC::Point already initialized");
GetECPoint(other, point);
group_v = rb_obj_dup(rb_attr_get(other, id_i_group));
@@ -1276,7 +1280,7 @@ ossl_ec_point_initialize_copy(VALUE self, VALUE other)
point_new = EC_POINT_dup(point, group);
if (!point_new)
- ossl_raise(eEC_POINT, "EC_POINT_dup");
+ ossl_raise(eEC_POINT, "EC_POINT_dup");
RTYPEDDATA_DATA(self) = point_new;
rb_ivar_set(self, id_i_group, group_v);
@@ -1303,9 +1307,9 @@ static VALUE ossl_ec_point_eql(VALUE a, VALUE b)
GetECGroup(group_v1, group);
switch (EC_POINT_cmp(group, point1, point2, ossl_bn_ctx)) {
- case 0: return Qtrue;
- case 1: return Qfalse;
- default: ossl_raise(eEC_POINT, "EC_POINT_cmp");
+ case 0: return Qtrue;
+ case 1: return Qfalse;
+ default: ossl_raise(eEC_POINT, "EC_POINT_cmp");
}
UNREACHABLE;
@@ -1324,9 +1328,9 @@ static VALUE ossl_ec_point_is_at_infinity(VALUE self)
GetECPointGroup(self, group);
switch (EC_POINT_is_at_infinity(group, point)) {
- case 1: return Qtrue;
- case 0: return Qfalse;
- default: ossl_raise(eEC_POINT, "EC_POINT_is_at_infinity");
+ case 1: return Qtrue;
+ case 0: return Qfalse;
+ default: ossl_raise(eEC_POINT, "EC_POINT_is_at_infinity");
}
UNREACHABLE;
@@ -1345,9 +1349,9 @@ static VALUE ossl_ec_point_is_on_curve(VALUE self)
GetECPointGroup(self, group);
switch (EC_POINT_is_on_curve(group, point, ossl_bn_ctx)) {
- case 1: return Qtrue;
- case 0: return Qfalse;
- default: ossl_raise(eEC_POINT, "EC_POINT_is_on_curve");
+ case 1: return Qtrue;
+ case 0: return Qfalse;
+ default: ossl_raise(eEC_POINT, "EC_POINT_is_on_curve");
}
UNREACHABLE;
@@ -1368,7 +1372,7 @@ static VALUE ossl_ec_point_make_affine(VALUE self)
GetECPointGroup(self, group);
rb_warn("OpenSSL::PKey::EC::Point#make_affine! is deprecated");
-#if !OSSL_OPENSSL_PREREQ(3, 0, 0) && !defined(OPENSSL_IS_AWSLC)
+#if !defined(OSSL_HAVE_IMMUTABLE_PKEY) && !defined(OPENSSL_IS_AWSLC)
if (EC_POINT_make_affine(group, point, ossl_bn_ctx) != 1)
ossl_raise(eEC_POINT, "EC_POINT_make_affine");
#endif
@@ -1439,12 +1443,12 @@ ossl_ec_point_to_octet_string(VALUE self, VALUE conversion_form)
len = EC_POINT_point2oct(group, point, form, NULL, 0, ossl_bn_ctx);
if (!len)
- ossl_raise(eEC_POINT, "EC_POINT_point2oct");
+ ossl_raise(eEC_POINT, "EC_POINT_point2oct");
str = rb_str_new(NULL, (long)len);
if (!EC_POINT_point2oct(group, point, form,
- (unsigned char *)RSTRING_PTR(str), len,
- ossl_bn_ctx))
- ossl_raise(eEC_POINT, "EC_POINT_point2oct");
+ (unsigned char *)RSTRING_PTR(str), len,
+ ossl_bn_ctx))
+ ossl_raise(eEC_POINT, "EC_POINT_point2oct");
return str;
}
@@ -1522,15 +1526,6 @@ static VALUE ossl_ec_point_mul(int argc, VALUE *argv, VALUE self)
void Init_ossl_ec(void)
{
#undef rb_intern
-#if 0
- mPKey = rb_define_module_under(mOSSL, "PKey");
- cPKey = rb_define_class_under(mPKey, "PKey", rb_cObject);
- eOSSLError = rb_define_class_under(mOSSL, "OpenSSLError", rb_eStandardError);
- ePKeyError = rb_define_class_under(mPKey, "PKeyError", eOSSLError);
-#endif
-
- eECError = rb_define_class_under(mPKey, "ECError", ePKeyError);
-
/*
* Document-class: OpenSSL::PKey::EC
*
diff --git a/ext/openssl/ossl_pkey_rsa.c b/ext/openssl/ossl_pkey_rsa.c
index 185b47cbfb..039b2c6a34 100644
--- a/ext/openssl/ossl_pkey_rsa.c
+++ b/ext/openssl/ossl_pkey_rsa.c
@@ -14,13 +14,15 @@
#define GetPKeyRSA(obj, pkey) do { \
GetPKey((obj), (pkey)); \
if (EVP_PKEY_base_id(pkey) != EVP_PKEY_RSA) { /* PARANOIA? */ \
- ossl_raise(rb_eRuntimeError, "THIS IS NOT A RSA!") ; \
+ ossl_raise(rb_eRuntimeError, "THIS IS NOT A RSA!") ; \
} \
} while (0)
#define GetRSA(obj, rsa) do { \
EVP_PKEY *_pkey; \
GetPKeyRSA((obj), _pkey); \
(rsa) = EVP_PKEY_get0_RSA(_pkey); \
+ if ((rsa) == NULL) \
+ ossl_raise(ePKeyError, "failed to get RSA from EVP_PKEY"); \
} while (0)
static inline int
@@ -42,7 +44,6 @@ RSA_PRIVATE(VALUE obj, OSSL_3_const RSA *rsa)
* Classes
*/
VALUE cRSA;
-static VALUE eRSAError;
/*
* Private
@@ -59,6 +60,7 @@ static VALUE eRSAError;
* If called without arguments, creates a new instance with no key components
* set. They can be set individually by #set_key, #set_factors, and
* #set_crt_params.
+ * This form is not compatible with OpenSSL 3.0 or later.
*
* 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
@@ -89,10 +91,15 @@ ossl_rsa_initialize(int argc, VALUE *argv, VALUE self)
/* The RSA.new(size, generator) form is handled by lib/openssl/pkey.rb */
rb_scan_args(argc, argv, "02", &arg, &pass);
if (argc == 0) {
- rsa = RSA_new();
+#ifdef OSSL_HAVE_IMMUTABLE_PKEY
+ rb_raise(rb_eArgError, "OpenSSL::PKey::RSA.new cannot be called " \
+ "without arguments; pkeys are immutable with OpenSSL 3.0");
+#else
+ rsa = RSA_new();
if (!rsa)
- ossl_raise(eRSAError, "RSA_new");
+ ossl_raise(ePKeyError, "RSA_new");
goto legacy;
+#endif
}
pass = ossl_pem_passwd_value(pass);
@@ -113,12 +120,12 @@ ossl_rsa_initialize(int argc, VALUE *argv, VALUE self)
pkey = ossl_pkey_read_generic(in, pass);
BIO_free(in);
if (!pkey)
- ossl_raise(eRSAError, "Neither PUB key nor PRIV key");
+ ossl_raise(ePKeyError, "Neither PUB key nor PRIV key");
type = EVP_PKEY_base_id(pkey);
if (type != EVP_PKEY_RSA) {
EVP_PKEY_free(pkey);
- rb_raise(eRSAError, "incorrect pkey type: %s", OBJ_nid2sn(type));
+ rb_raise(ePKeyError, "incorrect pkey type: %s", OBJ_nid2sn(type));
}
RTYPEDDATA_DATA(self) = pkey;
return self;
@@ -129,7 +136,7 @@ ossl_rsa_initialize(int argc, VALUE *argv, VALUE self)
if (!pkey || EVP_PKEY_assign_RSA(pkey, rsa) != 1) {
EVP_PKEY_free(pkey);
RSA_free(rsa);
- ossl_raise(eRSAError, "EVP_PKEY_assign_RSA");
+ ossl_raise(ePKeyError, "EVP_PKEY_assign_RSA");
}
RTYPEDDATA_DATA(self) = pkey;
return self;
@@ -152,12 +159,12 @@ ossl_rsa_initialize_copy(VALUE self, VALUE other)
(d2i_of_void *)d2i_RSAPrivateKey,
(char *)rsa);
if (!rsa_new)
- ossl_raise(eRSAError, "ASN1_dup");
+ ossl_raise(ePKeyError, "ASN1_dup");
pkey = EVP_PKEY_new();
if (!pkey || EVP_PKEY_assign_RSA(pkey, rsa_new) != 1) {
RSA_free(rsa_new);
- ossl_raise(eRSAError, "EVP_PKEY_assign_RSA");
+ ossl_raise(ePKeyError, "EVP_PKEY_assign_RSA");
}
RTYPEDDATA_DATA(self) = pkey;
@@ -312,7 +319,7 @@ ossl_rsa_to_der(VALUE self)
* Signs _data_ using the Probabilistic Signature Scheme (RSA-PSS) and returns
* the calculated signature.
*
- * RSAError will be raised if an error occurs.
+ * PKeyError will be raised if an error occurs.
*
* See #verify_pss for the verification operation.
*
@@ -341,7 +348,7 @@ ossl_rsa_to_der(VALUE self)
static VALUE
ossl_rsa_sign_pss(int argc, VALUE *argv, VALUE self)
{
- VALUE digest, data, options, kwargs[2], signature;
+ VALUE digest, data, options, kwargs[2], signature, mgf1md_holder, md_holder;
static ID kwargs_ids[2];
EVP_PKEY *pkey;
EVP_PKEY_CTX *pkey_ctx;
@@ -351,46 +358,46 @@ ossl_rsa_sign_pss(int argc, VALUE *argv, VALUE self)
int salt_len;
if (!kwargs_ids[0]) {
- kwargs_ids[0] = rb_intern_const("salt_length");
- kwargs_ids[1] = rb_intern_const("mgf1_hash");
+ kwargs_ids[0] = rb_intern_const("salt_length");
+ kwargs_ids[1] = rb_intern_const("mgf1_hash");
}
rb_scan_args(argc, argv, "2:", &digest, &data, &options);
rb_get_kwargs(options, kwargs_ids, 2, 0, kwargs);
if (kwargs[0] == ID2SYM(rb_intern("max")))
- salt_len = -2; /* RSA_PSS_SALTLEN_MAX_SIGN */
+ salt_len = -2; /* RSA_PSS_SALTLEN_MAX_SIGN */
else if (kwargs[0] == ID2SYM(rb_intern("digest")))
- salt_len = -1; /* RSA_PSS_SALTLEN_DIGEST */
+ salt_len = -1; /* RSA_PSS_SALTLEN_DIGEST */
else
- salt_len = NUM2INT(kwargs[0]);
- mgf1md = ossl_evp_get_digestbyname(kwargs[1]);
+ salt_len = NUM2INT(kwargs[0]);
+ mgf1md = ossl_evp_md_fetch(kwargs[1], &mgf1md_holder);
pkey = GetPrivPKeyPtr(self);
buf_len = EVP_PKEY_size(pkey);
- md = ossl_evp_get_digestbyname(digest);
+ md = ossl_evp_md_fetch(digest, &md_holder);
StringValue(data);
signature = rb_str_new(NULL, (long)buf_len);
md_ctx = EVP_MD_CTX_new();
if (!md_ctx)
- goto err;
+ goto err;
if (EVP_DigestSignInit(md_ctx, &pkey_ctx, md, NULL, pkey) != 1)
- goto err;
+ goto err;
if (EVP_PKEY_CTX_set_rsa_padding(pkey_ctx, RSA_PKCS1_PSS_PADDING) != 1)
- goto err;
+ goto err;
if (EVP_PKEY_CTX_set_rsa_pss_saltlen(pkey_ctx, salt_len) != 1)
- goto err;
+ goto err;
if (EVP_PKEY_CTX_set_rsa_mgf1_md(pkey_ctx, mgf1md) != 1)
- goto err;
+ goto err;
if (EVP_DigestSignUpdate(md_ctx, RSTRING_PTR(data), RSTRING_LEN(data)) != 1)
- goto err;
+ goto err;
if (EVP_DigestSignFinal(md_ctx, (unsigned char *)RSTRING_PTR(signature), &buf_len) != 1)
- goto err;
+ goto err;
rb_str_set_len(signature, (long)buf_len);
@@ -399,7 +406,7 @@ ossl_rsa_sign_pss(int argc, VALUE *argv, VALUE self)
err:
EVP_MD_CTX_free(md_ctx);
- ossl_raise(eRSAError, NULL);
+ ossl_raise(ePKeyError, NULL);
}
/*
@@ -409,7 +416,7 @@ ossl_rsa_sign_pss(int argc, VALUE *argv, VALUE self)
* Verifies _data_ using the Probabilistic Signature Scheme (RSA-PSS).
*
* The return value is +true+ if the signature is valid, +false+ otherwise.
- * RSAError will be raised if an error occurs.
+ * PKeyError will be raised if an error occurs.
*
* See #sign_pss for the signing operation and an example code.
*
@@ -428,7 +435,7 @@ ossl_rsa_sign_pss(int argc, VALUE *argv, VALUE self)
static VALUE
ossl_rsa_verify_pss(int argc, VALUE *argv, VALUE self)
{
- VALUE digest, signature, data, options, kwargs[2];
+ VALUE digest, signature, data, options, kwargs[2], mgf1md_holder, md_holder;
static ID kwargs_ids[2];
EVP_PKEY *pkey;
EVP_PKEY_CTX *pkey_ctx;
@@ -437,62 +444,61 @@ ossl_rsa_verify_pss(int argc, VALUE *argv, VALUE self)
int result, salt_len;
if (!kwargs_ids[0]) {
- kwargs_ids[0] = rb_intern_const("salt_length");
- kwargs_ids[1] = rb_intern_const("mgf1_hash");
+ kwargs_ids[0] = rb_intern_const("salt_length");
+ kwargs_ids[1] = rb_intern_const("mgf1_hash");
}
rb_scan_args(argc, argv, "3:", &digest, &signature, &data, &options);
rb_get_kwargs(options, kwargs_ids, 2, 0, kwargs);
if (kwargs[0] == ID2SYM(rb_intern("auto")))
- salt_len = -2; /* RSA_PSS_SALTLEN_AUTO */
+ salt_len = -2; /* RSA_PSS_SALTLEN_AUTO */
else if (kwargs[0] == ID2SYM(rb_intern("digest")))
- salt_len = -1; /* RSA_PSS_SALTLEN_DIGEST */
+ salt_len = -1; /* RSA_PSS_SALTLEN_DIGEST */
else
- salt_len = NUM2INT(kwargs[0]);
- mgf1md = ossl_evp_get_digestbyname(kwargs[1]);
+ salt_len = NUM2INT(kwargs[0]);
+ mgf1md = ossl_evp_md_fetch(kwargs[1], &mgf1md_holder);
GetPKey(self, pkey);
- md = ossl_evp_get_digestbyname(digest);
+ md = ossl_evp_md_fetch(digest, &md_holder);
StringValue(signature);
StringValue(data);
md_ctx = EVP_MD_CTX_new();
if (!md_ctx)
- goto err;
+ goto err;
if (EVP_DigestVerifyInit(md_ctx, &pkey_ctx, md, NULL, pkey) != 1)
- goto err;
+ goto err;
if (EVP_PKEY_CTX_set_rsa_padding(pkey_ctx, RSA_PKCS1_PSS_PADDING) != 1)
- goto err;
+ goto err;
if (EVP_PKEY_CTX_set_rsa_pss_saltlen(pkey_ctx, salt_len) != 1)
- goto err;
+ goto err;
if (EVP_PKEY_CTX_set_rsa_mgf1_md(pkey_ctx, mgf1md) != 1)
- goto err;
+ goto err;
if (EVP_DigestVerifyUpdate(md_ctx, RSTRING_PTR(data), RSTRING_LEN(data)) != 1)
- goto err;
+ goto err;
result = EVP_DigestVerifyFinal(md_ctx,
- (unsigned char *)RSTRING_PTR(signature),
- RSTRING_LEN(signature));
+ (unsigned char *)RSTRING_PTR(signature),
+ RSTRING_LEN(signature));
+ EVP_MD_CTX_free(md_ctx);
switch (result) {
case 0:
- ossl_clear_error();
- EVP_MD_CTX_free(md_ctx);
- return Qfalse;
+ ossl_clear_error();
+ return Qfalse;
case 1:
- EVP_MD_CTX_free(md_ctx);
- return Qtrue;
+ return Qtrue;
default:
- goto err;
+ ossl_raise(ePKeyError, "EVP_DigestVerifyFinal");
}
err:
EVP_MD_CTX_free(md_ctx);
- ossl_raise(eRSAError, NULL);
+ ossl_raise(ePKeyError, NULL);
}
/*
@@ -530,20 +536,6 @@ OSSL_PKEY_BN_DEF3(rsa, RSA, crt_params, dmp1, dmq1, iqmp)
void
Init_ossl_rsa(void)
{
-#if 0
- mPKey = rb_define_module_under(mOSSL, "PKey");
- cPKey = rb_define_class_under(mPKey, "PKey", rb_cObject);
- ePKeyError = rb_define_class_under(mPKey, "PKeyError", eOSSLError);
-#endif
-
- /* Document-class: OpenSSL::PKey::RSAError
- *
- * Generic exception that is raised if an operation on an RSA PKey
- * fails unexpectedly or in case an instantiation of an instance of RSA
- * fails due to non-conformant input data.
- */
- eRSAError = rb_define_class_under(mPKey, "RSAError", ePKeyError);
-
/* Document-class: OpenSSL::PKey::RSA
*
* RSA is an asymmetric public key algorithm that has been formalized in
diff --git a/ext/openssl/ossl_provider.c b/ext/openssl/ossl_provider.c
index 529a5e1c72..ea5abb8e48 100644
--- a/ext/openssl/ossl_provider.c
+++ b/ext/openssl/ossl_provider.c
@@ -185,11 +185,6 @@ ossl_provider_inspect(VALUE self)
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);
diff --git a/ext/openssl/ossl_rand.c b/ext/openssl/ossl_rand.c
index 764900dfc6..753f8b25f7 100644
--- a/ext/openssl/ossl_rand.c
+++ b/ext/openssl/ossl_rand.c
@@ -68,7 +68,7 @@ static VALUE
ossl_rand_load_file(VALUE self, VALUE filename)
{
if(!RAND_load_file(StringValueCStr(filename), -1)) {
- ossl_raise(eRandomError, NULL);
+ ossl_raise(eRandomError, NULL);
}
return Qtrue;
}
@@ -85,14 +85,14 @@ static VALUE
ossl_rand_write_file(VALUE self, VALUE filename)
{
if (RAND_write_file(StringValueCStr(filename)) == -1) {
- ossl_raise(eRandomError, NULL);
+ ossl_raise(eRandomError, NULL);
}
return Qtrue;
}
/*
* call-seq:
- * random_bytes(length) -> string
+ * random_bytes(length) -> string
*
* Generates a String with _length_ number of cryptographically strong
* pseudo-random bytes.
@@ -112,9 +112,9 @@ ossl_rand_bytes(VALUE self, VALUE len)
str = rb_str_new(0, n);
ret = RAND_bytes((unsigned char *)RSTRING_PTR(str), n);
if (ret == 0) {
- ossl_raise(eRandomError, "RAND_bytes");
+ ossl_raise(eRandomError, "RAND_bytes");
} else if (ret == -1) {
- ossl_raise(eRandomError, "RAND_bytes is not supported");
+ ossl_raise(eRandomError, "RAND_bytes is not supported");
}
return str;
@@ -131,7 +131,7 @@ static VALUE
ossl_rand_egd(VALUE self, VALUE filename)
{
if (RAND_egd(StringValueCStr(filename)) == -1) {
- ossl_raise(eRandomError, NULL);
+ ossl_raise(eRandomError, NULL);
}
return Qtrue;
}
@@ -151,7 +151,7 @@ ossl_rand_egd_bytes(VALUE self, VALUE filename, VALUE len)
int n = NUM2INT(len);
if (RAND_egd_bytes(StringValueCStr(filename), n) == -1) {
- ossl_raise(eRandomError, NULL);
+ ossl_raise(eRandomError, NULL);
}
return Qtrue;
}
@@ -175,11 +175,6 @@ ossl_rand_status(VALUE self)
void
Init_ossl_rand(void)
{
-#if 0
- mOSSL = rb_define_module("OpenSSL");
- eOSSLError = rb_define_class_under(mOSSL, "OpenSSLError", rb_eStandardError);
-#endif
-
mRandom = rb_define_module_under(mOSSL, "Random");
eRandomError = rb_define_class_under(mRandom, "RandomError", eOSSLError);
diff --git a/ext/openssl/ossl_ssl.c b/ext/openssl/ossl_ssl.c
index 29564a8139..3d913a3968 100644
--- a/ext/openssl/ossl_ssl.c
+++ b/ext/openssl/ossl_ssl.c
@@ -25,7 +25,7 @@
#endif
#define GetSSLCTX(obj, ctx) do { \
- TypedData_Get_Struct((obj), SSL_CTX, &ossl_sslctx_type, (ctx)); \
+ TypedData_Get_Struct((obj), SSL_CTX, &ossl_sslctx_type, (ctx)); \
} while (0)
VALUE mSSL;
@@ -36,19 +36,18 @@ VALUE cSSLSocket;
static VALUE eSSLErrorWaitReadable;
static VALUE eSSLErrorWaitWritable;
-static ID id_call, ID_callback_state, id_tmp_dh_callback,
- id_npn_protocols_encoded, id_each;
+static ID id_call, ID_callback_state, id_npn_protocols_encoded, id_each;
static VALUE sym_exception, sym_wait_readable, sym_wait_writable;
static ID id_i_cert_store, id_i_ca_file, id_i_ca_path, id_i_verify_mode,
- id_i_verify_depth, id_i_verify_callback, id_i_client_ca,
- id_i_renegotiation_cb, id_i_cert, id_i_key, id_i_extra_chain_cert,
- id_i_client_cert_cb, id_i_timeout,
- id_i_session_id_context, id_i_session_get_cb, id_i_session_new_cb,
- id_i_session_remove_cb, id_i_npn_select_cb, id_i_npn_protocols,
- id_i_alpn_select_cb, id_i_alpn_protocols, id_i_servername_cb,
- id_i_verify_hostname, id_i_keylog_cb;
-static ID id_i_io, id_i_context, id_i_hostname;
+ id_i_verify_depth, id_i_verify_callback, id_i_client_ca,
+ id_i_renegotiation_cb, id_i_cert, id_i_key, id_i_extra_chain_cert,
+ id_i_client_cert_cb, id_i_timeout,
+ id_i_session_id_context, id_i_session_get_cb, id_i_session_new_cb,
+ id_i_session_remove_cb, id_i_npn_select_cb, id_i_npn_protocols,
+ id_i_alpn_select_cb, id_i_alpn_protocols, id_i_servername_cb,
+ id_i_verify_hostname, id_i_keylog_cb, id_i_tmp_dh_callback;
+static ID id_i_io, id_i_context, id_i_hostname, id_i_sync_close;
static int ossl_ssl_ex_ptr_idx;
static int ossl_sslctx_ex_ptr_idx;
@@ -79,9 +78,9 @@ ossl_sslctx_s_alloc(VALUE klass)
{
SSL_CTX *ctx;
long mode = 0 |
- SSL_MODE_ENABLE_PARTIAL_WRITE |
- SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER |
- SSL_MODE_RELEASE_BUFFERS;
+ SSL_MODE_ENABLE_PARTIAL_WRITE |
+ SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER |
+ SSL_MODE_RELEASE_BUFFERS;
VALUE obj;
obj = TypedData_Wrap_Struct(klass, &ossl_sslctx_type, 0);
@@ -90,8 +89,10 @@ ossl_sslctx_s_alloc(VALUE klass)
ossl_raise(eSSLError, "SSL_CTX_new");
}
SSL_CTX_set_mode(ctx, mode);
+ SSL_CTX_set_dh_auto(ctx, 1);
RTYPEDDATA_DATA(obj) = ctx;
- SSL_CTX_set_ex_data(ctx, ossl_sslctx_ex_ptr_idx, (void *)obj);
+ if (!SSL_CTX_set_ex_data(ctx, ossl_sslctx_ex_ptr_idx, (void *)obj))
+ ossl_raise(eSSLError, "SSL_CTX_set_ex_data");
return obj;
}
@@ -104,7 +105,7 @@ ossl_call_client_cert_cb(VALUE obj)
ctx_obj = rb_attr_get(obj, id_i_context);
cb = rb_attr_get(ctx_obj, id_i_client_cert_cb);
if (NIL_P(cb))
- return Qnil;
+ return Qnil;
ary = rb_funcallv(cb, id_call, 1, &obj);
Check_Type(ary, T_ARRAY);
@@ -122,7 +123,7 @@ ossl_client_cert_cb(SSL *ssl, X509 **x509, EVP_PKEY **pkey)
obj = (VALUE)SSL_get_ex_data(ssl, ossl_ssl_ex_ptr_idx);
ret = rb_protect(ossl_call_client_cert_cb, obj, NULL);
if (NIL_P(ret))
- return 0;
+ return 0;
*x509 = DupX509CertPtr(RARRAY_AREF(ret, 0));
*pkey = DupPKeyPtr(RARRAY_AREF(ret, 1));
@@ -133,8 +134,6 @@ ossl_client_cert_cb(SSL *ssl, X509 **x509, EVP_PKEY **pkey)
#if !defined(OPENSSL_NO_DH)
struct tmp_dh_callback_args {
VALUE ssl_obj;
- ID id;
- int type;
int is_export;
int keylength;
};
@@ -143,48 +142,36 @@ static VALUE
ossl_call_tmp_dh_callback(VALUE arg)
{
struct tmp_dh_callback_args *args = (struct tmp_dh_callback_args *)arg;
- VALUE cb, dh;
- EVP_PKEY *pkey;
+ VALUE ctx_obj, cb, obj;
+ const DH *dh;
- cb = rb_funcall(args->ssl_obj, args->id, 0);
+ ctx_obj = rb_attr_get(args->ssl_obj, id_i_context);
+ cb = rb_attr_get(ctx_obj, id_i_tmp_dh_callback);
if (NIL_P(cb))
- return (VALUE)NULL;
- dh = rb_funcall(cb, id_call, 3, args->ssl_obj, INT2NUM(args->is_export),
- INT2NUM(args->keylength));
- pkey = GetPKeyPtr(dh);
- if (EVP_PKEY_base_id(pkey) != args->type)
- return (VALUE)NULL;
+ return (VALUE)NULL;
- return (VALUE)pkey;
+ obj = rb_funcall(cb, id_call, 3, args->ssl_obj, INT2NUM(args->is_export),
+ INT2NUM(args->keylength));
+ // TODO: We should riase if obj is not DH
+ dh = EVP_PKEY_get0_DH(GetPKeyPtr(obj));
+ if (!dh)
+ ossl_clear_error();
+
+ return (VALUE)dh;
}
-#endif
-#if !defined(OPENSSL_NO_DH)
static DH *
ossl_tmp_dh_callback(SSL *ssl, int is_export, int keylength)
{
- VALUE rb_ssl;
- EVP_PKEY *pkey;
- struct tmp_dh_callback_args args;
int state;
-
- rb_ssl = (VALUE)SSL_get_ex_data(ssl, ossl_ssl_ex_ptr_idx);
- args.ssl_obj = rb_ssl;
- args.id = id_tmp_dh_callback;
- args.is_export = is_export;
- args.keylength = keylength;
- args.type = EVP_PKEY_DH;
-
- pkey = (EVP_PKEY *)rb_protect(ossl_call_tmp_dh_callback,
- (VALUE)&args, &state);
+ VALUE rb_ssl = (VALUE)SSL_get_ex_data(ssl, ossl_ssl_ex_ptr_idx);
+ struct tmp_dh_callback_args args = {rb_ssl, is_export, keylength};
+ VALUE ret = rb_protect(ossl_call_tmp_dh_callback, (VALUE)&args, &state);
if (state) {
- rb_ivar_set(rb_ssl, ID_callback_state, INT2NUM(state));
- return NULL;
+ rb_ivar_set(rb_ssl, ID_callback_state, INT2NUM(state));
+ return NULL;
}
- if (!pkey)
- return NULL;
-
- return (DH *)EVP_PKEY_get0_DH(pkey);
+ return (DH *)ret;
}
#endif /* OPENSSL_NO_DH */
@@ -200,13 +187,13 @@ call_verify_certificate_identity(VALUE ctx_v)
hostname = rb_attr_get(ssl_obj, id_i_hostname);
if (!RTEST(hostname)) {
- rb_warning("verify_hostname requires hostname to be set");
- return Qtrue;
+ rb_warning("verify_hostname requires hostname to be set");
+ return Qtrue;
}
cert_obj = ossl_x509_new(X509_STORE_CTX_get_current_cert(ctx));
return rb_funcall(mSSL, rb_intern("verify_certificate_identity"), 2,
- cert_obj, hostname);
+ cert_obj, hostname);
}
static int
@@ -223,12 +210,12 @@ ossl_ssl_verify_callback(int preverify_ok, X509_STORE_CTX *ctx)
verify_hostname = rb_attr_get(sslctx_obj, id_i_verify_hostname);
if (preverify_ok && RTEST(verify_hostname) && !SSL_is_server(ssl) &&
- !X509_STORE_CTX_get_error_depth(ctx)) {
- ret = rb_protect(call_verify_certificate_identity, (VALUE)ctx, &status);
- if (status) {
- rb_ivar_set(ssl_obj, ID_callback_state, INT2NUM(status));
- return 0;
- }
+ !X509_STORE_CTX_get_error_depth(ctx)) {
+ ret = rb_protect(call_verify_certificate_identity, (VALUE)ctx, &status);
+ if (status) {
+ rb_ivar_set(ssl_obj, ID_callback_state, INT2NUM(status));
+ return 0;
+ }
if (ret != Qtrue) {
preverify_ok = 0;
X509_STORE_CTX_set_error(ctx, X509_V_ERR_HOSTNAME_MISMATCH);
@@ -399,7 +386,7 @@ ossl_sslctx_session_remove_cb(SSL_CTX *ctx, SSL_SESSION *sess)
* when SSL_CTX_free() is called.
*/
if (rb_during_gc())
- return;
+ return;
OSSL_Debug("SSL SESSION remove callback entered");
@@ -462,8 +449,8 @@ ossl_call_servername_cb(VALUE arg)
ossl_raise(eSSLError, "SSL_set_SSL_CTX");
rb_ivar_set(ssl_obj, id_i_context, ret_obj);
} else if (!NIL_P(ret_obj)) {
- ossl_raise(rb_eArgError, "servername_cb must return an "
- "OpenSSL::SSL::SSLContext object or nil");
+ ossl_raise(rb_eArgError, "servername_cb must return an "
+ "OpenSSL::SSL::SSLContext object or nil");
}
return Qnil;
@@ -503,7 +490,7 @@ ssl_npn_encode_protocol_i(RB_BLOCK_CALL_FUNC_ARGLIST(cur, encoded))
int len = RSTRING_LENINT(cur);
char len_byte;
if (len < 1 || len > 255)
- ossl_raise(eSSLError, "Advertised protocol must have length 1..255");
+ ossl_raise(eSSLError, "Advertised protocol must have length 1..255");
/* Encode the length byte */
len_byte = len;
rb_str_buf_cat(encoded, &len_byte, 1);
@@ -537,16 +524,16 @@ npn_select_cb_common_i(VALUE tmp)
/* assume OpenSSL verifies this format */
/* The format is len_1|proto_1|...|len_n|proto_n */
while (in < in_end) {
- l = *in++;
- rb_ary_push(protocols, rb_str_new((const char *)in, l));
- in += l;
+ l = *in++;
+ rb_ary_push(protocols, rb_str_new((const char *)in, l));
+ in += l;
}
selected = rb_funcallv(args->cb, id_call, 1, &protocols);
StringValue(selected);
len = RSTRING_LEN(selected);
if (len < 1 || len >= 256) {
- ossl_raise(eSSLError, "Selected protocol name must have length 1..255");
+ ossl_raise(eSSLError, "Selected protocol name must have length 1..255");
}
return selected;
@@ -554,8 +541,8 @@ npn_select_cb_common_i(VALUE tmp)
static int
ssl_npn_select_cb_common(SSL *ssl, VALUE cb, const unsigned char **out,
- unsigned char *outlen, const unsigned char *in,
- unsigned int inlen)
+ unsigned char *outlen, const unsigned char *in,
+ unsigned int inlen)
{
VALUE selected;
int status;
@@ -567,10 +554,10 @@ ssl_npn_select_cb_common(SSL *ssl, VALUE cb, const unsigned char **out,
selected = rb_protect(npn_select_cb_common_i, (VALUE)&args, &status);
if (status) {
- VALUE ssl_obj = (VALUE)SSL_get_ex_data(ssl, ossl_ssl_ex_ptr_idx);
+ VALUE ssl_obj = (VALUE)SSL_get_ex_data(ssl, ossl_ssl_ex_ptr_idx);
- rb_ivar_set(ssl_obj, ID_callback_state, INT2NUM(status));
- return SSL_TLSEXT_ERR_ALERT_FATAL;
+ rb_ivar_set(ssl_obj, ID_callback_state, INT2NUM(status));
+ return SSL_TLSEXT_ERR_ALERT_FATAL;
}
*out = (unsigned char *)RSTRING_PTR(selected);
@@ -582,7 +569,7 @@ ssl_npn_select_cb_common(SSL *ssl, VALUE cb, const unsigned char **out,
#ifdef OSSL_USE_NEXTPROTONEG
static int
ssl_npn_advertise_cb(SSL *ssl, const unsigned char **out, unsigned int *outlen,
- void *arg)
+ void *arg)
{
VALUE protocols = rb_attr_get((VALUE)arg, id_npn_protocols_encoded);
@@ -594,7 +581,7 @@ ssl_npn_advertise_cb(SSL *ssl, const unsigned char **out, unsigned int *outlen,
static int
ssl_npn_select_cb(SSL *ssl, unsigned char **out, unsigned char *outlen,
- const unsigned char *in, unsigned int inlen, void *arg)
+ const unsigned char *in, unsigned int inlen, void *arg)
{
VALUE sslctx_obj, cb;
@@ -602,13 +589,13 @@ ssl_npn_select_cb(SSL *ssl, unsigned char **out, unsigned char *outlen,
cb = rb_attr_get(sslctx_obj, id_i_npn_select_cb);
return ssl_npn_select_cb_common(ssl, cb, (const unsigned char **)out,
- outlen, in, inlen);
+ outlen, in, inlen);
}
#endif
static int
ssl_alpn_select_cb(SSL *ssl, const unsigned char **out, unsigned char *outlen,
- const unsigned char *in, unsigned int inlen, void *arg)
+ const unsigned char *in, unsigned int inlen, void *arg)
{
VALUE sslctx_obj, cb;
@@ -625,7 +612,7 @@ ssl_info_cb(const SSL *ssl, int where, int val)
int is_server = SSL_is_server((SSL *)ssl);
if (is_server && where & SSL_CB_HANDSHAKE_START) {
- ssl_renegotiation_cb(ssl);
+ ssl_renegotiation_cb(ssl);
}
}
@@ -671,9 +658,9 @@ ossl_sslctx_set_options(VALUE self, VALUE options)
SSL_CTX_clear_options(ctx, SSL_CTX_get_options(ctx));
if (NIL_P(options)) {
- SSL_CTX_set_options(ctx, SSL_OP_ALL);
+ SSL_CTX_set_options(ctx, SSL_OP_ALL);
} else {
- SSL_CTX_set_options(ctx, NUM2ULONG(options));
+ SSL_CTX_set_options(ctx, NUM2ULONG(options));
}
return self;
@@ -703,7 +690,10 @@ ossl_sslctx_setup(VALUE self)
GetSSLCTX(self, ctx);
#if !defined(OPENSSL_NO_DH)
- SSL_CTX_set_tmp_dh_callback(ctx, ossl_tmp_dh_callback);
+ if (!NIL_P(rb_attr_get(self, id_i_tmp_dh_callback))) {
+ SSL_CTX_set_tmp_dh_callback(ctx, ossl_tmp_dh_callback);
+ SSL_CTX_set_dh_auto(ctx, 0);
+ }
#endif
#if !defined(OPENSSL_IS_AWSLC) /* AWS-LC has no support for TLS 1.3 PHA. */
@@ -712,14 +702,14 @@ ossl_sslctx_setup(VALUE self)
val = rb_attr_get(self, id_i_cert_store);
if (!NIL_P(val)) {
- X509_STORE *store = GetX509StorePtr(val); /* NO NEED TO DUP */
- SSL_CTX_set_cert_store(ctx, store);
- X509_STORE_up_ref(store);
+ X509_STORE *store = GetX509StorePtr(val); /* NO NEED TO DUP */
+ SSL_CTX_set_cert_store(ctx, store);
+ X509_STORE_up_ref(store);
}
val = rb_attr_get(self, id_i_extra_chain_cert);
if(!NIL_P(val)){
- rb_block_call(val, rb_intern("each"), 0, 0, ossl_sslctx_add_extra_chain_cert_i, self);
+ rb_block_call(val, rb_intern("each"), 0, 0, ossl_sslctx_add_extra_chain_cert_i, self);
}
/* private key may be bundled in certificate file. */
@@ -743,22 +733,22 @@ ossl_sslctx_setup(VALUE self)
val = rb_attr_get(self, id_i_client_ca);
if(!NIL_P(val)){
- if (RB_TYPE_P(val, T_ARRAY)) {
- for(i = 0; i < RARRAY_LEN(val); i++){
- client_ca = GetX509CertPtr(RARRAY_AREF(val, i));
- if (!SSL_CTX_add_client_CA(ctx, client_ca)){
- /* Copies X509_NAME => FREE it. */
- ossl_raise(eSSLError, "SSL_CTX_add_client_CA");
- }
- }
+ if (RB_TYPE_P(val, T_ARRAY)) {
+ for(i = 0; i < RARRAY_LEN(val); i++){
+ client_ca = GetX509CertPtr(RARRAY_AREF(val, i));
+ if (!SSL_CTX_add_client_CA(ctx, client_ca)){
+ /* Copies X509_NAME => FREE it. */
+ ossl_raise(eSSLError, "SSL_CTX_add_client_CA");
+ }
+ }
}
- else{
- client_ca = GetX509CertPtr(val); /* NO DUP NEEDED. */
+ else{
+ client_ca = GetX509CertPtr(val); /* NO DUP NEEDED. */
if (!SSL_CTX_add_client_CA(ctx, client_ca)){
- /* Copies X509_NAME => FREE it. */
- ossl_raise(eSSLError, "SSL_CTX_add_client_CA");
+ /* Copies X509_NAME => FREE it. */
+ ossl_raise(eSSLError, "SSL_CTX_add_client_CA");
}
- }
+ }
}
val = rb_attr_get(self, id_i_ca_file);
@@ -781,7 +771,7 @@ ossl_sslctx_setup(VALUE self)
verify_mode = NIL_P(val) ? SSL_VERIFY_NONE : NUM2INT(val);
SSL_CTX_set_verify(ctx, verify_mode, ossl_ssl_verify_callback);
if (RTEST(rb_attr_get(self, id_i_client_cert_cb)))
- SSL_CTX_set_client_cert_cb(ctx, ossl_client_cert_cb);
+ SSL_CTX_set_client_cert_cb(ctx, ossl_client_cert_cb);
val = rb_attr_get(self, id_i_timeout);
if(!NIL_P(val)) SSL_CTX_set_timeout(ctx, NUM2LONG(val));
@@ -792,60 +782,60 @@ ossl_sslctx_setup(VALUE self)
#ifdef OSSL_USE_NEXTPROTONEG
val = rb_attr_get(self, id_i_npn_protocols);
if (!NIL_P(val)) {
- VALUE encoded = ssl_encode_npn_protocols(val);
- rb_ivar_set(self, id_npn_protocols_encoded, encoded);
- SSL_CTX_set_next_protos_advertised_cb(ctx, ssl_npn_advertise_cb, (void *)self);
- OSSL_Debug("SSL NPN advertise callback added");
+ VALUE encoded = ssl_encode_npn_protocols(val);
+ rb_ivar_set(self, id_npn_protocols_encoded, encoded);
+ SSL_CTX_set_next_protos_advertised_cb(ctx, ssl_npn_advertise_cb, (void *)self);
+ OSSL_Debug("SSL NPN advertise callback added");
}
if (RTEST(rb_attr_get(self, id_i_npn_select_cb))) {
- SSL_CTX_set_next_proto_select_cb(ctx, ssl_npn_select_cb, (void *) self);
- OSSL_Debug("SSL NPN select callback added");
+ SSL_CTX_set_next_proto_select_cb(ctx, ssl_npn_select_cb, (void *) self);
+ OSSL_Debug("SSL NPN select callback added");
}
#endif
val = rb_attr_get(self, id_i_alpn_protocols);
if (!NIL_P(val)) {
- VALUE rprotos = ssl_encode_npn_protocols(val);
+ VALUE rprotos = ssl_encode_npn_protocols(val);
- /* returns 0 on success */
- if (SSL_CTX_set_alpn_protos(ctx, (unsigned char *)RSTRING_PTR(rprotos),
- RSTRING_LENINT(rprotos)))
- ossl_raise(eSSLError, "SSL_CTX_set_alpn_protos");
- OSSL_Debug("SSL ALPN values added");
+ /* returns 0 on success */
+ if (SSL_CTX_set_alpn_protos(ctx, (unsigned char *)RSTRING_PTR(rprotos),
+ RSTRING_LENINT(rprotos)))
+ ossl_raise(eSSLError, "SSL_CTX_set_alpn_protos");
+ OSSL_Debug("SSL ALPN values added");
}
if (RTEST(rb_attr_get(self, id_i_alpn_select_cb))) {
- SSL_CTX_set_alpn_select_cb(ctx, ssl_alpn_select_cb, (void *) self);
- OSSL_Debug("SSL ALPN select callback added");
+ SSL_CTX_set_alpn_select_cb(ctx, ssl_alpn_select_cb, (void *) self);
+ OSSL_Debug("SSL ALPN select callback added");
}
rb_obj_freeze(self);
val = rb_attr_get(self, id_i_session_id_context);
if (!NIL_P(val)){
- StringValue(val);
- if (!SSL_CTX_set_session_id_context(ctx, (unsigned char *)RSTRING_PTR(val),
- RSTRING_LENINT(val))){
- ossl_raise(eSSLError, "SSL_CTX_set_session_id_context");
- }
+ StringValue(val);
+ if (!SSL_CTX_set_session_id_context(ctx, (unsigned char *)RSTRING_PTR(val),
+ RSTRING_LENINT(val))){
+ ossl_raise(eSSLError, "SSL_CTX_set_session_id_context");
+ }
}
if (RTEST(rb_attr_get(self, id_i_session_get_cb))) {
- SSL_CTX_sess_set_get_cb(ctx, ossl_sslctx_session_get_cb);
- OSSL_Debug("SSL SESSION get callback added");
+ SSL_CTX_sess_set_get_cb(ctx, ossl_sslctx_session_get_cb);
+ OSSL_Debug("SSL SESSION get callback added");
}
if (RTEST(rb_attr_get(self, id_i_session_new_cb))) {
- SSL_CTX_sess_set_new_cb(ctx, ossl_sslctx_session_new_cb);
- OSSL_Debug("SSL SESSION new callback added");
+ SSL_CTX_sess_set_new_cb(ctx, ossl_sslctx_session_new_cb);
+ OSSL_Debug("SSL SESSION new callback added");
}
if (RTEST(rb_attr_get(self, id_i_session_remove_cb))) {
- SSL_CTX_sess_set_remove_cb(ctx, ossl_sslctx_session_remove_cb);
- OSSL_Debug("SSL SESSION remove callback added");
+ SSL_CTX_sess_set_remove_cb(ctx, ossl_sslctx_session_remove_cb);
+ OSSL_Debug("SSL SESSION remove callback added");
}
val = rb_attr_get(self, id_i_servername_cb);
if (!NIL_P(val)) {
SSL_CTX_set_tlsext_servername_callback(ctx, ssl_servername_cb);
- OSSL_Debug("SSL TLSEXT servername callback added");
+ OSSL_Debug("SSL TLSEXT servername callback added");
}
#if !OSSL_IS_LIBRESSL
@@ -868,28 +858,28 @@ parse_proto_version(VALUE str)
{
int i;
static const struct {
- const char *name;
- int version;
+ const char *name;
+ int version;
} map[] = {
- { "SSL2", SSL2_VERSION },
- { "SSL3", SSL3_VERSION },
- { "TLS1", TLS1_VERSION },
- { "TLS1_1", TLS1_1_VERSION },
- { "TLS1_2", TLS1_2_VERSION },
- { "TLS1_3", TLS1_3_VERSION },
+ { "SSL2", SSL2_VERSION },
+ { "SSL3", SSL3_VERSION },
+ { "TLS1", TLS1_VERSION },
+ { "TLS1_1", TLS1_1_VERSION },
+ { "TLS1_2", TLS1_2_VERSION },
+ { "TLS1_3", TLS1_3_VERSION },
};
if (NIL_P(str))
- return 0;
+ return 0;
if (RB_INTEGER_TYPE_P(str))
- return NUM2INT(str);
+ return NUM2INT(str);
if (SYMBOL_P(str))
- str = rb_sym2str(str);
+ str = rb_sym2str(str);
StringValue(str);
for (i = 0; i < numberof(map); i++)
- if (!strncmp(map[i].name, RSTRING_PTR(str), RSTRING_LEN(str)))
- return map[i].version;
+ if (!strncmp(map[i].name, RSTRING_PTR(str), RSTRING_LEN(str)))
+ return map[i].version;
rb_raise(rb_eArgError, "unrecognized version %+"PRIsVALUE, str);
}
@@ -1148,7 +1138,7 @@ ossl_sslctx_set_client_sigalgs(VALUE self, VALUE v)
* contained in the key object, if any, are ignored. The server will always
* generate a new key pair for each handshake.
*
- * Added in version 3.0. See also the man page SSL_set0_tmp_dh_pkey(3).
+ * Added in version 3.0. See also the man page SSL_CTX_set0_tmp_dh_pkey(3).
*
* Example:
* ctx = OpenSSL::SSL::SSLContext.new
@@ -1169,7 +1159,7 @@ ossl_sslctx_set_tmp_dh(VALUE self, VALUE arg)
if (EVP_PKEY_base_id(pkey) != EVP_PKEY_DH)
rb_raise(eSSLError, "invalid pkey type %s (expected DH)",
OBJ_nid2sn(EVP_PKEY_base_id(pkey)));
-#ifdef HAVE_SSL_SET0_TMP_DH_PKEY
+#ifdef HAVE_SSL_CTX_SET0_TMP_DH_PKEY
if (!SSL_CTX_set0_tmp_dh_pkey(ctx, pkey))
ossl_raise(eSSLError, "SSL_CTX_set0_tmp_dh_pkey");
EVP_PKEY_up_ref(pkey);
@@ -1178,6 +1168,9 @@ ossl_sslctx_set_tmp_dh(VALUE self, VALUE arg)
ossl_raise(eSSLError, "SSL_CTX_set_tmp_dh");
#endif
+ // Turn off the "auto" DH parameters set by ossl_sslctx_s_alloc()
+ SSL_CTX_set_dh_auto(ctx, 0);
+
return arg;
}
#endif
@@ -1352,20 +1345,20 @@ ossl_sslctx_add_certificate(int argc, VALUE *argv, VALUE self)
pub_pkey = X509_get_pubkey(x509);
EVP_PKEY_free(pub_pkey);
if (!pub_pkey)
- rb_raise(rb_eArgError, "certificate does not contain public key");
+ rb_raise(rb_eArgError, "certificate does not contain public key");
if (EVP_PKEY_eq(pub_pkey, pkey) != 1)
- rb_raise(rb_eArgError, "public key mismatch");
+ rb_raise(rb_eArgError, "public key mismatch");
if (argc >= 3)
- extra_chain = ossl_x509_ary2sk(extra_chain_ary);
+ extra_chain = ossl_x509_ary2sk(extra_chain_ary);
if (!SSL_CTX_use_certificate(ctx, x509)) {
- sk_X509_pop_free(extra_chain, X509_free);
- ossl_raise(eSSLError, "SSL_CTX_use_certificate");
+ sk_X509_pop_free(extra_chain, X509_free);
+ ossl_raise(eSSLError, "SSL_CTX_use_certificate");
}
if (!SSL_CTX_use_PrivateKey(ctx, pkey)) {
- sk_X509_pop_free(extra_chain, X509_free);
- ossl_raise(eSSLError, "SSL_CTX_use_PrivateKey");
+ sk_X509_pop_free(extra_chain, X509_free);
+ ossl_raise(eSSLError, "SSL_CTX_use_PrivateKey");
}
if (extra_chain && !SSL_CTX_set0_chain(ctx, extra_chain)) {
sk_X509_pop_free(extra_chain, X509_free);
@@ -1598,32 +1591,31 @@ ossl_ssl_s_alloc(VALUE klass)
}
static VALUE
-peer_ip_address(VALUE self)
+peer_ip_address(VALUE io)
{
- VALUE remote_address = rb_funcall(rb_attr_get(self, id_i_io), rb_intern("remote_address"), 0);
+ VALUE remote_address = rb_funcall(io, rb_intern("remote_address"), 0);
return rb_funcall(remote_address, rb_intern("inspect_sockaddr"), 0);
}
static VALUE
-fallback_peer_ip_address(VALUE self, VALUE args)
+fallback_peer_ip_address(VALUE self, VALUE exc)
{
return rb_str_new_cstr("(null)");
}
static VALUE
-peeraddr_ip_str(VALUE self)
+peeraddr_ip_str(VALUE io)
{
- VALUE rb_mErrno = rb_const_get(rb_cObject, rb_intern("Errno"));
- VALUE rb_eSystemCallError = rb_const_get(rb_mErrno, rb_intern("SystemCallError"));
-
- return rb_rescue2(peer_ip_address, self, fallback_peer_ip_address, (VALUE)0, rb_eSystemCallError, NULL);
+ return rb_rescue2(peer_ip_address, io, fallback_peer_ip_address, Qnil,
+ rb_eSystemCallError, (VALUE)0);
}
/*
* call-seq:
* SSLSocket.new(io) => aSSLSocket
* SSLSocket.new(io, ctx) => aSSLSocket
+ * SSLSocket.new(io, ctx, sync_close:) => aSSLSocket
*
* Creates a new SSL socket from _io_ which must be a real IO object (not an
* IO-like object that responds to read/write).
@@ -1631,6 +1623,10 @@ peeraddr_ip_str(VALUE self)
* If _ctx_ is provided the SSL Sockets initial params will be taken from
* the context.
*
+ * The optional _sync_close_ keyword parameter sets the _sync_close_ instance
+ * variable. Setting this to +true+ will cause the underlying socket to be
+ * closed when the SSL/TLS connection is shut down.
+ *
* The OpenSSL::Buffering module provides additional IO methods.
*
* This method will freeze the SSLContext if one is provided;
@@ -1639,32 +1635,46 @@ peeraddr_ip_str(VALUE self)
static VALUE
ossl_ssl_initialize(int argc, VALUE *argv, VALUE self)
{
+ static ID kw_ids[1];
+ VALUE kw_args[1];
+ VALUE opts;
+
VALUE io, v_ctx;
SSL *ssl;
SSL_CTX *ctx;
TypedData_Get_Struct(self, SSL, &ossl_ssl_type, ssl);
if (ssl)
- ossl_raise(eSSLError, "SSL already initialized");
+ ossl_raise(eSSLError, "SSL already initialized");
- if (rb_scan_args(argc, argv, "11", &io, &v_ctx) == 1)
- v_ctx = rb_funcall(cSSLContext, rb_intern("new"), 0);
+ if (rb_scan_args(argc, argv, "11:", &io, &v_ctx, &opts) == 1)
+ v_ctx = rb_funcall(cSSLContext, rb_intern("new"), 0);
+
+ if (!kw_ids[0]) {
+ kw_ids[0] = rb_intern_const("sync_close");
+ }
+
+ rb_get_kwargs(opts, kw_ids, 0, 1, kw_args);
+ if (kw_args[0] != Qundef) {
+ rb_ivar_set(self, id_i_sync_close, kw_args[0]);
+ }
GetSSLCTX(v_ctx, ctx);
rb_ivar_set(self, id_i_context, v_ctx);
ossl_sslctx_setup(v_ctx);
if (rb_respond_to(io, rb_intern("nonblock=")))
- rb_funcall(io, rb_intern("nonblock="), 1, Qtrue);
+ rb_funcall(io, rb_intern("nonblock="), 1, Qtrue);
Check_Type(io, T_FILE);
rb_ivar_set(self, id_i_io, io);
ssl = SSL_new(ctx);
if (!ssl)
- ossl_raise(eSSLError, NULL);
+ ossl_raise(eSSLError, NULL);
RTYPEDDATA_DATA(self) = ssl;
- SSL_set_ex_data(ssl, ossl_ssl_ex_ptr_idx, (void *)self);
+ if (!SSL_set_ex_data(ssl, ossl_ssl_ex_ptr_idx, (void *)self))
+ ossl_raise(eSSLError, "SSL_set_ex_data");
SSL_set_info_callback(ssl, ssl_info_cb);
rb_call_super(0, NULL);
@@ -1692,7 +1702,7 @@ ossl_ssl_setup(VALUE self)
GetSSL(self, ssl);
if (ssl_started(ssl))
- return Qtrue;
+ return Qtrue;
io = rb_attr_get(self, id_i_io);
GetOpenFile(io, fptr);
@@ -1704,24 +1714,28 @@ ossl_ssl_setup(VALUE self)
return Qtrue;
}
+static int
+errno_mapped(void)
+{
#ifdef _WIN32
-#define ssl_get_error(ssl, ret) (errno = rb_w32_map_errno(WSAGetLastError()), SSL_get_error((ssl), (ret)))
+ return rb_w32_map_errno(WSAGetLastError());
#else
-#define ssl_get_error(ssl, ret) SSL_get_error((ssl), (ret))
+ return errno;
#endif
+}
static void
write_would_block(int nonblock)
{
if (nonblock)
- ossl_raise(eSSLErrorWaitWritable, "write would block");
+ ossl_raise(eSSLErrorWaitWritable, "write would block");
}
static void
read_would_block(int nonblock)
{
if (nonblock)
- ossl_raise(eSSLErrorWaitReadable, "read would block");
+ ossl_raise(eSSLErrorWaitReadable, "read would block");
}
static int
@@ -1729,7 +1743,7 @@ no_exception_p(VALUE opts)
{
if (RB_TYPE_P(opts, T_HASH) &&
rb_hash_lookup2(opts, sym_exception, Qundef) == Qfalse)
- return 1;
+ return 1;
return 0;
}
@@ -1749,13 +1763,13 @@ static void
io_wait_writable(VALUE io)
{
#ifdef HAVE_RB_IO_MAYBE_WAIT
- if (!rb_io_maybe_wait_writable(errno, io, RUBY_IO_TIMEOUT_DEFAULT)) {
+ if (!rb_io_wait(io, INT2NUM(RUBY_IO_WRITABLE), RUBY_IO_TIMEOUT_DEFAULT)) {
rb_raise(IO_TIMEOUT_ERROR, "Timed out while waiting to become writable!");
}
#else
rb_io_t *fptr;
GetOpenFile(io, fptr);
- rb_io_wait_writable(fptr->fd);
+ rb_thread_fd_writable(fptr->fd);
#endif
}
@@ -1763,13 +1777,13 @@ static void
io_wait_readable(VALUE io)
{
#ifdef HAVE_RB_IO_MAYBE_WAIT
- if (!rb_io_maybe_wait_readable(errno, io, RUBY_IO_TIMEOUT_DEFAULT)) {
+ if (!rb_io_wait(io, INT2NUM(RUBY_IO_READABLE), RUBY_IO_TIMEOUT_DEFAULT)) {
rb_raise(IO_TIMEOUT_ERROR, "Timed out while waiting to become readable!");
}
#else
rb_io_t *fptr;
GetOpenFile(io, fptr);
- rb_io_wait_readable(fptr->fd);
+ rb_thread_wait_fd(fptr->fd);
#endif
}
@@ -1777,7 +1791,6 @@ static VALUE
ossl_start_ssl(VALUE self, int (*func)(SSL *), const char *funcname, VALUE opts)
{
SSL *ssl;
- int ret, ret2;
VALUE cb_state;
int nonblock = opts != Qfalse;
@@ -1787,7 +1800,8 @@ ossl_start_ssl(VALUE self, int (*func)(SSL *), const char *funcname, VALUE opts)
VALUE io = rb_attr_get(self, id_i_io);
for (;;) {
- ret = func(ssl);
+ int ret = func(ssl);
+ int saved_errno = errno_mapped();
cb_state = rb_attr_get(self, ID_callback_state);
if (!NIL_P(cb_state)) {
@@ -1799,7 +1813,8 @@ ossl_start_ssl(VALUE self, int (*func)(SSL *), const char *funcname, VALUE opts)
if (ret > 0)
break;
- switch ((ret2 = ssl_get_error(ssl, ret))) {
+ int code = SSL_get_error(ssl, ret);
+ switch (code) {
case SSL_ERROR_WANT_WRITE:
if (no_exception_p(opts)) { return sym_wait_writable; }
write_would_block(nonblock);
@@ -1813,10 +1828,11 @@ ossl_start_ssl(VALUE self, int (*func)(SSL *), const char *funcname, VALUE opts)
case SSL_ERROR_SYSCALL:
#ifdef __APPLE__
/* See ossl_ssl_write_internal() */
- if (errno == EPROTOTYPE)
+ if (saved_errno == EPROTOTYPE)
continue;
#endif
- if (errno) rb_sys_fail(funcname);
+ if (saved_errno)
+ rb_exc_raise(rb_syserr_new(saved_errno, funcname));
/* fallthrough */
default: {
VALUE error_append = Qnil;
@@ -1837,10 +1853,10 @@ ossl_start_ssl(VALUE self, int (*func)(SSL *), const char *funcname, VALUE opts)
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),
+ code == SSL_ERROR_SYSCALL ? " SYSCALL" : "",
+ code,
+ saved_errno,
+ peeraddr_ip_str(io),
SSL_state_string_long(ssl),
error_append);
}
@@ -1953,9 +1969,9 @@ ossl_ssl_read_internal(int argc, VALUE *argv, VALUE self, int nonblock)
VALUE opts = Qnil;
if (nonblock) {
- rb_scan_args(argc, argv, "11:", &len, &str, &opts);
+ rb_scan_args(argc, argv, "11:", &len, &str, &opts);
} else {
- rb_scan_args(argc, argv, "11", &len, &str);
+ rb_scan_args(argc, argv, "11", &len, &str);
}
GetSSL(self, ssl);
if (!ssl_started(ssl))
@@ -1963,13 +1979,13 @@ ossl_ssl_read_internal(int argc, VALUE *argv, VALUE self, int nonblock)
ilen = NUM2INT(len);
if (NIL_P(str))
- str = rb_str_new(0, ilen);
+ str = rb_str_new(0, ilen);
else {
- StringValue(str);
- if (RSTRING_LEN(str) >= ilen)
- rb_str_modify(str);
- else
- rb_str_modify_expand(str, ilen - RSTRING_LEN(str));
+ StringValue(str);
+ if (RSTRING_LEN(str) >= ilen)
+ rb_str_modify(str);
+ else
+ rb_str_modify_expand(str, ilen - RSTRING_LEN(str));
}
if (ilen == 0) {
@@ -1982,6 +1998,7 @@ ossl_ssl_read_internal(int argc, VALUE *argv, VALUE self, int nonblock)
for (;;) {
rb_str_locktmp(str);
int nread = SSL_read(ssl, RSTRING_PTR(str), ilen);
+ int saved_errno = errno_mapped();
rb_str_unlocktmp(str);
cb_state = rb_attr_get(self, ID_callback_state);
@@ -1991,7 +2008,7 @@ ossl_ssl_read_internal(int argc, VALUE *argv, VALUE self, int nonblock)
rb_jump_tag(NUM2INT(cb_state));
}
- switch (ssl_get_error(ssl, nread)) {
+ switch (SSL_get_error(ssl, nread)) {
case SSL_ERROR_NONE:
rb_str_set_len(str, nread);
return str;
@@ -2014,8 +2031,8 @@ ossl_ssl_read_internal(int argc, VALUE *argv, VALUE self, int nonblock)
break;
case SSL_ERROR_SYSCALL:
if (!ERR_peek_error()) {
- if (errno)
- rb_sys_fail(0);
+ if (saved_errno)
+ rb_exc_raise(rb_syserr_new(saved_errno, "SSL_read"));
else {
/*
* The underlying BIO returned 0. This is actually a
@@ -2100,6 +2117,7 @@ ossl_ssl_write_internal_safe(VALUE _args)
for (;;) {
int nwritten = SSL_write(ssl, RSTRING_PTR(str), num);
+ int saved_errno = errno_mapped();
cb_state = rb_attr_get(self, ID_callback_state);
if (!NIL_P(cb_state)) {
@@ -2108,7 +2126,7 @@ ossl_ssl_write_internal_safe(VALUE _args)
rb_jump_tag(NUM2INT(cb_state));
}
- switch (ssl_get_error(ssl, nwritten)) {
+ switch (SSL_get_error(ssl, nwritten)) {
case SSL_ERROR_NONE:
return INT2NUM(nwritten);
case SSL_ERROR_WANT_WRITE:
@@ -2129,10 +2147,11 @@ ossl_ssl_write_internal_safe(VALUE _args)
* make the error handling in line with the socket library.
* [Bug #14713] https://bugs.ruby-lang.org/issues/14713
*/
- if (errno == EPROTOTYPE)
+ if (saved_errno == EPROTOTYPE)
continue;
#endif
- if (errno) rb_sys_fail(0);
+ if (saved_errno)
+ rb_exc_raise(rb_syserr_new(saved_errno, "SSL_write"));
/* fallthrough */
default:
ossl_raise(eSSLError, "SSL_write");
@@ -2177,9 +2196,12 @@ ossl_ssl_write(VALUE self, VALUE str)
/*
* call-seq:
* ssl.syswrite_nonblock(string) => Integer
+ * ssl.syswrite_nonblock(string, opts) => Integer
*
* Writes _string_ to the SSL connection in a non-blocking manner. Raises an
- * SSLError if writing would block.
+ * SSLError if writing would block. If "exception: false" is passed, this
+ * method returns a symbol of :wait_readable or :wait_writable, rather than
+ * raising an exception.
*/
static VALUE
ossl_ssl_write_nonblock(int argc, VALUE *argv, VALUE self)
@@ -2206,12 +2228,12 @@ ossl_ssl_stop(VALUE self)
GetSSL(self, ssl);
if (!ssl_started(ssl))
- return Qnil;
+ return Qnil;
ret = SSL_shutdown(ssl);
if (ret == 1) /* Have already received close_notify */
- return Qnil;
+ return Qnil;
if (ret == 0) /* Sent close_notify, but we don't wait for reply */
- return Qnil;
+ return Qnil;
/*
* XXX: Something happened. Possibly it failed because the underlying socket
@@ -2297,20 +2319,20 @@ ossl_ssl_get_peer_cert_chain(VALUE self)
num = sk_X509_num(chain);
ary = rb_ary_new2(num);
for (i = 0; i < num; i++){
- cert = sk_X509_value(chain, i);
- rb_ary_push(ary, ossl_x509_new(cert));
+ cert = sk_X509_value(chain, i);
+ rb_ary_push(ary, ossl_x509_new(cert));
}
return ary;
}
/*
-* call-seq:
-* ssl.ssl_version => String
-*
-* Returns a String representing the SSL/TLS version that was negotiated
-* for the connection, for example "TLSv1.2".
-*/
+ * call-seq:
+ * ssl.ssl_version => String
+ *
+ * Returns a String representing the SSL/TLS version that was negotiated
+ * for the connection, for example "TLSv1.2".
+ */
static VALUE
ossl_ssl_get_version(VALUE self)
{
@@ -2431,10 +2453,10 @@ ossl_ssl_set_hostname(VALUE self, VALUE arg)
GetSSL(self, ssl);
if (!NIL_P(arg))
- hostname = StringValueCStr(arg);
+ hostname = StringValueCStr(arg);
if (!SSL_set_tlsext_host_name(ssl, hostname))
- ossl_raise(eSSLError, NULL);
+ ossl_raise(eSSLError, NULL);
/* for SSLSocket#hostname */
rb_ivar_set(self, id_i_hostname, arg);
@@ -2463,16 +2485,15 @@ ossl_ssl_get_verify_result(VALUE self)
/*
* call-seq:
- * ssl.finished_message => "finished message"
- *
- * Returns the last *Finished* message sent
+ * ssl.finished_message -> string or nil
*
+ * Returns the contents of the last +Finished+ message sent to the peer.
*/
static VALUE
ossl_ssl_get_finished(VALUE self)
{
SSL *ssl;
- char sizer[1], *buf;
+ char sizer[1];
size_t len;
GetSSL(self, ssl);
@@ -2481,23 +2502,23 @@ ossl_ssl_get_finished(VALUE self)
if (len == 0)
return Qnil;
- buf = ALLOCA_N(char, len);
- SSL_get_finished(ssl, buf, len);
- return rb_str_new(buf, len);
+ VALUE str = rb_str_new(NULL, len);
+ SSL_get_finished(ssl, RSTRING_PTR(str), len);
+ return str;
}
/*
* call-seq:
- * ssl.peer_finished_message => "peer finished message"
- *
- * Returns the last *Finished* message received
+ * ssl.peer_finished_message -> string or nil
*
+ * Returns the contents of the last +Finished+ message expected to be sent
+ * by the peer.
*/
static VALUE
ossl_ssl_get_peer_finished(VALUE self)
{
SSL *ssl;
- char sizer[1], *buf;
+ char sizer[1];
size_t len;
GetSSL(self, ssl);
@@ -2506,9 +2527,9 @@ ossl_ssl_get_peer_finished(VALUE self)
if (len == 0)
return Qnil;
- buf = ALLOCA_N(char, len);
- SSL_get_peer_finished(ssl, buf, len);
- return rb_str_new(buf, len);
+ VALUE str = rb_str_new(NULL, len);
+ SSL_get_peer_finished(ssl, RSTRING_PTR(str), len);
+ return str;
}
/*
@@ -2555,9 +2576,9 @@ ossl_ssl_npn_protocol(VALUE self)
SSL_get0_next_proto_negotiated(ssl, &out, &outlen);
if (!outlen)
- return Qnil;
+ return Qnil;
else
- return rb_str_new((const char *) out, outlen);
+ return rb_str_new((const char *) out, outlen);
}
# endif
@@ -2579,9 +2600,9 @@ ossl_ssl_alpn_protocol(VALUE self)
SSL_get0_alpn_selected(ssl, &out, &outlen);
if (!outlen)
- return Qnil;
+ return Qnil;
else
- return rb_str_new((const char *) out, outlen);
+ return rb_str_new((const char *) out, outlen);
}
/*
@@ -2614,15 +2635,15 @@ ossl_ssl_export_keying_material(int argc, VALUE *argv, VALUE self)
str = rb_str_new(0, len);
p = (unsigned char *)RSTRING_PTR(str);
if (!NIL_P(context)) {
- use_ctx = 1;
- StringValue(context);
- ctx = (unsigned char *)RSTRING_PTR(context);
- ctx_len = RSTRING_LEN(context);
+ use_ctx = 1;
+ StringValue(context);
+ ctx = (unsigned char *)RSTRING_PTR(context);
+ ctx_len = RSTRING_LEN(context);
}
ret = SSL_export_keying_material(ssl, p, len, (char *)RSTRING_PTR(label),
- RSTRING_LENINT(label), ctx, ctx_len, use_ctx);
+ RSTRING_LENINT(label), ctx, ctx_len, use_ctx);
if (ret == 0 || ret == -1) {
- ossl_raise(eSSLError, "SSL_export_keying_material");
+ ossl_raise(eSSLError, "SSL_export_keying_material");
}
return str;
}
@@ -2641,7 +2662,7 @@ ossl_ssl_tmp_key(VALUE self)
GetSSL(self, ssl);
if (!SSL_get_server_tmp_key(ssl, &key))
- return Qnil;
+ return Qnil;
return ossl_pkey_wrap(key);
}
@@ -2712,8 +2733,6 @@ void
Init_ossl_ssl(void)
{
#if 0
- mOSSL = rb_define_module("OpenSSL");
- eOSSLError = rb_define_class_under(mOSSL, "OpenSSLError", rb_eStandardError);
rb_mWaitReadable = rb_define_module_under(rb_cIO, "WaitReadable");
rb_mWaitWritable = rb_define_module_under(rb_cIO, "WaitWritable");
#endif
@@ -2724,10 +2743,10 @@ Init_ossl_ssl(void)
ossl_ssl_ex_ptr_idx = SSL_get_ex_new_index(0, (void *)"ossl_ssl_ex_ptr_idx", 0, 0, 0);
if (ossl_ssl_ex_ptr_idx < 0)
- ossl_raise(rb_eRuntimeError, "SSL_get_ex_new_index");
+ ossl_raise(rb_eRuntimeError, "SSL_get_ex_new_index");
ossl_sslctx_ex_ptr_idx = SSL_CTX_get_ex_new_index(0, (void *)"ossl_sslctx_ex_ptr_idx", 0, 0, 0);
if (ossl_sslctx_ex_ptr_idx < 0)
- ossl_raise(rb_eRuntimeError, "SSL_CTX_get_ex_new_index");
+ ossl_raise(rb_eRuntimeError, "SSL_CTX_get_ex_new_index");
/* Document-module: OpenSSL::SSL
*
@@ -2865,6 +2884,23 @@ Init_ossl_ssl(void)
*/
rb_attr(cSSLContext, rb_intern_const("client_cert_cb"), 1, 1, Qfalse);
+#ifndef OPENSSL_NO_DH
+ /*
+ * A callback invoked when DH parameters are required for ephemeral DH key
+ * exchange.
+ *
+ * The callback is invoked with the SSLSocket, a
+ * flag indicating the use of an export cipher and the keylength
+ * required.
+ *
+ * The callback must return an OpenSSL::PKey::DH instance of the correct
+ * key length.
+ *
+ * <b>Deprecated in version 3.0.</b> Use #tmp_dh= instead.
+ */
+ rb_attr(cSSLContext, rb_intern_const("tmp_dh_callback"), 1, 1, Qfalse);
+#endif
+
/*
* Sets the context in which a session can be reused. This allows
* sessions for multiple applications to be distinguished, for example, by
@@ -3258,7 +3294,6 @@ Init_ossl_ssl(void)
sym_wait_readable = ID2SYM(rb_intern_const("wait_readable"));
sym_wait_writable = ID2SYM(rb_intern_const("wait_writable"));
- id_tmp_dh_callback = rb_intern_const("tmp_dh_callback");
id_npn_protocols_encoded = rb_intern_const("npn_protocols_encoded");
id_each = rb_intern_const("each");
@@ -3289,9 +3324,11 @@ Init_ossl_ssl(void)
DefIVarID(servername_cb);
DefIVarID(verify_hostname);
DefIVarID(keylog_cb);
+ DefIVarID(tmp_dh_callback);
DefIVarID(io);
DefIVarID(context);
DefIVarID(hostname);
+ DefIVarID(sync_close);
#endif /* !defined(OPENSSL_NO_SOCK) */
}
diff --git a/ext/openssl/ossl_ssl.h b/ext/openssl/ossl_ssl.h
index a92985c601..a87e62d450 100644
--- a/ext/openssl/ossl_ssl.h
+++ b/ext/openssl/ossl_ssl.h
@@ -11,17 +11,17 @@
#define _OSSL_SSL_H_
#define GetSSL(obj, ssl) do { \
- TypedData_Get_Struct((obj), SSL, &ossl_ssl_type, (ssl)); \
- if (!(ssl)) { \
- ossl_raise(rb_eRuntimeError, "SSL is not initialized"); \
- } \
+ TypedData_Get_Struct((obj), SSL, &ossl_ssl_type, (ssl)); \
+ if (!(ssl)) { \
+ ossl_raise(rb_eRuntimeError, "SSL is not initialized"); \
+ } \
} while (0)
#define GetSSLSession(obj, sess) do { \
- TypedData_Get_Struct((obj), SSL_SESSION, &ossl_ssl_session_type, (sess)); \
- if (!(sess)) { \
- ossl_raise(rb_eRuntimeError, "SSL Session wasn't initialized."); \
- } \
+ TypedData_Get_Struct((obj), SSL_SESSION, &ossl_ssl_session_type, (sess)); \
+ if (!(sess)) { \
+ ossl_raise(rb_eRuntimeError, "SSL Session wasn't initialized."); \
+ } \
} while (0)
extern const rb_data_type_t ossl_ssl_type;
diff --git a/ext/openssl/ossl_ssl_session.c b/ext/openssl/ossl_ssl_session.c
index 55b9d6c6d5..8a2fbf4100 100644
--- a/ext/openssl/ossl_ssl_session.c
+++ b/ext/openssl/ossl_ssl_session.c
@@ -17,14 +17,14 @@ ossl_ssl_session_free(void *ptr)
const rb_data_type_t ossl_ssl_session_type = {
"OpenSSL/SSL/Session",
{
- 0, ossl_ssl_session_free,
+ 0, ossl_ssl_session_free,
},
0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
};
static VALUE ossl_ssl_session_alloc(VALUE klass)
{
- return TypedData_Wrap_Struct(klass, &ossl_ssl_session_type, NULL);
+ return TypedData_Wrap_Struct(klass, &ossl_ssl_session_type, NULL);
}
/*
@@ -80,9 +80,9 @@ ossl_ssl_session_initialize_copy(VALUE self, VALUE other)
GetSSLSession(other, sess_other);
sess_new = ASN1_dup((i2d_of_void *)i2d_SSL_SESSION, (d2i_of_void *)d2i_SSL_SESSION,
- (char *)sess_other);
+ (char *)sess_other);
if (!sess_new)
- ossl_raise(eSSLSession, "ASN1_dup");
+ ossl_raise(eSSLSession, "ASN1_dup");
RTYPEDDATA_DATA(self) = sess_new;
SSL_SESSION_free(sess);
@@ -99,9 +99,9 @@ ossl_SSL_SESSION_cmp(const SSL_SESSION *a, const SSL_SESSION *b)
const unsigned char *b_sid = SSL_SESSION_get_id(b, &b_len);
if (SSL_SESSION_get_protocol_version(a) != SSL_SESSION_get_protocol_version(b))
- return 1;
+ return 1;
if (a_len != b_len)
- return 1;
+ return 1;
return CRYPTO_memcmp(a_sid, b_sid, a_len);
}
@@ -114,15 +114,15 @@ ossl_SSL_SESSION_cmp(const SSL_SESSION *a, const SSL_SESSION *b)
*/
static VALUE ossl_ssl_session_eq(VALUE val1, VALUE val2)
{
- SSL_SESSION *ctx1, *ctx2;
+ SSL_SESSION *ctx1, *ctx2;
- GetSSLSession(val1, ctx1);
- GetSSLSession(val2, ctx2);
+ GetSSLSession(val1, ctx1);
+ GetSSLSession(val2, ctx2);
- switch (ossl_SSL_SESSION_cmp(ctx1, ctx2)) {
- case 0: return Qtrue;
- default: return Qfalse;
- }
+ switch (ossl_SSL_SESSION_cmp(ctx1, ctx2)) {
+ case 0: return Qtrue;
+ default: return Qfalse;
+ }
}
/*
@@ -140,7 +140,7 @@ ossl_ssl_session_get_time(VALUE self)
GetSSLSession(self, ctx);
t = SSL_SESSION_get_time(ctx);
if (t == 0)
- return Qnil;
+ return Qnil;
return rb_funcall(rb_cTime, rb_intern("at"), 1, LONG2NUM(t));
}
@@ -175,16 +175,16 @@ ossl_ssl_session_get_timeout(VALUE self)
*/
static VALUE ossl_ssl_session_set_time(VALUE self, VALUE time_v)
{
- SSL_SESSION *ctx;
- long t;
-
- GetSSLSession(self, ctx);
- if (rb_obj_is_instance_of(time_v, rb_cTime)) {
- time_v = rb_funcall(time_v, rb_intern("to_i"), 0);
- }
- t = NUM2LONG(time_v);
- SSL_SESSION_set_time(ctx, t);
- return ossl_ssl_session_get_time(self);
+ SSL_SESSION *ctx;
+ long t;
+
+ GetSSLSession(self, ctx);
+ if (rb_obj_is_instance_of(time_v, rb_cTime)) {
+ time_v = rb_funcall(time_v, rb_intern("to_i"), 0);
+ }
+ t = NUM2LONG(time_v);
+ SSL_SESSION_set_time(ctx, t);
+ return ossl_ssl_session_get_time(self);
}
/*
@@ -195,13 +195,13 @@ static VALUE ossl_ssl_session_set_time(VALUE self, VALUE time_v)
*/
static VALUE ossl_ssl_session_set_timeout(VALUE self, VALUE time_v)
{
- SSL_SESSION *ctx;
- long t;
+ SSL_SESSION *ctx;
+ long t;
- GetSSLSession(self, ctx);
- t = NUM2LONG(time_v);
- SSL_SESSION_set_timeout(ctx, t);
- return ossl_ssl_session_get_timeout(self);
+ GetSSLSession(self, ctx);
+ t = NUM2LONG(time_v);
+ SSL_SESSION_set_timeout(ctx, t);
+ return ossl_ssl_session_get_timeout(self);
}
/*
@@ -209,18 +209,18 @@ static VALUE ossl_ssl_session_set_timeout(VALUE self, VALUE time_v)
* session.id -> String
*
* Returns the Session ID.
-*/
+ */
static VALUE ossl_ssl_session_get_id(VALUE self)
{
- SSL_SESSION *ctx;
- const unsigned char *p = NULL;
- unsigned int i = 0;
+ SSL_SESSION *ctx;
+ const unsigned char *p = NULL;
+ unsigned int i = 0;
- GetSSLSession(self, ctx);
+ GetSSLSession(self, ctx);
- p = SSL_SESSION_get_id(ctx, &i);
+ p = SSL_SESSION_get_id(ctx, &i);
- return rb_str_new((const char *) p, i);
+ return rb_str_new((const char *) p, i);
}
/*
@@ -231,22 +231,22 @@ static VALUE ossl_ssl_session_get_id(VALUE self)
*/
static VALUE ossl_ssl_session_to_der(VALUE self)
{
- SSL_SESSION *ctx;
- unsigned char *p;
- int len;
- VALUE str;
-
- GetSSLSession(self, ctx);
- len = i2d_SSL_SESSION(ctx, NULL);
- if (len <= 0) {
- ossl_raise(eSSLSession, "i2d_SSL_SESSION");
- }
-
- str = rb_str_new(0, len);
- p = (unsigned char *)RSTRING_PTR(str);
- i2d_SSL_SESSION(ctx, &p);
- ossl_str_adjust(str, p);
- return str;
+ SSL_SESSION *ctx;
+ unsigned char *p;
+ int len;
+ VALUE str;
+
+ GetSSLSession(self, ctx);
+ len = i2d_SSL_SESSION(ctx, NULL);
+ if (len <= 0) {
+ ossl_raise(eSSLSession, "i2d_SSL_SESSION");
+ }
+
+ str = rb_str_new(0, len);
+ p = (unsigned char *)RSTRING_PTR(str);
+ i2d_SSL_SESSION(ctx, &p);
+ ossl_str_adjust(str, p);
+ return str;
}
/*
@@ -257,22 +257,22 @@ static VALUE ossl_ssl_session_to_der(VALUE self)
*/
static VALUE ossl_ssl_session_to_pem(VALUE self)
{
- SSL_SESSION *ctx;
- BIO *out;
+ SSL_SESSION *ctx;
+ BIO *out;
- GetSSLSession(self, ctx);
+ GetSSLSession(self, ctx);
- if (!(out = BIO_new(BIO_s_mem()))) {
- ossl_raise(eSSLSession, "BIO_s_mem()");
- }
+ if (!(out = BIO_new(BIO_s_mem()))) {
+ ossl_raise(eSSLSession, "BIO_s_mem()");
+ }
- if (!PEM_write_bio_SSL_SESSION(out, ctx)) {
- BIO_free(out);
- ossl_raise(eSSLSession, "SSL_SESSION_print()");
- }
+ if (!PEM_write_bio_SSL_SESSION(out, ctx)) {
+ BIO_free(out);
+ ossl_raise(eSSLSession, "SSL_SESSION_print()");
+ }
- return ossl_membio2str(out);
+ return ossl_membio2str(out);
}
@@ -284,49 +284,44 @@ static VALUE ossl_ssl_session_to_pem(VALUE self)
*/
static VALUE ossl_ssl_session_to_text(VALUE self)
{
- SSL_SESSION *ctx;
- BIO *out;
+ SSL_SESSION *ctx;
+ BIO *out;
- GetSSLSession(self, ctx);
+ GetSSLSession(self, ctx);
- if (!(out = BIO_new(BIO_s_mem()))) {
- ossl_raise(eSSLSession, "BIO_s_mem()");
- }
+ if (!(out = BIO_new(BIO_s_mem()))) {
+ ossl_raise(eSSLSession, "BIO_s_mem()");
+ }
- if (!SSL_SESSION_print(out, ctx)) {
- BIO_free(out);
- ossl_raise(eSSLSession, "SSL_SESSION_print()");
- }
+ if (!SSL_SESSION_print(out, ctx)) {
+ BIO_free(out);
+ ossl_raise(eSSLSession, "SSL_SESSION_print()");
+ }
- return ossl_membio2str(out);
+ return ossl_membio2str(out);
}
#endif /* !defined(OPENSSL_NO_SOCK) */
void Init_ossl_ssl_session(void)
{
-#if 0
- mOSSL = rb_define_module("OpenSSL");
- mSSL = rb_define_module_under(mOSSL, "SSL");
- eOSSLError = rb_define_class_under(mOSSL, "OpenSSLError", rb_eStandardError);
-#endif
#ifndef OPENSSL_NO_SOCK
- cSSLSession = rb_define_class_under(mSSL, "Session", rb_cObject);
- eSSLSession = rb_define_class_under(cSSLSession, "SessionError", eOSSLError);
-
- rb_define_alloc_func(cSSLSession, ossl_ssl_session_alloc);
- rb_define_method(cSSLSession, "initialize", ossl_ssl_session_initialize, 1);
- rb_define_method(cSSLSession, "initialize_copy", ossl_ssl_session_initialize_copy, 1);
-
- rb_define_method(cSSLSession, "==", ossl_ssl_session_eq, 1);
-
- rb_define_method(cSSLSession, "time", ossl_ssl_session_get_time, 0);
- rb_define_method(cSSLSession, "time=", ossl_ssl_session_set_time, 1);
- rb_define_method(cSSLSession, "timeout", ossl_ssl_session_get_timeout, 0);
- rb_define_method(cSSLSession, "timeout=", ossl_ssl_session_set_timeout, 1);
- rb_define_method(cSSLSession, "id", ossl_ssl_session_get_id, 0);
- rb_define_method(cSSLSession, "to_der", ossl_ssl_session_to_der, 0);
- rb_define_method(cSSLSession, "to_pem", ossl_ssl_session_to_pem, 0);
- rb_define_method(cSSLSession, "to_text", ossl_ssl_session_to_text, 0);
+ cSSLSession = rb_define_class_under(mSSL, "Session", rb_cObject);
+ eSSLSession = rb_define_class_under(cSSLSession, "SessionError", eOSSLError);
+
+ rb_define_alloc_func(cSSLSession, ossl_ssl_session_alloc);
+ rb_define_method(cSSLSession, "initialize", ossl_ssl_session_initialize, 1);
+ rb_define_method(cSSLSession, "initialize_copy", ossl_ssl_session_initialize_copy, 1);
+
+ rb_define_method(cSSLSession, "==", ossl_ssl_session_eq, 1);
+
+ rb_define_method(cSSLSession, "time", ossl_ssl_session_get_time, 0);
+ rb_define_method(cSSLSession, "time=", ossl_ssl_session_set_time, 1);
+ rb_define_method(cSSLSession, "timeout", ossl_ssl_session_get_timeout, 0);
+ rb_define_method(cSSLSession, "timeout=", ossl_ssl_session_set_timeout, 1);
+ rb_define_method(cSSLSession, "id", ossl_ssl_session_get_id, 0);
+ rb_define_method(cSSLSession, "to_der", ossl_ssl_session_to_der, 0);
+ rb_define_method(cSSLSession, "to_pem", ossl_ssl_session_to_pem, 0);
+ rb_define_method(cSSLSession, "to_text", ossl_ssl_session_to_text, 0);
#endif /* !defined(OPENSSL_NO_SOCK) */
}
diff --git a/ext/openssl/ossl_ts.c b/ext/openssl/ossl_ts.c
index c7d2bd271b..317f7786aa 100644
--- a/ext/openssl/ossl_ts.c
+++ b/ext/openssl/ossl_ts.c
@@ -103,7 +103,7 @@ static const rb_data_type_t ossl_ts_resp_type = {
static void
ossl_ts_token_info_free(void *ptr)
{
- TS_TST_INFO_free(ptr);
+ TS_TST_INFO_free(ptr);
}
static const rb_data_type_t ossl_ts_token_info_type = {
@@ -132,44 +132,10 @@ asn1_to_der(void *template, int (*i2d)(void *template, unsigned char **pp))
return str;
}
-static ASN1_OBJECT*
-obj_to_asn1obj(VALUE obj)
-{
- ASN1_OBJECT *a1obj;
-
- StringValue(obj);
- a1obj = OBJ_txt2obj(RSTRING_PTR(obj), 0);
- if(!a1obj) a1obj = OBJ_txt2obj(RSTRING_PTR(obj), 1);
- if(!a1obj) ossl_raise(eASN1Error, "invalid OBJECT ID");
-
- return a1obj;
-}
-
static VALUE
obj_to_asn1obj_i(VALUE obj)
{
- return (VALUE)obj_to_asn1obj(obj);
-}
-
-static VALUE
-get_asn1obj(const ASN1_OBJECT *obj)
-{
- BIO *out;
- VALUE ret;
- int nid;
- if ((nid = OBJ_obj2nid(obj)) != NID_undef)
- ret = rb_str_new2(OBJ_nid2sn(nid));
- else{
- if (!(out = BIO_new(BIO_s_mem())))
- ossl_raise(eTimestampError, "BIO_new(BIO_s_mem())");
- if (i2a_ASN1_OBJECT(out, obj) <= 0) {
- BIO_free(out);
- ossl_raise(eTimestampError, "i2a_ASN1_OBJECT");
- }
- ret = ossl_membio2str(out);
- }
-
- return ret;
+ return (VALUE)ossl_to_asn1obj(obj);
}
static VALUE
@@ -202,7 +168,7 @@ ossl_ts_req_alloc(VALUE klass)
static VALUE
ossl_ts_req_initialize(int argc, VALUE *argv, VALUE self)
{
- TS_REQ *ts_req = DATA_PTR(self);
+ TS_REQ *req, *req_orig = DATA_PTR(self);
BIO *in;
VALUE arg;
@@ -212,13 +178,14 @@ ossl_ts_req_initialize(int argc, VALUE *argv, VALUE self)
arg = ossl_to_der_if_possible(arg);
in = ossl_obj2bio(&arg);
- ts_req = d2i_TS_REQ_bio(in, &ts_req);
+ req = d2i_TS_REQ_bio(in, NULL);
BIO_free(in);
- if (!ts_req) {
- DATA_PTR(self) = NULL;
- ossl_raise(eTimestampError, "Error when decoding the timestamp request");
+ if (!req) {
+ ossl_raise(eTimestampError,
+ "Error when decoding the timestamp request");
}
- DATA_PTR(self) = ts_req;
+ TS_REQ_free(req_orig);
+ RTYPEDDATA_DATA(self) = req;
return self;
}
@@ -242,7 +209,7 @@ ossl_ts_req_get_algorithm(VALUE self)
mi = TS_REQ_get_msg_imprint(req);
algor = TS_MSG_IMPRINT_get_algo(mi);
X509_ALGOR_get0(&obj, NULL, NULL, algor);
- return get_asn1obj(obj);
+ return ossl_asn1obj_to_string(obj);
}
/*
@@ -264,7 +231,7 @@ ossl_ts_req_set_algorithm(VALUE self, VALUE algo)
X509_ALGOR *algor;
GetTSRequest(self, req);
- obj = obj_to_asn1obj(algo);
+ obj = ossl_to_asn1obj(algo);
mi = TS_REQ_get_msg_imprint(req);
algor = TS_MSG_IMPRINT_get_algo(mi);
if (!X509_ALGOR_set0(algor, obj, V_ASN1_NULL, NULL)) {
@@ -293,7 +260,7 @@ ossl_ts_req_get_msg_imprint(VALUE self)
mi = TS_REQ_get_msg_imprint(req);
hashed_msg = TS_MSG_IMPRINT_get_msg(mi);
- ret = rb_str_new((const char *)hashed_msg->data, hashed_msg->length);
+ ret = asn1str_to_str(hashed_msg);
return ret;
}
@@ -371,7 +338,7 @@ ossl_ts_req_get_policy_id(VALUE self)
GetTSRequest(self, req);
if (!TS_REQ_get_policy_id(req))
return Qnil;
- return get_asn1obj(TS_REQ_get_policy_id(req));
+ return ossl_asn1obj_to_string(TS_REQ_get_policy_id(req));
}
/*
@@ -394,7 +361,7 @@ ossl_ts_req_set_policy_id(VALUE self, VALUE oid)
int ok;
GetTSRequest(self, req);
- obj = obj_to_asn1obj(oid);
+ obj = ossl_to_asn1obj(oid);
ok = TS_REQ_set_policy_id(req, obj);
ASN1_OBJECT_free(obj);
if (!ok)
@@ -504,7 +471,7 @@ ossl_ts_req_to_der(VALUE self)
ossl_raise(eTimestampError, "Message imprint missing algorithm");
hashed_msg = TS_MSG_IMPRINT_get_msg(mi);
- if (!hashed_msg->length)
+ if (!ASN1_STRING_length(hashed_msg))
ossl_raise(eTimestampError, "Message imprint missing hashed message");
return asn1_to_der((void *)req, (int (*)(void *, unsigned char **))i2d_TS_REQ);
@@ -556,18 +523,19 @@ ossl_ts_resp_alloc(VALUE klass)
static VALUE
ossl_ts_resp_initialize(VALUE self, VALUE der)
{
- TS_RESP *ts_resp = DATA_PTR(self);
+ TS_RESP *resp, *resp_orig = DATA_PTR(self);
BIO *in;
der = ossl_to_der_if_possible(der);
- in = ossl_obj2bio(&der);
- ts_resp = d2i_TS_RESP_bio(in, &ts_resp);
+ in = ossl_obj2bio(&der);
+ resp = d2i_TS_RESP_bio(in, NULL);
BIO_free(in);
- if (!ts_resp) {
- DATA_PTR(self) = NULL;
- ossl_raise(eTimestampError, "Error when decoding the timestamp response");
+ if (!resp) {
+ ossl_raise(eTimestampError,
+ "Error when decoding the timestamp response");
}
- DATA_PTR(self) = ts_resp;
+ TS_RESP_free(resp_orig);
+ RTYPEDDATA_DATA(self) = resp;
return self;
}
@@ -740,7 +708,7 @@ ossl_ts_resp_get_tsa_certificate(VALUE self)
TS_RESP *resp;
PKCS7 *p7;
PKCS7_SIGNER_INFO *ts_info;
- X509 *cert;
+ const X509 *cert;
GetTSResponse(self, resp);
if (!(p7 = TS_RESP_get_token(resp)))
@@ -910,18 +878,19 @@ ossl_ts_token_info_alloc(VALUE klass)
static VALUE
ossl_ts_token_info_initialize(VALUE self, VALUE der)
{
- TS_TST_INFO *info = DATA_PTR(self);
+ TS_TST_INFO *info, *info_orig = DATA_PTR(self);
BIO *in;
der = ossl_to_der_if_possible(der);
- in = ossl_obj2bio(&der);
- info = d2i_TS_TST_INFO_bio(in, &info);
+ in = ossl_obj2bio(&der);
+ info = d2i_TS_TST_INFO_bio(in, NULL);
BIO_free(in);
if (!info) {
- DATA_PTR(self) = NULL;
- ossl_raise(eTimestampError, "Error when decoding the timestamp token info");
+ ossl_raise(eTimestampError,
+ "Error when decoding the timestamp token info");
}
- DATA_PTR(self) = info;
+ TS_TST_INFO_free(info_orig);
+ RTYPEDDATA_DATA(self) = info;
return self;
}
@@ -961,7 +930,7 @@ ossl_ts_token_info_get_policy_id(VALUE self)
TS_TST_INFO *info;
GetTSTokenInfo(self, info);
- return get_asn1obj(TS_TST_INFO_get_policy_id(info));
+ return ossl_asn1obj_to_string(TS_TST_INFO_get_policy_id(info));
}
/*
@@ -989,7 +958,7 @@ ossl_ts_token_info_get_algorithm(VALUE self)
mi = TS_TST_INFO_get_msg_imprint(info);
algo = TS_MSG_IMPRINT_get_algo(mi);
X509_ALGOR_get0(&obj, NULL, NULL, algo);
- return get_asn1obj(obj);
+ return ossl_asn1obj_to_string(obj);
}
/*
@@ -1015,7 +984,7 @@ ossl_ts_token_info_get_msg_imprint(VALUE self)
GetTSTokenInfo(self, info);
mi = TS_TST_INFO_get_msg_imprint(info);
hashed_msg = TS_MSG_IMPRINT_get_msg(mi);
- ret = rb_str_new((const char *)hashed_msg->data, hashed_msg->length);
+ ret = asn1str_to_str(hashed_msg);
return ret;
}
@@ -1155,9 +1124,14 @@ ossl_tsfac_time_cb(struct TS_resp_ctx *ctx, void *data, time_t *sec, long *usec)
}
static VALUE
-ossl_evp_get_digestbyname_i(VALUE arg)
+ossl_evp_md_fetch_i(VALUE args_)
{
- return (VALUE)ossl_evp_get_digestbyname(arg);
+ VALUE *args = (VALUE *)args_, md_holder;
+ const EVP_MD *md;
+
+ md = ossl_evp_md_fetch(args[1], &md_holder);
+ rb_ary_push(args[0], md_holder);
+ return (VALUE)md;
}
static VALUE
@@ -1193,7 +1167,8 @@ ossl_obj2bio_i(VALUE arg)
static VALUE
ossl_tsfac_create_ts(VALUE self, VALUE key, VALUE certificate, VALUE request)
{
- VALUE serial_number, def_policy_id, gen_time, additional_certs, allowed_digests;
+ VALUE serial_number, def_policy_id, gen_time, additional_certs,
+ allowed_digests, allowed_digests_tmp = Qnil;
VALUE str;
STACK_OF(X509) *inter_certs;
VALUE tsresp, ret = Qnil;
@@ -1254,7 +1229,7 @@ ossl_tsfac_create_ts(VALUE self, VALUE key, VALUE certificate, VALUE request)
if (rb_obj_is_kind_of(additional_certs, rb_cArray)) {
inter_certs = ossl_protect_x509_ary2sk(additional_certs, &status);
if (status)
- goto end;
+ goto end;
/* this dups the sk_X509 and ups each cert's ref count */
TS_RESP_CTX_set_certs(ctx, inter_certs);
@@ -1270,16 +1245,18 @@ ossl_tsfac_create_ts(VALUE self, VALUE key, VALUE certificate, VALUE request)
allowed_digests = ossl_tsfac_get_allowed_digests(self);
if (rb_obj_is_kind_of(allowed_digests, rb_cArray)) {
- int i;
- VALUE rbmd;
- const EVP_MD *md;
-
- for (i = 0; i < RARRAY_LEN(allowed_digests); i++) {
- rbmd = rb_ary_entry(allowed_digests, i);
- md = (const EVP_MD *)rb_protect(ossl_evp_get_digestbyname_i, rbmd, &status);
+ allowed_digests_tmp = rb_ary_new_capa(RARRAY_LEN(allowed_digests));
+ for (long i = 0; i < RARRAY_LEN(allowed_digests); i++) {
+ VALUE args[] = {
+ allowed_digests_tmp,
+ rb_ary_entry(allowed_digests, i),
+ };
+ const EVP_MD *md = (const EVP_MD *)rb_protect(ossl_evp_md_fetch_i,
+ (VALUE)args, &status);
if (status)
goto end;
- TS_RESP_CTX_add_md(ctx, md);
+ if (!TS_RESP_CTX_add_md(ctx, md))
+ goto end;
}
}
@@ -1293,6 +1270,7 @@ ossl_tsfac_create_ts(VALUE self, VALUE key, VALUE certificate, VALUE request)
response = TS_RESP_create_response(ctx, req_bio);
BIO_free(req_bio);
+ RB_GC_GUARD(allowed_digests_tmp);
if (!response) {
err_msg = "Error during response generation";
@@ -1306,7 +1284,7 @@ ossl_tsfac_create_ts(VALUE self, VALUE key, VALUE certificate, VALUE request)
SetTSResponse(tsresp, response);
ret = tsresp;
-end:
+ end:
ASN1_INTEGER_free(asn1_serial);
ASN1_OBJECT_free(def_policy_id_obj);
TS_RESP_CTX_free(ctx);
@@ -1323,10 +1301,6 @@ end:
void
Init_ossl_ts(void)
{
- #if 0
- mOSSL = rb_define_module("OpenSSL"); /* let rdoc know about mOSSL */
- #endif
-
/*
* Possible return value for +Response#failure_info+. Indicates that the
* timestamp server rejects the message imprint algorithm used in the
@@ -1536,65 +1510,39 @@ Init_ossl_ts(void)
* fac.default_policy_id = '1.2.3.4.5'
* fac.additional_certificates = [ inter1, inter2 ]
* timestamp = fac.create_timestamp(p12.key, p12.certificate, req)
- *
- * ==Attributes
- *
- * ===default_policy_id
+ */
+ cTimestampFactory = rb_define_class_under(mTimestamp, "Factory", rb_cObject);
+ /*
+ * The list of digest algorithms that the factory is allowed
+ * create timestamps for. Known vulnerable or weak algorithms should not be
+ * allowed where possible. Must be an Array of String or OpenSSL::Digest
+ * subclass instances.
+ */
+ rb_attr(cTimestampFactory, rb_intern_const("allowed_digests"), 1, 1, 0);
+ /*
+ * A String representing the default policy object identifier, or +nil+.
*
* Request#policy_id will always be preferred over this if present in the
- * Request, only if Request#policy_id is nil default_policy will be used.
+ * Request, only if Request#policy_id is +nil+ default_policy will be used.
* If none of both is present, a TimestampError will be raised when trying
* to create a Response.
- *
- * call-seq:
- * factory.default_policy_id = "string" -> string
- * factory.default_policy_id -> string or nil
- *
- * ===serial_number
- *
- * Sets or retrieves the serial number to be used for timestamp creation.
- * Must be present for timestamp creation.
- *
- * call-seq:
- * factory.serial_number = number -> number
- * factory.serial_number -> number or nil
- *
- * ===gen_time
- *
- * Sets or retrieves the Time value to be used in the Response. Must be
- * present for timestamp creation.
- *
- * call-seq:
- * factory.gen_time = Time -> Time
- * factory.gen_time -> Time or nil
- *
- * ===additional_certs
- *
- * Sets or retrieves additional certificates apart from the timestamp
- * certificate (e.g. intermediate certificates) to be added to the Response.
- * Must be an Array of OpenSSL::X509::Certificate.
- *
- * call-seq:
- * factory.additional_certs = [cert1, cert2] -> [ cert1, cert2 ]
- * factory.additional_certs -> array or nil
- *
- * ===allowed_digests
- *
- * Sets or retrieves the digest algorithms that the factory is allowed
- * create timestamps for. Known vulnerable or weak algorithms should not be
- * allowed where possible.
- * Must be an Array of String or OpenSSL::Digest subclass instances.
- *
- * call-seq:
- * factory.allowed_digests = ["sha1", OpenSSL::Digest.new('SHA256').new] -> [ "sha1", OpenSSL::Digest) ]
- * factory.allowed_digests -> array or nil
- *
*/
- cTimestampFactory = rb_define_class_under(mTimestamp, "Factory", rb_cObject);
- rb_attr(cTimestampFactory, rb_intern_const("allowed_digests"), 1, 1, 0);
rb_attr(cTimestampFactory, rb_intern_const("default_policy_id"), 1, 1, 0);
+ /*
+ * The serial number to be used for timestamp creation. Must be present for
+ * timestamp creation. Must be an instance of OpenSSL::BN or Integer.
+ */
rb_attr(cTimestampFactory, rb_intern_const("serial_number"), 1, 1, 0);
+ /*
+ * The Time value to be used in the Response. Must be present for timestamp
+ * creation.
+ */
rb_attr(cTimestampFactory, rb_intern_const("gen_time"), 1, 1, 0);
+ /*
+ * Additional certificates apart from the timestamp certificate (e.g.
+ * intermediate certificates) to be added to the Response.
+ * Must be an Array of OpenSSL::X509::Certificate, or +nil+.
+ */
rb_attr(cTimestampFactory, rb_intern_const("additional_certs"), 1, 1, 0);
rb_define_method(cTimestampFactory, "create_timestamp", ossl_tsfac_create_ts, 3);
}
diff --git a/ext/openssl/ossl_x509.c b/ext/openssl/ossl_x509.c
index 2d552d7847..bc3914fda2 100644
--- a/ext/openssl/ossl_x509.c
+++ b/ext/openssl/ossl_x509.c
@@ -13,7 +13,8 @@ VALUE mX509;
#define DefX509Const(x) rb_define_const(mX509, #x, INT2NUM(X509_##x))
#define DefX509Default(x,i) \
- rb_define_const(mX509, "DEFAULT_" #x, rb_str_new2(X509_get_default_##i()))
+ rb_define_const(mX509, "DEFAULT_" #x, \
+ rb_obj_freeze(rb_str_new_cstr(X509_get_default_##i())))
ASN1_TIME *
ossl_x509_time_adjust(ASN1_TIME *s, VALUE time)
@@ -29,10 +30,6 @@ ossl_x509_time_adjust(ASN1_TIME *s, VALUE time)
void
Init_ossl_x509(void)
{
-#if 0
- mOSSL = rb_define_module("OpenSSL");
-#endif
-
mX509 = rb_define_module_under(mOSSL, "X509");
Init_ossl_x509attr();
diff --git a/ext/openssl/ossl_x509.h b/ext/openssl/ossl_x509.h
index d25167ee7b..71932ef1a9 100644
--- a/ext/openssl/ossl_x509.h
+++ b/ext/openssl/ossl_x509.h
@@ -29,7 +29,7 @@ void Init_ossl_x509(void);
*/
extern VALUE cX509Attr;
-VALUE ossl_x509attr_new(X509_ATTRIBUTE *);
+VALUE ossl_x509attr_new(const X509_ATTRIBUTE *);
X509_ATTRIBUTE *GetX509AttrPtr(VALUE);
void Init_ossl_x509attr(void);
@@ -38,7 +38,7 @@ void Init_ossl_x509attr(void);
*/
extern VALUE cX509Cert;
-VALUE ossl_x509_new(X509 *);
+VALUE ossl_x509_new(const X509 *);
X509 *GetX509CertPtr(VALUE);
X509 *DupX509CertPtr(VALUE);
void Init_ossl_x509cert(void);
@@ -46,7 +46,7 @@ void Init_ossl_x509cert(void);
/*
* X509CRL
*/
-VALUE ossl_x509crl_new(X509_CRL *);
+VALUE ossl_x509crl_new(const X509_CRL *);
X509_CRL *GetX509CRLPtr(VALUE);
void Init_ossl_x509crl(void);
@@ -55,14 +55,14 @@ void Init_ossl_x509crl(void);
*/
extern VALUE cX509Ext;
-VALUE ossl_x509ext_new(X509_EXTENSION *);
+VALUE ossl_x509ext_new(const X509_EXTENSION *);
X509_EXTENSION *GetX509ExtPtr(VALUE);
void Init_ossl_x509ext(void);
/*
* X509Name
*/
-VALUE ossl_x509name_new(X509_NAME *);
+VALUE ossl_x509name_new(const X509_NAME *);
X509_NAME *GetX509NamePtr(VALUE);
void Init_ossl_x509name(void);
@@ -77,7 +77,7 @@ void Init_ossl_x509req(void);
*/
extern VALUE cX509Rev;
-VALUE ossl_x509revoked_new(X509_REVOKED *);
+VALUE ossl_x509revoked_new(const X509_REVOKED *);
X509_REVOKED *DupX509RevokedPtr(VALUE);
void Init_ossl_x509revoked(void);
diff --git a/ext/openssl/ossl_x509attr.c b/ext/openssl/ossl_x509attr.c
index d983af5968..38600b9b00 100644
--- a/ext/openssl/ossl_x509attr.c
+++ b/ext/openssl/ossl_x509attr.c
@@ -13,14 +13,14 @@
TypedData_Wrap_Struct((klass), &ossl_x509attr_type, 0)
#define SetX509Attr(obj, attr) do { \
if (!(attr)) { \
- ossl_raise(rb_eRuntimeError, "ATTR wasn't initialized!"); \
+ ossl_raise(rb_eRuntimeError, "ATTR wasn't initialized!"); \
} \
RTYPEDDATA_DATA(obj) = (attr); \
} while (0)
#define GetX509Attr(obj, attr) do { \
TypedData_Get_Struct((obj), X509_ATTRIBUTE, &ossl_x509attr_type, (attr)); \
if (!(attr)) { \
- ossl_raise(rb_eRuntimeError, "ATTR wasn't initialized!"); \
+ ossl_raise(rb_eRuntimeError, "ATTR wasn't initialized!"); \
} \
} while (0)
@@ -39,7 +39,7 @@ ossl_x509attr_free(void *ptr)
static const rb_data_type_t ossl_x509attr_type = {
"OpenSSL/X509/ATTRIBUTE",
{
- 0, ossl_x509attr_free,
+ 0, ossl_x509attr_free,
},
0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
};
@@ -48,13 +48,14 @@ static const rb_data_type_t ossl_x509attr_type = {
* Public
*/
VALUE
-ossl_x509attr_new(X509_ATTRIBUTE *attr)
+ossl_x509attr_new(const X509_ATTRIBUTE *attr)
{
X509_ATTRIBUTE *new;
VALUE obj;
obj = NewX509Attr(cX509Attr);
- new = X509_ATTRIBUTE_dup(attr);
+ /* OpenSSL 1.1.1 takes a non-const pointer */
+ new = X509_ATTRIBUTE_dup((X509_ATTRIBUTE *)attr);
if (!new)
ossl_raise(eX509AttrError, "X509_ATTRIBUTE_dup");
SetX509Attr(obj, new);
@@ -83,7 +84,7 @@ ossl_x509attr_alloc(VALUE klass)
obj = NewX509Attr(klass);
if (!(attr = X509_ATTRIBUTE_new()))
- ossl_raise(eX509AttrError, NULL);
+ ossl_raise(eX509AttrError, NULL);
SetX509Attr(obj, attr);
return obj;
@@ -102,15 +103,15 @@ ossl_x509attr_initialize(int argc, VALUE *argv, VALUE self)
GetX509Attr(self, attr);
if(rb_scan_args(argc, argv, "11", &oid, &value) == 1){
- oid = ossl_to_der_if_possible(oid);
- StringValue(oid);
- p = (unsigned char *)RSTRING_PTR(oid);
- x = d2i_X509_ATTRIBUTE(&attr, &p, RSTRING_LEN(oid));
- DATA_PTR(self) = attr;
- if(!x){
- ossl_raise(eX509AttrError, NULL);
- }
- return self;
+ oid = ossl_to_der_if_possible(oid);
+ StringValue(oid);
+ p = (unsigned char *)RSTRING_PTR(oid);
+ x = d2i_X509_ATTRIBUTE(&attr, &p, RSTRING_LEN(oid));
+ DATA_PTR(self) = attr;
+ if(!x){
+ ossl_raise(eX509AttrError, NULL);
+ }
+ return self;
}
rb_funcall(self, rb_intern("oid="), 1, oid);
rb_funcall(self, rb_intern("value="), 1, value);
@@ -130,7 +131,7 @@ ossl_x509attr_initialize_copy(VALUE self, VALUE other)
attr_new = X509_ATTRIBUTE_dup(attr_other);
if (!attr_new)
- ossl_raise(eX509AttrError, "X509_ATTRIBUTE_dup");
+ ossl_raise(eX509AttrError, "X509_ATTRIBUTE_dup");
SetX509Attr(self, attr_new);
X509_ATTRIBUTE_free(attr);
@@ -154,8 +155,8 @@ ossl_x509attr_set_oid(VALUE self, VALUE oid)
obj = OBJ_txt2obj(s, 0);
if(!obj) ossl_raise(eX509AttrError, NULL);
if (!X509_ATTRIBUTE_set1_object(attr, obj)) {
- ASN1_OBJECT_free(obj);
- ossl_raise(eX509AttrError, "X509_ATTRIBUTE_set1_object");
+ ASN1_OBJECT_free(obj);
+ ossl_raise(eX509AttrError, "X509_ATTRIBUTE_set1_object");
}
ASN1_OBJECT_free(obj);
@@ -164,29 +165,18 @@ ossl_x509attr_set_oid(VALUE self, VALUE oid)
/*
* call-seq:
- * attr.oid => string
+ * attr.oid -> string
+ *
+ * Returns the OID of the attribute. Returns the short name or the dotted
+ * decimal notation.
*/
static VALUE
ossl_x509attr_get_oid(VALUE self)
{
X509_ATTRIBUTE *attr;
- ASN1_OBJECT *oid;
- BIO *out;
- VALUE ret;
- int nid;
GetX509Attr(self, attr);
- oid = X509_ATTRIBUTE_get0_object(attr);
- if ((nid = OBJ_obj2nid(oid)) != NID_undef)
- ret = rb_str_new2(OBJ_nid2sn(nid));
- else{
- if (!(out = BIO_new(BIO_s_mem())))
- ossl_raise(eX509AttrError, NULL);
- i2a_ASN1_OBJECT(out, oid);
- ret = ossl_membio2str(out);
- }
-
- return ret;
+ return ossl_asn1obj_to_string(X509_ATTRIBUTE_get0_object(attr));
}
/*
@@ -207,7 +197,7 @@ ossl_x509attr_set_value(VALUE self, VALUE value)
ossl_raise(eX509AttrError, "attribute value must be ASN1::Set");
if (X509_ATTRIBUTE_count(attr)) { /* populated, reset first */
- ASN1_OBJECT *obj = X509_ATTRIBUTE_get0_object(attr);
+ const 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);
@@ -245,23 +235,32 @@ ossl_x509attr_get_value(VALUE self)
unsigned char *p;
GetX509Attr(self, attr);
+ count = X509_ATTRIBUTE_count(attr);
/* there is no X509_ATTRIBUTE_get0_set() :( */
+#ifdef HAVE_OPENSSL_SK_NEW_RESERVE
+ if (!(sk = sk_ASN1_TYPE_new_reserve(NULL, count)))
+ ossl_raise(eX509AttrError, "sk_new_reserve");
+#else
if (!(sk = sk_ASN1_TYPE_new_null()))
- ossl_raise(eX509AttrError, "sk_new");
+ ossl_raise(eX509AttrError, "sk_new");
+#endif
- count = X509_ATTRIBUTE_count(attr);
- for (i = 0; i < count; i++)
- sk_ASN1_TYPE_push(sk, X509_ATTRIBUTE_get0_type(attr, i));
+ for (i = 0; i < count; i++) {
+ if (!sk_ASN1_TYPE_push(sk, (ASN1_TYPE *)X509_ATTRIBUTE_get0_type(attr, i))) {
+ sk_ASN1_TYPE_free(sk);
+ ossl_raise(eX509AttrError, NULL);
+ }
+ }
if ((len = i2d_ASN1_SET_ANY(sk, NULL)) <= 0) {
- sk_ASN1_TYPE_free(sk);
- ossl_raise(eX509AttrError, NULL);
+ sk_ASN1_TYPE_free(sk);
+ ossl_raise(eX509AttrError, NULL);
}
str = rb_str_new(0, len);
p = (unsigned char *)RSTRING_PTR(str);
if (i2d_ASN1_SET_ANY(sk, &p) <= 0) {
- sk_ASN1_TYPE_free(sk);
- ossl_raise(eX509AttrError, NULL);
+ sk_ASN1_TYPE_free(sk);
+ ossl_raise(eX509AttrError, NULL);
}
ossl_str_adjust(str, p);
sk_ASN1_TYPE_free(sk);
@@ -283,11 +282,11 @@ ossl_x509attr_to_der(VALUE self)
GetX509Attr(self, attr);
if((len = i2d_X509_ATTRIBUTE(attr, NULL)) <= 0)
- ossl_raise(eX509AttrError, NULL);
+ ossl_raise(eX509AttrError, NULL);
str = rb_str_new(0, len);
p = (unsigned char *)RSTRING_PTR(str);
if(i2d_X509_ATTRIBUTE(attr, &p) <= 0)
- ossl_raise(eX509AttrError, NULL);
+ ossl_raise(eX509AttrError, NULL);
ossl_str_adjust(str, p);
return str;
@@ -299,12 +298,6 @@ ossl_x509attr_to_der(VALUE self)
void
Init_ossl_x509attr(void)
{
-#if 0
- mOSSL = rb_define_module("OpenSSL");
- eOSSLError = rb_define_class_under(mOSSL, "OpenSSLError", rb_eStandardError);
- mX509 = rb_define_module_under(mOSSL, "X509");
-#endif
-
eX509AttrError = rb_define_class_under(mX509, "AttributeError", eOSSLError);
cX509Attr = rb_define_class_under(mX509, "Attribute", rb_cObject);
diff --git a/ext/openssl/ossl_x509cert.c b/ext/openssl/ossl_x509cert.c
index 30e3c61753..08dd184a0c 100644
--- a/ext/openssl/ossl_x509cert.c
+++ b/ext/openssl/ossl_x509cert.c
@@ -13,14 +13,14 @@
TypedData_Wrap_Struct((klass), &ossl_x509_type, 0)
#define SetX509(obj, x509) do { \
if (!(x509)) { \
- ossl_raise(rb_eRuntimeError, "CERT wasn't initialized!"); \
+ ossl_raise(rb_eRuntimeError, "CERT wasn't initialized!"); \
} \
RTYPEDDATA_DATA(obj) = (x509); \
} while (0)
#define GetX509(obj, x509) do { \
TypedData_Get_Struct((obj), X509, &ossl_x509_type, (x509)); \
if (!(x509)) { \
- ossl_raise(rb_eRuntimeError, "CERT wasn't initialized!"); \
+ ossl_raise(rb_eRuntimeError, "CERT wasn't initialized!"); \
} \
} while (0)
@@ -39,7 +39,7 @@ ossl_x509_free(void *ptr)
static const rb_data_type_t ossl_x509_type = {
"OpenSSL/X509",
{
- 0, ossl_x509_free,
+ 0, ossl_x509_free,
},
0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
};
@@ -48,13 +48,14 @@ static const rb_data_type_t ossl_x509_type = {
* Public
*/
VALUE
-ossl_x509_new(X509 *x509)
+ossl_x509_new(const X509 *x509)
{
X509 *new;
VALUE obj;
obj = NewX509(cX509Cert);
- new = X509_dup(x509);
+ /* OpenSSL 1.1.1 takes a non-const pointer */
+ new = X509_dup((X509 *)x509);
if (!new)
ossl_raise(eX509CertError, "X509_dup");
SetX509(obj, new);
@@ -115,8 +116,8 @@ ossl_x509_initialize(int argc, VALUE *argv, VALUE self)
rb_check_frozen(self);
if (rb_scan_args(argc, argv, "01", &arg) == 0) {
- /* create just empty X509Cert */
- return self;
+ /* create just empty X509Cert */
+ return self;
}
arg = ossl_to_der_if_possible(arg);
in = ossl_obj2bio(&arg);
@@ -170,11 +171,11 @@ ossl_x509_to_der(VALUE self)
GetX509(self, x509);
if ((len = i2d_X509(x509, NULL)) <= 0)
- ossl_raise(eX509CertError, NULL);
+ ossl_raise(eX509CertError, NULL);
str = rb_str_new(0, len);
p = (unsigned char *)RSTRING_PTR(str);
if (i2d_X509(x509, &p) <= 0)
- ossl_raise(eX509CertError, NULL);
+ ossl_raise(eX509CertError, NULL);
ossl_str_adjust(str, p);
return str;
@@ -196,8 +197,8 @@ ossl_x509_to_pem(VALUE self)
if (!out) ossl_raise(eX509CertError, NULL);
if (!PEM_write_bio_X509(out, x509)) {
- BIO_free(out);
- ossl_raise(eX509CertError, NULL);
+ BIO_free(out);
+ ossl_raise(eX509CertError, NULL);
}
str = ossl_membio2str(out);
@@ -221,8 +222,8 @@ ossl_x509_to_text(VALUE self)
if (!out) ossl_raise(eX509CertError, NULL);
if (!X509_print(out, x509)) {
- BIO_free(out);
- ossl_raise(eX509CertError, NULL);
+ BIO_free(out);
+ ossl_raise(eX509CertError, NULL);
}
str = ossl_membio2str(out);
@@ -242,7 +243,7 @@ ossl_x509_to_req(VALUE self)
GetX509(self, x509);
if (!(req = X509_to_X509_REQ(x509, NULL, EVP_md5()))) {
- ossl_raise(eX509CertError, NULL);
+ ossl_raise(eX509CertError, NULL);
}
obj = ossl_x509req_new(req);
X509_REQ_free(req);
@@ -276,11 +277,11 @@ ossl_x509_set_version(VALUE self, VALUE version)
long ver;
if ((ver = NUM2LONG(version)) < 0) {
- ossl_raise(eX509CertError, "version must be >= 0!");
+ ossl_raise(eX509CertError, "version must be >= 0!");
}
GetX509(self, x509);
if (!X509_set_version(x509, ver)) {
- ossl_raise(eX509CertError, NULL);
+ ossl_raise(eX509CertError, NULL);
}
return version;
@@ -310,7 +311,9 @@ ossl_x509_set_serial(VALUE self, VALUE num)
X509 *x509;
GetX509(self, x509);
- X509_set_serialNumber(x509, num_to_asn1integer(num, X509_get_serialNumber(x509)));
+ if (!X509_set_serialNumber(x509, num_to_asn1integer(num, X509_get_serialNumber(x509)))) {
+ ossl_raise(eX509CertError, NULL);
+ }
return num;
}
@@ -318,27 +321,23 @@ ossl_x509_set_serial(VALUE self, VALUE num)
/*
* call-seq:
* cert.signature_algorithm => string
+ *
+ * Returns the signature algorithm used to sign this certificate. This returns
+ * the algorithm name found in the TBSCertificate structure, not the outer
+ * \Certificate structure.
+ *
+ * Returns the long name of the signature algorithm, or the dotted decimal
+ * notation if \OpenSSL does not define a long name for it.
*/
static VALUE
ossl_x509_get_signature_algorithm(VALUE self)
{
X509 *x509;
- BIO *out;
const ASN1_OBJECT *obj;
- VALUE str;
GetX509(self, x509);
- out = BIO_new(BIO_s_mem());
- if (!out) ossl_raise(eX509CertError, NULL);
-
X509_ALGOR_get0(&obj, NULL, NULL, X509_get0_tbs_sigalg(x509));
- if (!i2a_ASN1_OBJECT(out, obj)) {
- BIO_free(out);
- ossl_raise(eX509CertError, NULL);
- }
- str = ossl_membio2str(out);
-
- return str;
+ return ossl_asn1obj_to_string_long_name(obj);
}
/*
@@ -349,11 +348,11 @@ static VALUE
ossl_x509_get_subject(VALUE self)
{
X509 *x509;
- X509_NAME *name;
+ const X509_NAME *name;
GetX509(self, x509);
if (!(name = X509_get_subject_name(x509))) { /* NO DUP - don't free! */
- ossl_raise(eX509CertError, NULL);
+ ossl_raise(eX509CertError, NULL);
}
return ossl_x509name_new(name);
@@ -370,7 +369,7 @@ ossl_x509_set_subject(VALUE self, VALUE subject)
GetX509(self, x509);
if (!X509_set_subject_name(x509, GetX509NamePtr(subject))) { /* DUPs name */
- ossl_raise(eX509CertError, NULL);
+ ossl_raise(eX509CertError, NULL);
}
return subject;
@@ -384,11 +383,11 @@ static VALUE
ossl_x509_get_issuer(VALUE self)
{
X509 *x509;
- X509_NAME *name;
+ const X509_NAME *name;
GetX509(self, x509);
if(!(name = X509_get_issuer_name(x509))) { /* NO DUP - don't free! */
- ossl_raise(eX509CertError, NULL);
+ ossl_raise(eX509CertError, NULL);
}
return ossl_x509name_new(name);
@@ -405,7 +404,7 @@ ossl_x509_set_issuer(VALUE self, VALUE issuer)
GetX509(self, x509);
if (!X509_set_issuer_name(x509, GetX509NamePtr(issuer))) { /* DUPs name */
- ossl_raise(eX509CertError, NULL);
+ ossl_raise(eX509CertError, NULL);
}
return issuer;
@@ -423,7 +422,7 @@ ossl_x509_get_not_before(VALUE self)
GetX509(self, x509);
if (!(asn1time = X509_get0_notBefore(x509))) {
- ossl_raise(eX509CertError, NULL);
+ ossl_raise(eX509CertError, NULL);
}
return asn1time_to_time(asn1time);
@@ -442,8 +441,8 @@ ossl_x509_set_not_before(VALUE self, VALUE time)
GetX509(self, x509);
asn1time = ossl_x509_time_adjust(NULL, time);
if (!X509_set1_notBefore(x509, asn1time)) {
- ASN1_TIME_free(asn1time);
- ossl_raise(eX509CertError, "X509_set_notBefore");
+ ASN1_TIME_free(asn1time);
+ ossl_raise(eX509CertError, "X509_set_notBefore");
}
ASN1_TIME_free(asn1time);
@@ -462,7 +461,7 @@ ossl_x509_get_not_after(VALUE self)
GetX509(self, x509);
if (!(asn1time = X509_get0_notAfter(x509))) {
- ossl_raise(eX509CertError, NULL);
+ ossl_raise(eX509CertError, NULL);
}
return asn1time_to_time(asn1time);
@@ -481,8 +480,8 @@ ossl_x509_set_not_after(VALUE self, VALUE time)
GetX509(self, x509);
asn1time = ossl_x509_time_adjust(NULL, time);
if (!X509_set1_notAfter(x509, asn1time)) {
- ASN1_TIME_free(asn1time);
- ossl_raise(eX509CertError, "X509_set_notAfter");
+ ASN1_TIME_free(asn1time);
+ ossl_raise(eX509CertError, "X509_set_notAfter");
}
ASN1_TIME_free(asn1time);
@@ -501,7 +500,7 @@ ossl_x509_get_public_key(VALUE self)
GetX509(self, x509);
if (!(pkey = X509_get_pubkey(x509))) { /* adds an reference */
- ossl_raise(eX509CertError, NULL);
+ ossl_raise(eX509CertError, NULL);
}
return ossl_pkey_wrap(pkey);
@@ -521,7 +520,7 @@ ossl_x509_set_public_key(VALUE self, VALUE key)
pkey = GetPKeyPtr(key);
ossl_pkey_check_public_key(pkey);
if (!X509_set_pubkey(x509, pkey))
- ossl_raise(eX509CertError, "X509_set_pubkey");
+ ossl_raise(eX509CertError, "X509_set_pubkey");
return key;
}
@@ -535,17 +534,14 @@ ossl_x509_sign(VALUE self, VALUE key, VALUE digest)
X509 *x509;
EVP_PKEY *pkey;
const EVP_MD *md;
+ VALUE md_holder;
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);
- }
+ /* NULL needed for some key types, e.g. Ed25519 */
+ md = NIL_P(digest) ? NULL : ossl_evp_md_fetch(digest, &md_holder);
GetX509(self, x509);
- if (!X509_sign(x509, pkey, md)) {
- ossl_raise(eX509CertError, NULL);
- }
+ if (!X509_sign(x509, pkey, md))
+ ossl_raise(eX509CertError, "X509_sign");
return self;
}
@@ -568,12 +564,12 @@ ossl_x509_verify(VALUE self, VALUE key)
ossl_pkey_check_public_key(pkey);
switch (X509_verify(x509, pkey)) {
case 1:
- return Qtrue;
+ return Qtrue;
case 0:
- ossl_clear_error();
- return Qfalse;
+ ossl_clear_error();
+ return Qfalse;
default:
- ossl_raise(eX509CertError, NULL);
+ ossl_raise(eX509CertError, NULL);
}
}
@@ -594,8 +590,8 @@ ossl_x509_check_private_key(VALUE self, VALUE key)
pkey = GetPrivPKeyPtr(key); /* NO NEED TO DUP */
GetX509(self, x509);
if (!X509_check_private_key(x509, pkey)) {
- ossl_clear_error();
- return Qfalse;
+ ossl_clear_error();
+ return Qfalse;
}
return Qtrue;
@@ -610,15 +606,14 @@ ossl_x509_get_extensions(VALUE self)
{
X509 *x509;
int count, i;
- X509_EXTENSION *ext;
VALUE ary;
GetX509(self, x509);
count = X509_get_ext_count(x509);
ary = rb_ary_new_capa(count);
for (i=0; i<count; i++) {
- ext = X509_get_ext(x509, i); /* NO DUP - don't free! */
- rb_ary_push(ary, ossl_x509ext_new(ext));
+ const X509_EXTENSION *ext = X509_get_ext(x509, i);
+ rb_ary_push(ary, ossl_x509ext_new(ext));
}
return ary;
@@ -638,16 +633,16 @@ ossl_x509_set_extensions(VALUE self, VALUE ary)
Check_Type(ary, T_ARRAY);
/* All ary's members should be X509Extension */
for (i=0; i<RARRAY_LEN(ary); i++) {
- OSSL_Check_Kind(RARRAY_AREF(ary, i), cX509Ext);
+ OSSL_Check_Kind(RARRAY_AREF(ary, i), cX509Ext);
}
GetX509(self, x509);
for (i = X509_get_ext_count(x509); i > 0; i--)
X509_EXTENSION_free(X509_delete_ext(x509, 0));
for (i=0; i<RARRAY_LEN(ary); i++) {
- ext = GetX509ExtPtr(RARRAY_AREF(ary, i));
- if (!X509_add_ext(x509, ext, -1)) { /* DUPs ext */
- ossl_raise(eX509CertError, "X509_add_ext");
- }
+ ext = GetX509ExtPtr(RARRAY_AREF(ary, i));
+ if (!X509_add_ext(x509, ext, -1)) { /* DUPs ext */
+ ossl_raise(eX509CertError, "X509_add_ext");
+ }
}
return ary;
@@ -666,32 +661,24 @@ ossl_x509_add_extension(VALUE self, VALUE extension)
GetX509(self, x509);
ext = GetX509ExtPtr(extension);
if (!X509_add_ext(x509, ext, -1)) { /* DUPs ext - FREE it */
- ossl_raise(eX509CertError, NULL);
+ ossl_raise(eX509CertError, NULL);
}
return extension;
}
-static VALUE
-ossl_x509_inspect(VALUE self)
-{
- return rb_sprintf("#<%"PRIsVALUE": subject=%+"PRIsVALUE", "
- "issuer=%+"PRIsVALUE", serial=%+"PRIsVALUE", "
- "not_before=%+"PRIsVALUE", not_after=%+"PRIsVALUE">",
- rb_obj_class(self),
- ossl_x509_get_subject(self),
- ossl_x509_get_issuer(self),
- ossl_x509_get_serial(self),
- ossl_x509_get_not_before(self),
- ossl_x509_get_not_after(self));
-}
-
/*
* call-seq:
* cert1 == cert2 -> true | false
*
* Compares the two certificates. Note that this takes into account all fields,
* not just the issuer name and the serial number.
+ *
+ * This method uses X509_cmp() from OpenSSL, which compares certificates based
+ * on their cached DER encodings. The comparison can be unreliable if a
+ * certificate is incomplete.
+ *
+ * See also the man page X509_cmp(3).
*/
static VALUE
ossl_x509_eq(VALUE self, VALUE other)
@@ -700,7 +687,7 @@ ossl_x509_eq(VALUE self, VALUE other)
GetX509(self, a);
if (!rb_obj_is_kind_of(other, cX509Cert))
- return Qfalse;
+ return Qfalse;
GetX509(other, b);
return !X509_cmp(a, b) ? Qtrue : Qfalse;
@@ -795,7 +782,7 @@ load_chained_certificates_PEM(BIO *in) {
certificates = load_chained_certificates_append(Qnil, certificate);
while ((certificate = PEM_read_bio_X509(in, NULL, NULL, NULL))) {
- load_chained_certificates_append(certificates, certificate);
+ load_chained_certificates_append(certificates, certificate);
}
/* We tried to read one more certificate but could not read start line: */
@@ -893,12 +880,6 @@ ossl_x509_load(VALUE klass, VALUE buffer)
void
Init_ossl_x509cert(void)
{
-#if 0
- mOSSL = rb_define_module("OpenSSL");
- eOSSLError = rb_define_class_under(mOSSL, "OpenSSLError", rb_eStandardError);
- mX509 = rb_define_module_under(mOSSL, "X509");
-#endif
-
eX509CertError = rb_define_class_under(mX509, "CertificateError", eOSSLError);
/* Document-class: OpenSSL::X509::Certificate
@@ -1026,7 +1007,6 @@ Init_ossl_x509cert(void)
rb_define_method(cX509Cert, "extensions", ossl_x509_get_extensions, 0);
rb_define_method(cX509Cert, "extensions=", ossl_x509_set_extensions, 1);
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);
rb_define_method(cX509Cert, "tbs_bytes", ossl_x509_tbs_bytes, 0);
}
diff --git a/ext/openssl/ossl_x509crl.c b/ext/openssl/ossl_x509crl.c
index 52174d1711..9b59bda9e2 100644
--- a/ext/openssl/ossl_x509crl.c
+++ b/ext/openssl/ossl_x509crl.c
@@ -13,14 +13,14 @@
TypedData_Wrap_Struct((klass), &ossl_x509crl_type, 0)
#define SetX509CRL(obj, crl) do { \
if (!(crl)) { \
- ossl_raise(rb_eRuntimeError, "CRL wasn't initialized!"); \
+ ossl_raise(rb_eRuntimeError, "CRL wasn't initialized!"); \
} \
RTYPEDDATA_DATA(obj) = (crl); \
} while (0)
#define GetX509CRL(obj, crl) do { \
TypedData_Get_Struct((obj), X509_CRL, &ossl_x509crl_type, (crl)); \
if (!(crl)) { \
- ossl_raise(rb_eRuntimeError, "CRL wasn't initialized!"); \
+ ossl_raise(rb_eRuntimeError, "CRL wasn't initialized!"); \
} \
} while (0)
@@ -39,7 +39,7 @@ ossl_x509crl_free(void *ptr)
static const rb_data_type_t ossl_x509crl_type = {
"OpenSSL/X509/CRL",
{
- 0, ossl_x509crl_free,
+ 0, ossl_x509crl_free,
},
0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
};
@@ -58,13 +58,14 @@ GetX509CRLPtr(VALUE obj)
}
VALUE
-ossl_x509crl_new(X509_CRL *crl)
+ossl_x509crl_new(const X509_CRL *crl)
{
X509_CRL *tmp;
VALUE obj;
obj = NewX509CRL(cX509CRL);
- tmp = X509_CRL_dup(crl);
+ /* OpenSSL 1.1.1 takes a non-const pointer */
+ tmp = X509_CRL_dup((X509_CRL *)crl);
if (!tmp)
ossl_raise(eX509CRLError, "X509_CRL_dup");
SetX509CRL(obj, tmp);
@@ -83,7 +84,7 @@ ossl_x509crl_alloc(VALUE klass)
obj = NewX509CRL(klass);
if (!(crl = X509_CRL_new())) {
- ossl_raise(eX509CRLError, NULL);
+ ossl_raise(eX509CRLError, NULL);
}
SetX509CRL(obj, crl);
@@ -99,7 +100,7 @@ ossl_x509crl_initialize(int argc, VALUE *argv, VALUE self)
rb_check_frozen(self);
if (rb_scan_args(argc, argv, "01", &arg) == 0) {
- return self;
+ return self;
}
arg = ossl_to_der_if_possible(arg);
in = ossl_obj2bio(&arg);
@@ -129,7 +130,7 @@ ossl_x509crl_copy(VALUE self, VALUE other)
GetX509CRL(self, a);
GetX509CRL(other, b);
if (!(crl = X509_CRL_dup(b))) {
- ossl_raise(eX509CRLError, NULL);
+ ossl_raise(eX509CRLError, NULL);
}
X509_CRL_free(a);
DATA_PTR(self) = crl;
@@ -156,36 +157,36 @@ ossl_x509crl_set_version(VALUE self, VALUE version)
long ver;
if ((ver = NUM2LONG(version)) < 0) {
- ossl_raise(eX509CRLError, "version must be >= 0!");
+ ossl_raise(eX509CRLError, "version must be >= 0!");
}
GetX509CRL(self, crl);
if (!X509_CRL_set_version(crl, ver)) {
- ossl_raise(eX509CRLError, NULL);
+ ossl_raise(eX509CRLError, NULL);
}
return version;
}
+/*
+ * call-seq:
+ * crl.signature_algorithm -> string
+ *
+ * Returns the signature algorithm used to sign this CRL.
+ *
+ * Returns the long name of the signature algorithm, or the dotted decimal
+ * notation if \OpenSSL does not define a long name for it.
+ */
static VALUE
ossl_x509crl_get_signature_algorithm(VALUE self)
{
X509_CRL *crl;
const X509_ALGOR *alg;
const ASN1_OBJECT *obj;
- BIO *out;
GetX509CRL(self, crl);
- if (!(out = BIO_new(BIO_s_mem()))) {
- ossl_raise(eX509CRLError, NULL);
- }
X509_CRL_get0_signature(crl, NULL, &alg);
X509_ALGOR_get0(&obj, NULL, NULL, alg);
- if (!i2a_ASN1_OBJECT(out, obj)) {
- BIO_free(out);
- ossl_raise(eX509CRLError, NULL);
- }
-
- return ossl_membio2str(out);
+ return ossl_asn1obj_to_string_long_name(obj);
}
static VALUE
@@ -206,7 +207,7 @@ ossl_x509crl_set_issuer(VALUE self, VALUE issuer)
GetX509CRL(self, crl);
if (!X509_CRL_set_issuer_name(crl, GetX509NamePtr(issuer))) { /* DUPs name */
- ossl_raise(eX509CRLError, NULL);
+ ossl_raise(eX509CRLError, NULL);
}
return issuer;
}
@@ -220,7 +221,7 @@ ossl_x509crl_get_last_update(VALUE self)
GetX509CRL(self, crl);
time = X509_CRL_get0_lastUpdate(crl);
if (!time)
- return Qnil;
+ return Qnil;
return asn1time_to_time(time);
}
@@ -234,8 +235,8 @@ ossl_x509crl_set_last_update(VALUE self, VALUE time)
GetX509CRL(self, crl);
asn1time = ossl_x509_time_adjust(NULL, time);
if (!X509_CRL_set1_lastUpdate(crl, asn1time)) {
- ASN1_TIME_free(asn1time);
- ossl_raise(eX509CRLError, "X509_CRL_set_lastUpdate");
+ ASN1_TIME_free(asn1time);
+ ossl_raise(eX509CRLError, "X509_CRL_set_lastUpdate");
}
ASN1_TIME_free(asn1time);
@@ -251,7 +252,7 @@ ossl_x509crl_get_next_update(VALUE self)
GetX509CRL(self, crl);
time = X509_CRL_get0_nextUpdate(crl);
if (!time)
- return Qnil;
+ return Qnil;
return asn1time_to_time(time);
}
@@ -265,8 +266,8 @@ ossl_x509crl_set_next_update(VALUE self, VALUE time)
GetX509CRL(self, crl);
asn1time = ossl_x509_time_adjust(NULL, time);
if (!X509_CRL_set1_nextUpdate(crl, asn1time)) {
- ASN1_TIME_free(asn1time);
- ossl_raise(eX509CRLError, "X509_CRL_set_nextUpdate");
+ ASN1_TIME_free(asn1time);
+ ossl_raise(eX509CRLError, "X509_CRL_set_nextUpdate");
}
ASN1_TIME_free(asn1time);
@@ -289,8 +290,8 @@ ossl_x509crl_get_revoked(VALUE self)
num = sk_X509_REVOKED_num(sk);
ary = rb_ary_new_capa(num);
for(i=0; i<num; i++) {
- X509_REVOKED *rev = sk_X509_REVOKED_value(sk, i);
- rb_ary_push(ary, ossl_x509revoked_new(rev));
+ const X509_REVOKED *rev = sk_X509_REVOKED_value(sk, i);
+ rb_ary_push(ary, ossl_x509revoked_new(rev));
}
return ary;
@@ -307,19 +308,19 @@ ossl_x509crl_set_revoked(VALUE self, VALUE ary)
Check_Type(ary, T_ARRAY);
/* All ary members should be X509 Revoked */
for (i=0; i<RARRAY_LEN(ary); i++) {
- OSSL_Check_Kind(RARRAY_AREF(ary, i), cX509Rev);
+ OSSL_Check_Kind(RARRAY_AREF(ary, i), cX509Rev);
}
GetX509CRL(self, crl);
if ((sk = X509_CRL_get_REVOKED(crl))) {
- while ((rev = sk_X509_REVOKED_pop(sk)))
- X509_REVOKED_free(rev);
+ while ((rev = sk_X509_REVOKED_pop(sk)))
+ X509_REVOKED_free(rev);
}
for (i=0; i<RARRAY_LEN(ary); i++) {
- rev = DupX509RevokedPtr(RARRAY_AREF(ary, i));
- if (!X509_CRL_add0_revoked(crl, rev)) { /* NO DUP - don't free! */
- X509_REVOKED_free(rev);
- ossl_raise(eX509CRLError, "X509_CRL_add0_revoked");
- }
+ rev = DupX509RevokedPtr(RARRAY_AREF(ary, i));
+ if (!X509_CRL_add0_revoked(crl, rev)) { /* NO DUP - don't free! */
+ X509_REVOKED_free(rev);
+ ossl_raise(eX509CRLError, "X509_CRL_add0_revoked");
+ }
}
X509_CRL_sort(crl);
@@ -335,8 +336,8 @@ ossl_x509crl_add_revoked(VALUE self, VALUE revoked)
GetX509CRL(self, crl);
rev = DupX509RevokedPtr(revoked);
if (!X509_CRL_add0_revoked(crl, rev)) { /* NO DUP - don't free! */
- X509_REVOKED_free(rev);
- ossl_raise(eX509CRLError, "X509_CRL_add0_revoked");
+ X509_REVOKED_free(rev);
+ ossl_raise(eX509CRLError, "X509_CRL_add0_revoked");
}
X509_CRL_sort(crl);
@@ -349,17 +350,14 @@ ossl_x509crl_sign(VALUE self, VALUE key, VALUE digest)
X509_CRL *crl;
EVP_PKEY *pkey;
const EVP_MD *md;
+ VALUE md_holder;
GetX509CRL(self, crl);
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);
- }
- if (!X509_CRL_sign(crl, pkey, md)) {
- ossl_raise(eX509CRLError, NULL);
- }
+ /* NULL needed for some key types, e.g. Ed25519 */
+ md = NIL_P(digest) ? NULL : ossl_evp_md_fetch(digest, &md_holder);
+ if (!X509_CRL_sign(crl, pkey, md))
+ ossl_raise(eX509CRLError, "X509_CRL_sign");
return self;
}
@@ -375,12 +373,12 @@ ossl_x509crl_verify(VALUE self, VALUE key)
ossl_pkey_check_public_key(pkey);
switch (X509_CRL_verify(crl, pkey)) {
case 1:
- return Qtrue;
+ return Qtrue;
case 0:
- ossl_clear_error();
- return Qfalse;
+ ossl_clear_error();
+ return Qfalse;
default:
- ossl_raise(eX509CRLError, NULL);
+ ossl_raise(eX509CRLError, NULL);
}
}
@@ -392,11 +390,11 @@ ossl_x509crl_to_der(VALUE self)
GetX509CRL(self, crl);
if (!(out = BIO_new(BIO_s_mem()))) {
- ossl_raise(eX509CRLError, NULL);
+ ossl_raise(eX509CRLError, NULL);
}
if (!i2d_X509_CRL_bio(out, crl)) {
- BIO_free(out);
- ossl_raise(eX509CRLError, NULL);
+ BIO_free(out);
+ ossl_raise(eX509CRLError, NULL);
}
return ossl_membio2str(out);
@@ -410,11 +408,11 @@ ossl_x509crl_to_pem(VALUE self)
GetX509CRL(self, crl);
if (!(out = BIO_new(BIO_s_mem()))) {
- ossl_raise(eX509CRLError, NULL);
+ ossl_raise(eX509CRLError, NULL);
}
if (!PEM_write_bio_X509_CRL(out, crl)) {
- BIO_free(out);
- ossl_raise(eX509CRLError, NULL);
+ BIO_free(out);
+ ossl_raise(eX509CRLError, NULL);
}
return ossl_membio2str(out);
@@ -428,11 +426,11 @@ ossl_x509crl_to_text(VALUE self)
GetX509CRL(self, crl);
if (!(out = BIO_new(BIO_s_mem()))) {
- ossl_raise(eX509CRLError, NULL);
+ ossl_raise(eX509CRLError, NULL);
}
if (!X509_CRL_print(out, crl)) {
- BIO_free(out);
- ossl_raise(eX509CRLError, NULL);
+ BIO_free(out);
+ ossl_raise(eX509CRLError, NULL);
}
return ossl_membio2str(out);
@@ -446,15 +444,14 @@ ossl_x509crl_get_extensions(VALUE self)
{
X509_CRL *crl;
int count, i;
- X509_EXTENSION *ext;
VALUE ary;
GetX509CRL(self, crl);
count = X509_CRL_get_ext_count(crl);
ary = rb_ary_new_capa(count);
for (i=0; i<count; i++) {
- ext = X509_CRL_get_ext(crl, i); /* NO DUP - don't free! */
- rb_ary_push(ary, ossl_x509ext_new(ext));
+ const X509_EXTENSION *ext = X509_CRL_get_ext(crl, i);
+ rb_ary_push(ary, ossl_x509ext_new(ext));
}
return ary;
@@ -473,16 +470,16 @@ ossl_x509crl_set_extensions(VALUE self, VALUE ary)
Check_Type(ary, T_ARRAY);
/* All ary members should be X509 Extensions */
for (i=0; i<RARRAY_LEN(ary); i++) {
- OSSL_Check_Kind(RARRAY_AREF(ary, i), cX509Ext);
+ OSSL_Check_Kind(RARRAY_AREF(ary, i), cX509Ext);
}
GetX509CRL(self, crl);
for (i = X509_CRL_get_ext_count(crl); i > 0; i--)
X509_EXTENSION_free(X509_CRL_delete_ext(crl, 0));
for (i=0; i<RARRAY_LEN(ary); i++) {
- ext = GetX509ExtPtr(RARRAY_AREF(ary, i)); /* NO NEED TO DUP */
- if (!X509_CRL_add_ext(crl, ext, -1)) {
- ossl_raise(eX509CRLError, "X509_CRL_add_ext");
- }
+ ext = GetX509ExtPtr(RARRAY_AREF(ary, i)); /* NO NEED TO DUP */
+ if (!X509_CRL_add_ext(crl, ext, -1)) {
+ ossl_raise(eX509CRLError, "X509_CRL_add_ext");
+ }
}
return ary;
@@ -497,7 +494,7 @@ ossl_x509crl_add_extension(VALUE self, VALUE extension)
GetX509CRL(self, crl);
ext = GetX509ExtPtr(extension);
if (!X509_CRL_add_ext(crl, ext, -1)) {
- ossl_raise(eX509CRLError, NULL);
+ ossl_raise(eX509CRLError, NULL);
}
return extension;
@@ -509,12 +506,6 @@ ossl_x509crl_add_extension(VALUE self, VALUE extension)
void
Init_ossl_x509crl(void)
{
-#if 0
- mOSSL = rb_define_module("OpenSSL");
- eOSSLError = rb_define_class_under(mOSSL, "OpenSSLError", rb_eStandardError);
- mX509 = rb_define_module_under(mOSSL, "X509");
-#endif
-
eX509CRLError = rb_define_class_under(mX509, "CRLError", eOSSLError);
cX509CRL = rb_define_class_under(mX509, "CRL", rb_cObject);
diff --git a/ext/openssl/ossl_x509ext.c b/ext/openssl/ossl_x509ext.c
index 01aa3a8f51..1fe727d3f1 100644
--- a/ext/openssl/ossl_x509ext.c
+++ b/ext/openssl/ossl_x509ext.c
@@ -13,14 +13,14 @@
TypedData_Wrap_Struct((klass), &ossl_x509ext_type, 0)
#define SetX509Ext(obj, ext) do { \
if (!(ext)) { \
- ossl_raise(rb_eRuntimeError, "EXT wasn't initialized!"); \
+ ossl_raise(rb_eRuntimeError, "EXT wasn't initialized!"); \
} \
RTYPEDDATA_DATA(obj) = (ext); \
} while (0)
#define GetX509Ext(obj, ext) do { \
TypedData_Get_Struct((obj), X509_EXTENSION, &ossl_x509ext_type, (ext)); \
if (!(ext)) { \
- ossl_raise(rb_eRuntimeError, "EXT wasn't initialized!"); \
+ ossl_raise(rb_eRuntimeError, "EXT wasn't initialized!"); \
} \
} while (0)
#define MakeX509ExtFactory(klass, obj, ctx) do { \
@@ -33,7 +33,7 @@
#define GetX509ExtFactory(obj, ctx) do { \
TypedData_Get_Struct((obj), X509V3_CTX, &ossl_x509extfactory_type, (ctx)); \
if (!(ctx)) { \
- ossl_raise(rb_eRuntimeError, "CTX wasn't initialized!"); \
+ ossl_raise(rb_eRuntimeError, "CTX wasn't initialized!"); \
} \
} while (0)
@@ -53,7 +53,7 @@ ossl_x509ext_free(void *ptr)
static const rb_data_type_t ossl_x509ext_type = {
"OpenSSL/X509/EXTENSION",
{
- 0, ossl_x509ext_free,
+ 0, ossl_x509ext_free,
},
0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
};
@@ -62,13 +62,14 @@ static const rb_data_type_t ossl_x509ext_type = {
* Public
*/
VALUE
-ossl_x509ext_new(X509_EXTENSION *ext)
+ossl_x509ext_new(const X509_EXTENSION *ext)
{
X509_EXTENSION *new;
VALUE obj;
obj = NewX509Ext(cX509Ext);
- new = X509_EXTENSION_dup(ext);
+ /* OpenSSL 1.1.1 takes a non-const pointer */
+ new = X509_EXTENSION_dup((X509_EXTENSION *)ext);
if (!new)
ossl_raise(eX509ExtError, "X509_EXTENSION_dup");
SetX509Ext(obj, new);
@@ -101,7 +102,7 @@ ossl_x509extfactory_free(void *ctx)
static const rb_data_type_t ossl_x509extfactory_type = {
"OpenSSL/X509/EXTENSION/Factory",
{
- 0, ossl_x509extfactory_free,
+ 0, ossl_x509extfactory_free,
},
0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
};
@@ -175,15 +176,15 @@ ossl_x509extfactory_initialize(int argc, VALUE *argv, VALUE self)
/*GetX509ExtFactory(self, ctx);*/
rb_scan_args(argc, argv, "04",
- &issuer_cert, &subject_cert, &subject_req, &crl);
+ &issuer_cert, &subject_cert, &subject_req, &crl);
if (!NIL_P(issuer_cert))
- ossl_x509extfactory_set_issuer_cert(self, issuer_cert);
+ ossl_x509extfactory_set_issuer_cert(self, issuer_cert);
if (!NIL_P(subject_cert))
- ossl_x509extfactory_set_subject_cert(self, subject_cert);
+ ossl_x509extfactory_set_subject_cert(self, subject_cert);
if (!NIL_P(subject_req))
- ossl_x509extfactory_set_subject_req(self, subject_req);
+ ossl_x509extfactory_set_subject_req(self, subject_req);
if (!NIL_P(crl))
- ossl_x509extfactory_set_crl(self, crl);
+ ossl_x509extfactory_set_crl(self, crl);
return self;
}
@@ -213,7 +214,7 @@ ossl_x509extfactory_create_ext(int argc, VALUE *argv, VALUE self)
oid_cstr = StringValueCStr(oid);
nid = OBJ_ln2nid(oid_cstr);
if (nid != NID_undef)
- oid_cstr = OBJ_nid2sn(nid);
+ oid_cstr = OBJ_nid2sn(nid);
valstr = rb_str_new2(RTEST(critical) ? "critical," : "");
rb_str_append(valstr, value);
@@ -228,7 +229,7 @@ ossl_x509extfactory_create_ext(int argc, VALUE *argv, VALUE self)
ext = X509V3_EXT_nconf(conf, ctx, oid_cstr, RSTRING_PTR(valstr));
X509V3_set_ctx_nodb(ctx);
if (!ext){
- ossl_raise(eX509ExtError, "%"PRIsVALUE" = %"PRIsVALUE, oid, valstr);
+ ossl_raise(eX509ExtError, "%"PRIsVALUE" = %"PRIsVALUE, oid, valstr);
}
SetX509Ext(obj, ext);
@@ -246,7 +247,7 @@ ossl_x509ext_alloc(VALUE klass)
obj = NewX509Ext(klass);
if(!(ext = X509_EXTENSION_new())){
- ossl_raise(eX509ExtError, NULL);
+ ossl_raise(eX509ExtError, NULL);
}
SetX509Ext(obj, ext);
@@ -274,14 +275,14 @@ ossl_x509ext_initialize(int argc, VALUE *argv, VALUE self)
GetX509Ext(self, ext);
if(rb_scan_args(argc, argv, "12", &oid, &value, &critical) == 1){
- oid = ossl_to_der_if_possible(oid);
- StringValue(oid);
- p = (unsigned char *)RSTRING_PTR(oid);
- x = d2i_X509_EXTENSION(&ext, &p, RSTRING_LEN(oid));
- DATA_PTR(self) = ext;
- if(!x)
- ossl_raise(eX509ExtError, NULL);
- return self;
+ oid = ossl_to_der_if_possible(oid);
+ StringValue(oid);
+ p = (unsigned char *)RSTRING_PTR(oid);
+ x = d2i_X509_EXTENSION(&ext, &p, RSTRING_LEN(oid));
+ DATA_PTR(self) = ext;
+ if(!x)
+ ossl_raise(eX509ExtError, NULL);
+ return self;
}
rb_funcall(self, rb_intern("oid="), 1, oid);
rb_funcall(self, rb_intern("value="), 1, value);
@@ -302,7 +303,7 @@ ossl_x509ext_initialize_copy(VALUE self, VALUE other)
ext_new = X509_EXTENSION_dup(ext_other);
if (!ext_new)
- ossl_raise(eX509ExtError, "X509_EXTENSION_dup");
+ ossl_raise(eX509ExtError, "X509_EXTENSION_dup");
SetX509Ext(self, ext_new);
X509_EXTENSION_free(ext);
@@ -319,10 +320,10 @@ ossl_x509ext_set_oid(VALUE self, VALUE oid)
GetX509Ext(self, ext);
obj = OBJ_txt2obj(StringValueCStr(oid), 0);
if (!obj)
- ossl_raise(eX509ExtError, "OBJ_txt2obj");
+ ossl_raise(eX509ExtError, "OBJ_txt2obj");
if (!X509_EXTENSION_set_object(ext, obj)) {
- ASN1_OBJECT_free(obj);
- ossl_raise(eX509ExtError, "X509_EXTENSION_set_object");
+ ASN1_OBJECT_free(obj);
+ ossl_raise(eX509ExtError, "X509_EXTENSION_set_object");
}
ASN1_OBJECT_free(obj);
@@ -338,12 +339,20 @@ ossl_x509ext_set_value(VALUE self, VALUE data)
GetX509Ext(self, ext);
data = ossl_to_der_if_possible(data);
StringValue(data);
- asn1s = X509_EXTENSION_get_data(ext);
+ asn1s = ASN1_OCTET_STRING_new();
+ if (!asn1s)
+ ossl_raise(eX509ExtError, "ASN1_OCTET_STRING_new");
if (!ASN1_OCTET_STRING_set(asn1s, (unsigned char *)RSTRING_PTR(data),
- RSTRING_LENINT(data))) {
- ossl_raise(eX509ExtError, "ASN1_OCTET_STRING_set");
+ RSTRING_LENINT(data))) {
+ ASN1_OCTET_STRING_free(asn1s);
+ ossl_raise(eX509ExtError, "ASN1_OCTET_STRING_set");
+ }
+ if (!X509_EXTENSION_set_data(ext, asn1s)) {
+ ASN1_OCTET_STRING_free(asn1s);
+ ossl_raise(eX509ExtError, "X509_EXTENSION_set_data");
}
+ ASN1_OCTET_STRING_free(asn1s);
return data;
}
@@ -359,27 +368,20 @@ ossl_x509ext_set_critical(VALUE self, VALUE flag)
return flag;
}
+/*
+ * call-seq:
+ * ext.oid -> string
+ *
+ * Returns the OID of the extension. Returns the short name or the dotted
+ * decimal notation.
+ */
static VALUE
ossl_x509ext_get_oid(VALUE obj)
{
X509_EXTENSION *ext;
- ASN1_OBJECT *extobj;
- BIO *out;
- VALUE ret;
- int nid;
GetX509Ext(obj, ext);
- extobj = X509_EXTENSION_get_object(ext);
- if ((nid = OBJ_obj2nid(extobj)) != NID_undef)
- ret = rb_str_new2(OBJ_nid2sn(nid));
- else{
- if (!(out = BIO_new(BIO_s_mem())))
- ossl_raise(eX509ExtError, NULL);
- i2a_ASN1_OBJECT(out, extobj);
- ret = ossl_membio2str(out);
- }
-
- return ret;
+ return ossl_asn1obj_to_string(X509_EXTENSION_get_object(ext));
}
static VALUE
@@ -391,9 +393,9 @@ ossl_x509ext_get_value(VALUE obj)
GetX509Ext(obj, ext);
if (!(out = BIO_new(BIO_s_mem())))
- ossl_raise(eX509ExtError, NULL);
+ ossl_raise(eX509ExtError, NULL);
if (!X509V3_EXT_print(out, ext, 0, 0))
- ASN1_STRING_print(out, (ASN1_STRING *)X509_EXTENSION_get_data(ext));
+ ASN1_STRING_print(out, X509_EXTENSION_get_data(ext));
ret = ossl_membio2str(out);
return ret;
@@ -403,13 +405,13 @@ static VALUE
ossl_x509ext_get_value_der(VALUE obj)
{
X509_EXTENSION *ext;
- ASN1_OCTET_STRING *value;
+ const ASN1_OCTET_STRING *value;
GetX509Ext(obj, ext);
if ((value = X509_EXTENSION_get_data(ext)) == NULL)
- ossl_raise(eX509ExtError, NULL);
+ ossl_raise(eX509ExtError, NULL);
- return rb_str_new((const char *)value->data, value->length);
+ return asn1str_to_str(value);
}
static VALUE
@@ -431,11 +433,11 @@ ossl_x509ext_to_der(VALUE obj)
GetX509Ext(obj, ext);
if((len = i2d_X509_EXTENSION(ext, NULL)) <= 0)
- ossl_raise(eX509ExtError, NULL);
+ ossl_raise(eX509ExtError, NULL);
str = rb_str_new(0, len);
p = (unsigned char *)RSTRING_PTR(str);
if(i2d_X509_EXTENSION(ext, &p) < 0)
- ossl_raise(eX509ExtError, NULL);
+ ossl_raise(eX509ExtError, NULL);
ossl_str_adjust(str, p);
return str;
@@ -448,12 +450,6 @@ void
Init_ossl_x509ext(void)
{
#undef rb_intern
-#if 0
- mOSSL = rb_define_module("OpenSSL");
- eOSSLError = rb_define_class_under(mOSSL, "OpenSSLError", rb_eStandardError);
- mX509 = rb_define_module_under(mOSSL, "X509");
-#endif
-
eX509ExtError = rb_define_class_under(mX509, "ExtensionError", eOSSLError);
cX509ExtFactory = rb_define_class_under(mX509, "ExtensionFactory", rb_cObject);
diff --git a/ext/openssl/ossl_x509name.c b/ext/openssl/ossl_x509name.c
index 7d0fd35247..eb97b23c02 100644
--- a/ext/openssl/ossl_x509name.c
+++ b/ext/openssl/ossl_x509name.c
@@ -13,21 +13,21 @@
TypedData_Wrap_Struct((klass), &ossl_x509name_type, 0)
#define SetX509Name(obj, name) do { \
if (!(name)) { \
- ossl_raise(rb_eRuntimeError, "Name wasn't initialized."); \
+ ossl_raise(rb_eRuntimeError, "Name wasn't initialized."); \
} \
RTYPEDDATA_DATA(obj) = (name); \
} while (0)
#define GetX509Name(obj, name) do { \
TypedData_Get_Struct((obj), X509_NAME, &ossl_x509name_type, (name)); \
if (!(name)) { \
- ossl_raise(rb_eRuntimeError, "Name wasn't initialized."); \
+ ossl_raise(rb_eRuntimeError, "Name wasn't initialized."); \
} \
} while (0)
#define OBJECT_TYPE_TEMPLATE \
- rb_const_get(cX509Name, rb_intern("OBJECT_TYPE_TEMPLATE"))
+ rb_const_get(cX509Name, rb_intern("OBJECT_TYPE_TEMPLATE"))
#define DEFAULT_OBJECT_TYPE \
- rb_const_get(cX509Name, rb_intern("DEFAULT_OBJECT_TYPE"))
+ rb_const_get(cX509Name, rb_intern("DEFAULT_OBJECT_TYPE"))
/*
* Classes
@@ -44,7 +44,7 @@ ossl_x509name_free(void *ptr)
static const rb_data_type_t ossl_x509name_type = {
"OpenSSL/X509/NAME",
{
- 0, ossl_x509name_free,
+ 0, ossl_x509name_free,
},
0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
};
@@ -53,13 +53,14 @@ static const rb_data_type_t ossl_x509name_type = {
* Public
*/
VALUE
-ossl_x509name_new(X509_NAME *name)
+ossl_x509name_new(const X509_NAME *name)
{
X509_NAME *new;
VALUE obj;
obj = NewX509Name(cX509Name);
- new = X509_NAME_dup(name);
+ /* OpenSSL 1.1.1 takes a non-const pointer */
+ new = X509_NAME_dup((X509_NAME *)name);
if (!new)
ossl_raise(eX509NameError, "X509_NAME_dup");
SetX509Name(obj, new);
@@ -88,7 +89,7 @@ ossl_x509name_alloc(VALUE klass)
obj = NewX509Name(klass);
if (!(name = X509_NAME_new())) {
- ossl_raise(eX509NameError, NULL);
+ ossl_raise(eX509NameError, NULL);
}
SetX509Name(obj, name);
@@ -145,28 +146,28 @@ ossl_x509name_initialize(int argc, VALUE *argv, VALUE self)
GetX509Name(self, name);
if (rb_scan_args(argc, argv, "02", &arg, &template) == 0) {
- return self;
+ return self;
}
else {
- VALUE tmp = rb_check_array_type(arg);
- if (!NIL_P(tmp)) {
- VALUE args;
- if(NIL_P(template)) template = OBJECT_TYPE_TEMPLATE;
- args = rb_ary_new3(2, self, template);
- rb_block_call(tmp, rb_intern("each"), 0, 0, ossl_x509name_init_i, args);
- }
- else{
- const unsigned char *p;
- VALUE str = ossl_to_der_if_possible(arg);
- X509_NAME *x;
- StringValue(str);
- p = (unsigned char *)RSTRING_PTR(str);
- x = d2i_X509_NAME(&name, &p, RSTRING_LEN(str));
- DATA_PTR(self) = name;
- if(!x){
- ossl_raise(eX509NameError, NULL);
- }
- }
+ VALUE tmp = rb_check_array_type(arg);
+ if (!NIL_P(tmp)) {
+ VALUE args;
+ if(NIL_P(template)) template = OBJECT_TYPE_TEMPLATE;
+ args = rb_ary_new3(2, self, template);
+ rb_block_call(tmp, rb_intern("each"), 0, 0, ossl_x509name_init_i, args);
+ }
+ else{
+ const unsigned char *p;
+ VALUE str = ossl_to_der_if_possible(arg);
+ X509_NAME *x;
+ StringValue(str);
+ p = (unsigned char *)RSTRING_PTR(str);
+ x = d2i_X509_NAME(&name, &p, RSTRING_LEN(str));
+ DATA_PTR(self) = name;
+ if(!x){
+ ossl_raise(eX509NameError, NULL);
+ }
+ }
}
return self;
@@ -184,7 +185,7 @@ ossl_x509name_initialize_copy(VALUE self, VALUE other)
name_new = X509_NAME_dup(name_other);
if (!name_new)
- ossl_raise(eX509NameError, "X509_NAME_dup");
+ ossl_raise(eX509NameError, "X509_NAME_dup");
SetX509Name(self, name_new);
X509_NAME_free(name);
@@ -221,8 +222,8 @@ VALUE ossl_x509name_add_entry(int argc, VALUE *argv, VALUE self)
int loc = -1, set = 0;
if (!kwargs_ids[0]) {
- kwargs_ids[0] = rb_intern_const("loc");
- kwargs_ids[1] = rb_intern_const("set");
+ kwargs_ids[0] = rb_intern_const("loc");
+ kwargs_ids[1] = rb_intern_const("set");
}
rb_scan_args(argc, argv, "21:", &oid, &value, &type, &opts);
rb_get_kwargs(opts, kwargs_ids, 0, 2, kwargs);
@@ -230,14 +231,14 @@ VALUE ossl_x509name_add_entry(int argc, VALUE *argv, VALUE self)
StringValue(value);
if(NIL_P(type)) type = rb_aref(OBJECT_TYPE_TEMPLATE, oid);
if (kwargs[0] != Qundef)
- loc = NUM2INT(kwargs[0]);
+ loc = NUM2INT(kwargs[0]);
if (kwargs[1] != Qundef)
- set = NUM2INT(kwargs[1]);
+ set = NUM2INT(kwargs[1]);
GetX509Name(self, name);
if (!X509_NAME_add_entry_by_txt(name, oid_name, NUM2INT(type),
- (unsigned char *)RSTRING_PTR(value),
- RSTRING_LENINT(value), loc, set))
- ossl_raise(eX509NameError, "X509_NAME_add_entry_by_txt");
+ (unsigned char *)RSTRING_PTR(value),
+ RSTRING_LENINT(value), loc, set))
+ ossl_raise(eX509NameError, "X509_NAME_add_entry_by_txt");
return self;
}
@@ -250,7 +251,7 @@ ossl_x509name_to_s_old(VALUE self)
GetX509Name(self, name);
buf = X509_NAME_oneline(name, NULL, 0);
if (!buf)
- ossl_raise(eX509NameError, "X509_NAME_oneline");
+ ossl_raise(eX509NameError, "X509_NAME_oneline");
return ossl_buf2str(buf, rb_long2int(strlen(buf)));
}
@@ -264,11 +265,11 @@ x509name_print(VALUE self, unsigned long iflag)
GetX509Name(self, name);
out = BIO_new(BIO_s_mem());
if (!out)
- ossl_raise(eX509NameError, NULL);
+ ossl_raise(eX509NameError, NULL);
ret = X509_NAME_print_ex(out, name, 0, iflag);
if (ret < 0 || (iflag == XN_FLAG_COMPAT && ret == 0)) {
- BIO_free(out);
- ossl_raise(eX509NameError, "X509_NAME_print_ex");
+ BIO_free(out);
+ ossl_raise(eX509NameError, "X509_NAME_print_ex");
}
return ossl_membio2str(out);
}
@@ -302,9 +303,9 @@ ossl_x509name_to_s(int argc, VALUE *argv, VALUE self)
rb_check_arity(argc, 0, 1);
/* name.to_s(nil) was allowed */
if (!argc || NIL_P(argv[0]))
- return ossl_x509name_to_s_old(self);
+ return ossl_x509name_to_s_old(self);
else
- return x509name_print(self, NUM2ULONG(argv[0]));
+ return x509name_print(self, NUM2ULONG(argv[0]));
}
/*
@@ -327,7 +328,7 @@ static VALUE
ossl_x509name_inspect(VALUE self)
{
return rb_enc_sprintf(rb_utf8_encoding(), "#<%"PRIsVALUE" %"PRIsVALUE">",
- rb_obj_class(self), ossl_x509name_to_utf8(self));
+ rb_obj_class(self), ossl_x509name_to_utf8(self));
}
/*
@@ -341,34 +342,22 @@ static VALUE
ossl_x509name_to_a(VALUE self)
{
X509_NAME *name;
- X509_NAME_ENTRY *entry;
- int i,entries,nid;
- char long_name[512];
- const char *short_name;
- VALUE ary, vname, ret;
- ASN1_STRING *value;
+ int entries;
+ VALUE ret;
GetX509Name(self, name);
entries = X509_NAME_entry_count(name);
ret = rb_ary_new_capa(entries);
- for (i=0; i<entries; i++) {
- if (!(entry = X509_NAME_get_entry(name, i))) {
- ossl_raise(eX509NameError, NULL);
- }
- if (!i2t_ASN1_OBJECT(long_name, sizeof(long_name),
- X509_NAME_ENTRY_get_object(entry))) {
- ossl_raise(eX509NameError, NULL);
- }
- nid = OBJ_ln2nid(long_name);
- if (nid == NID_undef) {
- vname = rb_str_new2((const char *) &long_name);
- } else {
- short_name = OBJ_nid2sn(nid);
- vname = rb_str_new2(short_name); /*do not free*/
- }
- value = X509_NAME_ENTRY_get_data(entry);
- ary = rb_ary_new3(3, vname, asn1str_to_str(value), INT2NUM(value->type));
- rb_ary_push(ret, ary);
+ for (int i = 0; i < entries; i++) {
+ const X509_NAME_ENTRY *entry = X509_NAME_get_entry(name, i);
+ if (!entry)
+ ossl_raise(eX509NameError, "X509_NAME_get_entry");
+ const ASN1_OBJECT *obj = X509_NAME_ENTRY_get_object(entry);
+ VALUE vname = ossl_asn1obj_to_string(obj);
+ const ASN1_STRING *data = X509_NAME_ENTRY_get_data(entry);
+ VALUE vdata = asn1str_to_str(data);
+ VALUE type = INT2NUM(ASN1_STRING_type(data));
+ rb_ary_push(ret, rb_ary_new_from_args(3, vname, vdata, type));
}
return ret;
}
@@ -377,11 +366,17 @@ static int
ossl_x509name_cmp0(VALUE self, VALUE other)
{
X509_NAME *name1, *name2;
+ int result;
GetX509Name(self, name1);
GetX509Name(other, name2);
- return X509_NAME_cmp(name1, name2);
+ result = X509_NAME_cmp(name1, name2);
+ if (result == -2) {
+ ossl_raise(eX509NameError, NULL);
+ }
+
+ return result;
}
/*
@@ -399,7 +394,7 @@ ossl_x509name_cmp(VALUE self, VALUE other)
int result;
if (!rb_obj_is_kind_of(other, cX509Name))
- return Qnil;
+ return Qnil;
result = ossl_x509name_cmp0(self, other);
if (result < 0) return INT2FIX(-1);
@@ -418,7 +413,7 @@ static VALUE
ossl_x509name_eql(VALUE self, VALUE other)
{
if (!rb_obj_is_kind_of(other, cX509Name))
- return Qfalse;
+ return Qfalse;
return ossl_x509name_cmp0(self, other) == 0 ? Qtrue : Qfalse;
}
@@ -478,11 +473,11 @@ ossl_x509name_to_der(VALUE self)
GetX509Name(self, name);
if((len = i2d_X509_NAME(name, NULL)) <= 0)
- ossl_raise(eX509NameError, NULL);
+ ossl_raise(eX509NameError, NULL);
str = rb_str_new(0, len);
p = (unsigned char *)RSTRING_PTR(str);
if(i2d_X509_NAME(name, &p) <= 0)
- ossl_raise(eX509NameError, NULL);
+ ossl_raise(eX509NameError, NULL);
ossl_str_adjust(str, p);
return str;
@@ -508,12 +503,6 @@ Init_ossl_x509name(void)
#undef rb_intern
VALUE utf8str, ptrstr, ia5str, hash;
-#if 0
- mOSSL = rb_define_module("OpenSSL");
- eOSSLError = rb_define_class_under(mOSSL, "OpenSSLError", rb_eStandardError);
- mX509 = rb_define_module_under(mOSSL, "X509");
-#endif
-
id_aref = rb_intern("[]");
eX509NameError = rb_define_class_under(mX509, "NameError", eOSSLError);
cX509Name = rb_define_class_under(mX509, "Name", rb_cObject);
@@ -552,6 +541,7 @@ Init_ossl_x509name(void)
rb_hash_aset(hash, rb_str_new2("DC"), ia5str);
rb_hash_aset(hash, rb_str_new2("domainComponent"), ia5str);
rb_hash_aset(hash, rb_str_new2("emailAddress"), ia5str);
+ rb_obj_freeze(hash);
/*
* The default object type template for name entries.
diff --git a/ext/openssl/ossl_x509req.c b/ext/openssl/ossl_x509req.c
index b4c29f877e..ad5dd08033 100644
--- a/ext/openssl/ossl_x509req.c
+++ b/ext/openssl/ossl_x509req.c
@@ -13,14 +13,14 @@
TypedData_Wrap_Struct((klass), &ossl_x509req_type, 0)
#define SetX509Req(obj, req) do { \
if (!(req)) { \
- ossl_raise(rb_eRuntimeError, "Req wasn't initialized!"); \
+ ossl_raise(rb_eRuntimeError, "Req wasn't initialized!"); \
} \
RTYPEDDATA_DATA(obj) = (req); \
} while (0)
#define GetX509Req(obj, req) do { \
TypedData_Get_Struct((obj), X509_REQ, &ossl_x509req_type, (req)); \
if (!(req)) { \
- ossl_raise(rb_eRuntimeError, "Req wasn't initialized!"); \
+ ossl_raise(rb_eRuntimeError, "Req wasn't initialized!"); \
} \
} while (0)
@@ -39,7 +39,7 @@ ossl_x509req_free(void *ptr)
static const rb_data_type_t ossl_x509req_type = {
"OpenSSL/X509/REQ",
{
- 0, ossl_x509req_free,
+ 0, ossl_x509req_free,
},
0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
};
@@ -68,7 +68,7 @@ ossl_x509req_alloc(VALUE klass)
obj = NewX509Req(klass);
if (!(req = X509_REQ_new())) {
- ossl_raise(eX509ReqError, NULL);
+ ossl_raise(eX509ReqError, NULL);
}
SetX509Req(obj, req);
@@ -84,7 +84,7 @@ ossl_x509req_initialize(int argc, VALUE *argv, VALUE self)
rb_check_frozen(self);
if (rb_scan_args(argc, argv, "01", &arg) == 0) {
- return self;
+ return self;
}
arg = ossl_to_der_if_possible(arg);
in = ossl_obj2bio(&arg);
@@ -114,7 +114,7 @@ ossl_x509req_copy(VALUE self, VALUE other)
GetX509Req(self, a);
GetX509Req(other, b);
if (!(req = X509_REQ_dup(b))) {
- ossl_raise(eX509ReqError, NULL);
+ ossl_raise(eX509ReqError, NULL);
}
X509_REQ_free(a);
DATA_PTR(self) = req;
@@ -130,11 +130,11 @@ ossl_x509req_to_pem(VALUE self)
GetX509Req(self, req);
if (!(out = BIO_new(BIO_s_mem()))) {
- ossl_raise(eX509ReqError, NULL);
+ ossl_raise(eX509ReqError, NULL);
}
if (!PEM_write_bio_X509_REQ(out, req)) {
- BIO_free(out);
- ossl_raise(eX509ReqError, NULL);
+ BIO_free(out);
+ ossl_raise(eX509ReqError, NULL);
}
return ossl_membio2str(out);
@@ -150,11 +150,11 @@ ossl_x509req_to_der(VALUE self)
GetX509Req(self, req);
if ((len = i2d_X509_REQ(req, NULL)) <= 0)
- ossl_raise(eX509ReqError, NULL);
+ ossl_raise(eX509ReqError, NULL);
str = rb_str_new(0, len);
p = (unsigned char *)RSTRING_PTR(str);
if (i2d_X509_REQ(req, &p) <= 0)
- ossl_raise(eX509ReqError, NULL);
+ ossl_raise(eX509ReqError, NULL);
ossl_str_adjust(str, p);
return str;
@@ -168,11 +168,11 @@ ossl_x509req_to_text(VALUE self)
GetX509Req(self, req);
if (!(out = BIO_new(BIO_s_mem()))) {
- ossl_raise(eX509ReqError, NULL);
+ ossl_raise(eX509ReqError, NULL);
}
if (!X509_REQ_print(out, req)) {
- BIO_free(out);
- ossl_raise(eX509ReqError, NULL);
+ BIO_free(out);
+ ossl_raise(eX509ReqError, NULL);
}
return ossl_membio2str(out);
@@ -191,7 +191,7 @@ ossl_x509req_to_x509(VALUE self, VALUE days, VALUE key)
GetX509Req(self, req);
...
if (!(x509 = X509_REQ_to_X509(req, d, pkey))) {
- ossl_raise(eX509ReqError, NULL);
+ ossl_raise(eX509ReqError, NULL);
}
return ossl_x509_new(x509);
@@ -217,11 +217,11 @@ ossl_x509req_set_version(VALUE self, VALUE version)
long ver;
if ((ver = NUM2LONG(version)) < 0) {
- ossl_raise(eX509ReqError, "version must be >= 0!");
+ ossl_raise(eX509ReqError, "version must be >= 0!");
}
GetX509Req(self, req);
if (!X509_REQ_set_version(req, ver)) {
- ossl_raise(eX509ReqError, "X509_REQ_set_version");
+ ossl_raise(eX509ReqError, "X509_REQ_set_version");
}
return version;
@@ -231,11 +231,11 @@ static VALUE
ossl_x509req_get_subject(VALUE self)
{
X509_REQ *req;
- X509_NAME *name;
+ const X509_NAME *name;
GetX509Req(self, req);
if (!(name = X509_REQ_get_subject_name(req))) { /* NO DUP - don't free */
- ossl_raise(eX509ReqError, NULL);
+ ossl_raise(eX509ReqError, NULL);
}
return ossl_x509name_new(name);
@@ -249,33 +249,32 @@ ossl_x509req_set_subject(VALUE self, VALUE subject)
GetX509Req(self, req);
/* DUPs name */
if (!X509_REQ_set_subject_name(req, GetX509NamePtr(subject))) {
- ossl_raise(eX509ReqError, NULL);
+ ossl_raise(eX509ReqError, NULL);
}
return subject;
}
+/*
+ * call-seq:
+ * req.signature_algorithm -> string
+ *
+ * Returns the signature algorithm used to sign this request.
+ *
+ * Returns the long name of the signature algorithm, or the dotted decimal
+ * notation if \OpenSSL does not define a long name for it.
+ */
static VALUE
ossl_x509req_get_signature_algorithm(VALUE self)
{
X509_REQ *req;
const X509_ALGOR *alg;
const ASN1_OBJECT *obj;
- BIO *out;
GetX509Req(self, req);
-
- if (!(out = BIO_new(BIO_s_mem()))) {
- ossl_raise(eX509ReqError, NULL);
- }
X509_REQ_get0_signature(req, NULL, &alg);
X509_ALGOR_get0(&obj, NULL, NULL, alg);
- if (!i2a_ASN1_OBJECT(out, obj)) {
- BIO_free(out);
- ossl_raise(eX509ReqError, NULL);
- }
-
- return ossl_membio2str(out);
+ return ossl_asn1obj_to_string_long_name(obj);
}
static VALUE
@@ -286,7 +285,7 @@ ossl_x509req_get_public_key(VALUE self)
GetX509Req(self, req);
if (!(pkey = X509_REQ_get_pubkey(req))) { /* adds reference */
- ossl_raise(eX509ReqError, NULL);
+ ossl_raise(eX509ReqError, NULL);
}
return ossl_pkey_wrap(pkey);
@@ -302,7 +301,7 @@ ossl_x509req_set_public_key(VALUE self, VALUE key)
pkey = GetPKeyPtr(key);
ossl_pkey_check_public_key(pkey);
if (!X509_REQ_set_pubkey(req, pkey))
- ossl_raise(eX509ReqError, "X509_REQ_set_pubkey");
+ ossl_raise(eX509ReqError, "X509_REQ_set_pubkey");
return key;
}
@@ -312,17 +311,14 @@ ossl_x509req_sign(VALUE self, VALUE key, VALUE digest)
X509_REQ *req;
EVP_PKEY *pkey;
const EVP_MD *md;
+ VALUE md_holder;
GetX509Req(self, req);
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);
- }
- if (!X509_REQ_sign(req, pkey, md)) {
- ossl_raise(eX509ReqError, NULL);
- }
+ /* NULL needed for some key types, e.g. Ed25519 */
+ md = NIL_P(digest) ? NULL : ossl_evp_md_fetch(digest, &md_holder);
+ if (!X509_REQ_sign(req, pkey, md))
+ ossl_raise(eX509ReqError, "X509_REQ_sign");
return self;
}
@@ -341,12 +337,12 @@ ossl_x509req_verify(VALUE self, VALUE key)
ossl_pkey_check_public_key(pkey);
switch (X509_REQ_verify(req, pkey)) {
case 1:
- return Qtrue;
+ return Qtrue;
case 0:
- ossl_clear_error();
- return Qfalse;
+ ossl_clear_error();
+ return Qfalse;
default:
- ossl_raise(eX509ReqError, NULL);
+ ossl_raise(eX509ReqError, NULL);
}
}
@@ -355,20 +351,20 @@ ossl_x509req_get_attributes(VALUE self)
{
X509_REQ *req;
int count, i;
- X509_ATTRIBUTE *attr;
+ const X509_ATTRIBUTE *attr;
VALUE ary;
GetX509Req(self, req);
count = X509_REQ_get_attr_count(req);
if (count < 0) {
- OSSL_Debug("count < 0???");
- return rb_ary_new();
+ OSSL_Debug("count < 0???");
+ return rb_ary_new();
}
ary = rb_ary_new2(count);
for (i=0; i<count; i++) {
- attr = X509_REQ_get_attr(req, i);
- rb_ary_push(ary, ossl_x509attr_new(attr));
+ attr = X509_REQ_get_attr(req, i);
+ rb_ary_push(ary, ossl_x509attr_new(attr));
}
return ary;
@@ -384,17 +380,17 @@ ossl_x509req_set_attributes(VALUE self, VALUE ary)
Check_Type(ary, T_ARRAY);
for (i=0;i<RARRAY_LEN(ary); i++) {
- OSSL_Check_Kind(RARRAY_AREF(ary, i), cX509Attr);
+ OSSL_Check_Kind(RARRAY_AREF(ary, i), cX509Attr);
}
GetX509Req(self, req);
for (i = X509_REQ_get_attr_count(req); i > 0; i--)
X509_ATTRIBUTE_free(X509_REQ_delete_attr(req, 0));
for (i=0;i<RARRAY_LEN(ary); i++) {
- item = RARRAY_AREF(ary, i);
- attr = GetX509AttrPtr(item);
- if (!X509_REQ_add1_attr(req, attr)) {
- ossl_raise(eX509ReqError, "X509_REQ_add1_attr");
- }
+ item = RARRAY_AREF(ary, i);
+ attr = GetX509AttrPtr(item);
+ if (!X509_REQ_add1_attr(req, attr)) {
+ ossl_raise(eX509ReqError, "X509_REQ_add1_attr");
+ }
}
return ary;
}
@@ -406,7 +402,7 @@ ossl_x509req_add_attribute(VALUE self, VALUE attr)
GetX509Req(self, req);
if (!X509_REQ_add1_attr(req, GetX509AttrPtr(attr))) {
- ossl_raise(eX509ReqError, NULL);
+ ossl_raise(eX509ReqError, NULL);
}
return attr;
@@ -418,12 +414,6 @@ ossl_x509req_add_attribute(VALUE self, VALUE attr)
void
Init_ossl_x509req(void)
{
-#if 0
- mOSSL = rb_define_module("OpenSSL");
- eOSSLError = rb_define_class_under(mOSSL, "OpenSSLError", rb_eStandardError);
- mX509 = rb_define_module_under(mOSSL, "X509");
-#endif
-
eX509ReqError = rb_define_class_under(mX509, "RequestError", eOSSLError);
cX509Req = rb_define_class_under(mX509, "Request", rb_cObject);
diff --git a/ext/openssl/ossl_x509revoked.c b/ext/openssl/ossl_x509revoked.c
index 9496c4bf1b..0151961e9f 100644
--- a/ext/openssl/ossl_x509revoked.c
+++ b/ext/openssl/ossl_x509revoked.c
@@ -13,14 +13,14 @@
TypedData_Wrap_Struct((klass), &ossl_x509rev_type, 0)
#define SetX509Rev(obj, rev) do { \
if (!(rev)) { \
- ossl_raise(rb_eRuntimeError, "REV wasn't initialized!"); \
+ ossl_raise(rb_eRuntimeError, "REV wasn't initialized!"); \
} \
RTYPEDDATA_DATA(obj) = (rev); \
} while (0)
#define GetX509Rev(obj, rev) do { \
TypedData_Get_Struct((obj), X509_REVOKED, &ossl_x509rev_type, (rev)); \
if (!(rev)) { \
- ossl_raise(rb_eRuntimeError, "REV wasn't initialized!"); \
+ ossl_raise(rb_eRuntimeError, "REV wasn't initialized!"); \
} \
} while (0)
@@ -39,7 +39,7 @@ ossl_x509rev_free(void *ptr)
static const rb_data_type_t ossl_x509rev_type = {
"OpenSSL/X509/REV",
{
- 0, ossl_x509rev_free,
+ 0, ossl_x509rev_free,
},
0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
};
@@ -48,15 +48,16 @@ static const rb_data_type_t ossl_x509rev_type = {
* PUBLIC
*/
VALUE
-ossl_x509revoked_new(X509_REVOKED *rev)
+ossl_x509revoked_new(const X509_REVOKED *rev)
{
X509_REVOKED *new;
VALUE obj;
obj = NewX509Rev(cX509Rev);
- new = X509_REVOKED_dup(rev);
+ /* OpenSSL 1.1.1 takes a non-const pointer */
+ new = X509_REVOKED_dup((X509_REVOKED *)rev);
if (!new)
- ossl_raise(eX509RevError, "X509_REVOKED_dup");
+ ossl_raise(eX509RevError, "X509_REVOKED_dup");
SetX509Rev(obj, new);
return obj;
@@ -69,7 +70,7 @@ DupX509RevokedPtr(VALUE obj)
GetX509Rev(obj, rev);
if (!(new = X509_REVOKED_dup(rev))) {
- ossl_raise(eX509RevError, NULL);
+ ossl_raise(eX509RevError, NULL);
}
return new;
@@ -86,7 +87,7 @@ ossl_x509revoked_alloc(VALUE klass)
obj = NewX509Rev(klass);
if (!(rev = X509_REVOKED_new())) {
- ossl_raise(eX509RevError, NULL);
+ ossl_raise(eX509RevError, NULL);
}
SetX509Rev(obj, rev);
@@ -112,7 +113,7 @@ ossl_x509revoked_initialize_copy(VALUE self, VALUE other)
rev_new = X509_REVOKED_dup(rev_other);
if (!rev_new)
- ossl_raise(eX509RevError, "X509_REVOKED_dup");
+ ossl_raise(eX509RevError, "X509_REVOKED_dup");
SetX509Rev(self, rev_new);
X509_REVOKED_free(rev);
@@ -139,8 +140,8 @@ ossl_x509revoked_set_serial(VALUE self, VALUE num)
GetX509Rev(self, rev);
asn1int = num_to_asn1integer(num, NULL);
if (!X509_REVOKED_set_serialNumber(rev, asn1int)) {
- ASN1_INTEGER_free(asn1int);
- ossl_raise(eX509RevError, "X509_REVOKED_set_serialNumber");
+ ASN1_INTEGER_free(asn1int);
+ ossl_raise(eX509RevError, "X509_REVOKED_set_serialNumber");
}
ASN1_INTEGER_free(asn1int);
@@ -156,7 +157,7 @@ ossl_x509revoked_get_time(VALUE self)
GetX509Rev(self, rev);
time = X509_REVOKED_get0_revocationDate(rev);
if (!time)
- return Qnil;
+ return Qnil;
return asn1time_to_time(time);
}
@@ -170,8 +171,8 @@ ossl_x509revoked_set_time(VALUE self, VALUE time)
GetX509Rev(self, rev);
asn1time = ossl_x509_time_adjust(NULL, time);
if (!X509_REVOKED_set_revocationDate(rev, asn1time)) {
- ASN1_TIME_free(asn1time);
- ossl_raise(eX509RevError, "X509_REVOKED_set_revocationDate");
+ ASN1_TIME_free(asn1time);
+ ossl_raise(eX509RevError, "X509_REVOKED_set_revocationDate");
}
ASN1_TIME_free(asn1time);
@@ -185,15 +186,15 @@ ossl_x509revoked_get_extensions(VALUE self)
{
X509_REVOKED *rev;
int count, i;
- X509_EXTENSION *ext;
+ const X509_EXTENSION *ext;
VALUE ary;
GetX509Rev(self, rev);
count = X509_REVOKED_get_ext_count(rev);
ary = rb_ary_new_capa(count);
for (i=0; i<count; i++) {
- ext = X509_REVOKED_get_ext(rev, i);
- rb_ary_push(ary, ossl_x509ext_new(ext));
+ ext = X509_REVOKED_get_ext(rev, i);
+ rb_ary_push(ary, ossl_x509ext_new(ext));
}
return ary;
@@ -212,17 +213,17 @@ ossl_x509revoked_set_extensions(VALUE self, VALUE ary)
Check_Type(ary, T_ARRAY);
for (i=0; i<RARRAY_LEN(ary); i++) {
- OSSL_Check_Kind(RARRAY_AREF(ary, i), cX509Ext);
+ OSSL_Check_Kind(RARRAY_AREF(ary, i), cX509Ext);
}
GetX509Rev(self, rev);
for (i = X509_REVOKED_get_ext_count(rev); i > 0; i--)
X509_EXTENSION_free(X509_REVOKED_delete_ext(rev, 0));
for (i=0; i<RARRAY_LEN(ary); i++) {
- item = RARRAY_AREF(ary, i);
- ext = GetX509ExtPtr(item);
- if(!X509_REVOKED_add_ext(rev, ext, -1)) {
- ossl_raise(eX509RevError, "X509_REVOKED_add_ext");
- }
+ item = RARRAY_AREF(ary, i);
+ ext = GetX509ExtPtr(item);
+ if(!X509_REVOKED_add_ext(rev, ext, -1)) {
+ ossl_raise(eX509RevError, "X509_REVOKED_add_ext");
+ }
}
return ary;
@@ -235,7 +236,7 @@ ossl_x509revoked_add_extension(VALUE self, VALUE ext)
GetX509Rev(self, rev);
if (!X509_REVOKED_add_ext(rev, GetX509ExtPtr(ext), -1)) {
- ossl_raise(eX509RevError, NULL);
+ ossl_raise(eX509RevError, NULL);
}
return ext;
@@ -252,11 +253,11 @@ ossl_x509revoked_to_der(VALUE self)
GetX509Rev(self, rev);
len = i2d_X509_REVOKED(rev, NULL);
if (len <= 0)
- ossl_raise(eX509RevError, "i2d_X509_REVOKED");
+ ossl_raise(eX509RevError, "i2d_X509_REVOKED");
str = rb_str_new(NULL, len);
p = (unsigned char *)RSTRING_PTR(str);
if (i2d_X509_REVOKED(rev, &p) <= 0)
- ossl_raise(eX509RevError, "i2d_X509_REVOKED");
+ ossl_raise(eX509RevError, "i2d_X509_REVOKED");
ossl_str_adjust(str, p);
return str;
}
@@ -267,12 +268,6 @@ ossl_x509revoked_to_der(VALUE self)
void
Init_ossl_x509revoked(void)
{
-#if 0
- mOSSL = rb_define_module("OpenSSL");
- eOSSLError = rb_define_class_under(mOSSL, "OpenSSLError", rb_eStandardError);
- mX509 = rb_define_module_under(mOSSL, "X509");
-#endif
-
eX509RevError = rb_define_class_under(mX509, "RevokedError", eOSSLError);
cX509Rev = rb_define_class_under(mX509, "Revoked", rb_cObject);
diff --git a/ext/openssl/ossl_x509store.c b/ext/openssl/ossl_x509store.c
index c18596cbf5..9e43336c44 100644
--- a/ext/openssl/ossl_x509store.c
+++ b/ext/openssl/ossl_x509store.c
@@ -13,14 +13,14 @@
TypedData_Wrap_Struct((klass), &ossl_x509store_type, 0)
#define SetX509Store(obj, st) do { \
if (!(st)) { \
- ossl_raise(rb_eRuntimeError, "STORE wasn't initialized!"); \
+ ossl_raise(rb_eRuntimeError, "STORE wasn't initialized!"); \
} \
RTYPEDDATA_DATA(obj) = (st); \
} while (0)
#define GetX509Store(obj, st) do { \
TypedData_Get_Struct((obj), X509_STORE, &ossl_x509store_type, (st)); \
if (!(st)) { \
- ossl_raise(rb_eRuntimeError, "STORE wasn't initialized!"); \
+ ossl_raise(rb_eRuntimeError, "STORE wasn't initialized!"); \
} \
} while (0)
@@ -28,14 +28,14 @@
TypedData_Wrap_Struct((klass), &ossl_x509stctx_type, 0)
#define SetX509StCtx(obj, ctx) do { \
if (!(ctx)) { \
- ossl_raise(rb_eRuntimeError, "STORE_CTX wasn't initialized!"); \
+ ossl_raise(rb_eRuntimeError, "STORE_CTX wasn't initialized!"); \
} \
RTYPEDDATA_DATA(obj) = (ctx); \
} while (0)
#define GetX509StCtx(obj, ctx) do { \
TypedData_Get_Struct((obj), X509_STORE_CTX, &ossl_x509stctx_type, (ctx)); \
if (!(ctx)) { \
- ossl_raise(rb_eRuntimeError, "STORE_CTX is out of scope!"); \
+ ossl_raise(rb_eRuntimeError, "STORE_CTX is out of scope!"); \
} \
} while (0)
@@ -62,7 +62,7 @@ call_verify_cb_proc(VALUE arg)
{
struct ossl_verify_cb_args *args = (struct ossl_verify_cb_args *)arg;
return rb_funcall(args->proc, rb_intern("call"), 2,
- args->preverify_ok, args->store_ctx);
+ args->preverify_ok, args->store_ctx);
}
int
@@ -73,33 +73,33 @@ ossl_verify_cb_call(VALUE proc, int ok, X509_STORE_CTX *ctx)
int state;
if (NIL_P(proc))
- return ok;
+ return ok;
ret = Qfalse;
rctx = rb_protect(ossl_x509stctx_new_i, (VALUE)ctx, &state);
if (state) {
- rb_set_errinfo(Qnil);
- rb_warn("StoreContext initialization failure");
+ rb_set_errinfo(Qnil);
+ rb_warn("StoreContext initialization failure");
}
else {
- args.proc = proc;
- args.preverify_ok = ok ? Qtrue : Qfalse;
- args.store_ctx = rctx;
- ret = rb_protect(call_verify_cb_proc, (VALUE)&args, &state);
- if (state) {
- rb_set_errinfo(Qnil);
- rb_warn("exception in verify_callback is ignored");
- }
- RTYPEDDATA_DATA(rctx) = NULL;
+ args.proc = proc;
+ args.preverify_ok = ok ? Qtrue : Qfalse;
+ args.store_ctx = rctx;
+ ret = rb_protect(call_verify_cb_proc, (VALUE)&args, &state);
+ if (state) {
+ rb_set_errinfo(Qnil);
+ rb_warn("exception in verify_callback is ignored");
+ }
+ RTYPEDDATA_DATA(rctx) = NULL;
}
if (ret == Qtrue) {
- X509_STORE_CTX_set_error(ctx, X509_V_OK);
- ok = 1;
+ X509_STORE_CTX_set_error(ctx, X509_V_OK);
+ ok = 1;
}
else {
- if (X509_STORE_CTX_get_error(ctx) == X509_V_OK)
- X509_STORE_CTX_set_error(ctx, X509_V_ERR_CERT_REJECTED);
- ok = 0;
+ if (X509_STORE_CTX_get_error(ctx) == X509_V_OK)
+ X509_STORE_CTX_set_error(ctx, X509_V_ERR_CERT_REJECTED);
+ ok = 0;
}
return ok;
@@ -159,10 +159,10 @@ x509store_verify_cb(int ok, X509_STORE_CTX *ctx)
proc = (VALUE)X509_STORE_CTX_get_ex_data(ctx, stctx_ex_verify_cb_idx);
if (!proc)
- proc = (VALUE)X509_STORE_get_ex_data(X509_STORE_CTX_get0_store(ctx),
- store_ex_verify_cb_idx);
+ proc = (VALUE)X509_STORE_get_ex_data(X509_STORE_CTX_get0_store(ctx),
+ store_ex_verify_cb_idx);
if (!proc)
- return ok;
+ return ok;
return ossl_verify_cb_call(proc, ok, ctx);
}
@@ -190,8 +190,9 @@ ossl_x509store_set_vfy_cb(VALUE self, VALUE cb)
X509_STORE *store;
GetX509Store(self, store);
+ if (!X509_STORE_set_ex_data(store, store_ex_verify_cb_idx, (void *)cb))
+ ossl_raise(eX509StoreError, "X509_STORE_set_ex_data");
rb_iv_set(self, "@verify_callback", cb);
- X509_STORE_set_ex_data(store, store_ex_verify_cb_idx, (void *)cb);
RB_OBJ_WRITTEN(self, Qundef, cb);
return cb;
@@ -484,7 +485,7 @@ ossl_x509store_verify(int argc, VALUE *argv, VALUE self)
rb_scan_args(argc, argv, "11", &cert, &chain);
ctx = rb_funcall(cX509StoreContext, rb_intern("new"), 3, self, cert, chain);
proc = rb_block_given_p() ? rb_block_proc() :
- rb_iv_get(self, "@verify_callback");
+ rb_iv_get(self, "@verify_callback");
rb_iv_set(ctx, "@verify_callback", proc);
result = rb_funcall(ctx, rb_intern("verify"), 0);
@@ -512,10 +513,8 @@ static void
ossl_x509stctx_free(void *ptr)
{
X509_STORE_CTX *ctx = ptr;
- if (X509_STORE_CTX_get0_untrusted(ctx))
- sk_X509_pop_free(X509_STORE_CTX_get0_untrusted(ctx), X509_free);
- if (X509_STORE_CTX_get0_cert(ctx))
- X509_free(X509_STORE_CTX_get0_cert(ctx));
+ sk_X509_pop_free(X509_STORE_CTX_get0_untrusted(ctx), X509_free);
+ X509_free((X509 *)X509_STORE_CTX_get0_cert(ctx));
X509_STORE_CTX_free(ctx);
}
@@ -610,7 +609,8 @@ ossl_x509stctx_verify(VALUE self)
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);
+ if (!X509_STORE_CTX_set_ex_data(ctx, stctx_ex_verify_cb_idx, (void *)cb))
+ ossl_raise(eX509StoreError, "X509_STORE_CTX_set_ex_data");
RB_OBJ_WRITTEN(self, Qundef, cb);
switch (X509_verify_cert(ctx)) {
@@ -736,7 +736,7 @@ static VALUE
ossl_x509stctx_get_curr_cert(VALUE self)
{
X509_STORE_CTX *ctx;
- X509 *x509;
+ const X509 *x509;
GetX509StCtx(self, ctx);
x509 = X509_STORE_CTX_get_current_cert(ctx);
@@ -758,12 +758,12 @@ static VALUE
ossl_x509stctx_get_curr_crl(VALUE self)
{
X509_STORE_CTX *ctx;
- X509_CRL *crl;
+ const X509_CRL *crl;
GetX509StCtx(self, ctx);
crl = X509_STORE_CTX_get0_current_crl(ctx);
if (!crl)
- return Qnil;
+ return Qnil;
return ossl_x509crl_new(crl);
}
@@ -859,19 +859,13 @@ void
Init_ossl_x509store(void)
{
#undef rb_intern
-#if 0
- mOSSL = rb_define_module("OpenSSL");
- eOSSLError = rb_define_class_under(mOSSL, "OpenSSLError", rb_eStandardError);
- mX509 = rb_define_module_under(mOSSL, "X509");
-#endif
-
/* Register ext_data slot for verify callback Proc */
stctx_ex_verify_cb_idx = X509_STORE_CTX_get_ex_new_index(0, (void *)"stctx_ex_verify_cb_idx", 0, 0, 0);
if (stctx_ex_verify_cb_idx < 0)
- ossl_raise(eOSSLError, "X509_STORE_CTX_get_ex_new_index");
+ ossl_raise(eOSSLError, "X509_STORE_CTX_get_ex_new_index");
store_ex_verify_cb_idx = X509_STORE_get_ex_new_index(0, (void *)"store_ex_verify_cb_idx", 0, 0, 0);
if (store_ex_verify_cb_idx < 0)
- ossl_raise(eOSSLError, "X509_STORE_get_ex_new_index");
+ ossl_raise(eOSSLError, "X509_STORE_get_ex_new_index");
eX509StoreError = rb_define_class_under(mX509, "StoreError", eOSSLError);
diff --git a/ext/psych/extconf.rb b/ext/psych/extconf.rb
index e7dd0bb60a..589e201c1c 100644
--- a/ext/psych/extconf.rb
+++ b/ext/psych/extconf.rb
@@ -36,8 +36,11 @@ if yaml_source
libyaml = "libyaml.#$LIBEXT"
$cleanfiles << libyaml
$LOCAL_LIBS.prepend("$(LIBYAML) ")
-else # default to pre-installed libyaml
- pkg_config('yaml-0.1')
+
+ # default to pre-installed libyaml
+elsif pkg_config('yaml-0.1')
+ # found with pkg-config
+else
dir_config('libyaml')
find_header('yaml.h') or abort "yaml.h not found"
find_library('yaml', 'yaml_get_version') or abort "libyaml not found"
diff --git a/ext/psych/lib/psych.rb b/ext/psych/lib/psych.rb
index 0c158c9ff3..850a6d1937 100644
--- a/ext/psych/lib/psych.rb
+++ b/ext/psych/lib/psych.rb
@@ -269,10 +269,10 @@ module Psych
# YAML documents that are supplied via user input. Instead, please use the
# load method or the safe_load method.
#
- def self.unsafe_load yaml, filename: nil, fallback: false, symbolize_names: false, freeze: false, strict_integer: false
+ def self.unsafe_load yaml, filename: nil, fallback: false, symbolize_names: false, freeze: false, strict_integer: false, parse_symbols: true
result = parse(yaml, filename: filename)
return fallback unless result
- result.to_ruby(symbolize_names: symbolize_names, freeze: freeze, strict_integer: strict_integer)
+ result.to_ruby(symbolize_names: symbolize_names, freeze: freeze, strict_integer: strict_integer, parse_symbols: parse_symbols)
end
###
@@ -320,13 +320,13 @@ module Psych
# Psych.safe_load("---\n foo: bar") # => {"foo"=>"bar"}
# Psych.safe_load("---\n foo: bar", symbolize_names: true) # => {:foo=>"bar"}
#
- def self.safe_load yaml, permitted_classes: [], permitted_symbols: [], aliases: false, filename: nil, fallback: nil, symbolize_names: false, freeze: false, strict_integer: false
+ def self.safe_load yaml, permitted_classes: [], permitted_symbols: [], aliases: false, filename: nil, fallback: nil, symbolize_names: false, freeze: false, strict_integer: false, parse_symbols: true
result = parse(yaml, filename: filename)
return fallback unless result
class_loader = ClassLoader::Restricted.new(permitted_classes.map(&:to_s),
permitted_symbols.map(&:to_s))
- scanner = ScalarScanner.new class_loader, strict_integer: strict_integer
+ scanner = ScalarScanner.new class_loader, strict_integer: strict_integer, parse_symbols: parse_symbols
visitor = if aliases
Visitors::ToRuby.new scanner, class_loader, symbolize_names: symbolize_names, freeze: freeze
else
@@ -366,7 +366,7 @@ module Psych
# Raises a TypeError when `yaml` parameter is NilClass. This method is
# similar to `safe_load` except that `Symbol` objects are allowed by default.
#
- def self.load yaml, permitted_classes: [Symbol], permitted_symbols: [], aliases: false, filename: nil, fallback: nil, symbolize_names: false, freeze: false, strict_integer: false
+ def self.load yaml, permitted_classes: [Symbol], permitted_symbols: [], aliases: false, filename: nil, fallback: nil, symbolize_names: false, freeze: false, strict_integer: false, parse_symbols: true
safe_load yaml, permitted_classes: permitted_classes,
permitted_symbols: permitted_symbols,
aliases: aliases,
@@ -374,7 +374,8 @@ module Psych
fallback: fallback,
symbolize_names: symbolize_names,
freeze: freeze,
- strict_integer: strict_integer
+ strict_integer: strict_integer,
+ parse_symbols: parse_symbols
end
###
diff --git a/ext/psych/lib/psych/core_ext.rb b/ext/psych/lib/psych/core_ext.rb
index fc259fd4a2..6dfd0f1696 100644
--- a/ext/psych/lib/psych/core_ext.rb
+++ b/ext/psych/lib/psych/core_ext.rb
@@ -14,13 +14,9 @@ class Object
end
end
-if defined?(::IRB)
- require_relative 'y'
-end
-
# Up to Ruby 3.4, Set was a regular object and was dumped as such
# by Pysch.
-# Starting from Ruby 3.5 it's a core class written in C, so we have to implement
+# Starting from Ruby 4.0 it's a core class written in C, so we have to implement
# #encode_with / #init_with to preserve backward compatibility.
if defined?(::Set) && Set.new.instance_variables.empty?
class Set
diff --git a/ext/psych/lib/psych/nodes/node.rb b/ext/psych/lib/psych/nodes/node.rb
index 6ae5c59148..fc27448f2e 100644
--- a/ext/psych/lib/psych/nodes/node.rb
+++ b/ext/psych/lib/psych/nodes/node.rb
@@ -45,8 +45,8 @@ module Psych
# Convert this node to Ruby.
#
# See also Psych::Visitors::ToRuby
- def to_ruby(symbolize_names: false, freeze: false, strict_integer: false)
- Visitors::ToRuby.create(symbolize_names: symbolize_names, freeze: freeze, strict_integer: strict_integer).accept(self)
+ def to_ruby(symbolize_names: false, freeze: false, strict_integer: false, parse_symbols: true)
+ Visitors::ToRuby.create(symbolize_names: symbolize_names, freeze: freeze, strict_integer: strict_integer, parse_symbols: parse_symbols).accept(self)
end
alias :transform :to_ruby
diff --git a/ext/psych/lib/psych/scalar_scanner.rb b/ext/psych/lib/psych/scalar_scanner.rb
index 8cf868f863..6a556fb3b8 100644
--- a/ext/psych/lib/psych/scalar_scanner.rb
+++ b/ext/psych/lib/psych/scalar_scanner.rb
@@ -27,10 +27,11 @@ module Psych
attr_reader :class_loader
# Create a new scanner
- def initialize class_loader, strict_integer: false
+ def initialize class_loader, strict_integer: false, parse_symbols: true
@symbol_cache = {}
@class_loader = class_loader
@strict_integer = strict_integer
+ @parse_symbols = parse_symbols
end
# Tokenize +string+ returning the Ruby object
@@ -72,7 +73,7 @@ module Psych
-Float::INFINITY
elsif string.match?(/^\.nan$/i)
Float::NAN
- elsif string.match?(/^:./)
+ elsif @parse_symbols && string.match?(/^:./)
if string =~ /^:(["'])(.*)\1/
@symbol_cache[string] = class_loader.symbolize($2.sub(/^:/, ''))
else
diff --git a/ext/psych/lib/psych/versions.rb b/ext/psych/lib/psych/versions.rb
index 3202b10296..6c1679bf65 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.6'
+ VERSION = '5.4.0'
if RUBY_ENGINE == 'jruby'
- DEFAULT_SNAKEYAML_VERSION = '2.9'.freeze
+ DEFAULT_SNAKEYAML_VERSION = '2.10'.freeze
end
end
diff --git a/ext/psych/lib/psych/visitors/to_ruby.rb b/ext/psych/lib/psych/visitors/to_ruby.rb
index 580a74e9fb..475444e589 100644
--- a/ext/psych/lib/psych/visitors/to_ruby.rb
+++ b/ext/psych/lib/psych/visitors/to_ruby.rb
@@ -12,9 +12,13 @@ module Psych
###
# This class walks a YAML AST, converting each node to Ruby
class ToRuby < Psych::Visitors::Visitor
- def self.create(symbolize_names: false, freeze: false, strict_integer: false)
+ unless RUBY_VERSION < "3.2"
+ DATA_INITIALIZE = Data.instance_method(:initialize)
+ end
+
+ def self.create(symbolize_names: false, freeze: false, strict_integer: false, parse_symbols: true)
class_loader = ClassLoader.new
- scanner = ScalarScanner.new class_loader, strict_integer: strict_integer
+ scanner = ScalarScanner.new class_loader, strict_integer: strict_integer, parse_symbols: parse_symbols
new(scanner, class_loader, symbolize_names: symbolize_names, freeze: freeze)
end
@@ -219,7 +223,7 @@ module Psych
revive_data_members(members, o)
end
data ||= allocate_anon_data(o, members)
- init_struct(data, **members)
+ DATA_INITIALIZE.bind_call(data, **members)
data.freeze
data
diff --git a/ext/psych/psych_parser.c b/ext/psych/psych_parser.c
index d973496284..00a2207b58 100644
--- a/ext/psych/psych_parser.c
+++ b/ext/psych/psych_parser.c
@@ -32,9 +32,20 @@ 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);
+ char * str = StringValuePtr(string);
+ size_t len = (size_t)RSTRING_LEN(string);
+
+ /* IO#read(size) is documented to return at most `size` bytes, but a
+ * misbehaving IO-like object may return more. Clamp the copy to the
+ * buffer libyaml gave us to avoid writing past its end, rounding down
+ * to a character boundary so a multibyte character is never split. */
+ if(len > size) {
+ rb_encoding * enc = rb_enc_get(string);
+ len = (size_t)(rb_enc_left_char_head(str, str + size, str + len, enc) - str);
+ }
+
+ *read = len;
+ memcpy(buf, str, len);
}
return 1;
diff --git a/ext/psych/psych_to_ruby.c b/ext/psych/psych_to_ruby.c
index d473a5f840..3ab0138b52 100644
--- a/ext/psych/psych_to_ruby.c
+++ b/ext/psych/psych_to_ruby.c
@@ -10,7 +10,11 @@ static VALUE build_exception(VALUE self, VALUE klass, VALUE mesg)
{
VALUE e = rb_obj_alloc(klass);
+#ifdef TRUFFLERUBY
+ rb_exc_set_message(e, mesg);
+#else
rb_iv_set(e, "mesg", mesg);
+#endif
return e;
}
@@ -24,15 +28,6 @@ static VALUE path2class(VALUE self, VALUE path)
return rb_path_to_class(path);
}
-static VALUE init_struct(VALUE self, VALUE data, VALUE attrs)
-{
- VALUE args = rb_ary_new2(1);
- rb_ary_push(args, attrs);
- rb_struct_initialize(data, args);
-
- return data;
-}
-
void Init_psych_to_ruby(void)
{
VALUE psych = rb_define_module("Psych");
@@ -42,7 +37,6 @@ void Init_psych_to_ruby(void)
VALUE visitor = rb_define_class_under(visitors, "Visitor", rb_cObject);
cPsychVisitorsToRuby = rb_define_class_under(visitors, "ToRuby", visitor);
- rb_define_private_method(cPsychVisitorsToRuby, "init_struct", init_struct, 2);
rb_define_private_method(cPsychVisitorsToRuby, "build_exception", build_exception, 2);
rb_define_private_method(class_loader, "path2class", path2class, 1);
}
diff --git a/ext/pty/extconf.rb b/ext/pty/extconf.rb
index da3655cf4d..ae2cb45d3c 100644
--- a/ext/pty/extconf.rb
+++ b/ext/pty/extconf.rb
@@ -21,6 +21,8 @@ if /mswin|mingw|bccwin/ !~ RUBY_PLATFORM
(util or have_func("openpty")) or
have_func("_getpty") or
have_func("ioctl")
+ have_macro("HAVE_FCHMOD") or have_func("fchmod")
+ have_macro("HAVE_FCHOWN") or have_func("fchown")
create_makefile('pty')
end
end
diff --git a/ext/pty/pty.c b/ext/pty/pty.c
index 7c79f81e33..3d5977707f 100644
--- a/ext/pty/pty.c
+++ b/ext/pty/pty.c
@@ -274,12 +274,23 @@ ptsname_r(int fd, char *buf, size_t buflen)
# define HAVE_PTSNAME_R 1
#endif
+#ifdef HAVE_FCHMOD
+# define change_mode(name, fd, mode) fchmod(fd, mode)
+#else
+# define change_mode(name, fd, mode) chmod(name, mode)
+#endif
+#ifdef HAVE_FCHOWN
+# define change_owner(name, fd, uid, gid) fchown(fd, uid, gid)
+#else
+# define change_owner(name, fd, uid, gid) chown(name, uid, gid)
+#endif
+
#if defined(HAVE_POSIX_OPENPT) || defined(HAVE_OPENPTY) || defined(HAVE_PTSNAME_R)
-static int
-no_mesg(char *slavedevice, int nomesg)
+static inline int
+prevent_messages(const char *slavedevice, int fd, int nomesg)
{
if (nomesg)
- return chmod(slavedevice, 0600);
+ return change_mode(slavedevice, fd, 0600);
else
return 0;
}
@@ -340,8 +351,8 @@ get_device_once(int *master, int *slave, char SlaveName[DEVICELEN], int nomesg,
if (unlockpt(masterfd) == -1) goto error;
if (ptsname_r(masterfd, SlaveName, DEVICELEN) != 0) goto error;
slavedevice = SlaveName;
- if (no_mesg(slavedevice, nomesg) == -1) goto error;
if ((slavefd = rb_cloexec_open(slavedevice, O_RDWR|O_NOCTTY, 0)) == -1) goto error;
+ if (prevent_messages(slavedevice, slavefd, nomesg) == -1) goto error;
rb_update_max_fd(slavefd);
#if defined(I_PUSH) && !defined(__linux__) && !defined(_AIX)
@@ -375,7 +386,9 @@ get_device_once(int *master, int *slave, char SlaveName[DEVICELEN], int nomesg,
}
rb_fd_fix_cloexec(*master);
rb_fd_fix_cloexec(*slave);
- if (no_mesg(SlaveName, nomesg) == -1) {
+ if (prevent_messages(SlaveName, *slave, nomesg) == -1) {
+ close(*master);
+ close(*slave);
if (!fail) return -1;
rb_raise(rb_eRuntimeError, "can't chmod slave pty");
}
@@ -424,8 +437,8 @@ get_device_once(int *master, int *slave, char SlaveName[DEVICELEN], int nomesg,
if(unlockpt(masterfd) == -1) goto error;
if (ptsname_r(masterfd, SlaveName, DEVICELEN) != 0) goto error;
slavedevice = SlaveName;
- if (no_mesg(slavedevice, nomesg) == -1) goto error;
if((slavefd = rb_cloexec_open(slavedevice, O_RDWR, 0)) == -1) goto error;
+ if (prevent_messages(slavedevice, slavefd, nomesg) == -1) goto error;
rb_update_max_fd(slavefd);
#if defined(I_PUSH) && !defined(__linux__) && !defined(_AIX)
if(ioctl_I_PUSH(slavefd, "ptem") == -1) goto error;
@@ -478,8 +491,8 @@ get_device_once(int *master, int *slave, char SlaveName[DEVICELEN], int nomesg,
if ((slavefd = rb_cloexec_open(SlaveName,O_RDWR,0)) >= 0) {
rb_update_max_fd(slavefd);
*slave = slavefd;
- if (chown(SlaveName, getuid(), getgid()) != 0) goto error;
- if (chmod(SlaveName, nomesg ? 0600 : 0622) != 0) goto error;
+ if (change_owner(SlaveName, slavefd, getuid(), getgid()) != 0) goto error;
+ if (change_mode(SlaveName, slavefd, nomesg ? 0600 : 0622) != 0) goto error;
return 0;
}
close(masterfd);
diff --git a/ext/ripper/depend b/ext/ripper/depend
index c8ba34962c..db83378a1d 100644
--- a/ext/ripper/depend
+++ b/ext/ripper/depend
@@ -474,6 +474,7 @@ ripper.o: $(hdrdir)/ruby/internal/core/rclass.h
ripper.o: $(hdrdir)/ruby/internal/core/rdata.h
ripper.o: $(hdrdir)/ruby/internal/core/rfile.h
ripper.o: $(hdrdir)/ruby/internal/core/rhash.h
+ripper.o: $(hdrdir)/ruby/internal/core/rmatch.h
ripper.o: $(hdrdir)/ruby/internal/core/robject.h
ripper.o: $(hdrdir)/ruby/internal/core/rregexp.h
ripper.o: $(hdrdir)/ruby/internal/core/rstring.h
@@ -566,6 +567,7 @@ ripper.o: $(hdrdir)/ruby/missing.h
ripper.o: $(hdrdir)/ruby/onigmo.h
ripper.o: $(hdrdir)/ruby/oniguruma.h
ripper.o: $(hdrdir)/ruby/ractor.h
+ripper.o: $(hdrdir)/ruby/re.h
ripper.o: $(hdrdir)/ruby/regex.h
ripper.o: $(hdrdir)/ruby/ruby.h
ripper.o: $(hdrdir)/ruby/st.h
@@ -578,12 +580,15 @@ 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)/encindex.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/box.h
+ripper.o: $(top_srcdir)/internal/compar.h
ripper.o: $(top_srcdir)/internal/compile.h
ripper.o: $(top_srcdir)/internal/compilers.h
ripper.o: $(top_srcdir)/internal/complex.h
@@ -594,7 +599,6 @@ ripper.o: $(top_srcdir)/internal/gc.h
ripper.o: $(top_srcdir)/internal/hash.h
ripper.o: $(top_srcdir)/internal/imemo.h
ripper.o: $(top_srcdir)/internal/io.h
-ripper.o: $(top_srcdir)/internal/namespace.h
ripper.o: $(top_srcdir)/internal/numeric.h
ripper.o: $(top_srcdir)/internal/parse.h
ripper.o: $(top_srcdir)/internal/rational.h
@@ -605,6 +609,7 @@ ripper.o: $(top_srcdir)/internal/serial.h
ripper.o: $(top_srcdir)/internal/set_table.h
ripper.o: $(top_srcdir)/internal/static_assert.h
ripper.o: $(top_srcdir)/internal/string.h
+ripper.o: $(top_srcdir)/internal/struct.h
ripper.o: $(top_srcdir)/internal/symbol.h
ripper.o: $(top_srcdir)/internal/thread.h
ripper.o: $(top_srcdir)/internal/variable.h
@@ -810,8 +815,10 @@ 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/basic_operators.h
ripper_init.o: $(top_srcdir)/internal/bignum.h
ripper_init.o: $(top_srcdir)/internal/bits.h
+ripper_init.o: $(top_srcdir)/internal/compar.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
diff --git a/ext/ripper/lib/ripper/lexer.rb b/ext/ripper/lib/ripper/lexer.rb
index 870c79857b..9b849dfeae 100644
--- a/ext/ripper/lib/ripper/lexer.rb
+++ b/ext/ripper/lib/ripper/lexer.rb
@@ -68,7 +68,7 @@ class Ripper
when 0, :to_int
@to_int
when 1, :to_s
- @event
+ @to_s
else
nil
end
diff --git a/ext/socket/ancdata.c b/ext/socket/ancdata.c
index f1e9e42524..0e17d9e873 100644
--- a/ext/socket/ancdata.c
+++ b/ext/socket/ancdata.c
@@ -711,6 +711,9 @@ anc_inspect_passcred_credentials(int level, int type, VALUE data, VALUE ret)
static int
anc_inspect_socket_creds(int level, int type, VALUE data, VALUE ret)
{
+ long len;
+ const char *ptr;
+
if (level != SOL_SOCKET && type != SCM_CREDS)
return 0;
@@ -725,48 +728,59 @@ anc_inspect_socket_creds(int level, int type, VALUE data, VALUE ret)
* This heuristics works well except when sc_ngroups == CMGROUP_MAX.
*/
+ RSTRING_GETMEM(data, ptr, len);
#if defined(HAVE_TYPE_STRUCT_CMSGCRED) /* FreeBSD */
- if (RSTRING_LEN(data) == sizeof(struct cmsgcred)) {
+ if (len == sizeof(struct cmsgcred)) {
struct cmsgcred cred;
- memcpy(&cred, RSTRING_PTR(data), sizeof(struct cmsgcred));
+ int ngroups;
+ memcpy(&cred, ptr, sizeof(struct cmsgcred));
rb_str_catf(ret, " pid=%u", cred.cmcred_pid);
rb_str_catf(ret, " uid=%u", cred.cmcred_uid);
rb_str_catf(ret, " euid=%u", cred.cmcred_euid);
rb_str_catf(ret, " gid=%u", cred.cmcred_gid);
- if (cred.cmcred_ngroups) {
+ rb_str_catf(ret, " groups[%d]=[", cred.cmcred_ngroups);
+ ngroups = cred.cmcred_ngroups;
+ if (ngroups > 0) {
int i;
- const char *sep = " groups=";
- for (i = 0; i < cred.cmcred_ngroups; i++) {
- rb_str_catf(ret, "%s%u", sep, cred.cmcred_groups[i]);
- sep = ",";
+ rb_str_catf(ret, "%u", cred.cmcred_groups[0]);
+ if (ngroups > CMGROUP_MAX) ngroups = CMGROUP_MAX;
+ for (i = 1; i < ngroups; i++) {
+ rb_str_catf(ret, ",%u", cred.cmcred_groups[i]);
}
}
- rb_str_cat2(ret, " (cmsgcred)");
+ rb_str_cat2(ret, "] (cmsgcred)");
return 1;
}
#endif
#if defined(HAVE_TYPE_STRUCT_SOCKCRED) /* FreeBSD, NetBSD */
- if ((size_t)RSTRING_LEN(data) >= SOCKCREDSIZE(0)) {
- struct sockcred cred0, *cred;
- memcpy(&cred0, RSTRING_PTR(data), SOCKCREDSIZE(0));
- if ((size_t)RSTRING_LEN(data) == SOCKCREDSIZE(cred0.sc_ngroups)) {
- cred = (struct sockcred *)ALLOCA_N(char, SOCKCREDSIZE(cred0.sc_ngroups));
- memcpy(cred, RSTRING_PTR(data), SOCKCREDSIZE(cred0.sc_ngroups));
- rb_str_catf(ret, " uid=%u", cred->sc_uid);
- rb_str_catf(ret, " euid=%u", cred->sc_euid);
- rb_str_catf(ret, " gid=%u", cred->sc_gid);
- rb_str_catf(ret, " egid=%u", cred->sc_egid);
- if (cred0.sc_ngroups) {
- int i;
- const char *sep = " groups=";
- for (i = 0; i < cred0.sc_ngroups; i++) {
- rb_str_catf(ret, "%s%u", sep, cred->sc_groups[i]);
- sep = ",";
- }
+ if ((size_t)len >= SOCKCREDSIZE(0)) {
+ struct sockcred cred;
+ int ngroups;
+ memcpy(&cred, ptr, SOCKCREDSIZE(0));
+ rb_str_catf(ret, " uid=%u", cred.sc_uid);
+ rb_str_catf(ret, " euid=%u", cred.sc_euid);
+ rb_str_catf(ret, " gid=%u", cred.sc_gid);
+ rb_str_catf(ret, " egid=%u", cred.sc_egid);
+ rb_str_catf(ret, " groups[%d]=[", cred.sc_ngroups);
+ ngroups = cred.sc_ngroups;
+ if (ngroups <= 0) {
+ ngroups = 0;
+ }
+ else {
+ size_t max = ((size_t)len - SOCKCREDSIZE(0)) / sizeof(gid_t);
+ if ((size_t)ngroups > max) ngroups = (int)max;
+ }
+ if (ngroups > 0) {
+ int i;
+ const void *gp = ptr + offsetof(struct sockcred, sc_groups);
+ const gid_t *groups = MEMCPY(ALLOCA_N(gid_t, ngroups), gp, gid_t, ngroups);
+ rb_str_catf(ret, "%u", groups[0]);
+ for (i = 1; i < ngroups; i++) {
+ rb_str_catf(ret, ",%u", groups[i]);
}
- rb_str_cat2(ret, " (sockcred)");
- return 1;
}
+ rb_str_cat2(ret, "] (sockcred)");
+ return 1;
}
#endif
return 0;
@@ -1000,6 +1014,7 @@ ancillary_inspect(VALUE self)
rb_str_catf(ret, " %"PRIsVALUE, rb_sym2str(vtype));
else
rb_str_catf(ret, " cmsg_type:%d", type);
+ RB_GC_GUARD(vtype);
}
else {
rb_str_catf(ret, " cmsg_level:%d", level);
diff --git a/ext/socket/depend b/ext/socket/depend
index 6f2d280bfd..77f6239a3d 100644
--- a/ext/socket/depend
+++ b/ext/socket/depend
@@ -193,16 +193,17 @@ 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)/encindex.h
ancdata.o: $(top_srcdir)/id_table.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/box.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/namespace.h
ancdata.o: $(top_srcdir)/internal/sanitizers.h
ancdata.o: $(top_srcdir)/internal/serial.h
ancdata.o: $(top_srcdir)/internal/set_table.h
@@ -408,16 +409,17 @@ 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)/encindex.h
basicsocket.o: $(top_srcdir)/id_table.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/box.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/namespace.h
basicsocket.o: $(top_srcdir)/internal/sanitizers.h
basicsocket.o: $(top_srcdir)/internal/serial.h
basicsocket.o: $(top_srcdir)/internal/set_table.h
@@ -623,16 +625,17 @@ 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)/encindex.h
constants.o: $(top_srcdir)/id_table.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/box.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/namespace.h
constants.o: $(top_srcdir)/internal/sanitizers.h
constants.o: $(top_srcdir)/internal/serial.h
constants.o: $(top_srcdir)/internal/set_table.h
@@ -839,16 +842,17 @@ 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)/encindex.h
ifaddr.o: $(top_srcdir)/id_table.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/box.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/namespace.h
ifaddr.o: $(top_srcdir)/internal/sanitizers.h
ifaddr.o: $(top_srcdir)/internal/serial.h
ifaddr.o: $(top_srcdir)/internal/set_table.h
@@ -1054,16 +1058,17 @@ 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)/encindex.h
init.o: $(top_srcdir)/id_table.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/box.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/namespace.h
init.o: $(top_srcdir)/internal/sanitizers.h
init.o: $(top_srcdir)/internal/serial.h
init.o: $(top_srcdir)/internal/set_table.h
@@ -1269,16 +1274,17 @@ 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)/encindex.h
ipsocket.o: $(top_srcdir)/id_table.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/box.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/namespace.h
ipsocket.o: $(top_srcdir)/internal/sanitizers.h
ipsocket.o: $(top_srcdir)/internal/serial.h
ipsocket.o: $(top_srcdir)/internal/set_table.h
@@ -1484,16 +1490,17 @@ 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)/encindex.h
option.o: $(top_srcdir)/id_table.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/box.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/namespace.h
option.o: $(top_srcdir)/internal/sanitizers.h
option.o: $(top_srcdir)/internal/serial.h
option.o: $(top_srcdir)/internal/set_table.h
@@ -1699,16 +1706,17 @@ 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)/encindex.h
raddrinfo.o: $(top_srcdir)/id_table.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/box.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/namespace.h
raddrinfo.o: $(top_srcdir)/internal/sanitizers.h
raddrinfo.o: $(top_srcdir)/internal/serial.h
raddrinfo.o: $(top_srcdir)/internal/set_table.h
@@ -1914,16 +1922,17 @@ 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)/encindex.h
socket.o: $(top_srcdir)/id_table.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/box.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/namespace.h
socket.o: $(top_srcdir)/internal/sanitizers.h
socket.o: $(top_srcdir)/internal/serial.h
socket.o: $(top_srcdir)/internal/set_table.h
@@ -2129,16 +2138,17 @@ 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)/encindex.h
sockssocket.o: $(top_srcdir)/id_table.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/box.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/namespace.h
sockssocket.o: $(top_srcdir)/internal/sanitizers.h
sockssocket.o: $(top_srcdir)/internal/serial.h
sockssocket.o: $(top_srcdir)/internal/set_table.h
@@ -2344,16 +2354,17 @@ 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)/encindex.h
tcpserver.o: $(top_srcdir)/id_table.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/box.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/namespace.h
tcpserver.o: $(top_srcdir)/internal/sanitizers.h
tcpserver.o: $(top_srcdir)/internal/serial.h
tcpserver.o: $(top_srcdir)/internal/set_table.h
@@ -2559,16 +2570,17 @@ 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)/encindex.h
tcpsocket.o: $(top_srcdir)/id_table.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/box.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/namespace.h
tcpsocket.o: $(top_srcdir)/internal/sanitizers.h
tcpsocket.o: $(top_srcdir)/internal/serial.h
tcpsocket.o: $(top_srcdir)/internal/set_table.h
@@ -2774,16 +2786,17 @@ 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)/encindex.h
udpsocket.o: $(top_srcdir)/id_table.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/box.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/namespace.h
udpsocket.o: $(top_srcdir)/internal/sanitizers.h
udpsocket.o: $(top_srcdir)/internal/serial.h
udpsocket.o: $(top_srcdir)/internal/set_table.h
@@ -2989,16 +3002,17 @@ 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)/encindex.h
unixserver.o: $(top_srcdir)/id_table.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/box.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/namespace.h
unixserver.o: $(top_srcdir)/internal/sanitizers.h
unixserver.o: $(top_srcdir)/internal/serial.h
unixserver.o: $(top_srcdir)/internal/set_table.h
@@ -3204,16 +3218,17 @@ 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)/encindex.h
unixsocket.o: $(top_srcdir)/id_table.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/box.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/namespace.h
unixsocket.o: $(top_srcdir)/internal/sanitizers.h
unixsocket.o: $(top_srcdir)/internal/serial.h
unixsocket.o: $(top_srcdir)/internal/set_table.h
diff --git a/ext/socket/extconf.rb b/ext/socket/extconf.rb
index d44ce31b0a..a814e21c3a 100644
--- a/ext/socket/extconf.rb
+++ b/ext/socket/extconf.rb
@@ -704,6 +704,7 @@ SRC
have_func("pthread_create")
have_func("pthread_detach")
+ have_func("pthread_attr_setdetachstate")
$VPATH << '$(topdir)' << '$(top_srcdir)'
create_makefile("socket")
diff --git a/ext/socket/getaddrinfo.c b/ext/socket/getaddrinfo.c
index bf0d90129f..9a65490b1d 100644
--- a/ext/socket/getaddrinfo.c
+++ b/ext/socket/getaddrinfo.c
@@ -62,9 +62,6 @@
#endif
#include <unistd.h>
#else
-#if defined(_MSC_VER) && _MSC_VER <= 1200
-#include <windows.h>
-#endif
#include <winsock2.h>
#include <ws2tcpip.h>
#include <io.h>
@@ -171,9 +168,7 @@ static const char *const ai_errlist[] = {
#define GET_CANONNAME(ai, str) \
if (pai->ai_flags & AI_CANONNAME) {\
- if (((ai)->ai_canonname = (char *)malloc(strlen(str) + 1)) != NULL) {\
- strcpy((ai)->ai_canonname, (str));\
- } else {\
+ if (((ai)->ai_canonname = strdup(str)) == NULL) {\
error = EAI_MEMORY;\
goto free;\
}\
diff --git a/ext/socket/getnameinfo.c b/ext/socket/getnameinfo.c
index ae5284fab6..98da8c1647 100644
--- a/ext/socket/getnameinfo.c
+++ b/ext/socket/getnameinfo.c
@@ -55,9 +55,6 @@
#endif
#endif
#ifdef _WIN32
-#if defined(_MSC_VER) && _MSC_VER <= 1200
-#include <windows.h>
-#endif
#include <winsock2.h>
#include <ws2tcpip.h>
#define snprintf _snprintf
@@ -158,16 +155,14 @@ getnameinfo(const struct sockaddr *sa, socklen_t salen, char *host, socklen_t ho
/* what we should do? */
} else if (flags & NI_NUMERICSERV) {
snprintf(numserv, sizeof(numserv), "%d", ntohs(port));
- if (strlen(numserv) + 1 > servlen)
+ if (strlcpy(serv, numserv, servlen) >= servlen)
return ENI_MEMORY;
- strcpy(serv, numserv);
} else {
#if defined(HAVE_GETSERVBYPORT)
struct servent *sp = getservbyport(port, (flags & NI_DGRAM) ? "udp" : "tcp");
if (sp) {
- if (strlen(sp->s_name) + 1 > servlen)
+ if (strlcpy(serv, sp->s_name, servlen) >= servlen)
return ENI_MEMORY;
- strcpy(serv, sp->s_name);
} else
return ENI_NOSERVNAME;
#else
@@ -202,9 +197,8 @@ getnameinfo(const struct sockaddr *sa, socklen_t salen, char *host, socklen_t ho
if (inet_ntop(afd->a_af, addr, numaddr, sizeof(numaddr))
== NULL)
return ENI_SYSTEM;
- if (strlen(numaddr) > hostlen)
+ if (strlcpy(host, numaddr, hostlen) >= hostlen)
return ENI_MEMORY;
- strcpy(host, numaddr);
} else {
#ifdef INET6
hp = getipnodebyaddr(addr, afd->a_addrlen, afd->a_af, &h_error);
@@ -218,13 +212,12 @@ getnameinfo(const struct sockaddr *sa, socklen_t salen, char *host, socklen_t ho
p = strchr(hp->h_name, '.');
if (p) *p = '\0';
}
- if (strlen(hp->h_name) + 1 > hostlen) {
+ if (strlcpy(host, hp->h_name, hostlen) >= hostlen) {
#ifdef INET6
freehostent(hp);
#endif
return ENI_MEMORY;
}
- strcpy(host, hp->h_name);
#ifdef INET6
freehostent(hp);
#endif
@@ -234,9 +227,8 @@ getnameinfo(const struct sockaddr *sa, socklen_t salen, char *host, socklen_t ho
if (inet_ntop(afd->a_af, addr, numaddr, sizeof(numaddr))
== NULL)
return ENI_NOHOSTNAME;
- if (strlen(numaddr) > hostlen)
+ if (strlcpy(host, numaddr, hostlen) >= hostlen)
return ENI_MEMORY;
- strcpy(host, numaddr);
}
}
return SUCCESS;
diff --git a/ext/socket/init.c b/ext/socket/init.c
index 8e405609ba..6091385561 100644
--- a/ext/socket/init.c
+++ b/ext/socket/init.c
@@ -473,7 +473,7 @@ rsock_socket(int domain, int type, int proto)
/* emulate blocking connect behavior on EINTR or non-blocking socket */
static int
-wait_connectable(VALUE self, VALUE timeout)
+wait_connectable(VALUE self, VALUE timeout, const struct sockaddr *sockaddr, int len)
{
int sockerr;
socklen_t sockerrlen;
@@ -514,7 +514,9 @@ wait_connectable(VALUE self, VALUE timeout)
VALUE result = rb_io_wait(self, RB_INT2NUM(RUBY_IO_READABLE|RUBY_IO_WRITABLE), timeout);
if (result == Qfalse) {
- rb_raise(rb_eIOTimeoutError, "Connect timed out!");
+ VALUE rai = rsock_addrinfo_new((struct sockaddr *)sockaddr, len, PF_UNSPEC, 0, 0, Qnil, Qnil);
+ VALUE addr_str = rsock_addrinfo_inspect_sockaddr(rai);
+ rb_raise(rb_eIOTimeoutError, "user specified timeout for %" PRIsVALUE, addr_str);
}
int revents = RB_NUM2INT(result);
@@ -603,7 +605,7 @@ rsock_connect(VALUE self, const struct sockaddr *sockaddr, int len, int socks, V
#ifdef EINPROGRESS
case EINPROGRESS:
#endif
- return wait_connectable(self, timeout);
+ return wait_connectable(self, timeout, sockaddr, len);
}
}
return status;
diff --git a/ext/socket/ipsocket.c b/ext/socket/ipsocket.c
index edd270c3ad..e1943b8496 100644
--- a/ext/socket/ipsocket.c
+++ b/ext/socket/ipsocket.c
@@ -27,11 +27,19 @@ struct inetsock_arg
};
void
-rsock_raise_user_specified_timeout(void)
+rsock_raise_user_specified_timeout(struct addrinfo *ai, VALUE host, VALUE port)
{
- VALUE errno_module = rb_const_get(rb_cObject, rb_intern("Errno"));
- VALUE etimedout_error = rb_const_get(errno_module, rb_intern("ETIMEDOUT"));
- rb_raise(etimedout_error, "user specified timeout");
+ VALUE message;
+
+ if (ai && ai->ai_addr) {
+ VALUE rai = rsock_addrinfo_new((struct sockaddr *)ai->ai_addr, (socklen_t)ai->ai_addrlen, PF_UNSPEC, 0, 0, Qnil, Qnil);
+ VALUE addr_str = rsock_addrinfo_inspect_sockaddr(rai);
+ message = rb_sprintf("user specified timeout for %" PRIsVALUE, addr_str);
+ } else {
+ message = rb_sprintf("user specified timeout for %" PRIsVALUE " port %" PRIsVALUE, host, port);
+ }
+
+ rb_exc_raise(rb_exc_new_str(rb_eIOTimeoutError, message));
}
static VALUE
@@ -75,15 +83,13 @@ init_inetsock_internal(VALUE v)
VALUE open_timeout = arg->open_timeout;
VALUE timeout;
VALUE starts_at;
- unsigned int timeout_msec;
timeout = NIL_P(open_timeout) ? resolv_timeout : open_timeout;
- timeout_msec = NIL_P(timeout) ? 0 : rsock_value_timeout_to_msec(timeout);
starts_at = current_clocktime();
arg->remote.res = rsock_addrinfo(arg->remote.host, arg->remote.serv,
family, SOCK_STREAM,
- (type == INET_SERVER) ? AI_PASSIVE : 0, timeout_msec);
+ (type == INET_SERVER) ? AI_PASSIVE : 0, timeout);
/*
* Maybe also accept a local address
@@ -91,7 +97,7 @@ init_inetsock_internal(VALUE v)
if (type != INET_SERVER && (!NIL_P(arg->local.host) || !NIL_P(arg->local.serv))) {
arg->local.res = rsock_addrinfo(arg->local.host, arg->local.serv,
- family, SOCK_STREAM, 0, 0);
+ family, SOCK_STREAM, 0, timeout);
}
VALUE io = Qnil;
@@ -151,7 +157,9 @@ init_inetsock_internal(VALUE v)
} else {
VALUE elapsed = rb_funcall(current_clocktime(), '-', 1, starts_at);
timeout = rb_funcall(open_timeout, '-', 1, elapsed);
- if (rb_funcall(timeout, '<', 1, INT2FIX(0)) == Qtrue) rsock_raise_user_specified_timeout();
+ if (rb_funcall(timeout, '<', 1, INT2FIX(0)) == Qtrue) {
+ rsock_raise_user_specified_timeout(res, arg->remote.host, arg->remote.serv);
+ }
}
if (status >= 0) {
@@ -208,8 +216,8 @@ rsock_init_inetsock(
VALUE self, VALUE remote_host, VALUE remote_serv,
VALUE local_host, VALUE local_serv, int type,
VALUE resolv_timeout, VALUE connect_timeout, VALUE open_timeout,
- VALUE _fast_fallback, VALUE _test_mode_settings
-) {
+ VALUE _fast_fallback, VALUE _test_mode_settings)
+{
if (!NIL_P(open_timeout) && (!NIL_P(resolv_timeout) || !NIL_P(connect_timeout))) {
rb_raise(rb_eArgError, "Cannot specify open_timeout along with connect_timeout or resolv_timeout");
}
@@ -250,6 +258,21 @@ is_specified_ip_address(const char *hostname)
inet_pton(AF_INET, hostname, &ipv4addr) == 1);
}
+static int
+is_local_port_fixed(const char *portp)
+{
+ if (!portp) return 0;
+
+ char *endp;
+ errno = 0;
+ long port = strtol(portp, &endp, 10);
+
+ if (endp == portp) return 0;
+ if (errno == ERANGE) return 0;
+
+ return port > 0;
+}
+
struct fast_fallback_inetsock_arg
{
VALUE self;
@@ -423,8 +446,8 @@ select_expires_at(
struct timeval *connection_attempt_delay,
struct timeval *user_specified_resolv_timeout_at,
struct timeval *user_specified_connect_timeout_at,
- struct timeval *user_specified_open_timeout_at
-) {
+ struct timeval *user_specified_open_timeout_at)
+{
if (any_addrinfos(resolution_store)) {
struct timeval *delay;
delay = resolution_delay ? resolution_delay : connection_attempt_delay;
@@ -526,7 +549,8 @@ in_progress_fds(int fds_size)
}
static void
-remove_connection_attempt_fd(int *fds, int *fds_size, int removing_fd) {
+remove_connection_attempt_fd(int *fds, int *fds_size, int removing_fd)
+{
int i, j;
for (i = 0; i < *fds_size; i++) {
@@ -605,6 +629,7 @@ init_fast_fallback_inetsock_internal(VALUE v)
struct timeval user_specified_open_timeout_storage;
struct timeval *user_specified_open_timeout_at = NULL;
struct timespec now = current_clocktime_ts();
+ VALUE starts_at = current_clocktime();
if (!NIL_P(open_timeout)) {
struct timeval open_timeout_tv = rb_time_interval(open_timeout);
@@ -618,7 +643,7 @@ init_fast_fallback_inetsock_internal(VALUE v)
arg->getaddrinfo_shared = NULL;
int family = arg->families[0];
- unsigned int t = NIL_P(resolv_timeout) ? 0 : rsock_value_timeout_to_msec(resolv_timeout);
+ VALUE t = NIL_P(open_timeout) ? resolv_timeout : open_timeout;
arg->remote.res = rsock_addrinfo(
arg->remote.host,
@@ -704,7 +729,6 @@ init_fast_fallback_inetsock_internal(VALUE v)
if (raddrinfo_pthread_create(&threads[i], fork_safe_do_fast_fallback_getaddrinfo, arg->getaddrinfo_entries[i]) != 0) {
rsock_raise_resolution_error("getaddrinfo(3)", EAI_AGAIN);
}
- pthread_detach(threads[i]);
}
if (NIL_P(resolv_timeout)) {
@@ -833,14 +857,26 @@ init_fast_fallback_inetsock_internal(VALUE v)
status = connect(fd, remote_ai->ai_addr, remote_ai->ai_addrlen);
last_family = remote_ai->ai_family;
} else {
- if (!NIL_P(connect_timeout)) {
- user_specified_connect_timeout_storage = rb_time_interval(connect_timeout);
- user_specified_connect_timeout_at = &user_specified_connect_timeout_storage;
+ VALUE timeout = Qnil;
+
+ if (!NIL_P(open_timeout)) {
+ VALUE elapsed = rb_funcall(current_clocktime(), '-', 1, starts_at);
+ timeout = rb_funcall(open_timeout, '-', 1, elapsed);
+
+ if (rb_funcall(timeout, '<', 1, INT2FIX(0)) == Qtrue) {
+ rsock_raise_user_specified_timeout(NULL, arg->remote.host, arg->remote.serv);
+ }
+ }
+ if (NIL_P(timeout)) {
+ if (!NIL_P(connect_timeout)) {
+ user_specified_connect_timeout_storage = rb_time_interval(connect_timeout);
+ user_specified_connect_timeout_at = &user_specified_connect_timeout_storage;
+ }
+ timeout =
+ (user_specified_connect_timeout_at && is_infinity(*user_specified_connect_timeout_at)) ?
+ Qnil : tv_to_seconds(user_specified_connect_timeout_at);
}
- VALUE timeout =
- (user_specified_connect_timeout_at && is_infinity(*user_specified_connect_timeout_at)) ?
- Qnil : tv_to_seconds(user_specified_connect_timeout_at);
io = arg->io = rsock_init_sock(arg->self, fd);
status = rsock_connect(io, remote_ai->ai_addr, remote_ai->ai_addrlen, 0, timeout);
}
@@ -1166,7 +1202,9 @@ init_fast_fallback_inetsock_internal(VALUE v)
}
}
- if (is_timeout_tv(user_specified_open_timeout_at, now)) rsock_raise_user_specified_timeout();
+ if (is_timeout_tv(user_specified_open_timeout_at, now)) {
+ rsock_raise_user_specified_timeout(NULL, arg->remote.host, arg->remote.serv);
+ }
if (!any_addrinfos(&resolution_store)) {
if (!in_progress_fds(arg->connection_attempt_fds_size) &&
@@ -1189,7 +1227,7 @@ init_fast_fallback_inetsock_internal(VALUE v)
resolution_store.is_all_finished) &&
(is_timeout_tv(user_specified_connect_timeout_at, now) ||
!in_progress_fds(arg->connection_attempt_fds_size))) {
- rsock_raise_user_specified_timeout();
+ rsock_raise_user_specified_timeout(NULL, arg->remote.host, arg->remote.serv);
}
}
}
@@ -1283,21 +1321,23 @@ rsock_init_inetsock(
VALUE self, VALUE remote_host, VALUE remote_serv,
VALUE local_host, VALUE local_serv, int type,
VALUE resolv_timeout, VALUE connect_timeout, VALUE open_timeout,
- VALUE fast_fallback, VALUE test_mode_settings
-) {
+ VALUE fast_fallback, VALUE test_mode_settings)
+{
if (!NIL_P(open_timeout) && (!NIL_P(resolv_timeout) || !NIL_P(connect_timeout))) {
rb_raise(rb_eArgError, "Cannot specify open_timeout along with connect_timeout or resolv_timeout");
}
if (type == INET_CLIENT && FAST_FALLBACK_INIT_INETSOCK_IMPL == 1 && RTEST(fast_fallback)) {
struct rb_addrinfo *local_res = NULL;
- char *hostp, *portp;
- char hbuf[NI_MAXHOST], pbuf[NI_MAXSERV];
+ char *hostp, *portp, *local_portp;
+ char hbuf[NI_MAXHOST], pbuf[NI_MAXSERV], local_pbuf[NI_MAXSERV];
int additional_flags = 0;
+ int local_flags = 0;
hostp = raddrinfo_host_str(remote_host, hbuf, sizeof(hbuf), &additional_flags);
portp = raddrinfo_port_str(remote_serv, pbuf, sizeof(pbuf), &additional_flags);
+ local_portp = raddrinfo_port_str(local_serv, local_pbuf, sizeof(local_pbuf), &local_flags);
- if (!is_specified_ip_address(hostp)) {
+ if (!is_specified_ip_address(hostp) && !is_local_port_fixed(local_portp)) {
int target_families[2] = { 0, 0 };
int resolving_family_size = 0;
@@ -1305,17 +1345,18 @@ rsock_init_inetsock(
* Maybe also accept a local address
*/
if (!NIL_P(local_host) || !NIL_P(local_serv)) {
+ VALUE t = NIL_P(open_timeout) ? resolv_timeout : open_timeout;
local_res = rsock_addrinfo(
local_host,
local_serv,
AF_UNSPEC,
SOCK_STREAM,
0,
- 0
+ t
);
struct addrinfo *tmp_p = local_res->ai;
- for (tmp_p; tmp_p != NULL; tmp_p = tmp_p->ai_next) {
+ for (; tmp_p != NULL; tmp_p = tmp_p->ai_next) {
if (target_families[0] == 0 && tmp_p->ai_family == AF_INET6) {
target_families[0] = AF_INET6;
resolving_family_size++;
@@ -1568,7 +1609,7 @@ static VALUE
ip_s_getaddress(VALUE obj, VALUE host)
{
union_sockaddr addr;
- struct rb_addrinfo *res = rsock_addrinfo(host, Qnil, AF_UNSPEC, SOCK_STREAM, 0, 0);
+ struct rb_addrinfo *res = rsock_addrinfo(host, Qnil, AF_UNSPEC, SOCK_STREAM, 0, Qnil);
socklen_t len = res->ai->ai_addrlen;
/* just take the first one */
diff --git a/ext/socket/lib/socket.rb b/ext/socket/lib/socket.rb
index 1e30861efa..465b74964f 100644
--- a/ext/socket/lib/socket.rb
+++ b/ext/socket/lib/socket.rb
@@ -62,7 +62,7 @@ class Addrinfo
break
when :wait_writable
sock.wait_writable(timeout) or
- raise Errno::ETIMEDOUT, 'user specified timeout'
+ raise Errno::ETIMEDOUT, "user specified timeout for #{self.ip_address}:#{self.ip_port}"
end while true
else
sock.connect(self)
@@ -599,6 +599,7 @@ class Socket < BasicSocket
__accept_nonblock(exception)
end
+ # :stopdoc:
RESOLUTION_DELAY = 0.05
private_constant :RESOLUTION_DELAY
@@ -616,6 +617,7 @@ class Socket < BasicSocket
IPV6_ADDRESS_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_ADDRESS_FORMAT
+ # :startdoc:
# :call-seq:
# Socket.tcp(host, port, local_host=nil, local_port=nil, [opts]) {|socket| ... }
@@ -658,12 +660,11 @@ class Socket < BasicSocket
# puts sock.read
# }
def self.tcp(host, port, local_host = nil, local_port = nil, connect_timeout: nil, resolv_timeout: nil, open_timeout: nil, fast_fallback: tcp_fast_fallback, &) # :yield: socket
-
if open_timeout && (connect_timeout || resolv_timeout)
raise ArgumentError, "Cannot specify open_timeout along with connect_timeout or resolv_timeout"
end
- sock = if fast_fallback && !(host && ip_address?(host))
+ sock = if fast_fallback && !(host && ip_address?(host)) && !(local_port && local_port.to_i != 0)
tcp_with_fast_fallback(host, port, local_host, local_port, connect_timeout:, resolv_timeout:, open_timeout:)
else
tcp_without_fast_fallback(host, port, local_host, local_port, connect_timeout:, resolv_timeout:, open_timeout:)
@@ -680,9 +681,10 @@ class Socket < BasicSocket
end
end
+ # :stopdoc:
def self.tcp_with_fast_fallback(host, port, local_host = nil, local_port = nil, connect_timeout: nil, resolv_timeout: nil, open_timeout: nil)
if local_host || local_port
- local_addrinfos = Addrinfo.getaddrinfo(local_host, local_port, nil, :STREAM, timeout: resolv_timeout)
+ local_addrinfos = Addrinfo.getaddrinfo(local_host, local_port, nil, :STREAM, timeout: open_timeout || resolv_timeout)
resolving_family_names = local_addrinfos.map { |lai| ADDRESS_FAMILIES.key(lai.afamily) }.uniq
else
local_addrinfos = []
@@ -695,6 +697,7 @@ class Socket < BasicSocket
is_windows_environment ||= (RUBY_PLATFORM =~ /mswin|mingw|cygwin/)
now = current_clock_time
+ starts_at = now
resolution_delay_expires_at = nil
connection_attempt_delay_expires_at = nil
user_specified_connect_timeout_at = nil
@@ -704,7 +707,7 @@ class Socket < BasicSocket
if resolving_family_names.size == 1
family_name = resolving_family_names.first
- addrinfos = Addrinfo.getaddrinfo(host, port, ADDRESS_FAMILIES[:family_name], :STREAM, timeout: resolv_timeout)
+ addrinfos = Addrinfo.getaddrinfo(host, port, ADDRESS_FAMILIES[:family_name], :STREAM, timeout: open_timeout || resolv_timeout)
resolution_store.add_resolved(family_name, addrinfos)
hostname_resolution_result = nil
hostname_resolution_notifier = nil
@@ -721,7 +724,6 @@ class Socket < BasicSocket
thread
}
)
-
user_specified_resolv_timeout_at = resolv_timeout ? now + resolv_timeout : Float::INFINITY
end
@@ -733,7 +735,7 @@ class Socket < BasicSocket
if local_addrinfos.any?
local_addrinfo = local_addrinfos.find { |lai| lai.afamily == addrinfo.afamily }
- if local_addrinfo.nil? # Connecting addrinfoã¨åŒã˜ã‚¢ãƒ‰ãƒ¬ã‚¹ãƒ•ァミリã®Local addrinfoãŒãªã„
+ if local_addrinfo.nil?
if resolution_store.any_addrinfos?
# Try other Addrinfo in next "while"
next
@@ -755,9 +757,16 @@ class Socket < BasicSocket
socket.bind(local_addrinfo) if local_addrinfo
result = socket.connect_nonblock(addrinfo, exception: false)
else
+ timeout =
+ if open_timeout
+ t = open_timeout - (current_clock_time - starts_at)
+ t.negative? ? 0 : t
+ else
+ connect_timeout
+ end
result = socket = local_addrinfo ?
- addrinfo.connect_from(local_addrinfo, timeout: connect_timeout) :
- addrinfo.connect(timeout: connect_timeout)
+ addrinfo.connect_from(local_addrinfo, timeout:) :
+ addrinfo.connect(timeout:)
end
if result == :wait_writable
@@ -895,7 +904,9 @@ class Socket < BasicSocket
end
end
- raise(Errno::ETIMEDOUT, 'user specified timeout') if expired?(now, user_specified_open_timeout_at)
+ if expired?(now, user_specified_open_timeout_at)
+ raise(IO::TimeoutError, "user specified timeout for #{host}:#{port}")
+ end
if resolution_store.empty_addrinfos?
if connecting_sockets.empty? && resolution_store.resolved_all_families?
@@ -908,21 +919,18 @@ class Socket < BasicSocket
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'
+ raise(IO::TimeoutError, "user specified timeout for #{host}:#{port}")
end
end
end
ensure
- hostname_resolution_threads.each do |thread|
- thread.exit
- end
+ hostname_resolution_threads.each(&:exit).each(&:join)
hostname_resolution_result&.close
- connecting_sockets.each_key do |connecting_socket|
- connecting_socket.close
- end
+ connecting_sockets.each_key(&:close)
end
+ private_class_method :tcp_with_fast_fallback
def self.tcp_without_fast_fallback(host, port, local_host, local_port, connect_timeout:, resolv_timeout:, open_timeout:)
last_error = nil
@@ -930,7 +938,7 @@ class Socket < BasicSocket
local_addr_list = nil
if local_host != nil || local_port != nil
- local_addr_list = Addrinfo.getaddrinfo(local_host, local_port, nil, :STREAM, nil)
+ local_addr_list = Addrinfo.getaddrinfo(local_host, local_port, nil, :STREAM, nil, timeout: open_timeout || resolv_timeout)
end
timeout = open_timeout ? open_timeout : resolv_timeout
@@ -944,7 +952,14 @@ class Socket < BasicSocket
local_addr = nil
end
begin
- timeout = open_timeout ? open_timeout - (current_clock_time - starts_at) : connect_timeout
+ timeout =
+ if open_timeout
+ t = open_timeout - (current_clock_time - starts_at)
+ t.negative? ? 0 : t
+ else
+ connect_timeout
+ end
+
sock = local_addr ?
ai.connect_from(local_addr, timeout:) :
ai.connect(timeout:)
@@ -1106,7 +1121,6 @@ class Socket < BasicSocket
end
private_constant :HostnameResolutionStore
- # :stopdoc:
def self.ip_sockets_port0(ai_list, reuseaddr)
sockets = []
begin
@@ -1139,9 +1153,7 @@ class Socket < BasicSocket
end
sockets
end
- class << self
- private :ip_sockets_port0
- end
+ private_class_method :ip_sockets_port0
def self.tcp_server_sockets_port0(host)
ai_list = Addrinfo.getaddrinfo(host, 0, nil, :STREAM, nil, Socket::AI_PASSIVE)
@@ -1569,13 +1581,18 @@ class Socket < BasicSocket
end
end
- class << self
- private
-
- def unix_socket_abstract_name?(path)
- /linux/ =~ RUBY_PLATFORM && /\A(\0|\z)/ =~ path
+ # :stopdoc:
+ if RUBY_PLATFORM.include?("linux")
+ def self.unix_socket_abstract_name?(path)
+ path.empty? or path.start_with?("\0")
+ end
+ else
+ def self.unix_socket_abstract_name?(path)
+ false
end
end
+ private_class_method :unix_socket_abstract_name?
+ # :startdoc:
# creates a UNIX socket server on _path_.
# It calls the block for each socket accepted.
diff --git a/ext/socket/raddrinfo.c b/ext/socket/raddrinfo.c
index ca00e51ee7..f1fbcc35de 100644
--- a/ext/socket/raddrinfo.c
+++ b/ext/socket/raddrinfo.c
@@ -293,7 +293,7 @@ rb_freeaddrinfo(struct rb_addrinfo *ai)
xfree(ai);
}
-unsigned int
+static int
rsock_value_timeout_to_msec(VALUE timeout)
{
double seconds = NUM2DBL(timeout);
@@ -308,7 +308,7 @@ rsock_value_timeout_to_msec(VALUE timeout)
#if GETADDRINFO_IMPL == 0
static int
-rb_getaddrinfo(const char *hostp, const char *portp, const struct addrinfo *hints, struct addrinfo **ai, unsigned int _timeout)
+rb_getaddrinfo(const char *hostp, const char *portp, const struct addrinfo *hints, struct addrinfo **ai, int _timeout)
{
return getaddrinfo(hostp, portp, hints, ai);
}
@@ -346,7 +346,7 @@ fork_safe_getaddrinfo(void *arg)
}
static int
-rb_getaddrinfo(const char *hostp, const char *portp, const struct addrinfo *hints, struct addrinfo **ai, unsigned int _timeout)
+rb_getaddrinfo(const char *hostp, const char *portp, const struct addrinfo *hints, struct addrinfo **ai, int _timeout)
{
struct getaddrinfo_arg arg;
MEMZERO(&arg, struct getaddrinfo_arg, 1);
@@ -367,11 +367,11 @@ struct getaddrinfo_arg
int err, gai_errno, refcount, done, cancelled, timedout;
rb_nativethread_lock_t lock;
rb_nativethread_cond_t cond;
- unsigned int timeout;
+ int timeout;
};
static struct getaddrinfo_arg *
-allocate_getaddrinfo_arg(const char *hostp, const char *portp, const struct addrinfo *hints, unsigned int timeout)
+allocate_getaddrinfo_arg(const char *hostp, const char *portp, const struct addrinfo *hints, int timeout)
{
size_t hostp_offset = sizeof(struct getaddrinfo_arg);
size_t portp_offset = hostp_offset + (hostp ? strlen(hostp) + 1 : 0);
@@ -387,7 +387,7 @@ allocate_getaddrinfo_arg(const char *hostp, const char *portp, const struct addr
if (hostp) {
arg->node = buf + hostp_offset;
- strcpy(arg->node, hostp);
+ memcpy(arg->node, hostp, portp_offset - hostp_offset);
}
else {
arg->node = NULL;
@@ -395,7 +395,7 @@ allocate_getaddrinfo_arg(const char *hostp, const char *portp, const struct addr
if (portp) {
arg->service = buf + portp_offset;
- strcpy(arg->service, portp);
+ memcpy(arg->service, portp, bufsize - portp_offset);
}
else {
arg->service = NULL;
@@ -465,8 +465,11 @@ wait_getaddrinfo(void *ptr)
struct getaddrinfo_arg *arg = (struct getaddrinfo_arg *)ptr;
rb_nativethread_lock_lock(&arg->lock);
while (!arg->done && !arg->cancelled) {
- unsigned long msec = arg->timeout;
- if (msec > 0) {
+ long msec = arg->timeout;
+ if (msec == 0) {
+ arg->cancelled = 1;
+ arg->timedout = 1;
+ } else if (msec > 0) {
rb_native_cond_timedwait(&arg->cond, &arg->lock, msec);
if (!arg->done) {
arg->cancelled = 1;
@@ -496,13 +499,49 @@ int
raddrinfo_pthread_create(pthread_t *th, void *(*start_routine) (void *), void *arg)
{
int limit = 3, ret;
+ int saved_errno;
+#ifdef HAVE_PTHREAD_ATTR_SETDETACHSTATE
+ pthread_attr_t attr;
+ pthread_attr_t *attr_p = &attr;
+ int err;
+ int init_retries = 0;
+ int init_retries_max = 3;
+retry_attr_init:
+ if ((err = pthread_attr_init(attr_p)) != 0) {
+ if (err == ENOMEM && init_retries < init_retries_max) {
+ init_retries++;
+ rb_gc();
+ goto retry_attr_init;
+ }
+ return err;
+ }
+ if ((err = pthread_attr_setdetachstate(attr_p, PTHREAD_CREATE_DETACHED)) != 0) {
+ saved_errno = errno;
+ pthread_attr_destroy(attr_p);
+ errno = saved_errno;
+ return err; // EINVAL - shouldn't happen
+ }
+#else
+ pthread_attr_t *attr_p = NULL;
+#endif
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);
+ ret = pthread_create(th, attr_p, start_routine, arg);
} while (ret == EAGAIN && limit-- > 0);
+#ifdef HAVE_PTHREAD_ATTR_SETDETACHSTATE
+ saved_errno = errno;
+ pthread_attr_destroy(attr_p);
+ if (ret != 0) {
+ errno = saved_errno;
+ }
+#else
+ if (ret == 0) {
+ pthread_detach(th); // this can race with shutdown routine of thread in some glibc versions
+ }
+#endif
return ret;
}
@@ -513,7 +552,7 @@ fork_safe_do_getaddrinfo(void *ptr)
}
static int
-rb_getaddrinfo(const char *hostp, const char *portp, const struct addrinfo *hints, struct addrinfo **ai, unsigned int timeout)
+rb_getaddrinfo(const char *hostp, const char *portp, const struct addrinfo *hints, struct addrinfo **ai, int timeout)
{
int retry;
struct getaddrinfo_arg *arg;
@@ -534,7 +573,6 @@ start:
errno = err;
return EAI_SYSTEM;
}
- pthread_detach(th);
rb_thread_call_without_gvl2(wait_getaddrinfo, arg, cancel_getaddrinfo, arg);
@@ -562,7 +600,11 @@ start:
if (need_free) free_getaddrinfo_arg(arg);
- if (timedout) rsock_raise_user_specified_timeout();
+ if (timedout) {
+ VALUE host = rb_str_new_cstr(hostp);
+ VALUE port = rb_str_new_cstr(portp);
+ rsock_raise_user_specified_timeout(NULL, host, port);
+ }
// 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.
@@ -589,7 +631,7 @@ 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);
+ return getnameinfo(sa, salen, host, (socklen_t)hostlen, serv, (socklen_t)servlen, flags);
}
#elif GETADDRINFO_IMPL == 1
@@ -752,7 +794,7 @@ rb_getnameinfo(const struct sockaddr *sa, socklen_t salen,
int err = 0, gni_errno = 0;
if (GETNAMEINFO_WONT_BLOCK(host, serv, flags)) {
- return getnameinfo(sa, salen, host, hostlen, serv, servlen, flags);
+ return getnameinfo(sa, salen, host, (socklen_t)hostlen, serv, (socklen_t)servlen, flags);
}
start:
@@ -770,7 +812,6 @@ start:
errno = err;
return EAI_SYSTEM;
}
- pthread_detach(th);
rb_thread_call_without_gvl2(wait_getnameinfo, arg, cancel_getnameinfo, arg);
@@ -979,7 +1020,7 @@ rb_scheduler_getaddrinfo(VALUE scheduler, VALUE host, const char *service,
}
struct rb_addrinfo*
-rsock_getaddrinfo(VALUE host, VALUE port, struct addrinfo *hints, int socktype_hack, unsigned int timeout)
+rsock_getaddrinfo(VALUE host, VALUE port, struct addrinfo *hints, int socktype_hack, VALUE timeout)
{
struct rb_addrinfo* res = NULL;
struct addrinfo *ai;
@@ -1014,7 +1055,8 @@ rsock_getaddrinfo(VALUE host, VALUE port, struct addrinfo *hints, int socktype_h
}
if (!resolved) {
- error = rb_getaddrinfo(hostp, portp, hints, &ai, timeout);
+ int t = NIL_P(timeout) ? -1 : rsock_value_timeout_to_msec(timeout);
+ error = rb_getaddrinfo(hostp, portp, hints, &ai, t);
if (error == 0) {
res = (struct rb_addrinfo *)xmalloc(sizeof(struct rb_addrinfo));
res->allocated_by_malloc = 0;
@@ -1047,7 +1089,7 @@ rsock_fd_family(int fd)
}
struct rb_addrinfo*
-rsock_addrinfo(VALUE host, VALUE port, int family, int socktype, int flags, unsigned int timeout)
+rsock_addrinfo(VALUE host, VALUE port, int family, int socktype, int flags, VALUE timeout)
{
struct addrinfo hints;
@@ -1338,8 +1380,7 @@ call_getaddrinfo(VALUE node, VALUE service,
hints.ai_flags = NUM2INT(flags);
}
- unsigned int t = NIL_P(timeout) ? 0 : rsock_value_timeout_to_msec(timeout);
- res = rsock_getaddrinfo(node, service, &hints, socktype_hack, t);
+ res = rsock_getaddrinfo(node, service, &hints, socktype_hack, timeout);
if (res == NULL)
rb_raise(rb_eSocket, "host not found");
diff --git a/ext/socket/rubysocket.h b/ext/socket/rubysocket.h
index 29b8afc163..2ec3ab335a 100644
--- a/ext/socket/rubysocket.h
+++ b/ext/socket/rubysocket.h
@@ -327,8 +327,8 @@ void rb_freeaddrinfo(struct rb_addrinfo *ai);
VALUE rsock_freeaddrinfo(VALUE arg);
int rb_getnameinfo(const struct sockaddr *sa, socklen_t salen, char *host, size_t hostlen, char *serv, size_t servlen, int flags);
int rsock_fd_family(int fd);
-struct rb_addrinfo *rsock_addrinfo(VALUE host, VALUE port, int family, int socktype, int flags, unsigned int timeout);
-struct rb_addrinfo *rsock_getaddrinfo(VALUE host, VALUE port, struct addrinfo *hints, int socktype_hack, unsigned int timeout);
+struct rb_addrinfo *rsock_addrinfo(VALUE host, VALUE port, int family, int socktype, int flags, VALUE timeout);
+struct rb_addrinfo *rsock_getaddrinfo(VALUE host, VALUE port, struct addrinfo *hints, int socktype_hack, VALUE timeout);
VALUE rsock_fd_socket_addrinfo(int fd, struct sockaddr *addr, socklen_t len);
VALUE rsock_io_socket_addrinfo(VALUE io, struct sockaddr *addr, socklen_t len);
@@ -453,8 +453,7 @@ void free_fast_fallback_getaddrinfo_shared(struct fast_fallback_getaddrinfo_shar
# endif
#endif
-unsigned int rsock_value_timeout_to_msec(VALUE);
-NORETURN(void rsock_raise_user_specified_timeout(void));
+NORETURN(void rsock_raise_user_specified_timeout(struct addrinfo *ai, VALUE host, VALUE port));
void rsock_init_basicsocket(void);
void rsock_init_ipsocket(void);
@@ -510,8 +509,6 @@ extern ID tcp_fast_fallback;
const char *inet_ntop(int, const void *, char *, size_t);
#elif defined __MINGW32__
# define inet_ntop(f,a,n,l) rb_w32_inet_ntop(f,a,n,l)
-#elif defined _MSC_VER && RUBY_MSVCRT_VERSION < 90
-const char *WSAAPI inet_ntop(int, const void *, char *, size_t);
#endif
#endif
diff --git a/ext/socket/socket.c b/ext/socket/socket.c
index 26bf0bae8c..a8e5ae8119 100644
--- a/ext/socket/socket.c
+++ b/ext/socket/socket.c
@@ -965,7 +965,7 @@ sock_s_gethostbyname(VALUE obj, VALUE host)
{
rb_warn("Socket.gethostbyname is deprecated; use Addrinfo.getaddrinfo instead.");
struct rb_addrinfo *res =
- rsock_addrinfo(host, Qnil, AF_UNSPEC, SOCK_STREAM, AI_CANONNAME, 0);
+ rsock_addrinfo(host, Qnil, AF_UNSPEC, SOCK_STREAM, AI_CANONNAME, Qnil);
return rsock_make_hostent(host, res, sock_sockaddr);
}
@@ -1183,7 +1183,7 @@ sock_s_getaddrinfo(int argc, VALUE *argv, VALUE _)
norevlookup = rsock_do_not_reverse_lookup;
}
- res = rsock_getaddrinfo(host, port, &hints, 0, 0);
+ res = rsock_getaddrinfo(host, port, &hints, 0, Qnil);
ret = make_addrinfo(res, norevlookup);
rb_freeaddrinfo(res);
@@ -1279,7 +1279,7 @@ sock_s_getnameinfo(int argc, VALUE *argv, VALUE _)
hints.ai_socktype = (fl & NI_DGRAM) ? SOCK_DGRAM : SOCK_STREAM;
/* af */
hints.ai_family = NIL_P(af) ? PF_UNSPEC : rsock_family_arg(af);
- res = rsock_getaddrinfo(host, port, &hints, 0, 0);
+ res = rsock_getaddrinfo(host, port, &hints, 0, Qnil);
sap = res->ai->ai_addr;
salen = res->ai->ai_addrlen;
}
@@ -1335,7 +1335,7 @@ sock_s_getnameinfo(int argc, VALUE *argv, VALUE _)
static VALUE
sock_s_pack_sockaddr_in(VALUE self, VALUE port, VALUE host)
{
- struct rb_addrinfo *res = rsock_addrinfo(host, port, AF_UNSPEC, 0, 0, 0);
+ struct rb_addrinfo *res = rsock_addrinfo(host, port, AF_UNSPEC, 0, 0, Qnil);
VALUE addr = rb_str_new((char*)res->ai->ai_addr, res->ai->ai_addrlen);
rb_freeaddrinfo(res);
diff --git a/ext/socket/tcpsocket.c b/ext/socket/tcpsocket.c
index 22c9f28ab7..7ce536e0af 100644
--- a/ext/socket/tcpsocket.c
+++ b/ext/socket/tcpsocket.c
@@ -12,7 +12,7 @@
/*
* call-seq:
- * TCPSocket.new(remote_host, remote_port, local_host=nil, local_port=nil, resolv_timeout: nil, connect_timeout: nil, fast_fallback: true)
+ * TCPSocket.new(remote_host, remote_port, local_host=nil, local_port=nil, resolv_timeout: nil, connect_timeout: nil, open_timeout: nil, fast_fallback: true)
*
* Opens a TCP connection to +remote_host+ on +remote_port+. If +local_host+
* and +local_port+ are specified, then those parameters are used on the local
@@ -113,7 +113,7 @@ tcp_s_gethostbyname(VALUE obj, VALUE host)
{
rb_warn("TCPSocket.gethostbyname is deprecated; use Addrinfo.getaddrinfo instead.");
struct rb_addrinfo *res =
- rsock_addrinfo(host, Qnil, AF_UNSPEC, SOCK_STREAM, AI_CANONNAME, 0);
+ rsock_addrinfo(host, Qnil, AF_UNSPEC, SOCK_STREAM, AI_CANONNAME, Qnil);
return rsock_make_hostent(host, res, tcp_sockaddr);
}
diff --git a/ext/socket/udpsocket.c b/ext/socket/udpsocket.c
index 5538f24523..b2bc925538 100644
--- a/ext/socket/udpsocket.c
+++ b/ext/socket/udpsocket.c
@@ -84,7 +84,7 @@ udp_connect(VALUE self, VALUE host, VALUE port)
{
struct udp_arg arg = {.io = self};
- arg.res = rsock_addrinfo(host, port, rsock_fd_family(rb_io_descriptor(self)), SOCK_DGRAM, 0, 0);
+ arg.res = rsock_addrinfo(host, port, rsock_fd_family(rb_io_descriptor(self)), SOCK_DGRAM, 0, Qnil);
int result = (int)rb_ensure(udp_connect_internal, (VALUE)&arg, rsock_freeaddrinfo, (VALUE)arg.res);
if (!result) {
@@ -129,7 +129,7 @@ udp_bind(VALUE self, VALUE host, VALUE port)
{
struct udp_arg arg = {.io = self};
- arg.res = rsock_addrinfo(host, port, rsock_fd_family(rb_io_descriptor(self)), SOCK_DGRAM, 0, 0);
+ arg.res = rsock_addrinfo(host, port, rsock_fd_family(rb_io_descriptor(self)), SOCK_DGRAM, 0, Qnil);
VALUE result = rb_ensure(udp_bind_internal, (VALUE)&arg, rsock_freeaddrinfo, (VALUE)arg.res);
if (!result) {
@@ -212,7 +212,7 @@ udp_send(int argc, VALUE *argv, VALUE sock)
GetOpenFile(sock, arg.fptr);
arg.sarg.fd = arg.fptr->fd;
arg.sarg.flags = NUM2INT(flags);
- arg.res = rsock_addrinfo(host, port, rsock_fd_family(arg.fptr->fd), SOCK_DGRAM, 0, 0);
+ arg.res = rsock_addrinfo(host, port, rsock_fd_family(arg.fptr->fd), SOCK_DGRAM, 0, Qnil);
ret = rb_ensure(udp_send_internal, (VALUE)&arg,
rsock_freeaddrinfo, (VALUE)arg.res);
if (!ret) rsock_sys_fail_host_port("sendto(2)", host, port);
diff --git a/ext/socket/unixsocket.c b/ext/socket/unixsocket.c
index 31e2acee04..2ec9376074 100644
--- a/ext/socket/unixsocket.c
+++ b/ext/socket/unixsocket.c
@@ -42,11 +42,12 @@ unixsock_path_value(VALUE path)
}
}
#endif
+ path = rb_get_path(path);
#ifdef _WIN32
/* UNIXSocket requires UTF-8 per spec. */
path = rb_str_export_to_enc(path, rb_utf8_encoding());
#endif
- return rb_get_path(path);
+ return path;
}
VALUE
diff --git a/ext/stringio/stringio.c b/ext/stringio/stringio.c
index 0493c8cd50..41aa71f893 100644
--- a/ext/stringio/stringio.c
+++ b/ext/stringio/stringio.c
@@ -13,7 +13,7 @@
**********************************************************************/
static const char *const
-STRINGIO_VERSION = "3.1.8.dev";
+STRINGIO_VERSION = "3.2.1.dev";
#include <stdbool.h>
@@ -62,6 +62,7 @@ struct StringIO {
int count;
};
+static struct StringIO *get_strio_for_read(VALUE self);
static VALUE strio_init(int, VALUE *, struct StringIO *, VALUE);
static VALUE strio_unget_bytes(struct StringIO *, const char *, long);
static long strio_write(VALUE self, VALUE str);
@@ -126,8 +127,14 @@ static const rb_data_type_t strio_data_type = {
static struct StringIO*
get_strio(VALUE self)
{
- struct StringIO *ptr = check_strio(rb_io_taint_check(self));
+ rb_check_frozen(self);
+ return get_strio_for_read(self);
+}
+static struct StringIO*
+get_strio_for_read(VALUE self)
+{
+ struct StringIO *ptr = check_strio(self);
if (!ptr) {
rb_raise(rb_eIOError, "uninitialized stream");
}
@@ -154,14 +161,38 @@ strio_substr(struct StringIO *ptr, long pos, long len, rb_encoding *enc)
return enc_subseq(str, pos, len, enc);
}
+static VALUE
+strio_readbuf(struct StringIO *ptr, VALUE str)
+{
+ if (!NIL_P(str)) {
+ StringValue(str);
+ rb_str_modify(str);
+ if (str == ptr->string) {
+ rb_raise(rb_eArgError, "cannot read into the underlying string");
+ }
+ }
+ return str;
+}
+
#define StringIO(obj) get_strio(obj)
+#define StringIOForRead(obj) get_strio_for_read(obj)
#define STRIO_READABLE FL_USER4
#define STRIO_WRITABLE FL_USER5
#define STRIO_READWRITE (STRIO_READABLE|STRIO_WRITABLE)
typedef char strio_flags_check[(STRIO_READABLE/FMODE_READABLE == STRIO_WRITABLE/FMODE_WRITABLE) * 2 - 1];
+#ifndef RB_FL_TEST_RAW
+# define RB_FL_TEST_RAW(obj, bits) (RBASIC(obj)->flags & (bits))
+#endif
+#ifndef RB_FL_SET_RAW
+# define RB_FL_SET_RAW(obj, bits) (RBASIC(obj)->flags |= (bits))
+#endif
+#ifndef RB_FL_UNSET_RAW
+# define RB_FL_UNSET_RAW(obj, bits) (RBASIC(obj)->flags &= ~(bits))
+#endif
+
#define STRIO_MODE_SET_P(strio, mode) \
- ((RBASIC(strio)->flags & STRIO_##mode) && \
+ (RB_FL_TEST_RAW(strio, STRIO_##mode) && \
((struct StringIO*)DATA_PTR(strio))->flags & FMODE_##mode)
#define CLOSED(strio) (!STRIO_MODE_SET_P(strio, READWRITE))
#define READABLE(strio) STRIO_MODE_SET_P(strio, READABLE)
@@ -172,7 +203,7 @@ static VALUE sym_exception;
static struct StringIO*
readable(VALUE strio)
{
- struct StringIO *ptr = StringIO(strio);
+ struct StringIO *ptr = StringIOForRead(strio);
if (!READABLE(strio)) {
rb_raise(rb_eIOError, "not opened for reading");
}
@@ -225,17 +256,32 @@ strio_s_allocate(VALUE klass)
* call-seq:
* StringIO.new(string = '', mode = 'r+') -> new_stringio
*
- * Note that +mode+ defaults to <tt>'r'</tt> if +string+ is frozen.
- *
* Returns a new \StringIO instance formed from +string+ and +mode+;
- * see {Access Modes}[rdoc-ref:File@Access+Modes]:
+ * the instance should be closed when no longer needed:
+ *
+ * strio = StringIO.new
+ * strio.string # => ""
+ * strio.closed_read? # => false
+ * strio.closed_write? # => false
+ * strio.close
+ *
+ * If +string+ is frozen, the default +mode+ is <tt>'r'</tt>:
*
- * strio = StringIO.new # => #<StringIO>
+ * strio = StringIO.new('foo'.freeze)
+ * strio.string # => "foo"
+ * strio.closed_read? # => false
+ * strio.closed_write? # => true
* strio.close
*
- * The instance should be closed when no longer needed.
+ * Argument +mode+ must be a valid
+ * {Access Mode}[rdoc-ref:File@Access+Modes],
+ * which may be a string or an integer constant:
*
- * Related: StringIO.open (accepts block; closes automatically).
+ * StringIO.new('foo', 'w+')
+ * StringIO.new('foo', File::RDONLY)
+ *
+ * Related: StringIO.open
+ * (passes the \StringIO object to the block; closes the object automatically on block exit).
*/
static VALUE
strio_initialize(int argc, VALUE *argv, VALUE self)
@@ -355,14 +401,15 @@ strio_init(int argc, VALUE *argv, struct StringIO *ptr, VALUE self)
ptr->pos = 0;
ptr->lineno = 0;
if (ptr->flags & FMODE_SETENC_BY_BOM) set_encoding_by_bom(ptr);
- RBASIC(self)->flags |= (ptr->flags & FMODE_READWRITE) * (STRIO_READABLE / FMODE_READABLE);
+ RB_FL_SET_RAW(self, (ptr->flags & FMODE_READWRITE) * (STRIO_READABLE / FMODE_READABLE));
return self;
}
static VALUE
strio_finalize(VALUE self)
{
- struct StringIO *ptr = StringIO(self);
+ struct StringIO *ptr = check_strio(self);
+ if (!ptr) return Qnil;
RB_OBJ_WRITE(self, &ptr->string, Qnil);
ptr->flags &= ~FMODE_READWRITE;
return self;
@@ -370,23 +417,20 @@ strio_finalize(VALUE self)
/*
* call-seq:
- * StringIO.open(string = '', mode = 'r+') {|strio| ... }
+ * StringIO.open(string = '', mode = 'r+') -> new_stringio
+ * StringIO.open(string = '', mode = 'r+') {|strio| ... } -> object
*
- * Note that +mode+ defaults to <tt>'r'</tt> if +string+ is frozen.
+ * Creates new \StringIO instance by calling <tt>StringIO.new(string, mode)</tt>.
*
- * Creates a new \StringIO instance formed from +string+ and +mode+;
- * see {Access Modes}[rdoc-ref:File@Access+Modes].
- *
- * With no block, returns the new instance:
+ * With no block given, returns the new instance:
*
* strio = StringIO.open # => #<StringIO>
*
- * With a block, calls the block with the new instance
+ * With a block given, calls the block with the new instance
* and returns the block's value;
- * closes the instance on block exit.
+ * closes the instance on block exit:
*
- * StringIO.open {|strio| p strio }
- * # => #<StringIO>
+ * StringIO.open('foo') {|strio| strio.string.upcase } # => "FOO"
*
* Related: StringIO.new.
*/
@@ -412,42 +456,42 @@ strio_s_new(int argc, VALUE *argv, VALUE klass)
}
/*
- * Returns +false+. Just for compatibility to IO.
+ * Returns +false+; for compatibility with IO.
*/
static VALUE
strio_false(VALUE self)
{
- StringIO(self);
+ StringIOForRead(self);
return Qfalse;
}
/*
- * Returns +nil+. Just for compatibility to IO.
+ * Returns +nil+; for compatibility with IO.
*/
static VALUE
strio_nil(VALUE self)
{
- StringIO(self);
+ StringIOForRead(self);
return Qnil;
}
/*
- * Returns an object itself. Just for compatibility to IO.
+ * Returns +self+; for compatibility with IO.
*/
static VALUE
strio_self(VALUE self)
{
- StringIO(self);
+ StringIOForRead(self);
return self;
}
/*
- * Returns 0. Just for compatibility to IO.
+ * Returns 0; for compatibility with IO.
*/
static VALUE
strio_0(VALUE self)
{
- StringIO(self);
+ StringIOForRead(self);
return INT2FIX(0);
}
@@ -457,7 +501,7 @@ strio_0(VALUE self)
static VALUE
strio_first(VALUE self, VALUE arg)
{
- StringIO(self);
+ StringIOForRead(self);
return arg;
}
@@ -467,7 +511,7 @@ strio_first(VALUE self, VALUE arg)
static VALUE
strio_unimpl(int argc, VALUE *argv, VALUE self)
{
- StringIO(self);
+ StringIOForRead(self);
rb_notimplement();
UNREACHABLE;
@@ -495,14 +539,14 @@ strio_unimpl(int argc, VALUE *argv, VALUE self)
static VALUE
strio_get_string(VALUE self)
{
- return StringIO(self)->string;
+ return StringIOForRead(self)->string;
}
/*
* call-seq:
* string = other_string -> other_string
*
- * Assigns the underlying string as +other_string+, and sets position to zero;
+ * Replaces the stored string with +other_string+, and sets the position to zero;
* returns +other_string+:
*
* StringIO.open('foo') do |strio|
@@ -516,7 +560,7 @@ strio_get_string(VALUE self)
* "foo"
* "bar"
*
- * Related: StringIO#string (returns the underlying string).
+ * Related: StringIO#string (returns the stored string).
*/
static VALUE
strio_set_string(VALUE self, VALUE string)
@@ -537,17 +581,22 @@ strio_set_string(VALUE self, VALUE string)
* call-seq:
* close -> nil
*
- * Closes +self+ for both reading and writing.
+ * Closes +self+ for both reading and writing; returns +nil+:
*
- * Raises IOError if reading or writing is attempted.
+ * strio = StringIO.new
+ * strio.closed? # => false
+ * strio.close # => nil
+ * strio.closed? # => true
+ * strio.read # Raises IOError: not opened for reading
+ * strio.write # Raises IOError: not opened for writing
*
- * Related: StringIO#close_read, StringIO#close_write.
+ * Related: StringIO#close_read, StringIO#close_write, StringIO.closed?.
*/
static VALUE
strio_close(VALUE self)
{
StringIO(self);
- RBASIC(self)->flags &= ~STRIO_READWRITE;
+ RB_FL_UNSET_RAW(self, STRIO_READWRITE);
return Qnil;
}
@@ -555,9 +604,16 @@ strio_close(VALUE self)
* call-seq:
* close_read -> nil
*
- * Closes +self+ for reading; closed-write setting remains unchanged.
+ * Closes +self+ for reading;
+ * closed-write setting remains unchanged;
+ * returns +nil+:
*
- * Raises IOError if reading is attempted.
+ * strio = StringIO.new
+ * strio.closed_read? # => false
+ * strio.close_read # => nil
+ * strio.closed_read? # => true
+ * strio.closed_write? # => false
+ * strio.read # Raises IOError: not opened for reading
*
* Related: StringIO#close, StringIO#close_write.
*/
@@ -568,7 +624,7 @@ strio_close_read(VALUE self)
if (!(ptr->flags & FMODE_READABLE)) {
rb_raise(rb_eIOError, "closing non-duplex IO for reading");
}
- RBASIC(self)->flags &= ~STRIO_READABLE;
+ RB_FL_UNSET_RAW(self, STRIO_READABLE);
return Qnil;
}
@@ -576,11 +632,16 @@ strio_close_read(VALUE self)
* call-seq:
* close_write -> nil
*
- * Closes +self+ for writing; closed-read setting remains unchanged.
+ * Closes +self+ for writing; closed-read setting remains unchanged; returns +nil+:
*
- * Raises IOError if writing is attempted.
+ * strio = StringIO.new
+ * strio.closed_write? # => false
+ * strio.close_write # => nil
+ * strio.closed_write? # => true
+ * strio.closed_read? # => false
+ * strio.write('foo') # Raises IOError: not opened for writing
*
- * Related: StringIO#close, StringIO#close_read.
+ * Related: StringIO#close, StringIO#close_read, StringIO#closed_write?.
*/
static VALUE
strio_close_write(VALUE self)
@@ -589,7 +650,7 @@ strio_close_write(VALUE self)
if (!(ptr->flags & FMODE_WRITABLE)) {
rb_raise(rb_eIOError, "closing non-duplex IO for writing");
}
- RBASIC(self)->flags &= ~STRIO_WRITABLE;
+ RB_FL_UNSET_RAW(self, STRIO_WRITABLE);
return Qnil;
}
@@ -597,13 +658,21 @@ strio_close_write(VALUE self)
* call-seq:
* closed? -> true or false
*
- * Returns +true+ if +self+ is closed for both reading and writing,
- * +false+ otherwise.
+ * Returns whether +self+ is closed for both reading and writing:
+ *
+ * strio = StringIO.new
+ * strio.closed? # => false # Open for reading and writing.
+ * strio.close_read
+ * strio.closed? # => false # Still open for writing.
+ * strio.close_write
+ * strio.closed? # => true # Now closed for both.
+ *
+ * Related: StringIO.closed_read?, StringIO.closed_write?.
*/
static VALUE
strio_closed(VALUE self)
{
- StringIO(self);
+ StringIOForRead(self);
if (!CLOSED(self)) return Qfalse;
return Qtrue;
}
@@ -612,12 +681,19 @@ strio_closed(VALUE self)
* call-seq:
* closed_read? -> true or false
*
- * Returns +true+ if +self+ is closed for reading, +false+ otherwise.
+ * Returns whether +self+ is closed for reading:
+ *
+ * strio = StringIO.new
+ * strio.closed_read? # => false
+ * strio.close_read
+ * strio.closed_read? # => true
+ *
+ * Related: StringIO#closed?, StringIO#closed_write?, StringIO#close_read.
*/
static VALUE
strio_closed_read(VALUE self)
{
- StringIO(self);
+ StringIOForRead(self);
if (READABLE(self)) return Qfalse;
return Qtrue;
}
@@ -626,12 +702,19 @@ strio_closed_read(VALUE self)
* call-seq:
* closed_write? -> true or false
*
- * Returns +true+ if +self+ is closed for writing, +false+ otherwise.
+ * Returns whether +self+ is closed for writing:
+ *
+ * strio = StringIO.new
+ * strio.closed_write? # => false
+ * strio.close_write
+ * strio.closed_write? # => true
+ *
+ * Related: StringIO#close_write, StringIO#closed?, StringIO#closed_read?.
*/
static VALUE
strio_closed_write(VALUE self)
{
- StringIO(self);
+ StringIOForRead(self);
if (WRITABLE(self)) return Qfalse;
return Qtrue;
}
@@ -648,10 +731,18 @@ strio_to_read(VALUE self)
* call-seq:
* eof? -> true or false
*
- * Returns +true+ if positioned at end-of-stream, +false+ otherwise;
- * see {Position}[rdoc-ref:IO@Position].
+ * Returns whether +self+ is positioned at end-of-stream:
+ *
+ * strio = StringIO.new('foo')
+ * strio.pos # => 0
+ * strio.eof? # => false
+ * strio.read # => "foo"
+ * strio.pos # => 3
+ * strio.eof? # => true
+ * strio.close_read
+ * strio.eof? # Raises IOError: not opened for reading
*
- * Raises IOError if the stream is not opened for reading.
+ * Related: StringIO#pos.
*/
static VALUE
strio_eof(VALUE self)
@@ -669,7 +760,7 @@ strio_copy(VALUE copy, VALUE orig)
orig = rb_convert_type(orig, T_DATA, "StringIO", "to_strio");
if (copy == orig) return copy;
- ptr = StringIO(orig);
+ ptr = StringIOForRead(orig);
old_ptr = check_strio(copy);
if (old_ptr) {
old_string = old_ptr->string;
@@ -677,8 +768,8 @@ strio_copy(VALUE copy, VALUE orig)
}
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;
+ RB_FL_UNSET_RAW(copy, STRIO_READWRITE);
+ RB_FL_SET_RAW(copy, RB_FL_TEST_RAW(orig, STRIO_READWRITE));
++ptr->count;
return copy;
}
@@ -688,12 +779,12 @@ strio_copy(VALUE copy, VALUE orig)
* lineno -> current_line_number
*
* Returns the current line number in +self+;
- * see {Line Number}[rdoc-ref:IO@Line+Number].
+ * see {Line Number}[rdoc-ref:StringIO@Line+Number].
*/
static VALUE
strio_get_lineno(VALUE self)
{
- return LONG2NUM(StringIO(self)->lineno);
+ return LONG2NUM(StringIOForRead(self)->lineno);
}
/*
@@ -701,7 +792,7 @@ strio_get_lineno(VALUE self)
* lineno = new_line_number -> new_line_number
*
* Sets the current line number in +self+ to the given +new_line_number+;
- * see {Line Number}[rdoc-ref:IO@Line+Number].
+ * see {Line Number}[rdoc-ref:StringIO@Line+Number].
*/
static VALUE
strio_set_lineno(VALUE self, VALUE lineno)
@@ -715,7 +806,7 @@ strio_set_lineno(VALUE self, VALUE lineno)
* binmode -> self
*
* Sets the data mode in +self+ to binary mode;
- * see {Data Mode}[rdoc-ref:File@Data+Mode].
+ * see {Data Mode}[rdoc-ref:StringIO@Data+Mode].
*
*/
static VALUE
@@ -776,12 +867,12 @@ strio_reopen(int argc, VALUE *argv, VALUE self)
* pos -> stream_position
*
* Returns the current position (in bytes);
- * see {Position}[rdoc-ref:IO@Position].
+ * see {Position}[rdoc-ref:StringIO@Position].
*/
static VALUE
strio_get_pos(VALUE self)
{
- return LONG2NUM(StringIO(self)->pos);
+ return LONG2NUM(StringIOForRead(self)->pos);
}
/*
@@ -789,7 +880,7 @@ strio_get_pos(VALUE self)
* pos = new_position -> new_position
*
* Sets the current position (in bytes);
- * see {Position}[rdoc-ref:IO@Position].
+ * see {Position}[rdoc-ref:StringIO@Position].
*/
static VALUE
strio_set_pos(VALUE self, VALUE pos)
@@ -824,9 +915,9 @@ strio_rewind(VALUE self)
* call-seq:
* seek(offset, whence = SEEK_SET) -> 0
*
- * Sets the current position to the given integer +offset+ (in bytes),
+ * Sets the position to the given integer +offset+ (in bytes),
* with respect to a given constant +whence+;
- * see {Position}[rdoc-ref:IO@Position].
+ * see {IO#seek}[rdoc-ref:IO#seek].
*/
static VALUE
strio_seek(int argc, VALUE *argv, VALUE self)
@@ -873,7 +964,7 @@ strio_seek(int argc, VALUE *argv, VALUE self)
static VALUE
strio_get_sync(VALUE self)
{
- StringIO(self);
+ StringIOForRead(self);
return Qtrue;
}
@@ -885,10 +976,9 @@ strio_get_sync(VALUE self)
* call-seq:
* each_byte {|byte| ... } -> self
*
- * With a block given, calls the block with each remaining byte in the stream;
- * see {Byte IO}[rdoc-ref:IO@Byte+IO].
+ * :include: stringio/each_byte.rdoc
*
- * With no block given, returns an enumerator.
+ * Related: StringIO#each_char, StringIO#each_codepoint, StringIO#each_line.
*/
static VALUE
strio_each_byte(VALUE self)
@@ -906,10 +996,10 @@ strio_each_byte(VALUE self)
/*
* call-seq:
- * getc -> character or nil
+ * getc -> character, byte, or nil
+ *
+ * :include: stringio/getc.rdoc
*
- * Reads and returns the next character from the stream;
- * see {Character IO}[rdoc-ref:IO@Character+IO].
*/
static VALUE
strio_getc(VALUE self)
@@ -932,10 +1022,10 @@ strio_getc(VALUE self)
/*
* call-seq:
- * getbyte -> byte or nil
+ * getbyte -> integer or nil
+ *
+ * :include: stringio/getbyte.rdoc
*
- * Reads and returns the next 8-bit byte from the stream;
- * see {Byte IO}[rdoc-ref:IO@Byte+IO].
*/
static VALUE
strio_getbyte(VALUE self)
@@ -1111,12 +1201,11 @@ strio_readbyte(VALUE self)
/*
* call-seq:
- * each_char {|c| ... } -> self
+ * each_char {|char| ... } -> self
*
- * With a block given, calls the block with each remaining character in the stream;
- * see {Character IO}[rdoc-ref:IO@Character+IO].
+ * :include: stringio/each_char.rdoc
*
- * With no block given, returns an enumerator.
+ * Related: StringIO#each_byte, StringIO#each_codepoint, StringIO#each_line.
*/
static VALUE
strio_each_char(VALUE self)
@@ -1135,10 +1224,9 @@ strio_each_char(VALUE self)
* call-seq:
* each_codepoint {|codepoint| ... } -> self
*
- * With a block given, calls the block with each remaining codepoint in the stream;
- * see {Codepoint IO}[rdoc-ref:IO@Codepoint+IO].
+ * :include: stringio/each_codepoint.rdoc
*
- * With no block given, returns an enumerator.
+ * Related: StringIO#each_byte, StringIO#each_char, StringIO#each_line.
*/
static VALUE
strio_each_codepoint(VALUE self)
@@ -1372,9 +1460,8 @@ strio_getline(struct getline_arg *arg, struct StringIO *ptr)
* gets(limit, chomp: false) -> string or nil
* gets(sep, limit, chomp: false) -> string or nil
*
- * Reads and returns a line from the stream;
- * assigns the return value to <tt>$_</tt>;
- * see {Line IO}[rdoc-ref:IO@Line+IO].
+ * :include: stringio/gets.rdoc
+ *
*/
static VALUE
strio_gets(int argc, VALUE *argv, VALUE self)
@@ -1411,15 +1498,15 @@ strio_readline(int argc, VALUE *argv, VALUE self)
}
/*
+ * :markup: markdown
+ *
* call-seq:
* each_line(sep = $/, chomp: false) {|line| ... } -> self
* each_line(limit, chomp: false) {|line| ... } -> self
* each_line(sep, limit, chomp: false) {|line| ... } -> self
*
- * Calls the block with each remaining line read from the stream;
- * does nothing if already at end-of-file;
- * returns +self+.
- * See {Line IO}[rdoc-ref:IO@Line+IO].
+ * :include: stringio/each_line.md
+ *
*/
static VALUE
strio_each(int argc, VALUE *argv, VALUE self)
@@ -1560,9 +1647,10 @@ strio_write(VALUE self, VALUE str)
/*
* call-seq:
- * strio.putc(obj) -> obj
+ * putc(object) -> object
+ *
+ * :include: stringio/putc.rdoc
*
- * See IO#putc.
*/
static VALUE
strio_putc(VALUE self, VALUE ch)
@@ -1594,9 +1682,10 @@ strio_putc(VALUE self, VALUE ch)
/*
* call-seq:
- * strio.read([length [, outbuf]]) -> string, outbuf, or nil
+ * read(maxlen = nil, out_string = nil) → new_string, out_string, or nil
+ *
+ * :include: stringio/read.rdoc
*
- * See IO#read.
*/
static VALUE
strio_read(int argc, VALUE *argv, VALUE self)
@@ -1608,11 +1697,7 @@ strio_read(int argc, VALUE *argv, VALUE self)
switch (argc) {
case 2:
- str = argv[1];
- if (!NIL_P(str)) {
- StringValue(str);
- rb_str_modify(str);
- }
+ str = strio_readbuf(ptr, argv[1]);
/* fall through */
case 1:
if (!NIL_P(argv[0])) {
@@ -1668,15 +1753,17 @@ strio_read(int argc, VALUE *argv, VALUE self)
/*
* call-seq:
- * pread(maxlen, offset) -> string
- * pread(maxlen, offset, out_string) -> string
+ * pread(maxlen, offset, out_string = nil) -> new_string or out_string
+ *
+ * :include: stringio/pread.rdoc
*
- * See IO#pread.
*/
static VALUE
strio_pread(int argc, VALUE *argv, VALUE self)
{
VALUE rb_len, rb_offset, rb_buf;
+ struct StringIO *ptr = readable(self);
+
rb_scan_args(argc, argv, "21", &rb_len, &rb_offset, &rb_buf);
long len = NUM2LONG(rb_len);
long offset = NUM2LONG(rb_offset);
@@ -1685,6 +1772,12 @@ strio_pread(int argc, VALUE *argv, VALUE self)
rb_raise(rb_eArgError, "negative string size (or size too big): %" PRIsVALUE, rb_len);
}
+ if (offset < 0) {
+ rb_syserr_fail_str(EINVAL, rb_sprintf("pread: Invalid offset argument: %" PRIsVALUE, rb_offset));
+ }
+
+ rb_buf = strio_readbuf(ptr, rb_buf);
+
if (len == 0) {
if (NIL_P(rb_buf)) {
return rb_str_new("", 0);
@@ -1692,12 +1785,6 @@ strio_pread(int argc, VALUE *argv, VALUE self)
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 (outside_p(ptr, offset)) {
rb_eof_error();
}
@@ -1788,15 +1875,15 @@ strio_syswrite_nonblock(int argc, VALUE *argv, VALUE self)
/*
* call-seq:
- * strio.length -> integer
- * strio.size -> integer
+ * size -> integer
+ *
+ * :include: stringio/size.rdoc
*
- * Returns the size of the buffer string.
*/
static VALUE
strio_size(VALUE self)
{
- VALUE string = StringIO(self)->string;
+ VALUE string = StringIOForRead(self)->string;
if (NIL_P(string)) {
return INT2FIX(0);
}
@@ -1829,27 +1916,34 @@ strio_truncate(VALUE self, VALUE len)
}
/*
- * call-seq:
- * strio.external_encoding => encoding
+ * call-seq:
+ * external_encoding -> encoding or nil
+ *
+ * Returns an Encoding object that represents the encoding of the string;
+ * see {Encodings}[rdoc-ref:StringIO@Encodings]:
+ *
+ * strio = StringIO.new('foo')
+ * strio.external_encoding # => #<Encoding:UTF-8>
+ *
+ * Returns +nil+ if +self+ has no string and is in write mode:
+ *
+ * strio = StringIO.new(nil, 'w+')
+ * strio.external_encoding # => nil
*
- * Returns the Encoding object that represents the encoding of the file.
- * If the stream is write mode and no encoding is specified, returns
- * +nil+.
*/
static VALUE
strio_external_encoding(VALUE self)
{
- struct StringIO *ptr = StringIO(self);
+ struct StringIO *ptr = StringIOForRead(self);
return rb_enc_from_encoding(get_enc(ptr));
}
/*
* call-seq:
- * strio.internal_encoding => encoding
+ * internal_encoding -> nil
*
- * Returns the Encoding of the internal string if conversion is
- * specified. Otherwise returns +nil+.
+ * Returns +nil+; for compatibility with IO.
*/
static VALUE
@@ -1918,16 +2012,9 @@ strio_set_encoding_by_bom(VALUE self)
}
/*
- * \IO streams for strings, with access similar to
- * {IO}[rdoc-ref:IO];
- * see {IO}[rdoc-ref:IO].
- *
- * === About the Examples
- *
- * Examples on this page assume that \StringIO has been required:
- *
- * require 'stringio'
+ * :markup: markdown
*
+ * :include: stringio/stringio.md
*/
void
Init_stringio(void)
@@ -2027,7 +2114,9 @@ Init_stringio(void)
rb_define_method(StringIO, "set_encoding_by_bom", strio_set_encoding_by_bom, 0);
{
+ /* :stopdoc: */
VALUE mReadable = rb_define_module_under(rb_cIO, "generic_readable");
+ /* :startdoc: */
rb_define_method(mReadable, "readchar", strio_readchar, 0);
rb_define_method(mReadable, "readbyte", strio_readbyte, 0);
rb_define_method(mReadable, "readline", strio_readline, -1);
@@ -2037,7 +2126,9 @@ Init_stringio(void)
rb_include_module(StringIO, mReadable);
}
{
+ /* :stopdoc: */
VALUE mWritable = rb_define_module_under(rb_cIO, "generic_writable");
+ /* :startdoc: */
rb_define_method(mWritable, "<<", strio_addstr, 1);
rb_define_method(mWritable, "print", strio_print, -1);
rb_define_method(mWritable, "printf", strio_printf, -1);
diff --git a/ext/strscan/extconf.rb b/ext/strscan/extconf.rb
index 3c311d2364..4e8d851fdb 100644
--- a/ext/strscan/extconf.rb
+++ b/ext/strscan/extconf.rb
@@ -4,6 +4,10 @@ if RUBY_ENGINE == 'ruby'
$INCFLAGS << " -I$(top_srcdir)" if $extmk
have_func("onig_region_memsize(NULL)")
have_func("rb_reg_onig_match", "ruby/re.h")
+ have_func("rb_deprecate_constant")
+ have_func("rb_int_parse_cstr", "ruby.h") # RUBY_VERSION >= 2.5
+ have_func("rb_gc_location", "ruby.h") # RUBY_VERSION >= 2.7
+ have_const("RUBY_TYPED_EMBEDDABLE", "ruby.h") # RUBY_VERSION >= 3.3
create_makefile 'strscan'
else
File.write('Makefile', dummy_makefile("").join)
diff --git a/ext/strscan/lib/strscan.rb b/ext/strscan/lib/strscan.rb
new file mode 100644
index 0000000000..4e8910d141
--- /dev/null
+++ b/ext/strscan/lib/strscan.rb
@@ -0,0 +1,20 @@
+# frozen_string_literal: true
+
+case RUBY_ENGINE
+when 'ruby'
+ require 'strscan.so'
+ require_relative 'strscan/strscan'
+when 'jruby'
+ require 'strscan.jar'
+ JRuby::Util.load_ext('org.jruby.ext.strscan.StringScannerLibrary')
+ require_relative 'strscan/strscan'
+when 'truffleruby'
+ if RUBY_ENGINE_VERSION.to_i >= 34
+ require 'strscan/truffleruby'
+ else
+ $LOAD_PATH.delete __dir__
+ require 'strscan'
+ end
+else
+ raise NotImplementedError, "Unknown Ruby: #{RUBY_ENGINE}"
+end
diff --git a/ext/strscan/lib/strscan/strscan.rb b/ext/strscan/lib/strscan/strscan.rb
index 46acc7ea82..5e262f4007 100644
--- a/ext/strscan/lib/strscan/strscan.rb
+++ b/ext/strscan/lib/strscan/strscan.rb
@@ -1,17 +1,47 @@
# frozen_string_literal: true
class StringScanner
+ unless method_defined?(:integer_at) # For JRuby
+ def integer_at(specifier, *to_i_args)
+ self[specifier]&.to_i(*to_i_args)
+ end
+ end
+
+ # :markup: markdown
+ #
# call-seq:
- # scan_integer(base: 10)
+ # scan_integer(base: 10) -> integer or nil
+ #
+ # Returns an integer scanned from `self`,
+ # beginning at the current position;
+ # returns `nil` if no such integer was available.
+ #
+ # When `base` is `10` (the default),
+ # equivalent to calling #scan with argument +pattern+
+ # as `'[+-]?\d+'`:
+ #
+ # ```ruby
+ # scanner = StringScanner.new('Form 27B/6')
+ # scanner.scan_integer # => nil # No integer at position 0.
+ # scanner.pos = 5
+ # scanner.scan_integer # => 27
+ # scanner.matched # => "27"
+ # scanner.pos # => 7
+ # ```
#
- # If `base` isn't provided or is `10`, then it is equivalent to calling `#scan` with a `[+-]?\d+` pattern,
- # and returns an Integer or nil.
+ # When `base` is `16` (the only other value allowed),
+ # equivalent to calling #scan with argument `pattern`
+ # as `'[+-]?(0x)?[0-9a-fA-F]+'`:
#
- # If `base` is `16`, then it is equivalent to calling `#scan` with a `[+-]?(0x)?[0-9a-fA-F]+` pattern,
- # and returns an Integer or nil.
+ # ```ruby
+ # scanner.pos = 5
+ # scanner.scan_integer(base: 16) # => 635
+ # scanner.matched # => "27B"
+ # scanner.pos # => 8
+ # ```
#
- # The scanned string must be encoded with an ASCII compatible encoding, otherwise
- # Encoding::CompatibilityError will be raised.
+ # Raises Encoding::CompatibilityError if `self` does not have
+ # an ASCII compatible encoding.
def scan_integer(base: 10)
case base
when 10
diff --git a/ext/strscan/strscan.c b/ext/strscan/strscan.c
index bc543f62b1..dede57218b 100644
--- a/ext/strscan/strscan.c
+++ b/ext/strscan/strscan.c
@@ -22,7 +22,15 @@ extern size_t onig_region_memsize(const struct re_registers *regs);
#include <stdbool.h>
-#define STRSCAN_VERSION "3.1.6.dev"
+#define STRSCAN_VERSION "3.1.9.dev"
+
+
+#ifdef HAVE_RB_DEPRECATE_CONSTANT
+/* In ruby 3.0, defined but exposed in external headers */
+extern void rb_deprecate_constant(VALUE mod, const char *name);
+#else
+# define rb_deprecate_constant(mod, name) ((void)0)
+#endif
/* =======================================================================
Data Type Definitions
@@ -30,7 +38,6 @@ extern size_t onig_region_memsize(const struct re_registers *regs);
static VALUE StringScanner;
static VALUE ScanError;
-static ID id_byteslice;
static int usascii_encindex, utf8_encindex, binary_encindex;
@@ -97,7 +104,6 @@ static VALUE strscan_init_copy _((VALUE vself, VALUE vorig));
static VALUE strscan_s_mustc _((VALUE self));
static VALUE strscan_terminate _((VALUE self));
-static VALUE strscan_clear _((VALUE self));
static VALUE strscan_get_string _((VALUE self));
static VALUE strscan_set_string _((VALUE self, VALUE str));
static VALUE strscan_concat _((VALUE self, VALUE str));
@@ -119,14 +125,11 @@ static VALUE strscan_search_full _((VALUE self, VALUE re,
static void adjust_registers_to_matched _((struct strscanner *p));
static VALUE strscan_getch _((VALUE self));
static VALUE strscan_get_byte _((VALUE self));
-static VALUE strscan_getbyte _((VALUE self));
static VALUE strscan_peek _((VALUE self, VALUE len));
-static VALUE strscan_peep _((VALUE self, VALUE len));
static VALUE strscan_scan_base10_integer _((VALUE self));
static VALUE strscan_unscan _((VALUE self));
static VALUE strscan_bol_p _((VALUE self));
static VALUE strscan_eos_p _((VALUE self));
-static VALUE strscan_empty_p _((VALUE self));
static VALUE strscan_rest_p _((VALUE self));
static VALUE strscan_matched_p _((VALUE self));
static VALUE strscan_matched _((VALUE self));
@@ -179,12 +182,35 @@ extract_beg_len(struct strscanner *p, long beg_i, long len)
Constructor
======================================================================= */
+#ifdef RUBY_TYPED_EMBEDDABLE
+# define HAVE_RUBY_TYPED_EMBEDDABLE 1
+#else
+# ifdef HAVE_CONST_RUBY_TYPED_EMBEDDABLE
+# define RUBY_TYPED_EMBEDDABLE RUBY_TYPED_EMBEDDABLE
+# define HAVE_RUBY_TYPED_EMBEDDABLE 1
+# else
+# define RUBY_TYPED_EMBEDDABLE 0
+# endif
+#endif
+
+#ifdef HAVE_RB_GC_LOCATION
+static void
+strscan_compact(void *ptr)
+{
+ struct strscanner *p = ptr;
+ p->str = rb_gc_location(p->str);
+ p->regex = rb_gc_location(p->regex);
+}
+#else
+#define rb_gc_mark_movable rb_gc_mark
+#endif
+
static void
strscan_mark(void *ptr)
{
struct strscanner *p = ptr;
- rb_gc_mark(p->str);
- rb_gc_mark(p->regex);
+ rb_gc_mark_movable(p->str);
+ rb_gc_mark_movable(p->regex);
}
static void
@@ -192,24 +218,37 @@ strscan_free(void *ptr)
{
struct strscanner *p = ptr;
onig_region_free(&(p->regs), 0);
+#ifndef HAVE_RUBY_TYPED_EMBEDDABLE
ruby_xfree(p);
+#endif
}
static size_t
strscan_memsize(const void *ptr)
{
- const struct strscanner *p = ptr;
- size_t size = sizeof(*p) - sizeof(p->regs);
+ size_t size = 0;
+#ifndef HAVE_RUBY_TYPED_EMBEDDABLE
+ size += sizeof(struct strscanner);
+#endif
+
#ifdef HAVE_ONIG_REGION_MEMSIZE
- size += onig_region_memsize(&p->regs);
+ const struct strscanner *p = ptr;
+ size += onig_region_memsize(&p->regs) - sizeof(p->regs);
#endif
return size;
}
static const rb_data_type_t strscanner_type = {
- "StringScanner",
- {strscan_mark, strscan_free, strscan_memsize},
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED
+ .wrap_struct_name = "StringScanner",
+ .function = {
+ .dmark = strscan_mark,
+ .dfree = strscan_free,
+ .dsize = strscan_memsize,
+#ifdef HAVE_RB_GC_LOCATION
+ .dcompact = strscan_compact,
+#endif
+ },
+ .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_EMBEDDABLE
};
static VALUE
@@ -371,6 +410,9 @@ strscan_reset(VALUE self)
/*
* :markup: markdown
+ * :call-seq:
+ * terminate -> self
+ *
* :include: strscan/link_refs.txt
* :include: strscan/methods/terminate.md
*/
@@ -386,21 +428,6 @@ strscan_terminate(VALUE self)
}
/*
- * call-seq:
- * clear -> self
- *
- * This method is obsolete; use the equivalent method StringScanner#terminate.
- */
-
- /* :nodoc: */
-static VALUE
-strscan_clear(VALUE self)
-{
- rb_warning("StringScanner#clear is obsolete; use #terminate instead");
- return strscan_terminate(self);
-}
-
-/*
* :markup: markdown
* :include: strscan/link_refs.txt
*
@@ -515,6 +542,9 @@ strscan_concat(VALUE self, VALUE str)
/*
* :markup: markdown
+ * :call-seq:
+ * pos -> byte_position
+ *
* :include: strscan/link_refs.txt
* :include: strscan/methods/get_pos.md
*/
@@ -529,6 +559,9 @@ strscan_get_pos(VALUE self)
/*
* :markup: markdown
+ * :call-seq:
+ * charpos -> character_position
+ *
* :include: strscan/link_refs.txt
* :include: strscan/methods/get_charpos.md
*/
@@ -544,6 +577,10 @@ strscan_get_charpos(VALUE self)
/*
* :markup: markdown
+ * :call-seq:
+ * pos = n -> n
+ * pointer = n -> n
+ *
* :include: strscan/link_refs.txt
* :include: strscan/methods/set_pos.md
*/
@@ -768,6 +805,9 @@ strscan_do_scan(VALUE self, VALUE pattern, int succptr, int getstr, int headonly
/*
* :markup: markdown
+ * :call-seq:
+ * scan(pattern) -> substring or nil
+ *
* :include: strscan/link_refs.txt
* :include: strscan/methods/scan.md
*/
@@ -782,7 +822,7 @@ strscan_scan(VALUE self, VALUE re)
* :include: strscan/link_refs.txt
*
* call-seq:
- * match?(pattern) -> updated_position or nil
+ * match?(pattern) -> match_size or nil
*
* Attempts to [match][17] the given `pattern`
* at the beginning of the [target substring][3];
@@ -841,6 +881,9 @@ strscan_match_p(VALUE self, VALUE re)
/*
* :markup: markdown
+ * call-seq:
+ * skip(pattern) -> match_size or nil
+ *
* :include: strscan/link_refs.txt
* :include: strscan/methods/skip.md
*/
@@ -913,7 +956,7 @@ strscan_check(VALUE self, VALUE re)
/*
* call-seq:
- * scan_full(pattern, advance_pointer_p, return_string_p) -> matched_substring or nil
+ * scan_full(pattern, advance_pointer_p, return_string_p) -> matched_substring or length or nil
*
* Equivalent to one of the following:
*
@@ -938,6 +981,9 @@ strscan_scan_full(VALUE self, VALUE re, VALUE s, VALUE f)
/*
* :markup: markdown
+ * :call-seq:
+ * scan_until(pattern) -> substring or nil
+ *
* :include: strscan/link_refs.txt
* :include: strscan/methods/scan_until.md
*/
@@ -1012,6 +1058,9 @@ strscan_exist_p(VALUE self, VALUE re)
/*
* :markup: markdown
+ * :call-seq:
+ * skip_until(pattern) -> matched_substring_size or nil
+ *
* :include: strscan/link_refs.txt
* :include: strscan/methods/skip_until.md
*/
@@ -1123,6 +1172,9 @@ adjust_registers_to_matched(struct strscanner *p)
/*
* :markup: markdown
+ * :call-seq:
+ * getch -> character or nil
+ *
* :include: strscan/link_refs.txt
* :include: strscan/methods/getch.md
*/
@@ -1150,7 +1202,7 @@ strscan_getch(VALUE self)
/*
* call-seq:
- * scan_byte -> integer_byte
+ * scan_byte -> integer_byte or nil
*
* Scans one byte and returns it as an integer.
* This method is not multibyte character sensitive.
@@ -1196,6 +1248,9 @@ strscan_peek_byte(VALUE self)
/*
* :markup: markdown
+ * :call-seq:
+ * get_byte -> byte_as_character or nil
+ *
* :include: strscan/link_refs.txt
* :include: strscan/methods/get_byte.md
*/
@@ -1219,22 +1274,6 @@ 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)
-{
- rb_warning("StringScanner#getbyte is obsolete; use #get_byte instead");
- return strscan_get_byte(self);
-}
-
-/*
* :markup: markdown
* :include: strscan/link_refs.txt
*
@@ -1269,22 +1308,6 @@ strscan_peek(VALUE self, VALUE vlen)
return extract_beg_len(p, p->curr, len);
}
-/*
- * call-seq:
- * peep
- *
- * Equivalent to #peek.
- * This method is obsolete; use #peek instead.
- */
-
- /* :nodoc: */
-static VALUE
-strscan_peep(VALUE self, VALUE vlen)
-{
- rb_warning("StringScanner#peep is obsolete; use #peek instead");
- return strscan_peek(self, vlen);
-}
-
static VALUE
strscan_parse_integer(struct strscanner *p, int base, long len)
{
@@ -1305,16 +1328,17 @@ strscan_parse_integer(struct strscanner *p, int base, long len)
}
static inline bool
-strscan_ascii_compat_fastpath(VALUE str) {
+strscan_ascii_compat_fastpath(VALUE str)
+{
int encindex = ENCODING_GET_INLINED(str);
- // The overwhelming majority of strings are in one of these 3 encodings.
+ /* The overwhelming majority of strings are in one of these 3 encodings. */
return encindex == utf8_encindex || encindex == binary_encindex || encindex == usascii_encindex;
}
static inline void
strscan_must_ascii_compat(VALUE str)
{
- // The overwhelming majority of strings are in one of these 3 encodings.
+ /* The overwhelming majority of strings are in one of these 3 encodings. */
if (RB_LIKELY(strscan_ascii_compat_fastpath(str))) {
return;
}
@@ -1322,11 +1346,12 @@ strscan_must_ascii_compat(VALUE str)
rb_must_asciicompat(str);
}
+/* :nodoc: */
static VALUE
strscan_scan_base10_integer(VALUE self)
{
char *ptr;
- long len = 0;
+ long len = 0, remaining_len;
struct strscanner *p;
GET_SCANNER(self, p);
@@ -1336,7 +1361,7 @@ strscan_scan_base10_integer(VALUE self)
ptr = CURPTR(p);
- long remaining_len = S_RESTLEN(p);
+ remaining_len = S_RESTLEN(p);
if (remaining_len <= 0) {
return Qnil;
@@ -1359,11 +1384,12 @@ strscan_scan_base10_integer(VALUE self)
return strscan_parse_integer(p, 10, len);
}
+/* :nodoc: */
static VALUE
strscan_scan_base16_integer(VALUE self)
{
char *ptr;
- long len = 0;
+ long len = 0, remaining_len;
struct strscanner *p;
GET_SCANNER(self, p);
@@ -1373,7 +1399,7 @@ strscan_scan_base16_integer(VALUE self)
ptr = CURPTR(p);
- long remaining_len = S_RESTLEN(p);
+ remaining_len = S_RESTLEN(p);
if (remaining_len <= 0) {
return Qnil;
@@ -1526,26 +1552,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)
-{
- rb_warning("StringScanner#empty? is obsolete; use #eos? instead");
- return strscan_eos_p(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.
*
* s = StringScanner.new('test string')
* # These two are opposites
@@ -1673,7 +1682,7 @@ name_to_backref_number(struct re_registers *regs, VALUE regexp, const char* name
(const unsigned char* )name_end,
regs);
if (num >= 1) {
- return num;
+ return num;
}
}
rb_enc_raise(enc, rb_eIndexError, "undefined group name reference: %.*s",
@@ -1681,6 +1690,38 @@ name_to_backref_number(struct re_registers *regs, VALUE regexp, const char* name
}
/*
+ * Resolve capture group index from Integer, Symbol, or String.
+ * Returns the resolved register index, or -1 if unmatched/out of range.
+ * For Symbol/String specifiers, raises IndexError if the named group
+ * does not exist.
+ */
+static long
+resolve_capture_index(struct strscanner *p, VALUE specifier)
+{
+ const char *name;
+ long i;
+ if (! MATCHED_P(p)) return -1;
+ switch (TYPE(specifier)) {
+ case T_SYMBOL:
+ specifier = rb_sym2str(specifier);
+ /* fall through */
+ case T_STRING:
+ RSTRING_GETMEM(specifier, name, i);
+ i = name_to_backref_number(&(p->regs), p->regex, name, name + i,
+ rb_enc_get(specifier));
+ break;
+ default:
+ i = NUM2LONG(specifier);
+ }
+ if (i < 0)
+ i += p->regs.num_regs;
+ if (i < 0) return -1;
+ if (i >= p->regs.num_regs) return -1;
+ if (p->regs.beg[i] == -1) return -1;
+ return i;
+}
+
+/*
*
* :markup: markdown
* :include: strscan/link_refs.txt
@@ -1754,30 +1795,12 @@ name_to_backref_number(struct re_registers *regs, VALUE regexp, const char* name
static VALUE
strscan_aref(VALUE self, VALUE idx)
{
- const char *name;
struct strscanner *p;
long i;
GET_SCANNER(self, p);
- if (! MATCHED_P(p)) return Qnil;
-
- switch (TYPE(idx)) {
- case T_SYMBOL:
- idx = rb_sym2str(idx);
- /* fall through */
- case T_STRING:
- RSTRING_GETMEM(idx, name, i);
- i = name_to_backref_number(&(p->regs), p->regex, name, name + i, rb_enc_get(idx));
- break;
- default:
- i = NUM2LONG(idx);
- }
-
- if (i < 0)
- i += p->regs.num_regs;
- if (i < 0) return Qnil;
- if (i >= p->regs.num_regs) return Qnil;
- if (p->regs.beg[i] == -1) return Qnil;
+ i = resolve_capture_index(p, idx);
+ if (i < 0) return Qnil;
return extract_range(p,
adjust_register_position(p, p->regs.beg[i]),
@@ -1786,6 +1809,81 @@ strscan_aref(VALUE self, VALUE idx)
/*
* :markup: markdown
+ *
+ * call-seq:
+ * integer_at(specifier, base=10) -> integer or nil
+ *
+ * Returns the captured substring at the given `specifier` as an Integer,
+ * following the behavior of `String#to_i(base)`.
+ *
+ * `specifier` can be an Integer (positive, negative, or zero), a Symbol,
+ * or a String for named capture groups.
+ *
+ * Returns `nil` if:
+ * - No match has been performed or the last match failed
+ * - The `specifier` is an Integer and is out of range
+ * - The group at `specifier` did not participate in the match
+ *
+ * Raises IndexError if `specifier` is a Symbol or String that does not
+ * correspond to a named capture group, consistent with
+ * `StringScanner#[]`.
+ *
+ * This is semantically equivalent to `self[specifier]&.to_i(base)`
+ * but avoids the allocation of a temporary String when possible.
+ *
+ * ```rb
+ * scanner = StringScanner.new("2024-06-15")
+ * scanner.scan(/(\d{4})-(\d{2})-(\d{2})/)
+ * scanner.integer_at(1) # => 2024
+ * scanner.integer_at(1, 16) # => 8228
+ * ```
+ */
+static VALUE
+strscan_integer_at(int argc, VALUE *argv, VALUE self)
+{
+ struct strscanner *p;
+ long i;
+ long beg, end, len;
+ const char *ptr;
+ VALUE rb_specifier;
+ VALUE rb_base;
+ int base = 10;
+
+ GET_SCANNER(self, p);
+ rb_scan_args(argc, argv, "11", &rb_specifier, &rb_base);
+ if (argc > 1)
+ base = NUM2INT(rb_base);
+ i = resolve_capture_index(p, rb_specifier);
+ if (i < 0)
+ return Qnil;
+
+ beg = adjust_register_position(p, p->regs.beg[i]);
+ end = adjust_register_position(p, p->regs.end[i]);
+ len = end - beg;
+ ptr = S_PBEG(p) + beg;
+#ifdef HAVE_RB_INT_PARSE_CSTR
+ {
+ /*
+ * Ruby 2.5 or later export the rb_int_parse_cstr() symbol but
+ * prototype definition isn't provided. Ruby 4.1 or later
+ * provide prototype definition.
+ */
+# ifndef RB_INT_PARSE_DEFAULT
+ VALUE rb_int_parse_cstr(const char *str, ssize_t len, char **endp,
+ size_t *ndigits, int base, int flags);
+# define RB_INT_PARSE_DEFAULT 0x07
+# endif
+ char *endp;
+ return rb_int_parse_cstr(ptr, len, &endp, NULL, base,
+ RB_INT_PARSE_DEFAULT);
+ }
+#else
+ return rb_str_to_inum(rb_str_new(ptr, len), base, 0);
+#endif
+}
+
+/*
+ * :markup: markdown
* :include: strscan/link_refs.txt
*
* call-seq:
@@ -2053,22 +2151,6 @@ strscan_rest_size(VALUE self)
return INT2FIX(i);
}
-/*
- * 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)
-{
- rb_warning("StringScanner#restsize is obsolete; use #rest_size instead");
- return strscan_rest_size(self);
-}
-
#define INSPECT_LENGTH 5
/*
@@ -2227,8 +2309,8 @@ named_captures_iter(const OnigUChar *name,
* 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;
+ * Returns a hash of named captures for the most recent regexp match,
+ * or an empty hash if there are no named captures;
* see [Captured Match Values][13]:
*
* ```rb
@@ -2268,6 +2350,13 @@ strscan_named_captures(VALUE self)
======================================================================= */
/*
+ * Document-class: StringScanner::Error
+ *
+ * The error class for StringScanner.
+ * See StringScanner#unscan.
+ */
+
+/*
* Document-class: StringScanner
*
* :markup: markdown
@@ -2287,8 +2376,6 @@ Init_strscan(void)
ID id_scanerr = rb_intern("ScanError");
VALUE tmp;
- id_byteslice = rb_intern("byteslice");
-
usascii_encindex = rb_usascii_encindex();
utf8_encindex = rb_utf8_encindex();
binary_encindex = rb_ascii8bit_encindex();
@@ -2297,6 +2384,7 @@ Init_strscan(void)
ScanError = rb_define_class_under(StringScanner, "Error", rb_eStandardError);
if (!rb_const_defined(rb_cObject, id_scanerr)) {
rb_const_set(rb_cObject, id_scanerr, ScanError);
+ rb_deprecate_constant(rb_cObject, "ScanError");
}
tmp = rb_str_new2(STRSCAN_VERSION);
rb_obj_freeze(tmp);
@@ -2304,6 +2392,7 @@ Init_strscan(void)
tmp = rb_str_new2("$Id$");
rb_obj_freeze(tmp);
rb_const_set(StringScanner, rb_intern("Id"), tmp);
+ rb_deprecate_constant(StringScanner, "Id");
rb_define_alloc_func(StringScanner, strscan_s_allocate);
rb_define_private_method(StringScanner, "initialize", strscan_initialize, -1);
@@ -2311,7 +2400,6 @@ Init_strscan(void)
rb_define_singleton_method(StringScanner, "must_C_version", strscan_s_mustc, 0);
rb_define_method(StringScanner, "reset", strscan_reset, 0);
rb_define_method(StringScanner, "terminate", strscan_terminate, 0);
- rb_define_method(StringScanner, "clear", strscan_clear, 0);
rb_define_method(StringScanner, "string", strscan_get_string, 0);
rb_define_method(StringScanner, "string=", strscan_set_string, 1);
rb_define_method(StringScanner, "concat", strscan_concat, 1);
@@ -2336,11 +2424,9 @@ 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_private_method(StringScanner, "scan_base10_integer", strscan_scan_base10_integer, 0);
rb_define_private_method(StringScanner, "scan_base16_integer", strscan_scan_base16_integer, 0);
@@ -2350,13 +2436,13 @@ Init_strscan(void)
rb_define_method(StringScanner, "beginning_of_line?", strscan_bol_p, 0);
rb_alias(StringScanner, rb_intern("bol?"), rb_intern("beginning_of_line?"));
rb_define_method(StringScanner, "eos?", strscan_eos_p, 0);
- rb_define_method(StringScanner, "empty?", strscan_empty_p, 0);
rb_define_method(StringScanner, "rest?", strscan_rest_p, 0);
rb_define_method(StringScanner, "matched?", strscan_matched_p, 0);
rb_define_method(StringScanner, "matched", strscan_matched, 0);
rb_define_method(StringScanner, "matched_size", strscan_matched_size, 0);
rb_define_method(StringScanner, "[]", strscan_aref, 1);
+ rb_define_method(StringScanner, "integer_at", strscan_integer_at, -1);
rb_define_method(StringScanner, "pre_match", strscan_pre_match, 0);
rb_define_method(StringScanner, "post_match", strscan_post_match, 0);
rb_define_method(StringScanner, "size", strscan_size, 0);
@@ -2365,13 +2451,10 @@ Init_strscan(void)
rb_define_method(StringScanner, "rest", strscan_rest, 0);
rb_define_method(StringScanner, "rest_size", strscan_rest_size, 0);
- rb_define_method(StringScanner, "restsize", strscan_restsize, 0);
rb_define_method(StringScanner, "inspect", strscan_inspect, 0);
rb_define_method(StringScanner, "fixed_anchor?", strscan_fixed_anchor_p, 0);
rb_define_method(StringScanner, "named_captures", strscan_named_captures, 0);
-
- rb_require("strscan/strscan");
}
diff --git a/ext/strscan/strscan.gemspec b/ext/strscan/strscan.gemspec
index 47180bb8d8..a51285fa7e 100644
--- a/ext/strscan/strscan.gemspec
+++ b/ext/strscan/strscan.gemspec
@@ -16,18 +16,18 @@ Gem::Specification.new do |s|
s.summary = "Provides lexical scanning operations on a String."
s.description = "Provides lexical scanning operations on a String."
- files = [
- "COPYING",
- "LICENSE.txt",
- "lib/strscan/strscan.rb"
+ files = %w[
+ COPYING
+ LICENSE.txt
+ lib/strscan.rb
+ lib/strscan/strscan.rb
+ lib/strscan/truffleruby.rb
]
s.require_paths = %w{lib}
if RUBY_ENGINE == "jruby"
files << "lib/strscan.jar"
- files << "ext/jruby/lib/strscan.rb"
- s.require_paths += %w{ext/jruby/lib}
s.platform = "java"
else
files << "ext/strscan/extconf.rb"
diff --git a/ext/win32/lib/win32/registry.rb b/ext/win32/lib/win32/registry.rb
deleted file mode 100644
index 8e2c8b2e1a..0000000000
--- a/ext/win32/lib/win32/registry.rb
+++ /dev/null
@@ -1,925 +0,0 @@
-# frozen_string_literal: true
-require 'fiddle/import'
-
-module Win32
-
-=begin rdoc
-= Win32 Registry
-
-win32/registry is registry accessor library for Win32 platform.
-It uses importer to call Win32 Registry APIs.
-
-== example
- Win32::Registry::HKEY_CURRENT_USER.open('SOFTWARE\foo') do |reg|
- value = reg['foo'] # read a value
- value = reg['foo', Win32::Registry::REG_SZ] # read a value with type
- type, value = reg.read('foo') # read a value
- reg['foo'] = 'bar' # write a value
- reg['foo', Win32::Registry::REG_SZ] = 'bar' # write a value with type
- reg.write('foo', Win32::Registry::REG_SZ, 'bar') # write a value
-
- reg.each_value { |name, type, data| ... } # Enumerate values
- reg.each_key { |key, wtime| ... } # Enumerate subkeys
-
- reg.delete_value(name) # Delete a value
- reg.delete_key(name) # Delete a subkey
- reg.delete_key(name, true) # Delete a subkey recursively
- end
-
-= Reference
-
-== Win32::Registry class
-
---- info
-
---- num_keys
-
---- max_key_length
-
---- num_values
-
---- max_value_name_length
-
---- max_value_length
-
---- descriptor_length
-
---- wtime
- Returns an item of key information.
-
-=== constants
---- HKEY_CLASSES_ROOT
-
---- HKEY_CURRENT_USER
-
---- HKEY_LOCAL_MACHINE
-
---- HKEY_PERFORMANCE_DATA
-
---- HKEY_CURRENT_CONFIG
-
---- HKEY_DYN_DATA
-
- Win32::Registry object whose key is predefined key.
-For detail, see the MSDN[http://msdn.microsoft.com/library/en-us/sysinfo/base/predefined_keys.asp] article.
-
-=end rdoc
-
- WCHAR = Encoding::UTF_16LE
- WCHAR_NUL = "\0".encode(WCHAR).freeze
- WCHAR_CR = "\r".encode(WCHAR).freeze
- WCHAR_SIZE = WCHAR_NUL.bytesize
- LOCALE = Encoding::UTF_8
-
- class Registry
-
- #
- # For detail, see the MSDN[http://msdn.microsoft.com/library/en-us/sysinfo/base/registry.asp].
- #
- # --- HKEY_*
- #
- # Predefined key ((*handle*)).
- # These are Integer, not Win32::Registry.
- #
- # --- REG_*
- #
- # Registry value type.
- #
- # --- KEY_*
- #
- # Security access mask.
- #
- # --- KEY_OPTIONS_*
- #
- # Key options.
- #
- # --- REG_CREATED_NEW_KEY
- #
- # --- REG_OPENED_EXISTING_KEY
- #
- # If the key is created newly or opened existing key.
- # See also Registry#disposition method.
- module Constants
- HKEY_CLASSES_ROOT = 0x80000000
- HKEY_CURRENT_USER = 0x80000001
- HKEY_LOCAL_MACHINE = 0x80000002
- HKEY_USERS = 0x80000003
- HKEY_PERFORMANCE_DATA = 0x80000004
- HKEY_PERFORMANCE_TEXT = 0x80000050
- HKEY_PERFORMANCE_NLSTEXT = 0x80000060
- HKEY_CURRENT_CONFIG = 0x80000005
- HKEY_DYN_DATA = 0x80000006
-
- REG_NONE = 0
- REG_SZ = 1
- REG_EXPAND_SZ = 2
- REG_BINARY = 3
- REG_DWORD = 4
- REG_DWORD_LITTLE_ENDIAN = 4
- REG_DWORD_BIG_ENDIAN = 5
- REG_LINK = 6
- REG_MULTI_SZ = 7
- REG_RESOURCE_LIST = 8
- REG_FULL_RESOURCE_DESCRIPTOR = 9
- REG_RESOURCE_REQUIREMENTS_LIST = 10
- REG_QWORD = 11
- REG_QWORD_LITTLE_ENDIAN = 11
-
- STANDARD_RIGHTS_READ = 0x00020000
- STANDARD_RIGHTS_WRITE = 0x00020000
- KEY_QUERY_VALUE = 0x0001
- KEY_SET_VALUE = 0x0002
- KEY_CREATE_SUB_KEY = 0x0004
- KEY_ENUMERATE_SUB_KEYS = 0x0008
- KEY_NOTIFY = 0x0010
- KEY_CREATE_LINK = 0x0020
- KEY_READ = STANDARD_RIGHTS_READ |
- KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS | KEY_NOTIFY
- KEY_WRITE = STANDARD_RIGHTS_WRITE |
- KEY_SET_VALUE | KEY_CREATE_SUB_KEY
- KEY_EXECUTE = KEY_READ
- KEY_ALL_ACCESS = KEY_READ | KEY_WRITE | KEY_CREATE_LINK
-
- REG_OPTION_RESERVED = 0x0000
- REG_OPTION_NON_VOLATILE = 0x0000
- REG_OPTION_VOLATILE = 0x0001
- REG_OPTION_CREATE_LINK = 0x0002
- REG_OPTION_BACKUP_RESTORE = 0x0004
- REG_OPTION_OPEN_LINK = 0x0008
- REG_LEGAL_OPTION = REG_OPTION_RESERVED |
- REG_OPTION_NON_VOLATILE | REG_OPTION_CREATE_LINK |
- REG_OPTION_BACKUP_RESTORE | REG_OPTION_OPEN_LINK
-
- REG_CREATED_NEW_KEY = 1
- REG_OPENED_EXISTING_KEY = 2
-
- REG_WHOLE_HIVE_VOLATILE = 0x0001
- REG_REFRESH_HIVE = 0x0002
- REG_NO_LAZY_FLUSH = 0x0004
- REG_FORCE_RESTORE = 0x0008
-
- MAX_KEY_LENGTH = 514
- MAX_VALUE_LENGTH = 32768
- end
- include Constants
- include Enumerable
-
- #
- # Error
- #
- class Error < ::StandardError
- module Kernel32
- extend Fiddle::Importer
- dlload "kernel32.dll"
- end
- FormatMessageW = Kernel32.extern "int FormatMessageW(int, void *, int, int, void *, int, void *)", :stdcall
- def initialize(code)
- @code = code
- buff = WCHAR_NUL * 1024
- lang = 0
- begin
- len = FormatMessageW.call(0x1200, nil, code, lang, buff, 1024, nil)
- msg = buff.byteslice(0, len * WCHAR_SIZE)
- msg.delete!(WCHAR_CR)
- msg.chomp!
- msg.encode!(LOCALE)
- rescue EncodingError
- raise unless lang == 0
- lang = 0x0409 # en_US
- retry
- end
- super msg
- end
- attr_reader :code
- end
-
- #
- # Predefined Keys
- #
- class PredefinedKey < Registry
- def initialize(hkey, keyname)
- @hkey = Fiddle::Pointer.new(hkey)
- @parent = nil
- @keyname = keyname
- @disposition = REG_OPENED_EXISTING_KEY
- end
-
- # Predefined keys cannot be closed
- def close
- raise Error.new(5) ## ERROR_ACCESS_DENIED
- end
-
- # Fake #class method for Registry#open, Registry#create
- def class
- Registry
- end
-
- # Make all
- Constants.constants.grep(/^HKEY_/) do |c|
- Registry.const_set c, new(Constants.const_get(c), c.to_s)
- end
- end
-
- #
- # Win32 APIs
- #
- module API
- include Constants
- extend Fiddle::Importer
- dlload "advapi32.dll"
- [
- "long RegOpenKeyExW(void *, void *, long, long, void *)",
- "long RegCreateKeyExW(void *, void *, long, long, long, long, void *, void *, void *)",
- "long RegEnumValueW(void *, long, void *, void *, void *, void *, void *, void *)",
- "long RegEnumKeyExW(void *, long, void *, void *, void *, void *, void *, void *)",
- "long RegQueryValueExW(void *, void *, void *, void *, void *, void *)",
- "long RegSetValueExW(void *, void *, long, long, void *, long)",
- "long RegDeleteValueW(void *, void *)",
- "long RegDeleteKeyW(void *, void *)",
- "long RegFlushKey(void *)",
- "long RegCloseKey(void *)",
- "long RegQueryInfoKeyW(void *, void *, void *, void *, void *, void *, void *, void *, void *, void *, void *, void *)",
- ].each do |fn|
- cfunc = extern fn, :stdcall
- const_set cfunc.name.intern, cfunc
- end
-
- module_function
-
- def check(result)
- raise Error, result, caller(1) if result != 0
- end
-
- def win64?
- /^(?:x64|x86_64)/ =~ RUBY_PLATFORM
- end
-
- TEMPLATE_HANDLE = 'J<'
-
- def packhandle(h)
- [h].pack(TEMPLATE_HANDLE)
- end
-
- def unpackhandle(h)
- (h + [0].pack(TEMPLATE_HANDLE)).unpack1(TEMPLATE_HANDLE)
- end
-
- TEMPLATE_DWORD = 'V'
-
- def packdw(dw)
- [dw].pack(TEMPLATE_DWORD)
- end
-
- def unpackdw(dw)
- (dw + [0].pack(TEMPLATE_DWORD)).unpack1(TEMPLATE_DWORD)
- end
-
- TEMPLATE_QWORD = 'Q<'
-
- def packqw(qw)
- [qw].pack(TEMPLATE_QWORD)
- end
-
- def unpackqw(qw)
- (qw + [0].pack(TEMPLATE_QWORD)).unpack1(TEMPLATE_QWORD)
- end
-
- def make_wstr(str)
- (str+"\0").encode(WCHAR)
- end
-
- def OpenKey(hkey, name, opt, desired)
- result = packhandle(0)
- check RegOpenKeyExW.call(hkey, make_wstr(name), opt, desired, result)
- unpackhandle(result)
- end
-
- def CreateKey(hkey, name, opt, desired)
- result = packhandle(0)
- disp = packdw(0)
- check RegCreateKeyExW.call(hkey, make_wstr(name), 0, 0, opt, desired,
- nil, result, disp)
- [ unpackhandle(result), unpackdw(disp) ]
- end
-
- def EnumValue(hkey, index)
- name = WCHAR_NUL * Constants::MAX_KEY_LENGTH
- size = packdw(Constants::MAX_KEY_LENGTH)
- check RegEnumValueW.call(hkey, index, name, size, nil, nil, nil, nil)
- name.byteslice(0, unpackdw(size) * WCHAR_SIZE)
- end
-
- def EnumKey(hkey, index)
- name = WCHAR_NUL * Constants::MAX_KEY_LENGTH
- size = packdw(Constants::MAX_KEY_LENGTH)
- wtime = ' ' * 8
- check RegEnumKeyExW.call(hkey, index, name, size, nil, nil, nil, wtime)
- [ name.byteslice(0, unpackdw(size) * WCHAR_SIZE), unpackqw(wtime) ]
- end
-
- def QueryValue(hkey, name)
- type = packdw(0)
- size = packdw(0)
- name = make_wstr(name)
- check RegQueryValueExW.call(hkey, name, nil, type, nil, size)
- data = "\0".b * unpackdw(size)
- check RegQueryValueExW.call(hkey, name, nil, type, data, size)
- [ unpackdw(type), data[0, unpackdw(size)] ]
- end
-
- def SetValue(hkey, name, type, data, size)
- case type
- when REG_SZ, REG_EXPAND_SZ, REG_MULTI_SZ
- data = data.encode(WCHAR)
- size ||= data.bytesize + WCHAR_SIZE
- end
- check RegSetValueExW.call(hkey, make_wstr(name), 0, type, data, size)
- end
-
- def DeleteValue(hkey, name)
- check RegDeleteValueW.call(hkey, make_wstr(name))
- end
-
- def DeleteKey(hkey, name)
- check RegDeleteKeyW.call(hkey, make_wstr(name))
- end
-
- def FlushKey(hkey)
- check RegFlushKey.call(hkey)
- end
-
- def CloseKey(hkey)
- check RegCloseKey.call(hkey)
- end
-
- def QueryInfoKey(hkey)
- subkeys = packdw(0)
- maxsubkeylen = packdw(0)
- values = packdw(0)
- maxvaluenamelen = packdw(0)
- maxvaluelen = packdw(0)
- secdescs = packdw(0)
- wtime = ' ' * 8
- check RegQueryInfoKeyW.call(hkey, 0, 0, 0, subkeys, maxsubkeylen, 0,
- values, maxvaluenamelen, maxvaluelen, secdescs, wtime)
- [ unpackdw(subkeys), unpackdw(maxsubkeylen), unpackdw(values),
- unpackdw(maxvaluenamelen), unpackdw(maxvaluelen),
- unpackdw(secdescs), unpackqw(wtime) ]
- end
- end
-
- #
- # Replace %\w+% into the environment value of what is contained between the %'s
- # This method is used for REG_EXPAND_SZ.
- #
- # For detail, see expandEnvironmentStrings[https://learn.microsoft.com/en-us/windows/win32/api/processenv/nf-processenv-expandenvironmentstringsa] \Win32 \API.
- #
- def self.expand_environ(str)
- str.gsub(Regexp.compile("%([^%]+)%".encode(str.encoding))) {
- v = $1.encode(LOCALE)
- (ENV[v] || ENV[v.upcase])&.encode(str.encoding) || $&
- }
- end
-
- @@type2name = %w[
- REG_NONE REG_SZ REG_EXPAND_SZ REG_BINARY REG_DWORD
- REG_DWORD_BIG_ENDIAN REG_LINK REG_MULTI_SZ
- REG_RESOURCE_LIST REG_FULL_RESOURCE_DESCRIPTOR
- REG_RESOURCE_REQUIREMENTS_LIST REG_QWORD
- ].inject([]) do |ary, type|
- ary[Constants.const_get(type)] = type
- ary
- end.freeze
-
- #
- # Convert registry type value to readable string.
- #
- def self.type2name(type)
- @@type2name[type] || type.to_s
- end
-
- #
- # Convert 64-bit FILETIME integer into Time object.
- #
- def self.wtime2time(wtime)
- Time.at((wtime - 116444736000000000) / 10000000)
- end
-
- #
- # Convert Time object or Integer object into 64-bit FILETIME.
- #
- def self.time2wtime(time)
- time.to_i * 10000000 + 116444736000000000
- end
-
- #
- # constructor
- #
- private_class_method :new
-
- #
- # --- Registry.open(key, subkey, desired = KEY_READ, opt = REG_OPTION_RESERVED)
- #
- # --- Registry.open(key, subkey, desired = KEY_READ, opt = REG_OPTION_RESERVED) { |reg| ... }
- #
- # Open the registry key subkey under key.
- # key is Win32::Registry object of parent key.
- # You can use predefined key HKEY_* (see Constants)
- # desired and opt is access mask and key option.
- # For detail, see the MSDN[http://msdn.microsoft.com/library/en-us/sysinfo/base/regopenkeyex.asp].
- # If block is given, the key is closed automatically.
- def self.open(hkey, subkey, desired = KEY_READ, opt = REG_OPTION_RESERVED)
- subkey = subkey.chomp('\\')
- newkey = API.OpenKey(hkey.instance_variable_get(:@hkey), subkey, opt, desired)
- obj = new(newkey, hkey, subkey, REG_OPENED_EXISTING_KEY)
- if block_given?
- begin
- yield obj
- ensure
- obj.close
- end
- else
- obj
- end
- end
-
- #
- # --- Registry.create(key, subkey, desired = KEY_ALL_ACCESS, opt = REG_OPTION_RESERVED)
- #
- # --- Registry.create(key, subkey, desired = KEY_ALL_ACCESS, opt = REG_OPTION_RESERVED) { |reg| ... }
- #
- # Create or open the registry key subkey under key.
- # You can use predefined key HKEY_* (see Constants)
- #
- # If subkey is already exists, key is opened and Registry#created?
- # method will return false.
- #
- # If block is given, the key is closed automatically.
- #
- def self.create(hkey, subkey, desired = KEY_ALL_ACCESS, opt = REG_OPTION_RESERVED)
- newkey, disp = API.CreateKey(hkey.instance_variable_get(:@hkey), subkey, opt, desired)
- obj = new(newkey, hkey, subkey, disp)
- if block_given?
- begin
- yield obj
- ensure
- obj.close
- end
- else
- obj
- end
- end
-
- #
- # finalizer
- #
- @@final = proc { |hkey| proc { API.CloseKey(hkey[0]) if hkey[0] } }
-
- #
- # initialize
- #
- def initialize(hkey, parent, keyname, disposition)
- @hkey = Fiddle::Pointer.new(hkey)
- @parent = parent
- @keyname = keyname
- @disposition = disposition
- @hkeyfinal = [ hkey ]
- ObjectSpace.define_finalizer self, @@final.call(@hkeyfinal)
- end
-
- # Win32::Registry object of parent key, or nil if predefined key.
- attr_reader :parent
- # Same as subkey value of Registry.open or
- # Registry.create method.
- attr_reader :keyname
- # Disposition value (REG_CREATED_NEW_KEY or REG_OPENED_EXISTING_KEY).
- attr_reader :disposition
-
- # Returns key handle value.
- def hkey
- @hkey.to_i
- end
-
- #
- # Returns if key is created ((*newly*)).
- # (see Registry.create) -- basically you call create
- # then when you call created? on the instance returned
- # it will tell if it was successful or not
- #
- def created?
- @disposition == REG_CREATED_NEW_KEY
- end
-
- #
- # Returns if key is not closed.
- #
- def open?
- !@hkey.nil?
- end
-
- #
- # Full path of key such as 'HKEY_CURRENT_USER\SOFTWARE\foo\bar'.
- #
- def name
- parent = self
- name = @keyname
- while parent = parent.parent
- name = parent.keyname + '\\' + name
- end
- name
- end
-
- def inspect
- "\#<Win32::Registry key=#{name.inspect}>"
- end
-
- #
- # marshalling is not allowed
- #
- def _dump(depth)
- raise TypeError, "can't dump Win32::Registry"
- end
-
- #
- # Same as Win32::Registry.open (self, subkey, desired, opt)
- #
- def open(subkey, desired = KEY_READ, opt = REG_OPTION_RESERVED, &blk)
- self.class.open(self, subkey, desired, opt, &blk)
- end
-
- #
- # Same as Win32::Registry.create (self, subkey, desired, opt)
- #
- def create(subkey, desired = KEY_ALL_ACCESS, opt = REG_OPTION_RESERVED, &blk)
- self.class.create(self, subkey, desired, opt, &blk)
- end
-
- #
- # Close key.
- #
- # After close, most method raise an error.
- #
- def close
- API.CloseKey(@hkey)
- @hkey = @parent = @keyname = nil
- @hkeyfinal[0] = nil
- end
-
- #
- # Enumerate all values in this registry path.
- #
- # For each value it yields key, type and data.
- #
- # key is a String which contains name of key.
- # type is a type constant kind of Win32::Registry::REG_*
- # data is the value of this key.
- #
- def each_value
- return enum_for(:each_value) unless block_given?
- index = 0
- while true
- begin
- subkey = API.EnumValue(@hkey, index)
- rescue Error
- break
- end
- subkey = export_string(subkey)
- begin
- type, data = read(subkey)
- rescue Error
- else
- yield subkey, type, data
- end
- index += 1
- end
- index
- end
- alias each each_value
-
- #
- # return values as an array
- #
- def values
- vals_ary = []
- each_value { |*, val| vals_ary << val }
- vals_ary
- end
-
- #
- # Enumerate all subkeys.
- #
- # For each subkey it yields subkey and wtime.
- #
- # subkey is String which contains name of subkey.
- # wtime is last write time as FILETIME (64-bit integer).
- # (see Registry.wtime2time)
- #
- def each_key
- return enum_for(:each_key) unless block_given?
- index = 0
- while true
- begin
- subkey, wtime = API.EnumKey(@hkey, index)
- rescue Error
- break
- end
- subkey = export_string(subkey)
- yield subkey, wtime
- index += 1
- end
- index
- end
-
- #
- # return keys as an array
- #
- def keys
- keys_ary = []
- each_key { |key,| keys_ary << key }
- keys_ary
- end
-
- # Read a registry value named name and return array of
- # [ type, data ].
- # When name is nil, the `default' value is read.
- # type is value type. (see Win32::Registry::Constants module)
- # data is value data, its class is:
- # :REG_SZ, REG_EXPAND_SZ
- # String
- # :REG_MULTI_SZ
- # Array of String
- # :REG_DWORD, REG_DWORD_BIG_ENDIAN, REG_QWORD
- # Integer
- # :REG_BINARY, REG_NONE
- # String (contains binary data)
- #
- # When rtype is specified, the value type must be included by
- # rtype array, or TypeError is raised.
- def read(name, *rtype)
- type, data = API.QueryValue(@hkey, name)
- unless rtype.empty? or rtype.include?(type)
- raise TypeError, "Type mismatch (expect [#{
- rtype.map{|t|Registry.type2name(t)}.join(', ')}] but #{
- Registry.type2name(type)} present)"
- end
- case type
- when REG_SZ, REG_EXPAND_SZ
- [ type, data.encode(name.encoding, WCHAR).chop ]
- when REG_MULTI_SZ
- [ type, data.encode(name.encoding, WCHAR).split(/\0/) ]
- when REG_BINARY, REG_NONE
- [ type, data ]
- when REG_DWORD
- [ type, API.unpackdw(data) ]
- when REG_DWORD_BIG_ENDIAN
- [ type, data.unpack1('N') ]
- when REG_QWORD
- [ type, API.unpackqw(data) ]
- else
- raise TypeError, "Type #{Registry.type2name(type)} is not supported."
- end
- end
-
- #
- # Read a registry value named name and return its value data.
- # The class of the value is the same as the #read method returns.
- #
- # If the value type is REG_EXPAND_SZ, returns value data whose environment
- # variables are replaced.
- # If the value type is neither REG_SZ, REG_MULTI_SZ, REG_DWORD,
- # REG_DWORD_BIG_ENDIAN, nor REG_QWORD, TypeError is raised.
- #
- # The meaning of rtype is the same as for the #read method.
- #
- def [](name, *rtype)
- type, data = read(name, *rtype)
- case type
- when REG_SZ, REG_DWORD, REG_QWORD, REG_MULTI_SZ
- data
- when REG_EXPAND_SZ
- Registry.expand_environ(data)
- else
- raise TypeError, "Type #{Registry.type2name(type)} is not supported."
- end
- end
-
- # Read a REG_SZ(read_s), REG_DWORD(read_i), or REG_BINARY(read_bin)
- # registry value named name.
- #
- # If the values type does not match, TypeError is raised.
- def read_s(name)
- read(name, REG_SZ)[1]
- end
-
- #
- # Read a REG_SZ or REG_EXPAND_SZ registry value named name.
- #
- # If the value type is REG_EXPAND_SZ, environment variables are replaced.
- # Unless the value type is REG_SZ or REG_EXPAND_SZ, TypeError is raised.
- #
- def read_s_expand(name)
- type, data = read(name, REG_SZ, REG_EXPAND_SZ)
- if type == REG_EXPAND_SZ
- Registry.expand_environ(data)
- else
- data
- end
- end
-
- #
- # Read a REG_SZ(read_s), REG_DWORD(read_i), or REG_BINARY(read_bin)
- # registry value named name.
- #
- # If the values type does not match, TypeError is raised.
- #
- def read_i(name)
- read(name, REG_DWORD, REG_DWORD_BIG_ENDIAN, REG_QWORD)[1]
- end
-
- #
- # Read a REG_SZ(read_s), REG_DWORD(read_i), or REG_BINARY(read_bin)
- # registry value named name.
- #
- # If the values type does not match, TypeError is raised.
- #
- def read_bin(name)
- read(name, REG_BINARY)[1]
- end
-
- #
- # Write data to a registry value named name.
- # When name is nil, write to the `default' value.
- #
- # type is type value. (see Registry::Constants module)
- # Class of data must be same as which #read
- # method returns.
- #
- def write(name, type, data)
- case type
- when REG_SZ, REG_EXPAND_SZ
- data = data.encode(WCHAR) << WCHAR_NUL
- when REG_MULTI_SZ
- data = data.to_a.map {|s| s.encode(WCHAR)}.join(WCHAR_NUL) << WCHAR_NUL
- when REG_BINARY, REG_NONE
- data = data.to_s
- when REG_DWORD
- data = API.packdw(data.to_i)
- when REG_DWORD_BIG_ENDIAN
- data = [data.to_i].pack('N')
- when REG_QWORD
- data = API.packqw(data.to_i)
- else
- raise TypeError, "Unsupported type #{Registry.type2name(type)}"
- end
- API.SetValue(@hkey, name, type, data, data.bytesize)
- end
-
- #
- # Write value to a registry value named name.
- #
- # If wtype is specified, the value type is it.
- # Otherwise, the value type is depend on class of value:
- # :Integer
- # REG_DWORD
- # :String
- # REG_SZ
- # :Array
- # REG_MULTI_SZ
- #
- def []=(name, rtype, value = nil)
- if value
- write name, rtype, value
- else
- case value = rtype
- when Integer
- write name, REG_DWORD, value
- when String
- write name, REG_SZ, value
- when Array
- write name, REG_MULTI_SZ, value
- else
- raise TypeError, "Unexpected type #{value.class}"
- end
- end
- value
- end
-
- #
- # Write value to a registry value named name.
- #
- # The value type is REG_SZ(write_s), REG_DWORD(write_i), or
- # REG_BINARY(write_bin).
- #
- def write_s(name, value)
- write name, REG_SZ, value.to_s
- end
-
- #
- # Write value to a registry value named name.
- #
- # The value type is REG_SZ(write_s), REG_DWORD(write_i), or
- # REG_BINARY(write_bin).
- #
- def write_i(name, value)
- write name, REG_DWORD, value.to_i
- end
-
- #
- # Write value to a registry value named name.
- #
- # The value type is REG_SZ(write_s), REG_DWORD(write_i), or
- # REG_BINARY(write_bin).
- #
- def write_bin(name, value)
- write name, REG_BINARY, value.to_s
- end
-
- #
- # Delete a registry value named name.
- # We can not delete the `default' value.
- #
- def delete_value(name)
- API.DeleteValue(@hkey, name)
- end
- alias delete delete_value
-
- #
- # Delete a subkey named name and all its values.
- #
- # If recursive is false, the subkey must not have subkeys.
- # Otherwise, this method deletes all subkeys and values recursively.
- #
- def delete_key(name, recursive = false)
- if recursive
- open(name, KEY_ALL_ACCESS) do |reg|
- reg.keys.each do |key|
- begin
- reg.delete_key(key, true)
- rescue Error
- #
- end
- end
- end
- API.DeleteKey(@hkey, name)
- else
- begin
- API.EnumKey @hkey, 0
- rescue Error
- return API.DeleteKey(@hkey, name)
- end
- raise Error.new(5) ## ERROR_ACCESS_DENIED
- end
- end
-
- #
- # Write all the attributes into the registry file.
- #
- def flush
- API.FlushKey @hkey
- end
-
- #
- # Returns key information as Array of:
- # :num_keys
- # The number of subkeys.
- # :max_key_length
- # Maximum length of name of subkeys.
- # :num_values
- # The number of values.
- # :max_value_name_length
- # Maximum length of name of values.
- # :max_value_length
- # Maximum length of value of values.
- # :descriptor_length
- # Length of security descriptor.
- # :wtime
- # Last write time as FILETIME(64-bit integer)
- #
- # For detail, see RegQueryInfoKey[http://msdn.microsoft.com/library/en-us/sysinfo/base/regqueryinfokey.asp] Win32 API.
- #
- def info
- API.QueryInfoKey(@hkey)
- end
-
- #
- # Returns an item of key information.
- #
- %w[
- num_keys max_key_length
- num_values max_value_name_length max_value_length
- descriptor_length wtime
- ].each_with_index do |s, i|
- eval <<-__END__
- def #{s}
- info[#{i}]
- end
- __END__
- end
-
- private
-
- def export_string(str, enc = Encoding.default_internal || LOCALE) # :nodoc:
- str.encode(enc)
- end
- end
-end
diff --git a/ext/win32/lib/win32/resolv.rb b/ext/win32/lib/win32/resolv.rb
index 67762da375..08fed08563 100644
--- a/ext/win32/lib/win32/resolv.rb
+++ b/ext/win32/lib/win32/resolv.rb
@@ -4,8 +4,24 @@
=end
+require 'win32/resolv.so'
+
+# Generic namespace for Windows platform-specific features.
module Win32
- module Resolv
+ module Resolv # :nodoc:
+ # Error at Win32 API
+ class Error < StandardError
+ # +code+ Win32 Error code
+ # +message+ Formatted message for +code+
+ def initialize(code, message)
+ super(message)
+ @code = code
+ end
+
+ # Win32 error code
+ attr_reader :code
+ end
+
def self.get_hosts_path
path = get_hosts_dir
path = File.expand_path('hosts', path)
@@ -29,115 +45,62 @@ module Win32
end
[ search, nameserver ]
end
- end
-end
-
-begin
- require 'win32/resolv.so'
-rescue LoadError
-end
-
-module Win32
-#====================================================================
-# Windows NT
-#====================================================================
- module Resolv
- begin
- require 'win32/registry'
- module SZ
- refine Registry do
- # ad hoc workaround for broken registry
- def read_s(key)
- type, str = read(key)
- unless type == Registry::REG_SZ
- warn "Broken registry, #{name}\\#{key} was #{Registry.type2name(type)}, ignored"
- return String.new
- end
- str
- end
- end
- end
- using SZ
- rescue LoadError
- require "open3"
- end
-
- TCPIP_NT = 'SYSTEM\CurrentControlSet\Services\Tcpip\Parameters'
class << self
private
def get_hosts_dir
- get_item_property(TCPIP_NT, 'DataBasePath', expand: true)
+ tcpip_params do |params|
+ params.value('DataBasePath')
+ end
end
def get_info
search = nil
nameserver = get_dns_server_list
- slist = get_item_property(TCPIP_NT, 'SearchList')
- search = slist.split(/,\s*/) unless slist.empty?
+ tcpip_params do |params|
+ slist = params.value('SearchList')
+ search = slist.split(/,\s*/) if slist and !slist.empty?
- if add_search = search.nil?
- search = []
- nvdom = get_item_property(TCPIP_NT, 'NV Domain')
+ if add_search = search.nil?
+ search = []
+ domain = params.value('Domain')
- unless nvdom.empty?
- @search = [ nvdom ]
- udmnd = get_item_property(TCPIP_NT, 'UseDomainNameDevolution').to_i
- if udmnd != 0
- if /^\w+\./ =~ nvdom
- devo = $'
+ if domain and !domain.empty?
+ search = [ domain ]
+ udmnd = params.value('UseDomainNameDevolution')
+ if udmnd&.nonzero?
+ if /^\w+\./ =~ domain
+ devo = $'
+ end
end
end
end
- end
- ifs = if defined?(Win32::Registry)
- Registry::HKEY_LOCAL_MACHINE.open(TCPIP_NT + '\Interfaces') do |reg|
- reg.keys
- rescue Registry::Error
- []
- end
- else
- cmd = "Get-ChildItem 'HKLM:\\#{TCPIP_NT}\\Interfaces' | ForEach-Object { $_.PSChildName }"
- output, _ = Open3.capture2('powershell', '-Command', cmd)
- output.split(/\n+/)
+ params.open('Interfaces') do |reg|
+ reg.each_key do |iface|
+ next unless ns = %w[NameServer DhcpNameServer].find do |key|
+ ns = iface.value(key)
+ break ns.split(/[,\s]\s*/) if ns and !ns.empty?
end
- ifs.each do |iface|
- next unless ns = %w[NameServer DhcpNameServer].find do |key|
- ns = get_item_property(TCPIP_NT + '\Interfaces' + "\\#{iface}", key)
- break ns.split(/[,\s]\s*/) unless ns.empty?
- end
-
- next if (nameserver & ns).empty?
+ next if (nameserver & ns).empty?
- if add_search
- [ 'Domain', 'DhcpDomain' ].each do |key|
- dom = get_item_property(TCPIP_NT + '\Interfaces' + "\\#{iface}", key)
- unless dom.empty?
- search.concat(dom.split(/,\s*/))
- break
+ if add_search
+ [ 'Domain', 'DhcpDomain' ].each do |key|
+ dom = iface.value(key)
+ if dom and !dom.empty?
+ search.concat(dom.split(/,\s*/))
+ break
+ end
+ end
end
end
end
- end
- search << devo if add_search and devo
- [ search.uniq, nameserver.uniq ]
- end
- def get_item_property(path, name, expand: false)
- if defined?(Win32::Registry)
- Registry::HKEY_LOCAL_MACHINE.open(path) do |reg|
- expand ? reg.read_s_expand(name) : reg.read_s(name)
- rescue Registry::Error
- ""
- end
- else
- cmd = "Get-ItemProperty -Path 'HKLM:\\#{path}' -Name '#{name}' -ErrorAction SilentlyContinue | Select-Object -ExpandProperty '#{name}'"
- output, _ = Open3.capture2('powershell', '-Command', cmd)
- output.strip
+ search << devo if add_search and devo
end
+ [ search.uniq, nameserver.uniq ]
end
end
end
diff --git a/ext/win32/resolv/extconf.rb b/ext/win32/resolv/extconf.rb
index a5f8cc279d..5ee4c0d7c4 100644
--- a/ext/win32/resolv/extconf.rb
+++ b/ext/win32/resolv/extconf.rb
@@ -1,5 +1,6 @@
require 'mkmf'
if RUBY_ENGINE == "ruby" and have_library('iphlpapi', 'GetNetworkParams', ['windows.h', 'iphlpapi.h'])
+ have_library('advapi32', 'RegGetValueW', ['windows.h'])
create_makefile('win32/resolv')
else
File.write('Makefile', "all clean install:\n\t@echo Done: $(@)\n")
diff --git a/ext/win32/resolv/resolv.c b/ext/win32/resolv/resolv.c
index af678e1f17..9150df5dc1 100644
--- a/ext/win32/resolv/resolv.c
+++ b/ext/win32/resolv/resolv.c
@@ -1,26 +1,59 @@
#include <ruby.h>
#include <ruby/encoding.h>
#include <windows.h>
+#include <windns.h>
#ifndef NTDDI_VERSION
#define NTDDI_VERSION 0x06000000
#endif
#include <iphlpapi.h>
+#ifndef numberof
+#define numberof(array) ((int)(sizeof(array) / sizeof((array)[0])))
+#endif
+
static VALUE
w32error_make_error(DWORD e)
{
- VALUE code = ULONG2NUM(e);
- return rb_class_new_instance(1, &code, rb_path2class("Win32::Resolv::Error"));
+ char buffer[512], *p;
+ DWORD source = 0;
+ VALUE args[2];
+ if (!FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS, &source, e,
+ MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),
+ buffer, sizeof(buffer), NULL)) {
+ snprintf(buffer, sizeof(buffer), "Unknown Error %lu", (unsigned long)e);
+ }
+ p = buffer;
+ while ((p = strpbrk(p, "\r\n")) != NULL) {
+ memmove(p, p + 1, strlen(p));
+ if (!p[1]) {
+ p[0] = '\0';
+ break;
+ }
+ }
+ args[0] = ULONG2NUM(e);
+ args[1] = rb_str_new_cstr(buffer);
+ return rb_class_new_instance(2, args, rb_path2class("Win32::Resolv::Error"));
}
-NORETURN(static void w32error_raise(DWORD e));
-
static void
-w32error_raise(DWORD e)
+w32error_check(DWORD e)
+{
+ if (e != NO_ERROR) {
+ rb_exc_raise(w32error_make_error(e));
+ }
+}
+
+static VALUE
+wchar_to_utf8(const WCHAR *w, int n)
{
- rb_exc_raise(w32error_make_error(e));
+ int clen = WideCharToMultiByte(CP_UTF8, 0, w, n, NULL, 0, NULL, NULL);
+ VALUE str = rb_enc_str_new(NULL, clen, rb_utf8_encoding());
+ WideCharToMultiByte(CP_UTF8, 0, w, n, RSTRING_PTR(str), clen, NULL, NULL);
+ return str;
}
+/* :nodoc: */
static VALUE
get_dns_server_list(VALUE self)
{
@@ -30,9 +63,7 @@ get_dns_server_list(VALUE self)
VALUE buf, nameservers = Qnil;
ret = GetNetworkParams(NULL, &buflen);
- if (ret != NO_ERROR && ret != ERROR_BUFFER_OVERFLOW) {
- w32error_raise(ret);
- }
+ if (ret != ERROR_BUFFER_OVERFLOW) w32error_check(ret);
fixedinfo = ALLOCV(buf, buflen);
ret = GetNetworkParams(fixedinfo, &buflen);
if (ret == NO_ERROR) {
@@ -46,18 +77,181 @@ get_dns_server_list(VALUE self)
} while ((ipaddr = ipaddr->Next) != NULL);
}
ALLOCV_END(buf);
- if (ret != NO_ERROR) w32error_raise(ret);
+ w32error_check(ret);
return nameservers;
}
+static const WCHAR TCPIP_Params[] = L"SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters";
+
+static void
+hkey_finalize(void *p)
+{
+ RegCloseKey((HKEY)p);
+}
+
+static const rb_data_type_t hkey_type = {
+ "RegKey",
+ {0, hkey_finalize},
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY,
+};
+
+static VALUE
+hkey_close(VALUE self)
+{
+ RegCloseKey((HKEY)DATA_PTR(self));
+ DATA_PTR(self) = 0;
+ return self;
+}
+
+static VALUE reg_key_class;
+
+static VALUE
+reg_open_key(VALUE klass, HKEY hkey, const WCHAR *wname)
+{
+ VALUE k = TypedData_Wrap_Struct(klass, &hkey_type, NULL);
+ DWORD e = RegOpenKeyExW(hkey, wname, 0, KEY_READ, (HKEY *)&DATA_PTR(k));
+ if (e == ERROR_FILE_NOT_FOUND) return Qnil;
+ w32error_check(e);
+ return rb_ensure(rb_yield, k, hkey_close, k);
+}
+
+/* :nodoc: */
+static VALUE
+tcpip_params_open(VALUE klass)
+{
+ return reg_open_key(reg_key_class, HKEY_LOCAL_MACHINE, TCPIP_Params);
+}
+
+static int
+to_wname(VALUE *name, WCHAR *wname, int wlen)
+{
+ const char *n = StringValueCStr(*name);
+ int nlen = RSTRING_LEN(*name);
+ int len = MultiByteToWideChar(CP_UTF8, 0, n, nlen, wname, wlen - 1);
+ if (len == 0) w32error_check(GetLastError());
+ if (len >= wlen) rb_raise(rb_eArgError, "too long name");
+ wname[len] = L'\0';
+ return len;
+}
+
+static VALUE
+reg_open(VALUE self, VALUE name)
+{
+ HKEY hkey = DATA_PTR(self);
+ WCHAR wname[256];
+ to_wname(&name, wname, numberof(wname));
+ return reg_open_key(CLASS_OF(self), hkey, wname);
+}
+
+
+static VALUE
+reg_each_key(VALUE self)
+{
+ WCHAR wname[256];
+ HKEY hkey = DATA_PTR(self);
+ VALUE k = TypedData_Wrap_Struct(CLASS_OF(self), &hkey_type, NULL);
+ DWORD i, e, n;
+ for (i = 0; n = numberof(wname), (e = RegEnumKeyExW(hkey, i, wname, &n, NULL, NULL, NULL, NULL)) == ERROR_SUCCESS; i++) {
+ e = RegOpenKeyExW(hkey, wname, 0, KEY_READ, (HKEY *)&DATA_PTR(k));
+ w32error_check(e);
+ rb_ensure(rb_yield, k, hkey_close, k);
+ }
+ if (e != ERROR_NO_MORE_ITEMS) w32error_check(e);
+ return self;
+}
+
+static inline DWORD
+swap_dw(DWORD x)
+{
+#if defined(_MSC_VER)
+ return _byteswap_ulong(x);
+#else
+ return __builtin_bswap32(x);
+#endif
+}
+
+static VALUE
+reg_value(VALUE self, VALUE name)
+{
+ HKEY hkey = DATA_PTR(self);
+ DWORD type = 0, size = 0, e;
+ VALUE result, value_buffer;
+ void *buffer;
+ WCHAR wname[256];
+ to_wname(&name, wname, numberof(wname));
+ e = RegGetValueW(hkey, NULL, wname, RRF_RT_ANY, &type, NULL, &size);
+ if (e == ERROR_FILE_NOT_FOUND) return Qnil;
+ w32error_check(e);
+# define get_value_2nd(data, dsize) do { \
+ DWORD type2 = type; \
+ w32error_check(RegGetValueW(hkey, NULL, wname, RRF_RT_ANY, &type2, data, dsize)); \
+ if (type != type2) { \
+ rb_raise(rb_eRuntimeError, "registry value type changed %lu -> %lu", \
+ (unsigned long)type, (unsigned long)type2); \
+ } \
+ } while (0)
+
+ switch (type) {
+ case REG_DWORD: case REG_DWORD_BIG_ENDIAN:
+ {
+ DWORD d;
+ if (size != sizeof(d)) rb_raise(rb_eRuntimeError, "invalid size returned: %lu", (unsigned long)size);
+ w32error_check(RegGetValueW(hkey, NULL, wname, RRF_RT_REG_DWORD, &type, &d, &size));
+ if (type == REG_DWORD_BIG_ENDIAN) d = swap_dw(d);
+ return ULONG2NUM(d);
+ }
+ case REG_QWORD:
+ {
+ QWORD q;
+ if (size != sizeof(q)) rb_raise(rb_eRuntimeError, "invalid size returned: %lu", (unsigned long)size);
+ w32error_check(RegGetValueW(hkey, NULL, wname, RRF_RT_REG_QWORD, &type, &q, &size));
+ return ULL2NUM(q);
+ }
+ case REG_SZ: case REG_MULTI_SZ: case REG_EXPAND_SZ:
+ if (size % sizeof(WCHAR)) rb_raise(rb_eRuntimeError, "invalid size returned: %lu", (unsigned long)size);
+ buffer = ALLOCV_N(char, value_buffer, size);
+ get_value_2nd(buffer, &size);
+ if (type == REG_MULTI_SZ) {
+ const WCHAR *w = (WCHAR *)buffer;
+ result = rb_ary_new();
+ size /= sizeof(WCHAR);
+ size -= 1;
+ for (size_t i = 0; i < size; ++i) {
+ int n = lstrlenW(w+i);
+ rb_ary_push(result, wchar_to_utf8(w+i, n));
+ i += n;
+ }
+ }
+ else {
+ result = wchar_to_utf8((WCHAR *)buffer, lstrlenW((WCHAR *)buffer));
+ }
+ ALLOCV_END(value_buffer);
+ break;
+ default:
+ result = rb_str_new(0, size);
+ get_value_2nd(RSTRING_PTR(result), &size);
+ rb_str_set_len(result, size);
+ break;
+ }
+ return result;
+}
+
void
InitVM_resolv(void)
{
VALUE mWin32 = rb_define_module("Win32");
VALUE resolv = rb_define_module_under(mWin32, "Resolv");
VALUE singl = rb_singleton_class(resolv);
+ VALUE regkey = rb_define_class_under(resolv, "registry key", rb_cObject);
+
+ reg_key_class = regkey;
+ rb_undef_alloc_func(regkey);
rb_define_private_method(singl, "get_dns_server_list", get_dns_server_list, 0);
+ rb_define_private_method(singl, "tcpip_params", tcpip_params_open, 0);
+ rb_define_method(regkey, "open", reg_open, 1);
+ rb_define_method(regkey, "each_key", reg_each_key, 0);
+ rb_define_method(regkey, "value", reg_value, 1);
}
void
diff --git a/ext/win32/win32-registry.gemspec b/ext/win32/win32-registry.gemspec
deleted file mode 100644
index d747daf458..0000000000
--- a/ext/win32/win32-registry.gemspec
+++ /dev/null
@@ -1,32 +0,0 @@
-# frozen_string_literal: true
-Gem::Specification.new do |spec|
- spec.name = "win32-registry"
- spec.version = "0.1.0"
- spec.authors = ["U.Nakamura"]
- spec.email = ["usa@garbagecollect.jp"]
-
- spec.summary = %q{Provides an interface to the Windows Registry in Ruby}
- spec.description = spec.summary
- spec.homepage = "https://github.com/ruby/win32-registry"
- spec.required_ruby_version = ">= 2.6.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.
- excludes = %w[
- bin/ test/ spec/ features/ rakelib/
- .git .github .mailmap appveyor Rakefile Gemfile
- ]
- spec.files = Dir.chdir(__dir__) do
- `git ls-files -z`.split("\x0").reject do |f|
- File.identical?(f, __FILE__) || f.start_with?(*excludes)
- end
- end
- spec.bindir = "exe"
- spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
- spec.require_paths = ["lib"]
-
- spec.add_dependency "fiddle", "~> 1.0"
-end
diff --git a/ext/zlib/zlib.c b/ext/zlib/zlib.c
index 0b9c4d65ee..481d74b2b6 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.2.1"
+#define RUBY_ZLIB_VERSION "3.2.3"
#ifndef RB_PASS_CALLED_KEYWORDS
# define rb_class_new_instance_kw(argc, argv, klass, kw_splat) rb_class_new_instance(argc, argv, klass)
@@ -860,9 +860,7 @@ zstream_buffer_ungets(struct zstream *z, const Bytef *b, unsigned long len)
char *bufptr;
long filled;
- if (NIL_P(z->buf) || (long)rb_str_capacity(z->buf) <= ZSTREAM_BUF_FILLED(z)) {
- zstream_expand_buffer_into(z, len);
- }
+ zstream_expand_buffer_into(z, len);
RSTRING_GETMEM(z->buf, bufptr, filled);
memmove(bufptr + len, bufptr, filled);
@@ -1094,8 +1092,9 @@ zstream_run_func(struct zstream_run_args *args)
break;
}
- if (err != Z_OK && err != Z_BUF_ERROR)
+ if (err != Z_OK && err != Z_BUF_ERROR) {
break;
+ }
if (z->stream.avail_out > 0) {
z->flags |= ZSTREAM_FLAG_IN_STREAM;
@@ -1170,12 +1169,17 @@ loop:
/* retry if no exception is thrown */
if (err == Z_OK && args->interrupt) {
args->interrupt = 0;
- goto loop;
+
+ /* Retry only if both avail_in > 0 (more input to process) and avail_out > 0
+ * (output buffer has space). If avail_out == 0, the buffer is full and should
+ * be consumed by the caller first. If avail_in == 0, there's nothing more to process. */
+ if (z->stream.avail_in > 0 && z->stream.avail_out > 0) {
+ goto loop;
+ }
}
- if (flush != Z_FINISH && err == Z_BUF_ERROR
- && z->stream.avail_out > 0) {
- z->flags |= ZSTREAM_FLAG_IN_STREAM;
+ if (flush != Z_FINISH && err == Z_BUF_ERROR && z->stream.avail_out > 0) {
+ z->flags |= ZSTREAM_FLAG_IN_STREAM;
}
zstream_reset_input(z);
@@ -1456,6 +1460,7 @@ rb_zstream_finish(VALUE obj)
* call-seq:
* flush_next_in -> input
*
+ * Flushes input buffer and returns all data in that buffer.
*/
static VALUE
rb_zstream_flush_next_in(VALUE obj)
@@ -2444,17 +2449,16 @@ struct gzfile {
#define GZFILE_READ_SIZE 2048
+enum { read_raw_arg_len, read_raw_arg_buf, read_raw_arg__count};
struct read_raw_arg {
VALUE io;
- union {
- const VALUE argv[2]; /* for rb_funcallv */
- struct {
- VALUE len;
- VALUE buf;
- } in;
- } as;
+ const VALUE argv[read_raw_arg__count]; /* for rb_funcallv */
};
+#define read_raw_arg_argc(ra) \
+ ((int)read_raw_arg__count - NIL_P((ra)->argv[read_raw_arg__count - 1]))
+#define read_raw_arg_init(io, len, buf) { io, { len, buf } }
+
static void
gzfile_mark(void *p)
{
@@ -2580,9 +2584,9 @@ gzfile_read_raw_partial(VALUE arg)
{
struct read_raw_arg *ra = (struct read_raw_arg *)arg;
VALUE str;
- int argc = NIL_P(ra->as.argv[1]) ? 1 : 2;
+ int argc = read_raw_arg_argc(ra);
- str = rb_funcallv(ra->io, id_readpartial, argc, ra->as.argv);
+ str = rb_funcallv(ra->io, id_readpartial, argc, ra->argv);
Check_Type(str, T_STRING);
return str;
}
@@ -2593,8 +2597,8 @@ gzfile_read_raw_rescue(VALUE arg, VALUE _)
struct read_raw_arg *ra = (struct read_raw_arg *)arg;
VALUE str = Qnil;
if (rb_obj_is_kind_of(rb_errinfo(), rb_eNoMethodError)) {
- int argc = NIL_P(ra->as.argv[1]) ? 1 : 2;
- str = rb_funcallv(ra->io, id_read, argc, ra->as.argv);
+ int argc = read_raw_arg_argc(ra);
+ str = rb_funcallv(ra->io, id_read, argc, ra->argv);
if (!NIL_P(str)) {
Check_Type(str, T_STRING);
}
@@ -2605,11 +2609,8 @@ gzfile_read_raw_rescue(VALUE arg, VALUE _)
static VALUE
gzfile_read_raw(struct gzfile *gz, VALUE outbuf)
{
- struct read_raw_arg ra;
-
- ra.io = gz->io;
- ra.as.in.len = INT2FIX(GZFILE_READ_SIZE);
- ra.as.in.buf = outbuf;
+ struct read_raw_arg ra =
+ read_raw_arg_init(gz->io, INT2FIX(GZFILE_READ_SIZE), outbuf);
return rb_rescue2(gzfile_read_raw_partial, (VALUE)&ra,
gzfile_read_raw_rescue, (VALUE)&ra,
diff --git a/ext/zlib/zlib.gemspec b/ext/zlib/zlib.gemspec
index 345dc5f225..ba7114476f 100644
--- a/ext/zlib/zlib.gemspec
+++ b/ext/zlib/zlib.gemspec
@@ -27,5 +27,5 @@ Gem::Specification.new do |spec|
spec.executables = []
spec.require_paths = ["lib"]
spec.extensions = "ext/zlib/extconf.rb"
- spec.required_ruby_version = ">= 2.5.0"
+ spec.required_ruby_version = ">= 2.7.0"
end
diff --git a/file.c b/file.c
index 3d8c800429..fffd09c22e 100644
--- a/file.c
+++ b/file.c
@@ -169,6 +169,7 @@ typedef struct timespec stat_timestamp;
#include "internal.h"
#include "internal/compilers.h"
#include "internal/dir.h"
+#include "internal/encoding.h"
#include "internal/error.h"
#include "internal/file.h"
#include "internal/io.h"
@@ -213,15 +214,16 @@ file_path_convert(VALUE name)
return name;
}
-static rb_encoding *
+static void
check_path_encoding(VALUE str)
{
- rb_encoding *enc = rb_enc_get(str);
- if (!rb_enc_asciicompat(enc)) {
- rb_raise(rb_eEncCompatError, "path name must be ASCII-compatible (%s): %"PRIsVALUE,
- rb_enc_name(enc), rb_str_inspect(str));
+ if (RB_UNLIKELY(!rb_str_enc_fastpath(str))) {
+ rb_encoding *enc = rb_str_enc_get(str);
+ if (!rb_enc_asciicompat(enc)) {
+ rb_raise(rb_eEncCompatError, "path name must be ASCII-compatible (%s): %"PRIsVALUE,
+ rb_enc_name(enc), rb_str_inspect(str));
+ }
}
- return enc;
}
VALUE
@@ -243,13 +245,20 @@ VALUE
rb_get_path_check_convert(VALUE obj)
{
obj = file_path_convert(obj);
+ rb_get_path_check_no_convert(obj);
+ return rb_str_new_frozen(obj);
+}
+/* TODO: name */
+VALUE
+rb_get_path_check_no_convert(VALUE obj)
+{
check_path_encoding(obj);
if (!rb_str_to_cstr(obj)) {
rb_raise(rb_eArgError, "path name contains null byte");
}
- return rb_str_new4(obj);
+ return obj;
}
VALUE
@@ -264,6 +273,19 @@ rb_get_path(VALUE obj)
return rb_get_path_check_convert(rb_get_path_check_to_string(obj));
}
+static inline VALUE
+check_path(VALUE obj, const char **cstr)
+{
+ VALUE str = rb_get_path_check_convert(rb_get_path_check_to_string(obj));
+#if RUBY_DEBUG
+ str = rb_str_new_frozen(str);
+#endif
+ *cstr = RSTRING_PTR(str);
+ return str;
+}
+
+#define CheckPath(str, cstr) RB_GC_GUARD(str) = check_path(str, &cstr);
+
VALUE
rb_str_encode_ospath(VALUE path)
{
@@ -365,9 +387,15 @@ rb_str_normalize_ospath(const char *ptr, long len)
const char *p = ptr;
const char *e = ptr + len;
const char *p1 = p;
- VALUE str = rb_str_buf_new(len);
rb_encoding *enc = rb_utf8_encoding();
- rb_enc_associate(str, enc);
+ VALUE str = rb_utf8_str_new(ptr, len);
+ if (RB_LIKELY(rb_enc_str_coderange(str) == ENC_CODERANGE_7BIT)) {
+ return str;
+ }
+ else {
+ str = rb_str_buf_new(len);
+ rb_enc_associate(str, enc);
+ }
while (p < e) {
int l, c;
@@ -605,17 +633,31 @@ statx_mtimespec(const rb_io_stat_data *st)
/*
* call-seq:
- * stat <=> other_stat -> -1, 0, 1, nil
+ * self <=> other -> -1, 0, 1, or nil
+ *
+ * Compares +self+ and +other+, by comparing their modification times;
+ * that is, by comparing <tt>self.mtime</tt> and <tt>other.mtime</tt>.
*
- * Compares File::Stat objects by comparing their respective modification
- * times.
+ * Returns:
*
- * +nil+ is returned if +other_stat+ is not a File::Stat object
+ * - +-1+, if <tt>self.mtime</tt> is earlier.
+ * - +0+, if the two values are equal.
+ * - +1+, if <tt>self.mtime</tt> is later.
+ * - +nil+, if +other+ is not a File::Stat object.
*
- * f1 = File.new("f1", "w")
- * sleep 1
- * f2 = File.new("f2", "w")
- * f1.stat <=> f2.stat #=> -1
+ * Examples:
+ *
+ * stat0 = File.stat('README.md')
+ * stat1 = File.stat('NEWS.md')
+ * stat0.mtime # => 2025-12-20 15:33:05.6972341 -0600
+ * stat1.mtime # => 2025-12-20 16:02:08.2672945 -0600
+ * stat0 <=> stat1 # => -1
+ * stat0 <=> stat0.dup # => 0
+ * stat1 <=> stat0 # => 1
+ * stat0 <=> :foo # => nil
+ *
+ * \Class \File::Stat includes module Comparable,
+ * each of whose methods uses File::Stat#<=> for comparison.
*/
static VALUE
@@ -1066,13 +1108,28 @@ static VALUE statx_birthtime(const rb_io_stat_data *st);
/*
* call-seq:
- * stat.atime -> time
- *
- * Returns the last access time for this file as an object of class
- * Time.
- *
- * File.stat("testfile").atime #=> Wed Dec 31 18:00:00 CST 1969
- *
+ * atime -> new_time
+ *
+ * Returns a new Time object containing the access time
+ * of the object represented by +self+
+ * at the time +self+ was created;
+ * see {Snapshot}[rdoc-ref:File::Stat@Snapshot]:
+ *
+ * filepath = 't.tmp'
+ * File.write(filepath, 'foo')
+ * file = File.new(filepath, 'w')
+ * stat = File::Stat.new(filepath)
+ * file.atime # => 2026-03-31 16:26:39.5913207 -0500
+ * stat.atime # => 2026-03-31 16:26:39.5913207 -0500
+ * File.write(filepath, 'bar')
+ * file.atime # => 2026-03-31 16:27:01.4981624 -0500 # Changed by access.
+ * stat.atime # => 2026-03-31 16:26:39.5913207 -0500 # Unchanged by access.
+ * stat = File::Stat.new(filepath)
+ * stat.atime # => 2026-03-31 16:27:01.4981624 -0500 # New access time.
+ * file.close
+ * File.delete(filepath)
+ *
+ * See {File System Timestamps}[rdoc-ref:file/timestamps.md].
*/
static VALUE
@@ -1120,24 +1177,22 @@ rb_stat_ctime(VALUE self)
#if defined(HAVE_STAT_BIRTHTIME)
/*
* call-seq:
- * stat.birthtime -> time
- *
- * Returns the birth time for <i>stat</i>.
- *
- * If the platform doesn't have birthtime, raises NotImplementedError.
- *
- * File.write("testfile", "foo")
- * sleep 10
- * File.write("testfile", "bar")
- * sleep 10
- * File.chmod(0644, "testfile")
- * sleep 10
- * File.read("testfile")
- * File.stat("testfile").birthtime #=> 2014-02-24 11:19:17 +0900
- * File.stat("testfile").mtime #=> 2014-02-24 11:19:27 +0900
- * File.stat("testfile").ctime #=> 2014-02-24 11:19:37 +0900
- * File.stat("testfile").atime #=> 2014-02-24 11:19:47 +0900
- *
+ * birthtime -> new_time
+ *
+ * Returns a new Time object containing the create time
+ * of the object represented by +self+
+ * at the time +self+ was created;
+ * see {Snapshot}[rdoc-ref:File::Stat@Snapshot]:
+ *
+ * filename = 't.tmp'
+ * stat = File::Stat.new(filename) # Raises Errno::ENOENT: No such file or directory
+ * File.write(filename, 'foo')
+ * stat = File::Stat.new(filename)
+ * stat.birthtime # => 2026-04-14 10:41:55.5146554 -0500
+ * File.delete(filename)
+ * stat.birthtime # => 2026-04-14 10:41:55.5146554 -0500
+ *
+ * See {File System Timestamps}[rdoc-ref:file/timestamps.md].
*/
static VALUE
@@ -2172,7 +2227,7 @@ rb_file_size_p(VALUE obj, VALUE fname)
* File.owned?(file_name) -> true or false
*
* Returns <code>true</code> if the named file exists and the
- * effective used id of the calling process is the owner of
+ * effective user id of the calling process is the owner of
* the file.
*
* _file_name_ can be an IO object.
@@ -2383,7 +2438,7 @@ rb_file_ftype(mode_t mode)
t = "unknown";
}
- return rb_usascii_str_new2(t);
+ return rb_fstring_cstr(t);
}
/*
@@ -2417,14 +2472,25 @@ rb_file_s_ftype(VALUE klass, VALUE fname)
/*
* call-seq:
- * File.atime(file_name) -> time
+ * File.atime(object) -> new_time
*
- * Returns the last access time for the named file as a Time object.
+ * Returns a new Time object containing the time of the most recent
+ * access (read or write) to the object,
+ * which may be a string filepath or dirpath, or a File or Dir object:
*
- * _file_name_ can be an IO object.
+ * filepath = 't.tmp'
+ * File.exist?(filepath) # => false
+ * File.atime(filepath) # Raises Errno::ENOENT.
+ * File.write(filepath, 'foo')
+ * File.atime(filepath) # => 2026-03-31 16:39:37.9290772 -0500
+ * File.write(filepath, 'bar')
+ * File.atime(filepath) # => 2026-03-31 16:39:57.7710876 -0500
*
- * File.atime("testfile") #=> Wed Apr 09 08:51:48 CDT 2003
+ * File.atime('.') # => 2026-03-31 16:47:49.0970483 -0500
+ * File.atime(File.new('README.md')) # => 2026-03-31 11:15:27.8215934 -0500
+ * File.atime(Dir.new('.')) # => 2026-03-31 12:39:45.5910591 -0500
*
+ * See {File System Timestamps}[rdoc-ref:file/timestamps.md].
*/
static VALUE
@@ -2442,13 +2508,22 @@ rb_file_s_atime(VALUE klass, VALUE fname)
/*
* call-seq:
- * file.atime -> time
- *
- * Returns the last access time (a Time object) for <i>file</i>, or
- * epoch if <i>file</i> has not been accessed.
- *
- * File.new("testfile").atime #=> Wed Dec 31 18:00:00 CST 1969
- *
+ * atime -> new_time
+ *
+ * Returns a new Time object containing the time of the most recent
+ * access (read or write) to the file represented by +self+:
+ *
+ * filepath = 't.tmp'
+ * file = File.new(filepath, 'a+')
+ * file.atime # => 2026-03-31 17:11:27.7285397 -0500
+ * file.write('foo')
+ * file.atime # => 2026-03-31 17:11:27.7285397 -0500 # Unchanged; not yet written.
+ * file.flush
+ * file.atime # => 2026-03-31 17:12:11.3408054 -0500 # Changed; now written.
+ * file.close
+ * File.delete(filename)
+ *
+ * See {File System Timestamps}[rdoc-ref:file/timestamps.md].
*/
static VALUE
@@ -2570,16 +2645,21 @@ rb_file_ctime(VALUE obj)
#if defined(HAVE_STAT_BIRTHTIME)
/*
* call-seq:
- * File.birthtime(file_name) -> time
+ * File.birthtime(entry_path) -> new_time
*
- * Returns the birth time for the named file.
+ * Returns a new Time object containing the create time
+ * of the entry at the given +path+:
*
- * _file_name_ can be an IO object.
- *
- * File.birthtime("testfile") #=> Wed Apr 09 08:53:13 CDT 2003
- *
- * If the platform doesn't have birthtime, raises NotImplementedError.
+ * path = 't.tmp'
+ * File.birthtime(path) # Raises Errno::ENOENT: No such file or directory
+ * File.write(path, 'foo')
+ * File.birthtime(path) # => 2026-04-14 11:10:43.2891695 -0500
+ * File.write(path, 'bar')
+ * File.birthtime(path) # => 2026-04-14 11:10:43.2891695 -0500
+ * File.delete(path)
+ * File.birthtime(path) # Raises Errno::ENOENT: No such file or directory
*
+ * See {File System Timestamps}[rdoc-ref:file/timestamps.md].
*/
VALUE
@@ -2601,14 +2681,21 @@ rb_file_s_birthtime(VALUE klass, VALUE fname)
#if defined(HAVE_STAT_BIRTHTIME)
/*
* call-seq:
- * file.birthtime -> time
+ * birthtime -> new_time
*
- * Returns the birth time for <i>file</i>.
+ * Returns a new Time object containing the create time for +self+:
*
- * File.new("testfile").birthtime #=> Wed Apr 09 08:53:14 CDT 2003
- *
- * If the platform doesn't have birthtime, raises NotImplementedError.
+ * filepath = 't.tmp'
+ * File.write(filepath, 'foo')
+ * file = File.new(filepath)
+ * file.birthtime # => 2026-04-14 15:53:45.002656 -0500
+ * File.write(filepath, 'bar')
+ * file.birthtime # => 2026-04-14 15:53:45.002656 -0500
+ * file.close
+ * File.delete(filepath)
+ * file.birthtime # Raises IOError: closed stream
*
+ * See {File System Timestamps}[rdoc-ref:file/timestamps.md].
*/
static VALUE
@@ -3396,7 +3483,7 @@ unlink_internal(const char *path, void *arg)
* Since the underlying implementation relies on the
* <code>unlink(2)</code> system call, the type of
* exception raised depends on its error type (see
- * https://linux.die.net/man/2/unlink) and has the form of
+ * https://man7.org/linux/man-pages/man2/unlink.2.html) and has the form of
* e.g. Errno::ENOENT.
*
* See also Dir::rmdir.
@@ -3542,8 +3629,10 @@ static const char file_alt_separator[] = {FILE_ALT_SEPARATOR, '\0'};
# define isADS(x) 0
#endif
-#define Next(p, e, enc) ((p) + rb_enc_mbclen((p), (e), (enc)))
-#define Inc(p, e, enc) ((p) = Next((p), (e), (enc)))
+#define enc_mbclen_needed(enc) (!rb_str_encindex_fastpath(rb_enc_to_index(enc)))
+
+#define Next(p, e, mb_enc, enc) ((p) + ((mb_enc) ? rb_enc_mbclen((p), (e), (enc)) : 1))
+#define Inc(p, e, mb_enc, enc) ((p) = Next((p), (e), (mb_enc), (enc)))
#if defined(DOSISH_UNC)
#define has_unc(buf) (isdirsep((buf)[0]) && isdirsep((buf)[1]))
@@ -3564,11 +3653,12 @@ has_drive_letter(const char *buf)
}
#ifndef _WIN32
-static char*
+static VALUE
getcwdofdrv(int drv)
{
char drive[4];
- char *drvcwd, *oldcwd;
+ char *oldcwd;
+ VALUE drvcwd;
drive[0] = drv;
drive[1] = ':';
@@ -3580,13 +3670,13 @@ getcwdofdrv(int drv)
*/
oldcwd = ruby_getcwd();
if (chdir(drive) == 0) {
- drvcwd = ruby_getcwd();
+ drvcwd = rb_dir_getwd_ospath();
chdir(oldcwd);
xfree(oldcwd);
}
else {
/* perhaps the drive is not exist. we return only drive letter */
- drvcwd = strdup(drive);
+ drvcwd = rb_enc_str_new_cstr(drive, rb_filesystem_encoding());
}
return drvcwd;
}
@@ -3607,7 +3697,7 @@ not_same_drive(VALUE path, int drive)
#endif /* DOSISH_DRIVE_LETTER */
static inline char *
-skiproot(const char *path, const char *end, rb_encoding *enc)
+skiproot(const char *path, const char *end)
{
#ifdef DOSISH_DRIVE_LETTER
if (path + 2 <= end && has_drive_letter(path)) path += 2;
@@ -3616,57 +3706,76 @@ skiproot(const char *path, const char *end, rb_encoding *enc)
return (char *)path;
}
-#define nextdirsep rb_enc_path_next
-char *
-rb_enc_path_next(const char *s, const char *e, rb_encoding *enc)
+static inline char *
+enc_path_next(const char *s, const char *e, bool mb_enc, rb_encoding *enc)
{
while (s < e && !isdirsep(*s)) {
- Inc(s, e, enc);
+ Inc(s, e, mb_enc, enc);
}
return (char *)s;
}
+#define nextdirsep rb_enc_path_next
+char *
+rb_enc_path_next(const char *s, const char *e, rb_encoding *enc)
+{
+ return enc_path_next(s, e, enc_mbclen_needed(enc), enc);
+}
+
#if defined(DOSISH_UNC) || defined(DOSISH_DRIVE_LETTER)
-#define skipprefix rb_enc_path_skip_prefix
+#define skipprefix enc_path_skip_prefix
#else
-#define skipprefix(path, end, enc) (path)
+#define skipprefix(path, end, mb_enc, enc) (path)
#endif
-char *
-rb_enc_path_skip_prefix(const char *path, const char *end, rb_encoding *enc)
+static inline char *
+enc_path_skip_prefix(const char *path, const char *end, bool mb_enc, rb_encoding *enc)
{
#if defined(DOSISH_UNC) || defined(DOSISH_DRIVE_LETTER)
#ifdef DOSISH_UNC
if (path + 2 <= end && isdirsep(path[0]) && isdirsep(path[1])) {
path += 2;
while (path < end && isdirsep(*path)) path++;
- if ((path = rb_enc_path_next(path, end, enc)) < end && path[0] && path[1] && !isdirsep(path[1]))
- path = rb_enc_path_next(path + 1, end, enc);
+ if ((path = enc_path_next(path, end, mb_enc, enc)) < end &&
+ path + 2 <= end && !isdirsep(path[1])) {
+ path = enc_path_next(path + 1, end, mb_enc, enc);
+ }
return (char *)path;
}
#endif
#ifdef DOSISH_DRIVE_LETTER
- if (has_drive_letter(path))
+ if (path + 2 <= end && has_drive_letter(path))
return (char *)(path + 2);
#endif
#endif /* defined(DOSISH_UNC) || defined(DOSISH_DRIVE_LETTER) */
return (char *)path;
}
+char *
+rb_enc_path_skip_prefix(const char *path, const char *end, rb_encoding *enc)
+{
+ return enc_path_skip_prefix(path, end, enc_mbclen_needed(enc), enc);
+}
+
static inline char *
skipprefixroot(const char *path, const char *end, rb_encoding *enc)
{
#if defined(DOSISH_UNC) || defined(DOSISH_DRIVE_LETTER)
- char *p = skipprefix(path, end, enc);
- while (isdirsep(*p)) p++;
+ char *p = skipprefix(path, end, enc_mbclen_needed(enc), enc);
+ while (p < end && isdirsep(*p)) p++;
return p;
#else
- return skiproot(path, end, enc);
+ return skiproot(path, end);
#endif
}
-#define strrdirsep rb_enc_path_last_separator
char *
-rb_enc_path_last_separator(const char *path, const char *end, rb_encoding *enc)
+rb_enc_path_skip_prefix_root(const char *path, const char *end, rb_encoding *enc)
+{
+ return skipprefixroot(path, end, enc);
+}
+
+static char *
+enc_path_last_separator(const char *path, const char *end, bool mb_enc, rb_encoding *enc)
{
char *last = NULL;
while (path < end) {
@@ -3677,14 +3786,44 @@ rb_enc_path_last_separator(const char *path, const char *end, rb_encoding *enc)
last = (char *)tmp;
}
else {
- Inc(path, end, enc);
+ Inc(path, end, mb_enc, enc);
}
}
return last;
}
+char *
+rb_enc_path_last_separator(const char *path, const char *end, rb_encoding *enc)
+{
+ return enc_path_last_separator(path, end, enc_mbclen_needed(enc), enc);
+}
+
+static inline char *
+strrdirsep(const char *path, const char *end, bool mb_enc, rb_encoding *enc)
+{
+ if (RB_UNLIKELY(mb_enc)) {
+ return enc_path_last_separator(path, end, mb_enc, enc);
+ }
+
+ const char *cursor = end - 1;
+
+ while (isdirsep(cursor[0])) {
+ cursor--;
+ }
+
+ while (cursor >= path) {
+ if (isdirsep(cursor[0])) {
+ while (cursor > path && isdirsep(cursor[-1])) {
+ cursor--;
+ }
+ return (char *)cursor;
+ }
+ cursor--;
+ }
+ return NULL;
+}
static char *
-chompdirsep(const char *path, const char *end, rb_encoding *enc)
+chompdirsep(const char *path, const char *end, bool mb_enc, rb_encoding *enc)
{
while (path < end) {
if (isdirsep(*path)) {
@@ -3693,7 +3832,7 @@ chompdirsep(const char *path, const char *end, rb_encoding *enc)
if (path >= end) return (char *)last;
}
else {
- Inc(path, end, enc);
+ Inc(path, end, mb_enc, enc);
}
}
return (char *)path;
@@ -3703,13 +3842,13 @@ char *
rb_enc_path_end(const char *path, const char *end, rb_encoding *enc)
{
if (path < end && isdirsep(*path)) path++;
- return chompdirsep(path, end, enc);
+ return chompdirsep(path, end, enc_mbclen_needed(enc), enc);
}
static rb_encoding *
fs_enc_check(VALUE path1, VALUE path2)
{
- rb_encoding *enc = rb_enc_check(path1, path2);
+ rb_encoding *enc = rb_enc_check_str(path1, path2);
int encidx = rb_enc_to_index(enc);
if (encidx == ENCINDEX_US_ASCII) {
encidx = rb_enc_get_index(path1);
@@ -3724,6 +3863,7 @@ fs_enc_check(VALUE path1, VALUE path2)
static char *
ntfs_tail(const char *path, const char *end, rb_encoding *enc)
{
+ bool mb_enc = enc_mbclen_needed(enc);
while (path < end && *path == '.') path++;
while (path < end && !isADS(*path)) {
if (istrailinggarbage(*path)) {
@@ -3738,7 +3878,7 @@ ntfs_tail(const char *path, const char *end, rb_encoding *enc)
if (isADS(*path)) path++;
}
else {
- Inc(path, end, enc);
+ Inc(path, end, mb_enc, enc);
}
}
return (char *)path;
@@ -3786,10 +3926,6 @@ static VALUE
copy_home_path(VALUE result, const char *dir)
{
char *buf;
-#if defined DOSISH || defined __CYGWIN__
- char *p, *bend;
- rb_encoding *enc;
-#endif
long dirlen;
int encidx;
@@ -3798,10 +3934,11 @@ copy_home_path(VALUE result, const char *dir)
memcpy(buf = RSTRING_PTR(result), dir, dirlen);
encidx = rb_filesystem_encindex();
rb_enc_associate_index(result, encidx);
-#if defined DOSISH || defined __CYGWIN__
- enc = rb_enc_from_index(encidx);
- for (bend = (p = buf) + dirlen; p < bend; Inc(p, bend, enc)) {
- if (*p == '\\') {
+#if defined FILE_ALT_SEPARATOR
+ rb_encoding *enc = rb_enc_from_index(encidx);
+ bool mb_enc = enc_mbclen_needed(enc);
+ for (char *p = buf, *bend = p + dirlen; p < bend; Inc(p, bend, mb_enc, enc)) {
+ if (*p == FILE_ALT_SEPARATOR) {
*p = '/';
}
}
@@ -3909,16 +4046,19 @@ ospath_new(const char *ptr, long len, rb_encoding *fsenc)
}
static char *
-append_fspath(VALUE result, VALUE fname, char *dir, rb_encoding **enc, rb_encoding *fsenc)
+append_fspath(VALUE result, VALUE fname, VALUE dirname, rb_encoding **enc, rb_encoding *fsenc)
{
- char *buf, *cwdp = dir;
- VALUE dirname = Qnil;
- size_t dirlen = strlen(dir), buflen = rb_str_capacity(result);
+ if (RB_UNLIKELY(!rb_enc_asciicompat(fsenc) || rb_enc_str_coderange(dirname) != ENC_CODERANGE_7BIT)) {
+ dirname = rb_str_new_shared(dirname);
+ rb_enc_associate(dirname, fsenc);
+ }
+
+ char *buf, *cwdp;
+ size_t dirlen = RSTRING_LEN(dirname);
+ size_t 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);
@@ -3927,19 +4067,15 @@ append_fspath(VALUE result, VALUE fname, char *dir, rb_encoding **enc, rb_encodi
rb_encoding *direnc = fs_enc_check(fname, dirname);
if (direnc != fsenc) {
dirname = rb_str_conv_enc(dirname, fsenc, direnc);
- RSTRING_GETMEM(dirname, cwdp, dirlen);
- }
- else if (NORMALIZE_UTF8PATH) {
- RSTRING_GETMEM(dirname, cwdp, dirlen);
}
*enc = direnc;
}
+
+ RSTRING_GETMEM(dirname, cwdp, dirlen);
do {buflen *= 2;} while (dirlen > buflen);
rb_str_resize(result, buflen);
buf = RSTRING_PTR(result);
memcpy(buf, cwdp, dirlen);
- xfree(dir);
- if (!NIL_P(dirname)) rb_str_resize(dirname, 0);
rb_enc_associate(result, *enc);
return buf + dirlen;
}
@@ -3954,16 +4090,21 @@ rb_file_expand_path_internal(VALUE fname, VALUE dname, int abs_mode, int long_na
s = StringValuePtr(fname);
fend = s + RSTRING_LEN(fname);
- enc = rb_enc_get(fname);
+ enc = rb_str_enc_get(fname);
+ bool mb_enc = enc_mbclen_needed(enc);
+ if (!mb_enc && RTEST(dname)) {
+ mb_enc = enc_mbclen_needed(rb_str_enc_get(dname));
+ }
+
BUFINIT();
- if (s[0] == '~' && abs_mode == 0) { /* execute only if NOT absolute_path() */
+ if (s < fend && s[0] == '~' && abs_mode == 0) { /* execute only if NOT absolute_path() */
long userlen = 0;
- if (isdirsep(s[1]) || s[1] == '\0') {
+ if (s + 1 == fend || isdirsep(s[1])) {
buf = 0;
b = 0;
rb_str_set_len(result, 0);
- if (*++s) ++s;
+ if (++s < fend) ++s;
rb_default_home_dir(result);
}
else {
@@ -3993,8 +4134,8 @@ rb_file_expand_path_internal(VALUE fname, VALUE dname, int abs_mode, int long_na
}
#ifdef DOSISH_DRIVE_LETTER
/* skip drive letter */
- else if (has_drive_letter(s)) {
- if (isdirsep(s[2])) {
+ else if (s + 1 < fend && has_drive_letter(s)) {
+ if (s + 2 < fend && isdirsep(s[2])) {
/* specified drive letter, and full path */
/* skip drive letter */
BUFCHECK(bdiff + 2 >= buflen);
@@ -4023,12 +4164,12 @@ rb_file_expand_path_internal(VALUE fname, VALUE dname, int abs_mode, int long_na
rb_enc_associate(result, enc = fs_enc_check(result, fname));
p = pend;
}
- p = chompdirsep(skiproot(buf, p, enc), p, enc);
+ p = chompdirsep(skiproot(buf, p), p, mb_enc, enc);
s += 2;
}
}
#endif /* DOSISH_DRIVE_LETTER */
- else if (!rb_is_absolute_path(s)) {
+ else if (s == fend || !rb_is_absolute_path(s)) {
if (!NIL_P(dname)) {
rb_file_expand_path_internal(dname, Qnil, abs_mode, long_name, result);
rb_enc_associate(result, fs_enc_check(result, fname));
@@ -4036,24 +4177,24 @@ rb_file_expand_path_internal(VALUE fname, VALUE dname, int abs_mode, int long_na
p = pend;
}
else {
- char *e = append_fspath(result, fname, ruby_getcwd(), &enc, fsenc);
+ char *e = append_fspath(result, fname, rb_dir_getwd_ospath(), &enc, fsenc);
BUFINIT();
p = e;
}
-#if defined DOSISH || defined __CYGWIN__
- if (isdirsep(*s)) {
+#if defined DOSISH_DRIVE_LETTER || defined DOSISH_UNC
+ if (s < fend && isdirsep(*s)) {
/* specified full path, but not drive letter nor UNC */
/* we need to get the drive letter or UNC share name */
- p = skipprefix(buf, p, enc);
+ p = skipprefix(buf, p, mb_enc, enc);
}
else
-#endif /* defined DOSISH || defined __CYGWIN__ */
- p = chompdirsep(skiproot(buf, p, enc), p, enc);
+#endif /* defined DOSISH_DRIVE_LETTER || defined DOSISH_UNC */
+ p = chompdirsep(skiproot(buf, p), p, mb_enc, enc);
}
else {
size_t len;
b = s;
- do s++; while (isdirsep(*s));
+ do s++; while (s < fend && isdirsep(*s));
len = s - b;
p = buf + len;
BUFCHECK(bdiff >= buflen);
@@ -4072,23 +4213,24 @@ rb_file_expand_path_internal(VALUE fname, VALUE dname, int abs_mode, int long_na
rb_str_set_len(result, p-buf+1);
BUFCHECK(bdiff + 1 >= buflen);
p[1] = 0;
- root = skipprefix(buf, p+1, enc);
+ root = skipprefix(buf, p+1, mb_enc, enc);
b = s;
- while (*s) {
+ while (s < fend) {
switch (*s) {
case '.':
if (b == s++) { /* beginning of path element */
- switch (*s) {
- case '\0':
+ if (s == fend) {
b = s;
break;
+ }
+ switch (*s) {
case '.':
- if (*(s+1) == '\0' || isdirsep(*(s+1))) {
+ if (s+1 == fend || isdirsep(*(s+1))) {
/* We must go back to the parent */
char *n;
*p = '\0';
- if (!(n = strrdirsep(root, p, enc))) {
+ if (!(n = strrdirsep(root, p, mb_enc, enc))) {
*p = '/';
}
else {
@@ -4098,13 +4240,13 @@ rb_file_expand_path_internal(VALUE fname, VALUE dname, int abs_mode, int long_na
}
#if USE_NTFS
else {
- do ++s; while (istrailinggarbage(*s));
+ do ++s; while (s < fend && istrailinggarbage(*s));
}
#endif /* USE_NTFS */
break;
case '/':
-#if defined DOSISH || defined __CYGWIN__
- case '\\':
+#if defined FILE_ALT_SEPARATOR
+ case FILE_ALT_SEPARATOR:
#endif
b = ++s;
break;
@@ -4128,8 +4270,8 @@ rb_file_expand_path_internal(VALUE fname, VALUE dname, int abs_mode, int long_na
#endif /* USE_NTFS */
break;
case '/':
-#if defined DOSISH || defined __CYGWIN__
- case '\\':
+#if defined FILE_ALT_SEPARATOR
+ case FILE_ALT_SEPARATOR:
#endif
if (s > b) {
WITH_ROOTDIFF(BUFCOPY(b, s-b));
@@ -4151,7 +4293,7 @@ rb_file_expand_path_internal(VALUE fname, VALUE dname, int abs_mode, int long_na
}
}
#endif /* __APPLE__ */
- Inc(s, fend, enc);
+ Inc(s, fend, mb_enc, enc);
break;
}
}
@@ -4179,7 +4321,7 @@ rb_file_expand_path_internal(VALUE fname, VALUE dname, int abs_mode, int long_na
BUFCOPY(b, s-b);
rb_str_set_len(result, p-buf);
}
- if (p == skiproot(buf, p + !!*p, enc) - 1) p++;
+ if (p == skiproot(buf, p + !!*p) - 1) p++;
#if USE_NTFS
*p = '\0';
@@ -4337,31 +4479,43 @@ rb_file_s_expand_path(int argc, const VALUE *argv)
}
/*
+ * :markup: markdown
+ *
* call-seq:
- * File.expand_path(file_name [, dir_string] ) -> abs_file_name
+ * File.expand_path(path, dirpath = '.') -> absolute_path
*
- * Converts a pathname to an absolute pathname. Relative paths are
- * referenced from the current working directory of the process unless
- * +dir_string+ is given, in which case it will be used as the
- * starting point. The given pathname may start with a
- * ``<code>~</code>'', which expands to the process owner's home
- * directory (the environment variable +HOME+ must be set
- * correctly). ``<code>~</code><i>user</i>'' expands to the named
- * user's home directory.
+ * Returns the string absolute path for the given `path`.
*
- * File.expand_path("~oracle/bin") #=> "/home/oracle/bin"
+ * Evaluates a relative path with respect to the directory given by `dirpath`:
*
- * A simple example of using +dir_string+ is as follows.
- * File.expand_path("ruby", "/usr/bin") #=> "/usr/bin/ruby"
+ * ```ruby
+ * Dir.chdir('/snap')
+ * # Default dirpath.
+ * File.expand_path('README') # => "/snap/README"
+ * File.expand_path('bin') # => "/snap/bin"
+ * File.expand_path('bin/../var') # => "/snap/var" # Cleaned.
+ * # Other dirpath.
+ * File.expand_path('../zip', '/usr/bin/ruby') # => "/usr/bin/zip"
+ * Dir.chdir('/usr/bin')
+ * File.expand_path('../../snap', __FILE__) # => "/usr/snap"
+ * ```
+ *
+ * Evaluates an absolute path without respect to `dirpath`:
*
- * A more complex example which also resolves parent directory is as follows.
- * Suppose we are in bin/mygem and want the absolute path of lib/mygem.rb.
+ * ```ruby
+ * File.expand_path('/snap') # => "/snap"
+ * File.expand_path('/snap', 'nosuch') # => "/snap"
+ * File.expand_path('/snap/../snap') # => "/snap" # Cleaned.
+ * ```
*
- * File.expand_path("../../lib/mygem.rb", __FILE__)
- * #=> ".../path/to/project/lib/mygem.rb"
+ * More examples:
+ *
+ * ```
+ * Dir.chdir('/usr/bin')
+ * File.expand_path('../../snap', __FILE__) # => "/usr/snap"
+ * File.expand_path('../../snap') # => "/snap"
+ * ```
*
- * So first it resolves the parent of __FILE__, that is bin/, then go to the
- * parent, the root of the project and appends +lib/mygem.rb+.
*/
static VALUE
@@ -4449,9 +4603,10 @@ realpath_rec(long *prefixlenp, VALUE *resolvedp, const char *unresolved, VALUE f
}
else if (testnamelen == 2 && testname[0] == '.' && testname[1] == '.') {
if (*prefixlenp < RSTRING_LEN(*resolvedp)) {
+ bool mb_enc = enc_mbclen_needed(enc);
const char *resolved_str = RSTRING_PTR(*resolvedp);
const char *resolved_names = resolved_str + *prefixlenp;
- const char *lastsep = strrdirsep(resolved_names, resolved_str + RSTRING_LEN(*resolvedp), enc);
+ const char *lastsep = strrdirsep(resolved_names, resolved_str + RSTRING_LEN(*resolvedp), mb_enc, enc);
long len = lastsep ? lastsep - resolved_names : 0;
rb_str_resize(*resolvedp, *prefixlenp + len);
}
@@ -4591,7 +4746,8 @@ rb_check_realpath_emulate(VALUE basedir, VALUE path, rb_encoding *origenc, enum
root_found:
RSTRING_GETMEM(resolved, prefixptr, prefixlen);
pend = prefixptr + prefixlen;
- ptr = chompdirsep(prefixptr, pend, enc);
+ bool mb_enc = enc_mbclen_needed(enc);
+ ptr = chompdirsep(prefixptr, pend, mb_enc, enc);
if (ptr < pend) {
prefixlen = ++ptr - prefixptr;
rb_str_set_len(resolved, prefixlen);
@@ -4601,7 +4757,7 @@ rb_check_realpath_emulate(VALUE basedir, VALUE path, rb_encoding *origenc, enum
if (*prefixptr == FILE_ALT_SEPARATOR) {
*prefixptr = '/';
}
- Inc(prefixptr, pend, enc);
+ Inc(prefixptr, pend, mb_enc, enc);
}
#endif
@@ -4637,7 +4793,7 @@ rb_check_realpath_emulate(VALUE basedir, VALUE path, rb_encoding *origenc, enum
return resolved;
}
-static VALUE rb_file_join(VALUE ary);
+static VALUE rb_file_join(long argc, VALUE *args);
#ifndef HAVE_REALPATH
static VALUE
@@ -4678,7 +4834,8 @@ rb_check_realpath_internal(VALUE basedir, VALUE path, rb_encoding *origenc, enum
unresolved_path = rb_str_dup_frozen(path);
if (*RSTRING_PTR(unresolved_path) != '/' && !NIL_P(basedir)) {
- unresolved_path = rb_file_join(rb_assoc_new(basedir, unresolved_path));
+ VALUE paths[2] = {basedir, unresolved_path};
+ unresolved_path = rb_file_join(2, paths);
}
if (origenc) unresolved_path = TO_OSPATH(unresolved_path);
@@ -4844,23 +5001,29 @@ rmext(const char *p, long l0, long l1, const char *e, long l2, rb_encoding *enc)
return 0;
}
-const char *
-ruby_enc_find_basename(const char *name, long *baselen, long *alllen, rb_encoding *enc)
+static inline const char *
+enc_find_basename(const char *name, long *baselen, long *alllen, bool mb_enc, rb_encoding *enc)
{
const char *p, *q, *e, *end;
-#if defined DOSISH_DRIVE_LETTER || defined DOSISH_UNC
- const char *root;
-#endif
long f = 0, n = -1;
- end = name + (alllen ? (size_t)*alllen : strlen(name));
- name = skipprefix(name, end, enc);
+ long len = (alllen ? (size_t)*alllen : strlen(name));
+
+ if (len <= 0) {
+ return name;
+ }
+
+ end = name + len;
+ name = skipprefix(name, end, mb_enc, enc);
#if defined DOSISH_DRIVE_LETTER || defined DOSISH_UNC
- root = name;
+ const char *root = name;
#endif
- while (isdirsep(*name))
+
+ while (name < end && isdirsep(*name)) {
name++;
- if (!*name) {
+ }
+
+ if (name == end) {
p = name - 1;
f = 1;
#if defined DOSISH_DRIVE_LETTER || defined DOSISH_UNC
@@ -4881,91 +5044,127 @@ ruby_enc_find_basename(const char *name, long *baselen, long *alllen, rb_encodin
#endif /* defined DOSISH_DRIVE_LETTER || defined DOSISH_UNC */
}
else {
- if (!(p = strrdirsep(name, end, enc))) {
+ p = strrdirsep(name, end, mb_enc, enc);
+ if (!p) {
p = name;
}
else {
- while (isdirsep(*p)) p++; /* skip last / */
+ while (isdirsep(*p)) {
+ p++; /* skip last / */
+ }
}
#if USE_NTFS
n = ntfs_tail(p, end, enc) - p;
#else
- n = chompdirsep(p, end, enc) - p;
+ n = chompdirsep(p, end, mb_enc, enc) - p;
#endif
for (q = p; q - p < n && *q == '.'; q++);
- for (e = 0; q - p < n; Inc(q, end, enc)) {
+ for (e = 0; q - p < n; Inc(q, end, mb_enc, enc)) {
if (*q == '.') e = q;
}
- if (e) f = e - p;
- else f = n;
+ if (e) {
+ f = e - p;
+ }
+ else {
+ f = n;
+ }
}
- if (baselen)
+ if (baselen) {
*baselen = f;
- if (alllen)
+ }
+ if (alllen) {
*alllen = n;
+ }
return p;
}
+const char *
+ruby_enc_find_basename(const char *name, long *baselen, long *alllen, rb_encoding *enc)
+{
+ return enc_find_basename(name, baselen, alllen, enc_mbclen_needed(enc), enc);
+}
+
/*
* call-seq:
- * File.basename(file_name [, suffix] ) -> base_name
+ * File.basename(path, suffix = '') -> new_string
*
- * Returns the last component of the filename given in
- * <i>file_name</i> (after first stripping trailing separators),
- * which can be formed using both File::SEPARATOR and
- * File::ALT_SEPARATOR as the separator when File::ALT_SEPARATOR is
- * not <code>nil</code>. If <i>suffix</i> is given and present at the
- * end of <i>file_name</i>, it is removed. If <i>suffix</i> is ".*",
- * any extension will be removed.
+ * Returns a new string containing all or part of the last entry of the given +path+.
+ * Entries are delimited by the value of constant File::SEPARATOR
+ * and, if non-nil, the value of constant File::ALT_SEPARATOR.
+ *
+ * When +suffix+ is the empty string <tt>''</tt>,
+ * returns all of the last entry:
+ *
+ * File.basename('foo/bar/baz/bat.txt') # => "bat.txt"
+ * File.basename('foo/bar/baz') # => "baz"
+ *
+ * File::SEPARATOR # => "/"
+ * File.basename('foo/bar.txt////') # => "bar.txt"
+ * File::ALT_SEPARATOR # => "\\" # On Windows.
+ * File.basename('foo/bar.txt//\\\\//') # => "bar.txt"
+ *
+ * When +suffix+ is <tt>'.*'</tt>,
+ * the last {filename extension}[https://en.wikipedia.org/wiki/Filename_extension],
+ * if any, is removed:
+ *
+ * File.basename('foo/bar.txt', '.*') # => "bar"
+ * File.basename('foo/bar.txt.old', '.*') # => "bar.txt"
+ * File.basename('foo/bar', '.*') # => "bar"
+ *
+ * When +suffix+ is any string other than <tt>''</tt> or <tt>'.*'</tt>,
+ * the matching trailing substring, if any, is removed:
+ *
+ * File.basename('foo/bar.txt', '.txt') # => "bar"
+ * File.basename('foo/bar.txt', 'txt') # => "bar."
+ * File.basename('foo/bar.txt', '*') # => "bar.txt"
+ * File.basename('foo/bar.txt', '.') # => "bar.txt"
*
- * File.basename("/home/gumby/work/ruby.rb") #=> "ruby.rb"
- * File.basename("/home/gumby/work/ruby.rb", ".rb") #=> "ruby"
- * File.basename("/home/gumby/work/ruby.rb", ".*") #=> "ruby"
*/
static VALUE
rb_file_s_basename(int argc, VALUE *argv, VALUE _)
{
- VALUE fname, fext, basename;
- const char *name, *p;
- long f, n;
+ VALUE fname, fext = Qnil;
+ const char *name, *p, *fp = 0;
+ long f = 0, n;
rb_encoding *enc;
- fext = Qnil;
- if (rb_check_arity(argc, 1, 2) == 2) {
+ argc = rb_check_arity(argc, 1, 2);
+ fname = argv[0];
+ CheckPath(fname, name);
+ if (argc == 2) {
fext = argv[1];
- StringValue(fext);
- enc = check_path_encoding(fext);
+ fp = StringValueCStr(fext);
+ check_path_encoding(fext);
}
- fname = argv[0];
- FilePathStringValue(fname);
if (NIL_P(fext) || !(enc = rb_enc_compatible(fname, fext))) {
- enc = rb_enc_get(fname);
- fext = Qnil;
+ enc = rb_str_enc_get(fname);
}
- if ((n = RSTRING_LEN(fname)) == 0 || !*(name = RSTRING_PTR(fname)))
- return rb_str_new_shared(fname);
- p = ruby_enc_find_basename(name, &f, &n, enc);
+ n = RSTRING_LEN(fname);
+ if (n <= 0 || !*name) {
+ return rb_enc_str_new(0, 0, enc);
+ }
+
+ bool mb_enc = enc_mbclen_needed(enc);
+ p = enc_find_basename(name, &f, &n, mb_enc, enc);
if (n >= 0) {
- if (NIL_P(fext)) {
+ if (!fp) {
f = n;
}
else {
- const char *fp;
- fp = StringValueCStr(fext);
if (!(f = rmext(p, f, n, fp, RSTRING_LEN(fext), enc))) {
f = n;
}
RB_GC_GUARD(fext);
}
- if (f == RSTRING_LEN(fname)) return rb_str_new_shared(fname);
+ if (f == RSTRING_LEN(fname)) {
+ return rb_str_new_shared(fname);
+ }
}
- basename = rb_str_new(p, f);
- rb_enc_copy(basename, fname);
- return basename;
+ return rb_enc_str_new(p, f, enc);
}
static VALUE rb_file_dirname_n(VALUE fname, int n);
@@ -5010,19 +5209,18 @@ rb_file_dirname_n(VALUE fname, int n)
{
const char *name, *root, *p, *end;
VALUE dirname;
- rb_encoding *enc;
- VALUE sepsv = 0;
- const char **seps;
if (n < 0) rb_raise(rb_eArgError, "negative level: %d", n);
- FilePathStringValue(fname);
- name = StringValueCStr(fname);
+ CheckPath(fname, name);
end = name + RSTRING_LEN(fname);
- enc = rb_enc_get(fname);
- root = skiproot(name, end, enc);
+
+ bool mb_enc = !rb_str_enc_fastpath(fname);
+ rb_encoding *enc = rb_str_enc_get(fname);
+
+ root = skiproot(name, end);
#ifdef DOSISH_UNC
if (root > name + 1 && isdirsep(*name))
- root = skipprefix(name = root - 2, end, enc);
+ root = skipprefix(name = root - 2, end, mb_enc, enc);
#else
if (root > name + 1)
name = root - 1;
@@ -5031,72 +5229,41 @@ rb_file_dirname_n(VALUE fname, int n)
p = root;
}
else {
- int i;
- switch (n) {
- case 0:
- p = end;
- break;
- case 1:
- if (!(p = strrdirsep(root, end, enc))) p = root;
- break;
- default:
- seps = ALLOCV_N(const char *, sepsv, n);
- for (i = 0; i < n; ++i) seps[i] = root;
- i = 0;
- for (p = root; p < end; ) {
- if (isdirsep(*p)) {
- const char *tmp = p++;
- while (p < end && isdirsep(*p)) p++;
- if (p >= end) break;
- seps[i++] = tmp;
- if (i == n) i = 0;
- }
- else {
- Inc(p, end, enc);
- }
+ p = end;
+ while (n) {
+ if (!(p = strrdirsep(root, p, mb_enc, enc))) {
+ p = root;
+ break;
}
- p = seps[i];
- ALLOCV_END(sepsv);
- break;
+ n--;
}
}
- if (p == name)
- return rb_usascii_str_new2(".");
+
+ if (p == name) {
+ return rb_enc_str_new(".", 1, enc);
+ }
#ifdef DOSISH_DRIVE_LETTER
- if (has_drive_letter(name) && isdirsep(*(name + 2))) {
- const char *top = skiproot(name + 2, end, enc);
- dirname = rb_str_new(name, 3);
+ if (name + 3 < end && has_drive_letter(name) && isdirsep(*(name + 2))) {
+ const char *top = skiproot(name + 2, end);
+ dirname = rb_enc_str_new(name, 3, enc);
rb_str_cat(dirname, top, p - top);
}
else
#endif
- dirname = rb_str_new(name, p - name);
+ dirname = rb_enc_str_new(name, p - name, enc);
#ifdef DOSISH_DRIVE_LETTER
- if (has_drive_letter(name) && root == name + 2 && p - name == 2)
+ if (root == name + 2 && p == root && name[1] == ':')
rb_str_cat(dirname, ".", 1);
#endif
- rb_enc_copy(dirname, fname);
return dirname;
}
-/*
- * accept a String, and return the pointer of the extension.
- * if len is passed, set the length of extension to it.
- * returned pointer is in ``name'' or NULL.
- * returns *len
- * no dot NULL 0
- * dotfile top 0
- * end with dot dot 1
- * .ext dot len of .ext
- * .ext:stream dot len of .ext without :stream (NTFS only)
- *
- */
-const char *
-ruby_enc_find_extname(const char *name, long *len, rb_encoding *enc)
+static inline const char *
+enc_find_extname(const char *name, long *len, bool mb_enc, rb_encoding *enc)
{
const char *p, *e, *end = name + (len ? *len : (long)strlen(name));
- p = strrdirsep(name, end, enc); /* get the last path component */
+ p = strrdirsep(name, end, mb_enc, enc); /* get the last path component */
if (!p)
p = name;
else
@@ -5129,7 +5296,7 @@ ruby_enc_find_extname(const char *name, long *len, rb_encoding *enc)
#endif
else if (isdirsep(*p))
break;
- Inc(p, end, enc);
+ Inc(p, end, mb_enc, enc);
}
if (len) {
@@ -5145,57 +5312,106 @@ ruby_enc_find_extname(const char *name, long *len, rb_encoding *enc)
}
/*
+ * accept a String, and return the pointer of the extension.
+ * if len is passed, set the length of extension to it.
+ * returned pointer is in ``name'' or NULL.
+ * returns *len
+ * no dot NULL 0
+ * dotfile top 0
+ * end with dot dot 1
+ * .ext dot len of .ext
+ * .ext:stream dot len of .ext without :stream (NTFS only)
+ *
+ */
+const char *
+ruby_enc_find_extname(const char *name, long *len, rb_encoding *enc)
+{
+ return enc_find_extname(name, len, enc_mbclen_needed(enc), enc);
+}
+
+/*
+ * :markup: markdown
+ *
* call-seq:
- * File.extname(path) -> string
+ * File.extname(path) -> extension
+ *
+ * Returns the filename extension --
+ * usually the portion of the string `path`
+ * beginning from the last period:
*
- * Returns the extension (the portion of file name in +path+
- * starting from the last period).
+ * ```ruby
+ * File.extname('t.rb') # => ".rb"
+ * File.extname('foo.bar.t.rb') # => ".rb"
+ * File.extname('foo/bar/t.rb') # => ".rb"
+ * File.extname('nosuch.txt') # => ".txt" # Path need not exist.
+ * ```
*
- * If +path+ is a dotfile, or starts with a period, then the starting
- * dot is not dealt with the start of the extension.
+ * Returns the entire string when there is no period:
*
- * An empty string will also be returned when the period is the last character
- * in +path+.
+ * ```ruby
+ * Pathname('foo').extname # => ""
+ * ```
*
- * On Windows, trailing dots are truncated.
+ * Returns an empty string when the only period is the first character:
*
- * File.extname("test.rb") #=> ".rb"
- * File.extname("a/b/d/test.rb") #=> ".rb"
- * File.extname(".a/b/d/test.rb") #=> ".rb"
- * File.extname("foo.") #=> "" on Windows
- * File.extname("foo.") #=> "." on non-Windows
- * File.extname("test") #=> ""
- * File.extname(".profile") #=> ""
- * File.extname(".profile.sh") #=> ".sh"
+ * ```ruby
+ * File.extname('.irbrc') # => ""
+ * ```
+ *
+ * Returns an empty string or `'.'` when `path` ends with a period:
+ *
+ * ```
+ * File.extname('foo.') # => "" # On Windows.
+ * File.extname('foo.') # => "." # Elsewhere.
+ * File.extname('foo....') # => "" # On Windows.
+ * File.extname('foo....') # => "." # Elsewhere.
+ * ```
*
*/
static VALUE
rb_file_s_extname(VALUE klass, VALUE fname)
{
- const char *name, *e;
- long len;
- VALUE extname;
+ const char *name;
+ CheckPath(fname, name);
+ long len = RSTRING_LEN(fname);
- FilePathStringValue(fname);
- name = StringValueCStr(fname);
- len = RSTRING_LEN(fname);
- e = ruby_enc_find_extname(name, &len, rb_enc_get(fname));
- if (len < 1)
- return rb_str_new(0, 0);
- extname = rb_str_subseq(fname, e - name, len); /* keep the dot, too! */
- return extname;
+ if (len < 1) {
+ return rb_enc_str_new(0, 0, rb_str_enc_get(fname));
+ }
+
+ bool mb_enc = !rb_str_enc_fastpath(fname);
+ rb_encoding *enc = rb_str_enc_get(fname);
+
+ const char *ext = enc_find_extname(name, &len, mb_enc, enc);
+ return rb_enc_str_new(ext, len, enc);
}
/*
- * call-seq:
+ * call-seq:
* File.path(path) -> string
*
- * Returns the string representation of the path
+ * Returns the string representation of the path
*
* File.path(File::NULL) #=> "/dev/null"
* File.path(Pathname.new("/tmp")) #=> "/tmp"
*
+ * If +path+ is not a String:
+ *
+ * 1. If it has the +to_path+ method, that method will be called to
+ * coerce to a String.
+ *
+ * 2. Otherwise, or if the coerced result is not a String too, the
+ * standard coercion using +to_str+ method will take place on that
+ * object. (See also String.try_convert)
+ *
+ * The coerced string must satisfy the following conditions:
+ *
+ * 1. It must be in an ASCII-compatible encoding; otherwise, an
+ * Encoding::CompatibilityError is raised.
+ *
+ * 2. It must not contain the NUL character (<tt>\0</tt>); otherwise,
+ * an ArgumentError is raised.
*/
static VALUE
@@ -5222,15 +5438,17 @@ rb_file_s_split(VALUE klass, VALUE path)
return rb_assoc_new(rb_file_dirname(path), rb_file_s_basename(1,&path,Qundef));
}
+static VALUE rb_file_join_ary(VALUE ary);
+
static VALUE
file_inspect_join(VALUE ary, VALUE arg, int recur)
{
if (recur || ary == arg) rb_raise(rb_eArgError, "recursive array");
- return rb_file_join(arg);
+ return rb_file_join_ary(arg);
}
static VALUE
-rb_file_join(VALUE ary)
+rb_file_join_ary(VALUE ary)
{
long len, i;
VALUE result, tmp;
@@ -5278,11 +5496,11 @@ rb_file_join(VALUE ary)
rb_enc_copy(result, tmp);
}
else {
- tail = chompdirsep(name, name + len, rb_enc_get(result));
- if (RSTRING_PTR(tmp) && isdirsep(RSTRING_PTR(tmp)[0])) {
+ tail = chompdirsep(name, name + len, true, rb_enc_get(result));
+ if (RSTRING_LEN(tmp) > 0 && isdirsep(RSTRING_PTR(tmp)[0])) {
rb_str_set_len(result, tail - name);
}
- else if (!*tail) {
+ else if (tail == name + len) {
rb_str_cat(result, "/", 1);
}
}
@@ -5295,6 +5513,77 @@ rb_file_join(VALUE ary)
return result;
}
+static inline VALUE
+rb_file_join_fastpath(long argc, VALUE *args)
+{
+ long size = argc;
+
+ long i;
+ for (i = 0; i < argc; i++) {
+ VALUE tmp = args[i];
+ if (RB_LIKELY(RB_TYPE_P(tmp, T_STRING) && rb_str_enc_fastpath(tmp))) {
+ size += RSTRING_LEN(tmp);
+ }
+ else {
+ return 0;
+ }
+ }
+
+ VALUE result = rb_str_buf_new(size);
+
+ int encidx = ENCODING_GET_INLINED(args[0]);
+ ENCODING_SET_INLINED(result, encidx);
+ rb_str_buf_append(result, args[0]);
+
+ const char *name = RSTRING_PTR(result);
+ for (i = 1; i < argc; i++) {
+ VALUE tmp = args[i];
+ long len = RSTRING_LEN(result);
+
+ const char *tmp_s;
+ long tmp_len;
+ RSTRING_GETMEM(tmp, tmp_s, tmp_len);
+
+ if (tmp_len > 0 && isdirsep(tmp_s[0])) {
+ // right side has a leading separator, remove left side separators.
+ long chomp = len;
+ while (chomp > 0 && isdirsep(name[chomp - 1])) {
+ --chomp;
+ }
+ rb_str_set_len(result, chomp);
+ }
+ else if (len < 1 || !isdirsep(name[len - 1])) {
+ // neither side have a separator, append one;
+ rb_str_cat(result, "/", 1);
+ }
+
+ if (RB_UNLIKELY(ENCODING_GET_INLINED(tmp) != encidx)) {
+ rb_encoding *new_enc = fs_enc_check(result, tmp);
+ rb_enc_associate(result, new_enc);
+ encidx = rb_enc_to_index(new_enc);
+ }
+
+ rb_str_buf_cat(result, tmp_s, tmp_len);
+ }
+
+ rb_str_null_check(result);
+ return result;
+}
+
+static inline VALUE
+rb_file_join(long argc, VALUE *args)
+{
+ if (RB_UNLIKELY(argc == 0)) {
+ return rb_str_new(0, 0);
+ }
+
+ VALUE result = rb_file_join_fastpath(argc, args);
+ if (RB_LIKELY(result)) {
+ return result;
+ }
+
+ return rb_file_join_ary(rb_ary_new_from_values(argc, args));
+}
/*
* call-seq:
* File.join(string, ...) -> string
@@ -5307,9 +5596,9 @@ rb_file_join(VALUE ary)
*/
static VALUE
-rb_file_s_join(VALUE klass, VALUE args)
+rb_file_s_join(int argc, VALUE *argv, VALUE klass)
{
- return rb_file_join(args);
+ return rb_file_join(argc, argv);
}
#if defined(HAVE_TRUNCATE)
@@ -5449,7 +5738,7 @@ rb_thread_flock(void *data)
* call-seq:
* flock(locking_constant) -> 0 or false
*
- * Locks or unlocks file +self+ according to the given `locking_constant`,
+ * 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.
@@ -5459,10 +5748,10 @@ rb_thread_flock(void *data)
*
* | 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::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. |
*
* Example:
*
@@ -5589,11 +5878,11 @@ test_check(int n, int argc, VALUE *argv)
* | <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+:
+ * 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. |
+ * | <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;
@@ -5775,13 +6064,48 @@ rb_f_test(int argc, VALUE *argv, VALUE _)
/*
* Document-class: File::Stat
*
- * Objects of class File::Stat encapsulate common status information
- * for File objects. The information is recorded at the moment the
- * File::Stat object is created; changes made to the file after that
- * point will not be reflected. File::Stat objects are returned by
- * IO#stat, File::stat, File#lstat, and File::lstat. Many of these
- * methods return platform-specific values, and not all values are
- * meaningful on all systems. See also Kernel#test.
+ * A \File::Stat object contains information about an entry in the file system.
+ *
+ * Each of these methods returns a new \File::Stat object:
+ *
+ * - File#lstat.
+ * - File::Stat.new.
+ * - File::lstat.
+ * - File::stat.
+ * - IO#stat.
+ *
+ * === Snapshot
+ *
+ * A new \File::Stat object takes an immediate "snapshot" of the entry's information;
+ * the captured information is never updated,
+ * regardless of changes in the actual entry:
+ *
+ * The entry must exist when File::Stat.new is called:
+ *
+ * filepath = 't.tmp'
+ * File.exist?(filepath) # => false
+ * File::Stat.new(filepath) # Raises Errno::ENOENT: No such file or directory.
+ * File.write(filepath, 'foo') # Create the file.
+ * stat = File::Stat.new(filepath) # Okay.
+ *
+ * Later changes to the actual entry do not change the \File::Stat object:
+ *
+ * File.atime(filepath) # => 2026-04-01 11:51:38.0014518 -0500
+ * stat.atime # => 2026-04-01 11:51:38.0014518 -0500
+ * File.write(filepath, 'bar')
+ * File.atime(filepath) # => 2026-04-01 11:58:11.922614 -0500
+ * stat.atime # => 2026-04-01 11:51:38.0014518 -0500
+ * File.delete(filepath)
+ * stat.atime # => 2026-04-01 11:51:38.0014518 -0500
+ *
+ * === OS-Dependencies
+ *
+ * Methods in a \File::Stat object may return platform-dependents values,
+ * and not all values are meaningful on all systems;
+ * for example, File::Stat#blocks returns +nil+ on Windows,
+ * but returns an integer on Linux.
+ *
+ * See also Kernel#test.
*/
static VALUE
@@ -6475,96 +6799,6 @@ rb_is_absolute_path(const char *path)
return 0;
}
-#ifndef ENABLE_PATH_CHECK
-# if defined DOSISH || defined __CYGWIN__
-# define ENABLE_PATH_CHECK 0
-# else
-# define ENABLE_PATH_CHECK 1
-# endif
-#endif
-
-#if ENABLE_PATH_CHECK
-static int
-path_check_0(VALUE path)
-{
- struct stat st;
- const char *p0 = StringValueCStr(path);
- const char *e0;
- rb_encoding *enc;
- char *p = 0, *s;
-
- if (!rb_is_absolute_path(p0)) {
- char *buf = ruby_getcwd();
- VALUE newpath;
-
- newpath = rb_str_new2(buf);
- xfree(buf);
-
- rb_str_cat2(newpath, "/");
- rb_str_cat2(newpath, p0);
- path = newpath;
- p0 = RSTRING_PTR(path);
- }
- e0 = p0 + RSTRING_LEN(path);
- enc = rb_enc_get(path);
- for (;;) {
-#ifndef S_IWOTH
-# define S_IWOTH 002
-#endif
- if (STAT(p0, &st) == 0 && S_ISDIR(st.st_mode) && (st.st_mode & S_IWOTH)
-#ifdef S_ISVTX
- && !(p && (st.st_mode & S_ISVTX))
-#endif
- && !access(p0, W_OK)) {
- rb_enc_warn(enc, "Insecure world writable dir %s in PATH, mode 0%"
-#if SIZEOF_DEV_T > SIZEOF_INT
- PRI_MODET_PREFIX"o",
-#else
- "o",
-#endif
- p0, st.st_mode);
- if (p) *p = '/';
- RB_GC_GUARD(path);
- return 0;
- }
- s = strrdirsep(p0, e0, enc);
- if (p) *p = '/';
- if (!s || s == p0) return 1;
- p = s;
- e0 = p;
- *p = '\0';
- }
-}
-#endif
-
-int
-rb_path_check(const char *path)
-{
- rb_warn_deprecated_to_remove_at(3.6, "rb_path_check", NULL);
-#if ENABLE_PATH_CHECK
- const char *p0, *p, *pend;
- const char sep = PATH_SEP_CHAR;
-
- if (!path) return 1;
-
- pend = path + strlen(path);
- p0 = path;
- p = strchr(path, sep);
- if (!p) p = pend;
-
- for (;;) {
- if (!path_check_0(rb_str_new(p0, p - p0))) {
- return 0; /* not safe */
- }
- p0 = p + 1;
- if (p0 > pend) break;
- p = strchr(p0, sep);
- if (!p) p = pend;
- }
-#endif
- return 1;
-}
-
int
ruby_is_fd_loadable(int fd)
{
@@ -6785,7 +7019,7 @@ const char ruby_null_device[] =
* 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].
+ * {read/write mode}[rdoc-ref:File@ReadWrite+Mode].
* - May also contain a 1-character {data mode}[rdoc-ref:File@Data+Mode].
* - May also contain a 1-character
* {file-create mode}[rdoc-ref:File@File-Create+Mode].
@@ -7426,7 +7660,7 @@ const char ruby_null_device[] =
*
* First, what's elsewhere. Class \File:
*
- * - Inherits from {class IO}[rdoc-ref:IO@What-27s+Here],
+ * - Inherits from {class IO}[rdoc-ref:IO@Whats+Here],
* in particular, methods for creating, reading, and writing files
* - Includes module FileTest,
* which provides dozens of additional methods.
@@ -7641,7 +7875,7 @@ Init_File(void)
/* separates directory parts in path */
rb_define_const(rb_cFile, "SEPARATOR", separator);
rb_define_singleton_method(rb_cFile, "split", rb_file_s_split, 1);
- rb_define_singleton_method(rb_cFile, "join", rb_file_s_join, -2);
+ rb_define_singleton_method(rb_cFile, "join", rb_file_s_join, -1);
#ifdef DOSISH
/* platform specific alternative separator */
@@ -7945,11 +8179,11 @@ Init_File(void)
*
* ==== File::FNM_EXTGLOB
*
- * Flag File::FNM_EXTGLOB enables pattern <tt>'{_a_,_b_}'</tt>,
+ * 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>):
+ * (e.g., <tt>'(?:a|b)'</tt>):
*
* pattern = '{LEGAL,BSDL}'
* Dir.glob(pattern) # => ["LEGAL", "BSDL"]
diff --git a/gc.c b/gc.c
index 686e727521..0219fa6e78 100644
--- a/gc.c
+++ b/gc.c
@@ -11,9 +11,6 @@
**********************************************************************/
-#define rb_data_object_alloc rb_data_object_alloc
-#define rb_data_typed_object_alloc rb_data_typed_object_alloc
-
#include "ruby/internal/config.h"
#ifdef _WIN32
# include "ruby/ruby.h"
@@ -82,7 +79,6 @@
#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"
@@ -103,6 +99,7 @@
#include "internal/object.h"
#include "internal/proc.h"
#include "internal/rational.h"
+#include "internal/re.h"
#include "internal/sanitizers.h"
#include "internal/struct.h"
#include "internal/symbol.h"
@@ -127,10 +124,19 @@
#include "vm_callinfo.h"
#include "ractor_core.h"
#include "yjit.h"
+#include "zjit.h"
#include "builtin.h"
#include "shape.h"
+// TODO: Don't export this function in modular GC, instead MMTk should figure out
+// how to combine GC thread backtrace with mutator thread backtrace.
+void
+rb_gc_print_backtrace(void)
+{
+ rb_print_backtrace(stderr);
+}
+
unsigned int
rb_gc_vm_lock(const char *file, int line)
{
@@ -179,7 +185,6 @@ rb_gc_vm_barrier(void)
rb_vm_barrier();
}
-#if USE_MODULAR_GC
void *
rb_gc_get_ractor_newobj_cache(void)
{
@@ -193,35 +198,6 @@ rb_gc_initialize_vm_context(struct rb_gc_vm_context *context)
context->ec = GET_EC();
}
-void
-rb_gc_worker_thread_set_vm_context(struct rb_gc_vm_context *context)
-{
- rb_native_mutex_lock(&context->lock);
-
- GC_ASSERT(rb_current_execution_context(false) == NULL);
-
-#ifdef RB_THREAD_LOCAL_SPECIFIER
- rb_current_ec_set(context->ec);
-#else
- native_tls_set(ruby_current_ec_key, context->ec);
-#endif
-}
-
-void
-rb_gc_worker_thread_unset_vm_context(struct rb_gc_vm_context *context)
-{
- rb_native_mutex_unlock(&context->lock);
-
- GC_ASSERT(rb_current_execution_context(true) == context->ec);
-
-#ifdef RB_THREAD_LOCAL_SPECIFIER
- rb_current_ec_set(NULL);
-#else
- native_tls_set(ruby_current_ec_key, NULL);
-#endif
-}
-#endif
-
bool
rb_gc_event_hook_required_p(rb_event_flag_t event)
{
@@ -233,10 +209,33 @@ rb_gc_event_hook(VALUE obj, rb_event_flag_t event)
{
if (LIKELY(!rb_gc_event_hook_required_p(event))) return;
- rb_execution_context_t *ec = GET_EC();
+ rb_execution_context_t *ec = rb_gc_get_ec();
if (!ec->cfp) return;
+#if USE_MODULAR_GC
+ bool gc_thread_p = false;
+ if (!GET_EC()) {
+ gc_thread_p = true;
+
+# ifdef RB_THREAD_LOCAL_SPECIFIER
+ rb_current_ec_set(ec);
+# else
+ native_tls_set(ruby_current_ec_key, ec);
+# endif
+ }
+#endif
+
EXEC_EVENT_HOOK(ec, event, ec->cfp->self, 0, 0, 0, obj);
+
+#if USE_MODULAR_GC
+ if (gc_thread_p) {
+# ifdef RB_THREAD_LOCAL_SPECIFIER
+ rb_current_ec_set(NULL);
+# else
+ native_tls_set(ruby_current_ec_key, NULL);
+# endif
+ }
+#endif
}
void *
@@ -245,7 +244,6 @@ rb_gc_get_objspace(void)
return GET_VM()->gc.objspace;
}
-
void
rb_gc_ractor_newobj_cache_foreach(void (*func)(void *cache, void *data), void *data)
{
@@ -289,6 +287,7 @@ rb_gc_run_obj_finalizer(VALUE objid, long count, VALUE (*callback)(long i, void
saved.finished = 0;
saved.final = Qundef;
+ ASSERT_vm_unlocking();
rb_ractor_ignore_belonging(true);
EC_PUSH_TAG(ec);
enum ruby_tag_type state = EC_EXEC_TAG();
@@ -337,7 +336,10 @@ rb_gc_shutdown_call_finalizer_p(VALUE obj)
{
switch (BUILTIN_TYPE(obj)) {
case T_DATA:
- if (!ruby_free_at_exit_p() && (!DATA_PTR(obj) || !RDATA(obj)->dfree)) return false;
+ if (!ruby_free_at_exit_p()) {
+ if (!RDATA(obj)->type) return false;
+ if (!rbimpl_typeddata_embedded_p(obj) && !RTYPEDDATA(obj)->data) 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;
@@ -361,31 +363,18 @@ rb_gc_shutdown_call_finalizer_p(VALUE obj)
}
}
-uint32_t
-rb_gc_get_shape(VALUE obj)
-{
- return (uint32_t)rb_obj_shape_id(obj);
-}
-
void
-rb_gc_set_shape(VALUE obj, uint32_t shape_id)
-{
- rb_obj_set_shape_id(obj, (uint32_t)shape_id);
-}
-
-uint32_t
-rb_gc_rebuild_shape(VALUE obj, size_t heap_id)
+rb_gc_obj_changed_pool(VALUE obj, size_t heap_id)
{
RUBY_ASSERT(RB_TYPE_P(obj, T_OBJECT));
- return (uint32_t)rb_shape_transition_heap(obj, heap_id);
+ RBASIC_SET_SHAPE_ID(obj, rb_obj_shape_transition_heap(obj, heap_id));
}
void rb_vm_update_references(void *ptr);
#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
@@ -400,7 +389,7 @@ void rb_vm_update_references(void *ptr);
#define RMOVED(obj) ((struct RMoved *)(obj))
#define TYPED_UPDATE_IF_MOVED(_objspace, _type, _thing) do { \
- if (rb_gc_impl_object_moved_p((_objspace), (VALUE)(_thing))) { \
+ if (gc_object_moved_p_internal((_objspace), (VALUE)(_thing))) { \
*(_type *)&(_thing) = (_type)gc_location_internal(_objspace, (VALUE)_thing); \
} \
} while (0)
@@ -482,21 +471,21 @@ rb_malloc_grow_capa(size_t current, size_t type_size)
return new_capacity;
}
-static inline struct rbimpl_size_mul_overflow_tag
+static inline struct rbimpl_size_overflow_tag
size_mul_add_overflow(size_t x, size_t y, size_t z) /* x * y + z */
{
- struct rbimpl_size_mul_overflow_tag t = rbimpl_size_mul_overflow(x, y);
- struct rbimpl_size_mul_overflow_tag u = rbimpl_size_add_overflow(t.right, z);
- return (struct rbimpl_size_mul_overflow_tag) { t.left || u.left, u.right };
+ struct rbimpl_size_overflow_tag t = rbimpl_size_mul_overflow(x, y);
+ struct rbimpl_size_overflow_tag u = rbimpl_size_add_overflow(t.result, z);
+ return (struct rbimpl_size_overflow_tag) { t.overflowed || u.overflowed, u.result };
}
-static inline struct rbimpl_size_mul_overflow_tag
+static inline struct rbimpl_size_overflow_tag
size_mul_add_mul_overflow(size_t x, size_t y, size_t z, size_t w) /* x * y + z * w */
{
- 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 = rbimpl_size_add_overflow(t.right, u.right);
- return (struct rbimpl_size_mul_overflow_tag) { t.left || u.left || v.left, v.right };
+ struct rbimpl_size_overflow_tag t = rbimpl_size_mul_overflow(x, y);
+ struct rbimpl_size_overflow_tag u = rbimpl_size_mul_overflow(z, w);
+ struct rbimpl_size_overflow_tag v = rbimpl_size_add_overflow(t.result, u.result);
+ return (struct rbimpl_size_overflow_tag) { t.overflowed || u.overflowed || v.overflowed, v.result };
}
PRINTF_ARGS(NORETURN(static void gc_raise(VALUE, const char*, ...)), 2, 3);
@@ -504,9 +493,9 @@ 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)
{
- struct rbimpl_size_mul_overflow_tag t = rbimpl_size_mul_overflow(x, y);
- if (LIKELY(!t.left)) {
- return t.right;
+ struct rbimpl_size_overflow_tag t = rbimpl_size_mul_overflow(x, y);
+ if (LIKELY(!t.overflowed)) {
+ return t.result;
}
else if (rb_during_gc()) {
rb_memerror(); /* or...? */
@@ -530,9 +519,9 @@ rb_size_mul_or_raise(size_t x, size_t y, VALUE exc)
static inline size_t
size_mul_add_or_raise(size_t x, size_t y, size_t z, VALUE exc)
{
- struct rbimpl_size_mul_overflow_tag t = size_mul_add_overflow(x, y, z);
- if (LIKELY(!t.left)) {
- return t.right;
+ struct rbimpl_size_overflow_tag t = size_mul_add_overflow(x, y, z);
+ if (LIKELY(!t.overflowed)) {
+ return t.result;
}
else if (rb_during_gc()) {
rb_memerror(); /* or...? */
@@ -557,9 +546,9 @@ rb_size_mul_add_or_raise(size_t x, size_t y, size_t z, VALUE exc)
static inline size_t
size_mul_add_mul_or_raise(size_t x, size_t y, size_t z, size_t w, VALUE exc)
{
- struct rbimpl_size_mul_overflow_tag t = size_mul_add_mul_overflow(x, y, z, w);
- if (LIKELY(!t.left)) {
- return t.right;
+ struct rbimpl_size_overflow_tag t = size_mul_add_mul_overflow(x, y, z, w);
+ if (LIKELY(!t.overflowed)) {
+ return t.result;
}
else if (rb_during_gc()) {
rb_memerror(); /* or...? */
@@ -589,6 +578,7 @@ rb_gc_guarded_ptr_val(volatile VALUE *ptr, VALUE val)
#endif
static const char *obj_type_name(VALUE obj);
+static st_table *id2ref_tbl;
#include "gc/default/default.c"
#if USE_MODULAR_GC && !defined(HAVE_DLOPEN)
@@ -619,15 +609,16 @@ typedef struct gc_function_map {
void (*config_set)(void *objspace_ptr, VALUE hash);
void (*stress_set)(void *objspace_ptr, VALUE flag);
VALUE (*stress_get)(void *objspace_ptr);
+ struct rb_gc_vm_context *(*get_vm_context)(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);
+ VALUE (*new_obj)(void *objspace_ptr, void *cache_ptr, VALUE klass, VALUE flags, 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 *(*malloc)(void *objspace_ptr, size_t size, bool gc_allowed);
+ void *(*calloc)(void *objspace_ptr, size_t size, bool gc_allowed);
+ void *(*realloc)(void *objspace_ptr, void *ptr, size_t new_size, size_t old_size, bool gc_allowed);
void (*free)(void *objspace_ptr, void *ptr, size_t old_size);
void (*adjust_memory_usage)(void *objspace_ptr, ssize_t diff);
// Marking
@@ -635,9 +626,11 @@ typedef struct gc_function_map {
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);
+ // Weak references
+ void (*declare_weak_references)(void *objspace_ptr, VALUE obj);
+ bool (*handle_weak_references_alive_p)(void *objspace_ptr, VALUE obj);
// Compaction
+ void (*register_pinning_obj)(void *objspace_ptr, VALUE obj);
bool (*object_moved_p)(void *objspace_ptr, VALUE obj);
VALUE (*location)(void *objspace_ptr, VALUE value);
// Write barriers
@@ -704,7 +697,7 @@ ruby_modular_gc_init(void)
break;
default:
fprintf(stderr, "Only alphanumeric, dash, and underscore is allowed in "RUBY_GC_LIBRARY"\n");
- exit(1);
+ exit(EXIT_FAILURE);
}
}
@@ -751,19 +744,21 @@ ruby_modular_gc_init(void)
handle = dlopen(gc_so_path, RTLD_LAZY | RTLD_GLOBAL);
if (!handle) {
fprintf(stderr, "ruby_modular_gc_init: Shared library %s cannot be opened: %s\n", gc_so_path, dlerror());
- exit(1);
+ exit(EXIT_FAILURE);
}
gc_functions.modular_gc_loaded_p = true;
}
+ unsigned int err_count = 0;
+
# define load_modular_gc_func(name) do { \
if (handle) { \
const char *func_name = "rb_gc_impl_" #name; \
gc_functions.name = dlsym(handle, func_name); \
if (!gc_functions.name) { \
fprintf(stderr, "ruby_modular_gc_init: %s function not exported by library %s\n", func_name, gc_so_path); \
- exit(1); \
+ err_count++; \
} \
} \
else { \
@@ -793,6 +788,7 @@ ruby_modular_gc_init(void)
load_modular_gc_func(config_get);
load_modular_gc_func(stress_set);
load_modular_gc_func(stress_get);
+ load_modular_gc_func(get_vm_context);
// Object allocation
load_modular_gc_func(new_obj);
load_modular_gc_func(obj_slot_size);
@@ -809,9 +805,11 @@ ruby_modular_gc_init(void)
load_modular_gc_func(mark_and_move);
load_modular_gc_func(mark_and_pin);
load_modular_gc_func(mark_maybe);
- load_modular_gc_func(mark_weak);
- load_modular_gc_func(remove_weak);
+ // Weak references
+ load_modular_gc_func(declare_weak_references);
+ load_modular_gc_func(handle_weak_references_alive_p);
// Compaction
+ load_modular_gc_func(register_pinning_obj);
load_modular_gc_func(object_moved_p);
load_modular_gc_func(location);
// Write barriers
@@ -846,6 +844,11 @@ ruby_modular_gc_init(void)
load_modular_gc_func(set_event_hook);
load_modular_gc_func(copy_attributes);
+ if (err_count > 0) {
+ fprintf(stderr, "ruby_modular_gc_init: found %u missing exports in library %s\n", err_count, gc_so_path);
+ exit(EXIT_FAILURE);
+ }
+
# undef load_modular_gc_func
rb_gc_functions = gc_functions;
@@ -873,6 +876,7 @@ ruby_modular_gc_init(void)
# 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
+# define rb_gc_impl_get_vm_context rb_gc_functions.get_vm_context
// 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
@@ -889,9 +893,11 @@ ruby_modular_gc_init(void)
# 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
+// Weak references
+# define rb_gc_impl_declare_weak_references rb_gc_functions.declare_weak_references
+# define rb_gc_impl_handle_weak_references_alive_p rb_gc_functions.handle_weak_references_alive_p
// Compaction
+# define rb_gc_impl_register_pinning_obj rb_gc_functions.register_pinning_obj
# define rb_gc_impl_object_moved_p rb_gc_functions.object_moved_p
# define rb_gc_impl_location rb_gc_functions.location
// Write barriers
@@ -971,60 +977,159 @@ rb_gc_obj_slot_size(VALUE obj)
}
static inline void
-gc_validate_pc(void)
+gc_validate_pc(VALUE obj)
{
#if RUBY_DEBUG
+ // IMEMOs and objects without a class (e.g managed id table) are not traceable
+ if (RB_TYPE_P(obj, T_IMEMO) || !CLASS_OF(obj)) return;
+
rb_execution_context_t *ec = GET_EC();
const rb_control_frame_t *cfp = ec->cfp;
- if (cfp && VM_FRAME_RUBYFRAME_P(cfp) && cfp->pc) {
- RUBY_ASSERT(cfp->pc >= ISEQ_BODY(cfp->iseq)->iseq_encoded);
- RUBY_ASSERT(cfp->pc <= ISEQ_BODY(cfp->iseq)->iseq_encoded + ISEQ_BODY(cfp->iseq)->iseq_size);
+ if (cfp && VM_FRAME_RUBYFRAME_P(cfp) && CFP_PC(cfp)) {
+ const VALUE *iseq_encoded = ISEQ_BODY(CFP_ISEQ(cfp))->iseq_encoded;
+ const VALUE *iseq_encoded_end = iseq_encoded + ISEQ_BODY(CFP_ISEQ(cfp))->iseq_size;
+ RUBY_ASSERT(CFP_PC(cfp) >= iseq_encoded, "PC not set when allocating, breaking tracing");
+ RUBY_ASSERT(CFP_PC(cfp) <= iseq_encoded_end, "PC not set when allocating, breaking tracing");
}
#endif
}
-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)
+NOINLINE(static void gc_newobj_hook(VALUE obj));
+static void
+gc_newobj_hook(VALUE obj)
{
- VALUE obj = rb_gc_impl_new_obj(rb_gc_get_objspace(), cr->newobj_cache, klass, flags, v1, v2, v3, wb_protected, size);
+ int lev = RB_GC_VM_LOCK_NO_BARRIER();
+ {
+ size_t slot_size = rb_gc_obj_slot_size(obj);
+ memset((char *)obj + sizeof(struct RBasic), 0, slot_size - sizeof(struct RBasic));
+
+ /* We must disable GC here because the callback could call xmalloc
+ * which could potentially trigger a GC, and a lot of code is unsafe
+ * to trigger a GC right after an object has been allocated because
+ * they perform initialization for the object and assume that the
+ * GC does not trigger before then. */
+ bool gc_disabled = RTEST(rb_gc_disable_no_rest());
+ {
+ rb_gc_event_hook(obj, RUBY_INTERNAL_EVENT_NEWOBJ);
+ }
+ if (!gc_disabled) rb_gc_enable();
+ }
+ RB_GC_VM_UNLOCK_NO_BARRIER(lev);
+}
+
+VALUE
+rb_newobj(rb_execution_context_t *ec, VALUE klass, VALUE flags, shape_id_t shape_id, bool wb_protected, size_t size)
+{
+ GC_ASSERT((flags & FL_WB_PROTECTED) == 0);
+ rb_ractor_t *cr = rb_ec_ractor_ptr(ec);
+ VALUE obj = rb_gc_impl_new_obj(rb_gc_get_objspace(), cr->newobj_cache, klass, flags, wb_protected, size);
+
+#if RACTOR_CHECK_MODE
+ void rb_ractor_setup_belonging(VALUE obj);
+ rb_ractor_setup_belonging(obj);
+#endif
+
+ RBASIC_SET_SHAPE_ID_NO_CHECKS(obj, shape_id);
- gc_validate_pc();
+ gc_validate_pc(obj);
if (UNLIKELY(rb_gc_event_hook_required_p(RUBY_INTERNAL_EVENT_NEWOBJ))) {
- unsigned int lev;
- RB_VM_LOCK_ENTER_CR_LEV(cr, &lev);
- {
- memset((char *)obj + RVALUE_SIZE, 0, rb_gc_obj_slot_size(obj) - RVALUE_SIZE);
-
- /* We must disable GC here because the callback could call xmalloc
- * which could potentially trigger a GC, and a lot of code is unsafe
- * to trigger a GC right after an object has been allocated because
- * they perform initialization for the object and assume that the
- * GC does not trigger before then. */
- bool gc_disabled = RTEST(rb_gc_disable_no_rest());
- {
- rb_gc_event_hook(obj, RUBY_INTERNAL_EVENT_NEWOBJ);
- }
- if (!gc_disabled) rb_gc_enable();
- }
- RB_VM_LOCK_LEAVE_CR_LEV(cr, &lev);
+ gc_newobj_hook(obj);
}
+#if RGENGC_CHECK_MODE
+# ifndef GC_DEBUG_SLOT_FILL_SPECIAL_VALUE
+# define GC_DEBUG_SLOT_FILL_SPECIAL_VALUE 255
+# endif
+
+ memset(
+ (void *)(obj + sizeof(struct RBasic)),
+ GC_DEBUG_SLOT_FILL_SPECIAL_VALUE,
+ rb_gc_obj_slot_size(obj) - sizeof(struct RBasic)
+ );
+#endif
+
return obj;
}
VALUE
-rb_wb_unprotected_newobj_of(VALUE klass, VALUE flags, size_t size)
+rb_ec_newobj_of(rb_execution_context_t *ec, 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);
+ VALUE type = flags & T_MASK;
+ RUBY_ASSERT(type != T_OBJECT);
+ RUBY_ASSERT(type != T_DATA);
+ RUBY_ASSERT(type != T_CLASS);
+ RUBY_ASSERT(type != T_MODULE);
+ RUBY_ASSERT(type != T_ICLASS);
+ (void)type;
+
+ return rb_newobj(ec, klass, flags, ROOT_SHAPE_ID | SHAPE_ID_LAYOUT_OTHER, true, size);
}
VALUE
-rb_wb_protected_newobj_of(rb_execution_context_t *ec, VALUE klass, VALUE flags, size_t size)
+rb_newobj_of_with_shape(VALUE klass, VALUE flags, shape_id_t shape_id, 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 rb_newobj(GET_EC(), klass, flags, shape_id, true, size);
+}
+
+VALUE
+rb_newobj_of(VALUE klass, VALUE flags, size_t size)
+{
+ return rb_newobj(GET_EC(), klass, flags, ROOT_SHAPE_ID | SHAPE_ID_LAYOUT_OTHER, true, size);
+}
+
+static
+VALUE class_allocate_complex_instance(VALUE klass, uint32_t capacity)
+{
+ shape_id_t initial_shape_id = rb_shape_id_with_robject_layout(rb_shape_root(rb_gc_heap_id_for_size(sizeof(struct RObject))));
+ VALUE obj = rb_newobj_of_with_shape(klass, T_OBJECT, initial_shape_id, sizeof(struct RObject));
+ rb_obj_init_complex(obj, rb_st_init_numtable_with_size(capacity));
+ return obj;
+}
+
+VALUE
+rb_class_allocate_instance(VALUE klass)
+{
+ uint32_t index_tbl_num_entries = RCLASS_MAX_IV_COUNT(klass);
+ VALUE obj;
+
+ // Directly start as COMPLEX if we know we're over the limit.
+ RUBY_ASSERT(rb_shape_tree.max_capacity > 0);
+ if (RB_UNLIKELY(index_tbl_num_entries > rb_shape_tree.max_capacity)) {
+ obj = class_allocate_complex_instance(klass, index_tbl_num_entries);
+ }
+ else {
+ size_t size = rb_obj_embedded_size(index_tbl_num_entries);
+ if (!rb_gc_size_allocatable_p(size)) {
+ size = sizeof(struct RObject);
+ }
+
+ // There might be a NEWOBJ tracepoint callback, and it may set fields.
+ // So the shape must be passed to `NEWOBJ_OF`.
+ obj = rb_newobj_of_with_shape(klass, T_OBJECT, rb_shape_id_with_robject_layout(rb_shape_root(rb_gc_heap_id_for_size(size))), size);
+
+ #if RUBY_DEBUG
+ VALUE *ptr = ROBJECT_FIELDS(obj);
+ size_t fields_count = RSHAPE_LEN(RBASIC_SHAPE_ID(obj));
+ for (size_t i = fields_count; i < ROBJECT_FIELDS_CAPACITY(obj); i++) {
+ ptr[i] = Qundef;
+ }
+ #endif
+ }
+
+#if RUBY_DEBUG
+ if (rb_obj_class(obj) != rb_class_real(klass)) {
+ rb_bug("Expected rb_class_allocate_instance to set the class correctly");
+ }
+#endif
+
+ return obj;
+}
+
+void
+rb_gc_register_pinning_obj(VALUE obj)
+{
+ rb_gc_impl_register_pinning_obj(rb_gc_get_objspace(), obj);
}
#define UNEXPECTED_NODE(func) \
@@ -1034,27 +1139,16 @@ rb_wb_protected_newobj_of(rb_execution_context_t *ec, VALUE klass, VALUE flags,
static inline void
rb_data_object_check(VALUE klass)
{
+ RUBY_ASSERT(!RCLASS_SINGLETON_P(klass));
if (klass != rb_cObject && (rb_get_alloc_func(klass) == rb_class_allocate_instance)) {
rb_undef_alloc_func(klass);
rb_warn("undefining the allocator of T_DATA class %"PRIsVALUE, klass);
}
}
-VALUE
-rb_data_object_wrap(VALUE klass, void *datap, RUBY_DATA_FUNC dmark, RUBY_DATA_FUNC dfree)
-{
- 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));
-}
-
-VALUE
-rb_data_object_zalloc(VALUE klass, size_t size, RUBY_DATA_FUNC dmark, RUBY_DATA_FUNC dfree)
-{
- VALUE obj = rb_data_object_wrap(klass, 0, dmark, dfree);
- DATA_PTR(obj) = xcalloc(1, size);
- return obj;
-}
+#define RTYPEDDATA_EMBEDDED_P rbimpl_typeddata_embedded_p
+#define RB_DATA_TYPE_EMBEDDABLE_P(type) ((type)->flags & RUBY_TYPED_EMBEDDABLE)
+#define RTYPEDDATA_EMBEDDABLE_P(obj) RB_DATA_TYPE_EMBEDDABLE_P(RTYPEDDATA_TYPE(obj))
static VALUE
typed_data_alloc(VALUE klass, VALUE typed_flag, void *datap, const rb_data_type_t *type, size_t size)
@@ -1062,13 +1156,22 @@ typed_data_alloc(VALUE klass, VALUE typed_flag, void *datap, const rb_data_type_
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, 0, ((VALUE)type) | IS_TYPED_DATA | typed_flag, (VALUE)datap, wb_protected, size);
+ VALUE obj = rb_newobj(GET_EC(), klass, T_DATA, ROOT_SHAPE_ID | SHAPE_ID_LAYOUT_RDATA, wb_protected, size);
+
+ rb_gc_register_pinning_obj(obj);
+
+ struct RTypedData *data = (struct RTypedData *)obj;
+ data->fields_obj = 0;
+ *(VALUE *)&data->type = ((VALUE)type) | typed_flag;
+ data->data = datap;
+
+ return obj;
}
VALUE
rb_data_typed_object_wrap(VALUE klass, void *datap, const rb_data_type_t *type)
{
- if (UNLIKELY(type->flags & RUBY_TYPED_EMBEDDABLE)) {
+ if (UNLIKELY(RB_DATA_TYPE_EMBEDDABLE_P(type))) {
rb_raise(rb_eTypeError, "Cannot wrap an embeddable TypedData");
}
@@ -1078,7 +1181,7 @@ rb_data_typed_object_wrap(VALUE klass, void *datap, const rb_data_type_t *type)
VALUE
rb_data_typed_object_zalloc(VALUE klass, size_t size, const rb_data_type_t *type)
{
- if (type->flags & RUBY_TYPED_EMBEDDABLE) {
+ if (RB_DATA_TYPE_EMBEDDABLE_P(type)) {
if (!(type->flags & RUBY_TYPED_FREE_IMMEDIATELY)) {
rb_raise(rb_eTypeError, "Embeddable TypedData must be freed immediately");
}
@@ -1097,20 +1200,33 @@ rb_data_typed_object_zalloc(VALUE klass, size_t size, const rb_data_type_t *type
}
static size_t
+ruby_xmalloc_usable_size(void *ptr)
+{
+#ifdef HAVE_MALLOC_USABLE_SIZE
+#if CALC_EXACT_MALLOC_SIZE
+ struct malloc_obj_info *info = (struct malloc_obj_info *)ptr - 1;
+ return malloc_usable_size(info) - sizeof(struct malloc_obj_info);
+#else
+ return malloc_usable_size(ptr);
+#endif
+#else
+ return 0;
+#endif
+}
+
+static 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);
+ 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
+ if (ptr) {
+ if (RTYPEDDATA_EMBEDDABLE_P(obj) && !RTYPEDDATA_EMBEDDED_P(obj)) {
+ size += ruby_xmalloc_usable_size((void *)ptr);
}
- if (ptr && type->function.dsize) {
+ const rb_data_type_t *type = RTYPEDDATA_TYPE(obj);
+ if (type->function.dsize) {
size += type->function.dsize(ptr);
}
}
@@ -1121,19 +1237,207 @@ rb_objspace_data_type_memsize(VALUE obj)
const char *
rb_objspace_data_type_name(VALUE obj)
{
- if (RTYPEDDATA_P(obj)) {
- return RTYPEDDATA_TYPE(obj)->wrap_struct_name;
+ return RTYPEDDATA_TYPE(obj)->wrap_struct_name;
+}
+
+void
+rb_gc_declare_weak_references(VALUE obj)
+{
+ rb_gc_impl_declare_weak_references(rb_gc_get_objspace(), obj);
+}
+
+bool
+rb_gc_handle_weak_references_alive_p(VALUE obj)
+{
+ if (SPECIAL_CONST_P(obj)) return true;
+
+ return rb_gc_impl_handle_weak_references_alive_p(rb_gc_get_objspace(), obj);
+}
+
+void
+rb_gc_handle_weak_references(VALUE obj)
+{
+ switch (BUILTIN_TYPE(obj)) {
+ case T_DATA:
+ {
+ const rb_data_type_t *type = RTYPEDDATA_TYPE(obj);
+
+ if (type->function.handle_weak_references) {
+ (type->function.handle_weak_references)(RTYPEDDATA_GET_DATA(obj));
+ }
+ else {
+ rb_bug(
+ "rb_gc_handle_weak_references: TypedData %s does not implement handle_weak_references",
+ RTYPEDDATA_TYPE(obj)->wrap_struct_name
+ );
+ }
+ }
+ break;
+
+ case T_IMEMO: {
+ switch (imemo_type(obj)) {
+ case imemo_callcache: {
+ struct rb_callcache *cc = (struct rb_callcache *)obj;
+ if (cc->klass != Qundef &&
+ (!rb_gc_handle_weak_references_alive_p(cc->klass) ||
+ !rb_gc_handle_weak_references_alive_p((VALUE)cc->cme_))) {
+ vm_cc_invalidate(cc);
+ }
+ break;
+ }
+ case imemo_subclasses: {
+ struct rb_subclasses *subs = (struct rb_subclasses *)obj;
+ VALUE *entries = rb_imemo_subclasses_entries(obj);
+ for (uint32_t i = 0; i < subs->count; i++) {
+ if (entries[i] && !rb_gc_handle_weak_references_alive_p(entries[i])) {
+ entries[i] = 0;
+ }
+ }
+ break;
+ }
+ default:
+ rb_bug("rb_gc_handle_weak_references: unexpected imemo type");
+ }
+
+ break;
+ }
+ default:
+ rb_bug("rb_gc_handle_weak_references: type not supported\n");
}
- else {
- return 0;
+}
+
+static inline bool
+rb_gc_imemo_needs_cleanup_p(VALUE obj)
+{
+ switch (imemo_type(obj)) {
+ case imemo_constcache:
+ case imemo_cref:
+ case imemo_ifunc:
+ case imemo_memo:
+ case imemo_svar:
+ case imemo_callcache:
+ case imemo_throw_data:
+ case imemo_cvar_entry:
+ return false;
+
+ case imemo_env:
+ case imemo_ment:
+ case imemo_iseq:
+ case imemo_callinfo:
+ case imemo_cdhash:
+ return true;
+
+ case imemo_subclasses:
+ return FL_TEST_RAW(obj, IMEMO_SUBCLASSES_HEAP);
+
+ case imemo_tmpbuf:
+ return ((rb_imemo_tmpbuf_t *)obj)->ptr != NULL;
+
+ case imemo_fields:
+ return FL_TEST_RAW(obj, OBJ_FIELD_HEAP) || (id2ref_tbl && rb_obj_shape_has_id(obj));
}
+ UNREACHABLE_RETURN(true);
}
-static enum rb_id_table_iterator_result
-cvar_table_free_i(VALUE value, void *ctx)
+/*
+ * Returns true if the object requires a full rb_gc_obj_free() call during sweep,
+ * false if it can be freed quickly without calling destructors or cleanup.
+ *
+ * Objects that return false are:
+ * - Simple embedded objects without external allocations
+ * - Objects without finalizers
+ * - Objects without object IDs registered in id2ref
+ * - Objects without generic instance variables
+ *
+ * This is used by the GC sweep fast path to avoid function call overhead
+ * for the majority of simple objects.
+ */
+bool
+rb_gc_obj_needs_cleanup_p(VALUE obj)
{
- xfree((void *)value);
- return ID_TABLE_CONTINUE;
+ VALUE flags = RBASIC(obj)->flags;
+
+ if (flags & FL_FINALIZE) return true;
+
+ switch (flags & RUBY_T_MASK) {
+ case T_IMEMO:
+ return rb_gc_imemo_needs_cleanup_p(obj);
+
+ case T_DATA:
+ case T_OBJECT:
+ case T_STRING:
+ case T_ARRAY:
+ case T_HASH:
+ case T_BIGNUM:
+ case T_STRUCT:
+ case T_FLOAT:
+ case T_RATIONAL:
+ case T_COMPLEX:
+ case T_MATCH:
+ break;
+
+ case T_FILE:
+ case T_SYMBOL:
+ case T_CLASS:
+ case T_ICLASS:
+ case T_MODULE:
+ case T_REGEXP:
+ return true;
+ }
+
+ shape_id_t shape_id = RBASIC_SHAPE_ID(obj);
+ if (id2ref_tbl && rb_shape_has_object_id(shape_id)) return true;
+
+ switch (flags & RUBY_T_MASK) {
+ case T_OBJECT:
+ if (flags & ROBJECT_HEAP) return true;
+ return false;
+
+ case T_DATA:
+ {
+ uintptr_t type = (uintptr_t)RTYPEDDATA(obj)->type;
+ if (type & TYPED_DATA_EMBEDDED) {
+ RUBY_DATA_FUNC dfree = ((const rb_data_type_t *)(type & TYPED_DATA_PTR_MASK))->function.dfree;
+ if (dfree == RUBY_NEVER_FREE || dfree == RUBY_TYPED_DEFAULT_FREE) {
+ return false;
+ }
+ }
+ }
+ return true;
+
+ case T_STRING:
+ if (flags & (RSTRING_NOEMBED | RSTRING_FSTR)) return true;
+ return rb_shape_has_fields(shape_id);
+
+ case T_ARRAY:
+ if (!(flags & RARRAY_EMBED_FLAG)) return true;
+ return rb_shape_has_fields(shape_id);
+
+ case T_HASH:
+ if (flags & RHASH_ST_TABLE_FLAG) return true;
+ return rb_shape_has_fields(shape_id);
+
+ case T_MATCH:
+ if ((flags & (RMATCH_ONIG | RMATCH_OFFSETS_EXTERNAL)) || USE_DEBUG_COUNTER) return true;
+ return rb_shape_has_fields(shape_id);
+
+ case T_BIGNUM:
+ if (!(flags & BIGNUM_EMBED_FLAG)) return true;
+ return rb_shape_has_fields(shape_id);
+
+ case T_STRUCT:
+ if (!(flags & RSTRUCT_EMBED_LEN_MASK)) return true;
+ if (flags & RSTRUCT_GEN_FIELDS) return rb_shape_has_fields(shape_id);
+ return false;
+
+ case T_FLOAT:
+ case T_RATIONAL:
+ case T_COMPLEX:
+ return rb_shape_has_fields(shape_id);
+
+ default:
+ UNREACHABLE_RETURN(true);
+ }
}
static void
@@ -1152,29 +1456,24 @@ make_io_zombie(void *objspace, VALUE obj)
static bool
rb_data_free(void *objspace, VALUE obj)
{
- void *data = RTYPEDDATA_P(obj) ? RTYPEDDATA_GET_DATA(obj) : DATA_PTR(obj);
+ void *data = RTYPEDDATA_GET_DATA(obj);
if (data) {
int free_immediately = false;
void (*dfree)(void *);
- if (RTYPEDDATA_P(obj)) {
- free_immediately = (RTYPEDDATA_TYPE(obj)->flags & RUBY_TYPED_FREE_IMMEDIATELY) != 0;
- dfree = RTYPEDDATA_TYPE(obj)->function.dfree;
- }
- else {
- dfree = RDATA(obj)->dfree;
- }
+ free_immediately = (RTYPEDDATA_TYPE(obj)->flags & RUBY_TYPED_FREE_IMMEDIATELY) != 0;
+ dfree = RTYPEDDATA_TYPE(obj)->function.dfree;
if (dfree) {
if (dfree == RUBY_DEFAULT_FREE) {
- if (!RTYPEDDATA_P(obj) || !RTYPEDDATA_EMBEDDED_P(obj)) {
+ if (!RTYPEDDATA_EMBEDDED_P(obj)) {
xfree(data);
RB_DEBUG_COUNTER_INC(obj_data_xfree);
}
}
else if (free_immediately) {
(*dfree)(data);
- if (RTYPEDDATA_TYPE(obj)->flags & RUBY_TYPED_EMBEDDABLE && !RTYPEDDATA_EMBEDDED_P(obj)) {
+ if (RTYPEDDATA_EMBEDDABLE_P(obj) && !RTYPEDDATA_EMBEDDED_P(obj)) {
xfree(data);
}
@@ -1200,48 +1499,19 @@ struct classext_foreach_args {
};
static void
-classext_free(rb_classext_t *ext, bool is_prime, VALUE namespace, void *arg)
+classext_free(rb_classext_t *ext, bool is_prime, VALUE box_value, void *arg)
{
- struct rb_id_table *tbl;
struct classext_foreach_args *args = (struct classext_foreach_args *)arg;
- rb_id_table_free(RCLASSEXT_M_TBL(ext));
-
- if (!RCLASSEXT_SHARED_CONST_TBL(ext) && (tbl = RCLASSEXT_CONST_TBL(ext)) != NULL) {
- rb_free_const_table(tbl);
- }
- if ((tbl = RCLASSEXT_CVC_TBL(ext)) != NULL) {
- rb_id_table_foreach_values(tbl, cvar_table_free_i, NULL);
- rb_id_table_free(tbl);
- }
- rb_class_classext_free_subclasses(ext, args->klass);
- if (RCLASSEXT_SUPERCLASSES_WITH_SELF(ext)) {
- RUBY_ASSERT(is_prime); // superclasses should only be used on prime
- xfree(RCLASSEXT_SUPERCLASSES(ext));
- }
- if (!is_prime) { // the prime classext will be freed with RClass
- xfree(ext);
- }
+ rb_class_classext_free(args->klass, ext, is_prime);
}
static void
-classext_iclass_free(rb_classext_t *ext, bool is_prime, VALUE namespace, void *arg)
+classext_iclass_free(rb_classext_t *ext, bool is_prime, VALUE box_value, void *arg)
{
struct classext_foreach_args *args = (struct classext_foreach_args *)arg;
- if (RCLASSEXT_ICLASS_IS_ORIGIN(ext) && !RCLASSEXT_ICLASS_ORIGIN_SHARED_MTBL(ext)) {
- /* Method table is not shared for origin iclasses of classes */
- rb_id_table_free(RCLASSEXT_M_TBL(ext));
- }
- if (RCLASSEXT_CALLABLE_M_TBL(ext) != NULL) {
- rb_id_table_free(RCLASSEXT_CALLABLE_M_TBL(ext));
- }
-
- rb_class_classext_free_subclasses(ext, args->klass);
-
- if (!is_prime) { // the prime classext will be freed with RClass
- xfree(ext);
- }
+ rb_iclass_classext_free(args->klass, ext, is_prime);
}
bool
@@ -1264,20 +1534,25 @@ rb_gc_obj_free(void *objspace, VALUE obj)
switch (BUILTIN_TYPE(obj)) {
case T_OBJECT:
- if (rb_shape_obj_too_complex_p(obj)) {
- RB_DEBUG_COUNTER_INC(obj_obj_too_complex);
- st_free_table(ROBJECT_FIELDS_HASH(obj));
- }
- else if (RBASIC(obj)->flags & ROBJECT_EMBED) {
- RB_DEBUG_COUNTER_INC(obj_obj_embed);
+ if (FL_TEST_RAW(obj, ROBJECT_HEAP)) {
+ if (rb_obj_shape_complex_p(obj)) {
+ RB_DEBUG_COUNTER_INC(obj_obj_complex);
+ st_free_table(ROBJECT_FIELDS_HASH(obj));
+ }
+ else {
+ SIZED_FREE_N(ROBJECT(obj)->as.heap.fields, ROBJECT_FIELDS_CAPACITY(obj));
+ RB_DEBUG_COUNTER_INC(obj_obj_ptr);
+ }
}
else {
- xfree(ROBJECT(obj)->as.heap.fields);
- RB_DEBUG_COUNTER_INC(obj_obj_ptr);
+ RB_DEBUG_COUNTER_INC(obj_obj_embed);
}
break;
case T_MODULE:
case T_CLASS:
+#if USE_ZJIT
+ rb_zjit_klass_free(obj);
+#endif
args.klass = obj;
rb_class_classext_foreach(obj, classext_free, (void *)&args);
if (RCLASS_CLASSEXT_TBL(obj)) {
@@ -1347,29 +1622,32 @@ rb_gc_obj_free(void *objspace, VALUE obj)
break;
case T_MATCH:
{
- rb_matchext_t *rm = RMATCH_EXT(obj);
+ struct RMatch *rm = RMATCH(obj);
#if USE_DEBUG_COUNTER
- if (rm->regs.num_regs >= 8) {
+ if (rm->num_regs >= 8) {
RB_DEBUG_COUNTER_INC(obj_match_ge8);
}
- else if (rm->regs.num_regs >= 4) {
+ else if (rm->num_regs >= 4) {
RB_DEBUG_COUNTER_INC(obj_match_ge4);
}
- else if (rm->regs.num_regs >= 1) {
+ else if (rm->num_regs >= 1) {
RB_DEBUG_COUNTER_INC(obj_match_under4);
}
#endif
- onig_region_free(&rm->regs, 0);
- xfree(rm->char_offset);
+ if (FL_TEST_RAW(obj, RMATCH_ONIG)) {
+ onig_region_free(&rm->as.onig, 0);
+ }
+ SIZED_FREE_N(rm->char_offset, rm->char_offset_num_allocated);
RB_DEBUG_COUNTER_INC(obj_match_ptr);
}
break;
case T_FILE:
if (RFILE(obj)->fptr) {
- make_io_zombie(objspace, obj);
+ bool closed = rb_io_fptr_finalize_closed(RFILE(obj)->fptr);
+ if (!closed) make_io_zombie(objspace, obj);
RB_DEBUG_COUNTER_INC(obj_file_ptr);
- return FALSE;
+ return closed;
}
break;
case T_RATIONAL:
@@ -1397,7 +1675,7 @@ rb_gc_obj_free(void *objspace, VALUE obj)
case T_BIGNUM:
if (!BIGNUM_EMBED_P(obj) && BIGNUM_DIGITS(obj)) {
- xfree(BIGNUM_DIGITS(obj));
+ SIZED_FREE_N(BIGNUM_DIGITS(obj), BIGNUM_LEN(obj));
RB_DEBUG_COUNTER_INC(obj_bignum_ptr);
}
else {
@@ -1415,7 +1693,7 @@ rb_gc_obj_free(void *objspace, VALUE obj)
RB_DEBUG_COUNTER_INC(obj_struct_embed);
}
else {
- xfree((void *)RSTRUCT(obj)->as.heap.ptr);
+ SIZED_FREE_N(RSTRUCT(obj)->as.heap.ptr, RSTRUCT(obj)->as.heap.len);
RB_DEBUG_COUNTER_INC(obj_struct_ptr);
}
break;
@@ -1535,34 +1813,26 @@ os_obj_of(VALUE of)
* Ruby process. If <i>module</i> is specified, calls the block
* for only those classes or modules that match (or are a subclass of)
* <i>module</i>. Returns the number of objects found. Immediate
- * objects (<code>Fixnum</code>s, <code>Symbol</code>s
- * <code>true</code>, <code>false</code>, and <code>nil</code>) are
- * never returned. In the example below, #each_object returns both
- * the numbers we defined and several constants defined in the Math
- * module.
+ * objects (such as <code>Fixnum</code>s, static <code>Symbol</code>s
+ * <code>true</code>, <code>false</code> and <code>nil</code>) are
+ * never returned.
*
* If no block is given, an enumerator is returned instead.
*
- * a = 102.7
- * b = 95 # Won't be returned
- * c = 12345678987654321
- * count = ObjectSpace.each_object(Numeric) {|x| p x }
+ * Job = Class.new
+ * jobs = [Job.new, Job.new]
+ * count = ObjectSpace.each_object(Job) {|x| p x }
* puts "Total count: #{count}"
*
* <em>produces:</em>
*
- * 12345678987654321
- * 102.7
- * 2.71828182845905
- * 3.14159265358979
- * 2.22044604925031e-16
- * 1.7976931348623157e+308
- * 2.2250738585072e-308
- * Total count: 7
+ * #<Job:0x000000011d6cbbf0>
+ * #<Job:0x000000011d6cbc68>
+ * Total count: 2
*
- * Due to a current known Ractor implementation issue, this method will not yield
- * Ractor-unshareable objects in multi-Ractor mode (when
- * <code>Ractor.new</code> has been called within the process at least once).
+ * Due to a current Ractor implementation issue, this method does not yield
+ * Ractor-unshareable objects when the process is in multi-Ractor mode. Multi-ractor
+ * mode is enabled when <code>Ractor.new</code> has been called for the first time.
* See https://bugs.ruby-lang.org/issues/19387 for more information.
*
* a = 12345678987654321 # shareable
@@ -1586,10 +1856,12 @@ os_each_obj(int argc, VALUE *argv, VALUE os)
/*
* call-seq:
- * ObjectSpace.undefine_finalizer(obj)
+ * ObjectSpace.undefine_finalizer(obj) -> obj
*
- * Removes all finalizers for <i>obj</i>.
+ * Removes all finalizers registered for +obj+ with
+ * ObjectSpace.define_finalizer, and returns +obj+.
*
+ * Does nothing if +obj+ has no finalizers.
*/
static VALUE
@@ -1635,63 +1907,68 @@ rb_gc_copy_finalizer(VALUE dest, VALUE obj)
/*
* call-seq:
- * ObjectSpace.define_finalizer(obj, aProc=proc())
+ * ObjectSpace.define_finalizer(obj) {|id| ... } -> array
+ * ObjectSpace.define_finalizer(obj, finalizer) -> array
*
- * Adds <i>aProc</i> as a finalizer, to be called after <i>obj</i>
- * was destroyed. The object ID of the <i>obj</i> will be passed
- * as an argument to <i>aProc</i>. If <i>aProc</i> is a lambda or
- * method, make sure it can be called with a single argument.
+ * Adds a new finalizer for +obj+ that is called when +obj+ is destroyed
+ * by the garbage collector or when Ruby shuts down (which ever comes first).
*
- * The return value is an array <code>[0, aProc]</code>.
+ * With a block given, uses the block as the callback. Without a block given,
+ * uses a callable object +finalizer+ as the callback. The callback is called
+ * when +obj+ is destroyed with a single argument +id+ which is the object
+ * ID of +obj+ (see Object#object_id).
*
- * The two recommended patterns are to either create the finaliser proc
- * in a non-instance method where it can safely capture the needed state,
- * or to use a custom callable object that stores the needed state
- * explicitly as instance variables.
+ * The return value is an array <code>[0, callback]</code>, where +callback+
+ * is a Proc created from the block if one was given or +finalizer+ otherwise.
*
- * class Foo
- * def initialize(data_needed_for_finalization)
- * ObjectSpace.define_finalizer(self, self.class.create_finalizer(data_needed_for_finalization))
- * end
+ * Note that defining a finalizer in an instance method of the object may prevent
+ * the object from being garbage collected since if the block or +finalizer+ refers
+ * to +obj+ then +obj+ will never be reclaimed by the garbage collector. For example,
+ * the following script demonstrates the issue:
*
- * def self.create_finalizer(data_needed_for_finalization)
- * proc {
- * puts "finalizing #{data_needed_for_finalization}"
- * }
+ * class Foo
+ * def define_final
+ * ObjectSpace.define_finalizer(self) do |id|
+ * puts "Running finalizer for #{id}!"
+ * end
* end
* end
*
- * class Bar
- * class Remover
- * def initialize(data_needed_for_finalization)
- * @data_needed_for_finalization = data_needed_for_finalization
- * end
+ * obj = Foo.new
+ * obj.define_final
*
- * def call(id)
- * puts "finalizing #{@data_needed_for_finalization}"
- * end
+ * There are two patterns to solve this issue:
+ *
+ * - Create the finalizer in a non-instance method so it can safely capture
+ * the needed state:
+ *
+ * class Foo
+ * def define_final
+ * ObjectSpace.define_finalizer(self, self.class.create_finalizer)
* end
*
- * def initialize(data_needed_for_finalization)
- * ObjectSpace.define_finalizer(self, Remover.new(data_needed_for_finalization))
+ * def self.create_finalizer
+ * proc do |id|
+ * puts "Running finalizer for #{id}!"
+ * end
* end
* end
*
- * Note that if your finalizer references the object to be
- * finalized it will never be run on GC, although it will still be
- * run at exit. You will get a warning if you capture the object
- * to be finalized as the receiver of the finalizer.
+ * - Use a callable object:
*
- * class CapturesSelf
- * def initialize(name)
- * ObjectSpace.define_finalizer(self, proc {
- * # this finalizer will only be run on exit
- * puts "finalizing #{name}"
- * })
+ * class Foo
+ * class Finalizer
+ * def call(id)
+ * puts "Running finalizer for #{id}!"
+ * end
+ * end
+ *
+ * def define_final
+ * ObjectSpace.define_finalizer(self, Finalizer.new)
* end
* end
*
- * Also note that finalization can be unpredictable and is never guaranteed
+ * Note that finalization can be unpredictable and is never guaranteed
* to be run except on exit.
*/
@@ -1752,7 +2029,6 @@ rb_gc_pointer_to_heap_p(VALUE obj)
#define OBJ_ID_INCREMENT (RUBY_IMMEDIATE_MASK + 1)
#define LAST_OBJECT_ID() (object_id_counter * OBJ_ID_INCREMENT)
static VALUE id2ref_value = 0;
-static st_table *id2ref_tbl = NULL;
#if SIZEOF_SIZE_T == SIZEOF_LONG_LONG
static size_t object_id_counter = 1;
@@ -1814,7 +2090,7 @@ id2ref_tbl_mark(void *data)
// It's very unlikely, but if enough object ids were generated, keys may be T_BIGNUM
rb_mark_set(table);
}
- // We purposedly don't mark values, as they are weak references.
+ // We purposely don't mark values, as they are weak references.
// rb_gc_obj_free_vm_weak_references takes care of cleaning them up.
}
@@ -1867,8 +2143,8 @@ static inline VALUE
object_id_get(VALUE obj, shape_id_t shape_id)
{
VALUE id;
- if (rb_shape_too_complex_p(shape_id)) {
- id = rb_obj_field_get(obj, ROOT_TOO_COMPLEX_WITH_OBJ_ID);
+ if (rb_shape_complex_p(shape_id)) {
+ id = rb_obj_field_get(obj, ROOT_COMPLEX_WITH_OBJ_ID);
}
else {
id = rb_obj_field_get(obj, rb_shape_object_id(shape_id));
@@ -1894,16 +2170,18 @@ object_id0(VALUE obj)
return object_id_get(obj, shape_id);
}
- shape_id_t object_id_shape_id = rb_shape_transition_object_id(obj);
+ shape_id_t object_id_shape_id = rb_obj_shape_transition_object_id(obj);
id = generate_next_object_id();
rb_obj_field_set(obj, object_id_shape_id, 0, id);
RUBY_ASSERT(RBASIC_SHAPE_ID(obj) == object_id_shape_id);
- RUBY_ASSERT(rb_shape_obj_has_id(obj));
+ RUBY_ASSERT(rb_obj_shape_has_id(obj));
if (RB_UNLIKELY(id2ref_tbl)) {
- st_insert(id2ref_tbl, (st_data_t)id, (st_data_t)obj);
+ RB_VM_LOCKING() {
+ st_insert(id2ref_tbl, (st_data_t)id, (st_data_t)obj);
+ }
}
return id;
}
@@ -1914,8 +2192,8 @@ object_id(VALUE obj)
switch (BUILTIN_TYPE(obj)) {
case T_CLASS:
case T_MODULE:
- // With namespaces, classes and modules have different fields
- // in different namespaces, so we cannot store the object id
+ // With Ruby Box, classes and modules have different fields
+ // in different boxes, so we cannot store the object id
// in fields.
return class_object_id(obj);
case T_IMEMO:
@@ -1950,13 +2228,13 @@ build_id2ref_i(VALUE obj, void *data)
break;
case T_IMEMO:
RUBY_ASSERT(!rb_objspace_garbage_object_p(obj));
- if (IMEMO_TYPE_P(obj, imemo_fields) && rb_shape_obj_has_id(obj)) {
+ if (IMEMO_TYPE_P(obj, imemo_fields) && rb_obj_shape_has_id(obj)) {
st_insert(id2ref_tbl, rb_obj_id(obj), rb_imemo_fields_owner(obj));
}
break;
case T_OBJECT:
RUBY_ASSERT(!rb_objspace_garbage_object_p(obj));
- if (rb_shape_obj_has_id(obj)) {
+ if (rb_obj_shape_has_id(obj)) {
st_insert(id2ref_tbl, rb_obj_id(obj), obj);
}
break;
@@ -2057,9 +2335,10 @@ obj_free_object_id(VALUE obj)
void
rb_gc_obj_free_vm_weak_references(VALUE obj)
{
+ ASSUME(!RB_SPECIAL_CONST_P(obj));
obj_free_object_id(obj);
- if (rb_obj_exivar_p(obj)) {
+ if (rb_obj_gen_fields_p(obj)) {
rb_free_generic_ivar(obj);
}
@@ -2074,15 +2353,6 @@ rb_gc_obj_free_vm_weak_references(VALUE obj)
break;
case T_IMEMO:
switch (imemo_type(obj)) {
- case imemo_callcache: {
- const struct rb_callcache *cc = (const struct rb_callcache *)obj;
-
- if (vm_cc_refinement_p(cc)) {
- rb_vm_delete_cc_refinement(cc);
- }
-
- break;
- }
case imemo_callinfo:
rb_vm_ci_free((const struct rb_callinfo *)obj);
break;
@@ -2118,14 +2388,9 @@ rb_gc_obj_free_vm_weak_references(VALUE obj)
static VALUE
id2ref(VALUE objid)
{
-#if SIZEOF_LONG == SIZEOF_VOIDP
-#define NUM2PTR(x) NUM2ULONG(x)
-#elif SIZEOF_LONG_LONG == SIZEOF_VOIDP
-#define NUM2PTR(x) NUM2ULL(x)
-#endif
objid = rb_to_int(objid);
if (FIXNUM_P(objid) || rb_big_size(objid) <= SIZEOF_VOIDP) {
- VALUE ptr = NUM2PTR(objid);
+ VALUE ptr = (VALUE)NUM2PTR(objid);
if (SPECIAL_CONST_P(ptr)) {
if (ptr == Qtrue) return Qtrue;
if (ptr == Qfalse) return Qfalse;
@@ -2236,7 +2501,7 @@ rb_obj_id(VALUE obj)
bool
rb_obj_id_p(VALUE obj)
{
- return !RB_TYPE_P(obj, T_IMEMO) && rb_shape_obj_has_id(obj);
+ return !RB_TYPE_P(obj, T_IMEMO) && rb_obj_shape_has_id(obj);
}
/*
@@ -2251,6 +2516,9 @@ rb_gc_before_updating_jit_code(void)
#if USE_YJIT
rb_yjit_mark_all_writeable();
#endif
+#if USE_ZJIT
+ rb_zjit_mark_all_writable();
+#endif
}
/*
@@ -2264,10 +2532,13 @@ rb_gc_after_updating_jit_code(void)
#if USE_YJIT
rb_yjit_mark_all_executable();
#endif
+#if USE_ZJIT
+ rb_zjit_mark_all_executable();
+#endif
}
static void
-classext_memsize(rb_classext_t *ext, bool prime, VALUE namespace, void *arg)
+classext_memsize(rb_classext_t *ext, bool prime, VALUE box_value, void *arg)
{
size_t *size = (size_t *)arg;
size_t s = 0;
@@ -2275,9 +2546,6 @@ classext_memsize(rb_classext_t *ext, bool prime, VALUE namespace, void *arg)
if (RCLASSEXT_M_TBL(ext)) {
s += rb_id_table_memsize(RCLASSEXT_M_TBL(ext));
}
- if (RCLASSEXT_CVC_TBL(ext)) {
- s += rb_id_table_memsize(RCLASSEXT_CVC_TBL(ext));
- }
if (RCLASSEXT_CONST_TBL(ext)) {
s += rb_id_table_memsize(RCLASSEXT_CONST_TBL(ext));
}
@@ -2291,7 +2559,7 @@ classext_memsize(rb_classext_t *ext, bool prime, VALUE namespace, void *arg)
}
static void
-classext_superclasses_memsize(rb_classext_t *ext, bool prime, VALUE namespace, void *arg)
+classext_superclasses_memsize(rb_classext_t *ext, bool prime, VALUE box_value, void *arg)
{
size_t *size = (size_t *)arg;
size_t array_size;
@@ -2313,11 +2581,13 @@ rb_obj_memsize_of(VALUE obj)
switch (BUILTIN_TYPE(obj)) {
case T_OBJECT:
- if (rb_shape_obj_too_complex_p(obj)) {
- size += rb_st_memsize(ROBJECT_FIELDS_HASH(obj));
- }
- else if (!(RBASIC(obj)->flags & ROBJECT_EMBED)) {
- size += ROBJECT_FIELDS_CAPACITY(obj) * sizeof(VALUE);
+ if (FL_TEST_RAW(obj, ROBJECT_HEAP)) {
+ if (rb_obj_shape_complex_p(obj)) {
+ size += rb_st_memsize(ROBJECT_FIELDS_HASH(obj));
+ }
+ else {
+ size += ROBJECT_FIELDS_CAPACITY(obj) * sizeof(VALUE);
+ }
}
break;
case T_MODULE:
@@ -2355,8 +2625,10 @@ rb_obj_memsize_of(VALUE obj)
break;
case T_MATCH:
{
- rb_matchext_t *rm = RMATCH_EXT(obj);
- size += onig_region_memsize(&rm->regs);
+ struct RMatch *rm = RMATCH(obj);
+ if (FL_TEST_RAW(obj, RMATCH_ONIG)) {
+ size += onig_region_memsize(&rm->as.onig);
+ }
size += sizeof(struct rmatch_offset) * rm->char_offset_num_allocated;
}
break;
@@ -2387,9 +2659,8 @@ rb_obj_memsize_of(VALUE obj)
break;
case T_STRUCT:
- if ((RBASIC(obj)->flags & RSTRUCT_EMBED_LEN_MASK) == 0 &&
- RSTRUCT(obj)->as.heap.ptr) {
- size += sizeof(VALUE) * RSTRUCT_LEN(obj);
+ if (RSTRUCT_EMBED_LEN(obj) == 0) {
+ size += sizeof(VALUE) * RSTRUCT_LEN_RAW(obj);
}
break;
@@ -2437,34 +2708,39 @@ count_objects_i(VALUE obj, void *d)
/*
* call-seq:
- * ObjectSpace.count_objects([result_hash]) -> hash
+ * ObjectSpace.count_objects(result_hash = {}) -> hash
*
- * Counts all objects grouped by type.
+ * Counts the number of objects, grouped by type.
*
- * It returns a hash, such as:
- * {
- * :TOTAL=>10000,
- * :FREE=>3011,
- * :T_OBJECT=>6,
- * :T_CLASS=>404,
- * # ...
- * }
+ * It returns a hash that looks like:
*
- * The contents of the returned hash are implementation specific.
- * It may be changed in future.
+ * {
+ * TOTAL: 10000,
+ * FREE: 3011,
+ * T_OBJECT: 6,
+ * T_CLASS: 404,
+ * # ...
+ * }
*
- * The keys starting with +:T_+ means live objects.
+ * The contents of the returned hash are implementation specific and
+ * may be changed in future versions without notice.
+ *
+ * The keys starting with +:T_+ are live objects of a particular type.
* For example, +:T_ARRAY+ is the number of arrays.
- * +:FREE+ means object slots which is not used now.
- * +:TOTAL+ means sum of above.
+ *
+ * The key +:FREE+ is the number of object slots which are empty.
+ *
+ * The key +:TOTAL+ is the total number of slots (which is the sum of
+ * all of the other values).
*
* If the optional argument +result_hash+ is given,
- * it is overwritten and returned. This is intended to avoid probe effect.
+ * it is overwritten and returned.
+ * This is intended to avoid the probe effect.
*
* h = {}
* ObjectSpace.count_objects(h)
* puts h
- * # => { :TOTAL=>10000, :T_CLASS=>158280, :T_MODULE=>20672, :T_STRING=>527249 }
+ * # => { TOTAL: 10000, T_CLASS: 158280, T_MODULE: 20672, T_STRING: 527249 }
*
* This method is only expected to work on C Ruby.
*
@@ -2490,6 +2766,10 @@ count_objects(int argc, VALUE *argv, VALUE os)
types[i] = type_sym(i);
}
+ // Same as type_sym, we need to create all key symbols in advance
+ VALUE total = ID2SYM(rb_intern("TOTAL"));
+ VALUE free = ID2SYM(rb_intern("FREE"));
+
rb_gc_impl_each_object(rb_gc_get_objspace(), count_objects_i, &data);
if (NIL_P(hash)) {
@@ -2498,8 +2778,8 @@ 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, total, SIZET2NUM(data.total));
+ rb_hash_aset(hash, free, SIZET2NUM(data.freed));
for (size_t i = 0; i <= T_MASK; i++) {
if (data.counts[i]) {
@@ -2648,29 +2928,6 @@ rb_gc_mark_maybe(VALUE obj)
gc_mark_maybe_internal(obj);
}
-void
-rb_gc_mark_weak(VALUE *ptr)
-{
- 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));
-
- rb_gc_impl_mark_weak(objspace, ptr);
- }
- else {
- GC_ASSERT(!rb_gc_impl_during_gc_p(objspace));
- }
-}
-
-void
-rb_gc_remove_weak(VALUE parent_obj, VALUE *ptr)
-{
- rb_gc_impl_remove_weak(rb_gc_get_objspace(), parent_obj, ptr);
-}
-
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)
@@ -2803,8 +3060,10 @@ mark_const_entry_i(VALUE value, void *objspace)
{
const rb_const_entry_t *ce = (const rb_const_entry_t *)value;
- gc_mark_internal(ce->value);
- gc_mark_internal(ce->file);
+ if (!rb_gc_checking_shareable()) {
+ gc_mark_internal(ce->value);
+ gc_mark_internal(ce->file); // TODO: ce->file should be shareable?
+ }
return ID_TABLE_CONTINUE;
}
@@ -2815,26 +3074,6 @@ mark_const_tbl(rb_objspace_t *objspace, struct rb_id_table *tbl)
rb_id_table_foreach_values(tbl, mark_const_entry_i, objspace);
}
-static enum rb_id_table_iterator_result
-mark_cvc_tbl_i(VALUE cvc_entry, void *objspace)
-{
- 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)));
- gc_mark_internal((VALUE)entry->cref);
-
- return ID_TABLE_CONTINUE;
-}
-
-static void
-mark_cvc_tbl(rb_objspace_t *objspace, struct rb_id_table *tbl)
-{
- if (!tbl) return;
- rb_id_table_foreach_values(tbl, mark_cvc_tbl_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
@@ -2865,6 +3104,16 @@ gc_mark_machine_stack_location_maybe(VALUE obj, void *data)
#endif
}
+static bool
+gc_object_moved_p_internal(void *objspace, VALUE obj)
+{
+ if (SPECIAL_CONST_P(obj)) {
+ return false;
+ }
+
+ return rb_gc_impl_object_moved_p(objspace, obj);
+}
+
static VALUE
gc_location_internal(void *objspace, VALUE value)
{
@@ -2997,16 +3246,37 @@ rb_mark_tbl_no_pin(st_table *tbl)
gc_mark_tbl_no_pin(tbl);
}
+void
+rb_gc_mark_set_no_pin(st_table *tbl)
+{
+ if (!tbl || tbl->num_entries == 0) return;
+
+ st_foreach(tbl, gc_mark_set_no_pin_i, 0);
+}
+
static bool
gc_declarative_marking_p(const rb_data_type_t *type)
{
return (type->flags & RUBY_TYPED_DECL_MARKING) != 0;
}
+rb_execution_context_t *
+rb_gc_get_ec(void)
+{
+ void *objspace = rb_gc_get_objspace();
+
+ if (RB_LIKELY(rb_gc_impl_during_gc_p(objspace))) {
+ return rb_gc_impl_get_vm_context(objspace)->ec;
+ }
+ else {
+ return GET_EC();
+ }
+}
+
void
rb_gc_mark_roots(void *objspace, const char **categoryp)
{
- rb_execution_context_t *ec = GET_EC();
+ rb_execution_context_t *ec = rb_gc_get_ec();
rb_vm_t *vm = rb_ec_vm_ptr(ec);
#define MARK_CHECKPOINT(category) do { \
@@ -3031,6 +3301,14 @@ rb_gc_mark_roots(void *objspace, const char **categoryp)
}
#endif
+#if USE_ZJIT
+ void rb_zjit_root_mark(void);
+ if (rb_zjit_enabled_p) {
+ MARK_CHECKPOINT("ZJIT");
+ rb_zjit_root_mark();
+ }
+#endif
+
MARK_CHECKPOINT("machine_context");
mark_current_machine_context(ec);
@@ -3048,7 +3326,7 @@ struct gc_mark_classext_foreach_arg {
};
static void
-gc_mark_classext_module(rb_classext_t *ext, bool prime, VALUE namespace, void *arg)
+gc_mark_classext_module(rb_classext_t *ext, bool prime, VALUE box_value, void *arg)
{
struct gc_mark_classext_foreach_arg *foreach_arg = (struct gc_mark_classext_foreach_arg *)arg;
rb_objspace_t *objspace = foreach_arg->objspace;
@@ -3057,18 +3335,26 @@ gc_mark_classext_module(rb_classext_t *ext, bool prime, VALUE namespace, void *a
gc_mark_internal(RCLASSEXT_SUPER(ext));
}
mark_m_tbl(objspace, RCLASSEXT_M_TBL(ext));
- gc_mark_internal(RCLASSEXT_FIELDS_OBJ(ext));
+
+ if (!rb_gc_checking_shareable()) {
+ // unshareable
+ gc_mark_internal(RCLASSEXT_FIELDS_OBJ(ext));
+ gc_mark_internal(RCLASSEXT_CVC_TBL(ext));
+ }
+
if (!RCLASSEXT_SHARED_CONST_TBL(ext) && RCLASSEXT_CONST_TBL(ext)) {
mark_const_tbl(objspace, RCLASSEXT_CONST_TBL(ext));
}
mark_m_tbl(objspace, RCLASSEXT_CALLABLE_M_TBL(ext));
gc_mark_internal(RCLASSEXT_CC_TBL(ext));
- mark_cvc_tbl(objspace, RCLASSEXT_CVC_TBL(ext));
+ if (RCLASSEXT_SUBCLASSES(ext)) {
+ gc_mark_internal(RCLASSEXT_SUBCLASSES(ext));
+ }
gc_mark_internal(RCLASSEXT_CLASSPATH(ext));
}
static void
-gc_mark_classext_iclass(rb_classext_t *ext, bool prime, VALUE namespace, void *arg)
+gc_mark_classext_iclass(rb_classext_t *ext, bool prime, VALUE box_value, void *arg)
{
struct gc_mark_classext_foreach_arg *foreach_arg = (struct gc_mark_classext_foreach_arg *)arg;
rb_objspace_t *objspace = foreach_arg->objspace;
@@ -3084,16 +3370,27 @@ gc_mark_classext_iclass(rb_classext_t *ext, bool prime, VALUE namespace, void *a
}
mark_m_tbl(objspace, RCLASSEXT_CALLABLE_M_TBL(ext));
gc_mark_internal(RCLASSEXT_CC_TBL(ext));
+ if (RCLASSEXT_SUBCLASSES(ext)) {
+ gc_mark_internal(RCLASSEXT_SUBCLASSES(ext));
+ }
}
#define TYPED_DATA_REFS_OFFSET_LIST(d) (size_t *)(uintptr_t)RTYPEDDATA_TYPE(d)->function.dmark
void
+rb_gc_move_obj_during_marking(VALUE from, VALUE to)
+{
+ if (rb_obj_using_gen_fields_table_p(to)) {
+ rb_mark_generic_ivar(from);
+ }
+}
+
+void
rb_gc_mark_children(void *objspace, VALUE obj)
{
struct gc_mark_classext_foreach_arg foreach_args;
- if (rb_obj_exivar_p(obj)) {
+ if (rb_obj_using_gen_fields_table_p(obj)) {
rb_mark_generic_ivar(obj);
}
@@ -3123,7 +3420,8 @@ rb_gc_mark_children(void *objspace, VALUE obj)
switch (BUILTIN_TYPE(obj)) {
case T_CLASS:
- if (FL_TEST_RAW(obj, FL_SINGLETON)) {
+ if (FL_TEST_RAW(obj, FL_SINGLETON) &&
+ !rb_gc_checking_shareable()) {
gc_mark_internal(RCLASS_ATTACHED_OBJECT(obj));
}
// Continue to the shared T_CLASS/T_MODULE
@@ -3131,12 +3429,18 @@ rb_gc_mark_children(void *objspace, VALUE obj)
foreach_args.objspace = objspace;
foreach_args.obj = obj;
rb_class_classext_foreach(obj, gc_mark_classext_module, (void *)&foreach_args);
+ if (BOX_USER_P(RCLASS_PRIME_BOX(obj))) {
+ gc_mark_internal(RCLASS_PRIME_BOX(obj)->box_object);
+ }
break;
case T_ICLASS:
foreach_args.objspace = objspace;
foreach_args.obj = obj;
rb_class_classext_foreach(obj, gc_mark_classext_iclass, (void *)&foreach_args);
+ if (BOX_USER_P(RCLASS_PRIME_BOX(obj))) {
+ gc_mark_internal(RCLASS_PRIME_BOX(obj)->box_object);
+ }
break;
case T_ARRAY:
@@ -3177,15 +3481,12 @@ rb_gc_mark_children(void *objspace, VALUE obj)
break;
case T_DATA: {
- bool typed_data = RTYPEDDATA_P(obj);
- void *const ptr = typed_data ? RTYPEDDATA_GET_DATA(obj) : DATA_PTR(obj);
+ void *const ptr = RTYPEDDATA_GET_DATA(obj);
- if (typed_data) {
- gc_mark_internal(RTYPEDDATA(obj)->fields_obj);
- }
+ gc_mark_internal(RTYPEDDATA(obj)->fields_obj);
if (ptr) {
- if (typed_data && gc_declarative_marking_p(RTYPEDDATA_TYPE(obj))) {
+ if (gc_declarative_marking_p(RTYPEDDATA_TYPE(obj))) {
size_t *offset_list = TYPED_DATA_REFS_OFFSET_LIST(obj);
for (size_t offset = *offset_list; offset != RUBY_REF_END; offset = *offset_list++) {
@@ -3193,9 +3494,7 @@ rb_gc_mark_children(void *objspace, VALUE obj)
}
}
else {
- RUBY_DATA_FUNC mark_func = typed_data ?
- RTYPEDDATA_TYPE(obj)->function.dmark :
- RDATA(obj)->dmark;
+ RUBY_DATA_FUNC mark_func = RTYPEDDATA_TYPE(obj)->function.dmark;
if (mark_func) (*mark_func)(ptr);
}
}
@@ -3204,28 +3503,19 @@ rb_gc_mark_children(void *objspace, VALUE obj)
}
case T_OBJECT: {
- if (rb_shape_obj_too_complex_p(obj)) {
+ uint32_t len;
+ if (rb_obj_shape_complex_p(obj)) {
gc_mark_tbl_no_pin(ROBJECT_FIELDS_HASH(obj));
+ len = ROBJECT_FIELDS_COUNT_COMPLEX(obj);
}
else {
const VALUE * const ptr = ROBJECT_FIELDS(obj);
- uint32_t len = ROBJECT_FIELDS_COUNT(obj);
+ len = ROBJECT_FIELDS_COUNT_NOT_COMPLEX(obj);
for (uint32_t i = 0; i < len; i++) {
gc_mark_internal(ptr[i]);
}
}
-
- attr_index_t fields_count = ROBJECT_FIELDS_COUNT(obj);
- if (fields_count) {
- VALUE klass = RBASIC_CLASS(obj);
-
- // Increment max_iv_count if applicable, used to determine size pool allocation
- if (RCLASS_MAX_IV_COUNT(klass) < fields_count) {
- RCLASS_SET_MAX_IV_COUNT(klass, fields_count);
- }
- }
-
break;
}
@@ -3272,7 +3562,7 @@ rb_gc_mark_children(void *objspace, VALUE obj)
gc_mark_internal(ptr[i]);
}
- if (!FL_TEST_RAW(obj, RSTRUCT_GEN_FIELDS)) {
+ if (rb_obj_shape_has_fields(obj) && !FL_TEST_RAW(obj, RSTRUCT_GEN_FIELDS)) {
gc_mark_internal(RSTRUCT_FIELDS_OBJ(obj));
}
@@ -3294,21 +3584,48 @@ rb_gc_obj_optimal_size(VALUE obj)
{
switch (BUILTIN_TYPE(obj)) {
case T_ARRAY:
- return rb_ary_size_as_embedded(obj);
+ {
+ size_t size = rb_ary_size_as_embedded(obj);
+ if (rb_gc_size_allocatable_p(size)) {
+ return size;
+ }
+ else {
+ return sizeof(struct RArray);
+ }
+ }
case T_OBJECT:
- if (rb_shape_obj_too_complex_p(obj)) {
+ if (rb_obj_shape_complex_p(obj)) {
return sizeof(struct RObject);
}
else {
- return rb_obj_embedded_size(ROBJECT_FIELDS_CAPACITY(obj));
+ size_t size = rb_obj_embedded_size(ROBJECT_FIELDS_CAPACITY(obj));
+ if (rb_gc_size_allocatable_p(size)) {
+ return size;
+ }
+ else {
+ return sizeof(struct RObject);
+ }
}
case T_STRING:
- return rb_str_size_as_embedded(obj);
+ {
+ size_t size = rb_str_size_as_embedded(obj);
+ if (rb_gc_size_allocatable_p(size)) {
+ return size;
+ }
+ else {
+ return sizeof(struct RString);
+ }
+ }
case T_HASH:
- return sizeof(struct RHash) + (RHASH_ST_TABLE_P(obj) ? sizeof(st_table) : sizeof(ar_table));
+ {
+ if (RB_OBJ_FROZEN(obj) && RHASH_AR_TABLE_P(obj)) {
+ return sizeof(struct RHash) + offsetof(ar_table, pairs) + RHASH_AR_TABLE_BOUND(obj) * sizeof(ar_table_pair);
+ }
+ return sizeof(struct RHash) + (RHASH_ST_TABLE_P(obj) ? sizeof(st_table) : sizeof(ar_table));
+ }
default:
return 0;
@@ -3342,14 +3659,11 @@ rb_gc_copy_attributes(VALUE dest, VALUE obj)
rb_gc_impl_copy_attributes(rb_gc_get_objspace(), dest, obj);
}
+#if USE_MODULAR_GC
int
rb_gc_modular_gc_loaded_p(void)
{
-#if USE_MODULAR_GC
return rb_gc_functions.modular_gc_loaded_p;
-#else
- return false;
-#endif
}
const char *
@@ -3365,6 +3679,7 @@ rb_gc_active_gc_name(void)
return gc_name;
}
+#endif
struct rb_gc_object_metadata_entry *
rb_gc_object_metadata(VALUE obj)
@@ -3402,10 +3717,15 @@ rb_gc_register_address(VALUE *addr)
VALUE obj = *addr;
- struct global_object_list *tmp = ALLOC(struct global_object_list);
- tmp->next = vm->global_object_list;
- tmp->varptr = addr;
- vm->global_object_list = tmp;
+ RB_VM_LOCKING() {
+ if (vm->global_object_list_size == vm->global_object_list_capa) {
+ size_t new_capa = vm->global_object_list_capa ? vm->global_object_list_capa * 2 : 64;
+ SIZED_REALLOC_N(vm->global_object_list, VALUE *, new_capa, vm->global_object_list_capa);
+ vm->global_object_list_capa = new_capa;
+ }
+
+ vm->global_object_list[vm->global_object_list_size++] = addr;
+ }
/*
* Because some C extensions have assignment-then-register bugs,
@@ -3423,22 +3743,20 @@ void
rb_gc_unregister_address(VALUE *addr)
{
rb_vm_t *vm = GET_VM();
- struct global_object_list *tmp = vm->global_object_list;
-
- if (tmp->varptr == addr) {
- vm->global_object_list = tmp->next;
- xfree(tmp);
- return;
- }
- while (tmp->next) {
- if (tmp->next->varptr == addr) {
- struct global_object_list *t = tmp->next;
-
- tmp->next = tmp->next->next;
- xfree(t);
- break;
+ RB_VM_LOCKING() {
+ size_t index;
+ for (index = 0; index < vm->global_object_list_size; index++) {
+ if (addr == vm->global_object_list[index]) {
+ MEMMOVE(
+ vm->global_object_list[index],
+ &vm->global_object_list[index + 1],
+ VALUE *,
+ vm->global_object_list_size - index - 1
+ );
+ vm->global_object_list_size--;
+ break;
+ }
}
- tmp = tmp->next;
}
}
@@ -3539,19 +3857,21 @@ gc_ref_update_object(void *objspace, VALUE v)
{
VALUE *ptr = ROBJECT_FIELDS(v);
- if (rb_shape_obj_too_complex_p(v)) {
- gc_ref_update_table_values_only(ROBJECT_FIELDS_HASH(v));
- return;
- }
+ if (FL_TEST_RAW(v, ROBJECT_HEAP)) {
+ if (rb_obj_shape_complex_p(v)) {
+ gc_ref_update_table_values_only(ROBJECT_FIELDS_HASH(v));
+ return;
+ }
- size_t slot_size = rb_gc_obj_slot_size(v);
- size_t embed_size = rb_obj_embedded_size(ROBJECT_FIELDS_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_FIELDS_COUNT(v));
- RB_FL_SET_RAW(v, ROBJECT_EMBED);
- xfree(ptr);
- ptr = ROBJECT(v)->as.ary;
+ size_t slot_size = rb_gc_obj_slot_size(v);
+ size_t embed_size = rb_obj_embedded_size(ROBJECT_FIELDS_CAPACITY(v));
+ if (slot_size >= embed_size) {
+ // Object can be re-embedded
+ memcpy(ROBJECT(v)->as.ary, ptr, sizeof(VALUE) * ROBJECT_FIELDS_COUNT(v));
+ SIZED_FREE_N(ptr, ROBJECT_FIELDS_CAPACITY(v));
+ FL_UNSET_RAW(v, ROBJECT_HEAP);
+ ptr = ROBJECT(v)->as.ary;
+ }
}
for (uint32_t i = 0; i < ROBJECT_FIELDS_COUNT(v); i++) {
@@ -3572,6 +3892,36 @@ rb_gc_update_tbl_refs(st_table *ptr)
gc_update_table_refs(ptr);
}
+static int
+rb_gc_update_set_refs_i(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;
+ }
+
+ return ST_CONTINUE;
+}
+
+static int
+rb_gc_update_set_refs_replace_i(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);
+ }
+
+ return ST_CONTINUE;
+}
+
+void
+rb_gc_update_set_refs(st_table *tbl)
+{
+ if (!tbl || tbl->num_entries == 0) return;
+
+ if (st_foreach_with_replace(tbl, rb_gc_update_set_refs_i, rb_gc_update_set_refs_replace_i, 0)) {
+ rb_raise(rb_eRuntimeError, "hash modified during iteration");
+ }
+}
+
static void
gc_ref_update_hash(void *objspace, VALUE v)
{
@@ -3597,7 +3947,7 @@ check_id_table_move(VALUE value, void *data)
{
void *objspace = (void *)data;
- if (rb_gc_impl_object_moved_p(objspace, (VALUE)value)) {
+ if (gc_object_moved_p_internal(objspace, (VALUE)value)) {
return ID_TABLE_REPLACE;
}
@@ -3641,7 +3991,7 @@ update_id_table(VALUE *value, void *data, int existing)
{
void *objspace = (void *)data;
- if (rb_gc_impl_object_moved_p(objspace, (VALUE)*value)) {
+ if (gc_object_moved_p_internal(objspace, (VALUE)*value)) {
*value = gc_location_internal(objspace, (VALUE)*value);
}
@@ -3657,38 +4007,15 @@ update_m_tbl(void *objspace, struct rb_id_table *tbl)
}
static enum rb_id_table_iterator_result
-update_cvc_tbl_i(VALUE cvc_entry, void *objspace)
-{
- struct rb_cvar_class_tbl_entry *entry;
-
- entry = (struct rb_cvar_class_tbl_entry *)cvc_entry;
-
- if (entry->cref) {
- TYPED_UPDATE_IF_MOVED(objspace, rb_cref_t *, entry->cref);
- }
-
- entry->class_value = gc_location_internal(objspace, entry->class_value);
-
- return ID_TABLE_CONTINUE;
-}
-
-static void
-update_cvc_tbl(void *objspace, struct rb_id_table *tbl)
-{
- if (!tbl) return;
- rb_id_table_foreach_values(tbl, update_cvc_tbl_i, objspace);
-}
-
-static enum rb_id_table_iterator_result
update_const_tbl_i(VALUE value, void *objspace)
{
rb_const_entry_t *ce = (rb_const_entry_t *)value;
- if (rb_gc_impl_object_moved_p(objspace, ce->value)) {
+ if (gc_object_moved_p_internal(objspace, ce->value)) {
ce->value = gc_location_internal(objspace, ce->value);
}
- if (rb_gc_impl_object_moved_p(objspace, ce->file)) {
+ if (gc_object_moved_p_internal(objspace, ce->file)) {
ce->file = gc_location_internal(objspace, ce->file);
}
@@ -3703,20 +4030,6 @@ update_const_tbl(void *objspace, struct rb_id_table *tbl)
}
static void
-update_subclasses(void *objspace, rb_classext_t *ext)
-{
- rb_subclass_entry_t *entry;
- rb_subclass_anchor_t *anchor = RCLASSEXT_SUBCLASSES(ext);
- if (!anchor) return;
- entry = anchor->head;
- while (entry) {
- if (entry->klass)
- UPDATE_IF_MOVED(objspace, entry->klass);
- entry = entry->next;
- }
-}
-
-static void
update_superclasses(rb_objspace_t *objspace, rb_classext_t *ext)
{
if (RCLASSEXT_SUPERCLASSES_WITH_SELF(ext)) {
@@ -3739,7 +4052,7 @@ update_classext_values(rb_objspace_t *objspace, rb_classext_t *ext, bool is_icla
}
static void
-update_classext(rb_classext_t *ext, bool is_prime, VALUE namespace, void *arg)
+update_classext(rb_classext_t *ext, bool is_prime, VALUE box_value, void *arg)
{
struct classext_foreach_args *args = (struct classext_foreach_args *)arg;
rb_objspace_t *objspace = args->objspace;
@@ -3755,15 +4068,17 @@ update_classext(rb_classext_t *ext, bool is_prime, VALUE namespace, void *arg)
update_const_tbl(objspace, RCLASSEXT_CONST_TBL(ext));
}
UPDATE_IF_MOVED(objspace, RCLASSEXT_CC_TBL(ext));
- update_cvc_tbl(objspace, RCLASSEXT_CVC_TBL(ext));
+ UPDATE_IF_MOVED(objspace, RCLASSEXT_CVC_TBL(ext));
update_superclasses(objspace, ext);
- update_subclasses(objspace, ext);
+ if (RCLASSEXT_SUBCLASSES(ext)) {
+ UPDATE_IF_MOVED(objspace, RCLASSEXT_SUBCLASSES(ext));
+ }
update_classext_values(objspace, ext, false);
}
static void
-update_iclass_classext(rb_classext_t *ext, bool is_prime, VALUE namespace, void *arg)
+update_iclass_classext(rb_classext_t *ext, bool is_prime, VALUE box_value, void *arg)
{
struct classext_foreach_args *args = (struct classext_foreach_args *)arg;
rb_objspace_t *objspace = args->objspace;
@@ -3774,7 +4089,10 @@ update_iclass_classext(rb_classext_t *ext, bool is_prime, VALUE namespace, void
update_m_tbl(objspace, RCLASSEXT_M_TBL(ext));
update_m_tbl(objspace, RCLASSEXT_CALLABLE_M_TBL(ext));
UPDATE_IF_MOVED(objspace, RCLASSEXT_CC_TBL(ext));
- update_subclasses(objspace, ext);
+ UPDATE_IF_MOVED(objspace, RCLASSEXT_CVC_TBL(ext));
+ if (RCLASSEXT_SUBCLASSES(ext)) {
+ UPDATE_IF_MOVED(objspace, RCLASSEXT_SUBCLASSES(ext));
+ }
update_classext_values(objspace, ext, true);
}
@@ -3819,23 +4137,6 @@ vm_weak_table_foreach_update_weak_key(st_data_t *key, st_data_t *value, st_data_
}
static int
-vm_weak_table_cc_refinement_foreach(st_data_t key, st_data_t data, int error)
-{
- struct global_vm_table_foreach_data *iter_data = (struct global_vm_table_foreach_data *)data;
-
- return iter_data->callback((VALUE)key, iter_data->data);
-}
-
-static int
-vm_weak_table_cc_refinement_foreach_update_update(st_data_t *key, st_data_t data, int existing)
-{
- struct global_vm_table_foreach_data *iter_data = (struct global_vm_table_foreach_data *)data;
-
- return iter_data->update_callback((VALUE *)key, iter_data->data);
-}
-
-
-static int
vm_weak_table_sym_set_foreach(VALUE *sym_ptr, void *data)
{
VALUE sym = *sym_ptr;
@@ -3896,7 +4197,11 @@ vm_weak_table_gen_fields_foreach(st_data_t key, st_data_t value, st_data_t data)
break;
case ST_DELETE:
- RBASIC_SET_SHAPE_ID((VALUE)key, ROOT_SHAPE_ID);
+ // When we're removing an object from the weak ref table, we need to
+ // set the shape on it so that the GC finalizer won't try to remove
+ // it again. A "root shape" indicates to the GC that this object
+ // has no fields on it, hence it won't be in the gen fields table.
+ RBASIC_SET_SHAPE_ID((VALUE)key, ROOT_SHAPE_ID | SHAPE_ID_LAYOUT_OTHER);
return ST_DELETE;
case ST_REPLACE: {
@@ -3974,25 +4279,21 @@ rb_gc_vm_weak_table_foreach(vm_table_foreach_callback_func callback,
switch (table) {
case RB_GC_VM_CI_TABLE: {
- if (vm->ci_table) {
- st_foreach_with_replace(
- vm->ci_table,
- vm_weak_table_foreach_weak_key,
- vm_weak_table_foreach_update_weak_key,
- (st_data_t)&foreach_data
- );
- }
+ st_foreach_with_replace(
+ &vm->ci_table,
+ vm_weak_table_foreach_weak_key,
+ vm_weak_table_foreach_update_weak_key,
+ (st_data_t)&foreach_data
+ );
break;
}
case RB_GC_VM_OVERLOADED_CME_TABLE: {
- if (vm->overloaded_cme_table) {
- st_foreach_with_replace(
- vm->overloaded_cme_table,
- vm_weak_table_foreach_weak_key,
- vm_weak_table_foreach_update_weak_key,
- (st_data_t)&foreach_data
- );
- }
+ st_foreach_with_replace(
+ &vm->overloaded_cme_table,
+ vm_weak_table_foreach_weak_key,
+ vm_weak_table_foreach_update_weak_key,
+ (st_data_t)&foreach_data
+ );
break;
}
case RB_GC_VM_GLOBAL_SYMBOLS_TABLE: {
@@ -4031,17 +4332,6 @@ rb_gc_vm_weak_table_foreach(vm_table_foreach_callback_func callback,
);
break;
}
- case RB_GC_VM_CC_REFINEMENT_TABLE: {
- if (vm->cc_refinement_table) {
- set_foreach_with_replace(
- vm->cc_refinement_table,
- vm_weak_table_cc_refinement_foreach,
- vm_weak_table_cc_refinement_foreach_update_update,
- (st_data_t)&foreach_data
- );
- }
- break;
- }
case RB_GC_VM_WEAK_TABLE_COUNT:
rb_bug("Unreachable");
default:
@@ -4066,6 +4356,14 @@ rb_gc_update_vm_references(void *objspace)
rb_yjit_root_update_references();
}
#endif
+
+#if USE_ZJIT
+ void rb_zjit_root_update_references(void); // in Rust
+
+ if (rb_zjit_enabled_p) {
+ rb_zjit_root_update_references();
+ }
+#endif
}
void
@@ -4130,15 +4428,12 @@ rb_gc_update_object_references(void *objspace, VALUE obj)
case T_DATA:
/* Call the compaction callback, if it exists */
{
- bool typed_data = RTYPEDDATA_P(obj);
- void *const ptr = typed_data ? RTYPEDDATA_GET_DATA(obj) : DATA_PTR(obj);
+ void *const ptr = RTYPEDDATA_GET_DATA(obj);
- if (typed_data) {
- UPDATE_IF_MOVED(objspace, RTYPEDDATA(obj)->fields_obj);
- }
+ UPDATE_IF_MOVED(objspace, RTYPEDDATA(obj)->fields_obj);
if (ptr) {
- if (typed_data && gc_declarative_marking_p(RTYPEDDATA_TYPE(obj))) {
+ if (gc_declarative_marking_p(RTYPEDDATA_TYPE(obj))) {
size_t *offset_list = TYPED_DATA_REFS_OFFSET_LIST(obj);
for (size_t offset = *offset_list; offset != RUBY_REF_END; offset = *offset_list++) {
@@ -4146,7 +4441,7 @@ rb_gc_update_object_references(void *objspace, VALUE obj)
*ref = gc_location_internal(objspace, *ref);
}
}
- else if (typed_data) {
+ else {
RUBY_DATA_FUNC compact_func = RTYPEDDATA_TYPE(obj)->function.dcompact;
if (compact_func) (*compact_func)(ptr);
}
@@ -4575,7 +4870,7 @@ rb_method_type_name(rb_method_type_t type)
{
switch (type) {
case VM_METHOD_TYPE_ISEQ: return "iseq";
- case VM_METHOD_TYPE_ATTRSET: return "attrest";
+ case VM_METHOD_TYPE_ATTRSET: return "attrset";
case VM_METHOD_TYPE_IVAR: return "ivar";
case VM_METHOD_TYPE_BMETHOD: return "bmethod";
case VM_METHOD_TYPE_ALIAS: return "alias";
@@ -4668,7 +4963,7 @@ rb_raw_obj_info_common(char *const buff, const size_t buff_size, const VALUE obj
APPEND_S("(temporary internal)");
}
else if (RTEST(RBASIC(obj)->klass)) {
- VALUE class_path = rb_class_path_cached(RBASIC(obj)->klass);
+ VALUE class_path = rb_mod_name(RBASIC(obj)->klass);
if (!NIL_P(class_path)) {
APPEND_F("%s ", RSTRING_PTR(class_path));
}
@@ -4715,6 +5010,10 @@ rb_raw_obj_info_buitin_type(char *const buff, const size_t buff_size, const VALU
}
break;
case T_STRING: {
+ APPEND_F("[%s%s] ",
+ C(FL_TEST(obj, RSTRING_FSTR), "F"),
+ C(RB_OBJ_FROZEN(obj), "R"));
+
if (STR_SHARED_P(obj)) {
APPEND_F(" [shared] len: %ld", RSTRING_LEN(obj));
}
@@ -4750,7 +5049,7 @@ rb_raw_obj_info_buitin_type(char *const buff, const size_t buff_size, const VALU
case T_CLASS:
case T_MODULE:
{
- VALUE class_path = rb_class_path_cached(obj);
+ VALUE class_path = rb_mod_name(obj);
if (!NIL_P(class_path)) {
APPEND_F("%s", RSTRING_PTR(class_path));
}
@@ -4761,7 +5060,7 @@ rb_raw_obj_info_buitin_type(char *const buff, const size_t buff_size, const VALU
}
case T_ICLASS:
{
- VALUE class_path = rb_class_path_cached(RBASIC_CLASS(obj));
+ VALUE class_path = rb_mod_name(RBASIC_CLASS(obj));
if (!NIL_P(class_path)) {
APPEND_F("src:%s", RSTRING_PTR(class_path));
}
@@ -4769,21 +5068,18 @@ 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_p(obj)) {
- size_t hash_len = rb_st_table_size(ROBJECT_FIELDS_HASH(obj));
- APPEND_F("(too_complex) len:%zu", hash_len);
- }
- else {
- uint32_t len = ROBJECT_FIELDS_CAPACITY(obj);
-
- if (RBASIC(obj)->flags & ROBJECT_EMBED) {
- APPEND_F("(embed) len:%d", len);
+ if (FL_TEST_RAW(obj, ROBJECT_HEAP)) {
+ if (rb_obj_shape_complex_p(obj)) {
+ size_t hash_len = rb_st_table_size(ROBJECT_FIELDS_HASH(obj));
+ APPEND_F("(complex) len:%zu", hash_len);
}
else {
- VALUE *ptr = ROBJECT_FIELDS(obj);
- APPEND_F("len:%d ptr:%p", len, (void *)ptr);
+ APPEND_F("(embed) len:%d capa:%d", RSHAPE_LEN(RBASIC_SHAPE_ID(obj)), ROBJECT_FIELDS_CAPACITY(obj));
}
}
+ else {
+ APPEND_F("len:%d capa:%d ptr:%p", RSHAPE_LEN(RBASIC_SHAPE_ID(obj)), ROBJECT_FIELDS_CAPACITY(obj), (void *)ROBJECT_FIELDS(obj));
+ }
}
break;
case T_DATA: {
@@ -4801,12 +5097,6 @@ rb_raw_obj_info_buitin_type(char *const buff, const size_t buff_size, const VALU
APPEND_F("r:%d", r->pub.id);
}
}
- else {
- const char * const type_name = rb_objspace_data_type_name(obj);
- if (type_name) {
- APPEND_F("%s", type_name);
- }
- }
break;
}
case T_IMEMO: {
@@ -4861,7 +5151,7 @@ rb_raw_obj_info_buitin_type(char *const buff, const size_t buff_size, const VALU
case imemo_callcache:
{
const struct rb_callcache *cc = (const struct rb_callcache *)obj;
- VALUE class_path = vm_cc_valid(cc) ? rb_class_path_cached(cc->klass) : Qnil;
+ VALUE class_path = vm_cc_valid(cc) ? rb_mod_name(cc->klass) : Qnil;
const rb_callable_method_entry_t *cme = vm_cc_cme(cc);
APPEND_F("(klass:%s cme:%s%s (%p) call:%p",
@@ -4946,12 +5236,6 @@ rb_raw_obj_info(char *const buff, const size_t buff_size, VALUE obj)
#undef APPEND_F
#undef BUFF_ARGS
-#if RGENGC_OBJ_INFO
-#define OBJ_INFO_BUFFERS_NUM 10
-#define OBJ_INFO_BUFFERS_SIZE 0x100
-static rb_atomic_t obj_info_buffers_index = 0;
-static char obj_info_buffers[OBJ_INFO_BUFFERS_NUM][OBJ_INFO_BUFFERS_SIZE];
-
/* Increments *var atomically and resets *var to 0 when maxval is
* reached. Returns the wraparound old *var value (0...maxval). */
static rb_atomic_t
@@ -4969,17 +5253,18 @@ atomic_inc_wraparound(rb_atomic_t *var, const rb_atomic_t maxval)
static const char *
obj_info(VALUE obj)
{
- rb_atomic_t index = atomic_inc_wraparound(&obj_info_buffers_index, OBJ_INFO_BUFFERS_NUM);
- char *const buff = obj_info_buffers[index];
- return rb_raw_obj_info(buff, OBJ_INFO_BUFFERS_SIZE, obj);
-}
-#else
-static const char *
-obj_info(VALUE obj)
-{
+ if (RGENGC_OBJ_INFO) {
+ static struct {
+ rb_atomic_t index;
+ char buffers[10][0x100];
+ } info = {0};
+
+ rb_atomic_t index = atomic_inc_wraparound(&info.index, numberof(info.buffers));
+ char *const buff = info.buffers[index];
+ return rb_raw_obj_info(buff, sizeof(info.buffers[0]), obj);
+ }
return obj_type_name(obj);
}
-#endif
/*
------------------------ Extended allocator ------------------------
@@ -5008,11 +5293,7 @@ gc_raise(VALUE exc, const char *fmt, ...)
exc, fmt, &ap,
};
- if (ruby_thread_has_gvl_p()) {
- gc_vraise(&argv);
- UNREACHABLE;
- }
- else if (ruby_native_thread_p()) {
+ if (ruby_native_thread_p()) {
rb_thread_call_with_gvl(gc_vraise, &argv);
UNREACHABLE;
}
@@ -5118,6 +5399,14 @@ ruby_xmalloc(size_t size)
return handle_malloc_failure(ruby_xmalloc_body(size));
}
+static bool
+malloc_gc_allowed(void)
+{
+ rb_ractor_t *r = rb_current_ractor_raw(false);
+
+ return r == NULL || !r->malloc_gc_disabled;
+}
+
static void *
ruby_xmalloc_body(size_t size)
{
@@ -5125,7 +5414,7 @@ ruby_xmalloc_body(size_t size)
negative_size_allocation_error("too large allocation size");
}
- return rb_gc_impl_malloc(rb_gc_get_objspace(), size);
+ return rb_gc_impl_malloc(rb_gc_get_objspace(), size, malloc_gc_allowed());
}
void
@@ -5155,7 +5444,7 @@ ruby_xmalloc2(size_t n, size_t size)
static void *
ruby_xmalloc2_body(size_t n, size_t size)
{
- return rb_gc_impl_malloc(rb_gc_get_objspace(), xmalloc2_size(n, size));
+ return rb_gc_impl_malloc(rb_gc_get_objspace(), xmalloc2_size(n, size), malloc_gc_allowed());
}
static void *ruby_xcalloc_body(size_t n, size_t size);
@@ -5169,65 +5458,65 @@ ruby_xcalloc(size_t n, size_t size)
static void *
ruby_xcalloc_body(size_t n, size_t size)
{
- return rb_gc_impl_calloc(rb_gc_get_objspace(), xmalloc2_size(n, size));
+ return rb_gc_impl_calloc(rb_gc_get_objspace(), xmalloc2_size(n, size), malloc_gc_allowed());
}
-static void *ruby_sized_xrealloc_body(void *ptr, size_t new_size, size_t old_size);
+static void *ruby_xrealloc_sized_body(void *ptr, size_t new_size, size_t old_size);
-#ifdef ruby_sized_xrealloc
-#undef ruby_sized_xrealloc
+#ifdef ruby_xrealloc_sized
+#undef ruby_xrealloc_sized
#endif
void *
-ruby_sized_xrealloc(void *ptr, size_t new_size, size_t old_size)
+ruby_xrealloc_sized(void *ptr, size_t new_size, size_t old_size)
{
- return handle_malloc_failure(ruby_sized_xrealloc_body(ptr, new_size, old_size));
+ return handle_malloc_failure(ruby_xrealloc_sized_body(ptr, new_size, old_size));
}
static void *
-ruby_sized_xrealloc_body(void *ptr, size_t new_size, size_t old_size)
+ruby_xrealloc_sized_body(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 rb_gc_impl_realloc(rb_gc_get_objspace(), ptr, new_size, old_size);
+ return rb_gc_impl_realloc(rb_gc_get_objspace(), ptr, new_size, old_size, malloc_gc_allowed());
}
void *
ruby_xrealloc(void *ptr, size_t new_size)
{
- return ruby_sized_xrealloc(ptr, new_size, 0);
+ return ruby_xrealloc_sized(ptr, new_size, 0);
}
-static void *ruby_sized_xrealloc2_body(void *ptr, size_t n, size_t size, size_t old_n);
+static void *ruby_xrealloc2_sized_body(void *ptr, size_t n, size_t size, size_t old_n);
-#ifdef ruby_sized_xrealloc2
-#undef ruby_sized_xrealloc2
+#ifdef ruby_xrealloc2_sized
+#undef ruby_xrealloc2_sized
#endif
void *
-ruby_sized_xrealloc2(void *ptr, size_t n, size_t size, size_t old_n)
+ruby_xrealloc2_sized(void *ptr, size_t n, size_t size, size_t old_n)
{
- return handle_malloc_failure(ruby_sized_xrealloc2_body(ptr, n, size, old_n));
+ return handle_malloc_failure(ruby_xrealloc2_sized_body(ptr, n, size, old_n));
}
static void *
-ruby_sized_xrealloc2_body(void *ptr, size_t n, size_t size, size_t old_n)
+ruby_xrealloc2_sized_body(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);
+ return rb_gc_impl_realloc(rb_gc_get_objspace(), ptr, len, old_n * size, malloc_gc_allowed());
}
void *
ruby_xrealloc2(void *ptr, size_t n, size_t size)
{
- return ruby_sized_xrealloc2(ptr, n, size, 0);
+ return ruby_xrealloc2_sized(ptr, n, size, 0);
}
-#ifdef ruby_sized_xfree
-#undef ruby_sized_xfree
+#ifdef ruby_xfree_sized
+#undef ruby_xfree_sized
#endif
void
-ruby_sized_xfree(void *x, size_t size)
+ruby_xfree_sized(void *x, size_t size)
{
if (LIKELY(x)) {
/* It's possible for a C extension's pthread destructor function set by pthread_key_create
@@ -5245,7 +5534,7 @@ ruby_sized_xfree(void *x, size_t size)
void
ruby_xfree(void *x)
{
- ruby_sized_xfree(x, 0);
+ ruby_xfree_sized(x, 0);
}
void *
@@ -5314,11 +5603,11 @@ 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)) {
+ struct rbimpl_size_overflow_tag t = rbimpl_size_mul_overflow(num, size);
+ if (UNLIKELY(t.overflowed)) {
return NULL;
}
- size = t.right + sizeof(struct malloc_obj_info);
+ size = t.result + sizeof(struct malloc_obj_info);
mem = calloc1(size);
if (!mem) {
return NULL;
@@ -5386,6 +5675,80 @@ rb_gc_after_fork(rb_pid_t pid)
rb_gc_impl_after_fork(rb_gc_get_objspace(), pid);
}
+bool
+rb_gc_obj_shareable_p(VALUE obj)
+{
+ return RB_OBJ_SHAREABLE_P(obj);
+}
+
+void
+rb_gc_rp(VALUE obj)
+{
+ rp(obj);
+}
+
+struct check_shareable_data {
+ VALUE parent;
+ long err_count;
+};
+
+static void
+check_shareable_i(const VALUE child, void *ptr)
+{
+ struct check_shareable_data *data = (struct check_shareable_data *)ptr;
+
+ if (!rb_gc_obj_shareable_p(child)) {
+ fprintf(stderr, "(a) ");
+ rb_gc_rp(data->parent);
+ fprintf(stderr, "(b) ");
+ rb_gc_rp(child);
+ fprintf(stderr, "check_shareable_i: shareable (a) -> unshareable (b)\n");
+
+ data->err_count++;
+ rb_bug("!! violate shareable constraint !!");
+ }
+}
+
+static bool gc_checking_shareable = false;
+
+static void
+gc_verify_shareable(void *objspace, VALUE obj, void *data)
+{
+ // while gc_checking_shareable is true,
+ // other Ractors should not run the GC, until the flag is not local.
+ // TODO: remove VM locking if the flag is Ractor local
+
+ unsigned int lev = RB_GC_VM_LOCK();
+ {
+ gc_checking_shareable = true;
+ rb_objspace_reachable_objects_from(obj, check_shareable_i, (void *)data);
+ gc_checking_shareable = false;
+ }
+ RB_GC_VM_UNLOCK(lev);
+}
+
+// TODO: only one level (non-recursive)
+void
+rb_gc_verify_shareable(VALUE obj)
+{
+ rb_objspace_t *objspace = rb_gc_get_objspace();
+ struct check_shareable_data data = {
+ .parent = obj,
+ .err_count = 0,
+ };
+ gc_verify_shareable(objspace, obj, &data);
+
+ if (data.err_count > 0) {
+ rb_bug("rb_gc_verify_shareable");
+ }
+}
+
+bool
+rb_gc_checking_shareable(void)
+{
+ return gc_checking_shareable;
+}
+
/*
* Document-module: ObjectSpace
*
diff --git a/gc.rb b/gc.rb
index f5e62eed60..48bed27880 100644
--- a/gc.rb
+++ b/gc.rb
@@ -37,7 +37,7 @@ module GC
# interleaved with program execution both before the method returns and afterward;
# therefore sweeping may not be completed before the return.
#
- # Note that these keword arguments are implementation- and version-dependent,
+ # Note that these keyword arguments are implementation- and version-dependent,
# are not guaranteed to be future-compatible,
# and may be ignored in some implementations.
def self.start full_mark: true, immediate_mark: true, immediate_sweep: true
@@ -147,7 +147,7 @@ module GC
# sweeping_time: 0,
# heap_allocated_pages: 521,
# heap_empty_pages: 0,
- # heap_allocatable_slots: 0,
+ # heap_allocatable_bytes: 0,
# heap_available_slots: 539590,
# heap_live_slots: 422243,
# heap_free_slots: 117347,
@@ -193,7 +193,9 @@ 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 allocated pages.
+ # - +:heap_empty_pages+:
+ # The number of pages with no live objects, and that could be released to the system.
# - +:heap_sorted_length+:
# The number of pages that can fit into the buffer that holds references to all pages.
# - +:heap_allocatable_pages+:
@@ -210,8 +212,6 @@ module GC
# The total number of objects marked in the last \GC.
# - +:heap_eden_pages+:
# The total number of pages which contain at least one live slot.
- # - +:heap_tomb_pages+:
- # The total number of pages which do not contain any live slots.
# - +:total_allocated_pages+:
# The cumulative number of pages allocated since application start.
# - +:total_freed_pages+:
@@ -269,7 +269,16 @@ module GC
# GC.stat_heap
# # =>
# {0 =>
- # {slot_size: 40,
+ # {slot_size: 32,
+ # heap_eden_pages: 24,
+ # heap_eden_slots: 12288,
+ # total_allocated_pages: 24,
+ # force_major_gc_count: 0,
+ # force_incremental_marking_finish_count: 0,
+ # total_allocated_objects: 8450,
+ # total_freed_objects: 3120},
+ # 1 =>
+ # {slot_size: 64,
# heap_eden_pages: 246,
# heap_eden_slots: 402802,
# total_allocated_pages: 246,
@@ -277,8 +286,8 @@ module GC
# force_incremental_marking_finish_count: 1,
# total_allocated_objects: 33867152,
# total_freed_objects: 33520523},
- # 1 =>
- # {slot_size: 80,
+ # 2 =>
+ # {slot_size: 128,
# heap_eden_pages: 84,
# heap_eden_slots: 68746,
# total_allocated_pages: 84,
@@ -286,8 +295,8 @@ module GC
# force_incremental_marking_finish_count: 4,
# total_allocated_objects: 147491,
# total_freed_objects: 90699},
- # 2 =>
- # {slot_size: 160,
+ # 3 =>
+ # {slot_size: 256,
# heap_eden_pages: 157,
# heap_eden_slots: 64182,
# total_allocated_pages: 157,
@@ -295,8 +304,8 @@ module GC
# force_incremental_marking_finish_count: 0,
# total_allocated_objects: 211460,
# total_freed_objects: 190075},
- # 3 =>
- # {slot_size: 320,
+ # 4 =>
+ # {slot_size: 512,
# heap_eden_pages: 8,
# heap_eden_slots: 1631,
# total_allocated_pages: 8,
@@ -304,8 +313,8 @@ module GC
# force_incremental_marking_finish_count: 0,
# total_allocated_objects: 1422,
# total_freed_objects: 700},
- # 4 =>
- # {slot_size: 640,
+ # 5 =>
+ # {slot_size: 1024,
# heap_eden_pages: 16,
# heap_eden_slots: 1628,
# total_allocated_pages: 16,
@@ -316,7 +325,7 @@ module GC
#
# In the example above, the keys in the outer hash are the heap identifiers:
#
- # GC.stat_heap.keys # => [0, 1, 2, 3, 4]
+ # GC.stat_heap.keys # => [0, 1, 2, 3, 4, 5]
#
# On CRuby, each heap identifier is an integer;
# on other implementations, a heap identifier may be a string.
@@ -324,9 +333,9 @@ module GC
# With only argument +heap_id+ given,
# returns statistics for the given heap identifier:
#
- # GC.stat_heap(2)
+ # GC.stat_heap(3)
# # =>
- # {slot_size: 160,
+ # {slot_size: 256,
# heap_eden_pages: 157,
# heap_eden_slots: 64182,
# total_allocated_pages: 157,
@@ -338,7 +347,7 @@ module GC
# With arguments +heap_id+ and +key+ given,
# returns the value for the given key in the given heap:
#
- # GC.stat_heap(2, :slot_size) # => 160
+ # GC.stat_heap(3, :slot_size) # => 256
#
# With arguments +nil+ and +hash+ given,
# merges the statistics for all heaps into the given hash:
@@ -374,11 +383,6 @@ module GC
# 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+:
diff --git a/gc/default/default.c b/gc/default/default.c
index d2ed2244e1..0027f7a13c 100644
--- a/gc/default/default.c
+++ b/gc/default/default.c
@@ -23,6 +23,7 @@
#include "ruby/ruby.h"
#include "ruby/atomic.h"
+#include "ruby_atomic.h"
#include "ruby/debug.h"
#include "ruby/thread.h"
#include "ruby/util.h"
@@ -96,21 +97,12 @@
# 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
+#ifndef GC_HEAP_INIT_BYTES
+#define GC_HEAP_INIT_BYTES (2560 * 1024)
#endif
#ifndef GC_HEAP_FREE_SLOTS
#define GC_HEAP_FREE_SLOTS 4096
@@ -118,8 +110,8 @@
#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 */
+#ifndef GC_HEAP_GROWTH_MAX_BYTES
+#define GC_HEAP_GROWTH_MAX_BYTES 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
@@ -158,6 +150,17 @@
#define GC_OLDMALLOC_LIMIT_MAX (128 * 1024 * 1024 /* 128MB */)
#endif
+#ifndef GC_MALLOC_INCREASE_LOCAL_THRESHOLD
+#define GC_MALLOC_INCREASE_LOCAL_THRESHOLD (8 * 1024 /* 8KB */)
+#endif
+
+#ifdef RB_THREAD_LOCAL_SPECIFIER
+#define USE_MALLOC_INCREASE_LOCAL 1
+static RB_THREAD_LOCAL_SPECIFIER int malloc_increase_local;
+#else
+#define USE_MALLOC_INCREASE_LOCAL 0
+#endif
+
#ifndef GC_CAN_COMPILE_COMPACTION
#if defined(__wasi__) /* WebAssembly doesn't support signals */
# define GC_CAN_COMPILE_COMPACTION 0
@@ -176,7 +179,22 @@
#define USE_TICK_T (PRINT_ENTER_EXIT_TICK || PRINT_ROOT_TICKS)
#ifndef HEAP_COUNT
-# define HEAP_COUNT 5
+# if SIZEOF_VALUE >= 8
+# define HEAP_COUNT 12
+# else
+# define HEAP_COUNT 5
+# endif
+#endif
+
+/* The reciprocal table and pool_slot_sizes array are both generated from this
+ * single definition, so they can never get out of sync. */
+#if SIZEOF_VALUE >= 8
+# define EACH_POOL_SLOT_SIZE(SLOT) \
+ SLOT(32) SLOT(40) SLOT(64) SLOT(80) SLOT(96) SLOT(128) \
+ SLOT(160) SLOT(256) SLOT(512) SLOT(640) SLOT(768) SLOT(1024)
+#else
+# define EACH_POOL_SLOT_SIZE(SLOT) \
+ SLOT(32) SLOT(64) SLOT(128) SLOT(256) SLOT(512)
#endif
typedef struct ractor_newobj_heap_cache {
@@ -191,10 +209,10 @@ typedef struct ractor_newobj_cache {
} rb_ractor_newobj_cache_t;
typedef struct {
- size_t heap_init_slots[HEAP_COUNT];
+ size_t heap_init_bytes;
size_t heap_free_slots;
double growth_factor;
- size_t growth_max_slots;
+ size_t growth_max_bytes;
double heap_free_slots_min_ratio;
double heap_free_slots_goal_ratio;
@@ -212,10 +230,10 @@ typedef struct {
} ruby_gc_params_t;
static ruby_gc_params_t gc_params = {
- { GC_HEAP_INIT_SLOTS },
+ GC_HEAP_INIT_BYTES,
GC_HEAP_FREE_SLOTS,
GC_HEAP_GROWTH_FACTOR,
- GC_HEAP_GROWTH_MAX_SLOTS,
+ GC_HEAP_GROWTH_MAX_BYTES,
GC_HEAP_FREE_SLOTS_MIN_RATIO,
GC_HEAP_FREE_SLOTS_GOAL_RATIO,
@@ -290,9 +308,24 @@ int ruby_rgengc_debug;
#ifndef GC_ENABLE_LAZY_SWEEP
# define GC_ENABLE_LAZY_SWEEP 1
#endif
+
+#ifndef VERIFY_FREE_SIZE
+#if RUBY_DEBUG
+#define VERIFY_FREE_SIZE 1
+#else
+#define VERIFY_FREE_SIZE 0
+#endif
+#endif
+
+#if VERIFY_FREE_SIZE
+#undef CALC_EXACT_MALLOC_SIZE
+#define CALC_EXACT_MALLOC_SIZE 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
@@ -305,7 +338,7 @@ int ruby_rgengc_debug;
#endif
#ifndef GC_DEBUG_STRESS_TO_CLASS
-# define GC_DEBUG_STRESS_TO_CLASS 1
+# define GC_DEBUG_STRESS_TO_CLASS RUBY_DEBUG
#endif
typedef enum {
@@ -385,7 +418,6 @@ struct RMoved {
VALUE flags;
VALUE dummy;
VALUE destination;
- uint32_t original_shape_id;
};
#define RMOVED(obj) ((struct RMoved *)(obj))
@@ -446,7 +478,7 @@ typedef struct rb_heap_struct {
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) */
+ size_t total_slots; /* total slot count */
} rb_heap_t;
@@ -464,10 +496,35 @@ enum gc_mode {
gc_mode_compacting,
};
+typedef rbimpl_atomic_uint64_t gc_counter_t;
+
+#if !defined(HAVE_GCC_ATOMIC_BUILTINS_64) && !defined(_WIN32) && \
+ !(defined(__sun) && defined(HAVE_ATOMIC_H) && (defined(_LP64) || defined(_I32LPx)))
+# define MALLOC_COUNTERS_NEED_LOCK 1
+#endif
+
+struct gc_malloc_bytes {
+ gc_counter_t malloc;
+ gc_counter_t free;
+
+ /* Snapshots of `malloc` / `free` taken at the end of the last GC */
+ gc_counter_t malloc_at_last_gc;
+ gc_counter_t free_at_last_gc;
+};
+
typedef struct rb_objspace {
struct {
+ struct gc_malloc_bytes counters;
+#if RGENGC_ESTIMATE_OLDMALLOC
+ struct gc_malloc_bytes oldcounters;
+#endif
+#ifdef MALLOC_COUNTERS_NEED_LOCK
+ rb_nativethread_lock_t lock;
+#endif
+ } malloc_counters;
+
+ struct {
size_t limit;
- size_t increase;
#if MALLOC_ALLOCATED_SIZE
size_t allocated_size;
size_t allocations;
@@ -487,7 +544,6 @@ typedef struct rb_objspace {
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;
@@ -514,7 +570,7 @@ typedef struct rb_objspace {
uintptr_t range[2];
size_t freeable_pages;
- size_t allocatable_slots;
+ size_t allocatable_bytes;
/* final */
VALUE deferred_final;
@@ -561,6 +617,7 @@ typedef struct rb_objspace {
double gc_sweep_start_time;
size_t total_allocated_objects_at_gc_start;
size_t heap_used_at_gc_start;
+ size_t heap_total_slots_at_gc_start;
/* basic statistics */
size_t count;
@@ -571,13 +628,14 @@ typedef struct rb_objspace {
/* Weak references */
size_t weak_references_count;
- size_t retained_weak_references_count;
} profile;
VALUE gc_stress_mode;
struct {
+ bool parent_object_old_p;
VALUE parent_object;
+
int need_major_gc;
size_t last_major_gc;
size_t uncollectible_wb_unprotected_objects;
@@ -586,7 +644,6 @@ typedef struct rb_objspace {
size_t old_objects_limit;
#if RGENGC_ESTIMATE_OLDMALLOC
- size_t oldmalloc_increase;
size_t oldmalloc_increase_limit;
#endif
@@ -616,10 +673,16 @@ typedef struct rb_objspace {
VALUE stress_to_class;
#endif
- rb_darray(VALUE *) weak_references;
+ rb_darray(VALUE) weak_references;
rb_postponed_job_handle_t finalize_deferred_pjob;
unsigned long live_ractor_cache_count;
+
+ int sweeping_heap_count;
+
+ int fork_vm_lock_lev;
+
+ struct rb_gc_vm_context vm_context;
} rb_objspace_t;
#ifndef HEAP_PAGE_ALIGN_LOG
@@ -627,10 +690,10 @@ typedef struct rb_objspace {
#define HEAP_PAGE_ALIGN_LOG 16
#endif
-#if RACTOR_CHECK_MODE || GC_DEBUG
+#if RB_GC_OBJ_HAS_SUFFIX || GC_DEBUG
struct rvalue_overhead {
-# if RACTOR_CHECK_MODE
- uint32_t _ractor_belonging_id;
+# if RB_GC_OBJ_HAS_SUFFIX
+ struct rb_gc_obj_suffix suffix;
# endif
# if GC_DEBUG
const char *file;
@@ -653,7 +716,32 @@ size_t rb_gc_impl_obj_slot_size(VALUE obj);
# endif
#endif
-#define BASE_SLOT_SIZE (sizeof(struct RBasic) + sizeof(VALUE[RBIMPL_RVALUE_EMBED_LEN_MAX]) + RVALUE_OVERHEAD)
+#define RVALUE_SLOT_SIZE (sizeof(struct RBasic) + sizeof(VALUE[RBIMPL_RVALUE_EMBED_LEN_MAX]) + RVALUE_OVERHEAD)
+
+static const size_t pool_slot_sizes[HEAP_COUNT] = {
+#define SLOT(size) ((size) + RVALUE_OVERHEAD),
+ EACH_POOL_SLOT_SIZE(SLOT)
+#undef SLOT
+};
+
+/* Precomputed reciprocals for fast slot index calculation.
+ * For slot size d: reciprocal = ceil(2^48 / d).
+ * Then offset / d == (uint32_t)((offset * reciprocal) >> 48)
+ * for all offset < HEAP_PAGE_SIZE. */
+#define SLOT_RECIPROCAL_SHIFT 48
+#define SLOT_RECIPROCAL(size) (((1ULL << SLOT_RECIPROCAL_SHIFT) + (size) - 1) / (size))
+
+static const uint64_t heap_slot_reciprocal_table[HEAP_COUNT] = {
+#define SLOT(size) SLOT_RECIPROCAL((size) + RVALUE_OVERHEAD),
+ EACH_POOL_SLOT_SIZE(SLOT)
+#undef SLOT
+};
+
+#if SIZEOF_VALUE >= 8
+static uint8_t size_to_heap_idx[1024 / 8 + 1];
+#else
+static uint8_t size_to_heap_idx[512 / 8 + 1];
+#endif
#ifndef MAX
# define MAX(a, b) (((a) > (b)) ? (a) : (b))
@@ -663,12 +751,12 @@ size_t rb_gc_impl_obj_slot_size(VALUE obj);
#endif
#define roomof(x, y) (((x) + (y) - 1) / (y))
#define CEILDIV(i, mod) roomof(i, mod)
+#define MIN_POOL_SLOT_SIZE 32
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_LIMIT = CEILDIV(CEILDIV(HEAP_PAGE_SIZE, MIN_POOL_SLOT_SIZE), BITS_BITLENGTH),
HEAP_PAGE_BITMAP_SIZE = (BITS_SIZE * HEAP_PAGE_BITMAP_LIMIT),
};
#define HEAP_PAGE_ALIGN (1 << HEAP_PAGE_ALIGN_LOG)
@@ -730,6 +818,10 @@ struct free_slot {
};
struct heap_page {
+ /* Cache line 0: allocation fast path + SLOT_INDEX */
+ struct free_slot *freelist;
+ uintptr_t start;
+ uint64_t slot_size_reciprocal;
unsigned short slot_size;
unsigned short total_slots;
unsigned short free_slots;
@@ -745,8 +837,6 @@ struct heap_page {
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];
@@ -807,42 +897,63 @@ heap_page_in_global_empty_pages_pool(rb_objspace_t *objspace, struct heap_page *
#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))
+static inline size_t
+slot_index_for_offset(size_t offset, uint64_t reciprocal)
+{
+ return (uint32_t)(((uint64_t)offset * reciprocal) >> SLOT_RECIPROCAL_SHIFT);
+}
-/* 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))
+#define SLOT_INDEX(page, p) slot_index_for_offset((uintptr_t)(p) - (page)->start, (page)->slot_size_reciprocal)
+#define SLOT_BITMAP_INDEX(page, p) (SLOT_INDEX(page, p) / BITS_BITLENGTH)
+#define SLOT_BITMAP_OFFSET(page, p) (SLOT_INDEX(page, p) & (BITS_BITLENGTH - 1))
+#define SLOT_BITMAP_BIT(page, p) ((bits_t)1 << SLOT_BITMAP_OFFSET(page, p))
+
+#define _MARKED_IN_BITMAP(bits, page, p) ((bits)[SLOT_BITMAP_INDEX(page, p)] & SLOT_BITMAP_BIT(page, p))
+#define _MARK_IN_BITMAP(bits, page, p) ((bits)[SLOT_BITMAP_INDEX(page, p)] |= SLOT_BITMAP_BIT(page, p))
+#define _CLEAR_IN_BITMAP(bits, page, p) ((bits)[SLOT_BITMAP_INDEX(page, p)] &= ~SLOT_BITMAP_BIT(page, p))
+
+#define MARKED_IN_BITMAP(bits, p) _MARKED_IN_BITMAP(bits, GET_HEAP_PAGE(p), p)
+#define MARK_IN_BITMAP(bits, p) _MARK_IN_BITMAP(bits, GET_HEAP_PAGE(p), p)
+#define CLEAR_IN_BITMAP(bits, p) _CLEAR_IN_BITMAP(bits, GET_HEAP_PAGE(p), 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 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;
+ struct heap_page *page = GET_HEAP_PAGE(obj);
+ bits_t *age_bits = page->age_bits;
+ size_t slot_idx = SLOT_INDEX(page, obj);
+ size_t idx = (slot_idx / BITS_BITLENGTH) * 2;
+ int shift = (int)(slot_idx & (BITS_BITLENGTH - 1));
+ int lo = (age_bits[idx] >> shift) & 1;
+ int hi = (age_bits[idx + 1] >> shift) & 1;
+ return lo | (hi << 1);
}
static void
-RVALUE_AGE_SET(VALUE obj, int age)
+RVALUE_AGE_SET_BITMAP(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));
+ struct heap_page *page = GET_HEAP_PAGE(obj);
+ bits_t *age_bits = page->age_bits;
+ size_t slot_idx = SLOT_INDEX(page, obj);
+ size_t idx = (slot_idx / BITS_BITLENGTH) * 2;
+ int shift = (int)(slot_idx & (BITS_BITLENGTH - 1));
+ bits_t mask = (bits_t)1 << shift;
+
+ age_bits[idx] = (age_bits[idx] & ~mask) | ((bits_t)(age & 1) << shift);
+ age_bits[idx + 1] = (age_bits[idx + 1] & ~mask) | ((bits_t)((age >> 1) & 1) << shift);
+}
+
+static void
+RVALUE_AGE_SET(VALUE obj, int age)
+{
+ RVALUE_AGE_SET_BITMAP(obj, age);
if (age == RVALUE_OLD_AGE) {
RB_FL_SET_RAW(obj, RUBY_FL_PROMOTED);
}
@@ -852,8 +963,112 @@ RVALUE_AGE_SET(VALUE obj, int age)
}
#define malloc_limit objspace->malloc_params.limit
-#define malloc_increase objspace->malloc_params.increase
+#define malloc_increase gc_malloc_counters_increase_unsigned(objspace, &objspace->malloc_counters.counters)
#define malloc_allocated_size objspace->malloc_params.allocated_size
+
+#ifdef MALLOC_COUNTERS_NEED_LOCK
+# define MALLOC_COUNTERS_LOCK(o) rb_native_mutex_lock(&(o)->malloc_counters.lock)
+# define MALLOC_COUNTERS_UNLOCK(o) rb_native_mutex_unlock(&(o)->malloc_counters.lock)
+#else
+# define MALLOC_COUNTERS_LOCK(o) ((void)0)
+# define MALLOC_COUNTERS_UNLOCK(o) ((void)0)
+#endif
+
+static inline void
+gc_counter_add(gc_counter_t *p, size_t delta)
+{
+#ifdef MALLOC_COUNTERS_NEED_LOCK
+ *p += (gc_counter_t)delta;
+#else
+ rbimpl_atomic_u64_fetch_add_relaxed(p, (uint64_t)delta);
+#endif
+}
+
+static inline gc_counter_t
+gc_counter_load_relaxed(const gc_counter_t *p)
+{
+#ifdef MALLOC_COUNTERS_NEED_LOCK
+ return *p;
+#else
+ return rbimpl_atomic_u64_load_relaxed(p);
+#endif
+}
+
+static inline gc_counter_t
+gc_counter_load_acquire(const gc_counter_t *p)
+{
+#ifdef MALLOC_COUNTERS_NEED_LOCK
+ return *p;
+#else
+ return rbimpl_atomic_u64_load_acquire(p);
+#endif
+}
+
+static inline void
+gc_counter_store_release(gc_counter_t *p, gc_counter_t v)
+{
+#ifdef MALLOC_COUNTERS_NEED_LOCK
+ *p = v;
+#else
+ rbimpl_atomic_u64_set_release(p, v);
+#endif
+}
+
+static inline int64_t
+gc_malloc_counters_increase(rb_objspace_t *objspace, const struct gc_malloc_bytes *c)
+{
+ MALLOC_COUNTERS_LOCK(objspace);
+ gc_counter_t malloc_at = gc_counter_load_acquire(&c->malloc_at_last_gc);
+ gc_counter_t free_at = gc_counter_load_acquire(&c->free_at_last_gc);
+ gc_counter_t malloc_now = gc_counter_load_relaxed(&c->malloc);
+ gc_counter_t free_now = gc_counter_load_relaxed(&c->free);
+ MALLOC_COUNTERS_UNLOCK(objspace);
+
+ gc_counter_t malloc_delta = malloc_now - malloc_at;
+ gc_counter_t free_delta = free_now - free_at;
+
+ if (malloc_delta >= free_delta) {
+ return (int64_t)(malloc_delta - free_delta);
+ }
+ else {
+ return -(int64_t)(free_delta - malloc_delta);
+ }
+}
+
+static inline size_t
+gc_malloc_counters_increase_unsigned(rb_objspace_t *objspace, const struct gc_malloc_bytes *c)
+{
+ int64_t inc = gc_malloc_counters_increase(objspace, c);
+ if (inc <= 0) return 0;
+#if SIZEOF_SIZE_T < 8
+ if ((uint64_t)inc > SIZE_MAX) return SIZE_MAX;
+#endif
+ return (size_t)inc;
+}
+
+static inline int64_t
+gc_malloc_counters_snapshot(rb_objspace_t *objspace, struct gc_malloc_bytes *c)
+{
+ MALLOC_COUNTERS_LOCK(objspace);
+ gc_counter_t malloc_now = gc_counter_load_relaxed(&c->malloc);
+ gc_counter_t free_now = gc_counter_load_relaxed(&c->free);
+ gc_counter_t malloc_at = gc_counter_load_relaxed(&c->malloc_at_last_gc);
+ gc_counter_t free_at = gc_counter_load_relaxed(&c->free_at_last_gc);
+ gc_counter_store_release(&c->malloc_at_last_gc, malloc_now);
+ gc_counter_store_release(&c->free_at_last_gc, free_now);
+ MALLOC_COUNTERS_UNLOCK(objspace);
+
+ gc_counter_t malloc_delta = malloc_now - malloc_at;
+ gc_counter_t free_delta = free_now - free_at;
+
+ if (malloc_delta >= free_delta) {
+ return (int64_t)(malloc_delta - free_delta);
+ }
+ else {
+ return -(int64_t)(free_delta - malloc_delta);
+ }
+}
+
#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
@@ -919,12 +1134,7 @@ gc_mode_verify(enum gc_mode 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;
+ return objspace->sweeping_heap_count != 0;
}
static inline size_t
@@ -979,9 +1189,22 @@ total_final_slots_count(rb_objspace_t *objspace)
#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
+/*
+ * Byte budget for incremental sweep steps. Each step sweeps at most
+ * this many bytes worth of slots before yielding. The effective slot
+ * count per step is GC_INCREMENTAL_SWEEP_BYTES / heap->slot_size,
+ * so larger slot pools (which are less heavily used) naturally get
+ * fewer slots swept per step.
+ *
+ * Baseline: 2048 slots * RVALUE_SLOT_SIZE = 2048 * 40 = 81920 bytes,
+ * preserving the historical behavior for the smallest heap.
+ */
+#define GC_INCREMENTAL_SWEEP_BYTES (2048 * RVALUE_SLOT_SIZE)
+#define GC_INCREMENTAL_SWEEP_POOL_BYTES (1024 * RVALUE_SLOT_SIZE)
#define is_lazy_sweeping(objspace) (GC_ENABLE_LAZY_SWEEP && has_sweeping_pages(objspace))
+/* In lazy sweeping or the previous incremental marking finished and did not yield a free page. */
+#define needs_continue_sweeping(objspace, heap) \
+ ((heap)->free_pages == NULL && is_lazy_sweeping(objspace))
#if SIZEOF_LONG == SIZEOF_VOIDP
# define obj_id_to_ref(objid) ((objid) ^ FIXNUM_FLAG) /* unset FIXNUM_FLAG */
@@ -993,7 +1216,7 @@ total_final_slots_count(rb_objspace_t *objspace)
#endif
struct RZombie {
- struct RBasic basic;
+ VALUE flags;
VALUE next;
void (*dfree)(void *);
void *data;
@@ -1345,16 +1568,12 @@ check_rvalue_consistency(rb_objspace_t *objspace, const VALUE obj)
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;
+
+ bool ret;
+ asan_unpoisoning_object(obj) {
+ ret = BUILTIN_TYPE(obj) == T_MOVED;
}
+ return ret;
}
static inline int
@@ -1495,7 +1714,6 @@ 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
@@ -1525,13 +1743,6 @@ rb_gc_impl_get_measure_total_time(void *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];
-}
-
/* garbage objects will be collected soon. */
bool
rb_gc_impl_garbage_object_p(void *objspace_ptr, VALUE ptr)
@@ -1557,6 +1768,14 @@ rb_gc_impl_garbage_object_p(void *objspace_ptr, VALUE ptr)
!RVALUE_MARKED(objspace, ptr);
}
+struct rb_gc_vm_context *
+rb_gc_impl_get_vm_context(void *objspace_ptr)
+{
+ rb_objspace_t *objspace = objspace_ptr;
+
+ return &objspace->vm_context;
+}
+
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);
@@ -1574,13 +1793,14 @@ heap_page_add_freeobj(rb_objspace_t *objspace, struct heap_page *page, VALUE obj
page->freelist = slot;
asan_lock_freelist(page);
- RVALUE_AGE_RESET(obj);
+ // Should have already been reset
+ GC_ASSERT(RVALUE_AGE_GET(obj) == 0);
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)) {
+ obj % sizeof(VALUE) == 0)) {
rb_bug("heap_page_add_freeobj: %p is not rvalue.", (void *)obj);
}
@@ -1589,8 +1809,8 @@ heap_page_add_freeobj(rb_objspace_t *objspace, struct heap_page *page, VALUE obj
}
static void
-heap_allocatable_slots_expand(rb_objspace_t *objspace,
- rb_heap_t *heap, size_t free_slots, size_t total_slots)
+heap_allocatable_bytes_expand(rb_objspace_t *objspace,
+ rb_heap_t *heap, size_t free_slots, size_t total_slots, size_t slot_size)
{
double goal_ratio = gc_params.heap_free_slots_goal_ratio;
size_t target_total_slots;
@@ -1599,7 +1819,7 @@ heap_allocatable_slots_expand(rb_objspace_t *objspace,
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);
+ target_total_slots = gc_params.heap_init_bytes / slot_size;
}
else {
/* Find `f' where free_slots = f * total_slots * goal_ratio
@@ -1622,8 +1842,8 @@ heap_allocatable_slots_expand(rb_objspace_t *objspace,
}
}
- if (gc_params.growth_max_slots > 0) {
- size_t max_total_slots = (size_t)(total_slots + gc_params.growth_max_slots);
+ if (gc_params.growth_max_bytes > 0) {
+ size_t max_total_slots = total_slots + gc_params.growth_max_bytes / slot_size;
if (target_total_slots > max_total_slots) target_total_slots = max_total_slots;
}
@@ -1631,7 +1851,7 @@ heap_allocatable_slots_expand(rb_objspace_t *objspace,
/* Extend by at least 1 page. */
if (extend_slot_count == 0) extend_slot_count = 1;
- objspace->heap_pages.allocatable_slots += extend_slot_count;
+ objspace->heap_pages.allocatable_bytes += extend_slot_count * slot_size;
}
static inline void
@@ -1921,31 +2141,22 @@ heap_add_page(rb_objspace_t *objspace, rb_heap_t *heap, struct heap_page *page)
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) */
+ /* Align start to slot_size boundary */
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);
- }
+ uintptr_t rem = start % heap->slot_size;
+ if (rem) start += heap->slot_size - rem;
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->slot_size_reciprocal = heap_slot_reciprocal_table[heap - heaps];
page->heap = heap;
+ memset(&page->wb_unprotected_bits[0], 0, HEAP_PAGE_BITMAP_SIZE);
+ memset(&page->age_bits[0], 0, sizeof(page->age_bits));
+
asan_unlock_freelist(page);
page->freelist = NULL;
asan_unpoison_memory_region(page->body, HEAP_PAGE_SIZE, false);
@@ -1967,13 +2178,13 @@ static int
heap_page_allocate_and_initialize(rb_objspace_t *objspace, rb_heap_t *heap)
{
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);
+ "allocatable_bytes: %"PRIdSIZE", heap->total_pages: %"PRIdSIZE"\n",
+ rb_darray_size(objspace->heap_pages.sorted), objspace->heap_pages.allocatable_bytes, heap->total_pages);
bool allocated = false;
struct heap_page *page = heap_page_resurrect(objspace);
- if (page == NULL && objspace->heap_pages.allocatable_slots > 0) {
+ if (page == NULL && objspace->heap_pages.allocatable_bytes > 0) {
page = heap_page_allocate(objspace);
allocated = true;
@@ -1985,11 +2196,12 @@ heap_page_allocate_and_initialize(rb_objspace_t *objspace, rb_heap_t *heap)
heap_add_freepage(heap, page);
if (allocated) {
- if (objspace->heap_pages.allocatable_slots > (size_t)page->total_slots) {
- objspace->heap_pages.allocatable_slots -= page->total_slots;
+ size_t page_bytes = (size_t)page->total_slots * page->slot_size;
+ if (objspace->heap_pages.allocatable_bytes > page_bytes) {
+ objspace->heap_pages.allocatable_bytes -= page_bytes;
}
else {
- objspace->heap_pages.allocatable_slots = 0;
+ objspace->heap_pages.allocatable_bytes = 0;
}
}
}
@@ -2000,19 +2212,21 @@ heap_page_allocate_and_initialize(rb_objspace_t *objspace, rb_heap_t *heap)
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;
+ size_t prev_allocatable_bytes = objspace->heap_pages.allocatable_bytes;
+ objspace->heap_pages.allocatable_bytes = HEAP_PAGE_SIZE;
heap_page_allocate_and_initialize(objspace, heap);
GC_ASSERT(heap->free_pages != NULL);
- objspace->heap_pages.allocatable_slots = prev_allocatable_slots;
+ objspace->heap_pages.allocatable_bytes = prev_allocatable_bytes;
}
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);
+ bool needs_gc = is_incremental_marking(objspace) || needs_continue_sweeping(objspace, heap);
+ if (!needs_gc) return;
+
+ gc_enter(objspace, gc_enter_event_continue, &lock_lev); // takes vm barrier, try to avoid
/* Continue marking if in incremental marking. */
if (is_incremental_marking(objspace)) {
@@ -2021,9 +2235,7 @@ gc_continue(rb_objspace_t *objspace, rb_heap_t *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)) {
+ if (needs_continue_sweeping(objspace, heap)) {
gc_sweep_continue(objspace, heap);
}
@@ -2035,7 +2247,7 @@ 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] &&
+ if (heap->total_slots < gc_params.heap_init_bytes / heap->slot_size &&
heap->sweeping_page == NULL) {
heap_page_allocate_and_initialize_force(objspace, heap);
GC_ASSERT(heap->free_pages != NULL);
@@ -2053,17 +2265,17 @@ heap_prepare(rb_objspace_t *objspace, rb_heap_t *heap)
* we should start a new GC cycle. */
if (heap->free_pages == NULL) {
GC_ASSERT(objspace->empty_pages_count == 0);
- GC_ASSERT(objspace->heap_pages.allocatable_slots == 0);
+ GC_ASSERT(objspace->heap_pages.allocatable_bytes == 0);
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,
+ if (objspace->heap_pages.allocatable_bytes == 0 && !gc_config_full_mark_val) {
+ heap_allocatable_bytes_expand(objspace, heap,
heap->freed_slots + heap->empty_slots,
- heap->total_slots);
- GC_ASSERT(objspace->heap_pages.allocatable_slots > 0);
+ heap->total_slots, heap->slot_size);
+ GC_ASSERT(objspace->heap_pages.allocatable_bytes > 0);
}
/* Do steps of incremental marking or lazy sweeping if the GC run permits. */
gc_continue(objspace, heap);
@@ -2096,16 +2308,6 @@ heap_prepare(rb_objspace_t *objspace, rb_heap_t *heap)
GC_ASSERT(heap->free_pages != NULL);
}
-static inline VALUE
-newobj_fill(VALUE obj, VALUE v1, VALUE v2, VALUE v3)
-{
- VALUE *p = (VALUE *)(obj + sizeof(struct RBasic));
- p[0] = v1;
- p[1] = v2;
- p[2] = v3;
- return obj;
-}
-
#if GC_DEBUG
static inline const char*
rb_gc_impl_source_location_cstr(int *ptr)
@@ -2135,19 +2337,7 @@ newobj_init(VALUE klass, VALUE flags, int wb_protected, rb_objspace_t *objspace,
RBASIC(obj)->shape_id = 0;
#endif
- 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);
@@ -2203,25 +2393,27 @@ 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;
+ return pool_slot_sizes[pool_id] - RVALUE_OVERHEAD;
}
bool
rb_gc_impl_size_allocatable_p(size_t size)
{
- return size <= heap_slot_size(HEAP_COUNT - 1);
+ return size + RVALUE_OVERHEAD <= pool_slot_sizes[HEAP_COUNT - 1];
}
static const size_t ALLOCATED_COUNT_STEP = 1024;
+static void
+ractor_cache_flush_count(rb_objspace_t *objspace, rb_ractor_newobj_cache_t *cache)
+{
+ for (int heap_idx = 0; heap_idx < HEAP_COUNT; heap_idx++) {
+ rb_ractor_newobj_heap_cache_t *heap_cache = &cache->heap_caches[heap_idx];
+
+ rb_heap_t *heap = &heaps[heap_idx];
+ RUBY_ATOMIC_SIZE_ADD(heap->total_allocated_objects, heap_cache->allocated_objects_count);
+ heap_cache->allocated_objects_count = 0;
+ }
+}
static inline VALUE
ractor_cache_allocate_slot(rb_objspace_t *objspace, rb_ractor_newobj_cache_t *cache,
@@ -2246,19 +2438,11 @@ ractor_cache_allocate_slot(rb_objspace_t *objspace, rb_ractor_newobj_cache_t *ca
rb_asan_unpoison_object(obj, true);
heap_cache->freelist = p->next;
- if (rb_gc_multi_ractor_p()) {
- heap_cache->allocated_objects_count++;
- rb_heap_t *heap = &heaps[heap_idx];
- if (heap_cache->allocated_objects_count >= ALLOCATED_COUNT_STEP) {
- RUBY_ATOMIC_SIZE_ADD(heap->total_allocated_objects, heap_cache->allocated_objects_count);
- heap_cache->allocated_objects_count = 0;
- }
- }
- else {
- rb_heap_t *heap = &heaps[heap_idx];
- heap->total_allocated_objects++;
- GC_ASSERT(heap->total_slots >=
- (heap->total_allocated_objects - heap->total_freed_objects - heap->final_slots_count));
+ heap_cache->allocated_objects_count++;
+ rb_heap_t *heap = &heaps[heap_idx];
+ if (heap_cache->allocated_objects_count >= ALLOCATED_COUNT_STEP) {
+ RUBY_ATOMIC_SIZE_ADD(heap->total_allocated_objects, heap_cache->allocated_objects_count);
+ heap_cache->allocated_objects_count = 0;
}
#if RGENGC_CHECK_MODE
@@ -2314,28 +2498,30 @@ ractor_cache_set_page(rb_objspace_t *objspace, rb_ractor_newobj_cache_t *cache,
rb_asan_poison_object((VALUE)heap_cache->freelist);
}
+static void
+init_size_to_heap_idx(void)
+{
+ for (size_t i = 0; i < sizeof(size_to_heap_idx); i++) {
+ size_t effective = i * 8 + RVALUE_OVERHEAD;
+ uint8_t idx;
+ for (idx = 0; idx < HEAP_COUNT; idx++) {
+ if (effective <= pool_slot_sizes[idx]) break;
+ }
+ size_to_heap_idx[i] = idx;
+ }
+}
+
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);
+ size_t compressed = (size + 7) >> 3;
+ if (compressed < sizeof(size_to_heap_idx)) {
+ size_t heap_idx = size_to_heap_idx[compressed];
+ if (RB_LIKELY(heap_idx < HEAP_COUNT)) return 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;
+ rb_bug("heap_idx_for_size: allocation size too large "
+ "(size=%"PRIuSIZE")", size);
}
size_t
@@ -2469,7 +2655,7 @@ newobj_slowpath_wb_unprotected(VALUE klass, VALUE flags, rb_objspace_t *objspace
}
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)
+rb_gc_impl_new_obj(void *objspace_ptr, void *cache_ptr, VALUE klass, VALUE flags, bool wb_protected, size_t alloc_size)
{
VALUE obj;
rb_objspace_t *objspace = objspace_ptr;
@@ -2500,7 +2686,7 @@ rb_gc_impl_new_obj(void *objspace_ptr, void *cache_ptr, VALUE klass, VALUE flags
newobj_slowpath_wb_unprotected(klass, flags, objspace, cache, heap_idx);
}
- return newobj_fill(obj, v1, v2, v3);
+ return obj;
}
static int
@@ -2552,7 +2738,7 @@ is_pointer_to_heap(rb_objspace_t *objspace, const void *ptr)
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;
+ if (p % sizeof(VALUE) != 0) return FALSE;
RB_DEBUG_COUNTER_INC(gc_isptr_align);
page = heap_page_for_ptr(objspace, (uintptr_t)ptr);
@@ -2564,7 +2750,7 @@ is_pointer_to_heap(rb_objspace_t *objspace, const void *ptr)
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;
+ if ((p - page->start) % page->slot_size != 0) return FALSE;
return TRUE;
}
@@ -2586,7 +2772,7 @@ rb_gc_impl_make_zombie(void *objspace_ptr, VALUE obj, void (*dfree)(void *), voi
rb_objspace_t *objspace = objspace_ptr;
struct RZombie *zombie = RZOMBIE(obj);
- zombie->basic.flags = T_ZOMBIE | (zombie->basic.flags & ZOMBIE_OBJ_KEPT_FLAGS);
+ zombie->flags = T_ZOMBIE | (zombie->flags & ZOMBIE_OBJ_KEPT_FLAGS);
zombie->dfree = dfree;
zombie->data = data;
VALUE prev, next = heap_pages_deferred_final;
@@ -2761,24 +2947,27 @@ rb_gc_impl_define_finalizer(void *objspace_ptr, VALUE obj, VALUE block)
RBASIC(obj)->flags |= FL_FINALIZE;
- int lev = RB_GC_VM_LOCK();
+ unsigned int lev = RB_GC_VM_LOCK();
if (st_lookup(finalizer_table, obj, &data)) {
table = (VALUE)data;
+ VALUE dup_table = rb_ary_dup(table);
+ RB_GC_VM_UNLOCK(lev);
/* 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)) {
- RB_GC_VM_UNLOCK(lev);
+ VALUE recv = RARRAY_AREF(dup_table, i);
+ if (rb_equal(recv, block)) { // can't be called with VM lock held
return recv;
}
}
}
+ lev = RB_GC_VM_LOCK();
+ RB_GC_GUARD(dup_table);
rb_ary_push(table, block);
}
@@ -2839,8 +3028,8 @@ get_final(long i, void *data)
return RARRAY_AREF(table, i + 1);
}
-static void
-run_final(rb_objspace_t *objspace, VALUE zombie)
+static unsigned int
+run_final(rb_objspace_t *objspace, VALUE zombie, unsigned int lev)
{
if (RZOMBIE(zombie)->dfree) {
RZOMBIE(zombie)->dfree(RZOMBIE(zombie)->data);
@@ -2851,7 +3040,9 @@ run_final(rb_objspace_t *objspace, VALUE zombie)
FL_UNSET(zombie, FL_FINALIZE);
st_data_t table;
if (st_delete(finalizer_table, &key, &table)) {
+ RB_GC_VM_UNLOCK(lev);
rb_gc_run_obj_finalizer(RARRAY_AREF(table, 0), RARRAY_LEN(table) - 1, get_final, (void *)table);
+ lev = RB_GC_VM_LOCK();
}
else {
rb_bug("FL_FINALIZE flag is set, but finalizers are not found");
@@ -2860,6 +3051,7 @@ run_final(rb_objspace_t *objspace, VALUE zombie)
else {
GC_ASSERT(!st_lookup(finalizer_table, key, NULL));
}
+ return lev;
}
static void
@@ -2872,9 +3064,9 @@ finalize_list(rb_objspace_t *objspace, VALUE zombie)
next_zombie = RZOMBIE(zombie)->next;
page = GET_HEAP_PAGE(zombie);
- int lev = RB_GC_VM_LOCK();
+ unsigned int lev = RB_GC_VM_LOCK();
- run_final(objspace, zombie);
+ lev = run_final(objspace, zombie, lev);
{
GC_ASSERT(BUILTIN_TYPE(zombie) == T_ZOMBIE);
GC_ASSERT(page->heap->final_slots_count > 0);
@@ -2883,6 +3075,7 @@ finalize_list(rb_objspace_t *objspace, VALUE zombie)
page->heap->final_slots_count--;
page->final_slots--;
page->free_slots++;
+ RVALUE_AGE_SET_BITMAP(zombie, 0);
heap_page_add_freeobj(objspace, page, zombie);
page->heap->total_freed_objects++;
}
@@ -2942,6 +3135,7 @@ gc_abort(void *objspace_ptr)
}
if (is_lazy_sweeping(objspace)) {
+ objspace->sweeping_heap_count = 0;
for (int i = 0; i < HEAP_COUNT; i++) {
rb_heap_t *heap = &heaps[i];
@@ -3127,7 +3321,7 @@ gc_setup_mark_bits(struct heap_page *page)
}
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);
+static VALUE gc_move(rb_objspace_t *objspace, VALUE scan, VALUE free, struct heap_page *src_page, struct heap_page *dest_page);
#if defined(_WIN32)
enum {HEAP_PAGE_LOCK = PAGE_NOACCESS, HEAP_PAGE_UNLOCK = PAGE_READWRITE};
@@ -3210,7 +3404,7 @@ try_move(rb_objspace_t *objspace, rb_heap_t *heap, struct heap_page *free_page,
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_move(objspace, src, dest, src_page, free_page);
gc_pin(objspace, src);
free_page->free_slots--;
@@ -3448,18 +3642,35 @@ gc_sweep_plane(rb_objspace_t *objspace, rb_heap_t *heap, uintptr_t p, bits_t bit
{
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);
+ GC_ASSERT(vp % sizeof(VALUE) == 0);
rb_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);
+ 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;
+
+ default:
#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);
@@ -3467,8 +3678,6 @@ gc_sweep_plane(rb_objspace_t *objspace, rb_heap_t *heap, uintptr_t p, bits_t bit
}
#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);
@@ -3478,45 +3687,31 @@ gc_sweep_plane(rb_objspace_t *objspace, rb_heap_t *heap, uintptr_t p, bits_t bit
#undef CHECK
#endif
- rb_gc_event_hook(vp, RUBY_INTERNAL_EVENT_FREEOBJ);
-
- rb_gc_obj_free_vm_weak_references(vp);
- if (rb_gc_obj_free(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);
+ if (!rb_gc_obj_needs_cleanup_p(vp)) {
+ (void)VALGRIND_MAKE_MEM_UNDEFINED((void*)p, 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));
+ gc_report(3, objspace, "page_sweep: %s (fast path) added to freelist\n", rb_obj_info(vp));
ctx->freed_slots++;
}
else {
- ctx->final_slots++;
- }
- break;
+ gc_report(2, objspace, "page_sweep: free %p\n", (void *)p);
- 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");
+ rb_gc_obj_free_vm_weak_references(vp);
+ if (rb_gc_obj_free(objspace, vp)) {
+ (void)VALGRIND_MAKE_MEM_UNDEFINED((void*)p, 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++;
+ }
}
- 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;
+ bitset >>= 1;
} while (bitset);
}
@@ -3541,34 +3736,33 @@ gc_sweep_page(rb_objspace_t *objspace, rb_heap_t *heap, struct gc_sweep_context
p = (uintptr_t)sweep_page->start;
bits = sweep_page->mark_bits;
+ short slot_size = sweep_page->slot_size;
+ int total_slots = sweep_page->total_slots;
+ int bitmap_plane_count = CEILDIV(total_slots, BITS_BITLENGTH);
- 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);
+ int out_of_range_bits = total_slots % BITS_BITLENGTH;
+ if (out_of_range_bits != 0) {
+ bits[bitmap_plane_count - 1] |= ~(((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);
+ // Clear wb_unprotected and age bits for all unmarked slots
+ {
+ bits_t *wb_unprotected_bits = sweep_page->wb_unprotected_bits;
+ bits_t *age_bits = sweep_page->age_bits;
+ for (int i = 0; i < bitmap_plane_count; i++) {
+ bits_t unmarked = ~bits[i];
+ wb_unprotected_bits[i] &= ~unmarked;
+ age_bits[i * 2] &= ~unmarked;
+ age_bits[i * 2 + 1] &= ~unmarked;
+ }
}
- p += (BITS_BITLENGTH - NUM_IN_PAGE(p)) * BASE_SLOT_SIZE;
- for (int i = 1; i < bitmap_plane_count; i++) {
+ for (int i = 0; i < bitmap_plane_count; i++) {
bitset = ~bits[i];
if (bitset) {
gc_sweep_plane(objspace, heap, p, bitset, ctx);
}
- p += BITS_BITLENGTH * BASE_SLOT_SIZE;
+ p += BITS_BITLENGTH * slot_size;
}
if (!heap->compact_cursor) {
@@ -3670,6 +3864,9 @@ 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);
+ if (heap->sweeping_page) {
+ objspace->sweeping_heap_count++;
+ }
heap->free_pages = NULL;
heap->pooled_pages = NULL;
if (!objspace->flags.immediate_sweep) {
@@ -3718,11 +3915,71 @@ gc_ractor_newobj_cache_clear(void *c, void *data)
}
static void
+gc_sweep_freeobj_hooks_page(rb_objspace_t *objspace, struct heap_page *page)
+{
+ bits_t *bits = page->mark_bits;
+ uintptr_t p = (uintptr_t)page->start;
+ short slot_size = page->slot_size;
+ int total_slots = page->total_slots;
+ int bitmap_plane_count = CEILDIV(total_slots, BITS_BITLENGTH);
+
+ int out_of_range_bits = total_slots % BITS_BITLENGTH;
+ bits_t last_plane_mask = (out_of_range_bits != 0)
+ ? ~(((bits_t)1 << out_of_range_bits) - 1)
+ : 0;
+
+ for (int j = 0; j < bitmap_plane_count; j++) {
+ bits_t bitset = ~bits[j];
+ if (j == bitmap_plane_count - 1) {
+ bitset &= ~last_plane_mask;
+ }
+
+ uintptr_t pp = p;
+ while (bitset) {
+ if (bitset & 1) {
+ VALUE vp = (VALUE)pp;
+ asan_unpoisoning_object(vp) {
+ switch (BUILTIN_TYPE(vp)) {
+ case T_NONE:
+ case T_ZOMBIE:
+ case T_MOVED:
+ break;
+ default:
+ rb_gc_event_hook(vp, RUBY_INTERNAL_EVENT_FREEOBJ);
+ break;
+ }
+ }
+ }
+ pp += slot_size;
+ bitset >>= 1;
+ }
+ p += BITS_BITLENGTH * slot_size;
+ }
+}
+
+static void
+gc_sweep_freeobj_hooks(rb_objspace_t *objspace)
+{
+ for (int i = 0; i < HEAP_COUNT; i++) {
+ rb_heap_t *heap = &heaps[i];
+ struct heap_page *page = NULL;
+
+ ccan_list_for_each(&heap->pages, page, page_node) {
+ gc_sweep_freeobj_hooks_page(objspace, page);
+ }
+ }
+}
+
+static void
gc_sweep_start(rb_objspace_t *objspace)
{
gc_mode_transition(objspace, gc_mode_sweeping);
objspace->rincgc.pooled_slots = 0;
+ if (RB_UNLIKELY(objspace->hook_events & RUBY_INTERNAL_EVENT_FREEOBJ)) {
+ gc_sweep_freeobj_hooks(objspace);
+ }
+
#if GC_CAN_COMPILE_COMPACTION
if (objspace->flags.during_compacting) {
gc_sort_heap_by_compare_func(
@@ -3753,7 +4010,7 @@ 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 init_slots = gc_params.heap_init_bytes / heap->slot_size;
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 &&
@@ -3777,11 +4034,12 @@ gc_sweep_finish_heap(rb_objspace_t *objspace, rb_heap_t *heap)
* 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) {
- if (objspace->heap_pages.allocatable_slots < min_free_slots) {
- heap_allocatable_slots_expand(objspace, heap, swept_slots, heap->total_slots);
+ if (objspace->heap_pages.allocatable_bytes < min_free_slots * heap->slot_size) {
+ heap_allocatable_bytes_expand(objspace, heap, swept_slots, heap->total_slots, heap->slot_size);
}
}
- else {
+ else if (swept_slots < min_free_slots * 7 / 8 &&
+ objspace->heap_pages.allocatable_bytes < (min_free_slots * 7 / 8 - swept_slots) * heap->slot_size) {
gc_needs_major_flags |= GPR_FLAG_MAJOR_BY_NOFREE;
heap->force_major_gc_count++;
}
@@ -3817,6 +4075,13 @@ gc_sweep_finish(rb_objspace_t *objspace)
}
}
+ (void)gc_malloc_counters_snapshot(objspace, &objspace->malloc_counters.counters);
+#if RGENGC_ESTIMATE_OLDMALLOC
+ if (objspace->profile.latest_gc_info & GPR_FLAG_MAJOR_MASK) {
+ (void)gc_malloc_counters_snapshot(objspace, &objspace->malloc_counters.oldcounters);
+ }
+#endif
+
rb_gc_event_hook(0, RUBY_INTERNAL_EVENT_GC_END_SWEEP);
gc_mode_transition(objspace, gc_mode_none);
@@ -3831,6 +4096,8 @@ gc_sweep_step(rb_objspace_t *objspace, rb_heap_t *heap)
struct heap_page *sweep_page = heap->sweeping_page;
int swept_slots = 0;
int pooled_slots = 0;
+ int sweep_budget = GC_INCREMENTAL_SWEEP_BYTES / heap->slot_size;
+ int pool_budget = GC_INCREMENTAL_SWEEP_POOL_BYTES / heap->slot_size;
if (sweep_page == NULL) return FALSE;
@@ -3876,14 +4143,14 @@ gc_sweep_step(rb_objspace_t *objspace, rb_heap_t *heap)
heap->freed_slots += ctx.freed_slots;
heap->empty_slots += ctx.empty_slots;
- if (pooled_slots < GC_INCREMENTAL_SWEEP_POOL_SLOT_COUNT) {
+ if (pooled_slots < pool_budget) {
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) {
+ if (swept_slots > sweep_budget) {
break;
}
}
@@ -3894,6 +4161,8 @@ gc_sweep_step(rb_objspace_t *objspace, rb_heap_t *heap)
} while ((sweep_page = heap->sweeping_page));
if (!heap->sweeping_page) {
+ objspace->sweeping_heap_count--;
+ GC_ASSERT(objspace->sweeping_heap_count >= 0);
gc_sweep_finish_heap(objspace, heap);
if (!has_sweeping_pages(objspace)) {
@@ -3934,7 +4203,7 @@ gc_sweep_continue(rb_objspace_t *objspace, rb_heap_t *sweep_heap)
GC_ASSERT(heap->free_pages != NULL);
}
else if (heap == sweep_heap) {
- if (objspace->empty_pages_count > 0 || objspace->heap_pages.allocatable_slots > 0) {
+ if (objspace->empty_pages_count > 0 || objspace->heap_pages.allocatable_bytes > 0) {
/* [Bug #21548]
*
* If this heap is the heap we want to sweep, but we weren't able
@@ -3996,22 +4265,13 @@ invalidate_moved_plane(rb_objspace_t *objspace, struct heap_page *page, uintptr_
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);
+ gc_move(objspace, object, forwarding_object, GET_HEAP_PAGE(object), page);
/* 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++;
+ RVALUE_AGE_SET_BITMAP(object, 0);
heap_page_add_freeobj(objspace, orig_page, object);
GC_ASSERT(RVALUE_MARKED(objspace, forwarding_object));
@@ -4019,7 +4279,7 @@ invalidate_moved_plane(rb_objspace_t *objspace, struct heap_page *page, uintptr_
GC_ASSERT(BUILTIN_TYPE(forwarding_object) != T_NONE);
}
}
- p += BASE_SLOT_SIZE;
+ p += page->slot_size;
bitset >>= 1;
} while (bitset);
}
@@ -4031,25 +4291,21 @@ invalidate_moved_page(rb_objspace_t *objspace, struct heap_page *page)
int i;
bits_t *mark_bits, *pin_bits;
bits_t bitset;
+ short slot_size = page->slot_size;
+ int total_slots = page->total_slots;
+ int bitmap_plane_count = CEILDIV(total_slots, BITS_BITLENGTH);
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++) {
+ for (i=0; i < bitmap_plane_count; 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;
+ p += BITS_BITLENGTH * slot_size;
}
}
#endif
@@ -4321,15 +4577,11 @@ init_mark_stack(mark_stack_t *stack)
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 (objspace->rgengc.parent_object_old_p) {
if (RVALUE_WB_UNPROTECTED(objspace, obj) || !RVALUE_OLD_P(objspace, obj)) {
- rgengc_remember(objspace, old_parent);
+ rgengc_remember(objspace, objspace->rgengc.parent_object);
}
}
-
- GC_ASSERT(old_parent == objspace->rgengc.parent_object);
}
static inline int
@@ -4360,8 +4612,16 @@ gc_aging(rb_objspace_t *objspace, VALUE 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);
+ int t = BUILTIN_TYPE(obj);
+ if (t == T_CLASS || t == T_MODULE || t == T_ICLASS) {
+ gc_report(3, objspace, "gc_aging: YOUNG class: %s\n", rb_obj_info(obj));
+ RVALUE_AGE_SET(obj, RVALUE_OLD_AGE);
+ RVALUE_OLD_UNCOLLECTIBLE_SET(objspace, obj);
+ }
+ else {
+ 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);
@@ -4385,32 +4645,44 @@ gc_grey(rb_objspace_t *objspace, VALUE obj)
MARK_IN_BITMAP(GET_HEAP_MARKING_BITS(obj), obj);
}
+ if (RB_FL_TEST_RAW(obj, RUBY_FL_WEAK_REFERENCE)) {
+ rb_darray_append_without_gc(&objspace->weak_references, obj);
+ }
+
push_mark_stack(&objspace->mark_stack, obj);
}
+static inline void
+gc_mark_check_t_none(rb_objspace_t *objspace, VALUE obj)
+{
+ if (RB_UNLIKELY(BUILTIN_TYPE(obj) == T_NONE)) {
+ enum {info_size = 256};
+ char obj_info_buf[info_size];
+ rb_raw_obj_info(obj_info_buf, info_size, obj);
+
+ char parent_obj_info_buf[info_size];
+ rb_raw_obj_info(parent_obj_info_buf, info_size, objspace->rgengc.parent_object);
+
+ rb_bug("try to mark T_NONE object (obj: %s, parent: %s)", obj_info_buf, parent_obj_info_buf);
+ }
+}
+
static void
gc_mark(rb_objspace_t *objspace, VALUE obj)
{
GC_ASSERT(during_gc);
+ GC_ASSERT(!objspace->flags.during_reference_updating);
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));
- }
+ 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));
}
- 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_mark_check_t_none(objspace, obj);
gc_aging(objspace, obj);
gc_grey(objspace, obj);
@@ -4495,64 +4767,34 @@ rb_gc_impl_mark_maybe(void *objspace_ptr, VALUE obj)
}
}
-void
-rb_gc_impl_mark_weak(void *objspace_ptr, VALUE *ptr)
+static int
+pin_value(st_data_t key, st_data_t value, st_data_t data)
{
- 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 references 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);
-
- rb_darray_append_without_gc(&objspace->weak_references, ptr);
+ rb_gc_impl_mark_and_pin((void *)data, (VALUE)value);
- objspace->profile.weak_references_count++;
+ return ST_CONTINUE;
}
-void
-rb_gc_impl_remove_weak(void *objspace_ptr, VALUE parent_obj, VALUE *ptr)
+static inline void
+gc_mark_set_parent_raw(rb_objspace_t *objspace, VALUE obj, bool old_p)
{
- 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;
- }
- }
+ asan_unpoison_memory_region(&objspace->rgengc.parent_object, sizeof(objspace->rgengc.parent_object), false);
+ asan_unpoison_memory_region(&objspace->rgengc.parent_object_old_p, sizeof(objspace->rgengc.parent_object_old_p), false);
+ objspace->rgengc.parent_object = obj;
+ objspace->rgengc.parent_object_old_p = old_p;
}
-static int
-pin_value(st_data_t key, st_data_t value, st_data_t data)
+static inline void
+gc_mark_set_parent(rb_objspace_t *objspace, VALUE obj)
{
- rb_gc_impl_mark_and_pin((void *)data, (VALUE)value);
+ gc_mark_set_parent_raw(objspace, obj, RVALUE_OLD_P(objspace, obj));
+}
- return ST_CONTINUE;
+static inline void
+gc_mark_set_parent_invalid(rb_objspace_t *objspace)
+{
+ asan_poison_memory_region(&objspace->rgengc.parent_object, sizeof(objspace->rgengc.parent_object));
+ asan_poison_memory_region(&objspace->rgengc.parent_object_old_p, sizeof(objspace->rgengc.parent_object_old_p));
}
static void
@@ -4563,7 +4805,7 @@ mark_roots(rb_objspace_t *objspace, const char **categoryp)
} while (0)
MARK_CHECKPOINT("objspace");
- objspace->rgengc.parent_object = Qfalse;
+ gc_mark_set_parent_raw(objspace, Qundef, false);
if (finalizer_table != NULL) {
st_foreach(finalizer_table, pin_value, (st_data_t)objspace);
@@ -4573,17 +4815,7 @@ mark_roots(rb_objspace_t *objspace, const char **categoryp)
rb_gc_save_machine_context();
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;
- }
+ gc_mark_set_parent_invalid(objspace);
}
static void
@@ -4591,6 +4823,7 @@ gc_mark_children(rb_objspace_t *objspace, VALUE obj)
{
gc_mark_set_parent(objspace, obj);
rb_gc_mark_children(objspace, obj);
+ gc_mark_set_parent_invalid(objspace);
}
/**
@@ -4876,10 +5109,22 @@ gc_check_after_marks_i(st_data_t k, st_data_t v, st_data_t ptr)
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;
+ MALLOC_COUNTERS_LOCK(objspace);
+ struct gc_malloc_bytes saved_malloc = {
+ .malloc = gc_counter_load_relaxed(&objspace->malloc_counters.counters.malloc),
+ .free = gc_counter_load_relaxed(&objspace->malloc_counters.counters.free),
+ .malloc_at_last_gc = gc_counter_load_relaxed(&objspace->malloc_counters.counters.malloc_at_last_gc),
+ .free_at_last_gc = gc_counter_load_relaxed(&objspace->malloc_counters.counters.free_at_last_gc),
+ };
#if RGENGC_ESTIMATE_OLDMALLOC
- size_t saved_oldmalloc_increase = objspace->rgengc.oldmalloc_increase;
+ struct gc_malloc_bytes saved_oldmalloc = {
+ .malloc = gc_counter_load_relaxed(&objspace->malloc_counters.oldcounters.malloc),
+ .free = gc_counter_load_relaxed(&objspace->malloc_counters.oldcounters.free),
+ .malloc_at_last_gc = gc_counter_load_relaxed(&objspace->malloc_counters.oldcounters.malloc_at_last_gc),
+ .free_at_last_gc = gc_counter_load_relaxed(&objspace->malloc_counters.oldcounters.free_at_last_gc),
+ };
#endif
+ MALLOC_COUNTERS_UNLOCK(objspace);
VALUE already_disabled = rb_objspace_gc_disable(objspace);
objspace->rgengc.allrefs_table = objspace_allrefs(objspace);
@@ -4899,10 +5144,18 @@ gc_marks_check(rb_objspace_t *objspace, st_foreach_callback_func *checker_func,
objspace->rgengc.allrefs_table = 0;
if (already_disabled == Qfalse) rb_objspace_gc_enable(objspace);
- objspace->malloc_params.increase = saved_malloc_increase;
+ MALLOC_COUNTERS_LOCK(objspace);
+ gc_counter_store_release(&objspace->malloc_counters.counters.malloc, saved_malloc.malloc);
+ gc_counter_store_release(&objspace->malloc_counters.counters.free, saved_malloc.free);
+ gc_counter_store_release(&objspace->malloc_counters.counters.malloc_at_last_gc, saved_malloc.malloc_at_last_gc);
+ gc_counter_store_release(&objspace->malloc_counters.counters.free_at_last_gc, saved_malloc.free_at_last_gc);
#if RGENGC_ESTIMATE_OLDMALLOC
- objspace->rgengc.oldmalloc_increase = saved_oldmalloc_increase;
+ gc_counter_store_release(&objspace->malloc_counters.oldcounters.malloc, saved_oldmalloc.malloc);
+ gc_counter_store_release(&objspace->malloc_counters.oldcounters.free, saved_oldmalloc.free);
+ gc_counter_store_release(&objspace->malloc_counters.oldcounters.malloc_at_last_gc, saved_oldmalloc.malloc_at_last_gc);
+ gc_counter_store_release(&objspace->malloc_counters.oldcounters.free_at_last_gc, saved_oldmalloc.free_at_last_gc);
#endif
+ MALLOC_COUNTERS_UNLOCK(objspace);
}
#endif /* RGENGC_CHECK_MODE >= 4 */
@@ -4991,6 +5244,10 @@ verify_internal_consistency_i(void *page_start, void *page_end, size_t stride,
rb_objspace_reachable_objects_from(obj, check_generation_i, (void *)data);
}
+ if (!is_marking(objspace) && rb_gc_obj_shareable_p(obj)) {
+ rb_gc_verify_shareable(obj);
+ }
+
if (is_incremental_marking(objspace)) {
if (RVALUE_BLACK_P(objspace, obj)) {
/* reachable objects from black objects should be black or grey objects */
@@ -5156,6 +5413,8 @@ gc_verify_internal_consistency_(rb_objspace_t *objspace)
/* check counters */
+ ractor_cache_flush_count(objspace, rb_gc_get_ractor_newobj_cache());
+
if (!is_lazy_sweeping(objspace) &&
!finalizing &&
!rb_gc_multi_ractor_p()) {
@@ -5268,7 +5527,7 @@ gc_remember_unprotected(rb_objspace_t *objspace, VALUE obj)
}
static inline void
-gc_marks_wb_unprotected_objects_plane(rb_objspace_t *objspace, uintptr_t p, bits_t bits)
+gc_marks_wb_unprotected_objects_plane(rb_objspace_t *objspace, uintptr_t p, bits_t bits, short slot_size)
{
if (bits) {
do {
@@ -5278,7 +5537,7 @@ gc_marks_wb_unprotected_objects_plane(rb_objspace_t *objspace, uintptr_t p, bits
GC_ASSERT(RVALUE_MARKED(objspace, (VALUE)p));
gc_mark_children(objspace, (VALUE)p);
}
- p += BASE_SLOT_SIZE;
+ p += slot_size;
bits >>= 1;
} while (bits);
}
@@ -5293,48 +5552,63 @@ gc_marks_wb_unprotected_objects(rb_objspace_t *objspace, rb_heap_t *heap)
bits_t *mark_bits = page->mark_bits;
bits_t *wbun_bits = page->wb_unprotected_bits;
uintptr_t p = page->start;
+ short slot_size = page->slot_size;
+ int total_slots = page->total_slots;
+ int bitmap_plane_count = CEILDIV(total_slots, BITS_BITLENGTH);
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++) {
+ for (j=0; j<(size_t)bitmap_plane_count; 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_marks_wb_unprotected_objects_plane(objspace, p, bits, slot_size);
+ p += BITS_BITLENGTH * slot_size;
}
}
gc_mark_stacked_objects_all(objspace);
}
-static void
-gc_update_weak_references(rb_objspace_t *objspace)
+void
+rb_gc_impl_declare_weak_references(void *objspace_ptr, VALUE obj)
+{
+ FL_SET_RAW(obj, RUBY_FL_WEAK_REFERENCE);
+}
+
+bool
+rb_gc_impl_handle_weak_references_alive_p(void *objspace_ptr, VALUE obj)
{
- size_t retained_weak_references_count = 0;
- VALUE **ptr_ptr;
- rb_darray_foreach(objspace->weak_references, i, ptr_ptr) {
- if (!*ptr_ptr) continue;
+ rb_objspace_t *objspace = objspace_ptr;
- VALUE obj = **ptr_ptr;
+ bool marked = RVALUE_MARKED(objspace, obj);
- if (RB_SPECIAL_CONST_P(obj)) continue;
+ if (marked) {
+ rgengc_check_relation(objspace, obj);
+ }
- if (!RVALUE_MARKED(objspace, obj)) {
- **ptr_ptr = Qundef;
- }
- else {
- retained_weak_references_count++;
- }
+ return marked;
+}
+
+static void
+gc_update_weak_references(rb_objspace_t *objspace)
+{
+ VALUE *obj_ptr;
+ rb_darray_foreach(objspace->weak_references, i, obj_ptr) {
+ gc_mark_set_parent(objspace, *obj_ptr);
+ rb_gc_handle_weak_references(*obj_ptr);
+ gc_mark_set_parent_invalid(objspace);
}
- objspace->profile.retained_weak_references_count = retained_weak_references_count;
+ size_t capa = rb_darray_capa(objspace->weak_references);
+ size_t size = rb_darray_size(objspace->weak_references);
+
+ objspace->profile.weak_references_count = size;
rb_darray_clear(objspace->weak_references);
- rb_darray_resize_capa_without_gc(&objspace->weak_references, retained_weak_references_count);
+
+ /* If the darray has capacity for more than four times the amount used, we
+ * shrink it down to half of that capacity. */
+ if (capa > size * 4) {
+ rb_darray_resize_capa_without_gc(&objspace->weak_references, size * 2);
+ }
}
static void
@@ -5393,22 +5667,27 @@ gc_marks_finish(rb_objspace_t *objspace)
/* 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;
+ total_init_slots += (gc_params.heap_init_bytes / heaps[i].slot_size) * r_mul;
}
if (max_free_slots < total_init_slots) {
max_free_slots = total_init_slots;
}
+ /* Approximate freeable pages using the average slots-per-pages across all heaps */
if (sweep_slots > max_free_slots) {
- heap_pages_freeable_pages = (sweep_slots - max_free_slots) / HEAP_PAGE_OBJ_LIMIT;
+ size_t excess_slots = sweep_slots - max_free_slots;
+ size_t total_heap_pages = heap_eden_total_pages(objspace);
+ heap_pages_freeable_pages = total_heap_pages > 0
+ ? excess_slots * total_heap_pages / total_slots
+ : 0;
}
else {
heap_pages_freeable_pages = 0;
}
- if (objspace->heap_pages.allocatable_slots == 0 && sweep_slots < min_free_slots) {
- if (!full_marking) {
+ if (objspace->heap_pages.allocatable_bytes == 0 && sweep_slots < min_free_slots) {
+ if (!full_marking && sweep_slots < min_free_slots * 7 / 8) {
if (objspace->profile.count - objspace->rgengc.last_major_gc < RVALUE_OLD_AGE) {
full_marking = TRUE;
}
@@ -5419,7 +5698,7 @@ gc_marks_finish(rb_objspace_t *objspace)
}
if (full_marking) {
- heap_allocatable_slots_expand(objspace, NULL, sweep_slots, total_slots);
+ heap_allocatable_bytes_expand(objspace, NULL, sweep_slots, total_slots, heaps[0].slot_size);
}
}
@@ -5442,8 +5721,8 @@ gc_marks_finish(rb_objspace_t *objspace)
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,
+ "sweep %"PRIdSIZE" slots, allocatable %"PRIdSIZE" bytes, next GC: %s)\n",
+ objspace->marked_slots, objspace->rgengc.old_objects, objspace_available_slots(objspace), sweep_slots, objspace->heap_pages.allocatable_bytes,
gc_needs_major_flags ? "major" : "minor");
}
@@ -5468,10 +5747,9 @@ gc_compact_destination_pool(rb_objspace_t *objspace, rb_heap_t *src_pool, VALUE
return src_pool;
}
- size_t idx = 0;
- if (rb_gc_impl_size_allocatable_p(obj_size)) {
- idx = heap_idx_for_size(obj_size);
- }
+ GC_ASSERT(rb_gc_impl_size_allocatable_p(obj_size));
+
+ size_t idx = heap_idx_for_size(obj_size);
return &heaps[idx];
}
@@ -5483,25 +5761,10 @@ gc_compact_move(rb_objspace_t *objspace, rb_heap_t *heap, VALUE src)
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,
@@ -5527,14 +5790,6 @@ gc_compact_move(rb_objspace_t *objspace, rb_heap_t *heap, VALUE src)
}
}
- 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;
}
@@ -5542,12 +5797,10 @@ 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);
+ GC_ASSERT(vp % sizeof(VALUE) == 0);
if (bitset & 1) {
objspace->rcompactor.considered_count_table[BUILTIN_TYPE(vp)]++;
@@ -5560,7 +5813,7 @@ gc_compact_plane(rb_objspace_t *objspace, rb_heap_t *heap, uintptr_t p, bits_t b
}
}
p += slot_size;
- bitset >>= slot_bits;
+ bitset >>= 1;
} while (bitset);
return true;
@@ -5575,26 +5828,21 @@ gc_compact_page(rb_objspace_t *objspace, rb_heap_t *heap, struct heap_page *page
bits_t *mark_bits, *pin_bits;
bits_t bitset;
uintptr_t p = page->start;
+ short slot_size = page->slot_size;
+ int total_slots = page->total_slots;
+ int bitmap_plane_count = CEILDIV(total_slots, BITS_BITLENGTH);
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++) {
+ for (int j = 0; j < bitmap_plane_count; j++) {
+ // objects that can be moved are marked and not pinned
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;
+ p += BITS_BITLENGTH * slot_size;
}
return true;
@@ -5771,7 +6019,6 @@ gc_marks_start(rb_objspace_t *objspace, int full_mark)
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;
@@ -5792,7 +6039,6 @@ gc_marks(rb_objspace_t *objspace, int full_mark)
#endif
gc_marking_exit(objspace);
- gc_prof_mark_timer_stop(objspace);
return marking_finished;
}
@@ -5881,7 +6127,7 @@ rgengc_remember(rb_objspace_t *objspace, VALUE obj)
#endif
static inline void
-rgengc_rememberset_mark_plane(rb_objspace_t *objspace, uintptr_t p, bits_t bitset)
+rgengc_rememberset_mark_plane(rb_objspace_t *objspace, uintptr_t p, bits_t bitset, short slot_size)
{
if (bitset) {
do {
@@ -5892,8 +6138,12 @@ rgengc_rememberset_mark_plane(rb_objspace_t *objspace, uintptr_t p, bits_t bitse
GC_ASSERT(RVALUE_OLD_P(objspace, obj) || RVALUE_WB_UNPROTECTED(objspace, obj));
gc_mark_children(objspace, obj);
+
+ if (RB_FL_TEST_RAW(obj, RUBY_FL_WEAK_REFERENCE)) {
+ rb_darray_append_without_gc(&objspace->weak_references, obj);
+ }
}
- p += BASE_SLOT_SIZE;
+ p += slot_size;
bitset >>= 1;
} while (bitset);
}
@@ -5912,6 +6162,9 @@ rgengc_rememberset_mark(rb_objspace_t *objspace, rb_heap_t *heap)
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;
+ short slot_size = page->slot_size;
+ int total_slots = page->total_slots;
+ int bitmap_plane_count = CEILDIV(total_slots, BITS_BITLENGTH);
bits_t bitset, bits[HEAP_PAGE_BITMAP_LIMIT];
bits_t *remembered_bits = page->remembered_bits;
bits_t *uncollectible_bits = page->uncollectible_bits;
@@ -5921,21 +6174,16 @@ rgengc_rememberset_mark(rb_objspace_t *objspace, rb_heap_t *heap)
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++) {
+ for (j=0; j < (size_t)bitmap_plane_count; 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++) {
+ for (j=0; j < (size_t)bitmap_plane_count; j++) {
bitset = bits[j];
- rgengc_rememberset_mark_plane(objspace, p, bitset);
- p += BITS_BITLENGTH * BASE_SLOT_SIZE;
+ rgengc_rememberset_mark_plane(objspace, p, bitset, slot_size);
+ p += BITS_BITLENGTH * slot_size;
}
}
#if PROFILE_REMEMBERSET_MARK
@@ -6000,9 +6248,11 @@ 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);
+ if (gc_mark_set(objspace, obj) != FALSE) {
+ gc_aging(objspace, obj);
+ gc_grey(objspace, obj);
+ }
+ gc_mark_set_parent_invalid(objspace);
}
NOINLINE(static void gc_writebarrier_incremental(VALUE a, VALUE b, rb_objspace_t *objspace));
@@ -6034,12 +6284,15 @@ 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)) return;
+#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);
+#else
+ RBIMPL_ASSERT_OR_ASSUME(!SPECIAL_CONST_P(a));
+ RBIMPL_ASSERT_OR_ASSUME(!SPECIAL_CONST_P(b));
+#endif
+ GC_ASSERT(!during_gc);
GC_ASSERT(RB_BUILTIN_TYPE(a) != T_NONE);
GC_ASSERT(RB_BUILTIN_TYPE(a) != T_MOVED);
GC_ASSERT(RB_BUILTIN_TYPE(a) != T_ZOMBIE);
@@ -6156,7 +6409,7 @@ rb_gc_impl_writebarrier_remember(void *objspace_ptr, VALUE obj)
struct rb_gc_object_metadata_names {
// Must be ID only
ID ID_wb_protected, ID_age, ID_old, ID_uncollectible, ID_marking,
- ID_marked, ID_pinned, ID_object_id, ID_shareable;
+ ID_marked, ID_pinned, ID_remembered, ID_object_id, ID_shareable;
};
#define RB_GC_OBJECT_METADATA_ENTRY_COUNT (sizeof(struct rb_gc_object_metadata_names) / sizeof(ID))
@@ -6178,6 +6431,7 @@ rb_gc_impl_object_metadata(void *objspace_ptr, VALUE obj)
I(marking);
I(marked);
I(pinned);
+ I(remembered);
I(object_id);
I(shareable);
#undef I
@@ -6197,6 +6451,7 @@ rb_gc_impl_object_metadata(void *objspace_ptr, VALUE obj)
if (RVALUE_MARKING(objspace, obj)) SET_ENTRY(marking, Qtrue);
if (RVALUE_MARKED(objspace, obj)) SET_ENTRY(marked, Qtrue);
if (RVALUE_PINNED(objspace, obj)) SET_ENTRY(pinned, Qtrue);
+ if (RVALUE_REMEMBERED(objspace, obj)) SET_ENTRY(remembered, Qtrue);
if (rb_obj_id_p(obj)) SET_ENTRY(object_id, rb_obj_id(obj));
if (FL_TEST(obj, FL_SHAREABLE)) SET_ENTRY(shareable, Qtrue);
@@ -6232,7 +6487,7 @@ 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;
+ objspace->heap_pages.allocatable_bytes = HEAP_PAGE_SIZE;
heap_page_allocate_and_initialize(objspace, heap);
}
}
@@ -6258,11 +6513,14 @@ 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);
+ int64_t inc = gc_malloc_counters_increase(objspace, &objspace->malloc_counters.counters);
size_t old_limit = malloc_limit;
- if (inc > malloc_limit) {
- malloc_limit = (size_t)(inc * gc_params.malloc_limit_growth_factor);
+ /* A net-negative `inc` (more freed than malloc'd since last GC) is
+ * treated the same as "allocated less than malloc_limit".
+ * This matches what we were doing pre-monotonic counters, but is it right? */
+ if (inc > 0 && (size_t)inc > malloc_limit) {
+ malloc_limit = (size_t)((size_t)inc * gc_params.malloc_limit_growth_factor);
if (malloc_limit > gc_params.malloc_limit_max) {
malloc_limit = gc_params.malloc_limit_max;
}
@@ -6289,7 +6547,11 @@ gc_reset_malloc_info(rb_objspace_t *objspace, bool full_mark)
/* reset oldmalloc info */
#if RGENGC_ESTIMATE_OLDMALLOC
if (!full_mark) {
- if (objspace->rgengc.oldmalloc_increase > objspace->rgengc.oldmalloc_increase_limit) {
+ /* Don't snapshot on minor GC: oldmalloc_increase is meant to
+ * accumulate across minor GCs and only reset at major GC. */
+ int64_t oldmalloc_increase = gc_malloc_counters_increase(objspace, &objspace->malloc_counters.oldcounters);
+ if (oldmalloc_increase > 0 &&
+ (uint64_t)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);
@@ -6299,17 +6561,14 @@ gc_reset_malloc_info(rb_objspace_t *objspace, bool full_mark)
}
}
- if (0) fprintf(stderr, "%"PRIdSIZE"\t%d\t%"PRIuSIZE"\t%"PRIuSIZE"\t%"PRIdSIZE"\n",
+ if (0) fprintf(stderr, "%"PRIdSIZE"\t%d\t%"PRId64"\t%"PRIuSIZE"\t%"PRIdSIZE"\n",
rb_gc_count(),
gc_needs_major_flags,
- objspace->rgengc.oldmalloc_increase,
+ 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));
@@ -6353,6 +6612,8 @@ gc_start(rb_objspace_t *objspace, unsigned int reason)
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 */
+ rb_gc_initialize_vm_context(&objspace->vm_context);
+
GC_ASSERT(gc_mode(objspace) == gc_mode_none, "gc_mode is %s\n", gc_mode_name(gc_mode(objspace)));
GC_ASSERT(!is_lazy_sweeping(objspace));
GC_ASSERT(!is_incremental_marking(objspace));
@@ -6445,8 +6706,8 @@ gc_start(rb_objspace_t *objspace, unsigned int reason)
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.heap_total_slots_at_gc_start = objspace_available_slots(objspace);
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);
@@ -6628,8 +6889,6 @@ gc_enter(rb_objspace_t *objspace, enum gc_enter_event event, unsigned int *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
@@ -6675,9 +6934,13 @@ gc_marking_enter(rb_objspace_t *objspace)
{
GC_ASSERT(during_gc != 0);
+ gc_prof_mark_timer_start(objspace);
+
if (MEASURE_GC) {
gc_clock_start(&objspace->profile.marking_start_time);
}
+
+ rb_gc_initialize_vm_context(&objspace->vm_context);
}
static void
@@ -6688,6 +6951,8 @@ gc_marking_exit(rb_objspace_t *objspace)
if (MEASURE_GC) {
objspace->profile.marking_time_ns += gc_clock_end(&objspace->profile.marking_start_time);
}
+
+ gc_prof_mark_timer_stop(objspace);
}
static void
@@ -6802,7 +7067,7 @@ 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;
+ size_t orig_allocatable_bytes = objspace->heap_pages.allocatable_bytes;
rb_gc_impl_each_objects(objspace, gc_set_candidate_object_i, objspace_ptr);
@@ -6812,16 +7077,16 @@ rb_gc_impl_prepare_heap(void *objspace_ptr)
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;
+ objspace->heap_pages.allocatable_bytes = 0;
heap_pages_freeable_pages = objspace->empty_pages_count;
heap_pages_free_unused_pages(objspace_ptr);
GC_ASSERT(heap_pages_freeable_pages == 0);
GC_ASSERT(objspace->empty_pages_count == 0);
- objspace->heap_pages.allocatable_slots = orig_allocatable_slots;
+ objspace->heap_pages.allocatable_bytes = orig_allocatable_bytes;
size_t total_slots = objspace_available_slots(objspace);
if (orig_total_slots > total_slots) {
- objspace->heap_pages.allocatable_slots += orig_total_slots - total_slots;
+ objspace->heap_pages.allocatable_bytes += (orig_total_slots - total_slots) * heaps[0].slot_size;
}
#if defined(HAVE_MALLOC_TRIM) && !defined(RUBY_ALTERNATIVE_MALLOC_HEADER)
@@ -6840,12 +7105,6 @@ gc_is_moveable_obj(rb_objspace_t *objspace, VALUE obj)
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:
@@ -6890,8 +7149,11 @@ gc_is_moveable_obj(rb_objspace_t *objspace, VALUE obj)
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)
+gc_move(rb_objspace_t *objspace, VALUE src, VALUE dest, struct heap_page *src_page, struct heap_page *dest_page)
{
+ size_t src_slot_size = src_page->slot_size;
+ size_t slot_size = dest_page->slot_size;
+
int marked;
int wb_unprotected;
int uncollectible;
@@ -6920,6 +7182,10 @@ gc_move(rb_objspace_t *objspace, VALUE src, VALUE dest, size_t src_slot_size, si
/* Move the object */
memcpy((void *)dest, (void *)src, MIN(src_slot_size, slot_size));
+ if (src_slot_size != slot_size && RB_TYPE_P(src, T_OBJECT)) {
+ rb_gc_obj_changed_pool(dest, dest_page->heap - heaps);
+ }
+
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);
@@ -6928,7 +7194,7 @@ gc_move(rb_objspace_t *objspace, VALUE src, VALUE dest, size_t src_slot_size, si
}
memset((void *)src, 0, src_slot_size);
- RVALUE_AGE_RESET(src);
+ RVALUE_AGE_SET_BITMAP(src, 0);
/* Set bits for object in new location */
if (remembered) {
@@ -7035,6 +7301,12 @@ gc_sort_heap_by_compare_func(rb_objspace_t *objspace, gc_compact_compare_func co
}
#endif
+void
+rb_gc_impl_register_pinning_obj(void *objspace_ptr, VALUE obj)
+{
+ /* no-op */
+}
+
bool
rb_gc_impl_object_moved_p(void *objspace_ptr, VALUE obj)
{
@@ -7268,7 +7540,7 @@ gc_info_decode(rb_objspace_t *objspace, const VALUE hash_or_key, const unsigned
#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;
+ static VALUE sym_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;
@@ -7310,7 +7582,6 @@ gc_info_decode(rb_objspace_t *objspace, const VALUE hash_or_key, const unsigned
S(sweeping);
S(weak_references_count);
- S(retained_weak_references_count);
#undef S
}
@@ -7363,7 +7634,6 @@ gc_info_decode(rb_objspace_t *objspace, const VALUE hash_or_key, const unsigned
}
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)) {
@@ -7390,7 +7660,7 @@ enum gc_stat_sym {
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_allocatable_bytes,
gc_stat_sym_heap_available_slots,
gc_stat_sym_heap_live_slots,
gc_stat_sym_heap_free_slots,
@@ -7401,6 +7671,8 @@ enum gc_stat_sym {
gc_stat_sym_total_freed_pages,
gc_stat_sym_total_allocated_objects,
gc_stat_sym_total_freed_objects,
+ gc_stat_sym_total_malloc_bytes,
+ gc_stat_sym_total_free_bytes,
gc_stat_sym_malloc_increase_bytes,
gc_stat_sym_malloc_increase_bytes_limit,
gc_stat_sym_minor_gc_count,
@@ -7416,7 +7688,6 @@ enum gc_stat_sym {
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,
@@ -7441,7 +7712,7 @@ setup_gc_stat_symbols(void)
S(sweeping_time),
S(heap_allocated_pages);
S(heap_empty_pages);
- S(heap_allocatable_slots);
+ S(heap_allocatable_bytes);
S(heap_available_slots);
S(heap_live_slots);
S(heap_free_slots);
@@ -7452,6 +7723,8 @@ setup_gc_stat_symbols(void)
S(total_freed_pages);
S(total_allocated_objects);
S(total_freed_objects);
+ S(total_malloc_bytes);
+ S(total_free_bytes);
S(malloc_increase_bytes);
S(malloc_increase_bytes_limit);
S(minor_gc_count);
@@ -7467,7 +7740,6 @@ setup_gc_stat_symbols(void)
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);
@@ -7486,6 +7758,8 @@ ns_to_ms(uint64_t ns)
return ns / (1000 * 1000);
}
+static void malloc_increase_local_flush(rb_objspace_t *objspace);
+
VALUE
rb_gc_impl_stat(void *objspace_ptr, VALUE hash_or_sym)
{
@@ -7494,6 +7768,9 @@ rb_gc_impl_stat(void *objspace_ptr, VALUE hash_or_sym)
setup_gc_stat_symbols();
+ ractor_cache_flush_count(objspace, rb_gc_get_ractor_newobj_cache());
+ malloc_increase_local_flush(objspace);
+
if (RB_TYPE_P(hash_or_sym, T_HASH)) {
hash = hash_or_sym;
}
@@ -7509,27 +7786,32 @@ rb_gc_impl_stat(void *objspace_ptr, VALUE hash_or_sym)
return SIZET2NUM(attr); \
else if (hash != Qnil) \
rb_hash_aset(hash, gc_stat_symbols[gc_stat_sym_##name], SIZET2NUM(attr));
+#define SET64(name, attr) \
+ if (key == gc_stat_symbols[gc_stat_sym_##name]) \
+ return ULL2NUM(attr); \
+ else if (hash != Qnil) \
+ rb_hash_aset(hash, gc_stat_symbols[gc_stat_sym_##name], ULL2NUM(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 */
+ {
+ uint64_t total_malloc = (uint64_t)gc_counter_load_relaxed(&objspace->malloc_counters.counters.malloc);
+ uint64_t total_free = (uint64_t)gc_counter_load_relaxed(&objspace->malloc_counters.counters.free);
+ SET64(total_malloc_bytes, total_malloc);
+ SET64(total_free_bytes, total_free);
+ }
+
+ /* implementation dependent counters (small / fixnum-safe) */
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_allocatable_bytes, objspace->heap_pages.allocatable_bytes);
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, gc_malloc_counters_increase_unsigned(objspace, &objspace->malloc_counters.counters));
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);
@@ -7541,10 +7823,19 @@ rb_gc_impl_stat(void *objspace_ptr, VALUE hash_or_sym)
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, gc_malloc_counters_increase_unsigned(objspace, &objspace->malloc_counters.oldcounters));
SET(oldmalloc_increase_bytes_limit, objspace->rgengc.oldmalloc_increase_limit);
#endif
+ ractor_cache_flush_count(objspace, rb_gc_get_ractor_newobj_cache());
+ SET(total_allocated_objects, total_allocated_objects(objspace));
+ SET(total_freed_objects, total_freed_objects(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, total_final_slots_count(objspace));
+ SET(heap_marked_slots, objspace->marked_slots);
+
#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);
@@ -7554,6 +7845,7 @@ rb_gc_impl_stat(void *objspace_ptr, VALUE hash_or_sym)
SET(total_remembered_shady_object_count, objspace->profile.total_remembered_shady_object_count);
#endif /* RGENGC_PROFILE */
#undef SET
+#undef SET64
if (!NIL_P(key)) {
// Matched key should return above
@@ -7576,11 +7868,15 @@ rb_gc_impl_stat(void *objspace_ptr, VALUE hash_or_sym)
enum gc_stat_heap_sym {
gc_stat_heap_sym_slot_size,
+ gc_stat_heap_sym_heap_live_slots,
+ gc_stat_heap_sym_heap_free_slots,
+ gc_stat_heap_sym_heap_final_slots,
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_heap_allocatable_slots,
gc_stat_heap_sym_total_allocated_objects,
gc_stat_heap_sym_total_freed_objects,
gc_stat_heap_sym_last
@@ -7594,8 +7890,12 @@ 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_live_slots);
+ S(heap_free_slots);
+ S(heap_final_slots);
S(heap_eden_pages);
S(heap_eden_slots);
+ S(heap_allocatable_slots);
S(total_allocated_pages);
S(force_major_gc_count);
S(force_incremental_marking_finish_count);
@@ -7606,7 +7906,7 @@ setup_gc_stat_heap_symbols(void)
}
static VALUE
-stat_one_heap(rb_heap_t *heap, VALUE hash, VALUE key)
+stat_one_heap(rb_objspace_t *objspace, rb_heap_t *heap, VALUE hash, VALUE key)
{
#define SET(name, attr) \
if (key == gc_stat_heap_symbols[gc_stat_heap_sym_##name]) \
@@ -7615,8 +7915,12 @@ stat_one_heap(rb_heap_t *heap, VALUE hash, VALUE key)
rb_hash_aset(hash, gc_stat_heap_symbols[gc_stat_heap_sym_##name], SIZET2NUM(attr));
SET(slot_size, heap->slot_size);
+ SET(heap_live_slots, heap->total_allocated_objects - heap->total_freed_objects - heap->final_slots_count);
+ SET(heap_free_slots, heap->total_slots - (heap->total_allocated_objects - heap->total_freed_objects));
+ SET(heap_final_slots, heap->final_slots_count);
SET(heap_eden_pages, heap->total_pages);
SET(heap_eden_slots, heap->total_slots);
+ SET(heap_allocatable_slots, objspace->heap_pages.allocatable_bytes / heap->slot_size);
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);
@@ -7637,6 +7941,8 @@ rb_gc_impl_stat_heap(void *objspace_ptr, VALUE heap_name, VALUE hash_or_sym)
{
rb_objspace_t *objspace = objspace_ptr;
+ ractor_cache_flush_count(objspace, rb_gc_get_ractor_newobj_cache());
+
setup_gc_stat_heap_symbols();
if (NIL_P(heap_name)) {
@@ -7651,7 +7957,7 @@ rb_gc_impl_stat_heap(void *objspace_ptr, VALUE heap_name, VALUE hash_or_sym)
rb_hash_aset(hash_or_sym, INT2FIX(i), hash);
}
- stat_one_heap(&heaps[i], hash, Qnil);
+ stat_one_heap(objspace, &heaps[i], hash, Qnil);
}
}
else if (FIXNUM_P(heap_name)) {
@@ -7662,10 +7968,10 @@ rb_gc_impl_stat_heap(void *objspace_ptr, VALUE heap_name, VALUE hash_or_sym)
}
if (SYMBOL_P(hash_or_sym)) {
- return stat_one_heap(&heaps[heap_idx], Qnil, hash_or_sym);
+ return stat_one_heap(objspace, &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);
+ return stat_one_heap(objspace, &heaps[heap_idx], hash_or_sym, Qnil);
}
else {
rb_bug("non-hash or symbol given");
@@ -7847,8 +8153,8 @@ get_envparam_double(const char *name, double *default_value, double lower_bound,
* * 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_GROWTH_MAX_BYTES (was RUBY_GC_HEAP_GROWTH_MAX_SLOTS)
+ * - Allocation rate is limited to this number of bytes.
* * 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)).
@@ -7867,7 +8173,7 @@ get_envparam_double(const char *name, double *default_value, double lower_bound,
*
* * 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_HEAP_MIN_SLOTS -> RUBY_GC_HEAP_INIT_SLOTS (from 2.1) -> RUBY_GC_HEAP_INIT_BYTES
*
* * RUBY_GC_MALLOC_LIMIT
* * RUBY_GC_MALLOC_LIMIT_MAX (new from 2.1)
@@ -7887,15 +8193,10 @@ rb_gc_impl_set_params(void *objspace_ptr)
/* 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_size("RUBY_GC_HEAP_INIT_BYTES", &gc_params.heap_init_bytes, 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_size ("RUBY_GC_HEAP_GROWTH_MAX_BYTES", &gc_params.growth_max_bytes, 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,
@@ -7969,8 +8270,53 @@ objspace_malloc_gc_stress(rb_objspace_t *objspace)
}
}
+static void
+malloc_increase_commit(rb_objspace_t *objspace, size_t new_size, size_t old_size)
+{
+ if (new_size > old_size) {
+ size_t delta = new_size - old_size;
+ MALLOC_COUNTERS_LOCK(objspace);
+ gc_counter_add(&objspace->malloc_counters.counters.malloc, delta);
+#if RGENGC_ESTIMATE_OLDMALLOC
+ gc_counter_add(&objspace->malloc_counters.oldcounters.malloc, delta);
+#endif
+ MALLOC_COUNTERS_UNLOCK(objspace);
+ }
+ else if (old_size > new_size) {
+ size_t delta = old_size - new_size;
+ MALLOC_COUNTERS_LOCK(objspace);
+ gc_counter_add(&objspace->malloc_counters.counters.free, delta);
+#if RGENGC_ESTIMATE_OLDMALLOC
+ gc_counter_add(&objspace->malloc_counters.oldcounters.free, delta);
+#endif
+ MALLOC_COUNTERS_UNLOCK(objspace);
+ }
+}
+
+#if USE_MALLOC_INCREASE_LOCAL
+static void
+malloc_increase_local_flush(rb_objspace_t *objspace)
+{
+ int delta = malloc_increase_local;
+ if (delta == 0) return;
+
+ malloc_increase_local = 0;
+ if (delta > 0) {
+ malloc_increase_commit(objspace, (size_t)delta, 0);
+ }
+ else {
+ malloc_increase_commit(objspace, 0, (size_t)(-delta));
+ }
+}
+#else
+static void
+malloc_increase_local_flush(rb_objspace_t *objspace)
+{
+}
+#endif
+
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)
+objspace_malloc_increase_report(rb_objspace_t *objspace, void *mem, size_t new_size, size_t old_size, enum memop_type type, bool gc_allowed)
{
if (0) fprintf(stderr, "increase - ptr: %p, type: %s, new_size: %"PRIdSIZE", old_size: %"PRIdSIZE"\n",
mem,
@@ -7982,22 +8328,27 @@ objspace_malloc_increase_report(rb_objspace_t *objspace, void *mem, size_t new_s
}
static bool
-objspace_malloc_increase_body(rb_objspace_t *objspace, void *mem, size_t new_size, size_t old_size, enum memop_type type)
+objspace_malloc_increase_body(rb_objspace_t *objspace, void *mem, size_t new_size, size_t old_size, enum memop_type type, bool gc_allowed)
{
- 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
+#if USE_MALLOC_INCREASE_LOCAL
+ if (new_size < GC_MALLOC_INCREASE_LOCAL_THRESHOLD &&
+ old_size < GC_MALLOC_INCREASE_LOCAL_THRESHOLD) {
+ malloc_increase_local += (int)new_size - (int)old_size;
+
+ if (malloc_increase_local >= GC_MALLOC_INCREASE_LOCAL_THRESHOLD ||
+ malloc_increase_local <= -GC_MALLOC_INCREASE_LOCAL_THRESHOLD) {
+ malloc_increase_local_flush(objspace);
+ }
}
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
+ malloc_increase_local_flush(objspace);
+ malloc_increase_commit(objspace, new_size, old_size);
}
+#else
+ malloc_increase_commit(objspace, new_size, old_size);
+#endif
- if (type == MEMOP_TYPE_MALLOC) {
+ if (type == MEMOP_TYPE_MALLOC && gc_allowed) {
retry:
if (malloc_increase > malloc_limit && ruby_native_thread_p() && !dont_gc_val()) {
if (ruby_thread_has_gvl_p() && is_lazy_sweeping(objspace)) {
@@ -8079,10 +8430,10 @@ malloc_during_gc_p(rb_objspace_t *objspace)
}
static inline void *
-objspace_malloc_fixup(rb_objspace_t *objspace, void *mem, size_t size)
+objspace_malloc_fixup(rb_objspace_t *objspace, void *mem, size_t size, bool gc_allowed)
{
size = objspace_malloc_size(objspace, mem, size);
- objspace_malloc_increase(objspace, mem, size, 0, MEMOP_TYPE_MALLOC) {}
+ objspace_malloc_increase(objspace, mem, size, 0, MEMOP_TYPE_MALLOC, gc_allowed) {}
#if CALC_EXACT_MALLOC_SIZE
{
@@ -8114,10 +8465,10 @@ objspace_malloc_fixup(rb_objspace_t *objspace, void *mem, size_t size)
GPR_FLAG_MALLOC; \
objspace_malloc_gc_stress(objspace); \
\
- if (RB_LIKELY((expr))) { \
+ if (RB_LIKELY((expr))) { \
/* Success on 1st try */ \
} \
- else if (!garbage_collect_with_gvl(objspace, gpr)) { \
+ else if (gc_allowed && !garbage_collect_with_gvl(objspace, gpr)) { \
/* @shyouhei thinks this doesn't happen */ \
GC_MEMERROR("TRY_WITH_GC: could not GC"); \
} \
@@ -8155,12 +8506,21 @@ rb_gc_impl_free(void *objspace_ptr, void *ptr, size_t old_size)
}
#if CALC_EXACT_MALLOC_SIZE
struct malloc_obj_info *info = (struct malloc_obj_info *)ptr - 1;
+#if VERIFY_FREE_SIZE
+ if (!info->size) {
+ rb_bug("buffer %p has no recorded size. Was it allocated with ruby_mimalloc? If so it should be freed with ruby_mimfree", ptr);
+ }
+
+ if (old_size && (old_size + sizeof(struct malloc_obj_info)) != info->size) {
+ rb_bug("buffer %p freed with old_size=%zu, but was allocated with size=%zu", ptr, old_size, info->size - sizeof(struct malloc_obj_info));
+ }
+#endif
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) {
+ objspace_malloc_increase(objspace, ptr, 0, old_size, MEMOP_TYPE_FREE, true) {
free(ptr);
ptr = NULL;
RB_DEBUG_COUNTER_INC(heap_xfree);
@@ -8168,7 +8528,7 @@ rb_gc_impl_free(void *objspace_ptr, void *ptr, size_t old_size)
}
void *
-rb_gc_impl_malloc(void *objspace_ptr, size_t size)
+rb_gc_impl_malloc(void *objspace_ptr, size_t size, bool gc_allowed)
{
rb_objspace_t *objspace = objspace_ptr;
check_malloc_not_in_gc(objspace, "malloc");
@@ -8179,11 +8539,11 @@ rb_gc_impl_malloc(void *objspace_ptr, size_t size)
TRY_WITH_GC(size, mem = malloc(size));
RB_DEBUG_COUNTER_INC(heap_xmalloc);
if (!mem) return mem;
- return objspace_malloc_fixup(objspace, mem, size);
+ return objspace_malloc_fixup(objspace, mem, size, gc_allowed);
}
void *
-rb_gc_impl_calloc(void *objspace_ptr, size_t size)
+rb_gc_impl_calloc(void *objspace_ptr, size_t size, bool gc_allowed)
{
rb_objspace_t *objspace = objspace_ptr;
@@ -8199,11 +8559,11 @@ rb_gc_impl_calloc(void *objspace_ptr, size_t size)
size = objspace_malloc_prepare(objspace, size);
TRY_WITH_GC(size, mem = calloc1(size));
if (!mem) return mem;
- return objspace_malloc_fixup(objspace, mem, size);
+ return objspace_malloc_fixup(objspace, mem, size, gc_allowed);
}
void *
-rb_gc_impl_realloc(void *objspace_ptr, void *ptr, size_t new_size, size_t old_size)
+rb_gc_impl_realloc(void *objspace_ptr, void *ptr, size_t new_size, size_t old_size, bool gc_allowed)
{
rb_objspace_t *objspace = objspace_ptr;
@@ -8211,7 +8571,7 @@ rb_gc_impl_realloc(void *objspace_ptr, void *ptr, size_t new_size, size_t old_si
void *mem;
- if (!ptr) return rb_gc_impl_malloc(objspace, new_size);
+ if (!ptr) return rb_gc_impl_malloc(objspace, new_size, gc_allowed);
/*
* The behavior of realloc(ptr, 0) is implementation defined.
@@ -8219,7 +8579,7 @@ rb_gc_impl_realloc(void *objspace_ptr, void *ptr, size_t new_size, size_t old_si
* 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) {
+ if ((mem = rb_gc_impl_malloc(objspace, 0, gc_allowed)) != 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.
@@ -8261,6 +8621,11 @@ rb_gc_impl_realloc(void *objspace_ptr, void *ptr, size_t new_size, size_t old_si
struct malloc_obj_info *info = (struct malloc_obj_info *)ptr - 1;
new_size += sizeof(struct malloc_obj_info);
ptr = info;
+#if VERIFY_FREE_SIZE
+ if (old_size && (old_size + sizeof(struct malloc_obj_info)) != info->size) {
+ rb_bug("buffer %p realloced with old_size=%zu, but was allocated with size=%zu", ptr, old_size, info->size - sizeof(struct malloc_obj_info));
+ }
+#endif
old_size = info->size;
}
#endif
@@ -8278,7 +8643,7 @@ rb_gc_impl_realloc(void *objspace_ptr, void *ptr, size_t new_size, size_t old_si
}
#endif
- objspace_malloc_increase(objspace, mem, new_size, old_size, MEMOP_TYPE_REALLOC);
+ objspace_malloc_increase(objspace, mem, new_size, old_size, MEMOP_TYPE_REALLOC, gc_allowed);
RB_DEBUG_COUNTER_INC(heap_xrealloc);
return mem;
@@ -8290,10 +8655,10 @@ 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);
+ objspace_malloc_increase(objspace, 0, diff, 0, MEMOP_TYPE_REALLOC, true);
}
else if (diff < 0) {
- objspace_malloc_increase(objspace, 0, 0, -diff, MEMOP_TYPE_REALLOC);
+ objspace_malloc_increase(objspace, 0, 0, -diff, MEMOP_TYPE_REALLOC, true);
}
}
@@ -8532,18 +8897,29 @@ 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;
+
+ /* Sum across all size pools since each has a different slot size. */
+ size_t total = 0;
+ size_t use_size = 0;
+ size_t total_size = 0;
+ for (int i = 0; i < HEAP_COUNT; i++) {
+ rb_heap_t *heap = &heaps[i];
+ size_t heap_live = heap->total_allocated_objects - heap->total_freed_objects - heap->final_slots_count;
+ total += heap->total_slots;
+ use_size += heap_live * heap->slot_size;
+ total_size += heap->total_slots * heap->slot_size;
+ }
#if GC_PROFILE_MORE_DETAIL
+ size_t live = objspace->profile.total_allocated_objects_at_gc_start - total_freed_objects(objspace);
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;
+ record->heap_use_size = use_size;
+ record->heap_total_size = total_size;
}
}
@@ -8910,6 +9286,12 @@ gc_profile_disable(VALUE _)
return Qnil;
}
+void
+rb_gc_verify_internal_consistency(void)
+{
+ gc_verify_internal_consistency(rb_gc_get_objspace());
+}
+
/*
* call-seq:
* GC.verify_internal_consistency -> nil
@@ -8923,7 +9305,7 @@ gc_profile_disable(VALUE _)
static VALUE
gc_verify_internal_consistency_m(VALUE dummy)
{
- gc_verify_internal_consistency(rb_gc_get_objspace());
+ rb_gc_verify_internal_consistency();
return Qnil;
}
@@ -9180,8 +9562,8 @@ gc_verify_compaction_references(int argc, VALUE* argv, VALUE self)
* 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) {
+ objspace->heap_pages.allocatable_bytes = desired_compaction.required_slots[i] * heap->slot_size;
+ while (objspace->heap_pages.allocatable_bytes > 0) {
heap_page_allocate_and_initialize(objspace, heap);
}
/*
@@ -9244,6 +9626,10 @@ rb_gc_impl_objspace_free(void *objspace_ptr)
rb_darray_free_without_gc(objspace->weak_references);
+#ifdef MALLOC_COUNTERS_NEED_LOCK
+ rb_native_mutex_destroy(&objspace->malloc_counters.lock);
+#endif
+
free(objspace);
}
@@ -9281,8 +9667,23 @@ gc_malloc_allocations(VALUE self)
}
#endif
-void rb_gc_impl_before_fork(void *objspace_ptr) { /* no-op */ }
-void rb_gc_impl_after_fork(void *objspace_ptr, rb_pid_t pid) {
+void
+rb_gc_impl_before_fork(void *objspace_ptr)
+{
+ rb_objspace_t *objspace = objspace_ptr;
+
+ objspace->fork_vm_lock_lev = RB_GC_VM_LOCK();
+ rb_gc_vm_barrier();
+}
+
+void
+rb_gc_impl_after_fork(void *objspace_ptr, rb_pid_t pid)
+{
+ rb_objspace_t *objspace = objspace_ptr;
+
+ RB_GC_VM_UNLOCK(objspace->fork_vm_lock_lev);
+ objspace->fork_vm_lock_lev = 0;
+
if (pid == 0) { /* child process */
rb_gc_ractor_newobj_cache_foreach(gc_ractor_newobj_cache_clear, NULL);
}
@@ -9290,6 +9691,7 @@ void rb_gc_impl_after_fork(void *objspace_ptr, rb_pid_t pid) {
VALUE rb_ident_hash_new_with_size(st_index_t size);
+#if GC_DEBUG_STRESS_TO_CLASS
/*
* call-seq:
* GC.add_stress_to_class(class[, ...])
@@ -9339,6 +9741,7 @@ rb_gcdebug_remove_stress_to_class(int argc, VALUE *argv, VALUE self)
return Qnil;
}
+#endif
void *
rb_gc_impl_objspace_alloc(void)
@@ -9357,27 +9760,32 @@ rb_gc_impl_objspace_init(void *objspace_ptr)
objspace->flags.measure_gc = true;
malloc_limit = gc_params.malloc_limit_min;
+#ifdef MALLOC_COUNTERS_NEED_LOCK
+ rb_native_mutex_initialize(&objspace->malloc_counters.lock);
+#endif
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");
}
+ /* A standard RVALUE (RBasic + embedded VALUEs + debug overhead) must fit
+ * in at least one pool. In debug builds RVALUE_OVERHEAD can push this
+ * beyond the 48-byte pool into the 64-byte pool, which is fine. */
+ GC_ASSERT(rb_gc_impl_size_allocatable_p(sizeof(struct RBasic) + sizeof(VALUE[RBIMPL_RVALUE_EMBED_LEN_MAX])));
+
for (int i = 0; i < HEAP_COUNT; i++) {
rb_heap_t *heap = &heaps[i];
- heap->slot_size = (1 << i) * BASE_SLOT_SIZE;
+ heap->slot_size = pool_slot_sizes[i];
ccan_list_head_init(&heap->pages);
}
+ init_size_to_heap_idx();
+
rb_darray_make_without_gc(&objspace->heap_pages.sorted, 0);
rb_darray_make_without_gc(&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;
@@ -9385,11 +9793,7 @@ rb_gc_impl_objspace_init(void *objspace_ptr)
#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;
- }
+ gc_params.heap_init_bytes = GC_HEAP_INIT_BYTES;
init_mark_stack(&objspace->mark_stack);
@@ -9402,10 +9806,14 @@ 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));
+ /* Minimum slot size that fits a standard RVALUE */
+ size_t rvalue_pool = 0;
+ for (size_t i = 0; i < HEAP_COUNT; i++) {
+ if (pool_slot_sizes[i] >= RVALUE_SLOT_SIZE) { rvalue_pool = pool_slot_sizes[i]; break; }
+ }
+ rb_hash_aset(gc_constants, ID2SYM(rb_intern("RVALUE_SIZE")), SIZET2NUM(rvalue_pool - RVALUE_OVERHEAD));
rb_hash_aset(gc_constants, ID2SYM(rb_intern("RBASIC_SIZE")), SIZET2NUM(sizeof(struct RBasic)));
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));
@@ -9433,10 +9841,10 @@ rb_gc_impl_init(void)
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);
- }
+#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
/* internal methods */
rb_define_singleton_method(rb_mGC, "verify_internal_consistency", gc_verify_internal_consistency_m, 0);
diff --git a/gc/gc.h b/gc/gc.h
index fe9aaeb965..d147a3122a 100644
--- a/gc/gc.h
+++ b/gc/gc.h
@@ -10,16 +10,38 @@
* first introduced for [Feature #20470].
*/
#include "ruby/ruby.h"
+#include "ruby/assert.h"
-#if USE_MODULAR_GC
#include "ruby/thread_native.h"
+#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
+
+#if RACTOR_CHECK_MODE
+void rb_ractor_setup_belonging(VALUE obj);
+
+struct rb_gc_obj_suffix {
+ uint32_t _ractor_belonging_id;
+};
+
+# define RB_GC_OBJ_HAS_SUFFIX 1
+# define RB_GC_OBJ_SUFFIX_SIZE (sizeof(struct rb_gc_obj_suffix))
+#else
+# define RB_GC_OBJ_HAS_SUFFIX 0
+# define RB_GC_OBJ_SUFFIX_SIZE 0
+#endif
+
struct rb_gc_vm_context {
rb_nativethread_lock_t lock;
struct rb_execution_context_struct *ec;
};
-#endif
typedef int (*vm_table_foreach_callback_func)(VALUE value, void *data);
typedef int (*vm_table_update_callback_func)(VALUE *value, void *data);
@@ -31,7 +53,6 @@ enum rb_gc_vm_weak_tables {
RB_GC_VM_ID2REF_TABLE,
RB_GC_VM_GENERIC_FIELDS_TABLE,
RB_GC_VM_FROZEN_STRINGS_TABLE,
- RB_GC_VM_CC_REFINEMENT_TABLE,
RB_GC_VM_WEAK_TABLE_COUNT
};
@@ -58,11 +79,12 @@ RUBY_SYMBOL_EXPORT_BEGIN
// files in Ruby.
size_t rb_size_mul_or_raise(size_t x, size_t y, VALUE exc);
void rb_objspace_reachable_objects_from(VALUE obj, void (func)(VALUE, void *), void *data);
-void rb_obj_info_dump(VALUE obj);
+const char *rb_raw_obj_info(char *const buff, const size_t buff_size, VALUE obj);
const char *rb_obj_info(VALUE obj);
size_t rb_obj_memsize_of(VALUE obj);
bool ruby_free_at_exit_p(void);
void rb_objspace_reachable_objects_from_root(void (func)(const char *category, VALUE, void *), void *passing_data);
+void rb_gc_verify_shareable(VALUE);
MODULAR_GC_FN unsigned int rb_gc_vm_lock(const char *file, int line);
MODULAR_GC_FN void rb_gc_vm_unlock(unsigned int lev, const char *file, int line);
@@ -88,21 +110,23 @@ MODULAR_GC_FN void rb_gc_mark_roots(void *objspace, const char **categoryp);
MODULAR_GC_FN void rb_gc_ractor_newobj_cache_foreach(void (*func)(void *cache, void *data), void *data);
MODULAR_GC_FN bool rb_gc_multi_ractor_p(void);
MODULAR_GC_FN bool rb_gc_shutdown_call_finalizer_p(VALUE obj);
-MODULAR_GC_FN uint32_t rb_gc_get_shape(VALUE obj);
-MODULAR_GC_FN void rb_gc_set_shape(VALUE obj, uint32_t shape_id);
-MODULAR_GC_FN uint32_t rb_gc_rebuild_shape(VALUE obj, size_t heap_id);
+MODULAR_GC_FN void rb_gc_obj_changed_pool(VALUE obj, size_t heap_id);
MODULAR_GC_FN void rb_gc_prepare_heap_process_object(VALUE obj);
MODULAR_GC_FN bool rb_memerror_reentered(void);
MODULAR_GC_FN bool rb_obj_id_p(VALUE);
MODULAR_GC_FN void rb_gc_before_updating_jit_code(void);
MODULAR_GC_FN void rb_gc_after_updating_jit_code(void);
+MODULAR_GC_FN bool rb_gc_obj_shareable_p(VALUE);
+MODULAR_GC_FN void rb_gc_rp(VALUE);
+MODULAR_GC_FN void rb_gc_handle_weak_references(VALUE obj);
+MODULAR_GC_FN bool rb_gc_obj_needs_cleanup_p(VALUE obj);
#if USE_MODULAR_GC
MODULAR_GC_FN bool rb_gc_event_hook_required_p(rb_event_flag_t event);
MODULAR_GC_FN void *rb_gc_get_ractor_newobj_cache(void);
MODULAR_GC_FN void rb_gc_initialize_vm_context(struct rb_gc_vm_context *context);
-MODULAR_GC_FN void rb_gc_worker_thread_set_vm_context(struct rb_gc_vm_context *context);
-MODULAR_GC_FN void rb_gc_worker_thread_unset_vm_context(struct rb_gc_vm_context *context);
+MODULAR_GC_FN void rb_gc_move_obj_during_marking(VALUE from, VALUE to);
+MODULAR_GC_FN void rb_gc_print_backtrace();
#endif
#if USE_MODULAR_GC
@@ -171,6 +195,14 @@ gc_mark_tbl_no_pin_i(st_data_t key, st_data_t value, st_data_t data)
}
static int
+gc_mark_set_no_pin_i(st_data_t key, st_data_t value, st_data_t data)
+{
+ rb_gc_mark_movable((VALUE)key);
+
+ 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) {
@@ -187,12 +219,14 @@ hash_foreach_replace(st_data_t key, st_data_t value, st_data_t argp, int error)
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);
+ VALUE new_key = rb_gc_location((VALUE)*key);
+ if (new_key != (VALUE)*key) {
+ *key = new_key;
}
- if (rb_gc_location((VALUE)*value) != (VALUE)*value) {
- *value = rb_gc_location((VALUE)*value);
+ VALUE new_value = rb_gc_location((VALUE)*value);
+ if (new_value != (VALUE)*value) {
+ *value = new_value;
}
return ST_CONTINUE;
diff --git a/gc/gc_impl.h b/gc/gc_impl.h
index d1ae7983a2..d9e44cc66d 100644
--- a/gc/gc_impl.h
+++ b/gc/gc_impl.h
@@ -54,8 +54,9 @@ 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 void rb_gc_impl_config_set(void *objspace_ptr, VALUE hash);
+GC_IMPL_FN struct rb_gc_vm_context *rb_gc_impl_get_vm_context(void *objspace_ptr);
// 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 VALUE rb_gc_impl_new_obj(void *objspace_ptr, void *cache_ptr, VALUE klass, VALUE flags, 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);
@@ -72,9 +73,9 @@ GC_IMPL_FN bool rb_gc_impl_size_allocatable_p(size_t size);
* memory just return NULL (with appropriate errno set).
* The caller side takes care of that situation.
*/
-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_malloc(void *objspace_ptr, size_t size, bool gc_allowed);
+GC_IMPL_FN void *rb_gc_impl_calloc(void *objspace_ptr, size_t size, bool gc_allowed);
+GC_IMPL_FN void *rb_gc_impl_realloc(void *objspace_ptr, void *ptr, size_t new_size, size_t old_size, bool gc_allowed);
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
@@ -82,9 +83,11 @@ 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);
+// Weak references
+GC_IMPL_FN void rb_gc_impl_declare_weak_references(void *objspace_ptr, VALUE obj);
+GC_IMPL_FN bool rb_gc_impl_handle_weak_references_alive_p(void *objspace_ptr, VALUE obj);
// Compaction
+GC_IMPL_FN void rb_gc_impl_register_pinning_obj(void *objspace_ptr, VALUE obj);
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
diff --git a/gc/mmtk/Cargo.lock b/gc/mmtk/Cargo.lock
index f7d62ddacb..910048fa80 100644
--- a/gc/mmtk/Cargo.lock
+++ b/gc/mmtk/Cargo.lock
@@ -301,9 +301,9 @@ dependencies = [
[[package]]
name = "git2"
-version = "0.20.2"
+version = "0.20.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2deb07a133b1520dc1a5690e9bd08950108873d7ed5de38dcc74d3b5ebffa110"
+checksum = "7b88256088d75a56f8ecfa070513a775dd9107f6530ef14919dac831af9cfe2b"
dependencies = [
"bitflags",
"libc",
@@ -435,9 +435,9 @@ checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa"
[[package]]
name = "libgit2-sys"
-version = "0.18.1+1.9.0"
+version = "0.18.3+1.9.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e1dcb20f84ffcdd825c7a311ae347cce604a6f084a767dec4a4929829645290e"
+checksum = "c9b3acc4b91781bb0b3386669d325163746af5f6e4f73e6d2d630e09a35f3487"
dependencies = [
"cc",
"libc",
@@ -491,7 +491,7 @@ dependencies = [
[[package]]
name = "mmtk"
version = "0.31.0"
-source = "git+https://github.com/mmtk/mmtk-core.git?rev=3d89bb51c191d3077278684ec5059726128d3e2b#3d89bb51c191d3077278684ec5059726128d3e2b"
+source = "git+https://github.com/mmtk/mmtk-core.git?rev=c6317a3f1c262e33fc2e427e4cc999c17bcc4791#c6317a3f1c262e33fc2e427e4cc999c17bcc4791"
dependencies = [
"atomic",
"atomic-traits",
@@ -517,6 +517,7 @@ dependencies = [
"num_cpus",
"portable-atomic",
"probe",
+ "rayon-core",
"regex",
"rustversion",
"spin",
@@ -529,7 +530,7 @@ dependencies = [
[[package]]
name = "mmtk-macros"
version = "0.31.0"
-source = "git+https://github.com/mmtk/mmtk-core.git?rev=3d89bb51c191d3077278684ec5059726128d3e2b#3d89bb51c191d3077278684ec5059726128d3e2b"
+source = "git+https://github.com/mmtk/mmtk-core.git?rev=c6317a3f1c262e33fc2e427e4cc999c17bcc4791#c6317a3f1c262e33fc2e427e4cc999c17bcc4791"
dependencies = [
"proc-macro-error",
"proc-macro2",
diff --git a/gc/mmtk/Cargo.toml b/gc/mmtk/Cargo.toml
index e1b1d1e13b..d856122900 100644
--- a/gc/mmtk/Cargo.toml
+++ b/gc/mmtk/Cargo.toml
@@ -21,11 +21,11 @@ probe = "0.5"
sysinfo = "0.32.0"
[dependencies.mmtk]
-features = ["is_mmtk_object", "object_pinning", "sticky_immix_non_moving_nursery", "immix_non_moving"]
+features = ["is_mmtk_object", "object_pinning", "sticky_immix_non_moving_nursery"]
# Uncomment the following lines to use mmtk-core from the official repository.
git = "https://github.com/mmtk/mmtk-core.git"
-rev = "3d89bb51c191d3077278684ec5059726128d3e2b"
+rev = "c6317a3f1c262e33fc2e427e4cc999c17bcc4791"
# Uncomment the following line to use mmtk-core from a local repository.
# path = "../../../mmtk-core"
diff --git a/gc/mmtk/cbindgen.toml b/gc/mmtk/cbindgen.toml
index c66f829b3d..b99c30efc8 100644
--- a/gc/mmtk/cbindgen.toml
+++ b/gc/mmtk/cbindgen.toml
@@ -20,6 +20,11 @@ typedef void *MMTk_Address;
typedef void *MMTk_ObjectReference;
typedef void *MMTk_NullableObjectReference;
typedef uint32_t MMTk_AllocationSemantics;
+
+typedef struct MMTk_BumpPointer {
+ uintptr_t cursor;
+ uintptr_t limit;
+} MMTk_BumpPointer;
"""
[export]
diff --git a/gc/mmtk/extconf.rb b/gc/mmtk/extconf.rb
index 5f4228972b..c0e788037e 100644
--- a/gc/mmtk/extconf.rb
+++ b/gc/mmtk/extconf.rb
@@ -15,6 +15,10 @@ create_gc_makefile("mmtk") do |makefile|
MMTK_BUILD = debug
LIBMMTK_RUBY = libmmtk_ruby.#$LIBEXT
RUSTSRCS = #{rustsrcs.join(" \\\n\t ")}
+
+ ifeq ($(MMTK_BUILD), debug)
+ CPPFLAGS += -DMMTK_DEBUG
+ endif
MAKEFILE
]
end
diff --git a/gc/mmtk/mmtk.c b/gc/mmtk/mmtk.c
index 1c7d2d9455..8be69b4fe6 100644
--- a/gc/mmtk/mmtk.c
+++ b/gc/mmtk/mmtk.c
@@ -21,6 +21,7 @@ struct objspace {
bool gc_stress;
size_t gc_count;
+ size_t moving_gc_count;
size_t total_gc_time;
size_t total_allocated_objects;
@@ -32,19 +33,38 @@ struct objspace {
unsigned long live_ractor_cache_count;
pthread_mutex_t mutex;
+ rb_atomic_t mutator_blocking_count;
bool world_stopped;
pthread_cond_t cond_world_stopped;
pthread_cond_t cond_world_started;
size_t start_the_world_count;
+ pthread_mutex_t event_hook_mutex;
+
+ struct {
+ bool gc_thread_crashed;
+ char crash_msg[256];
+ } crash_context;
+
struct rb_gc_vm_context vm_context;
+
+ unsigned int fork_hook_vm_lock_lev;
};
+#define OBJ_FREE_BUF_CAPACITY 128
+
struct MMTk_ractor_cache {
struct ccan_list_node list_node;
MMTk_Mutator *mutator;
bool gc_mutator_p;
+
+ MMTk_BumpPointer *bump_pointer;
+
+ MMTk_ObjectReference obj_free_parallel_buf[OBJ_FREE_BUF_CAPACITY];
+ size_t obj_free_parallel_count;
+ MMTk_ObjectReference obj_free_non_parallel_buf[OBJ_FREE_BUF_CAPACITY];
+ size_t obj_free_non_parallel_count;
};
struct MMTk_final_job {
@@ -67,12 +87,22 @@ struct MMTk_final_job {
#ifdef RB_THREAD_LOCAL_SPECIFIER
RB_THREAD_LOCAL_SPECIFIER struct MMTk_GCThreadTLS *rb_mmtk_gc_thread_tls;
+
+RB_THREAD_LOCAL_SPECIFIER VALUE marking_parent_object;
#else
# error We currently need language-supported TLS
#endif
+#ifdef MMTK_DEBUG
+# define MMTK_ASSERT(expr, ...) RUBY_ASSERT_ALWAYS(expr, #expr RBIMPL_VA_OPT_ARGS(__VA_ARGS__))
+#else
+# define MMTK_ASSERT(expr, ...) ((void)0)
+#endif
+
#include <pthread.h>
+static inline VALUE rb_mmtk_call_object_closure(VALUE obj, bool pin);
+
static void
rb_mmtk_init_gc_worker_thread(MMTk_VMWorkerThread gc_thread_tls)
{
@@ -105,7 +135,7 @@ rb_mmtk_stop_the_world(void)
}
static void
-rb_mmtk_resume_mutators(void)
+rb_mmtk_resume_mutators(bool current_gc_may_move)
{
struct objspace *objspace = rb_gc_get_objspace();
@@ -116,6 +146,7 @@ rb_mmtk_resume_mutators(void)
objspace->world_stopped = false;
objspace->gc_count++;
+ if (current_gc_may_move) objspace->moving_gc_count++;
pthread_cond_broadcast(&objspace->cond_world_started);
if ((err = pthread_mutex_unlock(&objspace->mutex)) != 0) {
@@ -123,13 +154,17 @@ rb_mmtk_resume_mutators(void)
}
}
+static void mmtk_flush_obj_free_buffer(struct MMTk_ractor_cache *cache);
+
static void
rb_mmtk_block_for_gc(MMTk_VMMutatorThread mutator)
{
struct objspace *objspace = rb_gc_get_objspace();
size_t starting_gc_count = objspace->gc_count;
+ RUBY_ATOMIC_INC(objspace->mutator_blocking_count);
int lock_lev = RB_GC_VM_LOCK();
+ RUBY_ATOMIC_DEC(objspace->mutator_blocking_count);
int err;
if ((err = pthread_mutex_lock(&objspace->mutex)) != 0) {
rb_bug("ERROR: cannot lock objspace->mutex: %s", strerror(err));
@@ -151,6 +186,11 @@ rb_mmtk_block_for_gc(MMTk_VMMutatorThread mutator)
rb_gc_vm_barrier();
+ struct MMTk_ractor_cache *rc;
+ ccan_list_for_each(&objspace->ractor_caches, rc, list_node) {
+ mmtk_flush_obj_free_buffer(rc);
+ }
+
objspace->world_stopped = true;
pthread_cond_broadcast(&objspace->cond_world_stopped);
@@ -160,6 +200,10 @@ rb_mmtk_block_for_gc(MMTk_VMMutatorThread mutator)
pthread_cond_wait(&objspace->cond_world_started, &objspace->mutex);
}
+ if (RB_UNLIKELY(objspace->crash_context.gc_thread_crashed)) {
+ rb_bug("%s", objspace->crash_context.crash_msg);
+ }
+
if (objspace->measure_gc_time) {
struct timespec gc_end_time;
clock_gettime(CLOCK_MONOTONIC, &gc_end_time);
@@ -176,6 +220,18 @@ rb_mmtk_block_for_gc(MMTk_VMMutatorThread mutator)
RB_GC_VM_UNLOCK(lock_lev);
}
+static void
+rb_mmtk_before_updating_jit_code(void)
+{
+ rb_gc_before_updating_jit_code();
+}
+
+static void
+rb_mmtk_after_updating_jit_code(void)
+{
+ rb_gc_after_updating_jit_code();
+}
+
static size_t
rb_mmtk_number_of_mutators(void)
{
@@ -199,11 +255,7 @@ rb_mmtk_scan_gc_roots(void)
{
struct objspace *objspace = rb_gc_get_objspace();
- // FIXME: Make `rb_gc_mark_roots` aware that the current thread may not have EC.
- // See: https://github.com/ruby/mmtk/issues/22
- rb_gc_worker_thread_set_vm_context(&objspace->vm_context);
rb_gc_mark_roots(objspace, NULL);
- rb_gc_worker_thread_unset_vm_context(&objspace->vm_context);
}
static int
@@ -240,15 +292,45 @@ rb_mmtk_scan_objspace(void)
}
static void
-rb_mmtk_scan_object_ruby_style(MMTk_ObjectReference object)
+rb_mmtk_move_obj_during_marking(MMTk_ObjectReference from, MMTk_ObjectReference to)
{
- rb_gc_mark_children(rb_gc_get_objspace(), (VALUE)object);
+ rb_gc_move_obj_during_marking((VALUE)from, (VALUE)to);
+}
+
+static void
+rb_mmtk_update_object_references(MMTk_ObjectReference mmtk_object)
+{
+ VALUE object = (VALUE)mmtk_object;
+
+ if (!RB_FL_TEST(object, RUBY_FL_WEAK_REFERENCE)) {
+ marking_parent_object = object;
+ rb_gc_update_object_references(rb_gc_get_objspace(), object);
+ marking_parent_object = 0;
+ }
}
static void
rb_mmtk_call_gc_mark_children(MMTk_ObjectReference object)
{
+ marking_parent_object = (VALUE)object;
rb_gc_mark_children(rb_gc_get_objspace(), (VALUE)object);
+ marking_parent_object = 0;
+}
+
+static void
+rb_mmtk_handle_weak_references(MMTk_ObjectReference mmtk_object, bool moving)
+{
+ VALUE object = (VALUE)mmtk_object;
+
+ marking_parent_object = object;
+
+ rb_gc_handle_weak_references(object);
+
+ if (moving) {
+ rb_gc_update_object_references(rb_gc_get_objspace(), object);
+ }
+
+ marking_parent_object = 0;
}
static void
@@ -258,12 +340,18 @@ rb_mmtk_call_obj_free(MMTk_ObjectReference object)
struct objspace *objspace = rb_gc_get_objspace();
if (RB_UNLIKELY(rb_gc_event_hook_required_p(RUBY_INTERNAL_EVENT_FREEOBJ))) {
- rb_gc_worker_thread_set_vm_context(&objspace->vm_context);
+ pthread_mutex_lock(&objspace->event_hook_mutex);
rb_gc_event_hook(obj, RUBY_INTERNAL_EVENT_FREEOBJ);
- rb_gc_worker_thread_unset_vm_context(&objspace->vm_context);
+ pthread_mutex_unlock(&objspace->event_hook_mutex);
}
- rb_gc_obj_free(objspace, obj);
+ if (RB_UNLIKELY(rb_gc_obj_needs_cleanup_p(obj))) {
+ rb_gc_obj_free(objspace, obj);
+ }
+
+#ifdef MMTK_DEBUG
+ memset((void *)obj, 0, rb_gc_impl_obj_slot_size(obj));
+#endif
}
static size_t
@@ -275,11 +363,7 @@ rb_mmtk_vm_live_bytes(void)
static void
make_final_job(struct objspace *objspace, VALUE obj, VALUE table)
{
- RUBY_ASSERT(RB_FL_TEST(obj, RUBY_FL_FINALIZE));
- RUBY_ASSERT(mmtk_is_reachable((MMTk_ObjectReference)table));
- RUBY_ASSERT(RB_BUILTIN_TYPE(table) == T_ARRAY);
-
- RB_FL_UNSET(obj, RUBY_FL_FINALIZE);
+ MMTK_ASSERT(RB_BUILTIN_TYPE(table) == T_ARRAY);
struct MMTk_final_job *job = xmalloc(sizeof(struct MMTk_final_job));
job->next = objspace->finalizer_jobs;
@@ -290,15 +374,23 @@ make_final_job(struct objspace *objspace, VALUE obj, VALUE table)
}
static int
-rb_mmtk_update_finalizer_table_i(st_data_t key, st_data_t value, st_data_t data)
+rb_mmtk_update_finalizer_table_i(st_data_t key, st_data_t value, st_data_t data, int error)
{
- RUBY_ASSERT(RB_FL_TEST(key, RUBY_FL_FINALIZE));
- RUBY_ASSERT(mmtk_is_reachable((MMTk_ObjectReference)value));
- RUBY_ASSERT(RB_BUILTIN_TYPE(value) == T_ARRAY);
+ MMTK_ASSERT(mmtk_is_reachable((MMTk_ObjectReference)value));
+ MMTK_ASSERT(RB_BUILTIN_TYPE(value) == T_ARRAY);
struct objspace *objspace = (struct objspace *)data;
- if (!mmtk_is_reachable((MMTk_ObjectReference)key)) {
+ if (mmtk_is_reachable((MMTk_ObjectReference)key)) {
+ VALUE new_key_location = rb_mmtk_call_object_closure((VALUE)key, false);
+
+ MMTK_ASSERT(RB_FL_TEST(new_key_location, RUBY_FL_FINALIZE));
+
+ if (new_key_location != key) {
+ return ST_REPLACE;
+ }
+ }
+ else {
make_final_job(objspace, (VALUE)key, (VALUE)value);
rb_postponed_job_trigger(objspace->finalizer_postponed_job);
@@ -309,37 +401,71 @@ rb_mmtk_update_finalizer_table_i(st_data_t key, st_data_t value, st_data_t data)
return ST_CONTINUE;
}
+static int
+rb_mmtk_update_finalizer_table_replace_i(st_data_t *key, st_data_t *value, st_data_t data, int existing)
+{
+ *key = rb_mmtk_call_object_closure((VALUE)*key, false);
+
+ return ST_CONTINUE;
+}
+
static void
rb_mmtk_update_finalizer_table(void)
{
struct objspace *objspace = rb_gc_get_objspace();
- // TODO: replace with st_foreach_with_replace when GC is moving
- st_foreach(objspace->finalizer_table, rb_mmtk_update_finalizer_table_i, (st_data_t)objspace);
+ st_foreach_with_replace(
+ objspace->finalizer_table,
+ rb_mmtk_update_finalizer_table_i,
+ rb_mmtk_update_finalizer_table_replace_i,
+ (st_data_t)objspace
+ );
}
static int
-rb_mmtk_update_table_i(VALUE val, void *data)
+rb_mmtk_global_tables_count(void)
+{
+ return RB_GC_VM_WEAK_TABLE_COUNT;
+}
+
+static inline VALUE rb_mmtk_call_object_closure(VALUE obj, bool pin);
+
+static int
+rb_mmtk_update_global_tables_i(VALUE val, void *data)
{
if (!mmtk_is_reachable((MMTk_ObjectReference)val)) {
return ST_DELETE;
}
+ // TODO: check only if in moving GC
+ if (rb_mmtk_call_object_closure(val, false) != val) {
+ return ST_REPLACE;
+ }
+
return ST_CONTINUE;
}
static int
-rb_mmtk_global_tables_count(void)
+rb_mmtk_update_global_tables_replace_i(VALUE *ptr, void *data)
{
- return RB_GC_VM_WEAK_TABLE_COUNT;
+ // TODO: cache the new location so we don't call rb_mmtk_call_object_closure twice
+ *ptr = rb_mmtk_call_object_closure(*ptr, false);
+
+ return ST_CONTINUE;
}
static void
-rb_mmtk_update_global_tables(int table)
+rb_mmtk_update_global_tables(int table, bool moving)
{
- RUBY_ASSERT(table < RB_GC_VM_WEAK_TABLE_COUNT);
+ MMTK_ASSERT(table < RB_GC_VM_WEAK_TABLE_COUNT);
- rb_gc_vm_weak_table_foreach(rb_mmtk_update_table_i, NULL, NULL, true, (enum rb_gc_vm_weak_tables)table);
+ rb_gc_vm_weak_table_foreach(
+ rb_mmtk_update_global_tables_i,
+ rb_mmtk_update_global_tables_replace_i,
+ NULL,
+ !moving,
+ (enum rb_gc_vm_weak_tables)table
+ );
}
static bool
@@ -350,6 +476,46 @@ rb_mmtk_special_const_p(MMTk_ObjectReference object)
return RB_SPECIAL_CONST_P(obj);
}
+RBIMPL_ATTR_FORMAT(RBIMPL_PRINTF_FORMAT, 1, 2)
+RBIMPL_ATTR_NORETURN()
+static void
+rb_mmtk_gc_thread_bug(const char *msg, ...)
+{
+ struct objspace *objspace = rb_gc_get_objspace();
+
+ objspace->crash_context.gc_thread_crashed = true;
+
+ va_list args;
+ va_start(args, msg);
+ vsnprintf(objspace->crash_context.crash_msg, sizeof(objspace->crash_context.crash_msg), msg, args);
+ va_end(args);
+
+ fprintf(stderr, "-- GC thread backtrace "
+ "-------------------------------------------\n");
+ rb_gc_print_backtrace();
+ fprintf(stderr, "\n");
+
+ rb_mmtk_resume_mutators(false);
+
+ sleep(5);
+
+ rb_bug("rb_mmtk_gc_thread_bug");
+}
+
+RBIMPL_ATTR_NORETURN()
+static void
+rb_mmtk_gc_thread_panic_handler(void)
+{
+ rb_mmtk_gc_thread_bug("MMTk GC thread panicked");
+}
+
+RBIMPL_ATTR_NORETURN()
+static void
+rb_mmtk_mutator_thread_panic_handler(void)
+{
+ rb_bug("Ruby mutator thread panicked");
+}
+
// Bootup
MMTk_RubyUpcalls ruby_upcalls = {
rb_mmtk_init_gc_worker_thread,
@@ -357,18 +523,24 @@ MMTk_RubyUpcalls ruby_upcalls = {
rb_mmtk_stop_the_world,
rb_mmtk_resume_mutators,
rb_mmtk_block_for_gc,
+ rb_mmtk_before_updating_jit_code,
+ rb_mmtk_after_updating_jit_code,
rb_mmtk_number_of_mutators,
rb_mmtk_get_mutators,
rb_mmtk_scan_gc_roots,
rb_mmtk_scan_objspace,
- rb_mmtk_scan_object_ruby_style,
+ rb_mmtk_move_obj_during_marking,
+ rb_mmtk_update_object_references,
rb_mmtk_call_gc_mark_children,
+ rb_mmtk_handle_weak_references,
rb_mmtk_call_obj_free,
rb_mmtk_vm_live_bytes,
rb_mmtk_update_global_tables,
rb_mmtk_global_tables_count,
rb_mmtk_update_finalizer_table,
rb_mmtk_special_const_p,
+ rb_mmtk_mutator_thread_panic_handler,
+ rb_mmtk_gc_thread_panic_handler,
};
// Use max 80% of the available memory by default for MMTk
@@ -392,7 +564,10 @@ void *
rb_gc_impl_objspace_alloc(void)
{
MMTk_Builder *builder = rb_mmtk_builder_init();
- mmtk_init_binding(builder, NULL, &ruby_upcalls, (MMTk_ObjectReference)Qundef);
+ MMTk_RubyBindingOptions binding_options = {
+ .suffix_size = RB_GC_OBJ_SUFFIX_SIZE,
+ };
+ mmtk_init_binding(builder, &binding_options, &ruby_upcalls);
return calloc(1, sizeof(struct objspace));
}
@@ -414,6 +589,8 @@ rb_gc_impl_objspace_init(void *objspace_ptr)
objspace->mutex = (pthread_mutex_t)PTHREAD_MUTEX_INITIALIZER;
objspace->cond_world_stopped = (pthread_cond_t)PTHREAD_COND_INITIALIZER;
objspace->cond_world_started = (pthread_cond_t)PTHREAD_COND_INITIALIZER;
+
+ objspace->event_hook_mutex = (pthread_mutex_t)PTHREAD_MUTEX_INITIALIZER;
}
void
@@ -431,10 +608,11 @@ rb_gc_impl_ractor_cache_alloc(void *objspace_ptr, void *ractor)
}
objspace->live_ractor_cache_count++;
- struct MMTk_ractor_cache *cache = malloc(sizeof(struct MMTk_ractor_cache));
+ struct MMTk_ractor_cache *cache = calloc(1, sizeof(struct MMTk_ractor_cache));
ccan_list_add(&objspace->ractor_caches, &cache->list_node);
cache->mutator = mmtk_bind_mutator(cache);
+ cache->bump_pointer = mmtk_get_bump_pointer_allocator(cache->mutator);
return cache;
}
@@ -447,7 +625,15 @@ rb_gc_impl_ractor_cache_free(void *objspace_ptr, void *cache_ptr)
ccan_list_del(&cache->list_node);
- RUBY_ASSERT(objspace->live_ractor_cache_count > 1);
+ mmtk_flush_obj_free_buffer(cache);
+
+ if (ruby_free_at_exit_p()) {
+ MMTK_ASSERT(objspace->live_ractor_cache_count > 0);
+ }
+ else {
+ MMTK_ASSERT(objspace->live_ractor_cache_count > 1);
+ }
+
objspace->live_ractor_cache_count--;
mmtk_destroy_mutator(cache->mutator);
@@ -457,16 +643,31 @@ void rb_gc_impl_set_params(void *objspace_ptr) { }
static VALUE gc_verify_internal_consistency(VALUE self) { return Qnil; }
+#if SIZEOF_VALUE >= 8
+#define MMTK_HEAP_COUNT 12
+#define MMTK_MAX_OBJ_SIZE 1024
+static size_t heap_sizes[MMTK_HEAP_COUNT + 1] = {
+ 32, 40, 64, 80, 96, 128, 160, 256, 512, 640, 768, MMTK_MAX_OBJ_SIZE, 0
+};
+#else
+#define MMTK_HEAP_COUNT 5
+#define MMTK_MAX_OBJ_SIZE 512
+static size_t heap_sizes[MMTK_HEAP_COUNT + 1] = {
+ 32, 64, 128, 256, MMTK_MAX_OBJ_SIZE, 0
+};
+#endif
+
void
rb_gc_impl_init(void)
{
VALUE gc_constants = rb_hash_new();
- rb_hash_aset(gc_constants, ID2SYM(rb_intern("BASE_SLOT_SIZE")), SIZET2NUM(sizeof(VALUE) * 5));
+ rb_hash_aset(gc_constants, ID2SYM(rb_intern("RVALUE_SIZE")), SIZET2NUM(SIZEOF_VALUE >= 8 ? 64 : 32));
rb_hash_aset(gc_constants, ID2SYM(rb_intern("RBASIC_SIZE")), SIZET2NUM(sizeof(struct RBasic)));
rb_hash_aset(gc_constants, ID2SYM(rb_intern("RVALUE_OVERHEAD")), INT2NUM(0));
- rb_hash_aset(gc_constants, ID2SYM(rb_intern("RVARGC_MAX_ALLOCATE_SIZE")), LONG2FIX(640));
- // Pretend we have 5 size pools
- rb_hash_aset(gc_constants, ID2SYM(rb_intern("SIZE_POOL_COUNT")), LONG2FIX(5));
+ rb_hash_aset(gc_constants, ID2SYM(rb_intern("RVARGC_MAX_ALLOCATE_SIZE")), LONG2FIX(MMTK_MAX_OBJ_SIZE));
+ rb_hash_aset(gc_constants, ID2SYM(rb_intern("HEAP_COUNT")), LONG2FIX(MMTK_HEAP_COUNT));
+ // TODO: correctly set RVALUE_OLD_AGE when we have generational GC support
+ rb_hash_aset(gc_constants, ID2SYM(rb_intern("RVALUE_OLD_AGE")), INT2FIX(0));
OBJ_FREEZE(gc_constants);
rb_define_const(rb_mGC, "INTERNAL_CONSTANTS", gc_constants);
@@ -480,10 +681,6 @@ rb_gc_impl_init(void)
rb_define_singleton_method(rb_mGC, "verify_compaction_references", rb_f_notimplement, -1);
}
-static size_t heap_sizes[6] = {
- 40, 80, 160, 320, 640, 0
-};
-
size_t *
rb_gc_impl_heap_sizes(void *objspace_ptr)
{
@@ -524,8 +721,8 @@ rb_gc_impl_start(void *objspace_ptr, bool full_mark, bool immediate_mark, bool i
bool
rb_gc_impl_during_gc_p(void *objspace_ptr)
{
- // TODO
- return false;
+ struct objspace *objspace = objspace_ptr;
+ return objspace->world_stopped;
}
static void
@@ -595,17 +792,106 @@ rb_gc_impl_config_set(void *objspace_ptr, VALUE hash)
// TODO
}
+struct rb_gc_vm_context *
+rb_gc_impl_get_vm_context(void *objspace_ptr)
+{
+ struct objspace *objspace = objspace_ptr;
+
+ return &objspace->vm_context;
+}
+
// Object allocation
+static VALUE
+rb_mmtk_alloc_fast_path(struct objspace *objspace, struct MMTk_ractor_cache *ractor_cache, size_t size, size_t align)
+{
+ MMTk_BumpPointer *bump_pointer = ractor_cache->bump_pointer;
+ if (bump_pointer == NULL) return 0;
+
+ uintptr_t cursor = bump_pointer->cursor;
+
+ // Ensure cursor is aligned
+ size_t mask = align - 1;
+ cursor = (cursor + mask) & ~mask;
+
+ cursor += size;
+
+ if (cursor > bump_pointer->limit) {
+ return 0;
+ }
+ else {
+ VALUE obj = cursor - size;
+ bump_pointer->cursor = cursor;
+ return obj;
+ }
+}
+
+static bool
+obj_can_parallel_free_p(VALUE obj)
+{
+ switch (RB_BUILTIN_TYPE(obj)) {
+ case T_ARRAY:
+ case T_BIGNUM:
+ case T_COMPLEX:
+ case T_FLOAT:
+ case T_HASH:
+ case T_OBJECT:
+ case T_RATIONAL:
+ case T_REGEXP:
+ case T_STRING:
+ case T_STRUCT:
+ case T_SYMBOL:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static void
+mmtk_flush_obj_free_buffer(struct MMTk_ractor_cache *cache)
+{
+ if (cache->obj_free_parallel_count > 0) {
+ mmtk_add_obj_free_candidates(cache->obj_free_parallel_buf,
+ cache->obj_free_parallel_count, true);
+ cache->obj_free_parallel_count = 0;
+ }
+ if (cache->obj_free_non_parallel_count > 0) {
+ mmtk_add_obj_free_candidates(cache->obj_free_non_parallel_buf,
+ cache->obj_free_non_parallel_count, false);
+ cache->obj_free_non_parallel_count = 0;
+ }
+}
+
+static inline void
+mmtk_buffer_obj_free_candidate(struct MMTk_ractor_cache *cache, VALUE obj)
+{
+ if (obj_can_parallel_free_p(obj)) {
+ cache->obj_free_parallel_buf[cache->obj_free_parallel_count++] = (MMTk_ObjectReference)obj;
+ if (cache->obj_free_parallel_count >= OBJ_FREE_BUF_CAPACITY) {
+ mmtk_add_obj_free_candidates(cache->obj_free_parallel_buf,
+ cache->obj_free_parallel_count, true);
+ cache->obj_free_parallel_count = 0;
+ }
+ }
+ else {
+ cache->obj_free_non_parallel_buf[cache->obj_free_non_parallel_count++] = (MMTk_ObjectReference)obj;
+ if (cache->obj_free_non_parallel_count >= OBJ_FREE_BUF_CAPACITY) {
+ mmtk_add_obj_free_candidates(cache->obj_free_non_parallel_buf,
+ cache->obj_free_non_parallel_count, false);
+ cache->obj_free_non_parallel_count = 0;
+ }
+ }
+}
+
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)
+rb_gc_impl_new_obj(void *objspace_ptr, void *cache_ptr, VALUE klass, VALUE flags, bool wb_protected, size_t alloc_size)
{
#define MMTK_ALLOCATION_SEMANTICS_DEFAULT 0
struct objspace *objspace = objspace_ptr;
struct MMTk_ractor_cache *ractor_cache = cache_ptr;
- if (alloc_size > 640) rb_bug("too big");
- for (int i = 0; i < 5; i++) {
+ if (alloc_size > MMTK_MAX_OBJ_SIZE) rb_bug("too big");
+ for (int i = 0; i < MMTK_HEAP_COUNT; i++) {
if (alloc_size == heap_sizes[i]) break;
if (alloc_size < heap_sizes[i]) {
alloc_size = heap_sizes[i];
@@ -617,19 +903,24 @@ rb_gc_impl_new_obj(void *objspace_ptr, void *cache_ptr, VALUE klass, VALUE flags
mmtk_handle_user_collection_request(ractor_cache, false, false);
}
- VALUE *alloc_obj = mmtk_alloc(ractor_cache->mutator, alloc_size + 8, MMTk_MIN_OBJ_ALIGN, 0, MMTK_ALLOCATION_SEMANTICS_DEFAULT);
+ // Layout: [hidden size header (sizeof(VALUE))][payload (alloc_size)][suffix (RB_GC_OBJ_SUFFIX_SIZE)]
+ alloc_size += sizeof(VALUE) + RB_GC_OBJ_SUFFIX_SIZE;
+
+ VALUE *alloc_obj = (VALUE *)rb_mmtk_alloc_fast_path(objspace, ractor_cache, alloc_size, MMTk_MIN_OBJ_ALIGN);
+ if (!alloc_obj) {
+ alloc_obj = mmtk_alloc(ractor_cache->mutator, alloc_size, MMTk_MIN_OBJ_ALIGN, 0, MMTK_ALLOCATION_SEMANTICS_DEFAULT);
+ }
+
alloc_obj++;
- alloc_obj[-1] = alloc_size;
+ alloc_obj[-1] = alloc_size - sizeof(VALUE) - RB_GC_OBJ_SUFFIX_SIZE;
alloc_obj[0] = flags;
alloc_obj[1] = klass;
- if (alloc_size > 16) alloc_obj[2] = v1;
- if (alloc_size > 24) alloc_obj[3] = v2;
- if (alloc_size > 32) alloc_obj[4] = v3;
- mmtk_post_alloc(ractor_cache->mutator, (void*)alloc_obj, alloc_size + 8, MMTK_ALLOCATION_SEMANTICS_DEFAULT);
+ // TODO: implement fast path for mmtk_post_alloc
+ mmtk_post_alloc(ractor_cache->mutator, (void*)alloc_obj, alloc_size, MMTK_ALLOCATION_SEMANTICS_DEFAULT);
// TODO: only add when object needs obj_free to be called
- mmtk_add_obj_free_candidate(alloc_obj);
+ mmtk_buffer_obj_free_candidate(ractor_cache, (VALUE)alloc_obj);
objspace->total_allocated_objects++;
@@ -645,7 +936,7 @@ rb_gc_impl_obj_slot_size(VALUE obj)
size_t
rb_gc_impl_heap_id_for_size(void *objspace_ptr, size_t size)
{
- for (int i = 0; i < 5; i++) {
+ for (int i = 0; i < MMTK_HEAP_COUNT; i++) {
if (size == heap_sizes[i]) return i;
if (size < heap_sizes[i]) return i;
}
@@ -656,26 +947,26 @@ rb_gc_impl_heap_id_for_size(void *objspace_ptr, size_t size)
bool
rb_gc_impl_size_allocatable_p(size_t size)
{
- return size <= 640;
+ return size <= MMTK_MAX_OBJ_SIZE;
}
// Malloc
void *
-rb_gc_impl_malloc(void *objspace_ptr, size_t size)
+rb_gc_impl_malloc(void *objspace_ptr, size_t size, bool gc_allowed)
{
// TODO: don't use system malloc
return malloc(size);
}
void *
-rb_gc_impl_calloc(void *objspace_ptr, size_t size)
+rb_gc_impl_calloc(void *objspace_ptr, size_t size, bool gc_allowed)
{
// TODO: don't use system calloc
return calloc(1, size);
}
void *
-rb_gc_impl_realloc(void *objspace_ptr, void *ptr, size_t new_size, size_t old_size)
+rb_gc_impl_realloc(void *objspace_ptr, void *ptr, size_t new_size, size_t old_size, bool gc_allowed)
{
// TODO: don't use system realloc
return realloc(ptr, new_size);
@@ -691,15 +982,34 @@ rb_gc_impl_free(void *objspace_ptr, void *ptr, size_t old_size)
void rb_gc_impl_adjust_memory_usage(void *objspace_ptr, ssize_t diff) { }
// Marking
+static inline VALUE
+rb_mmtk_call_object_closure(VALUE obj, bool pin)
+{
+ if (RB_UNLIKELY(RB_BUILTIN_TYPE(obj) == T_NONE)) {
+ enum { info_size = 256 };
+ char obj_info_buf[info_size];
+ rb_raw_obj_info(obj_info_buf, info_size, obj);
+
+ char parent_obj_info_buf[info_size];
+ rb_raw_obj_info(parent_obj_info_buf, info_size, marking_parent_object);
+
+ rb_mmtk_gc_thread_bug("try to mark T_NONE object (obj: %s, parent: %s)", obj_info_buf, parent_obj_info_buf);
+ }
+
+ return (VALUE)rb_mmtk_gc_thread_tls->object_closure.c_function(
+ rb_mmtk_gc_thread_tls->object_closure.rust_closure,
+ rb_mmtk_gc_thread_tls->gc_context,
+ (MMTk_ObjectReference)obj,
+ pin
+ );
+}
+
void
rb_gc_impl_mark(void *objspace_ptr, VALUE obj)
{
if (RB_SPECIAL_CONST_P(obj)) return;
- rb_mmtk_gc_thread_tls->object_closure.c_function(rb_mmtk_gc_thread_tls->object_closure.rust_closure,
- rb_mmtk_gc_thread_tls->gc_context,
- (MMTk_ObjectReference)obj,
- false);
+ rb_mmtk_call_object_closure(obj, false);
}
void
@@ -707,8 +1017,10 @@ rb_gc_impl_mark_and_move(void *objspace_ptr, VALUE *ptr)
{
if (RB_SPECIAL_CONST_P(*ptr)) return;
- // TODO: make it movable
- rb_gc_impl_mark(objspace_ptr, *ptr);
+ VALUE new_obj = rb_mmtk_call_object_closure(*ptr, false);
+ if (new_obj != *ptr) {
+ *ptr = new_obj;
+ }
}
void
@@ -716,8 +1028,7 @@ rb_gc_impl_mark_and_pin(void *objspace_ptr, VALUE obj)
{
if (RB_SPECIAL_CONST_P(obj)) return;
- // TODO: also pin
- rb_gc_impl_mark(objspace_ptr, obj);
+ rb_mmtk_call_object_closure(obj, true);
}
void
@@ -729,28 +1040,35 @@ rb_gc_impl_mark_maybe(void *objspace_ptr, VALUE obj)
}
void
-rb_gc_impl_mark_weak(void *objspace_ptr, VALUE *ptr)
+rb_gc_impl_declare_weak_references(void *objspace_ptr, VALUE obj)
{
- mmtk_mark_weak((MMTk_ObjectReference *)ptr);
+ RB_FL_SET(obj, RUBY_FL_WEAK_REFERENCE);
+ mmtk_declare_weak_references((MMTk_ObjectReference)obj);
}
-void
-rb_gc_impl_remove_weak(void *objspace_ptr, VALUE parent_obj, VALUE *ptr)
+bool
+rb_gc_impl_handle_weak_references_alive_p(void *objspace_ptr, VALUE obj)
{
- mmtk_remove_weak((MMTk_ObjectReference *)ptr);
+ return mmtk_weak_references_alive_p((MMTk_ObjectReference)obj);
}
// Compaction
+void
+rb_gc_impl_register_pinning_obj(void *objspace_ptr, VALUE obj)
+{
+ mmtk_register_pinning_obj((MMTk_ObjectReference)obj);
+}
+
bool
rb_gc_impl_object_moved_p(void *objspace_ptr, VALUE obj)
{
- rb_bug("unimplemented");
+ return rb_mmtk_call_object_closure(obj, false) != obj;
}
VALUE
-rb_gc_impl_location(void *objspace_ptr, VALUE value)
+rb_gc_impl_location(void *objspace_ptr, VALUE obj)
{
- rb_bug("unimplemented");
+ return rb_mmtk_call_object_closure(obj, false);
}
// Write barriers
@@ -761,6 +1079,21 @@ rb_gc_impl_writebarrier(void *objspace_ptr, VALUE a, VALUE b)
if (SPECIAL_CONST_P(b)) return;
+#ifdef MMTK_DEBUG
+ if (!rb_gc_impl_pointer_to_heap_p(objspace_ptr, (void *)a)) {
+ char buff[256];
+ rb_bug("a: %s is not an object", rb_raw_obj_info(buff, 256, a));
+ }
+
+ if (!rb_gc_impl_pointer_to_heap_p(objspace_ptr, (void *)b)) {
+ char buff[256];
+ rb_bug("b: %s is not an object", rb_raw_obj_info(buff, 256, b));
+ }
+#endif
+
+ MMTK_ASSERT(BUILTIN_TYPE(a) != T_NONE);
+ MMTK_ASSERT(BUILTIN_TYPE(b) != T_NONE);
+
mmtk_object_reference_write_post(cache->mutator, (MMTk_ObjectReference)a);
}
@@ -1025,16 +1358,25 @@ rb_gc_impl_shutdown_call_finalizer(void *objspace_ptr)
gc_run_finalizers(objspace);
}
- struct MMTk_RawVecOfObjRef registered_candidates = mmtk_get_all_obj_free_candidates();
- for (size_t i = 0; i < registered_candidates.len; i++) {
- VALUE obj = (VALUE)registered_candidates.ptr[i];
+ unsigned int lev = RB_GC_VM_LOCK();
+ {
+ struct MMTk_ractor_cache *rc;
+ ccan_list_for_each(&objspace->ractor_caches, rc, list_node) {
+ mmtk_flush_obj_free_buffer(rc);
+ }
+
+ struct MMTk_RawVecOfObjRef registered_candidates = mmtk_get_all_obj_free_candidates();
+ for (size_t i = 0; i < registered_candidates.len; i++) {
+ VALUE obj = (VALUE)registered_candidates.ptr[i];
- if (rb_gc_shutdown_call_finalizer_p(obj)) {
- rb_gc_obj_free(objspace_ptr, obj);
- RBASIC(obj)->flags = 0;
+ if (rb_gc_shutdown_call_finalizer_p(obj)) {
+ rb_gc_obj_free(objspace_ptr, obj);
+ RBASIC(obj)->flags = 0;
+ }
}
+ mmtk_free_raw_vec_of_obj_ref(registered_candidates);
}
- mmtk_free_raw_vec_of_obj_ref(registered_candidates);
+ RB_GC_VM_UNLOCK(lev);
gc_run_finalizers(objspace);
}
@@ -1044,13 +1386,39 @@ rb_gc_impl_shutdown_call_finalizer(void *objspace_ptr)
void
rb_gc_impl_before_fork(void *objspace_ptr)
{
+ struct objspace *objspace = objspace_ptr;
+
+ retry:
+ objspace->fork_hook_vm_lock_lev = RB_GC_VM_LOCK();
+ rb_gc_vm_barrier();
+
+ /* At this point, we know that all the Ractors are paused because of the
+ * rb_gc_vm_barrier above. Since rb_mmtk_block_for_gc is a barrier point,
+ * one or more Ractors could be paused there. However, mmtk_before_fork is
+ * not compatible with that because it assumes that the MMTk workers are idle,
+ * but the workers are not idle because they are busy working on a GC.
+ *
+ * This essentially implements a trylock. It will optimistically lock but will
+ * release the lock if it detects that any other Ractors are waiting in
+ * rb_mmtk_block_for_gc.
+ */
+ rb_atomic_t mutator_blocking_count = RUBY_ATOMIC_LOAD(objspace->mutator_blocking_count);
+ if (mutator_blocking_count != 0) {
+ RB_GC_VM_UNLOCK(objspace->fork_hook_vm_lock_lev);
+ goto retry;
+ }
+
mmtk_before_fork();
}
void
rb_gc_impl_after_fork(void *objspace_ptr, rb_pid_t pid)
{
+ struct objspace *objspace = objspace_ptr;
+
mmtk_after_fork(rb_gc_get_ractor_newobj_cache());
+
+ RB_GC_VM_UNLOCK(objspace->fork_hook_vm_lock_lev);
}
// Statistics
@@ -1123,6 +1491,7 @@ rb_gc_impl_latest_gc_info(void *objspace_ptr, VALUE hash_or_key)
enum gc_stat_sym {
gc_stat_sym_count,
+ gc_stat_sym_moving_gc_count,
gc_stat_sym_time,
gc_stat_sym_total_allocated_objects,
gc_stat_sym_total_bytes,
@@ -1130,6 +1499,7 @@ enum gc_stat_sym {
gc_stat_sym_free_bytes,
gc_stat_sym_starting_heap_address,
gc_stat_sym_last_heap_address,
+ gc_stat_sym_weak_references_count,
gc_stat_sym_last
};
@@ -1141,6 +1511,7 @@ 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(moving_gc_count);
S(time);
S(total_allocated_objects);
S(total_bytes);
@@ -1148,6 +1519,7 @@ setup_gc_stat_symbols(void)
S(free_bytes);
S(starting_heap_address);
S(last_heap_address);
+ S(weak_references_count);
}
}
@@ -1176,6 +1548,7 @@ rb_gc_impl_stat(void *objspace_ptr, VALUE hash_or_sym)
rb_hash_aset(hash, gc_stat_symbols[gc_stat_sym_##name], SIZET2NUM(attr));
SET(count, objspace->gc_count);
+ SET(moving_gc_count, objspace->moving_gc_count);
SET(time, objspace->total_gc_time / (1000 * 1000));
SET(total_allocated_objects, objspace->total_allocated_objects);
SET(total_bytes, mmtk_total_bytes());
@@ -1183,6 +1556,7 @@ rb_gc_impl_stat(void *objspace_ptr, VALUE hash_or_sym)
SET(free_bytes, mmtk_free_bytes());
SET(starting_heap_address, (size_t)mmtk_starting_heap_address());
SET(last_heap_address, (size_t)mmtk_last_heap_address());
+ SET(weak_references_count, mmtk_weak_references_count());
#undef SET
if (!NIL_P(key)) {
@@ -1196,12 +1570,24 @@ rb_gc_impl_stat(void *objspace_ptr, VALUE hash_or_sym)
VALUE
rb_gc_impl_stat_heap(void *objspace_ptr, VALUE heap_name, VALUE hash_or_sym)
{
+ if (FIXNUM_P(heap_name) && SYMBOL_P(hash_or_sym)) {
+ int heap_idx = FIX2INT(heap_name);
+ if (heap_idx < 0 || heap_idx >= MMTK_HEAP_COUNT) {
+ rb_raise(rb_eArgError, "size pool index out of range");
+ }
+
+ if (hash_or_sym == ID2SYM(rb_intern("slot_size"))) {
+ return SIZET2NUM(heap_sizes[heap_idx]);
+ }
+
+ return Qundef;
+ }
+
if (RB_TYPE_P(hash_or_sym, T_HASH)) {
return hash_or_sym;
}
- else {
- return Qundef;
- }
+
+ return Qundef;
}
// Miscellaneous
@@ -1223,7 +1609,7 @@ rb_gc_impl_object_metadata(void *objspace_ptr, VALUE obj)
size_t n = 0;
#define SET_ENTRY(na, v) do { \
- RUBY_ASSERT(n <= RB_GC_OBJECT_METADATA_ENTRY_COUNT); \
+ MMTK_ASSERT(n <= RB_GC_OBJECT_METADATA_ENTRY_COUNT); \
object_metadata_entries[n].name = ID_##na; \
object_metadata_entries[n].val = v; \
n++; \
diff --git a/gc/mmtk/mmtk.h b/gc/mmtk/mmtk.h
index b00133a820..b11e2873e3 100644
--- a/gc/mmtk/mmtk.h
+++ b/gc/mmtk/mmtk.h
@@ -20,6 +20,11 @@ typedef void *MMTk_ObjectReference;
typedef void *MMTk_NullableObjectReference;
typedef uint32_t MMTk_AllocationSemantics;
+typedef struct MMTk_BumpPointer {
+ uintptr_t cursor;
+ uintptr_t limit;
+} MMTk_BumpPointer;
+
#define MMTk_OBJREF_OFFSET 8
@@ -28,7 +33,6 @@ typedef uint32_t MMTk_AllocationSemantics;
#define MMTk_GC_THREAD_KIND_WORKER 1
typedef struct MMTk_RubyBindingOptions {
- bool ractor_check_mode;
size_t suffix_size;
} MMTk_RubyBindingOptions;
@@ -55,20 +59,26 @@ typedef struct MMTk_RubyUpcalls {
void (*init_gc_worker_thread)(struct MMTk_GCThreadTLS *gc_worker_tls);
bool (*is_mutator)(void);
void (*stop_the_world)(void);
- void (*resume_mutators)(void);
+ void (*resume_mutators)(bool gc_may_move);
void (*block_for_gc)(MMTk_VMMutatorThread tls);
+ void (*before_updating_jit_code)(void);
+ void (*after_updating_jit_code)(void);
size_t (*number_of_mutators)(void);
void (*get_mutators)(void (*visit_mutator)(MMTk_Mutator*, void*), void *data);
void (*scan_gc_roots)(void);
void (*scan_objspace)(void);
- void (*scan_object_ruby_style)(MMTk_ObjectReference object);
+ void (*move_obj_during_marking)(MMTk_ObjectReference from, MMTk_ObjectReference to);
+ void (*update_object_references)(MMTk_ObjectReference object);
void (*call_gc_mark_children)(MMTk_ObjectReference object);
+ void (*handle_weak_references)(MMTk_ObjectReference object, bool moving);
void (*call_obj_free)(MMTk_ObjectReference object);
size_t (*vm_live_bytes)(void);
- void (*update_global_tables)(int tbl_idx);
+ void (*update_global_tables)(int tbl_idx, bool moving);
int (*global_tables_count)(void);
void (*update_finalizer_table)(void);
bool (*special_const_p)(MMTk_ObjectReference object);
+ void (*mutator_thread_panic_handler)(void);
+ void (*gc_thread_panic_handler)(void);
} MMTk_RubyUpcalls;
typedef struct MMTk_RawVecOfObjRef {
@@ -84,14 +94,15 @@ bool mmtk_is_reachable(MMTk_ObjectReference object);
MMTk_Builder *mmtk_builder_default(void);
void mmtk_init_binding(MMTk_Builder *builder,
- const struct MMTk_RubyBindingOptions *_binding_options,
- const struct MMTk_RubyUpcalls *upcalls,
- MMTk_ObjectReference weak_reference_dead_value);
+ const struct MMTk_RubyBindingOptions *binding_options,
+ const struct MMTk_RubyUpcalls *upcalls);
void mmtk_initialize_collection(MMTk_VMThread tls);
MMTk_Mutator *mmtk_bind_mutator(MMTk_VMMutatorThread tls);
+MMTk_BumpPointer *mmtk_get_bump_pointer_allocator(MMTk_Mutator *m);
+
void mmtk_destroy_mutator(MMTk_Mutator *mutator);
void mmtk_handle_user_collection_request(MMTk_VMMutatorThread tls, bool force, bool exhaustive);
@@ -111,11 +122,17 @@ void mmtk_post_alloc(MMTk_Mutator *mutator,
size_t bytes,
MMTk_AllocationSemantics semantics);
-void mmtk_add_obj_free_candidate(MMTk_ObjectReference object);
+void mmtk_add_obj_free_candidates(const MMTk_ObjectReference *objects,
+ size_t count,
+ bool can_parallel_free);
+
+void mmtk_declare_weak_references(MMTk_ObjectReference object);
+
+bool mmtk_weak_references_alive_p(MMTk_ObjectReference object);
-void mmtk_mark_weak(MMTk_ObjectReference *ptr);
+size_t mmtk_weak_references_count(void);
-void mmtk_remove_weak(const MMTk_ObjectReference *ptr);
+void mmtk_register_pinning_obj(MMTk_ObjectReference obj);
void mmtk_object_reference_write_post(MMTk_Mutator *mutator, MMTk_ObjectReference object);
diff --git a/gc/mmtk/src/abi.rs b/gc/mmtk/src/abi.rs
index 2214441c9d..30890e0853 100644
--- a/gc/mmtk/src/abi.rs
+++ b/gc/mmtk/src/abi.rs
@@ -1,8 +1,12 @@
use crate::api::RubyMutator;
-use crate::{extra_assert, Ruby};
+use crate::extra_assert;
+use crate::Ruby;
use libc::c_int;
use mmtk::scheduler::GCWorker;
-use mmtk::util::{Address, ObjectReference, VMMutatorThread, VMWorkerThread};
+use mmtk::util::Address;
+use mmtk::util::ObjectReference;
+use mmtk::util::VMMutatorThread;
+use mmtk::util::VMWorkerThread;
// For the C binding
pub const OBJREF_OFFSET: usize = 8;
@@ -287,7 +291,6 @@ impl From<Vec<ObjectReference>> for RawVecOfObjRef {
#[repr(C)]
#[derive(Clone)]
pub struct RubyBindingOptions {
- pub ractor_check_mode: bool,
pub suffix_size: usize,
}
@@ -297,8 +300,10 @@ pub struct RubyUpcalls {
pub init_gc_worker_thread: extern "C" fn(gc_worker_tls: *mut GCThreadTLS),
pub is_mutator: extern "C" fn() -> bool,
pub stop_the_world: extern "C" fn(),
- pub resume_mutators: extern "C" fn(),
+ pub resume_mutators: extern "C" fn(gc_may_move: bool),
pub block_for_gc: extern "C" fn(tls: VMMutatorThread),
+ pub before_updating_jit_code: extern "C" fn(),
+ pub after_updating_jit_code: extern "C" fn(),
pub number_of_mutators: extern "C" fn() -> usize,
pub get_mutators: extern "C" fn(
visit_mutator: extern "C" fn(*mut RubyMutator, *mut libc::c_void),
@@ -306,14 +311,18 @@ pub struct RubyUpcalls {
),
pub scan_gc_roots: extern "C" fn(),
pub scan_objspace: extern "C" fn(),
- pub scan_object_ruby_style: extern "C" fn(object: ObjectReference),
+ pub move_obj_during_marking: extern "C" fn(from: ObjectReference, to: ObjectReference),
+ pub update_object_references: extern "C" fn(object: ObjectReference),
pub call_gc_mark_children: extern "C" fn(object: ObjectReference),
+ pub handle_weak_references: extern "C" fn(object: ObjectReference, moving: bool),
pub call_obj_free: extern "C" fn(object: ObjectReference),
pub vm_live_bytes: extern "C" fn() -> usize,
- pub update_global_tables: extern "C" fn(tbl_idx: c_int),
+ pub update_global_tables: extern "C" fn(tbl_idx: c_int, moving: bool),
pub global_tables_count: extern "C" fn() -> c_int,
pub update_finalizer_table: extern "C" fn(),
pub special_const_p: extern "C" fn(object: ObjectReference) -> bool,
+ pub mutator_thread_panic_handler: extern "C" fn(),
+ pub gc_thread_panic_handler: extern "C" fn(),
}
unsafe impl Sync for RubyUpcalls {}
diff --git a/gc/mmtk/src/api.rs b/gc/mmtk/src/api.rs
index 5217eb4a75..c0540fe0c8 100644
--- a/gc/mmtk/src/api.rs
+++ b/gc/mmtk/src/api.rs
@@ -2,6 +2,9 @@
// They are called by C functions and they need to pass raw pointers to Rust.
#![allow(clippy::missing_safety_doc)]
+use mmtk::util::alloc::BumpPointer;
+use mmtk::util::alloc::ImmixAllocator;
+use mmtk::util::conversions;
use mmtk::util::options::PlanSelector;
use std::str::FromStr;
use std::sync::atomic::Ordering;
@@ -11,6 +14,10 @@ use crate::abi::RubyBindingOptions;
use crate::abi::RubyUpcalls;
use crate::binding;
use crate::binding::RubyBinding;
+use crate::heap::CpuHeapTriggerConfig;
+use crate::heap::RubyHeapTriggerConfig;
+use crate::heap::CPU_HEAP_TRIGGER_CONFIG;
+use crate::heap::RUBY_HEAP_TRIGGER_CONFIG;
use crate::mmtk;
use crate::utils::default_heap_max;
use crate::utils::parse_capacity;
@@ -77,6 +84,29 @@ fn mmtk_builder_default_parse_heap_max() -> usize {
parse_env_var_with("MMTK_HEAP_MAX", parse_capacity).unwrap_or_else(default_heap_max)
}
+fn parse_float_env_var(key: &str, default: f64, min: f64, max: f64) -> f64 {
+ parse_env_var_with(key, |s| {
+ let mut float = f64::from_str(s).unwrap_or(default);
+
+ if float <= min {
+ eprintln!(
+ "{key} has value {float} which must be greater than {min}, using default instead"
+ );
+ float = default;
+ }
+
+ if float >= max {
+ eprintln!(
+ "{key} has value {float} which must be less than {max}, using default instead"
+ );
+ float = default;
+ }
+
+ Some(float)
+ })
+ .unwrap_or(default)
+}
+
fn mmtk_builder_default_parse_heap_mode(heap_min: usize, heap_max: usize) -> GCTriggerSelector {
let make_fixed = || GCTriggerSelector::FixedHeapSize(heap_max);
let make_dynamic = || GCTriggerSelector::DynamicHeapSize(heap_min, heap_max);
@@ -84,6 +114,61 @@ fn mmtk_builder_default_parse_heap_mode(heap_min: usize, heap_max: usize) -> GCT
parse_env_var_with("MMTK_HEAP_MODE", |s| match s {
"fixed" => Some(make_fixed()),
"dynamic" => Some(make_dynamic()),
+ "ruby" => {
+ let min_ratio = parse_float_env_var("RUBY_GC_HEAP_FREE_SLOTS_MIN_RATIO", 0.2, 0.0, 1.0);
+ let goal_ratio =
+ parse_float_env_var("RUBY_GC_HEAP_FREE_SLOTS_GOAL_RATIO", 0.4, min_ratio, 1.0);
+ let max_ratio =
+ parse_float_env_var("RUBY_GC_HEAP_FREE_SLOTS_MAX_RATIO", 0.65, goal_ratio, 1.0);
+
+ crate::heap::RUBY_HEAP_TRIGGER_CONFIG
+ .set(RubyHeapTriggerConfig {
+ min_heap_pages: conversions::bytes_to_pages_up(heap_min),
+ max_heap_pages: conversions::bytes_to_pages_up(heap_max),
+ heap_pages_min_ratio: min_ratio,
+ heap_pages_goal_ratio: goal_ratio,
+ heap_pages_max_ratio: max_ratio,
+ })
+ .unwrap_or_else(|_| panic!("RUBY_HEAP_TRIGGER_CONFIG is already set"));
+
+ Some(GCTriggerSelector::Delegated)
+ }
+ "cpu" => {
+ // CPU-overhead-driven heap sizing based on Tavakolisomeh et al.,
+ // "Heap Size Adjustment with CPU Control", MPLR '23.
+ //
+ // Target is expressed as a percentage (0, 100) via
+ // `MMTK_GC_CPU_TARGET`. The paper recommends 15 for ZGC (a
+ // concurrent collector); we default to 5 for MMTk-Ruby. With
+ // MMTk's stop-the-world Immix, every percent of GC CPU is also
+ // a percent of wall-clock the mutator is blocked on, so a much
+ // smaller budget is appropriate. An empirical sweep across
+ // ruby-bench (railsbench, lobsters, psych-load, liquid-render,
+ // lee) found target=5 to be Pareto-optimal: ~6% geomean speedup
+ // vs. the `ruby` heap mode with effectively identical geomean
+ // peak RSS.
+ let target_percent = parse_float_env_var("MMTK_GC_CPU_TARGET", 5.0, 0.0, 100.0);
+ let window_size = parse_env_var::<usize>("MMTK_GC_CPU_WINDOW").unwrap_or(3);
+ let window_size = window_size.max(1);
+
+ let min_heap_pages = conversions::bytes_to_pages_up(heap_min);
+ let max_heap_pages = conversions::bytes_to_pages_up(heap_max);
+ // Start at the min heap size, as the other delegated triggers do.
+ // The control loop will adjust from here after the first GC cycle.
+ let initial_heap_pages = min_heap_pages;
+
+ CPU_HEAP_TRIGGER_CONFIG
+ .set(CpuHeapTriggerConfig {
+ min_heap_pages,
+ max_heap_pages,
+ initial_heap_pages,
+ target_gc_cpu: target_percent / 100.0,
+ window_size,
+ })
+ .unwrap_or_else(|_| panic!("CPU_HEAP_TRIGGER_CONFIG is already set"));
+
+ Some(GCTriggerSelector::Delegated)
+ }
_ => None,
})
.unwrap_or_else(make_dynamic)
@@ -134,26 +219,24 @@ pub extern "C" fn mmtk_builder_default() -> *mut MMTKBuilder {
#[no_mangle]
pub unsafe extern "C" fn mmtk_init_binding(
builder: *mut MMTKBuilder,
- _binding_options: *const RubyBindingOptions,
+ binding_options: *const RubyBindingOptions,
upcalls: *const RubyUpcalls,
- weak_reference_dead_value: ObjectReference,
) {
+ crate::MUTATOR_THREAD_PANIC_HANDLER
+ .set((unsafe { (*upcalls).clone() }).mutator_thread_panic_handler)
+ .unwrap_or_else(|_| panic!("MUTATOR_THREAD_PANIC_HANDLER is already initialized"));
+
crate::set_panic_hook();
- let builder = unsafe { Box::from_raw(builder) };
- let binding_options = RubyBindingOptions {
- ractor_check_mode: false,
- suffix_size: 0,
- };
+ let builder: Box<MMTKBuilder> = unsafe { Box::from_raw(builder) };
+ let binding_options = unsafe { (*binding_options).clone() };
let mmtk_boxed = mmtk_init(&builder);
let mmtk_static = Box::leak(Box::new(mmtk_boxed));
- let binding = RubyBinding::new(
- mmtk_static,
- &binding_options,
- upcalls,
- weak_reference_dead_value,
- );
+ let mut binding = RubyBinding::new(mmtk_static, &binding_options, upcalls);
+ binding
+ .weak_proc
+ .init_parallel_obj_free_candidates(memory_manager::num_of_workers(binding.mmtk));
crate::BINDING
.set(binding)
@@ -171,6 +254,24 @@ pub extern "C" fn mmtk_bind_mutator(tls: VMMutatorThread) -> *mut RubyMutator {
}
#[no_mangle]
+pub unsafe extern "C" fn mmtk_get_bump_pointer_allocator(m: *mut RubyMutator) -> *mut BumpPointer {
+ match *crate::BINDING.get().unwrap().mmtk.get_options().plan {
+ PlanSelector::Immix => {
+ let mutator: &mut Mutator<Ruby> = unsafe { &mut *m };
+ let allocator =
+ unsafe { mutator.allocator_mut(mmtk::util::alloc::AllocatorSelector::Immix(0)) };
+
+ if let Some(immix_allocator) = allocator.downcast_mut::<ImmixAllocator<Ruby>>() {
+ &mut immix_allocator.bump_pointer as *mut BumpPointer
+ } else {
+ panic!("Failed to get bump pointer allocator");
+ }
+ }
+ _ => std::ptr::null_mut(),
+ }
+}
+
+#[no_mangle]
pub unsafe extern "C" fn mmtk_destroy_mutator(mutator: *mut RubyMutator) {
// notify mmtk-core about destroyed mutator
memory_manager::destroy_mutator(unsafe { &mut *mutator });
@@ -231,22 +332,40 @@ pub unsafe extern "C" fn mmtk_post_alloc(
memory_manager::post_alloc::<Ruby>(unsafe { &mut *mutator }, refer, bytes, semantics)
}
-// TODO: Replace with buffered mmtk_add_obj_free_candidates
#[no_mangle]
-pub extern "C" fn mmtk_add_obj_free_candidate(object: ObjectReference) {
- binding().weak_proc.add_obj_free_candidate(object)
+pub unsafe extern "C" fn mmtk_add_obj_free_candidates(
+ objects: *const ObjectReference,
+ count: usize,
+ can_parallel_free: bool,
+) {
+ let objects = unsafe { std::slice::from_raw_parts(objects, count) };
+ binding()
+ .weak_proc
+ .add_obj_free_candidates_batch(objects, can_parallel_free)
}
-// =============== Marking ===============
+// =============== Weak references ===============
#[no_mangle]
-pub extern "C" fn mmtk_mark_weak(ptr: &'static mut ObjectReference) {
- binding().weak_proc.add_weak_reference(ptr);
+pub extern "C" fn mmtk_declare_weak_references(object: ObjectReference) {
+ binding().weak_proc.add_weak_reference(object);
+}
+
+#[no_mangle]
+pub extern "C" fn mmtk_weak_references_alive_p(object: ObjectReference) -> bool {
+ object.is_reachable()
}
#[no_mangle]
-pub extern "C" fn mmtk_remove_weak(ptr: &ObjectReference) {
- binding().weak_proc.remove_weak_reference(ptr);
+pub extern "C" fn mmtk_weak_references_count() -> usize {
+ binding().weak_proc.weak_references_count()
+}
+
+// =============== Compaction ===============
+
+#[no_mangle]
+pub extern "C" fn mmtk_register_pinning_obj(obj: ObjectReference) {
+ crate::binding().pinning_registry.register(obj);
}
// =============== Write barriers ===============
@@ -364,11 +483,21 @@ pub extern "C" fn mmtk_plan() -> *const u8 {
pub extern "C" fn mmtk_heap_mode() -> *const u8 {
static FIXED_HEAP: &[u8] = b"fixed\0";
static DYNAMIC_HEAP: &[u8] = b"dynamic\0";
+ static RUBY_HEAP: &[u8] = b"ruby\0";
+ static CPU_HEAP: &[u8] = b"cpu\0";
match *crate::BINDING.get().unwrap().mmtk.get_options().gc_trigger {
GCTriggerSelector::FixedHeapSize(_) => FIXED_HEAP.as_ptr(),
GCTriggerSelector::DynamicHeapSize(_, _) => DYNAMIC_HEAP.as_ptr(),
- _ => panic!("Unknown heap mode"),
+ GCTriggerSelector::Delegated => {
+ // Two delegated triggers exist; disambiguate via the populated
+ // config singleton.
+ if CPU_HEAP_TRIGGER_CONFIG.get().is_some() {
+ CPU_HEAP.as_ptr()
+ } else {
+ RUBY_HEAP.as_ptr()
+ }
+ }
}
}
@@ -377,7 +506,18 @@ pub extern "C" fn mmtk_heap_min() -> usize {
match *crate::BINDING.get().unwrap().mmtk.get_options().gc_trigger {
GCTriggerSelector::FixedHeapSize(_) => 0,
GCTriggerSelector::DynamicHeapSize(min_size, _) => min_size,
- _ => panic!("Unknown heap mode"),
+ GCTriggerSelector::Delegated => {
+ if let Some(cfg) = CPU_HEAP_TRIGGER_CONFIG.get() {
+ conversions::pages_to_bytes(cfg.min_heap_pages)
+ } else {
+ conversions::pages_to_bytes(
+ RUBY_HEAP_TRIGGER_CONFIG
+ .get()
+ .expect("RUBY_HEAP_TRIGGER_CONFIG not set")
+ .min_heap_pages,
+ )
+ }
+ }
}
}
@@ -386,7 +526,18 @@ pub extern "C" fn mmtk_heap_max() -> usize {
match *crate::BINDING.get().unwrap().mmtk.get_options().gc_trigger {
GCTriggerSelector::FixedHeapSize(max_size) => max_size,
GCTriggerSelector::DynamicHeapSize(_, max_size) => max_size,
- _ => panic!("Unknown heap mode"),
+ GCTriggerSelector::Delegated => {
+ if let Some(cfg) = CPU_HEAP_TRIGGER_CONFIG.get() {
+ conversions::pages_to_bytes(cfg.max_heap_pages)
+ } else {
+ conversions::pages_to_bytes(
+ RUBY_HEAP_TRIGGER_CONFIG
+ .get()
+ .expect("RUBY_HEAP_TRIGGER_CONFIG not set")
+ .max_heap_pages,
+ )
+ }
+ }
}
}
diff --git a/gc/mmtk/src/binding.rs b/gc/mmtk/src/binding.rs
index 811cbf8abf..36d4a992fd 100644
--- a/gc/mmtk/src/binding.rs
+++ b/gc/mmtk/src/binding.rs
@@ -9,6 +9,7 @@ use mmtk::MMTK;
use crate::abi;
use crate::abi::RubyBindingOptions;
+use crate::pinning_registry::PinningRegistry;
use crate::weak_proc::WeakProcessor;
use crate::Ruby;
@@ -54,10 +55,9 @@ pub struct RubyBinding {
pub upcalls: *const abi::RubyUpcalls,
pub plan_name: Mutex<Option<CString>>,
pub weak_proc: WeakProcessor,
+ pub pinning_registry: PinningRegistry,
pub gc_thread_join_handles: Mutex<Vec<JoinHandle<()>>>,
pub wb_unprotected_objects: Mutex<HashSet<ObjectReference>>,
-
- pub weak_reference_dead_value: ObjectReference,
}
unsafe impl Sync for RubyBinding {}
@@ -68,7 +68,6 @@ impl RubyBinding {
mmtk: &'static MMTK<Ruby>,
binding_options: &RubyBindingOptions,
upcalls: *const abi::RubyUpcalls,
- weak_reference_dead_value: ObjectReference,
) -> Self {
unsafe {
crate::BINDING_FAST.suffix_size = binding_options.suffix_size;
@@ -80,10 +79,9 @@ impl RubyBinding {
upcalls,
plan_name: Mutex::new(None),
weak_proc: WeakProcessor::new(),
+ pinning_registry: PinningRegistry::new(),
gc_thread_join_handles: Default::default(),
wb_unprotected_objects: Default::default(),
-
- weak_reference_dead_value,
}
}
diff --git a/gc/mmtk/src/collection.rs b/gc/mmtk/src/collection.rs
index 41c508afd9..648efa4e27 100644
--- a/gc/mmtk/src/collection.rs
+++ b/gc/mmtk/src/collection.rs
@@ -1,14 +1,26 @@
use crate::abi::GCThreadTLS;
use crate::api::RubyMutator;
-use crate::{mmtk, upcalls, Ruby};
+use crate::heap::CpuHeapTrigger;
+use crate::heap::RubyHeapTrigger;
+use crate::heap::CPU_HEAP_TRIGGER_CONFIG;
+use crate::mmtk;
+use crate::upcalls;
+use crate::Ruby;
use mmtk::memory_manager;
use mmtk::scheduler::*;
-use mmtk::util::{VMMutatorThread, VMThread, VMWorkerThread};
-use mmtk::vm::{Collection, GCThreadContext};
+use mmtk::util::heap::GCTriggerPolicy;
+use mmtk::util::VMMutatorThread;
+use mmtk::util::VMThread;
+use mmtk::util::VMWorkerThread;
+use mmtk::vm::Collection;
+use mmtk::vm::GCThreadContext;
+use std::sync::atomic::AtomicBool;
use std::sync::atomic::Ordering;
use std::thread;
+static CURRENT_GC_MAY_MOVE: AtomicBool = AtomicBool::new(false);
+
pub struct VMCollection {}
impl Collection<Ruby> for VMCollection {
@@ -16,11 +28,21 @@ impl Collection<Ruby> for VMCollection {
crate::CONFIGURATION.gc_enabled.load(Ordering::Relaxed)
}
- fn stop_all_mutators<F>(_tls: VMWorkerThread, mut mutator_visitor: F)
+ fn stop_all_mutators<F>(tls: VMWorkerThread, mut mutator_visitor: F)
where
F: FnMut(&'static mut mmtk::Mutator<Ruby>),
{
(upcalls().stop_the_world)();
+
+ if crate::mmtk().get_plan().current_gc_may_move_object() {
+ CURRENT_GC_MAY_MOVE.store(true, Ordering::Relaxed);
+ (upcalls().before_updating_jit_code)();
+ } else {
+ CURRENT_GC_MAY_MOVE.store(false, Ordering::Relaxed);
+ }
+
+ crate::binding().pinning_registry.pin_children(tls);
+
(upcalls().get_mutators)(
Self::notify_mutator_ready::<F>,
&mut mutator_visitor as *mut F as *mut _,
@@ -28,7 +50,13 @@ impl Collection<Ruby> for VMCollection {
}
fn resume_mutators(_tls: VMWorkerThread) {
- (upcalls().resume_mutators)();
+ let current_gc_may_move = CURRENT_GC_MAY_MOVE.load(Ordering::Relaxed);
+
+ if current_gc_may_move {
+ (upcalls().after_updating_jit_code)();
+ }
+
+ (upcalls().resume_mutators)(current_gc_may_move);
}
fn block_for_gc(tls: VMMutatorThread) {
@@ -67,6 +95,19 @@ impl Collection<Ruby> for VMCollection {
fn vm_live_bytes() -> usize {
(upcalls().vm_live_bytes)()
}
+
+ fn create_gc_trigger() -> Box<dyn GCTriggerPolicy<Ruby>> {
+ // `GCTriggerSelector::Delegated` is currently used by two different
+ // heap modes: `ruby` (the Ruby-like free-slot ratio trigger) and `cpu`
+ // (the CPU-overhead trigger from Tavakolisomeh et al., MPLR '23).
+ // Which one is active is determined by which `OnceCell` config the
+ // `MMTK_HEAP_MODE` parser populated.
+ if CPU_HEAP_TRIGGER_CONFIG.get().is_some() {
+ Box::new(CpuHeapTrigger::default())
+ } else {
+ Box::new(RubyHeapTrigger::default())
+ }
+ }
}
impl VMCollection {
diff --git a/gc/mmtk/src/heap/cpu_heap_trigger.rs b/gc/mmtk/src/heap/cpu_heap_trigger.rs
new file mode 100644
index 0000000000..ef5a79fe9a
--- /dev/null
+++ b/gc/mmtk/src/heap/cpu_heap_trigger.rs
@@ -0,0 +1,370 @@
+//! A GC trigger that adjusts the heap size based on the CPU overhead of GC.
+//!
+//! This is an implementation of the heap sizing policy described in
+//! Tavakolisomeh, Shimchenko, Österlund, Bruno, Ferreira, Wrigstad,
+//! "Heap Size Adjustment with CPU Control", MPLR '23.
+//! <https://doi.org/10.1145/3617651.3622988>
+//!
+//! The idea: rather than letting heap size control GC frequency, let a
+//! user-supplied *target GC CPU overhead* control the heap size. After each GC
+//! cycle, we measure the GC CPU overhead (fraction of process CPU time spent
+//! in GC) and compare it to the target. If GC is over budget we grow the heap
+//! (reducing GC frequency); if it is under budget we shrink the heap (trading
+//! memory for more frequent collections).
+//!
+//! ## Algorithm
+//!
+//! After each GC cycle we compute, using an average of the last `n` cycles:
+//!
+//! ```text
+//! GC_CPU = T_GC / T_APP (Eq. 1)
+//! overhead_error = GC_CPU - target (Eq. 2)
+//! sigmoid_error = 1 / (1 + e^(-overhead_error)) (Eq. 3)
+//! adjustment_factor = sigmoid_error + 0.5 (in (0.5, 1.5)) (Eq. 4)
+//! new_size = current_size * adjustment_factor (Eq. 5)
+//! ```
+//!
+//! where:
+//! - `T_GC` is the wall-clock duration of each GC cycle.
+//! - `T_APP` is process CPU time elapsed between consecutive GC cycles (sum of
+//! CPU time over all threads — mutators, GC workers, compilers, etc.), read
+//! via `clock_gettime(CLOCK_PROCESS_CPUTIME_ID)`.
+//!
+//! The final heap size is then clamped to the range
+//! `[max(1.1 * used, min_heap_pages), max_heap_pages]`, providing 10% headroom
+//! above current live memory to avoid triggering GC on an effectively-empty
+//! heap.
+//!
+//! ## Differences from the paper
+//!
+//! The paper targets ZGC, a concurrent generational collector. MMTk's Ruby
+//! binding currently ships stop-the-world collectors (Immix, MarkSweep). The
+//! paper's formula still applies: with a STW collector the process CPU time
+//! during GC closely tracks the wall-clock GC time, and mutator CPU time
+//! during the mutator phase is correctly attributed. For generational plans
+//! we skip nursery-only GCs, consistent with MemBalancer.
+
+use std::sync::atomic::AtomicUsize;
+use std::sync::atomic::Ordering;
+use std::sync::Mutex;
+
+use mmtk::util::heap::GCTriggerPolicy;
+use mmtk::util::heap::SpaceStats;
+use mmtk::Plan;
+use mmtk::MMTK;
+use once_cell::sync::OnceCell;
+
+use crate::Ruby;
+
+pub static CPU_HEAP_TRIGGER_CONFIG: OnceCell<CpuHeapTriggerConfig> = OnceCell::new();
+
+/// Configuration for the [`CpuHeapTrigger`].
+pub struct CpuHeapTriggerConfig {
+ /// Lower bound on heap size (in pages). The trigger will never shrink below
+ /// this value.
+ pub min_heap_pages: usize,
+ /// Upper bound on heap size (in pages). The trigger will never grow above
+ /// this value.
+ pub max_heap_pages: usize,
+ /// Initial heap size (in pages).
+ pub initial_heap_pages: usize,
+ /// Target GC CPU overhead as a fraction of total process CPU time. For
+ /// example, `0.15` means the policy will try to keep GC CPU usage near 15%.
+ /// Valid range: `(0.0, 1.0)`.
+ pub target_gc_cpu: f64,
+ /// Number of recent GC cycles averaged together when computing the CPU
+ /// overhead signal. Smoothes out short-term fluctuations. The paper uses 3.
+ pub window_size: usize,
+}
+
+/// A single GC cycle's timing measurements.
+#[derive(Clone, Copy, Debug, Default)]
+struct GcSample {
+ /// Wall-clock seconds spent inside this GC cycle.
+ gc_seconds: f64,
+ /// Seconds of process CPU time elapsed since the previous GC cycle ended.
+ /// This covers both mutator time and (on multi-threaded mutators) any
+ /// mutator CPU time consumed in parallel with the previous GC.
+ app_cpu_seconds: f64,
+}
+
+struct CpuHeapTriggerState {
+ /// Ring buffer of the last `window_size` samples. Oldest-first.
+ samples: Vec<GcSample>,
+ /// Wall-clock time when the current GC cycle started. `None` when no GC is
+ /// in progress.
+ gc_start_wall: Option<std::time::Instant>,
+ /// Process CPU time (seconds) recorded at the end of the previous GC
+ /// cycle. `None` until the first cycle completes.
+ last_gc_end_cpu: Option<f64>,
+}
+
+impl CpuHeapTriggerState {
+ fn new() -> Self {
+ Self {
+ samples: Vec::new(),
+ gc_start_wall: None,
+ last_gc_end_cpu: None,
+ }
+ }
+
+ /// Pushes a new sample, dropping the oldest when the window is full.
+ fn push_sample(&mut self, sample: GcSample, window_size: usize) {
+ if self.samples.len() >= window_size {
+ self.samples.remove(0);
+ }
+ self.samples.push(sample);
+ }
+
+ /// Returns the arithmetic mean GC CPU overhead across the window, or
+ /// `None` if we don't yet have a full sample (which happens on the first
+ /// GC cycle — we have no baseline for `app_cpu_seconds`).
+ fn mean_gc_cpu(&self) -> Option<f64> {
+ if self.samples.is_empty() {
+ return None;
+ }
+ let total_gc: f64 = self.samples.iter().map(|s| s.gc_seconds).sum();
+ let total_app: f64 = self.samples.iter().map(|s| s.app_cpu_seconds).sum();
+ if total_app <= 0.0 {
+ return None;
+ }
+ Some(total_gc / total_app)
+ }
+}
+
+pub struct CpuHeapTrigger {
+ /// Target heap size in pages. Updated at the end of each GC cycle.
+ target_heap_pages: AtomicUsize,
+ /// Mutable timing state. Wrapped in a `Mutex` because `on_gc_start` and
+ /// `on_gc_end` are the only mutation sites and they are not on an
+ /// allocation hot path; avoiding the complexity of lock-free state is
+ /// worth the trivial contention.
+ state: Mutex<CpuHeapTriggerState>,
+}
+
+impl Default for CpuHeapTrigger {
+ fn default() -> Self {
+ let cfg = Self::get_config();
+ Self {
+ target_heap_pages: AtomicUsize::new(cfg.initial_heap_pages),
+ state: Mutex::new(CpuHeapTriggerState::new()),
+ }
+ }
+}
+
+impl GCTriggerPolicy<Ruby> for CpuHeapTrigger {
+ fn is_gc_required(
+ &self,
+ space_full: bool,
+ space: Option<SpaceStats<Ruby>>,
+ plan: &dyn Plan<VM = Ruby>,
+ ) -> bool {
+ // Let the plan decide, matching the other triggers.
+ plan.collection_required(space_full, space)
+ }
+
+ fn on_gc_start(&self, _mmtk: &'static MMTK<Ruby>) {
+ let mut state = self.state.lock().unwrap();
+ state.gc_start_wall = Some(std::time::Instant::now());
+ }
+
+ fn on_gc_end(&self, mmtk: &'static MMTK<Ruby>) {
+ // Skip nursery-only GCs for generational plans. The heap resizing
+ // decision is driven by the (much more expensive) full collections
+ // where the signal-to-noise ratio is high enough to be useful.
+ if let Some(gen_plan) = mmtk.get_plan().generational() {
+ if gen_plan.is_current_gc_nursery() {
+ return;
+ }
+ }
+
+ let cfg = Self::get_config();
+ let gc_end_cpu = process_cpu_time_seconds();
+
+ let mut state = self.state.lock().unwrap();
+
+ // Duration of this GC cycle (wall clock).
+ let gc_seconds = state
+ .gc_start_wall
+ .take()
+ .map(|start| start.elapsed().as_secs_f64())
+ .unwrap_or(0.0);
+
+ // Process CPU time elapsed since the previous GC cycle ended. We
+ // require at least one previous end timestamp to produce a valid
+ // sample — without it we cannot compute `T_APP`.
+ if let (Some(last_end), Some(now)) = (state.last_gc_end_cpu, gc_end_cpu) {
+ let app_cpu_seconds = (now - last_end).max(0.0);
+ // Only record non-degenerate samples to avoid poisoning the window
+ // with zero-time entries from back-to-back GCs.
+ if app_cpu_seconds > 0.0 {
+ state.push_sample(
+ GcSample {
+ gc_seconds,
+ app_cpu_seconds,
+ },
+ cfg.window_size,
+ );
+ }
+ }
+ state.last_gc_end_cpu = gc_end_cpu;
+
+ // Compute the new heap size only when we have samples to average over.
+ if let Some(gc_cpu) = state.mean_gc_cpu() {
+ // Drop the lock before doing the (relatively cheap) math and
+ // atomic update; nothing below needs the state.
+ drop(state);
+
+ let overhead_error = gc_cpu - cfg.target_gc_cpu; // Eq. (2)
+ let sigmoid_error = sigmoid(overhead_error); // Eq. (3)
+ let adjustment_factor = sigmoid_error + 0.5; // Eq. (4), range (0.5, 1.5)
+
+ let current = self.target_heap_pages.load(Ordering::Relaxed);
+ let suggested = ((current as f64) * adjustment_factor) as usize; // Eq. (5)
+
+ // Clamp:
+ // - upper bound: configured max
+ // - lower bound: max(1.1 * used, min) — 10% headroom above current
+ // live memory, so we never request a heap so small that GC is
+ // triggered immediately on return from this one.
+ let used = mmtk.get_plan().get_used_pages();
+ let floor = ((used as f64) * 1.1).ceil() as usize;
+ let lower = floor.max(cfg.min_heap_pages).min(cfg.max_heap_pages);
+ let upper = cfg.max_heap_pages;
+ let new_target = suggested.clamp(lower, upper);
+
+ self.target_heap_pages.store(new_target, Ordering::Relaxed);
+
+ info!(
+ "CpuHeapTrigger: gc_cpu={:.4} target={:.4} factor={:.4} \
+ pages {} -> {} (used={}, clamp=[{}, {}])",
+ gc_cpu,
+ cfg.target_gc_cpu,
+ adjustment_factor,
+ current,
+ new_target,
+ used,
+ lower,
+ upper
+ );
+ }
+ }
+
+ fn is_heap_full(&self, plan: &dyn Plan<VM = Ruby>) -> bool {
+ plan.get_reserved_pages() > self.target_heap_pages.load(Ordering::Relaxed)
+ }
+
+ fn get_current_heap_size_in_pages(&self) -> usize {
+ self.target_heap_pages.load(Ordering::Relaxed)
+ }
+
+ fn get_max_heap_size_in_pages(&self) -> usize {
+ Self::get_config().max_heap_pages
+ }
+
+ fn can_heap_size_grow(&self) -> bool {
+ self.target_heap_pages.load(Ordering::Relaxed) < Self::get_config().max_heap_pages
+ }
+}
+
+impl CpuHeapTrigger {
+ fn get_config<'b>() -> &'b CpuHeapTriggerConfig {
+ CPU_HEAP_TRIGGER_CONFIG
+ .get()
+ .expect("Attempt to use CPU_HEAP_TRIGGER_CONFIG before it is initialized")
+ }
+}
+
+/// Standard logistic sigmoid. Returns 0.5 when x == 0, asymptotes to 0 and 1.
+fn sigmoid(x: f64) -> f64 {
+ 1.0 / (1.0 + (-x).exp())
+}
+
+/// Reads the process-wide CPU time as a floating-point number of seconds,
+/// summed across all threads of this process. Returns `None` if the clock
+/// query fails (which should be essentially impossible on supported
+/// platforms).
+fn process_cpu_time_seconds() -> Option<f64> {
+ let mut ts = libc::timespec {
+ tv_sec: 0,
+ tv_nsec: 0,
+ };
+ // SAFETY: `clock_gettime` writes exactly `sizeof(timespec)` bytes to the
+ // pointer we pass, which is a valid local stack allocation.
+ let rc = unsafe { libc::clock_gettime(libc::CLOCK_PROCESS_CPUTIME_ID, &mut ts) };
+ if rc != 0 {
+ return None;
+ }
+ Some((ts.tv_sec as f64) + (ts.tv_nsec as f64) / 1_000_000_000.0)
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn sigmoid_is_well_behaved() {
+ assert!((sigmoid(0.0) - 0.5).abs() < 1e-12);
+ assert!(sigmoid(-100.0) < 1e-9);
+ assert!(sigmoid(100.0) > 1.0 - 1e-9);
+ // Monotonic.
+ assert!(sigmoid(-1.0) < sigmoid(0.0));
+ assert!(sigmoid(0.0) < sigmoid(1.0));
+ }
+
+ #[test]
+ fn adjustment_factor_is_within_paper_bounds() {
+ // Eq. (4): adjustment_factor = sigmoid(e) + 0.5 must lie in (0.5, 1.5).
+ for e in [-10.0_f64, -1.0, 0.0, 1.0, 10.0] {
+ let f = sigmoid(e) + 0.5;
+ assert!(f > 0.5 && f < 1.5, "factor {f} out of range for e={e}");
+ }
+ }
+
+ #[test]
+ fn mean_gc_cpu_is_total_weighted() {
+ let mut state = CpuHeapTriggerState::new();
+ state.push_sample(
+ GcSample {
+ gc_seconds: 1.0,
+ app_cpu_seconds: 10.0,
+ },
+ 3,
+ );
+ state.push_sample(
+ GcSample {
+ gc_seconds: 3.0,
+ app_cpu_seconds: 10.0,
+ },
+ 3,
+ );
+ // (1 + 3) / (10 + 10) = 0.2
+ assert!((state.mean_gc_cpu().unwrap() - 0.2).abs() < 1e-12);
+ }
+
+ #[test]
+ fn window_drops_oldest() {
+ let mut state = CpuHeapTriggerState::new();
+ for i in 0..5 {
+ state.push_sample(
+ GcSample {
+ gc_seconds: i as f64,
+ app_cpu_seconds: 1.0,
+ },
+ 3,
+ );
+ }
+ assert_eq!(state.samples.len(), 3);
+ // After pushing 0,1,2,3,4 with window 3, we should have [2,3,4].
+ assert_eq!(state.samples[0].gc_seconds, 2.0);
+ assert_eq!(state.samples[2].gc_seconds, 4.0);
+ }
+
+ #[test]
+ fn no_sample_without_prior_gc() {
+ // First GC cycle cannot produce a sample (no previous end time). The
+ // push happens only when last_gc_end_cpu is Some.
+ let state = CpuHeapTriggerState::new();
+ assert!(state.mean_gc_cpu().is_none());
+ }
+}
diff --git a/gc/mmtk/src/heap/mod.rs b/gc/mmtk/src/heap/mod.rs
new file mode 100644
index 0000000000..05a35efb23
--- /dev/null
+++ b/gc/mmtk/src/heap/mod.rs
@@ -0,0 +1,9 @@
+mod cpu_heap_trigger;
+mod ruby_heap_trigger;
+
+pub use cpu_heap_trigger::CpuHeapTrigger;
+pub use cpu_heap_trigger::CpuHeapTriggerConfig;
+pub use cpu_heap_trigger::CPU_HEAP_TRIGGER_CONFIG;
+pub use ruby_heap_trigger::RubyHeapTrigger;
+pub use ruby_heap_trigger::RubyHeapTriggerConfig;
+pub use ruby_heap_trigger::RUBY_HEAP_TRIGGER_CONFIG;
diff --git a/gc/mmtk/src/heap/ruby_heap_trigger.rs b/gc/mmtk/src/heap/ruby_heap_trigger.rs
new file mode 100644
index 0000000000..fe1130043d
--- /dev/null
+++ b/gc/mmtk/src/heap/ruby_heap_trigger.rs
@@ -0,0 +1,105 @@
+use std::sync::atomic::AtomicUsize;
+use std::sync::atomic::Ordering;
+
+use mmtk::util::heap::GCTriggerPolicy;
+use mmtk::util::heap::SpaceStats;
+use mmtk::Plan;
+use mmtk::MMTK;
+use once_cell::sync::OnceCell;
+
+use crate::Ruby;
+
+pub static RUBY_HEAP_TRIGGER_CONFIG: OnceCell<RubyHeapTriggerConfig> = OnceCell::new();
+
+pub struct RubyHeapTriggerConfig {
+ /// Min heap size
+ pub min_heap_pages: usize,
+ /// Max heap size
+ pub max_heap_pages: usize,
+ /// Minimum ratio of empty space after a GC before the heap will grow
+ pub heap_pages_min_ratio: f64,
+ /// Ratio the heap will grow by
+ pub heap_pages_goal_ratio: f64,
+ /// Maximum ratio of empty space after a GC before the heap will shrink
+ pub heap_pages_max_ratio: f64,
+}
+
+pub struct RubyHeapTrigger {
+ /// Target number of heap pages
+ target_heap_pages: AtomicUsize,
+}
+
+impl GCTriggerPolicy<Ruby> for RubyHeapTrigger {
+ fn is_gc_required(
+ &self,
+ space_full: bool,
+ space: Option<SpaceStats<Ruby>>,
+ plan: &dyn Plan<VM = Ruby>,
+ ) -> bool {
+ // Let the plan decide
+ plan.collection_required(space_full, space)
+ }
+
+ fn on_gc_end(&self, mmtk: &'static MMTK<Ruby>) {
+ if let Some(plan) = mmtk.get_plan().generational() {
+ if plan.is_current_gc_nursery() {
+ // Nursery GC
+ } else {
+ // Full GC
+ }
+
+ panic!("TODO: support for generational GC not implemented")
+ } else {
+ let used_pages = mmtk.get_plan().get_used_pages();
+
+ let target_min =
+ (used_pages as f64 * (1.0 + Self::get_config().heap_pages_min_ratio)) as usize;
+ let target_max =
+ (used_pages as f64 * (1.0 + Self::get_config().heap_pages_max_ratio)) as usize;
+ let new_target =
+ (((used_pages as f64) * (1.0 + Self::get_config().heap_pages_goal_ratio)) as usize)
+ .clamp(
+ Self::get_config().min_heap_pages,
+ Self::get_config().max_heap_pages,
+ );
+
+ if used_pages < target_min || used_pages > target_max {
+ self.target_heap_pages.store(new_target, Ordering::Relaxed);
+ }
+ }
+ }
+
+ fn is_heap_full(&self, plan: &dyn Plan<VM = Ruby>) -> bool {
+ plan.get_reserved_pages() > self.target_heap_pages.load(Ordering::Relaxed)
+ }
+
+ fn get_current_heap_size_in_pages(&self) -> usize {
+ self.target_heap_pages.load(Ordering::Relaxed)
+ }
+
+ fn get_max_heap_size_in_pages(&self) -> usize {
+ Self::get_config().max_heap_pages
+ }
+
+ fn can_heap_size_grow(&self) -> bool {
+ self.target_heap_pages.load(Ordering::Relaxed) < Self::get_config().max_heap_pages
+ }
+}
+
+impl Default for RubyHeapTrigger {
+ fn default() -> Self {
+ let min_heap_pages = Self::get_config().min_heap_pages;
+
+ Self {
+ target_heap_pages: AtomicUsize::new(min_heap_pages),
+ }
+ }
+}
+
+impl RubyHeapTrigger {
+ fn get_config<'b>() -> &'b RubyHeapTriggerConfig {
+ RUBY_HEAP_TRIGGER_CONFIG
+ .get()
+ .expect("Attempt to use RUBY_HEAP_TRIGGER_CONFIG before it is initialized")
+ }
+}
diff --git a/gc/mmtk/src/lib.rs b/gc/mmtk/src/lib.rs
index d16a5bf42f..52dc782051 100644
--- a/gc/mmtk/src/lib.rs
+++ b/gc/mmtk/src/lib.rs
@@ -14,8 +14,11 @@ use std::sync::Mutex;
use std::thread::ThreadId;
use abi::RubyUpcalls;
-use binding::{RubyBinding, RubyBindingFast, RubyConfiguration};
-use mmtk::vm::slot::{SimpleSlot, UnimplementedMemorySlice};
+use binding::RubyBinding;
+use binding::RubyBindingFast;
+use binding::RubyConfiguration;
+use mmtk::vm::slot::SimpleSlot;
+use mmtk::vm::slot::UnimplementedMemorySlice;
use mmtk::vm::VMBinding;
use mmtk::MMTK;
use once_cell::sync::OnceCell;
@@ -25,7 +28,9 @@ pub mod active_plan;
pub mod api;
pub mod binding;
pub mod collection;
+pub mod heap;
pub mod object_model;
+pub mod pinning_registry;
pub mod reference_glue;
pub mod scanning;
pub mod utils;
@@ -55,6 +60,11 @@ impl VMBinding for Ruby {
type VMMemorySlice = RubyMemorySlice;
}
+/// The callback for mutator thread panic handler (which calls rb_bug to output
+/// debugging information such as the Ruby backtrace and memory maps).
+/// This is set before BINDING is set because mmtk_init could panic.
+pub static MUTATOR_THREAD_PANIC_HANDLER: OnceCell<extern "C" fn()> = OnceCell::new();
+
/// The singleton object for the Ruby binding itself.
pub static BINDING: OnceCell<RubyBinding> = OnceCell::new();
@@ -116,8 +126,6 @@ fn handle_gc_thread_panic(panic_info: &PanicHookInfo) {
eprintln!("Unknown backtrace status: {s:?}");
}
}
-
- std::process::abort();
}
pub(crate) fn set_panic_hook() {
@@ -130,8 +138,13 @@ pub(crate) fn set_panic_hook() {
std::panic::set_hook(Box::new(move |panic_info| {
if is_gc_thread(std::thread::current().id()) {
handle_gc_thread_panic(panic_info);
+
+ (crate::binding().upcalls().gc_thread_panic_handler)();
} else {
old_hook(panic_info);
+ (crate::MUTATOR_THREAD_PANIC_HANDLER
+ .get()
+ .expect("MUTATOR_THREAD_PANIC_HANDLER is not set"))();
}
}));
}
diff --git a/gc/mmtk/src/object_model.rs b/gc/mmtk/src/object_model.rs
index 93b6063a05..d673ca11a0 100644
--- a/gc/mmtk/src/object_model.rs
+++ b/gc/mmtk/src/object_model.rs
@@ -1,8 +1,15 @@
-use crate::abi::{RubyObjectAccess, OBJREF_OFFSET};
-use crate::{abi, Ruby};
+use std::ptr::copy_nonoverlapping;
+
+use crate::abi;
+use crate::abi::RubyObjectAccess;
+use crate::abi::MIN_OBJ_ALIGN;
+use crate::abi::OBJREF_OFFSET;
+use crate::Ruby;
use mmtk::util::constants::BITS_IN_BYTE;
-use mmtk::util::copy::{CopySemantics, GCWorkerCopyContext};
-use mmtk::util::{Address, ObjectReference};
+use mmtk::util::copy::CopySemantics;
+use mmtk::util::copy::GCWorkerCopyContext;
+use mmtk::util::Address;
+use mmtk::util::ObjectReference;
use mmtk::vm::*;
pub struct VMObjectModel {}
@@ -36,11 +43,39 @@ impl ObjectModel<Ruby> for VMObjectModel {
const NEED_VO_BITS_DURING_TRACING: bool = true;
fn copy(
- _from: ObjectReference,
- _semantics: CopySemantics,
- _copy_context: &mut GCWorkerCopyContext<Ruby>,
+ from: ObjectReference,
+ semantics: CopySemantics,
+ copy_context: &mut GCWorkerCopyContext<Ruby>,
) -> ObjectReference {
- unimplemented!("Copying GC not currently supported")
+ let from_acc = RubyObjectAccess::from_objref(from);
+ let from_start = from_acc.obj_start();
+ let object_size = from_acc.object_size();
+ let to_start = copy_context.alloc_copy(from, object_size, MIN_OBJ_ALIGN, 0, semantics);
+ debug_assert!(!to_start.is_zero());
+ let to_payload = to_start.add(OBJREF_OFFSET);
+ unsafe {
+ copy_nonoverlapping::<u8>(from_start.to_ptr(), to_start.to_mut_ptr(), object_size);
+ }
+ let to_obj = unsafe { ObjectReference::from_raw_address_unchecked(to_payload) };
+ copy_context.post_copy(to_obj, object_size, semantics);
+ trace!("Copied object from {} to {}", from, to_obj);
+
+ (crate::binding().upcalls().move_obj_during_marking)(from, to_obj);
+
+ #[cfg(feature = "clear_old_copy")]
+ {
+ trace!(
+ "Clearing old copy {} ({}-{})",
+ from,
+ from_start,
+ from_start + object_size
+ );
+ // For debug purpose, we clear the old copy so that if the Ruby VM reads from the old
+ // copy again, it will likely result in an error.
+ unsafe { std::ptr::write_bytes::<u8>(from_start.to_mut_ptr(), 0, object_size) }
+ }
+
+ to_obj
}
fn copy_to(_from: ObjectReference, _to: ObjectReference, _region: Address) -> Address {
diff --git a/gc/mmtk/src/pinning_registry.rs b/gc/mmtk/src/pinning_registry.rs
new file mode 100644
index 0000000000..b498b508f1
--- /dev/null
+++ b/gc/mmtk/src/pinning_registry.rs
@@ -0,0 +1,187 @@
+use std::sync::Mutex;
+
+use mmtk::memory_manager;
+use mmtk::scheduler::GCWork;
+use mmtk::scheduler::GCWorker;
+use mmtk::scheduler::WorkBucketStage;
+use mmtk::util::ObjectReference;
+use mmtk::util::VMWorkerThread;
+use mmtk::MMTK;
+
+use crate::abi::GCThreadTLS;
+use crate::upcalls;
+use crate::Ruby;
+
+pub struct PinningRegistry {
+ pinning_objs: Mutex<Vec<ObjectReference>>,
+ pinned_objs: Mutex<Vec<ObjectReference>>,
+}
+
+impl PinningRegistry {
+ pub fn new() -> Self {
+ Self {
+ pinning_objs: Default::default(),
+ pinned_objs: Default::default(),
+ }
+ }
+
+ pub fn register(&self, object: ObjectReference) {
+ let mut pinning_objs = self.pinning_objs.lock().unwrap();
+ pinning_objs.push(object);
+ }
+
+ pub fn pin_children(&self, tls: VMWorkerThread) {
+ if !crate::mmtk().get_plan().current_gc_may_move_object() {
+ log::debug!("The current GC is non-moving, skipping pinning children.");
+ return;
+ }
+
+ let gc_tls = unsafe { GCThreadTLS::from_vwt_check(tls) };
+ let worker = gc_tls.worker();
+
+ let pinning_objs = self
+ .pinning_objs
+ .try_lock()
+ .expect("PinningRegistry should not have races during GC.");
+
+ let packet_size = 512;
+ let work_packets = pinning_objs
+ .chunks(packet_size)
+ .map(|chunk| {
+ Box::new(PinPinningChildren {
+ pinning_objs: chunk.to_vec(),
+ }) as _
+ })
+ .collect();
+
+ worker.scheduler().work_buckets[WorkBucketStage::Prepare].bulk_add(work_packets);
+ }
+
+ pub fn cleanup(&self, worker: &mut GCWorker<Ruby>) {
+ worker.scheduler().work_buckets[WorkBucketStage::VMRefClosure].add(RemoveDeadPinnings);
+ if crate::mmtk().get_plan().current_gc_may_move_object() {
+ let packet = {
+ let mut pinned_objs = self
+ .pinned_objs
+ .try_lock()
+ .expect("Unexpected contention on pinned_objs");
+ UnpinPinnedObjects {
+ objs: std::mem::take(&mut pinned_objs),
+ }
+ };
+
+ worker.scheduler().work_buckets[WorkBucketStage::VMRefClosure].add(packet);
+ } else {
+ debug!("The current GC is non-moving, skipping unpinning objects.");
+ debug_assert_eq!(
+ {
+ let pinned_objs = self
+ .pinned_objs
+ .try_lock()
+ .expect("Unexpected contention on pinned_objs");
+ pinned_objs.len()
+ },
+ 0
+ );
+ }
+ }
+}
+
+impl Default for PinningRegistry {
+ fn default() -> Self {
+ Self::new()
+ }
+}
+
+struct PinPinningChildren {
+ pinning_objs: Vec<ObjectReference>,
+}
+
+impl GCWork<Ruby> for PinPinningChildren {
+ fn do_work(&mut self, worker: &mut GCWorker<Ruby>, _mmtk: &'static MMTK<Ruby>) {
+ let gc_tls = unsafe { GCThreadTLS::from_vwt_check(worker.tls) };
+ let mut pinned_objs = vec![];
+ let mut newly_pinned_objs = vec![];
+
+ let visit_object = |_worker, target_object: ObjectReference, pin| {
+ log::trace!(
+ " -> {} {}",
+ if pin { "(pin)" } else { " " },
+ target_object
+ );
+ if pin {
+ debug_assert!(
+ target_object.get_forwarded_object().is_none(),
+ "Trying to pin {target_object} but has been moved"
+ );
+
+ pinned_objs.push(target_object);
+ }
+ target_object
+ };
+
+ gc_tls
+ .object_closure
+ .set_temporarily_and_run_code(visit_object, || {
+ for obj in self.pinning_objs.iter().cloned() {
+ log::trace!(" Pinning: {}", obj);
+ (upcalls().call_gc_mark_children)(obj);
+ }
+ });
+
+ for target_object in pinned_objs {
+ if memory_manager::pin_object(target_object) {
+ newly_pinned_objs.push(target_object);
+ }
+ }
+
+ let mut pinned_objs = crate::binding()
+ .pinning_registry
+ .pinned_objs
+ .lock()
+ .unwrap();
+ pinned_objs.append(&mut newly_pinned_objs);
+ }
+}
+
+struct RemoveDeadPinnings;
+
+impl GCWork<Ruby> for RemoveDeadPinnings {
+ fn do_work(&mut self, _worker: &mut GCWorker<Ruby>, _mmtk: &'static MMTK<Ruby>) {
+ log::debug!("Removing dead Pinnings...");
+
+ let registry = &crate::binding().pinning_registry;
+ {
+ let mut pinning_objs = registry
+ .pinning_objs
+ .try_lock()
+ .expect("PinningRegistry should not have races during GC.");
+
+ pinning_objs.retain_mut(|obj| {
+ if obj.is_live() {
+ let new_obj = obj.get_forwarded_object().unwrap_or(*obj);
+ *obj = new_obj;
+ true
+ } else {
+ log::trace!(" Dead Pinning removed: {}", *obj);
+ false
+ }
+ });
+ }
+ }
+}
+
+struct UnpinPinnedObjects {
+ objs: Vec<ObjectReference>,
+}
+
+impl GCWork<Ruby> for UnpinPinnedObjects {
+ fn do_work(&mut self, _worker: &mut GCWorker<Ruby>, _mmtk: &'static MMTK<Ruby>) {
+ log::debug!("Unpinning pinned objects...");
+
+ for obj in self.objs.iter() {
+ let unpinned = memory_manager::unpin_object(*obj);
+ debug_assert!(unpinned);
+ }
+ }
+}
diff --git a/gc/mmtk/src/scanning.rs b/gc/mmtk/src/scanning.rs
index af43581377..355a2e7759 100644
--- a/gc/mmtk/src/scanning.rs
+++ b/gc/mmtk/src/scanning.rs
@@ -1,10 +1,19 @@
use crate::abi::GCThreadTLS;
+use crate::upcalls;
use crate::utils::ChunkedVecCollector;
-use crate::{upcalls, Ruby, RubySlot};
-use mmtk::scheduler::{GCWork, GCWorker, WorkBucketStage};
-use mmtk::util::{ObjectReference, VMWorkerThread};
-use mmtk::vm::{ObjectTracer, RootsWorkFactory, Scanning, SlotVisitor};
+use crate::Ruby;
+use crate::RubySlot;
+use mmtk::memory_manager;
+use mmtk::scheduler::GCWork;
+use mmtk::scheduler::GCWorker;
+use mmtk::scheduler::WorkBucketStage;
+use mmtk::util::ObjectReference;
+use mmtk::util::VMWorkerThread;
+use mmtk::vm::ObjectTracer;
+use mmtk::vm::RootsWorkFactory;
+use mmtk::vm::Scanning;
+use mmtk::vm::SlotVisitor;
use mmtk::Mutator;
pub struct VMScanning {}
@@ -45,6 +54,19 @@ impl Scanning<Ruby> for VMScanning {
mmtk::memory_manager::is_mmtk_object(target_object.to_raw_address()).is_some(),
"Destination is not an MMTk object. Src: {object} dst: {target_object}"
);
+
+ debug_assert!(
+ // If we are in a moving GC, all objects should be pinned by PinningRegistry.
+ // If it is requested that target_object be pinned but it is not pinned, then
+ // it is a bug because it could be moved.
+ if crate::mmtk().get_plan().current_gc_may_move_object() && pin {
+ memory_manager::is_pinned(target_object)
+ } else {
+ true
+ },
+ "Object {object} is trying to pin {target_object}"
+ );
+
let forwarded_target = object_tracer.trace_object(target_object);
if forwarded_target != target_object {
trace!(" Forwarded target {target_object} -> {forwarded_target}");
@@ -54,7 +76,11 @@ impl Scanning<Ruby> for VMScanning {
gc_tls
.object_closure
.set_temporarily_and_run_code(visit_object, || {
- (upcalls().scan_object_ruby_style)(object);
+ (upcalls().call_gc_mark_children)(object);
+
+ if crate::mmtk().get_plan().current_gc_may_move_object() {
+ (upcalls().update_object_references)(object);
+ }
});
}
@@ -131,6 +157,7 @@ impl Scanning<Ruby> for VMScanning {
crate::binding()
.weak_proc
.process_weak_stuff(worker, tracer_context);
+ crate::binding().pinning_registry.cleanup(worker);
false
}
@@ -248,7 +275,11 @@ impl<F: RootsWorkFactory<RubySlot>> GCWork<Ruby> for ScanWbUnprotectedRoots<F> {
for object in self.objects.iter().copied() {
if object.is_reachable() {
debug!("[wb_unprot_roots] Visiting WB-unprotected object (parent): {object}");
- (upcalls().scan_object_ruby_style)(object);
+ (upcalls().call_gc_mark_children)(object);
+
+ if crate::mmtk().get_plan().current_gc_may_move_object() {
+ (upcalls().update_object_references)(object);
+ }
} else {
debug!(
"[wb_unprot_roots] Skipping young WB-unprotected object (parent): {object}"
diff --git a/gc/mmtk/src/utils.rs b/gc/mmtk/src/utils.rs
index 71a7ae8dd2..d1979eaf58 100644
--- a/gc/mmtk/src/utils.rs
+++ b/gc/mmtk/src/utils.rs
@@ -1,7 +1,10 @@
-use std::sync::atomic::{AtomicUsize, Ordering};
+use std::sync::atomic::AtomicUsize;
+use std::sync::atomic::Ordering;
use atomic_refcell::AtomicRefCell;
-use mmtk::scheduler::{GCWork, GCWorker, WorkBucketStage};
+use mmtk::scheduler::GCWork;
+use mmtk::scheduler::GCWorker;
+use mmtk::scheduler::WorkBucketStage;
use crate::Ruby;
use sysinfo::System;
diff --git a/gc/mmtk/src/weak_proc.rs b/gc/mmtk/src/weak_proc.rs
index 68d3dd3273..d38dbe04a4 100644
--- a/gc/mmtk/src/weak_proc.rs
+++ b/gc/mmtk/src/weak_proc.rs
@@ -1,19 +1,23 @@
use std::sync::Mutex;
-use mmtk::{
- scheduler::{GCWork, GCWorker, WorkBucketStage},
- util::ObjectReference,
- vm::ObjectTracerContext,
-};
+use mmtk::scheduler::GCWork;
+use mmtk::scheduler::GCWorker;
+use mmtk::scheduler::WorkBucketStage;
+use mmtk::util::ObjectReference;
+use mmtk::vm::ObjectTracerContext;
-use crate::{abi::GCThreadTLS, upcalls, Ruby};
+use crate::abi::GCThreadTLS;
+use crate::upcalls;
+use crate::Ruby;
pub struct WeakProcessor {
+ non_parallel_obj_free_candidates: Mutex<Vec<ObjectReference>>,
+ parallel_obj_free_candidates: Vec<Mutex<Vec<ObjectReference>>>,
+
/// Objects that needs `obj_free` called when dying.
/// If it is a bottleneck, replace it with a lock-free data structure,
/// or add candidates in batch.
- obj_free_candidates: Mutex<Vec<ObjectReference>>,
- weak_references: Mutex<Vec<&'static mut ObjectReference>>,
+ weak_references: Mutex<Vec<ObjectReference>>,
}
impl Default for WeakProcessor {
@@ -25,47 +29,74 @@ impl Default for WeakProcessor {
impl WeakProcessor {
pub fn new() -> Self {
Self {
- obj_free_candidates: Mutex::new(Vec::new()),
+ non_parallel_obj_free_candidates: Mutex::new(Vec::new()),
+ parallel_obj_free_candidates: vec![Mutex::new(Vec::new())],
weak_references: Mutex::new(Vec::new()),
}
}
- /// Add an object as a candidate for `obj_free`.
- ///
- /// Multiple mutators can call it concurrently, so it has `&self`.
- pub fn add_obj_free_candidate(&self, object: ObjectReference) {
- let mut obj_free_candidates = self.obj_free_candidates.lock().unwrap();
- obj_free_candidates.push(object);
+ pub fn init_parallel_obj_free_candidates(&mut self, num_workers: usize) {
+ debug_assert_eq!(self.parallel_obj_free_candidates.len(), 1);
+
+ for _ in 1..num_workers {
+ self.parallel_obj_free_candidates
+ .push(Mutex::new(Vec::new()));
+ }
}
- /// Add many objects as candidates for `obj_free`.
+ /// Add a batch of objects as candidates for `obj_free`.
///
- /// Multiple mutators can call it concurrently, so it has `&self`.
- pub fn add_obj_free_candidates(&self, objects: &[ObjectReference]) {
- let mut obj_free_candidates = self.obj_free_candidates.lock().unwrap();
- for object in objects.iter().copied() {
- obj_free_candidates.push(object);
+ /// Amortizes mutex acquisition over the entire batch. Called when a
+ /// mutator's local buffer is flushed (buffer full or stop-the-world).
+ pub fn add_obj_free_candidates_batch(
+ &self,
+ objects: &[ObjectReference],
+ can_parallel_free: bool,
+ ) {
+ if objects.is_empty() {
+ return;
+ }
+
+ if can_parallel_free {
+ let num_buckets = self.parallel_obj_free_candidates.len();
+ for idx in 0..num_buckets {
+ let mut bucket = self.parallel_obj_free_candidates[idx].lock().unwrap();
+ for (i, &obj) in objects.iter().enumerate() {
+ if i % num_buckets == idx {
+ bucket.push(obj);
+ }
+ }
+ }
+ } else {
+ self.non_parallel_obj_free_candidates
+ .lock()
+ .unwrap()
+ .extend_from_slice(objects);
}
}
pub fn get_all_obj_free_candidates(&self) -> Vec<ObjectReference> {
- let mut obj_free_candidates = self.obj_free_candidates.lock().unwrap();
- std::mem::take(obj_free_candidates.as_mut())
+ // let mut obj_free_candidates = self.obj_free_candidates.lock().unwrap();
+ let mut all_obj_free_candidates = self
+ .non_parallel_obj_free_candidates
+ .lock()
+ .unwrap()
+ .to_vec();
+
+ for candidates_mutex in &self.parallel_obj_free_candidates {
+ all_obj_free_candidates.extend(candidates_mutex.lock().unwrap().to_vec());
+ }
+
+ std::mem::take(all_obj_free_candidates.as_mut())
}
- pub fn add_weak_reference(&self, ptr: &'static mut ObjectReference) {
+ pub fn add_weak_reference(&self, object: ObjectReference) {
let mut weak_references = self.weak_references.lock().unwrap();
- weak_references.push(ptr);
+ weak_references.push(object);
}
- pub fn remove_weak_reference(&self, ptr: &ObjectReference) {
- let mut weak_references = self.weak_references.lock().unwrap();
- for (i, curr_ptr) in weak_references.iter().enumerate() {
- if *curr_ptr == ptr {
- weak_references.swap_remove(i);
- break;
- }
- }
+ pub fn weak_references_count(&self) -> usize {
+ self.weak_references.lock().unwrap().len()
}
pub fn process_weak_stuff(
@@ -73,7 +104,18 @@ impl WeakProcessor {
worker: &mut GCWorker<Ruby>,
_tracer_context: impl ObjectTracerContext<Ruby>,
) {
- worker.add_work(WorkBucketStage::VMRefClosure, ProcessObjFreeCandidates);
+ worker.add_work(
+ WorkBucketStage::VMRefClosure,
+ ProcessNonParallelObjFreeCanadidates {},
+ );
+
+ for index in 0..self.parallel_obj_free_candidates.len() {
+ worker.add_work(
+ WorkBucketStage::VMRefClosure,
+ ProcessParallelObjFreeCandidates { index },
+ );
+ }
+
worker.add_work(WorkBucketStage::VMRefClosure, ProcessWeakReferences);
worker.add_work(WorkBucketStage::Prepare, UpdateFinalizerObjIdTables);
@@ -90,60 +132,105 @@ impl WeakProcessor {
}
}
-struct ProcessObjFreeCandidates;
+fn process_obj_free_candidates(obj_free_candidates: &mut Vec<ObjectReference>) {
+ // Process obj_free
+ let mut new_candidates = Vec::new();
+
+ for object in obj_free_candidates.iter().copied() {
+ if object.is_reachable() {
+ // Forward and add back to the candidate list.
+ let new_object = object.forward();
+ trace!("Forwarding obj_free candidate: {object} -> {new_object}");
+ new_candidates.push(new_object);
+ } else {
+ (upcalls().call_obj_free)(object);
+ }
+ }
+
+ *obj_free_candidates = new_candidates;
+}
-impl GCWork<Ruby> for ProcessObjFreeCandidates {
+struct ProcessParallelObjFreeCandidates {
+ index: usize,
+}
+
+impl GCWork<Ruby> for ProcessParallelObjFreeCandidates {
fn do_work(&mut self, _worker: &mut GCWorker<Ruby>, _mmtk: &'static mmtk::MMTK<Ruby>) {
- // If it blocks, it is a bug.
- let mut obj_free_candidates = crate::binding()
- .weak_proc
- .obj_free_candidates
+ let mut obj_free_candidates = crate::binding().weak_proc.parallel_obj_free_candidates
+ [self.index]
.try_lock()
- .expect("It's GC time. No mutators should hold this lock at this time.");
-
- let n_cands = obj_free_candidates.len();
+ .expect("Lock for parallel_obj_free_candidates should not be held");
- debug!("Total: {n_cands} candidates");
+ process_obj_free_candidates(&mut obj_free_candidates);
+ }
+}
- // Process obj_free
- let mut new_candidates = Vec::new();
+struct ProcessNonParallelObjFreeCanadidates;
- for object in obj_free_candidates.iter().copied() {
- if object.is_reachable() {
- // Forward and add back to the candidate list.
- let new_object = object.forward();
- trace!("Forwarding obj_free candidate: {object} -> {new_object}");
- new_candidates.push(new_object);
- } else {
- (upcalls().call_obj_free)(object);
- }
- }
+impl GCWork<Ruby> for ProcessNonParallelObjFreeCanadidates {
+ fn do_work(&mut self, _worker: &mut GCWorker<Ruby>, _mmtk: &'static mmtk::MMTK<Ruby>) {
+ let mut obj_free_candidates = crate::binding()
+ .weak_proc
+ .non_parallel_obj_free_candidates
+ .try_lock()
+ .expect("Lock for non_parallel_obj_free_candidates should not be held");
- *obj_free_candidates = new_candidates;
+ process_obj_free_candidates(&mut obj_free_candidates);
}
}
struct ProcessWeakReferences;
impl GCWork<Ruby> for ProcessWeakReferences {
- fn do_work(&mut self, _worker: &mut GCWorker<Ruby>, _mmtk: &'static mmtk::MMTK<Ruby>) {
+ fn do_work(&mut self, worker: &mut GCWorker<Ruby>, _mmtk: &'static mmtk::MMTK<Ruby>) {
+ if crate::mmtk().get_plan().current_gc_may_move_object() {
+ let gc_tls: &mut GCThreadTLS = unsafe { GCThreadTLS::from_vwt_check(worker.tls) };
+
+ let visit_object = |_worker, target_object: ObjectReference, _pin| {
+ debug_assert!(
+ mmtk::memory_manager::is_mmtk_object(target_object.to_raw_address()).is_some(),
+ "Destination is not an MMTk object"
+ );
+
+ target_object
+ .get_forwarded_object()
+ .unwrap_or(target_object)
+ };
+
+ gc_tls
+ .object_closure
+ .set_temporarily_and_run_code(visit_object, || {
+ self.process_weak_references(true);
+ })
+ } else {
+ self.process_weak_references(false);
+ }
+ }
+}
+
+impl ProcessWeakReferences {
+ fn process_weak_references(&mut self, moving_gc: bool) {
let mut weak_references = crate::binding()
.weak_proc
.weak_references
.try_lock()
.expect("Mutators should not be holding the lock.");
- for ptr_ptr in weak_references.iter_mut() {
- if (upcalls().special_const_p)(**ptr_ptr) {
- continue;
- }
+ weak_references.retain_mut(|object_ptr| {
+ let object = object_ptr.get_forwarded_object().unwrap_or(*object_ptr);
- if !(**ptr_ptr).is_reachable() {
- **ptr_ptr = crate::binding().weak_reference_dead_value;
+ if object != *object_ptr {
+ *object_ptr = object;
}
- }
- weak_references.clear();
+ if object.is_reachable() {
+ (upcalls().handle_weak_references)(object, moving_gc);
+
+ true
+ } else {
+ false
+ }
+ });
}
}
@@ -190,7 +277,10 @@ struct UpdateGlobalTables {
}
impl GlobalTableProcessingWork for UpdateGlobalTables {
fn process_table(&mut self) {
- (crate::upcalls().update_global_tables)(self.idx)
+ (crate::upcalls().update_global_tables)(
+ self.idx,
+ crate::mmtk().get_plan().current_gc_may_move_object(),
+ )
}
}
impl GCWork<Ruby> for UpdateGlobalTables {
diff --git a/gc/wbcheck/extconf.rb b/gc/wbcheck/extconf.rb
new file mode 100644
index 0000000000..18b32d820d
--- /dev/null
+++ b/gc/wbcheck/extconf.rb
@@ -0,0 +1,3 @@
+require_relative '../extconf_base'
+
+create_gc_makefile("wbcheck")
diff --git a/gc/wbcheck/wbcheck.c b/gc/wbcheck/wbcheck.c
new file mode 100644
index 0000000000..a7d4cd6ccf
--- /dev/null
+++ b/gc/wbcheck/wbcheck.c
@@ -0,0 +1,1936 @@
+#include "internal.h"
+#include "ruby/ruby.h"
+#include "ruby/assert.h"
+#include "ruby/atomic.h"
+#include "ruby/debug.h"
+#include "ruby/internal/core/rbasic.h"
+#include "ruby/st.h"
+#include "internal/object.h"
+#include "internal/array.h"
+#include "internal/class.h"
+
+#include "ruby/thread.h"
+#include "gc/gc.h"
+#include "gc/gc_impl.h"
+
+#include <stdbool.h>
+#include <stdarg.h>
+
+// Debug output control
+static bool wbcheck_debug_enabled = false;
+
+// Verification after write barrier control
+static bool wbcheck_verify_after_wb_enabled = false;
+
+// Useless write barrier warning control
+static bool wbcheck_warn_useless_wb_enabled = false;
+
+static void
+wbcheck_debug(const char *format, ...)
+{
+ if (!wbcheck_debug_enabled) return;
+
+ va_list args;
+ va_start(args, format);
+ vfprintf(stderr, format, args);
+ va_end(args);
+}
+
+#define WBCHECK_DEBUG(...) do { \
+ if (wbcheck_debug_enabled) { \
+ wbcheck_debug(__VA_ARGS__); \
+ } \
+} while (0)
+
+static void
+wbcheck_debug_obj_info_dump(VALUE obj)
+{
+ if (!wbcheck_debug_enabled) return;
+ char buff[0x100];
+ fprintf(stderr, "%s\n", rb_raw_obj_info(buff, sizeof(buff), obj));
+}
+
+// Forward declaration
+static void lock_and_maybe_gc(void *objspace_ptr);
+static void force_gc(void *objspace_ptr);
+
+// Configure wbcheck from environment variables
+static void
+wbcheck_configure_from_env(void)
+{
+ // Configure debug output based on environment variable
+ const char *debug_env = getenv("WBCHECK_DEBUG");
+ if (debug_env && (strcmp(debug_env, "1") == 0 || strcmp(debug_env, "true") == 0)) {
+ wbcheck_debug_enabled = true;
+ }
+
+ // Configure verification after write barrier based on environment variable
+ const char *verify_after_wb_env = getenv("WBCHECK_VERIFY_AFTER_WB");
+ if (verify_after_wb_env && (strcmp(verify_after_wb_env, "1") == 0 || strcmp(verify_after_wb_env, "true") == 0)) {
+ wbcheck_verify_after_wb_enabled = true;
+ }
+
+ // Configure useless write barrier warnings based on environment variable
+ const char *warn_useless_wb_env = getenv("WBCHECK_WARN_USELESS_WB");
+ if (warn_useless_wb_env && (strcmp(warn_useless_wb_env, "1") == 0 || strcmp(warn_useless_wb_env, "true") == 0)) {
+ wbcheck_warn_useless_wb_enabled = true;
+ }
+}
+
+// Define same heap sizes as the default GC
+static size_t heap_sizes[] = {
+ 32,
+ 40,
+ 48,
+ 56,
+ 64,
+ 72,
+ 80,
+ 96,
+ 128,
+ 160,
+ 256,
+ 512,
+ 640,
+ 768,
+ 1024,
+ 0
+};
+
+#define HEAP_COUNT ((int)(sizeof(heap_sizes) / sizeof(heap_sizes[0])) - 1)
+#define MAX_HEAP_SIZE (heap_sizes[(HEAP_COUNT) - 1])
+
+// Object states for verification tracking
+typedef enum {
+ WBCHECK_STATE_CLEAR, // Just allocated or writebarrier_remember, needs reference capture
+ WBCHECK_STATE_MARKED, // Has valid snapshot, ready for normal operation
+ WBCHECK_STATE_DIRTY // Has seen writebarrier since last snapshot, queued for verification
+} wbcheck_object_state_t;
+
+// Tri-color marking colors
+typedef enum {
+ WBCHECK_COLOR_WHITE, // Unmarked - will be swept
+ WBCHECK_COLOR_GRAY, // Marked but children not processed
+ WBCHECK_COLOR_BLACK // Marked and children processed
+} wbcheck_color_t;
+
+// GC phases
+typedef enum {
+ WBCHECK_PHASE_MUTATOR, // Normal execution
+ WBCHECK_PHASE_SNAPSHOT, // Collecting references for verification
+ WBCHECK_PHASE_FULL_GC // Marking objects during full GC
+} wbcheck_phase_t;
+
+// List of objects
+typedef struct {
+ VALUE *items;
+ size_t count;
+ size_t capacity;
+} wbcheck_object_list_t;
+
+// Helper functions for object list
+static wbcheck_object_list_t *
+wbcheck_object_list_init_with_capacity(size_t capacity)
+{
+ wbcheck_object_list_t *list = calloc(1, sizeof(wbcheck_object_list_t));
+ if (!list) rb_bug("wbcheck: failed to allocate object list structure");
+
+ if (capacity < 4) capacity = 4;
+ list->items = malloc(capacity * sizeof(VALUE));
+ if (!list->items) rb_bug("wbcheck: failed to allocate object list array");
+ list->capacity = capacity;
+ list->count = 0;
+ return list;
+}
+
+static wbcheck_object_list_t *
+wbcheck_object_list_init(void)
+{
+ return wbcheck_object_list_init_with_capacity(4);
+}
+
+static void
+wbcheck_object_list_append(wbcheck_object_list_t *list, VALUE obj)
+{
+ if (list->count >= list->capacity) {
+ size_t new_capacity = list->capacity == 0 ? 4 : list->capacity * 2;
+ VALUE *new_items = realloc(list->items, new_capacity * sizeof(VALUE));
+ if (!new_items) rb_bug("wbcheck: failed to reallocate object list array");
+ list->items = new_items;
+ list->capacity = new_capacity;
+ }
+ list->items[list->count++] = obj;
+}
+
+static void
+wbcheck_object_list_free(wbcheck_object_list_t *list)
+{
+ if (!list) return;
+ if (list->items) {
+ free(list->items);
+ }
+ free(list);
+}
+
+static void
+wbcheck_object_list_debug_print(wbcheck_object_list_t *list)
+{
+ if (!wbcheck_debug_enabled) return;
+ for (size_t i = 0; i < list->count; i++) {
+ char buff[0x100];
+ fprintf(stderr, "-> %s\n", rb_raw_obj_info(buff, sizeof(buff), list->items[i]));
+ }
+}
+
+static bool
+wbcheck_object_list_contains(wbcheck_object_list_t *list, VALUE obj)
+{
+ for (size_t i = 0; i < list->count; i++) {
+ if (list->items[i] == obj) {
+ return true;
+ }
+ }
+ return false;
+}
+
+// Information tracked for each object
+typedef struct {
+ size_t alloc_size; // Allocated size (static)
+ bool wb_protected; // Write barrier protection status (static)
+ VALUE finalizers; // Ruby Array of finalizers like [finalizer1, finalizer2, ...]
+ wbcheck_object_list_t *gc_mark_snapshot; // Snapshot of references from last GC mark
+ wbcheck_object_list_t *mark_maybe_snapshot; // Conservative refs reported via mark_maybe; needed for liveness, not verifiable
+ wbcheck_object_list_t *writebarrier_children; // References added via write barriers since last snapshot
+ wbcheck_object_state_t state; // Current state in verification lifecycle
+ wbcheck_color_t color; // Tri-color marking color
+} rb_wbcheck_object_info_t;
+
+// Finalizer job types
+struct wbcheck_final_job {
+ struct wbcheck_final_job *next;
+ enum {
+ WBCHECK_FINAL_JOB_DFREE,
+ WBCHECK_FINAL_JOB_FINALIZE,
+ } kind;
+ union {
+ struct {
+ void (*func)(void *);
+ void *data;
+ } dfree;
+ struct {
+ VALUE finalizer_array;
+ } finalize;
+ } as;
+};
+
+// wbcheck objspace structure to track all objects
+typedef struct {
+ st_table *object_table; // Hash table to track all allocated objects (VALUE -> rb_wbcheck_object_info_t*)
+ wbcheck_object_list_t *objects_to_capture; // Objects that need initial reference capture
+ wbcheck_object_list_t *objects_to_verify; // Objects that need verification after write barriers
+ wbcheck_object_list_t *current_refs; // Current list for collecting references during marking
+ wbcheck_object_list_t *current_maybe_refs; // Current list for collecting mark_maybe references during marking
+ wbcheck_object_list_t *mark_queue; // Queue of gray objects for tri-color marking
+ wbcheck_object_list_t *weak_references; // Objects holding weak references, found during marking
+ wbcheck_phase_t phase; // Current GC phase
+ bool gc_enabled; // Whether GC is allowed to run
+ bool gc_stress; // GC stress mode (run GC on every allocation)
+ size_t gc_threshold; // Trigger GC when object count reaches this
+ size_t missed_write_barrier_parents; // Number of parent objects with missed write barriers
+ size_t missed_write_barrier_children; // Total number of missed write barriers detected
+ size_t simulated_gc_count; // Simulated GC count incremented on each GC.start
+ bool measure_total_time; // Whether to accumulate :time in stats
+ struct wbcheck_final_job *finalizer_jobs; // Linked list of finalizer jobs
+ rb_nativethread_lock_t finalizer_lock; // Protects finalizer_jobs list
+ rb_postponed_job_handle_t finalizer_postponed_job; // Postponed job handle for finalizers
+} rb_wbcheck_objspace_t;
+
+// Global objspace pointer for accessing from obj_slot_size function
+static rb_wbcheck_objspace_t *wbcheck_global_objspace = NULL;
+
+// Forward declarations
+static void wbcheck_foreach_object(rb_wbcheck_objspace_t *objspace, int (*callback)(VALUE obj, rb_wbcheck_object_info_t *info, void *data), void *data);
+static int wbcheck_verify_all_references_callback(VALUE obj, rb_wbcheck_object_info_t *info, void *data);
+static int wbcheck_update_all_snapshots_callback(VALUE obj, rb_wbcheck_object_info_t *info, void *data);
+static void wbcheck_run_finalizers_for_object(VALUE obj, rb_wbcheck_object_info_t *info);
+static void gc_run_finalizers(void *data);
+static void make_final_job(rb_wbcheck_objspace_t *objspace, VALUE obj, VALUE finalizer_array);
+
+// Helper functions for object tracking
+static rb_wbcheck_object_info_t *
+wbcheck_get_object_info(VALUE obj)
+{
+ // Objspace must be initialized by this point
+ GC_ASSERT(wbcheck_global_objspace);
+
+ st_data_t value;
+ if (st_lookup(wbcheck_global_objspace->object_table, (st_data_t)obj, &value)) {
+ return (rb_wbcheck_object_info_t *)value;
+ }
+
+ fprintf(stderr, "wbcheck: object not found in tracking table\n");
+ char buff[0x100];
+ fprintf(stderr, "%s\n", rb_raw_obj_info(buff, sizeof(buff), obj));
+
+ // Force ASAN crash?
+ ((volatile VALUE *)obj)[0];
+
+ // Object not found in tracking table - this should never happen
+ rb_bug("wbcheck: object not found in tracking table");
+}
+
+static void
+wbcheck_report_error(void *objspace_ptr, VALUE parent_obj, wbcheck_object_list_t *current_refs, wbcheck_object_list_t *gc_mark_snapshot, wbcheck_object_list_t *writebarrier_children, wbcheck_object_list_t *missed_refs)
+{
+ rb_wbcheck_objspace_t *objspace = (rb_wbcheck_objspace_t *)objspace_ptr;
+
+ rb_wbcheck_object_info_t *parent_info = wbcheck_get_object_info(parent_obj);
+
+ size_t snapshot_count = gc_mark_snapshot ? gc_mark_snapshot->count : 0;
+ size_t wb_count = writebarrier_children ? writebarrier_children->count : 0;
+
+ fprintf(stderr, "WBCHECK ERROR: Missed write barrier detected!\n");
+ fprintf(stderr, " Parent object: %p (wb_protected: %s)\n",
+ (void *)parent_obj, parent_info->wb_protected ? "true" : "false");
+ char buff[0x100];
+ fprintf(stderr, " %s\n", rb_raw_obj_info(buff, sizeof(buff), parent_obj));
+ fprintf(stderr, " Reference counts - snapshot: %zu, writebarrier: %zu, current: %zu, missed: %zu\n",
+ snapshot_count, wb_count, current_refs->count, missed_refs->count);
+
+ for (size_t i = 0; i < missed_refs->count; i++) {
+ VALUE missed_ref = missed_refs->items[i];
+ char buff[0x100];
+ fprintf(stderr, " Missing reference to: %p\n %s\n", (void *)missed_ref, rb_raw_obj_info(buff, sizeof(buff), missed_ref));
+ }
+
+ fprintf(stderr, "\n");
+ objspace->missed_write_barrier_parents++;
+ objspace->missed_write_barrier_children += missed_refs->count;
+}
+
+static void
+wbcheck_compare_references(void *objspace_ptr, VALUE parent_obj, wbcheck_object_list_t *current_refs, wbcheck_object_list_t *gc_mark_snapshot, wbcheck_object_list_t *writebarrier_children)
+{
+ rb_wbcheck_objspace_t *objspace = (rb_wbcheck_objspace_t *)objspace_ptr;
+ (void)objspace;
+
+ size_t snapshot_count = gc_mark_snapshot ? gc_mark_snapshot->count : 0;
+ size_t wb_count = writebarrier_children ? writebarrier_children->count : 0;
+
+ WBCHECK_DEBUG("wbcheck: comparing references for object %p\n", (void *)parent_obj);
+ WBCHECK_DEBUG("wbcheck: current refs: %zu, snapshot refs: %zu, wb refs: %zu\n",
+ current_refs->count, snapshot_count, wb_count);
+
+ // Collect missed references (lazily allocated)
+ wbcheck_object_list_t *missed_refs = NULL;
+
+ // Use circular comparison for better performance when lists are mostly similar
+ size_t snapshot_idx = 0;
+
+ // Check each object in current_refs to see if it's in either stored list
+ for (size_t i = 0; i < current_refs->count; i++) {
+ VALUE current_ref = current_refs->items[i];
+
+ // Usually the lists are nearly identical. We take advantage of this by
+ // attempting to loop over both lists in sequence. When the next element
+ // of the snapshot doesn't match the next element of our current_refs,
+ // we'll loop around the list to try to find it and continue from that
+ // match, so any runs of identical items can be matched efficiently.
+ //
+ // Pathologically this is O(N**2), but is O(N * num_changes)
+ bool found_in_snapshot = false;
+ if (gc_mark_snapshot && snapshot_count > 0) {
+ size_t start_idx = snapshot_idx;
+ do {
+ if (gc_mark_snapshot->items[snapshot_idx] == current_ref) {
+ found_in_snapshot = true;
+ snapshot_idx++;
+ if (snapshot_idx >= snapshot_count) snapshot_idx = 0;
+ break;
+ }
+ snapshot_idx++;
+ if (snapshot_idx >= snapshot_count) snapshot_idx = 0;
+ } while (snapshot_idx != start_idx);
+ }
+
+ if (found_in_snapshot) {
+ continue;
+ }
+
+ // Built-in immortal classes can be assigned via RBASIC_SET_CLASS_RAW,
+ // which bypasses the write barrier. They're pinned as VM roots and
+ // can never be collected, so a missing WB to them is harmless.
+ if (RB_TYPE_P(current_ref, T_CLASS) && FL_TEST_RAW(current_ref, RCLASS_IS_ROOT)) {
+ continue;
+ }
+
+ // Self reference... Weird but okay I guess
+ if (current_ref == parent_obj) {
+ continue;
+ }
+
+
+ // Check if reference exists in writebarrier_children
+ if (writebarrier_children && wbcheck_object_list_contains(writebarrier_children, current_ref)) {
+ continue;
+ }
+
+ // If we get here, the reference wasn't found in either list
+ // Lazily allocate missed_refs list on first miss
+ if (!missed_refs) {
+ missed_refs = wbcheck_object_list_init();
+ }
+ wbcheck_object_list_append(missed_refs, current_ref);
+ }
+
+ // Report any errors found
+ if (missed_refs) {
+ wbcheck_report_error(objspace_ptr, parent_obj, current_refs, gc_mark_snapshot, writebarrier_children, missed_refs);
+ wbcheck_object_list_free(missed_refs);
+ }
+}
+
+static void
+wbcheck_register_object(void *objspace_ptr, VALUE obj, size_t alloc_size, bool wb_protected)
+{
+ rb_wbcheck_objspace_t *objspace = (rb_wbcheck_objspace_t *)objspace_ptr;
+ GC_ASSERT(objspace);
+
+ // Allocate and initialize object info structure
+ rb_wbcheck_object_info_t *info = calloc(1, sizeof(rb_wbcheck_object_info_t));
+ if (!info) rb_bug("wbcheck_register_object: failed to allocate object info");
+
+ info->alloc_size = alloc_size;
+ info->wb_protected = wb_protected;
+ info->finalizers = 0; /* No finalizers initially */
+ info->gc_mark_snapshot = NULL; /* No snapshot initially */
+ info->mark_maybe_snapshot = NULL; /* No mark_maybe snapshot initially */
+ info->writebarrier_children = NULL; /* No write barrier children initially */
+ info->state = WBCHECK_STATE_CLEAR; /* Start in clear state */
+ info->color = WBCHECK_COLOR_BLACK; /* Start as black to survive current GC */
+
+ // Store object info in hash table (VALUE -> rb_wbcheck_object_info_t*)
+ st_insert(objspace->object_table, (st_data_t)obj, (st_data_t)info);
+}
+
+static void
+wbcheck_unregister_object(void *objspace_ptr, VALUE obj)
+{
+ rb_wbcheck_objspace_t *objspace = (rb_wbcheck_objspace_t *)objspace_ptr;
+ rb_wbcheck_object_info_t *info;
+
+ if (st_delete(objspace->object_table, (st_data_t *)&obj, (st_data_t *)&info)) {
+ // Free object lists if they were allocated
+ wbcheck_object_list_free(info->gc_mark_snapshot);
+ wbcheck_object_list_free(info->mark_maybe_snapshot);
+ wbcheck_object_list_free(info->writebarrier_children);
+ free(info);
+ } else {
+ rb_bug("wbcheck_unregister_object: object not found in table");
+ }
+}
+
+// Bootup
+void *
+rb_gc_impl_objspace_alloc(void)
+{
+ wbcheck_configure_from_env();
+
+ rb_wbcheck_objspace_t *objspace = calloc(1, sizeof(rb_wbcheck_objspace_t));
+ if (!objspace) rb_bug("wbcheck: failed to allocate objspace");
+
+ objspace->object_table = st_init_numtable();
+ if (!objspace->object_table) {
+ free(objspace);
+ rb_bug("wbcheck: failed to create object table");
+ }
+
+ objspace->objects_to_capture = wbcheck_object_list_init(); // Initialize empty list
+ objspace->objects_to_verify = wbcheck_object_list_init(); // Initialize empty list
+ objspace->current_refs = NULL; // No current refs initially
+ objspace->current_maybe_refs = NULL; // No current maybe refs initially
+ objspace->mark_queue = wbcheck_object_list_init(); // Initialize mark queue
+ objspace->weak_references = wbcheck_object_list_init(); // Initialize weak references array
+ objspace->phase = WBCHECK_PHASE_MUTATOR; // Start in mutator phase
+ objspace->gc_enabled = true; // GC enabled by default (like default GC)
+ objspace->gc_stress = false; // GC stress disabled by default
+ objspace->gc_threshold = 1000; // Start with 1000 objects, will adjust after first GC
+ objspace->missed_write_barrier_parents = 0; // No errors found yet
+ objspace->missed_write_barrier_children = 0; // No errors found yet
+ objspace->simulated_gc_count = 0; // Start with GC count of 0
+ objspace->measure_total_time = true; // On by default
+
+ return objspace;
+}
+
+void
+rb_gc_impl_objspace_init(void *objspace_ptr)
+{
+ rb_wbcheck_objspace_t *objspace = objspace_ptr;
+
+ // Object table is already initialized in objspace_alloc
+ // Set up global objspace pointer for obj_slot_size function
+ wbcheck_global_objspace = objspace;
+
+ // Initialize postponed job for finalizers
+ rb_native_mutex_initialize(&objspace->finalizer_lock);
+ objspace->finalizer_postponed_job = rb_postponed_job_preregister(0, gc_run_finalizers, objspace);
+}
+
+void *
+rb_gc_impl_ractor_cache_alloc(void *objspace_ptr, void *ractor)
+{
+ // Stub implementation
+ return NULL;
+}
+
+void
+rb_gc_impl_set_params(void *objspace_ptr)
+{
+ // Stub implementation
+}
+
+static VALUE
+gc_verify_internal_consistency(VALUE self)
+{
+ return Qnil;
+}
+
+void
+rb_gc_impl_init(void)
+{
+ VALUE gc_constants = rb_hash_new();
+ //rb_hash_aset(gc_constants, ID2SYM(rb_intern("BASE_SLOT_SIZE")), SIZET2NUM(BASE_SLOT_SIZE));
+ rb_hash_aset(gc_constants, ID2SYM(rb_intern("RVALUE_SIZE")), SIZET2NUM(sizeof(struct RBasic) + sizeof(VALUE[RBIMPL_RVALUE_EMBED_LEN_MAX])));
+ rb_hash_aset(gc_constants, ID2SYM(rb_intern("RBASIC_SIZE")), SIZET2NUM(sizeof(struct RBasic)));
+ rb_hash_aset(gc_constants, ID2SYM(rb_intern("RVALUE_OVERHEAD")), INT2NUM(0));
+ rb_hash_aset(gc_constants, ID2SYM(rb_intern("RVARGC_MAX_ALLOCATE_SIZE")), LONG2FIX(MAX_HEAP_SIZE));
+ rb_hash_aset(gc_constants, ID2SYM(rb_intern("HEAP_COUNT")), LONG2FIX(HEAP_COUNT));
+ rb_hash_aset(gc_constants, ID2SYM(rb_intern("SIZE_POOL_COUNT")), LONG2FIX(HEAP_COUNT));
+ rb_hash_aset(gc_constants, ID2SYM(rb_intern("RVALUE_OLD_AGE")), INT2FIX(3));
+ OBJ_FREEZE(gc_constants);
+ rb_define_const(rb_mGC, "INTERNAL_CONSTANTS", gc_constants);
+
+ // no-ops for compatibility
+ rb_define_singleton_method(rb_mGC, "verify_internal_consistency", gc_verify_internal_consistency, 0);
+
+ 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);
+ // Stub implementation
+}
+
+size_t *
+rb_gc_impl_heap_sizes(void *objspace_ptr)
+{
+ return heap_sizes;
+}
+
+// Shutdown
+void
+rb_gc_impl_shutdown_free_objects(void *objspace_ptr)
+{
+ // Stub implementation
+}
+
+void
+rb_gc_impl_objspace_free(void *objspace_ptr)
+{
+ // This should free everything, but we'll just let it leak
+}
+
+void
+rb_gc_impl_ractor_cache_free(void *objspace_ptr, void *cache)
+{
+ // Stub implementation
+}
+
+// GC
+void
+rb_gc_impl_start(void *objspace_ptr, bool full_mark, bool immediate_mark, bool immediate_sweep, bool compact)
+{
+ rb_wbcheck_objspace_t *objspace = (rb_wbcheck_objspace_t *)objspace_ptr;
+ if (objspace) {
+ objspace->simulated_gc_count++;
+ }
+
+ if (!ruby_native_thread_p()) return;
+
+ unsigned int lev = RB_GC_VM_LOCK();
+ rb_gc_vm_barrier();
+ force_gc(objspace_ptr);
+ RB_GC_VM_UNLOCK(lev);
+}
+
+bool
+rb_gc_impl_during_gc_p(void *objspace_ptr)
+{
+ rb_wbcheck_objspace_t *objspace = (rb_wbcheck_objspace_t *)objspace_ptr;
+ return objspace->phase != WBCHECK_PHASE_MUTATOR;
+}
+
+static void
+wbcheck_prepare_heap_i(VALUE obj, void *data)
+{
+ rb_gc_prepare_heap_process_object(obj);
+}
+
+void
+rb_gc_impl_prepare_heap(void *objspace_ptr)
+{
+ rb_gc_impl_each_object(objspace_ptr, wbcheck_prepare_heap_i, NULL);
+}
+
+void
+rb_gc_impl_gc_enable(void *objspace_ptr)
+{
+ rb_wbcheck_objspace_t *objspace = (rb_wbcheck_objspace_t *)objspace_ptr;
+ objspace->gc_enabled = true;
+}
+
+void
+rb_gc_impl_gc_disable(void *objspace_ptr, bool finish_current_gc)
+{
+ rb_wbcheck_objspace_t *objspace = (rb_wbcheck_objspace_t *)objspace_ptr;
+ objspace->gc_enabled = false;
+}
+
+bool
+rb_gc_impl_gc_enabled_p(void *objspace_ptr)
+{
+ rb_wbcheck_objspace_t *objspace = (rb_wbcheck_objspace_t *)objspace_ptr;
+ return objspace->gc_enabled;
+}
+
+void
+rb_gc_impl_stress_set(void *objspace_ptr, VALUE flag)
+{
+ rb_wbcheck_objspace_t *objspace = (rb_wbcheck_objspace_t *)objspace_ptr;
+ objspace->gc_stress = RTEST(flag);
+}
+
+VALUE
+rb_gc_impl_stress_get(void *objspace_ptr)
+{
+ rb_wbcheck_objspace_t *objspace = (rb_wbcheck_objspace_t *)objspace_ptr;
+ return objspace->gc_stress ? Qtrue : Qfalse;
+}
+
+VALUE
+rb_gc_impl_config_get(void *objspace_ptr)
+{
+ return rb_hash_new();
+}
+
+void
+rb_gc_impl_config_set(void *objspace_ptr, VALUE hash)
+{
+}
+
+static wbcheck_object_list_t *
+wbcheck_collect_references_from_object(VALUE obj, rb_wbcheck_object_info_t *info)
+{
+ rb_wbcheck_objspace_t *objspace = wbcheck_global_objspace;
+
+ // Use combination of writebarrier children and last snapshot as capacity hint
+ size_t snapshot_count = (info->gc_mark_snapshot) ? info->gc_mark_snapshot->count : 0;
+ size_t wb_children_count = (info->writebarrier_children) ? info->writebarrier_children->count : 0;
+ size_t capacity_hint = snapshot_count + wb_children_count;
+ wbcheck_object_list_t *new_list = wbcheck_object_list_init_with_capacity(capacity_hint);
+
+ // Set up objspace state for marking. current_maybe_refs is allocated lazily
+ // by rb_gc_impl_mark_maybe, since most objects have no conservative refs.
+ objspace->current_refs = new_list;
+ objspace->current_maybe_refs = NULL;
+ objspace->phase = WBCHECK_PHASE_SNAPSHOT;
+
+ // Use the marking infrastructure to collect references
+ rb_gc_mark_children(objspace, obj);
+
+ // Clean up objspace state
+ objspace->phase = WBCHECK_PHASE_MUTATOR;
+ objspace->current_refs = NULL;
+
+ // Update the mark_maybe snapshot in place. These references don't participate
+ // in verification, but we need to keep them so full GC can mark them gray.
+ wbcheck_object_list_free(info->mark_maybe_snapshot);
+ info->mark_maybe_snapshot = objspace->current_maybe_refs;
+ objspace->current_maybe_refs = NULL;
+
+ if (wbcheck_debug_enabled) {
+ WBCHECK_DEBUG("wbcheck: collected %zu references from %p\n", new_list->count, (void *)obj);
+ char buff[0x100];
+ fprintf(stderr, "%s\n", rb_raw_obj_info(buff, sizeof(buff), obj));
+ wbcheck_object_list_debug_print(new_list);
+ }
+
+ return new_list;
+}
+
+static void
+wbcheck_collect_initial_references(void *objspace_ptr, VALUE obj)
+{
+ WBCHECK_DEBUG("wbcheck: collecting initial references from %p:\n", obj);
+ wbcheck_debug_obj_info_dump(obj);
+
+ // Get the object info and set the initial GC mark snapshot
+ rb_wbcheck_object_info_t *info = wbcheck_get_object_info(obj);
+ wbcheck_object_list_t *new_list = wbcheck_collect_references_from_object(obj, info);
+ RUBY_ASSERT(!info->gc_mark_snapshot);
+ RUBY_ASSERT(info->state == WBCHECK_STATE_CLEAR);
+ info->gc_mark_snapshot = new_list; // Set the initial snapshot
+ info->state = WBCHECK_STATE_MARKED; // Transition to marked state
+}
+
+static void
+wbcheck_verify_object_references(void *objspace_ptr, VALUE obj)
+{
+ rb_wbcheck_object_info_t *info = wbcheck_get_object_info(obj);
+
+ // Ignore objects which are not write barrier protected
+ if (!info->wb_protected) {
+ return;
+ }
+
+ // We hadn't captured initial references
+ if (info->state == WBCHECK_STATE_CLEAR) {
+ RUBY_ASSERT(!info->gc_mark_snapshot);
+ return;
+ }
+
+ WBCHECK_DEBUG("wbcheck: verifying references for object:\n");
+ wbcheck_debug_obj_info_dump(obj);
+
+ // Get the current references from the object
+ wbcheck_object_list_t *current_refs = wbcheck_collect_references_from_object(obj, info);
+
+ // Check for useless write barriers before clearing them
+ if (wbcheck_warn_useless_wb_enabled && info->writebarrier_children) {
+ for (size_t i = 0; i < info->writebarrier_children->count; i++) {
+ VALUE wb_ref = info->writebarrier_children->items[i];
+ if (!wbcheck_object_list_contains(current_refs, wb_ref)) {
+ fprintf(stderr, "WBCHECK WARNING: Potentially useless write barrier detected for object %p\n", (void *)obj);
+ fprintf(stderr, " Write barrier was recorded for reference to %p, but object no longer references it\n", (void *)wb_ref);
+ char buff[0x100];
+ fprintf(stderr, " Parent: %s\n", rb_raw_obj_info(buff, sizeof(buff), obj));
+ fprintf(stderr, " Stale reference: %s\n", rb_raw_obj_info(buff, sizeof(buff), wb_ref));
+ }
+ }
+ }
+
+ // Compare current_refs against both stored lists to detect missed write barriers
+ wbcheck_compare_references(objspace_ptr, obj, current_refs, info->gc_mark_snapshot, info->writebarrier_children);
+
+ // Update the snapshot with current references and clear write barrier children
+ wbcheck_object_list_free(info->gc_mark_snapshot);
+ wbcheck_object_list_free(info->writebarrier_children);
+ info->gc_mark_snapshot = current_refs;
+ info->writebarrier_children = NULL;
+ info->state = WBCHECK_STATE_MARKED; // Back to marked state after verification
+}
+
+// Mark object as gray (add to mark queue)
+static void
+wbcheck_mark_gray(rb_wbcheck_objspace_t *objspace, VALUE obj)
+{
+ if (RB_SPECIAL_CONST_P(obj)) return;
+
+ st_data_t value;
+ if (!st_lookup(objspace->object_table, (st_data_t)obj, &value)) {
+ rb_bug("wbcheck: asked to mark object %p not in our object table", (void *)obj);
+ }
+
+ rb_wbcheck_object_info_t *info = (rb_wbcheck_object_info_t *)value;
+ if (info->color != WBCHECK_COLOR_WHITE) {
+ return; // Already marked
+ }
+
+ info->color = WBCHECK_COLOR_GRAY;
+ wbcheck_object_list_append(objspace->mark_queue, obj);
+
+ if (RB_FL_TEST_RAW(obj, RUBY_FL_WEAK_REFERENCE)) {
+ wbcheck_object_list_append(objspace->weak_references, obj);
+ }
+
+ WBCHECK_DEBUG("wbcheck: marked gray: %p\n", (void *)obj);
+}
+
+// Reset all objects to white
+static int
+st_foreach_reset_white(st_data_t key, st_data_t val, st_data_t arg)
+{
+ rb_wbcheck_object_info_t *info = (rb_wbcheck_object_info_t *)val;
+ info->color = WBCHECK_COLOR_WHITE;
+ return ST_CONTINUE;
+}
+
+// Mark all finalizer arrays to keep them alive during GC
+static int
+st_foreach_mark_finalizers(st_data_t key, st_data_t val, st_data_t arg)
+{
+ rb_wbcheck_object_info_t *info = (rb_wbcheck_object_info_t *)val;
+ rb_wbcheck_objspace_t *objspace = (rb_wbcheck_objspace_t *)arg;
+
+ if (info->finalizers) {
+ wbcheck_mark_gray(objspace, info->finalizers);
+ }
+
+ return ST_CONTINUE;
+}
+
+// Full mark phase using tri-color marking with snapshots
+static void
+wbcheck_mark_phase(rb_wbcheck_objspace_t *objspace)
+{
+ WBCHECK_DEBUG("wbcheck: starting GC mark phase\n");
+
+ objspace->phase = WBCHECK_PHASE_FULL_GC;
+
+ // Clear mark queue and reset all objects to white
+ objspace->mark_queue->count = 0;
+ st_foreach(objspace->object_table, st_foreach_reset_white, 0);
+
+ // Mark all finalizer arrays first to keep them alive
+ st_foreach(objspace->object_table, st_foreach_mark_finalizers, (st_data_t)objspace);
+
+ // Mark finalizer arrays in pending jobs to keep them alive.
+ // No lock needed: all other threads are stopped during GC.
+ struct wbcheck_final_job *job = objspace->finalizer_jobs;
+ while (job != NULL) {
+ switch (job->kind) {
+ case WBCHECK_FINAL_JOB_DFREE:
+ break;
+ case WBCHECK_FINAL_JOB_FINALIZE:
+ wbcheck_mark_gray(objspace, job->as.finalize.finalizer_array);
+ break;
+ default:
+ rb_bug("wbcheck_mark_phase: unknown final job type %d", job->kind);
+ }
+ job = job->next;
+ }
+
+ // Mark roots gray
+ rb_gc_save_machine_context();
+ rb_gc_mark_roots(objspace, NULL);
+
+ // Process gray queue until empty
+ while (objspace->mark_queue->count > 0) {
+ // Get last object from queue (LIFO)
+ VALUE obj = objspace->mark_queue->items[--objspace->mark_queue->count];
+
+ st_data_t value;
+ if (st_lookup(objspace->object_table, (st_data_t)obj, &value)) {
+ rb_wbcheck_object_info_t *info = (rb_wbcheck_object_info_t *)value;
+ if (info->color == WBCHECK_COLOR_GRAY) {
+ // Mark all children from snapshot gray
+ if (info->gc_mark_snapshot) {
+ for (size_t i = 0; i < info->gc_mark_snapshot->count; i++) {
+ wbcheck_mark_gray(objspace, info->gc_mark_snapshot->items[i]);
+ }
+ }
+
+ // Conservatively-scanned children must also be kept alive
+ if (info->mark_maybe_snapshot) {
+ for (size_t i = 0; i < info->mark_maybe_snapshot->count; i++) {
+ wbcheck_mark_gray(objspace, info->mark_maybe_snapshot->items[i]);
+ }
+ }
+
+ // Mark this object black
+ info->color = WBCHECK_COLOR_BLACK;
+ WBCHECK_DEBUG("wbcheck: marked black: %p\n", (void *)obj);
+ }
+ }
+ }
+
+ objspace->phase = WBCHECK_PHASE_MUTATOR;
+
+ WBCHECK_DEBUG("wbcheck: tri-color mark phase complete\n");
+}
+
+// Sweep phase callback - free white objects
+static int
+wbcheck_sweep_callback(st_data_t key, st_data_t val, st_data_t arg, int error)
+{
+ VALUE obj = (VALUE)key;
+ rb_wbcheck_object_info_t *info = (rb_wbcheck_object_info_t *)val;
+ rb_wbcheck_objspace_t *objspace = (rb_wbcheck_objspace_t *)arg;
+
+ if (info->color == WBCHECK_COLOR_WHITE) {
+ WBCHECK_DEBUG("wbcheck: sweeping unmarked object %p\n", (void *)obj);
+
+ rb_gc_event_hook(obj, RUBY_INTERNAL_EVENT_FREEOBJ);
+
+ // Clear weak references first
+ rb_gc_obj_free_vm_weak_references(obj);
+
+ // Queue finalizers for postponed job if they exist
+ if (info->finalizers) {
+ make_final_job(objspace, obj, info->finalizers);
+ rb_postponed_job_trigger(objspace->finalizer_postponed_job);
+ }
+
+ // Call rb_gc_obj_free which handles finalizers/zombies
+ if (rb_gc_obj_free(objspace, obj)) {
+ // Object was actually freed, clean up our tracking
+ wbcheck_object_list_free(info->gc_mark_snapshot);
+ wbcheck_object_list_free(info->mark_maybe_snapshot);
+ wbcheck_object_list_free(info->writebarrier_children);
+ free(info);
+
+ // Free the actual object memory
+ free((void *)obj);
+
+ return ST_DELETE; // Remove from hash table
+ } else {
+ // Object became a zombie - it will be freed by postponed job
+ // Remove from tracking since we can't safely access it anymore
+ wbcheck_object_list_free(info->gc_mark_snapshot);
+ wbcheck_object_list_free(info->mark_maybe_snapshot);
+ wbcheck_object_list_free(info->writebarrier_children);
+ free(info);
+
+ // Free the actual object memory
+ free((void *)obj);
+
+ return ST_DELETE; // Remove from hash table
+ }
+ }
+
+ return ST_CONTINUE; // Keep marked objects
+}
+
+static void
+wbcheck_sweep_phase(rb_wbcheck_objspace_t *objspace)
+{
+ WBCHECK_DEBUG("wbcheck: starting sweep phase\n");
+
+ size_t objects_before = st_table_size(objspace->object_table);
+
+ // Sweep unmarked objects
+ st_foreach_check(objspace->object_table, wbcheck_sweep_callback, (st_data_t)objspace, 0);
+
+ size_t objects_after = st_table_size(objspace->object_table);
+ size_t freed_objects = objects_before - objects_after;
+
+ // Update GC threshold: 2x the live set after GC
+ objspace->gc_threshold = objects_after * 2;
+
+ WBCHECK_DEBUG("wbcheck: sweep phase complete - freed %zu objects (%zu -> %zu), new threshold: %zu\n",
+ freed_objects, objects_before, objects_after, objspace->gc_threshold);
+}
+
+// Process weak references after marking - call rb_gc_handle_weak_references
+// on each object that was flagged with RUBY_FL_WEAK_REFERENCE and collected
+// during the mark phase.
+static void
+wbcheck_process_weak_references(rb_wbcheck_objspace_t *objspace)
+{
+ WBCHECK_DEBUG("wbcheck: processing %zu weak reference objects\n", objspace->weak_references->count);
+
+ for (size_t i = 0; i < objspace->weak_references->count; i++) {
+ VALUE obj = objspace->weak_references->items[i];
+ rb_gc_handle_weak_references(obj);
+ }
+
+ objspace->weak_references->count = 0;
+}
+
+// Full GC: verify all objects then mark from roots
+static void
+wbcheck_full_gc(rb_wbcheck_objspace_t *objspace)
+{
+ WBCHECK_DEBUG("wbcheck: starting full GC\n");
+
+ rb_gc_event_hook(0, RUBY_INTERNAL_EVENT_GC_ENTER);
+ rb_gc_event_hook(0, RUBY_INTERNAL_EVENT_GC_START);
+
+ // First, update snapshots for all objects (verify wb_protected ones)
+ WBCHECK_DEBUG("wbcheck: updating snapshots for all objects\n");
+ wbcheck_foreach_object(objspace, wbcheck_update_all_snapshots_callback, objspace);
+
+ // Now start tri-color marking
+ wbcheck_mark_phase(objspace);
+
+ rb_gc_event_hook(0, RUBY_INTERNAL_EVENT_GC_END_MARK);
+
+ // Process weak references after marking, before sweeping
+ wbcheck_process_weak_references(objspace);
+
+ // Sweep unmarked objects
+ wbcheck_sweep_phase(objspace);
+
+ rb_gc_event_hook(0, RUBY_INTERNAL_EVENT_GC_END_SWEEP);
+ rb_gc_event_hook(0, RUBY_INTERNAL_EVENT_GC_EXIT);
+
+ WBCHECK_DEBUG("wbcheck: full GC complete\n");
+}
+
+static void
+gc_step(void *objspace_ptr, bool force)
+{
+ rb_wbcheck_objspace_t *objspace = (rb_wbcheck_objspace_t *)objspace_ptr;
+
+ // Not initialized yet
+ if (!objspace) return;
+
+ if (!objspace->gc_enabled && !force) return;
+
+ // Process all objects that need verification after write barriers (if enabled)
+ if (wbcheck_verify_after_wb_enabled) {
+ for (size_t i = 0; i < objspace->objects_to_verify->count; i++) {
+ VALUE obj = objspace->objects_to_verify->items[i];
+ wbcheck_verify_object_references(objspace_ptr, obj);
+ }
+
+ // Clear the list after processing
+ objspace->objects_to_verify->count = 0;
+
+ // If any new errors were detected during verification, exit immediately
+ if (objspace->missed_write_barrier_parents > 0) {
+ rb_bug("wbcheck: missed write barrier detected during immediate verification (WBCHECK_VERIFY_AFTER_WB=1)");
+ }
+ }
+
+ // Process all objects that need initial reference capture
+ for (size_t i = 0; i < objspace->objects_to_capture->count; i++) {
+ VALUE obj = objspace->objects_to_capture->items[i];
+ wbcheck_collect_initial_references(objspace_ptr, obj);
+ }
+
+ // Clear the list after processing
+ objspace->objects_to_capture->count = 0;
+
+ // Run full GC if forced, if we exceed the threshold, or if gc_stress is enabled
+ if (ruby_native_thread_p() &&
+ (force ||
+ (objspace->gc_enabled &&
+ (objspace->gc_stress || st_table_size(objspace->object_table) >= objspace->gc_threshold)))) {
+ wbcheck_full_gc(objspace);
+ }
+
+}
+
+static void
+maybe_gc(void *objspace_ptr)
+{
+ gc_step(objspace_ptr, false);
+}
+
+static void
+force_gc(void *objspace_ptr)
+{
+ gc_step(objspace_ptr, true);
+}
+
+int ruby_thread_has_gvl_p(void);
+
+static void *
+lock_and_maybe_gc_gvl(void *objspace_ptr)
+{
+ unsigned int lev = RB_GC_VM_LOCK();
+ rb_gc_vm_barrier();
+
+ maybe_gc(objspace_ptr);
+
+ RB_GC_VM_UNLOCK(lev);
+ return NULL;
+}
+
+static void
+lock_and_maybe_gc(void *objspace_ptr)
+{
+ if (!ruby_native_thread_p()) return;
+
+ if (!ruby_thread_has_gvl_p()) {
+ rb_thread_call_with_gvl(lock_and_maybe_gc_gvl, objspace_ptr);
+ }
+ else {
+ lock_and_maybe_gc_gvl(objspace_ptr);
+ }
+}
+
+VALUE
+rb_gc_impl_new_obj(void *objspace_ptr, void *cache_ptr, VALUE klass, VALUE flags, bool wb_protected, size_t alloc_size)
+{
+ unsigned int lev = RB_GC_VM_LOCK();
+ rb_gc_vm_barrier();
+
+ // Check if we should trigger GC before allocating
+ maybe_gc(objspace_ptr);
+
+ // Ensure minimum allocation size of BASE_SLOT_SIZE
+ alloc_size = heap_sizes[rb_gc_impl_heap_id_for_size(objspace_ptr, alloc_size)];
+
+ // Allocate memory for the object
+ VALUE *mem = malloc(alloc_size);
+ if (!mem) rb_bug("FIXME: malloc failed");
+
+ // Initialize the object
+ VALUE obj = (VALUE)mem;
+ RBASIC(obj)->flags = flags;
+ *((VALUE *)&RBASIC(obj)->klass) = klass;
+
+ // Register the new object in our tracking table
+ wbcheck_register_object(objspace_ptr, obj, alloc_size, wb_protected);
+
+ // Add this object to the list of objects that need initial reference capture
+ rb_wbcheck_objspace_t *objspace = (rb_wbcheck_objspace_t *)objspace_ptr;
+ wbcheck_object_list_append(objspace->objects_to_capture, obj);
+
+ RB_GC_VM_UNLOCK(lev);
+ return obj;
+}
+
+size_t
+rb_gc_impl_obj_slot_size(VALUE obj)
+{
+ unsigned int lev = RB_GC_VM_LOCK();
+
+ rb_wbcheck_object_info_t *info = wbcheck_get_object_info(obj);
+ size_t result = info->alloc_size;
+
+ RB_GC_VM_UNLOCK(lev);
+ return result;
+}
+
+size_t
+rb_gc_impl_heap_id_for_size(void *objspace_ptr, size_t size)
+{
+ for (int i = 0; i < HEAP_COUNT; i++) {
+ if (size <= heap_sizes[i]) return i;
+ }
+ rb_bug("size too big");
+}
+
+bool
+rb_gc_impl_size_allocatable_p(size_t size)
+{
+ // Only allow sizes up to the largest heap size
+ return size <= MAX_HEAP_SIZE;
+}
+
+// Malloc
+void *
+rb_gc_impl_malloc(void *objspace_ptr, size_t size, bool gc_allowed)
+{
+ if (gc_allowed) {
+ lock_and_maybe_gc(objspace_ptr);
+ }
+ return malloc(size);
+}
+
+void *
+rb_gc_impl_calloc(void *objspace_ptr, size_t size, bool gc_allowed)
+{
+ if (gc_allowed) {
+ lock_and_maybe_gc(objspace_ptr);
+ }
+ return calloc(1, size);
+}
+
+void *
+rb_gc_impl_realloc(void *objspace_ptr, void *ptr, size_t new_size, size_t old_size, bool gc_allowed)
+{
+ if (gc_allowed) {
+ lock_and_maybe_gc(objspace_ptr);
+ }
+ return realloc(ptr, new_size);
+}
+
+void
+rb_gc_impl_free(void *objspace_ptr, void *ptr, size_t old_size)
+{
+ free(ptr);
+}
+
+void
+rb_gc_impl_adjust_memory_usage(void *objspace_ptr, ssize_t diff)
+{
+ // For wbcheck, we don't track memory usage
+}
+
+// Marking
+static void
+gc_mark(rb_wbcheck_objspace_t *objspace, VALUE obj)
+{
+ WBCHECK_DEBUG("wbcheck: gc_mark called\n");
+ wbcheck_debug_obj_info_dump(obj);
+
+ if (RB_SPECIAL_CONST_P(obj)) return;
+
+ switch (objspace->phase) {
+ case WBCHECK_PHASE_SNAPSHOT:
+ // Collecting references during verification
+ GC_ASSERT(objspace->current_refs);
+ wbcheck_object_list_append(objspace->current_refs, obj);
+ break;
+ case WBCHECK_PHASE_FULL_GC:
+ // Marking during full GC
+ wbcheck_mark_gray(objspace, obj);
+ break;
+ case WBCHECK_PHASE_MUTATOR:
+ // Should not be called during mutator phase
+ rb_bug("wbcheck: gc_mark called during mutator phase");
+ break;
+ }
+}
+
+void
+rb_gc_impl_mark(void *objspace_ptr, VALUE obj)
+{
+ rb_wbcheck_objspace_t *objspace = objspace_ptr;
+ gc_mark(objspace, obj);
+}
+
+void
+rb_gc_impl_mark_and_move(void *objspace_ptr, VALUE *ptr)
+{
+ rb_wbcheck_objspace_t *objspace = objspace_ptr;
+ gc_mark(objspace, *ptr);
+}
+
+void
+rb_gc_impl_mark_and_pin(void *objspace_ptr, VALUE obj)
+{
+ rb_wbcheck_objspace_t *objspace = objspace_ptr;
+ gc_mark(objspace, obj);
+}
+
+void
+rb_gc_impl_mark_maybe(void *objspace_ptr, VALUE obj)
+{
+ rb_wbcheck_objspace_t *objspace = objspace_ptr;
+
+ if (!rb_gc_impl_pointer_to_heap_p(objspace_ptr, (void *)obj)) return;
+
+ switch (objspace->phase) {
+ case WBCHECK_PHASE_SNAPSHOT:
+ // We don't know if this is actually a reference or just a value
+ // that looks like one, so we can't expect a write barrier for it.
+ // Keep it separate from the verifiable refs, but retain it so full
+ // GC can mark the target gray if it does turn out to be live.
+ if (!objspace->current_maybe_refs) {
+ objspace->current_maybe_refs = wbcheck_object_list_init();
+ }
+ wbcheck_object_list_append(objspace->current_maybe_refs, obj);
+ break;
+ case WBCHECK_PHASE_FULL_GC:
+ wbcheck_mark_gray(objspace, obj);
+ break;
+ case WBCHECK_PHASE_MUTATOR:
+ rb_bug("wbcheck: rb_gc_impl_mark_maybe called during mutator phase");
+ break;
+ }
+}
+
+// Weak references
+void
+rb_gc_impl_declare_weak_references(void *objspace_ptr, VALUE obj)
+{
+ FL_SET_RAW(obj, RUBY_FL_WEAK_REFERENCE);
+}
+
+bool
+rb_gc_impl_handle_weak_references_alive_p(void *objspace_ptr, VALUE obj)
+{
+ rb_wbcheck_objspace_t *objspace = (rb_wbcheck_objspace_t *)objspace_ptr;
+
+ st_data_t value;
+ if (st_lookup(objspace->object_table, (st_data_t)obj, &value)) {
+ rb_wbcheck_object_info_t *info = (rb_wbcheck_object_info_t *)value;
+ return info->color != WBCHECK_COLOR_WHITE;
+ }
+
+ return false;
+}
+
+// Compaction
+void
+rb_gc_impl_register_pinning_obj(void *objspace_ptr, VALUE obj)
+{
+ /* no-op */
+}
+
+bool
+rb_gc_impl_object_moved_p(void *objspace_ptr, VALUE obj)
+{
+ // Stub implementation
+ return false;
+}
+
+VALUE
+rb_gc_impl_location(void *objspace_ptr, VALUE value)
+{
+ // Stub implementation
+ return Qnil;
+}
+
+// Write barriers
+void
+rb_gc_impl_writebarrier(void *objspace_ptr, VALUE a, VALUE b)
+{
+ if (RB_SPECIAL_CONST_P(b)) return;
+
+ unsigned int lev = RB_GC_VM_LOCK_NO_BARRIER();
+
+ rb_wbcheck_objspace_t *objspace = objspace_ptr;
+
+ // Get the object info for the parent object (a)
+ rb_wbcheck_object_info_t *info = wbcheck_get_object_info(a);
+
+ // Only record the write barrier if we have a valid snapshot
+ if (info->state != WBCHECK_STATE_CLEAR) {
+ RUBY_ASSERT(info->gc_mark_snapshot);
+
+ // Initialize writebarrier_children list if it doesn't exist
+ if (!info->writebarrier_children) {
+ info->writebarrier_children = wbcheck_object_list_init();
+ }
+
+ // Add the new reference to the write barrier children list
+ wbcheck_object_list_append(info->writebarrier_children, b);
+
+ WBCHECK_DEBUG("wbcheck: write barrier recorded reference from %p to %p\n", (void *)a, (void *)b);
+
+ // If verification after write barrier is enabled, queue the object for verification
+ if (wbcheck_verify_after_wb_enabled && info->state != WBCHECK_STATE_DIRTY) {
+ WBCHECK_DEBUG("wbcheck: queueing object for verification after write barrier\n");
+ info->state = WBCHECK_STATE_DIRTY; // Mark as dirty
+ wbcheck_object_list_append(objspace->objects_to_verify, a);
+ }
+ } else {
+ WBCHECK_DEBUG("wbcheck: write barrier skipped (snapshot not initialized) from %p to %p\n", (void *)a, (void *)b);
+ }
+
+ RB_GC_VM_UNLOCK_NO_BARRIER(lev);
+}
+
+void
+rb_gc_impl_writebarrier_unprotect(void *objspace_ptr, VALUE obj)
+{
+ WBCHECK_DEBUG("wbcheck: writebarrier_unprotect called on object %p\n", (void *)obj);
+
+ unsigned int lev = RB_GC_VM_LOCK_NO_BARRIER();
+
+ rb_wbcheck_object_info_t *info = wbcheck_get_object_info(obj);
+ info->wb_protected = false;
+
+ RB_GC_VM_UNLOCK_NO_BARRIER(lev);
+}
+
+void
+rb_gc_impl_writebarrier_remember(void *objspace_ptr, VALUE obj)
+{
+ WBCHECK_DEBUG("wbcheck: writebarrier_remember called on object %p\n", (void *)obj);
+
+ unsigned int lev = RB_GC_VM_LOCK_NO_BARRIER();
+
+ rb_wbcheck_objspace_t *objspace = (rb_wbcheck_objspace_t *)objspace_ptr;
+ rb_wbcheck_object_info_t *info = wbcheck_get_object_info(obj);
+
+ // Clear existing references since they may be stale
+ if (info->state != WBCHECK_STATE_CLEAR) {
+ RUBY_ASSERT(info->gc_mark_snapshot);
+ wbcheck_object_list_free(info->gc_mark_snapshot);
+ info->gc_mark_snapshot = NULL;
+
+ wbcheck_object_list_free(info->mark_maybe_snapshot);
+ info->mark_maybe_snapshot = NULL;
+
+ // Only re-add to objects_to_capture if it had previous snapshot
+ // (new objects don't need to be re-added since they'll be captured at allocation)
+ wbcheck_object_list_append(objspace->objects_to_capture, obj);
+
+ // Also clear write barrier children
+ if (info->writebarrier_children) {
+ wbcheck_object_list_free(info->writebarrier_children);
+ info->writebarrier_children = NULL;
+ }
+
+ // Reset to clear state
+ info->state = WBCHECK_STATE_CLEAR;
+ }
+ RUBY_ASSERT(!info->gc_mark_snapshot);
+ RUBY_ASSERT(!info->mark_maybe_snapshot);
+ RUBY_ASSERT(!info->writebarrier_children);
+
+ RB_GC_VM_UNLOCK_NO_BARRIER(lev);
+}
+
+// Heap walking
+struct wbcheck_foreach_data {
+ int (*callback)(VALUE obj, rb_wbcheck_object_info_t *info, void *data);
+ void *data;
+};
+
+static int
+wbcheck_foreach_object_i(st_data_t key, st_data_t val, st_data_t arg)
+{
+ VALUE obj = (VALUE)key;
+ rb_wbcheck_object_info_t *info = (rb_wbcheck_object_info_t *)val;
+ struct wbcheck_foreach_data *foreach_data = (struct wbcheck_foreach_data *)arg;
+
+ return foreach_data->callback(obj, info, foreach_data->data);
+}
+
+static void
+wbcheck_foreach_object(rb_wbcheck_objspace_t *objspace, int (*callback)(VALUE obj, rb_wbcheck_object_info_t *info, void *data), void *data)
+{
+ struct wbcheck_foreach_data foreach_data = {
+ .callback = callback,
+ .data = data
+ };
+
+ st_foreach(objspace->object_table, wbcheck_foreach_object_i, (st_data_t)&foreach_data);
+}
+
+// Helper to collect all objects into a snapshot list
+static int
+wbcheck_snapshot_collector(st_data_t key, st_data_t val, st_data_t arg)
+{
+ VALUE obj = (VALUE)key;
+ wbcheck_object_list_t *snapshot = (wbcheck_object_list_t *)arg;
+ wbcheck_object_list_append(snapshot, obj);
+ return ST_CONTINUE;
+}
+
+// Take a snapshot of all objects for safe iteration
+static wbcheck_object_list_t *
+wbcheck_take_object_snapshot(rb_wbcheck_objspace_t *objspace)
+{
+ size_t object_count = st_table_size(objspace->object_table);
+ wbcheck_object_list_t *snapshot = wbcheck_object_list_init_with_capacity(object_count);
+ st_foreach(objspace->object_table, wbcheck_snapshot_collector, (st_data_t)snapshot);
+ return snapshot;
+}
+
+
+void
+rb_gc_impl_each_objects(void *objspace_ptr, int (*callback)(void *, void *, size_t, void *), void *data)
+{
+ rb_wbcheck_objspace_t *objspace = (rb_wbcheck_objspace_t *)objspace_ptr;
+ GC_ASSERT(objspace);
+
+ wbcheck_object_list_t *snapshot = wbcheck_take_object_snapshot(objspace);
+
+ for (size_t i = 0; i < snapshot->count; i++) {
+ VALUE obj = snapshot->items[i];
+ st_data_t value;
+ if (st_lookup(objspace->object_table, (st_data_t)obj, &value)) {
+ rb_wbcheck_object_info_t *info = (rb_wbcheck_object_info_t *)value;
+ int result = callback(
+ (void *)obj,
+ (void *)((char *)obj + info->alloc_size),
+ info->alloc_size,
+ data
+ );
+ if (result != 0) break;
+ }
+ }
+
+ wbcheck_object_list_free(snapshot);
+}
+
+void
+rb_gc_impl_each_object(void *objspace_ptr, void (*func)(VALUE obj, void *data), void *data)
+{
+ rb_wbcheck_objspace_t *objspace = (rb_wbcheck_objspace_t *)objspace_ptr;
+ GC_ASSERT(objspace);
+
+ wbcheck_object_list_t *snapshot = wbcheck_take_object_snapshot(objspace);
+
+ for (size_t i = 0; i < snapshot->count; i++) {
+ VALUE obj = snapshot->items[i];
+ st_data_t value;
+ if (st_lookup(objspace->object_table, (st_data_t)obj, &value)) {
+ func(obj, data);
+ }
+ }
+
+ wbcheck_object_list_free(snapshot);
+}
+
+static void
+finalizer_jobs_push(rb_wbcheck_objspace_t *objspace, struct wbcheck_final_job *job)
+{
+ rb_native_mutex_lock(&objspace->finalizer_lock);
+ job->next = objspace->finalizer_jobs;
+ objspace->finalizer_jobs = job;
+ rb_native_mutex_unlock(&objspace->finalizer_lock);
+}
+
+static struct wbcheck_final_job *
+finalizer_jobs_pop(rb_wbcheck_objspace_t *objspace)
+{
+ rb_native_mutex_lock(&objspace->finalizer_lock);
+ struct wbcheck_final_job *job = objspace->finalizer_jobs;
+ if (job) {
+ objspace->finalizer_jobs = job->next;
+ }
+ rb_native_mutex_unlock(&objspace->finalizer_lock);
+ return job;
+}
+
+// Finalizers
+void
+rb_gc_impl_make_zombie(void *objspace_ptr, VALUE obj, void (*dfree)(void *), void *data)
+{
+ if (dfree == NULL) return;
+
+ rb_wbcheck_objspace_t *objspace = (rb_wbcheck_objspace_t *)objspace_ptr;
+
+ struct wbcheck_final_job *job = malloc(sizeof(struct wbcheck_final_job));
+ job->kind = WBCHECK_FINAL_JOB_DFREE;
+ job->as.dfree.func = dfree;
+ job->as.dfree.data = data;
+
+ finalizer_jobs_push(objspace, job);
+
+ if (!ruby_free_at_exit_p()) {
+ rb_postponed_job_trigger(objspace->finalizer_postponed_job);
+ }
+
+ WBCHECK_DEBUG("wbcheck: made zombie for object %p with dfree function\n", (void *)obj);
+}
+
+VALUE
+rb_gc_impl_define_finalizer(void *objspace_ptr, VALUE obj, VALUE block)
+{
+ unsigned int lev = RB_GC_VM_LOCK();
+
+ (void)objspace_ptr;
+ rb_wbcheck_object_info_t *info = wbcheck_get_object_info(obj);
+
+ GC_ASSERT(!OBJ_FROZEN(obj));
+
+ RBASIC(obj)->flags |= FL_FINALIZE;
+
+ VALUE table = info->finalizers;
+ VALUE result = block;
+
+ if (!table) {
+ /* First finalizer for this object - store object ID as first element */
+ table = rb_ary_new3(2, rb_obj_id(obj), block);
+ rb_obj_hide(table);
+ info->finalizers = table;
+ } else {
+ /* Check for duplicate finalizers (skip index 0 which is object ID) */
+ long len = RARRAY_LEN(table);
+ long i;
+
+ for (i = 1; i < len; i++) {
+ VALUE recv = RARRAY_AREF(table, i);
+ if (rb_equal(recv, block)) {
+ result = recv; /* Duplicate found, return existing */
+ goto unlock_and_return;
+ }
+ }
+
+ rb_ary_push(table, block);
+ }
+
+unlock_and_return:
+ RB_GC_VM_UNLOCK(lev);
+ return result;
+}
+
+void
+rb_gc_impl_undefine_finalizer(void *objspace_ptr, VALUE obj)
+{
+ unsigned int lev = RB_GC_VM_LOCK();
+
+ (void)objspace_ptr;
+ rb_wbcheck_object_info_t *info = wbcheck_get_object_info(obj);
+
+ GC_ASSERT(!OBJ_FROZEN(obj));
+
+ info->finalizers = 0;
+ FL_UNSET(obj, FL_FINALIZE);
+
+ RB_GC_VM_UNLOCK(lev);
+}
+
+void
+rb_gc_impl_copy_finalizer(void *objspace_ptr, VALUE dest, VALUE obj)
+{
+ (void)objspace_ptr;
+
+ if (!FL_TEST(obj, FL_FINALIZE)) return;
+
+ unsigned int lev = RB_GC_VM_LOCK();
+
+ rb_wbcheck_object_info_t *src_info = wbcheck_get_object_info(obj);
+ rb_wbcheck_object_info_t *dest_info = wbcheck_get_object_info(dest);
+
+ if (src_info->finalizers) {
+ VALUE table = rb_ary_dup(src_info->finalizers);
+ RARRAY_ASET(table, 0, rb_obj_id(dest));
+ rb_obj_hide(table);
+ dest_info->finalizers = table;
+ FL_SET(dest, FL_FINALIZE);
+ }
+
+ RB_GC_VM_UNLOCK(lev);
+}
+
+static VALUE
+wbcheck_get_final(long i, void *data)
+{
+ VALUE table = (VALUE)data;
+
+ return RARRAY_AREF(table, i + 1);
+}
+
+static void
+make_final_job(rb_wbcheck_objspace_t *objspace, VALUE obj, VALUE finalizer_array)
+{
+ RUBY_ASSERT(RB_FL_TEST(obj, FL_FINALIZE));
+ RUBY_ASSERT(RB_BUILTIN_TYPE(finalizer_array) == T_ARRAY);
+
+ RB_FL_UNSET(obj, FL_FINALIZE);
+
+ struct wbcheck_final_job *job = malloc(sizeof(struct wbcheck_final_job));
+ job->kind = WBCHECK_FINAL_JOB_FINALIZE;
+ job->as.finalize.finalizer_array = finalizer_array;
+
+ finalizer_jobs_push(objspace, job);
+}
+
+static void
+gc_run_finalizers(void *data)
+{
+ rb_wbcheck_objspace_t *objspace = data;
+
+ rb_gc_set_pending_interrupt();
+
+ struct wbcheck_final_job *job;
+ while ((job = finalizer_jobs_pop(objspace)) != NULL) {
+ switch (job->kind) {
+ case WBCHECK_FINAL_JOB_DFREE:
+ job->as.dfree.func(job->as.dfree.data);
+ break;
+ case WBCHECK_FINAL_JOB_FINALIZE: {
+ VALUE finalizer_array = job->as.finalize.finalizer_array;
+
+ rb_gc_run_obj_finalizer(
+ RARRAY_AREF(finalizer_array, 0),
+ RARRAY_LEN(finalizer_array) - 1,
+ wbcheck_get_final,
+ (void *)finalizer_array
+ );
+
+ RB_GC_GUARD(finalizer_array);
+ break;
+ }
+ }
+
+ free(job);
+ }
+
+ rb_gc_unset_pending_interrupt();
+}
+
+static void
+wbcheck_run_finalizers_for_object(VALUE obj, rb_wbcheck_object_info_t *info)
+{
+ if (info->finalizers) {
+ VALUE table = info->finalizers;
+ long count = RARRAY_LEN(table) - 1;
+ rb_gc_run_obj_finalizer(RARRAY_AREF(table, 0), count, wbcheck_get_final, (void *)table);
+ FL_UNSET(obj, FL_FINALIZE);
+ }
+ info->finalizers = 0;
+}
+
+static int
+wbcheck_shutdown_call_finalizer_callback(VALUE obj, rb_wbcheck_object_info_t *info, void *data)
+{
+ wbcheck_run_finalizers_for_object(obj, info);
+ return ST_CONTINUE; /* Keep iterating through all objects */
+}
+
+static int
+wbcheck_verify_all_references_callback(VALUE obj, rb_wbcheck_object_info_t *info, void *data)
+{
+ void *objspace_ptr = data;
+ wbcheck_verify_object_references(objspace_ptr, obj);
+ return ST_CONTINUE;
+}
+
+static int
+wbcheck_update_all_snapshots_callback(VALUE obj, rb_wbcheck_object_info_t *info, void *data)
+{
+ void *objspace_ptr = data;
+
+ // For wb_protected objects, do full verification if they have a snapshot
+ if (info->wb_protected && info->state != WBCHECK_STATE_CLEAR) {
+ wbcheck_verify_object_references(objspace_ptr, obj);
+ } else {
+ // For CLEAR objects (wb_protected or not) and non-wb_protected objects, just take a new snapshot
+ wbcheck_object_list_t *current_refs = wbcheck_collect_references_from_object(obj, info);
+ wbcheck_object_list_free(info->gc_mark_snapshot);
+ info->gc_mark_snapshot = current_refs;
+ info->state = WBCHECK_STATE_MARKED;
+ }
+
+ return ST_CONTINUE;
+}
+
+static int
+wbcheck_shutdown_finalizer_callback(VALUE obj, rb_wbcheck_object_info_t *info, void *data)
+{
+ void *objspace_ptr = data;
+
+ if (rb_gc_shutdown_call_finalizer_p(obj)) {
+ WBCHECK_DEBUG("wbcheck: finalizing object during shutdown: %p\n", (void *)obj);
+ rb_gc_obj_free_vm_weak_references(obj);
+ if (rb_gc_obj_free(objspace_ptr, obj)) {
+ RBASIC(obj)->flags = 0;
+ }
+ }
+
+ return ST_CONTINUE;
+}
+
+
+void
+rb_gc_impl_shutdown_call_finalizer(void *objspace_ptr)
+{
+ rb_wbcheck_objspace_t *objspace = objspace_ptr;
+
+ // Call all finalizers for all objects using our shared iteration helper
+ wbcheck_foreach_object(objspace, wbcheck_shutdown_call_finalizer_callback, NULL);
+
+ // After all finalizers have been called, verify all object references
+ unsigned int verify_lev = RB_GC_VM_LOCK();
+ WBCHECK_DEBUG("wbcheck: verifying references for all objects after finalizers\n");
+ wbcheck_foreach_object(objspace, wbcheck_verify_all_references_callback, objspace_ptr);
+ WBCHECK_DEBUG("wbcheck: finished verifying all object references\n");
+ RB_GC_VM_UNLOCK(verify_lev);
+
+ // Print summary and exit with error code if violations were found
+ if (objspace->missed_write_barrier_parents > 0 || objspace->missed_write_barrier_children > 0) {
+ fprintf(stderr, "WBCHECK SUMMARY: Found %zu objects with missed write barriers (%zu total violations)\n",
+ objspace->missed_write_barrier_parents, objspace->missed_write_barrier_children);
+
+
+ exit(1); // Exit with error code to indicate violations were found
+ } else {
+ WBCHECK_DEBUG("wbcheck: no write barrier violations detected\n");
+ }
+
+ // Call rb_gc_obj_free on objects that need shutdown finalization (File, Data with dfree, etc.)
+ unsigned int lev = RB_GC_VM_LOCK();
+ WBCHECK_DEBUG("wbcheck: calling rb_gc_obj_free on objects that need shutdown finalization\n");
+ wbcheck_foreach_object(objspace, wbcheck_shutdown_finalizer_callback, objspace_ptr);
+ WBCHECK_DEBUG("wbcheck: finished calling rb_gc_obj_free\n");
+
+ // Run any pending finalizer jobs (dfree functions)
+ WBCHECK_DEBUG("wbcheck: running pending finalizer jobs\n");
+ gc_run_finalizers(objspace);
+ WBCHECK_DEBUG("wbcheck: finished running finalizer jobs\n");
+ RB_GC_VM_UNLOCK(lev);
+}
+
+// Forking
+void
+rb_gc_impl_before_fork(void *objspace_ptr)
+{
+ // Stub implementation
+}
+
+void
+rb_gc_impl_after_fork(void *objspace_ptr, rb_pid_t pid)
+{
+ // Stub implementation
+}
+
+// Statistics
+void
+rb_gc_impl_set_measure_total_time(void *objspace_ptr, VALUE flag)
+{
+ rb_wbcheck_objspace_t *objspace = (rb_wbcheck_objspace_t *)objspace_ptr;
+ objspace->measure_total_time = RTEST(flag);
+}
+
+bool
+rb_gc_impl_get_measure_total_time(void *objspace_ptr)
+{
+ rb_wbcheck_objspace_t *objspace = (rb_wbcheck_objspace_t *)objspace_ptr;
+ return objspace->measure_total_time;
+}
+
+unsigned long long
+rb_gc_impl_get_total_time(void *objspace_ptr)
+{
+ rb_wbcheck_objspace_t *objspace = (rb_wbcheck_objspace_t *)objspace_ptr;
+ return objspace->measure_total_time ? objspace->simulated_gc_count : 0;
+}
+
+size_t
+rb_gc_impl_gc_count(void *objspace_ptr)
+{
+ rb_wbcheck_objspace_t *objspace = (rb_wbcheck_objspace_t *)objspace_ptr;
+ if (objspace) {
+ return objspace->simulated_gc_count;
+ }
+ return 0;
+}
+
+VALUE
+rb_gc_impl_latest_gc_info(void *objspace_ptr, VALUE key)
+{
+ // Stub implementation
+ return Qnil;
+}
+
+VALUE
+rb_gc_impl_stat(void *objspace_ptr, VALUE hash_or_sym)
+{
+ rb_wbcheck_objspace_t *objspace = (rb_wbcheck_objspace_t *)objspace_ptr;
+ GC_ASSERT(objspace);
+
+ VALUE hash = Qnil, key = Qnil;
+
+ 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_bug("non-hash or symbol given");
+ }
+
+#define SET(name, attr) \
+ if (key == ID2SYM(rb_intern(#name))) \
+ return SIZET2NUM(attr); \
+ else if (hash != Qnil) \
+ rb_hash_aset(hash, ID2SYM(rb_intern(#name)), SIZET2NUM(attr));
+
+ /* Pretend each GC takes 1ms; :time is reported in milliseconds. */
+ SET(count, objspace->simulated_gc_count);
+ SET(time, objspace->measure_total_time ? objspace->simulated_gc_count : 0);
+ SET(tracked_objects, st_table_size(objspace->object_table));
+#undef SET
+
+ if (!NIL_P(key)) {
+ rb_raise(rb_eArgError, "unknown key: %"PRIsVALUE, rb_sym2str(key));
+ }
+
+ rb_hash_aset(hash, ID2SYM(rb_intern("gc_implementation")), rb_str_new_cstr("wbcheck"));
+
+ return hash;
+}
+
+VALUE
+rb_gc_impl_stat_heap(void *objspace_ptr, VALUE heap_name, VALUE hash_or_sym)
+{
+ if (FIXNUM_P(heap_name) && SYMBOL_P(hash_or_sym)) {
+ 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 (hash_or_sym == ID2SYM(rb_intern("slot_size"))) {
+ return SIZET2NUM(heap_sizes[heap_idx]);
+ }
+
+ return Qundef;
+ }
+
+ if (RB_TYPE_P(hash_or_sym, T_HASH)) {
+ return hash_or_sym;
+ }
+
+ return Qundef;
+}
+
+const char *
+rb_gc_impl_active_gc_name(void)
+{
+ // Stub implementation
+ return "wbcheck";
+}
+
+// Miscellaneous
+#define WBCHECK_OBJECT_METADATA_ENTRY_COUNT 2
+static struct rb_gc_object_metadata_entry object_metadata_entries[WBCHECK_OBJECT_METADATA_ENTRY_COUNT + 1];
+
+struct rb_gc_object_metadata_entry *
+rb_gc_impl_object_metadata(void *objspace_ptr, VALUE obj)
+{
+ static ID ID_object_id, ID_shareable;
+
+ if (!ID_object_id) {
+ ID_object_id = rb_intern("object_id");
+ ID_shareable = rb_intern("shareable");
+ }
+
+ size_t n = 0;
+
+#define SET_ENTRY(na, v) do { \
+ GC_ASSERT(n < WBCHECK_OBJECT_METADATA_ENTRY_COUNT); \
+ object_metadata_entries[n].name = ID_##na; \
+ object_metadata_entries[n].val = v; \
+ n++; \
+} while (0)
+
+ if (rb_obj_id_p(obj)) SET_ENTRY(object_id, rb_obj_id(obj));
+ if (FL_TEST(obj, FL_SHAREABLE)) SET_ENTRY(shareable, Qtrue);
+#undef SET_ENTRY
+
+ object_metadata_entries[n].name = 0;
+ object_metadata_entries[n].val = 0;
+
+ return object_metadata_entries;
+}
+
+bool
+rb_gc_impl_pointer_to_heap_p(void *objspace_ptr, const void *ptr)
+{
+ GC_ASSERT(wbcheck_global_objspace);
+
+ unsigned int lev = RB_GC_VM_LOCK();
+
+ // Check if this pointer exists in our object tracking table
+ st_data_t value;
+ bool result = st_lookup(wbcheck_global_objspace->object_table, (st_data_t)ptr, &value);
+
+ RB_GC_VM_UNLOCK(lev);
+ return result;
+}
+
+bool
+rb_gc_impl_garbage_object_p(void *objspace_ptr, VALUE obj)
+{
+ unsigned int lev = RB_GC_VM_LOCK();
+
+ // Check if this pointer exists in our object tracking table
+ st_data_t value;
+ bool result = st_lookup(wbcheck_global_objspace->object_table, (st_data_t)obj, &value);
+
+ RB_GC_VM_UNLOCK(lev);
+ return !result;
+}
+
+void
+rb_gc_impl_set_event_hook(void *objspace_ptr, const rb_event_flag_t event)
+{
+ // Stub implementation
+}
+
+void
+rb_gc_impl_copy_attributes(void *objspace_ptr, VALUE dest, VALUE obj)
+{
+ rb_wbcheck_object_info_t *src_info = wbcheck_get_object_info(obj);
+
+ if (!src_info->wb_protected) {
+ rb_gc_impl_writebarrier_unprotect(objspace_ptr, dest);
+ }
+ rb_gc_impl_copy_finalizer(objspace_ptr, dest, obj);
+}
+
diff --git a/gem_prelude.rb b/gem_prelude.rb
index bcd2560fab..1b78d80c72 100644
--- a/gem_prelude.rb
+++ b/gem_prelude.rb
@@ -25,4 +25,3 @@ begin
rescue LoadError
warn "`syntax_suggest' was not loaded."
end if defined?(SyntaxSuggest)
-
diff --git a/gems/bundled_gems b/gems/bundled_gems
index 77ace93114..14f79ce9ae 100644
--- a/gems/bundled_gems
+++ b/gems/bundled_gems
@@ -6,42 +6,42 @@
# - revision: revision in repository-url to test
# if `revision` is not given, "v"+`version` or `version` will be used.
-minitest 5.25.5 https://github.com/minitest/minitest
-power_assert 2.0.5 https://github.com/ruby/power_assert f88e406e7c9e0810cc149869582afbae1fb84c4a
-rake 13.3.0 https://github.com/ruby/rake
-test-unit 3.7.0 https://github.com/test-unit/test-unit
-rexml 3.4.1 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.5.9 https://github.com/ruby/net-imap
-net-pop 0.1.2 https://github.com/ruby/net-pop
+minitest 6.0.6 https://github.com/minitest/minitest
+power_assert 3.0.1 https://github.com/ruby/power_assert
+rake 13.4.2 https://github.com/ruby/rake
+test-unit 3.7.8 https://github.com/test-unit/test-unit
+rexml 3.4.4 https://github.com/ruby/rexml
+rss 0.3.2 https://github.com/ruby/rss
+net-imap 0.6.4 https://github.com/ruby/net-imap
net-smtp 0.5.1 https://github.com/ruby/net-smtp
matrix 0.4.3 https://github.com/ruby/matrix
prime 0.1.4 https://github.com/ruby/prime
-rbs 3.9.4 https://github.com/ruby/rbs fba1f778b7eff01dde5e3d886e850f7eea018f2b
-typeprof 0.30.1 https://github.com/ruby/typeprof
-debug 1.11.0 https://github.com/ruby/debug
+rbs 4.0.2 https://github.com/ruby/rbs 1582ce76429810b057a2816e5000cf5de4b1363d
+typeprof 0.32.0 https://github.com/ruby/typeprof
+debug 1.11.1 https://github.com/ruby/debug 9dc2024a5a05116b3d38afbc5579d9503d8913f3
racc 1.8.1 https://github.com/ruby/racc
mutex_m 0.3.0 https://github.com/ruby/mutex_m
getoptlong 0.2.1 https://github.com/ruby/getoptlong
base64 0.3.0 https://github.com/ruby/base64
-bigdecimal 3.2.2 https://github.com/ruby/bigdecimal
+bigdecimal 4.1.2 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
+resolv-replace 0.2.0 https://github.com/ruby/resolv-replace
rinda 0.2.0 https://github.com/ruby/rinda
drb 2.2.3 https://github.com/ruby/drb
nkf 0.2.0 https://github.com/ruby/nkf
-syslog 0.3.0 https://github.com/ruby/syslog
+syslog 0.4.0 https://github.com/ruby/syslog
csv 3.3.5 https://github.com/ruby/csv
-repl_type_completor 0.1.11 https://github.com/ruby/repl_type_completor 25108aa8d69ddaba0b5da3feff1c0035371524b2
+repl_type_completor 0.1.15 https://github.com/ruby/repl_type_completor
ostruct 0.6.3 https://github.com/ruby/ostruct
-pstore 0.2.0 https://github.com/ruby/pstore
-benchmark 0.4.1 https://github.com/ruby/benchmark
+pstore 0.2.1 https://github.com/ruby/pstore
+benchmark 0.5.0 https://github.com/ruby/benchmark
logger 1.7.0 https://github.com/ruby/logger
-rdoc 6.14.2 https://github.com/ruby/rdoc
-win32ole 1.9.2 https://github.com/ruby/win32ole
-irb 1.15.2 https://github.com/ruby/irb 331c4e851296b115db766c291e8cf54a2492fb36
-reline 0.6.2 https://github.com/ruby/reline
+rdoc 7.2.0 https://github.com/ruby/rdoc 1f93543615928b6d45357432f16ec6006e2d8b1e
+win32ole 1.9.3 https://github.com/ruby/win32ole
+irb 1.18.0 https://github.com/ruby/irb
+reline 0.6.3 https://github.com/ruby/reline
readline 0.0.4 https://github.com/ruby/readline
fiddle 1.1.8 https://github.com/ruby/fiddle
+tsort 0.2.0 https://github.com/ruby/tsort
+win32-registry 0.1.2 https://github.com/ruby/win32-registry
diff --git a/hash.c b/hash.c
index 8b1d5fde8b..9ba8c3d4fe 100644
--- a/hash.c
+++ b/hash.c
@@ -471,58 +471,11 @@ ar_set_entry(VALUE hash, unsigned int index, st_data_t key, st_data_t val, st_ha
#define RHASH_AR_TABLE_SIZE(h) (HASH_ASSERT(RHASH_AR_TABLE_P(h)), \
RHASH_AR_TABLE_SIZE_RAW(h))
-#define RHASH_AR_TABLE_BOUND_RAW(h) \
- ((unsigned int)((RBASIC(h)->flags >> RHASH_AR_TABLE_BOUND_SHIFT) & \
- (RHASH_AR_TABLE_BOUND_MASK >> RHASH_AR_TABLE_BOUND_SHIFT)))
-
-#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__)
-void
-rb_hash_dump(VALUE hash)
-{
- rb_obj_info_dump(hash);
-
- if (RHASH_AR_TABLE_P(hash)) {
- unsigned i, bound = RHASH_AR_TABLE_BOUND(hash);
-
- fprintf(stderr, " size:%u bound:%u\n",
- RHASH_AR_TABLE_SIZE(hash), bound);
-
- for (i=0; i<bound; i++) {
- st_data_t k, v;
-
- if (!ar_cleared_entry(hash, i)) {
- char b1[0x100], b2[0x100];
- ar_table_pair *pair = RHASH_AR_TABLE_REF(hash, i);
- k = pair->key;
- v = pair->val;
- fprintf(stderr, " %d key:%s val:%s hint:%02x\n", i,
- rb_raw_obj_info(b1, 0x100, k),
- rb_raw_obj_info(b2, 0x100, v),
- ar_hint(hash, i));
- }
- else {
- fprintf(stderr, " %d empty\n", i);
- }
- }
- }
-}
-
static VALUE
hash_verify_(VALUE hash, const char *file, int line)
{
@@ -575,7 +528,7 @@ hash_st_table_init(VALUE hash, const struct st_hash_type *type, st_index_t size)
RHASH_SET_ST_FLAG(hash);
}
-void
+static void
rb_hash_st_table_set(VALUE hash, st_table *st)
{
HASH_ASSERT(st != NULL);
@@ -635,6 +588,7 @@ RHASH_AR_TABLE_SIZE_DEC(VALUE h)
static inline void
RHASH_AR_TABLE_CLEAR(VALUE h)
{
+ RUBY_ASSERT(rb_gc_obj_slot_size(h) >= sizeof(struct RHash) + sizeof(ar_table));
RBASIC(h)->flags &= ~RHASH_AR_TABLE_SIZE_MASK;
RBASIC(h)->flags &= ~RHASH_AR_TABLE_BOUND_MASK;
@@ -750,6 +704,8 @@ ar_force_convert_table(VALUE hash, const char *file, int line)
st_hash_t hashes[RHASH_AR_TABLE_MAX_SIZE];
unsigned int bound, size;
+ RUBY_ASSERT(rb_gc_obj_slot_size(hash) >= sizeof(struct RHash) + sizeof(ar_table));
+
// prepare hash values
do {
st_data_t keys[RHASH_AR_TABLE_MAX_SIZE];
@@ -774,7 +730,7 @@ ar_force_convert_table(VALUE hash, const char *file, int line)
st_init_existing_table_with_size(new_tab, &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);
+ rb_hash_st_table_set(hash, new_tab);
return RHASH_ST_TABLE(hash);
}
}
@@ -1173,12 +1129,15 @@ ar_values(VALUE hash, st_data_t *values, st_index_t size)
static ar_table*
ar_copy(VALUE hash1, VALUE hash2)
{
+ RUBY_ASSERT(rb_gc_obj_slot_size(hash1) >= sizeof(struct RHash) + sizeof(ar_table));
ar_table *old_tab = RHASH_AR_TABLE(hash2);
ar_table *new_tab = RHASH_AR_TABLE(hash1);
- *new_tab = *old_tab;
+ unsigned int bound = RHASH_AR_TABLE_BOUND(hash2);
+ new_tab->ar_hint.word = old_tab->ar_hint.word;
+ MEMCPY(&new_tab->pairs, &old_tab->pairs, ar_table_pair, bound);
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_BOUND_SET(hash1, bound);
RHASH_AR_TABLE_SIZE_SET(hash1, RHASH_AR_TABLE_SIZE(hash2));
rb_gc_writebarrier_remember(hash1);
@@ -1204,17 +1163,13 @@ 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);
+ rb_st_free_embedded_table(RHASH_ST_TABLE(hash));
}
static void
hash_st_free_and_clear_table(VALUE hash)
{
hash_st_free(hash);
-
RHASH_ST_CLEAR(hash);
}
@@ -1466,14 +1421,9 @@ compact_after_delete(VALUE hash)
static VALUE
hash_alloc_flags(VALUE klass, VALUE flags, VALUE ifnone, bool st)
{
- 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);
-
- RHASH_SET_IFNONE((VALUE)hash, ifnone);
-
- return (VALUE)hash;
+ VALUE hash = rb_newobj_of(klass, T_HASH | flags, size);
+ return rb_hash_set_ifnone(hash, ifnone);
}
static VALUE
@@ -1525,9 +1475,30 @@ rb_hash_new_capa(long capa)
return rb_hash_new_with_size((st_index_t)capa);
}
+VALUE
+rb_hash_alloc_fixed_size(VALUE klass, st_index_t size)
+{
+ VALUE ret;
+ if (size > RHASH_AR_TABLE_MAX_SIZE) {
+ ret = hash_alloc_flags(klass, 0, Qnil, true);
+ hash_st_table_init(ret, &objhash, size);
+ }
+ else {
+ size_t slot_size = sizeof(struct RHash) + offsetof(ar_table, pairs) + size * sizeof(ar_table_pair);
+ ret = rb_newobj_of(klass, T_HASH, slot_size);
+ }
+
+ RHASH_SET_IFNONE(ret, Qnil);
+ return ret;
+}
+
static VALUE
hash_copy(VALUE ret, VALUE hash)
{
+ if (rb_hash_compare_by_id_p(hash)) {
+ rb_gc_register_pinning_obj(ret);
+ }
+
if (RHASH_AR_TABLE_P(hash)) {
if (RHASH_AR_TABLE_P(ret)) {
ar_copy(ret, hash);
@@ -1585,9 +1556,8 @@ rb_hash_dup(VALUE hash)
const VALUE flags = RBASIC(hash)->flags;
VALUE ret = hash_dup(hash, rb_obj_class(hash), flags & RHASH_PROC_DEFAULT);
- if (rb_obj_exivar_p(hash)) {
- rb_copy_generic_ivar(ret, hash);
- }
+ rb_copy_generic_ivar(ret, hash);
+
return ret;
}
@@ -1970,6 +1940,9 @@ rb_hash_rehash_i(VALUE key, VALUE value, VALUE arg)
else {
st_insert(RHASH_ST_TABLE(arg), (st_data_t)key, (st_data_t)value);
}
+
+ RB_OBJ_WRITTEN(arg, Qundef, key);
+ RB_OBJ_WRITTEN(arg, Qundef, value);
return ST_CONTINUE;
}
@@ -2013,7 +1986,7 @@ rb_hash_rehash(VALUE hash)
rb_hash_foreach(hash, rb_hash_rehash_i, (VALUE)tmp);
hash_st_free(hash);
- RHASH_ST_TABLE_SET(hash, tbl);
+ rb_hash_st_table_set(hash, tbl);
RHASH_ST_CLEAR(tmp);
}
hash_verify(hash);
@@ -2672,9 +2645,9 @@ rb_hash_slice(int argc, VALUE *argv, VALUE hash)
* Returns a copy of +self+ that excludes entries for the given +keys+;
* any +keys+ that are not found are ignored:
*
- * h = {foo:0, bar: 1, baz: 2} # => {:foo=>0, :bar=>1, :baz=>2}
- * h.except(:baz, :foo) # => {:bar=>1}
- * h.except(:bar, :nosuch) # => {:foo=>0, :baz=>2}
+ * h = {foo:0, bar: 1, baz: 2} # => {foo: 0, bar: 1, baz: 2}
+ * h.except(:baz, :foo) # => {bar: 1}
+ * h.except(:bar, :nosuch) # => {foo: 0, baz: 2}
*
* Related: see {Methods for Deleting}[rdoc-ref:Hash@Methods+for+Deleting].
*/
@@ -2907,7 +2880,7 @@ hash_aset(st_data_t *key, st_data_t *val, struct update_arg *arg, int existing)
VALUE
rb_hash_key_str(VALUE key)
{
- if (!rb_obj_exivar_p(key) && RBASIC_CLASS(key) == rb_cString) {
+ if (!rb_obj_gen_fields_p(key) && RBASIC_CLASS(key) == rb_cString) {
return rb_fstring(key);
}
else {
@@ -2951,7 +2924,7 @@ NOINSERT_UPDATE_CALLBACK(hash_aset_str)
* h = {foo: 0, bar: 1}
* h[:baz] = 2 # => 2
* h[:baz] # => 2
- * h # => {:foo=>0, :bar=>1, :baz=>2}
+ * h # => {foo: 0, bar: 1, baz: 2}
*
* Related: #[]; see also {Methods for Assigning}[rdoc-ref:Hash@Methods+for+Assigning].
*/
@@ -4007,17 +3980,13 @@ hash_equal(VALUE hash1, VALUE hash2, int eql)
/*
* call-seq:
- * self == object -> true or false
- *
- * Returns whether +self+ and +object+ are equal.
+ * self == other -> true or false
*
- * Returns +true+ if all of the following are true:
- *
- * - +object+ is a +Hash+ object (or can be converted to one).
- * - +self+ and +object+ have the same keys (regardless of order).
- * - For each key +key+, <tt>self[key] == object[key]</tt>.
+ * Returns whether all of the following are true:
*
- * Otherwise, returns +false+.
+ * - +other+ is a +Hash+ object (or can be converted to one).
+ * - +self+ and +other+ have the same keys (regardless of order).
+ * - For each key +key+, <tt>self[key] == other[key]</tt>.
*
* Examples:
*
@@ -4026,8 +3995,8 @@ hash_equal(VALUE hash1, VALUE hash2, int eql)
* h == {bar: 1, foo: 0} # => true # Equal entries (different order).
* h == 1 # => false # Object not a hash.
* h == {} # => false # Different number of entries.
- * h == {foo: 0, bar: 1} # => false # Different key.
- * h == {foo: 0, bar: 1} # => false # Different value.
+ * h == {foo: 0, bat: 1} # => false # Different key.
+ * h == {foo: 0, bar: 2} # => false # Different value.
*
* Related: see {Methods for Comparing}[rdoc-ref:Hash@Methods+for+Comparing].
*/
@@ -4524,21 +4493,21 @@ flatten_i(VALUE key, VALUE val, VALUE ary)
* Examples; note that entry <tt>foo: {bar: 1, baz: 2}</tt> is never flattened.
*
* h = {foo: {bar: 1, baz: 2}, bat: [:bam, [:bap, [:bah]]]}
- * h.flatten(1) # => [:foo, {:bar=>1, :baz=>2}, :bat, [:bam, [:bap, [:bah]]]]
- * h.flatten(2) # => [:foo, {:bar=>1, :baz=>2}, :bat, :bam, [:bap, [:bah]]]
- * h.flatten(3) # => [:foo, {:bar=>1, :baz=>2}, :bat, :bam, :bap, [:bah]]
- * h.flatten(4) # => [:foo, {:bar=>1, :baz=>2}, :bat, :bam, :bap, :bah]
- * h.flatten(5) # => [:foo, {:bar=>1, :baz=>2}, :bat, :bam, :bap, :bah]
+ * h.flatten(1) # => [:foo, {bar: 1, baz: 2}, :bat, [:bam, [:bap, [:bah]]]]
+ * h.flatten(2) # => [:foo, {bar: 1, baz: 2}, :bat, :bam, [:bap, [:bah]]]
+ * h.flatten(3) # => [:foo, {bar: 1, baz: 2}, :bat, :bam, :bap, [:bah]]
+ * h.flatten(4) # => [:foo, {bar: 1, baz: 2}, :bat, :bam, :bap, :bah]
+ * h.flatten(5) # => [:foo, {bar: 1, baz: 2}, :bat, :bam, :bap, :bah]
*
* With negative integer +depth+,
* flattens all levels:
*
- * h.flatten(-1) # => [:foo, {:bar=>1, :baz=>2}, :bat, :bam, :bap, :bah]
+ * h.flatten(-1) # => [:foo, {bar: 1, baz: 2}, :bat, :bam, :bap, :bah]
*
* With +depth+ zero,
* returns the equivalent of #to_a:
*
- * h.flatten(0) # => [[:foo, {:bar=>1, :baz=>2}], [:bat, [:bam, [:bap, [:bah]]]]]
+ * h.flatten(0) # => [[:foo, {bar: 1, baz: 2}], [:bat, [:bam, [:bap, [:bah]]]]]
*
* Related: see {Methods for Converting}[rdoc-ref:Hash@Methods+for+Converting].
*/
@@ -4649,7 +4618,7 @@ rb_hash_compact_bang(VALUE hash)
* returns +self+:
*
* By default, two keys are considered to be the same key
- * if and only if they are _equal_ objects (per method #==):
+ * if and only if they are _equal_ objects (per method #eql?):
*
* h = {}
* h['x'] = 0
@@ -4700,10 +4669,12 @@ rb_hash_compare_by_id(VALUE 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);
+ rb_hash_st_table_set(hash, identtable);
RHASH_ST_CLEAR(tmp);
}
+ rb_gc_register_pinning_obj(hash);
+
return hash;
}
@@ -4733,6 +4704,7 @@ rb_ident_hash_new(void)
{
VALUE hash = rb_hash_new();
hash_st_table_init(hash, &identhash, 0);
+ rb_gc_register_pinning_obj(hash);
return hash;
}
@@ -4741,6 +4713,7 @@ rb_ident_hash_new_with_size(st_index_t size)
{
VALUE hash = rb_hash_new();
hash_st_table_init(hash, &identhash, size);
+ rb_gc_register_pinning_obj(hash);
return hash;
}
@@ -4882,7 +4855,7 @@ rb_hash_any_p(int argc, VALUE *argv, VALUE hash)
* h.dig(:hello) # => nil
* h.default_proc = -> (hash, _key) { hash }
* h.dig(:hello, :world)
- * # => {:foo=>{:bar=>[:a, :b, :c]}}
+ * # => {foo: {bar: [:a, :b, :c]}}
*
* Related: {Methods for Fetching}[rdoc-ref:Hash@Methods+for+Fetching].
*/
@@ -4919,10 +4892,9 @@ hash_le(VALUE hash1, VALUE hash2)
/*
* call-seq:
- * self <= other_hash -> true or false
+ * self <= other -> true or false
*
- * Returns +true+ if the entries of +self+ are a subset of the entries of +other_hash+,
- * +false+ otherwise:
+ * Returns whether the entries of +self+ are a subset of the entries of +other+:
*
* h0 = {foo: 0, bar: 1}
* h1 = {foo: 0, bar: 1, baz: 2}
@@ -4930,7 +4902,7 @@ hash_le(VALUE hash1, VALUE hash2)
* h0 <= h1 # => true
* h1 <= h0 # => false
*
- * See {Hash Inclusion}[rdoc-ref:hash_inclusion.rdoc].
+ * See {Hash Inclusion}[rdoc-ref:language/hash_inclusion.rdoc].
*
* Raises TypeError if +other_hash+ is not a hash and cannot be converted to a hash.
*
@@ -4946,20 +4918,19 @@ rb_hash_le(VALUE hash, VALUE other)
/*
* call-seq:
- * self < other_hash -> true or false
+ * self < other -> true or false
*
- * Returns +true+ if the entries of +self+ are a proper subset of the entries of +other_hash+,
- * +false+ otherwise:
+ * Returns whether the entries of +self+ are a proper subset of the entries of +other+:
*
* h = {foo: 0, bar: 1}
* h < {foo: 0, bar: 1, baz: 2} # => true # Proper subset.
* h < {baz: 2, bar: 1, foo: 0} # => true # Order may differ.
* h < h # => false # Not a proper subset.
* h < {bar: 1, foo: 0} # => false # Not a proper subset.
- * h < {foo: 0, bar: 1, baz: 2} # => false # Different key.
- * h < {foo: 0, bar: 1, baz: 2} # => false # Different value.
+ * h < {foo: 0, bat: 1, baz: 2} # => false # Different key.
+ * h < {foo: 0, bar: 3, baz: 2} # => false # Different value.
*
- * See {Hash Inclusion}[rdoc-ref:hash_inclusion.rdoc].
+ * See {Hash Inclusion}[rdoc-ref:language/hash_inclusion.rdoc].
*
* Raises TypeError if +other_hash+ is not a hash and cannot be converted to a hash.
*
@@ -4975,10 +4946,9 @@ rb_hash_lt(VALUE hash, VALUE other)
/*
* call-seq:
- * self >= other_hash -> true or false
+ * self >= other -> true or false
*
- * Returns +true+ if the entries of +self+ are a superset of the entries of +other_hash+,
- * +false+ otherwise:
+ * Returns whether the entries of +self+ are a superset of the entries of +other+:
*
* h0 = {foo: 0, bar: 1, baz: 2}
* h1 = {foo: 0, bar: 1}
@@ -4986,7 +4956,7 @@ rb_hash_lt(VALUE hash, VALUE other)
* h0 >= h0 # => true
* h1 >= h0 # => false
*
- * See {Hash Inclusion}[rdoc-ref:hash_inclusion.rdoc].
+ * See {Hash Inclusion}[rdoc-ref:language/hash_inclusion.rdoc].
*
* Raises TypeError if +other_hash+ is not a hash and cannot be converted to a hash.
*
@@ -5002,20 +4972,19 @@ rb_hash_ge(VALUE hash, VALUE other)
/*
* call-seq:
- * self > other_hash -> true or false
+ * self > other -> true or false
*
- * Returns +true+ if the entries of +self+ are a proper superset of the entries of +other_hash+,
- * +false+ otherwise:
+ * Returns whether the entries of +self+ are a proper superset of the entries of +other+:
*
* h = {foo: 0, bar: 1, baz: 2}
* h > {foo: 0, bar: 1} # => true # Proper superset.
* h > {bar: 1, foo: 0} # => true # Order may differ.
* h > h # => false # Not a proper superset.
* h > {baz: 2, bar: 1, foo: 0} # => false # Not a proper superset.
- * h > {foo: 0, bar: 1} # => false # Different key.
- * h > {foo: 0, bar: 1} # => false # Different value.
+ * h > {foo: 0, bat: 1} # => false # Different key.
+ * h > {foo: 0, bar: 3} # => false # Different value.
*
- * See {Hash Inclusion}[rdoc-ref:hash_inclusion.rdoc].
+ * See {Hash Inclusion}[rdoc-ref:language/hash_inclusion.rdoc].
*
* Raises TypeError if +other_hash+ is not a hash and cannot be converted to a hash.
*
@@ -5048,6 +5017,8 @@ hash_proc_call(RB_BLOCK_CALL_FUNC_ARGLIST(key, hash))
* proc.call(:foo) # => 0
* proc.call(:bar) # => 1
* proc.call(:nosuch) # => nil
+ * h.default_proc = proc { |hash, key| "Missing key: #{key}" } # This affect the existing proc object
+ * proc.call(:nosuch) # => "Missing key: #{nosuch}"
*
* Related: see {Methods for Converting}[rdoc-ref:Hash@Methods+for+Converting].
*/
@@ -5138,6 +5109,14 @@ rb_hash_bulk_insert(long argc, const VALUE *argv, VALUE hash)
}
}
+VALUE
+rb_hash_new_with_bulk_insert(long argc, const VALUE *argv)
+{
+ VALUE val = rb_hash_new_with_size(argc / 2);
+ rb_hash_bulk_insert(argc, argv, val);
+ return val;
+}
+
static char **origenviron;
#ifdef _WIN32
#define GET_ENVIRON(e) ((e) = rb_w32_get_environ())
@@ -5368,7 +5347,7 @@ static VALUE
env_fetch(int argc, VALUE *argv, VALUE _)
{
VALUE key;
- long block_given;
+ int block_given;
const char *nam;
VALUE env;
@@ -5391,6 +5370,42 @@ env_fetch(int argc, VALUE *argv, VALUE _)
return env;
}
+/*
+ * call-seq:
+ * ENV.fetch_values(*names) -> array of values
+ * ENV.fetch_values(*names) {|name| ... } -> array of values
+ *
+ * Returns an Array containing the environment variable values associated with
+ * the given names:
+ * ENV.replace('foo' => '0', 'bar' => '1', 'baz' => '2')
+ * ENV.fetch_values('foo', 'baz') # => ["0", "2"]
+ *
+ * Otherwise if a block is given yields +name+ to
+ * the block and returns the block's return value:
+ * ENV.fetch_values('foo', 'bam') {|key| key.to_s} # => ["0", "bam"]
+ *
+ * Raises KeyError if +name+ is valid, but not found and block is not given:
+ * ENV.fetch_values('foo', 'bam') # Raises KeyError (key not found: "bam")
+ *
+ * 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].
+ */
+
+static VALUE
+env_fetch_values(int argc, VALUE *argv, VALUE ehash)
+{
+ VALUE result = rb_ary_new2(argc);
+ long i;
+
+ for (i=0; i<argc; i++) {
+ rb_ary_push(result, env_fetch(1, &argv[i], ehash));
+ }
+
+ return result;
+}
+
#if defined(_WIN32) || (defined(HAVE_SETENV) && defined(HAVE_UNSETENV))
#elif defined __sun
static int
@@ -6470,7 +6485,7 @@ env_rassoc(VALUE dmy, VALUE obj)
while (*env) {
const char *p = *env;
- char *s = strchr(p, '=');
+ const char *s = strchr(p, '=');
if (s++) {
long len = strlen(s);
if (RSTRING_LEN(obj) == len && strncmp(s, RSTRING_PTR(obj), len) == 0) {
@@ -6690,7 +6705,7 @@ env_shift(VALUE _)
char **env = GET_ENVIRON(environ);
if (*env) {
const char *p = *env;
- char *s = strchr(p, '=');
+ const char *s = strchr(p, '=');
if (s) {
key = env_str_new(p, s-p, enc);
VALUE val = env_str_new2(getenv(RSTRING_PTR(key)), enc);
@@ -6912,7 +6927,7 @@ static const rb_data_type_t env_data_type = {
* A \Hash object 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.
*
@@ -7248,8 +7263,8 @@ static const rb_data_type_t env_data_type = {
*
* 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],
+ * - Inherits from {class Object}[rdoc-ref:Object@Whats+Here].
+ * - Includes {module Enumerable}[rdoc-ref:Enumerable@Whats+Here],
* which provides dozens of additional methods.
*
* Here, class +Hash+ provides methods that are useful for:
@@ -7313,7 +7328,7 @@ static const rb_data_type_t env_data_type = {
* - #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.
- * - #values: Returns an array containing all values in +self+/
+ * - #values: Returns an array containing all values in +self+.
* - #values_at: Returns an array containing values for given keys.
*
* ==== Methods for Assigning
@@ -7362,7 +7377,6 @@ static const rb_data_type_t env_data_type = {
*
* ==== Methods for Transforming Keys and Values
*
- * - #flatten!: Returns +self+, flattened.
* - #invert: Returns a hash with the each key-value pair inverted.
* - #transform_keys: Returns a copy of +self+ with modified keys.
* - #transform_keys!: Modifies keys in +self+
@@ -7474,7 +7488,8 @@ 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_cHash_empty_frozen = rb_hash_freeze(rb_hash_alloc_fixed_size(rb_cHash, 0));
+ RB_OBJ_SET_SHAREABLE(rb_cHash_empty_frozen);
rb_vm_register_global_object(rb_cHash_empty_frozen);
/* Document-class: ENV
@@ -7560,8 +7575,8 @@ Init_Hash(void)
*
* 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],
+ * - Inherits from {class Object}[rdoc-ref:Object@Whats+Here].
+ * - Extends {module Enumerable}[rdoc-ref:Enumerable@Whats+Here],
*
* Here, class +ENV+ provides methods that are useful for:
*
@@ -7613,6 +7628,7 @@ Init_Hash(void)
* - ::clone: Raises an exception.
* - ::except: Returns a hash of all name/value pairs except those given.
* - ::fetch: Returns the value for the given name.
+ * - ::fetch_values: Returns array containing the values associated with given 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.
@@ -7644,11 +7660,11 @@ Init_Hash(void)
origenviron = environ;
envtbl = TypedData_Wrap_Struct(rb_cObject, &env_data_type, NULL);
rb_extend_object(envtbl, rb_mEnumerable);
- FL_SET_RAW(envtbl, RUBY_FL_SHAREABLE);
-
+ RB_OBJ_SET_SHAREABLE(envtbl);
rb_define_singleton_method(envtbl, "[]", rb_f_getenv, 1);
rb_define_singleton_method(envtbl, "fetch", env_fetch, -1);
+ rb_define_singleton_method(envtbl, "fetch_values", env_fetch_values, -1);
rb_define_singleton_method(envtbl, "[]=", env_aset_m, 2);
rb_define_singleton_method(envtbl, "store", env_aset_m, 2);
rb_define_singleton_method(envtbl, "each", env_each_pair, 0);
diff --git a/hash.rb b/hash.rb
index 99b34a9bda..40f823783e 100644
--- a/hash.rb
+++ b/hash.rb
@@ -7,7 +7,7 @@ class Hash
#
# Initializes the values of Hash#default and Hash#default_proc,
# which determine the behavior when a given key is not found;
- # see {Key Not Found?}[rdoc-ref:Hash@Key+Not+Found-3F].
+ # see {Key Not Found?}[rdoc-ref:Hash@Key+Not+Found].
#
# By default, a hash has +nil+ values for both +default+ and +default_proc+:
#
diff --git a/id_table.c b/id_table.c
index b705873191..299b7d3ae5 100644
--- a/id_table.c
+++ b/id_table.c
@@ -38,13 +38,6 @@ typedef struct rb_id_item {
VALUE val;
} item_t;
-struct rb_id_table {
- int capa;
- int num;
- int used;
- item_t *items;
-};
-
#if SIZEOF_VALUE == 8
#define ITEM_GET_KEY(tbl, i) ((tbl)->items[i].key)
#define ITEM_KEY_ISSET(tbl, i) ((tbl)->items && (tbl)->items[i].key)
@@ -353,7 +346,7 @@ const rb_data_type_t rb_managed_id_table_type = {
.wrap_struct_name = "VM/managed_id_table",
.function = {
.dmark = NULL, // Nothing to mark
- .dfree = (RUBY_DATA_FUNC)managed_id_table_free,
+ .dfree = managed_id_table_free,
.dsize = managed_id_table_memsize,
},
.flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_EMBEDDABLE,
@@ -373,7 +366,8 @@ rb_managed_id_table_create(const rb_data_type_t *type, size_t capa)
{
struct rb_id_table *tbl;
VALUE obj = TypedData_Make_Struct(0, struct rb_id_table, type, tbl);
- rb_id_table_init(tbl, capa);
+ RB_OBJ_SET_SHAREABLE(obj);
+ rb_id_table_init(tbl, capa); // NOTE: this can cause GC, so dmark and dsize need to check tbl->items
return obj;
}
@@ -437,3 +431,82 @@ rb_managed_id_table_delete(VALUE table, ID id)
{
return rb_id_table_delete(managed_id_table_ptr(table), id);
}
+
+static enum rb_id_table_iterator_result
+marked_id_table_mark_i(VALUE val, void *data)
+{
+ rb_gc_mark_movable(val);
+ return ID_TABLE_CONTINUE;
+}
+
+static void
+marked_id_table_mark(void *ptr)
+{
+ struct rb_id_table *tbl = (struct rb_id_table *)ptr;
+ rb_id_table_foreach_values(tbl, marked_id_table_mark_i, NULL);
+}
+
+static enum rb_id_table_iterator_result
+marked_id_table_compact_check_i(VALUE value, void *data)
+{
+ if (rb_gc_location(value) != value) {
+ return ID_TABLE_REPLACE;
+ }
+ return ID_TABLE_CONTINUE;
+}
+
+static enum rb_id_table_iterator_result
+marked_id_table_compact_replace_i(VALUE *value, void *data, int existing)
+{
+ *value = rb_gc_location(*value);
+ return ID_TABLE_CONTINUE;
+}
+
+static void
+marked_id_table_compact(void *ptr)
+{
+ struct rb_id_table *tbl = (struct rb_id_table *)ptr;
+ rb_id_table_foreach_values_with_replace(tbl, marked_id_table_compact_check_i, marked_id_table_compact_replace_i, NULL);
+}
+
+const rb_data_type_t rb_marked_id_table_type = {
+ .wrap_struct_name = "VM/marked_id_table",
+ .function = {
+ .dmark = marked_id_table_mark,
+ .dfree = managed_id_table_free,
+ .dsize = managed_id_table_memsize,
+ .dcompact = marked_id_table_compact,
+ },
+ .parent = &rb_managed_id_table_type,
+ .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_EMBEDDABLE,
+};
+
+VALUE
+rb_marked_id_table_new(size_t capa)
+{
+ return rb_managed_id_table_create(&rb_marked_id_table_type, capa);
+}
+
+int
+rb_marked_id_table_insert(VALUE table, ID id, VALUE val)
+{
+ int result = rb_managed_id_table_insert(table, id, val);
+ RB_OBJ_WRITTEN(table, Qundef, val);
+ return result;
+}
+
+static enum rb_id_table_iterator_result
+marked_id_table_dup_i(VALUE val, void *data)
+{
+ VALUE new_table = (VALUE)data;
+ RB_OBJ_WRITTEN(new_table, Qundef, val);
+ return ID_TABLE_CONTINUE;
+}
+
+VALUE
+rb_marked_id_table_dup(VALUE old_table)
+{
+ VALUE new_table = rb_managed_id_table_dup(old_table);
+ rb_managed_id_table_foreach_values(new_table, marked_id_table_dup_i, (void *)new_table);
+ return new_table;
+}
diff --git a/id_table.h b/id_table.h
index 0c8cd343ee..c4333bea98 100644
--- a/id_table.h
+++ b/id_table.h
@@ -4,7 +4,14 @@
#include <stddef.h>
#include "ruby/ruby.h"
-struct rb_id_table;
+struct rb_id_item;
+
+struct rb_id_table {
+ int capa;
+ int num;
+ int used;
+ struct rb_id_item *items;
+};
/* compatible with ST_* */
enum rb_id_table_iterator_result {
@@ -47,6 +54,16 @@ int rb_managed_id_table_delete(VALUE table, ID id);
extern const rb_data_type_t rb_managed_id_table_type;
+VALUE rb_marked_id_table_new(size_t capa);
+int rb_marked_id_table_insert(VALUE table, ID id, VALUE val);
+VALUE rb_marked_id_table_dup(VALUE table);
+
+// alisases
+#define rb_marked_id_table_size rb_managed_id_table_size
+#define rb_marked_id_table_lookup rb_managed_id_table_lookup
+#define rb_marked_id_table_foreach rb_managed_id_table_foreach
+#define rb_marked_id_table_foreach_values rb_managed_id_table_foreach_values
+
RUBY_SYMBOL_EXPORT_BEGIN
size_t rb_id_table_size(const struct rb_id_table *tbl);
RUBY_SYMBOL_EXPORT_END
diff --git a/imemo.c b/imemo.c
index 2fde22a3db..796e078c89 100644
--- a/imemo.c
+++ b/imemo.c
@@ -29,7 +29,10 @@ rb_imemo_name(enum imemo_type type)
IMEMO_NAME(svar);
IMEMO_NAME(throw_data);
IMEMO_NAME(tmpbuf);
+ IMEMO_NAME(cvar_entry);
IMEMO_NAME(fields);
+ IMEMO_NAME(subclasses);
+ IMEMO_NAME(cdhash);
#undef IMEMO_NAME
}
rb_bug("unreachable");
@@ -40,110 +43,125 @@ rb_imemo_name(enum imemo_type type)
* ========================================================================= */
VALUE
-rb_imemo_new(enum imemo_type type, VALUE v0, size_t size)
+rb_imemo_new(enum imemo_type type, VALUE v0, size_t size, bool is_shareable)
{
- VALUE flags = T_IMEMO | FL_WB_PROTECTED | (type << FL_USHIFT);
- NEWOBJ_OF(obj, void, v0, flags, size, 0);
-
- return (VALUE)obj;
+ VALUE flags = T_IMEMO | (type << FL_USHIFT) | (is_shareable ? FL_SHAREABLE : 0);
+ return rb_newobj_of(v0, flags, size);
}
-static rb_imemo_tmpbuf_t *
+VALUE
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);
+ UNPROTECTED_NEWOBJ_OF(obj, rb_imemo_tmpbuf_t, 0, flags, sizeof(rb_imemo_tmpbuf_t));
+
+ rb_gc_register_pinning_obj((VALUE)obj);
+
+ obj->ptr = NULL;
+ obj->size = 0;
- return obj;
+ return (VALUE)obj;
}
void *
-rb_alloc_tmp_buffer_with_count(volatile VALUE *store, size_t size, size_t cnt)
+rb_alloc_tmp_buffer(volatile VALUE *store, long len)
{
- void *ptr;
- rb_imemo_tmpbuf_t *tmpbuf;
+ if (len < 0) {
+ rb_raise(rb_eArgError, "negative buffer size (or size too big)");
+ }
/* Keep the order; allocate an empty imemo first then xmalloc, to
* get rid of potential memory leak */
- tmpbuf = rb_imemo_tmpbuf_new();
+ rb_imemo_tmpbuf_t *tmpbuf = (rb_imemo_tmpbuf_t *)rb_imemo_tmpbuf_new();
*store = (VALUE)tmpbuf;
- ptr = ruby_xmalloc(size);
+ void *ptr = ruby_xmalloc(len);
tmpbuf->ptr = ptr;
- tmpbuf->cnt = cnt;
+ tmpbuf->size = len;
return ptr;
}
void *
-rb_alloc_tmp_buffer(volatile VALUE *store, long len)
+rb_alloc_tmp_buffer_with_count(volatile VALUE *store, size_t size, size_t cnt)
{
- 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);
+ return rb_alloc_tmp_buffer(store, (long)size);
}
void
rb_free_tmp_buffer(volatile VALUE *store)
{
+ if (!*store) return;
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);
+ long size = s->size;
+ s->size = 0;
+ ruby_xfree_sized(ptr, size);
}
}
-rb_imemo_tmpbuf_t *
-rb_imemo_tmpbuf_parser_heap(void *buf, rb_imemo_tmpbuf_t *old_heap, size_t cnt)
+struct MEMO *
+rb_imemo_memo_new(VALUE a, VALUE b, long c)
{
- rb_imemo_tmpbuf_t *tmpbuf = rb_imemo_tmpbuf_new();
- tmpbuf->ptr = buf;
- tmpbuf->next = old_heap;
- tmpbuf->cnt = cnt;
+ struct MEMO *memo = IMEMO_NEW(struct MEMO, imemo_memo, 0);
+
+ *((VALUE *)&memo->v1) = a;
+ *((VALUE *)&memo->v2) = b;
+ memo->u3.cnt = c;
- return tmpbuf;
+ return memo;
}
-static VALUE
-imemo_fields_new(VALUE owner, size_t capa)
+struct MEMO *
+rb_imemo_memo_new_value(VALUE a, VALUE b, VALUE c)
{
- size_t embedded_size = offsetof(struct rb_fields, as.embed) + capa * sizeof(VALUE);
- if (rb_gc_size_allocatable_p(embedded_size)) {
- VALUE fields = rb_imemo_new(imemo_fields, owner, embedded_size);
- RUBY_ASSERT(IMEMO_TYPE_P(fields, imemo_fields));
- return fields;
- }
- else {
- VALUE fields = rb_imemo_new(imemo_fields, owner, sizeof(struct rb_fields));
- FL_SET_RAW(fields, OBJ_FIELD_EXTERNAL);
- IMEMO_OBJ_FIELDS(fields)->as.external.ptr = ALLOC_N(VALUE, capa);
- return fields;
- }
+ struct MEMO *memo = IMEMO_NEW(struct MEMO, imemo_memo, 0);
+
+ *((VALUE *)&memo->v1) = a;
+ *((VALUE *)&memo->v2) = b;
+ *((VALUE *)&memo->u3.value) = c;
+ memo->flags |= MEMO_U3_IS_VALUE;
+
+ return memo;
}
VALUE
-rb_imemo_fields_new(VALUE owner, size_t capa)
+rb_imemo_cdhash_new(size_t size, const struct st_hash_type *type)
{
- return imemo_fields_new(owner, capa);
+ struct rb_imemo_cdhash *memo = IMEMO_NEW(struct rb_imemo_cdhash, imemo_cdhash, 0);
+ memo->tbl.num_entries = 0;
+ st_init_existing_table_with_size(&memo->tbl, type, size);
+ return (VALUE)memo;
}
-static VALUE
-imemo_fields_new_complex(VALUE owner, size_t capa)
+VALUE
+rb_imemo_fields_new(VALUE owner, shape_id_t shape_id, bool shareable)
{
- VALUE fields = imemo_fields_new(owner, sizeof(struct rb_fields));
- IMEMO_OBJ_FIELDS(fields)->as.complex.table = st_init_numtable_with_size(capa);
+ size_t capa = RSHAPE_CAPACITY(shape_id);
+ size_t embedded_size = offsetof(struct rb_fields, as.embed) + capa * sizeof(VALUE);
+ RUBY_ASSERT(rb_gc_size_allocatable_p(embedded_size));
+ VALUE fields = rb_imemo_new(imemo_fields, owner, embedded_size, shareable);
+ // imemo fields objects should always have "RObject" layout. The
+ // layout in the shape describes the layout of the thing on which it is set.
+ // Imemo fields have the same layout as robject, therefore the layout
+ // should reflect that fact.
+ RBASIC_SET_SHAPE_ID(fields, rb_shape_id_with_robject_layout(shape_id));
+ RUBY_ASSERT(IMEMO_TYPE_P(fields, imemo_fields));
return fields;
}
VALUE
-rb_imemo_fields_new_complex(VALUE owner, size_t capa)
+rb_imemo_fields_new_complex(VALUE owner, shape_id_t shape_id, size_t capa, bool shareable)
{
- return imemo_fields_new_complex(owner, capa);
+ VALUE fields = rb_imemo_new(imemo_fields, owner, sizeof(struct rb_fields), shareable);
+ IMEMO_OBJ_FIELDS(fields)->as.complex.table = st_init_numtable_with_size(capa);
+ FL_SET_RAW(fields, OBJ_FIELD_HEAP);
+ // imemo fields objects should always have "RObject" layout. The
+ // layout in the shape describes the layout of the thing on which it is set.
+ // Imemo fields have the same layout as robject, therefore the layout
+ // should reflect that fact.
+ RBASIC_SET_SHAPE_ID(fields, rb_shape_id_with_robject_layout(shape_id));
+ return fields;
}
static int
@@ -162,10 +180,16 @@ imemo_fields_complex_wb_i(st_data_t key, st_data_t value, st_data_t arg)
}
VALUE
-rb_imemo_fields_new_complex_tbl(VALUE owner, st_table *tbl)
+rb_imemo_fields_new_complex_tbl(VALUE owner, shape_id_t shape_id, st_table *tbl, bool shareable)
{
- VALUE fields = imemo_fields_new(owner, sizeof(struct rb_fields));
+ VALUE fields = rb_imemo_new(imemo_fields, owner, sizeof(struct rb_fields), shareable);
IMEMO_OBJ_FIELDS(fields)->as.complex.table = tbl;
+ FL_SET_RAW(fields, OBJ_FIELD_HEAP);
+ // imemo fields objects should always have "RObject" layout. The
+ // layout in the shape describes the layout of the thing on which it is set.
+ // Imemo fields have the same layout as robject, therefore the layout
+ // should reflect that fact.
+ RBASIC_SET_SHAPE_ID(fields, rb_shape_id_with_robject_layout(shape_id));
st_foreach(tbl, imemo_fields_trigger_wb_i, (st_data_t)fields);
return fields;
}
@@ -176,17 +200,18 @@ rb_imemo_fields_clone(VALUE fields_obj)
shape_id_t shape_id = RBASIC_SHAPE_ID(fields_obj);
VALUE clone;
- if (rb_shape_too_complex_p(shape_id)) {
- clone = rb_imemo_fields_new_complex(rb_imemo_fields_owner(fields_obj), 0);
- RBASIC_SET_SHAPE_ID(clone, shape_id);
+ if (rb_shape_complex_p(shape_id)) {
st_table *src_table = rb_imemo_fields_complex_tbl(fields_obj);
- st_table *dest_table = rb_imemo_fields_complex_tbl(clone);
+
+ st_table *dest_table = xcalloc(1, sizeof(st_table));
+ clone = rb_imemo_fields_new_complex_tbl(rb_imemo_fields_owner(fields_obj), shape_id, dest_table, false /* TODO: check */);
+
st_replace(dest_table, src_table);
+
st_foreach(dest_table, imemo_fields_complex_wb_i, (st_data_t)clone);
}
else {
- clone = imemo_fields_new(rb_imemo_fields_owner(fields_obj), RSHAPE_CAPACITY(shape_id));
- RBASIC_SET_SHAPE_ID(clone, shape_id);
+ clone = rb_imemo_fields_new(rb_imemo_fields_owner(fields_obj), shape_id, false /* TODO: check */);
VALUE *fields = rb_imemo_fields_ptr(clone);
attr_index_t fields_count = RSHAPE_LEN(shape_id);
MEMCPY(fields, rb_imemo_fields_ptr(fields_obj), VALUE, fields_count);
@@ -203,8 +228,8 @@ rb_imemo_fields_clear(VALUE fields_obj)
{
// When replacing an imemo/fields by another one, we must clear
// its shape so that gc.c:obj_free_object_id won't be called.
- if (rb_shape_obj_too_complex_p(fields_obj)) {
- RBASIC_SET_SHAPE_ID(fields_obj, ROOT_TOO_COMPLEX_SHAPE_ID);
+ if (rb_obj_shape_complex_p(fields_obj)) {
+ RBASIC_SET_SHAPE_ID(fields_obj, ROOT_COMPLEX_SHAPE_ID);
}
else {
RBASIC_SET_SHAPE_ID(fields_obj, ROOT_SHAPE_ID);
@@ -213,6 +238,32 @@ rb_imemo_fields_clear(VALUE fields_obj)
RBASIC_CLEAR_CLASS(fields_obj);
}
+VALUE
+rb_imemo_subclasses_new(uint32_t capacity)
+{
+ size_t embed_size = offsetof(struct rb_subclasses, as) + capacity * sizeof(VALUE);
+ struct rb_subclasses *subs;
+
+ if (rb_gc_size_allocatable_p(embed_size)) {
+ subs = (struct rb_subclasses *)rb_imemo_new(imemo_subclasses, 0, embed_size, true);
+ subs->count = 0;
+ subs->capacity = capacity;
+ memset(subs->as.embed, 0, capacity * sizeof(VALUE));
+ rb_gc_declare_weak_references((VALUE)subs);
+ }
+ else {
+ subs = (struct rb_subclasses *)rb_imemo_new(imemo_subclasses, 0, sizeof(struct rb_subclasses), true);
+ subs->as.external = NULL;
+ subs->count = 0;
+ subs->capacity = 0;
+ FL_SET_RAW((VALUE)subs, IMEMO_SUBCLASSES_HEAP);
+ rb_gc_declare_weak_references((VALUE)subs);
+ subs->as.external = ZALLOC_N(VALUE, capacity);
+ subs->capacity = capacity;
+ }
+ return (VALUE)subs;
+}
+
/* =========================================================================
* memsize
* ========================================================================= */
@@ -251,16 +302,28 @@ rb_imemo_memsize(VALUE obj)
case imemo_throw_data:
break;
case imemo_tmpbuf:
- size += ((rb_imemo_tmpbuf_t *)obj)->cnt * sizeof(VALUE);
+ size += ((rb_imemo_tmpbuf_t *)obj)->size;
break;
+ case imemo_cvar_entry:
+ break;
case imemo_fields:
- if (rb_shape_obj_too_complex_p(obj)) {
+ if (rb_obj_shape_complex_p(obj)) {
size += st_memsize(IMEMO_OBJ_FIELDS(obj)->as.complex.table);
}
- else if (FL_TEST_RAW(obj, OBJ_FIELD_EXTERNAL)) {
- size += RSHAPE_CAPACITY(RBASIC_SHAPE_ID(obj)) * sizeof(VALUE);
+
+ break;
+ case imemo_subclasses: {
+ if (FL_TEST_RAW(obj, IMEMO_SUBCLASSES_HEAP)) {
+ struct rb_subclasses *subs = (struct rb_subclasses *)obj;
+ size += subs->capacity * sizeof(VALUE);
}
+
+ break;
+ }
+ case imemo_cdhash:
+ size += st_memsize(rb_imemo_cdhash_tbl(obj)) - sizeof(st_table);
+
break;
default:
rb_bug("unreachable");
@@ -308,9 +371,8 @@ mark_and_move_method_entry(rb_method_entry_t *ment, bool reference_updating)
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);
+ if (!rb_gc_checking_shareable()) {
+ rb_gc_mark_and_move(&def->body.bmethod.proc);
}
break;
case VM_METHOD_TYPE_ALIAS:
@@ -378,7 +440,6 @@ rb_imemo_mark_and_move(VALUE obj, bool reference_updating)
RUBY_ASSERT(RB_TYPE_P(cc->klass, T_CLASS) || RB_TYPE_P(cc->klass, T_ICLASS));
RUBY_ASSERT(IMEMO_TYPE_P((VALUE)cc->cme_, imemo_ment));
- rb_gc_mark_weak((VALUE *)&cc->klass);
if ((vm_cc_super_p(cc) || vm_cc_refinement_p(cc))) {
rb_gc_mark_movable((VALUE)cc->cme_);
}
@@ -391,16 +452,27 @@ rb_imemo_mark_and_move(VALUE obj, bool reference_updating)
case imemo_constcache: {
struct iseq_inline_constant_cache_entry *ice = (struct iseq_inline_constant_cache_entry *)obj;
- rb_gc_mark_and_move(&ice->value);
+ if ((ice->flags & IMEMO_CONST_CACHE_SHAREABLE) ||
+ !rb_gc_checking_shareable()) {
+ 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);
+ if (!rb_gc_checking_shareable()) {
+ // cref->klass_or_self can be unshareable, but no way to access it from other ractors
+ rb_gc_mark_and_move(&cref->klass_or_self);
+ }
+
rb_gc_mark_and_move_ptr(&cref->next);
- rb_gc_mark_and_move(&cref->refinements);
+
+ // TODO: Ractor and refeinements are not resolved yet
+ if (!rb_gc_checking_shareable()) {
+ rb_gc_mark_and_move(&cref->refinements);
+ }
break;
}
@@ -418,6 +490,13 @@ rb_imemo_mark_and_move(VALUE obj, bool reference_updating)
rb_gc_mark_and_move_ptr(&env->iseq);
+ if (VM_ENV_LOCAL_P(env->ep) && VM_ENV_BOXED_P(env->ep)) {
+ const rb_box_t *box = VM_ENV_BOX(env->ep);
+ if (BOX_USER_P(box)) {
+ rb_gc_mark_and_move((VALUE *)&box->box_object);
+ }
+ }
+
if (reference_updating) {
((VALUE *)env->ep)[VM_ENV_DATA_INDEX_ENV] = rb_gc_location(env->ep[VM_ENV_DATA_INDEX_ENV]);
}
@@ -448,8 +527,8 @@ rb_imemo_mark_and_move(VALUE obj, bool reference_updating)
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);
+ if (FL_TEST_RAW(obj, MEMO_U3_IS_VALUE)) {
+ rb_gc_mark_and_move((VALUE *)&memo->u3.value);
}
break;
@@ -478,31 +557,62 @@ rb_imemo_mark_and_move(VALUE obj, bool reference_updating)
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);
+ rb_gc_mark_locations(m->ptr, m->ptr + (m->size / sizeof(VALUE)));
}
break;
}
+ case imemo_cvar_entry: {
+ struct rb_cvar_class_tbl_entry *ent = (struct rb_cvar_class_tbl_entry *)obj;
+ rb_gc_mark_and_move(&ent->class_value);
+ rb_gc_mark_and_move((VALUE *)&ent->cref);
+ break;
+ }
+ case imemo_subclasses: {
+ if (reference_updating) {
+ struct rb_subclasses *subs = (struct rb_subclasses *)obj;
+ VALUE *entries = rb_imemo_subclasses_entries(obj);
+ for (uint32_t i = 0; i < subs->count; i++) {
+ if (entries[i]) {
+ entries[i] = rb_gc_location(entries[i]);
+ }
+ }
+ }
+ break;
+ }
case imemo_fields: {
rb_gc_mark_and_move((VALUE *)&RBASIC(obj)->klass);
- if (rb_shape_obj_too_complex_p(obj)) {
- st_table *tbl = rb_imemo_fields_complex_tbl(obj);
- if (reference_updating) {
- rb_gc_ref_update_table_values_only(tbl);
+ if (!rb_gc_checking_shareable()) {
+ // imemo_fields can refer unshareable objects
+ // even if the imemo_fields is shareable.
+
+ if (rb_obj_shape_complex_p(obj)) {
+ st_table *tbl = rb_imemo_fields_complex_tbl(obj);
+ if (reference_updating) {
+ rb_gc_ref_update_table_values_only(tbl);
+ }
+ else {
+ rb_mark_tbl_no_pin(tbl);
+ }
}
else {
- rb_mark_tbl_no_pin(tbl);
+ VALUE *fields = rb_imemo_fields_ptr(obj);
+ attr_index_t len = RSHAPE_LEN(RBASIC_SHAPE_ID(obj));
+ for (attr_index_t i = 0; i < len; i++) {
+ rb_gc_mark_and_move(&fields[i]);
+ }
}
}
+ break;
+ }
+ case imemo_cdhash: {
+ st_table *tbl = rb_imemo_cdhash_tbl(obj);
+ if (reference_updating) {
+ rb_gc_update_set_refs(tbl);
+ }
else {
- VALUE *fields = rb_imemo_fields_ptr(obj);
- attr_index_t len = RSHAPE_LEN(RBASIC_SHAPE_ID(obj));
- for (attr_index_t i = 0; i < len; i++) {
- rb_gc_mark_and_move(&fields[i]);
- }
+ rb_gc_mark_set_no_pin(tbl);
}
break;
}
@@ -519,7 +629,7 @@ 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);
+ SIZED_FREE(ce);
return ID_TABLE_CONTINUE;
}
@@ -533,12 +643,10 @@ rb_free_const_table(struct rb_id_table *tbl)
static inline void
imemo_fields_free(struct rb_fields *fields)
{
- if (rb_shape_obj_too_complex_p((VALUE)fields)) {
+ if (FL_TEST_RAW((VALUE)fields, OBJ_FIELD_HEAP)) {
+ RUBY_ASSERT(rb_shape_complex_p(RBASIC_SHAPE_ID((VALUE)fields)));
st_free_table(fields->as.complex.table);
}
- else if (FL_TEST_RAW((VALUE)fields, OBJ_FIELD_EXTERNAL)) {
- xfree(fields->as.external.ptr);
- }
}
void
@@ -553,8 +661,9 @@ rb_imemo_free(VALUE obj)
const struct rb_callinfo *ci = ((const struct rb_callinfo *)obj);
if (ci->kwarg) {
- ((struct rb_callinfo_kwarg *)ci->kwarg)->references--;
- if (ci->kwarg->references == 0) xfree((void *)ci->kwarg);
+ if (RUBY_ATOMIC_FETCH_SUB(((struct rb_callinfo_kwarg *)ci->kwarg)->references, 1) == 1) {
+ ruby_xfree_sized((void *)ci->kwarg, rb_callinfo_kwarg_bytes(ci->kwarg->keyword_len));
+ }
}
RB_DEBUG_COUNTER_INC(obj_imemo_callinfo);
@@ -572,7 +681,7 @@ rb_imemo_free(VALUE obj)
rb_env_t *env = (rb_env_t *)obj;
RUBY_ASSERT(VM_ENV_ESCAPED_P(env->ep));
- xfree((VALUE *)env->env);
+ SIZED_FREE_N(env->env, env->env_size);
RB_DEBUG_COUNTER_INC(obj_imemo_env);
break;
@@ -603,13 +712,31 @@ rb_imemo_free(VALUE obj)
break;
case imemo_tmpbuf:
- xfree(((rb_imemo_tmpbuf_t *)obj)->ptr);
+ ruby_xfree_sized(((rb_imemo_tmpbuf_t *)obj)->ptr, ((rb_imemo_tmpbuf_t *)obj)->size);
RB_DEBUG_COUNTER_INC(obj_imemo_tmpbuf);
break;
+ case imemo_cvar_entry:
+ RB_DEBUG_COUNTER_INC(obj_imemo_cvar_entry);
+
+ break;
case imemo_fields:
imemo_fields_free(IMEMO_OBJ_FIELDS(obj));
RB_DEBUG_COUNTER_INC(obj_imemo_fields);
+
+ break;
+ case imemo_subclasses: {
+ if (FL_TEST_RAW(obj, IMEMO_SUBCLASSES_HEAP)) {
+ struct rb_subclasses *subs = (struct rb_subclasses *)obj;
+ SIZED_FREE_N(subs->as.external, subs->capacity);
+ }
+ RB_DEBUG_COUNTER_INC(obj_imemo_subclasses);
+ break;
+ }
+ case imemo_cdhash:
+ st_free_embedded_table(rb_imemo_cdhash_tbl(obj));
+ RB_DEBUG_COUNTER_INC(obj_imemo_cdhash);
+
break;
default:
rb_bug("unreachable");
diff --git a/include/ruby/atomic.h b/include/ruby/atomic.h
index c7043b0476..fcc48f532c 100644
--- a/include/ruby/atomic.h
+++ b/include/ruby/atomic.h
@@ -34,7 +34,7 @@
# include <sys/types.h> /* ssize_t */
#endif
-#if RBIMPL_COMPILER_SINCE(MSVC, 13, 0, 0)
+#if RBIMPL_COMPILER_IS(MSVC)
# pragma intrinsic(_InterlockedOr)
#elif defined(__sun) && defined(HAVE_ATOMIC_H)
# include <atomic.h>
@@ -790,22 +790,9 @@ rbimpl_atomic_or(volatile rb_atomic_t *ptr, rb_atomic_t val, int memory_order)
#elif defined(HAVE_GCC_SYNC_BUILTINS)
__sync_or_and_fetch(ptr, val);
-#elif RBIMPL_COMPILER_SINCE(MSVC, 13, 0, 0)
+#elif RBIMPL_COMPILER_IS(MSVC)
_InterlockedOr(ptr, val);
-#elif defined(_WIN32) && defined(__GNUC__)
- /* This was for old MinGW. Maybe not needed any longer? */
- __asm__(
- "lock\n\t"
- "orl\t%1, %0"
- : "=m"(ptr)
- : "Ir"(val));
-
-#elif defined(_WIN32) && defined(_M_IX86)
- __asm mov eax, ptr;
- __asm mov ecx, val;
- __asm lock or [eax], ecx;
-
#elif defined(__sun) && defined(HAVE_ATOMIC_H)
atomic_or_uint(ptr, val);
@@ -817,15 +804,6 @@ rbimpl_atomic_or(volatile rb_atomic_t *ptr, rb_atomic_t val, int memory_order)
#endif
}
-/* Nobody uses this but for theoretical backwards compatibility... */
-#if RBIMPL_COMPILER_BEFORE(MSVC, 13, 0, 0)
-static inline rb_atomic_t
-rb_w32_atomic_or(volatile rb_atomic_t *var, rb_atomic_t val)
-{
- return rbimpl_atomic_or(var, val);
-}
-#endif
-
RBIMPL_ATTR_ARTIFICIAL()
RBIMPL_ATTR_NOALIAS()
RBIMPL_ATTR_NONNULL((1))
@@ -1031,16 +1009,9 @@ rbimpl_atomic_cas(volatile rb_atomic_t *ptr, rb_atomic_t oldval, rb_atomic_t new
#elif defined(HAVE_GCC_SYNC_BUILTINS)
return __sync_val_compare_and_swap(ptr, oldval, newval);
-#elif RBIMPL_COMPILER_SINCE(MSVC, 13, 0, 0)
+#elif RBIMPL_COMPILER_IS(MSVC)
return InterlockedCompareExchange(ptr, newval, oldval);
-#elif defined(_WIN32)
- PVOID *pptr = RBIMPL_CAST((PVOID *)ptr);
- PVOID pold = RBIMPL_CAST((PVOID)oldval);
- PVOID pnew = RBIMPL_CAST((PVOID)newval);
- PVOID pret = InterlockedCompareExchange(pptr, pnew, pold);
- return RBIMPL_CAST((rb_atomic_t)pret);
-
#elif defined(__sun) && defined(HAVE_ATOMIC_H)
return atomic_cas_uint(ptr, oldval, newval);
@@ -1054,15 +1025,6 @@ rbimpl_atomic_cas(volatile rb_atomic_t *ptr, rb_atomic_t oldval, rb_atomic_t new
#endif
}
-/* Nobody uses this but for theoretical backwards compatibility... */
-#if RBIMPL_COMPILER_BEFORE(MSVC, 13, 0, 0)
-static inline rb_atomic_t
-rb_w32_atomic_cas(volatile rb_atomic_t *var, rb_atomic_t oldval, rb_atomic_t newval)
-{
- return rbimpl_atomic_cas(var, oldval, newval);
-}
-#endif
-
RBIMPL_ATTR_ARTIFICIAL()
RBIMPL_ATTR_NOALIAS()
RBIMPL_ATTR_NONNULL((1))
diff --git a/include/ruby/backward.h b/include/ruby/backward.h
index f804c2c36e..6726102158 100644
--- a/include/ruby/backward.h
+++ b/include/ruby/backward.h
@@ -11,12 +11,6 @@
#include "ruby/internal/interpreter.h"
#include "ruby/backward/2/attributes.h"
-#define RBIMPL_ATTR_DEPRECATED_SINCE(ver) RBIMPL_ATTR_DEPRECATED(("since " #ver))
-#define RBIMPL_ATTR_DEPRECATED_INTERNAL(ver) RBIMPL_ATTR_DEPRECATED(("since "#ver", also internal"))
-#define RBIMPL_ATTR_DEPRECATED_INTERNAL_ONLY() RBIMPL_ATTR_DEPRECATED(("only for internal use"))
-
-RBIMPL_ATTR_DEPRECATED_INTERNAL_ONLY() void rb_clear_constant_cache(void);
-
/* from version.c */
#if defined(RUBY_SHOW_COPYRIGHT_TO_DIE) && !!(RUBY_SHOW_COPYRIGHT_TO_DIE+0)
# error RUBY_SHOW_COPYRIGHT_TO_DIE is deprecated
diff --git a/include/ruby/backward/cxxanyargs.hpp b/include/ruby/backward/cxxanyargs.hpp
index 2414b7ae6d..0ca2745c20 100644
--- a/include/ruby/backward/cxxanyargs.hpp
+++ b/include/ruby/backward/cxxanyargs.hpp
@@ -190,33 +190,6 @@ rb_define_hooked_variable(const char *q, VALUE *w, std::nullptr_t e, void_type *
/// @name Exceptions and tag jumps
/// @{
-// RUBY_CXX_DEPRECATED("by rb_block_call since 1.9")
-RUBY_CXX_DEPRECATED("Use of ANYARGS in this function is deprecated")
-/// @brief Old way to implement iterators.
-/// @param[in] q A function that can yield.
-/// @param[in] w Passed to `q`.
-/// @param[in] e What is to be yielded.
-/// @param[in] r Passed to `e`.
-/// @return The return value of `q`.
-/// @note `e` can be nullptr.
-/// @deprecated This function is obsoleted since long before 2.x era. Do not
-/// use it any longer. rb_block_call() is provided instead.
-inline VALUE
-rb_iterate(onearg_type *q, VALUE w, type *e, VALUE r)
-{
- rb_block_call_func_t t = reinterpret_cast<rb_block_call_func_t>(e);
- return backward::rb_iterate_deprecated(q, w, t, r);
-}
-
-#ifdef HAVE_NULLPTR
-RUBY_CXX_DEPRECATED("by rb_block_call since 1.9")
-inline VALUE
-rb_iterate(onearg_type *q, VALUE w, std::nullptr_t e, VALUE r)
-{
- return backward::rb_iterate_deprecated(q, w, e, r);
-}
-#endif
-
RUBY_CXX_DEPRECATED("Use of ANYARGS in this function is deprecated")
/// @brief Call a method with a block.
/// @param[in] q The self.
@@ -537,9 +510,7 @@ struct driver {
* this writing the version is 2.8. Let's warn this later, some time
* during 3.x. Hopefully codes in old (ANYARGS-ed) format should be
* less than now. */
-#if (RUBY_API_VERSION_MAJOR * 100 + RUBY_API_VERSION_MINOR) >= 301
RUBY_CXX_DEPRECATED("use of ANYARGS is deprecated")
-#endif
/// @copydoc define(VALUE klass, T mid, U func)
/// @deprecated Pass correctly typed function instead.
static inline void
diff --git a/include/ruby/debug.h b/include/ruby/debug.h
index 0a9f693951..27a7a5f2c1 100644
--- a/include/ruby/debug.h
+++ b/include/ruby/debug.h
@@ -297,7 +297,7 @@ VALUE rb_debug_inspector_frame_depth(const rb_debug_inspector_t *dc, long index)
#define RB_DEBUG_INSPECTOR_FRAME_DEPTH(dc, index) rb_debug_inspector_frame_depth(dc, index)
/**
- * Return current frmae depth.
+ * Return current frame depth.
*
* @retval The depth of the current frame in Integer.
*/
@@ -754,59 +754,6 @@ rb_postponed_job_handle_t rb_postponed_job_preregister(unsigned int flags, rb_po
*/
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] 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.
- */
- 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`
- *
- * @param[in] flags Unused and ignored.
- * @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.
- */
- 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 b06884f596..4d764f68ae 100644
--- a/include/ruby/fiber/scheduler.h
+++ b/include/ruby/fiber/scheduler.h
@@ -27,6 +27,7 @@ RBIMPL_SYMBOL_EXPORT_BEGIN()
#define RUBY_FIBER_SCHEDULER_VERSION 3
struct timeval;
+struct rb_thread_struct;
/**
* Wrap a `ssize_t` and `int errno` into a single `VALUE`. This interface should
@@ -118,7 +119,7 @@ VALUE rb_fiber_scheduler_current(void);
/**
* Identical to rb_fiber_scheduler_current(), except it queries for that of the
- * passed thread instead of the implicit current one.
+ * passed thread value instead of the implicit current one.
*
* @param[in] thread Target thread.
* @exception rb_eTypeError `thread` is not a thread.
@@ -128,6 +129,17 @@ VALUE rb_fiber_scheduler_current(void);
VALUE rb_fiber_scheduler_current_for_thread(VALUE thread);
/**
+ * Identical to rb_fiber_scheduler_current_for_thread(), except it expects
+ * a threadptr instead of a thread value.
+ *
+ * @param[in] thread Target thread.
+ * @exception rb_eTypeError `thread` is not a thread.
+ * @retval RUBY_Qnil No scheduler is in effect in `thread`.
+ * @retval otherwise The scheduler that is in effect in `thread`.
+ */
+VALUE rb_fiber_scheduler_current_for_threadptr(struct rb_thread_struct *thread);
+
+/**
* Converts the passed timeout to an expression that rb_fiber_scheduler_block()
* etc. expects.
*
@@ -167,6 +179,14 @@ VALUE rb_fiber_scheduler_kernel_sleep(VALUE scheduler, VALUE duration);
*/
VALUE rb_fiber_scheduler_kernel_sleepv(VALUE scheduler, int argc, VALUE * argv);
+/**
+ * Yield to the scheduler, to be resumed on the next scheduling cycle.
+ *
+ * @param[in] scheduler Target scheduler.
+ * @return What `scheduler.yield` returns.
+ */
+VALUE rb_fiber_scheduler_yield(VALUE scheduler);
+
/* Description TBW */
#if 0
VALUE rb_fiber_scheduler_timeout_after(VALUE scheduler, VALUE timeout, VALUE exception, VALUE message);
diff --git a/include/ruby/internal/arithmetic/intptr_t.h b/include/ruby/internal/arithmetic/intptr_t.h
index a354f4469c..70090f88e6 100644
--- a/include/ruby/internal/arithmetic/intptr_t.h
+++ b/include/ruby/internal/arithmetic/intptr_t.h
@@ -32,6 +32,18 @@
#define rb_int_new rb_int2inum /**< @alias{rb_int2inum} */
#define rb_uint_new rb_uint2inum /**< @alias{rb_uint2inum} */
+// These definitions are same as fiddle/conversions.h
+#if SIZEOF_VOIDP <= SIZEOF_LONG
+# define PTR2NUM(x) (LONG2NUM((long)(x)))
+# define NUM2PTR(x) ((void*)(NUM2ULONG(x)))
+#elif SIZEOF_VOIDP <= SIZEOF_LONG_LONG
+# define PTR2NUM(x) (LL2NUM((LONG_LONG)(x)))
+# define NUM2PTR(x) ((void*)(NUM2ULL(x)))
+#else
+// should have been an error in ruby/internal/value.h
+# error Need integer for VALUE
+#endif
+
RBIMPL_SYMBOL_EXPORT_BEGIN()
/**
diff --git a/include/ruby/internal/attr/deprecated.h b/include/ruby/internal/attr/deprecated.h
index e1bbdbd15a..a374ace868 100644
--- a/include/ruby/internal/attr/deprecated.h
+++ b/include/ruby/internal/attr/deprecated.h
@@ -48,7 +48,7 @@
#elif RBIMPL_HAS_ATTRIBUTE(deprecated) /* but not with message. */
# define RBIMPL_ATTR_DEPRECATED(msg) __attribute__((__deprecated__))
-#elif RBIMPL_COMPILER_SINCE(MSVC, 14, 0, 0)
+#elif RBIMPL_COMPILER_IS(MSVC)
# define RBIMPL_ATTR_DEPRECATED(msg) __declspec(deprecated msg)
#elif RBIMPL_HAS_DECLSPEC_ATTRIBUTE(deprecated)
@@ -72,4 +72,11 @@
# define RBIMPL_ATTR_DEPRECATED_EXT(msg) RBIMPL_ATTR_DEPRECATED(msg)
#endif
+#define RBIMPL_ATTR_DEPRECATED_SINCE(ver) \
+ RBIMPL_ATTR_DEPRECATED(("since " #ver))
+#define RBIMPL_ATTR_DEPRECATED_INTERNAL(ver) \
+ RBIMPL_ATTR_DEPRECATED(("since "#ver", also internal"))
+#define RBIMPL_ATTR_DEPRECATED_INTERNAL_ONLY() \
+ RBIMPL_ATTR_DEPRECATED(("only for internal use"))
+
#endif /* RBIMPL_ATTR_DEPRECATED_H */
diff --git a/include/ruby/internal/attr/forceinline.h b/include/ruby/internal/attr/forceinline.h
index b7daafede7..5b9ae794af 100644
--- a/include/ruby/internal/attr/forceinline.h
+++ b/include/ruby/internal/attr/forceinline.h
@@ -29,7 +29,7 @@
* `__forceinline` are mutually exclusive. We have to mimic that behaviour for
* non-MSVC compilers.
*/
-#if RBIMPL_COMPILER_SINCE(MSVC, 12, 0, 0)
+#if RBIMPL_COMPILER_IS(MSVC)
# define RBIMPL_ATTR_FORCEINLINE() __forceinline
#elif RBIMPL_HAS_ATTRIBUTE(always_inline)
# define RBIMPL_ATTR_FORCEINLINE() __attribute__((__always_inline__)) inline
diff --git a/include/ruby/internal/attr/format.h b/include/ruby/internal/attr/format.h
index b3488ee00a..7feff1c846 100644
--- a/include/ruby/internal/attr/format.h
+++ b/include/ruby/internal/attr/format.h
@@ -22,6 +22,10 @@
*/
#include "ruby/internal/has/attribute.h"
+#if defined(__MINGW32__)
+#include <stdio.h> /* for __MINGW_PRINTF_FORMAT */
+#endif
+
/** Wraps (or simulates) `__attribute__((format))` */
#if RBIMPL_HAS_ATTRIBUTE(format)
# define RBIMPL_ATTR_FORMAT(x, y, z) __attribute__((__format__(x, y, z)))
diff --git a/include/ruby/internal/attr/noexcept.h b/include/ruby/internal/attr/noexcept.h
index 7c3f92f1e7..dd4c667407 100644
--- a/include/ruby/internal/attr/noexcept.h
+++ b/include/ruby/internal/attr/noexcept.h
@@ -78,7 +78,7 @@
#elif defined(__INTEL_CXX11_MODE__)
# define RBIMPL_ATTR_NOEXCEPT(_) noexcept(noexcept(_))
-#elif RBIMPL_COMPILER_SINCE(MSVC, 19, 0, 0)
+#elif RBIMPL_COMPILER_IS(MSVC)
# define RBIMPL_ATTR_NOEXCEPT(_) noexcept(noexcept(_))
#elif __cplusplus >= 201103L
diff --git a/include/ruby/internal/attr/nonstring.h b/include/ruby/internal/attr/nonstring.h
index 9a66180e19..da2501f7bf 100644
--- a/include/ruby/internal/attr/nonstring.h
+++ b/include/ruby/internal/attr/nonstring.h
@@ -27,6 +27,8 @@
# define RBIMPL_ATTR_NONSTRING() __attribute__((nonstring))
# if RBIMPL_COMPILER_SINCE(GCC, 15, 0, 0)
# define RBIMPL_ATTR_NONSTRING_ARRAY() RBIMPL_ATTR_NONSTRING()
+# elif defined(__clang_major__) && __clang_major__ >= 21
+# define RBIMPL_ATTR_NONSTRING_ARRAY() RBIMPL_ATTR_NONSTRING()
# else
# define RBIMPL_ATTR_NONSTRING_ARRAY() /* void */
# endif
diff --git a/include/ruby/internal/attr/restrict.h b/include/ruby/internal/attr/restrict.h
index e39104138c..b12fdc9dbc 100644
--- a/include/ruby/internal/attr/restrict.h
+++ b/include/ruby/internal/attr/restrict.h
@@ -28,7 +28,7 @@
* `__has_declspec_attribute()` which involves macro substitution. */
/** Wraps (or simulates) `__declspec(restrict)` */
-#if RBIMPL_COMPILER_SINCE(MSVC, 14, 0, 0)
+#if RBIMPL_COMPILER_IS(MSVC)
# define RBIMPL_ATTR_RESTRICT() __declspec(re ## strict)
#elif RBIMPL_HAS_ATTRIBUTE(malloc)
diff --git a/include/ruby/internal/compiler_is/msvc.h b/include/ruby/internal/compiler_is/msvc.h
index 8a864ea558..824f0ecc21 100644
--- a/include/ruby/internal/compiler_is/msvc.h
+++ b/include/ruby/internal/compiler_is/msvc.h
@@ -38,19 +38,8 @@
# define RBIMPL_COMPILER_VERSION_MINOR (_MSC_FULL_VER % 10000000 / 100000)
# define RBIMPL_COMPILER_VERSION_PATCH (_MSC_FULL_VER % 100000)
-#elif defined(_MSC_FULL_VER)
-# define RBIMPL_COMPILER_IS_MSVC 1
-# /* _MSC_FULL_VER = XXYYZZZZ */
-# define RBIMPL_COMPILER_VERSION_MAJOR (_MSC_FULL_VER / 1000000)
-# define RBIMPL_COMPILER_VERSION_MINOR (_MSC_FULL_VER % 1000000 / 10000)
-# define RBIMPL_COMPILER_VERSION_PATCH (_MSC_FULL_VER % 10000)
-
#else
-# define RBIMPL_COMPILER_IS_MSVC 1
-# /* _MSC_VER = XXYY */
-# define RBIMPL_COMPILER_VERSION_MAJOR (_MSC_VER / 100)
-# define RBIMPL_COMPILER_VERSION_MINOR (_MSC_VER % 100)
-# define RBIMPL_COMPILER_VERSION_PATCH 0
+# error Unsupported MSVC version
#endif
#endif /* RBIMPL_COMPILER_IS_MSVC_H */
diff --git a/include/ruby/internal/config.h b/include/ruby/internal/config.h
index da070f0979..34862ded6e 100644
--- a/include/ruby/internal/config.h
+++ b/include/ruby/internal/config.h
@@ -50,7 +50,7 @@
# define HAVE_VA_ARGS_MACRO
# elif defined(__INTEL_CXX11_MODE__)
# define HAVE_VA_ARGS_MACRO
-# elif RBIMPL_COMPILER_SINCE(MSVC, 16, 0, 0)
+# elif RBIMPL_COMPILER_IS(MSVC)
# define HAVE_VA_ARGS_MACRO
# else
# /* NG, not known. */
diff --git a/include/ruby/internal/core/rarray.h b/include/ruby/internal/core/rarray.h
index 73cc0f5dd9..b47b63d51b 100644
--- a/include/ruby/internal/core/rarray.h
+++ b/include/ruby/internal/core/rarray.h
@@ -367,7 +367,7 @@ RARRAY_PTR(VALUE ary)
{
RBIMPL_ASSERT_TYPE(ary, RUBY_T_ARRAY);
- VALUE tmp = RB_OBJ_WB_UNPROTECT_FOR(ARRAY, ary);
+ VALUE tmp = RB_OBJ_WB_UNPROTECT(ary);
return RBIMPL_CAST((VALUE *)RARRAY_CONST_PTR(tmp));
}
diff --git a/include/ruby/internal/core/rbasic.h b/include/ruby/internal/core/rbasic.h
index 35af03f7c8..63cdff8e09 100644
--- a/include/ruby/internal/core/rbasic.h
+++ b/include/ruby/internal/core/rbasic.h
@@ -115,6 +115,9 @@ RBasic {
#endif
{
}
+# define RBASIC_INIT RBasic()
+#else
+# define RBASIC_INIT {RBIMPL_VALUE_NULL}
#endif
};
diff --git a/include/ruby/internal/core/rdata.h b/include/ruby/internal/core/rdata.h
index f9ff3acc5f..d0a4dc7c83 100644
--- a/include/ruby/internal/core/rdata.h
+++ b/include/ruby/internal/core/rdata.h
@@ -42,31 +42,9 @@
#endif
#define RBIMPL_DATA_FUNC(f) RBIMPL_CAST((void (*)(void *))(f))
-#define RBIMPL_ATTRSET_UNTYPED_DATA_FUNC() \
- RBIMPL_ATTR_WARNING(("untyped Data is unsafe; use TypedData instead")) \
- RBIMPL_ATTR_DEPRECATED(("by TypedData"))
-
-#define RBIMPL_MACRO_SELECT(x, y) x ## y
-#define RUBY_MACRO_SELECT(x, y) RBIMPL_MACRO_SELECT(x, y)
/** @endcond */
/**
- * Convenient casting macro.
- *
- * @param obj An object, which is in fact an ::RData.
- * @return The passed object casted to ::RData.
- */
-#define RDATA(obj) RBIMPL_CAST((struct RData *)(obj))
-
-/**
- * Convenient getter macro.
- *
- * @param obj An object, which is in fact an ::RData.
- * @return The passed object's ::RData::data field.
- */
-#define DATA_PTR(obj) RDATA(obj)->data
-
-/**
* This is a value you can set to ::RData::dfree. Setting this means the data
* was allocated using ::ruby_xmalloc() (or variants), and shall be freed using
* ::ruby_xfree().
@@ -85,19 +63,6 @@
#define RUBY_NEVER_FREE RBIMPL_DATA_FUNC(0)
/**
- * @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 RUBY_UNTYPED_DATA_FUNC(f) f RBIMPL_ATTRSET_UNTYPED_DATA_FUNC()
-
-/*
-#define RUBY_DATA_FUNC(func) ((void (*)(void*))(func))
-*/
-
-/**
* This is the type of callbacks registered to ::RData. The argument is the
* `data` field.
*/
@@ -106,271 +71,16 @@ typedef void (*RUBY_DATA_FUNC)(void*);
/**
* @deprecated
*
- * Old "untyped" user data. It has roughly the same usage as struct
- * ::RTypedData, but lacked several features such as support for compaction GC.
- * Use of this struct is not recommended any longer. If it is dead necessary,
- * please inform the core devs about your usage.
- *
- * @internal
- *
- * @shyouhei tried to add RBIMPL_ATTR_DEPRECATED for this type but that yielded
- * too many warnings in the core. Maybe we want to retry later... Just add
- * deprecated document for now.
+ * DO NOT USE: Obsolete "untyped" user data, that is remained only for
+ * the backward compatibility for some wrapper generator gems.
*/
struct RData {
-
- /** Basic part, including flags and class. */
struct RBasic basic;
-
- /**
- * This function is called when the object is experiencing GC marks. If it
- * contains references to other Ruby objects, you need to mark them also.
- * Otherwise GC will smash your data.
- *
- * @see rb_gc_mark()
- * @warning This is called during GC runs. Object allocations are
- * impossible at that moment (that is why GC runs).
- */
+ VALUE fields_obj;
+ VALUE _reserved;
+ void *data;
RUBY_DATA_FUNC dmark;
-
- /**
- * This function is called when the object is no longer used. You need to
- * do whatever necessary to avoid memory leaks.
- *
- * @warning This is called during GC runs. Object allocations are
- * impossible at that moment (that is why GC runs).
- */
RUBY_DATA_FUNC dfree;
-
- /** Pointer to the actual C level struct that you want to wrap.
- * This is after dmark and dfree to allow DATA_PTR to continue to work for
- * both RData and non-embedded RTypedData.
- */
- void *data;
};
-RBIMPL_SYMBOL_EXPORT_BEGIN()
-
-/**
- * This is the primitive way to wrap an existing C struct into ::RData.
- *
- * @param[in] klass Ruby level class of the returning object.
- * @param[in] datap Pointer to the target C struct.
- * @param[in] dmark Mark function.
- * @param[in] dfree Free function.
- * @exception rb_eTypeError `klass` is not a class.
- * @exception rb_eNoMemError Out of memory.
- * @return An allocated object that wraps `datap`.
- */
-VALUE rb_data_object_wrap(VALUE klass, void *datap, RUBY_DATA_FUNC dmark, RUBY_DATA_FUNC dfree);
-
-/**
- * Identical to rb_data_object_wrap(), except it allocates a new data region
- * internally instead of taking an existing one. The allocation is done using
- * ruby_calloc(). Hence it makes no sense to pass anything other than
- * ::RUBY_DEFAULT_FREE to the last argument.
- *
- * @param[in] klass Ruby level class of the returning object.
- * @param[in] size Requested size of memory to allocate.
- * @param[in] dmark Mark function.
- * @param[in] dfree Free function.
- * @exception rb_eTypeError `klass` is not a class.
- * @exception rb_eNoMemError Out of memory.
- * @return An allocated object that wraps a new `size` byte region.
- */
-VALUE rb_data_object_zalloc(VALUE klass, size_t size, RUBY_DATA_FUNC dmark, RUBY_DATA_FUNC dfree);
-
-/**
- * @private
- * Documented in include/ruby/internal/globals.h
- */
-RUBY_EXTERN VALUE rb_cObject;
-RBIMPL_SYMBOL_EXPORT_END()
-
-/**
- * Converts sval, a pointer to your struct, into a Ruby object.
- *
- * @param klass A ruby level class.
- * @param mark Mark function.
- * @param free Free function.
- * @param sval A pointer to your struct.
- * @exception rb_eTypeError `klass` is not a class.
- * @exception rb_eNoMemError Out of memory.
- * @return A created Ruby object.
- */
-#define Data_Wrap_Struct(klass, mark, free, sval) \
- rb_data_object_wrap( \
- (klass), \
- (sval), \
- RBIMPL_DATA_FUNC(mark), \
- RBIMPL_DATA_FUNC(free))
-
-/**
- * @private
- *
- * This is an implementation detail of #Data_Make_Struct. People don't use it
- * directly.
- *
- * @param result Variable name of created Ruby object.
- * @param klass Ruby level class of the object.
- * @param type Type name of the C struct.
- * @param size Size of the C struct.
- * @param mark Mark function.
- * @param free Free function.
- * @param sval Variable name of created C struct.
- */
-#define Data_Make_Struct0(result, klass, type, size, mark, free, sval) \
- VALUE result = rb_data_object_zalloc( \
- (klass), \
- (size), \
- RBIMPL_DATA_FUNC(mark), \
- RBIMPL_DATA_FUNC(free)); \
- (sval) = RBIMPL_CAST((type *)DATA_PTR(result)); \
- RBIMPL_CAST(/*suppress unused variable warnings*/(void)(sval))
-
-/**
- * Identical to #Data_Wrap_Struct, except it allocates a new data region
- * internally instead of taking an existing one. The allocation is done using
- * ruby_calloc(). Hence it makes no sense to pass anything other than
- * ::RUBY_DEFAULT_FREE to the `free` argument.
- *
- * @param klass Ruby level class of the returning object.
- * @param type Type name of the C struct.
- * @param mark Mark function.
- * @param free Free function.
- * @param sval Variable name of created C struct.
- * @exception rb_eTypeError `klass` is not a class.
- * @exception rb_eNoMemError Out of memory.
- * @return A created Ruby object.
- */
-#ifdef HAVE_STMT_AND_DECL_IN_EXPR
-#define Data_Make_Struct(klass, type, mark, free, sval) \
- RB_GNUC_EXTENSION({ \
- Data_Make_Struct0( \
- data_struct_obj, \
- klass, \
- type, \
- sizeof(type), \
- mark, \
- free, \
- sval); \
- data_struct_obj; \
- })
-#else
-#define Data_Make_Struct(klass, type, mark, free, sval) \
- rb_data_object_make( \
- (klass), \
- RBIMPL_DATA_FUNC(mark), \
- RBIMPL_DATA_FUNC(free), \
- RBIMPL_CAST((void **)&(sval)), \
- sizeof(type))
-#endif
-
-/**
- * Obtains a C struct from inside of a wrapper Ruby object.
- *
- * @param obj An instance of ::RData.
- * @param type Type name of the C struct.
- * @param sval Variable name of obtained C struct.
- * @return Unwrapped C struct that `obj` holds.
- */
-#define Data_Get_Struct(obj, type, sval) \
- ((sval) = RBIMPL_CAST((type*)rb_data_object_get(obj)))
-
-RBIMPL_ATTRSET_UNTYPED_DATA_FUNC()
-/**
- * @private
- *
- * This is an implementation detail of rb_data_object_wrap(). People don't use
- * it directly.
- *
- * @param[in] klass Ruby level class of the returning object.
- * @param[in] ptr Pointer to the target C struct.
- * @param[in] mark Mark function.
- * @param[in] free Free function.
- * @exception rb_eTypeError `klass` is not a class.
- * @exception rb_eNoMemError Out of memory.
- * @return An allocated object that wraps `datap`.
- */
-static inline VALUE
-rb_data_object_wrap_warning(VALUE klass, void *ptr, RUBY_DATA_FUNC mark, RUBY_DATA_FUNC free)
-{
- return rb_data_object_wrap(klass, ptr, mark, free);
-}
-
-/**
- * @private
- *
- * This is an implementation detail of #Data_Get_Struct. People don't use it
- * directly.
- *
- * @param[in] obj An instance of ::RData.
- * @return Unwrapped C struct that `obj` holds.
- */
-static inline void *
-rb_data_object_get(VALUE obj)
-{
- Check_Type(obj, RUBY_T_DATA);
- return DATA_PTR(obj);
-}
-
-RBIMPL_ATTRSET_UNTYPED_DATA_FUNC()
-/**
- * @private
- *
- * This is an implementation detail of #Data_Get_Struct. People don't use it
- * directly.
- *
- * @param[in] obj An instance of ::RData.
- * @return Unwrapped C struct that `obj` holds.
- */
-static inline void *
-rb_data_object_get_warning(VALUE obj)
-{
- return rb_data_object_get(obj);
-}
-
-/**
- * This is an implementation detail of #Data_Make_Struct. People don't use it
- * directly.
- *
- * @param[in] klass Ruby level class of the returning object.
- * @param[in] mark_func Mark function.
- * @param[in] free_func Free function.
- * @param[in] datap Variable of created C struct.
- * @param[in] size Requested size of allocation.
- * @exception rb_eTypeError `klass` is not a class.
- * @exception rb_eNoMemError Out of memory.
- * @return A created Ruby object.
- * @post `*datap` holds the created C struct.
- */
-static inline VALUE
-rb_data_object_make(VALUE klass, RUBY_DATA_FUNC mark_func, RUBY_DATA_FUNC free_func, void **datap, size_t size)
-{
- Data_Make_Struct0(result, klass, void, size, mark_func, free_func, *datap);
- return result;
-}
-
-RBIMPL_ATTR_DEPRECATED(("by: rb_data_object_wrap"))
-/** @deprecated This function was renamed to rb_data_object_wrap(). */
-static inline VALUE
-rb_data_object_alloc(VALUE klass, void *data, RUBY_DATA_FUNC dmark, RUBY_DATA_FUNC dfree)
-{
- return rb_data_object_wrap(klass, data, dmark, dfree);
-}
-
-/** @cond INTERNAL_MACRO */
-#define rb_data_object_wrap_0 rb_data_object_wrap
-#define rb_data_object_wrap_1 rb_data_object_wrap_warning
-#define rb_data_object_wrap_2 rb_data_object_wrap_ /* Used here vvvv */
-#define rb_data_object_wrap RUBY_MACRO_SELECT(rb_data_object_wrap_2, RUBY_UNTYPED_DATA_WARNING)
-#define rb_data_object_get_0 rb_data_object_get
-#define rb_data_object_get_1 rb_data_object_get_warning
-#define rb_data_object_get_2 rb_data_object_get_ /* Used here vvvv */
-#define rb_data_object_get RUBY_MACRO_SELECT(rb_data_object_get_2, RUBY_UNTYPED_DATA_WARNING)
-#define rb_data_object_make_0 rb_data_object_make
-#define rb_data_object_make_1 rb_data_object_make_warning
-#define rb_data_object_make_2 rb_data_object_make_ /* Used here vvvv */
-#define rb_data_object_make RUBY_MACRO_SELECT(rb_data_object_make_2, RUBY_UNTYPED_DATA_WARNING)
-/** @endcond */
#endif /* RBIMPL_RDATA_H */
diff --git a/include/ruby/internal/core/rmatch.h b/include/ruby/internal/core/rmatch.h
index a528c2999e..ae93755531 100644
--- a/include/ruby/internal/core/rmatch.h
+++ b/include/ruby/internal/core/rmatch.h
@@ -67,23 +67,6 @@ struct rmatch_offset {
long end; /**< End of a group. */
};
-/** Represents a match. */
-struct rb_matchext_struct {
- /**
- * "Registers" of a match. This is a quasi-opaque struct that holds
- * execution result of a match. Roughly resembles `&~`.
- */
- struct re_registers regs;
-
- /** Capture group offsets, in C array. */
- struct rmatch_offset *char_offset;
-
- /** Number of ::rmatch_offset that ::rmatch::char_offset holds. */
- 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.
@@ -107,12 +90,41 @@ struct RMatch {
* The expression of this match.
*/
VALUE regexp; /* RRegexp */
+
+ /** Number of ::rmatch_offset that ::rmatch::char_offset holds. */
+ int char_offset_num_allocated;
+
+ /** Capture group offsets, in C array. */
+ struct rmatch_offset *char_offset;
+
+ /** Number of capture-group registers. */
+ int num_regs;
+
+ /** Capacity of `as.embed`, in OnigPosition slots. */
+ int capa;
+
+ /**
+ * "Registers" of a match. This is a quasi-opaque struct that holds
+ * execution result of a match. Roughly resembles `$~`.
+ */
+ union {
+ OnigPosition embed[1];
+ struct re_registers onig;
+ } as;
};
-#define RMATCH_EXT(m) ((rb_matchext_t *)((char *)(m) + sizeof(struct RMatch)))
+RBIMPL_SYMBOL_EXPORT_BEGIN()
+/**
+ * @private
+ *
+ * Converts an embedded match to onig form. This is an implementation
+ * detail of #RMATCH_REGS. People don't use it directly.
+ *
+ * @param[out] match A match object, possibly in embedded form.
+ */
+void rb_match_ensure_onig(VALUE match);
+RBIMPL_SYMBOL_EXPORT_END()
-RBIMPL_ATTR_PURE_UNLESS_DEBUG()
-RBIMPL_ATTR_ARTIFICIAL()
/**
* Queries the raw ::re_registers.
*
@@ -138,7 +150,8 @@ static inline struct re_registers *
RMATCH_REGS(VALUE match)
{
RBIMPL_ASSERT_TYPE(match, RUBY_T_MATCH);
- return &RMATCH_EXT(match)->regs;
+ rb_match_ensure_onig(match);
+ return &RMATCH(match)->as.onig;
}
#endif /* RBIMPL_RMATCH_H */
diff --git a/include/ruby/internal/core/robject.h b/include/ruby/internal/core/robject.h
index d84e318a2c..df1901eb1e 100644
--- a/include/ruby/internal/core/robject.h
+++ b/include/ruby/internal/core/robject.h
@@ -43,7 +43,7 @@
#define ROBJECT(obj) RBIMPL_CAST((struct RObject *)(obj))
/** @cond INTERNAL_MACRO */
#define ROBJECT_EMBED_LEN_MAX ROBJECT_EMBED_LEN_MAX
-#define ROBJECT_EMBED ROBJECT_EMBED
+#define ROBJECT_HEAP ROBJECT_HEAP
#define ROBJECT_FIELDS_CAPACITY ROBJECT_FIELDS_CAPACITY
#define ROBJECT_FIELDS ROBJECT_FIELDS
/** @endcond */
@@ -55,10 +55,12 @@
*/
enum ruby_robject_flags {
/**
- * This flag has something to do with memory footprint. If the object is
- * "small" enough, ruby tries to be creative to abuse padding bits of
- * struct ::RObject for storing instance variables. This flag denotes that
- * situation.
+ * This flag marks that the object's instance variables are stored in an
+ * external heap buffer.
+ * Normally, instance variable references are stored inside the object slot,
+ * but if it overflow, Ruby may have to allocate a separate buffer and spills
+ * the instance variables there.
+ * This flag denotes that situation.
*
* @warning This bit has to be considered read-only. Setting/clearing
* this bit without corresponding fix up must cause immediate
@@ -71,7 +73,7 @@ enum ruby_robject_flags {
* 3rd parties must not be aware that there even is more than one way to
* store instance variables. Might better be hidden.
*/
- ROBJECT_EMBED = RUBY_FL_USER1
+ ROBJECT_HEAP = RUBY_FL_USER4
};
struct st_table;
@@ -97,6 +99,11 @@ struct RObject {
VALUE *fields;
} heap;
+ /* When an object is too complex, it uses a st_table to store instance
+ * variable name to value mappings.
+ */
+ st_table *hash;
+
/* Embedded instance variables. When an object is small enough, it
* uses this area to store the instance variables.
*
@@ -129,11 +136,11 @@ ROBJECT_FIELDS(VALUE obj)
struct RObject *const ptr = ROBJECT(obj);
- if (RB_FL_ANY_RAW(obj, ROBJECT_EMBED)) {
- return ptr->as.ary;
+ if (RB_UNLIKELY(RB_FL_ANY_RAW(obj, ROBJECT_HEAP))) {
+ return ptr->as.heap.fields;
}
else {
- return ptr->as.heap.fields;
+ return ptr->as.ary;
}
}
diff --git a/include/ruby/internal/core/rstring.h b/include/ruby/internal/core/rstring.h
index 0bca74e688..35175ea94a 100644
--- a/include/ruby/internal/core/rstring.h
+++ b/include/ruby/internal/core/rstring.h
@@ -369,41 +369,6 @@ RSTRING_LEN(VALUE str)
return RSTRING(str)->len;
}
-RBIMPL_WARNING_PUSH()
-#if RBIMPL_COMPILER_IS(Intel)
-RBIMPL_WARNING_IGNORED(413)
-#endif
-
-RBIMPL_ATTR_PURE_UNLESS_DEBUG()
-RBIMPL_ATTR_ARTIFICIAL()
-/**
- * @private
- *
- * "Expands" an embedded string into an ordinal one. This is a function that
- * returns aggregated type. The returned struct always has its `as.heap.len`
- * an `as.heap.ptr` fields set appropriately.
- *
- * This is an implementation detail that 3rd parties should never bother.
- */
-static inline struct RString
-rbimpl_rstring_getmem(VALUE str)
-{
- RBIMPL_ASSERT_TYPE(str, RUBY_T_STRING);
-
- if (RB_FL_ANY_RAW(str, RSTRING_NOEMBED)) {
- return *RSTRING(str);
- }
- else {
- /* Expecting compilers to optimize this on-stack struct away. */
- struct RString retval;
- retval.len = RSTRING_LEN(str);
- retval.as.heap.ptr = RSTRING(str)->as.embed.ary;
- return retval;
- }
-}
-
-RBIMPL_WARNING_POP()
-
RBIMPL_ATTR_ARTIFICIAL()
/**
* Queries the contents pointer of the string.
@@ -415,7 +380,9 @@ RBIMPL_ATTR_ARTIFICIAL()
static inline char *
RSTRING_PTR(VALUE str)
{
- char *ptr = rbimpl_rstring_getmem(str).as.heap.ptr;
+ char *ptr = RB_FL_TEST_RAW(str, RSTRING_NOEMBED) ?
+ RSTRING(str)->as.heap.ptr :
+ RSTRING(str)->as.embed.ary;
if (RUBY_DEBUG && RB_UNLIKELY(! ptr)) {
/* :BEWARE: @shyouhei thinks that currently, there are rooms for this
@@ -441,14 +408,17 @@ RBIMPL_ATTR_ARTIFICIAL()
static inline char *
RSTRING_END(VALUE str)
{
- struct RString buf = rbimpl_rstring_getmem(str);
+ char *ptr = RB_FL_TEST_RAW(str, RSTRING_NOEMBED) ?
+ RSTRING(str)->as.heap.ptr :
+ RSTRING(str)->as.embed.ary;
+ long len = RSTRING_LEN(str);
- if (RUBY_DEBUG && RB_UNLIKELY(! buf.as.heap.ptr)) {
+ if (RUBY_DEBUG && RB_UNLIKELY(!ptr)) {
/* Ditto. */
rb_debug_rstring_null_ptr("RSTRING_END");
}
- return &buf.as.heap.ptr[buf.len];
+ return &ptr[len];
}
RBIMPL_ATTR_ARTIFICIAL()
@@ -477,16 +447,7 @@ RSTRING_LENINT(VALUE str)
* @param ptrvar Variable where its contents is stored.
* @param lenvar Variable where its length is stored.
*/
-#ifdef HAVE_STMT_AND_DECL_IN_EXPR
-# define RSTRING_GETMEM(str, ptrvar, lenvar) \
- __extension__ ({ \
- struct RString rbimpl_str = rbimpl_rstring_getmem(str); \
- (ptrvar) = rbimpl_str.as.heap.ptr; \
- (lenvar) = rbimpl_str.len; \
- })
-#else
# define RSTRING_GETMEM(str, ptrvar, lenvar) \
((ptrvar) = RSTRING_PTR(str), \
(lenvar) = RSTRING_LEN(str))
-#endif /* HAVE_STMT_AND_DECL_IN_EXPR */
#endif /* RBIMPL_RSTRING_H */
diff --git a/include/ruby/internal/core/rstruct.h b/include/ruby/internal/core/rstruct.h
index 69be487b59..0028a1bdcd 100644
--- a/include/ruby/internal/core/rstruct.h
+++ b/include/ruby/internal/core/rstruct.h
@@ -31,18 +31,6 @@
# include "ruby/backward.h"
#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
- *
- * Declaration of rb_struct_ptr() is at include/ruby/backward.h.
- */
-#define RSTRUCT_PTR(st) rb_struct_ptr(st)
/** @cond INTERNAL_MACRO */
#define RSTRUCT_LEN RSTRUCT_LEN
#define RSTRUCT_SET RSTRUCT_SET
diff --git a/include/ruby/internal/core/rtypeddata.h b/include/ruby/internal/core/rtypeddata.h
index 4d9fd4a6ac..eb8313f180 100644
--- a/include/ruby/internal/core/rtypeddata.h
+++ b/include/ruby/internal/core/rtypeddata.h
@@ -26,6 +26,7 @@
# include <stddef.h>
#endif
+#include "ruby/assert.h"
#include "ruby/internal/assume.h"
#include "ruby/internal/attr/artificial.h"
#include "ruby/internal/attr/flag_enum.h"
@@ -94,13 +95,15 @@
*/
#define RTYPEDDATA(obj) RBIMPL_CAST((struct RTypedData *)(obj))
+static inline VALUE rbimpl_check_external_typeddata(VALUE obj);
+
/**
* Convenient getter macro.
*
* @param v An object, which is in fact an ::RTypedData.
* @return The passed object's ::RTypedData::data field.
*/
-#define RTYPEDDATA_DATA(v) (RTYPEDDATA(v)->data)
+#define RTYPEDDATA_DATA(v) (RTYPEDDATA(rbimpl_check_external_typeddata(v))->data)
/** @old{rb_check_typeddata} */
#define Check_TypedStruct(v, t) \
@@ -109,16 +112,18 @@
/** @cond INTERNAL_MACRO */
#define RTYPEDDATA_P RTYPEDDATA_P
#define RTYPEDDATA_TYPE RTYPEDDATA_TYPE
+#define TYPED_DATA_EMBEDDED ((VALUE)1)
+#define TYPED_DATA_PTR_MASK (~(TYPED_DATA_EMBEDDED))
+/** @endcond */
+
+/**
+ * Macros to see if each corresponding flag is defined.
+ */
#define RUBY_TYPED_FREE_IMMEDIATELY RUBY_TYPED_FREE_IMMEDIATELY
#define RUBY_TYPED_FROZEN_SHAREABLE RUBY_TYPED_FROZEN_SHAREABLE
#define RUBY_TYPED_WB_PROTECTED RUBY_TYPED_WB_PROTECTED
+#define RUBY_TYPED_EMBEDDABLE RUBY_TYPED_EMBEDDABLE
#define RUBY_TYPED_PROMOTED1 RUBY_TYPED_PROMOTED1
-/** @endcond */
-
-#define IS_TYPED_DATA ((VALUE)1)
-#define TYPED_DATA_EMBEDDED ((VALUE)2)
-#define TYPED_DATA_PTR_FLAGS ((VALUE)3)
-#define TYPED_DATA_PTR_MASK (~TYPED_DATA_PTR_FLAGS)
/**
* @private
@@ -143,6 +148,20 @@ rbimpl_typeddata_flags {
*/
RUBY_TYPED_FREE_IMMEDIATELY = 1,
+ /**
+ * This flag indicate to Ruby that the associated C struct may be embedded
+ * inside the object slot, instead of being externally allocated
+ * with +malloc+.
+ *
+ * Embeddable types MUST NOT be accessed using the +DATA_PTR+ macro, only
+ * with +TypedData_Get_Struct+ or +RTYPEDDATA_GET_DATA+.
+ *
+ * Embeddable types MUST NOT free the associated C struct.
+ *
+ * Pointers into the associated C struct MUST NOT be used after the ruby
+ * object is not longer on the stack, as they become invalid when GC
+ * compaction occurs
+ */
RUBY_TYPED_EMBEDDABLE = 2,
/**
@@ -159,6 +178,12 @@ rbimpl_typeddata_flags {
*/
RUBY_TYPED_FROZEN_SHAREABLE = RUBY_FL_SHAREABLE,
+ // experimental flag
+ // Similar to RUBY_TYPED_FROZEN_SHAREABLE, but doesn't make shareable
+ // reachable objects from this T_DATA object on the Ractor.make_shareable.
+ // If it refers to unshareable objects, simply raise an error.
+ // RUBY_TYPED_FROZEN_SHAREABLE_NO_REC = RUBY_FL_FINALIZE,
+
/**
* This flag has something to do with our garbage collector. These days
* ruby objects are "generational". There are those who are young and
@@ -181,11 +206,6 @@ rbimpl_typeddata_flags {
RUBY_TYPED_WB_PROTECTED = RUBY_FL_WB_PROTECTED, /* THIS FLAG DEPENDS ON Ruby version */
/**
- * This flag no longer in use
- */
- 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
@@ -255,10 +275,15 @@ struct rb_data_type_struct {
RUBY_DATA_FUNC dcompact;
/**
- * This field is reserved for future extension. For now, it must be
- * filled with zeros.
+ * @internal
*/
- void *reserved[1]; /* For future extension.
+ void (*handle_weak_references)(void *);
+
+ /**
+ * This field is reserved for future extension. For now, it must be
+ * filled with zeros.
+ */
+ void *reserved[7]; /* For future extension.
This array *must* be filled with ZERO. */
} function;
@@ -362,8 +387,7 @@ struct RTypedData {
/**
* This is a `const rb_data_type_t *const` value, with the low bits set:
*
- * 1: Always set, to differentiate RTypedData from RData.
- * 2: Set if object is embedded.
+ * 1: Set if object is embedded.
*
* This field stores various information about how Ruby should handle a
* data. This roughly resembles a Ruby level class (apart from method
@@ -376,9 +400,26 @@ struct RTypedData {
};
#if !defined(__cplusplus) || __cplusplus >= 201103L
+RBIMPL_STATIC_ASSERT(fields_obj_in_rdata, offsetof(struct RData, fields_obj) == offsetof(struct RTypedData, fields_obj));
RBIMPL_STATIC_ASSERT(data_in_rtypeddata, offsetof(struct RData, data) == offsetof(struct RTypedData, data));
#endif
+/**
+ * Convenient casting macro for backward compatibility.
+ *
+ * @param obj An object, which is in fact an ::RData.
+ * @return The passed object casted to ::RData.
+ */
+#define RDATA(obj) RTYPEDDATA(obj)
+
+/**
+ * Convenient casting macro for backward compatibility.
+ *
+ * @param obj An object, which is in fact an ::RData.
+ * @return The passed object's ::RTypedData::data field.
+ */
+#define DATA_PTR(obj) RTYPEDDATA_DATA(obj)
+
RBIMPL_SYMBOL_EXPORT_BEGIN()
RBIMPL_ATTR_NONNULL((3))
/**
@@ -393,11 +434,11 @@ RBIMPL_ATTR_NONNULL((3))
*/
VALUE rb_data_typed_object_wrap(VALUE klass, void *datap, const rb_data_type_t *type);
+RBIMPL_ATTR_NONNULL((3))
/**
* Identical to rb_data_typed_object_wrap(), except it allocates a new data
* region internally instead of taking an existing one. The allocation is done
- * using ruby_calloc(). Hence it makes no sense for `type->function.dfree` to
- * be anything other than ::RUBY_TYPED_DEFAULT_FREE.
+ * using ruby_calloc().
*
* @param[in] klass Ruby level class of the returning object.
* @param[in] size Requested size of memory to allocate.
@@ -408,6 +449,7 @@ VALUE rb_data_typed_object_wrap(VALUE klass, void *datap, const rb_data_type_t *
*/
VALUE rb_data_typed_object_zalloc(VALUE klass, size_t size, const rb_data_type_t *type);
+RBIMPL_ATTR_NONNULL(())
/**
* Checks for the domestic relationship between the two.
*
@@ -422,6 +464,7 @@ VALUE rb_data_typed_object_zalloc(VALUE klass, size_t size, const rb_data_type_t
*/
int rb_typeddata_inherited_p(const rb_data_type_t *child, const rb_data_type_t *parent);
+RBIMPL_ATTR_NONNULL((2))
/**
* Checks if the given object is of given kind.
*
@@ -432,6 +475,7 @@ int rb_typeddata_inherited_p(const rb_data_type_t *child, const rb_data_type_t *
*/
int rb_typeddata_is_kind_of(VALUE obj, const rb_data_type_t *data_type);
+RBIMPL_ATTR_NONNULL((2))
/**
* Identical to rb_typeddata_is_kind_of(), except it raises exceptions instead
* of returning false.
@@ -443,8 +487,49 @@ int rb_typeddata_is_kind_of(VALUE obj, const rb_data_type_t *data_type);
* @post Upon successful return `obj`'s type is guaranteed `data_type`.
*/
void *rb_check_typeddata(VALUE obj, const rb_data_type_t *data_type);
+
+RBIMPL_ATTR_NORETURN()
+RBIMPL_ATTR_NONNULL((2))
+/**
+ * @private
+ *
+ * Fails with the given object's type incompatibility to the type.
+ *
+ * This is an implementation detail of Check_Type. People don't use it
+ * directly.
+ *
+ * @param[in] obj The object in question.
+ * @param[in] expected Name of expected data type of `obj`.
+ */
+void rb_unexpected_object_type(VALUE obj, const char *expected);
+
+RBIMPL_ATTR_NORETURN()
+RBIMPL_ATTR_NONNULL(())
+/**
+ * @private
+ *
+ * Fails with the given object's type incompatibility to the type.
+ *
+ * This is an implementation detail of #TypedData_Make_Struct. People don't
+ * use it directly.
+ *
+ * @param[in] actual Actual data type.
+ * @param[in] expected Expected data type.
+ */
+void rb_unexpected_typeddata(const rb_data_type_t *actual, const rb_data_type_t *expected);
RBIMPL_SYMBOL_EXPORT_END()
+#if RUBY_DEBUG
+# define RBIMPL_TYPEDDATA_PRECONDITION(obj, unreachable) \
+ while (RB_UNLIKELY(!RB_TYPE_P(obj, RUBY_T_DATA))) { \
+ rb_unexpected_object_type(obj, "Data"); \
+ unreachable; \
+ }
+#else
+# define RBIMPL_TYPEDDATA_PRECONDITION(obj, unreachable) \
+ RBIMPL_ASSERT_NOTHING
+#endif
+
/**
* Converts sval, a pointer to your struct, into a Ruby object.
*
@@ -473,7 +558,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 *)rbimpl_typeddata_get_data(result)); \
RBIMPL_CAST(/*suppress unused variable warnings*/(void)(sval))
/**
@@ -510,47 +595,36 @@ RBIMPL_SYMBOL_EXPORT_END()
sizeof(type))
#endif
-/**
- * Obtains a C struct from inside of a wrapper Ruby object.
- *
- * @param obj An instance of ::RTypedData.
- * @param type Type name of the C struct.
- * @param data_type The data type describing `type`.
- * @param sval Variable name of obtained C struct.
- * @exception rb_eTypeError `obj` is not a kind of `data_type`.
- * @return Unwrapped C struct that `obj` holds.
- */
-#define TypedData_Get_Struct(obj,type,data_type,sval) \
- ((sval) = RBIMPL_CAST((type *)rb_check_typeddata((obj), (data_type))))
+static inline bool
+rbimpl_typeddata_embedded_p(VALUE obj)
+{
+ return (RTYPEDDATA(obj)->type) & TYPED_DATA_EMBEDDED;
+}
+RBIMPL_ATTR_DEPRECATED_INTERNAL_ONLY()
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
+ RBIMPL_TYPEDDATA_PRECONDITION(obj, RBIMPL_UNREACHABLE_RETURN(false));
- return (RTYPEDDATA(obj)->type) & TYPED_DATA_EMBEDDED;
+ return rbimpl_typeddata_embedded_p(obj);
}
static inline void *
-RTYPEDDATA_GET_DATA(VALUE obj)
+rbimpl_typeddata_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. */
+ return rbimpl_typeddata_embedded_p(obj) ?
+ RBIMPL_CAST((void *)&RTYPEDDATA(obj)->data) :
+ RTYPEDDATA_DATA(obj);
+}
- /* 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 *);
+static inline void *
+RTYPEDDATA_GET_DATA(VALUE obj)
+{
+ RBIMPL_TYPEDDATA_PRECONDITION(obj, RBIMPL_UNREACHABLE_RETURN(NULL));
- return RTYPEDDATA_EMBEDDED_P(obj) ? (char *)obj + embedded_typed_data_size : RTYPEDDATA(obj)->data;
+ return rbimpl_typeddata_get_data(obj);
}
RBIMPL_ATTR_PURE()
@@ -558,46 +632,41 @@ RBIMPL_ATTR_ARTIFICIAL()
/**
* @private
*
- * This is an implementation detail of Check_Type(). People don't use it
- * directly.
+ * Checks whether the passed object is ::RTypedData.
+ *
+ * This is an implementation detail of inline functions defined in this file.
+ * People don't use it directly.
*
* @param[in] obj Object in question
* @retval true `obj` is an instance of ::RTypedData.
- * @retval false `obj` is an instance of ::RData.
- * @pre `obj` must be a Ruby object of ::RUBY_T_DATA.
+ * @retval false `obj` is not an instance of ::RTypedData
*/
static inline bool
-rbimpl_rtypeddata_p(VALUE obj)
+rbimpl_obj_typeddata_p(VALUE obj)
{
- return RTYPEDDATA(obj)->type & IS_TYPED_DATA;
+ return RB_TYPE_P(obj, RUBY_T_DATA);
}
RBIMPL_ATTR_PURE_UNLESS_DEBUG()
RBIMPL_ATTR_ARTIFICIAL()
/**
- * Checks whether the passed object is ::RTypedData or ::RData.
+ * Checks whether the passed object is ::RTypedData.
*
* @param[in] obj Object in question
- * @retval true `obj` is an instance of ::RTypedData.
- * @retval false `obj` is an instance of ::RData.
+ * @retval true
* @pre `obj` must be a Ruby object of ::RUBY_T_DATA.
*/
static inline bool
RTYPEDDATA_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
+ RBIMPL_TYPEDDATA_PRECONDITION(obj, RBIMPL_UNREACHABLE_RETURN(false));
- return rbimpl_rtypeddata_p(obj);
+ return true;
}
RBIMPL_ATTR_PURE_UNLESS_DEBUG()
RBIMPL_ATTR_ARTIFICIAL()
-/* :TODO: can this function be __attribute__((returns_nonnull)) or not? */
+RBIMPL_ATTR_RETURNS_NONNULL()
/**
* Queries for the type of given object.
*
@@ -605,20 +674,93 @@ RBIMPL_ATTR_ARTIFICIAL()
* @return Data type struct that corresponds to `obj`.
* @pre `obj` must be an instance of ::RTypedData.
*/
-static inline const struct rb_data_type_struct *
+static inline const rb_data_type_t *
RTYPEDDATA_TYPE(VALUE obj)
{
-#if RUBY_DEBUG
- if (RB_UNLIKELY(! RTYPEDDATA_P(obj))) {
- rb_unexpected_type(obj, RUBY_T_DATA);
- RBIMPL_UNREACHABLE_RETURN(NULL);
+ RBIMPL_TYPEDDATA_PRECONDITION(obj, RBIMPL_UNREACHABLE_RETURN(NULL));
+
+ VALUE type = RTYPEDDATA(obj)->type & TYPED_DATA_PTR_MASK;
+ const rb_data_type_t *ptr = RBIMPL_CAST((const rb_data_type_t *)type);
+ RBIMPL_ASSERT_OR_ASSUME(ptr);
+ return ptr;
+}
+
+RBIMPL_ATTR_ARTIFICIAL()
+RBIMPL_ATTR_NONNULL(())
+static inline bool
+rbimpl_typeddata_inherited_p_inline(const rb_data_type_t *child, const rb_data_type_t *parent)
+{
+ do {
+ if (RB_LIKELY(child == parent)) return true;
+ } while ((child = child->parent) != NULL);
+ return false;
+}
+#define rb_typeddata_inherited_p rbimpl_typeddata_inherited_p_inline
+
+RBIMPL_ATTR_ARTIFICIAL()
+RBIMPL_ATTR_NONNULL((2))
+static inline bool
+rbimpl_typeddata_is_kind_of_inline(VALUE obj, const rb_data_type_t *data_type)
+{
+ if (RB_UNLIKELY(!rbimpl_obj_typeddata_p(obj))) return false;
+ return rb_typeddata_inherited_p(RTYPEDDATA_TYPE(obj), data_type);
+}
+#define rb_typeddata_is_kind_of rbimpl_typeddata_is_kind_of_inline
+
+RBIMPL_ATTR_ARTIFICIAL()
+RBIMPL_ATTR_NONNULL((2))
+/**
+ * @private
+ *
+ * This is an implementation detail of TypedData_Get_Struct(). Don't use it
+ * directly.
+ */
+static inline void *
+rbimpl_check_typeddata(VALUE obj, const rb_data_type_t *expected_type)
+{
+ if (RB_UNLIKELY(!rbimpl_obj_typeddata_p(obj))) {
+ rb_unexpected_object_type(obj, expected_type->wrap_struct_name);
}
-#endif
- return (const struct rb_data_type_struct *)(RTYPEDDATA(obj)->type & TYPED_DATA_PTR_MASK);
+ const rb_data_type_t *actual_type = RTYPEDDATA_TYPE(obj);
+ if (RB_UNLIKELY(!rb_typeddata_inherited_p(actual_type, expected_type))){
+ rb_unexpected_typeddata(actual_type, expected_type);
+ }
+
+ return RTYPEDDATA_GET_DATA(obj);
+}
+
+RBIMPL_ATTR_PURE_UNLESS_DEBUG()
+RBIMPL_ATTR_ARTIFICIAL()
+/**
+ * @private
+ *
+ * This is an implementation detail of RTYPEDDATA_DATA(). Don't use it
+ * directly.
+ */
+static inline VALUE
+rbimpl_check_external_typeddata(VALUE obj)
+{
+ RBIMPL_TYPEDDATA_PRECONDITION(obj, RBIMPL_UNREACHABLE_RETURN(false));
+ RUBY_ASSERT(!rbimpl_typeddata_embedded_p(obj));
+ return obj;
}
/**
+ * Obtains a C struct from inside of a wrapper Ruby object.
+ *
+ * @param obj An instance of ::RTypedData.
+ * @param type Type name of the C struct.
+ * @param data_type The data type describing `type`.
+ * @param sval Variable name of obtained C struct.
+ * @exception rb_eTypeError `obj` is not a kind of `data_type`.
+ * @return Unwrapped C struct that `obj` holds.
+ */
+#define TypedData_Get_Struct(obj,type,data_type,sval) \
+ ((sval) = RBIMPL_CAST((type *)rbimpl_check_typeddata((obj), (data_type))))
+
+RBIMPL_ATTR_NONNULL((2))
+/**
* While we don't stop you from using this function, it seems to be an
* implementation detail of #TypedData_Make_Struct, which is preferred over
* this one.
@@ -639,12 +781,4 @@ rb_data_typed_object_make(VALUE klass, const rb_data_type_t *type, void **datap,
return result;
}
-RBIMPL_ATTR_DEPRECATED(("by: rb_data_typed_object_wrap"))
-/** @deprecated This function was renamed to rb_data_typed_object_wrap(). */
-static inline VALUE
-rb_data_typed_object_alloc(VALUE klass, void *datap, const rb_data_type_t *type)
-{
- return rb_data_typed_object_wrap(klass, datap, type);
-}
-
#endif /* RBIMPL_RTYPEDDATA_H */
diff --git a/include/ruby/internal/ctype.h b/include/ruby/internal/ctype.h
index 0f7ca6c516..8b24026311 100644
--- a/include/ruby/internal/ctype.h
+++ b/include/ruby/internal/ctype.h
@@ -498,8 +498,8 @@ RBIMPL_ATTR_ARTIFICIAL()
* Our own locale-insensitive version of `tolower(3)`.
*
* @param[in] c Byte in question to convert.
- * @retval c The byte is not listed in in IEEE 1003.1 section
- * 7.3.1.1 "upper".
+ * @retval c The byte is not listed in IEEE 1003.1 section 7.3.1.1
+ * "upper".
* @retval otherwise Byte converted using the map defined in IEEE 1003.1
* section 7.3.1 "tolower".
* @note Not only does this function works under the POSIX Locale, but
diff --git a/include/ruby/internal/encoding/string.h b/include/ruby/internal/encoding/string.h
index 2cfa91c01e..ea78cf23f3 100644
--- a/include/ruby/internal/encoding/string.h
+++ b/include/ruby/internal/encoding/string.h
@@ -264,6 +264,14 @@ VALUE rb_str_conv_enc(VALUE str, rb_encoding *from, rb_encoding *to);
VALUE rb_str_conv_enc_opts(VALUE str, rb_encoding *from, rb_encoding *to, int ecflags, VALUE ecopts);
/**
+ * @private
+ *
+ * This is an implementation detail of rb_enc_str_coderange(). Don't use this
+ * directly.
+ **/
+int rbimpl_enc_str_coderange_scan(VALUE str);
+
+/**
* Scans the passed string to collect its code range. Because a Ruby's string
* is mutable, its contents change from time to time; so does its code range.
* A long-lived string tends to fall back to ::RUBY_ENC_CODERANGE_UNKNOWN.
@@ -275,6 +283,27 @@ VALUE rb_str_conv_enc_opts(VALUE str, rb_encoding *from, rb_encoding *to, int ec
int rb_enc_str_coderange(VALUE str);
/**
+ * Scans the passed string to collect its code range. Because a Ruby's string
+ * is mutable, its contents change from time to time; so does its code range.
+ * A long-lived string tends to fall back to ::RUBY_ENC_CODERANGE_UNKNOWN.
+ * This API scans it and re-assigns a fine-grained code range constant.
+ *
+ * @param[out] str A string.
+ * @return An enum ::ruby_coderange_type.
+ */
+static inline int
+rb_enc_str_coderange_inline(VALUE str)
+{
+ int cr = ENC_CODERANGE(str);
+ if (cr == ENC_CODERANGE_UNKNOWN) {
+ cr = rbimpl_enc_str_coderange_scan(str);
+ }
+ return cr;
+}
+
+#define rb_enc_str_coderange rb_enc_str_coderange_inline
+
+/**
* Scans the passed string until it finds something odd. Returns the number of
* bytes scanned. As the name implies this is suitable for repeated call. One
* of its application is `IO#readlines`. The method reads from its receiver's
diff --git a/include/ruby/internal/error.h b/include/ruby/internal/error.h
index 3ff885b2b1..5bf82bfe7d 100644
--- a/include/ruby/internal/error.h
+++ b/include/ruby/internal/error.h
@@ -421,11 +421,12 @@ void rb_readwrite_syserr_fail(enum rb_io_wait_readwrite waiting, int err, const
RBIMPL_ATTR_COLD()
RBIMPL_ATTR_NORETURN()
/**
+ * @private
+ *
* Fails with the given object's type incompatibility to the type.
*
- * It seems this function is visible from extension libraries only because
- * RTYPEDDATA_TYPE() uses it on RUBY_DEBUG. So you can basically ignore it;
- * use some other fine-grained method instead.
+ * This is an implementation detail of Check_Type. People don't use it
+ * directly.
*
* @param[in] self The object in question.
* @param[in] t Expected type of the object.
diff --git a/include/ruby/internal/eval.h b/include/ruby/internal/eval.h
index 5bcbb97746..23aa1d9580 100644
--- a/include/ruby/internal/eval.h
+++ b/include/ruby/internal/eval.h
@@ -155,7 +155,8 @@ VALUE rb_funcallv(VALUE recv, ID mid, int argc, const VALUE *argv);
* @param[in] kw_splat Handling of keyword parameters:
* - RB_NO_KEYWORDS `argv`'s last is not a keyword argument.
* - RB_PASS_KEYWORDS `argv`'s last is a keyword argument.
- * - RB_PASS_CALLED_KEYWORDS it depends if there is a passed block.
+ * - RB_PASS_CALLED_KEYWORDS Pass keyword arguments if the current method
+ * was called with keyword arguments.
* @exception rb_eNoMethodError No such method.
* @exception rb_eException Any exceptions happen inside.
* @return What the method evaluates to.
@@ -189,7 +190,8 @@ VALUE rb_funcallv_public(VALUE recv, ID mid, int argc, const VALUE *argv);
* @param[in] kw_splat Handling of keyword parameters:
* - RB_NO_KEYWORDS `argv`'s last is not a keyword argument.
* - RB_PASS_KEYWORDS `argv`'s last is a keyword argument.
- * - RB_PASS_CALLED_KEYWORDS it depends if there is a passed block.
+ * - RB_PASS_CALLED_KEYWORDS Pass keyword arguments if the current method
+ * was called with keyword arguments.
* @exception rb_eNoMethodError No such method.
* @exception rb_eNoMethodError The method is private or protected.
* @exception rb_eException Any exceptions happen inside.
@@ -261,7 +263,8 @@ VALUE rb_funcall_passing_block(VALUE recv, ID mid, int argc, const VALUE *argv);
* @param[in] kw_splat Handling of keyword parameters:
* - RB_NO_KEYWORDS `argv`'s last is not a keyword argument.
* - RB_PASS_KEYWORDS `argv`'s last is a keyword argument.
- * - RB_PASS_CALLED_KEYWORDS it depends if there is a passed block.
+ * - RB_PASS_CALLED_KEYWORDS Pass keyword arguments if the current method
+ * was called with keyword arguments.
* @exception rb_eNoMethodError No such method.
* @exception rb_eNoMethodError The method is private or protected.
* @exception rb_eException Any exceptions happen inside.
@@ -307,7 +310,8 @@ VALUE rb_funcall_with_block(VALUE recv, ID mid, int argc, const VALUE *argv, VAL
* @param[in] kw_splat Handling of keyword parameters:
* - RB_NO_KEYWORDS `argv`'s last is not a keyword argument.
* - RB_PASS_KEYWORDS `argv`'s last is a keyword argument.
- * - RB_PASS_CALLED_KEYWORDS it depends if there is a passed block.
+ * - RB_PASS_CALLED_KEYWORDS Pass keyword arguments if the current method
+ * was called with keyword arguments.
* @exception rb_eNoMethodError No such method.
* @exception rb_eNoMethodError The method is private or protected.
* @exception rb_eException Any exceptions happen inside.
@@ -335,7 +339,8 @@ VALUE rb_call_super(int argc, const VALUE *argv);
* @param[in] kw_splat Handling of keyword parameters:
* - RB_NO_KEYWORDS `argv`'s last is not a keyword argument.
* - RB_PASS_KEYWORDS `argv`'s last is a keyword argument.
- * - RB_PASS_CALLED_KEYWORDS it depends if there is a passed block.
+ * - RB_PASS_CALLED_KEYWORDS Pass keyword arguments if the current method
+ * was called with keyword arguments.
* @exception rb_eNoMethodError No super method are there.
* @exception rb_eException Any exceptions happen inside.
* @return What the super method evaluates to.
diff --git a/include/ruby/internal/fl_type.h b/include/ruby/internal/fl_type.h
index 9e1f3dd15c..f7ec742422 100644
--- a/include/ruby/internal/fl_type.h
+++ b/include/ruby/internal/fl_type.h
@@ -59,7 +59,6 @@
#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_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} */
#define FL_UNTRUSTED RBIMPL_CAST((VALUE)RUBY_FL_UNTRUSTED) /**< @old{RUBY_FL_UNTRUSTED} */
#define FL_EXIVAR RBIMPL_CAST((VALUE)RUBY_FL_EXIVAR) /**< @old{RUBY_FL_EXIVAR} */
@@ -109,8 +108,6 @@
#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_UNTRUST RB_OBJ_TAINT
-#define RB_OBJ_UNTRUSTED RB_OBJ_TAINTED
/** @endcond */
/**
@@ -135,15 +132,6 @@
#define OBJ_FREEZE_RAW RB_OBJ_FREEZE_RAW /**< @old{RB_OBJ_FREEZE_RAW} */
#define OBJ_FROZEN RB_OBJ_FROZEN /**< @old{RB_OBJ_FROZEN} */
#define OBJ_FROZEN_RAW RB_OBJ_FROZEN_RAW /**< @old{RB_OBJ_FROZEN_RAW} */
-#define OBJ_INFECT RB_OBJ_INFECT /**< @old{RB_OBJ_INFECT} */
-#define OBJ_INFECT_RAW RB_OBJ_INFECT_RAW /**< @old{RB_OBJ_INFECT_RAW} */
-#define OBJ_TAINT RB_OBJ_TAINT /**< @old{RB_OBJ_TAINT} */
-#define OBJ_TAINTABLE RB_OBJ_TAINTABLE /**< @old{RB_OBJ_TAINT_RAW} */
-#define OBJ_TAINTED RB_OBJ_TAINTED /**< @old{RB_OBJ_TAINTED} */
-#define OBJ_TAINTED_RAW RB_OBJ_TAINTED_RAW /**< @old{RB_OBJ_TAINTED_RAW} */
-#define OBJ_TAINT_RAW RB_OBJ_TAINT_RAW /**< @old{RB_OBJ_TAINT_RAW} */
-#define OBJ_UNTRUST RB_OBJ_UNTRUST /**< @old{RB_OBJ_TAINT} */
-#define OBJ_UNTRUSTED RB_OBJ_UNTRUSTED /**< @old{RB_OBJ_TAINTED} */
/** @} */
/**
@@ -221,7 +209,7 @@ ruby_fl_type {
*
* @internal
*/
- RUBY_FL_UNUSED6 = (1<<6),
+ RUBY_FL_UNUSED6 = (1<<6),
/**
* This flag has something to do with finalisers. A ruby object can have
@@ -238,21 +226,6 @@ ruby_fl_type {
RUBY_FL_FINALIZE = (1<<7),
/**
- * @deprecated This flag once was a thing back in the old days, but makes
- * no sense any longer today. Exists here for backwards
- * compatibility only. You can safely forget about it.
- */
- RUBY_FL_TAINT
-
-#if defined(RBIMPL_HAVE_ENUM_ATTRIBUTE)
- RBIMPL_ATTR_DEPRECATED(("taintedness turned out to be a wrong idea."))
-#elif defined(_MSC_VER)
-# pragma deprecated(RUBY_FL_TAINT)
-#endif
-
- = 0,
-
- /**
* @deprecated This flag was an implementation detail that should never have
* no been exposed. Exists here for backwards
* compatibility only. You can safely forget about it.
@@ -260,7 +233,7 @@ ruby_fl_type {
RUBY_FL_EXIVAR
#if defined(RBIMPL_HAVE_ENUM_ATTRIBUTE)
- RBIMPL_ATTR_DEPRECATED(("FL_EXIVAR is an outdated implementation detail, it shoudl be used."))
+ RBIMPL_ATTR_DEPRECATED(("FL_EXIVAR is an outdated implementation detail, it should not be used."))
#elif defined(_MSC_VER)
# pragma deprecated(RUBY_FL_EXIVAR)
#endif
@@ -279,27 +252,12 @@ ruby_fl_type {
*/
RUBY_FL_SHAREABLE = (1<<8),
- /**
- * @deprecated This flag once was a thing back in the old days, but makes
- * no sense any longer today. Exists here for backwards
- * compatibility only. You can safely forget about it.
- */
- RUBY_FL_UNTRUSTED
-
-#if defined(RBIMPL_HAVE_ENUM_ATTRIBUTE)
- RBIMPL_ATTR_DEPRECATED(("trustedness turned out to be a wrong idea."))
-#elif defined(_MSC_VER)
-# pragma deprecated(RUBY_FL_UNTRUSTED)
-#endif
-
- = 0,
-
/**
- * This flag is no longer in use
+ * This object weakly refers to other objects.
*
* @internal
*/
- RUBY_FL_UNUSED9 = (1<<9),
+ RUBY_FL_WEAK_REFERENCE = (1<<9),
/**
* This flag is no longer in use
@@ -394,23 +352,6 @@ ruby_fl_type {
RUBY_FL_SINGLETON = RUBY_FL_USER1,
};
-enum {
- /**
- * @deprecated This flag once was a thing back in the old days, but makes
- * no sense any longer today. Exists here for backwards
- * compatibility only. You can safely forget about it.
- */
- RUBY_FL_DUPPED
-
-#if defined(RBIMPL_HAVE_ENUM_ATTRIBUTE)
- RBIMPL_ATTR_DEPRECATED(("It seems there is no actual usage of this enum."))
-#elif defined(_MSC_VER)
-# pragma deprecated(RUBY_FL_DUPPED)
-#endif
-
- = (int)RUBY_T_MASK
-};
-
#undef RBIMPL_HAVE_ENUM_ATTRIBUTE
RBIMPL_SYMBOL_EXPORT_BEGIN()
@@ -737,128 +678,6 @@ RB_FL_REVERSE(VALUE obj, VALUE flags)
RBIMPL_ATTR_PURE_UNLESS_DEBUG()
RBIMPL_ATTR_ARTIFICIAL()
-RBIMPL_ATTR_DEPRECATED(("taintedness turned out to be a wrong idea."))
-/**
- * @deprecated This function 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.
- *
- * @param[in] obj Object in question.
- * @return false always.
- */
-static inline bool
-RB_OBJ_TAINTABLE(VALUE obj)
-{
- (void)obj;
- return false;
-}
-
-RBIMPL_ATTR_PURE_UNLESS_DEBUG()
-RBIMPL_ATTR_ARTIFICIAL()
-RBIMPL_ATTR_DEPRECATED(("taintedness turned out to be a wrong idea."))
-/**
- * @deprecated This function 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.
- *
- * @param[in] obj Object in question.
- * @return false always.
- */
-static inline VALUE
-RB_OBJ_TAINTED_RAW(VALUE obj)
-{
- (void)obj;
- return false;
-}
-
-RBIMPL_ATTR_PURE_UNLESS_DEBUG()
-RBIMPL_ATTR_ARTIFICIAL()
-RBIMPL_ATTR_DEPRECATED(("taintedness turned out to be a wrong idea."))
-/**
- * @deprecated This function 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.
- *
- * @param[in] obj Object in question.
- * @return false always.
- */
-static inline bool
-RB_OBJ_TAINTED(VALUE obj)
-{
- (void)obj;
- return false;
-}
-
-RBIMPL_ATTR_ARTIFICIAL()
-RBIMPL_ATTR_DEPRECATED(("taintedness turned out to be a wrong idea."))
-/**
- * @deprecated This function 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.
- *
- * @param[in] obj Object in question.
- */
-static inline void
-RB_OBJ_TAINT_RAW(VALUE obj)
-{
- (void)obj;
- return;
-}
-
-RBIMPL_ATTR_ARTIFICIAL()
-RBIMPL_ATTR_DEPRECATED(("taintedness turned out to be a wrong idea."))
-/**
- * @deprecated This function 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.
- *
- * @param[in] obj Object in question.
- */
-static inline void
-RB_OBJ_TAINT(VALUE obj)
-{
- (void)obj;
- return;
-}
-
-RBIMPL_ATTR_ARTIFICIAL()
-RBIMPL_ATTR_DEPRECATED(("taintedness turned out to be a wrong idea."))
-/**
- * @deprecated This function 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.
- *
- * @param[in] dst Victim object.
- * @param[in] src Infectant object.
- */
-static inline void
-RB_OBJ_INFECT_RAW(VALUE dst, VALUE src)
-{
- (void)dst;
- (void)src;
- return;
-}
-
-RBIMPL_ATTR_ARTIFICIAL()
-RBIMPL_ATTR_DEPRECATED(("taintedness turned out to be a wrong idea."))
-/**
- * @deprecated This function 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.
- *
- * @param[in] dst Victim object.
- * @param[in] src Infectant object.
- */
-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
* use this. Just always use RB_OBJ_FROZEN().
diff --git a/include/ruby/internal/gc.h b/include/ruby/internal/gc.h
index 19783f3023..1900b48a75 100644
--- a/include/ruby/internal/gc.h
+++ b/include/ruby/internal/gc.h
@@ -436,153 +436,6 @@ RBIMPL_SYMBOL_EXPORT_END()
#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
@@ -621,11 +474,11 @@ RBIMPL_SYMBOL_EXPORT_END()
#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.
+ * Marks the object as not protected by write barriers. These objects do not
+ * participate in generational GCs which means that, as long as the object is
+ * alive, they will be scanned on every GC cycle.
*
- * @param[out] x An object that would not be protected by the barrier.
+ * @param[out] x An object that is not protected by the write barrier.
*/
#define RB_OBJ_WB_UNPROTECT(x) rb_obj_wb_unprotect(x, __FILE__, __LINE__)
@@ -640,8 +493,7 @@ RBIMPL_SYMBOL_EXPORT_END()
*
* @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)
+#define RB_OBJ_WB_UNPROTECT_FOR(type, obj) OBJ_WB_UNPROTECT(obj)
/**
* @private
@@ -785,7 +637,9 @@ rb_obj_written(
RGENGC_LOGGING_OBJ_WRITTEN(a, oldv, b, filename, line);
#endif
- rb_gc_writebarrier(a, b);
+ if (!RB_SPECIAL_CONST_P(b)) {
+ rb_gc_writebarrier(a, b);
+ }
return a;
}
@@ -821,7 +675,4 @@ rb_obj_write(
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 528371abbb..9beb215c0c 100644
--- a/include/ruby/internal/globals.h
+++ b/include/ruby/internal/globals.h
@@ -68,6 +68,7 @@ RUBY_EXTERN VALUE rb_cBasicObject; /**< `BasicObject` class. */
RUBY_EXTERN VALUE rb_cObject; /**< `Object` class. */
RUBY_EXTERN VALUE rb_cArray; /**< `Array` class. */
RUBY_EXTERN VALUE rb_cBinding; /**< `Binding` class. */
+RUBY_EXTERN VALUE rb_cBox; /**< `Ruby::Box` class. */
RUBY_EXTERN VALUE rb_cClass; /**< `Class` class. */
RUBY_EXTERN VALUE rb_cDir; /**< `Dir` class. */
RUBY_EXTERN VALUE rb_cEncoding; /**< `Encoding` class. */
@@ -84,8 +85,6 @@ RUBY_EXTERN VALUE rb_cMethod; /**< `Method` class. */
RUBY_EXTERN VALUE rb_cModule; /**< `Module` class. */
RUBY_EXTERN VALUE rb_cRefinement; /**< `Refinement` class. */
RUBY_EXTERN VALUE rb_cNameErrorMesg; /**< `NameError::Message` class. */
-RUBY_EXTERN VALUE rb_cNamespace; /**< `Namespace` class. */
-RUBY_EXTERN VALUE rb_mNamespaceRefiner; /**< `Namespace::Refiner` module. */
RUBY_EXTERN VALUE rb_cNilClass; /**< `NilClass` class. */
RUBY_EXTERN VALUE rb_cNumeric; /**< `Numeric` class. */
RUBY_EXTERN VALUE rb_cProc; /**< `Proc` class. */
diff --git a/include/ruby/internal/intern/bignum.h b/include/ruby/internal/intern/bignum.h
index c27f77a1fb..6ab26fef71 100644
--- a/include/ruby/internal/intern/bignum.h
+++ b/include/ruby/internal/intern/bignum.h
@@ -26,6 +26,10 @@
# include <stddef.h>
#endif
+#ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h> /* for ssize_t (note: on Windows ssize_t is */
+#endif /* `#define`d in ruby/config.h) */
+
#include "ruby/internal/attr/nonnull.h"
#include "ruby/internal/dllexport.h"
#include "ruby/internal/value.h"
@@ -841,6 +845,47 @@ size_t rb_absint_numwords(VALUE val, size_t word_numbits, size_t *nlz_bits_ret);
*/
int rb_absint_singlebit_p(VALUE val);
+/**
+ * @name Flags for rb_int_parse_cstr()
+ * @{
+ */
+
+/** Allows a leading sign (`+` or `-`). */
+#define RB_INT_PARSE_SIGN 0x01
+
+/** Allows underscores between digits. */
+#define RB_INT_PARSE_UNDERSCORE 0x02
+
+/** Allows a base prefix (`0x`, `0b`, `0o`, `0d`). */
+#define RB_INT_PARSE_PREFIX 0x04
+
+/** Shorthand for all of the above flags combined. */
+#define RB_INT_PARSE_ALL 0x07
+
+/** Default flags (all features enabled). */
+#define RB_INT_PARSE_DEFAULT 0x07
+
+/** @} */
+
+/**
+ * Parses a C string to convert into a Ruby integer, with detailed control over
+ * parsing behaviour. Unlike rb_cstr_to_inum(), this function can report the
+ * end position of the parsed integer and the number of parsed digits.
+ *
+ * @param[in] str Pointer to the string to parse.
+ * @param[in] len Length of `str` in bytes, or `-1` to use `strlen(str)`.
+ * @param[out] endp If not `NULL`, the pointer to the first unparsed
+ * character is stored here on return.
+ * @param[out] ndigits If not `NULL`, the number of parsed digits (excluding
+ * prefix, sign, and underscores) is stored here.
+ * @param[in] base Base of conversion. `0` means auto-detect from
+ * prefix. `2..36` for explicit base.
+ * @param[in] flags Bitwise or of `RB_INT_PARSE_*` macros.
+ * @return A Ruby Integer (Fixnum or Bignum), or `Qnil` on parse failure
+ * (when no digits are found).
+ */
+VALUE rb_int_parse_cstr(const char *str, ssize_t len, char **endp, size_t *ndigits, int base, int flags);
+
RBIMPL_SYMBOL_EXPORT_END()
#endif /* RBIMPL_INTERN_BIGNUM_H */
diff --git a/include/ruby/internal/intern/complex.h b/include/ruby/internal/intern/complex.h
index e111bd8ced..1efc093631 100644
--- a/include/ruby/internal/intern/complex.h
+++ b/include/ruby/internal/intern/complex.h
@@ -87,10 +87,6 @@ VALUE rb_complex_new(VALUE real, VALUE imag);
*/
VALUE rb_complex_new_polar(VALUE abs, VALUE arg);
-RBIMPL_ATTR_DEPRECATED(("by: rb_complex_new_polar"))
-/** @old{rb_complex_new_polar} */
-VALUE rb_complex_polar(VALUE abs, VALUE arg);
-
RBIMPL_ATTR_PURE()
/**
* Queries the real part of the passed Complex.
diff --git a/include/ruby/internal/intern/cont.h b/include/ruby/internal/intern/cont.h
index e3c89557fd..2d813ceb9d 100644
--- a/include/ruby/internal/intern/cont.h
+++ b/include/ruby/internal/intern/cont.h
@@ -148,7 +148,8 @@ VALUE rb_fiber_resume(VALUE fiber, int argc, const VALUE *argv);
* @param[in] kw_splat Handling of keyword parameters:
* - RB_NO_KEYWORDS `argv`'s last is not a keyword argument.
* - RB_PASS_KEYWORDS `argv`'s last is a keyword argument.
- * - RB_PASS_CALLED_KEYWORDS it depends if there is a passed block.
+ * - RB_PASS_CALLED_KEYWORDS Pass keyword arguments if the current method
+ * was called with keyword arguments.
* @exception rb_eFiberError `fiber` is terminated etc.
* @exception rb_eException Any exceptions happen in `fiber`.
* @return Either what was yielded or the last value of the fiber body.
@@ -192,7 +193,8 @@ VALUE rb_fiber_yield(int argc, const VALUE *argv);
* @param[in] kw_splat Handling of keyword parameters:
* - RB_NO_KEYWORDS `argv`'s last is not a keyword argument.
* - RB_PASS_KEYWORDS `argv`'s last is a keyword argument.
- * - RB_PASS_CALLED_KEYWORDS it depends if there is a passed block.
+ * - RB_PASS_CALLED_KEYWORDS Pass keyword arguments if the current method
+ * was called with keyword arguments.
* @exception rb_eException What was raised using `Fiber#raise`.
* @return (See rb_fiber_resume() for details)
*/
@@ -247,7 +249,8 @@ VALUE rb_fiber_transfer(VALUE fiber, int argc, const VALUE *argv);
* @param[in] kw_splat Handling of keyword parameters:
* - RB_NO_KEYWORDS `argv`'s last is not a keyword argument.
* - RB_PASS_KEYWORDS `argv`'s last is a keyword argument.
- * - RB_PASS_CALLED_KEYWORDS it depends if there is a passed block.
+ * - RB_PASS_CALLED_KEYWORDS Pass keyword arguments if the current method
+ * was called with keyword arguments.
* @exception rb_eFiberError (See above)
* @exception rb_eException What was raised using `Fiber#raise`.
* @return (See rb_fiber_resume() for details)
diff --git a/include/ruby/internal/intern/enumerator.h b/include/ruby/internal/intern/enumerator.h
index 20e5d7c6fc..00804d786a 100644
--- a/include/ruby/internal/intern/enumerator.h
+++ b/include/ruby/internal/intern/enumerator.h
@@ -100,7 +100,8 @@ VALUE rb_enumeratorize_with_size(VALUE recv, VALUE meth, int argc, const VALUE *
* @param[in] kw_splat Handling of keyword parameters:
* - RB_NO_KEYWORDS `argv`'s last is not a keyword argument.
* - RB_PASS_KEYWORDS `argv`'s last is a keyword argument.
- * - RB_PASS_CALLED_KEYWORDS it depends if there is a passed block.
+ * - RB_PASS_CALLED_KEYWORDS Pass keyword arguments if the current method
+ * was called with keyword arguments.
* @exception rb_eTypeError `meth` is not an instance of ::rb_cSymbol.
* @return A new instance of ::rb_cEnumerator which, when yielded,
* enumerates by calling `meth` on `recv` with `argv`.
@@ -186,7 +187,8 @@ RBIMPL_SYMBOL_EXPORT_END()
* @param[in] kw_splat Handling of keyword parameters:
* - RB_NO_KEYWORDS `argv`'s last is not a keyword argument.
* - RB_PASS_KEYWORDS `argv`'s last is a keyword argument.
- * - RB_PASS_CALLED_KEYWORDS it depends if there is a passed block.
+ * - RB_PASS_CALLED_KEYWORDS Pass keyword arguments if the current method
+ * was called with keyword arguments.
* @return A new instance of ::rb_cEnumerator which, when yielded,
* enumerates by calling the current method on `recv` with `argv`.
*/
@@ -220,7 +222,8 @@ RBIMPL_SYMBOL_EXPORT_END()
* @param[in] kw_splat Handling of keyword parameters:
* - RB_NO_KEYWORDS `argv`'s last is not a keyword argument.
* - RB_PASS_KEYWORDS `argv`'s last is a keyword argument.
- * - RB_PASS_CALLED_KEYWORDS it depends if there is a passed block.
+ * - RB_PASS_CALLED_KEYWORDS Pass keyword arguments if the current method
+ * was called with keyword arguments.
* @note This macro may return inside.
*/
#define RETURN_SIZED_ENUMERATOR_KW(obj, argc, argv, size_fn, kw_splat) do { \
@@ -250,7 +253,8 @@ RBIMPL_SYMBOL_EXPORT_END()
* @param[in] kw_splat Handling of keyword parameters:
* - RB_NO_KEYWORDS `argv`'s last is not a keyword argument.
* - RB_PASS_KEYWORDS `argv`'s last is a keyword argument.
- * - RB_PASS_CALLED_KEYWORDS it depends if there is a passed block.
+ * - RB_PASS_CALLED_KEYWORDS Pass keyword arguments if the current method
+ * was called with keyword arguments.
* @note This macro may return inside.
*/
#define RETURN_ENUMERATOR_KW(obj, argc, argv, kw_splat) \
diff --git a/include/ruby/internal/intern/file.h b/include/ruby/internal/intern/file.h
index b669758d21..8508b7ab9e 100644
--- a/include/ruby/internal/intern/file.h
+++ b/include/ruby/internal/intern/file.h
@@ -211,22 +211,6 @@ int rb_is_absolute_path(const char *path);
*/
rb_off_t rb_file_size(VALUE file);
-#ifdef RBIMPL_ATTR_DEPRECATED_INTERNAL_ONLY
-RBIMPL_ATTR_DEPRECATED_INTERNAL_ONLY()
-#endif
-/**
- * If the PATH_SEPARATOR-separated list of directory names contains the name of
- * a world-writable directory, issue a warning for it. This may do nothing on
- * some platforms.
- *
- * @param[in] path A local path.
- * @retval 0 The "check" succeeded.
- * @retval otherwise The "check" failed.
- * @note This feature may be disabled by setting `ENABLE_PATH_CHECK`
- * macro to zero at compilation time.
- */
-int rb_path_check(const char *path);
-
RBIMPL_SYMBOL_EXPORT_END()
#endif /* RBIMPL_INTERN_FILE_H */
diff --git a/include/ruby/internal/intern/object.h b/include/ruby/internal/intern/object.h
index 9daad7d046..3897639a0a 100644
--- a/include/ruby/internal/intern/object.h
+++ b/include/ruby/internal/intern/object.h
@@ -80,7 +80,8 @@ VALUE rb_class_new_instance(int argc, const VALUE *argv, VALUE klass);
* @param[in] kw_splat Handling of keyword parameters:
* - RB_NO_KEYWORDS `argv`'s last is not a keyword argument.
* - RB_PASS_KEYWORDS `argv`'s last is a keyword argument.
- * - RB_PASS_CALLED_KEYWORDS it depends if there is a passed block.
+ * - RB_PASS_CALLED_KEYWORDS Pass keyword arguments if the current method
+ * was called with keyword arguments.
* @exception rb_eTypeError `klass`'s allocator is undefined.
* @exception rb_eException Any exceptions can happen inside.
* @return An allocated new instance of `klass`.
diff --git a/include/ruby/internal/intern/proc.h b/include/ruby/internal/intern/proc.h
index b8c3c5e146..2635d672eb 100644
--- a/include/ruby/internal/intern/proc.h
+++ b/include/ruby/internal/intern/proc.h
@@ -101,7 +101,8 @@ VALUE rb_proc_call(VALUE recv, VALUE args);
* @param[in] kw_splat Handling of keyword parameters:
* - RB_NO_KEYWORDS `args`' last is not a keyword argument.
* - RB_PASS_KEYWORDS `args`' last is a keyword argument.
- * - RB_PASS_CALLED_KEYWORDS it depends if there is a passed block.
+ * - RB_PASS_CALLED_KEYWORDS Pass keyword arguments if the current method
+ * was called with keyword arguments.
* @exception rb_eException Any exceptions happen inside.
* @return What the proc evaluates to.
*/
@@ -141,7 +142,8 @@ VALUE rb_proc_call_with_block(VALUE recv, int argc, const VALUE *argv, VALUE pro
* @param[in] kw_splat Handling of keyword parameters:
* - RB_NO_KEYWORDS `args`' last is not a keyword argument.
* - RB_PASS_KEYWORDS `args`' last is a keyword argument.
- * - RB_PASS_CALLED_KEYWORDS it depends if there is a passed block.
+ * - RB_PASS_CALLED_KEYWORDS Pass keyword arguments if the current method
+ * was called with keyword arguments.
* @exception rb_eException Any exceptions happen inside.
* @return What the proc evaluates to.
*/
@@ -245,7 +247,8 @@ VALUE rb_method_call(int argc, const VALUE *argv, VALUE recv);
* @param[in] kw_splat Handling of keyword parameters:
* - RB_NO_KEYWORDS `args`' last is not a keyword argument.
* - RB_PASS_KEYWORDS `args`' last is a keyword argument.
- * - RB_PASS_CALLED_KEYWORDS it depends if there is a passed block.
+ * - RB_PASS_CALLED_KEYWORDS Pass keyword arguments if the current method
+ * was called with keyword arguments.
* @exception rb_eTypeError `recv` is not a method.
* @exception rb_eException Any exceptions happen inside.
* @return What the method returns.
@@ -279,7 +282,8 @@ VALUE rb_method_call_with_block(int argc, const VALUE *argv, VALUE recv, VALUE p
* @param[in] kw_splat Handling of keyword parameters:
* - RB_NO_KEYWORDS `args`' last is not a keyword argument.
* - RB_PASS_KEYWORDS `args`' last is a keyword argument.
- * - RB_PASS_CALLED_KEYWORDS it depends if there is a passed block.
+ * - RB_PASS_CALLED_KEYWORDS Pass keyword arguments if the current method
+ * was called with keyword arguments.
* @exception rb_eTypeError `recv` is not a method.
* @exception rb_eException Any exceptions happen inside.
* @return What the method returns.
diff --git a/include/ruby/internal/intern/select.h b/include/ruby/internal/intern/select.h
index 6ba84c6e63..ba75213618 100644
--- a/include/ruby/internal/intern/select.h
+++ b/include/ruby/internal/intern/select.h
@@ -72,6 +72,8 @@ struct timeval;
* someone else, vastly varies among operating systems. You would better avoid
* touching an fd from more than one threads.
*
+ * NOTE: this function is used in native extensions, so change its API with care.
+ *
* @internal
*
* Although any file descriptors are possible here, it makes completely no
diff --git a/include/ruby/internal/intern/string.h b/include/ruby/internal/intern/string.h
index 7b1bf5cc54..8bd1ffcfb4 100644
--- a/include/ruby/internal/intern/string.h
+++ b/include/ruby/internal/intern/string.h
@@ -412,8 +412,8 @@ 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(),
- * except it returns an infamous "f"string.
+ * C's and preserves its encoding. It can also be seen as a routine identical
+ * to rb_str_new_shared(), except it returns an infamous "f"string.
*
* @param[in] str An object of ::RString.
* @return An instance of ::rb_cString, either cached or allocated, which
@@ -444,8 +444,9 @@ VALUE rb_str_to_interned_str(VALUE str);
* terminating NUL character.
* @exception rb_eArgError `len` is negative.
* @return A found or created instance of ::rb_cString, of `len` bytes
- * length, of "binary" encoding, whose contents are identical to
- * that of `ptr`.
+ * length, whose contents are identical to that of `ptr`. Its
+ * encoding will be US-ASCII if all bytes are lower ASCII, BINARY
+ * otherwise.
* @pre At least `len` bytes of continuous memory region shall be
* accessible via `ptr`.
*/
@@ -461,8 +462,9 @@ RBIMPL_ATTR_NONNULL(())
*
* @param[in] ptr A C string.
* @exception rb_eNoMemError Failed to allocate memory.
- * @return An instance of ::rb_cString, of "binary" encoding, whose
- * contents are verbatim copy of `ptr`.
+ * @return An instance of ::rb_cString, whose contents are verbatim copy
+ * of `ptr`. Its encoding will be US-ASCII if all bytes are lower
+ * ASCII, BINARY otherwise.
* @pre `ptr` must not be a null pointer.
*/
VALUE rb_interned_str_cstr(const char *ptr);
@@ -591,10 +593,9 @@ void rb_must_asciicompat(VALUE obj);
VALUE rb_str_dup(VALUE str);
/**
- * I guess there is no use case of this function in extension libraries, but
- * this is a routine identical to rb_str_dup(), except it always creates an
- * instance of ::rb_cString regardless of the given object's class. This makes
- * the most sense when the passed string is formerly hidden by rb_obj_hide().
+ * Like rb_str_dup(), but always create an instance of ::rb_cString
+ * regardless of the given object's class. This makes the most sense
+ * when the passed string is formerly hidden by rb_obj_hide().
*
* @param[in] str A string, possibly hidden.
* @return A duplicated new instance of ::rb_cString.
diff --git a/include/ruby/internal/intern/variable.h b/include/ruby/internal/intern/variable.h
index 479c3950c1..315584790c 100644
--- a/include/ruby/internal/intern/variable.h
+++ b/include/ruby/internal/intern/variable.h
@@ -48,6 +48,7 @@ VALUE rb_mod_name(VALUE mod);
*/
VALUE rb_class_path(VALUE mod);
+RBIMPL_ATTR_DEPRECATED(("rb_mod_name"))
/**
* @alias{rb_mod_name}
*
diff --git a/include/ruby/internal/intern/vm.h b/include/ruby/internal/intern/vm.h
index 29e0c7f534..f0b54c702c 100644
--- a/include/ruby/internal/intern/vm.h
+++ b/include/ruby/internal/intern/vm.h
@@ -89,7 +89,8 @@ VALUE rb_check_funcall(VALUE recv, ID mid, int argc, const VALUE *argv);
* @param[in] kw_splat Handling of keyword parameters:
* - RB_NO_KEYWORDS `argv`'s last is not a keyword argument.
* - RB_PASS_KEYWORDS `argv`'s last is a keyword argument.
- * - RB_PASS_CALLED_KEYWORDS it depends if there is a passed block.
+ * - RB_PASS_CALLED_KEYWORDS Pass keyword arguments if the current method
+ * was called with keyword arguments.
* @retval RUBY_Qundef `recv` doesn't respond to `mid`.
* @retval otherwise What the method evaluates to.
*/
@@ -106,9 +107,11 @@ VALUE rb_check_funcall_kw(VALUE recv, ID mid, int argc, const VALUE *argv, int k
* @param[in] kw_splat Handling of keyword parameters:
* - RB_NO_KEYWORDS `arg`'s last is not a keyword argument.
* - RB_PASS_KEYWORDS `arg`'s last is a keyword argument.
- * - RB_PASS_CALLED_KEYWORDS it depends if there is a passed block.
+ * - RB_PASS_CALLED_KEYWORDS Pass keyword arguments if the current method
+ * was called with keyword arguments.
* @return What the command evaluates to.
*/
+RBIMPL_ATTR_DEPRECATED_INTERNAL(4.0)
VALUE rb_eval_cmd_kw(VALUE cmd, VALUE arg, int kw_splat);
/**
diff --git a/include/ruby/internal/iterator.h b/include/ruby/internal/iterator.h
index 5f706460f8..891045363e 100644
--- a/include/ruby/internal/iterator.h
+++ b/include/ruby/internal/iterator.h
@@ -265,48 +265,6 @@ int rb_block_given_p(void);
*/
void rb_need_block(void);
-#ifndef __cplusplus
-RBIMPL_ATTR_DEPRECATED(("by: rb_block_call since 1.9"))
-#endif
-/**
- * Old way to iterate a block.
- *
- * @deprecated This is an old API. Use rb_block_call() instead.
- * @warning The passed function must at least once call a ruby method
- * (to handle interrupts etc.)
- * @param[in] func1 A function that could yield a value.
- * @param[in,out] data1 Passed to `func1`
- * @param[in] proc A function acts as a block.
- * @param[in,out] data2 Passed to `proc` as the data2 parameter.
- * @return What `func1` returns.
- */
-VALUE rb_iterate(VALUE (*func1)(VALUE), VALUE data1, rb_block_call_func_t proc, VALUE data2);
-
-#ifdef __cplusplus
-namespace ruby {
-namespace backward {
-/**
- * Old way to iterate a block.
- *
- * @deprecated This is an old API. Use rb_block_call() instead.
- * @warning The passed function must at least once call a ruby method
- * (to handle interrupts etc.)
- * @param[in] iter A function that could yield a value.
- * @param[in,out] data1 Passed to `func1`
- * @param[in] bl A function acts as a block.
- * @param[in,out] data2 Passed to `proc` as the data2 parameter.
- * @return What `func1` returns.
- */
-static inline VALUE
-rb_iterate_deprecated(VALUE (*iter)(VALUE), VALUE data1, rb_block_call_func_t bl, VALUE data2)
-{
- return ::rb_iterate(iter, data1, bl, data2);
-}}}
-
-RBIMPL_ATTR_DEPRECATED(("by: rb_block_call since 1.9"))
-VALUE rb_iterate(VALUE (*func1)(VALUE), VALUE data1, rb_block_call_func_t proc, VALUE data2);
-#endif
-
/**
* Identical to rb_funcallv(), except it additionally passes a function as a
* block. When the method yields, `proc` is called with the yielded value as
@@ -337,7 +295,8 @@ VALUE rb_block_call(VALUE obj, ID mid, int argc, const VALUE *argv, rb_block_cal
* @param[in] kw_splat Handling of keyword parameters:
* - RB_NO_KEYWORDS `argv`'s last is not a keyword argument.
* - RB_PASS_KEYWORDS `argv`'s last is a keyword argument.
- * - RB_PASS_CALLED_KEYWORDS it depends if there is a passed block.
+ * - RB_PASS_CALLED_KEYWORDS Pass keyword arguments if the current method
+ * was called with keyword arguments.
* @return What `obj.mid` returns.
*/
VALUE rb_block_call_kw(VALUE obj, ID mid, int argc, const VALUE *argv, rb_block_call_func_t proc, VALUE data2, int kw_splat);
diff --git a/include/ruby/internal/memory.h b/include/ruby/internal/memory.h
index 9fc6c39efc..eb9c1d2525 100644
--- a/include/ruby/internal/memory.h
+++ b/include/ruby/internal/memory.h
@@ -408,7 +408,8 @@ typedef uint128_t DSIZE_T;
/**
* @private
*
- * This is an implementation detail of rbimpl_size_mul_overflow().
+ * This is an implementation detail of rbimpl_size_mul_overflow() and
+ * rbimpl_size_add_overflow().
*
* @internal
*
@@ -416,9 +417,9 @@ typedef uint128_t DSIZE_T;
* nothing more than std::variant<std::size_t> if we could use recent C++, but
* reality is we cannot.
*/
-struct rbimpl_size_mul_overflow_tag {
- bool left; /**< Whether overflow happened or not. */
- size_t right; /**< Multiplication result. */
+struct rbimpl_size_overflow_tag {
+ bool overflowed; /**< Whether overflow happened or not. */
+ size_t result; /**< Calculation result. */
};
RBIMPL_SYMBOL_EXPORT_BEGIN()
@@ -572,46 +573,46 @@ RBIMPL_ATTR_CONST()
*
* @param[in] x Arbitrary value.
* @param[in] y Arbitrary value.
- * @return `{ left, right }`, where `left` is whether there is an integer
- * overflow or not, and `right` is a (possibly overflowed) result
- * of `x` * `y`.
+ * @return `{ overflowed, result }`, where `overflowed` is whether there is
+ * an integer overflow or not, and `result` is a (possibly
+ * overflowed) result of `x` * `y`.
*
* @internal
*
* This is in fact also an implementation detail of ruby_xmalloc2() etc.
*/
-static inline struct rbimpl_size_mul_overflow_tag
+static inline struct rbimpl_size_overflow_tag
rbimpl_size_mul_overflow(size_t x, size_t y)
{
- struct rbimpl_size_mul_overflow_tag ret = { false, 0, };
+ struct rbimpl_size_overflow_tag ret = { false, 0, };
#if defined(ckd_mul)
- ret.left = ckd_mul(&ret.right, x, y);
+ ret.overflowed = ckd_mul(&ret.result, x, y);
#elif RBIMPL_HAS_BUILTIN(__builtin_mul_overflow)
- ret.left = __builtin_mul_overflow(x, y, &ret.right);
+ ret.overflowed = __builtin_mul_overflow(x, y, &ret.result);
#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;
- ret.left = dz > SIZE_MAX;
- ret.right = RBIMPL_CAST((size_t)dz);
+ ret.overflowed = dz > SIZE_MAX;
+ ret.result = RBIMPL_CAST((size_t)dz);
#elif defined(_MSC_VER) && defined(_M_AMD64)
unsigned __int64 dp = 0;
unsigned __int64 dz = _umul128(x, y, &dp);
- ret.left = RBIMPL_CAST((bool)dp);
- ret.right = RBIMPL_CAST((size_t)dz);
+ ret.overflowed = RBIMPL_CAST((bool)dp);
+ ret.result = RBIMPL_CAST((size_t)dz);
#elif defined(_MSC_VER) && defined(_M_ARM64)
- ret.left = __umulh(x, y) != 0;
- ret.right = x * y;
+ ret.overflowed = __umulh(x, y) != 0;
+ ret.result = x * y;
#else
/* https://wiki.sei.cmu.edu/confluence/display/c/INT30-C.+Ensure+that+unsigned+integer+operations+do+not+wrap */
- ret.left = (y != 0) && (x > SIZE_MAX / y);
- ret.right = x * y;
+ ret.overflowed = (y != 0) && (x > SIZE_MAX / y);
+ ret.result = x * y;
#endif
return ret;
@@ -635,11 +636,11 @@ rbimpl_size_mul_overflow(size_t x, size_t y)
static inline size_t
rbimpl_size_mul_or_raise(size_t x, size_t y)
{
- struct rbimpl_size_mul_overflow_tag size =
+ struct rbimpl_size_overflow_tag size =
rbimpl_size_mul_overflow(x, y);
- if (RB_LIKELY(! size.left)) {
- return size.right;
+ if (RB_LIKELY(! size.overflowed)) {
+ return size.result;
}
else {
ruby_malloc_size_overflow(x, y);
@@ -662,33 +663,33 @@ RBIMPL_ATTR_CONST()
*
* @param[in] x Arbitrary value.
* @param[in] y Arbitrary value.
- * @return `{ left, right }`, where `left` is whether there is an integer
- * overflow or not, and `right` is a (possibly overflowed) result
- * of `x` + `y`.
+ * @return `{ overflowed, result }`, where `overflowed` is whether there is
+ * an integer overflow or not, and `result` is a (possibly
+ * overflowed) result of `x` + `y`.
*
* @internal
*/
-static inline struct rbimpl_size_mul_overflow_tag
+static inline struct rbimpl_size_overflow_tag
rbimpl_size_add_overflow(size_t x, size_t y)
{
- struct rbimpl_size_mul_overflow_tag ret = { false, 0, };
+ struct rbimpl_size_overflow_tag ret = { false, 0, };
#if defined(ckd_add)
- ret.left = ckd_add(&ret.right, x, y);
+ ret.overflowed = ckd_add(&ret.result, x, y);
#elif RBIMPL_HAS_BUILTIN(__builtin_add_overflow)
- ret.left = __builtin_add_overflow(x, y, &ret.right);
+ ret.overflowed = __builtin_add_overflow(x, y, &ret.result);
#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;
- ret.left = dz > SIZE_MAX;
- ret.right = (size_t)dz;
+ ret.overflowed = dz > SIZE_MAX;
+ ret.result = (size_t)dz;
#else
- ret.right = x + y;
- ret.left = ret.right < y;
+ ret.result = x + y;
+ ret.overflowed = ret.result < y;
#endif
@@ -710,11 +711,11 @@ rbimpl_size_add_overflow(size_t x, size_t y)
static inline size_t
rbimpl_size_add_or_raise(size_t x, size_t y)
{
- struct rbimpl_size_mul_overflow_tag size =
+ struct rbimpl_size_overflow_tag size =
rbimpl_size_add_overflow(x, y);
- if (RB_LIKELY(!size.left)) {
- return size.right;
+ if (RB_LIKELY(!size.overflowed)) {
+ return size.result;
}
else {
ruby_malloc_add_size_overflow(x, y);
@@ -740,8 +741,7 @@ 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 cnt = (total_size + sizeof(VALUE) - 1) / sizeof(VALUE);
- return rb_alloc_tmp_buffer_with_count(store, total_size, cnt);
+ return rb_alloc_tmp_buffer(store, (long)total_size);
}
RBIMPL_SYMBOL_EXPORT_BEGIN()
diff --git a/include/ruby/internal/newobj.h b/include/ruby/internal/newobj.h
index 6eee2fa5fa..13030ae279 100644
--- a/include/ruby/internal/newobj.h
+++ b/include/ruby/internal/newobj.h
@@ -109,42 +109,4 @@ void rb_singleton_class_attached(VALUE klass, VALUE obj);
void rb_copy_generic_ivar(VALUE clone, VALUE obj);
RBIMPL_SYMBOL_EXPORT_END()
-RBIMPL_ATTR_DEPRECATED(("This is no longer how Object#clone works."))
-/**
- * @deprecated Not sure exactly when but at some time, the implementation of
- * `Object#clone` stopped using this function. It remained
- * untouched for a while, and then @shyouhei realised that they
- * are no longer doing the same thing. It seems nobody seriously
- * uses this function any longer. Let's just abandon it.
- *
- * @param[out] clone The destination object.
- * @param[in] obj The source object.
- */
-static inline void
-rb_clone_setup(VALUE clone, VALUE obj)
-{
- (void)clone;
- (void)obj;
- return;
-}
-
-RBIMPL_ATTR_DEPRECATED(("This is no longer how Object#dup works."))
-/**
- * @deprecated Not sure exactly when but at some time, the implementation of
- * `Object#dup` stopped using this function. It remained
- * untouched for a while, and then @shyouhei realised that they
- * are no longer the same thing. It seems nobody seriously uses
- * this function any longer. Let's just abandon it.
- *
- * @param[out] dup The destination object.
- * @param[in] obj The source object.
- */
-static inline void
-rb_dup_setup(VALUE dup, VALUE obj)
-{
- (void)dup;
- (void)obj;
- return;
-}
-
#endif /* RBIMPL_NEWOBJ_H */
diff --git a/include/ruby/internal/scan_args.h b/include/ruby/internal/scan_args.h
index 2dbc1ee7bc..da64678db5 100644
--- a/include/ruby/internal/scan_args.h
+++ b/include/ruby/internal/scan_args.h
@@ -49,11 +49,11 @@
/** Same behaviour as rb_scan_args(). */
#define RB_SCAN_ARGS_PASS_CALLED_KEYWORDS 0
-/** The final argument should be a hash treated as keywords.*/
+/** The final argument must be a hash, which will be treated as keywords. */
#define RB_SCAN_ARGS_KEYWORDS 1
/**
- * Treat a final argument as keywords if it is a hash, and not as keywords
+ * Treat a final argument as keywords if it is a hash, and not as keywords
* otherwise.
*/
#define RB_SCAN_ARGS_LAST_HASH_KEYWORDS 3
@@ -68,7 +68,7 @@
/** Do not pass keywords. */
#define RB_NO_KEYWORDS 0
-/** Pass keywords, final argument should be a hash of keywords. */
+/** Pass keywords, final argument must be a hash of keywords. */
#define RB_PASS_KEYWORDS 1
/**
diff --git a/include/ruby/internal/static_assert.h b/include/ruby/internal/static_assert.h
index 7f00bc21eb..30bfd3bb79 100644
--- a/include/ruby/internal/static_assert.h
+++ b/include/ruby/internal/static_assert.h
@@ -30,7 +30,7 @@
# /* https://isocpp.org/std/standing-documents/sd-6-sg10-feature-test-recommendations */
# define RBIMPL_STATIC_ASSERT0 static_assert
-#elif defined(__cplusplus) && RBIMPL_COMPILER_SINCE(MSVC, 16, 0, 0)
+#elif defined(__cplusplus) && RBIMPL_COMPILER_IS(MSVC)
# define RBIMPL_STATIC_ASSERT0 static_assert
#elif defined(__INTEL_CXX11_MODE__)
diff --git a/include/ruby/internal/symbol.h b/include/ruby/internal/symbol.h
index 569bf215a2..8bfd686fbe 100644
--- a/include/ruby/internal/symbol.h
+++ b/include/ruby/internal/symbol.h
@@ -101,12 +101,11 @@ ID rb_intern(const char *name);
ID rb_intern2(const char *name, long len);
/**
- * Identical to rb_intern(), except it takes an instance of ::rb_cString.
+ * Identical to rb_intern(), except it takes a `T_STRING` object.
*
* @param[in] str The name of the id.
- * @pre `str` must either be an instance of ::rb_cSymbol, or an instance
- * of ::rb_cString, or responds to `#to_str` method.
- * @exception rb_eTypeError Can't convert `str` into ::rb_cString.
+ * @pre `rb_type(str)` must be `T_STRING`.
+ * @exception rb_eEncodingError `str` contains invalid character(s).
* @exception rb_eRuntimeError Too many symbols.
* @return A (possibly new) id whose value is the given str.
* @note These days Ruby internally has two kinds of symbols
@@ -166,29 +165,34 @@ RBIMPL_ATTR_NONNULL(())
* of ::rb_cSymbol, or an instance of ::rb_cString, or responds
* to `#to_str` method.
* @exception rb_eTypeError Can't convert `*namep` into ::rb_cString.
- * @exception rb_eEncodingError Given string is non-ASCII.
+ * @exception rb_eEncodingError Given string contains invalid character(s).
* @retval 0 No such id ever existed in the history.
* @retval otherwise The id that represents the given name.
* @post The object that `*namep` points to is a converted result
* object, which is always an instance of either ::rb_cSymbol
* or ::rb_cString.
+ * @see rb_str_to_str
* @see https://bugs.ruby-lang.org/issues/5072
- *
- * @internal
- *
- * @shyouhei doesn't know why this has to raise rb_eEncodingError.
*/
ID rb_check_id(volatile VALUE *namep);
/**
- * @copydoc rb_intern_str()
+ * Identical to rb_intern_str(), except it tries to convert the parameter object
+ * to an instance of ::rb_cString or its subclasses.
*
- * @internal
- *
- * :FIXME: Can anyone tell us what is the difference between this one and
- * rb_intern_str()? As far as @shyouhei reads the implementation it seems what
- * rb_to_id() does is is just waste some CPU time, then call rb_intern_str().
- * He hopes he is wrong.
+ * @param[in] str The name of the id.
+ * @pre `str` must either be an instance of ::rb_cSymbol, or an instance
+ * of ::rb_cString, or responds to `#to_str` method.
+ * @exception rb_eTypeError Can't convert `str` into ::rb_cString.
+ * @exception rb_eEncodingError Given string contains invalid character(s).
+ * @exception rb_eRuntimeError Too many symbols.
+ * @return A (possibly new) id whose value is the given str.
+ * @note These days Ruby internally has two kinds of symbols
+ * (static/dynamic). Symbols created using this function would
+ * become static ones; i.e. would never be garbage collected. It
+ * is up to you to avoid memory leaks. Think twice before using
+ * it.
+ * @see rb_str_to_str
*/
ID rb_to_id(VALUE str);
@@ -245,17 +249,14 @@ RBIMPL_ATTR_NONNULL(())
* of ::rb_cSymbol, or an instance of ::rb_cString, or responds
* to `#to_str` method.
* @exception rb_eTypeError Can't convert `*namep` into ::rb_cString.
- * @exception rb_eEncodingError Given string is non-ASCII.
+ * @exception rb_eEncodingError Given string contains invalid character(s).
* @retval RUBY_Qnil No such id ever existed in the history.
* @retval otherwise The id that represents the given name.
* @post The object that `*namep` points to is a converted result
* object, which is always an instance of either ::rb_cSymbol
* or ::rb_cString.
* @see https://bugs.ruby-lang.org/issues/5072
- *
- * @internal
- *
- * @shyouhei doesn't know why this has to raise rb_eEncodingError.
+ * @see rb_str_to_str
*/
VALUE rb_check_symbol(volatile VALUE *namep);
RBIMPL_SYMBOL_EXPORT_END()
diff --git a/include/ruby/internal/value_type.h b/include/ruby/internal/value_type.h
index b47d8afb97..77cb38bc7d 100644
--- a/include/ruby/internal/value_type.h
+++ b/include/ruby/internal/value_type.h
@@ -410,14 +410,6 @@ RB_TYPE_P(VALUE obj, enum ruby_value_type t)
#endif
/** @endcond */
-RBIMPL_ATTR_PURE()
-RBIMPL_ATTR_ARTIFICIAL()
-/**
- * @private
- * Defined in ruby/internal/core/rtypeddata.h
- */
-static inline bool rbimpl_rtypeddata_p(VALUE obj);
-
RBIMPL_ATTR_ARTIFICIAL()
/**
* Identical to RB_TYPE_P(), except it raises exceptions on predication
@@ -432,19 +424,11 @@ RBIMPL_ATTR_ARTIFICIAL()
static inline void
Check_Type(VALUE v, enum ruby_value_type t)
{
+ /* Typed data is not simple `T_DATA`, see `rb_check_type` */
+ RUBY_ASSERT_ALWAYS(t != RUBY_T_DATA);
if (RB_UNLIKELY(! RB_TYPE_P(v, t))) {
- goto unexpected_type;
+ rb_unexpected_type(v, RBIMPL_CAST((int)t));
}
- else if (t == RUBY_T_DATA && rbimpl_rtypeddata_p(v)) {
- /* Typed data is not simple `T_DATA`, see `rb_check_type` */
- goto unexpected_type;
- }
- else {
- return;
- }
-
- unexpected_type:
- rb_unexpected_type(v, RBIMPL_CAST((int)t));
}
#endif /* RBIMPL_VALUE_TYPE_H */
diff --git a/include/ruby/internal/warning_push.h b/include/ruby/internal/warning_push.h
index f5981633f8..91d62cb00d 100644
--- a/include/ruby/internal/warning_push.h
+++ b/include/ruby/internal/warning_push.h
@@ -79,7 +79,7 @@
*/
#define RBIMPL_WARNING_IGNORED(flag) __pragma(warning(disable: flag))
-#elif RBIMPL_COMPILER_SINCE(MSVC, 12, 0, 0)
+#elif RBIMPL_COMPILER_IS(MSVC)
# /* Not sure exactly when but it seems VC++ 6.0 is a version with it.*/
# define RBIMPL_WARNING_PUSH() __pragma(warning(push))
# define RBIMPL_WARNING_POP() __pragma(warning(pop))
diff --git a/include/ruby/internal/xmalloc.h b/include/ruby/internal/xmalloc.h
index 132bc478ce..2551609123 100644
--- a/include/ruby/internal/xmalloc.h
+++ b/include/ruby/internal/xmalloc.h
@@ -57,6 +57,10 @@
#define xrealloc2 ruby_xrealloc2 /**< @old{ruby_xrealloc2} */
#define xfree ruby_xfree /**< @old{ruby_xfree} */
+#define xfree_sized ruby_xfree_sized
+#define xrealloc_sized ruby_xrealloc_sized
+#define xrealloc2_sized ruby_xrealloc2_sized
+
RBIMPL_SYMBOL_EXPORT_BEGIN()
RBIMPL_ATTR_NODISCARD()
@@ -196,6 +200,58 @@ RBIMPL_ATTR_NOEXCEPT(realloc(ptr, newsiz))
RBIMPL_ATTR_NODISCARD()
RBIMPL_ATTR_RETURNS_NONNULL()
+RBIMPL_ATTR_ALLOC_SIZE((2))
+/**
+ * Identical to ruby_xrealloc(), except that it takes the old storage size
+ * as third argument.
+ *
+ * @param[in] ptr A valid pointer to a storage instance that was
+ * previously returned from either:
+ * - ruby_xmalloc(),
+ * - ruby_xmalloc2(),
+ * - ruby_xcalloc(),
+ * - ruby_xrealloc(), or
+ * - ruby_xrealloc2().
+ * @param[in] newsiz Requested new amount of memory.
+ * @param[in] oldsiz Existing amount of memory.
+ * @exception rb_eNoMemError No space left for `newsiz` bytes allocation.
+ * @return A valid pointer to a (possibly newly allocated) storage
+ * instance; which has at least `newsiz` bytes width, with
+ * appropriate alignment detected by the underlying realloc()
+ * routine.
+ * @pre The passed pointer must point to a valid live storage instance.
+ * It is a failure to pass an already freed pointer.
+ * @pre The passed oldsiz must be exactly equal to the size the pointer
+ * was allocated with.
+ * Passing an incorrect oldsiz is undefined behavior, which may
+ * cause memory leaks or crashes.
+ * @post In case the function returns the passed pointer as-is, the
+ * storage instance that the pointer holds is either grown or
+ * shrunken to have at least `newsiz` bytes. Otherwise a valid
+ * pointer to a newly allocated storage instance is returned. In
+ * this case `ptr` is invalidated as if it was passed to
+ * ruby_xfree().
+ * @note It doesn't return NULL.
+ * @warning Unlike some realloc() implementations, passing zero to `newsiz`
+ * is not the same as calling ruby_xfree(), because this function
+ * never returns NULL. Something meaningful still returns then.
+ * @warning It is a failure not to check the return value. Do not assume
+ * anything on it. It could be either identical to, or distinct
+ * form the passed argument.
+ * @warning Do not assume anything on the alignment of the return value.
+ * There is no guarantee that it inherits the passed argument's
+ * one.
+ * @warning The return value shall be invalidated exactly once by either
+ * ruby_xfree(), ruby_xrealloc(), or ruby_xrealloc2(). It is a
+ * failure to pass it to system free(), because the system and Ruby
+ * might or might not share the same malloc() implementation.
+ */
+void *ruby_xrealloc_sized(void *ptr, size_t newsiz, size_t oldsiz)
+RBIMPL_ATTR_NOEXCEPT(realloc(ptr, newsiz))
+;
+
+RBIMPL_ATTR_NODISCARD()
+RBIMPL_ATTR_RETURNS_NONNULL()
RBIMPL_ATTR_ALLOC_SIZE((2,3))
/**
* Identical to ruby_xrealloc(), except it resizes the given storage instance
@@ -251,6 +307,64 @@ void *ruby_xrealloc2(void *ptr, size_t newelems, size_t newsiz)
RBIMPL_ATTR_NOEXCEPT(realloc(ptr, newelems * newsiz))
;
+RBIMPL_ATTR_NODISCARD()
+RBIMPL_ATTR_RETURNS_NONNULL()
+RBIMPL_ATTR_ALLOC_SIZE((2,3))
+/**
+ * Identical to ruby_xrealloc2(), except it takes the old elements count.
+ *
+ * This is roughly the same as reallocarray() function that OpenBSD
+ * etc. provides, but also interacts with our GC.
+ *
+ * @param[in] ptr A valid pointer to a storage instance that was
+ * previously returned from either:
+ * - ruby_xmalloc(),
+ * - ruby_xmalloc2(),
+ * - ruby_xcalloc(),
+ * - ruby_xrealloc(), or
+ * - ruby_xrealloc2().
+ * @param[in] newelems Requested new number of elements.
+ * @param[in] newsiz Requested new size of each element.
+ * @param[in] oldelems The number of elements the pointer was
+ * previously allocated with.
+ * @exception rb_eNoMemError No space left for allocation.
+ * @exception rb_eArgError `newelems` * `newsiz` would overflow.
+ * @return A valid pointer to a (possibly newly allocated) storage
+ * instance; which has at least `newelems` * `newsiz` bytes width,
+ * with appropriate alignment detected by the underlying realloc()
+ * routine.
+ * @pre The passed pointer must point to a valid live storage instance.
+ * It is a failure to pass an already freed pointer.
+ * @pre The passed oldelems must be exactly equal to the number of
+ * elements the pointer was allocated with.
+ * Passing an incorrect oldelems is undefined behavior, which may
+ * cause memory leaks or crashes.
+ * @post In case the function returns the passed pointer as-is, the
+ * storage instance that the pointer holds is either grown or
+ * shrunken to have at least `newelems` * `newsiz` bytes.
+ * Otherwise a valid pointer to a newly allocated storage instance
+ * is returned. In this case `ptr` is invalidated as if it was
+ * passed to ruby_xfree().
+ * @note It doesn't return NULL.
+ * @warning Unlike some realloc() implementations, passing zero to either
+ * `newelems` or `elemsiz` are not the same as calling
+ * ruby_xfree(), because this function never returns NULL.
+ * Something meaningful still returns then.
+ * @warning It is a failure not to check the return value. Do not assume
+ * anything on it. It could be either identical to, or distinct
+ * form the passed argument.
+ * @warning Do not assume anything on the alignment of the return value.
+ * There is no guarantee that it inherits the passed argument's
+ * one.
+ * @warning The return value shall be invalidated exactly once by either
+ * ruby_xfree(), ruby_xrealloc(), or ruby_xrealloc2(). It is a
+ * failure to pass it to system free(), because the system and Ruby
+ * might or might not share the same malloc() implementation.
+ */
+void *ruby_xrealloc2_sized(void *ptr, size_t newelems, size_t newsiz, size_t oldelems)
+RBIMPL_ATTR_NOEXCEPT(realloc(ptr, newelems * newsiz))
+;
+
/**
* Deallocates a storage instance.
*
@@ -283,6 +397,43 @@ void ruby_xfree(void *ptr)
RBIMPL_ATTR_NOEXCEPT(free(ptr))
;
+/**
+ * Deallocates a storage instance of a specific ssize.
+ *
+ * @param[out] ptr Either
+ * - NULL, or
+ * - a valid pointer previously returned from one of:
+ * - ruby_xmalloc(),
+ * - ruby_xmalloc2(),
+ * - ruby_xcalloc(),
+ * - ruby_xrealloc(), or
+ * - ruby_xrealloc2().
+ * @pre The passed pointer must point to a valid live storage instance.
+ * It is a failure to pass an already freed pointer.
+ * @pre The passed size must be exactly equal to the size the pointer
+ * was allocated with.
+ * Passing an incorrect size is undefined behavior, which may
+ * cause memory leaks or crashes.
+ * @post The storage instance pointed by the passed pointer gets
+ * invalidated; it is no longer addressable.
+ * @warning Every single storage instance that was previously allocated by
+ * either ruby_xmalloc(), ruby_xmalloc2(), ruby_xcalloc(),
+ * ruby_xrealloc(), or ruby_xrealloc2() shall be invalidated
+ * exactly once by either passing it to ruby_xfree(), or passing
+ * it to either ruby_xrealloc(), ruby_xrealloc2() then check the
+ * return value for invalidation.
+ * @warning Do not pass anything other than pointers described above. For
+ * instance pointers returned from malloc() or mmap() shall not be
+ * passed to this function, because the underlying memory
+ * management mechanism could differ.
+ * @warning Do not pass any invalid pointers to this function e.g. by
+ * calling it twice with a same argument.
+ */
+void ruby_xfree_sized(void *ptr, size_t size)
+RBIMPL_ATTR_NOEXCEPT(free(ptr))
+;
+
+
RBIMPL_SYMBOL_EXPORT_END()
#endif /* RBIMPL_XMALLOC_H */
diff --git a/include/ruby/onigmo.h b/include/ruby/onigmo.h
index db290cd47a..5c2ebe55fe 100644
--- a/include/ruby/onigmo.h
+++ b/include/ruby/onigmo.h
@@ -4,8 +4,8 @@
onigmo.h - Onigmo (Oniguruma-mod) (regular expression library)
**********************************************************************/
/*-
- * Copyright (c) 2002-2009 K.Kosako <sndgk393 AT ybb DOT ne DOT jp>
- * Copyright (c) 2011-2017 K.Takata <kentkt AT csc DOT jp>
+ * Copyright (c) 2002-2016 K.Kosako <sndgk393 AT ybb DOT ne DOT jp>
+ * Copyright (c) 2011-2019 K.Takata <kentkt AT csc DOT jp>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -38,8 +38,8 @@ extern "C" {
#endif
#define ONIGMO_VERSION_MAJOR 6
-#define ONIGMO_VERSION_MINOR 1
-#define ONIGMO_VERSION_TEENY 3
+#define ONIGMO_VERSION_MINOR 2
+#define ONIGMO_VERSION_TEENY 0
#ifndef ONIG_EXTERN
# ifdef RUBY_EXTERN
@@ -687,6 +687,8 @@ ONIG_EXTERN const OnigSyntaxType* OnigDefaultSyntax;
#define ONIGERR_NEVER_ENDING_RECURSION -221
#define ONIGERR_GROUP_NUMBER_OVER_FOR_CAPTURE_HISTORY -222
#define ONIGERR_INVALID_CHAR_PROPERTY_NAME -223
+#define ONIGERR_TOO_MANY_RANGE_REPEAT -224
+#define ONIGERR_TOO_MANY_NULL_CHECK -225
#define ONIGERR_INVALID_CODE_POINT_VALUE -400
#define ONIGERR_INVALID_WIDE_CHAR_VALUE -400
#define ONIGERR_TOO_BIG_WIDE_CHAR_VALUE -401
@@ -789,8 +791,8 @@ typedef struct re_pattern_buffer {
unsigned char *exact;
unsigned char *exact_end;
unsigned char map[ONIG_CHAR_TABLE_SIZE]; /* used as BM skip or char-map */
- int *int_map; /* BM skip for exact_len > 255 */
- int *int_map_backward; /* BM skip for backward search */
+ int *reserved1;
+ int *reserved2;
OnigDistance dmin; /* min-distance of exact or map */
OnigDistance dmax; /* max-distance of exact or map */
diff --git a/include/ruby/ractor.h b/include/ruby/ractor.h
index 7811616f6d..8cfca21621 100644
--- a/include/ruby/ractor.h
+++ b/include/ruby/ractor.h
@@ -217,7 +217,7 @@ VALUE rb_ractor_make_shareable(VALUE obj);
*
* @param[in] obj Arbitrary ruby object to duplicate.
* @exception rb_eRactorError Ractors cannot share `obj` by nature.
- * @return A deep copy of `obj` which is sharable among Ractors.
+ * @return A deep copy of `obj` which is shareable among Ractors.
*/
VALUE rb_ractor_make_shareable_copy(VALUE obj);
@@ -261,4 +261,18 @@ rb_ractor_shareable_p(VALUE obj)
}
}
+// TODO: optimize on interpreter core
+#ifndef RB_OBJ_SET_SHAREABLE
+VALUE rb_obj_set_shareable(VALUE obj); // ractor.c
+#define RB_OBJ_SET_SHAREABLE(obj) rb_obj_set_shareable(obj)
+#endif
+
+static inline VALUE
+RB_OBJ_SET_FROZEN_SHAREABLE(VALUE obj)
+{
+ RB_OBJ_FREEZE(obj);
+ RB_OBJ_SET_SHAREABLE(obj);
+ return obj;
+}
+
#endif /* RUBY_RACTOR_H */
diff --git a/include/ruby/random.h b/include/ruby/random.h
index f3df0d96fb..3b63a23334 100644
--- a/include/ruby/random.h
+++ b/include/ruby/random.h
@@ -332,7 +332,8 @@ RBIMPL_ATTR_PURE_UNLESS_DEBUG()
static inline const rb_random_interface_t *
rb_rand_if(VALUE obj)
{
- RBIMPL_ASSERT_OR_ASSUME(RTYPEDDATA_P(obj));
+ RBIMPL_ASSERT_OR_ASSUME(RB_TYPE_P(obj, T_DATA));
+ RUBY_ASSERT(rb_typeddata_is_kind_of(obj, &rb_random_data_type));
const struct rb_data_type_struct *t = RTYPEDDATA_TYPE(obj);
const void *ret = t->data;
return RBIMPL_CAST((const rb_random_interface_t *)ret);
diff --git a/include/ruby/st.h b/include/ruby/st.h
index f35ab43603..b510989b6b 100644
--- a/include/ruby/st.h
+++ b/include/ruby/st.h
@@ -84,13 +84,12 @@ struct st_table {
const struct st_hash_type *type;
/* Number of entries currently in the table. */
st_index_t num_entries;
- /* Array of bins used for access by keys. */
- st_index_t *bins;
/* Start and bound index of entries in array entries.
entries_starts and entries_bound are in interval
[0,allocated_entries]. */
st_index_t entries_start, entries_bound;
- /* Array of size 2^entry_power. */
+ /* Array of size 2^entry_power.
+ Optionnally followed by an array of bins used for access by keys. */
st_table_entry *entries;
};
diff --git a/include/ruby/version.h b/include/ruby/version.h
index a521d925ed..5bb381cea2 100644
--- a/include/ruby/version.h
+++ b/include/ruby/version.h
@@ -61,13 +61,13 @@
* doesn't mean a total rewrite. Practically when it comes to API versioning,
* major and minor version changes are equally catastrophic.
*/
-#define RUBY_API_VERSION_MAJOR 3
+#define RUBY_API_VERSION_MAJOR 4
/**
* 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 5
+#define RUBY_API_VERSION_MINOR 1
/**
* Teeny version. This digit is kind of reserved these days. Kept 0 for the
diff --git a/include/ruby/win32.h b/include/ruby/win32.h
index 31dc13e932..ae11a61481 100644
--- a/include/ruby/win32.h
+++ b/include/ruby/win32.h
@@ -30,15 +30,10 @@ extern "C++" { /* template without extern "C++" */
#if !defined(_WIN64) && !defined(WIN32)
#define WIN32
#endif
-#if defined(_MSC_VER) && _MSC_VER <= 1200
-#include <windows.h>
-#endif
#include <winsock2.h>
#include <ws2tcpip.h>
#include <mswsock.h>
-#if !defined(_MSC_VER) || _MSC_VER >= 1400
#include <iphlpapi.h>
-#endif
#if defined(__cplusplus) && defined(_MSC_VER)
}
#endif
@@ -59,13 +54,7 @@ extern "C++" { /* template without extern "C++" */
#include <direct.h>
#include <process.h>
#include <time.h>
-#if defined(__cplusplus) && defined(_MSC_VER) && _MSC_VER == 1200
-extern "C++" { /* template without extern "C++" */
-#endif
#include <math.h>
-#if defined(__cplusplus) && defined(_MSC_VER) && _MSC_VER == 1200
-}
-#endif
#include <signal.h>
#include <sys/stat.h>
#include <sys/types.h>
@@ -126,28 +115,30 @@ typedef unsigned int uintptr_t;
#define O_SHARE_DELETE 0x20000000 /* for rb_w32_open(), rb_w32_wopen() */
typedef int clockid_t;
-#if defined(__MINGW32__)
-/* I don't know why but these return some strange values. */
-#undef CLOCK_PROCESS_CPUTIME_ID
-#undef CLOCK_THREAD_CPUTIME_ID
-#undef CLOCK_REALTIME_COARSE
-#endif
-/* defined in win32/win32.c for old versions */
-#if !defined(__MINGW32__) || !defined(HAVE_CLOCK_GETTIME)
-# define HAVE_CLOCK_GETTIME 1
-# define NEED_CLOCK_GETTIME 1
-#endif
-#if !defined(__MINGW32__) || !defined(HAVE_CLOCK_GETRES)
-# define HAVE_CLOCK_GETRES 1
-# define NEED_CLOCK_GETRES 1
-#endif
+/*
+ * Since we use our versions in win32/win32.c, not to depend on yet
+ * another DLL, prefix our versions not to conflict with inline
+ * versions provided in time.h.
+ */
+#define clock_gettime rb_w32_clock_gettime
+#define clock_getres rb_w32_clock_getres
+
#ifndef CLOCK_REALTIME
# define CLOCK_REALTIME 0
#endif
#ifndef CLOCK_MONOTONIC
# define CLOCK_MONOTONIC 1
#endif
+#ifndef CLOCK_PROCESS_CPUTIME_ID
+# define CLOCK_PROCESS_CPUTIME_ID 2
+#endif
+#ifndef CLOCK_THREAD_CPUTIME_ID
+# define CLOCK_THREAD_CPUTIME_ID 3
+#endif
+#ifndef CLOCK_REALTIME_COARSE
+# define CLOCK_REALTIME_COARSE 4
+#endif
#undef utime
#undef lseek
@@ -271,7 +262,6 @@ struct ifaddrs {
#endif
extern void rb_w32_sysinit(int *, char ***);
-extern DWORD rb_w32_osid(void);
extern int flock(int fd, int oper);
extern int rb_w32_io_cancelable_p(int);
extern int rb_w32_is_socket(int);
@@ -315,7 +305,11 @@ extern void rb_w32_free_environ(char **);
extern int rb_w32_map_errno(DWORD);
extern const char *WSAAPI rb_w32_inet_ntop(int,const void *,char *,size_t);
extern int WSAAPI rb_w32_inet_pton(int,const char *,void *);
-extern DWORD rb_w32_osver(void);
+
+RBIMPL_ATTR_DEPRECATED(("as Windows 9x is not supported already"))
+static inline DWORD rb_w32_osid(void) {return VER_PLATFORM_WIN32_NT;}
+RBIMPL_ATTR_DEPRECATED(("by Windows Version Helper APIs"))
+extern DWORD rb_w32_osver(void);
extern int rb_w32_uchown(const char *, int, int);
extern int rb_w32_ulink(const char *, const char *);
@@ -351,7 +345,7 @@ extern int rb_w32_dup2(int, int);
#include <float.h>
-#if defined _MSC_VER && _MSC_VER >= 1800 && defined INFINITY
+#if defined _MSC_VER && defined INFINITY
#pragma warning(push)
#pragma warning(disable:4756)
static inline float
@@ -434,11 +428,6 @@ extern int rb_w32_utruncate(const char *path, rb_off_t length);
#define HAVE_TRUNCATE 1
#define truncate rb_w32_utruncate
-#if defined(_MSC_VER) && _MSC_VER >= 1400 && _MSC_VER < 1800
-#define strtoll _strtoi64
-#define strtoull _strtoui64
-#endif
-
/*
* stubs
*/
diff --git a/inits.c b/inits.c
index e0dab9e890..4988fa09d0 100644
--- a/inits.c
+++ b/inits.c
@@ -52,6 +52,8 @@ rb_call_inits(void)
CALL(Time);
CALL(Random);
CALL(load);
+ CALL(Ruby_module);
+ CALL(Box);
CALL(Proc);
CALL(Binding);
CALL(Math);
@@ -78,7 +80,6 @@ rb_call_inits(void)
CALL(Prism);
CALL(unicode_version);
CALL(Set);
- CALL(Namespace);
// enable builtin loading
CALL(builtin);
diff --git a/insns.def b/insns.def
index f21a1810a5..3ad378081a 100644
--- a/insns.def
+++ b/insns.def
@@ -145,6 +145,7 @@ getblockparamproxy
(lindex_t idx, rb_num_t level)
()
(VALUE val)
+// attr bool zjit_profile = true;
{
const VALUE *ep = vm_get_ep(GET_EP(), level);
VM_ASSERT(VM_ENV_LOCAL_P(ep));
@@ -212,6 +213,7 @@ getinstancevariable
(VALUE val)
/* Ractor crashes when it accesses class/module-level instances variables. */
// attr bool leaf = false; /* has IVAR_ACCESSOR_SHOULD_BE_MAIN_RACTOR() */
+// attr bool zjit_profile = true;
{
val = vm_getinstancevariable(GET_ISEQ(), GET_SELF(), id, ic);
}
@@ -223,6 +225,7 @@ setinstancevariable
(VALUE val)
()
// attr bool leaf = false; /* has rb_check_frozen() */
+// attr bool zjit_profile = true;
{
vm_setinstancevariable(GET_ISEQ(), GET_SELF(), id, val, ic);
}
@@ -370,7 +373,7 @@ putspecialobject
/* put string val. string will be copied. */
DEFINE_INSN
-putstring
+dupstring
(VALUE str)
()
(VALUE val)
@@ -380,7 +383,7 @@ putstring
/* put chilled string val. string will be copied but frozen in the future. */
DEFINE_INSN
-putchilledstring
+dupchilledstring
(VALUE str)
()
(VALUE val)
@@ -426,9 +429,7 @@ toregexp
// attr bool leaf = false;
// attr rb_snum_t sp_inc = 1 - (rb_snum_t)cnt;
{
- const VALUE ary = rb_ary_tmp_new_from_values(0, cnt, STACK_ADDR_FROM_TOP(cnt));
- val = rb_reg_new_ary(ary, (int)opt);
- rb_ary_clear(ary);
+ val = rb_reg_new_from_values(cnt, STACK_ADDR_FROM_TOP(cnt), (int)opt);
}
/* intern str to Symbol and push it. */
@@ -566,6 +567,7 @@ splatkw
(VALUE hash, VALUE block)
(VALUE obj, VALUE block)
// attr bool leaf = false; /* has rb_to_hash_type() */
+// attr bool zjit_profile = true;
{
if (NIL_P(hash)) {
obj = Qnil;
@@ -587,8 +589,7 @@ newhash
RUBY_DTRACE_CREATE_HOOK(HASH, num);
if (num) {
- val = rb_hash_new_with_size(num / 2);
- rb_hash_bulk_insert(num, STACK_ADDR_FROM_TOP(num), val);
+ val = rb_hash_new_with_bulk_insert(num, STACK_ADDR_FROM_TOP(num));
}
else {
val = rb_hash_new();
@@ -744,6 +745,7 @@ definedivar
()
(VALUE val)
// attr bool leaf = false;
+// attr bool zjit_profile = true;
{
val = Qnil;
if (!UNDEF_P(vm_getivar(GET_SELF(), id, GET_ISEQ(), ic, NULL, FALSE, Qundef))) {
@@ -802,13 +804,20 @@ defineclass
(VALUE val)
{
VALUE klass = vm_find_or_create_class_by_id(id, flags, cbase, super);
+ const rb_box_t *box = rb_current_box();
rb_iseq_check(class_iseq);
+ rb_cref_t *cref = vm_cref_push(ec, klass, NULL, FALSE, FALSE);
+
+ if (VM_DEFINECLASS_DYNAMIC_CREF_P(flags)) {
+ CREF_DYNAMIC_SET(cref);
+ }
+
/* enter scope */
vm_push_frame(ec, class_iseq, VM_FRAME_MAGIC_CLASS | VM_ENV_FLAG_LOCAL, klass,
- GET_BLOCK_HANDLER(),
- (VALUE)vm_cref_push(ec, klass, NULL, FALSE, FALSE),
+ GC_GUARDED_PTR(box),
+ (VALUE)cref,
ISEQ_BODY(class_iseq)->iseq_encoded, GET_SP(),
ISEQ_BODY(class_iseq)->local_table_size,
ISEQ_BODY(class_iseq)->stack_max);
@@ -844,6 +853,7 @@ send
(CALL_DATA cd, ISEQ blockiseq)
(...)
(VALUE val)
+// attr bool zjit_profile = true;
// attr rb_snum_t sp_inc = sp_inc_of_sendish(cd->ci);
// attr rb_snum_t comptime_sp_inc = sp_inc_of_sendish(ci);
{
@@ -919,7 +929,7 @@ opt_new
// The bookkeeping slot should be empty.
RUBY_ASSERT(TOPN(argc + 1) == Qnil);
- if (vm_method_cfunc_is(GET_ISEQ(), cd, val, rb_class_new_instance_pass_kw)) {
+ if (vm_method_cfunc_is(GET_CFP(), cd, val, rb_class_new_instance_pass_kw)) {
RB_DEBUG_COUNTER_INC(opt_new_hit);
val = rb_obj_alloc(val);
TOPN(argc) = val;
@@ -938,8 +948,9 @@ objtostring
(VALUE recv)
(VALUE val)
// attr bool leaf = false;
+// attr bool zjit_profile = true;
{
- val = vm_objtostring(GET_ISEQ(), recv, cd);
+ val = vm_objtostring(GET_CFP(), recv, cd);
if (UNDEF_P(val)) {
CALL_SIMPLE_METHOD();
@@ -998,7 +1009,7 @@ opt_nil_p
(VALUE val)
// attr bool zjit_profile = true;
{
- val = vm_opt_nil_p(GET_ISEQ(), cd, recv);
+ val = vm_opt_nil_p(GET_CFP(), cd, recv);
if (UNDEF_P(val)) {
CALL_SIMPLE_METHOD();
@@ -1086,11 +1097,27 @@ invokesuper
(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);
+// attr bool zjit_profile = true;
{
- 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);
+ struct rb_callinfo adjusted_ci = VM_CI_ON_STACK(vm_ci_mid(cd->ci),
+ vm_ci_flag(cd->ci),
+ vm_ci_argc(cd->ci),
+ vm_ci_kwarg(cd->ci));
+ const struct rb_callcache *original_cc = rbimpl_atomic_ptr_load((void **)&cd->cc, RBIMPL_ATOMIC_ACQUIRE);
+ struct rb_call_data adjusted_cd = {
+ .ci = &adjusted_ci,
+ .cc = original_cc,
+ };
+
+ VALUE bh = vm_caller_setup_arg_block(ec, GET_CFP(), adjusted_cd.ci, blockiseq, true);
+ val = vm_sendish(ec, GET_CFP(), &adjusted_cd, bh, mexp_search_super);
JIT_EXEC(ec, val);
+ if (original_cc != adjusted_cd.cc && vm_cc_markable(adjusted_cd.cc)) {
+ rbimpl_atomic_ptr_store((volatile void **)&cd->cc, (void *)adjusted_cd.cc, RBIMPL_ATOMIC_RELEASE);
+ RB_OBJ_WRITTEN(GET_ISEQ(), Qundef, adjusted_cd.cc);
+ }
+
if (UNDEF_P(val)) {
RESTORE_REGS();
NEXT_INSN();
@@ -1133,6 +1160,7 @@ invokeblock
// attr bool handles_sp = true;
// attr rb_snum_t sp_inc = sp_inc_of_invokeblock(cd->ci);
// attr rb_snum_t comptime_sp_inc = sp_inc_of_invokeblock(ci);
+// attr bool zjit_profile = true;
{
VALUE bh = VM_BLOCK_HANDLER_NONE;
val = vm_sendish(ec, GET_CFP(), cd, bh, mexp_search_invokeblock);
@@ -1205,7 +1233,7 @@ jump
()
()
/* Same discussion as leave. */
-// attr bool leaf = leafness_of_check_ints; /* has rb_threadptr_execute_interrupts() */
+// attr bool leaf = false; /* has rb_threadptr_execute_interrupts() */
{
RUBY_VM_CHECK_INTS(ec);
JUMP(dst);
@@ -1218,7 +1246,7 @@ branchif
(VALUE val)
()
/* Same discussion as jump. */
-// attr bool leaf = leafness_of_check_ints; /* has rb_threadptr_execute_interrupts() */
+// attr bool leaf = false; /* has rb_threadptr_execute_interrupts() */
{
if (RTEST(val)) {
RUBY_VM_CHECK_INTS(ec);
@@ -1233,7 +1261,7 @@ branchunless
(VALUE val)
()
/* Same discussion as jump. */
-// attr bool leaf = leafness_of_check_ints; /* has rb_threadptr_execute_interrupts() */
+// attr bool leaf = false; /* has rb_threadptr_execute_interrupts() */
{
if (!RTEST(val)) {
RUBY_VM_CHECK_INTS(ec);
@@ -1248,7 +1276,7 @@ branchnil
(VALUE val)
()
/* Same discussion as jump. */
-// attr bool leaf = leafness_of_check_ints; /* has rb_threadptr_execute_interrupts() */
+// attr bool leaf = false; /* has rb_threadptr_execute_interrupts() */
{
if (NIL_P(val)) {
RUBY_VM_CHECK_INTS(ec);
@@ -1256,6 +1284,56 @@ branchnil
}
}
+/* same as jump, but without interrupt check */
+DEFINE_INSN
+jump_without_ints
+(OFFSET dst)
+()
+()
+// attr bool leaf = true;
+{
+ JUMP(dst);
+}
+
+/* same as branchif, but without interrupt check */
+DEFINE_INSN
+branchif_without_ints
+(OFFSET dst)
+(VALUE val)
+()
+// attr bool leaf = true;
+{
+ if (RTEST(val)) {
+ JUMP(dst);
+ }
+}
+
+/* same as branchunless, but without interrupt check */
+DEFINE_INSN
+branchunless_without_ints
+(OFFSET dst)
+(VALUE val)
+()
+// attr bool leaf = true;
+{
+ if (!RTEST(val)) {
+ JUMP(dst);
+ }
+}
+
+/* same as branchnil, but without interrupt check */
+DEFINE_INSN
+branchnil_without_ints
+(OFFSET dst)
+(VALUE val)
+()
+// attr bool leaf = true;
+{
+ if (NIL_P(val)) {
+ JUMP(dst);
+ }
+}
+
/**********************************************************/
/* for optimize */
/**********************************************************/
@@ -1375,7 +1453,7 @@ opt_eq
(VALUE val)
// attr bool zjit_profile = true;
{
- val = opt_equality(GET_ISEQ(), recv, obj, cd);
+ val = opt_equality(GET_CFP(), recv, obj, cd);
if (UNDEF_P(val)) {
CALL_SIMPLE_METHOD();
@@ -1390,7 +1468,7 @@ opt_neq
(VALUE val)
// attr bool zjit_profile = true;
{
- val = vm_opt_neq(GET_ISEQ(), cd, cd_eq, recv, obj);
+ val = vm_opt_neq(GET_CFP(), cd, cd_eq, recv, obj);
if (UNDEF_P(val)) {
CALL_SIMPLE_METHOD();
@@ -1467,6 +1545,7 @@ opt_ltlt
* string. Then what happens if that codepoint does not exist in the
* string's encoding? Of course an exception. That's not a leaf. */
// attr bool leaf = false; /* has "invalid codepoint" exception */
+// attr bool zjit_profile = true;
{
val = vm_opt_ltlt(recv, obj);
@@ -1516,6 +1595,7 @@ opt_aref
* default_proc. This is a method call. So opt_aref is
* (surprisingly) not leaf. */
// attr bool leaf = false; /* has rb_funcall() */ /* calls #yield */
+// attr bool zjit_profile = true;
{
val = vm_opt_aref(recv, obj);
@@ -1533,6 +1613,7 @@ opt_aset
/* This is another story than opt_aref. When vm_opt_aset() resorts
* to rb_hash_aset(), which should call #hash for `obj`. */
// attr bool leaf = false; /* has rb_funcall() */ /* calls #hash */
+// attr bool zjit_profile = true;
{
val = vm_opt_aset(recv, obj, set);
@@ -1541,50 +1622,13 @@ opt_aset
}
}
-/* recv[str] = set */
-DEFINE_INSN
-opt_aset_with
-(VALUE key, CALL_DATA cd)
-(VALUE recv, VALUE val)
-(VALUE val)
-/* Same discussion as opt_aset. */
-// attr bool leaf = false; /* has rb_funcall() */ /* calls #hash */
-{
- VALUE tmp = vm_opt_aset_with(recv, key, val);
-
- if (!UNDEF_P(tmp)) {
- val = tmp;
- }
- else {
- TOPN(0) = rb_str_resurrect(key);
- PUSH(val);
- CALL_SIMPLE_METHOD();
- }
-}
-
-/* recv[str] */
-DEFINE_INSN
-opt_aref_with
-(VALUE key, CALL_DATA cd)
-(VALUE recv)
-(VALUE val)
-/* Same discussion as opt_aref. */
-// attr bool leaf = false; /* has rb_funcall() */ /* calls #yield */
-{
- val = vm_opt_aref_with(recv, key);
-
- if (UNDEF_P(val)) {
- PUSH(rb_str_resurrect(key));
- CALL_SIMPLE_METHOD();
- }
-}
-
/* optimized length */
DEFINE_INSN
opt_length
(CALL_DATA cd)
(VALUE recv)
(VALUE val)
+// attr bool zjit_profile = true;
{
val = vm_opt_length(recv, BOP_LENGTH);
@@ -1599,6 +1643,7 @@ opt_size
(CALL_DATA cd)
(VALUE recv)
(VALUE val)
+// attr bool zjit_profile = true;
{
val = vm_opt_length(recv, BOP_SIZE);
@@ -1613,6 +1658,7 @@ opt_empty_p
(CALL_DATA cd)
(VALUE recv)
(VALUE val)
+// attr bool zjit_profile = true;
{
val = vm_opt_empty_p(recv);
@@ -1627,6 +1673,7 @@ opt_succ
(CALL_DATA cd)
(VALUE recv)
(VALUE val)
+// attr bool zjit_profile = true;
{
val = vm_opt_succ(recv);
@@ -1641,8 +1688,9 @@ opt_not
(CALL_DATA cd)
(VALUE recv)
(VALUE val)
+// attr bool zjit_profile = true;
{
- val = vm_opt_not(GET_ISEQ(), cd, recv);
+ val = vm_opt_not(GET_CFP(), cd, recv);
if (UNDEF_P(val)) {
CALL_SIMPLE_METHOD();
@@ -1656,6 +1704,7 @@ opt_regexpmatch2
(VALUE obj2, VALUE obj1)
(VALUE val)
// attr bool leaf = false; /* match_at() has rb_thread_check_ints() */
+// attr bool zjit_profile = true;
{
val = vm_opt_regexpmatch2(obj2, obj1);
diff --git a/internal/array.h b/internal/array.h
index 398676df4a..a2cd06f2e3 100644
--- a/internal/array.h
+++ b/internal/array.h
@@ -37,6 +37,7 @@ 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);
+VALUE rb_ary_compact_bang(VALUE ary);
RUBY_EXTERN VALUE rb_cArray_empty_frozen;
static inline VALUE rb_ary_entry_internal(VALUE ary, long offset);
@@ -140,6 +141,8 @@ RARRAY_AREF(VALUE ary, long i)
VALUE val;
RBIMPL_ASSERT_TYPE(ary, RUBY_T_ARRAY);
+ RUBY_ASSERT(i < RARRAY_LEN(ary));
+
RBIMPL_WARNING_PUSH();
#if defined(__GNUC__) && !defined(__clang__) && __GNUC__ == 13
RBIMPL_WARNING_IGNORED(-Warray-bounds);
diff --git a/internal/basic_operators.h b/internal/basic_operators.h
index 5dc8d7fe8d..493d2fa7f7 100644
--- a/internal/basic_operators.h
+++ b/internal/basic_operators.h
@@ -24,6 +24,7 @@ enum ruby_basic_operators {
BOP_SUCC,
BOP_GT,
BOP_GE,
+ BOP_GTGT,
BOP_NOT,
BOP_NEQ,
BOP_MATCH,
diff --git a/internal/bignum.h b/internal/bignum.h
index 0ba21a4923..7389a17c74 100644
--- a/internal/bignum.h
+++ b/internal/bignum.h
@@ -9,6 +9,7 @@
* @brief Internal header for Bignums.
*/
#include "ruby/internal/config.h" /* for HAVE_LIBGMP */
+#include "internal/compilers.h" /* for FLEX_ARY_LEN */
#include <stddef.h> /* for size_t */
#ifdef HAVE_SYS_TYPES_H
@@ -76,26 +77,17 @@
#define RBIGNUM(obj) ((struct RBignum *)(obj))
#define BIGNUM_SIGN_BIT FL_USER1
#define BIGNUM_EMBED_FLAG ((VALUE)FL_USER2)
-#define BIGNUM_EMBED_LEN_NUMBITS 3
+
+/* This is likely more bits than we need today and will also need adjustment if
+ * we change GC slot sizes.
+ */
+#define BIGNUM_EMBED_LEN_NUMBITS 9
#define BIGNUM_EMBED_LEN_MASK \
- (~(~(VALUE)0U << BIGNUM_EMBED_LEN_NUMBITS) << BIGNUM_EMBED_LEN_SHIFT)
+ (RUBY_FL_USER11 | RUBY_FL_USER10 | RUBY_FL_USER9 | RUBY_FL_USER8 | RUBY_FL_USER7 | \
+ RUBY_FL_USER6 | RUBY_FL_USER5 | RUBY_FL_USER4 | RUBY_FL_USER3)
#define BIGNUM_EMBED_LEN_SHIFT \
(FL_USHIFT+3) /* bit offset of BIGNUM_EMBED_LEN_MASK */
-#ifndef BIGNUM_EMBED_LEN_MAX
-# if (SIZEOF_VALUE*RBIMPL_RVALUE_EMBED_LEN_MAX/SIZEOF_ACTUAL_BDIGIT) < (1 << BIGNUM_EMBED_LEN_NUMBITS)-1
-# define BIGNUM_EMBED_LEN_MAX (SIZEOF_VALUE*RBIMPL_RVALUE_EMBED_LEN_MAX/SIZEOF_ACTUAL_BDIGIT)
-# else
-# define BIGNUM_EMBED_LEN_MAX ((1 << BIGNUM_EMBED_LEN_NUMBITS)-1)
-# endif
-#endif
-
-enum rb_int_parse_flags {
- RB_INT_PARSE_SIGN = 0x01,
- RB_INT_PARSE_UNDERSCORE = 0x02,
- RB_INT_PARSE_PREFIX = 0x04,
- RB_INT_PARSE_ALL = 0x07,
- RB_INT_PARSE_DEFAULT = 0x07,
-};
+#define BIGNUM_EMBED_LEN_MAX (BIGNUM_EMBED_LEN_MASK >> BIGNUM_EMBED_LEN_SHIFT)
struct RBignum {
struct RBasic basic;
@@ -104,12 +96,18 @@ struct RBignum {
size_t len;
BDIGIT *digits;
} heap;
- BDIGIT ary[BIGNUM_EMBED_LEN_MAX];
+ /* 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
+ */
+ BDIGIT ary[1];
} as;
};
/* bignum.c */
extern const char ruby_digitmap[];
+extern const char ruby_decimal_digit_pairs[];
double rb_big_fdiv_double(VALUE x, VALUE y);
VALUE rb_big_uminus(VALUE x);
VALUE rb_big_hash(VALUE);
@@ -161,10 +159,15 @@ VALUE rb_big_divrem_gmp(VALUE x, VALUE y);
VALUE rb_big2str_gmp(VALUE x, int base);
VALUE rb_str2big_gmp(VALUE arg, int base, int badcheck);
#endif
-VALUE rb_int_parse_cstr(const char *str, ssize_t len, char **endp, size_t *ndigits, int base, int flags);
RUBY_SYMBOL_EXPORT_END
+#if HAVE_LONG_LONG
+VALUE rb_ull2big(unsigned LONG_LONG n);
+VALUE rb_ll2big(LONG_LONG n);
+#endif
+
#if defined(HAVE_INT128_T)
+VALUE rb_uint128t2big(uint128_t n);
VALUE rb_int128t2big(int128_t n);
#endif
diff --git a/internal/bits.h b/internal/bits.h
index 2b5aecf112..698ab3e219 100644
--- a/internal/bits.h
+++ b/internal/bits.h
@@ -30,13 +30,13 @@
#include <stdint.h> /* for uintptr_t */
#include "internal/compilers.h" /* for MSC_VERSION_SINCE */
-#if MSC_VERSION_SINCE(1310)
+#ifdef _MSC_VER
# include <stdlib.h> /* for _byteswap_uint64 */
#endif
#if defined(HAVE_X86INTRIN_H)
# include <x86intrin.h> /* for _lzcnt_u64 */
-#elif MSC_VERSION_SINCE(1310)
+#elif defined(_MSC_VER)
# include <intrin.h> /* for the following intrinsics */
#endif
@@ -50,16 +50,13 @@
# pragma intrinsic(__lzcnt64)
#endif
-#if MSC_VERSION_SINCE(1310)
+#if defined(_MSC_VER)
# 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
@@ -266,7 +263,7 @@ ruby_swap16(uint16_t x)
#if __has_builtin(__builtin_bswap16)
return __builtin_bswap16(x);
-#elif MSC_VERSION_SINCE(1310)
+#elif defined(_MSC_VER)
return _byteswap_ushort(x);
#else
@@ -281,7 +278,7 @@ ruby_swap32(uint32_t x)
#if __has_builtin(__builtin_bswap32)
return __builtin_bswap32(x);
-#elif MSC_VERSION_SINCE(1310)
+#elif defined(_MSC_VER)
return _byteswap_ulong(x);
#else
@@ -298,7 +295,7 @@ ruby_swap64(uint64_t x)
#if __has_builtin(__builtin_bswap64)
return __builtin_bswap64(x);
-#elif MSC_VERSION_SINCE(1310)
+#elif defined(_MSC_VER)
return _byteswap_uint64(x);
#else
@@ -323,7 +320,7 @@ nlz_int32(uint32_t x)
#elif defined(__x86_64__) && defined(__LZCNT__)
return (unsigned int)_lzcnt_u32(x);
-#elif MSC_VERSION_SINCE(1400) /* &&! defined(__AVX2__) */
+#elif defined(_MSC_VER) /* &&! defined(__AVX2__) */
unsigned long r;
return _BitScanReverse(&r, x) ? (31 - (int)r) : 32;
@@ -352,7 +349,7 @@ nlz_int64(uint64_t x)
#elif defined(__x86_64__) && defined(__LZCNT__)
return (unsigned int)_lzcnt_u64(x);
-#elif defined(_WIN64) && MSC_VERSION_SINCE(1400) /* &&! defined(__AVX2__) */
+#elif defined(_WIN64) && defined(_MSC_VER) /* &&! defined(__AVX2__) */
unsigned long r;
return _BitScanReverse64(&r, x) ? (63u - (unsigned int)r) : 64;
@@ -538,7 +535,7 @@ ntz_int32(uint32_t x)
#if defined(__x86_64__) && defined(__BMI__)
return (unsigned)_tzcnt_u32(x);
-#elif MSC_VERSION_SINCE(1400)
+#elif defined(_MSC_VER)
/* :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;
@@ -560,7 +557,7 @@ ntz_int64(uint64_t x)
#if defined(__x86_64__) && defined(__BMI__)
return (unsigned)_tzcnt_u64(x);
-#elif defined(_WIN64) && MSC_VERSION_SINCE(1400)
+#elif defined(_WIN64) && defined(_MSC_VER)
unsigned long r;
return _BitScanForward64(&r, x) ? (int)r : 64;
@@ -608,10 +605,10 @@ RUBY_BIT_ROTL(VALUE v, int 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)
+#elif defined(_MSC_VER) && (SIZEOF_VALUE * CHAR_BIT == 32)
return _rotl(v, n);
-#elif MSC_VERSION_SINCE(1310) && (SIZEOF_VALUE * CHAR_BIT == 64)
+#elif defined(_MSC_VER) && (SIZEOF_VALUE * CHAR_BIT == 64)
return _rotl64(v, n);
#elif defined(_lrotl) && (SIZEOF_VALUE == SIZEOF_LONG)
@@ -632,10 +629,10 @@ RUBY_BIT_ROTR(VALUE v, int 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)
+#elif defined(_MSC_VER) && (SIZEOF_VALUE * CHAR_BIT == 32)
return _rotr(v, n);
-#elif MSC_VERSION_SINCE(1310) && (SIZEOF_VALUE * CHAR_BIT == 64)
+#elif defined(_MSC_VER) && (SIZEOF_VALUE * CHAR_BIT == 64)
return _rotr64(v, n);
#elif defined(_lrotr) && (SIZEOF_VALUE == SIZEOF_LONG)
diff --git a/internal/box.h b/internal/box.h
new file mode 100644
index 0000000000..c717dc4e24
--- /dev/null
+++ b/internal/box.h
@@ -0,0 +1,96 @@
+#ifndef INTERNAL_BOX_H /*-*-C-*-vi:se ft=c:*/
+#define INTERNAL_BOX_H
+
+#include "ruby/ruby.h" /* for VALUE */
+
+/**
+ * @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 Ruby Box.
+ */
+struct rb_box_struct {
+ /*
+ * To retrieve Ruby::Box object that provides #require and so on.
+ * That is used from load.c, etc., that uses rb_box_t internally.
+ */
+ VALUE box_object;
+ long box_id; // box_id to generate ext filenames
+
+ VALUE top_self;
+
+ VALUE load_path;
+ VALUE load_path_snapshot;
+ VALUE load_path_check_cache;
+ VALUE expanded_load_path;
+ VALUE loaded_features;
+ VALUE loaded_features_snapshot;
+ VALUE loaded_features_realpaths;
+ VALUE loaded_features_realpath_map;
+ struct st_table *loaded_features_index;
+ struct st_table *loading_table;
+ VALUE ruby_dln_libmap;
+
+ VALUE gvar_tbl;
+ struct st_table *classext_cow_classes;
+
+ bool is_root;
+ bool is_user;
+ bool is_optional;
+};
+typedef struct rb_box_struct rb_box_t;
+
+struct rb_box_gem_flags {
+ bool gem;
+ bool error_highlight;
+ bool did_you_mean;
+ bool syntax_suggest;
+};
+typedef struct rb_box_gem_flags rb_box_gem_flags_t;
+
+#define BOX_OBJ_P(obj) (rb_obj_class(obj) == rb_cBox)
+
+#define BOX_MASTER_P(box) (box && !box->is_root && !box->is_user)
+#define BOX_MUTABLE_P(box) (box && (box->is_root || box->is_user))
+#define BOX_ROOT_P(box) (box && box->is_root)
+#define BOX_USER_P(box) (box && box->is_user)
+#define BOX_OPTIONAL_P(box) (box && box->is_optional)
+#define BOX_MAIN_P(box) (box && box->is_user && !box->is_optional)
+
+#define BOX_METHOD_DEFINITION(mdef) (mdef ? mdef->ns : NULL)
+#define BOX_METHOD_ENTRY(me) (me ? BOX_METHOD_DEFINITION(me->def) : NULL)
+#define BOX_CC(cc) (cc ? BOX_METHOD_ENTRY(cc->cme_) : NULL)
+#define BOX_CC_ENTRIES(ccs) (ccs ? BOX_METHOD_ENTRY(ccs->cme) : NULL)
+
+RUBY_EXTERN bool ruby_box_enabled;
+RUBY_EXTERN bool ruby_box_init_done;
+RUBY_EXTERN bool ruby_box_crashed;
+
+static inline bool
+rb_box_available(void)
+{
+ return ruby_box_enabled;
+}
+
+const rb_box_t * rb_master_box(void);
+const rb_box_t * rb_root_box(void);
+const rb_box_t * rb_main_box(void);
+const rb_box_t * rb_current_box(void);
+const rb_box_t * rb_loading_box(void);
+const rb_box_t * rb_current_box_in_crash_report(void);
+
+void rb_box_entry_mark(void *);
+void rb_box_gc_update_references(void *ptr);
+
+rb_box_t * rb_get_box_t(VALUE ns);
+VALUE rb_get_box_object(rb_box_t *ns);
+
+VALUE rb_box_local_extension(VALUE box, VALUE fname, VALUE path, VALUE *cleanup);
+void rb_box_cleanup_local_extension(VALUE cleanup);
+
+void rb_initialize_mandatory_boxes(void);
+void rb_box_init_done(void);
+void rb_box_set_gem_flags(rb_box_gem_flags_t *);
+#endif /* INTERNAL_BOX_H */
diff --git a/internal/class.h b/internal/class.h
index bed69adef7..0773dbad95 100644
--- a/internal/class.h
+++ b/internal/class.h
@@ -10,7 +10,7 @@
*/
#include "id.h"
#include "id_table.h" /* for struct rb_id_table */
-#include "internal/namespace.h" /* for rb_current_namespace */
+#include "internal/box.h"
#include "internal/serial.h" /* for rb_serial_t */
#include "internal/static_assert.h"
#include "internal/variable.h" /* for rb_class_ivar_set */
@@ -27,84 +27,30 @@
# undef RCLASS_SUPER
#endif
-struct rb_ns_subclasses {
- long refcount;
- struct st_table *tbl;
-};
-typedef struct rb_ns_subclasses rb_ns_subclasses_t;
-
-static inline long
-rb_ns_subclasses_ref_count(rb_ns_subclasses_t *ns_sub)
-{
- return ns_sub->refcount;
-}
-
-static inline rb_ns_subclasses_t *
-rb_ns_subclasses_ref_inc(rb_ns_subclasses_t *ns_sub)
-{
- ns_sub->refcount++;
- return ns_sub;
-}
-
-static inline void
-rb_ns_subclasses_ref_dec(rb_ns_subclasses_t *ns_sub)
-{
- ns_sub->refcount--;
- if (ns_sub->refcount == 0) {
- st_free_table(ns_sub->tbl);
- xfree(ns_sub);
- }
-}
-
-struct rb_subclass_anchor {
- rb_ns_subclasses_t *ns_subclasses;
- struct rb_subclass_entry *head;
-};
-typedef struct rb_subclass_anchor rb_subclass_anchor_t;
-
-struct rb_subclass_entry {
- VALUE klass;
- 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 {
+ VALUE imemo_flags;
uint32_t index;
rb_serial_t global_cvar_state;
- const rb_cref_t * cref;
+ const rb_cref_t *cref;
VALUE class_value;
};
struct rb_classext_struct {
- const rb_namespace_t *ns;
+ const rb_box_t *box;
VALUE super;
VALUE fields_obj; // Fields are either ivar or other internal properties stored inline
+ VALUE classpath;
struct rb_id_table *m_tbl;
struct rb_id_table *const_tbl;
struct rb_id_table *callable_m_tbl;
VALUE cc_tbl; /* { ID => { cme, [cc1, cc2, ...] }, ... } */
- struct rb_id_table *cvc_tbl;
+ VALUE cvc_tbl;
VALUE *superclasses;
/**
- * The head of subclasses is a blank (w/o klass) entry to be referred from anchor (and be never deleted).
- * (anchor -> head -> 1st-entry)
- */
- struct rb_subclass_anchor *subclasses;
- /**
- * The `ns_super_subclasses` points the `ns_subclasses` struct to retreive the subclasses
- * of the super class in a specific namespace.
- * In compaction GCs, collecting a classext should trigger the deletion of a rb_subclass_entry
- * from the super's subclasses. But it may be prevented by the read barrier.
- * Fetching the super's subclasses for a ns is to avoid the read barrier in that process.
+ * imemo_subclasses VALUE tracking this class's subclasses.
+ * Only used in prime classext. Lazily allocated on first subclass addition.
*/
- rb_ns_subclasses_t *ns_super_subclasses;
- /**
- * In the case that this is an `ICLASS`, `ns_module_subclasses` points to the link
- * in the module's `subclasses` list that indicates that the klass has been
- * included. Hopefully that makes sense.
- */
- rb_ns_subclasses_t *ns_module_subclasses;
+ VALUE subclasses;
const VALUE origin_;
const VALUE refined_class;
@@ -119,16 +65,15 @@ struct rb_classext_struct {
const VALUE includer;
} iclass;
} as;
- attr_index_t max_iv_count;
uint16_t superclass_depth;
- unsigned char variation_count;
+ attr_index_t max_iv_count;
+ uint8_t variation_count;
bool permanent_classpath : 1;
- bool cloned : 1;
bool shared_const_tbl : 1;
bool iclass_is_origin : 1;
bool iclass_origin_shared_mtbl : 1;
bool superclasses_with_self : 1;
- VALUE classpath;
+ bool expect_no_ivar : 1;
};
typedef struct rb_classext_struct rb_classext_t;
@@ -138,7 +83,7 @@ struct RClass {
struct RBasic basic;
VALUE object_id;
/*
- * If ns_classext_tbl is NULL, then the prime classext is readable (because no other classext exists).
+ * If box_classext_tbl is NULL, then the prime classext is readable (because no other classext exists).
* For the check whether writable or not, check flag RCLASS_PRIME_CLASSEXT_WRITABLE
*/
};
@@ -149,14 +94,14 @@ struct RClass_and_rb_classext_t {
};
#if SIZEOF_VALUE >= SIZEOF_LONG_LONG
-// Assert that classes can be embedded in heaps[2] (which has 160B slot size)
+// Assert that classes can be embedded in heaps[3] (256B slot size on 64-bit).
// On 32bit platforms there is no variable width allocation so it doesn't matter.
-STATIC_ASSERT(sizeof_rb_classext_t, sizeof(struct RClass_and_rb_classext_t) <= 4 * RVALUE_SIZE);
+STATIC_ASSERT(sizeof_rb_classext_t, sizeof(struct RClass_and_rb_classext_t) <= 256);
#endif
-struct RClass_namespaceable {
+struct RClass_boxable {
struct RClass_and_rb_classext_t base;
- st_table *ns_classext_tbl; // ns_object -> (rb_classext_t *)
+ st_table *box_classext_tbl; // box_object -> (rb_classext_t *)
};
static const uint16_t RCLASS_MAX_SUPERCLASS_DEPTH = ((uint16_t)-1);
@@ -170,13 +115,13 @@ static inline void RCLASS_SET_PRIME_CLASSEXT_WRITABLE(VALUE obj, bool writable);
#define RCLASS_EXT_PRIME(c) (&((struct RClass_and_rb_classext_t*)(c))->classext)
#define RCLASS_EXT_PRIME_P(ext, c) (&((struct RClass_and_rb_classext_t*)(c))->classext == ext)
-static inline rb_classext_t * RCLASS_EXT_READABLE_IN_NS(VALUE obj, const rb_namespace_t *ns);
+static inline rb_classext_t * RCLASS_EXT_READABLE_IN_BOX(VALUE obj, const rb_box_t *box);
static inline rb_classext_t * RCLASS_EXT_READABLE(VALUE obj);
-static inline rb_classext_t * RCLASS_EXT_WRITABLE_IN_NS(VALUE obj, const rb_namespace_t *ns);
+static inline rb_classext_t * RCLASS_EXT_WRITABLE_IN_BOX(VALUE obj, const rb_box_t *box);
static inline rb_classext_t * RCLASS_EXT_WRITABLE(VALUE obj);
// Raw accessor
-#define RCLASSEXT_NS(ext) (ext->ns)
+#define RCLASSEXT_BOX(ext) (ext->box)
#define RCLASSEXT_SUPER(ext) (ext->super)
#define RCLASSEXT_FIELDS(ext) (ext->fields_obj ? ROBJECT_FIELDS(ext->fields_obj) : NULL)
#define RCLASSEXT_FIELDS_OBJ(ext) (ext->fields_obj)
@@ -188,14 +133,11 @@ static inline rb_classext_t * RCLASS_EXT_WRITABLE(VALUE obj);
#define RCLASSEXT_SUPERCLASS_DEPTH(ext) (ext->superclass_depth)
#define RCLASSEXT_SUPERCLASSES(ext) (ext->superclasses)
#define RCLASSEXT_SUBCLASSES(ext) (ext->subclasses)
-#define RCLASSEXT_NS_SUPER_SUBCLASSES(ext) (ext->ns_super_subclasses)
-#define RCLASSEXT_NS_MODULE_SUBCLASSES(ext) (ext->ns_module_subclasses)
#define RCLASSEXT_ORIGIN(ext) (ext->origin_)
#define RCLASSEXT_REFINED_CLASS(ext) (ext->refined_class)
// class.allocator/singleton_class.attached_object are not accessed directly via RCLASSEXT_*
#define RCLASSEXT_INCLUDER(ext) (ext->as.iclass.includer)
#define RCLASSEXT_PERMANENT_CLASSPATH(ext) (ext->permanent_classpath)
-#define RCLASSEXT_CLONED(ext) (ext->cloned)
#define RCLASSEXT_SHARED_CONST_TBL(ext) (ext->shared_const_tbl)
#define RCLASSEXT_ICLASS_IS_ORIGIN(ext) (ext->iclass_is_origin)
#define RCLASSEXT_ICLASS_ORIGIN_SHARED_MTBL(ext) (ext->iclass_origin_shared_mtbl)
@@ -206,7 +148,7 @@ static inline void RCLASSEXT_SET_ORIGIN(rb_classext_t *ext, VALUE klass, VALUE o
static inline void RCLASSEXT_SET_INCLUDER(rb_classext_t *ext, VALUE klass, VALUE includer);
/* Prime classext entry accessor for very specific reason */
-#define RCLASS_PRIME_NS(c) (RCLASS_EXT_PRIME(c)->ns)
+#define RCLASS_PRIME_BOX(c) (RCLASS_EXT_PRIME(c)->box)
// To invalidate CC by inserting&invalidating method entry into tables containing the target cme
// See clear_method_cache_by_id_in_class()
#define RCLASS_PRIME_FIELDS_OBJ(c) (RCLASS_EXT_PRIME(c)->fields_obj)
@@ -218,7 +160,7 @@ static inline void RCLASSEXT_SET_INCLUDER(rb_classext_t *ext, VALUE klass, VALUE
#define RCLASS_CALLABLE_M_TBL_NOT_PRIME_P(c, tbl) (RCLASS_EXT_PRIME(c)->callable_m_tbl != tbl)
#define RCLASS_CC_TBL_NOT_PRIME_P(c, tbl) (RCLASS_EXT_PRIME(c)->cc_tbl != tbl)
-// Read accessor, regarding namespaces
+// Read accessor, regarding box
#define RCLASS_SUPER(c) (RCLASS_EXT_READABLE(c)->super)
#define RCLASS_M_TBL(c) (RCLASS_EXT_READABLE(c)->m_tbl)
#define RCLASS_CONST_TBL(c) (RCLASS_EXT_READABLE(c)->const_tbl)
@@ -227,12 +169,10 @@ static inline void RCLASSEXT_SET_INCLUDER(rb_classext_t *ext, VALUE klass, VALUE
* so always those should be writable.
*/
#define RCLASS_CVC_TBL(c) (RCLASS_EXT_READABLE(c)->cvc_tbl)
-#define RCLASS_SUBCLASSES_X(c) (RCLASS_EXT_READABLE(c)->subclasses)
-#define RCLASS_SUBCLASSES_FIRST(c) (RCLASS_EXT_READABLE(c)->subclasses->head->next)
+#define RCLASS_SUBCLASSES(c) (RCLASS_EXT_PRIME(c)->subclasses)
#define RCLASS_ORIGIN(c) (RCLASS_EXT_READABLE(c)->origin_)
#define RICLASS_IS_ORIGIN_P(c) (RCLASS_EXT_READABLE(c)->iclass_is_origin)
#define RCLASS_PERMANENT_CLASSPATH_P(c) (RCLASS_EXT_READABLE(c)->permanent_classpath)
-#define RCLASS_CLONED_P(c) (RCLASS_EXT_READABLE(c)->cloned)
#define RCLASS_CLASSPATH(c) (RCLASS_EXT_READABLE(c)->classpath)
// Superclasses can't be changed after initialization
@@ -240,12 +180,12 @@ static inline void RCLASSEXT_SET_INCLUDER(rb_classext_t *ext, VALUE klass, VALUE
#define RCLASS_SUPERCLASSES(c) (RCLASS_EXT_PRIME(c)->superclasses)
#define RCLASS_SUPERCLASSES_WITH_SELF_P(c) (RCLASS_EXT_PRIME(c)->superclasses_with_self)
-// namespaces don't make changes on these refined_class/attached_object/includer
+// Ruby Box doesn't make changes on these refined_class/attached_object/includer
#define RCLASS_REFINED_CLASS(c) (RCLASS_EXT_PRIME(c)->refined_class)
#define RCLASS_ATTACHED_OBJECT(c) (RCLASS_EXT_PRIME(c)->as.singleton_class.attached_object)
#define RCLASS_INCLUDER(c) (RCLASS_EXT_PRIME(c)->as.iclass.includer)
-// max IV count and variation count are just hints, so they don't need to be per-namespace
+// max IV count and variation count are just hints, so they don't need to be per-box
#define RCLASS_MAX_IV_COUNT(ext) (RCLASS_EXT_PRIME(ext)->max_iv_count)
#define RCLASS_VARIATION_COUNT(ext) (RCLASS_EXT_PRIME(ext)->variation_count)
@@ -255,7 +195,8 @@ static inline void RCLASSEXT_SET_INCLUDER(rb_classext_t *ext, VALUE klass, VALUE
#define RCLASS_WRITABLE_CALLABLE_M_TBL(c) (RCLASS_EXT_WRITABLE(c)->callable_m_tbl)
#define RCLASS_WRITABLE_CC_TBL(c) (RCLASS_EXT_WRITABLE(c)->cc_tbl)
#define RCLASS_WRITABLE_CVC_TBL(c) (RCLASS_EXT_WRITABLE(c)->cvc_tbl)
-#define RCLASS_WRITABLE_SUBCLASSES(c) (RCLASS_EXT_WRITABLE(c)->subclasses)
+// Subclasses are only in the prime classext (box-invariant)
+#define RCLASS_WRITABLE_SUBCLASSES(c) (RCLASS_EXT_PRIME(c)->subclasses)
static inline void RCLASS_SET_SUPER(VALUE klass, VALUE super);
static inline void RCLASS_WRITE_SUPER(VALUE klass, VALUE super);
@@ -263,13 +204,11 @@ static inline void RCLASS_SET_CONST_TBL(VALUE klass, struct rb_id_table *table,
static inline void RCLASS_WRITE_CONST_TBL(VALUE klass, struct rb_id_table *table, bool shared);
static inline void RCLASS_WRITE_CALLABLE_M_TBL(VALUE klass, struct rb_id_table *table);
static inline void RCLASS_WRITE_CC_TBL(VALUE klass, VALUE table);
-static inline void RCLASS_SET_CVC_TBL(VALUE klass, struct rb_id_table *table);
-static inline void RCLASS_WRITE_CVC_TBL(VALUE klass, struct rb_id_table *table);
+static inline void RCLASS_SET_CVC_TBL(VALUE klass, VALUE table);
+static inline void RCLASS_WRITE_CVC_TBL(VALUE klass, VALUE table);
static inline void RCLASS_WRITE_SUPERCLASSES(VALUE klass, size_t depth, VALUE *superclasses, bool with_self);
-static inline void RCLASS_SET_SUBCLASSES(VALUE klass, rb_subclass_anchor_t *anchor);
-static inline void RCLASS_WRITE_NS_SUPER_SUBCLASSES(VALUE klass, rb_ns_subclasses_t *ns_subclasses);
-static inline void RCLASS_WRITE_NS_MODULE_SUBCLASSES(VALUE klass, rb_ns_subclasses_t *ns_subclasses);
+static inline void RCLASS_SET_SUBCLASSES(VALUE klass, VALUE subclasses);
static inline void RCLASS_SET_ORIGIN(VALUE klass, VALUE origin);
static inline void RCLASS_WRITE_ORIGIN(VALUE klass, VALUE origin);
@@ -284,7 +223,6 @@ static inline VALUE RCLASS_SET_ATTACHED_OBJECT(VALUE klass, VALUE attached_objec
static inline void RCLASS_SET_INCLUDER(VALUE iclass, VALUE klass);
static inline void RCLASS_SET_MAX_IV_COUNT(VALUE klass, attr_index_t count);
-static inline void RCLASS_SET_CLONED(VALUE klass, bool cloned);
static inline void RCLASS_SET_CLASSPATH(VALUE klass, VALUE classpath, bool permanent);
static inline void RCLASS_WRITE_CLASSPATH(VALUE klass, VALUE classpath, bool permanent);
@@ -293,14 +231,16 @@ static inline void RCLASS_WRITE_CLASSPATH(VALUE klass, VALUE classpath, bool per
#define RCLASS_PRIME_CLASSEXT_WRITABLE FL_USER2
#define RCLASS_IS_INITIALIZED FL_USER3
// 3 is RMODULE_IS_REFINEMENT for RMODULE
-#define RCLASS_NAMESPACEABLE FL_USER4
+#define RCLASS_BOXABLE FL_USER4
+#define RCLASS_ALLOCATOR_DEFINED FL_USER5
+#define RCLASS_HAS_SUBCLASSES FL_USER6
static inline st_table *
RCLASS_CLASSEXT_TBL(VALUE klass)
{
- if (FL_TEST_RAW(klass, RCLASS_NAMESPACEABLE)) {
- struct RClass_namespaceable *ns_klass = (struct RClass_namespaceable *)klass;
- return ns_klass->ns_classext_tbl;
+ if (FL_TEST_RAW(klass, RCLASS_BOXABLE)) {
+ struct RClass_boxable *box_klass = (struct RClass_boxable *)klass;
+ return box_klass->box_classext_tbl;
}
return NULL;
}
@@ -308,23 +248,25 @@ RCLASS_CLASSEXT_TBL(VALUE klass)
static inline void
RCLASS_SET_CLASSEXT_TBL(VALUE klass, st_table *tbl)
{
- RUBY_ASSERT(FL_TEST_RAW(klass, RCLASS_NAMESPACEABLE));
- struct RClass_namespaceable *ns_klass = (struct RClass_namespaceable *)klass;
- ns_klass->ns_classext_tbl = tbl;
+ RUBY_ASSERT(FL_TEST_RAW(klass, RCLASS_BOXABLE));
+ struct RClass_boxable *box_klass = (struct RClass_boxable *)klass;
+ box_klass->box_classext_tbl = tbl;
}
/* class.c */
-rb_classext_t * rb_class_duplicate_classext(rb_classext_t *orig, VALUE obj, const rb_namespace_t *ns);
+rb_classext_t * rb_class_duplicate_classext(rb_classext_t *orig, VALUE obj, const rb_box_t *box);
void rb_class_ensure_writable(VALUE obj);
+void rb_class_set_box_classext(VALUE obj, const rb_box_t *box, rb_classext_t *ext);
+
static inline int
-RCLASS_SET_NAMESPACE_CLASSEXT(VALUE obj, const rb_namespace_t *ns, rb_classext_t *ext)
+RCLASS_SET_BOX_CLASSEXT(VALUE obj, const rb_box_t *box, rb_classext_t *ext)
{
int first_set = 0;
st_table *tbl = RCLASS_CLASSEXT_TBL(obj);
- VM_ASSERT(NAMESPACE_USER_P(ns)); // non-prime classext is only for user namespace, with ns_object
- VM_ASSERT(ns->ns_object);
- VM_ASSERT(RCLASSEXT_NS(ext) == ns);
+ VM_ASSERT(BOX_MUTABLE_P(box)); // Setting non-prime classext never happens on the master box
+ VM_ASSERT(box->box_object);
+ VM_ASSERT(RCLASSEXT_BOX(ext) == box);
if (!tbl) {
tbl = st_init_numtable_with_size(1);
RCLASS_SET_CLASSEXT_TBL(obj, tbl);
@@ -332,45 +274,53 @@ RCLASS_SET_NAMESPACE_CLASSEXT(VALUE obj, const rb_namespace_t *ns, rb_classext_t
if (rb_st_table_size(tbl) == 0) {
first_set = 1;
}
- rb_st_insert(tbl, (st_data_t)ns->ns_object, (st_data_t)ext);
+
+ rb_class_set_box_classext(obj, box, ext);
+
return first_set;
}
+#define VM_ASSERT_BOXABLE_TYPE(klass) \
+ VM_ASSERT(RB_TYPE_P(klass, T_CLASS) || RB_TYPE_P(klass, T_MODULE) || RB_TYPE_P(klass, T_ICLASS), "%s is not boxable type", rb_type_str(BUILTIN_TYPE(klass)))
+
static inline bool
RCLASS_PRIME_CLASSEXT_READABLE_P(VALUE klass)
{
- VM_ASSERT(RB_TYPE_P(klass, T_CLASS) || RB_TYPE_P(klass, T_MODULE) || RB_TYPE_P(klass, T_ICLASS));
+ VM_ASSERT(klass != 0, "klass should be a valid object");
+ VM_ASSERT_BOXABLE_TYPE(klass);
// if the lookup table exists, then it means the prime classext is NOT directly readable.
- return !FL_TEST_RAW(klass, RCLASS_NAMESPACEABLE) || RCLASS_CLASSEXT_TBL(klass) == NULL;
+ return !FL_TEST_RAW(klass, RCLASS_BOXABLE) || RCLASS_CLASSEXT_TBL(klass) == NULL;
}
static inline bool
RCLASS_PRIME_CLASSEXT_WRITABLE_P(VALUE klass)
{
- VM_ASSERT(RB_TYPE_P(klass, T_CLASS) || RB_TYPE_P(klass, T_MODULE) || RB_TYPE_P(klass, T_ICLASS));
- return FL_TEST(klass, RCLASS_PRIME_CLASSEXT_WRITABLE);
+ VM_ASSERT(klass != 0, "klass should be a valid object");
+ VM_ASSERT_BOXABLE_TYPE(klass);
+ RBIMPL_ASSUME(klass != 0);
+ return FL_TEST_RAW(klass, RCLASS_PRIME_CLASSEXT_WRITABLE);
}
static inline void
RCLASS_SET_PRIME_CLASSEXT_WRITABLE(VALUE klass, bool writable)
{
- VM_ASSERT(RB_TYPE_P(klass, T_CLASS) || RB_TYPE_P(klass, T_MODULE) || RB_TYPE_P(klass, T_ICLASS));
-
+ VM_ASSERT(klass != 0, "klass should be a valid object");
+ VM_ASSERT_BOXABLE_TYPE(klass);
if (writable) {
- FL_SET(klass, RCLASS_PRIME_CLASSEXT_WRITABLE);
+ FL_SET_RAW(klass, RCLASS_PRIME_CLASSEXT_WRITABLE);
}
else {
- FL_UNSET(klass, RCLASS_PRIME_CLASSEXT_WRITABLE);
+ FL_UNSET_RAW(klass, RCLASS_PRIME_CLASSEXT_WRITABLE);
}
}
static inline rb_classext_t *
-RCLASS_EXT_TABLE_LOOKUP_INTERNAL(VALUE obj, const rb_namespace_t *ns)
+RCLASS_EXT_TABLE_LOOKUP_INTERNAL(VALUE obj, const rb_box_t *box)
{
st_data_t classext_ptr;
st_table *classext_tbl = RCLASS_CLASSEXT_TBL(obj);
if (classext_tbl) {
- if (rb_st_lookup(classext_tbl, (st_data_t)ns->ns_object, &classext_ptr)) {
+ if (rb_st_lookup(classext_tbl, (st_data_t)box->box_object, &classext_ptr)) {
return (rb_classext_t *)classext_ptr;
}
}
@@ -378,9 +328,9 @@ RCLASS_EXT_TABLE_LOOKUP_INTERNAL(VALUE obj, const rb_namespace_t *ns)
}
static inline rb_classext_t *
-RCLASS_EXT_READABLE_LOOKUP(VALUE obj, const rb_namespace_t *ns)
+RCLASS_EXT_READABLE_LOOKUP(VALUE obj, const rb_box_t *box)
{
- rb_classext_t *ext = RCLASS_EXT_TABLE_LOOKUP_INTERNAL(obj, ns);
+ rb_classext_t *ext = RCLASS_EXT_TABLE_LOOKUP_INTERNAL(obj, box);
if (ext)
return ext;
// Classext for the ns not found. Refer the prime one instead.
@@ -388,48 +338,48 @@ RCLASS_EXT_READABLE_LOOKUP(VALUE obj, const rb_namespace_t *ns)
}
static inline rb_classext_t *
-RCLASS_EXT_READABLE_IN_NS(VALUE obj, const rb_namespace_t *ns)
+RCLASS_EXT_READABLE_IN_BOX(VALUE obj, const rb_box_t *box)
{
- if (!ns
- || NAMESPACE_BUILTIN_P(ns)
+ if (BOX_MASTER_P(box)
|| RCLASS_PRIME_CLASSEXT_READABLE_P(obj)) {
return RCLASS_EXT_PRIME(obj);
}
- return RCLASS_EXT_READABLE_LOOKUP(obj, ns);
+ return RCLASS_EXT_READABLE_LOOKUP(obj, box);
}
static inline rb_classext_t *
RCLASS_EXT_READABLE(VALUE obj)
{
- const rb_namespace_t *ns;
+ const rb_box_t *box;
if (RCLASS_PRIME_CLASSEXT_READABLE_P(obj)) {
return RCLASS_EXT_PRIME(obj);
}
- // delay namespace loading to optimize for unmodified classes
- ns = rb_current_namespace();
- if (!ns || NAMESPACE_BUILTIN_P(ns)) {
+ // delay determining the current box to optimize for unmodified classes
+ box = rb_current_box();
+ if (BOX_MASTER_P(box)) {
return RCLASS_EXT_PRIME(obj);
}
- return RCLASS_EXT_READABLE_LOOKUP(obj, ns);
+ return RCLASS_EXT_READABLE_LOOKUP(obj, box);
}
static inline rb_classext_t *
-RCLASS_EXT_WRITABLE_LOOKUP(VALUE obj, const rb_namespace_t *ns)
+RCLASS_EXT_WRITABLE_LOOKUP(VALUE obj, const rb_box_t *box)
{
rb_classext_t *ext;
int first_set = 0;
- ext = RCLASS_EXT_TABLE_LOOKUP_INTERNAL(obj, ns);
+ ext = RCLASS_EXT_TABLE_LOOKUP_INTERNAL(obj, box);
if (ext)
return ext;
RB_VM_LOCKING() {
// re-check the classext is not created to avoid the multi-thread race
- ext = RCLASS_EXT_TABLE_LOOKUP_INTERNAL(obj, ns);
+ ext = RCLASS_EXT_TABLE_LOOKUP_INTERNAL(obj, box);
if (!ext) {
- ext = rb_class_duplicate_classext(RCLASS_EXT_PRIME(obj), obj, ns);
- first_set = RCLASS_SET_NAMESPACE_CLASSEXT(obj, ns, ext);
+ ext = rb_class_duplicate_classext(RCLASS_EXT_PRIME(obj), obj, box);
+ first_set = RCLASS_SET_BOX_CLASSEXT(obj, box, ext);
if (first_set) {
+ // TODO: are there any case that a class/module become non-writable after its birthtime?
RCLASS_SET_PRIME_CLASSEXT_WRITABLE(obj, false);
}
}
@@ -438,31 +388,28 @@ RCLASS_EXT_WRITABLE_LOOKUP(VALUE obj, const rb_namespace_t *ns)
}
static inline rb_classext_t *
-RCLASS_EXT_WRITABLE_IN_NS(VALUE obj, const rb_namespace_t *ns)
+RCLASS_EXT_WRITABLE_IN_BOX(VALUE obj, const rb_box_t *box)
{
- if (!ns
- || NAMESPACE_BUILTIN_P(ns)
+ if (BOX_MASTER_P(box)
|| RCLASS_PRIME_CLASSEXT_WRITABLE_P(obj)) {
return RCLASS_EXT_PRIME(obj);
}
- return RCLASS_EXT_WRITABLE_LOOKUP(obj, ns);
+ return RCLASS_EXT_WRITABLE_LOOKUP(obj, box);
}
static inline rb_classext_t *
RCLASS_EXT_WRITABLE(VALUE obj)
{
- const rb_namespace_t *ns;
+ const rb_box_t *box;
if (LIKELY(RCLASS_PRIME_CLASSEXT_WRITABLE_P(obj))) {
return RCLASS_EXT_PRIME(obj);
}
- // delay namespace loading to optimize for unmodified classes
- ns = rb_current_namespace();
- if (!ns || NAMESPACE_BUILTIN_P(ns)) {
- // If no namespace is specified, Ruby VM is in bootstrap
- // and the clean class definition is under construction.
+ // delay determining the current box to optimize for unmodified classes
+ box = rb_current_box();
+ if (BOX_MASTER_P(box)) {
return RCLASS_EXT_PRIME(obj);
}
- return RCLASS_EXT_WRITABLE_LOOKUP(obj, ns);
+ return RCLASS_EXT_WRITABLE_LOOKUP(obj, box);
}
static inline void
@@ -479,18 +426,11 @@ RCLASSEXT_SET_INCLUDER(rb_classext_t *ext, VALUE klass, VALUE includer)
}
/* class.c */
-typedef void rb_class_classext_foreach_callback_func(rb_classext_t *classext, bool is_prime, VALUE namespace, void *arg);
+typedef void rb_class_classext_foreach_callback_func(rb_classext_t *classext, bool is_prime, VALUE box_value, void *arg);
void rb_class_classext_foreach(VALUE klass, rb_class_classext_foreach_callback_func *func, void *arg);
void rb_class_subclass_add(VALUE super, VALUE klass);
-void rb_class_remove_from_super_subclasses(VALUE);
-void rb_class_remove_from_module_subclasses(VALUE);
-void rb_class_classext_free_subclasses(rb_classext_t *, VALUE);
void rb_class_foreach_subclass(VALUE klass, void (*f)(VALUE, VALUE), VALUE);
-void rb_class_detach_subclasses(VALUE);
-void rb_class_detach_module_subclasses(VALUE);
void rb_class_update_superclasses(VALUE);
-size_t rb_class_superclasses_memsize(VALUE);
-void rb_class_remove_subclass_head(VALUE);
int rb_singleton_class_internal_p(VALUE sklass);
VALUE rb_class_set_super(VALUE klass, VALUE super);
VALUE rb_class_boot(VALUE);
@@ -513,6 +453,10 @@ void rb_undef_methods_from(VALUE klass, VALUE super);
VALUE rb_class_inherited(VALUE, VALUE);
VALUE rb_keyword_error_new(const char *, VALUE);
+rb_classext_t *rb_class_unlink_classext(VALUE klass, const rb_box_t *box);
+void rb_class_classext_free(VALUE klass, rb_classext_t *ext, bool is_prime);
+void rb_iclass_classext_free(VALUE klass, rb_classext_t *ext, bool is_prime);
+
RUBY_SYMBOL_EXPORT_BEGIN
/* for objspace */
@@ -525,7 +469,8 @@ RUBY_SYMBOL_EXPORT_END
static inline bool
RCLASS_SINGLETON_P(VALUE klass)
{
- return RB_TYPE_P(klass, T_CLASS) && FL_TEST_RAW(klass, FL_SINGLETON);
+ RUBY_ASSERT(RB_TYPE_P(klass, T_CLASS) || RB_TYPE_P(klass, T_MODULE) || RB_TYPE_P(klass, T_ICLASS));
+ return RB_BUILTIN_TYPE(klass) == T_CLASS && FL_TEST_RAW(klass, FL_SINGLETON);
}
static inline void
@@ -546,7 +491,7 @@ RCLASS_WRITABLE_ENSURE_FIELDS_OBJ(VALUE obj)
RUBY_ASSERT(RB_TYPE_P(obj, RUBY_T_CLASS) || RB_TYPE_P(obj, RUBY_T_MODULE));
rb_classext_t *ext = RCLASS_EXT_WRITABLE(obj);
if (!ext->fields_obj) {
- RB_OBJ_WRITE(obj, &ext->fields_obj, rb_imemo_fields_new(obj, 1));
+ RB_OBJ_WRITE(obj, &ext->fields_obj, rb_imemo_fields_new(obj, ROOT_SHAPE_ID, true));
}
return ext->fields_obj;
}
@@ -581,7 +526,7 @@ RCLASS_FIELDS_COUNT(VALUE obj)
VALUE fields_obj = RCLASS_WRITABLE_FIELDS_OBJ(obj);
if (fields_obj) {
- if (rb_shape_obj_too_complex_p(fields_obj)) {
+ if (rb_obj_shape_complex_p(fields_obj)) {
return (uint32_t)rb_st_table_size(rb_imemo_fields_complex_tbl(fields_obj));
}
else {
@@ -634,15 +579,15 @@ RCLASS_WRITE_CC_TBL(VALUE klass, VALUE table)
}
static inline void
-RCLASS_SET_CVC_TBL(VALUE klass, struct rb_id_table *table)
+RCLASS_SET_CVC_TBL(VALUE klass, VALUE table)
{
- RCLASSEXT_CVC_TBL(RCLASS_EXT_PRIME(klass)) = table;
+ RB_OBJ_ATOMIC_WRITE(klass, &RCLASSEXT_CVC_TBL(RCLASS_EXT_PRIME(klass)), table);
}
static inline void
-RCLASS_WRITE_CVC_TBL(VALUE klass, struct rb_id_table *table)
+RCLASS_WRITE_CVC_TBL(VALUE klass, VALUE table)
{
- RCLASSEXT_CVC_TBL(RCLASS_EXT_WRITABLE(klass)) = table;
+ RB_OBJ_ATOMIC_WRITE(klass, &RCLASSEXT_CVC_TBL(RCLASS_EXT_WRITABLE(klass)), table);
}
static inline void
@@ -654,10 +599,8 @@ RCLASS_SET_REFINED_CLASS(VALUE klass, VALUE refined)
static inline rb_alloc_func_t
RCLASS_ALLOCATOR(VALUE klass)
{
- RUBY_ASSERT(RB_TYPE_P(klass, T_CLASS) || RB_TYPE_P(klass, T_ICLASS));
- if (RCLASS_SINGLETON_P(klass) || RB_TYPE_P(klass, T_ICLASS)) {
- return 0;
- }
+ RBIMPL_ASSERT_TYPE(klass, T_CLASS);
+ RUBY_ASSERT(!RCLASS_SINGLETON_P(klass));
return RCLASS_EXT_PRIME(klass)->as.class.allocator;
}
@@ -704,6 +647,14 @@ RICLASS_OWNS_M_TBL_P(VALUE iclass)
return RCLASSEXT_ICLASS_IS_ORIGIN(ext) && !RCLASSEXT_ICLASS_ORIGIN_SHARED_MTBL(ext);
}
+static inline bool
+RICLASS_FOR_REFINEMENT_P(VALUE iclass)
+{
+ return BUILTIN_TYPE(iclass) == T_ICLASS &&
+ RB_TYPE_P(RBASIC(iclass)->klass, T_MODULE) &&
+ FL_TEST_RAW(RBASIC(iclass)->klass, RMODULE_IS_REFINEMENT);
+}
+
static inline void
RCLASS_SET_INCLUDER(VALUE iclass, VALUE klass)
{
@@ -723,28 +674,10 @@ RCLASS_WRITE_SUPERCLASSES(VALUE klass, size_t depth, VALUE *superclasses, bool w
}
static inline void
-RCLASS_SET_SUBCLASSES(VALUE klass, struct rb_subclass_anchor *anchor)
+RCLASS_SET_SUBCLASSES(VALUE klass, VALUE subclasses)
{
rb_classext_t *ext = RCLASS_EXT_PRIME(klass);
- RCLASSEXT_SUBCLASSES(ext) = anchor;
-}
-
-static inline void
-RCLASS_WRITE_NS_SUPER_SUBCLASSES(VALUE klass, rb_ns_subclasses_t *ns_subclasses)
-{
- rb_classext_t *ext = RCLASS_EXT_WRITABLE(klass);
- if (RCLASSEXT_NS_SUPER_SUBCLASSES(ext))
- rb_ns_subclasses_ref_dec(RCLASSEXT_NS_SUPER_SUBCLASSES(ext));
- RCLASSEXT_NS_SUPER_SUBCLASSES(ext) = rb_ns_subclasses_ref_inc(ns_subclasses);
-}
-
-static inline void
-RCLASS_WRITE_NS_MODULE_SUBCLASSES(VALUE klass, rb_ns_subclasses_t *ns_subclasses)
-{
- rb_classext_t *ext = RCLASS_EXT_WRITABLE(klass);
- if (RCLASSEXT_NS_MODULE_SUBCLASSES(ext))
- rb_ns_subclasses_ref_dec(RCLASSEXT_NS_MODULE_SUBCLASSES(ext));
- RCLASSEXT_NS_MODULE_SUBCLASSES(ext) = rb_ns_subclasses_ref_inc(ns_subclasses);
+ RB_OBJ_WRITE(klass, &RCLASSEXT_SUBCLASSES(ext), subclasses);
}
static inline void
@@ -753,6 +686,7 @@ RCLASS_SET_CLASSPATH(VALUE klass, VALUE classpath, bool permanent)
rb_classext_t *ext = RCLASS_EXT_READABLE(klass);
assert(BUILTIN_TYPE(klass) == T_CLASS || BUILTIN_TYPE(klass) == T_MODULE);
assert(classpath == 0 || BUILTIN_TYPE(classpath) == T_STRING);
+ assert(FL_TEST_RAW(classpath, RUBY_FL_SHAREABLE));
RB_OBJ_WRITE(klass, &(RCLASSEXT_CLASSPATH(ext)), classpath);
RCLASSEXT_PERMANENT_CLASSPATH(ext) = permanent;
@@ -764,6 +698,7 @@ RCLASS_WRITE_CLASSPATH(VALUE klass, VALUE classpath, bool permanent)
rb_classext_t *ext = RCLASS_EXT_WRITABLE(klass);
assert(BUILTIN_TYPE(klass) == T_CLASS || BUILTIN_TYPE(klass) == T_MODULE);
assert(classpath == 0 || BUILTIN_TYPE(classpath) == T_STRING);
+ assert(!RB_FL_ABLE(classpath) || FL_TEST_RAW(classpath, RUBY_FL_SHAREABLE));
RB_OBJ_WRITE(klass, &(RCLASSEXT_CLASSPATH(ext)), classpath);
RCLASSEXT_PERMANENT_CLASSPATH(ext) = permanent;
@@ -781,13 +716,22 @@ RCLASS_SET_ATTACHED_OBJECT(VALUE klass, VALUE attached_object)
static inline void
RCLASS_SET_MAX_IV_COUNT(VALUE klass, attr_index_t count)
{
+ RUBY_ASSERT(klass != rb_cObject);
+ RUBY_ASSERT(klass != rb_cBasicObject);
+
RCLASS_MAX_IV_COUNT(klass) = count;
}
static inline void
-RCLASS_SET_CLONED(VALUE klass, bool cloned)
+RCLASS_SET_EXPECT_NO_IVAR(VALUE klass)
+{
+ RCLASS_EXT_PRIME(klass)->expect_no_ivar = true;
+}
+
+static inline bool
+RCLASS_EXPECT_NO_IVAR(VALUE klass)
{
- RCLASSEXT_CLONED(RCLASS_EXT_PRIME(klass)) = cloned;
+ return RCLASS_EXT_PRIME(klass)->expect_no_ivar;
}
static inline bool
diff --git a/internal/compar.h b/internal/compar.h
index 9115e4bd63..5eb5e8714e 100644
--- a/internal/compar.h
+++ b/internal/compar.h
@@ -25,5 +25,6 @@
/* compar.c */
VALUE rb_invcmp(VALUE, VALUE);
+NORETURN(void rb_cmperr_reason(VALUE, VALUE, const char*));
#endif /* INTERNAL_COMPAR_H */
diff --git a/internal/cont.h b/internal/cont.h
index 3c2528a02a..dcf6f820a3 100644
--- a/internal/cont.h
+++ b/internal/cont.h
@@ -31,5 +31,4 @@ VALUE rb_fiber_inherit_storage(struct rb_execution_context_struct *ec, struct rb
VALUE rb_fiberptr_self(struct rb_fiber_struct *fiber);
unsigned int rb_fiberptr_blocking(struct rb_fiber_struct *fiber);
struct rb_execution_context_struct * rb_fiberptr_get_ec(struct rb_fiber_struct *fiber);
-
#endif /* INTERNAL_CONT_H */
diff --git a/internal/error.h b/internal/error.h
index de189698b8..fead2aee95 100644
--- a/internal/error.h
+++ b/internal/error.h
@@ -75,11 +75,11 @@ PRINTF_ARGS(void rb_warn_deprecated_to_remove(const char *removal, const char *f
PRINTF_ARGS(void rb_warn_reserved_name(const char *removal, const char *fmt, ...), 2, 3);
#if RUBY_DEBUG
# include "ruby/version.h"
-# define RUBY_VERSION_SINCE(major, minor) (RUBY_API_VERSION_CODE >= (major * 10000) + (minor) * 100)
-# define RUBY_VERSION_BEFORE(major, minor) (RUBY_API_VERSION_CODE < (major * 10000) + (minor) * 100)
+# define RUBY_VERSION_SINCE(major, minor) (RUBY_API_VERSION_CODE >= (major) * 10000 + (minor) * 100)
+# define RUBY_VERSION_BEFORE(major, minor) (RUBY_API_VERSION_CODE < (major) * 10000 + (minor) * 100)
# if defined(RBIMPL_WARNING_PRAGMA0)
# define RBIMPL_TODO0(x) RBIMPL_WARNING_PRAGMA0(message(x))
-# elif RBIMPL_COMPILER_SINCE(MSVC, 12, 0, 0)
+# elif RBIMPL_COMPILER_IS(MSVC)
# define RBIMPL_TODO0(x) __pragma(message(x))
# endif
@@ -186,6 +186,9 @@ static inline void Check_Type(VALUE v, enum ruby_value_type t);
static inline bool rb_typeddata_is_instance_of_inline(VALUE obj, const rb_data_type_t *data_type);
#define rb_typeddata_is_instance_of rb_typeddata_is_instance_of_inline
void rb_bug_without_die(const char *fmt, ...);
+NORETURN(void rb_no_implicit_conversion(VALUE val, const char *tname));
+NORETURN(void rb_cant_convert(VALUE val, const char *tname));
+NORETURN(void rb_cant_convert_invalid_return(VALUE val, const char *tname, const char *method_name, VALUE ret));
RUBY_SYMBOL_EXPORT_BEGIN
/* error.c (export) */
@@ -235,10 +238,11 @@ rb_key_err_raise(VALUE mesg, VALUE recv, VALUE name)
rb_exc_raise(exc);
}
+RBIMPL_ATTR_NONNULL((2))
static inline bool
rb_typeddata_is_instance_of_inline(VALUE obj, const rb_data_type_t *data_type)
{
- return RB_TYPE_P(obj, T_DATA) && RTYPEDDATA_P(obj) && (RTYPEDDATA_TYPE(obj) == data_type);
+ return rbimpl_obj_typeddata_p(obj) && (RTYPEDDATA_TYPE(obj) == data_type);
}
typedef enum {
diff --git a/internal/eval.h b/internal/eval.h
index 4c1c045b4e..17ade0a7f1 100644
--- a/internal/eval.h
+++ b/internal/eval.h
@@ -11,6 +11,7 @@
* header (related to this file, but not the same role).
*/
#include "ruby/ruby.h" /* for ID */
+#include "vm_core.h" /* for ID */
#define id_signo ruby_static_id_signo
#define id_status ruby_static_id_status
@@ -30,6 +31,7 @@ VALUE rb_exception_setup(int argc, VALUE *argv);
void rb_refinement_setup(struct rb_refinements_data *data, VALUE module, VALUE klass);
void rb_vm_using_module(VALUE module);
VALUE rb_top_main_class(const char *method);
+VALUE rb_ec_ensure(rb_execution_context_t *ec, VALUE (*b_proc)(VALUE), VALUE data1, VALUE (*e_proc)(VALUE), VALUE data2);
/* eval_error.c */
VALUE rb_get_backtrace(VALUE info);
diff --git a/internal/file.h b/internal/file.h
index 9c192ff4d1..1aa4c67043 100644
--- a/internal/file.h
+++ b/internal/file.h
@@ -23,7 +23,9 @@ VALUE rb_file_expand_path_fast(VALUE, VALUE);
VALUE rb_file_expand_path_internal(VALUE, VALUE, int, int, VALUE);
VALUE rb_get_path_check_to_string(VALUE);
VALUE rb_get_path_check_convert(VALUE);
+VALUE rb_get_path_check_no_convert(VALUE);
int ruby_is_fd_loadable(int fd);
+char *rb_enc_path_skip_prefix_root(const char *path, const char *end, rb_encoding *enc);
RUBY_SYMBOL_EXPORT_BEGIN
/* file.c (export) */
diff --git a/internal/gc.h b/internal/gc.h
index f0dc04fc58..e21fb89267 100644
--- a/internal/gc.h
+++ b/internal/gc.h
@@ -83,8 +83,6 @@ rb_gc_debug_body(const char *mode, const char *msg, int st, void *ptr)
#define RUBY_GC_INFO if(0)printf
#endif
-#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
@@ -122,10 +120,11 @@ const char *rb_raw_obj_info(char *const buff, const size_t buff_size, VALUE obj)
struct rb_execution_context_struct; /* in vm_core.h */
struct rb_objspace; /* in vm_core.h */
-#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 EC_NEWOBJ_OF(var, T, c, f, s, ec) \
+ T *(var) = (T *)rb_ec_newobj_of((ec), (c), (f), s)
+#define NEWOBJ_OF(var, T, c, f, s) EC_NEWOBJ_OF(var, T, c, f, s, GET_EC())
+#define UNPROTECTED_NEWOBJ_OF(var, T, c, f, s) \
+ T *(var) = (T *)rb_newobj((GET_EC()), (c), (f), ROOT_SHAPE_ID | SHAPE_ID_LAYOUT_OTHER, false, s)
#ifndef RB_GC_OBJECT_METADATA_ENTRY_DEFINED
# define RB_GC_OBJECT_METADATA_ENTRY_DEFINED
@@ -198,10 +197,9 @@ 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);
RUBY_ATTR_MALLOC void *rb_xmalloc_mul_add_mul(size_t, size_t, size_t, size_t);
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_obj_id_moved(VALUE obj);
+void rb_gc_register_pinning_obj(VALUE obj);
+rb_execution_context_t *rb_gc_get_ec(void);
void *rb_gc_ractor_cache_alloc(rb_ractor_t *ractor);
void rb_gc_ractor_cache_free(void *cache);
@@ -212,9 +210,6 @@ 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);
@@ -235,6 +230,8 @@ void rb_objspace_reachable_objects_from_root(void (func)(const char *category, V
int rb_objspace_internal_object_p(VALUE obj);
int rb_objspace_garbage_object_p(VALUE obj);
bool rb_gc_pointer_to_heap_p(VALUE obj);
+void rb_gc_declare_weak_references(VALUE obj);
+bool rb_gc_handle_weak_references_alive_p(VALUE obj);
void rb_objspace_each_objects(
int (*callback)(void *start, void *end, size_t stride, void *data),
@@ -248,19 +245,21 @@ VALUE rb_gc_disable_no_rest(void);
/* 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_unprotected_newobj_of(VALUE, VALUE, size_t);
+VALUE rb_newobj(struct rb_execution_context_struct *, VALUE, VALUE, uint32_t /* shape_id_t */, bool, size_t);
+VALUE rb_newobj_of(VALUE, VALUE, size_t);
+VALUE rb_ec_newobj_of(struct rb_execution_context_struct *, VALUE, VALUE, size_t);
size_t rb_obj_memsize_of(VALUE);
struct rb_gc_object_metadata_entry *rb_gc_object_metadata(VALUE obj);
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);
+void rb_gc_mark_set_no_pin(st_table *);
+void rb_gc_update_set_refs(st_table *);
+#if USE_MODULAR_GC
const char *rb_gc_active_gc_name(void);
int rb_gc_modular_gc_loaded_p(void);
+#endif
RUBY_SYMBOL_EXPORT_END
@@ -289,66 +288,19 @@ void rb_gc_writebarrier_remember(VALUE obj);
const char *rb_obj_info(VALUE obj);
void ruby_annotate_mmap(const void *addr, unsigned long size, const char *name);
-#if defined(HAVE_MALLOC_USABLE_SIZE) || defined(HAVE_MALLOC_SIZE) || defined(_WIN32)
-
-static inline void *
-ruby_sized_xrealloc_inlined(void *ptr, size_t new_size, size_t old_size)
-{
- return ruby_xrealloc(ptr, new_size);
-}
-
-static inline void *
-ruby_sized_xrealloc2_inlined(void *ptr, size_t new_count, size_t elemsiz, size_t old_count)
-{
- return ruby_xrealloc2(ptr, new_count, elemsiz);
-}
-
-static inline void
-ruby_sized_xfree_inlined(void *ptr, size_t size)
-{
- ruby_xfree(ptr);
-}
-
-# 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 *
-ruby_sized_xrealloc_inlined(void *ptr, size_t new_size, size_t old_size)
-{
- return ruby_sized_xrealloc(ptr, new_size, old_size);
-}
-
-static inline void *
-ruby_sized_xrealloc2_inlined(void *ptr, size_t new_count, size_t elemsiz, size_t old_count)
-{
- return ruby_sized_xrealloc2(ptr, new_count, elemsiz, old_count);
-}
-
-static inline void
-ruby_sized_xfree_inlined(void *ptr, size_t size)
-{
- ruby_sized_xfree(ptr, size);
-}
-
# define SIZED_REALLOC_N(v, T, m, n) \
- ((v) = (T *)ruby_sized_xrealloc2((void *)(v), (m), sizeof(T), (n)))
+ ((v) = (T *)ruby_xrealloc2_sized((void *)(v), (m), sizeof(T), (n)))
+
+# define SIZED_FREE(v) ruby_xfree_sized((void *)(v), sizeof(*(v)))
+# define SIZED_FREE_N(v, n) ruby_xfree_sized((void *)(v), sizeof(*(v)) * (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);
+ return ruby_xrealloc2_sized(ptr, new_count, element_size, old_count);
}
-#endif /* HAVE_MALLOC_USABLE_SIZE */
+void rb_gc_verify_shareable(VALUE);
+bool rb_gc_checking_shareable(void);
-#define ruby_sized_xrealloc ruby_sized_xrealloc_inlined
-#define ruby_sized_xrealloc2 ruby_sized_xrealloc2_inlined
-#define ruby_sized_xfree ruby_sized_xfree_inlined
#endif /* INTERNAL_GC_H */
diff --git a/internal/hash.h b/internal/hash.h
index 03cd830506..0386a5009c 100644
--- a/internal/hash.h
+++ b/internal/hash.h
@@ -70,7 +70,6 @@ struct RHash {
#endif
/* hash.c */
-void rb_hash_st_table_set(VALUE hash, st_table *st);
VALUE rb_hash_default_value(VALUE hash, VALUE key);
VALUE rb_hash_set_default(VALUE hash, VALUE ifnone);
VALUE rb_hash_set_default_proc(VALUE hash, VALUE proc);
@@ -88,6 +87,7 @@ 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);
bool rb_hash_default_unredefined(VALUE hash);
+VALUE rb_hash_alloc_fixed_size(VALUE klass, st_index_t size);
VALUE rb_ident_hash_new_with_size(st_index_t size);
void rb_hash_free(VALUE hash);
RUBY_EXTERN VALUE rb_cHash_empty_frozen;
@@ -111,6 +111,7 @@ int rb_hash_stlike_foreach(VALUE hash, st_foreach_callback_func *func, st_data_t
RUBY_SYMBOL_EXPORT_END
VALUE rb_hash_new_with_size(st_index_t size);
+VALUE rb_hash_new_with_bulk_insert(long argc, const VALUE *argv);
VALUE rb_hash_resurrect(VALUE hash);
int rb_hash_stlike_lookup(VALUE hash, st_data_t key, st_data_t *pval);
VALUE rb_hash_keys(VALUE hash);
@@ -191,4 +192,19 @@ RHASH_AR_TABLE_SIZE_RAW(VALUE h)
return (unsigned)ret;
}
+#define RHASH_AR_TABLE_BOUND_RAW(h) \
+ ((unsigned int)((RBASIC(h)->flags >> RHASH_AR_TABLE_BOUND_SHIFT) & \
+ (RHASH_AR_TABLE_BOUND_MASK >> RHASH_AR_TABLE_BOUND_SHIFT)))
+
+#define RHASH_TYPE(hash) (RHASH_AR_TABLE_P(hash) ? &objhash : RHASH_ST_TABLE(hash)->type)
+
+static inline unsigned int
+RHASH_AR_TABLE_BOUND(VALUE h)
+{
+ RUBY_ASSERT(RHASH_AR_TABLE_P(h));
+ const unsigned int bound = RHASH_AR_TABLE_BOUND_RAW(h);
+ RUBY_ASSERT(bound <= RHASH_AR_TABLE_MAX_SIZE);
+ return bound;
+}
+
#endif /* INTERNAL_HASH_H */
diff --git a/internal/imemo.h b/internal/imemo.h
index 8d1e42353d..e8a5f0fc8e 100644
--- a/internal/imemo.h
+++ b/internal/imemo.h
@@ -37,10 +37,13 @@ enum imemo_type {
imemo_ment = 6,
imemo_iseq = 7,
imemo_tmpbuf = 8,
+ imemo_cvar_entry = 9,
imemo_callinfo = 10,
imemo_callcache = 11,
imemo_constcache = 12,
- imemo_fields = 13,
+ imemo_fields = 13,
+ imemo_subclasses = 14,
+ imemo_cdhash = 15,
};
/* CREF (Class REFerence) is defined in method.h */
@@ -57,7 +60,6 @@ struct vm_svar {
/*! THROW_DATA */
struct vm_throw_data {
VALUE flags;
- VALUE reserved;
const VALUE throw_obj;
const struct rb_control_frame_struct *catch_frame;
int throw_state;
@@ -93,30 +95,36 @@ struct vm_ifunc {
struct rb_imemo_tmpbuf_struct {
VALUE flags;
- VALUE reserved;
VALUE *ptr; /* malloc'ed buffer */
- struct rb_imemo_tmpbuf_struct *next; /* next imemo */
- size_t cnt; /* buffer size in VALUE */
+ size_t size; /* buffer size in bytes */
};
+struct rb_imemo_cdhash {
+ VALUE flags;
+ st_table tbl;
+};
+
+/* Set on imemo_memo when u3 holds a VALUE that GC must mark.
+ * When unset, u3 is a non-VALUE (cnt/state). */
+#define MEMO_U3_IS_VALUE IMEMO_FL_USER0
+
/*! MEMO
*
* @see imemo_type
* */
struct MEMO {
VALUE flags;
- VALUE reserved;
const VALUE v1;
const VALUE v2;
union {
long cnt;
long state;
const VALUE value;
- void (*func)(void);
} u3;
};
-#define IMEMO_NEW(T, type, v0) ((T *)rb_imemo_new((type), (v0), sizeof(T)))
+#define IMEMO_NEW(T, type, v0) ((T *)rb_imemo_new((type), (v0), sizeof(T), false))
+#define SHAREABLE_IMEMO_NEW(T, type, v0) ((T *)rb_imemo_new((type), (v0), sizeof(T), true))
/* ment is in method.h */
@@ -133,16 +141,16 @@ struct MEMO {
#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);
+VALUE rb_imemo_new(enum imemo_type type, VALUE v0, size_t size, bool is_shareable);
+VALUE rb_imemo_tmpbuf_new(void);
+struct MEMO *rb_imemo_memo_new(VALUE a, VALUE b, long c);
+struct MEMO *rb_imemo_memo_new_value(VALUE a, VALUE b, VALUE c);
struct vm_ifunc *rb_vm_ifunc_new(rb_block_call_func_t func, const void *data, int min_argc, int max_argc);
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);
static inline struct vm_ifunc *rb_vm_ifunc_proc_new(rb_block_call_func_t func, const void *data);
-static inline VALUE rb_imemo_tmpbuf_auto_free_pointer(void);
static inline void *RB_IMEMO_TMPBUF_PTR(VALUE v);
-static inline void *rb_imemo_tmpbuf_set_ptr(VALUE v, void *ptr);
-static inline VALUE rb_imemo_tmpbuf_auto_free_pointer_new_from_an_RString(VALUE str);
static inline void MEMO_V1_SET(struct MEMO *m, VALUE v);
static inline void MEMO_V2_SET(struct MEMO *m, VALUE v);
@@ -151,21 +159,9 @@ void rb_imemo_mark_and_move(VALUE obj, bool reference_updating);
void rb_imemo_free(VALUE obj);
RUBY_SYMBOL_EXPORT_BEGIN
-VALUE rb_imemo_new(enum imemo_type type, VALUE v0, size_t size);
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)
{
@@ -201,12 +197,6 @@ rb_vm_ifunc_proc_new(rb_block_call_func_t func, const void *data)
return rb_vm_ifunc_new(func, data, 0, UNLIMITED_ARGUMENTS);
}
-static inline VALUE
-rb_imemo_tmpbuf_auto_free_pointer(void)
-{
- return rb_imemo_new(imemo_tmpbuf, 0, sizeof(rb_imemo_tmpbuf_t));
-}
-
static inline void *
RB_IMEMO_TMPBUF_PTR(VALUE v)
{
@@ -214,30 +204,16 @@ RB_IMEMO_TMPBUF_PTR(VALUE v)
return p->ptr;
}
-static inline void *
-rb_imemo_tmpbuf_set_ptr(VALUE v, void *ptr)
-{
- return ((rb_imemo_tmpbuf_t *)v)->ptr = ptr;
-}
-
static inline VALUE
-rb_imemo_tmpbuf_auto_free_pointer_new_from_an_RString(VALUE str)
+rb_imemo_tmpbuf_new_from_an_RString(VALUE str)
{
- const void *src;
VALUE imemo;
- rb_imemo_tmpbuf_t *tmpbuf;
- void *dst;
size_t len;
StringValue(str);
- /* create tmpbuf to keep the pointer before xmalloc */
- imemo = rb_imemo_tmpbuf_auto_free_pointer();
- tmpbuf = (rb_imemo_tmpbuf_t *)imemo;
len = RSTRING_LEN(str);
- src = RSTRING_PTR(str);
- dst = ruby_xmalloc(len);
- memcpy(dst, src, len);
- tmpbuf->ptr = dst;
+ rb_alloc_tmp_buffer(&imemo, len);
+ memcpy(RB_IMEMO_TMPBUF_PTR(imemo), RSTRING_PTR(str), len);
return imemo;
}
@@ -253,6 +229,15 @@ MEMO_V2_SET(struct MEMO *m, VALUE v)
RB_OBJ_WRITE(m, &m->v2, v);
}
+VALUE rb_imemo_cdhash_new(size_t size, const struct st_hash_type *type);
+
+static inline st_table *
+rb_imemo_cdhash_tbl(VALUE obj)
+{
+ RUBY_ASSERT(IMEMO_TYPE_P(obj, imemo_cdhash));
+ return &((struct rb_imemo_cdhash *)obj)->tbl;
+}
+
struct rb_fields {
struct RBasic basic;
union {
@@ -270,48 +255,82 @@ struct rb_fields {
} as;
};
-#define OBJ_FIELD_EXTERNAL IMEMO_FL_USER0
+// IMEMO/fields and T_OBJECT have exactly the same layout.
+// This is useful for JIT and common codepaths.
+#define OBJ_FIELD_HEAP ROBJECT_HEAP
+STATIC_ASSERT(imemo_fields_flags, OBJ_FIELD_HEAP == IMEMO_FL_USER0);
+STATIC_ASSERT(imemo_fields_embed_offset, offsetof(struct RObject, as.ary) == offsetof(struct rb_fields, as.embed.fields));
+STATIC_ASSERT(imemo_fields_external_offset, offsetof(struct RObject, as.heap.fields) == offsetof(struct rb_fields, as.external.ptr));
+STATIC_ASSERT(imemo_fields_complex_offset, offsetof(struct RObject, as.heap.fields) == offsetof(struct rb_fields, as.complex.table));
+
#define IMEMO_OBJ_FIELDS(fields) ((struct rb_fields *)fields)
-VALUE rb_imemo_fields_new(VALUE owner, size_t capa);
-VALUE rb_imemo_fields_new_complex(VALUE owner, size_t capa);
-VALUE rb_imemo_fields_new_complex_tbl(VALUE owner, st_table *tbl);
+#define IMEMO_SUBCLASSES_HEAP IMEMO_FL_USER0
+
+struct rb_subclasses {
+ VALUE flags;
+ uint32_t count;
+ uint32_t capacity;
+ union {
+ VALUE *external;
+ VALUE embed[1];
+ } as;
+};
+
+static inline VALUE *
+rb_imemo_subclasses_entries(VALUE v)
+{
+ struct rb_subclasses *s = (struct rb_subclasses *)v;
+ return FL_TEST_RAW(v, IMEMO_SUBCLASSES_HEAP) ? s->as.external : s->as.embed;
+}
+
+VALUE rb_imemo_fields_new(VALUE owner, /* shape_id_t */ uint32_t shape_id, bool shareable);
+VALUE rb_imemo_subclasses_new(uint32_t capacity);
+VALUE rb_imemo_fields_new_complex(VALUE owner, /* shape_id_t */ uint32_t shape_id, size_t capa, bool shareable);
+VALUE rb_imemo_fields_new_complex_tbl(VALUE owner, /* shape_id_t */ uint32_t shape_id, st_table *tbl, bool shareable);
VALUE rb_imemo_fields_clone(VALUE fields_obj);
void rb_imemo_fields_clear(VALUE fields_obj);
static inline VALUE
rb_imemo_fields_owner(VALUE fields_obj)
{
+ RUBY_ASSERT(IMEMO_TYPE_P(fields_obj, imemo_fields));
+
return CLASS_OF(fields_obj);
}
static inline VALUE *
-rb_imemo_fields_ptr(VALUE obj_fields)
+rb_imemo_fields_ptr(VALUE fields_obj)
{
- if (!obj_fields) {
+ if (!fields_obj) {
return NULL;
}
- RUBY_ASSERT(IMEMO_TYPE_P(obj_fields, imemo_fields));
+ RUBY_ASSERT(IMEMO_TYPE_P(fields_obj, imemo_fields) || RB_TYPE_P(fields_obj, T_OBJECT));
- if (RB_UNLIKELY(FL_TEST_RAW(obj_fields, OBJ_FIELD_EXTERNAL))) {
- return IMEMO_OBJ_FIELDS(obj_fields)->as.external.ptr;
+ if (UNLIKELY(FL_TEST_RAW(fields_obj, OBJ_FIELD_HEAP))) {
+ return IMEMO_OBJ_FIELDS(fields_obj)->as.external.ptr;
}
else {
- return IMEMO_OBJ_FIELDS(obj_fields)->as.embed.fields;
+ return IMEMO_OBJ_FIELDS(fields_obj)->as.embed.fields;
}
}
static inline st_table *
-rb_imemo_fields_complex_tbl(VALUE obj_fields)
+rb_imemo_fields_complex_tbl(VALUE fields_obj)
{
- if (!obj_fields) {
+ if (!fields_obj) {
return NULL;
}
- RUBY_ASSERT(IMEMO_TYPE_P(obj_fields, imemo_fields));
+ RUBY_ASSERT(IMEMO_TYPE_P(fields_obj, imemo_fields) || RB_TYPE_P(fields_obj, T_OBJECT));
+ RUBY_ASSERT(FL_TEST_RAW(fields_obj, OBJ_FIELD_HEAP));
+
+ // Some codepaths unconditionally access the fields_ptr, and assume it can be used as st_table if the
+ // shape is complex.
+ RUBY_ASSERT((st_table *)rb_imemo_fields_ptr(fields_obj) == IMEMO_OBJ_FIELDS(fields_obj)->as.complex.table);
- return IMEMO_OBJ_FIELDS(obj_fields)->as.complex.table;
+ return IMEMO_OBJ_FIELDS(fields_obj)->as.complex.table;
}
#endif /* INTERNAL_IMEMO_H */
diff --git a/internal/inits.h b/internal/inits.h
index e618d87cc3..be73dac1dc 100644
--- a/internal/inits.h
+++ b/internal/inits.h
@@ -9,6 +9,10 @@
* @brief Internal header aggregating init functions.
*/
+/* box.c */
+void Init_enable_box(void);
+void Init_master_box(void);
+
/* class.c */
void Init_class_hierarchy(void);
@@ -25,9 +29,6 @@ int Init_enc_set_filesystem_encoding(void);
/* newline.c */
void Init_newline(void);
-/* namespace.c */
-void Init_enable_namespace(void);
-
/* vm.c */
void Init_BareVM(void);
void Init_vm_objects(void);
diff --git a/internal/io.h b/internal/io.h
index e6a741ee71..2110f0b087 100644
--- a/internal/io.h
+++ b/internal/io.h
@@ -132,7 +132,7 @@ struct rb_io {
struct rb_execution_context_struct *closing_ec;
VALUE wakeup_mutex;
- // The fork generation of the the blocking operations list.
+ // The fork generation of the blocking operations list.
rb_serial_t fork_generation;
};
@@ -149,6 +149,7 @@ VALUE rb_io_prep_stdout(void);
VALUE rb_io_prep_stderr(void);
int rb_io_notify_close(struct rb_io *fptr);
+bool rb_io_fptr_finalize_closed(struct rb_io *fptr);
RUBY_SYMBOL_EXPORT_BEGIN
/* io.c (export) */
diff --git a/internal/load.h b/internal/load.h
index fb880a43ba..6cffe0ce64 100644
--- a/internal/load.h
+++ b/internal/load.h
@@ -12,7 +12,7 @@
/* load.c */
VALUE rb_get_expanded_load_path(void);
-VALUE rb_load_entrypoint(VALUE args);
+VALUE rb_load_entrypoint(VALUE fname, VALUE wrap);
VALUE rb_require_relative_entrypoint(VALUE fname);
int rb_require_internal(VALUE fname);
NORETURN(void rb_load_fail(VALUE, const char*));
diff --git a/internal/namespace.h b/internal/namespace.h
deleted file mode 100644
index 4cdfbc305f..0000000000
--- a/internal/namespace.h
+++ /dev/null
@@ -1,86 +0,0 @@
-#ifndef INTERNAL_NAMESPACE_H /*-*-C-*-vi:se ft=c:*/
-#define INTERNAL_NAMESPACE_H
-
-#include "ruby/ruby.h" /* for VALUE */
-
-/**
- * @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 Namespace.
- */
-struct rb_namespace_struct {
- /*
- * To retrieve Namespace object that provides #require and so on.
- * That is used from load.c, etc., that uses rb_namespace_t internally.
- */
- VALUE ns_object;
- long ns_id; // namespace id to generate ext filenames
-
- VALUE top_self;
-
- VALUE load_path;
- VALUE load_path_snapshot;
- VALUE load_path_check_cache;
- VALUE expanded_load_path;
- VALUE loaded_features;
- VALUE loaded_features_snapshot;
- VALUE loaded_features_realpaths;
- VALUE loaded_features_realpath_map;
- struct st_table *loaded_features_index;
- struct st_table *loading_table;
- VALUE ruby_dln_libmap;
-
- VALUE gvar_tbl;
-
- bool is_builtin;
- bool is_user;
- bool is_optional;
-};
-typedef struct rb_namespace_struct rb_namespace_t;
-
-#define NAMESPACE_BUILTIN_P(ns) (ns && ns->is_builtin)
-#define NAMESPACE_USER_P(ns) (ns && ns->is_user)
-#define NAMESPACE_OPTIONAL_P(ns) (ns && ns->is_optional)
-#define NAMESPACE_MAIN_P(ns) (ns && ns->is_user && !ns->is_optional)
-
-#define NAMESPACE_METHOD_DEFINITION(mdef) (mdef ? mdef->ns : NULL)
-#define NAMESPACE_METHOD_ENTRY(me) (me ? NAMESPACE_METHOD_DEFINITION(me->def) : NULL)
-#define NAMESPACE_CC(cc) (cc ? NAMESPACE_METHOD_ENTRY(cc->cme_) : NULL)
-#define NAMESPACE_CC_ENTRIES(ccs) (ccs ? NAMESPACE_METHOD_ENTRY(ccs->cme) : NULL)
-
-RUBY_EXTERN bool ruby_namespace_enabled;
-RUBY_EXTERN bool ruby_namespace_init_done;
-
-static inline bool
-rb_namespace_available(void)
-{
- return ruby_namespace_enabled;
-}
-
-void rb_namespace_enable_builtin(void);
-void rb_namespace_disable_builtin(void);
-void rb_namespace_push_loading_namespace(const rb_namespace_t *);
-void rb_namespace_pop_loading_namespace(const rb_namespace_t *);
-rb_namespace_t * rb_root_namespace(void);
-const rb_namespace_t *rb_builtin_namespace(void);
-rb_namespace_t * rb_main_namespace(void);
-const rb_namespace_t * rb_definition_namespace(void);
-const rb_namespace_t * rb_loading_namespace(void);
-const rb_namespace_t * rb_current_namespace(void);
-VALUE rb_current_namespace_details(VALUE);
-
-void rb_namespace_entry_mark(void *);
-
-rb_namespace_t * rb_get_namespace_t(VALUE ns);
-VALUE rb_get_namespace_object(rb_namespace_t *ns);
-typedef VALUE namespace_exec_func(VALUE arg);
-VALUE rb_namespace_exec(const rb_namespace_t *ns, namespace_exec_func *func, VALUE arg);
-
-VALUE rb_namespace_local_extension(VALUE namespace, VALUE fname, VALUE path);
-
-void rb_initialize_main_namespace(void);
-void rb_namespace_init_done(void);
-#endif /* INTERNAL_NAMESPACE_H */
diff --git a/internal/numeric.h b/internal/numeric.h
index 58f42f41ac..a24432df1e 100644
--- a/internal/numeric.h
+++ b/internal/numeric.h
@@ -10,9 +10,9 @@
*/
#include "internal/bignum.h" /* for BIGNUM_POSITIVE_P */
#include "internal/bits.h" /* for RUBY_BIT_ROTL */
+#include "internal/compar.h" /* for rb_cmperr_reason */
#include "internal/fixnum.h" /* for FIXNUM_POSITIVE_P */
#include "internal/vm.h" /* for rb_method_basic_definition_p */
-#include "ruby/intern.h" /* for rb_cmperr */
#include "ruby/ruby.h" /* for USE_FLONUM */
#define ROUND_TO(mode, even, up, down) \
@@ -70,6 +70,7 @@ VALUE rb_float_minus(VALUE x, VALUE y);
VALUE rb_int_mul(VALUE x, VALUE y);
VALUE rb_float_mul(VALUE x, VALUE y);
VALUE rb_float_div(VALUE x, VALUE y);
+VALUE rb_flo_to_i(VALUE num);
VALUE rb_int_idiv(VALUE x, VALUE y);
VALUE rb_int_modulo(VALUE x, VALUE y);
VALUE rb_int2str(VALUE num, int base);
@@ -78,6 +79,7 @@ VALUE rb_int_gt(VALUE x, VALUE y);
VALUE rb_float_gt(VALUE x, VALUE y);
VALUE rb_int_ge(VALUE x, VALUE y);
enum ruby_num_rounding_mode rb_num_get_rounding_option(VALUE opts);
+VALUE rb_int_fdiv(VALUE x, VALUE y);
double rb_int_fdiv_double(VALUE x, VALUE y);
VALUE rb_int_pow(VALUE x, VALUE y);
VALUE rb_float_pow(VALUE x, VALUE y);
@@ -127,6 +129,54 @@ VALUE rb_int_bit_length(VALUE num);
VALUE rb_int_uminus(VALUE num);
VALUE rb_int_comp(VALUE num);
+// Unified 128-bit integer structures that work with or without native support:
+union rb_uint128 {
+#ifdef WORDS_BIGENDIAN
+ struct {
+ uint64_t high;
+ uint64_t low;
+ } parts;
+#else
+ struct {
+ uint64_t low;
+ uint64_t high;
+ } parts;
+#endif
+#ifdef HAVE_UINT128_T
+ uint128_t value;
+#endif
+};
+typedef union rb_uint128 rb_uint128_t;
+
+union rb_int128 {
+#ifdef WORDS_BIGENDIAN
+ struct {
+ uint64_t high;
+ uint64_t low;
+ } parts;
+#else
+ struct {
+ uint64_t low;
+ uint64_t high;
+ } parts;
+#endif
+#ifdef HAVE_UINT128_T
+ int128_t value;
+#endif
+};
+typedef union rb_int128 rb_int128_t;
+
+union uint128_int128_conversion {
+ rb_uint128_t uint128;
+ rb_int128_t int128;
+};
+
+// Conversion functions for 128-bit integers:
+rb_uint128_t rb_numeric_to_uint128(VALUE x);
+rb_int128_t rb_numeric_to_int128(VALUE x);
+VALUE rb_uint128_to_numeric(rb_uint128_t n);
+VALUE rb_int128_to_numeric(rb_int128_t n);
+
static inline bool
INT_POSITIVE_P(VALUE num)
{
@@ -161,7 +211,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)) {
- rb_cmperr(num, zero);
+ rb_cmperr_reason(num, zero, "unable to compare with zero");
}
return r;
}
diff --git a/internal/object.h b/internal/object.h
index 3bde53c31b..99aa1f524b 100644
--- a/internal/object.h
+++ b/internal/object.h
@@ -11,7 +11,7 @@
#include "ruby/ruby.h" /* for VALUE */
/* object.c */
-size_t rb_obj_embedded_size(uint32_t fields_count);
+
VALUE rb_class_allocate_instance(VALUE klass);
VALUE rb_class_search_ancestor(VALUE klass, VALUE super);
NORETURN(void rb_undefined_alloc(VALUE klass));
@@ -60,4 +60,13 @@ RBASIC_SET_CLASS(VALUE obj, VALUE klass)
RBASIC_SET_CLASS_RAW(obj, klass);
RB_OBJ_WRITTEN(obj, oldv, klass);
}
+
+static inline size_t
+rb_obj_embedded_size(uint32_t fields_count)
+{
+ size_t size = offsetof(struct RObject, as.ary) + (sizeof(VALUE) * fields_count);
+ // Ensure enough room for the heap pointer if this expands
+ if (size < sizeof(struct RObject)) size = sizeof(struct RObject);
+ return size;
+}
#endif /* INTERNAL_OBJECT_H */
diff --git a/internal/range.h b/internal/range.h
index 2394937bf8..80493ce13e 100644
--- a/internal/range.h
+++ b/internal/range.h
@@ -18,19 +18,19 @@ static inline VALUE RANGE_EXCL(VALUE r);
static inline VALUE
RANGE_BEG(VALUE r)
{
- return RSTRUCT(r)->as.ary[0];
+ return RSTRUCT_GET_RAW(r, 0);
}
static inline VALUE
RANGE_END(VALUE r)
{
- return RSTRUCT_GET(r, 1);
+ return RSTRUCT_GET_RAW(r, 1);
}
static inline VALUE
RANGE_EXCL(VALUE r)
{
- return RSTRUCT_GET(r, 2);
+ return RSTRUCT_GET_RAW(r, 2);
}
VALUE
diff --git a/internal/rational.h b/internal/rational.h
index f11fab4583..6861a90130 100644
--- a/internal/rational.h
+++ b/internal/rational.h
@@ -28,6 +28,7 @@ VALUE rb_rational_plus(VALUE self, VALUE other);
VALUE rb_rational_minus(VALUE self, VALUE other);
VALUE rb_rational_mul(VALUE self, VALUE other);
VALUE rb_rational_div(VALUE self, VALUE other);
+VALUE rb_rational_fdiv(VALUE self, VALUE other);
VALUE rb_lcm(VALUE x, VALUE y);
VALUE rb_rational_reciprocal(VALUE x);
VALUE rb_cstr_to_rat(const char *, int);
@@ -37,7 +38,9 @@ VALUE rb_rational_cmp(VALUE self, VALUE other);
VALUE rb_rational_pow(VALUE self, VALUE other);
VALUE rb_rational_floor(VALUE self, int ndigits);
VALUE rb_numeric_quo(VALUE x, VALUE y);
-VALUE rb_flo_round_by_rational(int argc, VALUE *argv, VALUE num);
+VALUE rb_flo_round_by_rational(VALUE num, int ndigits, enum ruby_num_rounding_mode mode);
+VALUE rb_flo_ceil_by_rational(VALUE num, int ndigits);
+VALUE rb_flo_floor_by_rational(VALUE num, int ndigits);
VALUE rb_float_numerator(VALUE x);
VALUE rb_float_denominator(VALUE x);
@@ -68,4 +71,22 @@ RATIONAL_SET_DEN(VALUE r, VALUE d)
RB_OBJ_WRITE(r, &RRATIONAL(r)->den, d);
}
+inline static bool
+f_zero_p(VALUE x)
+{
+ if (RB_INTEGER_TYPE_P(x)) {
+ return FIXNUM_ZERO_P(x);
+ }
+ else if (RB_FLOAT_TYPE_P(x)) {
+ return FLOAT_ZERO_P(x);
+ }
+ else if (RB_TYPE_P(x, T_RATIONAL)) {
+ const VALUE num = RRATIONAL(x)->num;
+ return FIXNUM_ZERO_P(num);
+ }
+ return rb_equal(x, INT2FIX(0)) != 0;
+}
+
+#define f_nonzero_p(x) (!f_zero_p(x))
+
#endif /* INTERNAL_RATIONAL_H */
diff --git a/internal/re.h b/internal/re.h
index 593e5c464f..6c0aee6d06 100644
--- a/internal/re.h
+++ b/internal/re.h
@@ -10,19 +10,65 @@
*/
#include "ruby/internal/stdbool.h" /* for bool */
#include "ruby/ruby.h" /* for VALUE */
+#include "ruby/re.h" /* for struct RMatch and struct re_registers */
+
+#define RMATCH_ONIG FL_USER1
+#define RMATCH_OFFSETS_EXTERNAL FL_USER2
+
+static inline OnigPosition *
+RMATCH_BEG_PTR(VALUE match)
+{
+ if (FL_TEST_RAW(match, RMATCH_ONIG)) {
+ return RMATCH(match)->as.onig.beg;
+ }
+ else {
+ return &RMATCH(match)->as.embed[0];
+ }
+}
+
+static inline OnigPosition *
+RMATCH_END_PTR(VALUE match)
+{
+ if (FL_TEST_RAW(match, RMATCH_ONIG)) {
+ return RMATCH(match)->as.onig.end;
+ }
+ else {
+ return &RMATCH(match)->as.embed[RMATCH(match)->num_regs];
+ }
+}
+
+static inline long
+RMATCH_BEG(VALUE match, int i)
+{
+ return RMATCH_BEG_PTR(match)[i];
+}
+
+static inline long
+RMATCH_END(VALUE match, int i)
+{
+ return RMATCH_END_PTR(match)[i];
+}
+
+static inline int
+RMATCH_NREGS(VALUE match)
+{
+ return RMATCH(match)->num_regs;
+}
/* re.c */
+VALUE rb_reg_s_alloc(VALUE klass);
VALUE rb_reg_compile(VALUE str, int options, const char *sourcefile, int sourceline);
VALUE rb_reg_check_preprocess(VALUE);
long rb_reg_search0(VALUE, VALUE, long, int, int, VALUE *);
VALUE rb_reg_match_p(VALUE re, VALUE str, long pos);
+VALUE rb_reg_regsub_match(VALUE str, VALUE src, VALUE match);
bool rb_reg_start_with_p(VALUE re, VALUE str);
VALUE rb_reg_hash(VALUE re);
VALUE rb_reg_equal(VALUE re1, VALUE re2);
VALUE rb_backref_set_string(VALUE string, long pos, long len);
void rb_match_unbusy(VALUE);
int rb_match_count(VALUE match);
-VALUE rb_reg_new_ary(VALUE ary, int options);
+VALUE rb_reg_new_from_values(long cnt, const VALUE *elements, int opt);
VALUE rb_reg_last_defined(VALUE match);
#define ARG_REG_OPTION_MASK \
diff --git a/internal/set_table.h b/internal/set_table.h
index 6242e979c6..3876a8935e 100644
--- a/internal/set_table.h
+++ b/internal/set_table.h
@@ -1,7 +1,7 @@
#ifndef INTERNAL_SET_TABLE_H
#define INTERNAL_SET_TABLE_H
-#include "include/ruby/st.h"
+#include "ruby/st.h"
struct set_table_entry;
@@ -42,6 +42,8 @@ set_table *rb_set_init_table_with_size(set_table *tab, const struct st_hash_type
set_table *rb_set_init_numtable(void);
#define set_init_numtable_with_size rb_set_init_numtable_with_size
set_table *rb_set_init_numtable_with_size(st_index_t size);
+#define set_init_embedded_numtable_with_size rb_set_init_embedded_numtable_with_size
+set_table *rb_set_init_embedded_numtable_with_size(struct set_table *tbl, st_index_t size);
#define set_table_delete rb_set_table_delete
int rb_set_table_delete(set_table *, st_data_t *); /* returns 0:notfound 1:deleted */
#define set_insert rb_set_insert
@@ -58,6 +60,8 @@ int rb_set_foreach_check(set_table *, set_foreach_check_callback_func *, st_data
st_index_t rb_set_keys(set_table *table, st_data_t *keys, st_index_t size);
#define set_free_table rb_set_free_table
void rb_set_free_table(set_table *);
+#define set_free_embedded_table rb_set_free_embedded_table
+void set_free_embedded_table(set_table *tab);
#define set_table_clear rb_set_table_clear
void rb_set_table_clear(set_table *);
#define set_copy rb_set_copy
diff --git a/internal/st.h b/internal/st.h
index a26b224505..14dcb25511 100644
--- a/internal/st.h
+++ b/internal/st.h
@@ -1,11 +1,20 @@
#ifndef INTERNAL_ST_H
#define INTERNAL_ST_H
-#include "include/ruby/st.h"
+#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
+st_table *rb_st_init_existing_numtable_with_size(st_table *tab, st_index_t size);
+#define st_init_existing_numtable_with_size rb_st_init_existing_numtable_with_size
+
+st_table *rb_st_init_existing_strtable_with_size(st_table *tab, st_index_t size);
+#define st_init_existing_strtable_with_size rb_st_init_existing_strtable_with_size
+
+void rb_st_free_embedded_table(st_table *tab);
+#define st_free_embedded_table rb_st_free_embedded_table
+
#endif
diff --git a/internal/string.h b/internal/string.h
index d6fea62061..94a46a9657 100644
--- a/internal/string.h
+++ b/internal/string.h
@@ -14,6 +14,7 @@
#include "ruby/internal/stdbool.h" /* for bool */
#include "ruby/encoding.h" /* for rb_encoding */
#include "ruby/ruby.h" /* for VALUE */
+#include "encindex.h"
#define STR_SHARED FL_USER0 /* = ELTS_SHARED */
#define STR_NOEMBED FL_USER1
@@ -29,6 +30,39 @@ enum ruby_rstring_private_flags {
# undef rb_fstring_cstr
#endif
+static inline bool
+rb_str_encindex_fastpath(int encindex)
+{
+ // The overwhelming majority of strings are in one of these 3 encodings,
+ // which are all either ASCII or perfect ASCII supersets.
+ // Hence you can use fast, single byte algorithms on them, such as `memchr` etc,
+ // without all the overhead of fetching the rb_encoding and using functions such as
+ // rb_enc_mbminlen etc.
+ // Many other encodings could qualify, but they are expected to be rare occurrences,
+ // so it's better to keep that list small.
+ switch (encindex) {
+ case ENCINDEX_ASCII_8BIT:
+ case ENCINDEX_UTF_8:
+ case ENCINDEX_US_ASCII:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static inline bool
+rb_str_enc_fastpath(VALUE str)
+{
+ return rb_str_encindex_fastpath(ENCODING_GET_INLINED(str));
+}
+
+static inline rb_encoding *
+rb_str_enc_get(VALUE str)
+{
+ RUBY_ASSERT(RB_TYPE_P(str, T_STRING));
+ return rb_enc_from_index(ENCODING_GET(str));
+}
+
/* string.c */
VALUE rb_str_dup_m(VALUE str);
VALUE rb_fstring(VALUE);
@@ -63,6 +97,8 @@ bool rb_str_reembeddable_p(VALUE);
VALUE rb_str_upto_endless_each(VALUE, int (*each)(VALUE, VALUE), VALUE);
VALUE rb_str_with_debug_created_info(VALUE, VALUE, int);
VALUE rb_str_frozen_bare_string(VALUE);
+const char *rb_str_null_check(VALUE);
+VALUE rb_str_casecmp(VALUE str1, VALUE str2);
/* error.c */
void rb_warn_unchilled_literal(VALUE str);
diff --git a/internal/struct.h b/internal/struct.h
index 337f96a336..d3c8157393 100644
--- a/internal/struct.h
+++ b/internal/struct.h
@@ -49,36 +49,16 @@ struct RStruct {
#define RSTRUCT(obj) ((struct RStruct *)(obj))
-#ifdef RSTRUCT_LEN
-# undef RSTRUCT_LEN
-#endif
-
-#ifdef RSTRUCT_PTR
-# undef RSTRUCT_PTR
-#endif
-
-#ifdef RSTRUCT_SET
-# undef RSTRUCT_SET
-#endif
-
-#ifdef RSTRUCT_GET
-# undef RSTRUCT_GET
-#endif
-
-#define RSTRUCT_LEN internal_RSTRUCT_LEN
-#define RSTRUCT_SET internal_RSTRUCT_SET
-#define RSTRUCT_GET internal_RSTRUCT_GET
-
/* struct.c */
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 long RSTRUCT_EMBED_LEN(VALUE st);
-static inline long RSTRUCT_LEN(VALUE st);
+static inline long RSTRUCT_LEN_RAW(VALUE st);
static inline int RSTRUCT_LENINT(VALUE st);
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 void RSTRUCT_SET_RAW(VALUE st, long k, VALUE v);
+static inline VALUE RSTRUCT_GET_RAW(VALUE st, long k);
static inline long
RSTRUCT_EMBED_LEN(VALUE st)
@@ -89,7 +69,7 @@ RSTRUCT_EMBED_LEN(VALUE st)
}
static inline long
-RSTRUCT_LEN(VALUE st)
+RSTRUCT_LEN_RAW(VALUE st)
{
if (FL_TEST_RAW(st, RSTRUCT_EMBED_LEN_MASK)) {
return RSTRUCT_EMBED_LEN(st);
@@ -102,7 +82,7 @@ RSTRUCT_LEN(VALUE st)
static inline int
RSTRUCT_LENINT(VALUE st)
{
- return rb_long2int(RSTRUCT_LEN(st));
+ return rb_long2int(RSTRUCT_LEN_RAW(st));
}
static inline const VALUE *
@@ -119,13 +99,13 @@ RSTRUCT_CONST_PTR(VALUE st)
}
static inline void
-RSTRUCT_SET(VALUE st, long k, VALUE v)
+RSTRUCT_SET_RAW(VALUE st, long k, VALUE v)
{
RB_OBJ_WRITE(st, &RSTRUCT_CONST_PTR(st)[k], v);
}
static inline VALUE
-RSTRUCT_GET(VALUE st, long k)
+RSTRUCT_GET_RAW(VALUE st, long k)
{
return RSTRUCT_CONST_PTR(st)[k];
}
@@ -137,7 +117,7 @@ RSTRUCT_FIELDS_OBJ(VALUE st)
VALUE fields_obj;
if (embed_len) {
RUBY_ASSERT(!FL_TEST_RAW(st, RSTRUCT_GEN_FIELDS));
- fields_obj = RSTRUCT_GET(st, embed_len);
+ fields_obj = RSTRUCT_GET_RAW(st, embed_len);
}
else {
fields_obj = RSTRUCT(st)->as.heap.fields_obj;
@@ -151,7 +131,7 @@ RSTRUCT_SET_FIELDS_OBJ(VALUE st, VALUE fields_obj)
const long embed_len = RSTRUCT_EMBED_LEN(st);
if (embed_len) {
RUBY_ASSERT(!FL_TEST_RAW(st, RSTRUCT_GEN_FIELDS));
- RSTRUCT_SET(st, embed_len, fields_obj);
+ RSTRUCT_SET_RAW(st, embed_len, fields_obj);
}
else {
RB_OBJ_WRITE(st, &RSTRUCT(st)->as.heap.fields_obj, fields_obj);
diff --git a/internal/thread.h b/internal/thread.h
index 928126c3b0..ea891b4372 100644
--- a/internal/thread.h
+++ b/internal/thread.h
@@ -56,14 +56,16 @@ 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_io_wait(struct rb_io *io, int events, struct timeval * timeout);
-int rb_thread_wait_for_single_fd(int fd, int events, struct timeval * timeout);
+int rb_thread_io_wait(struct rb_thread_struct *th, struct rb_io *io, int events, struct timeval * timeout);
+int rb_thread_wait_for_single_fd(struct rb_thread_struct *th, int fd, int events, struct timeval * timeout);
size_t rb_thread_io_close_interrupt(struct rb_io *);
void rb_thread_io_close_wait(struct rb_io *);
void rb_ec_check_ints(struct rb_execution_context_struct *ec);
+void rb_thread_free_native_thread(void *th_ptr);
+
RUBY_SYMBOL_EXPORT_BEGIN
void *rb_thread_prevent_fork(void *(*func)(void *), void *data); /* for ext/socket/raddrinfo.c */
diff --git a/internal/time.h b/internal/time.h
index e21b3574f6..1f3505f5bc 100644
--- a/internal/time.h
+++ b/internal/time.h
@@ -27,11 +27,8 @@ struct timeval rb_time_timeval(VALUE);
RUBY_SYMBOL_EXPORT_BEGIN
/* time.c (export) */
-void ruby_reset_leap_second_info(void);
-#ifdef RBIMPL_ATTR_DEPRECATED_INTERNAL_ONLY
-RBIMPL_ATTR_DEPRECATED_INTERNAL_ONLY()
-#endif
-void ruby_reset_timezone(const char *);
RUBY_SYMBOL_EXPORT_END
+void ruby_reset_timezone(const char *);
+
#endif /* INTERNAL_TIME_H */
diff --git a/internal/variable.h b/internal/variable.h
index 0a474d6669..58364941c1 100644
--- a/internal/variable.h
+++ b/internal/variable.h
@@ -22,13 +22,14 @@ VALUE rb_search_class_path(VALUE);
VALUE rb_attr_delete(VALUE, ID);
void rb_autoload_str(VALUE mod, ID id, VALUE file);
VALUE rb_autoload_at_p(VALUE, ID, int);
-void rb_autoload_copy_table_for_namespace(st_table *, const rb_namespace_t *);
+void rb_autoload_copy_table_for_box(st_table *, const rb_box_t *);
NORETURN(VALUE rb_mod_const_missing(VALUE,VALUE));
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);
-void rb_gvar_namespace_ready(const char *name);
+void rb_gvar_box_ready(const char *name);
+void rb_gvar_box_dynamic(const char *name);
/**
* Sets the name of a module.
@@ -47,12 +48,15 @@ void rb_gvar_namespace_ready(const char *name);
VALUE rb_mod_set_temporary_name(VALUE, VALUE);
void rb_obj_copy_ivs_to_hash_table(VALUE obj, st_table *table);
-void rb_obj_init_too_complex(VALUE obj, st_table *table);
+void rb_obj_init_complex(VALUE obj, st_table *table);
void rb_evict_ivars_to_hash(VALUE obj);
-shape_id_t rb_evict_fields_to_hash(VALUE obj);
VALUE rb_obj_field_get(VALUE obj, shape_id_t target_shape_id);
void rb_ivar_set_internal(VALUE obj, ID id, VALUE val);
-void rb_obj_field_set(VALUE obj, shape_id_t target_shape_id, ID field_name, VALUE val);
+void rb_ivar_foreach_buffered(VALUE obj, int (*func)(ID name, VALUE val, st_data_t arg), st_data_t arg);
+attr_index_t rb_ivar_set_index(VALUE obj, ID id, VALUE val);
+attr_index_t rb_obj_field_set(VALUE obj, shape_id_t target_shape_id, ID field_name, VALUE val);
+VALUE rb_ivar_get_at(VALUE obj, attr_index_t index, ID id);
+VALUE rb_ivar_get_at_no_ractor_check(VALUE obj, attr_index_t index);
RUBY_SYMBOL_EXPORT_BEGIN
/* variable.c (export) */
@@ -68,6 +72,5 @@ VALUE rb_gvar_set(ID, VALUE);
VALUE rb_gvar_defined(ID);
void rb_const_warn_if_deprecated(const rb_const_entry_t *, VALUE, ID);
void rb_ensure_iv_list_size(VALUE obj, uint32_t current_len, uint32_t newsize);
-attr_index_t rb_obj_ivar_set(VALUE obj, ID id, VALUE val);
#endif /* INTERNAL_VARIABLE_H */
diff --git a/internal/vm.h b/internal/vm.h
index 3a99011c44..4e50ec2710 100644
--- a/internal/vm.h
+++ b/internal/vm.h
@@ -69,6 +69,7 @@ const char *rb_type_str(enum ruby_value_type type);
VALUE rb_check_funcall_default(VALUE, ID, int, const VALUE *, VALUE);
VALUE rb_check_funcall_basic_kw(VALUE, ID, VALUE, int, const VALUE*, int);
VALUE rb_yield_1(VALUE val);
+VALUE rb_ec_yield(struct rb_execution_context_struct *ec, VALUE val);
VALUE rb_yield_force_blockarg(VALUE values);
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,
@@ -77,11 +78,12 @@ 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);
struct vm_ifunc *rb_current_ifunc(void);
-VALUE rb_gccct_clear_table(VALUE);
+VALUE rb_gccct_clear_table(void);
+VALUE rb_eval_cmd_call_kw(VALUE cmd, int argc, const VALUE *argv, int kw_splat);
#if USE_YJIT || USE_ZJIT
/* vm_exec.c */
-extern uint64_t rb_vm_insns_count;
+extern uint64_t rb_vm_insn_count;
#endif
extern bool rb_free_at_exit;
@@ -99,8 +101,6 @@ const struct rb_callcache *rb_vm_search_method_slowpath(const struct rb_callinfo
/* vm_method.c */
int rb_ec_obj_respond_to(struct rb_execution_context_struct *ec, VALUE obj, ID id, int priv);
-void rb_clear_constant_cache(void);
-
/* vm_dump.c */
void rb_print_backtrace(FILE *);
diff --git a/io.c b/io.c
index 4ee45c1344..effcb349c3 100644
--- a/io.c
+++ b/io.c
@@ -500,6 +500,7 @@ rb_cloexec_fcntl_dupfd(int fd, int minfd)
#define argf_of(obj) (*(struct argf *)DATA_PTR(obj))
#define ARGF argf_of(argf)
+#define ARGF_SET(field, value) RB_OBJ_WRITE(argf, &ARGF.field, value)
#define GetWriteIO(io) rb_io_get_write_io(io)
@@ -1110,7 +1111,7 @@ ruby_dup(int orig)
static VALUE
io_alloc(VALUE klass)
{
- NEWOBJ_OF(io, struct RFile, klass, T_FILE, sizeof(struct RFile), 0);
+ UNPROTECTED_NEWOBJ_OF(io, struct RFile, klass, T_FILE, sizeof(struct RFile));
io->fptr = 0;
@@ -1291,7 +1292,8 @@ internal_writev_func(void *ptr)
static ssize_t
rb_io_read_memory(rb_io_t *fptr, void *buf, size_t count)
{
- VALUE scheduler = rb_fiber_scheduler_current();
+ rb_thread_t *th = GET_THREAD();
+ VALUE scheduler = rb_fiber_scheduler_current_for_threadptr(th);
if (scheduler != Qnil) {
VALUE result = rb_fiber_scheduler_io_read_memory(scheduler, fptr->self, buf, count, 0);
@@ -1301,7 +1303,7 @@ rb_io_read_memory(rb_io_t *fptr, void *buf, size_t count)
}
struct io_internal_read_struct iis = {
- .th = rb_thread_current(),
+ .th = th->self,
.fptr = fptr,
.nonblock = 0,
.fd = fptr->fd,
@@ -1324,7 +1326,8 @@ rb_io_read_memory(rb_io_t *fptr, void *buf, size_t count)
static ssize_t
rb_io_write_memory(rb_io_t *fptr, const void *buf, size_t count)
{
- VALUE scheduler = rb_fiber_scheduler_current();
+ rb_thread_t *th = GET_THREAD();
+ VALUE scheduler = rb_fiber_scheduler_current_for_threadptr(th);
if (scheduler != Qnil) {
VALUE result = rb_fiber_scheduler_io_write_memory(scheduler, fptr->self, buf, count, 0);
@@ -1334,7 +1337,7 @@ rb_io_write_memory(rb_io_t *fptr, const void *buf, size_t count)
}
struct io_internal_write_struct iis = {
- .th = rb_thread_current(),
+ .th = th->self,
.fptr = fptr,
.nonblock = 0,
.fd = fptr->fd,
@@ -1360,7 +1363,9 @@ rb_writev_internal(rb_io_t *fptr, const struct iovec *iov, int iovcnt)
{
if (!iovcnt) return 0;
- VALUE scheduler = rb_fiber_scheduler_current();
+ rb_thread_t *th = GET_THREAD();
+
+ VALUE scheduler = rb_fiber_scheduler_current_for_threadptr(th);
if (scheduler != Qnil) {
// This path assumes at least one `iov`:
VALUE result = rb_fiber_scheduler_io_write_memory(scheduler, fptr->self, iov[0].iov_base, iov[0].iov_len, 0);
@@ -1371,7 +1376,7 @@ rb_writev_internal(rb_io_t *fptr, const struct iovec *iov, int iovcnt)
}
struct io_internal_writev_struct iis = {
- .th = rb_thread_current(),
+ .th = th->self,
.fptr = fptr,
.nonblock = 0,
.fd = fptr->fd,
@@ -1414,10 +1419,34 @@ io_flush_buffer_sync(void *arg)
return (VALUE)-1;
}
+static inline VALUE
+io_flush_buffer_fiber_scheduler(VALUE scheduler, rb_io_t *fptr)
+{
+ VALUE ret = rb_fiber_scheduler_io_write_memory(scheduler, fptr->self, fptr->wbuf.ptr+fptr->wbuf.off, fptr->wbuf.len, 0);
+ if (!UNDEF_P(ret)) {
+ ssize_t result = rb_fiber_scheduler_io_result_apply(ret);
+ if (result > 0) {
+ fptr->wbuf.off += result;
+ fptr->wbuf.len -= result;
+ }
+ return result >= 0 ? (VALUE)0 : (VALUE)-1;
+ }
+ return ret;
+}
+
static VALUE
io_flush_buffer_async(VALUE arg)
{
rb_io_t *fptr = (rb_io_t *)arg;
+
+ VALUE scheduler = rb_fiber_scheduler_current();
+ if (scheduler != Qnil) {
+ VALUE result = io_flush_buffer_fiber_scheduler(scheduler, fptr);
+ if (!UNDEF_P(result)) {
+ return result;
+ }
+ }
+
return rb_io_blocking_region_wait(fptr, io_flush_buffer_sync, fptr, RUBY_IO_WRITABLE);
}
@@ -1453,7 +1482,8 @@ io_fflush(rb_io_t *fptr)
VALUE
rb_io_wait(VALUE io, VALUE events, VALUE timeout)
{
- VALUE scheduler = rb_fiber_scheduler_current();
+ rb_thread_t *th = GET_THREAD();
+ VALUE scheduler = rb_fiber_scheduler_current_for_threadptr(th);
if (scheduler != Qnil) {
return rb_fiber_scheduler_io_wait(scheduler, io, events, timeout);
@@ -1474,7 +1504,7 @@ rb_io_wait(VALUE io, VALUE events, VALUE timeout)
tv = &tv_storage;
}
- int ready = rb_thread_io_wait(fptr, RB_NUM2INT(events), tv);
+ int ready = rb_thread_io_wait(th, fptr, RB_NUM2INT(events), tv);
if (ready < 0) {
rb_sys_fail(0);
@@ -1498,17 +1528,15 @@ io_from_fd(int fd)
}
static int
-io_wait_for_single_fd(int fd, int events, struct timeval *timeout)
+io_wait_for_single_fd(int fd, int events, struct timeval *timeout, rb_thread_t *th, VALUE scheduler)
{
- VALUE scheduler = rb_fiber_scheduler_current();
-
if (scheduler != Qnil) {
return RTEST(
rb_fiber_scheduler_io_wait(scheduler, io_from_fd(fd), RB_INT2NUM(events), rb_fiber_scheduler_make_timeout(timeout))
);
}
- return rb_thread_wait_for_single_fd(fd, events, timeout);
+ return rb_thread_wait_for_single_fd(th, fd, events, timeout);
}
int
@@ -1516,7 +1544,8 @@ rb_io_wait_readable(int f)
{
io_fd_check_closed(f);
- VALUE scheduler = rb_fiber_scheduler_current();
+ rb_thread_t *th = GET_THREAD();
+ VALUE scheduler = rb_fiber_scheduler_current_for_threadptr(th);
switch (errno) {
case EINTR:
@@ -1536,7 +1565,7 @@ rb_io_wait_readable(int f)
);
}
else {
- io_wait_for_single_fd(f, RUBY_IO_READABLE, NULL);
+ io_wait_for_single_fd(f, RUBY_IO_READABLE, NULL, th, scheduler);
}
return TRUE;
@@ -1550,7 +1579,8 @@ rb_io_wait_writable(int f)
{
io_fd_check_closed(f);
- VALUE scheduler = rb_fiber_scheduler_current();
+ rb_thread_t *th = GET_THREAD();
+ VALUE scheduler = rb_fiber_scheduler_current_for_threadptr(th);
switch (errno) {
case EINTR:
@@ -1579,7 +1609,7 @@ rb_io_wait_writable(int f)
);
}
else {
- io_wait_for_single_fd(f, RUBY_IO_WRITABLE, NULL);
+ io_wait_for_single_fd(f, RUBY_IO_WRITABLE, NULL, th, scheduler);
}
return TRUE;
@@ -1591,7 +1621,9 @@ rb_io_wait_writable(int f)
int
rb_wait_for_single_fd(int fd, int events, struct timeval *timeout)
{
- return io_wait_for_single_fd(fd, events, timeout);
+ rb_thread_t *th = GET_THREAD();
+ VALUE scheduler = rb_fiber_scheduler_current_for_threadptr(th);
+ return io_wait_for_single_fd(fd, events, timeout, th, scheduler);
}
int
@@ -2504,7 +2536,7 @@ interpret_seek_whence(VALUE vwhence)
* f.tell # => 12
* f.close
*
- * - +:SET+ or <tt>IO:SEEK_SET</tt>:
+ * - +:SET+ or <tt>IO::SEEK_SET</tt>:
* Repositions the stream to the given +offset+:
*
* f = File.open('t.txt')
@@ -2628,9 +2660,6 @@ io_fillbuf(rb_io_t *fptr)
fptr->rbuf.len = 0;
fptr->rbuf.capa = IO_RBUF_CAPA_FOR(fptr);
fptr->rbuf.ptr = ALLOC_N(char, fptr->rbuf.capa);
-#ifdef _WIN32
- fptr->rbuf.capa--;
-#endif
}
if (fptr->rbuf.len == 0) {
retry:
@@ -3156,8 +3185,6 @@ io_enc_str(VALUE str, rb_io_t *fptr)
return str;
}
-static rb_encoding *io_read_encoding(rb_io_t *fptr);
-
static void
make_readconv(rb_io_t *fptr, int size)
{
@@ -3300,10 +3327,6 @@ io_shift_cbuf(rb_io_t *fptr, int len, VALUE *strp)
static int
io_setstrbuf(VALUE *str, long len)
{
-#ifdef _WIN32
- if (len > 0)
- len = (len + 1) & ~1L; /* round up for wide char */
-#endif
if (NIL_P(*str)) {
*str = rb_str_new(0, len);
return TRUE;
@@ -4307,11 +4330,17 @@ rb_io_gets(VALUE io)
}
VALUE
-rb_io_gets_internal(VALUE io)
+rb_io_gets_limit_internal(VALUE io, long limit)
{
rb_io_t *fptr;
GetOpenFile(io, fptr);
- return rb_io_getline_0(rb_default_rs, -1, FALSE, fptr);
+ return rb_io_getline_0(rb_default_rs, limit, FALSE, fptr);
+}
+
+VALUE
+rb_io_gets_internal(VALUE io)
+{
+ return rb_io_gets_limit_internal(io, -1);
}
/*
@@ -4692,10 +4721,11 @@ rb_io_each_line(int argc, VALUE *argv, VALUE io)
* Calls the given block with each byte (0..255) in the stream; returns +self+.
* See {Byte IO}[rdoc-ref:IO@Byte+IO].
*
- * f = File.new('t.rus')
+ * File.read('t.ja') # => "ã“ã‚“ã«ã¡ã¯"
+ * f = File.new('t.ja')
* a = []
* f.each_byte {|b| a << b }
- * a # => [209, 130, 208, 181, 209, 129, 209, 130]
+ * a # => [227, 129, 147, 227, 130, 147, 227, 129, 171, 227, 129, 161, 227, 129, 175]
* f.close
*
* Returns an Enumerator if no block is given.
@@ -4840,10 +4870,11 @@ io_getc(rb_io_t *fptr, rb_encoding *enc)
* Calls the given block with each character in the stream; returns +self+.
* See {Character IO}[rdoc-ref:IO@Character+IO].
*
- * f = File.new('t.rus')
+ * File.read('t.ja') # => "ã“ã‚“ã«ã¡ã¯"
+ * f = File.new('t.ja')
* a = []
* f.each_char {|c| a << c.ord }
- * a # => [1090, 1077, 1089, 1090]
+ * a # => [12371, 12435, 12395, 12385, 12399]
* f.close
*
* Returns an Enumerator if no block is given.
@@ -4878,10 +4909,11 @@ rb_io_each_char(VALUE io)
*
* Calls the given block with each codepoint in the stream; returns +self+:
*
- * f = File.new('t.rus')
+ * File.read('t.ja') # => "ã“ã‚“ã«ã¡ã¯"
+ * f = File.new('t.ja')
* a = []
* f.each_codepoint {|c| a << c }
- * a # => [1090, 1077, 1089, 1090]
+ * a # => [12371, 12435, 12395, 12385, 12399]
* f.close
*
* Returns an Enumerator if no block is given.
@@ -4903,6 +4935,7 @@ rb_io_each_codepoint(VALUE io)
rb_io_check_char_readable(fptr);
READ_CHECK(fptr);
+ enc = io_read_encoding(fptr);
if (NEED_READCONV(fptr)) {
SET_BINARY_MODE(fptr);
r = 1; /* no invalid char yet */
@@ -4910,12 +4943,9 @@ rb_io_each_codepoint(VALUE io)
make_readconv(fptr, 0);
for (;;) {
if (fptr->cbuf.len) {
- if (fptr->encs.enc)
- r = rb_enc_precise_mbclen(fptr->cbuf.ptr+fptr->cbuf.off,
- fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
- fptr->encs.enc);
- else
- r = ONIGENC_CONSTRUCT_MBCLEN_CHARFOUND(1);
+ r = rb_enc_precise_mbclen(fptr->cbuf.ptr+fptr->cbuf.off,
+ fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
+ enc);
if (!MBCLEN_NEEDMORE_P(r))
break;
if (fptr->cbuf.len == fptr->cbuf.capa) {
@@ -4925,33 +4955,25 @@ rb_io_each_codepoint(VALUE io)
if (more_char(fptr) == MORE_CHAR_FINISHED) {
clear_readconv(fptr);
if (!MBCLEN_CHARFOUND_P(r)) {
- enc = fptr->encs.enc;
goto invalid;
}
return io;
}
}
if (MBCLEN_INVALID_P(r)) {
- enc = fptr->encs.enc;
goto invalid;
}
n = MBCLEN_CHARFOUND_LEN(r);
- if (fptr->encs.enc) {
- c = rb_enc_codepoint(fptr->cbuf.ptr+fptr->cbuf.off,
- fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
- fptr->encs.enc);
- }
- else {
- c = (unsigned char)fptr->cbuf.ptr[fptr->cbuf.off];
- }
+ c = rb_enc_codepoint(fptr->cbuf.ptr+fptr->cbuf.off,
+ fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
+ enc);
fptr->cbuf.off += n;
fptr->cbuf.len -= n;
rb_yield(UINT2NUM(c));
- rb_io_check_byte_readable(fptr);
+ rb_io_check_char_readable(fptr);
}
}
NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
- enc = io_input_encoding(fptr);
while (io_fillbuf(fptr) >= 0) {
r = rb_enc_precise_mbclen(fptr->rbuf.ptr+fptr->rbuf.off,
fptr->rbuf.ptr+fptr->rbuf.off+fptr->rbuf.len, enc);
@@ -5005,8 +5027,9 @@ rb_io_each_codepoint(VALUE io)
* f = File.open('t.txt')
* f.getc # => "F"
* f.close
- * f = File.open('t.rus')
- * f.getc.ord # => 1090
+ * File.read('t.ja') # => "ã“ã‚“ã«ã¡ã¯"
+ * f = File.open('t.ja')
+ * f.getc.ord # => 12371
* f.close
*
* Related: IO#readchar (may raise EOFError).
@@ -5038,8 +5061,9 @@ rb_io_getc(VALUE io)
* f = File.open('t.txt')
* f.readchar # => "F"
* f.close
- * f = File.open('t.rus')
- * f.readchar.ord # => 1090
+ * File.read('t.ja') # => "ã“ã‚“ã«ã¡ã¯"
+ * f = File.open('t.ja')
+ * f.readchar.ord # => 12371
* f.close
*
* Related: IO#getc (will not raise EOFError).
@@ -5068,8 +5092,9 @@ rb_io_readchar(VALUE io)
* f = File.open('t.txt')
* f.getbyte # => 70
* f.close
- * f = File.open('t.rus')
- * f.getbyte # => 209
+ * File.read('t.ja') # => "ã“ã‚“ã«ã¡ã¯"
+ * f = File.open('t.ja')
+ * f.getbyte # => 227
* f.close
*
* Related: IO#readbyte (may raise EOFError).
@@ -5112,8 +5137,9 @@ rb_io_getbyte(VALUE io)
* f = File.open('t.txt')
* f.readbyte # => 70
* f.close
- * f = File.open('t.rus')
- * f.readbyte # => 209
+ * File.read('t.ja') # => "ã“ã‚“ã«ã¡ã¯"
+ * f = File.open('t.ja')
+ * f.readbyte # => 227
* f.close
*
* Related: IO#getbyte (will not raise EOFError).
@@ -5557,18 +5583,9 @@ fptr_finalize_flush(rb_io_t *fptr, int noraise, int keepgvl)
fptr->stdio_file = 0;
fptr->mode &= ~(FMODE_READABLE|FMODE_WRITABLE);
- // wait for blocking operations to ensure they do not hit EBADF:
+ // Wait for blocking operations to ensure they do not hit EBADF:
rb_thread_io_close_wait(fptr);
- // Disable for now.
- // if (!done && fd >= 0) {
- // VALUE scheduler = rb_fiber_scheduler_current();
- // if (scheduler != Qnil) {
- // VALUE result = rb_fiber_scheduler_io_close(scheduler, fptr->self);
- // if (!UNDEF_P(result)) done = 1;
- // }
- // }
-
if (!done && stdio_file) {
// stdio_file is deallocated anyway even if fclose failed.
if ((maygvl_fclose(stdio_file, noraise) < 0) && NIL_P(error)) {
@@ -5580,6 +5597,15 @@ fptr_finalize_flush(rb_io_t *fptr, int noraise, int keepgvl)
done = 1;
}
+ VALUE scheduler = rb_fiber_scheduler_current();
+ if (!done && fd >= 0 && scheduler != Qnil) {
+ VALUE result = rb_fiber_scheduler_io_close(scheduler, RB_INT2NUM(fd));
+
+ if (!UNDEF_P(result)) {
+ done = RTEST(result);
+ }
+ }
+
if (!done && fd >= 0) {
// fptr->fd may be closed even if close fails. POSIX doesn't specify it.
// We assumes it is closed.
@@ -5627,7 +5653,7 @@ static void
free_io_buffer(rb_io_buffer_t *buf)
{
if (buf->ptr) {
- ruby_sized_xfree(buf->ptr, (size_t)buf->capa);
+ ruby_xfree_sized(buf->ptr, (size_t)buf->capa);
buf->ptr = NULL;
}
}
@@ -5681,6 +5707,15 @@ rb_io_fptr_finalize(struct rb_io *io)
return 1;
}
+bool
+rb_io_fptr_finalize_closed(struct rb_io *io)
+{
+ if (!io) return true;
+ if (io->fd >= 0) return false;
+ rb_io_fptr_finalize(io);
+ return true;
+}
+
size_t
rb_io_memsize(const rb_io_t *io)
{
@@ -5730,10 +5765,12 @@ io_close_fptr(VALUE io)
if (!fptr) return 0;
if (fptr->fd < 0) return 0;
+ // This guards against multiple threads closing the same IO object:
if (rb_thread_io_close_interrupt(fptr)) {
/* calls close(fptr->fd): */
fptr_finalize_flush(fptr, FALSE, KEEPGVL);
}
+
rb_io_fptr_cleanup(fptr, FALSE);
return fptr;
}
@@ -6260,6 +6297,14 @@ internal_pwrite_func(void *_arg)
{
struct prdwr_internal_arg *arg = _arg;
+ return (VALUE)pwrite(arg->fd, arg->buf, arg->count, arg->offset);
+}
+
+static VALUE
+pwrite_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_pwrite_memory(scheduler, arg->io->self, arg->offset, arg->buf, arg->count, 0);
@@ -6269,8 +6314,7 @@ internal_pwrite_func(void *_arg)
}
}
-
- return (VALUE)pwrite(arg->fd, arg->buf, arg->count, arg->offset);
+ return rb_io_blocking_region_wait(arg->io, internal_pwrite_func, arg, RUBY_IO_WRITABLE);
}
/*
@@ -6322,7 +6366,7 @@ rb_io_pwrite(VALUE io, VALUE str, VALUE offset)
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)pwrite_internal_call((VALUE)&arg);
if (n < 0) rb_sys_fail_path(fptr->pathv);
rb_str_tmp_frozen_release(str, tmp);
@@ -7826,7 +7870,7 @@ static VALUE popen_finish(VALUE port, VALUE klass);
* whose $stdin and $stdout are connected to a new stream +io+.
*
* This method has potential security vulnerabilities if called with untrusted input;
- * see {Command Injection}[rdoc-ref:command_injection.rdoc].
+ * see {Command Injection}[rdoc-ref:security/command_injection.rdoc].
*
* If no block is given, returns the new stream,
* which depending on given +mode+ may be open for reading, writing, or both.
@@ -7835,7 +7879,8 @@ static VALUE popen_finish(VALUE port, VALUE klass);
* If a block is given, the stream is passed to the block
* (again, open for reading, writing, or both);
* when the block exits, the stream is closed,
- * and the block's value is assigned to global variable <tt>$?</tt> and returned.
+ * the block's value is returned,
+ * and the global variable <tt>$?</tt> is set to the child's exit status.
*
* Optional argument +mode+ may be any valid \IO mode.
* See {Access Modes}[rdoc-ref:File@Access+Modes].
@@ -8044,7 +8089,7 @@ popen_finish(VALUE port, VALUE klass)
rb_protect(rb_yield, Qnil, NULL);
rb_io_flush(rb_ractor_stdout());
rb_io_flush(rb_ractor_stderr());
- _exit(0);
+ _exit(EXIT_SUCCESS);
}
return Qnil;
}
@@ -8084,7 +8129,12 @@ ruby_popen_writer(char *const *argv, rb_pid_t *pid)
int write_pair[2];
# endif
- int result = rb_cloexec_pipe(write_pair);
+#ifdef HAVE_PIPE2
+ int result = pipe2(write_pair, O_CLOEXEC);
+#else
+ int result = pipe(write_pair);
+#endif
+
*pid = -1;
if (result == 0) {
# ifdef HAVE_WORKING_FORK
@@ -8216,21 +8266,6 @@ rb_io_s_sysopen(int argc, VALUE *argv, VALUE _)
return INT2NUM(fd);
}
-static VALUE
-check_pipe_command(VALUE filename_or_command)
-{
- char *s = RSTRING_PTR(filename_or_command);
- long l = RSTRING_LEN(filename_or_command);
- char *e = s + l;
- int chlen;
-
- if (rb_enc_ascget(s, e, &chlen, rb_enc_get(filename_or_command)) == '|') {
- VALUE cmd = rb_str_new(s+chlen, l-chlen);
- return cmd;
- }
- return Qnil;
-}
-
/*
* call-seq:
* open(path, mode = 'r', perm = 0666, **opts) -> io or nil
@@ -8238,9 +8273,6 @@ check_pipe_command(VALUE filename_or_command)
*
* Creates an IO object connected to the given file.
*
- * This method has potential security vulnerabilities if called with untrusted input;
- * see {Command Injection}[rdoc-ref:command_injection.rdoc].
- *
* With no block given, file stream is returned:
*
* open('t.txt') # => #<File:t.txt>
@@ -8276,13 +8308,7 @@ rb_f_open(int argc, VALUE *argv, VALUE _)
redirect = TRUE;
}
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);
- }
+ argv[0] = tmp;
}
}
}
@@ -8301,16 +8327,8 @@ static VALUE
rb_io_open_generic(VALUE klass, VALUE filename, int oflags, enum rb_io_mode fmode,
const struct rb_io_encoding *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 {
- return rb_file_open_generic(io_alloc(klass), filename,
- oflags, fmode, convconfig, perm);
- }
+ return rb_file_open_generic(io_alloc(klass), filename,
+ oflags, fmode, convconfig, perm);
}
static VALUE
@@ -8606,7 +8624,7 @@ rb_io_init_copy(VALUE dest, VALUE io)
* Formats and writes +objects+ to the stream.
*
* For details on +format_string+, see
- * {Format Specifications}[rdoc-ref:format_specifications.rdoc].
+ * {Format Specifications}[rdoc-ref:language/format_specifications.rdoc].
*
*/
@@ -8627,7 +8645,7 @@ rb_io_printf(int argc, const VALUE *argv, VALUE out)
* io.write(sprintf(format_string, *objects))
*
* For details on +format_string+, see
- * {Format Specifications}[rdoc-ref:format_specifications.rdoc].
+ * {Format Specifications}[rdoc-ref:language/format_specifications.rdoc].
*
* With the single argument +format_string+, formats +objects+ into the string,
* then writes the formatted string to $stdout:
@@ -8670,31 +8688,19 @@ rb_f_printf(int argc, VALUE *argv, VALUE _)
return Qnil;
}
-static void
-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));
- }
- *var = val;
-}
+extern void rb_deprecated_str_setter(VALUE val, ID id, VALUE *var);
static void
deprecated_rs_setter(VALUE val, ID id, VALUE *var)
{
+ rb_deprecated_str_setter(val, id, &val);
if (!NIL_P(val)) {
- if (!RB_TYPE_P(val, T_STRING)) {
- rb_raise(rb_eTypeError, "value of %"PRIsVALUE" must be String", rb_id2str(id));
- }
if (rb_str_equal(val, rb_default_rs)) {
val = rb_default_rs;
}
else {
val = rb_str_frozen_bare_string(val);
}
- rb_enc_str_coderange(val);
- rb_warn_deprecated("'%s'", NULL, rb_id2name(id));
}
*var = val;
}
@@ -9503,7 +9509,8 @@ static VALUE io_initialize(VALUE io, VALUE fnum, VALUE vmode, VALUE opt);
* The new \IO object does not inherit encoding
* (because the integer file descriptor does not have an encoding):
*
- * fd = IO.sysopen('t.rus', 'rb')
+ * File.read('t.ja') # => "ã“ã‚“ã«ã¡ã¯"
+ * fd = IO.sysopen('t.ja', 'rb')
* io = IO.new(fd)
* io.external_encoding # => #<Encoding:UTF-8> # Not ASCII-8BIT.
*
@@ -9825,7 +9832,7 @@ io_wait_readable(int argc, VALUE *argv, VALUE io)
rb_io_t *fptr;
RB_IO_POINTER(io, fptr);
- rb_io_check_readable(fptr);
+ rb_io_check_char_readable(fptr);
if (rb_io_read_pending(fptr)) return Qtrue;
@@ -9872,7 +9879,7 @@ io_wait_priority(int argc, VALUE *argv, VALUE io)
rb_io_t *fptr = NULL;
RB_IO_POINTER(io, fptr);
- rb_io_check_readable(fptr);
+ rb_io_check_char_readable(fptr);
if (rb_io_read_pending(fptr)) return Qtrue;
@@ -10020,16 +10027,16 @@ argf_memsize(const void *ptr)
static const rb_data_type_t argf_type = {
"ARGF",
{argf_mark_and_move, RUBY_TYPED_DEFAULT_FREE, argf_memsize, argf_mark_and_move},
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED
};
static inline void
-argf_init(struct argf *p, VALUE v)
+argf_init(VALUE argf, struct argf *p, VALUE v)
{
p->filename = Qnil;
p->current_file = Qnil;
p->lineno = 0;
- p->argv = v;
+ RB_OBJ_WRITE(argf, &p->argv, v);
}
static VALUE
@@ -10038,7 +10045,7 @@ argf_alloc(VALUE klass)
struct argf *p;
VALUE argf = TypedData_Make_Struct(klass, struct argf, &argf_type, p);
- argf_init(p, Qnil);
+ argf_init(argf, p, Qnil);
return argf;
}
@@ -10049,7 +10056,7 @@ static VALUE
argf_initialize(VALUE argf, VALUE argv)
{
memset(&ARGF, 0, sizeof(ARGF));
- argf_init(&ARGF, argv);
+ argf_init(argf, &ARGF, argv);
return argf;
}
@@ -10060,7 +10067,8 @@ argf_initialize_copy(VALUE argf, VALUE orig)
{
if (!OBJ_INIT_COPY(argf, orig)) return argf;
ARGF = argf_of(orig);
- ARGF.argv = rb_obj_dup(ARGF.argv);
+ rb_gc_writebarrier_remember(argf);
+ ARGF_SET(argv, rb_obj_dup(ARGF.argv));
return argf;
}
@@ -10179,11 +10187,11 @@ argf_next_argv(VALUE argf)
if (RARRAY_LEN(ARGF.argv) > 0) {
VALUE filename = rb_ary_shift(ARGF.argv);
FilePathValue(filename);
- ARGF.filename = filename;
+ ARGF_SET(filename, filename);
filename = rb_str_encode_ospath(filename);
fn = StringValueCStr(filename);
if (RSTRING_LEN(filename) == 1 && fn[0] == '-') {
- ARGF.current_file = rb_stdin;
+ ARGF_SET(current_file, rb_stdin);
if (ARGF.inplace) {
rb_warn("Can't do inplace edit for stdio; skipping");
goto retry;
@@ -10278,7 +10286,7 @@ argf_next_argv(VALUE argf)
if (!ARGF.binmode) {
fmode |= DEFAULT_TEXTMODE;
}
- ARGF.current_file = prep_io(fr, fmode, rb_cFile, fn);
+ ARGF_SET(current_file, prep_io(fr, fmode, rb_cFile, fn));
if (!NIL_P(write_io)) {
rb_io_set_write_io(ARGF.current_file, write_io);
}
@@ -10307,8 +10315,8 @@ argf_next_argv(VALUE argf)
}
}
else if (ARGF.next_p == -1) {
- ARGF.current_file = rb_stdin;
- ARGF.filename = rb_str_new2("-");
+ ARGF_SET(current_file, rb_stdin);
+ ARGF_SET(filename, rb_str_new2("-"));
if (ARGF.inplace) {
rb_warn("Can't do inplace edit for stdio");
rb_ractor_stdout_set(orig_stdout);
@@ -10650,7 +10658,7 @@ argf_readlines(int argc, VALUE *argv, VALUE argf)
* sets global variable <tt>$?</tt> to the process status.
*
* This method has potential security vulnerabilities if called with untrusted input;
- * see {Command Injection}[rdoc-ref:command_injection.rdoc].
+ * see {Command Injection}[rdoc-ref:security/command_injection.rdoc].
*
* Examples:
*
@@ -10761,9 +10769,9 @@ select_internal(VALUE read, VALUE write, VALUE except, struct timeval *tp, rb_fd
if (!pending && n == 0) return Qnil; /* returns nil on timeout */
res = rb_ary_new2(3);
- rb_ary_push(res, rp?rb_ary_new():rb_ary_new2(0));
- rb_ary_push(res, wp?rb_ary_new():rb_ary_new2(0));
- rb_ary_push(res, ep?rb_ary_new():rb_ary_new2(0));
+ rb_ary_push(res, rp ? rb_ary_new_capa(RARRAY_LEN(read)) : rb_ary_new());
+ rb_ary_push(res, wp ? rb_ary_new_capa(RARRAY_LEN(write)) : rb_ary_new());
+ rb_ary_push(res, ep ? rb_ary_new_capa(RARRAY_LEN(except)) : rb_ary_new());
if (rp) {
list = RARRAY_AREF(res, 0);
@@ -10951,7 +10959,7 @@ advice_arg_check(VALUE advice)
* advise(advice, offset = 0, len = 0) -> nil
*
* Invokes Posix system call
- * {posix_fadvise(2)}[https://linux.die.net/man/2/posix_fadvise],
+ * {posix_fadvise(2)}[https://man7.org/linux/man-pages/man2/posix_fadvise.2.html],
* which announces an intention to access data from the current file
* in a particular manner.
*
@@ -11017,7 +11025,7 @@ is_pos_inf(VALUE x)
* call-seq:
* IO.select(read_ios, write_ios = [], error_ios = [], timeout = nil) -> array or nil
*
- * Invokes system call {select(2)}[https://linux.die.net/man/2/select],
+ * Invokes system call {select(2)}[https://man7.org/linux/man-pages/man2/select.2.html],
* which monitors multiple file descriptors,
* waiting until one or more of the file descriptors
* becomes ready for some class of I/O operation.
@@ -11104,7 +11112,7 @@ is_pos_inf(VALUE x)
* Finally, Linux kernel developers don't guarantee that
* readability of select(2) means readability of following read(2) even
* for a single process;
- * see {select(2)}[https://linux.die.net/man/2/select]
+ * see {select(2)}[https://man7.org/linux/man-pages/man2/select.2.html]
*
* Invoking \IO.select before IO#readpartial works well as usual.
* However it is not the best way to use \IO.select.
@@ -11498,7 +11506,7 @@ rb_ioctl(VALUE io, VALUE req, VALUE arg)
* call-seq:
* ioctl(integer_cmd, argument) -> integer
*
- * Invokes Posix system call {ioctl(2)}[https://linux.die.net/man/2/ioctl],
+ * Invokes Posix system call {ioctl(2)}[https://man7.org/linux/man-pages/man2/ioctl.2.html],
* which issues a low-level command to an I/O device.
*
* Issues a low-level command to an I/O device.
@@ -11587,7 +11595,7 @@ rb_fcntl(VALUE io, VALUE req, VALUE arg)
* call-seq:
* fcntl(integer_cmd, argument) -> integer
*
- * Invokes Posix system call {fcntl(2)}[https://linux.die.net/man/2/fcntl],
+ * Invokes Posix system call {fcntl(2)}[https://man7.org/linux/man-pages/man2/fcntl.2.html],
* which provides a mechanism for issuing low-level commands to control or query
* a file-oriented I/O stream. Arguments and results are platform
* dependent.
@@ -11617,7 +11625,7 @@ rb_io_fcntl(int argc, VALUE *argv, VALUE io)
* call-seq:
* syscall(integer_callno, *arguments) -> integer
*
- * Invokes Posix system call {syscall(2)}[https://linux.die.net/man/2/syscall],
+ * Invokes Posix system call {syscall(2)}[https://man7.org/linux/man-pages/man2/syscall.2.html],
* which calls a specified function.
*
* Calls the operating system function identified by +integer_callno+;
@@ -12062,10 +12070,6 @@ io_s_foreach(VALUE v)
*
* Calls the block with each successive line read from the stream.
*
- * When called from class \IO (but not subclasses of \IO),
- * 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.
*
* With only argument +path+ given, parses lines from the file at the given +path+,
@@ -12165,10 +12169,6 @@ io_s_readlines(VALUE v)
*
* Returns an array of all lines read from the stream.
*
- * When called from class \IO (but not subclasses of \IO),
- * 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.
*
* With only argument +path+ given, parses lines from the file at the given +path+,
@@ -12254,17 +12254,17 @@ seek_before_access(VALUE argp)
* Opens the stream, reads and returns some or all of its content,
* and closes the stream; returns +nil+ if no bytes were read.
*
- * When called from class \IO (but not subclasses of \IO),
- * 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.
*
* With only argument +path+ given, reads in text mode and returns the entire content
* of the file at the given path:
*
- * IO.read('t.txt')
- * # => "First line\nSecond line\n\nThird line\nFourth line\n"
+ * File.read('t.txt')
+ * # => "First line\nSecond line\n\nFourth line\nFifth line\n"
+ * File.read('t.ja')
+ * # => "ã“ã‚“ã«ã¡ã¯"
+ * File.read('t.dat')
+ * # => "\xFE\xFF\x99\x90\x99\x91\x99\x92\x99\x93\x99\x94"
*
* On Windows, text mode can terminate reading and leave bytes in the file
* unread when encountering certain special bytes. Consider using
@@ -12272,15 +12272,36 @@ seek_before_access(VALUE argp)
*
* With argument +length+, returns +length+ bytes if available:
*
- * IO.read('t.txt', 7) # => "First l"
- * IO.read('t.txt', 700)
+ * File.read('t.txt', 7)
+ * # => "First l"
+ * File.read('t.ja', 7)
+ * # => "\xE3\x81\x93\xE3\x82\x93\xE3"
+ * File.read('t.dat', 7)
+ * # => "\xFE\xFF\x99\x90\x99\x91\x99"
+ *
+ * Returns all bytes if +length+ is larger than the files size:
+ *
+ * File.read('t.txt', 700)
* # => "First line\r\nSecond line\r\n\r\nFourth line\r\nFifth line\r\n"
+ * File.read('t.ja', 700)
+ * # => "\xE3\x81\x93\xE3\x82\x93\xE3\x81\xAB\xE3\x81\xA1\xE3\x81\xAF"
+ * File.read('t.dat', 700)
+ * # => "\xFE\xFF\x99\x90\x99\x91\x99\x92\x99\x93\x99\x94"
*
* With arguments +length+ and +offset+, returns +length+ bytes
* if available, beginning at the given +offset+:
*
- * IO.read('t.txt', 10, 2) # => "rst line\nS"
- * IO.read('t.txt', 10, 200) # => nil
+ * File.read('t.txt', 10, 2)
+ * # => "rst line\r\n"
+ * File.read('t.ja', 10, 2)
+ * # => "\x93\xE3\x82\x93\xE3\x81\xAB\xE3\x81\xA1"
+ * File.read('t.dat', 10, 2)
+ * # => "\x99\x90\x99\x91\x99\x92\x99\x93\x99\x94"
+ *
+ * Returns +nil+ if +offset+ is past the end of the stream:
+ *
+ * File.read('t.txt', 10, 200)
+ * # => nil
*
* Optional keyword arguments +opts+ specify:
*
@@ -12325,10 +12346,6 @@ rb_io_s_read(int argc, VALUE *argv, VALUE io)
* Behaves like IO.read, except that the stream is opened in binary mode
* with ASCII-8BIT encoding.
*
- * When called from class \IO (but not subclasses of \IO),
- * this method has potential security vulnerabilities if called with untrusted input;
- * see {Command Injection}[rdoc-ref:command_injection.rdoc].
- *
*/
static VALUE
@@ -12424,40 +12441,50 @@ io_s_write(int argc, VALUE *argv, VALUE klass, int binary)
/*
* call-seq:
- * IO.write(path, data, offset = 0, **opts) -> integer
+ * IO.write(path, data, offset = 0, **opts) -> nonnegative_integer
*
* Opens the stream, writes the given +data+ to it,
* and closes the stream; returns the number of bytes written.
*
- * When called from class \IO (but not subclasses of \IO),
- * 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.
*
- * With only argument +path+ given, writes the given +data+ to the file at that path:
+ * With only arguments +path+ and +data+ given,
+ * writes the given data to the file at that path:
+ *
+ * path = 't.tmp'
+ * File.write(path, "First line\nSecond line\n\nFourth line\nFifth line\n") # => 47
+ * File.write(path, 'ã“ã‚“ã«ã¡ã¯') # => 15
+ * File.write(path, "\xFE\xFF\x99\x90\x99\x91\x99\x92\x99\x93\x99\x94") # => 12
+ *
+ * When +offset+ is zero (the default), the entire file content is overwritten:
*
- * IO.write('t.tmp', 'abc') # => 3
- * File.read('t.tmp') # => "abc"
+ * File.read(path) # => "\xFE\xFF\x99\x90\x99\x91\x99\x92\x99\x93\x99\x94"
+ * File.write(path, 'foo')
+ * File.read(path) # => "foo"
*
- * If +offset+ is zero (the default), the file is overwritten:
+ * When +offset+ in within the file content, the file content is partly overwritten,
+ * beginning at byte +offset+:
*
- * IO.write('t.tmp', 'A') # => 1
- * File.read('t.tmp') # => "A"
+ * File.write(path, "First line\nSecond line\n\nFourth line\nFifth line\n")
+ * File.write(path, 'LINE', 6)
+ * File.read(path) # => "First LINE\nSecond line\n\nFourth line\nFifth line\n"
*
- * If +offset+ in within the file content, the file is partly overwritten:
+ * When the file contains multi-byte characters,
+ * the effect of writing may disturb some characters:
*
- * IO.write('t.tmp', 'abcdef') # => 3
- * File.read('t.tmp') # => "abcdef"
- * # Offset within content.
- * IO.write('t.tmp', '012', 2) # => 3
- * File.read('t.tmp') # => "ab012f"
+ * File.write(path, "ã“ã‚“ã«ã¡ã¯")
+ * File.write(path, 'FOO', 3) # Replace one 3-byte character.
+ * File.read(path) # => "ã“FOOã«ã¡ã¯"
+ * File.write(path, 'BAR', 7) # Replace bytes in two different 3-byte characters.
+ * File.read(path) # => "ã“FOO\xE3BAR\x81\xA1ã¯"
*
* If +offset+ is outside the file content,
* the file is padded with null characters <tt>"\u0000"</tt>:
*
- * IO.write('t.tmp', 'xyz', 10) # => 3
- * File.read('t.tmp') # => "ab012f\u0000\u0000\u0000\u0000xyz"
+ * File.write(path, "First line\nSecond line\n\nFourth line\nFifth line\n")
+ * File.write(path, 'FOO', 55)
+ * File.read(path)
+ * # => "First line\nSecond line\n\nFourth line\nFifth line\n\u0000\u0000\u0000FOO"
*
* Optional keyword arguments +opts+ specify:
*
@@ -12474,15 +12501,11 @@ rb_io_s_write(int argc, VALUE *argv, VALUE io)
/*
* call-seq:
- * IO.binwrite(path, string, offset = 0) -> integer
+ * IO.binwrite(path, string, offset = 0, **opts) -> integer
*
* Behaves like IO.write, except that the stream is opened in binary mode
* with ASCII-8BIT encoding.
*
- * When called from class \IO (but not subclasses of \IO),
- * this method has potential security vulnerabilities if called with untrusted input;
- * see {Command Injection}[rdoc-ref:command_injection.rdoc].
- *
*/
static VALUE
@@ -13701,6 +13724,7 @@ argf_set_encoding(int argc, VALUE *argv, VALUE argf)
rb_io_set_encoding(argc, argv, ARGF.current_file);
GetOpenFile(ARGF.current_file, fptr);
ARGF.encs = fptr->encs;
+ RB_OBJ_WRITTEN(argf, Qundef, ARGF.encs.ecopts);
return argf;
}
@@ -14633,7 +14657,7 @@ argf_inplace_mode_set(VALUE argf, VALUE val)
ARGF.inplace = Qnil;
}
else {
- ARGF.inplace = rb_str_new_frozen(val);
+ ARGF_SET(inplace, rb_str_new_frozen(val));
}
return argf;
}
@@ -14647,7 +14671,7 @@ opt_i_set(VALUE val, ID id, VALUE *var)
void
ruby_set_inplace_mode(const char *suffix)
{
- ARGF.inplace = !suffix ? Qfalse : !*suffix ? Qnil : rb_str_new(suffix, strlen(suffix));
+ ARGF_SET(inplace, !suffix ? Qfalse : !*suffix ? Qnil : rb_str_new(suffix, strlen(suffix)));
}
/*
@@ -14981,9 +15005,7 @@ set_LAST_READ_LINE(VALUE val, ID _x, VALUE *_y)
* ["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]):
+ * When no character <tt>'-'</tt> is given, stream <tt>$stdin</tt> is ignored.
*
* - Command and output:
*
@@ -15098,7 +15120,7 @@ set_LAST_READ_LINE(VALUE val, ID _x, VALUE *_y)
* 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].
+ * see {Read/Write Mode}[rdoc-ref:File@ReadWrite+Mode].
* - A data mode, which may be text-only or binary;
* see {Data Mode}[rdoc-ref:File@Data+Mode].
* - Internal and external encodings;
@@ -15142,7 +15164,7 @@ set_LAST_READ_LINE(VALUE val, ID _x, VALUE *_y)
* - +:binmode+: If a truthy value, specifies the mode as binary, text-only otherwise.
* - +:autoclose+: If a truthy value, specifies that the +fd+ will close
* when the stream closes; otherwise it remains open.
- * - +:path:+ If a string value is provided, it is used in #inspect and is available as
+ * - +:path+: If a string value is provided, it is used in #inspect and is available as
* #path method.
*
* Also available are the options offered in String#encode,
@@ -15339,11 +15361,13 @@ set_LAST_READ_LINE(VALUE val, ID _x, VALUE *_y)
* File.open('t.txt') {|f| f.gets(11) } # => "First line\n"
* File.open('t.txt') {|f| f.gets(12) } # => "First line\n"
*
- * # Text with 2-byte characters, which will not be split.
- * File.open('t.rus') {|f| f.gets(1).size } # => 1
- * File.open('t.rus') {|f| f.gets(2).size } # => 1
- * File.open('t.rus') {|f| f.gets(3).size } # => 2
- * File.open('t.rus') {|f| f.gets(4).size } # => 2
+ * # Text with 3-byte characters, which will not be split.
+ * File.read('t.ja') # => "ã“ã‚“ã«ã¡ã¯"
+ * File.open('t.ja') {|f| f.gets(1).size } # => 1
+ * File.open('t.ja') {|f| f.gets(2).size } # => 1
+ * File.open('t.ja') {|f| f.gets(3).size } # => 1
+ * File.open('t.ja') {|f| f.gets(4).size } # => 2
+ * File.open('t.ja') {|f| f.gets(5).size } # => 2
*
* ===== Line Separator and Line Limit
*
@@ -15494,8 +15518,8 @@ set_LAST_READ_LINE(VALUE val, ID _x, VALUE *_y)
*
* First, what's elsewhere. Class \IO:
*
- * - Inherits from {class Object}[rdoc-ref:Object@What-27s+Here].
- * - Includes {module Enumerable}[rdoc-ref:Enumerable@What-27s+Here],
+ * - Inherits from {class Object}[rdoc-ref:Object@Whats+Here].
+ * - Includes {module Enumerable}[rdoc-ref:Enumerable@Whats+Here],
* which provides dozens of additional methods.
*
* Here, class \IO provides methods that are useful for:
@@ -15759,7 +15783,7 @@ Init_IO(void)
rb_define_method(rb_cIO, "initialize", rb_io_initialize, -1);
rb_output_fs = Qnil;
- rb_define_hooked_variable("$,", &rb_output_fs, 0, deprecated_str_setter);
+ rb_define_hooked_variable("$,", &rb_output_fs, 0, rb_deprecated_str_setter);
rb_default_rs = rb_fstring_lit("\n"); /* avoid modifying RS_default */
rb_vm_register_global_object(rb_default_rs);
@@ -15769,10 +15793,11 @@ Init_IO(void)
rb_gvar_ractor_local("$/"); // not local but ractor safe
rb_define_hooked_variable("$-0", &rb_rs, 0, deprecated_rs_setter);
rb_gvar_ractor_local("$-0"); // not local but ractor safe
- rb_define_hooked_variable("$\\", &rb_output_rs, 0, deprecated_str_setter);
+ rb_define_hooked_variable("$\\", &rb_output_rs, 0, rb_deprecated_str_setter);
rb_define_virtual_variable("$_", get_LAST_READ_LINE, set_LAST_READ_LINE);
rb_gvar_ractor_local("$_");
+ rb_gvar_box_dynamic("$_");
rb_define_method(rb_cIO, "initialize_copy", rb_io_init_copy, 1);
rb_define_method(rb_cIO, "reopen", rb_io_reopen, -1);
@@ -15994,7 +16019,7 @@ Init_IO(void)
rb_define_hooked_variable("$.", &argf, argf_lineno_getter, argf_lineno_setter);
rb_define_hooked_variable("$FILENAME", &argf, argf_filename_getter, rb_gvar_readonly_setter);
- ARGF.filename = rb_str_new2("-");
+ ARGF_SET(filename, rb_str_new2("-"));
rb_define_hooked_variable("$-i", &argf, opt_i_get, opt_i_set);
rb_gvar_ractor_local("$-i");
diff --git a/io_buffer.c b/io_buffer.c
index 96f13c364a..faa5304248 100644
--- a/io_buffer.c
+++ b/io_buffer.c
@@ -39,6 +39,7 @@ size_t RUBY_IO_BUFFER_DEFAULT_SIZE;
enum {
RB_IO_BUFFER_HEXDUMP_DEFAULT_WIDTH = 16,
+ RB_IO_BUFFER_HEXDUMP_MAXIMUM_WIDTH = 1024,
RB_IO_BUFFER_INSPECT_HEXDUMP_MAXIMUM_SIZE = 256,
RB_IO_BUFFER_INSPECT_HEXDUMP_WIDTH = 16,
@@ -273,7 +274,7 @@ io_buffer_free(struct rb_io_buffer *buffer)
}
static void
-rb_io_buffer_type_mark_and_move(void *_buffer)
+rb_io_buffer_type_mark(void *_buffer)
{
struct rb_io_buffer *buffer = _buffer;
if (buffer->source != Qnil) {
@@ -282,7 +283,21 @@ rb_io_buffer_type_mark_and_move(void *_buffer)
// which can be otherwise moved by GC compaction.
rb_gc_mark(buffer->source);
} else {
- rb_gc_mark_and_move(&buffer->source);
+ rb_gc_mark_movable(buffer->source);
+ }
+ }
+}
+
+static void
+rb_io_buffer_type_compact(void *_buffer)
+{
+ struct rb_io_buffer *buffer = _buffer;
+ if (buffer->source != Qnil) {
+ if (RB_TYPE_P(buffer->source, T_STRING)) {
+ // The `source` String has to be pinned, because the `base` may point to the embedded String content,
+ // which can be otherwise moved by GC compaction.
+ } else {
+ buffer->source = rb_gc_location(buffer->source);
}
}
}
@@ -311,10 +326,10 @@ rb_io_buffer_type_size(const void *_buffer)
static const rb_data_type_t rb_io_buffer_type = {
.wrap_struct_name = "IO::Buffer",
.function = {
- .dmark = rb_io_buffer_type_mark_and_move,
+ .dmark = rb_io_buffer_type_mark,
.dfree = rb_io_buffer_type_free,
.dsize = rb_io_buffer_type_size,
- .dcompact = rb_io_buffer_type_mark_and_move,
+ .dcompact = rb_io_buffer_type_compact,
},
.data = NULL,
.flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_EMBEDDABLE,
@@ -370,7 +385,7 @@ io_buffer_extract_size(VALUE argument)
}
// Extract a width argument, which must be a non-negative integer, and must be
-// at least the given minimum.
+// at least the given minimum and at most RB_IO_BUFFER_HEXDUMP_MAXIMUM_WIDTH.
static inline size_t
io_buffer_extract_width(VALUE argument, size_t minimum)
{
@@ -384,6 +399,10 @@ io_buffer_extract_width(VALUE argument, size_t minimum)
rb_raise(rb_eArgError, "Width must be at least %" PRIuSIZE "!", minimum);
}
+ if (width > RB_IO_BUFFER_HEXDUMP_MAXIMUM_WIDTH) {
+ rb_raise(rb_eArgError, "Width must be at most %" PRIuSIZE "!", (size_t)RB_IO_BUFFER_HEXDUMP_MAXIMUM_WIDTH);
+ }
+
return width;
}
@@ -465,6 +484,8 @@ io_buffer_extract_offset_length(VALUE self, int argc, VALUE argv[], size_t *offs
VALUE
rb_io_buffer_type_allocate(VALUE self)
{
+ io_buffer_experimental();
+
struct rb_io_buffer *buffer = NULL;
VALUE instance = TypedData_Make_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, buffer);
@@ -555,7 +576,7 @@ io_buffer_for_yield_instance_ensure(VALUE _arguments)
* buffer.get_string(0, 1)
* # => "t"
* string
- * # => "best"
+ * # => "test"
*
* buffer.resize(100)
* # in `resize': Cannot resize external buffer! (IO::Buffer::AccessError)
@@ -635,8 +656,6 @@ rb_io_buffer_new(void *base, size_t size, enum rb_io_buffer_flags flags)
VALUE
rb_io_buffer_map(VALUE io, size_t size, rb_off_t offset, enum rb_io_buffer_flags flags)
{
- io_buffer_experimental();
-
VALUE instance = rb_io_buffer_type_allocate(rb_cIOBuffer);
struct rb_io_buffer *buffer = NULL;
@@ -653,18 +672,25 @@ rb_io_buffer_map(VALUE io, size_t size, rb_off_t offset, enum rb_io_buffer_flags
* call-seq: IO::Buffer.map(file, [size, [offset, [flags]]]) -> io_buffer
*
* Create an IO::Buffer for reading from +file+ by memory-mapping the file.
- * +file_io+ should be a +File+ instance, opened for reading.
+ * +file+ should be a +File+ instance, opened for reading or reading and writing.
*
* Optional +size+ and +offset+ of mapping can be specified.
+ * Trying to map an empty file or specify +size+ of 0 will raise an error.
+ * Valid values for +offset+ are system-dependent.
*
- * By default, the buffer would be immutable (read only); to create a writable
- * mapping, you need to open a file in read-write mode, and explicitly pass
- * +flags+ argument without IO::Buffer::IMMUTABLE.
+ * By default, the buffer is writable and expects the file to be writable.
+ * It is also shared, so several processes can use the same mapping.
+ *
+ * You can pass IO::Buffer::READONLY in +flags+ argument to make a read-only buffer;
+ * this allows to work with files opened only for reading.
+ * Specifying IO::Buffer::PRIVATE in +flags+ creates a private mapping,
+ * which will not impact other processes or the underlying file.
+ * It also allows updating a buffer created from a read-only file.
*
* File.write('test.txt', 'test')
*
* buffer = IO::Buffer.map(File.open('test.txt'), nil, 0, IO::Buffer::READONLY)
- * # => #<IO::Buffer 0x00000001014a0000+4 MAPPED READONLY>
+ * # => #<IO::Buffer 0x00000001014a0000+4 EXTERNAL MAPPED FILE SHARED READONLY>
*
* buffer.readonly? # => true
*
@@ -672,7 +698,7 @@ rb_io_buffer_map(VALUE io, size_t size, rb_off_t offset, enum rb_io_buffer_flags
* # => "test"
*
* buffer.set_string('b', 0)
- * # `set_string': Buffer is not writable! (IO::Buffer::AccessError)
+ * # 'IO::Buffer#set_string': Buffer is not writable! (IO::Buffer::AccessError)
*
* # create read/write mapping: length 4 bytes, offset 0, flags 0
* buffer = IO::Buffer.map(File.open('test.txt', 'r+'), 4, 0)
@@ -694,31 +720,48 @@ io_buffer_map(int argc, VALUE *argv, VALUE klass)
// We might like to handle a string path?
VALUE io = argv[0];
+ rb_off_t file_size = rb_file_size(io);
+ // Compiler can confirm that we handled file_size <= 0 case:
+ if (UNLIKELY(file_size <= 0)) {
+ rb_raise(rb_eArgError, "Invalid negative or zero file size!");
+ }
+ // Here, we assume that file_size is positive:
+ else if (UNLIKELY((uintmax_t)file_size > SIZE_MAX)) {
+ rb_raise(rb_eArgError, "File larger than address space!");
+ }
+
size_t size;
if (argc >= 2 && !RB_NIL_P(argv[1])) {
size = io_buffer_extract_size(argv[1]);
- }
- else {
- rb_off_t file_size = rb_file_size(io);
-
- // Compiler can confirm that we handled file_size < 0 case:
- if (file_size < 0) {
- rb_raise(rb_eArgError, "Invalid negative file size!");
- }
- // Here, we assume that file_size is positive:
- else if ((uintmax_t)file_size > SIZE_MAX) {
- rb_raise(rb_eArgError, "File larger than address space!");
+ if (UNLIKELY(size == 0)) {
+ rb_raise(rb_eArgError, "Size can't be zero!");
}
- else {
- // This conversion should be safe:
- size = (size_t)file_size;
+ if (UNLIKELY(size > (size_t)file_size)) {
+ rb_raise(rb_eArgError, "Size can't be larger than file size!");
}
}
+ else {
+ // This conversion should be safe:
+ size = (size_t)file_size;
+ }
// This is the file offset, not the buffer offset:
rb_off_t offset = 0;
if (argc >= 3) {
offset = NUM2OFFT(argv[2]);
+ if (UNLIKELY(offset < 0)) {
+ rb_raise(rb_eArgError, "Offset can't be negative!");
+ }
+ if (UNLIKELY(offset >= file_size)) {
+ rb_raise(rb_eArgError, "Offset too large!");
+ }
+ if (RB_NIL_P(argv[1])) {
+ // Decrease size if it's set from the actual file size:
+ size = (size_t)(file_size - offset);
+ }
+ else if (UNLIKELY((size_t)(file_size - offset) < size)) {
+ rb_raise(rb_eArgError, "Offset too large!");
+ }
}
enum rb_io_buffer_flags flags = 0;
@@ -767,8 +810,6 @@ io_flags_for_size(size_t size)
VALUE
rb_io_buffer_initialize(int argc, VALUE *argv, VALUE self)
{
- io_buffer_experimental();
-
rb_check_arity(argc, 0, 2);
struct rb_io_buffer *buffer = NULL;
@@ -1388,6 +1429,17 @@ rb_io_buffer_try_unlock(VALUE self)
return 0;
}
+static VALUE
+rb_io_buffer_locked_ensure(VALUE self)
+{
+ struct rb_io_buffer *buffer = NULL;
+ TypedData_Get_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, buffer);
+
+ buffer->flags &= ~RB_IO_BUFFER_LOCKED;
+
+ return Qnil;
+}
+
/*
* call-seq: locked { ... }
*
@@ -1430,11 +1482,7 @@ rb_io_buffer_locked(VALUE self)
buffer->flags |= RB_IO_BUFFER_LOCKED;
- VALUE result = rb_yield(self);
-
- buffer->flags &= ~RB_IO_BUFFER_LOCKED;
-
- return result;
+ return rb_ensure(rb_yield, self, rb_io_buffer_locked_ensure, self);
}
/*
@@ -1445,7 +1493,7 @@ rb_io_buffer_locked(VALUE self)
* * for a buffer created from scratch: free memory.
* * for a buffer created from string: undo the association.
*
- * After the buffer is freed, no further operations can't be performed on it.
+ * After the buffer is freed, no further operations can be performed on it.
*
* You can resize a freed buffer to re-allocate it.
*
@@ -1488,13 +1536,19 @@ VALUE rb_io_buffer_free_locked(VALUE self)
return self;
}
+static bool
+size_sum_is_bigger_than(size_t a, size_t b, size_t x)
+{
+ struct rbimpl_size_overflow_tag size = rbimpl_size_add_overflow(a, b);
+ return size.overflowed || size.result > x;
+}
+
// Validate that access to the buffer is within bounds, assuming you want to
// access length bytes from the specified offset.
static inline void
io_buffer_validate_range(struct rb_io_buffer *buffer, size_t offset, size_t length)
{
- // We assume here that offset + length won't overflow:
- if (offset + length > buffer->size) {
+ if (size_sum_is_bigger_than(offset, length, buffer->size)) {
rb_raise(rb_eArgError, "Specified offset+length is bigger than the buffer size!");
}
}
@@ -1804,9 +1858,9 @@ rb_io_buffer_compare(VALUE self, VALUE other)
}
static void
-io_buffer_validate_type(size_t size, size_t offset)
+io_buffer_validate_type(size_t size, size_t offset, size_t extend)
{
- if (offset > size) {
+ if (size_sum_is_bigger_than(offset, extend, size)) {
rb_raise(rb_eArgError, "Type extends beyond end of buffer! (offset=%"PRIdSIZE" > size=%"PRIdSIZE")", offset, size);
}
}
@@ -1826,6 +1880,9 @@ io_buffer_validate_type(size_t size, size_t offset)
// :u64, :U64 | unsigned 64-bit integer.
// :s64, :S64 | signed 64-bit integer.
//
+// :u128, :U128 | unsigned 128-bit integer.
+// :s128, :S128 | signed 128-bit integer.
+//
// :f32, :F32 | 32-bit floating point number.
// :f64, :F64 | 64-bit floating point number.
@@ -1857,13 +1914,53 @@ ruby_swapf64(double value)
return swap.value;
}
+// Structures and conversion functions are now in numeric.h/numeric.c
+// Unified swap function for 128-bit integers (works with both signed and unsigned)
+// Since both rb_uint128_t and rb_int128_t have the same memory layout,
+// we can use a union to make the swap function work with both types
+static inline rb_uint128_t
+ruby_swap128_uint(rb_uint128_t x)
+{
+ rb_uint128_t result;
+#ifdef HAVE_UINT128_T
+#if __has_builtin(__builtin_bswap128)
+ result.value = __builtin_bswap128(x.value);
+#else
+ // Manual byte swap for 128-bit integers
+ uint64_t low = (uint64_t)x.value;
+ uint64_t high = (uint64_t)(x.value >> 64);
+ low = ruby_swap64(low);
+ high = ruby_swap64(high);
+ result.value = ((uint128_t)low << 64) | high;
+#endif
+#else
+ // Fallback swap function using two 64-bit integers
+ // For big-endian data on little-endian host (or vice versa):
+ // 1. Swap bytes within each 64-bit part
+ // 2. Swap the order of the parts (since big-endian stores high first, little-endian stores low first)
+ result.parts.low = ruby_swap64(x.parts.high);
+ result.parts.high = ruby_swap64(x.parts.low);
+#endif
+ return result;
+}
+
+static inline rb_int128_t
+ruby_swap128_int(rb_int128_t x)
+{
+ union uint128_int128_conversion conversion = {
+ .int128 = x
+ };
+ conversion.uint128 = ruby_swap128_uint(conversion.uint128);
+ return conversion.int128;
+}
+
#define IO_BUFFER_DECLARE_TYPE(name, type, endian, wrap, unwrap, swap) \
static ID RB_IO_BUFFER_DATA_TYPE_##name; \
\
static VALUE \
io_buffer_read_##name(const void* base, size_t size, size_t *offset) \
{ \
- io_buffer_validate_type(size, *offset + sizeof(type)); \
+ io_buffer_validate_type(size, *offset, sizeof(type)); \
type value; \
memcpy(&value, (char*)base + *offset, sizeof(type)); \
if (endian != RB_IO_BUFFER_HOST_ENDIAN) value = swap(value); \
@@ -1874,7 +1971,7 @@ io_buffer_read_##name(const void* base, size_t size, size_t *offset) \
static void \
io_buffer_write_##name(const void* base, size_t size, size_t *offset, VALUE _value) \
{ \
- io_buffer_validate_type(size, *offset + sizeof(type)); \
+ io_buffer_validate_type(size, *offset, sizeof(type)); \
type value = unwrap(_value); \
if (endian != RB_IO_BUFFER_HOST_ENDIAN) value = swap(value); \
memcpy((char*)base + *offset, &value, sizeof(type)); \
@@ -1903,6 +2000,11 @@ IO_BUFFER_DECLARE_TYPE(U64, uint64_t, RB_IO_BUFFER_BIG_ENDIAN, RB_ULL2NUM, RB_NU
IO_BUFFER_DECLARE_TYPE(s64, int64_t, RB_IO_BUFFER_LITTLE_ENDIAN, RB_LL2NUM, RB_NUM2LL, ruby_swap64)
IO_BUFFER_DECLARE_TYPE(S64, int64_t, RB_IO_BUFFER_BIG_ENDIAN, RB_LL2NUM, RB_NUM2LL, ruby_swap64)
+IO_BUFFER_DECLARE_TYPE(u128, rb_uint128_t, RB_IO_BUFFER_LITTLE_ENDIAN, rb_uint128_to_numeric, rb_numeric_to_uint128, ruby_swap128_uint)
+IO_BUFFER_DECLARE_TYPE(U128, rb_uint128_t, RB_IO_BUFFER_BIG_ENDIAN, rb_uint128_to_numeric, rb_numeric_to_uint128, ruby_swap128_uint)
+IO_BUFFER_DECLARE_TYPE(s128, rb_int128_t, RB_IO_BUFFER_LITTLE_ENDIAN, rb_int128_to_numeric, rb_numeric_to_int128, ruby_swap128_int)
+IO_BUFFER_DECLARE_TYPE(S128, rb_int128_t, RB_IO_BUFFER_BIG_ENDIAN, rb_int128_to_numeric, rb_numeric_to_int128, ruby_swap128_int)
+
IO_BUFFER_DECLARE_TYPE(f32, float, RB_IO_BUFFER_LITTLE_ENDIAN, DBL2NUM, NUM2DBL, ruby_swapf32)
IO_BUFFER_DECLARE_TYPE(F32, float, RB_IO_BUFFER_BIG_ENDIAN, DBL2NUM, NUM2DBL, ruby_swapf32)
IO_BUFFER_DECLARE_TYPE(f64, double, RB_IO_BUFFER_LITTLE_ENDIAN, DBL2NUM, NUM2DBL, ruby_swapf64)
@@ -1927,6 +2029,10 @@ io_buffer_buffer_type_size(ID buffer_type)
IO_BUFFER_DATA_TYPE_SIZE(U64)
IO_BUFFER_DATA_TYPE_SIZE(s64)
IO_BUFFER_DATA_TYPE_SIZE(S64)
+ IO_BUFFER_DATA_TYPE_SIZE(u128)
+ IO_BUFFER_DATA_TYPE_SIZE(U128)
+ IO_BUFFER_DATA_TYPE_SIZE(s128)
+ IO_BUFFER_DATA_TYPE_SIZE(S128)
IO_BUFFER_DATA_TYPE_SIZE(f32)
IO_BUFFER_DATA_TYPE_SIZE(F32)
IO_BUFFER_DATA_TYPE_SIZE(f64)
@@ -1983,6 +2089,11 @@ rb_io_buffer_get_value(const void* base, size_t size, ID buffer_type, size_t *of
IO_BUFFER_GET_VALUE(s64)
IO_BUFFER_GET_VALUE(S64)
+ IO_BUFFER_GET_VALUE(u128)
+ IO_BUFFER_GET_VALUE(U128)
+ IO_BUFFER_GET_VALUE(s128)
+ IO_BUFFER_GET_VALUE(S128)
+
IO_BUFFER_GET_VALUE(f32)
IO_BUFFER_GET_VALUE(F32)
IO_BUFFER_GET_VALUE(f64)
@@ -2012,6 +2123,10 @@ rb_io_buffer_get_value(const void* base, size_t size, ID buffer_type, size_t *of
* * +:U64+: unsigned integer, 8 bytes, big-endian
* * +:s64+: signed integer, 8 bytes, little-endian
* * +:S64+: signed integer, 8 bytes, big-endian
+ * * +:u128+: unsigned integer, 16 bytes, little-endian
+ * * +:U128+: unsigned integer, 16 bytes, big-endian
+ * * +:s128+: signed integer, 16 bytes, little-endian
+ * * +:S128+: signed integer, 16 bytes, big-endian
* * +:f32+: float, 4 bytes, little-endian
* * +:F32+: float, 4 bytes, big-endian
* * +:f64+: double, 8 bytes, little-endian
@@ -2193,7 +2308,7 @@ io_buffer_values(int argc, VALUE *argv, VALUE self)
/*
* call-seq:
- * each_byte([offset, [count]]) {|offset, byte| ...} -> self
+ * each_byte([offset, [count]]) {|byte| ...} -> self
* each_byte([offset, [count]]) -> enumerator
*
* Iterates over the buffer, yielding each byte starting from +offset+.
@@ -2217,7 +2332,11 @@ io_buffer_each_byte(int argc, VALUE *argv, VALUE self)
rb_io_buffer_get_bytes_for_reading(self, &base, &size);
size_t offset, count;
- io_buffer_extract_offset_count(RB_IO_BUFFER_DATA_TYPE_U8, size, argc-1, argv+1, &offset, &count);
+ io_buffer_extract_offset_count(RB_IO_BUFFER_DATA_TYPE_U8, size, argc, argv, &offset, &count);
+
+ if (size_sum_is_bigger_than(offset, count, size)) {
+ rb_raise(rb_eArgError, "Specified offset+count is bigger than the buffer size!");
+ }
for (size_t i = 0; i < count; i++) {
unsigned char *value = (unsigned char *)base + i + offset;
@@ -2249,6 +2368,11 @@ rb_io_buffer_set_value(const void* base, size_t size, ID buffer_type, size_t *of
IO_BUFFER_SET_VALUE(s64);
IO_BUFFER_SET_VALUE(S64);
+ IO_BUFFER_SET_VALUE(u128);
+ IO_BUFFER_SET_VALUE(U128);
+ IO_BUFFER_SET_VALUE(s128);
+ IO_BUFFER_SET_VALUE(S128);
+
IO_BUFFER_SET_VALUE(f32);
IO_BUFFER_SET_VALUE(F32);
IO_BUFFER_SET_VALUE(f64);
@@ -2379,7 +2503,7 @@ io_buffer_memmove(struct rb_io_buffer *buffer, size_t offset, const void *source
io_buffer_validate_range(buffer, offset, length);
- if (source_offset + length > source_size) {
+ if (size_sum_is_bigger_than(source_offset, length, source_size)) {
rb_raise(rb_eArgError, "The computed source range exceeds the size of the source buffer!");
}
@@ -2465,7 +2589,9 @@ rb_io_buffer_initialize_copy(VALUE self, VALUE source)
io_buffer_initialize(self, buffer, NULL, source_size, io_flags_for_size(source_size), Qnil);
- return io_buffer_copy_from(buffer, source_base, source_size, 0, NULL);
+ VALUE result = io_buffer_copy_from(buffer, source_base, source_size, 0, NULL);
+ RB_GC_GUARD(source);
+ return result;
}
/*
@@ -2550,7 +2676,9 @@ io_buffer_copy(int argc, VALUE *argv, VALUE self)
rb_io_buffer_get_bytes_for_reading(source, &source_base, &source_size);
- return io_buffer_copy_from(buffer, source_base, source_size, argc-1, argv+1);
+ VALUE result = io_buffer_copy_from(buffer, source_base, source_size, argc-1, argv+1);
+ RB_GC_GUARD(source);
+ return result;
}
/*
@@ -2628,7 +2756,9 @@ io_buffer_set_string(int argc, VALUE *argv, VALUE self)
const void *source_base = RSTRING_PTR(string);
size_t source_size = RSTRING_LEN(string);
- return io_buffer_copy_from(buffer, source_base, source_size, argc-1, argv+1);
+ VALUE result = io_buffer_copy_from(buffer, source_base, source_size, argc-1, argv+1);
+ RB_GC_GUARD(string);
+ return result;
}
void
@@ -3248,14 +3378,14 @@ io_buffer_pwrite(int argc, VALUE *argv, VALUE self)
}
static inline void
-io_buffer_check_mask(const struct rb_io_buffer *buffer)
+io_buffer_check_mask_size(size_t size)
{
- if (buffer->size == 0)
+ if (size == 0)
rb_raise(rb_eIOBufferMaskError, "Zero-length mask given!");
}
static void
-memory_and(unsigned char * restrict output, unsigned char * restrict base, size_t size, unsigned char * restrict mask, size_t mask_size)
+memory_and(unsigned char * restrict output, const unsigned char * restrict base, size_t size, const unsigned char * restrict mask, size_t mask_size)
{
for (size_t offset = 0; offset < size; offset += 1) {
output[offset] = base[offset] & mask[offset % mask_size];
@@ -3283,19 +3413,27 @@ io_buffer_and(VALUE self, VALUE mask)
struct rb_io_buffer *mask_buffer = NULL;
TypedData_Get_Struct(mask, struct rb_io_buffer, &rb_io_buffer_type, mask_buffer);
- io_buffer_check_mask(mask_buffer);
+ const void *base;
+ size_t size;
+ io_buffer_get_bytes_for_reading(buffer, &base, &size);
+
+ const void *mask_base;
+ size_t mask_size;
+ io_buffer_get_bytes_for_reading(mask_buffer, &mask_base, &mask_size);
+
+ io_buffer_check_mask_size(mask_size);
- VALUE output = rb_io_buffer_new(NULL, buffer->size, io_flags_for_size(buffer->size));
+ VALUE output = rb_io_buffer_new(NULL, size, io_flags_for_size(size));
struct rb_io_buffer *output_buffer = NULL;
TypedData_Get_Struct(output, struct rb_io_buffer, &rb_io_buffer_type, output_buffer);
- memory_and(output_buffer->base, buffer->base, buffer->size, mask_buffer->base, mask_buffer->size);
+ memory_and(output_buffer->base, base, size, mask_base, mask_size);
return output;
}
static void
-memory_or(unsigned char * restrict output, unsigned char * restrict base, size_t size, unsigned char * restrict mask, size_t mask_size)
+memory_or(unsigned char * restrict output, const unsigned char * restrict base, size_t size, const unsigned char * restrict mask, size_t mask_size)
{
for (size_t offset = 0; offset < size; offset += 1) {
output[offset] = base[offset] | mask[offset % mask_size];
@@ -3323,19 +3461,27 @@ io_buffer_or(VALUE self, VALUE mask)
struct rb_io_buffer *mask_buffer = NULL;
TypedData_Get_Struct(mask, struct rb_io_buffer, &rb_io_buffer_type, mask_buffer);
- io_buffer_check_mask(mask_buffer);
+ const void *base;
+ size_t size;
+ io_buffer_get_bytes_for_reading(buffer, &base, &size);
+
+ const void *mask_base;
+ size_t mask_size;
+ io_buffer_get_bytes_for_reading(mask_buffer, &mask_base, &mask_size);
- VALUE output = rb_io_buffer_new(NULL, buffer->size, io_flags_for_size(buffer->size));
+ io_buffer_check_mask_size(mask_size);
+
+ VALUE output = rb_io_buffer_new(NULL, size, io_flags_for_size(size));
struct rb_io_buffer *output_buffer = NULL;
TypedData_Get_Struct(output, struct rb_io_buffer, &rb_io_buffer_type, output_buffer);
- memory_or(output_buffer->base, buffer->base, buffer->size, mask_buffer->base, mask_buffer->size);
+ memory_or(output_buffer->base, base, size, mask_base, mask_size);
return output;
}
static void
-memory_xor(unsigned char * restrict output, unsigned char * restrict base, size_t size, unsigned char * restrict mask, size_t mask_size)
+memory_xor(unsigned char * restrict output, const unsigned char * restrict base, size_t size, const unsigned char * restrict mask, size_t mask_size)
{
for (size_t offset = 0; offset < size; offset += 1) {
output[offset] = base[offset] ^ mask[offset % mask_size];
@@ -3363,19 +3509,27 @@ io_buffer_xor(VALUE self, VALUE mask)
struct rb_io_buffer *mask_buffer = NULL;
TypedData_Get_Struct(mask, struct rb_io_buffer, &rb_io_buffer_type, mask_buffer);
- io_buffer_check_mask(mask_buffer);
+ const void *base;
+ size_t size;
+ io_buffer_get_bytes_for_reading(buffer, &base, &size);
+
+ const void *mask_base;
+ size_t mask_size;
+ io_buffer_get_bytes_for_reading(mask_buffer, &mask_base, &mask_size);
+
+ io_buffer_check_mask_size(mask_size);
- VALUE output = rb_io_buffer_new(NULL, buffer->size, io_flags_for_size(buffer->size));
+ VALUE output = rb_io_buffer_new(NULL, size, io_flags_for_size(size));
struct rb_io_buffer *output_buffer = NULL;
TypedData_Get_Struct(output, struct rb_io_buffer, &rb_io_buffer_type, output_buffer);
- memory_xor(output_buffer->base, buffer->base, buffer->size, mask_buffer->base, mask_buffer->size);
+ memory_xor(output_buffer->base, base, size, mask_base, mask_size);
return output;
}
static void
-memory_not(unsigned char * restrict output, unsigned char * restrict base, size_t size)
+memory_not(unsigned char * restrict output, const unsigned char * restrict base, size_t size)
{
for (size_t offset = 0; offset < size; offset += 1) {
output[offset] = ~base[offset];
@@ -3386,7 +3540,7 @@ memory_not(unsigned char * restrict output, unsigned char * restrict base, size_
* call-seq:
* ~source -> io_buffer
*
- * Generate a new buffer the same size as the source by applying the binary NOT
+ * Generate a new buffer the same size as the source by applying the unary NOT
* operation to the source.
*
* ~IO::Buffer.for("1234567890")
@@ -3400,11 +3554,15 @@ io_buffer_not(VALUE self)
struct rb_io_buffer *buffer = NULL;
TypedData_Get_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, buffer);
- VALUE output = rb_io_buffer_new(NULL, buffer->size, io_flags_for_size(buffer->size));
+ const void *base;
+ size_t size;
+ io_buffer_get_bytes_for_reading(buffer, &base, &size);
+
+ VALUE output = rb_io_buffer_new(NULL, size, io_flags_for_size(size));
struct rb_io_buffer *output_buffer = NULL;
TypedData_Get_Struct(output, struct rb_io_buffer, &rb_io_buffer_type, output_buffer);
- memory_not(output_buffer->base, buffer->base, buffer->size);
+ memory_not(output_buffer->base, base, size);
return output;
}
@@ -3460,7 +3618,7 @@ io_buffer_and_inplace(VALUE self, VALUE mask)
struct rb_io_buffer *mask_buffer = NULL;
TypedData_Get_Struct(mask, struct rb_io_buffer, &rb_io_buffer_type, mask_buffer);
- io_buffer_check_mask(mask_buffer);
+ io_buffer_check_mask_size(mask_buffer->size);
io_buffer_check_overlaps(buffer, mask_buffer);
void *base;
@@ -3506,7 +3664,7 @@ io_buffer_or_inplace(VALUE self, VALUE mask)
struct rb_io_buffer *mask_buffer = NULL;
TypedData_Get_Struct(mask, struct rb_io_buffer, &rb_io_buffer_type, mask_buffer);
- io_buffer_check_mask(mask_buffer);
+ io_buffer_check_mask_size(mask_buffer->size);
io_buffer_check_overlaps(buffer, mask_buffer);
void *base;
@@ -3552,7 +3710,7 @@ io_buffer_xor_inplace(VALUE self, VALUE mask)
struct rb_io_buffer *mask_buffer = NULL;
TypedData_Get_Struct(mask, struct rb_io_buffer, &rb_io_buffer_type, mask_buffer);
- io_buffer_check_mask(mask_buffer);
+ io_buffer_check_mask_size(mask_buffer->size);
io_buffer_check_overlaps(buffer, mask_buffer);
void *base;
@@ -3576,7 +3734,7 @@ memory_not_inplace(unsigned char * restrict base, size_t size)
* call-seq:
* source.not! -> io_buffer
*
- * Modify the source buffer in place by applying the binary NOT
+ * Modify the source buffer in place by applying the unary NOT
* operation to the source.
*
* source = IO::Buffer.for("1234567890").dup # Make a read/write copy.
@@ -3604,6 +3762,60 @@ io_buffer_not_inplace(VALUE self)
return self;
}
+static size_t
+memory_bit_count(const unsigned char *base, size_t size)
+{
+ size_t count = 0;
+
+ // Process 8 bytes at a time for efficiency:
+ const uint64_t *base64 = (const uint64_t *)base;
+ size_t count64 = size / 8;
+ for (size_t i = 0; i < count64; i += 1) {
+ count += rb_popcount64(base64[i]);
+ }
+
+ // Process any remaining bytes:
+ size_t remaining = size % 8;
+ const unsigned char *tail = base + (count64 * 8);
+ for (size_t i = 0; i < remaining; i += 1) {
+ count += rb_popcount32(tail[i]);
+ }
+
+ return count;
+}
+
+/*
+ * call-seq: bit_count([offset, [length]]) -> integer
+ *
+ * Returns the number of set bits (1s) in the buffer, also known as the
+ * Hamming weight or population count. An optional +offset+ and +length+
+ * can be provided to count bits in a subrange of the buffer.
+ *
+ * IO::Buffer.for("\xFF\x00\x0F").bit_count
+ * # => 12
+ *
+ * IO::Buffer.for("\xFF\x00\x0F").bit_count(1, 2)
+ * # => 4
+ */
+static VALUE
+io_buffer_bit_count(int argc, VALUE *argv, VALUE self)
+{
+ rb_check_arity(argc, 0, 2);
+
+ size_t offset, length;
+ struct rb_io_buffer *buffer = io_buffer_extract_offset_length(self, argc, argv, &offset, &length);
+
+ io_buffer_validate_range(buffer, offset, length);
+
+ const void *base;
+ size_t size;
+ io_buffer_get_bytes_for_reading(buffer, &base, &size);
+
+ size_t count = memory_bit_count((const unsigned char *)base + offset, length);
+
+ return SIZET2NUM(count);
+}
+
/*
* Document-class: IO::Buffer
*
@@ -3670,9 +3882,9 @@ io_buffer_not_inplace(VALUE self)
*
* File.write('test.txt', 'test data')
* # => 9
- * buffer = IO::Buffer.map(File.open('test.txt'))
+ * buffer = IO::Buffer.map(File.open('test.txt'), nil, 0, IO::Buffer::READONLY)
* # =>
- * # #<IO::Buffer 0x00007f3f0768c000+9 MAPPED IMMUTABLE>
+ * # #<IO::Buffer 0x00007f3f0768c000+9 EXTERNAL MAPPED FILE SHARED READONLY>
* # ...
* buffer.get_string(5, 2) # read 2 bytes, starting from offset 5
* # => "da"
@@ -3821,6 +4033,11 @@ Init_IO_Buffer(void)
IO_BUFFER_DEFINE_DATA_TYPE(s64);
IO_BUFFER_DEFINE_DATA_TYPE(S64);
+ IO_BUFFER_DEFINE_DATA_TYPE(u128);
+ IO_BUFFER_DEFINE_DATA_TYPE(U128);
+ IO_BUFFER_DEFINE_DATA_TYPE(s128);
+ IO_BUFFER_DEFINE_DATA_TYPE(S128);
+
IO_BUFFER_DEFINE_DATA_TYPE(f32);
IO_BUFFER_DEFINE_DATA_TYPE(F32);
IO_BUFFER_DEFINE_DATA_TYPE(f64);
@@ -3854,6 +4071,8 @@ Init_IO_Buffer(void)
rb_define_method(rb_cIOBuffer, "xor!", io_buffer_xor_inplace, 1);
rb_define_method(rb_cIOBuffer, "not!", io_buffer_not_inplace, 0);
+ rb_define_method(rb_cIOBuffer, "bit_count", io_buffer_bit_count, -1);
+
// IO operations:
rb_define_method(rb_cIOBuffer, "read", io_buffer_read, -1);
rb_define_method(rb_cIOBuffer, "pread", io_buffer_pread, -1);
diff --git a/iseq.c b/iseq.c
index 09346994dd..b90fcb4334 100644
--- a/iseq.c
+++ b/iseq.c
@@ -19,6 +19,7 @@
#endif
#include "eval_intern.h"
+#include "id.h"
#include "id_table.h"
#include "internal.h"
#include "internal/bits.h"
@@ -38,6 +39,7 @@
#include "iseq.h"
#include "ruby/util.h"
#include "vm_core.h"
+#include "ractor_core.h"
#include "vm_callinfo.h"
#include "yjit.h"
#include "ruby/ractor.h"
@@ -86,7 +88,7 @@ free_arena(struct iseq_compile_data_storage *cur)
while (cur) {
next = cur->next;
- ruby_xfree(cur);
+ ruby_xfree_sized(cur, offsetof(struct iseq_compile_data_storage, buff) + cur->size * sizeof(char));
cur = next;
}
}
@@ -100,7 +102,7 @@ compile_data_free(struct iseq_compile_data *compile_data)
if (compile_data->ivar_cache_table) {
rb_id_table_free(compile_data->ivar_cache_table);
}
- ruby_xfree(compile_data);
+ SIZED_FREE(compile_data);
}
}
@@ -111,14 +113,14 @@ remove_from_constant_cache(ID id, IC ic)
VALUE lookup_result;
st_data_t ic_data = (st_data_t)ic;
- if (rb_id_table_lookup(vm->constant_cache, id, &lookup_result)) {
+ if (rb_id_table_lookup(&vm->constant_cache, id, &lookup_result)) {
set_table *ics = (set_table *)lookup_result;
set_table_delete(ics, &ic_data);
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);
+ rb_id_table_delete(&vm->constant_cache, id);
set_free_table(ics);
}
}
@@ -150,14 +152,33 @@ iseq_clear_ic_references(const rb_iseq_t *iseq)
if (segments == NULL)
continue;
- for (int i = 0; segments[i]; i++) {
+ int i;
+ for (i = 0; segments[i]; i++) {
ID id = segments[i];
if (id == idNULL) continue;
remove_from_constant_cache(id, ic);
}
- ruby_xfree((void *)segments);
+ SIZED_FREE_N(segments, i + 1);
+ }
+}
+
+
+rb_hook_list_t *
+rb_iseq_local_hooks(const rb_iseq_t *iseq, rb_ractor_t *r, bool create)
+{
+ rb_hook_list_t *hook_list = NULL;
+ st_data_t val;
+ if (st_lookup(rb_ractor_targeted_hooks(r), (st_data_t)iseq, &val)) {
+ hook_list = (rb_hook_list_t*)val;
+ RUBY_ASSERT(hook_list->type == hook_list_type_targeted_iseq);
+ }
+ else if (create) {
+ hook_list = RB_ZALLOC(rb_hook_list_t);
+ hook_list->type = hook_list_type_targeted_iseq;
+ st_insert(rb_ractor_targeted_hooks(r), (st_data_t)iseq, (st_data_t)hook_list);
}
+ return hook_list;
}
void
@@ -175,39 +196,44 @@ rb_iseq_free(const rb_iseq_t *iseq)
rb_yjit_live_iseq_count--;
}
#endif
- ruby_xfree((void *)body->iseq_encoded);
- ruby_xfree((void *)body->insns_info.body);
- ruby_xfree((void *)body->insns_info.positions);
+#if USE_ZJIT
+ rb_zjit_iseq_free(iseq);
+#endif
+ SIZED_FREE_N(body->iseq_encoded, body->iseq_size);
+ SIZED_FREE_N(body->insns_info.body, body->insns_info.size);
+ SIZED_FREE_N(body->insns_info.positions, body->insns_info.size);
#if VM_INSN_INFO_TABLE_IMPL == 2
ruby_xfree(body->insns_info.succ_index_table);
#endif
- ruby_xfree((void *)body->is_entries);
- ruby_xfree(body->call_data);
- ruby_xfree((void *)body->catch_table);
- ruby_xfree((void *)body->param.opt_table);
+ SIZED_FREE_N(body->is_entries, ISEQ_IS_SIZE(body));
+ SIZED_FREE_N(body->call_data, body->ci_size);
+ if (body->catch_table) {
+ ruby_xfree_sized(body->catch_table, iseq_catch_table_bytes(body->catch_table->size));
+ }
+ SIZED_FREE_N(body->param.opt_table, body->param.opt_num + 1);
if (ISEQ_MBITS_BUFLEN(body->iseq_size) > 1 && body->mark_bits.list) {
- ruby_xfree((void *)body->mark_bits.list);
+ SIZED_FREE_N(body->mark_bits.list, ISEQ_MBITS_BUFLEN(body->iseq_size));
}
- ruby_xfree(body->variable.original_iseq);
+ ISEQ_ORIGINAL_ISEQ_CLEAR(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);
+ struct rb_iseq_param_keyword *pkw = (struct rb_iseq_param_keyword *)body->param.keyword;
+ if (pkw != NULL) {
+ if (pkw->table != &body->local_table[pkw->bits_start - pkw->num])
+ SIZED_FREE_N(pkw->table, pkw->required_num);
+ if (pkw->default_values) {
+ SIZED_FREE_N(pkw->default_values, pkw->num - pkw->required_num);
}
- ruby_xfree((void *)body->param.keyword);
+ SIZED_FREE(pkw);
+ }
+ if (LIKELY(body->local_table != rb_iseq_shared_exc_local_tbl)) {
+ SIZED_FREE_N(body->local_table, body->local_table_size);
}
- if (LIKELY(body->local_table != rb_iseq_shared_exc_local_tbl))
- ruby_xfree((void *)body->local_table);
+ SIZED_FREE_N(body->lvar_states, body->local_table_size);
+
compile_data_free(ISEQ_COMPILE_DATA(iseq));
if (body->outer_variables) rb_id_table_free(body->outer_variables);
- ruby_xfree(body);
- }
-
- if (iseq && ISEQ_EXECUTABLE_P(iseq) && iseq->aux.exec.local_hooks) {
- rb_hook_list_free(iseq->aux.exec.local_hooks);
+ SIZED_FREE(body);
}
RUBY_FREE_LEAVE("iseq");
@@ -276,9 +302,7 @@ rb_iseq_mark_and_move_each_body_value(const rb_iseq_t *iseq, VALUE *original_ise
for (unsigned int i = 0; i < body->icvarc_size; i++, is_entries++) {
ICVARC icvarc = (ICVARC)is_entries;
if (icvarc->entry) {
- RUBY_ASSERT(!RB_TYPE_P(icvarc->entry->class_value, T_NONE));
-
- rb_gc_mark_and_move(&icvarc->entry->class_value);
+ rb_gc_mark_and_move((VALUE *)&icvarc->entry);
}
}
@@ -350,8 +374,6 @@ rb_iseq_mark_and_move(rb_iseq_t *iseq, bool reference_updating)
rb_iseq_mark_and_move_each_body_value(iseq, reference_updating ? ISEQ_ORIGINAL_ISEQ(iseq) : 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);
@@ -406,34 +428,43 @@ rb_iseq_mark_and_move(rb_iseq_t *iseq, bool reference_updating)
#endif
}
else {
+ // TODO: check jit payload
+ if (!rb_gc_checking_shareable()) {
#if USE_YJIT
- rb_yjit_iseq_mark(body->yjit_payload);
+ rb_yjit_iseq_mark(body->yjit_payload);
#endif
#if USE_ZJIT
- rb_zjit_iseq_mark(body->zjit_payload);
+ rb_zjit_iseq_mark(body->zjit_payload);
#endif
+ }
+ }
+
+ // TODO: ractor aware coverage
+ if (!rb_gc_checking_shareable()) {
+ rb_gc_mark_and_move(&body->variable.coverage);
+ rb_gc_mark_and_move(&body->variable.pc2branchindex);
}
}
if (FL_TEST_RAW((VALUE)iseq, ISEQ_NOT_LOADED_YET)) {
- rb_gc_mark_and_move(&iseq->aux.loader.obj);
+ if (!rb_gc_checking_shareable()) {
+ rb_gc_mark_and_move(&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 (!rb_gc_checking_shareable()) {
+ const struct iseq_compile_data *const compile_data = ISEQ_COMPILE_DATA(iseq);
- rb_iseq_mark_and_move_insn_storage(compile_data->insn.storage_head);
- rb_iseq_mark_and_move_each_compile_data_value(iseq, reference_updating ? ISEQ_ORIGINAL_ISEQ(iseq) : NULL);
+ rb_iseq_mark_and_move_insn_storage(compile_data->insn.storage_head);
+ rb_iseq_mark_and_move_each_compile_data_value(iseq, reference_updating ? ISEQ_ORIGINAL_ISEQ(iseq) : NULL);
- rb_gc_mark_and_move((VALUE *)&compile_data->err_info);
- rb_gc_mark_and_move((VALUE *)&compile_data->catch_table_ary);
+ rb_gc_mark_and_move((VALUE *)&compile_data->err_info);
+ rb_gc_mark_and_move((VALUE *)&compile_data->catch_table_ary);
+ }
}
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);
- }
}
RUBY_MARK_LEAVE("iseq");
@@ -538,9 +569,14 @@ rb_iseq_pathobj_new(VALUE path, VALUE realpath)
pathobj = rb_fstring(path);
}
else {
- if (!NIL_P(realpath)) realpath = rb_fstring(realpath);
- pathobj = rb_ary_new_from_args(2, rb_fstring(path), realpath);
+ if (!NIL_P(realpath)) {
+ realpath = rb_fstring(realpath);
+ }
+ VALUE fpath = rb_fstring(path);
+
+ pathobj = rb_ary_new_from_args(2, fpath, realpath);
rb_ary_freeze(pathobj);
+ RB_OBJ_SET_SHAREABLE(pathobj);
}
return pathobj;
}
@@ -559,6 +595,11 @@ rb_iseq_alloc_with_dummy_path(VALUE fname)
rb_iseq_t *dummy_iseq = iseq_alloc();
ISEQ_BODY(dummy_iseq)->type = ISEQ_TYPE_TOP;
+
+ if (!RB_OBJ_SHAREABLE_P(fname)) {
+ RB_OBJ_SET_FROZEN_SHAREABLE(fname);
+ }
+
RB_OBJ_WRITE(dummy_iseq, &ISEQ_BODY(dummy_iseq)->location.pathobj, fname);
RB_OBJ_WRITE(dummy_iseq, &ISEQ_BODY(dummy_iseq)->location.label, fname);
@@ -634,6 +675,18 @@ new_arena(void)
return new_arena;
}
+static int
+prepare_node_id(const NODE *node)
+{
+ if (!node) return -1;
+
+ if (nd_type(node) == NODE_SCOPE && RNODE_SCOPE(node)->nd_parent) {
+ return nd_node_id(RNODE_SCOPE(node)->nd_parent);
+ }
+
+ return nd_node_id(node);
+}
+
static VALUE
prepare_iseq_build(rb_iseq_t *iseq,
VALUE name, VALUE path, VALUE realpath, int first_lineno, const rb_code_location_t *code_location, const int node_id,
@@ -707,7 +760,7 @@ rb_iseq_insns_info_encode_positions(const rb_iseq_t *iseq)
if (body->insns_info.succ_index_table) ruby_xfree(body->insns_info.succ_index_table);
body->insns_info.succ_index_table = succ_index_table_create(max_pos, data, size);
#if VM_CHECK_MODE == 0
- ruby_xfree(body->insns_info.positions);
+ SIZED_FREE_N(body->insns_info.positions, body->insns_info.size);
body->insns_info.positions = NULL;
#endif
#endif
@@ -811,10 +864,6 @@ set_compile_option_from_hash(rb_compile_option_t *option, VALUE opt)
static rb_compile_option_t *
set_compile_option_from_ast(rb_compile_option_t *option, const rb_ast_body_t *ast)
{
-#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;
}
@@ -927,7 +976,7 @@ rb_iseq_new_top(const VALUE ast_value, VALUE name, VALUE path, VALUE realpath, c
rb_iseq_t *
pm_iseq_new_top(pm_scope_node_t *node, VALUE name, VALUE path, VALUE realpath, const rb_iseq_t *parent, int *error_state)
{
- iseq_new_setup_coverage(path, (int) (node->parser->newline_list.size - 1));
+ iseq_new_setup_coverage(path, (int) (pm_parser_line_offsets(node->parser)->size - 1));
return pm_iseq_new_with_opt(node, name, path, realpath, 0, parent, 0,
ISEQ_TYPE_TOP, &COMPILE_OPTION_DEFAULT, error_state);
@@ -951,7 +1000,7 @@ rb_iseq_new_main(const VALUE ast_value, VALUE path, VALUE realpath, const rb_ise
rb_iseq_t *
pm_iseq_new_main(pm_scope_node_t *node, VALUE path, VALUE realpath, const rb_iseq_t *parent, int opt, int *error_state)
{
- iseq_new_setup_coverage(path, (int) (node->parser->newline_list.size - 1));
+ iseq_new_setup_coverage(path, (int) (pm_parser_line_offsets(node->parser)->size - 1));
return pm_iseq_new_with_opt(node, rb_fstring_lit("<main>"),
path, realpath, 0,
@@ -968,8 +1017,13 @@ rb_iseq_new_eval(const VALUE ast_value, VALUE name, VALUE path, VALUE realpath,
}
}
+ rb_compile_option_t option = COMPILE_OPTION_DEFAULT;
+ rb_ast_t *ast = rb_ruby_ast_data_get(ast_value);
+ if (ast->body.coverage_enabled >= 0) {
+ option.coverage_enabled = ast->body.coverage_enabled;
+ }
return rb_iseq_new_with_opt(ast_value, name, path, realpath, first_lineno,
- parent, isolated_depth, ISEQ_TYPE_EVAL, &COMPILE_OPTION_DEFAULT,
+ parent, isolated_depth, ISEQ_TYPE_EVAL, &option,
Qnil);
}
@@ -980,7 +1034,7 @@ pm_iseq_new_eval(pm_scope_node_t *node, VALUE name, VALUE path, VALUE realpath,
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, ((int) (pm_parser_line_offsets(node->parser)->size - 1)) + first_lineno - 1);
}
}
@@ -1031,7 +1085,7 @@ rb_iseq_new_with_opt(VALUE ast_value, VALUE name, VALUE path, VALUE realpath,
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,
+ prepare_iseq_build(iseq, name, path, realpath, first_lineno, node ? &node->nd_loc : NULL, prepare_node_id(node),
parent, isolated_depth, type, script_lines, option);
rb_iseq_compile_node(iseq, node);
@@ -1041,41 +1095,15 @@ rb_iseq_new_with_opt(VALUE ast_value, VALUE name, VALUE path, VALUE realpath,
return iseq_translate(iseq);
}
-struct pm_iseq_new_with_opt_data {
- rb_iseq_t *iseq;
- pm_scope_node_t *node;
-};
-
-VALUE
-pm_iseq_new_with_opt_try(VALUE d)
-{
- struct pm_iseq_new_with_opt_data *data = (struct pm_iseq_new_with_opt_data *)d;
-
- // This can compile child iseqs, which can raise syntax errors
- pm_iseq_compile_node(data->iseq, data->node);
-
- // This raises an exception if there is a syntax error
- finish_iseq_build(data->iseq);
-
- return Qundef;
-}
-
/**
- * 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 *).
+ * Core implementation for building a prism iseq. This does not use rb_protect,
+ * so any exceptions (e.g. from finish_iseq_build) propagate normally up the
+ * call stack — matching the parse.y compiler's behavior.
*/
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, int *error_state)
+pm_iseq_build(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;
@@ -1088,10 +1116,11 @@ pm_iseq_new_with_opt(pm_scope_node_t *node, VALUE name, VALUE path, VALUE realpa
option = &next_option;
pm_location_t *location = &node->base.location;
- int32_t start_line = node->parser->start_line;
+ int32_t start_line = pm_parser_start_line(node->parser);
+ const pm_line_offset_list_t *line_offsets = pm_parser_line_offsets(node->parser);
- 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);
+ pm_line_column_t start = pm_line_offset_list_line_column(line_offsets, location->start, start_line);
+ pm_line_column_t end = pm_line_offset_list_line_column(line_offsets, location->start + location->length, start_line);
rb_code_location_t code_location = (rb_code_location_t) {
.beg_pos = { .lineno = (int) start.line, .column = (int) start.column },
@@ -1101,15 +1130,59 @@ pm_iseq_new_with_opt(pm_scope_node_t *node, VALUE name, VALUE path, VALUE realpa
prepare_iseq_build(iseq, name, path, realpath, first_lineno, &code_location, node->ast_node->node_id,
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);
+}
+
+struct pm_iseq_new_with_opt_data {
+ rb_iseq_t *iseq;
+ pm_scope_node_t *node;
+ VALUE name, path, realpath;
+ int first_lineno, isolated_depth;
+ const rb_iseq_t *parent;
+ enum rb_iseq_type type;
+ const rb_compile_option_t *option;
+};
+
+static VALUE
+pm_iseq_new_with_opt_try(VALUE d)
+{
+ struct pm_iseq_new_with_opt_data *data = (struct pm_iseq_new_with_opt_data *)d;
+ data->iseq = pm_iseq_build(data->node, data->name, data->path, data->realpath,
+ data->first_lineno, data->parent, data->isolated_depth,
+ data->type, data->option);
+ return Qundef;
+}
+
+/**
+ * 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.
+ *
+ * This function uses rb_protect to catch exceptions, storing the error state
+ * in the provided out parameter. This is only needed at top-level entry points
+ * where the caller wants to handle errors gracefully. Child iseqs compiled
+ * during the compilation process do NOT go through this function — they use
+ * pm_iseq_build directly, letting exceptions propagate naturally (matching
+ * the parse.y compiler's behavior).
+ */
+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, int *error_state)
+{
struct pm_iseq_new_with_opt_data data = {
- .iseq = iseq,
- .node = node
+ .node = node, .name = name, .path = path, .realpath = realpath,
+ .first_lineno = first_lineno, .parent = parent,
+ .isolated_depth = isolated_depth, .type = type, .option = option
};
rb_protect(pm_iseq_new_with_opt_try, (VALUE)&data, error_state);
if (*error_state) return NULL;
- return iseq_translate(iseq);
+ return data.iseq;
}
rb_iseq_t *
@@ -1137,7 +1210,22 @@ rb_iseq_load_iseq(VALUE fname)
VALUE iseqv = rb_check_funcall(rb_cISeq, rb_intern("load_iseq"), 1, &fname);
if (!SPECIAL_CONST_P(iseqv) && RBASIC_CLASS(iseqv) == rb_cISeq) {
- return iseqw_check(iseqv);
+ return iseqw_check(iseqv);
+ }
+
+ return NULL;
+}
+
+const rb_iseq_t *
+rb_iseq_compile_iseq(VALUE str, VALUE fname)
+{
+ VALUE args[] = {
+ str, fname
+ };
+ VALUE iseqv = rb_check_funcall(rb_cISeq, rb_intern("compile"), 2, args);
+
+ if (!SPECIAL_CONST_P(iseqv) && RBASIC_CLASS(iseqv) == rb_cISeq) {
+ return iseqw_check(iseqv);
}
return NULL;
@@ -1310,6 +1398,7 @@ rb_iseq_compile_with_option(VALUE src, VALUE file, VALUE realpath, VALUE line, V
rb_exc_raise(GET_EC()->errinfo);
}
else {
+ iseq_new_setup_coverage(file, ast_line_count(ast_value));
iseq = rb_iseq_new_with_opt(ast_value, name, file, realpath, ln,
NULL, 0, ISEQ_TYPE_TOP, &option,
Qnil);
@@ -1341,19 +1430,20 @@ pm_iseq_compile_with_option(VALUE src, VALUE file, VALUE realpath, VALUE line, V
src = StringValue(src);
}
- pm_parse_result_t result = { 0 };
- pm_options_line_set(&result.options, NUM2INT(line));
- pm_options_scopes_init(&result.options, 1);
+ pm_parse_result_t result;
+ pm_parse_result_init(&result);
+ 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);
+ 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);
+ 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);
@@ -1374,6 +1464,7 @@ pm_iseq_compile_with_option(VALUE src, VALUE file, VALUE realpath, VALUE line, V
if (error == Qnil) {
int error_state;
+ iseq_new_setup_coverage(file, (int) (pm_parser_line_offsets(result.node.parser)->size - 1));
iseq = pm_iseq_new_with_opt(&result.node, name, file, realpath, ln, NULL, 0, ISEQ_TYPE_TOP, &option, &error_state);
pm_parse_result_free(&result);
@@ -1535,6 +1626,7 @@ iseqw_new(const rb_iseq_t *iseq)
RB_OBJ_WRITE(obj, ptr, iseq);
/* cache a wrapper object */
+ RB_OBJ_SET_FROZEN_SHAREABLE((VALUE)obj);
RB_OBJ_WRITE((VALUE)iseq, &iseq->wrapper, obj);
return obj;
@@ -1597,7 +1689,7 @@ iseqw_s_compile_parser(int argc, VALUE *argv, VALUE self, bool prism)
* 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
+ * +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.
*
@@ -1639,7 +1731,7 @@ iseqw_s_compile(int argc, VALUE *argv, VALUE self)
* 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
+ * +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.
*
@@ -1681,7 +1773,7 @@ iseqw_s_compile_parsey(int argc, VALUE *argv, VALUE self)
* 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
+ * +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.
*
@@ -1712,6 +1804,8 @@ iseqw_s_compile_prism(int argc, VALUE *argv, VALUE self)
return iseqw_s_compile_parser(argc, argv, self, true);
}
+static VALUE iseqw_s_compile_file_prism(int argc, VALUE *argv, VALUE self);
+
/*
* call-seq:
* InstructionSequence.compile_file(file[, options]) -> iseq
@@ -1735,6 +1829,10 @@ iseqw_s_compile_prism(int argc, VALUE *argv, VALUE self)
static VALUE
iseqw_s_compile_file(int argc, VALUE *argv, VALUE self)
{
+ if (rb_ruby_prism_p()) {
+ return iseqw_s_compile_file_prism(argc, argv, self);
+ }
+
VALUE file, opt = Qnil;
VALUE parser, f, exc = Qnil, ret;
rb_ast_t *ast;
@@ -1758,6 +1856,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);
+ iseq_new_setup_coverage(file, ast_line_count(ast_value));
ast = rb_ruby_ast_data_get(ast_value);
if (!ast->body.root) exc = GET_EC()->errinfo;
@@ -1821,17 +1920,32 @@ iseqw_s_compile_file_prism(int argc, VALUE *argv, VALUE self)
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;
+ make_compile_option(&option, opt);
+
+ pm_parse_result_t result;
+ pm_parse_result_init(&result);
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("iseqw_s_compile_file_prism: invalid frozen_string_literal=%d", option.frozen_string_literal);
+ break;
+ }
+
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);
-
int error_state;
+ iseq_new_setup_coverage(file, (int) (pm_parser_line_offsets(result.node.parser)->size - 1));
rb_iseq_t *iseq = pm_iseq_new_with_opt(&result.node, rb_fstring_lit("<main>"),
file,
rb_realpath_internal(Qnil, file, 1),
@@ -1948,7 +2062,7 @@ iseqw_eval(VALUE self)
if (0 == ISEQ_BODY(iseq)->iseq_size) {
rb_raise(rb_eTypeError, "attempt to evaluate dummy InstructionSequence");
}
- return rb_iseq_eval(iseq);
+ return rb_iseq_eval(iseq, rb_current_box());
}
/*
@@ -2382,17 +2496,22 @@ rb_iseq_event_flags(const rb_iseq_t *iseq, size_t pos)
}
}
+static void rb_iseq_trace_flag_cleared(const rb_iseq_t *iseq, size_t pos);
+
// Clear tracing event flags and turn off tracing for a given instruction as needed.
// This is currently used after updating a one-shot line coverage for the current instruction.
void
rb_iseq_clear_event_flags(const rb_iseq_t *iseq, size_t pos, rb_event_flag_t reset)
{
- struct iseq_insn_info_entry *entry = (struct iseq_insn_info_entry *)get_insn_info(iseq, pos);
- if (entry) {
- entry->events &= ~reset;
- if (!(entry->events & iseq->aux.exec.global_trace_events)) {
- void rb_iseq_trace_flag_cleared(const rb_iseq_t *iseq, size_t pos);
- rb_iseq_trace_flag_cleared(iseq, pos);
+ RB_VM_LOCKING() {
+ rb_vm_barrier();
+
+ struct iseq_insn_info_entry *entry = (struct iseq_insn_info_entry *)get_insn_info(iseq, pos);
+ if (entry) {
+ entry->events &= ~reset;
+ if (!(entry->events & iseq->aux.exec.global_trace_events)) {
+ rb_iseq_trace_flag_cleared(iseq, pos);
+ }
}
}
}
@@ -2911,24 +3030,31 @@ rb_iseq_disasm(const rb_iseq_t *iseq)
attr_index_t
rb_estimate_iv_count(VALUE klass, const rb_iseq_t * initialize_iseq)
{
- struct rb_id_table * iv_names = rb_id_table_create(0);
+ set_table iv_names = { 0 };
+ set_init_embedded_numtable_with_size(&iv_names, 0);
for (unsigned int i = 0; i < ISEQ_BODY(initialize_iseq)->ivc_size; i++) {
IVC cache = (IVC)&ISEQ_BODY(initialize_iseq)->is_entries[i];
if (cache->iv_set_name) {
- rb_id_table_insert(iv_names, cache->iv_set_name, Qtrue);
+ set_insert(&iv_names, cache->iv_set_name);
}
}
- attr_index_t count = (attr_index_t)rb_id_table_size(iv_names);
+ size_t count = iv_names.num_entries;
VALUE superclass = rb_class_superclass(klass);
- count += RCLASS_MAX_IV_COUNT(superclass);
+ if (!NIL_P(superclass)) { // BasicObject doesn't have a superclass
+ count += RCLASS_MAX_IV_COUNT(superclass);
+ }
- rb_id_table_free(iv_names);
+ set_free_embedded_table(&iv_names);
+
+ if (count > (attr_index_t)-1) {
+ return (attr_index_t)-1;
+ }
- return count;
+ return (attr_index_t)count;
}
/*
@@ -3149,7 +3275,7 @@ iseqw_s_of(VALUE klass, VALUE body)
* 0000 trace 8 ( 1)
* 0002 trace 1 ( 2)
* 0004 putself
- * 0005 putstring "hello, world"
+ * 0005 dupstring "hello, world"
* 0007 send :puts, 1, nil, 8, <ic:0>
* 0013 trace 16 ( 3)
* 0015 leave ( 2)
@@ -3214,7 +3340,7 @@ static int
cdhash_each(VALUE key, VALUE value, VALUE ary)
{
rb_ary_push(ary, obj_resurrect(key));
- rb_ary_push(ary, value);
+ rb_ary_push(ary, INT2FIX(value));
return ST_CONTINUE;
}
@@ -3273,6 +3399,7 @@ iseq_type_id(enum rb_iseq_type type)
static VALUE
iseq_data_to_ary(const rb_iseq_t *iseq)
{
+ VALUE iseq_value = (VALUE)iseq;
unsigned int i;
long l;
const struct rb_iseq_constant_body *const iseq_body = ISEQ_BODY(iseq);
@@ -3308,7 +3435,7 @@ iseq_data_to_ary(const rb_iseq_t *iseq)
for (i=0; i<iseq_body->local_table_size; i++) {
ID lid = iseq_body->local_table[i];
if (lid) {
- if (rb_id2str(lid)) {
+ if (lid != idItImplicit && rb_id2str(lid)) {
rb_ary_push(locals, ID2SYM(lid));
}
else { /* hidden variable from id_internal() */
@@ -3454,11 +3581,11 @@ iseq_data_to_ary(const rb_iseq_t *iseq)
break;
case TS_CDHASH:
{
- VALUE hash = *seq;
+ VALUE cdhash = *seq;
VALUE val = rb_ary_new();
int i;
- rb_hash_foreach(hash, cdhash_each, val);
+ st_foreach(rb_imemo_cdhash_tbl(cdhash), cdhash_each, val);
for (i=0; i<RARRAY_LEN(val); i+=2) {
VALUE pos = FIX2INT(rb_ary_entry(val, i+1));
@@ -3605,6 +3732,9 @@ iseq_data_to_ary(const rb_iseq_t *iseq)
rb_ary_push(val, params);
rb_ary_push(val, exception);
rb_ary_push(val, body);
+
+ RB_GC_GUARD(iseq_value);
+
return val;
}
@@ -3618,10 +3748,10 @@ rb_iseq_parameters(const rb_iseq_t *iseq, int is_proc)
ID req, opt, rest, block, key, keyrest;
#define PARAM_TYPE(type) rb_ary_push(a = rb_ary_new2(2), ID2SYM(type))
#define PARAM_ID(i) body->local_table[(i)]
-#define PARAM(i, type) ( \
- PARAM_TYPE(type), \
- rb_id2str(PARAM_ID(i)) ? \
- rb_ary_push(a, ID2SYM(PARAM_ID(i))) : \
+#define PARAM(i, type) ( \
+ PARAM_TYPE(type), \
+ PARAM_ID(i) != idItImplicit && rb_id2str(PARAM_ID(i)) ? \
+ rb_ary_push(a, ID2SYM(PARAM_ID(i))) : \
a)
CONST_ID(req, "req");
@@ -3639,11 +3769,7 @@ rb_iseq_parameters(const rb_iseq_t *iseq, int is_proc)
if (is_proc) {
for (i = 0; i < body->param.lead_num; i++) {
- PARAM_TYPE(opt);
- if (rb_id2str(PARAM_ID(i))) {
- rb_ary_push(a, ID2SYM(PARAM_ID(i)));
- }
- rb_ary_push(args, a);
+ rb_ary_push(args, PARAM(i, opt));
}
}
else {
@@ -3653,11 +3779,7 @@ rb_iseq_parameters(const rb_iseq_t *iseq, int is_proc)
}
r = body->param.lead_num + body->param.opt_num;
for (; i < r; i++) {
- PARAM_TYPE(opt);
- if (rb_id2str(PARAM_ID(i))) {
- rb_ary_push(a, ID2SYM(PARAM_ID(i)));
- }
- rb_ary_push(args, a);
+ rb_ary_push(args, PARAM(i, opt));
}
if (body->param.flags.has_rest) {
CONST_ID(rest, "rest");
@@ -3666,11 +3788,7 @@ rb_iseq_parameters(const rb_iseq_t *iseq, int is_proc)
r = body->param.post_start + body->param.post_num;
if (is_proc) {
for (i = body->param.post_start; i < r; i++) {
- PARAM_TYPE(opt);
- if (rb_id2str(PARAM_ID(i))) {
- rb_ary_push(a, ID2SYM(PARAM_ID(i)));
- }
- rb_ary_push(args, a);
+ rb_ary_push(args, PARAM(i, opt));
}
}
else {
@@ -3719,7 +3837,13 @@ rb_iseq_parameters(const rb_iseq_t *iseq, int is_proc)
}
rb_ary_push(args, a);
}
- if (body->param.flags.has_block) {
+ if (body->param.flags.accepts_no_block) {
+ ID noblock;
+ CONST_ID(noblock, "noblock");
+ PARAM_TYPE(noblock);
+ rb_ary_push(args, a);
+ }
+ else if (body->param.flags.has_block) {
CONST_ID(block, "block");
rb_ary_push(args, PARAM(body->param.block_start, block));
}
@@ -3874,14 +3998,14 @@ rb_vm_insn_decode(const VALUE encoded)
// Turn on or off tracing for a given instruction address
static inline int
-encoded_iseq_trace_instrument(VALUE *iseq_encoded_insn, rb_event_flag_t turnon, bool remain_current_trace)
+encoded_iseq_trace_instrument(VALUE *iseq_encoded_insn, rb_event_flag_t turnon, bool remain_traced)
{
st_data_t key = (st_data_t)*iseq_encoded_insn;
st_data_t val;
if (st_lookup(encoded_insn_data, key, &val)) {
insn_data_t *e = (insn_data_t *)val;
- if (remain_current_trace && key == (st_data_t)e->trace_encoded_insn) {
+ if (remain_traced && key == (st_data_t)e->trace_encoded_insn) {
turnon = 1;
}
*iseq_encoded_insn = (VALUE) (turnon ? e->trace_encoded_insn : e->notrace_encoded_insn);
@@ -3892,7 +4016,7 @@ encoded_iseq_trace_instrument(VALUE *iseq_encoded_insn, rb_event_flag_t turnon,
}
// Turn off tracing for an instruction at pos after tracing event flags are cleared
-void
+static void
rb_iseq_trace_flag_cleared(const rb_iseq_t *iseq, size_t pos)
{
const struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
@@ -3918,14 +4042,16 @@ add_bmethod_events(rb_event_flag_t events)
// Note, to support call/return events for bmethods, turnon_event can have more events than tpval.
static int
-iseq_add_local_tracepoint(const rb_iseq_t *iseq, rb_event_flag_t turnon_events, VALUE tpval, unsigned int target_line)
+iseq_add_local_tracepoint(const rb_iseq_t *iseq, rb_event_flag_t turnon_events, VALUE tpval, unsigned int target_line, rb_ractor_t *r)
{
unsigned int pc;
int n = 0;
const struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
VALUE *iseq_encoded = (VALUE *)body->iseq_encoded;
+ rb_iseq_t *iseq_mut = (rb_iseq_t*)iseq;
VM_ASSERT(ISEQ_EXECUTABLE_P(iseq));
+ ASSERT_vm_locking_with_barrier();
for (pc=0; pc<body->iseq_size;) {
const struct iseq_insn_info_entry *entry = get_insn_info(iseq, pc);
@@ -3947,11 +4073,9 @@ iseq_add_local_tracepoint(const rb_iseq_t *iseq, rb_event_flag_t turnon_events,
}
if (n > 0) {
- if (iseq->aux.exec.local_hooks == NULL) {
- ((rb_iseq_t *)iseq)->aux.exec.local_hooks = RB_ZALLOC(rb_hook_list_t);
- iseq->aux.exec.local_hooks->is_local = true;
- }
- rb_hook_list_connect_tracepoint((VALUE)iseq, iseq->aux.exec.local_hooks, tpval, target_line);
+ rb_hook_list_t *hook_list = rb_iseq_local_hooks(iseq, r, true);
+ rb_hook_list_connect_local_tracepoint(hook_list, tpval, target_line);
+ iseq_mut->aux.exec.local_hooks_cnt++;
}
return n;
@@ -3962,19 +4086,21 @@ struct trace_set_local_events_struct {
VALUE tpval;
unsigned int target_line;
int n;
+ rb_ractor_t *r;
};
static void
iseq_add_local_tracepoint_i(const rb_iseq_t *iseq, void *p)
{
struct trace_set_local_events_struct *data = (struct trace_set_local_events_struct *)p;
- data->n += iseq_add_local_tracepoint(iseq, data->turnon_events, data->tpval, data->target_line);
+ data->n += iseq_add_local_tracepoint(iseq, data->turnon_events, data->tpval, data->target_line, data->r);
iseq_iterate_children(iseq, iseq_add_local_tracepoint_i, p);
}
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)
{
+ ASSERT_vm_locking_with_barrier();
struct trace_set_local_events_struct data;
if (target_bmethod) {
turnon_events = add_bmethod_events(turnon_events);
@@ -3983,35 +4109,52 @@ rb_iseq_add_local_tracepoint_recursively(const rb_iseq_t *iseq, rb_event_flag_t
data.tpval = tpval;
data.target_line = target_line;
data.n = 0;
+ data.r = GET_RACTOR();
iseq_add_local_tracepoint_i(iseq, (void *)&data);
- if (0) rb_funcall(Qnil, rb_intern("puts"), 1, rb_iseq_disasm(iseq)); /* for debug */
+ if (0) fprintf(stderr, "Iseq disasm:\n:%s", RSTRING_PTR(rb_iseq_disasm(iseq))); /* for debug */
return data.n;
}
static int
-iseq_remove_local_tracepoint(const rb_iseq_t *iseq, VALUE tpval)
+iseq_remove_local_tracepoint(const rb_iseq_t *iseq, VALUE tpval, rb_ractor_t *r)
{
int n = 0;
+ unsigned int num_hooks_left;
+ unsigned int pc;
+ const struct rb_iseq_constant_body *body;
+ rb_iseq_t *iseq_mut = (rb_iseq_t*)iseq;
+ rb_hook_list_t *hook_list;
+ VALUE *iseq_encoded;
+ ASSERT_vm_locking_with_barrier();
- if (iseq->aux.exec.local_hooks) {
- unsigned int pc;
- const struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
- VALUE *iseq_encoded = (VALUE *)body->iseq_encoded;
+ hook_list = rb_iseq_local_hooks(iseq, r, false);
+
+ if (hook_list) {
rb_event_flag_t local_events = 0;
- rb_hook_list_remove_tracepoint(iseq->aux.exec.local_hooks, tpval);
- local_events = iseq->aux.exec.local_hooks->events;
+ rb_event_flag_t prev_events = hook_list->events;
+ if (rb_hook_list_remove_local_tracepoint(hook_list, tpval)) {
+ RUBY_ASSERT(iseq->aux.exec.local_hooks_cnt > 0);
+ iseq_mut->aux.exec.local_hooks_cnt--;
+ local_events = hook_list->events; // remaining events for this ractor
+ num_hooks_left = rb_hook_list_count(hook_list);
+ if (local_events == 0 && prev_events != 0) {
+ st_delete(rb_ractor_targeted_hooks(r), (st_data_t*)&iseq, NULL);
+ rb_hook_list_free(hook_list);
+ }
- if (local_events == 0) {
- rb_hook_list_free(iseq->aux.exec.local_hooks);
- ((rb_iseq_t *)iseq)->aux.exec.local_hooks = NULL;
- }
+ if (iseq->aux.exec.local_hooks_cnt == num_hooks_left) {
+ body = ISEQ_BODY(iseq);
+ iseq_encoded = (VALUE *)body->iseq_encoded;
+ local_events = add_bmethod_events(local_events);
+ for (pc = 0; pc<body->iseq_size;) {
+ rb_event_flag_t pc_events = rb_iseq_event_flags(iseq, pc);
+ pc += encoded_iseq_trace_instrument(&iseq_encoded[pc], pc_events & (local_events | iseq->aux.exec.global_trace_events), false);
+ }
+ }
- local_events = add_bmethod_events(local_events);
- for (pc = 0; pc<body->iseq_size;) {
- rb_event_flag_t pc_events = rb_iseq_event_flags(iseq, pc);
- pc += encoded_iseq_trace_instrument(&iseq_encoded[pc], pc_events & (local_events | iseq->aux.exec.global_trace_events), false);
+ n++;
}
}
return n;
@@ -4020,22 +4163,25 @@ iseq_remove_local_tracepoint(const rb_iseq_t *iseq, VALUE tpval)
struct trace_clear_local_events_struct {
VALUE tpval;
int n;
+ rb_ractor_t *r;
};
static void
iseq_remove_local_tracepoint_i(const rb_iseq_t *iseq, void *p)
{
struct trace_clear_local_events_struct *data = (struct trace_clear_local_events_struct *)p;
- data->n += iseq_remove_local_tracepoint(iseq, data->tpval);
+ data->n += iseq_remove_local_tracepoint(iseq, data->tpval, data->r);
iseq_iterate_children(iseq, iseq_remove_local_tracepoint_i, p);
}
int
-rb_iseq_remove_local_tracepoint_recursively(const rb_iseq_t *iseq, VALUE tpval)
+rb_iseq_remove_local_tracepoint_recursively(const rb_iseq_t *iseq, VALUE tpval, rb_ractor_t *r)
{
struct trace_clear_local_events_struct data;
+ ASSERT_vm_locking_with_barrier();
data.tpval = tpval;
data.n = 0;
+ data.r = r;
iseq_remove_local_tracepoint_i(iseq, (void *)&data);
return data.n;
@@ -4053,11 +4199,14 @@ rb_iseq_trace_set(const rb_iseq_t *iseq, rb_event_flag_t turnon_events)
return;
}
else {
+ // NOTE: this does not need VM barrier if it's a new ISEQ
unsigned int pc;
const struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
+
VALUE *iseq_encoded = (VALUE *)body->iseq_encoded;
rb_event_flag_t enabled_events;
- rb_event_flag_t local_events = iseq->aux.exec.local_hooks ? iseq->aux.exec.local_hooks->events : 0;
+ rb_hook_list_t *local_hooks = rb_iseq_local_hooks(iseq, GET_RACTOR(), false);
+ rb_event_flag_t local_events = local_hooks ? local_hooks->events : 0;
((rb_iseq_t *)iseq)->aux.exec.global_trace_events = turnon_events;
enabled_events = add_bmethod_events(turnon_events | local_events);
@@ -4073,6 +4222,7 @@ void rb_vm_cc_general(const struct rb_callcache *cc);
static bool
clear_attr_cc(VALUE v)
{
+ ASSERT_vm_locking_with_barrier();
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;
@@ -4085,6 +4235,7 @@ clear_attr_cc(VALUE v)
static bool
clear_bf_cc(VALUE v)
{
+ ASSERT_vm_locking_with_barrier();
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;
@@ -4110,7 +4261,10 @@ clear_attr_ccs_i(void *vstart, void *vend, size_t stride, void *data)
void
rb_clear_attr_ccs(void)
{
- rb_objspace_each_objects(clear_attr_ccs_i, NULL);
+ RB_VM_LOCKING() {
+ rb_vm_barrier();
+ rb_objspace_each_objects(clear_attr_ccs_i, NULL);
+ }
}
static int
@@ -4129,6 +4283,7 @@ clear_bf_ccs_i(void *vstart, void *vend, size_t stride, void *data)
void
rb_clear_bf_ccs(void)
{
+ ASSERT_vm_locking_with_barrier();
rb_objspace_each_objects(clear_bf_ccs_i, NULL);
}
@@ -4158,7 +4313,10 @@ trace_set_i(void *vstart, void *vend, size_t stride, void *data)
void
rb_iseq_trace_set_all(rb_event_flag_t turnon_events)
{
- rb_objspace_each_objects(trace_set_i, &turnon_events);
+ RB_VM_LOCKING() {
+ rb_vm_barrier();
+ rb_objspace_each_objects(trace_set_i, &turnon_events);
+ }
}
VALUE
diff --git a/iseq.h b/iseq.h
index 1cecc6960d..b9bc03c23c 100644
--- a/iseq.h
+++ b/iseq.h
@@ -68,9 +68,11 @@ ISEQ_ORIGINAL_ISEQ(const rb_iseq_t *iseq)
static inline void
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);
+ VALUE *ptr = (VALUE *)ISEQ_BODY(iseq)->variable.original_iseq;
+ if (ptr) {
+ ISEQ_BODY(iseq)->variable.original_iseq = NULL;
+ SIZED_FREE_N(ptr, ISEQ_BODY(iseq)->iseq_size);
+ }
}
static inline VALUE *
@@ -129,7 +131,6 @@ 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;
@@ -175,7 +176,12 @@ 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);
+ rb_iseq_t *iseq = SHAREABLE_IMEMO_NEW(rb_iseq_t, imemo_iseq, 0);
+
+ // Clear out the whole iseq except for the flags.
+ memset((char *)iseq + sizeof(VALUE), 0, sizeof(rb_iseq_t) - sizeof(VALUE));
+
+ return iseq;
}
VALUE rb_iseq_ibf_dump(const rb_iseq_t *iseq, VALUE opt);
@@ -185,9 +191,12 @@ const rb_iseq_t *rb_iseq_ibf_load_bytes(const char *cstr, size_t);
VALUE rb_iseq_ibf_load_extra_data(VALUE str);
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);
+int rb_iseq_remove_local_tracepoint_recursively(const rb_iseq_t *iseq, VALUE tpval, rb_ractor_t *r);
const rb_iseq_t *rb_iseq_load_iseq(VALUE fname);
+const rb_iseq_t *rb_iseq_compile_iseq(VALUE str, VALUE fname);
int rb_iseq_opt_frozen_string_literal(void);
+rb_hook_list_t *rb_iseq_local_hooks(const rb_iseq_t *iseq, rb_ractor_t *r, bool create);
+
#if VM_INSN_INFO_TABLE_IMPL == 2
unsigned int *rb_iseq_insns_info_decode_positions(const struct rb_iseq_constant_body *body);
diff --git a/jit.c b/jit.c
index e68758368a..9bd16eab84 100644
--- a/jit.c
+++ b/jit.c
@@ -12,7 +12,49 @@
#include "insns.inc"
#include "insns_info.inc"
#include "iseq.h"
+#include "internal/compile.h"
#include "internal/gc.h"
+#include "vm_sync.h"
+#include "internal/fixnum.h"
+#include "internal/string.h"
+#include "internal/class.h"
+#include "internal/imemo.h"
+#include "ruby/internal/core/rtypeddata.h"
+#include "zjit.h"
+
+#ifndef _WIN32
+#include <sys/mman.h>
+#endif
+
+enum jit_bindgen_constants {
+ // Field offsets for the RObject struct
+ ROBJECT_OFFSET_AS_HEAP_FIELDS = offsetof(struct RObject, as.heap.fields),
+ ROBJECT_OFFSET_AS_ARY = offsetof(struct RObject, as.ary),
+
+ // Field offset for prime classext's fields_obj from a class pointer
+ RCLASS_OFFSET_PRIME_FIELDS_OBJ = offsetof(struct RClass_and_rb_classext_t, classext.fields_obj),
+
+ // Field offset for fields_obj in T_DATA
+ TDATA_OFFSET_FIELDS_OBJ = offsetof(struct RTypedData, fields_obj),
+
+ // Field offsets for the RString struct
+ RUBY_OFFSET_RSTRING_LEN = offsetof(struct RString, len),
+
+ // Shape constant related to RBasic::flags. (See RBASIC_SET_SHAPE_ID())
+ RB_SHAPE_FLAG_SHIFT = SHAPE_FLAG_SHIFT,
+
+ // Field offsets for rb_execution_context_t
+ RUBY_OFFSET_EC_CFP = offsetof(rb_execution_context_t, cfp),
+ RUBY_OFFSET_EC_INTERRUPT_FLAG = offsetof(rb_execution_context_t, interrupt_flag),
+ RUBY_OFFSET_EC_INTERRUPT_MASK = offsetof(rb_execution_context_t, interrupt_mask),
+ RUBY_OFFSET_EC_THREAD_PTR = offsetof(rb_execution_context_t, thread_ptr),
+ RUBY_OFFSET_EC_RACTOR_ID = offsetof(rb_execution_context_t, ractor_id),
+};
+
+// Manually bound in rust since this is out-of-range of `int`,
+// so this can't be in a `enum`, and we avoid `static const`
+// to avoid allocating storage for the constant.
+const shape_id_t rb_invalid_shape_id = INVALID_SHAPE_ID;
unsigned int
rb_iseq_encoded_size(const rb_iseq_t *iseq)
@@ -35,13 +77,29 @@ rb_iseq_pc_at_idx(const rb_iseq_t *iseq, uint32_t insn_idx)
int
rb_iseq_opcode_at_pc(const rb_iseq_t *iseq, const VALUE *pc)
{
- // YJIT should only use iseqs after AST to bytecode compilation
- RUBY_ASSERT_ALWAYS(FL_TEST_RAW((VALUE)iseq, ISEQ_TRANSLATED));
+ // YJIT should only use iseqs after AST to bytecode compilation.
+ // (Certain non-default interpreter configurations never set ISEQ_TRANSLATED)
+ if (OPT_DIRECT_THREADED_CODE || OPT_CALL_THREADED_CODE) {
+ RUBY_ASSERT_ALWAYS(FL_TEST_RAW((VALUE)iseq, ISEQ_TRANSLATED));
+ }
const VALUE at_pc = *pc;
return rb_vm_insn_addr2opcode((const void *)at_pc);
}
+// Get the bare opcode given a program counter. Always returns the base
+// instruction, stripping trace/zjit variants.
+int
+rb_iseq_bare_opcode_at_pc(const rb_iseq_t *iseq, const VALUE *pc)
+{
+ if (OPT_DIRECT_THREADED_CODE || OPT_CALL_THREADED_CODE) {
+ RUBY_ASSERT_ALWAYS(FL_TEST_RAW((VALUE)iseq, ISEQ_TRANSLATED));
+ }
+
+ const VALUE at_pc = *pc;
+ return rb_vm_insn_addr2insn((const void *)at_pc);
+}
+
unsigned long
rb_RSTRING_LEN(VALUE str)
{
@@ -149,6 +207,35 @@ rb_get_def_original_id(const rb_method_definition_t *def)
return def->original_id;
}
+VALUE
+rb_get_def_bmethod_proc(rb_method_definition_t *def)
+{
+ RUBY_ASSERT(def->type == VM_METHOD_TYPE_BMETHOD);
+ return def->body.bmethod.proc;
+}
+
+rb_proc_t *
+rb_jit_get_proc_ptr(VALUE procv)
+{
+ rb_proc_t *proc;
+ GetProcPtr(procv, proc);
+ return proc;
+}
+
+VALUE
+rb_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);
+}
+
+unsigned int
+rb_jit_iseq_builtin_attrs(const rb_iseq_t *iseq)
+{
+ return iseq->body->builtin_attrs;
+}
+
int
rb_get_mct_argc(const rb_method_cfunc_t *mct)
{
@@ -319,7 +406,7 @@ rb_get_ec_cfp(const rb_execution_context_t *ec)
const rb_iseq_t *
rb_get_cfp_iseq(struct rb_control_frame_struct *cfp)
{
- return cfp->iseq;
+ return CFP_ISEQ(cfp);
}
VALUE *
@@ -443,6 +530,12 @@ rb_yarv_ary_entry_internal(VALUE ary, long offset)
return rb_ary_entry_internal(ary, offset);
}
+long
+rb_jit_array_len(VALUE a)
+{
+ return rb_array_len(a);
+}
+
void
rb_set_cfp_pc(struct rb_control_frame_struct *cfp, const VALUE *pc)
{
@@ -454,3 +547,298 @@ rb_set_cfp_sp(struct rb_control_frame_struct *cfp, VALUE *sp)
{
cfp->sp = sp;
}
+
+bool
+rb_jit_shape_complex_p(shape_id_t shape_id)
+{
+ return rb_shape_complex_p(shape_id);
+}
+
+bool
+rb_jit_multi_ractor_p(void)
+{
+ return rb_multi_ractor_p();
+}
+
+bool
+rb_jit_class_fields_embedded_p(VALUE klass)
+{
+ VALUE fields_obj = RCLASS_EXT_PRIME(klass)->fields_obj;
+ return !fields_obj || !FL_TEST_RAW(fields_obj, OBJ_FIELD_HEAP);
+}
+
+bool
+rb_jit_data_fields_embedded_p(VALUE obj)
+{
+ VALUE fields_obj = RTYPEDDATA(obj)->fields_obj;
+ return !fields_obj || !FL_TEST_RAW(fields_obj, OBJ_FIELD_HEAP);
+}
+
+// Acquire the VM lock and then signal all other Ruby threads (ractors) to
+// contend for the VM lock, putting them to sleep. ZJIT and YJIT use this to
+// evict threads running inside generated code so among other things, it can
+// safely change memory protection of regions housing generated code.
+void
+rb_jit_vm_lock_then_barrier(unsigned int *recursive_lock_level, const char *file, int line)
+{
+ rb_vm_lock_enter(recursive_lock_level, file, line);
+ rb_vm_barrier();
+}
+
+// Release the VM lock. The lock level must point to the same integer used to
+// acquire the lock.
+void
+rb_jit_vm_unlock(unsigned int *recursive_lock_level, const char *file, int line)
+{
+ rb_vm_lock_leave(recursive_lock_level, file, line);
+}
+
+void
+rb_iseq_reset_jit_func(const rb_iseq_t *iseq)
+{
+ RUBY_ASSERT_ALWAYS(IMEMO_TYPE_P(iseq, imemo_iseq));
+ iseq->body->jit_entry = NULL;
+ iseq->body->jit_exception = NULL;
+ // Enable re-compiling this ISEQ. Event when it's invalidated for TracePoint,
+ // we'd like to re-compile ISEQs that haven't been converted to trace_* insns.
+ iseq->body->jit_entry_calls = 0;
+ iseq->body->jit_exception_calls = 0;
+}
+
+// Callback data for rb_jit_for_each_iseq
+struct iseq_callback_data {
+ rb_iseq_callback callback;
+ void *data;
+};
+
+// Heap-walking callback for rb_jit_for_each_iseq
+static int
+for_each_iseq_i(void *vstart, void *vend, size_t stride, void *data)
+{
+ const struct iseq_callback_data *callback_data = (struct iseq_callback_data *)data;
+ VALUE v = (VALUE)vstart;
+ for (; v != (VALUE)vend; v += stride) {
+ void *ptr = rb_asan_poisoned_object_p(v);
+ rb_asan_unpoison_object(v, false);
+
+ if (rb_obj_is_iseq(v)) {
+ rb_iseq_t *iseq = (rb_iseq_t *)v;
+ callback_data->callback(iseq, callback_data->data);
+ }
+
+ if (ptr) {
+ rb_asan_poison_object(v);
+ }
+ }
+ return 0;
+}
+
+uint32_t
+rb_jit_get_page_size(void)
+{
+#if defined(_SC_PAGESIZE)
+ long page_size = sysconf(_SC_PAGESIZE);
+ if (page_size <= 0) rb_bug("jit: failed to get page size");
+
+ // 1 GiB limit. x86 CPUs with PDPE1GB can do this and anything larger is unexpected.
+ // Though our design sort of assume we have fine grained control over memory protection
+ // which require small page sizes.
+ if (page_size > 0x40000000l) rb_bug("jit page size too large");
+
+ return (uint32_t)page_size;
+#else
+#error "JIT supports POSIX only for now"
+#endif
+}
+
+#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.
+uint8_t *
+rb_jit_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 *)(uintptr_t)&rb_jit_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) {
+ ruby_annotate_mmap(mem_block, mem_size, "Ruby:rb_jit_reserve_addr_space");
+ break;
+ }
+
+ // -4MiB. Downwards to probe away from the heap. (On x86/A64 Linux
+ // main_code_addr < heap_addr, and in case we are in a shared
+ // library mapped higher than the heap, downwards is still better
+ // since it's towards the end of the heap rather than the stack.)
+ 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 *)rb_jit_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
+ );
+
+ if (mem_block != MAP_FAILED) {
+ ruby_annotate_mmap(mem_block, mem_size, "Ruby:rb_jit_reserve_addr_space:fallback");
+ }
+ }
+
+ // Check that the memory mapping was successful
+ if (mem_block == MAP_FAILED) {
+ perror("ruby: jit: 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
+}
+
+// Walk all ISEQs in the heap and invoke the callback - shared between YJIT and ZJIT
+void
+rb_jit_for_each_iseq(rb_iseq_callback callback, void *data)
+{
+ struct iseq_callback_data callback_data = { .callback = callback, .data = data };
+ rb_objspace_each_objects(for_each_iseq_i, (void *)&callback_data);
+}
+
+bool
+rb_jit_mark_writable(void *mem_block, uint32_t mem_size)
+{
+ return mprotect(mem_block, mem_size, PROT_READ | PROT_WRITE) == 0;
+}
+
+void
+rb_jit_mark_executable(void *mem_block, uint32_t mem_size)
+{
+ // Do not call mprotect when mem_size is zero. Some platforms may return
+ // an error for it. https://github.com/Shopify/ruby/issues/450
+ if (mem_size == 0) {
+ return;
+ }
+ 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));
+ }
+}
+
+// Free the specified memory block.
+bool
+rb_jit_mark_unused(void *mem_block, uint32_t mem_size)
+{
+ // On Linux, you need to use madvise MADV_DONTNEED to free memory.
+ // We might not need to call this on macOS, but it's not really documented.
+ // We generally prefer to do the same thing on both to ease testing too.
+ madvise(mem_block, mem_size, MADV_DONTNEED);
+
+ // On macOS, mprotect PROT_NONE seems to reduce RSS.
+ // We also call this on Linux to avoid executing unused pages.
+ return mprotect(mem_block, mem_size, PROT_NONE) == 0;
+}
+
+// Invalidate icache for arm64.
+// `start` is inclusive and `end` is exclusive.
+void
+rb_jit_icache_invalidate(void *start, void *end)
+{
+ // Clear/invalidate the instruction cache. Compiles to nothing on x86_64
+ // but required on ARM before running freshly written code.
+ // On Darwin it's the same as calling sys_icache_invalidate().
+#ifdef __GNUC__
+ __builtin___clear_cache(start, end);
+#elif defined(__aarch64__)
+#error No instruction cache clear available with this compiler on Aarch64!
+#endif
+}
+
+VALUE
+rb_jit_fix_mod_fix(VALUE recv, VALUE obj)
+{
+ return rb_fix_mod_fix(recv, obj);
+}
+
+VALUE
+rb_jit_fix_div_fix(VALUE recv, VALUE obj)
+{
+ return rb_fix_div_fix(recv, obj);
+}
+
+// YJIT/ZJIT need this function to never allocate and never raise
+VALUE
+rb_yarv_str_eql_internal(VALUE str1, VALUE str2)
+{
+ // We wrap this since it's static inline
+ return rb_str_eql_internal(str1, str2);
+}
+
+void rb_jit_str_concat_codepoint(VALUE str, VALUE codepoint);
+
+attr_index_t
+rb_jit_shape_capacity(shape_id_t shape_id)
+{
+ return RSHAPE_CAPACITY(shape_id);
+}
diff --git a/jit/Cargo.toml b/jit/Cargo.toml
new file mode 100644
index 0000000000..530fe3674b
--- /dev/null
+++ b/jit/Cargo.toml
@@ -0,0 +1,6 @@
+[package]
+name = "jit"
+version = "0.1.0"
+edition = "2024"
+
+[dependencies]
diff --git a/jit/src/lib.rs b/jit/src/lib.rs
new file mode 100644
index 0000000000..c0f043131e
--- /dev/null
+++ b/jit/src/lib.rs
@@ -0,0 +1,38 @@
+//! Shared code between YJIT and ZJIT.
+#![warn(unsafe_op_in_unsafe_fn)] // Adopt 2024 edition default when targeting 2021 editions
+
+use std::sync::atomic::{AtomicUsize, Ordering};
+use std::alloc::{GlobalAlloc, Layout, System};
+
+#[global_allocator]
+pub static GLOBAL_ALLOCATOR: StatsAlloc = StatsAlloc { alloc_size: AtomicUsize::new(0) };
+
+pub struct StatsAlloc {
+ pub alloc_size: AtomicUsize,
+}
+
+unsafe impl GlobalAlloc for StatsAlloc {
+ unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
+ self.alloc_size.fetch_add(layout.size(), Ordering::SeqCst);
+ unsafe { System.alloc(layout) }
+ }
+
+ unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
+ self.alloc_size.fetch_sub(layout.size(), Ordering::SeqCst);
+ unsafe { System.dealloc(ptr, layout) }
+ }
+
+ unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
+ self.alloc_size.fetch_add(layout.size(), Ordering::SeqCst);
+ unsafe { System.alloc_zeroed(layout) }
+ }
+
+ unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
+ if new_size > layout.size() {
+ self.alloc_size.fetch_add(new_size - layout.size(), Ordering::SeqCst);
+ } else if new_size < layout.size() {
+ self.alloc_size.fetch_sub(layout.size() - new_size, Ordering::SeqCst);
+ }
+ unsafe { System.realloc(ptr, layout, new_size) }
+ }
+}
diff --git a/jit_hook.rb b/jit_hook.rb
index 487361c049..c605d6e26d 100644
--- a/jit_hook.rb
+++ b/jit_hook.rb
@@ -2,11 +2,10 @@ class Module
# Internal helper for built-in initializations to define methods only when JIT is enabled.
# This method is removed in jit_undef.rb.
private def with_jit(&block) # :nodoc:
- # ZJIT currently doesn't compile Array#each properly, so it's disabled for now.
- if defined?(RubyVM::ZJIT) && Primitive.rb_zjit_option_enabled_p && false # TODO: remove `&& false` (Shopify/ruby#667)
- # We don't support lazily enabling ZJIT yet, so we can call the block right away.
- block.call
- elsif defined?(RubyVM::YJIT)
+ if defined?(RubyVM::ZJIT)
+ RubyVM::ZJIT.send(:add_jit_hook, block)
+ end
+ if defined?(RubyVM::YJIT)
RubyVM::YJIT.send(:add_jit_hook, block)
end
end
diff --git a/kernel.rb b/kernel.rb
index 888ef0c531..dc5cea1515 100644
--- a/kernel.rb
+++ b/kernel.rb
@@ -17,7 +17,7 @@ module Kernel
#
def class
Primitive.attr! :leaf
- Primitive.cexpr! 'rb_obj_class(self)'
+ Primitive.cexpr! 'rb_obj_class_must(self)'
end
#
@@ -141,6 +141,7 @@ module Kernel
# loop do
# print "Input: "
# line = gets
+ # # break if q, Q is entered or EOF signal (Ctrl-D on Unix, Ctrl-Z on windows) is sent
# break if !line or line =~ /^q/i
# # ...
# end
diff --git a/lib/English.gemspec b/lib/English.gemspec
index 261162dde3..9c09555ca1 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.8.1"
spec.authors = ["Yukihiro Matsumoto"]
spec.email = ["matz@ruby-lang.org"]
diff --git a/lib/English.rb b/lib/English.rb
index 03fe721991..bf7896dcd6 100644
--- a/lib/English.rb
+++ b/lib/English.rb
@@ -9,7 +9,7 @@
# "waterbuffalo" =~ /buff/
# print $', $$, "\n"
#
-# With English:
+# With 'English':
#
# require "English"
#
@@ -20,30 +20,30 @@
# Below is a full list of descriptive aliases and their associated global
# variable:
#
-# $ERROR_INFO:: $!
-# $ERROR_POSITION:: $@
-# $FS:: $;
-# $FIELD_SEPARATOR:: $;
-# $OFS:: $,
-# $OUTPUT_FIELD_SEPARATOR:: $,
-# $RS:: $/
-# $INPUT_RECORD_SEPARATOR:: $/
-# $ORS:: $\
-# $OUTPUT_RECORD_SEPARATOR:: $\
-# $INPUT_LINE_NUMBER:: $.
-# $NR:: $.
-# $LAST_READ_LINE:: $_
-# $DEFAULT_OUTPUT:: $>
-# $DEFAULT_INPUT:: $<
-# $PID:: $$
-# $PROCESS_ID:: $$
-# $CHILD_STATUS:: $?
-# $LAST_MATCH_INFO:: $~
-# $ARGV:: $*
-# $MATCH:: $&
-# $PREMATCH:: $`
-# $POSTMATCH:: $'
-# $LAST_PAREN_MATCH:: $+
+# <tt>$ERROR_INFO</tt>:: <tt>$!</tt>
+# <tt>$ERROR_POSITION</tt>:: <tt>$@</tt>
+# <tt>$FS</tt>:: <tt>$;</tt>
+# <tt>$FIELD_SEPARATOR</tt>:: <tt>$;</tt>
+# <tt>$OFS</tt>:: <tt>$,</tt>
+# <tt>$OUTPUT_FIELD_SEPARATOR</tt>:: <tt>$,</tt>
+# <tt>$RS</tt>:: <tt>$/</tt>
+# <tt>$INPUT_RECORD_SEPARATOR</tt>:: <tt>$/</tt>
+# <tt>$ORS</tt>:: <tt>$\</tt>
+# <tt>$OUTPUT_RECORD_SEPARATOR</tt>:: <tt>$\</tt>
+# <tt>$NR</tt>:: <tt>$.</tt>
+# <tt>$INPUT_LINE_NUMBER</tt>:: <tt>$.</tt>
+# <tt>$LAST_READ_LINE</tt>:: <tt>$_</tt>
+# <tt>$DEFAULT_OUTPUT</tt>:: <tt>$></tt>
+# <tt>$DEFAULT_INPUT</tt>:: <tt>$<</tt>
+# <tt>$PID</tt>:: <tt>$$</tt>
+# <tt>$PROCESS_ID</tt>:: <tt>$$</tt>
+# <tt>$CHILD_STATUS</tt>:: <tt>$?</tt>
+# <tt>$LAST_MATCH_INFO</tt>:: <tt>$~</tt>
+# <tt>$ARGV</tt>:: <tt>$*</tt>
+# <tt>$MATCH</tt>:: <tt>$&</tt>
+# <tt>$PREMATCH</tt>:: <tt>$`</tt>
+# <tt>$POSTMATCH</tt>:: <tt>$'</tt>
+# <tt>$LAST_PAREN_MATCH</tt>:: <tt>$+</tt>
#
module English end if false
diff --git a/lib/bundled_gems.rb b/lib/bundled_gems.rb
index 852d7c48e3..a287c49a34 100644
--- a/lib/bundled_gems.rb
+++ b/lib/bundled_gems.rb
@@ -1,5 +1,10 @@
# -*- frozen-string-literal: true -*-
+module Gem # :nodoc:
+ # TODO: the nodoc above is a workaround for RDoc's Prism parser handling stopdoc differently, we may want to use
+ # stopdoc/startdoc pair like before
+end
+
module Gem::BUNDLED_GEMS # :nodoc:
SINCE = {
"racc" => "3.3.0",
@@ -15,17 +20,17 @@ module Gem::BUNDLED_GEMS # :nodoc:
"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.
- "tsort" => "3.6.0",
+ "ostruct" => "4.0.0",
+ "pstore" => "4.0.0",
+ "rdoc" => "4.0.0",
+ "win32ole" => "4.0.0",
+ "fiddle" => "4.0.0",
+ "logger" => "4.0.0",
+ "benchmark" => "4.0.0",
+ "irb" => "4.0.0",
+ "reline" => "4.0.0",
+ # "readline" => "4.0.0", # This is wrapper for reline. We don't warn for this.
+ "tsort" => "4.1.0",
}.freeze
EXACT = {
@@ -117,8 +122,26 @@ module Gem::BUNDLED_GEMS # :nodoc:
false
end
+ if suppress_list = Thread.current[:__bundled_gems_warning_suppression]
+ return if suppress_list.include?(name) || suppress_list.include?(feature)
+ end
+
return if specs.include?(name)
+ # Don't warn if a hyphenated gem provides this feature
+ # (e.g., benchmark-ips provides benchmark/ips, benchmark/timing, etc.)
+ if subfeature
+ prefix = feature.split("/").first + "-"
+ return if specs.any? { |spec, _| spec.start_with?(prefix) }
+
+ # Don't warn if the feature is found outside the standard library
+ # (e.g., benchmark-ips's lib dir is on $LOAD_PATH but not in specs)
+ resolved = $LOAD_PATH.resolve_feature_path(feature) rescue nil
+ if resolved && !resolved[1].start_with?(LIBDIR, ARCHDIR)
+ return
+ end
+ end
+
return if WARNED[name]
WARNED[name] = true
@@ -192,19 +215,28 @@ module Gem::BUNDLED_GEMS # :nodoc:
require "bundler"
Bundler.reset!
+ # Build and activate a temporary definition containing the original gems + the requested gem
builder = Bundler::Dsl.new
- if Bundler::SharedHelpers.in_bundle?
- if Bundler.locked_gems
- Bundler.locked_gems.specs.each{|spec| builder.gem spec.name, spec.version.to_s }
- elsif Bundler.definition.gemfiles.size > 0
- Bundler.definition.gemfiles.each{|gemfile| builder.eval_gemfile(gemfile) }
+ lockfile = nil
+ if Bundler::SharedHelpers.in_bundle? && Bundler.definition.gemfiles.size > 0
+ Bundler.definition.gemfiles.each {|gemfile| builder.eval_gemfile(gemfile) }
+ lockfile = begin
+ Bundler.default_lockfile
+ rescue Bundler::GemfileNotFound
+ nil
end
+ else
+ # Fake BUNDLE_GEMFILE and BUNDLE_LOCKFILE to let checks pass
+ orig_gemfile = ENV["BUNDLE_GEMFILE"]
+ orig_lockfile = ENV["BUNDLE_LOCKFILE"]
+ Bundler::SharedHelpers.set_env "BUNDLE_GEMFILE", "Gemfile"
+ Bundler::SharedHelpers.set_env "BUNDLE_LOCKFILE", "Gemfile.lock"
end
builder.gem gem
- definition = builder.to_definition(nil, true)
+ definition = builder.to_definition(lockfile, nil)
definition.validate_runtime!
begin
@@ -220,6 +252,8 @@ module Gem::BUNDLED_GEMS # :nodoc:
rescue Bundler::GemNotFound
warn "Failed to activate #{gem}, please install it with 'gem install #{gem}'"
ensure
+ ENV['BUNDLE_GEMFILE'] = orig_gemfile if orig_gemfile
+ ENV['BUNDLE_LOCKFILE'] = orig_lockfile if orig_lockfile
Bundler.ui = orig_ui
Bundler::Definition.no_lock = orig_no_lock
end
diff --git a/lib/bundler.rb b/lib/bundler.rb
index 761679ec8d..12dde90fc5 100644
--- a/lib/bundler.rb
+++ b/lib/bundler.rb
@@ -2,7 +2,7 @@
require_relative "bundler/rubygems_ext"
require_relative "bundler/vendored_fileutils"
-require "pathname"
+autoload :Pathname, "pathname" unless defined?(Pathname)
require "rbconfig"
require_relative "bundler/errors"
@@ -54,7 +54,6 @@ module Bundler
autoload :FREEBSD, File.expand_path("bundler/constants", __dir__)
autoload :GemHelper, File.expand_path("bundler/gem_helper", __dir__)
autoload :GemVersionPromoter, File.expand_path("bundler/gem_version_promoter", __dir__)
- autoload :Graph, File.expand_path("bundler/graph", __dir__)
autoload :Index, File.expand_path("bundler/index", __dir__)
autoload :Injector, File.expand_path("bundler/injector", __dir__)
autoload :Installer, File.expand_path("bundler/installer", __dir__)
@@ -63,6 +62,7 @@ module Bundler
autoload :MatchRemoteMetadata, File.expand_path("bundler/match_remote_metadata", __dir__)
autoload :Materialization, File.expand_path("bundler/materialization", __dir__)
autoload :NULL, File.expand_path("bundler/constants", __dir__)
+ autoload :Override, File.expand_path("bundler/override", __dir__)
autoload :ProcessLock, File.expand_path("bundler/process_lock", __dir__)
autoload :RemoteSpecification, File.expand_path("bundler/remote_specification", __dir__)
autoload :Resolver, File.expand_path("bundler/resolver", __dir__)
@@ -157,6 +157,7 @@ module Bundler
# Return if all groups are already loaded
return @setup if defined?(@setup) && @setup
+ configure_custom_gemfile
definition.validate_runtime!
SharedHelpers.print_major_deprecations!
@@ -173,7 +174,7 @@ module Bundler
self_manager.restart_with_locked_bundler_if_needed
end
- # Automatically install dependencies if settings[:auto_install] exists.
+ # Automatically install dependencies if <tt>settings[:auto_install]</tt> 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
@@ -219,8 +220,7 @@ module Bundler
end
def environment
- SharedHelpers.major_deprecation 2, "Bundler.environment has been removed in favor of Bundler.load", print_caller_location: true
- load
+ SharedHelpers.feature_removed! "Bundler.environment has been removed in favor of Bundler.load"
end
# Returns an instance of Bundler::Definition for given Gemfile and lockfile
@@ -365,16 +365,11 @@ module Bundler
ORIGINAL_ENV.clone
end
- # @deprecated Use `unbundled_env` instead
def clean_env
- message =
- "`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)
- unbundled_env
+ Bundler::SharedHelpers.feature_removed!(removed_message)
end
# @return [Hash] Environment with all bundler-related variables removed
@@ -392,16 +387,11 @@ module Bundler
with_env(original_env) { yield }
end
- # @deprecated Use `with_unbundled_env` instead
def with_clean_env
- message =
- "`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)
- with_env(unbundled_env) { yield }
+ Bundler::SharedHelpers.feature_removed!(removed_message)
end
# Run block with all bundler-related variables removed
@@ -414,16 +404,11 @@ module Bundler
with_original_env { Kernel.system(*args) }
end
- # @deprecated Use `unbundled_system` instead
def clean_system(*args)
- message =
- "`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)
- with_env(unbundled_env) { Kernel.system(*args) }
+ Bundler::SharedHelpers.feature_removed!(removed_message)
end
# Run subcommand in an environment with all bundler related variables removed
@@ -436,16 +421,11 @@ module Bundler
with_original_env { Kernel.exec(*args) }
end
- # @deprecated Use `unbundled_exec` instead
def clean_exec(*args)
- message =
- "`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)
- with_env(unbundled_env) { Kernel.exec(*args) }
+ Bundler::SharedHelpers.feature_removed!(removed_message)
end
# Run a `Kernel.exec` to a subcommand in an environment with all bundler related variables removed
@@ -608,6 +588,15 @@ module Bundler
Bundler.rubygems.clear_paths
end
+ def configure_custom_gemfile(custom_gemfile = nil)
+ custom_gemfile ||= Bundler.settings[:gemfile]
+
+ if custom_gemfile && !custom_gemfile.empty?
+ Bundler::SharedHelpers.set_env "BUNDLE_GEMFILE", File.expand_path(custom_gemfile)
+ reset_settings_and_root!
+ end
+ end
+
def self_manager
@self_manager ||= begin
require_relative "bundler/self_manager"
diff --git a/lib/bundler/bundler.gemspec b/lib/bundler/bundler.gemspec
index 16ca4a022c..49319e81b4 100644
--- a/lib/bundler/bundler.gemspec
+++ b/lib/bundler/bundler.gemspec
@@ -23,10 +23,10 @@ Gem::Specification.new do |s|
s.description = "Bundler manages an application's dependencies through its entire life, across many machines, systematically and repeatably"
s.metadata = {
- "bug_tracker_uri" => "https://github.com/rubygems/rubygems/issues?q=is%3Aopen+is%3Aissue+label%3ABundler",
- "changelog_uri" => "https://github.com/rubygems/rubygems/blob/master/bundler/CHANGELOG.md",
+ "bug_tracker_uri" => "https://github.com/ruby/rubygems/issues?q=is%3Aopen+is%3Aissue+label%3ABundler",
+ "changelog_uri" => "https://github.com/ruby/rubygems/blob/master/bundler/CHANGELOG.md",
"homepage_uri" => "https://bundler.io/",
- "source_code_uri" => "https://github.com/rubygems/rubygems/tree/master/bundler",
+ "source_code_uri" => "https://github.com/ruby/rubygems/tree/master/bundler",
}
s.required_ruby_version = ">= 3.2.0"
diff --git a/lib/bundler/capistrano.rb b/lib/bundler/capistrano.rb
index 705840143f..6d2437d895 100644
--- a/lib/bundler/capistrano.rb
+++ b/lib/bundler/capistrano.rb
@@ -1,22 +1,4 @@
# frozen_string_literal: true
require_relative "shared_helpers"
-Bundler::SharedHelpers.major_deprecation 2,
- "The Bundler task for Capistrano. Please use https://github.com/capistrano/bundler"
-
-# Capistrano task for Bundler.
-#
-# Add "require 'bundler/capistrano'" in your Capistrano deploy.rb, and
-# Bundler will be activated after each new deployment.
-require_relative "deployment"
-require "capistrano/version"
-
-if defined?(Capistrano::Version) && Gem::Version.new(Capistrano::Version).release >= Gem::Version.new("3.0")
- raise "For Capistrano 3.x integration, please use https://github.com/capistrano/bundler"
-end
-
-Capistrano::Configuration.instance(:must_exist).load do
- before "deploy:finalize_update", "bundle:install"
- Bundler::Deployment.define_task(self, :task, except: { no_release: true })
- set :rake, lambda { "#{fetch(:bundle_cmd, "bundle")} exec rake" }
-end
+Bundler::SharedHelpers.feature_removed! "The Bundler task for Capistrano. Please use https://github.com/capistrano/bundler"
diff --git a/lib/bundler/cli.rb b/lib/bundler/cli.rb
index 47a39069cc..9d8a68fff9 100644
--- a/lib/bundler/cli.rb
+++ b/lib/bundler/cli.rb
@@ -11,7 +11,7 @@ module Bundler
AUTO_INSTALL_CMDS = %w[show binstubs outdated exec open console licenses clean].freeze
PARSEABLE_COMMANDS = %w[check config help exec platform show version].freeze
- EXTENSIONS = ["c", "rust"].freeze
+ EXTENSIONS = ["c", "rust", "go"].freeze
COMMAND_ALIASES = {
"check" => "c",
@@ -24,7 +24,7 @@ module Bundler
}.freeze
def self.start(*)
- check_deprecated_ext_option(ARGV) if ARGV.include?("--ext")
+ check_invalid_ext_option(ARGV) if ARGV.include?("--ext")
super
ensure
@@ -59,17 +59,29 @@ module Bundler
def initialize(*args)
super
- custom_gemfile = options[:gemfile] || Bundler.settings[:gemfile]
- if custom_gemfile && !custom_gemfile.empty?
- Bundler::SharedHelpers.set_env "BUNDLE_GEMFILE", File.expand_path(custom_gemfile)
- Bundler.reset_settings_and_root!
+ current_cmd = args.last[:current_command].name
+
+ # `bundle config` manages stored settings, so avoid promoting settings
+ # like `gemfile` or `lockfile` to environment variables before it runs.
+ unless current_cmd == "config"
+ Bundler.configure_custom_gemfile(options[:gemfile])
+
+ # lock --lockfile works differently than install --lockfile
+ unless current_cmd == "lock"
+ custom_lockfile = options[:lockfile] || ENV["BUNDLE_LOCKFILE"] || Bundler.settings[:lockfile]
+ if custom_lockfile && !custom_lockfile.empty?
+ Bundler::SharedHelpers.set_env "BUNDLE_LOCKFILE", File.expand_path(custom_lockfile)
+ reset_settings = true
+ end
+ end
end
+ Bundler.reset_settings_and_root! if reset_settings
+
Bundler.auto_switch
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)
rescue UnknownArgumentError => e
raise InvalidOption, e.message
@@ -92,7 +104,7 @@ module Bundler
primary_commands = ["install", "update", "cache", "exec", "config", "help"]
list = self.class.printable_commands(true)
- by_name = list.group_by {|name, _message| name.match(/^bundle (\w+)/)[1] }
+ by_name = list.group_by {|name, _message| name.match(/^bundler? (\w+)/)[1] }
utilities = by_name.keys.sort - primary_commands
primary_commands.map! {|name| (by_name[name] || raise("no primary command #{name}")).first }
utilities.map! {|name| by_name[name].first }
@@ -107,7 +119,33 @@ module Bundler
shell.say
self.class.send(:class_options_help, shell)
end
- default_task(Bundler.feature_flag.default_cli_command)
+
+ desc "install_or_cli_help", "Deprecated alias of install", hide: true
+ def install_or_cli_help
+ Bundler.ui.warn <<~MSG
+ `bundle install_or_cli_help` is a deprecated alias of `bundle install`.
+ It might be called due to the 'default_cli_command' being set to 'install_or_cli_help',
+ if so fix that by running `bundle config set default_cli_command install --global`.
+ MSG
+ invoke_other_command("install")
+ end
+
+ def self.default_command(meth = nil)
+ return super if meth
+
+ unless Bundler.settings[:default_cli_command]
+ Bundler.ui.info <<~MSG
+ In a future version of Bundler, running `bundle` without argument will no longer run `bundle install`.
+ Instead, the `cli_help` command will be displayed. Please use `bundle install` explicitly for scripts like CI/CD.
+ You can use the future behavior now with `bundle config set default_cli_command cli_help --global`,
+ or you can continue to use the current behavior with `bundle config set default_cli_command install --global`.
+ This message will be removed after a default_cli_command value is set.
+
+ MSG
+ end
+
+ Bundler.settings[:default_cli_command] || "install"
+ end
class_option "no-color", type: :boolean, desc: "Disable colorization in output"
class_option "retry", type: :numeric, aliases: "-r", banner: "NUM",
@@ -117,6 +155,10 @@ module Bundler
def help(cli = nil)
cli = self.class.all_aliases[cli] if self.class.all_aliases[cli]
+ if Bundler.settings[:plugins] && Bundler::Plugin.command?(cli) && !self.class.all_commands.key?(cli)
+ return Bundler::Plugin.exec_command(cli, ["--help"])
+ end
+
case cli
when "gemfile" then command = "gemfile"
when nil then command = "bundle"
@@ -143,7 +185,7 @@ module Bundler
end
def self.handle_no_command_error(command, has_namespace = $thor_runner)
- if Bundler.feature_flag.plugins? && Bundler::Plugin.command?(command)
+ if Bundler.settings[:plugins] && Bundler::Plugin.command?(command)
return Bundler::Plugin.exec_command(command, ARGV[1..-1])
end
@@ -173,7 +215,7 @@ module Bundler
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 "path", type: :string, banner: "Specify a different path than the system default, namely, $BUNDLE_PATH or $GEM_HOME (removed)"
def check
remembered_flag_deprecation("path")
@@ -187,12 +229,11 @@ 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 (removed)"
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)
+ raise InvalidOption, removed_message
end
require_relative "cli/remove"
@@ -210,27 +251,30 @@ 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 "binstubs", type: :string, lazy_default: "bin", banner: "Generate bin stubs for bundled gems to ./bin (removed)"
+ method_option "clean", type: :boolean, banner: "Run bundle clean automatically after install (removed)"
+ method_option "deployment", type: :boolean, banner: "Install using defaults tuned for deployment environments (removed)"
+ method_option "frozen", type: :boolean, banner: "Do not allow the Gemfile.lock to be updated after this install (removed)"
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 "lockfile", type: :string, banner: "Use the specified lockfile instead of the default."
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 "no-lock", type: :boolean, banner: "Don't create a lockfile."
method_option "force", type: :boolean, aliases: "--redownload", banner: "Force reinstalling every gem, even if already installed"
- 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 "no-prune", type: :boolean, banner: "Don't remove stale gems from the cache (removed)."
+ method_option "path", type: :string, banner: "Specify a different path than the system default, namely, $BUNDLE_PATH or $GEM_HOME (removed)."
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 "shebang", type: :string, banner: "Specify a different shebang executable name than the default, usually 'ruby' (removed)"
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 "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 (removed)"
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: "Path to 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 "without", type: :array, banner: "Exclude gems that are part of the specified named group (removed)."
+ method_option "with", type: :array, banner: "Include gems that are part of the specified named group (removed)."
+ method_option "cooldown", type: :numeric, banner: "Only consider gem versions published at least N days ago. Use 0 to disable."
def install
%w[clean deployment frozen no-prune path shebang without with].each do |option|
remembered_flag_deprecation(option)
@@ -240,10 +284,20 @@ module Bundler
remembered_flag_deprecation("deployment", negative: true)
+ if ARGV.include?("--binstubs")
+ removed_message = "The --binstubs option has been removed in favor of `bundle binstubs --all`"
+ raise InvalidOption, removed_message
+ end
+
require_relative "cli/install"
+ options = self.options.dup
+ options["lockfile"] ||= ENV["BUNDLE_LOCKFILE"]
Bundler.settings.temporary(no_install: false) do
- Install.new(options.dup).run
+ Install.new(options).run
end
+ rescue GemfileNotFound => error
+ invoke_other_command("cli_help")
+ raise error # re-raise to show the error and get a failing exit status
end
map aliases_for("install")
@@ -271,6 +325,7 @@ module Bundler
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 "cooldown", type: :numeric, banner: "Only consider gem versions published at least N days ago. Use 0 to disable."
def update(*gems)
require_relative "cli/update"
Bundler.settings.temporary(no_install: false) do
@@ -284,12 +339,11 @@ module Bundler
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 "outdated", type: :boolean, banner: "Show verbose output including whether gems are outdated (removed)."
def show(gem_name = nil)
if ARGV.include?("--outdated")
- message = "the `--outdated` flag to `bundle show` will be removed in favor of `bundle show --verbose`"
removed_message = "the `--outdated` flag to `bundle show` has been removed in favor of `bundle show --verbose`"
- SharedHelpers.major_deprecation(2, message, removed_message: removed_message)
+ raise InvalidOption, removed_message
end
require_relative "cli/show"
Show.new(options, gem_name).run
@@ -323,7 +377,7 @@ module Bundler
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 "path", type: :string, lazy_default: "bin", banner: "Binstub destination directory, `bin` by default (removed)"
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"
@@ -351,8 +405,10 @@ module Bundler
method_option "glob", type: :string, banner: "The location of a dependency's .gemspec, expanded within Ruby (single quotes recommended)"
method_option "quiet", type: :boolean, banner: "Only output warnings and errors."
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 "optimistic", type: :boolean, banner: "Ignored (now default behavior)"
+ method_option "pessimistic", type: :boolean, banner: "Adds pessimistic declaration of version to gem"
method_option "strict", type: :boolean, banner: "Adds strict declaration of version to gem"
+ method_option "cooldown", type: :numeric, banner: "Only consider gem versions published at least N days ago. Use 0 to disable."
def add(*gems)
require_relative "cli/add"
Add.new(options.dup, gems).run
@@ -383,6 +439,7 @@ module Bundler
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 "cooldown", type: :numeric, banner: "Only consider gem versions published at least N days ago. Use 0 to disable."
def outdated(*gems)
require_relative "cli/outdated"
Outdated.new(options, gems).run
@@ -396,15 +453,15 @@ module Bundler
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", type: :boolean, default: Bundler.settings[:cache_all], banner: "Include all sources (including path and git) (removed)."
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 "no-prune", type: :boolean, banner: "Don't remove stale gems from the cache (removed)."
+ method_option "path", type: :string, banner: "Specify a different path than the system default, namely, $BUNDLE_PATH or $GEM_HOME (removed)."
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 "frozen", type: :boolean, banner: "Do not allow the Gemfile.lock to be updated after this bundle cache operation's install (removed)"
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
@@ -415,17 +472,17 @@ module Bundler
print_remembered_flag_deprecation("--all", "cache_all", "true") if ARGV.include?("--all")
print_remembered_flag_deprecation("--no-all", "cache_all", "false") if ARGV.include?("--no-all")
+ %w[frozen no-prune].each do |option|
+ remembered_flag_deprecation(option)
+ end
+
if flag_passed?("--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
+ "and `bundle config path` to configure the path where your gems are installed, " \
+ "and stop using this flag"
+ raise InvalidOption, removed_message
end
require_relative "cli/cache"
@@ -435,7 +492,7 @@ 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, banner: "Passes all file descriptors to the new processes. Default is true, and setting it to false is deprecated"
+ method_option :keep_file_descriptors, type: :boolean, default: true, banner: "Passes all file descriptors to the new processes. Default is true, and setting it to false is not permitted (removed)."
method_option :gemfile, type: :string, required: false, banner: "Use the specified gemfile instead of Gemfile"
long_desc <<-D
Exec runs a command, providing it access to the gems in the bundle. While using
@@ -444,9 +501,8 @@ 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)
+ raise InvalidOption, removed_message
end
require_relative "cli/exec"
@@ -490,7 +546,7 @@ module Bundler
build_info = " (#{BuildMetadata.timestamp} commit #{BuildMetadata.git_commit_sha})"
end
- if !cli_help && Bundler.feature_flag.bundler_4_mode?
+ if !cli_help
Bundler.ui.info "#{Bundler.verbose_version}#{build_info}"
else
Bundler.ui.info "Bundler version #{Bundler.verbose_version}#{build_info}"
@@ -513,23 +569,9 @@ module Bundler
end
end
- unless Bundler.feature_flag.bundler_4_mode?
- 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", banner: "The name to use for the generated file. see format option"
- method_option :format, type: :string, default: "png", aliases: "-F", banner: "This is output format option. Supported format is png, jpg, svg, dot ..."
- method_option :requirements, type: :boolean, default: false, aliases: "-R", banner: "Set to show the version of each required dependency."
- method_option :version, type: :boolean, default: false, aliases: "-v", banner: "Set to show each gem version."
- method_option :without, type: :array, default: [], aliases: "-W", banner: "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"
- Viz.new(options.dup).run
- end
+ desc "viz [OPTIONS]", "Generates a visual dependency graph", hide: true
+ def viz
+ SharedHelpers.feature_removed! "The `viz` command has been renamed to `graph` and moved to a plugin. See https://github.com/rubygems/bundler-graph"
end
desc "gem NAME [OPTIONS]", "Creates a skeleton for creating a rubygem"
@@ -539,7 +581,7 @@ module Bundler
method_option :ext, type: :string, banner: "Generate the boilerplate for C extension code.", enum: EXTENSIONS
method_option :git, type: :boolean, default: true, banner: "Initialize a git repo inside your library."
method_option :mit, type: :boolean, banner: "Generate an MIT license file. Set a default with `bundle config set --global gem.mit true`."
- method_option :rubocop, type: :boolean, banner: "Add rubocop to the generated Rakefile and gemspec. Set a default with `bundle config set --global gem.rubocop true`."
+ method_option :rubocop, type: :boolean, banner: "Add rubocop to the generated Rakefile and gemspec. Set a default with `bundle config set --global gem.rubocop true` (removed)."
method_option :changelog, type: :boolean, banner: "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], banner: "Generate CI configuration, either GitHub Actions, GitLab CI or CircleCI. Set a default with `bundle config set --global gem.ci (github|gitlab|circle)`"
@@ -549,6 +591,10 @@ module Bundler
def gem(name)
require_relative "cli/gem"
+
+ raise InvalidOption, "--rubocop has been removed, use --linter=rubocop" if ARGV.include?("--rubocop")
+ raise InvalidOption, "--no-rubocop has been removed, use --no-linter" if ARGV.include?("--no-rubocop")
+
cmd_args = args + [self]
cmd_args.unshift(options)
@@ -559,7 +605,7 @@ module Bundler
File.expand_path("templates", __dir__)
end
- desc "clean [OPTIONS]", "Cleans up unused gems in your bundler directory", hide: true
+ desc "clean [OPTIONS]", "Cleans up unused gems in your bundler directory"
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
@@ -575,12 +621,8 @@ module Bundler
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"
- def inject(name, version)
- SharedHelpers.major_deprecation 2, "The `inject` command has been replaced by the `add` command"
- require_relative "cli/inject"
- Inject.new(options.dup, name, version).run
+ def inject(*)
+ SharedHelpers.feature_removed! "The `inject` command has been replaced by the `add` command"
end
desc "lock", "Creates a lockfile without installing"
@@ -634,7 +676,7 @@ module Bundler
end
end
- if Bundler.feature_flag.plugins?
+ if Bundler.settings[:plugins]
require_relative "cli/plugin"
desc "plugin", "Manage the bundler plugins"
subcommand "plugin", Plugin
@@ -668,18 +710,15 @@ module Bundler
end
end
- def self.check_deprecated_ext_option(arguments)
- # 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."
+ def self.check_invalid_ext_option(arguments)
+ # when invalid version of `--ext` is called
+ if invalid_ext_value?(arguments)
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
- arguments[arguments.index("--ext")] = "--ext=c"
+ raise InvalidOption, removed_message
end
end
- def self.deprecated_ext_value?(arguments)
+ def self.invalid_ext_value?(arguments)
index = arguments.index("--ext")
next_argument = arguments[index + 1]
@@ -687,15 +726,15 @@ module Bundler
# for example `bundle gem hello --ext c`
return false if EXTENSIONS.include?(next_argument)
- # deprecated call when --ext is called with no value in last position
+ # invalid call when --ext is called with no value in last position
# for example `bundle gem hello_gem --ext`
return true if next_argument.nil?
- # deprecated call when --ext is followed by other parameter
+ # invalid call when --ext is followed by other parameter
# for example `bundle gem --ext --no-ci hello_gem`
return true if next_argument.start_with?("-")
- # deprecated call when --ext is followed by gem name
+ # invalid call when --ext is followed by gem name
# for example `bundle gem --ext hello_gem`
return true if next_argument
@@ -709,6 +748,19 @@ module Bundler
config[:current_command]
end
+ def invoke_other_command(name)
+ _, _, config = @_initializer
+ original_command = config[:current_command]
+ command = self.class.all_commands[name]
+ config[:current_command] = command
+ send(name)
+ ensure
+ config[:current_command] = original_command
+ end
+
+ def current_command=(command)
+ end
+
def print_command
return unless Bundler.ui.debug?
cmd = current_command
@@ -763,17 +815,12 @@ module Bundler
end
def print_remembered_flag_deprecation(flag_name, option_name, option_value)
- message =
- "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
+ "remembered across bundler invocations, which bundler no longer does. " \
+ "Instead please use `bundle config set #{option_name} #{option_value}`, " \
+ "and stop using this flag"
+ raise InvalidOption, removed_message
end
def flag_passed?(name)
diff --git a/lib/bundler/cli/add.rb b/lib/bundler/cli/add.rb
index 12a681a816..20f76b59d1 100644
--- a/lib/bundler/cli/add.rb
+++ b/lib/bundler/cli/add.rb
@@ -14,6 +14,9 @@ module Bundler
def run
Bundler.ui.level = "warn" if options[:quiet]
+ Bundler::CLI::Common.validate_cooldown!(options[:cooldown])
+ Bundler.settings.set_command_option_if_given :cooldown, options[:cooldown]
+
validate_options!
inject_dependencies
perform_bundle_install unless options["skip-install"]
@@ -31,12 +34,22 @@ module Bundler
Injector.inject(dependencies,
conservative_versioning: options[:version].nil?, # Perform conservative versioning only when version is not specified
- optimistic: options[:optimistic],
+ pessimistic: options[:pessimistic],
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 cannot specify `--git` and `--github` at the same time." if options["git"] && options["github"]
+
+ unless options["git"] || options["github"]
+ raise InvalidOption, "You cannot specify `--branch` unless `--git` or `--github` is specified." if options["branch"]
+
+ raise InvalidOption, "You cannot specify `--ref` unless `--git` or `--github` is specified." if options["ref"]
+ end
+
+ raise InvalidOption, "You cannot specify `--branch` and `--ref` at the same time." if options["branch"] && options["ref"]
+
+ raise InvalidOption, "You cannot specify `--strict` and `--pessimistic` at the same time." if options[:strict] && options[:pessimistic]
# raise error when no gems are specified
raise InvalidOption, "Please specify gems to add." if gems.empty?
diff --git a/lib/bundler/cli/cache.rb b/lib/bundler/cli/cache.rb
index 92d7a1c519..59605df847 100644
--- a/lib/bundler/cli/cache.rb
+++ b/lib/bundler/cli/cache.rb
@@ -10,16 +10,12 @@ module Bundler
def run
Bundler.ui.level = "warn" if options[:quiet]
- Bundler.settings.set_command_option_if_given :path, options[:path]
Bundler.settings.set_command_option_if_given :cache_path, options["cache-path"]
- setup_cache_all
install
- custom_path = Bundler.settings[:path] if options[:path]
-
Bundler.settings.temporary(cache_all_platforms: options["all-platforms"]) do
- Bundler.load.cache(custom_path)
+ Bundler.load.cache
end
end
@@ -32,11 +28,5 @@ module Bundler
options["no-cache"] = true
Bundler::CLI::Install.new(options).run
end
-
- def setup_cache_all
- all = options.fetch(:all, Bundler.feature_flag.cache_all? || nil)
-
- Bundler.settings.set_command_option_if_given :cache_all, all
- end
end
end
diff --git a/lib/bundler/cli/common.rb b/lib/bundler/cli/common.rb
index 7608adf2ef..b44fbc3096 100644
--- a/lib/bundler/cli/common.rb
+++ b/lib/bundler/cli/common.rb
@@ -2,6 +2,12 @@
module Bundler
module CLI::Common
+ def self.validate_cooldown!(value)
+ return if value.nil?
+ return if value.is_a?(Integer) && value >= 0
+ raise InvalidOption, "Expected `--cooldown` to be a non-negative integer, got #{value.inspect}"
+ end
+
def self.output_post_install_messages(messages)
return if Bundler.settings["ignore_messages"]
messages.to_a.each do |name, msg|
@@ -94,11 +100,14 @@ module Bundler
end
def self.gem_not_found_message(missing_gem_name, alternatives)
- require_relative "../similarity_detector"
message = "Could not find gem '#{missing_gem_name}'."
alternate_names = alternatives.map {|a| a.respond_to?(:name) ? a.name : a }
- suggestions = SimilarityDetector.new(alternate_names).similar_word_list(missing_gem_name)
- message += "\nDid you mean #{suggestions}?" if suggestions
+ if alternate_names.include?(missing_gem_name.downcase)
+ message += "\nDid you mean '#{missing_gem_name.downcase}'?"
+ elsif defined?(DidYouMean::SpellChecker)
+ suggestions = DidYouMean::SpellChecker.new(dictionary: alternate_names).correct(missing_gem_name)
+ message += "\nDid you mean #{word_list(suggestions)}?" unless suggestions.empty?
+ end
message
end
@@ -134,5 +143,19 @@ module Bundler
clean &&= !Bundler.use_system_gems?
clean
end
+
+ def self.word_list(words)
+ if words.empty?
+ return ""
+ end
+
+ words = words.map {|word| "'#{word}'" }
+
+ if words.length == 1
+ return words[0]
+ end
+
+ [words[0..-2].join(", "), words[-1]].join(" or ")
+ end
end
end
diff --git a/lib/bundler/cli/config.rb b/lib/bundler/cli/config.rb
index d963679085..976cda7484 100644
--- a/lib/bundler/cli/config.rb
+++ b/lib/bundler/cli/config.rb
@@ -26,8 +26,7 @@ module Bundler
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] has been removed. Use `bundle #{new_args.join(" ")}` instead."
- SharedHelpers.major_deprecation 4, message, removed_message: removed_message
+ SharedHelpers.feature_deprecated! message
Base.new(options, name, value, self).run
end
@@ -88,16 +87,21 @@ module Bundler
if value.nil?
warn_unused_scope "Ignoring --#{scope} since no value to set was given"
+ current_value = Bundler.settings[name]
if options[:parseable]
if value = Bundler.settings[name]
Bundler.ui.info("#{name}=#{value}")
end
- return
+ else
+ confirm(name)
end
- confirm(name)
- return
+ if current_value.nil?
+ exit 1
+ else
+ return
+ end
end
Bundler.ui.info(message) if message
diff --git a/lib/bundler/cli/console.rb b/lib/bundler/cli/console.rb
index f6389e8ea0..2d1a2ce458 100644
--- a/lib/bundler/cli/console.rb
+++ b/lib/bundler/cli/console.rb
@@ -21,6 +21,11 @@ module Bundler
get_constant(name)
rescue LoadError
if name == "irb"
+ if defined?(Gem::BUNDLED_GEMS) && Gem::BUNDLED_GEMS.respond_to?(:force_activate)
+ Gem::BUNDLED_GEMS.force_activate "irb"
+ require name
+ return get_constant(name)
+ end
Bundler.ui.error "#{name} is not available"
exit 1
else
diff --git a/lib/bundler/cli/exec.rb b/lib/bundler/cli/exec.rb
index 9428e9db3b..2fdc416286 100644
--- a/lib/bundler/cli/exec.rb
+++ b/lib/bundler/cli/exec.rb
@@ -19,11 +19,13 @@ module Bundler
validate_cmd!
SharedHelpers.set_bundle_environment
if bin_path = Bundler.which(cmd)
- if !Bundler.settings[:disable_exec_load] && ruby_shebang?(bin_path)
- return kernel_load(bin_path, *args)
+ if !Bundler.settings[:disable_exec_load] && directly_loadable?(bin_path)
+ bin_path.delete_suffix!(".bat") if Gem.win_platform?
+ kernel_load(bin_path, *args)
+ else
+ bin_path = "./" + bin_path unless File.absolute_path?(bin_path)
+ kernel_exec(bin_path, *args)
end
- bin_path = "./" + bin_path unless File.absolute_path?(bin_path)
- kernel_exec(bin_path, *args)
else
# exec using the given command
kernel_exec(cmd, *args)
@@ -69,6 +71,29 @@ module Bundler
"#{file} #{args.join(" ")}".strip
end
+ def directly_loadable?(file)
+ if Gem.win_platform?
+ script_wrapper?(file)
+ else
+ ruby_shebang?(file)
+ end
+ end
+
+ def script_wrapper?(file)
+ script_file = file.delete_suffix(".bat")
+ return false unless File.exist?(script_file)
+
+ if File.zero?(script_file)
+ Bundler.ui.warn "#{script_file} is empty"
+ return false
+ end
+
+ header = File.open(file, "r") {|f| f.read(32) }
+ ruby_exe = "#{RbConfig::CONFIG["RUBY_INSTALL_NAME"]}#{RbConfig::CONFIG["EXEEXT"]}"
+ ruby_exe = "ruby.exe" if ruby_exe.empty?
+ header.include?(ruby_exe)
+ end
+
def ruby_shebang?(file)
possibilities = [
"#!/usr/bin/env ruby\n",
diff --git a/lib/bundler/cli/gem.rb b/lib/bundler/cli/gem.rb
index 5b71d71c67..c8c24c8e66 100644
--- a/lib/bundler/cli/gem.rb
+++ b/lib/bundler/cli/gem.rb
@@ -1,7 +1,5 @@
# frozen_string_literal: true
-require "pathname"
-
module Bundler
class CLI
Bundler.require_thor_actions
@@ -9,11 +7,7 @@ module Bundler
end
class CLI::Gem
- TEST_FRAMEWORK_VERSIONS = {
- "rspec" => "3.0",
- "minitest" => "5.16",
- "test-unit" => "3.0",
- }.freeze
+ DEFAULT_GITHUB_USERNAME = "[USERNAME]"
attr_reader :options, :gem_name, :thor, :name, :target, :extension
@@ -26,7 +20,7 @@ module Bundler
thor.destination_root = nil
@name = @gem_name
- @target = SharedHelpers.pwd.join(gem_name)
+ @target = Pathname.new(SharedHelpers.pwd).join(gem_name)
@extension = options[:ext]
@@ -74,7 +68,7 @@ module Bundler
bundle: options[:bundle],
bundler_version: bundler_dependency_version,
git: use_git,
- github_username: github_username.empty? ? "[USERNAME]" : github_username,
+ github_username: github_username.empty? ? DEFAULT_GITHUB_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,
@@ -117,7 +111,6 @@ module Bundler
if test_framework = ask_and_set_test_framework
config[:test] = test_framework
- config[:test_framework_version] = TEST_FRAMEWORK_VERSIONS[test_framework]
case test_framework
when "rspec"
@@ -158,6 +151,9 @@ module Bundler
case config[:ci]
when "github"
templates.merge!("github/workflows/main.yml.tt" => ".github/workflows/main.yml")
+ if extension == "rust"
+ templates.merge!("github/workflows/build-gems.yml.tt" => ".github/workflows/build-gems.yml")
+ end
config[:ignore_paths] << ".github/"
when "gitlab"
templates.merge!("gitlab-ci.yml.tt" => ".gitlab-ci.yml")
@@ -178,12 +174,8 @@ module Bundler
if ask_and_set(:coc, "Do you want to include a code of conduct in gems you generate?",
"Codes of conduct can increase contributions to your project by contributors who " \
- "prefer collaborative, safe spaces. You can read more about the code of conduct at " \
- "contributor-covenant.org. Having a code of conduct means agreeing to the responsibility " \
- "of enforcing it, so be sure that you are prepared to do that. Be sure that your email " \
- "address is specified as a contact in the generated code of conduct so that people know " \
- "who to contact in case of a violation. For suggestions about " \
- "how to enforce codes of conduct, see https://bit.ly/coc-enforcement.")
+ "prefer safe, respectful, productive, and collaborative spaces. \n" \
+ "See https://github.com/ruby/rubygems/blob/master/CODE_OF_CONDUCT.md")
config[:coc] = true
Bundler.ui.info "Code of conduct enabled in config"
templates.merge!("CODE_OF_CONDUCT.md.tt" => "CODE_OF_CONDUCT.md")
@@ -204,12 +196,10 @@ module Bundler
config[:linter] = ask_and_set_linter
case config[:linter]
when "rubocop"
- config[:linter_version] = rubocop_version
Bundler.ui.info "RuboCop enabled in config"
templates.merge!("rubocop.yml.tt" => ".rubocop.yml")
config[:ignore_paths] << ".rubocop.yml"
when "standard"
- config[:linter_version] = standard_version
Bundler.ui.info "Standard enabled in config"
templates.merge!("standard.yml.tt" => ".standard.yml")
config[:ignore_paths] << ".standard.yml"
@@ -232,11 +222,24 @@ module Bundler
templates.merge!(
"Cargo.toml.tt" => "Cargo.toml",
"ext/newgem/Cargo.toml.tt" => "ext/#{name}/Cargo.toml",
+ "ext/newgem/build.rs.tt" => "ext/#{name}/build.rs",
"ext/newgem/extconf-rust.rb.tt" => "ext/#{name}/extconf.rb",
"ext/newgem/src/lib.rs.tt" => "ext/#{name}/src/lib.rs",
)
end
+ if extension == "go"
+ templates.merge!(
+ "ext/newgem/go.mod.tt" => "ext/#{name}/go.mod",
+ "ext/newgem/extconf-go.rb.tt" => "ext/#{name}/extconf.rb",
+ "ext/newgem/newgem.h.tt" => "ext/#{name}/#{underscored_name}.h",
+ "ext/newgem/newgem.go.tt" => "ext/#{name}/#{underscored_name}.go",
+ "ext/newgem/newgem-go.c.tt" => "ext/#{name}/#{underscored_name}.c",
+ )
+
+ config[:go_module_username] = config[:github_username] == DEFAULT_GITHUB_USERNAME ? "username" : config[:github_username]
+ end
+
if target.exist? && !target.directory?
Bundler.ui.error "Couldn't create a new gem named `#{gem_name}` because there's an existing file named `#{gem_name}`."
exit Bundler::BundlerError.all_errors[Bundler::GenericSystemCallError]
@@ -276,13 +279,13 @@ module Bundler
open_editor(options["edit"], target.join("#{name}.gemspec")) if options[:edit]
Bundler.ui.info "\nGem '#{name}' was successfully created. " \
- "For more information on making a RubyGem visit https://bundler.io/guides/creating_gem.html"
+ "For more information on making a RubyGem visit https://guides.rubygems.org/make-your-own-gem/"
end
private
def resolve_name(name)
- SharedHelpers.pwd.join(name).basename.to_s
+ Pathname.new(SharedHelpers.pwd).join(name).basename.to_s
end
def ask_and_set(key, prompt, explanation)
@@ -382,7 +385,6 @@ module Bundler
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?
if linter_template.to_s.empty?
Bundler.ui.info "\nDo you want to add a code linter and formatter to your gem? " \
@@ -415,27 +417,6 @@ module Bundler
linter_template
end
- 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"
- "rubocop"
- else
- Bundler::SharedHelpers.major_deprecation 2,
- "--no-rubocop is deprecated, use --linter",
- removed_message: "--no-rubocop has been removed, 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"
- Bundler.settings["gem.rubocop"] ? "rubocop" : false
- end
- end
-
def bundler_dependency_version
v = Gem::Version.new(Bundler::VERSION)
req = v.segments[0..1]
@@ -449,6 +430,10 @@ module Bundler
exit 1
end
+ if /[A-Z]/.match?(name)
+ Bundler.ui.warn "Gem names with capital letters are not recommended. Please use only lowercase letters, numbers, and hyphens."
+ end
+
constant_name = constant_array.join("::")
existing_constant = constant_array.inject(Object) do |c, s|
@@ -478,14 +463,6 @@ module Bundler
"3.2.0"
end
- def rubocop_version
- "1.21"
- end
-
- def standard_version
- "1.3"
- end
-
def github_username(git_username)
if options[:github_username].nil?
git_username
diff --git a/lib/bundler/cli/inject.rb b/lib/bundler/cli/inject.rb
deleted file mode 100644
index a09d5c6bda..0000000000
--- a/lib/bundler/cli/inject.rb
+++ /dev/null
@@ -1,60 +0,0 @@
-# frozen_string_literal: true
-
-module Bundler
- class CLI::Inject
- attr_reader :options, :name, :version, :group, :source, :gems
- def initialize(options, name, version)
- @options = options
- @name = name
- @version = version || last_version_number
- @group = options[:group].split(",") unless options[:group].nil?
- @source = options[:source]
- @gems = []
- end
-
- def run
- # The required arguments allow Thor to give useful feedback when the arguments
- # are incorrect. This adds those first two arguments onto the list as a whole.
- gems.unshift(source).unshift(group).unshift(version).unshift(name)
-
- # Build an array of Dependency objects out of the arguments
- deps = []
- # when `inject` support addition of more than one gem, then this loop will
- # help. Currently this loop is running once.
- gems.each_slice(4) do |gem_name, gem_version, gem_group, gem_source|
- ops = Gem::Requirement::OPS.map {|key, _val| key }
- has_op = ops.any? {|op| gem_version.start_with? op }
- gem_version = "~> #{gem_version}" unless has_op
- deps << Bundler::Dependency.new(gem_name, gem_version, "group" => gem_group, "source" => gem_source)
- end
-
- added = Injector.inject(deps, options)
-
- if added.any?
- Bundler.ui.confirm "Added to Gemfile:"
- Bundler.ui.confirm(added.map do |d|
- name = "'#{d.name}'"
- requirement = ", '#{d.requirement}'"
- group = ", group: #{d.groups.inspect}" if d.groups != Array(:default)
- source = ", source: '#{d.source}'" unless d.source.nil?
- %(gem #{name}#{requirement}#{group}#{source})
- end.join("\n"))
- else
- Bundler.ui.confirm "All gems were already present in the Gemfile"
- end
- end
-
- private
-
- def last_version_number
- definition = Bundler.definition(true)
- definition.remotely!
- specs = definition.index[name].sort_by(&:version)
- unless options[:pre]
- specs.delete_if {|b| b.respond_to?(:version) && b.version.prerelease? }
- end
- spec = specs.last
- spec.version.to_s
- end
- end
-end
diff --git a/lib/bundler/cli/install.rb b/lib/bundler/cli/install.rb
index 074afd64eb..69affd1a10 100644
--- a/lib/bundler/cli/install.rb
+++ b/lib/bundler/cli/install.rb
@@ -20,56 +20,32 @@ module Bundler
Bundler::SharedHelpers.set_env "RB_USER_INSTALL", "1" if Gem.freebsd_platform?
- # 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 " \
- "before deploying."
- end
-
- options[:local] = true if Bundler.app_cache.exist?
-
- Bundler.settings.set_command_option :deployment, true if options[:deployment]
- Bundler.settings.set_command_option :frozen, true if options[:frozen]
- end
-
- # When install is called with --no-deployment, disable deployment mode
- if options[:deployment] == false
- Bundler.settings.set_command_option :frozen, nil
- options[:system] = true
+ if Bundler.frozen_bundle? && !Bundler.default_lockfile.exist?
+ 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 " \
+ "before deploying."
end
normalize_settings
Bundler::Fetcher.disable_endpoint = options["full-index"]
- 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`"
- end
-
- Plugin.gemfile_install(Bundler.default_gemfile) if Bundler.feature_flag.plugins?
+ Plugin.gemfile_install(Bundler.default_gemfile) if Bundler.settings[:plugins]
# For install we want to enable strict validation
# (rather than some optimizations we perform at app runtime).
definition = Bundler.definition(strict: true)
definition.validate_runtime!
+ definition.lockfile = options["lockfile"] if options["lockfile"]
+ definition.lockfile = false if options["no-lock"]
installer = Installer.install(Bundler.root, definition, options)
@@ -89,8 +65,6 @@ module Bundler
Bundler::CLI::Common.output_post_install_messages installer.post_install_messages
- warn_ambiguous_gems
-
if CLI::Common.clean_after_install?
require_relative "clean"
Bundler::CLI::Clean.new(options).run
@@ -116,26 +90,10 @@ module Bundler
end
def gems_installed_for(definition)
- count = definition.specs.count
+ count = definition.specs.count {|spec| spec.name != "bundler" }
"#{count} #{count == 1 ? "gem" : "gems"} now installed"
end
- def check_for_group_conflicts_in_cli_options
- conflicting_groups = Array(options[:without]) & Array(options[:with])
- return if conflicting_groups.empty?
- raise InvalidOption, "You can't list a group in both with and without." \
- " The offending groups are: #{conflicting_groups.join(", ")}."
- end
-
- def check_for_options_conflicts
- if (options[:path] || options[:deployment]) && options[:system]
- error_message = String.new
- error_message << "You have specified both --path as well as --system. Please choose only one option.\n" if options[:path]
- error_message << "You have specified both --deployment as well as --system. Please choose only one option.\n" if options[:deployment]
- raise InvalidOption.new(error_message)
- end
- end
-
def check_trust_policy
trust_policy = options["trust-policy"]
unless Bundler.rubygems.security_policies.keys.unshift(nil).include?(trust_policy)
@@ -145,55 +103,25 @@ module Bundler
Bundler.settings.set_command_option_if_given :"trust-policy", trust_policy
end
- def normalize_groups
- check_for_group_conflicts_in_cli_options
-
- # need to nil them out first to get around validation for backwards compatibility
- Bundler.settings.set_command_option :without, nil
- Bundler.settings.set_command_option :with, nil
- Bundler.settings.set_command_option :without, options[:without]
- Bundler.settings.set_command_option :with, options[:with]
- end
-
def normalize_settings
- Bundler.settings.set_command_option :path, nil if options[:system]
- Bundler.settings.set_command_option_if_given :path, options[:path]
-
if options["standalone"] && Bundler.settings[:path].nil? && !options["local"]
Bundler.settings.set_command_option :path, "bundle"
end
- bin_option = options["binstubs"]
- bin_option = nil if bin_option&.empty?
- Bundler.settings.set_command_option :bin, bin_option if options["binstubs"]
-
Bundler.settings.set_command_option_if_given :shebang, options["shebang"]
Bundler.settings.set_command_option_if_given :jobs, options["jobs"]
+ Bundler::CLI::Common.validate_cooldown!(options["cooldown"])
+ Bundler.settings.set_command_option_if_given :cooldown, options["cooldown"]
+
Bundler.settings.set_command_option_if_given :no_prune, options["no-prune"]
Bundler.settings.set_command_option_if_given :no_install, options["no-install"]
Bundler.settings.set_command_option_if_given :clean, options["clean"]
- normalize_groups if options[:without] || options[:with]
-
options[:force] = options[:redownload] if options[:redownload]
end
-
- def warn_ambiguous_gems
- # TODO: remove this when we drop Bundler 1.x support
- Installer.ambiguous_gems.to_a.each do |name, installed_from_uri, *also_found_in_uris|
- Bundler.ui.warn "Warning: the gem '#{name}' was found in multiple sources."
- Bundler.ui.warn "Installed from: #{installed_from_uri}"
- Bundler.ui.warn "Also found in:"
- also_found_in_uris.each {|uri| Bundler.ui.warn " * #{uri}" }
- Bundler.ui.warn "You should add a source requirement to restrict this gem to your preferred source."
- Bundler.ui.warn "For example:"
- Bundler.ui.warn " gem '#{name}', :source => '#{installed_from_uri}'"
- Bundler.ui.warn "Then uninstall the gem '#{name}' (or delete all bundled gems) and then install again."
- end
- end
end
end
diff --git a/lib/bundler/cli/issue.rb b/lib/bundler/cli/issue.rb
index fbe9184d12..cbfb7da2d8 100644
--- a/lib/bundler/cli/issue.rb
+++ b/lib/bundler/cli/issue.rb
@@ -10,7 +10,7 @@ module Bundler
be sure to check out these resources:
1. Check out our troubleshooting guide for quick fixes to common issues:
- https://github.com/rubygems/rubygems/blob/master/doc/bundler/TROUBLESHOOTING.md
+ https://github.com/ruby/rubygems/blob/master/doc/bundler/TROUBLESHOOTING.md
2. Instructions for common Bundler uses can be found on the documentation
site: https://bundler.io/
@@ -22,7 +22,7 @@ module Bundler
still aren't working the way you expect them to, please let us know so
that we can diagnose and help fix the problem you're having, by filling
in the new issue form located at
- https://github.com/rubygems/rubygems/issues/new?labels=Bundler&template=bundler-related-issue.md,
+ https://github.com/ruby/rubygems/issues/new?labels=Bundler&template=bundler-related-issue.md,
and copy and pasting the information below.
EOS
diff --git a/lib/bundler/cli/lock.rb b/lib/bundler/cli/lock.rb
index b60c82e3a1..2f78868936 100644
--- a/lib/bundler/cli/lock.rb
+++ b/lib/bundler/cli/lock.rb
@@ -35,11 +35,8 @@ module Bundler
update = { bundler: bundler }
end
- file = options[:lockfile]
- file = file ? Pathname.new(file).expand_path : Bundler.default_lockfile
-
Bundler.settings.temporary(frozen: false) do
- definition = Bundler.definition(update, file)
+ definition = Bundler.definition(update, Bundler.default_lockfile)
definition.add_checksums if options["add-checksums"]
Bundler::CLI::Common.configure_gem_version_promoter(definition, options) if options[:update]
@@ -71,8 +68,11 @@ module Bundler
if print
puts definition.to_lock
else
+ file = options[:lockfile]
+ file = file ? Pathname.new(file).expand_path : Bundler.default_lockfile
+
puts "Writing lockfile to #{file}"
- definition.lock
+ definition.write_lock(file, false)
end
end
diff --git a/lib/bundler/cli/outdated.rb b/lib/bundler/cli/outdated.rb
index 0c8ba3ebf7..465e56ada2 100644
--- a/lib/bundler/cli/outdated.rb
+++ b/lib/bundler/cli/outdated.rb
@@ -26,6 +26,9 @@ module Bundler
def run
check_for_deployment_mode!
+ Bundler::CLI::Common.validate_cooldown!(options[:cooldown])
+ Bundler.settings.set_command_option_if_given :cooldown, options[:cooldown]
+
Bundler.definition.validate_runtime!
current_specs = Bundler.ui.silence { Bundler.definition.resolve }
@@ -199,7 +202,15 @@ module Bundler
end
spec_outdated_info = "#{active_spec.name} (newest #{spec_version}, " \
- "installed #{current_version}#{dependency_version})"
+ "installed #{current_version}#{dependency_version}"
+
+ release_date = release_date_for(active_spec)
+ spec_outdated_info += ", released #{release_date}" unless release_date.empty?
+
+ remaining = cooldown_days_remaining(active_spec)
+ spec_outdated_info += ", in cooldown for #{remaining} more day#{"s" if remaining > 1}" if remaining
+
+ spec_outdated_info += ")"
output_message = if options[:parseable]
spec_outdated_info.to_s
@@ -215,13 +226,25 @@ module Bundler
def gem_column_for(current_spec, active_spec, dependency, groups)
current_version = "#{current_spec.version}#{current_spec.git_version}"
spec_version = "#{active_spec.version}#{active_spec.git_version}"
+ remaining = cooldown_days_remaining(active_spec)
+ spec_version += " (cooldown #{remaining}d)" if remaining
dependency = dependency.requirement if dependency
ret_val = [active_spec.name, current_version, spec_version, dependency.to_s, groups.to_s]
+ ret_val << release_date_for(active_spec)
ret_val << loaded_from_for(active_spec).to_s if Bundler.ui.debug?
ret_val
end
+ def cooldown_days_remaining(spec, now = Time.now)
+ return nil unless spec.respond_to?(:created_at) && spec.created_at
+ return nil unless spec.respond_to?(:remote) && spec.remote
+ days = spec.remote.effective_cooldown
+ return nil if days.nil? || days <= 0
+ remaining = days - ((now - spec.created_at) / 86_400.0)
+ remaining > 0 ? remaining.ceil : nil
+ end
+
def check_for_deployment_mode!
return unless Bundler.frozen_bundle?
suggested_command = if Bundler.settings.locations("frozen").keys.&([:global, :local]).any?
@@ -283,11 +306,28 @@ module Bundler
end
def table_header
- header = ["Gem", "Current", "Latest", "Requested", "Groups"]
+ header = ["Gem", "Current", "Latest", "Requested", "Groups", "Release Date"]
header << "Path" if Bundler.ui.debug?
header
end
+ def release_date_for(spec)
+ return "" unless spec.respond_to?(:date)
+
+ date = spec.date
+ return "" unless date
+
+ return "" unless Gem.const_defined?(:DEFAULT_SOURCE_DATE_EPOCH)
+ default_date = Time.at(Gem::DEFAULT_SOURCE_DATE_EPOCH).utc
+ default_date = Time.utc(default_date.year, default_date.month, default_date.day)
+
+ date = date.utc if date.respond_to?(:utc)
+
+ return "" if date == default_date
+
+ date.strftime("%Y-%m-%d")
+ end
+
def justify(row, sizes)
row.each_with_index.map do |element, index|
element.ljust(sizes[index])
diff --git a/lib/bundler/cli/plugin.rb b/lib/bundler/cli/plugin.rb
index fd61ef0d95..32fa660fe0 100644
--- a/lib/bundler/cli/plugin.rb
+++ b/lib/bundler/cli/plugin.rb
@@ -10,11 +10,15 @@ module Bundler
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 "local_git", type: :string, default: nil, banner: "Path of the local git repo to fetch from (removed)"
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"
def install(*plugins)
+ if options.key?(:local_git)
+ raise InvalidOption, "--local_git has been removed, use --git"
+ end
+
Bundler::Plugin.install(plugins, options)
end
diff --git a/lib/bundler/cli/pristine.rb b/lib/bundler/cli/pristine.rb
index cfd4a995a3..f463f0bce8 100644
--- a/lib/bundler/cli/pristine.rb
+++ b/lib/bundler/cli/pristine.rb
@@ -11,6 +11,7 @@ module Bundler
definition = Bundler.definition
definition.validate_runtime!
installer = Bundler::Installer.new(Bundler.root, definition)
+ git_sources = []
ProcessLock.lock do
installed_specs = definition.specs.reject do |spec|
@@ -41,6 +42,9 @@ module Bundler
end
FileUtils.rm_rf spec.extension_dir
FileUtils.rm_rf spec.full_gem_path
+
+ next if git_sources.include?(source)
+ git_sources << source
else
Bundler.ui.warn("Cannot pristine #{gem_name}. Gem is sourced from local path.")
next
@@ -49,7 +53,7 @@ module Bundler
true
end.map(&:name)
- jobs = installer.send(:installation_parallelization)
+ jobs = Bundler.settings.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
diff --git a/lib/bundler/cli/show.rb b/lib/bundler/cli/show.rb
index b55eb7bad5..67fdcc797e 100644
--- a/lib/bundler/cli/show.rb
+++ b/lib/bundler/cli/show.rb
@@ -6,7 +6,7 @@ module Bundler
def initialize(options, gem_name)
@options = options
@gem_name = gem_name
- @verbose = options[:verbose] || options[:outdated]
+ @verbose = options[:verbose]
@latest_specs = fetch_latest_specs if @verbose
end
diff --git a/lib/bundler/cli/update.rb b/lib/bundler/cli/update.rb
index 13f576cfa7..d92ffd995f 100644
--- a/lib/bundler/cli/update.rb
+++ b/lib/bundler/cli/update.rb
@@ -15,7 +15,7 @@ module Bundler
Bundler.self_manager.update_bundler_and_restart_with_it_if_needed(update_bundler) if update_bundler
- Plugin.gemfile_install(Bundler.default_gemfile) if Bundler.feature_flag.plugins?
+ Plugin.gemfile_install(Bundler.default_gemfile) if Bundler.settings[:plugins]
sources = Array(options[:source])
groups = Array(options[:group]).map(&:to_sym)
@@ -23,10 +23,10 @@ module Bundler
full_update = gems.empty? && sources.empty? && groups.empty? && !options[:ruby] && !update_bundler
if full_update && !options[:all]
- if Bundler.feature_flag.update_requires_all_flag?
+ if Bundler.settings[:update_requires_all_flag]
raise InvalidOption, "To update everything, pass the `--all` flag."
end
- SharedHelpers.major_deprecation 4, "Pass --all to `bundle update` to update everything"
+ SharedHelpers.feature_deprecated! "Pass --all to `bundle update` to update everything"
elsif !full_update && options[:all]
raise InvalidOption, "Cannot specify --all along with specific options."
end
@@ -66,6 +66,8 @@ module Bundler
opts["force"] = options[:redownload] if options[:redownload]
Bundler.settings.set_command_option_if_given :jobs, opts["jobs"]
+ Bundler::CLI::Common.validate_cooldown!(options[:cooldown])
+ Bundler.settings.set_command_option_if_given :cooldown, options[:cooldown]
Bundler.definition.validate_runtime!
diff --git a/lib/bundler/cli/viz.rb b/lib/bundler/cli/viz.rb
deleted file mode 100644
index 5c09e00995..0000000000
--- a/lib/bundler/cli/viz.rb
+++ /dev/null
@@ -1,31 +0,0 @@
-# frozen_string_literal: true
-
-module Bundler
- class CLI::Viz
- attr_reader :options, :gem_name
- def initialize(options)
- @options = options
- end
-
- def run
- # make sure we get the right `graphviz`. There is also a `graphviz`
- # gem we're not built to support
- gem "ruby-graphviz"
- require "graphviz"
-
- options[:without] = options[:without].join(":").tr(" ", ":").split(":")
- output_file = File.expand_path(options[:file])
-
- graph = Graph.new(Bundler.load, output_file, options[:version], options[:requirements], options[:format], options[:without])
- graph.viz
- rescue LoadError => e
- Bundler.ui.error e.inspect
- Bundler.ui.warn "Make sure you have the graphviz ruby gem. You can install it with:"
- Bundler.ui.warn "`gem install ruby-graphviz`"
- rescue StandardError => e
- raise unless e.message.to_s.include?("GraphViz not installed or dot not in PATH")
- Bundler.ui.error e.message
- Bundler.ui.warn "Please install GraphViz. On a Mac with Homebrew, you can run `brew install graphviz`."
- end
- end
-end
diff --git a/lib/bundler/compact_index_client.rb b/lib/bundler/compact_index_client.rb
index 37e2ccced8..6865e30dbc 100644
--- a/lib/bundler/compact_index_client.rb
+++ b/lib/bundler/compact_index_client.rb
@@ -1,6 +1,5 @@
# frozen_string_literal: true
-require "pathname"
require "set"
module Bundler
diff --git a/lib/bundler/compact_index_client/parser.rb b/lib/bundler/compact_index_client/parser.rb
index 43581fd7ef..ad0d17ed4a 100644
--- a/lib/bundler/compact_index_client/parser.rb
+++ b/lib/bundler/compact_index_client/parser.rb
@@ -71,7 +71,10 @@ module Bundler
# 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_start = line.index(" ", name_end + 1)
+ return unless checksum_start
+ checksum_start += 1
+
checksum_end = line.size - checksum_start
line.freeze # allows slicing into the string to not allocate a copy of the line
diff --git a/lib/bundler/current_ruby.rb b/lib/bundler/current_ruby.rb
index faec695369..17c7655adb 100644
--- a/lib/bundler/current_ruby.rb
+++ b/lib/bundler/current_ruby.rb
@@ -11,7 +11,7 @@ module Bundler
end
class CurrentRuby
- ALL_RUBY_VERSIONS = (18..27).to_a.concat((30..35).to_a).freeze
+ ALL_RUBY_VERSIONS = [*18..27, *30..34, *40..41].freeze
KNOWN_MINOR_VERSIONS = ALL_RUBY_VERSIONS.map {|v| v.digits.reverse.join(".") }.freeze
KNOWN_MAJOR_VERSIONS = ALL_RUBY_VERSIONS.map {|v| v.digits.last.to_s }.uniq.freeze
PLATFORM_MAP = {
@@ -50,19 +50,10 @@ module Bundler
end
def maglev?
- message =
- "`CurrentRuby#maglev?` is deprecated with no replacement. Please use the " \
- "built-in Ruby `RUBY_ENGINE` constant to check the Ruby implementation you are running on."
removed_message =
"`CurrentRuby#maglev?` was removed with no replacement. Please use the " \
"built-in Ruby `RUBY_ENGINE` constant to check the Ruby implementation you are running on."
- internally_exempted = caller_locations(1, 1).first.path == __FILE__
-
- unless internally_exempted
- SharedHelpers.major_deprecation(2, message, removed_message: removed_message, print_caller_location: true)
- end
-
- RUBY_ENGINE == "maglev"
+ SharedHelpers.feature_removed!(removed_message)
end
def truffleruby?
@@ -90,14 +81,11 @@ module Bundler
end
define_method(:"maglev_#{trimmed_version}?") do
- message =
- "`CurrentRuby##{__method__}` is deprecated with no replacement. Please use the " \
- "built-in Ruby `RUBY_ENGINE` and `RUBY_VERSION` constants to perform a similar check."
removed_message =
"`CurrentRuby##{__method__}` was removed with no replacement. Please use the " \
"built-in Ruby `RUBY_ENGINE` and `RUBY_VERSION` constants to perform a similar check."
- SharedHelpers.major_deprecation(2, message, removed_message: removed_message, print_caller_location: true)
+ SharedHelpers.feature_removed!(removed_message)
send(:"maglev?") && send(:"on_#{trimmed_version}?")
end
diff --git a/lib/bundler/definition.rb b/lib/bundler/definition.rb
index 52f9c6e125..7a95671471 100644
--- a/lib/bundler/definition.rb
+++ b/lib/bundler/definition.rb
@@ -1,6 +1,7 @@
# frozen_string_literal: true
require_relative "lockfile_parser"
+require_relative "worker"
module Bundler
class Definition
@@ -9,11 +10,14 @@ module Bundler
attr_accessor :no_lock
end
+ attr_writer :lockfile, :overrides
+
attr_reader(
:dependencies,
:locked_checksums,
:locked_deps,
:locked_gems,
+ :overrides,
:platforms,
:ruby_version,
:lockfile,
@@ -34,7 +38,10 @@ module Bundler
raise GemfileNotFound, "#{gemfile} not found" unless gemfile.file?
- Dsl.evaluate(gemfile, lockfile, unlock)
+ Plugin.hook(Plugin::Events::GEM_BEFORE_EVAL, gemfile, lockfile)
+ Dsl.evaluate(gemfile, lockfile, unlock).tap do |definition|
+ Plugin.hook(Plugin::Events::GEM_AFTER_EVAL, definition)
+ end
end
#
@@ -55,7 +62,7 @@ module Bundler
# to be updated or true if all gems should be updated
# @param ruby_version [Bundler::RubyVersion, nil] Requested Ruby Version
# @param optional_groups [Array(String)] A list of optional groups
- def initialize(lockfile, dependencies, sources, unlock, ruby_version = nil, optional_groups = [], gemfiles = [])
+ def initialize(lockfile, dependencies, sources, unlock, ruby_version = nil, optional_groups = [], gemfiles = [], overrides = [])
unlock ||= {}
if unlock == true
@@ -85,6 +92,7 @@ module Bundler
@specs = nil
@ruby_version = ruby_version
@gemfiles = gemfiles
+ @overrides = overrides
@lockfile = lockfile
@lockfile_contents = String.new
@@ -106,7 +114,9 @@ module Bundler
@locked_bundler_version = @locked_gems.bundler_version
@locked_ruby_version = @locked_gems.ruby_version
@locked_deps = @locked_gems.dependencies
+ Override.attach(@locked_gems.specs, @overrides)
@originally_locked_specs = SpecSet.new(@locked_gems.specs)
+ @originally_locked_sources = @locked_gems.sources
@locked_checksums = @locked_gems.checksums
if @unlocking_all
@@ -114,7 +124,16 @@ module Bundler
@locked_sources = []
else
@locked_specs = @originally_locked_specs
- @locked_sources = @locked_gems.sources
+ @locked_sources = @originally_locked_sources
+ end
+
+ locked_gem_sources = @originally_locked_sources.select {|s| s.is_a?(Source::Rubygems) }
+ multisource_lockfile = locked_gem_sources.size == 1 && locked_gem_sources.first.multiple_remotes?
+
+ if multisource_lockfile
+ msg = "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::SharedHelpers.feature_removed! msg
end
else
@locked_gems = nil
@@ -123,22 +142,10 @@ module Bundler
@platforms = []
@locked_deps = {}
@locked_specs = SpecSet.new([])
- @originally_locked_specs = @locked_specs
@locked_sources = []
- @locked_checksums = Bundler.feature_flag.lockfile_checksums?
- end
-
- locked_gem_sources = @locked_sources.select {|s| s.is_a?(Source::Rubygems) }
- @multisource_allowed = locked_gem_sources.size == 1 && locked_gem_sources.first.multiple_remotes? && Bundler.frozen_bundle?
-
- if @multisource_allowed
- unless sources.aggregate_global_source?
- msg = "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::SharedHelpers.major_deprecation 2, msg
- end
-
- @sources.merged_gem_lockfile_sections!(locked_gem_sources.first)
+ @originally_locked_specs = @locked_specs
+ @originally_locked_sources = @locked_sources
+ @locked_checksums = Bundler.settings[:lockfile_checksums]
end
@unlocking_ruby ||= if @ruby_version && locked_ruby_version_object
@@ -189,12 +196,14 @@ module Bundler
def setup_domain!(options = {})
prefer_local! if options[:"prefer-local"]
+ sources.cached!
+
if options[:add_checksums] || (!options[:local] && install_needed?)
- remotely!
+ sources.remote!
true
else
Bundler.settings.set_command_option(:jobs, 1) unless install_needed? # to avoid the overhead of Bundler::Worker
- with_cache!
+ sources.local!
false
end
end
@@ -246,6 +255,7 @@ module Bundler
end
def missing_specs
+ preload_git_sources
resolve.missing_specs_for(requested_dependencies)
end
@@ -282,12 +292,17 @@ module Bundler
end
def filter_relevant(dependencies)
- platforms_array = [Bundler.generic_local_platform].freeze
dependencies.select do |d|
- d.should_include? && !d.gem_platforms(platforms_array).empty?
+ relevant_deps?(d)
end
end
+ def relevant_deps?(dep)
+ platforms_array = [Bundler.generic_local_platform].freeze
+
+ dep.should_include? && !dep.gem_platforms(platforms_array).empty?
+ end
+
def locked_dependencies
@locked_deps.values
end
@@ -367,12 +382,50 @@ module Bundler
msg = "`Definition#lock` was passed a target file argument. #{suggestion}"
- Bundler::SharedHelpers.major_deprecation 2, msg
+ Bundler::SharedHelpers.feature_removed! msg
end
write_lock(target_lockfile, preserve_unknown_sections)
end
+ def write_lock(file, preserve_unknown_sections)
+ return if Definition.no_lock || !lockfile || 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
+
+ begin
+ SharedHelpers.filesystem_access(file) do |p|
+ File.open(p, "wb") {|f| f.puts(contents) }
+ end
+ rescue ReadOnlyFileSystemError
+ raise ProductionError, lockfile_changes_summary("file system is read-only")
+ end
+ end
+
def locked_ruby_version
return unless ruby_version
if @unlocking_ruby || !@locked_ruby_version
@@ -440,12 +493,6 @@ module Bundler
"Your Ruby version is #{actual}, but your Gemfile specified #{expected}"
when :engine_version
"Your #{Bundler::RubyVersion.system.engine} version is #{actual}, but your Gemfile specified #{ruby_version.engine} #{expected}"
- when :patchlevel
- if !expected.is_a?(String)
- "The Ruby patchlevel in your Gemfile must be a string"
- else
- "Your Ruby patchlevel is #{actual}, but your Gemfile specified #{expected}"
- end
end
raise RubyVersionMismatch, msg
@@ -493,11 +540,24 @@ module Bundler
end
def add_checksums
+ require "rubygems/package"
+
@locked_checksums = true
setup_domain!(add_checksums: true)
- specs # force materialization to real specifications, so that checksums are fetched
+ # force materialization to real specifications, so that checksums are fetched
+ specs.each do |spec|
+ next unless spec.source.is_a?(Bundler::Source::Rubygems)
+ # Checksum was fetched from the compact index API.
+ next if !spec.source.checksum_store.missing?(spec) && !spec.source.checksum_store.empty?(spec)
+ # The gem isn't installed, can't compute the checksum.
+ next unless spec.loaded_from
+
+ package = Gem::Package.new(spec.source.cached_built_in_gem(spec))
+ checksum = Checksum.from_gem_package(package)
+ spec.source.checksum_store.register(spec, checksum)
+ end
end
private
@@ -574,50 +634,25 @@ module Bundler
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
-
- begin
- SharedHelpers.filesystem_access(file) do |p|
- File.open(p, "wb") {|f| f.puts(contents) }
- end
- rescue ReadOnlyFileSystemError
- raise ProductionError, lockfile_changes_summary("file system is read-only")
- end
- end
-
def resolver
@resolver ||= new_resolver(resolution_base)
end
def expanded_dependencies
- dependencies_with_bundler + metadata_dependencies
+ apply_overrides_to(dependencies_with_bundler) + metadata_dependencies
+ end
+
+ def apply_overrides_to(deps)
+ return deps if @overrides.empty?
+ deps.map {|dep| apply_override_to(dep) }
+ end
+
+ def apply_override_to(dep)
+ override = Override.find_for(@overrides, dep.name, :version)
+ return dep unless override
+ new_dep = dep.dup
+ new_dep.instance_variable_set(:@requirement, override.apply_to(dep.requirement))
+ new_dep
end
def dependencies_with_bundler
@@ -761,7 +796,25 @@ module Bundler
end
def precompute_source_requirements_for_indirect_dependencies?
- sources.non_global_rubygems_sources.all?(&:dependency_api_available?) && !sources.aggregate_global_source?
+ if sources.non_global_rubygems_sources.all?(&:dependency_api_available?)
+ true
+ else
+ non_dependency_api_warning
+ false
+ end
+ end
+
+ def non_dependency_api_warning
+ non_api_sources = sources.non_global_rubygems_sources.reject(&:dependency_api_available?)
+ non_api_source_names = non_api_sources.map {|d| " * #{d}" }.join("\n")
+
+ msg = String.new
+ msg << "Your Gemfile contains scoped sources that don't implement a dependency API, namely:\n\n"
+ msg << non_api_source_names
+ msg << "\n\nUsing the above gem servers may result in installing unexpected gems. " \
+ "To resolve this warning, make sure you use gem servers that implement dependency APIs, " \
+ "such as gemstash or geminabox gem servers."
+ Bundler.ui.warn msg
end
def current_platform_locked?
@@ -952,7 +1005,7 @@ module Bundler
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) }
+ if @locked_checksums && @locked_gems && locked_source = @originally_locked_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
@@ -966,6 +1019,8 @@ module Bundler
end
end
+ sources.metadata_source.checksum_store.merge!(@locked_gems.metadata_source.checksum_store) if @locked_gems
+
changes
end
@@ -973,10 +1028,11 @@ module Bundler
@missing_lockfile_dep = nil
@changed_dependencies = []
- current_dependencies.each do |dep|
+ @dependencies.each do |dep|
if dep.source
dep.source = sources.get(dep.source)
end
+ next unless relevant_deps?(dep)
name = dep.name
@@ -992,7 +1048,7 @@ module Bundler
@locked_specs.delete(locked_specs.select {|s| s.source != dep.source })
end
- unless dep.matches_spec?(locked_specs.first)
+ unless apply_override_to(dep).matches_spec?(locked_specs.first)
@gems_to_unlock << name
dep_changed = true
end
@@ -1002,9 +1058,32 @@ module Bundler
@changed_dependencies << name if dep_changed
end
+ converge_overrides_outside_dependencies
+
@changed_dependencies.any?
end
+ def converge_overrides_outside_dependencies
+ @overrides.each do |override|
+ # :all overrides are intentionally not pre-unlocked. They take effect on
+ # fresh resolution (no lockfile) or when the user runs `bundle update`.
+ # Forcing a full re-resolve from a single :all directive would surprise
+ # users with unrelated dependency churn.
+ next unless override.target.is_a?(String)
+
+ name = override.target
+ next if @changed_dependencies.include?(name)
+ next if @originally_locked_specs[name].empty?
+ # version: overrides on direct deps are detected in the per-dep
+ # converge_dependencies loop via apply_override_to + matches_spec?.
+ # Other fields are not visible there, so they always reach here.
+ next if override.field == :version && @dependencies.any? {|d| d.name == name }
+
+ @gems_to_unlock << name
+ @changed_dependencies << name
+ end
+ end
+
# Remove elements from the locked specs that are expired. This will most
# commonly happen if the Gemfile has changed since the lockfile was last
# generated
@@ -1034,6 +1113,8 @@ module Bundler
specs.each do |s|
name = s.name
+ next if @gems_to_unlock.include?(name)
+
dep = @dependencies.find {|d| s.satisfies?(d) }
lockfile_source = s.source
@@ -1042,17 +1123,33 @@ module Bundler
deps << dep if !replacement_source || lockfile_source.include?(replacement_source) || new_deps.include?(dep)
else
- replacement_source = sources.get(lockfile_source)
+ parent_dep = @dependencies.find do |d|
+ next unless d.source && d.source != lockfile_source
+ next if d.source.is_a?(Source::Gemspec)
+
+ parent_locked_specs = @originally_locked_specs[d.name]
+
+ parent_locked_specs.any? do |parent_spec|
+ parent_spec.runtime_dependencies.any? {|rd| rd.name == s.name }
+ end
+ end
+
+ if parent_dep && parent_dep.source.is_a?(Source::Path) && parent_dep.source.specs[s]&.any?
+ replacement_source = parent_dep.source
+ else
+ replacement_source = sources.get(lockfile_source)
+ end
end
# Replace the locked dependency's source with the equivalent source from the Gemfile
s.source = replacement_source || default_source
+ next if s.source_changed?
source = s.source
next if @sources_to_unlock.include?(source.name)
# Path sources have special logic
- if source.instance_of?(Source::Path) || source.instance_of?(Source::Gemspec) || (source.instance_of?(Source::Git) && !@gems_to_unlock.include?(name) && deps.include?(dep))
+ if source.is_a?(Source::Path)
new_spec = source.specs[s].first
if new_spec
s.runtime_dependencies.replace(new_spec.runtime_dependencies)
@@ -1080,17 +1177,56 @@ module Bundler
@source_requirements ||= find_source_requirements
end
+ def preload_git_source_worker
+ workers = Bundler.settings.installation_parallelization
+
+ @preload_git_source_worker ||= Bundler::Worker.new(workers, "Git source preloading", ->(source, _) { source.specs })
+ end
+
+ def preload_git_sources
+ if Gem.ruby_version < Gem::Version.new("3.3")
+ # Ruby 3.2 has a bug that incorrectly triggers a circular dependency warning. This version will continue to
+ # fetch git repositories one by one.
+ return
+ end
+
+ begin
+ needed_git_sources.each {|source| preload_git_source_worker.enq(source) }
+ ensure
+ preload_git_source_worker.stop
+ end
+ end
+
+ # Git sources needed for the requested groups (excludes sources only used by --without groups)
+ def needed_git_sources
+ needed_deps = dependencies_for(requested_groups)
+ sources.git_sources.select do |source|
+ needed_deps.any? {|d| d.source == source }
+ end
+ end
+
+ # Git sources that should be excluded (only used by --without groups)
+ def excluded_git_sources
+ sources.git_sources - needed_git_sources
+ end
+
def find_source_requirements
+ preload_git_sources
+
+ # Only safe to exclude when locked_requirements (merged below) backfills the gap.
+ nothing_changed = nothing_changed?
+ excluded = nothing_changed ? excluded_git_sources : []
+
# 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
+ all_requirements = source_map.all_requirements(excluded)
{ 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, excluded) }.merge(source_map.direct_requirements)
end
- source_requirements.merge!(source_map.locked_requirements) if nothing_changed?
+ source_requirements.merge!(source_map.locked_requirements) if nothing_changed
metadata_dependencies.each do |dep|
source_requirements[dep.name] = sources.metadata_source
end
@@ -1132,9 +1268,9 @@ module Bundler
end
def additional_base_requirements_to_prevent_downgrades(resolution_base)
- return resolution_base unless @locked_gems && !sources.expired_sources?(@locked_gems.sources)
+ return resolution_base unless @locked_gems
@originally_locked_specs.each do |locked_spec|
- next if locked_spec.source.is_a?(Source::Path)
+ next if locked_spec.source.is_a?(Source::Path) || locked_spec.source_changed?
name = locked_spec.name
next if @changed_dependencies.include?(name)
@@ -1183,7 +1319,7 @@ module Bundler
def new_resolution_base(last_resolve:, unlock:)
new_resolution_platforms = @current_platform_missing ? @new_platforms + [Bundler.local_platform] : @new_platforms
- Resolver::Base.new(source_requirements, expanded_dependencies, last_resolve, @platforms, locked_specs: @originally_locked_specs, unlock: unlock, prerelease: gem_version_promoter.pre?, prefer_local: @prefer_local, new_platforms: new_resolution_platforms)
+ Resolver::Base.new(source_requirements, expanded_dependencies, last_resolve, @platforms, locked_specs: @originally_locked_specs, unlock: unlock, prerelease: gem_version_promoter.pre?, prefer_local: @prefer_local, new_platforms: new_resolution_platforms, overrides: @overrides)
end
def new_resolver(base)
diff --git a/lib/bundler/deployment.rb b/lib/bundler/deployment.rb
index b432ae6ae1..3344449e82 100644
--- a/lib/bundler/deployment.rb
+++ b/lib/bundler/deployment.rb
@@ -1,69 +1,6 @@
# frozen_string_literal: true
require_relative "shared_helpers"
-Bundler::SharedHelpers.major_deprecation 2, "Bundler no longer integrates with " \
+Bundler::SharedHelpers.feature_removed! "Bundler no longer integrates with " \
"Capistrano, but Capistrano provides its own integration with " \
"Bundler via the capistrano-bundler gem. Use it instead."
-
-module Bundler
- class Deployment
- def self.define_task(context, task_method = :task, opts = {})
- if defined?(Capistrano) && context.is_a?(Capistrano::Configuration)
- context_name = "capistrano"
- role_default = "{:except => {:no_release => true}}"
- error_type = ::Capistrano::CommandError
- else
- context_name = "vlad"
- role_default = "[:app]"
- error_type = ::Rake::CommandFailedError
- end
-
- roles = context.fetch(:bundle_roles, false)
- opts[:roles] = roles if roles
-
- context.send :namespace, :bundle do
- send :desc, <<-DESC
- Install the current Bundler environment. By default, gems will be \
- installed to the shared/bundle path. Gems in the development and \
- test group will not be installed. The install command is executed \
- with the --deployment and --quiet flags. If the bundle cmd cannot \
- be found then you can override the bundle_cmd variable to specify \
- which one it should use. The base path to the app is fetched from \
- the :latest_release variable. Set it for custom deploy layouts.
-
- You can override any of these defaults by setting the variables shown below.
-
- N.B. bundle_roles must be defined before you require 'bundler/#{context_name}' \
- in your deploy.rb file.
-
- set :bundle_gemfile, "Gemfile"
- set :bundle_dir, File.join(fetch(:shared_path), 'bundle')
- set :bundle_flags, "--deployment --quiet"
- set :bundle_without, [:development, :test]
- set :bundle_with, [:mysql]
- set :bundle_cmd, "bundle" # e.g. "/opt/ruby/bin/bundle"
- set :bundle_roles, #{role_default} # e.g. [:app, :batch]
- DESC
- send task_method, :install, opts do
- bundle_cmd = context.fetch(:bundle_cmd, "bundle")
- bundle_flags = context.fetch(:bundle_flags, "--deployment --quiet")
- bundle_dir = context.fetch(:bundle_dir, File.join(context.fetch(:shared_path), "bundle"))
- bundle_gemfile = context.fetch(:bundle_gemfile, "Gemfile")
- bundle_without = [*context.fetch(:bundle_without, [:development, :test])].compact
- bundle_with = [*context.fetch(:bundle_with, [])].compact
- app_path = context.fetch(:latest_release)
- if app_path.to_s.empty?
- raise error_type.new("Cannot detect current release path - make sure you have deployed at least once.")
- end
- args = ["--gemfile #{File.join(app_path, bundle_gemfile)}"]
- args << "--path #{bundle_dir}" unless bundle_dir.to_s.empty?
- args << bundle_flags.to_s
- args << "--without #{bundle_without.join(" ")}" unless bundle_without.empty?
- args << "--with #{bundle_with.join(" ")}" unless bundle_with.empty?
-
- run "cd #{app_path} && #{bundle_cmd} install #{args.join(" ")}"
- end
- end
- end
- end
-end
diff --git a/lib/bundler/digest.rb b/lib/bundler/digest.rb
index 2c6d971f1b..158803033d 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
diff --git a/lib/bundler/dsl.rb b/lib/bundler/dsl.rb
index 4f9fbc55b1..6e2638a8be 100644
--- a/lib/bundler/dsl.rb
+++ b/lib/bundler/dsl.rb
@@ -9,8 +9,9 @@ module Bundler
def self.evaluate(gemfile, lockfile, unlock)
builder = new
+ builder.lockfile(lockfile)
builder.eval_gemfile(gemfile)
- builder.to_definition(lockfile, unlock)
+ builder.to_definition(builder.lockfile_path, unlock)
end
VALID_PLATFORMS = Bundler::CurrentRuby::PLATFORM_MAP.keys.freeze
@@ -21,7 +22,7 @@ module Bundler
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}
- attr_reader :gemspecs, :gemfile
+ attr_reader :gemspecs, :gemfile, :overrides
attr_accessor :dependencies
def initialize
@@ -38,6 +39,8 @@ module Bundler
@gemspecs = []
@gemfile = nil
@gemfiles = []
+ @lockfile = nil
+ @overrides = []
add_git_sources
end
@@ -101,10 +104,23 @@ module Bundler
add_dependency(name, version, options)
end
+ # For usage in Dsl.evaluate, since lockfile is used as part of the Gemfile.
+ def lockfile_path
+ @lockfile
+ end
+
+ def lockfile(file)
+ @lockfile = file
+ end
+
def source(source, *args, &blk)
options = args.last.is_a?(Hash) ? args.pop.dup : {}
options = normalize_hash(options)
source = normalize_source(source)
+ cooldown = options["cooldown"]
+ if cooldown && !(cooldown.is_a?(Integer) && cooldown >= 0)
+ raise InvalidOption, "Expected `cooldown` to be a non-negative integer, got #{cooldown.inspect}"
+ end
if options.key?("type")
options["type"] = options["type"].to_s
@@ -119,9 +135,9 @@ module Bundler
source_opts = options.merge("uri" => source)
with_source(@sources.add_plugin_source(options["type"], source_opts), &blk)
elsif block_given?
- with_source(@sources.add_rubygems_source("remotes" => source), &blk)
+ with_source(@sources.add_rubygems_source("remotes" => source, "cooldown" => cooldown), &blk)
else
- @sources.add_global_rubygems_remote(source)
+ @sources.add_global_rubygems_remote(source, cooldown: cooldown)
end
end
@@ -173,9 +189,32 @@ module Bundler
with_source(git_source) { yield }
end
+ SUPPORTED_OVERRIDE_FIELDS = [:version, :required_ruby_version, :required_rubygems_version].freeze
+ SUPPORTED_OVERRIDE_SYMBOL_OPERATIONS = [:ignore_upper].freeze
+
+ def override(target, **operations)
+ validate_override_target!(target)
+
+ if target == :all && operations.key?(:version)
+ raise ArgumentError, "`override :all, version:` is not allowed; version requirements are per-gem"
+ end
+
+ operations.each do |field, operation|
+ validate_override_field!(field)
+ validate_override_operation!(operation)
+ validate_override_uniqueness!(target, field)
+ end
+
+ source_location = caller_locations(1, 1)&.first
+ operations.each do |field, operation|
+ @overrides << Override.new(target, field, operation, source_location: source_location)
+ end
+ end
+
def to_definition(lockfile, unlock)
check_primary_source_safety
- Definition.new(lockfile, @dependencies, @sources, unlock, @ruby_version, @optional_groups, @gemfiles)
+ lockfile = @lockfile unless @lockfile.nil?
+ Definition.new(lockfile, @dependencies, @sources, unlock, @ruby_version, @optional_groups, @gemfiles, @overrides)
end
def group(*args, &blk)
@@ -232,6 +271,39 @@ module Bundler
private
+ def validate_override_target!(target)
+ return if target == :all
+ return if target.is_a?(String)
+ raise ArgumentError, "override target must be :all or a gem name string, got #{target.inspect}"
+ end
+
+ def validate_override_field!(field)
+ return if SUPPORTED_OVERRIDE_FIELDS.include?(field)
+ supported = SUPPORTED_OVERRIDE_FIELDS.map {|f| "`#{f}:`" }.join(", ")
+ raise ArgumentError, "unsupported override field `#{field}:`; supported fields: #{supported}"
+ end
+
+ def validate_override_operation!(operation)
+ case operation
+ when String
+ Gem::Requirement.new(operation)
+ when nil
+ # ok
+ when Symbol
+ return if SUPPORTED_OVERRIDE_SYMBOL_OPERATIONS.include?(operation)
+ raise ArgumentError, "unsupported override operation: #{operation.inspect}"
+ else
+ raise ArgumentError, "override operation must be a String, Symbol, or nil, got #{operation.inspect}"
+ end
+ rescue Gem::Requirement::BadRequirementError => e
+ raise ArgumentError, "invalid override version requirement #{operation.inspect}: #{e.message}"
+ end
+
+ def validate_override_uniqueness!(target, field)
+ return unless @overrides.any? {|o| o.target == target && o.field == field }
+ raise ArgumentError, "duplicate override for #{target.inspect} `#{field}:`"
+ end
+
def add_dependency(name, version = nil, options = {})
options["gemfile"] = @gemfile
options["source"] ||= @source
@@ -290,7 +362,7 @@ module Bundler
@dependencies.delete(current)
elsif dep.gemspec_dev_dep?
return
- elsif current.source != dep.source
+ elsif current.source.to_s != dep.source.to_s
raise GemfileError, "You cannot specify the same gem twice coming from different sources.\n" \
"You specified that #{name} (#{dep.requirement}) should come from " \
"#{current.source || "an unspecified source"} and #{dep.source}\n"
@@ -411,7 +483,13 @@ module Bundler
next if VALID_PLATFORMS.include?(p)
raise GemfileError, "`#{p}` is not a valid platform. The available options are: #{VALID_PLATFORMS.inspect}"
end
- deprecate_legacy_windows_platforms(platforms)
+
+ windows_platforms = platforms.select {|pl| pl.to_s.match?(/mingw|mswin/) }
+ if windows_platforms.any?
+ windows_platforms = windows_platforms.map! {|pl| ":#{pl}" }.join(", ")
+ deprecated_message = "Platform #{windows_platforms} will be removed in the future. Please use platform :windows instead."
+ Bundler::SharedHelpers.feature_deprecated! deprecated_message
+ end
# Save sources passed in a key
if opts.key?("source")
@@ -477,14 +555,10 @@ 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
- "http://rubygems.org"
+ Bundler::SharedHelpers.feature_removed! removed_message
when String
source
else
@@ -492,16 +566,6 @@ module Bundler
end
end
- def deprecate_legacy_windows_platforms(platforms)
- windows_platforms = platforms.select {|pl| pl.to_s.match?(/mingw|mswin/) }
- return if windows_platforms.empty?
-
- windows_platforms = windows_platforms.map! {|pl| ":#{pl}" }.join(", ")
- message = "Platform #{windows_platforms} is deprecated. Please use platform :windows instead."
- removed_message = "Platform #{windows_platforms} has been removed. Please use platform :windows instead."
- Bundler::SharedHelpers.major_deprecation 2, message, removed_message: removed_message
- end
-
def check_path_source_safety
return if @sources.global_path_source.nil?
@@ -513,7 +577,7 @@ module Bundler
" gem 'rails'\n" \
" end\n\n"
- SharedHelpers.major_deprecation(2, msg.strip)
+ SharedHelpers.feature_removed! msg.strip
end
def check_rubygems_source_safety
@@ -521,24 +585,10 @@ module Bundler
end
def multiple_global_source_warning
- if Bundler.feature_flag.bundler_4_mode?
- msg = "This Gemfile contains multiple global sources. " \
- "Each source after the first must include a block to indicate which gems " \
- "should come from that source"
- raise GemfileEvalError, msg
- else
- 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 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
+ msg = "This Gemfile contains multiple global sources. " \
+ "Each source after the first must include a block to indicate which gems " \
+ "should come from that source"
+ raise GemfileEvalError, msg
end
class DSLError < GemfileError
diff --git a/lib/bundler/endpoint_specification.rb b/lib/bundler/endpoint_specification.rb
index c06684657d..7c7ce107e2 100644
--- a/lib/bundler/endpoint_specification.rb
+++ b/lib/bundler/endpoint_specification.rb
@@ -5,7 +5,7 @@ module Bundler
class EndpointSpecification < Gem::Specification
include MatchRemoteMetadata
- attr_reader :name, :version, :platform, :checksum
+ attr_reader :name, :version, :platform, :checksum, :created_at
attr_writer :dependencies
attr_accessor :remote, :locked_platform
@@ -145,6 +145,7 @@ module Bundler
unless data
@required_ruby_version = nil
@required_rubygems_version = nil
+ @created_at = nil
return
end
@@ -161,6 +162,15 @@ module Bundler
@required_rubygems_version = Gem::Requirement.new(v)
when "ruby"
@required_ruby_version = Gem::Requirement.new(v)
+ when "created_at"
+ value = v.is_a?(Array) ? v.last : v
+ if value.is_a?(String)
+ @created_at = begin
+ Time.new(value)
+ rescue ArgumentError
+ nil
+ end
+ end
end
end
rescue StandardError => e
diff --git a/lib/bundler/env.rb b/lib/bundler/env.rb
index 074bef6edc..2b29705060 100644
--- a/lib/bundler/env.rb
+++ b/lib/bundler/env.rb
@@ -78,17 +78,6 @@ module Bundler
"not installed"
end
- def self.version_of(script)
- return "not installed" unless Bundler.which(script)
- `#{script} --version`.chomp
- end
-
- def self.chruby_version
- return "not installed" unless Bundler.which("chruby-exec")
- `chruby-exec -- chruby --version`.
- sub(/.*^chruby: (#{Gem::Version::VERSION_PATTERN}).*/m, '\1')
- end
-
def self.environment
out = []
@@ -110,16 +99,8 @@ module Bundler
out << [" Cert File", OpenSSL::X509::DEFAULT_CERT_FILE] if defined?(OpenSSL::X509::DEFAULT_CERT_FILE)
out << [" Cert Dir", OpenSSL::X509::DEFAULT_CERT_DIR] if defined?(OpenSSL::X509::DEFAULT_CERT_DIR)
end
- out << ["Tools"]
- out << [" Git", git_version]
- out << [" RVM", ENV.fetch("rvm_version") { version_of("rvm") }]
- out << [" rbenv", version_of("rbenv")]
- out << [" chruby", chruby_version]
-
- %w[rubygems-bundler open_gem].each do |name|
- specs = Bundler.rubygems.find_name(name)
- out << [" #{name}", "(#{specs.map(&:version).join(",")})"] unless specs.empty?
- end
+ out << ["Git", git_version]
+
if (exe = caller_locations.last.absolute_path)&.match? %r{(exe|bin)/bundler?\z}
shebang = File.read(exe).lines.first
shebang.sub!(/^#!\s*/, "")
@@ -143,6 +124,6 @@ module Bundler
out << "```\n"
end
- private_class_method :read_file, :ruby_version, :git_version, :append_formatted_table, :version_of, :chruby_version
+ private_class_method :read_file, :ruby_version, :git_version, :append_formatted_table
end
end
diff --git a/lib/bundler/environment_preserver.rb b/lib/bundler/environment_preserver.rb
index 444ab6fd37..bf9478a299 100644
--- a/lib/bundler/environment_preserver.rb
+++ b/lib/bundler/environment_preserver.rb
@@ -6,6 +6,7 @@ module Bundler
BUNDLER_KEYS = %w[
BUNDLE_BIN_PATH
BUNDLE_GEMFILE
+ BUNDLE_LOCKFILE
BUNDLER_VERSION
BUNDLER_SETUP
GEM_HOME
diff --git a/lib/bundler/errors.rb b/lib/bundler/errors.rb
index 4d1bface51..dff5d93128 100644
--- a/lib/bundler/errors.rb
+++ b/lib/bundler/errors.rb
@@ -25,6 +25,7 @@ module Bundler
class GemNotFound < BundlerError; status_code(7); end
class InstallHookError < BundlerError; status_code(8); end
+ class RemovedError < BundlerError; status_code(9); end
class GemfileNotFound < BundlerError; status_code(10); end
class GitError < BundlerError; status_code(11); end
class DeprecatedError < BundlerError; status_code(12); end
@@ -76,11 +77,6 @@ module Bundler
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
@@ -135,7 +131,8 @@ module Bundler
attr_reader :orig_exception
def initialize(orig_exception, msg)
- full_message = msg + "\nGem Load Error is: #{orig_exception.message}\n"\
+ full_message = msg + "\nGem Load Error is:
+ #{orig_exception.full_message(highlight: false)}\n"\
"Backtrace for gem load error is:\n"\
"#{orig_exception.backtrace.join("\n")}\n"\
"Bundler Error Backtrace:\n"
@@ -225,7 +222,9 @@ module Bundler
class DirectoryRemovalError < BundlerError
def initialize(orig_exception, msg)
full_message = "#{msg}.\n" \
- "The underlying error was #{orig_exception.class}: #{orig_exception.message}, with backtrace:\n" \
+ "The underlying error was #{orig_exception.class}:
+ #{orig_exception.full_message(highlight: false)},
+ with backtrace:\n" \
" #{orig_exception.backtrace.join("\n ")}\n\n" \
"Bundler Error Backtrace:"
super(full_message)
@@ -266,14 +265,40 @@ module Bundler
class InvalidArgumentError < BundlerError; status_code(40); end
class IncorrectLockfileDependencies < BundlerError
- attr_reader :spec
+ attr_reader :spec, :actual_dependencies, :lockfile_dependencies
- def initialize(spec)
+ def initialize(spec, actual_dependencies = nil, lockfile_dependencies = nil)
@spec = spec
+ @actual_dependencies = actual_dependencies
+ @lockfile_dependencies = lockfile_dependencies
end
def message
- "Bundler found incorrect dependencies in the lockfile for #{spec.full_name}"
+ lines = ["Bundler found incorrect dependencies in the lockfile for #{spec.full_name}", ""]
+
+ if @actual_dependencies && @lockfile_dependencies
+ actual_by_name = @actual_dependencies.each_with_object({}) {|d, h| h[d.name] = d }
+ lockfile_by_name = @lockfile_dependencies.each_with_object({}) {|d, h| h[d.name] = d }
+
+ (actual_by_name.keys | lockfile_by_name.keys).sort.each do |name|
+ actual = actual_by_name[name]
+ lockfile = lockfile_by_name[name]
+ next if actual && lockfile && actual.requirement == lockfile.requirement
+
+ if actual && lockfile
+ lines << " #{name}: gemspec specifies #{actual.requirement}, lockfile has #{lockfile.requirement}"
+ elsif actual
+ lines << " #{name}: gemspec specifies #{actual.requirement}, not in lockfile"
+ else
+ lines << " #{name}: not in gemspec, lockfile has #{lockfile.requirement}"
+ end
+ end
+
+ lines << ""
+ end
+
+ lines << "Please run `bundle install` to regenerate the lockfile."
+ lines.join("\n")
end
status_code(41)
diff --git a/lib/bundler/feature_flag.rb b/lib/bundler/feature_flag.rb
index 2cf58eefd6..dea8abedba 100644
--- a/lib/bundler/feature_flag.rb
+++ b/lib/bundler/feature_flag.rb
@@ -2,41 +2,8 @@
module Bundler
class FeatureFlag
- def self.settings_flag(flag, &default)
- unless Bundler::Settings::BOOL_KEYS.include?(flag.to_s)
- raise "Cannot use `#{flag}` as a settings feature flag since it isn't a bool key"
- end
-
- settings_method("#{flag}?", flag, &default)
- end
- private_class_method :settings_flag
-
- def self.settings_option(key, &default)
- settings_method(key, key, &default)
- end
- private_class_method :settings_option
-
- def self.settings_method(name, key, &default)
- define_method(name) do
- value = Bundler.settings[key]
- value = instance_eval(&default) if value.nil?
- value
- end
- end
- private_class_method :settings_method
-
(1..10).each {|v| define_method("bundler_#{v}_mode?") { @major_version >= v } }
- settings_flag(:allow_offline_install) { bundler_4_mode? }
- settings_flag(:cache_all) { bundler_4_mode? }
- settings_flag(:forget_cli_options) { bundler_4_mode? }
- settings_flag(:global_gem_cache) { bundler_5_mode? }
- settings_flag(:lockfile_checksums) { bundler_4_mode? }
- settings_flag(:plugins) { @bundler_version >= Gem::Version.new("1.14") }
- settings_flag(:update_requires_all_flag) { bundler_5_mode? }
-
- settings_option(:default_cli_command) { bundler_4_mode? ? :cli_help : :install }
-
def removed_major?(target_major_version)
@major_version > target_major_version
end
diff --git a/lib/bundler/fetcher/compact_index.rb b/lib/bundler/fetcher/compact_index.rb
index 6c82d57011..52168111fe 100644
--- a/lib/bundler/fetcher/compact_index.rb
+++ b/lib/bundler/fetcher/compact_index.rb
@@ -110,7 +110,7 @@ module Bundler
def call(path, headers)
fetcher.downloader.fetch(fetcher.fetch_uri + path, headers)
rescue NetworkDownError => e
- raise unless Bundler.feature_flag.allow_offline_install? && headers["If-None-Match"]
+ raise unless 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)
end
diff --git a/lib/bundler/fetcher/dependency.rb b/lib/bundler/fetcher/dependency.rb
index 994b415e9c..4f2414e33d 100644
--- a/lib/bundler/fetcher/dependency.rb
+++ b/lib/bundler/fetcher/dependency.rb
@@ -50,7 +50,7 @@ module Bundler
def unmarshalled_dep_gems(gem_names)
gem_list = []
- gem_names.each_slice(Source::Rubygems::API_REQUEST_SIZE) do |names|
+ gem_names.each_slice(api_request_size) do |names|
marshalled_deps = downloader.fetch(dependency_api_uri(names)).body
gem_list.concat(Bundler.safe_load_marshal(marshalled_deps))
end
@@ -74,6 +74,12 @@ module Bundler
uri.query = "gems=#{CGI.escape(gem_names.sort.join(","))}" if gem_names.any?
uri
end
+
+ private
+
+ def api_request_size
+ Bundler.settings[:api_request_size]&.to_i || Source::Rubygems::API_REQUEST_SIZE
+ end
end
end
end
diff --git a/lib/bundler/fetcher/downloader.rb b/lib/bundler/fetcher/downloader.rb
index 2eac6e7975..179eed8340 100644
--- a/lib/bundler/fetcher/downloader.rb
+++ b/lib/bundler/fetcher/downloader.rb
@@ -54,7 +54,6 @@ module Bundler
when Gem::Net::HTTPRequestedRangeNotSatisfiable
new_headers = headers.dup
new_headers.delete("Range")
- new_headers["Accept-Encoding"] = "gzip"
fetch(uri, new_headers)
when Gem::Net::HTTPRequestEntityTooLarge
raise FallbackError, response.body
diff --git a/lib/bundler/fetcher/gem_remote_fetcher.rb b/lib/bundler/fetcher/gem_remote_fetcher.rb
index 3fc7b68263..3159e05688 100644
--- a/lib/bundler/fetcher/gem_remote_fetcher.rb
+++ b/lib/bundler/fetcher/gem_remote_fetcher.rb
@@ -5,6 +5,12 @@ require "rubygems/remote_fetcher"
module Bundler
class Fetcher
class GemRemoteFetcher < Gem::RemoteFetcher
+ def initialize(*)
+ super
+
+ @pool_size = Bundler.settings.installation_parallelization
+ end
+
def request(*args)
super do |req|
req.delete("User-Agent") if headers["User-Agent"]
diff --git a/lib/bundler/friendly_errors.rb b/lib/bundler/friendly_errors.rb
index 8a5ab2e025..5e8eaee6bb 100644
--- a/lib/bundler/friendly_errors.rb
+++ b/lib/bundler/friendly_errors.rb
@@ -104,12 +104,12 @@ module Bundler
message = message.split("-").first if exception.is_a?(Errno)
require "cgi/escape"
require "cgi/util" unless defined?(CGI::EscapeExt)
- "https://github.com/rubygems/rubygems/search?q=" \
+ "https://github.com/ruby/rubygems/search?q=" \
"#{CGI.escape(message)}&type=Issues"
end
def new_issue_url
- "https://github.com/rubygems/rubygems/issues/new?labels=Bundler&template=bundler-related-issue.md"
+ "https://github.com/ruby/rubygems/issues/new?labels=Bundler&template=bundler-related-issue.md"
end
end
diff --git a/lib/bundler/graph.rb b/lib/bundler/graph.rb
deleted file mode 100644
index b22b17a453..0000000000
--- a/lib/bundler/graph.rb
+++ /dev/null
@@ -1,152 +0,0 @@
-# frozen_string_literal: true
-
-require "set"
-module Bundler
- class Graph
- GRAPH_NAME = :Gemfile
-
- def initialize(env, output_file, show_version = false, show_requirements = false, output_format = "png", without = [])
- @env = env
- @output_file = output_file
- @show_version = show_version
- @show_requirements = show_requirements
- @output_format = output_format
- @without_groups = without.map(&:to_sym)
-
- @groups = []
- @relations = Hash.new {|h, k| h[k] = Set.new }
- @node_options = {}
- @edge_options = {}
-
- _populate_relations
- end
-
- attr_reader :groups, :relations, :node_options, :edge_options, :output_file, :output_format
-
- def viz
- GraphVizClient.new(self).run
- end
-
- private
-
- def _populate_relations
- parent_dependencies = _groups.values.to_set.flatten
- loop do
- break if parent_dependencies.empty?
-
- tmp = Set.new
- parent_dependencies.each do |dependency|
- child_dependencies = spec_for_dependency(dependency).runtime_dependencies.to_set
- @relations[dependency.name] += child_dependencies.map(&:name).to_set
- tmp += child_dependencies
-
- @node_options[dependency.name] = _make_label(dependency, :node)
- child_dependencies.each do |c_dependency|
- @edge_options["#{dependency.name}_#{c_dependency.name}"] = _make_label(c_dependency, :edge)
- end
- end
- parent_dependencies = tmp
- end
- end
-
- def _groups
- relations = Hash.new {|h, k| h[k] = Set.new }
- @env.current_dependencies.each do |dependency|
- dependency.groups.each do |group|
- next if @without_groups.include?(group)
-
- relations[group.to_s].add(dependency)
- @relations[group.to_s].add(dependency.name)
-
- @node_options[group.to_s] ||= _make_label(group, :node)
- @edge_options["#{group}_#{dependency.name}"] = _make_label(dependency, :edge)
- end
- end
- @groups = relations.keys
- relations
- end
-
- def _make_label(symbol_or_string_or_dependency, element_type)
- case element_type.to_sym
- when :node
- if symbol_or_string_or_dependency.is_a?(Gem::Dependency)
- label = symbol_or_string_or_dependency.name.dup
- label << "\n#{spec_for_dependency(symbol_or_string_or_dependency).version}" if @show_version
- else
- label = symbol_or_string_or_dependency.to_s
- end
- when :edge
- label = nil
- if symbol_or_string_or_dependency.respond_to?(:requirements_list) && @show_requirements
- tmp = symbol_or_string_or_dependency.requirements_list.join(", ")
- label = tmp if tmp != ">= 0"
- end
- else
- raise ArgumentError, "2nd argument is invalid"
- end
- label.nil? ? {} : { label: label }
- end
-
- def spec_for_dependency(dependency)
- @env.requested_specs.find {|s| s.name == dependency.name }
- end
-
- class GraphVizClient
- def initialize(graph_instance)
- @graph_name = graph_instance.class::GRAPH_NAME
- @groups = graph_instance.groups
- @relations = graph_instance.relations
- @node_options = graph_instance.node_options
- @edge_options = graph_instance.edge_options
- @output_file = graph_instance.output_file
- @output_format = graph_instance.output_format
- end
-
- def 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
- end
- end
-
- def run
- @groups.each do |group|
- g.add_nodes(
- group, {
- style: "filled",
- fillcolor: "#B9B9D5",
- shape: "box3d",
- fontsize: 16,
- }.merge(@node_options[group])
- )
- end
-
- @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}"]))
- else
- g.add_nodes(child, @node_options[child])
- g.add_edges(parent, child, @edge_options["#{parent}_#{child}"])
- end
- end
- end
-
- if @output_format.to_s == "debug"
- $stdout.puts g.output none: String
- Bundler.ui.info "debugging bundle viz..."
- else
- begin
- g.output @output_format.to_sym => "#{@output_file}.#{@output_format}"
- Bundler.ui.info "#{@output_file}.#{@output_format}"
- rescue ArgumentError => e
- warn "Unsupported output format. See Ruby-Graphviz/lib/graphviz/constants.rb"
- raise e
- end
- end
- end
- end
- end
-end
diff --git a/lib/bundler/index.rb b/lib/bundler/index.rb
index d591b34cc7..9aef2dfa12 100644
--- a/lib/bundler/index.rb
+++ b/lib/bundler/index.rb
@@ -46,13 +46,6 @@ 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) }
- end
-
# Search this index's specs, and any source indexes that this index knows
# about, returning all of the results.
def search(query)
diff --git a/lib/bundler/injector.rb b/lib/bundler/injector.rb
index 21ff90ad13..6aa9179024 100644
--- a/lib/bundler/injector.rb
+++ b/lib/bundler/injector.rb
@@ -80,20 +80,19 @@ module Bundler
def conservative_version(spec)
version = spec.version
return ">= 0" if version.nil?
- 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?
- "#{version_prefix}#{segments[0..seg_end_index].join(".")}#{prerelease_suffix}"
+ "#{version_prefix}#{version.segments[0..seg_end_index].join(".")}#{prerelease_suffix}"
end
def version_prefix
if @options[:strict]
"= "
- elsif @options[:optimistic]
- ">= "
- else
+ elsif @options[:pessimistic]
"~> "
+ else
+ ">= "
end
end
diff --git a/lib/bundler/inline.rb b/lib/bundler/inline.rb
index f2f5b22cd3..a1b8e0475e 100644
--- a/lib/bundler/inline.rb
+++ b/lib/bundler/inline.rb
@@ -44,14 +44,16 @@ def gemfile(force_latest_compatible = false, options = {}, &gemfile)
raise ArgumentError, "Unknown options: #{opts.keys.join(", ")}" unless opts.empty?
old_gemfile = ENV["BUNDLE_GEMFILE"]
+ old_lockfile = ENV["BUNDLE_LOCKFILE"]
Bundler.unbundle_env!
begin
Bundler.instance_variable_set(:@bundle_path, Pathname.new(Gem.dir))
Bundler::SharedHelpers.set_env "BUNDLE_GEMFILE", "Gemfile"
+ Bundler::SharedHelpers.set_env "BUNDLE_LOCKFILE", "Gemfile.lock"
- Bundler::Plugin.gemfile_install(&gemfile) if Bundler.feature_flag.plugins?
+ Bundler::Plugin.gemfile_install(&gemfile) if Bundler.settings[:plugins]
builder = Bundler::Dsl.new
builder.instance_eval(&gemfile)
@@ -60,14 +62,53 @@ def gemfile(force_latest_compatible = false, options = {}, &gemfile)
definition.validate_runtime!
if force_latest_compatible || definition.missing_specs?
- 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}"
+ do_install = -> do
+ 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
+
+ # When possible we do the install in a subprocess because to install
+ # gems we need to require some default gems like `securerandom` etc
+ # which may later conflict with the Gemfile requirements.
+ installed_in_fork = false
+ if Process.respond_to?(:fork)
+ Gem.load_yaml # Avoid NameError on Ruby 3.2's safe_yaml.rb after Gem::Specification.reset
+ _, status = Process.waitpid2(Process.fork do
+ $VERBOSE = nil
+ do_install.call end)
+ exit(status.exitstatus || status.to_i) unless status.success?
+
+ installed_in_fork = true
+
+ Bundler.reset!
+ Gem::Specification.reset
+ Bundler.instance_variable_set(:@bundle_path, Pathname.new(Gem.dir))
+
+ builder = Bundler::Dsl.new
+ builder.instance_eval(&gemfile)
+ builder.check_primary_source_safety
+
+ definition = builder.to_definition(nil, true)
+ definition.validate_runtime!
+ else
+ do_install.call
+ end
end
+ configure_forked_definition = ->(d) do
+ d.sources.rubygems_sources.each(&:remote!)
+ d.sources.git_sources.each do |source|
+ source.cached!
+ source.instance_variable_set(:@copied, true)
+ end
+ def d.lock(*); end
+ end
+ configure_forked_definition.call(definition) if installed_in_fork
+
begin
runtime = Bundler::Runtime.new(nil, definition).setup
rescue Gem::LoadError => e
@@ -82,6 +123,7 @@ def gemfile(force_latest_compatible = false, options = {}, &gemfile)
builder.dependencies.delete_if {|d| d.name == name }
builder.instance_eval { gem name, activated_version }
definition = builder.to_definition(nil, true)
+ configure_forked_definition.call(definition) if installed_in_fork
retry
end
@@ -94,5 +136,11 @@ def gemfile(force_latest_compatible = false, options = {}, &gemfile)
else
ENV["BUNDLE_GEMFILE"] = ""
end
+
+ if old_lockfile
+ ENV["BUNDLE_LOCKFILE"] = old_lockfile
+ else
+ ENV["BUNDLE_LOCKFILE"] = ""
+ end
end
end
diff --git a/lib/bundler/installer.rb b/lib/bundler/installer.rb
index d41740a411..87d9a75627 100644
--- a/lib/bundler/installer.rb
+++ b/lib/bundler/installer.rb
@@ -7,12 +7,6 @@ require_relative "installer/gem_installer"
module Bundler
class Installer
- class << self
- attr_accessor :ambiguous_gems
-
- Installer.ambiguous_gems = []
- end
-
attr_reader :post_install_messages, :definition
# Begins the installation process for Bundler.
@@ -69,6 +63,11 @@ module Bundler
Bundler.create_bundle_path
ProcessLock.lock do
+ # Invalidate any stale gem specification cache from before we acquired the lock.
+ # Another process may have installed gems while we were waiting.
+ Gem::Specification.reset
+ @definition.sources.clear_cache
+
@definition.ensure_equivalent_gemfile_and_lockfile(options[:deployment])
if @definition.dependencies.empty?
@@ -195,21 +194,13 @@ module Bundler
standalone = options[:standalone]
force = options[:force]
local = options[:local] || options[:"prefer-local"]
- jobs = installation_parallelization
+ jobs = Bundler.settings.installation_parallelization
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
end
- def installation_parallelization
- if jobs = Bundler.settings[:jobs]
- return jobs
- end
-
- Bundler.settings.processor_count
- end
-
def load_plugins
Gem.load_plugins
@@ -225,12 +216,13 @@ module Bundler
end
def ensure_specs_are_compatible!
+ overrides = @definition.overrides
@definition.specs.each do |spec|
- unless spec.matches_current_ruby?
+ unless spec.matches_current_ruby_with_overrides?(overrides)
raise InstallError, "#{spec.full_name} requires ruby version #{spec.required_ruby_version}, " \
"which is incompatible with the current version, #{Gem.ruby_version}"
end
- unless spec.matches_current_rubygems?
+ unless spec.matches_current_rubygems_with_overrides?(overrides)
raise InstallError, "#{spec.full_name} requires rubygems version #{spec.required_rubygems_version}, " \
"which is incompatible with the current version, #{Gem.rubygems_version}"
end
diff --git a/lib/bundler/installer/gem_installer.rb b/lib/bundler/installer/gem_installer.rb
index 1da91857bd..f3b43c31ee 100644
--- a/lib/bundler/installer/gem_installer.rb
+++ b/lib/bundler/installer/gem_installer.rb
@@ -16,7 +16,6 @@ module Bundler
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
raise
@@ -26,6 +25,20 @@ module Bundler
[false, specific_failure_message(e)]
end
+ def download
+ spec.source.download(
+ spec,
+ force: force,
+ local: local,
+ build_args: Array(spec_settings),
+ previous_spec: previous_spec,
+ )
+
+ [true, nil]
+ rescue Bundler::BundlerError => e
+ [false, specific_failure_message(e)]
+ end
+
private
def specific_failure_message(e)
@@ -71,15 +84,5 @@ module Bundler
def out_of_space_message
"#{install_error_message}\nYour disk is out of space. Free some space to be able to install your bundle."
end
-
- def generate_executable_stubs
- return if Bundler.feature_flag.forget_cli_options?
- return if Bundler.settings[:inline]
- if Bundler.settings[:bin] && standalone
- installer.generate_standalone_bundler_executable_stubs(spec)
- elsif Bundler.settings[:bin]
- installer.generate_bundler_executable_stubs(spec, force: true)
- end
- end
end
end
diff --git a/lib/bundler/installer/parallel_installer.rb b/lib/bundler/installer/parallel_installer.rb
index d10e5ec924..fef326ed0a 100644
--- a/lib/bundler/installer/parallel_installer.rb
+++ b/lib/bundler/installer/parallel_installer.rb
@@ -6,7 +6,7 @@ require_relative "gem_installer"
module Bundler
class ParallelInstaller
class SpecInstallation
- attr_accessor :spec, :name, :full_name, :post_install_message, :state, :error
+ attr_accessor :spec, :name, :full_name, :post_install_message, :state, :error, :dependencies
def initialize(spec)
@spec = spec
@name = spec.name
@@ -24,6 +24,10 @@ module Bundler
state == :enqueued
end
+ def enqueue_with_priority?
+ state == :installable && spec.extensions.any?
+ end
+
def failed?
state == :failed
end
@@ -32,29 +36,21 @@ module Bundler
state == :none
end
- def has_post_install_message?
- !post_install_message.empty?
- end
-
- def ignorable_dependency?(dep)
- dep.type == :development || dep.name == @name
- end
+ def ready_to_install?(installed_specs)
+ return false unless state == :downloaded
- # Checks installed dependencies against spec's dependencies to make
- # sure needed dependencies have been installed.
- def dependencies_installed?(installed_specs)
- dependencies.all? {|d| installed_specs.include? d.name }
+ spec.extensions.none? || dependencies_installed?(installed_specs)
end
- # Represents only the non-development dependencies, the ones that are
- # itself and are in the total list.
- def dependencies
- @dependencies ||= all_dependencies.reject {|dep| ignorable_dependency? dep }
+ def has_post_install_message?
+ !post_install_message.empty?
end
- # Represents all dependencies
- def all_dependencies
- @spec.dependencies
+ # Recursively checks that all dependencies (direct and transitive) have been installed.
+ def dependencies_installed?(installed_specs)
+ dependencies.all? do |dep|
+ installed_specs.include?(dep.name) && dep.dependencies_installed?(installed_specs)
+ end
end
def to_s
@@ -75,6 +71,12 @@ module Bundler
@force = force
@local = local
@specs = all_specs.map {|s| SpecInstallation.new(s) }
+ specs_by_name = @specs.to_h {|s| [s.name, s] }
+ @specs.each do |spec_install|
+ spec_install.dependencies = spec_install.spec.dependencies.filter_map do |dep|
+ specs_by_name[dep.name] unless dep.type == :development || dep.name == spec_install.name
+ end
+ end
@specs.each do |spec_install|
spec_install.state = :installed if skip.include?(spec_install.name)
end if skip
@@ -84,6 +86,7 @@ module Bundler
def call
if @rake
+ do_download(@rake, 0)
do_install(@rake, 0)
Gem::Specification.reset
end
@@ -107,26 +110,54 @@ module Bundler
end
def install_with_worker
- enqueue_specs
- process_specs until finished_installing?
+ installed_specs = {}
+ enqueue_specs(installed_specs)
+
+ process_specs(installed_specs) until finished_installing?
end
def install_serially
until finished_installing?
raise "failed to find a spec to enqueue while installing serially" unless spec_install = @specs.find(&:ready_to_enqueue?)
spec_install.state = :enqueued
+ do_download(spec_install, 0)
do_install(spec_install, 0)
end
end
def worker_pool
@worker_pool ||= Bundler::Worker.new @size, "Parallel Installer", lambda {|spec_install, worker_num|
- do_install(spec_install, worker_num)
+ case spec_install.state
+ when :enqueued
+ do_download(spec_install, worker_num)
+ when :installable
+ do_install(spec_install, worker_num)
+ else
+ spec_install
+ end
}
end
- def do_install(spec_install, worker_num)
+ def do_download(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
+ )
+
+ success, message = gem_installer.download
+
+ if success
+ spec_install.state = :downloaded
+ else
+ spec_install.error = "#{message}\n\n#{require_tree_for_spec(spec_install.spec)}"
+ spec_install.state = :failed
+ end
+
+ spec_install
+ end
+
+ def do_install(spec_install, worker_num)
gem_installer = Bundler::GemInstaller.new(
spec_install.spec, @installer, @standalone, worker_num, @force, @local
)
@@ -147,9 +178,19 @@ module Bundler
# Some specs might've had to wait til this spec was installed to be
# processed so the call to `enqueue_specs` is important after every
# dequeue.
- def process_specs
- worker_pool.deq
- enqueue_specs
+ def process_specs(installed_specs)
+ spec = worker_pool.deq
+
+ if spec.installed?
+ installed_specs[spec.name] = true
+ return
+ elsif spec.failed?
+ return
+ elsif spec.ready_to_install?(installed_specs)
+ spec.state = :installable
+ end
+
+ worker_pool.enq(spec, priority: spec.enqueue_with_priority?)
end
def finished_installing?
@@ -185,18 +226,15 @@ module Bundler
# Later we call this lambda again to install specs that depended on
# previously installed specifications. We continue until all specs
# are installed.
- def enqueue_specs
- installed_specs = {}
+ 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)
- spec.state = :enqueued
- worker_pool.enq spec
+ if spec.installed?
+ installed_specs[spec.name] = true
+ next
end
+
+ spec.state = :enqueued
+ worker_pool.enq spec
end
end
end
diff --git a/lib/bundler/lazy_specification.rb b/lib/bundler/lazy_specification.rb
index 81ded54797..0da621d21f 100644
--- a/lib/bundler/lazy_specification.rb
+++ b/lib/bundler/lazy_specification.rb
@@ -9,7 +9,7 @@ module Bundler
include ForcePlatform
attr_reader :name, :version, :platform, :materialization
- attr_accessor :source, :remote, :force_ruby_platform, :dependencies, :required_ruby_version, :required_rubygems_version
+ attr_accessor :source, :remote, :force_ruby_platform, :dependencies, :required_ruby_version, :required_rubygems_version, :overrides
#
# For backwards compatibility with existing lockfiles, if the most specific
@@ -30,6 +30,7 @@ module Bundler
lazy_spec.dependencies = s.runtime_dependencies
lazy_spec.required_ruby_version = s.required_ruby_version
lazy_spec.required_rubygems_version = s.required_rubygems_version
+ lazy_spec.overrides = s.overrides if s.is_a?(LazySpecification)
lazy_spec
end
@@ -138,24 +139,16 @@ module Bundler
source.local!
if use_exact_resolved_specifications?
- materialize(self) do |matching_specs|
- choose_compatible(matching_specs)
- end
- else
- materialize([name, version]) do |matching_specs|
- target_platform = source.is_a?(Source::Path) ? platform : Bundler.local_platform
-
- installable_candidates = MatchPlatform.select_best_platform_match(matching_specs, target_platform)
-
- specification = choose_compatible(installable_candidates, fallback_to_non_installable: false)
- return specification unless specification.nil?
+ spec = materialize(self) {|specs| choose_compatible(specs, fallback_to_non_installable: false) }
+ return spec if spec
- if target_platform != platform
- installable_candidates = MatchPlatform.select_best_platform_match(matching_specs, platform)
- end
-
- choose_compatible(installable_candidates)
+ # Exact spec is incompatible; in frozen mode, try to find a compatible platform variant
+ # In non-frozen mode, return nil to trigger re-resolution and lockfile update
+ if Bundler.frozen_bundle?
+ materialize([name, version]) {|specs| resolve_best_platform(specs) }
end
+ else
+ materialize([name, version]) {|specs| resolve_best_platform(specs) }
end
end
@@ -190,6 +183,39 @@ module Bundler
!source.is_a?(Source::Path) && ruby_platform_materializes_to_ruby_platform?
end
+ # Try platforms in order of preference until finding a compatible spec.
+ # Used for legacy lockfiles and as a fallback when the exact locked spec
+ # is incompatible. Falls back to frozen bundle behavior if none match.
+ def resolve_best_platform(specs)
+ find_compatible_platform_spec(specs) || frozen_bundle_fallback(specs)
+ end
+
+ def find_compatible_platform_spec(specs)
+ candidate_platforms.each do |plat|
+ candidates = MatchPlatform.select_best_platform_match(specs, plat)
+ spec = choose_compatible(candidates, fallback_to_non_installable: false)
+ return spec if spec
+ end
+ nil
+ end
+
+ # Platforms to try in order of preference. Ruby platform is last since it
+ # requires compilation, but works when precompiled gems are incompatible.
+ def candidate_platforms
+ target = source.is_a?(Source::Path) ? platform : Bundler.local_platform
+ [target, platform, Gem::Platform::RUBY].uniq
+ end
+
+ # In frozen mode, accept any candidate. Will error at install time.
+ # When target differs from locked platform, prefer locked platform's candidates
+ # to preserve lockfile integrity.
+ def frozen_bundle_fallback(specs)
+ target = source.is_a?(Source::Path) ? platform : Bundler.local_platform
+ fallback_platform = target == platform ? target : platform
+ candidates = MatchPlatform.select_best_platform_match(specs, fallback_platform)
+ choose_compatible(candidates)
+ end
+
def ruby_platform_materializes_to_ruby_platform?
generic_platform = Bundler.generic_local_platform == Gem::Platform::JAVA ? Gem::Platform::JAVA : Gem::Platform::RUBY
@@ -209,8 +235,9 @@ module Bundler
# about the mismatch higher up the stack, right before trying to install the
# bad gem.
def choose_compatible(candidates, fallback_to_non_installable: Bundler.frozen_bundle?)
+ override_list = overrides || []
search = candidates.reverse.find do |spec|
- spec.is_a?(StubSpecification) || spec.matches_current_metadata?
+ spec.is_a?(StubSpecification) || spec.matches_current_metadata_with_overrides?(override_list)
end
if search.nil? && fallback_to_non_installable
search = candidates.last
@@ -237,7 +264,7 @@ module Bundler
spec.dependencies = dependencies
else
if !source.is_a?(Source::Path) && spec.runtime_dependencies.sort != dependencies.sort
- raise IncorrectLockfileDependencies.new(self)
+ raise IncorrectLockfileDependencies.new(self, spec.runtime_dependencies, dependencies)
end
end
end
diff --git a/lib/bundler/lockfile_generator.rb b/lib/bundler/lockfile_generator.rb
index 904552fa0c..2a3ad22480 100644
--- a/lib/bundler/lockfile_generator.rb
+++ b/lib/bundler/lockfile_generator.rb
@@ -71,7 +71,8 @@ module Bundler
checksums = definition.resolve.map do |spec|
spec.source.checksum_store.to_lock(spec)
end
- add_section("CHECKSUMS", checksums)
+
+ add_section("CHECKSUMS", checksums + bundler_checksum)
end
def add_locked_ruby_version
@@ -95,10 +96,24 @@ module Bundler
out << " #{key}: #{val}\n"
end
when String
- out << " #{value}\n"
+ out << " #{value}\n"
else
raise ArgumentError, "#{value.inspect} can't be serialized in a lockfile"
end
end
+
+ def bundler_checksum
+ return [] if Bundler.gem_version.to_s.end_with?(".dev") || ENV["SKIP_BUNDLER_CHECKSUM"]
+
+ bundler_spec = definition.sources.metadata_source.specs.search(["bundler", Bundler.gem_version]).last
+ return [] unless File.exist?(bundler_spec.cache_file)
+
+ require "rubygems/package"
+
+ package = Gem::Package.new(bundler_spec.cache_file)
+ definition.sources.metadata_source.checksum_store.register(bundler_spec, Checksum.from_gem_package(package))
+
+ [definition.sources.metadata_source.checksum_store.to_lock(bundler_spec)]
+ end
end
end
diff --git a/lib/bundler/lockfile_parser.rb b/lib/bundler/lockfile_parser.rb
index 9ab9d73ae2..852fc631f3 100644
--- a/lib/bundler/lockfile_parser.rb
+++ b/lib/bundler/lockfile_parser.rb
@@ -28,6 +28,7 @@ module Bundler
attr_reader(
:sources,
+ :metadata_source,
:dependencies,
:specs,
:platforms,
@@ -94,13 +95,14 @@ module Bundler
lockfile_contents.split(BUNDLED).last.strip
end
- def initialize(lockfile, strict: false)
+ def initialize(lockfile, strict: false, lockfile_path: nil)
@platforms = []
@sources = []
+ @metadata_source = Source::Metadata.new
@dependencies = {}
@parse_method = nil
@specs = {}
- @lockfile_path = begin
+ @lockfile_path = lockfile_path || begin
SharedHelpers.relative_lockfile_path
rescue GemfileNotFound
"Gemfile.lock"
@@ -113,6 +115,17 @@ module Bundler
"Run `git checkout HEAD -- #{@lockfile_path}` first to get a clean lock."
end
+ @valid = lockfile.strip.empty? ||
+ lockfile.split(/(?:\r?\n)+/).any? {|l| KNOWN_SECTIONS.include?(l) }
+
+ unless @valid
+ SharedHelpers.feature_deprecated!(
+ "Your #{@lockfile_path} does not appear to be a valid lockfile. " \
+ "Run `rm #{@lockfile_path}` and then `bundle install` to generate a new lockfile. " \
+ "This will raise a LockfileError in a future version of Bundler."
+ )
+ end
+
lockfile.split(/((?:\r?\n)+)/) do |line|
# split alternates between the line and the following whitespace
next @pos.advance!(line) if line.match?(/^\s*$/)
@@ -141,18 +154,8 @@ module Bundler
@pos.advance!(line)
end
- if !Bundler.frozen_bundle? && @platforms.include?(Gem::Platform::X64_MINGW_LEGACY)
- if @platforms.include?(Gem::Platform::X64_MINGW)
- @platforms.delete(Gem::Platform::X64_MINGW_LEGACY)
- SharedHelpers.major_deprecation(2,
- "Found x64-mingw32 in lockfile, which is deprecated. Removing it. Support for x64-mingw32 will be removed in Bundler 4.0.",
- removed_message: "Found x64-mingw32 in lockfile, which is no longer supported as of Bundler 4.0.")
- else
- @platforms[@platforms.index(Gem::Platform::X64_MINGW_LEGACY)] = Gem::Platform::X64_MINGW
- SharedHelpers.major_deprecation(2,
- "Found x64-mingw32 in lockfile, which is deprecated. Using x64-mingw-ucrt, the replacement for x64-mingw32 in modern rubies, instead. Support for x64-mingw32 will be removed in Bundler 4.0.",
- removed_message: "Found x64-mingw32 in lockfile, which is no longer supported as of Bundler 4.0.")
- end
+ if @platforms.include?(Gem::Platform::X64_MINGW_LEGACY)
+ SharedHelpers.feature_deprecated!("Found x64-mingw32 in lockfile, which is deprecated and will be removed in the future.")
end
@most_specific_locked_platform = @platforms.min_by do |bundle_platform|
@@ -172,6 +175,10 @@ module Bundler
bundler_version.nil? || bundler_version < Gem::Version.new("1.16.2")
end
+ def valid?
+ @valid
+ end
+
private
TYPES = {
@@ -262,7 +269,12 @@ module Bundler
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]
+ spec = @specs[full_name]
+
+ if name == "bundler"
+ spec ||= LazySpecification.new(name, version, platform, @metadata_source)
+ end
+ return unless spec
if checksums
checksums.split(",") do |lock_checksum|
diff --git a/lib/bundler/man/bundle-add.1 b/lib/bundler/man/bundle-add.1
index 74422cbd31..0956aa83f1 100644
--- a/lib/bundler/man/bundle-add.1
+++ b/lib/bundler/man/bundle-add.1
@@ -1,10 +1,10 @@
.\" generated with Ronn-NG/v0.10.1
.\" http://github.com/apjanke/ronn-ng/tree/0.10.1
-.TH "BUNDLE\-ADD" "1" "August 2025" ""
+.TH "BUNDLE\-ADD" "1" "May 2026" ""
.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] [\-\-quiet] [\-\-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] [\-\-cooldown=NUMBER] [\-\-quiet] [\-\-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\.
.SH "OPTIONS"
@@ -46,10 +46,16 @@ Do not print progress information to the standard output\.
Adds the gem to the Gemfile but does not install it\.
.TP
\fB\-\-optimistic\fR
-Adds optimistic declaration of version\.
+Ignored (now default behavior)
+.TP
+\fB\-\-pessimistic\fR
+Adds pessimistic declaration of version\.
.TP
\fB\-\-strict\fR
Adds strict declaration of version\.
+.TP
+\fB\-\-cooldown=<number>\fR
+Only consider gem versions published at least \fInumber\fR days ago when resolving\. Pass \fB0\fR to disable cooldown for this run\. See \fBcooldown\fR in bundle\-config(1) for precedence rules\.
.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\.
@@ -62,7 +68,7 @@ You can add the \fBrails\fR gem with version greater than 1\.1 (not including 1\
.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
+\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
diff --git a/lib/bundler/man/bundle-add.1.ronn b/lib/bundler/man/bundle-add.1.ronn
index 48c0c66b09..8c65af0cc0 100644
--- a/lib/bundler/man/bundle-add.1.ronn
+++ b/lib/bundler/man/bundle-add.1.ronn
@@ -5,7 +5,7 @@ bundle-add(1) -- Add gem to the Gemfile and run bundle install
`bundle add` <GEM_NAME> [--group=GROUP] [--version=VERSION] [--source=SOURCE]
[--path=PATH] [--git=GIT|--github=GITHUB] [--branch=BRANCH] [--ref=REF]
- [--quiet] [--skip-install] [--strict|--optimistic]
+ [--cooldown=NUMBER] [--quiet] [--skip-install] [--strict|--optimistic]
## DESCRIPTION
@@ -51,11 +51,19 @@ Adds the named gem to the [`Gemfile(5)`][Gemfile(5)] and run `bundle install`.
Adds the gem to the Gemfile but does not install it.
* `--optimistic`:
- Adds optimistic declaration of version.
+ Ignored (now default behavior)
+
+* `--pessimistic`:
+ Adds pessimistic declaration of version.
* `--strict`:
Adds strict declaration of version.
+* `--cooldown=<number>`:
+ Only consider gem versions published at least <number> days ago when
+ resolving. Pass `0` to disable cooldown for this run. See `cooldown`
+ in bundle-config(1) for precedence rules.
+
## EXAMPLES
1. You can add the `rails` gem to the Gemfile without any version restriction.
@@ -70,7 +78,7 @@ Adds the named gem to the [`Gemfile(5)`][Gemfile(5)] and run `bundle install`.
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"`
+ `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`.
diff --git a/lib/bundler/man/bundle-binstubs.1 b/lib/bundler/man/bundle-binstubs.1
index be9c6d0d09..246daeae53 100644
--- a/lib/bundler/man/bundle-binstubs.1
+++ b/lib/bundler/man/bundle-binstubs.1
@@ -1,24 +1,21 @@
.\" generated with Ronn-NG/v0.10.1
.\" http://github.com/apjanke/ronn-ng/tree/0.10.1
-.TH "BUNDLE\-BINSTUBS" "1" "August 2025" ""
+.TH "BUNDLE\-BINSTUBS" "1" "May 2026" ""
.SH "NAME"
\fBbundle\-binstubs\fR \- Install the binstubs of the listed gems
.SH "SYNOPSIS"
-\fBbundle binstubs\fR \fIGEM_NAME\fR [\-\-force] [\-\-path PATH] [\-\-standalone] [\-\-all\-platforms]
+\fBbundle binstubs\fR \fIGEM_NAME\fR [\-\-force] [\-\-standalone] [\-\-all\-platforms]
.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\.
+This command generates binstubs for executables in \fBGEM_NAME\fR\. Binstubs are put into \fBbin\fR, or the directory specified by \fBbin\fR setting if it has been configured\. 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[=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
diff --git a/lib/bundler/man/bundle-binstubs.1.ronn b/lib/bundler/man/bundle-binstubs.1.ronn
index ec2cfd80db..cbe5983f4d 100644
--- a/lib/bundler/man/bundle-binstubs.1.ronn
+++ b/lib/bundler/man/bundle-binstubs.1.ronn
@@ -3,7 +3,7 @@ bundle-binstubs(1) -- Install the binstubs of the listed gems
## SYNOPSIS
-`bundle binstubs` <GEM_NAME> [--force] [--path PATH] [--standalone] [--all-platforms]
+`bundle binstubs` <GEM_NAME> [--force] [--standalone] [--all-platforms]
## DESCRIPTION
@@ -19,17 +19,15 @@ the file `bin/rspec`. That file will contain enough code to load Bundler,
tell it to load the bundled gems, and then run rspec.
This command generates binstubs for executables in `GEM_NAME`.
-Binstubs are put into `bin`, or the `--path` directory if one has been set.
-Calling binstubs with [GEM [GEM]] will create binstubs for all given gems.
+Binstubs are put into `bin`, or the directory specified by `bin` setting if it
+has been configured. Calling binstubs with [GEM [GEM]] will create binstubs for
+all given gems.
## OPTIONS
* `--force`:
Overwrite existing binstubs if they exist.
-* `--path[=PATH]`:
- The location to install the specified binstubs to. This defaults to `bin`.
-
* `--standalone`:
Makes binstubs that can work without depending on Rubygems or Bundler at
runtime.
diff --git a/lib/bundler/man/bundle-cache.1 b/lib/bundler/man/bundle-cache.1
index 1d16b164fa..38ea047961 100644
--- a/lib/bundler/man/bundle-cache.1
+++ b/lib/bundler/man/bundle-cache.1
@@ -1,6 +1,6 @@
.\" generated with Ronn-NG/v0.10.1
.\" http://github.com/apjanke/ronn-ng/tree/0.10.1
-.TH "BUNDLE\-CACHE" "1" "August 2025" ""
+.TH "BUNDLE\-CACHE" "1" "May 2026" ""
.SH "NAME"
\fBbundle\-cache\fR \- Package your needed \fB\.gem\fR files into your application
.SH "SYNOPSIS"
@@ -11,9 +11,6 @@ alias: \fBpackage\fR, \fBpack\fR
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 "OPTIONS"
.TP
-\fB\-\-all\fR
-Include all sources (including path and git)\.
-.TP
\fB\-\-all\-platforms\fR
Include gems for all platforms present in the lockfile, not only the current one\.
.TP
@@ -26,19 +23,10 @@ Use the specified gemfile instead of Gemfile\.
\fB\-\-no\-install\fR
Don't install the gems, only update the cache\.
.TP
-\fB\-\-no\-prune\fR
-Don't remove stale gems from the cache\.
-.TP
-\fB\-\-path=PATH\fR
-Specify a different path than the system default ($BUNDLE_PATH or $GEM_HOME)\.
-.TP
\fB\-\-quiet\fR
Only output warnings and errors\.
-.TP
-\fB\-\-frozen\fR
-Do not allow the Gemfile\.lock to be updated after this bundle cache operation's install\.
.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\.
+The \fBbundle cache\fR command can also package \fB:git\fR and \fB:path\fR dependencies besides \.gem files\. This can be disabled setting \fBcache_all\fR to false\.
.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"
diff --git a/lib/bundler/man/bundle-cache.1.ronn b/lib/bundler/man/bundle-cache.1.ronn
index ffcc07c7b1..51846c96b4 100644
--- a/lib/bundler/man/bundle-cache.1.ronn
+++ b/lib/bundler/man/bundle-cache.1.ronn
@@ -15,9 +15,6 @@ use the gems in the cache in preference to the ones on `rubygems.org`.
## OPTIONS
-* `--all`:
- Include all sources (including path and git).
-
* `--all-platforms`:
Include gems for all platforms present in the lockfile, not only the current one.
@@ -30,23 +27,13 @@ use the gems in the cache in preference to the ones on `rubygems.org`.
* `--no-install`:
Don't install the gems, only update the cache.
-* `--no-prune`:
- Don't remove stale gems from the cache.
-
-* `--path=PATH`:
- Specify a different path than the system default ($BUNDLE_PATH or $GEM_HOME).
-
* `--quiet`:
Only output warnings and errors.
-* `--frozen`:
- Do not allow the Gemfile.lock to be updated after this bundle cache operation's install.
-
## GIT AND PATH GEMS
The `bundle cache` command can also package `:git` and `:path` dependencies
-besides .gem files. This needs to be explicitly enabled via the `--all` option.
-Once used, the `--all` option will be remembered.
+besides .gem files. This can be disabled setting `cache_all` to false.
## SUPPORT FOR MULTIPLE PLATFORMS
diff --git a/lib/bundler/man/bundle-check.1 b/lib/bundler/man/bundle-check.1
index 4f0d51bb71..6cd474d90a 100644
--- a/lib/bundler/man/bundle-check.1
+++ b/lib/bundler/man/bundle-check.1
@@ -1,10 +1,10 @@
.\" generated with Ronn-NG/v0.10.1
.\" http://github.com/apjanke/ronn-ng/tree/0.10.1
-.TH "BUNDLE\-CHECK" "1" "August 2025" ""
+.TH "BUNDLE\-CHECK" "1" "May 2026" ""
.SH "NAME"
\fBbundle\-check\fR \- Verifies if dependencies are satisfied by installed gems
.SH "SYNOPSIS"
-\fBbundle check\fR [\-\-dry\-run] [\-\-gemfile=FILE] [\-\-path=PATH]
+\fBbundle check\fR [\-\-dry\-run] [\-\-gemfile=FILE]
.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
@@ -18,7 +18,4 @@ Locks the [\fBGemfile(5)\fR][Gemfile(5)] before running the command\.
.TP
\fB\-\-gemfile=GEMFILE\fR
Use the specified gemfile instead of the [\fBGemfile(5)\fR][Gemfile(5)]\.
-.TP
-\fB\-\-path=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 23bb6f3eb8..92589159c9 100644
--- a/lib/bundler/man/bundle-check.1.ronn
+++ b/lib/bundler/man/bundle-check.1.ronn
@@ -5,7 +5,6 @@ bundle-check(1) -- Verifies if dependencies are satisfied by installed gems
`bundle check` [--dry-run]
[--gemfile=FILE]
- [--path=PATH]
## DESCRIPTION
@@ -25,7 +24,3 @@ installed on the local machine, if they satisfy the requirements.
* `--gemfile=GEMFILE`:
Use the specified gemfile instead of the [`Gemfile(5)`][Gemfile(5)].
-
-* `--path=PATH`:
- Specify a different path than the system default (`$BUNDLE_PATH` or `$GEM_HOME`).
- Bundler will remember this value for future installs on this machine.
diff --git a/lib/bundler/man/bundle-clean.1 b/lib/bundler/man/bundle-clean.1
index df66523829..eb90636c17 100644
--- a/lib/bundler/man/bundle-clean.1
+++ b/lib/bundler/man/bundle-clean.1
@@ -1,6 +1,6 @@
.\" generated with Ronn-NG/v0.10.1
.\" http://github.com/apjanke/ronn-ng/tree/0.10.1
-.TH "BUNDLE\-CLEAN" "1" "August 2025" ""
+.TH "BUNDLE\-CLEAN" "1" "May 2026" ""
.SH "NAME"
\fBbundle\-clean\fR \- Cleans up unused gems in your bundler directory
.SH "SYNOPSIS"
diff --git a/lib/bundler/man/bundle-config.1 b/lib/bundler/man/bundle-config.1
index 5157e51453..c055c8a415 100644
--- a/lib/bundler/man/bundle-config.1
+++ b/lib/bundler/man/bundle-config.1
@@ -1,6 +1,6 @@
.\" generated with Ronn-NG/v0.10.1
.\" http://github.com/apjanke/ronn-ng/tree/0.10.1
-.TH "BUNDLE\-CONFIG" "1" "August 2025" ""
+.TH "BUNDLE\-CONFIG" "1" "May 2026" ""
.SH "NAME"
\fBbundle\-config\fR \- Set bundler configuration options
.SH "SYNOPSIS"
@@ -69,183 +69,130 @@ The canonical form of this configuration is \fB"without"\fR\. To convert the can
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\.
-.TP
-\fBallow_offline_install\fR (\fBBUNDLE_ALLOW_OFFLINE_INSTALL\fR)
-Allow Bundler to use cached data when installing without network access\.
-.TP
-\fBauto_install\fR (\fBBUNDLE_AUTO_INSTALL\fR)
-Automatically run \fBbundle install\fR when gems are missing\.
-.TP
-\fBbin\fR (\fBBUNDLE_BIN\fR)
-Install executables from gems in the bundle to the specified directory\. Defaults to \fBfalse\fR\.
-.TP
-\fBcache_all\fR (\fBBUNDLE_CACHE_ALL\fR)
-Cache all gems, including path and git gems\. This needs to be explicitly before bundler 4, but will be the default on bundler 4\.
-.TP
-\fBcache_all_platforms\fR (\fBBUNDLE_CACHE_ALL_PLATFORMS\fR)
-Cache gems for all platforms\.
-.TP
-\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\.
-.TP
-\fBclean\fR (\fBBUNDLE_CLEAN\fR)
-Whether Bundler should run \fBbundle clean\fR automatically after \fBbundle install\fR\. Defaults to \fBtrue\fR in Bundler 4, as long as \fBpath\fR is not explicitly configured\.
-.TP
-\fBconsole\fR (\fBBUNDLE_CONSOLE\fR)
-The console that \fBbundle console\fR starts\. Defaults to \fBirb\fR\.
-.TP
-\fBdefault_cli_command\fR (\fBBUNDLE_DEFAULT_CLI_COMMAND\fR)
-The command that running \fBbundle\fR without arguments should run\. Defaults to \fBcli_help\fR since Bundler 4, but can also be \fBinstall\fR which was the previous default\.
-.TP
-\fBdeployment\fR (\fBBUNDLE_DEPLOYMENT\fR)
-Equivalent to setting \fBfrozen\fR to \fBtrue\fR and \fBpath\fR to \fBvendor/bundle\fR\.
-.TP
-\fBdisable_checksum_validation\fR (\fBBUNDLE_DISABLE_CHECKSUM_VALIDATION\fR)
-Allow installing gems even if they do not match the checksum provided by RubyGems\.
-.TP
-\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\.
-.TP
-\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\.
-.TP
-\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\.
-.TP
-\fBdisable_shared_gems\fR (\fBBUNDLE_DISABLE_SHARED_GEMS\fR)
-Stop Bundler from accessing gems installed to RubyGems' normal location\.
-.TP
-\fBdisable_version_check\fR (\fBBUNDLE_DISABLE_VERSION_CHECK\fR)
-Stop Bundler from checking if a newer Bundler version is available on rubygems\.org\.
-.TP
-\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\.
-.TP
-\fBfrozen\fR (\fBBUNDLE_FROZEN\fR)
-Disallow any automatic changes to \fBGemfile\.lock\fR\. Bundler commands will be blocked unless the lockfile can be installed exactly as written\. Usually this will happen when changing the \fBGemfile\fR manually and forgetting to update the lockfile through \fBbundle lock\fR or \fBbundle install\fR\.
-.TP
-\fBgem\.github_username\fR (\fBBUNDLE_GEM__GITHUB_USERNAME\fR)
-Sets a GitHub username or organization to be used in the \fBREADME\fR and \fB\.gemspec\fR files 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\.
-.TP
-\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\.
-.TP
-\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\.
-.TP
-\fBglobal_gem_cache\fR (\fBBUNDLE_GLOBAL_GEM_CACHE\fR)
-Whether Bundler should cache all gems and compiled extensions globally, rather than locally to the configured installation path\.
-.TP
-\fBignore_funding_requests\fR (\fBBUNDLE_IGNORE_FUNDING_REQUESTS\fR)
-When set, no funding requests will be printed\.
-.TP
-\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\.
-.TP
-\fBinit_gems_rb\fR (\fBBUNDLE_INIT_GEMS_RB\fR)
-Generate a \fBgems\.rb\fR instead of a \fBGemfile\fR when running \fBbundle init\fR\.
-.TP
-\fBjobs\fR (\fBBUNDLE_JOBS\fR)
-The number of gems Bundler can install in parallel\. Defaults to the number of available processors\.
-.TP
-\fBlockfile_checksums\fR (\fBBUNDLE_LOCKFILE_CHECKSUMS\fR)
-Whether Bundler should include a checksums section in new lockfiles, to protect from compromised gem sources\.
-.TP
-\fBno_install\fR (\fBBUNDLE_NO_INSTALL\fR)
-Whether \fBbundle package\fR should skip installing gems\.
-.TP
-\fBno_prune\fR (\fBBUNDLE_NO_PRUNE\fR)
-Whether Bundler should leave outdated gems unpruned when caching\.
-.TP
-\fBonly\fR (\fBBUNDLE_ONLY\fR)
-A space\-separated list of groups to install only gems of the specified groups\.
-.TP
-\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 \fB\.bundle\fR relative to repository root in Bundler 4, and to the default system path (\fBGem\.dir\fR) before Bundler 4\.
-.TP
-\fBpath\.system\fR (\fBBUNDLE_PATH__SYSTEM\fR)
-Whether Bundler will install gems into the default system path (\fBGem\.dir\fR)\.
-.TP
-\fBplugins\fR (\fBBUNDLE_PLUGINS\fR)
-Enable Bundler's experimental plugin system\.
-.TP
-\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\.
-.TP
-\fBredirect\fR (\fBBUNDLE_REDIRECT\fR)
-The number of redirects allowed for network requests\. Defaults to \fB5\fR\.
-.TP
-\fBretry\fR (\fBBUNDLE_RETRY\fR)
-The number of times to retry failed network requests\. Defaults to \fB3\fR\.
-.TP
-\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\.
-.TP
-\fBsilence_deprecations\fR (\fBBUNDLE_SILENCE_DEPRECATIONS\fR)
-Whether Bundler should silence deprecation warnings for behavior that will be changed in the next major version\.
-.TP
-\fBsilence_root_warning\fR (\fBBUNDLE_SILENCE_ROOT_WARNING\fR)
-Silence the warning Bundler prints when installing gems as root\.
-.TP
-\fBsimulate_version\fR (\fBBUNDLE_SIMULATE_VERSION\fR)
-The virtual version Bundler should use for activating feature flags\. Can be used to simulate all the new functionality that will be enabled in a future major version\.
-.TP
-\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\.
-.TP
-\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\.
-.TP
-\fBssl_verify_mode\fR (\fBBUNDLE_SSL_VERIFY_MODE\fR)
-The SSL verification mode Bundler uses when making HTTPS requests\. Defaults to verify peer\.
-.TP
-\fBsystem_bindir\fR (\fBBUNDLE_SYSTEM_BINDIR\fR)
-The location where RubyGems installs binstubs\. Defaults to \fBGem\.bindir\fR\.
-.TP
-\fBtimeout\fR (\fBBUNDLE_TIMEOUT\fR)
-The seconds allowed before timing out for network requests\. Defaults to \fB10\fR\.
-.TP
-\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\.
-.TP
-\fBuser_agent\fR (\fBBUNDLE_USER_AGENT\fR)
-The custom user agent fragment Bundler includes in API requests\.
-.TP
-\fBverbose\fR (\fBBUNDLE_VERBOSE\fR)
-Whether Bundler should print verbose output\. Defaults to \fBfalse\fR, unless the \fB\-\-verbose\fR CLI flag is used\.
-.TP
-\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\.
-.TP
-\fBwith\fR (\fBBUNDLE_WITH\fR)
-A space\-separated or \fB:\fR\-separated list of groups whose gems bundler should install\.
-.TP
-\fBwithout\fR (\fBBUNDLE_WITHOUT\fR)
-A space\-separated or \fB:\fR\-separated list of groups whose gems bundler should not install\.
-.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)\.
-.P
-However, this will be changed in bundler 4, 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 flags that can be configured are:
-.TP
-\fB\-\-bin\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\.
-.TP
-\fB\-\-deployment\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\.
-.TP
-\fB\-\-only\fR
-A space\-separated list of groups to install only gems of the specified groups\. Please check carefully if you want to install also gems without a group, cause they get put inside \fBdefault\fR group\. For example \fBonly test:default\fR will install all gems specified in test group and without one\.
-.TP
-\fB\-\-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\.
-.TP
-\fB\-\-without\fR
-A space\-separated or \fB:\fR\-separated list of groups referencing gems to skip during installation\.
-.TP
-\fB\-\-with\fR
-A space\-separated or \fB:\fR\-separated list of \fBoptional\fR groups referencing gems to include during installation\.
+.IP "\(bu" 4
+\fBapi_request_size\fR (\fBBUNDLE_API_REQUEST_SIZE\fR): Configure how many dependencies to fetch when resolving the specifications\. This configuration is only used when fetching specifications from RubyGems servers that didn't implement the Compact Index API\. Defaults to 100\.
+.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): If configured, \fBbundle binstubs\fR will install executables from gems in the bundle to the specified directory\. Otherwise it will create them in a \fBbin\fR directory relative to the Gemfile directory\. 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, \fBbundle binstubs\fR will create a \fBbin/rails\fR executable that ensures that all referred dependencies will be resolved using the bundled gems\.
+.IP "\(bu" 4
+\fBcache_all\fR (\fBBUNDLE_CACHE_ALL\fR): Cache all gems, including path and git gems\. This needs to be explicitly before bundler 4, but will be the default on bundler 4\.
+.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\. Defaults to \fBtrue\fR in Bundler 4, as long as \fBpath\fR is not explicitly configured\.
+.IP "\(bu" 4
+\fBconsole\fR (\fBBUNDLE_CONSOLE\fR): The console that \fBbundle console\fR starts\. Defaults to \fBirb\fR\.
+.IP "\(bu" 4
+\fBcooldown\fR (\fBBUNDLE_COOLDOWN\fR): Number of days a published gem version must age before bundler will resolve to it\. Defaults to unset (no cooldown)\. Pass \fB0\fR to disable cooldown for an individual run\.
+.IP
+The effective cooldown for any given gem is resolved from three layers, highest precedence first:
+.IP "1." 4
+CLI flag \fB\-\-cooldown N\fR on \fBinstall\fR, \fBupdate\fR, \fBadd\fR, and \fBoutdated\fR\.
+.IP "2." 4
+This setting (\fBbundle config set cooldown N\fR or \fBBUNDLE_COOLDOWN=N\fR)\.
+.IP "3." 4
+The per\-source \fBcooldown:\fR keyword in the Gemfile, such as \fBsource "https://rubygems\.org", cooldown: 7\fR\.
+.IP "" 0
+.IP
+The CLI flag and this setting apply uniformly to every source, including ones declared with their own \fBcooldown:\fR value\. To keep a private registry permanently exempt while still cooling down public gems, declare \fBsource "https://internal", cooldown: 0\fR in the Gemfile; remember that \fB\-\-cooldown N\fR on the command line will still override it for that single run\.
+.IP
+Cooldown filtering depends on the gem server providing a per\-version \fBcreated_at\fR timestamp in the v2 compact\-index format\. Versions without that metadata \- older gem servers, historical entries that predate the v2 cutover on \fBrubygems\.org\fR, or private registries that still emit the v1 format \- are treated as outside the cooldown window and remain resolvable\. If you rely on cooldown for supply\-chain protection, confirm that the gem server emits \fBcreated_at\fR in its \fB/info/<gem>\fR responses\.
+.IP "\(bu" 4
+\fBdefault_cli_command\fR (\fBBUNDLE_DEFAULT_CLI_COMMAND\fR): The command that running \fBbundle\fR without arguments should run\. Defaults to \fBcli_help\fR since Bundler 4, but can also be \fBinstall\fR which was the previous default\.
+.IP "\(bu" 4
+\fBdeployment\fR (\fBBUNDLE_DEPLOYMENT\fR): Equivalent to setting \fBfrozen\fR to \fBtrue\fR and \fBpath\fR to \fBvendor/bundle\fR\.
+.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\.
+.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\.
+.IP "\(bu" 4
+\fBfrozen\fR (\fBBUNDLE_FROZEN\fR): Disallow any automatic changes to \fBGemfile\.lock\fR\. Bundler commands will be blocked unless the lockfile can be installed exactly as written\. Usually this will happen when changing the \fBGemfile\fR manually and forgetting to update the lockfile through \fBbundle lock\fR or \fBbundle install\fR\.
+.IP "\(bu" 4
+\fBgem\.github_username\fR (\fBBUNDLE_GEM__GITHUB_USERNAME\fR): Sets a GitHub username or organization to be used in the \fBREADME\fR and \fB\.gemspec\fR files 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 and compiled extensions globally, rather than locally to the configured installation path\.
+.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 download and install in parallel\. Defaults to the number of available processors\.
+.IP "\(bu" 4
+\fBlockfile\fR (\fBBUNDLE_LOCKFILE\fR): The path to the lockfile that bundler should use\. By default, Bundler adds \fB\.lock\fR to the end of the \fBgemfile\fR entry\. Can be set to \fBfalse\fR in the Gemfile to disable lockfile creation entirely (see gemfile(5))\.
+.IP "\(bu" 4
+\fBlockfile_checksums\fR (\fBBUNDLE_LOCKFILE_CHECKSUMS\fR): Whether Bundler should include a checksums section in new lockfiles, to protect from compromised gem sources\. Defaults to true\.
+.IP "\(bu" 4
+\fBno_build_extension\fR (\fBBUNDLE_NO_BUILD_EXTENSION\fR): Whether Bundler should skip building native extensions during installation\. When set, gems are installed without compiling their C extensions\. To build extensions later, unset this setting and run \fBbundle pristine <gem>\fR\.
+.IP "\(bu" 4
+\fBno_install\fR (\fBBUNDLE_NO_INSTALL\fR): Whether \fBbundle package\fR should skip installing gems\.
+.IP "\(bu" 4
+\fBno_install_plugin\fR (\fBBUNDLE_NO_INSTALL_PLUGIN\fR): Whether Bundler should skip installing RubyGems plugins during installation\. When set, plugin files are not written to the plugins directory\. To install plugins later, unset this setting and run \fBbundle pristine <gem>\fR\.
+.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\. Please check carefully if you want to install also gems without a group, because they get put inside \fBdefault\fR group\. For example \fBonly test:default\fR will install all gems specified in test group and without one\.
+.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\. When not set, Bundler install by default to a \fB\.bundle\fR directory relative to repository root in Bundler 4, and to the default system path (\fBGem\.dir\fR) before Bundler 4\. That means that before Bundler 4, Bundler shares this location with Rubygems, and \fBgem install \|\.\|\.\|\.\fR will have gems installed in the same location and therefore, gems installed without \fBpath\fR set will show up by calling \fBgem list\fR\. This will not be the case in Bundler 4\.
+.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
+\fBplugins\fR (\fBBUNDLE_PLUGINS\fR): Enable Bundler's experimental plugin system\.
+.IP "\(bu" 4
+\fBprefer_patch\fR (\fBBUNDLE_PREFER_PATCH\fR): Prefer updating only to next patch version during updates\. Makes \fBbundle update\fR calls equivalent to \fBbundler update \-\-patch\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
+\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
+\fBsimulate_version\fR (\fBBUNDLE_SIMULATE_VERSION\fR): The virtual version Bundler should use for activating feature flags\. Can be used to simulate all the new functionality that will be enabled in a future major version\.
+.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
+\fBverbose\fR (\fBBUNDLE_VERBOSE\fR): Whether Bundler should print verbose output\. Defaults to \fBfalse\fR, unless the \fB\-\-verbose\fR CLI flag is used\.
+.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 space\-separated or \fB:\fR\-separated list of groups whose gems bundler should install\.
+.IP "\(bu" 4
+\fBwithout\fR (\fBBUNDLE_WITHOUT\fR): A space\-separated or \fB:\fR\-separated list of groups whose gems bundler should not install\.
+.IP "" 0
.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
@@ -272,7 +219,16 @@ 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:
+Important: This feature only works for gems that are specified with a git source in your Gemfile\. It does not work for gems installed from RubyGems or other sources\. The gem must be defined with \fBgit:\fR option pointing to a remote repository\.
+.P
+For example, if your Gemfile contains:
+.IP "" 4
+.nf
+gem "rack", git: "https://github\.com/rack/rack\.git", branch: "main"
+.fi
+.IP "" 0
+.P
+Then you can use a local Rack repository by running:
.IP "" 4
.nf
bundle config set \-\-local local\.rack ~/Work/git/rack
@@ -284,6 +240,13 @@ Now instead of checking out the remote git repository, the local override will b
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\.
+.P
+If you need to temporarily use a local version of a gem that is normally installed from RubyGems (not from git), use a path source instead:
+.IP "" 4
+.nf
+gem "rack", path: "~/Work/git/rack"
+.fi
+.IP "" 0
.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
@@ -339,7 +302,7 @@ export BUNDLE_GEMS__LONGEROUS__COM="claudette:s00pers3krit"
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
+bundle config set \-\-global https://github\.com/ruby/rubygems\.git username:password
.fi
.IP "" 0
.P
diff --git a/lib/bundler/man/bundle-config.1.ronn b/lib/bundler/man/bundle-config.1.ronn
index 2b2e39f03e..72f891b428 100644
--- a/lib/bundler/man/bundle-config.1.ronn
+++ b/lib/bundler/man/bundle-config.1.ronn
@@ -106,13 +106,22 @@ 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_offline_install` (`BUNDLE_ALLOW_OFFLINE_INSTALL`):
- Allow Bundler to use cached data when installing without network access.
+* `api_request_size` (`BUNDLE_API_REQUEST_SIZE`):
+ Configure how many dependencies to fetch when resolving the specifications.
+ This configuration is only used when fetching specifications from RubyGems
+ servers that didn't implement the Compact Index API.
+ Defaults to 100.
* `auto_install` (`BUNDLE_AUTO_INSTALL`):
Automatically run `bundle install` when gems are missing.
* `bin` (`BUNDLE_BIN`):
- Install executables from gems in the bundle to the specified directory.
- Defaults to `false`.
+ If configured, `bundle binstubs` will install executables from gems in the
+ bundle to the specified directory. Otherwise it will create them in a `bin`
+ directory relative to the Gemfile directory. These executables run in
+ Bundler's context. If used, you might add this directory to your
+ environment's `PATH` variable. For instance, if the `rails` gem comes with a
+ `rails` executable, `bundle binstubs` will create a `bin/rails` executable
+ that ensures that all referred dependencies will be resolved using the
+ bundled gems.
* `cache_all` (`BUNDLE_CACHE_ALL`):
Cache all gems, including path and git gems. This needs to be explicitly
before bundler 4, but will be the default on bundler 4.
@@ -128,6 +137,36 @@ learn more about their operation in [bundle install(1)](bundle-install.1.html).
explicitly configured.
* `console` (`BUNDLE_CONSOLE`):
The console that `bundle console` starts. Defaults to `irb`.
+* `cooldown` (`BUNDLE_COOLDOWN`):
+ Number of days a published gem version must age before bundler will
+ resolve to it. Defaults to unset (no cooldown). Pass `0` to disable
+ cooldown for an individual run.
+
+ The effective cooldown for any given gem is resolved from three
+ layers, highest precedence first:
+
+ 1. CLI flag `--cooldown N` on `install`, `update`, `add`, and
+ `outdated`.
+ 2. This setting (`bundle config set cooldown N` or
+ `BUNDLE_COOLDOWN=N`).
+ 3. The per-source `cooldown:` keyword in the Gemfile, such as
+ `source "https://rubygems.org", cooldown: 7`.
+
+ The CLI flag and this setting apply uniformly to every source,
+ including ones declared with their own `cooldown:` value. To keep a
+ private registry permanently exempt while still cooling down public
+ gems, declare `source "https://internal", cooldown: 0` in the
+ Gemfile; remember that `--cooldown N` on the command line will
+ still override it for that single run.
+
+ Cooldown filtering depends on the gem server providing a per-version
+ `created_at` timestamp in the v2 compact-index format. Versions
+ without that metadata - older gem servers, historical entries that
+ predate the v2 cutover on `rubygems.org`, or private registries that
+ still emit the v1 format - are treated as outside the cooldown
+ window and remain resolvable. If you rely on cooldown for
+ supply-chain protection, confirm that the gem server emits
+ `created_at` in its `/info/<gem>` responses.
* `default_cli_command` (`BUNDLE_DEFAULT_CLI_COMMAND`):
The command that running `bundle` without arguments should run. Defaults to
`cli_help` since Bundler 4, but can also be `install` which was the previous
@@ -183,27 +222,46 @@ learn more about their operation in [bundle install(1)](bundle-install.1.html).
* `init_gems_rb` (`BUNDLE_INIT_GEMS_RB`):
Generate a `gems.rb` instead of a `Gemfile` when running `bundle init`.
* `jobs` (`BUNDLE_JOBS`):
- The number of gems Bundler can install in parallel. Defaults to the number of
- available processors.
+ The number of gems Bundler can download and install in parallel.
+ Defaults to the number of available processors.
+* `lockfile` (`BUNDLE_LOCKFILE`):
+ The path to the lockfile that bundler should use. By default, Bundler adds
+ `.lock` to the end of the `gemfile` entry. Can be set to `false` in the
+ Gemfile to disable lockfile creation entirely (see gemfile(5)).
* `lockfile_checksums` (`BUNDLE_LOCKFILE_CHECKSUMS`):
- Whether Bundler should include a checksums section in new lockfiles, to protect from compromised gem sources.
+ Whether Bundler should include a checksums section in new lockfiles, to protect from compromised gem sources. Defaults to true.
+* `no_build_extension` (`BUNDLE_NO_BUILD_EXTENSION`):
+ Whether Bundler should skip building native extensions during installation.
+ When set, gems are installed without compiling their C extensions.
+ To build extensions later, unset this setting and run `bundle pristine <gem>`.
* `no_install` (`BUNDLE_NO_INSTALL`):
Whether `bundle package` should skip installing gems.
+* `no_install_plugin` (`BUNDLE_NO_INSTALL_PLUGIN`):
+ Whether Bundler should skip installing RubyGems plugins during installation.
+ When set, plugin files are not written to the plugins directory.
+ To install plugins later, unset this setting and run `bundle pristine <gem>`.
* `no_prune` (`BUNDLE_NO_PRUNE`):
Whether Bundler should leave outdated gems unpruned when caching.
* `only` (`BUNDLE_ONLY`):
A space-separated list of groups to install only gems of the specified groups.
+ Please check carefully if you want to install also gems without a group, because
+ they get put inside `default` group. For example `only test:default` will install
+ all gems specified in test group and without one.
* `path` (`BUNDLE_PATH`):
The location on disk where all gems in your bundle will be located regardless
of `$GEM_HOME` or `$GEM_PATH` values. Bundle gems not found in this location
- will be installed by `bundle install`. Defaults to `.bundle` relative to
- repository root in Bundler 4, and to the default system path (`Gem.dir`)
- before Bundler 4.
+ will be installed by `bundle install`. When not set, Bundler install by
+ default to a `.bundle` directory relative to repository root in Bundler 4,
+ and to the default system path (`Gem.dir`) before Bundler 4. That means that
+ before Bundler 4, Bundler shares this location with Rubygems, and `gem
+ install ...` will have gems installed in the same location and therefore,
+ gems installed without `path` set will show up by calling `gem list`. This
+ will not be the case in Bundler 4.
* `path.system` (`BUNDLE_PATH__SYSTEM`):
Whether Bundler will install gems into the default system path (`Gem.dir`).
* `plugins` (`BUNDLE_PLUGINS`):
Enable Bundler's experimental plugin system.
-* `prefer_patch` (BUNDLE_PREFER_PATCH):
+* `prefer_patch` (`BUNDLE_PREFER_PATCH`):
Prefer updating only to next patch version during updates. Makes `bundle update` calls equivalent to `bundler update --patch`.
* `redirect` (`BUNDLE_REDIRECT`):
The number of redirects allowed for network requests. Defaults to `5`.
@@ -253,52 +311,6 @@ learn more about their operation in [bundle install(1)](bundle-install.1.html).
* `without` (`BUNDLE_WITHOUT`):
A space-separated or `:`-separated list of groups whose gems bundler should not install.
-## REMEMBERING OPTIONS
-
-Flags passed to `bundle install` or the Bundler runtime, such as `--path foo` or
-`--without production`, are remembered between commands and saved to your local
-application's configuration (normally, `./.bundle/config`).
-
-However, this will be changed in bundler 4, so it's better not to rely on this
-behavior. If these options must be remembered, it's better to set them using
-`bundle config` (e.g., `bundle config set --local path foo`).
-
-The flags that can be configured are:
-
-* `--bin`:
- Creates a directory (defaults to `~/bin`) 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 `PATH` variable. For instance, if the
- `rails` gem comes with a `rails` executable, this flag will create a
- `bin/rails` executable that ensures that all referred dependencies will be
- resolved using the bundled gems.
-
-* `--deployment`:
- In deployment mode, Bundler will 'roll-out' the bundle for
- `production` use. Please check carefully if you want to have this option
- enabled in `development` or `test` environments.
-
-* `--only`:
- A space-separated list of groups to install only gems of the specified groups.
- Please check carefully if you want to install also gems without a group, cause
- they get put inside `default` group. For example `only test:default` will install
- all gems specified in test group and without one.
-
-* `--path`:
- The location to install the specified gems to. This defaults to Rubygems'
- setting. Bundler shares this location with Rubygems, `gem install ...` will
- have gem installed there, too. Therefore, gems installed without a
- `--path ...` setting will show up by calling `gem list`. Accordingly, gems
- installed to other locations will not get listed.
-
-* `--without`:
- A space-separated or `:`-separated list of groups referencing gems to skip during
- installation.
-
-* `--with`:
- A space-separated or `:`-separated list of **optional** groups referencing gems to
- include during installation.
-
## BUILD OPTIONS
You can use `bundle config` to give Bundler the flags to pass to the gem
@@ -326,7 +338,16 @@ up a local override:
bundle config set --local local.GEM_NAME /path/to/local/git/repository
-For example, in order to use a local Rack repository, a developer could call:
+Important: This feature only works for gems that are specified with a git
+source in your Gemfile. It does not work for gems installed from RubyGems
+or other sources. The gem must be defined with `git:` option pointing to a
+remote repository.
+
+For example, if your Gemfile contains:
+
+ gem "rack", git: "https://github.com/rack/rack.git", branch: "main"
+
+Then you can use a local Rack repository by running:
bundle config set --local local.rack ~/Work/git/rack
@@ -352,6 +373,11 @@ Finally, Bundler also ensures that the current revision in the
`Gemfile.lock` exists in the local git repository. By doing this, Bundler
forces you to fetch the latest changes in the remotes.
+If you need to temporarily use a local version of a gem that is normally
+installed from RubyGems (not from git), use a path source instead:
+
+ gem "rack", path: "~/Work/git/rack"
+
## MIRRORS OF GEM SOURCES
Bundler supports overriding gem sources with mirrors. This allows you to
@@ -395,7 +421,7 @@ Or you can set the credentials as an environment variable like this:
For gems with a git source with HTTP(S) URL you can specify credentials like so:
- bundle config set --global https://github.com/rubygems/rubygems.git username:password
+ bundle config set --global https://github.com/ruby/rubygems.git username:password
Or you can set the credentials as an environment variable like so:
diff --git a/lib/bundler/man/bundle-console.1 b/lib/bundler/man/bundle-console.1
index 18c765372b..5d3f65365f 100644
--- a/lib/bundler/man/bundle-console.1
+++ b/lib/bundler/man/bundle-console.1
@@ -1,6 +1,6 @@
.\" generated with Ronn-NG/v0.10.1
.\" http://github.com/apjanke/ronn-ng/tree/0.10.1
-.TH "BUNDLE\-CONSOLE" "1" "August 2025" ""
+.TH "BUNDLE\-CONSOLE" "1" "May 2026" ""
.SH "NAME"
\fBbundle\-console\fR \- Open an IRB session with the bundle pre\-loaded
.SH "SYNOPSIS"
diff --git a/lib/bundler/man/bundle-doctor.1 b/lib/bundler/man/bundle-doctor.1
index 6d4b0376a6..4c59871b66 100644
--- a/lib/bundler/man/bundle-doctor.1
+++ b/lib/bundler/man/bundle-doctor.1
@@ -1,6 +1,6 @@
.\" generated with Ronn-NG/v0.10.1
.\" http://github.com/apjanke/ronn-ng/tree/0.10.1
-.TH "BUNDLE\-DOCTOR" "1" "August 2025" ""
+.TH "BUNDLE\-DOCTOR" "1" "May 2026" ""
.SH "NAME"
\fBbundle\-doctor\fR \- Checks the bundle for common problems
.SH "SYNOPSIS"
diff --git a/lib/bundler/man/bundle-env.1 b/lib/bundler/man/bundle-env.1
index 28ccc17f03..25fcb64891 100644
--- a/lib/bundler/man/bundle-env.1
+++ b/lib/bundler/man/bundle-env.1
@@ -1,6 +1,6 @@
.\" generated with Ronn-NG/v0.10.1
.\" http://github.com/apjanke/ronn-ng/tree/0.10.1
-.TH "BUNDLE\-ENV" "1" "August 2025" ""
+.TH "BUNDLE\-ENV" "1" "May 2026" ""
.SH "NAME"
\fBbundle\-env\fR \- Print information about the environment Bundler is running under
.SH "SYNOPSIS"
diff --git a/lib/bundler/man/bundle-exec.1 b/lib/bundler/man/bundle-exec.1
index cd53916cff..c3a6a09d57 100644
--- a/lib/bundler/man/bundle-exec.1
+++ b/lib/bundler/man/bundle-exec.1
@@ -1,10 +1,10 @@
.\" generated with Ronn-NG/v0.10.1
.\" http://github.com/apjanke/ronn-ng/tree/0.10.1
-.TH "BUNDLE\-EXEC" "1" "August 2025" ""
+.TH "BUNDLE\-EXEC" "1" "May 2026" ""
.SH "NAME"
\fBbundle\-exec\fR \- Execute a command in the context of the bundle
.SH "SYNOPSIS"
-\fBbundle exec\fR [\-\-keep\-file\-descriptors] [\-\-gemfile=GEMFILE] \fIcommand\fR
+\fBbundle exec\fR [\-\-gemfile=GEMFILE] \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
@@ -13,9 +13,6 @@ Essentially, if you would normally have run something like \fBrspec spec/my_spec
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\.
-.TP
\fB\-\-gemfile=GEMFILE\fR
Use the specified gemfile instead of [\fBGemfile(5)\fR][Gemfile(5)]\.
.SH "BUNDLE INSTALL \-\-BINSTUBS"
diff --git a/lib/bundler/man/bundle-exec.1.ronn b/lib/bundler/man/bundle-exec.1.ronn
index 3d3f0eed7b..e51a66a084 100644
--- a/lib/bundler/man/bundle-exec.1.ronn
+++ b/lib/bundler/man/bundle-exec.1.ronn
@@ -3,7 +3,7 @@ bundle-exec(1) -- Execute a command in the context of the bundle
## SYNOPSIS
-`bundle exec` [--keep-file-descriptors] [--gemfile=GEMFILE] <command>
+`bundle exec` [--gemfile=GEMFILE] <command>
## DESCRIPTION
@@ -20,10 +20,6 @@ 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.
-
* `--gemfile=GEMFILE`:
Use the specified gemfile instead of [`Gemfile(5)`][Gemfile(5)].
diff --git a/lib/bundler/man/bundle-fund.1 b/lib/bundler/man/bundle-fund.1
index a91c180951..caee1f81dd 100644
--- a/lib/bundler/man/bundle-fund.1
+++ b/lib/bundler/man/bundle-fund.1
@@ -1,6 +1,6 @@
.\" generated with Ronn-NG/v0.10.1
.\" http://github.com/apjanke/ronn-ng/tree/0.10.1
-.TH "BUNDLE\-FUND" "1" "August 2025" ""
+.TH "BUNDLE\-FUND" "1" "May 2026" ""
.SH "NAME"
\fBbundle\-fund\fR \- Lists information about gems seeking funding assistance
.SH "SYNOPSIS"
diff --git a/lib/bundler/man/bundle-gem.1 b/lib/bundler/man/bundle-gem.1
index 5fe2777230..87d7568246 100644
--- a/lib/bundler/man/bundle-gem.1
+++ b/lib/bundler/man/bundle-gem.1
@@ -1,6 +1,6 @@
.\" generated with Ronn-NG/v0.10.1
.\" http://github.com/apjanke/ronn-ng/tree/0.10.1
-.TH "BUNDLE\-GEM" "1" "August 2025" ""
+.TH "BUNDLE\-GEM" "1" "May 2026" ""
.SH "NAME"
\fBbundle\-gem\fR \- Generate a project skeleton for creating a rubygem
.SH "SYNOPSIS"
@@ -38,8 +38,8 @@ Add a \fBCHANGELOG\.md\fR file to the root of the generated project\. If this op
\fB\-\-no\-changelog\fR
Do not create a \fBCHANGELOG\.md\fR (overrides \fB\-\-changelog\fR specified in the global config)\.
.TP
-\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\.
+\fB\-\-ext=c\fR, \fB\-\-ext=go\fR, \fB\-\-ext=rust\fR
+Add boilerplate for C, Go (currently go\-gem\-wrapper \fIhttps://github\.com/ruby\-go\-gem/go\-gem\-wrapper\fR based) or Rust (currently magnus \fIhttps://docs\.rs/magnus\fR based) extension code to the generated project\. This behavior is disabled by default\.
.TP
\fB\-\-no\-ext\fR
Do not add extension code (overrides \fB\-\-ext\fR specified in the global config)\.
@@ -92,9 +92,6 @@ When Bundler is unconfigured, an interactive prompt will be displayed and the an
\fB\-\-no\-linter\fR
Do not add a linter (overrides \fB\-\-linter\fR specified in the global config)\.
.TP
-\fB\-\-rubocop\fR
-Add rubocop to the generated Rakefile and gemspec\. Set a default with \fBbundle config set \-\-global gem\.rubocop true\fR\.
-.TP
\fB\-\-edit=EDIT\fR, \fB\-e=EDIT\fR
Open the resulting GEM_NAME\.gemspec in EDIT, or the default editor if not specified\. The default is \fB$BUNDLER_EDITOR\fR, \fB$VISUAL\fR, or \fB$EDITOR\fR\.
.TP
diff --git a/lib/bundler/man/bundle-gem.1.ronn b/lib/bundler/man/bundle-gem.1.ronn
index b1327aa342..488c8113e4 100644
--- a/lib/bundler/man/bundle-gem.1.ronn
+++ b/lib/bundler/man/bundle-gem.1.ronn
@@ -51,8 +51,8 @@ configuration file using the following names:
Do not create a `CHANGELOG.md` (overrides `--changelog` specified in the
global config).
-* `--ext=c`, `--ext=rust`:
- Add boilerplate for C or Rust (currently [magnus](https://docs.rs/magnus) based) extension code to the generated project. This behavior
+* `--ext=c`, `--ext=go`, `--ext=rust`:
+ Add boilerplate for C, Go (currently [go-gem-wrapper](https://github.com/ruby-go-gem/go-gem-wrapper) based) or Rust (currently [magnus](https://docs.rs/magnus) based) extension code to the generated project. This behavior
is disabled by default.
* `--no-ext`:
@@ -135,9 +135,6 @@ configuration file using the following names:
* `--no-linter`:
Do not add a linter (overrides `--linter` specified in the global config).
-* `--rubocop`:
- Add rubocop to the generated Rakefile and gemspec. Set a default with `bundle config set --global gem.rubocop true`.
-
* `--edit=EDIT`, `-e=EDIT`:
Open the resulting GEM_NAME.gemspec in EDIT, 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 9ea28bef14..3bcfd047e5 100644
--- a/lib/bundler/man/bundle-help.1
+++ b/lib/bundler/man/bundle-help.1
@@ -1,6 +1,6 @@
.\" generated with Ronn-NG/v0.10.1
.\" http://github.com/apjanke/ronn-ng/tree/0.10.1
-.TH "BUNDLE\-HELP" "1" "August 2025" ""
+.TH "BUNDLE\-HELP" "1" "May 2026" ""
.SH "NAME"
\fBbundle\-help\fR \- Displays detailed help for each subcommand
.SH "SYNOPSIS"
diff --git a/lib/bundler/man/bundle-info.1 b/lib/bundler/man/bundle-info.1
index 29d649d342..49c2295f8c 100644
--- a/lib/bundler/man/bundle-info.1
+++ b/lib/bundler/man/bundle-info.1
@@ -1,6 +1,6 @@
.\" generated with Ronn-NG/v0.10.1
.\" http://github.com/apjanke/ronn-ng/tree/0.10.1
-.TH "BUNDLE\-INFO" "1" "August 2025" ""
+.TH "BUNDLE\-INFO" "1" "May 2026" ""
.SH "NAME"
\fBbundle\-info\fR \- Show information for the given gem in your bundle
.SH "SYNOPSIS"
diff --git a/lib/bundler/man/bundle-init.1 b/lib/bundler/man/bundle-init.1
index be9399c20f..63e2376c3f 100644
--- a/lib/bundler/man/bundle-init.1
+++ b/lib/bundler/man/bundle-init.1
@@ -1,6 +1,6 @@
.\" generated with Ronn-NG/v0.10.1
.\" http://github.com/apjanke/ronn-ng/tree/0.10.1
-.TH "BUNDLE\-INIT" "1" "August 2025" ""
+.TH "BUNDLE\-INIT" "1" "May 2026" ""
.SH "NAME"
\fBbundle\-init\fR \- Generates a Gemfile into the current working directory
.SH "SYNOPSIS"
diff --git a/lib/bundler/man/bundle-inject.1 b/lib/bundler/man/bundle-inject.1
deleted file mode 100644
index 7e30e26a4e..0000000000
--- a/lib/bundler/man/bundle-inject.1
+++ /dev/null
@@ -1,31 +0,0 @@
-.\" generated with Ronn-NG/v0.10.1
-.\" http://github.com/apjanke/ronn-ng/tree/0.10.1
-.TH "BUNDLE\-INJECT" "1" "August 2025" ""
-.SH "NAME"
-\fBbundle\-inject\fR \- Add named gem(s) with version requirements to Gemfile
-.SH "SYNOPSIS"
-\fBbundle inject\fR [GEM] [VERSION] [\-\-source=SOURCE] [\-\-group=GROUP]
-.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\.
-.P
-Example:
-.IP "" 4
-.nf
-bundle install
-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\.
-.P
-The \fBbundle inject\fR command was deprecated in Bundler 2\.1 and will be removed in Bundler 4\.0\.
-.SH "OPTIONS"
-.TP
-\fB\-\-source=SOURCE\fR
-Install gem from the given source\.
-.TP
-\fB\-\-group=GROUP\fR
-Install gem into a bundler group\.
-
diff --git a/lib/bundler/man/bundle-inject.1.ronn b/lib/bundler/man/bundle-inject.1.ronn
deleted file mode 100644
index 7f6f0fb5b6..0000000000
--- a/lib/bundler/man/bundle-inject.1.ronn
+++ /dev/null
@@ -1,32 +0,0 @@
-bundle-inject(1) -- Add named gem(s) with version requirements to Gemfile
-=========================================================================
-
-## SYNOPSIS
-
-`bundle inject` [GEM] [VERSION] [--source=SOURCE] [--group=GROUP]
-
-## DESCRIPTION
-
-Adds the named gem(s) with their version requirements to the resolved
-[`Gemfile(5)`][Gemfile(5)].
-
-This command will add the gem to both your [`Gemfile(5)`][Gemfile(5)] and Gemfile.lock if it
-isn't listed yet.
-
-Example:
-
- bundle install
- bundle inject 'rack' '> 0'
-
-This will inject the 'rack' gem with a version greater than 0 in your
-[`Gemfile(5)`][Gemfile(5)] and Gemfile.lock.
-
-The `bundle inject` command was deprecated in Bundler 2.1 and will be removed in Bundler 4.0.
-
-## OPTIONS
-
-* `--source=SOURCE`:
- Install gem from the given source.
-
-* `--group=GROUP`:
- Install gem into a bundler group.
diff --git a/lib/bundler/man/bundle-install.1 b/lib/bundler/man/bundle-install.1
index f9bbade2fd..801768c7ec 100644
--- a/lib/bundler/man/bundle-install.1
+++ b/lib/bundler/man/bundle-install.1
@@ -1,10 +1,10 @@
.\" generated with Ronn-NG/v0.10.1
.\" http://github.com/apjanke/ronn-ng/tree/0.10.1
-.TH "BUNDLE\-INSTALL" "1" "August 2025" ""
+.TH "BUNDLE\-INSTALL" "1" "May 2026" ""
.SH "NAME"
\fBbundle\-install\fR \- Install the dependencies specified in your Gemfile
.SH "SYNOPSIS"
-\fBbundle install\fR [\-\-binstubs[=DIRECTORY]] [\-\-clean] [\-\-deployment] [\-\-force] [\-\-frozen] [\-\-full\-index] [\-\-gemfile=GEMFILE] [\-\-jobs=NUMBER] [\-\-local] [\-\-no\-cache] [\-\-no\-prune] [\-\-path PATH] [\-\-prefer\-local] [\-\-quiet] [\-\-retry=NUMBER] [\-\-shebang=SHEBANG] [\-\-standalone[=GROUP[ GROUP\|\.\|\.\|\.]]] [\-\-system] [\-\-trust\-policy=TRUST\-POLICY] [\-\-target\-rbconfig=TARGET\-RBCONFIG] [\-\-with=GROUP[ GROUP\|\.\|\.\|\.]] [\-\-without=GROUP[ GROUP\|\.\|\.\|\.]]
+\fBbundle install\fR [\-\-cooldown=NUMBER] [\-\-force] [\-\-full\-index] [\-\-gemfile=GEMFILE] [\-\-jobs=NUMBER] [\-\-local] [\-\-lockfile=LOCKFILE] [\-\-no\-cache] [\-\-no\-lock] [\-\-prefer\-local] [\-\-quiet] [\-\-retry=NUMBER] [\-\-standalone[=GROUP[ GROUP\|\.\|\.\|\.]]] [\-\-trust\-policy=TRUST\-POLICY] [\-\-target\-rbconfig=TARGET\-RBCONFIG]
.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
@@ -12,31 +12,13 @@ If a \fBGemfile\.lock\fR does exist, and you have not updated your Gemfile(5), B
.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[=BINSTUBS]\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 when the option is used without a value, or to the given \fB<BINSTUBS>\fR directory otherwise) 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\.
-.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\.
-.IP
-This option is deprecated in favor of the \fBdeployment\fR setting\.
+\fB\-\-cooldown=<number>\fR
+Only consider gem versions published at least \fInumber\fR days ago when resolving\. Pass \fB0\fR to disable cooldown for this run, overriding any per\-source or global configuration\. See \fBcooldown\fR in bundle\-config(1) for details on the precedence between the CLI flag, Bundler config, and Gemfile per\-source settings\.
.TP
\fB\-\-force\fR, \fB\-\-redownload\fR
Force reinstalling every gem, even if already installed\.
.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\.
.TP
@@ -49,21 +31,19 @@ The maximum number of parallel download and install jobs\. The default is the nu
\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\.
.TP
+\fB\-\-lockfile=LOCKFILE\fR
+The location of the lockfile which Bundler should use\. This defaults to the Gemfile location with \fB\.lock\fR appended\.
+.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\.
.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\.
-.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\.
+\fB\-\-no\-lock\fR
+Do not create a lockfile\. Useful if you want to install dependencies but not lock versions of gems\. Recommended for library development, and other situations where the code is expected to work with a range of dependency versions\.
.IP
-This option is deprecated in favor of the \fBpath\fR setting\.
+This has the same effect as using \fBlockfile false\fR in the Gemfile\. See gemfile(5) for more information\.
.TP
\fB\-\-quiet\fR
Do not print progress information to the standard output\.
@@ -71,36 +51,16 @@ Do not print progress information to the standard output\.
\fB\-\-retry=[<number>]\fR
Retry failed network or git requests for \fInumber\fR times\.
.TP
-\fB\-\-shebang=SHEBANG\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 can 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\.
-.IP
-This option is deprecated in favor of the \fBsystem\fR setting\.
+Makes a bundle that can work without depending on Rubygems or Bundler at runtime\. A space separated list of groups to install can 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\.
.TP
\fB\-\-trust\-policy=TRUST\-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\-\-target\-rbconfig=TARGET\-RBCONFIG\fR
Path to rbconfig\.rb for the deployment target platform\.
-.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 \fBdeployment\fR setting\. 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
@@ -120,14 +80,14 @@ In development, it's convenient to share the gems used in your application with
.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\.
+As a result, when \fBdeployment\fR is configured, \fBbundle install\fR installs gems to the \fBvendor/bundle\fR directory in the application\. This may be overridden using the \fBpath\fR setting\.
.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\.
+However, you can explicitly tell Bundler to skip installing certain groups with the \fBwithout\fR setting\. This setting 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)\.
+While the \fBwithout\fR setting will skip \fIinstalling\fR the gems in the specified groups, \fBbundle install\fR 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
@@ -148,7 +108,7 @@ end
.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\.
+When you configure \fBbundle config 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
diff --git a/lib/bundler/man/bundle-install.1.ronn b/lib/bundler/man/bundle-install.1.ronn
index cc6241dd67..56fd8bdf42 100644
--- a/lib/bundler/man/bundle-install.1.ronn
+++ b/lib/bundler/man/bundle-install.1.ronn
@@ -3,28 +3,21 @@ bundle-install(1) -- Install the dependencies specified in your Gemfile
## SYNOPSIS
-`bundle install` [--binstubs[=DIRECTORY]]
- [--clean]
- [--deployment]
+`bundle install` [--cooldown=NUMBER]
[--force]
- [--frozen]
[--full-index]
[--gemfile=GEMFILE]
[--jobs=NUMBER]
[--local]
+ [--lockfile=LOCKFILE]
[--no-cache]
- [--no-prune]
- [--path PATH]
+ [--no-lock]
[--prefer-local]
[--quiet]
[--retry=NUMBER]
- [--shebang=SHEBANG]
[--standalone[=GROUP[ GROUP...]]]
- [--system]
[--trust-policy=TRUST-POLICY]
[--target-rbconfig=TARGET-RBCONFIG]
- [--with=GROUP[ GROUP...]]
- [--without=GROUP[ GROUP...]]
## DESCRIPTION
@@ -45,50 +38,16 @@ update process below under [CONSERVATIVE UPDATING][].
## OPTIONS
-The `--clean`, `--deployment`, `--frozen`, `--no-prune`, `--path`, `--shebang`,
-`--system`, `--without` and `--with` options are deprecated because they only
-make sense if they are applied to every subsequent `bundle install` run
-automatically and that requires `bundler` to silently remember them. Since
-`bundler` will no longer remember CLI flags in future versions, `bundle config`
-(see bundle-config(1)) should be used to apply them permanently.
-
-* `--binstubs[=BINSTUBS]`:
- 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 `bin/`.
- This lets you link the binstub inside of an application to the exact gem
- version the application needs.
-
- Creates a directory (defaults to `~/bin` when the option is used without a
- value, or to the given `<BINSTUBS>` directory otherwise) 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 `PATH` variable. For
- instance, if the `rails` gem comes with a `rails` executable, this flag will
- create a `bin/rails` executable that ensures that all referred dependencies
- will be resolved using the bundled gems.
-
-* `--clean`:
- 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.
-
- This option is deprecated in favor of the `clean` setting.
-
-* `--deployment`:
- In [deployment mode][DEPLOYMENT MODE], 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.
-
- This option is deprecated in favor of the `deployment` setting.
+* `--cooldown=<number>`:
+ Only consider gem versions published at least <number> days ago when
+ resolving. Pass `0` to disable cooldown for this run, overriding any
+ per-source or global configuration. See `cooldown` in bundle-config(1)
+ for details on the precedence between the CLI flag, Bundler config,
+ and Gemfile per-source settings.
* `--force`, `--redownload`:
Force reinstalling every gem, even if already installed.
-* `--frozen`:
- 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.
-
- This option is deprecated in favor of the `frozen` setting.
-
* `--full-index`:
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
@@ -111,6 +70,10 @@ automatically and that requires `bundler` to silently remember them. Since
appropriate platform-specific gem exists on `rubygems.org` it will not be
found.
+* `--lockfile=LOCKFILE`:
+ The location of the lockfile which Bundler should use. This defaults
+ to the Gemfile location with `.lock` appended.
+
* `--prefer-local`:
Force using locally installed gems, or gems already present in Rubygems' cache
or in `vendor/cache`, when resolving, even if newer versions are available
@@ -122,19 +85,14 @@ automatically and that requires `bundler` to silently remember them. Since
does not remove any gems in the cache but keeps the newly bundled gems from
being cached during the install.
-* `--no-prune`:
- Don't remove stale gems from the cache when the installation finishes.
-
- This option is deprecated in favor of the `no_prune` setting.
+* `--no-lock`:
+ Do not create a lockfile. Useful if you want to install dependencies but not
+ lock versions of gems. Recommended for library development, and other
+ situations where the code is expected to work with a range of dependency
+ versions.
-* `--path=PATH`:
- The location to install the specified gems to. This defaults to Rubygems'
- setting. Bundler shares this location with Rubygems, `gem install ...` will
- have gem installed there, too. Therefore, gems installed without a
- `--path ...` setting will show up by calling `gem list`. Accordingly, gems
- installed to other locations will not get listed.
-
- This option is deprecated in favor of the `path` setting.
+ This has the same effect as using `lockfile false` in the Gemfile.
+ See gemfile(5) for more information.
* `--quiet`:
Do not print progress information to the standard output.
@@ -142,27 +100,12 @@ automatically and that requires `bundler` to silently remember them. Since
* `--retry=[<number>]`:
Retry failed network or git requests for <number> times.
-* `--shebang=SHEBANG`:
- Uses the specified ruby executable (usually `ruby`) to execute the scripts
- created with `--binstubs`. In addition, if you use `--binstubs` together with
- `--shebang jruby` these executables will be changed to execute `jruby`
- instead.
-
- This option is deprecated in favor of the `shebang` setting.
-
* `--standalone[=<list>]`:
Makes a bundle that can work without depending on Rubygems or Bundler at
runtime. A space separated list of groups to install can be specified.
Bundler creates a directory named `bundle` and installs the bundle there. It
also generates a `bundle/bundler/setup.rb` file to replace Bundler's own setup
- in the manner required. Using this option implicitly sets `path`, which is a
- [remembered option][REMEMBERED OPTIONS].
-
-* `--system`:
- Installs the gems specified in the bundle to the system's Rubygems location.
- This overrides any previous configuration of `--path`.
-
- This option is deprecated in favor of the `system` setting.
+ in the manner required.
* `--trust-policy=TRUST-POLICY`:
Apply the Rubygems security policy <policy>, where policy is one of
@@ -173,26 +116,11 @@ automatically and that requires `bundler` to silently remember them. Since
* `--target-rbconfig=TARGET-RBCONFIG`:
Path to rbconfig.rb for the deployment target platform.
-* `--with=<list>`:
- 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.
-
- This option is deprecated in favor of the `with` setting.
-
-* `--without=<list>`:
- 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.
-
- This option is deprecated in favor of the `without` setting.
-
## DEPLOYMENT MODE
Bundler's defaults are optimized for development. To switch to
-defaults optimized for deployment and for CI, use the `--deployment`
-flag. Do not activate deployment mode on development machines, as it
+defaults optimized for deployment and for CI, use the `deployment`
+setting. Do not activate deployment mode on development machines, as it
will cause an error when the Gemfile(5) is modified.
1. A `Gemfile.lock` is required.
@@ -224,9 +152,9 @@ will cause an error when the Gemfile(5) is modified.
gems to the system, or the web server may not have permission to
read them.
- As a result, `bundle install --deployment` installs gems to
- the `vendor/bundle` directory in the application. This may be
- overridden using the `--path` option.
+ As a result, when `deployment` is configured, `bundle install` installs gems
+ to the `vendor/bundle` directory in the application. This may be
+ overridden using the `path` setting.
## INSTALLING GROUPS
@@ -234,12 +162,12 @@ By default, `bundle install` will install all gems in all groups
in your Gemfile(5), except those declared for a different platform.
However, you can explicitly tell Bundler to skip installing
-certain groups with the `--without` option. This option takes
+certain groups with the `without` setting. This setting takes
a space-separated list of groups.
-While the `--without` option will skip _installing_ the gems in the
-specified groups, it will still _download_ those gems and use them to
-resolve the dependencies of every gem in your Gemfile(5).
+While the `without` setting will skip _installing_ the gems in the
+specified groups, `bundle install` will still _download_ those gems and use them
+to resolve the dependencies of every gem in your Gemfile(5).
This is so that installing a different set of groups on another
machine (such as a production server) will not change the
@@ -265,7 +193,7 @@ For a simple illustration, consider the following Gemfile(5):
In this case, `sinatra` depends on any version of Rack (`>= 1.0`), while
`rack-perftools-profiler` depends on 1.x (`~> 1.0`).
-When you run `bundle install --without production` in development, we
+When you configure `bundle config without production` in development, we
look at the dependencies of `rack-perftools-profiler` 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
diff --git a/lib/bundler/man/bundle-issue.1 b/lib/bundler/man/bundle-issue.1
index 3c7e5305f3..3af277ef86 100644
--- a/lib/bundler/man/bundle-issue.1
+++ b/lib/bundler/man/bundle-issue.1
@@ -1,6 +1,6 @@
.\" generated with Ronn-NG/v0.10.1
.\" http://github.com/apjanke/ronn-ng/tree/0.10.1
-.TH "BUNDLE\-ISSUE" "1" "August 2025" ""
+.TH "BUNDLE\-ISSUE" "1" "May 2026" ""
.SH "NAME"
\fBbundle\-issue\fR \- Get help reporting Bundler issues
.SH "SYNOPSIS"
diff --git a/lib/bundler/man/bundle-licenses.1 b/lib/bundler/man/bundle-licenses.1
index eb0ad5ae40..ab5996d2be 100644
--- a/lib/bundler/man/bundle-licenses.1
+++ b/lib/bundler/man/bundle-licenses.1
@@ -1,6 +1,6 @@
.\" generated with Ronn-NG/v0.10.1
.\" http://github.com/apjanke/ronn-ng/tree/0.10.1
-.TH "BUNDLE\-LICENSES" "1" "August 2025" ""
+.TH "BUNDLE\-LICENSES" "1" "May 2026" ""
.SH "NAME"
\fBbundle\-licenses\fR \- Print the license of all gems in the bundle
.SH "SYNOPSIS"
diff --git a/lib/bundler/man/bundle-list.1 b/lib/bundler/man/bundle-list.1
index a345787a5e..e759e0d449 100644
--- a/lib/bundler/man/bundle-list.1
+++ b/lib/bundler/man/bundle-list.1
@@ -1,6 +1,6 @@
.\" generated with Ronn-NG/v0.10.1
.\" http://github.com/apjanke/ronn-ng/tree/0.10.1
-.TH "BUNDLE\-LIST" "1" "August 2025" ""
+.TH "BUNDLE\-LIST" "1" "May 2026" ""
.SH "NAME"
\fBbundle\-list\fR \- List all the gems in the bundle
.SH "SYNOPSIS"
diff --git a/lib/bundler/man/bundle-lock.1 b/lib/bundler/man/bundle-lock.1
index 79aa1e2452..396c8ff6ca 100644
--- a/lib/bundler/man/bundle-lock.1
+++ b/lib/bundler/man/bundle-lock.1
@@ -1,6 +1,6 @@
.\" generated with Ronn-NG/v0.10.1
.\" http://github.com/apjanke/ronn-ng/tree/0.10.1
-.TH "BUNDLE\-LOCK" "1" "August 2025" ""
+.TH "BUNDLE\-LOCK" "1" "May 2026" ""
.SH "NAME"
\fBbundle\-lock\fR \- Creates / Updates a lockfile without installing
.SH "SYNOPSIS"
diff --git a/lib/bundler/man/bundle-open.1 b/lib/bundler/man/bundle-open.1
index b1c2022f40..2aab59f14b 100644
--- a/lib/bundler/man/bundle-open.1
+++ b/lib/bundler/man/bundle-open.1
@@ -1,6 +1,6 @@
.\" generated with Ronn-NG/v0.10.1
.\" http://github.com/apjanke/ronn-ng/tree/0.10.1
-.TH "BUNDLE\-OPEN" "1" "August 2025" ""
+.TH "BUNDLE\-OPEN" "1" "May 2026" ""
.SH "NAME"
\fBbundle\-open\fR \- Opens the source directory for a gem in your bundle
.SH "SYNOPSIS"
diff --git a/lib/bundler/man/bundle-outdated.1 b/lib/bundler/man/bundle-outdated.1
index d4790f8876..c2f8086e24 100644
--- a/lib/bundler/man/bundle-outdated.1
+++ b/lib/bundler/man/bundle-outdated.1
@@ -1,10 +1,10 @@
.\" generated with Ronn-NG/v0.10.1
.\" http://github.com/apjanke/ronn-ng/tree/0.10.1
-.TH "BUNDLE\-OUTDATED" "1" "August 2025" ""
+.TH "BUNDLE\-OUTDATED" "1" "May 2026" ""
.SH "NAME"
\fBbundle\-outdated\fR \- List installed gems with newer versions available
.SH "SYNOPSIS"
-\fBbundle outdated\fR [GEM] [\-\-local] [\-\-pre] [\-\-source] [\-\-filter\-strict | \-\-strict] [\-\-update\-strict] [\-\-parseable | \-\-porcelain] [\-\-group=GROUP] [\-\-groups] [\-\-patch|\-\-minor|\-\-major] [\-\-filter\-major] [\-\-filter\-minor] [\-\-filter\-patch] [\-\-only\-explicit]
+\fBbundle outdated\fR [GEM] [\-\-local] [\-\-pre] [\-\-source] [\-\-filter\-strict | \-\-strict] [\-\-update\-strict] [\-\-parseable | \-\-porcelain] [\-\-group=GROUP] [\-\-groups] [\-\-patch|\-\-minor|\-\-major] [\-\-filter\-major] [\-\-filter\-minor] [\-\-filter\-patch] [\-\-only\-explicit] [\-\-cooldown=NUMBER]
.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"
@@ -53,6 +53,9 @@ Only list patch newer versions\.
.TP
\fB\-\-only\-explicit\fR
Only list gems specified in your Gemfile, not their dependencies\.
+.TP
+\fB\-\-cooldown=<number>\fR
+Annotate (rather than hide) versions that are still inside the cooldown window of \fInumber\fR days\. The prose output appends "in cooldown for Nd more days" and the table form adds "(cooldown Nd)" to the Latest column\. See \fBcooldown\fR in bundle\-config(1)\.
.SH "PATCH LEVEL OPTIONS"
See bundle update(1) \fIbundle\-update\.1\.html\fR for details\.
.SH "FILTERING OUTPUT"
@@ -61,42 +64,42 @@ The 3 filtering options do not affect the resolution of versions, merely what ve
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
+* Gem Current Latest Requested Groups Release Date
+* faker 1\.6\.5 1\.6\.6 ~> 1\.4 development, test 2024\-02\-05
+* hashie 1\.2\.0 3\.4\.6 = 1\.2\.0 default 2023\-11\-10
+* headless 2\.2\.3 2\.3\.1 = 2\.2\.3 test 2022\-08\-19
.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
+* Gem Current Latest Requested Groups Release Date
+* hashie 1\.2\.0 3\.4\.6 = 1\.2\.0 default 2023\-11\-10
.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
+* Gem Current Latest Requested Groups Release Date
+* headless 2\.2\.3 2\.3\.1 = 2\.2\.3 test 2022\-08\-19
.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
+* Gem Current Latest Requested Groups Release Date
+* faker 1\.6\.5 1\.6\.6 ~> 1\.4 development, test 2024\-02\-05
.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
+* Gem Current Latest Requested Groups Release Date
+* faker 1\.6\.5 1\.6\.6 ~> 1\.4 development, test 2024\-02\-05
.fi
.IP "" 0
.P
diff --git a/lib/bundler/man/bundle-outdated.1.ronn b/lib/bundler/man/bundle-outdated.1.ronn
index 6f67a31977..e5badac2e9 100644
--- a/lib/bundler/man/bundle-outdated.1.ronn
+++ b/lib/bundler/man/bundle-outdated.1.ronn
@@ -16,6 +16,7 @@ bundle-outdated(1) -- List installed gems with newer versions available
[--filter-minor]
[--filter-patch]
[--only-explicit]
+ [--cooldown=NUMBER]
## DESCRIPTION
@@ -71,6 +72,12 @@ are up to date, Bundler will exit with a status of 0. Otherwise, it will exit 1.
* `--only-explicit`:
Only list gems specified in your Gemfile, not their dependencies.
+* `--cooldown=<number>`:
+ Annotate (rather than hide) versions that are still inside the
+ cooldown window of <number> days. The prose output appends "in
+ cooldown for Nd more days" and the table form adds "(cooldown Nd)" to
+ the Latest column. See `cooldown` in bundle-config(1).
+
## PATCH LEVEL OPTIONS
See [bundle update(1)](bundle-update.1.html) for details.
@@ -82,29 +89,29 @@ in the output.
If the regular output shows the following:
- * 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
+ * Gem Current Latest Requested Groups Release Date
+ * faker 1.6.5 1.6.6 ~> 1.4 development, test 2024-02-05
+ * hashie 1.2.0 3.4.6 = 1.2.0 default 2023-11-10
+ * headless 2.2.3 2.3.1 = 2.2.3 test 2022-08-19
`--filter-major` would only show:
- * Gem Current Latest Requested Groups
- * hashie 1.2.0 3.4.6 = 1.2.0 default
+ * Gem Current Latest Requested Groups Release Date
+ * hashie 1.2.0 3.4.6 = 1.2.0 default 2023-11-10
`--filter-minor` would only show:
- * Gem Current Latest Requested Groups
- * headless 2.2.3 2.3.1 = 2.2.3 test
+ * Gem Current Latest Requested Groups Release Date
+ * headless 2.2.3 2.3.1 = 2.2.3 test 2022-08-19
`--filter-patch` would only show:
- * Gem Current Latest Requested Groups
- * faker 1.6.5 1.6.6 ~> 1.4 development, test
+ * Gem Current Latest Requested Groups Release Date
+ * faker 1.6.5 1.6.6 ~> 1.4 development, test 2024-02-05
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
+ * Gem Current Latest Requested Groups Release Date
+ * faker 1.6.5 1.6.6 ~> 1.4 development, test 2024-02-05
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 78de506b57..39b7111263 100644
--- a/lib/bundler/man/bundle-platform.1
+++ b/lib/bundler/man/bundle-platform.1
@@ -1,6 +1,6 @@
.\" generated with Ronn-NG/v0.10.1
.\" http://github.com/apjanke/ronn-ng/tree/0.10.1
-.TH "BUNDLE\-PLATFORM" "1" "August 2025" ""
+.TH "BUNDLE\-PLATFORM" "1" "May 2026" ""
.SH "NAME"
\fBbundle\-platform\fR \- Displays platform compatibility information
.SH "SYNOPSIS"
diff --git a/lib/bundler/man/bundle-plugin.1 b/lib/bundler/man/bundle-plugin.1
index 5fcc88b50d..d182c7789b 100644
--- a/lib/bundler/man/bundle-plugin.1
+++ b/lib/bundler/man/bundle-plugin.1
@@ -1,10 +1,10 @@
.\" generated with Ronn-NG/v0.10.1
.\" http://github.com/apjanke/ronn-ng/tree/0.10.1
-.TH "BUNDLE\-PLUGIN" "1" "August 2025" ""
+.TH "BUNDLE\-PLUGIN" "1" "May 2026" ""
.SH "NAME"
\fBbundle\-plugin\fR \- Manage Bundler plugins
.SH "SYNOPSIS"
-\fBbundle plugin\fR install PLUGINS [\-\-source=SOURCE] [\-\-version=VERSION] [\-\-git=GIT] [\-\-branch=BRANCH|\-\-ref=REF] [\-\-local\-git=LOCAL_GIT] [\-\-path=PATH]
+\fBbundle plugin\fR install PLUGINS [\-\-source=SOURCE] [\-\-version=VERSION] [\-\-git=GIT] [\-\-branch=BRANCH|\-\-ref=REF] [\-\-path=PATH]
.br
\fBbundle plugin\fR uninstall PLUGINS [\-\-all]
.br
@@ -54,13 +54,6 @@ When you specify \fB\-\-git\fR, you can use \fB\-\-ref\fR to specify any tag, or
Install the plugin gem from a local path\.
.IP
Example: \fBbundle plugin install bundler\-graph \-\-path \.\./bundler\-graph\fR
-.TP
-\fB\-\-local\-git=LOCAL_GIT\fR
-Install the plugin gem from a local Git repository\.
-.IP
-Example: \fBbundle plugin install bundler\-graph \-\-local\-git \.\./bundler\-graph\fR\.
-.IP
-This option is deprecated in favor of \fB\-\-git\fR\.
.SS "uninstall"
Uninstall the plugin(s) specified in PLUGINS\.
.P
diff --git a/lib/bundler/man/bundle-plugin.1.ronn b/lib/bundler/man/bundle-plugin.1.ronn
index efb4240761..b54e0c08b4 100644
--- a/lib/bundler/man/bundle-plugin.1.ronn
+++ b/lib/bundler/man/bundle-plugin.1.ronn
@@ -5,7 +5,6 @@ bundle-plugin(1) -- Manage Bundler plugins
`bundle plugin` install PLUGINS [--source=SOURCE] [--version=VERSION]
[--git=GIT] [--branch=BRANCH|--ref=REF]
- [--local-git=LOCAL_GIT]
[--path=PATH]<br>
`bundle plugin` uninstall PLUGINS [--all]<br>
`bundle plugin` list<br>
@@ -59,13 +58,6 @@ global source specified in Gemfile is ignored.
Example: `bundle plugin install bundler-graph --path ../bundler-graph`
-* `--local-git=LOCAL_GIT`:
- Install the plugin gem from a local Git repository.
-
- Example: `bundle plugin install bundler-graph --local-git ../bundler-graph`.
-
- This option is deprecated in favor of `--git`.
-
### uninstall
Uninstall the plugin(s) specified in PLUGINS.
diff --git a/lib/bundler/man/bundle-pristine.1 b/lib/bundler/man/bundle-pristine.1
index e39f264cef..f6cc066571 100644
--- a/lib/bundler/man/bundle-pristine.1
+++ b/lib/bundler/man/bundle-pristine.1
@@ -1,6 +1,6 @@
.\" generated with Ronn-NG/v0.10.1
.\" http://github.com/apjanke/ronn-ng/tree/0.10.1
-.TH "BUNDLE\-PRISTINE" "1" "August 2025" ""
+.TH "BUNDLE\-PRISTINE" "1" "May 2026" ""
.SH "NAME"
\fBbundle\-pristine\fR \- Restores installed gems to their pristine condition
.SH "SYNOPSIS"
diff --git a/lib/bundler/man/bundle-remove.1 b/lib/bundler/man/bundle-remove.1
index 6750817680..2ca40e74db 100644
--- a/lib/bundler/man/bundle-remove.1
+++ b/lib/bundler/man/bundle-remove.1
@@ -1,21 +1,15 @@
.\" generated with Ronn-NG/v0.10.1
.\" http://github.com/apjanke/ronn-ng/tree/0.10.1
-.TH "BUNDLE\-REMOVE" "1" "August 2025" ""
+.TH "BUNDLE\-REMOVE" "1" "May 2026" ""
.SH "NAME"
\fBbundle\-remove\fR \- Removes gems from the Gemfile
.SH "SYNOPSIS"
-\fBbundle remove [GEM [GEM \|\.\|\.\|\.]] [\-\-install]\fR
+`bundle remove [GEM [GEM \|\.\|\.\|\.]]
.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-remove.1.ronn b/lib/bundler/man/bundle-remove.1.ronn
index ceb1a980be..49cb4dc1fd 100644
--- a/lib/bundler/man/bundle-remove.1.ronn
+++ b/lib/bundler/man/bundle-remove.1.ronn
@@ -3,21 +3,14 @@ bundle-remove(1) -- Removes gems from the Gemfile
## SYNOPSIS
-`bundle remove [GEM [GEM ...]] [--install]`
+`bundle remove [GEM [GEM ...]]
## 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.
-## OPTIONS
-
-* `--install`:
- Runs `bundle install` 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).
-
Example:
bundle remove rails
bundle remove rails rack
-
-bundle remove rails rack --install
diff --git a/lib/bundler/man/bundle-show.1 b/lib/bundler/man/bundle-show.1
index 67b387559d..a2142694b8 100644
--- a/lib/bundler/man/bundle-show.1
+++ b/lib/bundler/man/bundle-show.1
@@ -1,10 +1,10 @@
.\" generated with Ronn-NG/v0.10.1
.\" http://github.com/apjanke/ronn-ng/tree/0.10.1
-.TH "BUNDLE\-SHOW" "1" "August 2025" ""
+.TH "BUNDLE\-SHOW" "1" "May 2026" ""
.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] [\-\-outdated]
+\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
@@ -13,7 +13,4 @@ Calling show with [GEM] will list the exact location of that gem on your machine
.TP
\fB\-\-paths\fR
List the paths of all gems that are required by your [\fBGemfile(5)\fR][Gemfile(5)], sorted by gem name\.
-.TP
-\fB\-\-outdated\fR
-Show verbose output including whether gems are outdated\.
diff --git a/lib/bundler/man/bundle-show.1.ronn b/lib/bundler/man/bundle-show.1.ronn
index 6e80b04696..a6a59a1445 100644
--- a/lib/bundler/man/bundle-show.1.ronn
+++ b/lib/bundler/man/bundle-show.1.ronn
@@ -5,7 +5,6 @@ bundle-show(1) -- Shows all the gems in your bundle, or the path to a gem
`bundle show` [GEM]
[--paths]
- [--outdated]
## DESCRIPTION
@@ -20,6 +19,3 @@ machine.
* `--paths`:
List the paths of all gems that are required by your [`Gemfile(5)`][Gemfile(5)],
sorted by gem name.
-
-* `--outdated`:
- Show verbose output including whether gems are outdated.
diff --git a/lib/bundler/man/bundle-update.1 b/lib/bundler/man/bundle-update.1
index fbcabb69a8..94161083fc 100644
--- a/lib/bundler/man/bundle-update.1
+++ b/lib/bundler/man/bundle-update.1
@@ -1,10 +1,10 @@
.\" generated with Ronn-NG/v0.10.1
.\" http://github.com/apjanke/ronn-ng/tree/0.10.1
-.TH "BUNDLE\-UPDATE" "1" "August 2025" ""
+.TH "BUNDLE\-UPDATE" "1" "May 2026" ""
.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]] [\-\-force] [\-\-full\-index] [\-\-gemfile=GEMFILE] [\-\-jobs=NUMBER] [\-\-quiet] [\-\-patch|\-\-minor|\-\-major] [\-\-pre] [\-\-strict] [\-\-conservative]
+\fBbundle update\fR \fI*gems\fR [\-\-all] [\-\-group=NAME] [\-\-source=NAME] [\-\-local] [\-\-ruby] [\-\-bundler[=VERSION]] [\-\-cooldown=NUMBER] [\-\-force] [\-\-full\-index] [\-\-gemfile=GEMFILE] [\-\-jobs=NUMBER] [\-\-quiet] [\-\-patch|\-\-minor|\-\-major] [\-\-pre] [\-\-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
@@ -64,6 +64,9 @@ Do not allow any gem to be updated past latest \fB\-\-patch\fR | \fB\-\-minor\fR
.TP
\fB\-\-conservative\fR
Use bundle install conservative update behavior and do not allow indirect dependencies to be updated\.
+.TP
+\fB\-\-cooldown=<number>\fR
+Only consider gem versions published at least \fInumber\fR days ago when resolving\. Pass \fB0\fR to disable cooldown for this run, overriding any per\-source or global configuration\. Combine with \fB\-\-conservative\fR to minimize transitive churn when bypassing cooldown for an urgent update\. See \fBcooldown\fR in bundle\-config(1)\.
.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
diff --git a/lib/bundler/man/bundle-update.1.ronn b/lib/bundler/man/bundle-update.1.ronn
index bfe381677c..72fbf054d1 100644
--- a/lib/bundler/man/bundle-update.1.ronn
+++ b/lib/bundler/man/bundle-update.1.ronn
@@ -9,6 +9,7 @@ bundle-update(1) -- Update your gems to the latest available versions
[--local]
[--ruby]
[--bundler[=VERSION]]
+ [--cooldown=NUMBER]
[--force]
[--full-index]
[--gemfile=GEMFILE]
@@ -91,6 +92,13 @@ gem.
* `--conservative`:
Use bundle install conservative update behavior and do not allow indirect dependencies to be updated.
+* `--cooldown=<number>`:
+ Only consider gem versions published at least <number> days ago when
+ resolving. Pass `0` to disable cooldown for this run, overriding any
+ per-source or global configuration. Combine with `--conservative` to
+ minimize transitive churn when bypassing cooldown for an urgent
+ update. See `cooldown` in bundle-config(1).
+
## UPDATING ALL GEMS
If you run `bundle update --all`, bundler will ignore
diff --git a/lib/bundler/man/bundle-version.1 b/lib/bundler/man/bundle-version.1
index 261140ff38..751a408312 100644
--- a/lib/bundler/man/bundle-version.1
+++ b/lib/bundler/man/bundle-version.1
@@ -1,6 +1,6 @@
.\" generated with Ronn-NG/v0.10.1
.\" http://github.com/apjanke/ronn-ng/tree/0.10.1
-.TH "BUNDLE\-VERSION" "1" "August 2025" ""
+.TH "BUNDLE\-VERSION" "1" "May 2026" ""
.SH "NAME"
\fBbundle\-version\fR \- Prints Bundler version information
.SH "SYNOPSIS"
diff --git a/lib/bundler/man/bundle-viz.1 b/lib/bundler/man/bundle-viz.1
deleted file mode 100644
index f2570103dc..0000000000
--- a/lib/bundler/man/bundle-viz.1
+++ /dev/null
@@ -1,30 +0,0 @@
-.\" generated with Ronn-NG/v0.10.1
-.\" http://github.com/apjanke/ronn-ng/tree/0.10.1
-.TH "BUNDLE\-VIZ" "1" "August 2025" ""
-.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=FILE\fR, \fB\-f=FILE\fR
-The name to use for the generated file\. See \fB\-\-format\fR option
-.TP
-\fB\-\-format=FORMAT\fR, \fB\-F=FORMAT\fR
-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=<list>\fR, \fB\-W=<list>\fR
-Exclude gems that are part of the specified named group\.
-
diff --git a/lib/bundler/man/bundle-viz.1.ronn b/lib/bundler/man/bundle-viz.1.ronn
deleted file mode 100644
index 730b0eed22..0000000000
--- a/lib/bundler/man/bundle-viz.1.ronn
+++ /dev/null
@@ -1,36 +0,0 @@
-bundle-viz(1) -- Generates a visual dependency graph for your Gemfile
-=====================================================================
-
-## SYNOPSIS
-
-`bundle viz` [--file=FILE]
- [--format=FORMAT]
- [--requirements]
- [--version]
- [--without=GROUP GROUP]
-
-## DESCRIPTION
-
-`viz` generates a PNG file of the current `Gemfile(5)` as a dependency graph.
-`viz` requires the ruby-graphviz gem (and its dependencies).
-
-The associated gems must also be installed via [`bundle install(1)`](bundle-install.1.html).
-
-`viz` command was deprecated in Bundler 2.2. Use [bundler-graph plugin](https://github.com/rubygems/bundler-graph) instead.
-
-## OPTIONS
-
-* `--file=FILE`, `-f=FILE`:
- The name to use for the generated file. See `--format` option
-
-* `--format=FORMAT`, `-F=FORMAT`:
- This is output format option. Supported format is png, jpg, svg, dot ...
-
-* `--requirements`, `-R`:
- Set to show the version of each required dependency.
-
-* `--version`, `-v`:
- Set to show each gem version.
-
-* `--without=<list>`, `-W=<list>`:
- 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 f87a98150d..167815631a 100644
--- a/lib/bundler/man/bundle.1
+++ b/lib/bundler/man/bundle.1
@@ -1,6 +1,6 @@
.\" generated with Ronn-NG/v0.10.1
.\" http://github.com/apjanke/ronn-ng/tree/0.10.1
-.TH "BUNDLE" "1" "August 2025" ""
+.TH "BUNDLE" "1" "May 2026" ""
.SH "NAME"
\fBbundle\fR \- Ruby Dependency Management
.SH "SYNOPSIS"
@@ -66,9 +66,6 @@ Open an installed gem in the editor
\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
@@ -94,9 +91,3 @@ Manage Bundler plugins
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\.
-.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/bundle.1.ronn b/lib/bundler/man/bundle.1.ronn
index 8245effabd..1c2b3df7af 100644
--- a/lib/bundler/man/bundle.1.ronn
+++ b/lib/bundler/man/bundle.1.ronn
@@ -76,9 +76,6 @@ We divide `bundle` subcommands into primary commands and utilities:
* [`bundle lock(1)`](bundle-lock.1.html):
Generate a lockfile for your dependencies
-* [`bundle viz(1)`](bundle-viz.1.html) (deprecated):
- Generate a visual representation of your dependencies
-
* [`bundle init(1)`](bundle-init.1.html):
Generate a simple `Gemfile`, placed in the current directory
@@ -108,9 +105,3 @@ We divide `bundle` subcommands into primary commands and utilities:
When running a command that isn't listed in PRIMARY COMMANDS or UTILITIES,
Bundler will try to find an executable on your path named `bundler-<command>`
and execute it, passing down any extra arguments to it.
-
-## OBSOLETE
-
-These commands are obsolete and should no longer be used:
-
-* `bundle inject(1)`
diff --git a/lib/bundler/man/gemfile.5 b/lib/bundler/man/gemfile.5
index cd04d3d198..64e93c4b15 100644
--- a/lib/bundler/man/gemfile.5
+++ b/lib/bundler/man/gemfile.5
@@ -1,6 +1,6 @@
.\" generated with Ronn-NG/v0.10.1
.\" http://github.com/apjanke/ronn-ng/tree/0.10.1
-.TH "GEMFILE" "5" "August 2025" ""
+.TH "GEMFILE" "5" "May 2026" ""
.SH "NAME"
\fBGemfile\fR \- A format for describing gem dependencies for Ruby programs
.SH "SYNOPSIS"
@@ -460,6 +460,50 @@ The \fBgemspec\fR method adds any runtime dependencies as gem requirements in th
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 "OVERRIDE"
+The \fBoverride\fR directive rewrites a constraint on another gem before resolution runs\. It targets the common case where an upstream gem's published metadata is too narrow on the current project's machine \-\- a stale upper bound, an unwanted floor, or a transitive pin that has to be lifted\.
+.IP "" 4
+.nf
+override <target>, <field>: <operation>
+.fi
+.IP "" 0
+.P
+\fB<target>\fR is a gem name string or \fB:all\fR\. \fB<field>\fR is one of \fBversion:\fR, \fBrequired_ruby_version:\fR, or \fBrequired_rubygems_version:\fR\. \fB<operation>\fR is one of:
+.IP "\(bu" 4
+a version requirement string (e\.g\. \fB">= 8\.0"\fR), which \fBreplaces\fR the target's requirement absolutely\. The original requirement, both direct and transitive, is discarded in favour of the override\.
+.IP "\(bu" 4
+\fB:ignore_upper\fR, which removes upper\-bound operators (\fB<\fR and \fB<=\fR) from the existing requirement and folds \fB~>\fR into its lower bound (\fB~> 1\.5\fR becomes \fB>= 1\.5\fR)\. Other operators, including \fB!=\fR, are preserved\.
+.IP "\(bu" 4
+\fBnil\fR, which collapses the requirement to \fB>= 0\fR (no constraint at all)\.
+.IP "" 0
+.P
+\fB:all\fR only applies to \fBrequired_ruby_version:\fR and \fBrequired_rubygems_version:\fR\. A per\-gem override on the same field takes precedence over an \fB:all\fR override\. \fB:all + version:\fR is rejected: version requirements only make sense per gem\.
+.P
+Multiple \fBoverride\fR calls for distinct targets are allowed; declaring the same \fBtarget\fR and \fBfield\fR twice is an error\.
+.IP "" 4
+.nf
+source "https://rubygems\.org"
+
+# Force every reference to "rails" \-\- direct or transitive \-\- to >= 8\.0\.
+override "rails", version: ">= 8\.0"
+
+# Strip the upper bound on nokogiri\.
+override "nokogiri", version: :ignore_upper
+
+# Drop the version pin on legacy entirely\.
+override "legacy", version: nil
+
+# Loosen every gem's required_ruby_version upper bound\.
+override :all, required_ruby_version: :ignore_upper
+
+# Override one specific gem's required_rubygems_version\.
+override "tricky", required_rubygems_version: nil
+
+gem "rails", "~> 7\.0"
+.fi
+.IP "" 0
+.P
+The override only affects resolution and the install\-time Ruby/RubyGems compatibility checks; \fBGemfile\.lock\fR continues to reflect the resolved versions, not the rewritten requirements\. When resolution still fails, Bundler appends the active overrides (with their Gemfile location) to the error message so it is clear which override shaped the constraint set\.
.SH "SOURCE PRIORITY"
When attempting to locate a gem to satisfy a gem requirement, bundler uses the following priority order:
.IP "1." 4
@@ -469,4 +513,35 @@ For implicit gems (dependencies of explicit gems), any source, git, or path repo
.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
+.SH "LOCKFILE"
+By default, Bundler will create a lockfile by adding \fB\.lock\fR to the end of the Gemfile name\. To change this, use the \fBlockfile\fR method:
+.IP "" 4
+.nf
+lockfile "/path/to/lockfile\.lock"
+.fi
+.IP "" 0
+.P
+This is useful when you want to use different lockfiles per ruby version or platform\.
+.P
+To avoid writing a lock file, use \fBfalse\fR as the argument:
+.IP "" 4
+.nf
+lockfile false
+.fi
+.IP "" 0
+.P
+This is useful for library development and other situations where the code is expected to work with a range of dependency versions\.
+.SS "LOCKFILE PRECEDENCE"
+When determining path to the lockfile or whether to create a lockfile, the following precedence is used:
+.IP "1." 4
+The \fBbundle install\fR \fB\-\-no\-lock\fR option (which disables lockfile creation)\.
+.IP "2." 4
+The \fBbundle install\fR \fB\-\-lockfile\fR option\.
+.IP "3." 4
+The \fBBUNDLE_LOCKFILE\fR environment variable\.
+.IP "4." 4
+The \fBlockfile\fR method in the Gemfile\.
+.IP "5." 4
+The default behavior of adding \fB\.lock\fR to the end of the Gemfile name\.
+.IP "" 0
diff --git a/lib/bundler/man/gemfile.5.ronn b/lib/bundler/man/gemfile.5.ronn
index 802549737e..69fef90654 100644
--- a/lib/bundler/man/gemfile.5.ronn
+++ b/lib/bundler/man/gemfile.5.ronn
@@ -541,6 +541,59 @@ When a `gemspec` 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 `gemspec` gem.
+## OVERRIDE
+
+The `override` directive rewrites a constraint on another gem before
+resolution runs. It targets the common case where an upstream gem's
+published metadata is too narrow on the current project's machine -- a stale
+upper bound, an unwanted floor, or a transitive pin that has to be lifted.
+
+ override <target>, <field>: <operation>
+
+`<target>` is a gem name string or `:all`. `<field>` is one of `version:`,
+`required_ruby_version:`, or `required_rubygems_version:`. `<operation>` is
+one of:
+
+ * a version requirement string (e.g. `">= 8.0"`), which **replaces** the
+ target's requirement absolutely. The original requirement, both direct
+ and transitive, is discarded in favour of the override.
+ * `:ignore_upper`, which removes upper-bound operators (`<` and `<=`) from
+ the existing requirement and folds `~>` into its lower bound (`~> 1.5`
+ becomes `>= 1.5`). Other operators, including `!=`, are preserved.
+ * `nil`, which collapses the requirement to `>= 0` (no constraint at all).
+
+`:all` only applies to `required_ruby_version:` and `required_rubygems_version:`.
+A per-gem override on the same field takes precedence over an `:all` override.
+`:all + version:` is rejected: version requirements only make sense per gem.
+
+Multiple `override` calls for distinct targets are allowed; declaring the
+same `target` and `field` twice is an error.
+
+ source "https://rubygems.org"
+
+ # Force every reference to "rails" -- direct or transitive -- to >= 8.0.
+ override "rails", version: ">= 8.0"
+
+ # Strip the upper bound on nokogiri.
+ override "nokogiri", version: :ignore_upper
+
+ # Drop the version pin on legacy entirely.
+ override "legacy", version: nil
+
+ # Loosen every gem's required_ruby_version upper bound.
+ override :all, required_ruby_version: :ignore_upper
+
+ # Override one specific gem's required_rubygems_version.
+ override "tricky", required_rubygems_version: nil
+
+ gem "rails", "~> 7.0"
+
+The override only affects resolution and the install-time Ruby/RubyGems
+compatibility checks; `Gemfile.lock` continues to reflect the resolved
+versions, not the rewritten requirements. When resolution still fails,
+Bundler appends the active overrides (with their Gemfile location) to the
+error message so it is clear which override shaped the constraint set.
+
## SOURCE PRIORITY
When attempting to locate a gem to satisfy a gem requirement,
@@ -556,3 +609,31 @@ bundler uses the following priority order:
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.
+
+## LOCKFILE
+
+By default, Bundler will create a lockfile by adding `.lock` to the end of the
+Gemfile name. To change this, use the `lockfile` method:
+
+ lockfile "/path/to/lockfile.lock"
+
+This is useful when you want to use different lockfiles per ruby version or
+platform.
+
+To avoid writing a lock file, use `false` as the argument:
+
+ lockfile false
+
+This is useful for library development and other situations where the code is
+expected to work with a range of dependency versions.
+
+### LOCKFILE PRECEDENCE
+
+When determining path to the lockfile or whether to create a lockfile, the
+following precedence is used:
+
+1. The `bundle install` `--no-lock` option (which disables lockfile creation).
+1. The `bundle install` `--lockfile` option.
+1. The `BUNDLE_LOCKFILE` environment variable.
+1. The `lockfile` method in the Gemfile.
+1. The default behavior of adding `.lock` to the end of the Gemfile name.
diff --git a/lib/bundler/man/index.txt b/lib/bundler/man/index.txt
index 3ea3495f1b..f610ba852a 100644
--- a/lib/bundler/man/index.txt
+++ b/lib/bundler/man/index.txt
@@ -15,7 +15,6 @@ bundle-gem(1) bundle-gem.1
bundle-help(1) bundle-help.1
bundle-info(1) bundle-info.1
bundle-init(1) bundle-init.1
-bundle-inject(1) bundle-inject.1
bundle-install(1) bundle-install.1
bundle-issue(1) bundle-issue.1
bundle-licenses(1) bundle-licenses.1
@@ -30,4 +29,3 @@ bundle-remove(1) bundle-remove.1
bundle-show(1) bundle-show.1
bundle-update(1) bundle-update.1
bundle-version(1) bundle-version.1
-bundle-viz(1) bundle-viz.1
diff --git a/lib/bundler/match_metadata.rb b/lib/bundler/match_metadata.rb
index 6fd2994a85..92aeb2e893 100644
--- a/lib/bundler/match_metadata.rb
+++ b/lib/bundler/match_metadata.rb
@@ -14,6 +14,18 @@ module Bundler
@required_rubygems_version.satisfied_by?(Gem.rubygems_version)
end
+ def matches_current_metadata_with_overrides?(overrides)
+ matches_current_ruby_with_overrides?(overrides) && matches_current_rubygems_with_overrides?(overrides)
+ end
+
+ def matches_current_ruby_with_overrides?(overrides)
+ effective_required_version(@required_ruby_version, :required_ruby_version, overrides).satisfied_by?(Gem.ruby_version)
+ end
+
+ def matches_current_rubygems_with_overrides?(overrides)
+ effective_required_version(@required_rubygems_version, :required_rubygems_version, overrides).satisfied_by?(Gem.rubygems_version)
+ end
+
def expanded_dependencies
runtime_dependencies + [
metadata_dependency("Ruby", @required_ruby_version),
@@ -26,5 +38,13 @@ module Bundler
Gem::Dependency.new("#{name}\0", requirement)
end
+
+ private
+
+ def effective_required_version(requirement, field, overrides)
+ return requirement if overrides.nil? || overrides.empty?
+ override = Override.find_for(overrides, name, field)
+ override ? override.apply_to(requirement) : requirement
+ end
end
end
diff --git a/lib/bundler/match_remote_metadata.rb b/lib/bundler/match_remote_metadata.rb
index 5e46d52441..601af7e55d 100644
--- a/lib/bundler/match_remote_metadata.rb
+++ b/lib/bundler/match_remote_metadata.rb
@@ -6,19 +6,34 @@ module Bundler
# API didn't include that field, so some marshalled specs in the index have it
# set to +nil+.
def matches_current_ruby?
- @required_ruby_version ||= _remote_specification.required_ruby_version || Gem::Requirement.default
-
+ ensure_required_ruby_version_loaded
super
end
def matches_current_rubygems?
- # A fallback is included because the original version of the specification
- # API didn't include that field, so some marshalled specs in the index have it
- # set to +nil+.
- @required_rubygems_version ||= _remote_specification.required_rubygems_version || Gem::Requirement.default
+ ensure_required_rubygems_version_loaded
+ super
+ end
+
+ def matches_current_ruby_with_overrides?(overrides)
+ ensure_required_ruby_version_loaded
+ super
+ end
+ def matches_current_rubygems_with_overrides?(overrides)
+ ensure_required_rubygems_version_loaded
super
end
+
+ private
+
+ def ensure_required_ruby_version_loaded
+ @required_ruby_version ||= _remote_specification.required_ruby_version || Gem::Requirement.default # rubocop:disable Naming/MemoizedInstanceVariableName
+ end
+
+ def ensure_required_rubygems_version_loaded
+ @required_rubygems_version ||= _remote_specification.required_rubygems_version || Gem::Requirement.default # rubocop:disable Naming/MemoizedInstanceVariableName
+ end
end
module MatchRemoteMetadata
diff --git a/lib/bundler/materialization.rb b/lib/bundler/materialization.rb
index 43124f25fb..82e48464a7 100644
--- a/lib/bundler/materialization.rb
+++ b/lib/bundler/materialization.rb
@@ -29,7 +29,7 @@ module Bundler
end
def dependencies
- specs.first.runtime_dependencies.map {|d| [d, platform] }
+ (materialized_spec || specs.first).runtime_dependencies.map {|d| [d, platform] }
end
def materialized_spec
diff --git a/lib/bundler/override.rb b/lib/bundler/override.rb
new file mode 100644
index 0000000000..0e0ec59fd7
--- /dev/null
+++ b/lib/bundler/override.rb
@@ -0,0 +1,69 @@
+# frozen_string_literal: true
+
+module Bundler
+ class Override
+ UPPER_BOUND_OPERATORS = ["<", "<="].freeze
+
+ def self.find_for(overrides, name, field)
+ overrides.find {|o| o.target == name && o.field == field } ||
+ overrides.find {|o| o.target == :all && o.field == field }
+ end
+
+ # Attach the given overrides onto every LazySpecification in `specs` so
+ # downstream consumers (LazySpecification#choose_compatible, the install-
+ # time compatibility check, etc.) can read the override list off the spec
+ # itself. Non-LazySpec entries (StubSpecification, Gem::Specification, ...)
+ # are left untouched.
+ def self.attach(specs, overrides)
+ return if overrides.nil? || overrides.empty?
+ specs.each {|s| s.overrides = overrides if s.is_a?(LazySpecification) }
+ end
+
+ attr_reader :target, :field, :operation, :source_location
+
+ def initialize(target, field, operation, source_location: nil)
+ @target = target
+ @field = field
+ @operation = operation
+ @source_location = source_location
+ end
+
+ def source_location_label
+ return nil unless @source_location
+ "#{File.basename(@source_location.path)}:#{@source_location.lineno}"
+ end
+
+ def apply_to(requirement)
+ case operation
+ when nil
+ Gem::Requirement.default
+ when :ignore_upper
+ remove_upper_bounds(requirement)
+ when String
+ Gem::Requirement.new(operation)
+ else
+ raise ArgumentError, "unsupported override operation: #{operation.inspect}"
+ end
+ end
+
+ private
+
+ def remove_upper_bounds(requirement)
+ return Gem::Requirement.default if requirement.nil? || requirement.none?
+
+ preserved = requirement.requirements.filter_map do |op, version|
+ if UPPER_BOUND_OPERATORS.include?(op)
+ nil
+ elsif op == "~>"
+ [">=", version]
+ else
+ [op, version]
+ end
+ end
+
+ return Gem::Requirement.default if preserved.empty?
+
+ Gem::Requirement.new(preserved.map {|op, v| "#{op} #{v}" })
+ end
+ end
+end
diff --git a/lib/bundler/plugin.rb b/lib/bundler/plugin.rb
index 44129cc0ff..faca6bea53 100644
--- a/lib/bundler/plugin.rb
+++ b/lib/bundler/plugin.rb
@@ -113,7 +113,7 @@ module Bundler
return if definition.dependencies.empty?
- plugins = definition.dependencies.map(&:name).reject {|p| index.installed? p }
+ plugins = definition.dependencies.map(&:name)
installed_specs = Installer.new.install_definition(definition)
save_plugins plugins, installed_specs, builder.inferred_plugins
@@ -220,7 +220,7 @@ module Bundler
#
# @param [String] event
def hook(event, *args, &arg_blk)
- return unless Bundler.feature_flag.plugins?
+ return unless Bundler.settings[:plugins]
unless Events.defined_event?(event)
raise ArgumentError, "Event '#{event}' not defined in Bundler::Plugin::Events"
end
@@ -253,10 +253,13 @@ module Bundler
# @param [Array<String>] names of inferred source plugins that can be ignored
def save_plugins(plugins, specs, optional_plugins = [])
plugins.each do |name|
- next if index.installed?(name)
-
spec = specs[name]
+ # It's possible that the `plugin` found in the Gemfile don't appear in the specs. For instance when
+ # calling `BUNDLE_WITHOUT=default bundle install`, the plugins will not get installed.
+ next if spec.nil?
+ next if index.up_to_date?(spec)
+
save_plugin(name, spec, optional_plugins.include?(name))
end
end
diff --git a/lib/bundler/plugin/api/source.rb b/lib/bundler/plugin/api/source.rb
index 6c888d0373..798326673a 100644
--- a/lib/bundler/plugin/api/source.rb
+++ b/lib/bundler/plugin/api/source.rb
@@ -74,6 +74,14 @@ module Bundler
{}
end
+ # Download the gem specified by the spec at appropriate path.
+ #
+ # A source plugin can implement this method to split the download and the
+ # installation of a gem.
+ #
+ # @return [Boolean] Whether the download of the gem succeeded.
+ def download(spec, opts); end
+
# Install the gem specified by the spec at appropriate path.
# `install_path` provides a sufficient default, if the source can only
# satisfy one gem, but is not binding.
diff --git a/lib/bundler/plugin/events.rb b/lib/bundler/plugin/events.rb
index 29c05098ae..3fbf60307e 100644
--- a/lib/bundler/plugin/events.rb
+++ b/lib/bundler/plugin/events.rb
@@ -31,6 +31,54 @@ module Bundler
end
# @!parse
+ # A hook called before the Gemfile is evaluated
+ # Includes the Gemfile path and the Lockfile path
+ # GEM_BEFORE_EVAL = "before-eval"
+ define :GEM_BEFORE_EVAL, "before-eval"
+
+ # @!parse
+ # A hook called after the Gemfile is evaluated
+ # Includes a Bundler::Definition
+ # GEM_AFTER_EVAL = "after-eval"
+ define :GEM_AFTER_EVAL, "after-eval"
+
+ # @!parse
+ # A hook called before any gems install
+ # Includes an Array of Bundler::Dependency objects
+ # GEM_BEFORE_INSTALL_ALL = "before-install-all"
+ define :GEM_BEFORE_INSTALL_ALL, "before-install-all"
+
+ # @!parse
+ # A hook called before each individual gem is downloaded from a remote source.
+ # Includes a spec-like object responding to the Gem::Specification API
+ # (for example, a Bundler spec proxy such as Bundler::EndpointSpecification
+ # or Bundler::RemoteSpecification). Does not fire when the gem is already
+ # present at the initial download-cache check.
+ # GEM_BEFORE_FETCH = "before-fetch"
+ define :GEM_BEFORE_FETCH, "before-fetch"
+
+ # @!parse
+ # A hook called after each individual gem is downloaded from a remote source.
+ # Includes a spec-like object responding to the Gem::Specification API
+ # (for example, a Bundler spec proxy such as Bundler::EndpointSpecification
+ # or Bundler::RemoteSpecification). Does not fire when the gem is already
+ # present at the initial download-cache check.
+ # GEM_AFTER_FETCH = "after-fetch"
+ define :GEM_AFTER_FETCH, "after-fetch"
+
+ # @!parse
+ # A hook called before a git source is fetched or checked out.
+ # Includes a Bundler::Source::Git reference.
+ # GIT_BEFORE_FETCH = "before-git-fetch"
+ define :GIT_BEFORE_FETCH, "before-git-fetch"
+
+ # @!parse
+ # A hook called after a git source is fetched or checked out.
+ # Includes a Bundler::Source::Git reference.
+ # GIT_AFTER_FETCH = "after-git-fetch"
+ define :GIT_AFTER_FETCH, "after-git-fetch"
+
+ # @!parse
# A hook called before each individual gem is installed
# Includes a Bundler::ParallelInstaller::SpecInstallation.
# No state, error, post_install_message will be present as nothing has installed yet
@@ -46,18 +94,18 @@ module Bundler
define :GEM_AFTER_INSTALL, "after-install"
# @!parse
- # A hook called before any gems install
- # Includes an Array of Bundler::Dependency objects
- # GEM_BEFORE_INSTALL_ALL = "before-install-all"
- define :GEM_BEFORE_INSTALL_ALL, "before-install-all"
-
- # @!parse
# A hook called after any gems install
# 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 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 before each individual gem is required
# Includes a Bundler::Dependency.
# GEM_BEFORE_REQUIRE = "before-require"
@@ -70,16 +118,10 @@ module Bundler
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"
+ 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 0682d37772..1dfb061304 100644
--- a/lib/bundler/plugin/index.rb
+++ b/lib/bundler/plugin/index.rb
@@ -119,6 +119,12 @@ module Bundler
@plugin_paths[name]
end
+ def up_to_date?(spec)
+ path = installed?(spec.name)
+
+ path == spec.full_gem_path
+ end
+
def installed_plugins
@plugin_paths.keys
end
@@ -157,6 +163,8 @@ module Bundler
# @param [Pathname] index file path
# @param [Boolean] is the index file global index
def load_index(index_file, global = false)
+ base = base_for_index(global)
+
SharedHelpers.filesystem_access(index_file, :read) do |index_f|
valid_file = index_f&.exist? && !index_f.size.zero?
break unless valid_file
@@ -168,8 +176,8 @@ module Bundler
@commands.merge!(index["commands"])
@hooks.merge!(index["hooks"])
- @load_paths.merge!(index["load_paths"])
- @plugin_paths.merge!(index["plugin_paths"])
+ @load_paths.merge!(transform_index_paths(index["load_paths"]) {|p| absolutize_path(p, base) })
+ @plugin_paths.merge!(transform_index_paths(index["plugin_paths"]) {|p| absolutize_path(p, base) })
@sources.merge!(index["sources"]) unless global
end
end
@@ -178,11 +186,13 @@ module Bundler
# instance variables in YAML format. (The instance variables are supposed
# to be only String key value pairs)
def save_index
+ base = base_for_index(false)
+
index = {
"commands" => @commands,
"hooks" => @hooks,
- "load_paths" => @load_paths,
- "plugin_paths" => @plugin_paths,
+ "load_paths" => transform_index_paths(@load_paths) {|p| relativize_path(p, base) },
+ "plugin_paths" => transform_index_paths(@plugin_paths) {|p| relativize_path(p, base) },
"sources" => @sources,
}
@@ -192,6 +202,40 @@ module Bundler
File.open(index_f, "w") {|f| f.puts YAMLSerializer.dump(index) }
end
end
+
+ def base_for_index(global)
+ global ? Plugin.global_root : Plugin.root
+ end
+
+ def transform_index_paths(paths)
+ return {} unless paths
+
+ paths.transform_values do |value|
+ if value.is_a?(Array)
+ value.map {|path| yield path }
+ else
+ yield value
+ end
+ end
+ end
+
+ def relativize_path(path, base)
+ pathname = Pathname.new(path)
+ return path unless pathname.absolute?
+
+ base_path = Pathname.new(base)
+ if pathname == base_path || pathname.to_s.start_with?(base_path.to_s + File::SEPARATOR)
+ pathname.relative_path_from(base_path).to_s
+ else
+ path
+ end
+ end
+
+ def absolutize_path(path, base)
+ pathname = Pathname.new(path)
+ pathname = Pathname.new(base).join(pathname) unless pathname.absolute?
+ pathname.to_s
+ end
end
end
end
diff --git a/lib/bundler/plugin/installer.rb b/lib/bundler/plugin/installer.rb
index ac3c3ea7f3..9be8b36843 100644
--- a/lib/bundler/plugin/installer.rb
+++ b/lib/bundler/plugin/installer.rb
@@ -43,16 +43,6 @@ module Bundler
private
def check_sources_consistency!(options)
- 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
@@ -120,7 +110,8 @@ module Bundler
paths = {}
specs.each do |spec|
- spec.source.install spec
+ spec.source.download(spec)
+ spec.source.install(spec)
paths[spec.name] = spec
end
diff --git a/lib/bundler/plugin/source_list.rb b/lib/bundler/plugin/source_list.rb
index 746996de55..d929ade29e 100644
--- a/lib/bundler/plugin/source_list.rb
+++ b/lib/bundler/plugin/source_list.rb
@@ -23,7 +23,7 @@ module Bundler
private
- def rubygems_aggregate_class
+ def source_class
Plugin::Installer::Rubygems
end
end
diff --git a/lib/bundler/remote_specification.rb b/lib/bundler/remote_specification.rb
index ab163e2b04..dcaaf6af2e 100644
--- a/lib/bundler/remote_specification.rb
+++ b/lib/bundler/remote_specification.rb
@@ -12,7 +12,7 @@ module Bundler
attr_reader :name, :version, :platform
attr_writer :dependencies
- attr_accessor :source, :remote, :locked_platform
+ attr_accessor :source, :remote, :locked_platform, :created_at
def initialize(name, version, platform, spec_fetcher)
@name = name
diff --git a/lib/bundler/resolver.rb b/lib/bundler/resolver.rb
index 1dbf565d46..753e9987d5 100644
--- a/lib/bundler/resolver.rb
+++ b/lib/bundler/resolver.rb
@@ -64,7 +64,9 @@ module Bundler
@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)
+ deps = version.dependencies.reject {|d| d.name == package.name }
+ deps = apply_metadata_overrides(deps, package.name)
+ versions[version] = to_dependency_hash(deps, @packages)
end
end
@@ -80,6 +82,7 @@ module Bundler
solver = PubGrub::VersionSolver.new(source: self, root: root, strategy: Strategy.new(self), logger: logger)
result = solver.solve
resolved_specs = result.flat_map {|package, version| version.to_specs(package, @most_specific_locked_platform) }
+ Override.attach(resolved_specs, @base.overrides)
SpecSet.new(resolved_specs).specs_with_additional_variants_from(@base.locked_specs)
rescue PubGrub::SolveFailure => e
incompatibility = e.incompatibility
@@ -120,9 +123,25 @@ module Bundler
explanation << extended_explanation
end
+ override_summary = override_diagnostic_summary
+ explanation << override_summary if override_summary
+
raise SolveFailure.new(explanation)
end
+ def override_diagnostic_summary
+ return nil if @base.overrides.empty?
+
+ lines = ["Bundler applied the following overrides while resolving:"]
+ @base.overrides.each do |override|
+ target = override.target == :all ? ":all" : override.target.inspect
+ location = override.source_location_label
+ lines << " override #{target}, #{override.field}: #{override.operation.inspect}" \
+ "#{location ? " (declared at #{location})" : ""}"
+ end
+ "\n\n#{lines.join("\n")}"
+ end
+
def find_names_to_relax(incompatibility)
names_to_unlock = []
names_to_allow_prereleases_for = []
@@ -184,6 +203,9 @@ module Bundler
platforms_explanation = specs_matching_other_platforms.any? ? " for any resolution platforms (#{package.platforms.join(", ")})" : ""
custom_explanation = "#{constraint} could not be found in #{repository_for(package)}#{platforms_explanation}"
+ if hint = cooldown_hint(specs_matching_other_platforms)
+ custom_explanation += " (#{hint})"
+ end
label = "#{name} (#{constraint_string})"
extended_explanation = other_specs_matching_message(specs_matching_other_platforms, label) if specs_matching_other_platforms.any?
@@ -353,9 +375,31 @@ module Bundler
message << "\n#{other_specs_matching_message(specs, matching_part)}"
end
+ if hint = cooldown_hint(specs_matching_requirement)
+ message << "\n\n#{hint}."
+ end
+
+ if specs_matching_requirement.any? && (hint = platform_mismatch_hint)
+ message << "\n\n#{hint}"
+ end
+
raise GemNotFound, message
end
+ def platform_mismatch_hint
+ locked_platforms = Bundler.locked_gems&.platforms
+ return unless locked_platforms
+
+ local_platform = Bundler.local_platform
+ return if locked_platforms.include?(local_platform)
+ return if locked_platforms.any? {|p| p == Gem::Platform::RUBY }
+
+ "Your current platform (#{local_platform}) is not included in the lockfile's platforms (#{locked_platforms.join(", ")}). " \
+ "Add the current platform to the lockfile with\n`bundle lock --add-platform #{local_platform}` and try again."
+ rescue GemfileNotFound
+ nil
+ end
+
def filtered_versions_for(package)
@gem_version_promoter.filter_versions(package, @all_versions[package])
end
@@ -378,7 +422,7 @@ module Bundler
end
def filter_specs(specs, package)
- filter_remote_specs(filter_prereleases(specs, package), package)
+ filter_remote_specs(filter_cooldown(filter_prereleases(specs, package)), package)
end
def filter_prereleases(specs, package)
@@ -387,6 +431,56 @@ module Bundler
specs.reject {|s| s.version.prerelease? }
end
+ def filter_cooldown(specs)
+ return specs if specs.empty?
+ excluded_versions = cooldown_excluded_versions(specs)
+ return specs if excluded_versions.empty?
+ specs.reject {|s| excluded_versions.include?([s.name, s.version]) }
+ end
+
+ def cooldown_excluded_versions(specs)
+ excluded = {}
+ specs.each do |spec|
+ next unless cooldown_excluded?(spec)
+ excluded[[spec.name, spec.version]] = true
+ end
+ excluded
+ end
+
+ def cooldown_hint(specs)
+ excluded_versions = cooldown_excluded_versions(specs)
+ return nil if excluded_versions.empty?
+ "#{excluded_versions.size} version#{"s" if excluded_versions.size > 1} excluded by the cooldown setting; pass `--cooldown 0` to bypass"
+ end
+
+ def cooldown_excluded?(spec)
+ return false unless spec.respond_to?(:created_at) && spec.created_at
+ return false unless spec.respond_to?(:remote) && spec.remote
+ return false if pinned_by_lockfile_floor?(spec)
+ days = spec.remote.effective_cooldown
+ return false if days.nil? || days <= 0
+ (cooldown_now - spec.created_at) < (days * 86_400)
+ end
+
+ # A spec sitting exactly at a `>= locked_version` prevent-downgrade floor is
+ # the version the lockfile currently pins. `bundle update` and `bundle
+ # outdated` install that floor so resolution never moves a gem backwards.
+ # Filtering it out for cooldown would then make resolution impossible
+ # whenever the locked version is itself inside the cooldown window, which is
+ # exactly what happens to a lockfile written before cooldown was enabled.
+ # Keep it eligible; gems being explicitly updated carry an exact `=`
+ # requirement instead and stay subject to the cooldown filter.
+ def pinned_by_lockfile_floor?(spec)
+ return false unless defined?(@base) && @base
+ requirement = base_requirements[spec.name]
+ return false unless requirement && !requirement.exact?
+ requirement.requirements.any? {|op, version| op == ">=" && version == spec.version }
+ end
+
+ def cooldown_now
+ @cooldown_now ||= Time.now
+ end
+
def filter_remote_specs(specs, package)
if package.prefer_local?
local_specs = specs.select {|s| s.is_a?(StubSpecification) }
@@ -492,7 +586,7 @@ module Bundler
end
def to_dependency_hash(dependencies, packages)
- dependencies.inject({}) do |deps, dep|
+ apply_overrides(dependencies).inject({}) do |deps, dep|
package = packages[dep.name]
current_req = deps[package]
@@ -508,6 +602,33 @@ module Bundler
end
end
+ def apply_overrides(dependencies)
+ return dependencies if @base.overrides.empty?
+
+ dependencies.map do |dep|
+ override = Override.find_for(@base.overrides, dep.name, :version)
+ next dep unless override
+ Gem::Dependency.new(dep.name, override.apply_to(dep.requirement))
+ end
+ end
+
+ METADATA_DEP_FIELD = {
+ "Ruby\0" => :required_ruby_version,
+ "RubyGems\0" => :required_rubygems_version,
+ }.freeze
+
+ def apply_metadata_overrides(dependencies, name)
+ return dependencies if @base.overrides.empty?
+
+ dependencies.map do |dep|
+ field = METADATA_DEP_FIELD[dep.name]
+ next dep unless field
+ override = Override.find_for(@base.overrides, name, field)
+ next dep unless override
+ Gem::Dependency.new(dep.name, override.apply_to(dep.requirement))
+ end
+ end
+
def bundler_not_found_message(conflict_dependencies)
candidate_specs = filter_matching_specs(default_bundler_source.specs.search("bundler"), conflict_dependencies)
diff --git a/lib/bundler/resolver/base.rb b/lib/bundler/resolver/base.rb
index 932a92ff41..00bdd08303 100644
--- a/lib/bundler/resolver/base.rb
+++ b/lib/bundler/resolver/base.rb
@@ -5,9 +5,10 @@ require_relative "package"
module Bundler
class Resolver
class Base
- attr_reader :packages, :requirements, :source_requirements, :locked_specs
+ attr_reader :packages, :requirements, :source_requirements, :locked_specs, :overrides
def initialize(source_requirements, dependencies, base, platforms, options)
+ @overrides = options.delete(:overrides) || []
@source_requirements = source_requirements
@locked_specs = options[:locked_specs]
diff --git a/lib/bundler/resolver/strategy.rb b/lib/bundler/resolver/strategy.rb
index 4f343bf0ce..7519d38968 100644
--- a/lib/bundler/resolver/strategy.rb
+++ b/lib/bundler/resolver/strategy.rb
@@ -5,6 +5,7 @@ module Bundler
class Strategy
def initialize(source)
@source = source
+ @package_priority_cache = {}
end
def next_package_and_version(unsatisfied)
@@ -17,10 +18,12 @@ module Bundler
def next_term_to_try_from(unsatisfied)
unsatisfied.min_by do |package, range|
- matching_versions = @source.versions_for(package, range)
- higher_versions = @source.versions_for(package, range.upper_invert)
+ @package_priority_cache[[package, range]] ||= begin
+ matching_versions = @source.versions_for(package, range)
+ higher_versions = @source.versions_for(package, range.upper_invert)
- [matching_versions.count <= 1 ? 0 : 1, higher_versions.count]
+ [matching_versions.count <= 1 ? 0 : 1, higher_versions.count]
+ end
end
end
diff --git a/lib/bundler/retry.rb b/lib/bundler/retry.rb
index 090cb7e2ca..49b0f63838 100644
--- a/lib/bundler/retry.rb
+++ b/lib/bundler/retry.rb
@@ -6,6 +6,8 @@ module Bundler
attr_accessor :name, :total_runs, :current_run
class << self
+ attr_accessor :default_base_delay
+
def default_attempts
default_retries + 1
end
@@ -16,11 +18,17 @@ module Bundler
end
end
- def initialize(name, exceptions = nil, retries = self.class.default_retries)
+ # Set default base delay for exponential backoff
+ self.default_base_delay = 1.0
+
+ def initialize(name, exceptions = nil, retries = self.class.default_retries, opts = {})
@name = name
@retries = retries
@exceptions = Array(exceptions) || []
@total_runs = @retries + 1 # will run once, then upto attempts.times
+ @base_delay = opts[:base_delay] || self.class.default_base_delay
+ @max_delay = opts[:max_delay] || 60.0
+ @jitter = opts[:jitter] || 0.5
end
def attempt(&block)
@@ -48,9 +56,27 @@ module Bundler
Bundler.ui.info "" unless Bundler.ui.debug?
raise e
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
+ if 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
+ end
+ backoff_sleep if @base_delay > 0
+ true
+ end
+
+ def backoff_sleep
+ # Exponential backoff: delay = base_delay * 2^(attempt - 1)
+ # Add jitter to prevent thundering herd: random value between 0 and jitter seconds
+ delay = @base_delay * (2**(@current_run - 1))
+ delay = [@max_delay, delay].min
+ jitter_amount = rand * @jitter
+ total_delay = delay + jitter_amount
+ Bundler.ui.debug "Sleeping for #{total_delay.round(2)} seconds before retry"
+ sleep(total_delay)
+ end
+
+ def sleep(duration)
+ Kernel.sleep(duration)
end
def keep_trying?
diff --git a/lib/bundler/ruby_dsl.rb b/lib/bundler/ruby_dsl.rb
index cd88253f46..5e52f38c8f 100644
--- a/lib/bundler/ruby_dsl.rb
+++ b/lib/bundler/ruby_dsl.rb
@@ -42,21 +42,26 @@ module Bundler
# 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", ruby = "3.2.2" or "ruby 3.2.2" capturing version string up to the first space or comment
- if /^ # Start of line
- ruby # Literal "ruby"
- [\s-]* # Optional whitespace or hyphens (for "ruby-3.2.2" format)
- (?:=\s*)? # Optional equals sign with whitespace (for ruby = "3.2.2" format)
- "? # Optional opening quote
- ( # Start capturing group
- [^\s#"]+ # One or more chars that aren't spaces, #, or quotes
- ) # End capturing group
- "? # Optional closing quote
- /x.match(file_content)
- $1
+ # match "ruby-3.2.2", ruby = "3.2.2", ruby = '3.2.2' or "ruby 3.2.2" capturing version string up to the first space or comment
+ version_match = /^ # Start of line
+ ruby # Literal "ruby"
+ [\s-]* # Optional whitespace or hyphens (for "ruby-3.2.2" format)
+ (?:=\s*)? # Optional equals sign with whitespace (for ruby = "3.2.2" format)
+ (?:
+ "([^"]+)" # Double quoted version
+ |
+ '([^']+)' # Single quoted version
+ |
+ ([^\s#"']+) # Unquoted version
+ )
+ /x.match(file_content)
+ if version_match
+ version_match[1] || version_match[2] || version_match[3]
else
file_content.strip
end
+ rescue Errno::ENOENT
+ raise GemfileError, "Could not find version file #{filename}"
end
end
end
diff --git a/lib/bundler/ruby_version.rb b/lib/bundler/ruby_version.rb
index 0ed5cbc6ca..aeff07582e 100644
--- a/lib/bundler/ruby_version.rb
+++ b/lib/bundler/ruby_version.rb
@@ -43,7 +43,6 @@ module Bundler
def to_s(versions = self.versions)
output = String.new("ruby #{versions_string(versions)}")
- output << "p#{patchlevel}" if patchlevel && patchlevel != "-1"
output << " (#{engine} #{versions_string(engine_versions)})" unless engine == "ruby"
output
@@ -72,8 +71,7 @@ module Bundler
def ==(other)
versions == other.versions &&
engine == other.engine &&
- engine_versions == other.engine_versions &&
- patchlevel == other.patchlevel
+ engine_versions == other.engine_versions
end
def host
@@ -98,8 +96,6 @@ module Bundler
[:version, versions_string(versions), versions_string(other.versions)]
elsif @input_engine && !matches?(engine_versions, other.engine_gem_version)
[:engine_version, versions_string(engine_versions), versions_string(other.engine_versions)]
- elsif patchlevel && (!patchlevel.is_a?(String) || !other.patchlevel.is_a?(String) || !matches?(patchlevel, other.patchlevel))
- [:patchlevel, patchlevel, other.patchlevel]
end
end
diff --git a/lib/bundler/rubygems_ext.rb b/lib/bundler/rubygems_ext.rb
index fedf44b0e6..4ad2bdf46f 100644
--- a/lib/bundler/rubygems_ext.rb
+++ b/lib/bundler/rubygems_ext.rb
@@ -465,6 +465,28 @@ module Gem
Resolver::APISet::GemParser.prepend(UnfreezeCompactIndexParsedResponse)
end
+ # RubyGems before 4.0.13 split compact index dependency/requirement entries
+ # on every colon, which mangles metadata values that contain colons such as
+ # the `created_at` timestamps the cooldown feature relies on. Split only on
+ # the first colon so those values survive on older RubyGems.
+ #
+ # The module is defined unconditionally so it stays testable on any RubyGems,
+ # but only prepended when the host RubyGems still has the buggy behavior.
+ module SplitCompactIndexEntryOnFirstColon
+ private
+
+ def parse_dependency(string)
+ dependency = string.split(":", 2)
+ dependency[-1] = dependency[-1].split("&") if dependency.size > 1
+ dependency[0] = -dependency[0]
+ dependency
+ end
+ end
+
+ unless Gem.rubygems_version >= Gem::Version.new("4.0.13")
+ Resolver::APISet::GemParser.prepend(SplitCompactIndexEntryOnFirstColon)
+ end
+
if Gem.rubygems_version < Gem::Version.new("3.6.0")
class Package; end
require "rubygems/package/tar_reader"
diff --git a/lib/bundler/rubygems_gem_installer.rb b/lib/bundler/rubygems_gem_installer.rb
index 1af1b85ff0..fc019f54d2 100644
--- a/lib/bundler/rubygems_gem_installer.rb
+++ b/lib/bundler/rubygems_gem_installer.rb
@@ -20,14 +20,18 @@ 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
end
SharedHelpers.filesystem_access(gem_dir, :write) do
extract_files
end
- build_extensions if spec.extensions.any?
+ if options[:build_extension] == false
+ warn_skipped_extensions
+ elsif spec.extensions.any?
+ build_extensions
+ end
write_build_info_file
run_post_build_hooks
@@ -35,7 +39,12 @@ module Bundler
generate_bin
end
- generate_plugins
+ if options[:install_plugin] == false
+ remove_stale_plugins
+ warn_skipped_plugins
+ else
+ generate_plugins
+ end
write_spec
@@ -69,10 +78,7 @@ module Bundler
end
def generate_plugins
- return unless Gem::Installer.instance_methods(false).include?(:generate_plugins)
-
- latest = Gem::Specification.stubs_for(spec.name).first
- return if latest && latest.version > spec.version
+ return unless Gem::Installer.method_defined?(:generate_plugins, false)
ensure_writable_dir @plugins_dir
@@ -83,6 +89,20 @@ module Bundler
end
end
+ def warn_skipped_extensions
+ return if spec.extensions.empty?
+
+ Bundler.ui.warn "#{spec.full_name} contains native extensions that were not built.\n" \
+ "To build extensions, unset no_build_extension and run `bundle pristine #{spec.name}`."
+ end
+
+ def warn_skipped_plugins
+ return if spec.plugins.empty?
+
+ Bundler.ui.warn "#{spec.full_name} contains plugins that were not installed.\n" \
+ "To install plugins, unset no_install_plugin and run `bundle pristine #{spec.name}`."
+ end
+
if Bundler.rubygems.provides?("< 3.5.19")
def generate_bin_script(filename, bindir)
bin_script_path = File.join bindir, formatted_program_filename(filename)
@@ -103,6 +123,10 @@ module Bundler
end
end
+ def build_jobs
+ Bundler.settings[:jobs] || super
+ end
+
def build_extensions
extension_cache_path = options[:bundler_extension_cache_path]
extension_dir = spec.extension_dir
diff --git a/lib/bundler/rubygems_integration.rb b/lib/bundler/rubygems_integration.rb
index 31f255d997..e04ef23259 100644
--- a/lib/bundler/rubygems_integration.rb
+++ b/lib/bundler/rubygems_integration.rb
@@ -416,11 +416,7 @@ 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
+ SharedHelpers.feature_removed! "Bundler.rubygems.all_specs has been removed in favor of Bundler.rubygems.installed_specs"
end
def installed_specs
@@ -436,7 +432,7 @@ module Bundler
end
def find_bundler(version)
- find_name("bundler").find {|s| s.version.to_s == version }
+ find_name("bundler").find {|s| s.version.to_s == version.to_s }
end
def find_name(name)
diff --git a/lib/bundler/runtime.rb b/lib/bundler/runtime.rb
index 9b2416402b..5280e72aa2 100644
--- a/lib/bundler/runtime.rb
+++ b/lib/bundler/runtime.rb
@@ -174,7 +174,14 @@ module Bundler
spec_cache_paths = []
spec_gemspec_paths = []
spec_extension_paths = []
- Bundler.rubygems.add_default_gems_to(specs).values.each do |spec|
+ specs_to_keep = Bundler.rubygems.add_default_gems_to(specs).values
+
+ current_bundler = Bundler.rubygems.find_bundler(Bundler.gem_version)
+ if current_bundler
+ specs_to_keep << current_bundler
+ end
+
+ specs_to_keep.each do |spec|
spec_gem_paths << spec.full_gem_path
# need to check here in case gems are nested like for the rails git repo
md = %r{(.+bundler/gems/.+-[a-f0-9]{7,12})}.match(spec.full_gem_path)
@@ -240,7 +247,11 @@ module Bundler
cached.each do |path|
Bundler.ui.info " * #{File.basename(path)}"
- File.delete(path)
+
+ begin
+ File.delete(path)
+ rescue Errno::ENOENT
+ end
end
end
end
diff --git a/lib/bundler/self_manager.rb b/lib/bundler/self_manager.rb
index 7db6c9f6f1..82efbf56a4 100644
--- a/lib/bundler/self_manager.rb
+++ b/lib/bundler/self_manager.rb
@@ -63,6 +63,7 @@ module Bundler
end
def install(spec)
+ spec.source.download(spec)
spec.source.install(spec)
end
@@ -97,7 +98,7 @@ module Bundler
end
def autoswitching_applies?
- ENV["BUNDLER_VERSION"].nil? &&
+ (ENV["BUNDLER_VERSION"].nil? || ENV["BUNDLER_VERSION"].empty?) &&
ruby_can_restart_with_same_arguments? &&
lockfile_version
end
diff --git a/lib/bundler/settings.rb b/lib/bundler/settings.rb
index cc20598fd9..fd77c2f7fc 100644
--- a/lib/bundler/settings.rb
+++ b/lib/bundler/settings.rb
@@ -7,7 +7,6 @@ module Bundler
autoload :Validator, File.expand_path("settings/validator", __dir__)
BOOL_KEYS = %w[
- allow_offline_install
auto_install
cache_all
cache_all_platforms
@@ -20,7 +19,6 @@ module Bundler
disable_shared_gems
disable_version_check
force_ruby_platform
- forget_cli_options
frozen
gem.changelog
gem.coc
@@ -32,7 +30,9 @@ module Bundler
init_gems_rb
inline
lockfile_checksums
+ no_build_extension
no_install
+ no_install_plugin
no_prune
path.system
plugins
@@ -43,21 +43,8 @@ module Bundler
verbose
].freeze
- REMEMBERED_KEYS = %w[
- bin
- cache_all
- clean
- deployment
- frozen
- no_prune
- path
- shebang
- path.system
- without
- with
- ].freeze
-
NUMBER_KEYS = %w[
+ cooldown
jobs
redirect
retry
@@ -75,12 +62,14 @@ module Bundler
bin
cache_path
console
+ default_cli_command
gem.ci
gem.github_username
gem.linter
gem.rubocop
gem.test
gemfile
+ lockfile
path
shebang
simulate_version
@@ -97,6 +86,11 @@ module Bundler
"BUNDLE_RETRY" => 3,
"BUNDLE_TIMEOUT" => 10,
"BUNDLE_VERSION" => "lockfile",
+ "BUNDLE_LOCKFILE_CHECKSUMS" => true,
+ "BUNDLE_CACHE_ALL" => true,
+ "BUNDLE_PLUGINS" => true,
+ "BUNDLE_GLOBAL_GEM_CACHE" => false,
+ "BUNDLE_UPDATE_REQUIRES_ALL_FLAG" => false,
}.freeze
def initialize(root = nil)
@@ -128,12 +122,8 @@ module Bundler
end
def set_command_option(key, value)
- if !is_remembered(key) || Bundler.feature_flag.forget_cli_options?
- temporary(key => value)
- value
- else
- set_local(key, value)
- end
+ temporary(key => value)
+ value
end
def set_command_option_if_given(key, value)
@@ -317,6 +307,10 @@ module Bundler
@app_cache_path ||= self[:cache_path] || "vendor/cache"
end
+ def installation_parallelization
+ self[:jobs] || processor_count
+ end
+
def validate!
all.each do |raw_key|
[@local_config, @env_config, @global_config].each do |settings|
@@ -387,10 +381,6 @@ module Bundler
ARRAY_KEYS.include?(self.class.key_to_s(key))
end
- def is_remembered(key)
- REMEMBERED_KEYS.include?(self.class.key_to_s(key))
- end
-
def is_credential(key)
key == "gem.push_key"
end
@@ -494,7 +484,7 @@ 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)|
+ (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!(".", "__")
diff --git a/lib/bundler/settings/validator.rb b/lib/bundler/settings/validator.rb
index 9aa1627fb2..70a0ca36d4 100644
--- a/lib/bundler/settings/validator.rb
+++ b/lib/bundler/settings/validator.rb
@@ -74,6 +74,13 @@ module Bundler
fail!(key, value, "`#{other_key}` is current set to #{other_setting.inspect}", "the `#{conflicting.join("`, `")}` groups conflict")
end
end
+
+ rule %w[default_cli_command], "default_cli_command must be either 'install' or 'cli_help'" do |key, value, _settings|
+ valid_values = %w[install cli_help]
+ if !value.nil? && !valid_values.include?(value.to_s)
+ fail!(key, value, "must be one of: #{valid_values.join(", ")}")
+ end
+ end
end
end
end
diff --git a/lib/bundler/shared_helpers.rb b/lib/bundler/shared_helpers.rb
index 2bdaabdaa7..2aa8abe0a0 100644
--- a/lib/bundler/shared_helpers.rb
+++ b/lib/bundler/shared_helpers.rb
@@ -4,8 +4,6 @@ require_relative "version"
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__)
@@ -25,6 +23,9 @@ module Bundler
end
def default_lockfile
+ given = ENV["BUNDLE_LOCKFILE"]
+ return Pathname.new(given) if given && !given.empty?
+
gemfile = default_gemfile
case gemfile.basename.to_s
@@ -57,7 +58,7 @@ module Bundler
def pwd
Bundler.rubygems.ext_lock.synchronize do
- Pathname.pwd
+ Dir.pwd
end
end
@@ -104,7 +105,8 @@ module Bundler
def filesystem_access(path, action = :write, &block)
yield(path.dup)
rescue Errno::EACCES => e
- raise unless e.message.include?(path.to_s) || action == :create
+ path_basename = File.basename(path.to_s)
+ raise unless e.message.include?(path_basename) || action == :create
raise PermissionError.new(path, action)
rescue Errno::EAGAIN
@@ -125,27 +127,17 @@ module Bundler
raise GenericSystemCallError.new(e, "There was an error #{[:create, :write].include?(action) ? "creating" : "accessing"} `#{path}`.")
end
- def major_deprecation(major_version, message, removed_message: nil, 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
- end
-
- require_relative "../bundler"
-
- feature_flag = Bundler.feature_flag
+ def feature_deprecated!(message)
+ return unless prints_major_deprecations?
- if feature_flag.removed_major?(major_version)
- require_relative "errors"
- raise DeprecatedError, "[REMOVED] #{removed_message || message}"
- end
-
- return unless feature_flag.deprecated_major?(major_version) && prints_major_deprecations?
Bundler.ui.warn("[DEPRECATED] #{message}")
end
+ def feature_removed!(message)
+ require_relative "errors"
+ raise RemovedError, "[REMOVED] #{message}"
+ end
+
def print_major_deprecations!
multiple_gemfiles = search_up(".") do |dir|
gemfiles = gemfile_names.select {|gf| File.file? File.expand_path(gf, dir) }
@@ -309,6 +301,7 @@ module Bundler
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 "BUNDLE_LOCKFILE", default_lockfile.to_s
Bundler::SharedHelpers.set_env "BUNDLER_VERSION", Bundler::VERSION
Bundler::SharedHelpers.set_env "BUNDLER_SETUP", File.expand_path("setup", __dir__)
end
diff --git a/lib/bundler/similarity_detector.rb b/lib/bundler/similarity_detector.rb
deleted file mode 100644
index 50e66b9cab..0000000000
--- a/lib/bundler/similarity_detector.rb
+++ /dev/null
@@ -1,63 +0,0 @@
-# frozen_string_literal: true
-
-module Bundler
- class SimilarityDetector
- SimilarityScore = Struct.new(:string, :distance)
-
- # initialize with an array of words to be matched against
- def initialize(corpus)
- @corpus = corpus
- end
-
- # return an array of words similar to 'word' from the corpus
- def similar_words(word, limit = 3)
- words_by_similarity = @corpus.map {|w| SimilarityScore.new(w, levenshtein_distance(word, w)) }
- words_by_similarity.select {|s| s.distance <= limit }.sort_by(&:distance).map(&:string)
- end
-
- # return the result of 'similar_words', concatenated into a list
- # (eg "a, b, or c")
- def similar_word_list(word, limit = 3)
- words = similar_words(word, limit)
- if words.length == 1
- words[0]
- elsif words.length > 1
- [words[0..-2].join(", "), words[-1]].join(" or ")
- end
- end
-
- protected
-
- # https://www.informit.com/articles/article.aspx?p=683059&seqNum=36
- def levenshtein_distance(this, that, ins = 2, del = 2, sub = 1)
- # ins, del, sub are weighted costs
- return nil if this.nil?
- return nil if that.nil?
- dm = [] # distance matrix
-
- # Initialize first row values
- dm[0] = (0..this.length).collect {|i| i * ins }
- fill = [0] * (this.length - 1)
-
- # Initialize first column values
- (1..that.length).each do |i|
- dm[i] = [i * del, fill.flatten]
- end
-
- # populate matrix
- (1..that.length).each do |i|
- (1..this.length).each do |j|
- # critical comparison
- dm[i][j] = [
- dm[i - 1][j - 1] + (this[j - 1] == that[i - 1] ? 0 : sub),
- dm[i][j - 1] + ins,
- dm[i - 1][j] + del,
- ].min
- end
- end
-
- # The last value in matrix is the Levenshtein distance between the strings
- dm[that.length][this.length]
- end
- end
-end
diff --git a/lib/bundler/source.rb b/lib/bundler/source.rb
index 232873503b..cf71be8801 100644
--- a/lib/bundler/source.rb
+++ b/lib/bundler/source.rb
@@ -31,6 +31,8 @@ module Bundler
message
end
+ def download(*); end
+
def can_lock?(spec)
spec.source == self
end
@@ -79,7 +81,7 @@ module Bundler
end
def extension_cache_path(spec)
- return unless Bundler.feature_flag.global_gem_cache?
+ return unless Bundler.settings[:global_gem_cache]
return unless source_slug = extension_cache_slug(spec)
Bundler.user_cache.join(
"extensions", Gem::Platform.local.to_s, Bundler.ruby_scope,
diff --git a/lib/bundler/source/gemspec.rb b/lib/bundler/source/gemspec.rb
index b59dce1d09..ed766dbe74 100644
--- a/lib/bundler/source/gemspec.rb
+++ b/lib/bundler/source/gemspec.rb
@@ -10,6 +10,10 @@ module Bundler
super
@gemspec = options["gemspec"]
end
+
+ def to_s
+ "gemspec at `#{@path}`"
+ end
end
end
end
diff --git a/lib/bundler/source/git.rb b/lib/bundler/source/git.rb
index d57944ee12..a002a2570a 100644
--- a/lib/bundler/source/git.rb
+++ b/lib/bundler/source/git.rb
@@ -191,8 +191,13 @@ module Bundler
set_cache_path!(app_cache_path) if use_app_cache?
if requires_checkout? && !@copied
- fetch unless use_app_cache?
- checkout
+ Plugin.hook(Plugin::Events::GIT_BEFORE_FETCH, self)
+ begin
+ fetch unless use_app_cache?
+ checkout
+ ensure
+ Plugin.hook(Plugin::Events::GIT_AFTER_FETCH, self)
+ end
end
local_specs
@@ -238,7 +243,7 @@ module Bundler
# across different projects, this cache will be shared.
# When using local git repos, this is set to the local repo.
def cache_path
- @cache_path ||= if Bundler.feature_flag.global_gem_cache?
+ @cache_path ||= if Bundler.settings[:global_gem_cache]
Bundler.user_cache
else
Bundler.bundle_path.join("cache", "bundler")
@@ -268,7 +273,7 @@ module Bundler
private
def cache_to(custom_path, try_migrate: false)
- return unless Bundler.feature_flag.cache_all?
+ return unless Bundler.settings[:cache_all]
app_cache_path = app_cache_path(custom_path)
@@ -416,7 +421,6 @@ module Bundler
def fetch
git_proxy.checkout
rescue GitError => e
- raise unless Bundler.feature_flag.allow_offline_install?
Bundler.ui.warn "Using cached git data because of network errors:\n#{e}"
end
diff --git a/lib/bundler/source/git/git_proxy.rb b/lib/bundler/source/git/git_proxy.rb
index f613377cb2..8094dcaa9d 100644
--- a/lib/bundler/source/git/git_proxy.rb
+++ b/lib/bundler/source/git/git_proxy.rb
@@ -16,7 +16,7 @@ module Bundler
def initialize(command)
msg = String.new
msg << "Bundler is trying to run `#{command}` at runtime. You probably need to run `bundle install`. However, "
- msg << "this error message could probably be more useful. Please submit a ticket at https://github.com/rubygems/rubygems/issues/new?labels=Bundler&template=bundler-related-issue.md "
+ msg << "this error message could probably be more useful. Please submit a ticket at https://github.com/ruby/rubygems/issues/new?labels=Bundler&template=bundler-related-issue.md "
msg << "with steps to reproduce as well as the following\n\nCALLER: #{caller.join("\n")}"
super msg
end
@@ -57,6 +57,29 @@ module Bundler
attr_accessor :path, :uri, :branch, :tag, :ref, :explicit_ref
attr_writer :revision
+ def self.version
+ @version ||= full_version[/((\.?\d+)+).*/, 1]
+ end
+
+ def self.full_version
+ @full_version ||= begin
+ raise GitNotInstalledError.new unless Bundler.git_present?
+
+ require "open3"
+ out, err, status = Open3.capture3("git", "--version")
+
+ raise GitCommandError.new("--version", SharedHelpers.pwd, err) unless status.success?
+ Bundler.ui.warn err unless err.empty?
+
+ out.sub(/git version\s*/, "").strip
+ end
+ end
+
+ def self.reset
+ @version = nil
+ @full_version = nil
+ end
+
def initialize(path, uri, options = {}, revision = nil, git = nil)
@path = path
@uri = uri
@@ -92,11 +115,11 @@ module Bundler
end
def version
- @version ||= full_version.match(/((\.?\d+)+).*/)[1]
+ self.class.version
end
def full_version
- @full_version ||= git_local("--version").sub(/git version\s*/, "").strip
+ self.class.full_version
end
def checkout
@@ -121,7 +144,7 @@ module Bundler
FileUtils.rm_rf(p)
end
git "clone", "--no-checkout", "--quiet", path.to_s, destination.to_s
- File.chmod(((File.stat(destination).mode | 0o777) & ~File.umask), destination)
+ File.chmod((File.stat(destination).mode | 0o777) & ~File.umask, destination)
rescue Errno::EEXIST => e
file_path = e.message[%r{.*?((?:[a-zA-Z]:)?/.*)}, 1]
raise GitError, "Bundler could not install a gem because it needs to " \
@@ -137,7 +160,7 @@ module Bundler
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
@@ -156,7 +179,7 @@ module Bundler
private
def git_remote_fetch(args)
- command = ["fetch", "--force", "--quiet", "--no-tags", *args, "--", configured_uri, refspec].compact
+ command = fetch_command(args)
command_with_no_credentials = check_allowed(command)
Bundler::Retry.new("`#{command_with_no_credentials}` at #{path}", [MissingGitRevisionError]).attempts do
@@ -166,6 +189,11 @@ module Bundler
if err.include?("couldn't find remote ref") || err.include?("not our ref")
raise MissingGitRevisionError.new(command_with_no_credentials, path, commit || explicit_ref, credential_filtered_uri)
else
+ if shallow?
+ args -= depth_args
+ command = fetch_command(args)
+ command_with_no_credentials = check_allowed(command)
+ end
raise GitCommandError.new(command_with_no_credentials, path, err)
end
end
@@ -178,7 +206,8 @@ module Bundler
FileUtils.mkdir_p(p)
end
- command = ["clone", "--bare", "--no-hardlinks", "--quiet", *extra_clone_args, "--", configured_uri, path.to_s]
+ clone_args = extra_clone_args
+ command = clone_command(clone_args)
command_with_no_credentials = check_allowed(command)
Bundler::Retry.new("`#{command_with_no_credentials}`", [MissingGitRevisionError]).attempts do
@@ -189,13 +218,10 @@ module Bundler
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)
+ if shallow?
+ clone_args -= depth_args
+ command = clone_command(clone_args)
command_with_no_credentials = check_allowed(command)
-
- err += "Retrying without --depth argument."
end
raise GitCommandError.new(command_with_no_credentials, path, err)
end
@@ -204,14 +230,14 @@ module Bundler
def clone_needs_unshallow?
return false unless path.join("shallow").exist?
- return true if full_clone?
+ return true unless shallow?
@revision && @revision != head_revision
end
def extra_ref
return false if not_pinned?
- return true unless full_clone?
+ return true if shallow?
ref.start_with?("refs/")
end
@@ -406,13 +432,14 @@ module Bundler
end
def capture3_args_for(cmd, dir)
- return ["git", *cmd] unless dir
+ # Disable automatic maintenance so a background commit-graph write in
+ # the source repo can't race the hardlinking local clone and fail with
+ # "hardlink different from source".
+ opts = ["-c", "gc.auto=0", "-c", "maintenance.auto=false"]
- if Bundler.feature_flag.bundler_4_mode? || supports_minus_c?
- ["git", "-C", dir.to_s, *cmd]
- else
- ["git", *cmd, { chdir: dir.to_s }]
- end
+ return ["git", *opts, *cmd] unless dir
+
+ ["git", "-C", dir.to_s, *opts, *cmd]
end
def extra_clone_args
@@ -431,8 +458,16 @@ module Bundler
args
end
+ def fetch_command(args)
+ ["fetch", "--force", "--quiet", "--no-tags", *args, "--", configured_uri, refspec].compact
+ end
+
+ def clone_command(args)
+ ["clone", "--bare", "--no-hardlinks", "--quiet", *args, "--", configured_uri, path.to_s]
+ end
+
def depth_args
- return [] if full_clone?
+ return [] unless shallow?
["--depth", depth.to_s]
end
@@ -447,12 +482,8 @@ module Bundler
branch || tag
end
- def full_clone?
- depth.nil?
- end
-
- def supports_minus_c?
- @supports_minus_c ||= Gem::Version.new(version) >= Gem::Version.new("1.8.5")
+ def shallow?
+ !depth.nil?
end
def needs_allow_any_sha1_in_want?
diff --git a/lib/bundler/source/metadata.rb b/lib/bundler/source/metadata.rb
index fd959cd64e..ecf8895187 100644
--- a/lib/bundler/source/metadata.rb
+++ b/lib/bundler/source/metadata.rb
@@ -58,6 +58,10 @@ module Bundler
def version_message(spec)
"#{spec.name} #{spec.version}"
end
+
+ def checksum_store
+ @checksum_store ||= Checksum::Store.new
+ end
end
end
end
diff --git a/lib/bundler/source/path.rb b/lib/bundler/source/path.rb
index 7511def230..366a23aea7 100644
--- a/lib/bundler/source/path.rb
+++ b/lib/bundler/source/path.rb
@@ -24,7 +24,7 @@ module Bundler
@path = Pathname.new(options["path"])
expanded_path = expand(@path)
@path = if @path.relative?
- expanded_path.relative_path_from(root_path.expand_path)
+ expanded_path.relative_path_from(File.expand_path(root_path))
else
expanded_path
end
@@ -53,6 +53,8 @@ module Bundler
"source at `#{@path}`"
end
+ alias_method :identifier, :to_s
+
alias_method :to_gemfile, :path
def hash
@@ -81,7 +83,7 @@ module Bundler
def cache(spec, custom_path = nil)
app_cache_path = app_cache_path(custom_path)
- return unless Bundler.feature_flag.cache_all?
+ return unless Bundler.settings[:cache_all]
return if expand(@original_path).to_s.index(root_path.to_s + "/") == 0
unless @original_path.exist?
@@ -218,10 +220,11 @@ module Bundler
# Some gem authors put absolute paths in their gemspec
# and we have to save them from themselves
spec.files = spec.files.filter_map do |path|
- next path unless /\A#{Pathname::SEPARATOR_PAT}/o.match?(path)
+ pathname = Pathname.new(path)
+ next path unless pathname.absolute?
next if File.directory?(path)
begin
- Pathname.new(path).relative_path_from(gem_dir).to_s
+ pathname.relative_path_from(gem_dir).to_s
rescue ArgumentError
path
end
diff --git a/lib/bundler/source/path/installer.rb b/lib/bundler/source/path/installer.rb
index 0af28fe770..39765e5da2 100644
--- a/lib/bundler/source/path/installer.rb
+++ b/lib/bundler/source/path/installer.rb
@@ -24,7 +24,7 @@ module Bundler
def post_install
run_hooks(:pre_install)
- unless @disable_extensions
+ unless @disable_extensions || Bundler.settings[:no_build_extension]
build_extensions
run_hooks(:post_build)
end
diff --git a/lib/bundler/source/rubygems.rb b/lib/bundler/source/rubygems.rb
index 19800e9c58..ed864604fe 100644
--- a/lib/bundler/source/rubygems.rb
+++ b/lib/bundler/source/rubygems.rb
@@ -8,21 +8,26 @@ module Bundler
autoload :Remote, File.expand_path("rubygems/remote", __dir__)
# Ask for X gems per API request
- API_REQUEST_SIZE = 50
+ API_REQUEST_SIZE = 100
+ REQUIRE_MUTEX = Mutex.new
attr_accessor :remotes
def initialize(options = {})
@options = options
@remotes = []
+ @remote_cooldowns = {}
@dependency_names = []
@allow_remote = false
@allow_cached = false
@allow_local = options["allow_local"] || false
@prefer_local = false
@checksum_store = Checksum::Store.new
+ @gem_installers = {}
+ @gem_installers_mutex = Mutex.new
- Array(options["remotes"]).reverse_each {|r| add_remote(r) }
+ cooldown = options["cooldown"]
+ Array(options["remotes"]).reverse_each {|r| add_remote(r, cooldown: cooldown) }
@lockfile_remotes = @remotes if options["from_lockfile"]
end
@@ -145,6 +150,13 @@ module Bundler
# sources, and large_idx.merge! small_idx is way faster than
# small_idx.merge! large_idx.
index = @allow_remote ? remote_specs.dup : Index.new
+
+ # Snapshot per-version `created_at` from the remote info before installed
+ # / cached specs overwrite the EndpointSpecification objects that carry
+ # it. The cooldown filter consults `created_at` on every candidate, so
+ # local stubs need the published date back-filled to participate.
+ remote_created_at = collect_remote_created_at(index)
+
index.merge!(cached_specs) if @allow_cached
index.merge!(installed_specs) if @allow_local
@@ -158,66 +170,57 @@ module Bundler
end
end
+ backfill_created_at(index, remote_created_at) unless remote_created_at.empty?
+
index
end
end
- def install(spec, options = {})
+ def download(spec, options = {})
if (spec.default_gem? && !cached_built_in_gem(spec, local: options[:local])) || (installed?(spec) && !options[:force])
- print_using_message "Using #{version_message(spec, options[:previous_spec])}"
- return nil # no post-install message
+ return true
end
- if spec.remote
- # Check for this spec from other sources
- uris = [spec.remote, *remotes_for_spec(spec)].map(&:anonymized_uri).uniq
- Installer.ambiguous_gems << [spec.name, *uris] if uris.length > 1
- end
-
- path = fetch_gem_if_possible(spec, options[:previous_spec])
- raise GemNotFound, "Could not find #{spec.file_name} for installation" unless path
-
- return if Bundler.settings[:no_install]
-
- install_path = rubygems_dir
- bin_path = Bundler.system_bindir
-
- require_relative "../rubygems_gem_installer"
-
- 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)
- )
+ installer = rubygems_gem_installer(spec, options)
if spec.remote
s = begin
installer.spec
rescue Gem::Package::FormatError
- Bundler.rm_rf(path)
+ Bundler.rm_rf(installer.gem)
raise
rescue Gem::Security::Exception => e
raise SecurityError,
- "The gem #{File.basename(path, ".gem")} can't be installed because " \
+ "The gem #{installer.gem} can't be installed because " \
"the security policy didn't allow it, with the message: #{e.message}"
end
spec.__swap__(s)
end
+ spec
+ end
+
+ def install(spec, options = {})
+ if (spec.default_gem? && !cached_built_in_gem(spec, local: options[:local])) || (installed?(spec) && !options[:force])
+ print_using_message "Using #{version_message(spec, options[:previous_spec])}"
+ return nil # no post-install message
+ end
+
+ return if Bundler.settings[:no_install]
+
+ installer = rubygems_gem_installer(spec, options)
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
- installed_spec = installer.install
+ installed_spec = nil
+
+ Gem.time("Installed #{spec.name} in", 0, true) do
+ installed_spec = installer.install
+ end
spec.full_gem_path = installed_spec.full_gem_path
spec.loaded_from = installed_spec.loaded_from
@@ -251,9 +254,14 @@ module Bundler
cached_path
end
- def add_remote(source)
+ def add_remote(source, cooldown: nil)
uri = normalize_uri(source)
@remotes.unshift(uri) unless @remotes.include?(uri)
+ @remote_cooldowns[uri] = cooldown if cooldown
+ end
+
+ def cooldown_for(uri)
+ @remote_cooldowns[uri]
end
def spec_names
@@ -274,7 +282,7 @@ module Bundler
def remote_fetchers
@remote_fetchers ||= remotes.to_h do |uri|
- remote = Source::Rubygems::Remote.new(uri)
+ remote = Source::Rubygems::Remote.new(uri, cooldown: cooldown_for(uri))
[remote, Bundler::Fetcher.new(remote)]
end.freeze
end
@@ -322,6 +330,13 @@ module Bundler
@allow_remote && api_fetchers.any?
end
+ def clear_cache
+ @specs = nil
+ @installed_specs = nil
+ @default_specs = nil
+ @cached_specs = nil
+ end
+
protected
def remote_names
@@ -332,13 +347,6 @@ module Bundler
remotes.map(&method(:remove_auth))
end
- def remotes_for_spec(spec)
- specs.search_all(spec.name).inject([]) do |uris, s|
- uris << s.remote if s.remote
- uris
- end
- end
-
def cached_gem(spec)
global_cache_path = download_cache_path(spec)
caches << global_cache_path if global_cache_path
@@ -471,6 +479,31 @@ module Bundler
private
+ def collect_remote_created_at(index)
+ return {} unless @allow_remote
+
+ snapshot = {}
+ index.each do |spec|
+ next unless spec.respond_to?(:created_at) && spec.created_at
+ # Remember the remote that supplied the date too: when a source has
+ # several remotes with different per-URI cooldown settings we must
+ # restore the same one during backfill so `effective_cooldown` agrees.
+ snapshot[[spec.name, spec.version]] = [spec.created_at, spec.remote]
+ end
+ snapshot
+ end
+
+ def backfill_created_at(index, snapshot)
+ index.each do |spec|
+ next unless spec.respond_to?(:created_at=)
+ next if spec.created_at
+ remote_created_at, remote = snapshot[[spec.name, spec.version]]
+ next unless remote_created_at
+ spec.created_at = remote_created_at
+ spec.remote ||= remote if remote && spec.respond_to?(:remote=)
+ end
+ end
+
def lockfile_remotes
@lockfile_remotes || credless_remotes
end
@@ -491,7 +524,15 @@ module Bundler
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)
+
+ Plugin.hook(Plugin::Events::GEM_BEFORE_FETCH, spec)
+ begin
+ Gem.time("Downloaded #{spec.name} in", 0, true) do
+ Bundler.rubygems.download_gem(spec, uri, download_cache_path, gem_remote_fetcher)
+ end
+ ensure
+ Plugin.hook(Plugin::Events::GEM_AFTER_FETCH, spec)
+ end
end
# Returns the global cache path of the calling Rubygems::Source object.
@@ -506,17 +547,52 @@ module Bundler
# @return [Pathname] The global cache path.
#
def download_cache_path(spec)
- return unless Bundler.feature_flag.global_gem_cache?
+ return unless Bundler.settings[:global_gem_cache]
return unless remote = spec.remote
return unless cache_slug = remote.cache_slug
- Bundler.user_cache.join("gems", cache_slug)
+ if Gem.respond_to?(:global_gem_cache_path)
+ Pathname.new(Gem.global_gem_cache_path).join(cache_slug)
+ else
+ # Fall back to old location for older RubyGems versions
+ Bundler.user_cache.join("gems", cache_slug)
+ end
end
def extension_cache_slug(spec)
return unless remote = spec.remote
remote.cache_slug
end
+
+ # We are using a mutex to read and write from/to the hash.
+ # The reason this double synchronization was added is for performance
+ # and to lock the mutex for the shortest possible amount of time. Otherwise,
+ # all threads are fighting over this mutex and when it gets acquired it gets locked
+ # until a thread finishes downloading a gem, leaving the other threads waiting
+ # doing nothing.
+ def rubygems_gem_installer(spec, options)
+ @gem_installers_mutex.synchronize { @gem_installers[spec.name] } || begin
+ path = fetch_gem_if_possible(spec, options[:previous_spec])
+ raise GemNotFound, "Could not find #{spec.file_name} for installation" unless path
+
+ REQUIRE_MUTEX.synchronize { require_relative "../rubygems_gem_installer" }
+
+ installer = Bundler::RubyGemsGemInstaller.at(
+ path,
+ security_policy: Bundler.rubygems.security_policies[Bundler.settings["trust-policy"]],
+ install_dir: rubygems_dir.to_s,
+ bin_dir: Bundler.system_bindir.to_s,
+ ignore_dependencies: true,
+ wrappers: true,
+ env_shebang: true,
+ build_args: options[:build_args],
+ bundler_extension_cache_path: extension_cache_path(spec),
+ build_extension: Bundler.settings[:no_build_extension] ? false : nil,
+ install_plugin: Bundler.settings[:no_install_plugin] ? false : nil
+ )
+ @gem_installers_mutex.synchronize { @gem_installers[spec.name] ||= installer }
+ end
+ end
end
end
end
diff --git a/lib/bundler/source/rubygems/remote.rb b/lib/bundler/source/rubygems/remote.rb
index ed55912a99..3d847424b7 100644
--- a/lib/bundler/source/rubygems/remote.rb
+++ b/lib/bundler/source/rubygems/remote.rb
@@ -4,9 +4,9 @@ module Bundler
class Source
class Rubygems
class Remote
- attr_reader :uri, :anonymized_uri, :original_uri
+ attr_reader :uri, :anonymized_uri, :original_uri, :cooldown
- def initialize(uri)
+ def initialize(uri, cooldown: nil)
orig_uri = uri
uri = Bundler.settings.mirror_for(uri)
@original_uri = orig_uri if orig_uri != uri
@@ -14,6 +14,16 @@ module Bundler
@uri = apply_auth(uri, fallback_auth).freeze
@anonymized_uri = remove_auth(@uri).freeze
+ @cooldown = cooldown
+ end
+
+ # Returns the cooldown days that apply to this remote, resolving the
+ # precedence CLI > config > Gemfile per-source. Returns nil if no
+ # cooldown applies.
+ def effective_cooldown
+ override = Bundler.settings[:cooldown]
+ return override if override
+ @cooldown
end
MAX_CACHE_SLUG_HOST_SIZE = 255 - 1 - 32 # 255 minus dot minus MD5 length
diff --git a/lib/bundler/source/rubygems_aggregate.rb b/lib/bundler/source/rubygems_aggregate.rb
index 99ef81ad54..8aeaa375fa 100644
--- a/lib/bundler/source/rubygems_aggregate.rb
+++ b/lib/bundler/source/rubygems_aggregate.rb
@@ -5,9 +5,10 @@ module Bundler
class RubygemsAggregate
attr_reader :source_map, :sources
- def initialize(sources, source_map)
+ def initialize(sources, source_map, excluded_sources = [])
@sources = sources
@source_map = source_map
+ @excluded_sources = excluded_sources
@index = build_index
end
@@ -31,6 +32,8 @@ module Bundler
dependency_names = source_map.pinned_spec_names
sources.all_sources.each do |source|
+ next if @excluded_sources.include?(source)
+
source.dependency_names = dependency_names - source_map.pinned_spec_names(source)
idx.add_source source.specs
dependency_names.concat(source.unmet_deps).uniq!
diff --git a/lib/bundler/source_list.rb b/lib/bundler/source_list.rb
index 2f16281045..ab7002d6e5 100644
--- a/lib/bundler/source_list.rb
+++ b/lib/bundler/source_list.rb
@@ -9,7 +9,7 @@ module Bundler
:metadata_source
def global_rubygems_source
- @global_rubygems_source ||= rubygems_aggregate_class.new("allow_local" => true)
+ @global_rubygems_source ||= source_class.new("allow_local" => true)
end
def initialize
@@ -21,19 +21,9 @@ module Bundler
@rubygems_sources = []
@metadata_source = Source::Metadata.new
- @merged_gem_lockfile_sections = false
@local_mode = true
end
- def merged_gem_lockfile_sections?
- @merged_gem_lockfile_sections
- end
-
- def merged_gem_lockfile_sections!(replacement_source)
- @merged_gem_lockfile_sections = true
- @global_rubygems_source = replacement_source
- end
-
def aggregate_global_source?
global_rubygems_source.multiple_remotes?
end
@@ -69,8 +59,8 @@ module Bundler
add_source_to_list Plugin.source(source).new(options), @plugin_sources
end
- def add_global_rubygems_remote(uri)
- global_rubygems_source.add_remote(uri)
+ def add_global_rubygems_remote(uri, cooldown: nil)
+ global_rubygems_source.add_remote(uri, cooldown: cooldown)
global_rubygems_source
end
@@ -90,10 +80,6 @@ module Bundler
@rubygems_sources
end
- def rubygems_remotes
- rubygems_sources.flat_map(&:remotes).uniq
- end
-
def all_sources
path_sources + git_sources + plugin_sources + rubygems_sources + [metadata_source]
end
@@ -115,11 +101,7 @@ module Bundler
end
def lock_rubygems_sources
- if merged_gem_lockfile_sections?
- [combine_rubygems_sources]
- else
- rubygems_sources.sort_by(&:identifier)
- end
+ rubygems_sources.sort_by(&:identifier)
end
# Returns true if there are changes
@@ -129,16 +111,7 @@ module Bundler
@rubygems_sources, @path_sources, @git_sources, @plugin_sources = map_sources(replacement_sources)
@global_rubygems_source = global_replacement_source(replacement_sources)
- different_sources?(lock_sources, replacement_sources)
- end
-
- # Returns true if there are changes
- def expired_sources?(replacement_sources)
- return false if replacement_sources.empty?
-
- lock_sources = dup_with_replaced_sources(replacement_sources).lock_sources
-
- different_sources?(lock_sources, replacement_sources)
+ !equivalent_sources?(lock_sources, replacement_sources)
end
def prefer_local!
@@ -163,14 +136,12 @@ module Bundler
all_sources.each(&:remote!)
end
- private
-
- def dup_with_replaced_sources(replacement_sources)
- new_source_list = dup
- new_source_list.replace_sources!(replacement_sources)
- new_source_list
+ def clear_cache
+ rubygems_sources.each(&:clear_cache)
end
+ private
+
def map_sources(replacement_sources)
rubygems = @rubygems_sources.map do |source|
replace_rubygems_source(replacement_sources, source)
@@ -224,11 +195,7 @@ module Bundler
end
end
- def different_sources?(lock_sources, replacement_sources)
- !equivalent_sources?(lock_sources, replacement_sources)
- end
-
- def rubygems_aggregate_class
+ def source_class
Source::Rubygems
end
@@ -247,10 +214,6 @@ module Bundler
end
end
- def combine_rubygems_sources
- Source::Rubygems.new("remotes" => rubygems_remotes)
- end
-
def warn_on_git_protocol(source)
return if Bundler.settings["git.allow_insecure"]
diff --git a/lib/bundler/source_map.rb b/lib/bundler/source_map.rb
index a8e12d08c3..513eb37f8b 100644
--- a/lib/bundler/source_map.rb
+++ b/lib/bundler/source_map.rb
@@ -14,24 +14,25 @@ module Bundler
direct_requirements.reject {|_, source| source == skip }.keys
end
- def all_requirements
+ def all_requirements(excluded_sources = [])
requirements = direct_requirements.dup
- unmet_deps = sources.non_default_explicit_sources.map do |source|
+ explicit_sources = sources.non_default_explicit_sources.reject do |source|
+ excluded_sources.include?(source)
+ end
+
+ unmet_deps = explicit_sources.map do |source|
(source.spec_names - pinned_spec_names).each do |indirect_dependency_name|
previous_source = requirements[indirect_dependency_name]
if previous_source.nil?
requirements[indirect_dependency_name] = source
else
- no_ambiguous_sources = Bundler.feature_flag.bundler_4_mode?
-
msg = ["The gem '#{indirect_dependency_name}' was found in multiple relevant sources."]
msg.concat [previous_source, source].map {|s| " * #{s}" }.sort
- msg << "You #{no_ambiguous_sources ? :must : :should} add this gem to the source block for the source you wish it to be installed from."
+ msg << "You must add this gem to the source block for the source you wish it to be installed from."
msg = msg.join("\n")
- raise SecurityError, msg if no_ambiguous_sources
- Bundler.ui.warn "Warning: #{msg}"
+ raise SecurityError, msg
end
end
diff --git a/lib/bundler/spec_set.rb b/lib/bundler/spec_set.rb
index 411393ce1b..ae5e5cbaa9 100644
--- a/lib/bundler/spec_set.rb
+++ b/lib/bundler/spec_set.rb
@@ -11,16 +11,11 @@ module Bundler
@specs = specs
end
- def for(dependencies, platforms_or_legacy_check = [nil], legacy_platforms = [nil], skips: [])
- platforms = if [true, false].include?(platforms_or_legacy_check)
- Bundler::SharedHelpers.major_deprecation 2,
+ def for(dependencies, platforms = [nil], legacy_platforms = [nil], skips: [])
+ if [true, false].include?(platforms)
+ Bundler::SharedHelpers.feature_removed! \
"SpecSet#for received a `check` parameter, but that's no longer used and deprecated. " \
- "SpecSet#for always implicitly performs validation. Please remove this parameter",
- print_caller_location: true
-
- legacy_platforms
- else
- platforms_or_legacy_check
+ "SpecSet#for always implicitly performs validation. Please remove this parameter"
end
materialize_dependencies(dependencies, platforms, skips: skips)
@@ -179,13 +174,11 @@ module Bundler
end
def -(other)
- SharedHelpers.major_deprecation 2, "SpecSet#- has been removed with no replacement"
-
- SpecSet.new(to_a - other.to_a)
+ SharedHelpers.feature_removed! "SpecSet#- has been removed with no replacement"
end
def find_by_name_and_platform(name, platform)
- @specs.detect {|spec| spec.name == name && spec.installable_on_platform?(platform) }
+ lookup[name]&.detect {|spec| spec.installable_on_platform?(platform) }
end
def specs_with_additional_variants_from(other)
@@ -212,9 +205,7 @@ module Bundler
end
def <<(spec)
- SharedHelpers.major_deprecation 2, "SpecSet#<< has been removed with no replacement"
-
- @specs << spec
+ SharedHelpers.feature_removed! "SpecSet#<< has been removed with no replacement"
end
def length
@@ -283,13 +274,25 @@ module Bundler
valid_platform = lookup.all? do |_, specs|
spec = specs.first
+ # The matching candidates returned by source.specs.search are remote
+ # specs that do not carry the override list themselves. Borrow it from
+ # the LazySpec we are validating so platform-variant validation honors
+ # the same overrides the install/resolve path already applies.
+ overrides = spec.is_a?(LazySpecification) ? Array(spec.overrides) : []
matching_specs = spec.source.specs.search([spec.name, spec.version])
platform_spec = MatchPlatform.select_best_platform_match(matching_specs, platform).find do |s|
- valid?(s)
+ s.matches_current_metadata_with_overrides?(overrides) && valid_dependencies?(s)
end
if platform_spec
- new_specs << LazySpecification.from_spec(platform_spec) unless specs.include?(platform_spec)
+ unless specs.include?(platform_spec)
+ new_lazy = LazySpecification.from_spec(platform_spec)
+ # Carry the overrides forward so a follow-up complete_platform
+ # call that picks this synthesized variant as its exemplar still
+ # honors the user's override list.
+ new_lazy.overrides = overrides if overrides.any?
+ new_specs << new_lazy
+ end
true
else
false
@@ -323,7 +326,7 @@ module Bundler
end
def sorted
- @sorted ||= ([@specs.find {|s| s.name == "rake" }] + tsort).compact.uniq
+ @sorted ||= ([lookup["rake"]&.first] + tsort).compact.uniq
rescue TSort::Cyclic => error
cgems = extract_circular_gems(error)
raise CyclicDependencyError, "Your bundle requires gems that depend" \
diff --git a/lib/bundler/stub_specification.rb b/lib/bundler/stub_specification.rb
index 026f753d41..b353642b40 100644
--- a/lib/bundler/stub_specification.rb
+++ b/lib/bundler/stub_specification.rb
@@ -52,6 +52,7 @@ module Bundler
# This is defined directly to avoid having to loading the full spec
def missing_extensions?
+ return false if RUBY_ENGINE == "jruby"
return false if default_gem?
return false if extensions.empty?
return false if File.exist? gem_build_complete_path
diff --git a/lib/bundler/templates/newgem/CODE_OF_CONDUCT.md.tt b/lib/bundler/templates/newgem/CODE_OF_CONDUCT.md.tt
index 67fe8cee79..633baebdd5 100644
--- a/lib/bundler/templates/newgem/CODE_OF_CONDUCT.md.tt
+++ b/lib/bundler/templates/newgem/CODE_OF_CONDUCT.md.tt
@@ -1,132 +1,10 @@
-# Contributor Covenant Code of Conduct
+# Code of Conduct
-## Our Pledge
+<%= config[:name].inspect %> follows [The Ruby Community Conduct Guideline](https://www.ruby-lang.org/en/conduct) in all "collaborative space", which is defined as community communications channels (such as mailing lists, submitted patches, commit comments, etc.):
-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.
+* Participants will be tolerant of opposing views.
+* Participants must ensure that their language and actions are free of personal attacks and disparaging personal remarks.
+* When interpreting the words and actions of others, participants should always assume good intentions.
+* Behaviour which can be reasonably considered harassment will not be tolerated.
-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:
-
-* 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
-
-Examples of unacceptable behavior include:
-
-* 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
-* 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 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.
-
-## 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.
-
-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:
-
-### 1. Correction
-
-**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.
-
-### 2. Warning
-
-**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.
-
-### 3. Temporary Ban
-
-**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.
-
-### 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.
-
-**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].
-
-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].
-
-[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
+If you have any concerns about behaviour within this project, please contact us at [<%= config[:email].inspect %>](mailto:<%= config[:email].inspect %>).
diff --git a/lib/bundler/templates/newgem/Cargo.toml.tt b/lib/bundler/templates/newgem/Cargo.toml.tt
index f5a460c9bb..cd00f97e5a 100644
--- a/lib/bundler/templates/newgem/Cargo.toml.tt
+++ b/lib/bundler/templates/newgem/Cargo.toml.tt
@@ -5,3 +5,9 @@
[workspace]
members = ["./ext/<%= config[:name] %>"]
resolver = "2"
+
+[profile.release]
+# By default, debug symbols are stripped from the final binary which makes it
+# harder to debug if something goes wrong. It's recommended to keep debug
+# symbols in the release build so that you can debug the final binary if needed.
+debug = true
diff --git a/lib/bundler/templates/newgem/Gemfile.tt b/lib/bundler/templates/newgem/Gemfile.tt
index ea7a33ee28..85dc593b8f 100644
--- a/lib/bundler/templates/newgem/Gemfile.tt
+++ b/lib/bundler/templates/newgem/Gemfile.tt
@@ -6,19 +6,19 @@ source "https://rubygems.org"
gemspec
gem "irb"
-gem "rake", "~> 13.0"
+gem "rake", ">= 13.0"
<%- if config[:ext] -%>
gem "rake-compiler"
<%- end -%>
<%- if config[:test] -%>
-gem "<%= config[:test] %>", "~> <%= config[:test_framework_version] %>"
+gem "<%= config[:test] %>"
<%- end -%>
<%- if config[:linter] == "rubocop" -%>
-gem "rubocop", "~> <%= config[:linter_version] %>"
+gem "rubocop"
<%- elsif config[:linter] == "standard" -%>
-gem "standard", "~> <%= config[:linter_version] %>"
+gem "standard"
<%- end -%>
diff --git a/lib/bundler/templates/newgem/Rakefile.tt b/lib/bundler/templates/newgem/Rakefile.tt
index 172183d4b4..83f10009c7 100644
--- a/lib/bundler/templates/newgem/Rakefile.tt
+++ b/lib/bundler/templates/newgem/Rakefile.tt
@@ -59,6 +59,11 @@ Rake::ExtensionTask.new("<%= config[:underscored_name] %>", GEMSPEC) do |ext|
end
<% end -%>
+<% if config[:ext] == "go" -%>
+require "go_gem/rake_task"
+
+GoGem::RakeTask.new("<%= config[:underscored_name] %>")
+<% end -%>
<% end -%>
<% if default_task_names.size == 1 -%>
task default: <%= default_task_names.first.inspect %>
diff --git a/lib/bundler/templates/newgem/circleci/config.yml.tt b/lib/bundler/templates/newgem/circleci/config.yml.tt
index f40f029bf1..c4dd9d0647 100644
--- a/lib/bundler/templates/newgem/circleci/config.yml.tt
+++ b/lib/bundler/templates/newgem/circleci/config.yml.tt
@@ -7,6 +7,10 @@ jobs:
environment:
RB_SYS_FORCE_INSTALL_RUST_TOOLCHAIN: 'true'
<%- end -%>
+<%- if config[:ext] == 'go' -%>
+ environment:
+ GO_VERSION: '1.23.0'
+<%- end -%>
steps:
- checkout
<%- if config[:ext] == 'rust' -%>
@@ -17,6 +21,14 @@ jobs:
name: Install a RubyGems version that can compile rust extensions
command: gem update --system '<%= ::Gem.rubygems_version %>'
<%- end -%>
+<%- if config[:ext] == 'go' -%>
+ - run:
+ name: Install Go
+ command: |
+ wget https://go.dev/dl/go$GO_VERSION.linux-amd64.tar.gz -O /tmp/go.tar.gz
+ tar -C /usr/local -xzf /tmp/go.tar.gz
+ echo 'export PATH=/usr/local/go/bin:"$PATH"' >> "$BASH_ENV"
+<%- end -%>
- run:
name: Run the default task
command: |
diff --git a/lib/bundler/templates/newgem/ext/newgem/Cargo.toml.tt b/lib/bundler/templates/newgem/ext/newgem/Cargo.toml.tt
index 0ebce0e4a0..a06166aee7 100644
--- a/lib/bundler/templates/newgem/ext/newgem/Cargo.toml.tt
+++ b/lib/bundler/templates/newgem/ext/newgem/Cargo.toml.tt
@@ -12,4 +12,11 @@ publish = false
crate-type = ["cdylib"]
[dependencies]
-magnus = { version = "0.6.2" }
+magnus = { version = "0.8.2" }
+rb-sys = { version = "0.9", features = ["stable-api-compiled-fallback"] }
+
+[build-dependencies]
+rb-sys-env = "0.2.2"
+
+[dev-dependencies]
+rb-sys-test-helpers = { version = "0.2.2" }
diff --git a/lib/bundler/templates/newgem/ext/newgem/build.rs.tt b/lib/bundler/templates/newgem/ext/newgem/build.rs.tt
new file mode 100644
index 0000000000..80a7842753
--- /dev/null
+++ b/lib/bundler/templates/newgem/ext/newgem/build.rs.tt
@@ -0,0 +1,5 @@
+pub fn main() -> Result<(), Box<dyn std::error::Error>> {
+ let _ = rb_sys_env::activate()?;
+
+ Ok(())
+}
diff --git a/lib/bundler/templates/newgem/ext/newgem/extconf-go.rb.tt b/lib/bundler/templates/newgem/ext/newgem/extconf-go.rb.tt
new file mode 100644
index 0000000000..a689e21ebe
--- /dev/null
+++ b/lib/bundler/templates/newgem/ext/newgem/extconf-go.rb.tt
@@ -0,0 +1,11 @@
+# frozen_string_literal: true
+
+require "mkmf"
+require "go_gem/mkmf"
+
+# Makes all symbols private by default to avoid unintended conflict
+# with other gems. To explicitly export symbols you can use RUBY_FUNC_EXPORTED
+# selectively, or entirely remove this flag.
+append_cflags("-fvisibility=hidden")
+
+create_go_makefile(<%= config[:makefile_path].inspect %>)
diff --git a/lib/bundler/templates/newgem/ext/newgem/go.mod.tt b/lib/bundler/templates/newgem/ext/newgem/go.mod.tt
new file mode 100644
index 0000000000..3f4819d004
--- /dev/null
+++ b/lib/bundler/templates/newgem/ext/newgem/go.mod.tt
@@ -0,0 +1,5 @@
+module github.com/<%= config[:go_module_username] %>/<%= config[:underscored_name] %>
+
+go 1.23
+
+require github.com/ruby-go-gem/go-gem-wrapper latest
diff --git a/lib/bundler/templates/newgem/ext/newgem/newgem-go.c.tt b/lib/bundler/templates/newgem/ext/newgem/newgem-go.c.tt
new file mode 100644
index 0000000000..119c0c96ea
--- /dev/null
+++ b/lib/bundler/templates/newgem/ext/newgem/newgem-go.c.tt
@@ -0,0 +1,2 @@
+#include "<%= config[:underscored_name] %>.h"
+#include "_cgo_export.h"
diff --git a/lib/bundler/templates/newgem/ext/newgem/newgem.go.tt b/lib/bundler/templates/newgem/ext/newgem/newgem.go.tt
new file mode 100644
index 0000000000..f19b750e58
--- /dev/null
+++ b/lib/bundler/templates/newgem/ext/newgem/newgem.go.tt
@@ -0,0 +1,31 @@
+package main
+
+/*
+#include "<%= config[:underscored_name] %>.h"
+
+VALUE rb_<%= config[:underscored_name] %>_sum(VALUE self, VALUE a, VALUE b);
+*/
+import "C"
+
+import (
+ "github.com/ruby-go-gem/go-gem-wrapper/ruby"
+)
+
+//export rb_<%= config[:underscored_name] %>_sum
+func rb_<%= config[:underscored_name] %>_sum(_ C.VALUE, a C.VALUE, b C.VALUE) C.VALUE {
+ longA := ruby.NUM2LONG(ruby.VALUE(a))
+ longB := ruby.NUM2LONG(ruby.VALUE(b))
+
+ sum := longA + longB
+
+ return C.VALUE(ruby.LONG2NUM(sum))
+}
+
+//export Init_<%= config[:underscored_name] %>
+func Init_<%= config[:underscored_name] %>() {
+ rb_m<%= config[:constant_array].join %> := ruby.RbDefineModule(<%= config[:constant_name].inspect %>)
+ ruby.RbDefineSingletonMethod(rb_m<%= config[:constant_array].join %>, "sum", C.rb_<%= config[:underscored_name] %>_sum, 2)
+}
+
+func main() {
+}
diff --git a/lib/bundler/templates/newgem/ext/newgem/src/lib.rs.tt b/lib/bundler/templates/newgem/ext/newgem/src/lib.rs.tt
index ba234529a3..09ce97682d 100644
--- a/lib/bundler/templates/newgem/ext/newgem/src/lib.rs.tt
+++ b/lib/bundler/templates/newgem/ext/newgem/src/lib.rs.tt
@@ -1,7 +1,7 @@
use magnus::{function, prelude::*, Error, Ruby};
-fn hello(subject: String) -> String {
- format!("Hello from Rust, {subject}!")
+pub fn hello(subject: String) -> String {
+ format!("Hello {subject}, from Rust!")
}
#[magnus::init]
@@ -10,3 +10,14 @@ fn init(ruby: &Ruby) -> Result<(), Error> {
module.define_singleton_method("hello", function!(hello, 1))?;
Ok(())
}
+
+#[cfg(test)]
+mod tests {
+ use rb_sys_test_helpers::ruby_test;
+ use super::hello;
+
+ #[ruby_test]
+ fn test_hello() {
+ assert_eq!("Hello world, from Rust!", hello("world".to_string()));
+ }
+}
diff --git a/lib/bundler/templates/newgem/github/workflows/build-gems.yml.tt b/lib/bundler/templates/newgem/github/workflows/build-gems.yml.tt
new file mode 100644
index 0000000000..d49954d2cd
--- /dev/null
+++ b/lib/bundler/templates/newgem/github/workflows/build-gems.yml.tt
@@ -0,0 +1,69 @@
+---
+name: Build gems
+
+on:
+ push:
+ tags:
+ - "v*"
+ - "cross-gem/*"
+ workflow_dispatch:
+
+permissions:
+ contents: read
+ packages: write
+
+jobs:
+ ci-data:
+ runs-on: ubuntu-latest
+ outputs:
+ result: ${{ steps.fetch.outputs.result }}
+ steps:
+ - uses: oxidize-rb/actions/fetch-ci-data@v1
+ id: fetch
+ with:
+ supported-ruby-platforms: |
+ exclude: ["arm-linux", "x64-mingw32"]
+ stable-ruby-versions: |
+ exclude: ["head"]
+
+ source-gem:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v6
+
+ - uses: ruby/setup-ruby@v1
+ with:
+ bundler-cache: true
+
+ - name: Build gem
+ run: bundle exec rake build
+
+ - uses: actions/upload-artifact@v7
+ with:
+ name: source-gem
+ path: pkg/*.gem
+
+ cross-gem:
+ name: Compile native gem for ${{ matrix.platform }}
+ runs-on: ubuntu-latest
+ needs: ci-data
+ strategy:
+ matrix:
+ platform: ${{ fromJSON(needs.ci-data.outputs.result).supported-ruby-platforms }}
+ steps:
+ - uses: actions/checkout@v6
+
+ - uses: ruby/setup-ruby@v1
+ with:
+ bundler-cache: true
+
+ - uses: oxidize-rb/actions/cross-gem@v1
+ id: cross-gem
+ with:
+ platform: ${{ matrix.platform }}
+ ruby-versions: ${{ join(fromJSON(needs.ci-data.outputs.result).stable-ruby-versions, ',') }}
+
+ - uses: actions/upload-artifact@v7
+ with:
+ name: cross-gem
+ path: ${{ steps.cross-gem.outputs.gem-path }}
diff --git a/lib/bundler/templates/newgem/github/workflows/main.yml.tt b/lib/bundler/templates/newgem/github/workflows/main.yml.tt
index 9224ee0ca2..cc8f04dd33 100644
--- a/lib/bundler/templates/newgem/github/workflows/main.yml.tt
+++ b/lib/bundler/templates/newgem/github/workflows/main.yml.tt
@@ -7,6 +7,9 @@ on:
pull_request:
+permissions:
+ contents: read
+
jobs:
build:
runs-on: ubuntu-latest
@@ -17,7 +20,7 @@ jobs:
- '<%= RUBY_VERSION %>'
steps:
- - uses: actions/checkout@v4
+ - uses: actions/checkout@v6
with:
persist-credentials: false
<%- if config[:ext] == 'rust' -%>
@@ -35,5 +38,11 @@ jobs:
ruby-version: ${{ matrix.ruby }}
bundler-cache: true
<%- end -%>
+<%- if config[:ext] == 'go' -%>
+ - name: Setup Go
+ uses: actions/setup-go@v5
+ with:
+ go-version-file: ext/<%= config[:underscored_name] %>/go.mod
+<%- end -%>
- name: Run the default task
run: bundle exec rake
diff --git a/lib/bundler/templates/newgem/gitlab-ci.yml.tt b/lib/bundler/templates/newgem/gitlab-ci.yml.tt
index d2e1f33736..adbd70cbc0 100644
--- a/lib/bundler/templates/newgem/gitlab-ci.yml.tt
+++ b/lib/bundler/templates/newgem/gitlab-ci.yml.tt
@@ -6,6 +6,11 @@ default:
- apt-get update && apt-get install -y clang
- gem update --system '<%= ::Gem.rubygems_version %>'
<%- end -%>
+<%- if config[:ext] == 'go' -%>
+ - wget https://go.dev/dl/go$GO_VERSION.linux-amd64.tar.gz -O /tmp/go.tar.gz
+ - tar -C /usr/local -xzf /tmp/go.tar.gz
+ - export PATH=/usr/local/go/bin:$PATH
+<%- end -%>
- gem install bundler -v <%= Bundler::VERSION %>
- bundle install
@@ -14,5 +19,9 @@ example_job:
variables:
RB_SYS_FORCE_INSTALL_RUST_TOOLCHAIN: 'true'
<%- end -%>
+<%- if config[:ext] == 'go' -%>
+ variables:
+ GO_VERSION: '1.23.0'
+<%- end -%>
script:
- bundle exec rake
diff --git a/lib/bundler/templates/newgem/lib/newgem.rb.tt b/lib/bundler/templates/newgem/lib/newgem.rb.tt
index caf6e32f4a..3aedee0d25 100644
--- a/lib/bundler/templates/newgem/lib/newgem.rb.tt
+++ b/lib/bundler/templates/newgem/lib/newgem.rb.tt
@@ -2,7 +2,7 @@
require_relative "<%= File.basename(config[:namespaced_path]) %>/version"
<%- if config[:ext] -%>
-require_relative "<%= File.basename(config[:namespaced_path]) %>/<%= config[:underscored_name] %>"
+require "<%= File.basename(config[:namespaced_path]) %>/<%= config[:underscored_name] %>"
<%- end -%>
<%- config[:constant_array].each_with_index do |c, i| -%>
diff --git a/lib/bundler/templates/newgem/newgem.gemspec.tt b/lib/bundler/templates/newgem/newgem.gemspec.tt
index c87abda8a0..1ab1c28f46 100644
--- a/lib/bundler/templates/newgem/newgem.gemspec.tt
+++ b/lib/bundler/templates/newgem/newgem.gemspec.tt
@@ -15,10 +15,6 @@ Gem::Specification.new do |spec|
spec.license = "MIT"
<%- end -%>
spec.required_ruby_version = ">= <%= config[:required_ruby_version] %>"
-<%- if config[:ext] == 'rust' -%>
- spec.required_rubygems_version = ">= <%= config[:rust_builder_required_rubygems_version] %>"
-<%- end -%>
-
spec.metadata["allowed_push_host"] = "TODO: Set to your gem server 'https://example.com'"
spec.metadata["homepage_uri"] = spec.homepage
spec.metadata["source_code_uri"] = "<%= config[:source_code_uri] %>"
@@ -26,6 +22,12 @@ Gem::Specification.new do |spec|
spec.metadata["changelog_uri"] = "<%= config[:changelog_uri] %>"
<%- end -%>
+ # Uncomment the line below to require MFA for gem pushes.
+ # This helps protect your gem from supply chain attacks by ensuring
+ # no one can publish a new version without multi-factor authentication.
+ # See: https://guides.rubygems.org/mfa-requirement-opt-in/
+ # spec.metadata["rubygems_mfa_required"] = "true"
+
# 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__)
@@ -38,16 +40,19 @@ Gem::Specification.new do |spec|
spec.bindir = "exe"
spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
spec.require_paths = ["lib"]
-<%- if config[:ext] == 'c' || config[:ext] == 'rust' -%>
+<%- if %w(c rust go).include?(config[:ext]) -%>
spec.extensions = ["ext/<%= config[:underscored_name] %>/extconf.rb"]
<%- end -%>
# Uncomment to register a new dependency of your gem
- # spec.add_dependency "example-gem", "~> 1.0"
+ # spec.add_dependency "example-gem", ">= 1.0"
<%- if config[:ext] == 'rust' -%>
- spec.add_dependency "rb_sys", "~> 0.9.91"
+ spec.add_dependency "rb_sys", ">= 0.9.128"
+<%- end -%>
+<%- if config[:ext] == 'go' -%>
+ spec.add_dependency "go_gem", ">= 0.2"
<%- end -%>
# For more information and examples about making a new gem, check out our
- # guide at: https://bundler.io/guides/creating_gem.html
+ # guide at: https://guides.rubygems.org/make-your-own-gem/
end
diff --git a/lib/bundler/templates/newgem/spec/newgem_spec.rb.tt b/lib/bundler/templates/newgem/spec/newgem_spec.rb.tt
index 82cada988c..7c6cde170b 100644
--- a/lib/bundler/templates/newgem/spec/newgem_spec.rb.tt
+++ b/lib/bundler/templates/newgem/spec/newgem_spec.rb.tt
@@ -5,7 +5,15 @@ RSpec.describe <%= config[:constant_name] %> do
expect(<%= config[:constant_name] %>::VERSION).not_to be nil
end
+<%- if config[:ext] == 'rust' -%>
+ it "can call into Rust" do
+ result = <%= config[:constant_name] %>.hello("world")
+
+ expect(result).to eq("Hello world, from Rust!")
+ end
+<%- else -%>
it "does something useful" do
expect(false).to eq(true)
end
+<%- end -%>
end
diff --git a/lib/bundler/templates/newgem/test/minitest/test_newgem.rb.tt b/lib/bundler/templates/newgem/test/minitest/test_newgem.rb.tt
index 4b35a63071..844d3aff81 100644
--- a/lib/bundler/templates/newgem/test/minitest/test_newgem.rb.tt
+++ b/lib/bundler/templates/newgem/test/minitest/test_newgem.rb.tt
@@ -7,7 +7,13 @@ class <%= config[:minitest_constant_name] %> < Minitest::Test
refute_nil ::<%= config[:constant_name] %>::VERSION
end
+<%- if config[:ext] == 'rust' -%>
+ def test_hello_world
+ assert_equal "Hello world, from Rust!", <%= config[:constant_name] %>.hello("world")
+ end
+<%- else -%>
def test_it_does_something_useful
assert false
end
+<%- end -%>
end
diff --git a/lib/bundler/ui/shell.rb b/lib/bundler/ui/shell.rb
index 6f080b6459..b836208da8 100644
--- a/lib/bundler/ui/shell.rb
+++ b/lib/bundler/ui/shell.rb
@@ -17,6 +17,7 @@ module Bundler
@level = ENV["DEBUG"] ? "debug" : "info"
@warning_history = []
@output_stream = :stdout
+ @thread_safe_logger_key = "logger_level_#{object_id}"
end
def add_color(string, *color)
@@ -97,11 +98,13 @@ module Bundler
end
def level(name = nil)
- return @level unless name
+ current_level = Thread.current.thread_variable_get(@thread_safe_logger_key) || @level
+ return current_level unless name
+
unless index = LEVELS.index(name)
raise "#{name.inspect} is not a valid level"
end
- index <= LEVELS.index(@level)
+ index <= LEVELS.index(current_level)
end
def output_stream=(symbol)
@@ -167,12 +170,13 @@ module Bundler
end * "\n"
end
- def with_level(level)
- original = @level
- @level = level
+ def with_level(desired_level)
+ old_level = level
+ Thread.current.thread_variable_set(@thread_safe_logger_key, desired_level)
+
yield
ensure
- @level = original
+ Thread.current.thread_variable_set(@thread_safe_logger_key, old_level)
end
def with_output_stream(symbol)
diff --git a/lib/bundler/vendor/connection_pool/lib/connection_pool.rb b/lib/bundler/vendor/connection_pool/lib/connection_pool.rb
index cb4485e463..e8aaf70016 100644
--- a/lib/bundler/vendor/connection_pool/lib/connection_pool.rb
+++ b/lib/bundler/vendor/connection_pool/lib/connection_pool.rb
@@ -39,7 +39,7 @@ end
# - :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, auto_reload_after_fork: true}.freeze
def self.wrap(options, &block)
Wrapper.new(options, &block)
@@ -99,10 +99,14 @@ class Bundler::ConnectionPool
@available = TimedStack.new(@size, &block)
@key = :"pool-#{@available.object_id}"
@key_count = :"pool-#{@available.object_id}-count"
- INSTANCES[self] = self if INSTANCES
+ @discard_key = :"pool-#{@available.object_id}-discard"
+ INSTANCES[self] = self if @auto_reload_after_fork && INSTANCES
end
def with(options = {})
+ # We need to manage exception handling manually here in order
+ # to work correctly with `Gem::Timeout.timeout` and `Thread#raise`.
+ # Otherwise an interrupted Thread can leak connections.
Thread.handle_interrupt(Exception => :never) do
conn = checkout(options)
begin
@@ -116,20 +120,65 @@ class Bundler::ConnectionPool
end
alias_method :then, :with
+ ##
+ # Marks the current thread's checked-out connection for discard.
+ #
+ # When a connection is marked for discard, it will not be returned to the pool
+ # when checked in. Instead, the connection will be discarded.
+ # This is useful when a connection has become invalid or corrupted
+ # and should not be reused.
+ #
+ # Takes an optional block that will be called with the connection to be discarded.
+ # The block should perform any necessary clean-up on the connection.
+ #
+ # @yield [conn]
+ # @yieldparam conn [Object] The connection to be discarded.
+ # @yieldreturn [void]
+ #
+ #
+ # Note: This only affects the connection currently checked out by the calling thread.
+ # The connection will be discarded when +checkin+ is called.
+ #
+ # @return [void]
+ #
+ # @example
+ # pool.with do |conn|
+ # begin
+ # conn.execute("SELECT 1")
+ # rescue SomeConnectionError
+ # pool.discard_current_connection # Mark connection as bad
+ # raise
+ # end
+ # end
+ def discard_current_connection(&block)
+ ::Thread.current[@discard_key] = block || proc { |conn| conn }
+ end
+
def checkout(options = {})
if ::Thread.current[@key]
::Thread.current[@key_count] += 1
::Thread.current[@key]
else
::Thread.current[@key_count] = 1
- ::Thread.current[@key] = @available.pop(options[:timeout] || @timeout)
+ ::Thread.current[@key] = @available.pop(options[:timeout] || @timeout, options)
end
end
def checkin(force: false)
if ::Thread.current[@key]
if ::Thread.current[@key_count] == 1 || force
- @available.push(::Thread.current[@key])
+ if ::Thread.current[@discard_key]
+ begin
+ @available.decrement_created
+ ::Thread.current[@discard_key].call(::Thread.current[@key])
+ rescue
+ nil
+ ensure
+ ::Thread.current[@discard_key] = nil
+ end
+ else
+ @available.push(::Thread.current[@key])
+ end
::Thread.current[@key] = nil
::Thread.current[@key_count] = nil
else
@@ -146,7 +195,6 @@ class Bundler::ConnectionPool
# Shuts down the Bundler::ConnectionPool by passing each connection to +block+ and
# then removing it from the pool. Attempting to checkout a connection after
# shutdown will raise +Bundler::ConnectionPool::PoolShuttingDownError+.
-
def shutdown(&block)
@available.shutdown(&block)
end
@@ -155,7 +203,6 @@ class Bundler::ConnectionPool
# Reloads the Bundler::ConnectionPool by passing each connection to +block+ and then
# removing it the pool. Subsequent checkouts will create new connections as
# needed.
-
def reload(&block)
@available.shutdown(reload: true, &block)
end
diff --git a/lib/bundler/vendor/connection_pool/lib/connection_pool/timed_stack.rb b/lib/bundler/vendor/connection_pool/lib/connection_pool/timed_stack.rb
index 02e4485eb2..026d2c5be2 100644
--- a/lib/bundler/vendor/connection_pool/lib/connection_pool/timed_stack.rb
+++ b/lib/bundler/vendor/connection_pool/lib/connection_pool/timed_stack.rb
@@ -1,8 +1,8 @@
##
# The TimedStack manages a pool of homogeneous connections (or any resource
-# you wish to manage). Connections are created lazily up to a given maximum
+# you wish to manage). Connections are created lazily up to a given maximum
# number.
-
+#
# Examples:
#
# ts = TimedStack.new(1) { MyConnection.new }
@@ -16,14 +16,12 @@
# conn = ts.pop
# ts.pop timeout: 5
# #=> raises Bundler::ConnectionPool::TimeoutError after 5 seconds
-
class Bundler::ConnectionPool::TimedStack
attr_reader :max
##
# Creates a new pool with +size+ connections that are created from the given
# +block+.
-
def initialize(size = 0, &block)
@create_block = block
@created = 0
@@ -35,9 +33,8 @@ class Bundler::ConnectionPool::TimedStack
end
##
- # Returns +obj+ to the stack. +options+ is ignored in TimedStack but may be
+ # Returns +obj+ to the stack. +options+ is ignored in TimedStack but may be
# used by subclasses that extend TimedStack.
-
def push(obj, options = {})
@mutex.synchronize do
if @shutdown_block
@@ -53,14 +50,16 @@ class Bundler::ConnectionPool::TimedStack
alias_method :<<, :push
##
- # Retrieves a connection from the stack. If a connection is available it is
- # immediately returned. If no connection is available within the given
+ # Retrieves a connection from the stack. If a connection is available it is
+ # immediately returned. If no connection is available within the given
# timeout a Bundler::ConnectionPool::TimeoutError is raised.
#
- # +:timeout+ is the only checked entry in +options+ and is preferred over
- # the +timeout+ argument (which will be removed in a future release). Other
- # options may be used by subclasses that extend TimedStack.
-
+ # @option options [Float] :timeout (0.5) Wait this many seconds for an available entry
+ # @option options [Class] :exception (Bundler::ConnectionPool::TimeoutError) Exception class to raise
+ # if an entry was not available within the timeout period. Use `exception: false` to return nil.
+ #
+ # The +timeout+ argument will be removed in 3.0.
+ # Other options may be used by subclasses that extend TimedStack.
def pop(timeout = 0.5, options = {})
options, timeout = timeout, 0.5 if Hash === timeout
timeout = options.fetch :timeout, timeout
@@ -69,13 +68,22 @@ class Bundler::ConnectionPool::TimedStack
@mutex.synchronize do
loop do
raise Bundler::ConnectionPool::PoolShuttingDownError if @shutdown_block
- return fetch_connection(options) if connection_stored?(options)
+ if (conn = try_fetch_connection(options))
+ return conn
+ end
connection = try_create(options)
return connection if connection
to_wait = deadline - current_time
- raise Bundler::ConnectionPool::TimeoutError, "Waited #{timeout} sec, #{length}/#{@max} available" if to_wait <= 0
+ if to_wait <= 0
+ exc = options.fetch(:exception, Bundler::ConnectionPool::TimeoutError)
+ if exc
+ raise Bundler::ConnectionPool::TimeoutError, "Waited #{timeout} sec, #{length}/#{@max} available"
+ else
+ return nil
+ end
+ end
@resource.wait(@mutex, to_wait)
end
end
@@ -86,7 +94,6 @@ class Bundler::ConnectionPool::TimedStack
# removing it from the pool. Attempting to checkout a connection after
# shutdown will raise +Bundler::ConnectionPool::PoolShuttingDownError+ unless
# +:reload+ is +true+.
-
def shutdown(reload: false, &block)
raise ArgumentError, "shutdown must receive a block" unless block
@@ -121,14 +128,12 @@ class Bundler::ConnectionPool::TimedStack
##
# Returns +true+ if there are no available connections.
-
def empty?
(@created - @que.length) >= @max
end
##
# The number of connections available on the stack.
-
def length
@max - @created + @que.length
end
@@ -139,6 +144,12 @@ class Bundler::ConnectionPool::TimedStack
@que.length
end
+ ##
+ # Reduce the created count
+ def decrement_created
+ @created -= 1 unless @created == 0
+ end
+
private
def current_time
@@ -148,8 +159,17 @@ class Bundler::ConnectionPool::TimedStack
##
# This is an extension point for TimedStack and is called with a mutex.
#
- # This method must returns true if a connection is available on the stack.
+ # This method must returns a connection from the stack if one exists. Allows
+ # subclasses with expensive match/search algorithms to avoid double-handling
+ # their stack.
+ def try_fetch_connection(options = nil)
+ connection_stored?(options) && fetch_connection(options)
+ end
+ ##
+ # This is an extension point for TimedStack and is called with a mutex.
+ #
+ # This method must returns true if a connection is available on the stack.
def connection_stored?(options = nil)
!@que.empty?
end
@@ -158,7 +178,6 @@ class Bundler::ConnectionPool::TimedStack
# This is an extension point for TimedStack and is called with a mutex.
#
# This method must return a connection from the stack.
-
def fetch_connection(options = nil)
@que.pop&.first
end
@@ -167,10 +186,8 @@ class Bundler::ConnectionPool::TimedStack
# This is an extension point for TimedStack and is called with a mutex.
#
# This method must shut down all connections on the stack.
-
def shutdown_connections(options = nil)
- while connection_stored?(options)
- conn = fetch_connection(options)
+ while (conn = try_fetch_connection(options))
@created -= 1 unless @created == 0
@shutdown_block.call(conn)
end
@@ -181,7 +198,6 @@ class Bundler::ConnectionPool::TimedStack
#
# This method returns the oldest idle connection if it has been idle for more than idle_seconds.
# This requires that the stack is kept in order of checked in time (oldest first).
-
def reserve_idle_connection(idle_seconds)
return unless idle_connections?(idle_seconds)
@@ -194,7 +210,6 @@ class Bundler::ConnectionPool::TimedStack
# This is an extension point for TimedStack and is called with a mutex.
#
# Returns true if the first connection in the stack has been idle for more than idle_seconds
-
def idle_connections?(idle_seconds)
connection_stored? && (current_time - @que.first.last > idle_seconds)
end
@@ -203,7 +218,6 @@ class Bundler::ConnectionPool::TimedStack
# This is an extension point for TimedStack and is called with a mutex.
#
# This method must return +obj+ to the stack.
-
def store_connection(obj, options = nil)
@que.push [obj, current_time]
end
@@ -213,7 +227,6 @@ class Bundler::ConnectionPool::TimedStack
#
# This method must create a connection if and only if the total number of
# connections allowed has not been met.
-
def try_create(options = nil)
unless @created == @max
object = @create_block.call
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 88a3714fb8..2e9eebdbb6 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.5.0"
+ VERSION = "2.5.5"
end
diff --git a/lib/bundler/vendor/fileutils/lib/fileutils.rb b/lib/bundler/vendor/fileutils/lib/fileutils.rb
index 4d7619ddcf..a11fdc7176 100644
--- a/lib/bundler/vendor/fileutils/lib/fileutils.rb
+++ b/lib/bundler/vendor/fileutils/lib/fileutils.rb
@@ -181,7 +181,7 @@ end
#
module Bundler::FileUtils
# The version number.
- VERSION = "1.7.3"
+ VERSION = "1.8.0"
def self.private_module_function(name) #:nodoc:
module_function name
@@ -706,11 +706,12 @@ module Bundler::FileUtils
#
def ln_s(src, dest, force: nil, relative: false, target_directory: true, noop: nil, verbose: nil)
if relative
- return ln_sr(src, dest, force: force, noop: noop, verbose: verbose)
+ return ln_sr(src, dest, force: force, target_directory: target_directory, noop: noop, verbose: verbose)
end
- fu_output_message "ln -s#{force ? 'f' : ''} #{[src,dest].flatten.join ' '}" if verbose
+ fu_output_message "ln -s#{force ? 'f' : ''}#{
+ target_directory ? '' : 'T'} #{[src,dest].flatten.join ' '}" if verbose
return if noop
- fu_each_src_dest0(src, dest) do |s,d|
+ fu_each_src_dest0(src, dest, target_directory) do |s,d|
remove_file d, true if force
File.symlink s, d
end
@@ -730,42 +731,37 @@ module Bundler::FileUtils
# Like Bundler::FileUtils.ln_s, but create links relative to +dest+.
#
def ln_sr(src, dest, target_directory: true, force: nil, noop: nil, verbose: nil)
- options = "#{force ? 'f' : ''}#{target_directory ? '' : 'T'}"
- dest = File.path(dest)
- srcs = Array(src)
- link = proc do |s, target_dir_p = true|
- s = File.path(s)
- if target_dir_p
- d = File.join(destdirs = dest, File.basename(s))
+ cmd = "ln -s#{force ? 'f' : ''}#{target_directory ? '' : 'T'}" if verbose
+ fu_each_src_dest0(src, dest, target_directory) do |s,d|
+ if target_directory
+ parent = File.dirname(d)
+ destdirs = fu_split_path(parent)
+ real_ddirs = fu_split_path(File.realpath(parent))
else
- destdirs = File.dirname(d = dest)
+ destdirs ||= fu_split_path(dest)
+ real_ddirs ||= fu_split_path(File.realdirpath(dest))
end
- destdirs = fu_split_path(File.realpath(destdirs))
- if fu_starting_path?(s)
- srcdirs = fu_split_path((File.realdirpath(s) rescue File.expand_path(s)))
- base = fu_relative_components_from(srcdirs, destdirs)
- s = File.join(*base)
+ srcdirs = fu_split_path(s)
+ i = fu_common_components(srcdirs, destdirs)
+ n = destdirs.size - i
+ n -= 1 unless target_directory
+ link1 = fu_clean_components(*Array.new([n, 0].max, '..'), *srcdirs[i..-1])
+ begin
+ real_sdirs = fu_split_path(File.realdirpath(s)) rescue nil
+ rescue
else
- srcdirs = fu_clean_components(*fu_split_path(s))
- base = fu_relative_components_from(fu_split_path(Dir.pwd), destdirs)
- while srcdirs.first&. == ".." and base.last&.!=("..") and !fu_starting_path?(base.last)
- srcdirs.shift
- base.pop
- end
- s = File.join(*base, *srcdirs)
+ i = fu_common_components(real_sdirs, real_ddirs)
+ n = real_ddirs.size - i
+ n -= 1 unless target_directory
+ link2 = fu_clean_components(*Array.new([n, 0].max, '..'), *real_sdirs[i..-1])
+ link1 = link2 if link1.size > link2.size
end
- fu_output_message "ln -s#{options} #{s} #{d}" if verbose
+ s = File.join(link1)
+ fu_output_message [cmd, s, d].flatten.join(' ') if verbose
next if noop
remove_file d, true if force
File.symlink s, d
end
- case srcs.size
- when 0
- when 1
- link[srcs[0], target_directory && File.directory?(dest)]
- else
- srcs.each(&link)
- end
end
module_function :ln_sr
@@ -800,13 +796,13 @@ module Bundler::FileUtils
# File.file?('dest1/dir1/t2.txt') # => true
# File.file?('dest1/dir1/t3.txt') # => true
#
- # Keyword arguments:
+ # Optional arguments:
#
- # - <tt>dereference_root: true</tt> - dereferences +src+ if it is a symbolic link.
- # - <tt>remove_destination: true</tt> - removes +dest+ before creating links.
+ # - +dereference_root+ - dereferences +src+ if it is a symbolic link (+false+ by default).
+ # - +remove_destination+ - removes +dest+ before creating links (+false+ by default).
#
# Raises an exception if +dest+ is the path to an existing file or directory
- # and keyword argument <tt>remove_destination: true</tt> is not given.
+ # and optional argument +remove_destination+ is not given.
#
# Related: Bundler::FileUtils.ln (has different options).
#
@@ -1029,12 +1025,12 @@ module Bundler::FileUtils
# directories, and symbolic links;
# other file types (FIFO streams, device files, etc.) are not supported.
#
- # Keyword arguments:
+ # Optional arguments:
#
- # - <tt>dereference_root: true</tt> - if +src+ is a symbolic link,
- # follows the link.
- # - <tt>preserve: true</tt> - preserves file times.
- # - <tt>remove_destination: true</tt> - removes +dest+ before copying files.
+ # - +dereference_root+ - if +src+ is a symbolic link,
+ # follows the link (+false+ by default).
+ # - +preserve+ - preserves file times (+false+ by default).
+ # - +remove_destination+ - removes +dest+ before copying files (+false+ by default).
#
# Related: {methods for copying}[rdoc-ref:FileUtils@Copying].
#
@@ -1065,12 +1061,12 @@ module Bundler::FileUtils
# Bundler::FileUtils.copy_file('src0.txt', 'dest0.txt')
# File.file?('dest0.txt') # => true
#
- # Keyword arguments:
+ # Optional arguments:
#
- # - <tt>dereference: false</tt> - if +src+ is a symbolic link,
- # does not follow the link.
- # - <tt>preserve: true</tt> - preserves file times.
- # - <tt>remove_destination: true</tt> - removes +dest+ before copying files.
+ # - +dereference+ - if +src+ is a symbolic link,
+ # follows the link (+true+ by default).
+ # - +preserve+ - preserves file times (+false+ by default).
+ # - +remove_destination+ - removes +dest+ before copying files (+false+ by default).
#
# Related: {methods for copying}[rdoc-ref:FileUtils@Copying].
#
@@ -1491,7 +1487,8 @@ module Bundler::FileUtils
# Related: {methods for deleting}[rdoc-ref:FileUtils@Deleting].
#
def remove_dir(path, force = false)
- remove_entry path, force # FIXME?? check if it is a directory
+ raise Errno::ENOTDIR, path unless force or File.directory?(path)
+ remove_entry path, force
end
module_function :remove_dir
@@ -2475,6 +2472,10 @@ module Bundler::FileUtils
def fu_each_src_dest0(src, dest, target_directory = true) #:nodoc:
if tmp = Array.try_convert(src)
+ unless target_directory or tmp.size <= 1
+ tmp = tmp.map {|f| File.path(f)} # A workaround for RBS
+ raise ArgumentError, "extra target #{tmp}"
+ end
tmp.each do |s|
s = File.path(s)
yield s, (target_directory ? File.join(dest, File.basename(s)) : dest)
@@ -2509,7 +2510,11 @@ module Bundler::FileUtils
path = File.path(path)
list = []
until (parent, base = File.split(path); parent == path or parent == ".")
- list << base
+ if base != '..' and list.last == '..' and !(fu_have_symlink? && File.symlink?(path))
+ list.pop
+ else
+ list << base
+ end
path = parent
end
list << path
@@ -2517,14 +2522,14 @@ module Bundler::FileUtils
end
private_module_function :fu_split_path
- def fu_relative_components_from(target, base) #:nodoc:
+ def fu_common_components(target, base) #:nodoc:
i = 0
while target[i]&.== base[i]
i += 1
end
- Array.new(base.size-i, '..').concat(target[i..-1])
+ i
end
- private_module_function :fu_relative_components_from
+ private_module_function :fu_common_components
def fu_clean_components(*comp) #:nodoc:
comp.shift while comp.first == "."
@@ -2534,7 +2539,7 @@ module Bundler::FileUtils
while c = comp.shift
if c == ".." and clean.last != ".." and !(fu_have_symlink? && File.symlink?(path))
clean.pop
- path.chomp!(%r((?<=\A|/)[^/]+/\z), "")
+ path.sub!(%r((?<=\A|/)[^/]+/\z), "")
else
clean << c
path << c << "/"
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 03909a298b..93e403a5bb 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,7 +1,10 @@
require_relative '../../../../../vendored_net_http'
require_relative '../../../../../vendored_uri'
-require 'cgi/escape'
-require 'cgi/util' unless defined?(CGI::EscapeExt)
+begin
+ require 'cgi/escape'
+rescue LoadError
+ require 'cgi/util' # for escaping
+end
require_relative '../../../../connection_pool/lib/connection_pool'
autoload :OpenSSL, 'openssl'
diff --git a/lib/bundler/vendor/thor/lib/thor.rb b/lib/bundler/vendor/thor/lib/thor.rb
index bfd9f5c914..945bdbd551 100644
--- a/lib/bundler/vendor/thor/lib/thor.rb
+++ b/lib/bundler/vendor/thor/lib/thor.rb
@@ -625,7 +625,7 @@ class Bundler::Thor
# alias name.
def find_command_possibilities(meth)
len = meth.to_s.length
- possibilities = all_commands.merge(map).keys.select { |n| meth == n[0, len] }.sort
+ possibilities = all_commands.reject { |_k, c| c.hidden? }.merge(map).keys.select { |n| meth == n[0, len] }.sort
unique_possibilities = possibilities.map { |k| map[k] || k }.uniq
if possibilities.include?(meth)
diff --git a/lib/bundler/vendor/thor/lib/thor/runner.rb b/lib/bundler/vendor/thor/lib/thor/runner.rb
index 95f8b16e31..f0ce6df96c 100644
--- a/lib/bundler/vendor/thor/lib/thor/runner.rb
+++ b/lib/bundler/vendor/thor/lib/thor/runner.rb
@@ -2,7 +2,7 @@ require_relative "../thor"
require_relative "group"
require "digest/sha2"
-require "pathname"
+require "pathname" unless defined?(Pathname)
class Bundler::Thor::Runner < Bundler::Thor #:nodoc:
map "-T" => :list, "-i" => :install, "-u" => :update, "-v" => :version
diff --git a/lib/bundler/vendor/uri/lib/uri/common.rb b/lib/bundler/vendor/uri/lib/uri/common.rb
index 186da24fa8..38339119c5 100644
--- a/lib/bundler/vendor/uri/lib/uri/common.rb
+++ b/lib/bundler/vendor/uri/lib/uri/common.rb
@@ -30,6 +30,9 @@ module Bundler::URI
remove_const(:Parser) if defined?(::Bundler::URI::Parser)
const_set("Parser", parser.class)
+ remove_const(:PARSER) if defined?(::Bundler::URI::PARSER)
+ const_set("PARSER", parser)
+
remove_const(:REGEXP) if defined?(::Bundler::URI::REGEXP)
remove_const(:PATTERN) if defined?(::Bundler::URI::PATTERN)
if Parser == RFC2396_Parser
@@ -49,10 +52,10 @@ module Bundler::URI
warn "Bundler::URI::REGEXP is obsolete. Use Bundler::URI::RFC2396_REGEXP explicitly.", uplevel: 1 if $VERBOSE
Bundler::URI::RFC2396_REGEXP
elsif value = RFC2396_PARSER.regexp[const]
- warn "Bundler::URI::#{const} is obsolete. Use RFC2396_PARSER.regexp[#{const.inspect}] explicitly.", uplevel: 1 if $VERBOSE
+ warn "Bundler::URI::#{const} is obsolete. Use Bundler::URI::RFC2396_PARSER.regexp[#{const.inspect}] explicitly.", uplevel: 1 if $VERBOSE
value
elsif value = RFC2396_Parser.const_get(const)
- warn "Bundler::URI::#{const} is obsolete. Use RFC2396_Parser::#{const} explicitly.", uplevel: 1 if $VERBOSE
+ warn "Bundler::URI::#{const} is obsolete. Use Bundler::URI::RFC2396_Parser::#{const} explicitly.", uplevel: 1 if $VERBOSE
value
else
super
@@ -92,6 +95,40 @@ module Bundler::URI
end
module Schemes # :nodoc:
+ class << self
+ ReservedChars = ".+-"
+ EscapedChars = "\u01C0\u01C1\u01C2"
+ # Use Lo category chars as escaped chars for TruffleRuby, which
+ # does not allow Symbol categories as identifiers.
+
+ def escape(name)
+ unless name and name.ascii_only?
+ return nil
+ end
+ name.upcase.tr(ReservedChars, EscapedChars)
+ end
+
+ def unescape(name)
+ name.tr(EscapedChars, ReservedChars).encode(Encoding::US_ASCII).upcase
+ end
+
+ def find(name)
+ const_get(name, false) if name and const_defined?(name, false)
+ end
+
+ def register(name, klass)
+ unless scheme = escape(name)
+ raise ArgumentError, "invalid character as scheme - #{name}"
+ end
+ const_set(scheme, klass)
+ end
+
+ def list
+ constants.map { |name|
+ [unescape(name.to_s), const_get(name)]
+ }.to_h
+ end
+ end
end
private_constant :Schemes
@@ -104,7 +141,7 @@ module Bundler::URI
# 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)
+ Schemes.register(scheme, klass)
end
# Returns a hash of the defined schemes:
@@ -122,14 +159,14 @@ module Bundler::URI
#
# Related: Bundler::URI.register_scheme.
def self.scheme_list
- Schemes.constants.map { |name|
- [name.to_s.upcase, Schemes.const_get(name)]
- }.to_h
+ Schemes.list
end
+ # :stopdoc:
INITIAL_SCHEMES = scheme_list
private_constant :INITIAL_SCHEMES
Ractor.make_shareable(INITIAL_SCHEMES) if defined?(Ractor)
+ # :startdoc:
# Returns a new object constructed from the given +scheme+, +arguments+,
# and +default+:
@@ -148,12 +185,10 @@ module Bundler::URI
# # => #<Bundler::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
+ const_name = Schemes.escape(scheme)
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 ||= Schemes.find(const_name)
uri_class ||= default
return uri_class.new(scheme, *arguments)
@@ -195,7 +230,7 @@ module Bundler::URI
# ["fragment", "top"]]
#
def self.split(uri)
- DEFAULT_PARSER.split(uri)
+ PARSER.split(uri)
end
# Returns a new \Bundler::URI object constructed from the given string +uri+:
@@ -205,11 +240,11 @@ module Bundler::URI
# 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>
#
- # It's recommended to first ::escape string +uri+
+ # It's recommended to first Bundler::URI::RFC2396_PARSER.escape string +uri+
# if it may contain invalid Bundler::URI characters.
#
def self.parse(uri)
- DEFAULT_PARSER.parse(uri)
+ PARSER.parse(uri)
end
# Merges the given Bundler::URI strings +str+
@@ -265,7 +300,7 @@ module Bundler::URI
#
def self.extract(str, schemes = nil, &block) # :nodoc:
warn "Bundler::URI.extract is obsolete", uplevel: 1 if $VERBOSE
- DEFAULT_PARSER.extract(str, schemes, &block)
+ PARSER.extract(str, schemes, &block)
end
#
@@ -302,7 +337,7 @@ module Bundler::URI
#
def self.regexp(schemes = nil)# :nodoc:
warn "Bundler::URI.regexp is obsolete", uplevel: 1 if $VERBOSE
- DEFAULT_PARSER.make_regexp(schemes)
+ PARSER.make_regexp(schemes)
end
TBLENCWWWCOMP_ = {} # :nodoc:
@@ -407,6 +442,8 @@ module Bundler::URI
_decode_uri_component(/%\h\h/, str, enc)
end
+ # Returns a string derived from the given string +str+ with
+ # Bundler::URI-encoded characters matching +regexp+ according to +table+.
def self._encode_uri_component(regexp, table, str, enc)
str = str.to_s.dup
if str.encoding != Encoding::ASCII_8BIT
@@ -421,6 +458,8 @@ module Bundler::URI
end
private_class_method :_encode_uri_component
+ # Returns a string decoding characters matching +regexp+ from the
+ # given \URL-encoded string +str+.
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)
@@ -859,6 +898,7 @@ 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:
#
+ # require 'bundler/vendor/uri/lib/uri'
# # Returns a new Bundler::URI.
# uri = Bundler::URI('http://github.com/ruby/ruby')
# # => #<Bundler::URI::HTTP http://github.com/ruby/ruby>
@@ -866,6 +906,8 @@ module Bundler
# Bundler::URI(uri)
# # => #<Bundler::URI::HTTP http://github.com/ruby/ruby>
#
+ # You must require 'bundler/vendor/uri/lib/uri' to use this method.
+ #
def URI(uri)
if uri.is_a?(Bundler::URI::Generic)
uri
diff --git a/lib/bundler/vendor/uri/lib/uri/file.rb b/lib/bundler/vendor/uri/lib/uri/file.rb
index de347af6eb..21dd9ee535 100644
--- a/lib/bundler/vendor/uri/lib/uri/file.rb
+++ b/lib/bundler/vendor/uri/lib/uri/file.rb
@@ -47,7 +47,7 @@ module Bundler::URI
# :path => '/ruby/src'})
# uri2.to_s # => "file://host.example.com/ruby/src"
#
- # uri3 = Bundler::URI::File.build({:path => Bundler::URI::escape('/path/my file.txt')})
+ # uri3 = Bundler::URI::File.build({:path => Bundler::URI::RFC2396_PARSER.escape('/path/my file.txt')})
# uri3.to_s # => "file:///path/my%20file.txt"
#
def self.build(args)
diff --git a/lib/bundler/vendor/uri/lib/uri/generic.rb b/lib/bundler/vendor/uri/lib/uri/generic.rb
index 6abb171d14..30dab60903 100644
--- a/lib/bundler/vendor/uri/lib/uri/generic.rb
+++ b/lib/bundler/vendor/uri/lib/uri/generic.rb
@@ -73,7 +73,7 @@ module Bundler::URI
#
# At first, tries to create a new Bundler::URI::Generic instance using
# Bundler::URI::Generic::build. But, if exception Bundler::URI::InvalidComponentError is raised,
- # then it does Bundler::URI::Escape.escape all Bundler::URI components and tries again.
+ # then it does Bundler::URI::RFC2396_PARSER.escape all Bundler::URI components and tries again.
#
def self.build2(args)
begin
@@ -126,9 +126,9 @@ module Bundler::URI
end
end
else
- component = self.class.component rescue ::Bundler::URI::Generic::COMPONENT
+ component = self.component rescue ::Bundler::URI::Generic::COMPONENT
raise ArgumentError,
- "expected Array of or Hash of components of #{self.class} (#{component.join(', ')})"
+ "expected Array of or Hash of components of #{self} (#{component.join(', ')})"
end
tmp << nil
@@ -186,18 +186,18 @@ module Bundler::URI
if arg_check
self.scheme = scheme
- self.userinfo = userinfo
self.hostname = host
self.port = port
+ self.userinfo = userinfo
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_userinfo(userinfo)
self.set_path(path)
self.query = query
self.set_opaque(opaque)
@@ -284,7 +284,7 @@ module Bundler::URI
# Returns the parser to be used.
#
- # Unless a Bundler::URI::Parser is defined, DEFAULT_PARSER is used.
+ # Unless the +parser+ is defined, DEFAULT_PARSER is used.
#
def parser
if !defined?(@parser) || !@parser
@@ -315,7 +315,7 @@ module Bundler::URI
end
#
- # Checks the scheme +v+ component against the Bundler::URI::Parser Regexp for :SCHEME.
+ # Checks the scheme +v+ component against the +parser+ Regexp for :SCHEME.
#
def check_scheme(v)
if v && parser.regexp[:SCHEME] !~ v
@@ -385,7 +385,7 @@ module Bundler::URI
#
# Checks the user +v+ component for RFC2396 compliance
- # and against the Bundler::URI::Parser Regexp for :USERINFO.
+ # and against the +parser+ Regexp for :USERINFO.
#
# Can not have a registry or opaque component defined,
# with a user component defined.
@@ -409,7 +409,7 @@ module Bundler::URI
#
# Checks the password +v+ component for RFC2396 compliance
- # and against the Bundler::URI::Parser Regexp for :USERINFO.
+ # and against the +parser+ Regexp for :USERINFO.
#
# Can not have a registry or opaque component defined,
# with a user component defined.
@@ -511,7 +511,7 @@ module Bundler::URI
user, password = split_userinfo(user)
end
@user = user
- @password = password if password
+ @password = password
[@user, @password]
end
@@ -522,7 +522,7 @@ module Bundler::URI
# See also Bundler::URI::Generic.user=.
#
def set_user(v)
- set_userinfo(v, @password)
+ set_userinfo(v, nil)
v
end
protected :set_user
@@ -574,6 +574,12 @@ module Bundler::URI
@password
end
+ # Returns the authority info (array of user, password, host and
+ # port), if any is set. Or returns +nil+.
+ def authority
+ return @user, @password, @host, @port if @user || @password || @host || @port
+ end
+
# Returns the user component after Bundler::URI decoding.
def decoded_user
Bundler::URI.decode_uri_component(@user) if @user
@@ -586,7 +592,7 @@ module Bundler::URI
#
# Checks the host +v+ component for RFC2396 compliance
- # and against the Bundler::URI::Parser Regexp for :HOST.
+ # and against the +parser+ Regexp for :HOST.
#
# Can not have a registry or opaque component defined,
# with a host component defined.
@@ -615,6 +621,13 @@ module Bundler::URI
end
protected :set_host
+ # Protected setter for the authority info (+user+, +password+, +host+
+ # and +port+). If +port+ is +nil+, +default_port+ will be set.
+ #
+ protected def set_authority(user, password, host, port = nil)
+ @user, @password, @host, @port = user, password, host, port || self.default_port
+ end
+
#
# == Args
#
@@ -639,6 +652,7 @@ module Bundler::URI
def host=(v)
check_host(v)
set_host(v)
+ set_userinfo(nil)
v
end
@@ -675,7 +689,7 @@ module Bundler::URI
#
# Checks the port +v+ component for RFC2396 compliance
- # and against the Bundler::URI::Parser Regexp for :PORT.
+ # and against the +parser+ Regexp for :PORT.
#
# Can not have a registry or opaque component defined,
# with a port component defined.
@@ -729,6 +743,7 @@ module Bundler::URI
def port=(v)
check_port(v)
set_port(v)
+ set_userinfo(nil)
port
end
@@ -748,7 +763,7 @@ module Bundler::URI
#
# Checks the path +v+ component for RFC2396 compliance
- # and against the Bundler::URI::Parser Regexp
+ # and against the +parser+ Regexp
# for :ABS_PATH and :REL_PATH.
#
# Can not have a opaque component defined,
@@ -853,7 +868,7 @@ module Bundler::URI
#
# Checks the opaque +v+ component for RFC2396 compliance and
- # against the Bundler::URI::Parser Regexp for :OPAQUE.
+ # against the +parser+ Regexp for :OPAQUE.
#
# Can not have a host, port, user, or path component defined,
# with an opaque component defined.
@@ -905,7 +920,7 @@ module Bundler::URI
end
#
- # Checks the fragment +v+ component against the Bundler::URI::Parser Regexp for :FRAGMENT.
+ # Checks the fragment +v+ component against the +parser+ Regexp for :FRAGMENT.
#
#
# == Args
@@ -1121,7 +1136,7 @@ module Bundler::URI
base = self.dup
- authority = rel.userinfo || rel.host || rel.port
+ authority = rel.authority
# RFC2396, Section 5.2, 2)
if (rel.path.nil? || rel.path.empty?) && !authority && !rel.query
@@ -1134,9 +1149,7 @@ module Bundler::URI
# RFC2396, Section 5.2, 4)
if authority
- base.set_userinfo(rel.userinfo)
- base.set_host(rel.host)
- base.set_port(rel.port || base.default_port)
+ base.set_authority(*authority)
base.set_path(rel.path)
elsif base.path && rel.path
base.set_path(merge_path(base.path, rel.path))
@@ -1527,7 +1540,7 @@ module Bundler::URI
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
+ warn 'The environment variable HTTP_PROXY is discouraged. Please use http_proxy instead.', uplevel: 1
end
end
end
diff --git a/lib/bundler/vendor/uri/lib/uri/http.rb b/lib/bundler/vendor/uri/lib/uri/http.rb
index 6c34a469b7..9b217ee266 100644
--- a/lib/bundler/vendor/uri/lib/uri/http.rb
+++ b/lib/bundler/vendor/uri/lib/uri/http.rb
@@ -61,6 +61,18 @@ module Bundler::URI
super(tmp)
end
+ # Do not allow empty host names, as they are not allowed by RFC 3986.
+ def check_host(v)
+ ret = super
+
+ if ret && v.empty?
+ raise InvalidComponentError,
+ "bad component(expected host component): #{v}"
+ end
+
+ ret
+ end
+
#
# == Description
#
diff --git a/lib/bundler/vendor/uri/lib/uri/rfc2396_parser.rb b/lib/bundler/vendor/uri/lib/uri/rfc2396_parser.rb
index 229971f73c..522113fe67 100644
--- a/lib/bundler/vendor/uri/lib/uri/rfc2396_parser.rb
+++ b/lib/bundler/vendor/uri/lib/uri/rfc2396_parser.rb
@@ -67,7 +67,7 @@ module Bundler::URI
#
# == Synopsis
#
- # Bundler::URI::Parser.new([opts])
+ # Bundler::URI::RFC2396_Parser.new([opts])
#
# == Args
#
@@ -86,7 +86,7 @@ module Bundler::URI
#
# == Examples
#
- # p = Bundler::URI::Parser.new(:ESCAPED => "(?:%[a-fA-F0-9]{2}|%u[a-fA-F0-9]{4})")
+ # p = Bundler::URI::RFC2396_Parser.new(:ESCAPED => "(?:%[a-fA-F0-9]{2}|%u[a-fA-F0-9]{4})")
# u = p.parse("http://example.jp/%uABCD") #=> #<Bundler::URI::HTTP http://example.jp/%uABCD>
# Bundler::URI.parse(u.to_s) #=> raises Bundler::URI::InvalidURIError
#
@@ -108,12 +108,12 @@ module Bundler::URI
# The Hash of patterns.
#
- # See also Bundler::URI::Parser.initialize_pattern.
+ # See also #initialize_pattern.
attr_reader :pattern
# The Hash of Regexp.
#
- # See also Bundler::URI::Parser.initialize_regexp.
+ # See also #initialize_regexp.
attr_reader :regexp
# Returns a split Bundler::URI against +regexp[:ABS_URI]+.
@@ -202,8 +202,7 @@ module Bundler::URI
#
# == Usage
#
- # p = Bundler::URI::Parser.new
- # p.parse("ldap://ldap.example.com/dc=example?user=john")
+ # Bundler::URI::RFC2396_PARSER.parse("ldap://ldap.example.com/dc=example?user=john")
# #=> #<Bundler::URI::LDAP ldap://ldap.example.com/dc=example?user=john>
#
def parse(uri)
@@ -244,7 +243,7 @@ module Bundler::URI
# If no +block+ given, then returns the result,
# else it calls +block+ for each element in result.
#
- # See also Bundler::URI::Parser.make_regexp.
+ # See also #make_regexp.
#
def extract(str, schemes = nil)
if block_given?
@@ -263,7 +262,7 @@ module Bundler::URI
unless schemes
@regexp[:ABS_URI_REF]
else
- /(?=#{Regexp.union(*schemes)}:)#{@pattern[:X_ABS_URI]}/x
+ /(?=(?i:#{Regexp.union(*schemes).source}):)#{@pattern[:X_ABS_URI]}/x
end
end
@@ -524,6 +523,8 @@ module Bundler::URI
ret
end
+ # Returns +uri+ as-is if it is Bundler::URI, or convert it to Bundler::URI if it is
+ # a String.
def convert_to_uri(uri)
if uri.is_a?(Bundler::URI::Generic)
uri
diff --git a/lib/bundler/vendor/uri/lib/uri/version.rb b/lib/bundler/vendor/uri/lib/uri/version.rb
index d4996a12e2..ad76308e81 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 = '010003'.freeze
- VERSION = VERSION_CODE.scan(/../).collect{|n| n.to_i}.join('.').freeze
+ VERSION = '1.1.1'.freeze
+ VERSION_CODE = VERSION.split('.').map{|s| s.rjust(2, '0')}.join.freeze
# :startdoc:
end
diff --git a/lib/bundler/version.rb b/lib/bundler/version.rb
index 5a55b23ac1..ca7bb0719a 100644
--- a/lib/bundler/version.rb
+++ b/lib/bundler/version.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: false
module Bundler
- VERSION = "2.8.0.dev".freeze
+ VERSION = "4.1.0.dev".freeze
def self.bundler_major_version
@bundler_major_version ||= gem_version.segments.first
diff --git a/lib/bundler/vlad.rb b/lib/bundler/vlad.rb
index 6179d0e4eb..c3a3d949a6 100644
--- a/lib/bundler/vlad.rb
+++ b/lib/bundler/vlad.rb
@@ -1,17 +1,4 @@
# frozen_string_literal: true
require_relative "shared_helpers"
-Bundler::SharedHelpers.major_deprecation 2,
- "The Bundler task for Vlad"
-
-# Vlad task for Bundler.
-#
-# Add "require 'bundler/vlad'" in your Vlad deploy.rb, and
-# include the vlad:bundle:install task in your vlad:deploy task.
-require_relative "deployment"
-
-include Rake::DSL if defined? Rake::DSL
-
-namespace :vlad do
- Bundler::Deployment.define_task(Rake::RemoteTask, :remote_task, roles: :app)
-end
+Bundler::SharedHelpers.feature_removed! "The Bundler task for Vlad"
diff --git a/lib/bundler/worker.rb b/lib/bundler/worker.rb
index 7137484cc6..77f4f004aa 100644
--- a/lib/bundler/worker.rb
+++ b/lib/bundler/worker.rb
@@ -22,6 +22,7 @@ module Bundler
def initialize(size, name, func)
@name = name
@request_queue = Thread::Queue.new
+ @request_queue_with_priority = Thread::Queue.new
@response_queue = Thread::Queue.new
@func = func
@size = size
@@ -32,9 +33,10 @@ module Bundler
# Enqueue a request to be executed in the worker pool
#
# @param obj [String] mostly it is name of spec that should be downloaded
- def enq(obj)
+ def enq(obj, priority: false)
+ queue = priority ? @request_queue_with_priority : @request_queue
create_threads unless @threads
- @request_queue.enq obj
+ queue.enq obj
end
# Retrieves results of job function being executed in worker pool
@@ -52,7 +54,13 @@ module Bundler
def process_queue(i)
loop do
- obj = @request_queue.deq
+ obj = begin
+ @request_queue_with_priority.deq(true)
+ rescue ThreadError
+ @request_queue.deq(false, timeout: 0.05)
+ end
+
+ next if obj.nil?
break if obj.equal? POISON
@response_queue.enq apply_func(obj, i)
end
diff --git a/lib/cgi.rb b/lib/cgi.rb
index b041c1bed1..0c403bd19c 100644
--- a/lib/cgi.rb
+++ b/lib/cgi.rb
@@ -2,6 +2,8 @@
require "cgi/escape"
warn <<-WARNING, uplevel: Gem::BUNDLED_GEMS.uplevel if $VERBOSE
-CGI library is removed from Ruby 3.5. Please use cgi/escape instead for CGI.escape and CGI.unescape features.
-If you need to use the full features of CGI library, Please install cgi gem.
+CGI library is removed from Ruby 4.0. Please use cgi/escape instead for CGI.escape and CGI.unescape features.
+
+If you need to use the full features of CGI library, please add 'gem "cgi"' to your script
+or use Bundler to ensure you are using the cgi gem instead of this file.
WARNING
diff --git a/lib/cgi/escape.rb b/lib/cgi/escape.rb
index 59a310b32d..555d24a5da 100644
--- a/lib/cgi/escape.rb
+++ b/lib/cgi/escape.rb
@@ -1,16 +1,28 @@
# frozen_string_literal: true
+# Since Ruby 4.0, \CGI is a small holder for various escaping methods, included from CGI::Escape
+#
+# require 'cgi/escape'
+#
+# CGI.escape("Ruby programming language")
+# #=> "Ruby+programming+language"
+# CGI.escapeURIComponent("Ruby programming language")
+# #=> "Ruby%20programming%20language"
+#
+# See CGI::Escape module for methods list and their description.
class CGI
module Escape; end
include Escape
extend Escape
+ module EscapeExt; end # :nodoc:
end
+# Web-related escape/unescape functionality.
module CGI::Escape
@@accept_charset = Encoding::UTF_8 unless defined?(@@accept_charset)
# URL-encode a string into application/x-www-form-urlencoded.
- # Space characters (+" "+) are encoded with plus signs (+"+"+)
+ # Space characters (<tt>" "</tt>) are encoded with plus signs (<tt>"+"</tt>)
# url_encoded_string = CGI.escape("'Stop!' said Fred")
# # => "%27Stop%21%27+said+Fred"
def escape(string)
@@ -37,7 +49,7 @@ module CGI::Escape
end
# URL-encode a string following RFC 3986
- # Space characters (+" "+) are encoded with (+"%20"+)
+ # Space characters (<tt>" "</tt>) are encoded with (<tt>"%20"</tt>)
# url_encoded_string = CGI.escapeURIComponent("'Stop!' said Fred")
# # => "%27Stop%21%27%20said%20Fred"
def escapeURIComponent(string)
@@ -65,7 +77,7 @@ module CGI::Escape
alias unescape_uri_component unescapeURIComponent
# The set of special characters and their escaped values
- TABLE_FOR_ESCAPE_HTML__ = {
+ TABLE_FOR_ESCAPE_HTML__ = { # :nodoc:
"'" => '&#39;',
'&' => '&amp;',
'"' => '&quot;',
@@ -73,7 +85,7 @@ module CGI::Escape
'>' => '&gt;',
}
- # Escape special characters in HTML, namely '&\"<>
+ # \Escape special characters in HTML, namely <tt>'&\"<></tt>
# CGI.escapeHTML('Usage: foo "bar" <baz>')
# # => "Usage: foo &quot;bar&quot; &lt;baz&gt;"
def escapeHTML(string)
@@ -156,11 +168,9 @@ module CGI::Escape
string.force_encoding enc
end
- # Synonym for CGI.escapeHTML(str)
alias escape_html escapeHTML
alias h escapeHTML
- # Synonym for CGI.unescapeHTML(str)
alias unescape_html unescapeHTML
# TruffleRuby runs the pure-Ruby variant faster, do not use the C extension there
@@ -171,7 +181,7 @@ module CGI::Escape
end
end
- # Escape only the tags of certain HTML elements in +string+.
+ # \Escape only the tags of certain HTML elements in +string+.
#
# Takes an element or elements or array of elements. Each element
# is specified by the name of the element, without angle brackets.
@@ -195,7 +205,7 @@ module CGI::Escape
end
end
- # Undo escaping such as that done by CGI.escapeElement()
+ # Undo escaping such as that done by CGI.escapeElement
#
# print CGI.unescapeElement(
# CGI.escapeHTML('<BR><A HREF="url"></A>'), "A", "IMG")
@@ -215,10 +225,8 @@ module CGI::Escape
end
end
- # Synonym for CGI.escapeElement(str)
alias escape_element escapeElement
- # Synonym for CGI.unescapeElement(str)
alias unescape_element unescapeElement
end
diff --git a/lib/cgi/util.rb b/lib/cgi/util.rb
index 389a04acd2..50a2e91665 100644
--- a/lib/cgi/util.rb
+++ b/lib/cgi/util.rb
@@ -2,6 +2,6 @@
require "cgi/escape"
warn <<-WARNING, uplevel: Gem::BUNDLED_GEMS.uplevel if $VERBOSE
-CGI::Util is removed from Ruby 3.5. Please use cgi/escape instead for CGI.escape and CGI.unescape features.
+CGI::Util is removed from Ruby 4.0. Please use cgi/escape instead for CGI.escape and CGI.unescape features.
If you are using CGI.parse, please install and use the cgi gem instead.
WARNING
diff --git a/lib/delegate.rb b/lib/delegate.rb
index 824d02f28b..0ff9797bdb 100644
--- a/lib/delegate.rb
+++ b/lib/delegate.rb
@@ -39,7 +39,8 @@
# Be advised, RDoc will not detect delegated methods.
#
class Delegator < BasicObject
- VERSION = "0.4.0"
+ # The version string
+ VERSION = "0.6.1"
kernel = ::Kernel.dup
kernel.class_eval do
@@ -77,7 +78,7 @@ class Delegator < BasicObject
end
#
- # Handles the magic of delegation through \_\_getobj\_\_.
+ # Handles the magic of delegation through +__getobj__+.
#
ruby2_keywords def method_missing(m, *args, &block)
r = true
@@ -94,7 +95,7 @@ class Delegator < BasicObject
#
# Checks for a method provided by this the delegate object by forwarding the
- # call through \_\_getobj\_\_.
+ # call through +__getobj__+.
#
def respond_to_missing?(m, include_private)
r = true
@@ -107,7 +108,7 @@ class Delegator < BasicObject
r
end
- KERNEL_RESPOND_TO = ::Kernel.instance_method(:respond_to?)
+ KERNEL_RESPOND_TO = ::Kernel.instance_method(:respond_to?) # :nodoc:
private_constant :KERNEL_RESPOND_TO
# Handle BasicObject instances
@@ -126,7 +127,7 @@ class Delegator < BasicObject
#
# Returns the methods available to this delegate object as the union
- # of this object's and \_\_getobj\_\_ methods.
+ # of this object's and +__getobj__+ methods.
#
def methods(all=true)
__getobj__.methods(all) | super
@@ -134,7 +135,7 @@ class Delegator < BasicObject
#
# Returns the methods available to this delegate object as the union
- # of this object's and \_\_getobj\_\_ public methods.
+ # of this object's and +__getobj__+ public methods.
#
def public_methods(all=true)
__getobj__.public_methods(all) | super
@@ -142,7 +143,7 @@ class Delegator < BasicObject
#
# Returns the methods available to this delegate object as the union
- # of this object's and \_\_getobj\_\_ protected methods.
+ # of this object's and +__getobj__+ protected methods.
#
def protected_methods(all=true)
__getobj__.protected_methods(all) | super
@@ -175,7 +176,7 @@ class Delegator < BasicObject
end
#
- # Delegates ! to the \_\_getobj\_\_
+ # Delegates ! to the +__getobj__+
#
def !
!__getobj__
@@ -198,7 +199,7 @@ class Delegator < BasicObject
end
#
- # Serialization support for the object returned by \_\_getobj\_\_.
+ # Serialization support for the object returned by +__getobj__+.
#
def marshal_dump
ivars = instance_variables.reject {|var| /\A@delegate_/ =~ var}
@@ -232,7 +233,7 @@ class Delegator < BasicObject
##
# :method: freeze
- # Freeze both the object returned by \_\_getobj\_\_ and self.
+ # Freeze both the object returned by +__getobj__+ and self.
#
def freeze
__getobj__.freeze
@@ -343,13 +344,6 @@ class SimpleDelegator < Delegator
end
end
-def Delegator.delegating_block(mid) # :nodoc:
- lambda do |*args, &block|
- target = self.__getobj__
- target.__send__(mid, *args, &block)
- end.ruby2_keywords
-end
-
#
# The primary interface to this library. Use to setup delegation when defining
# your class.
@@ -398,6 +392,32 @@ def DelegateClass(superclass, &block)
protected_instance_methods -= ignores
public_instance_methods = superclass.public_instance_methods
public_instance_methods -= ignores
+
+ methods_to_define =
+ public_instance_methods.map { |x| [x, false] } +
+ protected_instance_methods.map { |x| [x, true] }
+
+ source = []
+
+ methods_to_define.each do |target_name, is_protected|
+ unless target_name.match?(/\A[_a-zA-Z]\w*[!\?]?\z/)
+ placeholder_name = :__delegate
+ end
+
+ send_source =
+ if is_protected || placeholder_name
+ "__getobj__.__send__(#{target_name.inspect}, ...)"
+ else
+ "__getobj__.#{target_name}(...)"
+ end
+ source << "def #{placeholder_name || target_name}(...); #{send_source}; end"
+
+ if placeholder_name
+ source << "alias_method #{target_name.inspect}, :#{placeholder_name}"
+ source << "remove_method :#{placeholder_name}"
+ end
+ end
+
klass.module_eval do
def __getobj__ # :nodoc:
unless defined?(@delegate_dc_obj)
@@ -406,18 +426,17 @@ def DelegateClass(superclass, &block)
end
@delegate_dc_obj
end
+
def __setobj__(obj) # :nodoc:
__raise__ ::ArgumentError, "cannot delegate to self" if self.equal?(obj)
@delegate_dc_obj = obj
end
- protected_instance_methods.each do |method|
- define_method(method, Delegator.delegating_block(method))
- protected method
- end
- public_instance_methods.each do |method|
- define_method(method, Delegator.delegating_block(method))
- end
+
+ class_eval(source.join(";"), __FILE__, __LINE__)
+
+ protected(*protected_instance_methods)
end
+
klass.define_singleton_method :public_instance_methods do |all=true|
super(all) | superclass.public_instance_methods
end
diff --git a/lib/did_you_mean.rb b/lib/did_you_mean.rb
index 74cd176042..640d910389 100644
--- a/lib/did_you_mean.rb
+++ b/lib/did_you_mean.rb
@@ -47,9 +47,9 @@ require_relative 'did_you_mean/tree_spell_checker'
# # Did you mean? :foo
#
#
-# == Disabling +did_you_mean+
+# == Disabling \DidYouMean
#
-# Occasionally, you may want to disable the +did_you_mean+ gem for e.g.
+# Occasionally, you may want to disable the \DidYouMean gem for e.g.
# debugging issues in the error object itself. You can disable it entirely by
# specifying +--disable-did_you_mean+ option to the +ruby+ command:
#
diff --git a/lib/erb.rb b/lib/erb.rb
index ebf91e4792..bde90de841 100644
--- a/lib/erb.rb
+++ b/lib/erb.rb
@@ -12,394 +12,963 @@
#
# You can redistribute it and/or modify it under the same terms as Ruby.
+# A NOTE ABOUT TERMS:
+#
+# Formerly: The documentation in this file used the term _template_ to refer to an ERB object.
+#
+# Now: The documentation in this file uses the term _template_
+# to refer to the string input to ERB.new.
+#
+# The reason for the change: When documenting the ERB executable erb,
+# we need a term that refers to its string input;
+# _source_ is not a good idea, because ERB#src means something entirely different;
+# the two different sorts of sources would bring confusion.
+#
+# Therefore we use the term _template_ to refer to:
+#
+# - The string input to ERB.new
+# - The string input to executable erb.
+#
+
require 'erb/version'
require 'erb/compiler'
require 'erb/def_method'
require 'erb/util'
+# :markup: markdown
#
-# = ERB -- Ruby Templating
+# Class **ERB** (the name stands for **Embedded Ruby**)
+# is an easy-to-use, but also very powerful, [template processor][template processor].
#
-# == Introduction
+# ## Usage
#
-# ERB provides an easy to use but powerful templating system for Ruby. Using
-# ERB, actual Ruby code can be added to any plain text document for the
-# purposes of generating document information details and/or flow control.
+# Before you can use \ERB, you must first require it
+# (examples on this page assume that this has been done):
#
-# A very simple example is this:
+# ```
+# require 'erb'
+# ```
#
-# require 'erb'
+# ## In Brief
#
-# x = 42
-# template = ERB.new <<-EOF
-# The value of x is: <%= x %>
-# EOF
-# puts template.result(binding)
+# Here's how \ERB works:
#
-# <em>Prints:</em> The value of x is: 42
+# - You can create a *template*: a plain-text string that includes specially formatted *tags*..
+# - You can create an \ERB object to store the template.
+# - You can call instance method ERB#result to get the *result*.
#
-# More complex examples are given below.
+# \ERB supports tags of three kinds:
#
+# - [Expression tags][expression tags]:
+# each begins with `'<%='`, ends with `'%>'`; contains a Ruby expression;
+# in the result, the value of the expression replaces the entire tag:
#
-# == Recognized Tags
+# template = 'The magic word is <%= magic_word %>.'
+# erb = ERB.new(template)
+# magic_word = 'xyzzy'
+# erb.result(binding) # => "The magic word is xyzzy."
#
-# ERB recognizes certain tags in the provided template and converts them based
-# on the rules below:
+# The above call to #result passes argument `binding`,
+# which contains the binding of variable `magic_word` to its string value `'xyzzy'`.
#
-# <% Ruby code -- inline with output %>
-# <%= Ruby expression -- replace with result %>
-# <%# comment -- ignored -- useful in testing %> (`<% #` doesn't work. Don't use Ruby comments.)
-# % a line of Ruby code -- treated as <% line %> (optional -- see ERB.new)
-# %% replaced with % if first thing on a line and % processing is used
-# <%% or %%> -- replace with <% or %> respectively
+# The below call to #result need not pass a binding,
+# because its expression `Date::DAYNAMES` is globally defined.
#
-# All other text is passed through ERB filtering unchanged.
+# ERB.new('Today is <%= Date::DAYNAMES[Date.today.wday] %>.').result # => "Today is Monday."
#
+# - [Execution tags][execution tags]:
+# each begins with `'<%'`, ends with `'%>'`; contains Ruby code to be executed:
#
-# == Options
+# template = '<% File.write("t.txt", "Some stuff.") %>'
+# ERB.new(template).result
+# File.read('t.txt') # => "Some stuff."
#
-# There are several settings you can change when you use ERB:
-# * the nature of the tags that are recognized;
-# * the binding used to resolve local variables in the template.
+# - [Comment tags][comment tags]:
+# each begins with `'<%#'`, ends with `'%>'`; contains comment text;
+# in the result, the entire tag is omitted.
#
-# See the ERB.new and ERB#result methods for more detail.
+# template = 'Some stuff;<%# Note to self: figure out what the stuff is. %> more stuff.'
+# ERB.new(template).result # => "Some stuff; more stuff."
#
-# == Character encodings
+# ## Some Simple Examples
#
-# ERB (or Ruby code generated by ERB) returns a string in the same
-# character encoding as the input string. When the input string has
-# a magic comment, however, it returns a string in the encoding specified
-# by the magic comment.
+# Here's a simple example of \ERB in action:
#
-# # -*- coding: utf-8 -*-
-# require 'erb'
+# ```
+# template = 'The time is <%= Time.now %>.'
+# erb = ERB.new(template)
+# erb.result
+# # => "The time is 2025-09-09 10:49:26 -0500."
+# ```
#
-# template = ERB.new <<EOF
-# <%#-*- coding: Big5 -*-%>
-# \_\_ENCODING\_\_ is <%= \_\_ENCODING\_\_ %>.
-# EOF
-# puts template.result
+# Details:
#
-# <em>Prints:</em> \_\_ENCODING\_\_ is Big5.
+# 1. A plain-text string is assigned to variable `template`.
+# Its embedded [expression tag][expression tags] `'<%= Time.now %>'` includes a Ruby expression, `Time.now`.
+# 2. The string is put into a new \ERB object, and stored in variable `erb`.
+# 4. Method call `erb.result` generates a string that contains the run-time value of `Time.now`,
+# as computed at the time of the call.
#
+# The
+# \ERB object may be re-used:
#
-# == Examples
+# ```
+# erb.result
+# # => "The time is 2025-09-09 10:49:33 -0500."
+# ```
#
-# === Plain Text
+# Another example:
#
-# ERB is useful for any generic templating situation. Note that in this example, we use the
-# convenient "% at start of line" tag, and we quote the template literally with
-# <tt>%q{...}</tt> to avoid trouble with the backslash.
+# ```
+# template = 'The magic word is <%= magic_word %>.'
+# erb = ERB.new(template)
+# magic_word = 'abracadabra'
+# erb.result(binding)
+# # => "The magic word is abracadabra."
+# ```
#
-# require "erb"
+# Details:
#
-# # Create template.
-# template = %q{
-# From: James Edward Gray II <james@grayproductions.net>
-# To: <%= to %>
-# Subject: Addressing Needs
+# 1. As before, a plain-text string is assigned to variable `template`.
+# Its embedded [expression tag][expression tags] `'<%= magic_word %>'` has a variable *name*, `magic_word`.
+# 2. The string is put into a new \ERB object, and stored in variable `erb`;
+# note that `magic_word` need not be defined before the \ERB object is created.
+# 3. `magic_word = 'abracadabra'` assigns a value to variable `magic_word`.
+# 4. Method call `erb.result(binding)` generates a string
+# that contains the *value* of `magic_word`.
#
-# <%= to[/\w+/] %>:
+# As before, the \ERB object may be re-used:
#
-# Just wanted to send a quick note assuring that your needs are being
-# addressed.
+# ```
+# magic_word = 'xyzzy'
+# erb.result(binding)
+# # => "The magic word is xyzzy."
+# ```
#
-# I want you to know that my team will keep working on the issues,
-# especially:
+# ## Bindings
#
-# <%# ignore numerous minor requests -- focus on priorities %>
-# % priorities.each do |priority|
-# * <%= priority %>
-# % end
+# A call to method #result, which produces the formatted result string,
+# requires a [Binding object][binding object] as its argument.
+#
+# The binding object provides the bindings for expressions in [expression tags][expression tags].
+#
+# There are three ways to provide the required binding:
+#
+# - [Default binding][default binding].
+# - [Local binding][local binding].
+# - [Augmented binding][augmented binding]
+#
+# ### Default Binding
+#
+# When you pass no `binding` argument to method #result,
+# the method uses its default binding: the one returned by method #new_toplevel.
+# This binding has the bindings defined by Ruby itself,
+# which are those for Ruby's constants and variables.
+#
+# That binding is sufficient for an expression tag that refers only to Ruby's constants and variables;
+# these expression tags refer only to Ruby's global constant `RUBY_COPYRIGHT` and global variable `$0`:
#
-# Thanks for your patience.
+# ```
+# template = <<TEMPLATE
+# The Ruby copyright is <%= RUBY_COPYRIGHT.inspect %>.
+# The current process is <%= $0 %>.
+# TEMPLATE
+# puts ERB.new(template).result
+# The Ruby copyright is "ruby - Copyright (C) 1993-2025 Yukihiro Matsumoto".
+# The current process is irb.
+# ```
+#
+# (The current process is `irb` because that's where we're doing these examples!)
+#
+# ### Local Binding
+#
+# The default binding is *not* sufficient for an expression
+# that refers to a a constant or variable that is not defined there:
+#
+# ```
+# Foo = 1 # Defines local constant Foo.
+# foo = 2 # Defines local variable foo.
+# template = <<TEMPLATE
+# The current value of constant Foo is <%= Foo %>.
+# The current value of variable foo is <%= foo %>.
+# The Ruby copyright is <%= RUBY_COPYRIGHT.inspect %>.
+# The current process is <%= $0 %>.
+# TEMPLATE
+# erb = ERB.new(template)
+# ```
+#
+# This call below raises `NameError` because although `Foo` and `foo` are defined locally,
+# they are not defined in the default binding:
+#
+# ```
+# erb.result # Raises NameError.
+# ```
+#
+# To make the locally-defined constants and variables available,
+# you can call #result with the local binding:
+#
+# ```
+# puts erb.result(binding)
+# The current value of constant Foo is 1.
+# The current value of variable foo is 2.
+# The Ruby copyright is "ruby - Copyright (C) 1993-2025 Yukihiro Matsumoto".
+# The current process is irb.
+# ```
+#
+# ### Augmented Binding
+#
+# Another way to make variable bindings (but not constant bindings) available
+# is to use method #result_with_hash(hash);
+# the passed hash has name/value pairs that are to be used to define and assign variables
+# in a copy of the default binding:
+#
+# ```
+# template = <<TEMPLATE
+# The current value of variable bar is <%= bar %>.
+# The current value of variable baz is <%= baz %>.
+# The Ruby copyright is <%= RUBY_COPYRIGHT.inspect %>.
+# The current process is <%= $0 %>.
+# TEMPLATE
+# erb = ERB.new(template)
+# ```
+#
+# Both of these calls raise `NameError`, because `bar` and `baz`
+# are not defined in either the default binding or the local binding.
+#
+# ```
+# puts erb.result # Raises NameError.
+# puts erb.result(binding) # Raises NameError.
+# ```
+#
+# This call passes a hash that causes `bar` and `baz` to be defined
+# in a new binding (derived from #new_toplevel):
+#
+# ```
+# hash = {bar: 3, baz: 4}
+# puts erb.result_with_hash(hash)
+# The current value of variable bar is 3.
+# The current value of variable baz is 4.
+# The Ruby copyright is "ruby - Copyright (C) 1993-2025 Yukihiro Matsumoto".
+# The current process is irb.
+# ```
+#
+# ## Tags
+#
+# The examples above use expression tags.
+# These are the tags available in \ERB:
+#
+# - [Expression tag][expression tags]: the tag contains a Ruby expression;
+# in the result, the entire tag is to be replaced with the run-time value of the expression.
+# - [Execution tag][execution tags]: the tag contains Ruby code;
+# in the result, the entire tag is to be replaced with the run-time value of the code.
+# - [Comment tag][comment tags]: the tag contains comment code;
+# in the result, the entire tag is to be omitted.
+#
+# ### Expression Tags
+#
+# You can embed a Ruby expression in a template using an *expression tag*.
+#
+# Its syntax is `<%= _expression_ %>`,
+# where *expression* is any valid Ruby expression.
+#
+# When you call method #result,
+# the method evaluates the expression and replaces the entire expression tag with the expression's value:
+#
+# ```
+# ERB.new('Today is <%= Date::DAYNAMES[Date.today.wday] %>.').result
+# # => "Today is Monday."
+# ERB.new('Tomorrow will be <%= Date::DAYNAMES[Date.today.wday + 1] %>.').result
+# # => "Tomorrow will be Tuesday."
+# ERB.new('Yesterday was <%= Date::DAYNAMES[Date.today.wday - 1] %>.').result
+# # => "Yesterday was Sunday."
+# ```
+#
+# Note that whitespace before and after the expression
+# is allowed but not required,
+# and that such whitespace is stripped from the result.
+#
+# ```
+# ERB.new('My appointment is on <%=Date::DAYNAMES[Date.today.wday + 2]%>.').result
+# # => "My appointment is on Wednesday."
+# ERB.new('My appointment is on <%= Date::DAYNAMES[Date.today.wday + 2] %>.').result
+# # => "My appointment is on Wednesday."
+# ```
+#
+# ### Execution Tags
+#
+# You can embed Ruby executable code in template using an *execution tag*.
+#
+# Its syntax is `<% _code_ %>`,
+# where *code* is any valid Ruby code.
+#
+# When you call method #result,
+# the method executes the code and removes the entire execution tag
+# (generating no text in the result):
+#
+# ```
+# ERB.new('foo <% Dir.chdir("C:/") %> bar').result # => "foo bar"
+# ```
+#
+# Whitespace before and after the embedded code is optional:
+#
+# ```
+# ERB.new('foo <%Dir.chdir("C:/")%> bar').result # => "foo bar"
+# ```
+#
+# You can interleave text with execution tags to form a control structure
+# such as a conditional, a loop, or a `case` statements.
+#
+# Conditional:
+#
+# ```
+# template = <<TEMPLATE
+# <% if verbosity %>
+# An error has occurred.
+# <% else %>
+# Oops!
+# <% end %>
+# TEMPLATE
+# erb = ERB.new(template)
+# verbosity = true
+# erb.result(binding)
+# # => "\nAn error has occurred.\n\n"
+# verbosity = false
+# erb.result(binding)
+# # => "\nOops!\n\n"
+# ```
+#
+# Note that the interleaved text may itself contain expression tags:
+#
+# Loop:
+#
+# ```
+# template = <<TEMPLATE
+# <% Date::ABBR_DAYNAMES.each do |dayname| %>
+# <%= dayname %>
+# <% end %>
+# TEMPLATE
+# ERB.new(template).result
+# # => "\nSun\n\nMon\n\nTue\n\nWed\n\nThu\n\nFri\n\nSat\n\n"
+# ```
+#
+# Other, non-control, lines of Ruby code may be interleaved with the text,
+# and the Ruby code may itself contain regular Ruby comments:
+#
+# ```
+# template = <<TEMPLATE
+# <% 3.times do %>
+# <%= Time.now %>
+# <% sleep(1) # Let's make the times different. %>
+# <% end %>
+# TEMPLATE
+# ERB.new(template).result
+# # => "\n2025-09-09 11:36:02 -0500\n\n\n2025-09-09 11:36:03 -0500\n\n\n2025-09-09 11:36:04 -0500\n\n\n"
+# ```
+#
+# The execution tag may also contain multiple lines of code:
+#
+# ```
+# template = <<TEMPLATE
+# <%
+# (0..2).each do |i|
+# (0..2).each do |j|
+# %>
+# * <%=i%>,<%=j%>
+# <%
+# end
+# end
+# %>
+# TEMPLATE
+# ERB.new(template).result
+# # => "\n* 0,0\n\n* 0,1\n\n* 0,2\n\n* 1,0\n\n* 1,1\n\n* 1,2\n\n* 2,0\n\n* 2,1\n\n* 2,2\n\n"
+# ```
+#
+# #### Shorthand Format for Execution Tags
+#
+# You can use keyword argument `trim_mode: '%'` to enable a shorthand format for execution tags;
+# this example uses the shorthand format `% _code_` instead of `<% _code_ %>`:
+#
+# ```
+# template = <<TEMPLATE
+# % priorities.each do |priority|
+# * <%= priority %>
+# % end
+# TEMPLATE
+# erb = ERB.new(template, trim_mode: '%')
+# priorities = [ 'Run Ruby Quiz',
+# 'Document Modules',
+# 'Answer Questions on Ruby Talk' ]
+# puts erb.result(binding)
+# * Run Ruby Quiz
+# * Document Modules
+# * Answer Questions on Ruby Talk
+# ```
+#
+# Note that in the shorthand format, the character `'%'` must be the first character in the code line
+# (no leading whitespace).
+#
+# #### Suppressing Unwanted Blank Lines
+#
+# With keyword argument `trim_mode` not given,
+# all blank lines go into the result:
+#
+# ```
+# template = <<TEMPLATE
+# <% if true %>
+# <%= RUBY_VERSION %>
+# <% end %>
+# TEMPLATE
+# ERB.new(template).result.lines.each {|line| puts line.inspect }
+# "\n"
+# "3.4.5\n"
+# "\n"
+# ```
+#
+# You can give `trim_mode: '-'`, you can suppress each blank line
+# whose source line ends with `-%>` (instead of `%>`):
+#
+# ```
+# template = <<TEMPLATE
+# <% if true -%>
+# <%= RUBY_VERSION %>
+# <% end -%>
+# TEMPLATE
+# ERB.new(template, trim_mode: '-').result.lines.each {|line| puts line.inspect }
+# "3.4.5\n"
+# ```
+#
+# It is an error to use the trailing `'-%>'` notation without `trim_mode: '-'`:
+#
+# ```
+# ERB.new(template).result.lines.each {|line| puts line.inspect } # Raises SyntaxError.
+# ```
+#
+# #### Suppressing Unwanted Newlines
+#
+# Consider this template:
+#
+# ```
+# template = <<TEMPLATE
+# <% RUBY_VERSION %>
+# <%= RUBY_VERSION %>
+# foo <% RUBY_VERSION %>
+# foo <%= RUBY_VERSION %>
+# TEMPLATE
+# ```
+#
+# With keyword argument `trim_mode` not given, all newlines go into the result:
+#
+# ```
+# ERB.new(template).result.lines.each {|line| puts line.inspect }
+# "\n"
+# "3.4.5\n"
+# "foo \n"
+# "foo 3.4.5\n"
+# ```
+#
+# You can give `trim_mode: '>'` to suppress the trailing newline
+# for each line that ends with `'%>'` (regardless of its beginning):
+#
+# ```
+# ERB.new(template, trim_mode: '>').result.lines.each {|line| puts line.inspect }
+# "3.4.5foo foo 3.4.5"
+# ```
+#
+# You can give `trim_mode: '<>'` to suppress the trailing newline
+# for each line that both begins with `'<%'` and ends with `'%>'`:
+#
+# ```
+# ERB.new(template, trim_mode: '<>').result.lines.each {|line| puts line.inspect }
+# "3.4.5foo \n"
+# "foo 3.4.5\n"
+# ```
+#
+# #### Combining Trim Modes
+#
+# You can combine certain trim modes:
+#
+# - `'%-'`: Enable shorthand and omit each blank line ending with `'-%>'`.
+# - `'%>'`: Enable shorthand and omit newline for each line ending with `'%>'`.
+# - `'%<>'`: Enable shorthand and omit newline for each line starting with `'<%'` and ending with `'%>'`.
+#
+# ### Comment Tags
+#
+# You can embed a comment in a template using a *comment tag*;
+# its syntax is `<%# _text_ %>`,
+# where *text* is the text of the comment.
+#
+# When you call method #result,
+# it removes the entire comment tag
+# (generating no text in the result).
+#
+# Example:
+#
+# ```
+# template = 'Some stuff;<%# Note to self: figure out what the stuff is. %> more stuff.'
+# ERB.new(template).result # => "Some stuff; more stuff."
+# ```
+#
+# A comment tag may appear anywhere in the template.
+#
+# Note that the beginning of the tag must be `'<%#'`, not `'<% #'`.
+#
+# In this example, the tag begins with `'<% #'`, and so is an execution tag, not a comment tag;
+# the cited code consists entirely of a Ruby-style comment (which is of course ignored):
+#
+# ```
+# ERB.new('Some stuff;<% # Note to self: figure out what the stuff is. %> more stuff.').result
+# # => "Some stuff;"
+# ```
+#
+# ## Encodings
+#
+# An \ERB object has an [encoding][encoding],
+# which is by default the encoding of the template string;
+# the result string will also have that encoding.
#
-# James Edward Gray II
-# }.gsub(/^ /, '')
+# ```
+# template = <<TEMPLATE
+# <%# Comment. %>
+# TEMPLATE
+# erb = ERB.new(template)
+# template.encoding # => #<Encoding:UTF-8>
+# erb.encoding # => #<Encoding:UTF-8>
+# erb.result.encoding # => #<Encoding:UTF-8>
+# ```
#
-# message = ERB.new(template, trim_mode: "%<>")
+# You can specify a different encoding by adding a [magic comment][magic comments]
+# at the top of the given template:
#
-# # Set up template data.
-# to = "Community Spokesman <spokesman@ruby_community.org>"
-# priorities = [ "Run Ruby Quiz",
-# "Document Modules",
-# "Answer Questions on Ruby Talk" ]
+# ```
+# template = <<TEMPLATE
+# <%#-*- coding: Big5 -*-%>
+# <%# Comment. %>
+# TEMPLATE
+# erb = ERB.new(template)
+# template.encoding # => #<Encoding:UTF-8>
+# erb.encoding # => #<Encoding:Big5>
+# erb.result.encoding # => #<Encoding:Big5>
+# ```
#
-# # Produce result.
-# email = message.result
-# puts email
+# ## Error Reporting
#
-# <i>Generates:</i>
+# Consider this template (containing an error):
#
-# From: James Edward Gray II <james@grayproductions.net>
-# To: Community Spokesman <spokesman@ruby_community.org>
-# Subject: Addressing Needs
+# ```
+# template = '<%= nosuch %>'
+# erb = ERB.new(template)
+# ```
#
-# Community:
+# When \ERB reports an error,
+# it includes a file name (if available) and a line number;
+# the file name comes from method #filename, the line number from method #lineno.
#
-# Just wanted to send a quick note assuring that your needs are being addressed.
+# Initially, those values are `nil` and `0`, respectively;
+# these initial values are reported as `'(erb)'` and `1`, respectively:
#
-# I want you to know that my team will keep working on the issues, especially:
+# ```
+# erb.filename # => nil
+# erb.lineno # => 0
+# erb.result
+# (erb):1:in '<main>': undefined local variable or method 'nosuch' for main (NameError)
+# ```
#
-# * Run Ruby Quiz
-# * Document Modules
-# * Answer Questions on Ruby Talk
+# You can use methods #filename= and #lineno= to assign values
+# that are more meaningful in your context:
#
-# Thanks for your patience.
+# ```
+# erb.filename = 't.txt'
+# erb.lineno = 555
+# erb.result
+# t.txt:556:in '<main>': undefined local variable or method 'nosuch' for main (NameError)
+# ```
#
-# James Edward Gray II
+# You can use method #location= to set both values:
#
-# === Ruby in HTML
+# ```
+# erb.location = ['u.txt', 999]
+# erb.result
+# u.txt:1000:in '<main>': undefined local variable or method 'nosuch' for main (NameError)
+# ```
#
-# ERB is often used in <tt>.rhtml</tt> files (HTML with embedded Ruby). Notice the need in
-# this example to provide a special binding when the template is run, so that the instance
-# variables in the Product object can be resolved.
+# ## Plain Text with Embedded Ruby
#
-# require "erb"
+# Here's a plain-text template;
+# it uses the literal notation `'%q{ ... }'` to define the template
+# (see [%q literals][%q literals]);
+# this avoids problems with backslashes.
#
-# # Build template data class.
-# class Product
-# def initialize( code, name, desc, cost )
-# @code = code
-# @name = name
-# @desc = desc
-# @cost = cost
+# ```
+# template = %q{
+# From: James Edward Gray II <james@grayproductions.net>
+# To: <%= to %>
+# Subject: Addressing Needs
#
-# @features = [ ]
-# end
+# <%= to[/\w+/] %>:
#
-# def add_feature( feature )
-# @features << feature
-# end
+# Just wanted to send a quick note assuring that your needs are being
+# addressed.
#
-# # Support templating of member data.
-# def get_binding
-# binding
-# end
+# I want you to know that my team will keep working on the issues,
+# especially:
#
-# # ...
-# end
+# <%# ignore numerous minor requests -- focus on priorities %>
+# % priorities.each do |priority|
+# * <%= priority %>
+# % end
+#
+# Thanks for your patience.
#
-# # Create template.
-# template = %{
-# <html>
-# <head><title>Ruby Toys -- <%= @name %></title></head>
-# <body>
+# James Edward Gray II
+# }
+# ```
#
-# <h1><%= @name %> (<%= @code %>)</h1>
-# <p><%= @desc %></p>
+# The template will need these:
#
-# <ul>
-# <% @features.each do |f| %>
-# <li><b><%= f %></b></li>
-# <% end %>
-# </ul>
+# ```
+# to = 'Community Spokesman <spokesman@ruby_community.org>'
+# priorities = [ 'Run Ruby Quiz',
+# 'Document Modules',
+# 'Answer Questions on Ruby Talk' ]
+# ```
#
-# <p>
-# <% if @cost < 10 %>
-# <b>Only <%= @cost %>!!!</b>
-# <% else %>
-# Call for a price, today!
-# <% end %>
-# </p>
+# Finally, create the \ERB object and get the result
#
-# </body>
-# </html>
-# }.gsub(/^ /, '')
+# ```
+# erb = ERB.new(template, trim_mode: '%<>')
+# puts erb.result(binding)
#
-# rhtml = ERB.new(template)
+# From: James Edward Gray II <james@grayproductions.net>
+# To: Community Spokesman <spokesman@ruby_community.org>
+# Subject: Addressing Needs
#
-# # Set up template data.
-# toy = Product.new( "TZ-1002",
-# "Rubysapien",
-# "Geek's Best Friend! Responds to Ruby commands...",
-# 999.95 )
-# toy.add_feature("Listens for verbal commands in the Ruby language!")
-# toy.add_feature("Ignores Perl, Java, and all C variants.")
-# toy.add_feature("Karate-Chop Action!!!")
-# toy.add_feature("Matz signature on left leg.")
-# toy.add_feature("Gem studded eyes... Rubies, of course!")
+# Community:
#
-# # Produce result.
-# rhtml.run(toy.get_binding)
+# Just wanted to send a quick note assuring that your needs are being
+# addressed.
#
-# <i>Generates (some blank lines removed):</i>
+# I want you to know that my team will keep working on the issues,
+# especially:
#
-# <html>
-# <head><title>Ruby Toys -- Rubysapien</title></head>
-# <body>
+# * Run Ruby Quiz
+# * Document Modules
+# * Answer Questions on Ruby Talk
#
-# <h1>Rubysapien (TZ-1002)</h1>
-# <p>Geek's Best Friend! Responds to Ruby commands...</p>
+# Thanks for your patience.
#
-# <ul>
-# <li><b>Listens for verbal commands in the Ruby language!</b></li>
-# <li><b>Ignores Perl, Java, and all C variants.</b></li>
-# <li><b>Karate-Chop Action!!!</b></li>
-# <li><b>Matz signature on left leg.</b></li>
-# <li><b>Gem studded eyes... Rubies, of course!</b></li>
-# </ul>
+# James Edward Gray II
+# ```
#
-# <p>
-# Call for a price, today!
-# </p>
+# ## HTML with Embedded Ruby
#
-# </body>
-# </html>
+# This example shows an HTML template.
#
+# First, here's a custom class, `Product`:
#
-# == Notes
+# ```
+# class Product
+# def initialize(code, name, desc, cost)
+# @code = code
+# @name = name
+# @desc = desc
+# @cost = cost
+# @features = []
+# end
#
-# There are a variety of templating solutions available in various Ruby projects.
-# For example, RDoc, distributed with Ruby, uses its own template engine, which
-# can be reused elsewhere.
+# def add_feature(feature)
+# @features << feature
+# end
#
-# Other popular engines could be found in the corresponding
-# {Category}[https://www.ruby-toolbox.com/categories/template_engines] of
-# The Ruby Toolbox.
+# # Support templating of member data.
+# def get_binding
+# binding
+# end
+#
+# end
+# ```
+#
+# The template below will need these values:
+#
+# ```
+# toy = Product.new('TZ-1002',
+# 'Rubysapien',
+# "Geek's Best Friend! Responds to Ruby commands...",
+# 999.95
+# )
+# toy.add_feature('Listens for verbal commands in the Ruby language!')
+# toy.add_feature('Ignores Perl, Java, and all C variants.')
+# toy.add_feature('Karate-Chop Action!!!')
+# toy.add_feature('Matz signature on left leg.')
+# toy.add_feature('Gem studded eyes... Rubies, of course!')
+# ```
+#
+# Here's the HTML:
+#
+# ```
+# template = <<TEMPLATE
+# <html>
+# <head><title>Ruby Toys -- <%= @name %></title></head>
+# <body>
+# <h1><%= @name %> (<%= @code %>)</h1>
+# <p><%= @desc %></p>
+# <ul>
+# <% @features.each do |f| %>
+# <li><b><%= f %></b></li>
+# <% end %>
+# </ul>
+# <p>
+# <% if @cost < 10 %>
+# <b>Only <%= @cost %>!!!</b>
+# <% else %>
+# Call for a price, today!
+# <% end %>
+# </p>
+# </body>
+# </html>
+# TEMPLATE
+# ```
+#
+# Finally, create the \ERB object and get the result (omitting some blank lines):
+#
+# ```
+# erb = ERB.new(template)
+# puts erb.result(toy.get_binding)
+# <html>
+# <head><title>Ruby Toys -- Rubysapien</title></head>
+# <body>
+# <h1>Rubysapien (TZ-1002)</h1>
+# <p>Geek's Best Friend! Responds to Ruby commands...</p>
+# <ul>
+# <li><b>Listens for verbal commands in the Ruby language!</b></li>
+# <li><b>Ignores Perl, Java, and all C variants.</b></li>
+# <li><b>Karate-Chop Action!!!</b></li>
+# <li><b>Matz signature on left leg.</b></li>
+# <li><b>Gem studded eyes... Rubies, of course!</b></li>
+# </ul>
+# <p>
+# Call for a price, today!
+# </p>
+# </body>
+# </html>
+# ```
+#
+#
+# ## Other Template Processors
+#
+# Various Ruby projects have their own template processors.
+# The Ruby Processing System [RDoc][rdoc], for example, has one that can be used elsewhere.
+#
+# Other popular template processors may found in the [Template Engines][template engines] page
+# of the Ruby Toolbox.
+#
+# [%q literals]: https://docs.ruby-lang.org/en/master/syntax/literals_rdoc.html#label-25q-3A+Non-Interpolable+String+Literals
+# [augmented binding]: rdoc-ref:ERB@Augmented+Binding
+# [binding object]: https://docs.ruby-lang.org/en/master/Binding.html
+# [comment tags]: rdoc-ref:ERB@Comment+Tags
+# [default binding]: rdoc-ref:ERB@Default+Binding
+# [encoding]: https://docs.ruby-lang.org/en/master/Encoding.html
+# [execution tags]: rdoc-ref:ERB@Execution+Tags
+# [expression tags]: rdoc-ref:ERB@Expression+Tags
+# [kernel#binding]: https://docs.ruby-lang.org/en/master/Kernel.html#method-i-binding
+# [local binding]: rdoc-ref:ERB@Local+Binding
+# [magic comments]: https://docs.ruby-lang.org/en/master/syntax/comments_rdoc.html#label-Magic+Comments
+# [rdoc]: https://ruby.github.io/rdoc
+# [sprintf]: https://docs.ruby-lang.org/en/master/Kernel.html#method-i-sprintf
+# [template engines]: https://www.ruby-toolbox.com/categories/template_engines
+# [template processor]: https://en.wikipedia.org/wiki/Template_processor
#
class ERB
- Revision = '$Date:: $' # :nodoc: #'
- deprecate_constant :Revision
-
- # Returns revision information for the erb.rb module.
+ # :markup: markdown
+ #
+ # :call-seq:
+ # self.version -> string
+ #
+ # Returns the string \ERB version.
def self.version
VERSION
end
+ # :markup: markdown
#
- # Constructs a new ERB object with the template specified in _str_.
- #
- # An ERB object works by building a chunk of Ruby code that will output
- # the completed template when run.
+ # :call-seq:
+ # ERB.new(template, trim_mode: nil, eoutvar: '_erbout')
#
- # If _trim_mode_ is passed a String containing one or more of the following
- # modifiers, ERB will adjust its code generation as listed:
+ # Returns a new \ERB object containing the given string +template+.
#
- # % enables Ruby code processing for lines beginning with %
- # <> omit newline for lines starting with <% and ending in %>
- # > omit newline for lines ending in %>
- # - omit blank lines ending in -%>
+ # For details about `template`, its embedded tags, and generated results, see ERB.
#
- # _eoutvar_ can be used to set the name of the variable ERB will build up
- # its output in. This is useful when you need to run multiple ERB
- # templates through the same binding and/or when you want to control where
- # output ends up. Pass the name of the variable to be used inside a String.
+ # **Keyword Argument `trim_mode`**
#
- # === Example
+ # You can use keyword argument `trim_mode: '%'`
+ # to enable the [shorthand format][shorthand format] for execution tags.
#
- # require "erb"
+ # This value allows [blank line control][blank line control]:
#
- # # build data class
- # class Listings
- # PRODUCT = { :name => "Chicken Fried Steak",
- # :desc => "A well messaged pattie, breaded and fried.",
- # :cost => 9.95 }
+ # - `'-'`: Omit each blank line ending with `'%>'`.
#
- # attr_reader :product, :price
+ # Other values allow [newline control][newline control]:
#
- # def initialize( product = "", price = "" )
- # @product = product
- # @price = price
- # end
+ # - `'>'`: Omit newline for each line ending with `'%>'`.
+ # - `'<>'`: Omit newline for each line starting with `'<%'` and ending with `'%>'`.
#
- # def build
- # b = binding
- # # create and run templates, filling member data variables
- # ERB.new(<<~'END_PRODUCT', trim_mode: "", eoutvar: "@product").result b
- # <%= PRODUCT[:name] %>
- # <%= PRODUCT[:desc] %>
- # END_PRODUCT
- # ERB.new(<<~'END_PRICE', trim_mode: "", eoutvar: "@price").result b
- # <%= PRODUCT[:name] %> -- <%= PRODUCT[:cost] %>
- # <%= PRODUCT[:desc] %>
- # END_PRICE
- # end
- # end
+ # You can also [combine trim modes][combine trim modes].
#
- # # setup template data
- # listings = Listings.new
- # listings.build
+ # **Keyword Argument `eoutvar`**
#
- # puts listings.product + "\n" + listings.price
+ # The string value of keyword argument `eoutvar` specifies the name of the variable
+ # that method #result uses to construct its result string;
+ # see #src.
#
- # _Generates_
+ # This is useful when you need to run multiple \ERB templates through the same binding
+ # and/or when you want to control where output ends up.
#
- # Chicken Fried Steak
- # A well massaged pattie, breaded and fried.
+ # It's good practice to choose a variable name that begins with an underscore: `'_'`.
#
- # Chicken Fried Steak -- 9.95
- # A well massaged pattie, breaded and fried.
+ # [blank line control]: rdoc-ref:ERB@Suppressing+Unwanted+Blank+Lines
+ # [combine trim modes]: rdoc-ref:ERB@Combining+Trim+Modes
+ # [newline control]: rdoc-ref:ERB@Suppressing+Unwanted+Newlines
+ # [shorthand format]: rdoc-ref:ERB@Shorthand+Format+for+Execution+Tags
#
- def initialize(str, safe_level=NOT_GIVEN, legacy_trim_mode=NOT_GIVEN, legacy_eoutvar=NOT_GIVEN, trim_mode: nil, eoutvar: '_erbout')
- # Complex initializer for $SAFE deprecation at [Feature #14256]. Use keyword arguments to pass trim_mode or eoutvar.
- if safe_level != NOT_GIVEN
- warn 'Passing safe_level with the 2nd argument of ERB.new is deprecated. Do not use it, and specify other arguments as keyword arguments.', uplevel: 1
- end
- if legacy_trim_mode != NOT_GIVEN
- warn 'Passing trim_mode with the 3rd argument of ERB.new is deprecated. Use keyword argument like ERB.new(str, trim_mode: ...) instead.', uplevel: 1
- trim_mode = legacy_trim_mode
- end
- if legacy_eoutvar != NOT_GIVEN
- warn 'Passing eoutvar with the 4th argument of ERB.new is deprecated. Use keyword argument like ERB.new(str, eoutvar: ...) instead.', uplevel: 1
- eoutvar = legacy_eoutvar
- end
-
+ def initialize(str, trim_mode: nil, eoutvar: '_erbout')
compiler = make_compiler(trim_mode)
set_eoutvar(compiler, eoutvar)
@src, @encoding, @frozen_string = *compiler.compile(str)
+ @src.freeze
@filename = nil
@lineno = 0
@_init = self.class.singleton_class
end
- NOT_GIVEN = defined?(Ractor) ? Ractor.make_shareable(Object.new) : Object.new
- private_constant :NOT_GIVEN
-
- ##
- # Creates a new compiler for ERB. See ERB::Compiler.new for details
+ # :markup: markdown
+ #
+ # :call-seq:
+ # make_compiler -> erb_compiler
+ #
+ # Returns a new ERB::Compiler with the given `trim_mode`;
+ # for `trim_mode` values, see ERB.new:
+ #
+ # ```
+ # ERB.new('').make_compiler(nil)
+ # # => #<ERB::Compiler:0x000001cff9467678 @insert_cmd="print", @percent=false, @post_cmd=[], @pre_cmd=[], @put_cmd="print", @trim_mode=nil>
+ # ```
+ #
def make_compiler(trim_mode)
ERB::Compiler.new(trim_mode)
end
- # The Ruby code generated by ERB
+ # :markup: markdown
+ #
+ # Returns the Ruby code that, when executed, generates the result;
+ # the code is executed by method #result,
+ # and by its wrapper methods #result_with_hash and #run:
+ #
+ # ```
+ # template = 'The time is <%= Time.now %>.'
+ # erb = ERB.new(template)
+ # erb.src
+ # # => "#coding:UTF-8\n_erbout = +''; _erbout.<< \"The time is \".freeze; _erbout.<<(( Time.now ).to_s); _erbout.<< \".\".freeze; _erbout"
+ # erb.result
+ # # => "The time is 2025-09-18 15:58:08 -0500."
+ # ```
+ #
+ # In a more readable format:
+ #
+ # ```
+ # # puts erb.src.split('; ')
+ # # #coding:UTF-8
+ # # _erbout = +''
+ # # _erbout.<< "The time is ".freeze
+ # # _erbout.<<(( Time.now ).to_s)
+ # # _erbout.<< ".".freeze
+ # # _erbout
+ # ```
+ #
+ # Variable `_erbout` is used to store the intermediate results in the code;
+ # the name `_erbout` is the default in ERB.new,
+ # and can be changed via keyword argument `eoutvar`:
+ #
+ # ```
+ # erb = ERB.new(template, eoutvar: '_foo')
+ # puts template.src.split('; ')
+ # #coding:UTF-8
+ # _foo = +''
+ # _foo.<< "The time is ".freeze
+ # _foo.<<(( Time.now ).to_s)
+ # _foo.<< ".".freeze
+ # _foo
+ # ```
+ #
attr_reader :src
- # The encoding to eval
+ # :markup: markdown
+ #
+ # Returns the encoding of `self`;
+ # see [Encodings][encodings]:
+ #
+ # [encodings]: rdoc-ref:ERB@Encodings
+ #
attr_reader :encoding
- # The optional _filename_ argument passed to Kernel#eval when the ERB code
- # is run
+ # :markup: markdown
+ #
+ # Sets or returns the file name to be used in reporting errors;
+ # see [Error Reporting][error reporting].
+ #
+ # [error reporting]: rdoc-ref:ERB@Error+Reporting
attr_accessor :filename
- # The optional _lineno_ argument passed to Kernel#eval when the ERB code
- # is run
+ # :markup: markdown
+ #
+ # Sets or returns the line number to be used in reporting errors;
+ # see [Error Reporting][error reporting].
+ #
+ # [error reporting]: rdoc-ref:ERB@Error+Reporting
attr_accessor :lineno
+ # :markup: markdown
#
- # Sets optional filename and line number that will be used in ERB code
- # evaluation and error reporting. See also #filename= and #lineno=
- #
- # erb = ERB.new('<%= some_x %>')
- # erb.render
- # # undefined local variable or method `some_x'
- # # from (erb):1
+ # :call-seq:
+ # location = [filename, lineno] => [filename, lineno]
+ # location = filename -> filename
#
- # erb.location = ['file.erb', 3]
- # # All subsequent error reporting would use new location
- # erb.render
- # # undefined local variable or method `some_x'
- # # from file.erb:4
+ # Sets the values of #filename and, if given, #lineno;
+ # see [Error Reporting][error reporting].
#
+ # [error reporting]: rdoc-ref:ERB@Error+Reporting
def location=((filename, lineno))
@filename = filename
@lineno = lineno if lineno
end
+ # :markup: markdown
+ #
+ # :call-seq:
+ # set_eoutvar(compiler, eoutvar = '_erbout') -> [eoutvar]
#
- # Can be used to set _eoutvar_ as described in ERB::new. It's probably
- # easier to just use the constructor though, since calling this method
- # requires the setup of an ERB _compiler_ object.
+ # Sets the `eoutvar` value in the ERB::Compiler object `compiler`;
+ # returns a 1-element array containing the value of `eoutvar`:
+ #
+ # ```
+ # template = ERB.new('')
+ # compiler = template.make_compiler(nil)
+ # pp compiler
+ # #<ERB::Compiler:0x000001cff8a9aa00
+ # @insert_cmd="print",
+ # @percent=false,
+ # @post_cmd=[],
+ # @pre_cmd=[],
+ # @put_cmd="print",
+ # @trim_mode=nil>
+ # template.set_eoutvar(compiler, '_foo') # => ["_foo"]
+ # pp compiler
+ # #<ERB::Compiler:0x000001cff8a9aa00
+ # @insert_cmd="_foo.<<",
+ # @percent=false,
+ # @post_cmd=["_foo"],
+ # @pre_cmd=["_foo = +''"],
+ # @put_cmd="_foo.<<",
+ # @trim_mode=nil>
+ # ```
#
def set_eoutvar(compiler, eoutvar = '_erbout')
compiler.put_cmd = "#{eoutvar}.<<"
@@ -408,17 +977,34 @@ class ERB
compiler.post_cmd = [eoutvar]
end
- # Generate results and print them. (see ERB#result)
+ # :markup: markdown
+ #
+ # :call-seq:
+ # run(binding = new_toplevel) -> nil
+ #
+ # Like #result, but prints the result string (instead of returning it);
+ # returns `nil`.
def run(b=new_toplevel)
print self.result(b)
end
+ # :markup: markdown
#
- # Executes the generated ERB code to produce a completed template, returning
- # the results of that code.
+ # :call-seq:
+ # result(binding = new_toplevel) -> new_string
#
- # _b_ accepts a Binding object which is used to set the context of
- # code evaluation.
+ # Returns the string result formed by processing \ERB tags found in the stored template in `self`.
+ #
+ # With no argument given, uses the default binding;
+ # see [Default Binding][default binding].
+ #
+ # With argument `binding` given, uses the local binding;
+ # see [Local Binding][local binding].
+ #
+ # See also #result_with_hash.
+ #
+ # [default binding]: rdoc-ref:ERB@Default+Binding
+ # [local binding]: rdoc-ref:ERB@Local+Binding
#
def result(b=new_toplevel)
unless @_init.equal?(self.class.singleton_class)
@@ -427,8 +1013,18 @@ class ERB
eval(@src, b, (@filename || '(erb)'), @lineno)
end
- # Render a template on a new toplevel binding with local variables specified
- # by a Hash object.
+ # :markup: markdown
+ #
+ # :call-seq:
+ # result_with_hash(hash) -> new_string
+ #
+ # Returns the string result formed by processing \ERB tags found in the stored string in `self`;
+ # see [Augmented Binding][augmented binding].
+ #
+ # See also #result.
+ #
+ # [augmented binding]: rdoc-ref:ERB@Augmented+Binding
+ #
def result_with_hash(hash)
b = new_toplevel(hash.keys)
hash.each_pair do |key, value|
@@ -437,10 +1033,22 @@ class ERB
result(b)
end
- ##
- # Returns a new binding each time *near* TOPLEVEL_BINDING for runs that do
- # not specify a binding.
-
+ # :markup: markdown
+ #
+ # :call-seq:
+ # new_toplevel(symbols) -> new_binding
+ #
+ # Returns a new binding based on `TOPLEVEL_BINDING`;
+ # used to create a default binding for a call to #result.
+ #
+ # See [Default Binding][default binding].
+ #
+ # Argument `symbols` is an array of symbols;
+ # each symbol `symbol` is defined as a new variable to hide and
+ # prevent it from overwriting a variable of the same name already
+ # defined within the binding.
+ #
+ # [default binding]: rdoc-ref:ERB@Default+Binding
def new_toplevel(vars = nil)
b = TOPLEVEL_BINDING
if vars
@@ -453,49 +1061,116 @@ class ERB
end
private :new_toplevel
- # Define _methodname_ as instance method of _mod_ from compiled Ruby source.
+ # :markup: markdown
+ #
+ # :call-seq:
+ # def_method(module, method_signature, filename = '(ERB)') -> method_name
+ #
+ # Creates and returns a new instance method in the given module `module`;
+ # returns the method name as a symbol.
+ #
+ # The method is created from the given `method_signature`,
+ # which consists of the method name and its argument names (if any).
+ #
+ # The `filename` sets the value of #filename;
+ # see [Error Reporting][error reporting].
+ #
+ # [error reporting]: rdoc-ref:ERB@Error+Reporting
+ #
+ # ```
+ # template = '<%= arg1 %> <%= arg2 %>'
+ # erb = ERB.new(template)
+ # MyModule = Module.new
+ # erb.def_method(MyModule, 'render(arg1, arg2)') # => :render
+ # class MyClass; include MyModule; end
+ # MyClass.new.render('foo', 123) # => "foo 123"
+ # ```
#
- # example:
- # filename = 'example.rhtml' # 'arg1' and 'arg2' are used in example.rhtml
- # erb = ERB.new(File.read(filename))
- # erb.def_method(MyClass, 'render(arg1, arg2)', filename)
- # print MyClass.new.render('foo', 123)
def def_method(mod, methodname, fname='(ERB)')
+ unless @_init.equal?(self.class.singleton_class)
+ raise ArgumentError, "not initialized"
+ end
src = self.src.sub(/^(?!#|$)/) {"def #{methodname}\n"} << "\nend\n"
mod.module_eval do
eval(src, binding, fname, -1)
end
end
- # Create unnamed module, define _methodname_ as instance method of it, and return it.
- #
- # example:
- # filename = 'example.rhtml' # 'arg1' and 'arg2' are used in example.rhtml
- # erb = ERB.new(File.read(filename))
- # erb.filename = filename
- # MyModule = erb.def_module('render(arg1, arg2)')
- # class MyClass
- # include MyModule
- # end
+ # :markup: markdown
+ #
+ # :call-seq:
+ # def_module(method_name = 'erb') -> new_module
+ #
+ # Returns a new nameless module that has instance method `method_name`.
+ #
+ # ```
+ # template = '<%= arg1 %> <%= arg2 %>'
+ # erb = ERB.new(template)
+ # MyModule = template.def_module('render(arg1, arg2)')
+ # class MyClass
+ # include MyModule
+ # end
+ # MyClass.new.render('foo', 123)
+ # # => "foo 123"
+ # ```
+ #
def def_module(methodname='erb')
mod = Module.new
def_method(mod, methodname, @filename || '(ERB)')
mod
end
- # Define unnamed class which has _methodname_ as instance method, and return it.
+ # :markup: markdown
+ #
+ # :call-seq:
+ # def_class(super_class = Object, method_name = 'result') -> new_class
+ #
+ # Returns a new nameless class whose superclass is `super_class`,
+ # and which has instance method `method_name`.
+ #
+ # Create a template from HTML that has embedded expression tags that use `@arg1` and `@arg2`:
+ #
+ # ```
+ # html = <<TEMPLATE
+ # <html>
+ # <body>
+ # <p><%= @arg1 %></p>
+ # <p><%= @arg2 %></p>
+ # </body>
+ # </html>
+ # TEMPLATE
+ # template = ERB.new(html)
+ # ```
+ #
+ # Create a base class that has `@arg1` and `@arg2`:
#
- # example:
- # class MyClass_
- # def initialize(arg1, arg2)
- # @arg1 = arg1; @arg2 = arg2
- # end
+ # ```
+ # class MyBaseClass
+ # def initialize(arg1, arg2)
+ # @arg1 = arg1
+ # @arg2 = arg2
# end
- # filename = 'example.rhtml' # @arg1 and @arg2 are used in example.rhtml
- # erb = ERB.new(File.read(filename))
- # erb.filename = filename
- # MyClass = erb.def_class(MyClass_, 'render()')
- # print MyClass.new('foo', 123).render()
+ # end
+ # ```
+ #
+ # Use method #def_class to create a subclass that has method `:render`:
+ #
+ # ```
+ # MySubClass = template.def_class(MyBaseClass, :render)
+ # ```
+ #
+ # Generate the result:
+ #
+ # ```
+ # puts MySubClass.new('foo', 123).render
+ # <html>
+ # <body>
+ # <p>foo</p>
+ # <p>123</p>
+ # </body>
+ # </html>
+ # ```
+ #
def def_class(superklass=Object, methodname='result')
cls = Class.new(superklass)
def_method(cls, methodname, @filename || '(ERB)')
diff --git a/lib/erb/compiler.rb b/lib/erb/compiler.rb
index 08b5eb4ee1..6d70288b4f 100644
--- a/lib/erb/compiler.rb
+++ b/lib/erb/compiler.rb
@@ -225,7 +225,7 @@ class ERB::Compiler # :nodoc:
end
end
- ERB_STAG = %w(<%= <%# <%)
+ ERB_STAG = %w(<%= <%# <%).freeze
def is_erb_stag?(s)
ERB_STAG.member?(s)
end
@@ -480,7 +480,6 @@ class ERB::Compiler # :nodoc:
end
}.new(caller(0)).c
private_constant :WARNING_UPLEVEL
- # :startdoc:
def warn_invalid_trim_mode(mode, uplevel:)
warn "Invalid ERB trim mode: #{mode.inspect} (trim_mode: nil, 0, 1, 2, or String composed of '%' and/or '-', '>', '<>')", uplevel: uplevel + WARNING_UPLEVEL
diff --git a/lib/erb/erb.gemspec b/lib/erb/erb.gemspec
index 94edc68682..70113a2a04 100644
--- a/lib/erb/erb.gemspec
+++ b/lib/erb/erb.gemspec
@@ -18,9 +18,10 @@ Gem::Specification.new do |spec|
spec.metadata['homepage_uri'] = spec.homepage
spec.metadata['source_code_uri'] = spec.homepage
+ spec.metadata['changelog_uri'] = "https://github.com/ruby/erb/blob/v#{spec.version}/NEWS.md"
- spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
- `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
+ spec.files = Dir.chdir(__dir__) do
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|\.git|\.github)/}) }
end
spec.bindir = 'libexec'
spec.executables = ['erb']
diff --git a/lib/erb/util.rb b/lib/erb/util.rb
index 42c7a57622..d7d69eb4f1 100644
--- a/lib/erb/util.rb
+++ b/lib/erb/util.rb
@@ -2,14 +2,14 @@
# Load CGI.escapeHTML and CGI.escapeURIComponent.
# CRuby:
-# cgi.gem v0.1.0+ (Ruby 2.7-3.4) and Ruby 3.5+ stdlib have 'cgi/escape' and CGI.escapeHTML.
-# cgi.gem v0.3.3+ (Ruby 3.2-3.4) and Ruby 3.5+ stdlib have CGI.escapeURIComponent.
+# cgi.gem v0.1.0+ (Ruby 2.7-3.4) and Ruby 4.0+ stdlib have 'cgi/escape' and CGI.escapeHTML.
+# cgi.gem v0.3.3+ (Ruby 3.2-3.4) and Ruby 4.0+ stdlib have CGI.escapeURIComponent.
# JRuby: cgi.gem has a Java extension 'cgi/escape'.
# TruffleRuby: lib/truffle/cgi/escape.rb requires 'cgi/util'.
require 'cgi/escape'
# Load or define ERB::Escape#html_escape.
-# We don't build the C extention 'cgi/escape' for JRuby, TruffleRuby, and WASM.
+# We don't build the C extension 'cgi/escape' for JRuby, TruffleRuby, and WASM.
# miniruby (used by CRuby build scripts) also fails to load erb/escape.so.
begin
require 'erb/escape'
@@ -19,6 +19,7 @@ rescue LoadError
# A subset of ERB::Util. Unlike ERB::Util#html_escape, we expect/hope
# Rails will not monkey-patch ERB::Escape#html_escape.
module ERB::Escape
+ # :stopdoc:
def html_escape(s)
CGI.escapeHTML(s.to_s)
end
@@ -47,19 +48,19 @@ module ERB::Util
alias h html_escape
module_function :h
- #
- # A utility method for encoding the String _s_ as a URL.
- #
- # require "erb"
- # include ERB::Util
- #
- # puts url_encode("Programming Ruby: The Pragmatic Programmer's Guide")
- #
- # _Generates_
- #
- # Programming%20Ruby%3A%20%20The%20Pragmatic%20Programmer%27s%20Guide
- #
if CGI.respond_to?(:escapeURIComponent)
+ #
+ # A utility method for encoding the String _s_ as a URL.
+ #
+ # require "erb"
+ # include ERB::Util
+ #
+ # puts url_encode("Programming Ruby: The Pragmatic Programmer's Guide")
+ #
+ # _Generates_
+ #
+ # Programming%20Ruby%3A%20%20The%20Pragmatic%20Programmer%27s%20Guide
+ #
def url_encode(s)
CGI.escapeURIComponent(s.to_s)
end
diff --git a/lib/erb/version.rb b/lib/erb/version.rb
index 0875dcb42a..fde4a2776a 100644
--- a/lib/erb/version.rb
+++ b/lib/erb/version.rb
@@ -1,4 +1,5 @@
# frozen_string_literal: true
class ERB
- VERSION = '5.0.2'
+ # The string \ERB version.
+ VERSION = '6.0.4'
end
diff --git a/lib/error_highlight/base.rb b/lib/error_highlight/base.rb
index 14e0ce5785..5fffe5ec34 100644
--- a/lib/error_highlight/base.rb
+++ b/lib/error_highlight/base.rb
@@ -1,13 +1,13 @@
require_relative "version"
module ErrorHighlight
- # Identify the code fragment at that a given exception occurred.
+ # Identify the code fragment where a given exception occurred.
#
# Options:
#
# point_type: :name | :args
- # :name (default) points the method/variable name that the exception occurred.
- # :args points the arguments of the method call that the exception occurred.
+ # :name (default) points to the method/variable name where the exception occurred.
+ # :args points to the arguments of the method call where the exception occurred.
#
# backtrace_location: Thread::Backtrace::Location
# It locates the code fragment of the given backtrace_location.
@@ -28,7 +28,7 @@ module ErrorHighlight
# Currently, ErrorHighlight.spot only supports a single-line code fragment.
# Therefore, if the return value is not nil, first_lineno and last_lineno will have
# the same value. If the relevant code fragment spans multiple lines
- # (e.g., Array#[] of +ary[(newline)expr(newline)]+), the method will return nil.
+ # (e.g., Array#[] of <tt>ary[(newline)expr(newline)]</tt>), the method will return nil.
# This restriction may be removed in the future.
def self.spot(obj, **opts)
case obj
@@ -113,7 +113,7 @@ module ErrorHighlight
snippet = @node.script_lines[lineno - 1 .. last_lineno - 1].join("")
snippet += "\n" unless snippet.end_with?("\n")
- # It require some work to support Unicode (or multibyte) characters.
+ # It requires some work to support Unicode (or multibyte) characters.
# Tentatively, we stop highlighting if the code snippet has non-ascii characters.
# See https://github.com/ruby/error_highlight/issues/4
raise NonAscii unless snippet.ascii_only?
@@ -122,56 +122,51 @@ 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
+ # 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
case @node.type
@@ -239,6 +234,20 @@ module ErrorHighlight
when :OP_CDECL
spot_op_cdecl
+ when :DEFN
+ raise NotImplementedError if @point_type != :name
+ spot_defn
+
+ when :DEFS
+ raise NotImplementedError if @point_type != :name
+ spot_defs
+
+ when :LAMBDA
+ spot_lambda
+
+ when :ITER
+ spot_iter
+
when :call_node
case @point_type
when :name
@@ -280,6 +289,30 @@ module ErrorHighlight
when :constant_path_operator_write_node
prism_spot_constant_path_operator_write
+ when :def_node
+ case @point_type
+ when :name
+ prism_spot_def_for_name
+ when :args
+ raise NotImplementedError
+ end
+
+ when :lambda_node
+ case @point_type
+ when :name
+ prism_spot_lambda_for_name
+ when :args
+ raise NotImplementedError
+ end
+
+ when :block_node
+ case @point_type
+ when :name
+ prism_spot_block_for_name
+ when :args
+ raise NotImplementedError
+ end
+
end
if @snippet && @beg_column && @end_column && @beg_column < @end_column
@@ -471,7 +504,6 @@ module ErrorHighlight
def spot_fcall_for_args
_mid, nd_args = @node.children
if nd_args && nd_args.first_lineno == nd_args.last_lineno
- # binary operator
fetch_line(nd_args.first_lineno)
@beg_column = nd_args.first_column
@end_column = nd_args.last_column
@@ -621,6 +653,55 @@ module ErrorHighlight
end
end
+ # Example:
+ # def bar; end
+ # ^^^
+ def spot_defn
+ mid, = @node.children
+ fetch_line(@node.first_lineno)
+ if @snippet.match(/\Gdef\s+(#{ Regexp.quote(mid) }\b)/, @node.first_column)
+ @beg_column = $~.begin(1)
+ @end_column = $~.end(1)
+ end
+ end
+
+ # Example:
+ # def Foo.bar; end
+ # ^^^^
+ def spot_defs
+ nd_recv, mid, = @node.children
+ fetch_line(nd_recv.last_lineno)
+ if @snippet.match(/\G\s*(\.\s*#{ Regexp.quote(mid) }\b)/, nd_recv.last_column)
+ @beg_column = $~.begin(1)
+ @end_column = $~.end(1)
+ end
+ end
+
+ # Example:
+ # -> { ... }
+ # ^^
+ def spot_lambda
+ fetch_line(@node.first_lineno)
+ if @snippet.match(/\G->/, @node.first_column)
+ @beg_column = $~.begin(0)
+ @end_column = $~.end(0)
+ end
+ end
+
+ # Example:
+ # lambda { ... }
+ # ^
+ # define_method :foo do
+ # ^^
+ def spot_iter
+ _nd_fcall, nd_scope = @node.children
+ fetch_line(nd_scope.first_lineno)
+ if @snippet.match(/\G(?:do\b|\{)/, nd_scope.first_column)
+ @beg_column = $~.begin(0)
+ @end_column = $~.end(0)
+ end
+ end
+
def fetch_line(lineno)
@beg_lineno = @end_lineno = lineno
@snippet = @fetch[lineno]
@@ -826,6 +907,31 @@ module ErrorHighlight
prism_location(@node.binary_operator_loc.chop)
end
end
+
+ # Example:
+ # def foo()
+ # ^^^
+ def prism_spot_def_for_name
+ location = @node.name_loc
+ location = @node.operator_loc.join(location) if @node.operator_loc
+ prism_location(location)
+ end
+
+ # Example:
+ # -> x, y { }
+ # ^^
+ def prism_spot_lambda_for_name
+ prism_location(@node.operator_loc)
+ end
+
+ # Example:
+ # lambda { }
+ # ^
+ # define_method :foo do |x, y|
+ # ^
+ def prism_spot_block_for_name
+ prism_location(@node.opening_loc)
+ end
end
private_constant :Spotter
diff --git a/lib/error_highlight/core_ext.rb b/lib/error_highlight/core_ext.rb
index b69093f74e..c3354f46cd 100644
--- a/lib/error_highlight/core_ext.rb
+++ b/lib/error_highlight/core_ext.rb
@@ -3,9 +3,38 @@ require_relative "formatter"
module ErrorHighlight
module CoreExt
private def generate_snippet
- spot = ErrorHighlight.spot(self)
- return "" unless spot
- return ErrorHighlight.formatter.message_for(spot)
+ if ArgumentError === self && message =~ /\A(?:wrong number of arguments|missing keyword[s]?|unknown keyword[s]?|no keywords accepted)\b/
+ locs = self.backtrace_locations
+ return "" if locs.size < 2
+ callee_loc, caller_loc = locs
+ callee_spot = ErrorHighlight.spot(self, backtrace_location: callee_loc, point_type: :name)
+ caller_spot = ErrorHighlight.spot(self, backtrace_location: caller_loc, point_type: :name)
+ if caller_spot && callee_spot &&
+ caller_loc.path == callee_loc.path &&
+ caller_loc.lineno == callee_loc.lineno &&
+ caller_spot == callee_spot
+ callee_loc = callee_spot = nil
+ end
+ ret = +"\n"
+ [["caller", caller_loc, caller_spot], ["callee", callee_loc, callee_spot]].each do |header, loc, spot|
+ out = nil
+ if loc
+ out = " #{ header }: #{ loc.path }:#{ loc.lineno }"
+ if spot
+ _, _, snippet, highlight = ErrorHighlight.formatter.message_for(spot).lines
+ out += "\n | #{ snippet } #{ highlight }"
+ else
+ # do nothing
+ end
+ end
+ ret << "\n" + out if out
+ end
+ ret
+ else
+ spot = ErrorHighlight.spot(self)
+ return "" unless spot
+ return ErrorHighlight.formatter.message_for(spot)
+ end
end
if Exception.method_defined?(:detailed_message)
diff --git a/lib/error_highlight/error_highlight.gemspec b/lib/error_highlight/error_highlight.gemspec
index b2da18df83..edfc4b776f 100644
--- a/lib/error_highlight/error_highlight.gemspec
+++ b/lib/error_highlight/error_highlight.gemspec
@@ -18,7 +18,7 @@ Gem::Specification.new do |spec|
spec.homepage = "https://github.com/ruby/error_highlight"
spec.license = "MIT"
- spec.required_ruby_version = Gem::Requirement.new(">= 3.1.0.dev")
+ spec.required_ruby_version = Gem::Requirement.new(">= 3.2.0")
spec.files = Dir.chdir(File.expand_path(__dir__)) do
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{\A(?:test|spec|features)/}) }
diff --git a/lib/error_highlight/formatter.rb b/lib/error_highlight/formatter.rb
index 5180576405..d2fad9e75c 100644
--- a/lib/error_highlight/formatter.rb
+++ b/lib/error_highlight/formatter.rb
@@ -56,11 +56,11 @@ module ErrorHighlight
end
def self.terminal_width
- # lazy load io/console, so it's not loaded when 'max_snippet_width' is set
+ # lazy load io/console to avoid loading it when 'max_snippet_width' is manually set
require "io/console"
$stderr.winsize[1] if $stderr.tty?
rescue LoadError, NoMethodError, SystemCallError
- # do not truncate when window size is not available
+ # skip truncation when terminal window size is unavailable
end
end
diff --git a/lib/error_highlight/version.rb b/lib/error_highlight/version.rb
index d7a29c7c1e..f0a5376b14 100644
--- a/lib/error_highlight/version.rb
+++ b/lib/error_highlight/version.rb
@@ -1,3 +1,3 @@
module ErrorHighlight
- VERSION = "0.7.0"
+ VERSION = "0.7.1"
end
diff --git a/lib/fileutils.rb b/lib/fileutils.rb
index 6ef71d75ef..0706e007ca 100644
--- a/lib/fileutils.rb
+++ b/lib/fileutils.rb
@@ -181,7 +181,7 @@ end
#
module FileUtils
# The version number.
- VERSION = "1.7.3"
+ VERSION = "1.8.0"
def self.private_module_function(name) #:nodoc:
module_function name
diff --git a/lib/find.rb b/lib/find.rb
index 98a79cc76d..d9b81eb92d 100644
--- a/lib/find.rb
+++ b/lib/find.rb
@@ -3,40 +3,50 @@
# find.rb: the Find module for processing all files under a given directory.
#
+# :markup: markdown
#
-# The +Find+ module supports the top-down traversal of a set of file paths.
-#
-# For example, to total the size of all files under your home directory,
-# ignoring anything in a "dot" directory (e.g. $HOME/.ssh):
-#
-# require 'find'
-#
-# total_size = 0
-#
-# Find.find(ENV["HOME"]) do |path|
-# if FileTest.directory?(path)
-# if File.basename(path).start_with?('.')
-# Find.prune # Don't look any further into this directory.
-# else
-# next
-# end
-# else
-# total_size += FileTest.size(path)
-# end
-# end
-#
+# \Module \Find supports the top-down traversal of entries in the file system.
module Find
+ # The version string
VERSION = "0.2.0"
+ # :markup: markdown
#
- # Calls the associated block with the name of every file and directory listed
- # as arguments, then recursively on their subdirectories, and so on.
+ # With a block given, performs a depth-first traversal of each given path in `paths`;
+ # calls the block with each found file or directory path:
#
- # Returns an enumerator if no block is given.
+ # ```ruby
+ # paths = []
+ # Find.find('bin', 'jit') {|path| paths << path }
+ # paths
+ # # =>
+ # # ["bin",
+ # # "bin/gem",
+ # # "jit",
+ # # "jit/Cargo.toml",
+ # # "jit/src",
+ # # "jit/src/lib.rs"]
+ # ```
#
- # See the +Find+ module documentation for an example.
+ # Raises an exception if a given path cannot be read.
#
+ # When keyword argument `ignore_error` is given as `true` (the default),
+ # certain exceptions during traversal are ignored (i.e., silently rescued):
+ # Errno::ENOENT, Errno::EACCES, Errno::ENOTDIR, Errno::ELOOP, Errno::ENAMETOOLONG, Errno::EINVAL;
+ # when given as `false`, no exceptions are rescued.
+ #
+ # Note that these exceptions may be ignored only in `Find` traversal code;
+ # an exception raised before traversal begins,
+ # or raised while in the block is not ignored.
+ # Each of the calls below raises an Errno::ENOENT exception that is not ignored:
+ #
+ # ```ruby
+ # Find.find('nosuch') { }
+ # Find.find('lib') {|entry| raise Errno::ENOENT }
+ # ```
+ #
+ # With no block given, returns a new Enumerator.
def find(*paths, ignore_error: true) # :yield: path
block_given? or return enum_for(__method__, *paths, ignore_error: ignore_error)
@@ -74,13 +84,26 @@ module Find
nil
end
+ # :markup: markdown
+ #
+ # call-seq:
+ # Find.prune
+ #
+ # This method is meaningful only within a block given with Find.find.
#
- # Skips the current file or directory, restarting the loop with the next
- # entry. If the current file is a directory, that directory will not be
- # recursively entered. Meaningful only within the block associated with
- # Find::find.
+ # Inside such a block,
+ # "prunes" the traversed file tree by not descending into the current directory:
#
- # See the +Find+ module documentation for an example.
+ # ```ruby
+ # files = []
+ # Find.find('.') do |path|
+ # Find.prune if File.basename(path) == 'test'
+ # next unless File.file?(path) && File.extname(path) == '.rb'
+ # files << path
+ # end
+ # files.size # => 6690
+ # files.take(3) # => ["./KNOWNBUGS.rb", "./array.rb", "./ast.rb"]
+ # ```
#
def prune
throw :prune
diff --git a/lib/forwardable.rb b/lib/forwardable.rb
index 71b4e6adad..175d6d9c6b 100644
--- a/lib/forwardable.rb
+++ b/lib/forwardable.rb
@@ -109,11 +109,11 @@
# +delegate.rb+.
#
module Forwardable
- require 'forwardable/impl'
-
# Version of +forwardable.rb+
- VERSION = "1.3.3"
+ VERSION = "1.4.0"
VERSION.freeze
+
+ # Version for backward compatibility
FORWARDABLE_VERSION = VERSION
FORWARDABLE_VERSION.freeze
@@ -190,9 +190,7 @@ module Forwardable
# If it's not a class or module, it's an instance
mod = Module === self ? self : singleton_class
- ret = mod.module_eval(&gen)
- mod.__send__(:ruby2_keywords, ali) if RUBY_VERSION >= '2.7'
- ret
+ mod.module_eval(&gen)
end
alias delegate instance_delegate
@@ -206,36 +204,33 @@ module Forwardable
if Module === obj ?
obj.method_defined?(accessor) || obj.private_method_defined?(accessor) :
obj.respond_to?(accessor, true)
- accessor = "#{accessor}()"
+ accessor = "(#{accessor}())"
end
- method_call = ".__send__(:#{method}, *args, &block)"
- if _valid_method?(method)
+ args = RUBY_VERSION >= '2.7' ? '...' : '*args, &block'
+ method_call = ".__send__(:#{method}, #{args})"
+ if method.match?(/\A[_a-zA-Z]\w*[?!]?\z/)
loc, = caller_locations(2,1)
pre = "_ ="
mesg = "#{Module === obj ? obj : obj.class}\##{ali} at #{loc.path}:#{loc.lineno} forwarding to private method "
- method_call = "#{<<-"begin;"}\n#{<<-"end;".chomp}"
- begin;
- unless defined? _.#{method}
- ::Kernel.warn #{mesg.dump}"\#{_.class}"'##{method}', uplevel: 1
- _#{method_call}
- else
- _.#{method}(*args, &block)
- end
- end;
+ method_call = <<~RUBY.chomp
+ if defined?(_.#{method})
+ _.#{method}(#{args})
+ else
+ ::Kernel.warn #{mesg.dump}"\#{_.class}"'##{method}', uplevel: 1
+ _#{method_call}
+ end
+ RUBY
end
- _compile_method("#{<<-"begin;"}\n#{<<-"end;"}", __FILE__, __LINE__+1)
- begin;
+ eval(<<~RUBY, nil, __FILE__, __LINE__ + 1)
proc do
- def #{ali}(*args, &block)
- #{pre}
- begin
- #{accessor}
- end#{method_call}
+ def #{ali}(#{args})
+ #{pre}#{accessor}
+ #{method_call}
end
end
- end;
+ RUBY
end
end
@@ -310,9 +305,7 @@ module SingleForwardable
def def_single_delegator(accessor, method, ali = method)
gen = Forwardable._delegator_method(self, accessor, method, ali)
- ret = instance_eval(&gen)
- singleton_class.__send__(:ruby2_keywords, ali) if RUBY_VERSION >= '2.7'
- ret
+ instance_eval(&gen)
end
alias delegate single_delegate
diff --git a/lib/forwardable/forwardable.gemspec b/lib/forwardable/forwardable.gemspec
index 9ad59c5f8a..1b539bcfcb 100644
--- a/lib/forwardable/forwardable.gemspec
+++ b/lib/forwardable/forwardable.gemspec
@@ -19,7 +19,7 @@ Gem::Specification.new do |spec|
spec.licenses = ["Ruby", "BSD-2-Clause"]
spec.required_ruby_version = '>= 2.4.0'
- spec.files = ["forwardable.gemspec", "lib/forwardable.rb", "lib/forwardable/impl.rb"]
+ spec.files = ["forwardable.gemspec", "lib/forwardable.rb"]
spec.bindir = "exe"
spec.executables = []
spec.require_paths = ["lib"]
diff --git a/lib/forwardable/impl.rb b/lib/forwardable/impl.rb
deleted file mode 100644
index 0322c136db..0000000000
--- a/lib/forwardable/impl.rb
+++ /dev/null
@@ -1,17 +0,0 @@
-module Forwardable
- # :stopdoc:
-
- def self._valid_method?(method)
- catch {|tag|
- eval("BEGIN{throw tag}; ().#{method}", binding, __FILE__, __LINE__)
- }
- rescue SyntaxError
- false
- else
- true
- end
-
- def self._compile_method(src, file, line)
- eval(src, nil, file, line)
- end
-end
diff --git a/lib/ipaddr.gemspec b/lib/ipaddr.gemspec
index 5719f83fc4..cabc9161ba 100644
--- a/lib/ipaddr.gemspec
+++ b/lib/ipaddr.gemspec
@@ -29,7 +29,7 @@ Both IPv4 and IPv6 are supported.
spec.homepage = "https://github.com/ruby/ipaddr"
spec.licenses = ["Ruby", "BSD-2-Clause"]
- spec.files = ["LICENSE.txt", "README.md", "ipaddr.gemspec", "lib/ipaddr.rb"]
+ spec.files = ["LICENSE.txt", "README.md", "lib/ipaddr.rb"]
spec.require_paths = ["lib"]
spec.required_ruby_version = ">= 2.4"
diff --git a/lib/ipaddr.rb b/lib/ipaddr.rb
index 525466bbd9..70b804f642 100644
--- a/lib/ipaddr.rb
+++ b/lib/ipaddr.rb
@@ -40,7 +40,8 @@ require 'socket'
# p ipaddr3 #=> #<IPAddr: IPv4:192.168.2.0/255.255.255.0>
class IPAddr
- VERSION = "1.2.7"
+ # The version string
+ VERSION = "1.2.9"
# 32 bit mask for IPv4
IN4MASK = 0xffffffff
@@ -163,6 +164,10 @@ class IPAddr
# Returns true if two ipaddrs are equal.
def ==(other)
+ if other.nil?
+ return false
+ end
+
other = coerce_other(other)
rescue
false
@@ -292,7 +297,7 @@ class IPAddr
@addr & 0xff000000 == 0x7f000000 # 127.0.0.1/8
when Socket::AF_INET6
@addr == 1 || # ::1
- (@addr & 0xffff_0000_0000 == 0xffff_0000_0000 && (
+ (@addr >> 32 == 0xffff && (
@addr & 0xff000000 == 0x7f000000 # ::ffff:127.0.0.1/8
))
else
@@ -313,10 +318,10 @@ class IPAddr
@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 >> 32 == 0xffff && (
@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 & 0xfff00000 == 0xac100000 || # ::ffff:172.16.0.0/12
+ @addr & 0xffff0000 == 0xc0a80000 # ::ffff:192.168.0.0/16
))
else
raise AddressFamilyError, "unsupported address family"
@@ -334,7 +339,7 @@ class IPAddr
@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 >> 32 == 0xffff && (
@addr & 0xffff0000 == 0xa9fe0000 # ::ffff:169.254.0.0/16
))
else
@@ -353,7 +358,7 @@ class IPAddr
_ipv4_compat?
end
- def _ipv4_compat?
+ def _ipv4_compat? # :nodoc:
if !ipv6? || (@addr >> 32) != 0
return false
end
@@ -367,7 +372,7 @@ class IPAddr
# into an IPv4-mapped IPv6 address.
def ipv4_mapped
if !ipv4?
- raise InvalidAddressError, "not an IPv4 address: #{@addr}"
+ raise InvalidAddressError, "not an IPv4 address: #{to_s}"
end
clone = self.clone.set(@addr | 0xffff00000000, Socket::AF_INET6)
clone.instance_variable_set(:@mask_addr, @mask_addr | 0xffffffffffffffffffffffff00000000)
@@ -379,9 +384,11 @@ class IPAddr
def ipv4_compat
warn "IPAddr\##{__callee__} is obsolete", uplevel: 1 if $VERBOSE
if !ipv4?
- raise InvalidAddressError, "not an IPv4 address: #{@addr}"
+ raise InvalidAddressError, "not an IPv4 address: #{to_s}"
end
- return self.clone.set(@addr, Socket::AF_INET6)
+ clone = self.clone.set(@addr, Socket::AF_INET6)
+ clone.instance_variable_set(:@mask_addr, @mask_addr | 0xffffffffffffffffffffffff00000000)
+ clone
end
# Returns a new ipaddr built by converting the IPv6 address into a
@@ -410,7 +417,7 @@ class IPAddr
# Returns a string for DNS reverse lookup compatible with RFC3172.
def ip6_arpa
if !ipv6?
- raise InvalidAddressError, "not an IPv6 address: #{@addr}"
+ raise InvalidAddressError, "not an IPv6 address: #{to_s}"
end
return _reverse + ".ip6.arpa"
end
@@ -418,7 +425,7 @@ class IPAddr
# Returns a string for DNS reverse lookup compatible with RFC1886.
def ip6_int
if !ipv6?
- raise InvalidAddressError, "not an IPv6 address: #{@addr}"
+ raise InvalidAddressError, "not an IPv6 address: #{to_s}"
end
return _reverse + ".ip6.int"
end
@@ -543,6 +550,7 @@ class IPAddr
end
protected
+ # :stopdoc:
def begin_addr
@addr & @mask_addr
@@ -558,6 +566,7 @@ class IPAddr
raise AddressFamilyError, "unsupported address family"
end
end
+ #:startdoc:
# Set +@addr+, the internal stored ip address, to given +addr+. The
# parameter +addr+ is validated using the first +family+ member,
@@ -699,6 +708,7 @@ class IPAddr
end
end
+ # :stopdoc:
def coerce_other(other)
case other
when IPAddr
@@ -719,8 +729,8 @@ class IPAddr
octets = addr.split('.')
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}"
+ (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}"
i << 8 | n
}
end
@@ -737,19 +747,19 @@ class IPAddr
right = ''
when RE_IPV6ADDRLIKE_COMPRESSED
if $4
- left.count(':') <= 6 or raise InvalidAddressError, "invalid address: #{@addr}"
+ left.count(':') <= 6 or raise InvalidAddressError, "invalid address: #{left}"
addr = in_addr($~[4,4])
left = $1
right = $3 + '0:0'
else
left.count(':') <= ($1.empty? || $2.empty? ? 8 : 7) or
- raise InvalidAddressError, "invalid address: #{@addr}"
+ raise InvalidAddressError, "invalid address: #{left}"
left = $1
right = $2
addr = 0
end
else
- raise InvalidAddressError, "invalid address: #{@addr}"
+ raise InvalidAddressError, "invalid address: #{left}"
end
l = left.split(':')
r = right.split(':')
@@ -810,7 +820,7 @@ unless Socket.const_defined? :AF_INET6
class << IPSocket
private
- def valid_v6?(addr)
+ def valid_v6?(addr) # :nodoc:
case addr
when IPAddr::RE_IPV6ADDRLIKE_FULL
if $2
diff --git a/lib/mkmf.rb b/lib/mkmf.rb
index d0974b0543..37ee4a70d9 100644
--- a/lib/mkmf.rb
+++ b/lib/mkmf.rb
@@ -40,7 +40,7 @@ class Array # :nodoc:
end
##
-# mkmf.rb is used by Ruby C extensions to generate a Makefile which will
+# \Module \MakeMakefile is used by Ruby C extensions to generate a Makefile which will
# correctly compile and link the C extension to Ruby and a third-party
# library.
module MakeMakefile
@@ -419,7 +419,7 @@ MESSAGE
# 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')
+ envs['LSAN_OPTIONS'] = "detect_leaks=0" unless ENV.key?('LSAN_OPTIONS')
return envs, expand[commands]
end
@@ -573,11 +573,16 @@ MSG
conf)
end
- def cpp_command(outfile, opt="")
+ def cpp_config(opt)
conf = cc_config(opt)
if $universal and (arch_flag = conf['ARCH_FLAG']) and !arch_flag.empty?
conf['ARCH_FLAG'] = arch_flag.gsub(/(?:\G|\s)-arch\s+\S+/, '')
end
+ conf
+ end
+
+ def cpp_command(outfile, opt="")
+ conf = cpp_config(opt)
RbConfig::expand("$(CPP) #$INCFLAGS #$CPPFLAGS #$CFLAGS #{opt} #{CONFTEST_C} #{outfile}",
conf)
end
@@ -926,20 +931,12 @@ SRC
xpopen(cpp_command('', opt)) do |f|
if Regexp === pat
puts(" ruby -ne 'print if #{pat.inspect}'")
- f.grep(pat) {|l|
+ !f.grep(pat) {|l|
puts "#{f.lineno}: #{l}"
- return true
- }
- false
+ }.empty?
else
puts(" egrep '#{pat}'")
- begin
- stdin = $stdin.dup
- $stdin.reopen(f)
- system("egrep", pat)
- ensure
- $stdin.reopen(stdin)
- end
+ system("egrep", pat, in: f)
end
end
ensure
@@ -3033,15 +3030,32 @@ realclean: distclean
def cc_command(opt="")
conf = cc_config(opt)
+ cxx_command(opt, conf)
RbConfig::expand("$(CXX) #$INCFLAGS #$CPPFLAGS #$CXXFLAGS #$ARCH_FLAG #{opt} -c #{CONFTEST_CXX}",
conf)
end
+ def cpp_command(outfile, opt="")
+ conf = cpp_config(opt)
+ cxx = cxx_command(opt, conf)
+ cpp = conf['CPP'].sub(/(\A|\s)#{Regexp.quote(conf['CC'])}(?=\z|\s)/) {
+ "#$1#{cxx}"
+ }
+ RbConfig::expand("#{cpp} #$INCFLAGS #$CPPFLAGS #$CXXFLAGS #{opt} #{CONFTEST_CXX} #{outfile}",
+ conf)
+ end
+
def link_command(ldflags, *opts)
conf = link_config(ldflags, *opts)
RbConfig::expand(TRY_LINK_CXX.dup, conf)
end
+ def cxx_command(opt="", conf = cc_config(opt))
+ cxx = conf['CXX']
+ raise Errno::ENOENT, "C++ compiler not found" if !cxx or cxx == 'false'
+ cxx
+ end
+
# :startdoc:
end
diff --git a/lib/monitor.rb b/lib/monitor.rb
new file mode 100644
index 0000000000..21329a5de7
--- /dev/null
+++ b/lib/monitor.rb
@@ -0,0 +1,216 @@
+# frozen_string_literal: false
+# = monitor.rb
+#
+# Copyright (C) 2001 Shugo Maeda <shugo@ruby-lang.org>
+#
+# This library is distributed under the terms of the Ruby license.
+# You can freely distribute/modify this library.
+#
+#
+# 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
+# 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].
+#
+# == Examples
+#
+# === Simple object.extend
+#
+# require 'monitor.rb'
+#
+# buf = []
+# buf.extend(MonitorMixin)
+# empty_cond = buf.new_cond
+#
+# # consumer
+# Thread.start do
+# loop do
+# buf.synchronize do
+# empty_cond.wait_while { buf.empty? }
+# print buf.shift
+# end
+# end
+# end
+#
+# # producer
+# while line = ARGF.gets
+# buf.synchronize do
+# buf.push(line)
+# empty_cond.signal
+# end
+# 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
+# line from ARGF and pushes it into buf then calls <tt>empty_cond.signal</tt>
+# to notify the consumer thread of new data.
+#
+# === Simple Class include
+#
+# require 'monitor'
+#
+# class SynchronizedArray < Array
+#
+# include MonitorMixin
+#
+# def initialize(*args)
+# super(*args)
+# end
+#
+# alias :old_shift :shift
+# alias :old_unshift :unshift
+#
+# def shift(n=1)
+# self.synchronize do
+# self.old_shift(n)
+# end
+# end
+#
+# def unshift(item)
+# self.synchronize do
+# self.old_unshift(item)
+# end
+# end
+#
+# # other methods ...
+# end
+#
+# +SynchronizedArray+ implements an Array with synchronized access to items.
+# This Class is implemented as subclass of Array which includes the
+# MonitorMixin module.
+#
+module MonitorMixin
+ ConditionVariable = Monitor::ConditionVariable # :nodoc:
+
+ #
+ # FIXME: This isn't documented in Nutshell.
+ #
+ # Since MonitorMixin.new_cond returns a ConditionVariable, and the example
+ # above calls while_wait and signal, this class should be documented.
+ #
+
+ def self.extend_object(obj) # :nodoc:
+ super(obj)
+ obj.__send__(:mon_initialize)
+ end
+
+ #
+ # Attempts to enter exclusive section. Returns +false+ if lock fails.
+ #
+ def mon_try_enter
+ @mon_data.try_enter
+ end
+ # For backward compatibility
+ alias try_mon_enter mon_try_enter
+
+ #
+ # Enters exclusive section.
+ #
+ def mon_enter
+ @mon_data.enter
+ end
+
+ #
+ # Leaves exclusive section.
+ #
+ def mon_exit
+ mon_check_owner
+ @mon_data.exit
+ end
+
+ #
+ # Returns true if this monitor is locked by any thread
+ #
+ def mon_locked?
+ @mon_data.mon_locked?
+ end
+
+ #
+ # Returns true if this monitor is locked by current thread.
+ #
+ def mon_owned?
+ @mon_data.mon_owned?
+ end
+
+ #
+ # Enters exclusive section and executes the block. Leaves the exclusive
+ # section automatically when the block exits. See example under
+ # +MonitorMixin+.
+ #
+ def mon_synchronize(&b)
+ @mon_data.synchronize(&b)
+ end
+ alias synchronize mon_synchronize
+
+ #
+ # Creates a new MonitorMixin::ConditionVariable associated with the
+ # Monitor object.
+ #
+ def new_cond
+ unless defined?(@mon_data)
+ mon_initialize
+ @mon_initialized_by_new_cond = true
+ end
+ return ConditionVariable.new(@mon_data)
+ end
+
+ private
+
+ # Use <tt>extend MonitorMixin</tt> or <tt>include MonitorMixin</tt> instead
+ # of this constructor. Have look at the examples above to understand how to
+ # use this module.
+ def initialize(...)
+ super
+ mon_initialize
+ end
+
+ # Initializes the MonitorMixin after being included in a class or when an
+ # object has been extended with the MonitorMixin
+ def mon_initialize
+ if defined?(@mon_data)
+ if defined?(@mon_initialized_by_new_cond)
+ return # already initialized.
+ elsif @mon_data_owner_object_id == self.object_id
+ raise ThreadError, "already initialized"
+ end
+ end
+ @mon_data = ::Monitor.new
+ @mon_data_owner_object_id = self.object_id
+ end
+
+ # Ensures that the MonitorMixin is owned by the current thread,
+ # otherwise raises an exception.
+ def mon_check_owner
+ @mon_data.mon_check_owner
+ end
+end
+
+class Monitor # :nodoc:
+ alias try_mon_enter try_enter
+ alias mon_try_enter try_enter
+ alias mon_enter enter
+ alias mon_exit exit
+ alias mon_synchronize synchronize
+end
+
+# Documentation comments:
+# - All documentation comes from Nutshell.
+# - MonitorMixin.new_cond appears in the example, but is not documented in
+# Nutshell.
+# - All the internals (internal modules Accessible and Initializable, class
+# ConditionVariable) appear in RDoc. It might be good to hide them, by
+# making them private, or marking them :nodoc:, etc.
+# - RDoc doesn't recognise aliases, so we have mon_synchronize documented, but
+# not synchronize.
+# - mon_owner is in Nutshell, but appears as an accessor in a separate module
+# here, so is hard/impossible to RDoc. Some other useful accessors
+# (mon_count and some queue stuff) are also in this module, and don't appear
+# directly in the RDoc output.
+# - in short, it may be worth changing the code layout in this file to make the
+# documentation easier
diff --git a/lib/net/http.rb b/lib/net/http.rb
index 85051a4468..53295fe90c 100644
--- a/lib/net/http.rb
+++ b/lib/net/http.rb
@@ -37,7 +37,7 @@ module Net #:nodoc:
# 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].
+ # - {Technology}[https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Technology].
#
# == About the Examples
#
@@ -72,7 +72,7 @@ module Net #:nodoc:
#
# - If performance is important, consider using sessions, which lower request overhead.
# This {session}[rdoc-ref:Net::HTTP@Sessions] has multiple requests for
- # {HTTP methods}[https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Request_methods]
+ # {HTTP methods}[https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Method]
# and {WebDAV methods}[https://en.wikipedia.org/wiki/WebDAV#Implementation]:
#
# Net::HTTP.start(hostname) do |http|
@@ -198,7 +198,7 @@ module Net #:nodoc:
# 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]:
+ # - {HTTP methods}[https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Method]:
#
# - #get, #request_get: GET.
# - #head, #request_head: HEAD.
@@ -447,7 +447,7 @@ module Net #:nodoc:
# 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]:
+ # {Content-Encoding}[https://en.wikipedia.org/wiki/List_of_HTTP_header_fields#Content-Encoding_2]:
#
# - <tt>'deflate'</tt>, <tt>'gzip'</tt>, or <tt>'x-gzip'</tt>:
# decompresses the body and deletes the header.
@@ -460,7 +460,7 @@ module Net #:nodoc:
#
# First, what's elsewhere. Class Net::HTTP:
#
- # - Inherits from {class Object}[rdoc-ref:Object@What-27s+Here].
+ # - Inherits from {class Object}[rdoc-ref:Object#class-object-whats-here].
#
# This is a categorized summary of methods and attributes.
#
@@ -724,7 +724,7 @@ module Net #:nodoc:
class HTTP < Protocol
# :stopdoc:
- VERSION = "0.6.0"
+ VERSION = "0.9.1"
HTTPVersion = '1.1'
begin
require 'zlib'
@@ -1179,6 +1179,7 @@ module Net #:nodoc:
@debug_output = options[:debug_output]
@response_body_encoding = options[:response_body_encoding]
@ignore_eof = options[:ignore_eof]
+ @tcpsocket_supports_open_timeout = nil
@proxy_from_env = false
@proxy_uri = nil
@@ -1303,7 +1304,7 @@ module Net #:nodoc:
# Sets whether to determine the proxy from environment variable
# '<tt>ENV['http_proxy']</tt>';
- # see {Proxy Using ENV['http_proxy']}[rdoc-ref:Net::HTTP@Proxy+Using+-27ENV-5B-27http_proxy-27-5D-27].
+ # see {Proxy Using ENV['http_proxy']}[rdoc-ref:Net::HTTP@Proxy+Using+ENVHTTPProxy].
attr_writer :proxy_from_env
# Sets the proxy address;
@@ -1321,6 +1322,9 @@ module Net #:nodoc:
# Sets the proxy password;
# see {Proxy Server}[rdoc-ref:Net::HTTP@Proxy+Server].
attr_writer :proxy_pass
+
+ # Sets whether the proxy uses SSL;
+ # see {Proxy Server}[rdoc-ref:Net::HTTP@Proxy+Server].
attr_writer :proxy_use_ssl
# Returns the IP address for the connection.
@@ -1527,7 +1531,7 @@ module Net #:nodoc:
:verify_depth,
:verify_mode,
:verify_hostname,
- ] # :nodoc:
+ ].freeze # :nodoc:
SSL_IVNAMES = SSL_ATTRIBUTES.map { |a| "@#{a}".to_sym }.freeze # :nodoc:
@@ -1632,6 +1636,21 @@ module Net #:nodoc:
self
end
+ # Finishes the \HTTP session:
+ #
+ # http = 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
+
+ # :stopdoc:
def do_start
connect
@started = true
@@ -1654,14 +1673,15 @@ module Net #:nodoc:
end
debug "opening connection to #{conn_addr}:#{conn_port}..."
- s = Timeout.timeout(@open_timeout, 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})"
+ begin
+ s = timeouted_connect(conn_addr, conn_port)
+ rescue => e
+ if (defined?(IO::TimeoutError) && e.is_a?(IO::TimeoutError)) || e.is_a?(Errno::ETIMEDOUT) # for compatibility with previous versions
+ e = Net::OpenTimeout.new(e)
end
- }
+ 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?
@@ -1754,23 +1774,30 @@ module Net #:nodoc:
end
private :connect
- def on_connect
+ tcp_socket_parameters = TCPSocket.instance_method(:initialize).parameters
+ TCP_SOCKET_NEW_HAS_OPEN_TIMEOUT = if tcp_socket_parameters != [[:rest]]
+ tcp_socket_parameters.include?([:key, :open_timeout])
+ else
+ # Use Socket.tcp to find out since there is no parameters information for TCPSocket#initialize
+ # See discussion in https://github.com/ruby/net-http/pull/224
+ Socket.method(:tcp).parameters.include?([:key, :open_timeout])
end
- private :on_connect
+ private_constant :TCP_SOCKET_NEW_HAS_OPEN_TIMEOUT
- # Finishes the \HTTP session:
- #
- # http = 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
+ def timeouted_connect(conn_addr, conn_port)
+ if TCP_SOCKET_NEW_HAS_OPEN_TIMEOUT
+ TCPSocket.open(conn_addr, conn_port, @local_host, @local_port, open_timeout: @open_timeout)
+ else
+ Timeout.timeout(@open_timeout, Net::OpenTimeout) {
+ TCPSocket.open(conn_addr, conn_port, @local_host, @local_port)
+ }
+ end
+ end
+ private :timeouted_connect
+
+ def on_connect
end
+ private :on_connect
def do_finish
@started = false
@@ -1821,6 +1848,8 @@ module Net #:nodoc:
}
end
+ # :startdoc:
+
class << HTTP
# Returns true if self is a class which was created by HTTP::Proxy.
def proxy_class?
@@ -1915,6 +1944,7 @@ module Net #:nodoc:
alias proxyport proxy_port #:nodoc: obsolete
private
+ # :stopdoc:
def unescape(value)
require 'cgi/escape'
@@ -1943,6 +1973,7 @@ module Net #:nodoc:
path
end
end
+ # :startdoc:
#
# HTTP operations
@@ -2397,7 +2428,9 @@ module Net #:nodoc:
res
end
- IDEMPOTENT_METHODS_ = %w/GET HEAD PUT DELETE OPTIONS TRACE/ # :nodoc:
+ # :stopdoc:
+
+ IDEMPOTENT_METHODS_ = %w/GET HEAD PUT DELETE OPTIONS TRACE/.freeze # :nodoc:
def transport_request(req)
count = 0
@@ -2554,7 +2587,7 @@ module Net #:nodoc:
alias_method :D, :debug
end
- # for backward compatibility until Ruby 3.5
+ # for backward compatibility until Ruby 4.0
# https://bugs.ruby-lang.org/issues/20900
# https://github.com/bblimke/webmock/pull/1081
HTTPSession = HTTP
diff --git a/lib/net/http/exceptions.rb b/lib/net/http/exceptions.rb
index ceec8f7b0a..4342cfc0ef 100644
--- a/lib/net/http/exceptions.rb
+++ b/lib/net/http/exceptions.rb
@@ -3,7 +3,7 @@ module Net
# Net::HTTP exception class.
# You cannot use Net::HTTPExceptions directly; instead, you must use
# its subclasses.
- module HTTPExceptions
+ module HTTPExceptions # :nodoc:
def initialize(msg, res) #:nodoc:
super msg
@response = res
@@ -12,6 +12,7 @@ module Net
alias data response #:nodoc: obsolete
end
+ # :stopdoc:
class HTTPError < ProtocolError
include HTTPExceptions
end
diff --git a/lib/net/http/generic_request.rb b/lib/net/http/generic_request.rb
index c92004e557..5b01ea4abd 100644
--- a/lib/net/http/generic_request.rb
+++ b/lib/net/http/generic_request.rb
@@ -19,16 +19,13 @@ class Net::HTTPGenericRequest
if URI === uri_or_path then
raise ArgumentError, "not an HTTP URI" unless URI::HTTP === uri_or_path
- hostname = uri_or_path.hostname
+ hostname = uri_or_path.host
raise ArgumentError, "no host component for 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
@@ -51,7 +48,7 @@ class Net::HTTPGenericRequest
initialize_http_header initheader
self['Accept'] ||= '*/*'
self['User-Agent'] ||= 'Ruby'
- self['Host'] ||= host if host
+ self['Host'] ||= @uri.authority if @uri
@body = nil
@body_stream = nil
@body_data = nil
@@ -245,7 +242,7 @@ class Net::HTTPGenericRequest
end
if host = self['host']
- host.sub!(/:.*/m, '')
+ host = URI.parse("//#{host}").host # Remove a port component from the existing Host header
elsif host = @uri.host
else
host = addr
@@ -264,6 +261,8 @@ class Net::HTTPGenericRequest
private
+ # :stopdoc:
+
class Chunker #:nodoc:
def initialize(sock)
@sock = sock
diff --git a/lib/net/http/header.rb b/lib/net/http/header.rb
index f6c36f1b5e..5dcdcc7d74 100644
--- a/lib/net/http/header.rb
+++ b/lib/net/http/header.rb
@@ -179,7 +179,9 @@
# - #each_value: Passes each string field value to the block.
#
module Net::HTTPHeader
+ # The maximum length of HTTP header keys.
MAX_KEY_LENGTH = 1024
+ # The maximum length of HTTP header values.
MAX_FIELD_LENGTH = 65536
def initialize_http_header(initheader) #:nodoc:
@@ -267,6 +269,7 @@ module Net::HTTPHeader
end
end
+ # :stopdoc:
private def set_field(key, val)
case val
when Enumerable
@@ -294,6 +297,7 @@ module Net::HTTPHeader
ary.push val
end
end
+ # :startdoc:
# Returns the array field value for the given +key+,
# or +nil+ if there is no such field;
@@ -490,7 +494,7 @@ module Net::HTTPHeader
alias canonical_each each_capitalized
- def capitalize(name)
+ def capitalize(name) # :nodoc:
name.to_s.split('-'.freeze).map {|s| s.capitalize }.join('-'.freeze)
end
private :capitalize
@@ -957,12 +961,12 @@ module Net::HTTPHeader
@header['proxy-authorization'] = [basic_encode(account, password)]
end
- def basic_encode(account, password)
+ def basic_encode(account, password) # :nodoc:
'Basic ' + ["#{account}:#{password}"].pack('m0')
end
private :basic_encode
-# Returns whether the HTTP session is to be closed.
+ # 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}
@@ -970,7 +974,7 @@ module Net::HTTPHeader
false
end
-# Returns whether the HTTP session is to be kept alive.
+ # 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}
diff --git a/lib/net/http/net-http.gemspec b/lib/net/http/net-http.gemspec
index 70528d58cb..d59d5c3b74 100644
--- a/lib/net/http/net-http.gemspec
+++ b/lib/net/http/net-http.gemspec
@@ -21,7 +21,7 @@ Gem::Specification.new do |spec|
spec.summary = %q{HTTP client api for Ruby.}
spec.description = %q{HTTP client api for Ruby.}
spec.homepage = "https://github.com/ruby/net-http"
- spec.required_ruby_version = Gem::Requirement.new(">= 2.6.0")
+ spec.required_ruby_version = Gem::Requirement.new(">= 2.7.0")
spec.licenses = ["Ruby", "BSD-2-Clause"]
spec.metadata["changelog_uri"] = spec.homepage + "/releases"
@@ -30,11 +30,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.
- spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
- `git ls-files -z 2>#{IO::NULL}`.split("\x0").reject { |f| f.match(%r{\A(?:(?:test|spec|features)/|\.git)}) }
- end
+ excludes = %W[/.git* /bin /test /test_sig /*file /#{File.basename(__FILE__)}]
+ spec.files = IO.popen(%W[git -C #{__dir__} ls-files -z --] + excludes.map {|e| ":^#{e}"}, &:read).split("\x0")
spec.bindir = "exe"
spec.require_paths = ["lib"]
- spec.add_dependency "uri"
+ spec.add_dependency "uri", ">= 0.11.1"
end
diff --git a/lib/net/http/requests.rb b/lib/net/http/requests.rb
index e58057adf1..8dc79a9f66 100644
--- a/lib/net/http/requests.rb
+++ b/lib/net/http/requests.rb
@@ -19,9 +19,9 @@
#
# - 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.
+# - {Safe}[https://en.wikipedia.org/wiki/HTTP#Safe_method]: yes.
+# - {Idempotent}[https://en.wikipedia.org/wiki/HTTP#Idempotent_method]: yes.
+# - {Cacheable}[https://en.wikipedia.org/wiki/HTTP#Cacheable_method]: yes.
#
# Related:
#
@@ -29,6 +29,7 @@
# - Net::HTTP#get: sends +GET+ request, returns response object.
#
class Net::HTTP::Get < Net::HTTPRequest
+ # :stopdoc:
METHOD = 'GET'
REQUEST_HAS_BODY = false
RESPONSE_HAS_BODY = true
@@ -51,15 +52,16 @@ end
#
# - 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.
+# - {Safe}[https://en.wikipedia.org/wiki/HTTP#Safe_method]: yes.
+# - {Idempotent}[https://en.wikipedia.org/wiki/HTTP#Idempotent_method]: yes.
+# - {Cacheable}[https://en.wikipedia.org/wiki/HTTP#Cacheable_method]: yes.
#
# Related:
#
# - Net::HTTP#head: sends +HEAD+ request, returns response object.
#
class Net::HTTP::Head < Net::HTTPRequest
+ # :stopdoc:
METHOD = 'HEAD'
REQUEST_HAS_BODY = false
RESPONSE_HAS_BODY = false
@@ -85,9 +87,9 @@ end
#
# - 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.
+# - {Safe}[https://en.wikipedia.org/wiki/HTTP#Safe_method]: no.
+# - {Idempotent}[https://en.wikipedia.org/wiki/HTTP#Idempotent_method]: no.
+# - {Cacheable}[https://en.wikipedia.org/wiki/HTTP#Cacheable_method]: yes.
#
# Related:
#
@@ -95,6 +97,7 @@ end
# - Net::HTTP#post: sends +POST+ request, returns response object.
#
class Net::HTTP::Post < Net::HTTPRequest
+ # :stopdoc:
METHOD = 'POST'
REQUEST_HAS_BODY = true
RESPONSE_HAS_BODY = true
@@ -120,9 +123,9 @@ end
#
# - 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.
+# - {Safe}[https://en.wikipedia.org/wiki/HTTP#Safe_method]: no.
+# - {Idempotent}[https://en.wikipedia.org/wiki/HTTP#Idempotent_method]: yes.
+# - {Cacheable}[https://en.wikipedia.org/wiki/HTTP#Cacheable_method]: no.
#
# Related:
#
@@ -130,6 +133,7 @@ end
# - Net::HTTP#put: sends +PUT+ request, returns response object.
#
class Net::HTTP::Put < Net::HTTPRequest
+ # :stopdoc:
METHOD = 'PUT'
REQUEST_HAS_BODY = true
RESPONSE_HAS_BODY = true
@@ -153,15 +157,16 @@ end
#
# - 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.
+# - {Safe}[https://en.wikipedia.org/wiki/HTTP#Safe_method]: no.
+# - {Idempotent}[https://en.wikipedia.org/wiki/HTTP#Idempotent_method]: yes.
+# - {Cacheable}[https://en.wikipedia.org/wiki/HTTP#Cacheable_method]: no.
#
# Related:
#
# - Net::HTTP#delete: sends +DELETE+ request, returns response object.
#
class Net::HTTP::Delete < Net::HTTPRequest
+ # :stopdoc:
METHOD = 'DELETE'
REQUEST_HAS_BODY = false
RESPONSE_HAS_BODY = true
@@ -184,15 +189,16 @@ end
#
# - 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.
+# - {Safe}[https://en.wikipedia.org/wiki/HTTP#Safe_method]: yes.
+# - {Idempotent}[https://en.wikipedia.org/wiki/HTTP#Idempotent_method]: yes.
+# - {Cacheable}[https://en.wikipedia.org/wiki/HTTP#Cacheable_method]: no.
#
# Related:
#
# - Net::HTTP#options: sends +OPTIONS+ request, returns response object.
#
class Net::HTTP::Options < Net::HTTPRequest
+ # :stopdoc:
METHOD = 'OPTIONS'
REQUEST_HAS_BODY = false
RESPONSE_HAS_BODY = true
@@ -215,15 +221,16 @@ end
#
# - 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.
+# - {Safe}[https://en.wikipedia.org/wiki/HTTP#Safe_method]: yes.
+# - {Idempotent}[https://en.wikipedia.org/wiki/HTTP#Idempotent_method]: yes.
+# - {Cacheable}[https://en.wikipedia.org/wiki/HTTP#Cacheable_method]: no.
#
# Related:
#
# - Net::HTTP#trace: sends +TRACE+ request, returns response object.
#
class Net::HTTP::Trace < Net::HTTPRequest
+ # :stopdoc:
METHOD = 'TRACE'
REQUEST_HAS_BODY = false
RESPONSE_HAS_BODY = true
@@ -249,15 +256,16 @@ end
#
# - 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.
+# - {Safe}[https://en.wikipedia.org/wiki/HTTP#Safe_method]: no.
+# - {Idempotent}[https://en.wikipedia.org/wiki/HTTP#Idempotent_method]: no.
+# - {Cacheable}[https://en.wikipedia.org/wiki/HTTP#Cacheable_method]: no.
#
# Related:
#
# - Net::HTTP#patch: sends +PATCH+ request, returns response object.
#
class Net::HTTP::Patch < Net::HTTPRequest
+ # :stopdoc:
METHOD = 'PATCH'
REQUEST_HAS_BODY = true
RESPONSE_HAS_BODY = true
@@ -285,6 +293,7 @@ end
# - Net::HTTP#propfind: sends +PROPFIND+ request, returns response object.
#
class Net::HTTP::Propfind < Net::HTTPRequest
+ # :stopdoc:
METHOD = 'PROPFIND'
REQUEST_HAS_BODY = true
RESPONSE_HAS_BODY = true
@@ -308,6 +317,7 @@ end
# - Net::HTTP#proppatch: sends +PROPPATCH+ request, returns response object.
#
class Net::HTTP::Proppatch < Net::HTTPRequest
+ # :stopdoc:
METHOD = 'PROPPATCH'
REQUEST_HAS_BODY = true
RESPONSE_HAS_BODY = true
@@ -331,6 +341,7 @@ end
# - Net::HTTP#mkcol: sends +MKCOL+ request, returns response object.
#
class Net::HTTP::Mkcol < Net::HTTPRequest
+ # :stopdoc:
METHOD = 'MKCOL'
REQUEST_HAS_BODY = true
RESPONSE_HAS_BODY = true
@@ -354,6 +365,7 @@ end
# - Net::HTTP#copy: sends +COPY+ request, returns response object.
#
class Net::HTTP::Copy < Net::HTTPRequest
+ # :stopdoc:
METHOD = 'COPY'
REQUEST_HAS_BODY = false
RESPONSE_HAS_BODY = true
@@ -377,6 +389,7 @@ end
# - Net::HTTP#move: sends +MOVE+ request, returns response object.
#
class Net::HTTP::Move < Net::HTTPRequest
+ # :stopdoc:
METHOD = 'MOVE'
REQUEST_HAS_BODY = false
RESPONSE_HAS_BODY = true
@@ -400,6 +413,7 @@ end
# - Net::HTTP#lock: sends +LOCK+ request, returns response object.
#
class Net::HTTP::Lock < Net::HTTPRequest
+ # :stopdoc:
METHOD = 'LOCK'
REQUEST_HAS_BODY = true
RESPONSE_HAS_BODY = true
@@ -423,8 +437,8 @@ end
# - Net::HTTP#unlock: sends +UNLOCK+ request, returns response object.
#
class Net::HTTP::Unlock < Net::HTTPRequest
+ # :stopdoc:
METHOD = 'UNLOCK'
REQUEST_HAS_BODY = true
RESPONSE_HAS_BODY = true
end
-
diff --git a/lib/net/http/response.rb b/lib/net/http/response.rb
index 40de963868..8804a99c9e 100644
--- a/lib/net/http/response.rb
+++ b/lib/net/http/response.rb
@@ -153,6 +153,7 @@ class Net::HTTPResponse
end
private
+ # :stopdoc:
def read_status_line(sock)
str = sock.readline
@@ -259,7 +260,7 @@ class Net::HTTPResponse
# header.
attr_accessor :ignore_eof
- def inspect
+ def inspect # :nodoc:
"#<#{self.class} #{@code} #{@message} readbody=#{@read}>"
end
diff --git a/lib/net/http/responses.rb b/lib/net/http/responses.rb
index 5e2f8ce1aa..941a6fed80 100644
--- a/lib/net/http/responses.rb
+++ b/lib/net/http/responses.rb
@@ -4,7 +4,9 @@
module Net
+ # Unknown HTTP response
class HTTPUnknownResponse < HTTPResponse
+ # :stopdoc:
HAS_BODY = true
EXCEPTION_TYPE = HTTPError #
end
@@ -19,6 +21,7 @@ module Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#1xx_informational_response].
#
class HTTPInformation < HTTPResponse
+ # :stopdoc:
HAS_BODY = false
EXCEPTION_TYPE = HTTPError #
end
@@ -34,6 +37,7 @@ module Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#2xx_success].
#
class HTTPSuccess < HTTPResponse
+ # :stopdoc:
HAS_BODY = true
EXCEPTION_TYPE = HTTPError #
end
@@ -49,6 +53,7 @@ module Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#3xx_redirection].
#
class HTTPRedirection < HTTPResponse
+ # :stopdoc:
HAS_BODY = true
EXCEPTION_TYPE = HTTPRetriableError #
end
@@ -63,6 +68,7 @@ module Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#4xx_client_errors].
#
class HTTPClientError < HTTPResponse
+ # :stopdoc:
HAS_BODY = true
EXCEPTION_TYPE = HTTPClientException #
end
@@ -77,6 +83,7 @@ module Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#5xx_server_errors].
#
class HTTPServerError < HTTPResponse
+ # :stopdoc:
HAS_BODY = true
EXCEPTION_TYPE = HTTPFatalError #
end
@@ -94,6 +101,7 @@ module Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#100].
#
class HTTPContinue < HTTPInformation
+ # :stopdoc:
HAS_BODY = false
end
@@ -111,6 +119,7 @@ module Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#101].
#
class HTTPSwitchProtocol < HTTPInformation
+ # :stopdoc:
HAS_BODY = false
end
@@ -127,6 +136,7 @@ module Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#102].
#
class HTTPProcessing < HTTPInformation
+ # :stopdoc:
HAS_BODY = false
end
@@ -145,6 +155,7 @@ module Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#103].
#
class HTTPEarlyHints < HTTPInformation
+ # :stopdoc:
HAS_BODY = false
end
@@ -162,6 +173,7 @@ module Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#200].
#
class HTTPOK < HTTPSuccess
+ # :stopdoc:
HAS_BODY = true
end
@@ -179,6 +191,7 @@ module Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#201].
#
class HTTPCreated < HTTPSuccess
+ # :stopdoc:
HAS_BODY = true
end
@@ -196,6 +209,7 @@ module Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#202].
#
class HTTPAccepted < HTTPSuccess
+ # :stopdoc:
HAS_BODY = true
end
@@ -215,6 +229,7 @@ module Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#203].
#
class HTTPNonAuthoritativeInformation < HTTPSuccess
+ # :stopdoc:
HAS_BODY = true
end
@@ -232,6 +247,7 @@ module Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#204].
#
class HTTPNoContent < HTTPSuccess
+ # :stopdoc:
HAS_BODY = false
end
@@ -250,6 +266,7 @@ module Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#205].
#
class HTTPResetContent < HTTPSuccess
+ # :stopdoc:
HAS_BODY = false
end
@@ -268,6 +285,7 @@ module Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#206].
#
class HTTPPartialContent < HTTPSuccess
+ # :stopdoc:
HAS_BODY = true
end
@@ -285,6 +303,7 @@ module Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#207].
#
class HTTPMultiStatus < HTTPSuccess
+ # :stopdoc:
HAS_BODY = true
end
@@ -304,6 +323,7 @@ module Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#208].
#
class HTTPAlreadyReported < HTTPSuccess
+ # :stopdoc:
HAS_BODY = true
end
@@ -321,6 +341,7 @@ module Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#226].
#
class HTTPIMUsed < HTTPSuccess
+ # :stopdoc:
HAS_BODY = true
end
@@ -338,6 +359,7 @@ module Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#300].
#
class HTTPMultipleChoices < HTTPRedirection
+ # :stopdoc:
HAS_BODY = true
end
HTTPMultipleChoice = HTTPMultipleChoices
@@ -356,6 +378,7 @@ module Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#301].
#
class HTTPMovedPermanently < HTTPRedirection
+ # :stopdoc:
HAS_BODY = true
end
@@ -373,6 +396,7 @@ module Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#302].
#
class HTTPFound < HTTPRedirection
+ # :stopdoc:
HAS_BODY = true
end
HTTPMovedTemporarily = HTTPFound
@@ -390,6 +414,7 @@ module Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#303].
#
class HTTPSeeOther < HTTPRedirection
+ # :stopdoc:
HAS_BODY = true
end
@@ -407,6 +432,7 @@ module Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#304].
#
class HTTPNotModified < HTTPRedirection
+ # :stopdoc:
HAS_BODY = false
end
@@ -423,6 +449,7 @@ module Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#305].
#
class HTTPUseProxy < HTTPRedirection
+ # :stopdoc:
HAS_BODY = false
end
@@ -440,6 +467,7 @@ module Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#307].
#
class HTTPTemporaryRedirect < HTTPRedirection
+ # :stopdoc:
HAS_BODY = true
end
@@ -456,6 +484,7 @@ module Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#308].
#
class HTTPPermanentRedirect < HTTPRedirection
+ # :stopdoc:
HAS_BODY = true
end
@@ -472,6 +501,7 @@ module Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#400].
#
class HTTPBadRequest < HTTPClientError
+ # :stopdoc:
HAS_BODY = true
end
@@ -488,6 +518,7 @@ module Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#401].
#
class HTTPUnauthorized < HTTPClientError
+ # :stopdoc:
HAS_BODY = true
end
@@ -504,6 +535,7 @@ module Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#402].
#
class HTTPPaymentRequired < HTTPClientError
+ # :stopdoc:
HAS_BODY = true
end
@@ -521,6 +553,7 @@ module Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#403].
#
class HTTPForbidden < HTTPClientError
+ # :stopdoc:
HAS_BODY = true
end
@@ -537,6 +570,7 @@ module Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#404].
#
class HTTPNotFound < HTTPClientError
+ # :stopdoc:
HAS_BODY = true
end
@@ -553,6 +587,7 @@ module Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#405].
#
class HTTPMethodNotAllowed < HTTPClientError
+ # :stopdoc:
HAS_BODY = true
end
@@ -570,6 +605,7 @@ module Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#406].
#
class HTTPNotAcceptable < HTTPClientError
+ # :stopdoc:
HAS_BODY = true
end
@@ -586,6 +622,7 @@ module Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#407].
#
class HTTPProxyAuthenticationRequired < HTTPClientError
+ # :stopdoc:
HAS_BODY = true
end
@@ -602,6 +639,7 @@ module Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#408].
#
class HTTPRequestTimeout < HTTPClientError
+ # :stopdoc:
HAS_BODY = true
end
HTTPRequestTimeOut = HTTPRequestTimeout
@@ -619,6 +657,7 @@ module Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#409].
#
class HTTPConflict < HTTPClientError
+ # :stopdoc:
HAS_BODY = true
end
@@ -636,6 +675,7 @@ module Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#410].
#
class HTTPGone < HTTPClientError
+ # :stopdoc:
HAS_BODY = true
end
@@ -653,6 +693,7 @@ module Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#411].
#
class HTTPLengthRequired < HTTPClientError
+ # :stopdoc:
HAS_BODY = true
end
@@ -670,6 +711,7 @@ module Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#412].
#
class HTTPPreconditionFailed < HTTPClientError
+ # :stopdoc:
HAS_BODY = true
end
@@ -686,6 +728,7 @@ module Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#413].
#
class HTTPPayloadTooLarge < HTTPClientError
+ # :stopdoc:
HAS_BODY = true
end
HTTPRequestEntityTooLarge = HTTPPayloadTooLarge
@@ -703,6 +746,7 @@ module Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#414].
#
class HTTPURITooLong < HTTPClientError
+ # :stopdoc:
HAS_BODY = true
end
HTTPRequestURITooLong = HTTPURITooLong
@@ -721,6 +765,7 @@ module Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#415].
#
class HTTPUnsupportedMediaType < HTTPClientError
+ # :stopdoc:
HAS_BODY = true
end
@@ -737,6 +782,7 @@ module Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#416].
#
class HTTPRangeNotSatisfiable < HTTPClientError
+ # :stopdoc:
HAS_BODY = true
end
HTTPRequestedRangeNotSatisfiable = HTTPRangeNotSatisfiable
@@ -754,6 +800,7 @@ module Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#417].
#
class HTTPExpectationFailed < HTTPClientError
+ # :stopdoc:
HAS_BODY = true
end
@@ -774,6 +821,7 @@ module Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#421].
#
class HTTPMisdirectedRequest < HTTPClientError
+ # :stopdoc:
HAS_BODY = true
end
@@ -790,6 +838,7 @@ module Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#422].
#
class HTTPUnprocessableEntity < HTTPClientError
+ # :stopdoc:
HAS_BODY = true
end
@@ -805,6 +854,7 @@ module Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#423].
#
class HTTPLocked < HTTPClientError
+ # :stopdoc:
HAS_BODY = true
end
@@ -821,6 +871,7 @@ module Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#424].
#
class HTTPFailedDependency < HTTPClientError
+ # :stopdoc:
HAS_BODY = true
end
@@ -840,6 +891,7 @@ module Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#426].
#
class HTTPUpgradeRequired < HTTPClientError
+ # :stopdoc:
HAS_BODY = true
end
@@ -856,6 +908,7 @@ module Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#428].
#
class HTTPPreconditionRequired < HTTPClientError
+ # :stopdoc:
HAS_BODY = true
end
@@ -872,6 +925,7 @@ module Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#429].
#
class HTTPTooManyRequests < HTTPClientError
+ # :stopdoc:
HAS_BODY = true
end
@@ -889,6 +943,7 @@ module Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#431].
#
class HTTPRequestHeaderFieldsTooLarge < HTTPClientError
+ # :stopdoc:
HAS_BODY = true
end
@@ -906,6 +961,7 @@ module Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#451].
#
class HTTPUnavailableForLegalReasons < HTTPClientError
+ # :stopdoc:
HAS_BODY = true
end
# 444 No Response - Nginx
@@ -926,6 +982,7 @@ module Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#500].
#
class HTTPInternalServerError < HTTPServerError
+ # :stopdoc:
HAS_BODY = true
end
@@ -943,6 +1000,7 @@ module Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#501].
#
class HTTPNotImplemented < HTTPServerError
+ # :stopdoc:
HAS_BODY = true
end
@@ -960,6 +1018,7 @@ module Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#502].
#
class HTTPBadGateway < HTTPServerError
+ # :stopdoc:
HAS_BODY = true
end
@@ -977,6 +1036,7 @@ module Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#503].
#
class HTTPServiceUnavailable < HTTPServerError
+ # :stopdoc:
HAS_BODY = true
end
@@ -994,6 +1054,7 @@ module Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#504].
#
class HTTPGatewayTimeout < HTTPServerError
+ # :stopdoc:
HAS_BODY = true
end
HTTPGatewayTimeOut = HTTPGatewayTimeout
@@ -1011,6 +1072,7 @@ module Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#505].
#
class HTTPVersionNotSupported < HTTPServerError
+ # :stopdoc:
HAS_BODY = true
end
@@ -1027,6 +1089,7 @@ module Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#506].
#
class HTTPVariantAlsoNegotiates < HTTPServerError
+ # :stopdoc:
HAS_BODY = true
end
@@ -1043,6 +1106,7 @@ module Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#507].
#
class HTTPInsufficientStorage < HTTPServerError
+ # :stopdoc:
HAS_BODY = true
end
@@ -1059,6 +1123,7 @@ module Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#508].
#
class HTTPLoopDetected < HTTPServerError
+ # :stopdoc:
HAS_BODY = true
end
# 509 Bandwidth Limit Exceeded - Apache bw/limited extension
@@ -1076,6 +1141,7 @@ module Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#510].
#
class HTTPNotExtended < HTTPServerError
+ # :stopdoc:
HAS_BODY = true
end
@@ -1092,12 +1158,14 @@ module Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#511].
#
class HTTPNetworkAuthenticationRequired < HTTPServerError
+ # :stopdoc:
HAS_BODY = true
end
end
class Net::HTTPResponse
+ # :stopdoc:
CODE_CLASS_TO_OBJ = {
'1' => Net::HTTPInformation,
'2' => Net::HTTPSuccess,
diff --git a/lib/net/net-protocol.gemspec b/lib/net/net-protocol.gemspec
index f9fd83f12b..2d911a966c 100644
--- a/lib/net/net-protocol.gemspec
+++ b/lib/net/net-protocol.gemspec
@@ -25,9 +25,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.
- 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
+ excludes = %W[/.git* /bin /test /*file /#{File.basename(__FILE__)}]
+ spec.files = IO.popen(%W[git -C #{__dir__} ls-files -z --] + excludes.map {|e| ":^#{e}"}, &:read).split("\x0")
spec.require_paths = ["lib"]
spec.add_dependency "timeout"
diff --git a/lib/net/protocol.rb b/lib/net/protocol.rb
index 197ea09089..8c81298c0e 100644
--- a/lib/net/protocol.rb
+++ b/lib/net/protocol.rb
@@ -54,9 +54,20 @@ module Net # :nodoc:
s.connect
end
end
+
+ tcp_socket_parameters = TCPSocket.instance_method(:initialize).parameters
+ TCP_SOCKET_NEW_HAS_OPEN_TIMEOUT = if tcp_socket_parameters != [[:rest]]
+ tcp_socket_parameters.include?([:key, :open_timeout])
+ else
+ # Use Socket.tcp to find out since there is no parameters information for TCPSocket#initialize
+ # See discussion in https://github.com/ruby/net-http/pull/224
+ Socket.method(:tcp).parameters.include?([:key, :open_timeout])
+ end
+ private_constant :TCP_SOCKET_NEW_HAS_OPEN_TIMEOUT
end
+ # :stopdoc:
class ProtocolError < StandardError; end
class ProtoSyntaxError < ProtocolError; end
class ProtoFatalError < ProtocolError; end
@@ -66,6 +77,7 @@ module Net # :nodoc:
class ProtoCommandError < ProtocolError; end
class ProtoRetriableError < ProtocolError; end
ProtocRetryError = ProtoRetriableError
+ # :startdoc:
##
# OpenTimeout, a subclass of Timeout::Error, is raised if a connection cannot
@@ -78,6 +90,7 @@ module Net # :nodoc:
# response cannot be read within the read_timeout.
class ReadTimeout < Timeout::Error
+ # :stopdoc:
def initialize(io = nil)
@io = io
end
@@ -97,6 +110,7 @@ module Net # :nodoc:
# response cannot be written within the write_timeout. Not raised on Windows.
class WriteTimeout < Timeout::Error
+ # :stopdoc:
def initialize(io = nil)
@io = io
end
@@ -484,6 +498,7 @@ module Net # :nodoc:
# The writer adapter class
#
class WriteAdapter
+ # :stopdoc:
def initialize(writer)
@writer = writer
end
diff --git a/lib/open-uri.rb b/lib/open-uri.rb
index de710af261..844865b13a 100644
--- a/lib/open-uri.rb
+++ b/lib/open-uri.rb
@@ -4,22 +4,25 @@ require 'stringio'
require 'time'
module URI
- # Allows the opening of various resources including URIs.
+ # Allows the opening of various resources including URIs. Example:
#
- # If the first argument responds to the 'open' method, 'open' is called on
+ # require "open-uri"
+ # URI.open("http://example.com") { |f| f.read }
+ #
+ # If the first argument responds to the +open+ method, +open+ is called on
# it with the rest of the arguments.
#
# If the first argument is a string that begins with <code>(protocol)://</code>, it is parsed by
- # URI.parse. If the parsed object responds to the 'open' method,
- # 'open' is called on it with the rest of the arguments.
+ # URI.parse. If the parsed object responds to the +open+ method,
+ # +open+ is called on it with the rest of the arguments.
#
# Otherwise, Kernel#open is called.
#
# OpenURI::OpenRead#open provides URI::HTTP#open, URI::HTTPS#open and
# URI::FTP#open, Kernel#open.
#
- # We can accept URIs and strings that begin with http://, https:// and
- # ftp://. In these cases, the opened file object is extended by OpenURI::Meta.
+ # We can accept URIs and strings that begin with <code>http://</code>, <code>https://</code> and
+ # <code>ftp://</code>. In these cases, the opened file object is extended by OpenURI::Meta.
def self.open(name, *rest, &block)
if name.respond_to?(:open)
name.open(*rest, &block)
@@ -91,8 +94,10 @@ end
module OpenURI
+ # The version string
VERSION = "0.5.0"
+ # The default options
Options = {
:proxy => true,
:proxy_http_basic_authentication => true,
@@ -394,24 +399,28 @@ module OpenURI
end
end
+ # Raised on HTTP session failure
class HTTPError < StandardError
- def initialize(message, io)
+ def initialize(message, io) # :nodoc:
super(message)
@io = io
end
+ # StringIO having the received data
attr_reader :io
end
# Raised on redirection,
# only occurs when +redirect+ option for HTTP is +false+.
class HTTPRedirect < HTTPError
- def initialize(message, io, uri)
+ def initialize(message, io, uri) # :nodoc:
super(message, io)
@uri = uri
end
+ # URI to redirect
attr_reader :uri
end
+ # Raised on too many redirection,
class TooManyRedirects < HTTPError
end
diff --git a/lib/open3/version.rb b/lib/open3/version.rb
index bfcec44ccc..322dd71e2a 100644
--- a/lib/open3/version.rb
+++ b/lib/open3/version.rb
@@ -1,3 +1,4 @@
module Open3
+ # The version string
VERSION = "0.2.1"
end
diff --git a/lib/optparse.rb b/lib/optparse.rb
index 06e33db1f5..97178e284b 100644
--- a/lib/optparse.rb
+++ b/lib/optparse.rb
@@ -426,7 +426,9 @@ require 'set' unless defined?(Set)
#
class OptionParser
# The version string
- OptionParser::Version = "0.7.0.dev.2"
+ VERSION = "0.8.1"
+ # An alias for compatibility
+ Version = VERSION
# :stopdoc:
NoArgument = [NO_ARGUMENT = :NONE, nil].freeze
@@ -470,7 +472,6 @@ class OptionParser
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
@@ -560,7 +561,7 @@ class OptionParser
# 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:
+ private def parse_arg(arg) # :nodoc:
pattern or return nil, [arg]
unless m = pattern.match(arg)
yield(InvalidArgument, arg)
@@ -578,14 +579,13 @@ class OptionParser
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:
+ private def conv_arg(arg, val = []) # :nodoc:
v, = *val
if conv
val = conv.call(*val)
@@ -597,7 +597,6 @@ class OptionParser
end
return arg, block, val
end
- private :conv_arg
#
# Produces the summary text. Each line of the summary is yielded to the
@@ -881,14 +880,13 @@ class OptionParser
# +lopts+:: Long style option list.
# +nlopts+:: Negated long style options list.
#
- def update(sw, sopts, lopts, nsw = nil, nlopts = nil) # :nodoc:
+ private 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
@@ -1457,14 +1455,13 @@ XXX
# +prv+:: Previously specified argument.
# +msg+:: Exception message.
#
- def notwice(obj, prv, msg) # :nodoc:
+ private 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:
@@ -1731,7 +1728,7 @@ XXX
parse_in_order(argv, setter, **keywords, &nonopt)
end
- def parse_in_order(argv = default_argv, setter = nil, exact: require_exact, **, &nonopt) # :nodoc:
+ private def parse_in_order(argv = default_argv, setter = nil, exact: require_exact, **, &nonopt) # :nodoc:
opt, arg, val, rest = nil
nonopt ||= proc {|a| throw :terminate, a}
argv.unshift(arg) if arg = catch(:terminate) {
@@ -1822,10 +1819,9 @@ XXX
argv
end
- private :parse_in_order
# Calls callback with _val_.
- def callback!(cb, max_arity, *args) # :nodoc:
+ private def callback!(cb, max_arity, *args) # :nodoc:
args.compact!
if (size = args.size) < max_arity and cb.to_proc.lambda?
@@ -1835,7 +1831,6 @@ XXX
end
cb.call(*args)
end
- private :callback!
#
# Parses command line arguments +argv+ in permutation mode and returns
@@ -1855,7 +1850,7 @@ XXX
#
def permute!(argv = default_argv, **keywords)
nonopts = []
- order!(argv, **keywords, &nonopts.method(:<<))
+ order!(argv, **keywords) {|nonopt| nonopts << nonopt}
argv[0, 0] = nonopts
argv
end
@@ -1908,13 +1903,16 @@ XXX
single_options, *long_options = *args
result = {}
+ setter = (symbolize_names ?
+ ->(name, val) {result[name.to_sym] = val}
+ : ->(name, val) {result[name] = val})
single_options.scan(/(.)(:)?/) do |opt, val|
if val
- result[opt] = nil
+ setter[opt, nil]
define("-#{opt} VAL")
else
- result[opt] = false
+ setter[opt, false]
define("-#{opt}")
end
end if single_options
@@ -1923,16 +1921,16 @@ XXX
arg, desc = arg.split(';', 2)
opt, val = arg.split(':', 2)
if val
- result[opt] = val.empty? ? nil : val
+ setter[opt, (val unless val.empty?)]
define("--#{opt}=#{result[opt] || "VAL"}", *[desc].compact)
else
- result[opt] = false
+ setter[opt, false]
define("--#{opt}", *[desc].compact)
end
end
- parse_in_order(argv, result.method(:[]=), **keywords)
- symbolize_names ? result.transform_keys(&:to_sym) : result
+ parse_in_order(argv, setter, **keywords)
+ result
end
#
@@ -1946,24 +1944,22 @@ XXX
# Traverses @stack, sending each element method +id+ with +args+ and
# +block+.
#
- def visit(id, *args, &block) # :nodoc:
+ private 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:
+ private 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
@@ -1974,7 +1970,7 @@ XXX
# +icase+:: Search case insensitive if true.
# +pat+:: Optional pattern for completion.
#
- def complete(typ, opt, icase = false, *pat) # :nodoc:
+ private def complete(typ, opt, icase = false, *pat) # :nodoc:
if pat.empty?
search(typ, opt) {|sw| return [sw, opt]} # exact match or...
end
@@ -1982,9 +1978,8 @@ XXX
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])
+ raise exc.new(opt, additional: proc {|o| additional_message(typ, o)})
end
- private :complete
#
# Returns additional info.
@@ -2273,9 +2268,10 @@ XXX
argv
end
+ DIR = File.join(__dir__, '')
def self.filter_backtrace(array)
unless $DEBUG
- array.delete_if(&%r"\A#{Regexp.quote(__FILE__)}:"o.method(:=~))
+ array.delete_if {|bt| bt.start_with?(DIR)}
end
array
end
@@ -2318,42 +2314,42 @@ XXX
# Raises when ambiguously completable string is encountered.
#
class AmbiguousOption < ParseError
- const_set(:Reason, 'ambiguous option')
+ Reason = 'ambiguous option' # :nodoc:
end
#
# Raises when there is an argument for a switch which takes no argument.
#
class NeedlessArgument < ParseError
- const_set(:Reason, 'needless argument')
+ Reason = 'needless argument' # :nodoc:
end
#
# Raises when a switch with mandatory argument has no argument.
#
class MissingArgument < ParseError
- const_set(:Reason, 'missing argument')
+ Reason = 'missing argument' # :nodoc:
end
#
# Raises when switch is undefined.
#
class InvalidOption < ParseError
- const_set(:Reason, 'invalid option')
+ Reason = 'invalid option' # :nodoc:
end
#
# Raises when the given argument does not match required format.
#
class InvalidArgument < ParseError
- const_set(:Reason, 'invalid argument')
+ Reason = 'invalid argument' # :nodoc:
end
#
# Raises when the given argument word can't be completed uniquely.
#
class AmbiguousArgument < InvalidArgument
- const_set(:Reason, 'ambiguous argument')
+ Reason = 'ambiguous argument' # :nodoc:
end
#
@@ -2452,9 +2448,11 @@ XXX
# and DecimalNumeric. See Acceptable argument classes (in source code).
#
module Acceptables
- const_set(:DecimalInteger, OptionParser::DecimalInteger)
- const_set(:OctalInteger, OptionParser::OctalInteger)
- const_set(:DecimalNumeric, OptionParser::DecimalNumeric)
+ # :stopdoc:
+ DecimalInteger = OptionParser::DecimalInteger
+ OctalInteger = OptionParser::OctalInteger
+ DecimalNumeric = OptionParser::DecimalNumeric
+ # :startdoc:
end
end
diff --git a/lib/optparse/optparse.gemspec b/lib/optparse/optparse.gemspec
index 6ea6b88395..885b0ec380 100644
--- a/lib/optparse/optparse.gemspec
+++ b/lib/optparse/optparse.gemspec
@@ -3,7 +3,7 @@
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*OptionParser::Version\s*=\s*"(.*)"/ =~ line and break $1
+ /^\s*VERSION\s*=\s*"(.*)"/ =~ line and break $1
end rescue nil
end
diff --git a/lib/pathname.rb b/lib/pathname.rb
index a0da5ed93f..0e51e1fdf6 100644
--- a/lib/pathname.rb
+++ b/lib/pathname.rb
@@ -9,22 +9,77 @@
#
# For documentation, see class Pathname.
#
+class Pathname
-class Pathname # * Find *
+ # :markup: markdown
#
- # Iterates over the directory tree in a depth first manner, yielding a
- # Pathname for each file under "this" directory.
+ # call-seq:
+ # Pathname.find(ignore_error: true) -> nil
#
- # Returns an Enumerator if no block is given.
+ # With a block given, performs a depth-first traversal of the path in `self`;
+ # calls the block with each found path:
#
- # Since it is implemented by the standard library module Find, Find.prune can
- # be used to control the traversal.
+ # ```ruby
+ # paths = []
+ # Pathname('lib').find {|path| paths << path }
+ # paths.size # => 909
+ # paths.take(3)
+ # # =>
+ # # [#<Pathname:lib>,
+ # # #<Pathname:lib/English.gemspec>,
+ # # #<Pathname:lib/English.rb>]
+ # ```
#
- # If +self+ is +.+, yielded pathnames begin with a filename in the
- # current directory, not +./+.
+ # When `self` contains `'.'`, the found paths omit the leading `'./'`:
#
- # See Find.find
+ # ```ruby
+ # paths = []
+ # Dir.chdir('lib') do
+ # Pathname('.').find {|path| paths << path }
+ # end
+ # paths.take(3)
+ # # # =>
+ # # [#<Pathname:.>,
+ # # #<Pathname:English.gemspec>,
+ # # #<Pathname:English.rb>]
+ # ```
#
+ # This method calls method Find.find;
+ # therefore method Find.prune may be used in the block:
+ #
+ # ```ruby
+ # files = []
+ # Pathname('.').find do |path|
+ # Find.prune if File.basename(path) == 'test'
+ # next unless File.file?(path) && File.extname(path) == '.rb'
+ # files << path
+ # end
+ # files.size # => 6690
+ # files.take(3)
+ # # # =>
+ # # [#<Pathname:KNOWNBUGS.rb>,
+ # # #<Pathname:array.rb>,
+ # # #<Pathname:ast.rb>]
+ # ```
+ #
+ # Raises an exception if the path in `self` cannot be read.
+ #
+ # When keyword argument `ignore_error` is given as `true` (the default),
+ # certain exceptions during traversal are ignored (i.e., silently rescued):
+ # Errno::ENOENT, Errno::EACCES, Errno::ENOTDIR, Errno::ELOOP, Errno::ENAMETOOLONG, Errno::EINVAL;
+ # when given as `false`, no exceptions are rescued.
+ #
+ # Note that these exceptions may be ignored only in `Pathname#find` traversal code;
+ # an exception raised before traversal begins,
+ # or raised while in the block is not ignored.
+ # Each of the calls below raises an Errno::ENOENT exception that is not ignored:
+ #
+ # ```ruby
+ # Pathname('nosuch').find { }
+ # Pathname('lib').find {|entry| raise Errno::ENOENT }
+ # ```
+ #
+ # With no block given, returns a new Enumerator.
def find(ignore_error: true) # :yield: pathname
return to_enum(__method__, ignore_error: ignore_error) unless block_given?
require 'find'
@@ -40,6 +95,8 @@ end
class Pathname # * FileUtils *
# Recursively deletes a directory, including all directories beneath it.
#
+ # Note that you need to require 'pathname' to use this method.
+ #
# See FileUtils.rm_rf
def rmtree(noop: nil, verbose: nil, secure: nil)
# The name "rmtree" is borrowed from File::Path of Perl.
@@ -51,9 +108,35 @@ class Pathname # * FileUtils *
end
class Pathname # * tmpdir *
- # Creates a tmp directory and wraps the returned path in a Pathname object.
+ # call-seq:
+ # Pathname.mktmpdir -> new_pathname
+ # Pathname.mktmpdir {|pathname| ... } -> object
+ #
+ # Creates:
+ #
+ # - A temporary directory via Dir.mktmpdir.
+ # - A \Pathname object that contains the path to that directory.
+ #
+ # With no block given, returns the created pathname;
+ # the caller should delete the created directory when it is no longer needed
+ # (FileUtils.rm_r is a convenient method for the deletion):
+ #
+ # pathname = Pathname.mktmpdir
+ # dirpath = pathname.to_s
+ # Dir.exist?(dirpath) # => true
+ # # Do something with the directory.
+ # require 'fileutils'
+ # FileUtils.rm_r(dirpath)
+ #
+ # With a block given, calls the block with the created pathname;
+ # on block exit, automatically deletes the created directory and all its contents;
+ # returns the block's exit value:
#
- # See Dir.mktmpdir
+ # pathname = Pathname.mktmpdir do |p|
+ # # Do something with the directory.
+ # p
+ # end
+ # Dir.exist?(pathname.to_s) # => false
def self.mktmpdir
require 'tmpdir' unless defined?(Dir.mktmpdir)
if block_given?
diff --git a/lib/pp.rb b/lib/pp.rb
index 5318395631..5fd29a373a 100644
--- a/lib/pp.rb
+++ b/lib/pp.rb
@@ -64,7 +64,7 @@ require 'prettyprint'
class PP < PrettyPrint
# The version string
- VERSION = "0.6.2"
+ VERSION = "0.6.3"
# Returns the usable width for +out+.
# As the width of +out+:
@@ -145,21 +145,13 @@ class PP < PrettyPrint
# Yields to a block
# and preserves the previous set of objects being printed.
def guard_inspect_key
- if Thread.current[:__recursive_key__] == nil
- Thread.current[:__recursive_key__] = {}.compare_by_identity
- end
-
- if Thread.current[:__recursive_key__][:inspect] == nil
- Thread.current[:__recursive_key__][:inspect] = {}.compare_by_identity
- end
-
- save = Thread.current[:__recursive_key__][:inspect]
-
+ recursive_state = Thread.current[:__recursive_key__] ||= {}.compare_by_identity
+ save = recursive_state[:inspect] ||= {}.compare_by_identity
begin
- Thread.current[:__recursive_key__][:inspect] = {}.compare_by_identity
+ recursive_state[:inspect] = {}.compare_by_identity
yield
ensure
- Thread.current[:__recursive_key__][:inspect] = save
+ recursive_state[:inspect] = save
end
end
@@ -167,9 +159,8 @@ class PP < PrettyPrint
# to be pretty printed. Used to break cycles in chains of objects to be
# pretty printed.
def check_inspect_key(id)
- Thread.current[:__recursive_key__] &&
- Thread.current[:__recursive_key__][:inspect] &&
- Thread.current[:__recursive_key__][:inspect].include?(id)
+ recursive_state = Thread.current[:__recursive_key__] or return false
+ recursive_state[:inspect]&.include?(id)
end
# Adds the object_id +id+ to the set of objects being pretty printed, so
@@ -183,10 +174,10 @@ class PP < PrettyPrint
Thread.current[:__recursive_key__][:inspect].delete id
end
- private def guard_inspect(object)
+ private def guard_inspect(object) # :nodoc:
recursive_state = Thread.current[:__recursive_key__]
- if recursive_state && recursive_state.key?(:inspect)
+ if recursive_state&.key?(:inspect)
begin
push_inspect_key(object)
yield
@@ -286,7 +277,7 @@ class PP < PrettyPrint
kwsplat ? yield(*v, **kwsplat) : yield(*v)
}
end
- EMPTY_KWHASH = if RUBY_VERSION >= "3.0"
+ EMPTY_KWHASH = if RUBY_VERSION >= "3.0" # :nodoc:
{}.freeze
end
private_constant :EMPTY_KWHASH
@@ -322,12 +313,10 @@ class PP < PrettyPrint
# 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}:"
+ if k.inspect.match?(%r[\A:["$@!]|[%&*+\-\/<=>@\]^`|~]\z])
+ k = k.to_s.inspect
end
+ text "#{k}:"
else
pp k
text ' '
@@ -399,7 +388,8 @@ class PP < PrettyPrint
# This method should return an array of names of instance variables as symbols or strings as:
# +[:@a, :@b]+.
def pretty_print_instance_variables
- instance_variables.sort
+ ivars = respond_to?(:instance_variables_to_inspect, true) ? instance_variables_to_inspect || instance_variables : instance_variables
+ ivars.sort
end
# Is #inspect implementation using #pretty_print.
@@ -442,22 +432,27 @@ class Hash # :nodoc:
end
end
+if defined?(Set)
+ if set_pp = Set.instance_method(:initialize).source_location
+ set_pp = !set_pp.first.end_with?("/set.rb") # not defined in set.rb
+ else
+ set_pp = true # defined in C
+ end
+end
class Set # :nodoc:
def pretty_print(pp) # :nodoc:
- pp.group(1, '#<Set:', '>') {
- pp.breakable
- pp.group(1, '{', '}') {
- pp.seplist(self) { |o|
- pp.pp o
- }
+ pp.group(1, "#{self.class.name}[", ']') {
+ pp.seplist(self) { |o|
+ pp.pp o
}
}
end
def pretty_print_cycle(pp) # :nodoc:
- pp.text sprintf('#<Set: {%s}>', empty? ? '' : '...')
+ name = self.class.name
+ pp.text(empty? ? "#{name}[]" : "#{name}[...]")
end
-end
+end if set_pp
class << ENV # :nodoc:
def pretty_print(q) # :nodoc:
@@ -489,6 +484,13 @@ class Struct # :nodoc:
end
end
+verbose, $VERBOSE = $VERBOSE, nil
+begin
+ has_data_define = defined?(Data.define)
+ensure
+ $VERBOSE = verbose
+end
+
class Data # :nodoc:
def pretty_print(q) # :nodoc:
class_name = PP.mcall(self, Kernel, :class).name
@@ -521,7 +523,7 @@ 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 has_data_define
class Range # :nodoc:
def pretty_print(q) # :nodoc:
diff --git a/lib/prettyprint.rb b/lib/prettyprint.rb
index 6f50192f5d..44ca5e816f 100644
--- a/lib/prettyprint.rb
+++ b/lib/prettyprint.rb
@@ -33,6 +33,7 @@
#
class PrettyPrint
+ # The version string
VERSION = "0.2.0"
# This is a convenience method which is same as follows:
@@ -486,8 +487,10 @@ class PrettyPrint
# It is passed to be similar to a PrettyPrint object itself, by responding to:
# * #text
# * #breakable
+ # * #fill_breakable
# * #nest
# * #group
+ # * #group_sub
# * #flush
# * #first?
#
@@ -521,6 +524,13 @@ class PrettyPrint
@output << sep
end
+ # Appends +sep+ to the text to be output. By default +sep+ is ' '
+ #
+ # +width+ argument is here for compatibility. It is a noop argument.
+ def fill_breakable(sep=' ', width=nil)
+ @output << sep
+ end
+
# Takes +indent+ arg, but does nothing with it.
#
# Yields to a block.
@@ -544,6 +554,15 @@ class PrettyPrint
@first.pop
end
+ # Yields to a block for compatibility.
+ def group_sub # :nodoc:
+ yield
+ end
+
+ # Method present for compatibility, but is a noop
+ def break_outmost_groups # :nodoc:
+ end
+
# Method present for compatibility, but is a noop
def flush # :nodoc:
end
diff --git a/lib/prism.rb b/lib/prism.rb
index dceba4b1f5..8f0342724a 100644
--- a/lib/prism.rb
+++ b/lib/prism.rb
@@ -1,5 +1,7 @@
# frozen_string_literal: true
# :markup: markdown
+#--
+# rbs_inline: enabled
# The Prism Ruby parser.
#
@@ -20,9 +22,8 @@ module Prism
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 :NodeFind, "prism/node_find"
autoload :Pattern, "prism/pattern"
autoload :Reflection, "prism/reflection"
autoload :Relocation, "prism/relocation"
@@ -34,38 +35,91 @@ module Prism
# Some of these constants are not meant to be exposed, so marking them as
# private here.
- private_constant :LexCompat
- private_constant :LexRipper
+ if RUBY_ENGINE != "jruby"
+ private_constant :LexCompat
+ private_constant :NodeFind
+ end
+
+ # Raised when requested to parse as the currently running Ruby version but Prism has no support for it.
+ class CurrentVersionError < ArgumentError
+ # Initialize a new exception for the given ruby version string.
+ #--
+ #: (String version) -> void
+ def initialize(version)
+ message = +"invalid version: Requested to parse as `version: 'current'`; "
+ major, minor, =
+ if version.match?(/\A\d+\.\d+.\d+\z/)
+ version.split(".").map(&:to_i)
+ end
+
+ if major && minor && ((major < 3) || (major == 3 && minor < 3))
+ message << " #{version} is below the minimum supported syntax."
+ else
+ message << " #{version} is unknown. Please update the `prism` gem."
+ end
+
+ super(message)
+ end
+ end
# :call-seq:
- # Prism::lex_compat(source, **options) -> LexCompat::Result
+ # 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.
+ # resembles the return value of Ripper.lex.
#
- # For supported options, see Prism::parse.
+ # For supported options, see Prism.parse.
+ #--
+ #: (String source, **untyped options) -> LexCompat::Result
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, freeze) -> ParseResult
+ # load(source, serialized, freeze) -> ParseResult
#
# Load the serialized AST using the source as a reference into a tree.
+ #--
+ #: (String source, String serialized, ?bool freeze) -> ParseResult
def self.load(source, serialized, freeze = false)
Serialize.load_parse(source, serialized, freeze)
end
+
+ # Given a Method, UnboundMethod, Proc, or Thread::Backtrace::Location,
+ # returns the Prism node representing it. On CRuby, this uses node_id for
+ # an exact match. On other implementations, it falls back to best-effort
+ # matching by source location line number.
+ #--
+ #: (Method | UnboundMethod | Proc | Thread::Backtrace::Location callable, ?rubyvm: bool) -> Node?
+ def self.find(callable, rubyvm: !!defined?(RubyVM))
+ NodeFind.find(callable, rubyvm)
+ end
+
+ # @rbs!
+ # VERSION: String
+ # BACKEND: :CEXT | :FFI
+ #
+ # interface _Stream
+ # def gets: (?Integer integer) -> (String | nil)
+ # end
+ #
+ # def self.parse: (String source, ?filepath: String, ?command_line: String, ?encoding: Encoding | false, ?freeze: bool, ?frozen_string_literal: bool, ?line: Integer, ?main_script: bool, ?partial_script: bool, ?scopes: Array[Array[Symbol]], ?version: String) -> ParseResult
+ # def self.profile: (String source, ?filepath: String, ?command_line: String, ?encoding: Encoding | false, ?freeze: bool, ?frozen_string_literal: bool, ?line: Integer, ?main_script: bool, ?partial_script: bool, ?scopes: Array[Array[Symbol]], ?version: String) -> void
+ # def self.lex: (String source, ?filepath: String, ?command_line: String, ?encoding: Encoding | false, ?freeze: bool, ?frozen_string_literal: bool, ?line: Integer, ?main_script: bool, ?partial_script: bool, ?scopes: Array[Array[Symbol]], ?version: String) -> LexResult
+ # def self.parse_lex: (String source, ?filepath: String, ?command_line: String, ?encoding: Encoding | false, ?freeze: bool, ?frozen_string_literal: bool, ?line: Integer, ?main_script: bool, ?partial_script: bool, ?scopes: Array[Array[Symbol]], ?version: String) -> ParseLexResult
+ # def self.dump: (String source, ?filepath: String, ?command_line: String, ?encoding: Encoding | false, ?freeze: bool, ?frozen_string_literal: bool, ?line: Integer, ?main_script: bool, ?partial_script: bool, ?scopes: Array[Array[Symbol]], ?version: String) -> String
+ # def self.parse_comments: (String source, ?filepath: String, ?command_line: String, ?encoding: Encoding | false, ?freeze: bool, ?frozen_string_literal: bool, ?line: Integer, ?main_script: bool, ?partial_script: bool, ?scopes: Array[Array[Symbol]], ?version: String) -> Array[Comment]
+ # def self.parse_success?: (String source, ?filepath: String, ?command_line: String, ?encoding: Encoding | false, ?freeze: bool, ?frozen_string_literal: bool, ?line: Integer, ?main_script: bool, ?partial_script: bool, ?scopes: Array[Array[Symbol]], ?version: String) -> bool
+ # def self.parse_failure?: (String source, ?filepath: String, ?command_line: String, ?encoding: Encoding | false, ?freeze: bool, ?frozen_string_literal: bool, ?line: Integer, ?main_script: bool, ?partial_script: bool, ?scopes: Array[Array[Symbol]], ?version: String) -> bool
+ # def self.parse_stream: (_Stream stream, ?filepath: String, ?command_line: String, ?encoding: Encoding | false, ?freeze: bool, ?frozen_string_literal: bool, ?line: Integer, ?main_script: bool, ?partial_script: bool, ?scopes: Array[Array[Symbol]], ?version: String) -> ParseResult
+ # def self.parse_file: (String filepath, ?command_line: String, ?encoding: Encoding | false, ?freeze: bool, ?frozen_string_literal: bool, ?line: Integer, ?main_script: bool, ?partial_script: bool, ?scopes: Array[Array[Symbol]], ?version: String) -> ParseResult
+ # def self.profile_file: (String filepath, ?command_line: String, ?encoding: Encoding | false, ?freeze: bool, ?frozen_string_literal: bool, ?line: Integer, ?main_script: bool, ?partial_script: bool, ?scopes: Array[Array[Symbol]], ?version: String) -> void
+ # def self.lex_file: (String filepath, ?command_line: String, ?encoding: Encoding | false, ?freeze: bool, ?frozen_string_literal: bool, ?line: Integer, ?main_script: bool, ?partial_script: bool, ?scopes: Array[Array[Symbol]], ?version: String) -> LexResult
+ # def self.parse_lex_file: (String filepath, ?command_line: String, ?encoding: Encoding | false, ?freeze: bool, ?frozen_string_literal: bool, ?line: Integer, ?main_script: bool, ?partial_script: bool, ?scopes: Array[Array[Symbol]], ?version: String) -> ParseLexResult
+ # def self.dump_file: (String filepath, ?command_line: String, ?encoding: Encoding | false, ?freeze: bool, ?frozen_string_literal: bool, ?line: Integer, ?main_script: bool, ?partial_script: bool, ?scopes: Array[Array[Symbol]], ?version: String) -> String
+ # def self.parse_file_comments: (String filepath, ?command_line: String, ?encoding: Encoding | false, ?freeze: bool, ?frozen_string_literal: bool, ?line: Integer, ?main_script: bool, ?partial_script: bool, ?scopes: Array[Array[Symbol]], ?version: String) -> Array[Comment]
+ # def self.parse_file_success?: (String filepath, ?command_line: String, ?encoding: Encoding | false, ?freeze: bool, ?frozen_string_literal: bool, ?line: Integer, ?main_script: bool, ?partial_script: bool, ?scopes: Array[Array[Symbol]], ?version: String) -> bool
+ # def self.parse_file_failure?: (String filepath, ?command_line: String, ?encoding: Encoding | false, ?freeze: bool, ?frozen_string_literal: bool, ?line: Integer, ?main_script: bool, ?partial_script: bool, ?scopes: Array[Array[Symbol]], ?version: String) -> bool
end
require_relative "prism/polyfill/byteindex"
diff --git a/lib/prism/desugar_compiler.rb b/lib/prism/desugar_compiler.rb
index 5d7d38d841..c64d03f64a 100644
--- a/lib/prism/desugar_compiler.rb
+++ b/lib/prism/desugar_compiler.rb
@@ -1,12 +1,18 @@
# frozen_string_literal: true
# :markup: markdown
+#--
+# rbs_inline: enabled
module Prism
class DesugarAndWriteNode # :nodoc:
include DSL
- attr_reader :node, :default_source, :read_class, :write_class, :arguments
+ attr_reader :node #: ClassVariableAndWriteNode | ConstantAndWriteNode | GlobalVariableAndWriteNode | InstanceVariableAndWriteNode | LocalVariableAndWriteNode
+ attr_reader :default_source #: Source
+ attr_reader :read_class, :write_class #: Symbol
+ attr_reader :arguments #: Hash[Symbol, untyped]
+ #: ((ClassVariableAndWriteNode | ConstantAndWriteNode | GlobalVariableAndWriteNode | InstanceVariableAndWriteNode | LocalVariableAndWriteNode) node, Source default_source, Symbol read_class, Symbol write_class, **untyped arguments) -> void
def initialize(node, default_source, read_class, write_class, **arguments)
@node = node
@default_source = default_source
@@ -16,6 +22,8 @@ module Prism
end
# Desugar `x &&= y` to `x && x = y`
+ #--
+ #: () -> node
def compile
and_node(
location: node.location,
@@ -36,8 +44,12 @@ module Prism
class DesugarOrWriteDefinedNode # :nodoc:
include DSL
- attr_reader :node, :default_source, :read_class, :write_class, :arguments
+ attr_reader :node #: ClassVariableOrWriteNode | ConstantOrWriteNode | GlobalVariableOrWriteNode
+ attr_reader :default_source #: Source
+ attr_reader :read_class, :write_class #: Symbol
+ attr_reader :arguments #: Hash[Symbol, untyped]
+ #: ((ClassVariableOrWriteNode | ConstantOrWriteNode | GlobalVariableOrWriteNode) node, Source default_source, Symbol read_class, Symbol write_class, **untyped arguments) -> void
def initialize(node, default_source, read_class, write_class, **arguments)
@node = node
@default_source = default_source
@@ -47,6 +59,8 @@ module Prism
end
# Desugar `x ||= y` to `defined?(x) ? x : x = y`
+ #--
+ #: () -> node
def compile
if_node(
location: node.location,
@@ -87,8 +101,12 @@ module Prism
class DesugarOperatorWriteNode # :nodoc:
include DSL
- attr_reader :node, :default_source, :read_class, :write_class, :arguments
+ attr_reader :node #: ClassVariableOperatorWriteNode | ConstantOperatorWriteNode | GlobalVariableOperatorWriteNode | InstanceVariableOperatorWriteNode | LocalVariableOperatorWriteNode
+ attr_reader :default_source #: Source
+ attr_reader :read_class, :write_class #: Symbol
+ attr_reader :arguments #: Hash[Symbol, untyped]
+ #: ((ClassVariableOperatorWriteNode | ConstantOperatorWriteNode | GlobalVariableOperatorWriteNode | InstanceVariableOperatorWriteNode | LocalVariableOperatorWriteNode) node, Source default_source, Symbol read_class, Symbol write_class, **untyped arguments) -> void
def initialize(node, default_source, read_class, write_class, **arguments)
@node = node
@default_source = default_source
@@ -98,6 +116,8 @@ module Prism
end
# Desugar `x += y` to `x = x + y`
+ #--
+ #: () -> node
def compile
binary_operator_loc = node.binary_operator_loc.chop
@@ -131,8 +151,12 @@ module Prism
class DesugarOrWriteNode # :nodoc:
include DSL
- attr_reader :node, :default_source, :read_class, :write_class, :arguments
+ attr_reader :node #: InstanceVariableOrWriteNode | LocalVariableOrWriteNode
+ attr_reader :default_source #: Source
+ attr_reader :read_class, :write_class #: Symbol
+ attr_reader :arguments #: Hash[Symbol, untyped]
+ #: ((InstanceVariableOrWriteNode | LocalVariableOrWriteNode) node, Source default_source, Symbol read_class, Symbol write_class, **untyped arguments) -> void
def initialize(node, default_source, read_class, write_class, **arguments)
@node = node
@default_source = default_source
@@ -142,6 +166,8 @@ module Prism
end
# Desugar `x ||= y` to `x || x = y`
+ #--
+ #: () -> node
def compile
or_node(
location: node.location,
@@ -162,90 +188,105 @@ module Prism
private_constant :DesugarAndWriteNode, :DesugarOrWriteNode, :DesugarOrWriteDefinedNode, :DesugarOperatorWriteNode
class ClassVariableAndWriteNode
+ #: () -> node
def desugar # :nodoc:
DesugarAndWriteNode.new(self, source, :class_variable_read_node, :class_variable_write_node, name: name).compile
end
end
class ClassVariableOrWriteNode
+ #: () -> node
def desugar # :nodoc:
DesugarOrWriteDefinedNode.new(self, source, :class_variable_read_node, :class_variable_write_node, name: name).compile
end
end
class ClassVariableOperatorWriteNode
+ #: () -> node
def desugar # :nodoc:
DesugarOperatorWriteNode.new(self, source, :class_variable_read_node, :class_variable_write_node, name: name).compile
end
end
class ConstantAndWriteNode
+ #: () -> node
def desugar # :nodoc:
DesugarAndWriteNode.new(self, source, :constant_read_node, :constant_write_node, name: name).compile
end
end
class ConstantOrWriteNode
+ #: () -> node
def desugar # :nodoc:
DesugarOrWriteDefinedNode.new(self, source, :constant_read_node, :constant_write_node, name: name).compile
end
end
class ConstantOperatorWriteNode
+ #: () -> node
def desugar # :nodoc:
DesugarOperatorWriteNode.new(self, source, :constant_read_node, :constant_write_node, name: name).compile
end
end
class GlobalVariableAndWriteNode
+ #: () -> node
def desugar # :nodoc:
DesugarAndWriteNode.new(self, source, :global_variable_read_node, :global_variable_write_node, name: name).compile
end
end
class GlobalVariableOrWriteNode
+ #: () -> node
def desugar # :nodoc:
DesugarOrWriteDefinedNode.new(self, source, :global_variable_read_node, :global_variable_write_node, name: name).compile
end
end
class GlobalVariableOperatorWriteNode
+ #: () -> node
def desugar # :nodoc:
DesugarOperatorWriteNode.new(self, source, :global_variable_read_node, :global_variable_write_node, name: name).compile
end
end
class InstanceVariableAndWriteNode
+ #: () -> node
def desugar # :nodoc:
DesugarAndWriteNode.new(self, source, :instance_variable_read_node, :instance_variable_write_node, name: name).compile
end
end
class InstanceVariableOrWriteNode
+ #: () -> node
def desugar # :nodoc:
DesugarOrWriteNode.new(self, source, :instance_variable_read_node, :instance_variable_write_node, name: name).compile
end
end
class InstanceVariableOperatorWriteNode
+ #: () -> node
def desugar # :nodoc:
DesugarOperatorWriteNode.new(self, source, :instance_variable_read_node, :instance_variable_write_node, name: name).compile
end
end
class LocalVariableAndWriteNode
+ #: () -> node
def desugar # :nodoc:
DesugarAndWriteNode.new(self, source, :local_variable_read_node, :local_variable_write_node, name: name, depth: depth).compile
end
end
class LocalVariableOrWriteNode
+ #: () -> node
def desugar # :nodoc:
DesugarOrWriteNode.new(self, source, :local_variable_read_node, :local_variable_write_node, name: name, depth: depth).compile
end
end
class LocalVariableOperatorWriteNode
+ #: () -> node
def desugar # :nodoc:
DesugarOperatorWriteNode.new(self, source, :local_variable_read_node, :local_variable_write_node, name: name, depth: depth).compile
end
@@ -254,137 +295,167 @@ module Prism
# 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
+ # `@@foo &&= bar`
#
# becomes
#
- # @@foo && @@foo = bar
+ # `@@foo && @@foo = bar`
+ #--
+ #: (ClassVariableAndWriteNode node) -> node
def visit_class_variable_and_write_node(node)
node.desugar
end
- # @@foo ||= bar
+ # `@@foo ||= bar`
#
# becomes
#
- # defined?(@@foo) ? @@foo : @@foo = bar
+ # `defined?(@@foo) ? @@foo : @@foo = bar`
+ #--
+ #: (ClassVariableOrWriteNode node) -> node
def visit_class_variable_or_write_node(node)
node.desugar
end
- # @@foo += bar
+ # `@@foo += bar`
#
# becomes
#
- # @@foo = @@foo + bar
+ # `@@foo = @@foo + bar`
+ #--
+ #: (ClassVariableOperatorWriteNode node) -> node
def visit_class_variable_operator_write_node(node)
node.desugar
end
- # Foo &&= bar
+ # `Foo &&= bar`
#
# becomes
#
- # Foo && Foo = bar
+ # `Foo && Foo = bar`
+ #--
+ #: (ConstantAndWriteNode node) -> node
def visit_constant_and_write_node(node)
node.desugar
end
- # Foo ||= bar
+ # `Foo ||= bar`
#
# becomes
#
- # defined?(Foo) ? Foo : Foo = bar
+ # `defined?(Foo) ? Foo : Foo = bar`
+ #--
+ #: (ConstantOrWriteNode node) -> node
def visit_constant_or_write_node(node)
node.desugar
end
- # Foo += bar
+ # `Foo += bar`
#
# becomes
#
- # Foo = Foo + bar
+ # `Foo = Foo + bar`
+ #--
+ #: (ConstantOperatorWriteNode node) -> node
def visit_constant_operator_write_node(node)
node.desugar
end
- # $foo &&= bar
+ # `$foo &&= bar`
#
# becomes
#
- # $foo && $foo = bar
+ # `$foo && $foo = bar`
+ #--
+ #: (GlobalVariableAndWriteNode node) -> node
def visit_global_variable_and_write_node(node)
node.desugar
end
- # $foo ||= bar
+ # `$foo ||= bar`
#
# becomes
#
- # defined?($foo) ? $foo : $foo = bar
+ # `defined?($foo) ? $foo : $foo = bar`
+ #--
+ #: (GlobalVariableOrWriteNode node) -> node
def visit_global_variable_or_write_node(node)
node.desugar
end
- # $foo += bar
+ # `$foo += bar`
#
# becomes
#
- # $foo = $foo + bar
+ # `$foo = $foo + bar`
+ #--
+ #: (GlobalVariableOperatorWriteNode node) -> node
def visit_global_variable_operator_write_node(node)
node.desugar
end
- # @foo &&= bar
+ # `@foo &&= bar`
#
# becomes
#
- # @foo && @foo = bar
+ # `@foo && @foo = bar`
+ #--
+ #: (InstanceVariableAndWriteNode node) -> node
def visit_instance_variable_and_write_node(node)
node.desugar
end
- # @foo ||= bar
+ # `@foo ||= bar`
#
# becomes
#
- # @foo || @foo = bar
+ # `@foo || @foo = bar`
+ #--
+ #: (InstanceVariableOrWriteNode node) -> node
def visit_instance_variable_or_write_node(node)
node.desugar
end
- # @foo += bar
+ # `@foo += bar`
#
# becomes
#
- # @foo = @foo + bar
+ # `@foo = @foo + bar`
+ #--
+ #: (InstanceVariableOperatorWriteNode node) -> node
def visit_instance_variable_operator_write_node(node)
node.desugar
end
- # foo &&= bar
+ # `foo &&= bar`
#
# becomes
#
- # foo && foo = bar
+ # `foo && foo = bar`
+ #--
+ #: (LocalVariableAndWriteNode node) -> node
def visit_local_variable_and_write_node(node)
node.desugar
end
- # foo ||= bar
+ # `foo ||= bar`
#
# becomes
#
- # foo || foo = bar
+ # `foo || foo = bar`
+ #--
+ #: (LocalVariableOrWriteNode node) -> node
def visit_local_variable_or_write_node(node)
node.desugar
end
- # foo += bar
+ # `foo += bar`
#
# becomes
#
- # foo = foo + bar
+ # `foo = foo + bar`
+ #--
+ #: (LocalVariableOperatorWriteNode node) -> node
def visit_local_variable_operator_write_node(node)
node.desugar
end
diff --git a/lib/prism/ffi.rb b/lib/prism/ffi.rb
index 5ae177055f..6b9bde51ea 100644
--- a/lib/prism/ffi.rb
+++ b/lib/prism/ffi.rb
@@ -12,7 +12,7 @@ require "ffi"
# autoloaded from within a non-main Ractor.
require "prism/serialize" if defined?(Ractor)
-module Prism
+module Prism # :nodoc:
module LibRubyParser # :nodoc:
extend FFI::Library
@@ -59,6 +59,9 @@ module Prism
# We only want to load the functions that we are interested in.
next unless functions.any? { |function| line.include?(function) }
+ # Strip trailing attributes (PRISM_NODISCARD, PRISM_NONNULL(...), etc.)
+ line = line.sub(/\)(\s+PRISM_\w+(?:\([^)]*\))?)+\s*;/, ");")
+
# Parse the function declaration.
unless /^PRISM_EXPORTED_FUNCTION (?<return_type>.+) (?<name>\w+)\((?<arg_types>.+)\);$/ =~ line
raise "Could not parse #{line}"
@@ -85,30 +88,44 @@ module Prism
raise "Could not find functions #{functions.inspect}" unless functions.empty?
end
- callback :pm_parse_stream_fgets_t, [:pointer, :int, :pointer], :pointer
- callback :pm_parse_stream_feof_t, [:pointer], :int
- enum :pm_string_init_result_t, %i[PM_STRING_INIT_SUCCESS PM_STRING_INIT_ERROR_GENERIC PM_STRING_INIT_ERROR_DIRECTORY]
+ callback :pm_source_stream_fgets_t, [:pointer, :int, :pointer], :pointer
+ callback :pm_source_stream_feof_t, [:pointer], :int
+ pm_source_init_result_values = %i[PM_SOURCE_INIT_SUCCESS PM_SOURCE_INIT_ERROR_GENERIC PM_SOURCE_INIT_ERROR_DIRECTORY PM_SOURCE_INIT_ERROR_NON_REGULAR]
+ enum :pm_source_init_result_t, pm_source_init_result_values
enum :pm_string_query_t, [:PM_STRING_QUERY_ERROR, -1, :PM_STRING_QUERY_FALSE, :PM_STRING_QUERY_TRUE]
+ # Ractor-safe lookup table for pm_source_init_result_t, since FFI's
+ # enum_type accesses module instance variables that are not shareable.
+ SOURCE_INIT_RESULT = pm_source_init_result_values.freeze
+
load_exported_functions_from(
- "prism.h",
+ "prism/version.h",
"pm_version",
+ []
+ )
+
+ load_exported_functions_from(
+ "prism/serialize.h",
"pm_serialize_parse",
"pm_serialize_parse_stream",
"pm_serialize_parse_comments",
"pm_serialize_lex",
"pm_serialize_parse_lex",
- "pm_parse_success_p",
+ "pm_serialize_parse_success_p",
+ []
+ )
+
+ load_exported_functions_from(
+ "prism/string_query.h",
"pm_string_query_local",
"pm_string_query_constant",
"pm_string_query_method_name",
- [:pm_parse_stream_fgets_t, :pm_parse_stream_feof_t]
+ []
)
load_exported_functions_from(
- "prism/util/pm_buffer.h",
- "pm_buffer_sizeof",
- "pm_buffer_init",
+ "prism/buffer.h",
+ "pm_buffer_new",
"pm_buffer_value",
"pm_buffer_length",
"pm_buffer_free",
@@ -116,20 +133,19 @@ module Prism
)
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",
- []
+ "prism/source.h",
+ "pm_source_file_new",
+ "pm_source_mapped_new",
+ "pm_source_stream_new",
+ "pm_source_free",
+ "pm_source_source",
+ "pm_source_length",
+ [:pm_source_stream_fgets_t, :pm_source_stream_feof_t]
)
# 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)
@@ -151,20 +167,20 @@ module Prism
# 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)
+ buffer = LibRubyParser.pm_buffer_new
+ raise unless buffer
+
+ begin
+ yield new(buffer)
ensure
- LibRubyParser.pm_buffer_free(pointer)
+ LibRubyParser.pm_buffer_free(buffer)
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
-
+ # This object represents source code to be parsed. For strings it wraps a
+ # pointer directly; for files it uses a pm_source_t under the hood.
+ class PrismSource # :nodoc:
PLATFORM_EXPECTS_UTF8 =
RbConfig::CONFIG["host_os"].match?(/bccwin|cygwin|djgpp|mingw|mswin|wince|darwin/i)
@@ -181,7 +197,7 @@ module Prism
@pointer.read_string(@length)
end
- # Yields a pm_string_t pointer to the given block.
+ # Yields a PrismSource backed by the given string to the block.
def self.with_string(string)
raise TypeError unless string.is_a?(String)
@@ -195,32 +211,38 @@ module Prism
end
end
- # Yields a pm_string_t pointer to the given block.
+ # Yields a PrismSource to the given block, backed by a pm_source_t.
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.
+ # passing them into pm_source_mapped_new.
if PLATFORM_EXPECTS_UTF8 && (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)
+ FFI::MemoryPointer.new(:int) do |result_ptr|
+ pm_source = LibRubyParser.pm_source_mapped_new(filepath, 0, result_ptr)
+
+ case SOURCE_INIT_RESULT[result_ptr.read_int]
+ when :PM_SOURCE_INIT_SUCCESS
+ pointer = LibRubyParser.pm_source_source(pm_source)
+ length = LibRubyParser.pm_source_length(pm_source)
return yield new(pointer, length, false)
- when :PM_STRING_INIT_ERROR_GENERIC
+ when :PM_SOURCE_INIT_ERROR_GENERIC
raise SystemCallError.new(filepath, FFI.errno)
- when :PM_STRING_INIT_ERROR_DIRECTORY
+ when :PM_SOURCE_INIT_ERROR_DIRECTORY
raise Errno::EISDIR.new(filepath)
+ when :PM_SOURCE_INIT_ERROR_NON_REGULAR
+ # Fall back to reading the file through Ruby IO for non-regular
+ # files (pipes, character devices, etc.)
+ return with_string(File.read(filepath)) { |string| yield string }
else
- raise "Unknown error initializing pm_string_t: #{result.inspect}"
+ raise "Unknown error initializing pm_source_t: #{result_ptr.read_int}"
end
ensure
- LibRubyParser.pm_string_free(pm_string)
+ LibRubyParser.pm_source_free(pm_source) if pm_source && !pm_source.null?
end
end
end
@@ -236,29 +258,29 @@ module Prism
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) }
+ LibRubyParser::PrismSource.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) }
+ LibRubyParser::PrismSource.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) }
+ LibRubyParser::PrismSource.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) }
+ LibRubyParser::PrismSource.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) }
+ LibRubyParser::PrismSource.with_string(code) { |string| parse_common(string, code, options) }
end
# Mirror the Prism.parse_file API by using the serialization API. This uses
@@ -266,7 +288,7 @@ module Prism
# when it is available.
def parse_file(filepath, **options)
options[:filepath] = filepath
- LibRubyParser::PrismString.with_file(filepath) { |string| parse_common(string, string.read, options) }
+ LibRubyParser::PrismSource.with_file(filepath) { |string| parse_common(string, string.read, options) }
end
# Mirror the Prism.parse_stream API by using the serialization API.
@@ -284,19 +306,19 @@ module Prism
eof_callback = -> (_) { stream.eof? }
- # 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, eof_callback, dump_options(options))
- Prism.load(source, buffer.read, options.fetch(:freeze, false))
+ pm_source = LibRubyParser.pm_source_stream_new(nil, callback, eof_callback)
+ begin
+ LibRubyParser.pm_serialize_parse_stream(buffer.pointer, pm_source, dump_options(options))
+ Prism.load(source, buffer.read, options.fetch(:freeze, false))
+ ensure
+ LibRubyParser.pm_source_free(pm_source) if pm_source && !pm_source.null?
+ end
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) }
+ LibRubyParser::PrismSource.with_string(code) { |string| parse_comments_common(string, code, options) }
end
# Mirror the Prism.parse_file_comments API by using the serialization
@@ -304,23 +326,23 @@ module Prism
# 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) }
+ LibRubyParser::PrismSource.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) }
+ LibRubyParser::PrismSource.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) }
+ LibRubyParser::PrismSource.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) }
+ LibRubyParser::PrismSource.with_string(code) { |string| parse_file_success_common(string, options) }
end
# Mirror the Prism.parse_failure? API by using the serialization API.
@@ -331,7 +353,7 @@ module Prism
# 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) }
+ LibRubyParser::PrismSource.with_file(filepath) { |string| parse_file_success_common(string, options) }
end
# Mirror the Prism.parse_file_failure? API by using the serialization API.
@@ -341,7 +363,7 @@ module Prism
# Mirror the Prism.profile API by using the serialization API.
def profile(source, **options)
- LibRubyParser::PrismString.with_string(source) do |string|
+ LibRubyParser::PrismSource.with_string(source) do |string|
LibRubyParser::PrismBuffer.with do |buffer|
LibRubyParser.pm_serialize_parse(buffer.pointer, string.pointer, string.length, dump_options(options))
nil
@@ -351,7 +373,7 @@ module Prism
# Mirror the Prism.profile_file API by using the serialization API.
def profile_file(filepath, **options)
- LibRubyParser::PrismString.with_file(filepath) do |string|
+ LibRubyParser::PrismSource.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))
@@ -400,7 +422,7 @@ module Prism
end
def parse_file_success_common(string, options) # :nodoc:
- LibRubyParser.pm_parse_success_p(string.pointer, string.length, dump_options(options))
+ LibRubyParser.pm_serialize_parse_success_p(string.pointer, string.length, dump_options(options))
end
# Return the value that should be dumped for the command_line option.
@@ -424,16 +446,35 @@ module Prism
# Return the value that should be dumped for the version option.
def dump_options_version(version)
case version
- when nil, "latest"
+ when "current"
+ version_string_to_number(RUBY_VERSION) || raise(CurrentVersionError, RUBY_VERSION)
+ when "latest", nil
0 # Handled in pm_parser_init
+ when "nearest"
+ dump = version_string_to_number(RUBY_VERSION)
+ return dump if dump
+ if RUBY_VERSION < "3.3"
+ version_string_to_number("3.3")
+ else
+ 0 # Handled in pm_parser_init
+ end
+ else
+ version_string_to_number(version) || raise(ArgumentError, "invalid version: #{version}")
+ end
+ end
+
+ # Converts a version string like "4.0.0" or "4.0" into a number.
+ # Returns nil if the version is unknown.
+ def version_string_to_number(version)
+ case version
when /\A3\.3(\.\d+)?\z/
1
when /\A3\.4(\.\d+)?\z/
2
- when /\A3\.5(\.\d+)?\z/
+ when /\A3\.5(\.\d+)?\z/, /\A4\.0(\.\d+)?\z/
3
- else
- raise ArgumentError, "invalid version: #{version}"
+ when /\A4\.1(\.\d+)?\z/
+ 4
end
end
@@ -535,7 +576,7 @@ module Prism
# Here we are going to patch StringQuery to put in the class-level methods so
# that it can maintain a consistent interface
- class StringQuery
+ class StringQuery # :nodoc:
class << self
# Mirrors the C extension's StringQuery::local? method.
def local?(string)
diff --git a/lib/prism/lex_compat.rb b/lib/prism/lex_compat.rb
index 9b3f025ab6..7aacec037d 100644
--- a/lib/prism/lex_compat.rb
+++ b/lib/prism/lex_compat.rb
@@ -1,29 +1,64 @@
# frozen_string_literal: true
# :markup: markdown
-
-require "delegate"
-require "ripper"
+#--
+# rbs_inline: enabled
module Prism
+ # @rbs!
+ # module Translation
+ # class Ripper
+ # EXPR_NONE: Integer
+ # EXPR_BEG: Integer
+ # EXPR_MID: Integer
+ # EXPR_END: Integer
+ # EXPR_CLASS: Integer
+ # EXPR_VALUE: Integer
+ # EXPR_ARG: Integer
+ # EXPR_CMDARG: Integer
+ # EXPR_ENDARG: Integer
+ # EXPR_ENDFN: Integer
+ #
+ # class Lexer < Ripper
+ # class State
+ # def self.[]: (Integer value) -> State
+ # end
+ # end
+ #
+ # class LineAndColumnCache
+ # def initialize: (Source source) -> void
+ #
+ # def line_and_column: (Integer byte_offset) -> [Integer, Integer]
+ # end
+ # end
+ # end
+
# 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:
+ # @rbs!
+ # # A token produced by the Ripper lexer that Prism is replicating.
+ # type lex_compat_token = [[Integer, Integer], Symbol, String, untyped]
+
# 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
+ attr_reader :value #: Array[lex_compat_token]
# Create a new lex compat result object with the given values.
- def initialize(value, comments, magic_comments, data_loc, errors, warnings, source)
+ #--
+ #: (Array[lex_compat_token] value, Array[Comment] comments, Array[MagicComment] magic_comments, Location? data_loc, Array[ParseError] errors, Array[ParseWarning] warnings, bool continuable, Source source) -> void
+ def initialize(value, comments, magic_comments, data_loc, errors, warnings, continuable, source)
@value = value
- super(comments, magic_comments, data_loc, errors, warnings, source)
+ super(comments, magic_comments, data_loc, errors, warnings, continuable, source)
end
# Implement the hash pattern matching interface for Result.
- def deconstruct_keys(keys)
+ #--
+ #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
+ def deconstruct_keys(keys) # :nodoc:
super.merge!(value: value)
end
end
@@ -105,6 +140,7 @@ module Prism
KEYWORD_DEF: :on_kw,
KEYWORD_DEFINED: :on_kw,
KEYWORD_DO: :on_kw,
+ KEYWORD_DO_BLOCK: :on_kw,
KEYWORD_DO_LOOP: :on_kw,
KEYWORD_ELSE: :on_kw,
KEYWORD_ELSIF: :on_kw,
@@ -199,93 +235,6 @@ module Prism
"__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.
@@ -295,16 +244,19 @@ module Prism
# 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
+ attr_reader :tokens #: Array[lex_compat_token]
+ #: () -> void
def initialize
@tokens = []
end
+ #: (lex_compat_token token) -> void
def <<(token)
tokens << token
end
+ #: () -> Array[lex_compat_token]
def to_a
tokens
end
@@ -314,22 +266,26 @@ module Prism
# 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
+ attr_reader :split #: bool
+ attr_reader :tokens #: Array[lex_compat_token]
+ #: (bool split) -> void
def initialize(split)
@split = split
@tokens = []
end
+ #: (lex_compat_token token) -> void
def <<(token)
tokens << token
end
+ #: () -> Array[lex_compat_token]
def to_a
embexpr_balance = 0
- tokens.each_with_object([]) do |token, results| #$ Array[Token]
- case token.event
+ tokens.each_with_object([]) do |token, results| #$ Array[lex_compat_token]
+ case token[1]
when :on_embexpr_beg
embexpr_balance += 1
results << token
@@ -344,9 +300,9 @@ module Prism
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|
+ token[2].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])
+ results << [[lineno, column], :on_tstring_content, value, token[3]]
lineno += value.count("\n")
end
else
@@ -375,8 +331,13 @@ module Prism
class DedentingHeredoc # :nodoc:
TAB_WIDTH = 8
- attr_reader :tokens, :dedent_next, :dedent, :embexpr_balance
+ attr_reader :tokens #: Array[lex_compat_token]
+ attr_reader :dedent_next #: bool
+ attr_reader :dedent #: Integer?
+ attr_reader :embexpr_balance #: Integer
+ # @rbs @ended_on_newline: bool
+ #: () -> void
def initialize
@tokens = []
@dedent_next = true
@@ -388,8 +349,10 @@ module Prism
# 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.
+ #
+ #: (lex_compat_token token) -> void
def <<(token)
- case token.event
+ case token[1]
when :on_embexpr_beg, :on_heredoc_beg
@embexpr_balance += 1
@dedent = 0 if @dedent_next && @ended_on_newline
@@ -397,10 +360,10 @@ module Prism
@embexpr_balance -= 1
when :on_tstring_content
if embexpr_balance == 0
- line = token.value
+ line = token[2]
if dedent_next && !(line.strip.empty? && line.end_with?("\n"))
- leading = line[/\A(\s*)\n?/, 1]
+ leading = line[/\A(\s*)\n?/, 1] #: String
next_dedent = 0
leading.each_char do |char|
@@ -420,20 +383,21 @@ module Prism
end
end
- @dedent_next = token.event == :on_tstring_content && embexpr_balance == 0
+ @dedent_next = token[1] == :on_tstring_content && embexpr_balance == 0
@ended_on_newline = false
tokens << token
end
+ #: () -> Array[lex_compat_token]
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]
+ results = [] #: Array[lex_compat_token]
embexpr_balance = 0
tokens.each do |token|
- case token.event
+ case token[1]
when :on_embexpr_beg, :on_heredoc_beg
embexpr_balance += 1
results << token
@@ -445,9 +409,9 @@ module Prism
lineno = token[0][0]
column = token[0][1]
- token.value.split(/(?<=\n)/).each_with_index do |value, index|
+ token[2].split(/(?<=\n)/).each_with_index do |value, index|
column = 0 if index > 0
- results << Token.new([[lineno, column], :on_tstring_content, value, token.state])
+ results << [[lineno, column], :on_tstring_content, value, token[3]]
lineno += 1
end
else
@@ -464,7 +428,7 @@ module Prism
# 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]
+ results = [] #: Array[lex_compat_token]
embexpr_balance = 0
index = 0
@@ -475,15 +439,15 @@ module Prism
results << token
index += 1
- case token.event
+ case token[1]
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
+ while index < max_index && tokens[index][1] == :on_tstring_content && !token[2].match?(/\\\r?\n\z/)
+ token[2] << tokens[index][2]
index += 1
end
end
@@ -497,7 +461,7 @@ module Prism
# 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]
+ results = [] #: Array[lex_compat_token]
dedent_next = true
embexpr_balance = 0
@@ -506,7 +470,7 @@ module Prism
# 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
+ case token[1]
when :on_embexpr_beg
embexpr_balance += 1
results << token
@@ -518,7 +482,7 @@ module Prism
# 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)/)
+ splits = token[2].split(/(?<=\n)/)
index = 0
while index < splits.length
@@ -536,7 +500,8 @@ module Prism
# 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
+ unjoined = splits[index..] #: Array[String]
+ line = unjoined.join
index = splits.length
end
@@ -575,12 +540,12 @@ module Prism
ignored = deleted_chars.join
line.delete_prefix!(ignored)
- results << Token.new([[lineno, 0], :on_ignored_sp, ignored, token[3]])
+ results << [[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?
+ results << [[lineno, column], token[1], line, token[3]] unless line.empty?
index += 1
end
else
@@ -591,7 +556,7 @@ module Prism
end
dedent_next =
- ((token.event == :on_tstring_content) || (token.event == :on_heredoc_end)) &&
+ ((token[1] == :on_tstring_content) || (token[1] == :on_heredoc_end)) &&
embexpr_balance == 0
end
@@ -601,12 +566,14 @@ module Prism
# Here we will split between the two types of heredocs and return the
# object that will store their tokens.
+ #--
+ #: (lex_compat_token opening) -> (PlainHeredoc | DashHeredoc | DedentingHeredoc)
def self.build(opening)
- case opening.value[2]
+ case opening[2][2]
when "~"
DedentingHeredoc.new
when "-"
- DashHeredoc.new(opening.value[3] != "'")
+ DashHeredoc.new(opening[2][3] != "'")
else
PlainHeredoc.new
end
@@ -615,33 +582,43 @@ module Prism
private_constant :Heredoc
- attr_reader :source, :options
+ # 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.
+ BOM_FLUSHED = RUBY_VERSION >= "3.3.0"
+ private_constant :BOM_FLUSHED
+ attr_reader :options #: Hash[Symbol, untyped]
+ # @rbs @source: String
+
+ #: (String source, **untyped options) -> void
def initialize(source, **options)
@source = source
@options = options
end
+ #: () -> Result
def result
- tokens = [] #: Array[LexCompat::Token]
+ tokens = [] #: Array[lex_compat_token]
state = :default
heredoc_stack = [[]] #: Array[Array[Heredoc::PlainHeredoc | Heredoc::DashHeredoc | Heredoc::DedentingHeredoc]]
- result = Prism.lex(source, **options)
+ result = Prism.lex(@source, **options)
+ source = result.source
result_value = result.value
- previous_state = nil #: Ripper::Lexer::State?
+ previous_state = nil #: Translation::Ripper::Lexer::State?
last_heredoc_end = nil #: Integer?
+ eof_token = nil #: Token?
+
+ bom = source.slice(0, 3) == "\xEF\xBB\xBF"
- # 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 |(prism_token, prism_state), index|
+ lineno = prism_token.location.start_line
+ column = prism_token.location.start_column
- result_value.each_with_index do |(token, lex_state), index|
- lineno = token.location.start_line
- column = token.location.start_column
+ event = RIPPER.fetch(prism_token.type)
+ value = prism_token.value
+ lex_state = Translation::Ripper::Lexer::State[prism_state]
# 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
@@ -651,70 +628,53 @@ module Prism
if bom && lineno == 1
column -= 3
- if index == 0 && column == 0 && !bom_flushed
+ if index == 0 && column == 0 && !BOM_FLUSHED
flushed =
- case token.type
+ case prism_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?("%")
+ 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 =
+ lex_compat_token =
case event
when :on___end__
- EndContentToken.new([[lineno, column], event, value, lex_state])
+ # 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.
+ value = value[0..value.index("\n")] #: String
+ [[lineno, column], event, value, lex_state]
when :on_comment
- IgnoreStateToken.new([[lineno, column], event, value, lex_state])
+ [[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
+ last_heredoc_end = prism_token.location.end_offset
+ [[lineno, column], event, value, lex_state]
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])
+ [[lineno, column], event, value, lex_state]
+ when :on_words_sep
+ # Ripper emits one token each per line.
+ value.each_line.with_index do |line, index|
+ if index > 0
+ lineno += 1
+ column = 0
+ end
+ tokens << [[lineno, column], event, line, lex_state]
+ end
+ tokens.pop #: lex_compat_token
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
@@ -739,13 +699,14 @@ module Prism
counter += { on_embexpr_beg: -1, on_embexpr_end: 1 }[current_event] || 0
end
- Ripper::Lexer::State.new(result_value[current_index][1])
+ Translation::Ripper::Lexer::State[result_value[current_index][1]]
else
previous_state
end
- Token.new([[lineno, column], event, value, lex_state])
+ [[lineno, column], event, value, lex_state]
when :on_eof
+ eof_token = prism_token
previous_token = result_value[index - 1][0]
# If we're at the end of the file and the previous token was a
@@ -760,7 +721,7 @@ module Prism
# 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
+ end_offset = prism_token.location.start_offset
if start_offset < end_offset
if bom
@@ -768,14 +729,14 @@ module Prism
end_offset += 3
end
- tokens << Token.new([[lineno, 0], :on_nl, source.byteslice(start_offset...end_offset), lex_state])
+ tokens << [[lineno, 0], :on_nl, source.slice(start_offset, end_offset - start_offset), lex_state]
end
end
- Token.new([[lineno, column], event, value, lex_state])
+ [[lineno, column], event, value, lex_state]
else
- Token.new([[lineno, column], event, value, lex_state])
- end
+ [[lineno, column], event, value, lex_state]
+ end #: lex_compat_token
previous_state = lex_state
@@ -792,19 +753,19 @@ module Prism
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
+ tokens << lex_compat_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)
+ heredoc_stack.last << Heredoc.build(lex_compat_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
+ heredoc_stack.last.last << lex_compat_token
case event
when :on_heredoc_beg
@@ -812,7 +773,7 @@ module Prism
# 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)]
+ heredoc_stack << [Heredoc.build(lex_compat_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
@@ -821,10 +782,10 @@ module Prism
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 %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 = heredoc_stack.pop #: Array[Heredoc::PlainHeredoc | Heredoc::DashHeredoc | Heredoc::DedentingHeredoc]
+ heredoc_stack.last.last << lex_compat_token
flushing.each do |heredoc|
heredoc.to_a.each do |flushed_token|
@@ -836,12 +797,12 @@ module Prism
next
end
elsif event == :on_heredoc_beg
- tokens << token
+ tokens << lex_compat_token
state = :heredoc_opened
- heredoc_stack.last << Heredoc.build(token)
+ heredoc_stack.last << Heredoc.build(lex_compat_token)
next
elsif heredoc_stack.size > 1
- heredoc_stack[-2].last << token
+ heredoc_stack[-2].last << lex_compat_token
next
end
@@ -852,77 +813,94 @@ module Prism
heredoc_stack.last.clear
state = :default
- tokens << token
+ tokens << lex_compat_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
+ # Drop the EOF token from the list. The EOF token may not be
+ # present if the source was syntax invalid
+ if tokens.dig(-1, 1) == :on_eof
+ tokens = tokens[0...-1] #: Array[lex_compat_token]
+ end
- private_constant :LexCompat
+ # We sort by location because Ripper.lex sorts.
+ tokens.sort_by! do |token|
+ line, column = token[0]
+ source.byte_offset(line, column)
+ end
- # This is a class that wraps the Ripper lexer to produce almost exactly the
- # same tokens.
- class LexRipper # :nodoc:
- attr_reader :source
+ tokens = post_process_tokens(tokens, source, result.data_loc, bom, eof_token)
- def initialize(source)
- @source = source
+ Result.new(tokens, result.comments, result.magic_comments, result.data_loc, result.errors, result.warnings, result.continuable?, 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]
+ private
+
+ #: (Array[lex_compat_token] tokens, Source source, Location? data_loc, bool bom, Token? eof_token) -> Array[lex_compat_token]
+ def post_process_tokens(tokens, source, data_loc, bom, eof_token)
+ new_tokens = [] #: Array[lex_compat_token]
+
+ prev_token_state = Translation::Ripper::Lexer::State[Translation::Ripper::EXPR_BEG]
+ prev_token_end = bom ? 3 : 0
+
+ cache = Translation::Ripper::LineAndColumnCache.new(source)
+
+ tokens.each do |token|
+ # Skip missing heredoc ends.
+ next if token[1] == :on_heredoc_end && token[2] == ""
+
+ # Add :on_sp tokens.
+ line, column = token[0]
+ start_offset = source.byte_offset(line, column)
+
+ # Ripper reports columns on line 1 without counting the BOM, so we
+ # adjust to get the real offset
+ start_offset += 3 if line == 1 && bom
+
+ if start_offset > prev_token_end
+ sp_value = source.slice(prev_token_end, start_offset - prev_token_end)
+ sp_line, sp_column = cache.line_and_column(prev_token_end)
+ # Ripper reports columns on line 1 without counting the BOM
+ sp_column -= 3 if sp_line == 1 && bom
+ continuation_index = sp_value.byteindex("\\")
+
+ # ripper emits up to three :on_sp tokens when line continuations are used
+ if continuation_index
+ next_whitespace_index = continuation_index + 1
+ next_whitespace_index += 1 if sp_value.byteslice(next_whitespace_index) == "\r"
+ next_whitespace_index += 1
+ first_whitespace = sp_value[0...continuation_index] #: String
+ continuation = sp_value[continuation_index...next_whitespace_index] #: String
+ second_whitespace = sp_value[next_whitespace_index..] || ""
+
+ new_tokens << [[sp_line, sp_column], :on_sp, first_whitespace, prev_token_state] unless first_whitespace.empty?
+ new_tokens << [[sp_line, sp_column + continuation_index], :on_sp, continuation, prev_token_state]
+ new_tokens << [[sp_line + 1, 0], :on_sp, second_whitespace, prev_token_state] unless second_whitespace.empty?
else
- results << token
- previous = token
+ new_tokens << [[sp_line, sp_column], :on_sp, sp_value, prev_token_state]
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)
+ new_tokens << token
+ prev_token_state = token[3]
+ prev_token_end = start_offset + token[2].bytesize
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?
+
+ if !data_loc && eof_token # no trailing :on_sp with __END__ as it is always preceded by :on_nl
+ end_offset = eof_token.location.end_offset
+ if prev_token_end < end_offset
+ new_tokens << [
+ [source.line(prev_token_end), source.column(prev_token_end)],
+ :on_sp,
+ source.slice(prev_token_end, end_offset - prev_token_end),
+ prev_token_state
+ ]
end
end
+
+ new_tokens
end
end
- private_constant :LexRipper
+ private_constant :LexCompat
end
diff --git a/lib/prism/node_ext.rb b/lib/prism/node_ext.rb
index 469e54ca0c..8a6624e76d 100644
--- a/lib/prism/node_ext.rb
+++ b/lib/prism/node_ext.rb
@@ -1,5 +1,7 @@
# frozen_string_literal: true
# :markup: markdown
+#--
+# rbs_inline: enabled
#--
# Here we are reopening the prism module to provide methods on nodes that aren't
@@ -7,9 +9,9 @@
#++
module Prism
class Node
+ #: (*String replacements) -> void
def deprecated(*replacements) # :nodoc:
- location = caller_locations(1, 1)
- location = location[0].label if location
+ location = caller_locations(1, 1)&.[](0)&.label
suggest = replacements.map { |replacement| "#{self.class}##{replacement}" }
warn(<<~MSG, uplevel: 1, category: :deprecated)
@@ -23,7 +25,9 @@ module Prism
module RegularExpressionOptions # :nodoc:
# Returns a numeric value that represents the flags that were used to create
# the regular expression.
- def options
+ #--
+ #: (Integer flags) -> Integer
+ def self.options(flags)
o = 0
o |= Regexp::IGNORECASE if flags.anybits?(RegularExpressionFlags::IGNORE_CASE)
o |= Regexp::EXTENDED if flags.anybits?(RegularExpressionFlags::EXTENDED)
@@ -35,43 +39,87 @@ module Prism
end
class InterpolatedMatchLastLineNode < Node
- include RegularExpressionOptions
+ # Returns a numeric value that represents the flags that were used to create
+ # the regular expression.
+ #--
+ #: () -> Integer
+ def options
+ RegularExpressionOptions.options(flags)
+ end
end
class InterpolatedRegularExpressionNode < Node
- include RegularExpressionOptions
+ # Returns a numeric value that represents the flags that were used to create
+ # the regular expression.
+ #--
+ #: () -> Integer
+ def options
+ RegularExpressionOptions.options(flags)
+ end
end
class MatchLastLineNode < Node
- include RegularExpressionOptions
+ # Returns a numeric value that represents the flags that were used to create
+ # the regular expression.
+ #--
+ #: () -> Integer
+ def options
+ RegularExpressionOptions.options(flags)
+ end
end
class RegularExpressionNode < Node
- include RegularExpressionOptions
+ # Returns a numeric value that represents the flags that were used to create
+ # the regular expression.
+ #--
+ #: () -> Integer
+ def options
+ RegularExpressionOptions.options(flags)
+ end
end
private_constant :RegularExpressionOptions
module HeredocQuery # :nodoc:
# Returns true if this node was represented as a heredoc in the source code.
- def heredoc?
+ #--
+ #: (String? opening) -> bool?
+ def self.heredoc?(opening)
+ # @type self: InterpolatedStringNode | InterpolatedXStringNode | StringNode | XStringNode
opening&.start_with?("<<")
end
end
class InterpolatedStringNode < Node
- include HeredocQuery
+ # Returns true if this node was represented as a heredoc in the source code.
+ #--
+ #: () -> bool?
+ def heredoc?
+ HeredocQuery.heredoc?(opening)
+ end
end
class InterpolatedXStringNode < Node
- include HeredocQuery
+ # Returns true if this node was represented as a heredoc in the source code.
+ #--
+ #: () -> bool?
+ def heredoc?
+ HeredocQuery.heredoc?(opening)
+ end
end
class StringNode < Node
- include HeredocQuery
+ # Returns true if this node was represented as a heredoc in the source code.
+ #--
+ #: () -> bool?
+ def heredoc?
+ HeredocQuery.heredoc?(opening)
+ end
# Occasionally it's helpful to treat a string as if it were interpolated so
# that there's a consistent interface for working with strings.
+ #--
+ #: () -> InterpolatedStringNode
def to_interpolated
InterpolatedStringNode.new(
source,
@@ -86,10 +134,17 @@ module Prism
end
class XStringNode < Node
- include HeredocQuery
+ # Returns true if this node was represented as a heredoc in the source code.
+ #--
+ #: () -> bool?
+ def heredoc?
+ HeredocQuery.heredoc?(opening)
+ end
# Occasionally it's helpful to treat a string as if it were interpolated so
# that there's a consistent interface for working with strings.
+ #--
+ #: () -> InterpolatedXStringNode
def to_interpolated
InterpolatedXStringNode.new(
source,
@@ -107,6 +162,8 @@ module Prism
class ImaginaryNode < Node
# Returns the value of the node as a Ruby Complex.
+ #--
+ #: () -> Complex
def value
Complex(0, numeric.value)
end
@@ -114,31 +171,25 @@ module Prism
class RationalNode < Node
# Returns the value of the node as a Ruby Rational.
+ #--
+ #: () -> 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]
+ #--
+ #: () -> Array[Symbol]
def full_name_parts
[name]
end
# Returns the full name of this constant. For example: "Foo"
+ #--
+ #: () -> String
def full_name
name.to_s
end
@@ -147,11 +198,15 @@ module Prism
class ConstantWriteNode < Node
# Returns the list of parts for the full name of this constant.
# For example: [:Foo]
+ #--
+ #: () -> Array[Symbol]
def full_name_parts
[name]
end
# Returns the full name of this constant. For example: "Foo"
+ #--
+ #: () -> String
def full_name
name.to_s
end
@@ -166,13 +221,15 @@ module Prism
# local variable
class DynamicPartsInConstantPathError < StandardError; end
- # An error class raised when missing nodes are found while computing a
+ # An error class raised when error recovery 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
+ class ErrorRecoveryNodesInConstantPathError < StandardError; end
# Returns the list of parts for the full name of this constant path.
# For example: [:Foo, :Bar]
+ #--
+ #: () -> Array[Symbol]
def full_name_parts
parts = [] #: Array[Symbol]
current = self #: node?
@@ -180,7 +237,7 @@ module Prism
while current.is_a?(ConstantPathNode)
name = current.name
if name.nil?
- raise MissingNodesInConstantPathError, "Constant path contains missing nodes. Cannot compute full name"
+ raise ErrorRecoveryNodesInConstantPathError, "Constant path contains error recovery nodes. Cannot compute full name"
end
parts.unshift(name)
@@ -195,30 +252,21 @@ module Prism
end
# Returns the full name of this constant path. For example: "Foo::Bar"
+ #--
+ #: () -> String
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]
+ #--
+ #: () -> Array[Symbol]
def full_name_parts
parts =
- case parent
+ case (parent = self.parent)
when ConstantPathNode, ConstantReadNode
parent.full_name_parts
when nil
@@ -228,40 +276,33 @@ module Prism
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"
+ if (name = self.name).nil?
+ raise ConstantPathNode::ErrorRecoveryNodesInConstantPathError, "Constant target path contains error recovery nodes. Cannot compute full name"
end
parts.push(name)
end
# Returns the full name of this constant path. For example: "Foo::Bar"
+ #--
+ #: () -> String
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]
+ #--
+ #: () -> Array[Symbol]
def full_name_parts
[name]
end
# Returns the full name of this constant. For example: "Foo"
+ #--
+ #: () -> String
def full_name
name.to_s
end
@@ -269,6 +310,8 @@ module Prism
class ParametersNode < Node
# Mirrors the Method#parameters method.
+ #--
+ #: () -> Array[[Symbol, Symbol] | [Symbol]]
def signature
names = [] #: Array[[Symbol, Symbol] | [Symbol]]
@@ -278,7 +321,7 @@ module Prism
optionals.each { |param| names << [:opt, param.name] }
- if rest && rest.is_a?(RestParameterNode)
+ if (rest = self.rest).is_a?(RestParameterNode)
names << [:rest, rest.name || :*]
end
@@ -286,8 +329,7 @@ module Prism
case param
when MultiTargetNode
names << [:req]
- when NoKeywordsParameterNode, KeywordRestParameterNode, ForwardingParameterNode
- # Invalid syntax, e.g. "def f(**nil, ...)" moves the NoKeywordsParameterNode to posts
+ when ErrorRecoveryNode
raise "Invalid syntax"
else
names << [:req, param.name]
@@ -307,7 +349,7 @@ module Prism
keyopt.each { |param| names << [:key, param.name] }
- case keyword_rest
+ case (keyword_rest = self.keyword_rest)
when ForwardingParameterNode
names.concat([[:rest, :*], [:keyrest, :**], [:block, :&]])
when KeywordRestParameterNode
@@ -316,7 +358,13 @@ module Prism
names << [:nokey]
end
- names << [:block, block.name || :&] if block
+ case (block = self.block)
+ when BlockParameterNode
+ names << [:block, block.name || :&]
+ when NoBlockParameterNode
+ names << [:noblock]
+ end
+
names
end
end
@@ -331,181 +379,10 @@ module Prism
# 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.
+ #--
+ #: () -> Location?
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/node_find.rb b/lib/prism/node_find.rb
new file mode 100644
index 0000000000..697ee430e8
--- /dev/null
+++ b/lib/prism/node_find.rb
@@ -0,0 +1,185 @@
+# frozen_string_literal: true
+# :markup: markdown
+#--
+# rbs_inline: enabled
+
+module Prism
+ # Finds the Prism AST node corresponding to a given Method, UnboundMethod,
+ # Proc, or Thread::Backtrace::Location. On CRuby, uses node_id from the
+ # instruction sequence for an exact match. On other implementations, falls
+ # back to best-effort matching by source location line number.
+ #
+ # This module is autoloaded so that programs that don't use Prism.find don't
+ # pay for its definition.
+ module NodeFind # :nodoc:
+ # Find the node for the given callable or backtrace location.
+ #--
+ #: (Method | UnboundMethod | Proc | Thread::Backtrace::Location callable, bool rubyvm) -> Node?
+ def self.find(callable, rubyvm)
+ case callable
+ when Proc
+ if rubyvm
+ RubyVMCallableFind.new.find(callable)
+ elsif callable.lambda?
+ LineLambdaFind.new.find(callable)
+ else
+ LineProcFind.new.find(callable)
+ end
+ when Method, UnboundMethod
+ if rubyvm
+ RubyVMCallableFind.new.find(callable)
+ else
+ LineMethodFind.new.find(callable)
+ end
+ when Thread::Backtrace::Location
+ if rubyvm
+ RubyVMBacktraceLocationFind.new.find(callable)
+ else
+ LineBacktraceLocationFind.new.find(callable)
+ end
+ else
+ raise ArgumentError, "Expected a Method, UnboundMethod, Proc, or Thread::Backtrace::Location, got #{callable.class}"
+ end
+ end
+
+ # Base class that handles parsing a file.
+ class Find
+ private
+
+ # Parse the given file path, returning a ParseResult or nil.
+ #--
+ #: (String? file) -> ParseResult?
+ def parse_file(file)
+ return unless file && File.readable?(file)
+ result = Prism.parse_file(file)
+ result if result.success?
+ end
+ end
+
+ # Finds the AST node for a Method, UnboundMethod, or Proc using the node_id
+ # from the instruction sequence.
+ class RubyVMCallableFind < Find
+ # Find the node for the given callable using the ISeq node_id.
+ #--
+ #: (Method | UnboundMethod | Proc callable) -> Node?
+ def find(callable)
+ return unless (source_location = callable.source_location)
+ return unless (result = parse_file(source_location[0]))
+ return unless (iseq = RubyVM::InstructionSequence.of(callable))
+
+ header = iseq.to_a[4]
+ return unless header[:parser] == :prism
+
+ result.value.find { |node| node.node_id == header[:node_id] }
+ end
+ end
+
+ # Finds the AST node for a Thread::Backtrace::Location using the node_id
+ # from the backtrace location.
+ class RubyVMBacktraceLocationFind < Find
+ # Find the node for the given backtrace location using node_id.
+ #--
+ #: (Thread::Backtrace::Location location) -> Node?
+ def find(location)
+ file = location.absolute_path || location.path
+ return unless (result = parse_file(file))
+ return unless RubyVM::AbstractSyntaxTree.respond_to?(:node_id_for_backtrace_location)
+
+ node_id = RubyVM::AbstractSyntaxTree.node_id_for_backtrace_location(location)
+
+ result.value.find { |node| node.node_id == node_id }
+ end
+ end
+
+ # Finds the AST node for a Method or UnboundMethod using best-effort line
+ # matching. Used on non-CRuby implementations.
+ class LineMethodFind < Find
+ # Find the node for the given method by matching on name and line.
+ #--
+ #: (Method | UnboundMethod callable) -> Node?
+ def find(callable)
+ return unless (source_location = callable.source_location)
+ return unless (result = parse_file(source_location[0]))
+
+ name = callable.name
+ start_line = source_location[1]
+
+ result.value.find do |node|
+ case node
+ when DefNode
+ node.name == name && node.location.start_line == start_line
+ when CallNode
+ node.block.is_a?(BlockNode) && node.location.start_line == start_line
+ else
+ false
+ end
+ end
+ end
+ end
+
+ # Finds the AST node for a lambda using best-effort line matching. Used
+ # on non-CRuby implementations.
+ class LineLambdaFind < Find
+ # Find the node for the given lambda by matching on line.
+ #--
+ #: (Proc callable) -> Node?
+ def find(callable)
+ return unless (source_location = callable.source_location)
+ return unless (result = parse_file(source_location[0]))
+
+ start_line = source_location[1]
+
+ result.value.find do |node|
+ case node
+ when LambdaNode
+ node.location.start_line == start_line
+ when CallNode
+ node.block.is_a?(BlockNode) && node.location.start_line == start_line
+ else
+ false
+ end
+ end
+ end
+ end
+
+ # Finds the AST node for a non-lambda Proc using best-effort line
+ # matching. Used on non-CRuby implementations.
+ class LineProcFind < Find
+ # Find the node for the given proc by matching on line.
+ #--
+ #: (Proc callable) -> Node?
+ def find(callable)
+ return unless (source_location = callable.source_location)
+ return unless (result = parse_file(source_location[0]))
+
+ start_line = source_location[1]
+
+ result.value.find do |node|
+ case node
+ when ForNode
+ node.location.start_line == start_line
+ when CallNode
+ node.block.is_a?(BlockNode) && node.location.start_line == start_line
+ else
+ false
+ end
+ end
+ end
+ end
+
+ # Finds the AST node for a Thread::Backtrace::Location using best-effort
+ # line matching. Used on non-CRuby implementations.
+ class LineBacktraceLocationFind < Find
+ # Find the node for the given backtrace location by matching on line.
+ #--
+ #: (Thread::Backtrace::Location location) -> Node?
+ def find(location)
+ file = location.absolute_path || location.path
+ return unless (result = parse_file(file))
+
+ start_line = location.lineno
+ result.value.find { |node| node.location.start_line == start_line }
+ end
+ end
+ end
+end
diff --git a/lib/prism/pack.rb b/lib/prism/pack.rb
deleted file mode 100644
index 166c04c3c0..0000000000
--- a/lib/prism/pack.rb
+++ /dev/null
@@ -1,230 +0,0 @@
-# frozen_string_literal: true
-# :markup: markdown
-# 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
index 05c14e33f5..93d3c006b7 100644
--- a/lib/prism/parse_result.rb
+++ b/lib/prism/parse_result.rb
@@ -1,7 +1,16 @@
# frozen_string_literal: true
# :markup: markdown
+#--
+# rbs_inline: enabled
module Prism
+ # @rbs!
+ # # An internal interface for a cache that can be used to compute code
+ # # units from byte offsets.
+ # interface _CodeUnitsCache
+ # def []: (Integer byte_offset) -> Integer
+ # end
+
# 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.
@@ -10,7 +19,18 @@ module Prism
# 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 = [])
+ #
+ # Note that if you are calling this method manually, you will need to supply
+ # the start_line and offsets parameters. start_line is the line number that
+ # the source starts on, which is typically 1 but can be different if this
+ # source is a subset of a larger source or if this is an eval. offsets is an
+ # array of byte offsets for the start of each line in the source code, which
+ # can be calculated by iterating through the source code and recording the
+ # byte offset whenever a newline character is encountered. The first
+ # element is always 0 to mark the first line.
+ #--
+ #: (String source, Integer start_line, Array[Integer] offsets) -> Source
+ def self.for(source, start_line, offsets)
if source.ascii_only?
ASCIISource.new(source, start_line, offsets)
elsif source.encoding == Encoding::BINARY
@@ -34,77 +54,122 @@ module Prism
end
# The source code that this source object represents.
- attr_reader :source
+ attr_reader :source #: String
# 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 = [])
+ attr_reader :start_line #: Integer
+
+ # The list of newline byte offsets in the source code. When initialized from
+ # the C extension, this may be a packed binary string of uint32_t values
+ # that is lazily unpacked on first access.
+ #--
+ #: () -> Array[Integer]
+ def offsets
+ offsets = @offsets
+ return offsets if offsets.is_a?(Array)
+ @offsets = offsets.unpack("L*")
+ end
+
+ # Create a new source object with the given source code. The offsets
+ # parameter can be either an Array of Integer byte offsets or a packed
+ # binary string of uint32_t values (from the C extension).
+ #--
+ #: (String source, Integer start_line, Array[Integer] | String offsets) -> void
+ def initialize(source, start_line, offsets)
@source = source
- @start_line = start_line # set after parsing is done
- @offsets = offsets # set after parsing is done
+ @start_line = start_line
+ @offsets = offsets
end
# Replace the value of start_line with the given value.
+ #--
+ #: (Integer start_line) -> void
def replace_start_line(start_line)
@start_line = start_line
end
# Replace the value of offsets with the given value.
+ #--
+ #: (Array[Integer] offsets) -> void
def replace_offsets(offsets)
- @offsets.replace(offsets)
+ @offsets = offsets
end
# Returns the encoding of the source code, which is set by parameters to the
# parser or by the encoding magic comment.
+ #--
+ #: () -> Encoding
def encoding
source.encoding
end
# Returns the lines of the source code as an array of strings.
+ #--
+ #: () -> Array[String]
def lines
source.lines
end
# Perform a byteslice on the source code using the given byte offset and
# byte length.
+ #--
+ #: (Integer byte_offset, Integer length) -> String
def slice(byte_offset, length)
source.byteslice(byte_offset, length) or raise
end
+ # Converts the line number and column in bytes to a byte offset.
+ #--
+ #: (Integer line, Integer column) -> Integer
+ def byte_offset(line, column)
+ normal = line - @start_line
+ raise IndexError if normal < 0
+ offsets.fetch(normal) + column
+ rescue IndexError
+ raise ArgumentError, "line #{line} is out of range"
+ end
+
# Binary search through the offsets to find the line number for the given
# byte offset.
+ #--
+ #: (Integer byte_offset) -> Integer
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.
+ #--
+ #: (Integer byte_offset) -> Integer
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.
+ #--
+ #: (Integer byte_offset) -> Integer
def line_end(byte_offset)
offsets[find_line(byte_offset) + 1] || source.bytesize
end
- # Return the column number for the given byte offset.
+ # Return the column in bytes for the given byte offset.
+ #--
+ #: (Integer byte_offset) -> Integer
def column(byte_offset)
byte_offset - line_start(byte_offset)
end
# Return the character offset for the given byte offset.
+ #--
+ #: (Integer byte_offset) -> Integer
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.
+ # Return the column in characters for the given byte offset.
+ #--
+ #: (Integer byte_offset) -> Integer
def character_column(byte_offset)
character_offset(byte_offset) - character_offset(line_start(byte_offset))
end
@@ -121,7 +186,11 @@ module Prism
# possible that the given byte offset will not occur on a character
# boundary. Second, it's possible that the source code will contain a
# character that has no equivalent in the given encoding.
+ #--
+ #: (Integer byte_offset, Encoding encoding) -> Integer
def code_units_offset(byte_offset, encoding)
+ return byte_offset if encoding == Encoding::UTF_8
+
byteslice = (source.byteslice(0, byte_offset) or raise).encode(encoding, invalid: :replace, undef: :replace)
if encoding == Encoding::UTF_16LE || encoding == Encoding::UTF_16BE
@@ -133,43 +202,36 @@ module Prism
# Generate a cache that targets a specific encoding for calculating code
# unit offsets.
+ #--
+ #: (Encoding encoding) -> CodeUnitsCache
def code_units_cache(encoding)
CodeUnitsCache.new(source, encoding)
end
- # Returns the column number in code units for the given encoding for the
+ # Returns the column in code units for the given encoding for the
# given byte offset.
+ #--
+ #: (Integer byte_offset, Encoding encoding) -> Integer
def code_units_column(byte_offset, encoding)
code_units_offset(byte_offset, encoding) - code_units_offset(line_start(byte_offset), encoding)
end
# Freeze this object and the objects it contains.
+ #--
+ #: () -> void
def deep_freeze
source.freeze
offsets.freeze
freeze
end
- private
-
- # Binary search through the offsets to find the line number for the given
+ # Binary search through the offsets to find the index 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
+ #--
+ #: (Integer byte_offset) -> Integer
+ def find_line(byte_offset) # :nodoc:
+ index = offsets.bsearch_index { |offset| offset > byte_offset } || offsets.length
+ index - 1
end
end
@@ -188,38 +250,69 @@ module Prism
# has not yet been implemented.
#
class CodeUnitsCache
+ # Counter used for UTF-8, where one code unit equals one byte.
+ class UTF8Counter # :nodoc:
+ #: (Integer byte_offset, Integer byte_length) -> Integer
+ def count(byte_offset, byte_length)
+ byte_length
+ end
+ end
+
class UTF16Counter # :nodoc:
+ # @rbs @source: String
+ # @rbs @encoding: Encoding
+
+ #: (String source, Encoding encoding) -> void
def initialize(source, encoding)
@source = source
@encoding = encoding
end
+ #: (Integer byte_offset, Integer byte_length) -> Integer
def count(byte_offset, byte_length)
- @source.byteslice(byte_offset, byte_length).encode(@encoding, invalid: :replace, undef: :replace).bytesize / 2
+ (@source.byteslice(byte_offset, byte_length) or raise).encode(@encoding, invalid: :replace, undef: :replace).bytesize / 2
end
end
- class LengthCounter # :nodoc:
+ # Counter used for UTF-32, where one code unit equals one code point and
+ # matches String#length. Also used as a best-effort fallback for any other
+ # encoding that does not have a dedicated counter.
+ class UTF32Counter # :nodoc:
+ # @rbs @source: String
+ # @rbs @encoding: Encoding
+
+ #: (String source, Encoding encoding) -> void
def initialize(source, encoding)
@source = source
@encoding = encoding
end
+ #: (Integer byte_offset, Integer byte_length) -> Integer
def count(byte_offset, byte_length)
- @source.byteslice(byte_offset, byte_length).encode(@encoding, invalid: :replace, undef: :replace).length
+ (@source.byteslice(byte_offset, byte_length) or raise).encode(@encoding, invalid: :replace, undef: :replace).length
end
end
- private_constant :UTF16Counter, :LengthCounter
+ private_constant :UTF8Counter, :UTF16Counter, :UTF32Counter
+
+ # @rbs @source: String
+ # @rbs @counter: UTF8Counter | UTF16Counter | UTF32Counter
+ # @rbs @cache: Hash[Integer, Integer]
+ # @rbs @offsets: Array[Integer]
# Initialize a new cache with the given source and encoding.
+ #--
+ #: (String source, Encoding encoding) -> void
def initialize(source, encoding)
@source = source
@counter =
- if encoding == Encoding::UTF_16LE || encoding == Encoding::UTF_16BE
+ case encoding
+ when Encoding::UTF_8
+ UTF8Counter.new
+ when Encoding::UTF_16LE, Encoding::UTF_16BE
UTF16Counter.new(source, encoding)
else
- LengthCounter.new(source, encoding)
+ UTF32Counter.new(source, encoding)
end
@cache = {} #: Hash[Integer, Integer]
@@ -227,6 +320,8 @@ module Prism
end
# Retrieve the code units offset from the given byte offset.
+ #--
+ #: (Integer byte_offset) -> Integer
def [](byte_offset)
@cache[byte_offset] ||=
if (index = @offsets.bsearch_index { |offset| offset > byte_offset }).nil?
@@ -253,11 +348,15 @@ module Prism
# at that point we will treat everything as single-byte characters.
class ASCIISource < Source
# Return the character offset for the given byte offset.
+ #--
+ #: (Integer byte_offset) -> Integer
def character_offset(byte_offset)
byte_offset
end
- # Return the column number in characters for the given byte offset.
+ # Return the column in characters for the given byte offset.
+ #--
+ #: (Integer byte_offset) -> Integer
def character_column(byte_offset)
byte_offset - line_start(byte_offset)
end
@@ -268,6 +367,8 @@ module Prism
# 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.
+ #--
+ #: (Integer byte_offset, Encoding encoding) -> Integer
def code_units_offset(byte_offset, encoding)
byte_offset
end
@@ -275,6 +376,8 @@ module Prism
# Returns a cache that is the identity function in order to maintain the
# same interface. We can do this because code units are always equivalent to
# byte offsets for ASCII-only sources.
+ #--
+ #: (Encoding encoding) -> _CodeUnitsCache
def code_units_cache(encoding)
->(byte_offset) { byte_offset }
end
@@ -282,6 +385,8 @@ module Prism
# 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`.
+ #--
+ #: (Integer byte_offset, Encoding encoding) -> Integer
def code_units_column(byte_offset, encoding)
byte_offset - line_start(byte_offset)
end
@@ -291,18 +396,23 @@ module Prism
class Location
# A Source object that is used to determine more information from the given
# offset and length.
- attr_reader :source
+ attr_reader :source #: Source
protected :source
# The byte offset from the beginning of the source where this location
# starts.
- attr_reader :start_offset
+ attr_reader :start_offset #: Integer
# The length of this location in bytes.
- attr_reader :length
+ attr_reader :length #: Integer
+
+ # @rbs @leading_comments: Array[Comment]?
+ # @rbs @trailing_comments: Array[Comment]?
# Create a new location object with the given source, start byte offset, and
# byte length.
+ #--
+ #: (Source source, Integer start_offset, Integer length) -> void
def initialize(source, start_offset, length)
@source = source
@start_offset = start_offset
@@ -317,53 +427,73 @@ module Prism
# These are the comments that are associated with this location that exist
# before the start of this location.
+ #--
+ #: () -> Array[Comment]
def leading_comments
@leading_comments ||= []
end
# Attach a comment to the leading comments of this location.
+ #--
+ #: (Comment comment) -> void
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.
+ #--
+ #: () -> Array[Comment]
def trailing_comments
@trailing_comments ||= []
end
# Attach a comment to the trailing comments of this location.
+ #--
+ #: (Comment comment) -> void
def trailing_comment(comment)
trailing_comments << comment
end
# Returns all comments that are associated with this location (both leading
# and trailing comments).
+ #--
+ #: () -> Array[Comment]
def comments
- [*@leading_comments, *@trailing_comments]
+ [*@leading_comments, *@trailing_comments] #: Array[Comment]
end
# Create a new location object with the given options.
+ #--
+ #: (?source: Source, ?start_offset: Integer, ?length: Integer) -> Location
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.
+ #--
+ #: () -> Location
def chop
copy(length: length == 0 ? length : length - 1)
end
# Returns a string representation of this location.
- def inspect
+ #--
+ #: () -> String
+ def inspect # :nodoc:
"#<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.
+ #--
+ #: () -> Array[String]
def source_lines
source.lines
end
# The source code that this location represents.
+ #--
+ #: () -> String
def slice
source.slice(start_offset, length)
end
@@ -371,6 +501,8 @@ module Prism
# 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.
+ #--
+ #: () -> String
def slice_lines
line_start = source.line_start(start_offset)
line_end = source.line_end(end_offset)
@@ -379,118 +511,160 @@ module Prism
# The character offset from the beginning of the source where this location
# starts.
+ #--
+ #: () -> Integer
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.
+ #--
+ #: (Encoding encoding) -> Integer
def start_code_units_offset(encoding = Encoding::UTF_16LE)
source.code_units_offset(start_offset, encoding)
end
# The start offset from the start of the file in code units using the given
# cache to fetch or calculate the value.
+ #--
+ #: (_CodeUnitsCache cache) -> Integer
def cached_start_code_units_offset(cache)
cache[start_offset]
end
# The byte offset from the beginning of the source where this location ends.
+ #--
+ #: () -> Integer
def end_offset
start_offset + length
end
# The character offset from the beginning of the source where this location
# ends.
+ #--
+ #: () -> Integer
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.
+ #--
+ #: (Encoding encoding) -> Integer
def end_code_units_offset(encoding = Encoding::UTF_16LE)
source.code_units_offset(end_offset, encoding)
end
# The end offset from the start of the file in code units using the given
# cache to fetch or calculate the value.
+ #--
+ #: (_CodeUnitsCache cache) -> Integer
def cached_end_code_units_offset(cache)
cache[end_offset]
end
# The line number where this location starts.
+ #--
+ #: () -> Integer
def start_line
source.line(start_offset)
end
# The content of the line where this location starts before this location.
+ #--
+ #: () -> String
def start_line_slice
offset = source.line_start(start_offset)
source.slice(offset, start_offset - offset)
end
# The line number where this location ends.
+ #--
+ #: () -> Integer
def end_line
source.line(end_offset)
end
- # The column number in bytes where this location starts from the start of
+ # The column in bytes where this location starts from the start of
# the line.
+ #--
+ #: () -> Integer
def start_column
source.column(start_offset)
end
- # The column number in characters where this location ends from the start of
+ # The column in characters where this location ends from the start of
# the line.
+ #--
+ #: () -> Integer
def start_character_column
source.character_column(start_offset)
end
- # The column number in code units of the given encoding where this location
+ # The column in code units of the given encoding where this location
# starts from the start of the line.
+ #--
+ #: (?Encoding encoding) -> Integer
def start_code_units_column(encoding = Encoding::UTF_16LE)
source.code_units_column(start_offset, encoding)
end
# The start column in code units using the given cache to fetch or calculate
# the value.
+ #--
+ #: (_CodeUnitsCache cache) -> Integer
def cached_start_code_units_column(cache)
cache[start_offset] - cache[source.line_start(start_offset)]
end
- # The column number in bytes where this location ends from the start of the
+ # The column in bytes where this location ends from the start of the
# line.
+ #--
+ #: () -> Integer
def end_column
source.column(end_offset)
end
- # The column number in characters where this location ends from the start of
+ # The column in characters where this location ends from the start of
# the line.
+ #--
+ #: () -> Integer
def end_character_column
source.character_column(end_offset)
end
- # The column number in code units of the given encoding where this location
+ # The column in code units of the given encoding where this location
# ends from the start of the line.
+ #--
+ #: (?Encoding encoding) -> Integer
def end_code_units_column(encoding = Encoding::UTF_16LE)
source.code_units_column(end_offset, encoding)
end
# The end column in code units using the given cache to fetch or calculate
# the value.
+ #--
+ #: (_CodeUnitsCache cache) -> Integer
def cached_end_code_units_column(cache)
cache[end_offset] - cache[source.line_start(end_offset)]
end
# Implement the hash pattern matching interface for Location.
- def deconstruct_keys(keys)
+ #--
+ #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
+ def deconstruct_keys(keys) # :nodoc:
{ start_offset: start_offset, end_offset: end_offset }
end
# Implement the pretty print interface for Location.
- def pretty_print(q)
+ #--
+ #: (PP q) -> void
+ def pretty_print(q) # :nodoc:
q.text("(#{start_line},#{start_column})-(#{end_line},#{end_column})")
end
# Returns true if the given other location is equal to this location.
+ #--
+ #: (untyped other) -> bool
def ==(other)
Location === other &&
other.start_offset == start_offset &&
@@ -500,6 +674,8 @@ module Prism
# 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.
+ #--
+ #: (Location other) -> Location
def join(other)
raise "Incompatible sources" if source != other.source
raise "Incompatible locations" if start_offset > other.start_offset
@@ -510,6 +686,8 @@ module Prism
# 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.
+ #--
+ #: (String string) -> Location
def adjoin(string)
line_suffix = source.slice(end_offset, source.line_end(end_offset) - end_offset)
@@ -523,23 +701,38 @@ module Prism
# 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
+ # The Location of this comment in the source.
+ attr_reader :location #: Location
# Create a new comment object with the given location.
+ #--
+ #: (Location location) -> void
def initialize(location)
@location = location
end
# Implement the hash pattern matching interface for Comment.
- def deconstruct_keys(keys)
+ #--
+ #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
+ def deconstruct_keys(keys) # :nodoc:
{ location: location }
end
# Returns the content of the comment by slicing it from the source code.
+ #--
+ #: () -> String
def slice
location.slice
end
+
+ # Returns true if this comment happens on the same line as other code and
+ # false if the comment is by itself. This can only be true for inline
+ # comments and should be false for block comments.
+ #--
+ #: () -> bool
+ def trailing?
+ raise NotImplementedError, "trailing? is not implemented for #{self.class}"
+ end
end
# InlineComment objects are the most common. They correspond to comments in
@@ -547,12 +740,16 @@ module Prism
class InlineComment < Comment
# Returns true if this comment happens on the same line as other code and
# false if the comment is by itself.
+ #--
+ #: () -> bool
def trailing?
!location.start_line_slice.strip.empty?
end
# Returns a string representation of this comment.
- def inspect
+ #--
+ #: () -> String
+ def inspect # :nodoc:
"#<Prism::InlineComment @location=#{location.inspect}>"
end
end
@@ -560,13 +757,17 @@ module Prism
# EmbDocComment objects correspond to comments that are surrounded by =begin
# and =end.
class EmbDocComment < Comment
- # This can only be true for inline comments.
+ # Returns false. This can only be true for inline comments.
+ #--
+ #: () -> bool
def trailing?
false
end
# Returns a string representation of this comment.
- def inspect
+ #--
+ #: () -> String
+ def inspect # :nodoc:
"#<Prism::EmbDocComment @location=#{location.inspect}>"
end
end
@@ -574,34 +775,44 @@ module Prism
# 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
+ attr_reader :key_loc #: Location
# A Location object representing the location of the value in the source.
- attr_reader :value_loc
+ attr_reader :value_loc #: Location
# Create a new magic comment object with the given key and value locations.
+ #--
+ #: (Location key_loc, Location value_loc) -> void
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.
+ #--
+ #: () -> String
def key
key_loc.slice
end
# Returns the value of the magic comment by slicing it from the source code.
+ #--
+ #: () -> String
def value
value_loc.slice
end
# Implement the hash pattern matching interface for MagicComment.
- def deconstruct_keys(keys)
+ #--
+ #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
+ def deconstruct_keys(keys) # :nodoc:
{ key_loc: key_loc, value_loc: value_loc }
end
# Returns a string representation of this magic comment.
- def inspect
+ #--
+ #: () -> String
+ def inspect # :nodoc:
"#<Prism::MagicComment @key=#{key.inspect} @value=#{value.inspect}>"
end
end
@@ -610,18 +821,20 @@ module Prism
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
+ attr_reader :type #: Symbol
# The message associated with this error.
- attr_reader :message
+ attr_reader :message #: String
# A Location object representing the location of this error in the source.
- attr_reader :location
+ attr_reader :location #: Location
# The level of this error.
- attr_reader :level
+ attr_reader :level #: Symbol
# Create a new error object with the given message and location.
+ #--
+ #: (Symbol type, String message, Location location, Symbol level) -> void
def initialize(type, message, location, level)
@type = type
@message = message
@@ -630,12 +843,16 @@ module Prism
end
# Implement the hash pattern matching interface for ParseError.
- def deconstruct_keys(keys)
+ #--
+ #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
+ def deconstruct_keys(keys) # :nodoc:
{ type: type, message: message, location: location, level: level }
end
# Returns a string representation of this error.
- def inspect
+ #--
+ #: () -> String
+ def inspect # :nodoc:
"#<Prism::ParseError @type=#{@type.inspect} @message=#{@message.inspect} @location=#{@location.inspect} @level=#{@level.inspect}>"
end
end
@@ -644,18 +861,20 @@ module Prism
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
+ attr_reader :type #: Symbol
# The message associated with this warning.
- attr_reader :message
+ attr_reader :message #: String
# A Location object representing the location of this warning in the source.
- attr_reader :location
+ attr_reader :location #: Location
# The level of this warning.
- attr_reader :level
+ attr_reader :level #: Symbol
# Create a new warning object with the given message and location.
+ #--
+ #: (Symbol type, String message, Location location, Symbol level) -> void
def initialize(type, message, location, level)
@type = type
@message = message
@@ -664,73 +883,116 @@ module Prism
end
# Implement the hash pattern matching interface for ParseWarning.
- def deconstruct_keys(keys)
+ #--
+ #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
+ def deconstruct_keys(keys) # :nodoc:
{ type: type, message: message, location: location, level: level }
end
# Returns a string representation of this warning.
- def inspect
+ #--
+ #: () -> String
+ def inspect # :nodoc:
"#<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.
+ # This represents the result of a call to Prism.parse or Prism.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
+ attr_reader :comments #: Array[Comment]
# The list of magic comments that were encountered during parsing.
- attr_reader :magic_comments
+ attr_reader :magic_comments #: Array[MagicComment]
# 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
+ attr_reader :data_loc #: Location?
# The list of errors that were generated during parsing.
- attr_reader :errors
+ attr_reader :errors #: Array[ParseError]
# The list of warnings that were generated during parsing.
- attr_reader :warnings
+ attr_reader :warnings #: Array[ParseWarning]
# A Source instance that represents the source code that was parsed.
- attr_reader :source
+ attr_reader :source #: Source
# Create a new result object with the given values.
- def initialize(comments, magic_comments, data_loc, errors, warnings, source)
+ #--
+ #: (Array[Comment] comments, Array[MagicComment] magic_comments, Location? data_loc, Array[ParseError] errors, Array[ParseWarning] warnings, bool continuable, Source source) -> void
+ def initialize(comments, magic_comments, data_loc, errors, warnings, continuable, source)
@comments = comments
@magic_comments = magic_comments
@data_loc = data_loc
@errors = errors
@warnings = warnings
+ @continuable = continuable
@source = source
end
# Implement the hash pattern matching interface for Result.
- def deconstruct_keys(keys)
+ #--
+ #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
+ def deconstruct_keys(keys) # :nodoc:
{ 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.
+ #--
+ #: () -> Encoding
def encoding
source.encoding
end
# Returns true if there were no errors during parsing and false if there
# were.
+ #--
+ #: () -> bool
def success?
errors.empty?
end
# Returns true if there were errors during parsing and false if there were
# not.
+ #--
+ #: () -> bool
def failure?
!success?
end
+ # Returns true if the parsed source is an incomplete expression that could
+ # become valid with additional input. This is useful for REPL contexts (such
+ # as IRB) where the user may be entering a multi-line expression one line at
+ # a time and the implementation needs to determine whether to wait for more
+ # input or to evaluate what has been entered so far.
+ #
+ # Concretely, this returns true when every error present is caused by the
+ # parser reaching the end of the input before a construct was closed (e.g.
+ # an unclosed string, array, block, or keyword), and returns false when any
+ # error is caused by a token that makes the input structurally invalid
+ # regardless of what might follow (e.g. a stray `end`, `]`, or `)` with no
+ # matching opener).
+ #
+ # Examples:
+ #
+ # Prism.parse("1 + [").continuable? #=> true (unclosed array)
+ # Prism.parse("1 + ]").continuable? #=> false (stray ])
+ # Prism.parse("tap do").continuable? #=> true (unclosed block)
+ # Prism.parse("end.tap do").continuable? #=> false (stray end)
+ #
+ #--
+ #: () -> bool
+ def continuable?
+ @continuable
+ end
+
# Create a code units cache for the given encoding.
+ #--
+ #: (Encoding encoding) -> _CodeUnitsCache
def code_units_cache(encoding)
source.code_units_cache(encoding)
end
@@ -747,32 +1009,42 @@ module Prism
private_constant :Newlines
# The syntax tree that was parsed from the source code.
- attr_reader :value
+ attr_reader :value #: ProgramNode
# Create a new parse result object with the given values.
- def initialize(value, comments, magic_comments, data_loc, errors, warnings, source)
+ #--
+ #: (ProgramNode value, Array[Comment] comments, Array[MagicComment] magic_comments, Location? data_loc, Array[ParseError] errors, Array[ParseWarning] warnings, bool continuable, Source source) -> void
+ def initialize(value, comments, magic_comments, data_loc, errors, warnings, continuable, source)
@value = value
- super(comments, magic_comments, data_loc, errors, warnings, source)
+ super(comments, magic_comments, data_loc, errors, warnings, continuable, source)
end
# Implement the hash pattern matching interface for ParseResult.
- def deconstruct_keys(keys)
+ #--
+ #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
+ def deconstruct_keys(keys) # :nodoc:
super.merge!(value: value)
end
# Attach the list of comments to their respective locations in the tree.
+ #--
+ #: () -> void
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.
+ #--
+ #: () -> void
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.
+ #--
+ #: () -> String
def errors_format
Errors.new(self).format
end
@@ -781,16 +1053,20 @@ module Prism
# 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
+ attr_reader :value #: Array[[Token, Integer]]
# Create a new lex result object with the given values.
- def initialize(value, comments, magic_comments, data_loc, errors, warnings, source)
+ #--
+ #: (Array[[Token, Integer]] value, Array[Comment] comments, Array[MagicComment] magic_comments, Location? data_loc, Array[ParseError] errors, Array[ParseWarning] warnings, bool continuable, Source source) -> void
+ def initialize(value, comments, magic_comments, data_loc, errors, warnings, continuable, source)
@value = value
- super(comments, magic_comments, data_loc, errors, warnings, source)
+ super(comments, magic_comments, data_loc, errors, warnings, continuable, source)
end
# Implement the hash pattern matching interface for LexResult.
- def deconstruct_keys(keys)
+ #--
+ #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
+ def deconstruct_keys(keys) # :nodoc:
super.merge!(value: value)
end
end
@@ -799,16 +1075,20 @@ module Prism
class ParseLexResult < Result
# A tuple of the syntax tree and the list of tokens that were parsed from
# the source code.
- attr_reader :value
+ attr_reader :value #: [ProgramNode, Array[[Token, Integer]]]
# Create a new parse lex result object with the given values.
- def initialize(value, comments, magic_comments, data_loc, errors, warnings, source)
+ #--
+ #: ([ProgramNode, Array[[Token, Integer]]] value, Array[Comment] comments, Array[MagicComment] magic_comments, Location? data_loc, Array[ParseError] errors, Array[ParseWarning] warnings, bool continuable, Source source) -> void
+ def initialize(value, comments, magic_comments, data_loc, errors, warnings, continuable, source)
@value = value
- super(comments, magic_comments, data_loc, errors, warnings, source)
+ super(comments, magic_comments, data_loc, errors, warnings, continuable, source)
end
# Implement the hash pattern matching interface for ParseLexResult.
- def deconstruct_keys(keys)
+ #--
+ #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
+ def deconstruct_keys(keys) # :nodoc:
super.merge!(value: value)
end
end
@@ -816,16 +1096,20 @@ module Prism
# This represents a token from the Ruby source.
class Token
# The Source object that represents the source this token came from.
- attr_reader :source
+ attr_reader :source #: Source
private :source
# The type of token that this token is.
- attr_reader :type
+ attr_reader :type #: Symbol
# A byteslice of the source that this token represents.
- attr_reader :value
+ attr_reader :value #: String
+
+ # @rbs @location: Location | Integer
# Create a new token object with the given type, value, and location.
+ #--
+ #: (Source source, Symbol type, String value, Location | Integer location) -> void
def initialize(source, type, value, location)
@source = source
@type = type
@@ -834,11 +1118,15 @@ module Prism
end
# Implement the hash pattern matching interface for Token.
- def deconstruct_keys(keys)
+ #--
+ #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
+ def deconstruct_keys(keys) # :nodoc:
{ type: type, value: value, location: location }
end
# A Location object representing the location of this token in the source.
+ #--
+ #: () -> Location
def location
location = @location
return location if location.is_a?(Location)
@@ -846,7 +1134,9 @@ module Prism
end
# Implement the pretty print interface for Token.
- def pretty_print(q)
+ #--
+ #: (PP q) -> void
+ def pretty_print(q) # :nodoc:
q.group do
q.text(type.to_s)
self.location.pretty_print(q)
@@ -861,6 +1151,8 @@ module Prism
end
# Returns true if the given other token is equal to this token.
+ #--
+ #: (untyped other) -> bool
def ==(other)
Token === other &&
other.type == type &&
@@ -868,12 +1160,16 @@ module Prism
end
# Returns a string representation of this token.
- def inspect
+ #--
+ #: () -> String
+ def inspect # :nodoc:
location
super
end
# Freeze this object and the objects it contains.
+ #--
+ #: () -> void
def deep_freeze
value.freeze
location.freeze
@@ -888,14 +1184,16 @@ module Prism
class Scope
# The list of local variables that are defined in this scope. This should be
# defined as an array of symbols.
- attr_reader :locals
+ attr_reader :locals #: Array[Symbol]
# The list of local variables that are forwarded to the next scope. This
# should by defined as an array of symbols containing the specific values of
# :*, :**, :&, or :"...".
- attr_reader :forwarding
+ attr_reader :forwarding #: Array[Symbol]
# Create a new scope object with the given locals and forwarding.
+ #--
+ #: (Array[Symbol] locals, Array[Symbol] forwarding) -> void
def initialize(locals, forwarding)
@locals = locals
@forwarding = forwarding
@@ -905,6 +1203,8 @@ module Prism
# Create a new scope with the given locals and forwarding options that is
# suitable for passing into one of the Prism.* methods that accepts the
# `scopes` option.
+ #--
+ #: (?locals: Array[Symbol], ?forwarding: Array[Symbol]) -> Scope
def self.scope(locals: [], forwarding: [])
Scope.new(locals, forwarding)
end
diff --git a/lib/prism/parse_result/comments.rb b/lib/prism/parse_result/comments.rb
index 3e93316aff..df80792d39 100644
--- a/lib/prism/parse_result/comments.rb
+++ b/lib/prism/parse_result/comments.rb
@@ -1,5 +1,7 @@
# frozen_string_literal: true
# :markup: markdown
+#--
+# rbs_inline: enabled
module Prism
class ParseResult < Result
@@ -18,32 +20,49 @@ module Prism
# the comment. Otherwise it will favor attaching to the nearest location
# that is after the comment.
class Comments
+ # @rbs!
+ # # An internal interface for a target that comments can be attached
+ # # to. This is either going to be a NodeTarget or a CommentTarget.
+ # interface _CommentTarget
+ # def start_offset: () -> Integer
+ # def end_offset: () -> Integer
+ # def encloses?: (Comment) -> bool
+ # def leading_comment: (Comment) -> void
+ # def trailing_comment: (Comment) -> void
+ # end
+
# A target for attaching comments that is based on a specific node's
# location.
class NodeTarget # :nodoc:
- attr_reader :node
+ attr_reader :node #: node
+ #: (node node) -> void
def initialize(node)
@node = node
end
+ #: () -> Integer
def start_offset
node.start_offset
end
+ #: () -> Integer
def end_offset
node.end_offset
end
+ #: (Comment comment) -> bool
def encloses?(comment)
start_offset <= comment.location.start_offset &&
comment.location.end_offset <= end_offset
end
+ #: (Comment comment) -> void
def leading_comment(comment)
node.location.leading_comment(comment)
end
+ #: (Comment comment) -> void
def trailing_comment(comment)
node.location.trailing_comment(comment)
end
@@ -52,44 +71,54 @@ module Prism
# 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
+ attr_reader :location #: Location
+ #: (Location location) -> void
def initialize(location)
@location = location
end
+ #: () -> Integer
def start_offset
location.start_offset
end
+ #: () -> Integer
def end_offset
location.end_offset
end
+ #: (Comment comment) -> bool
def encloses?(comment)
false
end
+ #: (Comment comment) -> void
def leading_comment(comment)
location.leading_comment(comment)
end
+ #: (Comment comment) -> void
def trailing_comment(comment)
location.trailing_comment(comment)
end
end
# The parse result that we are attaching comments to.
- attr_reader :parse_result
+ attr_reader :parse_result #: ParseResult
# Create a new Comments object that will attach comments to the given
# parse result.
+ #--
+ #: (ParseResult parse_result) -> void
def initialize(parse_result)
@parse_result = parse_result
end
# Attach the comments to their respective locations in the tree by
# mutating the parse result.
+ #--
+ #: () -> void
def attach!
parse_result.comments.each do |comment|
preceding, enclosing, following = nearest_targets(parse_result.value, comment)
@@ -117,11 +146,13 @@ module Prism
# Responsible for finding the nearest targets to the given comment within
# the context of the given encapsulating node.
+ #--
+ #: (node node, Comment comment) -> [_CommentTarget?, _CommentTarget?, _CommentTarget?]
def nearest_targets(node, comment)
comment_start = comment.location.start_offset
comment_end = comment.location.end_offset
- targets = [] #: Array[_Target]
+ targets = [] #: Array[_CommentTarget]
node.comment_targets.map do |value|
case value
when StatementsNode
@@ -134,8 +165,8 @@ module Prism
end
targets.sort_by!(&:start_offset)
- preceding = nil #: _Target?
- following = nil #: _Target?
+ preceding = nil #: _CommentTarget?
+ following = nil #: _CommentTarget?
left = 0
right = targets.length
diff --git a/lib/prism/parse_result/errors.rb b/lib/prism/parse_result/errors.rb
index 26c376b3ce..388309d23d 100644
--- a/lib/prism/parse_result/errors.rb
+++ b/lib/prism/parse_result/errors.rb
@@ -1,5 +1,7 @@
# frozen_string_literal: true
# :markup: markdown
+#--
+# rbs_inline: enabled
require "stringio"
@@ -9,14 +11,18 @@ module Prism
# 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
+ attr_reader :parse_result #: ParseResult
# Initialize a new set of errors from the given parse result.
+ #--
+ #: (ParseResult parse_result) -> void
def initialize(parse_result)
@parse_result = parse_result
end
# Formats the errors in a human-readable way and return them as a string.
+ #--
+ #: () -> String
def format
error_lines = {} #: Hash[Integer, Array[ParseError]]
parse_result.errors.each do |error|
diff --git a/lib/prism/parse_result/newlines.rb b/lib/prism/parse_result/newlines.rb
index e7fd62cafe..450c790226 100644
--- a/lib/prism/parse_result/newlines.rb
+++ b/lib/prism/parse_result/newlines.rb
@@ -1,5 +1,7 @@
# frozen_string_literal: true
# :markup: markdown
+#--
+# rbs_inline: enabled
module Prism
class ParseResult < Result
@@ -24,13 +26,20 @@ module Prism
# 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
+ # The map of lines indices to whether or not they have been marked as
+ # emitting a newline event.
+ # @rbs @lines: Array[bool]
+
# Create a new Newlines visitor with the given newline offsets.
+ #--
+ #: (Integer lines) -> void
def initialize(lines)
- # @type var lines: Integer
@lines = Array.new(1 + lines, false)
end
- # Permit block/lambda nodes to mark newlines within themselves.
+ # Permit block nodes to mark newlines within themselves.
+ #--
+ #: (BlockNode node) -> void
def visit_block_node(node)
old_lines = @lines
@lines = Array.new(old_lines.size, false)
@@ -42,17 +51,39 @@ module Prism
end
end
- alias_method :visit_lambda_node, :visit_block_node
+ # Permit lambda nodes to mark newlines within themselves.
+ #--
+ #: (LambdaNode node) -> void
+ def visit_lambda_node(node)
+ old_lines = @lines
+ @lines = Array.new(old_lines.size, false)
+
+ begin
+ super(node)
+ ensure
+ @lines = old_lines
+ end
+ end
- # Mark if/unless nodes as newlines.
+ # Mark if nodes as newlines.
+ #--
+ #: (IfNode node) -> void
def visit_if_node(node)
node.newline_flag!(@lines)
super(node)
end
- alias_method :visit_unless_node, :visit_if_node
+ # Mark unless nodes as newlines.
+ #--
+ #: (UnlessNode node) -> void
+ def visit_unless_node(node)
+ node.newline_flag!(@lines)
+ super(node)
+ end
# Permit statements lists to mark newlines within themselves.
+ #--
+ #: (StatementsNode node) -> void
def visit_statements_node(node)
node.body.each do |child|
child.newline_flag!(@lines)
@@ -63,10 +94,16 @@ module Prism
end
class Node
+ # Tracks whether or not this node should emit a newline event when the
+ # instructions that it represents are executed.
+ # @rbs @newline_flag: bool
+
+ #: () -> bool
def newline_flag? # :nodoc:
!!defined?(@newline_flag)
end
+ #: (Array[bool] lines) -> void
def newline_flag!(lines) # :nodoc:
line = location.start_line
unless lines[line]
@@ -77,48 +114,56 @@ module Prism
end
class BeginNode < Node
+ #: (Array[bool] lines) -> void
def newline_flag!(lines) # :nodoc:
# Never mark BeginNode with a newline flag, mark children instead.
end
end
class ParenthesesNode < Node
+ #: (Array[bool] lines) -> void
def newline_flag!(lines) # :nodoc:
# Never mark ParenthesesNode with a newline flag, mark children instead.
end
end
class IfNode < Node
+ #: (Array[bool] lines) -> void
def newline_flag!(lines) # :nodoc:
predicate.newline_flag!(lines)
end
end
class UnlessNode < Node
+ #: (Array[bool] lines) -> void
def newline_flag!(lines) # :nodoc:
predicate.newline_flag!(lines)
end
end
class UntilNode < Node
+ #: (Array[bool] lines) -> void
def newline_flag!(lines) # :nodoc:
predicate.newline_flag!(lines)
end
end
class WhileNode < Node
+ #: (Array[bool] lines) -> void
def newline_flag!(lines) # :nodoc:
predicate.newline_flag!(lines)
end
end
class RescueModifierNode < Node
+ #: (Array[bool] lines) -> void
def newline_flag!(lines) # :nodoc:
expression.newline_flag!(lines)
end
end
class InterpolatedMatchLastLineNode < Node
+ #: (Array[bool] lines) -> void
def newline_flag!(lines) # :nodoc:
first = parts.first
first.newline_flag!(lines) if first
@@ -126,6 +171,7 @@ module Prism
end
class InterpolatedRegularExpressionNode < Node
+ #: (Array[bool] lines) -> void
def newline_flag!(lines) # :nodoc:
first = parts.first
first.newline_flag!(lines) if first
@@ -133,6 +179,7 @@ module Prism
end
class InterpolatedStringNode < Node
+ #: (Array[bool] lines) -> void
def newline_flag!(lines) # :nodoc:
first = parts.first
first.newline_flag!(lines) if first
@@ -140,6 +187,7 @@ module Prism
end
class InterpolatedSymbolNode < Node
+ #: (Array[bool] lines) -> void
def newline_flag!(lines) # :nodoc:
first = parts.first
first.newline_flag!(lines) if first
@@ -147,6 +195,7 @@ module Prism
end
class InterpolatedXStringNode < Node
+ #: (Array[bool] lines) -> void
def newline_flag!(lines) # :nodoc:
first = parts.first
first.newline_flag!(lines) if first
diff --git a/lib/prism/pattern.rb b/lib/prism/pattern.rb
index 6ad2d9e5b9..be0493df05 100644
--- a/lib/prism/pattern.rb
+++ b/lib/prism/pattern.rb
@@ -1,5 +1,7 @@
# frozen_string_literal: true
# :markup: markdown
+#--
+# rbs_inline: enabled
module Prism
# A pattern is an object that wraps a Ruby pattern matching expression. The
@@ -41,7 +43,9 @@ module Prism
class CompilationError < StandardError
# Create a new CompilationError with the given representation of the node
# that caused the error.
- def initialize(repr)
+ #--
+ #: (String repr) -> void
+ def initialize(repr) # :nodoc:
super(<<~ERROR)
prism was unable to compile the pattern you provided into a usable
expression. It failed on to understand the node represented by:
@@ -57,10 +61,13 @@ module Prism
end
# The query that this pattern was initialized with.
- attr_reader :query
+ attr_reader :query #: String
+ # @rbs @compiled: Proc?
# Create a new pattern with the given query. The query should be a string
# containing a Ruby pattern matching expression.
+ #--
+ #: (String query) -> void
def initialize(query)
@query = query
@compiled = nil
@@ -68,6 +75,8 @@ module Prism
# Compile the query into a callable object that can be used to match against
# nodes.
+ #--
+ #: () -> Proc
def compile
result = Prism.parse("case nil\nin #{query}\nend")
@@ -84,7 +93,10 @@ module Prism
# 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)
+ #--
+ #: (node root) -> Enumerator[node, void]
+ #: (node root) { (node) -> void } -> void
+ def scan(root, &blk)
return to_enum(:scan, root) unless block_given?
@compiled ||= compile
@@ -100,23 +112,33 @@ module Prism
# Shortcut for combining two procs into one that returns true if both return
# true.
- def combine_and(left, right)
+ #--
+ #: (Proc left, Proc right) -> Proc
+ def combine_and(left, right) # :nodoc:
->(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)
+ #--
+ #: (Proc left, Proc right) -> Proc
+ def combine_or(left, right) # :nodoc:
->(other) { left.call(other) || right.call(other) }
end
- # Raise an error because the given node is not supported.
- def compile_error(node)
+ # Raise an error because the given node is not supported. Note purposefully
+ # not typing this method since it is a no return method that Steep does not
+ # understand.
+ #--
+ #: (node node) -> bot
+ def compile_error(node) # :nodoc:
raise CompilationError, node.inspect
end
# in [foo, bar, baz]
- def compile_array_pattern_node(node)
+ #--
+ #: (ArrayPatternNode node) -> Proc
+ def compile_array_pattern_node(node) # :nodoc:
compile_error(node) if !node.rest.nil? || node.posts.any?
constant = node.constant
@@ -141,12 +163,16 @@ module Prism
end
# in foo | bar
- def compile_alternation_pattern_node(node)
+ #--
+ #: (AlternationPatternNode node) -> Proc
+ def compile_alternation_pattern_node(node) # :nodoc:
combine_or(compile_node(node.left), compile_node(node.right))
end
# in Prism::ConstantReadNode
- def compile_constant_path_node(node)
+ #--
+ #: (ConstantPathNode node) -> Proc
+ def compile_constant_path_node(node) # :nodoc:
parent = node.parent
if parent.is_a?(ConstantReadNode) && parent.slice == "Prism"
@@ -161,12 +187,16 @@ module Prism
# in ConstantReadNode
# in String
- def compile_constant_read_node(node)
+ #--
+ #: (ConstantReadNode node) -> Proc
+ def compile_constant_read_node(node) # :nodoc:
compile_constant_name(node, node.name)
end
# Compile a name associated with a constant.
- def compile_constant_name(node, name)
+ #--
+ #: ((ConstantPathNode | ConstantReadNode) node, Symbol name) -> Proc
+ def compile_constant_name(node, name) # :nodoc:
if Prism.const_defined?(name, false)
clazz = Prism.const_get(name)
@@ -182,9 +212,14 @@ module Prism
# in InstanceVariableReadNode[name: Symbol]
# in { name: Symbol }
- def compile_hash_pattern_node(node)
+ #--
+ #: (HashPatternNode node) -> Proc
+ def compile_hash_pattern_node(node) # :nodoc:
compile_error(node) if node.rest
- compiled_constant = compile_node(node.constant) if node.constant
+
+ if (constant = node.constant)
+ compiled_constant = compile_node(constant)
+ end
preprocessed =
node.elements.to_h do |element|
@@ -212,12 +247,16 @@ module Prism
end
# in nil
- def compile_nil_node(node)
+ #--
+ #: (NilNode node) -> Proc
+ def compile_nil_node(node) # :nodoc:
->(attribute) { attribute.nil? }
end
# in /foo/
- def compile_regular_expression_node(node)
+ #--
+ #: (RegularExpressionNode node) -> Proc
+ def compile_regular_expression_node(node) # :nodoc:
regexp = Regexp.new(node.unescaped, node.closing[1..])
->(attribute) { regexp === attribute }
@@ -225,7 +264,9 @@ module Prism
# in ""
# in "foo"
- def compile_string_node(node)
+ #--
+ #: (StringNode node) -> Proc
+ def compile_string_node(node) # :nodoc:
string = node.unescaped
->(attribute) { string === attribute }
@@ -233,7 +274,9 @@ module Prism
# in :+
# in :foo
- def compile_symbol_node(node)
+ #--
+ #: (SymbolNode node) -> Proc
+ def compile_symbol_node(node) # :nodoc:
symbol = node.unescaped.to_sym
->(attribute) { symbol === attribute }
@@ -241,7 +284,9 @@ module Prism
# Compile any kind of node. Dispatch out to the individual compilation
# methods based on the type of node.
- def compile_node(node)
+ #--
+ #: (node node) -> Proc
+ def compile_node(node) # :nodoc:
case node
when AlternationPatternNode
compile_alternation_pattern_node(node)
diff --git a/lib/prism/polyfill/scan_byte.rb b/lib/prism/polyfill/scan_byte.rb
index 2def4572c4..9276e509fc 100644
--- a/lib/prism/polyfill/scan_byte.rb
+++ b/lib/prism/polyfill/scan_byte.rb
@@ -3,7 +3,7 @@
require "strscan"
# Polyfill for StringScanner#scan_byte, which didn't exist until Ruby 3.4.
-if !(StringScanner.instance_methods.include?(:scan_byte))
+if !(StringScanner.method_defined?(:scan_byte))
StringScanner.include(
Module.new {
def scan_byte # :nodoc:
diff --git a/lib/prism/polyfill/warn.rb b/lib/prism/polyfill/warn.rb
index 560380d308..76a4264623 100644
--- a/lib/prism/polyfill/warn.rb
+++ b/lib/prism/polyfill/warn.rb
@@ -7,17 +7,14 @@ if (method = Kernel.instance_method(:warn)).respond_to?(:parameters) ? method.pa
Kernel.prepend(
Module.new {
def warn(*msgs, uplevel: nil, category: nil) # :nodoc:
- uplevel =
- case uplevel
- when nil
- 1
- when Integer
- uplevel + 1
- else
- uplevel.to_int + 1
- end
-
- super(*msgs, uplevel: uplevel)
+ case uplevel
+ when nil
+ super(*msgs)
+ when Integer
+ super(*msgs, uplevel: uplevel + 1)
+ else
+ super(*msgs, uplevel: uplevel.to_int + 1)
+ end
end
}
)
@@ -25,17 +22,14 @@ if (method = Kernel.instance_method(:warn)).respond_to?(:parameters) ? method.pa
Object.prepend(
Module.new {
def warn(*msgs, uplevel: nil, category: nil) # :nodoc:
- uplevel =
- case uplevel
- when nil
- 1
- when Integer
- uplevel + 1
- else
- uplevel.to_int + 1
- end
-
- super(*msgs, uplevel: uplevel)
+ case uplevel
+ when nil
+ super(*msgs)
+ when Integer
+ super(*msgs, uplevel: uplevel + 1)
+ else
+ super(*msgs, uplevel: uplevel.to_int + 1)
+ end
end
}
)
diff --git a/lib/prism/prism.gemspec b/lib/prism/prism.gemspec
index 4daa511300..aac056b3f8 100644
--- a/lib/prism/prism.gemspec
+++ b/lib/prism/prism.gemspec
@@ -2,7 +2,7 @@
Gem::Specification.new do |spec|
spec.name = "prism"
- spec.version = "1.4.0"
+ spec.version = "1.9.0"
spec.authors = ["Shopify"]
spec.email = ["ruby@shopify.com"]
@@ -42,31 +42,69 @@ Gem::Specification.new do |spec|
"docs/serialization.md",
"docs/testing.md",
"ext/prism/api_node.c",
- "ext/prism/api_pack.c",
+ "ext/prism/extconf.rb",
"ext/prism/extension.c",
"ext/prism/extension.h",
"include/prism.h",
+ "include/prism/compiler/accel.h",
+ "include/prism/compiler/align.h",
+ "include/prism/compiler/exported.h",
+ "include/prism/compiler/fallthrough.h",
+ "include/prism/compiler/filesystem.h",
+ "include/prism/compiler/flex_array.h",
+ "include/prism/compiler/force_inline.h",
+ "include/prism/compiler/format.h",
+ "include/prism/compiler/inline.h",
+ "include/prism/compiler/nodiscard.h",
+ "include/prism/compiler/nonnull.h",
+ "include/prism/compiler/unused.h",
+ "include/prism/internal/allocator.h",
+ "include/prism/internal/allocator_debug.h",
+ "include/prism/internal/arena.h",
+ "include/prism/internal/bit.h",
+ "include/prism/internal/buffer.h",
+ "include/prism/internal/char.h",
+ "include/prism/internal/comments.h",
+ "include/prism/internal/constant_pool.h",
+ "include/prism/internal/diagnostic.h",
+ "include/prism/internal/encoding.h",
+ "include/prism/internal/integer.h",
+ "include/prism/internal/isinf.h",
+ "include/prism/internal/line_offset_list.h",
+ "include/prism/internal/list.h",
+ "include/prism/internal/magic_comments.h",
+ "include/prism/internal/memchr.h",
+ "include/prism/internal/node.h",
+ "include/prism/internal/options.h",
+ "include/prism/internal/parser.h",
+ "include/prism/internal/regexp.h",
+ "include/prism/internal/serialize.h",
+ "include/prism/internal/source.h",
+ "include/prism/internal/static_literals.h",
+ "include/prism/internal/strncasecmp.h",
+ "include/prism/internal/stringy.h",
+ "include/prism/internal/strpbrk.h",
+ "include/prism/internal/tokens.h",
+ "include/prism/arena.h",
"include/prism/ast.h",
- "include/prism/defines.h",
+ "include/prism/buffer.h",
+ "include/prism/comments.h",
+ "include/prism/constant_pool.h",
"include/prism/diagnostic.h",
- "include/prism/encoding.h",
+ "include/prism/excludes.h",
+ "include/prism/integer.h",
+ "include/prism/json.h",
+ "include/prism/line_offset_list.h",
+ "include/prism/magic_comments.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/serialize.h",
+ "include/prism/source.h",
+ "include/prism/stream.h",
+ "include/prism/string_query.h",
+ "include/prism/stringy.h",
"include/prism/version.h",
"lib/prism.rb",
"lib/prism/compiler.rb",
@@ -79,8 +117,8 @@ Gem::Specification.new do |spec|
"lib/prism/lex_compat.rb",
"lib/prism/mutation_compiler.rb",
"lib/prism/node_ext.rb",
+ "lib/prism/node_find.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",
@@ -98,73 +136,93 @@ Gem::Specification.new do |spec|
"lib/prism/translation.rb",
"lib/prism/translation/parser.rb",
"lib/prism/translation/parser_current.rb",
- "lib/prism/translation/parser33.rb",
- "lib/prism/translation/parser34.rb",
- "lib/prism/translation/parser35.rb",
+ "lib/prism/translation/parser_versions.rb",
"lib/prism/translation/parser/builder.rb",
"lib/prism/translation/parser/compiler.rb",
"lib/prism/translation/parser/lexer.rb",
"lib/prism/translation/ripper.rb",
+ "lib/prism/translation/ripper/filter.rb",
+ "lib/prism/translation/ripper/lexer.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/string_query.rbi",
+ "rbi/generated/prism.rbi",
+ "rbi/generated/prism/compiler.rbi",
+ "rbi/generated/prism/desugar_compiler.rbi",
+ "rbi/generated/prism/dispatcher.rbi",
+ "rbi/generated/prism/dot_visitor.rbi",
+ "rbi/generated/prism/dsl.rbi",
+ "rbi/generated/prism/inspect_visitor.rbi",
+ "rbi/generated/prism/lex_compat.rbi",
+ "rbi/generated/prism/mutation_compiler.rbi",
+ "rbi/generated/prism/node.rbi",
+ "rbi/generated/prism/node_ext.rbi",
+ "rbi/generated/prism/node_find.rbi",
+ "rbi/generated/prism/parse_result.rbi",
+ "rbi/generated/prism/pattern.rbi",
+ "rbi/generated/prism/reflection.rbi",
+ "rbi/generated/prism/relocation.rbi",
+ "rbi/generated/prism/serialize.rbi",
+ "rbi/generated/prism/string_query.rbi",
+ "rbi/generated/prism/translation.rbi",
+ "rbi/generated/prism/visitor.rbi",
+ "rbi/generated/prism/parse_result/comments.rbi",
+ "rbi/generated/prism/parse_result/errors.rbi",
+ "rbi/generated/prism/parse_result/newlines.rbi",
"rbi/prism/translation/parser.rbi",
- "rbi/prism/translation/parser33.rbi",
- "rbi/prism/translation/parser34.rbi",
- "rbi/prism/translation/parser35.rbi",
+ "rbi/prism/translation/parser_versions.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/parse_result/comments.rbs",
- "sig/prism/pattern.rbs",
- "sig/prism/reflection.rbs",
- "sig/prism/relocation.rbs",
- "sig/prism/serialize.rbs",
- "sig/prism/string_query.rbs",
- "sig/prism/visitor.rbs",
+ "rbi/rubyvm/node_find.rbi",
+ "sig/generated/prism.rbs",
+ "sig/generated/prism/compiler.rbs",
+ "sig/generated/prism/desugar_compiler.rbs",
+ "sig/generated/prism/dispatcher.rbs",
+ "sig/generated/prism/dot_visitor.rbs",
+ "sig/generated/prism/dsl.rbs",
+ "sig/generated/prism/inspect_visitor.rbs",
+ "sig/generated/prism/lex_compat.rbs",
+ "sig/generated/prism/mutation_compiler.rbs",
+ "sig/generated/prism/node.rbs",
+ "sig/generated/prism/node_ext.rbs",
+ "sig/generated/prism/node_find.rbs",
+ "sig/generated/prism/parse_result.rbs",
+ "sig/generated/prism/pattern.rbs",
+ "sig/generated/prism/reflection.rbs",
+ "sig/generated/prism/relocation.rbs",
+ "sig/generated/prism/serialize.rbs",
+ "sig/generated/prism/string_query.rbs",
+ "sig/generated/prism/translation.rbs",
+ "sig/generated/prism/visitor.rbs",
+ "sig/generated/prism/parse_result/comments.rbs",
+ "sig/generated/prism/parse_result/errors.rbs",
+ "sig/generated/prism/parse_result/newlines.rbs",
+ "src/arena.c",
+ "src/buffer.c",
+ "src/char.c",
+ "src/constant_pool.c",
"src/diagnostic.c",
"src/encoding.c",
+ "src/integer.c",
+ "src/json.c",
+ "src/line_offset_list.c",
+ "src/list.c",
+ "src/memchr.c",
"src/node.c",
"src/options.c",
- "src/pack.c",
+ "src/parser.c",
"src/prettyprint.c",
"src/prism.c",
"src/regexp.c",
"src/serialize.c",
+ "src/source.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"
+ "src/string_query.c",
+ "src/stringy.c",
+ "src/strncasecmp.c",
+ "src/strpbrk.c",
+ "src/tokens.c"
]
spec.extensions = ["ext/prism/extconf.rb"]
diff --git a/lib/prism/relocation.rb b/lib/prism/relocation.rb
index 3e9210a785..af0f792827 100644
--- a/lib/prism/relocation.rb
+++ b/lib/prism/relocation.rb
@@ -1,5 +1,7 @@
# frozen_string_literal: true
# :markup: markdown
+#--
+# rbs_inline: enabled
module Prism
# Prism parses deterministically for the same input. This provides a nice
@@ -12,6 +14,33 @@ module Prism
# "save" nodes and locations using a minimal amount of memory (just the
# node_id and a field identifier) and then reify them later.
module Relocation
+ # @rbs!
+ # type entry_value = untyped
+ # type entry_values = Hash[Symbol, entry_value]
+ #
+ # interface _Value
+ # def start_line: () -> Integer
+ # def end_line: () -> Integer
+ # def start_offset: () -> Integer
+ # def end_offset: () -> Integer
+ # def start_character_offset: () -> Integer
+ # def end_character_offset: () -> Integer
+ # def cached_start_code_units_offset: (_CodeUnitsCache cache) -> Integer
+ # def cached_end_code_units_offset: (_CodeUnitsCache cache) -> Integer
+ # def start_column: () -> Integer
+ # def end_column: () -> Integer
+ # def start_character_column: () -> Integer
+ # def end_character_column: () -> Integer
+ # def cached_start_code_units_column: (_CodeUnitsCache cache) -> Integer
+ # def cached_end_code_units_column: (_CodeUnitsCache cache) -> Integer
+ # def leading_comments: () -> Array[Comment]
+ # def trailing_comments: () -> Array[Comment]
+ # end
+ #
+ # interface _Field
+ # def fields: (_Value value) -> entry_values
+ # end
+
# An entry in a repository that will lazily reify its values when they are
# first accessed.
class Entry
@@ -21,109 +50,152 @@ module Prism
class MissingValueError < StandardError
end
+ # @rbs @repository: Repository?
+ # @rbs @values: Hash[Symbol, untyped]?
+
# Initialize a new entry with the given repository.
+ #--
+ #: (Repository repository) -> void
def initialize(repository)
@repository = repository
@values = nil
end
# Fetch the filepath of the value.
+ #--
+ #: () -> String
def filepath
fetch_value(:filepath)
end
# Fetch the start line of the value.
+ #--
+ #: () -> Integer
def start_line
fetch_value(:start_line)
end
# Fetch the end line of the value.
+ #--
+ #: () -> Integer
def end_line
fetch_value(:end_line)
end
# Fetch the start byte offset of the value.
+ #--
+ #: () -> Integer
def start_offset
fetch_value(:start_offset)
end
# Fetch the end byte offset of the value.
+ #--
+ #: () -> Integer
def end_offset
fetch_value(:end_offset)
end
# Fetch the start character offset of the value.
+ #--
+ #: () -> Integer
def start_character_offset
fetch_value(:start_character_offset)
end
# Fetch the end character offset of the value.
+ #--
+ #: () -> Integer
def end_character_offset
fetch_value(:end_character_offset)
end
# Fetch the start code units offset of the value, for the encoding that
# was configured on the repository.
+ #--
+ #: () -> Integer
def start_code_units_offset
fetch_value(:start_code_units_offset)
end
# Fetch the end code units offset of the value, for the encoding that was
# configured on the repository.
+ #--
+ #: () -> Integer
def end_code_units_offset
fetch_value(:end_code_units_offset)
end
# Fetch the start byte column of the value.
+ #--
+ #: () -> Integer
def start_column
fetch_value(:start_column)
end
# Fetch the end byte column of the value.
+ #--
+ #: () -> Integer
def end_column
fetch_value(:end_column)
end
# Fetch the start character column of the value.
+ #--
+ #: () -> Integer
def start_character_column
fetch_value(:start_character_column)
end
# Fetch the end character column of the value.
+ #--
+ #: () -> Integer
def end_character_column
fetch_value(:end_character_column)
end
# Fetch the start code units column of the value, for the encoding that
# was configured on the repository.
+ #--
+ #: () -> Integer
def start_code_units_column
fetch_value(:start_code_units_column)
end
# Fetch the end code units column of the value, for the encoding that was
# configured on the repository.
+ #--
+ #: () -> Integer
def end_code_units_column
fetch_value(:end_code_units_column)
end
# Fetch the leading comments of the value.
+ #--
+ #: () -> Array[CommentsField::Comment]
def leading_comments
fetch_value(:leading_comments)
end
# Fetch the trailing comments of the value.
+ #--
+ #: () -> Array[CommentsField::Comment]
def trailing_comments
fetch_value(:trailing_comments)
end
# Fetch the leading and trailing comments of the value.
+ #--
+ #: () -> Array[CommentsField::Comment]
def comments
- leading_comments.concat(trailing_comments)
+ [*leading_comments, *trailing_comments]
end
# Reify the values on this entry with the given values. This is an
# internal-only API that is called from the repository when it is time to
# reify the values.
+ #--
+ #: (entry_values values) -> void
def reify!(values) # :nodoc:
@repository = nil
@values = values
@@ -132,6 +204,8 @@ module Prism
private
# Fetch a value from the entry, raising an error if it is missing.
+ #--
+ #: (Symbol name) -> entry_value
def fetch_value(name)
values.fetch(name) do
raise MissingValueError, "No value for #{name}, make sure the " \
@@ -140,27 +214,35 @@ module Prism
end
# Return the values from the repository, reifying them if necessary.
+ #--
+ #: () -> entry_values
def values
- @values || (@repository.reify!; @values)
+ @values || (@repository&.reify!; @values) #: entry_values
end
end
# Represents the source of a repository that will be reparsed.
class Source
# The value that will need to be reparsed.
- attr_reader :value
+ attr_reader :value #: untyped
# Initialize the source with the given value.
+ #--
+ #: (untyped value) -> void
def initialize(value)
@value = value
end
# Reparse the value and return the parse result.
+ #--
+ #: () -> ParseResult
def result
raise NotImplementedError, "Subclasses must implement #result"
end
# Create a code units cache for the given encoding.
+ #--
+ #: (Encoding encoding) -> _CodeUnitsCache
def code_units_cache(encoding)
result.code_units_cache(encoding)
end
@@ -169,6 +251,8 @@ module Prism
# A source that is represented by a file path.
class SourceFilepath < Source
# Reparse the file and return the parse result.
+ #--
+ #: () -> ParseResult
def result
Prism.parse_file(value)
end
@@ -177,6 +261,8 @@ module Prism
# A source that is represented by a string.
class SourceString < Source
# Reparse the string and return the parse result.
+ #--
+ #: () -> ParseResult
def result
Prism.parse(value)
end
@@ -185,14 +271,18 @@ module Prism
# A field that represents the file path.
class FilepathField
# The file path that this field represents.
- attr_reader :value
+ attr_reader :value #: String
# Initialize a new field with the given file path.
+ #--
+ #: (String value) -> void
def initialize(value)
@value = value
end
# Fetch the file path.
+ #--
+ #: (_Value _value) -> entry_values
def fields(_value)
{ filepath: value }
end
@@ -201,6 +291,8 @@ module Prism
# A field representing the start and end lines.
class LinesField
# Fetches the start and end line of a value.
+ #--
+ #: (_Value value) -> entry_values
def fields(value)
{ start_line: value.start_line, end_line: value.end_line }
end
@@ -209,6 +301,8 @@ module Prism
# A field representing the start and end byte offsets.
class OffsetsField
# Fetches the start and end byte offset of a value.
+ #--
+ #: (_Value value) -> entry_values
def fields(value)
{ start_offset: value.start_offset, end_offset: value.end_offset }
end
@@ -217,6 +311,8 @@ module Prism
# A field representing the start and end character offsets.
class CharacterOffsetsField
# Fetches the start and end character offset of a value.
+ #--
+ #: (_Value value) -> entry_values
def fields(value)
{
start_character_offset: value.start_character_offset,
@@ -229,12 +325,16 @@ module Prism
class CodeUnitOffsetsField
# A pointer to the repository object that is used for lazily creating a
# code units cache.
- attr_reader :repository
+ attr_reader :repository #: Repository
# The associated encoding for the code units.
- attr_reader :encoding
+ attr_reader :encoding #: Encoding
+
+ # @rbs @cache: _CodeUnitsCache?
# Initialize a new field with the associated repository and encoding.
+ #--
+ #: (Repository repository, Encoding encoding) -> void
def initialize(repository, encoding)
@repository = repository
@encoding = encoding
@@ -243,6 +343,8 @@ module Prism
# Fetches the start and end code units offset of a value for a particular
# encoding.
+ #--
+ #: (_Value value) -> entry_values
def fields(value)
{
start_code_units_offset: value.cached_start_code_units_offset(cache),
@@ -253,6 +355,8 @@ module Prism
private
# Lazily create a code units cache for the associated encoding.
+ #--
+ #: () -> _CodeUnitsCache
def cache
@cache ||= repository.code_units_cache(encoding)
end
@@ -261,6 +365,8 @@ module Prism
# A field representing the start and end byte columns.
class ColumnsField
# Fetches the start and end byte column of a value.
+ #--
+ #: (_Value value) -> entry_values
def fields(value)
{ start_column: value.start_column, end_column: value.end_column }
end
@@ -269,6 +375,8 @@ module Prism
# A field representing the start and end character columns.
class CharacterColumnsField
# Fetches the start and end character column of a value.
+ #--
+ #: (_Value value) -> entry_values
def fields(value)
{
start_character_column: value.start_character_column,
@@ -282,12 +390,16 @@ module Prism
class CodeUnitColumnsField
# The repository object that is used for lazily creating a code units
# cache.
- attr_reader :repository
+ attr_reader :repository #: Repository
# The associated encoding for the code units.
- attr_reader :encoding
+ attr_reader :encoding #: Encoding
+
+ # @rbs @cache: _CodeUnitsCache?
# Initialize a new field with the associated repository and encoding.
+ #--
+ #: (Repository repository, Encoding encoding) -> void
def initialize(repository, encoding)
@repository = repository
@encoding = encoding
@@ -296,6 +408,8 @@ module Prism
# Fetches the start and end code units column of a value for a particular
# encoding.
+ #--
+ #: (_Value value) -> entry_values
def fields(value)
{
start_code_units_column: value.cached_start_code_units_column(cache),
@@ -306,6 +420,8 @@ module Prism
private
# Lazily create a code units cache for the associated encoding.
+ #--
+ #: () -> _CodeUnitsCache
def cache
@cache ||= repository.code_units_cache(encoding)
end
@@ -316,9 +432,11 @@ module Prism
# An object that represents a slice of a comment.
class Comment
# The slice of the comment.
- attr_reader :slice
+ attr_reader :slice #: String
# Initialize a new comment with the given slice.
+ #
+ #: (String slice) -> void
def initialize(slice)
@slice = slice
end
@@ -327,6 +445,8 @@ module Prism
private
# Create comment objects from the given values.
+ #--
+ #: (entry_value values) -> Array[Comment]
def comments(values)
values.map { |value| Comment.new(value.slice) }
end
@@ -335,6 +455,8 @@ module Prism
# A field representing the leading comments.
class LeadingCommentsField < CommentsField
# Fetches the leading comments of a value.
+ #--
+ #: (_Value value) -> entry_values
def fields(value)
{ leading_comments: comments(value.leading_comments) }
end
@@ -343,6 +465,8 @@ module Prism
# A field representing the trailing comments.
class TrailingCommentsField < CommentsField
# Fetches the trailing comments of a value.
+ #--
+ #: (_Value value) -> entry_values
def fields(value)
{ trailing_comments: comments(value.trailing_comments) }
end
@@ -358,15 +482,17 @@ module Prism
# The source associated with this repository. This will be either a
# SourceFilepath (the most common use case) or a SourceString.
- attr_reader :source
+ attr_reader :source #: Source
# The fields that have been configured on this repository.
- attr_reader :fields
+ attr_reader :fields #: Hash[Symbol, _Field]
# The entries that have been saved on this repository.
- attr_reader :entries
+ attr_reader :entries #: Hash[Integer, Hash[Symbol, Entry]]
# Initialize a new repository with the given source.
+ #--
+ #: (Source source) -> void
def initialize(source)
@source = source
@fields = {}
@@ -374,69 +500,93 @@ module Prism
end
# Create a code units cache for the given encoding from the source.
+ #--
+ #: (Encoding encoding) -> _CodeUnitsCache
def code_units_cache(encoding)
source.code_units_cache(encoding)
end
# Configure the filepath field for this repository and return self.
+ #--
+ #: () -> self
def filepath
raise ConfigurationError, "Can only specify filepath for a filepath source" unless source.is_a?(SourceFilepath)
field(:filepath, FilepathField.new(source.value))
end
# Configure the lines field for this repository and return self.
+ #--
+ #: () -> self
def lines
field(:lines, LinesField.new)
end
# Configure the offsets field for this repository and return self.
+ #--
+ #: () -> self
def offsets
field(:offsets, OffsetsField.new)
end
# Configure the character offsets field for this repository and return
# self.
+ #--
+ #: () -> self
def character_offsets
field(:character_offsets, CharacterOffsetsField.new)
end
# Configure the code unit offsets field for this repository for a specific
# encoding and return self.
+ #--
+ #: (Encoding encoding) -> self
def code_unit_offsets(encoding)
field(:code_unit_offsets, CodeUnitOffsetsField.new(self, encoding))
end
# Configure the columns field for this repository and return self.
+ #--
+ #: () -> self
def columns
field(:columns, ColumnsField.new)
end
# Configure the character columns field for this repository and return
# self.
+ #--
+ #: () -> self
def character_columns
field(:character_columns, CharacterColumnsField.new)
end
# Configure the code unit columns field for this repository for a specific
# encoding and return self.
+ #--
+ #: (Encoding encoding) -> self
def code_unit_columns(encoding)
field(:code_unit_columns, CodeUnitColumnsField.new(self, encoding))
end
# Configure the leading comments field for this repository and return
# self.
+ #--
+ #: () -> self
def leading_comments
field(:leading_comments, LeadingCommentsField.new)
end
# Configure the trailing comments field for this repository and return
# self.
+ #--
+ #: () -> self
def trailing_comments
field(:trailing_comments, TrailingCommentsField.new)
end
# Configure both the leading and trailing comment fields for this
# repository and return self.
+ #--
+ #: () -> self
def comments
leading_comments.trailing_comments
end
@@ -444,6 +594,8 @@ module Prism
# This method is called from nodes and locations when they want to enter
# themselves into the repository. It it internal-only and meant to be
# called from the #save* APIs.
+ #--
+ #: (Integer node_id, Symbol field_name) -> Entry
def enter(node_id, field_name) # :nodoc:
entry = Entry.new(self)
@entries[node_id][field_name] = entry
@@ -453,6 +605,8 @@ module Prism
# This method is called from the entries in the repository when they need
# to reify their values. It is internal-only and meant to be called from
# the various value APIs.
+ #--
+ #: () -> void
def reify! # :nodoc:
result = source.result
@@ -466,7 +620,7 @@ module Prism
while (node = queue.shift)
@entries[node.node_id].each do |field_name, entry|
value = node.public_send(field_name)
- values = {} #: Hash[Symbol, untyped]
+ values = {} #: entry_values
fields.each_value do |field|
values.merge!(field.fields(value))
@@ -485,6 +639,8 @@ module Prism
# Append the given field to the repository and return the repository so
# that these calls can be chained.
+ #--
+ #: (Symbol name, _Field) -> self
def field(name, value)
raise ConfigurationError, "Cannot specify multiple #{name} fields" if @fields.key?(name)
@fields[name] = value
@@ -493,11 +649,15 @@ module Prism
end
# Create a new repository for the given filepath.
+ #--
+ #: (String value) -> Repository
def self.filepath(value)
Repository.new(SourceFilepath.new(value))
end
# Create a new repository for the given string.
+ #--
+ #: (String value) -> Repository
def self.string(value)
Repository.new(SourceString.new(value))
end
diff --git a/lib/prism/string_query.rb b/lib/prism/string_query.rb
index 547f58d2fa..99ce57e5fe 100644
--- a/lib/prism/string_query.rb
+++ b/lib/prism/string_query.rb
@@ -1,29 +1,44 @@
# frozen_string_literal: true
# :markup: markdown
+#--
+# rbs_inline: enabled
module Prism
# Query methods that allow categorizing strings based on their context for
# where they could be valid in a Ruby syntax tree.
class StringQuery
+ # @rbs!
+ # def self.local?: (String string) -> bool
+ # def self.constant?: (String string) -> bool
+ # def self.method_name?: (String string) -> bool
+
# The string that this query is wrapping.
- attr_reader :string
+ attr_reader :string #: String
# Initialize a new query with the given string.
+ #--
+ #: (String string) -> void
def initialize(string)
@string = string
end
# Whether or not this string is a valid local variable name.
+ #--
+ #: () -> bool
def local?
StringQuery.local?(string)
end
# Whether or not this string is a valid constant name.
+ #--
+ #: () -> bool
def constant?
StringQuery.constant?(string)
end
# Whether or not this string is a valid method name.
+ #--
+ #: () -> bool
def method_name?
StringQuery.method_name?(string)
end
diff --git a/lib/prism/translation.rb b/lib/prism/translation.rb
index d127f2006c..5a086a7542 100644
--- a/lib/prism/translation.rb
+++ b/lib/prism/translation.rb
@@ -1,5 +1,7 @@
# frozen_string_literal: true
# :markup: markdown
+#--
+# rbs_inline: enabled
module Prism
# This module is responsible for converting the prism syntax tree into other
@@ -7,9 +9,11 @@ module Prism
module Translation # steep:ignore
autoload :Parser, "prism/translation/parser"
autoload :ParserCurrent, "prism/translation/parser_current"
- autoload :Parser33, "prism/translation/parser33"
- autoload :Parser34, "prism/translation/parser34"
- autoload :Parser35, "prism/translation/parser35"
+ autoload :Parser33, "prism/translation/parser_versions"
+ autoload :Parser34, "prism/translation/parser_versions"
+ autoload :Parser35, "prism/translation/parser_versions"
+ autoload :Parser40, "prism/translation/parser_versions"
+ autoload :Parser41, "prism/translation/parser_versions"
autoload :Ripper, "prism/translation/ripper"
autoload :RubyParser, "prism/translation/ruby_parser"
end
diff --git a/lib/prism/translation/parser.rb b/lib/prism/translation/parser.rb
index a7888f77ec..70031f133a 100644
--- a/lib/prism/translation/parser.rb
+++ b/lib/prism/translation/parser.rb
@@ -19,6 +19,13 @@ module Prism
# 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.
+ #
+ # Note that this version of the parser always parses using the latest
+ # version of Ruby syntax supported by Prism. If you want specific version
+ # support, use one of the version-specific subclasses, such as
+ # `Prism::Translation::Parser34`. If you want to parse using the same
+ # version of Ruby syntax as the currently running version of Ruby, use
+ # `Prism::Translation::ParserCurrent`.
class Parser < ::Parser::Base
Diagnostic = ::Parser::Diagnostic # :nodoc:
private_constant :Diagnostic
@@ -26,7 +33,7 @@ module Prism
# 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
+ class PrismDiagnostic < Diagnostic # :nodoc:
# This is the cached message coming from prism.
attr_reader :message
@@ -77,7 +84,7 @@ module Prism
end
def version # :nodoc:
- 34
+ 41
end
# The default encoding for Ruby files is UTF-8.
@@ -349,8 +356,10 @@ module Prism
"3.3.1"
when 34
"3.4.0"
- when 35
- "3.5.0"
+ when 35, 40
+ "4.0.0"
+ when 41
+ "4.1.0"
else
"latest"
end
diff --git a/lib/prism/translation/parser/builder.rb b/lib/prism/translation/parser/builder.rb
index 6b620c25bc..7fc3bba6b7 100644
--- a/lib/prism/translation/parser/builder.rb
+++ b/lib/prism/translation/parser/builder.rb
@@ -7,12 +7,14 @@ module Prism
# A builder that knows how to convert more modern Ruby syntax
# into whitequark/parser gem's syntax tree.
class Builder < ::Parser::Builders::Default
- # It represents the `it` block argument, which is not yet implemented in the Parser gem.
+ # It represents the `it` block argument, which is not yet implemented in
+ # the Parser gem.
def itarg
n(:itarg, [:it], nil)
end
- # The following three lines have been added to support the `it` block parameter syntax in the source code below.
+ # The following three lines have been added to support the `it` block
+ # parameter syntax in the source code below.
#
# if args.type == :itarg
# block_type = :itblock
@@ -56,6 +58,12 @@ module Prism
method_call.loc.with_expression(join_exprs(method_call, block)))
end
end
+
+ # def foo(&nil); end
+ # ^^^^
+ def blocknilarg(amper_t, nil_t)
+ n0(:blocknilarg, arg_prefix_map(amper_t, nil_t))
+ end
end
end
end
diff --git a/lib/prism/translation/parser/compiler.rb b/lib/prism/translation/parser/compiler.rb
index 6e0618890d..d11db12ae6 100644
--- a/lib/prism/translation/parser/compiler.rb
+++ b/lib/prism/translation/parser/compiler.rb
@@ -6,9 +6,9 @@ module Prism
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
+ class Compiler < ::Prism::Compiler # :nodoc:
# Raised when the tree is malformed or there is a bug in the compiler.
- class CompilationError < StandardError
+ class CompilationError < StandardError # :nodoc:
end
# The Parser::Base instance that is being used to build the AST.
@@ -217,7 +217,7 @@ module Prism
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, ";"),
+ srange_semicolon(find_start_offset, find_end_offset),
visit(rescue_clause.statements)
)
end until (rescue_clause = rescue_clause.subsequent).nil?
@@ -297,11 +297,6 @@ module Prism
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 :=~
@@ -323,7 +318,7 @@ module Prism
visit_all(arguments),
token(node.closing_loc),
),
- srange_find(node.message_loc.end_offset, node.arguments.arguments.last.location.start_offset, "="),
+ token(node.equal_loc),
visit(node.arguments.arguments.last)
),
block
@@ -340,7 +335,7 @@ module Prism
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, "="),
+ token(node.equal_loc),
visit(node.arguments.arguments.last)
)
else
@@ -789,7 +784,7 @@ module Prism
if (do_keyword_loc = node.do_keyword_loc)
token(do_keyword_loc)
else
- srange_find(node.collection.location.end_offset, (node.statements&.location || node.end_keyword_loc).start_offset, ";")
+ srange_semicolon(node.collection.location.end_offset, (node.statements&.location || node.end_keyword_loc).start_offset)
end,
visit(node.statements),
token(node.end_keyword_loc)
@@ -921,7 +916,7 @@ module Prism
if (then_keyword_loc = node.then_keyword_loc)
token(then_keyword_loc)
else
- srange_find(node.predicate.location.end_offset, (node.statements&.location || node.subsequent&.location || node.end_keyword_loc).start_offset, ";")
+ srange_semicolon(node.predicate.location.end_offset, (node.statements&.location || node.subsequent&.location || node.end_keyword_loc).start_offset)
end,
visit(node.statements),
case node.subsequent
@@ -987,7 +982,7 @@ module Prism
if (then_loc = node.then_loc)
token(then_loc)
else
- srange_find(node.pattern.location.end_offset, node.statements&.location&.start_offset, ";")
+ srange_semicolon(node.pattern.location.end_offset, node.statements&.location&.start_offset)
end,
visit(node.statements)
)
@@ -1324,7 +1319,7 @@ module Prism
# 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)
+ def visit_error_recovery_node(node)
::AST::Node.new(:missing, [], location: ::Parser::Source::Map.new(srange(node.location)))
end
@@ -1390,6 +1385,12 @@ module Prism
builder.nil(token(node.location))
end
+ # def foo(&nil); end
+ # ^^^^
+ def visit_no_block_parameter_node(node)
+ builder.blocknilarg(token(node.operator_loc), token(node.keyword_loc))
+ end
+
# def foo(**nil); end
# ^^^^^
def visit_no_keywords_parameter_node(node)
@@ -1767,7 +1768,7 @@ module Prism
end
else
parts =
- if node.value == ""
+ if node.value_loc.nil?
[]
elsif node.value.include?("\n")
string_nodes_from_line_continuations(node.unescaped, node.value, node.value_loc.start_offset, node.opening)
@@ -1808,7 +1809,7 @@ module Prism
if (then_keyword_loc = node.then_keyword_loc)
token(then_keyword_loc)
else
- srange_find(node.predicate.location.end_offset, (node.statements&.location || node.else_clause&.location || node.end_keyword_loc).start_offset, ";")
+ srange_semicolon(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),
@@ -1839,7 +1840,7 @@ module Prism
if (do_keyword_loc = node.do_keyword_loc)
token(do_keyword_loc)
else
- srange_find(node.predicate.location.end_offset, (node.statements&.location || node.closing_loc).start_offset, ";")
+ srange_semicolon(node.predicate.location.end_offset, (node.statements&.location || node.closing_loc).start_offset)
end,
visit(node.statements),
token(node.closing_loc)
@@ -1863,7 +1864,7 @@ module Prism
if (then_keyword_loc = node.then_keyword_loc)
token(then_keyword_loc)
else
- srange_find(node.conditions.last.location.end_offset, node.statements&.location&.start_offset, ";")
+ srange_semicolon(node.conditions.last.location.end_offset, node.statements&.location&.start_offset)
end,
visit(node.statements)
)
@@ -1883,7 +1884,7 @@ module Prism
if (do_keyword_loc = node.do_keyword_loc)
token(do_keyword_loc)
else
- srange_find(node.predicate.location.end_offset, (node.statements&.location || node.closing_loc).start_offset, ";")
+ srange_semicolon(node.predicate.location.end_offset, (node.statements&.location || node.closing_loc).start_offset)
end,
visit(node.statements),
token(node.closing_loc)
@@ -1967,22 +1968,6 @@ module Prism
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.
@@ -2012,16 +1997,16 @@ module Prism
Range.new(source_buffer, offset_cache[start_offset], offset_cache[end_offset])
end
- # Constructs a new source range by finding the given character 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.
+ # Constructs a new source range by finding a semicolon between the given
+ # start offset and end offset. If the semicolon 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, character)
- if (match = source_buffer.source.byteslice(start_offset...end_offset)[/\A\s*#{character}/])
+ def srange_semicolon(start_offset, end_offset)
+ if (match = source_buffer.source.byteslice(start_offset...end_offset)[/\A\s*;/])
final_offset = start_offset + match.bytesize
- [character, Range.new(source_buffer, offset_cache[final_offset - character.bytesize], offset_cache[final_offset])]
+ [";", Range.new(source_buffer, offset_cache[final_offset - 1], offset_cache[final_offset])]
end
end
@@ -2193,7 +2178,7 @@ module Prism
else
lines.sum do |line|
count = line.scan(/(\\*)n/).count { |(backslashes)| backslashes&.length&.odd? }
- count -= 1 if !line.end_with?("\n") && count > 0
+ count -= 1 if line.match?(/(?:\A|[^\\])(?:\\\\)*\\n\z/) && count > 0
count
end
end
diff --git a/lib/prism/translation/parser/lexer.rb b/lib/prism/translation/parser/lexer.rb
index 222df74559..e82042867f 100644
--- a/lib/prism/translation/parser/lexer.rb
+++ b/lib/prism/translation/parser/lexer.rb
@@ -10,7 +10,7 @@ module Prism
class Parser
# Accepts a list of prism tokens and converts them into the expected
# format for the parser gem.
- class Lexer
+ class Lexer # :nodoc:
# These tokens are always skipped
TYPES_ALWAYS_SKIP = Set.new(%i[IGNORED_NEWLINE __END__ EOF])
private_constant :TYPES_ALWAYS_SKIP
@@ -18,8 +18,6 @@ module Prism
# The direct translating of types between the two lexers.
TYPES = {
# These tokens should never appear in the output of the lexer.
- MISSING: nil,
- NOT_PROVIDED: nil,
EMBDOC_END: nil,
EMBDOC_LINE: nil,
@@ -89,6 +87,7 @@ module Prism
KEYWORD_DEF: :kDEF,
KEYWORD_DEFINED: :kDEFINED,
KEYWORD_DO: :kDO,
+ KEYWORD_DO_BLOCK: :kDO_BLOCK,
KEYWORD_DO_LOOP: :kDO_COND,
KEYWORD_END: :kEND,
KEYWORD_END_UPCASE: :klEND,
@@ -190,8 +189,8 @@ module Prism
# 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:
+ EXPR_BEG = 0x1
+ EXPR_LABEL = 0x400
# It is used to determine whether `do` is of the token type `kDO` or `kDO_LAMBDA`.
#
@@ -203,7 +202,7 @@ module Prism
# The following token types are listed as those classified as `tLPAREN`.
LPAREN_CONVERSION_TOKEN_TYPES = Set.new([
:kBREAK, :tCARET, :kCASE, :tDIVIDE, :kFOR, :kIF, :kNEXT, :kRETURN, :kUNTIL, :kWHILE, :tAMPER, :tANDOP, :tBANG, :tCOMMA, :tDOT2, :tDOT3,
- :tEQL, :tLPAREN, :tLPAREN2, :tLPAREN_ARG, :tLSHFT, :tNL, :tOP_ASGN, :tOROP, :tPIPE, :tSEMI, :tSTRING_DBEG, :tUMINUS, :tUPLUS
+ :tEQL, :tLPAREN, :tLPAREN2, :tLPAREN_ARG, :tLSHFT, :tNL, :tOP_ASGN, :tOROP, :tPIPE, :tSEMI, :tSTRING_DBEG, :tUMINUS, :tUPLUS, :tLCURLY
])
# Types of tokens that are allowed to continue a method call with comments in-between.
@@ -234,7 +233,7 @@ module Prism
@offset_cache = offset_cache
end
- Range = ::Parser::Source::Range # :nodoc:
+ Range = ::Parser::Source::Range
private_constant :Range
# Convert the prism tokens into the expected format for the parser gem.
diff --git a/lib/prism/translation/parser33.rb b/lib/prism/translation/parser33.rb
deleted file mode 100644
index 0a59669465..0000000000
--- a/lib/prism/translation/parser33.rb
+++ /dev/null
@@ -1,13 +0,0 @@
-# frozen_string_literal: true
-# :markup: markdown
-
-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 566a23fadb..0000000000
--- a/lib/prism/translation/parser34.rb
+++ /dev/null
@@ -1,13 +0,0 @@
-# frozen_string_literal: true
-# :markup: markdown
-
-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/parser35.rb b/lib/prism/translation/parser35.rb
deleted file mode 100644
index 79cd59cbd9..0000000000
--- a/lib/prism/translation/parser35.rb
+++ /dev/null
@@ -1,13 +0,0 @@
-# frozen_string_literal: true
-# :markup: markdown
-
-module Prism
- module Translation
- # This class is the entry-point for Ruby 3.5 of `Prism::Translation::Parser`.
- class Parser35 < Parser
- def version # :nodoc:
- 35
- end
- end
- end
-end
diff --git a/lib/prism/translation/parser_current.rb b/lib/prism/translation/parser_current.rb
index 1b1794abbe..f7c1070e30 100644
--- a/lib/prism/translation/parser_current.rb
+++ b/lib/prism/translation/parser_current.rb
@@ -1,8 +1,8 @@
# frozen_string_literal: true
# :markup: markdown
+#--
# typed: ignore
-#
module Prism
module Translation
case RUBY_VERSION
@@ -10,11 +10,13 @@ module Prism
ParserCurrent = Parser33
when /^3\.4\./
ParserCurrent = Parser34
- when /^3\.5\./
- ParserCurrent = Parser35
+ when /^3\.5\./, /^4\.0\./
+ ParserCurrent = Parser40
+ when /^4\.1\./
+ ParserCurrent = Parser41
else
# Keep this in sync with released Ruby.
- parser = Parser34
+ parser = Parser40
major, minor, _patch = Gem::Version.new(RUBY_VERSION).segments
warn "warning: `Prism::Translation::Current` is loading #{parser.name}, " \
"but you are running #{major}.#{minor}."
diff --git a/lib/prism/translation/parser_versions.rb b/lib/prism/translation/parser_versions.rb
new file mode 100644
index 0000000000..720c7d548c
--- /dev/null
+++ b/lib/prism/translation/parser_versions.rb
@@ -0,0 +1,36 @@
+# frozen_string_literal: true
+# :markup: markdown
+
+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
+
+ # This class is the entry-point for Ruby 3.4 of `Prism::Translation::Parser`.
+ class Parser34 < Parser
+ def version # :nodoc:
+ 34
+ end
+ end
+
+ # This class is the entry-point for Ruby 4.0 of `Prism::Translation::Parser`.
+ class Parser40 < Parser
+ def version # :nodoc:
+ 40
+ end
+ end
+
+ Parser35 = Parser40 # :nodoc:
+
+ # This class is the entry-point for Ruby 4.1 of `Prism::Translation::Parser`.
+ class Parser41 < Parser
+ def version # :nodoc:
+ 41
+ end
+ end
+ end
+end
diff --git a/lib/prism/translation/ripper.rb b/lib/prism/translation/ripper.rb
index 6ea98fc1ea..f179a149a1 100644
--- a/lib/prism/translation/ripper.rb
+++ b/lib/prism/translation/ripper.rb
@@ -1,8 +1,6 @@
# frozen_string_literal: true
# :markup: markdown
-require "ripper"
-
module Prism
module Translation
# This class provides a compatibility layer between prism and Ripper. It
@@ -24,22 +22,10 @@ module Prism
# - 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+.
@@ -71,7 +57,8 @@ module Prism
# [[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)
+ coerced = coerce_source(src)
+ result = Prism.lex_compat(coerced, filepath: filename, line: lineno, version: "current", encoding: coerced.encoding)
if result.failure? && raise_errors
raise SyntaxError, result.errors.first.message
@@ -80,6 +67,34 @@ module Prism
end
end
+ # Tokenizes the Ruby program and returns an array of strings.
+ # The +filename+ and +lineno+ arguments are mostly ignored, since the
+ # return value is just the tokenized input.
+ # 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+.
+ #
+ # p Ripper.tokenize("def m(a) nil end")
+ # # => ["def", " ", "m", "(", "a", ")", " ", "nil", " ", "end"]
+ #
+ def self.tokenize(...)
+ lex(...).map { |token| token[2] }
+ end
+
+ # Mirros the various lex_types that ripper supports
+ def self.coerce_source(source) # :nodoc:
+ if source.is_a?(IO)
+ source.read
+ elsif source.respond_to?(:gets)
+ src = +""
+ while line = source.gets
+ src << line
+ end
+ src
+ else
+ source.to_str
+ end
+ end
+
# This contains a table of all of the parser events and their
# corresponding arity.
PARSER_EVENT_TABLE = {
@@ -332,7 +347,7 @@ module Prism
"__ENCODING__",
"__FILE__",
"__LINE__"
- ]
+ ].to_set
# A list of all of the Ruby binary operators.
BINARY_OPERATORS = [
@@ -357,7 +372,7 @@ module Prism
:/,
:*,
:**
- ]
+ ].to_set
private_constant :KEYWORDS, :BINARY_OPERATORS
@@ -426,9 +441,93 @@ module Prism
end
end
+ autoload :Filter, "prism/translation/ripper/filter"
+ autoload :Lexer, "prism/translation/ripper/lexer"
autoload :SexpBuilder, "prism/translation/ripper/sexp"
autoload :SexpBuilderPP, "prism/translation/ripper/sexp"
+ # Provides optimized access to line and column information.
+ # Ripper bounds are mostly accessed in a linear fashion, so
+ # we can try a linear scan first and fall back to binary search.
+ class LineAndColumnCache # :nodoc:
+ # How many should it look ahead/behind before falling back to binary searching.
+ WINDOW = 8
+ private_constant :WINDOW
+
+ #: (Source source) -> void
+ def initialize(source)
+ @source = source
+ @offsets = source.offsets
+ @hint = 0
+ end
+
+ #: (Integer byte_offset) -> [Integer, Integer]
+ def line_and_column(byte_offset)
+ @hint = new_hint(byte_offset) || @source.find_line(byte_offset)
+ return [@hint + @source.start_line, byte_offset - @offsets[@hint]]
+ end
+
+ private
+
+ def new_hint(byte_offset)
+ if @offsets[@hint] <= byte_offset
+ # Same line?
+ if (@hint + 1 >= @offsets.size || @offsets[@hint + 1] > byte_offset)
+ return @hint
+ end
+
+ # Scan forwards
+ limit = [@hint + WINDOW + 1, @offsets.size].min
+ idx = @hint + 1
+ while idx < limit
+ if @offsets[idx] > byte_offset
+ return idx - 1
+ end
+ if @offsets[idx] == byte_offset
+ return idx
+ end
+ idx += 1
+ end
+ else
+ # Scan backwards
+ limit = @hint > WINDOW ? @hint - WINDOW : 0
+ idx = @hint
+ while idx >= limit + 1
+ if @offsets[idx - 1] <= byte_offset
+ return idx - 1
+ end
+ idx -= 1
+ end
+ end
+
+ nil
+ end
+ end
+
+ # :stopdoc:
+ # This is not part of the public API but used by some gems.
+
+ # Ripper-internal bitflags.
+ LEX_STATE_NAMES = %i[
+ BEG END ENDARG ENDFN ARG CMDARG MID FNAME DOT CLASS LABEL LABELED FITEM
+ ].map.with_index.to_h { |name, i| [2 ** i, name] }.freeze
+ private_constant :LEX_STATE_NAMES
+
+ LEX_STATE_NAMES.each do |value, key|
+ const_set("EXPR_#{key}", value)
+ end
+ EXPR_NONE = 0
+ 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
+
+ def self.lex_state_name(state)
+ LEX_STATE_NAMES.filter_map { |flag, name| name if state & flag != 0 }.join("|")
+ end
+
+ # :startdoc:
+
# The source that is being parsed.
attr_reader :source
@@ -438,16 +537,17 @@ module Prism
# The current line number of the parser.
attr_reader :lineno
- # The current column number of the parser.
+ # The current column in bytes 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
+ @source = Ripper.coerce_source(source)
@filename = filename
@lineno = lineno
@column = 0
@result = nil
+ @line_and_column_cache = nil
end
##########################################################################
@@ -466,7 +566,12 @@ module Prism
bounds(location)
if comment.is_a?(InlineComment)
- on_comment(comment.slice)
+ # Inline comments always contain a newline if the line itself contains it
+ if result.source.source.bytesize > comment.location.end_offset
+ on_comment("#{comment.slice}\n")
+ else
+ on_comment(comment.slice)
+ end
else
offset = location.start_offset
lines = comment.slice.lines
@@ -547,9 +652,14 @@ module Prism
# Visitor methods
##########################################################################
+ # :stopdoc:
+
# alias foo bar
# ^^^^^^^^^^^^^
def visit_alias_method_node(node)
+ bounds(node.keyword_loc)
+ on_kw("alias")
+
new_name = visit(node.new_name)
old_name = visit(node.old_name)
@@ -560,6 +670,9 @@ module Prism
# alias $foo $bar
# ^^^^^^^^^^^^^^^
def visit_alias_global_variable_node(node)
+ bounds(node.keyword_loc)
+ on_kw("alias")
+
new_name = visit_alias_global_variable_node_value(node.new_name)
old_name = visit_alias_global_variable_node_value(node.old_name)
@@ -585,6 +698,10 @@ module Prism
# ^^^^^^^^^
def visit_alternation_pattern_node(node)
left = visit_pattern_node(node.left)
+
+ bounds(node.operator_loc)
+ on_op("|")
+
right = visit_pattern_node(node.right)
bounds(node.location)
@@ -595,7 +712,13 @@ module Prism
# parenthesis node that can be used to wrap patterns.
private def visit_pattern_node(node)
if node.is_a?(ParenthesesNode)
- visit(node.body)
+ bounds(node.opening_loc)
+ on_lparen("(")
+ result = visit(node.body)
+ bounds(node.closing_loc)
+ on_rparen(")")
+
+ result
else
visit(node)
end
@@ -605,6 +728,14 @@ module Prism
# ^^^^^^^
def visit_and_node(node)
left = visit(node.left)
+
+ bounds(node.operator_loc)
+ if node.operator == "and"
+ on_kw("and")
+ else
+ on_op("&&")
+ end
+
right = visit(node.right)
bounds(node.location)
@@ -632,6 +763,8 @@ module Prism
previous = element
end
+ visit_words_sep(opening_loc, node.elements.last, node.closing_loc)
+
bounds(node.closing_loc)
on_tstring_end(node.closing)
when /^%i/
@@ -651,6 +784,8 @@ module Prism
previous = element
end
+ visit_words_sep(opening_loc, node.elements.last, node.closing_loc)
+
bounds(node.closing_loc)
on_tstring_end(node.closing)
when /^%W/
@@ -688,6 +823,8 @@ module Prism
previous = element
end
+ visit_words_sep(opening_loc, node.elements.last, node.closing_loc)
+
bounds(node.closing_loc)
on_tstring_end(node.closing)
when /^%I/
@@ -725,6 +862,8 @@ module Prism
previous = element
end
+ visit_words_sep(opening_loc, node.elements.last, node.closing_loc)
+
bounds(node.closing_loc)
on_tstring_end(node.closing)
else
@@ -741,15 +880,21 @@ module Prism
on_array(elements)
end
- # Dispatch a words_sep event that contains the space between the elements
+ # Dispatch words_sep events that contains the whitespace 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))
+ start_offset = (previous.nil? ? opening_loc : previous.location).end_offset
+ end_offset = current.start_offset
+ length = end_offset - start_offset
+
+ if length > 0
+ whitespace = source.byteslice(start_offset, length)
+ current_offset = start_offset
+ whitespace.each_line do |part|
+ bounds(opening_loc.copy(start_offset: current_offset, length: part.bytesize))
+ on_words_sep(part)
+ current_offset += part.bytesize
+ end
end
end
@@ -775,9 +920,18 @@ module Prism
# ^^^^^
def visit_array_pattern_node(node)
constant = visit(node.constant)
+
+ if node.opening_loc
+ bounds(node.opening_loc)
+ node.opening == "[" ? on_lbracket("[") : on_lparen("(")
+ end
+
requireds = visit_all(node.requireds) if node.requireds.any?
rest =
if (rest_node = node.rest).is_a?(SplatNode)
+ bounds(rest_node.operator_loc)
+ on_op("*")
+
if rest_node.expression.nil?
bounds(rest_node.location)
on_var_field(nil)
@@ -788,6 +942,10 @@ module Prism
posts = visit_all(node.posts) if node.posts.any?
+ if node.closing_loc
+ bounds(node.closing_loc)
+ node.closing == "]" ? on_rbracket("]") : on_rparen(")")
+ end
bounds(node.location)
on_aryptn(constant, requireds, rest, posts)
end
@@ -803,6 +961,12 @@ module Prism
# ^^^^
def visit_assoc_node(node)
key = visit(node.key)
+
+ if node.operator_loc
+ bounds(node.operator_loc)
+ on_op("=>")
+ end
+
value = visit(node.value)
bounds(node.location)
@@ -815,6 +979,9 @@ module Prism
# { **foo }
# ^^^^^
def visit_assoc_splat_node(node)
+ bounds(node.operator_loc)
+ on_op("**")
+
value = visit(node.value)
bounds(node.location)
@@ -831,8 +998,18 @@ module Prism
# begin end
# ^^^^^^^^^
def visit_begin_node(node)
+ if node.begin_keyword_loc
+ bounds(node.begin_keyword_loc)
+ on_kw("begin")
+ end
+
clauses = visit_begin_node_clauses(node.begin_keyword_loc, node, false)
+ if node.end_keyword_loc
+ bounds(node.end_keyword_loc)
+ on_kw("end")
+ end
+
bounds(node.location)
on_begin(clauses)
end
@@ -844,7 +1021,7 @@ module Prism
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)
+ body = [nil, *body] if void_stmt?(location, node.statements.body[0].location, allow_newline)
bounds(node.statements.location)
visit_statements_node_body(body)
@@ -853,12 +1030,15 @@ module Prism
rescue_clause = visit(node.rescue_clause)
else_clause =
unless (else_clause_node = node.else_clause).nil?
+ bounds(else_clause_node.else_keyword_loc)
+ on_kw("else")
+
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 = [nil, *body] if void_stmt?(else_clause_node.else_keyword_loc, else_clause_node.statements.body[0].location, allow_newline)
body
end
@@ -880,7 +1060,7 @@ module Prism
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)
+ body = [nil, *body] if void_stmt?(location, body[0].location, allow_newline)
stmts = visit_statements_node_body(body)
bounds(node.body.first.location)
@@ -895,6 +1075,8 @@ module Prism
# foo(&bar)
# ^^^^
def visit_block_argument_node(node)
+ bounds(node.operator_loc)
+ on_op("&")
visit(node.expression)
end
@@ -908,6 +1090,13 @@ module Prism
# Visit a BlockNode.
def visit_block_node(node)
braces = node.opening == "{"
+ bounds(node.opening_loc)
+ if braces
+ on_lbrace("{")
+ else
+ on_kw("do")
+ end
+
parameters = visit(node.parameters)
body =
@@ -920,7 +1109,7 @@ module Prism
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 = [nil, *stmts] if void_stmt?(node.parameters&.location || node.opening_loc, node.body.location, false)
stmts = visit_statements_node_body(stmts)
bounds(node.body.location)
@@ -932,6 +1121,14 @@ module Prism
end
if braces
+ bounds(node.closing_loc)
+ on_rbrace("}")
+ else
+ bounds(node.closing_loc)
+ on_kw("end")
+ end
+
+ if braces
bounds(node.location)
on_brace_block(parameters, body)
else
@@ -943,12 +1140,15 @@ module Prism
# def foo(&bar); end
# ^^^^
def visit_block_parameter_node(node)
+ bounds(node.operator_loc)
+ on_op("&")
+
if node.name_loc.nil?
bounds(node.location)
on_blockarg(nil)
else
bounds(node.name_loc)
- name = visit_token(node.name.to_s)
+ name = on_ident(node.name.to_s)
bounds(node.location)
on_blockarg(name)
@@ -957,6 +1157,9 @@ module Prism
# A block's parameters.
def visit_block_parameters_node(node)
+ bounds(node.opening_loc)
+ on_op("|")
+
parameters =
if node.parameters.nil?
on_params(nil, nil, nil, nil, nil, nil, nil)
@@ -971,6 +1174,9 @@ module Prism
false
end
+ bounds(node.closing_loc)
+ on_op("|")
+
bounds(node.location)
on_block_var(parameters, locals)
end
@@ -981,6 +1187,9 @@ module Prism
# break foo
# ^^^^^^^^^
def visit_break_node(node)
+ bounds(node.keyword_loc)
+ on_kw("break")
+
if node.arguments.nil?
bounds(node.location)
on_break(on_args_new)
@@ -1005,20 +1214,32 @@ module Prism
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.opening_loc)
+ on_lbracket("[")
+
+ arguments, block_node = visit_call_node_arguments(node.arguments, node.block, trailing_comma?(node.arguments&.location || node.location, node.closing_loc))
+
+ bounds(node.closing_loc)
+ on_rbracket("]")
+
+ block = visit(block_node)
bounds(node.location)
call = on_aref(receiver, arguments)
- if block.nil?
- call
- else
+ if block_node
bounds(node.location)
on_method_add_block(call, block)
+ else
+ call
end
when :[]=
receiver = visit(node.receiver)
+ bounds(node.opening_loc)
+ on_lbracket("[")
+
*arguments, last_argument = node.arguments.arguments
arguments << node.block if !node.block.nil?
@@ -1034,6 +1255,11 @@ module Prism
end
end
+ bounds(node.closing_loc)
+ on_rbracket("]")
+ bounds(node.equal_loc)
+ on_op("=")
+
bounds(node.location)
call = on_aref_field(receiver, arguments)
value = visit_write_value(last_argument)
@@ -1041,27 +1267,54 @@ module Prism
bounds(last_argument.location)
on_assign(call, value)
when :-@, :+@, :~
- receiver = visit(node.receiver)
+ bounds(node.message_loc)
+ on_op(node.message)
+ receiver = visit(node.receiver)
bounds(node.location)
on_unary(node.name, receiver)
when :!
+ bounds(node.message_loc)
if node.message == "not"
+ on_kw("not")
+
+ if node.opening_loc
+ bounds(node.opening_loc)
+ on_lparen("(")
+ end
+
receiver =
- if !node.receiver.is_a?(ParenthesesNode) || !node.receiver.body.nil?
+ if node.receiver.is_a?(ParenthesesNode) && node.receiver.body.nil?
+ # The parens in `not()` just emit parens and nothing else.
+ bounds(node.receiver.opening_loc)
+ on_lparen("(")
+ bounds(node.receiver.closing_loc)
+ on_rparen(")")
+ nil
+ else
visit(node.receiver)
end
+ if node.closing_loc
+ bounds(node.closing_loc)
+ on_rparen(")")
+ end
bounds(node.location)
on_unary(:not, receiver)
else
+ on_op("!")
+
receiver = visit(node.receiver)
bounds(node.location)
on_unary(:!, receiver)
end
- when *BINARY_OPERATORS
+ when BINARY_OPERATORS
receiver = visit(node.receiver)
+
+ bounds(node.message_loc)
+ on_op(node.message)
+
value = visit(node.arguments.arguments.first)
bounds(node.location)
@@ -1073,9 +1326,21 @@ module Prism
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))
+ if node.opening_loc
+ bounds(node.opening_loc)
+ on_lparen("(")
+ end
+
+ arguments, block_node = visit_call_node_arguments(node.arguments, node.block, trailing_comma?(node.arguments&.location || node.location, node.closing_loc || node.location))
+
+ if node.closing_loc
+ bounds(node.closing_loc)
+ on_rparen(")")
+ end
+
+ block = visit(block_node)
call =
- if node.opening_loc.nil? && arguments&.any?
+ if node.opening_loc.nil? && get_arguments_and_block(node.arguments, node.block).first.any?
bounds(node.location)
on_command(message, arguments)
elsif !node.opening_loc.nil?
@@ -1086,11 +1351,11 @@ module Prism
on_method_add_arg(on_fcall(message), on_args_new)
end
- if block.nil?
- call
- else
+ if block_node
bounds(node.block.location)
on_method_add_block(call, block)
+ else
+ call
end
end
end
@@ -1098,7 +1363,7 @@ module Prism
receiver = visit(node.receiver)
bounds(node.call_operator_loc)
- call_operator = visit_token(node.call_operator)
+ call_operator = visit_call_operator(node.call_operator)
message =
if node.message_loc.nil?
@@ -1108,13 +1373,30 @@ module Prism
visit_token(node.message, false)
end
+ if node.equal_loc
+ bounds(node.equal_loc)
+ on_op("=")
+ 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))
+ if node.opening_loc
+ bounds(node.opening_loc)
+ on_lparen("(")
+ end
+
+ arguments, block_node = visit_call_node_arguments(node.arguments, node.block, trailing_comma?(node.arguments&.location || node.location, node.closing_loc || node.location))
+
+ if node.closing_loc
+ bounds(node.closing_loc)
+ on_rparen(")")
+ end
+
+ block = visit(block_node)
call =
if node.opening_loc.nil?
bounds(node.location)
@@ -1132,27 +1414,35 @@ module Prism
on_method_add_arg(on_call(receiver, call_operator, message), arguments)
end
- if block.nil?
- call
- else
+ if block_node
bounds(node.block.location)
on_method_add_block(call, block)
+ else
+ call
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)
+ # Extract the arguments and block Ripper-style, which means if the block
+ # is like `&b` then it's moved to arguments.
+ private def get_arguments_and_block(arguments_node, block_node)
arguments = arguments_node&.arguments || []
block = block_node
if block.is_a?(BlockArgumentNode)
- arguments << block
+ arguments += [block]
block = nil
end
+ [arguments, block]
+ 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, block = get_arguments_and_block(arguments_node, block_node)
+
[
if arguments.length == 1 && arguments.first.is_a?(ForwardingArgumentsNode)
visit(arguments.first)
@@ -1166,7 +1456,7 @@ module Prism
on_args_add_block(args, false)
end
end,
- visit(block)
+ block,
]
end
@@ -1184,7 +1474,7 @@ module Prism
receiver = visit(node.receiver)
bounds(node.call_operator_loc)
- call_operator = visit_token(node.call_operator)
+ call_operator = visit_call_operator(node.call_operator)
bounds(node.message_loc)
message = visit_token(node.message)
@@ -1206,7 +1496,7 @@ module Prism
receiver = visit(node.receiver)
bounds(node.call_operator_loc)
- call_operator = visit_token(node.call_operator)
+ call_operator = visit_call_operator(node.call_operator)
bounds(node.message_loc)
message = visit_token(node.message)
@@ -1228,7 +1518,7 @@ module Prism
receiver = visit(node.receiver)
bounds(node.call_operator_loc)
- call_operator = visit_token(node.call_operator)
+ call_operator = visit_call_operator(node.call_operator)
bounds(node.message_loc)
message = visit_token(node.message)
@@ -1250,6 +1540,9 @@ module Prism
if node.call_operator == "::"
receiver = visit(node.receiver)
+ bounds(node.call_operator_loc)
+ on_op("::")
+
bounds(node.message_loc)
message = visit_token(node.message)
@@ -1259,7 +1552,7 @@ module Prism
receiver = visit(node.receiver)
bounds(node.call_operator_loc)
- call_operator = visit_token(node.call_operator)
+ call_operator = visit_call_operator(node.call_operator)
bounds(node.message_loc)
message = visit_token(node.message)
@@ -1273,6 +1566,10 @@ module Prism
# ^^^^^^^^^^
def visit_capture_pattern_node(node)
value = visit(node.value)
+
+ bounds(node.operator_loc)
+ on_op("=>")
+
target = visit(node.target)
bounds(node.location)
@@ -1282,10 +1579,21 @@ module Prism
# case foo; when bar; end
# ^^^^^^^^^^^^^^^^^^^^^^^
def visit_case_node(node)
+ bounds(node.case_keyword_loc)
+ on_kw("case")
+
predicate = visit(node.predicate)
+ visited_conditions = node.conditions.map { |condition| visit(condition) }
+ visited_else_clause = visit(node.else_clause)
+
+ if !node.else_clause
+ bounds(node.end_keyword_loc)
+ on_kw("end")
+ end
+
clauses =
- node.conditions.reverse_each.inject(visit(node.else_clause)) do |current, condition|
- on_when(*visit(condition), current)
+ visited_conditions.reverse_each.inject(visited_else_clause) do |current, condition|
+ on_when(*condition, current)
end
bounds(node.location)
@@ -1295,10 +1603,23 @@ module Prism
# case foo; in bar; end
# ^^^^^^^^^^^^^^^^^^^^^
def visit_case_match_node(node)
+ bounds(node.case_keyword_loc)
+ on_kw("case")
+
predicate = visit(node.predicate)
+ visited_conditions = node.conditions.map do | condition|
+ visit(condition)
+ end
+ visited_else_clause = visit(node.else_clause)
+
+ if !node.else_clause
+ bounds(node.end_keyword_loc)
+ on_kw("end")
+ end
+
clauses =
- node.conditions.reverse_each.inject(visit(node.else_clause)) do |current, condition|
- on_in(*visit(condition), current)
+ visited_conditions.reverse_each.inject(visited_else_clause) do |current, condition|
+ on_in(*condition, current)
end
bounds(node.location)
@@ -1308,6 +1629,9 @@ module Prism
# class Foo; end
# ^^^^^^^^^^^^^^
def visit_class_node(node)
+ bounds(node.class_keyword_loc)
+ on_kw("class")
+
constant_path =
if node.constant_path.is_a?(ConstantReadNode)
bounds(node.constant_path.location)
@@ -1316,9 +1640,17 @@ module Prism
visit(node.constant_path)
end
+ if node.inheritance_operator_loc
+ bounds(node.inheritance_operator_loc)
+ on_op("<")
+ end
+
superclass = visit(node.superclass)
bodystmt = visit_body_node(node.superclass&.location || node.constant_path.location, node.body, node.superclass.nil?)
+ bounds(node.end_keyword_loc)
+ on_kw("end")
+
bounds(node.location)
on_class(constant_path, superclass, bodystmt)
end
@@ -1332,12 +1664,13 @@ module Prism
# @@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))
+
+ bounds(node.operator_loc)
+ on_op("=")
+
value = visit_write_value(node.value)
bounds(node.location)
@@ -1402,12 +1735,13 @@ module Prism
# 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))
+
+ bounds(node.operator_loc)
+ on_op("=")
+
value = visit_write_value(node.value)
bounds(node.location)
@@ -1467,6 +1801,11 @@ module Prism
# ^^^^^^^^
def visit_constant_path_node(node)
if node.parent.nil?
+ if node.delimiter_loc
+ bounds(node.delimiter_loc)
+ on_op("::")
+ end
+
bounds(node.name_loc)
child = on_const(node.name.to_s)
@@ -1475,6 +1814,9 @@ module Prism
else
parent = visit(node.parent)
+ bounds(node.delimiter_loc)
+ on_op("::")
+
bounds(node.name_loc)
child = on_const(node.name.to_s)
@@ -1485,11 +1827,12 @@ module Prism
# Foo::Bar = 1
# ^^^^^^^^^^^^
- #
- # Foo::Foo, Bar::Bar = 1
- # ^^^^^^^^ ^^^^^^^^
def visit_constant_path_write_node(node)
target = visit_constant_path_write_node_target(node.target)
+
+ bounds(node.operator_loc)
+ on_op("=")
+
value = visit_write_value(node.value)
bounds(node.location)
@@ -1499,6 +1842,11 @@ module Prism
# Visit a constant path that is part of a write node.
private def visit_constant_path_write_node_target(node)
if node.parent.nil?
+ if node.delimiter_loc
+ bounds(node.delimiter_loc)
+ on_op("::")
+ end
+
bounds(node.name_loc)
child = on_const(node.name.to_s)
@@ -1507,6 +1855,9 @@ module Prism
else
parent = visit(node.parent)
+ bounds(node.delimiter_loc)
+ on_op("::")
+
bounds(node.name_loc)
child = on_const(node.name.to_s)
@@ -1519,7 +1870,6 @@ module Prism
# ^^^^^^^^^^^^^^^
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}=")
@@ -1533,7 +1883,6 @@ module Prism
# ^^^^^^^^^^^^^^^^
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("&&=")
@@ -1547,7 +1896,6 @@ module Prism
# ^^^^^^^^^^^^^^^^
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("||=")
@@ -1569,16 +1917,24 @@ module Prism
# def self.foo; end
# ^^^^^^^^^^^^^^^^^
def visit_def_node(node)
+ bounds(node.def_keyword_loc)
+ on_kw("def")
+
receiver = visit(node.receiver)
operator =
if !node.operator_loc.nil?
bounds(node.operator_loc)
- visit_token(node.operator)
+ node.operator == "." ? on_period(".") : on_op("::")
end
bounds(node.name_loc)
name = visit_token(node.name_loc.slice)
+ if node.lparen_loc
+ bounds(node.lparen_loc)
+ on_lparen("(")
+ end
+
parameters =
if node.parameters.nil?
bounds(node.location)
@@ -1588,10 +1944,17 @@ module Prism
end
if !node.lparen_loc.nil?
+ bounds(node.rparen_loc)
+ on_rparen(")")
bounds(node.lparen_loc)
parameters = on_paren(parameters)
end
+ if node.equal_loc
+ bounds(node.equal_loc)
+ on_op("=")
+ end
+
bodystmt =
if node.equal_loc.nil?
visit_body_node(node.rparen_loc || node.end_keyword_loc, node.body)
@@ -1602,11 +1965,16 @@ module Prism
on_bodystmt(body, nil, nil, nil)
end
+ if node.end_keyword_loc
+ bounds(node.end_keyword_loc)
+ on_kw("end")
+ end
+
bounds(node.location)
- if receiver.nil?
- on_def(name, parameters, bodystmt)
- else
+ if receiver
on_defs(receiver, operator, name, parameters, bodystmt)
+ else
+ on_def(name, parameters, bodystmt)
end
end
@@ -1616,8 +1984,21 @@ module Prism
# defined?(a)
# ^^^^^^^^^^^
def visit_defined_node(node)
+ bounds(node.keyword_loc)
+ on_kw("defined?")
+
+ if node.lparen_loc
+ bounds(node.lparen_loc)
+ on_lparen("(")
+ end
+
expression = visit(node.value)
+ if node.rparen_loc
+ bounds(node.rparen_loc)
+ on_rparen(")")
+ end
+
# Very weird circumstances here where something like:
#
# defined?
@@ -1638,17 +2019,24 @@ module Prism
# if foo then bar else baz end
# ^^^^^^^^^^^^
def visit_else_node(node)
+ bounds(node.else_keyword_loc)
+ on_kw("else")
+
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 = [nil, *body] if void_stmt?(node.else_keyword_loc, node.statements.body[0].location, false)
body
end
+ else_statements = visit_statements_node_body(statements)
+
+ bounds(node.end_keyword_loc)
+ on_kw("end")
bounds(node.location)
- on_else(visit_statements_node_body(statements))
+ on_else(else_statements)
end
# "foo #{bar}"
@@ -1686,12 +2074,15 @@ module Prism
# Visit an EnsureNode node.
def visit_ensure_node(node)
+ bounds(node.ensure_keyword_loc)
+ on_kw("ensure")
+
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 = [nil, *body] if void_stmt?(node.ensure_keyword_loc, body[0].location, false)
body
end
@@ -1712,6 +2103,14 @@ module Prism
# ^^^^^^^^^^^
def visit_find_pattern_node(node)
constant = visit(node.constant)
+
+ if node.opening_loc
+ bounds(node.opening_loc)
+ node.opening == "[" ? on_lbracket("[") : on_lparen("(")
+ end
+ bounds(node.left.operator_loc)
+ on_op("*")
+
left =
if node.left.expression.nil?
bounds(node.left.location)
@@ -1721,6 +2120,10 @@ module Prism
end
requireds = visit_all(node.requireds) if node.requireds.any?
+
+ bounds(node.right.operator_loc)
+ on_op("*")
+
right =
if node.right.expression.nil?
bounds(node.right.location)
@@ -1729,6 +2132,10 @@ module Prism
visit(node.right.expression)
end
+ if node.closing_loc
+ bounds(node.closing_loc)
+ node.closing == "]" ? on_rbracket("]") : on_rparen(")")
+ end
bounds(node.location)
on_fndptn(constant, left, requireds, right)
end
@@ -1737,6 +2144,10 @@ module Prism
# ^^^^^^^^^^
def visit_flip_flop_node(node)
left = visit(node.left)
+
+ bounds(node.operator_loc)
+ on_op(node.operator)
+
right = visit(node.right)
bounds(node.location)
@@ -1756,8 +2167,18 @@ module Prism
# for foo in bar do end
# ^^^^^^^^^^^^^^^^^^^^^
def visit_for_node(node)
+ bounds(node.for_keyword_loc)
+ on_kw("for")
+
index = visit(node.index)
+ bounds(node.in_keyword_loc)
+ on_kw("in")
+
collection = visit(node.collection)
+ if node.do_keyword_loc
+ bounds(node.do_keyword_loc)
+ on_kw("do")
+ end
statements =
if node.statements.nil?
bounds(node.location)
@@ -1766,6 +2187,9 @@ module Prism
visit(node.statements)
end
+ bounds(node.end_keyword_loc)
+ on_kw("end")
+
bounds(node.location)
on_for(index, collection, statements)
end
@@ -1774,6 +2198,7 @@ module Prism
# ^^^
def visit_forwarding_arguments_node(node)
bounds(node.location)
+ on_op("...")
on_args_forward
end
@@ -1781,6 +2206,7 @@ module Prism
# ^^^
def visit_forwarding_parameter_node(node)
bounds(node.location)
+ on_op("...")
on_args_forward
end
@@ -1790,6 +2216,9 @@ module Prism
# super {}
# ^^^^^^^^
def visit_forwarding_super_node(node)
+ bounds(node.keyword_loc)
+ on_kw("super")
+
if node.block.nil?
bounds(node.location)
on_zsuper
@@ -1810,12 +2239,13 @@ module Prism
# $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))
+
+ bounds(node.operator_loc)
+ on_op("=")
+
value = visit_write_value(node.value)
bounds(node.location)
@@ -1874,6 +2304,9 @@ module Prism
# {}
# ^^
def visit_hash_node(node)
+ bounds(node.opening_loc)
+ on_lbrace("{")
+
elements =
if node.elements.any?
args = visit_all(node.elements)
@@ -1882,6 +2315,8 @@ module Prism
on_assoclist_from_args(args)
end
+ bounds(node.closing_loc)
+ on_rbrace("}")
bounds(node.location)
on_hash(elements)
end
@@ -1890,6 +2325,15 @@ module Prism
# ^^
def visit_hash_pattern_node(node)
constant = visit(node.constant)
+
+ if node.constant
+ bounds(node.opening_loc)
+ node.opening == "[" ? on_lbracket("[") : on_lparen("(")
+ elsif node.opening_loc
+ bounds(node.opening_loc)
+ on_lbrace("{")
+ end
+
elements =
if node.elements.any? || !node.rest.nil?
node.elements.map do |element|
@@ -1912,12 +2356,21 @@ module Prism
rest =
case node.rest
when AssocSplatNode
+ bounds(node.rest.operator_loc)
+ on_op("**")
visit(node.rest.value)
when NoKeywordsParameterNode
bounds(node.rest.location)
on_var_field(visit(node.rest))
end
+ if node.constant
+ bounds(node.closing_loc)
+ node.closing == "]" ? on_rbracket("]") : on_rparen(")")
+ elsif node.closing_loc
+ bounds(node.closing_loc)
+ on_rbrace("}")
+ end
bounds(node.location)
on_hshptn(constant, elements, rest)
end
@@ -1933,13 +2386,27 @@ module Prism
def visit_if_node(node)
if node.then_keyword == "?"
predicate = visit(node.predicate)
+
+ bounds(node.then_keyword_loc)
+ on_op("?")
+
truthy = visit(node.statements.body.first)
+
+ bounds(node.subsequent.else_keyword_loc)
+ on_op(":")
+
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)
+ bounds(node.if_keyword_loc)
+ on_kw(node.if_keyword)
predicate = visit(node.predicate)
+ if node.then_keyword_loc && node.then_keyword != "?"
+ bounds(node.then_keyword_loc)
+ on_kw("then")
+ end
statements =
if node.statements.nil?
bounds(node.location)
@@ -1949,6 +2416,11 @@ module Prism
end
subsequent = visit(node.subsequent)
+ if node.end_keyword_loc && !node.subsequent
+ bounds(node.end_keyword_loc)
+ on_kw("end")
+ end
+
bounds(node.location)
if node.if_keyword == "if"
on_if(predicate, statements, subsequent)
@@ -1957,6 +2429,8 @@ module Prism
end
else
statements = visit(node.statements.body.first)
+ bounds(node.if_keyword_loc)
+ on_kw(node.if_keyword)
predicate = visit(node.predicate)
bounds(node.location)
@@ -1988,7 +2462,14 @@ module Prism
# 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.
+ bounds(node.in_loc)
+ on_kw("in")
+
pattern = visit_pattern_node(node.pattern)
+ if node.then_loc
+ bounds(node.then_loc)
+ on_kw("then")
+ end
statements =
if node.statements.nil?
bounds(node.location)
@@ -2004,8 +2485,15 @@ module Prism
# ^^^^^^^^^^^^^^^
def visit_index_operator_write_node(node)
receiver = visit(node.receiver)
+
+ bounds(node.opening_loc)
+ on_lbracket("[")
+
arguments, _ = visit_call_node_arguments(node.arguments, node.block, trailing_comma?(node.arguments&.location || node.location, node.closing_loc))
+ bounds(node.closing_loc)
+ on_rbracket("]")
+
bounds(node.location)
target = on_aref_field(receiver, arguments)
@@ -2021,8 +2509,15 @@ module Prism
# ^^^^^^^^^^^^^^^^
def visit_index_and_write_node(node)
receiver = visit(node.receiver)
+
+ bounds(node.opening_loc)
+ on_lbracket("[")
+
arguments, _ = visit_call_node_arguments(node.arguments, node.block, trailing_comma?(node.arguments&.location || node.location, node.closing_loc))
+ bounds(node.closing_loc)
+ on_rbracket("]")
+
bounds(node.location)
target = on_aref_field(receiver, arguments)
@@ -2038,8 +2533,15 @@ module Prism
# ^^^^^^^^^^^^^^^^
def visit_index_or_write_node(node)
receiver = visit(node.receiver)
+
+ bounds(node.opening_loc)
+ on_lbracket("[")
+
arguments, _ = visit_call_node_arguments(node.arguments, node.block, trailing_comma?(node.arguments&.location || node.location, node.closing_loc))
+ bounds(node.closing_loc)
+ on_rbracket("]")
+
bounds(node.location)
target = on_aref_field(receiver, arguments)
@@ -2055,8 +2557,15 @@ module Prism
# ^^^^^^^^
def visit_index_target_node(node)
receiver = visit(node.receiver)
+
+ bounds(node.opening_loc)
+ on_lbracket("[")
+
arguments, _ = visit_call_node_arguments(node.arguments, node.block, trailing_comma?(node.arguments&.location || node.location, node.closing_loc))
+ bounds(node.closing_loc)
+ on_rbracket("]")
+
bounds(node.location)
on_aref_field(receiver, arguments)
end
@@ -2073,6 +2582,10 @@ module Prism
def visit_instance_variable_write_node(node)
bounds(node.name_loc)
target = on_var_field(on_ivar(node.name.to_s))
+
+ bounds(node.operator_loc)
+ on_op("=")
+
value = visit_write_value(node.value)
bounds(node.location)
@@ -2175,20 +2688,37 @@ module Prism
# "foo #{bar}"
# ^^^^^^^^^^^^
def visit_interpolated_string_node(node)
- if node.opening&.start_with?("<<~")
- heredoc = visit_heredoc_string_node(node)
+ with_string_bounds(node) do
+ 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(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(part.location)
- on_string_concat(content, concat)
+ bounds(node.location)
+ on_string_literal(parts)
end
- else
+ end
+ end
+
+ # :"foo #{bar}"
+ # ^^^^^^^^^^^^^
+ def visit_interpolated_symbol_node(node)
+ with_string_bounds(node) do
bounds(node.parts.first.location)
parts =
node.parts.inject(on_string_content) do |content, part|
@@ -2196,40 +2726,29 @@ module Prism
end
bounds(node.location)
- on_string_literal(parts)
+ on_dyna_symbol(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)
+ with_string_bounds(node) do
+ 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(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)
+ bounds(node.location)
+ on_xstring_literal(parts)
+ end
end
end
@@ -2270,6 +2789,9 @@ module Prism
# def foo(**); end
# ^^
def visit_keyword_rest_parameter_node(node)
+ bounds(node.operator_loc)
+ on_op("**")
+
if node.name_loc.nil?
bounds(node.location)
on_kwrest_param(nil)
@@ -2289,6 +2811,11 @@ module Prism
parameters =
if node.parameters.is_a?(BlockParametersNode)
+ if node.parameters.opening_loc
+ bounds(node.parameters.opening_loc)
+ on_lparen("(")
+ end
+
# Ripper does not track block-locals within lambdas, so we skip
# directly to the parameters here.
params =
@@ -2299,6 +2826,13 @@ module Prism
visit(node.parameters.parameters)
end
+ visit_all(node.parameters.locals)
+
+ if node.parameters.closing_loc
+ bounds(node.parameters.closing_loc)
+ on_rparen(")")
+ end
+
if node.parameters.opening_loc.nil?
params
else
@@ -2311,9 +2845,11 @@ module Prism
end
braces = node.opening == "{"
+ bounds(node.opening_loc)
if braces
- bounds(node.opening_loc)
on_tlambeg(node.opening)
+ else
+ on_kw("do")
end
body =
@@ -2326,7 +2862,7 @@ module Prism
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 = [nil, *stmts] if void_stmt?(node.parameters&.location || node.opening_loc, node.body.location, false)
stmts = visit_statements_node_body(stmts)
bounds(node.body.location)
@@ -2337,6 +2873,13 @@ module Prism
raise
end
+ bounds(node.closing_loc)
+ if braces
+ on_rbrace("}")
+ else
+ on_kw("end")
+ end
+
bounds(node.location)
on_lambda(parameters, body)
end
@@ -2353,6 +2896,10 @@ module Prism
def visit_local_variable_write_node(node)
bounds(node.name_loc)
target = on_var_field(on_ident(node.name_loc.slice))
+
+ bounds(node.operator_loc)
+ on_op("=")
+
value = visit_write_value(node.value)
bounds(node.location)
@@ -2427,6 +2974,8 @@ module Prism
# ^^^^^^^^^^
def visit_match_predicate_node(node)
value = visit(node.value)
+ bounds(node.operator_loc)
+ on_kw("in")
pattern = on_in(visit_pattern_node(node.pattern), nil, nil)
on_case(value, pattern)
@@ -2436,6 +2985,10 @@ module Prism
# ^^^^^^^^^^
def visit_match_required_node(node)
value = visit(node.value)
+
+ bounds(node.operator_loc)
+ on_op("=>")
+
pattern = on_in(visit_pattern_node(node.pattern), nil, nil)
on_case(value, pattern)
@@ -2449,13 +3002,16 @@ module Prism
# 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."
+ def visit_error_recovery_node(node)
+ raise "Cannot visit error recovery nodes directly."
end
# module Foo; end
# ^^^^^^^^^^^^^^^
def visit_module_node(node)
+ bounds(node.module_keyword_loc)
+ on_kw("module")
+
constant_path =
if node.constant_path.is_a?(ConstantReadNode)
bounds(node.constant_path.location)
@@ -2466,6 +3022,9 @@ module Prism
bodystmt = visit_body_node(node.constant_path.location, node.body, true)
+ bounds(node.end_keyword_loc)
+ on_kw("end")
+
bounds(node.location)
on_module(constant_path, bodystmt)
end
@@ -2473,9 +3032,19 @@ module Prism
# (foo, bar), bar = qux
# ^^^^^^^^^^
def visit_multi_target_node(node)
+ if node.lparen_loc
+ bounds(node.lparen_loc)
+ on_lparen("(")
+ end
+
bounds(node.location)
targets = visit_multi_target_node_targets(node.lefts, node.rest, node.rights, true)
+ if node.rparen_loc
+ bounds(node.rparen_loc)
+ on_rparen(")")
+ end
+
if node.lparen_loc.nil?
targets
else
@@ -2527,9 +3096,22 @@ module Prism
# foo, bar = baz
# ^^^^^^^^^^^^^^
def visit_multi_write_node(node)
+ if node.lparen_loc
+ bounds(node.lparen_loc)
+ on_lparen("(")
+ end
+
bounds(node.location)
targets = visit_multi_target_node_targets(node.lefts, node.rest, node.rights, true)
+ if node.rparen_loc
+ bounds(node.rparen_loc)
+ on_rparen(")")
+ end
+
+ bounds(node.operator_loc)
+ on_op("=")
+
unless node.lparen_loc.nil?
bounds(node.lparen_loc)
targets = on_mlhs_paren(targets)
@@ -2547,6 +3129,9 @@ module Prism
# next foo
# ^^^^^^^^
def visit_next_node(node)
+ bounds(node.keyword_loc)
+ on_kw("next")
+
if node.arguments.nil?
bounds(node.location)
on_next(on_args_new)
@@ -2565,9 +3150,24 @@ module Prism
on_var_ref(on_kw("nil"))
end
+ # def foo(&nil); end
+ # ^^^^
+ def visit_no_block_parameter_node(node)
+ bounds(node.operator_loc)
+ on_op("&")
+ bounds(node.keyword_loc)
+ on_kw("nil")
+ bounds(node.location)
+ on_blockarg(:nil)
+ end
+
# def foo(**nil); end
# ^^^^^
def visit_no_keywords_parameter_node(node)
+ bounds(node.operator_loc)
+ on_op("**")
+ bounds(node.keyword_loc)
+ on_kw("nil")
bounds(node.location)
on_nokw_param(nil)
@@ -2600,7 +3200,11 @@ module Prism
# ^^^^^^^
def visit_optional_parameter_node(node)
bounds(node.name_loc)
- name = visit_token(node.name.to_s)
+ name = on_ident(node.name.to_s)
+
+ bounds(node.operator_loc)
+ on_op("=")
+
value = visit(node.value)
[name, value]
@@ -2610,6 +3214,14 @@ module Prism
# ^^^^^^
def visit_or_node(node)
left = visit(node.left)
+
+ bounds(node.operator_loc)
+ if node.operator == "or"
+ on_kw("or")
+ else
+ on_op("||")
+ end
+
right = visit(node.right)
bounds(node.location)
@@ -2633,9 +3245,19 @@ module Prism
# Visit a destructured positional parameter node.
private def visit_destructured_parameter_node(node)
+ if node.lparen_loc
+ bounds(node.lparen_loc)
+ on_lparen("(")
+ end
+
bounds(node.location)
targets = visit_multi_target_node_targets(node.lefts, node.rest, node.rights, false)
+ if node.rparen_loc
+ bounds(node.rparen_loc)
+ on_rparen(")")
+ end
+
bounds(node.lparen_loc)
on_mlhs_paren(targets)
end
@@ -2646,6 +3268,9 @@ module Prism
# (1)
# ^^^
def visit_parentheses_node(node)
+ bounds(node.opening_loc)
+ on_lparen("(")
+
body =
if node.body.nil?
on_stmts_add(on_stmts_new, on_void_stmt)
@@ -2653,6 +3278,8 @@ module Prism
visit(node.body)
end
+ bounds(node.closing_loc)
+ on_rparen(")")
bounds(node.location)
on_paren(body)
end
@@ -2660,8 +3287,15 @@ module Prism
# foo => ^(bar)
# ^^^^^^
def visit_pinned_expression_node(node)
+ bounds(node.operator_loc)
+ on_op("^")
+ bounds(node.lparen_loc)
+ on_lparen("(")
+
expression = visit(node.expression)
+ bounds(node.rparen_loc)
+ on_rparen(")")
bounds(node.location)
on_begin(expression)
end
@@ -2669,12 +3303,20 @@ module Prism
# foo = 1 and bar => ^foo
# ^^^^
def visit_pinned_variable_node(node)
+ bounds(node.operator_loc)
+ on_op("^")
+
visit(node.variable)
end
# END {}
# ^^^^^^
def visit_post_execution_node(node)
+ bounds(node.keyword_loc)
+ on_kw("END")
+ bounds(node.opening_loc)
+ on_lbrace("{")
+
statements =
if node.statements.nil?
bounds(node.location)
@@ -2683,6 +3325,8 @@ module Prism
visit(node.statements)
end
+ bounds(node.closing_loc)
+ on_rbrace("}")
bounds(node.location)
on_END(statements)
end
@@ -2690,6 +3334,11 @@ module Prism
# BEGIN {}
# ^^^^^^^^
def visit_pre_execution_node(node)
+ bounds(node.keyword_loc)
+ on_kw("BEGIN")
+ bounds(node.opening_loc)
+ on_lbrace("{")
+
statements =
if node.statements.nil?
bounds(node.location)
@@ -2698,6 +3347,8 @@ module Prism
visit(node.statements)
end
+ bounds(node.closing_loc)
+ on_rbrace("}")
bounds(node.location)
on_BEGIN(statements)
end
@@ -2705,7 +3356,7 @@ module Prism
# The top-level program node.
def visit_program_node(node)
body = node.statements.body
- body << nil if body.empty?
+ body = [nil] if body.empty?
statements = visit_statements_node_body(body)
bounds(node.location)
@@ -2716,6 +3367,10 @@ module Prism
# ^^^^
def visit_range_node(node)
left = visit(node.left)
+
+ bounds(node.operator_loc)
+ on_op(node.operator)
+
right = visit(node.right)
bounds(node.location)
@@ -2736,6 +3391,7 @@ module Prism
# ^^^^
def visit_redo_node(node)
bounds(node.location)
+ on_kw("redo")
on_redo
end
@@ -2778,6 +3434,9 @@ module Prism
# foo rescue bar
# ^^^^^^^^^^^^^^
def visit_rescue_modifier_node(node)
+ bounds(node.keyword_loc)
+ on_kw("rescue")
+
expression = visit_write_value(node.expression)
rescue_expression = visit(node.rescue_expression)
@@ -2788,6 +3447,9 @@ module Prism
# begin; rescue; end
# ^^^^^^^
def visit_rescue_node(node)
+ bounds(node.keyword_loc)
+ on_kw("rescue")
+
exceptions =
case node.exceptions.length
when 0
@@ -2825,6 +3487,11 @@ module Prism
end
end
+ if node.operator_loc
+ bounds(node.operator_loc)
+ on_op("=>")
+ end
+
reference = visit(node.reference)
statements =
if node.statements.nil?
@@ -2846,12 +3513,15 @@ module Prism
# def foo(*); end
# ^
def visit_rest_parameter_node(node)
+ bounds(node.operator_loc)
+ on_op("*")
+
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))
+ on_rest_param(on_ident(node.name.to_s))
end
end
@@ -2859,6 +3529,7 @@ module Prism
# ^^^^^
def visit_retry_node(node)
bounds(node.location)
+ on_kw("retry")
on_retry
end
@@ -2868,6 +3539,9 @@ module Prism
# return 1
# ^^^^^^^^
def visit_return_node(node)
+ bounds(node.keyword_loc)
+ on_kw("return")
+
if node.arguments.nil?
bounds(node.location)
on_return0
@@ -2894,9 +3568,17 @@ module Prism
# class << self; end
# ^^^^^^^^^^^^^^^^^^
def visit_singleton_class_node(node)
+ bounds(node.class_keyword_loc)
+ on_kw("class")
+ bounds(node.operator_loc)
+ on_op("<<")
+
expression = visit(node.expression)
bodystmt = visit_body_node(node.body&.location || node.end_keyword_loc, node.body)
+ bounds(node.end_keyword_loc)
+ on_kw("end")
+
bounds(node.location)
on_sclass(expression, bodystmt)
end
@@ -2931,6 +3613,8 @@ module Prism
# def foo(*); bar(*); end
# ^
def visit_splat_node(node)
+ bounds(node.operator_loc)
+ on_op("*")
visit(node.expression)
end
@@ -2953,26 +3637,68 @@ module Prism
# "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)
+ with_string_bounds(node) do
+ 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(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))
+ bounds(node.location)
+ on_string_literal(on_string_add(on_string_content, tstring_content))
+ end
end
end
+ # Responsible for emitting the various string-like begin/end events
+ private def with_string_bounds(node)
+ # `foo "bar": baz` doesn't emit the closing location
+ assoc = !(opening = node.opening)&.include?(":") && node.closing&.end_with?(":")
+
+ is_heredoc = opening&.start_with?("<<")
+ if is_heredoc
+ bounds(node.opening_loc)
+ on_heredoc_beg(node.opening)
+ elsif opening&.start_with?(":", "%s")
+ bounds(node.opening_loc)
+ on_symbeg(node.opening)
+ elsif opening&.start_with?("`", "%x")
+ bounds(node.opening_loc)
+ on_backtick(node.opening)
+ elsif opening && !opening.start_with?("?")
+ bounds(node.opening_loc)
+ on_tstring_beg(opening)
+ end
+
+ result = yield
+ if assoc
+ if node.closing != ":"
+ bounds(node.closing_loc)
+ on_label_end(node.closing)
+ end
+ return result
+ end
+
+ if is_heredoc
+ bounds(node.closing_loc)
+ on_heredoc_end(node.closing)
+ elsif node.closing_loc
+ bounds(node.closing_loc)
+ on_tstring_end(node.closing)
+ end
+
+ result
+ 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
@@ -3050,42 +3776,39 @@ module Prism
# 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
+ visit_heredoc_node(node.parts, on_string_content) do |parts, part|
+ on_string_add(parts, part)
+ end
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
+ visit_heredoc_node(node.parts, on_xstring_new) do |parts, part|
+ on_xstring_add(parts, part)
+ end
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))
+ bounds(node.keyword_loc)
+ on_kw("super")
+
+ if node.lparen_loc
+ bounds(node.lparen_loc)
+ on_lparen("(")
+ end
+
+ arguments, block_node = visit_call_node_arguments(node.arguments, node.block, trailing_comma?(node.arguments&.location || node.location, node.rparen_loc || node.location))
+
+ if node.rparen_loc
+ bounds(node.rparen_loc)
+ on_rparen(")")
+ end
+
+ block = visit(block_node)
if !node.lparen_loc.nil?
bounds(node.lparen_loc)
@@ -3095,35 +3818,36 @@ module Prism
bounds(node.location)
call = on_super(arguments)
- if block.nil?
- call
- else
+ if block_node
bounds(node.block.location)
on_method_add_block(call, block)
+ else
+ call
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))
+ with_string_bounds(node) do
+ if node.value_loc.nil?
+ bounds(node.location)
+ on_dyna_symbol(on_string_content)
+ elsif (opening = node.opening)&.match?(/^%s|['"]:?$/)
+ bounds(node.value_loc)
+ content = on_string_add(on_string_content, on_tstring_content(node.value))
+ bounds(node.location)
+ 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
-
- 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
@@ -3137,6 +3861,9 @@ module Prism
# undef foo
# ^^^^^^^^^
def visit_undef_node(node)
+ bounds(node.keyword_loc)
+ on_kw("undef")
+
names = visit_all(node.names)
bounds(node.location)
@@ -3150,7 +3877,13 @@ module Prism
# ^^^^^^^^^^^^^^
def visit_unless_node(node)
if node.statements.nil? || (node.predicate.location.start_offset < node.statements.location.start_offset)
+ bounds(node.keyword_loc)
+ on_kw("unless")
predicate = visit(node.predicate)
+ if node.then_keyword_loc
+ bounds(node.then_keyword_loc)
+ on_kw("then")
+ end
statements =
if node.statements.nil?
bounds(node.location)
@@ -3160,10 +3893,17 @@ module Prism
end
else_clause = visit(node.else_clause)
+ if node.end_keyword_loc && !node.else_clause
+ bounds(node.end_keyword_loc)
+ on_kw("end")
+ end
+
bounds(node.location)
on_unless(predicate, statements, else_clause)
else
statements = visit(node.statements.body.first)
+ bounds(node.keyword_loc)
+ on_kw("unless")
predicate = visit(node.predicate)
bounds(node.location)
@@ -3177,7 +3917,14 @@ module Prism
# bar until foo
# ^^^^^^^^^^^^^
def visit_until_node(node)
+ bounds(node.keyword_loc)
+ on_kw("until")
+
if node.statements.nil? || (node.predicate.location.start_offset < node.statements.location.start_offset)
+ if node.do_keyword_loc
+ bounds(node.do_keyword_loc)
+ on_kw("do")
+ end
predicate = visit(node.predicate)
statements =
if node.statements.nil?
@@ -3187,6 +3934,11 @@ module Prism
visit(node.statements)
end
+ if node.closing_loc
+ bounds(node.closing_loc)
+ on_kw("end")
+ end
+
bounds(node.location)
on_until(predicate, statements)
else
@@ -3204,7 +3956,14 @@ module Prism
# 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.
+ bounds(node.keyword_loc)
+ on_kw("when")
+
conditions = visit_arguments(node.conditions)
+ if node.then_keyword_loc
+ bounds(node.then_keyword_loc)
+ on_kw("then")
+ end
statements =
if node.statements.nil?
bounds(node.location)
@@ -3223,7 +3982,17 @@ module Prism
# ^^^^^^^^^^^^^
def visit_while_node(node)
if node.statements.nil? || (node.predicate.location.start_offset < node.statements.location.start_offset)
+ bounds(node.keyword_loc)
+ on_kw("while")
+ if node.do_keyword_loc
+ bounds(node.do_keyword_loc)
+ on_kw("do")
+ end
predicate = visit(node.predicate)
+ if node.closing_loc
+ bounds(node.closing_loc)
+ on_kw("end")
+ end
statements =
if node.statements.nil?
bounds(node.location)
@@ -3236,6 +4005,8 @@ module Prism
on_while(predicate, statements)
else
statements = visit(node.statements.body.first)
+ bounds(node.keyword_loc)
+ on_kw("while")
predicate = visit(node.predicate)
bounds(node.location)
@@ -3246,20 +4017,22 @@ module Prism
# `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)
+ with_string_bounds(node) do
+ 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(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))
+ bounds(node.location)
+ on_xstring_literal(on_xstring_add(on_xstring_new, content))
+ end
end
end
@@ -3269,10 +4042,18 @@ module Prism
# yield 1
# ^^^^^^^
def visit_yield_node(node)
+ bounds(node.keyword_loc)
+ on_kw("yield")
+
if node.arguments.nil? && node.lparen_loc.nil?
bounds(node.location)
on_yield0
else
+ if node.lparen_loc
+ bounds(node.lparen_loc)
+ on_lparen("(")
+ end
+
arguments =
if node.arguments.nil?
bounds(node.location)
@@ -3282,6 +4063,8 @@ module Prism
end
unless node.lparen_loc.nil?
+ bounds(node.rparen_loc)
+ on_rparen(")")
bounds(node.lparen_loc)
arguments = on_paren(arguments)
end
@@ -3295,7 +4078,11 @@ module Prism
# Lazily initialize the parse result.
def result
- @result ||= Prism.parse(source, partial_script: true)
+ @result ||= Prism.parse(source, partial_script: true, version: "current", freeze: true, encoding: source.encoding)
+ end
+
+ def line_and_column_cache
+ @line_and_column_cache ||= LineAndColumnCache.new(result.source)
end
##########################################################################
@@ -3316,30 +4103,34 @@ module Prism
# 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 "."
+ if token == "."
on_period(token)
- when "`"
+ elsif token == "`"
on_backtick(token)
- when *(allow_keywords ? KEYWORDS : [])
+ elsif allow_keywords && KEYWORDS.include?(token)
on_kw(token)
- when /^_/
+ elsif token.start_with?("_")
on_ident(token)
- when /^[[:upper:]]\w*$/
+ elsif token.match?(/^[[:upper:]]\w*$/)
on_const(token)
- when /^@@/
+ elsif token.start_with?("@@")
on_cvar(token)
- when /^@/
+ elsif token.start_with?("@")
on_ivar(token)
- when /^\$/
+ elsif token.start_with?("$")
on_gvar(token)
- when /^[[:punct:]]/
+ elsif token.match?(/^[[:punct:]]/)
on_op(token)
else
on_ident(token)
end
end
+ # Visit either `.`, `&.`, or `::`.
+ def visit_call_operator(token)
+ token == "." ? on_period(token) : on_op(token)
+ end
+
# Visit a node that represents a number. We need to explicitly handle the
# unary - operator.
def visit_number_node(node)
@@ -3347,6 +4138,9 @@ module Prism
location = node.location
if slice[0] == "-"
+ bounds(location.copy(length: 1))
+ on_op("-")
+
bounds(location.copy(start_offset: location.start_offset + 1))
value = yield slice[1..-1]
@@ -3395,26 +4189,24 @@ module Prism
# 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
+ @lineno, @column = line_and_column_cache.line_and_column(location.start_offset)
end
+ # :startdoc:
+
##########################################################################
# 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
+ def _dispatch_1(arg); arg end
+ def _dispatch_2(arg, _); arg end
+ def _dispatch_3(arg, _, _); arg end
+ def _dispatch_4(arg, _, _, _); arg end
+ def _dispatch_5(arg, _, _, _, _); arg end
+ def _dispatch_7(arg, _, _, _, _, _, _); arg end
# :startdoc:
#
diff --git a/lib/prism/translation/ripper/filter.rb b/lib/prism/translation/ripper/filter.rb
new file mode 100644
index 0000000000..19deef2d37
--- /dev/null
+++ b/lib/prism/translation/ripper/filter.rb
@@ -0,0 +1,53 @@
+# frozen_string_literal: true
+
+module Prism
+ module Translation
+ class Ripper
+ class Filter # :nodoc:
+ # :stopdoc:
+ def initialize(src, filename = '-', lineno = 1)
+ @__lexer = Lexer.new(src, filename, lineno)
+ @__line = nil
+ @__col = nil
+ @__state = nil
+ end
+
+ def filename
+ @__lexer.filename
+ end
+
+ def lineno
+ @__line
+ end
+
+ def column
+ @__col
+ end
+
+ def state
+ @__state
+ end
+
+ def parse(init = nil)
+ data = init
+ @__lexer.lex.each do |pos, event, tok, state|
+ @__line, @__col = *pos
+ @__state = state
+ data = if respond_to?(event, true)
+ then __send__(event, tok, data)
+ else on_default(event, tok, data)
+ end
+ end
+ data
+ end
+
+ private
+
+ def on_default(event, token, data)
+ data
+ end
+ # :startdoc:
+ end
+ end
+ end
+end
diff --git a/lib/prism/translation/ripper/lexer.rb b/lib/prism/translation/ripper/lexer.rb
new file mode 100644
index 0000000000..c6aeae4bd7
--- /dev/null
+++ b/lib/prism/translation/ripper/lexer.rb
@@ -0,0 +1,133 @@
+# frozen_string_literal: true
+# :markup: markdown
+
+require_relative "../ripper"
+
+module Prism
+ module Translation
+ class Ripper
+ class Lexer < Ripper # :nodoc:
+ class State # :nodoc:
+ attr_reader :to_int, :to_s
+
+ def initialize(i)
+ @to_int = i
+ @to_s = Ripper.lex_state_name(i)
+ freeze
+ end
+
+ def [](index)
+ case index
+ when 0, :to_int
+ @to_int
+ when 1, :to_s
+ @to_s
+ else
+ nil
+ end
+ end
+
+ alias to_i to_int
+ alias inspect to_s
+ def pretty_print(q) q.text(to_s) end
+ def ==(i) super or to_int == i end
+ def &(i) self.class.new(to_int & i) end
+ def |(i) self.class.new(to_int | i) end
+ def allbits?(i) to_int.allbits?(i) end
+ def anybits?(i) to_int.anybits?(i) end
+ def nobits?(i) to_int.nobits?(i) end
+
+ # Instances are frozen and there are only a handful of them so we
+ # cache them here.
+ STATES = Hash.new { |hash, key| hash[key] = State.new(key) }
+ private_constant :STATES
+
+ def self.[](i)
+ STATES[i]
+ end
+ end
+
+ class Elem # :nodoc:
+ attr_accessor :pos, :event, :tok, :state, :message
+
+ def initialize(pos, event, tok, state, message = nil)
+ @pos = pos
+ @event = event
+ @tok = tok
+ @state = State[state]
+ @message = message
+ end
+
+ def [](index)
+ case index
+ when 0, :pos
+ @pos
+ when 1, :event
+ @event
+ when 2, :tok
+ @tok
+ when 3, :state
+ @state
+ when 4, :message
+ @message
+ else
+ nil
+ end
+ end
+
+ def inspect
+ "#<#{self.class}: #{event}@#{pos[0]}:#{pos[1]}:#{state}: #{tok.inspect}#{": " if message}#{message}>"
+ end
+
+ alias to_s inspect
+
+ def pretty_print(q)
+ q.group(2, "#<#{self.class}:", ">") {
+ q.breakable
+ q.text("#{event}@#{pos[0]}:#{pos[1]}")
+ q.breakable
+ state.pretty_print(q)
+ q.breakable
+ q.text("token: ")
+ tok.pretty_print(q)
+ if message
+ q.breakable
+ q.text("message: ")
+ q.text(message)
+ end
+ }
+ end
+
+ def to_a
+ if @message
+ [@pos, @event, @tok, @state, @message]
+ else
+ [@pos, @event, @tok, @state]
+ end
+ end
+ end
+
+ # Pretty much just the same as Prism.lex_compat.
+ def lex(raise_errors: false)
+ Ripper.lex(@source, filename, lineno, raise_errors: raise_errors)
+ end
+
+ # Returns the lex_compat result wrapped in `Elem`. Errors are omitted.
+ # Since ripper is a streaming parser, tokens are expected to be emitted in the order
+ # that the parser encounters them. This is not implemented.
+ def parse(...)
+ lex(...).map do |position, event, token, state|
+ Elem.new(position, event, token, state.to_int)
+ end
+ end
+
+ # Similar to parse but ripper sorts the elements by position in the source. Also
+ # includes errors. Since prism does error recovery, in cases of syntax errors
+ # the result may differ greatly compared to ripper.
+ def scan(...)
+ parse(...)
+ end
+ end
+ end
+ end
+end
diff --git a/lib/prism/translation/ripper/sexp.rb b/lib/prism/translation/ripper/sexp.rb
index 8cfefc8472..46c0333544 100644
--- a/lib/prism/translation/ripper/sexp.rb
+++ b/lib/prism/translation/ripper/sexp.rb
@@ -8,9 +8,7 @@ module Prism
class Ripper
# This class mirrors the ::Ripper::SexpBuilder subclass of ::Ripper that
# returns the arrays of [type, *children].
- class SexpBuilder < Ripper
- # :stopdoc:
-
+ class SexpBuilder < Ripper # :nodoc:
attr_reader :error
private
@@ -65,16 +63,12 @@ module Prism
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:
-
+ class SexpBuilderPP < SexpBuilder # :nodoc:
private
def on_heredoc_dedent(val, width)
@@ -118,8 +112,6 @@ module Prism
alias_method "on_#{event}", :_dispatch_event_push
end
end
-
- # :startdoc:
end
end
end
diff --git a/lib/prism/translation/ripper/shim.rb b/lib/prism/translation/ripper/shim.rb
index 10e21cd16a..00ed625da3 100644
--- a/lib/prism/translation/ripper/shim.rb
+++ b/lib/prism/translation/ripper/shim.rb
@@ -2,4 +2,6 @@
# This writes the prism ripper translation into the Ripper constant so that
# users can transparently use Ripper without any changes.
+# :stopdoc:
Ripper = Prism::Translation::Ripper
+# :startdoc:
diff --git a/lib/prism/translation/ruby_parser.rb b/lib/prism/translation/ruby_parser.rb
index ac538a2e97..42bc5ee658 100644
--- a/lib/prism/translation/ruby_parser.rb
+++ b/lib/prism/translation/ruby_parser.rb
@@ -2,19 +2,24 @@
# :markup: markdown
begin
- require "ruby_parser"
+ require "sexp"
rescue LoadError
- warn(%q{Error: Unable to load ruby_parser. Add `gem "ruby_parser"` to your Gemfile.})
+ warn(%q{Error: Unable to load sexp. Add `gem "sexp_processor"` to your Gemfile.})
exit(1)
end
+class RubyParser # :nodoc:
+ class SyntaxError < RuntimeError # :nodoc:
+ end
+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
+ class Compiler < ::Prism::Compiler # :nodoc:
# 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.
@@ -35,34 +40,26 @@ module Prism
@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)
@@ -79,10 +76,8 @@ module Prism
end
end
- # ```
# []
# ^^
- # ```
def visit_array_node(node)
if in_pattern
s(node, :array_pat, nil).concat(visit_all(node.elements))
@@ -91,10 +86,8 @@ module Prism
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)
@@ -116,29 +109,23 @@ module Prism
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)]
@@ -147,18 +134,14 @@ module Prism
end
end
- # ```
# $+
# ^^
- # ```
def visit_back_reference_read_node(node)
- s(node, :back_ref, node.name.name.delete_prefix("$").to_sym)
+ s(node, :back_ref, node.name.to_s.delete_prefix("$").to_sym)
end
- # ```
# begin end
# ^^^^^^^^^
- # ```
def visit_begin_node(node)
result = node.statements.nil? ? s(node, :nil) : visit(node.statements)
@@ -190,20 +173,16 @@ module Prism
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
@@ -213,10 +192,8 @@ module Prism
s(node, :block_pass, visit(node.expression))
end
- # ```
# def foo(&bar); end
# ^^^^
- # ```
def visit_block_parameter_node(node)
:"&#{node.name}"
end
@@ -257,13 +234,11 @@ module Prism
result
end
- # ```
# break
# ^^^^^
#
# break foo
# ^^^^^^^^^
- # ```
def visit_break_node(node)
if node.arguments.nil?
s(node, :break)
@@ -274,7 +249,6 @@ module Prism
end
end
- # ```
# foo
# ^^^
#
@@ -283,7 +257,6 @@ module Prism
#
# foo.bar() {}
# ^^^^^^^^^^^^
- # ```
def visit_call_node(node)
case node.name
when :!~
@@ -322,10 +295,8 @@ module Prism
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)
@@ -334,10 +305,8 @@ module Prism
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, :"&&")
@@ -346,10 +315,8 @@ module Prism
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, :"||")
@@ -371,42 +338,32 @@ module Prism
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)
@@ -415,63 +372,52 @@ module Prism
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
+ result =
+ 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
+
+ attach_comments(result, node)
+ result
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
@@ -482,61 +428,47 @@ module Prism
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)
@@ -545,45 +477,35 @@ module Prism
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?
@@ -595,13 +517,11 @@ module Prism
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 =
@@ -611,7 +531,9 @@ module Prism
s(node, :defs, visit(node.receiver), name)
end
+ attach_comments(result, node)
result.line(node.name_loc.start_line)
+
if node.parameters.nil?
result << s(node, :args).line(node.name_loc.start_line)
else
@@ -628,71 +550,55 @@ module Prism
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?))
@@ -701,112 +607,83 @@ module Prism
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) })
@@ -820,7 +697,6 @@ module Prism
result
end
- # ```
# if foo then bar end
# ^^^^^^^^^^^^^^^^^^^
#
@@ -829,7 +705,6 @@ module Prism
#
# foo ? bar : baz
# ^^^^^^^^^^^^^^^
- # ```
def visit_if_node(node)
s(node, :if, visit(node.predicate), visit(node.statements), visit(node.subsequent))
end
@@ -839,24 +714,18 @@ module Prism
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)
@@ -868,10 +737,8 @@ module Prism
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
@@ -883,10 +750,8 @@ module Prism
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
@@ -898,10 +763,8 @@ module Prism
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
@@ -913,10 +776,8 @@ module Prism
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?
@@ -924,69 +785,50 @@ module Prism
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 =
@@ -1002,10 +844,8 @@ module Prism
s(node, :match, regexp)
end
- # ```
# /foo #{bar}/
# ^^^^^^^^^^^^
- # ```
def visit_interpolated_regular_expression_node(node)
parts = visit_interpolated_parts(node.parts)
@@ -1019,28 +859,22 @@ module Prism
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)
@@ -1120,29 +954,23 @@ module Prism
results
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
@@ -1164,10 +992,8 @@ module Prism
end
end
- # ```
# foo
# ^^^
- # ```
def visit_local_variable_read_node(node)
if node.name.match?(/^_\d$/)
s(node, :call, nil, node.name)
@@ -1176,77 +1002,56 @@ module Prism
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
@@ -1254,14 +1059,12 @@ module Prism
# 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"
+ def visit_error_recovery_node(node)
+ raise "Cannot visit error recovery node directly"
end
- # ```
# module Foo; end
# ^^^^^^^^^^^^^^^
- # ```
def visit_module_node(node)
name =
if node.constant_path.is_a?(ConstantReadNode)
@@ -1270,20 +1073,22 @@ module Prism
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
+ result =
+ 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
+
+ attach_comments(result, node)
+ result
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)
@@ -1292,10 +1097,8 @@ module Prism
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)
@@ -1315,13 +1118,11 @@ module Prism
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)
@@ -1333,58 +1134,50 @@ module Prism
end
end
- # ```
# nil
# ^^^
- # ```
def visit_nil_node(node)
s(node, :nil)
end
- # ```
+ # def foo(&nil); end
+ # ^^^^
+ def visit_no_block_parameter_node(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)
@@ -1401,13 +1194,11 @@ module Prism
end
end
- # ```
# def foo(bar, *baz); end
# ^^^^^^^^^
- # ```
def visit_parameters_node(node)
children =
- node.compact_child_nodes.map do |element|
+ node.each_child_node.map do |element|
if element.is_a?(MultiTargetNode)
visit_destructured_parameter(element)
else
@@ -1418,10 +1209,8 @@ module Prism
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|
@@ -1440,13 +1229,11 @@ module Prism
s(node, :masgn).concat(children)
end
- # ```
# ()
# ^^
#
# (1)
# ^^^
- # ```
def visit_parentheses_node(node)
if node.body.nil?
s(node, :nil)
@@ -1455,18 +1242,14 @@ module Prism
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)
@@ -1490,10 +1273,8 @@ module Prism
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)
@@ -1514,58 +1295,44 @@ module Prism
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)
@@ -1581,32 +1348,26 @@ module Prism
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)
@@ -1618,10 +1379,8 @@ module Prism
end
end
- # ```
# self
# ^^^^
- # ```
def visit_self_node(node)
s(node, :self)
end
@@ -1631,42 +1390,33 @@ module Prism
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)
# ^^^^
#
@@ -1675,7 +1425,6 @@ module Prism
#
# def foo(*); bar(*); end
# ^
- # ```
def visit_splat_node(node)
if node.expression.nil?
s(node, :splat)
@@ -1695,10 +1444,8 @@ module Prism
end
end
- # ```
# "foo"
# ^^^^^
- # ```
def visit_string_node(node)
unescaped = node.unescaped
@@ -1710,10 +1457,8 @@ module Prism
s(node, :str, unescaped)
end
- # ```
# super(foo)
# ^^^^^^^^^^
- # ```
def visit_super_node(node)
arguments = node.arguments&.arguments || []
block = node.block
@@ -1726,76 +1471,60 @@ module Prism
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)
@@ -1807,19 +1536,28 @@ module Prism
result
end
- # ```
# yield
# ^^^^^
#
# yield 1
# ^^^^^^^
- # ```
def visit_yield_node(node)
s(node, :yield).concat(visit_all(node.arguments&.arguments || []))
end
private
+ # Attach prism comments to the given sexp.
+ def attach_comments(sexp, node)
+ return unless node.comments
+ return if node.comments.empty?
+
+ extra = node.location.start_line - node.comments.last.location.start_line
+ comments = node.comments.map(&:slice)
+ comments.concat([nil] * [0, extra].max)
+ sexp.comments = comments.join("\n")
+ end
+
# 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)
@@ -1898,6 +1636,14 @@ module Prism
translate(Prism.parse_file(filepath, partial_script: true), filepath)
end
+ # Parse the give file and translate it into the
+ # seattlerb/ruby_parser gem's Sexp format. This method is
+ # provided for API compatibility to RubyParser and takes an
+ # optional +timeout+ argument.
+ def process(ruby, file = "(string)", timeout = nil)
+ Timeout.timeout(timeout) { parse(ruby, file) }
+ end
+
class << self
# Parse the given source and translate it into the seattlerb/ruby_parser
# gem's Sexp format.
@@ -1922,6 +1668,7 @@ module Prism
raise ::RubyParser::SyntaxError, "#{filepath}:#{error.location.start_line} :: #{error.message}"
end
+ result.attach_comments!
result.value.accept(Compiler.new(filepath))
end
end
diff --git a/lib/resolv.gemspec b/lib/resolv.gemspec
index bfa2f9ff31..66aed34e01 100644
--- a/lib/resolv.gemspec
+++ b/lib/resolv.gemspec
@@ -21,9 +21,8 @@ Gem::Specification.new do |spec|
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
+ excludes = %W[/.git* /bin /test /*file /#{File.basename(__FILE__)}]
+ spec.files = IO.popen(%W[git -C #{__dir__} ls-files -z --] + excludes.map {|e| ":^#{e}"}, &:read).split("\x0")
spec.bindir = "exe"
spec.executables = []
spec.require_paths = ["lib"]
diff --git a/lib/resolv.rb b/lib/resolv.rb
index 73410f1324..6b58f92813 100644
--- a/lib/resolv.rb
+++ b/lib/resolv.rb
@@ -34,7 +34,8 @@ require 'rbconfig'
class Resolv
- VERSION = "0.6.2"
+ # The version string
+ VERSION = "0.7.1"
##
# Looks up the first IP address for +name+.
@@ -174,21 +175,19 @@ class Resolv
class ResolvTimeout < Timeout::Error; end
- WINDOWS = /mswin|cygwin|mingw|bccwin/ =~ RUBY_PLATFORM || ::RbConfig::CONFIG['host_os'] =~ /mswin/
- private_constant :WINDOWS
-
##
# Resolv::Hosts is a hostname resolver that uses the system hosts file.
class Hosts
- if WINDOWS
+ if /mswin|cygwin|mingw|bccwin/ =~ RUBY_PLATFORM || ::RbConfig::CONFIG['host_os'] =~ /mswin/
begin
require 'win32/resolv' unless defined?(Win32::Resolv)
- DefaultFileName = Win32::Resolv.get_hosts_path || IO::NULL
+ hosts = Win32::Resolv.get_hosts_path || IO::NULL
rescue LoadError
end
end
- DefaultFileName ||= '/etc/hosts'
+ # The default file name for host names
+ DefaultFileName = hosts || '/etc/hosts'
##
# Creates a new Resolv::Hosts, using +filename+ for its data source.
@@ -488,13 +487,18 @@ class Resolv
# * Resolv::DNS::Resource::IN::A
# * Resolv::DNS::Resource::IN::AAAA
# * Resolv::DNS::Resource::IN::ANY
+ # * Resolv::DNS::Resource::IN::CAA
# * Resolv::DNS::Resource::IN::CNAME
# * Resolv::DNS::Resource::IN::HINFO
+ # * Resolv::DNS::Resource::IN::HTTPS
+ # * Resolv::DNS::Resource::IN::LOC
# * Resolv::DNS::Resource::IN::MINFO
# * Resolv::DNS::Resource::IN::MX
# * Resolv::DNS::Resource::IN::NS
# * Resolv::DNS::Resource::IN::PTR
# * Resolv::DNS::Resource::IN::SOA
+ # * Resolv::DNS::Resource::IN::SRV
+ # * Resolv::DNS::Resource::IN::SVCB
# * Resolv::DNS::Resource::IN::TXT
# * Resolv::DNS::Resource::IN::WKS
#
@@ -526,6 +530,8 @@ class Resolv
}
end
+ # :stopdoc:
+
def fetch_resource(name, typeclass)
lazy_initialize
truncated = {}
@@ -720,7 +726,8 @@ class Resolv
begin
reply, from = recv_reply(select_result[0])
rescue Errno::ECONNREFUSED, # GNU/Linux, FreeBSD
- Errno::ECONNRESET # Windows
+ Errno::ECONNRESET, # Windows
+ EOFError
# No name server running on the server?
# Don't wait anymore.
raise ResolvTimeout
@@ -929,8 +936,11 @@ class Resolv
end
def recv_reply(readable_socks)
- len = readable_socks[0].read(2).unpack('n')[0]
+ len_data = readable_socks[0].read(2)
+ raise EOFError if len_data.nil? || len_data.bytesize != 2
+ len = len_data.unpack('n')[0]
reply = @socks[0].read(len)
+ raise EOFError if reply.nil? || reply.bytesize != len
return reply, nil
end
@@ -1022,8 +1032,7 @@ class Resolv
def Config.default_config_hash(filename="/etc/resolv.conf")
if File.exist? filename
Config.parse_resolv_conf(filename)
- elsif WINDOWS
- require 'win32/resolv' unless defined?(Win32::Resolv)
+ elsif defined?(Win32::Resolv)
search, nameserver = Win32::Resolv.get_resolv_info
config_hash = {}
config_hash[:nameserver] = nameserver if nameserver
@@ -2927,15 +2936,21 @@ class Resolv
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
+ |[3-9][0-9]?/x # :nodoc:
+
+ ##
+ # Regular expression IPv4 addresses must match.
Regex = /\A(#{Regex256})\.(#{Regex256})\.(#{Regex256})\.(#{Regex256})\z/
+ ##
+ # Creates a new IPv4 address from +arg+ which may be:
+ #
+ # IPv4:: returns +arg+.
+ # String:: +arg+ must match the IPv4::Regex constant
+
def self.create(arg)
case arg
when IPv4
@@ -3244,14 +3259,16 @@ class Resolv
end
- module LOC
+ module LOC # :nodoc:
##
# A Resolv::LOC::Size
class Size
- Regex = /^(\d+\.*\d*)[m]$/
+ # Regular expression LOC size must match.
+
+ Regex = /\A0*(\d{1,8}(?:\.\d+)?)m\z/
##
# Creates a new LOC::Size from +arg+ which may be:
@@ -3264,18 +3281,20 @@ class Resolv
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
+ unless Regex =~ arg
raise ArgumentError.new("not a properly formed Size string: " + arg)
end
- return Size.new(scalar)
+ unless (0.0...1e8) === (scalar = $1.to_f)
+ raise ArgumentError.new("out of range as Size: #{arg}")
+ end
+ str = (scalar * 100).to_i.to_s
+ return new([(str[0].to_i << 4) + (str.bytesize-1)].pack("C"))
else
raise ArgumentError.new("cannot interpret as Size: #{arg.inspect}")
end
end
+ # Internal use; use self.create.
def initialize(scalar)
@scalar = scalar
end
@@ -3286,8 +3305,8 @@ class Resolv
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"
+ s, = @scalar.unpack("C")
+ return "#{(s >> 4) * (10.0 ** ((s & 0xf) - 2))}m"
end
def inspect # :nodoc:
@@ -3313,7 +3332,12 @@ class Resolv
class Coord
- Regex = /^(\d+)\s(\d+)\s(\d+\.\d+)\s([NESW])$/
+ # Regular expression LOC Coord must match.
+
+ Regex = /\A0*(\d{1,3})\s([0-5]?\d)\s([0-5]?\d(?:\.\d+)?)\s([NESW])\z/
+
+ # Bias for the equator/prime meridian, in thousandths of a second of arc.
+ Bias = 1 << 31
##
# Creates a new LOC::Coord from +arg+ which may be:
@@ -3326,27 +3350,30 @@ class Resolv
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
+ unless m = Regex.match(arg)
raise ArgumentError.new("not a properly formed Coord string: " + arg)
end
- return Coord.new(coordinates,orientation)
+
+ arc = (m[1].to_i * 3_600_000) + (m[2].to_i * 60_000) + (m[3].to_f * 1_000).to_i
+ dir = m[4]
+ lat = dir[/[NS]/]
+ unless arc <= (lat ? 324_000_000 : 648_000_000) # (lat ? 90 : 180) * 3_600_000
+ raise ArgumentError.new("out of range as Coord: #{arg}")
+ end
+
+ hemi = dir[/[NE]/] ? 1 : -1
+ return new([arc * hemi + Bias].pack("N"), lat ? "lat" : "lon")
else
raise ArgumentError.new("cannot interpret as Coord: #{arg.inspect}")
end
end
+ # Internal use; use self.create.
def initialize(coordinates,orientation)
- unless coordinates.kind_of?(String)
+ unless coordinates.kind_of?(String) and coordinates.bytesize == 4
raise ArgumentError.new("Coord must be a 32bit unsigned integer in hex format: #{coordinates.inspect}")
end
- unless orientation.kind_of?(String) && orientation[/^lon$|^lat$/]
+ unless orientation == "lon" || orientation == "lat"
raise ArgumentError.new('Coord expects orientation to be a String argument of "lat" or "lon"')
end
@coordinates = coordinates
@@ -3363,22 +3390,17 @@ class Resolv
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"
+ c, = @coordinates.unpack("N")
+ val = (c -= Bias).abs
+ val, fracsecs = val.divmod(1000)
+ val, secs = val.divmod(60)
+ degs, mins = val.divmod(60)
+ hemi = if c.negative?
+ @orientation == "lon" ? "W" : "S"
else
- hemi = @orientation[/^lon$/] ? "W" : "S"
+ @orientation == "lat" ? "N" : "E"
end
- return degs << " " << mins << " " << secs << "." << fracsecs << " " << hemi
+ format("%d %02d %02d.%03d %s", degs, mins, secs, fracsecs, hemi)
end
def inspect # :nodoc:
@@ -3404,7 +3426,12 @@ class Resolv
class Alt
- Regex = /^([+-]*\d+\.*\d*)[m]$/
+ # Regular expression LOC Alt must match.
+
+ Regex = /\A([+-]?0*\d{1,8}(?:\.\d+)?)m\z/
+
+ # Bias to a base of 100,000m below the WGS 84 reference spheroid.
+ Bias = 100_000_00
##
# Creates a new LOC::Alt from +arg+ which may be:
@@ -3417,18 +3444,20 @@ class Resolv
when Alt
return arg
when String
- altitude = ''
- if Regex =~ arg
- altitude = [($1.to_f*(1e2))+(1e7)].pack("N")
- else
+ unless Regex =~ arg
raise ArgumentError.new("not a properly formed Alt string: " + arg)
end
- return Alt.new(altitude)
+ altitude = ($1.to_f * 100).to_i + Bias
+ unless (0...0x1_0000_0000) === altitude
+ raise ArgumentError.new("out of raise as Alt: #{arg}")
+ end
+ return new([altitude].pack("N"))
else
raise ArgumentError.new("cannot interpret as Alt: #{arg.inspect}")
end
end
+ # Internal use; use self.create.
def initialize(altitude)
@altitude = altitude
end
@@ -3439,8 +3468,8 @@ class Resolv
attr_reader :altitude
def to_s # :nodoc:
- a = @altitude.unpack("N").join.to_i
- return ((a.to_f/1e2)-1e5).to_s + "m"
+ a, = @altitude.unpack("N")
+ return "#{(a - Bias).fdiv(100)}m"
end
def inspect # :nodoc:
diff --git a/lib/rubygems.rb b/lib/rubygems.rb
index f8f1451ee6..d289cab0fd 100644
--- a/lib/rubygems.rb
+++ b/lib/rubygems.rb
@@ -9,13 +9,15 @@
require "rbconfig"
module Gem
- VERSION = "3.8.0.dev"
+ VERSION = "4.1.0.dev"
end
require_relative "rubygems/defaults"
require_relative "rubygems/deprecate"
require_relative "rubygems/errors"
require_relative "rubygems/target_rbconfig"
+require_relative "rubygems/win_platform"
+require_relative "rubygems/util/atomic_file_writer"
##
# RubyGems is the Ruby standard for publishing and managing third party
@@ -36,7 +38,7 @@ require_relative "rubygems/target_rbconfig"
# Further RubyGems documentation can be found at:
#
# * {RubyGems Guides}[https://guides.rubygems.org]
-# * {RubyGems API}[https://www.rubydoc.info/github/rubygems/rubygems] (also available from
+# * {RubyGems API}[https://guides.rubygems.org/rubygems-org-api/] (also available from
# <tt>gem server</tt>)
#
# == RubyGems Plugins
@@ -68,7 +70,7 @@ require_relative "rubygems/target_rbconfig"
# == Bugs
#
# You can submit bugs to the
-# {RubyGems bug tracker}[https://github.com/rubygems/rubygems/issues]
+# {RubyGems bug tracker}[https://github.com/ruby/rubygems/issues]
# on GitHub
#
# == Credits
@@ -104,7 +106,7 @@ require_relative "rubygems/target_rbconfig"
#
# == License
#
-# See {LICENSE.txt}[https://github.com/rubygems/rubygems/blob/master/LICENSE.txt] for permissions.
+# See {LICENSE.txt}[https://github.com/ruby/rubygems/blob/master/LICENSE.txt] for permissions.
#
# Thanks!
#
@@ -113,18 +115,6 @@ require_relative "rubygems/target_rbconfig"
module Gem
RUBYGEMS_DIR = __dir__
- ##
- # An Array of Regexps that match windows Ruby platforms.
-
- WIN_PATTERNS = [
- /bccwin/i,
- /cygwin/i,
- /djgpp/i,
- /mingw/i,
- /mswin/i,
- /wince/i,
- ].freeze
-
GEM_DEP_FILES = %w[
gem.deps.rb
gems.rb
@@ -160,8 +150,6 @@ module Gem
DEFAULT_SOURCE_DATE_EPOCH = 315_619_200
- @@win_platform = nil
-
@configuration = nil
@gemdeps = nil
@loaded_specs = {}
@@ -205,11 +193,13 @@ module Gem
begin
spec.activate
rescue Gem::LoadError => e # this could fail due to gem dep collisions, go lax
- spec_by_name = Gem::Specification.find_by_name(spec.name)
- if spec_by_name.nil?
+ name = spec.name
+ spec = Gem::Specification.find_unloaded_by_path(path)
+ spec ||= Gem::Specification.find_by_name(name)
+ if spec.nil?
raise e
else
- spec_by_name.activate
+ spec.activate
end
end
@@ -300,7 +290,7 @@ module Gem
# RubyGems now uses this new `Gem.activate_and_load_bin_path` helper in
# binstubs, which is of course not overridden in Bundler since it didn't
# exist at the time. So, include the override here to workaround that.
- load ENV["BUNDLE_BIN_PATH"] if ENV["BUNDLE_BIN_PATH"] && spec.version <= "2.5.22"
+ load ENV["BUNDLE_BIN_PATH"] if ENV["BUNDLE_BIN_PATH"] && spec.version <= Gem::Version.create("2.5.22")
# Make sure there's no version of Bundler in `$LOAD_PATH` that's different
# from the version we just activated. If that was the case (it happens
@@ -362,6 +352,8 @@ module Gem
def self.clear_paths
@paths = nil
@user_home = nil
+ @cache_home = nil
+ @data_home = nil
Gem::Specification.reset
Gem::Security.reset if defined?(Gem::Security)
end
@@ -649,6 +641,14 @@ An Array (#{env.inspect}) was passed in from #{caller[3]}
end
@yaml_loaded = false
+ @use_psych = nil
+
+ ##
+ # Returns true if the Psych YAML parser is enabled via configuration.
+
+ def self.use_psych?
+ @use_psych || false
+ end
##
# Loads YAML, preferring Psych
@@ -656,9 +656,15 @@ An Array (#{env.inspect}) was passed in from #{caller[3]}
def self.load_yaml
return if @yaml_loaded
- require "psych"
- require_relative "rubygems/psych_tree"
+ @use_psych = ENV["RUBYGEMS_USE_PSYCH"] == "true" ||
+ (defined?(@configuration) && @configuration && !@configuration[:use_psych].nil?)
+ if @use_psych
+ require "psych"
+ require_relative "rubygems/psych_tree"
+ end
+
+ require_relative "rubygems/yaml_serializer"
require_relative "rubygems/safe_yaml"
@yaml_loaded = true
@@ -679,7 +685,7 @@ An Array (#{env.inspect}) was passed in from #{caller[3]}
# warnings in platform constants
def self.load_bundler_extensions(version)
- return unless version <= "2.6.9"
+ return unless version <= Gem::Version.create("2.6.9")
previous_platforms = {}
@@ -846,14 +852,12 @@ An Array (#{env.inspect}) was passed in from #{caller[3]}
end
##
- # Safely write a file in binary mode on all platforms.
+ # Atomically write a file in binary mode on all platforms.
def self.write_binary(path, data)
- File.binwrite(path, data)
- 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)
- raise
+ Gem::AtomicFileWriter.open(path) do |file|
+ file.write(data)
+ end
end
##
@@ -1092,18 +1096,6 @@ An Array (#{env.inspect}) was passed in from #{caller[3]}
end
##
- # Is this a windows platform?
-
- def self.win_platform?
- if @@win_platform.nil?
- ruby_platform = RbConfig::CONFIG["host_os"]
- @@win_platform = !WIN_PATTERNS.find {|r| ruby_platform =~ r }.nil?
- end
-
- @@win_platform
- end
-
- ##
# Is this a java platform?
def self.java_platform?
@@ -1308,10 +1300,17 @@ An Array (#{env.inspect}) was passed in from #{caller[3]}
prefix_pattern = /^(#{prefix_group})/
end
+ native_extension_suffixes = Gem.dynamic_library_suffixes.reject(&:empty?)
+
spec.files.each do |file|
if new_format
file = file.sub(prefix_pattern, "")
- next unless $~
+ unless $~
+ # Also register native extension files (e.g. date_core.bundle)
+ # that are listed without require path prefix in the gemspec
+ next if file.include?("/")
+ next unless file.end_with?(*native_extension_suffixes)
+ end
end
spec.activate if already_loaded?(file)
@@ -1435,9 +1434,7 @@ require_relative "rubygems/specification"
# REFACTOR: This should be pulled out into some kind of hacks file.
begin
- ##
# Defaults the operating system (or packager) wants to provide for RubyGems.
-
require "rubygems/defaults/operating_system"
rescue LoadError
# Ignored
@@ -1452,9 +1449,7 @@ rescue StandardError => e
end
begin
- ##
# Defaults the Ruby implementation wants to provide for RubyGems
-
require "rubygems/defaults/#{RUBY_ENGINE}"
rescue LoadError
end
diff --git a/lib/rubygems/basic_specification.rb b/lib/rubygems/basic_specification.rb
index 591b555725..0ed7fc60bb 100644
--- a/lib/rubygems/basic_specification.rb
+++ b/lib/rubygems/basic_specification.rb
@@ -34,15 +34,6 @@ class Gem::BasicSpecification
internal_init
end
- def self.default_specifications_dir
- Gem.default_specifications_dir
- end
-
- class << self
- extend Gem::Deprecate
- rubygems_deprecate :default_specifications_dir, "Gem.default_specifications_dir"
- end
-
##
# The path to the gem.build_complete file within the extension install
# directory.
diff --git a/lib/rubygems/bundler_version_finder.rb b/lib/rubygems/bundler_version_finder.rb
index 4ebbad1c0c..bbe7bf0ab5 100644
--- a/lib/rubygems/bundler_version_finder.rb
+++ b/lib/rubygems/bundler_version_finder.rb
@@ -2,11 +2,17 @@
module Gem::BundlerVersionFinder
def self.bundler_version
+ bcv = bundle_config_version
+ return if bcv == "system"
+
v = ENV["BUNDLER_VERSION"]
+ v = nil if v&.empty?
v ||= bundle_update_bundler_version
return if v == true
+ v ||= bcv unless bcv == "lockfile"
+
v ||= lockfile_version
return unless v
@@ -46,6 +52,67 @@ module Gem::BundlerVersionFinder
private_class_method :lockfile_version
def self.lockfile_contents
+ gemfile = gemfile_path
+
+ return unless gemfile
+
+ lockfile = ENV["BUNDLE_LOCKFILE"]
+ lockfile = nil if lockfile&.empty?
+
+ lockfile ||= case gemfile
+ when "gems.rb" then "gems.locked"
+ else "#{gemfile}.lock"
+ end
+
+ return unless File.file?(lockfile)
+
+ File.read(lockfile)
+ end
+ private_class_method :lockfile_contents
+
+ def self.bundle_config_version
+ env_version = ENV["BUNDLE_VERSION"]
+ return env_version if env_version && !env_version.empty?
+
+ version = nil
+
+ [bundler_local_config_file, bundler_global_config_file].each do |config_file|
+ next unless config_file && File.file?(config_file)
+
+ contents = File.read(config_file)
+ contents =~ /^BUNDLE_VERSION:\s*["']?([^"'\s]+)["']?\s*$/
+
+ version = $1
+ break if version
+ end
+
+ version
+ end
+ private_class_method :bundle_config_version
+
+ def self.bundler_global_config_file
+ # see Bundler::Settings#global_config_file
+ if ENV["BUNDLE_CONFIG"] && !ENV["BUNDLE_CONFIG"].empty?
+ ENV["BUNDLE_CONFIG"]
+ elsif ENV["BUNDLE_USER_CONFIG"] && !ENV["BUNDLE_USER_CONFIG"].empty?
+ ENV["BUNDLE_USER_CONFIG"]
+ elsif ENV["BUNDLE_USER_HOME"] && !ENV["BUNDLE_USER_HOME"].empty?
+ ENV["BUNDLE_USER_HOME"] + "config"
+ elsif Gem.user_home && !Gem.user_home.empty?
+ Gem.user_home + ".bundle/config"
+ end
+ end
+ private_class_method :bundler_global_config_file
+
+ def self.bundler_local_config_file
+ gemfile = gemfile_path
+ return unless gemfile
+
+ File.join(File.dirname(gemfile), ".bundle", "config")
+ end
+ private_class_method :bundler_local_config_file
+
+ def self.gemfile_path
gemfile = ENV["BUNDLE_GEMFILE"]
gemfile = nil if gemfile&.empty?
@@ -62,16 +129,7 @@ module Gem::BundlerVersionFinder
end
end
- return unless gemfile
-
- lockfile = case gemfile
- when "gems.rb" then "gems.locked"
- else "#{gemfile}.lock"
- end
-
- return unless File.file?(lockfile)
-
- File.read(lockfile)
+ gemfile
end
- private_class_method :lockfile_contents
+ private_class_method :gemfile_path
end
diff --git a/lib/rubygems/command_manager.rb b/lib/rubygems/command_manager.rb
index 8521517a24..76b2fba835 100644
--- a/lib/rubygems/command_manager.rb
+++ b/lib/rubygems/command_manager.rb
@@ -58,7 +58,6 @@ class Gem::CommandManager
:owner,
:pristine,
:push,
- :query,
:rdoc,
:rebuild,
:search,
diff --git a/lib/rubygems/commands/build_command.rb b/lib/rubygems/commands/build_command.rb
index 2ec8324141..cfe1f8ec3c 100644
--- a/lib/rubygems/commands/build_command.rb
+++ b/lib/rubygems/commands/build_command.rb
@@ -25,13 +25,6 @@ class Gem::Commands::BuildCommand < Gem::Command
add_option "-o", "--output FILE", "output gem with the given filename" do |value, options|
options[:output] = 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
- deprecate_option "-C",
- version: "4.0",
- extra_msg: "-C is a global flag now. Use `gem -C PATH build GEMSPEC_FILE [options]` instead"
end
def arguments # :nodoc:
diff --git a/lib/rubygems/commands/cert_command.rb b/lib/rubygems/commands/cert_command.rb
index 72dcf1dd17..fe03841ddb 100644
--- a/lib/rubygems/commands/cert_command.rb
+++ b/lib/rubygems/commands/cert_command.rb
@@ -158,7 +158,7 @@ class Gem::Commands::CertCommand < Gem::Command
cert = Gem::Security.create_cert_email(
email,
key,
- (Gem::Security::ONE_DAY * expiration_length_days)
+ Gem::Security::ONE_DAY * expiration_length_days
)
Gem::Security.write cert, "gem-public_cert.pem"
diff --git a/lib/rubygems/commands/environment_command.rb b/lib/rubygems/commands/environment_command.rb
index aea8c0d7de..a5eb521a53 100644
--- a/lib/rubygems/commands/environment_command.rb
+++ b/lib/rubygems/commands/environment_command.rb
@@ -38,6 +38,7 @@ keys:
:verbose: Verbosity of the gem command. false, true, and :really are the
levels
:update_sources: Enable/disable automatic updating of repository metadata
+ :concurrent_downloads: The number of gem downloads to perform concurrently
:backtrace: Print backtrace when RubyGems encounters an error
:gempath: The paths in which to look for gems
:disable_default_gem_server: Force specification of gem server host on push
diff --git a/lib/rubygems/commands/exec_command.rb b/lib/rubygems/commands/exec_command.rb
index c24ebbf711..1feafbdd35 100644
--- a/lib/rubygems/commands/exec_command.rb
+++ b/lib/rubygems/commands/exec_command.rb
@@ -173,6 +173,9 @@ to the same gem path as user-installed gems.
rescue Gem::InstallError => e
alert_error "Error installing #{gem_name}:\n\t#{e.message}"
terminate_interaction 1
+ rescue Gem::DependencyResolutionError => e
+ alert_error "Error installing #{gem_name}:\n\t#{e.message}"
+ terminate_interaction 2
rescue Gem::GemNotFoundException => e
show_lookup_failure e.name, e.version, e.errors, false
diff --git a/lib/rubygems/commands/fetch_command.rb b/lib/rubygems/commands/fetch_command.rb
index c524cf7922..8e64a18cee 100644
--- a/lib/rubygems/commands/fetch_command.rb
+++ b/lib/rubygems/commands/fetch_command.rb
@@ -56,7 +56,7 @@ then repackaging it.
if options[:version] != Gem::Requirement.default &&
get_all_gem_names.size > 1
alert_error "Can't use --version with multiple gems. You can specify multiple gems with" \
- " version requirements using `gem fetch 'my_gem:1.0.0' 'my_other_gem:~>2.0.0'`"
+ " version requirements using `gem fetch 'my_gem:1.0.0' 'my_other_gem:>=2'`"
terminate_interaction 1
end
end
diff --git a/lib/rubygems/commands/help_command.rb b/lib/rubygems/commands/help_command.rb
index 1619b152e7..664f400561 100644
--- a/lib/rubygems/commands/help_command.rb
+++ b/lib/rubygems/commands/help_command.rb
@@ -90,7 +90,9 @@ Use #gem to declare which gems you directly depend upon:
To depend on a specific set of versions:
- gem 'rake', '~> 10.3', '>= 10.3.2'
+ gem 'rake', '>= 10.3.2'
+ # or for multiple version restrictions
+ gem 'rake', '>= 10.3.2', "< 13"
RubyGems will require the gem name when activating the gem using
the RUBYGEMS_GEMDEPS environment variable or Gem::use_gemdeps. Use the
diff --git a/lib/rubygems/commands/install_command.rb b/lib/rubygems/commands/install_command.rb
index 2888b6c55a..6d3beec0b4 100644
--- a/lib/rubygems/commands/install_command.rb
+++ b/lib/rubygems/commands/install_command.rb
@@ -140,7 +140,7 @@ You can use `i` command instead of `install`.
if options[:version] != Gem::Requirement.default &&
get_all_gem_names.size > 1
alert_error "Can't use --version with multiple gems. You can specify multiple gems with" \
- " version requirements using `gem install 'my_gem:1.0.0' 'my_other_gem:~>2.0.0'`"
+ " version requirements using `gem install 'my_gem:1.0.0' 'my_other_gem:>=2'`"
terminate_interaction 1
end
end
@@ -224,6 +224,9 @@ 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::DependencyResolutionError => e
+ alert_error "Error installing #{gem_name}:\n\t#{e.message}"
+ exit_code |= 2
rescue Gem::UnsatisfiableDependencyError => e
show_lookup_failure e.name, e.version, e.errors, suppress_suggestions,
"'#{gem_name}' (#{gem_version})"
@@ -239,11 +242,7 @@ You can use `i` command instead of `install`.
# Loads post-install hooks
def load_hooks # :nodoc:
- if options[:install_as_default]
- require_relative "../install_default_message"
- else
- require_relative "../install_message"
- end
+ require_relative "../install_message"
require_relative "../rdoc"
end
diff --git a/lib/rubygems/commands/owner_command.rb b/lib/rubygems/commands/owner_command.rb
index 12bfe3a834..675e866734 100644
--- a/lib/rubygems/commands/owner_command.rb
+++ b/lib/rubygems/commands/owner_command.rb
@@ -75,11 +75,12 @@ permission to.
end
with_response response do |resp|
- owners = Gem::SafeYAML.load clean_text(resp.body)
+ owners = Gem::SafeYAML.safe_load clean_text(resp.body)
say "Owners for gem: #{name}"
owners.each do |owner|
- say "- #{owner["email"] || owner["handle"] || owner["id"]}"
+ identifier = owner["email"] || owner["handle"] || owner["id"]
+ say "- #{identifier} (#{owner["role"]})"
end
end
end
diff --git a/lib/rubygems/commands/pristine_command.rb b/lib/rubygems/commands/pristine_command.rb
index 93503d2b69..10978c2af7 100644
--- a/lib/rubygems/commands/pristine_command.rb
+++ b/lib/rubygems/commands/pristine_command.rb
@@ -88,6 +88,10 @@ If you have made modifications to an installed gem, the pristine command
will revert them. All extensions are rebuilt and all bin stubs for the gem
are regenerated after checking for modifications.
+Rebuilding extensions also refreshes C-extension gems against updated system
+libraries (for example after OS or package upgrades) to avoid mismatches like
+outdated library version warnings.
+
If the cached gem cannot be found it will be downloaded.
If --no-extensions is provided pristine will not attempt to restore a gem
@@ -128,6 +132,11 @@ extensions will be restored.
specs = specs.select {|spec| spec.platform == RUBY_ENGINE || Gem::Platform.local === spec.platform || spec.platform == Gem::Platform::RUBY }
if specs.to_a.empty?
+ if options[:only_missing_extensions]
+ say "No gems with missing extensions to restore"
+ return
+ end
+
raise Gem::Exception,
"Failed to find gems #{options[:args]} #{options[:version]}"
end
diff --git a/lib/rubygems/commands/push_command.rb b/lib/rubygems/commands/push_command.rb
index d2ce86703b..02931b3025 100644
--- a/lib/rubygems/commands/push_command.rb
+++ b/lib/rubygems/commands/push_command.rb
@@ -92,21 +92,77 @@ The push command will use ~/.gem/credentials to authenticate to a server, but yo
private
def send_push_request(name, args)
+ # Always honor explicit --attestation option
+ # Auto-attestation is only supported on rubygems.org with GitHub Actions (not JRuby)
+ if options[:attestations].any? || (RUBY_ENGINE != "jruby" && attestation_supported_host? && ENV["GITHUB_ACTIONS"])
+ send_push_request_with_attestation(name, args)
+ else
+ send_push_request_without_attestation(name, args)
+ end
+ end
+
+ def send_push_request_without_attestation(name, args)
scope = get_push_scope
rubygems_api_request(*args, scope: scope) do |request|
body = Gem.read_binary name
- if options[:attestations].any?
- request.set_form([
- ["gem", body, { filename: name, content_type: "application/octet-stream" }],
- get_attestations_part,
- ], "multipart/form-data")
- else
- request.body = body
- request.add_field "Content-Type", "application/octet-stream"
- request.add_field "Content-Length", request.body.size
+ request.body = body
+ request.add_field "Content-Type", "application/octet-stream"
+ request.add_field "Content-Length", request.body.size
+ request.add_field "Authorization", api_key
+ end
+ end
+
+ def send_push_request_with_attestation(name, args)
+ attestations = if options[:attestations].any?
+ options[:attestations].map do |attestation|
+ Gem.read_binary(attestation)
end
+ else
+ bundle_path = attest!(name)
+ begin
+ [Gem.read_binary(bundle_path)]
+ ensure
+ File.unlink(bundle_path) if bundle_path && File.exist?(bundle_path)
+ end
+ end
+ bundles = "[" + attestations.join(",") + "]"
+
+ rubygems_api_request(*args, scope: get_push_scope) do |request|
+ request.set_form([
+ ["gem", Gem.read_binary(name), { filename: name, content_type: "application/octet-stream" }],
+ ["attestations", bundles, { content_type: "application/json" }],
+ ], "multipart/form-data")
request.add_field "Authorization", api_key
end
+ rescue StandardError => e
+ message = "Failed to push with attestation, retrying without attestation.\n"
+ message += if Gem.configuration.really_verbose
+ e.full_message
+ else
+ e.message
+ end
+ alert_warning message
+ send_push_request_without_attestation(name, args)
+ end
+
+ def attest!(name)
+ require "open3"
+ require "tempfile"
+
+ tempfile = Tempfile.new([File.basename(name, ".*"), ".sigstore.json"])
+ bundle = tempfile.path
+ tempfile.close(false)
+
+ env = defined?(Bundler.unbundled_env) ? Bundler.unbundled_env : ENV.to_h
+ out, st = Open3.capture2e(
+ env,
+ Gem.ruby, "-S", "gem", "exec", "--conservative",
+ "sigstore-cli", "sign", name, "--bundle", bundle,
+ unsetenv_others: true
+ )
+ raise Gem::Exception, "Failed to sign gem:\n\n#{out}" unless st.success?
+
+ bundle
end
def get_hosts_for(name)
@@ -122,14 +178,8 @@ The push command will use ~/.gem/credentials to authenticate to a server, but yo
:push_rubygem
end
- def get_attestations_part
- bundles = "[" + options[:attestations].map do |attestation|
- Gem.read_binary(attestation)
- end.join(",") + "]"
- [
- "attestations",
- bundles,
- { content_type: "application/json" },
- ]
+ def attestation_supported_host?
+ host = (@host || Gem.host).to_s.chomp("/")
+ host == Gem::DEFAULT_HOST
end
end
diff --git a/lib/rubygems/commands/query_command.rb b/lib/rubygems/commands/query_command.rb
deleted file mode 100644
index 3b527974a3..0000000000
--- a/lib/rubygems/commands/query_command.rb
+++ /dev/null
@@ -1,43 +0,0 @@
-# frozen_string_literal: true
-
-require_relative "../command"
-require_relative "../query_utils"
-require_relative "../deprecate"
-
-class Gem::Commands::QueryCommand < Gem::Command
- extend Gem::Deprecate
- rubygems_deprecate_command
-
- include Gem::QueryUtils
-
- alias_method :warning_without_suggested_alternatives, :deprecation_warning
- def deprecation_warning
- warning_without_suggested_alternatives
-
- message = "It is recommended that you use `gem search` or `gem list` instead.\n"
- alert_warning message unless Gem::Deprecate.skip
- end
-
- 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
-
- add_option("-n", "--name-matches REGEXP",
- "Name of gem(s) to query on matches the",
- "provided REGEXP") do |value, options|
- options[:name] = /#{value}/i
- end
-
- add_query_options
- end
-
- def description # :nodoc:
- <<-EOF
-The query command is the basis for the list and search commands.
-
-You should really use the list and search commands instead. This command
-is too hard to use.
- EOF
- end
-end
diff --git a/lib/rubygems/commands/rebuild_command.rb b/lib/rubygems/commands/rebuild_command.rb
index 77a474ef1d..23b9d7b3ba 100644
--- a/lib/rubygems/commands/rebuild_command.rb
+++ b/lib/rubygems/commands/rebuild_command.rb
@@ -1,6 +1,5 @@
# frozen_string_literal: true
-require "date"
require "digest"
require "fileutils"
require "tmpdir"
diff --git a/lib/rubygems/commands/setup_command.rb b/lib/rubygems/commands/setup_command.rb
index 85e28ccedd..175599967c 100644
--- a/lib/rubygems/commands/setup_command.rb
+++ b/lib/rubygems/commands/setup_command.rb
@@ -393,16 +393,20 @@ By default, this RubyGems will install gem as:
Dir.chdir("bundler") do
built_gem = Gem::Package.build(new_bundler_spec)
begin
- Gem::Installer.at(
+ installer = Gem::Installer.at(
built_gem,
env_shebang: options[:env_shebang],
format_executable: options[:format_executable],
force: options[:force],
- install_as_default: true,
bin_dir: bin_dir,
install_dir: default_dir,
wrappers: true
- ).install
+ )
+ # We need to install only executable and default spec files.
+ # lib/bundler.rb and lib/bundler/* are available under the site_ruby directory.
+ installer.extract_bin
+ installer.generate_bin
+ installer.write_default_spec
ensure
FileUtils.rm_f built_gem
end
diff --git a/lib/rubygems/commands/sources_command.rb b/lib/rubygems/commands/sources_command.rb
index 976f4a4ea2..b399af2bd3 100644
--- a/lib/rubygems/commands/sources_command.rb
+++ b/lib/rubygems/commands/sources_command.rb
@@ -18,6 +18,14 @@ class Gem::Commands::SourcesCommand < Gem::Command
options[:add] = value
end
+ add_option "--append SOURCE_URI", "Append source (can be used multiple times)" do |value, options|
+ options[:append] = value
+ end
+
+ add_option "-p", "--prepend SOURCE_URI", "Prepend source (can be used multiple times)" do |value, options|
+ options[:prepend] = value
+ end
+
add_option "-l", "--list", "List sources" do |value, options|
options[:list] = value
end
@@ -26,8 +34,7 @@ class Gem::Commands::SourcesCommand < Gem::Command
options[:remove] = value
end
- add_option "-c", "--clear-all",
- "Remove all sources (clear the cache)" do |value, options|
+ add_option "-c", "--clear-all", "Remove all sources (clear the cache)" do |value, options|
options[:clear_all] = value
end
@@ -43,11 +50,8 @@ class Gem::Commands::SourcesCommand < Gem::Command
end
def add_source(source_uri) # :nodoc:
- check_rubygems_https source_uri
-
- source = Gem::Source.new source_uri
-
- check_typo_squatting(source)
+ source = build_new_source(source_uri)
+ source_uri = source.uri.to_s
begin
if Gem.sources.include? source
@@ -68,6 +72,54 @@ class Gem::Commands::SourcesCommand < Gem::Command
end
end
+ def append_source(source_uri) # :nodoc:
+ source = build_new_source(source_uri)
+ source_uri = source.uri.to_s
+
+ begin
+ source.load_specs :released
+ was_present = Gem.sources.include?(source)
+ Gem.sources.append source
+ Gem.configuration.write
+
+ if was_present
+ say "#{source_uri} moved to end of sources"
+ else
+ say "#{source_uri} added to sources"
+ end
+ rescue Gem::URI::Error, ArgumentError
+ say "#{source_uri} is not a URI"
+ terminate_interaction 1
+ rescue Gem::RemoteFetcher::FetchError => e
+ say "Error fetching #{Gem::Uri.redact(source.uri)}:\n\t#{e.message}"
+ terminate_interaction 1
+ end
+ end
+
+ def prepend_source(source_uri) # :nodoc:
+ source = build_new_source(source_uri)
+ source_uri = source.uri.to_s
+
+ begin
+ source.load_specs :released
+ was_present = Gem.sources.include?(source)
+ Gem.sources.prepend source
+ Gem.configuration.write
+
+ if was_present
+ say "#{source_uri} moved to top of sources"
+ else
+ say "#{source_uri} added to sources"
+ end
+ rescue Gem::URI::Error, ArgumentError
+ say "#{source_uri} is not a URI"
+ terminate_interaction 1
+ rescue Gem::RemoteFetcher::FetchError => e
+ say "Error fetching #{Gem::Uri.redact(source.uri)}:\n\t#{e.message}"
+ terminate_interaction 1
+ end
+ end
+
def check_typo_squatting(source)
if source.typo_squatting?("rubygems.org")
question = <<-QUESTION.chomp
@@ -80,6 +132,19 @@ Do you want to add this source?
end
end
+ def normalize_source_uri(source_uri) # :nodoc:
+ # Ensure the source URI has a trailing slash for proper RFC 2396 path merging
+ # Without a trailing slash, the last path segment is treated as a file and removed
+ # during relative path resolution (e.g., "/blish" + "gems/foo.gem" = "/gems/foo.gem")
+ # With a trailing slash, it's treated as a directory (e.g., "/blish/" + "gems/foo.gem" = "/blish/gems/foo.gem")
+ uri = Gem::URI.parse(source_uri)
+ uri.path = uri.path.gsub(%r{/+\z}, "") + "/" if uri.path && !uri.path.empty?
+ uri.to_s
+ rescue Gem::URI::Error
+ # If parsing fails, return the original URI and let later validation handle it
+ source_uri
+ end
+
def check_rubygems_https(source_uri) # :nodoc:
uri = Gem::URI source_uri
@@ -128,7 +193,7 @@ yourself to use your own gem server.
Without any arguments the sources lists your currently configured sources:
$ gem sources
- *** CURRENT SOURCES ***
+ *** NO CONFIGURED SOURCES, DEFAULT SOURCES LISTED BELOW ***
https://rubygems.org
@@ -147,33 +212,49 @@ Since all of these sources point to the same set of gems you only need one
of them in your list. https://rubygems.org is recommended as it brings the
protections of an SSL connection to gem downloads.
-To add a source use the --add argument:
+To add a private gem source use the --prepend argument to insert it before
+the default source. This is usually the best place for private gem sources:
- $ gem sources --add https://rubygems.org
- https://rubygems.org added to sources
+ $ gem sources --prepend https://my.private.source
+ https://my.private.source added to sources
RubyGems will check to see if gems can be installed from the source given
before it is added.
+To add or move a source after all other sources, use --append:
+
+ $ gem sources --append https://rubygems.org
+ https://rubygems.org moved to end of sources
+
To remove a source use the --remove argument:
- $ gem sources --remove https://rubygems.org/
- https://rubygems.org/ removed from sources
+ $ gem sources --remove https://my.private.source/
+ https://my.private.source/ removed from sources
EOF
end
def list # :nodoc:
- say "*** CURRENT SOURCES ***"
+ if configured_sources
+ header = "*** CURRENT SOURCES ***"
+ list = configured_sources
+ else
+ header = "*** NO CONFIGURED SOURCES, DEFAULT SOURCES LISTED BELOW ***"
+ list = Gem.sources
+ end
+
+ say header
say
- Gem.sources.each do |src|
+ list.each do |src|
say src
end
end
def list? # :nodoc:
!(options[:add] ||
+ options[:prepend] ||
+ options[:append] ||
options[:clear_all] ||
options[:remove] ||
options[:update])
@@ -182,11 +263,13 @@ To remove a source use the --remove argument:
def execute
clear_all if options[:clear_all]
- source_uri = options[:add]
- add_source source_uri if source_uri
+ add_source options[:add] if options[:add]
+
+ prepend_source options[:prepend] if options[:prepend]
+
+ append_source options[:append] if options[:append]
- source_uri = options[:remove]
- remove_source source_uri if source_uri
+ remove_source options[:remove] if options[:remove]
update if options[:update]
@@ -194,13 +277,22 @@ To remove a source use the --remove argument:
end
def remove_source(source_uri) # :nodoc:
- if Gem.sources.include? source_uri
- Gem.sources.delete source_uri
+ source = build_source(source_uri)
+ source_uri = source.uri.to_s
+
+ if configured_sources&.include? source
+ Gem.sources.delete source
Gem.configuration.write
- say "#{source_uri} removed from sources"
+ if default_sources.include?(source) && configured_sources.one?
+ alert_warning "Removing a default source when it is the only source has no effect. Add a different source to #{config_file_name} if you want to stop using it as a source."
+ else
+ say "#{source_uri} removed from sources"
+ end
+ elsif configured_sources
+ say "source #{source_uri} cannot be removed because it's not present in #{config_file_name}"
else
- say "source #{source_uri} not present in cache"
+ say "source #{source_uri} cannot be removed because there are no configured sources in #{config_file_name}"
end
end
@@ -224,4 +316,33 @@ To remove a source use the --remove argument:
say "*** Unable to remove #{desc} source cache ***"
end
end
+
+ private
+
+ def default_sources
+ Gem::SourceList.from(Gem.default_sources)
+ end
+
+ def configured_sources
+ return @configured_sources if defined?(@configured_sources)
+
+ configuration_sources = Gem.configuration.sources
+ @configured_sources = Gem::SourceList.from(configuration_sources) if configuration_sources
+ end
+
+ def config_file_name
+ Gem.configuration.config_file_name
+ end
+
+ def build_source(source_uri)
+ source_uri = normalize_source_uri(source_uri)
+ Gem::Source.new(source_uri)
+ end
+
+ def build_new_source(source_uri)
+ source = build_source(source_uri)
+ check_rubygems_https(source.uri.to_s)
+ check_typo_squatting(source)
+ source
+ end
end
diff --git a/lib/rubygems/commands/specification_command.rb b/lib/rubygems/commands/specification_command.rb
index a21ed35be3..15e543f1a6 100644
--- a/lib/rubygems/commands/specification_command.rb
+++ b/lib/rubygems/commands/specification_command.rb
@@ -42,7 +42,7 @@ class Gem::Commands::SpecificationCommand < Gem::Command
def arguments # :nodoc:
<<-ARGS
-GEMFILE name of gem to show the gemspec for
+GEM_OR_FILE gem name or a .gem file to show the gemspec for
FIELD name of gemspec field to show
ARGS
end
@@ -68,7 +68,7 @@ Specific fields in the specification can be extracted in YAML format:
end
def usage # :nodoc:
- "#{program_name} [GEMFILE] [FIELD]"
+ "#{program_name} [GEM_OR_FILE] [FIELD]"
end
def execute
@@ -77,7 +77,7 @@ Specific fields in the specification can be extracted in YAML format:
unless gem
raise Gem::CommandLineError,
- "Please specify a gem name or file on the command line"
+ "Please specify a gem name or a .gem file on the command line"
end
case v = options[:version]
@@ -147,7 +147,7 @@ Specific fields in the specification can be extracted in YAML format:
say case options[:format]
when :ruby then s.to_ruby
when :marshal then Marshal.dump s
- else s.to_yaml
+ else Gem.use_psych? ? s.to_yaml : Gem::YAMLSerializer.dump(s)
end
say "\n"
diff --git a/lib/rubygems/commands/uninstall_command.rb b/lib/rubygems/commands/uninstall_command.rb
index 3d6e41e49e..3c26074f93 100644
--- a/lib/rubygems/commands/uninstall_command.rb
+++ b/lib/rubygems/commands/uninstall_command.rb
@@ -117,7 +117,7 @@ that is a dependency of an existing gem. You can use the
if options[:version] != Gem::Requirement.default &&
get_all_gem_names.size > 1
alert_error "Can't use --version with multiple gems. You can specify multiple gems with" \
- " version requirements using `gem uninstall 'my_gem:1.0.0' 'my_other_gem:~>2.0.0'`"
+ " version requirements using `gem uninstall 'my_gem:1.0.0' 'my_other_gem:>=2'`"
terminate_interaction 1
end
end
diff --git a/lib/rubygems/config_file.rb b/lib/rubygems/config_file.rb
index a2bcb6dfbc..d5e9eb4e33 100644
--- a/lib/rubygems/config_file.rb
+++ b/lib/rubygems/config_file.rb
@@ -26,9 +26,22 @@ require "rbconfig"
# RubyGems options use symbol keys. Valid options are:
#
# +:backtrace+:: See #backtrace
-# +:sources+:: Sets Gem::sources
+# +:bulk_threshold+:: See #bulk_threshold
# +:verbose+:: See #verbose
+# +:update_sources+:: See #update_sources
# +:concurrent_downloads+:: See #concurrent_downloads
+# +:cert_expiration_length_days+:: See #cert_expiration_length_days
+# +:install_extension_in_lib+:: See #install_extension_in_lib
+# +:ipv4_fallback_enabled+:: See #ipv4_fallback_enabled
+# +:global_gem_cache+:: See #global_gem_cache
+# +:use_psych+:: See #use_psych
+# +:gemhome+:: See #home
+# +:gempath+:: See #path
+# +:sources+:: Sets Gem::sources
+# +:disable_default_gem_server+:: See #disable_default_gem_server
+# +:ssl_verify_mode+:: See #ssl_verify_mode
+# +:ssl_ca_cert+:: See #ssl_ca_cert
+# +:ssl_client_cert+:: See #ssl_client_cert
#
# gemrc files may exist in various locations and are read and merged in
# the following order:
@@ -47,8 +60,9 @@ 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
+ DEFAULT_GLOBAL_GEM_CACHE = false
+ DEFAULT_USE_PSYCH = false
##
# For Ruby packagers to set configuration defaults. Set in
@@ -156,6 +170,17 @@ class Gem::ConfigFile
attr_accessor :ipv4_fallback_enabled
##
+ # Use a global cache for .gem files shared across all Ruby installations.
+ # When enabled, gems are cached to ~/.cache/gem/gems (or XDG_CACHE_HOME/gem/gems).
+
+ attr_accessor :global_gem_cache
+
+ ##
+ # Use Psych (C extension YAML parser) instead of the pure Ruby YAMLSerializer.
+
+ attr_accessor :use_psych
+
+ ##
# Path name of directory or file of openssl client certificate, used for remote https connection with client authentication
attr_reader :ssl_client_cert
@@ -192,6 +217,8 @@ class Gem::ConfigFile
@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
+ @global_gem_cache = ENV["RUBYGEMS_GLOBAL_GEM_CACHE"] == "true" || DEFAULT_GLOBAL_GEM_CACHE
+ @use_psych = ENV["RUBYGEMS_USE_PSYCH"] == "true" || DEFAULT_USE_PSYCH
operating_system_config = Marshal.load Marshal.dump(OPERATING_SYSTEM_DEFAULTS)
platform_config = Marshal.load Marshal.dump(PLATFORM_DEFAULTS)
@@ -213,8 +240,9 @@ class Gem::ConfigFile
@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)
+ concurrent_downloads install_extension_in_lib ipv4_fallback_enabled
+ global_gem_cache use_psych sources
+ disable_default_gem_server ssl_verify_mode ssl_ca_cert ssl_client_cert].include?(k)
k.to_sym
else
k
@@ -226,10 +254,12 @@ class Gem::ConfigFile
@bulk_threshold = @hash[:bulk_threshold] if @hash.key? :bulk_threshold
@verbose = @hash[:verbose] if @hash.key? :verbose
@update_sources = @hash[:update_sources] if @hash.key? :update_sources
- # TODO: We should handle concurrent_downloads same as other options
+ @concurrent_downloads = @hash[:concurrent_downloads] if @hash.key? :concurrent_downloads
@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
+ @global_gem_cache = @hash[:global_gem_cache] if @hash.key? :global_gem_cache
+ @use_psych = @hash[:use_psych] if @hash.key? :use_psych
@home = @hash[:gemhome] if @hash.key? :gemhome
@path = @hash[:gempath] if @hash.key? :gempath
@@ -345,7 +375,7 @@ if you believe they were disclosed to a third party.
require "fileutils"
FileUtils.mkdir_p(dirname)
- permissions = 0o600 & (~File.umask)
+ permissions = 0o600 & ~File.umask
File.open(credentials_path, "w", permissions) do |f|
f.write self.class.dump_with_rubygems_yaml(config)
end
@@ -369,7 +399,9 @@ if you believe they were disclosed to a third party.
begin
config = self.class.load_with_rubygems_config_hash(File.read(filename))
- if config.keys.any? {|k| k.to_s.gsub(%r{https?:\/\/}, "").include?(": ") }
+ has_invalid_keys = config.keys.any? {|k| k.to_s.gsub(%r{https?:\/\/}, "").include?(": ") }
+ has_invalid_values = config.values.any? {|v| v.is_a?(String) && v.gsub(%r{https?:\/\/}, "").match?(/\A\S+: /) }
+ if has_invalid_keys || has_invalid_values
warn "Failed to load #{filename} because it doesn't contain valid YAML hash"
return {}
else
@@ -554,7 +586,9 @@ if you believe they were disclosed to a third party.
def self.load_with_rubygems_config_hash(yaml)
require_relative "yaml_serializer"
- content = Gem::YAMLSerializer.load(yaml)
+ content = Gem::YAMLSerializer.load(yaml, permitted_classes: [])
+ return {} unless content.is_a?(Hash)
+
deep_transform_config_keys!(content)
end
@@ -588,7 +622,7 @@ if you believe they were disclosed to a third party.
else
v
end
- elsif v.empty?
+ elsif v.respond_to?(:empty?) && v.empty?
nil
elsif v.is_a?(Hash)
deep_transform_config_keys!(v)
diff --git a/lib/rubygems/defaults.rb b/lib/rubygems/defaults.rb
index db07681a17..2247c49c81 100644
--- a/lib/rubygems/defaults.rb
+++ b/lib/rubygems/defaults.rb
@@ -13,7 +13,7 @@ module Gem
# An Array of the default sources that come with RubyGems
def self.default_sources
- %w[https://rubygems.org/]
+ @default_sources ||= %w[https://rubygems.org/]
end
##
@@ -149,6 +149,15 @@ module Gem
end
##
+ # The path to the global gem cache directory.
+ # This is used when global_gem_cache is enabled to share .gem files
+ # across all Ruby installations.
+
+ def self.global_gem_cache_path
+ File.join(cache_home, "gem", "gems")
+ end
+
+ ##
# The path to standard location of the user's data directory.
def self.data_home
diff --git a/lib/rubygems/dependency_installer.rb b/lib/rubygems/dependency_installer.rb
index b4152e83e9..c842714d95 100644
--- a/lib/rubygems/dependency_installer.rb
+++ b/lib/rubygems/dependency_installer.rb
@@ -7,14 +7,12 @@ require_relative "installer"
require_relative "spec_fetcher"
require_relative "user_interaction"
require_relative "available_set"
-require_relative "deprecate"
##
# Installs a gem along with all its dependencies from local and remote gems.
class Gem::DependencyInstaller
include Gem::UserInteraction
- extend Gem::Deprecate
DEFAULT_OPTIONS = { # :nodoc:
env_shebang: false,
@@ -28,7 +26,6 @@ class Gem::DependencyInstaller
wrappers: true,
build_args: nil,
build_docs_in_background: false,
- install_as_default: false,
}.freeze
##
@@ -86,11 +83,13 @@ class Gem::DependencyInstaller
@user_install = options[:user_install]
@wrappers = options[:wrappers]
@build_args = options[:build_args]
+ @build_jobs = options[:build_jobs]
@build_docs_in_background = options[:build_docs_in_background]
- @install_as_default = options[:install_as_default]
@dir_mode = options[:dir_mode]
@data_mode = options[:data_mode]
@prog_mode = options[:prog_mode]
+ @build_extension = options[:build_extension]
+ @install_plugin = options[:install_plugin]
# Indicates that we should not try to update any deps unless
# we absolutely must.
@@ -121,78 +120,6 @@ class Gem::DependencyInstaller
@domain == :both || @domain == :remote
end
- ##
- # Returns a list of pairs of gemspecs and source_uris that match
- # Gem::Dependency +dep+ from both local (Dir.pwd) and remote (Gem.sources)
- # sources. Gems are sorted with newer gems preferred over older gems, and
- # local gems preferred over remote gems.
-
- def find_gems_with_sources(dep, best_only = false) # :nodoc:
- set = Gem::AvailableSet.new
-
- if consider_local?
- sl = Gem::Source::Local.new
-
- if spec = sl.find_gem(dep.name)
- if dep.matches_spec? spec
- set.add spec, sl
- end
- end
- end
-
- if consider_remote?
- begin
- # This is pulled from #spec_for_dependency to allow
- # us to filter tuples before fetching specs.
- tuples, errors = Gem::SpecFetcher.fetcher.search_for_dependency dep
-
- if best_only && !tuples.empty?
- tuples.sort! do |a,b|
- if b[0].version == a[0].version
- if b[0].platform != Gem::Platform::RUBY
- 1
- else
- -1
- end
- else
- b[0].version <=> a[0].version
- end
- end
- tuples = [tuples.first]
- end
-
- 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]
- end
-
- if @errors
- @errors += errors
- else
- @errors = errors
- 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
- # couldn't find their requested gem.
- verbose do
- "Error fetching remote data:\t\t#{e.message}\n" \
- "Falling back to local-only install"
- end
- @domain = :local
- end
- end
-
- set
- end
- rubygems_deprecate :find_gems_with_sources
-
def in_background(what) # :nodoc:
fork_happened = false
if @build_docs_in_background && Process.respond_to?(:fork)
@@ -230,6 +157,7 @@ class Gem::DependencyInstaller
options = {
bin_dir: @bin_dir,
build_args: @build_args,
+ build_jobs: @build_jobs,
document: @document,
env_shebang: @env_shebang,
force: @force,
@@ -240,10 +168,11 @@ class Gem::DependencyInstaller
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,
+ build_extension: @build_extension,
+ install_plugin: @install_plugin,
}
options[:install_dir] = @install_dir if @only_install_dir
diff --git a/lib/rubygems/dependency_list.rb b/lib/rubygems/dependency_list.rb
index 99643a426d..d50cfe2d54 100644
--- a/lib/rubygems/dependency_list.rb
+++ b/lib/rubygems/dependency_list.rb
@@ -7,7 +7,6 @@
#++
require_relative "vendored_tsort"
-require_relative "deprecate"
##
# Gem::DependencyList is used for installing and uninstalling gems in the
diff --git a/lib/rubygems/deprecate.rb b/lib/rubygems/deprecate.rb
index 303b344d42..eb503bb269 100644
--- a/lib/rubygems/deprecate.rb
+++ b/lib/rubygems/deprecate.rb
@@ -1,75 +1,75 @@
# frozen_string_literal: true
-##
-# Provides 3 methods for declaring when something is going away.
-#
-# +deprecate(name, repl, year, month)+:
-# Indicate something may be removed on/after a certain date.
-#
-# +rubygems_deprecate(name, replacement=:none)+:
-# Indicate something will be removed in the next major RubyGems version,
-# and (optionally) a replacement for it.
-#
-# +rubygems_deprecate_command+:
-# Indicate a RubyGems command (in +lib/rubygems/commands/*.rb+) will be
-# removed in the next RubyGems version.
-#
-# Also provides +skip_during+ for temporarily turning off deprecation warnings.
-# This is intended to be used in the test suite, so deprecation warnings
-# don't cause test failures if you need to make sure stderr is otherwise empty.
-#
-#
-# Example usage of +deprecate+ and +rubygems_deprecate+:
-#
-# class Legacy
-# def self.some_class_method
-# # ...
-# end
-#
-# def some_instance_method
-# # ...
-# end
-#
-# def some_old_method
-# # ...
-# end
-#
-# extend Gem::Deprecate
-# deprecate :some_instance_method, "X.z", 2011, 4
-# rubygems_deprecate :some_old_method, "Modern#some_new_method"
-#
-# class << self
-# extend Gem::Deprecate
-# deprecate :some_class_method, :none, 2011, 4
-# end
-# end
-#
-#
-# Example usage of +rubygems_deprecate_command+:
-#
-# class Gem::Commands::QueryCommand < Gem::Command
-# extend Gem::Deprecate
-# rubygems_deprecate_command
-#
-# # ...
-# end
-#
-#
-# Example usage of +skip_during+:
-#
-# class TestSomething < Gem::Testcase
-# def test_some_thing_with_deprecations
-# Gem::Deprecate.skip_during do
-# actual_stdout, actual_stderr = capture_output do
-# Gem.something_deprecated
-# end
-# assert_empty actual_stdout
-# assert_equal(expected, actual_stderr)
-# end
-# end
-# end
-
module Gem
+ ##
+ # Provides 3 methods for declaring when something is going away.
+ #
+ # <tt>deprecate(name, repl, year, month)</tt>:
+ # Indicate something may be removed on/after a certain date.
+ #
+ # <tt>rubygems_deprecate(name, replacement=:none)</tt>:
+ # Indicate something will be removed in the next major RubyGems version,
+ # and (optionally) a replacement for it.
+ #
+ # +rubygems_deprecate_command+:
+ # Indicate a RubyGems command (in +lib/rubygems/commands/*.rb+) will be
+ # removed in the next RubyGems version.
+ #
+ # Also provides +skip_during+ for temporarily turning off deprecation warnings.
+ # This is intended to be used in the test suite, so deprecation warnings
+ # don't cause test failures if you need to make sure stderr is otherwise empty.
+ #
+ #
+ # Example usage of +deprecate+ and +rubygems_deprecate+:
+ #
+ # class Legacy
+ # def self.some_class_method
+ # # ...
+ # end
+ #
+ # def some_instance_method
+ # # ...
+ # end
+ #
+ # def some_old_method
+ # # ...
+ # end
+ #
+ # extend Gem::Deprecate
+ # deprecate :some_instance_method, "X.z", 2011, 4
+ # rubygems_deprecate :some_old_method, "Modern#some_new_method"
+ #
+ # class << self
+ # extend Gem::Deprecate
+ # deprecate :some_class_method, :none, 2011, 4
+ # end
+ # end
+ #
+ #
+ # Example usage of +rubygems_deprecate_command+:
+ #
+ # class Gem::Commands::QueryCommand < Gem::Command
+ # extend Gem::Deprecate
+ # rubygems_deprecate_command
+ #
+ # # ...
+ # end
+ #
+ #
+ # Example usage of +skip_during+:
+ #
+ # class TestSomething < Gem::Testcase
+ # def test_some_thing_with_deprecations
+ # Gem::Deprecate.skip_during do
+ # actual_stdout, actual_stderr = capture_output do
+ # Gem.something_deprecated
+ # end
+ # assert_empty actual_stdout
+ # assert_equal(expected, actual_stderr)
+ # end
+ # end
+ # end
+
module Deprecate
def self.skip # :nodoc:
@skip ||= false
diff --git a/lib/rubygems/doctor.rb b/lib/rubygems/doctor.rb
index 56b7c081eb..4f26260d83 100644
--- a/lib/rubygems/doctor.rb
+++ b/lib/rubygems/doctor.rb
@@ -113,7 +113,7 @@ class Gem::Doctor
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 sub_directory == "plugins" && Gem.plugin_suffix_regexp =~ basename
type = File.directory?(child) ? "directory" : "file"
diff --git a/lib/rubygems/exceptions.rb b/lib/rubygems/exceptions.rb
index adf7ad6d7d..e00a70c662 100644
--- a/lib/rubygems/exceptions.rb
+++ b/lib/rubygems/exceptions.rb
@@ -1,6 +1,5 @@
# frozen_string_literal: true
-require_relative "deprecate"
require_relative "unknown_command_spell_checker"
##
@@ -21,20 +20,11 @@ class Gem::UnknownCommandError < Gem::Exception
end
def self.attach_correctable
- return if defined?(@attached)
+ return if method_defined?(:corrections)
- if defined?(DidYouMean::SPELL_CHECKERS) && defined?(DidYouMean::Correctable)
- if DidYouMean.respond_to?(:correct_error)
- DidYouMean.correct_error(Gem::UnknownCommandError, Gem::UnknownCommandSpellChecker)
- else
- DidYouMean::SPELL_CHECKERS["Gem::UnknownCommandError"] =
- Gem::UnknownCommandSpellChecker
-
- prepend DidYouMean::Correctable
- end
+ if defined?(DidYouMean) && DidYouMean.respond_to?(:correct_error)
+ DidYouMean.correct_error(Gem::UnknownCommandError, Gem::UnknownCommandSpellChecker)
end
-
- @attached = true
end
end
@@ -43,22 +33,24 @@ class Gem::DependencyError < Gem::Exception; end
class Gem::DependencyRemovalException < Gem::Exception; end
##
-# Raised by Gem::Resolver when a Gem::Dependency::Conflict reaches the
-# toplevel. Indicates which dependencies were incompatible through #conflict
-# and #conflicting_dependencies
+# Raised by Gem::Resolver when dependency resolution fails.
class Gem::DependencyResolutionError < Gem::DependencyError
- attr_reader :conflict
-
def initialize(conflict)
- @conflict = conflict
- a, b = conflicting_dependencies
+ @explanation = conflict.explanation
+ super @explanation
+ end
- super "conflicting dependencies #{a} and #{b}\n#{@conflict.explanation}"
+ def explanation
+ @explanation
+ end
+
+ def conflict
+ nil
end
def conflicting_dependencies
- @conflict.conflicting_dependencies
+ []
end
end
@@ -136,40 +128,6 @@ 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.
-
-class Gem::ImpossibleDependenciesError < Gem::Exception
- attr_reader :conflicts
- attr_reader :request
-
- def initialize(request, conflicts)
- @request = request
- @conflicts = conflicts
-
- super build_message
- end
-
- def build_message # :nodoc:
- requester = @request.requester
- requester = requester ? requester.spec.full_name : "The user"
- dependency = @request.dependency
-
- message = "#{requester} requires #{dependency} but it conflicted:\n".dup
-
- @conflicts.each do |_, conflict|
- message << conflict.explanation
- end
-
- message
- end
-
- def dependency
- @request.dependency
- end
-end
-
class Gem::InstallError < Gem::Exception; end
class Gem::RuntimeRequirementNotMetError < Gem::InstallError
diff --git a/lib/rubygems/ext/builder.rb b/lib/rubygems/ext/builder.rb
index b47996d092..e00cf159da 100644
--- a/lib/rubygems/ext/builder.rb
+++ b/lib/rubygems/ext/builder.rb
@@ -22,7 +22,7 @@ class Gem::Ext::Builder
end
def self.make(dest_path, results, make_dir = Dir.pwd, sitedir = nil, targets = ["clean", "", "install"],
- target_rbconfig: Gem.target_rbconfig)
+ target_rbconfig: Gem.target_rbconfig, n_jobs: nil)
unless File.exist? File.join(make_dir, "Makefile")
# No makefile exists, nothing to do.
raise NoMakefileError, "No Makefile found in #{make_dir}"
@@ -34,8 +34,18 @@ class Gem::Ext::Builder
make_program_name ||= RUBY_PLATFORM.include?("mswin") ? "nmake" : "make"
make_program = shellsplit(make_program_name)
+ is_nmake = /\bnmake/i.match?(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 = !is_nmake || ENV["DESTDIR"] && ENV["DESTDIR"] != "" ? format("DESTDIR=%s", ENV["DESTDIR"]) : ""
+
+ # nmake doesn't support parallel build
+ unless is_nmake
+ have_make_arguments = make_program.size > 1
+
+ if !have_make_arguments && !ENV["MAKEFLAGS"] && n_jobs
+ make_program << "-j#{n_jobs}"
+ end
+ end
env = [destdir]
@@ -92,7 +102,8 @@ 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|
+ Open3.popen2e(build_env, *command, chdir: dir) do |stdin, stdouterr, wait_thread|
+ stdin.close
output = String.new
while line = stdouterr.gets
output << line
@@ -147,13 +158,12 @@ 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, target_rbconfig = Gem.target_rbconfig, build_jobs = nil)
@spec = spec
@build_args = build_args
@gem_dir = spec.full_gem_path
@target_rbconfig = target_rbconfig
-
- @ran_rake = false
+ @build_jobs = build_jobs
end
##
@@ -166,10 +176,9 @@ class Gem::Ext::Builder
when /configure/ then
Gem::Ext::ConfigureBuilder
when /rakefile/i, /mkrf_conf/i then
- @ran_rake = true
Gem::Ext::RakeBuilder
when /CMakeLists.txt/ then
- Gem::Ext::CmakeBuilder
+ Gem::Ext::CmakeBuilder.new
when /Cargo.toml/ then
Gem::Ext::CargoBuilder.new
else
@@ -208,7 +217,7 @@ 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, @target_rbconfig, n_jobs: @build_jobs)
verbose { results.join("\n") }
@@ -239,8 +248,6 @@ EOF
FileUtils.rm_f @spec.gem_build_complete_path
@spec.extensions.each do |extension|
- break if @ran_rake
-
build_extension extension, dest_path
end
diff --git a/lib/rubygems/ext/cargo_builder.rb b/lib/rubygems/ext/cargo_builder.rb
index e58d0bb75c..516459dd60 100644
--- a/lib/rubygems/ext/cargo_builder.rb
+++ b/lib/rubygems/ext/cargo_builder.rb
@@ -15,7 +15,7 @@ class Gem::Ext::CargoBuilder < Gem::Ext::Builder
end
def build(extension, dest_path, results, args = [], lib_dir = nil, cargo_dir = Dir.pwd,
- target_rbconfig = Gem.target_rbconfig)
+ target_rbconfig = Gem.target_rbconfig, n_jobs: nil)
require "tempfile"
require "fileutils"
@@ -159,7 +159,7 @@ class Gem::Ext::CargoBuilder < Gem::Ext::Builder
def linker_args
cc_flag = self.class.shellsplit(makefile_config("CC"))
# Avoid to ccache like tool from Rust build
- # see https://github.com/rubygems/rubygems/pull/8521#issuecomment-2689854359
+ # see https://github.com/ruby/rubygems/pull/8521#issuecomment-2689854359
# ex. CC="ccache gcc" or CC="sccache clang --any --args"
cc_flag.shift if cc_flag.size >= 2 && !cc_flag[1].start_with?("-")
linker = cc_flag.shift
@@ -227,10 +227,9 @@ class Gem::Ext::CargoBuilder < Gem::Ext::Builder
raise Gem::InstallError, "cargo metadata failed#{exit_reason}"
end
- # cargo metadata output is specified as json, but with the
- # --format-version 1 option the output is compatible with YAML, so we can
- # avoid the json dependency
- metadata = Gem::SafeYAML.safe_load(output)
+ # cargo metadata output is specified as json
+ require "json"
+ metadata = JSON.parse(output)
package = metadata["packages"].find {|pkg| normalize_path(pkg["manifest_path"]) == manifest_path }
unless package
found = metadata["packages"].map {|md| "#{md["name"]} at #{md["manifest_path"]}" }
diff --git a/lib/rubygems/ext/cmake_builder.rb b/lib/rubygems/ext/cmake_builder.rb
index c7bfbb8a57..e660ed558b 100644
--- a/lib/rubygems/ext/cmake_builder.rb
+++ b/lib/rubygems/ext/cmake_builder.rb
@@ -1,21 +1,110 @@
# frozen_string_literal: true
+# This builder creates extensions defined using CMake. Its is invoked if a Gem's spec file
+# sets the `extension` property to a string that contains `CMakeLists.txt`.
+#
+# In general, CMake projects are built in two steps:
+#
+# * configure
+# * build
+#
+# The builder follow this convention. First it runs a configuration step and then it runs a build step.
+#
+# CMake projects can be quite configurable - it is likely you will want to specify options when
+# installing a gem. To pass options to CMake specify them after `--` in the gem install command. For example:
+#
+# gem install <gem_name> -- --preset <preset_name>
+#
+# Note that options are ONLY sent to the configure step - it is not currently possible to specify
+# options for the build step. If this becomes and issue then the CMake builder can be updated to
+# support build options.
+#
+# Useful options to know are:
+#
+# -G to specify a generator (-G Ninja is recommended)
+# -D<CMAKE_VARIABLE> to set a CMake variable (for example -DCMAKE_BUILD_TYPE=Release)
+# --preset <preset_name> to use a preset
+#
+# If the Gem author provides presets, via CMakePresets.json file, you will likely want to use one of them.
+# If not, you may wish to specify a generator. Ninja is recommended because it can build projects in parallel
+# and thus much faster than building them serially like Make does.
+
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)
+ attr_accessor :runner, :profile
+ def initialize
+ @runner = self.class.method(:run)
+ @profile = :release
+ end
+
+ def build(extension, dest_path, results, args = [], lib_dir = nil, cmake_dir = Dir.pwd,
+ target_rbconfig = Gem.target_rbconfig, n_jobs: nil)
if target_rbconfig.path
warn "--target-rbconfig is not yet supported for CMake extensions. Ignoring"
end
- unless File.exist?(File.join(cmake_dir, "Makefile"))
- require_relative "../command"
- cmd = ["cmake", ".", "-DCMAKE_INSTALL_PREFIX=#{dest_path}", *Gem::Command.build_args]
+ # Figure the build dir
+ build_dir = File.join(cmake_dir, "build")
- run cmd, results, class_name, cmake_dir
- end
+ # Check if the gem defined presets
+ check_presets(cmake_dir, args, results)
+
+ # Configure
+ configure(cmake_dir, build_dir, dest_path, args, results)
- make dest_path, results, cmake_dir, target_rbconfig: target_rbconfig
+ # Compile
+ compile(cmake_dir, build_dir, args, results)
results
end
+
+ def configure(cmake_dir, build_dir, install_dir, args, results)
+ cmd = ["cmake",
+ cmake_dir,
+ "-B",
+ build_dir,
+ "-DCMAKE_RUNTIME_OUTPUT_DIRECTORY=#{install_dir}", # Windows
+ "-DCMAKE_LIBRARY_OUTPUT_DIRECTORY=#{install_dir}", # Not Windows
+ *Gem::Command.build_args,
+ *args]
+
+ runner.call(cmd, results, "cmake_configure", cmake_dir)
+ end
+
+ def compile(cmake_dir, build_dir, args, results)
+ cmd = ["cmake",
+ "--build",
+ build_dir.to_s,
+ "--config",
+ @profile.to_s]
+
+ runner.call(cmd, results, "cmake_compile", cmake_dir)
+ end
+
+ private
+
+ def check_presets(cmake_dir, args, results)
+ # Return if the user specified a preset
+ return unless args.grep(/--preset/i).empty?
+
+ cmd = ["cmake",
+ "--list-presets"]
+
+ presets = Array.new
+ begin
+ runner.call(cmd, presets, "cmake_presets", cmake_dir)
+
+ # Remove the first two lines of the array which is the current_directory and the command
+ # that was run
+ presets = presets[2..].join
+ results << <<~EOS
+ The gem author provided a list of presets that can be used to build the gem. To use a preset specify it on the command line:
+
+ gem install <gem_name> -- --preset <preset_name>
+
+ #{presets}
+ EOS
+ rescue Gem::InstallError
+ # Do nothing, CMakePresets.json was not included in the Gem
+ end
+ end
end
diff --git a/lib/rubygems/ext/configure_builder.rb b/lib/rubygems/ext/configure_builder.rb
index 76c1cd8b19..230b214b3c 100644
--- a/lib/rubygems/ext/configure_builder.rb
+++ b/lib/rubygems/ext/configure_builder.rb
@@ -8,7 +8,7 @@
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)
+ target_rbconfig = Gem.target_rbconfig, n_jobs: nil)
if target_rbconfig.path
warn "--target-rbconfig is not yet supported for configure-based extensions. Ignoring"
end
@@ -19,7 +19,7 @@ class Gem::Ext::ConfigureBuilder < Gem::Ext::Builder
run cmd, results, class_name, configure_dir
end
- make dest_path, results, configure_dir, target_rbconfig: target_rbconfig
+ make dest_path, results, configure_dir, target_rbconfig: target_rbconfig, n_jobs: n_jobs
results
end
diff --git a/lib/rubygems/ext/ext_conf_builder.rb b/lib/rubygems/ext/ext_conf_builder.rb
index ec2fa59412..822454355d 100644
--- a/lib/rubygems/ext/ext_conf_builder.rb
+++ b/lib/rubygems/ext/ext_conf_builder.rb
@@ -8,7 +8,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)
+ target_rbconfig = Gem.target_rbconfig, n_jobs: nil)
require "fileutils"
require "tempfile"
@@ -41,7 +41,7 @@ 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, target_rbconfig: target_rbconfig, n_jobs: n_jobs
full_tmp_dest = File.join(extension_dir, tmp_dest_relative)
diff --git a/lib/rubygems/ext/rake_builder.rb b/lib/rubygems/ext/rake_builder.rb
index 0eac5a180c..d702d7f339 100644
--- a/lib/rubygems/ext/rake_builder.rb
+++ b/lib/rubygems/ext/rake_builder.rb
@@ -8,7 +8,7 @@
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)
+ target_rbconfig = Gem.target_rbconfig, n_jobs: nil)
if target_rbconfig.path
warn "--target-rbconfig is not yet supported for Rake extensions. Ignoring"
end
diff --git a/lib/rubygems/gem_runner.rb b/lib/rubygems/gem_runner.rb
index 4cb924677f..e60cebd0cb 100644
--- a/lib/rubygems/gem_runner.rb
+++ b/lib/rubygems/gem_runner.rb
@@ -8,7 +8,6 @@
require_relative "../rubygems"
require_relative "command_manager"
-require_relative "deprecate"
##
# Run an instance of the gem program.
diff --git a/lib/rubygems/gemcutter_utilities.rb b/lib/rubygems/gemcutter_utilities.rb
index afe7957f43..9c22c14fad 100644
--- a/lib/rubygems/gemcutter_utilities.rb
+++ b/lib/rubygems/gemcutter_utilities.rb
@@ -154,10 +154,11 @@ module Gem::GemcutterUtilities
def sign_in(sign_in_host = nil, scope: nil)
sign_in_host ||= host
- return if api_key
-
pretty_host = pretty_host(sign_in_host)
-
+ if api_key
+ say "You are already signed in on #{pretty_host}."
+ return
+ end
say "Enter your #{pretty_host} credentials."
say "Don't have an account yet? " \
"Create one at #{sign_in_host}/sign_up"
diff --git a/lib/rubygems/install_default_message.rb b/lib/rubygems/install_default_message.rb
deleted file mode 100644
index 0640eaaf08..0000000000
--- a/lib/rubygems/install_default_message.rb
+++ /dev/null
@@ -1,13 +0,0 @@
-# frozen_string_literal: true
-
-require_relative "../rubygems"
-require_relative "user_interaction"
-
-##
-# A post-install hook that displays "Successfully installed
-# some_gem-1.0 as a default gem"
-
-Gem.post_install do |installer|
- ui = Gem::DefaultUserInteraction.ui
- ui.say "Successfully installed #{installer.spec.full_name} as a default gem"
-end
diff --git a/lib/rubygems/install_update_options.rb b/lib/rubygems/install_update_options.rb
index 0d0f0dc211..e8859cadaf 100644
--- a/lib/rubygems/install_update_options.rb
+++ b/lib/rubygems/install_update_options.rb
@@ -31,6 +31,15 @@ module Gem::InstallUpdateOptions
options[:bin_dir] = File.expand_path(value)
end
+ add_option(:"Install/Update", "-j", "--build-jobs VALUE", Integer,
+ "Specify the number of jobs to pass to `make` when installing",
+ "gems with native extensions.",
+ "Defaults to the number of processors.",
+ "This option is ignored on the mswin platform or",
+ "if the MAKEFLAGS environment variable is set.") do |value, options|
+ options[:build_jobs] = value
+ end
+
add_option(:"Install/Update", "--document [TYPES]", Array,
"Generate documentation for installed gems",
"List the documentation types you wish to",
@@ -158,10 +167,9 @@ module Gem::InstallUpdateOptions
options[:without_groups].concat v.map(&:intern)
end
- add_option(:"Install/Update", "--default",
+ add_option(:Deprecated, "--default",
"Add the gem's full specification to",
"specifications/default and extract only its bin") do |v,_o|
- options[:install_as_default] = v
end
add_option(:"Install/Update", "--explain",
@@ -184,6 +192,18 @@ module Gem::InstallUpdateOptions
"rbconfig.rb for the deployment target platform") do |v, _o|
Gem.set_target_rbconfig(v)
end
+
+ add_option(:"Install/Update", "--[no-]build-extension",
+ "Build native extensions during installation.",
+ "Defaults to true") do |v, _o|
+ options[:build_extension] = v
+ end
+
+ add_option(:"Install/Update", "--[no-]install-plugin",
+ "Install plugins during installation.",
+ "Defaults to true") do |v, _o|
+ options[:install_plugin] = v
+ end
end
##
diff --git a/lib/rubygems/installer.rb b/lib/rubygems/installer.rb
index 0cfe59b5bb..a6e1dc4730 100644
--- a/lib/rubygems/installer.rb
+++ b/lib/rubygems/installer.rb
@@ -8,7 +8,6 @@
require_relative "installer_uninstaller_utils"
require_relative "exceptions"
-require_relative "deprecate"
require_relative "package"
require_relative "ext"
require_relative "user_interaction"
@@ -27,8 +26,6 @@ require_relative "user_interaction"
# file. See Gem.pre_install and Gem.post_install for details.
class Gem::Installer
- extend Gem::Deprecate
-
##
# Paths where env(1) might live. Some systems are broken and have it in
# /bin
@@ -274,11 +271,7 @@ class Gem::Installer
run_pre_install_hooks
# Set loaded_from to ensure extension_dir is correct
- if @options[:install_as_default]
- spec.loaded_from = default_spec_file
- else
- spec.loaded_from = spec_file
- end
+ spec.loaded_from = spec_file
# Completely remove any previous gem files
FileUtils.rm_rf gem_dir
@@ -287,32 +280,30 @@ class Gem::Installer
dir_mode = options[:dir_mode]
FileUtils.mkdir_p gem_dir, mode: dir_mode && 0o755
- if @options[:install_as_default]
- extract_bin
- write_default_spec
- else
- extract_files
+ extract_files
- build_extensions
- write_build_info_file
- run_post_build_hooks
- end
+ build_extensions
+ write_build_info_file
+ run_post_build_hooks
generate_bin
- generate_plugins
-
- unless @options[:install_as_default]
- write_spec
- write_cache_file
+ if options[:install_plugin] == false
+ remove_stale_plugins
+ warn_skipped_plugins
+ else
+ generate_plugins
end
+ write_spec
+ write_cache_file
+
File.chmod(dir_mode, gem_dir) if dir_mode
- say spec.post_install_message if options[:post_install_message] && !spec.post_install_message.nil?
+ say clean_text(spec.post_install_message.to_s) if options[:post_install_message] && !spec.post_install_message.nil?
Gem::Specification.add_spec(spec) unless @install_dir
- load_plugin
+ load_plugin unless options[:install_plugin] == false
run_post_install_hooks
@@ -393,15 +384,6 @@ class Gem::Installer
end
##
- # Unpacks the gem into the given directory.
-
- def unpack(directory)
- @gem_dir = directory
- extract_files
- end
- rubygems_deprecate :unpack
-
- ##
# The location of the spec file that is installed.
#
@@ -409,12 +391,18 @@ class Gem::Installer
File.join gem_home, "specifications", "#{spec.full_name}.gemspec"
end
+ def default_spec_dir
+ dir = File.join(gem_home, "specifications", "default")
+ FileUtils.mkdir_p dir
+ dir
+ end
+
##
# The location of the default spec file for default gems.
#
def default_spec_file
- File.join gem_home, "specifications", "default", "#{spec.full_name}.gemspec"
+ File.join default_spec_dir, "#{spec.full_name}.gemspec"
end
##
@@ -652,6 +640,7 @@ class Gem::Installer
@build_root = options[:build_root]
@build_args = options[:build_args]
+ @build_jobs = options[:build_jobs]
@gem_home = @install_dir || user_install_dir || Gem.dir
@@ -723,6 +712,18 @@ class Gem::Installer
if spec.dependencies.any? {|dep| dep.name =~ /(?:\R|[<>])/ }
raise Gem::InstallError, "#{spec} has an invalid dependencies"
end
+
+ if spec.executables.any? {|name| !name.is_a?(String) || name != File.basename(name) || /\A\.\.?\z|\R/.match?(name) }
+ raise Gem::InstallError, "#{spec} has an invalid executable"
+ end
+
+ raise Gem::InstallError, "#{spec} has an invalid bindir" unless spec.bindir.is_a?(String)
+
+ expanded_gem_dir = File.expand_path(gem_dir)
+ expanded_bindir = File.expand_path(File.join(gem_dir, spec.bindir))
+ unless expanded_bindir == expanded_gem_dir || expanded_bindir.start_with?("#{expanded_gem_dir}/")
+ raise Gem::InstallError, "#{spec} has an invalid bindir"
+ end
end
##
@@ -731,6 +732,7 @@ class Gem::Installer
def app_script_text(bin_file_name)
# NOTE: that the `load` lines cannot be indented, as old RG versions match
# against the beginning of the line
+ escaped_bin_file_name = bin_file_name.gsub(/[\\']/) {|c| "\\#{c}" }
<<~TEXT
#{shebang bin_file_name}
#
@@ -754,9 +756,9 @@ class Gem::Installer
end
if Gem.respond_to?(:activate_and_load_bin_path)
- Gem.activate_and_load_bin_path('#{spec.name}', '#{bin_file_name}', version)
+ Gem.activate_and_load_bin_path('#{spec.name}', '#{escaped_bin_file_name}', version)
else
- load Gem.activate_bin_path('#{spec.name}', '#{bin_file_name}', version)
+ load Gem.activate_bin_path('#{spec.name}', '#{escaped_bin_file_name}', version)
end
TEXT
end
@@ -820,11 +822,37 @@ class Gem::Installer
# configure scripts and rakefiles or mkrf_conf files.
def build_extensions
- builder = Gem::Ext::Builder.new spec, build_args, Gem.target_rbconfig
+ if options[:build_extension] == false
+ warn_skipped_extensions
+ return
+ end
+
+ builder = Gem::Ext::Builder.new spec, build_args, Gem.target_rbconfig, build_jobs
builder.build_extensions
end
+ def warn_skipped_extensions # :nodoc:
+ return if spec.extensions.empty?
+
+ alert_warning "#{spec.full_name} contains native extensions that were not built.\n" \
+ "To build extensions, run: gem pristine #{spec.name} --extensions"
+ end
+
+ def warn_skipped_plugins # :nodoc:
+ return if spec.plugins.empty?
+
+ alert_warning "#{spec.full_name} contains plugins that were not installed.\n" \
+ "To install plugins, run: gem pristine #{spec.name} --only-plugins"
+ end
+
+ def remove_stale_plugins # :nodoc:
+ return unless spec.plugins.empty?
+
+ ensure_writable_dir @plugins_dir
+ remove_plugins_for(spec, @plugins_dir)
+ end
+
##
# Reads the file index and extracts each file into the gem directory.
#
@@ -889,11 +917,7 @@ class Gem::Installer
ensure_loadable_spec
- if options[:install_as_default]
- Gem.ensure_default_gem_subdirectories gem_home
- else
- Gem.ensure_gem_subdirectories gem_home
- end
+ Gem.ensure_gem_subdirectories gem_home
return true if @force
@@ -962,6 +986,15 @@ class Gem::Installer
end
end
+ def build_jobs
+ @build_jobs ||= begin
+ require "etc"
+ Etc.nprocessors + 1
+ rescue LoadError
+ 1
+ end
+ end
+
def rb_config
Gem.target_rbconfig
end
@@ -1001,9 +1034,10 @@ class Gem::Installer
# are loaded at the same time.
return unless specs.size == 1
- plugin_files = spec.plugins.map do |plugin|
- File.join(@plugins_dir, "#{spec.name}_plugin#{File.extname(plugin)}")
+ plugin_files = spec.plugins.filter_map do |plugin|
+ path = File.join(@plugins_dir, "#{spec.name}_plugin#{File.extname(plugin)}")
+ path if File.exist?(path)
end
- Gem.load_plugin_files(plugin_files)
+ Gem.load_plugin_files(plugin_files) unless plugin_files.empty?
end
end
diff --git a/lib/rubygems/name_tuple.rb b/lib/rubygems/name_tuple.rb
index 67c6f30a3d..cbdf4d7ac5 100644
--- a/lib/rubygems/name_tuple.rb
+++ b/lib/rubygems/name_tuple.rb
@@ -81,6 +81,12 @@ class Gem::NameTuple
[@name, @version, @platform]
end
+ alias_method :deconstruct, :to_a
+
+ def deconstruct_keys(keys)
+ { name: @name, version: @version, platform: @platform }
+ end
+
def inspect # :nodoc:
"#<Gem::NameTuple #{@name}, #{@version}, #{@platform}>"
end
diff --git a/lib/rubygems/package.rb b/lib/rubygems/package.rb
index c855423ed7..7e41b18f66 100644
--- a/lib/rubygems/package.rb
+++ b/lib/rubygems/package.rb
@@ -7,6 +7,7 @@
# rubocop:enable Style/AsciiComments
+require_relative "win_platform"
require_relative "security"
require_relative "user_interaction"
@@ -231,7 +232,11 @@ class Gem::Package
tar.add_file_signed "checksums.yaml.gz", 0o444, @signer do |io|
gzip_to io do |gz_io|
- Psych.dump checksums_by_algorithm, gz_io
+ if Gem.use_psych?
+ Psych.dump checksums_by_algorithm, gz_io
+ else
+ gz_io.write Gem::YAMLSerializer.dump(checksums_by_algorithm)
+ end
end
end
end
@@ -267,7 +272,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)
+ copy_stream(src_io, dst_io, stat.size)
end
end
end
@@ -436,8 +441,6 @@ EOM
symlinks << [full_name, link_target, destination, real_destination]
end
- FileUtils.rm_rf destination
-
mkdir =
if entry.directory?
destination
@@ -450,9 +453,20 @@ EOM
directories << mkdir
end
+ real_mkdir = File.realpath(mkdir)
+ unless real_mkdir == destination_dir || normalize_path(real_mkdir).start_with?(normalize_path(destination_dir + "/"))
+ raise Gem::Package::PathError.new(real_mkdir, destination_dir)
+ 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") do |out|
+ copy_stream(tar.io, out, entry.size)
+ # Flush needs to happen before chmod because there could be data
+ # in the IO buffer that needs to be written, and that could be
+ # written after the chmod (on close) which would mess up the perms
+ out.flush
+ out.chmod file_mode(entry.header.mode) & ~File.umask
+ end
end
verbose destination
@@ -461,7 +475,7 @@ EOM
symlinks.each do |name, target, destination, real_destination|
if File.exist?(real_destination)
- File.symlink(target, destination)
+ create_symlink(target, destination)
else
alert_warning "#{@spec.full_name} ships with a dangling symlink named #{name} pointing to missing #{target} file. Ignoring"
end
@@ -514,10 +528,12 @@ EOM
destination
end
- def normalize_path(pathname)
- if Gem.win_platform?
+ if Gem.win_platform?
+ def normalize_path(pathname) # :nodoc:
pathname.downcase
- else
+ end
+ else
+ def normalize_path(pathname) # :nodoc:
pathname
end
end
@@ -525,7 +541,7 @@ EOM
##
# Loads a Gem::Specification from the TarEntry +entry+
- def load_spec(entry) # :nodoc:
+ def load_spec_from_metadata(entry) # :nodoc:
limit = 10 * 1024 * 1024
case entry.full_name
when "metadata" then
@@ -545,6 +561,15 @@ EOM
tar = Gem::Package::TarReader.new gzio
yield tar
+ ensure
+ # Consume remaining gzip data to prevent the
+ # "attempt to close unfinished zstream; reset forced" warning
+ # when the GzipReader is closed with unconsumed compressed data.
+ begin
+ IO.copy_stream(gzio, IO::NULL)
+ rescue Zlib::GzipFile::Error, IOError
+ nil
+ end
end
end
@@ -635,6 +660,8 @@ EOM
raise Gem::Package::FormatError.new e.message, @gem
end
+ private
+
##
# Verifies the +checksums+ against the +digests+. This check is not
# cryptographically secure. Missing checksums are ignored.
@@ -669,12 +696,7 @@ EOM
digest entry
end
- case file_name
- when "metadata", "metadata.gz" then
- load_spec entry
- when "data.tar.gz" then
- verify_gz entry
- end
+ load_spec_from_metadata entry
rescue StandardError
warn "Exception while verifying #{@gem.path}"
raise
@@ -702,25 +724,13 @@ EOM
end
end
- ##
- # Verifies that +entry+ is a valid gzipped file.
-
- 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
- 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
+ def copy_stream(src, dst, size) # :nodoc:
+ dst.write src.read(size)
end
else
- def copy_stream(src, dst) # :nodoc:
- IO.copy_stream(src, dst)
+ def copy_stream(src, dst, size) # :nodoc:
+ IO.copy_stream(src, dst, size)
end
end
@@ -729,6 +739,23 @@ EOM
raise Gem::Package::FormatError, "#{name} is too big (over #{limit} bytes)" if bytes.size > limit
bytes
end
+
+ if Gem.win_platform?
+ # Create a symlink and fallback to copy the file or directory on Windows,
+ # where symlink creation needs special privileges in form of the Developer Mode.
+ # JRuby on Windows raises TypeError from the wincode path-conversion helper
+ # when it cannot create the symlink, so fall back to copy in that case too.
+ def create_symlink(old_name, new_name)
+ File.symlink(old_name, new_name)
+ rescue Errno::EACCES, TypeError
+ from = File.expand_path(old_name, File.dirname(new_name))
+ FileUtils.cp_r(from, new_name)
+ end
+ else
+ def create_symlink(old_name, new_name)
+ File.symlink(old_name, new_name)
+ end
+ end
end
require_relative "package/digest_io"
diff --git a/lib/rubygems/package/tar_header.rb b/lib/rubygems/package/tar_header.rb
index 0ebcbd789d..dd20d65080 100644
--- a/lib/rubygems/package/tar_header.rb
+++ b/lib/rubygems/package/tar_header.rb
@@ -56,7 +56,7 @@ class Gem::Package::TarHeader
##
# Pack format for a tar header
- PACK_FORMAT = "a100" + # name
+ PACK_FORMAT = ("a100" + # name
"a8" + # mode
"a8" + # uid
"a8" + # gid
@@ -71,12 +71,12 @@ class Gem::Package::TarHeader
"a32" + # gname
"a8" + # devmajor
"a8" + # devminor
- "a155" # prefix
+ "a155").freeze # prefix
##
# Unpack format for a tar header
- UNPACK_FORMAT = "A100" + # name
+ UNPACK_FORMAT = ("A100" + # name
"A8" + # mode
"A8" + # uid
"A8" + # gid
@@ -91,7 +91,7 @@ class Gem::Package::TarHeader
"A32" + # gname
"A8" + # devmajor
"A8" + # devminor
- "A155" # prefix
+ "A155").freeze # prefix
attr_reader(*FIELDS)
diff --git a/lib/rubygems/package/tar_reader.rb b/lib/rubygems/package/tar_reader.rb
index 25f9b2f945..b66a8a62bc 100644
--- a/lib/rubygems/package/tar_reader.rb
+++ b/lib/rubygems/package/tar_reader.rb
@@ -30,6 +30,8 @@ class Gem::Package::TarReader
nil
end
+ attr_reader :io # :nodoc:
+
##
# Creates a new tar file reader on +io+ which needs to respond to #pos,
# #eof?, #read, #getc and #pos=
diff --git a/lib/rubygems/platform.rb b/lib/rubygems/platform.rb
index e30c266fab..367b00e7e1 100644
--- a/lib/rubygems/platform.rb
+++ b/lib/rubygems/platform.rb
@@ -1,7 +1,5 @@
# frozen_string_literal: true
-require_relative "deprecate"
-
##
# Available list of platforms for targeting Gem installations.
#
@@ -21,15 +19,6 @@ class Gem::Platform
end
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|
@@ -147,6 +136,37 @@ class Gem::Platform
end
##
+ # Deconstructs the platform into an array for pattern matching.
+ # Returns [cpu, os, version].
+ #
+ # Gem::Platform.new("x86_64-linux").deconstruct #=> ["x86_64", "linux", nil]
+ #
+ # This enables array pattern matching:
+ #
+ # case Gem::Platform.new("arm64-darwin-21")
+ # in ["arm64", "darwin", version]
+ # # version => "21"
+ # end
+ alias_method :deconstruct, :to_a
+
+ ##
+ # Deconstructs the platform into a hash for pattern matching.
+ # Returns a hash with keys +:cpu+, +:os+, and +:version+.
+ #
+ # Gem::Platform.new("x86_64-darwin-20").deconstruct_keys(nil)
+ # #=> { cpu: "x86_64", os: "darwin", version: "20" }
+ #
+ # This enables hash pattern matching:
+ #
+ # case Gem::Platform.new("x86_64-linux")
+ # in cpu: "x86_64", os: "linux"
+ # # Matches Linux on x86_64
+ # end
+ def deconstruct_keys(keys)
+ { cpu: @cpu, os: @os, version: @version }
+ end
+
+ ##
# Is +other+ equal to this platform? Two platforms are equal if they have
# the same CPU, OS and version.
diff --git a/lib/rubygems/psych_tree.rb b/lib/rubygems/psych_tree.rb
index 24857adb9d..8b4c425a33 100644
--- a/lib/rubygems/psych_tree.rb
+++ b/lib/rubygems/psych_tree.rb
@@ -22,7 +22,7 @@ module Gem
def register(target, obj)
end
- # This is ported over from the yaml_tree in 1.9.3
+ # This is ported over from the YAMLTree implementation in Ruby 1.9.3
def format_time(time)
if time.utc?
time.strftime("%Y-%m-%d %H:%M:%S.%9N Z")
diff --git a/lib/rubygems/remote_fetcher.rb b/lib/rubygems/remote_fetcher.rb
index 6ed0842963..5b83dc6f6f 100644
--- a/lib/rubygems/remote_fetcher.rb
+++ b/lib/rubygems/remote_fetcher.rb
@@ -82,6 +82,7 @@ class Gem::RemoteFetcher
@proxy = proxy
@pools = {}
@pool_lock = Thread::Mutex.new
+ @pool_size = 1
@cert_files = Gem::Request.get_cert_files
@headers = headers
@@ -110,9 +111,13 @@ class Gem::RemoteFetcher
# always replaced.
def download(spec, source_uri, install_dir = Gem.dir)
+ gem_file_name = File.basename spec.cache_file
+
install_cache_dir = File.join install_dir, "cache"
cache_dir =
- if Dir.pwd == install_dir # see fetch_command
+ if Gem.configuration.global_gem_cache
+ Gem.global_gem_cache_path
+ elsif Dir.pwd == install_dir # see fetch_command
install_dir
elsif File.writable?(install_cache_dir) || (File.writable?(install_dir) && !File.exist?(install_cache_dir))
install_cache_dir
@@ -120,7 +125,6 @@ class Gem::RemoteFetcher
File.join Gem.user_dir, "cache"
end
- gem_file_name = File.basename spec.cache_file
local_gem_path = File.join cache_dir, gem_file_name
require "fileutils"
@@ -173,7 +177,7 @@ class Gem::RemoteFetcher
end
verbose "Using local gem #{local_gem_path}"
- when nil then # TODO: test for local overriding cache
+ when nil then
source_path = if Gem.win_platform? && source_uri.scheme &&
!source_uri.path.include?(":")
"#{source_uri.scheme}:#{source_uri.path}"
@@ -233,7 +237,9 @@ class Gem::RemoteFetcher
fetch_http(location, last_modified, head, depth + 1)
else
- raise FetchError.new("bad response #{response.message} #{response.code}", uri)
+ custom_error = response["X-Error-Message"]
+ error_detail = custom_error || response.message
+ raise FetchError.new("Bad response #{error_detail} #{response.code}", uri)
end
end
@@ -245,11 +251,14 @@ class Gem::RemoteFetcher
def fetch_path(uri, mtime = nil, head = false)
uri = Gem::Uri.new uri
- unless uri.scheme
- raise ArgumentError, "uri scheme is invalid: #{uri.scheme.inspect}"
- end
+ method = {
+ "http" => "fetch_http",
+ "https" => "fetch_http",
+ "s3" => "fetch_s3",
+ "file" => "fetch_file",
+ }.fetch(uri.scheme) { raise ArgumentError, "uri scheme is invalid: #{uri.scheme.inspect}" }
- data = send "fetch_#{uri.scheme}", uri, mtime, head
+ data = send method, uri, mtime, head
if data && !head && uri.to_s.end_with?(".gz")
begin
@@ -335,7 +344,7 @@ class Gem::RemoteFetcher
def pools_for(proxy)
@pool_lock.synchronize do
- @pools[proxy] ||= Gem::Request::ConnectionPools.new proxy, @cert_files
+ @pools[proxy] ||= Gem::Request::ConnectionPools.new proxy, @cert_files, @pool_size
end
end
end
diff --git a/lib/rubygems/request.rb b/lib/rubygems/request.rb
index 9116785231..e817ee5704 100644
--- a/lib/rubygems/request.rb
+++ b/lib/rubygems/request.rb
@@ -2,6 +2,7 @@
require_relative "vendored_net_http"
require_relative "user_interaction"
+require_relative "uri_formatter"
class Gem::Request
extend Gem::UserInteraction
diff --git a/lib/rubygems/request/connection_pools.rb b/lib/rubygems/request/connection_pools.rb
index 6c1b04ab65..01e7e0629a 100644
--- a/lib/rubygems/request/connection_pools.rb
+++ b/lib/rubygems/request/connection_pools.rb
@@ -7,11 +7,12 @@ class Gem::Request::ConnectionPools # :nodoc:
attr_accessor :client
end
- def initialize(proxy_uri, cert_files)
+ def initialize(proxy_uri, cert_files, pool_size = 1)
@proxy_uri = proxy_uri
@cert_files = cert_files
@pools = {}
@pool_mutex = Thread::Mutex.new
+ @pool_size = pool_size
end
def pool_for(uri)
@@ -20,9 +21,9 @@ class Gem::Request::ConnectionPools # :nodoc:
@pool_mutex.synchronize do
@pools[key] ||=
if https? uri
- Gem::Request::HTTPSPool.new(http_args, @cert_files, @proxy_uri)
+ Gem::Request::HTTPSPool.new(http_args, @cert_files, @proxy_uri, @pool_size)
else
- Gem::Request::HTTPPool.new(http_args, @cert_files, @proxy_uri)
+ Gem::Request::HTTPPool.new(http_args, @cert_files, @proxy_uri, @pool_size)
end
end
end
diff --git a/lib/rubygems/request/http_pool.rb b/lib/rubygems/request/http_pool.rb
index 52543de41f..468502ca6b 100644
--- a/lib/rubygems/request/http_pool.rb
+++ b/lib/rubygems/request/http_pool.rb
@@ -9,12 +9,14 @@
class Gem::Request::HTTPPool # :nodoc:
attr_reader :cert_files, :proxy_uri
- def initialize(http_args, cert_files, proxy_uri)
+ def initialize(http_args, cert_files, proxy_uri, pool_size)
@http_args = http_args
@cert_files = cert_files
@proxy_uri = proxy_uri
- @queue = Thread::SizedQueue.new 1
- @queue << nil
+ @pool_size = pool_size
+
+ @queue = Thread::SizedQueue.new @pool_size
+ setup_queue
end
def checkout
@@ -31,7 +33,8 @@ class Gem::Request::HTTPPool # :nodoc:
connection.finish
end
end
- @queue.push(nil)
+
+ setup_queue
end
private
@@ -44,4 +47,8 @@ class Gem::Request::HTTPPool # :nodoc:
connection.start
connection
end
+
+ def setup_queue
+ @pool_size.times { @queue.push(nil) }
+ end
end
diff --git a/lib/rubygems/request_set.rb b/lib/rubygems/request_set.rb
index 5a855fdb10..eb8b4658f3 100644
--- a/lib/rubygems/request_set.rb
+++ b/lib/rubygems/request_set.rb
@@ -182,7 +182,7 @@ class Gem::RequestSet
# Install requested gems after they have been downloaded
sorted_requests.each do |req|
if req.installed? && @always_install.none? {|spec| spec == req.spec.spec }
- req.spec.spec.build_extensions
+ req.spec.spec.build_extensions unless options[:build_extension] == false
yield req, nil if block_given?
next
end
@@ -234,10 +234,6 @@ class Gem::RequestSet
sorted_requests.each do |spec|
puts " #{spec.full_name}"
end
-
- if Gem.configuration.really_verbose
- @resolver.stats.display
- end
else
installed = install options, &block
@@ -322,11 +318,8 @@ class Gem::RequestSet
@git_set.root_dir = @install_dir
lock_file = "#{File.expand_path(path)}.lock"
- begin
- tokenizer = Gem::RequestSet::Lockfile::Tokenizer.from_file lock_file
- parser = tokenizer.make_parser self, []
- parser.parse
- rescue Errno::ENOENT
+ if File.exist?(lock_file)
+ load_lockfile lock_file
end
gf = Gem::RequestSet::GemDependencyAPI.new self, path
@@ -335,6 +328,63 @@ class Gem::RequestSet
gf.load
end
+ def load_lockfile(lock_file) # :nodoc:
+ require "bundler"
+ require "bundler/lockfile_parser"
+
+ # Bundler::Source::Path resolves relative `remote:` paths against
+ # Bundler.root, which raises when there is no Gemfile in the working
+ # directory. Anchor it to the lockfile's directory so PATH sections in a
+ # `gem install -g` lockfile can be parsed without a Bundler environment.
+ previous_root = Bundler.instance_variable_get(:@root)
+ Bundler.instance_variable_set(:@root, Pathname.new(File.expand_path(File.dirname(lock_file))))
+
+ parser = Bundler::LockfileParser.new(File.read(lock_file), lockfile_path: lock_file)
+
+ parser.specs.group_by(&:source).each do |source, specs|
+ case source
+ when Bundler::Source::Rubygems
+ remotes = source.remotes.map {|remote| Gem::Source.new(remote.to_s) }
+ remotes << Gem::Source.new(Gem::DEFAULT_HOST) if remotes.empty?
+ lock_set = Gem::Resolver::LockSet.new(remotes)
+ specs.each do |spec|
+ added = lock_set.add(spec.name, spec.version.to_s, spec.platform)
+ spec.dependencies.each do |dep|
+ added.each {|s| s.add_dependency dep }
+ end
+ end
+ @sets << lock_set
+ when Bundler::Source::Git
+ git_set = Gem::Resolver::GitSet.new
+ git_set.root_dir = @install_dir
+ specs.each do |spec|
+ git_spec = git_set.add_git_spec(
+ spec.name,
+ spec.version.to_s,
+ source.uri.to_s,
+ source.revision,
+ source.submodules || false
+ )
+ spec.dependencies.each {|dep| git_spec.add_dependency dep }
+ end
+ @sets << git_set
+ when Bundler::Source::Path
+ vendor_set = Gem::Resolver::VendorSet.new
+ specs.each do |spec|
+ loaded = vendor_set.add_vendor_gem(spec.name, source.path.to_s)
+ spec.dependencies.each {|dep| loaded.dependencies << dep }
+ end
+ @sets << vendor_set
+ end
+ end
+
+ parser.dependencies.each_value do |dep|
+ gem dep.name, *dep.requirement.as_list
+ end
+ ensure
+ Bundler.instance_variable_set(:@root, previous_root) if defined?(previous_root)
+ end
+
def pretty_print(q) # :nodoc:
q.group 2, "[RequestSet:", "]" do
q.breakable
@@ -462,4 +512,3 @@ end
require_relative "request_set/gem_dependency_api"
require_relative "request_set/lockfile"
-require_relative "request_set/lockfile/tokenizer"
diff --git a/lib/rubygems/request_set/lockfile.rb b/lib/rubygems/request_set/lockfile.rb
index c446b3ae51..8b9c9690d6 100644
--- a/lib/rubygems/request_set/lockfile.rb
+++ b/lib/rubygems/request_set/lockfile.rb
@@ -38,7 +38,7 @@ class Gem::RequestSet::Lockfile
end
##
- # Creates a new Lockfile for the given +request_set+ and +gem_deps_file+
+ # Creates a new Lockfile for the given Gem::RequestSet and +gem_deps_file+
# location.
def self.build(request_set, gem_deps_file, dependencies = nil)
@@ -231,5 +231,3 @@ class Gem::RequestSet::Lockfile
@set.sorted_requests
end
end
-
-require_relative "lockfile/tokenizer"
diff --git a/lib/rubygems/request_set/lockfile/parser.rb b/lib/rubygems/request_set/lockfile/parser.rb
deleted file mode 100644
index e751a1445e..0000000000
--- a/lib/rubygems/request_set/lockfile/parser.rb
+++ /dev/null
@@ -1,344 +0,0 @@
-# frozen_string_literal: true
-
-class Gem::RequestSet::Lockfile::Parser
- ###
- # Parses lockfiles
-
- def initialize(tokenizer, set, platforms, filename = nil)
- @tokens = tokenizer
- @filename = filename
- @set = set
- @platforms = platforms
- end
-
- def parse
- until @tokens.empty? do
- token = get
-
- case token.type
- when :section then
- @tokens.skip :newline
-
- case token.value
- when "DEPENDENCIES" then
- parse_DEPENDENCIES
- when "GIT" then
- parse_GIT
- when "GEM" then
- parse_GEM
- when "PATH" then
- parse_PATH
- when "PLATFORMS" then
- parse_PLATFORMS
- else
- token = get until @tokens.empty? || peek.first == :section
- end
- else
- raise "BUG: unhandled token #{token.type} (#{token.value.inspect}) at line #{token.line} column #{token.column}"
- end
- end
- end
-
- ##
- # Gets the next token for a Lockfile
-
- def get(expected_types = nil, expected_value = nil) # :nodoc:
- token = @tokens.shift
-
- if expected_types && !Array(expected_types).include?(token.type)
- unget token
-
- 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
- end
-
- if expected_value && expected_value != token.value
- unget token
-
- 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
- end
-
- token
- end
-
- def parse_DEPENDENCIES # :nodoc:
- while !@tokens.empty? && peek.type == :text do
- token = get :text
-
- requirements = []
-
- case peek[0]
- when :bang then
- get :bang
-
- requirements << pinned_requirement(token.value)
- when :l_paren then
- get :l_paren
-
- loop do
- op = get(:requirement).value
- version = get(:text).value
-
- requirements << "#{op} #{version}"
-
- break unless peek.type == :comma
-
- get :comma
- end
-
- get :r_paren
-
- if peek[0] == :bang
- requirements.clear
- requirements << pinned_requirement(token.value)
-
- get :bang
- end
- end
-
- @set.gem token.value, *requirements
-
- skip :newline
- end
- end
-
- def parse_GEM # :nodoc:
- sources = []
-
- while peek.first(2) == [:entry, "remote"] do
- get :entry, "remote"
- data = get(:text).value
- skip :newline
-
- sources << Gem::Source.new(data)
- end
-
- sources << Gem::Source.new(Gem::DEFAULT_HOST) if sources.empty?
-
- get :entry, "specs"
-
- skip :newline
-
- set = Gem::Resolver::LockSet.new sources
- last_specs = nil
-
- while !@tokens.empty? && peek.type == :text do
- token = get :text
- name = token.value
- column = token.column
-
- case peek[0]
- when :newline then
- last_specs.each do |spec|
- spec.add_dependency Gem::Dependency.new name if column == 6
- end
- when :l_paren then
- get :l_paren
-
- token = get [:text, :requirement]
- type = token.type
- data = token.value
-
- if type == :text && column == 4
- version, platform = data.split "-", 2
-
- platform =
- platform ? Gem::Platform.new(platform) : Gem::Platform::RUBY
-
- last_specs = set.add name, version, platform
- else
- dependency = parse_dependency name, data
-
- last_specs.each do |spec|
- spec.add_dependency dependency
- end
- end
-
- get :r_paren
- else
- raise "BUG: unknown token #{peek}"
- end
-
- skip :newline
- end
-
- @set.sets << set
- end
-
- def parse_GIT # :nodoc:
- get :entry, "remote"
- repository = get(:text).value
-
- skip :newline
-
- get :entry, "revision"
- revision = get(:text).value
-
- skip :newline
-
- type = peek.type
- value = peek.value
- if type == :entry && %w[branch ref tag].include?(value)
- get
- get :text
-
- skip :newline
- end
-
- get :entry, "specs"
-
- skip :newline
-
- set = Gem::Resolver::GitSet.new
- set.root_dir = @set.install_dir
-
- last_spec = nil
-
- while !@tokens.empty? && peek.type == :text do
- token = get :text
- name = token.value
- column = token.column
-
- case peek[0]
- when :newline then
- last_spec.add_dependency Gem::Dependency.new name if column == 6
- when :l_paren then
- get :l_paren
-
- token = get [:text, :requirement]
- type = token.type
- data = token.value
-
- if type == :text && column == 4
- last_spec = set.add_git_spec name, data, repository, revision, true
- else
- dependency = parse_dependency name, data
-
- last_spec.add_dependency dependency
- end
-
- get :r_paren
- else
- raise "BUG: unknown token #{peek}"
- end
-
- skip :newline
- end
-
- @set.sets << set
- end
-
- def parse_PATH # :nodoc:
- get :entry, "remote"
- directory = get(:text).value
-
- skip :newline
-
- get :entry, "specs"
-
- skip :newline
-
- set = Gem::Resolver::VendorSet.new
- last_spec = nil
-
- while !@tokens.empty? && peek.first == :text do
- token = get :text
- name = token.value
- column = token.column
-
- case peek[0]
- when :newline then
- last_spec.add_dependency Gem::Dependency.new name if column == 6
- when :l_paren then
- get :l_paren
-
- token = get [:text, :requirement]
- type = token.type
- data = token.value
-
- if type == :text && column == 4
- last_spec = set.add_vendor_gem name, directory
- else
- dependency = parse_dependency name, data
-
- last_spec.dependencies << dependency
- end
-
- get :r_paren
- else
- raise "BUG: unknown token #{peek}"
- end
-
- skip :newline
- end
-
- @set.sets << set
- end
-
- def parse_PLATFORMS # :nodoc:
- while !@tokens.empty? && peek.first == :text do
- name = get(:text).value
-
- @platforms << name
-
- skip :newline
- end
- end
-
- ##
- # Parses the requirements following the dependency +name+ and the +op+ for
- # the first token of the requirements and returns a Gem::Dependency object.
-
- def parse_dependency(name, op) # :nodoc:
- return Gem::Dependency.new name, op unless peek[0] == :text
-
- version = get(:text).value
-
- requirements = ["#{op} #{version}"]
-
- while peek.type == :comma do
- get :comma
- op = get(:requirement).value
- version = get(:text).value
-
- requirements << "#{op} #{version}"
- end
-
- Gem::Dependency.new name, requirements
- end
-
- private
-
- def skip(type) # :nodoc:
- @tokens.skip type
- end
-
- ##
- # Peeks at the next token for Lockfile
-
- def peek # :nodoc:
- @tokens.peek
- end
-
- def pinned_requirement(name) # :nodoc:
- requirement = Gem::Dependency.new name
- specification = @set.sets.flat_map do |set|
- set.find_all(requirement)
- end.compact.first
-
- specification&.version
- end
-
- ##
- # Ungets the last token retrieved by #get
-
- def unget(token) # :nodoc:
- @tokens.unshift token
- end
-end
diff --git a/lib/rubygems/request_set/lockfile/tokenizer.rb b/lib/rubygems/request_set/lockfile/tokenizer.rb
deleted file mode 100644
index 65cef3baa0..0000000000
--- a/lib/rubygems/request_set/lockfile/tokenizer.rb
+++ /dev/null
@@ -1,122 +0,0 @@
-# frozen_string_literal: true
-
-# ) frozen_string_literal: true
-require_relative "parser"
-
-class Gem::RequestSet::Lockfile::Tokenizer
- Token = Struct.new :type, :value, :column, :line
- EOF = Token.new :EOF
-
- def self.from_file(file)
- new File.read(file), file
- end
-
- def initialize(input, filename = nil, line = 0, pos = 0)
- @line = line
- @line_pos = pos
- @tokens = []
- @filename = filename
- tokenize input
- end
-
- def make_parser(set, platforms)
- Gem::RequestSet::Lockfile::Parser.new self, set, platforms, @filename
- end
-
- def to_a
- @tokens.map {|token| [token.type, token.value, token.column, token.line] }
- end
-
- def skip(type)
- @tokens.shift while !@tokens.empty? && peek.type == type
- end
-
- ##
- # Calculates the column (by byte) and the line of the current token based on
- # +byte_offset+.
-
- def token_pos(byte_offset) # :nodoc:
- [byte_offset - @line_pos, @line]
- end
-
- def empty?
- @tokens.empty?
- end
-
- def unshift(token)
- @tokens.unshift token
- end
-
- def next_token
- @tokens.shift
- end
- alias_method :shift, :next_token
-
- def peek
- @tokens.first || EOF
- end
-
- private
-
- def tokenize(input)
- require "strscan"
- s = StringScanner.new input
-
- until s.eos? do
- pos = s.pos
-
- pos = s.pos if leading_whitespace = s.scan(/ +/)
-
- if s.scan(/[<|=>]{7}/)
- message = "your #{@filename} contains merge conflict markers"
- column, line = token_pos pos
-
- raise Gem::RequestSet::Lockfile::ParseError.new message, column, line, @filename
- end
-
- @tokens <<
- if s.scan(/\r?\n/)
-
- token = Token.new(:newline, nil, *token_pos(pos))
- @line_pos = s.pos
- @line += 1
- token
- elsif s.scan(/[A-Z]+/)
-
- if leading_whitespace
- text = s.matched
- text += s.scan(/[^\s)]*/).to_s # in case of no match
- Token.new(:text, text, *token_pos(pos))
- else
- Token.new(:section, s.matched, *token_pos(pos))
- end
- elsif s.scan(/([a-z]+):\s/)
-
- s.pos -= 1 # rewind for possible newline
- Token.new(:entry, s[1], *token_pos(pos))
- elsif s.scan(/\(/)
-
- Token.new(:l_paren, nil, *token_pos(pos))
- elsif s.scan(/\)/)
-
- Token.new(:r_paren, nil, *token_pos(pos))
- elsif s.scan(/<=|>=|=|~>|<|>|!=/)
-
- Token.new(:requirement, s.matched, *token_pos(pos))
- elsif s.scan(/,/)
-
- Token.new(:comma, nil, *token_pos(pos))
- elsif s.scan(/!/)
-
- Token.new(:bang, nil, *token_pos(pos))
- elsif s.scan(/[^\s),!]*/)
-
- Token.new(:text, s.matched, *token_pos(pos))
- else
- raise "BUG: can't create token for: #{s.string[s.pos..-1].inspect}"
- end
- end
-
- @tokens
- end
-end
diff --git a/lib/rubygems/resolver.rb b/lib/rubygems/resolver.rb
index ed4cbde3ba..788206c056 100644
--- a/lib/rubygems/resolver.rb
+++ b/lib/rubygems/resolver.rb
@@ -2,7 +2,6 @@
require_relative "dependency"
require_relative "exceptions"
-require_relative "util/list"
##
# Given a set of Gem::Dependency objects as +needed+ and a way to query the
@@ -11,7 +10,7 @@ require_relative "util/list"
# all the requirements.
class Gem::Resolver
- require_relative "vendored_molinillo"
+ require_relative "vendored_pub_grub"
##
# If the DEBUG_RESOLVER environment variable is set then debugging mode is
@@ -36,11 +35,6 @@ class Gem::Resolver
attr_accessor :ignore_dependencies
##
- # List of dependencies that could not be found in the configured sources.
-
- attr_reader :stats
-
- ##
# Hash of gems to skip resolution. Keyed by gem name, with arrays of
# gem specifications as values.
@@ -105,219 +99,449 @@ class Gem::Resolver
@ignore_dependencies = false
@skip_gems = {}
@soft_missing = false
- @stats = Gem::Resolver::Stats.new
- end
- def explain(stage, *data) # :nodoc:
- return unless DEBUG_RESOLVER
+ @root_package = RootPackage.new
+ @root_version = Gem::PubGrub::Package.root_version
+
+ @packages = {}
- d = data.map(&:pretty_inspect).join(", ")
- $stderr.printf "%10s %s\n", stage.to_s.upcase, d
+ @unfiltered_specs = Hash.new {|h, name| h[name] = find_unfiltered_specs_for(name) }
+ @all_specs = Hash.new {|h, name| h[name] = filter_specs(@unfiltered_specs[name]) }
+ @all_versions = Hash.new {|h, pkg| h[pkg] = @all_specs[pkg.to_s].map(&:version).uniq.sort }
+ @sorted_versions = Hash.new do |h, pkg|
+ h[pkg] = Gem::PubGrub::Package.root?(pkg) ? [@root_version] : @all_versions[pkg]
+ end
+ @cached_dependencies = Hash.new do |h, pkg|
+ h[pkg] = if Gem::PubGrub::Package.root?(pkg)
+ { @root_version => root_dependencies }
+ else
+ Hash.new {|v, ver| v[ver] = compute_dependencies(pkg, ver) }
+ end
+ end
+ @version_to_index = Hash.new {|h, pkg| h[pkg] = @sorted_versions[pkg].each_with_index.to_h }
+ @versions_for_cache = Hash.new {|h, pkg| h[pkg] = {} }
+ @spec_for_cache = Hash.new {|h, name| h[name] = build_spec_for_cache(name) }
end
- def explain_list(stage) # :nodoc:
- return unless DEBUG_RESOLVER
+ ##
+ # Proceed with resolution! Returns an array of ActivationRequest objects.
+
+ def resolve
+ # Pre-check: raise UnsatisfiableDependencyError for root deps with no
+ # platform match. We filter by platform ONLY here (not required_ruby_version
+ # / required_rubygems_version): a foreign-platform gem is genuinely "not
+ # found", but a gem that exists yet is incompatible with the running Ruby
+ # should flow through the solver to a DependencyResolutionError that names
+ # the Ruby requirement. That matches Bundler (which models Ruby as a
+ # synthetic dependency, so this surfaces as a solve failure) and gives a
+ # clearer message than the platform-oriented UnsatisfiableDependencyError.
+ @needed.each do |dep|
+ next if @soft_missing
+ dep_request = DependencyRequest.new(dep, nil)
+ all = @set.find_all(dep_request)
+ matching = select_local_platforms(all)
+
+ next unless matching.empty?
+
+ exc = Gem::UnsatisfiableDependencyError.new(dep_request, all)
+ exc.errors = @set.errors
+ raise exc
+ end
- data = yield
- $stderr.printf "%10s (%d entries)\n", stage.to_s.upcase, data.size
- unless data.empty?
- require "pp"
- PP.pp data, $stderr
+ solver = Gem::PubGrub::VersionSolver.new(
+ source: self,
+ root: @root_package,
+ strategy: Gem::Resolver::Strategy.new(self),
+ logger: make_logger
+ )
+ result = solver.solve
+
+ # Convert to Array<ActivationRequest>
+ needed_by_name = @needed.group_by(&:name)
+ result.filter_map do |package, version|
+ next if Gem::PubGrub::Package.root?(package)
+ spec = spec_for(package.to_s, version)
+ dep = needed_by_name[package.to_s]&.first || Gem::Dependency.new(package.to_s)
+ dep_request = DependencyRequest.new(dep, nil)
+ ActivationRequest.new(spec, dep_request)
+ end
+ rescue Gem::PubGrub::SolveFailure => e
+ extended = extract_extended_explanation(e.incompatibility)
+ if extended
+ message = "#{e.explanation}\n\n#{extended}"
+ raise Gem::DependencyResolutionError, Struct.new(:explanation).new(message)
+ else
+ raise Gem::DependencyResolutionError, e
end
end
- ##
- # Creates an ActivationRequest for the given +dep+ and the last +possible+
- # specification.
- #
- # Returns the Specification and the ActivationRequest
+ # PubGrub source interface methods
+
+ def all_versions_for(package)
+ versions = @sorted_versions[package].reverse # highest first
+ name = package.to_s
+
+ if (skip_dep_gems = skip_gems[name]) && !skip_dep_gems.empty?
+ # Conservative mode: float the already-installed (skip) versions to the
+ # front so the solver prefers them. This sets *preference* only (it feeds
+ # the strategy's version-index map); it does not restrict availability, so
+ # every version stays selectable via versions_for. When an installed
+ # version is made impossible by a downstream conflict, the solver
+ # backtracks to a newer version instead of failing. Molinillo instead
+ # hard-restricted the candidate set to skip versions and raised.
+ #
+ # This reaches the same outcome as Bundler (upgrade-over-raise) for the
+ # common single-blocked-gem case, though the mechanism differs: Bundler
+ # hard-pins locked gems and selectively unlocks + re-solves on conflict,
+ # whereas we float as a preference and let PubGrub backtrack in one solve.
+ # The float can therefore over-upgrade when several installed gems are
+ # jointly involved in a conflict; that outcome-level divergence is
+ # accepted (see test_conservative_upgrades_when_installed_blocked).
+ skip_versions = skip_dep_gems.map(&:version)
+ preferred, rest = versions.partition {|v| skip_versions.include?(v) }
+ preferred + rest
+ else
+ # Prefer already-installed versions to avoid unnecessary upgrades
+ installed_versions = @all_specs[name].
+ select {|s| s.is_a?(Gem::Resolver::InstalledSpecification) }.
+ map(&:version)
+ if installed_versions.any?
+ preferred, rest = versions.partition {|v| installed_versions.include?(v) }
+ preferred + rest
+ else
+ versions
+ end
+ end
+ end
+
+ def versions_for(package, range = Gem::PubGrub::VersionRange.any)
+ @versions_for_cache[package][range] ||= begin
+ candidates = range.select_versions(@sorted_versions[package])
+
+ if Gem::PubGrub::Package.root?(package) ||
+ (@set.respond_to?(:prerelease) && @set.prerelease) ||
+ range_admits_prerelease?(range)
+ candidates
+ elsif @all_versions[package].any? {|v| !v.prerelease? }
+ candidates.reject(&:prerelease?)
+ else
+ # Only prereleases exist for this gem; fall back to them so
+ # dependencies like `>= 1.0` can still be satisfied.
+ candidates
+ end
+ end
+ end
- def activation_request(dep, possible) # :nodoc:
- spec = possible.pop
+ def no_versions_incompatibility_for(_package, unsatisfied_term)
+ cause = Gem::PubGrub::Incompatibility::NoVersions.new(unsatisfied_term)
- explain :activate, [spec.full_name, possible.size]
- explain :possible, possible
+ name = unsatisfied_term.package.to_s
+ constraint = unsatisfied_term.constraint
+ extended_explanation = build_extended_explanation(name, constraint)
- activation_request =
- Gem::Resolver::ActivationRequest.new spec, dep, possible
+ custom_explanation = if extended_explanation
+ "#{constraint} could not be found in any repository"
+ end
- [spec, activation_request]
+ Gem::Resolver::Incompatibility.new(
+ [unsatisfied_term],
+ cause: cause,
+ custom_explanation: custom_explanation,
+ extended_explanation: extended_explanation
+ )
end
- def requests(s, act, reqs = []) # :nodoc:
- return reqs if @ignore_dependencies
+ def incompatibilities_for(package, version)
+ package_deps = @cached_dependencies[package]
+ sorted_versions = @sorted_versions[package]
+ package_deps[version].filter_map do |dep_package_name, dep_constraint|
+ dep_package = dep_constraint.package
- s.fetch_development_dependencies if @development
+ low = high = @version_to_index[package][version]
- s.dependencies.reverse_each do |d|
- next if d.type == :development && !@development
- next if d.type == :development && @development_shallow &&
- act.development?
- next if d.type == :development && @development_shallow &&
- act.parent
+ # find version low such that all >= low share the same dep
+ while low > 0 &&
+ package_deps[sorted_versions[low - 1]][dep_package_name] == dep_constraint
+ low -= 1
+ end
+ low =
+ if low == 0
+ nil
+ else
+ sorted_versions[low]
+ end
+
+ # find version high such that all < high share the same dep
+ while high < sorted_versions.length &&
+ package_deps[sorted_versions[high]][dep_package_name] == dep_constraint
+ high += 1
+ end
+ high =
+ if high == sorted_versions.length
+ nil
+ else
+ sorted_versions[high]
+ end
+
+ range = Gem::PubGrub::VersionRange.new(min: low, max: high, include_min: !low.nil?)
+ self_constraint = Gem::PubGrub::VersionConstraint.new(package, range: range)
+
+ # No specs anywhere means an unknown package. Check @unfiltered_specs, not
+ # the filtered set, so a dep filtered out by platform/Ruby/prerelease falls
+ # through to NoVersions for proper hints instead. The band-scoped
+ # self_constraint lets clean sibling versions still resolve via backtracking.
+ if @unfiltered_specs[dep_package_name].empty?
+ cause = Gem::PubGrub::Incompatibility::InvalidDependency.new(dep_package, dep_constraint)
+ self_term = Gem::PubGrub::Term.new(self_constraint, true)
+ # PubGrub's default InvalidDependency rendering drops the version
+ # requirement ("depends on unknown package bar"). Supply a custom
+ # explanation so the missing dependency's constraint is preserved
+ # ("depends on bar = 0.5 which could not be found in any repository"),
+ # matching Molinillo's diagnostics.
+ return [Gem::PubGrub::Incompatibility.new(
+ [self_term],
+ cause: cause,
+ custom_explanation: "#{self_term.to_s(allow_every: true)} depends on #{dep_constraint} which could not be found in any repository"
+ )]
+ end
- reqs << Gem::Resolver::DependencyRequest.new(d, act)
- @stats.requirement!
+ # An empty range means the requirement is self-contradictory (e.g. `> 2, < 1`).
+ if dep_constraint.range.empty?
+ return [Gem::Resolver::Incompatibility.new(
+ [Gem::PubGrub::Term.new(self_constraint, true)],
+ cause: Gem::PubGrub::Incompatibility::NoVersions.new(dep_constraint),
+ custom_explanation: "#{dep_package_name} cannot satisfy contradictory requirements #{dep_constraint.constraint_string}"
+ )]
+ end
+
+ Gem::PubGrub::Incompatibility.new(
+ [Gem::PubGrub::Term.new(self_constraint, true), Gem::PubGrub::Term.new(dep_constraint, false)],
+ cause: :dependency
+ )
end
+ end
+
+ ##
+ # Returns the gems in +specs+ that match the local platform.
- @set.prefetch reqs
+ def select_local_platforms(specs) # :nodoc:
+ specs.select do |spec|
+ Gem::Platform.installable? spec
+ end
+ end
- @stats.record_requirements reqs
+ private
- reqs
+ def package_for(name)
+ @packages[name] ||= Gem::PubGrub::Package.new(name)
end
- include Gem::Molinillo::UI
+ def root_dependencies
+ deps = {}
+ @needed.each do |dep|
+ constraint = Gem::PubGrub::RubyGems.requirement_to_constraint(package_for(dep.name), dep.requirement)
+ deps[dep.name] = deps.key?(dep.name) ? deps[dep.name].intersect(constraint) : constraint
+ end
+ deps
+ end
- def output
- @output ||= debug? ? $stdout : File.open(IO::NULL, "w")
+ # Only the min bound is inspected: `~>` synthesises a max like `X.A`
+ # whose suffix looks prerelease to Gem::Version but is not the user's
+ # intent, so checking max would mis-admit prereleases for every `~>`.
+ def range_admits_prerelease?(range)
+ range.ranges.any? do |r|
+ next false if r.empty?
+ r.min&.prerelease?
+ end
end
- def debug?
- DEBUG_RESOLVER
+ def find_unfiltered_specs_for(name)
+ dep = Gem::Dependency.new(name, ">= 0.a")
+ dep_request = DependencyRequest.new(dep, nil)
+ @set.find_all(dep_request)
end
- include Gem::Molinillo::SpecificationProvider
+ def filter_specs(specs)
+ filtered = select_local_platforms(specs)
- ##
- # Proceed with resolution! Returns an array of ActivationRequest objects.
+ unless @soft_missing
+ filtered = filtered.select do |s|
+ s.required_ruby_version.satisfied_by?(Gem.ruby_version) &&
+ s.required_rubygems_version.satisfied_by?(Gem.rubygems_version)
+ rescue StandardError
+ true
+ end
+ end
- def resolve
- Gem::Molinillo::Resolver.new(self, self).resolve(@needed.map {|d| DependencyRequest.new d, nil }).tsort.filter_map(&:payload)
- rescue Gem::Molinillo::VersionConflict => e
- conflict = e.conflicts.values.first
- raise Gem::DependencyResolutionError, Conflict.new(conflict.requirement_trees.first.first, conflict.existing, conflict.requirement)
- ensure
- @output.close if defined?(@output) && !debug?
+ filtered
end
- ##
- # Extracts the specifications that may be able to fulfill +dependency+ and
- # returns those that match the local platform and all those that match.
+ def spec_for(name, version)
+ @spec_for_cache[name][version]
+ end
- def find_possible(dependency) # :nodoc:
- all = @set.find_all dependency
+ def build_spec_for_cache(name)
+ # Rank sources by the order they were first supplied so that, when multiple
+ # sources offer the same version and platform, the earlier source wins.
+ source_rank = {}
+ @all_specs[name].each do |s|
+ source_rank[s.source] ||= source_rank.size
+ end
- if (skip_dep_gems = skip_gems[dependency.name]) && !skip_dep_gems.empty?
- matching = all.select do |api_spec|
- skip_dep_gems.any? {|s| api_spec.version == s.version }
- end
+ @all_specs[name].group_by(&:version).transform_values do |candidates|
+ next candidates.first if candidates.length == 1
+
+ # Prefer already-installed specs to avoid unnecessary downloads
+ installed = candidates.select {|s| s.is_a?(Gem::Resolver::InstalledSpecification) }
+ next installed.first if installed.length == 1
+ candidates = installed if installed.any?
- all = matching unless matching.empty?
+ # Among remaining candidates, prefer the most specific platform, then the
+ # earlier-supplied source.
+ candidates.min_by do |s|
+ [Gem::Platform.platform_specificity_match(s.platform, Gem::Platform.local),
+ source_rank[s.source]]
+ end
end
+ end
- matching_platform = select_local_platforms all
+ def compute_dependencies(package, version)
+ spec = spec_for(package.to_s, version)
+ return {} unless spec
+ return {} if @ignore_dependencies
- [matching_platform, all]
- end
+ spec.fetch_development_dependencies if @development && spec.respond_to?(:fetch_development_dependencies)
- ##
- # Returns the gems in +specs+ that match the local platform.
+ deps = {}
+ root_names = @needed.map(&:name)
- def select_local_platforms(specs) # :nodoc:
- specs.select do |spec|
- Gem::Platform.installable? spec
+ spec.dependencies.each do |d|
+ next if d.name == package.to_s
+ next if d.type == :development && !@development
+ next if d.type == :development && @development_shallow && !root_names.include?(package.to_s)
+
+ dep_package = package_for(d.name)
+
+ # In force mode, skip deps that can't be satisfied - either no
+ # specs at all, or no specs matching the version requirement.
+ if @soft_missing
+ dep_specs = @all_specs[d.name]
+ matching = dep_specs.select {|s| d.requirement.satisfied_by?(s.version) }
+ next if matching.empty?
+ end
+
+ deps[d.name] = Gem::PubGrub::RubyGems.requirement_to_constraint(dep_package, d.requirement)
end
+
+ deps
end
- def search_for(dependency)
- possibles, all = find_possible(dependency)
- if !@soft_missing && possibles.empty?
- exc = Gem::UnsatisfiableDependencyError.new dependency, all
- exc.errors = @set.errors
- raise exc
- end
+ def build_extended_explanation(name, constraint)
+ unfiltered = @unfiltered_specs[name]
+ return if unfiltered.empty?
+
+ filtered = @all_specs[name]
+ pkg = package_for(name)
- groups = Hash.new {|hash, key| hash[key] = [] }
+ # A prerelease hint applies when the source would strip prereleases for
+ # this constraint (global prerelease flag off and the constraint's range
+ # doesn't itself reach into prerelease territory) AND a prerelease of
+ # the gem exists somewhere.
+ prerelease_gated = !(@set.respond_to?(:prerelease) && @set.prerelease) &&
+ !range_admits_prerelease?(constraint.range)
+ has_prerelease_candidate = prerelease_gated &&
+ @all_versions[pkg].any?(&:prerelease?)
- # create groups & sources in the same loop
- sources = possibles.map do |spec|
- source = spec.source
- groups[source] << spec
- source
- end.uniq.reverse
+ return if filtered.length == unfiltered.length && !has_prerelease_candidate
- activation_requests = []
+ hints = []
- sources.each do |source|
- groups[source].
- sort_by {|spec| [spec.version, -Gem::Platform.platform_specificity_match(spec.platform, Gem::Platform.local)] }.
- map {|spec| ActivationRequest.new spec, dependency }.
- each {|activation_request| activation_requests << activation_request }
+ # Check for specs that exist for other platforms
+ platform_specs = unfiltered.select do |s|
+ !Gem::Platform.installable?(s) && constraint.range.include?(s.version)
+ end
+ if platform_specs.any?
+ label = "#{name} (#{constraint.constraint_string})"
+ hints << "The source contains the following gems matching '#{label}':"
+ platform_specs.each do |s|
+ actual = s.respond_to?(:spec) ? s.spec : s
+ hints << " * #{actual.full_name}"
+ end
end
- activation_requests
- end
+ # Check for specs filtered by Ruby version
+ installable = select_local_platforms(unfiltered)
+ ruby_specs = installable.select do |s|
+ actual = s.respond_to?(:spec) ? s.spec : s
+ constraint.range.include?(s.version) &&
+ !actual.required_ruby_version.satisfied_by?(Gem.ruby_version)
+ rescue StandardError
+ false
+ end
+ if ruby_specs.any?
+ versions = ruby_specs.map(&:version).uniq.sort.reverse.first(3)
+ sample = ruby_specs.find {|s| s.version == versions.first }
+ actual = sample.respond_to?(:spec) ? sample.spec : sample
+ ruby_req = actual.required_ruby_version
+ hints << "#{name} #{versions.join(", ")} requires Ruby #{ruby_req} (you have #{Gem.ruby_version})"
+ end
+
+ # Check for specs filtered by prerelease status
+ if prerelease_gated
+ prerelease_versions = @all_versions[pkg].select(&:prerelease?)
+ if prerelease_versions.any?
+ versions = prerelease_versions.sort.reverse.first(3) # limit to avoid cluttering error output
+ hints << "#{name} #{versions.join(", ")} are pre-release versions. Use --prerelease to allow pre-release gems."
+ end
+ end
- def dependencies_for(specification)
- return [] if @ignore_dependencies
- spec = specification.spec
- requests(spec, specification)
+ hints.empty? ? nil : hints.join("\n")
end
- def requirement_satisfied_by?(requirement, activated, spec)
- matches_spec = requirement.matches_spec? spec
- return matches_spec if @soft_missing
+ def extract_extended_explanation(incompatibility)
+ while incompatibility.cause.is_a?(Gem::PubGrub::Incompatibility::ConflictCause)
+ cause = incompatibility.cause
- matches_spec &&
- spec.spec.required_ruby_version.satisfied_by?(Gem.ruby_version) &&
- spec.spec.required_rubygems_version.satisfied_by?(Gem.rubygems_version)
- end
+ [cause.conflict, cause.other].each do |incompat|
+ if incompat.cause.is_a?(Gem::PubGrub::Incompatibility::NoVersions) &&
+ incompat.respond_to?(:extended_explanation) &&
+ incompat.extended_explanation
+ return incompat.extended_explanation
+ end
+ end
+
+ incompatibility = cause.conflict
+ end
- def name_for(dependency)
- dependency.name
+ nil
end
- def allow_missing?(dependency)
- @soft_missing
+ def make_logger
+ DEBUG_RESOLVER ? Gem::PubGrub::StderrLogger.new : Gem::PubGrub::NullLogger.new
end
- def sort_dependencies(dependencies, activated, conflicts)
- dependencies.sort_by.with_index do |dependency, i|
- name = name_for(dependency)
- [
- activated.vertex_named(name).payload ? 0 : 1,
- amount_constrained(dependency),
- conflicts[name] ? 0 : 1,
- activated.vertex_named(name).payload ? 0 : search_for(dependency).count,
- i, # for stable sort
- ]
+ # Custom root package so error messages say "your request depends on..."
+ # instead of PubGrub's default "root depends on...".
+ class RootPackage < Gem::PubGrub::Package
+ def initialize
+ super(:root)
end
- end
- SINGLE_POSSIBILITY_CONSTRAINT_PENALTY = 1_000_000
- private_constant :SINGLE_POSSIBILITY_CONSTRAINT_PENALTY if defined?(private_constant)
+ def root?
+ true
+ end
- # returns an integer \in (-\infty, 0]
- # a number closer to 0 means the dependency is less constraining
- #
- # dependencies w/ 0 or 1 possibilities (ignoring version requirements)
- # are given very negative values, so they _always_ sort first,
- # before dependencies that are unconstrained
- def amount_constrained(dependency)
- @amount_constrained ||= {}
- @amount_constrained[dependency.name] ||= begin
- name_dependency = Gem::Dependency.new(dependency.name)
- dependency_request_for_name = Gem::Resolver::DependencyRequest.new(name_dependency, dependency.requester)
- all = @set.find_all(dependency_request_for_name).size
-
- if all <= 1
- all - SINGLE_POSSIBILITY_CONSTRAINT_PENALTY
- else
- search = search_for(dependency).size
- search - all
- end
+ def to_s
+ "your request"
end
end
- private :amount_constrained
end
require_relative "resolver/activation_request"
-require_relative "resolver/conflict"
require_relative "resolver/dependency_request"
+require_relative "resolver/incompatibility"
+require_relative "resolver/strategy"
require_relative "resolver/requirement_list"
-require_relative "resolver/stats"
-
require_relative "resolver/set"
require_relative "resolver/api_set"
require_relative "resolver/composed_set"
diff --git a/lib/rubygems/resolver/api_set.rb b/lib/rubygems/resolver/api_set.rb
index 9f6695a6a9..3f443519d8 100644
--- a/lib/rubygems/resolver/api_set.rb
+++ b/lib/rubygems/resolver/api_set.rb
@@ -1,14 +1,14 @@
# frozen_string_literal: true
##
-# The global rubygems pool, available via the rubygems.org API.
+# The global rubygems pool, available via the Compact Index API.
# Returns instances of APISpecification.
class Gem::Resolver::APISet < Gem::Resolver::Set
autoload :GemParser, File.expand_path("api_set/gem_parser", __dir__)
##
- # The URI for the dependency API this APISet uses.
+ # The URI for the Compact Index API this APISet uses.
attr_reader :dep_uri # :nodoc:
@@ -23,9 +23,9 @@ class Gem::Resolver::APISet < Gem::Resolver::Set
attr_reader :uri
##
- # Creates a new APISet that will retrieve gems from +uri+ using the RubyGems
- # API URL +dep_uri+ which is described at
- # https://guides.rubygems.org/rubygems-org-api
+ # Creates a new APISet that will retrieve gems from +uri+ using the Compact
+ # Index API URL +dep_uri+ which is described at
+ # https://guides.rubygems.org/rubygems-org-compact-index-api
def initialize(dep_uri = "https://index.rubygems.org/info/")
super()
diff --git a/lib/rubygems/resolver/api_set/gem_parser.rb b/lib/rubygems/resolver/api_set/gem_parser.rb
index 7dd9a89ebc..4d827f4980 100644
--- a/lib/rubygems/resolver/api_set/gem_parser.rb
+++ b/lib/rubygems/resolver/api_set/gem_parser.rb
@@ -13,7 +13,7 @@ class Gem::Resolver::APISet::GemParser
private
def parse_dependency(string)
- dependency = string.split(":")
+ dependency = string.split(":", 2)
dependency[-1] = dependency[-1].split("&") if dependency.size > 1
dependency[0] = -dependency[0]
dependency
diff --git a/lib/rubygems/resolver/api_specification.rb b/lib/rubygems/resolver/api_specification.rb
index a14bcbfeb1..ccfd6fe084 100644
--- a/lib/rubygems/resolver/api_specification.rb
+++ b/lib/rubygems/resolver/api_specification.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
##
-# Represents a specification retrieved via the rubygems.org API.
+# Represents a specification retrieved via the Compact Index API.
#
# This is used to avoid loading the full Specification object when all we need
# is the name, version, and dependencies.
@@ -19,10 +19,10 @@ class Gem::Resolver::APISpecification < Gem::Resolver::Specification
end
##
- # Creates an APISpecification for the given +set+ from the rubygems.org
+ # Creates an APISpecification for the given +set+ from the Compact Index API
# +api_data+.
#
- # See https://guides.rubygems.org/rubygems-org-api/#misc-methods for the
+ # See https://guides.rubygems.org/rubygems-org-compact-index-api for the
# format of the +api_data+.
def initialize(set, api_data)
diff --git a/lib/rubygems/resolver/conflict.rb b/lib/rubygems/resolver/conflict.rb
deleted file mode 100644
index 77c3add4b3..0000000000
--- a/lib/rubygems/resolver/conflict.rb
+++ /dev/null
@@ -1,146 +0,0 @@
-# frozen_string_literal: true
-
-##
-# Used internally to indicate that a dependency conflicted
-# with a spec that would be activated.
-
-class Gem::Resolver::Conflict
- ##
- # The specification that was activated prior to the conflict
-
- attr_reader :activated
-
- ##
- # The dependency that is in conflict with the activated gem.
-
- attr_reader :dependency
-
- attr_reader :failed_dep # :nodoc:
-
- ##
- # Creates a new resolver conflict when +dependency+ is in conflict with an
- # already +activated+ specification.
-
- def initialize(dependency, activated, failed_dep = dependency)
- @dependency = dependency
- @activated = activated
- @failed_dep = failed_dep
- end
-
- def ==(other) # :nodoc:
- self.class === other &&
- @dependency == other.dependency &&
- @activated == other.activated &&
- @failed_dep == other.failed_dep
- end
-
- ##
- # A string explanation of the conflict.
-
- def explain
- "<Conflict wanted: #{@failed_dep}, had: #{activated.spec.full_name}>"
- end
-
- ##
- # Return the 2 dependency objects that conflicted
-
- def conflicting_dependencies
- [@failed_dep.dependency, @activated.request.dependency]
- end
-
- ##
- # Explanation of the conflict used by exceptions to print useful messages
-
- def explanation
- activated = @activated.spec.full_name
- dependency = @failed_dep.dependency
- requirement = dependency.requirement
- alternates = dependency.matching_specs.map(&:full_name)
-
- unless alternates.empty?
- matching = <<-MATCHING.chomp
-
- Gems matching %s:
- %s
- MATCHING
-
- matching = format(matching, dependency, alternates.join(", "))
- end
-
- explanation = <<-EXPLANATION
- Activated %s
- which does not match conflicting dependency (%s)
-
- Conflicting dependency chains:
- %s
-
- versus:
- %s
-%s
- EXPLANATION
-
- format(explanation, activated, requirement, request_path(@activated).reverse.join(", depends on\n "), request_path(@failed_dep).reverse.join(", depends on\n "), matching)
- end
-
- ##
- # Returns true if the conflicting dependency's name matches +spec+.
-
- def for_spec?(spec)
- @dependency.name == spec.name
- end
-
- def pretty_print(q) # :nodoc:
- q.group 2, "[Dependency conflict: ", "]" do
- q.breakable
-
- q.text "activated "
- q.pp @activated
-
- q.breakable
- q.text " dependency "
- q.pp @dependency
-
- q.breakable
- if @dependency == @failed_dep
- q.text " failed"
- else
- q.text " failed dependency "
- q.pp @failed_dep
- end
- end
- end
-
- ##
- # Path of activations from the +current+ list.
-
- def request_path(current)
- path = []
-
- while current do
- case current
- when Gem::Resolver::ActivationRequest then
- path <<
- "#{current.request.dependency}, #{current.spec.version} activated"
-
- current = current.parent
- when Gem::Resolver::DependencyRequest then
- path << current.dependency.to_s
-
- current = current.requester
- else
- raise Gem::Exception, "[BUG] unknown request class #{current.class}"
- end
- end
-
- path = ["user request (gem command or Gemfile)"] if path.empty?
-
- path
- end
-
- ##
- # Return the Specification that listed the dependency
-
- def requester
- @failed_dep.requester
- end
-end
diff --git a/lib/rubygems/resolver/incompatibility.rb b/lib/rubygems/resolver/incompatibility.rb
new file mode 100644
index 0000000000..57a60affb4
--- /dev/null
+++ b/lib/rubygems/resolver/incompatibility.rb
@@ -0,0 +1,10 @@
+# frozen_string_literal: true
+
+class Gem::Resolver::Incompatibility < Gem::PubGrub::Incompatibility
+ attr_reader :extended_explanation
+
+ def initialize(terms, cause:, custom_explanation: nil, extended_explanation: nil)
+ @extended_explanation = extended_explanation
+ super(terms, cause: cause, custom_explanation: custom_explanation)
+ end
+end
diff --git a/lib/rubygems/resolver/installer_set.rb b/lib/rubygems/resolver/installer_set.rb
index d9fe36c589..42ce0890e2 100644
--- a/lib/rubygems/resolver/installer_set.rb
+++ b/lib/rubygems/resolver/installer_set.rb
@@ -160,7 +160,7 @@ class Gem::Resolver::InstallerSet < Gem::Resolver::Set
res.concat matching_local
begin
- if local_spec = @local_source.find_gem(name, dep.requirement)
+ @local_source.find_all_gems(name, dep.requirement).each do |local_spec|
res << Gem::Resolver::IndexSpecification.new(
self, local_spec.name, local_spec.version,
@local_source, local_spec.platform
diff --git a/lib/rubygems/resolver/stats.rb b/lib/rubygems/resolver/stats.rb
deleted file mode 100644
index 9920976b2a..0000000000
--- a/lib/rubygems/resolver/stats.rb
+++ /dev/null
@@ -1,46 +0,0 @@
-# frozen_string_literal: true
-
-class Gem::Resolver::Stats
- def initialize
- @max_depth = 0
- @max_requirements = 0
- @requirements = 0
- @backtracking = 0
- @iterations = 0
- end
-
- def record_depth(stack)
- if stack.size > @max_depth
- @max_depth = stack.size
- end
- end
-
- def record_requirements(reqs)
- if reqs.size > @max_requirements
- @max_requirements = reqs.size
- end
- end
-
- def requirement!
- @requirements += 1
- end
-
- def backtracking!
- @backtracking += 1
- end
-
- def iteration!
- @iterations += 1
- end
-
- PATTERN = "%20s: %d\n"
-
- def display
- $stdout.puts "=== Resolver Statistics ==="
- $stdout.printf PATTERN, "Max Depth", @max_depth
- $stdout.printf PATTERN, "Total Requirements", @requirements
- $stdout.printf PATTERN, "Max Requirements", @max_requirements
- $stdout.printf PATTERN, "Backtracking #", @backtracking
- $stdout.printf PATTERN, "Iteration #", @iterations
- end
-end
diff --git a/lib/rubygems/resolver/strategy.rb b/lib/rubygems/resolver/strategy.rb
new file mode 100644
index 0000000000..bf0dbb6adc
--- /dev/null
+++ b/lib/rubygems/resolver/strategy.rb
@@ -0,0 +1,44 @@
+# frozen_string_literal: true
+
+# Custom PubGrub strategy with caching for version selection.
+# Modeled after Bundler's strategy to avoid redundant versions_for
+# calls during the solver's package selection loop.
+
+class Gem::Resolver::Strategy
+ def initialize(source)
+ @source = source
+ @package_priority_cache = Hash.new {|h, pkg| h[pkg] = {} }
+
+ @version_indexes = Hash.new do |h, k|
+ if Gem::PubGrub::Package.root?(k)
+ h[k] = { Gem::PubGrub::Package.root_version => 0 }
+ else
+ h[k] = @source.all_versions_for(k).each.with_index.to_h
+ end
+ end
+ end
+
+ def next_package_and_version(unsatisfied)
+ package, range = next_term_to_try_from(unsatisfied)
+ [package, most_preferred_version_of(package, range)]
+ end
+
+ private
+
+ def most_preferred_version_of(package, range)
+ versions = @source.versions_for(package, range)
+ indexes = @version_indexes[package]
+ versions.min_by {|version| indexes[version] || Float::INFINITY }
+ end
+
+ def next_term_to_try_from(unsatisfied)
+ unsatisfied.min_by do |package, range|
+ @package_priority_cache[package][range] ||= begin
+ matching_versions = @source.versions_for(package, range)
+ higher_versions = @source.versions_for(package, range.upper_invert)
+
+ [matching_versions.count <= 1 ? 0 : 1, higher_versions.count]
+ end
+ end
+ end
+end
diff --git a/lib/rubygems/safe_marshal.rb b/lib/rubygems/safe_marshal.rb
index b81d1a0a47..871f24727d 100644
--- a/lib/rubygems/safe_marshal.rb
+++ b/lib/rubygems/safe_marshal.rb
@@ -54,6 +54,7 @@ module Gem
"Gem::NameTuple" => %w[@name @version @platform],
"Gem::Platform" => %w[@os @cpu @version],
"Psych::PrivateType" => %w[@value @type_id],
+ "YAML::PrivateType" => %w[@value @type_id],
}.freeze
private_constant :PERMITTED_IVARS
diff --git a/lib/rubygems/safe_yaml.rb b/lib/rubygems/safe_yaml.rb
index 6a02a48230..f4bba00136 100644
--- a/lib/rubygems/safe_yaml.rb
+++ b/lib/rubygems/safe_yaml.rb
@@ -35,11 +35,21 @@ module Gem
end
def self.safe_load(input)
- ::Psych.safe_load(input, permitted_classes: PERMITTED_CLASSES, permitted_symbols: PERMITTED_SYMBOLS, aliases: @aliases_enabled)
+ if Gem.use_psych?
+ ::Psych.safe_load(input, permitted_classes: PERMITTED_CLASSES,
+ permitted_symbols: PERMITTED_SYMBOLS, aliases: @aliases_enabled)
+ else
+ Gem::YAMLSerializer.load(
+ input,
+ permitted_classes: PERMITTED_CLASSES,
+ permitted_symbols: PERMITTED_SYMBOLS,
+ aliases: aliases_enabled?
+ )
+ end
end
- def self.load(input)
- ::Psych.safe_load(input, permitted_classes: [::Symbol])
+ class << self
+ alias_method :load, :safe_load
end
end
end
diff --git a/lib/rubygems/security/policy.rb b/lib/rubygems/security/policy.rb
index 7b86ac5763..128958ab80 100644
--- a/lib/rubygems/security/policy.rb
+++ b/lib/rubygems/security/policy.rb
@@ -143,7 +143,7 @@ class Gem::Security::Policy
end
##
- # Ensures the root of +chain+ has a trusted certificate in +trust_dir+ and
+ # Ensures the root of +chain+ has a trusted certificate in Gem::Security.trust_dir and
# the digests of the two certificates match according to +digester+
def check_trust(chain, digester, trust_dir)
diff --git a/lib/rubygems/security/signer.rb b/lib/rubygems/security/signer.rb
index 5732fb57fd..eeeeb52906 100644
--- a/lib/rubygems/security/signer.rb
+++ b/lib/rubygems/security/signer.rb
@@ -52,7 +52,7 @@ class Gem::Security::Signer
re_signed_cert = Gem::Security.re_sign(
expired_cert,
private_key,
- (Gem::Security::ONE_DAY * Gem.configuration.cert_expiration_length_days)
+ Gem::Security::ONE_DAY * Gem.configuration.cert_expiration_length_days
)
Gem::Security.write(re_signed_cert, expired_cert_path)
diff --git a/lib/rubygems/source.rb b/lib/rubygems/source.rb
index 8b031e27a8..86717e3e71 100644
--- a/lib/rubygems/source.rb
+++ b/lib/rubygems/source.rb
@@ -5,7 +5,7 @@ require_relative "text"
# A Source knows how to list and fetch gems from a RubyGems marshal index.
#
# There are other Source subclasses for installed gems, local gems, the
-# bundler dependency API and so-forth.
+# Compact Index API and so-forth.
class Gem::Source
include Comparable
@@ -102,7 +102,7 @@ class Gem::Source
end
##
- # Fetches a specification for the given +name_tuple+.
+ # Fetches a specification for the given Gem::NameTuple.
def fetch_spec(name_tuple)
fetcher = Gem::RemoteFetcher.fetcher
diff --git a/lib/rubygems/source/local.rb b/lib/rubygems/source/local.rb
index ba6eea1f9a..4bef31a265 100644
--- a/lib/rubygems/source/local.rb
+++ b/lib/rubygems/source/local.rb
@@ -76,6 +76,10 @@ class Gem::Source::Local < Gem::Source
end
def find_gem(gem_name, version = Gem::Requirement.default, prerelease = false) # :nodoc:
+ find_all_gems(gem_name, version, prerelease).max_by(&:version)
+ end
+
+ def find_all_gems(gem_name, version = Gem::Requirement.default, prerelease = false) # :nodoc:
load_specs :complete
found = []
@@ -93,7 +97,7 @@ class Gem::Source::Local < Gem::Source
end
end
- found.max_by(&:version)
+ found
end
def fetch_spec(name) # :nodoc:
diff --git a/lib/rubygems/source_list.rb b/lib/rubygems/source_list.rb
index 33db64fbc1..19bf4595c4 100644
--- a/lib/rubygems/source_list.rb
+++ b/lib/rubygems/source_list.rb
@@ -60,6 +60,42 @@ class Gem::SourceList
end
##
+ # Prepends +obj+ to the beginning of the source list which may be a Gem::Source, Gem::URI or URI
+ # Moves +obj+ to the beginning of the list if already present.
+ # String.
+
+ def prepend(obj)
+ src = case obj
+ when Gem::Source
+ obj
+ else
+ Gem::Source.new(obj)
+ end
+
+ @sources.delete(src) if @sources.include?(src)
+ @sources.unshift(src)
+ src
+ end
+
+ ##
+ # Appends +obj+ to the end of the source list, moving it if already present.
+ # +obj+ may be a Gem::Source, Gem::URI or URI String.
+ # Moves +obj+ to the end of the list if already present.
+
+ def append(obj)
+ src = case obj
+ when Gem::Source
+ obj
+ else
+ Gem::Source.new(obj)
+ end
+
+ @sources.delete(src) if @sources.include?(src)
+ @sources << src
+ src
+ end
+
+ ##
# Replaces this SourceList with the sources in +other+ See #<< for
# acceptable items in +other+.
diff --git a/lib/rubygems/specification.rb b/lib/rubygems/specification.rb
index 1d351f8aff..51729d755b 100644
--- a/lib/rubygems/specification.rb
+++ b/lib/rubygems/specification.rb
@@ -7,12 +7,10 @@
# See LICENSE.txt for permissions.
#++
-require_relative "deprecate"
require_relative "basic_specification"
require_relative "stub_specification"
require_relative "platform"
require_relative "specification_record"
-require_relative "util/list"
require "rbconfig"
@@ -36,10 +34,17 @@ require "rbconfig"
# Starting in RubyGems 2.0, a Specification can hold arbitrary
# metadata. See #metadata for restrictions on the format and size of metadata
# items you may add to a specification.
+#
+# Specifications must be deterministic, as in the example above. For instance,
+# you cannot define attributes conditionally:
+#
+# # INVALID: do not do this.
+# unless RUBY_ENGINE == "jruby"
+# s.extensions << "ext/example/extconf.rb"
+# end
+#
class Gem::Specification < Gem::BasicSpecification
- extend Gem::Deprecate
-
# REFACTOR: Consider breaking out this version stuff into a separate
# module. There's enough special stuff around it that it may justify
# a separate class.
@@ -488,8 +493,6 @@ class Gem::Specification < Gem::BasicSpecification
end
@platform = @new_platform.to_s
-
- invalidate_memoized_attributes
end
##
@@ -738,14 +741,6 @@ class Gem::Specification < Gem::BasicSpecification
attr_accessor :autorequire # :nodoc:
##
- # Sets the default executable for this gem.
- #
- # Deprecated: You must now specify the executable name to Gem.bin_path.
-
- attr_writer :default_executable
- rubygems_deprecate :default_executable=
-
- ##
# Allows deinstallation of gems with legacy platforms.
attr_writer :original_platform # :nodoc:
@@ -974,6 +969,15 @@ class Gem::Specification < Gem::BasicSpecification
##
# Return the best specification that contains the file matching +path+
+ # amongst the specs that are not loaded. This method is different than
+ # +find_inactive_by_path+ as it will filter out loaded specs by their name.
+
+ def self.find_unloaded_by_path(path)
+ specification_record.find_unloaded_by_path(path)
+ end
+
+ ##
+ # Return the best specification that contains the file matching +path+
# amongst the specs that are not activated.
def self.find_inactive_by_path(path)
@@ -1271,7 +1275,7 @@ class Gem::Specification < Gem::BasicSpecification
raise unless message.include?("YAML::")
unless Object.const_defined?(:YAML)
- Object.const_set "YAML", Psych
+ Object.const_set "YAML", Module.new
yaml_set = true
end
@@ -1280,7 +1284,7 @@ class Gem::Specification < Gem::BasicSpecification
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.const_set "PrivateType", Class.new
+ YAML.const_set "PrivateType", Class.new { attr_accessor :type_id, :value }
end
retry_count += 1
@@ -1321,7 +1325,7 @@ class Gem::Specification < Gem::BasicSpecification
spec.instance_variable_set :@authors, array[12]
spec.instance_variable_set :@description, array[13]
spec.instance_variable_set :@homepage, array[14]
- spec.instance_variable_set :@has_rdoc, array[15]
+ # offset due to has_rdoc removal
spec.instance_variable_set :@licenses, array[17]
spec.instance_variable_set :@metadata, array[18]
spec.instance_variable_set :@loaded, false
@@ -1620,14 +1624,14 @@ class Gem::Specification < Gem::BasicSpecification
# spec's cached gem.
def cache_dir
- @cache_dir ||= File.join base_dir, "cache"
+ File.join base_dir, "cache"
end
##
# Returns the full path to the cached gem for this spec.
def cache_file
- @cache_file ||= File.join cache_dir, "#{full_name}.gem"
+ File.join cache_dir, "#{full_name}.gem"
end
##
@@ -1717,24 +1721,6 @@ class Gem::Specification < Gem::BasicSpecification
end
##
- # The default executable for this gem.
- #
- # Deprecated: The name of the gem is assumed to be the name of the
- # executable now. See Gem.bin_path.
-
- def default_executable # :nodoc:
- if defined?(@default_executable) && @default_executable
- result = @default_executable
- elsif @executables && @executables.size == 1
- result = Array(@executables).first
- else
- result = nil
- end
- result
- end
- rubygems_deprecate :default_executable
-
- ##
# The default value for specification attribute +name+
def default_value(name)
@@ -1903,10 +1889,6 @@ class Gem::Specification < Gem::BasicSpecification
spec
end
- def full_name
- @full_name ||= super
- end
-
##
# Work around old bundler versions removing my methods
# Can be removed once RubyGems can no longer install Bundler 2.5
@@ -1920,29 +1902,6 @@ class Gem::Specification < Gem::BasicSpecification
end
##
- # Deprecated and ignored, defaults to true.
- #
- # Formerly used to indicate this gem was RDoc-capable.
-
- def has_rdoc # :nodoc:
- true
- end
- rubygems_deprecate :has_rdoc
-
- ##
- # Deprecated and ignored.
- #
- # Formerly used to indicate this gem was RDoc-capable.
-
- def has_rdoc=(ignored) # :nodoc:
- @has_rdoc = true
- end
- rubygems_deprecate :has_rdoc=
-
- alias_method :has_rdoc?, :has_rdoc # :nodoc:
- rubygems_deprecate :has_rdoc?
-
- ##
# True if this gem has files in test_files
def has_unit_tests? # :nodoc:
@@ -2044,17 +2003,6 @@ class Gem::Specification < Gem::BasicSpecification
end
end
- ##
- # Expire memoized instance variables that can incorrectly generate, replace
- # or miss files due changes in certain attributes used to compute them.
-
- def invalidate_memoized_attributes
- @full_name = nil
- @cache_file = nil
- end
-
- private :invalidate_memoized_attributes
-
def inspect # :nodoc:
if $DEBUG
super
@@ -2093,8 +2041,6 @@ class Gem::Specification < Gem::BasicSpecification
def internal_init # :nodoc:
super
@bin_dir = nil
- @cache_dir = nil
- @cache_file = nil
@doc_dir = nil
@ri_dir = nil
@spec_dir = nil
@@ -2124,6 +2070,7 @@ class Gem::Specification < Gem::BasicSpecification
# probably want to build_extensions
def missing_extensions?
+ return false if RUBY_ENGINE == "jruby"
return false if extensions.empty?
return false if default_gem?
return false if File.exist? gem_build_complete_path
@@ -2244,10 +2191,13 @@ class Gem::Specification < Gem::BasicSpecification
end
##
- # Sets rdoc_options to +value+, ensuring it is an array.
+ # Sets rdoc_options to +value+, ensuring it is a flat array of strings.
+ # Handles malformed gemspecs where rdoc_options may be a Hash or contain Hashes.
def rdoc_options=(options)
- @rdoc_options = Array options
+ @rdoc_options = Array(options).flat_map do |opt|
+ opt.is_a?(Hash) ? opt.to_a.flatten.map(&:to_s) : opt
+ end
end
##
@@ -2447,8 +2397,6 @@ class Gem::Specification < Gem::BasicSpecification
:required_rubygems_version,
:specification_version,
:version,
- :has_rdoc,
- :default_executable,
:metadata,
:signing_key,
]
@@ -2511,24 +2459,28 @@ class Gem::Specification < Gem::BasicSpecification
def to_yaml(opts = {}) # :nodoc:
Gem.load_yaml
- # Because the user can switch the YAML engine behind our
- # back, we have to check again here to make sure that our
- # psych code was properly loaded, and load it if not.
- unless Gem.const_defined?(:NoAliasYAMLTree)
- require_relative "psych_tree"
- end
+ if Gem.use_psych?
+ # Because the user can switch the YAML engine behind our
+ # back, we have to check again here to make sure that our
+ # psych code was properly loaded, and load it if not.
+ unless Gem.const_defined?(:NoAliasYAMLTree)
+ require_relative "psych_tree"
+ end
- builder = Gem::NoAliasYAMLTree.create
- builder << self
- ast = builder.tree
+ builder = Gem::NoAliasYAMLTree.create
+ builder << self
+ ast = builder.tree
- require "stringio"
- io = StringIO.new
- io.set_encoding Encoding::UTF_8
+ require "stringio"
+ io = StringIO.new
+ io.set_encoding Encoding::UTF_8
- Psych::Visitors::Emitter.new(io).accept(ast)
+ Psych::Visitors::Emitter.new(io).accept(ast)
- io.string.gsub(/ !!null \n/, " \n")
+ io.string.gsub(/ !!null \n/, " \n")
+ else
+ Gem::YAMLSerializer.dump(self)
+ end
end
##
@@ -2586,29 +2538,11 @@ class Gem::Specification < Gem::BasicSpecification
Gem::SpecificationPolicy.new(self).validate_for_resolution
end
- def validate_metadata
- Gem::SpecificationPolicy.new(self).validate_metadata
- end
- rubygems_deprecate :validate_metadata
-
- def validate_dependencies
- Gem::SpecificationPolicy.new(self).validate_dependencies
- end
- rubygems_deprecate :validate_dependencies
-
- def validate_permissions
- Gem::SpecificationPolicy.new(self).validate_permissions
- end
- rubygems_deprecate :validate_permissions
-
##
# Set the version to +version+.
def version=(version)
- @version = Gem::Version.create(version)
- return if @version.nil?
-
- invalidate_memoized_attributes
+ @version = version.nil? ? version : Gem::Version.create(version)
end
def stubbed?
@@ -2623,6 +2557,10 @@ class Gem::Specification < Gem::BasicSpecification
self.date = val
when "platform"
self.platform = val
+ when "rdoc_options"
+ self.rdoc_options = val
+ when "requirements"
+ self.requirements = val
else
instance_variable_set "@#{ivar}", val
end
diff --git a/lib/rubygems/specification_policy.rb b/lib/rubygems/specification_policy.rb
index d79ee7df92..478e294e09 100644
--- a/lib/rubygems/specification_policy.rb
+++ b/lib/rubygems/specification_policy.rb
@@ -190,53 +190,16 @@ duplicate dependency on #{dep}, (#{prev.requirement}) use:
##
# Checks that the gem does not depend on itself.
- # Checks that dependencies use requirements as we recommend. Warnings are
- # issued when dependencies are open-ended or overly strict for semantic
- # versioning.
def validate_dependencies # :nodoc:
- warning_messages = []
+ error_messages = []
@specification.dependencies.each do |dep|
- if dep.name == @specification.name # warn on self reference
- warning_messages << "Self referencing dependency is unnecessary and strongly discouraged."
- end
-
- prerelease_dep = dep.requirements_list.any? do |req|
- Gem::Requirement.new(req).prerelease?
- end
-
- warning_messages << "prerelease dependency on #{dep} is not recommended" if
- prerelease_dep && !@specification.version.prerelease?
-
- open_ended = dep.requirement.requirements.all? do |op, version|
- !version.prerelease? && [">", ">="].include?(op)
+ if dep.name == @specification.name # error on self reference
+ error_messages << "Dependencies of this gem include a self-reference."
end
-
- next unless open_ended
- op, dep_version = dep.requirement.requirements.first
-
- segments = dep_version.segments
-
- 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}\""
- end
-
- " if #{dep.name} is semantically versioned, use:\n" \
- " add_#{dep.type}_dependency \"#{dep.name}\", \"~> #{base.join "."}\"#{bugfix}"
- 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
+
+ error error_messages.join if error_messages.any?
end
def validate_required_ruby_version
@@ -472,6 +435,7 @@ or set it to nil if you don't want to specify a license.
warning "deprecated autorequire specified" if @specification.autorequire
@specification.executables.each do |executable|
+ validate_executable(executable)
validate_shebang_line_in(executable)
end
@@ -485,6 +449,13 @@ or set it to nil if you don't want to specify a license.
warning("no #{attribute} specified") if value.nil? || value.empty?
end
+ def validate_executable(executable)
+ separators = [File::SEPARATOR, File::ALT_SEPARATOR, File::PATH_SEPARATOR].compact.map {|sep| Regexp.escape(sep) }.join
+ return unless executable.match?(/[\s#{separators}]/)
+
+ error "executable \"#{executable}\" contains invalid characters"
+ end
+
def validate_shebang_line_in(executable)
executable_path = File.join(@specification.bindir, executable)
return if File.read(executable_path, 2) == "#!"
@@ -504,6 +475,7 @@ or set it to nil if you don't want to specify a license.
validate_rake_extensions(builder)
validate_rust_extensions(builder)
+ validate_extension_require_relative
end
def validate_rust_extensions(builder) # :nodoc:
@@ -524,6 +496,33 @@ You have specified rake based extension, but rake is not added as runtime depend
WARNING
end
+ def validate_extension_require_relative # :nodoc:
+ return unless @specification.extensions.any?
+
+ require_paths = @specification.require_paths
+
+ @specification.files.each do |rb_file|
+ next unless rb_file.end_with?(".rb")
+ next unless require_paths.any? {|rp| rb_file.start_with?("#{rp}/") }
+ next unless File.file?(rb_file)
+
+ File.foreach(rb_file).with_index(1) do |line, lineno|
+ next unless line =~ /^\s*require_relative\s+["']([^"']+)["']/
+
+ required_path = Regexp.last_match(1)
+ resolved = File.join(File.dirname(rb_file), required_path)
+
+ next if @specification.files.any? {|f| f == "#{resolved}.rb" || f == resolved }
+
+ warning <<~WARNING
+ #{rb_file}:#{lineno} uses `require_relative "#{required_path}"` to load a compiled extension.
+ This will break in RubyGems 4.2, which will stop copying compiled extensions into the gem's lib directory.
+ Use `require` instead of `require_relative` to load compiled extensions.
+ WARNING
+ end
+ end
+ end
+
def validate_unique_links
links = @specification.metadata.slice(*METADATA_LINK_KEYS)
grouped = links.group_by {|_key, uri| uri }
diff --git a/lib/rubygems/specification_record.rb b/lib/rubygems/specification_record.rb
index 195a355496..c7e5cbedb5 100644
--- a/lib/rubygems/specification_record.rb
+++ b/lib/rubygems/specification_record.rb
@@ -73,7 +73,7 @@ module Gem
end
##
- # Adds +spec+ to the the record, keeping the collection properly sorted.
+ # Adds +spec+ to the record, keeping the collection properly sorted.
def add_spec(spec)
return if all.include? spec
@@ -155,6 +155,19 @@ module Gem
end
##
+ # Return the best specification that contains the file matching +path+
+ # amongst the specs that are not loaded. This method is different than
+ # +find_inactive_by_path+ as it will filter out loaded specs by their name.
+
+ def find_unloaded_by_path(path)
+ stub = stubs.find do |s|
+ next if Gem.loaded_specs[s.name]
+ s.contains_requirable_file? path
+ end
+ stub&.to_spec
+ end
+
+ ##
# Return the best specification in the record that contains the file
# matching +path+ amongst the specs that are not activated.
diff --git a/lib/rubygems/stub_specification.rb b/lib/rubygems/stub_specification.rb
index 4f6a70ba4b..53b337ed85 100644
--- a/lib/rubygems/stub_specification.rb
+++ b/lib/rubygems/stub_specification.rb
@@ -140,6 +140,7 @@ class Gem::StubSpecification < Gem::BasicSpecification
end
def missing_extensions?
+ return false if RUBY_ENGINE == "jruby"
return false if default_gem?
return false if extensions.empty?
return false if File.exist? gem_build_complete_path
diff --git a/lib/rubygems/text.rb b/lib/rubygems/text.rb
index 88d4ce59b4..0550dc473d 100644
--- a/lib/rubygems/text.rb
+++ b/lib/rubygems/text.rb
@@ -8,7 +8,16 @@ module Gem::Text
# Remove any non-printable characters and make the text suitable for
# printing.
def clean_text(text)
- text.gsub(/[\000-\b\v-\f\016-\037\177]/, ".")
+ text = text.gsub(/[\000-\b\v-\f\016-\037\177]/, ".")
+
+ # Match C1 control characters (U+0080-U+009F) as codepoints. This requires
+ # a valid UTF-8 string so the regexp does not split a multibyte sequence;
+ # strings in other encodings are left unchanged.
+ if text.encoding == Encoding::UTF_8 && text.valid_encoding?
+ text = text.gsub(/[\u0080-\u009f]/, ".")
+ end
+
+ text
end
def truncate_text(text, description, max_length = 100_000)
diff --git a/lib/rubygems/uninstaller.rb b/lib/rubygems/uninstaller.rb
index 991bc6fb95..fe4c3a80cf 100644
--- a/lib/rubygems/uninstaller.rb
+++ b/lib/rubygems/uninstaller.rb
@@ -42,10 +42,25 @@ class Gem::Uninstaller
attr_reader :spec
##
- # Constructs an uninstaller that will uninstall +gem+
+ # Constructs an uninstaller that will uninstall gem named +gem+.
+ # +options+ is a Hash with the following keys:
+ #
+ # :version:: Version requirement for the gem to uninstall. If not specified,
+ # uses Gem::Requirement.default.
+ # :install_dir:: The directory where the gem is installed. If not specified,
+ # uses Gem.dir.
+ # :executables:: Whether executables should be removed without confirmation or not. If nil, asks the user explicitly.
+ # :all:: If more than one version matches the requirement, whether to forcefully remove all matching versions or ask the user to select specific matching versions that should be removed.
+ # :ignore:: Ignore broken dependency checks when uninstalling.
+ # :bin_dir:: Directory containing executables to remove. If not specified,
+ # uses Gem.bindir.
+ # :format_executable:: In order to find executables to be removed, format executable names using Gem::Installer.exec_format.
+ # :abort_on_dependent:: Directly abort uninstallation if dependencies would be broken, rather than asking the user for confirmation.
+ # :check_dev:: When checking if uninstalling gem would leave broken dependencies around, also consider development dependencies.
+ # :force:: Set both :all and :ignore to true for forced uninstallation.
+ # :user_install:: Uninstall from user gem directory instead of system directory.
def initialize(gem, options = {})
- # TODO: document the valid options
@gem = gem
@version = options[:version] || Gem::Requirement.default
@install_dir = options[:install_dir]
@@ -57,10 +72,6 @@ class Gem::Uninstaller
@bin_dir = options[:bin_dir]
@format_executable = options[:format_executable]
@abort_on_dependent = options[:abort_on_dependent]
-
- # Indicate if development dependencies should be checked when
- # uninstalling. (default: false)
- #
@check_dev = options[:check_dev]
if options[:force]
diff --git a/lib/rubygems/user_interaction.rb b/lib/rubygems/user_interaction.rb
index 5711376294..9fe3e755c4 100644
--- a/lib/rubygems/user_interaction.rb
+++ b/lib/rubygems/user_interaction.rb
@@ -6,7 +6,6 @@
# See LICENSE.txt for permissions.
#++
-require_relative "deprecate"
require_relative "text"
##
@@ -170,8 +169,6 @@ end
# Gem::StreamUI implements a simple stream based user interface.
class Gem::StreamUI
- extend Gem::Deprecate
-
##
# The input stream
diff --git a/lib/rubygems/util.rb b/lib/rubygems/util.rb
index 51f9c2029f..ee4106c6ce 100644
--- a/lib/rubygems/util.rb
+++ b/lib/rubygems/util.rb
@@ -1,7 +1,5 @@
# frozen_string_literal: true
-require_relative "deprecate"
-
##
# This module contains various utility methods as module methods.
@@ -57,26 +55,6 @@ module Gem::Util
end
##
- # Invokes system, but silences all output.
-
- def self.silent_system(*command)
- opt = { out: IO::NULL, err: [:child, :out] }
- if Hash === command.last
- opt.update(command.last)
- cmds = command[0...-1]
- else
- cmds = command.dup
- end
- system(*(cmds << opt))
- end
-
- class << self
- extend Gem::Deprecate
-
- rubygems_deprecate :silent_system
- end
-
- ##
# Enumerates the parents of +directory+.
def self.traverse_parents(directory, &block)
diff --git a/lib/rubygems/util/atomic_file_writer.rb b/lib/rubygems/util/atomic_file_writer.rb
new file mode 100644
index 0000000000..32767c6a79
--- /dev/null
+++ b/lib/rubygems/util/atomic_file_writer.rb
@@ -0,0 +1,76 @@
+# frozen_string_literal: true
+
+# Based on ActiveSupport's AtomicFile implementation
+# Copyright (c) David Heinemeier Hansson
+# https://github.com/rails/rails/blob/main/activesupport/lib/active_support/core_ext/file/atomic.rb
+# Licensed under the MIT License
+
+module Gem
+ class AtomicFileWriter
+ ##
+ # Write to a file atomically. Useful for situations where you don't
+ # want other processes or threads to see half-written files.
+
+ def self.open(file_name)
+ require "securerandom" unless defined?(SecureRandom)
+
+ old_stat = begin
+ File.stat(file_name)
+ rescue SystemCallError
+ nil
+ end
+
+ # Names can't be longer than 255B
+ tmp_suffix = ".tmp.#{SecureRandom.hex}"
+ dirname = File.dirname(file_name)
+ basename = File.basename(file_name)
+ tmp_path = File.join(dirname, ".#{basename.byteslice(0, 254 - tmp_suffix.bytesize)}#{tmp_suffix}")
+
+ flags = File::RDWR | File::CREAT | File::EXCL | File::BINARY
+ flags |= File::SHARE_DELETE if defined?(File::SHARE_DELETE)
+
+ File.open(tmp_path, flags) do |temp_file|
+ temp_file.binmode
+ if old_stat
+ # Set correct permissions on new file
+ begin
+ File.chown(old_stat.uid, old_stat.gid, temp_file.path)
+ # This operation will affect filesystem ACL's
+ File.chmod(old_stat.mode, temp_file.path)
+ rescue Errno::EPERM, Errno::EACCES
+ # Changing file ownership failed, moving on.
+ end
+ end
+
+ return_val = yield temp_file
+ rescue StandardError => error
+ begin
+ temp_file.close
+ rescue StandardError
+ nil
+ end
+
+ begin
+ File.unlink(temp_file.path)
+ rescue StandardError
+ nil
+ end
+
+ raise error
+ else
+ begin
+ File.rename(temp_file.path, file_name)
+ rescue StandardError
+ begin
+ File.unlink(temp_file.path)
+ rescue StandardError
+ end
+
+ raise
+ end
+
+ return_val
+ end
+ end
+ end
+end
diff --git a/lib/rubygems/util/licenses.rb b/lib/rubygems/util/licenses.rb
index fbb7b55075..caf53d0b7e 100644
--- a/lib/rubygems/util/licenses.rb
+++ b/lib/rubygems/util/licenses.rb
@@ -27,6 +27,7 @@ class Gem::Licenses
AGPL-1.0-or-later
AGPL-3.0-only
AGPL-3.0-or-later
+ ALGLIB-Documentation
AMD-newlib
AMDPLPA
AML
@@ -48,6 +49,7 @@ class Gem::Licenses
Adobe-Display-PostScript
Adobe-Glyph
Adobe-Utopia
+ Advanced-Cryptics-Dictionary
Afmparse
Aladdin
Apache-1.0
@@ -61,6 +63,7 @@ class Gem::Licenses
Artistic-2.0
Artistic-dist
Aspell-RU
+ BOLA-1.1
BSD-1-Clause
BSD-2-Clause
BSD-2-Clause-Darwin
@@ -80,6 +83,7 @@ class Gem::Licenses
BSD-3-Clause-No-Nuclear-Warranty
BSD-3-Clause-Open-MPI
BSD-3-Clause-Sun
+ BSD-3-Clause-Tso
BSD-3-Clause-acpica
BSD-3-Clause-flex
BSD-4-Clause
@@ -90,6 +94,7 @@ class Gem::Licenses
BSD-Advertising-Acknowledgement
BSD-Attribution-HPND-disclaimer
BSD-Inferno-Nettverk
+ BSD-Mark-Modifications
BSD-Protection
BSD-Source-Code
BSD-Source-beginning-file
@@ -111,9 +116,11 @@ class Gem::Licenses
Borceux
Brian-Gladman-2-Clause
Brian-Gladman-3-Clause
+ Buddy
C-UDA-1.0
CAL-1.0
CAL-1.0-Combined-Work-Exception
+ CAPEC-tou
CATOSL-1.1
CC-BY-1.0
CC-BY-2.0
@@ -231,6 +238,9 @@ class Gem::Licenses
EPICS
EPL-1.0
EPL-2.0
+ ESA-PL-permissive-2.4
+ ESA-PL-strong-copyleft-2.4
+ ESA-PL-weak-copyleft-2.4
EUDatagrid
EUPL-1.0
EUPL-1.1
@@ -304,6 +314,7 @@ class Gem::Licenses
HPND-Markus-Kuhn
HPND-Netrek
HPND-Pbmplus
+ HPND-SMC
HPND-UC
HPND-UC-export-US
HPND-doc
@@ -318,6 +329,7 @@ class Gem::Licenses
HPND-sell-variant
HPND-sell-variant-MIT-disclaimer
HPND-sell-variant-MIT-disclaimer-rev
+ HPND-sell-variant-critical-systems
HTMLTIDY
HaskellReport
Hippocratic-2.1
@@ -330,6 +342,7 @@ class Gem::Licenses
IPL-1.0
ISC
ISC-Veillard
+ ISO-permission
ImageMagick
Imlib2
Info-ZIP
@@ -387,6 +400,7 @@ class Gem::Licenses
MIT-Festival
MIT-Khronos-old
MIT-Modern-Variant
+ MIT-STK
MIT-Wu
MIT-advertising
MIT-enna
@@ -395,6 +409,7 @@ class Gem::Licenses
MIT-testregex
MITNFA
MMIXware
+ MMPL-1.0.1
MPEG-SSG
MPL-1.0
MPL-1.1
@@ -426,6 +441,7 @@ class Gem::Licenses
NGPL
NICTA-1.0
NIST-PD
+ NIST-PD-TNT
NIST-PD-fallback
NIST-Software
NLOD-1.0
@@ -485,12 +501,15 @@ class Gem::Licenses
OPL-1.0
OPL-UK-3.0
OPUBL-1.0
+ OSC-1.0
OSET-PL-2.1
OSL-1.0
OSL-1.1
OSL-2.0
OSL-2.1
OSL-3.0
+ OSSP
+ OpenMDW-1.0
OpenPBS-2.3
OpenSSL
OpenSSL-standalone
@@ -501,6 +520,7 @@ class Gem::Licenses
PHP-3.01
PPL
PSF-2.0
+ ParaType-Free-Font-1.3
Parity-6.0.0
Parity-7.0.0
Pixar
@@ -529,6 +549,7 @@ class Gem::Licenses
SGI-B-1.1
SGI-B-2.0
SGI-OpenGL
+ SGMLUG-PM
SGP4
SHL-0.5
SHL-0.51
@@ -576,6 +597,7 @@ class Gem::Licenses
TTYP0
TU-Berlin-1.0
TU-Berlin-2.0
+ TekHVC
TermReadKey
ThirdEye
TrustedQSL
@@ -585,6 +607,7 @@ class Gem::Licenses
UPL-1.0
URT-RLE
Ubuntu-font-1.0
+ UnRAR
Unicode-3.0
Unicode-DFS-2015
Unicode-DFS-2016
@@ -596,15 +619,19 @@ class Gem::Licenses
VOSTROM
VSL-1.0
Vim
+ Vixie-Cron
W3C
W3C-19980720
W3C-20150513
+ WTFNMFPL
WTFPL
Watcom-1.0
Widget-Workshop
+ WordNet
Wsuipa
X11
X11-distribute-modifications-variant
+ X11-no-permit-persons
X11-swapped
XFree86-1.1
XSkat
@@ -645,6 +672,7 @@ class Gem::Licenses
gnuplot
gtkbook
hdparm
+ hyphen-bulgarian
iMatix
jove
libpng-1.6.35
@@ -734,6 +762,7 @@ class Gem::Licenses
CGAL-linking-exception
CLISP-exception-2.0
Classpath-exception-2.0
+ Classpath-exception-2.0-short
DigiRule-FOSS-exception
Digia-Qt-LGPL-exception-1.1
FLTK-exception
@@ -775,6 +804,7 @@ class Gem::Licenses
SHL-2.0
SHL-2.1
SWI-exception
+ Simple-Library-Usage-exception
Swift-exception
Texinfo-exception
UBDL-exception
@@ -788,12 +818,15 @@ class Gem::Licenses
gnu-javamail-exception
harbour-exception
i2p-gpl-java-exception
+ kvirc-openssl-exception
libpri-OpenH323-exception
mif-exception
mxml-exception
openvpn-openssl-exception
polyparse-exception
romic-exception
+ rsync-linking-exception
+ sqlitestudio-OpenSSL-exception
stunnel-exception
u-boot-exception-2.0
vsftpd-openssl-exception
diff --git a/lib/rubygems/util/list.rb b/lib/rubygems/util/list.rb
deleted file mode 100644
index 2899e8a2b9..0000000000
--- a/lib/rubygems/util/list.rb
+++ /dev/null
@@ -1,40 +0,0 @@
-# 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:
- include Enumerable
- attr_accessor :value, :tail
-
- def initialize(value = nil, tail = nil)
- @value = value
- @tail = tail
- end
-
- def each
- n = self
- while n
- yield n.value
- n = n.tail
- end
- end
-
- def to_a
- super.reverse
- end
-
- def prepend(value)
- List.new value, self
- end
-
- def pretty_print(q) # :nodoc:
- q.pp to_a
- end
-
- def self.prepend(list, value)
- return List.new(value) unless list
- List.new value, list
- end
- end
- deprecate_constant :List
-end
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/lib/net/http.rb b/lib/rubygems/vendor/net-http/lib/net/http.rb
index 0e86056614..4800cd25f1 100644
--- a/lib/rubygems/vendor/net-http/lib/net/http.rb
+++ b/lib/rubygems/vendor/net-http/lib/net/http.rb
@@ -102,14 +102,14 @@ module Gem::Net #:nodoc:
#
# == URIs
#
- # On the internet, a URI
+ # On the internet, a Gem::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].
+ # see {Gem::URI syntax}[https://en.wikipedia.org/wiki/Uniform_Resource_Identifier#Syntax].
#
- # A Ruby {Gem::URI::Generic}[https://docs.ruby-lang.org/en/master/Gem/URI/Generic.html] object
- # represents an internet URI.
+ # A Ruby {Gem::URI::Generic}[https://docs.ruby-lang.org/en/master/Gem::URI/Generic.html] object
+ # represents an internet Gem::URI.
# It provides, among others, methods
# +scheme+, +hostname+, +path+, +query+, and +fragment+.
#
@@ -144,7 +144,7 @@ module Gem::Net #:nodoc:
#
# === Queries
#
- # A host-specific query adds name/value pairs to the URI:
+ # A host-specific query adds name/value pairs to the Gem::URI:
#
# _uri = uri.dup
# params = {userId: 1, completed: false}
@@ -154,7 +154,7 @@ module Gem::Net #:nodoc:
#
# === Fragments
#
- # A {URI fragment}[https://en.wikipedia.org/wiki/URI_fragment] has no effect
+ # A {Gem::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.
#
@@ -327,9 +327,9 @@ module Gem::Net #:nodoc:
# res = http.request(req)
# end
#
- # Or if you simply want to make a GET request, you may pass in a URI
+ # Or if you simply want to make a GET request, you may pass in a Gem::URI
# object that has an \HTTPS URL. \Gem::Net::HTTP automatically turns on TLS
- # verification if the URI object has a 'https' :URI scheme:
+ # verification if the Gem::URI object has a 'https' Gem::URI scheme:
#
# uri # => #<Gem::URI::HTTPS https://jsonplaceholder.typicode.com/>
# Gem::Net::HTTP.get(uri)
@@ -374,7 +374,7 @@ module Gem::Net #:nodoc:
#
# 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;
+ # the returned +http+ will have the server at that Gem::URI as its proxy;
# note that the \Gem::URI string must have a protocol
# such as <tt>'http'</tt> or <tt>'https'</tt>:
#
@@ -724,7 +724,7 @@ module Gem::Net #:nodoc:
class HTTP < Protocol
# :stopdoc:
- VERSION = "0.6.0"
+ VERSION = "0.9.1"
HTTPVersion = '1.1'
begin
require 'zlib'
@@ -790,7 +790,7 @@ module Gem::Net #:nodoc:
# "completed": false
# }
#
- # With URI object +uri+ and optional hash argument +headers+:
+ # With Gem::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'}
@@ -863,7 +863,7 @@ module Gem::Net #:nodoc:
# Posts data to a host; returns a Gem::Net::HTTPResponse object.
#
- # Argument +url+ must be a URI;
+ # Argument +url+ must be a Gem::URI;
# argument +data+ must be a hash:
#
# _uri = uri.dup
@@ -1179,6 +1179,7 @@ module Gem::Net #:nodoc:
@debug_output = options[:debug_output]
@response_body_encoding = options[:response_body_encoding]
@ignore_eof = options[:ignore_eof]
+ @tcpsocket_supports_open_timeout = nil
@proxy_from_env = false
@proxy_uri = nil
@@ -1321,6 +1322,9 @@ module Gem::Net #:nodoc:
# Sets the proxy password;
# see {Proxy Server}[rdoc-ref:Gem::Net::HTTP@Proxy+Server].
attr_writer :proxy_pass
+
+ # Sets whether the proxy uses SSL;
+ # see {Proxy Server}[rdoc-ref:Gem::Net::HTTP@Proxy+Server].
attr_writer :proxy_use_ssl
# Returns the IP address for the connection.
@@ -1527,9 +1531,9 @@ module Gem::Net #:nodoc:
:verify_depth,
:verify_mode,
:verify_hostname,
- ] # :nodoc:
+ ].freeze # :nodoc:
- SSL_IVNAMES = SSL_ATTRIBUTES.map { |a| "@#{a}".to_sym } # :nodoc:
+ SSL_IVNAMES = SSL_ATTRIBUTES.map { |a| "@#{a}".to_sym }.freeze # :nodoc:
# Sets or returns the path to a CA certification file in PEM format.
attr_accessor :ca_file
@@ -1632,6 +1636,21 @@ module Gem::Net #:nodoc:
self
end
+ # 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
+
+ # :stopdoc:
def do_start
connect
@started = true
@@ -1654,14 +1673,15 @@ module Gem::Net #:nodoc:
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})"
+ begin
+ s = timeouted_connect(conn_addr, conn_port)
+ rescue => e
+ if (defined?(IO::TimeoutError) && e.is_a?(IO::TimeoutError)) || e.is_a?(Errno::ETIMEDOUT) # for compatibility with previous versions
+ e = Gem::Net::OpenTimeout.new(e)
end
- }
+ 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?
@@ -1754,23 +1774,30 @@ module Gem::Net #:nodoc:
end
private :connect
- def on_connect
+ tcp_socket_parameters = TCPSocket.instance_method(:initialize).parameters
+ TCP_SOCKET_NEW_HAS_OPEN_TIMEOUT = if tcp_socket_parameters != [[:rest]]
+ tcp_socket_parameters.include?([:key, :open_timeout])
+ else
+ # Use Socket.tcp to find out since there is no parameters information for TCPSocket#initialize
+ # See discussion in https://github.com/ruby/net-http/pull/224
+ Socket.method(:tcp).parameters.include?([:key, :open_timeout])
end
- private :on_connect
+ private_constant :TCP_SOCKET_NEW_HAS_OPEN_TIMEOUT
- # 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
+ def timeouted_connect(conn_addr, conn_port)
+ if TCP_SOCKET_NEW_HAS_OPEN_TIMEOUT
+ TCPSocket.open(conn_addr, conn_port, @local_host, @local_port, open_timeout: @open_timeout)
+ else
+ Gem::Timeout.timeout(@open_timeout, Gem::Net::OpenTimeout) {
+ TCPSocket.open(conn_addr, conn_port, @local_host, @local_port)
+ }
+ end
+ end
+ private :timeouted_connect
+
+ def on_connect
end
+ private :on_connect
def do_finish
@started = false
@@ -1821,6 +1848,8 @@ module Gem::Net #:nodoc:
}
end
+ # :startdoc:
+
class << HTTP
# Returns true if self is a class which was created by HTTP::Proxy.
def proxy_class?
@@ -1860,7 +1889,7 @@ module Gem::Net #:nodoc:
@proxy_from_env
end
- # The proxy URI determined from the environment for this connection.
+ # The proxy Gem::URI determined from the environment for this connection.
def proxy_uri # :nodoc:
return if @proxy_uri == false
@proxy_uri ||= Gem::URI::HTTP.new(
@@ -1915,6 +1944,7 @@ module Gem::Net #:nodoc:
alias proxyport proxy_port #:nodoc: obsolete
private
+ # :stopdoc:
def unescape(value)
require 'cgi/escape'
@@ -1943,6 +1973,7 @@ module Gem::Net #:nodoc:
path
end
end
+ # :startdoc:
#
# HTTP operations
@@ -2397,7 +2428,9 @@ module Gem::Net #:nodoc:
res
end
- IDEMPOTENT_METHODS_ = %w/GET HEAD PUT DELETE OPTIONS TRACE/ # :nodoc:
+ # :stopdoc:
+
+ IDEMPOTENT_METHODS_ = %w/GET HEAD PUT DELETE OPTIONS TRACE/.freeze # :nodoc:
def transport_request(req)
count = 0
@@ -2554,7 +2587,7 @@ module Gem::Net #:nodoc:
alias_method :D, :debug
end
- # for backward compatibility until Ruby 3.5
+ # for backward compatibility until Ruby 4.0
# https://bugs.ruby-lang.org/issues/20900
# https://github.com/bblimke/webmock/pull/1081
HTTPSession = HTTP
diff --git a/lib/rubygems/vendor/net-http/lib/net/http/exceptions.rb b/lib/rubygems/vendor/net-http/lib/net/http/exceptions.rb
index c629c0113b..218df9a8bd 100644
--- a/lib/rubygems/vendor/net-http/lib/net/http/exceptions.rb
+++ b/lib/rubygems/vendor/net-http/lib/net/http/exceptions.rb
@@ -3,7 +3,7 @@ module Gem::Net
# Gem::Net::HTTP exception class.
# You cannot use Gem::Net::HTTPExceptions directly; instead, you must use
# its subclasses.
- module HTTPExceptions
+ module HTTPExceptions # :nodoc:
def initialize(msg, res) #:nodoc:
super msg
@response = res
@@ -12,6 +12,7 @@ module Gem::Net
alias data response #:nodoc: obsolete
end
+ # :stopdoc:
class HTTPError < ProtocolError
include HTTPExceptions
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
index 5cfe75a7cd..d6496d4ac1 100644
--- a/lib/rubygems/vendor/net-http/lib/net/http/generic_request.rb
+++ b/lib/rubygems/vendor/net-http/lib/net/http/generic_request.rb
@@ -19,16 +19,13 @@ class Gem::Net::HTTPGenericRequest
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
+ hostname = uri_or_path.host
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
@@ -51,7 +48,7 @@ class Gem::Net::HTTPGenericRequest
initialize_http_header initheader
self['Accept'] ||= '*/*'
self['User-Agent'] ||= 'Ruby'
- self['Host'] ||= host if host
+ self['Host'] ||= @uri.authority if @uri
@body = nil
@body_stream = nil
@body_data = nil
@@ -102,6 +99,31 @@ class Gem::Net::HTTPGenericRequest
"\#<#{self.class} #{@method}>"
end
+ # Returns a string representation of the request with the details for pp:
+ #
+ # require 'pp'
+ # post = Gem::Net::HTTP::Post.new(uri)
+ # post.inspect # => "#<Gem::Net::HTTP::Post POST>"
+ # post.pretty_inspect
+ # # => #<Gem::Net::HTTP::Post
+ # POST
+ # path="/"
+ # headers={"accept-encoding" => ["gzip;q=1.0,deflate;q=0.6,identity;q=0.3"],
+ # "accept" => ["*/*"],
+ # "user-agent" => ["Ruby"],
+ # "host" => ["www.ruby-lang.org"]}>
+ #
+ def pretty_print(q)
+ q.object_group(self) {
+ q.breakable
+ q.text @method
+ q.breakable
+ q.text "path="; q.pp @path
+ q.breakable
+ q.text "headers="; q.pp to_hash
+ }
+ end
+
##
# Don't automatically decode response content-encoding if the user indicates
# they want to handle it.
@@ -220,7 +242,7 @@ class Gem::Net::HTTPGenericRequest
end
if host = self['host']
- host.sub!(/:.*/m, '')
+ host = Gem::URI.parse("//#{host}").host # Remove a port component from the existing Host header
elsif host = @uri.host
else
host = addr
@@ -239,6 +261,8 @@ class Gem::Net::HTTPGenericRequest
private
+ # :stopdoc:
+
class Chunker #:nodoc:
def initialize(sock)
@sock = sock
@@ -260,7 +284,6 @@ class Gem::Net::HTTPGenericRequest
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
@@ -271,7 +294,6 @@ class Gem::Net::HTTPGenericRequest
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?
@@ -373,12 +395,6 @@ class Gem::Net::HTTPGenericRequest
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.
@@ -411,4 +427,3 @@ class Gem::Net::HTTPGenericRequest
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
index 5cb1da01ec..bc68cd2eef 100644
--- a/lib/rubygems/vendor/net-http/lib/net/http/header.rb
+++ b/lib/rubygems/vendor/net-http/lib/net/http/header.rb
@@ -179,7 +179,9 @@
# - #each_value: Passes each string field value to the block.
#
module Gem::Net::HTTPHeader
+ # The maximum length of HTTP header keys.
MAX_KEY_LENGTH = 1024
+ # The maximum length of HTTP header values.
MAX_FIELD_LENGTH = 65536
def initialize_http_header(initheader) #:nodoc:
@@ -267,6 +269,7 @@ module Gem::Net::HTTPHeader
end
end
+ # :stopdoc:
private def set_field(key, val)
case val
when Enumerable
@@ -294,6 +297,7 @@ module Gem::Net::HTTPHeader
ary.push val
end
end
+ # :startdoc:
# Returns the array field value for the given +key+,
# or +nil+ if there is no such field;
@@ -490,7 +494,7 @@ module Gem::Net::HTTPHeader
alias canonical_each each_capitalized
- def capitalize(name)
+ def capitalize(name) # :nodoc:
name.to_s.split('-'.freeze).map {|s| s.capitalize }.join('-'.freeze)
end
private :capitalize
@@ -957,12 +961,12 @@ module Gem::Net::HTTPHeader
@header['proxy-authorization'] = [basic_encode(account, password)]
end
- def basic_encode(account, password)
+ def basic_encode(account, password) # :nodoc:
'Basic ' + ["#{account}:#{password}"].pack('m0')
end
private :basic_encode
-# Returns whether the HTTP session is to be closed.
+ # 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}
@@ -970,7 +974,7 @@ module Gem::Net::HTTPHeader
false
end
-# Returns whether the HTTP session is to be kept alive.
+ # 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}
diff --git a/lib/rubygems/vendor/net-http/lib/net/http/requests.rb b/lib/rubygems/vendor/net-http/lib/net/http/requests.rb
index 45727e7f61..f990761042 100644
--- a/lib/rubygems/vendor/net-http/lib/net/http/requests.rb
+++ b/lib/rubygems/vendor/net-http/lib/net/http/requests.rb
@@ -29,6 +29,7 @@
# - Gem::Net::HTTP#get: sends +GET+ request, returns response object.
#
class Gem::Net::HTTP::Get < Gem::Net::HTTPRequest
+ # :stopdoc:
METHOD = 'GET'
REQUEST_HAS_BODY = false
RESPONSE_HAS_BODY = true
@@ -60,6 +61,7 @@ end
# - Gem::Net::HTTP#head: sends +HEAD+ request, returns response object.
#
class Gem::Net::HTTP::Head < Gem::Net::HTTPRequest
+ # :stopdoc:
METHOD = 'HEAD'
REQUEST_HAS_BODY = false
RESPONSE_HAS_BODY = false
@@ -95,6 +97,7 @@ end
# - Gem::Net::HTTP#post: sends +POST+ request, returns response object.
#
class Gem::Net::HTTP::Post < Gem::Net::HTTPRequest
+ # :stopdoc:
METHOD = 'POST'
REQUEST_HAS_BODY = true
RESPONSE_HAS_BODY = true
@@ -130,6 +133,7 @@ end
# - Gem::Net::HTTP#put: sends +PUT+ request, returns response object.
#
class Gem::Net::HTTP::Put < Gem::Net::HTTPRequest
+ # :stopdoc:
METHOD = 'PUT'
REQUEST_HAS_BODY = true
RESPONSE_HAS_BODY = true
@@ -162,6 +166,7 @@ end
# - Gem::Net::HTTP#delete: sends +DELETE+ request, returns response object.
#
class Gem::Net::HTTP::Delete < Gem::Net::HTTPRequest
+ # :stopdoc:
METHOD = 'DELETE'
REQUEST_HAS_BODY = false
RESPONSE_HAS_BODY = true
@@ -193,6 +198,7 @@ end
# - Gem::Net::HTTP#options: sends +OPTIONS+ request, returns response object.
#
class Gem::Net::HTTP::Options < Gem::Net::HTTPRequest
+ # :stopdoc:
METHOD = 'OPTIONS'
REQUEST_HAS_BODY = false
RESPONSE_HAS_BODY = true
@@ -224,6 +230,7 @@ end
# - Gem::Net::HTTP#trace: sends +TRACE+ request, returns response object.
#
class Gem::Net::HTTP::Trace < Gem::Net::HTTPRequest
+ # :stopdoc:
METHOD = 'TRACE'
REQUEST_HAS_BODY = false
RESPONSE_HAS_BODY = true
@@ -258,6 +265,7 @@ end
# - Gem::Net::HTTP#patch: sends +PATCH+ request, returns response object.
#
class Gem::Net::HTTP::Patch < Gem::Net::HTTPRequest
+ # :stopdoc:
METHOD = 'PATCH'
REQUEST_HAS_BODY = true
RESPONSE_HAS_BODY = true
@@ -285,6 +293,7 @@ end
# - Gem::Net::HTTP#propfind: sends +PROPFIND+ request, returns response object.
#
class Gem::Net::HTTP::Propfind < Gem::Net::HTTPRequest
+ # :stopdoc:
METHOD = 'PROPFIND'
REQUEST_HAS_BODY = true
RESPONSE_HAS_BODY = true
@@ -308,6 +317,7 @@ end
# - Gem::Net::HTTP#proppatch: sends +PROPPATCH+ request, returns response object.
#
class Gem::Net::HTTP::Proppatch < Gem::Net::HTTPRequest
+ # :stopdoc:
METHOD = 'PROPPATCH'
REQUEST_HAS_BODY = true
RESPONSE_HAS_BODY = true
@@ -331,6 +341,7 @@ end
# - Gem::Net::HTTP#mkcol: sends +MKCOL+ request, returns response object.
#
class Gem::Net::HTTP::Mkcol < Gem::Net::HTTPRequest
+ # :stopdoc:
METHOD = 'MKCOL'
REQUEST_HAS_BODY = true
RESPONSE_HAS_BODY = true
@@ -354,6 +365,7 @@ end
# - Gem::Net::HTTP#copy: sends +COPY+ request, returns response object.
#
class Gem::Net::HTTP::Copy < Gem::Net::HTTPRequest
+ # :stopdoc:
METHOD = 'COPY'
REQUEST_HAS_BODY = false
RESPONSE_HAS_BODY = true
@@ -377,6 +389,7 @@ end
# - Gem::Net::HTTP#move: sends +MOVE+ request, returns response object.
#
class Gem::Net::HTTP::Move < Gem::Net::HTTPRequest
+ # :stopdoc:
METHOD = 'MOVE'
REQUEST_HAS_BODY = false
RESPONSE_HAS_BODY = true
@@ -400,6 +413,7 @@ end
# - Gem::Net::HTTP#lock: sends +LOCK+ request, returns response object.
#
class Gem::Net::HTTP::Lock < Gem::Net::HTTPRequest
+ # :stopdoc:
METHOD = 'LOCK'
REQUEST_HAS_BODY = true
RESPONSE_HAS_BODY = true
@@ -423,8 +437,8 @@ end
# - Gem::Net::HTTP#unlock: sends +UNLOCK+ request, returns response object.
#
class Gem::Net::HTTP::Unlock < Gem::Net::HTTPRequest
+ # :stopdoc:
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
index cbbd191d87..dc164f1504 100644
--- a/lib/rubygems/vendor/net-http/lib/net/http/response.rb
+++ b/lib/rubygems/vendor/net-http/lib/net/http/response.rb
@@ -153,6 +153,7 @@ class Gem::Net::HTTPResponse
end
private
+ # :stopdoc:
def read_status_line(sock)
str = sock.readline
@@ -259,7 +260,7 @@ class Gem::Net::HTTPResponse
# header.
attr_accessor :ignore_eof
- def inspect
+ def inspect # :nodoc:
"#<#{self.class} #{@code} #{@message} readbody=#{@read}>"
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
index 0f26ae6c26..62ce1cba1b 100644
--- a/lib/rubygems/vendor/net-http/lib/net/http/responses.rb
+++ b/lib/rubygems/vendor/net-http/lib/net/http/responses.rb
@@ -4,7 +4,9 @@
module Gem::Net
+ # Unknown HTTP response
class HTTPUnknownResponse < HTTPResponse
+ # :stopdoc:
HAS_BODY = true
EXCEPTION_TYPE = HTTPError #
end
@@ -19,6 +21,7 @@ module Gem::Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#1xx_informational_response].
#
class HTTPInformation < HTTPResponse
+ # :stopdoc:
HAS_BODY = false
EXCEPTION_TYPE = HTTPError #
end
@@ -34,6 +37,7 @@ module Gem::Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#2xx_success].
#
class HTTPSuccess < HTTPResponse
+ # :stopdoc:
HAS_BODY = true
EXCEPTION_TYPE = HTTPError #
end
@@ -49,6 +53,7 @@ module Gem::Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#3xx_redirection].
#
class HTTPRedirection < HTTPResponse
+ # :stopdoc:
HAS_BODY = true
EXCEPTION_TYPE = HTTPRetriableError #
end
@@ -63,6 +68,7 @@ module Gem::Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#4xx_client_errors].
#
class HTTPClientError < HTTPResponse
+ # :stopdoc:
HAS_BODY = true
EXCEPTION_TYPE = HTTPClientException #
end
@@ -77,6 +83,7 @@ module Gem::Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#5xx_server_errors].
#
class HTTPServerError < HTTPResponse
+ # :stopdoc:
HAS_BODY = true
EXCEPTION_TYPE = HTTPFatalError #
end
@@ -94,6 +101,7 @@ module Gem::Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#100].
#
class HTTPContinue < HTTPInformation
+ # :stopdoc:
HAS_BODY = false
end
@@ -111,6 +119,7 @@ module Gem::Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#101].
#
class HTTPSwitchProtocol < HTTPInformation
+ # :stopdoc:
HAS_BODY = false
end
@@ -127,6 +136,7 @@ module Gem::Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#102].
#
class HTTPProcessing < HTTPInformation
+ # :stopdoc:
HAS_BODY = false
end
@@ -145,6 +155,7 @@ module Gem::Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#103].
#
class HTTPEarlyHints < HTTPInformation
+ # :stopdoc:
HAS_BODY = false
end
@@ -162,6 +173,7 @@ module Gem::Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#200].
#
class HTTPOK < HTTPSuccess
+ # :stopdoc:
HAS_BODY = true
end
@@ -179,6 +191,7 @@ module Gem::Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#201].
#
class HTTPCreated < HTTPSuccess
+ # :stopdoc:
HAS_BODY = true
end
@@ -196,6 +209,7 @@ module Gem::Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#202].
#
class HTTPAccepted < HTTPSuccess
+ # :stopdoc:
HAS_BODY = true
end
@@ -215,6 +229,7 @@ module Gem::Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#203].
#
class HTTPNonAuthoritativeInformation < HTTPSuccess
+ # :stopdoc:
HAS_BODY = true
end
@@ -232,6 +247,7 @@ module Gem::Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#204].
#
class HTTPNoContent < HTTPSuccess
+ # :stopdoc:
HAS_BODY = false
end
@@ -250,6 +266,7 @@ module Gem::Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#205].
#
class HTTPResetContent < HTTPSuccess
+ # :stopdoc:
HAS_BODY = false
end
@@ -268,6 +285,7 @@ module Gem::Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#206].
#
class HTTPPartialContent < HTTPSuccess
+ # :stopdoc:
HAS_BODY = true
end
@@ -285,6 +303,7 @@ module Gem::Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#207].
#
class HTTPMultiStatus < HTTPSuccess
+ # :stopdoc:
HAS_BODY = true
end
@@ -304,6 +323,7 @@ module Gem::Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#208].
#
class HTTPAlreadyReported < HTTPSuccess
+ # :stopdoc:
HAS_BODY = true
end
@@ -321,6 +341,7 @@ module Gem::Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#226].
#
class HTTPIMUsed < HTTPSuccess
+ # :stopdoc:
HAS_BODY = true
end
@@ -338,6 +359,7 @@ module Gem::Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#300].
#
class HTTPMultipleChoices < HTTPRedirection
+ # :stopdoc:
HAS_BODY = true
end
HTTPMultipleChoice = HTTPMultipleChoices
@@ -356,6 +378,7 @@ module Gem::Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#301].
#
class HTTPMovedPermanently < HTTPRedirection
+ # :stopdoc:
HAS_BODY = true
end
@@ -373,6 +396,7 @@ module Gem::Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#302].
#
class HTTPFound < HTTPRedirection
+ # :stopdoc:
HAS_BODY = true
end
HTTPMovedTemporarily = HTTPFound
@@ -390,6 +414,7 @@ module Gem::Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#303].
#
class HTTPSeeOther < HTTPRedirection
+ # :stopdoc:
HAS_BODY = true
end
@@ -407,6 +432,7 @@ module Gem::Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#304].
#
class HTTPNotModified < HTTPRedirection
+ # :stopdoc:
HAS_BODY = false
end
@@ -423,6 +449,7 @@ module Gem::Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#305].
#
class HTTPUseProxy < HTTPRedirection
+ # :stopdoc:
HAS_BODY = false
end
@@ -440,6 +467,7 @@ module Gem::Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#307].
#
class HTTPTemporaryRedirect < HTTPRedirection
+ # :stopdoc:
HAS_BODY = true
end
@@ -456,6 +484,7 @@ module Gem::Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#308].
#
class HTTPPermanentRedirect < HTTPRedirection
+ # :stopdoc:
HAS_BODY = true
end
@@ -472,6 +501,7 @@ module Gem::Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#400].
#
class HTTPBadRequest < HTTPClientError
+ # :stopdoc:
HAS_BODY = true
end
@@ -488,6 +518,7 @@ module Gem::Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#401].
#
class HTTPUnauthorized < HTTPClientError
+ # :stopdoc:
HAS_BODY = true
end
@@ -504,6 +535,7 @@ module Gem::Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#402].
#
class HTTPPaymentRequired < HTTPClientError
+ # :stopdoc:
HAS_BODY = true
end
@@ -521,6 +553,7 @@ module Gem::Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#403].
#
class HTTPForbidden < HTTPClientError
+ # :stopdoc:
HAS_BODY = true
end
@@ -537,6 +570,7 @@ module Gem::Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#404].
#
class HTTPNotFound < HTTPClientError
+ # :stopdoc:
HAS_BODY = true
end
@@ -553,6 +587,7 @@ module Gem::Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#405].
#
class HTTPMethodNotAllowed < HTTPClientError
+ # :stopdoc:
HAS_BODY = true
end
@@ -570,6 +605,7 @@ module Gem::Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#406].
#
class HTTPNotAcceptable < HTTPClientError
+ # :stopdoc:
HAS_BODY = true
end
@@ -586,6 +622,7 @@ module Gem::Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#407].
#
class HTTPProxyAuthenticationRequired < HTTPClientError
+ # :stopdoc:
HAS_BODY = true
end
@@ -602,6 +639,7 @@ module Gem::Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#408].
#
class HTTPRequestTimeout < HTTPClientError
+ # :stopdoc:
HAS_BODY = true
end
HTTPRequestTimeOut = HTTPRequestTimeout
@@ -619,6 +657,7 @@ module Gem::Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#409].
#
class HTTPConflict < HTTPClientError
+ # :stopdoc:
HAS_BODY = true
end
@@ -636,6 +675,7 @@ module Gem::Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#410].
#
class HTTPGone < HTTPClientError
+ # :stopdoc:
HAS_BODY = true
end
@@ -653,6 +693,7 @@ module Gem::Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#411].
#
class HTTPLengthRequired < HTTPClientError
+ # :stopdoc:
HAS_BODY = true
end
@@ -670,6 +711,7 @@ module Gem::Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#412].
#
class HTTPPreconditionFailed < HTTPClientError
+ # :stopdoc:
HAS_BODY = true
end
@@ -686,6 +728,7 @@ module Gem::Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#413].
#
class HTTPPayloadTooLarge < HTTPClientError
+ # :stopdoc:
HAS_BODY = true
end
HTTPRequestEntityTooLarge = HTTPPayloadTooLarge
@@ -703,6 +746,7 @@ module Gem::Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#414].
#
class HTTPURITooLong < HTTPClientError
+ # :stopdoc:
HAS_BODY = true
end
HTTPRequestURITooLong = HTTPURITooLong
@@ -721,6 +765,7 @@ module Gem::Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#415].
#
class HTTPUnsupportedMediaType < HTTPClientError
+ # :stopdoc:
HAS_BODY = true
end
@@ -737,6 +782,7 @@ module Gem::Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#416].
#
class HTTPRangeNotSatisfiable < HTTPClientError
+ # :stopdoc:
HAS_BODY = true
end
HTTPRequestedRangeNotSatisfiable = HTTPRangeNotSatisfiable
@@ -754,6 +800,7 @@ module Gem::Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#417].
#
class HTTPExpectationFailed < HTTPClientError
+ # :stopdoc:
HAS_BODY = true
end
@@ -774,6 +821,7 @@ module Gem::Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#421].
#
class HTTPMisdirectedRequest < HTTPClientError
+ # :stopdoc:
HAS_BODY = true
end
@@ -790,6 +838,7 @@ module Gem::Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#422].
#
class HTTPUnprocessableEntity < HTTPClientError
+ # :stopdoc:
HAS_BODY = true
end
@@ -805,6 +854,7 @@ module Gem::Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#423].
#
class HTTPLocked < HTTPClientError
+ # :stopdoc:
HAS_BODY = true
end
@@ -821,6 +871,7 @@ module Gem::Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#424].
#
class HTTPFailedDependency < HTTPClientError
+ # :stopdoc:
HAS_BODY = true
end
@@ -840,6 +891,7 @@ module Gem::Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#426].
#
class HTTPUpgradeRequired < HTTPClientError
+ # :stopdoc:
HAS_BODY = true
end
@@ -856,6 +908,7 @@ module Gem::Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#428].
#
class HTTPPreconditionRequired < HTTPClientError
+ # :stopdoc:
HAS_BODY = true
end
@@ -872,6 +925,7 @@ module Gem::Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#429].
#
class HTTPTooManyRequests < HTTPClientError
+ # :stopdoc:
HAS_BODY = true
end
@@ -889,6 +943,7 @@ module Gem::Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#431].
#
class HTTPRequestHeaderFieldsTooLarge < HTTPClientError
+ # :stopdoc:
HAS_BODY = true
end
@@ -906,6 +961,7 @@ module Gem::Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#451].
#
class HTTPUnavailableForLegalReasons < HTTPClientError
+ # :stopdoc:
HAS_BODY = true
end
# 444 No Response - Nginx
@@ -926,6 +982,7 @@ module Gem::Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#500].
#
class HTTPInternalServerError < HTTPServerError
+ # :stopdoc:
HAS_BODY = true
end
@@ -943,6 +1000,7 @@ module Gem::Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#501].
#
class HTTPNotImplemented < HTTPServerError
+ # :stopdoc:
HAS_BODY = true
end
@@ -960,6 +1018,7 @@ module Gem::Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#502].
#
class HTTPBadGateway < HTTPServerError
+ # :stopdoc:
HAS_BODY = true
end
@@ -977,6 +1036,7 @@ module Gem::Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#503].
#
class HTTPServiceUnavailable < HTTPServerError
+ # :stopdoc:
HAS_BODY = true
end
@@ -994,6 +1054,7 @@ module Gem::Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#504].
#
class HTTPGatewayTimeout < HTTPServerError
+ # :stopdoc:
HAS_BODY = true
end
HTTPGatewayTimeOut = HTTPGatewayTimeout
@@ -1011,6 +1072,7 @@ module Gem::Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#505].
#
class HTTPVersionNotSupported < HTTPServerError
+ # :stopdoc:
HAS_BODY = true
end
@@ -1027,6 +1089,7 @@ module Gem::Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#506].
#
class HTTPVariantAlsoNegotiates < HTTPServerError
+ # :stopdoc:
HAS_BODY = true
end
@@ -1043,6 +1106,7 @@ module Gem::Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#507].
#
class HTTPInsufficientStorage < HTTPServerError
+ # :stopdoc:
HAS_BODY = true
end
@@ -1059,6 +1123,7 @@ module Gem::Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#508].
#
class HTTPLoopDetected < HTTPServerError
+ # :stopdoc:
HAS_BODY = true
end
# 509 Bandwidth Limit Exceeded - Apache bw/limited extension
@@ -1076,6 +1141,7 @@ module Gem::Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#510].
#
class HTTPNotExtended < HTTPServerError
+ # :stopdoc:
HAS_BODY = true
end
@@ -1092,19 +1158,21 @@ module Gem::Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#511].
#
class HTTPNetworkAuthenticationRequired < HTTPServerError
+ # :stopdoc:
HAS_BODY = true
end
end
class Gem::Net::HTTPResponse
+ # :stopdoc:
CODE_CLASS_TO_OBJ = {
'1' => Gem::Net::HTTPInformation,
'2' => Gem::Net::HTTPSuccess,
'3' => Gem::Net::HTTPRedirection,
'4' => Gem::Net::HTTPClientError,
'5' => Gem::Net::HTTPServerError
- }
+ }.freeze
CODE_TO_OBJ = {
'100' => Gem::Net::HTTPContinue,
'101' => Gem::Net::HTTPSwitchProtocol,
@@ -1170,5 +1238,5 @@ class Gem::Net::HTTPResponse
'508' => Gem::Net::HTTPLoopDetected,
'510' => Gem::Net::HTTPNotExtended,
'511' => Gem::Net::HTTPNetworkAuthenticationRequired,
- }
+ }.freeze
end
diff --git a/lib/rubygems/vendor/optparse/lib/optparse.rb b/lib/rubygems/vendor/optparse/lib/optparse.rb
index 537d06f229..d39d9dd4e0 100644
--- a/lib/rubygems/vendor/optparse/lib/optparse.rb
+++ b/lib/rubygems/vendor/optparse/lib/optparse.rb
@@ -7,6 +7,7 @@
#
# See Gem::OptionParser for documentation.
#
+require 'set' unless defined?(Set)
#--
# == Developer Documentation (not for RDoc output)
@@ -142,7 +143,7 @@
# Used:
#
# $ ruby optparse-test.rb -r
-# optparse-test.rb:9:in `<main>': missing argument: -r (Gem::OptionParser::MissingArgument)
+# optparse-test.rb:9:in '<main>': missing argument: -r (Gem::OptionParser::MissingArgument)
# $ ruby optparse-test.rb -r my-library
# You required my-library!
#
@@ -235,7 +236,7 @@
# $ 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)
+# optparse-test.rb:15:in 'block in find_user': No User Found for id 3 (RuntimeError)
#
# === Store options to a Hash
#
@@ -425,7 +426,8 @@
#
class Gem::OptionParser
# The version string
- Gem::OptionParser::Version = "0.6.0"
+ VERSION = "0.8.0"
+ Version = VERSION # for compatibility
# :stopdoc:
NoArgument = [NO_ARGUMENT = :NONE, nil].freeze
@@ -461,6 +463,10 @@ class Gem::OptionParser
candidates
end
+ def self.completable?(key)
+ String.try_convert(key) or defined?(key.id2name)
+ end
+
def candidate(key, icase = false, pat = nil, &_)
Completion.candidate(key, icase, pat, &method(:each))
end
@@ -496,7 +502,6 @@ class Gem::OptionParser
end
end
-
#
# Map from option/keyword string to object with completion.
#
@@ -504,7 +509,6 @@ class Gem::OptionParser
include Completion
end
-
#
# Individual switch class. Not important to the user.
#
@@ -546,11 +550,11 @@ class Gem::OptionParser
def initialize(pattern = nil, conv = nil,
short = nil, long = nil, arg = nil,
- desc = ([] if short or long), block = nil, &_block)
+ desc = ([] if short or long), block = nil, values = nil, &_block)
raise if Array === pattern
block ||= _block
- @pattern, @conv, @short, @long, @arg, @desc, @block =
- pattern, conv, short, long, arg, desc, block
+ @pattern, @conv, @short, @long, @arg, @desc, @block, @values =
+ pattern, conv, short, long, arg, desc, block, values
end
#
@@ -583,11 +587,15 @@ class Gem::OptionParser
# exception.
#
def conv_arg(arg, val = []) # :nodoc:
+ v, = *val
if conv
val = conv.call(*val)
else
val = proc {|v| v}.call(*val)
end
+ if @values
+ @values.include?(val) or raise InvalidArgument, v
+ end
return arg, block, val
end
private :conv_arg
@@ -668,7 +676,7 @@ class Gem::OptionParser
(sopts+lopts).each do |opt|
# "(-x -c -r)-l[left justify]"
- if /^--\[no-\](.+)$/ =~ opt
+ if /\A--\[no-\](.+)$/ =~ opt
o = $1
yield("--#{o}", desc.join(""))
yield("--no-#{o}", desc.join(""))
@@ -1032,7 +1040,6 @@ class Gem::OptionParser
DefaultList.short['-'] = Switch::NoArgument.new {}
DefaultList.long[''] = Switch::NoArgument.new {throw :terminate}
-
COMPSYS_HEADER = <<'XXX' # :nodoc:
typeset -A opt_args
@@ -1051,16 +1058,16 @@ XXX
end
def help_exit
- if STDOUT.tty? && (pager = ENV.values_at(*%w[RUBY_PAGER PAGER]).find {|e| e && !e.empty?})
+ 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"]
+ args = [{"LESS" => "#{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)}
+ IO.popen("-") {|f| f ? Process.exec(*args, in: f) : print.call($stdout)}
# unreachable
end
IO.popen(*args, &print)
@@ -1102,7 +1109,7 @@ XXX
#
Officious['*-completion-zsh'] = proc do |parser|
Switch::OptionalArgument.new do |arg|
- parser.compsys(STDOUT, arg)
+ parser.compsys($stdout, arg)
exit
end
end
@@ -1288,7 +1295,15 @@ XXX
# to $0.
#
def program_name
- @program_name || File.basename($0, '.*')
+ @program_name || strip_ext(File.basename($0))
+ end
+
+ private def strip_ext(name) # :nodoc:
+ exts = /#{
+ require "rbconfig"
+ Regexp.union(*RbConfig::CONFIG["EXECUTABLE_EXTS"]&.split(" "))
+ }\z/o
+ name.sub(exts, "")
end
# for experimental cascading :-)
@@ -1467,6 +1482,7 @@ XXX
klass = nil
q, a = nil
has_arg = false
+ values = nil
opts.each do |o|
# argument class
@@ -1480,7 +1496,7 @@ XXX
end
# directly specified pattern(any object possible to match)
- if (!(String === o || Symbol === o)) and o.respond_to?(:match)
+ if !Completion.completable?(o) and o.respond_to?(:match)
pattern = notwice(o, pattern, 'pattern')
if pattern.respond_to?(:convert)
conv = pattern.method(:convert).to_proc
@@ -1494,7 +1510,12 @@ XXX
case o
when Proc, Method
block = notwice(o, block, 'block')
- when Array, Hash
+ when Array, Hash, Set
+ if Array === o
+ o, v = o.partition {|v,| Completion.completable?(v)}
+ values = notwice(v, values, 'values') unless v.empty?
+ next if o.empty?
+ end
case pattern
when CompletingHash
when nil
@@ -1504,11 +1525,13 @@ XXX
raise ArgumentError, "argument pattern given twice"
end
o.each {|pat, *v| pattern[pat] = v.fetch(0) {pat}}
+ when Range
+ values = notwice(o, values, 'values')
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]*)(.+)?/
+ when /\A--no-([^\[\]=\s]*)(.+)?/
q, a = $1, $2
o = notwice(a ? Object : TrueClass, klass, 'type')
not_pattern, not_conv = search(:atype, o) unless not_style
@@ -1519,7 +1542,7 @@ XXX
(q = q.downcase).tr!('_', '-')
long << "no-#{q}"
nolong << q
- when /^--\[no-\]([^\[\]=\s]*)(.+)?/
+ when /\A--\[no-\]([^\[\]=\s]*)(.+)?/
q, a = $1, $2
o = notwice(a ? Object : TrueClass, klass, 'type')
if a
@@ -1532,7 +1555,7 @@ XXX
not_pattern, not_conv = search(:atype, FalseClass) unless not_style
not_style = Switch::NoArgument
nolong << "no-#{o}"
- when /^--([^\[\]=\s]*)(.+)?/
+ when /\A--([^\[\]=\s]*)(.+)?/
q, a = $1, $2
if a
o = notwice(NilClass, klass, 'type')
@@ -1542,7 +1565,7 @@ XXX
ldesc << "--#{q}"
(o = q.downcase).tr!('_', '-')
long << o
- when /^-(\[\^?\]?(?:[^\\\]]|\\.)*\])(.+)?/
+ when /\A-(\[\^?\]?(?:[^\\\]]|\\.)*\])(.+)?/
q, a = $1, $2
o = notwice(Object, klass, 'type')
if a
@@ -1553,7 +1576,7 @@ XXX
end
sdesc << "-#{q}"
short << Regexp.new(q)
- when /^-(.)(.+)?/
+ when /\A-(.)(.+)?/
q, a = $1, $2
if a
o = notwice(NilClass, klass, 'type')
@@ -1562,7 +1585,7 @@ XXX
end
sdesc << "-#{q}"
short << q
- when /^=/
+ when /\A=/
style = notwice(default_style.guess(arg = o), style, 'style')
default_pattern, conv = search(:atype, Object) unless default_pattern
else
@@ -1571,12 +1594,18 @@ XXX
end
default_pattern, conv = search(:atype, default_style.pattern) unless default_pattern
+ if Range === values and klass
+ unless (!values.begin or klass === values.begin) and
+ (!values.end or klass === values.end)
+ raise ArgumentError, "range does not match class"
+ end
+ end
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)
+ conv, sdesc, ldesc, arg, desc, block, values)
elsif !block
if style or pattern
raise ArgumentError, "no switch given", ParseError.filter_backtrace(caller)
@@ -1585,7 +1614,7 @@ XXX
else
short << pattern
s = (style || default_style).new(pattern,
- conv, nil, nil, arg, desc, block)
+ conv, nil, nil, arg, desc, block, values)
end
return s, short, long,
(not_style.new(not_pattern, not_conv, sdesc, ldesc, nil, desc, block) if not_style),
@@ -1827,7 +1856,7 @@ XXX
#
def permute!(argv = default_argv, **keywords)
nonopts = []
- order!(argv, **keywords, &nonopts.method(:<<))
+ order!(argv, **keywords) {|nonopt| nonopts << nonopt}
argv[0, 0] = nonopts
argv
end
@@ -1880,13 +1909,16 @@ XXX
single_options, *long_options = *args
result = {}
+ setter = (symbolize_names ?
+ ->(name, val) {result[name.to_sym] = val}
+ : ->(name, val) {result[name] = val})
single_options.scan(/(.)(:)?/) do |opt, val|
if val
- result[opt] = nil
+ setter[opt, nil]
define("-#{opt} VAL")
else
- result[opt] = false
+ setter[opt, false]
define("-#{opt}")
end
end if single_options
@@ -1895,16 +1927,16 @@ XXX
arg, desc = arg.split(';', 2)
opt, val = arg.split(':', 2)
if val
- result[opt] = val.empty? ? nil : val
+ setter[opt, (val unless val.empty?)]
define("--#{opt}=#{result[opt] || "VAL"}", *[desc].compact)
else
- result[opt] = false
+ setter[opt, false]
define("--#{opt}", *[desc].compact)
end
end
- parse_in_order(argv, result.method(:[]=), **keywords)
- symbolize_names ? result.transform_keys(&:to_sym) : result
+ parse_in_order(argv, setter, **keywords)
+ result
end
#
@@ -1954,7 +1986,7 @@ XXX
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])
+ raise exc.new(opt, additional: proc {|o| additional_message(typ, o)})
end
private :complete
@@ -2019,19 +2051,27 @@ XXX
def load(filename = nil, **keywords)
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("~/.options/#{basename}"), **keywords) rescue nil
basename << ".options"
+ if !(xdg = ENV['XDG_CONFIG_HOME']) or xdg.empty?
+ # https://specifications.freedesktop.org/basedir-spec/latest/#variables
+ #
+ # If $XDG_CONFIG_HOME is either not set or empty, a default
+ # equal to $HOME/.config should be used.
+ xdg = ['~/.config', true]
+ end
return [
- # XDG
- ENV['XDG_CONFIG_HOME'],
- '~/.config',
+ xdg,
+
*ENV['XDG_CONFIG_DIRS']&.split(File::PATH_SEPARATOR),
# Haiku
- '~/config/settings',
- ].any? {|dir|
+ ['~/config/settings', true],
+ ].any? {|dir, expand|
next if !dir or dir.empty?
- load(File.expand_path(basename, dir), **keywords) rescue nil
+ filename = File.join(dir, basename)
+ filename = File.expand_path(filename) if expand
+ load(filename, **keywords) rescue nil
}
end
begin
@@ -2237,9 +2277,10 @@ XXX
argv
end
+ DIR = File.join(__dir__, '')
def self.filter_backtrace(array)
unless $DEBUG
- array.delete_if(&%r"\A#{Regexp.quote(__FILE__)}:"o.method(:=~))
+ array.delete_if {|bt| bt.start_with?(DIR)}
end
array
end
diff --git a/lib/rubygems/vendor/pub_grub/lib/pub_grub.rb b/lib/rubygems/vendor/pub_grub/lib/pub_grub.rb
new file mode 100644
index 0000000000..818e947477
--- /dev/null
+++ b/lib/rubygems/vendor/pub_grub/lib/pub_grub.rb
@@ -0,0 +1,53 @@
+require_relative "pub_grub/package"
+require_relative "pub_grub/static_package_source"
+require_relative "pub_grub/term"
+require_relative "pub_grub/version_range"
+require_relative "pub_grub/version_constraint"
+require_relative "pub_grub/version_union"
+require_relative "pub_grub/version_solver"
+require_relative "pub_grub/incompatibility"
+require_relative 'pub_grub/solve_failure'
+require_relative 'pub_grub/failure_writer'
+require_relative 'pub_grub/version'
+
+module Gem::PubGrub
+ # Minimal logger that doesn't require the 'logger' gem
+ class NullLogger
+ def info(&block); end
+ def debug(&block); end
+ def warn(&block); end
+ def error(&block); end
+ end
+
+ class StderrLogger
+ def info(&block)
+ $stderr.puts "INFO: #{block.call}" if block
+ end
+
+ def debug(&block)
+ $stderr.puts "DEBUG: #{block.call}" if block
+ end
+
+ def warn(&block)
+ $stderr.puts "WARN: #{block.call}" if block
+ end
+
+ def error(&block)
+ $stderr.puts "ERROR: #{block.call}" if block
+ end
+ end
+
+ class << self
+ attr_writer :logger
+
+ def logger
+ @logger || default_logger
+ end
+
+ private
+
+ def default_logger
+ @logger = $DEBUG ? StderrLogger.new : NullLogger.new
+ end
+ end
+end
diff --git a/lib/rubygems/vendor/pub_grub/lib/pub_grub/assignment.rb b/lib/rubygems/vendor/pub_grub/lib/pub_grub/assignment.rb
new file mode 100644
index 0000000000..7a11cf0933
--- /dev/null
+++ b/lib/rubygems/vendor/pub_grub/lib/pub_grub/assignment.rb
@@ -0,0 +1,20 @@
+module Gem::PubGrub
+ class Assignment
+ attr_reader :term, :cause, :decision_level, :index
+ def initialize(term, cause, decision_level, index)
+ @term = term
+ @cause = cause
+ @decision_level = decision_level
+ @index = index
+ end
+
+ def self.decision(package, version, decision_level, index)
+ term = Term.new(VersionConstraint.exact(package, version), true)
+ new(term, :decision, decision_level, index)
+ end
+
+ def decision?
+ cause == :decision
+ end
+ end
+end
diff --git a/lib/rubygems/vendor/pub_grub/lib/pub_grub/basic_package_source.rb b/lib/rubygems/vendor/pub_grub/lib/pub_grub/basic_package_source.rb
new file mode 100644
index 0000000000..c8dbf2a5ab
--- /dev/null
+++ b/lib/rubygems/vendor/pub_grub/lib/pub_grub/basic_package_source.rb
@@ -0,0 +1,169 @@
+require_relative 'version_constraint'
+require_relative 'incompatibility'
+
+module Gem::PubGrub
+ # Types:
+ #
+ # Where possible, Gem::PubGrub will accept user-defined types, so long as they quack.
+ #
+ # ## "Package":
+ #
+ # This class will be used to represent the various packages being solved for.
+ # .to_s will be called when displaying errors and debugging info, it should
+ # probably return the package's name.
+ # It must also have a reasonable definition of #== and #hash
+ #
+ # Example classes: String ("rails")
+ #
+ #
+ # ## "Version":
+ #
+ # This class will be used to represent a single version number.
+ #
+ # Versions don't need to store their associated package, however they will
+ # only be compared against other versions of the same package.
+ #
+ # It must be Comparible (and implement <=> reasonably)
+ #
+ # Example classes: Gem::Version, Integer
+ #
+ #
+ # ## "Dependency"
+ #
+ # This class represents the requirement one package has on another. It is
+ # returned by dependencies_for(package, version) and will be passed to
+ # parse_dependency to convert it to a format Gem::PubGrub understands.
+ #
+ # It must also have a reasonable definition of #==
+ #
+ # Example classes: String ("~> 1.0"), Gem::Requirement
+ #
+ class BasicPackageSource
+ # Override me!
+ #
+ # This is called per package to find all possible versions of a package.
+ #
+ # It is called at most once per-package
+ #
+ # Returns: Array of versions for a package, in preferred order of selection
+ def all_versions_for(package)
+ raise NotImplementedError
+ end
+
+ # Override me!
+ #
+ # Returns: Hash in the form of { package => requirement, ... }
+ def dependencies_for(package, version)
+ raise NotImplementedError
+ end
+
+ # Override me!
+ #
+ # Convert a (user-defined) dependency into a format Gem::PubGrub understands.
+ #
+ # Package is passed to this method but for many implementations is not
+ # needed.
+ #
+ # Returns: either a Gem::PubGrub::VersionRange, Gem::PubGrub::VersionUnion, or a
+ # Gem::PubGrub::VersionConstraint
+ def parse_dependency(package, dependency)
+ raise NotImplementedError
+ end
+
+ # Override me!
+ #
+ # If not overridden, this will call dependencies_for with the root package.
+ #
+ # Returns: Hash in the form of { package => requirement, ... } (see dependencies_for)
+ def root_dependencies
+ dependencies_for(@root_package, @root_version)
+ end
+
+ def initialize
+ @root_package = Package.root
+ @root_version = Package.root_version
+
+ @sorted_versions = Hash.new do |h,k|
+ if k == @root_package
+ h[k] = [@root_version]
+ else
+ h[k] = all_versions_for(k).sort
+ end
+ end
+
+ @cached_dependencies = Hash.new do |packages, package|
+ if package == @root_package
+ packages[package] = {
+ @root_version => root_dependencies
+ }
+ else
+ packages[package] = Hash.new do |versions, version|
+ versions[version] = dependencies_for(package, version)
+ end
+ end
+ end
+ end
+
+ def versions_for(package, range=VersionRange.any)
+ range.select_versions(@sorted_versions[package])
+ end
+
+ def no_versions_incompatibility_for(_package, unsatisfied_term)
+ cause = Incompatibility::NoVersions.new(unsatisfied_term)
+
+ Incompatibility.new([unsatisfied_term], cause: cause)
+ end
+
+ def incompatibilities_for(package, version)
+ package_deps = @cached_dependencies[package]
+ sorted_versions = @sorted_versions[package]
+ package_deps[version].map do |dep_package, dep_constraint_name|
+ low = high = sorted_versions.index(version)
+
+ # find version low such that all >= low share the same dep
+ while low > 0 &&
+ package_deps[sorted_versions[low - 1]][dep_package] == dep_constraint_name
+ low -= 1
+ end
+ low =
+ if low == 0
+ nil
+ else
+ sorted_versions[low]
+ end
+
+ # find version high such that all < high share the same dep
+ while high < sorted_versions.length &&
+ package_deps[sorted_versions[high]][dep_package] == dep_constraint_name
+ high += 1
+ end
+ high =
+ if high == sorted_versions.length
+ nil
+ else
+ sorted_versions[high]
+ end
+
+ range = VersionRange.new(min: low, max: high, include_min: !low.nil?)
+
+ self_constraint = VersionConstraint.new(package, range: range)
+
+ if !@packages.include?(dep_package)
+ # no such package -> this version is invalid
+ end
+
+ dep_constraint = parse_dependency(dep_package, dep_constraint_name)
+ if !dep_constraint
+ # falsey indicates this dependency was invalid
+ cause = Gem::PubGrub::Incompatibility::InvalidDependency.new(dep_package, dep_constraint_name)
+ return [Incompatibility.new([Term.new(self_constraint, true)], cause: cause)]
+ elsif !dep_constraint.is_a?(VersionConstraint)
+ # Upgrade range/union to VersionConstraint
+ dep_constraint = VersionConstraint.new(dep_package, range: dep_constraint)
+ end
+
+ Incompatibility.new([Term.new(self_constraint, true), Term.new(dep_constraint, false)], cause: :dependency)
+ end
+ end
+ end
+end
diff --git a/lib/rubygems/vendor/pub_grub/lib/pub_grub/failure_writer.rb b/lib/rubygems/vendor/pub_grub/lib/pub_grub/failure_writer.rb
new file mode 100644
index 0000000000..d8bfde0286
--- /dev/null
+++ b/lib/rubygems/vendor/pub_grub/lib/pub_grub/failure_writer.rb
@@ -0,0 +1,182 @@
+module Gem::PubGrub
+ class FailureWriter
+ def initialize(root)
+ @root = root
+
+ # { Incompatibility => Integer }
+ @derivations = {}
+
+ # [ [ String, Integer or nil ] ]
+ @lines = []
+
+ # { Incompatibility => Integer }
+ @line_numbers = {}
+
+ count_derivations(root)
+ end
+
+ def write
+ return @root.to_s unless @root.conflict?
+
+ visit(@root)
+
+ padding = @line_numbers.empty? ? 0 : "(#{@line_numbers.values.last}) ".length
+
+ @lines.map do |message, number|
+ next "" if message.empty?
+
+ lead = number ? "(#{number}) " : ""
+ lead = lead.ljust(padding)
+ message = message.gsub("\n", "\n" + " " * (padding + 2))
+ "#{lead}#{message}"
+ end.join("\n")
+ end
+
+ private
+
+ def write_line(incompatibility, message, numbered:)
+ if numbered
+ number = @line_numbers.length + 1
+ @line_numbers[incompatibility] = number
+ end
+
+ @lines << [message, number]
+ end
+
+ def visit(incompatibility, conclusion: false)
+ raise unless incompatibility.conflict?
+
+ numbered = conclusion || @derivations[incompatibility] > 1;
+ conjunction = conclusion || incompatibility == @root ? "So," : "And"
+
+ cause = incompatibility.cause
+
+ if cause.conflict.conflict? && cause.other.conflict?
+ conflict_line = @line_numbers[cause.conflict]
+ other_line = @line_numbers[cause.other]
+
+ if conflict_line && other_line
+ write_line(
+ incompatibility,
+ "Because #{cause.conflict} (#{conflict_line})\nand #{cause.other} (#{other_line}),\n#{incompatibility}.",
+ numbered: numbered
+ )
+ elsif conflict_line || other_line
+ with_line = conflict_line ? cause.conflict : cause.other
+ without_line = conflict_line ? cause.other : cause.conflict
+ line = @line_numbers[with_line]
+
+ visit(without_line);
+ write_line(
+ incompatibility,
+ "#{conjunction} because #{with_line} (#{line}),\n#{incompatibility}.",
+ numbered: numbered
+ )
+ else
+ single_line_conflict = single_line?(cause.conflict.cause)
+ single_line_other = single_line?(cause.other.cause)
+
+ if single_line_conflict || single_line_other
+ first = single_line_other ? cause.conflict : cause.other
+ second = single_line_other ? cause.other : cause.conflict
+ visit(first)
+ visit(second)
+ write_line(
+ incompatibility,
+ "Thus, #{incompatibility}.",
+ numbered: numbered
+ )
+ else
+ visit(cause.conflict, conclusion: true)
+ @lines << ["", nil]
+ visit(cause.other)
+
+ write_line(
+ incompatibility,
+ "#{conjunction} because #{cause.conflict} (#{@line_numbers[cause.conflict]}),\n#{incompatibility}.",
+ numbered: numbered
+ )
+ end
+ end
+ elsif cause.conflict.conflict? || cause.other.conflict?
+ derived = cause.conflict.conflict? ? cause.conflict : cause.other
+ ext = cause.conflict.conflict? ? cause.other : cause.conflict
+
+ derived_line = @line_numbers[derived]
+ if derived_line
+ write_line(
+ incompatibility,
+ "Because #{ext}\nand #{derived} (#{derived_line}),\n#{incompatibility}.",
+ numbered: numbered
+ )
+ elsif collapsible?(derived)
+ derived_cause = derived.cause
+ if derived_cause.conflict.conflict?
+ collapsed_derived = derived_cause.conflict
+ collapsed_ext = derived_cause.other
+ else
+ collapsed_derived = derived_cause.other
+ collapsed_ext = derived_cause.conflict
+ end
+
+ visit(collapsed_derived)
+
+ write_line(
+ incompatibility,
+ "#{conjunction} because #{collapsed_ext}\nand #{ext},\n#{incompatibility}.",
+ numbered: numbered
+ )
+ else
+ visit(derived)
+ write_line(
+ incompatibility,
+ "#{conjunction} because #{ext},\n#{incompatibility}.",
+ numbered: numbered
+ )
+ end
+ else
+ write_line(
+ incompatibility,
+ "Because #{cause.conflict}\nand #{cause.other},\n#{incompatibility}.",
+ numbered: numbered
+ )
+ end
+ end
+
+ def single_line?(cause)
+ !cause.conflict.conflict? && !cause.other.conflict?
+ end
+
+ def collapsible?(incompatibility)
+ return false if @derivations[incompatibility] > 1
+
+ cause = incompatibility.cause
+ # If incompatibility is derived from two derived incompatibilities,
+ # there are too many transitive causes to display concisely.
+ return false if cause.conflict.conflict? && cause.other.conflict?
+
+ # If incompatibility is derived from two external incompatibilities, it
+ # tends to be confusing to collapse it.
+ return false unless cause.conflict.conflict? || cause.other.conflict?
+
+ # If incompatibility's internal cause is numbered, collapsing it would
+ # get too noisy.
+ complex = cause.conflict.conflict? ? cause.conflict : cause.other
+
+ !@line_numbers.has_key?(complex)
+ end
+
+ def count_derivations(incompatibility)
+ if @derivations.has_key?(incompatibility)
+ @derivations[incompatibility] += 1
+ else
+ @derivations[incompatibility] = 1
+ if incompatibility.conflict?
+ cause = incompatibility.cause
+ count_derivations(cause.conflict)
+ count_derivations(cause.other)
+ end
+ end
+ end
+ end
+end
diff --git a/lib/rubygems/vendor/pub_grub/lib/pub_grub/incompatibility.rb b/lib/rubygems/vendor/pub_grub/lib/pub_grub/incompatibility.rb
new file mode 100644
index 0000000000..b5652b5e01
--- /dev/null
+++ b/lib/rubygems/vendor/pub_grub/lib/pub_grub/incompatibility.rb
@@ -0,0 +1,150 @@
+module Gem::PubGrub
+ class Incompatibility
+ ConflictCause = Struct.new(:incompatibility, :satisfier) do
+ alias_method :conflict, :incompatibility
+ alias_method :other, :satisfier
+ end
+
+ InvalidDependency = Struct.new(:package, :constraint) do
+ end
+
+ NoVersions = Struct.new(:constraint) do
+ end
+
+ attr_reader :terms, :cause
+
+ def initialize(terms, cause:, custom_explanation: nil)
+ @cause = cause
+ @terms = cleanup_terms(terms)
+ @custom_explanation = custom_explanation
+
+ if cause == :dependency && @terms.length != 2
+ raise ArgumentError, "a dependency Incompatibility must have exactly two terms. Got #{@terms.inspect}"
+ end
+ end
+
+ def hash
+ cause.hash ^ terms.hash
+ end
+
+ def eql?(other)
+ cause.eql?(other.cause) &&
+ terms.eql?(other.terms)
+ end
+
+ def failure?
+ terms.empty? || (terms.length == 1 && Package.root?(terms[0].package) && terms[0].positive?)
+ end
+
+ def conflict?
+ ConflictCause === cause
+ end
+
+ # Returns all external incompatibilities in this incompatibility's
+ # derivation graph
+ def external_incompatibilities
+ if conflict?
+ [
+ cause.conflict,
+ cause.other
+ ].flat_map(&:external_incompatibilities)
+ else
+ [this]
+ end
+ end
+
+ def to_s
+ return @custom_explanation if @custom_explanation
+
+ case cause
+ when :root
+ "(root dependency)"
+ when :dependency
+ "#{terms[0].to_s(allow_every: true)} depends on #{terms[1].invert}"
+ when Gem::PubGrub::Incompatibility::InvalidDependency
+ "#{terms[0].to_s(allow_every: true)} depends on unknown package #{cause.package}"
+ when Gem::PubGrub::Incompatibility::NoVersions
+ "no versions satisfy #{cause.constraint}"
+ when Gem::PubGrub::Incompatibility::ConflictCause
+ if failure?
+ "version solving has failed"
+ elsif terms.length == 1
+ term = terms[0]
+ if term.positive?
+ if term.constraint.any?
+ "#{term.package} cannot be used"
+ else
+ "#{term.to_s(allow_every: true)} cannot be used"
+ end
+ else
+ "#{term.invert} is required"
+ end
+ else
+ if terms.all?(&:positive?)
+ if terms.length == 2
+ "#{terms[0].to_s(allow_every: true)} is incompatible with #{terms[1]}"
+ else
+ "one of #{terms.map(&:to_s).join(" or ")} must be false"
+ end
+ elsif terms.all?(&:negative?)
+ if terms.length == 2
+ "either #{terms[0].invert} or #{terms[1].invert}"
+ else
+ "one of #{terms.map(&:invert).join(" or ")} must be true";
+ end
+ else
+ positive = terms.select(&:positive?)
+ negative = terms.select(&:negative?).map(&:invert)
+
+ if positive.length == 1
+ "#{positive[0].to_s(allow_every: true)} requires #{negative.join(" or ")}"
+ else
+ "if #{positive.join(" and ")} then #{negative.join(" or ")}"
+ end
+ end
+ end
+ else
+ raise "unhandled cause: #{cause.inspect}"
+ end
+ end
+
+ def inspect
+ "#<#{self.class} #{to_s}>"
+ end
+
+ def pretty_print(q)
+ q.group 2, "#<#{self.class}", ">" do
+ q.breakable
+ q.text to_s
+
+ q.breakable
+ q.text " caused by "
+ q.pp @cause
+ end
+ end
+
+ private
+
+ def cleanup_terms(terms)
+ terms.each do |term|
+ raise "#{term.inspect} must be a term" unless term.is_a?(Term)
+ end
+
+ if terms.length != 1 && ConflictCause === cause
+ terms = terms.reject do |term|
+ term.positive? && Package.root?(term.package)
+ end
+ end
+
+ # Optimized simple cases
+ return terms if terms.length <= 1
+ return terms if terms.length == 2 && terms[0].package != terms[1].package
+
+ terms.group_by(&:package).map do |package, common_terms|
+ common_terms.inject do |acc, term|
+ acc.intersect(term)
+ end
+ end
+ end
+ end
+end
diff --git a/lib/rubygems/vendor/pub_grub/lib/pub_grub/package.rb b/lib/rubygems/vendor/pub_grub/lib/pub_grub/package.rb
new file mode 100644
index 0000000000..6baa908f60
--- /dev/null
+++ b/lib/rubygems/vendor/pub_grub/lib/pub_grub/package.rb
@@ -0,0 +1,43 @@
+# frozen_string_literal: true
+
+module Gem::PubGrub
+ class Package
+
+ attr_reader :name
+
+ def initialize(name)
+ @name = name
+ end
+
+ def inspect
+ "#<#{self.class} #{name.inspect}>"
+ end
+
+ def <=>(other)
+ name <=> other.name
+ end
+
+ ROOT = Package.new(:root)
+ ROOT_VERSION = 0
+
+ def self.root
+ ROOT
+ end
+
+ def self.root_version
+ ROOT_VERSION
+ end
+
+ def self.root?(package)
+ if package.respond_to?(:root?)
+ package.root?
+ else
+ package == root
+ end
+ end
+
+ def to_s
+ name.to_s
+ end
+ end
+end
diff --git a/lib/rubygems/vendor/pub_grub/lib/pub_grub/partial_solution.rb b/lib/rubygems/vendor/pub_grub/lib/pub_grub/partial_solution.rb
new file mode 100644
index 0000000000..f6a6ae6964
--- /dev/null
+++ b/lib/rubygems/vendor/pub_grub/lib/pub_grub/partial_solution.rb
@@ -0,0 +1,121 @@
+require_relative 'assignment'
+
+module Gem::PubGrub
+ class PartialSolution
+ attr_reader :assignments, :decisions
+ attr_reader :attempted_solutions
+
+ def initialize
+ reset!
+
+ @attempted_solutions = 1
+ @backtracking = false
+ end
+
+ def decision_level
+ @decisions.length
+ end
+
+ def relation(term)
+ package = term.package
+ return :overlap if !@terms.key?(package)
+
+ @relation_cache[package][term] ||=
+ @terms[package].relation(term)
+ end
+
+ def satisfies?(term)
+ relation(term) == :subset
+ end
+
+ def derive(term, cause)
+ add_assignment(Assignment.new(term, cause, decision_level, assignments.length))
+ end
+
+ def satisfier(term)
+ assignment =
+ @assignments_by[term.package].bsearch do |assignment_by|
+ @cumulative_assignments[assignment_by].satisfies?(term)
+ end
+
+ assignment || raise("#{term} unsatisfied")
+ end
+
+ # A list of unsatisfied terms
+ def unsatisfied
+ @required.keys.reject do |package|
+ @decisions.key?(package)
+ end.map do |package|
+ @terms[package]
+ end
+ end
+
+ def decide(package, version)
+ @attempted_solutions += 1 if @backtracking
+ @backtracking = false;
+
+ decisions[package] = version
+ assignment = Assignment.decision(package, version, decision_level, assignments.length)
+ add_assignment(assignment)
+ end
+
+ def backtrack(previous_level)
+ @backtracking = true
+
+ new_assignments = assignments.select do |assignment|
+ assignment.decision_level <= previous_level
+ end
+
+ new_decisions = Hash[decisions.first(previous_level)]
+
+ reset!
+
+ @decisions = new_decisions
+
+ new_assignments.each do |assignment|
+ add_assignment(assignment)
+ end
+ end
+
+ private
+
+ def reset!
+ # { Array<Assignment> }
+ @assignments = []
+
+ # { Package => Array<Assignment> }
+ @assignments_by = Hash.new { |h,k| h[k] = [] }
+ @cumulative_assignments = {}.compare_by_identity
+
+ # { Package => Package::Version }
+ @decisions = {}
+
+ # { Package => Term }
+ @terms = {}
+ @relation_cache = Hash.new { |h,k| h[k] = {} }
+
+ # { Package => Boolean }
+ @required = {}
+ end
+
+ def add_assignment(assignment)
+ term = assignment.term
+ package = term.package
+
+ @assignments << assignment
+ @assignments_by[package] << assignment
+
+ @required[package] = true if term.positive?
+
+ if @terms.key?(package)
+ old_term = @terms[package]
+ @terms[package] = old_term.intersect(term)
+ else
+ @terms[package] = term
+ end
+ @relation_cache[package].clear
+
+ @cumulative_assignments[assignment] = @terms[package]
+ end
+ end
+end
diff --git a/lib/rubygems/vendor/pub_grub/lib/pub_grub/rubygems.rb b/lib/rubygems/vendor/pub_grub/lib/pub_grub/rubygems.rb
new file mode 100644
index 0000000000..60ca3ca2ea
--- /dev/null
+++ b/lib/rubygems/vendor/pub_grub/lib/pub_grub/rubygems.rb
@@ -0,0 +1,45 @@
+module Gem::PubGrub
+ module RubyGems
+ extend self
+
+ def requirement_to_range(requirement)
+ ranges = requirement.requirements.map do |(op, ver)|
+ case op
+ when "~>"
+ name = "~> #{ver}"
+ bump = ver.class.new(ver.bump.to_s + ".A")
+ VersionRange.new(name: name, min: ver, max: bump, include_min: true)
+ when ">"
+ VersionRange.new(min: ver)
+ when ">="
+ VersionRange.new(min: ver, include_min: true)
+ when "<"
+ VersionRange.new(max: ver)
+ when "<="
+ VersionRange.new(max: ver, include_max: true)
+ when "="
+ VersionRange.new(min: ver, max: ver, include_min: true, include_max: true)
+ when "!="
+ VersionRange.new(min: ver, max: ver, include_min: true, include_max: true).invert
+ else
+ raise "bad version specifier: #{op}"
+ end
+ end
+
+ ranges.inject(&:intersect)
+ end
+
+ def requirement_to_constraint(package, requirement)
+ Gem::PubGrub::VersionConstraint.new(package, range: requirement_to_range(requirement))
+ end
+
+ def parse_range(dep)
+ requirement_to_range(Gem::Requirement.new(dep))
+ end
+
+ def parse_constraint(package, dep)
+ range = parse_range(dep)
+ Gem::PubGrub::VersionConstraint.new(package, range: range)
+ end
+ end
+end
diff --git a/lib/rubygems/vendor/pub_grub/lib/pub_grub/solve_failure.rb b/lib/rubygems/vendor/pub_grub/lib/pub_grub/solve_failure.rb
new file mode 100644
index 0000000000..c4181d2b25
--- /dev/null
+++ b/lib/rubygems/vendor/pub_grub/lib/pub_grub/solve_failure.rb
@@ -0,0 +1,19 @@
+require_relative 'failure_writer'
+
+module Gem::PubGrub
+ class SolveFailure < StandardError
+ attr_reader :incompatibility
+
+ def initialize(incompatibility)
+ @incompatibility = incompatibility
+ end
+
+ def to_s
+ "Could not find compatible versions\n\n#{explanation}"
+ end
+
+ def explanation
+ @explanation ||= FailureWriter.new(@incompatibility).write
+ end
+ end
+end
diff --git a/lib/rubygems/vendor/pub_grub/lib/pub_grub/static_package_source.rb b/lib/rubygems/vendor/pub_grub/lib/pub_grub/static_package_source.rb
new file mode 100644
index 0000000000..9e1de7d7a1
--- /dev/null
+++ b/lib/rubygems/vendor/pub_grub/lib/pub_grub/static_package_source.rb
@@ -0,0 +1,61 @@
+require_relative 'package'
+require_relative 'rubygems'
+require_relative 'version_constraint'
+require_relative 'incompatibility'
+require_relative 'basic_package_source'
+
+module Gem::PubGrub
+ class StaticPackageSource < BasicPackageSource
+ class DSL
+ def initialize(packages, root_deps)
+ @packages = packages
+ @root_deps = root_deps
+ end
+
+ def root(deps:)
+ @root_deps.update(deps)
+ end
+
+ def add(name, version, deps: {})
+ version = Gem::Version.new(version)
+ @packages[name] ||= {}
+ raise ArgumentError, "#{name} #{version} declared twice" if @packages[name].key?(version)
+ @packages[name][version] = clean_deps(name, version, deps)
+ end
+
+ private
+
+ # Exclude redundant self-referencing dependencies
+ def clean_deps(name, version, deps)
+ deps.reject {|dep_name, req| name == dep_name && Gem::PubGrub::RubyGems.parse_range(req).include?(version) }
+ end
+ end
+
+ def initialize
+ @root_deps = {}
+ @packages = {}
+
+ yield DSL.new(@packages, @root_deps)
+
+ super()
+ end
+
+ def all_versions_for(package)
+ @packages[package].keys
+ end
+
+ def root_dependencies
+ @root_deps
+ end
+
+ def dependencies_for(package, version)
+ @packages[package][version]
+ end
+
+ def parse_dependency(package, dependency)
+ return false unless @packages.key?(package)
+
+ Gem::PubGrub::RubyGems.parse_constraint(package, dependency)
+ end
+ end
+end
diff --git a/lib/rubygems/vendor/pub_grub/lib/pub_grub/strategy.rb b/lib/rubygems/vendor/pub_grub/lib/pub_grub/strategy.rb
new file mode 100644
index 0000000000..b9874cdece
--- /dev/null
+++ b/lib/rubygems/vendor/pub_grub/lib/pub_grub/strategy.rb
@@ -0,0 +1,42 @@
+module Gem::PubGrub
+ class Strategy
+ def initialize(source)
+ @source = source
+
+ @root_package = Package.root
+ @root_version = Package.root_version
+
+ @version_indexes = Hash.new do |h,k|
+ if k == @root_package
+ h[k] = { @root_version => 0 }
+ else
+ h[k] = @source.all_versions_for(k).each.with_index.to_h
+ end
+ end
+ end
+
+ def next_package_and_version(unsatisfied)
+ package, range = next_term_to_try_from(unsatisfied)
+
+ [package, most_preferred_version_of(package, range)]
+ end
+
+ private
+
+ def most_preferred_version_of(package, range)
+ versions = @source.versions_for(package, range)
+
+ indexes = @version_indexes[package]
+ versions.min_by { |version| indexes[version] || Float::INFINITY }
+ end
+
+ def next_term_to_try_from(unsatisfied)
+ unsatisfied.min_by do |package, range|
+ matching_versions = @source.versions_for(package, range)
+ higher_versions = @source.versions_for(package, range.upper_invert)
+
+ [matching_versions.count <= 1 ? 0 : 1, higher_versions.count]
+ end
+ end
+ end
+end
diff --git a/lib/rubygems/vendor/pub_grub/lib/pub_grub/term.rb b/lib/rubygems/vendor/pub_grub/lib/pub_grub/term.rb
new file mode 100644
index 0000000000..bb26bdc911
--- /dev/null
+++ b/lib/rubygems/vendor/pub_grub/lib/pub_grub/term.rb
@@ -0,0 +1,105 @@
+module Gem::PubGrub
+ class Term
+ attr_reader :package, :constraint, :positive
+
+ def initialize(constraint, positive)
+ @constraint = constraint
+ @package = @constraint.package
+ @positive = positive
+ end
+
+ def to_s(allow_every: false)
+ if positive
+ @constraint.to_s(allow_every: allow_every)
+ else
+ "not #{@constraint}"
+ end
+ end
+
+ def hash
+ constraint.hash ^ positive.hash
+ end
+
+ def eql?(other)
+ positive == other.positive &&
+ constraint.eql?(other.constraint)
+ end
+
+ def invert
+ self.class.new(@constraint, !@positive)
+ end
+ alias_method :inverse, :invert
+
+ def intersect(other)
+ raise ArgumentError, "packages must match" if package != other.package
+
+ if positive? && other.positive?
+ self.class.new(constraint.intersect(other.constraint), true)
+ elsif negative? && other.negative?
+ self.class.new(constraint.union(other.constraint), false)
+ else
+ positive = positive? ? self : other
+ negative = negative? ? self : other
+ self.class.new(positive.constraint.intersect(negative.constraint.invert), true)
+ end
+ end
+
+ def difference(other)
+ intersect(other.invert)
+ end
+
+ def relation(other)
+ if positive? && other.positive?
+ constraint.relation(other.constraint)
+ elsif negative? && other.positive?
+ if constraint.allows_all?(other.constraint)
+ :disjoint
+ else
+ :overlap
+ end
+ elsif positive? && other.negative?
+ if !other.constraint.allows_any?(constraint)
+ :subset
+ elsif other.constraint.allows_all?(constraint)
+ :disjoint
+ else
+ :overlap
+ end
+ elsif negative? && other.negative?
+ if constraint.allows_all?(other.constraint)
+ :subset
+ else
+ :overlap
+ end
+ else
+ raise
+ end
+ end
+
+ def normalized_constraint
+ @normalized_constraint ||= positive ? constraint : constraint.invert
+ end
+
+ def satisfies?(other)
+ raise ArgumentError, "packages must match" unless package == other.package
+
+ relation(other) == :subset
+ end
+
+ def positive?
+ @positive
+ end
+
+ def negative?
+ !positive?
+ end
+
+ def empty?
+ @empty ||= normalized_constraint.empty?
+ end
+
+ def inspect
+ "#<#{self.class} #{self}>"
+ end
+ end
+end
diff --git a/lib/rubygems/vendor/pub_grub/lib/pub_grub/version.rb b/lib/rubygems/vendor/pub_grub/lib/pub_grub/version.rb
new file mode 100644
index 0000000000..5701bf0656
--- /dev/null
+++ b/lib/rubygems/vendor/pub_grub/lib/pub_grub/version.rb
@@ -0,0 +1,3 @@
+module Gem::PubGrub
+ VERSION = "0.5.0"
+end
diff --git a/lib/rubygems/vendor/pub_grub/lib/pub_grub/version_constraint.rb b/lib/rubygems/vendor/pub_grub/lib/pub_grub/version_constraint.rb
new file mode 100644
index 0000000000..ee998b3271
--- /dev/null
+++ b/lib/rubygems/vendor/pub_grub/lib/pub_grub/version_constraint.rb
@@ -0,0 +1,129 @@
+require_relative 'version_range'
+
+module Gem::PubGrub
+ class VersionConstraint
+ attr_reader :package, :range
+
+ # @param package [Gem::PubGrub::Package]
+ # @param range [Gem::PubGrub::VersionRange]
+ def initialize(package, range: nil)
+ @package = package
+ @range = range
+ end
+
+ def hash
+ package.hash ^ range.hash
+ end
+
+ def ==(other)
+ package == other.package &&
+ range == other.range
+ end
+
+ def eql?(other)
+ package.eql?(other.package) &&
+ range.eql?(other.range)
+ end
+
+ class << self
+ def exact(package, version)
+ range = VersionRange.new(min: version, max: version, include_min: true, include_max: true)
+ new(package, range: range)
+ end
+
+ def any(package)
+ new(package, range: VersionRange.any)
+ end
+
+ def empty(package)
+ new(package, range: VersionRange.empty)
+ end
+ end
+
+ def intersect(other)
+ unless package == other.package
+ raise ArgumentError, "Can only intersect between VersionConstraint of the same package"
+ end
+
+ self.class.new(package, range: range.intersect(other.range))
+ end
+
+ def union(other)
+ unless package == other.package
+ raise ArgumentError, "Can only intersect between VersionConstraint of the same package"
+ end
+
+ self.class.new(package, range: range.union(other.range))
+ end
+
+ def invert
+ new_range = range.invert
+ self.class.new(package, range: new_range)
+ end
+
+ def difference(other)
+ intersect(other.invert)
+ end
+
+ def allows_all?(other)
+ range.allows_all?(other.range)
+ end
+
+ def allows_any?(other)
+ range.intersects?(other.range)
+ end
+
+ def subset?(other)
+ other.allows_all?(self)
+ end
+
+ def overlap?(other)
+ other.allows_any?(self)
+ end
+
+ def disjoint?(other)
+ !overlap?(other)
+ end
+
+ def relation(other)
+ if subset?(other)
+ :subset
+ elsif overlap?(other)
+ :overlap
+ else
+ :disjoint
+ end
+ end
+
+ def to_s(allow_every: false)
+ if Package.root?(package)
+ package.to_s
+ elsif allow_every && any?
+ "every version of #{package}"
+ else
+ "#{package} #{constraint_string}"
+ end
+ end
+
+ def constraint_string
+ if any?
+ ">= 0"
+ else
+ range.to_s
+ end
+ end
+
+ def empty?
+ range.empty?
+ end
+
+ # Does this match every version of the package
+ def any?
+ range.any?
+ end
+
+ def inspect
+ "#<#{self.class} #{self}>"
+ end
+ end
+end
diff --git a/lib/rubygems/vendor/pub_grub/lib/pub_grub/version_range.rb b/lib/rubygems/vendor/pub_grub/lib/pub_grub/version_range.rb
new file mode 100644
index 0000000000..fa0e2d5742
--- /dev/null
+++ b/lib/rubygems/vendor/pub_grub/lib/pub_grub/version_range.rb
@@ -0,0 +1,423 @@
+# frozen_string_literal: true
+
+module Gem::PubGrub
+ class VersionRange
+ attr_reader :min, :max, :include_min, :include_max
+
+ alias_method :include_min?, :include_min
+ alias_method :include_max?, :include_max
+
+ class Empty < VersionRange
+ undef_method :min, :max
+ undef_method :include_min, :include_min?
+ undef_method :include_max, :include_max?
+
+ def initialize
+ end
+
+ def empty?
+ true
+ end
+
+ def eql?(other)
+ other.empty?
+ end
+
+ def hash
+ [].hash
+ end
+
+ def intersects?(_)
+ false
+ end
+
+ def intersect(other)
+ self
+ end
+
+ def allows_all?(other)
+ other.empty?
+ end
+
+ def include?(_)
+ false
+ end
+
+ def any?
+ false
+ end
+
+ def to_s
+ "(no versions)"
+ end
+
+ def ==(other)
+ other.class == self.class
+ end
+
+ def invert
+ VersionRange.any
+ end
+
+ def select_versions(_)
+ []
+ end
+ end
+
+ EMPTY = Empty.new
+ Empty.singleton_class.undef_method(:new)
+
+ def self.empty
+ EMPTY
+ end
+
+ def self.any
+ new
+ end
+
+ def initialize(min: nil, max: nil, include_min: false, include_max: false, name: nil)
+ raise ArgumentError, "Ranges without a lower bound cannot have include_min == true" if !min && include_min == true
+ raise ArgumentError, "Ranges without an upper bound cannot have include_max == true" if !max && include_max == true
+
+ @min = min
+ @max = max
+ @include_min = include_min
+ @include_max = include_max
+ @name = name
+ end
+
+ def hash
+ @hash ||= min.hash ^ max.hash ^ include_min.hash ^ include_max.hash
+ end
+
+ def eql?(other)
+ if other.is_a?(VersionRange)
+ !other.empty? &&
+ min.eql?(other.min) &&
+ max.eql?(other.max) &&
+ include_min.eql?(other.include_min) &&
+ include_max.eql?(other.include_max)
+ else
+ ranges.eql?(other.ranges)
+ end
+ end
+
+ def ranges
+ [self]
+ end
+
+ def include?(version)
+ compare_version(version) == 0
+ end
+
+ # Partitions passed versions into [lower, within, higher]
+ #
+ # versions must be sorted
+ def partition_versions(versions)
+ min_index =
+ if !min || versions.empty?
+ 0
+ elsif include_min?
+ (0..versions.size).bsearch { |i| versions[i].nil? || versions[i] >= min }
+ else
+ (0..versions.size).bsearch { |i| versions[i].nil? || versions[i] > min }
+ end
+
+ lower = versions.slice(0, min_index)
+ versions = versions.slice(min_index, versions.size)
+
+ max_index =
+ if !max || versions.empty?
+ versions.size
+ elsif include_max?
+ (0..versions.size).bsearch { |i| versions[i].nil? || versions[i] > max }
+ else
+ (0..versions.size).bsearch { |i| versions[i].nil? || versions[i] >= max }
+ end
+
+ [
+ lower,
+ versions.slice(0, max_index),
+ versions.slice(max_index, versions.size)
+ ]
+ end
+
+ # Returns versions which are included by this range.
+ #
+ # versions must be sorted
+ def select_versions(versions)
+ return versions if any?
+
+ partition_versions(versions)[1]
+ end
+
+ def compare_version(version)
+ if min
+ case version <=> min
+ when -1
+ return -1
+ when 0
+ return -1 if !include_min
+ when 1
+ end
+ end
+
+ if max
+ case version <=> max
+ when -1
+ when 0
+ return 1 if !include_max
+ when 1
+ return 1
+ end
+ end
+
+ 0
+ end
+
+ def strictly_lower?(other)
+ return false if !max || !other.min
+
+ case max <=> other.min
+ when 0
+ !include_max || !other.include_min
+ when -1
+ true
+ when 1
+ false
+ end
+ end
+
+ def strictly_higher?(other)
+ other.strictly_lower?(self)
+ end
+
+ def intersects?(other)
+ return false if other.empty?
+ return other.intersects?(self) if other.is_a?(VersionUnion)
+ !strictly_lower?(other) && !strictly_higher?(other)
+ end
+ alias_method :allows_any?, :intersects?
+
+ def intersect(other)
+ return other if other.empty?
+ return other.intersect(self) if other.is_a?(VersionUnion)
+
+ min_range =
+ if !min
+ other
+ elsif !other.min
+ self
+ else
+ case min <=> other.min
+ when 0
+ include_min ? other : self
+ when -1
+ other
+ when 1
+ self
+ end
+ end
+
+ max_range =
+ if !max
+ other
+ elsif !other.max
+ self
+ else
+ case max <=> other.max
+ when 0
+ include_max ? other : self
+ when -1
+ self
+ when 1
+ other
+ end
+ end
+
+ if !min_range.equal?(max_range) && min_range.min && max_range.max
+ case min_range.min <=> max_range.max
+ when -1
+ when 0
+ if !min_range.include_min || !max_range.include_max
+ return EMPTY
+ end
+ when 1
+ return EMPTY
+ end
+ end
+
+ VersionRange.new(
+ min: min_range.min,
+ include_min: min_range.include_min,
+ max: max_range.max,
+ include_max: max_range.include_max
+ )
+ end
+
+ # The span covered by two ranges
+ #
+ # If self and other are contiguous, this builds a union of the two ranges.
+ # (if they aren't you are probably calling the wrong method)
+ def span(other)
+ return self if other.empty?
+
+ min_range =
+ if !min
+ self
+ elsif !other.min
+ other
+ else
+ case min <=> other.min
+ when 0
+ include_min ? self : other
+ when -1
+ self
+ when 1
+ other
+ end
+ end
+
+ max_range =
+ if !max
+ self
+ elsif !other.max
+ other
+ else
+ case max <=> other.max
+ when 0
+ include_max ? self : other
+ when -1
+ other
+ when 1
+ self
+ end
+ end
+
+ VersionRange.new(
+ min: min_range.min,
+ include_min: min_range.include_min,
+ max: max_range.max,
+ include_max: max_range.include_max
+ )
+ end
+
+ def union(other)
+ return other.union(self) if other.is_a?(VersionUnion)
+
+ if contiguous_to?(other)
+ span(other)
+ else
+ VersionUnion.union([self, other])
+ end
+ end
+
+ def contiguous_to?(other)
+ return false if other.empty?
+ return true if any?
+
+ intersects?(other) || contiguous_below?(other) || contiguous_above?(other)
+ end
+
+ def contiguous_below?(other)
+ return false if !max || !other.min
+
+ max == other.min && (include_max || other.include_min)
+ end
+
+ def contiguous_above?(other)
+ other.contiguous_below?(self)
+ end
+
+ def allows_all?(other)
+ return true if other.empty?
+
+ if other.is_a?(VersionUnion)
+ return VersionUnion.new([self]).allows_all?(other)
+ end
+
+ return false if max && !other.max
+ return false if min && !other.min
+
+ if min
+ case min <=> other.min
+ when -1
+ when 0
+ return false if !include_min && other.include_min
+ when 1
+ return false
+ end
+ end
+
+ if max
+ case max <=> other.max
+ when -1
+ return false
+ when 0
+ return false if !include_max && other.include_max
+ when 1
+ end
+ end
+
+ true
+ end
+
+ def any?
+ !min && !max
+ end
+
+ def empty?
+ false
+ end
+
+ def to_s
+ @name ||= constraints.join(", ")
+ end
+
+ def inspect
+ "#<#{self.class} #{to_s}>"
+ end
+
+ def upper_invert
+ return self.class.empty unless max
+
+ VersionRange.new(min: max, include_min: !include_max)
+ end
+
+ def invert
+ return self.class.empty if any?
+
+ low = -> { VersionRange.new(max: min, include_max: !include_min) }
+ high = -> { VersionRange.new(min: max, include_min: !include_max) }
+
+ if !min
+ high.call
+ elsif !max
+ low.call
+ else
+ low.call.union(high.call)
+ end
+ end
+
+ def ==(other)
+ self.class == other.class &&
+ min == other.min &&
+ max == other.max &&
+ include_min == other.include_min &&
+ include_max == other.include_max
+ end
+
+ private
+
+ def constraints
+ return ["any"] if any?
+ return ["= #{min}"] if min.to_s == max.to_s
+
+ c = []
+ c << "#{include_min ? ">=" : ">"} #{min}" if min
+ c << "#{include_max ? "<=" : "<"} #{max}" if max
+ c
+ end
+
+ end
+end
diff --git a/lib/rubygems/vendor/pub_grub/lib/pub_grub/version_solver.rb b/lib/rubygems/vendor/pub_grub/lib/pub_grub/version_solver.rb
new file mode 100644
index 0000000000..3341d8fe3b
--- /dev/null
+++ b/lib/rubygems/vendor/pub_grub/lib/pub_grub/version_solver.rb
@@ -0,0 +1,236 @@
+require_relative 'partial_solution'
+require_relative 'term'
+require_relative 'incompatibility'
+require_relative 'solve_failure'
+require_relative 'strategy'
+
+module Gem::PubGrub
+ class VersionSolver
+ attr_reader :logger
+ attr_reader :source
+ attr_reader :solution
+ attr_reader :strategy
+
+ def initialize(source:, root: Package.root, strategy: Strategy.new(source), logger: Gem::PubGrub.logger)
+ @logger = logger
+
+ @source = source
+ @strategy = strategy
+
+ # { package => [incompatibility, ...]}
+ @incompatibilities = Hash.new do |h, k|
+ h[k] = []
+ end
+
+ @seen_incompatibilities = {}
+
+ @solution = PartialSolution.new
+
+ add_incompatibility Incompatibility.new([
+ Term.new(VersionConstraint.any(root), false)
+ ], cause: :root)
+
+ propagate(root)
+ end
+
+ def solved?
+ solution.unsatisfied.empty?
+ end
+
+ # Returns true if there is more work to be done, false otherwise
+ def work
+ unsatisfied_terms = solution.unsatisfied
+ if unsatisfied_terms.empty?
+ logger.info { "Solution found after #{solution.attempted_solutions} attempts:" }
+ solution.decisions.each do |package, version|
+ next if Package.root?(package)
+ logger.info { "* #{package} #{version}" }
+ end
+
+ return false
+ end
+
+ next_package = choose_package_version_from(unsatisfied_terms)
+ propagate(next_package)
+
+ true
+ end
+
+ def solve
+ while work; end
+
+ solution.decisions
+ end
+
+ alias_method :result, :solve
+
+ private
+
+ def propagate(initial_package)
+ changed = [initial_package]
+ while package = changed.shift
+ @incompatibilities[package].reverse_each do |incompatibility|
+ result = propagate_incompatibility(incompatibility)
+ if result == :conflict
+ root_cause = resolve_conflict(incompatibility)
+ changed.clear
+ changed << propagate_incompatibility(root_cause)
+ elsif result # should be a Package
+ changed << result
+ end
+ end
+ changed.uniq!
+ end
+ end
+
+ def propagate_incompatibility(incompatibility)
+ unsatisfied = nil
+ incompatibility.terms.each do |term|
+ relation = solution.relation(term)
+ if relation == :disjoint
+ return nil
+ elsif relation == :overlap
+ # If more than one term is inconclusive, we can't deduce anything
+ return nil if unsatisfied
+ unsatisfied = term
+ end
+ end
+
+ if !unsatisfied
+ return :conflict
+ end
+
+ logger.debug { "derived: #{unsatisfied.invert}" }
+
+ solution.derive(unsatisfied.invert, incompatibility)
+
+ unsatisfied.package
+ end
+
+ def choose_package_version_from(unsatisfied_terms)
+ remaining = unsatisfied_terms.map { |t| [t.package, t.constraint.range] }.to_h
+
+ package, version = strategy.next_package_and_version(remaining)
+
+ logger.debug { "attempting #{package} #{version}" }
+
+ if version.nil?
+ unsatisfied_term = unsatisfied_terms.find { |t| t.package == package }
+ add_incompatibility source.no_versions_incompatibility_for(package, unsatisfied_term)
+ return package
+ end
+
+ conflict = false
+
+ source.incompatibilities_for(package, version).each do |incompatibility|
+ if @seen_incompatibilities.include?(incompatibility)
+ logger.debug { "knew: #{incompatibility}" }
+ next
+ end
+ @seen_incompatibilities[incompatibility] = true
+
+ add_incompatibility incompatibility
+
+ conflict ||= incompatibility.terms.all? do |term|
+ term.package == package || solution.satisfies?(term)
+ end
+ end
+
+ unless conflict
+ logger.info { "selected #{package} #{version}" }
+
+ solution.decide(package, version)
+ else
+ logger.info { "conflict: #{conflict.inspect}" }
+ end
+
+ package
+ end
+
+ def resolve_conflict(incompatibility)
+ logger.info { "conflict: #{incompatibility}" }
+
+ new_incompatibility = nil
+
+ while !incompatibility.failure?
+ most_recent_term = nil
+ most_recent_satisfier = nil
+ difference = nil
+
+ previous_level = 1
+
+ incompatibility.terms.each do |term|
+ satisfier = solution.satisfier(term)
+
+ if most_recent_satisfier.nil?
+ most_recent_term = term
+ most_recent_satisfier = satisfier
+ elsif most_recent_satisfier.index < satisfier.index
+ previous_level = [previous_level, most_recent_satisfier.decision_level].max
+ most_recent_term = term
+ most_recent_satisfier = satisfier
+ difference = nil
+ else
+ previous_level = [previous_level, satisfier.decision_level].max
+ end
+
+ if most_recent_term == term
+ difference = most_recent_satisfier.term.difference(most_recent_term)
+ if difference.empty?
+ difference = nil
+ else
+ difference_satisfier = solution.satisfier(difference.inverse)
+ previous_level = [previous_level, difference_satisfier.decision_level].max
+ end
+ end
+ end
+
+ if previous_level < most_recent_satisfier.decision_level ||
+ most_recent_satisfier.decision?
+
+ logger.info { "backtracking to #{previous_level}" }
+ solution.backtrack(previous_level)
+
+ if new_incompatibility
+ add_incompatibility(new_incompatibility)
+ end
+
+ return incompatibility
+ end
+
+ new_terms = []
+ new_terms += incompatibility.terms - [most_recent_term]
+ new_terms += most_recent_satisfier.cause.terms.reject { |term|
+ term.package == most_recent_satisfier.term.package
+ }
+ if difference
+ new_terms << difference.invert
+ end
+
+ new_incompatibility = Incompatibility.new(new_terms, cause: Incompatibility::ConflictCause.new(incompatibility, most_recent_satisfier.cause))
+
+ if incompatibility.to_s == new_incompatibility.to_s
+ logger.info { "!! failed to resolve conflicts, this shouldn't have happened" }
+ break
+ end
+
+ incompatibility = new_incompatibility
+
+ partially = difference ? " partially" : ""
+ logger.info { "! #{most_recent_term} is#{partially} satisfied by #{most_recent_satisfier.term}" }
+ logger.info { "! which is caused by #{most_recent_satisfier.cause}" }
+ logger.info { "! thus #{incompatibility}" }
+ end
+
+ raise SolveFailure.new(incompatibility)
+ end
+
+ def add_incompatibility(incompatibility)
+ logger.debug { "fact: #{incompatibility}" }
+ incompatibility.terms.each do |term|
+ package = term.package
+ @incompatibilities[package] << incompatibility
+ end
+ end
+ end
+end
diff --git a/lib/rubygems/vendor/pub_grub/lib/pub_grub/version_union.rb b/lib/rubygems/vendor/pub_grub/lib/pub_grub/version_union.rb
new file mode 100644
index 0000000000..4166318a98
--- /dev/null
+++ b/lib/rubygems/vendor/pub_grub/lib/pub_grub/version_union.rb
@@ -0,0 +1,178 @@
+# frozen_string_literal: true
+
+module Gem::PubGrub
+ class VersionUnion
+ attr_reader :ranges
+
+ def self.normalize_ranges(ranges)
+ ranges = ranges.flat_map do |range|
+ range.ranges
+ end
+
+ ranges.reject!(&:empty?)
+
+ return [] if ranges.empty?
+
+ mins, ranges = ranges.partition { |r| !r.min }
+ original_ranges = mins + ranges.sort_by { |r| [r.min, r.include_min ? 0 : 1] }
+ ranges = [original_ranges.shift]
+ original_ranges.each do |range|
+ if ranges.last.contiguous_to?(range)
+ ranges << ranges.pop.span(range)
+ else
+ ranges << range
+ end
+ end
+
+ ranges
+ end
+
+ def self.union(ranges, normalize: true)
+ ranges = normalize_ranges(ranges) if normalize
+
+ if ranges.size == 0
+ VersionRange.empty
+ elsif ranges.size == 1
+ ranges[0]
+ else
+ new(ranges)
+ end
+ end
+
+ def initialize(ranges)
+ raise ArgumentError unless ranges.all? { |r| r.instance_of?(VersionRange) }
+ @ranges = ranges
+ end
+
+ def hash
+ ranges.hash
+ end
+
+ def eql?(other)
+ ranges.eql?(other.ranges)
+ end
+
+ def include?(version)
+ !!ranges.bsearch {|r| r.compare_version(version) }
+ end
+
+ def select_versions(all_versions)
+ versions = []
+ ranges.inject(all_versions) do |acc, range|
+ _, matching, higher = range.partition_versions(acc)
+ versions.concat matching
+ higher
+ end
+ versions
+ end
+
+ def intersects?(other)
+ my_ranges = ranges.dup
+ other_ranges = other.ranges.dup
+
+ my_range = my_ranges.shift
+ other_range = other_ranges.shift
+ while my_range && other_range
+ if my_range.intersects?(other_range)
+ return true
+ end
+
+ if !my_range.max || other_range.empty? || (other_range.max && other_range.max < my_range.max)
+ other_range = other_ranges.shift
+ else
+ my_range = my_ranges.shift
+ end
+ end
+ end
+ alias_method :allows_any?, :intersects?
+
+ def allows_all?(other)
+ my_ranges = ranges.dup
+
+ my_range = my_ranges.shift
+
+ other.ranges.all? do |other_range|
+ while my_range
+ break if my_range.allows_all?(other_range)
+ my_range = my_ranges.shift
+ end
+
+ !!my_range
+ end
+ end
+
+ def empty?
+ false
+ end
+
+ def any?
+ false
+ end
+
+ def intersect(other)
+ my_ranges = ranges.dup
+ other_ranges = other.ranges.dup
+ new_ranges = []
+
+ my_range = my_ranges.shift
+ other_range = other_ranges.shift
+ while my_range && other_range
+ new_ranges << my_range.intersect(other_range)
+
+ if !my_range.max || other_range.empty? || (other_range.max && other_range.max < my_range.max)
+ other_range = other_ranges.shift
+ else
+ my_range = my_ranges.shift
+ end
+ end
+ new_ranges.reject!(&:empty?)
+ VersionUnion.union(new_ranges, normalize: false)
+ end
+
+ def upper_invert
+ ranges.last.upper_invert
+ end
+
+ def invert
+ ranges.map(&:invert).inject(:intersect)
+ end
+
+ def union(other)
+ VersionUnion.union([self, other])
+ end
+
+ def to_s
+ output = []
+
+ ranges = self.ranges.dup
+ while !ranges.empty?
+ ne = []
+ range = ranges.shift
+ while !ranges.empty? && ranges[0].min.to_s == range.max.to_s
+ ne << range.max
+ range = range.span(ranges.shift)
+ end
+
+ ne.map! {|x| "!= #{x}" }
+ if ne.empty?
+ output << range.to_s
+ elsif range.any?
+ output << ne.join(', ')
+ else
+ output << "#{range}, #{ne.join(', ')}"
+ end
+ end
+
+ output.join(" OR ")
+ end
+
+ def inspect
+ "#<#{self.class} #{to_s}>"
+ end
+
+ def ==(other)
+ self.class == other.class &&
+ self.ranges == other.ranges
+ end
+ end
+end
diff --git a/lib/rubygems/vendor/resolv/lib/resolv.rb b/lib/rubygems/vendor/resolv/lib/resolv.rb
index 2825b1ea97..4f48e0642b 100644
--- a/lib/rubygems/vendor/resolv/lib/resolv.rb
+++ b/lib/rubygems/vendor/resolv/lib/resolv.rb
@@ -1,9 +1,10 @@
# frozen_string_literal: true
require 'socket'
-require_relative '../../timeout/lib/timeout'
+require_relative '../../../vendored_timeout'
require 'io/wait'
require_relative '../../../vendored_securerandom'
+require 'rbconfig'
# 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
@@ -33,7 +34,8 @@ require_relative '../../../vendored_securerandom'
class Gem::Resolv
- VERSION = "0.6.2"
+ # The version string
+ VERSION = "0.7.0"
##
# Looks up the first IP address for +name+.
@@ -173,21 +175,19 @@ class Gem::Resolv
class ResolvTimeout < Gem::Timeout::Error; end
- WINDOWS = /mswin|cygwin|mingw|bccwin/ =~ RUBY_PLATFORM || ::RbConfig::CONFIG['host_os'] =~ /mswin/
- private_constant :WINDOWS
-
##
# Gem::Resolv::Hosts is a hostname resolver that uses the system hosts file.
class Hosts
- if WINDOWS
+ if /mswin|cygwin|mingw|bccwin/ =~ RUBY_PLATFORM || ::RbConfig::CONFIG['host_os'] =~ /mswin/
begin
require 'win32/resolv' unless defined?(Win32::Resolv)
- DefaultFileName = Win32::Resolv.get_hosts_path || IO::NULL
+ hosts = Win32::Resolv.get_hosts_path || IO::NULL
rescue LoadError
end
end
- DefaultFileName ||= '/etc/hosts'
+ # The default file name for host names
+ DefaultFileName = hosts || '/etc/hosts'
##
# Creates a new Gem::Resolv::Hosts, using +filename+ for its data source.
@@ -525,6 +525,8 @@ class Gem::Resolv
}
end
+ # :stopdoc:
+
def fetch_resource(name, typeclass)
lazy_initialize
truncated = {}
@@ -1021,8 +1023,7 @@ class Gem::Resolv
def Config.default_config_hash(filename="/etc/resolv.conf")
if File.exist? filename
Config.parse_resolv_conf(filename)
- elsif WINDOWS
- require 'win32/resolv' unless defined?(Win32::Resolv)
+ elsif defined?(Win32::Resolv)
search, nameserver = Win32::Resolv.get_resolv_info
config_hash = {}
config_hash[:nameserver] = nameserver if nameserver
@@ -2926,15 +2927,21 @@ class Gem::Resolv
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
+ |[3-9][0-9]?/x # :nodoc:
+
+ ##
+ # Regular expression IPv4 addresses must match.
Regex = /\A(#{Regex256})\.(#{Regex256})\.(#{Regex256})\.(#{Regex256})\z/
+ ##
+ # Creates a new IPv4 address from +arg+ which may be:
+ #
+ # IPv4:: returns +arg+.
+ # String:: +arg+ must match the IPv4::Regex constant
+
def self.create(arg)
case arg
when IPv4
@@ -3243,13 +3250,15 @@ class Gem::Resolv
end
- module LOC
+ module LOC # :nodoc:
##
# A Gem::Resolv::LOC::Size
class Size
+ # Regular expression LOC size must match.
+
Regex = /^(\d+\.*\d*)[m]$/
##
@@ -3275,6 +3284,7 @@ class Gem::Resolv
end
end
+ # Internal use; use self.create.
def initialize(scalar)
@scalar = scalar
end
@@ -3312,6 +3322,8 @@ class Gem::Resolv
class Coord
+ # Regular expression LOC Coord must match.
+
Regex = /^(\d+)\s(\d+)\s(\d+\.\d+)\s([NESW])$/
##
@@ -3341,6 +3353,7 @@ class Gem::Resolv
end
end
+ # Internal use; use self.create.
def initialize(coordinates,orientation)
unless coordinates.kind_of?(String)
raise ArgumentError.new("Coord must be a 32bit unsigned integer in hex format: #{coordinates.inspect}")
@@ -3403,6 +3416,8 @@ class Gem::Resolv
class Alt
+ # Regular expression LOC Alt must match.
+
Regex = /^([+-]*\d+\.*\d*)[m]$/
##
@@ -3428,6 +3443,7 @@ class Gem::Resolv
end
end
+ # Internal use; use self.create.
def initialize(altitude)
@altitude = altitude
end
diff --git a/lib/rubygems/vendor/timeout/lib/timeout.rb b/lib/rubygems/vendor/timeout/lib/timeout.rb
index 455c504f47..376b8c0e2b 100644
--- a/lib/rubygems/vendor/timeout/lib/timeout.rb
+++ b/lib/rubygems/vendor/timeout/lib/timeout.rb
@@ -20,7 +20,7 @@
module Gem::Timeout
# The version
- VERSION = "0.4.3"
+ VERSION = "0.4.4"
# Internal error raised to when a timeout is triggered.
class ExitException < Exception
@@ -123,6 +123,9 @@ module Gem::Timeout
def self.ensure_timeout_thread_created
unless @timeout_thread and @timeout_thread.alive?
+ # If the Mutex is already owned we are in a signal handler.
+ # In that case, just return and let the main thread create the @timeout_thread.
+ return if TIMEOUT_THREAD_MUTEX.owned?
TIMEOUT_THREAD_MUTEX.synchronize do
unless @timeout_thread and @timeout_thread.alive?
@timeout_thread = create_timeout_thread
diff --git a/lib/rubygems/vendor/uri/lib/uri/common.rb b/lib/rubygems/vendor/uri/lib/uri/common.rb
index f0755f5fdc..e9bdfa6a07 100644
--- a/lib/rubygems/vendor/uri/lib/uri/common.rb
+++ b/lib/rubygems/vendor/uri/lib/uri/common.rb
@@ -30,6 +30,9 @@ module Gem::URI
remove_const(:Parser) if defined?(::Gem::URI::Parser)
const_set("Parser", parser.class)
+ remove_const(:PARSER) if defined?(::Gem::URI::PARSER)
+ const_set("PARSER", parser)
+
remove_const(:REGEXP) if defined?(::Gem::URI::REGEXP)
remove_const(:PATTERN) if defined?(::Gem::URI::PATTERN)
if Parser == RFC2396_Parser
@@ -49,10 +52,10 @@ module Gem::URI
warn "Gem::URI::REGEXP is obsolete. Use Gem::URI::RFC2396_REGEXP explicitly.", uplevel: 1 if $VERBOSE
Gem::URI::RFC2396_REGEXP
elsif value = RFC2396_PARSER.regexp[const]
- warn "Gem::URI::#{const} is obsolete. Use RFC2396_PARSER.regexp[#{const.inspect}] explicitly.", uplevel: 1 if $VERBOSE
+ warn "Gem::URI::#{const} is obsolete. Use Gem::URI::RFC2396_PARSER.regexp[#{const.inspect}] explicitly.", uplevel: 1 if $VERBOSE
value
elsif value = RFC2396_Parser.const_get(const)
- warn "Gem::URI::#{const} is obsolete. Use RFC2396_Parser::#{const} explicitly.", uplevel: 1 if $VERBOSE
+ warn "Gem::URI::#{const} is obsolete. Use Gem::URI::RFC2396_Parser::#{const} explicitly.", uplevel: 1 if $VERBOSE
value
else
super
@@ -92,6 +95,40 @@ module Gem::URI
end
module Schemes # :nodoc:
+ class << self
+ ReservedChars = ".+-"
+ EscapedChars = "\u01C0\u01C1\u01C2"
+ # Use Lo category chars as escaped chars for TruffleRuby, which
+ # does not allow Symbol categories as identifiers.
+
+ def escape(name)
+ unless name and name.ascii_only?
+ return nil
+ end
+ name.upcase.tr(ReservedChars, EscapedChars)
+ end
+
+ def unescape(name)
+ name.tr(EscapedChars, ReservedChars).encode(Encoding::US_ASCII).upcase
+ end
+
+ def find(name)
+ const_get(name, false) if name and const_defined?(name, false)
+ end
+
+ def register(name, klass)
+ unless scheme = escape(name)
+ raise ArgumentError, "invalid character as scheme - #{name}"
+ end
+ const_set(scheme, klass)
+ end
+
+ def list
+ constants.map { |name|
+ [unescape(name.to_s), const_get(name)]
+ }.to_h
+ end
+ end
end
private_constant :Schemes
@@ -104,7 +141,7 @@ module Gem::URI
# 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)
+ Schemes.register(scheme, klass)
end
# Returns a hash of the defined schemes:
@@ -122,14 +159,14 @@ module Gem::URI
#
# Related: Gem::URI.register_scheme.
def self.scheme_list
- Schemes.constants.map { |name|
- [name.to_s.upcase, Schemes.const_get(name)]
- }.to_h
+ Schemes.list
end
+ # :stopdoc:
INITIAL_SCHEMES = scheme_list
private_constant :INITIAL_SCHEMES
Ractor.make_shareable(INITIAL_SCHEMES) if defined?(Ractor)
+ # :startdoc:
# Returns a new object constructed from the given +scheme+, +arguments+,
# and +default+:
@@ -148,12 +185,10 @@ module Gem::URI
# # => #<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
+ const_name = Schemes.escape(scheme)
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 ||= Schemes.find(const_name)
uri_class ||= default
return uri_class.new(scheme, *arguments)
@@ -195,7 +230,7 @@ module Gem::URI
# ["fragment", "top"]]
#
def self.split(uri)
- DEFAULT_PARSER.split(uri)
+ PARSER.split(uri)
end
# Returns a new \Gem::URI object constructed from the given string +uri+:
@@ -205,11 +240,11 @@ module Gem::URI
# 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+
+ # It's recommended to first Gem::URI::RFC2396_PARSER.escape string +uri+
# if it may contain invalid Gem::URI characters.
#
def self.parse(uri)
- DEFAULT_PARSER.parse(uri)
+ PARSER.parse(uri)
end
# Merges the given Gem::URI strings +str+
@@ -265,7 +300,7 @@ module Gem::URI
#
def self.extract(str, schemes = nil, &block) # :nodoc:
warn "Gem::URI.extract is obsolete", uplevel: 1 if $VERBOSE
- DEFAULT_PARSER.extract(str, schemes, &block)
+ PARSER.extract(str, schemes, &block)
end
#
@@ -302,7 +337,7 @@ module Gem::URI
#
def self.regexp(schemes = nil)# :nodoc:
warn "Gem::URI.regexp is obsolete", uplevel: 1 if $VERBOSE
- DEFAULT_PARSER.make_regexp(schemes)
+ PARSER.make_regexp(schemes)
end
TBLENCWWWCOMP_ = {} # :nodoc:
@@ -407,6 +442,8 @@ module Gem::URI
_decode_uri_component(/%\h\h/, str, enc)
end
+ # Returns a string derived from the given string +str+ with
+ # Gem::URI-encoded characters matching +regexp+ according to +table+.
def self._encode_uri_component(regexp, table, str, enc)
str = str.to_s.dup
if str.encoding != Encoding::ASCII_8BIT
@@ -421,6 +458,8 @@ module Gem::URI
end
private_class_method :_encode_uri_component
+ # Returns a string decoding characters matching +regexp+ from the
+ # given \URL-encoded string +str+.
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)
@@ -859,6 +898,7 @@ 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:
#
+ # require 'rubygems/vendor/uri/lib/uri'
# # Returns a new Gem::URI.
# uri = Gem::URI('http://github.com/ruby/ruby')
# # => #<Gem::URI::HTTP http://github.com/ruby/ruby>
@@ -866,6 +906,8 @@ module Gem
# Gem::URI(uri)
# # => #<Gem::URI::HTTP http://github.com/ruby/ruby>
#
+ # You must require 'rubygems/vendor/uri/lib/uri' to use this method.
+ #
def URI(uri)
if uri.is_a?(Gem::URI::Generic)
uri
diff --git a/lib/rubygems/vendor/uri/lib/uri/file.rb b/lib/rubygems/vendor/uri/lib/uri/file.rb
index 768755fc2d..391c499716 100644
--- a/lib/rubygems/vendor/uri/lib/uri/file.rb
+++ b/lib/rubygems/vendor/uri/lib/uri/file.rb
@@ -47,7 +47,7 @@ module Gem::URI
# :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 = Gem::URI::File.build({:path => Gem::URI::RFC2396_PARSER.escape('/path/my file.txt')})
# uri3.to_s # => "file:///path/my%20file.txt"
#
def self.build(args)
diff --git a/lib/rubygems/vendor/uri/lib/uri/generic.rb b/lib/rubygems/vendor/uri/lib/uri/generic.rb
index 2eabe2b4e3..d0bc77dfda 100644
--- a/lib/rubygems/vendor/uri/lib/uri/generic.rb
+++ b/lib/rubygems/vendor/uri/lib/uri/generic.rb
@@ -73,7 +73,7 @@ module Gem::URI
#
# 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.
+ # then it does Gem::URI::RFC2396_PARSER.escape all Gem::URI components and tries again.
#
def self.build2(args)
begin
@@ -126,9 +126,9 @@ module Gem::URI
end
end
else
- component = self.class.component rescue ::Gem::URI::Generic::COMPONENT
+ component = self.component rescue ::Gem::URI::Generic::COMPONENT
raise ArgumentError,
- "expected Array of or Hash of components of #{self.class} (#{component.join(', ')})"
+ "expected Array of or Hash of components of #{self} (#{component.join(', ')})"
end
tmp << nil
@@ -186,18 +186,18 @@ module Gem::URI
if arg_check
self.scheme = scheme
- self.userinfo = userinfo
self.hostname = host
self.port = port
+ self.userinfo = userinfo
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_userinfo(userinfo)
self.set_path(path)
self.query = query
self.set_opaque(opaque)
@@ -284,7 +284,7 @@ module Gem::URI
# Returns the parser to be used.
#
- # Unless a Gem::URI::Parser is defined, DEFAULT_PARSER is used.
+ # Unless the +parser+ is defined, DEFAULT_PARSER is used.
#
def parser
if !defined?(@parser) || !@parser
@@ -315,7 +315,7 @@ module Gem::URI
end
#
- # Checks the scheme +v+ component against the Gem::URI::Parser Regexp for :SCHEME.
+ # Checks the scheme +v+ component against the +parser+ Regexp for :SCHEME.
#
def check_scheme(v)
if v && parser.regexp[:SCHEME] !~ v
@@ -385,7 +385,7 @@ module Gem::URI
#
# Checks the user +v+ component for RFC2396 compliance
- # and against the Gem::URI::Parser Regexp for :USERINFO.
+ # and against the +parser+ Regexp for :USERINFO.
#
# Can not have a registry or opaque component defined,
# with a user component defined.
@@ -409,7 +409,7 @@ module Gem::URI
#
# Checks the password +v+ component for RFC2396 compliance
- # and against the Gem::URI::Parser Regexp for :USERINFO.
+ # and against the +parser+ Regexp for :USERINFO.
#
# Can not have a registry or opaque component defined,
# with a user component defined.
@@ -511,7 +511,7 @@ module Gem::URI
user, password = split_userinfo(user)
end
@user = user
- @password = password if password
+ @password = password
[@user, @password]
end
@@ -522,7 +522,7 @@ module Gem::URI
# See also Gem::URI::Generic.user=.
#
def set_user(v)
- set_userinfo(v, @password)
+ set_userinfo(v, nil)
v
end
protected :set_user
@@ -574,6 +574,12 @@ module Gem::URI
@password
end
+ # Returns the authority info (array of user, password, host and
+ # port), if any is set. Or returns +nil+.
+ def authority
+ return @user, @password, @host, @port if @user || @password || @host || @port
+ end
+
# Returns the user component after Gem::URI decoding.
def decoded_user
Gem::URI.decode_uri_component(@user) if @user
@@ -586,7 +592,7 @@ module Gem::URI
#
# Checks the host +v+ component for RFC2396 compliance
- # and against the Gem::URI::Parser Regexp for :HOST.
+ # and against the +parser+ Regexp for :HOST.
#
# Can not have a registry or opaque component defined,
# with a host component defined.
@@ -615,6 +621,13 @@ module Gem::URI
end
protected :set_host
+ # Protected setter for the authority info (+user+, +password+, +host+
+ # and +port+). If +port+ is +nil+, +default_port+ will be set.
+ #
+ protected def set_authority(user, password, host, port = nil)
+ @user, @password, @host, @port = user, password, host, port || self.default_port
+ end
+
#
# == Args
#
@@ -639,6 +652,7 @@ module Gem::URI
def host=(v)
check_host(v)
set_host(v)
+ set_userinfo(nil)
v
end
@@ -675,7 +689,7 @@ module Gem::URI
#
# Checks the port +v+ component for RFC2396 compliance
- # and against the Gem::URI::Parser Regexp for :PORT.
+ # and against the +parser+ Regexp for :PORT.
#
# Can not have a registry or opaque component defined,
# with a port component defined.
@@ -729,6 +743,7 @@ module Gem::URI
def port=(v)
check_port(v)
set_port(v)
+ set_userinfo(nil)
port
end
@@ -748,7 +763,7 @@ module Gem::URI
#
# Checks the path +v+ component for RFC2396 compliance
- # and against the Gem::URI::Parser Regexp
+ # and against the +parser+ Regexp
# for :ABS_PATH and :REL_PATH.
#
# Can not have a opaque component defined,
@@ -853,7 +868,7 @@ module Gem::URI
#
# Checks the opaque +v+ component for RFC2396 compliance and
- # against the Gem::URI::Parser Regexp for :OPAQUE.
+ # against the +parser+ Regexp for :OPAQUE.
#
# Can not have a host, port, user, or path component defined,
# with an opaque component defined.
@@ -905,7 +920,7 @@ module Gem::URI
end
#
- # Checks the fragment +v+ component against the Gem::URI::Parser Regexp for :FRAGMENT.
+ # Checks the fragment +v+ component against the +parser+ Regexp for :FRAGMENT.
#
#
# == Args
@@ -1121,7 +1136,7 @@ module Gem::URI
base = self.dup
- authority = rel.userinfo || rel.host || rel.port
+ authority = rel.authority
# RFC2396, Section 5.2, 2)
if (rel.path.nil? || rel.path.empty?) && !authority && !rel.query
@@ -1134,9 +1149,7 @@ module Gem::URI
# RFC2396, Section 5.2, 4)
if authority
- base.set_userinfo(rel.userinfo)
- base.set_host(rel.host)
- base.set_port(rel.port || base.default_port)
+ base.set_authority(*authority)
base.set_path(rel.path)
elsif base.path && rel.path
base.set_path(merge_path(base.path, rel.path))
@@ -1527,7 +1540,7 @@ module Gem::URI
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
+ warn 'The environment variable HTTP_PROXY is discouraged. Please use http_proxy instead.', uplevel: 1
end
end
end
diff --git a/lib/rubygems/vendor/uri/lib/uri/http.rb b/lib/rubygems/vendor/uri/lib/uri/http.rb
index 658e9941dd..99c78358ac 100644
--- a/lib/rubygems/vendor/uri/lib/uri/http.rb
+++ b/lib/rubygems/vendor/uri/lib/uri/http.rb
@@ -61,6 +61,18 @@ module Gem::URI
super(tmp)
end
+ # Do not allow empty host names, as they are not allowed by RFC 3986.
+ def check_host(v)
+ ret = super
+
+ if ret && v.empty?
+ raise InvalidComponentError,
+ "bad component(expected host component): #{v}"
+ end
+
+ ret
+ end
+
#
# == Description
#
diff --git a/lib/rubygems/vendor/uri/lib/uri/rfc2396_parser.rb b/lib/rubygems/vendor/uri/lib/uri/rfc2396_parser.rb
index 04a1d0c869..2bb4181649 100644
--- a/lib/rubygems/vendor/uri/lib/uri/rfc2396_parser.rb
+++ b/lib/rubygems/vendor/uri/lib/uri/rfc2396_parser.rb
@@ -67,7 +67,7 @@ module Gem::URI
#
# == Synopsis
#
- # Gem::URI::Parser.new([opts])
+ # Gem::URI::RFC2396_Parser.new([opts])
#
# == Args
#
@@ -86,7 +86,7 @@ module Gem::URI
#
# == Examples
#
- # p = Gem::URI::Parser.new(:ESCAPED => "(?:%[a-fA-F0-9]{2}|%u[a-fA-F0-9]{4})")
+ # p = Gem::URI::RFC2396_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
#
@@ -108,12 +108,12 @@ module Gem::URI
# The Hash of patterns.
#
- # See also Gem::URI::Parser.initialize_pattern.
+ # See also #initialize_pattern.
attr_reader :pattern
# The Hash of Regexp.
#
- # See also Gem::URI::Parser.initialize_regexp.
+ # See also #initialize_regexp.
attr_reader :regexp
# Returns a split Gem::URI against +regexp[:ABS_URI]+.
@@ -202,8 +202,7 @@ module Gem::URI
#
# == Usage
#
- # p = Gem::URI::Parser.new
- # p.parse("ldap://ldap.example.com/dc=example?user=john")
+ # Gem::URI::RFC2396_PARSER.parse("ldap://ldap.example.com/dc=example?user=john")
# #=> #<Gem::URI::LDAP ldap://ldap.example.com/dc=example?user=john>
#
def parse(uri)
@@ -244,7 +243,7 @@ module Gem::URI
# If no +block+ given, then returns the result,
# else it calls +block+ for each element in result.
#
- # See also Gem::URI::Parser.make_regexp.
+ # See also #make_regexp.
#
def extract(str, schemes = nil)
if block_given?
@@ -263,7 +262,7 @@ module Gem::URI
unless schemes
@regexp[:ABS_URI_REF]
else
- /(?=#{Regexp.union(*schemes)}:)#{@pattern[:X_ABS_URI]}/x
+ /(?=(?i:#{Regexp.union(*schemes).source}):)#{@pattern[:X_ABS_URI]}/x
end
end
@@ -524,6 +523,8 @@ module Gem::URI
ret
end
+ # Returns +uri+ as-is if it is Gem::URI, or convert it to Gem::URI if it is
+ # a String.
def convert_to_uri(uri)
if uri.is_a?(Gem::URI::Generic)
uri
diff --git a/lib/rubygems/vendor/uri/lib/uri/version.rb b/lib/rubygems/vendor/uri/lib/uri/version.rb
index c2f617ce25..7ee577887b 100644
--- a/lib/rubygems/vendor/uri/lib/uri/version.rb
+++ b/lib/rubygems/vendor/uri/lib/uri/version.rb
@@ -1,6 +1,6 @@
module Gem::URI
# :stopdoc:
- VERSION_CODE = '010003'.freeze
- VERSION = VERSION_CODE.scan(/../).collect{|n| n.to_i}.join('.').freeze
+ VERSION = '1.1.1'.freeze
+ VERSION_CODE = VERSION.split('.').map{|s| s.rjust(2, '0')}.join.freeze
# :startdoc:
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_pub_grub.rb b/lib/rubygems/vendored_pub_grub.rb
new file mode 100644
index 0000000000..844d243ab3
--- /dev/null
+++ b/lib/rubygems/vendored_pub_grub.rb
@@ -0,0 +1,3 @@
+# frozen_string_literal: true
+
+require_relative "vendor/pub_grub/lib/pub_grub"
diff --git a/lib/rubygems/version.rb b/lib/rubygems/version.rb
index 25c412be4b..306733c1d7 100644
--- a/lib/rubygems/version.rb
+++ b/lib/rubygems/version.rb
@@ -1,6 +1,9 @@
# frozen_string_literal: true
-require_relative "deprecate"
+#--
+# Workaround for directly loading Gem::Version in some cases
+module Gem; end
+#++
##
# The Version class processes string versions into comparable
@@ -27,136 +30,153 @@ require_relative "deprecate"
# 4. 0.9
#
# If you want to specify a version restriction that includes both prereleases
-# and regular releases of the 1.x series this is the best way:
+# and regular releases of 1.x or later versions:
#
-# s.add_dependency 'example', '>= 1.0.0.a', '< 2.0.0'
+# s.add_dependency 'example', '>= 1.0.0.a'
#
# == How Software Changes
#
-# Users expect to be able to specify a version constraint that gives them
-# some reasonable expectation that new versions of a library will work with
-# their software if the version constraint is true, and not work with their
-# software if the version constraint is false. In other words, the perfect
-# system will accept all compatible versions of the library and reject all
-# incompatible versions.
-#
-# Libraries change in 3 ways (well, more than 3, but stay focused here!).
-#
-# 1. The change may be an implementation detail only and have no effect on
-# the client software.
-# 2. The change may add new features, but do so in a way that client software
-# written to an earlier version is still compatible.
-# 3. The change may change the public interface of the library in such a way
-# that old software is no longer compatible.
-#
-# Some examples are appropriate at this point. Suppose I have a Stack class
-# that supports a <tt>push</tt> and a <tt>pop</tt> method.
+# Libraries generally change in 3 ways:
#
-# === Examples of Category 1 changes:
+# 1. The change is an implementation detail, bug fix, security fix, or
+# optimization, and has no behavioral effect on the software using it.
#
-# * Switch from an array based implementation to a linked-list based
-# implementation.
-# * Provide an automatic (and transparent) backing store for large stacks.
+# 2. The change adds new features, and software using those new features is
+# not compatible with previous versions of the library, but software using
+# previous versions of the library is compatible with the change.
#
-# === Examples of Category 2 changes might be:
+# 3. The change modifies the public interface of some part of the library in
+# such a way that software that uses that part of the library must be
+# modified to work.
#
-# * Add a <tt>depth</tt> method to return the current depth of the stack.
-# * Add a <tt>top</tt> method that returns the current top of stack (without
-# changing the stack).
-# * Change <tt>push</tt> so that it returns the item pushed (previously it
-# had no usable return value).
-#
-# === Examples of Category 3 changes might be:
-#
-# * Changes <tt>pop</tt> so that it no longer returns a value (you must use
-# <tt>top</tt> to get the top of the stack).
-# * Rename the methods to <tt>push_item</tt> and <tt>pop_item</tt>.
-#
-# == RubyGems Rational Versioning
+# == RubyGems Rational Versioning (the recommended approach)
#
# * Versions shall be represented by three non-negative integers, separated
-# by periods (e.g. 3.1.4). The first integers is the "major" version
+# by periods (e.g. 3.1.4). The first integer is the "major" version
# number, the second integer is the "minor" version number, and the third
-# integer is the "build" number.
+# integer is the "patch" version number.
#
-# * A category 1 change (implementation detail) will increment the build
-# number.
+# * A category 1 change (implementation detail, bug fix, or security fix)
+# will increment the patch number.
#
# * A category 2 change (backwards compatible) will increment the minor
-# version number and reset the build number.
-#
-# * A category 3 change (incompatible) will increment the major build number
-# and reset the minor and build numbers.
-#
-# * Any "public" release of a gem should have a different version. Normally
-# that means incrementing the build number. This means a developer can
-# generate builds all day long, but as soon as they make a public release,
-# the version must be updated.
-#
-# === Examples
+# version number and reset the patch number.
#
-# Let's work through a project lifecycle using our Stack example from above.
+# * A category 3 change (incompatible) will increment the major version number
+# and reset the minor and patch numbers.
#
-# Version 0.0.1:: The initial Stack class is release.
-# Version 0.0.2:: Switched to a linked=list implementation because it is
-# cooler.
-# Version 0.1.0:: Added a <tt>depth</tt> method.
-# Version 1.0.0:: Added <tt>top</tt> and made <tt>pop</tt> return nil
-# (<tt>pop</tt> used to return the old top item).
-# Version 1.1.0:: <tt>push</tt> now returns the value pushed (it used it
-# return nil).
-# Version 1.1.1:: Fixed a bug in the linked list implementation.
-# Version 1.1.2:: Fixed a bug introduced in the last fix.
+# * Any "public" release of a gem should have a different version.
#
-# Client A needs a stack with basic push/pop capability. They write to the
-# original interface (no <tt>top</tt>), so their version constraint looks like:
+# == Optimistic Vs. Pessimistic Dependency Versioning
#
-# gem 'stack', '>= 0.0'
-#
-# Essentially, any version is OK with Client A. An incompatible change to
-# the library will cause them grief, but they are willing to take the chance
-# (we call Client A optimistic).
-#
-# Client B is just like Client A except for two things: (1) They use the
-# <tt>depth</tt> method and (2) they are worried about future
-# incompatibilities, so they write their version constraint like this:
-#
-# gem 'stack', '~> 0.1'
-#
-# The <tt>depth</tt> method was introduced in version 0.1.0, so that version
-# or anything later is fine, as long as the version stays below version 1.0
-# where incompatibilities are introduced. We call Client B pessimistic
-# because they are worried about incompatible future changes (it is OK to be
-# pessimistic!).
-#
-# == Preventing Version Catastrophe:
-#
-# From: https://www.zenspider.com/ruby/2008/10/rubygems-how-to-preventing-catastrophe.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
-# happens if fnord 3.0 comes out and it isn't backwards compatible
-# with 2.y.z? Your stuff will break as a result of using ">=". The
-# better route is to specify your dependency with an "approximate" version
-# specifier ("~>"). They're a tad confusing, so here is how the dependency
-# specifiers work:
-#
-# Specification From ... To (exclusive)
-# ">= 3.0" 3.0 ... &infin;
-# "~> 3.0" 3.0 ... 4.0
-# "~> 3.0.0" 3.0.0 ... 3.1
-# "~> 3.5" 3.5 ... 4.0
-# "~> 3.5.0" 3.5.0 ... 3.6
-# "~> 3" 3.0 ... 4.0
-#
-# For the last example, single-digit versions are automatically extended with
-# a zero to give a sensible result.
+# Users expect to be able to specify a version constraint that gives them
+# a reasonable expectation that new versions of a library will work with
+# their software if the version constraint is true, and not work with their
+# software if the version constraint is false. In other words, the perfect
+# system will accept all compatible versions of the library and reject all
+# incompatible versions. Unfortunately, there is no perfect system, as you
+# cannot predict the future. You can never know whether a future version of
+# a library will contain which type of change.
+#
+# There are two common outlooks on dependency versioning:
+#
+# 1. Optimistic. This does not set an upper bound on a dependency. It is
+# possible that a future version of a dependency will break the software,
+# and in that case, the dependency version will need to be updated and
+# changes will need to be made.
+#
+# 2. Pessimistic. This assumes all major version changes of a dependency will
+# break the software, and that patch or minor changes of a dependency will
+# not break the software. If there is a major version of a dependency
+# released, the dependency version must be updated in order to use it, even
+# if no code changes are actually needed.
+#
+# In general, optimistic versioning is superior to pessimistic versioning.
+# Pessimistic versioning is often wrong in both directions. Dependencies can
+# release patch or minor versions that contain incompatibilities. One
+# common reason is that a security fix may require a backwards-incompatible API
+# change. In this case, even though pessimistic versioning was used, it
+# didn't even save effort, as you still need to make code changes and adjust
+# dependency versions. Similarly, for all but the smallest dependencies, just
+# because the dependency made a backwards incompatible change to one interface
+# doesn't mean the dependency made a backwards incompatible change to an
+# interface that the software is using. It is a common problem that a
+# dependency will release a new major version and the software does not require
+# any changes in order to use it. In this case, being pessimistic results in
+# additional work for no benefit.
+#
+# When a library uses pessimistic versioning of dependencies, it causes
+# significant problems if that library is not diligent about updating
+# dependency versions and any library is depending on that library.
+# For example:
+#
+# * Library A is currently on release 1.2.3.
+#
+# * Library B is at version 2.3.4 and has a pessimistic dependency on
+# library A, using ~> 1.0 (>= 1.0, < 2).
+#
+# * Library C is at version 3.4.5 and has an optimistic dependency on
+# library A, using >= 1.0.
+#
+# * Library D has optimistic dependencies on both libraries B and C.
+#
+# * Library A releases a new major version, 2.0.0, with new features, which
+# is mostly backwards compatible, but does contain some backwards
+# incompatible changes.
+#
+# * Library B would work with A 2.0.0, but cannot use it due to pessimistic
+# versioning.
+#
+# * Library C wants to use the new features in the major release of library
+# A to implement its own new features, so it does so, bumps the
+# dependency version of A to >= 2.0, and releases version 3.5.0.
+#
+# * Library D cannot upgrade to the new version of library C, because it
+# depends on library B, which has a pessimistic dependency on library A.
+#
+# * Library C releases a security fix patch version 3.5.1 to fix a
+# vulnerability present in all previous versions.
+#
+# * Library D is now in a terrible situation. It cannot upgrade to library
+# C 3.5.1, as that requires library A > 2.0, because it depends on library
+# B, which requires library A > 1.0, < 2, even though library B would work
+# fine with library A 2.0.0.
+#
+# This type of situation brought on by pessimistic versioning is unfortunately
+# both common and serious in practice.
+#
+# This is not to say that optimistic versioning never causes a problem.
+# However, with optimistic versioning, if there is a problem, it can be solved
+# with the addition of a single dependency. For example, continuing the
+# previous example:
+#
+# * Library A releases a new major version, 3.0.0, which makes backwards
+# incompatible changes that break library C.
+#
+# * Until library C releases an updated version with new changes, library
+# D only needs to set a specific dependency on library A for > 2.0, < 3,
+# until library C is updated to work with the new version of library A.
+#
+# Both optimistic versioning and pessimistic versioning have problems in
+# certain cases. However, it's significantly easier to fix optimistic
+# versioning problems than to fix pessimistic versioning problems.
+#
+# That is not to say that pessimistic versioning is never appropriate. If the
+# dependency is a library that adds a single method, where any change resulting
+# in a major version bump would probably break a library using it, then using
+# pessimistic versioning may be warranted. Additionally, if a dependency has
+# already announced or committed backwards incompatible changes that would
+# break a library's use of it, then having that library use a pessimistic
+# version constraint would likely be warranted. However, outside of
+# specific situations, you should avoid using pessimistic versioning, as the
+# costs typically exceed the benefits.
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:
+ RADIX_OPT = [9_500, 3_500, 260_000, 22_227, 24].freeze # :nodoc:
##
# A string representation of this Version.
@@ -171,9 +191,7 @@ class Gem::Version
# True if the +version+ string matches RubyGems' requirements.
def self.correct?(version)
- nil_versions_are_discouraged! if version.nil?
-
- ANCHORED_VERSION_PATTERN.match?(version.to_s)
+ version.nil? || ANCHORED_VERSION_PATTERN.match?(version.to_s)
end
##
@@ -182,15 +200,10 @@ class Gem::Version
#
# ver1 = Version.create('1.3.17') # -> (Version object)
# ver2 = Version.create(ver1) # -> (ver1)
- # ver3 = Version.create(nil) # -> nil
def self.create(input)
if self === input # check yourself before you wreck yourself
input
- elsif input.nil?
- nil_versions_are_discouraged!
-
- nil
else
new input
end
@@ -206,14 +219,6 @@ class Gem::Version
@@all[version] ||= super
end
- def self.nil_versions_are_discouraged!
- unless Gem::Deprecate.skip
- warn "nil versions are discouraged and will be deprecated in Rubygems 4"
- end
- end
-
- private_class_method :nil_versions_are_discouraged!
-
##
# Constructs a Version from the +version+ string. A version string is a
# series of digits or ASCII letters separated by dots.
@@ -224,7 +229,7 @@ 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 = 0 if version.nil? || (version.is_a?(String) && /\A\s*\Z/.match?(version))
@version = version.to_s
@@ -236,6 +241,7 @@ class Gem::Version
end
@version = -@version
@segments = nil
+ @sort_key = compute_sort_key
end
##
@@ -337,7 +343,7 @@ class Gem::Version
end
##
- # A recommended version for use with a ~> Requirement.
+ # A recommended version for use with a >= Requirement.
def approximate_recommendation
segments = self.segments
@@ -346,7 +352,7 @@ class Gem::Version
segments.pop while segments.size > 2
segments.push 0 while segments.size < 2
- recommendation = "~> #{segments.join(".")}"
+ recommendation = ">= #{segments.join(".")}"
recommendation += ".a" if prerelease?
recommendation
end
@@ -354,55 +360,62 @@ class Gem::Version
##
# Compares this version with +other+ returning -1, 0, or 1 if the
# other version is larger, the same, or smaller than this
- # one. Attempts to compare to something that's not a
- # <tt>Gem::Version</tt> or a valid version String return +nil+.
+ # one. +other+ must be an instance of Gem::Version, comparing with
+ # other types may raise an exception.
def <=>(other)
- 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
+ if Gem::Version === other
+ # Fast path for comparison when available.
+ if @sort_key && other.sort_key
+ return @sort_key <=> other.sort_key
+ end
- lhsegments = canonical_segments
- rhsegments = other.canonical_segments
+ return 0 if @version == other.version || canonical_segments == other.canonical_segments
- lhsize = lhsegments.size
- rhsize = rhsegments.size
- limit = (lhsize > rhsize ? rhsize : lhsize)
+ lhsegments = canonical_segments
+ rhsegments = other.canonical_segments
- i = 0
+ lhsize = lhsegments.size
+ rhsize = rhsegments.size
+ limit = (lhsize > rhsize ? rhsize : lhsize)
- while i < limit
- lhs = lhsegments[i]
- rhs = rhsegments[i]
- i += 1
+ i = 0
- next if lhs == rhs
- return -1 if String === lhs && Numeric === rhs
- return 1 if Numeric === lhs && String === rhs
+ while i < limit
+ lhs = lhsegments[i]
+ rhs = rhsegments[i]
+ i += 1
- return lhs <=> rhs
- end
+ next if lhs == rhs
+ return -1 if String === lhs && Numeric === rhs
+ return 1 if Numeric === lhs && String === rhs
- lhs = lhsegments[i]
+ return lhs <=> rhs
+ end
- if lhs.nil?
- rhs = rhsegments[i]
+ lhs = lhsegments[i]
- while i < rhsize
- return 1 if String === rhs
- return -1 unless rhs.zero?
- rhs = rhsegments[i += 1]
- end
- else
- while i < lhsize
- return -1 if String === lhs
- return 1 unless lhs.zero?
- lhs = lhsegments[i += 1]
+ if lhs.nil?
+ rhs = rhsegments[i]
+
+ while i < rhsize
+ return 1 if String === rhs
+ return -1 unless rhs.zero?
+ rhs = rhsegments[i += 1]
+ end
+ else
+ while i < lhsize
+ return -1 if String === lhs
+ return 1 unless lhs.zero?
+ lhs = lhsegments[i += 1]
+ end
end
- end
- 0
+ 0
+ elsif String === other
+ return unless self.class.correct?(other)
+ self <=> self.class.new(other)
+ end
end
# remove trailing zeros segments before first letter or at the end of the version
@@ -426,6 +439,24 @@ class Gem::Version
protected
+ attr_reader :sort_key # :nodoc:
+
+ def compute_sort_key
+ return if prerelease?
+
+ segments = canonical_segments
+ return if segments.size > 5
+
+ key = 0
+ RADIX_OPT.each_with_index do |radix, i|
+ seg = segments.fetch(i, 0)
+ return nil if seg >= radix
+ key = key * radix + seg
+ end
+
+ key
+ 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.
diff --git a/lib/rubygems/win_platform.rb b/lib/rubygems/win_platform.rb
new file mode 100644
index 0000000000..10556871b2
--- /dev/null
+++ b/lib/rubygems/win_platform.rb
@@ -0,0 +1,30 @@
+# frozen_string_literal: true
+
+require "rbconfig"
+
+module Gem
+ ##
+ # An Array of Regexps that match windows Ruby platforms.
+
+ WIN_PATTERNS = [
+ /bccwin/i,
+ /djgpp/i,
+ /mingw/i,
+ /mswin/i,
+ /wince/i,
+ ].freeze
+
+ @@win_platform = nil
+
+ ##
+ # Is this a windows platform?
+
+ def self.win_platform?
+ if @@win_platform.nil?
+ ruby_platform = RbConfig::CONFIG["host_os"]
+ @@win_platform = !WIN_PATTERNS.find {|r| ruby_platform =~ r }.nil?
+ end
+
+ @@win_platform
+ end
+end
diff --git a/lib/rubygems/yaml_serializer.rb b/lib/rubygems/yaml_serializer.rb
index f89004f32a..b2547b136b 100644
--- a/lib/rubygems/yaml_serializer.rb
+++ b/lib/rubygems/yaml_serializer.rb
@@ -1,98 +1,845 @@
# frozen_string_literal: true
+unless defined?(Psych::VERSION)
+ module Psych
+ class Exception < ::RuntimeError; end
+ class SyntaxError < Exception; end
+ class DisallowedClass < Exception; end
+ class BadAlias < Exception; end
+ class AliasesNotEnabled < BadAlias; end
+ end
+end
+
module Gem
- # A stub yaml serializer that can handle only hashes and strings (as of now).
module YAMLSerializer
- module_function
+ Scalar = Struct.new(:value, :tag, :anchor, keyword_init: true)
- def dump(hash)
- yaml = String.new("---")
- yaml << dump_hash(hash)
+ Mapping = Struct.new(:pairs, :tag, :anchor, keyword_init: true) do
+ def initialize(pairs: [], tag: nil, anchor: nil)
+ super
+ end
+ end
+
+ Sequence = Struct.new(:items, :tag, :anchor, keyword_init: true) do
+ def initialize(items: [], tag: nil, anchor: nil)
+ super
+ end
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"
+ AliasRef = Struct.new(:name, keyword_init: true)
+
+ class Parser
+ MAPPING_KEY_RE = /^((?:[^#:]|:[^ ])+):(?:[ ]+(.*))?$/
+ MAX_NESTING_DEPTH = 1_000
+
+ def initialize(source)
+ @lines = source.split("\n")
+ @anchors = {}
+ @depth = 0
+ strip_document_prefix
+ end
+
+ def parse
+ return nil if @lines.empty?
+
+ root = nil
+ while @lines.any?
+ before = @lines.size
+ node = parse_node(-1)
+ @lines.shift if @lines.size == before && @lines.any?
+
+ if root.is_a?(Mapping) && node.is_a?(Mapping)
+ root.pairs.concat(node.pairs)
+ elsif root.nil?
+ root = node
+ end
+ end
+ root
+ end
+
+ private
+
+ def strip_document_prefix
+ return if @lines.empty?
+ return unless @lines[0]&.start_with?("---")
+
+ if @lines[0].strip == "---"
+ @lines.shift
+ else
+ @lines[0] = @lines[0].sub(/^---\s*/, "")
+ end
+ end
+
+ def parse_node(base_indent)
+ @depth += 1
+ raise_max_nesting! if @depth > MAX_NESTING_DEPTH
+
+ skip_blank_and_comments
+ return nil if @lines.empty?
+
+ line = @lines[0]
+ stripped = line.lstrip
+ indent = line.size - stripped.size
+ return nil if indent < base_indent
+
+ return parse_alias_ref if stripped.start_with?("*")
+
+ anchor = consume_anchor
+
+ if anchor
+ line = @lines[0]
+ stripped = line.lstrip
+ end
+
+ if stripped.start_with?("- ") || stripped == "-"
+ parse_sequence(indent, anchor)
+ elsif stripped.start_with?("\"") && stripped.end_with?("\"")
+ # We don't need to care about the following case here:
+ # 1. "value with comment" # ...
+ # 2. "key": "value"
+ #
+ # 1. must not happen because YAMLSerializer doesn't emit any
+ # comment. YAMLSerializer parses only YAML that is generated
+ # by YAMLSerializer.
+ #
+ # 2. must not happen because #parse_node isn't used non
+ # top-level mapping. Non top-level mapping always uses
+ # #parse_mapping. Top-level mapping never use the '"key":
+ # "value"' form because all top-level keys
+ # ("!ruby/object:Gem::Specification"'s keys) are known and
+ # #emit_specification doesn't quote anything.
+ parse_plain_scalar(indent, anchor)
+ elsif stripped.start_with?("'") && stripped.end_with?("'")
+ # See also the above note for double quotation.
+ parse_plain_scalar(indent, anchor)
+ elsif stripped =~ MAPPING_KEY_RE && !stripped.start_with?("!ruby/object:")
+ parse_mapping(indent, anchor)
+ elsif stripped.start_with?("!ruby/object:")
+ parse_tagged_node(indent, anchor)
+ elsif stripped.start_with?("|")
+ modifier = stripped[1..].to_s.strip
+ @lines.shift
+ register_anchor(anchor, Scalar.new(value: parse_block_scalar(indent, modifier)))
+ else
+ parse_plain_scalar(indent, anchor)
+ end
+ ensure
+ @depth -= 1
+ end
+
+ def parse_sequence(indent, anchor)
+ items = []
+ while @lines.any?
+ line = @lines[0]
+ stripped = line.lstrip
+ break unless line.size - stripped.size == indent &&
+ (stripped.start_with?("- ") || stripped == "-")
+ content = @lines.shift.lstrip[1..].strip
+ item_anchor, content = extract_item_anchor(content)
+ item = parse_sequence_item(content, indent)
+ items << register_anchor(item_anchor, item)
+ end
+ register_anchor(anchor, Sequence.new(items: items))
+ end
+
+ def parse_sequence_item(content, indent)
+ if content.start_with?("*")
+ parse_inline_alias(content)
+ elsif content.empty?
+ @lines.any? && current_indent > indent ? parse_node(indent) : nil
+ elsif content.start_with?("!ruby/object:")
+ parse_tagged_content(content.strip, indent)
+ elsif content.start_with?("!binary ")
+ parse_binary_value(content, indent)
+ elsif content.start_with?("-")
+ @lines.unshift("#{" " * (indent + 2)}#{content}")
+ parse_node(indent)
+ elsif content =~ MAPPING_KEY_RE && !content.start_with?("!ruby/object:")
+ @lines.unshift("#{" " * (indent + 2)}#{content}")
+ parse_node(indent)
+ elsif content.start_with?("|")
+ Scalar.new(value: parse_block_scalar(indent, content[1..].to_s.strip))
+ else
+ parse_inline_scalar(content, indent)
+ end
+ end
+
+ def parse_mapping(indent, anchor)
+ pairs = []
+ while @lines.any?
+ line = @lines[0]
+ stripped = line.lstrip
+ break unless line.size - stripped.size == indent &&
+ stripped =~ MAPPING_KEY_RE && !stripped.start_with?("!ruby/object:")
+ key = $1.strip
+ @lines.shift
+ val = strip_comment($2.to_s.strip)
+
+ key = decode_binary_tag(key) if key.start_with?("!binary ")
+
+ val_anchor, val = consume_value_anchor(val)
+ value = parse_mapping_value(val, indent)
+ value = register_anchor(val_anchor, value) if val_anchor
+
+ pairs << [Scalar.new(value: key), value]
+ end
+ register_anchor(anchor, Mapping.new(pairs: pairs))
+ end
+
+ def parse_mapping_value(val, indent)
+ if val.start_with?("*")
+ parse_inline_alias(val)
+ elsif val.start_with?("!ruby/object:")
+ parse_tagged_content(val.strip, indent)
+ elsif val.start_with?("!binary ")
+ parse_binary_value(val, indent)
+ elsif val.empty?
+ next_stripped = nil
+ next_indent = nil
+ if @lines.any?
+ next_stripped = @lines[0].lstrip
+ next_indent = @lines[0].size - next_stripped.size
+ end
+ if next_stripped &&
+ (next_stripped.start_with?("- ") || next_stripped == "-") &&
+ next_indent == indent
+ parse_node(indent)
else
- yaml << "\n- " << v.map {|s| s.to_s.gsub(/\s+/, " ").inspect }.join("\n- ") << "\n"
+ parse_node(indent + 1)
end
+ elsif val == "[]"
+ Sequence.new
+ elsif val == "{}"
+ Mapping.new
+ elsif val.start_with?("|")
+ Scalar.new(value: parse_block_scalar(indent, val[1..].to_s.strip))
else
- yaml << " " << v.to_s.gsub(/\s+/, " ").inspect << "\n"
+ parse_inline_scalar(val, indent)
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]
+ def parse_tagged_node(indent, anchor)
+ tag = @lines.shift.strip
+ nested = parse_node(indent)
+ apply_tag(nested, tag, anchor)
+ end
+
+ def parse_tagged_content(tag, indent)
+ nested = parse_node(indent)
+ apply_tag(nested, tag, nil)
+ end
+
+ def apply_tag(node, tag, anchor)
+ if node.is_a?(Mapping)
+ node.tag = tag
+ node.anchor = anchor
+ node
+ else
+ Mapping.new(pairs: [[Scalar.new(value: "value"), node]], tag: tag, anchor: anchor)
+ end
+ end
+
+ def parse_block_scalar(base_indent, modifier)
+ parts = []
+ block_indent = nil
+
+ while @lines.any?
+ line = @lines[0]
+ if line.strip.empty?
+ parts << "\n"
+ @lines.shift
else
- val = [] if val == "[]" # empty array
- stack[depth][key] = val
+ line_indent = line.size - line.lstrip.size
+ break if line_indent <= base_indent
+ block_indent ||= line_indent
+ parts << @lines.shift[block_indent..].to_s << "\n"
+ end
+ end
+
+ res = parts.join
+ res.chomp! if modifier == "-" && res.end_with?("\n")
+ res
+ end
+
+ def parse_plain_scalar(indent, anchor)
+ result = coerce(@lines.shift.strip)
+ return register_anchor(anchor, result) if result.is_a?(Mapping) || result.is_a?(Sequence)
+
+ while result.is_a?(String) && @lines.any? &&
+ !@lines[0].strip.empty? && current_indent > indent
+ result << " " << @lines.shift.strip
+ end
+ register_anchor(anchor, Scalar.new(value: result))
+ end
+
+ def parse_inline_scalar(val, indent)
+ result = coerce(val)
+ return result if result.is_a?(Mapping) || result.is_a?(Sequence)
+
+ while result.is_a?(String) && @lines.any? &&
+ !@lines[0].strip.empty? && current_indent > indent
+ result << " " << @lines.shift.strip
+ end
+ Scalar.new(value: result)
+ end
+
+ def coerce(val, depth = 0)
+ raise_max_nesting! if depth > MAX_NESTING_DEPTH
+
+ val = val.sub(/^! /, "") if val.start_with?("! ")
+
+ if val =~ /^"(.*)"$/
+ $1.gsub(/\\["nrt\\]/) do |m|
+ case m
+ when '\\"' then '"'
+ when "\\n" then "\n"
+ when "\\r" then "\r"
+ when "\\t" then "\t"
+ when "\\\\" then "\\"
+ end
+ end
+ elsif val =~ /^'(.*)'$/
+ $1.gsub(/''/, "'")
+ elsif val == "true"
+ true
+ elsif val == "false"
+ false
+ elsif ["~", "null"].include?(val)
+ nil
+ elsif val == "{}"
+ Mapping.new
+ elsif val =~ /^\[(.*)\]$/
+ inner = $1.strip
+ return Sequence.new if inner.empty?
+ items = inner.split(/\s*,\s*/).reject(&:empty?).map {|e| Scalar.new(value: coerce(e, depth + 1)) }
+ Sequence.new(items: items)
+ elsif /\A\d{4}-\d{2}-\d{2}([ T]\d{2}:\d{2}:\d{2})?/.match?(val)
+ begin
+ Time.new(val)
+ rescue ArgumentError
+ # date-only format like "2024-06-15" is not supported by Time.new
+ if /\A(\d{4})-(\d{2})-(\d{2})\z/.match(val)
+ Time.utc($1.to_i, $2.to_i, $3.to_i)
+ else
+ val
+ end
end
- elsif match = ARRAY_REGEX.match(line)
- _, val = match.captures
- val = strip_comment(val)
+ elsif /^-?\d+$/.match?(val)
+ val.to_i
+ else
+ val
+ end
+ end
- last_hash[last_empty_key] = [] unless last_hash[last_empty_key].is_a?(Array)
+ def decode_binary_tag(str)
+ content = str.sub(/\A!binary\s+/, "")
+ content = $1 if content =~ /\A"(.*)"\z/ || content =~ /\A'(.*)'\z/
+ content.unpack1("m")
+ end
- last_hash[last_empty_key].push(val)
+ def parse_binary_value(val, indent)
+ rest = val.sub(/\A!binary\s+/, "")
+ if rest.start_with?("|")
+ content = parse_block_scalar(indent, rest[1..].to_s.strip)
+ Scalar.new(value: content.unpack1("m"))
+ else
+ Scalar.new(value: decode_binary_tag(val))
end
end
- res
- end
- def strip_comment(val)
- if val.include?("#") && !val.start_with?("#")
- val.split("#", 2).first.strip
- else
+ def parse_alias_ref
+ AliasRef.new(name: @lines.shift.lstrip[1..].strip)
+ end
+
+ def parse_inline_alias(content)
+ AliasRef.new(name: content[1..].strip)
+ end
+
+ def current_indent
+ line = @lines[0]
+ line.size - line.lstrip.size
+ end
+
+ def consume_anchor
+ line = @lines[0]
+ stripped = line.lstrip
+ return nil unless stripped.start_with?("&") && stripped =~ /^&(\S+)\s+/
+
+ anchor = $1
+ @lines[0] = line.sub(/&#{Regexp.escape(anchor)}\s+/, "")
+ anchor
+ end
+
+ def extract_item_anchor(content)
+ return [nil, content] unless content =~ /^&(\S+)/
+
+ anchor = $1
+ [anchor, content.sub(/^&#{Regexp.escape(anchor)}\s*/, "")]
+ end
+
+ def consume_value_anchor(val)
+ return [nil, val] unless val =~ /^&(\S+)\s+/
+
+ anchor = $1
+ [anchor, val.sub(/^&#{Regexp.escape(anchor)}\s+/, "")]
+ end
+
+ def register_anchor(name, node)
+ if name
+ @anchors[name] = node
+ node.anchor = name if node.respond_to?(:anchor=)
+ end
+ node
+ end
+
+ def raise_max_nesting!
+ message = "exceeded maximum nesting depth (#{MAX_NESTING_DEPTH})"
+ if defined?(Psych::VERSION)
+ raise Psych::SyntaxError.new(nil, 0, 0, 0, message, nil)
+ else
+ raise Psych::SyntaxError, message
+ end
+ end
+
+ def skip_blank_and_comments
+ while @lines.any?
+ line = @lines[0]
+ stripped = line.lstrip
+ break unless stripped.empty? || stripped.start_with?("#")
+ @lines.shift
+ end
+ end
+
+ def strip_comment(val)
+ return val unless val.include?("#")
+ return val if val.lstrip.start_with?("#")
+
+ in_single = false
+ in_double = false
+ escape = false
+
+ val.each_char.with_index do |ch, i|
+ if escape
+ escape = false
+ next
+ end
+
+ if in_single
+ in_single = false if ch == "'"
+ elsif in_double
+ if ch == "\\"
+ escape = true
+ elsif ch == '"'
+ in_double = false
+ end
+ else
+ case ch
+ when "'" then in_single = true
+ when '"' then in_double = true
+ when "#" then return val[0...i].rstrip
+ end
+ end
+ end
+
val
end
end
- class << self
- private :dump_hash
+ class Builder
+ VALID_OPS = %w[= != > < >= <= ~>].freeze
+ ARRAY_FIELDS = %w[files test_files executables extra_rdoc_files].freeze
+ MAX_ALIAS_RESOLUTIONS = 1_000
+
+ def initialize(permitted_classes: [], permitted_symbols: [], aliases: true)
+ @permitted_classes = permitted_classes.map {|c| "!ruby/object:#{c}" }
+ @permitted_symbols = permitted_symbols
+ @aliases = aliases
+ @anchor_values = {}
+ @alias_count = 0
+ end
+
+ def build(node)
+ return nil if node.nil?
+
+ result = build_node(node)
+
+ if result.is_a?(Hash) && result[:tag] == "!ruby/object:Gem::Specification"
+ build_specification(result)
+ else
+ result
+ end
+ end
+
+ private
+
+ def build_node(node)
+ case node
+ when nil then nil
+ when AliasRef then resolve_alias(node)
+ when Scalar then store_anchor(node.anchor, node.value)
+ when Mapping then build_mapping(node)
+ when Sequence then store_anchor(node.anchor, node.items.map {|item| build_node(item) })
+ else node # already a Ruby object
+ end
+ end
+
+ def resolve_alias(node)
+ raise Psych::AliasesNotEnabled unless @aliases
+ @alias_count += 1
+ if @alias_count > MAX_ALIAS_RESOLUTIONS
+ raise Psych::BadAlias, "exceeded maximum alias resolutions (#{MAX_ALIAS_RESOLUTIONS})"
+ end
+ unless @anchor_values.key?(node.name)
+ klass = defined?(Psych::AnchorNotDefined) ? Psych::AnchorNotDefined : Psych::BadAlias
+ raise klass, "An alias referenced an unknown anchor: #{node.name}"
+ end
+ @anchor_values.fetch(node.name)
+ end
+
+ def store_anchor(name, value)
+ @anchor_values[name] = value if name
+ value
+ end
+
+ def build_mapping(node)
+ validate_tag!(node.tag) if node.tag
+
+ result = case node.tag
+ when "!ruby/object:Gem::Version"
+ build_version(node)
+ when "!ruby/object:Gem::Platform"
+ build_platform(node)
+ when "!ruby/object:Gem::Requirement", "!ruby/object:Gem::Version::Requirement"
+ build_requirement(node)
+ when "!ruby/object:Gem::Dependency"
+ build_dependency(node)
+ when nil
+ build_hash(node)
+ when "!ruby/object:Gem::Specification"
+ hash = build_hash(node)
+ hash[:tag] = node.tag
+ hash
+ else
+ raise ArgumentError, "undefined class/module #{node.tag.sub("!ruby/object:", "")}"
+ end
+
+ store_anchor(node.anchor, result)
+ end
+
+ def build_hash(node)
+ result = {}
+ node.pairs.each do |key_node, value_node|
+ key = key_node.is_a?(Scalar) ? key_node.value.to_s : build_node(key_node).to_s
+ value = build_node(value_node)
+
+ if ARRAY_FIELDS.include?(key)
+ value = normalize_array_field(value)
+ end
+
+ result[key] = value
+ end
+ result
+ end
+
+ def build_version(node)
+ hash = pairs_to_hash(node)
+ Gem::Version.new((hash["version"] || hash["value"]).to_s)
+ end
+
+ PLATFORM_FIELDS = %w[cpu os version].freeze
+ PLATFORM_ALLOWED_IVARS = %w[cpu os version value].freeze
+
+ def build_platform(node)
+ hash = pairs_to_hash(node)
+ if (hash.keys & PLATFORM_FIELDS).any?
+ Gem::Platform.new([hash["cpu"], hash["os"], hash["version"]])
+ elsif hash["value"].is_a?(Array)
+ # Malformed platform (e.g. sequence instead of mapping).
+ # Return the raw value so yaml_initialize handles it like Psych does.
+ hash["value"]
+ else
+ plat = Gem::Platform.allocate
+ hash.each do |k, v|
+ plat.instance_variable_set(:"@#{k}", v) if PLATFORM_ALLOWED_IVARS.include?(k)
+ end
+ plat
+ end
+ end
+
+ def build_requirement(node)
+ r = Gem::Requirement.allocate
+ hash = pairs_to_hash(node)
+ reqs = hash["requirements"] || hash["value"]
+
+ if reqs.is_a?(Array) && !reqs.empty?
+ safe_reqs = []
+ reqs.each do |item|
+ if item.is_a?(Array) && item.size == 2
+ op = item[0].to_s
+ ver = item[1]
+ if VALID_OPS.include?(op)
+ version_obj = ver.is_a?(Gem::Version) ? ver : Gem::Version.new(ver.to_s)
+ safe_reqs << [op, version_obj]
+ end
+ elsif item.is_a?(String)
+ parsed = Gem::Requirement.parse(item)
+ safe_reqs << parsed
+ end
+ rescue Gem::Requirement::BadRequirementError, Gem::Version::BadVersionError
+ # Skip malformed items silently
+ end
+ reqs = safe_reqs unless safe_reqs.empty?
+ end
+
+ r.instance_variable_set(:@requirements, reqs)
+ r
+ end
+
+ def build_dependency(node)
+ hash = pairs_to_hash(node)
+ d = Gem::Dependency.allocate
+ d.instance_variable_set(:@name, hash["name"])
+
+ d.instance_variable_set(:@requirement, hash["requirement"] || hash["version_requirements"])
+
+ raw_type = hash["type"]
+ if raw_type
+ name = raw_type.to_s.sub(/^:/, "")
+ validate_symbol!(name)
+ type = name.to_sym
+ else
+ type = :runtime
+ end
+ d.instance_variable_set(:@type, type)
+
+ d.instance_variable_set(:@prerelease, ["true", true].include?(hash["prerelease"]))
+ d.instance_variable_set(:@version_requirements, d.instance_variable_get(:@requirement))
+ d
+ end
+
+ def build_specification(hash)
+ spec = Gem::Specification.allocate
+
+ normalize_specification_version!(hash)
+ normalize_array_fields!(hash)
+
+ spec.yaml_initialize("!ruby/object:Gem::Specification", hash)
+ spec
+ end
+
+ def pairs_to_hash(node)
+ result = {}
+ node.pairs.each do |key_node, value_node|
+ key = key_node.is_a?(Scalar) ? key_node.value.to_s : build_node(key_node).to_s
+ result[key] = build_node(value_node)
+ end
+ result
+ end
+
+ def validate_tag!(tag)
+ return if @permitted_classes.include?(tag)
+ raise_disallowed_class!(tag)
+ end
+
+ def raise_disallowed_class!(tag)
+ if defined?(Psych::VERSION)
+ raise Psych::DisallowedClass.new("load", tag)
+ else
+ raise Psych::DisallowedClass, "Tried to load unspecified class: #{tag}"
+ end
+ end
+
+ def validate_symbol!(name)
+ return if @permitted_symbols.empty? || @permitted_symbols.include?(name)
+
+ label = ":#{name}"
+ if defined?(Psych::VERSION)
+ raise Psych::DisallowedClass.new("load", label)
+ else
+ raise Psych::DisallowedClass, "Tried to load unspecified class: #{label}"
+ end
+ end
+
+ def normalize_specification_version!(hash)
+ val = hash["specification_version"]
+ return unless val && !val.is_a?(Integer)
+ hash["specification_version"] = val.to_i if val.is_a?(String) && /\A\d+\z/.match?(val)
+ end
+
+ def normalize_array_fields!(hash)
+ ARRAY_FIELDS.each do |field|
+ hash[field] = normalize_array_field(hash[field]) if hash[field]
+ end
+ end
+
+ def normalize_array_field(value)
+ if value.is_a?(Hash)
+ value.values.flatten.compact
+ elsif !value.is_a?(Array) && value
+ [value].flatten.compact
+ else
+ value
+ end
+ end
+ end
+
+ class Emitter
+ def emit(obj)
+ "---#{emit_node(obj, 0)}"
+ end
+
+ private
+
+ def emit_node(obj, indent, quote: false)
+ case obj
+ when Gem::Specification then emit_specification(obj, indent)
+ when Gem::Version then emit_version(obj, indent)
+ when Gem::Platform then emit_platform(obj, indent)
+ when Gem::Requirement then emit_requirement(obj, indent)
+ when Gem::Dependency then emit_dependency(obj, indent)
+ when Hash then emit_hash(obj, indent)
+ when Array then emit_array(obj, indent)
+ when Time then emit_time(obj)
+ when String then emit_string(obj, indent, quote: quote)
+ when NilClass
+ "\n"
+ when Numeric, Symbol, TrueClass, FalseClass
+ " #{obj.inspect}\n"
+ else
+ " #{obj.to_s.inspect}\n"
+ end
+ end
+
+ def emit_specification(spec, indent)
+ parts = [" !ruby/object:Gem::Specification\n"]
+ parts << "#{pad(indent)}name:#{emit_node(spec.name, indent + 2)}"
+ parts << "#{pad(indent)}version:#{emit_node(spec.version, indent + 2)}"
+ parts << "#{pad(indent)}platform: #{spec.platform}\n"
+ if spec.platform.to_s != spec.original_platform.to_s
+ parts << "#{pad(indent)}original_platform: #{spec.original_platform}\n"
+ end
+
+ attributes = Gem::Specification.attribute_names.map(&:to_s).sort - %w[name version platform]
+ attributes.each do |name|
+ val = spec.instance_variable_get("@#{name}")
+ next if val.nil?
+ parts << "#{pad(indent)}#{name}:#{emit_node(val, indent + 2)}"
+ end
+
+ res = parts.join
+ res << "\n" unless res.end_with?("\n")
+ res
+ end
+
+ def emit_version(ver, indent)
+ " !ruby/object:Gem::Version\n" \
+ "#{pad(indent)}version: #{emit_node(ver.version.to_s, indent + 2).lstrip}"
+ end
+
+ def emit_platform(plat, indent)
+ " !ruby/object:Gem::Platform\n" \
+ "#{pad(indent)}cpu:#{emit_node(plat.cpu, indent + 2)}" \
+ "#{pad(indent)}os:#{emit_node(plat.os, indent + 2)}" \
+ "#{pad(indent)}version:#{emit_node(plat.version, indent + 2)}"
+ end
+
+ def emit_requirement(req, indent)
+ " !ruby/object:Gem::Requirement\n" \
+ "#{pad(indent)}requirements:#{emit_node(req.requirements, indent + 2)}"
+ end
+
+ def emit_dependency(dep, indent)
+ [
+ " !ruby/object:Gem::Dependency\n",
+ "#{pad(indent)}name: #{emit_node(dep.name, indent + 2).lstrip}",
+ "#{pad(indent)}requirement:#{emit_node(dep.requirement, indent + 2)}",
+ "#{pad(indent)}type: #{emit_node(dep.type, indent + 2).lstrip}",
+ "#{pad(indent)}prerelease: #{emit_node(dep.prerelease?, indent + 2).lstrip}",
+ "#{pad(indent)}version_requirements:#{emit_node(dep.requirement, indent + 2)}",
+ ].join
+ end
+
+ def emit_hash(hash, indent)
+ if hash.empty?
+ " {}\n"
+ else
+ parts = ["\n"]
+ hash.each do |k, v|
+ is_symbol = k.is_a?(Symbol) || (k.is_a?(String) && k.start_with?(":"))
+ key_str = k.is_a?(Symbol) ? k.inspect : k.to_s
+ parts << "#{pad(indent)}#{key_str}:#{emit_node(v, indent + 2, quote: is_symbol)}"
+ end
+ parts.join
+ end
+ end
+
+ def emit_array(arr, indent)
+ if arr.empty?
+ " []\n"
+ else
+ parts = ["\n"]
+ arr.each do |v|
+ parts << "#{pad(indent)}-#{emit_node(v, indent + 2)}"
+ end
+ parts.join
+ end
+ end
+
+ def emit_time(time)
+ " #{time.utc.strftime("%Y-%m-%d %H:%M:%S.%N Z")}\n"
+ end
+
+ def emit_string(str, indent, quote: false)
+ if str.include?("\n")
+ emit_block_scalar(str, indent)
+ elsif needs_quoting?(str, quote)
+ " #{str.to_s.inspect}\n"
+ else
+ " #{str}\n"
+ end
+ end
+
+ def emit_block_scalar(str, indent)
+ parts = [str.end_with?("\n") ? " |\n" : " |-\n"]
+ str.each_line do |line|
+ parts << "#{pad(indent + 2)}#{line}"
+ end
+ res = parts.join
+ res << "\n" unless res.end_with?("\n")
+ res
+ end
+
+ def needs_quoting?(str, quote)
+ quote || str.empty? ||
+ str =~ /^[!*&:@%$]/ || str =~ /^-?\d+(\.\d+)?$/ || str =~ /^[<>=-]/ ||
+ str == "true" || str == "false" || str == "nil" ||
+ str.include?(":") || str.include?("#") || str.include?("[") || str.include?("]") ||
+ str.include?("{") || str.include?("}") || str.include?(",")
+ end
+
+ def pad(indent)
+ " " * indent
+ end
+ end
+
+ module_function
+
+ def dump(obj)
+ Emitter.new.emit(obj)
+ end
+
+ def load(str, permitted_classes: [], permitted_symbols: [], aliases: true)
+ raise TypeError, "no implicit conversion of nil into String" if str.nil?
+ return nil if str.empty?
+
+ ast = Parser.new(str).parse
+ return nil if ast.nil?
+
+ Builder.new(
+ permitted_classes: permitted_classes,
+ permitted_symbols: permitted_symbols,
+ aliases: aliases
+ ).build(ast)
end
end
end
diff --git a/lib/set/subclass_compatible.rb b/lib/set/subclass_compatible.rb
new file mode 100644
index 0000000000..f43c34f6a2
--- /dev/null
+++ b/lib/set/subclass_compatible.rb
@@ -0,0 +1,347 @@
+# frozen_string_literal: true
+
+# :markup: markdown
+#
+# set/subclass_compatible.rb - Provides compatibility for set subclasses
+#
+# Copyright (c) 2002-2024 Akinori MUSHA <knu@iDaemons.org>
+#
+# Documentation by Akinori MUSHA and Gavin Sinclair.
+#
+# All rights reserved. You can redistribute and/or modify it under the same
+# terms as Ruby.
+
+
+class Set
+ # This module is automatically included in subclasses of Set, to
+ # make them backwards compatible with the pure-Ruby set implementation
+ # used before Ruby 4. Users who want to use Set subclasses without
+ # this compatibility layer should subclass from Set::CoreSet.
+ #
+ # Note that Set subclasses that access `@hash` are not compatible even
+ # with this support. Such subclasses must be updated to support Ruby 4.
+ module SubclassCompatible
+ module ClassMethods
+ def [](*ary)
+ new(ary)
+ end
+ end
+
+ # Creates a new set containing the elements of the given enumerable
+ # object.
+ #
+ # If a block is given, the elements of enum are preprocessed by the
+ # given block.
+ #
+ # Set.new([1, 2]) #=> #<Set: {1, 2}>
+ # Set.new([1, 2, 1]) #=> #<Set: {1, 2}>
+ # Set.new([1, 'c', :s]) #=> #<Set: {1, "c", :s}>
+ # Set.new(1..5) #=> #<Set: {1, 2, 3, 4, 5}>
+ # Set.new([1, 2, 3]) { |x| x * x } #=> #<Set: {1, 4, 9}>
+ def initialize(enum = nil, &block) # :yields: o
+ enum.nil? and return
+
+ if block
+ do_with_enum(enum) { |o| add(block[o]) }
+ else
+ merge(enum)
+ end
+ end
+
+ def do_with_enum(enum, &block) # :nodoc:
+ if enum.respond_to?(:each_entry)
+ enum.each_entry(&block) if block
+ elsif enum.respond_to?(:each)
+ enum.each(&block) if block
+ else
+ raise ArgumentError, "value must be enumerable"
+ end
+ end
+ private :do_with_enum
+
+ def replace(enum)
+ if enum.instance_of?(self.class)
+ super
+ else
+ do_with_enum(enum) # make sure enum is enumerable before calling clear
+ clear
+ merge(enum)
+ end
+ end
+
+ def to_set(&block)
+ return self if instance_of?(Set) && block.nil?
+ Set.new(self, &block)
+ end
+
+ def flatten_merge(set, seen = {}) # :nodoc:
+ set.each { |e|
+ if e.is_a?(Set)
+ case seen[e_id = e.object_id]
+ when true
+ raise ArgumentError, "tried to flatten recursive Set"
+ when false
+ next
+ end
+
+ seen[e_id] = true
+ flatten_merge(e, seen)
+ seen[e_id] = false
+ else
+ add(e)
+ end
+ }
+
+ self
+ end
+ protected :flatten_merge
+
+ def flatten
+ self.class.new.flatten_merge(self)
+ end
+
+ def flatten!
+ replace(flatten()) if any?(Set)
+ end
+
+ def superset?(set)
+ case
+ when set.instance_of?(self.class)
+ super
+ when set.is_a?(Set)
+ size >= set.size && set.all?(self)
+ else
+ raise ArgumentError, "value must be a set"
+ end
+ end
+ alias >= superset?
+
+ def proper_superset?(set)
+ case
+ when set.instance_of?(self.class)
+ super
+ when set.is_a?(Set)
+ size > set.size && set.all?(self)
+ else
+ raise ArgumentError, "value must be a set"
+ end
+ end
+ alias > proper_superset?
+
+ def subset?(set)
+ case
+ when set.instance_of?(self.class)
+ super
+ when set.is_a?(Set)
+ size <= set.size && all?(set)
+ else
+ raise ArgumentError, "value must be a set"
+ end
+ end
+ alias <= subset?
+
+ def proper_subset?(set)
+ case
+ when set.instance_of?(self.class)
+ super
+ when set.is_a?(Set)
+ size < set.size && all?(set)
+ else
+ raise ArgumentError, "value must be a set"
+ end
+ end
+ alias < proper_subset?
+
+ def <=>(set)
+ return unless set.is_a?(Set)
+
+ case size <=> set.size
+ when -1 then -1 if proper_subset?(set)
+ when +1 then +1 if proper_superset?(set)
+ else 0 if self.==(set)
+ end
+ end
+
+ def intersect?(set)
+ case set
+ when Set
+ if size < set.size
+ any?(set)
+ else
+ set.any?(self)
+ end
+ when Enumerable
+ set.any?(self)
+ else
+ raise ArgumentError, "value must be enumerable"
+ end
+ end
+
+ def disjoint?(set)
+ !intersect?(set)
+ end
+
+ def add?(o)
+ add(o) unless include?(o)
+ end
+
+ def delete?(o)
+ delete(o) if include?(o)
+ end
+
+ def delete_if(&block)
+ block_given? or return enum_for(__method__) { size }
+ select(&block).each { |o| delete(o) }
+ self
+ end
+
+ def keep_if(&block)
+ block_given? or return enum_for(__method__) { size }
+ reject(&block).each { |o| delete(o) }
+ self
+ end
+
+ def collect!
+ block_given? or return enum_for(__method__) { size }
+ set = self.class.new
+ each { |o| set << yield(o) }
+ replace(set)
+ end
+ alias map! collect!
+
+ def reject!(&block)
+ block_given? or return enum_for(__method__) { size }
+ n = size
+ delete_if(&block)
+ self if size != n
+ end
+
+ def select!(&block)
+ block_given? or return enum_for(__method__) { size }
+ n = size
+ keep_if(&block)
+ self if size != n
+ end
+
+ alias filter! select!
+
+ def merge(*enums, **nil)
+ enums.each do |enum|
+ if enum.instance_of?(self.class)
+ super(enum)
+ else
+ do_with_enum(enum) { |o| add(o) }
+ end
+ end
+
+ self
+ end
+
+ def subtract(enum)
+ do_with_enum(enum) { |o| delete(o) }
+ self
+ end
+
+ def |(enum)
+ dup.merge(enum)
+ end
+ alias + |
+ alias union |
+
+ def -(enum)
+ dup.subtract(enum)
+ end
+ alias difference -
+
+ def &(enum)
+ n = self.class.new
+ if enum.is_a?(Set)
+ if enum.size > size
+ each { |o| n.add(o) if enum.include?(o) }
+ else
+ enum.each { |o| n.add(o) if include?(o) }
+ end
+ else
+ do_with_enum(enum) { |o| n.add(o) if include?(o) }
+ end
+ n
+ end
+ alias intersection &
+
+ def ^(enum)
+ n = self.class.new(enum)
+ each { |o| n.add(o) unless n.delete?(o) }
+ n
+ end
+
+ def ==(other)
+ if self.equal?(other)
+ true
+ elsif other.instance_of?(self.class)
+ super
+ elsif other.is_a?(Set) && self.size == other.size
+ other.all? { |o| include?(o) }
+ else
+ false
+ end
+ end
+
+ def eql?(o) # :nodoc:
+ return false unless o.is_a?(Set)
+ super
+ end
+
+ def classify
+ block_given? or return enum_for(__method__) { size }
+
+ h = {}
+
+ each { |i|
+ (h[yield(i)] ||= self.class.new).add(i)
+ }
+
+ h
+ end
+
+ def join(separator=nil)
+ to_a.join(separator)
+ end
+
+ InspectKey = :__inspect_key__ # :nodoc:
+
+ # Returns a string containing a human-readable representation of the
+ # set ("#<Set: {element1, element2, ...}>").
+ def inspect
+ ids = (Thread.current[InspectKey] ||= [])
+
+ if ids.include?(object_id)
+ return sprintf('#<%s: {...}>', self.class.name)
+ end
+
+ ids << object_id
+ begin
+ return sprintf('#<%s: {%s}>', self.class, to_a.inspect[1..-2])
+ ensure
+ ids.pop
+ end
+ end
+
+ alias to_s inspect
+
+ def pretty_print(pp) # :nodoc:
+ pp.group(1, sprintf('#<%s:', self.class.name), '>') {
+ pp.breakable
+ pp.group(1, '{', '}') {
+ pp.seplist(self) { |o|
+ pp.pp o
+ }
+ }
+ }
+ end
+
+ def pretty_print_cycle(pp) # :nodoc:
+ pp.text sprintf('#<%s: {%s}>', self.class.name, empty? ? '' : '...')
+ end
+ end
+ private_constant :SubclassCompatible
+end
diff --git a/lib/singleton.rb b/lib/singleton.rb
index b8e43a7794..74aec8903c 100644
--- a/lib/singleton.rb
+++ b/lib/singleton.rb
@@ -92,9 +92,10 @@
# p a.strip # => nil
#
module Singleton
+ # The version string
VERSION = "0.3.0"
- module SingletonInstanceMethods
+ module SingletonInstanceMethods # :nodoc:
# Raises a TypeError to prevent cloning.
def clone
raise TypeError, "can't clone instance of singleton #{self.class}"
@@ -143,11 +144,11 @@ module Singleton
end
end
- def self.module_with_class_methods
+ def self.module_with_class_methods # :nodoc:
SingletonClassMethods
end
- module SingletonClassProperties
+ module SingletonClassProperties # :nodoc:
def self.included(c)
# extending an object with Singleton is a bad idea
@@ -196,10 +197,10 @@ module Singleton
end
if defined?(Ractor)
- module RactorLocalSingleton
+ module RactorLocalSingleton # :nodoc:
include Singleton::SingletonInstanceMethods
- module RactorLocalSingletonClassMethods
+ module RactorLocalSingletonClassMethods # :nodoc:
include Singleton::SingletonClassMethods
def instance
set_mutex(Thread::Mutex.new) if Ractor.current[mutex_key].nil?
diff --git a/lib/syntax_suggest/api.rb b/lib/syntax_suggest/api.rb
index 0f82d8362a..5054efa888 100644
--- a/lib/syntax_suggest/api.rb
+++ b/lib/syntax_suggest/api.rb
@@ -7,25 +7,8 @@ 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 "prism"
module SyntaxSuggest
# Used to indicate a default value that cannot
@@ -35,14 +18,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
@@ -152,20 +127,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
-
- Prism.parse(source).failure?
- end
- else
- 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
- Ripper.new(source).tap(&:parse).error?
- end
+ Prism.parse(source).failure?
end
# SyntaxSuggest.valid? [Private]
@@ -219,7 +185,6 @@ require_relative "explain_syntax"
require_relative "clean_document"
# Helpers
-require_relative "lex_all"
require_relative "code_line"
require_relative "code_block"
require_relative "block_expand"
@@ -231,3 +196,5 @@ require_relative "priority_engulf_queue"
require_relative "pathname_from_message"
require_relative "display_invalid_blocks"
require_relative "parse_blocks_from_indent_line"
+require_relative "visitor"
+require_relative "token"
diff --git a/lib/syntax_suggest/clean_document.rb b/lib/syntax_suggest/clean_document.rb
index ba307af46e..94c68d8ad4 100644
--- a/lib/syntax_suggest/clean_document.rb
+++ b/lib/syntax_suggest/clean_document.rb
@@ -66,27 +66,9 @@ module SyntaxSuggest
#
# All of these problems are fixed by joining the whole heredoc into a single
# line.
- #
- # ## Comments and whitespace
- #
- # Comments can throw off the way the lexer tells us that the line
- # logically belongs with the next line. This is valid ruby but
- # results in a different lex output than before:
- #
- # 1 User.
- # 2 where(name: "schneems").
- # 3 # Comment here
- # 4 first
- #
- # To handle this we can replace comment lines with empty lines
- # and then re-lex the source. This removal and re-lexing preserves
- # line index and document size, but generates an easier to work with
- # document.
- #
class CleanDocument
def initialize(source:)
- lines = clean_sweep(source: source)
- @document = CodeLine.from_source(lines.join, lines: lines)
+ @document = CodeLine.from_source(source)
end
# Call all of the document "cleaners"
@@ -110,62 +92,6 @@ module SyntaxSuggest
@document.join
end
- # Remove comments
- #
- # replace with empty newlines
- #
- # source = <<~'EOM'
- # # Comment 1
- # puts "hello"
- # # Comment 2
- # puts "world"
- # EOM
- #
- # lines = CleanDocument.new(source: source).lines
- # expect(lines[0].to_s).to eq("\n")
- # expect(lines[1].to_s).to eq("puts "hello")
- # expect(lines[2].to_s).to eq("\n")
- # expect(lines[3].to_s).to eq("puts "world")
- #
- # Important: This must be done before lexing.
- #
- # After this change is made, we lex the document because
- # removing comments can change how the doc is parsed.
- #
- # For example:
- #
- # values = LexAll.new(source: <<~EOM))
- # User.
- # # comment
- # where(name: 'schneems')
- # EOM
- # expect(
- # values.count {|v| v.type == :on_ignored_nl}
- # ).to eq(1)
- #
- # After the comment is removed:
- #
- # values = LexAll.new(source: <<~EOM))
- # User.
- #
- # where(name: 'schneems')
- # EOM
- # expect(
- # values.count {|v| v.type == :on_ignored_nl}
- # ).to eq(2)
- #
- def clean_sweep(source:)
- # Match comments, but not HEREDOC strings with #{variable} interpolation
- # https://rubular.com/r/HPwtW9OYxKUHXQ
- source.lines.map do |line|
- if line.match?(/^\s*#([^{].*|)$/)
- $/
- else
- line
- end
- end
- end
-
# Smushes all heredoc lines into one line
#
# source = <<~'EOM'
@@ -182,11 +108,11 @@ module SyntaxSuggest
start_index_stack = []
heredoc_beg_end_index = []
lines.each do |line|
- line.lex.each do |lex_value|
- case lex_value.type
- when :on_heredoc_beg
+ line.tokens.each do |token|
+ case token.type
+ when :HEREDOC_START
start_index_stack << line.index
- when :on_heredoc_end
+ when :HEREDOC_END
start_index = start_index_stack.pop
end_index = line.index
heredoc_beg_end_index << [start_index, end_index]
@@ -212,20 +138,10 @@ module SyntaxSuggest
# expect(lines[0].to_s).to eq(source)
# expect(lines[1].to_s).to eq("")
#
- # The one known case this doesn't handle is:
- #
- # Ripper.lex <<~EOM
- # a &&
- # b ||
- # c
- # EOM
- #
- # For some reason this introduces `on_ignore_newline` but with BEG type
- #
def join_consecutive!
- consecutive_groups = @document.select(&:ignore_newline_not_beg?).map do |code_line|
+ consecutive_groups = @document.select(&:consecutive?).map do |code_line|
take_while_including(code_line.index..) do |line|
- line.ignore_newline_not_beg?
+ line.consecutive?
end
end
@@ -273,16 +189,17 @@ module SyntaxSuggest
# Join group into the first line
@document[line.index] = CodeLine.new(
- lex: lines.map(&:lex).flatten,
+ tokens: lines.map(&:tokens).flatten,
line: lines.join,
- index: line.index
+ index: line.index,
+ consecutive: false
)
# Hide the rest of the lines
lines[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: [])
+ @document[line.index] = CodeLine.new(line: "", index: line.index, tokens: [], consecutive: false)
end
end
self
diff --git a/lib/syntax_suggest/code_line.rb b/lib/syntax_suggest/code_line.rb
index 58197e95d0..7fb1aae26a 100644
--- a/lib/syntax_suggest/code_line.rb
+++ b/lib/syntax_suggest/code_line.rb
@@ -26,23 +26,57 @@ module SyntaxSuggest
# Returns an array of CodeLine objects
# from the source string
- def self.from_source(source, lines: nil)
- lines ||= source.lines
- lex_array_for_line = LexAll.new(source: source, source_lines: lines).each_with_object(Hash.new { |h, k| h[k] = [] }) { |lex, hash| hash[lex.line] << lex }
- lines.map.with_index do |line, index|
+ def self.from_source(source)
+ source = +source
+ parse_result = Prism.parse_lex(source)
+ ast, tokens = parse_result.value
+
+ clean_comments!(source, parse_result.comments)
+
+ visitor = Visitor.new
+ visitor.visit(ast)
+ tokens.sort_by! { |token, _state| token.location.start_line }
+
+ prev_token = nil
+ tokens.map! do |token, _state|
+ prev_token = Token.new(token, prev_token, visitor)
+ end
+
+ tokens_for_line = tokens.each_with_object(Hash.new { |h, k| h[k] = [] }) { |token, hash| hash[token.line] << token }
+ source.lines.map.with_index do |line, index|
CodeLine.new(
line: line,
index: index,
- lex: lex_array_for_line[index + 1]
+ tokens: tokens_for_line[index + 1],
+ consecutive: visitor.consecutive_lines.include?(index + 1)
)
end
end
- attr_reader :line, :index, :lex, :line_number, :indent
- def initialize(line:, index:, lex:)
- @lex = lex
+ # Remove comments that apear on their own in source. They will never be the cause
+ # of syntax errors and are just visual noise. Example:
+ #
+ # source = +<<~RUBY
+ # # Comment-only line
+ # foo # Inline comment
+ # RUBY
+ # CodeLine.clean_comments!(source, Prism.parse(source).comments)
+ # source # => "\nfoo # Inline comment\n"
+ def self.clean_comments!(source, comments)
+ # Iterate backwards since we are modifying the source in place and must preserve
+ # the offsets. Prism comments are sorted by their location in the source.
+ comments.reverse_each do |comment|
+ next if comment.trailing?
+ source.bytesplice(comment.location.start_offset, comment.location.length, "")
+ end
+ end
+
+ attr_reader :line, :index, :tokens, :line_number, :indent
+ def initialize(line:, index:, tokens:, consecutive:)
+ @tokens = tokens
@line = line
@index = index
+ @consecutive = consecutive
@original = line
@line_number = @index + 1
strip_line = line.dup
@@ -151,92 +185,36 @@ module SyntaxSuggest
index <=> other.index
end
- # [Not stable API]
- #
- # Lines that have a `on_ignored_nl` type token and NOT
- # a `BEG` type seem to be a good proxy for the ability
- # to join multiple lines into one.
- #
- # This predicate method is used to determine when those
- # two criteria have been met.
- #
- # The one known case this doesn't handle is:
- #
- # Ripper.lex <<~EOM
- # a &&
- # b ||
- # c
- # EOM
- #
- # For some reason this introduces `on_ignore_newline` but with BEG type
- def ignore_newline_not_beg?
- @ignore_newline_not_beg
+ # Can this line be logically joined together
+ # with the following line? Determined by walking
+ # the AST
+ def consecutive?
+ @consecutive
end
- # Determines if the given line has a trailing slash
+ # Determines if the given line has a trailing slash.
+ # Simply check if the line contains a backslash after
+ # the content of the last token.
#
# lines = CodeLine.from_source(<<~EOM)
# it "foo" \
# 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
-
- last.token == TRAILING_SLASH
- end
+ def trailing_slash?
+ return unless (last = @tokens.last)
+ @line.byteindex(TRAILING_SLASH, last.location.end_column) != nil
end
- # Endless method detection
- #
- # From https://github.com/ruby/irb/commit/826ae909c9c93a2ddca6f9cfcd9c94dbf53d44ab
- # Detecting a "oneliner" seems to need a state machine.
- # This can be done by looking mostly at the "state" (last value):
- #
- # ENDFN -> BEG (token = '=' ) -> END
- #
private def set_kw_end
- oneliner_count = 0
- in_oneliner_def = nil
-
kw_count = 0
end_count = 0
- @ignore_newline_not_beg = false
- @lex.each do |lex|
- kw_count += 1 if lex.is_kw?
- end_count += 1 if lex.is_end?
-
- if lex.type == :on_ignored_nl
- @ignore_newline_not_beg = !lex.expr_beg?
- end
-
- if in_oneliner_def.nil?
- in_oneliner_def = :ENDFN if lex.state.allbits?(Ripper::EXPR_ENDFN)
- elsif lex.state.allbits?(Ripper::EXPR_ENDFN)
- # Continue
- elsif lex.state.allbits?(Ripper::EXPR_BEG)
- in_oneliner_def = :BODY if lex.token == "="
- elsif lex.state.allbits?(Ripper::EXPR_END)
- # We found an endless method, count it
- oneliner_count += 1 if in_oneliner_def == :BODY
-
- in_oneliner_def = nil
- else
- in_oneliner_def = nil
- end
+ @tokens.each do |token|
+ kw_count += 1 if token.is_kw?
+ end_count += 1 if token.is_end?
end
- kw_count -= oneliner_count
-
@is_kw = (kw_count - end_count) > 0
@is_end = (end_count - kw_count) > 0
end
diff --git a/lib/syntax_suggest/core_ext.rb b/lib/syntax_suggest/core_ext.rb
index 94f57ba605..ffbc922eed 100644
--- a/lib/syntax_suggest/core_ext.rb
+++ b/lib/syntax_suggest/core_ext.rb
@@ -1,96 +1,47 @@
# frozen_string_literal: true
-# Ruby 3.2+ has a cleaner way to hook into Ruby that doesn't use `require`
-if SyntaxError.method_defined?(:detailed_message)
- module SyntaxSuggest
- # SyntaxSuggest.module_for_detailed_message [Private]
- #
- # Used to monkeypatch SyntaxError via Module.prepend
- def self.module_for_detailed_message
- Module.new {
- def detailed_message(highlight: true, syntax_suggest: true, **kwargs)
- return super unless syntax_suggest
-
- require "syntax_suggest/api" unless defined?(SyntaxSuggest::DEFAULT_VALUE)
-
- message = super
-
- if path
- file = Pathname.new(path)
- io = SyntaxSuggest::MiniStringIO.new
-
- SyntaxSuggest.call(
- io: io,
- source: file.read,
- filename: file,
- terminal: highlight
- )
- annotation = io.string
-
- annotation += "\n" unless annotation.end_with?("\n")
-
- annotation + message
- else
- message
- end
- rescue => e
- if ENV["SYNTAX_SUGGEST_DEBUG"]
- $stderr.warn(e.message)
- $stderr.warn(e.backtrace)
- end
-
- # Ignore internal errors
+module SyntaxSuggest
+ # SyntaxSuggest.module_for_detailed_message [Private]
+ #
+ # Used to monkeypatch SyntaxError via Module.prepend
+ def self.module_for_detailed_message
+ Module.new {
+ def detailed_message(highlight: true, syntax_suggest: true, **kwargs)
+ return super unless syntax_suggest
+
+ require "syntax_suggest/api" unless defined?(SyntaxSuggest::DEFAULT_VALUE)
+
+ message = super
+
+ if path
+ file = Pathname.new(path)
+ io = SyntaxSuggest::MiniStringIO.new
+
+ SyntaxSuggest.call(
+ io: io,
+ source: file.read,
+ filename: file,
+ terminal: highlight
+ )
+ annotation = io.string
+
+ annotation += "\n" unless annotation.end_with?("\n")
+
+ annotation + message
+ else
message
end
- }
- end
- end
-
- SyntaxError.prepend(SyntaxSuggest.module_for_detailed_message)
-else
- autoload :Pathname, "pathname"
-
- #--
- # Monkey patch kernel to ensure that all `require` calls call the same
- # method
- #++
- module Kernel
- # :stopdoc:
-
- module_function
-
- alias_method :syntax_suggest_original_require, :require
- alias_method :syntax_suggest_original_require_relative, :require_relative
- alias_method :syntax_suggest_original_load, :load
-
- def load(file, wrap = false)
- syntax_suggest_original_load(file)
- rescue SyntaxError => e
- require "syntax_suggest/api" unless defined?(SyntaxSuggest::DEFAULT_VALUE)
-
- SyntaxSuggest.handle_error(e)
- end
-
- def require(file)
- syntax_suggest_original_require(file)
- rescue SyntaxError => e
- require "syntax_suggest/api" unless defined?(SyntaxSuggest::DEFAULT_VALUE)
-
- SyntaxSuggest.handle_error(e)
- end
+ rescue => e
+ if ENV["SYNTAX_SUGGEST_DEBUG"]
+ $stderr.warn(e.message)
+ $stderr.warn(e.backtrace)
+ end
- def require_relative(file)
- if Pathname.new(file).absolute?
- syntax_suggest_original_require file
- else
- relative_from = caller_locations(1..1).first
- relative_from_path = relative_from.absolute_path || relative_from.path
- syntax_suggest_original_require File.expand_path("../#{file}", relative_from_path)
+ # Ignore internal errors
+ message
end
- rescue SyntaxError => e
- require "syntax_suggest/api" unless defined?(SyntaxSuggest::DEFAULT_VALUE)
-
- SyntaxSuggest.handle_error(e)
- end
+ }
end
end
+
+SyntaxError.prepend(SyntaxSuggest.module_for_detailed_message)
diff --git a/lib/syntax_suggest/explain_syntax.rb b/lib/syntax_suggest/explain_syntax.rb
index 0d80c4d869..d7f5262ddb 100644
--- a/lib/syntax_suggest/explain_syntax.rb
+++ b/lib/syntax_suggest/explain_syntax.rb
@@ -1,19 +1,11 @@
# frozen_string_literal: true
-require_relative "left_right_lex_count"
-
-if !SyntaxSuggest.use_prism_parser?
- require_relative "ripper_errors"
-end
+require_relative "left_right_token_count"
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
+ Prism.parse(source).errors.map(&:message)
end
end
@@ -53,14 +45,14 @@ module SyntaxSuggest
def initialize(code_lines:)
@code_lines = code_lines
- @left_right = LeftRightLexCount.new
+ @left_right = LeftRightTokenCount.new
@missing = nil
end
def call
@code_lines.each do |line|
- line.lex.each do |lex|
- @left_right.count_lex(lex)
+ line.tokens.each do |token|
+ @left_right.count_token(token)
end
end
diff --git a/lib/syntax_suggest/left_right_lex_count.rb b/lib/syntax_suggest/left_right_lex_count.rb
deleted file mode 100644
index 6fcae7482b..0000000000
--- a/lib/syntax_suggest/left_right_lex_count.rb
+++ /dev/null
@@ -1,168 +0,0 @@
-# frozen_string_literal: true
-
-module SyntaxSuggest
- # Find mis-matched syntax based on lexical count
- #
- # Used for detecting missing pairs of elements
- # each keyword needs an end, each '{' needs a '}'
- # etc.
- #
- # Example:
- #
- # left_right = LeftRightLexCount.new
- # left_right.count_kw
- # left_right.missing.first
- # # => "end"
- #
- # left_right = LeftRightLexCount.new
- # source = "{ a: b, c: d" # Note missing '}'
- # LexAll.new(source: source).each do |lex|
- # left_right.count_lex(lex)
- # end
- # left_right.missing.first
- # # => "}"
- class LeftRightLexCount
- def initialize
- @kw_count = 0
- @end_count = 0
-
- @count_for_char = {
- "{" => 0,
- "}" => 0,
- "[" => 0,
- "]" => 0,
- "(" => 0,
- ")" => 0,
- "|" => 0
- }
- end
-
- def count_kw
- @kw_count += 1
- end
-
- def count_end
- @end_count += 1
- end
-
- # Count source code characters
- #
- # Example:
- #
- # left_right = LeftRightLexCount.new
- # left_right.count_lex(LexValue.new(1, :on_lbrace, "{", Ripper::EXPR_BEG))
- # left_right.count_for_char("{")
- # # => 1
- # left_right.count_for_char("}")
- # # => 0
- def count_lex(lex)
- case lex.type
- when :on_tstring_content
- # ^^^
- # Means it's a string or a symbol `"{"` rather than being
- # part of a data structure (like a hash) `{ a: b }`
- # ignore it.
- when :on_words_beg, :on_symbos_beg, :on_qwords_beg,
- :on_qsymbols_beg, :on_regexp_beg, :on_tstring_beg
- # ^^^
- # Handle shorthand syntaxes like `%Q{ i am a string }`
- #
- # The start token will be the full thing `%Q{` but we
- # need to count it as if it's a `{`. Any token
- # can be used
- char = lex.token[-1]
- @count_for_char[char] += 1 if @count_for_char.key?(char)
- when :on_embexpr_beg
- # ^^^
- # Embedded string expressions like `"#{foo} <-embed"`
- # are parsed with chars:
- #
- # `#{` as :on_embexpr_beg
- # `}` as :on_embexpr_end
- #
- # We cannot ignore both :on_emb_expr_beg and :on_embexpr_end
- # because sometimes the lexer thinks something is an embed
- # string end, when it is not like `lol = }` (no clue why).
- #
- # When we see `#{` count it as a `{` or we will
- # have a mis-match count.
- #
- case lex.token
- when "\#{"
- @count_for_char["{"] += 1
- end
- else
- @end_count += 1 if lex.is_end?
- @kw_count += 1 if lex.is_kw?
- @count_for_char[lex.token] += 1 if @count_for_char.key?(lex.token)
- end
- end
-
- def count_for_char(char)
- @count_for_char[char]
- end
-
- # Returns an array of missing syntax characters
- # or `"end"` or `"keyword"`
- #
- # left_right.missing
- # # => ["}"]
- def missing
- out = missing_pairs
- out << missing_pipe
- out << missing_keyword_end
- out.compact!
- out
- end
-
- PAIRS = {
- "{" => "}",
- "[" => "]",
- "(" => ")"
- }.freeze
-
- # Opening characters like `{` need closing characters # like `}`.
- #
- # When a mis-match count is detected, suggest the
- # missing member.
- #
- # For example if there are 3 `}` and only two `{`
- # return `"{"`
- private def missing_pairs
- PAIRS.map do |(left, right)|
- case @count_for_char[left] <=> @count_for_char[right]
- when 1
- right
- when 0
- nil
- when -1
- left
- end
- end
- end
-
- # Keywords need ends and ends need keywords
- #
- # If we have more keywords, there's a missing `end`
- # if we have more `end`-s, there's a missing keyword
- private def missing_keyword_end
- case @kw_count <=> @end_count
- when 1
- "end"
- when 0
- nil
- when -1
- "keyword"
- end
- end
-
- # Pipes come in pairs.
- # If there's an odd number of pipes then we
- # are missing one
- private def missing_pipe
- if @count_for_char["|"].odd?
- "|"
- end
- end
- end
-end
diff --git a/lib/syntax_suggest/left_right_token_count.rb b/lib/syntax_suggest/left_right_token_count.rb
new file mode 100644
index 0000000000..e0562ba9cd
--- /dev/null
+++ b/lib/syntax_suggest/left_right_token_count.rb
@@ -0,0 +1,162 @@
+# frozen_string_literal: true
+
+module SyntaxSuggest
+ # Find mis-matched syntax based on lexical count
+ #
+ # Used for detecting missing pairs of elements
+ # each keyword needs an end, each '{' needs a '}'
+ # etc.
+ #
+ # Example:
+ #
+ # left_right = LeftRightTokenCount.new
+ # left_right.count_kw
+ # left_right.missing.first
+ # # => "end"
+ #
+ # left_right = LeftRightTokenCount.new
+ # source = "{ a: b, c: d" # Note missing '}'
+ # LexAll.new(source: source).each do |token|
+ # left_right.count_token(token)
+ # end
+ # left_right.missing.first
+ # # => "}"
+ class LeftRightTokenCount
+ def initialize
+ @kw_count = 0
+ @end_count = 0
+
+ @count_for_char = {
+ "{" => 0,
+ "}" => 0,
+ "[" => 0,
+ "]" => 0,
+ "(" => 0,
+ ")" => 0,
+ "|" => 0
+ }
+ end
+
+ def count_kw
+ @kw_count += 1
+ end
+
+ def count_end
+ @end_count += 1
+ end
+
+ # Count source code characters
+ #
+ # Example:
+ #
+ # token = CodeLine.from_source("{").first.tokens.first
+ # left_right = LeftRightTokenCount.new
+ # left_right.count_token(Token.new(token)
+ # left_right.count_for_char("{")
+ # # => 1
+ # left_right.count_for_char("}")
+ # # => 0
+ def count_token(token)
+ case token.type
+ when :STRING_CONTENT
+ # ^^^
+ # Means it's a string or a symbol `"{"` rather than being
+ # part of a data structure (like a hash) `{ a: b }`
+ # ignore it.
+ when :PERCENT_UPPER_W, :PERCENT_UPPER_I, :PERCENT_LOWER_W,
+ :PERCENT_LOWER_I, :REGEXP_BEGIN, :STRING_BEGIN
+ # ^^^
+ # Handle shorthand syntaxes like `%Q{ i am a string }`
+ #
+ # The start token will be the full thing `%Q{` but we
+ # need to count it as if it's a `{`. Any token
+ # can be used
+ char = token.value[-1]
+ @count_for_char[char] += 1 if @count_for_char.key?(char)
+ when :EMBEXPR_BEGIN
+ # ^^^
+ # Embedded string expressions like `"#{foo} <-embed"`
+ # are parsed with chars:
+ #
+ # `#{` as :EMBEXPR_BEGIN
+ # `}` as :EMBEXPR_END
+ #
+ # When we see `#{` count it as a `{` or we will
+ # have a mis-match count.
+ #
+ @count_for_char["{"] += 1
+ else
+ @end_count += 1 if token.is_end?
+ @kw_count += 1 if token.is_kw?
+ @count_for_char[token.value] += 1 if @count_for_char.key?(token.value)
+ end
+ end
+
+ def count_for_char(char)
+ @count_for_char[char]
+ end
+
+ # Returns an array of missing syntax characters
+ # or `"end"` or `"keyword"`
+ #
+ # left_right.missing
+ # # => ["}"]
+ def missing
+ out = missing_pairs
+ out << missing_pipe
+ out << missing_keyword_end
+ out.compact!
+ out
+ end
+
+ PAIRS = {
+ "{" => "}",
+ "[" => "]",
+ "(" => ")"
+ }.freeze
+
+ # Opening characters like `{` need closing characters # like `}`.
+ #
+ # When a mis-match count is detected, suggest the
+ # missing member.
+ #
+ # For example if there are 3 `}` and only two `{`
+ # return `"{"`
+ private def missing_pairs
+ PAIRS.map do |(left, right)|
+ case @count_for_char[left] <=> @count_for_char[right]
+ when 1
+ right
+ when 0
+ nil
+ when -1
+ left
+ end
+ end
+ end
+
+ # Keywords need ends and ends need keywords
+ #
+ # If we have more keywords, there's a missing `end`
+ # if we have more `end`-s, there's a missing keyword
+ private def missing_keyword_end
+ case @kw_count <=> @end_count
+ when 1
+ "end"
+ when 0
+ nil
+ when -1
+ "keyword"
+ end
+ end
+
+ # Pipes come in pairs.
+ # If there's an odd number of pipes then we
+ # are missing one
+ private def missing_pipe
+ if @count_for_char["|"].odd?
+ "|"
+ end
+ end
+ end
+end
diff --git a/lib/syntax_suggest/lex_all.rb b/lib/syntax_suggest/lex_all.rb
deleted file mode 100644
index c16fbb52d3..0000000000
--- a/lib/syntax_suggest/lex_all.rb
+++ /dev/null
@@ -1,74 +0,0 @@
-# frozen_string_literal: true
-
-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
- class LexAll
- include Enumerable
-
- def initialize(source:, source_lines: nil)
- @lex = self.class.lex(source, 1)
- lineno = @lex.last[0][0] + 1
- source_lines ||= source.lines
- last_lineno = source_lines.length
-
- until lineno >= last_lineno
- lines = source_lines[lineno..]
-
- @lex.concat(
- self.class.lex(lines.join, lineno + 1)
- )
-
- lineno = @lex.last[0].first + 1
- end
-
- last_lex = nil
- @lex.map! { |elem|
- last_lex = LexValue.new(elem[0].first, elem[1], elem[2], elem[3], 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
-
- def each
- return @lex.each unless block_given?
- @lex.each do |x|
- yield x
- end
- end
-
- def [](index)
- @lex[index]
- end
-
- def last
- @lex.last
- end
- end
-end
-
-require_relative "lex_value"
diff --git a/lib/syntax_suggest/lex_value.rb b/lib/syntax_suggest/lex_value.rb
deleted file mode 100644
index b46a332772..0000000000
--- a/lib/syntax_suggest/lex_value.rb
+++ /dev/null
@@ -1,70 +0,0 @@
-# frozen_string_literal: true
-
-module SyntaxSuggest
- # Value object for accessing lex values
- #
- # This lex:
- #
- # [1, 0], :on_ident, "describe", CMDARG
- #
- # Would translate into:
- #
- # lex.line # => 1
- # lex.type # => :on_indent
- # lex.token # => "describe"
- class LexValue
- attr_reader :line, :type, :token, :state
-
- def initialize(line, type, token, state, last_lex = nil)
- @line = line
- @type = type
- @token = token
- @state = state
-
- set_kw_end(last_lex)
- end
-
- private def set_kw_end(last_lex)
- @is_end = false
- @is_kw = false
- return if type != :on_kw
-
- return if last_lex && last_lex.fname? # https://github.com/ruby/ruby/commit/776759e300e4659bb7468e2b97c8c2d4359a2953
-
- case token
- when "if", "unless", "while", "until"
- # Only count if/unless when it's not a "trailing" if/unless
- # https://github.com/ruby/ruby/blob/06b44f819eb7b5ede1ff69cecb25682b56a1d60c/lib/irb/ruby-lex.rb#L374-L375
- @is_kw = true unless expr_label?
- when "def", "case", "for", "begin", "class", "module", "do"
- @is_kw = true
- when "end"
- @is_end = true
- end
- end
-
- def fname?
- state.allbits?(Ripper::EXPR_FNAME)
- end
-
- def ignore_newline?
- type == :on_ignored_nl
- end
-
- def is_end?
- @is_end
- end
-
- def is_kw?
- @is_kw
- end
-
- def expr_beg?
- state.anybits?(Ripper::EXPR_BEG)
- end
-
- def expr_label?
- state.allbits?(Ripper::EXPR_LABEL)
- end
- end
-end
diff --git a/lib/syntax_suggest/ripper_errors.rb b/lib/syntax_suggest/ripper_errors.rb
deleted file mode 100644
index 4e2bc90948..0000000000
--- a/lib/syntax_suggest/ripper_errors.rb
+++ /dev/null
@@ -1,39 +0,0 @@
-# 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.
- #
- # Example:
- #
- # puts RipperErrors.new(" def foo").call.errors
- # # => ["syntax error, unexpected end-of-input, expecting ';' or '\\n'"]
- class RipperErrors < Ripper
- attr_reader :errors
-
- # Comes from ripper, called
- # on every parse error, msg
- # is a string
- def on_parse_error(msg)
- @errors ||= []
- @errors << msg
- end
-
- alias_method :on_alias_error, :on_parse_error
- alias_method :on_assign_error, :on_parse_error
- alias_method :on_class_name_error, :on_parse_error
- alias_method :on_param_error, :on_parse_error
- alias_method :compile_error, :on_parse_error
-
- def call
- @run_once ||= begin
- @errors = []
- parse
- true
- end
- self
- end
- end
-end
diff --git a/lib/syntax_suggest/syntax_suggest.gemspec b/lib/syntax_suggest/syntax_suggest.gemspec
index 756a85bf63..44e458aaad 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(">= 3.3.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/token.rb b/lib/syntax_suggest/token.rb
new file mode 100644
index 0000000000..fc52639b1f
--- /dev/null
+++ b/lib/syntax_suggest/token.rb
@@ -0,0 +1,49 @@
+# frozen_string_literal: true
+
+module SyntaxSuggest
+ # Value object for accessing lex values
+ #
+ # This lex:
+ #
+ # [IDENTIFIER(1,0)-(1,8)("describe"), 32]
+ #
+ # Would translate into:
+ #
+ # lex.location # => (1,0)-(1,8)
+ # lex.type # => :IDENTIFIER
+ # lex.token # => "describe"
+ class Token
+ attr_reader :location, :type, :value
+
+ KW_TYPES = %i[
+ KEYWORD_IF KEYWORD_UNLESS KEYWORD_WHILE KEYWORD_UNTIL
+ KEYWORD_DEF KEYWORD_CASE KEYWORD_FOR KEYWORD_BEGIN KEYWORD_CLASS KEYWORD_MODULE KEYWORD_DO KEYWORD_DO_LOOP
+ ].to_set.freeze
+ private_constant :KW_TYPES
+
+ def initialize(prism_token, previous_prism_token, visitor)
+ @location = prism_token.location
+ @type = prism_token.type
+ @value = prism_token.value
+
+ # Prism lexes `:module` as SYMBOL_BEGIN, KEYWORD_MODULE
+ # https://github.com/ruby/prism/issues/3940
+ symbol_content = previous_prism_token&.type == :SYMBOL_BEGIN
+ @is_kw = KW_TYPES.include?(@type)
+ @is_kw = false if symbol_content || visitor.endless_def_keyword_offsets.include?(@location.start_offset)
+ @is_end = @type == :KEYWORD_END
+ end
+
+ def line
+ @location.start_line
+ end
+
+ def is_end?
+ @is_end
+ end
+
+ def is_kw?
+ @is_kw
+ end
+ end
+end
diff --git a/lib/syntax_suggest/version.rb b/lib/syntax_suggest/version.rb
index 1aa908f4e5..9114a079f6 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.2"
+ VERSION = "3.0.0"
end
diff --git a/lib/syntax_suggest/visitor.rb b/lib/syntax_suggest/visitor.rb
new file mode 100644
index 0000000000..6e25f7239c
--- /dev/null
+++ b/lib/syntax_suggest/visitor.rb
@@ -0,0 +1,80 @@
+# frozen_string_literal: true
+
+module SyntaxSuggest
+ # Walks the Prism AST to extract structural info that cannot be reliably determined from tokens
+ # alone.
+ #
+ # Such as the location of lines that must be logically joined so the search algorithm will
+ # treat them as one. Example:
+ #
+ # source = <<~RUBY
+ # User # 1
+ # .where(name: "Earlopain") # 2
+ # .first # 3
+ # RUBY
+ # ast, _tokens = Prism.parse_lex(source).value
+ # visitor = Visitor.new
+ # visitor.visit(ast)
+ # visitor.consecutive_lines # => Set[2, 1]
+ #
+ # This output means that line 1 and line 2 need to be joined with their next line.
+ #
+ # And determining the location of "endless" method definitions. For example:
+ #
+ # source = <<~RUBY
+ # def cube(x)
+ # x * x * x
+ # end
+ # def square(x) = x * x # 1
+ # RUBY
+ #
+ # ast, _tokens = Prism.parse_lex(source).value
+ # visitor = Visitor.new
+ # visitor.visit(ast)
+ # visitor.endless_def_keyword_offsets # => Set[28]
+ class Visitor < Prism::Visitor
+ attr_reader :endless_def_keyword_offsets, :consecutive_lines
+
+ def initialize
+ @endless_def_keyword_offsets = Set.new
+ @consecutive_lines = Set.new
+ end
+
+ # Called by Prism::Visitor for every method-call node in the AST
+ # (e.g. `foo.bar`, `foo.bar.baz`).
+ def visit_call_node(node)
+ receiver_loc = node.receiver&.location
+ call_operator_loc = node.call_operator_loc
+ message_loc = node.message_loc
+ if receiver_loc && call_operator_loc && message_loc
+ # dot-leading (dot on the next line)
+ # foo # line 1 - consecutive
+ # .bar # line 2
+ if receiver_loc.end_line != call_operator_loc.start_line && call_operator_loc.start_line == message_loc.start_line
+ (receiver_loc.end_line..call_operator_loc.start_line - 1).each do |line|
+ @consecutive_lines << line
+ end
+ end
+
+ # dot-trailing (dot on the same line as the receiver)
+ # foo. # line 1 - consecutive
+ # bar # line 2
+ if receiver_loc.end_line == call_operator_loc.start_line && call_operator_loc.start_line != message_loc.start_line
+ (call_operator_loc.start_line..message_loc.start_line - 1).each do |line|
+ @consecutive_lines << line
+ end
+ end
+ end
+ super
+ end
+
+ # Called by Prism::Visitor for every `def` node in the AST.
+ # Records the keyword start location for endless method definitions
+ # like `def foo = 123`. These are valid without a matching `end`,
+ # so Token must exclude them when deciding if a line is a keyword.
+ def visit_def_node(node)
+ @endless_def_keyword_offsets << node.def_keyword_loc.start_offset if node.equal_loc
+ super
+ end
+ end
+end
diff --git a/lib/tempfile.rb b/lib/tempfile.rb
index 7292e72c25..cd512bb1c5 100644
--- a/lib/tempfile.rb
+++ b/lib/tempfile.rb
@@ -550,8 +550,8 @@ end
#
# Implementation note:
#
-# The keyword argument +anonymous=true+ is implemented using FILE_SHARE_DELETE on Windows.
-# O_TMPFILE is used on Linux.
+# The keyword argument <tt>anonymous=true</tt> is implemented using +FILE_SHARE_DELETE+ on Windows.
+# +O_TMPFILE+ is used on Linux.
#
# Related: Tempfile.new.
#
@@ -564,6 +564,8 @@ def Tempfile.create(basename="", tmpdir=nil, mode: 0, anonymous: false, **option
end
class << Tempfile
+# :stopdoc:
+
private def create_with_filename(basename="", tmpdir=nil, mode: 0, **options)
tmpfile = nil
Dir::Tmpname.create(basename, tmpdir, **options) do |tmpname, n, opts|
diff --git a/lib/time.gemspec b/lib/time.gemspec
index 4b9f9e1218..73650ab12e 100644
--- a/lib/time.gemspec
+++ b/lib/time.gemspec
@@ -19,6 +19,7 @@ Gem::Specification.new do |spec|
spec.metadata["homepage_uri"] = spec.homepage
spec.metadata["source_code_uri"] = spec.homepage
+ spec.metadata["changelog_uri"] = "https://github.com/ruby/time/releases"
srcdir, gemspec = File.split(__FILE__)
spec.files = Dir.chdir(srcdir) do
diff --git a/lib/time.rb b/lib/time.rb
index a0fc7dfbf5..e6aab3fa5d 100644
--- a/lib/time.rb
+++ b/lib/time.rb
@@ -27,7 +27,7 @@ require 'date'
# #
class Time
- VERSION = "0.4.1" # :nodoc:
+ VERSION = "0.4.2" # :nodoc:
class << Time
@@ -80,7 +80,7 @@ class Time
#
# You must require 'time' to use this method.
#
- def zone_offset(zone, year=self.now.year)
+ def zone_offset(zone, year=nil)
off = nil
zone = zone.upcase
if /\A([+-])(\d\d)(:?)(\d\d)(?:\3(\d\d))?\z/ =~ zone
@@ -89,10 +89,13 @@ class Time
off = zone.to_i * 3600
elsif ZoneOffset.include?(zone)
off = ZoneOffset[zone] * 3600
- elsif ((t = self.local(year, 1, 1)).zone.upcase == zone rescue false)
- off = t.utc_offset
- elsif ((t = self.local(year, 7, 1)).zone.upcase == zone rescue false)
- off = t.utc_offset
+ else
+ year ||= self.now.year
+ if ((t = self.local(year, 1, 1)).zone.upcase == zone rescue false)
+ off = t.utc_offset
+ elsif ((t = self.local(year, 7, 1)).zone.upcase == zone rescue false)
+ off = t.utc_offset
+ end
end
off
end
diff --git a/lib/timeout.rb b/lib/timeout.rb
index f5f232ad2a..91b04a9562 100644
--- a/lib/timeout.rb
+++ b/lib/timeout.rb
@@ -20,9 +20,9 @@
module Timeout
# The version
- VERSION = "0.4.3"
+ VERSION = "0.6.1"
- # Internal error raised to when a timeout is triggered.
+ # Internal exception raised to when a timeout is triggered.
class ExitException < Exception
def exception(*) # :nodoc:
self
@@ -44,12 +44,101 @@ module Timeout
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
+
+ # We keep a private reference so that time mocking libraries won't break Timeout.
+ GET_TIME = Process.method(:clock_gettime)
+ if defined?(Ractor.make_shareable)
+ # Ractor.make_shareable(Method) only works on Ruby 4+
+ Ractor.make_shareable(GET_TIME) rescue nil
+ end
+ private_constant :GET_TIME
+
+ class State
+ def initialize
+ @condvar = ConditionVariable.new
+ @queue = Queue.new
+ @queue_mutex = Mutex.new
+
+ @timeout_thread = nil
+ @timeout_thread_mutex = Mutex.new
+ end
+
+ if defined?(Ractor.store_if_absent) && defined?(Ractor.shareable?) && Ractor.shareable?(GET_TIME)
+ # Ractor support if
+ # 1. Ractor.store_if_absent is available
+ # 2. Method object can be shareable (4.0~)
+ def self.instance
+ Ractor.store_if_absent :timeout_gem_state do
+ State.new
+ end
+ end
+ else
+ GLOBAL_STATE = State.new
+
+ def self.instance
+ GLOBAL_STATE
+ end
+ end
+
+ def create_timeout_thread
+ # Threads unexpectedly inherit the interrupt mask: https://github.com/ruby/timeout/issues/41
+ # So reset the interrupt mask to the default one for the timeout thread
+ Thread.handle_interrupt(Object => :immediate) do
+ 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
+
+ if !watcher.group.enclosed? && (!defined?(Ractor.main?) || Ractor.main?)
+ ThreadGroup::Default.add(watcher)
+ end
+
+ watcher.name = "Timeout stdlib thread"
+ watcher.thread_variable_set(:"\0__detached_thread__", true)
+ watcher
+ end
+ end
+
+ def ensure_timeout_thread_created
+ unless @timeout_thread&.alive?
+ # If the Mutex is already owned we are in a signal handler.
+ # In that case, just return and let the main thread create the Timeout thread.
+ return if @timeout_thread_mutex.owned?
+
+ Sync.synchronize @timeout_thread_mutex do
+ unless @timeout_thread&.alive?
+ @timeout_thread = create_timeout_thread
+ end
+ end
+ end
+ end
+
+ def add_request(request)
+ Sync.synchronize @queue_mutex do
+ @queue << request
+ @condvar.signal
+ end
+ end
+ end
+ private_constant :State
class Request
attr_reader :deadline
@@ -64,6 +153,7 @@ module Timeout
@done = false # protected by @mutex
end
+ # Only called by the timeout thread, so does not need Sync.synchronize
def done?
@mutex.synchronize do
@done
@@ -74,6 +164,7 @@ module Timeout
now >= @deadline
end
+ # Only called by the timeout thread, so does not need Sync.synchronize
def interrupt
@mutex.synchronize do
unless @done
@@ -84,64 +175,36 @@ module Timeout
end
def finished
- @mutex.synchronize do
+ Sync.synchronize @mutex 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 = "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?
- # If the Mutex is already owned we are in a signal handler.
- # In that case, just return and let the main thread create the @timeout_thread.
- return if TIMEOUT_THREAD_MUTEX.owned?
- TIMEOUT_THREAD_MUTEX.synchronize do
- unless @timeout_thread and @timeout_thread.alive?
- @timeout_thread = create_timeout_thread
- end
+ module Sync
+ # Calls mutex.synchronize(&block) but if that fails on CRuby due to being in a trap handler,
+ # run mutex.synchronize(&block) in a separate Thread instead.
+ def self.synchronize(mutex, &block)
+ begin
+ mutex.synchronize(&block)
+ rescue ThreadError => e
+ raise e unless e.message == "can't be called from trap context"
+ # Workaround CRuby issue https://bugs.ruby-lang.org/issues/19473
+ # which raises on Mutex#synchronize in trap handler.
+ # It's expensive to create a Thread just for this,
+ # but better than failing.
+ Thread.new {
+ mutex.synchronize(&block)
+ }.join
end
end
end
-
- # We keep a private reference so that time mocking libraries won't break
- # Timeout.
- GET_TIME = Process.method(:clock_gettime)
- private_constant :GET_TIME
+ private_constant :Sync
# :startdoc:
- # Perform an operation in a block, raising an error if it takes longer than
+ # Perform an operation in a block, raising an exception if it takes longer than
# +sec+ seconds to complete.
#
# +sec+:: Number of seconds to wait for the block to terminate. Any non-negative number
@@ -149,45 +212,91 @@ module Timeout
# value of 0 or +nil+ will execute the block without any timeout.
# Any negative number will raise an ArgumentError.
# +klass+:: Exception Class to raise if the block fails to terminate
- # in +sec+ seconds. Omitting will use the default, Timeout::Error
+ # in +sec+ seconds. Omitting will use the default, Timeout::Error.
# +message+:: Error message to raise with Exception Class.
- # Omitting will use the default, "execution expired"
+ # Omitting will use the default, <tt>"execution expired"</tt>.
#
# Returns the result of the block *if* the block completed before
- # +sec+ seconds, otherwise throws an exception, based on the value of +klass+.
+ # +sec+ seconds, otherwise raises an exception, based on the value of +klass+.
+ #
+ # The exception raised to terminate the given block is the given +klass+, or
+ # Timeout::ExitException if +klass+ is not given. The reason for that behavior
+ # is that Timeout::Error inherits from RuntimeError and might be caught unexpectedly by +rescue+.
+ # Timeout::ExitException inherits from Exception so it will only be rescued by <tt>rescue Exception</tt>.
+ # Note that the Timeout::ExitException is translated to a Timeout::Error once it reaches the Timeout.timeout call,
+ # so outside that call it will be a Timeout::Error.
#
- # 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.
+ # In general, be aware that the code block may rescue the exception, and in such a case not respect the timeout.
+ # Also, the block can use +ensure+ to prevent the handling of the exception.
+ # For those reasons, 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.
+ # Fiber::Scheduler#timeout_after.
#
# Note that this is both a method of module Timeout, so you can <tt>include
# Timeout</tt> into your classes so they have a #timeout method, as well as
# a module method, so you can call it directly as Timeout.timeout().
- def timeout(sec, klass = nil, message = nil, &block) #:yield: +sec+
+ #
+ # ==== Ensuring the exception does not fire inside ensure blocks
+ #
+ # When using Timeout.timeout, it can be desirable to ensure the timeout exception does not fire inside an +ensure+ block.
+ # The simplest and best way to do so is to put the Timeout.timeout call inside the body of the +begin+/+ensure+/+end+:
+ #
+ # begin
+ # Timeout.timeout(sec) { some_long_operation }
+ # ensure
+ # cleanup # safe, cannot be interrupted by timeout
+ # end
+ #
+ # If that is not feasible, e.g. if there are +ensure+ blocks inside +some_long_operation+,
+ # they need to not be interrupted by timeout, and it's not possible to move these ensure blocks outside,
+ # one can use Thread.handle_interrupt to delay the timeout exception like so:
+ #
+ # Thread.handle_interrupt(Timeout::Error => :never) {
+ # Timeout.timeout(sec, Timeout::Error) do
+ # setup # timeout cannot happen here, no matter how long it takes
+ # Thread.handle_interrupt(Timeout::Error => :immediate) {
+ # some_long_operation # timeout can happen here
+ # }
+ # ensure
+ # cleanup # timeout cannot happen here, no matter how long it takes
+ # end
+ # }
+ #
+ # An important thing to note is the need to pass an exception +klass+ to Timeout.timeout,
+ # otherwise it does not work. Specifically, using <tt>Thread.handle_interrupt(Timeout::ExitException => ...)</tt>
+ # is unsupported and causes subtle errors like raising the wrong exception outside the block, do not use that.
+ #
+ # Note that Thread.handle_interrupt is somewhat dangerous because if setup or cleanup hangs
+ # then the current thread will hang too and the timeout will never fire.
+ # Also note the block might run for longer than +sec+ seconds:
+ # e.g. +some_long_operation+ executes for +sec+ seconds + whatever time cleanup takes.
+ #
+ # If you want the timeout to only happen on blocking operations, one can use +:on_blocking+
+ # instead of +:immediate+. However, that means if the block uses no blocking operations after +sec+ seconds,
+ # the block will not be interrupted.
+ def self.timeout(sec, klass = nil, message = nil, &block) #:yield: +sec+
return yield(sec) if sec == nil or sec.zero?
raise ArgumentError, "Timeout sec must be a non-negative number" if 0 > sec
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
-
- 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
+ perform = Proc.new do |exc|
+ scheduler.timeout_after(sec, exc, message, &block)
end
- begin
- return yield(sec)
- ensure
- request.finished
+ else
+ state = State.instance
+ state.ensure_timeout_thread_created
+
+ perform = Proc.new do |exc|
+ request = Request.new(Thread.current, sec, exc, message)
+ state.add_request(request)
+ begin
+ return yield(sec)
+ ensure
+ request.finished
+ end
end
end
@@ -197,5 +306,9 @@ module Timeout
Error.handle_timeout(message, &perform)
end
end
- module_function :timeout
+
+ # See Timeout.timeout
+ private def timeout(*args, &block)
+ Timeout.timeout(*args, &block)
+ end
end
diff --git a/lib/tsort.gemspec b/lib/tsort.gemspec
deleted file mode 100644
index 4e0ef0507d..0000000000
--- a/lib/tsort.gemspec
+++ /dev/null
@@ -1,35 +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 = ["Tanaka Akira"]
- spec.email = ["akr@fsij.org"]
-
- spec.summary = %q{Topological sorting using Tarjan's algorithm}
- spec.description = %q{Topological sorting using Tarjan's algorithm}
- spec.homepage = "https://github.com/ruby/tsort"
- 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.metadata["changelog_uri"] = "#{spec.homepage}/releases"
-
- dir, gemspec = File.split(__FILE__)
- excludes = %W[
- :^/.git* :^/bin/ :^/test/ :^/spec/ :^/features/ :^/Gemfile :^/Rakefile
- :^/#{gemspec}
- ]
- spec.files = IO.popen(%w[git ls-files -z --] + excludes, chdir: dir) do |f|
- f.read.split("\x0")
- end
- spec.bindir = "exe"
- spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
- spec.require_paths = ["lib"]
-end
diff --git a/lib/tsort.rb b/lib/tsort.rb
deleted file mode 100644
index 3c9635baa3..0000000000
--- a/lib/tsort.rb
+++ /dev/null
@@ -1,457 +0,0 @@
-# frozen_string_literal: true
-
-#--
-# tsort.rb - provides a module for topological sorting and strongly connected components.
-#++
-#
-
-#
-# TSort implements topological sorting using Tarjan's algorithm for
-# strongly connected components.
-#
-# TSort is designed to be able to be used with any object which can be
-# interpreted as a directed graph.
-#
-# 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
-# TSort uses Hash internally.
-#
-# == A Simple Example
-#
-# The following example demonstrates how to mix the 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 'tsort'
-#
-# class Hash
-# include 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 '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 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 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 TSort
-
- # The version string.
- VERSION = "0.2.0"
-
- # Exception class to be raised when a cycle is found.
- 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, TSort::Cyclic is raised.
- #
- # class G
- # include 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 TSort::Cyclic
- #
- def tsort
- each_node = method(:tsort_each_node)
- each_child = method(:tsort_each_child)
- 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, 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 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 TSort.tsort(each_node, each_child) # raises 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, TSort::Cyclic is raised.
- #
- # class G
- # include 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)
- TSort.tsort_each(each_node, each_child, &block)
- end
-
- # The iterator version of the 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) }
- # 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 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)
- 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 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 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 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)
- TSort.each_strongly_connected_component(each_node, each_child, &block)
- end
-
- # The iterator version of the 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) }
- # 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) }
- # 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 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
- 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.
- #
- # #TSort.each_strongly_connected_component_from is a class method and
- # it doesn't need a class to represent a graph which includes TSort.
- #
- # graph = {1=>[2], 2=>[3, 4], 3=>[2], 4=>[]}
- # each_child = lambda {|n, &b| graph[n].each(&b) }
- # 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/unicode_normalize/normalize.rb b/lib/unicode_normalize/normalize.rb
index e67fad187a..0447df8de7 100644
--- a/lib/unicode_normalize/normalize.rb
+++ b/lib/unicode_normalize/normalize.rb
@@ -82,16 +82,22 @@ module UnicodeNormalize # :nodoc:
## Canonical Ordering
def self.canonical_ordering_one(string)
- sorting = string.each_char.collect { |c| [c, CLASS_TABLE[c]] }
- (sorting.length-2).downto(0) do |i| # almost, but not exactly bubble sort
- (0..i).each do |j|
- later_class = sorting[j+1].last
- if 0<later_class and later_class<sorting[j].last
- sorting[j], sorting[j+1] = sorting[j+1], sorting[j]
- end
+ result = ''
+ unordered = []
+ chars = string.chars
+ n = chars.size
+ chars.each_with_index do |char, i|
+ ccc = CLASS_TABLE[char]
+ if ccc == 0
+ unordered.sort!.each { result << chars[it % n] }
+ unordered.clear
+ result << char
+ else
+ unordered << ccc * n + i
end
end
- return sorting.collect(&:first).join('')
+ unordered.sort!.each { result << chars[it % n] }
+ result
end
## Normalization Forms for Patterns (not whole Strings)
@@ -105,17 +111,22 @@ module UnicodeNormalize # :nodoc:
start = nfd_string[0]
last_class = CLASS_TABLE[start]-1
accents = ''
+ result = ''
nfd_string[1..-1].each_char do |accent|
accent_class = CLASS_TABLE[accent]
if last_class<accent_class and composite = COMPOSITION_TABLE[start+accent]
start = composite
+ elsif accent_class == 0
+ result << start << accents
+ start = accent
+ accents = ''
+ last_class = -1
else
accents << accent
last_class = accent_class
end
end
- accents = nfc_one(accents) if accents.length>1 # TODO: change from recursion to loop
- hangul_comp_one(start+accents)
+ hangul_comp_one(result+start+accents)
end
def self.normalize(string, form = :nfc)
diff --git a/lib/unicode_normalize/tables.rb b/lib/unicode_normalize/tables.rb
index b5b708defd..dd5d3499b8 100644
--- a/lib/unicode_normalize/tables.rb
+++ b/lib/unicode_normalize/tables.rb
@@ -1,8 +1,8 @@
# coding: us-ascii
# frozen_string_literal: true
-Encoding::UNICODE_VERSION == "16.0.0" or
- raise "Unicode version mismatch: 16.0.0 expected but #{Encoding::UNICODE_VERSION}"
+Encoding::UNICODE_VERSION == "17.0.0" or
+ raise "Unicode version mismatch: 17.0.0 expected but #{Encoding::UNICODE_VERSION}"
# automatically generated by template/unicode_norm_gen.tmpl
@@ -99,7 +99,8 @@ module UnicodeNormalize # :nodoc:
"\u1A75-\u1A7C" \
"\u1A7F" \
"\u1AB0-\u1ABD" \
- "\u1ABF-\u1ACE" \
+ "\u1ABF-\u1ADD" \
+ "\u1AE0-\u1AEB" \
"\u1B34\u1B35" \
"\u1B44" \
"\u1B6B-\u1B73" \
@@ -154,6 +155,7 @@ module UnicodeNormalize # :nodoc:
"\u{10D24}-\u{10D27}" \
"\u{10D69}-\u{10D6D}" \
"\u{10EAB}\u{10EAC}" \
+ "\u{10EFA}\u{10EFB}" \
"\u{10EFD}-\u{10EFF}" \
"\u{10F46}-\u{10F50}" \
"\u{10F82}-\u{10F85}" \
@@ -230,6 +232,10 @@ module UnicodeNormalize # :nodoc:
"\u{1E2EC}-\u{1E2EF}" \
"\u{1E4EC}-\u{1E4EF}" \
"\u{1E5EE}\u{1E5EF}" \
+ "\u{1E6E3}" \
+ "\u{1E6E6}" \
+ "\u{1E6EE}\u{1E6EF}" \
+ "\u{1E6F5}" \
"\u{1E8D0}-\u{1E8D6}" \
"\u{1E944}-\u{1E94A}" \
"]"
@@ -1460,7 +1466,7 @@ module UnicodeNormalize # :nodoc:
"\u3280-\u33FF" \
"\uA69C\uA69D" \
"\uA770" \
- "\uA7F2-\uA7F4" \
+ "\uA7F1-\uA7F4" \
"\uA7F8\uA7F9" \
"\uAB5C-\uAB5F" \
"\uAB69" \
@@ -2019,6 +2025,33 @@ module UnicodeNormalize # :nodoc:
"\u1ACC"=>230,
"\u1ACD"=>230,
"\u1ACE"=>230,
+ "\u1ACF"=>230,
+ "\u1AD0"=>230,
+ "\u1AD1"=>230,
+ "\u1AD2"=>230,
+ "\u1AD3"=>230,
+ "\u1AD4"=>230,
+ "\u1AD5"=>230,
+ "\u1AD6"=>230,
+ "\u1AD7"=>230,
+ "\u1AD8"=>230,
+ "\u1AD9"=>230,
+ "\u1ADA"=>230,
+ "\u1ADB"=>230,
+ "\u1ADC"=>230,
+ "\u1ADD"=>220,
+ "\u1AE0"=>230,
+ "\u1AE1"=>230,
+ "\u1AE2"=>230,
+ "\u1AE3"=>230,
+ "\u1AE4"=>230,
+ "\u1AE5"=>230,
+ "\u1AE6"=>220,
+ "\u1AE7"=>230,
+ "\u1AE8"=>230,
+ "\u1AE9"=>230,
+ "\u1AEA"=>230,
+ "\u1AEB"=>234,
"\u1B34"=>7,
"\u1B44"=>9,
"\u1B6B"=>230,
@@ -2293,6 +2326,8 @@ module UnicodeNormalize # :nodoc:
"\u{10D6D}"=>230,
"\u{10EAB}"=>230,
"\u{10EAC}"=>230,
+ "\u{10EFA}"=>220,
+ "\u{10EFB}"=>220,
"\u{10EFD}"=>220,
"\u{10EFE}"=>220,
"\u{10EFF}"=>220,
@@ -2479,6 +2514,11 @@ module UnicodeNormalize # :nodoc:
"\u{1E4EF}"=>230,
"\u{1E5EE}"=>230,
"\u{1E5EF}"=>220,
+ "\u{1E6E3}"=>230,
+ "\u{1E6E6}"=>230,
+ "\u{1E6EE}"=>230,
+ "\u{1E6EF}"=>230,
+ "\u{1E6F5}"=>230,
"\u{1E8D0}"=>220,
"\u{1E8D1}"=>220,
"\u{1E8D2}"=>220,
@@ -5922,6 +5962,7 @@ module UnicodeNormalize # :nodoc:
"\uA69C"=>"\u044A",
"\uA69D"=>"\u044C",
"\uA770"=>"\uA76F",
+ "\uA7F1"=>"S",
"\uA7F2"=>"C",
"\uA7F3"=>"F",
"\uA7F4"=>"Q",
diff --git a/lib/uri/common.rb b/lib/uri/common.rb
index 61221fafad..a2fb531631 100644
--- a/lib/uri/common.rb
+++ b/lib/uri/common.rb
@@ -30,6 +30,9 @@ module URI
remove_const(:Parser) if defined?(::URI::Parser)
const_set("Parser", parser.class)
+ remove_const(:PARSER) if defined?(::URI::PARSER)
+ const_set("PARSER", parser)
+
remove_const(:REGEXP) if defined?(::URI::REGEXP)
remove_const(:PATTERN) if defined?(::URI::PATTERN)
if Parser == RFC2396_Parser
@@ -227,7 +230,7 @@ module URI
# ["fragment", "top"]]
#
def self.split(uri)
- DEFAULT_PARSER.split(uri)
+ PARSER.split(uri)
end
# Returns a new \URI object constructed from the given string +uri+:
@@ -237,11 +240,11 @@ module URI
# 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>
#
- # It's recommended to first ::escape string +uri+
+ # It's recommended to first URI::RFC2396_PARSER.escape string +uri+
# if it may contain invalid URI characters.
#
def self.parse(uri)
- DEFAULT_PARSER.parse(uri)
+ PARSER.parse(uri)
end
# Merges the given URI strings +str+
@@ -268,7 +271,7 @@ module URI
# # => #<URI::HTTP http://example.com/foo/bar>
#
def self.join(*str)
- DEFAULT_PARSER.join(*str)
+ PARSER.join(*str)
end
#
@@ -297,7 +300,7 @@ module URI
#
def self.extract(str, schemes = nil, &block) # :nodoc:
warn "URI.extract is obsolete", uplevel: 1 if $VERBOSE
- DEFAULT_PARSER.extract(str, schemes, &block)
+ PARSER.extract(str, schemes, &block)
end
#
@@ -334,7 +337,7 @@ module URI
#
def self.regexp(schemes = nil)# :nodoc:
warn "URI.regexp is obsolete", uplevel: 1 if $VERBOSE
- DEFAULT_PARSER.make_regexp(schemes)
+ PARSER.make_regexp(schemes)
end
TBLENCWWWCOMP_ = {} # :nodoc:
diff --git a/lib/uri/generic.rb b/lib/uri/generic.rb
index d811c5b944..6a0f638d76 100644
--- a/lib/uri/generic.rb
+++ b/lib/uri/generic.rb
@@ -186,18 +186,18 @@ module URI
if arg_check
self.scheme = scheme
- self.userinfo = userinfo
self.hostname = host
self.port = port
+ self.userinfo = userinfo
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_userinfo(userinfo)
self.set_path(path)
self.query = query
self.set_opaque(opaque)
@@ -466,7 +466,7 @@ module URI
#
# uri = URI.parse("http://john:S3nsit1ve@my.example.com")
# uri.user = "sam"
- # uri.to_s #=> "http://sam:V3ry_S3nsit1ve@my.example.com"
+ # uri.to_s #=> "http://sam@my.example.com"
#
def user=(user)
check_user(user)
@@ -511,7 +511,7 @@ module URI
user, password = split_userinfo(user)
end
@user = user
- @password = password if password
+ @password = password
[@user, @password]
end
@@ -522,7 +522,7 @@ module URI
# See also URI::Generic.user=.
#
def set_user(v)
- set_userinfo(v, @password)
+ set_userinfo(v, nil)
v
end
protected :set_user
@@ -574,6 +574,12 @@ module URI
@password
end
+ # Returns the authority info (array of user, password, host and
+ # port), if any is set. Or returns +nil+.
+ def authority
+ return @user, @password, @host, @port if @user || @password || @host || @port
+ end
+
# Returns the user component after URI decoding.
def decoded_user
URI.decode_uri_component(@user) if @user
@@ -615,6 +621,13 @@ module URI
end
protected :set_host
+ # Protected setter for the authority info (+user+, +password+, +host+
+ # and +port+). If +port+ is +nil+, +default_port+ will be set.
+ #
+ protected def set_authority(user, password, host, port = nil)
+ @user, @password, @host, @port = user, password, host, port || self.default_port
+ end
+
#
# == Args
#
@@ -639,6 +652,7 @@ module URI
def host=(v)
check_host(v)
set_host(v)
+ set_userinfo(nil)
v
end
@@ -729,6 +743,7 @@ module URI
def port=(v)
check_port(v)
set_port(v)
+ set_userinfo(nil)
port
end
@@ -1121,7 +1136,7 @@ module URI
base = self.dup
- authority = rel.userinfo || rel.host || rel.port
+ authority = rel.authority
# RFC2396, Section 5.2, 2)
if (rel.path.nil? || rel.path.empty?) && !authority && !rel.query
@@ -1134,9 +1149,7 @@ module URI
# RFC2396, Section 5.2, 4)
if authority
- base.set_userinfo(rel.userinfo)
- base.set_host(rel.host)
- base.set_port(rel.port || base.default_port)
+ base.set_authority(*authority)
base.set_path(rel.path)
elsif base.path && rel.path
base.set_path(merge_path(base.path, rel.path))
@@ -1527,7 +1540,7 @@ module URI
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
+ warn 'The environment variable HTTP_PROXY is discouraged. Please use http_proxy instead.', uplevel: 1
end
end
end
diff --git a/lib/uri/mailto.rb b/lib/uri/mailto.rb
index f747b79ec7..cb8024f301 100644
--- a/lib/uri/mailto.rb
+++ b/lib/uri/mailto.rb
@@ -52,11 +52,7 @@ module URI
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 = %r[\A#{
- atext = %q[(?:[a-zA-Z0-9!\#$%&'*+\/=?^_`{|}~-]+)]
- }(?:\.#{atext})*@#{
- label = %q[(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)]
- }(?:\.#{label})*\z]
+ 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:
#
diff --git a/lib/uri/version.rb b/lib/uri/version.rb
index b6a8ce1543..1f810602eb 100644
--- a/lib/uri/version.rb
+++ b/lib/uri/version.rb
@@ -1,6 +1,6 @@
module URI
# :stopdoc:
- VERSION_CODE = '010003'.freeze
- VERSION = VERSION_CODE.scan(/../).collect{|n| n.to_i}.join('.').freeze
+ VERSION = '1.1.1'.freeze
+ VERSION_CODE = VERSION.split('.').map{|s| s.rjust(2, '0')}.join.freeze
# :startdoc:
end
diff --git a/lib/weakref.rb b/lib/weakref.rb
index 0a09f7f993..c7274f9664 100644
--- a/lib/weakref.rb
+++ b/lib/weakref.rb
@@ -17,6 +17,7 @@ require "delegate"
#
class WeakRef < Delegator
+ # The version string
VERSION = "0.1.4"
##
diff --git a/lib/yaml.rb b/lib/yaml.rb
index 2cf11fc3df..c6f0f89fd2 100644
--- a/lib/yaml.rb
+++ b/lib/yaml.rb
@@ -66,5 +66,6 @@ YAML = Psych # :nodoc:
#
# Syck can also be found on github: https://github.com/ruby/syck
module YAML
+ # The version of YAML wrapper
LOADER_VERSION = "0.4.0"
end
diff --git a/libexec/erb b/libexec/erb
index 4381671f25..de7d5888c3 100755
--- a/libexec/erb
+++ b/libexec/erb
@@ -90,29 +90,49 @@ class ERB
when '-P'
disable_percent = true
when '--help'
- raise "print this help"
+ raise ''
when /\A-/
- raise "unknown switch #{switch.dump}"
+ raise "Unknown switch: #{switch.dump}"
else
var, val = *switch.split('=', 2)
(variables ||= {})[var] = val
end
end
rescue # usage
- STDERR.puts $!.to_s
- STDERR.puts File.basename($0) +
- " [switches] [var=value...] [inputfile]"
+ message = $!.to_s
+ STDERR.puts message unless message.empty?
+ STDERR.puts 'Usage:'
+ STDERR.puts " #{File.basename($0)} [options] [filepaths]"
STDERR.puts <<EOU
- -x print ruby script
- -n print ruby script with line number
- -v enable verbose mode
- -d set $DEBUG to true
- -r library load a library
- -E ex[:in] set default external/internal encodings
- -U set default encoding to UTF-8
- -T trim_mode specify trim_mode (0..2, -)
- -P disable ruby code evaluation for lines beginning with %
- var=value set variable
+
+Options:
+ -d --debug Set $DEBUG to enable debugging.
+ -E ex[:in] --encoding ex[:in]
+ Set default external and internal encodings.
+ -h --help Print this text and exit.
+ -n Print generated Ruby source code with line numbers;
+ ignored if given without option -x.
+ -P Disable execution tag shorthand (for lines beginning with '%').
+ -r library Load the named library.
+ -T trim_mode Specify trim_mode:
+ '0' means '%'; '1' means '%>'; '2' means '<>'; '-' means '%-'.
+ -U Set default encoding to UTF-8.
+ -v Set $VERBOSE to enable debugging,
+ --version Print ERB version string and exit.
+ -x Print generated Ruby source code.
+ -- Treat all following words as filepaths (not options).
+ name=value Set the variable named name to the given string value.
+
+Filepaths:
+ The erb program reads the text from all files at the filepaths as a single ERB template:
+ plain text, possibly with embedded ERB tags;
+ filepaths may be repeated.
+
+ The pseudo-filepath '-' (hyphen character) specifies the standard input.
+
+ If no filepaths are given, the sole input is the standard input.
+
+See details and examples at https://docs.ruby-lang.org/en/master/erb_executable_md.html
EOU
exit 1
end
diff --git a/load.c b/load.c
index b85a247c18..1ee66e2bfc 100644
--- a/load.c
+++ b/load.c
@@ -5,13 +5,13 @@
#include "dln.h"
#include "eval_intern.h"
#include "internal.h"
+#include "internal/box.h"
#include "internal/dir.h"
#include "internal/error.h"
#include "internal/eval.h"
#include "internal/file.h"
#include "internal/hash.h"
#include "internal/load.h"
-#include "internal/namespace.h"
#include "internal/ruby_parser.h"
#include "internal/thread.h"
#include "internal/variable.h"
@@ -23,54 +23,10 @@
#include "ractor_core.h"
#include "vm_core.h"
-static VALUE ruby_dln_libmap;
-
#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
-
-#define IS_NAMESPACE(obj) (CLASS_OF(obj) == rb_cNamespace)
-
-struct vm_and_namespace_struct {
- rb_vm_t *vm;
- rb_namespace_t *ns;
-};
-typedef struct vm_and_namespace_struct vm_ns_t;
-#define GET_vm_ns() vm_ns_t vm_ns_v = { .vm = GET_VM(), .ns = (rb_namespace_t *)rb_current_namespace(), }; vm_ns_t *vm_ns = &vm_ns_v;
-#define GET_loading_vm_ns() vm_ns_t vm_ns_v = { .vm = GET_VM(), .ns = (rb_namespace_t *)rb_loading_namespace(), }; vm_ns_t *vm_ns = &vm_ns_v;
-
-#define CURRENT_NS_attr(vm_ns, attr) (NAMESPACE_USER_P(vm_ns->ns) ? vm_ns->ns->attr : vm_ns->vm->attr)
-#define SET_NS_attr(vm_ns, attr, value) do { \
- if (NAMESPACE_USER_P(vm_ns->ns)) { vm_ns->ns->attr = value; } \
- else { vm_ns->vm->attr = value; } \
-} while (0)
-
-#define SET_NS_LOAD_PATH_CHECK_CACHE(vm_ns, value) SET_NS_attr(vm_ns, load_path_check_cache, value)
-#define SET_NS_EXPANDED_LOAD_PATH(vm_ns, value) SET_NS_attr(vm_ns, expanded_load_path, value)
-
-#define CURRENT_NS_LOAD_PATH(vm_ns) CURRENT_NS_attr(vm_ns, load_path)
-#define CURRENT_NS_LOAD_PATH_SNAPSHOT(vm_ns) CURRENT_NS_attr(vm_ns, load_path_snapshot)
-#define CURRENT_NS_LOAD_PATH_CHECK_CACHE(vm_ns) CURRENT_NS_attr(vm_ns, load_path_check_cache)
-#define CURRENT_NS_EXPANDED_LOAD_PATH(vm_ns) CURRENT_NS_attr(vm_ns, expanded_load_path)
-#define CURRENT_NS_LOADING_TABLE(vm_ns) CURRENT_NS_attr(vm_ns, loading_table)
-#define CURRENT_NS_LOADED_FEATURES(vm_ns) CURRENT_NS_attr(vm_ns, loaded_features)
-#define CURRENT_NS_LOADED_FEATURES_SNAPSHOT(vm_ns) CURRENT_NS_attr(vm_ns, loaded_features_snapshot)
-#define CURRENT_NS_LOADED_FEATURES_REALPATHS(vm_ns) CURRENT_NS_attr(vm_ns, loaded_features_realpaths)
-#define CURRENT_NS_LOADED_FEATURES_REALPATH_MAP(vm_ns) CURRENT_NS_attr(vm_ns, loaded_features_realpath_map)
-#define CURRENT_NS_LOADED_FEATURES_INDEX(vm_ns) CURRENT_NS_attr(vm_ns, loaded_features_index)
-
-#define CURRENT_NS_RUBY_DLN_LIBMAP(vm_ns, map) (NAMESPACE_USER_P(vm_ns->ns) ? vm_ns->ns->ruby_dln_libmap : map)
-
enum {
loadable_ext_rb = (0+ /* .rb extension is the first in both tables */
1) /* offset by rb_find_file_ext() */
@@ -99,10 +55,10 @@ enum expand_type {
string objects in $LOAD_PATH are frozen.
*/
static void
-rb_construct_expanded_load_path(vm_ns_t *vm_ns, enum expand_type type, int *has_relative, int *has_non_cache)
+rb_construct_expanded_load_path(rb_box_t *box, enum expand_type type, int *has_relative, int *has_non_cache)
{
- VALUE load_path = CURRENT_NS_LOAD_PATH(vm_ns);
- VALUE expanded_load_path = CURRENT_NS_EXPANDED_LOAD_PATH(vm_ns);
+ VALUE load_path = box->load_path;
+ VALUE expanded_load_path = box->expanded_load_path;
VALUE snapshot;
VALUE ary;
long i;
@@ -142,39 +98,39 @@ rb_construct_expanded_load_path(vm_ns_t *vm_ns, enum expand_type type, int *has_
rb_ary_push(ary, rb_fstring(expanded_path));
}
rb_ary_freeze(ary);
- SET_NS_EXPANDED_LOAD_PATH(vm_ns, ary);
- snapshot = CURRENT_NS_LOAD_PATH_SNAPSHOT(vm_ns);
- load_path = CURRENT_NS_LOAD_PATH(vm_ns);
+ box->expanded_load_path = ary;
+ snapshot = box->load_path_snapshot;
+ load_path = box->load_path;
rb_ary_replace(snapshot, load_path);
}
static VALUE
-get_expanded_load_path(vm_ns_t *vm_ns)
+get_expanded_load_path(rb_box_t *box)
{
VALUE check_cache;
const VALUE non_cache = Qtrue;
- const VALUE load_path_snapshot = CURRENT_NS_LOAD_PATH_SNAPSHOT(vm_ns);
- const VALUE load_path = CURRENT_NS_LOAD_PATH(vm_ns);
+ const VALUE load_path_snapshot = box->load_path_snapshot;
+ const VALUE load_path = box->load_path;
if (!rb_ary_shared_with_p(load_path_snapshot, load_path)) {
/* The load path was modified. Rebuild the expanded load path. */
int has_relative = 0, has_non_cache = 0;
- rb_construct_expanded_load_path(vm_ns, EXPAND_ALL, &has_relative, &has_non_cache);
+ rb_construct_expanded_load_path(box, EXPAND_ALL, &has_relative, &has_non_cache);
if (has_relative) {
- SET_NS_LOAD_PATH_CHECK_CACHE(vm_ns, rb_dir_getwd_ospath());
+ box->load_path_check_cache = rb_dir_getwd_ospath();
}
else if (has_non_cache) {
/* Non string object. */
- SET_NS_LOAD_PATH_CHECK_CACHE(vm_ns, non_cache);
+ box->load_path_check_cache = non_cache;
}
else {
- SET_NS_LOAD_PATH_CHECK_CACHE(vm_ns, 0);
+ box->load_path_check_cache = 0;
}
}
- else if ((check_cache = CURRENT_NS_LOAD_PATH_CHECK_CACHE(vm_ns)) == non_cache) {
+ else if ((check_cache = box->load_path_check_cache) == non_cache) {
int has_relative = 1, has_non_cache = 1;
/* Expand only non-cacheable objects. */
- rb_construct_expanded_load_path(vm_ns, EXPAND_NON_CACHE,
+ rb_construct_expanded_load_path(box, EXPAND_NON_CACHE,
&has_relative, &has_non_cache);
}
else if (check_cache) {
@@ -183,76 +139,49 @@ get_expanded_load_path(vm_ns_t *vm_ns)
if (!rb_str_equal(check_cache, cwd)) {
/* Current working directory or filesystem encoding was changed.
Expand relative load path and non-cacheable objects again. */
- SET_NS_LOAD_PATH_CHECK_CACHE(vm_ns, cwd);
- rb_construct_expanded_load_path(vm_ns, EXPAND_RELATIVE,
+ box->load_path_check_cache = cwd;
+ rb_construct_expanded_load_path(box, EXPAND_RELATIVE,
&has_relative, &has_non_cache);
}
else {
/* Expand only tilde (User HOME) and non-cacheable objects. */
- rb_construct_expanded_load_path(vm_ns, EXPAND_HOME,
+ rb_construct_expanded_load_path(box, EXPAND_HOME,
&has_relative, &has_non_cache);
}
}
- return CURRENT_NS_EXPANDED_LOAD_PATH(vm_ns);
+ return box->expanded_load_path;
}
VALUE
rb_get_expanded_load_path(void)
{
- GET_loading_vm_ns();
- return get_expanded_load_path(vm_ns);
-}
-
-static VALUE
-load_path_getter(ID id, VALUE * p)
-{
- GET_loading_vm_ns();
- return CURRENT_NS_LOAD_PATH(vm_ns);
-}
-
-static VALUE
-get_loaded_features(vm_ns_t *vm_ns)
-{
- return CURRENT_NS_LOADED_FEATURES(vm_ns);
+ return get_expanded_load_path((rb_box_t *)rb_loading_box());
}
static VALUE
-get_loaded_features_realpaths(vm_ns_t *vm_ns)
+load_path_getter(ID _x, VALUE * _y)
{
- return CURRENT_NS_LOADED_FEATURES_REALPATHS(vm_ns);
-}
-
-static VALUE
-get_loaded_features_realpath_map(vm_ns_t *vm_ns)
-{
- return CURRENT_NS_LOADED_FEATURES_REALPATH_MAP(vm_ns);
+ return rb_loading_box()->load_path;
}
static VALUE
get_LOADED_FEATURES(ID _x, VALUE *_y)
{
- GET_loading_vm_ns();
- return get_loaded_features(vm_ns);
+ return rb_loading_box()->loaded_features;
}
static void
-reset_loaded_features_snapshot(vm_ns_t *vm_ns)
+reset_loaded_features_snapshot(const rb_box_t *box)
{
- VALUE snapshot = CURRENT_NS_LOADED_FEATURES_SNAPSHOT(vm_ns);
- VALUE loaded_features = CURRENT_NS_LOADED_FEATURES(vm_ns);
+ VALUE snapshot = box->loaded_features_snapshot;
+ VALUE loaded_features = box->loaded_features;
rb_ary_replace(snapshot, loaded_features);
}
static struct st_table *
-get_loaded_features_index_raw(vm_ns_t *vm_ns)
-{
- return CURRENT_NS_LOADED_FEATURES_INDEX(vm_ns);
-}
-
-static st_table *
-get_loading_table(vm_ns_t *vm_ns)
+get_loaded_features_index_raw(const rb_box_t *box)
{
- return CURRENT_NS_LOADING_TABLE(vm_ns);
+ return box->loaded_features_index;
}
static st_data_t
@@ -273,7 +202,7 @@ is_rbext_path(VALUE feature_path)
typedef rb_darray(long) feature_indexes_t;
struct features_index_add_single_args {
- vm_ns_t *vm_ns;
+ const rb_box_t *box;
VALUE offset;
bool rb;
};
@@ -282,7 +211,7 @@ static int
features_index_add_single_callback(st_data_t *key, st_data_t *value, st_data_t raw_args, int existing)
{
struct features_index_add_single_args *args = (struct features_index_add_single_args *)raw_args;
- vm_ns_t *vm_ns = args->vm_ns;
+ const rb_box_t *box = args->box;
VALUE offset = args->offset;
bool rb = args->rb;
@@ -290,7 +219,7 @@ features_index_add_single_callback(st_data_t *key, st_data_t *value, st_data_t r
VALUE this_feature_index = *value;
if (FIXNUM_P(this_feature_index)) {
- VALUE loaded_features = get_loaded_features(vm_ns);
+ VALUE loaded_features = box->loaded_features;
VALUE this_feature_path = RARRAY_AREF(loaded_features, FIX2LONG(this_feature_index));
feature_indexes_t feature_indexes;
@@ -310,7 +239,7 @@ features_index_add_single_callback(st_data_t *key, st_data_t *value, st_data_t r
long pos = -1;
if (rb) {
- VALUE loaded_features = get_loaded_features(vm_ns);
+ VALUE loaded_features = box->loaded_features;
for (size_t i = 0; i < rb_darray_size(feature_indexes); ++i) {
long idx = rb_darray_get(feature_indexes, i);
VALUE this_feature_path = RARRAY_AREF(loaded_features, idx);
@@ -329,7 +258,7 @@ features_index_add_single_callback(st_data_t *key, st_data_t *value, st_data_t r
if (pos >= 0) {
long *ptr = rb_darray_data_ptr(feature_indexes);
long len = rb_darray_size(feature_indexes);
- MEMMOVE(ptr + pos, ptr + pos + 1, long, len - pos - 1);
+ MEMMOVE(ptr + pos + 1, ptr + pos, long, len - pos - 1);
ptr[pos] = FIX2LONG(offset);
}
}
@@ -342,7 +271,7 @@ features_index_add_single_callback(st_data_t *key, st_data_t *value, st_data_t r
}
static void
-features_index_add_single(vm_ns_t *vm_ns, const char* str, size_t len, VALUE offset, bool rb)
+features_index_add_single(const rb_box_t *box, const char* str, size_t len, VALUE offset, bool rb)
{
struct st_table *features_index;
st_data_t short_feature_key;
@@ -350,10 +279,10 @@ features_index_add_single(vm_ns_t *vm_ns, const char* str, size_t len, VALUE off
Check_Type(offset, T_FIXNUM);
short_feature_key = feature_key(str, len);
- features_index = get_loaded_features_index_raw(vm_ns);
+ features_index = get_loaded_features_index_raw(box);
struct features_index_add_single_args args = {
- .vm_ns = vm_ns,
+ .box = box,
.offset = offset,
.rb = rb,
};
@@ -370,7 +299,7 @@ features_index_add_single(vm_ns_t *vm_ns, const char* str, size_t len, VALUE off
relies on for its fast lookup.
*/
static void
-features_index_add(vm_ns_t *vm_ns, VALUE feature, VALUE offset)
+features_index_add(const rb_box_t *box, VALUE feature, VALUE offset)
{
RUBY_ASSERT(rb_ractor_main_p());
@@ -398,14 +327,14 @@ features_index_add(vm_ns_t *vm_ns, VALUE feature, VALUE offset)
if (p < feature_str)
break;
/* Now *p == '/'. We reach this point for every '/' in `feature`. */
- features_index_add_single(vm_ns, p + 1, feature_end - p - 1, offset, false);
+ features_index_add_single(box, p + 1, feature_end - p - 1, offset, false);
if (ext) {
- features_index_add_single(vm_ns, p + 1, ext - p - 1, offset, rb);
+ features_index_add_single(box, p + 1, ext - p - 1, offset, rb);
}
}
- features_index_add_single(vm_ns, feature_str, feature_end - feature_str, offset, false);
+ features_index_add_single(box, feature_str, feature_end - feature_str, offset, false);
if (ext) {
- features_index_add_single(vm_ns, feature_str, ext - feature_str, offset, rb);
+ features_index_add_single(box, feature_str, ext - feature_str, offset, rb);
}
}
@@ -414,39 +343,33 @@ loaded_features_index_clear_i(st_data_t key, st_data_t val, st_data_t arg)
{
VALUE obj = (VALUE)val;
if (!SPECIAL_CONST_P(obj)) {
- rb_darray_free((void *)obj);
+ rb_darray_free_sized((void *)obj, long);
}
return ST_DELETE;
}
-void
-rb_free_loaded_features_index(rb_vm_t *vm)
-{
- /* Destructs vm->loaded_features_index directly because this is only for
- the VM destruction */
- 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(vm_ns_t *vm_ns)
+get_loaded_features_index(const rb_box_t *box)
{
int i;
- VALUE features = CURRENT_NS_LOADED_FEATURES(vm_ns);
- const VALUE snapshot = CURRENT_NS_LOADED_FEATURES_SNAPSHOT(vm_ns);
+ VALUE features = box->loaded_features;
+ const VALUE snapshot = box->loaded_features_snapshot;
if (!rb_ary_shared_with_p(snapshot, features)) {
/* The sharing was broken; something (other than us in rb_provide_feature())
modified loaded_features. Rebuild the index. */
- st_foreach(CURRENT_NS_LOADED_FEATURES_INDEX(vm_ns), loaded_features_index_clear_i, 0);
+ st_foreach(box->loaded_features_index, loaded_features_index_clear_i, 0);
- VALUE realpaths = CURRENT_NS_LOADED_FEATURES_REALPATHS(vm_ns);
- VALUE realpath_map = CURRENT_NS_LOADED_FEATURES_REALPATH_MAP(vm_ns);
+ VALUE realpaths = box->loaded_features_realpaths;
+ VALUE realpath_map = box->loaded_features_realpath_map;
VALUE previous_realpath_map = rb_hash_dup(realpath_map);
rb_hash_clear(realpaths);
rb_hash_clear(realpath_map);
+
+ /* We have to make a copy of features here because the StringValue call
+ * below could call a Ruby method, which could modify $LOADED_FEATURES
+ * and cause it to be corrupt. */
+ features = rb_ary_resurrect(features);
for (i = 0; i < RARRAY_LEN(features); i++) {
VALUE entry, as_str;
as_str = entry = rb_ary_entry(features, i);
@@ -454,11 +377,15 @@ get_loaded_features_index(vm_ns_t *vm_ns)
as_str = rb_fstring(as_str);
if (as_str != entry)
rb_ary_store(features, i, as_str);
- features_index_add(vm_ns, as_str, INT2FIX(i));
+ features_index_add(box, as_str, INT2FIX(i));
+ }
+ /* The user modified $LOADED_FEATURES, so we should restore the changes. */
+ if (!rb_ary_shared_with_p(features, box->loaded_features)) {
+ rb_ary_replace(box->loaded_features, features);
}
- reset_loaded_features_snapshot(vm_ns);
+ reset_loaded_features_snapshot(box);
- features = CURRENT_NS_LOADED_FEATURES_SNAPSHOT(vm_ns);
+ features = box->loaded_features_snapshot;
long j = RARRAY_LEN(features);
for (i = 0; i < j; i++) {
VALUE as_str = rb_ary_entry(features, i);
@@ -472,7 +399,7 @@ get_loaded_features_index(vm_ns_t *vm_ns)
rb_hash_aset(realpath_map, as_str, realpath);
}
}
- return CURRENT_NS_LOADED_FEATURES_INDEX(vm_ns);
+ return box->loaded_features_index;
}
/* This searches `load_path` for a value such that
@@ -557,7 +484,7 @@ loaded_feature_path_i(st_data_t v, st_data_t b, st_data_t f)
* 'u': unsuffixed
*/
static int
-rb_feature_p(vm_ns_t *vm_ns, const char *feature, const char *ext, int rb, int expanded, const char **fn)
+rb_feature_p(const rb_box_t *box, const char *feature, const char *ext, int rb, int expanded, const char **fn)
{
VALUE features, this_feature_index = Qnil, v, p, load_path = 0;
const char *f, *e;
@@ -578,8 +505,8 @@ rb_feature_p(vm_ns_t *vm_ns, const char *feature, const char *ext, int rb, int e
elen = 0;
type = 0;
}
- features = get_loaded_features(vm_ns);
- features_index = get_loaded_features_index(vm_ns);
+ features = box->loaded_features;
+ features_index = get_loaded_features_index(box);
key = feature_key(feature, strlen(feature));
/* We search `features` for an entry such that either
@@ -621,12 +548,13 @@ rb_feature_p(vm_ns_t *vm_ns, const char *feature, const char *ext, int rb, int e
index = rb_darray_get(feature_indexes, i);
}
+ if (index >= RARRAY_LEN(features)) continue;
v = RARRAY_AREF(features, index);
f = StringValuePtr(v);
if ((n = RSTRING_LEN(v)) < len) continue;
if (strncmp(f, feature, len) != 0) {
if (expanded) continue;
- if (!load_path) load_path = get_expanded_load_path(vm_ns);
+ if (!load_path) load_path = get_expanded_load_path((rb_box_t *)box);
if (!(p = loaded_feature_path(f, n, feature, len, type, load_path)))
continue;
expanded = 1;
@@ -646,14 +574,14 @@ rb_feature_p(vm_ns_t *vm_ns, const char *feature, const char *ext, int rb, int e
}
}
- loading_tbl = get_loading_table(vm_ns);
+ loading_tbl = box->loading_table;
f = 0;
if (!expanded && !rb_is_absolute_path(feature)) {
struct loaded_feature_searching fs;
fs.name = feature;
fs.len = len;
fs.type = type;
- fs.load_path = load_path ? load_path : get_expanded_load_path(vm_ns);
+ fs.load_path = load_path ? load_path : get_expanded_load_path((rb_box_t *)box);
fs.result = 0;
st_foreach(loading_tbl, loaded_feature_path_i, (st_data_t)&fs);
if ((f = fs.result) != 0) {
@@ -708,7 +636,7 @@ rb_provided(const char *feature)
}
static int
-feature_provided(vm_ns_t *vm_ns, const char *feature, const char **loading)
+feature_provided(rb_box_t *box, const char *feature, const char **loading)
{
const char *ext = strrchr(feature, '.');
VALUE fullpath = 0;
@@ -720,15 +648,15 @@ feature_provided(vm_ns_t *vm_ns, const char *feature, const char **loading)
}
if (ext && !strchr(ext, '/')) {
if (IS_RBEXT(ext)) {
- if (rb_feature_p(vm_ns, feature, ext, TRUE, FALSE, loading)) return TRUE;
+ if (rb_feature_p(box, feature, ext, TRUE, FALSE, loading)) return TRUE;
return FALSE;
}
else if (IS_SOEXT(ext) || IS_DLEXT(ext)) {
- if (rb_feature_p(vm_ns, feature, ext, FALSE, FALSE, loading)) return TRUE;
+ if (rb_feature_p(box, feature, ext, FALSE, FALSE, loading)) return TRUE;
return FALSE;
}
}
- if (rb_feature_p(vm_ns, feature, 0, TRUE, FALSE, loading))
+ if (rb_feature_p(box, feature, 0, TRUE, FALSE, loading))
return TRUE;
RB_GC_GUARD(fullpath);
return FALSE;
@@ -737,41 +665,40 @@ feature_provided(vm_ns_t *vm_ns, const char *feature, const char **loading)
int
rb_feature_provided(const char *feature, const char **loading)
{
- GET_vm_ns();
- return feature_provided(vm_ns, feature, loading);
+ rb_box_t *box = (rb_box_t *)rb_current_box();
+ return feature_provided(box, feature, loading);
}
static void
-rb_provide_feature(vm_ns_t *vm_ns, VALUE feature)
+rb_provide_feature(const rb_box_t *box, VALUE feature)
{
VALUE features;
- features = get_loaded_features(vm_ns);
+ features = box->loaded_features;
if (OBJ_FROZEN(features)) {
rb_raise(rb_eRuntimeError,
"$LOADED_FEATURES is frozen; cannot append feature");
}
feature = rb_fstring(feature);
- get_loaded_features_index(vm_ns);
+ get_loaded_features_index(box);
// 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(CURRENT_NS_LOADED_FEATURES_SNAPSHOT(vm_ns));
+ rb_ary_clear(box->loaded_features_snapshot);
rb_ary_push(features, feature);
- features_index_add(vm_ns, feature, INT2FIX(RARRAY_LEN(features)-1));
- reset_loaded_features_snapshot(vm_ns);
+ features_index_add(box, feature, INT2FIX(RARRAY_LEN(features)-1));
+ reset_loaded_features_snapshot(box);
}
void
rb_provide(const char *feature)
{
/*
- * rb_provide() must use rb_current_namespace to store provided features
- * in the current namespace's loaded_features, etc.
+ * rb_provide() must use rb_current_box to store provided features
+ * in the current box's loaded_features, etc.
*/
- GET_vm_ns();
- rb_provide_feature(vm_ns, rb_fstring_cstr(feature));
+ rb_provide_feature(rb_current_box(), rb_fstring_cstr(feature));
}
NORETURN(static void load_failed(VALUE));
@@ -789,39 +716,21 @@ realpath_internal_cached(VALUE hash, VALUE path)
return realpath;
}
-struct iseq_eval_in_namespace_data {
- const rb_iseq_t *iseq;
- bool in_builtin;
-};
-
-static VALUE
-iseq_eval_in_namespace(VALUE arg)
-{
- struct iseq_eval_in_namespace_data *data = (struct iseq_eval_in_namespace_data *)arg;
- if (rb_namespace_available() && data->in_builtin) {
- return rb_iseq_eval_with_refinement(data->iseq, rb_mNamespaceRefiner);
- }
- else {
- return rb_iseq_eval(data->iseq);
- }
-}
-
static inline void
load_iseq_eval(rb_execution_context_t *ec, VALUE fname)
{
- GET_loading_vm_ns();
- const rb_namespace_t *loading_ns = rb_loading_namespace();
+ const rb_box_t *box = rb_loading_box();
const rb_iseq_t *iseq = rb_iseq_load_iseq(fname);
if (!iseq) {
rb_execution_context_t *ec = GET_EC();
VALUE v = rb_vm_push_frame_fname(ec, fname);
- VALUE realpath_map = get_loaded_features_realpath_map(vm_ns);
+ VALUE realpath_map = box->loaded_features_realpath_map;
if (rb_ruby_prism_p()) {
- pm_parse_result_t result = { 0 };
- result.options.line = 1;
+ pm_parse_result_t result;
+ pm_parse_result_init(&result);
result.node.coverage_enabled = 1;
VALUE error = pm_load_parse_file(&result, fname, NULL);
@@ -862,23 +771,14 @@ load_iseq_eval(rb_execution_context_t *ec, VALUE fname)
}
rb_exec_event_hook_script_compiled(ec, iseq, Qnil);
- if (loading_ns) {
- struct iseq_eval_in_namespace_data arg = {
- .iseq = iseq,
- .in_builtin = NAMESPACE_BUILTIN_P(loading_ns),
- };
- rb_namespace_exec(loading_ns, iseq_eval_in_namespace, (VALUE)&arg);
- }
- else {
- rb_iseq_eval(iseq);
- }
+ rb_iseq_eval(iseq, box);
}
static inline enum ruby_tag_type
load_wrapping(rb_execution_context_t *ec, VALUE fname, VALUE load_wrapper)
{
enum ruby_tag_type state;
- rb_namespace_t *ns;
+ rb_box_t *box;
rb_thread_t *th = rb_ec_thread_ptr(ec);
volatile VALUE wrapper = th->top_wrapper;
volatile VALUE self = th->top_self;
@@ -889,12 +789,12 @@ load_wrapping(rb_execution_context_t *ec, VALUE fname, VALUE load_wrapper)
ec->errinfo = Qnil; /* ensure */
/* load in module as toplevel */
- if (IS_NAMESPACE(load_wrapper)) {
- ns = rb_get_namespace_t(load_wrapper);
- if (!ns->top_self) {
- ns->top_self = rb_obj_clone(rb_vm_top_self());
+ if (BOX_OBJ_P(load_wrapper)) {
+ box = rb_get_box_t(load_wrapper);
+ if (!box->top_self) {
+ box->top_self = rb_obj_clone(rb_vm_top_self());
}
- th->top_self = ns->top_self;
+ th->top_self = box->top_self;
}
else {
th->top_self = rb_obj_clone(rb_vm_top_self());
@@ -933,9 +833,9 @@ raise_load_if_failed(rb_execution_context_t *ec, enum ruby_tag_type state)
static void
rb_load_internal(VALUE fname, VALUE wrap)
{
- VALUE namespace;
+ VALUE box_value;
rb_execution_context_t *ec = GET_EC();
- const rb_namespace_t *ns = rb_loading_namespace();
+ const rb_box_t *box = rb_loading_box();
enum ruby_tag_type state = TAG_NONE;
if (RTEST(wrap)) {
if (!RB_TYPE_P(wrap, T_MODULE)) {
@@ -943,9 +843,9 @@ rb_load_internal(VALUE fname, VALUE wrap)
}
state = load_wrapping(ec, fname, wrap);
}
- else if (NAMESPACE_OPTIONAL_P(ns)) {
- namespace = ns->ns_object;
- state = load_wrapping(ec, fname, namespace);
+ else if (BOX_OPTIONAL_P(box)) {
+ box_value = box->box_object;
+ state = load_wrapping(ec, fname, box_value);
}
else {
load_iseq_eval(ec, fname);
@@ -975,8 +875,8 @@ rb_load_protect(VALUE fname, int wrap, int *pstate)
if (state != TAG_NONE) *pstate = state;
}
-static VALUE
-load_entrypoint_internal(VALUE fname, VALUE wrap)
+VALUE
+rb_load_entrypoint(VALUE fname, VALUE wrap)
{
VALUE path, orig_fname;
@@ -997,18 +897,6 @@ load_entrypoint_internal(VALUE fname, VALUE wrap)
return Qtrue;
}
-VALUE
-rb_load_entrypoint(VALUE args)
-{
- VALUE fname, wrap;
- if (RARRAY_LEN(args) != 2) {
- rb_bug("invalid arguments: %ld", RARRAY_LEN(args));
- }
- fname = rb_ary_entry(args, 0);
- wrap = rb_ary_entry(args, 1);
- return load_entrypoint_internal(fname, wrap);
-}
-
/*
* call-seq:
* load(filename, wrap=false) -> true
@@ -1044,14 +932,14 @@ rb_f_load(int argc, VALUE *argv, VALUE _)
{
VALUE fname, wrap;
rb_scan_args(argc, argv, "11", &fname, &wrap);
- return load_entrypoint_internal(fname, wrap);
+ return rb_load_entrypoint(fname, wrap);
}
static char *
-load_lock(vm_ns_t *vm_ns, const char *ftptr, bool warn)
+load_lock(const rb_box_t *box, const char *ftptr, bool warn)
{
st_data_t data;
- st_table *loading_tbl = get_loading_table(vm_ns);
+ st_table *loading_tbl = box->loading_table;
if (!st_lookup(loading_tbl, (st_data_t)ftptr, &data)) {
/* partial state */
@@ -1093,11 +981,11 @@ release_thread_shield(st_data_t *key, st_data_t *value, st_data_t done, int exis
}
static void
-load_unlock(vm_ns_t *vm_ns, const char *ftptr, int done)
+load_unlock(const rb_box_t *box, const char *ftptr, int done)
{
if (ftptr) {
st_data_t key = (st_data_t)ftptr;
- st_table *loading_tbl = get_loading_table(vm_ns);
+ st_table *loading_tbl = box->loading_table;
st_update(loading_tbl, key, release_thread_shield, done);
}
@@ -1145,8 +1033,6 @@ static VALUE rb_require_string_internal(VALUE fname, bool resurrect);
VALUE
rb_f_require(VALUE obj, VALUE fname)
{
- // const rb_namespace_t *ns = rb_loading_namespace();
- // printf("F:current loading ns: %ld\n", ns->ns_id);
return rb_require_string(fname);
}
@@ -1176,10 +1062,10 @@ rb_f_require_relative(VALUE obj, VALUE fname)
return rb_require_relative_entrypoint(fname);
}
-typedef int (*feature_func)(vm_ns_t *vm_ns, const char *feature, const char *ext, int rb, int expanded, const char **fn);
+typedef int (*feature_func)(const rb_box_t *box, const char *feature, const char *ext, int rb, int expanded, const char **fn);
static int
-search_required(vm_ns_t *vm_ns, VALUE fname, volatile VALUE *path, feature_func rb_feature_p)
+search_required(const rb_box_t *box, VALUE fname, volatile VALUE *path, feature_func rb_feature_p)
{
VALUE tmp;
char *ext, *ftptr;
@@ -1190,20 +1076,20 @@ search_required(vm_ns_t *vm_ns, VALUE fname, volatile VALUE *path, feature_func
ext = strrchr(ftptr = RSTRING_PTR(fname), '.');
if (ext && !strchr(ext, '/')) {
if (IS_RBEXT(ext)) {
- if (rb_feature_p(vm_ns, ftptr, ext, TRUE, FALSE, &loading)) {
+ if (rb_feature_p(box, ftptr, ext, TRUE, FALSE, &loading)) {
if (loading) *path = rb_filesystem_str_new_cstr(loading);
return 'r';
}
if ((tmp = rb_find_file(fname)) != 0) {
ext = strrchr(ftptr = RSTRING_PTR(tmp), '.');
- if (!rb_feature_p(vm_ns, ftptr, ext, TRUE, TRUE, &loading) || loading)
+ if (!rb_feature_p(box, ftptr, ext, TRUE, TRUE, &loading) || loading)
*path = tmp;
return 'r';
}
return 0;
}
else if (IS_SOEXT(ext)) {
- if (rb_feature_p(vm_ns, ftptr, ext, FALSE, FALSE, &loading)) {
+ if (rb_feature_p(box, ftptr, ext, FALSE, FALSE, &loading)) {
if (loading) *path = rb_filesystem_str_new_cstr(loading);
return 's';
}
@@ -1212,25 +1098,25 @@ search_required(vm_ns_t *vm_ns, VALUE fname, volatile VALUE *path, feature_func
OBJ_FREEZE(tmp);
if ((tmp = rb_find_file(tmp)) != 0) {
ext = strrchr(ftptr = RSTRING_PTR(tmp), '.');
- if (!rb_feature_p(vm_ns, ftptr, ext, FALSE, TRUE, &loading) || loading)
+ if (!rb_feature_p(box, ftptr, ext, FALSE, TRUE, &loading) || loading)
*path = tmp;
return 's';
}
}
else if (IS_DLEXT(ext)) {
- if (rb_feature_p(vm_ns, ftptr, ext, FALSE, FALSE, &loading)) {
+ if (rb_feature_p(box, ftptr, ext, FALSE, FALSE, &loading)) {
if (loading) *path = rb_filesystem_str_new_cstr(loading);
return 's';
}
if ((tmp = rb_find_file(fname)) != 0) {
ext = strrchr(ftptr = RSTRING_PTR(tmp), '.');
- if (!rb_feature_p(vm_ns, ftptr, ext, FALSE, TRUE, &loading) || loading)
+ if (!rb_feature_p(box, ftptr, ext, FALSE, TRUE, &loading) || loading)
*path = tmp;
return 's';
}
}
}
- else if ((ft = rb_feature_p(vm_ns, ftptr, 0, FALSE, FALSE, &loading)) == 'r') {
+ else if ((ft = rb_feature_p(box, ftptr, 0, FALSE, FALSE, &loading)) == 'r') {
if (loading) *path = rb_filesystem_str_new_cstr(loading);
return 'r';
}
@@ -1239,20 +1125,23 @@ search_required(vm_ns_t *vm_ns, VALUE fname, volatile VALUE *path, feature_func
// 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_ns->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.
- // See encinit.c and extinit.c (generated at build-time).
- if (!ext) {
- lookup_name = rb_str_dup(lookup_name);
- rb_str_cat_cstr(lookup_name, ".so");
- }
- ftptr = RSTRING_PTR(lookup_name);
- if (st_lookup(vm_ns->vm->static_ext_inits, (st_data_t)ftptr, NULL)) {
- *path = rb_filesystem_str_new_cstr(ftptr);
- RB_GC_GUARD(lookup_name);
- return 's';
+ if (!ft && type != loadable_ext_rb) {
+ rb_vm_t *vm = GET_VM();
+ if (vm->static_ext_inits.num_entries) {
+ 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.
+ // See encinit.c and extinit.c (generated at build-time).
+ if (!ext) {
+ lookup_name = rb_str_dup(lookup_name);
+ rb_str_cat_cstr(lookup_name, ".so");
+ }
+ ftptr = RSTRING_PTR(lookup_name);
+ if (st_lookup(&vm->static_ext_inits, (st_data_t)ftptr, NULL)) {
+ *path = rb_filesystem_str_new_cstr(ftptr);
+ RB_GC_GUARD(lookup_name);
+ return 's';
+ }
}
}
@@ -1261,7 +1150,7 @@ search_required(vm_ns_t *vm_ns, VALUE fname, volatile VALUE *path, feature_func
if (ft)
goto feature_present;
ftptr = RSTRING_PTR(tmp);
- return rb_feature_p(vm_ns, ftptr, 0, FALSE, TRUE, 0);
+ return rb_feature_p(box, ftptr, 0, FALSE, TRUE, 0);
default:
if (ft) {
@@ -1270,7 +1159,7 @@ search_required(vm_ns_t *vm_ns, VALUE fname, volatile VALUE *path, feature_func
/* fall through */
case loadable_ext_rb:
ext = strrchr(ftptr = RSTRING_PTR(tmp), '.');
- if (rb_feature_p(vm_ns, ftptr, ext, type == loadable_ext_rb, TRUE, &loading) && !loading)
+ if (rb_feature_p(box, ftptr, ext, type == loadable_ext_rb, TRUE, &loading) && !loading)
break;
*path = tmp;
}
@@ -1291,45 +1180,54 @@ static VALUE
load_ext(VALUE path, VALUE fname)
{
VALUE loaded = path;
- GET_loading_vm_ns();
- if (NAMESPACE_USER_P(vm_ns->ns)) {
- loaded = rb_namespace_local_extension(vm_ns->ns->ns_object, fname, path);
+ const rb_box_t *box = rb_loading_box();
+ VALUE cleanup = 0;
+ if (BOX_USER_P(box)) {
+ loaded = rb_box_local_extension(box->box_object, fname, path, &cleanup);
}
rb_scope_visibility_set(METHOD_VISI_PUBLIC);
- return (VALUE)dln_load_feature(RSTRING_PTR(loaded), RSTRING_PTR(fname));
+ void *handle = dln_load_feature(RSTRING_PTR(loaded), RSTRING_PTR(fname));
+ if (cleanup) {
+ rb_box_cleanup_local_extension(cleanup);
+ }
+ RB_GC_GUARD(loaded);
+ RB_GC_GUARD(fname);
+ return (VALUE)handle;
}
-static bool
-run_static_ext_init(rb_vm_t *vm, const char *feature)
+static VALUE
+run_static_ext_init(VALUE vm_ptr, VALUE feature_value)
{
+ rb_vm_t *vm = (rb_vm_t *)vm_ptr;
+ const char *feature = RSTRING_PTR(feature_value);
st_data_t key = (st_data_t)feature;
st_data_t init_func;
- if (vm->static_ext_inits && st_delete(vm->static_ext_inits, &key, &init_func)) {
+ if (st_delete(&vm->static_ext_inits, &key, &init_func)) {
((void (*)(void))init_func)();
- return true;
+ return Qtrue;
}
- return false;
+ return Qfalse;
}
static int
-no_feature_p(vm_ns_t *vm_ns, const char *feature, const char *ext, int rb, int expanded, const char **fn)
+no_feature_p(const rb_box_t *box, const char *feature, const char *ext, int rb, int expanded, const char **fn)
{
return 0;
}
-// Documented in doc/globals.md
+// Documented in doc/language/globals.md
VALUE
rb_resolve_feature_path(VALUE klass, VALUE fname)
{
VALUE path;
int found;
VALUE sym;
- GET_loading_vm_ns();
+ const rb_box_t *box = rb_loading_box();
fname = rb_get_path(fname);
path = rb_str_encode_ospath(fname);
- found = search_required(vm_ns, path, &path, no_feature_p);
+ found = search_required(box, path, &path, no_feature_p);
switch (found) {
case 'r':
@@ -1364,21 +1262,6 @@ rb_ext_ractor_safe(bool flag)
GET_THREAD()->ext_config.ractor_safe = flag;
}
-struct rb_vm_call_cfunc2_data {
- VALUE recv;
- VALUE arg1;
- VALUE arg2;
- VALUE block_handler;
- VALUE filename;
-};
-
-static VALUE
-call_load_ext_in_ns(VALUE data)
-{
- struct rb_vm_call_cfunc2_data *arg = (struct rb_vm_call_cfunc2_data *)data;
- return rb_vm_call_cfunc2(arg->recv, load_ext, arg->arg1, arg->arg2, arg->block_handler, arg->filename);
-}
-
/*
* returns
* 0: if already loaded (false)
@@ -1391,21 +1274,22 @@ require_internal(rb_execution_context_t *ec, VALUE fname, int exception, bool wa
{
volatile int result = -1;
rb_thread_t *th = rb_ec_thread_ptr(ec);
+ const rb_box_t *box = rb_loading_box();
volatile const struct {
VALUE wrapper, self, errinfo;
rb_execution_context_t *ec;
+ const rb_box_t *box;
} saved = {
th->top_wrapper, th->top_self, ec->errinfo,
- ec,
+ ec, box,
};
- GET_loading_vm_ns();
enum ruby_tag_type state;
char *volatile ftptr = 0;
VALUE path;
volatile VALUE saved_path;
volatile VALUE realpath = 0;
- VALUE realpaths = get_loaded_features_realpaths(vm_ns);
- VALUE realpath_map = get_loaded_features_realpath_map(vm_ns);
+ VALUE realpaths = box->loaded_features_realpaths;
+ VALUE realpath_map = box->loaded_features_realpath_map;
volatile bool reset_ext_config = false;
volatile struct rb_ext_config prev_ext_config;
@@ -1421,18 +1305,18 @@ require_internal(rb_execution_context_t *ec, VALUE fname, int exception, bool wa
int found;
RUBY_DTRACE_HOOK(FIND_REQUIRE_ENTRY, RSTRING_PTR(fname));
- found = search_required(vm_ns, path, &saved_path, rb_feature_p);
+ found = search_required(box, path, &saved_path, rb_feature_p);
RUBY_DTRACE_HOOK(FIND_REQUIRE_RETURN, RSTRING_PTR(fname));
path = saved_path;
if (found) {
- if (!path || !(ftptr = load_lock(vm_ns, RSTRING_PTR(path), warn))) {
+ if (!path || !(ftptr = load_lock(box, RSTRING_PTR(path), warn))) {
result = 0;
}
else if (!*ftptr) {
result = TAG_RETURN;
}
- else if (found == 's' && run_static_ext_init(th->vm, RSTRING_PTR(path))) {
+ else if (found == 's' && RTEST(rb_vm_call_cfunc_in_box(Qnil, run_static_ext_init, (VALUE)th->vm, path, path, box))) {
result = TAG_RETURN;
}
else if (RTEST(rb_hash_aref(realpaths,
@@ -1442,31 +1326,14 @@ require_internal(rb_execution_context_t *ec, VALUE fname, int exception, bool wa
else {
switch (found) {
case 'r':
- // iseq_eval_in_namespace will be called with the loading namespace eventually
- if (NAMESPACE_OPTIONAL_P(vm_ns->ns)) {
- // check with NAMESPACE_OPTIONAL_P (not NAMESPACE_USER_P) for NS1::xxx naming
- // it is not expected for the main namespace
- load_wrapping(saved.ec, path, vm_ns->ns->ns_object);
- }
- else {
- load_iseq_eval(saved.ec, path);
- }
+ load_iseq_eval(saved.ec, path);
break;
case 's':
- // the loading namespace must be set to the current namespace before calling load_ext
reset_ext_config = true;
ext_config_push(th, &prev_ext_config);
- struct rb_vm_call_cfunc2_data arg = {
- .recv = rb_vm_top_self(),
- .arg1 = path,
- .arg2 = fname,
- .block_handler = VM_BLOCK_HANDLER_NONE,
- .filename = path,
- };
- handle = rb_namespace_exec(vm_ns->ns, call_load_ext_in_ns, (VALUE)&arg);
- rb_hash_aset(CURRENT_NS_RUBY_DLN_LIBMAP(vm_ns, ruby_dln_libmap), path,
- SVALUE2NUM((SIGNED_VALUE)handle));
+ handle = rb_vm_call_cfunc_in_box(box->top_self, load_ext, path, fname, path, box);
+ rb_hash_aset(box->ruby_dln_libmap, path, PTR2NUM(handle));
break;
}
result = TAG_RETURN;
@@ -1476,13 +1343,14 @@ require_internal(rb_execution_context_t *ec, VALUE fname, int exception, bool wa
EC_POP_TAG();
ec = saved.ec;
+ box = saved.box;
rb_thread_t *th2 = rb_ec_thread_ptr(ec);
th2->top_self = saved.self;
th2->top_wrapper = saved.wrapper;
if (reset_ext_config) ext_config_pop(th2, &prev_ext_config);
path = saved_path;
- if (ftptr) load_unlock(vm_ns, RSTRING_PTR(path), !state);
+ if (ftptr) load_unlock(box, RSTRING_PTR(path), !state);
if (state) {
if (state == TAG_FATAL || state == TAG_THROW) {
@@ -1508,7 +1376,7 @@ require_internal(rb_execution_context_t *ec, VALUE fname, int exception, bool wa
}
if (result == TAG_RETURN) {
- rb_provide_feature(vm_ns, path);
+ rb_provide_feature(box, path);
VALUE real = realpath;
if (real) {
real = rb_fstring(real);
@@ -1543,7 +1411,7 @@ rb_require_internal(VALUE fname)
int
ruby_require_internal(const char *fname, unsigned int len)
{
- struct RString fake;
+ struct RString fake = {RBASIC_INIT};
VALUE str = rb_setup_fake_str(&fake, fname, len, 0);
rb_execution_context_t *ec = GET_EC();
int result = require_internal(ec, str, 0, RTEST(ruby_verbose));
@@ -1585,7 +1453,7 @@ rb_require_string_internal(VALUE fname, bool resurrect)
VALUE
rb_require(const char *fname)
{
- struct RString fake;
+ struct RString fake = {RBASIC_INIT};
VALUE str = rb_setup_fake_str(&fake, fname, strlen(fname), 0);
return rb_require_string_internal(str, true);
}
@@ -1610,18 +1478,13 @@ register_init_ext(st_data_t *key, st_data_t *value, st_data_t init, int existing
void
ruby_init_ext(const char *name, void (*init)(void))
{
- st_table *inits_table;
- GET_loading_vm_ns();
+ rb_vm_t *vm = GET_VM();
+ const rb_box_t *box = rb_loading_box();
- if (feature_provided(vm_ns, name, 0))
+ if (feature_provided((rb_box_t *)box, name, 0))
return;
- inits_table = vm_ns->vm->static_ext_inits;
- if (!inits_table) {
- inits_table = st_init_strtable();
- vm_ns->vm->static_ext_inits = inits_table;
- }
- st_update(inits_table, (st_data_t)name, register_init_ext, (st_data_t)init);
+ st_update(&vm->static_ext_inits, (st_data_t)name, register_init_ext, (st_data_t)init);
}
/*
@@ -1657,6 +1520,49 @@ rb_mod_autoload(VALUE mod, VALUE sym, VALUE file)
/*
* call-seq:
+ * mod.autoload_relative(const, filename) -> nil
+ *
+ * Registers _filename_ to be loaded (using Kernel::require)
+ * the first time that _const_ (which may be a String or
+ * a symbol) is accessed in the namespace of _mod_. The _filename_
+ * is interpreted as relative to the directory of the file where
+ * autoload_relative is called.
+ *
+ * module A
+ * end
+ * A.autoload_relative(:B, "b.rb")
+ *
+ * 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.
+ *
+ * The relative path is converted to an absolute path, which is what
+ * will be returned by Module#autoload? for the constant.
+ *
+ * Raises LoadError if called without file context (e.g., from eval).
+ */
+
+static VALUE
+rb_mod_autoload_relative(VALUE mod, VALUE sym, VALUE file)
+{
+ ID id = rb_to_id(sym);
+ VALUE base, absolute_path;
+
+ FilePathValue(file);
+
+ base = rb_current_realfilepath();
+ if (NIL_P(base)) {
+ rb_loaderror("cannot infer basepath (autoload_relative called without file context)");
+ }
+ base = rb_file_dirname(base);
+ absolute_path = rb_file_absolute_path(file, base);
+
+ rb_autoload_str(mod, id, absolute_path);
+ return Qnil;
+}
+
+/*
+ * call-seq:
* mod.autoload?(name, inherit=true) -> String or nil
*
* Returns _filename_ to be loaded if _name_ is registered as
@@ -1724,6 +1630,38 @@ rb_f_autoload(VALUE obj, VALUE sym, VALUE file)
/*
* call-seq:
+ * autoload_relative(const, filename) -> nil
+ *
+ * Registers _filename_ to be loaded (using Kernel::require)
+ * the first time that _const_ (which may be a String or
+ * a symbol) is accessed. The _filename_ is interpreted as
+ * relative to the directory of the file where autoload_relative
+ * is called.
+ *
+ * autoload_relative(:MyModule, "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.
+ *
+ * The relative path is converted to an absolute path, which is what
+ * will be returned by Kernel#autoload? for the constant.
+ *
+ * Raises LoadError if called without file context (e.g., from eval).
+ */
+
+static VALUE
+rb_f_autoload_relative(VALUE obj, VALUE sym, VALUE file)
+{
+ VALUE klass = rb_class_real(rb_vm_cbase());
+ if (!klass) {
+ rb_raise(rb_eTypeError, "Can not set autoload on singleton class");
+ }
+ return rb_mod_autoload_relative(klass, sym, file);
+}
+
+/*
+ * call-seq:
* autoload?(name, inherit=true) -> String or nil
*
* Returns _filename_ to be loaded if _name_ is registered as
@@ -1762,9 +1700,9 @@ rb_ext_resolve_symbol(const char* fname, const char* symbol)
VALUE handle;
VALUE resolved;
VALUE path;
- char *ext;
+ const char *ext;
VALUE fname_str = rb_str_new_cstr(fname);
- GET_loading_vm_ns();
+ const rb_box_t *box = rb_loading_box();
resolved = rb_resolve_feature_path((VALUE)NULL, fname_str);
if (NIL_P(resolved)) {
@@ -1772,7 +1710,7 @@ rb_ext_resolve_symbol(const char* fname, const char* symbol)
if (!ext || !IS_SOEXT(ext)) {
rb_str_cat_cstr(fname_str, ".so");
}
- if (rb_feature_p(vm_ns, fname, 0, FALSE, FALSE, 0)) {
+ if (rb_feature_p(box, fname, 0, FALSE, FALSE, 0)) {
return dln_symbol(NULL, symbol);
}
return NULL;
@@ -1781,50 +1719,36 @@ rb_ext_resolve_symbol(const char* fname, const char* symbol)
return NULL;
}
path = rb_ary_entry(resolved, 1);
- handle = rb_hash_lookup(CURRENT_NS_RUBY_DLN_LIBMAP(vm_ns, ruby_dln_libmap), path);
+ handle = rb_hash_lookup(box->ruby_dln_libmap, path);
if (NIL_P(handle)) {
return NULL;
}
- return dln_symbol((void *)NUM2SVALUE(handle), symbol);
+ return dln_symbol(NUM2PTR(handle), symbol);
}
void
Init_load(void)
{
- rb_vm_t *vm = GET_VM();
static const char var_load_path[] = "$:";
ID id_load_path = rb_intern2(var_load_path, sizeof(var_load_path)-1);
- rb_define_hooked_variable(var_load_path, (VALUE*)vm, load_path_getter, rb_gvar_readonly_setter);
- rb_gvar_namespace_ready(var_load_path);
+ rb_define_hooked_variable(var_load_path, 0, load_path_getter, rb_gvar_readonly_setter);
+ rb_gvar_box_ready(var_load_path);
rb_alias_variable(rb_intern_const("$-I"), id_load_path);
rb_alias_variable(rb_intern_const("$LOAD_PATH"), id_load_path);
- vm->load_path = rb_ary_new();
- vm->expanded_load_path = rb_ary_hidden_new(0);
- vm->load_path_snapshot = rb_ary_hidden_new(0);
- vm->load_path_check_cache = 0;
- rb_define_singleton_method(vm->load_path, "resolve_feature_path", rb_resolve_feature_path, 1);
rb_define_virtual_variable("$\"", get_LOADED_FEATURES, 0);
- rb_gvar_namespace_ready("$\"");
+ rb_gvar_box_ready("$\"");
rb_define_virtual_variable("$LOADED_FEATURES", get_LOADED_FEATURES, 0); // TODO: rb_alias_variable ?
- rb_gvar_namespace_ready("$LOADED_FEATURES");
- vm->loaded_features = rb_ary_new();
- vm->loaded_features_snapshot = rb_ary_hidden_new(0);
- vm->loaded_features_index = st_init_numtable();
- vm->loaded_features_realpaths = rb_hash_new();
- rb_obj_hide(vm->loaded_features_realpaths);
- vm->loaded_features_realpath_map = rb_hash_new();
- rb_obj_hide(vm->loaded_features_realpath_map);
+ rb_gvar_box_ready("$LOADED_FEATURES");
rb_define_global_function("load", rb_f_load, -1);
rb_define_global_function("require", rb_f_require, 1);
rb_define_global_function("require_relative", rb_f_require_relative, 1);
rb_define_method(rb_cModule, "autoload", rb_mod_autoload, 2);
+ rb_define_method(rb_cModule, "autoload_relative", rb_mod_autoload_relative, 2);
rb_define_method(rb_cModule, "autoload?", rb_mod_autoload_p, -1);
rb_define_global_function("autoload", rb_f_autoload, 2);
+ rb_define_global_function("autoload_relative", rb_f_autoload_relative, 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);
}
diff --git a/man/erb.1 b/man/erb.1
index d8739a7639..38a4c14ea4 100644
--- a/man/erb.1
+++ b/man/erb.1
@@ -1,6 +1,6 @@
.\"Ruby is copyrighted by Yukihiro Matsumoto <matz@netlab.jp>.
-.Dd December 16, 2018
-.Dt ERB \&1 "Ruby Programmer's Reference Guide"
+.Dd March 27, 2026
+.Dt ERB 1 "Ruby Programmer's Reference Guide"
.Os UNIX
.Sh NAME
.Nm erb
diff --git a/man/goruby.1 b/man/goruby.1
index a305a5afce..732ecaa663 100644
--- a/man/goruby.1
+++ b/man/goruby.1
@@ -1,6 +1,6 @@
.\"Ruby is copyrighted by Yukihiro Matsumoto <matz@netlab.jp>.
-.Dd April 20, 2017
-.Dt GORUBY \&1 "Ruby Programmer's Reference Guide"
+.Dd March 27, 2026
+.Dt GORUBY 1 "Ruby Programmer's Reference Guide"
.Os UNIX
.Sh NAME
.Nm goruby
diff --git a/man/ruby.1 b/man/ruby.1
index 28d7ddadfa..bc776b8946 100644
--- a/man/ruby.1
+++ b/man/ruby.1
@@ -1,6 +1,6 @@
.\"Ruby is copyrighted by Yukihiro Matsumoto <matz@netlab.jp>.
-.Dd April 14, 2018
-.Dt RUBY \&1 "Ruby Programmer's Reference Guide"
+.Dd March 27, 2026
+.Dt RUBY 1 "Ruby Programmer's Reference Guide"
.Os UNIX
.Sh NAME
.Nm ruby
@@ -287,6 +287,8 @@ to the standard output.
.It Fl -debug
Turns on debug mode.
.Li "$DEBUG"
+and
+.Li "$VERBOSE"
will be set to true.
.Pp
.It Fl e Ar command
@@ -521,6 +523,13 @@ variable is not defined, Ruby refers to
If set, Ruby tries to free all dynamically allocated memories.
Introduced in Ruby 3.3, default: unset.
.Pp
+.It Ev RUBY_BOX
+If set to
+.Li 1 ,
+Ruby Box is enabled and users will be able to execute
+.Li Ruby::Box.new .
+Ruby Box is an experimental feature introduced in Ruby 4.0.
+.Pp
.It Ev RUBY_IO_BUFFER_DEFAULT_SIZE
The custom default buffer size of
.Li IO::Buffer .
@@ -691,6 +700,16 @@ 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
+.It Ev RUBY_SHARED_FIBER_POOL_MAXIMUM_COUNT
+If set to a non-negative integer, the shared fiber pool cannot allocate more
+than that many stacks; further fiber creation may fail with
+.Va FiberError .
+Unset or 0 means no explicit cap (subject to process limits).
+.Pp
+.It Ev RUBY_SHARED_FIBER_POOL_MINIMUM_COUNT
+Initial and minimum growth chunk size for the shared fiber pool (stacks).
+Unset uses the implementation default.
+.Pp
.El
.Sh STACK SIZE ENVIRONMENT
Stack size environment variables are implementation-dependent and
diff --git a/marshal.c b/marshal.c
index f7474ca60e..e6ee3b47b0 100644
--- a/marshal.c
+++ b/marshal.c
@@ -30,6 +30,7 @@
#include "internal/hash.h"
#include "internal/numeric.h"
#include "internal/object.h"
+#include "internal/re.h"
#include "internal/struct.h"
#include "internal/symbol.h"
#include "internal/util.h"
@@ -727,26 +728,9 @@ has_ivars(VALUE obj, VALUE encname, VALUE *ivobj)
static void
w_ivar_each(VALUE obj, st_index_t num, struct dump_call_arg *arg)
{
- shape_id_t shape_id = rb_obj_shape_id(arg->obj);
struct w_ivar_arg ivarg = {arg, num};
if (!num) return;
- rb_ivar_foreach(obj, w_obj_each, (st_data_t)&ivarg);
-
- shape_id_t actual_shape_id = rb_obj_shape_id(arg->obj);
- if (shape_id != actual_shape_id) {
- // If the shape tree got _shorter_ then we probably removed an IV
- // If the shape tree got longer, then we probably added an IV.
- // The exception message might not be accurate when someone adds and
- // removes the same number of IVs, but they will still get an exception
- if (rb_shape_depth(shape_id) > rb_shape_depth(rb_obj_shape_id(arg->obj))) {
- rb_raise(rb_eRuntimeError, "instance variable removed from %"PRIsVALUE" instance",
- CLASS_OF(arg->obj));
- }
- else {
- rb_raise(rb_eRuntimeError, "instance variable added to %"PRIsVALUE" instance",
- CLASS_OF(arg->obj));
- }
- }
+ rb_ivar_foreach_buffered(obj, w_obj_each, (st_data_t)&ivarg);
}
static void
@@ -946,8 +930,9 @@ w_object(VALUE obj, struct dump_arg *arg, int limit)
hasiv = has_ivars(obj, (encname = encoding_name(obj, arg)), &ivobj);
{
st_data_t compat_data;
- rb_alloc_func_t allocator = rb_get_alloc_func(RBASIC(obj)->klass);
- if (st_lookup(compat_allocator_tbl,
+ VALUE klass = CLASS_OF(obj);
+ rb_alloc_func_t allocator = RCLASS_SINGLETON_P(klass) ? 0 : rb_get_alloc_func(klass);
+ if (allocator && st_lookup(compat_allocator_tbl,
(st_data_t)allocator,
&compat_data)) {
marshal_compat_t *compat = (marshal_compat_t*)compat_data;
@@ -1084,7 +1069,7 @@ w_object(VALUE obj, struct dump_arg *arg, int limit)
case T_STRUCT:
w_class(TYPE_STRUCT, obj, arg, TRUE);
{
- long len = RSTRUCT_LEN(obj);
+ long len = RSTRUCT_LEN_RAW(obj);
VALUE mem;
long i;
@@ -1092,7 +1077,7 @@ w_object(VALUE obj, struct dump_arg *arg, int limit)
mem = rb_struct_members(obj);
for (i=0; i<len; i++) {
w_symbol(RARRAY_AREF(mem, i), arg);
- w_object(RSTRUCT_GET(obj, i), arg, limit);
+ w_object(RSTRUCT_GET_RAW(obj, i), arg, limit);
}
}
break;
@@ -1189,7 +1174,7 @@ io_needed(void)
* * anonymous Class/Module.
* * objects which are related to system (ex: Dir, File::Stat, IO, File, Socket
* and so on)
- * * an instance of MatchData, Data, Method, UnboundMethod, Proc, Thread,
+ * * an instance of MatchData, Method, UnboundMethod, Proc, Thread,
* ThreadGroup, Continuation
* * objects which define singleton methods
*/
@@ -1257,6 +1242,7 @@ rb_marshal_dump_limited(VALUE obj, VALUE port, int limit)
struct load_arg {
VALUE src;
char *buf;
+ long bufsize;
long buflen;
long readable;
long offset;
@@ -1342,15 +1328,23 @@ static unsigned char
r_byte1_buffered(struct load_arg *arg)
{
if (arg->buflen == 0) {
- long readable = arg->readable < BUFSIZ ? arg->readable : BUFSIZ;
+ long readable = arg->readable < arg->bufsize ? arg->readable : arg->bufsize;
+ long read_len;
VALUE str, n = LONG2NUM(readable);
str = load_funcall(arg, arg->src, s_read, 1, &n);
if (NIL_P(str)) too_short();
StringValue(str);
- memcpy(arg->buf, RSTRING_PTR(str), RSTRING_LEN(str));
+ read_len = RSTRING_LEN(str);
+ if (UNLIKELY(read_len < readable)) too_short();
+ if (UNLIKELY(read_len > arg->bufsize)) {
+ arg->buf = ruby_sized_realloc_n(arg->buf, read_len, 1, arg->bufsize);
+ arg->bufsize = read_len;
+ }
+ memcpy(arg->buf, RSTRING_PTR(str), read_len);
arg->offset = 0;
- arg->buflen = RSTRING_LEN(str);
+ arg->buflen = read_len;
+ RB_GC_GUARD(str);
}
arg->buflen--;
return arg->buf[arg->offset++];
@@ -1428,7 +1422,7 @@ long
ruby_marshal_read_long(const char **buf, long len)
{
long x;
- struct RString src;
+ struct RString src = {RBASIC_INIT};
struct load_arg arg;
memset(&arg, 0, sizeof(arg));
arg.src = rb_setup_fake_str(&src, *buf, len, 0);
@@ -1437,6 +1431,18 @@ ruby_marshal_read_long(const char **buf, long len)
return x;
}
+static long
+r_keep_readable(struct load_arg *arg, long len, size_t size)
+{
+ if (UNLIKELY(len < 0)) {
+ rb_raise(rb_eArgError, "negative length");
+ }
+ if (UNLIKELY((unsigned long)len > SIZE_MAX / size || arg->readable >= LONG_MAX - len)) {
+ rb_raise(rb_eArgError, "marshaled data too big");
+ }
+ return len;
+}
+
static VALUE
r_bytes1(long len, struct load_arg *arg)
{
@@ -1466,7 +1472,7 @@ r_bytes1_buffered(long len, struct load_arg *arg)
long tmp_len, read_len, need_len = len - buflen;
VALUE tmp, n;
- readable = readable < BUFSIZ ? readable : BUFSIZ;
+ readable = readable < arg->bufsize ? readable : arg->bufsize;
read_len = need_len > readable ? need_len : readable;
n = LONG2NUM(read_len);
tmp = load_funcall(arg, arg->src, s_read, 1, &n);
@@ -1731,7 +1737,10 @@ r_ivar_encoding(VALUE obj, struct load_arg *arg, VALUE sym, VALUE val)
int idx = sym2encidx(sym, val);
if (idx >= 0) {
if (rb_enc_capable(obj)) {
- rb_enc_associate_index(obj, idx);
+ // Check if needed to avoid rb_check_frozen() check for Regexps
+ if (rb_enc_get_index(obj) != idx) {
+ rb_enc_associate_index(obj, idx);
+ }
}
else {
rb_raise(rb_eArgError, "%"PRIsVALUE" is not enc_capable", obj);
@@ -1854,17 +1863,17 @@ append_extmod(VALUE obj, VALUE extmod)
override_ivar_error(type, str); \
} while (0)
-static VALUE r_object_for(struct load_arg *arg, bool partial, int *ivp, VALUE extmod, int type);
+static VALUE r_object_for(struct load_arg *arg, bool partial, int *ivp, VALUE klass, VALUE extmod, int type);
static VALUE
r_object0(struct load_arg *arg, bool partial, int *ivp, VALUE extmod)
{
int type = r_byte(arg);
- return r_object_for(arg, partial, ivp, extmod, type);
+ return r_object_for(arg, partial, ivp, 0, extmod, type);
}
static VALUE
-r_object_for(struct load_arg *arg, bool partial, int *ivp, VALUE extmod, int type)
+r_object_for(struct load_arg *arg, bool partial, int *ivp, VALUE klass, VALUE extmod, int type)
{
VALUE (*hash_new_with_size)(st_index_t) = rb_hash_new_with_size;
VALUE v = Qnil;
@@ -1879,6 +1888,9 @@ r_object_for(struct load_arg *arg, bool partial, int *ivp, VALUE extmod, int typ
}
v = (VALUE)link;
if (!st_lookup(arg->partial_objects, (st_data_t)v, &link)) {
+ if (arg->freeze && RB_TYPE_P(v, T_STRING)) {
+ v = rb_str_to_interned_str(v);
+ }
v = r_post_proc(v, arg);
}
break;
@@ -1937,12 +1949,12 @@ r_object_for(struct load_arg *arg, bool partial, int *ivp, VALUE extmod, int typ
}
type = r_byte(arg);
if ((c == rb_cHash) &&
- /* Hack for compare_by_identify */
+ /* Hack for compare_by_identity */
(type == TYPE_HASH || type == TYPE_HASH_DEF)) {
hash_new_with_size = rb_ident_hash_new_with_size;
goto type_hash;
}
- v = r_object_for(arg, partial, 0, extmod, type);
+ v = r_object_for(arg, partial, 0, c, extmod, type);
if (RB_SPECIAL_CONST_P(v) || RB_TYPE_P(v, T_OBJECT) || RB_TYPE_P(v, T_CLASS)) {
goto format_error;
}
@@ -2014,7 +2026,10 @@ r_object_for(struct load_arg *arg, bool partial, int *ivp, VALUE extmod, int typ
int sign;
sign = r_byte(arg);
- len = r_long(arg);
+ if (sign != '+' && sign != '-') {
+ rb_raise(rb_eArgError, "invalid Bignum sign");
+ }
+ len = r_keep_readable(arg, r_long(arg), 2);
if (SIZEOF_VALUE >= 8 && len <= 4) {
// Representable within uintptr, likely FIXNUM
@@ -2079,7 +2094,10 @@ 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);
+ if (!klass) {
+ klass = rb_cRegexp;
+ }
+ VALUE regexp = rb_reg_init_str(rb_reg_s_alloc(klass), str, options);
r_copy_ivar(regexp, str);
v = r_entry0(regexp, idx, arg);
@@ -2089,7 +2107,7 @@ r_object_for(struct load_arg *arg, bool partial, int *ivp, VALUE extmod, int typ
case TYPE_ARRAY:
{
- long len = r_long(arg);
+ long len = r_keep_readable(arg, r_long(arg), 1);
v = rb_ary_new2(len);
v = r_entry(v, arg);
@@ -2107,7 +2125,7 @@ r_object_for(struct load_arg *arg, bool partial, int *ivp, VALUE extmod, int typ
case TYPE_HASH_DEF:
type_hash:
{
- long len = r_long(arg);
+ long len = r_keep_readable(arg, r_long(arg), 2);
v = hash_new_with_size(len);
v = r_entry(v, arg);
@@ -2133,7 +2151,7 @@ r_object_for(struct load_arg *arg, bool partial, int *ivp, VALUE extmod, int typ
VALUE slot;
st_index_t idx = r_prepare(arg);
VALUE klass = path2class(r_unique(arg));
- long len = r_long(arg);
+ long len = r_keep_readable(arg, r_long(arg), 2);
v = rb_obj_alloc(klass);
if (!RB_TYPE_P(v, T_STRUCT)) {
@@ -2350,8 +2368,9 @@ r_object(struct load_arg *arg)
static void
clear_load_arg(struct load_arg *arg)
{
- xfree(arg->buf);
+ ruby_xfree_sized(arg->buf, arg->bufsize);
arg->buf = NULL;
+ arg->bufsize = 0;
arg->buflen = 0;
arg->offset = 0;
arg->readable = 0;
@@ -2397,10 +2416,14 @@ rb_marshal_load_with_proc(VALUE port, VALUE proc, bool freeze)
arg->readable = 0;
arg->freeze = freeze;
- if (NIL_P(v))
+ if (NIL_P(v)) {
+ arg->bufsize = BUFSIZ;
arg->buf = xmalloc(BUFSIZ);
- else
+ }
+ else {
+ arg->bufsize = 0;
arg->buf = 0;
+ }
major = r_byte(arg);
minor = r_byte(arg);
@@ -2590,7 +2613,7 @@ marshal_compat_table_mark_and_move(void *tbl)
static int
marshal_compat_table_free_i(st_data_t key, st_data_t value, st_data_t _)
{
- xfree((marshal_compat_t *)value);
+ SIZED_FREE((marshal_compat_t *)value);
return ST_CONTINUE;
}
diff --git a/math.c b/math.c
index 9e96f3666a..852620da20 100644
--- a/math.c
+++ b/math.c
@@ -1054,7 +1054,7 @@ math_gamma(VALUE unused_obj, VALUE x)
*
* [Math.log(Math.gamma(x).abs), Math.gamma(x) < 0 ? -1 : 1]
*
- * See {logarithmic gamma function}[https://en.wikipedia.org/wiki/Gamma_function#The_log-gamma_function].
+ * See {log gamma function}[https://en.wikipedia.org/wiki/Gamma_function#Log-gamma_function].
*
* - Domain: <tt>(-INFINITY, INFINITY]</tt>.
* - Range of first element: <tt>(-INFINITY, INFINITY]</tt>.
diff --git a/memory_view.c b/memory_view.c
index 7bcb39972f..2de756d681 100644
--- a/memory_view.c
+++ b/memory_view.c
@@ -65,7 +65,7 @@ const rb_data_type_t rb_memory_view_exported_object_registry_data_type = {
exported_object_registry_free,
0,
},
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED
};
static int
@@ -101,6 +101,7 @@ register_exported_object(VALUE obj)
{
RB_VM_LOCKING() {
st_update(exported_object_table, (st_data_t)obj, exported_object_add_ref, 0);
+ RB_OBJ_WRITTEN(rb_memory_view_exported_object_registry, Qundef, obj);
}
}
@@ -845,7 +846,7 @@ 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);
+ SIZED_FREE_N((rb_memory_view_item_component_t *)view->item_desc.components, view->item_desc.length);
}
return rv;
}
diff --git a/method.h b/method.h
index 8328b86ee9..fdbab41cf7 100644
--- a/method.h
+++ b/method.h
@@ -73,11 +73,18 @@ typedef struct rb_callable_method_entry_struct { /* same fields with rb_method_e
#define METHOD_ENTRY_COMPLEMENTED(me) ((me)->flags & IMEMO_FL_USER3)
#define METHOD_ENTRY_COMPLEMENTED_SET(me) ((me)->flags |= IMEMO_FL_USER3)
#define METHOD_ENTRY_CACHED(me) ((me)->flags & IMEMO_FL_USER4)
-#define METHOD_ENTRY_CACHED_SET(me) ((me)->flags |= IMEMO_FL_USER4)
#define METHOD_ENTRY_INVALIDATED(me) ((me)->flags & IMEMO_FL_USER5)
#define METHOD_ENTRY_INVALIDATED_SET(me) ((me)->flags |= IMEMO_FL_USER5)
static inline void
+METHOD_ENTRY_CACHED_SET(rb_callable_method_entry_t *me)
+{
+ if (!METHOD_ENTRY_CACHED(me)) {
+ me->flags |= IMEMO_FL_USER4;
+ }
+}
+
+static inline void
METHOD_ENTRY_VISI_SET(rb_method_entry_t *me, rb_method_visibility_t visi)
{
VM_ASSERT((int)visi >= 0 && visi <= 3);
@@ -159,8 +166,8 @@ typedef struct rb_method_refined_struct {
typedef struct rb_method_bmethod_struct {
VALUE proc; /* should be marked */
- struct rb_hook_list_struct *hooks;
- VALUE defined_ractor;
+ rb_serial_t defined_ractor_id;
+ unsigned int local_hooks_cnt;
} rb_method_bmethod_t;
enum method_optimized_type {
@@ -197,10 +204,12 @@ struct rb_method_definition_struct {
ID original_id;
uintptr_t method_serial;
- const rb_namespace_t *ns;
+ const rb_box_t *box;
};
struct rb_id_table;
+struct rb_ractor_struct;
+struct rb_hook_list_struct;
typedef struct rb_method_definition_struct rb_method_definition_t;
STATIC_ASSERT(sizeof_method_def, offsetof(rb_method_definition_t, body) <= 8);
@@ -255,10 +264,12 @@ void rb_scope_visibility_set(rb_method_visibility_t);
VALUE rb_unnamed_parameters(int arity);
void rb_vm_insert_cc_refinement(const struct rb_callcache *cc);
-void rb_vm_delete_cc_refinement(const struct rb_callcache *cc);
void rb_clear_method_cache(VALUE klass_or_module, ID mid);
void rb_clear_all_refinement_method_cache(void);
void rb_invalidate_method_caches(struct rb_id_table *cm_tbl, VALUE cc_tbl);
+struct rb_hook_list_struct *rb_method_def_local_hooks(rb_method_definition_t *def, struct rb_ractor_struct *cr, bool create);
+void rb_method_definition_addref(rb_method_definition_t *def);
+void rb_method_definition_release(rb_method_definition_t *def);
#endif /* RUBY_METHOD_H */
diff --git a/mini_builtin.c b/mini_builtin.c
index d9827e70e4..75ea94d37d 100644
--- a/mini_builtin.c
+++ b/mini_builtin.c
@@ -23,7 +23,8 @@ prelude_ast_value(VALUE name, VALUE code, int line)
static void
pm_prelude_load(pm_parse_result_t *result, VALUE name, VALUE code, int line)
{
- pm_options_line_set(&result->options, line);
+ pm_parse_result_init(result);
+ pm_options_line_set(result->options, line);
VALUE error = pm_parse_string(result, code, name, NULL);
if (!NIL_P(error)) {
@@ -60,7 +61,7 @@ builtin_iseq_load(const char *feature_name, const struct rb_builtin_function *ta
};
if (rb_ruby_prism_p()) {
- pm_parse_result_t result = { 0 };
+ pm_parse_result_t result;
pm_prelude_load(&result, name_str, code, start_line);
vm->builtin_function_table = table;
@@ -96,24 +97,22 @@ builtin_iseq_load(const char *feature_name, const struct rb_builtin_function *ta
return iseq;
}
-static void
-load_with_builtin_functions(const char *feature_name, const struct rb_builtin_function *table)
+void
+rb_load_with_builtin_functions(const char *feature_name, const struct rb_builtin_function *table)
{
const rb_iseq_t *iseq = builtin_iseq_load(feature_name, table);
- rb_namespace_enable_builtin();
- rb_iseq_eval_with_refinement(iseq, rb_mNamespaceRefiner);
- rb_namespace_disable_builtin();
+ rb_iseq_eval(iseq, rb_root_box());
+}
+
+VALUE
+rb_define_gem_modules(VALUE _a, VALUE _b)
+{
+ // do nothing - moniruby doesn't load gem_prelude.rb.
+ return Qnil;
}
void
-rb_load_with_builtin_functions(const char *feature_name, const struct rb_builtin_function *table)
+rb_load_gem_prelude(VALUE _)
{
- const rb_iseq_t *iseq;
- if (rb_namespace_available() && rb_mNamespaceRefiner) {
- load_with_builtin_functions(feature_name, table);
- }
- else {
- iseq = builtin_iseq_load(feature_name, table);
- rb_iseq_eval(iseq);
- }
+ // do nothing - miniruby doesn't support loading RubyGems.
}
diff --git a/misc/.vscode/settings.json b/misc/.vscode/settings.json
index c11838155e..a2e4e1ec69 100644
--- a/misc/.vscode/settings.json
+++ b/misc/.vscode/settings.json
@@ -3,4 +3,8 @@
"disasm",
],
"rust-analyzer.cfg.setTest": false,
+ // rust-analyzer bundled in the VSCode extension may only support Rust newer than 1.85.0.
+ // To avoid warnings, install rust-analyzer with `rustup component add rust-analyzer` and
+ // use `~/.cargo/bin/rust-analyzer` with the following config.
+ "rust-analyzer.server.path": "rust-analyzer",
}
diff --git a/misc/jit_perf.py b/misc/jit_perf.py
new file mode 100755
index 0000000000..bc0f961b20
--- /dev/null
+++ b/misc/jit_perf.py
@@ -0,0 +1,116 @@
+#!/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]') or symbol.startswith('ZJIT: ') or dso.startswith('perf-'):
+ return '[JIT code]'
+ elif '::' in symbol or symbol.startswith('_ZN4yjit') or symbol.startswith('_ZN4zjit'):
+ return '[JIT 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].rsplit(" (", 1) # "[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/misc/lldb_rb/utils.py b/misc/lldb_rb/utils.py
index f4775bc4f9..a2bcedc328 100644
--- a/misc/lldb_rb/utils.py
+++ b/misc/lldb_rb/utils.py
@@ -236,16 +236,20 @@ class RbInspector(LLDBInterface):
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())
+ type = val.GetValueForExpressionPath("->type").GetValueAsUnsigned()
+ embed = (type & 1)
+ if embed:
+ flaginfo += "[EMBED] "
+ type = self.frame.EvaluateExpression("(rb_data_type_t *)%0#x" % (type & ~1))
+ print("T_DATA: %s%s" %
+ (flaginfo, type.GetValueForExpressionPath("->wrap_struct_name")),
+ file=self.result)
+ print("%s", type.Dereference(), file=self.result)
+ ptr = val.GetValueForExpressionPath("->data")
+ if embed:
+ ptr = ptr.AddressOf()
+ self._append_expression("(void *)%0#x" % ptr.GetValueAsUnsigned())
elif rval.is_type("RUBY_T_IMEMO"):
imemo_type = ((rval.flags >> self.ruby_globals["RUBY_FL_USHIFT"])
@@ -279,7 +283,7 @@ class RbInspector(LLDBInterface):
# if val.GetType() != tRNode: does not work for unknown reason
- if val.GetType().GetPointeeType().name != "NODE":
+ if val.GetType().GetPointeeType().GetCanonicalType().name != "RNode":
return False
rbNodeTypeMask = self.ruby_globals["RUBY_NODE_TYPEMASK"]
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 8859fcfa44..ba8cd46ebd 100644
--- a/missing/dtoa.c
+++ b/missing/dtoa.c
@@ -210,6 +210,29 @@
#include <locale.h>
#endif
+#if defined(HAVE_STDCKDINT_H) || !defined(__has_include)
+#elif __has_include(<stdckdint.h>)
+# define HAVE_STDCKDINT_H 1
+#endif
+#ifdef HAVE_STDCKDINT_H
+# include <stdckdint.h>
+#endif
+
+#if !defined(ckd_add)
+static inline int /* bool */
+ckd_add(int *result, int x, int y)
+{
+ if (x < 0) {
+ if (y < INT_MIN - x) return 1;
+ }
+ else if (x > 0) {
+ if (y > INT_MAX - x) return 1;
+ }
+ *result = x + y;
+ return 0;
+}
+#endif
+
#ifdef MALLOC
extern void *MALLOC(size_t);
#else
@@ -516,6 +539,7 @@ Balloc(int k)
x = 1 << k;
rv = (Bigint *)MALLOC(sizeof(Bigint) + (x-1)*sizeof(ULong));
+ if (!rv) return NULL;
rv->k = k;
rv->maxwds = x;
rv->sign = rv->wds = 0;
@@ -523,10 +547,13 @@ Balloc(int k)
}
static void
-Bfree(Bigint *v)
+Bclear(Bigint **vp)
{
- FREE(v);
+ Bigint *v = *vp;
+ *vp = NULL;
+ if (v) FREE(v);
}
+#define Bfree(v) Bclear(&(v))
#define Bcopy(x,y) memcpy((char *)&(x)->sign, (char *)&(y)->sign, \
(y)->wds*sizeof(Long) + 2*sizeof(int))
@@ -572,6 +599,10 @@ multadd(Bigint *b, int m, int a) /* multiply by m and add a */
if (carry) {
if (wds >= b->maxwds) {
b1 = Balloc(b->k+1);
+ if (!b1) {
+ Bfree(b);
+ return NULL;
+ }
Bcopy(b1, b);
Bfree(b);
b = b1;
@@ -593,10 +624,12 @@ s2b(const char *s, int nd0, int nd, ULong y9)
for (k = 0, y = 1; x > y; y <<= 1, k++) ;
#ifdef Pack_32
b = Balloc(k);
+ if (!b) return NULL;
b->x[0] = y9;
b->wds = 1;
#else
b = Balloc(k+1);
+ if (!b) return NULL;
b->x[0] = y9 & 0xffff;
b->wds = (b->x[1] = y9 >> 16) ? 2 : 1;
#endif
@@ -606,13 +639,16 @@ s2b(const char *s, int nd0, int nd, ULong y9)
s += 9;
do {
b = multadd(b, 10, *s++ - '0');
+ if (!b) return NULL;
} while (++i < nd0);
s++;
}
else
s += 10;
- for (; i < nd; i++)
+ for (; i < nd; i++) {
b = multadd(b, 10, *s++ - '0');
+ if (!b) return NULL;
+ }
return b;
}
@@ -694,11 +730,14 @@ i2b(int i)
Bigint *b;
b = Balloc(1);
+ if (!b) return NULL;
b->x[0] = i;
b->wds = 1;
return b;
}
+#define Bzero_p(b) (!(b)->x[0] && (b)->wds <= 1)
+
static Bigint *
mult(Bigint *a, Bigint *b)
{
@@ -715,6 +754,14 @@ mult(Bigint *a, Bigint *b)
#endif
#endif
+ if (Bzero_p(a) || Bzero_p(b)) {
+ c = Balloc(0);
+ if (!c) return NULL;
+ c->wds = 1;
+ c->x[0] = 0;
+ return c;
+ }
+
if (a->wds < b->wds) {
c = a;
a = b;
@@ -727,6 +774,7 @@ mult(Bigint *a, Bigint *b)
if (wc > a->maxwds)
k++;
c = Balloc(k);
+ if (!c) return NULL;
for (x = c->x, xa = x + wc; x < xa; x++)
*x = 0;
xa = a->x;
@@ -806,50 +854,47 @@ 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)
+ if ((i = k & 3) != 0) {
b = multadd(b, p05[i-1], 0);
+ if (!b) return NULL;
+ }
+
+#define b_cache(var, addr, new_expr) \
+ if ((var = addr) != 0) {} else { \
+ Bigint *tmp = 0; \
+ ACQUIRE_DTOA_LOCK(1); \
+ if (!(var = addr) && (var = (new_expr)) != 0) { \
+ var->next = 0; \
+ tmp = ATOMIC_PTR_CAS(addr, NULL, var); \
+ } \
+ FREE_DTOA_LOCK(1); \
+ if (UNLIKELY(tmp)) { \
+ Bfree(var); \
+ var = tmp; \
+ } \
+ else if (!var) { \
+ Bfree(b); \
+ return NULL; \
+ } \
+ }
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);
- }
+ /* first time */
+ b_cache(p5, p5s, i2b(625));
for (;;) {
if (k & 1) {
b1 = mult(b, p5);
Bfree(b);
b = b1;
+ if (!b) return NULL;
}
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);
- }
+ b_cache(p51, p5->next, mult(p5, p5));
p5 = p51;
}
return b;
@@ -862,6 +907,8 @@ lshift(Bigint *b, int k)
Bigint *b1;
ULong *x, *x1, *xe, z;
+ if (!k || Bzero_p(b)) return b;
+
#ifdef Pack_32
n = k >> 5;
#else
@@ -872,6 +919,10 @@ lshift(Bigint *b, int k)
for (i = b->maxwds; n1 > i; i <<= 1)
k1++;
b1 = Balloc(k1);
+ if (!b1) {
+ Bfree(b);
+ return NULL;
+ }
x1 = b1->x;
for (i = 0; i < n; i++)
*x1++ = 0;
@@ -957,6 +1008,7 @@ diff(Bigint *a, Bigint *b)
i = cmp(a,b);
if (!i) {
c = Balloc(0);
+ if (!c) return NULL;
c->wds = 1;
c->x[0] = 0;
return c;
@@ -970,6 +1022,7 @@ diff(Bigint *a, Bigint *b)
else
i = 0;
c = Balloc(a->k);
+ if (!c) return NULL;
c->sign = i;
wa = a->wds;
xa = a->x;
@@ -1155,6 +1208,7 @@ d2b(double d_, int *e, int *bits)
#else
b = Balloc(2);
#endif
+ if (!b) return NULL;
x = b->x;
z = d0 & Frac_mask;
@@ -1905,12 +1959,16 @@ undfl:
/* Put digits into bd: true value = bd * 10^e */
bd0 = s2b(s0, nd0, nd, y);
+ if (!bd0) goto ret;
for (;;) {
bd = Balloc(bd0->k);
+ if (!bd) goto retfree;
Bcopy(bd, bd0);
bb = d2b(dval(rv), &bbe, &bbbits); /* rv = bb * 2^bbe */
+ if (!bb) goto retfree;
bs = i2b(1);
+ if (!bs) goto retfree;
if (e >= 0) {
bb2 = bb5 = 0;
@@ -1967,19 +2025,30 @@ undfl:
}
if (bb5 > 0) {
bs = pow5mult(bs, bb5);
+ if (!bs) goto retfree;
bb1 = mult(bs, bb);
Bfree(bb);
bb = bb1;
+ if (!bb) goto retfree;
}
- if (bb2 > 0)
+ if (bb2 > 0) {
bb = lshift(bb, bb2);
- if (bd5 > 0)
+ if (!bb) goto retfree;
+ }
+ if (bd5 > 0) {
bd = pow5mult(bd, bd5);
- if (bd2 > 0)
+ if (!bd) goto retfree;
+ }
+ if (bd2 > 0) {
bd = lshift(bd, bd2);
- if (bs2 > 0)
+ if (!bd) goto retfree;
+ }
+ if (bs2 > 0) {
bs = lshift(bs, bs2);
+ if (!bs) goto retfree;
+ }
delta = diff(bb, bd);
+ if (!delta) goto retfree;
dsign = delta->sign;
delta->sign = 0;
i = cmp(delta, bs);
@@ -2012,6 +2081,7 @@ undfl:
#endif
{
delta = lshift(delta,Log2P);
+ if (!delta) goto nomem;
if (cmp(delta, bs) <= 0)
adj = -0.5;
}
@@ -2101,6 +2171,7 @@ apply_adj:
break;
}
delta = lshift(delta,Log2P);
+ if (!delta) goto retfree;
if (cmp(delta, bs) > 0)
goto drop_down;
break;
@@ -2503,6 +2574,7 @@ nrv_alloc(const char *s, char **rve, size_t n)
char *rv, *t;
t = rv = rv_alloc(n);
+ if (!rv) return NULL;
while ((*t = *s++) != 0) t++;
if (rve)
*rve = t;
@@ -2675,6 +2747,7 @@ dtoa(double d_, int mode, int ndigits, int *decpt, int *sign, char **rve)
#endif
b = d2b(dval(d), &be, &bbits);
+ if (!b) return NULL;
#ifdef Sudden_Underflow
i = (int)(word0(d) >> Exp_shift1 & (Exp_mask>>Exp_shift1));
#else
@@ -2794,13 +2867,20 @@ dtoa(double d_, int mode, int ndigits, int *decpt, int *sign, char **rve)
leftright = 0;
/* no break */
case 5:
- i = ndigits + k + 1;
+ if (ckd_add(&i, ndigits, k + 1)) { /* k + 1 should be safe */
+ Bfree(b);
+ return NULL;
+ }
ilim = i;
ilim1 = i - 1;
if (i <= 0)
i = 1;
}
s = s0 = rv_alloc(i+1);
+ if (!s) {
+ Bfree(b);
+ return NULL;
+ }
#ifdef Honor_FLT_ROUNDS
if (mode > 1 && rounding != 1)
@@ -2981,6 +3061,7 @@ bump_up:
b2 += i;
s2 += i;
mhi = i2b(1);
+ if (!mhi) goto nomem;
}
if (m2 > 0 && s2 > 0) {
i = m2 < s2 ? m2 : s2;
@@ -2992,19 +3073,28 @@ bump_up:
if (leftright) {
if (m5 > 0) {
mhi = pow5mult(mhi, m5);
+ if (!mhi) goto nomem;
b1 = mult(mhi, b);
Bfree(b);
b = b1;
+ if (!b) goto nomem;
}
- if ((j = b5 - m5) != 0)
+ if ((j = b5 - m5) != 0) {
b = pow5mult(b, j);
+ if (!b) goto nomem;
+ }
}
- else
+ else {
b = pow5mult(b, b5);
+ if (!b) goto nomem;
+ }
}
S = i2b(1);
- if (s5 > 0)
+ if (!S) goto nomem;
+ if (s5 > 0) {
S = pow5mult(S, s5);
+ if (!S) goto nomem;
+ }
/* Check for special case that d is a normalized power of 2. */
@@ -3052,16 +3142,23 @@ bump_up:
m2 += i;
s2 += i;
}
- if (b2 > 0)
+ if (b2 > 0) {
b = lshift(b, b2);
- if (s2 > 0)
+ if (!b) goto nomem;
+ }
+ if (s2 > 0) {
S = lshift(S, s2);
+ if (!S) goto nomem;
+ }
if (k_check) {
if (cmp(b,S) < 0) {
k--;
b = multadd(b, 10, 0); /* we botched the k estimate */
- if (leftright)
+ if (!b) goto nomem;
+ if (leftright) {
mhi = multadd(mhi, 10, 0);
+ if (!mhi) goto nomem;
+ }
ilim = ilim1;
}
}
@@ -3078,8 +3175,10 @@ one_digit:
goto ret;
}
if (leftright) {
- if (m2 > 0)
+ if (m2 > 0) {
mhi = lshift(mhi, m2);
+ if (!mhi) goto nomem;
+ }
/* Compute mlo -- check for special case
* that d is a normalized power of 2.
@@ -3088,8 +3187,10 @@ one_digit:
mlo = mhi;
if (spec_case) {
mhi = Balloc(mhi->k);
+ if (!mhi) goto nomem;
Bcopy(mhi, mlo);
mhi = lshift(mhi, Log2P);
+ if (!mhi) goto nomem;
}
for (i = 1;;i++) {
@@ -3099,6 +3200,7 @@ one_digit:
*/
j = cmp(b, mlo);
delta = diff(S, mhi);
+ if (!delta) goto nomem;
j1 = delta->sign ? 1 : cmp(b, delta);
Bfree(delta);
#ifndef ROUND_BIASED
@@ -3139,6 +3241,7 @@ one_digit:
#endif /*Honor_FLT_ROUNDS*/
if (j1 > 0) {
b = lshift(b, 1);
+ if (!b) goto nomem;
j1 = cmp(b, S);
if ((j1 > 0 || (j1 == 0 && (dig & 1))) && dig++ == '9')
goto round_9_up;
@@ -3167,11 +3270,16 @@ keep_dig:
if (i == ilim)
break;
b = multadd(b, 10, 0);
- if (mlo == mhi)
+ if (!b) goto nomem;
+ if (mlo == mhi) {
mlo = mhi = multadd(mhi, 10, 0);
+ if (!mlo) goto nomem;
+ }
else {
mlo = multadd(mlo, 10, 0);
+ if (!mlo) goto nomem;
mhi = multadd(mhi, 10, 0);
+ if (!mhi) goto nomem;
}
}
}
@@ -3187,6 +3295,7 @@ keep_dig:
if (i >= ilim)
break;
b = multadd(b, 10, 0);
+ if (!b) goto nomem;
}
/* Round off last digit */
@@ -3198,6 +3307,7 @@ keep_dig:
}
#endif
b = lshift(b, 1);
+ if (!b) goto nomem;
j = cmp(b, S);
if (j > 0 || (j == 0 && (dig & 1))) {
roundoff:
@@ -3239,6 +3349,16 @@ ret1:
if (rve)
*rve = s;
return s0;
+ nomem:
+ if (S) Bfree(S);
+ if (mhi) {
+ if (mlo && mlo != mhi)
+ Bfree(mlo);
+ Bfree(mhi);
+ }
+ if (b) Bfree(b);
+ FREE(s0);
+ return NULL;
}
/*-
@@ -3347,6 +3467,7 @@ hdtoa(double d, const char *xdigs, int ndigits, int *decpt, int *sign, char **rv
*/
bufsize = (ndigits > 0) ? ndigits : SIGFIGS;
s0 = rv_alloc(bufsize+1);
+ if (!s0) return NULL;
/* Round to the desired number of digits. */
if (SIGFIGS > ndigits && ndigits > 0) {
diff --git a/namespace.c b/namespace.c
deleted file mode 100644
index 55b7580c72..0000000000
--- a/namespace.c
+++ /dev/null
@@ -1,1129 +0,0 @@
-/* indent-tabs-mode: nil */
-
-#include "internal.h"
-#include "internal/class.h"
-#include "internal/eval.h"
-#include "internal/error.h"
-#include "internal/file.h"
-#include "internal/gc.h"
-#include "internal/hash.h"
-#include "internal/load.h"
-#include "internal/namespace.h"
-#include "internal/st.h"
-#include "internal/variable.h"
-#include "ruby/internal/globals.h"
-#include "ruby/util.h"
-#include "vm_core.h"
-
-#include <stdio.h>
-
-VALUE rb_cNamespace = 0;
-VALUE rb_cNamespaceEntry = 0;
-VALUE rb_mNamespaceRefiner = 0;
-VALUE rb_mNamespaceLoader = 0;
-
-static rb_namespace_t builtin_namespace_data = {
- .ns_object = Qnil,
- .ns_id = 0,
- .is_builtin = true,
- .is_user = false,
- .is_optional = false
-};
-static rb_namespace_t * const root_namespace = 0;
-static rb_namespace_t * const builtin_namespace = &builtin_namespace_data;
-static rb_namespace_t * main_namespace = 0;
-static char *tmp_dir;
-static bool tmp_dir_has_dirsep;
-
-#define NAMESPACE_TMP_PREFIX "_ruby_ns_"
-
-#ifndef MAXPATHLEN
-# define MAXPATHLEN 1024
-#endif
-
-#if defined(_WIN32)
-# define DIRSEP "\\"
-#else
-# define DIRSEP "/"
-#endif
-
-bool ruby_namespace_enabled = false; // extern
-bool ruby_namespace_init_done = false; // extern
-
-VALUE rb_resolve_feature_path(VALUE klass, VALUE fname);
-static VALUE rb_namespace_inspect(VALUE obj);
-static void namespace_push(rb_thread_t *th, VALUE namespace);
-static VALUE namespace_pop(VALUE th_value);
-
-void
-rb_namespace_init_done(void)
-{
- ruby_namespace_init_done = true;
-}
-
-void
-rb_namespace_enable_builtin(void)
-{
- VALUE require_stack = GET_VM()->require_stack;
- if (require_stack) {
- rb_ary_push(require_stack, Qnil);
- }
-}
-
-void
-rb_namespace_disable_builtin(void)
-{
- VALUE require_stack = GET_VM()->require_stack;
- if (require_stack) {
- rb_ary_pop(require_stack);
- }
-}
-
-void
-rb_namespace_push_loading_namespace(const rb_namespace_t *ns)
-{
- VALUE require_stack = GET_VM()->require_stack;
- rb_ary_push(require_stack, ns->ns_object);
-}
-
-void
-rb_namespace_pop_loading_namespace(const rb_namespace_t *ns)
-{
- VALUE require_stack = GET_VM()->require_stack;
- long size = RARRAY_LEN(require_stack);
- if (size == 0)
- rb_bug("popping on the empty require_stack");
- VALUE latest = RARRAY_AREF(require_stack, size-1);
- if (latest != ns->ns_object)
- rb_bug("Inconsistent loading namespace");
- rb_ary_pop(require_stack);
-}
-
-rb_namespace_t *
-rb_root_namespace(void)
-{
- return root_namespace;
-}
-
-const rb_namespace_t *
-rb_builtin_namespace(void)
-{
- return (const rb_namespace_t *)builtin_namespace;
-}
-
-rb_namespace_t *
-rb_main_namespace(void)
-{
- return main_namespace;
-}
-
-static bool
-namespace_ignore_builtin_primitive_methods_p(const rb_namespace_t *ns, rb_method_definition_t *def)
-{
- if (!NAMESPACE_BUILTIN_P(ns)) {
- return false;
- }
- /* Primitive methods (just to call C methods) covers/hides the effective
- namespaces, so ignore the methods' namespaces to expose user code's
- namespace to the implementation.
- */
- if (def->type == VM_METHOD_TYPE_ISEQ) {
- ID mid = def->original_id;
- const char *path = RSTRING_PTR(pathobj_path(def->body.iseq.iseqptr->body->location.pathobj));
- if (strcmp(path, "<internal:kernel>") == 0) {
- if (mid == rb_intern("class") || mid == rb_intern("clone") ||
- mid == rb_intern("tag") || mid == rb_intern("then") ||
- mid == rb_intern("yield_self") || mid == rb_intern("loop") ||
- mid == rb_intern("Float") || mid == rb_intern("Integer")
- ) {
- return true;
- }
- }
- else if (strcmp(path, "<internal:warning>") == 0) {
- if (mid == rb_intern("warn")) {
- return true;
- }
- }
- else if (strcmp(path, "<internal:marshal>") == 0) {
- if (mid == rb_intern("load"))
- return true;
- }
- }
- return false;
-}
-
-static inline const rb_namespace_t *
-block_proc_namespace(const VALUE procval)
-{
- rb_proc_t *proc;
-
- if (procval) {
- GetProcPtr(procval, proc);
- return proc->ns;
- }
- else {
- return NULL;
- }
-}
-
-static const rb_namespace_t *
-current_namespace(bool permit_calling_builtin)
-{
- /*
- * TODO: move this code to vm.c or somewhere else
- * when it's fully updated with VM_FRAME_FLAG_*
- */
- const rb_callable_method_entry_t *cme;
- const rb_namespace_t *ns;
- rb_execution_context_t *ec = GET_EC();
- rb_control_frame_t *cfp = ec->cfp;
- rb_thread_t *th = rb_ec_thread_ptr(ec);
- int calling = 1;
-
- if (!rb_namespace_available())
- return 0;
-
- if (th->namespaces && RARRAY_LEN(th->namespaces) > 0) {
- // temp code to detect the context is in require/load
- // TODO: this doesn't work well in optional namespaces
- // calling = 0;
- }
- while (calling) {
- const rb_namespace_t *proc_ns = NULL;
- VALUE bh;
- if (VM_FRAME_NS_SWITCH_P(cfp)) {
- bh = rb_vm_frame_block_handler(cfp);
- if (bh && vm_block_handler_type(bh) == block_handler_type_proc) {
- proc_ns = block_proc_namespace(VM_BH_TO_PROC(bh));
- if (permit_calling_builtin || NAMESPACE_USER_P(proc_ns))
- return proc_ns;
- }
- }
- cme = rb_vm_frame_method_entry(cfp);
- if (cme && cme->def) {
- ns = cme->def->ns;
- if (ns) {
- // this method is not a built-in class/module's method
- // or a built-in primitive (Ruby) method
- if (!namespace_ignore_builtin_primitive_methods_p(ns, cme->def)) {
- if (permit_calling_builtin || (proc_ns && NAMESPACE_USER_P(proc_ns)))
- return ns;
- }
- }
- cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
- }
- else {
- calling = 0;
- }
- }
- // not in namespace-marked method calls
- ns = th->ns;
- if (ns) {
- return ns;
- }
- if (!main_namespace) {
- // Namespaces are not ready to be created
- return root_namespace;
- }
- return main_namespace;
-}
-
-const rb_namespace_t *
-rb_current_namespace(void)
-{
- return current_namespace(true);
-}
-
-const rb_namespace_t *
-rb_loading_namespace(void)
-{
- VALUE namespace;
- long len;
- VALUE require_stack = GET_VM()->require_stack;
-
- if (!rb_namespace_available())
- return 0;
-
- if (!require_stack) {
- return current_namespace(false);
- }
- if ((len = RARRAY_LEN(require_stack)) == 0) {
- return current_namespace(false);
- }
-
- if (!RB_TYPE_P(require_stack, T_ARRAY))
- rb_bug("require_stack is not an array: %s", rb_type_str(BUILTIN_TYPE(require_stack)));
-
- namespace = RARRAY_AREF(require_stack, len-1);
- return rb_get_namespace_t(namespace);
-}
-
-const rb_namespace_t *
-rb_definition_namespace(void)
-{
- const rb_namespace_t *ns = current_namespace(true);
- if (NAMESPACE_BUILTIN_P(ns)) {
- return root_namespace;
- }
- return ns;
-}
-
-static long namespace_id_counter = 0;
-
-static long
-namespace_generate_id(void)
-{
- long id;
- RB_VM_LOCKING() {
- id = ++namespace_id_counter;
- }
- return id;
-}
-
-static void
-namespace_entry_initialize(rb_namespace_t *ns)
-{
- rb_vm_t *vm = GET_VM();
-
- // These will be updated immediately
- ns->ns_object = 0;
- ns->ns_id = 0;
-
- ns->top_self = 0;
- ns->load_path = rb_ary_dup(vm->load_path);
- ns->expanded_load_path = rb_ary_dup(vm->expanded_load_path);
- ns->load_path_snapshot = rb_ary_new();
- ns->load_path_check_cache = 0;
- ns->loaded_features = rb_ary_dup(vm->loaded_features);
- ns->loaded_features_snapshot = rb_ary_new();
- ns->loaded_features_index = st_init_numtable();
- ns->loaded_features_realpaths = rb_hash_dup(vm->loaded_features_realpaths);
- ns->loaded_features_realpath_map = rb_hash_dup(vm->loaded_features_realpath_map);
- ns->loading_table = st_init_strtable();
- ns->ruby_dln_libmap = rb_hash_new_with_size(0);
- ns->gvar_tbl = rb_hash_new_with_size(0);
-
- ns->is_builtin = false;
- ns->is_user = true;
- ns->is_optional = true;
-}
-
-void rb_namespace_gc_update_references(void *ptr)
-{
- rb_namespace_t *ns = (rb_namespace_t *)ptr;
- if (!NIL_P(ns->ns_object))
- ns->ns_object = rb_gc_location(ns->ns_object);
- ns->top_self = rb_gc_location(ns->top_self);
- ns->load_path = rb_gc_location(ns->load_path);
- ns->expanded_load_path = rb_gc_location(ns->expanded_load_path);
- ns->load_path_snapshot = rb_gc_location(ns->load_path_snapshot);
- if (ns->load_path_check_cache) {
- ns->load_path_check_cache = rb_gc_location(ns->load_path_check_cache);
- }
- ns->loaded_features = rb_gc_location(ns->loaded_features);
- ns->loaded_features_snapshot = rb_gc_location(ns->loaded_features_snapshot);
- ns->loaded_features_realpaths = rb_gc_location(ns->loaded_features_realpaths);
- ns->loaded_features_realpath_map = rb_gc_location(ns->loaded_features_realpath_map);
- ns->ruby_dln_libmap = rb_gc_location(ns->ruby_dln_libmap);
- ns->gvar_tbl = rb_gc_location(ns->gvar_tbl);
-}
-
-void
-rb_namespace_entry_mark(void *ptr)
-{
- const rb_namespace_t *ns = (rb_namespace_t *)ptr;
- rb_gc_mark(ns->ns_object);
- rb_gc_mark(ns->top_self);
- rb_gc_mark(ns->load_path);
- rb_gc_mark(ns->expanded_load_path);
- rb_gc_mark(ns->load_path_snapshot);
- rb_gc_mark(ns->load_path_check_cache);
- rb_gc_mark(ns->loaded_features);
- rb_gc_mark(ns->loaded_features_snapshot);
- rb_gc_mark(ns->loaded_features_realpaths);
- rb_gc_mark(ns->loaded_features_realpath_map);
- if (ns->loading_table) {
- rb_mark_tbl(ns->loading_table);
- }
- rb_gc_mark(ns->ruby_dln_libmap);
- rb_gc_mark(ns->gvar_tbl);
-}
-
-#define namespace_entry_free RUBY_TYPED_DEFAULT_FREE
-
-static size_t
-namespace_entry_memsize(const void *ptr)
-{
- return sizeof(rb_namespace_t);
-}
-
-const rb_data_type_t rb_namespace_data_type = {
- "Namespace::Entry",
- {
- rb_namespace_entry_mark,
- namespace_entry_free,
- namespace_entry_memsize,
- rb_namespace_gc_update_references,
- },
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY // TODO: enable RUBY_TYPED_WB_PROTECTED when inserting write barriers
-};
-
-VALUE
-rb_namespace_entry_alloc(VALUE klass)
-{
- rb_namespace_t *entry;
- VALUE obj = TypedData_Make_Struct(klass, rb_namespace_t, &rb_namespace_data_type, entry);
- namespace_entry_initialize(entry);
- return obj;
-}
-
-static rb_namespace_t *
-get_namespace_struct_internal(VALUE entry)
-{
- rb_namespace_t *sval;
- TypedData_Get_Struct(entry, rb_namespace_t, &rb_namespace_data_type, sval);
- return sval;
-}
-
-rb_namespace_t *
-rb_get_namespace_t(VALUE namespace)
-{
- VALUE entry;
- ID id_namespace_entry;
-
- if (!namespace)
- return root_namespace;
- if (NIL_P(namespace))
- return builtin_namespace;
-
- CONST_ID(id_namespace_entry, "__namespace_entry__");
- entry = rb_attr_get(namespace, id_namespace_entry);
- return get_namespace_struct_internal(entry);
-}
-
-VALUE
-rb_get_namespace_object(rb_namespace_t *ns)
-{
- if (!ns) // root namespace
- return Qfalse;
- return ns->ns_object;
-}
-
-static void setup_pushing_loading_namespace(rb_namespace_t *ns);
-
-/*
- * call-seq:
- * Namespace.new -> new_namespace
- *
- * Returns a new Namespace object.
- */
-static VALUE
-namespace_initialize(VALUE namespace)
-{
- rb_namespace_t *ns;
- rb_classext_t *object_classext;
- VALUE entry;
- ID id_namespace_entry;
- CONST_ID(id_namespace_entry, "__namespace_entry__");
-
- if (!rb_namespace_available()) {
- rb_raise(rb_eRuntimeError, "Namespace is disabled. Set RUBY_NAMESPACE=1 environment variable to use Namespace.");
- }
-
- entry = rb_class_new_instance_pass_kw(0, NULL, rb_cNamespaceEntry);
- ns = get_namespace_struct_internal(entry);
-
- ns->ns_object = namespace;
- ns->ns_id = namespace_generate_id();
- ns->load_path = rb_ary_dup(GET_VM()->load_path);
- ns->is_user = true;
- rb_define_singleton_method(ns->load_path, "resolve_feature_path", rb_resolve_feature_path, 1);
-
- // Set the Namespace object unique/consistent from any namespaces to have just single
- // constant table from any view of every (including main) namespace.
- // If a code in the namespace adds a constant, the constant will be visible even from root/main.
- RCLASS_SET_PRIME_CLASSEXT_WRITABLE(namespace, true);
-
- // Get a clean constant table of Object even by writable one
- // because ns was just created, so it has not touched any constants yet.
- object_classext = RCLASS_EXT_WRITABLE_IN_NS(rb_cObject, ns);
- RCLASS_SET_CONST_TBL(namespace, RCLASSEXT_CONST_TBL(object_classext), true);
-
- rb_ivar_set(namespace, id_namespace_entry, entry);
-
- setup_pushing_loading_namespace(ns);
-
- return namespace;
-}
-
-/*
- * call-seq:
- * Namespace.enabled? -> true or false
- *
- * Returns +true+ if namespace is enabled.
- */
-static VALUE
-rb_namespace_s_getenabled(VALUE namespace)
-{
- return RBOOL(rb_namespace_available());
-}
-
-/*
- * call-seq:
- * Namespace.current -> namespace, nil or false
- *
- * Returns the current namespace.
- * Returns +nil+ if it is the built-in namespace.
- * Returns +false+ if namespace is not enabled.
- */
-static VALUE
-rb_namespace_current(VALUE klass)
-{
- const rb_namespace_t *ns = rb_current_namespace();
- if (NAMESPACE_USER_P(ns)) {
- return ns->ns_object;
- }
- if (NAMESPACE_BUILTIN_P(ns)) {
- return Qnil;
- }
- return Qfalse;
-}
-
-/*
- * call-seq:
- * Namespace.is_builtin?(klass) -> true or false
- *
- * Returns +true+ if +klass+ is only in a user namespace.
- */
-static VALUE
-rb_namespace_s_is_builtin_p(VALUE namespace, VALUE klass)
-{
- if (RCLASS_PRIME_CLASSEXT_READABLE_P(klass) && !RCLASS_PRIME_CLASSEXT_WRITABLE_P(klass))
- return Qtrue;
- return Qfalse;
-}
-
-/*
- * call-seq:
- * load_path -> array
- *
- * Returns namespace local load path.
- */
-static VALUE
-rb_namespace_load_path(VALUE namespace)
-{
- return rb_get_namespace_t(namespace)->load_path;
-}
-
-#ifdef _WIN32
-UINT rb_w32_system_tmpdir(WCHAR *path, UINT len);
-#endif
-
-/* Copied from mjit.c Ruby 3.0.3 */
-static char *
-system_default_tmpdir(void)
-{
- // c.f. ext/etc/etc.c:etc_systmpdir()
-#ifdef _WIN32
- WCHAR tmppath[_MAX_PATH];
- UINT len = rb_w32_system_tmpdir(tmppath, numberof(tmppath));
- if (len) {
- int blen = WideCharToMultiByte(CP_UTF8, 0, tmppath, len, NULL, 0, NULL, NULL);
- char *tmpdir = xmalloc(blen + 1);
- WideCharToMultiByte(CP_UTF8, 0, tmppath, len, tmpdir, blen, NULL, NULL);
- tmpdir[blen] = '\0';
- return tmpdir;
- }
-#elif 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 _WIN32
-# 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;
-#endif
- 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
-}
-
-/* end of copy */
-
-static int
-sprint_ext_filename(char *str, size_t size, long namespace_id, const char *prefix, const char *basename)
-{
- if (tmp_dir_has_dirsep) {
- return snprintf(str, size, "%s%sp%"PRI_PIDT_PREFIX"u_%ld_%s", tmp_dir, prefix, getpid(), namespace_id, basename);
- }
- return snprintf(str, size, "%s%s%sp%"PRI_PIDT_PREFIX"u_%ld_%s", tmp_dir, DIRSEP, prefix, getpid(), namespace_id, basename);
-}
-
-#ifdef _WIN32
-static const char *
-copy_ext_file_error(char *message, size_t size)
-{
- int error = GetLastError();
- char *p = message;
- size_t len = snprintf(message, size, "%d: ", error);
-
-#define format_message(sublang) FormatMessage(\
- FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, \
- NULL, error, MAKELANGID(LANG_NEUTRAL, (sublang)), \
- message + len, size - len, NULL)
- if (format_message(SUBLANG_ENGLISH_US) == 0)
- format_message(SUBLANG_DEFAULT);
- for (p = message + len; *p; p++) {
- if (*p == '\n' || *p == '\r')
- *p = ' ';
- }
- return message;
-}
-#else
-static const char *
-copy_ext_file_error(char *message, size_t size, int copy_retvalue, char *src_path, char *dst_path)
-{
- switch (copy_retvalue) {
- case 1:
- snprintf(message, size, "can't open the extension path: %s", src_path);
- case 2:
- snprintf(message, size, "can't open the file to write: %s", dst_path);
- case 3:
- snprintf(message, size, "failed to read the extension path: %s", src_path);
- case 4:
- snprintf(message, size, "failed to write the extension path: %s", dst_path);
- default:
- rb_bug("unknown return value of copy_ext_file: %d", copy_retvalue);
- }
- return message;
-}
-#endif
-
-static int
-copy_ext_file(char *src_path, char *dst_path)
-{
-#if defined(_WIN32)
- int rvalue;
-
- WCHAR *w_src = rb_w32_mbstr_to_wstr(CP_UTF8, src_path, -1, NULL);
- WCHAR *w_dst = rb_w32_mbstr_to_wstr(CP_UTF8, dst_path, -1, NULL);
- if (!w_src || !w_dst) {
- rb_memerror();
- }
-
- rvalue = CopyFileW(w_src, w_dst, FALSE) ? 0 : 1;
- free(w_src);
- free(w_dst);
- return rvalue;
-#else
- FILE *src, *dst;
- char buffer[1024];
- size_t read = 0, wrote, written = 0;
- size_t maxread = sizeof(buffer);
- int eof = 0;
- int clean_read = 1;
- int retvalue = 0;
-
- src = fopen(src_path, "rb");
- if (!src) {
- return 1;
- }
- dst = fopen(dst_path, "wb");
- if (!dst) {
- return 2;
- }
- while (!eof) {
- if (clean_read) {
- read = fread(buffer, 1, sizeof(buffer), src);
- written = 0;
- }
- if (read > 0) {
- wrote = fwrite(buffer+written, 1, read-written, dst);
- if (wrote < read-written) {
- if (ferror(dst)) {
- retvalue = 4;
- break;
- }
- else { // partial write
- clean_read = 0;
- written += wrote;
- }
- }
- else { // Wrote the entire buffer to dst, next read is clean one
- clean_read = 1;
- }
- }
- if (read < maxread) {
- if (clean_read && feof(src)) {
- // If it's not clean, buffer should have bytes not written yet.
- eof = 1;
- }
- else if (ferror(src)) {
- retvalue = 3;
- // Writes could be partial/dirty, but this load is failure anyway
- break;
- }
- }
- }
- fclose(src);
- fclose(dst);
- return retvalue;
-#endif
-}
-
-#if defined __CYGWIN__ || defined DOSISH
-#define isdirsep(x) ((x) == '/' || (x) == '\\')
-#else
-#define isdirsep(x) ((x) == '/')
-#endif
-
-#define IS_SOEXT(e) (strcmp((e), ".so") == 0 || strcmp((e), ".o") == 0)
-#define IS_DLEXT(e) (strcmp((e), DLEXT) == 0)
-
-static void
-fname_without_suffix(char *fname, char *rvalue)
-{
- char *pos;
- strcpy(rvalue, fname);
- for (pos = rvalue + strlen(fname); pos > rvalue; pos--) {
- if (IS_SOEXT(pos) || IS_DLEXT(pos)) {
- *pos = '\0';
- return;
- }
- }
-}
-
-static void
-escaped_basename(char *path, char *fname, char *rvalue)
-{
- char *pos, *leaf, *found;
- leaf = path;
- // `leaf + 1` looks uncomfortable (when leaf == path), but fname must not be the top-dir itself
- while ((found = strstr(leaf + 1, fname)) != NULL) {
- leaf = found; // find the last occurrence for the path like /etc/my-crazy-lib-dir/etc.so
- }
- strcpy(rvalue, leaf);
- for (pos = rvalue; *pos; pos++) {
- if (isdirsep(*pos)) {
- *pos = '+';
- }
- }
-}
-
-VALUE
-rb_namespace_local_extension(VALUE namespace, VALUE fname, VALUE path)
-{
- char ext_path[MAXPATHLEN], fname2[MAXPATHLEN], basename[MAXPATHLEN];
- int copy_error, wrote;
- char *src_path = RSTRING_PTR(path), *fname_ptr = RSTRING_PTR(fname);
- rb_namespace_t *ns = rb_get_namespace_t(namespace);
-
- fname_without_suffix(fname_ptr, fname2);
- escaped_basename(src_path, fname2, basename);
-
- wrote = sprint_ext_filename(ext_path, sizeof(ext_path), ns->ns_id, NAMESPACE_TMP_PREFIX, basename);
- if (wrote >= (int)sizeof(ext_path)) {
- rb_bug("Extension file path in namespace was too long");
- }
- copy_error = copy_ext_file(src_path, ext_path);
- if (copy_error) {
- char message[1024];
-#if defined(_WIN32)
- copy_ext_file_error(message, sizeof(message));
-#else
- copy_ext_file_error(message, sizeof(message), copy_error, src_path, ext_path);
-#endif
- rb_raise(rb_eLoadError, "can't prepare the extension file for namespaces (%s from %s): %s", ext_path, src_path, message);
- }
- // TODO: register the path to be clean-uped
- return rb_str_new_cstr(ext_path);
-}
-
-// TODO: delete it just after dln_load? or delay it?
-// At least for _WIN32, deleting extension files should be delayed until the namespace's destructor.
-// And it requires calling dlclose before deleting it.
-
-static void
-namespace_push(rb_thread_t *th, VALUE namespace)
-{
- if (RTEST(th->namespaces)) {
- rb_ary_push(th->namespaces, namespace);
- }
- else {
- th->namespaces = rb_ary_new_from_args(1, namespace);
- }
- th->ns = rb_get_namespace_t(namespace);
-}
-
-static VALUE
-namespace_pop(VALUE th_value)
-{
- VALUE upper_ns;
- long stack_len;
- rb_thread_t *th = (rb_thread_t *)th_value;
- VALUE namespaces = th->namespaces;
- if (!namespaces) {
- rb_bug("Too many namespace pops");
- }
- rb_ary_pop(namespaces);
- stack_len = RARRAY_LEN(namespaces);
- if (stack_len == 0) {
- th->namespaces = 0;
- th->ns = main_namespace;
- }
- else {
- upper_ns = RARRAY_AREF(namespaces, stack_len-1);
- th->ns = rb_get_namespace_t(upper_ns);
- }
- return Qnil;
-}
-
-VALUE
-rb_namespace_exec(const rb_namespace_t *ns, namespace_exec_func *func, VALUE arg)
-{
- rb_thread_t *th = GET_THREAD();
- namespace_push(th, ns ? ns->ns_object : Qnil);
- return rb_ensure(func, arg, namespace_pop, (VALUE)th);
-}
-
-struct namespace_pop2_arg {
- rb_thread_t *th;
- rb_namespace_t *ns;
-};
-
-static VALUE
-namespace_both_pop(VALUE arg)
-{
- struct namespace_pop2_arg *data = (struct namespace_pop2_arg *)arg;
- namespace_pop((VALUE) data->th);
- rb_namespace_pop_loading_namespace(data->ns);
- return Qnil;
-}
-
-static VALUE
-rb_namespace_load(int argc, VALUE *argv, VALUE namespace)
-{
- VALUE fname, wrap;
- rb_thread_t *th = GET_THREAD();
- rb_namespace_t *ns = rb_get_namespace_t(namespace);
-
- rb_scan_args(argc, argv, "11", &fname, &wrap);
-
- VALUE args = rb_ary_new_from_args(2, fname, wrap);
- namespace_push(th, namespace);
- rb_namespace_push_loading_namespace(ns);
- struct namespace_pop2_arg arg = {
- .th = th,
- .ns = ns
- };
- return rb_ensure(rb_load_entrypoint, args, namespace_both_pop, (VALUE)&arg);
-}
-
-static VALUE
-rb_namespace_require(VALUE namespace, VALUE fname)
-{
- rb_thread_t *th = GET_THREAD();
- rb_namespace_t *ns = rb_get_namespace_t(namespace);
- namespace_push(th, namespace);
- rb_namespace_push_loading_namespace(ns);
- struct namespace_pop2_arg arg = {
- .th = th,
- .ns = ns
- };
- return rb_ensure(rb_require_string, fname, namespace_both_pop, (VALUE)&arg);
-}
-
-static VALUE
-rb_namespace_require_relative(VALUE namespace, VALUE fname)
-{
- rb_thread_t *th = GET_THREAD();
- rb_namespace_t *ns = rb_get_namespace_t(namespace);
- namespace_push(th, namespace);
- rb_namespace_push_loading_namespace(ns);
- struct namespace_pop2_arg arg = {
- .th = th,
- .ns = ns
- };
- return rb_ensure(rb_require_relative_entrypoint, fname, namespace_both_pop, (VALUE)&arg);
-}
-
-static VALUE
-rb_namespace_eval_string(VALUE str)
-{
- return rb_eval_string(RSTRING_PTR(str));
-}
-
-static VALUE
-rb_namespace_eval(VALUE namespace, VALUE str)
-{
- rb_thread_t *th = GET_THREAD();
-
- StringValue(str);
-
- namespace_push(th, namespace);
- return rb_ensure(rb_namespace_eval_string, str, namespace_pop, (VALUE)th);
-}
-
-static int namespace_experimental_warned = 0;
-
-void
-rb_initialize_main_namespace(void)
-{
- rb_namespace_t *ns;
- rb_vm_t *vm = GET_VM();
- rb_thread_t *th = GET_THREAD();
- VALUE main_ns;
-
- if (!namespace_experimental_warned) {
- rb_category_warn(RB_WARN_CATEGORY_EXPERIMENTAL,
- "Namespace is experimental, and the behavior may change in the future!\n"
- "See doc/namespace.md for known issues, etc.");
- namespace_experimental_warned = 1;
- }
-
- main_ns = rb_class_new_instance_pass_kw(0, NULL, rb_cNamespace);
- ns = rb_get_namespace_t(main_ns);
- ns->ns_object = main_ns;
- ns->ns_id = namespace_generate_id();
- ns->is_builtin = false;
- ns->is_user = true;
- ns->is_optional = false;
-
- rb_const_set(rb_cNamespace, rb_intern("MAIN"), main_ns);
-
- vm->main_namespace = th->ns = main_namespace = ns;
-}
-
-static VALUE
-rb_namespace_inspect(VALUE obj)
-{
- rb_namespace_t *ns;
- VALUE r;
- if (obj == Qfalse) {
- r = rb_str_new_cstr("#<Namespace:root>");
- return r;
- }
- ns = rb_get_namespace_t(obj);
- r = rb_str_new_cstr("#<Namespace:");
- rb_str_concat(r, rb_funcall(LONG2NUM(ns->ns_id), rb_intern("to_s"), 0));
- if (NAMESPACE_BUILTIN_P(ns)) {
- rb_str_cat_cstr(r, ",builtin");
- }
- if (NAMESPACE_USER_P(ns)) {
- rb_str_cat_cstr(r, ",user");
- }
- if (NAMESPACE_MAIN_P(ns)) {
- rb_str_cat_cstr(r, ",main");
- }
- else if (NAMESPACE_OPTIONAL_P(ns)) {
- rb_str_cat_cstr(r, ",optional");
- }
- rb_str_cat_cstr(r, ">");
- return r;
-}
-
-struct refiner_calling_super_data {
- int argc;
- VALUE *argv;
-};
-
-static VALUE
-namespace_builtin_refiner_calling_super(VALUE arg)
-{
- struct refiner_calling_super_data *data = (struct refiner_calling_super_data *)arg;
- return rb_call_super(data->argc, data->argv);
-}
-
-static VALUE
-namespace_builtin_refiner_loading_func_ensure(VALUE _)
-{
- rb_vm_t *vm = GET_VM();
- if (!vm->require_stack)
- rb_bug("require_stack is not ready but the namespace refiner is called");
- rb_namespace_disable_builtin();
- return Qnil;
-}
-
-static VALUE
-rb_namespace_builtin_refiner_loading_func(int argc, VALUE *argv, VALUE _self)
-{
- rb_vm_t *vm = GET_VM();
- if (!vm->require_stack)
- rb_bug("require_stack is not ready but the namespace refiner is called");
- rb_namespace_enable_builtin();
- // const rb_namespace_t *ns = rb_loading_namespace();
- // printf("N:current loading ns: %ld\n", ns->ns_id);
- struct refiner_calling_super_data data = {
- .argc = argc,
- .argv = argv
- };
- return rb_ensure(namespace_builtin_refiner_calling_super, (VALUE)&data,
- namespace_builtin_refiner_loading_func_ensure, Qnil);
-}
-
-static void
-setup_builtin_refinement(VALUE mod)
-{
- struct rb_refinements_data data;
- rb_refinement_setup(&data, mod, rb_mKernel);
- rb_define_method(data.refinement, "require", rb_namespace_builtin_refiner_loading_func, -1);
- rb_define_method(data.refinement, "require_relative", rb_namespace_builtin_refiner_loading_func, -1);
- rb_define_method(data.refinement, "load", rb_namespace_builtin_refiner_loading_func, -1);
-}
-
-static VALUE
-namespace_user_loading_func_calling_super(VALUE arg)
-{
- struct refiner_calling_super_data *data = (struct refiner_calling_super_data *)arg;
- return rb_call_super(data->argc, data->argv);
-}
-
-static VALUE
-namespace_user_loading_func_ensure(VALUE arg)
-{
- rb_namespace_t *ns = (rb_namespace_t *)arg;
- rb_namespace_pop_loading_namespace(ns);
- return Qnil;
-}
-
-static VALUE
-rb_namespace_user_loading_func(int argc, VALUE *argv, VALUE _self)
-{
- const rb_namespace_t *ns;
- rb_vm_t *vm = GET_VM();
- if (!vm->require_stack)
- rb_bug("require_stack is not ready but require/load is called in user namespaces");
- ns = rb_current_namespace();
- VM_ASSERT(rb_namespace_available() || !ns);
- rb_namespace_push_loading_namespace(ns);
- struct refiner_calling_super_data data = {
- .argc = argc,
- .argv = argv
- };
- return rb_ensure(namespace_user_loading_func_calling_super, (VALUE)&data,
- namespace_user_loading_func_ensure, (VALUE)ns);
-}
-
-static VALUE
-setup_pushing_loading_namespace_include(VALUE mod)
-{
- rb_include_module(rb_cObject, mod);
- return Qnil;
-}
-
-static void
-setup_pushing_loading_namespace(rb_namespace_t *ns)
-{
- rb_namespace_exec(ns, setup_pushing_loading_namespace_include, rb_mNamespaceLoader);
-}
-
-static void
-namespace_define_loader_method(const char *name)
-{
- rb_define_private_method(rb_mNamespaceLoader, name, rb_namespace_user_loading_func, -1);
- rb_define_singleton_method(rb_mNamespaceLoader, name, rb_namespace_user_loading_func, -1);
-}
-
-void
-Init_enable_namespace(void)
-{
- const char *env = getenv("RUBY_NAMESPACE");
- if (env && strlen(env) == 1 && env[0] == '1') {
- ruby_namespace_enabled = true;
- }
- else {
- ruby_namespace_init_done = true;
- }
-}
-
-/*
- * Document-class: Namespace
- *
- * Namespace is designed to provide separated spaces in a Ruby
- * process, to isolate applications and libraries.
- * See {Namespace}[rdoc-ref:namespace.md].
- */
-void
-Init_Namespace(void)
-{
- tmp_dir = system_tmpdir();
- tmp_dir_has_dirsep = (strcmp(tmp_dir + (strlen(tmp_dir) - strlen(DIRSEP)), DIRSEP) == 0);
-
- rb_cNamespace = rb_define_class("Namespace", rb_cModule);
- rb_define_method(rb_cNamespace, "initialize", namespace_initialize, 0);
-
- /* :nodoc: */
- rb_cNamespaceEntry = rb_define_class_under(rb_cNamespace, "Entry", rb_cObject);
- rb_define_alloc_func(rb_cNamespaceEntry, rb_namespace_entry_alloc);
-
- /* :nodoc: */
- rb_mNamespaceRefiner = rb_define_module_under(rb_cNamespace, "Refiner");
- if (rb_namespace_available()) {
- setup_builtin_refinement(rb_mNamespaceRefiner);
- }
-
- /* :nodoc: */
- rb_mNamespaceLoader = rb_define_module_under(rb_cNamespace, "Loader");
- namespace_define_loader_method("require");
- namespace_define_loader_method("require_relative");
- namespace_define_loader_method("load");
-
- rb_define_singleton_method(rb_cNamespace, "enabled?", rb_namespace_s_getenabled, 0);
- rb_define_singleton_method(rb_cNamespace, "current", rb_namespace_current, 0);
- rb_define_singleton_method(rb_cNamespace, "is_builtin?", rb_namespace_s_is_builtin_p, 1);
-
- rb_define_method(rb_cNamespace, "load_path", rb_namespace_load_path, 0);
- rb_define_method(rb_cNamespace, "load", rb_namespace_load, -1);
- rb_define_method(rb_cNamespace, "require", rb_namespace_require, 1);
- rb_define_method(rb_cNamespace, "require_relative", rb_namespace_require_relative, 1);
- rb_define_method(rb_cNamespace, "eval", rb_namespace_eval, 1);
-
- rb_define_method(rb_cNamespace, "inspect", rb_namespace_inspect, 0);
-
- rb_vm_t *vm = GET_VM();
- vm->require_stack = rb_ary_new();
-}
diff --git a/node_dump.c b/node_dump.c
index 18ac3d7b35..82a7d78c28 100644
--- a/node_dump.c
+++ b/node_dump.c
@@ -1023,8 +1023,11 @@ dump_node(VALUE buf, VALUE indent, int comment, const NODE * node)
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");
+ F_LOC(class_keyword_loc, RNODE_SCLASS);
+ F_LOC(operator_loc, RNODE_SCLASS);
+ LAST_NODE;
+ F_LOC(end_keyword_loc, RNODE_SCLASS);
return;
case NODE_COLON2:
diff --git a/numeric.c b/numeric.c
index 89cff8a730..f4dc0f8927 100644
--- a/numeric.c
+++ b/numeric.c
@@ -30,6 +30,7 @@
#include "internal/compilers.h"
#include "internal/complex.h"
#include "internal/enumerator.h"
+#include "internal/error.h"
#include "internal/gc.h"
#include "internal/hash.h"
#include "internal/numeric.h"
@@ -74,6 +75,8 @@
#define DBL_EPSILON 2.2204460492503131e-16
#endif
+#define ACCURATE_POW10(ndigits) ((ndigits) < DBL_DIG)
+
#ifndef USE_RB_INFINITY
#elif !defined(WORDS_BIGENDIAN) /* BYTE_ORDER == LITTLE_ENDIAN */
const union bytesequence4_or_float rb_infinity = {{0x00, 0x00, 0x80, 0x7f}};
@@ -491,7 +494,7 @@ rb_num_coerce_cmp(VALUE x, VALUE y, ID func)
static VALUE
ensure_cmp(VALUE c, VALUE x, VALUE y)
{
- if (NIL_P(c)) rb_cmperr(x, y);
+ if (NIL_P(c)) rb_cmperr_reason(x, y, "comparator returned nil");
return c;
}
@@ -501,7 +504,7 @@ rb_num_coerce_relop(VALUE x, VALUE y, ID func)
VALUE x0 = x, y0 = y;
if (!do_coerce(&x, &y, FALSE)) {
- rb_cmperr(x0, y0);
+ rb_cmperr_reason(x0, y0, "coercion was not possible");
UNREACHABLE_RETURN(Qnil);
}
return ensure_cmp(rb_funcall(x, func, 1, y), x0, y0);
@@ -576,7 +579,7 @@ num_imaginary(VALUE num)
* call-seq:
* -self -> numeric
*
- * Unary Minus---Returns the receiver, negated.
+ * Returns +self+, negated.
*/
static VALUE
@@ -595,8 +598,8 @@ num_uminus(VALUE num)
* fdiv(other) -> float
*
* Returns the quotient <tt>self/other</tt> as a float,
- * using method +/+ in the derived class of +self+.
- * (\Numeric itself does not define method +/+.)
+ * using method +/+ as defined in the subclass of \Numeric.
+ * (\Numeric itself does not define +/+.)
*
* Of the Core and Standard Library classes,
* only BigDecimal uses this implementation.
@@ -614,8 +617,8 @@ num_fdiv(VALUE x, VALUE y)
* div(other) -> integer
*
* Returns the quotient <tt>self/other</tt> as an integer (via +floor+),
- * using method +/+ in the derived class of +self+.
- * (\Numeric itself does not define method +/+.)
+ * using method +/+ as defined in the subclass of \Numeric.
+ * (\Numeric itself does not define +/+.)
*
* Of the Core and Standard Library classes,
* Only Float and Rational use this implementation.
@@ -633,7 +636,7 @@ num_div(VALUE x, VALUE y)
* call-seq:
* self % other -> real_numeric
*
- * Returns +self+ modulo +other+ as a real number.
+ * Returns +self+ modulo +other+ as a real numeric (\Integer, \Float, or \Rational).
*
* Of the Core and Standard Library classes,
* only Rational uses this implementation.
@@ -847,7 +850,8 @@ num_nonzero_p(VALUE num)
* to_int -> integer
*
* Returns +self+ as an integer;
- * converts using method +to_i+ in the derived class.
+ * converts using method +to_i+ in the subclass of \Numeric.
+ * (\Numeric itself does not define +to_i+.)
*
* Of the Core and Standard Library classes,
* only Rational and Complex use this implementation.
@@ -905,92 +909,10 @@ num_negative_p(VALUE num)
return RBOOL(rb_num_negative_int_p(num));
}
-
-/********************************************************************
- *
- * Document-class: Float
- *
- * A \Float object represents a sometimes-inexact real number using the native
- * architecture's double-precision floating point representation.
- *
- * Floating point has a different arithmetic and is an inexact number.
- * 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://en.wikipedia.org/wiki/Floating_point#Accuracy_problems
- *
- * You can create a \Float object explicitly with:
- *
- * - A {floating-point literal}[rdoc-ref:syntax/literals.rdoc@Float+Literals].
- *
- * You can convert certain objects to Floats with:
- *
- * - Method #Float.
- *
- * == What's Here
- *
- * 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].
- *
- * Here, class \Float provides methods for:
- *
- * - {Querying}[rdoc-ref:Float@Querying]
- * - {Comparing}[rdoc-ref:Float@Comparing]
- * - {Converting}[rdoc-ref:Float@Converting]
- *
- * === Querying
- *
- * - #finite?: Returns whether +self+ is finite.
- * - #hash: Returns the integer hash code for +self+.
- * - #infinite?: Returns whether +self+ is infinite.
- * - #nan?: Returns whether +self+ is a NaN (not-a-number).
- *
- * === Comparing
- *
- * - #<: Returns whether +self+ is less than the given value.
- * - #<=: Returns whether +self+ is less than or equal to the given value.
- * - #<=>: Returns a number indicating whether +self+ is less than, equal
- * to, or greater than the given value.
- * - #== (aliased as #=== and #eql?): Returns whether +self+ is equal to
- * the given value.
- * - #>: Returns whether +self+ is greater than the given value.
- * - #>=: Returns whether +self+ is greater than or equal to the given value.
- *
- * === Converting
- *
- * - #% (aliased as #modulo): Returns +self+ modulo the given value.
- * - #*: Returns the product of +self+ and the given value.
- * - #**: Returns the value of +self+ raised to the power of the given value.
- * - #+: Returns the sum of +self+ and the given value.
- * - #-: Returns the difference of +self+ and the given value.
- * - #/: 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+
- * - #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.
- * - #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.
- * - #quo: Returns the quotient from dividing +self+ by the given value.
- * - #round: Returns +self+ rounded to the nearest value, to a given precision.
- * - #to_i (aliased as #to_int): Returns +self+ truncated to an Integer.
- * - #to_s (aliased as #inspect): Returns a string containing the place-value
- * representation of +self+ in the given radix.
- * - #truncate: Returns +self+ truncated to a given precision.
- *
- */
-
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, sizeof(struct RFloat));
#if SIZEOF_DOUBLE <= SIZEOF_VALUE
flt->float_value = d;
@@ -1131,15 +1053,21 @@ rb_float_uminus(VALUE flt)
/*
* call-seq:
- * self + other -> numeric
+ * self + other -> float or complex
*
- * Returns a new \Float which is the sum of +self+ and +other+:
+ * Returns the sum of +self+ and +other+;
+ * the result may be inexact (see Float):
*
- * f = 3.14
- * f + 1 # => 4.140000000000001
- * f + 1.0 # => 4.140000000000001
- * f + Rational(1, 1) # => 4.140000000000001
- * f + Complex(1, 0) # => (4.140000000000001+0i)
+ * 3.14 + 0 # => 3.14
+ * 3.14 + 1 # => 4.140000000000001
+ * -3.14 + 0 # => -3.14
+ * -3.14 + 1 # => -2.14
+
+ * 3.14 + -3.14 # => 0.0
+ * -3.14 + -3.14 # => -6.28
+ *
+ * 3.14 + Complex(1, 0) # => (4.140000000000001+0i)
+ * 3.14 + Rational(1, 1) # => 4.140000000000001
*
*/
@@ -1164,7 +1092,7 @@ rb_float_plus(VALUE x, VALUE y)
* call-seq:
* self - other -> numeric
*
- * Returns a new \Float which is the difference of +self+ and +other+:
+ * Returns the difference of +self+ and +other+:
*
* f = 3.14
* f - 1 # => 2.14
@@ -1195,13 +1123,14 @@ rb_float_minus(VALUE x, VALUE y)
* call-seq:
* self * other -> numeric
*
- * Returns a new \Float which is the product of +self+ and +other+:
+ * Returns the numeric product of +self+ and +other+:
*
* f = 3.14
* f * 2 # => 6.28
* f * 2.0 # => 6.28
* f * Rational(1, 2) # => 1.57
* f * Complex(2, 0) # => (6.28+0.0i)
+ *
*/
VALUE
@@ -1249,7 +1178,7 @@ rb_flo_div_flo(VALUE x, VALUE y)
* call-seq:
* self / other -> numeric
*
- * Returns a new \Float which is the result of dividing +self+ by +other+:
+ * Returns the quotient of +self+ and +other+:
*
* f = 3.14
* f / 2 # => 1.57
@@ -1358,7 +1287,7 @@ ruby_float_mod(double x, double y)
* call-seq:
* self % other -> float
*
- * Returns +self+ modulo +other+ as a float.
+ * Returns +self+ modulo +other+ as a \Float.
*
* For float +f+ and real number +r+, these expressions are equivalent:
*
@@ -1464,9 +1393,9 @@ flo_divmod(VALUE x, VALUE y)
/*
* call-seq:
- * self ** other -> numeric
+ * self ** exponent -> numeric
*
- * Raises +self+ to the power of +other+:
+ * Returns +self+ raised to the power +exponent+:
*
* f = 3.14
* f ** 2 # => 9.8596
@@ -1542,10 +1471,17 @@ num_eql(VALUE x, VALUE y)
* call-seq:
* self <=> other -> zero or nil
*
- * Returns zero if +self+ is the same as +other+, +nil+ otherwise.
+ * Compares +self+ and +other+.
*
- * No subclass in the Ruby Core or Standard Library uses this implementation.
+ * Returns:
*
+ * - Zero, if +self+ is the same as +other+.
+ * - +nil+, otherwise.
+ *
+ * \Class \Numeric includes module Comparable,
+ * each of whose methods uses Numeric#<=> for comparison.
+ *
+ * No subclass in the Ruby Core or Standard Library uses this implementation.
*/
static VALUE
@@ -1568,7 +1504,7 @@ num_equal(VALUE x, VALUE y)
* call-seq:
* self == other -> true or false
*
- * Returns +true+ if +other+ has the same value as +self+, +false+ otherwise:
+ * Returns whether +other+ is numerically equal to +self+:
*
* 2.0 == 2 # => true
* 2.0 == 2.0 # => true
@@ -1591,17 +1527,11 @@ rb_float_equal(VALUE x, VALUE y)
}
else if (RB_FLOAT_TYPE_P(y)) {
b = RFLOAT_VALUE(y);
-#if MSC_VERSION_BEFORE(1300)
- if (isnan(b)) return Qfalse;
-#endif
}
else {
return num_equal(x, y);
}
a = RFLOAT_VALUE(x);
-#if MSC_VERSION_BEFORE(1300)
- if (isnan(a)) return Qfalse;
-#endif
return RBOOL(a == b);
}
@@ -1641,30 +1571,32 @@ rb_dbl_cmp(double a, double b)
/*
* call-seq:
- * self <=> other -> -1, 0, +1, or nil
+ * self <=> other -> -1, 0, 1, or nil
*
- * Returns a value that depends on the numeric relation
- * between +self+ and +other+:
+ * Compares +self+ and +other+.
*
- * - -1, if +self+ is less than +other+.
- * - 0, if +self+ is equal to +other+.
- * - 1, if +self+ is greater than +other+.
+ * Returns:
+ *
+ * - +-1+, if +self+ is less than +other+.
+ * - +0+, if +self+ is equal to +other+.
+ * - +1+, if +self+ is greater than +other+.
* - +nil+, if the two values are incommensurate.
*
* Examples:
*
+ * 2.0 <=> 2.1 # => -1
* 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
*
- * This is the basis for the tests in the Comparable module.
- *
* <tt>Float::NAN <=> Float::NAN</tt> returns an implementation-dependent value.
*
+ * \Class \Float includes module Comparable,
+ * each of whose methods uses Float#<=> for comparison.
+ *
*/
static VALUE
@@ -1709,7 +1641,8 @@ rb_float_cmp(VALUE x, VALUE y)
* call-seq:
* self > other -> true or false
*
- * Returns +true+ if +self+ is numerically greater than +other+:
+ * Returns whether the value of +self+ is greater than the value of +other+;
+ * +other+ must be numeric, but may not be Complex:
*
* 2.0 > 1 # => true
* 2.0 > 1.0 # => true
@@ -1734,16 +1667,10 @@ rb_float_gt(VALUE x, VALUE y)
}
else if (RB_FLOAT_TYPE_P(y)) {
b = RFLOAT_VALUE(y);
-#if MSC_VERSION_BEFORE(1300)
- if (isnan(b)) return Qfalse;
-#endif
}
else {
return rb_num_coerce_relop(x, y, '>');
}
-#if MSC_VERSION_BEFORE(1300)
- if (isnan(a)) return Qfalse;
-#endif
return RBOOL(a > b);
}
@@ -1751,7 +1678,8 @@ rb_float_gt(VALUE x, VALUE y)
* call-seq:
* self >= other -> true or false
*
- * Returns +true+ if +self+ is numerically greater than or equal to +other+:
+ * Returns whether the value of +self+ is greater than or equal to the value of +other+;
+ * +other+ must be numeric, but may not be Complex:
*
* 2.0 >= 1 # => true
* 2.0 >= 1.0 # => true
@@ -1777,16 +1705,10 @@ flo_ge(VALUE x, VALUE y)
}
else if (RB_FLOAT_TYPE_P(y)) {
b = RFLOAT_VALUE(y);
-#if MSC_VERSION_BEFORE(1300)
- if (isnan(b)) return Qfalse;
-#endif
}
else {
return rb_num_coerce_relop(x, y, idGE);
}
-#if MSC_VERSION_BEFORE(1300)
- if (isnan(a)) return Qfalse;
-#endif
return RBOOL(a >= b);
}
@@ -1794,7 +1716,8 @@ flo_ge(VALUE x, VALUE y)
* call-seq:
* self < other -> true or false
*
- * Returns +true+ if +self+ is numerically less than +other+:
+ * Returns whether the value of +self+ is less than the value of +other+;
+ * +other+ must be numeric, but may not be Complex:
*
* 2.0 < 3 # => true
* 2.0 < 3.0 # => true
@@ -1802,7 +1725,6 @@ flo_ge(VALUE x, VALUE y)
* 2.0 < 2.0 # => false
*
* <tt>Float::NAN < Float::NAN</tt> returns an implementation-dependent value.
- *
*/
static VALUE
@@ -1819,16 +1741,10 @@ flo_lt(VALUE x, VALUE y)
}
else if (RB_FLOAT_TYPE_P(y)) {
b = RFLOAT_VALUE(y);
-#if MSC_VERSION_BEFORE(1300)
- if (isnan(b)) return Qfalse;
-#endif
}
else {
return rb_num_coerce_relop(x, y, '<');
}
-#if MSC_VERSION_BEFORE(1300)
- if (isnan(a)) return Qfalse;
-#endif
return RBOOL(a < b);
}
@@ -1836,7 +1752,8 @@ flo_lt(VALUE x, VALUE y)
* call-seq:
* self <= other -> true or false
*
- * Returns +true+ if +self+ is numerically less than or equal to +other+:
+ * Returns whether the value of +self+ is less than or equal to the value of +other+;
+ * +other+ must be numeric, but may not be Complex:
*
* 2.0 <= 3 # => true
* 2.0 <= 3.0 # => true
@@ -1862,16 +1779,10 @@ flo_le(VALUE x, VALUE y)
}
else if (RB_FLOAT_TYPE_P(y)) {
b = RFLOAT_VALUE(y);
-#if MSC_VERSION_BEFORE(1300)
- if (isnan(b)) return Qfalse;
-#endif
}
else {
return rb_num_coerce_relop(x, y, idLE);
}
-#if MSC_VERSION_BEFORE(1300)
- if (isnan(a)) return Qfalse;
-#endif
return RBOOL(a <= b);
}
@@ -1899,10 +1810,7 @@ rb_float_eql(VALUE x, VALUE y)
if (RB_FLOAT_TYPE_P(y)) {
double a = RFLOAT_VALUE(x);
double b = RFLOAT_VALUE(y);
-#if MSC_VERSION_BEFORE(1300)
- if (isnan(a) || isnan(b)) return Qfalse;
-#endif
- return RBOOL(a == b);
+ return RBOOL(a == b);
}
return Qfalse;
}
@@ -2112,6 +2020,9 @@ rb_float_floor(VALUE num, int ndigits)
if (float_round_overflow(ndigits, binexp)) return num;
if (number > 0.0 && float_round_underflow(ndigits, binexp))
return DBL2NUM(0.0);
+ if (!ACCURATE_POW10(ndigits)) {
+ return rb_flo_floor_by_rational(num, ndigits);
+ }
f = pow(10, ndigits);
mul = floor(number * f);
res = (mul + 1) / f;
@@ -2320,6 +2231,9 @@ rb_float_ceil(VALUE num, int ndigits)
if (float_round_overflow(ndigits, binexp)) return num;
if (number < 0.0 && float_round_underflow(ndigits, binexp))
return DBL2NUM(0.0);
+ if (!ACCURATE_POW10(ndigits)) {
+ return rb_flo_ceil_by_rational(num, ndigits);
+ }
f = pow(10, ndigits);
f = ceil(number * f) / f;
return DBL2NUM(f);
@@ -2584,9 +2498,8 @@ flo_round(int argc, VALUE *argv, VALUE num)
frexp(number, &binexp);
if (float_round_overflow(ndigits, binexp)) return num;
if (float_round_underflow(ndigits, binexp)) return DBL2NUM(0);
- if (ndigits > 14) {
- /* In this case, pow(10, ndigits) may not be accurate. */
- return rb_flo_round_by_rational(argc, argv, num);
+ if (!ACCURATE_POW10(ndigits)) {
+ return rb_flo_round_by_rational(num, ndigits, mode);
}
f = pow(10, ndigits);
x = ROUND_CALL(mode, round, (number, f));
@@ -2659,6 +2572,12 @@ flo_to_i(VALUE num)
return dbl2ival(f);
}
+VALUE
+rb_flo_to_i(VALUE num)
+{
+ return flo_to_i(num);
+}
+
/*
* call-seq:
* truncate(ndigits = 0) -> float or integer
@@ -2708,7 +2627,7 @@ flo_truncate(int argc, VALUE *argv, VALUE num)
* 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`,
+ * as specified by the given +ndigits+,
* which must be an
* {integer-convertible object}[rdoc-ref:implicit_conversion.rdoc@Integer-Convertible+Objects].
*
@@ -2728,7 +2647,7 @@ num_floor(int argc, VALUE *argv, VALUE num)
* 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`,
+ * as specified by the given +ndigits+,
* which must be an
* {integer-convertible object}[rdoc-ref:implicit_conversion.rdoc@Integer-Convertible+Objects].
*
@@ -3197,7 +3116,7 @@ rb_num2long(VALUE val)
{
again:
if (NIL_P(val)) {
- rb_raise(rb_eTypeError, "no implicit conversion from nil to integer");
+ rb_no_implicit_conversion(val, "Integer");
}
if (FIXNUM_P(val)) return FIX2LONG(val);
@@ -3225,7 +3144,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_no_implicit_conversion(val, "Integer");
}
if (FIXNUM_P(val)) {
@@ -3468,7 +3387,7 @@ LONG_LONG
rb_num2ll(VALUE val)
{
if (NIL_P(val)) {
- rb_raise(rb_eTypeError, "no implicit conversion from nil");
+ rb_no_implicit_conversion(val, "Integer");
}
if (FIXNUM_P(val)) return (LONG_LONG)FIX2LONG(val);
@@ -3485,11 +3404,8 @@ rb_num2ll(VALUE val)
else if (RB_BIGNUM_TYPE_P(val)) {
return rb_big2ll(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");
+ else if (val == Qfalse || val == Qtrue || RB_TYPE_P(val, T_STRING)) {
+ rb_no_implicit_conversion(val, "Integer");
}
val = rb_to_int(val);
@@ -3500,7 +3416,7 @@ unsigned LONG_LONG
rb_num2ull(VALUE val)
{
if (NIL_P(val)) {
- rb_raise(rb_eTypeError, "no implicit conversion of nil into Integer");
+ rb_no_implicit_conversion(val, "Integer");
}
else if (FIXNUM_P(val)) {
return (LONG_LONG)FIX2LONG(val); /* this is FIX2LONG, intended */
@@ -3527,6 +3443,232 @@ rb_num2ull(VALUE val)
#endif /* HAVE_LONG_LONG */
+// Conversion functions for unified 128-bit integer structures,
+// These work with or without native 128-bit integer support.
+
+#ifndef HAVE_UINT128_T
+// Helper function to build 128-bit value from bignum digits (fallback path).
+static inline void
+rb_uint128_from_bignum_digits_fallback(rb_uint128_t *result, BDIGIT *digits, size_t length)
+{
+ // Build the 128-bit value from bignum digits:
+ for (long i = length - 1; i >= 0; i--) {
+ // Shift both low and high parts:
+ uint64_t carry = result->parts.low >> (64 - (SIZEOF_BDIGIT * CHAR_BIT));
+ result->parts.low = (result->parts.low << (SIZEOF_BDIGIT * CHAR_BIT)) | digits[i];
+ result->parts.high = (result->parts.high << (SIZEOF_BDIGIT * CHAR_BIT)) | carry;
+ }
+}
+
+// Helper function to convert absolute value of negative bignum to two's complement.
+// Ruby stores negative bignums as absolute values, so we need to convert to two's complement.
+static inline void
+rb_uint128_twos_complement_negate(rb_uint128_t *value)
+{
+ if (value->parts.low == 0) {
+ value->parts.high = ~value->parts.high + 1;
+ }
+ else {
+ value->parts.low = ~value->parts.low + 1;
+ value->parts.high = ~value->parts.high + (value->parts.low == 0 ? 1 : 0);
+ }
+}
+#endif
+
+rb_uint128_t
+rb_numeric_to_uint128(VALUE x)
+{
+ rb_uint128_t result = {0};
+ if (RB_FIXNUM_P(x)) {
+ long value = RB_FIX2LONG(x);
+ if (value < 0) {
+ rb_raise(rb_eRangeError, "negative integer cannot be converted to unsigned 128-bit integer");
+ }
+#ifdef HAVE_UINT128_T
+ result.value = (uint128_t)value;
+#else
+ result.parts.low = (uint64_t)value;
+ result.parts.high = 0;
+#endif
+ return result;
+ }
+ else if (RB_BIGNUM_TYPE_P(x)) {
+ if (BIGNUM_NEGATIVE_P(x)) {
+ rb_raise(rb_eRangeError, "negative integer cannot be converted to unsigned 128-bit integer");
+ }
+ size_t length = BIGNUM_LEN(x);
+#ifdef HAVE_UINT128_T
+ if (length > roomof(SIZEOF_INT128_T, SIZEOF_BDIGIT)) {
+ rb_raise(rb_eRangeError, "bignum too big to convert into 'unsigned 128-bit integer'");
+ }
+ BDIGIT *digits = BIGNUM_DIGITS(x);
+ result.value = 0;
+ for (long i = length - 1; i >= 0; i--) {
+ result.value = (result.value << (SIZEOF_BDIGIT * CHAR_BIT)) | digits[i];
+ }
+#else
+ // Check if bignum fits in 128 bits (16 bytes)
+ if (length > roomof(16, SIZEOF_BDIGIT)) {
+ rb_raise(rb_eRangeError, "bignum too big to convert into 'unsigned 128-bit integer'");
+ }
+ BDIGIT *digits = BIGNUM_DIGITS(x);
+ rb_uint128_from_bignum_digits_fallback(&result, digits, length);
+#endif
+ return result;
+ }
+ else {
+ rb_raise(rb_eTypeError, "not an integer");
+ }
+}
+
+rb_int128_t
+rb_numeric_to_int128(VALUE x)
+{
+ rb_int128_t result = {0};
+ if (RB_FIXNUM_P(x)) {
+ long value = RB_FIX2LONG(x);
+#ifdef HAVE_UINT128_T
+ result.value = (int128_t)value;
+#else
+ if (value < 0) {
+ // Two's complement representation: for negative values, sign extend
+ // Convert to unsigned: for -1, we want all bits set
+ result.parts.low = (uint64_t)value; // This will be the two's complement representation
+ result.parts.high = UINT64_MAX; // Sign extend: all bits set for negative
+ }
+ else {
+ result.parts.low = (uint64_t)value;
+ result.parts.high = 0;
+ }
+#endif
+ return result;
+ }
+ else if (RB_BIGNUM_TYPE_P(x)) {
+ size_t length = BIGNUM_LEN(x);
+#ifdef HAVE_UINT128_T
+ if (length > roomof(SIZEOF_INT128_T, SIZEOF_BDIGIT)) {
+ rb_raise(rb_eRangeError, "bignum too big to convert into 'signed 128-bit integer'");
+ }
+ BDIGIT *digits = BIGNUM_DIGITS(x);
+ uint128_t unsigned_result = 0;
+ for (long i = length - 1; i >= 0; i--) {
+ unsigned_result = (unsigned_result << (SIZEOF_BDIGIT * CHAR_BIT)) | digits[i];
+ }
+ if (BIGNUM_NEGATIVE_P(x)) {
+ // Convert from two's complement
+ // Maximum negative value is 2^127
+ if (unsigned_result > ((uint128_t)1 << 127)) {
+ rb_raise(rb_eRangeError, "bignum too big to convert into 'signed 128-bit integer'");
+ }
+ result.value = -(int128_t)(unsigned_result - 1) - 1;
+ }
+ else {
+ // Maximum positive value is 2^127 - 1
+ if (unsigned_result > (((uint128_t)1 << 127) - 1)) {
+ rb_raise(rb_eRangeError, "bignum too big to convert into 'signed 128-bit integer'");
+ }
+ result.value = (int128_t)unsigned_result;
+ }
+#else
+ if (length > roomof(16, SIZEOF_BDIGIT)) {
+ rb_raise(rb_eRangeError, "bignum too big to convert into 'signed 128-bit integer'");
+ }
+ BDIGIT *digits = BIGNUM_DIGITS(x);
+ rb_uint128_t unsigned_result = {0};
+ rb_uint128_from_bignum_digits_fallback(&unsigned_result, digits, length);
+ if (BIGNUM_NEGATIVE_P(x)) {
+ // Check if value fits in signed 128-bit (max negative is 2^127)
+ uint64_t max_neg_high = (uint64_t)1 << 63;
+ if (unsigned_result.parts.high > max_neg_high || (unsigned_result.parts.high == max_neg_high && unsigned_result.parts.low > 0)) {
+ rb_raise(rb_eRangeError, "bignum too big to convert into 'signed 128-bit integer'");
+ }
+ // Convert from absolute value to two's complement (Ruby stores negative as absolute value)
+ rb_uint128_twos_complement_negate(&unsigned_result);
+ result.parts.low = unsigned_result.parts.low;
+ result.parts.high = (int64_t)unsigned_result.parts.high; // Sign extend
+ }
+ else {
+ // Check if value fits in signed 128-bit (max positive is 2^127 - 1)
+ // Max positive: high = 0x7FFFFFFFFFFFFFFF, low = 0xFFFFFFFFFFFFFFFF
+ uint64_t max_pos_high = ((uint64_t)1 << 63) - 1;
+ if (unsigned_result.parts.high > max_pos_high) {
+ rb_raise(rb_eRangeError, "bignum too big to convert into 'signed 128-bit integer'");
+ }
+ result.parts.low = unsigned_result.parts.low;
+ result.parts.high = unsigned_result.parts.high;
+ }
+#endif
+ return result;
+ }
+ else {
+ rb_raise(rb_eTypeError, "not an integer");
+ }
+}
+
+VALUE
+rb_uint128_to_numeric(rb_uint128_t n)
+{
+#ifdef HAVE_UINT128_T
+ if (n.value <= (uint128_t)RUBY_FIXNUM_MAX) {
+ return LONG2FIX((long)n.value);
+ }
+ return rb_uint128t2big(n.value);
+#else
+ // If high part is zero and low part fits in fixnum
+ if (n.parts.high == 0 && n.parts.low <= (uint64_t)RUBY_FIXNUM_MAX) {
+ return LONG2FIX((long)n.parts.low);
+ }
+ // Convert to bignum by building it from the two 64-bit parts
+ VALUE bignum = rb_ull2big(n.parts.low);
+ if (n.parts.high > 0) {
+ VALUE high_bignum = rb_ull2big(n.parts.high);
+ // Multiply high part by 2^64 and add to low part
+ VALUE shifted_value = rb_int_lshift(high_bignum, INT2FIX(64));
+ bignum = rb_int_plus(bignum, shifted_value);
+ }
+ return bignum;
+#endif
+}
+
+VALUE
+rb_int128_to_numeric(rb_int128_t n)
+{
+#ifdef HAVE_UINT128_T
+ if (FIXABLE(n.value)) {
+ return LONG2FIX((long)n.value);
+ }
+ return rb_int128t2big(n.value);
+#else
+ int64_t high = (int64_t)n.parts.high;
+ // If it's a small positive value that fits in fixnum
+ if (high == 0 && n.parts.low <= (uint64_t)RUBY_FIXNUM_MAX) {
+ return LONG2FIX((long)n.parts.low);
+ }
+ // Check if it's negative (high bit of high part is set)
+ if (high < 0) {
+ // Negative value - convert from two's complement to absolute value
+ rb_uint128_t unsigned_value = {0};
+ if (n.parts.low == 0) {
+ unsigned_value.parts.low = 0;
+ unsigned_value.parts.high = ~n.parts.high + 1;
+ }
+ else {
+ unsigned_value.parts.low = ~n.parts.low + 1;
+ unsigned_value.parts.high = ~n.parts.high + (unsigned_value.parts.low == 0 ? 1 : 0);
+ }
+ VALUE bignum = rb_uint128_to_numeric(unsigned_value);
+ return rb_int_uminus(bignum);
+ }
+ else {
+ // Positive value
+ union uint128_int128_conversion conversion = {
+ .int128 = n
+ };
+ return rb_uint128_to_numeric(conversion.uint128);
+ }
+#endif
+}
+
/********************************************************************
*
* Document-class: Integer
@@ -3549,9 +3691,9 @@ 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].
+ * {class Numeric}[rdoc-ref:Numeric@Whats+Here]
+ * and {class Object}[rdoc-ref:Object@Whats+Here].
+ * - Includes {module Comparable}[rdoc-ref:Comparable@Whats+Here].
*
* Here, class \Integer provides methods for:
*
@@ -3905,6 +4047,11 @@ rb_int_uminus(VALUE num)
}
}
+/* ruby_decimal_digit_pairs is defined in bignum.c and declared in
+ * internal/bignum.h. See there for the rationale of the 2-digit
+ * lookup-table itoa optimisation; both rb_fix2str here and big2str_2bdigits
+ * in bignum.c consume it. */
+
VALUE
rb_fix2str(VALUE x, int base)
{
@@ -3937,9 +4084,34 @@ rb_fix2str(VALUE x, int base)
else {
u = val;
}
- do {
- *--b = ruby_digitmap[(int)(u % base)];
- } while (u /= base);
+ if (base == 10) {
+ /* Emit two digits per iteration from a precomputed table. The
+ * compiler lowers `u % 100` and `u / 100` to a single multiply +
+ * shift, so each iteration costs roughly one multiply, one shift,
+ * and two stores. About 2x fewer iterations than the classic
+ * per-digit loop for multi-digit inputs. */
+ while (u >= 100) {
+ unsigned long idx = (u % 100) * 2;
+ u /= 100;
+ b -= 2;
+ b[0] = ruby_decimal_digit_pairs[idx];
+ b[1] = ruby_decimal_digit_pairs[idx + 1];
+ }
+ if (u >= 10) {
+ unsigned long idx = u * 2;
+ b -= 2;
+ b[0] = ruby_decimal_digit_pairs[idx];
+ b[1] = ruby_decimal_digit_pairs[idx + 1];
+ }
+ else {
+ *--b = (char)('0' + u);
+ }
+ }
+ else {
+ do {
+ *--b = ruby_digitmap[(int)(u % base)];
+ } while (u /= base);
+ }
if (neg) {
*--b = '-';
}
@@ -4030,17 +4202,20 @@ rb_fix_plus(VALUE x, VALUE y)
/*
* call-seq:
- * self + numeric -> numeric_result
+ * self + other -> numeric
*
- * Performs addition:
+ * Returns the sum of +self+ and +other+:
*
- * 2 + 2 # => 4
- * -2 + 2 # => 0
- * -2 + -2 # => -4
- * 2 + 2.0 # => 4.0
- * 2 + Rational(2, 1) # => (4/1)
- * 2 + Complex(2, 0) # => (4+0i)
+ * 1 + 1 # => 2
+ * 1 + -1 # => 0
+ * 1 + 0 # => 1
+ * 1 + -2 # => -1
+ * 1 + Complex(1, 0) # => (2+0i)
+ * 1 + Rational(1, 1) # => (2/1)
*
+ * For a computation involving Floats, the result may be inexact (see Float#+):
+ *
+ * 1 + 3.14 # => 4.140000000000001
*/
VALUE
@@ -4075,9 +4250,9 @@ fix_minus(VALUE x, VALUE y)
/*
* call-seq:
- * self - numeric -> numeric_result
+ * self - other -> numeric
*
- * Performs subtraction:
+ * Returns the difference of +self+ and +other+:
*
* 4 - 2 # => 2
* -4 - 2 # => -6
@@ -4131,16 +4306,17 @@ fix_mul(VALUE x, VALUE y)
/*
* call-seq:
- * self * numeric -> numeric_result
+ * self * other -> numeric
*
- * Performs multiplication:
+ * Returns the numeric product of +self+ and +other+:
*
* 4 * 2 # => 8
- * 4 * -2 # => -8
* -4 * 2 # => -8
+ * 4 * -2 # => -8
* 4 * 2.0 # => 8.0
* 4 * Rational(1, 3) # => (4/3)
* 4 * Complex(2, 0) # => (8+0i)
+ *
*/
VALUE
@@ -4155,16 +4331,24 @@ rb_int_mul(VALUE x, VALUE y)
return rb_num_coerce_bin(x, y, '*');
}
+static bool
+accurate_in_double(long i)
+{
+#if SIZEOF_LONG * CHAR_BIT > DBL_MANT_DIG
+ return ((i < 0 ? -i : i) < (1L << DBL_MANT_DIG));
+#else
+ return true;
+#endif
+}
+
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)) {
+ if (!accurate_in_double(iy)) {
return rb_big_fdiv_double(rb_int2big(FIX2LONG(x)), rb_int2big(iy));
}
-#endif
return double_div_double(FIX2LONG(x), iy);
}
else if (RB_BIGNUM_TYPE_P(y)) {
@@ -4178,10 +4362,29 @@ fix_fdiv_double(VALUE x, VALUE y)
}
}
+static bool
+int_accurate_in_double(VALUE n)
+{
+ if (FIXNUM_P(n)) {
+ return accurate_in_double(FIX2LONG(n));
+ }
+ RUBY_ASSERT(RB_TYPE_P(n, T_BIGNUM));
+#if SIZEOF_LONG * CHAR_BIT <= DBL_MANT_DIG
+ int nlz;
+ size_t size = rb_absint_size(n, &nlz);
+ const size_t mant_size = roomof(DBL_MANT_DIG, CHAR_BIT);
+ if (size < mant_size) return true;
+ if (size > mant_size) return false;
+ if ((size_t)nlz >= (CHAR_BIT * mant_size - DBL_MANT_DIG)) return true;
+#endif
+ return false;
+}
+
double
rb_int_fdiv_double(VALUE x, VALUE y)
{
- if (RB_INTEGER_TYPE_P(y) && !FIXNUM_ZERO_P(y)) {
+ if (RB_INTEGER_TYPE_P(y) && !FIXNUM_ZERO_P(y) &&
+ !(int_accurate_in_double(x) && int_accurate_in_double(y))) {
VALUE gcd = rb_gcd(x, y);
if (!FIXNUM_ZERO_P(gcd) && gcd != INT2FIX(1)) {
x = rb_int_idiv(x, gcd);
@@ -4263,16 +4466,18 @@ fix_div(VALUE x, VALUE y)
/*
* call-seq:
- * self / numeric -> numeric_result
+ * self / other -> numeric
+ *
+ * Returns the quotient of +self+ and +other+.
*
- * Performs division; for integer +numeric+, truncates the result to an integer:
+ * For integer +other+, truncates the result to an integer:
*
* 4 / 3 # => 1
* 4 / -3 # => -2
* -4 / 3 # => -2
* -4 / -3 # => 1
*
- * For other +numeric+, returns non-integer result:
+ * For non-integer +other+, returns a non-integer result:
*
* 4 / 3.0 # => 1.3333333333333333
* 4 / Rational(3, 1) # => (4/3)
@@ -4349,9 +4554,9 @@ fix_mod(VALUE x, VALUE y)
/*
* call-seq:
- * self % other -> real_number
+ * self % other -> real_numeric
*
- * Returns +self+ modulo +other+ as a real number.
+ * Returns +self+ modulo +other+ as a real numeric (\Integer, \Float, or \Rational).
*
* For integer +n+ and real number +r+, these expressions are equivalent:
*
@@ -4500,9 +4705,9 @@ rb_int_divmod(VALUE x, VALUE y)
/*
* call-seq:
- * self ** numeric -> numeric_result
+ * self ** exponent -> numeric
*
- * Raises +self+ to the power of +numeric+:
+ * Returns +self+ raised to the power +exponent+:
*
* 2 ** 3 # => 8
* 2 ** -3 # => (1/8)
@@ -4623,17 +4828,47 @@ fix_pow(VALUE x, VALUE y)
/*
* call-seq:
- * self ** numeric -> numeric_result
- *
- * Raises +self+ to the power of +numeric+:
- *
- * 2 ** 3 # => 8
- * 2 ** -3 # => (1/8)
- * -2 ** 3 # => -8
- * -2 ** -3 # => (-1/8)
- * 2 ** 3.3 # => 9.849155306759329
- * 2 ** Rational(3, 1) # => (8/1)
- * 2 ** Complex(3, 0) # => (8+0i)
+ * self ** exponent -> numeric
+ *
+ * Returns +self+ raised to the power +exponent+:
+ *
+ * # Result for non-negative Integer exponent is Integer.
+ * 2 ** 0 # => 1
+ * 2 ** 1 # => 2
+ * 2 ** 2 # => 4
+ * 2 ** 3 # => 8
+ * -2 ** 3 # => -8
+ * # Result for negative Integer exponent is Rational, not Float.
+ * 2 ** -3 # => (1/8)
+ * -2 ** -3 # => (-1/8)
+ *
+ * # Result for Float exponent is Float.
+ * 2 ** 0.0 # => 1.0
+ * 2 ** 1.0 # => 2.0
+ * 2 ** 2.0 # => 4.0
+ * 2 ** 3.0 # => 8.0
+ * -2 ** 3.0 # => -8.0
+ * 2 ** -3.0 # => 0.125
+ * -2 ** -3.0 # => -0.125
+ *
+ * # Result for non-negative Complex exponent is Complex with Integer parts.
+ * 2 ** Complex(0, 0) # => (1+0i)
+ * 2 ** Complex(1, 0) # => (2+0i)
+ * 2 ** Complex(2, 0) # => (4+0i)
+ * 2 ** Complex(3, 0) # => (8+0i)
+ * -2 ** Complex(3, 0) # => (-8+0i)
+ * # Result for negative Complex exponent is Complex with Rational parts.
+ * 2 ** Complex(-3, 0) # => ((1/8)+(0/1)*i)
+ * -2 ** Complex(-3, 0) # => ((-1/8)+(0/1)*i)
+ *
+ * # Result for Rational exponent is Rational.
+ * 2 ** Rational(0, 1) # => (1/1)
+ * 2 ** Rational(1, 1) # => (2/1)
+ * 2 ** Rational(2, 1) # => (4/1)
+ * 2 ** Rational(3, 1) # => (8/1)
+ * -2 ** Rational(3, 1) # => (-8/1)
+ * 2 ** Rational(-3, 1) # => (1/8)
+ * -2 ** Rational(-3, 1) # => (-1/8)
*
*/
VALUE
@@ -4686,7 +4921,7 @@ fix_equal(VALUE x, VALUE y)
* call-seq:
* self == other -> true or false
*
- * Returns +true+ if +self+ is numerically equal to +other+; +false+ otherwise.
+ * Returns whether +self+ is numerically equal to +other+:
*
* 1 == 2 #=> false
* 1 == 1.0 #=> true
@@ -4732,28 +4967,29 @@ fix_cmp(VALUE x, VALUE y)
/*
* call-seq:
- * self <=> other -> -1, 0, +1, or nil
+ * self <=> other -> -1, 0, 1, or nil
+ *
+ * Compares +self+ and +other+.
*
* Returns:
*
- * - -1, if +self+ is less than +other+.
- * - 0, if +self+ is equal to +other+.
- * - 1, if +self+ is greater then +other+.
+ * - +-1+, if +self+ is less than +other+.
+ * - +0+, if +self+ is equal to +other+.
+ * - +1+, if +self+ is greater then +other+.
* - +nil+, if +self+ and +other+ are incomparable.
*
* Examples:
*
* 1 <=> 2 # => -1
* 1 <=> 1 # => 0
- * 1 <=> 0 # => 1
- * 1 <=> 'foo' # => nil
- *
* 1 <=> 1.0 # => 0
* 1 <=> Rational(1, 1) # => 0
* 1 <=> Complex(1, 0) # => 0
+ * 1 <=> 0 # => 1
+ * 1 <=> 'foo' # => nil
*
- * This method is the basis for comparisons in module Comparable.
- *
+ * \Class \Integer includes module Comparable,
+ * each of whose methods uses Integer#<=> for comparison.
*/
VALUE
@@ -4791,7 +5027,8 @@ fix_gt(VALUE x, VALUE y)
* call-seq:
* self > other -> true or false
*
- * Returns +true+ if the value of +self+ is greater than that of +other+:
+ * Returns whether the value of +self+ is greater than the value of +other+;
+ * +other+ must be numeric, but may not be Complex:
*
* 1 > 0 # => true
* 1 > 1 # => false
@@ -4835,10 +5072,10 @@ fix_ge(VALUE x, VALUE y)
/*
* call-seq:
- * self >= real -> true or false
+ * self >= other -> true or false
*
- * Returns +true+ if the value of +self+ is greater than or equal to
- * that of +other+:
+ * Returns whether the value of +self+ is greater than or equal to the value of +other+;
+ * +other+ must be numeric, but may not be Complex:
*
* 1 >= 0 # => true
* 1 >= 1 # => true
@@ -4883,7 +5120,8 @@ fix_lt(VALUE x, VALUE y)
* call-seq:
* self < other -> true or false
*
- * Returns +true+ if the value of +self+ is less than that of +other+:
+ * Returns whether the value of +self+ is less than the value of +other+;
+ * +other+ must be numeric, but may not be Complex:
*
* 1 < 0 # => false
* 1 < 1 # => false
@@ -4891,8 +5129,6 @@ fix_lt(VALUE x, VALUE y)
* 1 < 0.5 # => false
* 1 < Rational(1, 2) # => false
*
- * Raises an exception if the comparison cannot be made.
- *
*/
static VALUE
@@ -4927,10 +5163,10 @@ fix_le(VALUE x, VALUE y)
/*
* call-seq:
- * self <= real -> true or false
+ * self <= other -> true or false
*
- * Returns +true+ if the value of +self+ is less than or equal to
- * that of +other+:
+ * Returns whether the value of +self+ is less than or equal to the value of +other+;
+ * +other+ must be numeric, but may not be Complex:
*
* 1 <= 0 # => false
* 1 <= 1 # => true
@@ -5553,7 +5789,7 @@ rb_int_digits_bigbase(VALUE num, VALUE base)
}
bases = rb_ary_new();
- for (VALUE b = base; int_lt(b, num) == Qtrue; b = rb_int_mul(b, b)) {
+ for (VALUE b = base; int_le(b, num) == Qtrue; b = rb_int_mul(b, b)) {
rb_ary_push(bases, b);
}
digits = rb_ary_new_from_args(1, num);
@@ -5718,7 +5954,7 @@ int_downto(VALUE from, VALUE to)
rb_yield(i);
i = rb_funcall(i, '-', 1, INT2FIX(1));
}
- if (NIL_P(c)) rb_cmperr(i, to);
+ ensure_cmp(c, i, to);
}
return from;
}
@@ -6197,8 +6433,8 @@ int_s_try_convert(VALUE self, VALUE num)
*
* First, what's elsewhere. Class \Numeric:
*
- * - Inherits from {class Object}[rdoc-ref:Object@What-27s+Here].
- * - Includes {module Comparable}[rdoc-ref:Comparable@What-27s+Here].
+ * - Inherits from {class Object}[rdoc-ref:Object@Whats+Here].
+ * - Includes {module Comparable}[rdoc-ref:Comparable@Whats+Here].
*
* Here, class \Numeric provides methods for:
*
@@ -6455,7 +6691,7 @@ Init_Numeric(void)
*
* If the platform supports denormalized numbers,
* there are numbers between zero and Float::MIN.
- * 0.0.next_float returns the smallest positive floating point number
+ * +0.0.next_float+ returns the smallest positive floating point number
* including denormalized numbers.
*/
rb_define_const(rb_cFloat, "MIN", DBL2NUM(DBL_MIN));
diff --git a/numeric.rb b/numeric.rb
index 552a3dd687..306561943d 100644
--- a/numeric.rb
+++ b/numeric.rb
@@ -93,9 +93,14 @@ end
class Integer
# call-seq:
- # -int -> integer
+ # -self -> integer
+ #
+ # Returns +self+, negated:
+ #
+ # -1 # => -1
+ # -(-1) # => 1
+ # -0 # => 0
#
- # Returns +self+, negated.
def -@
Primitive.attr! :leaf
Primitive.cexpr! 'rb_int_uminus(self)'
@@ -373,9 +378,13 @@ class Float
alias magnitude abs
# call-seq:
- # -float -> float
+ # -self -> float
+ #
+ # Returns +self+, negated:
#
- # Returns +self+, negated.
+ # -3.14 # => -3.14
+ # -(-3.14) # => 3.14
+ # -0.0 # => -0.0
#
def -@
Primitive.attr! :leaf
diff --git a/object.c b/object.c
index 28e6125421..2e962b1c3c 100644
--- a/object.c
+++ b/object.c
@@ -46,10 +46,9 @@
/* 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).
+ * 4: ROBJECT_HEAP
+ * The object has its instance variables in a separately allocated buffer.
+ * This can be either a flat buffer of reference, or an st_table for complex objects.
*/
/*!
@@ -91,11 +90,6 @@ static ID id_instance_variables_to_inspect;
/*! \endcond */
-size_t
-rb_obj_embedded_size(uint32_t fields_count)
-{
- return offsetof(struct RObject, as.ary) + (sizeof(VALUE) * fields_count);
-}
VALUE
rb_obj_hide(VALUE obj)
@@ -115,34 +109,6 @@ rb_obj_reveal(VALUE obj, VALUE klass)
return obj;
}
-VALUE
-rb_class_allocate_instance(VALUE klass)
-{
- uint32_t index_tbl_num_entries = RCLASS_MAX_IV_COUNT(klass);
-
- 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(RSHAPE_TYPE_P(RBASIC_SHAPE_ID(obj), SHAPE_ROOT));
-
- RBASIC_SET_SHAPE_ID(obj, rb_shape_root(rb_gc_heap_id_for_size(size)));
-
-#if RUBY_DEBUG
- RUBY_ASSERT(!rb_shape_obj_too_complex_p(obj));
- VALUE *ptr = ROBJECT_FIELDS(obj);
- for (size_t i = 0; i < ROBJECT_FIELDS_CAPACITY(obj); i++) {
- ptr[i] = Qundef;
- }
-#endif
-
- return obj;
-}
VALUE
rb_obj_setup(VALUE obj, VALUE klass, VALUE type)
@@ -161,7 +127,7 @@ rb_obj_setup(VALUE obj, VALUE klass, VALUE type)
*
* Returns +true+ or +false+.
*
- * Like Object#==, if +object+ is an instance of Object
+ * Like Object#==, if +other+ is an instance of \Object
* (and not an instance of one of its many subclasses).
*
* This method is commonly overridden by those subclasses,
@@ -199,14 +165,18 @@ rb_eql(VALUE obj1, VALUE obj2)
/**
* call-seq:
- * obj == other -> true or false
- * obj.equal?(other) -> true or false
- * obj.eql?(other) -> true or false
+ * self == other -> true or false
+ * equal?(other) -> true or false
+ * eql?(other) -> true or false
+ *
+ * Returns whether +self+ and +other+ are the same object:
*
- * Equality --- At the Object level, #== returns <code>true</code>
- * only if +obj+ and +other+ are the same object. Typically, this
- * method is overridden in descendant classes to provide
- * class-specific meaning.
+ * object = Object.new
+ * object == object # => true
+ * object == Object.new # => false
+ *
+ * Here in class \Object, #==, #equal?, and #eql? are the same method.
+ * A subclass may override #== to provide class-specific meaning.
*
* Unlike #==, the #equal? method should never be overridden by
* subclasses as it is used to determine object identity (that is,
@@ -279,12 +249,38 @@ rb_obj_not_equal(VALUE obj1, VALUE obj2)
return rb_obj_not(result);
}
+static inline VALUE
+fake_class_p(VALUE klass)
+{
+ RUBY_ASSERT(klass);
+ RUBY_ASSERT(RB_TYPE_P(klass, T_CLASS) || RB_TYPE_P(klass, T_MODULE) || RB_TYPE_P(klass, T_ICLASS));
+ STATIC_ASSERT(t_iclass_overlap_t_class, !(T_CLASS & T_ICLASS));
+ STATIC_ASSERT(t_iclass_overlap_t_module, !(T_MODULE & T_ICLASS));
+
+ return FL_TEST_RAW(klass, T_ICLASS | FL_SINGLETON);
+}
+
+static inline VALUE
+class_real(VALUE cl)
+{
+ RUBY_ASSERT(cl);
+
+ // TODO: In the future we should only call this with T_CLASS
+ RUBY_ASSERT(RB_TYPE_P(cl, T_CLASS) || RB_TYPE_P(cl, T_ICLASS) || RB_TYPE_P(cl, T_MODULE));
+
+ while (RB_UNLIKELY(fake_class_p(cl))) {
+ // All paths through super in any box will eventually result in the
+ // same class.
+ cl = RCLASSEXT_SUPER(RCLASS_EXT_PRIME(cl));
+ }
+ return cl;
+}
+
VALUE
rb_class_real(VALUE cl)
{
- while (cl &&
- (RCLASS_SINGLETON_P(cl) || BUILTIN_TYPE(cl) == T_ICLASS)) {
- cl = RCLASS_SUPER(cl);
+ if (cl) {
+ cl = class_real(cl);
}
return cl;
}
@@ -292,7 +288,17 @@ rb_class_real(VALUE cl)
VALUE
rb_obj_class(VALUE obj)
{
- return rb_class_real(CLASS_OF(obj));
+ VALUE cl = CLASS_OF(obj);
+ if (cl) {
+ cl = class_real(cl);
+ }
+ return cl;
+}
+
+static inline VALUE
+rb_obj_class_must(VALUE obj)
+{
+ return class_real(CLASS_OF(obj));
}
/*
@@ -322,8 +328,8 @@ rb_obj_singleton_class(VALUE obj)
void
rb_obj_copy_ivar(VALUE dest, VALUE obj)
{
- RUBY_ASSERT(!RB_TYPE_P(obj, T_CLASS) && !RB_TYPE_P(obj, T_MODULE));
- RUBY_ASSERT(BUILTIN_TYPE(dest) == BUILTIN_TYPE(obj));
+ RUBY_ASSERT(RB_TYPE_P(obj, T_OBJECT));
+ RUBY_ASSERT(RB_TYPE_P(dest, T_OBJECT));
unsigned long src_num_ivs = rb_ivar_count(obj);
if (!src_num_ivs) {
@@ -332,7 +338,7 @@ rb_obj_copy_ivar(VALUE dest, VALUE obj)
shape_id_t src_shape_id = RBASIC_SHAPE_ID(obj);
- if (rb_shape_too_complex_p(src_shape_id)) {
+ if (rb_shape_complex_p(src_shape_id)) {
rb_shape_copy_complex_ivars(dest, obj, src_shape_id, ROBJECT_FIELDS_HASH(obj));
return;
}
@@ -341,10 +347,10 @@ rb_obj_copy_ivar(VALUE dest, VALUE obj)
RUBY_ASSERT(RSHAPE_TYPE_P(initial_shape_id, SHAPE_ROOT));
shape_id_t dest_shape_id = rb_shape_rebuild(initial_shape_id, src_shape_id);
- if (UNLIKELY(rb_shape_too_complex_p(dest_shape_id))) {
+ if (UNLIKELY(rb_shape_complex_p(dest_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_init_too_complex(dest, table);
+ rb_obj_init_complex(dest, table);
return;
}
@@ -362,7 +368,7 @@ rb_obj_copy_ivar(VALUE dest, VALUE obj)
}
rb_shape_copy_fields(dest, dest_buf, dest_shape_id, src_buf, src_shape_id);
- rb_obj_set_shape_id(dest, dest_shape_id);
+ RBASIC_SET_SHAPE_ID(dest, dest_shape_id);
}
static void
@@ -380,7 +386,7 @@ init_copy(VALUE dest, VALUE obj)
break;
case T_CLASS:
case T_MODULE:
- // noop: handled in class.c: rb_mod_init_copy
+ rb_mod_init_copy(dest, obj);
break;
case T_OBJECT:
rb_obj_copy_ivar(dest, obj);
@@ -495,8 +501,8 @@ rb_obj_clone_setup(VALUE obj, VALUE clone, VALUE kwfreeze)
}
if (RB_OBJ_FROZEN(obj)) {
- shape_id_t next_shape_id = rb_shape_transition_frozen(clone);
- rb_obj_set_shape_id(clone, next_shape_id);
+ shape_id_t next_shape_id = rb_obj_shape_transition_frozen(clone);
+ RBASIC_SET_SHAPE_ID(clone, next_shape_id);
}
break;
case Qtrue: {
@@ -763,7 +769,7 @@ inspect_obj(VALUE obj, VALUE a, int recur)
rb_str_cat2(str, " ...");
}
else {
- rb_ivar_foreach(obj, inspect_i, a);
+ rb_ivar_foreach_buffered(obj, inspect_i, a);
}
rb_str_cat2(str, ">");
RSTRING_PTR(str)[0] = '#';
@@ -822,14 +828,21 @@ rb_obj_inspect(VALUE obj)
{
VALUE ivars = rb_check_funcall(obj, id_instance_variables_to_inspect, 0, 0);
st_index_t n = 0;
- if (UNDEF_P(ivars)) {
+ if (UNDEF_P(ivars) || NIL_P(ivars)) {
n = rb_ivar_count(obj);
ivars = Qnil;
}
- else if (!NIL_P(ivars)) {
- Check_Type(ivars, T_ARRAY);
+ else if (RB_TYPE_P(ivars, T_ARRAY)) {
n = RARRAY_LEN(ivars);
}
+ else {
+ rb_raise(
+ rb_eTypeError,
+ "Expected #instance_variables_to_inspect to return an Array or nil, but it returned %"PRIsVALUE,
+ rb_obj_class(ivars)
+ );
+ }
+
if (n > 0) {
VALUE c = rb_class_name(CLASS_OF(obj));
VALUE args[2] = {
@@ -843,6 +856,13 @@ rb_obj_inspect(VALUE obj)
}
}
+/* :nodoc: */
+static VALUE
+rb_obj_instance_variables_to_inspect(VALUE obj)
+{
+ return Qnil;
+}
+
static VALUE
class_or_module_required(VALUE c)
{
@@ -1535,10 +1555,10 @@ rb_true_to_s(VALUE obj)
/*
- * call-seq:
- * true & object -> true or false
+ * call-seq:
+ * true & object -> true or false
*
- * Returns +false+ if +object+ is +false+ or +nil+, +true+ otherwise:
+ * Returns +false+ if +object+ is +false+ or +nil+, +true+ otherwise:
*
* true & Object.new # => true
* true & false # => false
@@ -1721,21 +1741,33 @@ rb_obj_not_match(VALUE obj1, VALUE obj2)
/*
* call-seq:
- * obj <=> other -> 0 or nil
+ * self <=> other -> 0 or nil
+ *
+ * Compares +self+ and +other+.
+ *
+ * Returns:
+ *
+ * - +0+, if +self+ and +other+ are the same object,
+ * or if <tt>self == other</tt>.
+ * - +nil+, otherwise.
+ *
+ * Examples:
+ *
+ * o = Object.new
+ * o <=> o # => 0
+ * o <=> o.dup # => nil
*
- * Returns 0 if +obj+ and +other+ are the same object
- * or <code>obj == other</code>, otherwise nil.
+ * A class that includes module Comparable
+ * should override this method by defining an instance method that:
*
- * The #<=> is used by various methods to compare objects, for example
- * Enumerable#sort, Enumerable#max etc.
+ * - Take one argument, +other+.
+ * - Returns:
*
- * Your implementation of #<=> should return one of the following values: -1, 0,
- * 1 or nil. -1 means self is smaller than other. 0 means self is equal to other.
- * 1 means self is bigger than other. Nil means the two values could not be
- * compared.
+ * - +-1+, if +self+ is less than +other+.
+ * - +0+, if +self+ is equal to +other+.
+ * - +1+, if +self+ is greater than +other+.
+ * - +nil+, if the two values are incommensurate.
*
- * When you define #<=>, you can include Comparable to gain the
- * methods #<=, #<, #==, #>=, #> and #between?.
*/
static VALUE
rb_obj_cmp(VALUE obj1, VALUE obj2)
@@ -1835,11 +1867,12 @@ rb_mod_freeze(VALUE mod)
/*
* call-seq:
- * mod === obj -> true or false
+ * self === other -> true or false
*
- * Case Equality---Returns <code>true</code> if <i>obj</i> is an
- * instance of <i>mod</i> or an instance of one of <i>mod</i>'s descendants.
- * Of limited use for modules, but can be used in <code>case</code> statements
+ * Returns whether +other+ is an instance of +self+,
+ * or is an instance of a subclass of +self+.
+ *
+ * Of limited use for modules, but can be used in +case+ statements
* to classify objects by class.
*/
@@ -1851,13 +1884,27 @@ rb_mod_eqq(VALUE mod, VALUE arg)
/*
* call-seq:
- * mod <= other -> true, false, or nil
+ * self <= other -> true, false, or nil
+ *
+ * Compares +self+ and +other+ with respect to ancestry and inclusion.
+ *
+ * Returns +nil+ if there is no such relationship between the two:
+ *
+ * Array <= Hash # => nil
+ *
+ * Otherwise, returns +true+ if +other+ is an ancestor of +self+,
+ * or if +self+ includes +other+,
+ * or if the two are the same:
+ *
+ * File <= IO # => true # IO is an ancestor of File.
+ * Array <= Enumerable # => true # Array includes Enumerable.
+ * Array <= Array # => true
+ *
+ * Otherwise, returns +false+:
+ *
+ * IO <= File # => false
+ * Enumerable <= Array # => false
*
- * Returns true if <i>mod</i> is a subclass of <i>other</i> or
- * is the same as <i>other</i>. Returns
- * <code>nil</code> if there's no relationship between the two.
- * (Think of the relationship in terms of the class definition:
- * "class A < B" implies "A < B".)
*/
VALUE
@@ -1903,14 +1950,26 @@ rb_class_inherited_p(VALUE mod, VALUE arg)
/*
* call-seq:
- * mod < other -> true, false, or nil
+ * self < other -> true, false, or nil
+ *
+ * Returns +true+ if +self+ is a descendant of +other+
+ * (+self+ is a subclass of +other+ or +self+ includes +other+):
+ *
+ * Float < Numeric # => true
+ * Array < Enumerable # => true
+ *
+ * Returns +false+ if +self+ is an ancestor of +other+
+ * (+self+ is a superclass of +other+ or +self+ is included in +other+) or
+ * if +self+ is the same as +other+:
*
- * Returns true if <i>mod</i> is a subclass of <i>other</i>. Returns
- * <code>false</code> if <i>mod</i> is the same as <i>other</i>
- * or <i>mod</i> is an ancestor of <i>other</i>.
- * Returns <code>nil</code> if there's no relationship between the two.
- * (Think of the relationship in terms of the class definition:
- * "class A < B" implies "A < B".)
+ * Numeric < Float # => false
+ * Enumerable < Array # => false
+ * Float < Float # => false
+ *
+ * Returns +nil+ if there is no relationship between the two:
+ *
+ * Float < Hash # => nil
+ * Enumerable < String # => nil
*
*/
@@ -1924,13 +1983,28 @@ rb_mod_lt(VALUE mod, VALUE arg)
/*
* call-seq:
- * mod >= other -> true, false, or nil
+ * self >= other -> true, false, or nil
+ *
+ * Compares +self+ and +other+ with respect to ancestry and inclusion.
+ *
+ * Returns +true+ if +self+ is an ancestor of +other+
+ * (+self+ is a superclass of +other+ or +self+ is included in +other+) or
+ * if +self+ is the same as +other+:
*
- * Returns true if <i>mod</i> is an ancestor of <i>other</i>, or the
- * two modules are the same. Returns
- * <code>nil</code> if there's no relationship between the two.
- * (Think of the relationship in terms of the class definition:
- * "class A < B" implies "B > A".)
+ * Numeric >= Float # => true
+ * Enumerable >= Array # => true
+ * Float >= Float # => true
+ *
+ * Returns +false+ if +self+ is a descendant of +other+
+ * (+self+ is a subclass of +other+ or +self+ includes +other+):
+ *
+ * Float >= Numeric # => false
+ * Array >= Enumerable # => false
+ *
+ * Returns +nil+ if there is no relationship between the two:
+ *
+ * Float >= Hash # => nil
+ * Enumerable >= String # => nil
*
*/
@@ -1946,14 +2020,26 @@ rb_mod_ge(VALUE mod, VALUE arg)
/*
* call-seq:
- * mod > other -> true, false, or nil
+ * self > other -> true, false, or nil
+ *
+ * Returns +true+ if +self+ is an ancestor of +other+
+ * (+self+ is a superclass of +other+ or +self+ is included in +other+):
+ *
+ * Numeric > Float # => true
+ * Enumerable > Array # => true
+ *
+ * Returns +false+ if +self+ is a descendant of +other+
+ * (+self+ is a subclass of +other+ or +self+ includes +other+) or
+ * if +self+ is the same as +other+:
+ *
+ * Float > Numeric # => false
+ * Array > Enumerable # => false
+ * Float > Float # => false
*
- * Returns true if <i>mod</i> is an ancestor of <i>other</i>. Returns
- * <code>false</code> if <i>mod</i> is the same as <i>other</i>
- * or <i>mod</i> is a descendant of <i>other</i>.
- * Returns <code>nil</code> if there's no relationship between the two.
- * (Think of the relationship in terms of the class definition:
- * "class A < B" implies "B > A".)
+ * Returns +nil+ if there is no relationship between the two:
+ *
+ * Float > Hash # => nil
+ * Enumerable > String # => nil
*
*/
@@ -1966,14 +2052,30 @@ rb_mod_gt(VALUE mod, VALUE arg)
/*
* call-seq:
- * module <=> other_module -> -1, 0, +1, or nil
+ * self <=> other -> -1, 0, 1, or nil
+ *
+ * Compares +self+ and +other+.
+ *
+ * Returns:
+ *
+ * - +-1+, if +self+ includes +other+, if or +self+ is a subclass of +other+.
+ * - +0+, if +self+ and +other+ are the same.
+ * - +1+, if +other+ includes +self+, or if +other+ is a subclass of +self+.
+ * - +nil+, if none of the above is true.
*
- * Comparison---Returns -1, 0, +1 or nil depending on whether +module+
- * includes +other_module+, they are the same, or if +module+ is included by
- * +other_module+.
+ * Examples:
+ *
+ * # Class Array includes module Enumerable.
+ * Array <=> Enumerable # => -1
+ * Enumerable <=> Enumerable # => 0
+ * Enumerable <=> Array # => 1
+ * # Class File is a subclass of class IO.
+ * File <=> IO # => -1
+ * File <=> File # => 0
+ * IO <=> File # => 1
+ * # Class File has no relationship to class String.
+ * File <=> String # => nil
*
- * Returns +nil+ if +module+ has no relationship with +other_module+, if
- * +other_module+ is not a module, or if the two values are incomparable.
*/
static VALUE
@@ -1998,28 +2100,52 @@ static VALUE rb_mod_initialize_exec(VALUE module);
/*
* call-seq:
- * Module.new -> mod
- * Module.new {|mod| block } -> mod
+ * Module.new -> new_module
+ * Module.new {|module| ... } -> new_module
*
- * Creates a new anonymous module. If a block is given, it is passed
- * the module object, and the block is evaluated in the context of this
- * module like #module_eval.
+ * Returns a new anonymous module.
*
- * fred = Module.new do
- * def meth1
- * "hello"
- * end
- * def meth2
- * "bye"
- * end
- * end
- * a = "my string"
- * a.extend(fred) #=> "my string"
- * a.meth1 #=> "hello"
- * a.meth2 #=> "bye"
+ * The module may be assigned to a name,
+ * which should be a constant name
+ * in capitalized {camel case}[https://en.wikipedia.org/wiki/Camel_case]
+ * (e.g., +MyModule+, not +MY_MODULE+).
+ *
+ * With no block given, returns the new module.
+ *
+ * MyModule = Module.new
+ * MyModule.class # => Module
+ * MyModule.name # => "MyModule"
+ *
+ * With a block given, calls the block with the new (not yet named) module:
+ *
+ * MyModule = Module.new {|m| p [m.class, m.name] }
+ * # => MyModule
+ * MyModule.class # => Module
+ MyModule.name # => "MyModule"
+ *
+ * Output (from the block):
+ *
+ * [Module, nil]
+ *
+ * The block may define methods and constants for the module:
+ *
+ * MyModule = Module.new do |m|
+ * MY_CONSTANT = "#{MyModule} constant value"
+ * def self.method1 = "#{MyModule} first method (singleton)"
+ * def method2 = "#{MyModule} Second method (instance)"
+ * end
+ * MyModule.method1 # => "MyModule first method (singleton)"
+ * class Foo
+ * include MyModule
+ * def speak
+ * MY_CONSTANT
+ * end
+ * end
+ * foo = Foo.new
+ * foo.method2 # => "MyModule Second method (instance)"
+ * foo.speak
+ * # => "MyModule constant value"
*
- * Assign the module to a constant (name starting uppercase) if you
- * want to treat it like a regular module.
*/
static VALUE
@@ -2098,6 +2224,8 @@ rb_class_initialize(int argc, VALUE *argv, VALUE klass)
}
}
rb_class_set_super(klass, super);
+ RCLASS_SET_MAX_IV_COUNT(klass, RCLASS_MAX_IV_COUNT(super));
+ RCLASS_SET_ALLOCATOR(klass, RCLASS_ALLOCATOR(super));
rb_make_metaclass(klass, RBASIC(super)->klass);
rb_class_inherited(super, klass);
rb_mod_initialize_exec(klass);
@@ -2141,6 +2269,7 @@ static VALUE class_call_alloc_func(rb_alloc_func_t allocator, VALUE klass);
static VALUE
rb_class_alloc(VALUE klass)
{
+ RBIMPL_ASSERT_TYPE(klass, T_CLASS);
rb_alloc_func_t allocator = class_get_alloc_func(klass);
return class_call_alloc_func(allocator, klass);
}
@@ -2163,6 +2292,15 @@ class_get_alloc_func(VALUE klass)
return allocator;
}
+// Might return NULL.
+rb_alloc_func_t
+rb_zjit_class_get_alloc_func(VALUE klass)
+{
+ assert(RCLASS_INITIALIZED_P(klass));
+ assert(!RCLASS_SINGLETON_P(klass));
+ return rb_get_alloc_func(klass);
+}
+
static VALUE
class_call_alloc_func(rb_alloc_func_t allocator, VALUE klass)
{
@@ -2172,9 +2310,7 @@ class_call_alloc_func(rb_alloc_func_t allocator, VALUE klass)
obj = (*allocator)(klass);
- if (rb_obj_class(obj) != rb_class_real(klass)) {
- rb_raise(rb_eTypeError, "wrong instance allocation");
- }
+ RUBY_ASSERT(rb_obj_class(obj) == rb_class_real(klass));
return obj;
}
@@ -3166,19 +3302,12 @@ convert_type_with_id(VALUE val, const char *tname, ID method, int raise, int ind
VALUE r = rb_check_funcall(val, method, 0, 0);
if (UNDEF_P(r)) {
if (raise) {
- const char *msg =
- ((index < 0 ? conv_method_index(rb_id2name(method)) : index)
- < IMPLICIT_CONVERSIONS) ?
- "no implicit conversion of" : "can't convert";
- const char *cname = NIL_P(val) ? "nil" :
- val == Qtrue ? "true" :
- val == Qfalse ? "false" :
- NULL;
- if (cname)
- rb_raise(rb_eTypeError, "%s %s into %s", msg, cname, tname);
- rb_raise(rb_eTypeError, "%s %"PRIsVALUE" into %s", msg,
- rb_obj_class(val),
- tname);
+ if ((index < 0 ? conv_method_index(rb_id2name(method)) : index) < IMPLICIT_CONVERSIONS) {
+ rb_no_implicit_conversion(val, tname);
+ }
+ else {
+ rb_cant_convert(val, tname);
+ }
}
return Qnil;
}
@@ -3194,17 +3323,6 @@ convert_type(VALUE val, const char *tname, const char *method, int raise)
return convert_type_with_id(val, tname, m, raise, i);
}
-/*! \private */
-NORETURN(static void conversion_mismatch(VALUE, const char *, const char *, VALUE));
-static void
-conversion_mismatch(VALUE val, const char *tname, const char *method, VALUE result)
-{
- VALUE cname = rb_obj_class(val);
- rb_raise(rb_eTypeError,
- "can't convert %"PRIsVALUE" to %s (%"PRIsVALUE"#%s gives %"PRIsVALUE")",
- cname, tname, cname, method, rb_obj_class(result));
-}
-
VALUE
rb_convert_type(VALUE val, int type, const char *tname, const char *method)
{
@@ -3213,7 +3331,7 @@ rb_convert_type(VALUE val, int type, const char *tname, const char *method)
if (TYPE(val) == type) return val;
v = convert_type(val, tname, method, TRUE);
if (TYPE(v) != type) {
- conversion_mismatch(val, tname, method, v);
+ rb_cant_convert_invalid_return(val, tname, method, v);
}
return v;
}
@@ -3227,7 +3345,7 @@ rb_convert_type_with_id(VALUE val, int type, const char *tname, ID method)
if (TYPE(val) == type) return val;
v = convert_type_with_id(val, tname, method, TRUE, -1);
if (TYPE(v) != type) {
- conversion_mismatch(val, tname, RSTRING_PTR(rb_id2str(method)), v);
+ rb_cant_convert_invalid_return(val, tname, rb_id2name(method), v);
}
return v;
}
@@ -3242,7 +3360,7 @@ rb_check_convert_type(VALUE val, int type, const char *tname, const char *method
v = convert_type(val, tname, method, FALSE);
if (NIL_P(v)) return Qnil;
if (TYPE(v) != type) {
- conversion_mismatch(val, tname, method, v);
+ rb_cant_convert_invalid_return(val, tname, method, v);
}
return v;
}
@@ -3258,7 +3376,7 @@ rb_check_convert_type_with_id(VALUE val, int type, const char *tname, ID method)
v = convert_type_with_id(val, tname, method, FALSE, -1);
if (NIL_P(v)) return Qnil;
if (TYPE(v) != type) {
- conversion_mismatch(val, tname, RSTRING_PTR(rb_id2str(method)), v);
+ rb_cant_convert_invalid_return(val, tname, rb_id2name(method), v);
}
return v;
}
@@ -3284,7 +3402,7 @@ rb_to_integer_with_id_exception(VALUE val, const char *method, ID mid, int raise
return Qnil;
}
if (!RB_INTEGER_TYPE_P(v)) {
- conversion_mismatch(val, "Integer", method, v);
+ rb_cant_convert_invalid_return(val, "Integer", method, v);
}
GET_EC()->cfp = current_cfp;
return v;
@@ -3361,7 +3479,7 @@ rb_convert_to_integer(VALUE val, int base, int raise_exception)
}
else if (NIL_P(val)) {
if (!raise_exception) return Qnil;
- rb_raise(rb_eTypeError, "can't convert nil into Integer");
+ rb_cant_convert(val, "Integer");
}
tmp = rb_protect(rb_check_to_int, val, NULL);
@@ -3655,18 +3773,6 @@ rat2dbl_without_to_f(VALUE x)
}
/*! \endcond */
-static inline void
-conversion_to_float(VALUE val)
-{
- special_const_to_float(val, "can't convert ", " into Float");
-}
-
-static inline void
-implicit_conversion_to_float(VALUE val)
-{
- special_const_to_float(val, "no implicit conversion to float from ", "");
-}
-
static int
to_float(VALUE *valp, int raise_exception)
{
@@ -3680,7 +3786,7 @@ to_float(VALUE *valp, int raise_exception)
return T_FLOAT;
}
else if (raise_exception) {
- conversion_to_float(val);
+ rb_cant_convert(val, "Float");
}
}
else {
@@ -3760,8 +3866,7 @@ static VALUE
numeric_to_float(VALUE val)
{
if (!rb_obj_is_kind_of(val, rb_cNumeric)) {
- rb_raise(rb_eTypeError, "can't convert %"PRIsVALUE" into Float",
- rb_obj_class(val));
+ rb_cant_convert(val, "Float");
}
return rb_convert_type_with_id(val, T_FLOAT, "Float", id_to_f);
}
@@ -3805,7 +3910,7 @@ rb_num_to_dbl(VALUE val)
return rb_float_flonum_value(val);
}
else {
- conversion_to_float(val);
+ rb_cant_convert(val, "Float");
}
}
else {
@@ -3839,7 +3944,7 @@ rb_num2dbl(VALUE val)
return rb_float_flonum_value(val);
}
else {
- implicit_conversion_to_float(val);
+ rb_no_implicit_conversion(val, "Float");
}
}
else {
@@ -3851,7 +3956,7 @@ rb_num2dbl(VALUE val)
case T_RATIONAL:
return rat2dbl_without_to_f(val);
case T_STRING:
- rb_raise(rb_eTypeError, "no implicit conversion to float from string");
+ rb_no_implicit_conversion(val, "Float");
default:
break;
}
@@ -3945,7 +4050,7 @@ rb_Hash(VALUE val)
if (NIL_P(tmp)) {
if (RB_TYPE_P(val, T_ARRAY) && RARRAY_LEN(val) == 0)
return rb_hash_new();
- rb_raise(rb_eTypeError, "can't convert %s into Hash", rb_obj_classname(val));
+ rb_cant_convert(val, "Hash");
}
return tmp;
}
@@ -3966,7 +4071,7 @@ rb_Hash(VALUE val)
*
* Examples:
*
- * Hash({foo: 0, bar: 1}) # => {:foo=>0, :bar=>1}
+ * Hash({foo: 0, bar: 1}) # => {foo: 0, bar: 1}
* Hash(nil) # => {}
* Hash([]) # => {}
*
@@ -4053,7 +4158,7 @@ rb_obj_dig(int argc, VALUE *argv, VALUE obj, VALUE notfound)
* into +format_string+.
*
* For details on +format_string+, see
- * {Format Specifications}[rdoc-ref:format_specifications.rdoc].
+ * {Format Specifications}[rdoc-ref:language/format_specifications.rdoc].
*/
static VALUE
@@ -4218,8 +4323,8 @@ rb_f_loop_size(VALUE self, VALUE args, VALUE eobj)
*
* First, what's elsewhere. Class \Object:
*
- * - Inherits from {class BasicObject}[rdoc-ref:BasicObject@What-27s+Here].
- * - Includes {module Kernel}[rdoc-ref:Kernel@What-27s+Here].
+ * - Inherits from {class BasicObject}[rdoc-ref:BasicObject@Whats+Here].
+ * - Includes {module Kernel}[rdoc-ref:Kernel@Whats+Here].
*
* Here, class \Object provides methods for:
*
@@ -4313,7 +4418,6 @@ InitVM_Object(void)
#endif
rb_define_private_method(rb_cBasicObject, "initialize", rb_obj_initialize, 0);
- rb_define_alloc_func(rb_cBasicObject, rb_class_allocate_instance);
rb_define_method(rb_cBasicObject, "==", rb_obj_equal, 1);
rb_define_method(rb_cBasicObject, "equal?", rb_obj_equal, 1);
rb_define_method(rb_cBasicObject, "!", rb_obj_not, 0);
@@ -4494,6 +4598,7 @@ InitVM_Object(void)
rb_define_method(rb_mKernel, "to_s", rb_any_to_s, 0);
rb_define_method(rb_mKernel, "inspect", rb_obj_inspect, 0);
+ rb_define_private_method(rb_mKernel, "instance_variables_to_inspect", rb_obj_instance_variables_to_inspect, 0);
rb_define_method(rb_mKernel, "methods", rb_obj_methods, -1); /* in class.c */
rb_define_method(rb_mKernel, "singleton_methods", rb_obj_singleton_methods, -1); /* in class.c */
rb_define_method(rb_mKernel, "protected_methods", rb_obj_protected_methods, -1); /* in class.c */
@@ -4542,7 +4647,6 @@ InitVM_Object(void)
rb_define_method(rb_cModule, "<=", rb_class_inherited_p, 1);
rb_define_method(rb_cModule, ">", rb_mod_gt, 1);
rb_define_method(rb_cModule, ">=", rb_mod_ge, 1);
- rb_define_method(rb_cModule, "initialize_copy", rb_mod_init_copy, 1); /* in class.c */
rb_define_method(rb_cModule, "to_s", rb_mod_to_s, 0);
rb_define_alias(rb_cModule, "inspect", "to_s");
rb_define_method(rb_cModule, "included_modules", rb_mod_included_modules, 0); /* in class.c */
diff --git a/pack.c b/pack.c
index 3a5c1bfb96..24221bc3d6 100644
--- a/pack.c
+++ b/pack.c
@@ -19,6 +19,7 @@
#include "internal.h"
#include "internal/array.h"
#include "internal/bits.h"
+#include "internal/numeric.h"
#include "internal/string.h"
#include "internal/symbol.h"
#include "internal/variable.h"
@@ -61,7 +62,7 @@ is_bigendian(void)
{
static int init = 0;
static int endian_value;
- char *p;
+ const char *p;
if (init) return endian_value;
init = 1;
@@ -118,6 +119,7 @@ typedef union {
#define MAX_INTEGER_PACK_SIZE 8
static const char toofew[] = "too few arguments";
+static const char intoitself[] = "cannot pack buffer object into itself";
static void encodes(VALUE,const char*,long,int,int);
static void qpencode(VALUE,VALUE,long);
@@ -279,6 +281,8 @@ pack_pack(rb_execution_context_t *ec, VALUE ary, VALUE fmt, VALUE buffer)
#define MORE_ITEM (idx < RARRAY_LEN(ary))
#define THISFROM (MORE_ITEM ? RARRAY_AREF(ary, idx) : TOO_FEW)
#define NEXTFROM (MORE_ITEM ? RARRAY_AREF(ary, idx++) : TOO_FEW)
+#define NOT_BUFFER(val) (((val) == res) ? rb_raise(rb_eArgError, intoitself) : (void)0)
+#define STR_FROM(val) NOT_BUFFER(StringValue(val))
while (p < pend) {
int explicit_endian = 0;
@@ -302,7 +306,7 @@ pack_pack(rb_execution_context_t *ec, VALUE ary, VALUE fmt, VALUE buffer)
else if (ISDIGIT(*p)) {
errno = 0;
len = STRTOUL(p, (char**)&p, 10);
- if (errno) {
+ if (len < 0 || errno) {
rb_raise(rb_eRangeError, "pack length too big");
}
}
@@ -333,7 +337,7 @@ pack_pack(rb_execution_context_t *ec, VALUE ary, VALUE fmt, VALUE buffer)
plen = 0;
}
else {
- StringValue(from);
+ STR_FROM(from);
ptr = RSTRING_PTR(from);
plen = RSTRING_LEN(from);
}
@@ -667,10 +671,58 @@ pack_pack(rb_execution_context_t *ec, VALUE ary, VALUE fmt, VALUE buffer)
}
break;
+ case 'r': /* r for SLEB128 encoding (signed) */
+ case 'R': /* R for ULEB128 encoding (unsigned) */
+ {
+ int pack_flags = INTEGER_PACK_LITTLE_ENDIAN;
+
+ if (type == 'r') {
+ pack_flags |= INTEGER_PACK_2COMP;
+ }
+
+ while (len-- > 0) {
+ size_t numbytes, nlz_bits;
+ int sign, extra = 0;
+ char *cp;
+ const long start = RSTRING_LEN(res);
+
+ from = NEXTFROM;
+ from = rb_to_int(from);
+ if (type == 'R' && rb_int_negative_p(from)) {
+ rb_raise(rb_eArgError, "can't encode negative numbers in ULEB128");
+ }
+
+ numbytes = rb_absint_numwords(from, 7, &nlz_bits);
+ if (numbytes == 0) {
+ numbytes = 1;
+ }
+ else if (nlz_bits == 0 && type == 'r') {
+ /* No leading zero bits, we need an extra byte for sign extension */
+ extra = 1;
+ }
+ rb_str_modify_expand(res, numbytes + extra);
+
+ cp = RSTRING_PTR(res) + start;
+ sign = rb_integer_pack(from, cp, numbytes, 1, 1, pack_flags);
+
+ if (extra) {
+ /* Need an extra byte */
+ cp[numbytes++] = sign < 0 ? 0x7f : 0x00;
+ }
+ rb_str_set_len(res, start + numbytes);
+
+ while (1 < numbytes) {
+ *cp |= 0x80;
+ cp++;
+ numbytes--;
+ }
+ }
+ }
+ break;
case 'u': /* uuencoded string */
case 'm': /* base64 encoded string */
from = NEXTFROM;
- StringValue(from);
+ STR_FROM(from);
ptr = RSTRING_PTR(from);
plen = RSTRING_LEN(from);
@@ -700,6 +752,7 @@ pack_pack(rb_execution_context_t *ec, VALUE ary, VALUE fmt, VALUE buffer)
case 'M': /* quoted-printable encoded string */
from = rb_obj_as_string(NEXTFROM);
+ NOT_BUFFER(from);
if (len <= 1)
len = 72;
qpencode(res, from, len);
@@ -708,7 +761,7 @@ pack_pack(rb_execution_context_t *ec, VALUE ary, VALUE fmt, VALUE buffer)
case 'P': /* pointer to packed byte string */
from = THISFROM;
if (!NIL_P(from)) {
- StringValue(from);
+ STR_FROM(from);
if (RSTRING_LEN(from) < len) {
rb_raise(rb_eArgError, "too short buffer for P(%ld for %ld)",
RSTRING_LEN(from), len);
@@ -718,13 +771,11 @@ pack_pack(rb_execution_context_t *ec, VALUE ary, VALUE fmt, VALUE buffer)
/* FALL THROUGH */
case 'p': /* pointer to string */
while (len-- > 0) {
- char *t;
+ const char *t = 0;
from = NEXTFROM;
- if (NIL_P(from)) {
- t = 0;
- }
- else {
- t = StringValuePtr(from);
+ if (!NIL_P(from)) {
+ STR_FROM(from);
+ t = RSTRING_PTR(from);
}
if (!associates) {
associates = rb_ary_new();
@@ -736,7 +787,7 @@ pack_pack(rb_execution_context_t *ec, VALUE ary, VALUE fmt, VALUE buffer)
case 'w': /* BER compressed integer */
while (len-- > 0) {
- VALUE buf = rb_str_new(0, 0);
+ VALUE buf;
size_t numbytes;
int sign;
char *cp;
@@ -950,8 +1001,8 @@ static VALUE
pack_unpack_internal(VALUE str, VALUE fmt, enum unpack_mode mode, long offset)
{
#define hexdigits ruby_hexdigits
- char *s, *send;
- char *p, *pend;
+ const char *s, *send;
+ const char *p, *pend;
VALUE ary, associates = Qfalse;
long len;
AVOID_CC_BUG long tmp_len;
@@ -973,9 +1024,10 @@ pack_unpack_internal(VALUE str, VALUE fmt, enum unpack_mode mode, long offset)
StringValue(fmt);
rb_must_asciicompat(fmt);
- if (offset < 0) rb_raise(rb_eArgError, "offset can't be negative");
len = RSTRING_LEN(str);
- if (offset > len) rb_raise(rb_eArgError, "offset outside of string");
+ if (offset < 0 ? (offset += len) < 0 : offset > len) {
+ rb_raise(rb_eArgError, "offset outside of string");
+ }
s = RSTRING_PTR(str);
send = s + len;
@@ -1025,7 +1077,7 @@ pack_unpack_internal(VALUE str, VALUE fmt, enum unpack_mode mode, long offset)
if (len > send - s) len = send - s;
{
long end = len;
- char *t = s + len - 1;
+ const char *t = s + len - 1;
while (t >= s) {
if (*t != ' ' && *t != '\0') break;
@@ -1038,7 +1090,7 @@ pack_unpack_internal(VALUE str, VALUE fmt, enum unpack_mode mode, long offset)
case 'Z':
{
- char *t = s;
+ const char *t = s;
if (len > send-s) len = send-s;
while (t < s+len && *t) t++;
@@ -1472,7 +1524,8 @@ pack_unpack_internal(VALUE str, VALUE fmt, enum unpack_mode mode, long offset)
case 'M':
{
VALUE buf = rb_str_new(0, send - s);
- char *ptr = RSTRING_PTR(buf), *ss = s;
+ char *ptr = RSTRING_PTR(buf);
+ const char *ss = s;
int csum = 0;
int c1, c2;
@@ -1520,10 +1573,14 @@ pack_unpack_internal(VALUE str, VALUE fmt, enum unpack_mode mode, long offset)
s += len;
break;
+ case '^':
+ UNPACK_PUSH(SSIZET2NUM(s - RSTRING_PTR(str)));
+ break;
+
case 'P':
if (sizeof(char *) <= (size_t)(send - s)) {
VALUE tmp = Qnil;
- char *t;
+ const char *t;
UNPACK_FETCH(&t, char *);
if (t) {
@@ -1546,7 +1603,7 @@ pack_unpack_internal(VALUE str, VALUE fmt, enum unpack_mode mode, long offset)
break;
else {
VALUE tmp = Qnil;
- char *t;
+ const char *t;
UNPACK_FETCH(&t, char *);
if (t) {
@@ -1558,9 +1615,42 @@ pack_unpack_internal(VALUE str, VALUE fmt, enum unpack_mode mode, long offset)
}
break;
+ case 'r':
+ case 'R':
+ {
+ int pack_flags = INTEGER_PACK_LITTLE_ENDIAN;
+
+ if (type == 'r') {
+ pack_flags |= INTEGER_PACK_2COMP;
+ }
+ const char *s0 = s;
+ while (len > 0 && s < send) {
+ if (*s & 0x80) {
+ s++;
+ }
+ else {
+ s++;
+ UNPACK_PUSH(rb_integer_unpack(s0, s-s0, 1, 1, pack_flags));
+ len--;
+ s0 = s;
+ }
+ }
+ /* Handle incomplete value and remaining expected values with nil (only if not using *) */
+ if (!star) {
+ if (s0 != s && len > 0) {
+ UNPACK_PUSH(Qnil);
+ len--;
+ }
+ while (len-- > 0) {
+ UNPACK_PUSH(Qnil);
+ }
+ }
+ }
+ break;
+
case 'w':
{
- char *s0 = s;
+ const char *s0 = s;
while (len > 0 && s < send) {
if (*s & 0x80) {
s++;
diff --git a/pack.rb b/pack.rb
index e70c6c7dc8..78ef6973d4 100644
--- a/pack.rb
+++ b/pack.rb
@@ -3,23 +3,25 @@ class Array
# pack(template, buffer: nil) -> string
#
# Formats each element in +self+ into a binary string; returns that string.
- # See {Packed Data}[rdoc-ref:packed_data.rdoc].
+ # See {Packed Data}[rdoc-ref:language/packed_data.md].
def pack(fmt, buffer: nil)
Primitive.pack_pack(fmt, buffer)
end
end
class String
- # call-seq:
- # unpack(template, offset: 0, &block) -> array
+ # call-seq:
+ # unpack(template, offset: 0) {|o| .... } -> object
+ # unpack(template, offset: 0) -> array
#
- # Extracts data from +self+.
+ # Extracts data from +self+ to form new objects;
+ # see {Packed Data}[rdoc-ref:language/packed_data.md].
#
- # If +block+ is not given, forming objects that become the elements
- # of a new array, and returns that array. Otherwise, yields each
- # object.
+ # With a block given, calls the block with each unpacked object.
#
- # See {Packed Data}[rdoc-ref:packed_data.rdoc].
+ # With no block given, returns an array containing the unpacked objects.
+ #
+ # Related: see {Converting to Non-String}[rdoc-ref:String@Converting+to+Non--5CString].
def unpack(fmt, offset: 0)
Primitive.attr! :use_block
Primitive.pack_unpack(fmt, offset)
@@ -28,8 +30,10 @@ class String
# call-seq:
# unpack1(template, offset: 0) -> object
#
- # Like String#unpack, but unpacks and returns only the first extracted object.
- # See {Packed Data}[rdoc-ref:packed_data.rdoc].
+ # Like String#unpack with no block, but unpacks and returns only the first extracted object.
+ # See {Packed Data}[rdoc-ref:language/packed_data.md].
+ #
+ # Related: see {Converting to Non-String}[rdoc-ref:String@Converting+to+Non--5CString].
def unpack1(fmt, offset: 0)
Primitive.pack_unpack1(fmt, offset)
end
diff --git a/parse.y b/parse.y
index c0f46a395f..ecd26acbbb 100644
--- a/parse.y
+++ b/parse.y
@@ -318,6 +318,8 @@ struct lex_context {
BITFIELD(enum rb_parser_shareability, shareable_constant_value, 2);
BITFIELD(enum rescue_context, in_rescue, 2);
unsigned int cant_return: 1;
+ unsigned int in_alt_pattern: 1;
+ unsigned int capture_in_pattern: 1;
};
typedef struct RNode_DEF_TEMP rb_node_def_temp_t;
@@ -827,7 +829,7 @@ 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));
+ ruby_xfree_sized(p->end_expect_token_locations, sizeof(end_expect_token_locations_t));
p->end_expect_token_locations = locations;
debug_end_expect_token_locations(p, "pop_end_expect_token_locations");
@@ -1061,8 +1063,8 @@ rb_discard_node(struct parser_params *p, NODE *n)
rb_ast_delete_node(p->ast, n);
}
-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_scope_t *rb_node_scope_new(struct parser_params *p, rb_node_args_t *nd_args, NODE *nd_body, NODE *nd_parent, 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, NODE *nd_parent, 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, const YYLTYPE* if_keyword_loc, const YYLTYPE* then_keyword_loc, const YYLTYPE* end_keyword_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);
@@ -1146,7 +1148,7 @@ static rb_node_valias_t *rb_node_valias_new(struct parser_params *p, ID nd_alias
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, const YYLTYPE *class_keyword_loc, const YYLTYPE *inheritance_operator_loc, const YYLTYPE *end_keyword_loc);
static rb_node_module_t *rb_node_module_new(struct parser_params *p, NODE *nd_cpath, NODE *nd_body, const YYLTYPE *loc, const YYLTYPE *module_keyword_loc, const YYLTYPE *end_keyword_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_sclass_t *rb_node_sclass_new(struct parser_params *p, NODE *nd_recv, NODE *nd_body, const YYLTYPE *loc, const YYLTYPE *class_keyword_loc, const YYLTYPE *operator_loc, const YYLTYPE *end_keyword_loc);
static rb_node_colon2_t *rb_node_colon2_new(struct parser_params *p, NODE *nd_head, ID nd_mid, const YYLTYPE *loc, const YYLTYPE *delimiter_loc, const YYLTYPE *name_loc);
static rb_node_colon3_t *rb_node_colon3_new(struct parser_params *p, ID nd_mid, const YYLTYPE *loc, const YYLTYPE *delimiter_loc, const YYLTYPE *name_loc);
static rb_node_dot2_t *rb_node_dot2_new(struct parser_params *p, NODE *nd_beg, NODE *nd_end, const YYLTYPE *loc, const YYLTYPE *operator_loc);
@@ -1169,8 +1171,8 @@ static rb_node_line_t *rb_node_line_new(struct parser_params *p, const YYLTYPE *
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_SCOPE(a,b,c,loc) (NODE *)rb_node_scope_new(p,a,b,c,loc)
+#define NEW_SCOPE2(t,a,b,c,loc) (NODE *)rb_node_scope_new2(p,t,a,b,c,loc)
#define NEW_BLOCK(a,loc) (NODE *)rb_node_block_new(p,a,loc)
#define NEW_IF(c,t,e,loc,ik_loc,tk_loc,ek_loc) (NODE *)rb_node_if_new(p,c,t,e,loc,ik_loc,tk_loc,ek_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)
@@ -1254,7 +1256,7 @@ static rb_node_error_t *rb_node_error_new(struct parser_params *p, const YYLTYPE
#define NEW_UNDEF(i,loc) (NODE *)rb_node_undef_new(p,i,loc)
#define NEW_CLASS(n,b,s,loc,ck_loc,io_loc,ek_loc) (NODE *)rb_node_class_new(p,n,b,s,loc,ck_loc,io_loc,ek_loc)
#define NEW_MODULE(n,b,loc,mk_loc,ek_loc) (NODE *)rb_node_module_new(p,n,b,loc,mk_loc,ek_loc)
-#define NEW_SCLASS(r,b,loc) (NODE *)rb_node_sclass_new(p,r,b,loc)
+#define NEW_SCLASS(r,b,loc,ck_loc,op_loc,ek_loc) (NODE *)rb_node_sclass_new(p,r,b,loc,ck_loc,op_loc,ek_loc)
#define NEW_COLON2(c,i,loc,d_loc,n_loc) (NODE *)rb_node_colon2_new(p,c,i,loc,d_loc,n_loc)
#define NEW_COLON3(i,loc,d_loc,n_loc) (NODE *)rb_node_colon3_new(p,i,loc,d_loc,n_loc)
#define NEW_DOT2(b,e,loc,op_loc) (NODE *)rb_node_dot2_new(p,b,e,loc,op_loc)
@@ -1391,7 +1393,6 @@ last_expr_node(NODE *expr)
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*,const YYLTYPE*,const YYLTYPE*,const YYLTYPE*);
static NODE *new_unless(struct parser_params*,NODE*,NODE*,NODE*,const YYLTYPE*,const YYLTYPE*,const YYLTYPE*,const YYLTYPE*);
@@ -1400,10 +1401,9 @@ static NODE *logop(struct parser_params*,ID,NODE*,NODE*,const YYLTYPE*,const YYL
static NODE *newline_node(NODE*);
static void fixpos(NODE*,NODE*);
-static int value_expr_gen(struct parser_params*,NODE*);
+static int value_expr(struct parser_params*,NODE*);
static void void_expr(struct parser_params*,NODE*);
static NODE *remove_begin(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**);
static void block_dup_check(struct parser_params*,NODE*,NODE*);
@@ -1431,6 +1431,7 @@ static NODE *method_add_block(struct parser_params*p, NODE *m, NODE *b, const YY
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*);
+#define new_empty_args_tail(p, loc) new_args_tail(p, 0, 0, 0, loc)
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_find_pattern(struct parser_params *p, NODE *constant, NODE *fndptn, const YYLTYPE *loc);
@@ -1441,7 +1442,7 @@ static NODE *new_hash_pattern_tail(struct parser_params *p, NODE *kw_args, ID kw
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* negate_lit(struct parser_params*, NODE*);
+static NODE* negate_lit(struct parser_params*, NODE*,const YYLTYPE*);
static void no_blockarg(struct parser_params*,NODE*);
static NODE *ret_args(struct parser_params*,NODE*);
static NODE *arg_blk_pass(NODE*,rb_node_block_pass_t*);
@@ -1634,11 +1635,11 @@ aryptn_pre_args(struct parser_params *p, VALUE pre_arg, VALUE pre_args)
#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)
+new_scope_body(struct parser_params *p, rb_node_args_t *args, NODE *body, NODE *parent, const YYLTYPE *loc)
{
body = remove_begin(body);
reduce_nodes(p, &body);
- NODE *n = NEW_SCOPE(args, body, loc);
+ NODE *n = NEW_SCOPE(args, body, parent, loc);
nd_set_line(n, loc->end_pos.lineno);
set_line_body(body, loc->beg_pos.lineno);
return n;
@@ -1995,7 +1996,7 @@ parser_memhash(const void *ptr, long len)
#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)); \
+ REALLOC_N(str->ptr, char, (size_t)total + termlen); \
str->len = total; \
} while (0)
#define STRING_SET_LEN(str, n) do { \
@@ -2778,7 +2779,7 @@ rb_parser_ary_free(rb_parser_t *p, rb_parser_ary_t *ary)
%type <node> 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> f_arglist f_opt_paren_args f_paren_args f_args f_empty_arg
%type <node_args_aux> f_arg f_arg_item
%type <node> f_marg f_rest_marg
%type <node_masgn> f_margs
@@ -2787,7 +2788,7 @@ rb_parser_ary_free(rb_parser_t *p, rb_parser_ary_t *ary)
%type <id> do bv_decls opt_bv_decl bvar
%type <node> lambda brace_body do_body
%type <locations_lambda_body> lambda_body
-%type <node_args> f_larglist
+%type <node_args> f_larglist f_largs largs_tail
%type <node> brace_block cmd_brace_block do_block lhs none fitem
%type <node> mlhs_head mlhs_item mlhs_node
%type <node_masgn> mlhs mlhs_basic mlhs_inner
@@ -2797,7 +2798,7 @@ rb_parser_ary_free(rb_parser_t *p, rb_parser_ary_t *ary)
%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 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> cname fname op f_rest_arg f_block_arg opt_comma 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
@@ -2922,18 +2923,18 @@ rb_parser_ary_free(rb_parser_t *p, rb_parser_ary_t *ary)
}
;
-%rule args_tail_basic(value) <node_args>
- : f_kwarg(value) ',' f_kwrest opt_f_block_arg
+%rule args_tail_basic(value, trailing) <node_args>
+ : f_kwarg(value) ',' f_kwrest opt_f_block_arg(trailing)
{
$$ = new_args_tail(p, $1, $3, $4, &@3);
/*% ripper: [$:1, $:3, $:4] %*/
}
- | f_kwarg(value) opt_f_block_arg
+ | f_kwarg(value) opt_f_block_arg(trailing)
{
$$ = new_args_tail(p, $1, 0, $2, &@1);
/*% ripper: [$:1, Qnil, $:2] %*/
}
- | f_any_kwrest opt_f_block_arg
+ | f_any_kwrest opt_f_block_arg(trailing)
{
$$ = new_args_tail(p, 0, $1, $2, &@1);
/*% ripper: [Qnil, $:1, $:2] %*/
@@ -2943,14 +2944,24 @@ rb_parser_ary_free(rb_parser_t *p, rb_parser_ary_t *ary)
$$ = new_args_tail(p, 0, 0, $1, &@1);
/*% ripper: [Qnil, Qnil, $:1] %*/
}
+ ;
+
+%rule opt_f_block_arg(trailing) <id>
+ : ',' f_block_arg
+ {
+ $$ = $2;
+ /*% ripper: $:2 %*/
+ }
+ | trailing
+ ;
%rule def_endless_method(bodystmt) <node>
: defn_head[head] f_opt_paren_args[args] '=' 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 = @$;
+ $bodystmt = new_scope_body(p, $args, $bodystmt, $$, &@$);
RNODE_DEFN($$)->nd_defn = $bodystmt;
/*% ripper: bodystmt!($:bodystmt, Qnil, Qnil, Qnil) %*/
/*% ripper: def!($:head, $:args, $:$) %*/
@@ -2960,8 +2971,8 @@ rb_parser_ary_free(rb_parser_t *p, rb_parser_ary_t *ary)
{
endless_method_name(p, $head->nd_mid, &@head);
restore_defun(p, $head);
- $bodystmt = new_scope_body(p, $args, $bodystmt, &@$);
($$ = $head->nd_def)->nd_loc = @$;
+ $bodystmt = new_scope_body(p, $args, $bodystmt, $$, &@$);
RNODE_DEFS($$)->nd_defn = $bodystmt;
/*% ripper: bodystmt!($:bodystmt, Qnil, Qnil, Qnil) %*/
/*% ripper: defs!(*$:head[0..2], $:args, $:$) %*/
@@ -3026,13 +3037,13 @@ rb_parser_ary_free(rb_parser_t *p, rb_parser_ary_t *ary)
}
;
-%rule mlhs(item) <node>
+%rule mlhs_items(item) <node>
: item
{
$$ = NEW_LIST($1, &@$);
/*% ripper: mlhs_add!(mlhs_new!, $:1) %*/
}
- | mlhs(item) ',' item
+ | mlhs_items(item) ',' item
{
$$ = list_append(p, $1, $3);
/*% ripper: mlhs_add!($:1, $:3) %*/
@@ -3043,57 +3054,57 @@ rb_parser_ary_free(rb_parser_t *p, rb_parser_ary_t *ary)
: var_lhs tOP_ASGN lex_ctxt rhs
{
$$ = new_op_assign(p, $var_lhs, $tOP_ASGN, $rhs, $lex_ctxt, &@$);
- /*% ripper: opassign!($:1, $:2, $:4) %*/
+ /*% ripper: opassign!($:var_lhs, $:tOP_ASGN, $:rhs) %*/
}
| primary_value '['[lbracket] opt_call_args rbracket tOP_ASGN lex_ctxt rhs
{
$$ = new_ary_op_assign(p, $primary_value, $opt_call_args, $tOP_ASGN, $rhs, &@opt_call_args, &@$, &NULL_LOC, &@lbracket, &@rbracket, &@tOP_ASGN);
- /*% ripper: opassign!(aref_field!($:1, $:3), $:5, $:7) %*/
+ /*% ripper: opassign!(aref_field!($:primary_value, $:opt_call_args), $:tOP_ASGN, $:rhs) %*/
}
| primary_value call_op tIDENTIFIER tOP_ASGN lex_ctxt rhs
{
$$ = new_attr_op_assign(p, $primary_value, $call_op, $tIDENTIFIER, $tOP_ASGN, $rhs, &@$, &@call_op, &@tIDENTIFIER, &@tOP_ASGN);
- /*% ripper: opassign!(field!($:1, $:2, $:3), $:4, $:6) %*/
+ /*% ripper: opassign!(field!($:primary_value, $:call_op, $:tIDENTIFIER), $:tOP_ASGN, $:rhs) %*/
}
| primary_value call_op tCONSTANT tOP_ASGN lex_ctxt rhs
{
$$ = new_attr_op_assign(p, $primary_value, $call_op, $tCONSTANT, $tOP_ASGN, $rhs, &@$, &@call_op, &@tCONSTANT, &@tOP_ASGN);
- /*% ripper: opassign!(field!($:1, $:2, $:3), $:4, $:6) %*/
+ /*% ripper: opassign!(field!($:primary_value, $:call_op, $:tCONSTANT), $:tOP_ASGN, $:rhs) %*/
}
| primary_value tCOLON2 tIDENTIFIER tOP_ASGN lex_ctxt rhs
{
$$ = new_attr_op_assign(p, $primary_value, idCOLON2, $tIDENTIFIER, $tOP_ASGN, $rhs, &@$, &@tCOLON2, &@tIDENTIFIER, &@tOP_ASGN);
- /*% ripper: opassign!(field!($:1, $:2, $:3), $:4, $:6) %*/
+ /*% ripper: opassign!(field!($:primary_value, $:tCOLON2, $:tIDENTIFIER), $:tOP_ASGN, $:rhs) %*/
}
| primary_value tCOLON2 tCONSTANT tOP_ASGN lex_ctxt rhs
{
YYLTYPE loc = code_loc_gen(&@primary_value, &@tCONSTANT);
$$ = new_const_op_assign(p, NEW_COLON2($primary_value, $tCONSTANT, &loc, &@tCOLON2, &@tCONSTANT), $tOP_ASGN, $rhs, $lex_ctxt, &@$);
- /*% ripper: opassign!(const_path_field!($:1, $:3), $:4, $:6) %*/
+ /*% ripper: opassign!(const_path_field!($:primary_value, $:tCONSTANT), $:tOP_ASGN, $:rhs) %*/
}
| tCOLON3 tCONSTANT tOP_ASGN lex_ctxt rhs
{
YYLTYPE loc = code_loc_gen(&@tCOLON3, &@tCONSTANT);
$$ = new_const_op_assign(p, NEW_COLON3($tCONSTANT, &loc, &@tCOLON3, &@tCONSTANT), $tOP_ASGN, $rhs, $lex_ctxt, &@$);
- /*% ripper: opassign!(top_const_field!($:2), $:3, $:5) %*/
+ /*% ripper: opassign!(top_const_field!($:tCONSTANT), $:tOP_ASGN, $:rhs) %*/
}
| backref tOP_ASGN lex_ctxt rhs
{
VALUE MAYBE_UNUSED(e) = rb_backref_error(p, $backref);
$$ = NEW_ERROR(&@$);
- /*% ripper[error]: assign_error!(?e, opassign!(var_field!($:1), $:2, $:4)) %*/
+ /*% ripper[error]: assign_error!(?e, opassign!(var_field!($:backref), $:tOP_ASGN, $:rhs)) %*/
}
;
-%rule opt_args_tail(tail) <node_args>
+%rule opt_args_tail(tail, trailing) <node_args>
: ',' tail
{
$$ = $tail;
- /*% ripper: $:2 %*/
+ /*% ripper: $:tail %*/
}
- | /* none */
+ | trailing
{
- $$ = new_args_tail(p, 0, 0, 0, &@0);
+ $$ = new_empty_args_tail(p, &@$);
/*% ripper: [Qnil, Qnil, Qnil] %*/
}
;
@@ -3101,39 +3112,39 @@ rb_parser_ary_free(rb_parser_t *p, rb_parser_ary_t *ary)
%rule range_expr(range) <node>
: range tDOT2 range
{
- value_expr($1);
- value_expr($3);
+ value_expr(p, $1);
+ value_expr(p, $3);
$$ = NEW_DOT2($1, $3, &@$, &@2);
/*% ripper: dot2!($:1, $:3) %*/
}
| range tDOT3 range
{
- value_expr($1);
- value_expr($3);
+ value_expr(p, $1);
+ value_expr(p, $3);
$$ = NEW_DOT3($1, $3, &@$, &@2);
/*% ripper: dot3!($:1, $:3) %*/
}
| range tDOT2
{
- value_expr($1);
+ value_expr(p, $1);
$$ = NEW_DOT2($1, new_nil_at(p, &@2.end_pos), &@$, &@2);
/*% ripper: dot2!($:1, Qnil) %*/
}
| range tDOT3
{
- value_expr($1);
+ value_expr(p, $1);
$$ = NEW_DOT3($1, new_nil_at(p, &@2.end_pos), &@$, &@2);
/*% ripper: dot3!($:1, Qnil) %*/
}
| tBDOT2 range
{
- value_expr($2);
+ value_expr(p, $2);
$$ = NEW_DOT2(new_nil_at(p, &@1.beg_pos), $2, &@$, &@1);
/*% ripper: dot2!(Qnil, $:2) %*/
}
| tBDOT3 range
{
- value_expr($2);
+ value_expr(p, $2);
$$ = NEW_DOT3(new_nil_at(p, &@1.beg_pos), $2, &@$, &@1);
/*% ripper: dot3!(Qnil, $:2) %*/
}
@@ -3142,7 +3153,7 @@ rb_parser_ary_free(rb_parser_t *p, rb_parser_ary_t *ary)
%rule value_expr(value) <node>
: value
{
- value_expr($1);
+ value_expr(p, $1);
$$ = $1;
}
;
@@ -3151,7 +3162,7 @@ rb_parser_ary_free(rb_parser_t *p, rb_parser_ary_t *ary)
: begin ' '+ word_list tSTRING_END
{
$$ = make_list($word_list, &@$);
- /*% ripper: array!($:3) %*/
+ /*% ripper: array!($:word_list) %*/
}
;
@@ -3176,7 +3187,7 @@ program : {
node = remove_begin(node);
void_expr(p, node);
}
- p->eval_tree = NEW_SCOPE(0, block_append(p, p->eval_tree, $2), &@$);
+ p->eval_tree = NEW_SCOPE(0, block_append(p, p->eval_tree, $2), NULL, &@$);
/*% ripper[final]: program!($:2) %*/
local_pop(p);
}
@@ -3217,9 +3228,9 @@ begin_block : block_open compstmt(top_stmts) '}'
{
restore_block_exit(p, $block_open);
p->eval_tree_begin = block_append(p, p->eval_tree_begin,
- NEW_BEGIN($2, &@$));
+ NEW_BEGIN($compstmt, &@$));
$$ = NEW_BEGIN(0, &@$);
- /*% ripper: BEGIN!($:2) %*/
+ /*% ripper: BEGIN!($:compstmt) %*/
}
;
@@ -3285,123 +3296,125 @@ allow_exits : {$$ = allow_block_exit(p);};
k_END : keyword_END lex_ctxt
{
+ if (p->ctxt.in_def) {
+ rb_warn0("END in method; use at_exit");
+ }
$$ = $2;
p->ctxt.in_rescue = before_rescue;
/*% ripper: $:2 %*/
};
-stmt : keyword_alias fitem {SET_LEX_STATE(EXPR_FNAME|EXPR_FITEM);} fitem
+stmt : keyword_alias[kw] fitem[new] {SET_LEX_STATE(EXPR_FNAME|EXPR_FITEM);} fitem[old]
{
- $$ = NEW_ALIAS($2, $4, &@$, &@1);
- /*% ripper: alias!($:2, $:4) %*/
+ $$ = NEW_ALIAS($new, $old, &@$, &@kw);
+ /*% ripper: alias!($:new, $:old) %*/
}
- | keyword_alias tGVAR tGVAR
+ | keyword_alias[kw] tGVAR[new] tGVAR[old]
{
- $$ = NEW_VALIAS($2, $3, &@$, &@1);
- /*% ripper: var_alias!($:2, $:3) %*/
+ $$ = NEW_VALIAS($new, $old, &@$, &@kw);
+ /*% ripper: var_alias!($:new, $:old) %*/
}
- | keyword_alias tGVAR tBACK_REF
+ | keyword_alias[kw] tGVAR[new] tBACK_REF[old]
{
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) %*/
+ buf[1] = (char)RNODE_BACK_REF($old)->nd_nth;
+ $$ = NEW_VALIAS($new, rb_intern2(buf, 2), &@$, &@kw);
+ /*% ripper: var_alias!($:new, $:old) %*/
}
- | keyword_alias tGVAR tNTH_REF
+ | keyword_alias tGVAR tNTH_REF[nth]
{
static const char mesg[] = "can't make alias for the number variables";
/*%%%*/
- yyerror1(&@3, mesg);
+ yyerror1(&@nth, mesg);
/*% %*/
$$ = NEW_ERROR(&@$);
- /*% ripper[error]: alias_error!(ERR_MESG(), $:3) %*/
+ /*% ripper[error]: alias_error!(ERR_MESG(), $:nth) %*/
}
- | keyword_undef undef_list
+ | keyword_undef[kw] undef_list[list]
{
- nd_set_first_loc($2, @1.beg_pos);
- RNODE_UNDEF($2)->keyword_loc = @1;
- $$ = $2;
- /*% ripper: undef!($:2) %*/
+ nd_set_first_loc($list, @kw.beg_pos);
+ RNODE_UNDEF($list)->keyword_loc = @kw;
+ $$ = $list;
+ /*% ripper: undef!($:list) %*/
}
- | stmt modifier_if expr_value
+ | stmt[body] modifier_if[mod] expr_value[cond]
{
- $$ = new_if(p, $3, remove_begin($1), 0, &@$, &@2, &NULL_LOC, &NULL_LOC);
- fixpos($$, $3);
- /*% ripper: if_mod!($:3, $:1) %*/
+ $$ = new_if(p, $cond, remove_begin($body), 0, &@$, &@mod, &NULL_LOC, &NULL_LOC);
+ fixpos($$, $cond);
+ /*% ripper: if_mod!($:cond, $:body) %*/
}
- | stmt modifier_unless expr_value
+ | stmt[body] modifier_unless[mod] expr_value[cond]
{
- $$ = new_unless(p, $3, remove_begin($1), 0, &@$, &@2, &NULL_LOC, &NULL_LOC);
- fixpos($$, $3);
- /*% ripper: unless_mod!($:3, $:1) %*/
+ $$ = new_unless(p, $cond, remove_begin($body), 0, &@$, &@mod, &NULL_LOC, &NULL_LOC);
+ fixpos($$, $cond);
+ /*% ripper: unless_mod!($:cond, $:body) %*/
}
- | stmt modifier_while expr_value
+ | stmt[body] modifier_while[mod] expr_value[cond_expr]
{
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);
+ if ($body && nd_type_p($body, NODE_BEGIN)) {
+ $$ = NEW_WHILE(cond(p, $cond_expr, &@cond_expr), RNODE_BEGIN($body)->nd_body, 0, &@$, &@mod, &NULL_LOC);
}
else {
- $$ = NEW_WHILE(cond(p, $3, &@3), $1, 1, &@$, &@2, &NULL_LOC);
+ $$ = NEW_WHILE(cond(p, $cond_expr, &@cond_expr), $body, 1, &@$, &@mod, &NULL_LOC);
}
- /*% ripper: while_mod!($:3, $:1) %*/
+ /*% ripper: while_mod!($:cond_expr, $:body) %*/
}
- | stmt modifier_until expr_value
+ | stmt[body] modifier_until[mod] expr_value[cond_expr]
{
- 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);
+ clear_block_exit(p, 0);
+ if ($body && nd_type_p($body, NODE_BEGIN)) {
+ $$ = NEW_UNTIL(cond(p, $cond_expr, &@cond_expr), RNODE_BEGIN($body)->nd_body, 0, &@$, &@mod, &NULL_LOC);
}
else {
- $$ = NEW_UNTIL(cond(p, $3, &@3), $1, 1, &@$, &@2, &NULL_LOC);
+ $$ = NEW_UNTIL(cond(p, $cond_expr, &@cond_expr), $body, 1, &@$, &@mod, &NULL_LOC);
}
- /*% ripper: until_mod!($:3, $:1) %*/
+ /*% ripper: until_mod!($:cond_expr, $:body) %*/
}
- | stmt modifier_rescue after_rescue stmt
+ | stmt[body] modifier_rescue[mod] after_rescue[ctxt] stmt[resbody]
{
- p->ctxt.in_rescue = $3.in_rescue;
+ p->ctxt.in_rescue = $ctxt.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) %*/
+ YYLTYPE loc = code_loc_gen(&@mod, &@resbody);
+ resq = NEW_RESBODY(0, 0, remove_begin($resbody), 0, &loc);
+ $$ = NEW_RESCUE(remove_begin($body), resq, 0, &@$);
+ /*% ripper: rescue_mod!($:body, $:resbody) %*/
}
- | k_END allow_exits '{' compstmt(stmts) '}'
+ | k_END[k_end] block_open[lbrace] compstmt(stmts)[body] '}'[rbrace]
{
- if (p->ctxt.in_def) {
- rb_warn0("END in method; use at_exit");
- }
- restore_block_exit(p, $allow_exits);
- p->ctxt = $k_END;
+ clear_block_exit(p, true);
+ restore_block_exit(p, $block_open);
+ p->ctxt = $k_end;
{
- NODE *scope = NEW_SCOPE2(0 /* tbl */, 0 /* args */, $compstmt /* body */, &@$);
- $$ = NEW_POSTEXE(scope, &@$, &@1, &@3, &@5);
+ NODE *scope = NEW_SCOPE2(0 /* tbl */, 0 /* args */, $body /* body */, NULL /* parent */, &@$);
+ $$ = NEW_POSTEXE(scope, &@$, &@k_end, &@lbrace, &@rbrace);
+ RNODE_SCOPE(scope)->nd_parent = $$;
}
- /*% ripper: END!($:compstmt) %*/
+ /*% ripper: END!($:body) %*/
}
| command_asgn
- | mlhs '=' lex_ctxt command_call_value
+ | mlhs[lhs] '=' lex_ctxt[ctxt] command_call_value[rhs]
{
- $$ = node_assign(p, (NODE *)$1, $4, $3, &@$);
- /*% ripper: massign!($:1, $:4) %*/
+ $$ = node_assign(p, (NODE *)$lhs, $rhs, $ctxt, &@$);
+ /*% ripper: massign!($:lhs, $:rhs) %*/
}
| asgn(mrhs)
- | mlhs '=' lex_ctxt mrhs_arg modifier_rescue
- after_rescue stmt[resbody]
+ | mlhs[lhs] '=' lex_ctxt[lex_ctxt] mrhs_arg[mrhs_arg] modifier_rescue[modifier_rescue]
+ after_rescue[after_rescue] stmt[resbody]
{
- p->ctxt.in_rescue = $3.in_rescue;
+ p->ctxt.in_rescue = $after_rescue.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)) %*/
+ $$ = node_assign(p, (NODE *)$lhs, $mrhs_arg, $lex_ctxt, &@$);
+ /*% ripper: massign!($:lhs, rescue_mod!($:mrhs_arg, $:resbody)) %*/
}
- | mlhs '=' lex_ctxt mrhs_arg
+ | mlhs[lhs] '=' lex_ctxt[ctxt] mrhs_arg[rhs]
{
- $$ = node_assign(p, (NODE *)$1, $4, $3, &@$);
- /*% ripper: massign!($:1, $:4) %*/
+ $$ = node_assign(p, (NODE *)$lhs, $rhs, $ctxt, &@$);
+ /*% ripper: massign!($:lhs, $:rhs) %*/
}
| expr
| error
@@ -3442,29 +3455,29 @@ command_rhs : command_call_value %prec tOP_ASGN
;
expr : command_call
- | expr keyword_and expr
+ | expr[left] keyword_and[op] expr[right]
{
- $$ = logop(p, idAND, $1, $3, &@2, &@$);
- /*% ripper: binary!($:1, ID2VAL(idAND), $:3) %*/
+ $$ = logop(p, idAND, $left, $right, &@op, &@$);
+ /*% ripper: binary!($:left, ID2VAL(idAND), $:right) %*/
}
- | expr keyword_or expr
+ | expr[left] keyword_or[op] expr[right]
{
- $$ = logop(p, idOR, $1, $3, &@2, &@$);
- /*% ripper: binary!($:1, ID2VAL(idOR), $:3) %*/
+ $$ = logop(p, idOR, $left, $right, &@op, &@$);
+ /*% ripper: binary!($:left, ID2VAL(idOR), $:right) %*/
}
- | keyword_not '\n'? expr
+ | keyword_not[not] '\n'? expr[arg]
{
- $$ = call_uni_op(p, method_cond(p, $3, &@3), METHOD_NOT, &@1, &@$);
- /*% ripper: unary!(ID2VAL(idNOT), $:3) %*/
+ $$ = call_uni_op(p, method_cond(p, $arg, &@arg), METHOD_NOT, &@not, &@$);
+ /*% ripper: unary!(ID2VAL(idNOT), $:arg) %*/
}
- | '!' command_call
+ | '!'[not] command_call[arg]
{
- $$ = call_uni_op(p, method_cond(p, $2, &@2), '!', &@1, &@$);
- /*% ripper: unary!(ID2VAL('\'!\''), $:2) %*/
+ $$ = call_uni_op(p, method_cond(p, $arg, &@arg), '!', &@not, &@$);
+ /*% ripper: unary!(ID2VAL('\'!\''), $:arg) %*/
}
- | arg tASSOC
+ | arg tASSOC[assoc]
{
- value_expr($arg);
+ value_expr(p, $arg);
}
p_in_kwarg[ctxt] p_pvtbl p_pktbl
p_top_expr_body[body]
@@ -3472,12 +3485,14 @@ expr : command_call
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, &@2), &@$, &NULL_LOC, &NULL_LOC);
+ p->ctxt.in_alt_pattern = $ctxt.in_alt_pattern;
+ p->ctxt.capture_in_pattern = $ctxt.capture_in_pattern;
+ $$ = NEW_CASE3($arg, NEW_IN($body, 0, 0, &@body, &NULL_LOC, &NULL_LOC, &@assoc), &@$, &NULL_LOC, &NULL_LOC);
/*% ripper: case!($:arg, in!($:body, Qnil, Qnil)) %*/
}
| arg keyword_in
{
- value_expr($arg);
+ value_expr(p, $arg);
}
p_in_kwarg[ctxt] p_pvtbl p_pktbl
p_top_expr_body[body]
@@ -3485,6 +3500,8 @@ expr : command_call
pop_pktbl(p, $p_pktbl);
pop_pvtbl(p, $p_pvtbl);
p->ctxt.in_kwarg = $ctxt.in_kwarg;
+ p->ctxt.in_alt_pattern = $ctxt.in_alt_pattern;
+ p->ctxt.capture_in_pattern = $ctxt.capture_in_pattern;
$$ = NEW_CASE3($arg, NEW_IN($body, NEW_TRUE(&@body), NEW_FALSE(&@body), &@body, &@keyword_in, &NULL_LOC, &NULL_LOC), &@$, &NULL_LOC, &NULL_LOC);
/*% ripper: case!($:arg, in!($:body, Qnil, Qnil)) %*/
}
@@ -3675,7 +3692,7 @@ mlhs_basic : mlhs_head
$$ = NEW_MASGN($1, $3, &@$);
/*% ripper: mlhs_add_star!($:1, $:3) %*/
}
- | mlhs_head tSTAR mlhs_node ',' mlhs(mlhs_item)
+ | mlhs_head tSTAR mlhs_node ',' mlhs_items(mlhs_item)
{
$$ = NEW_MASGN($1, NEW_POSTARG($3,$5,&@$), &@$);
/*% ripper: mlhs_add_post!(mlhs_add_star!($:1, $:3), $:5) %*/
@@ -3685,7 +3702,7 @@ mlhs_basic : mlhs_head
$$ = NEW_MASGN($1, NODE_SPECIAL_NO_NAME_REST, &@$);
/*% ripper: mlhs_add_star!($:1, Qnil) %*/
}
- | mlhs_head tSTAR ',' mlhs(mlhs_item)
+ | mlhs_head tSTAR ',' mlhs_items(mlhs_item)
{
$$ = NEW_MASGN($1, NEW_POSTARG(NODE_SPECIAL_NO_NAME_REST, $4, &@$), &@$);
/*% ripper: mlhs_add_post!(mlhs_add_star!($:1, Qnil), $:4) %*/
@@ -3695,7 +3712,7 @@ mlhs_basic : mlhs_head
$$ = NEW_MASGN(0, $2, &@$);
/*% ripper: mlhs_add_star!(mlhs_new!, $:2) %*/
}
- | tSTAR mlhs_node ',' mlhs(mlhs_item)
+ | tSTAR mlhs_node ',' mlhs_items(mlhs_item)
{
$$ = NEW_MASGN(0, NEW_POSTARG($2,$4,&@$), &@$);
/*% ripper: mlhs_add_post!(mlhs_add_star!(mlhs_new!, $:2), $:4) %*/
@@ -3705,7 +3722,7 @@ mlhs_basic : mlhs_head
$$ = NEW_MASGN(0, NODE_SPECIAL_NO_NAME_REST, &@$);
/*% ripper: mlhs_add_star!(mlhs_new!, Qnil) %*/
}
- | tSTAR ',' mlhs(mlhs_item)
+ | tSTAR ',' mlhs_items(mlhs_item)
{
$$ = NEW_MASGN(0, NEW_POSTARG(NODE_SPECIAL_NO_NAME_REST, $3, &@$), &@$);
/*% ripper: mlhs_add_post!(mlhs_add_star!(mlhs_new!, Qnil), $:3) %*/
@@ -4052,7 +4069,7 @@ arg : asgn(arg_rhs)
ternary : arg '?' arg '\n'? ':' arg
{
- value_expr($1);
+ value_expr(p, $1);
$$ = new_if(p, $1, $3, $6, &@$, &NULL_LOC, &@5, &NULL_LOC);
fixpos($$, $1);
/*% ripper: ifop!($:1, $:3, $:6) %*/
@@ -4131,13 +4148,13 @@ aref_args : none
arg_rhs : arg %prec tOP_ASGN
{
- value_expr($1);
+ value_expr(p, $1);
$$ = $1;
}
| arg modifier_rescue after_rescue arg
{
p->ctxt.in_rescue = $3.in_rescue;
- value_expr($1);
+ value_expr(p, $1);
$$ = rescued_expr(p, $1, $4, &@1, &@2, &@4);
/*% ripper: rescue_mod!($:1, $:4) %*/
}
@@ -4197,6 +4214,11 @@ call_args : value_expr(command)
$$ = NEW_LIST($1, &@$);
/*% ripper: args_add!(args_new!, $:1) %*/
}
+ | def_endless_method(endless_command)
+ {
+ $$ = NEW_LIST($1, &@$);
+ /*% ripper: args_add!(args_new!, $:1) %*/
+ }
| args opt_block_arg
{
$$ = arg_blk_pass($1, $2);
@@ -4355,184 +4377,184 @@ mrhs : args ',' arg_value
primary : inline_primary
| var_ref
| backref
- | tFID
+ | tFID[fid]
{
- $$ = (NODE *)NEW_FCALL($1, 0, &@$);
- /*% ripper: method_add_arg!(fcall!($:1), args_new!) %*/
+ $$ = (NODE *)NEW_FCALL($fid, 0, &@$);
+ /*% ripper: method_add_arg!(fcall!($:fid), args_new!) %*/
}
- | k_begin
+ | k_begin[kw]
{
CMDARG_PUSH(0);
}
- bodystmt
- k_end
+ bodystmt[body]
+ k_end[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) %*/
+ set_line_body($body, @kw.end_pos.lineno);
+ $$ = NEW_BEGIN($body, &@$);
+ nd_set_line($$, @kw.end_pos.lineno);
+ /*% ripper: begin!($:body) %*/
}
- | tLPAREN_ARG compstmt(stmts) {SET_LEX_STATE(EXPR_ENDARG);} ')'
+ | tLPAREN_ARG compstmt(stmts)[body] {SET_LEX_STATE(EXPR_ENDARG);} ')'
{
- if (nd_type_p($2, NODE_SELF)) RNODE_SELF($2)->nd_state = 0;
- $$ = $2;
- /*% ripper: paren!($:2) %*/
+ if (nd_type_p($body, NODE_SELF)) RNODE_SELF($body)->nd_state = 0;
+ $$ = $body;
+ /*% ripper: paren!($:body) %*/
}
- | tLPAREN compstmt(stmts) ')'
+ | tLPAREN compstmt(stmts)[body] ')'
{
- if (nd_type_p($2, NODE_SELF)) RNODE_SELF($2)->nd_state = 0;
- $$ = NEW_BLOCK($2, &@$);
- /*% ripper: paren!($:2) %*/
+ if (nd_type_p($body, NODE_SELF)) RNODE_SELF($body)->nd_state = 0;
+ $$ = NEW_BLOCK($body, &@$);
+ /*% ripper: paren!($:body) %*/
}
- | primary_value tCOLON2 tCONSTANT
+ | primary_value[recv] tCOLON2[op] tCONSTANT[name]
{
- $$ = NEW_COLON2($1, $3, &@$, &@2, &@3);
- /*% ripper: const_path_ref!($:1, $:3) %*/
+ $$ = NEW_COLON2($recv, $name, &@$, &@op, &@name);
+ /*% ripper: const_path_ref!($:recv, $:name) %*/
}
- | tCOLON3 tCONSTANT
+ | tCOLON3[top] tCONSTANT[name]
{
- $$ = NEW_COLON3($2, &@$, &@1, &@2);
- /*% ripper: top_const_ref!($:2) %*/
+ $$ = NEW_COLON3($name, &@$, &@top, &@name);
+ /*% ripper: top_const_ref!($:name) %*/
}
- | tLBRACK aref_args ']'
+ | tLBRACK aref_args[args] ']'
{
- $$ = make_list($2, &@$);
- /*% ripper: array!($:2) %*/
+ $$ = make_list($args, &@$);
+ /*% ripper: array!($:args) %*/
}
- | tLBRACE assoc_list '}'
+ | tLBRACE assoc_list[list] '}'
{
- $$ = new_hash(p, $2, &@$);
+ $$ = new_hash(p, $list, &@$);
RNODE_HASH($$)->nd_brace = TRUE;
- /*% ripper: hash!($:2) %*/
+ /*% ripper: hash!($:list) %*/
}
- | k_return
+ | k_return[kw]
{
- $$ = NEW_RETURN(0, &@$, &@1);
+ $$ = NEW_RETURN(0, &@$, &@kw);
/*% ripper: return0! %*/
}
- | k_yield '(' call_args rparen
+ | k_yield[kw] '('[lpar] call_args[args] rparen[rpar]
{
- $$ = NEW_YIELD($3, &@$, &@1, &@2, &@4);
- /*% ripper: yield!(paren!($:3)) %*/
+ $$ = NEW_YIELD($args, &@$, &@kw, &@lpar, &@rpar);
+ /*% ripper: yield!(paren!($:args)) %*/
}
- | k_yield '(' rparen
+ | k_yield[kw] '('[lpar] rparen[rpar]
{
- $$ = NEW_YIELD(0, &@$, &@1, &@2, &@3);
+ $$ = NEW_YIELD(0, &@$, &@kw, &@lpar, &@rpar);
/*% ripper: yield!(paren!(args_new!)) %*/
}
- | k_yield
+ | k_yield[kw]
{
- $$ = NEW_YIELD(0, &@$, &@1, &NULL_LOC, &NULL_LOC);
+ $$ = NEW_YIELD(0, &@$, &@kw, &NULL_LOC, &NULL_LOC);
/*% ripper: yield0! %*/
}
- | keyword_defined '\n'? '(' begin_defined expr rparen
+ | keyword_defined[kw] '\n'? '(' begin_defined[ctxt] expr[arg] rparen
{
- p->ctxt.in_defined = $4.in_defined;
- $$ = new_defined(p, $5, &@$, &@1);
- p->ctxt.has_trailing_semicolon = $4.has_trailing_semicolon;
- /*% ripper: defined!($:5) %*/
+ p->ctxt.in_defined = $ctxt.in_defined;
+ $$ = new_defined(p, $arg, &@$, &@kw);
+ p->ctxt.has_trailing_semicolon = $ctxt.has_trailing_semicolon;
+ /*% ripper: defined!($:arg) %*/
}
- | keyword_not '(' expr rparen
+ | keyword_not[kw] '(' expr[arg] rparen
{
- $$ = call_uni_op(p, method_cond(p, $3, &@3), METHOD_NOT, &@1, &@$);
- /*% ripper: unary!(ID2VAL(idNOT), $:3) %*/
+ $$ = call_uni_op(p, method_cond(p, $arg, &@arg), METHOD_NOT, &@kw, &@$);
+ /*% ripper: unary!(ID2VAL(idNOT), $:arg) %*/
}
- | keyword_not '(' rparen
+ | keyword_not[kw] '('[lpar] rparen
{
- $$ = call_uni_op(p, method_cond(p, new_nil(&@2), &@2), METHOD_NOT, &@1, &@$);
+ $$ = call_uni_op(p, method_cond(p, NEW_NIL(&@lpar), &@lpar), METHOD_NOT, &@kw, &@$);
/*% ripper: unary!(ID2VAL(idNOT), Qnil) %*/
}
- | fcall brace_block
+ | fcall[call] brace_block[block]
{
- $$ = method_add_block(p, (NODE *)$1, $2, &@$);
- /*% ripper: method_add_block!(method_add_arg!(fcall!($:1), args_new!), $:2) %*/
+ $$ = method_add_block(p, (NODE *)$call, $block, &@$);
+ /*% ripper: method_add_block!(method_add_arg!(fcall!($:call), args_new!), $:block) %*/
}
| method_call
- | method_call brace_block
+ | method_call[call] brace_block[block]
{
- block_dup_check(p, get_nd_args(p, $1), $2);
- $$ = method_add_block(p, $1, $2, &@$);
- /*% ripper: method_add_block!($:1, $:2) %*/
+ block_dup_check(p, get_nd_args(p, $call), $block);
+ $$ = method_add_block(p, $call, $block, &@$);
+ /*% ripper: method_add_block!($:call, $:block) %*/
}
| lambda
- | k_if expr_value then
- compstmt(stmts)
- if_tail
- k_end
+ | k_if[kw] expr_value[cond] then[then]
+ compstmt(stmts)[body]
+ if_tail[tail]
+ k_end[k_end]
{
- if ($5 && nd_type_p($5, NODE_IF))
- RNODE_IF($5)->end_keyword_loc = @6;
+ if ($tail && nd_type_p($tail, NODE_IF))
+ RNODE_IF($tail)->end_keyword_loc = @k_end;
- $$ = new_if(p, $2, $4, $5, &@$, &@1, &@3, &@6);
- fixpos($$, $2);
- /*% ripper: if!($:2, $:4, $:5) %*/
+ $$ = new_if(p, $cond, $body, $tail, &@$, &@kw, &@then, &@k_end);
+ fixpos($$, $cond);
+ /*% ripper: if!($:cond, $:body, $:tail) %*/
}
- | k_unless expr_value then
- compstmt(stmts)
- opt_else
- k_end
+ | k_unless[kw] expr_value[cond] then[then]
+ compstmt(stmts)[body]
+ opt_else[tail]
+ k_end[k_end]
{
- $$ = new_unless(p, $2, $4, $5, &@$, &@1, &@3, &@6);
- fixpos($$, $2);
- /*% ripper: unless!($:2, $:4, $:5) %*/
+ $$ = new_unless(p, $cond, $body, $tail, &@$, &@kw, &@then, &@k_end);
+ fixpos($$, $cond);
+ /*% ripper: unless!($:cond, $:body, $:tail) %*/
}
- | k_while expr_value_do
- compstmt(stmts)
- k_end
+ | k_while[kw] expr_value_do[cond]
+ compstmt(stmts)[body]
+ k_end[k_end]
{
- restore_block_exit(p, $1);
- $$ = NEW_WHILE(cond(p, $2, &@2), $3, 1, &@$, &@1, &@4);
- fixpos($$, $2);
- /*% ripper: while!($:2, $:3) %*/
+ restore_block_exit(p, $kw);
+ $$ = NEW_WHILE(cond(p, $cond, &@cond), $body, 1, &@$, &@kw, &@k_end);
+ fixpos($$, $cond);
+ /*% ripper: while!($:cond, $:body) %*/
}
- | k_until expr_value_do
- compstmt(stmts)
- k_end
+ | k_until[kw] expr_value_do[cond]
+ compstmt(stmts)[body]
+ k_end[k_end]
{
- restore_block_exit(p, $1);
- $$ = NEW_UNTIL(cond(p, $2, &@2), $3, 1, &@$, &@1, &@4);
- fixpos($$, $2);
- /*% ripper: until!($:2, $:3) %*/
+ restore_block_exit(p, $kw);
+ $$ = NEW_UNTIL(cond(p, $cond, &@cond), $body, 1, &@$, &@kw, &@k_end);
+ fixpos($$, $cond);
+ /*% ripper: until!($:cond, $:body) %*/
}
- | k_case expr_value terms?
+ | k_case[k_case] expr_value[expr] terms?
{
$$ = p->case_labels;
p->case_labels = CHECK_LITERAL_WHEN;
- }<labels>
- case_body
- k_end
+ }[labels]<labels>
+ case_body[body]
+ k_end[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) %*/
+ p->case_labels = $labels;
+ $$ = NEW_CASE($expr, $body, &@$, &@k_case, &@k_end);
+ fixpos($$, $expr);
+ /*% ripper: case!($:expr, $:body) %*/
}
- | k_case terms?
+ | k_case[k_case] terms?
{
$$ = p->case_labels;
p->case_labels = 0;
- }<labels>
- case_body
- k_end
+ }[labels]<labels>
+ case_body[body]
+ k_end[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) %*/
+ p->case_labels = $labels;
+ $$ = NEW_CASE2($body, &@$, &@k_case, &@k_end);
+ /*% ripper: case!(Qnil, $:body) %*/
}
- | k_case expr_value terms?
- p_case_body
- k_end
+ | k_case[k_case] expr_value[expr] terms?
+ p_case_body[body]
+ k_end[k_end]
{
- $$ = NEW_CASE3($2, $4, &@$, &@1, &@5);
- /*% ripper: case!($:2, $:4) %*/
+ $$ = NEW_CASE3($expr, $body, &@$, &@k_case, &@k_end);
+ /*% ripper: case!($:expr, $:body) %*/
}
- | k_for for_var keyword_in
- {COND_PUSH(1);} expr_value do {COND_POP();}
- compstmt(stmts)
- k_end
+ | k_for[k_for] for_var[for_var] keyword_in[keyword_in]
+ {COND_PUSH(1);} expr_value[expr_value] do[do] {COND_POP();}
+ compstmt(stmts)[compstmt]
+ k_end[k_end]
{
restore_block_exit(p, $k_for);
/*
@@ -4559,17 +4581,18 @@ primary : inline_primary
m->nd_plen = 1;
m->nd_next = $for_var;
break;
- case NODE_MASGN: /* e.each {|*internal_var| a, b, c = (internal_var.length == 1 && Array === (tmp = internal_var[0]) ? tmp : internal_var); ... } */
+ 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, $for_var, NEW_FOR_MASGN(internal_var, &@for_var), NO_LEX_CTXT, &@for_var);
break;
- default: /* e.each {|*internal_var| @a, B, c[1], d.attr = internal_val; ... } */
+ default: /* e.each {|*internal_var| @a, B, c[1], d.attr = internal_val; ... } */
m->nd_next = node_assign(p, (NODE *)NEW_MASGN(NEW_LIST($for_var, &@for_var), 0, &@for_var), internal_var, NO_LEX_CTXT, &@for_var);
}
/* {|*internal_id| <m> = internal_id; ... } */
- args = new_args(p, m, 0, id, 0, new_args_tail(p, 0, 0, 0, &@for_var), &@for_var);
- scope = NEW_SCOPE2(tbl, args, $compstmt, &@$);
+ args = new_args(p, m, 0, id, 0, new_empty_args_tail(p, &@for_var), &@for_var);
+ scope = NEW_SCOPE2(tbl, args, $compstmt, NULL, &@$);
YYLTYPE do_keyword_loc = $do == keyword_do_cond ? @do : NULL_LOC;
- $$ = NEW_FOR($5, scope, &@$, &@k_for, &@keyword_in, &do_keyword_loc, &@k_end);
+ $$ = NEW_FOR($expr_value, scope, &@$, &@k_for, &@keyword_in, &do_keyword_loc, &@k_end);
+ RNODE_SCOPE(scope)->nd_parent = $$;
fixpos($$, $for_var);
/*% ripper: for!($:for_var, $:expr_value, $:compstmt) %*/
}
@@ -4603,7 +4626,7 @@ primary : inline_primary
bodystmt
k_end
{
- $$ = NEW_SCLASS($expr_value, $bodystmt, &@$);
+ $$ = NEW_SCLASS($expr_value, $bodystmt, &@$, &@k_class, &@tLSHFT, &@k_end);
nd_set_line(RNODE_SCLASS($$)->nd_body, @k_end.end_pos.lineno);
set_line_body($bodystmt, nd_line($expr_value));
fixpos($$, $expr_value);
@@ -4640,8 +4663,8 @@ primary : inline_primary
k_end
{
restore_defun(p, $head);
- $bodystmt = new_scope_body(p, $args, $bodystmt, &@$);
($$ = $head->nd_def)->nd_loc = @$;
+ $bodystmt = new_scope_body(p, $args, $bodystmt, $$, &@$);
RNODE_DEFN($$)->nd_defn = $bodystmt;
/*% ripper: def!($:head, $:args, $:bodystmt) %*/
local_pop(p);
@@ -4655,35 +4678,35 @@ primary : inline_primary
k_end
{
restore_defun(p, $head);
- $bodystmt = new_scope_body(p, $args, $bodystmt, &@$);
($$ = $head->nd_def)->nd_loc = @$;
+ $bodystmt = new_scope_body(p, $args, $bodystmt, $$, &@$);
RNODE_DEFS($$)->nd_defn = $bodystmt;
/*% ripper: defs!(*$:head[0..2], $:args, $:bodystmt) %*/
local_pop(p);
}
- | keyword_break
+ | keyword_break[kw]
{
- $$ = add_block_exit(p, NEW_BREAK(0, &@$, &@1));
+ $$ = add_block_exit(p, NEW_BREAK(0, &@$, &@kw));
/*% ripper: break!(args_new!) %*/
}
- | keyword_next
+ | keyword_next[kw]
{
- $$ = add_block_exit(p, NEW_NEXT(0, &@$, &@1));
+ $$ = add_block_exit(p, NEW_NEXT(0, &@$, &@kw));
/*% ripper: next!(args_new!) %*/
}
- | keyword_redo
+ | keyword_redo[kw]
{
- $$ = add_block_exit(p, NEW_REDO(&@$, &@1));
+ $$ = add_block_exit(p, NEW_REDO(&@$, &@kw));
/*% ripper: redo! %*/
}
- | keyword_retry
+ | keyword_retry[kw]
{
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;
+ case before_rescue: yyerror1(&@kw, "Invalid retry without rescue"); break;
+ case after_rescue: /* ok */ break;
+ case after_else: yyerror1(&@kw, "Invalid retry after else"); break;
+ case after_ensure: yyerror1(&@kw, "Invalid retry after ensure"); break;
}
}
$$ = NEW_RETRY(&@$);
@@ -4726,19 +4749,19 @@ k_unless : keyword_unless
}
;
-k_while : keyword_while allow_exits
+k_while : keyword_while[kw] allow_exits
{
$$ = $allow_exits;
token_info_push(p, "while", &@$);
- push_end_expect_token_locations(p, &@1.beg_pos);
+ push_end_expect_token_locations(p, &@kw.beg_pos);
}
;
-k_until : keyword_until allow_exits
+k_until : keyword_until[kw] allow_exits
{
$$ = $allow_exits;
token_info_push(p, "until", &@$);
- push_end_expect_token_locations(p, &@1.beg_pos);
+ push_end_expect_token_locations(p, &@kw.beg_pos);
}
;
@@ -4749,11 +4772,11 @@ k_case : keyword_case
}
;
-k_for : keyword_for allow_exits
+k_for : keyword_for[kw] allow_exits
{
$$ = $allow_exits;
token_info_push(p, "for", &@$);
- push_end_expect_token_locations(p, &@1.beg_pos);
+ push_end_expect_token_locations(p, &@kw.beg_pos);
}
;
@@ -4910,17 +4933,17 @@ f_marg : f_norm_arg
;
-f_margs : mlhs(f_marg)
+f_margs : mlhs_items(f_marg)
{
$$ = NEW_MASGN($1, 0, &@$);
/*% ripper: $:1 %*/
}
- | mlhs(f_marg) ',' f_rest_marg
+ | mlhs_items(f_marg) ',' f_rest_marg
{
$$ = NEW_MASGN($1, $3, &@$);
/*% ripper: mlhs_add_star!($:1, $:3) %*/
}
- | mlhs(f_marg) ',' f_rest_marg ',' mlhs(f_marg)
+ | mlhs_items(f_marg) ',' f_rest_marg ',' mlhs_items(f_marg)
{
$$ = NEW_MASGN($1, NEW_POSTARG($3, $5, &@$), &@$);
/*% ripper: mlhs_add_post!(mlhs_add_star!($:1, $:3), $:5) %*/
@@ -4930,7 +4953,7 @@ f_margs : mlhs(f_marg)
$$ = NEW_MASGN(0, $1, &@$);
/*% ripper: mlhs_add_star!(mlhs_new!, $:1) %*/
}
- | f_rest_marg ',' mlhs(f_marg)
+ | f_rest_marg ',' mlhs_items(f_marg)
{
$$ = NEW_MASGN(0, NEW_POSTARG($1, $3, &@$), &@$);
/*% ripper: mlhs_add_post!(mlhs_add_star!(mlhs_new!, $:1), $:3) %*/
@@ -4960,7 +4983,7 @@ f_any_kwrest : f_kwrest
f_eq : {p->ctxt.in_argdef = 0;} '=';
-block_args_tail : args_tail_basic(primary_value)
+block_args_tail : args_tail_basic(primary_value, none)
;
excessed_comma : ','
@@ -4971,82 +4994,19 @@ excessed_comma : ','
}
;
-block_param : f_arg ',' f_opt_arg(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_opt_arg(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_opt_arg(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_opt_arg(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_opt_arg(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_opt_arg(primary_value) ',' f_rest_arg ',' f_arg opt_args_tail(block_args_tail)
+block_param : args-list(primary_value, opt_args_tail(block_args_tail, none))
+ | f_arg[pre] excessed_comma
{
- $$ = new_args(p, 0, $1, $3, $5, $6, &@$);
- /*% ripper: params!(Qnil, $:1, $:3, $:5, *$:6[0..2]) %*/
+ $$ = new_empty_args_tail(p, &@excessed_comma);
+ $$ = new_args(p, $pre, 0, $excessed_comma, 0, $$, &@$);
+ /*% ripper: params!($:pre, Qnil, $:excessed_comma, Qnil, Qnil, Qnil, Qnil) %*/
}
- | f_opt_arg(primary_value) opt_args_tail(block_args_tail)
+ | f_arg[pre] opt_args_tail(block_args_tail, none)[tail]
{
- $$ = new_args(p, 0, $1, 0, 0, $2, &@$);
- /*% ripper: params!(Qnil, $:1, Qnil, Qnil, *$:2[0..2]) %*/
- }
- | f_opt_arg(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]) %*/
+ $$ = new_args(p, $pre, 0, 0, 0, $tail, &@$);
+ /*% ripper: params!($:pre, Qnil, Qnil, Qnil, *$:tail[0..2]) %*/
}
+ | tail-only-args(block_args_tail)
;
opt_block_param_def : none
@@ -5111,14 +5071,14 @@ numparam : {
;
it_id : {
- $$ = p->it_id;
- p->it_id = 0;
- }
- ;
+ $$ = p->it_id;
+ p->it_id = 0;
+ }
+ ;
lambda : tLAMBDA[lpar]
{
- token_info_push(p, "->", &@1);
+ token_info_push(p, "->", &@lpar);
$$ = dyna_push(p);
}[dyna]<vars>
max_numparam numparam it_id allow_exits
@@ -5137,11 +5097,11 @@ lambda : tLAMBDA[lpar]
CMDARG_POP();
$args = args_with_numbered(p, $args, max_numparam, it_id);
{
- YYLTYPE loc = code_loc_gen(&@args, &@body);
+ YYLTYPE loc = code_loc_gen(&@lpar, &@body);
$$ = NEW_LAMBDA($args, $body->node, &loc, &@lpar, &$body->opening_loc, &$body->closing_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);
+ nd_set_first_loc($$, @lpar.beg_pos);
xfree($body);
}
/*% ripper: lambda!($:args, $:body) %*/
@@ -5150,19 +5110,19 @@ lambda : tLAMBDA[lpar]
}
;
-f_larglist : '(' f_args opt_bv_decl ')'
+f_larglist : '(' f_largs[args] opt_bv_decl ')'
{
p->ctxt.in_argdef = 0;
- $$ = $f_args;
+ $$ = $args;
p->max_numparam = ORDINAL_PARAM;
- /*% ripper: paren!($:2) %*/
+ /*% ripper: paren!($:args) %*/
}
- | f_args
+ | f_largs[args]
{
p->ctxt.in_argdef = 0;
- if (!args_info_empty_p(&$1->nd_ainfo))
+ if (!args_info_empty_p(&$args->nd_ainfo))
p->max_numparam = ORDINAL_PARAM;
- $$ = $f_args;
+ $$ = $args;
}
;
@@ -5217,16 +5177,19 @@ block_call : command do_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) %*/
- }
+ /*% ripper: 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) %*/
}
+ | block_call call_op2 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) %*/
+ }
;
method_call : fcall paren_args
@@ -5385,6 +5348,8 @@ p_in_kwarg : {
SET_LEX_STATE(EXPR_BEG|EXPR_LABEL);
p->command_start = FALSE;
p->ctxt.in_kwarg = 1;
+ p->ctxt.in_alt_pattern = 0;
+ p->ctxt.capture_in_pattern = 0;
}
;
@@ -5395,6 +5360,8 @@ p_case_body : keyword_in
pop_pktbl(p, $p_pktbl);
pop_pvtbl(p, $p_pvtbl);
p->ctxt.in_kwarg = $ctxt.in_kwarg;
+ p->ctxt.in_alt_pattern = $ctxt.in_alt_pattern;
+ p->ctxt.capture_in_pattern = $ctxt.capture_in_pattern;
}
compstmt(stmts)
p_cases[cases]
@@ -5423,7 +5390,7 @@ p_top_expr : p_top_expr_body
}
;
-p_top_expr_body : p_expr
+p_top_expr_body : p_expr
| p_expr ','
{
$$ = new_array_pattern_tail(p, 0, 1, 0, 0, &@$);
@@ -5466,10 +5433,18 @@ p_as : p_expr tASSOC p_variable
| p_alt
;
-p_alt : p_alt '|' p_expr_basic
+p_alt : p_alt[left] '|'[alt]
+ {
+ p->ctxt.in_alt_pattern = 1;
+ }
+ p_expr_basic[right]
{
- $$ = NEW_OR($1, $3, &@$, &@2);
- /*% ripper: binary!($:1, ID2VAL(idOr), $:3) %*/
+ if (p->ctxt.capture_in_pattern) {
+ yyerror1(&@alt, "alternative pattern after variable capture");
+ }
+ p->ctxt.in_alt_pattern = 0;
+ $$ = NEW_OR($left, $right, &@$, &@alt);
+ /*% ripper: binary!($:left, ID2VAL(idOr), $:right) %*/
}
| p_expr_basic
;
@@ -5541,8 +5516,8 @@ p_expr_basic : p_value
| p_const '[' rbracket
{
$$ = new_array_pattern_tail(p, 0, 0, 0, 0, &@$);
- $$ = new_array_pattern(p, $1, 0, $$, &@$);
- /*% ripper: aryptn!($:1, Qnil, Qnil, Qnil) %*/
+ $$ = new_array_pattern(p, $p_const, 0, $$, &@$);
+ /*% ripper: aryptn!($:p_const, Qnil, Qnil, Qnil) %*/
}
| tLBRACK p_args rbracket
{
@@ -5768,7 +5743,7 @@ p_value : p_primitive
| p_const
;
-p_primitive : inline_primary
+p_primitive : inline_primary
| keyword_variable
{
if (!($$ = gettable(p, $1, &@$))) $$ = NEW_ERROR(&@$);
@@ -5890,7 +5865,8 @@ strings : string
{
if (!$1) {
$$ = NEW_STR(STRING_NEW0(), &@$);
- } else {
+ }
+ else {
$$ = evstr2dstr(p, $1);
}
/*% ripper: $:1 %*/
@@ -6031,7 +6007,7 @@ xstring_contents: /* none */
}
;
-regexp_contents: /* none */
+regexp_contents : /* none */
{
$$ = 0;
/*% ripper: regexp_new! %*/
@@ -6062,21 +6038,21 @@ regexp_contents: /* none */
}
;
-string_content : tSTRING_CONTENT
- /*% ripper[brace]: $:1 %*/
- | tSTRING_DVAR
+string_content : tSTRING_CONTENT[content]
+ /*% ripper[brace]: $:content %*/
+ | tSTRING_DVAR[state]
{
/* 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
+ }[strterm]<strterm>
+ string_dvar[dvar]
{
- p->lex.strterm = $2;
- $$ = NEW_EVSTR($3, &@$, &@1, &NULL_LOC);
- nd_set_line($$, @3.end_pos.lineno);
- /*% ripper: string_dvar!($:3) %*/
+ p->lex.strterm = $strterm;
+ $$ = NEW_EVSTR($dvar, &@$, &@state, &NULL_LOC);
+ nd_set_line($$, @dvar.end_pos.lineno);
+ /*% ripper: string_dvar!($:dvar) %*/
}
| tSTRING_DBEG[state]
{
@@ -6158,7 +6134,7 @@ numeric : simple_numeric
| tUMINUS_NUM simple_numeric %prec tLOWEST
{
$$ = $2;
- negate_lit(p, $$);
+ negate_lit(p, $$, &@$);
/*% ripper: unary!(ID2VAL(idUMinus), $:2) %*/
}
;
@@ -6178,14 +6154,14 @@ user_variable : ident_or_const
| 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_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);}
+ ;
var_ref : user_variable
{
@@ -6229,11 +6205,16 @@ superclass : '<'
;
f_opt_paren_args: f_paren_args
- | none
+ | f_empty_arg
{
p->ctxt.in_argdef = 0;
- $$ = new_args_tail(p, 0, 0, 0, &@0);
- $$ = new_args(p, 0, 0, 0, 0, $$, &@0);
+ }
+ ;
+
+f_empty_arg : /* none */
+ {
+ $$ = new_empty_args_tail(p, &@$);
+ $$ = new_args(p, 0, 0, 0, 0, $$, &@$);
/*% ripper: params!(Qnil, Qnil, Qnil, Qnil, Qnil, Qnil, Qnil) %*/
}
;
@@ -6266,109 +6247,117 @@ f_arglist : f_paren_args
}
;
-args_tail : args_tail_basic(arg_value)
+args_tail : args_tail_basic(arg_value, opt_comma)
| 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);
+ add_forwarding_args(p);
+ $$ = new_args_tail(p, 0, $args_forward, arg_FWD_BLOCK, &@args_forward);
$$->nd_ainfo.forwarding = 1;
- /*% ripper: [Qnil, $:1, Qnil] %*/
+ /*% ripper: [Qnil, $:args_forward, Qnil] %*/
}
;
-f_args : f_arg ',' f_opt_arg(arg_value) ',' f_rest_arg opt_args_tail(args_tail)
+largs_tail : args_tail_basic(arg_value, none)
+ | args_forward
{
- $$ = new_args(p, $1, $3, $5, 0, $6, &@$);
- /*% ripper: params!($:1, $:3, $:5, Qnil, *$:6[0..2]) %*/
+ yyerror1(&@args_forward, "unexpected ... in lambda argument");
+ $$ = new_args_tail(p, 0, 0, 0, &@args_forward);
+ $$->nd_ainfo.forwarding = 1;
+ /*% ripper: [Qnil, $:args_forward, Qnil] %*/
}
- | f_arg ',' f_opt_arg(arg_value) ',' f_rest_arg ',' f_arg opt_args_tail(args_tail)
+ ;
+
+%rule args-list(value, tail) <node_args>
+ : f_arg[pre] ',' f_opt_arg(value)[opt] ',' f_rest_arg[rest] tail
{
- $$ = new_args(p, $1, $3, $5, $7, $8, &@$);
- /*% ripper: params!($:1, $:3, $:5, $:7, *$:8[0..2]) %*/
+ $$ = new_args(p, $pre, $opt, $rest, 0, $tail, &@$);
+ /*% ripper: params!($:pre, $:opt, $:rest, Qnil, *$:tail[0..2]) %*/
}
- | f_arg ',' f_opt_arg(arg_value) opt_args_tail(args_tail)
+ | f_arg[pre] ',' f_opt_arg(value)[opt] ',' f_rest_arg[rest] ',' f_arg[post] tail
{
- $$ = new_args(p, $1, $3, 0, 0, $4, &@$);
- /*% ripper: params!($:1, $:3, Qnil, Qnil, *$:4[0..2]) %*/
+ $$ = new_args(p, $pre, $opt, $rest, $post, $tail, &@$);
+ /*% ripper: params!($:pre, $:opt, $:rest, $:post, *$:tail[0..2]) %*/
}
- | f_arg ',' f_opt_arg(arg_value) ',' f_arg opt_args_tail(args_tail)
+ | f_arg[pre] ',' f_opt_arg(value)[opt] tail
{
- $$ = new_args(p, $1, $3, 0, $5, $6, &@$);
- /*% ripper: params!($:1, $:3, Qnil, $:5, *$:6[0..2]) %*/
+ $$ = new_args(p, $pre, $opt, 0, 0, $tail, &@$);
+ /*% ripper: params!($:pre, $:opt, Qnil, Qnil, *$:tail[0..2]) %*/
}
- | f_arg ',' f_rest_arg opt_args_tail(args_tail)
+ | f_arg[pre] ',' f_opt_arg(value)[opt] ',' f_arg[post] tail
{
- $$ = new_args(p, $1, 0, $3, 0, $4, &@$);
- /*% ripper: params!($:1, Qnil, $:3, Qnil, *$:4[0..2]) %*/
+ $$ = new_args(p, $pre, $opt, 0, $post, $tail, &@$);
+ /*% ripper: params!($:pre, $:opt, Qnil, $:post, *$:tail[0..2]) %*/
}
- | f_arg ',' f_rest_arg ',' f_arg opt_args_tail(args_tail)
+ | f_arg[pre] ',' f_rest_arg[rest] tail
{
- $$ = new_args(p, $1, 0, $3, $5, $6, &@$);
- /*% ripper: params!($:1, Qnil, $:3, $:5, *$:6[0..2]) %*/
+ $$ = new_args(p, $pre, 0, $rest, 0, $tail, &@$);
+ /*% ripper: params!($:pre, Qnil, $:rest, Qnil, *$:tail[0..2]) %*/
}
- | f_arg opt_args_tail(args_tail)
+ | f_arg[pre] ',' f_rest_arg[rest] ',' f_arg[post] tail
{
- $$ = new_args(p, $1, 0, 0, 0, $2, &@$);
- /*% ripper: params!($:1, Qnil, Qnil, Qnil, *$:2[0..2]) %*/
+ $$ = new_args(p, $pre, 0, $rest, $post, $tail, &@$);
+ /*% ripper: params!($:pre, Qnil, $:rest, $:post, *$:tail[0..2]) %*/
}
- | f_opt_arg(arg_value) ',' f_rest_arg opt_args_tail(args_tail)
+ | f_opt_arg(value)[opt] ',' f_rest_arg[rest] tail
{
- $$ = new_args(p, 0, $1, $3, 0, $4, &@$);
- /*% ripper: params!(Qnil, $:1, $:3, Qnil, *$:4[0..2]) %*/
+ $$ = new_args(p, 0, $opt, $rest, 0, $tail, &@$);
+ /*% ripper: params!(Qnil, $:opt, $:rest, Qnil, *$:tail[0..2]) %*/
}
- | f_opt_arg(arg_value) ',' f_rest_arg ',' f_arg opt_args_tail(args_tail)
+ | f_opt_arg(value)[opt] ',' f_rest_arg[rest] ',' f_arg[post] tail
{
- $$ = new_args(p, 0, $1, $3, $5, $6, &@$);
- /*% ripper: params!(Qnil, $:1, $:3, $:5, *$:6[0..2]) %*/
+ $$ = new_args(p, 0, $opt, $rest, $post, $tail, &@$);
+ /*% ripper: params!(Qnil, $:opt, $:rest, $:post, *$:tail[0..2]) %*/
}
- | f_opt_arg(arg_value) opt_args_tail(args_tail)
+ | f_opt_arg(value)[opt] tail
{
- $$ = new_args(p, 0, $1, 0, 0, $2, &@$);
- /*% ripper: params!(Qnil, $:1, Qnil, Qnil, *$:2[0..2]) %*/
+ $$ = new_args(p, 0, $opt, 0, 0, $tail, &@$);
+ /*% ripper: params!(Qnil, $:opt, Qnil, Qnil, *$:tail[0..2]) %*/
}
- | f_opt_arg(arg_value) ',' f_arg opt_args_tail(args_tail)
+ | f_opt_arg(value)[opt] ',' f_arg[post] tail
{
- $$ = new_args(p, 0, $1, 0, $3, $4, &@$);
- /*% ripper: params!(Qnil, $:1, Qnil, $:3, *$:4[0..2]) %*/
+ $$ = new_args(p, 0, $opt, 0, $post, $tail, &@$);
+ /*% ripper: params!(Qnil, $:opt, Qnil, $:post, *$:tail[0..2]) %*/
}
- | f_rest_arg opt_args_tail(args_tail)
+ | f_rest_arg[rest] tail
{
- $$ = new_args(p, 0, 0, $1, 0, $2, &@$);
- /*% ripper: params!(Qnil, Qnil, $:1, Qnil, *$:2[0..2]) %*/
+ $$ = new_args(p, 0, 0, $rest, 0, $tail, &@$);
+ /*% ripper: params!(Qnil, Qnil, $:rest, Qnil, *$:tail[0..2]) %*/
}
- | f_rest_arg ',' f_arg opt_args_tail(args_tail)
+ | f_rest_arg[rest] ',' f_arg[post] tail
{
- $$ = new_args(p, 0, 0, $1, $3, $4, &@$);
- /*% ripper: params!(Qnil, Qnil, $:1, $:3, *$:4[0..2]) %*/
+ $$ = new_args(p, 0, 0, $rest, $post, $tail, &@$);
+ /*% ripper: params!(Qnil, Qnil, $:rest, $:post, *$:tail[0..2]) %*/
}
- | args_tail
+ ;
+
+%rule tail-only-args(tail) <node_args>
+ : tail
{
- $$ = new_args(p, 0, 0, 0, 0, $1, &@$);
- /*% ripper: params!(Qnil, Qnil, Qnil, Qnil, *$:1[0..2]) %*/
+ $$ = new_args(p, 0, 0, 0, 0, $tail, &@$);
+ /*% ripper: params!(Qnil, Qnil, Qnil, Qnil, *$:tail[0..2]) %*/
}
- | /* none */
+ ;
+
+%rule f_args-list(tail, trailing) <node_args>
+ : args-list(arg_value, opt_args_tail(tail, trailing))
+ | f_arg[pre] opt_args_tail(tail, trailing)[tail]
{
- $$ = 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) %*/
+ $$ = new_args(p, $pre, 0, 0, 0, $tail, &@$);
+ /*% ripper: params!($:pre, Qnil, Qnil, Qnil, *$:tail[0..2]) %*/
}
+ | tail-only-args(tail)
+ | f_empty_arg
+ ;
+
+f_args : f_args-list(args_tail, opt_comma)
+ ;
+
+f_largs : f_args-list(largs_tail, none)
;
args_forward : tBDOT3
{
-#ifdef FORWARD_ARGS_WITH_RUBY2_KEYWORDS
- $$ = 0;
-#else
$$ = idFWD_KWREST;
-#endif
/*% ripper: args_forward! %*/
}
;
@@ -6538,6 +6527,11 @@ f_block_arg : blkarg_mark tIDENTIFIER
$$ = $2;
/*% ripper: blockarg!($:2) %*/
}
+ | blkarg_mark keyword_nil
+ {
+ $$ = idNil;
+ /*% ripper: blockarg!(ID2VAL(idNil)) %*/
+ }
| blkarg_mark
{
arg_var(p, idFWD_BLOCK);
@@ -6546,12 +6540,11 @@ f_block_arg : blkarg_mark tIDENTIFIER
}
;
-opt_f_block_arg : ',' f_block_arg
+opt_comma : ','?
{
- $$ = $2;
- /*% ripper: $:2 %*/
+ $$ = 0;
+ /*% ripper: Qnil %*/
}
- | none
;
@@ -6915,7 +6908,8 @@ parser_dispatch_delayed_token(struct parser_params *p, enum yytokentype t, int l
if (p->keep_tokens) {
/* p->delayed.token is freed by rb_parser_tokens_free */
parser_append_tokens(p, p->delayed.token, t, line);
- } else {
+ }
+ else {
rb_parser_string_free(p, p->delayed.token);
}
@@ -6978,6 +6972,19 @@ is_identchar(struct parser_params *p, const char *ptr, const char *MAYBE_UNUSED(
return rb_enc_isalnum((unsigned char)*ptr, enc) || *ptr == '_' || !ISASCII(*ptr);
}
+static inline bool
+peek_word_at(struct parser_params *p, const char *str, size_t len, int at)
+{
+ const char *ptr = p->lex.pcur + at;
+ if (lex_eol_ptr_n_p(p, ptr, len-1)) return false;
+ if (memcmp(ptr, str, len)) return false;
+ if (lex_eol_ptr_n_p(p, ptr, len)) return true;
+ switch (ptr[len]) {
+ case '!': case '?': return false;
+ }
+ return !is_identchar(p, ptr+len, p->lex.pend, p->enc);
+}
+
static inline int
parser_is_identchar(struct parser_params *p)
{
@@ -7034,7 +7041,7 @@ token_info_pop(struct parser_params *p, const char *token, const rb_code_locatio
token_info_warn(p, token, ptinfo_beg, 1, loc);
p->token_info = ptinfo_beg->next;
- ruby_sized_xfree(ptinfo_beg, sizeof(*ptinfo_beg));
+ ruby_xfree_sized(ptinfo_beg, sizeof(*ptinfo_beg));
}
static void
@@ -7054,7 +7061,7 @@ token_info_drop(struct parser_params *p, const char *token, rb_code_position_t b
ptinfo_beg->token);
}
- ruby_sized_xfree(ptinfo_beg, sizeof(*ptinfo_beg));
+ ruby_xfree_sized(ptinfo_beg, sizeof(*ptinfo_beg));
}
static void
@@ -7306,9 +7313,9 @@ vtable_free_gen(struct parser_params *p, int line, const char *name,
#endif
if (!DVARS_TERMINAL_P(tbl)) {
if (tbl->tbl) {
- ruby_sized_xfree(tbl->tbl, tbl->capa * sizeof(ID));
+ ruby_xfree_sized(tbl->tbl, tbl->capa * sizeof(ID));
}
- ruby_sized_xfree(tbl, sizeof(*tbl));
+ ruby_xfree_sized(tbl, sizeof(*tbl));
}
}
#define vtable_free(tbl) vtable_free_gen(p, __LINE__, #tbl, tbl)
@@ -8921,7 +8928,6 @@ number_literal_suffix(struct parser_params *p, int mask)
}
if (!ISASCII(c) || ISALPHA(c) || c == '_') {
p->lex.pcur = lastp;
- literal_flush(p, p->lex.pcur);
return 0;
}
pushback(p, c);
@@ -10549,7 +10555,24 @@ parser_yylex(struct parser_params *p)
token_flush(p);
}
goto retry;
+ case 'a':
+ if (peek_word_at(p, "nd", 2, 0)) goto leading_logical;
+ goto bol;
+ case 'o':
+ if (peek_word_at(p, "r", 1, 0)) goto leading_logical;
+ goto bol;
+ case '|':
+ if (peek(p, '|')) goto leading_logical;
+ goto bol;
case '&':
+ if (peek(p, '&')) {
+ leading_logical:
+ pushback(p, c);
+ dispatch_delayed_token(p, tIGNORED_NL);
+ cmd_state = FALSE;
+ goto retry;
+ }
+ /* fall through */
case '.': {
dispatch_delayed_token(p, tIGNORED_NL);
if (peek(p, '.') == (c == '&')) {
@@ -10558,6 +10581,7 @@ parser_yylex(struct parser_params *p)
goto retry;
}
}
+ bol:
default:
p->ruby_sourceline--;
p->lex.nextline = p->lex.lastline;
@@ -11208,24 +11232,26 @@ node_newnode(struct parser_params *p, enum node_type type, size_t size, size_t a
#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_node_scope_new(struct parser_params *p, rb_node_args_t *nd_args, NODE *nd_body, NODE *nd_parent, 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_parent = nd_parent;
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_new2(struct parser_params *p, rb_ast_id_table_t *nd_tbl, rb_node_args_t *nd_args, NODE *nd_body, NODE *nd_parent, 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_parent = nd_parent;
n->nd_args = nd_args;
return n;
@@ -11413,8 +11439,9 @@ 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, const YYLTYPE *class_keyword_loc, const YYLTYPE *inheritance_operator_loc, const YYLTYPE *end_keyword_loc)
{
/* Keep the order of node creation */
- NODE *scope = NEW_SCOPE(0, nd_body, loc);
+ NODE *scope = NEW_SCOPE(0, nd_body, NULL, loc);
rb_node_class_t *n = NODE_NEWNODE(NODE_CLASS, rb_node_class_t, loc);
+ RNODE_SCOPE(scope)->nd_parent = &n->node;
n->nd_cpath = nd_cpath;
n->nd_body = scope;
n->nd_super = nd_super;
@@ -11426,13 +11453,17 @@ rb_node_class_new(struct parser_params *p, NODE *nd_cpath, NODE *nd_body, NODE *
}
static rb_node_sclass_t *
-rb_node_sclass_new(struct parser_params *p, NODE *nd_recv, NODE *nd_body, const YYLTYPE *loc)
+rb_node_sclass_new(struct parser_params *p, NODE *nd_recv, NODE *nd_body, const YYLTYPE *loc, const YYLTYPE *class_keyword_loc, const YYLTYPE *operator_loc, const YYLTYPE *end_keyword_loc)
{
/* Keep the order of node creation */
- NODE *scope = NEW_SCOPE(0, nd_body, loc);
+ NODE *scope = NEW_SCOPE(0, nd_body, NULL, loc);
rb_node_sclass_t *n = NODE_NEWNODE(NODE_SCLASS, rb_node_sclass_t, loc);
+ RNODE_SCOPE(scope)->nd_parent = &n->node;
n->nd_recv = nd_recv;
n->nd_body = scope;
+ n->class_keyword_loc = *class_keyword_loc;
+ n->operator_loc = *operator_loc;
+ n->end_keyword_loc = *end_keyword_loc;
return n;
}
@@ -11441,8 +11472,9 @@ static rb_node_module_t *
rb_node_module_new(struct parser_params *p, NODE *nd_cpath, NODE *nd_body, const YYLTYPE *loc, const YYLTYPE *module_keyword_loc, const YYLTYPE *end_keyword_loc)
{
/* Keep the order of node creation */
- NODE *scope = NEW_SCOPE(0, nd_body, loc);
+ NODE *scope = NEW_SCOPE(0, nd_body, NULL, loc);
rb_node_module_t *n = NODE_NEWNODE(NODE_MODULE, rb_node_module_t, loc);
+ RNODE_SCOPE(scope)->nd_parent = &n->node;
n->nd_cpath = nd_cpath;
n->nd_body = scope;
n->module_keyword_loc = *module_keyword_loc;
@@ -11455,8 +11487,9 @@ 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);
+ NODE *scope = NEW_SCOPE(nd_args, nd_body, NULL, loc);
rb_node_iter_t *n = NODE_NEWNODE(NODE_ITER, rb_node_iter_t, loc);
+ RNODE_SCOPE(scope)->nd_parent = &n->node;
n->nd_body = scope;
n->nd_iter = 0;
@@ -11467,9 +11500,10 @@ 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, const YYLTYPE *operator_loc, const YYLTYPE *opening_loc, const YYLTYPE *closing_loc)
{
/* Keep the order of node creation */
- NODE *scope = NEW_SCOPE(nd_args, nd_body, loc);
+ NODE *scope = NEW_SCOPE(nd_args, nd_body, NULL, loc);
YYLTYPE lambda_loc = code_loc_gen(operator_loc, closing_loc);
rb_node_lambda_t *n = NODE_NEWNODE(NODE_LAMBDA, rb_node_lambda_t, &lambda_loc);
+ RNODE_SCOPE(scope)->nd_parent = &n->node;
n->nd_body = scope;
n->operator_loc = *operator_loc;
n->opening_loc = *opening_loc;
@@ -11687,16 +11721,10 @@ rb_node_match3_new(struct parser_params *p, NODE *nd_recv, NODE *nd_value, const
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;
+ return rb_node_list_new2(p, nd_head, 1, 0, loc);
}
static rb_node_list_t *
@@ -12758,8 +12786,8 @@ call_bin_op(struct parser_params *p, NODE *recv, ID id, NODE *arg1,
const YYLTYPE *op_loc, const YYLTYPE *loc)
{
NODE *expr;
- value_expr(recv);
- value_expr(arg1);
+ value_expr(p, recv);
+ value_expr(p, arg1);
expr = NEW_OPCALL(recv, id, NEW_LIST(arg1, &arg1->nd_loc), loc);
nd_set_line(expr, op_loc->beg_pos.lineno);
return expr;
@@ -12769,7 +12797,7 @@ static NODE *
call_uni_op(struct parser_params *p, NODE *recv, ID id, const YYLTYPE *op_loc, const YYLTYPE *loc)
{
NODE *opcall;
- value_expr(recv);
+ value_expr(p, recv);
opcall = NEW_OPCALL(recv, id, 0, loc);
nd_set_line(opcall, op_loc->beg_pos.lineno);
return opcall;
@@ -12819,8 +12847,8 @@ match_op(struct parser_params *p, NODE *node1, NODE *node2, const YYLTYPE *op_lo
NODE *n;
int line = op_loc->beg_pos.lineno;
- value_expr(node1);
- value_expr(node2);
+ value_expr(p, node1);
+ value_expr(p, node2);
if ((n = last_expr_once_body(node1)) != 0) {
switch (nd_type(n)) {
@@ -12973,14 +13001,14 @@ gettable(struct parser_params *p, ID id, const YYLTYPE *loc)
}
# 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 (dyna_in_block(p) && id == idIt && !(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);
+ p->it_id = idItImplicit;
vtable_add(p->lvtbl->args, p->it_id);
}
NODE *node = NEW_DVAR(p->it_id, loc);
@@ -13776,7 +13804,9 @@ value_expr_check(struct parser_params *p, NODE *node)
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 (!vn || !(vn = value_expr_check(p, vn))) {
+ if (!RNODE_RESCUE(node)->nd_else) 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)) {
@@ -13784,8 +13814,7 @@ value_expr_check(struct parser_params *p, NODE *node)
return NULL;
}
if (!(vn = value_expr_check(p, RNODE_RESBODY(r)->nd_body))) {
- void_node = 0;
- break;
+ return NULL;
}
if (!void_node) void_node = vn;
}
@@ -13800,19 +13829,43 @@ value_expr_check(struct parser_params *p, NODE *node)
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;
+ case NODE_CASE:
+ case NODE_CASE2:
+ for (node = RNODE_CASE(node)->nd_body;
+ node && nd_type_p(node, NODE_WHEN);
+ node = RNODE_WHEN(node)->nd_next) {
+ if (!(vn = value_expr_check(p, RNODE_WHEN(node)->nd_body))) {
+ return NULL;
+ }
+ if (!void_node) void_node = vn;
}
- if (RNODE_IN(RNODE_CASE3(node)->nd_body)->nd_body) {
- return NULL;
+ break;
+
+ case NODE_CASE3:
+ {
+ NODE *in = RNODE_CASE3(node)->nd_body;
+ if (!in || !nd_type_p(in, NODE_IN)) {
+ compile_error(p, "unexpected node");
+ return NULL;
+ }
+ if (!RNODE_IN(in)->nd_body) {
+ /* single line pattern matching with "=>" operator */
+ goto found;
+ }
+ do {
+ vn = value_expr_check(p, RNODE_IN(in)->nd_body);
+ if (!vn) return NULL;
+ if (!void_node) void_node = vn;
+ in = RNODE_IN(in)->nd_next;
+ } while (in && nd_type_p(in, NODE_IN));
+ node = in; /* else */
}
- /* single line pattern matching with "=>" operator */
- goto found;
+ break;
case NODE_BLOCK:
while (RNODE_BLOCK(node)->nd_next) {
+ vn = value_expr_check(p, RNODE_BLOCK(node)->nd_head);
+ if (vn) return vn;
node = RNODE_BLOCK(node)->nd_next;
}
node = RNODE_BLOCK(node)->nd_head;
@@ -13860,7 +13913,7 @@ value_expr_check(struct parser_params *p, NODE *node)
}
static int
-value_expr_gen(struct parser_params *p, NODE *node)
+value_expr(struct parser_params *p, NODE *node)
{
NODE *void_node = value_expr_check(p, node);
if (void_node) {
@@ -14129,7 +14182,7 @@ range_op(struct parser_params *p, NODE *node, const YYLTYPE *loc)
if (node == 0) return 0;
type = nd_type(node);
- value_expr(node);
+ value_expr(p, node);
if (type == NODE_INTEGER) {
if (!e_option_supplied(p)) rb_warn0L(nd_line(node), "integer literal in flip-flop");
ID lineno = rb_intern("$.");
@@ -14266,7 +14319,7 @@ logop(struct parser_params *p, ID id, NODE *left, NODE *right,
{
enum node_type type = id == idAND || id == idANDOP ? NODE_AND : NODE_OR;
NODE *op;
- value_expr(left);
+ value_expr(p, 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)) {
@@ -14305,7 +14358,7 @@ ret_args(struct parser_params *p, NODE *node)
}
static NODE*
-negate_lit(struct parser_params *p, NODE* node)
+negate_lit(struct parser_params *p, NODE* node, const YYLTYPE *loc)
{
switch (nd_type(node)) {
case NODE_INTEGER:
@@ -14321,6 +14374,7 @@ negate_lit(struct parser_params *p, NODE* node)
RNODE_IMAGINARY(node)->minus = TRUE;
break;
}
+ node->nd_loc = *loc;
return node;
}
@@ -14374,12 +14428,6 @@ new_args(struct parser_params *p, rb_node_args_aux_t *pre_args, rb_node_opt_arg_
args->opt_args = opt_args;
-#ifdef FORWARD_ARGS_WITH_RUBY2_KEYWORDS
- args->ruby2_keywords = args->forwarding;
-#else
- args->ruby2_keywords = 0;
-#endif
-
nd_set_loc(RNODE(tail), loc);
return tail;
@@ -14392,6 +14440,10 @@ new_args_tail(struct parser_params *p, rb_node_kw_arg_t *kw_args, ID kw_rest_arg
struct rb_args_info *args = &node->nd_ainfo;
if (p->error_p) return node;
+ if (block == idNil) {
+ block = 0;
+ args->no_blockarg = TRUE;
+ }
args->block_arg = block;
args->kw_args = kw_args;
@@ -14448,7 +14500,7 @@ args_with_numbered(struct parser_params *p, rb_node_args_t *args, int max_numpar
if (max_numparam > NO_PARAM || it_id) {
if (!args) {
YYLTYPE loc = RUBY_INIT_YYLLOC();
- args = new_args_tail(p, 0, 0, 0, 0);
+ args = new_empty_args_tail(p, 0);
nd_set_loc(RNODE(args), &loc);
}
args->nd_ainfo.pre_args_num = it_id ? 1 : max_numparam;
@@ -14653,7 +14705,11 @@ error_duplicate_pattern_variable(struct parser_params *p, ID id, const YYLTYPE *
if (st_is_member(p->pvtbl, id)) {
yyerror1(loc, "duplicated variable name");
}
+ else if (p->ctxt.in_alt_pattern && id) {
+ yyerror1(loc, "variable capture in alternative pattern");
+ }
else {
+ p->ctxt.capture_in_pattern = 1;
st_insert(p->pvtbl, (st_data_t)id, 0);
}
}
@@ -14862,7 +14918,7 @@ local_free(struct parser_params *p, struct local_vars *local)
vtable_chain_free(p, local->args);
vtable_chain_free(p, local->vars);
- ruby_sized_xfree(local, sizeof(struct local_vars));
+ ruby_xfree_sized(local, sizeof(struct local_vars));
}
static void
@@ -14985,9 +15041,7 @@ static void
add_forwarding_args(struct parser_params *p)
{
arg_var(p, idFWD_REST);
-#ifndef FORWARD_ARGS_WITH_RUBY2_KEYWORDS
arg_var(p, idFWD_KWREST);
-#endif
arg_var(p, idFWD_BLOCK);
arg_var(p, idFWD_ALL);
}
@@ -15030,15 +15084,11 @@ static NODE *
new_args_forward_call(struct parser_params *p, NODE *leading, const YYLTYPE *loc, const YYLTYPE *argsloc)
{
NODE *rest = NEW_LVAR(idFWD_REST, 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;
-#ifndef FORWARD_ARGS_WITH_RUBY2_KEYWORDS
args = arg_append(p, args, new_hash(p, kwrest, loc), argsloc);
-#endif
return arg_blk_pass(args, block);
}
@@ -15127,7 +15177,7 @@ dyna_pop(struct parser_params *p, const struct vtable *lvargs)
dyna_pop_1(p);
if (!p->lvtbl->args) {
struct local_vars *local = p->lvtbl->prev;
- ruby_sized_xfree(p->lvtbl, sizeof(*p->lvtbl));
+ ruby_xfree_sized(p->lvtbl, sizeof(*p->lvtbl));
p->lvtbl = local;
}
}
@@ -15517,7 +15567,7 @@ rb_ruby_parser_free(void *ptr)
#endif
if (p->tokenbuf) {
- ruby_sized_xfree(p->tokenbuf, p->toksiz);
+ ruby_xfree_sized(p->tokenbuf, p->toksiz);
}
for (local = p->lvtbl; local; local = prev) {
diff --git a/parser_bits.h b/parser_bits.h
index ca7535280e..f894dde33e 100644
--- a/parser_bits.h
+++ b/parser_bits.h
@@ -30,13 +30,13 @@
#include <stdint.h> /* for uintptr_t */
#include "internal/compilers.h" /* for MSC_VERSION_SINCE */
-#if MSC_VERSION_SINCE(1310)
+#ifdef _MSC_VER
# include <stdlib.h> /* for _byteswap_uint64 */
#endif
#if defined(HAVE_X86INTRIN_H)
# include <x86intrin.h> /* for _lzcnt_u64 */
-#elif MSC_VERSION_SINCE(1310)
+#elif defined(_MSC_VER)
# include <intrin.h> /* for the following intrinsics */
#endif
@@ -50,16 +50,13 @@
# pragma intrinsic(__lzcnt64)
#endif
-#if MSC_VERSION_SINCE(1310)
+#if defined(_MSC_VER)
# 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
@@ -90,6 +87,7 @@
#define UNSIGNED_INTEGER_MAX(T) ((T)~(T)0)
+#ifndef MUL_OVERFLOW_SIGNED_INTEGER_P
#if __has_builtin(__builtin_mul_overflow_p)
# define MUL_OVERFLOW_P(a, b) \
__builtin_mul_overflow_p((a), (b), (__typeof__(a * b))0)
@@ -118,15 +116,100 @@
MUL_OVERFLOW_SIGNED_INTEGER_P(a, b, FIXNUM_MIN, FIXNUM_MAX)
#endif
-#ifdef MUL_OVERFLOW_P
+#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_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
+#endif
+
+#ifndef ADD_OVERFLOW_SIGNED_INTEGER_P
+#if __has_builtin(__builtin_add_overflow_p)
+# define ADD_OVERFLOW_P(a, b) \
+ __builtin_add_overflow_p((a), (b), (__typeof__(a * b))0)
+#elif __has_builtin(__builtin_add_overflow)
+# define ADD_OVERFLOW_P(a, b) \
+ __extension__ ({ __typeof__(a) c; __builtin_add_overflow((a), (b), &c); })
+#endif
+
+#define ADD_OVERFLOW_SIGNED_INTEGER_P(a, b, min, max) ( \
+ (a) > 0 ? (b) > (max) - (a) : (b) < (min) - (a))
+
+#if __has_builtin(__builtin_add_overflow_p)
+/* __builtin_add_overflow_p can take bitfield */
+/* and GCC permits bitfields for integers other than int */
+# define ADD_OVERFLOW_FIXNUM_P(a, b) \
+ __extension__ ({ \
+ struct { long fixnum : sizeof(long) * CHAR_BIT - 1; } c = { 0 }; \
+ __builtin_add_overflow_p((a), (b), c.fixnum); \
+ })
+#else
+# define ADD_OVERFLOW_FIXNUM_P(a, b) \
+ ADD_OVERFLOW_SIGNED_INTEGER_P(a, b, FIXNUM_MIN, FIXNUM_MAX)
+#endif
+
+#if defined(ADD_OVERFLOW_P) && defined(USE___BUILTIN_ADD_OVERFLOW_LONG_LONG)
+# define ADD_OVERFLOW_LONG_LONG_P(a, b) ADD_OVERFLOW_P(a, b)
+#else
+# define ADD_OVERFLOW_LONG_LONG_P(a, b) ADD_OVERFLOW_SIGNED_INTEGER_P(a, b, LLONG_MIN, LLONG_MAX)
+#endif
+
+#ifdef ADD_OVERFLOW_P
+# define ADD_OVERFLOW_LONG_P(a, b) ADD_OVERFLOW_P(a, b)
+# define ADD_OVERFLOW_INT_P(a, b) ADD_OVERFLOW_P(a, b)
+#else
+# define ADD_OVERFLOW_LONG_P(a, b) ADD_OVERFLOW_SIGNED_INTEGER_P(a, b, LONG_MIN, LONG_MAX)
+# define ADD_OVERFLOW_INT_P(a, b) ADD_OVERFLOW_SIGNED_INTEGER_P(a, b, INT_MIN, INT_MAX)
+#endif
+#endif
+
+#ifndef SUB_OVERFLOW_SIGNED_INTEGER_P
+#if __has_builtin(__builtin_sub_overflow_p)
+# define SUB_OVERFLOW_P(a, b) \
+ __builtin_sub_overflow_p((a), (b), (__typeof__(a * b))0)
+#elif __has_builtin(__builtin_sub_overflow)
+# define SUB_OVERFLOW_P(a, b) \
+ __extension__ ({ __typeof__(a) c; __builtin_sub_overflow((a), (b), &c); })
+#endif
+
+#define SUB_OVERFLOW_SIGNED_INTEGER_P(a, b, min, max) ( \
+ (b) > 0 ? (a) < (min) + (b) : (a) > (max) + (b))
+
+#if __has_builtin(__builtin_sub_overflow_p)
+/* __builtin_sub_overflow_p can take bitfield */
+/* and GCC permits bitfields for integers other than int */
+# define SUB_OVERFLOW_FIXNUM_P(a, b) \
+ __extension__ ({ \
+ struct { long fixnum : sizeof(long) * CHAR_BIT - 1; } c = { 0 }; \
+ __builtin_sub_overflow_p((a), (b), c.fixnum); \
+ })
+#else
+# define SUB_OVERFLOW_FIXNUM_P(a, b) \
+ SUB_OVERFLOW_SIGNED_INTEGER_P(a, b, FIXNUM_MIN, FIXNUM_MAX)
+#endif
+
+#if defined(SUB_OVERFLOW_P) && defined(USE___BUILTIN_SUB_OVERFLOW_LONG_LONG)
+# define SUB_OVERFLOW_LONG_LONG_P(a, b) SUB_OVERFLOW_P(a, b)
+#else
+# define SUB_OVERFLOW_LONG_LONG_P(a, b) SUB_OVERFLOW_SIGNED_INTEGER_P(a, b, LLONG_MIN, LLONG_MAX)
+#endif
+
+#ifdef SUB_OVERFLOW_P
+# define SUB_OVERFLOW_LONG_P(a, b) SUB_OVERFLOW_P(a, b)
+# define SUB_OVERFLOW_INT_P(a, b) SUB_OVERFLOW_P(a, b)
+#else
+# define SUB_OVERFLOW_LONG_P(a, b) SUB_OVERFLOW_SIGNED_INTEGER_P(a, b, LONG_MIN, LONG_MAX)
+# define SUB_OVERFLOW_INT_P(a, b) SUB_OVERFLOW_SIGNED_INTEGER_P(a, b, INT_MIN, INT_MAX)
+#endif
+#endif
#ifdef HAVE_UINT128_T
# define bit_length(x) \
@@ -180,7 +263,7 @@ ruby_swap16(uint16_t x)
#if __has_builtin(__builtin_bswap16)
return __builtin_bswap16(x);
-#elif MSC_VERSION_SINCE(1310)
+#elif defined(_MSC_VER)
return _byteswap_ushort(x);
#else
@@ -195,7 +278,7 @@ ruby_swap32(uint32_t x)
#if __has_builtin(__builtin_bswap32)
return __builtin_bswap32(x);
-#elif MSC_VERSION_SINCE(1310)
+#elif defined(_MSC_VER)
return _byteswap_ulong(x);
#else
@@ -212,7 +295,7 @@ ruby_swap64(uint64_t x)
#if __has_builtin(__builtin_bswap64)
return __builtin_bswap64(x);
-#elif MSC_VERSION_SINCE(1310)
+#elif defined(_MSC_VER)
return _byteswap_uint64(x);
#else
@@ -237,7 +320,7 @@ nlz_int32(uint32_t x)
#elif defined(__x86_64__) && defined(__LZCNT__)
return (unsigned int)_lzcnt_u32(x);
-#elif MSC_VERSION_SINCE(1400) /* &&! defined(__AVX2__) */
+#elif defined(_MSC_VER) /* &&! defined(__AVX2__) */
unsigned long r;
return _BitScanReverse(&r, x) ? (31 - (int)r) : 32;
@@ -266,7 +349,7 @@ nlz_int64(uint64_t x)
#elif defined(__x86_64__) && defined(__LZCNT__)
return (unsigned int)_lzcnt_u64(x);
-#elif defined(_WIN64) && MSC_VERSION_SINCE(1400) /* &&! defined(__AVX2__) */
+#elif defined(_WIN64) && defined(_MSC_VER) /* &&! defined(__AVX2__) */
unsigned long r;
return _BitScanReverse64(&r, x) ? (63u - (unsigned int)r) : 64;
@@ -394,9 +477,9 @@ rb_popcount32(uint32_t 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);
+ x = (x & 0x07070707) + (x >> 4 & 0x07070707);
+ x = (x & 0x000f000f) + (x >> 8 & 0x000f000f);
+ x = (x & 0x0000001f) + (x >>16 & 0x0000001f);
return (unsigned int)x;
#endif
@@ -424,9 +507,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 & 0x001f001f001f001f) + (x >> 8 & 0x001f001f001f001f);
- x = (x & 0x0000003f0000003f) + (x >>16 & 0x0000003f0000003f);
- x = (x & 0x000000000000007f) + (x >>32 & 0x000000000000007f);
+ x = (x & 0x000f000f000f000f) + (x >> 8 & 0x000f000f000f000f);
+ x = (x & 0x0000001f0000001f) + (x >>16 & 0x0000001f0000001f);
+ x = (x & 0x000000000000003f) + (x >>32 & 0x000000000000003f);
return (unsigned int)x;
#endif
@@ -452,7 +535,7 @@ ntz_int32(uint32_t x)
#if defined(__x86_64__) && defined(__BMI__)
return (unsigned)_tzcnt_u32(x);
-#elif MSC_VERSION_SINCE(1400)
+#elif defined(_MSC_VER)
/* :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;
@@ -474,7 +557,7 @@ ntz_int64(uint64_t x)
#if defined(__x86_64__) && defined(__BMI__)
return (unsigned)_tzcnt_u64(x);
-#elif defined(_WIN64) && MSC_VERSION_SINCE(1400)
+#elif defined(_WIN64) && defined(_MSC_VER)
unsigned long r;
return _BitScanForward64(&r, x) ? (int)r : 64;
@@ -522,10 +605,10 @@ RUBY_BIT_ROTL(VALUE v, int 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)
+#elif defined(_MSC_VER) && (SIZEOF_VALUE * CHAR_BIT == 32)
return _rotl(v, n);
-#elif MSC_VERSION_SINCE(1310) && (SIZEOF_VALUE * CHAR_BIT == 64)
+#elif defined(_MSC_VER) && (SIZEOF_VALUE * CHAR_BIT == 64)
return _rotl64(v, n);
#elif defined(_lrotl) && (SIZEOF_VALUE == SIZEOF_LONG)
@@ -546,10 +629,10 @@ RUBY_BIT_ROTR(VALUE v, int 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)
+#elif defined(_MSC_VER) && (SIZEOF_VALUE * CHAR_BIT == 32)
return _rotr(v, n);
-#elif MSC_VERSION_SINCE(1310) && (SIZEOF_VALUE * CHAR_BIT == 64)
+#elif defined(_MSC_VER) && (SIZEOF_VALUE * CHAR_BIT == 64)
return _rotr64(v, n);
#elif defined(_lrotr) && (SIZEOF_VALUE == SIZEOF_LONG)
diff --git a/parser_st.c b/parser_st.c
index c234026122..77d9df702e 100644
--- a/parser_st.c
+++ b/parser_st.c
@@ -80,6 +80,12 @@ nonempty_memcpy(void *dest, const void *src, size_t n)
#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_init_existing_strtable_with_size
+#define st_init_existing_strtable_with_size rb_parser_st_init_existing_strtable_with_size
+#undef st_init_existing_numtable_with_size
+#define st_init_existing_numtable_with_size rb_parser_st_init_existing_numtable_with_size
+#undef st_free_embedded_table
+#define st_free_embedded_table rb_parser_st_free_embedded_table
#undef st_insert
#define st_insert rb_parser_st_insert
#undef st_lookup
diff --git a/parser_st.h b/parser_st.h
index 877b1e9051..007ebb1bd4 100644
--- a/parser_st.h
+++ b/parser_st.h
@@ -88,13 +88,12 @@ struct parser_st_table {
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. */
+ /* Array of size 2^entry_power.
+ Optionnally followed by an array of bins used for access by keys. */
parser_st_table_entry *entries;
};
diff --git a/pathname.c b/pathname.c
index 64bed3d598..b12f640373 100644
--- a/pathname.c
+++ b/pathname.c
@@ -1,77 +1,30 @@
#include "ruby.h"
-#include "ruby/encoding.h"
+#include "internal.h"
+#include "internal/file.h"
+#include "internal/string.h"
+#include "internal/vm.h"
+
+#if defined __CYGWIN__ || defined DOSISH
+# define drive_letter 1
+# define alt_separator 1
+# define isdirsep(x) ((x) == '/' || (x) == '\\')
+#else
+# define drive_letter 0
+# define alt_separator 0
+# define isdirsep(x) ((x) == '/')
+#endif
static VALUE rb_cPathname;
-static ID id_ENOTDIR;
static ID id_at_path;
-static ID id_atime;
-static ID id_base;
-static ID id_basename;
-static ID id_binread;
-static ID id_binwrite;
-static ID id_birthtime;
-static ID id_blockdev_p;
-static ID id_chardev_p;
-static ID id_chmod;
-static ID id_chown;
-static ID id_ctime;
-static ID id_directory_p;
-static ID id_dirname;
-static ID id_empty_p;
-static ID id_entries;
-static ID id_executable_p;
-static ID id_executable_real_p;
-static ID id_exist_p;
-static ID id_expand_path;
-static ID id_extname;
-static ID id_file_p;
-static ID id_fnmatch;
-static ID id_foreach;
-static ID id_ftype;
-static ID id_getwd;
-static ID id_glob;
-static ID id_grpowned_p;
-static ID id_lchmod;
-static ID id_lchown;
-static ID id_link;
-static ID id_lstat;
-static ID id_lutime;
-static ID id_mkdir;
-static ID id_mtime;
-static ID id_open;
-static ID id_owned_p;
-static ID id_pipe_p;
-static ID id_read;
-static ID id_readable_p;
-static ID id_readable_real_p;
-static ID id_readlines;
-static ID id_readlink;
-static ID id_realdirpath;
-static ID id_realpath;
-static ID id_rename;
-static ID id_rmdir;
-static ID id_setgid_p;
-static ID id_setuid_p;
-static ID id_size;
-static ID id_size_p;
-static ID id_socket_p;
-static ID id_split;
-static ID id_stat;
-static ID id_sticky_p;
static ID id_sub;
-static ID id_symlink;
-static ID id_symlink_p;
-static ID id_sysopen;
-static ID id_to_path;
-static ID id_truncate;
-static ID id_unlink;
-static ID id_utime;
-static ID id_world_readable_p;
-static ID id_world_writable_p;
-static ID id_writable_p;
-static ID id_writable_real_p;
-static ID id_write;
-static ID id_zero_p;
+
+static VALUE
+check_strpath(VALUE path)
+{
+ Check_Type(path, T_STRING);
+ rb_get_path_check_no_convert(path);
+ return path;
+}
static VALUE
get_strpath(VALUE obj)
@@ -80,82 +33,37 @@ get_strpath(VALUE obj)
strpath = rb_ivar_get(obj, id_at_path);
if (!RB_TYPE_P(strpath, T_STRING))
rb_raise(rb_eTypeError, "unexpected @path");
+ rb_get_path_check_no_convert(strpath);
return strpath;
}
-static void
-set_strpath(VALUE obj, VALUE val)
-{
- rb_ivar_set(obj, id_at_path, val);
-}
-
-/*
- * Create a Pathname object from the given String (or String-like object).
- * If +path+ contains a NULL character (<tt>\0</tt>), an ArgumentError is raised.
- */
-static VALUE
-path_initialize(VALUE self, VALUE arg)
-{
- VALUE str;
- if (RB_TYPE_P(arg, T_STRING)) {
- str = arg;
- }
- else {
- str = rb_check_funcall(arg, id_to_path, 0, NULL);
- if (str == Qundef)
- str = arg;
- StringValue(str);
- }
- if (memchr(RSTRING_PTR(str), '\0', RSTRING_LEN(str)))
- rb_raise(rb_eArgError, "pathname contains null byte");
- str = rb_obj_dup(str);
-
- set_strpath(self, str);
- return self;
-}
-
/*
* call-seq:
- * pathname.freeze -> obj
+ * self <=> other -> -1, 0, 1, or nil
*
- * Freezes this Pathname.
+ * Compares the contents of +self+ and +other+ as strings;
+ * see String#<=>.
*
- * See Object.freeze.
- */
-static VALUE
-path_freeze(VALUE self)
-{
- rb_call_super(0, 0);
- rb_str_freeze(get_strpath(self));
- 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.
- */
-static VALUE
-path_eq(VALUE self, VALUE other)
-{
- if (!rb_obj_is_kind_of(other, rb_cPathname))
- return Qfalse;
- return rb_str_equal(get_strpath(self), get_strpath(other));
-}
-
-/*
- * Provides a case-sensitive comparison operator for pathnames.
+ * Returns:
*
- * Pathname.new('/usr') <=> Pathname.new('/usr/bin')
- * #=> -1
- * Pathname.new('/usr/bin') <=> Pathname.new('/usr/bin')
- * #=> 0
- * Pathname.new('/usr/bin') <=> Pathname.new('/USR/BIN')
- * #=> 1
+ * - <tt>-1</tt> if +self+'s string is smaller than +other+'s string.
+ * - <tt>0</tt> if the two are equal.
+ * - <tt>1</tt> if +self+'s string is larger than +other+'s string.
+ * - <tt>nil</tt> if +other+ is not a \Pathname.
+ *
+ * Examples:
+ *
+ * Pathname('a') <=> Pathname('b') # => -1
+ * Pathname('a') <=> Pathname('ab') # => -1
+ * Pathname('a') <=> Pathname('a') # => 0
+ * Pathname('b') <=> Pathname('a') # => 1
+ * Pathname('ab') <=> Pathname('a') # => 1
+ * Pathname('ab') <=> 'a' # => nil
+ *
+ * Two pathnames that are different may refer to the same entry in the filesystem:
+ *
+ * Pathname('lib') <=> Pathname('./lib') # => 1
*
- * It will return +-1+, +0+ or +1+ depending on the value of the left argument
- * relative to the right argument. Or it will return +nil+ if the arguments
- * are not comparable.
*/
static VALUE
path_cmp(VALUE self, VALUE other)
@@ -191,41 +99,6 @@ path_cmp(VALUE self, VALUE other)
return INT2FIX(0);
}
-#ifndef ST2FIX
-#define ST2FIX(h) LONG2FIX((long)(h))
-#endif
-
-/* :nodoc: */
-static VALUE
-path_hash(VALUE self)
-{
- return ST2FIX(rb_str_hash(get_strpath(self)));
-}
-
-/*
- * call-seq:
- * pathname.to_s -> string
- * pathname.to_path -> string
- *
- * Return the path as a String.
- *
- * to_path is implemented so Pathname objects are usable with File.open, etc.
- */
-static VALUE
-path_to_s(VALUE self)
-{
- return rb_obj_dup(get_strpath(self));
-}
-
-/* :nodoc: */
-static VALUE
-path_inspect(VALUE self)
-{
- const char *c = rb_obj_classname(self);
- VALUE str = get_strpath(self);
- return rb_sprintf("#<%s:%"PRIsVALUE">", c, str);
-}
-
/*
* Return a pathname which is substituted by String#sub.
*
@@ -247,1257 +120,217 @@ path_sub(int argc, VALUE *argv, VALUE self)
return rb_class_new_instance(1, &str, rb_obj_class(self));
}
-/*
- * Return a pathname with +repl+ added as a suffix to the basename.
- *
- * If self has no extension part, +repl+ is appended.
- *
- * Pathname.new('/usr/bin/shutdown').sub_ext('.rb')
- * #=> #<Pathname:/usr/bin/shutdown.rb>
- */
-static VALUE
-path_sub_ext(VALUE self, VALUE repl)
-{
- VALUE str = get_strpath(self);
- VALUE str2;
- long extlen;
- const char *ext;
- const char *p;
-
- StringValue(repl);
- p = RSTRING_PTR(str);
- extlen = RSTRING_LEN(str);
- ext = ruby_enc_find_extname(p, &extlen, rb_enc_get(str));
- if (ext == NULL) {
- ext = p + RSTRING_LEN(str);
- }
- else if (extlen <= 1) {
- ext += extlen;
- }
- str2 = rb_str_subseq(str, 0, ext-p);
- rb_str_append(str2, repl);
- return rb_class_new_instance(1, &str2, rb_obj_class(self));
-}
-
-/* Facade for File */
-
-/*
- * Returns the real (absolute) pathname for +self+ in the actual
- * filesystem.
- *
- * Does not contain symlinks or useless dots, +..+ and +.+.
- *
- * All components of the pathname must exist when this method is
- * called.
- *
- */
-static VALUE
-path_realpath(int argc, VALUE *argv, VALUE self)
-{
- VALUE basedir, str;
- rb_scan_args(argc, argv, "01", &basedir);
- str = rb_funcall(rb_cFile, id_realpath, 2, get_strpath(self), basedir);
- return rb_class_new_instance(1, &str, rb_obj_class(self));
-}
-
-/*
- * Returns the real (absolute) pathname of +self+ in the actual filesystem.
- *
- * Does not contain symlinks or useless dots, +..+ and +.+.
- *
- * The last component of the real pathname can be nonexistent.
- */
-static VALUE
-path_realdirpath(int argc, VALUE *argv, VALUE self)
-{
- VALUE basedir, str;
- rb_scan_args(argc, argv, "01", &basedir);
- str = rb_funcall(rb_cFile, id_realdirpath, 2, get_strpath(self), basedir);
- return rb_class_new_instance(1, &str, rb_obj_class(self));
-}
-
-/*
- * call-seq:
- * pathname.each_line {|line| ... }
- * pathname.each_line(sep=$/ [, open_args]) {|line| block } -> nil
- * pathname.each_line(limit [, open_args]) {|line| block } -> nil
- * pathname.each_line(sep, limit [, open_args]) {|line| block } -> nil
- * pathname.each_line(...) -> an_enumerator
- *
- * Iterates over each line in the file and yields a String object for each.
- */
-static VALUE
-path_each_line(int argc, VALUE *argv, VALUE self)
-{
- VALUE args[4];
- int n;
-
- args[0] = get_strpath(self);
- n = rb_scan_args(argc, argv, "03", &args[1], &args[2], &args[3]);
- if (rb_block_given_p()) {
- return rb_block_call_kw(rb_cFile, id_foreach, 1+n, args, 0, 0, RB_PASS_CALLED_KEYWORDS);
- }
- else {
- return rb_funcallv_kw(rb_cFile, id_foreach, 1+n, args, RB_PASS_CALLED_KEYWORDS);
- }
-}
-
-/*
- * call-seq:
- * pathname.read([length [, offset]]) -> string
- * pathname.read([length [, offset]], open_args) -> string
- *
- * Returns all data from the file, or the first +N+ bytes if specified.
- *
- * See File.read.
- *
- */
-static VALUE
-path_read(int argc, VALUE *argv, VALUE self)
-{
- VALUE args[4];
- int n;
-
- args[0] = get_strpath(self);
- n = rb_scan_args(argc, argv, "03", &args[1], &args[2], &args[3]);
- return rb_funcallv_kw(rb_cFile, id_read, 1+n, args, RB_PASS_CALLED_KEYWORDS);
-}
-
-/*
- * call-seq:
- * pathname.binread([length [, offset]]) -> string
- *
- * Returns all the bytes from the file, or the first +N+ if specified.
- *
- * See File.binread.
- *
- */
-static VALUE
-path_binread(int argc, VALUE *argv, VALUE self)
-{
- VALUE args[3];
- int n;
-
- args[0] = get_strpath(self);
- n = rb_scan_args(argc, argv, "02", &args[1], &args[2]);
- return rb_funcallv(rb_cFile, id_binread, 1+n, args);
-}
-
-/*
- * call-seq:
- * pathname.write(string, [offset] ) => fixnum
- * pathname.write(string, [offset], open_args ) => fixnum
- *
- * Writes +contents+ to the file.
- *
- * See File.write.
- *
- */
-static VALUE
-path_write(int argc, VALUE *argv, VALUE self)
-{
- VALUE args[4];
- int n;
-
- args[0] = get_strpath(self);
- n = rb_scan_args(argc, argv, "03", &args[1], &args[2], &args[3]);
- return rb_funcallv_kw(rb_cFile, id_write, 1+n, args, RB_PASS_CALLED_KEYWORDS);
-}
-
-/*
- * call-seq:
- * pathname.binwrite(string, [offset] ) => fixnum
- * pathname.binwrite(string, [offset], open_args ) => fixnum
- *
- * Writes +contents+ to the file, opening it in binary mode.
- *
- * See File.binwrite.
- *
- */
-static VALUE
-path_binwrite(int argc, VALUE *argv, VALUE self)
-{
- VALUE args[4];
- int n;
-
- args[0] = get_strpath(self);
- n = rb_scan_args(argc, argv, "03", &args[1], &args[2], &args[3]);
- return rb_funcallv_kw(rb_cFile, id_binwrite, 1+n, args, RB_PASS_CALLED_KEYWORDS);
-}
-
-/*
- * call-seq:
- * pathname.readlines(sep=$/ [, open_args]) -> array
- * pathname.readlines(limit [, open_args]) -> array
- * pathname.readlines(sep, limit [, open_args]) -> array
- *
- * Returns all the lines from the file.
- *
- * See File.readlines.
- *
- */
-static VALUE
-path_readlines(int argc, VALUE *argv, VALUE self)
-{
- VALUE args[4];
- int n;
-
- args[0] = get_strpath(self);
- n = rb_scan_args(argc, argv, "03", &args[1], &args[2], &args[3]);
- return rb_funcallv_kw(rb_cFile, id_readlines, 1+n, args, RB_PASS_CALLED_KEYWORDS);
-}
-
-/*
- * call-seq:
- * pathname.sysopen([mode, [perm]]) -> fixnum
- *
- * See IO.sysopen.
- *
- */
-static VALUE
-path_sysopen(int argc, VALUE *argv, VALUE self)
-{
- VALUE args[3];
- int n;
-
- args[0] = get_strpath(self);
- n = rb_scan_args(argc, argv, "02", &args[1], &args[2]);
- return rb_funcallv(rb_cIO, id_sysopen, 1+n, args);
-}
-
-/*
- * call-seq:
- * pathname.atime -> time
- *
- * Returns the last access time for the file.
- *
- * See File.atime.
- */
-static VALUE
-path_atime(VALUE self)
-{
- return rb_funcall(rb_cFile, id_atime, 1, get_strpath(self));
-}
-
-/*
- * call-seq:
- * pathname.birthtime -> time
- *
- * Returns the birth time for the file.
- * If the platform doesn't have birthtime, raises NotImplementedError.
- *
- * See File.birthtime.
- */
-static VALUE
-path_birthtime(VALUE self)
-{
- return rb_funcall(rb_cFile, id_birthtime, 1, get_strpath(self));
-}
-
-/*
- * call-seq:
- * pathname.ctime -> time
- *
- * Returns the last change time, using directory information, not the file itself.
- *
- * See File.ctime.
- */
-static VALUE
-path_ctime(VALUE self)
-{
- return rb_funcall(rb_cFile, id_ctime, 1, get_strpath(self));
-}
-
-/*
- * call-seq:
- * pathname.mtime -> time
- *
- * Returns the last modified time of the file.
- *
- * See File.mtime.
- */
-static VALUE
-path_mtime(VALUE self)
-{
- return rb_funcall(rb_cFile, id_mtime, 1, get_strpath(self));
-}
-
-/*
- * call-seq:
- * pathname.chmod(mode_int) -> integer
- *
- * Changes file permissions.
- *
- * See File.chmod.
- */
-static VALUE
-path_chmod(VALUE self, VALUE mode)
-{
- return rb_funcall(rb_cFile, id_chmod, 2, mode, get_strpath(self));
-}
-
-/*
- * call-seq:
- * pathname.lchmod(mode_int) -> integer
- *
- * Same as Pathname.chmod, but does not follow symbolic links.
- *
- * See File.lchmod.
- */
-static VALUE
-path_lchmod(VALUE self, VALUE mode)
-{
- return rb_funcall(rb_cFile, id_lchmod, 2, mode, get_strpath(self));
-}
-
-/*
- * call-seq:
- * pathname.chown(owner_int, group_int) -> integer
- *
- * Change owner and group of the file.
- *
- * See File.chown.
- */
-static VALUE
-path_chown(VALUE self, VALUE owner, VALUE group)
-{
- return rb_funcall(rb_cFile, id_chown, 3, owner, group, get_strpath(self));
-}
-
-/*
- * call-seq:
- * pathname.lchown(owner_int, group_int) -> integer
- *
- * Same as Pathname.chown, but does not follow symbolic links.
- *
- * See File.lchown.
- */
-static VALUE
-path_lchown(VALUE self, VALUE owner, VALUE group)
-{
- return rb_funcall(rb_cFile, id_lchown, 3, owner, group, get_strpath(self));
-}
-
-/*
- * call-seq:
- * pathname.fnmatch(pattern, [flags]) -> true or false
- * pathname.fnmatch?(pattern, [flags]) -> true or false
- *
- * Return +true+ if the receiver matches the given pattern.
- *
- * See File.fnmatch.
- */
+/* :nodoc: */
static VALUE
-path_fnmatch(int argc, VALUE *argv, VALUE self)
+same_paths(VALUE self, VALUE a, VALUE b)
{
- VALUE str = get_strpath(self);
- VALUE pattern, flags;
- if (rb_scan_args(argc, argv, "11", &pattern, &flags) == 1)
- return rb_funcall(rb_cFile, id_fnmatch, 2, pattern, str);
+ check_strpath(a);
+ check_strpath(b);
+ if (CASEFOLD_FILESYSTEM)
+ return RBOOL(rb_str_casecmp(a, b) == INT2FIX(0));
else
- return rb_funcall(rb_cFile, id_fnmatch, 3, pattern, str, flags);
-}
-
-/*
- * call-seq:
- * pathname.ftype -> string
- *
- * Returns "type" of file ("file", "directory", etc).
- *
- * See File.ftype.
- */
-static VALUE
-path_ftype(VALUE self)
-{
- return rb_funcall(rb_cFile, id_ftype, 1, get_strpath(self));
-}
-
-/*
- * call-seq:
- * pathname.make_link(old)
- *
- * Creates a hard link at _pathname_.
- *
- * See File.link.
- */
-static VALUE
-path_make_link(VALUE self, VALUE old)
-{
- return rb_funcall(rb_cFile, id_link, 2, old, get_strpath(self));
-}
-
-/*
- * call-seq:
- * pathname.open()
- * pathname.open(mode="r" [, opt]) -> file
- * pathname.open([mode [, perm]] [, opt]) -> file
- * pathname.open(mode="r" [, opt]) {|file| block } -> obj
- * pathname.open([mode [, perm]] [, opt]) {|file| block } -> obj
- *
- * Opens the file for reading or writing.
- *
- * See File.open.
- */
-static VALUE
-path_open(int argc, VALUE *argv, VALUE self)
-{
- VALUE args[4];
- int n;
-
- args[0] = get_strpath(self);
- n = rb_scan_args(argc, argv, "03", &args[1], &args[2], &args[3]);
- if (rb_block_given_p()) {
- return rb_block_call_kw(rb_cFile, id_open, 1+n, args, 0, 0, RB_PASS_CALLED_KEYWORDS);
- }
- else {
- return rb_funcallv_kw(rb_cFile, id_open, 1+n, args, RB_PASS_CALLED_KEYWORDS);
- }
-}
-
-/*
- * Read symbolic link.
- *
- * See File.readlink.
- */
-static VALUE
-path_readlink(VALUE self)
-{
- VALUE str;
- str = rb_funcall(rb_cFile, id_readlink, 1, get_strpath(self));
- return rb_class_new_instance(1, &str, rb_obj_class(self));
+ return rb_str_equal(a, b);
}
/*
- * Rename the file.
+ * Predicate method for root directories. Returns +true+ if the
+ * pathname consists of consecutive slashes.
*
- * See File.rename.
+ * It doesn't access the filesystem. So it may return +false+ for some
+ * pathnames which points to roots such as <tt>/usr/..</tt>.
*/
static VALUE
-path_rename(VALUE self, VALUE to)
+path_root_p(VALUE self)
{
- return rb_funcall(rb_cFile, id_rename, 2, get_strpath(self), to);
-}
-
-/*
- * Returns a File::Stat object.
- *
- * See File.stat.
- */
-static VALUE
-path_stat(VALUE self)
-{
- return rb_funcall(rb_cFile, id_stat, 1, get_strpath(self));
-}
-
-/*
- * See File.lstat.
- */
-static VALUE
-path_lstat(VALUE self)
-{
- return rb_funcall(rb_cFile, id_lstat, 1, get_strpath(self));
+ VALUE path = get_strpath(self);
+ if (RSTRING_LEN(path) == 0) return Qfalse;
+ const char *ptr = RSTRING_PTR(path), *end = RSTRING_END(path);
+ rb_encoding *enc = rb_enc_get(path);
+ const char *base = rb_enc_path_skip_prefix_root(ptr, end, enc);
+ return RBOOL(base == end);
}
/*
* call-seq:
- * pathname.make_symlink(old)
- *
- * Creates a symbolic link.
- *
- * See File.symlink.
- */
-static VALUE
-path_make_symlink(VALUE self, VALUE old)
-{
- return rb_funcall(rb_cFile, id_symlink, 2, old, get_strpath(self));
-}
-
-/*
- * Truncates the file to +length+ bytes.
- *
- * See File.truncate.
- */
-static VALUE
-path_truncate(VALUE self, VALUE length)
-{
- return rb_funcall(rb_cFile, id_truncate, 2, get_strpath(self), length);
-}
-
-/*
- * Update the access and modification times of the file.
- *
- * See File.utime.
- */
-static VALUE
-path_utime(VALUE self, VALUE atime, VALUE mtime)
-{
- return rb_funcall(rb_cFile, id_utime, 3, atime, mtime, get_strpath(self));
-}
-
-/*
- * Update the access and modification times of the file.
- *
- * Same as Pathname#utime, but does not follow symbolic links.
- *
- * See File.lutime.
- */
-static VALUE
-path_lutime(VALUE self, VALUE atime, VALUE mtime)
-{
- return rb_funcall(rb_cFile, id_lutime, 3, atime, mtime, get_strpath(self));
-}
-
-/*
- * Returns the last component of the path.
+ * absolute? -> true or false
*
- * See File.basename.
- */
-static VALUE
-path_basename(int argc, VALUE *argv, VALUE self)
-{
- VALUE str = get_strpath(self);
- VALUE fext;
- if (rb_scan_args(argc, argv, "01", &fext) == 0)
- str = rb_funcall(rb_cFile, id_basename, 1, str);
- else
- str = rb_funcall(rb_cFile, id_basename, 2, str, fext);
- return rb_class_new_instance(1, &str, rb_obj_class(self));
-}
-
-/*
- * Returns all but the last component of the path.
+ * Returns whether +self+ contains an absolute path:
*
- * See File.dirname.
- */
-static VALUE
-path_dirname(VALUE self)
-{
- VALUE str = get_strpath(self);
- str = rb_funcall(rb_cFile, id_dirname, 1, str);
- return rb_class_new_instance(1, &str, rb_obj_class(self));
-}
-
-/*
- * Returns the file's extension.
- *
- * See File.extname.
- */
-static VALUE
-path_extname(VALUE self)
-{
- VALUE str = get_strpath(self);
- return rb_funcall(rb_cFile, id_extname, 1, str);
-}
-
-/*
- * Returns the absolute path for the file.
+ * Pathname('/home').absolute? # => true
+ * Pathname('lib').absolute? # => false
*
- * See File.expand_path.
- */
-static VALUE
-path_expand_path(int argc, VALUE *argv, VALUE self)
-{
- VALUE str = get_strpath(self);
- VALUE dname;
- if (rb_scan_args(argc, argv, "01", &dname) == 0)
- str = rb_funcall(rb_cFile, id_expand_path, 1, str);
- else
- str = rb_funcall(rb_cFile, id_expand_path, 2, str, dname);
- return rb_class_new_instance(1, &str, rb_obj_class(self));
-}
-
-/*
- * Returns the #dirname and the #basename in an Array.
+ * The result is OS-dependent for some paths:
*
- * See File.split.
- */
-static VALUE
-path_split(VALUE self)
-{
- VALUE str = get_strpath(self);
- VALUE ary, dirname, basename;
- ary = rb_funcall(rb_cFile, id_split, 1, str);
- Check_Type(ary, T_ARRAY);
- dirname = rb_ary_entry(ary, 0);
- basename = rb_ary_entry(ary, 1);
- dirname = rb_class_new_instance(1, &dirname, rb_obj_class(self));
- basename = rb_class_new_instance(1, &basename, rb_obj_class(self));
- return rb_ary_new3(2, dirname, basename);
-}
-
-/*
- * See FileTest.blockdev?.
- */
-static VALUE
-path_blockdev_p(VALUE self)
-{
- return rb_funcall(rb_mFileTest, id_blockdev_p, 1, get_strpath(self));
-}
-
-/*
- * See FileTest.chardev?.
- */
-static VALUE
-path_chardev_p(VALUE self)
-{
- return rb_funcall(rb_mFileTest, id_chardev_p, 1, get_strpath(self));
-}
-
-/*
- * See FileTest.executable?.
- */
-static VALUE
-path_executable_p(VALUE self)
-{
- return rb_funcall(rb_mFileTest, id_executable_p, 1, get_strpath(self));
-}
-
-/*
- * See FileTest.executable_real?.
- */
-static VALUE
-path_executable_real_p(VALUE self)
-{
- return rb_funcall(rb_mFileTest, id_executable_real_p, 1, get_strpath(self));
-}
-
-/*
- * See FileTest.exist?.
- */
-static VALUE
-path_exist_p(VALUE self)
-{
- return rb_funcall(rb_mFileTest, id_exist_p, 1, get_strpath(self));
-}
-
-/*
- * See FileTest.grpowned?.
- */
-static VALUE
-path_grpowned_p(VALUE self)
-{
- return rb_funcall(rb_mFileTest, id_grpowned_p, 1, get_strpath(self));
-}
-
-/*
- * See FileTest.directory?.
- */
-static VALUE
-path_directory_p(VALUE self)
-{
- return rb_funcall(rb_mFileTest, id_directory_p, 1, get_strpath(self));
-}
-
-/*
- * See FileTest.file?.
- */
-static VALUE
-path_file_p(VALUE self)
-{
- return rb_funcall(rb_mFileTest, id_file_p, 1, get_strpath(self));
-}
-
-/*
- * See FileTest.pipe?.
- */
-static VALUE
-path_pipe_p(VALUE self)
-{
- return rb_funcall(rb_mFileTest, id_pipe_p, 1, get_strpath(self));
-}
-
-/*
- * See FileTest.socket?.
- */
-static VALUE
-path_socket_p(VALUE self)
-{
- return rb_funcall(rb_mFileTest, id_socket_p, 1, get_strpath(self));
-}
-
-/*
- * See FileTest.owned?.
- */
-static VALUE
-path_owned_p(VALUE self)
-{
- return rb_funcall(rb_mFileTest, id_owned_p, 1, get_strpath(self));
-}
-
-/*
- * See FileTest.readable?.
- */
-static VALUE
-path_readable_p(VALUE self)
-{
- return rb_funcall(rb_mFileTest, id_readable_p, 1, get_strpath(self));
-}
-
-/*
- * See FileTest.world_readable?.
- */
-static VALUE
-path_world_readable_p(VALUE self)
-{
- return rb_funcall(rb_mFileTest, id_world_readable_p, 1, get_strpath(self));
-}
-
-/*
- * See FileTest.readable_real?.
- */
-static VALUE
-path_readable_real_p(VALUE self)
-{
- return rb_funcall(rb_mFileTest, id_readable_real_p, 1, get_strpath(self));
-}
-
-/*
- * See FileTest.setuid?.
- */
-static VALUE
-path_setuid_p(VALUE self)
-{
- return rb_funcall(rb_mFileTest, id_setuid_p, 1, get_strpath(self));
-}
-
-/*
- * See FileTest.setgid?.
- */
-static VALUE
-path_setgid_p(VALUE self)
-{
- return rb_funcall(rb_mFileTest, id_setgid_p, 1, get_strpath(self));
-}
-
-/*
- * See FileTest.size.
- */
-static VALUE
-path_size(VALUE self)
-{
- return rb_funcall(rb_mFileTest, id_size, 1, get_strpath(self));
-}
-
-/*
- * See FileTest.size?.
- */
-static VALUE
-path_size_p(VALUE self)
-{
- return rb_funcall(rb_mFileTest, id_size_p, 1, get_strpath(self));
-}
-
-/*
- * See FileTest.sticky?.
- */
-static VALUE
-path_sticky_p(VALUE self)
-{
- return rb_funcall(rb_mFileTest, id_sticky_p, 1, get_strpath(self));
-}
-
-/*
- * See FileTest.symlink?.
- */
-static VALUE
-path_symlink_p(VALUE self)
-{
- return rb_funcall(rb_mFileTest, id_symlink_p, 1, get_strpath(self));
-}
-
-/*
- * See FileTest.writable?.
- */
-static VALUE
-path_writable_p(VALUE self)
-{
- return rb_funcall(rb_mFileTest, id_writable_p, 1, get_strpath(self));
-}
-
-/*
- * See FileTest.world_writable?.
- */
-static VALUE
-path_world_writable_p(VALUE self)
-{
- return rb_funcall(rb_mFileTest, id_world_writable_p, 1, get_strpath(self));
-}
-
-/*
- * See FileTest.writable_real?.
- */
-static VALUE
-path_writable_real_p(VALUE self)
-{
- return rb_funcall(rb_mFileTest, id_writable_real_p, 1, get_strpath(self));
-}
-
-/*
- * See FileTest.zero?.
- */
-static VALUE
-path_zero_p(VALUE self)
-{
- return rb_funcall(rb_mFileTest, id_zero_p, 1, get_strpath(self));
-}
-
-/*
- * Tests the file is empty.
+ * Pathname('C:/').absolute? # => true # On Windows.
+ * Pathname('C:/').absolute? # => false # Elsewhere.
*
- * See Dir#empty? and FileTest.empty?.
*/
static VALUE
-path_empty_p(VALUE self)
+path_absolute_p(VALUE self)
{
-
VALUE path = get_strpath(self);
- if (RTEST(rb_funcall(rb_mFileTest, id_directory_p, 1, path)))
- return rb_funcall(rb_cDir, id_empty_p, 1, path);
- else
- return rb_funcall(rb_mFileTest, id_empty_p, 1, path);
-}
-
-static VALUE
-s_glob_i(RB_BLOCK_CALL_FUNC_ARGLIST(elt, klass))
-{
- return rb_yield(rb_class_new_instance(1, &elt, klass));
+ const char *ptr = RSTRING_PTR(path);
+ long len = RSTRING_LEN(path);
+ if (len < 1) return Qfalse;
+ if (drive_letter) {
+ if (len >= 2 && ISALPHA(ptr[0]) && (ptr[1] == ':')) return Qtrue;
+ }
+ return RBOOL(isdirsep(ptr[0]));
}
-/*
- * Returns or yields Pathname objects.
- *
- * Pathname.glob("lib/i*.rb")
- * #=> [#<Pathname:lib/ipaddr.rb>, #<Pathname:lib/irb.rb>]
- *
- * See Dir.glob.
- */
+/* :nodoc: */
static VALUE
-path_s_glob(int argc, VALUE *argv, VALUE klass)
+has_separator_p(VALUE self, VALUE path)
{
- VALUE args[3];
- int n;
-
- n = rb_scan_args(argc, argv, "12", &args[0], &args[1], &args[2]);
- if (rb_block_given_p()) {
- return rb_block_call_kw(rb_cDir, id_glob, n, args, s_glob_i, klass, RB_PASS_CALLED_KEYWORDS);
+ const char *ptr = RSTRING_PTR(check_strpath(path));
+ const char *end = RSTRING_END(path);
+ if (alt_separator) {
+ rb_encoding *enc = rb_enc_get(path);
+ bool mb = !rb_str_enc_fastpath(path);
+ while (ptr < end) {
+ if (isdirsep(*ptr)) return Qtrue;
+ ptr += (mb ? rb_enc_mbclen(ptr, end, enc) : 1);
+ }
}
else {
- VALUE ary;
- long i;
- ary = rb_funcallv_kw(rb_cDir, id_glob, n, args, RB_PASS_CALLED_KEYWORDS);
- ary = rb_convert_type(ary, T_ARRAY, "Array", "to_ary");
- for (i = 0; i < RARRAY_LEN(ary); i++) {
- VALUE elt = RARRAY_AREF(ary, i);
- elt = rb_class_new_instance(1, &elt, klass);
- rb_ary_store(ary, i, elt);
- }
- return ary;
+ /* assume '/' will never be trailing bytes */
+ if (memchr(ptr, '/', end - ptr)) return Qtrue;
}
-}
-
-static VALUE
-glob_i(RB_BLOCK_CALL_FUNC_ARGLIST(elt, self))
-{
- elt = rb_funcall(self, '+', 1, elt);
- return rb_yield(elt);
+ return Qfalse;
}
/*
- * Returns or yields Pathname objects.
+ * Return a pathname with +repl+ added as a suffix to the basename.
*
- * Pathname("ruby-2.4.2").glob("R*.md")
- * #=> [#<Pathname:ruby-2.4.2/README.md>, #<Pathname:ruby-2.4.2/README.ja.md>]
+ * If self has no extension part, +repl+ is appended.
*
- * See Dir.glob.
- * This method uses the +base+ keyword argument of Dir.glob.
+ * Pathname.new('/usr/bin/shutdown').sub_ext('.rb')
+ * #=> #<Pathname:/usr/bin/shutdown.rb>
*/
static VALUE
-path_glob(int argc, VALUE *argv, VALUE self)
+path_sub_ext(VALUE self, VALUE repl)
{
- VALUE args[3];
- int n;
-
- n = rb_scan_args(argc, argv, "11", &args[0], &args[1]);
- if (n == 1)
- args[1] = INT2FIX(0);
-
- args[2] = rb_hash_new();
- rb_hash_aset(args[2], ID2SYM(id_base), get_strpath(self));
-
- n = 3;
-
- if (rb_block_given_p()) {
- return rb_block_call_kw(rb_cDir, id_glob, n, args, glob_i, self, RB_PASS_KEYWORDS);
+ VALUE path = get_strpath(self);
+ long len = RSTRING_LEN(path);
+ const char *ptr = RSTRING_PTR(path);
+ const char *ext = ruby_enc_find_extname(ptr, &len, rb_enc_get(path));
+ if (len > 0) {
+ RUBY_ASSERT(ext, "should point the last dot");
+ path = rb_str_subseq(path, 0, ext - ptr);
}
else {
- VALUE ary;
- long i;
- ary = rb_funcallv_kw(rb_cDir, id_glob, n, args, RB_PASS_KEYWORDS);
- ary = rb_convert_type(ary, T_ARRAY, "Array", "to_ary");
- for (i = 0; i < RARRAY_LEN(ary); i++) {
- VALUE elt = RARRAY_AREF(ary, i);
- elt = rb_funcall(self, '+', 1, elt);
- rb_ary_store(ary, i, elt);
- }
- return ary;
+ /* no dot or dotted file */
+ path = rb_str_dup(path);
}
+ path = rb_str_append(path, repl);
+ return rb_class_new_instance(1, &path, rb_obj_class(self));
}
-/*
- * Returns the current working directory as a Pathname.
- *
- * Pathname.getwd
- * #=> #<Pathname:/home/zzak/projects/ruby>
- *
- * See Dir.getwd.
- */
+/* :nodoc: */
+/* chop_basename(path) -> [pre-basename, basename] or nil */
static VALUE
-path_s_getwd(VALUE klass)
+chop_basename(VALUE self, VALUE path)
{
- VALUE str;
- str = rb_funcall(rb_cDir, id_getwd, 0);
- return rb_class_new_instance(1, &str, klass);
+ long baselen, alllen = RSTRING_LEN(check_strpath(path));
+ if (alllen <= 0) return Qnil;
+ rb_encoding *enc = rb_enc_get(path);
+ const char *name = RSTRING_PTR(path);
+ const char *base = ruby_enc_find_basename(name, &baselen, &alllen, enc);
+ if (baselen < 1) return Qnil;
+ if (baselen == 1 && isdirsep(*base)) return Qnil;
+ RUBY_ASSERT(base >= name);
+ RUBY_ASSERT(base <= RSTRING_END(path));
+ VALUE dir = rb_str_subseq(path, 0, base - name);
+ VALUE basename = rb_enc_str_new(base, alllen, enc);
+ RB_GC_GUARD(path);
+ return rb_assoc_new(dir, basename);
}
-/*
- * Return the entries (files and subdirectories) in the directory, each as a
- * Pathname object.
- *
- * The results contains just the names in the directory, without any trailing
- * slashes or recursive look-up.
- *
- * pp Pathname.new('/usr/local').entries
- * #=> [#<Pathname:share>,
- * # #<Pathname:lib>,
- * # #<Pathname:..>,
- * # #<Pathname:include>,
- * # #<Pathname:etc>,
- * # #<Pathname:bin>,
- * # #<Pathname:man>,
- * # #<Pathname:games>,
- * # #<Pathname:.>,
- * # #<Pathname:sbin>,
- * # #<Pathname:src>]
- *
- * The result may contain the current directory <code>#<Pathname:.></code> and
- * the parent directory <code>#<Pathname:..></code>.
- *
- * If you don't want +.+ and +..+ and
- * want directories, consider Pathname#children.
- */
-static VALUE
-path_entries(VALUE self)
-{
- VALUE klass, str, ary;
- long i;
- klass = rb_obj_class(self);
- str = get_strpath(self);
- ary = rb_funcall(rb_cDir, id_entries, 1, str);
- ary = rb_convert_type(ary, T_ARRAY, "Array", "to_ary");
- for (i = 0; i < RARRAY_LEN(ary); i++) {
- VALUE elt = RARRAY_AREF(ary, i);
- elt = rb_class_new_instance(1, &elt, klass);
- rb_ary_store(ary, i, elt);
+/* :nodoc: */
+/* split_names(path) -> prefix, [name, ...] */
+static VALUE
+split_names(VALUE self, VALUE path)
+{
+ rb_encoding *enc = rb_enc_get(check_strpath(path));
+ const char *beg = RSTRING_PTR(path), *ptr = beg;
+ const char *end = RSTRING_END(path);
+ const char *root = rb_enc_path_skip_prefix_root(ptr, end, enc);
+ VALUE pre = rb_str_subseq(path, 0, root - ptr);
+ VALUE names = rb_ary_new();
+ while (ptr < end) {
+ const char *next = rb_enc_path_next(ptr, end, enc);
+ if (next > ptr) rb_ary_push(names, rb_str_subseq(path, ptr - beg, next - ptr));
+ ptr = next;
+ while (ptr < end && isdirsep(*ptr)) ++ptr;
}
- return ary;
-}
-
-/*
- * Create the referenced directory.
- *
- * See Dir.mkdir.
- */
-static VALUE
-path_mkdir(int argc, VALUE *argv, VALUE self)
-{
- VALUE str = get_strpath(self);
- VALUE vmode;
- if (rb_scan_args(argc, argv, "01", &vmode) == 0)
- return rb_funcall(rb_cDir, id_mkdir, 1, str);
- else
- return rb_funcall(rb_cDir, id_mkdir, 2, str, vmode);
-}
-
-/*
- * Remove the referenced directory.
- *
- * See Dir.rmdir.
- */
-static VALUE
-path_rmdir(VALUE self)
-{
- return rb_funcall(rb_cDir, id_rmdir, 1, get_strpath(self));
-}
-
-/*
- * Opens the referenced directory.
- *
- * See Dir.open.
- */
-static VALUE
-path_opendir(VALUE self)
-{
- VALUE args[1];
-
- args[0] = get_strpath(self);
- return rb_block_call(rb_cDir, id_open, 1, args, 0, 0);
-}
-
-static VALUE
-each_entry_i(RB_BLOCK_CALL_FUNC_ARGLIST(elt, klass))
-{
- return rb_yield(rb_class_new_instance(1, &elt, klass));
-}
-
-/*
- * Iterates over the entries (files and subdirectories) in the directory,
- * yielding a Pathname object for each entry.
- */
-static VALUE
-path_each_entry(VALUE self)
-{
- VALUE args[1];
- RETURN_ENUMERATOR(self, 0, 0);
-
- args[0] = get_strpath(self);
- return rb_block_call(rb_cDir, id_foreach, 1, args, each_entry_i, rb_obj_class(self));
-}
-
-static VALUE
-unlink_body(VALUE str)
-{
- return rb_funcall(rb_cDir, id_unlink, 1, str);
+ return rb_assoc_new(pre, names);
}
+/* :nodoc: */
+/* has_trailing_separator?(path) -> bool */
static VALUE
-unlink_rescue(VALUE str, VALUE errinfo)
+has_trailing_separator(VALUE self, VALUE path)
{
- return rb_funcall(rb_cFile, id_unlink, 1, str);
+ long baselen, alllen = RSTRING_LEN(check_strpath(path));
+ if (alllen <= 0) return Qfalse;
+ rb_encoding *enc = rb_enc_get(path);
+ const char *name = RSTRING_PTR(path);
+ const char *base = ruby_enc_find_basename(name, &baselen, &alllen, enc);
+ if (baselen < 1) return Qfalse;
+ if (baselen == 1 && isdirsep(*base)) return Qfalse;
+ return RBOOL(base + alllen < RSTRING_END(path));
}
-/*
- * Removes a file or directory, using File.unlink if +self+ is a file, or
- * Dir.unlink as necessary.
- */
-static VALUE
-path_unlink(VALUE self)
-{
- VALUE eENOTDIR = rb_const_get_at(rb_mErrno, id_ENOTDIR);
- VALUE str = get_strpath(self);
- return rb_rescue2(unlink_body, str, unlink_rescue, str, eENOTDIR, (VALUE)0);
+/* :nodoc: */
+/* add_trailing_separator(path) -> path */
+static VALUE
+add_trailing_separator(VALUE self, VALUE path)
+{
+ if (RSTRING_LEN(check_strpath(path)) <= 0) return path;
+ rb_encoding *enc = rb_enc_get(path);
+ const char *name = RSTRING_PTR(path);
+ const char *end = RSTRING_END(path);
+ const char *top = rb_enc_path_skip_prefix(name, end, enc);
+ if (top < end && isdirsep(end[-1])) {
+ if (end[-1] == '/' || rb_enc_prev_char(top, end, end, enc) == end - 1)
+ return path;
+ }
+ return rb_str_cat_cstr(rb_str_dup(path), "/");
}
-/*
- * :call-seq:
- * Pathname(path) -> pathname
- *
- * Creates a new Pathname object from the given string, +path+, and returns
- * pathname object.
- *
- * In order to use this constructor, you must first require the Pathname
- * standard library extension.
- *
- * require 'pathname'
- * Pathname("/home/zzak")
- * #=> #<Pathname:/home/zzak>
- *
- * See also Pathname::new for more information.
- */
+/* :nodoc: */
static VALUE
-path_f_pathname(VALUE self, VALUE str)
-{
- if (CLASS_OF(str) == rb_cPathname)
- return str;
- return rb_class_new_instance(1, &str, rb_cPathname);
+del_trailing_separator(VALUE self, VALUE path)
+{
+ long len = RSTRING_LEN(check_strpath(path));
+ if (len <= 0) return path;
+ rb_encoding *enc = rb_enc_get(path);
+ const char *name = RSTRING_PTR(path);
+ const char *end = name + len, *tail = end;
+ const char *top = rb_enc_path_skip_prefix(name, end, enc);
+ if (tail > top && isdirsep(tail[-1])) {
+ while (--tail > top && isdirsep(tail[-1]));
+ if (tail > top &&
+ tail[0] != '/' &&
+ !rb_str_enc_fastpath(path) &&
+ rb_enc_left_char_head(top, tail, end, enc) != tail) {
+ /* trailing byte, not a directory separator */
+ ++tail;
+ }
+ if (tail < end) {
+ if (tail == name || (drive_letter && tail == top && top[-1] == ':')) {
+ ++tail;
+ }
+ }
+ }
+ if (tail == end) return path;
+ return rb_str_subseq(path, 0, tail - name);
}
#include "pathname_builtin.rbinc"
static void init_ids(void);
-/*
- *
- * Pathname represents the name of a file or directory on the filesystem,
- * but not the file itself.
- *
- * The pathname depends on the Operating System: Unix, Windows, etc.
- * This library works with pathnames of local OS, however non-Unix pathnames
- * are supported experimentally.
- *
- * A Pathname can be relative or absolute. It's not until you try to
- * reference the file that it even matters whether the file exists or not.
- *
- * Pathname is immutable. It has no method for destructive update.
- *
- * The goal of this class is to manipulate file path information in a neater
- * way than standard Ruby provides. The examples below demonstrate the
- * difference.
- *
- * *All* functionality from File, FileTest, and some from Dir and FileUtils is
- * included, in an unsurprising way. It is essentially a facade for all of
- * these, and more.
- *
- * == Examples
- *
- * === Example 1: Using Pathname
- *
- * require 'pathname'
- * pn = Pathname.new("/usr/bin/ruby")
- * size = pn.size # 27662
- * isdir = pn.directory? # false
- * dir = pn.dirname # Pathname:/usr/bin
- * base = pn.basename # Pathname:ruby
- * dir, base = pn.split # [Pathname:/usr/bin, Pathname:ruby]
- * data = pn.read
- * pn.open { |f| _ }
- * pn.each_line { |line| _ }
- *
- * === Example 2: Using standard Ruby
- *
- * pn = "/usr/bin/ruby"
- * size = File.size(pn) # 27662
- * isdir = File.directory?(pn) # false
- * dir = File.dirname(pn) # "/usr/bin"
- * base = File.basename(pn) # "ruby"
- * dir, base = File.split(pn) # ["/usr/bin", "ruby"]
- * data = File.read(pn)
- * File.open(pn) { |f| _ }
- * File.foreach(pn) { |line| _ }
- *
- * === Example 3: Special features
- *
- * p1 = Pathname.new("/usr/lib") # Pathname:/usr/lib
- * p2 = p1 + "ruby/1.8" # Pathname:/usr/lib/ruby/1.8
- * p3 = p1.parent # Pathname:/usr
- * p4 = p2.relative_path_from(p3) # Pathname:lib/ruby/1.8
- * pwd = Pathname.pwd # Pathname:/home/gavin
- * pwd.absolute? # true
- * p5 = Pathname.new "." # Pathname:.
- * p5 = p5 + "music/../articles" # Pathname:music/../articles
- * p5.cleanpath # Pathname:articles
- * p5.realpath # Pathname:/home/gavin/articles
- * p5.children # [Pathname:/home/gavin/articles/linux, ...]
- *
- * == Breakdown of functionality
- *
- * === Core methods
- *
- * These methods are effectively manipulating a String, because that's
- * all a path is. None of these access the file system except for
- * #mountpoint?, #children, #each_child, #realdirpath and #realpath.
- *
- * - +
- * - #join
- * - #parent
- * - #root?
- * - #absolute?
- * - #relative?
- * - #relative_path_from
- * - #each_filename
- * - #cleanpath
- * - #realpath
- * - #realdirpath
- * - #children
- * - #each_child
- * - #mountpoint?
- *
- * === File status predicate methods
- *
- * These methods are a facade for FileTest:
- * - #blockdev?
- * - #chardev?
- * - #directory?
- * - #executable?
- * - #executable_real?
- * - #exist?
- * - #file?
- * - #grpowned?
- * - #owned?
- * - #pipe?
- * - #readable?
- * - #world_readable?
- * - #readable_real?
- * - #setgid?
- * - #setuid?
- * - #size
- * - #size?
- * - #socket?
- * - #sticky?
- * - #symlink?
- * - #writable?
- * - #world_writable?
- * - #writable_real?
- * - #zero?
- *
- * === File property and manipulation methods
- *
- * These methods are a facade for File:
- * - #atime
- * - #birthtime
- * - #ctime
- * - #mtime
- * - #chmod(mode)
- * - #lchmod(mode)
- * - #chown(owner, group)
- * - #lchown(owner, group)
- * - #fnmatch(pattern, *args)
- * - #fnmatch?(pattern, *args)
- * - #ftype
- * - #make_link(old)
- * - #open(*args, &block)
- * - #readlink
- * - #rename(to)
- * - #stat
- * - #lstat
- * - #make_symlink(old)
- * - #truncate(length)
- * - #utime(atime, mtime)
- * - #lutime(atime, mtime)
- * - #basename(*args)
- * - #dirname
- * - #extname
- * - #expand_path(*args)
- * - #split
- *
- * === Directory methods
- *
- * These methods are a facade for Dir:
- * - Pathname.glob(*args)
- * - Pathname.getwd / Pathname.pwd
- * - #rmdir
- * - #entries
- * - #each_entry(&block)
- * - #mkdir(*args)
- * - #opendir(*args)
- *
- * === IO
- *
- * These methods are a facade for IO:
- * - #each_line(*args, &block)
- * - #read(*args)
- * - #binread(*args)
- * - #readlines(*args)
- * - #sysopen(*args)
- * - #write(*args)
- * - #binwrite(*args)
- *
- * === Utilities
- *
- * These methods are a mixture of Find, FileUtils, and others:
- * - #find(&block)
- * - #mkpath
- * - #rmtree
- * - #unlink / #delete
- *
- *
- * == Method documentation
- *
- * As the above section shows, most of the methods in Pathname are facades. The
- * documentation for these methods generally just says, for instance, "See
- * FileTest.writable?", as you should be familiar with the original method
- * anyway, and its documentation (e.g. through +ri+) will contain more
- * information. In some cases, a brief description will follow.
- */
void
Init_pathname(void)
{
@@ -1513,91 +346,19 @@ void
InitVM_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, "==", path_eq, 1);
- rb_define_method(rb_cPathname, "===", path_eq, 1);
- rb_define_method(rb_cPathname, "eql?", path_eq, 1);
rb_define_method(rb_cPathname, "<=>", path_cmp, 1);
- rb_define_method(rb_cPathname, "hash", path_hash, 0);
- rb_define_method(rb_cPathname, "to_s", path_to_s, 0);
- rb_define_method(rb_cPathname, "to_path", path_to_s, 0);
- rb_define_method(rb_cPathname, "inspect", path_inspect, 0);
rb_define_method(rb_cPathname, "sub", path_sub, -1);
rb_define_method(rb_cPathname, "sub_ext", path_sub_ext, 1);
- rb_define_method(rb_cPathname, "realpath", path_realpath, -1);
- rb_define_method(rb_cPathname, "realdirpath", path_realdirpath, -1);
- rb_define_method(rb_cPathname, "each_line", path_each_line, -1);
- rb_define_method(rb_cPathname, "read", path_read, -1);
- rb_define_method(rb_cPathname, "binread", path_binread, -1);
- rb_define_method(rb_cPathname, "readlines", path_readlines, -1);
- rb_define_method(rb_cPathname, "write", path_write, -1);
- rb_define_method(rb_cPathname, "binwrite", path_binwrite, -1);
- rb_define_method(rb_cPathname, "sysopen", path_sysopen, -1);
- rb_define_method(rb_cPathname, "atime", path_atime, 0);
- rb_define_method(rb_cPathname, "birthtime", path_birthtime, 0);
- rb_define_method(rb_cPathname, "ctime", path_ctime, 0);
- rb_define_method(rb_cPathname, "mtime", path_mtime, 0);
- rb_define_method(rb_cPathname, "chmod", path_chmod, 1);
- rb_define_method(rb_cPathname, "lchmod", path_lchmod, 1);
- rb_define_method(rb_cPathname, "chown", path_chown, 2);
- rb_define_method(rb_cPathname, "lchown", path_lchown, 2);
- rb_define_method(rb_cPathname, "fnmatch", path_fnmatch, -1);
- rb_define_method(rb_cPathname, "fnmatch?", path_fnmatch, -1);
- rb_define_method(rb_cPathname, "ftype", path_ftype, 0);
- rb_define_method(rb_cPathname, "make_link", path_make_link, 1);
- rb_define_method(rb_cPathname, "open", path_open, -1);
- rb_define_method(rb_cPathname, "readlink", path_readlink, 0);
- rb_define_method(rb_cPathname, "rename", path_rename, 1);
- rb_define_method(rb_cPathname, "stat", path_stat, 0);
- rb_define_method(rb_cPathname, "lstat", path_lstat, 0);
- rb_define_method(rb_cPathname, "make_symlink", path_make_symlink, 1);
- rb_define_method(rb_cPathname, "truncate", path_truncate, 1);
- rb_define_method(rb_cPathname, "utime", path_utime, 2);
- rb_define_method(rb_cPathname, "lutime", path_lutime, 2);
- rb_define_method(rb_cPathname, "basename", path_basename, -1);
- rb_define_method(rb_cPathname, "dirname", path_dirname, 0);
- rb_define_method(rb_cPathname, "extname", path_extname, 0);
- rb_define_method(rb_cPathname, "expand_path", path_expand_path, -1);
- rb_define_method(rb_cPathname, "split", path_split, 0);
- rb_define_method(rb_cPathname, "blockdev?", path_blockdev_p, 0);
- rb_define_method(rb_cPathname, "chardev?", path_chardev_p, 0);
- rb_define_method(rb_cPathname, "executable?", path_executable_p, 0);
- rb_define_method(rb_cPathname, "executable_real?", path_executable_real_p, 0);
- rb_define_method(rb_cPathname, "exist?", path_exist_p, 0);
- rb_define_method(rb_cPathname, "grpowned?", path_grpowned_p, 0);
- rb_define_method(rb_cPathname, "directory?", path_directory_p, 0);
- rb_define_method(rb_cPathname, "file?", path_file_p, 0);
- rb_define_method(rb_cPathname, "pipe?", path_pipe_p, 0);
- rb_define_method(rb_cPathname, "socket?", path_socket_p, 0);
- rb_define_method(rb_cPathname, "owned?", path_owned_p, 0);
- rb_define_method(rb_cPathname, "readable?", path_readable_p, 0);
- rb_define_method(rb_cPathname, "world_readable?", path_world_readable_p, 0);
- rb_define_method(rb_cPathname, "readable_real?", path_readable_real_p, 0);
- rb_define_method(rb_cPathname, "setuid?", path_setuid_p, 0);
- rb_define_method(rb_cPathname, "setgid?", path_setgid_p, 0);
- rb_define_method(rb_cPathname, "size", path_size, 0);
- rb_define_method(rb_cPathname, "size?", path_size_p, 0);
- rb_define_method(rb_cPathname, "sticky?", path_sticky_p, 0);
- rb_define_method(rb_cPathname, "symlink?", path_symlink_p, 0);
- rb_define_method(rb_cPathname, "writable?", path_writable_p, 0);
- rb_define_method(rb_cPathname, "world_writable?", path_world_writable_p, 0);
- rb_define_method(rb_cPathname, "writable_real?", path_writable_real_p, 0);
- rb_define_method(rb_cPathname, "zero?", path_zero_p, 0);
- rb_define_method(rb_cPathname, "empty?", path_empty_p, 0);
- rb_define_singleton_method(rb_cPathname, "glob", path_s_glob, -1);
- rb_define_singleton_method(rb_cPathname, "getwd", path_s_getwd, 0);
- rb_define_singleton_method(rb_cPathname, "pwd", path_s_getwd, 0);
- rb_define_method(rb_cPathname, "glob", path_glob, -1);
- rb_define_method(rb_cPathname, "entries", path_entries, 0);
- rb_define_method(rb_cPathname, "mkdir", path_mkdir, -1);
- rb_define_method(rb_cPathname, "rmdir", path_rmdir, 0);
- rb_define_method(rb_cPathname, "opendir", path_opendir, 0);
- rb_define_method(rb_cPathname, "each_entry", path_each_entry, 0);
- rb_define_method(rb_cPathname, "unlink", path_unlink, 0);
- rb_define_method(rb_cPathname, "delete", path_unlink, 0);
- rb_undef_method(rb_cPathname, "=~");
- rb_define_global_function("Pathname", path_f_pathname, 1);
+ rb_define_method(rb_cPathname, "root?", path_root_p, 0);
+ rb_define_method(rb_cPathname, "absolute?", path_absolute_p, 0);
+
+ rb_define_private_method(rb_cPathname, "same_paths?", same_paths, 2);
+ rb_define_private_method(rb_cPathname, "has_separator?", has_separator_p, 1);
+ rb_define_private_method(rb_cPathname, "chop_basename", chop_basename, 1);
+ rb_define_private_method(rb_cPathname, "split_names", split_names, 1);
+ rb_define_private_method(rb_cPathname, "has_trailing_separator?", has_trailing_separator, 1);
+ rb_define_private_method(rb_cPathname, "add_trailing_separator", add_trailing_separator, 1);
+ rb_define_private_method(rb_cPathname, "del_trailing_separator", del_trailing_separator, 1);
rb_provide("pathname.so");
}
@@ -1607,73 +368,5 @@ init_ids(void)
{
#undef rb_intern
id_at_path = rb_intern("@path");
- id_to_path = rb_intern("to_path");
- id_ENOTDIR = rb_intern("ENOTDIR");
- id_atime = rb_intern("atime");
- id_basename = rb_intern("basename");
- id_base = rb_intern("base");
- id_binread = rb_intern("binread");
- id_binwrite = rb_intern("binwrite");
- id_birthtime = rb_intern("birthtime");
- id_blockdev_p = rb_intern("blockdev?");
- id_chardev_p = rb_intern("chardev?");
- id_chmod = rb_intern("chmod");
- id_chown = rb_intern("chown");
- id_ctime = rb_intern("ctime");
- id_directory_p = rb_intern("directory?");
- id_dirname = rb_intern("dirname");
- id_empty_p = rb_intern("empty?");
- id_entries = rb_intern("entries");
- id_executable_p = rb_intern("executable?");
- id_executable_real_p = rb_intern("executable_real?");
- id_exist_p = rb_intern("exist?");
- id_expand_path = rb_intern("expand_path");
- id_extname = rb_intern("extname");
- id_file_p = rb_intern("file?");
- id_fnmatch = rb_intern("fnmatch");
- id_foreach = rb_intern("foreach");
- id_ftype = rb_intern("ftype");
- id_getwd = rb_intern("getwd");
- id_glob = rb_intern("glob");
- id_grpowned_p = rb_intern("grpowned?");
- id_lchmod = rb_intern("lchmod");
- id_lchown = rb_intern("lchown");
- id_link = rb_intern("link");
- id_lstat = rb_intern("lstat");
- id_lutime = rb_intern("lutime");
- id_mkdir = rb_intern("mkdir");
- id_mtime = rb_intern("mtime");
- id_open = rb_intern("open");
- id_owned_p = rb_intern("owned?");
- id_pipe_p = rb_intern("pipe?");
- id_read = rb_intern("read");
- id_readable_p = rb_intern("readable?");
- id_readable_real_p = rb_intern("readable_real?");
- id_readlines = rb_intern("readlines");
- id_readlink = rb_intern("readlink");
- id_realdirpath = rb_intern("realdirpath");
- id_realpath = rb_intern("realpath");
- id_rename = rb_intern("rename");
- id_rmdir = rb_intern("rmdir");
- id_setgid_p = rb_intern("setgid?");
- id_setuid_p = rb_intern("setuid?");
- id_size = rb_intern("size");
- id_size_p = rb_intern("size?");
- id_socket_p = rb_intern("socket?");
- id_split = rb_intern("split");
- id_stat = rb_intern("stat");
- id_sticky_p = rb_intern("sticky?");
id_sub = rb_intern("sub");
- id_symlink = rb_intern("symlink");
- id_symlink_p = rb_intern("symlink?");
- id_sysopen = rb_intern("sysopen");
- id_truncate = rb_intern("truncate");
- id_unlink = rb_intern("unlink");
- id_utime = rb_intern("utime");
- id_world_readable_p = rb_intern("world_readable?");
- id_world_writable_p = rb_intern("world_writable?");
- id_writable_p = rb_intern("writable?");
- id_writable_real_p = rb_intern("writable_real?");
- id_write = rb_intern("write");
- id_zero_p = rb_intern("zero?");
}
diff --git a/pathname_builtin.rb b/pathname_builtin.rb
index 95bd8d0e3a..11ade220f0 100644
--- a/pathname_builtin.rb
+++ b/pathname_builtin.rb
@@ -1,15 +1,219 @@
# frozen_string_literal: true
#
-# = pathname.rb
+# A \Pathname object contains a string directory path or filepath;
+# it does not represent a corresponding actual file or directory
+# -- which in fact may or may not exist.
#
-# Object-Oriented Pathname Class
+# A \Pathname object is immutable (except for method #freeze).
#
-# Author:: Tanaka Akira <akr@m17n.org>
-# Documentation:: Author and Gavin Sinclair
+# A pathname may be relative or absolute:
#
-# For documentation, see class Pathname.
+# Pathname.new('lib') # => #<Pathname:lib>
+# Pathname.new('/usr/local/bin') # => #<Pathname:/usr/local/bin>
+#
+# == About the Examples
+#
+# Many examples here use these variables:
+#
+# :include: doc/examples/files.rdoc
+#
+# == Convenience Methods
+#
+# The class provides *all* functionality from class File and module FileTest,
+# along with some functionality from class Dir and module FileUtils.
+#
+# Here's an example string path and corresponding \Pathname object:
+#
+# path = 'lib/fileutils.rb'
+# pn = Pathname.new(path) # => #<Pathname:lib/fileutils.rb>
+#
+# Each of these method pairs (\Pathname vs. \File) gives exactly the same result:
+#
+# pn.size # => 83777
+# File.size(path) # => 83777
+#
+# pn.directory? # => false
+# File.directory?(path) # => false
+#
+# pn.read.size # => 81074
+# File.read(path).size# # => 81074
+#
+# Each of these method pairs gives similar results,
+# but each \Pathname method returns a more versatile \Pathname object,
+# instead of a string:
+#
+# pn.dirname # => #<Pathname:lib>
+# File.dirname(path) # => "lib"
+#
+# pn.basename # => #<Pathname:fileutils.rb>
+# File.basename(path) # => "fileutils.rb"
+#
+# pn.split # => [#<Pathname:lib>, #<Pathname:fileutils.rb>]
+# File.split(path) # => ["lib", "fileutils.rb"]
+#
+# Each of these methods takes a block:
+#
+# pn.open do |file|
+# p file
+# end
+# File.open(path) do |file|
+# p file
+# end
+#
+# The outputs for each:
+#
+# #<File:lib/fileutils.rb (closed)>
+# #<File:lib/fileutils.rb (closed)>
+#
+# Each of these methods takes a block:
+#
+# pn.each_line do |line|
+# p line
+# break
+# end
+# File.foreach(path) do |line|
+# p line
+# break
+# end
+#
+# The outputs for each:
+#
+# "# frozen_string_literal: true\n"
+# "# frozen_string_literal: true\n"
+#
+# == More Methods
+#
+# Here is a sampling of other available methods:
+#
+# p1 = Pathname.new('/usr/lib') # => #<Pathname:/usr/lib>
+# p1.absolute? # => true
+# p2 = p1 + 'ruby/4.0' # => #<Pathname:/usr/lib/ruby/4.0>
+# p3 = p1.parent # => #<Pathname:/usr>
+# p4 = p2.relative_path_from(p3) # => #<Pathname:lib/ruby/4.0>
+# p4.absolute? # => false
+# p5 = Pathname.new('.') # => #<Pathname:.>
+# p6 = p5 + 'usr/../var' # => #<Pathname:usr/../var>
+# p6.cleanpath # => #<Pathname:var>
+# p6.realpath # => #<Pathname:/var>
+# p6.children.take(2)
+# # => [#<Pathname:usr/../var/local>, #<Pathname:usr/../var/spool>]
+#
+# == Breakdown of functionality
+#
+# === Core methods
+#
+# These methods are effectively manipulating a String, because that's
+# all a path is. None of these access the file system except for
+# #mountpoint?, #children, #each_child, #realdirpath and #realpath.
+#
+# - +
+# - #join
+# - #parent
+# - #root?
+# - #absolute?
+# - #relative?
+# - #relative_path_from
+# - #each_filename
+# - #cleanpath
+# - #realpath
+# - #realdirpath
+# - #children
+# - #each_child
+# - #mountpoint?
+#
+# === File status predicate methods
+#
+# These methods are a facade for FileTest:
+# - #blockdev?
+# - #chardev?
+# - #directory?
+# - #executable?
+# - #executable_real?
+# - #exist?
+# - #file?
+# - #grpowned?
+# - #owned?
+# - #pipe?
+# - #readable?
+# - #world_readable?
+# - #readable_real?
+# - #setgid?
+# - #setuid?
+# - #size
+# - #size?
+# - #socket?
+# - #sticky?
+# - #symlink?
+# - #writable?
+# - #world_writable?
+# - #writable_real?
+# - #zero?
+#
+# === File property and manipulation methods
+#
+# These methods are a facade for File:
+# - #each_line(*args, &block)
+# - #read(*args)
+# - #binread(*args)
+# - #readlines(*args)
+# - #sysopen(*args)
+# - #write(*args)
+# - #binwrite(*args)
+# - #atime
+# - #birthtime
+# - #ctime
+# - #mtime
+# - #chmod(mode)
+# - #lchmod(mode)
+# - #chown(owner, group)
+# - #lchown(owner, group)
+# - #fnmatch(pattern, *args)
+# - #fnmatch?(pattern, *args)
+# - #ftype
+# - #make_link(old)
+# - #open(*args, &block)
+# - #readlink
+# - #rename(to)
+# - #stat
+# - #lstat
+# - #make_symlink(old)
+# - #truncate(length)
+# - #utime(atime, mtime)
+# - #lutime(atime, mtime)
+# - #basename(*args)
+# - #dirname
+# - #extname
+# - #expand_path(*args)
+# - #split
+#
+# === Directory methods
+#
+# These methods are a facade for Dir:
+# - Pathname.glob(*args)
+# - Pathname.getwd / Pathname.pwd
+# - #rmdir
+# - #entries
+# - #each_entry(&block)
+# - #mkdir(*args)
+# - #opendir(*args)
+#
+# === Utilities
+#
+# These methods are a mixture of Find, FileUtils, and others:
+# - #find(&block)
+# - #mkpath
+# - #rmtree
+# - #unlink / #delete
+#
+#
+# == Method documentation
+#
+# As the above section shows, most of the methods in Pathname are facades. The
+# documentation for these methods generally just says, for instance, "See
+# FileTest.writable?", as you should be familiar with the original method
+# anyway, and its documentation (e.g. through +ri+) will contain more
+# information. In some cases, a brief description will follow.
#
-
class Pathname
# The version string.
@@ -17,33 +221,75 @@ class Pathname
# :stopdoc:
- # to_path is implemented so Pathname objects are usable with File.open, etc.
- TO_PATH = :to_path
+ attr_reader :path
+ protected :path
+
+ # :startdoc:
- SAME_PATHS = if File::FNM_SYSCASE.nonzero?
- # Avoid #zero? here because #casecmp can return nil.
- proc {|a, b| a.casecmp(b) == 0}
- else
- proc {|a, b| a == b}
+ # call-seq:
+ # Pathname.new(path) -> new_pathname
+ #
+ # Returns a new \Pathname object based on the given +path+,
+ # via <tt>File.path(path).dup</tt>.
+ # the +path+ may be a String, a File, a Dir, or another \Pathname;
+ # see File.path:
+ #
+ # Pathname.new('.') # => #<Pathname:.>
+ # Pathname.new('/usr/bin') # => #<Pathname:/usr/bin>
+ # Pathname.new(File.new('LEGAL')) # => #<Pathname:LEGAL>
+ # Pathname.new(Dir.new('.')) # => #<Pathname:.>
+ # Pathname.new(Pathname.new('.')) # => #<Pathname:.>
+ #
+ def initialize(path)
+ @path = File.path(path).dup
+ rescue TypeError => e
+ raise e.class, "Pathname.new requires a String, #to_path or #to_str", cause: nil
end
+ #
+ # Freze self.
+ #
+ def freeze
+ super
+ @path.freeze
+ self
+ end
- if File::ALT_SEPARATOR
- SEPARATOR_LIST = "#{Regexp.quote File::ALT_SEPARATOR}#{Regexp.quote File::SEPARATOR}"
- SEPARATOR_PAT = /[#{SEPARATOR_LIST}]/
- else
- SEPARATOR_LIST = "#{Regexp.quote File::SEPARATOR}"
- SEPARATOR_PAT = /#{Regexp.quote File::SEPARATOR}/
+ # call-seq:
+ # self == other -> true or false
+ #
+ # Returns whether the stored paths in +self+ and +other+ are equal:
+ #
+ # pn = Pathname('lib')
+ # pn == Pathname('lib') # => true
+ # pn == Pathname('./lib') # => false
+ #
+ # Returns +false+ if +other+ is not a pathname:
+ #
+ # pn == 'lib' # => false
+ #
+ def ==(other)
+ return false unless Pathname === other
+ other.path == @path
end
+ alias === ==
+ alias eql? ==
- if File.dirname('A:') == 'A:.' # DOSish drive letter
- ABSOLUTE_PATH = /\A(?:[A-Za-z]:|#{SEPARATOR_PAT})/
- else
- ABSOLUTE_PATH = /\A#{SEPARATOR_PAT}/
+ def hash # :nodoc:
+ @path.hash
end
- private_constant :ABSOLUTE_PATH
- # :startdoc:
+ # Return the path as a String.
+ def to_s
+ @path.dup
+ end
+
+ # to_path is implemented so Pathname objects are usable with File.open, etc.
+ alias to_path to_s
+
+ def inspect # :nodoc:
+ "#<#{self.class}:#{@path}>"
+ end
# Creates a full path, including any intermediate directories that don't yet
# exist.
@@ -53,9 +299,9 @@ class Pathname
path = @path == '/' ? @path : @path.chomp('/')
stack = []
- until File.directory?(path) || File.dirname(path) == path
+ until File.directory?(path) || (parent = File.dirname(path)) == path
stack.push path
- path = File.dirname(path)
+ path = parent
end
stack.reverse_each do |dir|
@@ -73,50 +319,144 @@ class Pathname
self
end
- # chop_basename(path) -> [pre-basename, basename] or nil
- def chop_basename(path) # :nodoc:
- base = File.basename(path)
- if /\A#{SEPARATOR_PAT}?\z/o.match?(base)
- return nil
- else
- return path[0, path.rindex(base)], base
- end
- end
- private :chop_basename
-
- # split_names(path) -> prefix, [name, ...]
- def split_names(path) # :nodoc:
- names = []
- while r = chop_basename(path)
- path, basename = r
- names.unshift basename
- end
- return path, names
- end
- private :split_names
-
def prepend_prefix(prefix, relpath) # :nodoc:
if relpath.empty?
File.dirname(prefix)
- elsif /#{SEPARATOR_PAT}/o.match?(prefix)
- prefix = File.dirname(prefix)
- prefix = File.join(prefix, "") if File.basename(prefix + 'a') != 'a'
- prefix + relpath
+ elsif has_separator?(prefix)
+ add_trailing_separator(File.dirname(prefix)) + relpath
else
prefix + relpath
end
end
private :prepend_prefix
- # Returns clean pathname of +self+ with consecutive slashes and useless dots
- # removed. The filesystem is not accessed.
+ # :markup: markdown
+ #
+ # call-seq:
+ # cleanpath(symlinks = false) -> new_pathname
+ #
+ # Returns a new \Pathname object, "cleaned" of unnecessary separators,
+ # single-dot entries, and double-dot entries.
+ #
+ # When `self` is empty, returns a pathname with a single-dot entry:
+ #
+ # ```
+ # Pathname('').cleanpath # => #<Pathname:.>
+ # ```
+ #
+ # <b>Separators</b>
+ #
+ # A lone separator is preserved:
+ #
+ # ```
+ # Pathname('/').cleanpath # => #<Pathname:/>
+ # ```
+ #
+ # Multiple trailing separators are removed:
+ #
+ # ```
+ # Pathname('foo/////').cleanpath # => #<Pathname:foo>
+ # Pathname('foo/').cleanpath # => #<Pathname:foo>
+ # ```
#
- # If +consider_symlink+ is +true+, then a more conservative algorithm is used
- # to avoid breaking symbolic linkages. This may retain more +..+
- # entries than absolutely necessary, but without accessing the filesystem,
- # this can't be avoided.
+ # Multiple embedded separators are reduced to a single separator:
#
- # See Pathname#realpath.
+ # ```
+ # Pathname('foo///bar').cleanpath # => #<Pathname:foo/bar>
+ # ```
+ #
+ # Multiple leading separators are reduced:
+ #
+ # ```
+ # # On Windows, where File.dirname('//') == '//'.
+ # Pathname('/////foo').cleanpath # => #<Pathname://foo>
+ # Pathname('/////').cleanpath # => #<Pathname://>
+ # # Otherwise, where File.dirname('//') == '/'.
+ # Pathname('/////foo').cleanpath # => #<Pathname:/foo>
+ # Pathname('/////').cleanpath # => #<Pathname:/>
+ # ```
+ #
+ # <b>Single-Dot Entries</b>
+ #
+ # A lone single-dot entry is preserved:
+ #
+ # ```
+ # Pathname('.').cleanpath # => #<Pathname:.>
+ # ```
+ #
+ # A non-lone single-dot entry, regardless of its location, is removed:
+ #
+ # ```
+ # Pathname('foo/././././bar').cleanpath # => #<Pathname:foo/bar>
+ # Pathname('./foo/./././bar').cleanpath # => #<Pathname:foo/bar>
+ # Pathname('foo/./././bar/./').cleanpath # => #<Pathname:foo/bar>
+ # ```
+ #
+ # <b>Double-Dot Entries</b>
+ #
+ # A lone double-dot entry is preserved:
+ #
+ # ```
+ # Pathname('..').cleanpath # => #<Pathname:..>
+ # ```
+ #
+ # When a non-lone double-dot entry is preceded by a named entry, both are removed:
+ #
+ # ```
+ # Pathname('foo/..').cleanpath # => #<Pathname:.>
+ # Pathname('foo/../bar').cleanpath # => #<Pathname:bar>
+ # Pathname('foo/../bar/..').cleanpath # => #<Pathname:.>
+ # Pathname('foo/bar/./../..').cleanpath # => #<Pathname:.>
+ # ```
+ #
+ # When a non-lone double-dot entry is _not_ preceded by a named entry,
+ # it is preserved:
+ #
+ # ```
+ # Pathname('../..').cleanpath # => #<Pathname:../..>
+ # ```
+ #
+ # A non-lone meaningless double-dot entry is removed:
+ #
+ # ```
+ # Pathname('/..').cleanpath # => #<Pathname:/>
+ # Pathname('/../..').cleanpath # => #<Pathname:/>
+ # ```
+ #
+ # <b> Symbolic Links</b>
+ #
+ # If the path may contain [symbolic links][symbolic link],
+ # consider give optional argument `symlinks` as `true`;
+ # the method then uses a more conservative algorithm
+ # that avoids breaking symbolic links.
+ # This may preserve more double-dot entries than are absolutely necessary,
+ # but without accessing the filesystem, this can't be avoided.
+ #
+ # Examples:
+ #
+ # ```
+ # Pathname('a/').cleanpath # => #<Pathname:a>
+ # Pathname('a/').cleanpath(true) # => #<Pathname:a/>
+ #
+ # Pathname('a/.').cleanpath # => #<Pathname:a>
+ # Pathname('a/.').cleanpath(true) # => #<Pathname:a/.>
+ #
+ # Pathname('a/./').cleanpath # => #<Pathname:a>
+ # Pathname('a/./').cleanpath(true) # => #<Pathname:a/.>
+ #
+ # Pathname('a/b/.').cleanpath # => #<Pathname:a/b>
+ # Pathname('a/b/.').cleanpath(true) # => #<Pathname:a/b/.>
+ #
+ # Pathname('a/../.').cleanpath # => #<Pathname:.>
+ # Pathname('a/../.').cleanpath(true) # => #<Pathname:a/..>
+ #
+ # Pathname('a/b/../../../../c/../d').cleanpath
+ # # => #<Pathname:../../d>
+ # Pathname('a/b/../../../../c/../d').cleanpath(true)
+ # # => #<Pathname:a/b/../../../../c/../d>
+ # ```
+ #
+ # [symbolic link]: https://en.wikipedia.org/wiki/Symbolic_link
#
def cleanpath(consider_symlink=false)
if consider_symlink
@@ -149,46 +489,13 @@ class Pathname
end
end
pre.tr!(File::ALT_SEPARATOR, File::SEPARATOR) if File::ALT_SEPARATOR
- if /#{SEPARATOR_PAT}/o.match?(File.basename(pre))
+ if has_separator?(File.basename(pre))
names.shift while names[0] == '..'
end
self.class.new(prepend_prefix(pre, File.join(*names)))
end
private :cleanpath_aggressive
- # has_trailing_separator?(path) -> bool
- def has_trailing_separator?(path) # :nodoc:
- if r = chop_basename(path)
- pre, basename = r
- pre.length + basename.length < path.length
- else
- false
- end
- end
- private :has_trailing_separator?
-
- # add_trailing_separator(path) -> path
- def add_trailing_separator(path) # :nodoc:
- if File.basename(path + 'a') == 'a'
- path
- else
- File.join(path, "") # xxx: Is File.join is appropriate to add separator?
- end
- end
- private :add_trailing_separator
-
- def del_trailing_separator(path) # :nodoc:
- if r = chop_basename(path)
- pre, basename = r
- pre + basename
- elsif /#{SEPARATOR_PAT}+\z/o =~ path
- $` + File.dirname(path)[/#{SEPARATOR_PAT}*\z/o]
- else
- path
- end
- end
- private :del_trailing_separator
-
def cleanpath_conservative # :nodoc:
path = @path
names = []
@@ -198,7 +505,7 @@ class Pathname
names.unshift base if base != '.'
end
pre.tr!(File::ALT_SEPARATOR, File::SEPARATOR) if File::ALT_SEPARATOR
- if /#{SEPARATOR_PAT}/o.match?(File.basename(pre))
+ if has_separator?(File.basename(pre))
names.shift while names[0] == '..'
end
if names.empty?
@@ -235,32 +542,6 @@ class Pathname
end
end
- #
- # Predicate method for root directories. Returns +true+ if the
- # pathname consists of consecutive slashes.
- #
- # It doesn't access the filesystem. So it may return +false+ for some
- # pathnames which points to roots such as <tt>/usr/..</tt>.
- #
- def root?
- chop_basename(@path) == nil && /#{SEPARATOR_PAT}/o.match?(@path)
- end
-
- # Predicate method for testing whether a path is absolute.
- #
- # It returns +true+ if the pathname begins with a slash.
- #
- # p = Pathname.new('/im/sure')
- # p.absolute?
- # #=> true
- #
- # p = Pathname.new('not/so/sure')
- # p.absolute?
- # #=> false
- def absolute?
- ABSOLUTE_PATH.match? @path
- end
-
# The opposite of Pathname#absolute?
#
# It returns +false+ if the pathname begins with a slash.
@@ -276,19 +557,28 @@ class Pathname
!absolute?
end
+ # :markup: markdown
+ #
+ # call-seq:
+ # each_filename {|component| ... } -> nil
+ # each_filename -> new_enumerator
#
- # Iterates over each component of the path.
+ # With a block given, yields each component of the string path:
#
- # Pathname.new("/usr/bin/ruby").each_filename {|filename| ... }
- # # yields "usr", "bin", and "ruby".
+ # ```ruby
+ # Pathname('/foo/bar/baz').each_filename {|filename| p filename }
+ # => nil
+ # ```
#
- # Returns an Enumerator if no block was given.
+ # Output:
#
- # enum = Pathname.new("/usr/bin/ruby").each_filename
- # # ... do stuff ...
- # enum.each { |e| ... }
- # # yields "usr", "bin", and "ruby".
+ # ```text
+ # "foo"
+ # "bar"
+ # "baz"
+ # ```
#
+ # With no block given, returns a new Enumerator.
def each_filename # :yield: filename
return to_enum(__method__) unless block_given?
_, names = split_names(@path)
@@ -296,31 +586,32 @@ class Pathname
nil
end
- # Iterates over and yields a new Pathname object
- # for each element in the given path in descending order.
+ # :markup: markdown
#
- # Pathname.new('/path/to/some/file.rb').descend {|v| p v}
- # #<Pathname:/>
- # #<Pathname:/path>
- # #<Pathname:/path/to>
- # #<Pathname:/path/to/some>
- # #<Pathname:/path/to/some/file.rb>
+ # call-seq:
+ # descend {|entry| ... } -> nil
+ # descend -> new_enumerator
#
- # Pathname.new('path/to/some/file.rb').descend {|v| p v}
- # #<Pathname:path>
- # #<Pathname:path/to>
- # #<Pathname:path/to/some>
- # #<Pathname:path/to/some/file.rb>
+ # With a block given, yields a new pathname for each successive dirname
+ # in the stored path; see File.dirname:
#
- # Returns an Enumerator if no block was given.
- #
- # enum = Pathname.new("/usr/bin/ruby").descend
- # # ... do stuff ...
- # enum.each { |e| ... }
- # # yields Pathnames /, /usr, /usr/bin, and /usr/bin/ruby.
- #
- # It doesn't access the filesystem.
+ # ```ruby
+ # # Absolute path.
+ # Pathname('/path/to/some/file.rb').descend {|pn| p pn }
+ # # #<Pathname:/>
+ # # #<Pathname:/path>
+ # # #<Pathname:/path/to>
+ # # #<Pathname:/path/to/some>
+ # # #<Pathname:/path/to/some/file.rb>
+ # # Relative path.
+ # Pathname('path/to/some/file.rb').descend {|pn| p pn }
+ # # #<Pathname:path>
+ # # #<Pathname:path/to>
+ # # #<Pathname:path/to/some>
+ # # #<Pathname:path/to/some/file.rb>
+ # ```
#
+ # With no block given, returns a new Enumerator.
def descend
return to_enum(__method__) unless block_given?
vs = []
@@ -329,31 +620,22 @@ class Pathname
nil
end
- # Iterates over and yields a new Pathname object
- # for each element in the given path in ascending order.
- #
- # Pathname.new('/path/to/some/file.rb').ascend {|v| p v}
- # #<Pathname:/path/to/some/file.rb>
- # #<Pathname:/path/to/some>
- # #<Pathname:/path/to>
- # #<Pathname:/path>
- # #<Pathname:/>
- #
- # Pathname.new('path/to/some/file.rb').ascend {|v| p v}
- # #<Pathname:path/to/some/file.rb>
- # #<Pathname:path/to/some>
- # #<Pathname:path/to>
- # #<Pathname:path>
+ # call-seq:
+ # ascend {|entry| ... } -> nil
+ # ascend -> new_enumerator
#
- # Returns an Enumerator if no block was given.
+ # With a block given,
+ # yields +self+, then a new pathname for each successive dirname in the stored path;
+ # see File.dirname:
#
- # enum = Pathname.new("/usr/bin/ruby").ascend
- # # ... do stuff ...
- # enum.each { |e| ... }
- # # yields Pathnames /usr/bin/ruby, /usr/bin, /usr, and /.
- #
- # It doesn't access the filesystem.
+ # Pathname('/path/to/some/file.rb').ascend {|dirname| p dirname}
+ # #<Pathname:/path/to/some/file.rb>
+ # #<Pathname:/path/to/some>
+ # #<Pathname:/path/to>
+ # #<Pathname:/path>
+ # #<Pathname:/>
#
+ # With no block given, returns a new Enumerator.
def ascend
return to_enum(__method__) unless block_given?
path = @path
@@ -365,28 +647,75 @@ class Pathname
end
end
+ # call-seq:
+ # self + other -> new_pathname
+ #
+ # Returns a new \Pathname object based on the content of +self+ and +other+;
+ # argument +other+ may be a String, a File, a Dir, or another \Pathname:
+ #
+ # pn = Pathname('foo') # => #<Pathname:foo>
+ # pn + 'bar' # => #<Pathname:foo/bar>
+ # pn + File.new('LEGAL') # => #<Pathname:foo/LEGAL>
+ # pn + Dir.new('lib') # => #<Pathname:foo/lib>
+ # pn + Pathname('bar') # => #<Pathname:foo/bar>
+ #
+ # When +other+ specifies a relative path (see #relative?),
+ # it is combined with +self+ to form a new pathname:
+ #
+ # Pathname('/a/b') + 'c' # => #<Pathname:/a/b/c>
+ #
+ # Extra component separators (<tt>'/'</tt>) are removed:
+ #
+ # Pathname('/a/b/') + 'c' # => #<Pathname:/a/b/c>
+ #
+ # Extra current-directory components (<tt>'.'</tt>) are removed:
+ #
+ # Pathname('a') + '.' # => #<Pathname:a>
+ # Pathname('.') + 'a' # => #<Pathname:a>
+ # Pathname('.') + '.' # => #<Pathname:.>
+ #
+ # Parent-directory components (<tt>'..'</tt>) are:
#
- # Appends a pathname fragment to +self+ to produce a new Pathname object.
- # Since +other+ is considered as a path relative to +self+, if +other+ is
- # an absolute path, the new Pathname object is created from just +other+.
+ # - Resolved, when possible:
#
- # p1 = Pathname.new("/usr") # Pathname:/usr
- # p2 = p1 + "bin/ruby" # Pathname:/usr/bin/ruby
- # p3 = p1 + "/etc/passwd" # Pathname:/etc/passwd
+ # Pathname('a') + '..' # => #<Pathname:.>
+ # Pathname('a/b') + '..' # => #<Pathname:a>
+ # Pathname('/') + '../a' # => #<Pathname:/a>
+ # Pathname('a') + '../b' # => #<Pathname:b>
+ # Pathname('a/b') + '../c' # => #<Pathname:a/c>
+ # Pathname('a//b/c') + '../d//e' # => #<Pathname:a//b/d//e>
#
- # # / is aliased to +.
- # p4 = p1 / "bin/ruby" # Pathname:/usr/bin/ruby
- # p5 = p1 / "/etc/passwd" # Pathname:/etc/passwd
+ # - Removed, when not needed:
#
- # This method doesn't access the file system; it is pure string manipulation.
+ # Pathname('/') + '..' # => #<Pathname:/>
+ #
+ # - Retained, when needed:
+ #
+ # Pathname('..') + '..' # => #<Pathname:../..>
+ # Pathname('..') + '../a' # => #<Pathname:../../a>
+ #
+ # When +other+ specifies an absolute path (see #absolute?),
+ # equivalent to <tt>Pathname(other.to_s)</tt>:
+ #
+ # Pathname('/a') + '/b/c' # => #<Pathname:/b/c>
+ #
+ # Occurrences of <tt>'/'</tt>, <tt>'.'</tt>, and <tt>'..'</tt> are preserved:
+ #
+ # Pathname('/a') + '//b//c/./../d' # => #<Pathname://b//c/./../d>
+ #
+ # This method does not access the file system, so +other+ need not represent
+ # an existing (or even a valid) file or directory path:
+ #
+ # Pathname('/var') + 'nosuch:ever' # => #<Pathname:/var/nosuch:ever>
#
def +(other)
other = Pathname.new(other) unless Pathname === other
- Pathname.new(plus(@path, other.to_s))
+ Pathname.new(plus(@path, other.path))
end
alias / +
- def plus(path1, path2) # -> path # :nodoc:
+ # (path1, path2) -> path
+ def plus(path1, path2) # :nodoc:
prefix2 = path2
index_list2 = []
basename_list2 = []
@@ -413,7 +742,7 @@ class Pathname
basename_list2.shift
end
r1 = chop_basename(prefix1)
- if !r1 && (r1 = /#{SEPARATOR_PAT}/o.match?(File.basename(prefix1)))
+ if !r1 && (r1 = has_separator?(File.basename(prefix1)))
while !basename_list2.empty? && basename_list2.first == '..'
index_list2.shift
basename_list2.shift
@@ -453,76 +782,77 @@ class Pathname
self + result
end
+ # :markup: markdown
+ #
+ # call-seq:
+ # children(with_dirnames = true) -> array_of_pathnames
#
- # Returns the children of the directory (files and subdirectories, not
- # recursive) as an array of Pathname objects.
+ # Returns an array of pathnames;
+ # each represents a child of the entry represented by `self`,
+ # which must be an existing directory in the underlying file system.
#
- # By default, the returned pathnames will have enough information to access
- # the files. If you set +with_directory+ to +false+, then the returned
- # pathnames will contain the filename only.
+ # With `with_dirnames` given as `true` (the default),
+ # each pathname contains the full entry:
#
- # For example:
- # pn = Pathname("/usr/lib/ruby/1.8")
- # pn.children
- # # -> [ Pathname:/usr/lib/ruby/1.8/English.rb,
- # Pathname:/usr/lib/ruby/1.8/Env.rb,
- # Pathname:/usr/lib/ruby/1.8/abbrev.rb, ... ]
- # pn.children(false)
- # # -> [ Pathname:English.rb, Pathname:Env.rb, Pathname:abbrev.rb, ... ]
+ # ```ruby
+ # Pathname('lib').children.size # => 72
+ # Pathname('lib').children.take(3)
+ # # => [#<Pathname:lib/bundled_gems.rb>, #<Pathname:lib/bundler>, #<Pathname:lib/bundler.rb>]
+ # ```
+ # With `with_dirnames` given as `false`,
+ # each pathname contains only the basename of the entry:
#
- # Note that the results never contain the entries +.+ and +..+ in
- # the directory because they are not children.
+ # ```ruby
+ # Pathname('lib').children(false).take(3)
+ # # => [#<Pathname:bundled_gems.rb>, #<Pathname:bundler>, #<Pathname:bundler.rb>]
+ # ```
#
+ # Note that entries `.` and `..` in directory are not actually children,
+ # and so are never included in the result.
def children(with_directory=true)
with_directory = false if @path == '.'
- result = []
- Dir.foreach(@path) {|e|
- next if e == '.' || e == '..'
- if with_directory
- result << self.class.new(File.join(@path, e))
- else
- result << self.class.new(e)
- end
- }
+ result = Dir.children(@path)
+ if with_directory
+ result.map! {|e| self.class.new(File.join(@path, e))}
+ else
+ result.map! {|e| self.class.new(e)}
+ end
result
end
- # Iterates over the children of the directory
- # (files and subdirectories, not recursive).
- #
- # It yields Pathname object for each child.
+ # :markup: markdown
#
- # By default, the yielded pathnames will have enough information to access
- # the files.
+ # call-seq:
+ # each_child(with_dirnames = true) {|entry| ... } -> array_of_pathnames
+ # each_child(with_dirnames = true) -> new_enumerator
#
- # If you set +with_directory+ to +false+, then the returned pathnames will
- # contain the filename only.
+ # With a block given and `with_dirnames` given as `true` (the default),
+ # yields a new pathname for each child
+ # of the entry represented by `self`;
+ # returns an array of those pathnames:
#
- # Pathname("/usr/local").each_child {|f| p f }
- # #=> #<Pathname:/usr/local/share>
- # # #<Pathname:/usr/local/bin>
- # # #<Pathname:/usr/local/games>
- # # #<Pathname:/usr/local/lib>
- # # #<Pathname:/usr/local/include>
- # # #<Pathname:/usr/local/sbin>
- # # #<Pathname:/usr/local/src>
- # # #<Pathname:/usr/local/man>
+ # ```ruby
+ # Pathname('include').each_child {|child| p child }
+ # # #<Pathname:include/ruby>
+ # # #<Pathname:include/ruby.h>
+ # # => [#<Pathname:include/ruby>, #<Pathname:include/ruby.h>]
+ # ```
#
- # Pathname("/usr/local").each_child(false) {|f| p f }
- # #=> #<Pathname:share>
- # # #<Pathname:bin>
- # # #<Pathname:games>
- # # #<Pathname:lib>
- # # #<Pathname:include>
- # # #<Pathname:sbin>
- # # #<Pathname:src>
- # # #<Pathname:man>
+ # With a block given and `with_dirnames` given as `false`,
+ # yields a new pathname for each child
+ # of the entry represented by `self` with its dirname omitted;
+ # returns an array of those pathnames:
#
- # Note that the results never contain the entries +.+ and +..+ in
- # the directory because they are not children.
+ # ```ruby
+ # Pathname('include').each_child(false) {|child| p child }
+ # # #<Pathname:ruby>
+ # # #<Pathname:ruby.h>
+ # # => [#<Pathname:ruby>, #<Pathname:ruby.h>]
+ # ```
#
- # See Pathname#children
+ # Note that entries `'.'` and `'..'` are not children.
#
+ # With no block given, returns a new Enumerator.
def each_child(with_directory=true, &b)
children(with_directory).each(&b)
end
@@ -543,8 +873,8 @@ class Pathname
#
def relative_path_from(base_directory)
base_directory = Pathname.new(base_directory) unless base_directory.is_a? Pathname
- dest_directory = self.cleanpath.to_s
- base_directory = base_directory.cleanpath.to_s
+ dest_directory = self.cleanpath.path
+ base_directory = base_directory.cleanpath.path
dest_prefix = dest_directory
dest_names = []
while r = chop_basename(dest_prefix)
@@ -557,12 +887,12 @@ class Pathname
base_prefix, basename = r
base_names.unshift basename if basename != '.'
end
- unless SAME_PATHS[dest_prefix, base_prefix]
+ unless same_paths?(dest_prefix, base_prefix)
raise ArgumentError, "different prefix: #{dest_prefix.inspect} and #{base_directory.inspect}"
end
while !dest_names.empty? &&
!base_names.empty? &&
- SAME_PATHS[dest_names.first, base_names.first]
+ same_paths?(dest_names.first, base_names.first)
dest_names.shift
base_names.shift
end
@@ -578,3 +908,988 @@ class Pathname
end
end
end
+
+class Pathname # * File *
+
+ # :markup: markdown
+ #
+ # call-seq:
+ # each_line(sep = $/, **opts) {|line| ... } → nil
+ # each_line(limit, **opts) {|line| ... } → nil
+ # each_line(sep, limit, **opts) {|line| ... } → nil
+ # each_line(...) → new_enumerator
+ #
+ # With a block given, calls the block with each line
+ # from the file represented by `self`;
+ # returns `nil`:
+ #
+ # ```ruby
+ # lines = []
+ # Pathname('COPYING').each_line {|line| lines << line }
+ # lines.take(3)
+ # # =>
+ # # ["{日本語}[rdoc-ref:COPYING.ja]\n",
+ # # "\n",
+ # # "Ruby is copyrighted free software by Yukihiro Matsumoto <matz@netlab.jp>.\n"]
+ # ```
+ #
+ # The lines are read using IO.foreach,
+ # all arguments and options are passed to that method;
+ # see details at IO.foreach.
+ #
+ # With no block given, returns a new Enumerator.
+ def each_line(...) # :yield: line
+ File.foreach(@path, ...)
+ end
+
+ # call-seq:
+ # read(length = nil, offset = 0, **opts) -> string or nil
+ #
+ # Reads and returns some or all of the content of the file
+ # whose path is <tt>self.to_s</tt>.
+ #
+ # With no arguments given,
+ # reads in text mode and returns the entire content of the file:
+ #
+ # Pathname.new('t.txt').read
+ # # => "First line\nSecond line\n\nFourth line\nFifth line\n"
+ # Pathname.new('t.ja').read
+ # # => "ã“ã‚“ã«ã¡ã¯"
+ # Pathname.new('t.dat').read
+ # # => "\xFE\xFF\x99\x90\x99\x91\x99\x92\x99\x93\x99\x94"
+ #
+ # On Windows, text mode can terminate reading and leave bytes in the file unread
+ # when encountering certain special bytes.
+ # Consider using #binread if all bytes in the file should be read.
+ #
+ # With argument +length+ given, returns +length+ bytes if available:
+ #
+ # Pathname.new('t.txt').read(7)
+ # # => "First l"
+ # Pathname.new('t.ja').read(7)
+ # # => "\xE3\x81\x93\xE3\x82\x93\xE3"
+ # Pathname.new('t.dat').read(7)
+ # # => "\xFE\xFF\x99\x90\x99\x91\x99"
+ #
+ # Returns all bytes if +length+ is larger than the files size:
+ #
+ # Pathname.new('t.txt').read(700)
+ # # => "First line\r\nSecond line\r\n\r\nFourth line\r\nFifth line\r\n"
+ # Pathname.new('t.ja').read(700)
+ # # => "\xE3\x81\x93\xE3\x82\x93\xE3\x81\xAB\xE3\x81\xA1\xE3\x81\xAF"
+ # Pathname.new('t.dat').read(700)
+ # # => "\xFE\xFF\x99\x90\x99\x91\x99\x92\x99\x93\x99\x94"
+ #
+ # With arguments +length+ and +offset+ given,
+ # returns +length+ bytes if available, beginning at the given +offset+:
+ #
+ # Pathname.new('t.txt').read(10, 2)
+ # # => "rst line\r\n"
+ # Pathname.new('t.ja').read(10, 2)
+ # # => "\x93\xE3\x82\x93\xE3\x81\xAB\xE3\x81\xA1"
+ # Pathname.new('t.dat').read(10, 2)
+ # # => "\x99\x90\x99\x91\x99\x92\x99\x93\x99\x94"
+ #
+ # Returns +nil+ if +offset+ is past the end of the file:
+ #
+ # Pathname.new('t.txt').read(10, 200) # => nil
+ #
+ # Optional keyword arguments +opts+ specify:
+ #
+ # - {Open Options}[rdoc-ref:IO@Open+Options].
+ # - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
+ #
+ def read(...) File.read(@path, ...) end
+
+ # call-seq:
+ # binread(length = nil, offset = 0) -> string or nil
+ #
+ # Behaves like #read, except that the file is opened in binary mode
+ # with ASCII-8BIT encoding.
+ #
+ def binread(...) File.binread(@path, ...) end
+
+ # See <tt>File.readlines</tt>. Returns all the lines from the file.
+ def readlines(...) File.readlines(@path, ...) end
+
+ # See <tt>File.sysopen</tt>.
+ def sysopen(...) File.sysopen(@path, ...) end
+
+ # call-seq:
+ # write(data, offset = 0, **opts) -> nonnegative_integer
+ #
+ # Opens the file at +self.to_s+, writes the given +data+ to it,
+ # and closes the file; returns the number of bytes written.
+ #
+ # With only argument +data+ given, writes the given data to the file:
+ #
+ # path = 't.tmp'
+ # pn = Pathname.new(path)
+ # pn.write('foo') # => 3
+ # File.read(path) # => "foo"
+ #
+ # If +offset+ is zero (the default), the file is overwritten:
+ #
+ # pn.write('bar')
+ # File.read(path) # => "bar"
+ #
+ # If +offset+ in within the file content, the file is partly overwritten:
+ #
+ # pn.write('foobarbaz')
+ # pn.write('BAR', 3)
+ # File.read(path) # => "fooBARbaz"
+ #
+ # If +offset+ is outside the file content,
+ # the file is padded with null characters <tt>"\u0000"</tt>:
+ #
+ # pn.write('bat', 12)
+ # File.read(path) # => "fooBARbaz\u0000\u0000\u0000bat"
+ #
+ # Optional keyword arguments +opts+ specify:
+ #
+ # - {Open Options}[rdoc-ref:IO@Open+Options].
+ # - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
+ #
+ def write(...) File.write(@path, ...) end
+
+ # call-seq:
+ # binwrite(string, offset = 0, **opts) -> nonnegative_integer
+ #
+ # Behaves like #write, except that the file is opened in binary mode
+ # with ASCII-8BIT encoding.
+ def binwrite(...) File.binwrite(@path, ...) end
+
+ # call-seq:
+ # atime -> new_time
+ #
+ # Returns a new Time object containing the time of the most recent
+ # access (read or write) to the entry represented by `self`;
+ # see {File System Timestamps}[rdoc-ref:file/timestamps.md]:
+ #
+ # # Work in a temporary directory.
+ # require 'tmpdir'
+ # Dir.mktmpdir do |tmpdirpath|
+ # # A subdirectory therein, and its Pathname.
+ # dirpath = File.join(tmpdirpath, 'subdir')
+ # Dir.mkdir(dirpath)
+ # dir_pn = Pathname(dirpath)
+ # puts "Create directory; establishes atime for directory."
+ # puts " Directory atime: #{dir_pn.atime}"
+ # sleep(1)
+ #
+ # # A file in the subdirectory, and its Pathname.
+ # filepath = File.join(dirpath, 't.txt')
+ # puts "Create file; establishes atime for file, updates atime for directory."
+ # File.write(filepath, 'foo')
+ # file_pn = Pathname(filepath)
+ # puts " File atime: #{file_pn.atime}"
+ # puts " Directory atime: #{dir_pn.atime}"
+ # sleep(1)
+ # puts "Write file; updates atimes for file and directory."
+ # File.write(filepath, 'bar')
+ # puts " File atime: #{file_pn.atime}"
+ # puts " Directory atime: #{dir_pn.atime}"
+ # end
+ #
+ # Output:
+ #
+ # Create directory; establishes atime for directory.
+ # Directory atime: 2026-05-14 14:36:43 +0100
+ # Create file; establishes atime for file, updates atime for directory.
+ # File atime: 2026-05-14 14:36:44 +0100
+ # Directory atime: 2026-05-14 14:36:44 +0100
+ # Write file; updates atimes for file and directory.
+ # File atime: 2026-05-14 14:36:45 +0100
+ # Directory atime: 2026-05-14 14:36:45 +0100
+ #
+ def atime() File.atime(@path) end
+
+ # :markup: markdown
+ #
+ # call-seq:
+ # birthtime -> new_time
+ #
+ # Returns a new Time object containing the create time of the entry
+ # represented by `self`;
+ # see [File System Timestamps](rdoc-ref:file/timestamps.md):
+ #
+ # ```ruby
+ # # Work in a temporary directory.
+ # Pathname.mktmpdir do |tmpdirpath|
+ # # A subdirectory therein, and its Pathname.
+ # dirpath = File.join(tmpdirpath, 'subdir')
+ # dir_pn = Pathname(dirpath)
+ # puts "Create directory; directory birthtime established."
+ # dir_pn.mkdir
+ # puts " Directory birthtime: #{dir_pn.birthtime}"
+ # sleep(1)
+ #
+ # # A file in the subdirectory, and its Pathname.
+ # filepath = File.join(dirpath, 't.txt')
+ # file_pn = Pathname(filepath)
+ # puts "Create file; file birthtime established; directory birthtime not updated."
+ # file_pn.write('foo')
+ # puts " File birthtime: #{file_pn.birthtime}"
+ # puts " Directory birthtime: #{dir_pn.birthtime}"
+ # sleep(1)
+ # puts "Write file; neither birthtime updated."
+ # file_pn.write('bar')
+ # puts " File birthtime: #{file_pn.birthtime}"
+ # puts " Directory birthtime: #{dir_pn.birthtime}"
+ # end
+ # ```
+ #
+ # Output:
+ #
+ # ```text
+ # Create directory; directory birthtime established.
+ # Directory birthtime: 2026-05-14 23:41:12 +0100
+ # Create file; file birthtime established; directory birthtime not updated.
+ # File birthtime: 2026-05-14 23:41:13 +0100
+ # Directory birthtime: 2026-05-14 23:41:12 +0100
+ # Write file; neither birthtime updated.
+ # File birthtime: 2026-05-14 23:41:13 +0100
+ # Directory birthtime: 2026-05-14 23:41:12 +0100
+ # ```
+ #
+ def birthtime() File.birthtime(@path) end
+
+ # :markup: markdown
+ #
+ # call-seq:
+ # ctime -> new_time
+ #
+ # On Windows, returns the #birthtime.
+ #
+ # On other systems,
+ # returns a new Time object containing the time of the most recent
+ # metadata change to the entry represented by `self`;
+ # see {File System Timestamps}[rdoc-ref:file/timestamps.md]:
+ #
+ # ```ruby
+ # # Work in a temporary directory.
+ # Pathname.mktmpdir do |tmpdirpath|
+ # # A subdirectory therein, and its Pathname.
+ # dirpath = File.join(tmpdirpath, 'subdir')
+ # dir_pn = Pathname(dirpath)
+ # puts "Create directory; directory ctime established."
+ # dir_pn.mkdir
+ # puts " Directory ctime: #{dir_pn.ctime}"
+ # sleep(1)
+ #
+ # # A file in the subdirectory, and its Pathname.
+ # filepath = File.join(dirpath, 't.txt')
+ # file_pn = Pathname(filepath)
+ # puts "Create file; file ctime established; directory ctime updated."
+ # file_pn.write('foo')
+ # puts " File ctime: #{file_pn.ctime}"
+ # puts " Directory ctime: #{dir_pn.ctime}"
+ # sleep(1)
+ # puts "Write file; file ctime updated; directory ctime not updated."
+ # file_pn.write('bar')
+ # puts " File ctime: #{file_pn.ctime}"
+ # puts " Directory ctime: #{dir_pn.ctime}"
+ # sleep(1)
+ # puts "Read file; neither ctime not updated."
+ # file_pn.read
+ # puts " File ctime: #{file_pn.ctime}"
+ # puts " Directory ctime: #{dir_pn.ctime}"
+ # end
+ # ```
+ #
+ # Output:
+ #
+ # ```text
+ # Create directory; directory ctime established.
+ # Directory ctime: 2026-05-20 14:05:05 -0500
+ # Create file; file ctime established; directory ctime updated.
+ # File ctime: 2026-05-20 14:05:06 -0500
+ # Directory ctime: 2026-05-20 14:05:06 -0500
+ # Write file; file ctime updated; directory ctime not updated.
+ # File ctime: 2026-05-20 14:05:07 -0500
+ # Directory ctime: 2026-05-20 14:05:06 -0500
+ # Read file; neither ctime not updated.
+ # File ctime: 2026-05-20 14:05:07 -0500
+ # Directory ctime: 2026-05-20 14:05:06 -0500
+ # ```
+ #
+ def ctime() File.ctime(@path) end
+
+ # See <tt>File.mtime</tt>. Returns last modification time.
+ def mtime() File.mtime(@path) end
+
+
+ # :markup: markdown
+ #
+ # call-seq:
+ # chmod(mode) -> 1
+ #
+ # Changes the mode (i.e., permissions) of the entry represented by `self`;
+ # see {File Permissions}[rdoc-ref:File@File+Permissions];
+ # returns `1`:
+ #
+ # ```ruby
+ # # A helper method to make an integer mode display as octal.
+ # def pretty(mode); '0' + (mode & 0777).to_s(8); end
+ #
+ # # Work in a temporary directory.
+ # Pathname.mktmpdir do |tmpdirpath|
+ # # A subdirectory therein, and its Pathname.
+ # dirpath = File.join(tmpdirpath, 'subdir')
+ # dir_pn = Pathname(dirpath)
+ # dir_pn.mkdir
+ # # The directory mode.
+ # puts "Original directory mode: #{pretty(dir_pn.stat.mode)}"
+ # # Change the directory mode.
+ # dir_pn.chmod(0777)
+ # puts "New directory mode: #{pretty(dir_pn.stat.mode)}"
+ #
+ # # A file in the subdirectory, and its Pathname.
+ # filepath = File.join(dirpath, 't.txt')
+ # file_pn = Pathname(filepath)
+ # # Create the file.
+ # file_pn.write('foo')
+ # # The file mode.
+ # puts "Original file mode: #{pretty(file_pn.stat.mode)}"
+ # # Change the file modes.
+ # file_pn.chmod(0777)
+ # puts "New file mode: #{pretty(file_pn.stat.mode)}"
+ # end
+ # ```
+ #
+ # Output:
+ #
+ # ```text
+ # Original directory mode: 0775
+ # New directory mode: 0777
+ # Original file mode: 0664
+ # New file mode: 0777
+ # ```
+ #
+ def chmod(mode) File.chmod(mode, @path) end
+
+ # See <tt>File.lchmod</tt>.
+ def lchmod(mode) File.lchmod(mode, @path) end
+
+ # :markup: markdown
+ #
+ # call-seq:
+ # chown(owner_id, group_id) -> 0
+ #
+ # Changes the owner and group of an entry (directory or file):
+ #
+ # ```ruby
+ # # Work in a temporary directory.
+ # Pathname.mktmpdir do |tmpdirpath|
+ # # A subdirectory therein, and its Pathname.
+ # dirpath = File.join(tmpdirpath, 'subdir')
+ # dir_pn = Pathname(dirpath)
+ # dir_pn.mkdir
+ # dir_stat = File.stat(dirpath)
+ # puts "Original directory owner: #{dir_stat.uid}"
+ # puts "Original directory group: #{dir_stat.gid}"
+ # dir_pn.chown(1000, 1000)
+ # dir_stat = File.stat(dirpath)
+ # puts "New directory owner: #{dir_stat.uid}"
+ # puts "New directory group: #{dir_stat.gid}"
+ #
+ # # A file in the subdirectory, and its Pathname.
+ # filepath = File.join(dirpath, 't.txt')
+ # file_pn = Pathname(filepath)
+ # # Create the file.
+ # file_pn.write('foo')
+ # file_stat = File.stat(filepath)
+ # puts "Original file owner: #{file_stat.uid}"
+ # puts "Original file group: #{file_stat.gid}"
+ # file_pn = Pathname(dirpath)
+ # file_pn.chown(1000, 1000)
+ # file_stat = File.stat(dirpath)
+ # puts "New file owner: #{file_stat.uid}"
+ # puts "New file group: #{file_stat.gid}"
+ # end
+ # ```
+ #
+ # Output:
+ #
+ # ```text
+ # Original directory owner: 0
+ # Original directory group: 0
+ # New directory owner: 1000
+ # New directory group: 1000
+ # Original file owner: 0
+ # Original file group: 0
+ # New file owner: 1000
+ # New file group: 1000
+ # ```
+ #
+ # Notes:
+ #
+ # - On Windows, the owner and group are not changed.
+ # - Only a process with superuser privileges can change the owner of an entry.
+ # - The owner of an entry can change its group to any group
+ # to which the owner belongs.
+ # - A +nil+ or +-1+ owner or group id is ignored.
+ # - The method follows symbolic links to the target entry.
+ #
+ def chown(owner, group) File.chown(owner, group, @path) end
+
+ # See <tt>File.lchown</tt>.
+ def lchown(owner, group) File.lchown(owner, group, @path) end
+
+ # See <tt>File.fnmatch</tt>. Return +true+ if the receiver matches the given
+ # pattern.
+ def fnmatch(pattern, ...) File.fnmatch(pattern, @path, ...) end
+
+ # See <tt>File.fnmatch?</tt> (same as #fnmatch).
+ def fnmatch?(pattern, ...) File.fnmatch?(pattern, @path, ...) end
+
+ # See <tt>File.ftype</tt>. Returns "type" of file ("file", "directory",
+ # etc).
+ def ftype() File.ftype(@path) end
+
+ # See <tt>File.link</tt>. Creates a hard link.
+ def make_link(old) File.link(old, @path) end
+
+ # See <tt>File.open</tt>. Opens the file for reading or writing.
+ def open(...) # :yield: file
+ File.open(@path, ...)
+ end
+
+ # See <tt>File.readlink</tt>. Read symbolic link.
+ def readlink() self.class.new(File.readlink(@path)) end
+
+ # See <tt>File.rename</tt>. Rename the file.
+ def rename(to) File.rename(@path, to) end
+
+ # See <tt>File.stat</tt>. Returns a <tt>File::Stat</tt> object.
+ def stat() File.stat(@path) end
+
+ # See <tt>File.lstat</tt>.
+ def lstat() File.lstat(@path) end
+
+ # See <tt>File.symlink</tt>. Creates a symbolic link.
+ def make_symlink(old) File.symlink(old, @path) end
+
+ # See <tt>File.truncate</tt>. Truncate the file to +length+ bytes.
+ def truncate(length) File.truncate(@path, length) end
+
+ # See <tt>File.utime</tt>. Update the access and modification times.
+ def utime(atime, mtime) File.utime(atime, mtime, @path) end
+
+ # Update the access and modification times of the file.
+ #
+ # Same as Pathname#utime, but does not follow symbolic links.
+ #
+ # See File.lutime.
+ def lutime(atime, mtime) File.lutime(atime, mtime, @path) end
+
+ # call-seq:
+ # basename(path, suffix = '') -> new_pathname
+ #
+ # Returns a new \Pathname object containing all or part of the last entry
+ # of the path represented by +self+.
+ # Entries are delimited by the value of constant File::SEPARATOR
+ # and, if non-nil, the value of constant File::ALT_SEPARATOR.
+ #
+ # When +suffix+ is the empty string <tt>''</tt>, returns all of the last entry:
+ #
+ # Pathname.new('foo/bar/baz/bat.txt').basename # => #<Pathname:bat.txt>
+ # Pathname.new('foo/bar/baz').basename # => #<Pathname:baz>
+ #
+ # File::SEPARATOR # => "/"
+ # Pathname.new('foo/bar.txt////').basename # => #<Pathname:bar.txt>
+ # File::ALT_SEPARATOR # => "\\" # On Windows.
+ # Pathname.new('foo/bar.txt//\\\\//').basename # => #<Pathname:bar.txt>
+ #
+ # When +suffix+ is <tt>'.*'</tt>,
+ # the last {filename extension}[https://en.wikipedia.org/wiki/Filename_extension],
+ # if any, is removed:
+ #
+ # Pathname.new('foo/bar.txt').basename('.*') # => #<Pathname:bar>
+ # Pathname.new('foo/bar.txt.old').basename('.*') # => #<Pathname:bar.txt>
+ # Pathname.new('foo/bar').basename('.*') # => #<Pathname:bar>
+ #
+ # When +suffix+ is any string other than <tt>''</tt> or <tt>'.*'</tt>,
+ # the matching trailing substring, if any, is removed:
+ #
+ # Pathname.new('foo/bar.txt').basename('.txt') # => #<Pathname:bar>
+ # Pathname.new('foo/bar.txt').basename('txt') # => #<Pathname:bar.>
+ # Pathname.new('foo/bar.txt').basename('*') # => #<Pathname:bar.txt>
+ # Pathname.new('foo/bar.txt').basename('.') # => #<Pathname:bar.txt>
+ #
+ def basename(...) self.class.new(File.basename(@path, ...)) end
+
+ # See <tt>File.dirname</tt>. Returns all but the last component of the path.
+ def dirname() self.class.new(File.dirname(@path)) end
+
+ # :markup: markdown
+ #
+ # call-seq:
+ # extname -> extension
+ #
+ # Returns the filename extension of `self` --
+ # usually the portion of the string path beginning from the last period:
+ #
+ # ```ruby
+ # Pathname('t.rb').extname # => ".rb"
+ # Pathname('foo.bar.t.rb').extname # => ".rb"
+ # Pathname('foo/bar/t.rb').extname # => ".rb"
+ # Pathname('nosuch.txt').extname # => ".txt" # Path need not exist.
+ # ```
+ #
+ # Returns the entire string when there is no period:
+ #
+ # ```ruby
+ # Pathname('foo').extname # => ""
+ # ```
+ #
+ # Returns an empty string when the only period is the first character:
+ #
+ # ```ruby
+ # Pathname('.irbrc').extname # => ""
+ # ```
+ #
+ # Returns an empty string or `'.'` when `path` ends with a period:
+ #
+ # ```ruby
+ # Pathname('foo.').extname # => "" # On Windows.
+ # Pathname('foo.').extname # => "." # Elsewhere.
+ # Pathname('foo....').extname # => "" # On Windows.
+ # Pathname('foo....').extname # => "." # Elsewhere.
+ # ```
+ #
+ def extname() File.extname(@path) end
+
+ # :markup: markdown
+ #
+ # call-seq:
+ # expand_path(dirpath = '.') -> new_pathname
+ #
+ # Returns a new pathname containing the absolute path for `self`.
+ #
+ # Evaluates a relative path with respect to the directory given by `dirpath`:
+ #
+ # ```ruby
+ # Dir.chdir('/snap')
+ # # Default dirpath.
+ # Pathname('README').expand_path # => #<Pathname:/snap/README>
+ # Pathname('bin').expand_path # => #<Pathname:/snap/bin>
+ # Pathname('bin/../var').expand_path # => #<Pathname:/snap/var> # Cleaned.
+ # # Other dirpath.
+ # Pathname('../zip').expand_path('/usr/bin/ruby') # => #<Pathname:/usr/bin/zip>
+ # Dir.chdir('/usr/bin')
+ # Pathname('../../snap').expand_path(__FILE__) # => #<Pathname:/usr/snap>
+ # ```
+ #
+ # Evaluates an absolute path without respect to `dirpath`:
+ #
+ # ```ruby
+ # Pathname('/snap').expand_path # => #<Pathname:/snap>
+ # Pathname('/snap').expand_path.expand_path('nosuch') # => #<Pathname:/snap>
+ # Pathname('/snap/../snap').expand_path # => #<Pathname:/snap> # Cleaned.
+ # ```
+ #
+ # More examples:
+ #
+ # ```
+ # Dir.chdir('/usr/bin')
+ # Pathname('../../snap').expand_path(__FILE__) # => #<Pathname:/usr/snap>
+ # Pathname('../../snap').expand_path # => #<Pathname:/snap>
+ # ```
+ #
+ def expand_path(...) self.class.new(File.expand_path(@path, ...)) end
+
+ # See <tt>File.split</tt>. Returns the #dirname and the #basename in an
+ # Array.
+ def split()
+ array = File.split(@path)
+ raise TypeError, 'wrong argument type nil (expected Array)' unless Array === array
+ array.map {|f| self.class.new(f) }
+ end
+
+ # Returns the real (absolute) pathname for +self+ in the actual filesystem.
+ #
+ # Does not contain symlinks or useless dots, +..+ and +.+.
+ #
+ # All components of the pathname must exist when this method is called.
+ def realpath(...) self.class.new(File.realpath(@path, ...)) end
+
+ # Returns the real (absolute) pathname of +self+ in the actual filesystem.
+ #
+ # Does not contain symlinks or useless dots, +..+ and +.+.
+ #
+ # The last component of the real pathname can be nonexistent.
+ def realdirpath(...) self.class.new(File.realdirpath(@path, ...)) end
+end
+
+
+class Pathname # * FileTest *
+
+ # :markup: markdown
+ #
+ # call-seq:
+ # blockdev? => true or false
+ #
+ # Returns whether `self` represents a path to a block device
+ # (i.e., a direct-access device):
+ #
+ # ```ruby
+ # Pathname('/dev/nvme0n1').blockdev? # => true
+ # Pathname('/dev/loop0').blockdev? # => true
+ # Pathname('/dev/tty').blockdev? # => false
+ # Pathname('/dev/null').blockdev? # => false
+ # Pathname('nosuch').blockdev? # => false
+ # Pathname($stdin).blockdev? # => false
+ # ```
+ #
+ # The returned value is OS-dependent; on Windows, almost always `false`.
+ def blockdev?() FileTest.blockdev?(@path) end
+
+ # :markup: markdown
+ #
+ # call-seq:
+ # chardev? => true or false
+ #
+ # Returns whether `self` represents a path to a character device
+ # (i.e., a sequential-access device):
+ #
+ # ```ruby
+ # Pathname('/dev/tty').chardev? # => true
+ # Pathname('/dev/null').chardev? # => true
+ # Pathname('/dev/nvme0n1').chardev? # => false
+ # Pathname('/dev/loop0').chardev? # => false
+ # Pathname($stdin).chardev? # => false
+ # Pathname('nosuch').chardev? # => false
+ # ```
+ #
+ # The returned value is OS-dependent; on Windows, almost always `false`.
+ def chardev?() FileTest.chardev?(@path) end
+
+ # :markup: markdown
+ #
+ # call-seq:
+ # empty? -> true or false
+ #
+ # Returns whether the entry represented by `self` exists and is empty:
+ #
+ # ```ruby
+ # dir_pn = Pathname('example_dir')
+ # dir_pn.empty? # => false # Dir does not exist.
+ # dir_pn.mkdir
+ # dir_pn.empty? # => true # Dir exists and is empty.
+ #
+ # file_pn = Pathname('example_dir/example.txt')
+ # file_pn.empty? # => false # File does not exist.
+ # file_pn.write('')
+ # file_pn.empty? # => true # File exists and is empty.
+ # dir_pn.empty? # => false # Dir exists and is not empty.
+ # file_pn.write('foo')
+ # file_pn.empty? # => false # File exists and is not empty.
+ #
+ # file_pn.delete
+ # dir_pn.delete
+ # ```
+ #
+ def empty?
+ if FileTest.directory?(@path)
+ Dir.empty?(@path)
+ else
+ File.empty?(@path)
+ end
+ end
+
+ # :markup: markdown
+ #
+ # call-seq:
+ # executable? -> true or false
+ #
+ # Returns whether the entry represented by `self` is executable;
+ # calls FileTest.executable? with argument `self.to_s`:
+ #
+ # ```ruby
+ # Pathname('bin/gem').executable? # => true
+ # Pathname('README.md').executable? # => false
+ # ```
+ #
+ def executable?() FileTest.executable?(@path) end
+
+ # :markup: markdown
+ #
+ # call-seq:
+ # executable_real? -> true or false
+ #
+ # Returns whether the entry represented by `self` is executable
+ # by the real user and group id of the current process;
+ # calls FileTest.executable_real? with argument `self.to_s`:
+ #
+ # ```ruby
+ # pn = Pathname('example')
+ # pn.write('')
+ # pn.executable_real? # => false
+ # pn.chmod(0100)
+ # pn.executable_real? # => true
+ # ```
+ #
+ def executable_real?() FileTest.executable_real?(@path) end
+
+ # :markup: markdown
+ #
+ # call-seq:
+ # exist? -> true or false
+ #
+ # Returns whether the entry represented by `self` exists:
+ #
+ # ```ruby
+ # Pathname('.').exist? # => true
+ # Pathname('README.md').exist? # => true
+ # Pathname('nosuch').exist? # => false
+ # ```
+ #
+ def exist?() FileTest.exist?(@path) end
+
+ # See <tt>FileTest.grpowned?</tt>.
+ def grpowned?() FileTest.grpowned?(@path) end
+
+ # :markup: markdown
+ #
+ # call-seq:
+ # directory? -> true or false
+ #
+ # Returns whether the entry represented by `self` is a directory:
+ #
+ # ```ruby
+ # Pathname('/etc').directory? # => true
+ # Pathname('lib').directory? # => true
+ # Pathname('README.md').directory? # => false
+ # Pathname('nosuch').directory? # => false
+ # ```
+ #
+ def directory?() FileTest.directory?(@path) end
+
+ # See <tt>FileTest.file?</tt>.
+ def file?() FileTest.file?(@path) end
+
+ # See <tt>FileTest.pipe?</tt>.
+ def pipe?() FileTest.pipe?(@path) end
+
+ # See <tt>FileTest.socket?</tt>.
+ def socket?() FileTest.socket?(@path) end
+
+ # See <tt>FileTest.owned?</tt>.
+ def owned?() FileTest.owned?(@path) end
+
+ # See <tt>FileTest.readable?</tt>.
+ def readable?() FileTest.readable?(@path) end
+
+ # See <tt>FileTest.world_readable?</tt>.
+ def world_readable?() File.world_readable?(@path) end
+
+ # See <tt>FileTest.readable_real?</tt>.
+ def readable_real?() FileTest.readable_real?(@path) end
+
+ # See <tt>FileTest.setuid?</tt>.
+ def setuid?() FileTest.setuid?(@path) end
+
+ # See <tt>FileTest.setgid?</tt>.
+ def setgid?() FileTest.setgid?(@path) end
+
+ # See <tt>FileTest.size</tt>.
+ def size() FileTest.size(@path) end
+
+ # See <tt>FileTest.size?</tt>.
+ def size?() FileTest.size?(@path) end
+
+ # See <tt>FileTest.sticky?</tt>.
+ def sticky?() FileTest.sticky?(@path) end
+
+ # See <tt>FileTest.symlink?</tt>.
+ def symlink?() FileTest.symlink?(@path) end
+
+ # See <tt>FileTest.writable?</tt>.
+ def writable?() FileTest.writable?(@path) end
+
+ # See <tt>FileTest.world_writable?</tt>.
+ def world_writable?() File.world_writable?(@path) end
+
+ # See <tt>FileTest.writable_real?</tt>.
+ def writable_real?() FileTest.writable_real?(@path) end
+
+ # See <tt>FileTest.zero?</tt>.
+ def zero?() FileTest.zero?(@path) end
+end
+
+
+class Pathname # * Dir *
+ # call-seq:
+ # glob(patterns, **kwargs) → array_of_pathnames
+ # glob(patterns, **kwargs) {|pathname| ... } → nil
+ #
+ # Calls <tt>Dir.glob(patterns, **kwargs)</tt>, which yields or returns entry names;
+ # see Dir.glob.
+ #
+ # Required argument +patterns+ is a string pattern or an array of string patterns;
+ # note that these patterns are not regexps.
+ #
+ # Keyword arguments <tt>**kwargs</tt> are passed through to Dir.glob;
+ # see the documentation there.
+ #
+ # With no block given, returns an array of \Pathname objects;
+ # each is <tt>Pathname.new(entry_name)</tt> for an entry name returned by Dir.glob.
+ #
+ # Pathname.glob('*').take(3)
+ # # => [#<Pathname:BSDL>, #<Pathname:CONTRIBUTING.md>, #<Pathname:COPYING>]
+ # Pathname.glob(['o*', 'a*']).take(3)
+ # # => [#<Pathname:object.c>, #<Pathname:aclocal.m4>, #<Pathname:addr2line.c>]
+ #
+ # With a block given, calls the block with each pathname
+ # <tt>Pathname.new(entry_name)</tt>,
+ # where each +entry_name+ is a \Pathname object created by the value yielded by Dir.glob.
+ #
+ # a = []
+ # Pathname.glob(['o*', 'a*']) {|pathname| a << pathname }
+ # a.take(3)
+ # # => [#<Pathname:object.c>, #<Pathname:aclocal.m4>, #<Pathname:addr2line.c>]
+ #
+ # Optional keyword argument +base+ is of particular interest.
+ # When it is given, its value specifies the base directory for the pathnames;
+ # each pattern string specifies entries relative to the base directory:
+ #
+ # Pathname.glob('*', base: 'lib').take(2)
+ # # => [#<Pathname:English.gemspec>, #<Pathname:English.rb>]
+ # Pathname.glob('*', base: 'lib/bundler').take(2)
+ # # => [#<Pathname:build_metadata.rb>, #<Pathname:bundler.gemspec>]
+ #
+ # Note that the base directory is not prepended to the entry names in the result.
+ def Pathname.glob(*args, **kwargs) # :yield: pathname
+ if block_given?
+ Dir.glob(*args, **kwargs) {|f| yield self.new(f) }
+ else
+ Dir.glob(*args, **kwargs).map {|f| self.new(f) }
+ end
+ end
+
+ # Returns or yields Pathname objects.
+ #
+ # Pathname("ruby-2.4.2").glob("R*.md")
+ # #=> [#<Pathname:ruby-2.4.2/README.md>, #<Pathname:ruby-2.4.2/README.ja.md>]
+ #
+ # See Dir.glob.
+ # This method uses the +base+ keyword argument of Dir.glob.
+ def glob(*args, **kwargs) # :yield: pathname
+ if block_given?
+ Dir.glob(*args, **kwargs, base: @path) {|f| yield self + f }
+ else
+ Dir.glob(*args, **kwargs, base: @path).map {|f| self + f }
+ end
+ end
+
+ # call-seq:
+ # Pathname.getwd -> new_pathname
+ #
+ # Returns a new \Pathname object containing the path to the current working directory
+ # (equivalent to <tt>Pathname.new(Dir.getwd)</tt>):
+ #
+ # Pathname.getwd # => #<Pathname:/home>
+ #
+ def Pathname.getwd() self.new(Dir.getwd) end
+ class << self
+ alias pwd getwd
+ end
+
+ # :markup: markdown
+ #
+ # call-seq:
+ # entries -> array_of_pathnames
+ #
+ # Returns an array of pathnames,
+ # one for each entry in the directory represented by `self`:
+ #
+ # ```ruby
+ # Pathname('.').entries.take(5)
+ # # =>
+ # # [#<Pathname:.>,
+ # # #<Pathname:..>,
+ # # #<Pathname:gc.rb>,
+ # # #<Pathname:yjit.rb>,
+ # # #<Pathname:iseq.h>]
+ # ```
+ #
+ def entries() Dir.entries(@path).map {|f| self.class.new(f) } end
+
+ # :markup: markdown
+ #
+ # call-seq:
+ # each_entry {|entry| ... } -> nil
+ # each_entry -> new_enumerator
+ #
+ # With a block given,
+ # yields a new pathname for each entry
+ # in the entry represented by `self`;
+ # returns `nil`:
+ #
+ # ```ruby
+ # Pathname('include').each_entry {|entry| p entry }
+ # # #<Pathname:ruby>
+ # # #<Pathname:..>
+ # # #<Pathname:ruby.h>
+ # # #<Pathname:.>
+ # # => nil
+ # ```
+ #
+ # With no block given, returns a new Enumerator.
+ def each_entry(&block) # :yield: pathname
+ return to_enum(__method__) unless block_given?
+ Dir.foreach(@path) {|f| yield self.class.new(f) }
+ end
+
+ # See <tt>Dir.mkdir</tt>. Create the referenced directory.
+ def mkdir(...) Dir.mkdir(@path, ...) end
+
+ # See <tt>Dir.rmdir</tt>. Remove the referenced directory.
+ def rmdir() Dir.rmdir(@path) end
+
+ # See <tt>Dir.open</tt>.
+ def opendir(&block) # :yield: dir
+ Dir.open(@path, &block)
+ end
+end
+
+class Pathname # * mixed *
+ #
+ # :markup: markdown
+ #
+ # call-seq:
+ # unlink -> 1 or 0
+ #
+ # Removes the file or directory represented by `self`, using:
+ #
+ # - File.unlink, if `self` represents a file; returns `1`.
+ # - Dir.unlink, if `self` represents a directory; returns `0`.
+ #
+ # Examples:
+ #
+ # ```ruby
+ # Pathname(Tempfile.create).unlink # => 1
+ # Pathname(Pathname.mktmpdir).unlink # => 0
+ # ```
+ #
+ def unlink()
+ Dir.unlink @path
+ rescue Errno::ENOTDIR
+ File.unlink @path
+ end
+ alias delete unlink
+end
+
+class Pathname
+ undef =~ if Kernel.method_defined?(:=~)
+end
+
+module Kernel
+ # Creates a Pathname object.
+ def Pathname(path) # :doc:
+ return path if Pathname === path
+ Pathname.new(path)
+ end
+ module_function :Pathname
+end
diff --git a/prelude.rb b/prelude.rb
index 36da381804..b6c610dd58 100644
--- a/prelude.rb
+++ b/prelude.rb
@@ -1,6 +1,9 @@
class Binding
# :nodoc:
def irb(...)
+ suppress = Thread.current[:__bundled_gems_warning_suppression]
+ Thread.current[:__bundled_gems_warning_suppression] = ['reline', 'rdoc']
+
begin
require 'irb'
rescue LoadError, Gem::LoadError
@@ -8,6 +11,8 @@ class Binding
require 'irb'
end
irb(...)
+ ensure
+ Thread.current[:__bundled_gems_warning_suppression] = suppress
end
# suppress redefinition warning
@@ -30,14 +35,7 @@ end
module Enumerable
# Makes a set from the enumerable object with given arguments.
- # Passing arguments to this method is deprecated.
- def to_set(*args, &block)
- klass = if args.empty?
- Set
- else
- warn "passing arguments to Enumerable#to_set is deprecated", uplevel: 1
- args.shift
- end
- klass.new(self, *args, &block)
+ def to_set(&block)
+ Set.new(self, &block)
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/arena.c b/prism/arena.c
new file mode 100644
index 0000000000..64a731649d
--- /dev/null
+++ b/prism/arena.c
@@ -0,0 +1,117 @@
+#include "prism/internal/arena.h"
+
+#include "prism/internal/allocator.h"
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+/**
+ * Compute the block allocation size using offsetof so it is correct regardless
+ * of PM_FLEX_ARRAY_LENGTH.
+ */
+#define PM_ARENA_BLOCK_SIZE(data_size) (offsetof(pm_arena_block_t, data) + (data_size))
+
+/** Initial block data size: 8 KB. */
+#define PM_ARENA_INITIAL_SIZE 8192
+
+/** Double the block size every this many blocks. */
+#define PM_ARENA_GROWTH_INTERVAL 8
+
+/** Maximum block data size: 1 MB. */
+#define PM_ARENA_MAX_SIZE (1024 * 1024)
+
+/**
+ * Compute the data size for the next block.
+ */
+static size_t
+pm_arena_next_block_size(const pm_arena_t *arena, size_t min_size) {
+ size_t size = PM_ARENA_INITIAL_SIZE;
+
+ for (size_t exp = PM_ARENA_GROWTH_INTERVAL; exp <= arena->block_count; exp += PM_ARENA_GROWTH_INTERVAL) {
+ if (size < PM_ARENA_MAX_SIZE) size *= 2;
+ }
+
+ return size > min_size ? size : min_size;
+}
+
+/**
+ * Allocate a new block with the given data capacity and initial usage, link it
+ * into the arena, and return it. Aborts on allocation failure.
+ */
+static pm_arena_block_t *
+pm_arena_block_new(pm_arena_t *arena, size_t data_size, size_t initial_used) {
+ assert(initial_used <= data_size);
+ pm_arena_block_t *block = (pm_arena_block_t *) xmalloc(PM_ARENA_BLOCK_SIZE(data_size));
+
+ if (block == NULL) {
+ fprintf(stderr, "prism: out of memory; aborting\n");
+ abort();
+ }
+
+ block->capacity = data_size;
+ block->used = initial_used;
+ block->prev = arena->current;
+ arena->current = block;
+ arena->block_count++;
+
+ return block;
+}
+
+/**
+ * Ensure the arena has at least `capacity` bytes available in its current
+ * block, allocating a new block if necessary. This allows callers to
+ * pre-size the arena to avoid repeated small block allocations.
+ */
+void
+pm_arena_reserve(pm_arena_t *arena, size_t capacity) {
+ if (capacity <= PM_ARENA_INITIAL_SIZE) return;
+ if (arena->current != NULL && (arena->current->capacity - arena->current->used) >= capacity) return;
+ pm_arena_block_new(arena, capacity, 0);
+}
+
+/**
+ * Slow path for pm_arena_alloc: allocate a new block and return a pointer to
+ * the first `size` bytes. Called when the current block has insufficient space.
+ */
+void *
+pm_arena_alloc_slow(pm_arena_t *arena, size_t size) {
+ size_t block_data_size = pm_arena_next_block_size(arena, size);
+ pm_arena_block_t *block = pm_arena_block_new(arena, block_data_size, size);
+ return block->data;
+}
+
+/**
+ * Returns a newly allocated and initialized arena.
+ */
+pm_arena_t *
+pm_arena_new(void) {
+ pm_arena_t *arena = (pm_arena_t *) xcalloc(1, sizeof(pm_arena_t));
+ if (arena == NULL) abort();
+ return arena;
+}
+
+/**
+ * Free all blocks in the arena.
+ */
+void
+pm_arena_cleanup(pm_arena_t *arena) {
+ pm_arena_block_t *block = arena->current;
+
+ while (block != NULL) {
+ pm_arena_block_t *prev = block->prev;
+ xfree_sized(block, PM_ARENA_BLOCK_SIZE(block->capacity));
+ block = prev;
+ }
+
+ *arena = (pm_arena_t) { 0 };
+}
+
+/**
+ * Frees both the held memory and the arena itself.
+ */
+void
+pm_arena_free(pm_arena_t *arena) {
+ pm_arena_cleanup(arena);
+ xfree_sized(arena, sizeof(pm_arena_t));
+}
diff --git a/prism/arena.h b/prism/arena.h
new file mode 100644
index 0000000000..e1fa8fc6ad
--- /dev/null
+++ b/prism/arena.h
@@ -0,0 +1,37 @@
+/**
+ * @file arena.h
+ *
+ * A bump allocator for the prism parser.
+ */
+#ifndef PRISM_ARENA_H
+#define PRISM_ARENA_H
+
+#include "prism/compiler/exported.h"
+#include "prism/compiler/nodiscard.h"
+#include "prism/compiler/nonnull.h"
+
+#include <stddef.h>
+
+/**
+ * An opaque pointer to an arena that is used for allocations.
+ */
+typedef struct pm_arena_t pm_arena_t;
+
+/**
+ * Returns a newly allocated and initialized arena. If the arena cannot be
+ * allocated, this function aborts the process.
+ *
+ * @returns A pointer to the newly allocated arena. It is the responsibility of
+ * the caller to free the arena using pm_arena_free when it is no longer
+ * needed.
+ */
+PRISM_EXPORTED_FUNCTION PRISM_NODISCARD pm_arena_t * pm_arena_new(void);
+
+/**
+ * Frees both the held memory and the arena itself.
+ *
+ * @param arena The arena to free.
+ */
+PRISM_EXPORTED_FUNCTION void pm_arena_free(pm_arena_t *arena) PRISM_NONNULL(1);
+
+#endif
diff --git a/prism/buffer.c b/prism/buffer.c
new file mode 100644
index 0000000000..cb3b9a4fe8
--- /dev/null
+++ b/prism/buffer.c
@@ -0,0 +1,374 @@
+#include "prism/internal/buffer.h"
+
+#include "prism/compiler/inline.h"
+
+#include "prism/internal/char.h"
+#include "prism/internal/allocator.h"
+
+#include <assert.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/**
+ * Initialize a pm_buffer_t with the given capacity.
+ */
+void
+pm_buffer_init(pm_buffer_t *buffer, size_t capacity) {
+ buffer->length = 0;
+ buffer->capacity = capacity;
+
+ buffer->value = (char *) xmalloc(capacity);
+ if (buffer->value == NULL) abort();
+}
+
+/**
+ * Allocate and initialize a new buffer.
+ */
+pm_buffer_t *
+pm_buffer_new(void) {
+ pm_buffer_t *buffer = (pm_buffer_t *) xmalloc(sizeof(pm_buffer_t));
+ if (buffer == NULL) abort();
+
+ pm_buffer_init(buffer, 1024);
+ return buffer;
+}
+
+/**
+ * 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 PRISM_INLINE bool
+pm_buffer_append_length(pm_buffer_t *buffer, size_t length) {
+ size_t next_length = buffer->length + length;
+ const size_t original_capacity = buffer->capacity;
+
+ if (next_length > buffer->capacity) {
+ if (buffer->capacity == 0) {
+ buffer->capacity = 1;
+ }
+
+ while (next_length > buffer->capacity) {
+ buffer->capacity *= 2;
+ }
+
+ buffer->value = xrealloc_sized(buffer->value, buffer->capacity, original_capacity);
+ if (buffer->value == NULL) return false;
+ }
+
+ buffer->length = next_length;
+ return true;
+}
+
+/**
+ * Append a generic pointer to memory to the buffer.
+ */
+static PRISM_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 unicode codepoint to the buffer.
+ */
+bool
+pm_buffer_append_unicode_codepoint(pm_buffer_t *buffer, uint32_t value) {
+ if (value <= 0x7F) {
+ pm_buffer_append_byte(buffer, (uint8_t) value); // 0xxxxxxx
+ return true;
+ } else if (value <= 0x7FF) {
+ uint8_t bytes[] = {
+ (uint8_t) (0xC0 | ((value >> 6) & 0x3F)), // 110xxxxx
+ (uint8_t) (0x80 | (value & 0x3F)) // 10xxxxxx
+ };
+
+ pm_buffer_append_bytes(buffer, bytes, 2);
+ return true;
+ } else if (value <= 0xFFFF) {
+ uint8_t bytes[] = {
+ (uint8_t) (0xE0 | ((value >> 12) & 0x3F)), // 1110xxxx
+ (uint8_t) (0x80 | ((value >> 6) & 0x3F)), // 10xxxxxx
+ (uint8_t) (0x80 | (value & 0x3F)) // 10xxxxxx
+ };
+
+ pm_buffer_append_bytes(buffer, bytes, 3);
+ return true;
+ } else if (value <= 0x10FFFF) {
+ uint8_t bytes[] = {
+ (uint8_t) (0xF0 | ((value >> 18) & 0x3F)), // 11110xxx
+ (uint8_t) (0x80 | ((value >> 12) & 0x3F)), // 10xxxxxx
+ (uint8_t) (0x80 | ((value >> 6) & 0x3F)), // 10xxxxxx
+ (uint8_t) (0x80 | (value & 0x3F)) // 10xxxxxx
+ };
+
+ pm_buffer_append_bytes(buffer, bytes, 4);
+ return true;
+ } else {
+ return false;
+ }
+}
+
+/**
+ * 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 held by the buffer.
+ */
+void
+pm_buffer_cleanup(pm_buffer_t *buffer) {
+ xfree_sized(buffer->value, buffer->capacity);
+}
+
+/**
+ * Free both the memory held by the buffer and the buffer itself.
+ */
+void
+pm_buffer_free(pm_buffer_t *buffer) {
+ pm_buffer_cleanup(buffer);
+ xfree_sized(buffer, sizeof(pm_buffer_t));
+}
diff --git a/prism/buffer.h b/prism/buffer.h
new file mode 100644
index 0000000000..24b572d2c3
--- /dev/null
+++ b/prism/buffer.h
@@ -0,0 +1,52 @@
+/**
+ * @file buffer.h
+ *
+ * A wrapper around a contiguous block of allocated memory.
+ */
+#ifndef PRISM_BUFFER_H
+#define PRISM_BUFFER_H
+
+#include "prism/compiler/exported.h"
+#include "prism/compiler/nodiscard.h"
+#include "prism/compiler/nonnull.h"
+
+#include <stddef.h>
+
+/**
+ * A wrapper around a contiguous block of allocated memory.
+ */
+typedef struct pm_buffer_t pm_buffer_t;
+
+/**
+ * Allocate and initialize a new buffer. If the buffer cannot be allocated, this
+ * function will abort the process.
+ *
+ * @returns A pointer to the initialized buffer. The caller is responsible for
+ * freeing the buffer with pm_buffer_free.
+ */
+PRISM_EXPORTED_FUNCTION PRISM_NODISCARD pm_buffer_t * pm_buffer_new(void);
+
+/**
+ * Free both the memory held by the buffer and the buffer itself.
+ *
+ * @param buffer The buffer to free.
+ */
+PRISM_EXPORTED_FUNCTION void pm_buffer_free(pm_buffer_t *buffer) PRISM_NONNULL(1);
+
+/**
+ * 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) PRISM_NONNULL(1);
+
+/**
+ * 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) PRISM_NONNULL(1);
+
+#endif
diff --git a/prism/char.c b/prism/char.c
new file mode 100644
index 0000000000..08e457aa1f
--- /dev/null
+++ b/prism/char.c
@@ -0,0 +1,274 @@
+#include "prism/internal/char.h"
+
+#include "prism/compiler/inline.h"
+#include "prism/internal/line_offset_list.h"
+
+#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)
+
+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 PRISM_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_arena_t *arena, pm_line_offset_list_t *line_offsets, uint32_t start_offset) {
+ if (length <= 0) return 0;
+
+ uint32_t size = 0;
+ uint32_t maximum = (uint32_t) length;
+
+ while (size < maximum && (pm_byte_table[string[size]] & PRISM_CHAR_BIT_WHITESPACE)) {
+ if (string[size] == '\n') {
+ pm_line_offset_list_append(arena, line_offsets, start_offset + size + 1);
+ }
+
+ size++;
+ }
+
+ return size;
+}
+
+/**
+ * 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);
+}
+
+
+/**
+ * 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 PRISM_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 PRISM_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 (size > 0 && 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 PRISM_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);
+}
diff --git a/prism/comments.h b/prism/comments.h
new file mode 100644
index 0000000000..2270d53889
--- /dev/null
+++ b/prism/comments.h
@@ -0,0 +1,43 @@
+/**
+ * @file comments.h
+ *
+ * Types and functions related to comments found during parsing.
+ */
+#ifndef PRISM_COMMENTS_H
+#define PRISM_COMMENTS_H
+
+#include "prism/compiler/exported.h"
+#include "prism/compiler/nodiscard.h"
+#include "prism/compiler/nonnull.h"
+
+#include "prism/ast.h"
+
+#include <stddef.h>
+
+/** 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;
+
+/** An opaque pointer to a comment found while parsing. */
+typedef struct pm_comment_t pm_comment_t;
+
+/**
+ * Returns the location associated with the given comment.
+ *
+ * @param comment the comment whose location we want to get
+ * @returns the location associated with the given comment
+ */
+PRISM_EXPORTED_FUNCTION pm_location_t pm_comment_location(const pm_comment_t *comment) PRISM_NONNULL(1);
+
+/**
+ * Returns the type associated with the given comment.
+ *
+ * @param comment the comment whose type we want to get
+ * @returns the type associated with the given comment. This can either be
+ * PM_COMMENT_INLINE or PM_COMMENT_EMBDOC.
+ */
+PRISM_EXPORTED_FUNCTION pm_comment_type_t pm_comment_type(const pm_comment_t *comment) PRISM_NONNULL(1);
+
+#endif
diff --git a/prism/compiler/accel.h b/prism/compiler/accel.h
new file mode 100644
index 0000000000..be23236d1d
--- /dev/null
+++ b/prism/compiler/accel.h
@@ -0,0 +1,19 @@
+/**
+ * @file compiler/accel.h
+ */
+#ifndef PRISM_COMPILER_ACCEL_H
+#define PRISM_COMPILER_ACCEL_H
+
+/**
+ * Platform detection for SIMD/fast-path implementations. At most one of these
+ * macros is defined, selecting the best available vectorization strategy.
+ */
+#if (defined(__aarch64__) && defined(__ARM_NEON)) || (defined(_MSC_VER) && defined(_M_ARM64))
+# define PRISM_HAS_NEON
+#elif (defined(__x86_64__) && defined(__SSSE3__)) || (defined(_MSC_VER) && defined(_M_X64))
+# define PRISM_HAS_SSSE3
+#elif defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+# define PRISM_HAS_SWAR
+#endif
+
+#endif
diff --git a/prism/compiler/align.h b/prism/compiler/align.h
new file mode 100644
index 0000000000..22cb49a48c
--- /dev/null
+++ b/prism/compiler/align.h
@@ -0,0 +1,36 @@
+/**
+ * @file compiler/align.h
+ */
+#ifndef PRISM_COMPILER_ALIGN_H
+#define PRISM_COMPILER_ALIGN_H
+
+/**
+ * Compiler-agnostic macros for specifying alignment of types and variables.
+ */
+#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L /* C11 or later */
+ /** Specify alignment for a type or variable. */
+ #define PRISM_ALIGNAS _Alignas
+
+ /** Get the alignment requirement of a type. */
+ #define PRISM_ALIGNOF _Alignof
+#elif defined(__GNUC__) || defined(__clang__)
+ /** Specify alignment for a type or variable. */
+ #define PRISM_ALIGNAS(size) __attribute__((aligned(size)))
+
+ /** Get the alignment requirement of a type. */
+ #define PRISM_ALIGNOF(type) __alignof__(type)
+#elif defined(_MSC_VER)
+ /** Specify alignment for a type or variable. */
+ #define PRISM_ALIGNAS(size) __declspec(align(size))
+
+ /** Get the alignment requirement of a type. */
+ #define PRISM_ALIGNOF(type) __alignof(type)
+#else
+ /** Void because this platform does not support specifying alignment. */
+ #define PRISM_ALIGNAS(size)
+
+ /** Fallback to sizeof as alignment requirement of a type. */
+ #define PRISM_ALIGNOF(type) sizeof(type)
+#endif
+
+#endif
diff --git a/prism/compiler/exported.h b/prism/compiler/exported.h
new file mode 100644
index 0000000000..823773ecbb
--- /dev/null
+++ b/prism/compiler/exported.h
@@ -0,0 +1,24 @@
+/**
+ * @file compiler/exported.h
+ */
+#ifndef PRISM_COMPILER_EXPORTED_H
+#define PRISM_COMPILER_EXPORTED_H
+
+/**
+ * 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
+
+#endif
diff --git a/prism/compiler/fallthrough.h b/prism/compiler/fallthrough.h
new file mode 100644
index 0000000000..ce1b450e8a
--- /dev/null
+++ b/prism/compiler/fallthrough.h
@@ -0,0 +1,22 @@
+/**
+ * @file compiler/fallthrough.h
+ */
+#ifndef PRISM_COMPILER_FALLTHROUGH_H
+#define PRISM_COMPILER_FALLTHROUGH_H
+
+/**
+ * We use -Wimplicit-fallthrough to guard potentially unintended fall-through
+ * between cases of a switch. Use PRISM_FALLTHROUGH to explicitly annotate cases
+ * where the fallthrough is intentional.
+ */
+#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202311L /* C23 or later */
+ #define PRISM_FALLTHROUGH [[fallthrough]];
+#elif defined(__GNUC__) || defined(__clang__)
+ #define PRISM_FALLTHROUGH __attribute__((fallthrough));
+#elif defined(_MSC_VER)
+ #define PRISM_FALLTHROUGH __fallthrough;
+#else
+ #define PRISM_FALLTHROUGH
+#endif
+
+#endif
diff --git a/prism/compiler/filesystem.h b/prism/compiler/filesystem.h
new file mode 100644
index 0000000000..f988909db8
--- /dev/null
+++ b/prism/compiler/filesystem.h
@@ -0,0 +1,32 @@
+/**
+ * @file compiler/filesystem.h
+ *
+ * Platform detection for mmap and filesystem support.
+ */
+#ifndef PRISM_COMPILER_FILESYSTEM_H
+#define PRISM_COMPILER_FILESYSTEM_H
+
+/**
+ * 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
+
+#endif
diff --git a/prism/compiler/flex_array.h b/prism/compiler/flex_array.h
new file mode 100644
index 0000000000..7504b5fdd3
--- /dev/null
+++ b/prism/compiler/flex_array.h
@@ -0,0 +1,19 @@
+/**
+ * @file compiler/flex_array.h
+ */
+#ifndef PRISM_COMPILER_FLEX_ARRAY_H
+#define PRISM_COMPILER_FLEX_ARRAY_H
+
+/**
+ * A macro for helper define a flexible array member. C99 supports `data[]`, GCC
+ * supports `data[0]` as an extension, and older compilers require `data[1]`.
+ */
+#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
+ #define PM_FLEX_ARRAY_LENGTH /* data[] */
+#elif defined(__GNUC__) && !defined(__STRICT_ANSI__)
+ #define PM_FLEX_ARRAY_LENGTH 0 /* data[0] */
+#else
+ #define PM_FLEX_ARRAY_LENGTH 1 /* data[1] */
+#endif
+
+#endif
diff --git a/prism/compiler/force_inline.h b/prism/compiler/force_inline.h
new file mode 100644
index 0000000000..e189d592d6
--- /dev/null
+++ b/prism/compiler/force_inline.h
@@ -0,0 +1,21 @@
+/**
+ * @file compiler/force_inline.h
+ */
+#ifndef PRISM_COMPILER_FORCE_INLINE_H
+#define PRISM_COMPILER_FORCE_INLINE_H
+
+#include "prism/compiler/inline.h"
+
+/**
+ * Force a function to be inlined at every call site. Use sparingly — only for
+ * small, hot functions where the compiler's heuristics fail to inline.
+ */
+#if defined(_MSC_VER)
+# define PRISM_FORCE_INLINE __forceinline
+#elif defined(__GNUC__) || defined(__clang__)
+# define PRISM_FORCE_INLINE PRISM_INLINE __attribute__((always_inline))
+#else
+# define PRISM_FORCE_INLINE PRISM_INLINE
+#endif
+
+#endif
diff --git a/prism/compiler/format.h b/prism/compiler/format.h
new file mode 100644
index 0000000000..32f4c3c6d7
--- /dev/null
+++ b/prism/compiler/format.h
@@ -0,0 +1,25 @@
+/**
+ * @file compiler/format.h
+ */
+#ifndef PRISM_COMPILER_FORMAT_H
+#define PRISM_COMPILER_FORMAT_H
+
+/**
+ * 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(fmt_idx_, arg_idx_) __attribute__((format(__MINGW_PRINTF_FORMAT, fmt_idx_, arg_idx_)))
+# else
+# define PRISM_ATTRIBUTE_FORMAT(fmt_idx_, arg_idx_) __attribute__((format(printf, fmt_idx_, arg_idx_)))
+# endif
+#elif defined(__clang__)
+# define PRISM_ATTRIBUTE_FORMAT(fmt_idx_, arg_idx_) __attribute__((__format__(__printf__, fmt_idx_, arg_idx_)))
+#else
+# define PRISM_ATTRIBUTE_FORMAT(fmt_idx_, arg_idx_)
+#endif
+
+#endif
diff --git a/prism/compiler/inline.h b/prism/compiler/inline.h
new file mode 100644
index 0000000000..856a375691
--- /dev/null
+++ b/prism/compiler/inline.h
@@ -0,0 +1,17 @@
+/**
+ * @file compiler/inline.h
+ */
+#ifndef PRISM_COMPILER_INLINE_H
+#define PRISM_COMPILER_INLINE_H
+
+/**
+ * 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 PRISM_INLINE __inline
+#else
+# define PRISM_INLINE inline
+#endif
+
+#endif
diff --git a/prism/compiler/nodiscard.h b/prism/compiler/nodiscard.h
new file mode 100644
index 0000000000..ccd6c00719
--- /dev/null
+++ b/prism/compiler/nodiscard.h
@@ -0,0 +1,22 @@
+/**
+ * @file compiler/nodiscard.h
+ */
+#ifndef PRISM_COMPILER_NODISCARD_H
+#define PRISM_COMPILER_NODISCARD_H
+
+/**
+ * Mark the return value of a function as important so that the compiler warns
+ * if a caller ignores it. This is useful for functions that return error codes
+ * or allocated resources that must be freed.
+ */
+#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202311L
+# define PRISM_NODISCARD [[nodiscard]]
+#elif defined(__GNUC__) || defined(__clang__)
+# define PRISM_NODISCARD __attribute__((__warn_unused_result__))
+#elif defined(_MSC_VER)
+# define PRISM_NODISCARD _Check_return_
+#else
+# define PRISM_NODISCARD
+#endif
+
+#endif
diff --git a/prism/compiler/nonnull.h b/prism/compiler/nonnull.h
new file mode 100644
index 0000000000..9d19355665
--- /dev/null
+++ b/prism/compiler/nonnull.h
@@ -0,0 +1,18 @@
+/**
+ * @file compiler/nonnull.h
+ */
+#ifndef PRISM_COMPILER_NONNULL_H
+#define PRISM_COMPILER_NONNULL_H
+
+/**
+ * Mark the parameters of a function as non-null. This allows the compiler to
+ * warn if a caller passes NULL for a parameter that should never be NULL. The
+ * arguments are the 1-based indices of the parameters.
+ */
+#if defined(__GNUC__) || defined(__clang__)
+# define PRISM_NONNULL(...) __attribute__((__nonnull__(__VA_ARGS__)))
+#else
+# define PRISM_NONNULL(...)
+#endif
+
+#endif
diff --git a/prism/compiler/unused.h b/prism/compiler/unused.h
new file mode 100644
index 0000000000..6a9e125dde
--- /dev/null
+++ b/prism/compiler/unused.h
@@ -0,0 +1,18 @@
+/**
+ * @file compiler/unused.h
+ */
+#ifndef PRISM_COMPILER_UNUSED_H
+#define PRISM_COMPILER_UNUSED_H
+
+/**
+ * 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_UNUSED __attribute__((unused))
+#else
+# define PRISM_UNUSED
+#endif
+
+#endif
diff --git a/prism/config.yml b/prism/config.yml
index b37b98cbdf..bbbc5f3d33 100644
--- a/prism/config.yml
+++ b/prism/config.yml
@@ -17,6 +17,8 @@ errors:
- ARGUMENT_FORWARDING_UNBOUND
- ARGUMENT_NO_FORWARDING_AMPERSAND
- ARGUMENT_NO_FORWARDING_ELLIPSES
+ - ARGUMENT_NO_FORWARDING_ELLIPSES_LAMBDA
+ - ARGUMENT_NO_FORWARDING_ELLIPSES_BLOCK
- ARGUMENT_NO_FORWARDING_STAR
- ARGUMENT_NO_FORWARDING_STAR_STAR
- ARGUMENT_SPLAT_AFTER_ASSOC_SPLAT
@@ -60,7 +62,9 @@ errors:
- CONDITIONAL_WHILE_PREDICATE
- CONSTANT_PATH_COLON_COLON_CONSTANT
- DEF_ENDLESS
+ - DEF_ENDLESS_PARAMETERS
- DEF_ENDLESS_SETTER
+ - DEF_ENDLESS_DO_BLOCK
- DEF_NAME
- DEF_PARAMS_TERM
- DEF_PARAMS_TERM_PAREN
@@ -218,6 +222,7 @@ errors:
- PARAMETER_WILD_LOOSE_COMMA
- PATTERN_ARRAY_MULTIPLE_RESTS
- PATTERN_CAPTURE_DUPLICATE
+ - PATTERN_CAPTURE_IN_ALTERNATIVE
- PATTERN_EXPRESSION_AFTER_BRACKET
- PATTERN_EXPRESSION_AFTER_COMMA
- PATTERN_EXPRESSION_AFTER_HROCKET
@@ -243,7 +248,9 @@ errors:
- PATTERN_TERM_PAREN
- PIPEPIPEEQ_MULTI_ASSIGN
- REGEXP_ENCODING_OPTION_MISMATCH
+ - REGEXP_ESCAPED_NON_ASCII_IN_UTF8
- REGEXP_INCOMPAT_CHAR_ENCODING
+ - REGEXP_INVALID_CHAR_PROPERTY
- REGEXP_INVALID_UNICODE_RANGE
- REGEXP_NON_ESCAPED_MBC
- REGEXP_PARSE_ERROR
@@ -279,6 +286,7 @@ errors:
- UNEXPECTED_INDEX_KEYWORDS
- UNEXPECTED_LABEL
- UNEXPECTED_MULTI_WRITE
+ - UNEXPECTED_PARAMETER_DEFAULT_VALUE
- UNEXPECTED_RANGE_OPERATOR
- UNEXPECTED_SAFE_NAVIGATION
- UNEXPECTED_TOKEN_CLOSE_CONTEXT
@@ -355,6 +363,8 @@ tokens:
comment: "a newline character outside of other tokens"
- name: PARENTHESIS_RIGHT
comment: ")"
+ - name: PIPE
+ comment: "|"
- name: SEMICOLON
comment: ";"
# Tokens from here on are not used for lookup, and can be in any order.
@@ -486,6 +496,8 @@ tokens:
comment: "def"
- name: KEYWORD_DEFINED
comment: "defined?"
+ - name: KEYWORD_DO_BLOCK
+ comment: "do keyword for a block attached to a command"
- name: KEYWORD_DO_LOOP
comment: "do keyword for a predicate in a while, until, or for loop"
- name: KEYWORD_END_UPCASE
@@ -588,8 +600,6 @@ tokens:
comment: "%I"
- name: PERCENT_UPPER_W
comment: "%W"
- - name: PIPE
- comment: "|"
- name: PIPE_EQUAL
comment: "|="
- name: PIPE_PIPE
@@ -650,10 +660,6 @@ tokens:
comment: "a separator between words in a list"
- name: __END__
comment: "marker for the point in the file at which the parser should stop"
- - 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"
flags:
- name: ArgumentsNodeFlags
values:
@@ -808,8 +814,6 @@ nodes:
- 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.
@@ -818,7 +822,7 @@ nodes:
- name: keyword_loc
type: location
comment: |
- The location of the `alias` keyword.
+ The Location of the `alias` keyword.
alias $foo $bar
^^^^^
@@ -850,8 +854,6 @@ nodes:
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.
@@ -866,7 +868,7 @@ nodes:
- name: keyword_loc
type: location
comment: |
- Represents the location of the `alias` keyword.
+ Represents the Location of the `alias` keyword.
alias foo bar
^^^^^
@@ -896,7 +898,7 @@ nodes:
- name: operator_loc
type: location
comment: |
- Represents the alternation operator location.
+ Represents the alternation operator Location.
foo => bar | baz
^
@@ -932,7 +934,7 @@ nodes:
- name: operator_loc
type: location
comment: |
- The location of the `and` keyword or the `&&` operator.
+ The Location of the `and` keyword or the `&&` operator.
left and right
^^^
@@ -967,7 +969,7 @@ nodes:
- name: opening_loc
type: location?
comment: |
- Represents the optional source location for the opening token.
+ Represents the optional source Location for the opening token.
[1,2,3] # "["
%w[foo bar baz] # "%w["
@@ -976,7 +978,7 @@ nodes:
- name: closing_loc
type: location?
comment: |
- Represents the optional source location for the closing token.
+ Represents the optional source Location for the closing token.
[1,2,3] # "]"
%w[foo bar baz] # "]"
@@ -992,8 +994,19 @@ nodes:
- name: constant
type: node?
kind:
- - ConstantReadNode
- ConstantPathNode
+ - ConstantReadNode
+ comment: |
+ Represents the optional constant preceding the Array
+
+ foo in Bar[]
+ ^^^
+
+ foo in Bar[1, 2, 3]
+ ^^^
+
+ foo in Bar::Baz[1, 2, 3]
+ ^^^^^^^^
- name: requireds
type: node[]
kind: pattern expression
@@ -1004,7 +1017,9 @@ nodes:
^ ^
- name: rest
type: node?
- kind: pattern expression
+ kind:
+ - ImplicitRestNode
+ - SplatNode
comment: |
Represents the rest element of the array pattern.
@@ -1021,14 +1036,14 @@ nodes:
- name: opening_loc
type: location?
comment: |
- Represents the opening location of the array pattern.
+ Represents the opening Location of the array pattern.
foo in [1, 2]
^
- name: closing_loc
type: location?
comment: |
- Represents the closing location of the array pattern.
+ Represents the closing Location of the array pattern.
foo in [1, 2]
^
@@ -1036,19 +1051,19 @@ nodes:
Represents an array pattern in pattern matching.
foo in 1, 2
- ^^^^^^^^^^^
+ ^^^^
foo in [1, 2]
- ^^^^^^^^^^^^^
+ ^^^^^^
foo in *bar
- ^^^^^^^^^^^
+ ^^^^
foo in Bar[]
- ^^^^^^^^^^^^
+ ^^^^^
foo in Bar[1, 2, 3]
- ^^^^^^^^^^^^^^^^^^^
+ ^^^^^^^^^^^^
- name: AssocNode
fields:
- name: key
@@ -1079,7 +1094,7 @@ nodes:
- name: operator_loc
type: location?
comment: |
- The location of the `=>` operator, if present.
+ The Location of the `=>` operator, if present.
{ foo => bar }
^^
@@ -1101,7 +1116,7 @@ nodes:
- name: operator_loc
type: location
comment: |
- The location of the `**` operator.
+ The Location of the `**` operator.
{ **x }
^^
@@ -1130,7 +1145,7 @@ nodes:
- name: begin_keyword_loc
type: location?
comment: |
- Represents the location of the `begin` keyword.
+ Represents the Location of the `begin` keyword.
begin x end
^^^^^
@@ -1157,7 +1172,7 @@ nodes:
Represents the else clause within the begin block.
begin x; rescue y; else z; end
- ^^^^^^
+ ^^^^^^^^^^^
- name: ensure_clause
type: node?
kind: EnsureNode
@@ -1169,7 +1184,7 @@ nodes:
- name: end_keyword_loc
type: location?
comment: |
- Represents the location of the `end` keyword.
+ Represents the Location of the `end` keyword.
begin x end
^^^
@@ -1190,11 +1205,11 @@ nodes:
The expression that is being passed as a block argument. This can be any [non-void expression](https://github.com/ruby/prism/blob/main/docs/parsing_rules.md#non-void-expression).
foo(&args)
- ^^^^^
+ ^^^^
- name: operator_loc
type: location
comment: |
- Represents the location of the `&` operator.
+ Represents the Location of the `&` operator.
foo(&args)
^
@@ -1202,7 +1217,7 @@ nodes:
Represents a block argument using `&`.
bar(&args)
- ^^^^^^^^^^
+ ^^^^^
- name: BlockLocalVariableNode
flags: ParameterFlags
fields:
@@ -1255,17 +1270,17 @@ nodes:
- name: opening_loc
type: location
comment: |
- Represents the location of the opening `|`.
+ Represents the Location of the opening `{` or `do`.
[1, 2, 3].each { |i| puts x }
- ^
+ ^
- name: closing_loc
type: location
comment: |
- Represents the location of the closing `|`.
+ Represents the Location of the closing `}` or `end`.
[1, 2, 3].each { |i| puts x }
- ^
+ ^
comment: |
Represents a block of ruby code.
@@ -1285,14 +1300,14 @@ nodes:
- name: name_loc
type: location?
comment: |
- Represents the location of the block parameter name.
+ Represents the Location of the block parameter name.
def a(&b)
^
- name: operator_loc
type: location
comment: |
- Represents the location of the `&` operator.
+ Represents the Location of the `&` operator.
def a(&b)
^
@@ -1332,7 +1347,7 @@ nodes:
- name: opening_loc
type: location?
comment: |
- Represents the opening location of the block parameters.
+ Represents the opening Location of the block parameters.
-> (a, b = 1; local) { }
^
@@ -1343,7 +1358,7 @@ nodes:
- name: closing_loc
type: location?
comment: |
- Represents the closing location of the block parameters.
+ Represents the closing Location of the block parameters.
-> (a, b = 1; local) { }
^
@@ -1373,7 +1388,7 @@ nodes:
- name: keyword_loc
type: location
comment: |
- The location of the `break` keyword.
+ The Location of the `break` keyword.
break foo
^^^^^
@@ -1396,14 +1411,14 @@ nodes:
- name: call_operator_loc
type: location?
comment: |
- Represents the location of the call operator.
+ Represents the Location of the call operator.
foo.bar &&= value
^
- name: message_loc
type: location?
comment: |
- Represents the location of the message.
+ Represents the Location of the message.
foo.bar &&= value
^^^
@@ -1424,7 +1439,7 @@ nodes:
- name: operator_loc
type: location
comment: |
- Represents the location of the operator.
+ Represents the Location of the operator.
foo.bar &&= value
^^^
@@ -1461,7 +1476,7 @@ nodes:
- name: call_operator_loc
type: location?
comment: |
- Represents the location of the call operator.
+ Represents the Location of the call operator.
foo.bar
^
@@ -1478,14 +1493,15 @@ nodes:
- name: message_loc
type: location?
comment: |
- Represents the location of the message.
+ Represents the Location of the message.
foo.bar
^^^
- name: opening_loc
type: location?
comment: |
- Represents the location of the left parenthesis.
+ Represents the Location of the left parenthesis.
+
foo(bar)
^
- name: arguments
@@ -1499,10 +1515,20 @@ nodes:
- name: closing_loc
type: location?
comment: |
- Represents the location of the right parenthesis.
+ Represents the Location of the right parenthesis.
foo(bar)
^
+ - name: equal_loc
+ type: location?
+ comment: |
+ Represents the Location of the equal sign, in the case that this is an attribute write.
+
+ foo.bar = value
+ ^
+
+ foo[bar] = value
+ ^
- name: block
type: node?
kind:
@@ -1547,14 +1573,14 @@ nodes:
- name: call_operator_loc
type: location?
comment: |
- Represents the location of the call operator.
+ Represents the Location of the call operator.
foo.bar += value
^
- name: message_loc
type: location?
comment: |
- Represents the location of the message.
+ Represents the Location of the message.
foo.bar += value
^^^
@@ -1582,7 +1608,7 @@ nodes:
- name: binary_operator_loc
type: location
comment: |
- Represents the location of the binary operator.
+ Represents the Location of the binary operator.
foo.bar += value
^^
@@ -1613,14 +1639,14 @@ nodes:
- name: call_operator_loc
type: location?
comment: |
- Represents the location of the call operator.
+ Represents the Location of the call operator.
foo.bar ||= value
^
- name: message_loc
type: location?
comment: |
- Represents the location of the message.
+ Represents the Location of the message.
foo.bar ||= value
^^^
@@ -1641,7 +1667,7 @@ nodes:
- name: operator_loc
type: location
comment: |
- Represents the location of the operator.
+ Represents the Location of the operator.
foo.bar ||= value
^^^
@@ -1672,7 +1698,7 @@ nodes:
- name: call_operator_loc
type: location
comment: |
- Represents the location of the call operator.
+ Represents the Location of the call operator.
foo.bar = 1
^
@@ -1686,7 +1712,7 @@ nodes:
- name: message_loc
type: location
comment: |
- Represents the location of the message.
+ Represents the Location of the message.
foo.bar = 1
^^^
@@ -1724,7 +1750,7 @@ nodes:
- name: operator_loc
type: location
comment: |
- Represents the location of the `=>` operator.
+ Represents the Location of the `=>` operator.
foo => bar
^^
@@ -1732,7 +1758,7 @@ nodes:
Represents assigning to a local variable in pattern matching.
foo => [bar => baz]
- ^^^^^^^^^^^^
+ ^^^^^^^^^^
- name: CaseMatchNode
fields:
- name: predicate
@@ -1742,7 +1768,7 @@ nodes:
Represents the predicate of the case match. This can be either `nil` or any [non-void expressions](https://github.com/ruby/prism/blob/main/docs/parsing_rules.md#non-void-expression).
case true; in false; end
- ^^^^
+ ^^^^
- name: conditions
type: node[]
kind: InNode
@@ -1758,18 +1784,18 @@ nodes:
Represents the else clause of the case match.
case true; in false; else; end
- ^^^^
+ ^^^^^^^^^
- name: case_keyword_loc
type: location
comment: |
- Represents the location of the `case` keyword.
+ Represents the Location of the `case` keyword.
case true; in false; end
^^^^
- name: end_keyword_loc
type: location
comment: |
- Represents the location of the `end` keyword.
+ Represents the Location of the `end` keyword.
case true; in false; end
^^^
@@ -1789,7 +1815,7 @@ nodes:
Represents the predicate of the case statement. This can be either `nil` or any [non-void expressions](https://github.com/ruby/prism/blob/main/docs/parsing_rules.md#non-void-expression).
case true; when false; end
- ^^^^
+ ^^^^
- name: conditions
type: node[]
kind: WhenNode
@@ -1805,18 +1831,18 @@ nodes:
Represents the else clause of the case statement.
case true; when false; else; end
- ^^^^
+ ^^^^^^^^^
- name: case_keyword_loc
type: location
comment: |
- Represents the location of the `case` keyword.
+ Represents the Location of the `case` keyword.
case true; when false; end
^^^^
- name: end_keyword_loc
type: location
comment: |
- Represents the location of the `end` keyword.
+ Represents the Location of the `end` keyword.
case true; when false; end
^^^
@@ -1834,7 +1860,7 @@ nodes:
- name: class_keyword_loc
type: location
comment: |
- Represents the location of the `class` keyword.
+ Represents the Location of the `class` keyword.
class Foo end
^^^^^
@@ -1843,11 +1869,10 @@ nodes:
kind:
- ConstantReadNode
- ConstantPathNode
- - on error: CallNode # class 0.X end
- name: inheritance_operator_loc
type: location?
comment: |
- Represents the location of the `<` operator.
+ Represents the Location of the `<` operator.
class Foo < Bar
^
@@ -1867,13 +1892,12 @@ nodes:
comment: |
Represents the body of the class.
- class Foo
- foo
- ^^^
+ class Foo; bar; end
+ ^^^
- name: end_keyword_loc
type: location
comment: |
- Represents the location of the `end` keyword.
+ Represents the Location of the `end` keyword.
class Foo end
^^^
@@ -1900,14 +1924,14 @@ nodes:
- name: name_loc
type: location
comment: |
- Represents the location of the variable name.
+ Represents the Location of the variable name.
@@target &&= value
^^^^^^^^
- name: operator_loc
type: location
comment: |
- Represents the location of the `&&=` operator.
+ Represents the Location of the `&&=` operator.
@@target &&= value
^^^
@@ -1995,7 +2019,7 @@ nodes:
- name: name_loc
type: location
comment: |
- The location of the variable name.
+ The Location of the variable name.
@@foo = :bar
^^^^^
@@ -2013,7 +2037,7 @@ nodes:
- name: operator_loc
type: location
comment: |
- The location of the `=` operator.
+ The Location of the `=` operator.
@@foo = :bar
^
@@ -2109,7 +2133,7 @@ nodes:
- name: delimiter_loc
type: location
comment: |
- The location of the `::` delimiter.
+ The Location of the `::` delimiter.
::Foo
^^
@@ -2119,7 +2143,7 @@ nodes:
- name: name_loc
type: location
comment: |
- The location of the name of the constant.
+ The Location of the name of the constant.
::Foo
^^^
@@ -2195,7 +2219,7 @@ nodes:
- name: operator_loc
type: location
comment: |
- The location of the `=` operator.
+ The Location of the `=` operator.
::ABC = 123
^
@@ -2255,7 +2279,7 @@ nodes:
- name: name_loc
type: location
comment: |
- The location of the constant name.
+ The Location of the constant name.
FOO = 1
^^^
@@ -2273,7 +2297,7 @@ nodes:
- name: operator_loc
type: location
comment: |
- The location of the `=` operator.
+ The Location of the `=` operator.
FOO = :bar
^
@@ -2398,6 +2422,15 @@ nodes:
^^^^^^
bar
end
+ - name: ErrorRecoveryNode
+ fields:
+ - name: unexpected
+ type: node?
+ kind: Node
+ comment: |
+ The unexpected node that was found in the tree, if there was one.
+ comment: |
+ Represents a node that is either missing or unexpected and results in a syntax error.
- name: FalseNode
comment: |
Represents the use of the literal `false` keyword.
@@ -2409,23 +2442,66 @@ nodes:
- name: constant
type: node?
kind:
- - ConstantReadNode
- ConstantPathNode
+ - ConstantReadNode
+ comment: |
+ Represents the optional constant preceding the pattern
+
+ foo in Foo(*bar, baz, *qux)
+ ^^^
- name: left
type: node
kind: SplatNode
+ comment: |
+ Represents the first wildcard node in the pattern.
+
+ foo in *bar, baz, *qux
+ ^^^^
+
+ foo in Foo(*bar, baz, *qux)
+ ^^^^
- name: requireds
type: node[]
kind: pattern expression
+ comment: |
+ Represents the nodes in between the wildcards.
+
+ foo in *bar, baz, *qux
+ ^^^
+
+ foo in Foo(*bar, baz, 1, *qux)
+ ^^^^^^
- name: right
type: node
- kind:
- - SplatNode
- - on error: MissingNode
+ kind: SplatNode
+ comment: |
+ Represents the second wildcard node in the pattern.
+
+ foo in *bar, baz, *qux
+ ^^^^
+
+ foo in Foo(*bar, baz, *qux)
+ ^^^^
- name: opening_loc
type: location?
+ comment: |
+ The Location of the opening brace.
+
+ foo in [*bar, baz, *qux]
+ ^
+
+ foo in Foo(*bar, baz, *qux)
+ ^
- name: closing_loc
type: location?
+ comment: |
+ The Location of the closing brace.
+
+ foo in [*bar, baz, *qux]
+ ^
+
+ foo in Foo(*bar, baz, *qux)
+ ^
comment: |
Represents a find pattern in pattern matching.
@@ -2437,6 +2513,9 @@ nodes:
foo in Foo(*bar, baz, *qux)
^^^^^^^^^^^^^^^^^^^^
+
+ foo => *bar, baz, *qux
+ ^^^^^^^^^^^^^^^
- name: FlipFlopNode
flags: RangeFlags
fields:
@@ -2477,9 +2556,6 @@ nodes:
- 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.
@@ -2506,28 +2582,28 @@ nodes:
- name: for_keyword_loc
type: location
comment: |
- The location of the `for` keyword.
+ The Location of the `for` keyword.
for i in a end
^^^
- name: in_keyword_loc
type: location
comment: |
- The location of the `in` keyword.
+ 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.
+ 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.
+ The Location of the `end` keyword.
for i in a end
^^^
@@ -2553,14 +2629,29 @@ nodes:
end
- name: ForwardingSuperNode
fields:
+ - name: keyword_loc
+ type: location
+ comment: |
+ super
+ ^^^^^
+
+ super { 123 }
+ ^^^^^
- name: block
type: node?
kind: BlockNode
+ comment: |
+ All other arguments are forwarded as normal, except the original block is replaced with the new block.
comment: |
- Represents the use of the `super` keyword without parentheses or arguments.
+ Represents the use of the `super` keyword without parentheses or arguments, but which might have a block.
super
^^^^^
+
+ super { 123 }
+ ^^^^^^^^^^^^^
+
+ If it has any other arguments, it would be a `SuperNode` instead.
- name: GlobalVariableAndWriteNode
fields:
- name: name
@@ -2648,7 +2739,7 @@ nodes:
- name: name_loc
type: location
comment: |
- The location of the global variable's name.
+ The Location of the global variable's name.
$foo = :bar
^^^^
@@ -2666,7 +2757,7 @@ nodes:
- name: operator_loc
type: location
comment: |
- The location of the `=` operator.
+ The Location of the `=` operator.
$foo = :bar
^
@@ -2680,7 +2771,7 @@ nodes:
- name: opening_loc
type: location
comment: |
- The location of the opening brace.
+ The Location of the opening brace.
{ a => b }
^
@@ -2700,7 +2791,7 @@ nodes:
- name: closing_loc
type: location
comment: |
- The location of the closing brace.
+ The Location of the closing brace.
{ a => b }
^
@@ -2714,20 +2805,60 @@ nodes:
- name: constant
type: node?
kind:
- - ConstantReadNode
- ConstantPathNode
+ - ConstantReadNode
+ comment: |
+ Represents the optional constant preceding the Hash.
+
+ foo => Bar[a: 1, b: 2]
+ ^^^
+
+ foo => Bar::Baz[a: 1, b: 2]
+ ^^^^^^^^
- name: elements
type: node[]
kind: AssocNode
+ comment: |
+ Represents the explicit named hash keys and values.
+
+ foo => { a: 1, b:, ** }
+ ^^^^^^^^
- name: rest
type: node?
kind:
- AssocSplatNode
- NoKeywordsParameterNode
+ comment: |
+ Represents the rest of the Hash keys and values. This can be named, unnamed, or explicitly forbidden via `**nil`, this last one results in a `NoKeywordsParameterNode`.
+
+ foo => { a: 1, b:, **c }
+ ^^^
+
+ foo => { a: 1, b:, ** }
+ ^^
+
+ foo => { a: 1, b:, **nil }
+ ^^^^^
- name: opening_loc
type: location?
+ comment: |
+ The Location of the opening brace.
+
+ foo => { a: 1 }
+ ^
+
+ foo => Bar[a: 1]
+ ^
- name: closing_loc
type: location?
+ comment: |
+ The Location of the closing brace.
+
+ foo => { a: 1 }
+ ^
+
+ foo => Bar[a: 1]
+ ^
comment: |
Represents a hash pattern in pattern matching.
@@ -2736,12 +2867,18 @@ nodes:
foo => { a: 1, b: 2, **c }
^^^^^^^^^^^^^^^^^^^
+
+ foo => Bar[a: 1, b: 2]
+ ^^^^^^^^^^^^^^^
+
+ foo in { a: 1, b: 2 }
+ ^^^^^^^^^^^^^^
- name: IfNode
fields:
- name: if_keyword_loc
type: location?
comment: |
- The location of the `if` keyword if present.
+ The Location of the `if` keyword if present.
bar if foo
^^
@@ -2766,7 +2903,7 @@ nodes:
- name: then_keyword_loc
type: location?
comment: |
- The location of the `then` keyword (if present) or the `?` in a ternary expression, `nil` otherwise.
+ The Location of the `then` keyword (if present) or the `?` in a ternary expression, `nil` otherwise.
if foo then bar end
^^^^
@@ -2807,7 +2944,7 @@ nodes:
- name: end_keyword_loc
type: location?
comment: |
- The location of the `end` keyword if present, `nil` otherwise.
+ The Location of the `end` keyword if present, `nil` otherwise.
if foo
bar
@@ -3092,7 +3229,7 @@ nodes:
- name: name_loc
type: location
comment: |
- The location of the variable name.
+ The Location of the variable name.
@_x = 1
^^^
@@ -3110,7 +3247,7 @@ nodes:
- name: operator_loc
type: location
comment: |
- The location of the `=` operator.
+ The Location of the `=` operator.
@x = y
^
@@ -3180,7 +3317,6 @@ nodes:
- EmbeddedStatementsNode
- EmbeddedVariableNode
- InterpolatedStringNode # `"a" "#{b}"`
- - on error: XStringNode # `<<`FOO` "bar"
- name: closing_loc
type: location?
newline: parts
@@ -3388,6 +3524,9 @@ nodes:
foo, bar = baz
^^^ ^^^
+
+ foo => baz
+ ^^^
- name: LocalVariableWriteNode
fields:
- name: name
@@ -3411,7 +3550,7 @@ nodes:
- name: name_loc
type: location
comment: |
- The location of the variable name.
+ The Location of the variable name.
foo = :bar
^^^
@@ -3433,7 +3572,7 @@ nodes:
- name: operator_loc
type: location
comment: |
- The location of the `=` operator.
+ The Location of the `=` operator.
x = :y
^
@@ -3478,11 +3617,65 @@ nodes:
- name: value
type: node
kind: non-void expression
+ comment: |
+ Represents the left-hand side of the operator.
+
+ foo => bar
+ ^^^
- name: pattern
type: node
kind: pattern expression
+ comment: |
+ Represents the right-hand side of the operator. The type of the node depends on the expression.
+
+ Anything that looks like a local variable name (including `_`) will result in a `LocalVariableTargetNode`.
+
+ foo => a # This is equivalent to writing `a = foo`
+ ^
+
+ Using an explicit `Array` or combining expressions with `,` will result in a `ArrayPatternNode`. This can be preceded by a constant.
+
+ foo => [a]
+ ^^^
+
+ foo => a, b
+ ^^^^
+
+ foo => Bar[a, b]
+ ^^^^^^^^^
+
+ If the array pattern contains at least two wildcard matches, a `FindPatternNode` is created instead.
+
+ foo => *, 1, *a
+ ^^^^^
+
+ Using an explicit `Hash` or a constant with square brackets and hash keys in the square brackets will result in a `HashPatternNode`.
+
+ foo => { a: 1, b: }
+
+ foo => Bar[a: 1, b:]
+
+ foo => Bar[**]
+
+ To use any variable that needs run time evaluation, pinning is required. This results in a `PinnedVariableNode`
+
+ foo => ^a
+ ^^
+
+ Similar, any expression can be used with pinning. This results in a `PinnedExpressionNode`.
+
+ foo => ^(a + 1)
+
+ Anything else will result in the regular node for that expression, for example a `ConstantReadNode`.
+
+ foo => CONST
- name: operator_loc
type: location
+ comment: |
+ The Location of the operator.
+
+ foo => bar
+ ^^
comment: |
Represents the use of the `=>` operator.
@@ -3501,9 +3694,6 @@ nodes:
/(?<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
@@ -3515,7 +3705,6 @@ nodes:
kind:
- ConstantReadNode
- ConstantPathNode
- - on error: MissingNode # module Parent module end
- name: body
type: node?
kind:
@@ -3545,8 +3734,6 @@ nodes:
- 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.
@@ -3590,8 +3777,6 @@ nodes:
- 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.
@@ -3600,14 +3785,14 @@ nodes:
- name: lparen_loc
type: location?
comment: |
- The location of the opening parenthesis.
+ The Location of the opening parenthesis.
a, (b, c) = 1, 2, 3
^
- name: rparen_loc
type: location?
comment: |
- The location of the closing parenthesis.
+ The Location of the closing parenthesis.
a, (b, c) = 1, 2, 3
^
@@ -3635,8 +3820,6 @@ nodes:
- CallTargetNode
- IndexTargetNode
- MultiTargetNode
- - on error: BackReferenceReadNode # $&, = z
- - on error: NumberedReferenceReadNode # $1, = z
comment: |
Represents the targets expressions before a splat node.
@@ -3679,8 +3862,6 @@ nodes:
- CallTargetNode
- IndexTargetNode
- MultiTargetNode
- - on error: BackReferenceReadNode # *, $& = z
- - on error: NumberedReferenceReadNode # *, $1 = z
comment: |
Represents the targets expressions after a splat node.
@@ -3689,21 +3870,21 @@ nodes:
- name: lparen_loc
type: location?
comment: |
- The location of the opening parenthesis.
+ The Location of the opening parenthesis.
(a, b, c) = 1, 2, 3
^
- name: rparen_loc
type: location?
comment: |
- The location of the closing parenthesis.
+ The Location of the closing parenthesis.
(a, b, c) = 1, 2, 3
^
- name: operator_loc
type: location
comment: |
- The location of the operator.
+ The Location of the operator.
a, b, c = 1, 2, 3
^
@@ -3738,6 +3919,18 @@ nodes:
nil
^^^
+ - name: NoBlockParameterNode
+ 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: NoKeywordsParameterNode
fields:
- name: operator_loc
@@ -3837,7 +4030,7 @@ nodes:
- name: operator_loc
type: location
comment: |
- The location of the `or` keyword or the `||` operator.
+ The Location of the `or` keyword or the `||` operator.
left or right
^^
@@ -3866,11 +4059,6 @@ nodes:
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:
@@ -3884,7 +4072,9 @@ nodes:
- NoKeywordsParameterNode
- name: block
type: node?
- kind: BlockParameterNode
+ kind:
+ - BlockParameterNode
+ - NoBlockParameterNode
comment: |
Represents the list of parameters on a method, block, or lambda definition.
@@ -3912,12 +4102,32 @@ nodes:
- name: expression
type: node
kind: non-void expression
+ comment: |
+ The expression used in the pinned expression
+
+ foo in ^(bar)
+ ^^^
- name: operator_loc
type: location
+ comment: |
+ The Location of the `^` operator
+
+ foo in ^(bar)
+ ^
- name: lparen_loc
type: location
+ comment: |
+ The Location of the opening parenthesis.
+
+ foo in ^(bar)
+ ^
- name: rparen_loc
type: location
+ comment: |
+ The Location of the closing parenthesis.
+
+ foo in ^(bar)
+ ^
comment: |
Represents the use of the `^` operator for pinning an expression in a pattern matching expression.
@@ -3935,9 +4145,18 @@ nodes:
- BackReferenceReadNode # foo in ^$&
- NumberedReferenceReadNode # foo in ^$1
- ItLocalVariableReadNode # proc { 1 in ^it }
- - on error: MissingNode # foo in ^Bar
+ comment: |
+ The variable used in the pinned expression
+
+ foo in ^bar
+ ^^^
- name: operator_loc
type: location
+ comment: |
+ The Location of the `^` operator
+
+ foo in ^bar
+ ^
comment: |
Represents the use of the `^` operator for pinning a variable in a pattern matching expression.
@@ -4008,11 +4227,11 @@ nodes:
1...foo
^^^
- If neither right-hand or left-hand side was included, this will be a MissingNode.
+ If neither right-hand or left-hand side was included, this will be an ErrorRecoveryNode.
- name: operator_loc
type: location
comment: |
- The location of the `..` or `...` operator.
+ The Location of the `..` or `...` operator.
comment: |
Represents the use of the `..` or `...` operators.
@@ -4123,9 +4342,6 @@ nodes:
- ConstantPathTargetNode
- CallTargetNode
- IndexTargetNode
- - on error: BackReferenceReadNode # => begin; rescue => $&; end
- - on error: NumberedReferenceReadNode # => begin; rescue => $1; end
- - on error: MissingNode # begin; rescue =>; end
- name: then_keyword_loc
type: location?
- name: statements
@@ -4238,7 +4454,7 @@ nodes:
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 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.
@@ -4303,6 +4519,7 @@ nodes:
- name: arguments
type: node?
kind: ArgumentsNode
+ comment: "Can be only `nil` when there are empty parentheses, like `super()`."
- name: rparen_loc
type: location?
- name: block
@@ -4318,6 +4535,8 @@ nodes:
super foo, bar
^^^^^^^^^^^^^^
+
+ If no arguments are provided (except for a block), it would be a `ForwardingSuperNode` instead.
- name: SymbolNode
flags: SymbolFlags
fields:
@@ -4362,7 +4581,7 @@ nodes:
- name: keyword_loc
type: location
comment: |
- The location of the `unless` keyword.
+ The Location of the `unless` keyword.
unless cond then bar end
^^^^^^
@@ -4383,7 +4602,7 @@ nodes:
- name: then_keyword_loc
type: location?
comment: |
- The location of the `then` keyword, if present.
+ The Location of the `then` keyword, if present.
unless cond then bar end
^^^^
@@ -4403,11 +4622,11 @@ nodes:
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.
+ The Location of the `end` keyword, if present.
unless cond then bar end
^^^
diff --git a/prism/constant_pool.c b/prism/constant_pool.c
new file mode 100644
index 0000000000..90201ebb8e
--- /dev/null
+++ b/prism/constant_pool.c
@@ -0,0 +1,360 @@
+#include "prism/internal/constant_pool.h"
+
+#include "prism/compiler/align.h"
+#include "prism/compiler/inline.h"
+#include "prism/internal/arena.h"
+
+#include <assert.h>
+#include <stdbool.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_arena_t *arena, pm_constant_id_list_t *list, size_t capacity) {
+ if (capacity) {
+ list->ids = (pm_constant_id_t *) pm_arena_zalloc(arena, capacity * sizeof(pm_constant_id_t), PRISM_ALIGNOF(pm_constant_id_t));
+ } else {
+ list->ids = NULL;
+ }
+
+ list->size = 0;
+ list->capacity = capacity;
+}
+
+/**
+ * Append a constant id to a list of constant ids.
+ */
+void
+pm_constant_id_list_append(pm_arena_t *arena, pm_constant_id_list_t *list, pm_constant_id_t id) {
+ if (list->size >= list->capacity) {
+ size_t new_capacity = list->capacity == 0 ? 8 : list->capacity * 2;
+ pm_constant_id_t *new_ids = (pm_constant_id_t *) pm_arena_alloc(arena, sizeof(pm_constant_id_t) * new_capacity, PRISM_ALIGNOF(pm_constant_id_t));
+
+ if (list->size > 0) {
+ memcpy(new_ids, list->ids, list->size * sizeof(pm_constant_id_t));
+ }
+
+ list->ids = new_ids;
+ list->capacity = new_capacity;
+ }
+
+ list->ids[list->size++] = id;
+}
+
+/**
+ * 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;
+}
+
+/**
+ * A multiply-xorshift hash that processes input a word at a time. This is
+ * significantly faster than the byte-at-a-time djb2 hash for the short strings
+ * typical in Ruby source (~15 bytes average). Each word is mixed into the hash
+ * by XOR followed by multiplication by a large odd constant, which spreads
+ * entropy across all bits. A final xorshift fold produces the 32-bit result.
+ */
+static PRISM_INLINE uint32_t
+pm_constant_pool_hash(const uint8_t *start, size_t length) {
+ // This constant is borrowed from wyhash. It is a 64-bit odd integer with
+ // roughly equal 0/1 bits, chosen for good avalanche behavior when used in
+ // multiply-xorshift sequences.
+ static const uint64_t secret = 0x517cc1b727220a95ULL;
+ uint64_t hash = (uint64_t) length;
+
+ if (length <= 8) {
+ // Short strings: read first and last 4 bytes (overlapping for len < 8).
+ // This covers the majority of Ruby identifiers with a single multiply.
+ if (length >= 4) {
+ uint32_t a, b;
+ memcpy(&a, start, 4);
+ memcpy(&b, start + length - 4, 4);
+ hash ^= (uint64_t) a | ((uint64_t) b << 32);
+ } else if (length > 0) {
+ hash ^= (uint64_t) start[0] | ((uint64_t) start[length >> 1] << 8) | ((uint64_t) start[length - 1] << 16);
+ }
+ hash *= secret;
+ } else if (length <= 16) {
+ // Medium strings: read first and last 8 bytes (overlapping).
+ // Two multiplies instead of the three the loop-based approach needs.
+ uint64_t word;
+ memcpy(&word, start, 8);
+ hash ^= word;
+ hash *= secret;
+ memcpy(&word, start + length - 8, 8);
+ hash ^= word;
+ hash *= secret;
+ } else {
+ const uint8_t *ptr = start;
+ size_t remaining = length;
+
+ while (remaining >= 8) {
+ uint64_t word;
+ memcpy(&word, ptr, 8);
+ hash ^= word;
+ hash *= secret;
+ ptr += 8;
+ remaining -= 8;
+ }
+
+ if (remaining > 0) {
+ // Read the last 8 bytes (overlapping with already-processed data).
+ uint64_t word;
+ memcpy(&word, start + length - 8, 8);
+ hash ^= word;
+ hash *= secret;
+ }
+ }
+
+ hash ^= hash >> 32;
+ return (uint32_t) hash;
+}
+
+/**
+ * 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 PRISM_INLINE void
+pm_constant_pool_resize(pm_arena_t *arena, pm_constant_pool_t *pool) {
+ assert(is_power_of_two(pool->capacity));
+
+ uint32_t next_capacity = pool->capacity * 2;
+ const uint32_t mask = next_capacity - 1;
+
+ pm_constant_pool_bucket_t *next_buckets = (pm_constant_pool_bucket_t *) pm_arena_zalloc(arena, next_capacity * sizeof(pm_constant_pool_bucket_t), PRISM_ALIGNOF(pm_constant_pool_bucket_t));
+ pm_constant_t *next_constants = (pm_constant_t *) pm_arena_alloc(arena, next_capacity * sizeof(pm_constant_t), PRISM_ALIGNOF(pm_constant_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 = next_constants;
+ pool->buckets = next_buckets;
+ pool->capacity = next_capacity;
+}
+
+/**
+ * Initialize a new constant pool with a given capacity.
+ */
+void
+pm_constant_pool_init(pm_arena_t *arena, pm_constant_pool_t *pool, uint32_t capacity) {
+ capacity = next_power_of_two(capacity);
+
+ pool->buckets = (pm_constant_pool_bucket_t *) pm_arena_zalloc(arena, capacity * sizeof(pm_constant_pool_bucket_t), PRISM_ALIGNOF(pm_constant_pool_bucket_t));
+ pool->constants = (pm_constant_t *) pm_arena_alloc(arena, capacity * sizeof(pm_constant_t), PRISM_ALIGNOF(pm_constant_t));
+ pool->size = 0;
+ pool->capacity = capacity;
+}
+
+/**
+ * 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) {
+ if ((bucket->length == length) && memcmp(bucket->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 PRISM_INLINE pm_constant_id_t
+pm_constant_pool_insert(pm_arena_t *arena, 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)) {
+ pm_constant_pool_resize(arena, pool);
+ }
+
+ 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.
+ if ((bucket->length == length) && memcmp(bucket->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 && 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 replace it with the
+ // shared constant to prefer non-owned references.
+ bucket->start = start;
+ bucket->type = (unsigned int) (type & 0x3);
+ pool->constants[bucket->id - 1].start = start;
+ }
+
+ 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,
+ .start = start,
+ .length = length
+ };
+
+ 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_arena_t *arena, pm_constant_pool_t *pool, const uint8_t *start, size_t length) {
+ return pm_constant_pool_insert(arena, 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_arena_t *arena, pm_constant_pool_t *pool, uint8_t *start, size_t length) {
+ return pm_constant_pool_insert(arena, 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_arena_t *arena, pm_constant_pool_t *pool, const uint8_t *start, size_t length) {
+ return pm_constant_pool_insert(arena, pool, start, length, PM_CONSTANT_POOL_BUCKET_CONSTANT);
+}
+
+/**
+ * Return a raw pointer to the start of a constant.
+ */
+const uint8_t *
+pm_constant_start(const pm_constant_t *constant) {
+ return constant->start;
+}
+
+/**
+ * Return the length of a constant.
+ */
+size_t pm_constant_length(const pm_constant_t *constant) {
+ return constant->length;
+}
diff --git a/prism/constant_pool.h b/prism/constant_pool.h
new file mode 100644
index 0000000000..dc03235c70
--- /dev/null
+++ b/prism/constant_pool.h
@@ -0,0 +1,81 @@
+/**
+ * @file 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/compiler/exported.h"
+#include "prism/compiler/nodiscard.h"
+#include "prism/compiler/nonnull.h"
+
+#include "prism/arena.h"
+
+#include <stddef.h>
+#include <stdint.h>
+
+/**
+ * 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;
+
+/** A constant in the pool which effectively stores a string. */
+typedef struct pm_constant_t pm_constant_t;
+
+/**
+ * The overall constant pool, which stores constants found while parsing.
+ */
+typedef struct pm_constant_pool_t pm_constant_pool_t;
+
+/**
+ * Return a raw pointer to the start of a constant.
+ *
+ * @param constant The constant to get the start of.
+ * @returns A raw pointer to the start of the constant.
+ */
+PRISM_EXPORTED_FUNCTION const uint8_t * pm_constant_start(const pm_constant_t *constant) PRISM_NONNULL(1);
+
+/**
+ * Return the length of a constant.
+ *
+ * @param constant The constant to get the length of.
+ * @returns The length of the constant.
+ */
+PRISM_EXPORTED_FUNCTION size_t pm_constant_length(const pm_constant_t *constant) PRISM_NONNULL(1);
+
+/**
+ * Initialize a list of constant ids.
+ *
+ * @param list The list to initialize.
+ */
+PRISM_EXPORTED_FUNCTION void pm_constant_id_list_init(pm_constant_id_list_t *list) PRISM_NONNULL(1);
+
+/**
+ * Append a constant id to a list of constant ids.
+ *
+ * @param arena The arena to use for allocations.
+ * @param list The list to append to.
+ * @param id The constant id to append.
+ */
+PRISM_EXPORTED_FUNCTION void pm_constant_id_list_append(pm_arena_t *arena, pm_constant_id_list_t *list, pm_constant_id_t id) PRISM_NONNULL(1, 2);
+
+#endif
diff --git a/prism/defines.h b/prism/defines.h
deleted file mode 100644
index e31429c789..0000000000
--- a/prism/defines.h
+++ /dev/null
@@ -1,260 +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 sys/types.h before inttypes.h to work around issue with
-// certain versions of GCC and newlib which causes omission of PRIx64
-#include <sys/types.h>
-#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 10000
-#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 POSIX systems it accepts a float, a double, or a long double.
- * But mingw didn't provide an isinf macro, only an isinf function that only
- * accepts floats, so we need to use _finite instead.
- */
-#ifdef __MINGW64__
- #include <float.h>
- #define PRISM_ISINF(x) (!_finite(x))
-#else
- #define PRISM_ISINF(x) isinf(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
-
-/**
- * We use -Wimplicit-fallthrough to guard potentially unintended fall-through between cases of a switch.
- * Use PRISM_FALLTHROUGH to explicitly annotate cases where the fallthrough is intentional.
- */
-#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202311L // C23 or later
- #define PRISM_FALLTHROUGH [[fallthrough]];
-#elif defined(__GNUC__) || defined(__clang__)
- #define PRISM_FALLTHROUGH __attribute__((fallthrough));
-#elif defined(_MSC_VER)
- #define PRISM_FALLTHROUGH __fallthrough;
-#else
- #define PRISM_FALLTHROUGH
-#endif
-
-#endif
diff --git a/prism/diagnostic.h b/prism/diagnostic.h
new file mode 100644
index 0000000000..370061ec56
--- /dev/null
+++ b/prism/diagnostic.h
@@ -0,0 +1,93 @@
+/**
+ * @file diagnostic.h
+ *
+ * A list of diagnostics generated during parsing.
+ */
+#ifndef PRISM_DIAGNOSTIC_H
+#define PRISM_DIAGNOSTIC_H
+
+#include "prism/compiler/exported.h"
+#include "prism/compiler/nodiscard.h"
+#include "prism/compiler/nonnull.h"
+
+#include "prism/ast.h"
+
+/**
+ * An opaque pointer to a diagnostic generated during parsing.
+ */
+typedef struct pm_diagnostic_t 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 type of the given diagnostic.
+ *
+ * @param diagnostic The diagnostic to get the type of.
+ * @returns The type of the given diagnostic. Note that this is a string
+ * representation of an internal ID, and is not meant to be relied upon as a
+ * stable identifier for the diagnostic. We do not guarantee that these will
+ * not change in the future. This is meant to be used for debugging and
+ * error reporting purposes, and not for programmatic checks.
+ */
+PRISM_EXPORTED_FUNCTION const char * pm_diagnostic_type(const pm_diagnostic_t *diagnostic) PRISM_NONNULL(1);
+
+/**
+ * Get the location of the given diagnostic.
+ *
+ * @param diagnostic The diagnostic to get the location of.
+ * @returns The location of the given diagnostic.
+ */
+PRISM_EXPORTED_FUNCTION pm_location_t pm_diagnostic_location(const pm_diagnostic_t *diagnostic) PRISM_NONNULL(1);
+
+/**
+ * Get the message of the given diagnostic.
+ *
+ * @param diagnostic The diagnostic to get the message of.
+ * @returns The message of the given diagnostic.
+ */
+PRISM_EXPORTED_FUNCTION const char * pm_diagnostic_message(const pm_diagnostic_t *diagnostic) PRISM_NONNULL(1);
+
+/**
+ * Get the error level associated with the given diagnostic.
+ *
+ * @param diagnostic The diagnostic to get the error level of.
+ * @returns The error level of the given diagnostic. If the diagnostic was a
+ * warning, or is in any way not an error, then the return value is
+ * undefined and should not be relied upon.
+ */
+PRISM_EXPORTED_FUNCTION pm_error_level_t pm_diagnostic_error_level(const pm_diagnostic_t *diagnostic) PRISM_NONNULL(1);
+
+/**
+ * Get the warning level associated with the given diagnostic.
+ *
+ * @param diagnostic The diagnostic to get the warning level of.
+ * @returns The warning level of the given diagnostic. If the diagnostic was an
+ * error, or is in any way not a warning, then the return value is
+ * undefined and should not be relied upon.
+ */
+PRISM_EXPORTED_FUNCTION pm_warning_level_t pm_diagnostic_warning_level(const pm_diagnostic_t *diagnostic) PRISM_NONNULL(1);
+
+#endif
diff --git a/prism/encoding.c b/prism/encoding.c
index a4aeed104f..c9c2e13056 100644
--- a/prism/encoding.c
+++ b/prism/encoding.c
@@ -1,8 +1,13 @@
-#include "prism/encoding.h"
+#include "prism/internal/encoding.h"
+
+#include "prism/compiler/unused.h"
+#include "prism/internal/strncasecmp.h"
+
+#include <assert.h>
typedef uint32_t pm_unicode_codepoint_t;
-#define UNICODE_ALPHA_CODEPOINTS_LENGTH 1450
+#define UNICODE_ALPHA_CODEPOINTS_LENGTH 1508
static const pm_unicode_codepoint_t unicode_alpha_codepoints[UNICODE_ALPHA_CODEPOINTS_LENGTH] = {
0x100, 0x2C1,
0x2C6, 0x2D1,
@@ -10,7 +15,7 @@ static const pm_unicode_codepoint_t unicode_alpha_codepoints[UNICODE_ALPHA_CODEP
0x2EC, 0x2EC,
0x2EE, 0x2EE,
0x345, 0x345,
- 0x370, 0x374,
+ 0x363, 0x374,
0x376, 0x377,
0x37A, 0x37D,
0x37F, 0x37F,
@@ -50,7 +55,8 @@ static const pm_unicode_codepoint_t unicode_alpha_codepoints[UNICODE_ALPHA_CODEP
0x840, 0x858,
0x860, 0x86A,
0x870, 0x887,
- 0x889, 0x88E,
+ 0x889, 0x88F,
+ 0x897, 0x897,
0x8A0, 0x8C9,
0x8D4, 0x8DF,
0x8E3, 0x8E9,
@@ -140,7 +146,7 @@ static const pm_unicode_codepoint_t unicode_alpha_codepoints[UNICODE_ALPHA_CODEP
0xC4A, 0xC4C,
0xC55, 0xC56,
0xC58, 0xC5A,
- 0xC5D, 0xC5D,
+ 0xC5C, 0xC5D,
0xC60, 0xC63,
0xC80, 0xC83,
0xC85, 0xC8C,
@@ -152,7 +158,7 @@ static const pm_unicode_codepoint_t unicode_alpha_codepoints[UNICODE_ALPHA_CODEP
0xCC6, 0xCC8,
0xCCA, 0xCCC,
0xCD5, 0xCD6,
- 0xCDD, 0xCDE,
+ 0xCDC, 0xCDE,
0xCE0, 0xCE3,
0xCF1, 0xCF3,
0xD00, 0xD0C,
@@ -264,7 +270,7 @@ static const pm_unicode_codepoint_t unicode_alpha_codepoints[UNICODE_ALPHA_CODEP
0x1C00, 0x1C36,
0x1C4D, 0x1C4F,
0x1C5A, 0x1C7D,
- 0x1C80, 0x1C88,
+ 0x1C80, 0x1C8A,
0x1C90, 0x1CBA,
0x1CBD, 0x1CBF,
0x1CE9, 0x1CEC,
@@ -272,7 +278,7 @@ static const pm_unicode_codepoint_t unicode_alpha_codepoints[UNICODE_ALPHA_CODEP
0x1CF5, 0x1CF6,
0x1CFA, 0x1CFA,
0x1D00, 0x1DBF,
- 0x1DE7, 0x1DF4,
+ 0x1DD3, 0x1DF4,
0x1E00, 0x1F15,
0x1F18, 0x1F1D,
0x1F20, 0x1F45,
@@ -352,11 +358,8 @@ static const pm_unicode_codepoint_t unicode_alpha_codepoints[UNICODE_ALPHA_CODEP
0xA67F, 0xA6EF,
0xA717, 0xA71F,
0xA722, 0xA788,
- 0xA78B, 0xA7CA,
- 0xA7D0, 0xA7D1,
- 0xA7D3, 0xA7D3,
- 0xA7D5, 0xA7D9,
- 0xA7F2, 0xA805,
+ 0xA78B, 0xA7DC,
+ 0xA7F1, 0xA805,
0xA807, 0xA827,
0xA840, 0xA873,
0xA880, 0xA8C3,
@@ -446,6 +449,7 @@ static const pm_unicode_codepoint_t unicode_alpha_codepoints[UNICODE_ALPHA_CODEP
0x105A3, 0x105B1,
0x105B3, 0x105B9,
0x105BB, 0x105BC,
+ 0x105C0, 0x105F3,
0x10600, 0x10736,
0x10740, 0x10755,
0x10760, 0x10767,
@@ -464,6 +468,7 @@ static const pm_unicode_codepoint_t unicode_alpha_codepoints[UNICODE_ALPHA_CODEP
0x108F4, 0x108F5,
0x10900, 0x10915,
0x10920, 0x10939,
+ 0x10940, 0x10959,
0x10980, 0x109B7,
0x109BE, 0x109BF,
0x10A00, 0x10A03,
@@ -483,9 +488,14 @@ static const pm_unicode_codepoint_t unicode_alpha_codepoints[UNICODE_ALPHA_CODEP
0x10C80, 0x10CB2,
0x10CC0, 0x10CF2,
0x10D00, 0x10D27,
+ 0x10D4A, 0x10D65,
+ 0x10D69, 0x10D69,
+ 0x10D6F, 0x10D85,
0x10E80, 0x10EA9,
0x10EAB, 0x10EAC,
0x10EB0, 0x10EB1,
+ 0x10EC2, 0x10EC7,
+ 0x10EFA, 0x10EFC,
0x10F00, 0x10F1C,
0x10F27, 0x10F27,
0x10F30, 0x10F45,
@@ -529,6 +539,17 @@ static const pm_unicode_codepoint_t unicode_alpha_codepoints[UNICODE_ALPHA_CODEP
0x11350, 0x11350,
0x11357, 0x11357,
0x1135D, 0x11363,
+ 0x11380, 0x11389,
+ 0x1138B, 0x1138B,
+ 0x1138E, 0x1138E,
+ 0x11390, 0x113B5,
+ 0x113B7, 0x113C0,
+ 0x113C2, 0x113C2,
+ 0x113C5, 0x113C5,
+ 0x113C7, 0x113CA,
+ 0x113CC, 0x113CD,
+ 0x113D1, 0x113D1,
+ 0x113D3, 0x113D3,
0x11400, 0x11441,
0x11443, 0x11445,
0x11447, 0x1144A,
@@ -567,6 +588,8 @@ static const pm_unicode_codepoint_t unicode_alpha_codepoints[UNICODE_ALPHA_CODEP
0x11A50, 0x11A97,
0x11A9D, 0x11A9D,
0x11AB0, 0x11AF8,
+ 0x11B60, 0x11B67,
+ 0x11BC0, 0x11BE0,
0x11C00, 0x11C08,
0x11C0A, 0x11C36,
0x11C38, 0x11C3E,
@@ -588,6 +611,7 @@ static const pm_unicode_codepoint_t unicode_alpha_codepoints[UNICODE_ALPHA_CODEP
0x11D90, 0x11D91,
0x11D93, 0x11D96,
0x11D98, 0x11D98,
+ 0x11DB0, 0x11DDB,
0x11EE0, 0x11EF6,
0x11F00, 0x11F10,
0x11F12, 0x11F3A,
@@ -599,7 +623,9 @@ static const pm_unicode_codepoint_t unicode_alpha_codepoints[UNICODE_ALPHA_CODEP
0x12F90, 0x12FF0,
0x13000, 0x1342F,
0x13441, 0x13446,
+ 0x13460, 0x143FA,
0x14400, 0x14646,
+ 0x16100, 0x1612E,
0x16800, 0x16A38,
0x16A40, 0x16A5E,
0x16A70, 0x16ABE,
@@ -608,16 +634,19 @@ static const pm_unicode_codepoint_t unicode_alpha_codepoints[UNICODE_ALPHA_CODEP
0x16B40, 0x16B43,
0x16B63, 0x16B77,
0x16B7D, 0x16B8F,
+ 0x16D40, 0x16D6C,
0x16E40, 0x16E7F,
+ 0x16EA0, 0x16EB8,
+ 0x16EBB, 0x16ED3,
0x16F00, 0x16F4A,
0x16F4F, 0x16F87,
0x16F8F, 0x16F9F,
0x16FE0, 0x16FE1,
0x16FE3, 0x16FE3,
- 0x16FF0, 0x16FF1,
- 0x17000, 0x187F7,
- 0x18800, 0x18CD5,
- 0x18D00, 0x18D08,
+ 0x16FF0, 0x16FF6,
+ 0x17000, 0x18CD5,
+ 0x18CFF, 0x18D1E,
+ 0x18D80, 0x18DF2,
0x1AFF0, 0x1AFF3,
0x1AFF5, 0x1AFFB,
0x1AFFD, 0x1AFFE,
@@ -677,6 +706,11 @@ static const pm_unicode_codepoint_t unicode_alpha_codepoints[UNICODE_ALPHA_CODEP
0x1E290, 0x1E2AD,
0x1E2C0, 0x1E2EB,
0x1E4D0, 0x1E4EB,
+ 0x1E5D0, 0x1E5ED,
+ 0x1E5F0, 0x1E5F0,
+ 0x1E6C0, 0x1E6DE,
+ 0x1E6E0, 0x1E6F5,
+ 0x1E6FE, 0x1E6FF,
0x1E7E0, 0x1E7E6,
0x1E7E8, 0x1E7EB,
0x1E7ED, 0x1E7EE,
@@ -722,16 +756,16 @@ static const pm_unicode_codepoint_t unicode_alpha_codepoints[UNICODE_ALPHA_CODEP
0x1F150, 0x1F169,
0x1F170, 0x1F189,
0x20000, 0x2A6DF,
- 0x2A700, 0x2B739,
- 0x2B740, 0x2B81D,
- 0x2B820, 0x2CEA1,
+ 0x2A700, 0x2B81D,
+ 0x2B820, 0x2CEAD,
0x2CEB0, 0x2EBE0,
+ 0x2EBF0, 0x2EE5D,
0x2F800, 0x2FA1D,
0x30000, 0x3134A,
- 0x31350, 0x323AF,
+ 0x31350, 0x33479,
};
-#define UNICODE_ALNUM_CODEPOINTS_LENGTH 1528
+#define UNICODE_ALNUM_CODEPOINTS_LENGTH 1598
static const pm_unicode_codepoint_t unicode_alnum_codepoints[UNICODE_ALNUM_CODEPOINTS_LENGTH] = {
0x100, 0x2C1,
0x2C6, 0x2D1,
@@ -739,7 +773,7 @@ static const pm_unicode_codepoint_t unicode_alnum_codepoints[UNICODE_ALNUM_CODEP
0x2EC, 0x2EC,
0x2EE, 0x2EE,
0x345, 0x345,
- 0x370, 0x374,
+ 0x363, 0x374,
0x376, 0x377,
0x37A, 0x37D,
0x37F, 0x37F,
@@ -778,7 +812,8 @@ static const pm_unicode_codepoint_t unicode_alnum_codepoints[UNICODE_ALNUM_CODEP
0x840, 0x858,
0x860, 0x86A,
0x870, 0x887,
- 0x889, 0x88E,
+ 0x889, 0x88F,
+ 0x897, 0x897,
0x8A0, 0x8C9,
0x8D4, 0x8DF,
0x8E3, 0x8E9,
@@ -872,7 +907,7 @@ static const pm_unicode_codepoint_t unicode_alnum_codepoints[UNICODE_ALNUM_CODEP
0xC4A, 0xC4C,
0xC55, 0xC56,
0xC58, 0xC5A,
- 0xC5D, 0xC5D,
+ 0xC5C, 0xC5D,
0xC60, 0xC63,
0xC66, 0xC6F,
0xC80, 0xC83,
@@ -885,7 +920,7 @@ static const pm_unicode_codepoint_t unicode_alnum_codepoints[UNICODE_ALNUM_CODEP
0xCC6, 0xCC8,
0xCCA, 0xCCC,
0xCD5, 0xCD6,
- 0xCDD, 0xCDE,
+ 0xCDC, 0xCDE,
0xCE0, 0xCE3,
0xCE6, 0xCEF,
0xCF1, 0xCF3,
@@ -1007,7 +1042,7 @@ static const pm_unicode_codepoint_t unicode_alnum_codepoints[UNICODE_ALNUM_CODEP
0x1C00, 0x1C36,
0x1C40, 0x1C49,
0x1C4D, 0x1C7D,
- 0x1C80, 0x1C88,
+ 0x1C80, 0x1C8A,
0x1C90, 0x1CBA,
0x1CBD, 0x1CBF,
0x1CE9, 0x1CEC,
@@ -1015,7 +1050,7 @@ static const pm_unicode_codepoint_t unicode_alnum_codepoints[UNICODE_ALNUM_CODEP
0x1CF5, 0x1CF6,
0x1CFA, 0x1CFA,
0x1D00, 0x1DBF,
- 0x1DE7, 0x1DF4,
+ 0x1DD3, 0x1DF4,
0x1E00, 0x1F15,
0x1F18, 0x1F1D,
0x1F20, 0x1F45,
@@ -1094,11 +1129,8 @@ static const pm_unicode_codepoint_t unicode_alnum_codepoints[UNICODE_ALNUM_CODEP
0xA67F, 0xA6EF,
0xA717, 0xA71F,
0xA722, 0xA788,
- 0xA78B, 0xA7CA,
- 0xA7D0, 0xA7D1,
- 0xA7D3, 0xA7D3,
- 0xA7D5, 0xA7D9,
- 0xA7F2, 0xA805,
+ 0xA78B, 0xA7DC,
+ 0xA7F1, 0xA805,
0xA807, 0xA827,
0xA840, 0xA873,
0xA880, 0xA8C3,
@@ -1191,6 +1223,7 @@ static const pm_unicode_codepoint_t unicode_alnum_codepoints[UNICODE_ALNUM_CODEP
0x105A3, 0x105B1,
0x105B3, 0x105B9,
0x105BB, 0x105BC,
+ 0x105C0, 0x105F3,
0x10600, 0x10736,
0x10740, 0x10755,
0x10760, 0x10767,
@@ -1209,6 +1242,7 @@ static const pm_unicode_codepoint_t unicode_alnum_codepoints[UNICODE_ALNUM_CODEP
0x108F4, 0x108F5,
0x10900, 0x10915,
0x10920, 0x10939,
+ 0x10940, 0x10959,
0x10980, 0x109B7,
0x109BE, 0x109BF,
0x10A00, 0x10A03,
@@ -1229,9 +1263,14 @@ static const pm_unicode_codepoint_t unicode_alnum_codepoints[UNICODE_ALNUM_CODEP
0x10CC0, 0x10CF2,
0x10D00, 0x10D27,
0x10D30, 0x10D39,
+ 0x10D40, 0x10D65,
+ 0x10D69, 0x10D69,
+ 0x10D6F, 0x10D85,
0x10E80, 0x10EA9,
0x10EAB, 0x10EAC,
0x10EB0, 0x10EB1,
+ 0x10EC2, 0x10EC7,
+ 0x10EFA, 0x10EFC,
0x10F00, 0x10F1C,
0x10F27, 0x10F27,
0x10F30, 0x10F45,
@@ -1278,6 +1317,17 @@ static const pm_unicode_codepoint_t unicode_alnum_codepoints[UNICODE_ALNUM_CODEP
0x11350, 0x11350,
0x11357, 0x11357,
0x1135D, 0x11363,
+ 0x11380, 0x11389,
+ 0x1138B, 0x1138B,
+ 0x1138E, 0x1138E,
+ 0x11390, 0x113B5,
+ 0x113B7, 0x113C0,
+ 0x113C2, 0x113C2,
+ 0x113C5, 0x113C5,
+ 0x113C7, 0x113CA,
+ 0x113CC, 0x113CD,
+ 0x113D1, 0x113D1,
+ 0x113D3, 0x113D3,
0x11400, 0x11441,
0x11443, 0x11445,
0x11447, 0x1144A,
@@ -1297,6 +1347,7 @@ static const pm_unicode_codepoint_t unicode_alnum_codepoints[UNICODE_ALNUM_CODEP
0x11680, 0x116B5,
0x116B8, 0x116B8,
0x116C0, 0x116C9,
+ 0x116D0, 0x116E3,
0x11700, 0x1171A,
0x1171D, 0x1172A,
0x11730, 0x11739,
@@ -1322,6 +1373,9 @@ static const pm_unicode_codepoint_t unicode_alnum_codepoints[UNICODE_ALNUM_CODEP
0x11A50, 0x11A97,
0x11A9D, 0x11A9D,
0x11AB0, 0x11AF8,
+ 0x11B60, 0x11B67,
+ 0x11BC0, 0x11BE0,
+ 0x11BF0, 0x11BF9,
0x11C00, 0x11C08,
0x11C0A, 0x11C36,
0x11C38, 0x11C3E,
@@ -1346,6 +1400,8 @@ static const pm_unicode_codepoint_t unicode_alnum_codepoints[UNICODE_ALNUM_CODEP
0x11D93, 0x11D96,
0x11D98, 0x11D98,
0x11DA0, 0x11DA9,
+ 0x11DB0, 0x11DDB,
+ 0x11DE0, 0x11DE9,
0x11EE0, 0x11EF6,
0x11F00, 0x11F10,
0x11F12, 0x11F3A,
@@ -1358,7 +1414,10 @@ static const pm_unicode_codepoint_t unicode_alnum_codepoints[UNICODE_ALNUM_CODEP
0x12F90, 0x12FF0,
0x13000, 0x1342F,
0x13441, 0x13446,
+ 0x13460, 0x143FA,
0x14400, 0x14646,
+ 0x16100, 0x1612E,
+ 0x16130, 0x16139,
0x16800, 0x16A38,
0x16A40, 0x16A5E,
0x16A60, 0x16A69,
@@ -1370,16 +1429,20 @@ static const pm_unicode_codepoint_t unicode_alnum_codepoints[UNICODE_ALNUM_CODEP
0x16B50, 0x16B59,
0x16B63, 0x16B77,
0x16B7D, 0x16B8F,
+ 0x16D40, 0x16D6C,
+ 0x16D70, 0x16D79,
0x16E40, 0x16E7F,
+ 0x16EA0, 0x16EB8,
+ 0x16EBB, 0x16ED3,
0x16F00, 0x16F4A,
0x16F4F, 0x16F87,
0x16F8F, 0x16F9F,
0x16FE0, 0x16FE1,
0x16FE3, 0x16FE3,
- 0x16FF0, 0x16FF1,
- 0x17000, 0x187F7,
- 0x18800, 0x18CD5,
- 0x18D00, 0x18D08,
+ 0x16FF0, 0x16FF6,
+ 0x17000, 0x18CD5,
+ 0x18CFF, 0x18D1E,
+ 0x18D80, 0x18DF2,
0x1AFF0, 0x1AFF3,
0x1AFF5, 0x1AFFB,
0x1AFFD, 0x1AFFE,
@@ -1394,6 +1457,7 @@ static const pm_unicode_codepoint_t unicode_alnum_codepoints[UNICODE_ALNUM_CODEP
0x1BC80, 0x1BC88,
0x1BC90, 0x1BC99,
0x1BC9E, 0x1BC9E,
+ 0x1CCF0, 0x1CCF9,
0x1D400, 0x1D454,
0x1D456, 0x1D49C,
0x1D49E, 0x1D49F,
@@ -1443,6 +1507,11 @@ static const pm_unicode_codepoint_t unicode_alnum_codepoints[UNICODE_ALNUM_CODEP
0x1E2F0, 0x1E2F9,
0x1E4D0, 0x1E4EB,
0x1E4F0, 0x1E4F9,
+ 0x1E5D0, 0x1E5ED,
+ 0x1E5F0, 0x1E5FA,
+ 0x1E6C0, 0x1E6DE,
+ 0x1E6E0, 0x1E6F5,
+ 0x1E6FE, 0x1E6FF,
0x1E7E0, 0x1E7E6,
0x1E7E8, 0x1E7EB,
0x1E7ED, 0x1E7EE,
@@ -1490,16 +1559,16 @@ static const pm_unicode_codepoint_t unicode_alnum_codepoints[UNICODE_ALNUM_CODEP
0x1F170, 0x1F189,
0x1FBF0, 0x1FBF9,
0x20000, 0x2A6DF,
- 0x2A700, 0x2B739,
- 0x2B740, 0x2B81D,
- 0x2B820, 0x2CEA1,
+ 0x2A700, 0x2B81D,
+ 0x2B820, 0x2CEAD,
0x2CEB0, 0x2EBE0,
+ 0x2EBF0, 0x2EE5D,
0x2F800, 0x2FA1D,
0x30000, 0x3134A,
- 0x31350, 0x323AF,
+ 0x31350, 0x33479,
};
-#define UNICODE_ISUPPER_CODEPOINTS_LENGTH 1302
+#define UNICODE_ISUPPER_CODEPOINTS_LENGTH 1320
static const pm_unicode_codepoint_t unicode_isupper_codepoints[UNICODE_ISUPPER_CODEPOINTS_LENGTH] = {
0x100, 0x100,
0x102, 0x102,
@@ -1774,6 +1843,7 @@ static const pm_unicode_codepoint_t unicode_isupper_codepoints[UNICODE_ISUPPER_C
0x10C7, 0x10C7,
0x10CD, 0x10CD,
0x13A0, 0x13F5,
+ 0x1C89, 0x1C89,
0x1C90, 0x1CBA,
0x1CBD, 0x1CBF,
0x1E00, 0x1E00,
@@ -2103,9 +2173,15 @@ static const pm_unicode_codepoint_t unicode_isupper_codepoints[UNICODE_ISUPPER_C
0xA7C2, 0xA7C2,
0xA7C4, 0xA7C7,
0xA7C9, 0xA7C9,
+ 0xA7CB, 0xA7CC,
+ 0xA7CE, 0xA7CE,
0xA7D0, 0xA7D0,
+ 0xA7D2, 0xA7D2,
+ 0xA7D4, 0xA7D4,
0xA7D6, 0xA7D6,
0xA7D8, 0xA7D8,
+ 0xA7DA, 0xA7DA,
+ 0xA7DC, 0xA7DC,
0xA7F5, 0xA7F5,
0xFF21, 0xFF3A,
0x10400, 0x10427,
@@ -2115,8 +2191,10 @@ static const pm_unicode_codepoint_t unicode_isupper_codepoints[UNICODE_ISUPPER_C
0x1058C, 0x10592,
0x10594, 0x10595,
0x10C80, 0x10CB2,
+ 0x10D50, 0x10D65,
0x118A0, 0x118BF,
0x16E40, 0x16E5F,
+ 0x16EA0, 0x16EB8,
0x1D400, 0x1D419,
0x1D434, 0x1D44D,
0x1D468, 0x1D481,
@@ -2304,6 +2382,10 @@ pm_encoding_utf_8_char_width(const uint8_t *b, ptrdiff_t n) {
*/
size_t
pm_encoding_utf_8_alpha_char(const uint8_t *b, ptrdiff_t n) {
+ if (n == 0) {
+ return 0;
+ }
+
if (*b < 0x80) {
return (pm_encoding_unicode_table[*b] & PRISM_ENCODING_ALPHABETIC_BIT) ? 1 : 0;
}
@@ -2324,6 +2406,10 @@ pm_encoding_utf_8_alpha_char(const uint8_t *b, ptrdiff_t n) {
*/
size_t
pm_encoding_utf_8_alnum_char(const uint8_t *b, ptrdiff_t n) {
+ if (n == 0) {
+ return 0;
+ }
+
if (*b < 0x80) {
return (pm_encoding_unicode_table[*b] & (PRISM_ENCODING_ALPHANUMERIC_BIT)) ? 1 : 0;
}
@@ -2344,6 +2430,10 @@ pm_encoding_utf_8_alnum_char(const uint8_t *b, ptrdiff_t n) {
*/
bool
pm_encoding_utf_8_isupper_char(const uint8_t *b, ptrdiff_t n) {
+ if (n == 0) {
+ return 0;
+ }
+
if (*b < 0x80) {
return (pm_encoding_unicode_table[*b] & PRISM_ENCODING_UPPERCASE_BIT) ? true : false;
}
@@ -2362,7 +2452,8 @@ pm_encoding_utf_8_isupper_char(const uint8_t *b, ptrdiff_t n) {
static pm_unicode_codepoint_t
pm_cesu_8_codepoint(const uint8_t *b, ptrdiff_t n, size_t *width) {
- if (b[0] < 0x80) {
+
+ if ((n > 0) && (b[0] < 0x80)) {
*width = 1;
return (pm_unicode_codepoint_t) b[0];
}
@@ -2401,6 +2492,10 @@ pm_cesu_8_codepoint(const uint8_t *b, ptrdiff_t n, size_t *width) {
static size_t
pm_encoding_cesu_8_char_width(const uint8_t *b, ptrdiff_t n) {
+ if (n == 0) {
+ return 0;
+ }
+
size_t width;
pm_cesu_8_codepoint(b, n, &width);
return width;
@@ -2408,6 +2503,10 @@ pm_encoding_cesu_8_char_width(const uint8_t *b, ptrdiff_t n) {
static size_t
pm_encoding_cesu_8_alpha_char(const uint8_t *b, ptrdiff_t n) {
+ if (n == 0) {
+ return 0;
+ }
+
if (*b < 0x80) {
return (pm_encoding_unicode_table[*b] & PRISM_ENCODING_ALPHABETIC_BIT) ? 1 : 0;
}
@@ -2424,6 +2523,10 @@ pm_encoding_cesu_8_alpha_char(const uint8_t *b, ptrdiff_t n) {
static size_t
pm_encoding_cesu_8_alnum_char(const uint8_t *b, ptrdiff_t n) {
+ if (n == 0) {
+ return 0;
+ }
+
if (*b < 0x80) {
return (pm_encoding_unicode_table[*b] & (PRISM_ENCODING_ALPHANUMERIC_BIT)) ? 1 : 0;
}
@@ -2440,6 +2543,10 @@ pm_encoding_cesu_8_alnum_char(const uint8_t *b, ptrdiff_t n) {
static bool
pm_encoding_cesu_8_isupper_char(const uint8_t *b, ptrdiff_t n) {
+ if (n == 0) {
+ return 0;
+ }
+
if (*b < 0x80) {
return (pm_encoding_unicode_table[*b] & PRISM_ENCODING_UPPERCASE_BIT) ? true : false;
}
@@ -3855,14 +3962,14 @@ static const uint8_t pm_encoding_windows_874_table[256] = {
};
#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 ## _alpha_char(const uint8_t *b, ptrdiff_t n) { \
+ return ((n > 0) && (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 size_t pm_encoding_ ##name ## _alnum_char(const uint8_t *b, ptrdiff_t n) { \
+ return ((n > 0) && (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); \
+ static bool pm_encoding_ ##name ## _isupper_char(const uint8_t *b, ptrdiff_t n) { \
+ return ((n > 0) && (pm_encoding_ ##name ## _table[*b] & PRISM_ENCODING_UPPERCASE_BIT)); \
}
PRISM_ENCODING_TABLE(cp850)
@@ -3931,8 +4038,8 @@ PRISM_ENCODING_TABLE(windows_874)
* 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;
+pm_encoding_ascii_char_width(const uint8_t *b, ptrdiff_t n) {
+ return ((n > 0) && (*b < 0x80)) ? 1 : 0;
}
/**
@@ -3940,8 +4047,8 @@ pm_encoding_ascii_char_width(const uint8_t *b, PRISM_ATTRIBUTE_UNUSED ptrdiff_t
* 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);
+pm_encoding_ascii_alpha_char(const uint8_t *b, ptrdiff_t n) {
+ return (n > 0) ? (pm_encoding_ascii_table[*b] & PRISM_ENCODING_ALPHABETIC_BIT) : 0;
}
/**
@@ -3951,7 +4058,7 @@ pm_encoding_ascii_alpha_char(const uint8_t *b, PRISM_ATTRIBUTE_UNUSED ptrdiff_t
*/
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 ((n > 0) && (*b < 0x80)) ? pm_encoding_ascii_alpha_char(b, n) : 0;
}
/**
@@ -3959,8 +4066,8 @@ pm_encoding_ascii_alpha_char_7bit(const uint8_t *b, ptrdiff_t n) {
* 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;
+pm_encoding_ascii_alnum_char(const uint8_t *b, ptrdiff_t n) {
+ return ((n > 0) && (pm_encoding_ascii_table[*b] & PRISM_ENCODING_ALPHANUMERIC_BIT)) ? 1 : 0;
}
/**
@@ -3970,7 +4077,7 @@ pm_encoding_ascii_alnum_char(const uint8_t *b, PRISM_ATTRIBUTE_UNUSED ptrdiff_t
*/
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 ((n > 0) && (*b < 0x80)) ? pm_encoding_ascii_alnum_char(b, n) : 0;
}
/**
@@ -3978,8 +4085,8 @@ pm_encoding_ascii_alnum_char_7bit(const uint8_t *b, ptrdiff_t n) {
* 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);
+pm_encoding_ascii_isupper_char(const uint8_t *b, ptrdiff_t n) {
+ return (n > 0) && (pm_encoding_ascii_table[*b] & PRISM_ENCODING_UPPERCASE_BIT);
}
/**
@@ -3987,7 +4094,7 @@ pm_encoding_ascii_isupper_char(const uint8_t *b, PRISM_ATTRIBUTE_UNUSED ptrdiff_
* 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) {
+pm_encoding_single_char_width(PRISM_UNUSED const uint8_t *b, PRISM_UNUSED ptrdiff_t n) {
return 1;
}
@@ -3998,7 +4105,7 @@ pm_encoding_single_char_width(PRISM_ATTRIBUTE_UNUSED const uint8_t *b, PRISM_ATT
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) {
+ if ((n > 0) && (*b < 0x80)) {
return 1;
}
@@ -4042,6 +4149,9 @@ pm_encoding_euc_jp_isupper_char(const uint8_t *b, ptrdiff_t n) {
*/
static size_t
pm_encoding_shift_jis_char_width(const uint8_t *b, ptrdiff_t n) {
+ if (n == 0) {
+ return 0;
+ }
// These are the single byte characters.
if (b[0] < 0x80 || (b[0] >= 0xA1 && b[0] <= 0xDF)) {
return 1;
@@ -4105,7 +4215,7 @@ pm_encoding_shift_jis_isupper_char(const uint8_t *b, ptrdiff_t n) {
*/
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);
+ return (n > 0) && (*b < 0x80) && pm_encoding_ascii_isupper_char(b, n);
}
/**
@@ -4115,7 +4225,7 @@ pm_encoding_ascii_isupper_char_7bit(const uint8_t *b, ptrdiff_t n) {
static size_t
pm_encoding_big5_char_width(const uint8_t *b, ptrdiff_t n) {
// These are the single byte characters.
- if (*b < 0x80) {
+ if ((n > 0) && (*b < 0x80)) {
return 1;
}
@@ -4134,7 +4244,7 @@ pm_encoding_big5_char_width(const uint8_t *b, ptrdiff_t n) {
static size_t
pm_encoding_cp949_char_width(const uint8_t *b, ptrdiff_t n) {
// These are the single byte characters
- if (*b <= 0x80) {
+ if ((n > 0) && (*b <= 0x80)) {
return 1;
}
@@ -4153,7 +4263,7 @@ pm_encoding_cp949_char_width(const uint8_t *b, ptrdiff_t n) {
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) {
+ if ((n > 0) && (*b < 0x80)) {
return 1;
}
@@ -4196,7 +4306,7 @@ pm_encoding_emacs_mule_char_width(const uint8_t *b, ptrdiff_t n) {
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) {
+ if ((n > 0) && (*b < 0x80)) {
return 1;
}
@@ -4215,7 +4325,7 @@ pm_encoding_euc_kr_char_width(const uint8_t *b, ptrdiff_t n) {
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) {
+ if ((n > 0) && (*b < 0x80)) {
return 1;
}
@@ -4239,7 +4349,7 @@ pm_encoding_euc_tw_char_width(const uint8_t *b, ptrdiff_t n) {
static size_t
pm_encoding_gb18030_char_width(const uint8_t *b, ptrdiff_t n) {
// These are the 1 byte characters.
- if (*b < 0x80) {
+ if ((n > 0) && (*b < 0x80)) {
return 1;
}
@@ -4263,7 +4373,7 @@ pm_encoding_gb18030_char_width(const uint8_t *b, ptrdiff_t n) {
static size_t
pm_encoding_gbk_char_width(const uint8_t *b, ptrdiff_t n) {
// These are the single byte characters.
- if (*b <= 0x80) {
+ if ((n > 0) && (*b <= 0x80)) {
return 1;
}
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/excludes.h b/prism/excludes.h
new file mode 100644
index 0000000000..8600622f63
--- /dev/null
+++ b/prism/excludes.h
@@ -0,0 +1,29 @@
+/**
+ * @file excludes.h
+ *
+ * A header file that defines macros to exclude certain features of the prism
+ * library. This is useful for reducing the size of the library when certain
+ * features are not needed.
+ */
+#ifndef PRISM_EXCLUDES_H
+#define PRISM_EXCLUDES_H
+
+/**
+ * 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 prettyprint API. */
+ #define PRISM_EXCLUDE_PRETTYPRINT
+
+ /** Exclude the full set of encodings, using the minimal only. */
+ #define PRISM_ENCODING_EXCLUDE_FULL
+#endif
+
+#endif
diff --git a/prism/extension.c b/prism/extension.c
index 83415d0c29..27df8dac50 100644
--- a/prism/extension.c
+++ b/prism/extension.c
@@ -4,6 +4,8 @@
#include <ruby/win32.h>
#endif
+#include <errno.h>
+
// NOTE: this file should contain only bindings. All non-trivial logic should be
// in libprism so it can be shared its the various callers.
@@ -25,6 +27,7 @@ VALUE rb_cPrismLexResult;
VALUE rb_cPrismParseLexResult;
VALUE rb_cPrismStringQuery;
VALUE rb_cPrismScope;
+VALUE rb_cPrismCurrentVersionError;
VALUE rb_cPrismDebugEncoding;
@@ -63,18 +66,6 @@ check_string(VALUE value) {
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 */
@@ -147,10 +138,8 @@ build_options_scopes(pm_options_t *options, VALUE scopes) {
// Initialize the scope array.
size_t locals_count = RARRAY_LEN(locals);
- 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");
- }
+ pm_options_scope_t *options_scope = pm_options_scope_mut(options, scope_index);
+ pm_options_scope_init(options_scope, locals_count);
// Iterate over the locals and add them to the scope.
for (size_t local_index = 0; local_index < locals_count; local_index++) {
@@ -163,7 +152,7 @@ build_options_scopes(pm_options_t *options, VALUE scopes) {
}
// Add the local to the scope.
- pm_string_t *scope_local = &options_scope->locals[local_index];
+ pm_string_t *scope_local = pm_options_scope_local_mut(options_scope, local_index);
const char *name = rb_id2name(SYM2ID(local));
pm_string_constant_init(scope_local, name, strlen(name));
}
@@ -199,7 +188,21 @@ build_options_i(VALUE key, VALUE value, VALUE argument) {
if (!NIL_P(value)) {
const char *version = check_string(value);
- if (!pm_options_version_set(options, version, RSTRING_LEN(value))) {
+ if (RSTRING_LEN(value) == 7 && strncmp(version, "current", 7) == 0) {
+ if (!pm_options_version_set(options, ruby_version, 3)) {
+ rb_exc_raise(rb_exc_new_cstr(rb_cPrismCurrentVersionError, ruby_version));
+ }
+ } else if (RSTRING_LEN(value) == 7 && strncmp(version, "nearest", 7) == 0) {
+ if (!pm_options_version_set(options, ruby_version, 3)) {
+ // Prism doesn't know this specific version. Is it lower?
+ if (ruby_version[0] < '3' || (ruby_version[0] == '3' && ruby_version[2] < '3')) {
+ pm_options_version_set_lowest(options);
+ } else {
+ // Must be higher.
+ pm_options_version_set_highest(options);
+ }
+ }
+ } else if (!pm_options_version_set(options, version, RSTRING_LEN(value))) {
rb_raise(rb_eArgError, "invalid version: %" PRIsVALUE, value);
}
}
@@ -263,7 +266,7 @@ build_options(VALUE argument) {
*/
static void
extract_options(pm_options_t *options, VALUE filepath, VALUE keywords) {
- options->line = 1; // default
+ pm_options_line_set(options, 1); /* default */
if (!NIL_P(keywords)) {
struct build_options_data data = { .options = options, .keywords = keywords };
@@ -291,36 +294,46 @@ extract_options(pm_options_t *options, VALUE filepath, VALUE keywords) {
/**
* 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) {
+static VALUE
+string_options(int argc, VALUE *argv, pm_options_t *options) {
VALUE string;
VALUE keywords;
rb_scan_args(argc, argv, "1:", &string, &keywords);
+ if (!RB_TYPE_P(string, T_STRING)) {
+ pm_options_free(options);
+ rb_raise(rb_eTypeError, "wrong argument type %"PRIsVALUE" (expected String)", rb_obj_class(string));
+ }
+
extract_options(options, Qnil, keywords);
- input_load_string(input, string);
+ return 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) {
+static pm_source_t *
+file_options(int argc, VALUE *argv, pm_options_t *options, VALUE *encoded_filepath) {
VALUE filepath;
VALUE keywords;
rb_scan_args(argc, argv, "1:", &filepath, &keywords);
- Check_Type(filepath, T_STRING);
+ 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));
+ }
+
*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;
+ const char *source = (const char *) pm_string_source(pm_options_filepath(options));
+ pm_source_init_result_t result;
+ pm_source_t *pm_src = pm_source_file_new(source, &result);
- switch (result = pm_string_file_init(input, source)) {
- case PM_STRING_INIT_SUCCESS:
+ switch (result) {
+ case PM_SOURCE_INIT_SUCCESS:
break;
- case PM_STRING_INIT_ERROR_GENERIC: {
+ case PM_SOURCE_INIT_ERROR_GENERIC: {
pm_options_free(options);
#ifdef _WIN32
@@ -332,7 +345,7 @@ file_options(int argc, VALUE *argv, pm_string_t *input, pm_options_t *options, V
rb_syserr_fail(e, source);
break;
}
- case PM_STRING_INIT_ERROR_DIRECTORY:
+ case PM_SOURCE_INIT_ERROR_DIRECTORY:
pm_options_free(options);
rb_syserr_fail(EISDIR, source);
break;
@@ -341,6 +354,8 @@ file_options(int argc, VALUE *argv, pm_string_t *input, pm_options_t *options, V
rb_raise(rb_eRuntimeError, "Unknown error (%d) initializing file: %s", result, source);
break;
}
+
+ return pm_src;
}
#ifndef PRISM_EXCLUDE_SERIALIZATION
@@ -353,77 +368,82 @@ file_options(int argc, VALUE *argv, pm_string_t *input, pm_options_t *options, V
* 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)) {
+dump_input(const uint8_t *input, size_t input_length, const pm_options_t *options) {
+ pm_buffer_t *buffer = pm_buffer_new();
+ if (!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_arena_t *arena = pm_arena_new();
+ pm_parser_t *parser = pm_parser_new(arena, input, input_length, options);
- pm_node_t *node = pm_parse(&parser);
- pm_serialize(&parser, node, &buffer);
+ 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);
+ VALUE result = rb_str_new(pm_buffer_value(buffer), pm_buffer_length(buffer));
+ pm_buffer_free(buffer);
+ pm_parser_free(parser);
+ pm_arena_free(arena);
return result;
}
/**
+ * :markup: markdown
* call-seq:
- * Prism::dump(source, **options) -> String
+ * dump(source, **options) -> String
*
* Dump the AST corresponding to the given string to a string. For supported
- * options, see Prism::parse.
+ * 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);
+ pm_options_t *options = pm_options_new();
+ VALUE string = string_options(argc, argv, options);
+
+ const uint8_t *source = (const uint8_t *) RSTRING_PTR(string);
+ size_t length = RSTRING_LEN(string);
#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);
+ memcpy(dup, source, length);
+ source = (const uint8_t *) dup;
#endif
- VALUE value = dump_input(&input, &options);
- if (options.freeze) rb_obj_freeze(value);
+ VALUE value = dump_input(source, length, options);
+ if (pm_options_freeze(options)) rb_obj_freeze(value);
#ifdef PRISM_BUILD_DEBUG
+#ifdef xfree_sized
+ xfree_sized(dup, length);
+#else
xfree(dup);
#endif
+#endif
- pm_string_free(&input);
- pm_options_free(&options);
+ pm_options_free(options);
return value;
}
/**
+ * :markup: markdown
* call-seq:
- * Prism::dump_file(filepath, **options) -> String
+ * dump_file(filepath, **options) -> String
*
* Dump the AST corresponding to the given file to a string. For supported
- * options, see Prism::parse.
+ * options, see Prism.parse.
*/
static VALUE
dump_file(int argc, VALUE *argv, VALUE self) {
- pm_string_t input;
- pm_options_t options = { 0 };
+ pm_options_t *options = pm_options_new();
VALUE encoded_filepath;
- file_options(argc, argv, &input, &options, &encoded_filepath);
+ pm_source_t *src = file_options(argc, argv, options, &encoded_filepath);
- VALUE value = dump_input(&input, &options);
- pm_string_free(&input);
- pm_options_free(&options);
+ VALUE value = dump_input(pm_source_source(src), pm_source_length(src), options);
+ pm_source_free(src);
+ pm_options_free(options);
return value;
}
@@ -449,42 +469,49 @@ rb_class_new_instance_freeze(int argc, const VALUE *argv, VALUE klass, bool free
* Create a new Location instance from the given parser and bounds.
*/
static inline VALUE
-parser_location(const pm_parser_t *parser, VALUE source, bool freeze, const uint8_t *start, size_t length) {
- VALUE argv[] = { source, LONG2FIX(start - parser->start), LONG2FIX(length) };
+parser_location(VALUE source, bool freeze, uint32_t start, uint32_t length) {
+ VALUE argv[] = { source, LONG2FIX(start), LONG2FIX(length) };
return rb_class_new_instance_freeze(3, argv, rb_cPrismLocation, freeze);
}
/**
* Create a new Location instance from the given parser and location.
*/
-#define PARSER_LOCATION_LOC(parser, source, freeze, loc) \
- parser_location(parser, source, freeze, loc.start, (size_t) (loc.end - loc.start))
+#define PARSER_LOCATION(source, freeze, location) \
+ parser_location(source, freeze, location.start, location.length)
/**
* Build a new Comment instance from the given parser and comment.
*/
static inline VALUE
-parser_comment(const pm_parser_t *parser, VALUE source, bool freeze, const pm_comment_t *comment) {
- VALUE argv[] = { PARSER_LOCATION_LOC(parser, source, freeze, comment->location) };
- VALUE type = (comment->type == PM_COMMENT_EMBDOC) ? rb_cPrismEmbDocComment : rb_cPrismInlineComment;
+parser_comment(VALUE source, bool freeze, const pm_comment_t *comment) {
+ VALUE argv[] = { PARSER_LOCATION(source, freeze, pm_comment_location(comment)) };
+ VALUE type = (pm_comment_type(comment) == PM_COMMENT_EMBDOC) ? rb_cPrismEmbDocComment : rb_cPrismInlineComment;
return rb_class_new_instance_freeze(1, argv, type, freeze);
}
+typedef struct {
+ VALUE comments;
+ VALUE source;
+ bool freeze;
+} parser_comments_each_data_t;
+
+static void
+parser_comments_each(const pm_comment_t *comment, void *data) {
+ parser_comments_each_data_t *each_data = (parser_comments_each_data_t *) data;
+ VALUE value = parser_comment(each_data->source, each_data->freeze, comment);
+ rb_ary_push(each_data->comments, value);
+}
+
/**
* Extract the comments out of the parser into an array.
*/
static VALUE
parser_comments(const pm_parser_t *parser, VALUE source, bool freeze) {
- VALUE comments = rb_ary_new_capa(parser->comment_list.size);
-
- for (
- const pm_comment_t *comment = (const pm_comment_t *) parser->comment_list.head;
- comment != NULL;
- comment = (const pm_comment_t *) comment->node.next
- ) {
- VALUE value = parser_comment(parser, source, freeze, comment);
- rb_ary_push(comments, value);
- }
+ VALUE comments = rb_ary_new_capa(pm_parser_comments_size(parser));
+
+ parser_comments_each_data_t each_data = { comments, source, freeze };
+ pm_parser_comments_each(parser, parser_comments_each, &each_data);
if (freeze) rb_obj_freeze(comments);
return comments;
@@ -494,28 +521,39 @@ parser_comments(const pm_parser_t *parser, VALUE source, bool freeze) {
* Build a new MagicComment instance from the given parser and magic comment.
*/
static inline VALUE
-parser_magic_comment(const pm_parser_t *parser, VALUE source, bool freeze, const pm_magic_comment_t *magic_comment) {
- VALUE key_loc = parser_location(parser, source, freeze, magic_comment->key_start, magic_comment->key_length);
- VALUE value_loc = parser_location(parser, source, freeze, magic_comment->value_start, magic_comment->value_length);
+parser_magic_comment(VALUE source, bool freeze, const pm_magic_comment_t *magic_comment) {
+ pm_location_t key = pm_magic_comment_key(magic_comment);
+ pm_location_t value = pm_magic_comment_value(magic_comment);
+
+ VALUE key_loc = parser_location(source, freeze, key.start, key.length);
+ VALUE value_loc = parser_location(source, freeze, value.start, value.length);
+
VALUE argv[] = { key_loc, value_loc };
return rb_class_new_instance_freeze(2, argv, rb_cPrismMagicComment, freeze);
}
+typedef struct {
+ VALUE magic_comments;
+ VALUE source;
+ bool freeze;
+} parser_magic_comments_each_data_t;
+
+static void
+parser_magic_comments_each(const pm_magic_comment_t *magic_comment, void *data) {
+ parser_magic_comments_each_data_t *each_data = (parser_magic_comments_each_data_t *) data;
+ VALUE value = parser_magic_comment(each_data->source, each_data->freeze, magic_comment);
+ rb_ary_push(each_data->magic_comments, value);
+}
+
/**
* Extract the magic comments out of the parser into an array.
*/
static VALUE
parser_magic_comments(const pm_parser_t *parser, VALUE source, bool freeze) {
- VALUE magic_comments = rb_ary_new_capa(parser->magic_comment_list.size);
-
- for (
- const pm_magic_comment_t *magic_comment = (const pm_magic_comment_t *) parser->magic_comment_list.head;
- magic_comment != NULL;
- magic_comment = (const pm_magic_comment_t *) magic_comment->node.next
- ) {
- VALUE value = parser_magic_comment(parser, source, freeze, magic_comment);
- rb_ary_push(magic_comments, value);
- }
+ VALUE magic_comments = rb_ary_new_capa(pm_parser_magic_comments_size(parser));
+
+ parser_magic_comments_each_data_t each_data = { magic_comments, source, freeze };
+ pm_parser_magic_comments_each(parser, parser_magic_comments_each, &each_data);
if (freeze) rb_obj_freeze(magic_comments);
return magic_comments;
@@ -527,11 +565,50 @@ parser_magic_comments(const pm_parser_t *parser, VALUE source, bool freeze) {
*/
static VALUE
parser_data_loc(const pm_parser_t *parser, VALUE source, bool freeze) {
- if (parser->data_loc.end == NULL) {
+ const pm_location_t *data_loc = pm_parser_data_loc(parser);
+
+ if (data_loc->length == 0) {
return Qnil;
} else {
- return PARSER_LOCATION_LOC(parser, source, freeze, parser->data_loc);
+ return parser_location(source, freeze, data_loc->start, data_loc->length);
+ }
+}
+
+typedef struct {
+ VALUE errors;
+ rb_encoding *encoding;
+ VALUE source;
+ bool freeze;
+} parser_errors_each_data_t;
+
+static void
+parser_errors_each(const pm_diagnostic_t *diagnostic, void *data) {
+ parser_errors_each_data_t *each_data = (parser_errors_each_data_t *) data;
+
+ VALUE type = ID2SYM(rb_intern(pm_diagnostic_type(diagnostic)));
+ VALUE message = rb_obj_freeze(rb_enc_str_new_cstr(pm_diagnostic_message(diagnostic), each_data->encoding));
+ VALUE location = PARSER_LOCATION(each_data->source, each_data->freeze, pm_diagnostic_location(diagnostic));
+
+ pm_error_level_t error_level = pm_diagnostic_error_level(diagnostic);
+ 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 argv[] = { type, message, location, level };
+ VALUE value = rb_class_new_instance_freeze(4, argv, rb_cPrismParseError, each_data->freeze);
+ rb_ary_push(each_data->errors, value);
}
/**
@@ -539,73 +616,58 @@ parser_data_loc(const pm_parser_t *parser, VALUE source, bool freeze) {
*/
static VALUE
parser_errors(const pm_parser_t *parser, rb_encoding *encoding, VALUE source, bool freeze) {
- VALUE errors = rb_ary_new_capa(parser->error_list.size);
-
- for (
- const pm_diagnostic_t *error = (const pm_diagnostic_t *) parser->error_list.head;
- error != NULL;
- error = (const pm_diagnostic_t *) error->node.next
- ) {
- VALUE type = ID2SYM(rb_intern(pm_diagnostic_id_human(error->diag_id)));
- VALUE message = rb_obj_freeze(rb_enc_str_new_cstr(error->message, encoding));
- VALUE location = PARSER_LOCATION_LOC(parser, source, freeze, error->location);
-
- 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 errors = rb_ary_new_capa(pm_parser_errors_size(parser));
- VALUE argv[] = { type, message, location, level };
- VALUE value = rb_class_new_instance_freeze(4, argv, rb_cPrismParseError, freeze);
- rb_ary_push(errors, value);
- }
+ parser_errors_each_data_t each_data = { errors, encoding, source, freeze };
+ pm_parser_errors_each(parser, parser_errors_each, &each_data);
if (freeze) rb_obj_freeze(errors);
return errors;
}
+typedef struct {
+ VALUE warnings;
+ rb_encoding *encoding;
+ VALUE source;
+ bool freeze;
+} parser_warnings_each_data_t;
+
+static void
+parser_warnings_each(const pm_diagnostic_t *diagnostic, void *data) {
+ parser_warnings_each_data_t *each_data = (parser_warnings_each_data_t *) data;
+
+ VALUE type = ID2SYM(rb_intern(pm_diagnostic_type(diagnostic)));
+ VALUE message = rb_obj_freeze(rb_enc_str_new_cstr(pm_diagnostic_message(diagnostic), each_data->encoding));
+ VALUE location = PARSER_LOCATION(each_data->source, each_data->freeze, pm_diagnostic_location(diagnostic));
+
+ pm_warning_level_t warning_level = pm_diagnostic_warning_level(diagnostic);
+ 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 argv[] = { type, message, location, level };
+ VALUE value = rb_class_new_instance_freeze(4, argv, rb_cPrismParseWarning, each_data->freeze);
+ rb_ary_push(each_data->warnings, value);
+}
+
/**
* Extract the warnings out of the parser into an array.
*/
static VALUE
parser_warnings(const pm_parser_t *parser, rb_encoding *encoding, VALUE source, bool freeze) {
- VALUE warnings = rb_ary_new_capa(parser->warning_list.size);
-
- for (
- const pm_diagnostic_t *warning = (const pm_diagnostic_t *) parser->warning_list.head;
- warning != NULL;
- warning = (const pm_diagnostic_t *) warning->node.next
- ) {
- VALUE type = ID2SYM(rb_intern(pm_diagnostic_id_human(warning->diag_id)));
- VALUE message = rb_obj_freeze(rb_enc_str_new_cstr(warning->message, encoding));
- VALUE location = PARSER_LOCATION_LOC(parser, source, freeze, warning->location);
-
- 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 warnings = rb_ary_new_capa(pm_parser_warnings_size(parser));
- VALUE argv[] = { type, message, location, level };
- VALUE value = rb_class_new_instance_freeze(4, argv, rb_cPrismParseWarning, freeze);
- rb_ary_push(warnings, value);
- }
+ parser_warnings_each_data_t each_data = { warnings, encoding, source, freeze };
+ pm_parser_warnings_each(parser, parser_warnings_each, &each_data);
if (freeze) rb_obj_freeze(warnings);
return warnings;
@@ -623,10 +685,11 @@ parse_result_create(VALUE class, const pm_parser_t *parser, VALUE value, rb_enco
parser_data_loc(parser, source, freeze),
parser_errors(parser, encoding, source, freeze),
parser_warnings(parser, encoding, source, freeze),
+ pm_parser_continuable(parser) ? Qtrue : Qfalse,
source
};
- return rb_class_new_instance_freeze(7, result_argv, class, freeze);
+ return rb_class_new_instance_freeze(8, result_argv, class, freeze);
}
/******************************************************************************/
@@ -651,11 +714,11 @@ typedef struct {
* 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;
+parse_lex_token(pm_parser_t *parser, pm_token_t *token, void *data) {
+ parse_lex_data_t *parse_lex_data = (parse_lex_data_t *) data;
VALUE value = pm_token_new(parser, token, parse_lex_data->encoding, parse_lex_data->source, parse_lex_data->freeze);
- VALUE yields = rb_assoc_new(value, INT2FIX(parser->lex_state));
+ VALUE yields = rb_assoc_new(value, INT2FIX(pm_parser_lex_state(parser)));
if (parse_lex_data->freeze) {
rb_obj_freeze(value);
@@ -672,8 +735,8 @@ parse_lex_token(void *data, pm_parser_t *parser, pm_token_t *token) {
*/
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);
+ parse_lex_data_t *parse_lex_data = (parse_lex_data_t *) pm_parser_lex_callback_data(parser);
+ parse_lex_data->encoding = rb_enc_find(pm_parser_encoding_name(parser));
// 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
@@ -718,43 +781,38 @@ parse_lex_encoding_changed_callback(pm_parser_t *parser) {
* 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);
+parse_lex_input(const uint8_t *input, size_t input_length, const pm_options_t *options, bool return_nodes) {
+ pm_arena_t *arena = pm_arena_new();
+ pm_parser_t *parser = pm_parser_new(arena, input, input_length, options);
+ pm_parser_encoding_changed_callback_set(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);
+ VALUE source_string = rb_str_new((const char *) input, input_length);
+ VALUE offsets = rb_ary_new_capa(pm_parser_line_offsets(parser)->size);
+ VALUE source = rb_funcall(rb_cPrismSource, rb_id_source_for, 3, source_string, LONG2NUM(pm_parser_start_line(parser)), offsets);
parse_lex_data_t parse_lex_data = {
.source = source,
.tokens = rb_ary_new(),
- .encoding = rb_utf8_encoding(),
- .freeze = options->freeze,
+ .encoding = rb_enc_find(pm_parser_encoding_name(parser)),
+ .freeze = pm_options_freeze(options),
};
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,
- };
+ pm_parser_lex_callback_set(parser, parse_lex_token, data);
- parser.lex_callback = &lex_callback;
- pm_node_t *node = pm_parse(&parser);
+ 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);
+ /* Update the Source object with the correct encoding and line offsets,
+ * which are only available after pm_parse() completes. */
+ rb_encoding *encoding = rb_enc_find(pm_parser_encoding_name(parser));
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]));
+ const pm_line_offset_list_t *line_offsets = pm_parser_line_offsets(parser);
+ for (size_t index = 0; index < line_offsets->size; index++) {
+ rb_ary_store(offsets, (long) index, ULONG2NUM(line_offsets->offsets[index]));
}
- if (options->freeze) {
+ if (pm_options_freeze(options)) {
rb_obj_freeze(source_string);
rb_obj_freeze(offsets);
rb_obj_freeze(source);
@@ -764,58 +822,57 @@ parse_lex_input(pm_string_t *input, const pm_options_t *options, bool return_nod
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, options->freeze));
+ rb_ary_push(value, pm_ast_new(parser, node, parse_lex_data.encoding, source, pm_options_freeze(options)));
rb_ary_push(value, parse_lex_data.tokens);
- if (options->freeze) rb_obj_freeze(value);
- result = parse_result_create(rb_cPrismParseLexResult, &parser, value, parse_lex_data.encoding, source, options->freeze);
+ if (pm_options_freeze(options)) rb_obj_freeze(value);
+ result = parse_result_create(rb_cPrismParseLexResult, parser, value, parse_lex_data.encoding, source, pm_options_freeze(options));
} else {
- result = parse_result_create(rb_cPrismLexResult, &parser, parse_lex_data.tokens, parse_lex_data.encoding, source, options->freeze);
+ result = parse_result_create(rb_cPrismLexResult, parser, parse_lex_data.tokens, parse_lex_data.encoding, source, pm_options_freeze(options));
}
- pm_node_destroy(&parser, node);
- pm_parser_free(&parser);
+ pm_parser_free(parser);
+ pm_arena_free(arena);
return result;
}
/**
+ * :markup: markdown
* call-seq:
- * Prism::lex(source, **options) -> LexResult
+ * 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.
+ * 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);
+ pm_options_t *options = pm_options_new();
+ VALUE string = string_options(argc, argv, options);
- VALUE result = parse_lex_input(&input, &options, false);
- pm_string_free(&input);
- pm_options_free(&options);
+ VALUE result = parse_lex_input((const uint8_t *) RSTRING_PTR(string), RSTRING_LEN(string), options, false);
+ pm_options_free(options);
return result;
}
/**
+ * :markup: markdown
* call-seq:
- * Prism::lex_file(filepath, **options) -> LexResult
+ * 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.
+ * 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 };
+ pm_options_t *options = pm_options_new();
VALUE encoded_filepath;
- file_options(argc, argv, &input, &options, &encoded_filepath);
+ pm_source_t *src = file_options(argc, argv, options, &encoded_filepath);
- VALUE value = parse_lex_input(&input, &options, false);
- pm_string_free(&input);
- pm_options_free(&options);
+ VALUE value = parse_lex_input(pm_source_source(src), pm_source_length(src), options, false);
+ pm_source_free(src);
+ pm_options_free(options);
return value;
}
@@ -828,30 +885,32 @@ lex_file(int argc, VALUE *argv, VALUE self) {
* 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);
+parse_input(const uint8_t *input, size_t input_length, const pm_options_t *options) {
+ pm_arena_t *arena = pm_arena_new();
+ pm_parser_t *parser = pm_parser_new(arena, input, input_length, options);
- pm_node_t *node = pm_parse(&parser);
- rb_encoding *encoding = rb_enc_find(parser.encoding->name);
+ pm_node_t *node = pm_parse(parser);
+ rb_encoding *encoding = rb_enc_find(pm_parser_encoding_name(parser));
- VALUE source = pm_source_new(&parser, encoding, options->freeze);
- VALUE value = pm_ast_new(&parser, node, encoding, source, options->freeze);
- VALUE result = parse_result_create(rb_cPrismParseResult, &parser, value, encoding, source, options->freeze);
+ bool freeze = pm_options_freeze(options);
+ VALUE source = pm_source_new(parser, encoding, freeze);
+ VALUE value = pm_ast_new(parser, node, encoding, source, freeze);
+ VALUE result = parse_result_create(rb_cPrismParseResult, parser, value, encoding, source, freeze);
- if (options->freeze) {
+ if (freeze) {
rb_obj_freeze(source);
}
- pm_node_destroy(&parser, node);
- pm_parser_free(&parser);
+ pm_parser_free(parser);
+ pm_arena_free(arena);
return result;
}
/**
+ * :markup: markdown
* call-seq:
- * Prism::parse(source, **options) -> ParseResult
+ * parse(source, **options) -> ParseResult
*
* Parse the given string and return a ParseResult instance. The options that
* are supported are:
@@ -888,51 +947,57 @@ parse_input(pm_string_t *input, const pm_options_t *options) {
* 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.
+ * the current Ruby is running use `version: "current"`. To parse with the
+ * nearest version to the current Ruby that is running, use
+ * `version: "nearest"`. 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);
+ pm_options_t *options = pm_options_new();
+ VALUE string = string_options(argc, argv, options);
+
+ const uint8_t *source = (const uint8_t *) RSTRING_PTR(string);
+ size_t length = RSTRING_LEN(string);
#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);
+ memcpy(dup, source, length);
+ source = (const uint8_t *) dup;
#endif
- VALUE value = parse_input(&input, &options);
+ VALUE value = parse_input(source, length, options);
#ifdef PRISM_BUILD_DEBUG
+#ifdef xfree_sized
+ xfree_sized(dup, length);
+#else
xfree(dup);
#endif
+#endif
- pm_string_free(&input);
- pm_options_free(&options);
+ pm_options_free(options);
return value;
}
/**
+ * :markup: markdown
* call-seq:
- * Prism::parse_file(filepath, **options) -> ParseResult
+ * parse_file(filepath, **options) -> ParseResult
*
* Parse the given file and return a ParseResult instance. For supported
- * options, see Prism::parse.
+ * options, see Prism.parse.
*/
static VALUE
parse_file(int argc, VALUE *argv, VALUE self) {
- pm_string_t input;
- pm_options_t options = { 0 };
+ pm_options_t *options = pm_options_new();
VALUE encoded_filepath;
- file_options(argc, argv, &input, &options, &encoded_filepath);
+ pm_source_t *src = file_options(argc, argv, options, &encoded_filepath);
- VALUE value = parse_input(&input, &options);
- pm_string_free(&input);
- pm_options_free(&options);
+ VALUE value = parse_input(pm_source_source(src), pm_source_length(src), options);
+ pm_source_free(src);
+ pm_options_free(options);
return value;
}
@@ -941,55 +1006,54 @@ parse_file(int argc, VALUE *argv, VALUE self) {
* 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);
+profile_input(const uint8_t *input, size_t input_length, const pm_options_t *options) {
+ pm_arena_t *arena = pm_arena_new();
+ pm_parser_t *parser = pm_parser_new(arena, input, input_length, options);
- pm_node_t *node = pm_parse(&parser);
- pm_node_destroy(&parser, node);
- pm_parser_free(&parser);
+ pm_parse(parser);
+ pm_parser_free(parser);
+ pm_arena_free(arena);
}
/**
+ * :markup: markdown
* call-seq:
- * Prism::profile(source, **options) -> nil
+ * 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.
+ * options, see Prism.parse.
*/
static VALUE
profile(int argc, VALUE *argv, VALUE self) {
- pm_string_t input;
- pm_options_t options = { 0 };
+ pm_options_t *options = pm_options_new();
+ VALUE string = string_options(argc, argv, options);
- string_options(argc, argv, &input, &options);
- profile_input(&input, &options);
- pm_string_free(&input);
- pm_options_free(&options);
+ profile_input((const uint8_t *) RSTRING_PTR(string), RSTRING_LEN(string), options);
+ pm_options_free(options);
return Qnil;
}
/**
+ * :markup: markdown
* call-seq:
- * Prism::profile_file(filepath, **options) -> nil
+ * 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.
+ * options, see Prism.parse.
*/
static VALUE
profile_file(int argc, VALUE *argv, VALUE self) {
- pm_string_t input;
- pm_options_t options = { 0 };
+ pm_options_t *options = pm_options_new();
VALUE encoded_filepath;
- file_options(argc, argv, &input, &options, &encoded_filepath);
+ pm_source_t *src = file_options(argc, argv, options, &encoded_filepath);
- profile_input(&input, &options);
- pm_string_free(&input);
- pm_options_free(&options);
+ profile_input(pm_source_source(src), pm_source_length(src), options);
+ pm_source_free(src);
+ pm_options_free(options);
return Qnil;
}
@@ -1024,11 +1088,12 @@ parse_stream_fgets(char *string, int size, void *stream) {
}
/**
+ * :markup: markdown
* call-seq:
- * Prism::parse_stream(stream, **options) -> ParseResult
+ * 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.
+ * instance. The options that are supported are the same as Prism.parse.
*/
static VALUE
parse_stream(int argc, VALUE *argv, VALUE self) {
@@ -1036,22 +1101,24 @@ parse_stream(int argc, VALUE *argv, VALUE self) {
VALUE keywords;
rb_scan_args(argc, argv, "1:", &stream, &keywords);
- pm_options_t options = { 0 };
- extract_options(&options, Qnil, keywords);
+ pm_options_t *options = pm_options_new();
+ extract_options(options, Qnil, keywords);
- pm_parser_t parser;
- pm_buffer_t buffer;
+ pm_source_t *src = pm_source_stream_new((void *) stream, parse_stream_fgets, parse_stream_eof);
+ pm_arena_t *arena = pm_arena_new();
+ pm_parser_t *parser;
- pm_node_t *node = pm_parse_stream(&parser, &buffer, (void *) stream, parse_stream_fgets, parse_stream_eof, &options);
- rb_encoding *encoding = rb_enc_find(parser.encoding->name);
+ pm_node_t *node = pm_parse_stream(&parser, arena, src, options);
+ rb_encoding *encoding = rb_enc_find(pm_parser_encoding_name(parser));
- VALUE source = pm_source_new(&parser, encoding, options.freeze);
- VALUE value = pm_ast_new(&parser, node, encoding, source, options.freeze);
- VALUE result = parse_result_create(rb_cPrismParseResult, &parser, value, encoding, source, options.freeze);
+ VALUE source = pm_source_new(parser, encoding, pm_options_freeze(options));
+ VALUE value = pm_ast_new(parser, node, encoding, source, pm_options_freeze(options));
+ VALUE result = parse_result_create(rb_cPrismParseResult, parser, value, encoding, source, pm_options_freeze(options));
- pm_node_destroy(&parser, node);
- pm_buffer_free(&buffer);
- pm_parser_free(&parser);
+ pm_source_free(src);
+ pm_parser_free(parser);
+ pm_arena_free(arena);
+ pm_options_free(options);
return result;
}
@@ -1060,116 +1127,114 @@ parse_stream(int argc, VALUE *argv, VALUE self) {
* 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);
+parse_input_comments(const uint8_t *input, size_t input_length, const pm_options_t *options) {
+ pm_arena_t *arena = pm_arena_new();
+ pm_parser_t *parser = pm_parser_new(arena, input, input_length, options);
- pm_node_t *node = pm_parse(&parser);
- rb_encoding *encoding = rb_enc_find(parser.encoding->name);
+ pm_parse(parser);
+ rb_encoding *encoding = rb_enc_find(pm_parser_encoding_name(parser));
- VALUE source = pm_source_new(&parser, encoding, options->freeze);
- VALUE comments = parser_comments(&parser, source, options->freeze);
+ VALUE source = pm_source_new(parser, encoding, pm_options_freeze(options));
+ VALUE comments = parser_comments(parser, source, pm_options_freeze(options));
- pm_node_destroy(&parser, node);
- pm_parser_free(&parser);
+ pm_parser_free(parser);
+ pm_arena_free(arena);
return comments;
}
/**
+ * :markup: markdown
* call-seq:
- * Prism::parse_comments(source, **options) -> Array
+ * parse_comments(source, **options) -> Array
*
* Parse the given string and return an array of Comment objects. For supported
- * options, see Prism::parse.
+ * 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);
+ pm_options_t *options = pm_options_new();
+ VALUE string = string_options(argc, argv, options);
- VALUE result = parse_input_comments(&input, &options);
- pm_string_free(&input);
- pm_options_free(&options);
+ VALUE result = parse_input_comments((const uint8_t *) RSTRING_PTR(string), RSTRING_LEN(string), options);
+ pm_options_free(options);
return result;
}
/**
+ * :markup: markdown
* call-seq:
- * Prism::parse_file_comments(filepath, **options) -> Array
+ * parse_file_comments(filepath, **options) -> Array
*
* Parse the given file and return an array of Comment objects. For supported
- * options, see Prism::parse.
+ * options, see Prism.parse.
*/
static VALUE
parse_file_comments(int argc, VALUE *argv, VALUE self) {
- pm_string_t input;
- pm_options_t options = { 0 };
+ pm_options_t *options = pm_options_new();
VALUE encoded_filepath;
- file_options(argc, argv, &input, &options, &encoded_filepath);
+ pm_source_t *src = file_options(argc, argv, options, &encoded_filepath);
- VALUE value = parse_input_comments(&input, &options);
- pm_string_free(&input);
- pm_options_free(&options);
+ VALUE value = parse_input_comments(pm_source_source(src), pm_source_length(src), options);
+ pm_source_free(src);
+ pm_options_free(options);
return value;
}
/**
+ * :markup: markdown
* call-seq:
- * Prism::parse_lex(source, **options) -> ParseLexResult
+ * 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.
+ * the tokens. If you only need one or the other, use either Prism.parse or
+ * Prism.lex.
*
- * For supported options, see Prism::parse.
+ * 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);
+ pm_options_t *options = pm_options_new();
+ VALUE string = string_options(argc, argv, options);
- VALUE value = parse_lex_input(&input, &options, true);
- pm_string_free(&input);
- pm_options_free(&options);
+ VALUE value = parse_lex_input((const uint8_t *) RSTRING_PTR(string), RSTRING_LEN(string), options, true);
+ pm_options_free(options);
return value;
}
/**
+ * :markup: markdown
* call-seq:
- * Prism::parse_lex_file(filepath, **options) -> ParseLexResult
+ * 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.
+ * 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.
+ * 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 };
+ pm_options_t *options = pm_options_new();
VALUE encoded_filepath;
- file_options(argc, argv, &input, &options, &encoded_filepath);
+ pm_source_t *src = file_options(argc, argv, options, &encoded_filepath);
- VALUE value = parse_lex_input(&input, &options, true);
- pm_string_free(&input);
- pm_options_free(&options);
+ VALUE value = parse_lex_input(pm_source_source(src), pm_source_length(src), options, true);
+ pm_source_free(src);
+ pm_options_free(options);
return value;
}
@@ -1178,45 +1243,45 @@ parse_lex_file(int argc, VALUE *argv, VALUE self) {
* 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);
+parse_input_success_p(const uint8_t *input, size_t input_length, const pm_options_t *options) {
+ pm_arena_t *arena = pm_arena_new();
+ pm_parser_t *parser = pm_parser_new(arena, input, input_length, options);
- pm_node_t *node = pm_parse(&parser);
- pm_node_destroy(&parser, node);
+ pm_parse(parser);
- VALUE result = parser.error_list.size == 0 ? Qtrue : Qfalse;
- pm_parser_free(&parser);
+ VALUE result = pm_parser_errors_size(parser) == 0 ? Qtrue : Qfalse;
+ pm_parser_free(parser);
+ pm_arena_free(arena);
return result;
}
/**
+ * :markup: markdown
* call-seq:
- * Prism::parse_success?(source, **options) -> bool
+ * parse_success?(source, **options) -> bool
*
* Parse the given string and return true if it parses without errors. For
- * supported options, see Prism::parse.
+ * 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);
+ pm_options_t *options = pm_options_new();
+ VALUE string = string_options(argc, argv, options);
- VALUE result = parse_input_success_p(&input, &options);
- pm_string_free(&input);
- pm_options_free(&options);
+ VALUE result = parse_input_success_p((const uint8_t *) RSTRING_PTR(string), RSTRING_LEN(string), options);
+ pm_options_free(options);
return result;
}
/**
+ * :markup: markdown
* call-seq:
- * Prism::parse_failure?(source, **options) -> bool
+ * parse_failure?(source, **options) -> bool
*
* Parse the given string and return true if it parses with errors. For
- * supported options, see Prism::parse.
+ * supported options, see Prism.parse.
*/
static VALUE
parse_failure_p(int argc, VALUE *argv, VALUE self) {
@@ -1224,33 +1289,34 @@ parse_failure_p(int argc, VALUE *argv, VALUE self) {
}
/**
+ * :markup: markdown
* call-seq:
- * Prism::parse_file_success?(filepath, **options) -> bool
+ * parse_file_success?(filepath, **options) -> bool
*
* Parse the given file and return true if it parses without errors. For
- * supported options, see Prism::parse.
+ * 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 };
+ pm_options_t *options = pm_options_new();
VALUE encoded_filepath;
- file_options(argc, argv, &input, &options, &encoded_filepath);
+ pm_source_t *src = file_options(argc, argv, options, &encoded_filepath);
- VALUE result = parse_input_success_p(&input, &options);
- pm_string_free(&input);
- pm_options_free(&options);
+ VALUE result = parse_input_success_p(pm_source_source(src), pm_source_length(src), options);
+ pm_source_free(src);
+ pm_options_free(options);
return result;
}
/**
+ * :markup: markdown
* call-seq:
- * Prism::parse_file_failure?(filepath, **options) -> bool
+ * parse_file_failure?(filepath, **options) -> bool
*
* Parse the given file and return true if it parses with errors. For
- * supported options, see Prism::parse.
+ * supported options, see Prism.parse.
*/
static VALUE
parse_file_failure_p(int argc, VALUE *argv, VALUE self) {
@@ -1280,8 +1346,9 @@ string_query(pm_string_query_t result) {
}
/**
+ * :markup: markdown
* call-seq:
- * Prism::StringQuery::local?(string) -> bool
+ * local?(string) -> bool
*
* Returns true if the string constitutes a valid local variable name. Note that
* this means the names that can be set through Binding#local_variable_set, not
@@ -1294,8 +1361,9 @@ string_query_local_p(VALUE self, VALUE string) {
}
/**
+ * :markup: markdown
* call-seq:
- * Prism::StringQuery::constant?(string) -> bool
+ * constant?(string) -> bool
*
* Returns true if the string constitutes a valid constant name. Note that this
* means the names that can be set through Module#const_set, not necessarily the
@@ -1308,8 +1376,9 @@ string_query_constant_p(VALUE self, VALUE string) {
}
/**
+ * :markup: markdown
* call-seq:
- * Prism::StringQuery::method_name?(string) -> bool
+ * method_name?(string) -> bool
*
* Returns true if the string constitutes a valid method name.
*/
@@ -1364,6 +1433,8 @@ Init_prism(void) {
rb_cPrismStringQuery = rb_define_class_under(rb_cPrism, "StringQuery", rb_cObject);
rb_cPrismScope = rb_define_class_under(rb_cPrism, "Scope", rb_cObject);
+ rb_cPrismCurrentVersionError = rb_const_get(rb_cPrism, rb_intern("CurrentVersionError"));
+
// 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");
@@ -1415,5 +1486,4 @@ Init_prism(void) {
// Next, initialize the other APIs.
Init_prism_api_node();
- Init_prism_pack();
}
diff --git a/prism/extension.h b/prism/extension.h
index 506da2fd6f..d0cbc2ff53 100644
--- a/prism/extension.h
+++ b/prism/extension.h
@@ -1,10 +1,11 @@
#ifndef PRISM_EXT_NODE_H
#define PRISM_EXT_NODE_H
-#define EXPECTED_PRISM_VERSION "1.4.0"
+#define EXPECTED_PRISM_VERSION "1.9.0"
#include <ruby.h>
#include <ruby/encoding.h>
+#include <ruby/version.h>
#include "prism.h"
VALUE pm_source_new(const pm_parser_t *parser, rb_encoding *encoding, bool freeze);
@@ -13,7 +14,6 @@ VALUE pm_ast_new(const pm_parser_t *parser, const pm_node_t *node, rb_encoding *
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/generate-srcs.mk.rb b/prism/generate-srcs.mk.rb
deleted file mode 100644
index af031ef2e4..0000000000
--- a/prism/generate-srcs.mk.rb
+++ /dev/null
@@ -1,17 +0,0 @@
-require_relative 'templates/template'
-
-puts %[
-PRISM_TEMPLATES_DIR = $(PRISM_SRCDIR)/templates
-PRISM_TEMPLATE = $(PRISM_TEMPLATES_DIR)/template.rb
-PRISM_CONFIG = $(PRISM_SRCDIR)/config.yml
-]
-
-Prism::Template::TEMPLATES.map do |t|
- /\.(?:[ch]|rb)\z/ =~ t or next
- s = t.sub(%r[\A(?:(src)|ext|include)/]) {$1 && 'prism/'}
- puts %[
-main srcs: $(srcdir)/#{s}
-$(srcdir)/#{s}: $(PRISM_CONFIG) $(PRISM_TEMPLATE) $(PRISM_TEMPLATES_DIR)/#{t}.erb
-\t$(Q) $(BASERUBY) $(PRISM_TEMPLATE) #{t} $@
-]
-end
diff --git a/prism/integer.c b/prism/integer.c
new file mode 100644
index 0000000000..1b69dbdceb
--- /dev/null
+++ b/prism/integer.c
@@ -0,0 +1,681 @@
+#include "prism/internal/integer.h"
+
+#include "prism/internal/allocator.h"
+#include "prism/internal/buffer.h"
+
+#include <assert.h>
+#include <inttypes.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+
+/**
+ * Free the internal memory of an integer. This memory will only be allocated if
+ * the integer exceeds the size of a single uint32_t.
+ */
+static void
+pm_integer_free(pm_integer_t *integer) {
+ if (integer->values) {
+ xfree(integer->values);
+ }
+}
+
+/**
+ * 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_sized(bigints, bigints_length * sizeof(pm_integer_t));
+ bigints = next_bigints;
+ bigints_length = next_length;
+ }
+
+ *destination = bigints[0];
+ destination->negative = source->negative;
+ pm_integer_normalize(destination);
+
+ xfree_sized(bigints, bigints_length * sizeof(pm_integer_t));
+ 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;
+ const 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_sized(values, length * sizeof(uint32_t));
+}
+
+/**
+ * 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.
+ const size_t digits_capa = sizeof(uint8_t) * (size_t) (end - start);
+ uint8_t *digits = xmalloc(digits_capa);
+ 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_sized(digits, digits_capa);
+}
+
+/**
+ * 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.
+ */
+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.
+ const 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_sized(digits, sizeof(char) * digits_length);
+ pm_integer_free(&converted);
+}
diff --git a/prism/integer.h b/prism/integer.h
new file mode 100644
index 0000000000..9285986885
--- /dev/null
+++ b/prism/integer.h
@@ -0,0 +1,41 @@
+/**
+ * @file integer.h
+ *
+ * This module provides functions for working with arbitrary-sized integers.
+ */
+#ifndef PRISM_INTEGER_H
+#define PRISM_INTEGER_H
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.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;
+
+#endif
diff --git a/prism/internal/allocator.h b/prism/internal/allocator.h
new file mode 100644
index 0000000000..6c54010dbf
--- /dev/null
+++ b/prism/internal/allocator.h
@@ -0,0 +1,68 @@
+#ifndef PRISM_INTERNAL_ALLOCATOR_H
+#define PRISM_INTERNAL_ALLOCATOR_H
+
+/* 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
+ * #define xrealloc_sized my_realloc_sized // (optional)
+ * #define xfree_sized my_free_sized // (optional)
+ * #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
+
+#ifndef xfree_sized
+ /* The free_sized function that should be used. This can be overridden with
+ * the PRISM_XALLOCATOR define. If not defined, defaults to calling xfree.
+ */
+ #define xfree_sized(p, s) xfree(((void)(s), (p)))
+#endif
+
+#ifndef xrealloc_sized
+ /* The xrealloc_sized function that should be used. This can be overridden
+ * with the PRISM_XALLOCATOR define. If not defined, defaults to calling
+ * xrealloc. */
+ #define xrealloc_sized(p, ns, os) xrealloc((p), ((void)(os), (ns)))
+#endif
+
+#ifdef PRISM_BUILD_DEBUG
+ #include "prism/internal/allocator_debug.h"
+#endif
+
+#endif
diff --git a/prism/internal/allocator_debug.h b/prism/internal/allocator_debug.h
new file mode 100644
index 0000000000..846e96ba2d
--- /dev/null
+++ b/prism/internal/allocator_debug.h
@@ -0,0 +1,88 @@
+#ifndef PRISM_INTERNAL_ALLOCATOR_DEBUG_H
+#define PRISM_INTERNAL_ALLOCATOR_DEBUG_H
+
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+static inline void *
+pm_allocator_debug_malloc(size_t size) {
+ size_t *memory = xmalloc(size + sizeof(size_t));
+ memory[0] = size;
+ return memory + 1;
+}
+
+static inline void *
+pm_allocator_debug_calloc(size_t nmemb, size_t size) {
+ size_t total_size = nmemb * size;
+ void *ptr = pm_allocator_debug_malloc(total_size);
+ memset(ptr, 0, total_size);
+ return ptr;
+}
+
+static inline void *
+pm_allocator_debug_realloc(void *ptr, size_t size) {
+ if (ptr == NULL) {
+ return pm_allocator_debug_malloc(size);
+ }
+
+ size_t *memory = (size_t *)ptr;
+ void *raw_memory = memory - 1;
+ memory = (size_t *)xrealloc(raw_memory, size + sizeof(size_t));
+ memory[0] = size;
+ return memory + 1;
+}
+
+static inline void
+pm_allocator_debug_free(void *ptr) {
+ if (ptr != NULL) {
+ size_t *memory = (size_t *)ptr;
+ xfree(memory - 1);
+ }
+}
+
+static inline void
+pm_allocator_debug_free_sized(void *ptr, size_t old_size) {
+ if (ptr != NULL) {
+ size_t *memory = (size_t *)ptr;
+ if (old_size != memory[-1]) {
+ fprintf(stderr, "[BUG] buffer %p was allocated with size %lu but freed with size %lu\n", ptr, memory[-1], old_size);
+ abort();
+ }
+ xfree_sized(memory - 1, old_size + sizeof(size_t));
+ }
+}
+
+static inline void *
+pm_allocator_debug_realloc_sized(void *ptr, size_t size, size_t old_size) {
+ if (ptr == NULL) {
+ if (old_size != 0) {
+ fprintf(stderr, "[BUG] realloc_sized called with NULL pointer and old size %lu\n", old_size);
+ abort();
+ }
+ return pm_allocator_debug_malloc(size);
+ }
+
+ size_t *memory = (size_t *)ptr;
+ if (old_size != memory[-1]) {
+ fprintf(stderr, "[BUG] buffer %p was allocated with size %lu but realloced with size %lu\n", ptr, memory[-1], old_size);
+ abort();
+ }
+ return pm_allocator_debug_realloc(ptr, size);
+}
+
+#undef xmalloc
+#undef xrealloc
+#undef xcalloc
+#undef xfree
+#undef xrealloc_sized
+#undef xfree_sized
+
+#define xmalloc pm_allocator_debug_malloc
+#define xrealloc pm_allocator_debug_realloc
+#define xcalloc pm_allocator_debug_calloc
+#define xfree pm_allocator_debug_free
+#define xrealloc_sized pm_allocator_debug_realloc_sized
+#define xfree_sized pm_allocator_debug_free_sized
+
+#endif
diff --git a/prism/internal/arena.h b/prism/internal/arena.h
new file mode 100644
index 0000000000..2e413b42bf
--- /dev/null
+++ b/prism/internal/arena.h
@@ -0,0 +1,108 @@
+#ifndef PRISM_INTERNAL_ARENA_H
+#define PRISM_INTERNAL_ARENA_H
+
+#include "prism/compiler/exported.h"
+#include "prism/compiler/flex_array.h"
+#include "prism/compiler/force_inline.h"
+#include "prism/compiler/inline.h"
+
+#include "prism/arena.h"
+
+#include <stddef.h>
+#include <string.h>
+
+/*
+ * A single block of memory in the arena. Blocks are linked via prev pointers so
+ * they can be freed by walking the chain.
+ */
+typedef struct pm_arena_block {
+ /* The previous block in the chain (for freeing). */
+ struct pm_arena_block *prev;
+
+ /* The total usable bytes in data[]. */
+ size_t capacity;
+
+ /* The number of bytes consumed so far. */
+ size_t used;
+
+ /* The block's data. */
+ char data[PM_FLEX_ARRAY_LENGTH];
+} pm_arena_block_t;
+
+/*
+ * A bump allocator. Allocations are made by bumping a pointer within the
+ * current block. When a block is full, a new block is allocated and linked to
+ * the previous one. All blocks are freed at once by walking the chain.
+ */
+struct pm_arena_t {
+ /* The active block (allocate from here). */
+ pm_arena_block_t *current;
+
+ /* The number of blocks allocated. */
+ size_t block_count;
+};
+
+/*
+ * Free all blocks in the arena. After this call, all pointers returned by
+ * pm_arena_alloc and pm_arena_zalloc are invalid.
+ */
+void pm_arena_cleanup(pm_arena_t *arena);
+
+/*
+ * Ensure the arena has at least `capacity` bytes available in its current
+ * block, allocating a new block if necessary. This allows callers to
+ * pre-size the arena to avoid repeated small block allocations.
+ */
+void pm_arena_reserve(pm_arena_t *arena, size_t capacity);
+
+/*
+ * Slow path for pm_arena_alloc: allocate a new block and return a pointer to
+ * the first `size` bytes. Do not call directly — use pm_arena_alloc instead.
+ */
+void * pm_arena_alloc_slow(pm_arena_t *arena, size_t size);
+
+/*
+ * Allocate memory from the arena. The returned memory is NOT zeroed. This
+ * function is infallible — it aborts on allocation failure.
+ *
+ * The fast path (bump pointer within the current block) is inlined at each
+ * call site. The slow path (new block allocation) is out-of-line.
+ */
+static PRISM_FORCE_INLINE void *
+pm_arena_alloc(pm_arena_t *arena, size_t size, size_t alignment) {
+ if (arena->current != NULL) {
+ size_t used_aligned = (arena->current->used + alignment - 1) & ~(alignment - 1);
+ size_t needed = used_aligned + size;
+
+ if (used_aligned >= arena->current->used && needed >= used_aligned && needed <= arena->current->capacity) {
+ arena->current->used = needed;
+ return arena->current->data + used_aligned;
+ }
+ }
+
+ return pm_arena_alloc_slow(arena, size);
+}
+
+/*
+ * Allocate zero-initialized memory from the arena. This function is infallible
+ * — it aborts on allocation failure.
+ */
+static PRISM_INLINE void *
+pm_arena_zalloc(pm_arena_t *arena, size_t size, size_t alignment) {
+ void *ptr = pm_arena_alloc(arena, size, alignment);
+ memset(ptr, 0, size);
+ return ptr;
+}
+
+/*
+ * Allocate memory from the arena and copy the given data into it. This is a
+ * convenience wrapper around pm_arena_alloc + memcpy.
+ */
+static PRISM_INLINE void *
+pm_arena_memdup(pm_arena_t *arena, const void *src, size_t size, size_t alignment) {
+ void *dst = pm_arena_alloc(arena, size, alignment);
+ memcpy(dst, src, size);
+ return dst;
+}
+
+#endif
diff --git a/prism/internal/bit.h b/prism/internal/bit.h
new file mode 100644
index 0000000000..b0111a4c2c
--- /dev/null
+++ b/prism/internal/bit.h
@@ -0,0 +1,42 @@
+#ifndef PRISM_INTERNAL_BIT_H
+#define PRISM_INTERNAL_BIT_H
+
+#include "prism/compiler/inline.h"
+
+/*
+ * Count trailing zero bits in a 64-bit value. Used by SWAR identifier scanning
+ * to find the first non-matching byte in a word.
+ *
+ * Precondition: v must be nonzero. The result is undefined when v == 0
+ * (matching the behavior of __builtin_ctzll and _BitScanForward64).
+ */
+#if defined(__GNUC__) || defined(__clang__)
+#define pm_ctzll(v) ((unsigned) __builtin_ctzll(v))
+#elif defined(_MSC_VER)
+#include <intrin.h>
+#include <stdint.h>
+
+static PRISM_INLINE unsigned
+pm_ctzll(uint64_t v) {
+ unsigned long index;
+ _BitScanForward64(&index, v);
+ return (unsigned) index;
+}
+#else
+#include <stdint.h>
+
+static PRISM_INLINE unsigned
+pm_ctzll(uint64_t v) {
+ unsigned c = 0;
+ v &= (uint64_t) (-(int64_t) v);
+ if (v & 0x00000000FFFFFFFFULL) c += 0; else c += 32;
+ if (v & 0x0000FFFF0000FFFFULL) c += 0; else c += 16;
+ if (v & 0x00FF00FF00FF00FFULL) c += 0; else c += 8;
+ if (v & 0x0F0F0F0F0F0F0F0FULL) c += 0; else c += 4;
+ if (v & 0x3333333333333333ULL) c += 0; else c += 2;
+ if (v & 0x5555555555555555ULL) c += 0; else c += 1;
+ return c;
+}
+#endif
+
+#endif
diff --git a/prism/internal/buffer.h b/prism/internal/buffer.h
new file mode 100644
index 0000000000..a849bbf8e6
--- /dev/null
+++ b/prism/internal/buffer.h
@@ -0,0 +1,91 @@
+#ifndef PRISM_INTERNAL_BUFFER_H
+#define PRISM_INTERNAL_BUFFER_H
+
+#include "prism/compiler/format.h"
+
+#include "prism/buffer.h"
+
+#include <stdbool.h>
+#include <stdint.h>
+
+/*
+ * A simple memory buffer that stores data in a contiguous block of memory.
+ */
+struct pm_buffer_t {
+ /* 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;
+};
+
+/* Initialize a pm_buffer_t with the given capacity. */
+void pm_buffer_init(pm_buffer_t *buffer, size_t capacity);
+
+/* Free the memory held by the buffer. */
+void pm_buffer_cleanup(pm_buffer_t *buffer);
+
+/* Append the given amount of space as zeroes to the buffer. */
+void pm_buffer_append_zeroes(pm_buffer_t *buffer, size_t length);
+
+/* Append a formatted string to the buffer. */
+void pm_buffer_append_format(pm_buffer_t *buffer, const char *format, ...) PRISM_ATTRIBUTE_FORMAT(2, 3);
+
+/* Append a string to the buffer. */
+void pm_buffer_append_string(pm_buffer_t *buffer, const char *value, size_t 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);
+
+/* Append a single byte to the buffer. */
+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. */
+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. */
+void pm_buffer_append_varsint(pm_buffer_t *buffer, int32_t value);
+
+/* Append a double to the buffer. */
+void pm_buffer_append_double(pm_buffer_t *buffer, double value);
+
+/* Append a unicode codepoint to the buffer. */
+bool pm_buffer_append_unicode_codepoint(pm_buffer_t *buffer, uint32_t 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. */
+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. */
+void pm_buffer_prepend_string(pm_buffer_t *buffer, const char *value, size_t length);
+
+/* Concatenate one buffer onto another. */
+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.
+ */
+void pm_buffer_clear(pm_buffer_t *buffer);
+
+/* Strip the whitespace from the end of the buffer. */
+void pm_buffer_rstrip(pm_buffer_t *buffer);
+
+/* Checks if the buffer includes the given value. */
+size_t pm_buffer_index(const pm_buffer_t *buffer, char 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);
+
+#endif
diff --git a/prism/internal/char.h b/prism/internal/char.h
new file mode 100644
index 0000000000..9a58fba8c5
--- /dev/null
+++ b/prism/internal/char.h
@@ -0,0 +1,139 @@
+#ifndef PRISM_INTERNAL_CHAR_H
+#define PRISM_INTERNAL_CHAR_H
+
+#include "prism/compiler/force_inline.h"
+
+#include "prism/arena.h"
+#include "prism/line_offset_list.h"
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+
+/* Bit flag for whitespace characters in pm_byte_table. */
+#define PRISM_CHAR_BIT_WHITESPACE (1 << 0)
+
+/* Bit flag for inline whitespace characters in pm_byte_table. */
+#define PRISM_CHAR_BIT_INLINE_WHITESPACE (1 << 1)
+
+/*
+ * A lookup table for classifying bytes. Each entry is a bitfield of
+ * PRISM_CHAR_BIT_* flags. Defined in char.c.
+ */
+extern const uint8_t pm_byte_table[256];
+
+/* Returns true if the given character is a whitespace character. */
+static PRISM_FORCE_INLINE bool
+pm_char_is_whitespace(const uint8_t b) {
+ return (pm_byte_table[b] & PRISM_CHAR_BIT_WHITESPACE) != 0;
+}
+
+/* Returns true if the given character is an inline whitespace character. */
+static PRISM_FORCE_INLINE bool
+pm_char_is_inline_whitespace(const uint8_t b) {
+ return (pm_byte_table[b] & PRISM_CHAR_BIT_INLINE_WHITESPACE) != 0;
+}
+
+/*
+ * Returns the number of characters at the start of the string that are inline
+ * whitespace (space/tab). Scans the byte table directly for use in hot paths.
+ */
+static PRISM_FORCE_INLINE size_t
+pm_strspn_inline_whitespace(const uint8_t *string, ptrdiff_t length) {
+ 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_INLINE_WHITESPACE)) 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);
+
+/*
+ * 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_arena_t *arena, pm_line_offset_list_t *line_offsets, uint32_t start_offset);
+
+/*
+ * 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);
+
+/*
+ * 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);
+
+/*
+ * 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);
+
+/*
+ * 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);
+
+/*
+ * 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);
+
+/*
+ * 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);
+
+/*
+ * 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);
+
+
+/* Returns 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. */
+bool pm_char_is_octal_digit(const uint8_t b);
+
+/* Returns 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. */
+bool pm_char_is_hexadecimal_digit(const uint8_t b);
+
+#endif
diff --git a/prism/internal/comments.h b/prism/internal/comments.h
new file mode 100644
index 0000000000..bb3039a658
--- /dev/null
+++ b/prism/internal/comments.h
@@ -0,0 +1,20 @@
+#ifndef PRISM_INTERNAL_COMMENTS_H
+#define PRISM_INTERNAL_COMMENTS_H
+
+#include "prism/comments.h"
+
+#include "prism/internal/list.h"
+
+/* A comment found while parsing. */
+struct pm_comment_t {
+ /* The embedded base node. */
+ pm_list_node_t node;
+
+ /* The location of the comment in the source. */
+ pm_location_t location;
+
+ /* The type of the comment. */
+ pm_comment_type_t type;
+};
+
+#endif
diff --git a/prism/internal/constant_pool.h b/prism/internal/constant_pool.h
new file mode 100644
index 0000000000..fa2be783f5
--- /dev/null
+++ b/prism/internal/constant_pool.h
@@ -0,0 +1,117 @@
+#ifndef PRISM_INTERNAL_CONSTANT_POOL_H
+#define PRISM_INTERNAL_CONSTANT_POOL_H
+
+#include "prism/constant_pool.h"
+
+#include "prism/arena.h"
+
+#include <stdbool.h>
+
+/* A constant in the pool which effectively stores a string. */
+struct pm_constant_t {
+ /* A pointer to the start of the string. */
+ const uint8_t *start;
+
+ /* The length of the string. */
+ size_t length;
+};
+
+/*
+ * 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;
+
+ /*
+ * A pointer to the start of the string, stored directly in the bucket to
+ * avoid a pointer chase to the constants array during probing.
+ */
+ const uint8_t *start;
+
+ /* The length of the string. */
+ size_t length;
+} pm_constant_pool_bucket_t;
+
+/* The overall constant pool, which stores constants found while parsing. */
+struct pm_constant_pool_t {
+ /* 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;
+};
+
+/*
+ * 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
+
+/* Initialize a list of constant ids with a given capacity. */
+void pm_constant_id_list_init_capacity(pm_arena_t *arena, pm_constant_id_list_t *list, size_t capacity);
+
+/* 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);
+
+/* 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);
+
+/* Initialize a new constant pool with a given capacity. */
+void pm_constant_pool_init(pm_arena_t *arena, pm_constant_pool_t *pool, uint32_t capacity);
+
+/* 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);
+
+/*
+ * 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);
+
+/*
+ * 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.
+ */
+pm_constant_id_t pm_constant_pool_insert_shared(pm_arena_t *arena, 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.
+ */
+pm_constant_id_t pm_constant_pool_insert_owned(pm_arena_t *arena, 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.
+ */
+pm_constant_id_t pm_constant_pool_insert_constant(pm_arena_t *arena, pm_constant_pool_t *pool, const uint8_t *start, size_t length);
+
+#endif
diff --git a/prism/internal/encoding.h b/prism/internal/encoding.h
new file mode 100644
index 0000000000..62392ef970
--- /dev/null
+++ b/prism/internal/encoding.h
@@ -0,0 +1,242 @@
+#ifndef PRISM_INTERNAL_ENCODING_H
+#define PRISM_INTERNAL_ENCODING_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. */
+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.
+ */
+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.
+ */
+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.
+ */
+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.
+ */
+const pm_encoding_t * pm_encoding_find(const uint8_t *start, const uint8_t *end);
+
+#endif
diff --git a/prism/internal/integer.h b/prism/internal/integer.h
new file mode 100644
index 0000000000..7c9767e323
--- /dev/null
+++ b/prism/internal/integer.h
@@ -0,0 +1,68 @@
+/*
+ * This module provides functions for working with arbitrary-sized integers.
+ */
+#ifndef PRISM_INTERNAL_INTEGER_H
+#define PRISM_INTERNAL_INTEGER_H
+
+#include "prism/buffer.h"
+#include "prism/integer.h"
+
+#include <stdint.h>
+
+/*
+ * 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.
+ */
+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.
+ */
+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.
+ */
+void pm_integers_reduce(pm_integer_t *numerator, pm_integer_t *denominator);
+
+/* Convert an integer to a decimal string. */
+void pm_integer_string(pm_buffer_t *buffer, const pm_integer_t *integer);
+
+#endif
diff --git a/prism/internal/isinf.h b/prism/internal/isinf.h
new file mode 100644
index 0000000000..41c160f56d
--- /dev/null
+++ b/prism/internal/isinf.h
@@ -0,0 +1,16 @@
+#ifndef PRISM_INTERNAL_ISINF_H
+#define PRISM_INTERNAL_ISINF_H
+
+/*
+ * isinf on POSIX systems accepts a float, a double, or a long double. But mingw
+ * didn't provide an isinf macro, only an isinf function that only accepts
+ * floats, so we need to use _finite instead.
+ */
+#ifdef __MINGW64__
+ #include <float.h>
+ #define PRISM_ISINF(x) (!_finite(x))
+#else
+ #define PRISM_ISINF(x) isinf(x)
+#endif
+
+#endif
diff --git a/prism/internal/line_offset_list.h b/prism/internal/line_offset_list.h
new file mode 100644
index 0000000000..dac9f7052e
--- /dev/null
+++ b/prism/internal/line_offset_list.h
@@ -0,0 +1,34 @@
+#ifndef PRISM_INTERNAL_LINE_OFFSET_LIST_H
+#define PRISM_INTERNAL_LINE_OFFSET_LIST_H
+
+#include "prism/compiler/force_inline.h"
+
+#include "prism/arena.h"
+#include "prism/line_offset_list.h"
+
+/* Initialize a new line offset list with the given capacity. */
+void pm_line_offset_list_init(pm_arena_t *arena, pm_line_offset_list_t *list, size_t capacity);
+
+/* Clear out the offsets that have been appended to the list. */
+void pm_line_offset_list_clear(pm_line_offset_list_t *list);
+
+/* Append a new offset to the list (slow path with resize). */
+void pm_line_offset_list_append_slow(pm_arena_t *arena, pm_line_offset_list_t *list, uint32_t cursor);
+
+/* Append a new offset to the list. */
+static PRISM_FORCE_INLINE void
+pm_line_offset_list_append(pm_arena_t *arena, pm_line_offset_list_t *list, uint32_t cursor) {
+ if (list->size < list->capacity) {
+ list->offsets[list->size++] = cursor;
+ } else {
+ pm_line_offset_list_append_slow(arena, list, 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.
+ */
+int32_t pm_line_offset_list_line(const pm_line_offset_list_t *list, uint32_t cursor, int32_t start_line);
+
+#endif
diff --git a/prism/internal/list.h b/prism/internal/list.h
new file mode 100644
index 0000000000..0ab59ef32a
--- /dev/null
+++ b/prism/internal/list.h
@@ -0,0 +1,62 @@
+#ifndef PRISM_INTERNAL_LIST_H
+#define PRISM_INTERNAL_LIST_H
+
+#include <stddef.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 the size of the list. */
+size_t pm_list_size(pm_list_t *list);
+
+/* Append a node to the given list. */
+void pm_list_append(pm_list_t *list, pm_list_node_t *node);
+
+#endif
diff --git a/prism/internal/magic_comments.h b/prism/internal/magic_comments.h
new file mode 100644
index 0000000000..72a581c5d7
--- /dev/null
+++ b/prism/internal/magic_comments.h
@@ -0,0 +1,23 @@
+#ifndef PRISM_INTERNAL_MAGIC_COMMENTS_H
+#define PRISM_INTERNAL_MAGIC_COMMENTS_H
+
+#include "prism/magic_comments.h"
+
+#include "prism/internal/list.h"
+
+/*
+ * This is a node in the linked list of magic comments that we've found while
+ * parsing.
+ */
+struct pm_magic_comment_t {
+ /* The embedded base node. */
+ pm_list_node_t node;
+
+ /* The key of the magic comment. */
+ pm_location_t key;
+
+ /* The value of the magic comment. */
+ pm_location_t value;
+};
+
+#endif
diff --git a/prism/internal/memchr.h b/prism/internal/memchr.h
new file mode 100644
index 0000000000..6f6b0bca30
--- /dev/null
+++ b/prism/internal/memchr.h
@@ -0,0 +1,15 @@
+#ifndef PRISM_INTERNAL_MEMCHR_H
+#define PRISM_INTERNAL_MEMCHR_H
+
+#include "prism/internal/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.
+ */
+const void * pm_memchr(const void *source, int character, size_t number, bool encoding_changed, const pm_encoding_t *encoding);
+
+#endif
diff --git a/prism/internal/node.h b/prism/internal/node.h
new file mode 100644
index 0000000000..ca6d5616d7
--- /dev/null
+++ b/prism/internal/node.h
@@ -0,0 +1,32 @@
+#ifndef PRISM_INTERNAL_NODE_H
+#define PRISM_INTERNAL_NODE_H
+
+#include "prism/node.h"
+
+#include "prism/compiler/force_inline.h"
+
+#include "prism/arena.h"
+
+/*
+ * Slow path for pm_node_list_append: grow the list and append the node.
+ * Do not call directly — use pm_node_list_append instead.
+ */
+void pm_node_list_append_slow(pm_arena_t *arena, pm_node_list_t *list, pm_node_t *node);
+
+/* Append a new node onto the end of the node list. */
+static PRISM_FORCE_INLINE void
+pm_node_list_append(pm_arena_t *arena, pm_node_list_t *list, pm_node_t *node) {
+ if (list->size < list->capacity) {
+ list->nodes[list->size++] = node;
+ } else {
+ pm_node_list_append_slow(arena, list, node);
+ }
+}
+
+/* Prepend a new node onto the beginning of the node list. */
+void pm_node_list_prepend(pm_arena_t *arena, pm_node_list_t *list, pm_node_t *node);
+
+/* Concatenate the given node list onto the end of the other node list. */
+void pm_node_list_concat(pm_arena_t *arena, pm_node_list_t *list, pm_node_list_t *other);
+
+#endif
diff --git a/prism/internal/options.h b/prism/internal/options.h
new file mode 100644
index 0000000000..7e37742a8b
--- /dev/null
+++ b/prism/internal/options.h
@@ -0,0 +1,212 @@
+#ifndef PRISM_INTERNAL_OPTIONS_H
+#define PRISM_INTERNAL_OPTIONS_H
+
+#include "prism/options.h"
+
+/* A scope of locals surrounding the code that is being parsed. */
+struct pm_options_scope_t {
+ /* The number of locals in the scope. */
+ size_t locals_count;
+
+ /* The names of the locals in the scope. */
+ pm_string_t *locals;
+
+ /* Flags for the set of forwarding parameters in this scope. */
+ uint8_t forwarding;
+};
+
+/*
+ * 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 {
+ /*
+ * If an explicit version is not provided, the current version of prism will
+ * be used.
+ */
+ PM_OPTIONS_VERSION_UNSET = 0,
+
+ /* The vendored version of prism in CRuby 3.3.x. */
+ PM_OPTIONS_VERSION_CRUBY_3_3 = 1,
+
+ /* The vendored version of prism in CRuby 3.4.x. */
+ PM_OPTIONS_VERSION_CRUBY_3_4 = 2,
+
+ /* The vendored version of prism in CRuby 4.0.x. */
+ PM_OPTIONS_VERSION_CRUBY_3_5 = 3,
+
+ /* The vendored version of prism in CRuby 4.0.x. */
+ PM_OPTIONS_VERSION_CRUBY_4_0 = 3,
+
+ /* The vendored version of prism in CRuby 4.1.x. */
+ PM_OPTIONS_VERSION_CRUBY_4_1 = 4,
+
+ /* The current version of prism. */
+ PM_OPTIONS_VERSION_LATEST = PM_OPTIONS_VERSION_CRUBY_4_1
+} pm_options_version_t;
+
+/* The options that can be passed to the parser. */
+struct pm_options_t {
+ /*
+ * 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;
+
+ /*
+ * Whether or not the parser should freeze the nodes that it creates. This
+ * makes it possible to have a deeply frozen AST that is safe to share
+ * between concurrency primitives.
+ */
+ bool freeze;
+};
+
+/* Free the internal memory associated with the options. */
+void pm_options_cleanup(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 |
+ * | `1` | freeze |
+ * | `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 |
+ * | `2` | use the version of prism that is vendored in CRuby 3.4.0 |
+ * | `3` | use the version of prism that is vendored in CRuby 4.0.0 |
+ * | `4` | use the version of prism that is vendored in CRuby 4.1.0 |
+ *
+ * Each scope is laid out as follows:
+ *
+ * | # bytes | field |
+ * | ------- | -------------------------- |
+ * | `4` | the number of locals |
+ * | `1` | the forwarding flags |
+ * | ... | 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.
+ */
+void pm_options_read(pm_options_t *options, const char *data);
+
+#endif
diff --git a/prism/internal/parser.h b/prism/internal/parser.h
new file mode 100644
index 0000000000..4320cf4029
--- /dev/null
+++ b/prism/internal/parser.h
@@ -0,0 +1,958 @@
+#ifndef PRISM_INTERNAL_PARSER_H
+#define PRISM_INTERNAL_PARSER_H
+
+#include "prism/compiler/accel.h"
+
+#include "prism/internal/arena.h"
+#include "prism/internal/constant_pool.h"
+#include "prism/internal/encoding.h"
+#include "prism/internal/list.h"
+#include "prism/internal/options.h"
+#include "prism/internal/static_literals.h"
+#include "prism/internal/strpbrk.h"
+
+#include "prism/ast.h"
+#include "prism/line_offset_list.h"
+#include "prism/parser.h"
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.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[PM_STRPBRK_CACHE_SIZE];
+ } 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[PM_STRPBRK_CACHE_SIZE];
+ } 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[PM_STRPBRK_CACHE_SIZE];
+ } 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
+
+/*
+ * 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,
+
+ /* expressions in block parameters `foo do |...| end ` */
+ PM_CONTEXT_BLOCK_PARAMETERS,
+
+ /* 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;
+
+/* 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;
+
+ /*
+ * A bloom filter over constant IDs stored in this set. Used to quickly
+ * reject lookups for names that are definitely not present, avoiding the
+ * cost of a linear scan or hash probe.
+ */
+ uint32_t bloom;
+
+ /* 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_t {
+ /* The arena used for all AST-lifetime allocations. Caller-owned. */
+ pm_arena_t *arena;
+
+ /* The arena used for parser metadata (comments, diagnostics, etc.). */
+ pm_arena_t metadata_arena;
+
+ /*
+ * 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;
+
+ /*
+ * A single-entry cache for pm_parser_constant_id_raw. Avoids redundant
+ * constant pool lookups when the same token is resolved multiple times
+ * (e.g., once during lexing for local variable detection, and again
+ * during parsing for node creation).
+ */
+ struct {
+ const uint8_t *start;
+ const uint8_t *end;
+ pm_constant_id_t id;
+ } constant_cache;
+
+ /* 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;
+
+ /*
+ * 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.
+ */
+ struct {
+ /*
+ * 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.
+ */
+ pm_lex_callback_t callback;
+
+ /*
+ * 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;
+ } 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 line offsets in the source file. */
+ pm_line_offset_list_t line_offsets;
+
+ /*
+ * State communicated from the lexer to the parser for integer tokens.
+ */
+ struct {
+ /*
+ * A flag indicating the base of the integer (binary, octal, decimal,
+ * hexadecimal). Set during lexing and read during node creation.
+ */
+ pm_node_flags_t base;
+
+ /*
+ * When lexing a decimal integer that fits in a uint32_t, we compute
+ * the value during lexing to avoid re-scanning the digits during
+ * parsing. If lexed is true, this holds the result and
+ * pm_integer_parse can be skipped.
+ */
+ uint32_t value;
+
+ /* Whether value holds a valid pre-computed integer. */
+ bool lexed;
+ } integer;
+
+ /*
+ * 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 parsing the body of an endless method
+ * definition. In this context, PM_TOKEN_KEYWORD_DO_BLOCK should not be
+ * consumed by commands (it should bubble up to the outer context).
+ */
+ bool in_endless_def_body;
+
+ /* Whether or not we're currently recovering from a syntax error. */
+ bool recovering;
+
+ /*
+ * Whether or not the source being parsed could become valid if more input
+ * were appended. This is set to false when the parser encounters a token
+ * that is definitively wrong (e.g., a stray `end` or `]`) as opposed to
+ * merely incomplete.
+ */
+ bool continuable;
+
+ /*
+ * 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;
+
+ /*
+ * By default, Ruby always warns about mismatched indentation. This can be
+ * toggled with a magic comment.
+ */
+ bool warn_mismatched_indentation;
+
+#if defined(PRISM_HAS_NEON) || defined(PRISM_HAS_SSSE3) || defined(PRISM_HAS_SWAR)
+ /*
+ * Cached lookup tables for pm_strpbrk's SIMD fast path. Avoids rebuilding
+ * the nibble-based tables on every call when the charset hasn't changed
+ * (which is the common case during string/regex/list lexing).
+ */
+ struct {
+ /* The cached charset (null-terminated, max 11 chars + NUL). */
+ uint8_t charset[12];
+
+ /* Nibble-based low lookup table for SIMD matching. */
+ uint8_t low_lut[16];
+
+ /* Nibble-based high lookup table for SIMD matching. */
+ uint8_t high_lut[16];
+
+ /* Scalar fallback table (4 x 64-bit bitmasks covering all ASCII). */
+ uint64_t table[4];
+ } strpbrk_cache;
+#endif
+};
+
+/*
+ * Initialize a parser with the given start and end pointers.
+ */
+void pm_parser_init(pm_arena_t *arena, pm_parser_t *parser, const uint8_t *source, size_t size, const pm_options_t *options);
+
+/*
+ * Free the memory held by the given parser.
+ *
+ * This does not free the `pm_options_t` object that was used to initialize the
+ * parser.
+ */
+void pm_parser_cleanup(pm_parser_t *parser);
+
+#endif
diff --git a/prism/internal/regexp.h b/prism/internal/regexp.h
new file mode 100644
index 0000000000..3710c984fc
--- /dev/null
+++ b/prism/internal/regexp.h
@@ -0,0 +1,41 @@
+#ifndef PRISM_INTERNAL_REGEXP_H
+#define PRISM_INTERNAL_REGEXP_H
+
+#include "prism/ast.h"
+#include "prism/parser.h"
+
+/*
+ * Accumulation state for named capture groups found during regexp parsing.
+ * The caller initializes this with the call node and passes it to
+ * pm_regexp_parse. The regexp parser populates match and names as groups
+ * are found.
+ */
+typedef struct {
+ /* The call node wrapping the regular expression node (for =~). */
+ pm_call_node_t *call;
+
+ /* The match write node being built, or NULL if no captures found yet. */
+ pm_match_write_node_t *match;
+
+ /* The list of capture names found so far (for deduplication). */
+ pm_constant_id_list_t names;
+} pm_regexp_name_data_t;
+
+/*
+ * Callback invoked by pm_regexp_parse() for each named capture group found.
+ */
+typedef void (*pm_regexp_name_callback_t)(pm_parser_t *parser, const pm_string_t *name, bool shared, pm_regexp_name_data_t *data);
+
+/*
+ * Parse a regular expression, validate its encoding, and optionally extract
+ * named capture groups. Returns the encoding flags to set on the node.
+ */
+PRISM_EXPORTED_FUNCTION pm_node_flags_t pm_regexp_parse(pm_parser_t *parser, pm_regular_expression_node_t *node, pm_regexp_name_callback_t name_callback, pm_regexp_name_data_t *name_data);
+
+/*
+ * Parse an interpolated regular expression for named capture groups only.
+ * No encoding validation is performed.
+ */
+void pm_regexp_parse_named_captures(pm_parser_t *parser, const uint8_t *source, size_t size, bool shared, bool extended_mode, pm_regexp_name_callback_t name_callback, pm_regexp_name_data_t *name_data);
+
+#endif
diff --git a/prism/internal/serialize.h b/prism/internal/serialize.h
new file mode 100644
index 0000000000..e611a0374b
--- /dev/null
+++ b/prism/internal/serialize.h
@@ -0,0 +1,34 @@
+#ifndef PRISM_INTERNAL_SERIALIZE_H
+#define PRISM_INTERNAL_SERIALIZE_H
+
+#include "prism/internal/encoding.h"
+#include "prism/internal/list.h"
+
+#include "prism/ast.h"
+#include "prism/buffer.h"
+#include "prism/excludes.h"
+#include "prism/parser.h"
+
+/* We optionally support serializing to a binary string. For systems that do not
+ * want or need this functionality, it can be turned off with the
+ * PRISM_EXCLUDE_SERIALIZATION define. */
+#ifndef PRISM_EXCLUDE_SERIALIZATION
+
+/*
+ * Serialize the given list of comments to the given buffer.
+ */
+void pm_serialize_comment_list(pm_list_t *list, pm_buffer_t *buffer);
+
+/*
+ * Serialize the name of the encoding to the buffer.
+ */
+void pm_serialize_encoding(const pm_encoding_t *encoding, pm_buffer_t *buffer);
+
+/*
+ * Serialize the encoding, metadata, nodes, and constant pool.
+ */
+void pm_serialize_content(pm_parser_t *parser, pm_node_t *node, pm_buffer_t *buffer);
+
+#endif
+
+#endif
diff --git a/prism/internal/source.h b/prism/internal/source.h
new file mode 100644
index 0000000000..b3c2b55be3
--- /dev/null
+++ b/prism/internal/source.h
@@ -0,0 +1,72 @@
+#ifndef PRISM_INTERNAL_SOURCE_H
+#define PRISM_INTERNAL_SOURCE_H
+
+#include "prism/source.h"
+#include "prism/buffer.h"
+
+#include <stdbool.h>
+
+/*
+ * The type of source, which determines cleanup behavior.
+ */
+typedef enum {
+ /* Wraps existing constant memory, no cleanup. */
+ PM_SOURCE_CONSTANT,
+
+ /* Wraps existing shared memory (non-owning slice), no cleanup. */
+ PM_SOURCE_SHARED,
+
+ /* Owns a heap-allocated buffer, freed on cleanup. */
+ PM_SOURCE_OWNED,
+
+ /* Memory-mapped file, unmapped on cleanup. */
+ PM_SOURCE_MAPPED,
+
+ /* Stream source backed by a pm_buffer_t. */
+ PM_SOURCE_STREAM
+} pm_source_type_t;
+
+/*
+ * The internal representation of a source.
+ */
+struct pm_source_t {
+ /* A pointer to the start of the source data. */
+ const uint8_t *source;
+
+ /* The length of the source data in bytes. */
+ size_t length;
+
+ /* The type of the source. */
+ pm_source_type_t type;
+
+ /* Stream-specific data, only used for PM_SOURCE_STREAM sources. */
+ struct {
+ /* The buffer that holds the accumulated stream data. */
+ pm_buffer_t *buffer;
+
+ /* The stream object to read from. */
+ void *stream;
+
+ /* The function to use to read from the stream. */
+ pm_source_stream_fgets_t *fgets;
+
+ /* The function to use to check if the stream is at EOF. */
+ pm_source_stream_feof_t *feof;
+
+ /* Whether the stream has reached EOF. */
+ bool eof;
+ } stream;
+};
+
+/*
+ * Read from a stream into the source's internal buffer. This is used by
+ * pm_parse_stream to incrementally read the source.
+ */
+bool pm_source_stream_read(pm_source_t *source);
+
+/*
+ * Returns whether the stream source has reached EOF.
+ */
+bool pm_source_stream_eof(const pm_source_t *source);
+
+#endif
diff --git a/prism/internal/static_literals.h b/prism/internal/static_literals.h
new file mode 100644
index 0000000000..d59002ac0a
--- /dev/null
+++ b/prism/internal/static_literals.h
@@ -0,0 +1,98 @@
+#ifndef PRISM_INTERNAL_STATIC_LITERALS_H
+#define PRISM_INTERNAL_STATIC_LITERALS_H
+
+#include "prism/ast.h"
+#include "prism/buffer.h"
+#include "prism/line_offset_list.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.
+ */
+pm_node_t * pm_static_literals_add(const pm_line_offset_list_t *line_offsets, const uint8_t *start, 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.
+ */
+void pm_static_literals_free(pm_static_literals_t *literals);
+
+/*
+ * Create a string-based representation of the given static literal.
+ */
+void pm_static_literal_inspect(pm_buffer_t *buffer, const pm_line_offset_list_t *line_offsets, const uint8_t *start, int32_t start_line, const char *encoding_name, const pm_node_t *node);
+
+#endif
diff --git a/prism/internal/stringy.h b/prism/internal/stringy.h
new file mode 100644
index 0000000000..1aaa23ea75
--- /dev/null
+++ b/prism/internal/stringy.h
@@ -0,0 +1,30 @@
+#ifndef PRISM_INTERNAL_STRINGY_H
+#define PRISM_INTERNAL_STRINGY_H
+
+#include "prism/stringy.h"
+
+/*
+ * 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.
+ */
+void pm_string_shared_init(pm_string_t *string, const uint8_t *start, const uint8_t *end);
+
+/*
+ * 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);
+
+/*
+ * Free the associated memory of the given string.
+ */
+void pm_string_cleanup(pm_string_t *string);
+
+#endif
diff --git a/prism/internal/strncasecmp.h b/prism/internal/strncasecmp.h
new file mode 100644
index 0000000000..775f6a993e
--- /dev/null
+++ b/prism/internal/strncasecmp.h
@@ -0,0 +1,18 @@
+#ifndef PRISM_INTERNAL_STRNCASECMP_H
+#define PRISM_INTERNAL_STRNCASECMP_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.
+ */
+int pm_strncasecmp(const uint8_t *string1, const uint8_t *string2, size_t length);
+
+#endif
diff --git a/prism/internal/strpbrk.h b/prism/internal/strpbrk.h
new file mode 100644
index 0000000000..d64156c002
--- /dev/null
+++ b/prism/internal/strpbrk.h
@@ -0,0 +1,33 @@
+#ifndef PRISM_INTERNAL_STRPBRK_H
+#define PRISM_INTERNAL_STRPBRK_H
+
+#include "prism/parser.h"
+
+/* The maximum number of bytes in a strpbrk charset. */
+#define PM_STRPBRK_CACHE_SIZE 16
+
+#include <stddef.h>
+#include <stdint.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.
+ */
+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/internal/tokens.h b/prism/internal/tokens.h
new file mode 100644
index 0000000000..3a983e54ae
--- /dev/null
+++ b/prism/internal/tokens.h
@@ -0,0 +1,11 @@
+#ifndef PRISM_INTERNAL_TOKENS_H
+#define PRISM_INTERNAL_TOKENS_H
+
+#include "prism/ast.h"
+
+/*
+ * Returns the human name of the given token type.
+ */
+const char * pm_token_str(pm_token_type_t token_type);
+
+#endif
diff --git a/prism/json.h b/prism/json.h
new file mode 100644
index 0000000000..11039e7796
--- /dev/null
+++ b/prism/json.h
@@ -0,0 +1,32 @@
+/**
+ * @file json.h
+ */
+#ifndef PRISM_JSON_H
+#define PRISM_JSON_H
+
+#include "prism/excludes.h"
+
+/* 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
+
+#include "prism/compiler/exported.h"
+#include "prism/compiler/nonnull.h"
+
+#include "prism/ast.h"
+#include "prism/buffer.h"
+#include "prism/parser.h"
+
+/**
+ * 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) PRISM_NONNULL(1, 2, 3);
+
+#endif
+
+#endif
diff --git a/prism/line_offset_list.c b/prism/line_offset_list.c
new file mode 100644
index 0000000000..ce217ebd3f
--- /dev/null
+++ b/prism/line_offset_list.c
@@ -0,0 +1,100 @@
+#include "prism/compiler/align.h"
+#include "prism/internal/line_offset_list.h"
+#include "prism/internal/arena.h"
+
+#include <assert.h>
+#include <string.h>
+
+/**
+ * Initialize a new line offset list with the given capacity.
+ */
+void
+pm_line_offset_list_init(pm_arena_t *arena, pm_line_offset_list_t *list, size_t capacity) {
+ list->offsets = (uint32_t *) pm_arena_alloc(arena, capacity * sizeof(uint32_t), PRISM_ALIGNOF(uint32_t));
+
+ // The first line always has offset 0.
+ list->offsets[0] = 0;
+ list->size = 1;
+ list->capacity = capacity;
+}
+
+/**
+ * Clear out the newlines that have been appended to the list.
+ */
+void
+pm_line_offset_list_clear(pm_line_offset_list_t *list) {
+ list->size = 1;
+}
+
+/**
+ * Append a new offset to the newline list (slow path: resize and store).
+ */
+void
+pm_line_offset_list_append_slow(pm_arena_t *arena, pm_line_offset_list_t *list, uint32_t cursor) {
+ size_t new_capacity = (list->capacity * 3) / 2;
+ uint32_t *new_offsets = (uint32_t *) pm_arena_alloc(arena, new_capacity * sizeof(uint32_t), PRISM_ALIGNOF(uint32_t));
+
+ memcpy(new_offsets, list->offsets, list->size * sizeof(uint32_t));
+
+ list->offsets = new_offsets;
+ list->capacity = new_capacity;
+
+ assert(list->size == 0 || cursor > list->offsets[list->size - 1]);
+ list->offsets[list->size++] = 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.
+ */
+int32_t
+pm_line_offset_list_line(const pm_line_offset_list_t *list, uint32_t cursor, int32_t start_line) {
+ size_t left = 0;
+ size_t right = list->size - 1;
+
+ while (left <= right) {
+ size_t mid = left + (right - left) / 2;
+
+ if (list->offsets[mid] == cursor) {
+ return ((int32_t) mid) + start_line;
+ }
+
+ if (list->offsets[mid] < cursor) {
+ 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_line_offset_list_line_column(const pm_line_offset_list_t *list, uint32_t cursor, int32_t start_line) {
+ size_t left = 0;
+ size_t right = list->size - 1;
+
+ while (left <= right) {
+ size_t mid = left + (right - left) / 2;
+
+ if (list->offsets[mid] == cursor) {
+ return ((pm_line_column_t) { ((int32_t) mid) + start_line, 0 });
+ }
+
+ if (list->offsets[mid] < cursor) {
+ left = mid + 1;
+ } else {
+ right = mid - 1;
+ }
+ }
+
+ return ((pm_line_column_t) {
+ .line = ((int32_t) left) + start_line - 1,
+ .column = cursor - list->offsets[left - 1]
+ });
+}
diff --git a/prism/line_offset_list.h b/prism/line_offset_list.h
new file mode 100644
index 0000000000..848bc49139
--- /dev/null
+++ b/prism/line_offset_list.h
@@ -0,0 +1,61 @@
+/**
+ * @file line_offset_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_LINE_OFFSET_LIST_H
+#define PRISM_LINE_OFFSET_LIST_H
+
+#include "prism/compiler/exported.h"
+#include "prism/compiler/nonnull.h"
+
+#include <stddef.h>
+#include <stdint.h>
+
+/**
+ * A list of offsets of the start of lines in a string. The offsets are assumed
+ * to be sorted/inserted in ascending order.
+ */
+typedef struct {
+ /** 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. */
+ uint32_t *offsets;
+} pm_line_offset_list_t;
+
+/**
+ * A line and column in a string.
+ */
+typedef struct {
+ /** The line number. */
+ int32_t line;
+
+ /** The column in bytes. */
+ uint32_t column;
+} pm_line_column_t;
+
+/**
+ * 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 The offset to search for.
+ * @param start_line The line to start counting from.
+ * @returns The line and column of the given offset.
+ */
+PRISM_EXPORTED_FUNCTION pm_line_column_t pm_line_offset_list_line_column(const pm_line_offset_list_t *list, uint32_t cursor, int32_t start_line) PRISM_NONNULL(1);
+
+#endif
diff --git a/prism/list.c b/prism/list.c
new file mode 100644
index 0000000000..8d4cd1be94
--- /dev/null
+++ b/prism/list.c
@@ -0,0 +1,24 @@
+#include "prism/internal/list.h"
+
+/**
+ * Returns the size of the list.
+ */
+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++;
+}
diff --git a/prism/magic_comments.h b/prism/magic_comments.h
new file mode 100644
index 0000000000..c9d6b600e8
--- /dev/null
+++ b/prism/magic_comments.h
@@ -0,0 +1,35 @@
+/**
+ * @file magic_comments.h
+ *
+ * Types and functions related to magic comments found during parsing.
+ */
+#ifndef PRISM_MAGIC_COMMENTS_H
+#define PRISM_MAGIC_COMMENTS_H
+
+#include "prism/compiler/exported.h"
+#include "prism/compiler/nonnull.h"
+
+#include "prism/ast.h"
+
+#include <stddef.h>
+
+/** An opaque pointer to a magic comment found while parsing. */
+typedef struct pm_magic_comment_t pm_magic_comment_t;
+
+/**
+ * Returns the location of the key associated with the given magic comment.
+ *
+ * @param magic_comment the magic comment whose key location we want to get
+ * @returns the location of the key associated with the given magic comment
+ */
+PRISM_EXPORTED_FUNCTION pm_location_t pm_magic_comment_key(const pm_magic_comment_t *magic_comment) PRISM_NONNULL(1);
+
+/**
+ * Returns the location of the value associated with the given magic comment.
+ *
+ * @param magic_comment the magic comment whose value location we want to get
+ * @returns the location of the value associated with the given magic comment
+ */
+PRISM_EXPORTED_FUNCTION pm_location_t pm_magic_comment_value(const pm_magic_comment_t *magic_comment) PRISM_NONNULL(1);
+
+#endif
diff --git a/prism/memchr.c b/prism/memchr.c
new file mode 100644
index 0000000000..900e6245b7
--- /dev/null
+++ b/prism/memchr.c
@@ -0,0 +1,37 @@
+#include "prism/internal/memchr.h"
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <string.h>
+
+#define 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.
+ */
+const 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 >= 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);
+ }
+}
diff --git a/prism/node.h b/prism/node.h
index e8686a327c..75bc3c9b2d 100644
--- a/prism/node.h
+++ b/prism/node.h
@@ -6,9 +6,10 @@
#ifndef PRISM_NODE_H
#define PRISM_NODE_H
-#include "prism/defines.h"
-#include "prism/parser.h"
-#include "prism/util/pm_buffer.h"
+#include "prism/compiler/exported.h"
+#include "prism/compiler/nonnull.h"
+
+#include "prism/ast.h"
/**
* Loop through each node in the node list, writing each node to the given
@@ -18,51 +19,12 @@
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.
+ * @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);
+PRISM_EXPORTED_FUNCTION const char * pm_node_type(pm_node_type_t node_type);
/**
* Visit each of the nodes in this subtree using the given visitor callback. The
@@ -80,7 +42,7 @@ PRISM_EXPORTED_FUNCTION const char * pm_node_type_to_str(pm_node_type_t node_typ
* 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));
+ * printf("%s\n", pm_node_type(node->type));
*
* size_t next_indent = *indent + 1;
* size_t *next_data = &next_indent;
@@ -93,18 +55,21 @@ PRISM_EXPORTED_FUNCTION const char * pm_node_type_to_str(pm_node_type_t node_typ
* 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);
+ * pm_arena_t *arena = pm_arena_new();
+ * pm_options_t *options = pm_options_new();
+ *
+ * pm_parser_t *parser = pm_parser_new(arena, (const uint8_t *) source, size, options);
*
* size_t indent = 0;
- * pm_node_t *node = pm_parse(&parser);
+ * 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);
+ * pm_parser_free(parser);
+ * pm_options_free(options);
+ * pm_arena_free(arena);
+ *
* return EXIT_SUCCESS;
* }
* ```
@@ -113,7 +78,7 @@ PRISM_EXPORTED_FUNCTION const char * pm_node_type_to_str(pm_node_type_t node_typ
* @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);
+PRISM_EXPORTED_FUNCTION void pm_visit_node(const pm_node_t *node, bool (*visitor)(const pm_node_t *node, void *data), void *data) PRISM_NONNULL(1);
/**
* Visit the children of the given node with the given callback. This is the
@@ -124,6 +89,6 @@ PRISM_EXPORTED_FUNCTION void pm_visit_node(const pm_node_t *node, bool (*visitor
* @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);
+PRISM_EXPORTED_FUNCTION void pm_visit_child_nodes(const pm_node_t *node, bool (*visitor)(const pm_node_t *node, void *data), void *data) PRISM_NONNULL(1);
#endif
diff --git a/prism/options.c b/prism/options.c
index 1b5c022cf5..b589865a2a 100644
--- a/prism/options.c
+++ b/prism/options.c
@@ -1,18 +1,78 @@
-#include "prism/options.h"
+#include "prism/internal/options.h"
+
+#include "prism/compiler/inline.h"
+
+#include "prism/internal/allocator.h"
+#include "prism/internal/char.h"
+#include "prism/internal/stringy.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+/**
+ * Allocate a new options struct. If the options struct cannot be allocated,
+ * this function aborts the process.
+ */
+pm_options_t *
+pm_options_new(void) {
+ pm_options_t *options = xcalloc(1, sizeof(pm_options_t));
+ if (options == NULL) abort();
+ return options;
+}
+
+/**
+ * Free the internal memory associated with the options.
+ */
+void
+pm_options_cleanup(pm_options_t *options) {
+ pm_string_cleanup(&options->filepath);
+ pm_string_cleanup(&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_cleanup(&scope->locals[local_index]);
+ }
+
+ xfree_sized(scope->locals, scope->locals_count * sizeof(pm_string_t));
+ }
+
+ xfree_sized(options->scopes, options->scopes_count * sizeof(pm_options_scope_t));
+}
+
+/**
+ * Free both the held memory of the given options struct and the struct itself.
+ *
+ * @param options The options struct to free.
+ */
+void
+pm_options_free(pm_options_t *options) {
+ pm_options_cleanup(options);
+ xfree_sized(options, sizeof(pm_options_t));
+}
/**
* Set the shebang callback option on the given options struct.
*/
-PRISM_EXPORTED_FUNCTION void
+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;
}
/**
+ * Get the filepath option on the given options struct.
+ */
+const pm_string_t *
+pm_options_filepath(const pm_options_t *options) {
+ return &options->filepath;
+}
+
+/**
* Set the filepath option on the given options struct.
*/
-PRISM_EXPORTED_FUNCTION void
+void
pm_options_filepath_set(pm_options_t *options, const char *filepath) {
pm_string_constant_init(&options->filepath, filepath, strlen(filepath));
}
@@ -20,7 +80,7 @@ pm_options_filepath_set(pm_options_t *options, const char *filepath) {
/**
* Set the encoding option on the given options struct.
*/
-PRISM_EXPORTED_FUNCTION void
+void
pm_options_encoding_set(pm_options_t *options, const char *encoding) {
pm_string_constant_init(&options->encoding, encoding, strlen(encoding));
}
@@ -28,7 +88,7 @@ pm_options_encoding_set(pm_options_t *options, const char *encoding) {
/**
* Set the encoding_locked option on the given options struct.
*/
-PRISM_EXPORTED_FUNCTION void
+void
pm_options_encoding_locked_set(pm_options_t *options, bool encoding_locked) {
options->encoding_locked = encoding_locked;
}
@@ -36,7 +96,7 @@ pm_options_encoding_locked_set(pm_options_t *options, bool encoding_locked) {
/**
* Set the line option on the given options struct.
*/
-PRISM_EXPORTED_FUNCTION void
+void
pm_options_line_set(pm_options_t *options, int32_t line) {
options->line = line;
}
@@ -44,7 +104,7 @@ pm_options_line_set(pm_options_t *options, int32_t line) {
/**
* Set the frozen string literal option on the given options struct.
*/
-PRISM_EXPORTED_FUNCTION void
+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;
}
@@ -52,7 +112,7 @@ pm_options_frozen_string_literal_set(pm_options_t *options, bool frozen_string_l
/**
* Sets the command line option on the given options struct.
*/
-PRISM_EXPORTED_FUNCTION void
+void
pm_options_command_line_set(pm_options_t *options, uint8_t command_line) {
options->command_line = command_line;
}
@@ -60,7 +120,7 @@ pm_options_command_line_set(pm_options_t *options, uint8_t command_line) {
/**
* Checks if the given slice represents a number.
*/
-static inline bool
+static PRISM_INLINE bool
is_number(const char *string, size_t length) {
return pm_strspn_decimal_digit((const uint8_t *) string, (ptrdiff_t) length) == length;
}
@@ -70,7 +130,7 @@ is_number(const char *string, size_t length) {
* string. If the string contains an invalid option, this returns false.
* Otherwise, it returns true.
*/
-PRISM_EXPORTED_FUNCTION bool
+bool
pm_options_version_set(pm_options_t *options, const char *version, size_t length) {
if (version == NULL) {
options->version = PM_OPTIONS_VERSION_LATEST;
@@ -88,33 +148,43 @@ pm_options_version_set(pm_options_t *options, const char *version, size_t length
return true;
}
- if (strncmp(version, "3.5", 3) == 0) {
- options->version = PM_OPTIONS_VERSION_CRUBY_3_5;
+ if (strncmp(version, "3.5", 3) == 0 || strncmp(version, "4.0", 3) == 0) {
+ options->version = PM_OPTIONS_VERSION_CRUBY_4_0;
+ return true;
+ }
+
+ if (strncmp(version, "4.1", 3) == 0) {
+ options->version = PM_OPTIONS_VERSION_CRUBY_4_1;
return true;
}
return false;
}
- if (length >= 4) {
- if (strncmp(version, "3.3.", 4) == 0 && is_number(version + 4, length - 4)) {
+ if (length >= 4 && is_number(version + 4, length - 4)) {
+ if (strncmp(version, "3.3.", 4) == 0) {
options->version = PM_OPTIONS_VERSION_CRUBY_3_3;
return true;
}
- if (strncmp(version, "3.4.", 4) == 0 && is_number(version + 4, length - 4)) {
+ if (strncmp(version, "3.4.", 4) == 0) {
options->version = PM_OPTIONS_VERSION_CRUBY_3_4;
return true;
}
- if (strncmp(version, "3.5.", 4) == 0 && is_number(version + 4, length - 4)) {
- options->version = PM_OPTIONS_VERSION_CRUBY_3_5;
+ if (strncmp(version, "3.5.", 4) == 0 || strncmp(version, "4.0.", 4) == 0) {
+ options->version = PM_OPTIONS_VERSION_CRUBY_4_0;
+ return true;
+ }
+
+ if (strncmp(version, "4.1.", 4) == 0) {
+ options->version = PM_OPTIONS_VERSION_CRUBY_4_1;
return true;
}
}
- if (length >= 6) {
- if (strncmp(version, "latest", 7) == 0) { // 7 to compare the \0 as well
+ if (length == 6) {
+ if (strncmp(version, "latest", 6) == 0) {
options->version = PM_OPTIONS_VERSION_LATEST;
return true;
}
@@ -124,9 +194,27 @@ pm_options_version_set(pm_options_t *options, const char *version, size_t length
}
/**
+ * Set the version option on the given options struct to the lowest version of
+ * Ruby that prism supports.
+ */
+void
+pm_options_version_set_lowest(pm_options_t *options) {
+ options->version = PM_OPTIONS_VERSION_CRUBY_3_3;
+}
+
+/**
+ * Set the version option on the given options struct to the highest version of
+ * Ruby that prism supports.
+ */
+void
+pm_options_version_set_highest(pm_options_t *options) {
+ options->version = PM_OPTIONS_VERSION_LATEST;
+}
+
+/**
* Set the main script option on the given options struct.
*/
-PRISM_EXPORTED_FUNCTION void
+void
pm_options_main_script_set(pm_options_t *options, bool main_script) {
options->main_script = main_script;
}
@@ -134,15 +222,23 @@ pm_options_main_script_set(pm_options_t *options, bool main_script) {
/**
* Set the partial script option on the given options struct.
*/
-PRISM_EXPORTED_FUNCTION void
+void
pm_options_partial_script_set(pm_options_t *options, bool partial_script) {
options->partial_script = partial_script;
}
/**
+ * Get the freeze option on the given options struct.
+ */
+bool
+pm_options_freeze(const pm_options_t *options) {
+ return options->freeze;
+}
+
+/**
* Set the freeze option on the given options struct.
*/
-PRISM_EXPORTED_FUNCTION void
+void
pm_options_freeze_set(pm_options_t *options, bool freeze) {
options->freeze = freeze;
}
@@ -158,7 +254,7 @@ pm_options_freeze_set(pm_options_t *options, bool freeze) {
/**
* Allocate and zero out the scopes array on the given options struct.
*/
-PRISM_EXPORTED_FUNCTION bool
+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));
@@ -166,10 +262,20 @@ 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.
+ * Return a constant pointer to the scope at the given index within the given
+ * options.
+ */
+const pm_options_scope_t *
+pm_options_scope(const pm_options_t *options, size_t index) {
+ return &options->scopes[index];
+}
+
+/**
+ * Return a mutable 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) {
+pm_options_scope_t *
+pm_options_scope_mut(pm_options_t *options, size_t index) {
return &options->scopes[index];
}
@@ -177,49 +283,38 @@ 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.
*/
-PRISM_EXPORTED_FUNCTION bool
+void
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));
scope->forwarding = PM_OPTIONS_SCOPE_FORWARDING_NONE;
- return scope->locals != NULL;
+ if (scope->locals == NULL) abort();
}
/**
- * Return a pointer to the local at the given index within the given scope.
+ * Return a constant 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) {
+const pm_string_t *
+pm_options_scope_local(const pm_options_scope_t *scope, size_t index) {
return &scope->locals[index];
}
/**
- * Set the forwarding option on the given scope struct.
+ * Return a mutable pointer to the local at the given index within the given
+ * scope.
*/
-PRISM_EXPORTED_FUNCTION void
-pm_options_scope_forwarding_set(pm_options_scope_t *scope, uint8_t forwarding) {
- scope->forwarding = forwarding;
+pm_string_t *
+pm_options_scope_local_mut(pm_options_scope_t *scope, size_t index) {
+ return &scope->locals[index];
}
/**
- * Free the internal memory associated with the options.
+ * Set the forwarding option on the given scope struct.
*/
-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);
+void
+pm_options_scope_forwarding_set(pm_options_scope_t *scope, uint8_t forwarding) {
+ scope->forwarding = forwarding;
}
/**
@@ -304,10 +399,7 @@ pm_options_read(pm_options_t *options, const char *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;
- }
+ pm_options_scope_init(scope, locals_count);
uint8_t forwarding = (uint8_t) *data++;
pm_options_scope_forwarding_set(&options->scopes[scope_index], forwarding);
diff --git a/prism/options.h b/prism/options.h
index 092fda4f07..0f5d7529b1 100644
--- a/prism/options.h
+++ b/prism/options.h
@@ -6,16 +6,27 @@
#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 "prism/compiler/exported.h"
+#include "prism/compiler/nodiscard.h"
+#include "prism/compiler/nonnull.h"
+
+#include "prism/stringy.h"
#include <stdbool.h>
#include <stddef.h>
-#include <stdint.h>
/**
- * String literals should be made frozen.
+ * A scope of locals surrounding the code that is being parsed.
+ */
+typedef struct pm_options_scope_t pm_options_scope_t;
+
+/**
+ * The options that can be passed to the parser.
+ */
+typedef struct pm_options_t pm_options_t;
+
+/**
+ * String literals should not be frozen.
*/
#define PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED ((int8_t) -1)
@@ -26,42 +37,25 @@
#define PM_OPTIONS_FROZEN_STRING_LITERAL_UNSET ((int8_t) 0)
/**
- * String literals should be made mutable.
+ * String literals should be made frozen.
*/
#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;
-
- /** Flags for the set of forwarding parameters in this scope. */
- uint8_t forwarding;
-} pm_options_scope_t;
-
/** The default value for parameters. */
static const uint8_t PM_OPTIONS_SCOPE_FORWARDING_NONE = 0x0;
-/** When the scope is fowarding with the * parameter. */
+/** When the scope is forwarding with the * parameter. */
static const uint8_t PM_OPTIONS_SCOPE_FORWARDING_POSITIONALS = 0x1;
-/** When the scope is fowarding with the ** parameter. */
+/** When the scope is forwarding with the ** parameter. */
static const uint8_t PM_OPTIONS_SCOPE_FORWARDING_KEYWORDS = 0x2;
-/** When the scope is fowarding with the & parameter. */
+/** When the scope is forwarding with the & parameter. */
static const uint8_t PM_OPTIONS_SCOPE_FORWARDING_BLOCK = 0x4;
-/** When the scope is fowarding with the ... parameter. */
+/** When the scope is forwarding with the ... parameter. */
static const uint8_t PM_OPTIONS_SCOPE_FORWARDING_ALL = 0x8;
-// 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.
@@ -74,124 +68,7 @@ struct pm_options;
* @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 {
- /** If an explicit version is not provided, the current version of prism will be used. */
- PM_OPTIONS_VERSION_UNSET = 0,
-
- /** The vendored version of prism in CRuby 3.3.x. */
- PM_OPTIONS_VERSION_CRUBY_3_3 = 1,
-
- /** The vendored version of prism in CRuby 3.4.x. */
- PM_OPTIONS_VERSION_CRUBY_3_4 = 2,
-
- /** The vendored version of prism in CRuby 3.5.x. */
- PM_OPTIONS_VERSION_CRUBY_3_5 = 3,
-
- /** The current version of prism. */
- PM_OPTIONS_VERSION_LATEST = PM_OPTIONS_VERSION_CRUBY_3_5
-} 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;
-
- /**
- * Whether or not the parser should freeze the nodes that it creates. This
- * makes it possible to have a deeply frozen AST that is safe to share
- * between concurrency primitives.
- */
- bool freeze;
-} pm_options_t;
+typedef void (*pm_options_shebang_callback_t)(pm_options_t *options, const uint8_t *source, size_t length, void *shebang_callback_data);
/**
* A bit representing whether or not the command line -a option was set. -a
@@ -226,11 +103,27 @@ 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.
+ * searches the input file for a shebang that includes "ruby".
*/
static const uint8_t PM_OPTIONS_COMMAND_LINE_X = 0x20;
/**
+ * Allocate a new options struct. If the options struct cannot be allocated,
+ * this function aborts the process.
+ *
+ * @returns A new options struct with default values. It is the responsibility
+ * of the caller to free this struct using pm_options_free().
+ */
+PRISM_EXPORTED_FUNCTION PRISM_NODISCARD pm_options_t * pm_options_new(void);
+
+/**
+ * Free both the held memory of the given options struct and the struct itself.
+ *
+ * @param options The options struct to free.
+ */
+PRISM_EXPORTED_FUNCTION void pm_options_free(pm_options_t *options) PRISM_NONNULL(1);
+
+/**
* Set the shebang callback option on the given options struct.
*
* @param options The options struct to set the shebang callback on.
@@ -238,7 +131,15 @@ static const uint8_t PM_OPTIONS_COMMAND_LINE_X = 0x20;
* @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);
+PRISM_EXPORTED_FUNCTION void pm_options_shebang_callback_set(pm_options_t *options, pm_options_shebang_callback_t shebang_callback, void *shebang_callback_data) PRISM_NONNULL(1);
+
+/**
+ * Get the filepath option on the given options struct.
+ *
+ * @param options The options struct to get the filepath from.
+ * @returns The filepath.
+ */
+PRISM_EXPORTED_FUNCTION const pm_string_t * pm_options_filepath(const pm_options_t *options) PRISM_NONNULL(1);
/**
* Set the filepath option on the given options struct.
@@ -246,7 +147,7 @@ PRISM_EXPORTED_FUNCTION void pm_options_shebang_callback_set(pm_options_t *optio
* @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);
+PRISM_EXPORTED_FUNCTION void pm_options_filepath_set(pm_options_t *options, const char *filepath) PRISM_NONNULL(1);
/**
* Set the line option on the given options struct.
@@ -254,7 +155,7 @@ PRISM_EXPORTED_FUNCTION void pm_options_filepath_set(pm_options_t *options, cons
* @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);
+PRISM_EXPORTED_FUNCTION void pm_options_line_set(pm_options_t *options, int32_t line) PRISM_NONNULL(1);
/**
* Set the encoding option on the given options struct.
@@ -262,7 +163,7 @@ PRISM_EXPORTED_FUNCTION void pm_options_line_set(pm_options_t *options, int32_t
* @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);
+PRISM_EXPORTED_FUNCTION void pm_options_encoding_set(pm_options_t *options, const char *encoding) PRISM_NONNULL(1);
/**
* Set the encoding_locked option on the given options struct.
@@ -270,7 +171,7 @@ PRISM_EXPORTED_FUNCTION void pm_options_encoding_set(pm_options_t *options, cons
* @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);
+PRISM_EXPORTED_FUNCTION void pm_options_encoding_locked_set(pm_options_t *options, bool encoding_locked) PRISM_NONNULL(1);
/**
* Set the frozen string literal option on the given options struct.
@@ -278,7 +179,7 @@ PRISM_EXPORTED_FUNCTION void pm_options_encoding_locked_set(pm_options_t *option
* @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);
+PRISM_EXPORTED_FUNCTION void pm_options_frozen_string_literal_set(pm_options_t *options, bool frozen_string_literal) PRISM_NONNULL(1);
/**
* Sets the command line option on the given options struct.
@@ -286,7 +187,7 @@ PRISM_EXPORTED_FUNCTION void pm_options_frozen_string_literal_set(pm_options_t *
* @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);
+PRISM_EXPORTED_FUNCTION void pm_options_command_line_set(pm_options_t *options, uint8_t command_line) PRISM_NONNULL(1);
/**
* Set the version option on the given options struct by parsing the given
@@ -296,9 +197,25 @@ PRISM_EXPORTED_FUNCTION void pm_options_command_line_set(pm_options_t *options,
* @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.
+ * @returns 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);
+PRISM_EXPORTED_FUNCTION bool pm_options_version_set(pm_options_t *options, const char *version, size_t length) PRISM_NONNULL(1);
+
+/**
+ * Set the version option on the given options struct to the lowest version of
+ * Ruby that prism supports.
+ *
+ * @param options The options struct to set the version on.
+ */
+PRISM_EXPORTED_FUNCTION void pm_options_version_set_lowest(pm_options_t *options) PRISM_NONNULL(1);
+
+/**
+ * Set the version option on the given options struct to the highest version of
+ * Ruby that prism supports.
+ *
+ * @param options The options struct to set the version on.
+ */
+PRISM_EXPORTED_FUNCTION void pm_options_version_set_highest(pm_options_t *options) PRISM_NONNULL(1);
/**
* Set the main script option on the given options struct.
@@ -306,7 +223,7 @@ PRISM_EXPORTED_FUNCTION bool pm_options_version_set(pm_options_t *options, const
* @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);
+PRISM_EXPORTED_FUNCTION void pm_options_main_script_set(pm_options_t *options, bool main_script) PRISM_NONNULL(1);
/**
* Set the partial script option on the given options struct.
@@ -314,7 +231,15 @@ PRISM_EXPORTED_FUNCTION void pm_options_main_script_set(pm_options_t *options, b
* @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);
+PRISM_EXPORTED_FUNCTION void pm_options_partial_script_set(pm_options_t *options, bool partial_script) PRISM_NONNULL(1);
+
+/**
+ * Get the freeze option on the given options struct.
+ *
+ * @param options The options struct to get the freeze value from.
+ * @returns The freeze value.
+ */
+PRISM_EXPORTED_FUNCTION bool pm_options_freeze(const pm_options_t *options) PRISM_NONNULL(1);
/**
* Set the freeze option on the given options struct.
@@ -322,127 +247,73 @@ PRISM_EXPORTED_FUNCTION void pm_options_partial_script_set(pm_options_t *options
* @param options The options struct to set the freeze value on.
* @param freeze The freeze value to set.
*/
-PRISM_EXPORTED_FUNCTION void pm_options_freeze_set(pm_options_t *options, bool freeze);
+PRISM_EXPORTED_FUNCTION void pm_options_freeze_set(pm_options_t *options, bool freeze) PRISM_NONNULL(1);
/**
* 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.
+ * @returns 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) PRISM_NONNULL(1);
+
+/**
+ * Return a constant 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.
+ * @returns A constant pointer to the scope at the given index.
*/
-PRISM_EXPORTED_FUNCTION bool pm_options_scopes_init(pm_options_t *options, size_t scopes_count);
+PRISM_EXPORTED_FUNCTION const pm_options_scope_t * pm_options_scope(const pm_options_t *options, size_t index) PRISM_NONNULL(1);
/**
- * Return a pointer to the scope at the given index within the given options.
+ * Return a mutable 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.
+ * @returns A mutable 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);
+PRISM_EXPORTED_FUNCTION pm_options_scope_t * pm_options_scope_mut(pm_options_t *options, size_t index) PRISM_NONNULL(1);
/**
* Create a new options scope struct. This will hold a set of locals that are in
- * scope surrounding the code that is being parsed.
+ * scope surrounding the code that is being parsed. If the scope was unable to
+ * allocate its locals, this function will abort the process.
*
* @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);
+PRISM_EXPORTED_FUNCTION void pm_options_scope_init(pm_options_scope_t *scope, size_t locals_count) PRISM_NONNULL(1);
/**
- * Return a pointer to the local at the given index within the given scope.
+ * Return a constant 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.
+ * @returns A constant 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);
+PRISM_EXPORTED_FUNCTION const pm_string_t * pm_options_scope_local(const pm_options_scope_t *scope, size_t index) PRISM_NONNULL(1);
/**
- * Set the forwarding option on the given scope struct.
+ * Return a mutable pointer to the local at the given index within the given
+ * scope.
*
- * @param scope The scope struct to set the forwarding on.
- * @param forwarding The forwarding value to set.
- */
-PRISM_EXPORTED_FUNCTION void pm_options_scope_forwarding_set(pm_options_scope_t *scope, uint8_t forwarding);
-
-/**
- * Free the internal memory associated with the options.
- *
- * @param options The options struct whose internal memory should be freed.
+ * @param scope The scope struct to get the local from.
+ * @param index The index of the local to get.
+ * @returns A mutable pointer to the local at the given index.
*/
-PRISM_EXPORTED_FUNCTION void pm_options_free(pm_options_t *options);
+PRISM_EXPORTED_FUNCTION pm_string_t * pm_options_scope_local_mut(pm_options_scope_t *scope, size_t index) PRISM_NONNULL(1);
/**
- * 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 |
- * | `1` | freeze |
- * | `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 |
- * | `1` | the forwarding flags |
- * | ... | 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.
+ * Set the forwarding option on the given scope struct.
*
- * @param options The options struct to deserialize into.
- * @param data The binary string to deserialize from.
+ * @param scope The scope struct to set the forwarding on.
+ * @param forwarding The forwarding value to set.
*/
-void pm_options_read(pm_options_t *options, const char *data);
+PRISM_EXPORTED_FUNCTION void pm_options_scope_forwarding_set(pm_options_scope_t *scope, uint8_t forwarding) PRISM_NONNULL(1);
#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.c b/prism/parser.c
new file mode 100644
index 0000000000..415cd31984
--- /dev/null
+++ b/prism/parser.c
@@ -0,0 +1,302 @@
+#include "prism/internal/parser.h"
+
+#include "prism/internal/allocator.h"
+#include "prism/internal/comments.h"
+#include "prism/internal/diagnostic.h"
+#include "prism/internal/encoding.h"
+#include "prism/internal/magic_comments.h"
+
+#include <stdlib.h>
+
+/**
+ * Register a callback that will be called whenever prism changes the encoding
+ * it is using to parse based on the magic comment.
+ */
+void
+pm_parser_encoding_changed_callback_set(pm_parser_t *parser, pm_encoding_changed_callback_t callback) {
+ parser->encoding_changed_callback = callback;
+}
+
+/**
+ * Register a callback that will be called whenever a token is lexed.
+ */
+void
+pm_parser_lex_callback_set(pm_parser_t *parser, pm_lex_callback_t callback, void *data) {
+ parser->lex_callback.callback = callback;
+ parser->lex_callback.data = data;
+}
+
+/**
+ * Returns the opaque data that is passed to the lex callback when it is called.
+ */
+void *
+pm_parser_lex_callback_data(const pm_parser_t *parser) {
+ return parser->lex_callback.data;
+}
+
+/**
+ * Returns the raw pointer to the start of the source that is being parsed.
+ */
+const uint8_t *
+pm_parser_start(const pm_parser_t *parser) {
+ return parser->start;
+}
+
+/**
+ * Returns the raw pointer to the end of the source that is being parsed.
+ */
+const uint8_t *
+pm_parser_end(const pm_parser_t *parser) {
+ return parser->end;
+}
+
+/**
+ * Returns the line that the parser was considered to have started on.
+ *
+ * @param parser the parser whose start line we want to get
+ * @return the line that the parser was considered to have started on
+ */
+int32_t
+pm_parser_start_line(const pm_parser_t *parser) {
+ return parser->start_line;
+}
+
+/**
+ * Returns the name of the encoding that is being used to parse the source.
+ */
+const char *
+pm_parser_encoding_name(const pm_parser_t *parser) {
+ return parser->encoding->name;
+}
+
+/**
+ * Returns the width of the character at the given pointer in the encoding that
+ * is being used to parse the source.
+ */
+size_t
+pm_parser_encoding_char_width(const pm_parser_t *parser, const uint8_t *start, ptrdiff_t remaining) {
+ return parser->encoding->char_width(start, remaining);
+}
+
+/**
+ * Returns whether or not the parser is using the US-ASCII encoding.
+ */
+bool
+pm_parser_encoding_us_ascii(const pm_parser_t *parser) {
+ return parser->encoding == PM_ENCODING_US_ASCII_ENTRY;
+}
+
+/**
+ * Returns the filepath that is being used to parse the source.
+ */
+const pm_string_t *
+pm_parser_filepath(const pm_parser_t *parser) {
+ return &parser->filepath;
+}
+
+/**
+ * Find a constant in the parser's constant pool. Returns the id of the
+ * constant, or 0 if the constant is not found.
+ */
+pm_constant_id_t
+pm_parser_constant_find(const pm_parser_t *parser, const uint8_t *start, size_t length) {
+ return pm_constant_pool_find(&parser->constant_pool, start, length);
+}
+
+/**
+ * Returns the frozen string literal value of the parser.
+ */
+int8_t
+pm_parser_frozen_string_literal(const pm_parser_t *parser) {
+ return parser->frozen_string_literal;
+}
+
+/**
+ * Returns the line offsets that are associated with the given parser.
+ *
+ * @param parser the parser whose line offsets we want to get
+ * @return the line offsets that are associated with the given parser
+ */
+const pm_line_offset_list_t *
+pm_parser_line_offsets(const pm_parser_t *parser) {
+ return &parser->line_offsets;
+}
+
+/**
+ * Returns the location of the __DATA__ section that is associated with the
+ * given parser, if it exists.
+ */
+const pm_location_t *
+pm_parser_data_loc(const pm_parser_t *parser) {
+ return &parser->data_loc;
+}
+
+/**
+ * Returns whether the given parser is continuable, meaning that it could become
+ * valid if more input were appended, as opposed to being definitively invalid.
+ */
+bool
+pm_parser_continuable(const pm_parser_t *parser) {
+ return parser->continuable;
+}
+
+/**
+ * Returns the lex state of the parser. Note that this is an internal detail,
+ * and we are purposefully not returning an instance of the internal enum that
+ * we use to track this. This is only exposed because we need it for some very
+ * niche use cases. Most consumers should avoid this function.
+ */
+int
+pm_parser_lex_state(const pm_parser_t *parser) {
+ return (int) parser->lex_state;
+}
+
+/**
+ * Returns the location associated with the given comment.
+ */
+pm_location_t
+pm_comment_location(const pm_comment_t *comment) {
+ return comment->location;
+}
+
+/**
+ * Returns the type associated with the given comment.
+ */
+pm_comment_type_t
+pm_comment_type(const pm_comment_t *comment) {
+ return comment->type;
+}
+
+/**
+ * Returns the number of comments associated with the given parser.
+ */
+size_t
+pm_parser_comments_size(const pm_parser_t *parser) {
+ return parser->comment_list.size;
+}
+
+/**
+ * Iterates over the comments associated with the given parser and calls the
+ * given callback for each comment.
+ */
+void
+pm_parser_comments_each(const pm_parser_t *parser, pm_comment_callback_t callback, void *data) {
+ const pm_list_node_t *current = parser->comment_list.head;
+ while (current != NULL) {
+ const pm_comment_t *comment = (const pm_comment_t *) current;
+ callback(comment, data);
+ current = current->next;
+ }
+}
+
+/**
+ * Returns the location associated with the given magic comment key.
+ */
+pm_location_t
+pm_magic_comment_key(const pm_magic_comment_t *magic_comment) {
+ return magic_comment->key;
+}
+
+/**
+ * Returns the location associated with the given magic comment value.
+ */
+pm_location_t
+pm_magic_comment_value(const pm_magic_comment_t *magic_comment) {
+ return magic_comment->value;
+}
+
+/**
+ * Returns the number of magic comments associated with the given parser.
+ */
+size_t
+pm_parser_magic_comments_size(const pm_parser_t *parser) {
+ return parser->magic_comment_list.size;
+}
+
+/**
+ * Iterates over the magic comments associated with the given parser and calls
+ * the given callback for each magic comment.
+ */
+void
+pm_parser_magic_comments_each(const pm_parser_t *parser, pm_magic_comment_callback_t callback, void *data) {
+ const pm_list_node_t *current = parser->magic_comment_list.head;
+ while (current != NULL) {
+ const pm_magic_comment_t *magic_comment = (const pm_magic_comment_t *) current;
+ callback(magic_comment, data);
+ current = current->next;
+ }
+}
+
+/**
+ * Returns the number of errors associated with the given parser.
+ */
+size_t
+pm_parser_errors_size(const pm_parser_t *parser) {
+ return parser->error_list.size;
+}
+
+/**
+ * Returns the number of warnings associated with the given parser.
+ */
+size_t
+pm_parser_warnings_size(const pm_parser_t *parser) {
+ return parser->warning_list.size;
+}
+
+static inline void
+pm_parser_diagnostics_each(const pm_list_t *list, pm_diagnostic_callback_t callback, void *data) {
+ const pm_list_node_t *current = list->head;
+ while (current != NULL) {
+ const pm_diagnostic_t *diagnostic = (const pm_diagnostic_t *) current;
+ callback(diagnostic, data);
+ current = current->next;
+ }
+}
+
+/**
+ * Iterates over the errors associated with the given parser and calls the
+ * given callback for each error.
+ */
+void
+pm_parser_errors_each(const pm_parser_t *parser, pm_diagnostic_callback_t callback, void *data) {
+ pm_parser_diagnostics_each(&parser->error_list, callback, data);
+}
+
+/**
+ * Iterates over the warnings associated with the given parser and calls the
+ * given callback for each warning.
+ */
+void
+pm_parser_warnings_each(const pm_parser_t *parser, pm_diagnostic_callback_t callback, void *data) {
+ pm_parser_diagnostics_each(&parser->warning_list, callback, data);
+}
+
+/**
+ * Returns the number of constants in the constant pool associated with the
+ * given parser.
+ */
+size_t
+pm_parser_constants_size(const pm_parser_t *parser) {
+ return parser->constant_pool.size;
+}
+
+/**
+ * Iterates over the constants in the constant pool associated with the given
+ * parser and calls the given callback for each constant.
+ */
+void
+pm_parser_constants_each(const pm_parser_t *parser, pm_constant_callback_t callback, void *data) {
+ for (uint32_t index = 0; index < parser->constant_pool.size; index++) {
+ const pm_constant_t *constant = &parser->constant_pool.constants[index];
+ callback(constant, data);
+ }
+}
+
+/**
+ * Returns a pointer to the constant at the given id in the constant pool
+ * associated with the given parser.
+ */
+const pm_constant_t *
+pm_parser_constant(const pm_parser_t *parser, pm_constant_id_t constant_id) {
+ return pm_constant_pool_id_to_constant(&parser->constant_pool, constant_id);
+}
diff --git a/prism/parser.h b/prism/parser.h
index 992729d655..2c8c4b3a7a 100644
--- a/prism/parser.h
+++ b/prism/parser.h
@@ -6,928 +6,343 @@
#ifndef PRISM_PARSER_H
#define PRISM_PARSER_H
-#include "prism/defines.h"
+#include "prism/compiler/nodiscard.h"
+#include "prism/compiler/nonnull.h"
+
#include "prism/ast.h"
-#include "prism/encoding.h"
+#include "prism/comments.h"
+#include "prism/diagnostic.h"
+#include "prism/line_offset_list.h"
+#include "prism/magic_comments.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;
+typedef struct pm_parser_t 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.
+ * Allocate and initialize a parser with the given start and end pointers.
+ *
+ * @param arena The arena to use for all AST-lifetime allocations. It is caller-
+ * owned and must outlive the parser.
+ * @param source The source to parse.
+ * @param size The size of the source.
+ * @param options The optional options to use when parsing. These options must
+ * live for the whole lifetime of this parser.
+ * @returns The initialized parser. It is the responsibility of the caller to
+ * free the parser with `pm_parser_free()`.
*/
-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,
+PRISM_EXPORTED_FUNCTION PRISM_NODISCARD pm_parser_t * pm_parser_new(pm_arena_t *arena, const uint8_t *source, size_t size, const pm_options_t *options) PRISM_NONNULL(1);
- /** a rescue else statement within a lambda expression */
- PM_CONTEXT_LAMBDA_ELSE,
-
- /** a rescue statement within a lambda expression */
- PM_CONTEXT_LAMBDA_RESCUE,
+/**
+ * Free both the memory held by the given parser and the parser itself.
+ *
+ * @param parser The parser to free.
+ */
+PRISM_EXPORTED_FUNCTION void pm_parser_free(pm_parser_t *parser) PRISM_NONNULL(1);
- /** the predicate clause of a loop statement */
- PM_CONTEXT_LOOP_PREDICATE,
+/**
+ * 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);
- /** the top level context */
- PM_CONTEXT_MAIN,
+/**
+ * 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.
+ */
+typedef void (*pm_lex_callback_t)(pm_parser_t *parser, pm_token_t *token, void *data);
- /** a module declaration */
- PM_CONTEXT_MODULE,
+/**
+ * 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_encoding_changed_callback_set(pm_parser_t *parser, pm_encoding_changed_callback_t callback) PRISM_NONNULL(1);
- /** an ensure statement within a module statement */
- PM_CONTEXT_MODULE_ENSURE,
+/**
+ * Register a callback that will be called whenever a token is lexed.
+ *
+ * @param parser The parser to register the callback with.
+ * @param data The opaque data to pass to the callback when it is called.
+ * @param callback The callback to register.
+ */
+PRISM_EXPORTED_FUNCTION void pm_parser_lex_callback_set(pm_parser_t *parser, pm_lex_callback_t callback, void *data) PRISM_NONNULL(1);
- /** a rescue else statement within a module statement */
- PM_CONTEXT_MODULE_ELSE,
+/**
+ * Returns the opaque data that is passed to the lex callback when it is called.
+ *
+ * @param parser The parser whose lex callback data we want to get.
+ * @returns The opaque data that is passed to the lex callback when it is called.
+ */
+PRISM_EXPORTED_FUNCTION void * pm_parser_lex_callback_data(const pm_parser_t *parser) PRISM_NONNULL(1);
- /** a rescue statement within a module statement */
- PM_CONTEXT_MODULE_RESCUE,
+/**
+ * Returns the raw pointer to the start of the source that is being parsed.
+ *
+ * @param parser the parser whose start pointer we want to get
+ * @returns the raw pointer to the start of the source that is being parsed
+ */
+PRISM_EXPORTED_FUNCTION const uint8_t * pm_parser_start(const pm_parser_t *parser) PRISM_NONNULL(1);
- /** a multiple target expression */
- PM_CONTEXT_MULTI_TARGET,
+/**
+ * Returns the raw pointer to the end of the source that is being parsed.
+ *
+ * @param parser the parser whose end pointer we want to get
+ * @returns the raw pointer to the end of the source that is being parsed
+ */
+PRISM_EXPORTED_FUNCTION const uint8_t * pm_parser_end(const pm_parser_t *parser) PRISM_NONNULL(1);
- /** a parenthesized expression */
- PM_CONTEXT_PARENS,
+/**
+ * Returns the line that the parser was considered to have started on.
+ *
+ * @param parser the parser whose start line we want to get
+ * @returns the line that the parser was considered to have started on
+ */
+PRISM_EXPORTED_FUNCTION int32_t pm_parser_start_line(const pm_parser_t *parser) PRISM_NONNULL(1);
- /** an END block */
- PM_CONTEXT_POSTEXE,
+/**
+ * Returns the name of the encoding that is being used to parse the source.
+ *
+ * @param parser the parser whose encoding name we want to get
+ * @returns the name of the encoding that is being used to parse the source
+ */
+PRISM_EXPORTED_FUNCTION const char * pm_parser_encoding_name(const pm_parser_t *parser) PRISM_NONNULL(1);
- /** a predicate inside an if/elsif/unless statement */
- PM_CONTEXT_PREDICATE,
+/**
+ * Returns the width of the character at the given pointer in the encoding that
+ * is being used to parse the source.
+ *
+ * @param parser the parser whose encoding we want to use
+ * @param start a pointer to the start of the character
+ * @param remaining the number of bytes remaining in the source
+ * @returns the width of the character in bytes
+ */
+PRISM_EXPORTED_FUNCTION size_t pm_parser_encoding_char_width(const pm_parser_t *parser, const uint8_t *start, ptrdiff_t remaining) PRISM_NONNULL(1, 2);
- /** a BEGIN block */
- PM_CONTEXT_PREEXE,
+/**
+ * Returns whether or not the parser is using the US-ASCII encoding.
+ *
+ * @param parser the parser to check
+ * @returns true if the parser is using US-ASCII encoding, false otherwise
+ */
+PRISM_EXPORTED_FUNCTION bool pm_parser_encoding_us_ascii(const pm_parser_t *parser) PRISM_NONNULL(1);
- /** a modifier rescue clause */
- PM_CONTEXT_RESCUE_MODIFIER,
+/**
+ * Returns the filepath that is being used to parse the source.
+ *
+ * @param parser the parser whose filepath we want to get
+ * @returns a pointer to the filepath string
+ */
+PRISM_EXPORTED_FUNCTION const pm_string_t * pm_parser_filepath(const pm_parser_t *parser) PRISM_NONNULL(1);
- /** a singleton class definition */
- PM_CONTEXT_SCLASS,
+/**
+ * Find a constant in the parser's constant pool. Returns the id of the
+ * constant, or 0 if the constant is not found.
+ *
+ * @param parser the parser whose constant pool we want to search
+ * @param start a pointer to the start of the string to search for
+ * @param length the length of the string to search for
+ * @returns the id of the constant, or 0 if the constant is not found
+ */
+PRISM_EXPORTED_FUNCTION pm_constant_id_t pm_parser_constant_find(const pm_parser_t *parser, const uint8_t *start, size_t length) PRISM_NONNULL(1, 2);
- /** an ensure statement with a singleton class */
- PM_CONTEXT_SCLASS_ENSURE,
+/**
+ * Returns the frozen string literal value of the parser, as determined by the
+ * frozen_string_literal magic comment or the option set on the parser.
+ *
+ * @param parser the parser whose frozen string literal value we want to get
+ * @returns -1 if disabled, 0 if unset, 1 if enabled
+ */
+PRISM_EXPORTED_FUNCTION int8_t pm_parser_frozen_string_literal(const pm_parser_t *parser) PRISM_NONNULL(1);
- /** a rescue else statement with a singleton class */
- PM_CONTEXT_SCLASS_ELSE,
+/**
+ * Returns the line offsets that are associated with the given parser.
+ *
+ * @param parser the parser whose line offsets we want to get
+ * @returns the line offsets that are associated with the given parser
+ */
+PRISM_EXPORTED_FUNCTION const pm_line_offset_list_t * pm_parser_line_offsets(const pm_parser_t *parser) PRISM_NONNULL(1);
- /** a rescue statement with a singleton class */
- PM_CONTEXT_SCLASS_RESCUE,
+/**
+ * Returns the location of the __DATA__ section that is associated with the
+ * given parser.
+ *
+ * @param parser the parser whose data location we want to get
+ * @returns the location of the __DATA__ section that is associated with the
+ * given parser. If it is unset, then the length will be set to 0.
+ */
+PRISM_EXPORTED_FUNCTION const pm_location_t * pm_parser_data_loc(const pm_parser_t *parser) PRISM_NONNULL(1);
- /** a ternary expression */
- PM_CONTEXT_TERNARY,
+/**
+ * Returns whether the given parser is continuable, meaning that it could become
+ * valid if more input were appended, as opposed to being definitively invalid.
+ *
+ * @param parser the parser whose continuable status we want to get
+ * @returns whether the given parser is continuable
+ */
+PRISM_EXPORTED_FUNCTION bool pm_parser_continuable(const pm_parser_t *parser) PRISM_NONNULL(1);
- /** an unless statement */
- PM_CONTEXT_UNLESS,
+/**
+ * Returns the lex state of the parser. Note that this is an internal detail,
+ * and we are purposefully not returning an instance of the internal enum that
+ * we use to track this. This is only exposed because we need it for some very
+ * niche use cases. Most consumers should avoid this function.
+ *
+ * @param parser the parser whose lex state we want to get
+ * @returns the lex state of the parser
+ */
+PRISM_EXPORTED_FUNCTION int pm_parser_lex_state(const pm_parser_t *parser) PRISM_NONNULL(1);
- /** an until statement */
- PM_CONTEXT_UNTIL,
+/**
+ * Returns the number of comments associated with the given parser.
+ *
+ * @param parser the parser whose comments we want to get the size of
+ * @returns the number of comments associated with the given parser
+ */
+PRISM_EXPORTED_FUNCTION size_t pm_parser_comments_size(const pm_parser_t *parser) PRISM_NONNULL(1);
- /** a while statement */
- PM_CONTEXT_WHILE,
-} pm_context_t;
+/**
+ * A callback function that can be used to process comments found while parsing.
+ */
+typedef void (*pm_comment_callback_t)(const pm_comment_t *comment, void *data);
-/** 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;
+/**
+ * Iterates over the comments associated with the given parser and calls the
+ * given callback for each comment.
+ *
+ * @param parser the parser whose comments we want to iterate over
+ * @param callback the callback function to call for each comment. This function
+ * will be passed a pointer to the comment and the data parameter passed to
+ * this function.
+ * @param data the data to pass to the callback function for each comment. This
+ * can be NULL if no data needs to be passed to the callback function.
+ */
+PRISM_EXPORTED_FUNCTION void pm_parser_comments_each(const pm_parser_t *parser, pm_comment_callback_t callback, void *data) PRISM_NONNULL(1);
- /** A pointer to the previous context in the linked list. */
- struct pm_context_node *prev;
-} pm_context_node_t;
+/**
+ * Returns the number of magic comments associated with the given parser.
+ *
+ * @param parser the parser whose magic comments we want to get the size of
+ * @returns the number of magic comments associated with the given parser
+ */
+PRISM_EXPORTED_FUNCTION size_t pm_parser_magic_comments_size(const pm_parser_t *parser) PRISM_NONNULL(1);
-/** 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;
+/**
+ * A callback function that can be used to process magic comments found while parsing.
+ */
+typedef void (*pm_magic_comment_callback_t)(const pm_magic_comment_t *magic_comment, void *data);
/**
- * This is a node in the linked list of comments that we've found while parsing.
+ * Iterates over the magic comments associated with the given parser and calls the
+ * given callback for each magic comment.
*
- * @extends pm_list_node_t
+ * @param parser the parser whose magic comments we want to iterate over
+ * @param callback the callback function to call for each magic comment. This
+ * function will be passed a pointer to the magic comment and the data
+ * parameter passed to this function.
+ * @param data the data to pass to the callback function for each magic comment.
+ * This can be NULL if no data needs to be passed to the callback function.
*/
-typedef struct pm_comment {
- /** The embedded base node. */
- pm_list_node_t node;
+PRISM_EXPORTED_FUNCTION void pm_parser_magic_comments_each(const pm_parser_t *parser, pm_magic_comment_callback_t callback, void *data) PRISM_NONNULL(1);
- /** The location of the comment in the source. */
- pm_location_t location;
+/**
+ * Returns the number of errors associated with the given parser.
+ *
+ * @param parser the parser whose errors we want to get the size of
+ * @returns the number of errors associated with the given parser
+ */
+PRISM_EXPORTED_FUNCTION size_t pm_parser_errors_size(const pm_parser_t *parser) PRISM_NONNULL(1);
- /** The type of comment that we've found. */
- pm_comment_type_t type;
-} pm_comment_t;
+/**
+ * Returns the number of warnings associated with the given parser.
+ *
+ * @param parser the parser whose warnings we want to get the size of
+ * @returns the number of warnings associated with the given parser
+ */
+PRISM_EXPORTED_FUNCTION size_t pm_parser_warnings_size(const pm_parser_t *parser) PRISM_NONNULL(1);
/**
- * This is a node in the linked list of magic comments that we've found while
+ * A callback function that can be used to process diagnostics found while
* parsing.
+ */
+typedef void (*pm_diagnostic_callback_t)(const pm_diagnostic_t *diagnostic, void *data);
+
+/**
+ * Iterates over the errors associated with the given parser and calls the
+ * given callback for each error.
*
- * @extends pm_list_node_t
+ * @param parser the parser whose errors we want to iterate over
+ * @param callback the callback function to call for each error. This function
+ * will be passed a pointer to the error and the data parameter passed to
+ * this function.
+ * @param data the data to pass to the callback function for each error. This
+ * can be NULL if no data needs to be passed to the callback function.
*/
-typedef struct {
- /** The embedded base node. */
- pm_list_node_t node;
+PRISM_EXPORTED_FUNCTION void pm_parser_errors_each(const pm_parser_t *parser, pm_diagnostic_callback_t callback, void *data) PRISM_NONNULL(1);
- /** A pointer to the start of the key in the source. */
- const uint8_t *key_start;
+/**
+ * Iterates over the warnings associated with the given parser and calls the
+ * given callback for each warning.
+ *
+ * @param parser the parser whose warnings we want to iterate over
+ * @param callback the callback function to call for each warning. This function
+ * will be passed a pointer to the warning and the data parameter passed to
+ * this function.
+ * @param data the data to pass to the callback function for each warning. This
+ * can be NULL if no data needs to be passed to the callback function.
+ */
+PRISM_EXPORTED_FUNCTION void pm_parser_warnings_each(const pm_parser_t *parser, pm_diagnostic_callback_t callback, void *data) PRISM_NONNULL(1);
- /** A pointer to the start of the value in the source. */
- const uint8_t *value_start;
+/**
+ * Returns the number of constants in the constant pool associated with the
+ * given parser.
+ *
+ * @param parser the parser whose constant pool constants we want to get the
+ * size of
+ * @returns the number of constants in the constant pool associated with the
+ * given parser
+ */
+PRISM_EXPORTED_FUNCTION size_t pm_parser_constants_size(const pm_parser_t *parser) PRISM_NONNULL(1);
- /** The length of the key in the source. */
- uint32_t key_length;
+/**
+ * A callback function that can be used to process constants found while
+ * parsing.
+ */
+typedef void (*pm_constant_callback_t)(const pm_constant_t *constant, void *data);
- /** The length of the value in the source. */
- uint32_t value_length;
-} pm_magic_comment_t;
+/**
+ * Iterates over the constants in the constant pool associated with the given
+ * parser and calls the given callback for each constant.
+ *
+ * @param parser the parser whose constants we want to iterate over
+ * @param callback the callback function to call for each constant. This function
+ * will be passed a pointer to the constant and the data parameter passed to
+ * this function.
+ * @param data the data to pass to the callback function for each constant. This
+ * can be NULL if no data needs to be passed to the callback function.
+ */
+PRISM_EXPORTED_FUNCTION void pm_parser_constants_each(const pm_parser_t *parser, pm_constant_callback_t callback, void *data) PRISM_NONNULL(1);
/**
- * 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.
+ * Returns a pointer to the constant at the given id in the constant pool
+ * associated with the given parser.
+ *
+ * @param parser the parser whose constant pool we want to look up from
+ * @param constant_id the id of the constant to look up (1-based)
+ * @returns a pointer to the constant at the given id
*/
-typedef void (*pm_encoding_changed_callback_t)(pm_parser_t *parser);
+PRISM_EXPORTED_FUNCTION const pm_constant_t * pm_parser_constant(const pm_parser_t *parser, pm_constant_id_t constant_id) PRISM_NONNULL(1);
/**
- * 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;
-};
+ * Initiate the parser with the given parser.
+ *
+ * @param parser The parser to use.
+ * @returns The AST representing the source.
+ */
+PRISM_EXPORTED_FUNCTION pm_node_t * pm_parse(pm_parser_t *parser) PRISM_NONNULL(1);
#endif
diff --git a/prism/prettyprint.h b/prism/prettyprint.h
index 5a52b2b6b8..0d8e416341 100644
--- a/prism/prettyprint.h
+++ b/prism/prettyprint.h
@@ -6,19 +6,16 @@
#ifndef PRISM_PRETTYPRINT_H
#define PRISM_PRETTYPRINT_H
-#include "prism/defines.h"
+#include "prism/excludes.h"
-#ifdef PRISM_EXCLUDE_PRETTYPRINT
+#ifndef PRISM_EXCLUDE_PRETTYPRINT
-void pm_prettyprint(void);
-
-#else
-
-#include <stdio.h>
+#include "prism/compiler/exported.h"
+#include "prism/compiler/nonnull.h"
#include "prism/ast.h"
+#include "prism/buffer.h"
#include "prism/parser.h"
-#include "prism/util/pm_buffer.h"
/**
* Pretty-prints the AST represented by the given node to the given buffer.
@@ -27,7 +24,7 @@ void pm_prettyprint(void);
* @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);
+PRISM_EXPORTED_FUNCTION void pm_prettyprint(pm_buffer_t *output_buffer, const pm_parser_t *parser, const pm_node_t *node) PRISM_NONNULL(1, 2, 3);
#endif
diff --git a/prism/prism.c b/prism/prism.c
index afd767b84c..a2e04ed106 100644
--- a/prism/prism.c
+++ b/prism/prism.c
@@ -1,4 +1,90 @@
-#include "prism.h"
+#include "prism/compiler/accel.h"
+#include "prism/compiler/fallthrough.h"
+#include "prism/compiler/unused.h"
+
+#include "prism/internal/allocator.h"
+#include "prism/internal/arena.h"
+#include "prism/internal/bit.h"
+#include "prism/internal/buffer.h"
+#include "prism/internal/char.h"
+#include "prism/internal/comments.h"
+#include "prism/internal/constant_pool.h"
+#include "prism/internal/diagnostic.h"
+#include "prism/internal/encoding.h"
+#include "prism/internal/integer.h"
+#include "prism/internal/isinf.h"
+#include "prism/internal/line_offset_list.h"
+#include "prism/internal/list.h"
+#include "prism/internal/magic_comments.h"
+#include "prism/internal/memchr.h"
+#include "prism/internal/node.h"
+#include "prism/internal/options.h"
+#include "prism/internal/parser.h"
+#include "prism/internal/regexp.h"
+#include "prism/internal/serialize.h"
+#include "prism/internal/source.h"
+#include "prism/internal/static_literals.h"
+#include "prism/internal/stringy.h"
+#include "prism/internal/strncasecmp.h"
+#include "prism/internal/strpbrk.h"
+#include "prism/internal/tokens.h"
+
+#include "prism/excludes.h"
+#include "prism/serialize.h"
+#include "prism/stream.h"
+#include "prism/version.h"
+
+#include <assert.h>
+#include <errno.h>
+#include <limits.h>
+#include <locale.h>
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.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 10000
+#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
+
+/**
+ * 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
/**
* The prism version and the serialization format.
@@ -19,6 +105,51 @@ pm_version(void) {
#define MAX(a,b) (((a)>(b))?(a):(b))
/******************************************************************************/
+/* Helpful AST-related macros */
+/******************************************************************************/
+
+#define U32(value_) ((uint32_t) (value_))
+
+#define FL PM_NODE_FLAGS
+#define UP PM_NODE_UPCAST
+
+#define PM_LOCATION_START(location_) ((location_)->start)
+#define PM_LOCATION_END(location_) ((location_)->start + (location_)->length)
+
+#define PM_TOKEN_START(parser_, token_) U32((token_)->start - (parser_)->start)
+#define PM_TOKEN_END(parser_, token_) U32((token_)->end - (parser_)->start)
+#define PM_TOKEN_LENGTH(token_) U32((token_)->end - (token_)->start)
+#define PM_TOKENS_LENGTH(left_, right_) U32((right_)->end - (left_)->start)
+
+#define PM_NODE_START(node_) (UP(node_)->location.start)
+#define PM_NODE_LENGTH(node_) (UP(node_)->location.length)
+#define PM_NODE_END(node_) (UP(node_)->location.start + UP(node_)->location.length)
+#define PM_NODES_LENGTH(left_, right_) (PM_NODE_END(right_) - PM_NODE_START(left_))
+
+#define PM_TOKEN_NODE_LENGTH(parser_, token_, node_) (PM_NODE_END(node_) - PM_TOKEN_START(parser_, token_))
+#define PM_NODE_TOKEN_LENGTH(parser_, node_, token_) (PM_TOKEN_END(parser_, token_) - PM_NODE_START(node_))
+
+#define PM_NODE_START_SET_NODE(left_, right_) (PM_NODE_START(left_) = PM_NODE_START(right_))
+#define PM_NODE_START_SET_TOKEN(parser_, node_, token_) (PM_NODE_START(node_) = PM_TOKEN_START(parser_, token_))
+#define PM_NODE_LENGTH_SET_NODE(left_, right_) (PM_NODE_LENGTH(left_) = PM_NODE_END(right_) - PM_NODE_START(left_))
+#define PM_NODE_LENGTH_SET_TOKEN(parser_, node_, token_) (PM_NODE_LENGTH(node_) = PM_TOKEN_END(parser_, token_) - PM_NODE_START(node_))
+#define PM_NODE_LENGTH_SET_LOCATION(node_, location_) (PM_NODE_LENGTH(node_) = PM_LOCATION_END(location_) - PM_NODE_START(node_))
+
+#define PM_LOCATION_INIT(start_, length_) ((pm_location_t) { .start = (start_), .length = (length_) })
+#define PM_LOCATION_INIT_UNSET PM_LOCATION_INIT(0, 0)
+#define PM_LOCATION_INIT_TOKEN(parser_, token_) PM_LOCATION_INIT(PM_TOKEN_START(parser_, token_), PM_TOKEN_LENGTH(token_))
+#define PM_LOCATION_INIT_NODE(node_) UP(node_)->location
+
+#define PM_LOCATION_INIT_TOKENS(parser_, left_, right_) PM_LOCATION_INIT(PM_TOKEN_START(parser_, left_), PM_TOKENS_LENGTH(left_, right_))
+#define PM_LOCATION_INIT_NODES(left_, right_) PM_LOCATION_INIT(PM_NODE_START(left_), PM_NODES_LENGTH(left_, right_))
+#define PM_LOCATION_INIT_TOKEN_NODE(parser_, token_, node_) PM_LOCATION_INIT(PM_TOKEN_START(parser_, token_), PM_TOKEN_NODE_LENGTH(parser_, token_, node_))
+#define PM_LOCATION_INIT_NODE_TOKEN(parser_, node_, token_) PM_LOCATION_INIT(PM_NODE_START(node_), PM_NODE_TOKEN_LENGTH(parser_, node_, token_))
+
+#define TOK2LOC(parser_, token_) PM_LOCATION_INIT_TOKEN(parser_, token_)
+#define NTOK2LOC(parser_, token_) ((token_) == NULL ? PM_LOCATION_INIT_UNSET : TOK2LOC(parser_, token_))
+#define NTOK2PTR(token_) ((token_).start == NULL ? NULL : &(token_))
+
+/******************************************************************************/
/* Lex mode manipulations */
/******************************************************************************/
@@ -26,7 +157,7 @@ pm_version(void) {
* Returns the incrementor character that should be used to increment the
* nesting count if one is possible.
*/
-static inline uint8_t
+static PRISM_INLINE uint8_t
lex_mode_incrementor(const uint8_t start) {
switch (start) {
case '(':
@@ -43,7 +174,7 @@ lex_mode_incrementor(const uint8_t start) {
* Returns the matching character that should be used to terminate a list
* beginning with the given character.
*/
-static inline uint8_t
+static PRISM_INLINE uint8_t
lex_mode_terminator(const uint8_t start) {
switch (start) {
case '(':
@@ -85,7 +216,7 @@ lex_mode_push(pm_parser_t *parser, pm_lex_mode_t lex_mode) {
/**
* Push on a new list lex mode.
*/
-static inline bool
+static PRISM_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);
@@ -103,7 +234,8 @@ lex_mode_push_list(pm_parser_t *parser, bool interpolation, uint8_t delimiter) {
// 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));
+ memset(breakpoints, 0, PM_STRPBRK_CACHE_SIZE);
+ memcpy(breakpoints, "\\ \t\f\r\v\n", sizeof("\\ \t\f\r\v\n") - 1);
size_t index = 7;
// Now we'll add the terminator to the list of breakpoints. If the
@@ -132,7 +264,7 @@ lex_mode_push_list(pm_parser_t *parser, bool interpolation, uint8_t delimiter) {
* 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
+static PRISM_INLINE bool
lex_mode_push_list_eof(pm_parser_t *parser) {
return lex_mode_push_list(parser, false, '\0');
}
@@ -140,7 +272,7 @@ lex_mode_push_list_eof(pm_parser_t *parser) {
/**
* Push on a new regexp lex mode.
*/
-static inline bool
+static PRISM_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,
@@ -155,7 +287,8 @@ lex_mode_push_regexp(pm_parser_t *parser, uint8_t incrementor, uint8_t terminato
// 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));
+ memset(breakpoints, 0, PM_STRPBRK_CACHE_SIZE);
+ memcpy(breakpoints, "\r\n\\#", sizeof("\r\n\\#") - 1);
size_t index = 4;
// First we'll add the terminator.
@@ -175,7 +308,7 @@ lex_mode_push_regexp(pm_parser_t *parser, uint8_t incrementor, uint8_t terminato
/**
* Push on a new string lex mode.
*/
-static inline bool
+static PRISM_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,
@@ -191,7 +324,8 @@ lex_mode_push_string(pm_parser_t *parser, bool interpolation, bool label_allowed
// 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));
+ memset(breakpoints, 0, PM_STRPBRK_CACHE_SIZE);
+ memcpy(breakpoints, "\r\n\\", sizeof("\r\n\\") - 1);
size_t index = 3;
// Now add in the terminator. If the terminator is not already a NULL byte,
@@ -221,7 +355,7 @@ lex_mode_push_string(pm_parser_t *parser, bool interpolation, bool label_allowed
* 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
+static PRISM_INLINE bool
lex_mode_push_string_eof(pm_parser_t *parser) {
return lex_mode_push_string(parser, false, false, '\0', '\0');
}
@@ -241,7 +375,7 @@ lex_mode_pop(pm_parser_t *parser) {
} else {
parser->lex_modes.index--;
pm_lex_mode_t *prev = parser->lex_modes.current->prev;
- xfree(parser->lex_modes.current);
+ xfree_sized(parser->lex_modes.current, sizeof(pm_lex_mode_t));
parser->lex_modes.current = prev;
}
}
@@ -249,7 +383,7 @@ lex_mode_pop(pm_parser_t *parser) {
/**
* This is the equivalent of IS_lex_state is CRuby.
*/
-static inline bool
+static PRISM_INLINE bool
lex_state_p(const pm_parser_t *parser, pm_lex_state_t state) {
return parser->lex_state & state;
}
@@ -260,7 +394,7 @@ typedef enum {
PM_IGNORED_NEWLINE_PATTERN
} pm_ignored_newline_type_t;
-static inline pm_ignored_newline_type_t
+static PRISM_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);
@@ -273,17 +407,17 @@ lex_state_ignored_p(pm_parser_t *parser) {
}
}
-static inline bool
+static PRISM_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
+static PRISM_INLINE bool
lex_state_arg_p(pm_parser_t *parser) {
return lex_state_p(parser, PM_LEX_STATE_ARG_ANY);
}
-static inline bool
+static PRISM_INLINE bool
lex_state_spcarg_p(pm_parser_t *parser, bool space_seen) {
if (parser->current.end >= parser->end) {
return false;
@@ -291,7 +425,7 @@ lex_state_spcarg_p(pm_parser_t *parser, bool space_seen) {
return lex_state_arg_p(parser) && space_seen && !pm_char_is_whitespace(*parser->current.end);
}
-static inline bool
+static PRISM_INLINE bool
lex_state_end_p(pm_parser_t *parser) {
return lex_state_p(parser, PM_LEX_STATE_END_ANY);
}
@@ -299,7 +433,7 @@ lex_state_end_p(pm_parser_t *parser) {
/**
* This is the equivalent of IS_AFTER_OPERATOR in CRuby.
*/
-static inline bool
+static PRISM_INLINE bool
lex_state_operator_p(pm_parser_t *parser) {
return lex_state_p(parser, PM_LEX_STATE_FNAME | PM_LEX_STATE_DOT);
}
@@ -308,7 +442,7 @@ lex_state_operator_p(pm_parser_t *parser) {
* Set the state of the lexer. This is defined as a function to be able to put a
* breakpoint in it.
*/
-static inline void
+static PRISM_INLINE void
lex_state_set(pm_parser_t *parser, pm_lex_state_t state) {
parser->lex_state = state;
}
@@ -322,7 +456,7 @@ lex_state_set(pm_parser_t *parser, pm_lex_state_t state) {
#endif
#if PM_DEBUG_LOGGING
-PRISM_ATTRIBUTE_UNUSED static void
+PRISM_UNUSED static void
debug_state(pm_parser_t *parser) {
fprintf(stderr, "STATE: ");
bool first = true;
@@ -403,140 +537,134 @@ debug_lex_state_set(pm_parser_t *parser, pm_lex_state_t state, char const * call
/**
* 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);
+static PRISM_INLINE void
+pm_parser_err(pm_parser_t *parser, uint32_t start, uint32_t length, pm_diagnostic_id_t diag_id) {
+ pm_diagnostic_list_append(&parser->metadata_arena, &parser->error_list, start, length, diag_id);
}
/**
- * Append an error to the list of errors on the parser using a format string.
+ * Append an error to the list of errors on the parser using the location of the
+ * given token.
*/
-#define PM_PARSER_ERR_FORMAT(parser, start, end, diag_id, ...) \
- pm_diagnostic_list_append_format(&parser->error_list, start, end, diag_id, __VA_ARGS__)
+static PRISM_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, PM_TOKEN_START(parser, token), PM_TOKEN_LENGTH(token), diag_id);
+}
/**
* Append an error to the list of errors on the parser using the location of the
* current token.
*/
-static inline void
+static PRISM_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);
+ pm_parser_err_token(parser, &parser->current, diag_id);
}
/**
- * Append an error to the list of errors on the parser using the given location
- * using a format string.
+ * Append an error to the list of errors on the parser using the location of the
+ * previous token.
*/
-#define PM_PARSER_ERR_LOCATION_FORMAT(parser, location, diag_id, ...) \
- PM_PARSER_ERR_FORMAT(parser, (location)->start, (location)->end, diag_id, __VA_ARGS__)
+static PRISM_INLINE void
+pm_parser_err_previous(pm_parser_t *parser, pm_diagnostic_id_t diag_id) {
+ pm_parser_err_token(parser, &parser->previous, diag_id);
+}
/**
* Append an error to the list of errors on the parser using the location of the
* given node.
*/
-static inline void
+static PRISM_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);
+ pm_parser_err(parser, PM_NODE_START(node), PM_NODE_LENGTH(node), 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.
+ * Append an error to the list of errors on the parser using a format string.
*/
-#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)
+#define PM_PARSER_ERR_FORMAT(parser_, start_, length_, diag_id_, ...) \
+ pm_diagnostic_list_append_format(&(parser_)->metadata_arena, &(parser_)->error_list, start_, length_, diag_id_, __VA_ARGS__)
/**
* Append an error to the list of errors on the parser using the location of the
- * previous token.
+ * given node and a format string.
*/
-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);
-}
+#define PM_PARSER_ERR_NODE_FORMAT(parser_, node_, diag_id_, ...) \
+ PM_PARSER_ERR_FORMAT(parser_, PM_NODE_START(node_), PM_NODE_LENGTH(node_), diag_id_, __VA_ARGS__)
/**
* Append an error to the list of errors on the parser using the location of the
- * given token.
+ * given node and a format string, and add on the content of the node.
*/
-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);
-}
+#define PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser_, node_, diag_id_) \
+ PM_PARSER_ERR_NODE_FORMAT(parser_, node_, diag_id_, (int) PM_NODE_LENGTH(node_), (const char *) (parser_->start + PM_NODE_START(node_)))
/**
* 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__)
+#define PM_PARSER_ERR_TOKEN_FORMAT(parser_, token_, diag_id, ...) \
+ PM_PARSER_ERR_FORMAT(parser_, PM_TOKEN_START(parser_, token_), PM_TOKEN_LENGTH(token_), 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)
+#define PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser_, token_, diag_id_) \
+ PM_PARSER_ERR_TOKEN_FORMAT(parser_, token_, diag_id_, (int) PM_TOKEN_LENGTH(token_), (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);
+static PRISM_INLINE void
+pm_parser_warn(pm_parser_t *parser, uint32_t start, uint32_t length, pm_diagnostic_id_t diag_id) {
+ pm_diagnostic_list_append(&parser->metadata_arena, &parser->warning_list, start, length, diag_id);
}
/**
* Append a warning to the list of warnings on the parser using the location of
* the given token.
*/
-static inline void
+static PRISM_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);
+ pm_parser_warn(parser, PM_TOKEN_START(parser, token), PM_TOKEN_LENGTH(token), diag_id);
}
/**
* Append a warning to the list of warnings on the parser using the location of
* the given node.
*/
-static inline void
+static PRISM_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);
+ pm_parser_warn(parser, PM_NODE_START(node), PM_NODE_LENGTH(node), diag_id);
}
/**
- * Append a warning to the list of warnings on the parser using a format string.
+ * Append a warning to the list of warnings on the parser using a format string
+ * and the given location.
*/
-#define PM_PARSER_WARN_FORMAT(parser, start, end, diag_id, ...) \
- pm_diagnostic_list_append_format(&parser->warning_list, start, end, diag_id, __VA_ARGS__)
+#define PM_PARSER_WARN_FORMAT(parser_, start_, length_, diag_id_, ...) \
+ pm_diagnostic_list_append_format(&(parser_)->metadata_arena, &(parser_)->warning_list, start_, length_, 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__)
+#define PM_PARSER_WARN_TOKEN_FORMAT(parser_, token_, diag_id_, ...) \
+ PM_PARSER_WARN_FORMAT(parser_, PM_TOKEN_START(parser_, token_), PM_TOKEN_LENGTH(token_), 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)
+#define PM_PARSER_WARN_TOKEN_FORMAT_CONTENT(parser_, token_, diag_id_) \
+ PM_PARSER_WARN_TOKEN_FORMAT(parser_, token_, diag_id_, (int) PM_TOKEN_LENGTH(token_), (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__)
+#define PM_PARSER_WARN_NODE_FORMAT(parser_, node_, diag_id_, ...) \
+ PM_PARSER_WARN_FORMAT(parser_, PM_NODE_START(node_), PM_NODE_LENGTH(node_), diag_id_, __VA_ARGS__)
/**
* Add an error for an expected heredoc terminator. This is a special function
@@ -547,8 +675,8 @@ 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,
+ U32(ident_start - parser->start),
+ U32(ident_length),
PM_ERR_HEREDOC_TERM,
(int) ident_length,
(const char *) ident_start
@@ -708,7 +836,7 @@ pm_parser_scope_forwarding_keywords_check(pm_parser_t *parser, const pm_token_t
/**
* Get the current state of constant shareability.
*/
-static inline pm_shareable_constant_value_t
+static PRISM_INLINE pm_shareable_constant_value_t
pm_parser_scope_shareable_constant_get(pm_parser_t *parser) {
return parser->current_scope->shareable_constant;
}
@@ -733,12 +861,12 @@ pm_parser_scope_shareable_constant_set(pm_parser_t *parser, pm_shareable_constan
/**
* The point at which the set of locals switches from being a list to a hash.
*/
-#define PM_LOCALS_HASH_THRESHOLD 9
+#define PM_LOCALS_HASH_THRESHOLD 5
static void
pm_locals_free(pm_locals_t *locals) {
if (locals->capacity > 0) {
- xfree(locals->locals);
+ xfree_sized(locals->locals, locals->capacity * sizeof(pm_local_t));
}
}
@@ -810,11 +938,13 @@ pm_locals_resize(pm_locals_t *locals) {
* @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) {
+pm_locals_write(pm_locals_t *locals, pm_constant_id_t name, uint32_t start, uint32_t length, uint32_t reads) {
if (locals->size >= (locals->capacity / 4 * 3)) {
pm_locals_resize(locals);
}
+ locals->bloom |= (1u << (name & 31));
+
if (locals->capacity < PM_LOCALS_HASH_THRESHOLD) {
for (uint32_t index = 0; index < locals->capacity; index++) {
pm_local_t *local = &locals->locals[index];
@@ -822,7 +952,7 @@ pm_locals_write(pm_locals_t *locals, pm_constant_id_t name, const uint8_t *start
if (local->name == PM_CONSTANT_ID_UNSET) {
*local = (pm_local_t) {
.name = name,
- .location = { .start = start, .end = end },
+ .location = { .start = start, .length = length },
.index = locals->size++,
.reads = reads,
.hash = 0
@@ -843,7 +973,7 @@ pm_locals_write(pm_locals_t *locals, pm_constant_id_t name, const uint8_t *start
if (local->name == PM_CONSTANT_ID_UNSET) {
*local = (pm_local_t) {
.name = name,
- .location = { .start = start, .end = end },
+ .location = { .start = start, .length = length },
.index = locals->size++,
.reads = reads,
.hash = initial_hash
@@ -867,6 +997,8 @@ pm_locals_write(pm_locals_t *locals, pm_constant_id_t name, const uint8_t *start
*/
static uint32_t
pm_locals_find(pm_locals_t *locals, pm_constant_id_t name) {
+ if (!(locals->bloom & (1u << (name & 31)))) return UINT32_MAX;
+
if (locals->capacity < PM_LOCALS_HASH_THRESHOLD) {
for (uint32_t index = 0; index < locals->size; index++) {
pm_local_t *local = &locals->locals[index];
@@ -943,8 +1075,8 @@ pm_locals_reads(pm_locals_t *locals, pm_constant_id_t name) {
* 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);
+pm_locals_order(pm_parser_t *parser, pm_locals_t *locals, pm_constant_id_list_t *list, bool toplevel) {
+ pm_constant_id_list_init_capacity(parser->arena, 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
@@ -961,14 +1093,14 @@ pm_locals_order(PRISM_ATTRIBUTE_UNUSED pm_parser_t *parser, pm_locals_t *locals,
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 && ((parser->start_line >= 0) || (pm_newline_list_line(&parser->newline_list, local->location.start, parser->start_line) >= 0))) {
+ if (warn_unused && local->reads == 0 && ((parser->start_line >= 0) || (pm_line_offset_list_line(&parser->line_offsets, local->location.start, parser->start_line) >= 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,
+ local->location.length,
PM_WARN_UNUSED_LOCAL_VARIABLE,
(int) constant->length,
(const char *) constant->start
@@ -986,43 +1118,53 @@ pm_locals_order(PRISM_ATTRIBUTE_UNUSED pm_parser_t *parser, pm_locals_t *locals,
/**
* 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));
+static PRISM_INLINE pm_constant_id_t
+pm_parser_constant_id_raw(pm_parser_t *parser, const uint8_t *start, const uint8_t *end) {
+ /* Fast path: if this is the same token as the last lookup (same pointer
+ * range), return the cached result. */
+ if (start == parser->constant_cache.start && end == parser->constant_cache.end) {
+ return parser->constant_cache.id;
+ }
+
+ pm_constant_id_t id = pm_constant_pool_insert_shared(&parser->metadata_arena, &parser->constant_pool, start, (size_t) (end - start));
+
+ parser->constant_cache.start = start;
+ parser->constant_cache.end = end;
+ parser->constant_cache.id = id;
+
+ return id;
}
/**
* Retrieve the constant pool id for the given string.
*/
-static inline pm_constant_id_t
+static PRISM_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);
+ return pm_constant_pool_insert_owned(&parser->metadata_arena, &parser->constant_pool, start, length);
}
/**
* Retrieve the constant pool id for the given static literal C string.
*/
-static inline pm_constant_id_t
+static PRISM_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);
+ return pm_constant_pool_insert_constant(&parser->metadata_arena, &parser->constant_pool, (const uint8_t *) start, length);
}
/**
* Retrieve the constant pool id for the given token.
*/
-static inline pm_constant_id_t
+static PRISM_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);
+ return pm_parser_constant_id_raw(parser, token->start, token->end);
}
/**
- * Retrieve the constant pool id for the given token. If the token is not
- * provided, then return 0.
+ * This macro allows you to define a case statement for all of the nodes that
+ * may result in a void value.
*/
-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);
-}
+#define PM_CASE_VOID_VALUE PM_RETURN_NODE: case PM_BREAK_NODE: case PM_NEXT_NODE: \
+ case PM_REDO_NODE: case PM_RETRY_NODE: case PM_MATCH_REQUIRED_NODE
/**
* Check whether or not the given node is value expression.
@@ -1035,12 +1177,7 @@ pm_check_value_expression(pm_parser_t *parser, pm_node_t *node) {
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:
+ case PM_CASE_VOID_VALUE:
return void_node != NULL ? void_node : node;
case PM_MATCH_PREDICATE_NODE:
return NULL;
@@ -1049,57 +1186,128 @@ pm_check_value_expression(pm_parser_t *parser, pm_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);
+ pm_node_t *vn = pm_check_value_expression(parser, UP(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);
+ pm_node_t *vn = pm_check_value_expression(parser, UP(cast->statements));
if (vn != NULL) return vn;
}
- node = (pm_node_t *) cast->ensure_clause;
+ node = UP(cast->ensure_clause);
} else if (cast->rescue_clause != NULL) {
- if (cast->statements == NULL) return NULL;
+ // https://bugs.ruby-lang.org/issues/21669
+ if (cast->else_clause == NULL || parser->version < PM_OPTIONS_VERSION_CRUBY_4_1) {
+ 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;
+ pm_node_t *vn = pm_check_value_expression(parser, UP(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);
+ pm_node_t *vn = pm_check_value_expression(parser, UP(rescue_clause->statements));
+
if (vn == NULL) {
+ // https://bugs.ruby-lang.org/issues/21669
+ if (parser->version >= PM_OPTIONS_VERSION_CRUBY_4_1) {
+ return NULL;
+ }
void_node = NULL;
break;
}
- if (void_node == NULL) {
- void_node = vn;
- }
}
if (cast->else_clause != NULL) {
- node = (pm_node_t *) cast->else_clause;
+ node = UP(cast->else_clause);
+
+ // https://bugs.ruby-lang.org/issues/21669
+ if (parser->version >= PM_OPTIONS_VERSION_CRUBY_4_1) {
+ pm_node_t *vn = pm_check_value_expression(parser, node);
+ if (vn != NULL) return vn;
+ }
} else {
return void_node;
}
} else {
- node = (pm_node_t *) cast->statements;
+ node = UP(cast->statements);
}
break;
}
+ case PM_CASE_NODE: {
+ // https://bugs.ruby-lang.org/issues/21669
+ if (parser->version < PM_OPTIONS_VERSION_CRUBY_4_1) {
+ return NULL;
+ }
+
+ pm_case_node_t *cast = (pm_case_node_t *) node;
+ if (cast->else_clause == NULL) return NULL;
+
+ pm_node_t *condition;
+ PM_NODE_LIST_FOREACH(&cast->conditions, index, condition) {
+ assert(PM_NODE_TYPE_P(condition, PM_WHEN_NODE));
+
+ pm_when_node_t *cast = (pm_when_node_t *) condition;
+ pm_node_t *vn = pm_check_value_expression(parser, UP(cast->statements));
+ if (vn == NULL) return NULL;
+ if (void_node == NULL) void_node = vn;
+ }
+
+ node = UP(cast->else_clause);
+ break;
+ }
+ case PM_CASE_MATCH_NODE: {
+ // https://bugs.ruby-lang.org/issues/21669
+ if (parser->version < PM_OPTIONS_VERSION_CRUBY_4_1) {
+ return NULL;
+ }
+
+ pm_case_match_node_t *cast = (pm_case_match_node_t *) node;
+ if (cast->else_clause == NULL) return NULL;
+
+ pm_node_t *condition;
+ PM_NODE_LIST_FOREACH(&cast->conditions, index, condition) {
+ assert(PM_NODE_TYPE_P(condition, PM_IN_NODE));
+
+ pm_in_node_t *cast = (pm_in_node_t *) condition;
+ pm_node_t *vn = pm_check_value_expression(parser, UP(cast->statements));
+ if (vn == NULL) return NULL;
+ if (void_node == NULL) void_node = vn;
+ }
+
+ node = UP(cast->else_clause);
+ break;
+ }
case PM_ENSURE_NODE: {
pm_ensure_node_t *cast = (pm_ensure_node_t *) node;
- node = (pm_node_t *) cast->statements;
+ node = UP(cast->statements);
break;
}
case PM_PARENTHESES_NODE: {
pm_parentheses_node_t *cast = (pm_parentheses_node_t *) node;
- node = (pm_node_t *) cast->body;
+ node = UP(cast->body);
break;
}
case PM_STATEMENTS_NODE: {
pm_statements_node_t *cast = (pm_statements_node_t *) node;
+
+ // https://bugs.ruby-lang.org/issues/21669
+ if (parser->version >= PM_OPTIONS_VERSION_CRUBY_4_1) {
+ pm_node_t *body_part;
+ PM_NODE_LIST_FOREACH(&cast->body, index, body_part) {
+ switch (PM_NODE_TYPE(body_part)) {
+ case PM_CASE_VOID_VALUE:
+ if (void_node == NULL) {
+ void_node = body_part;
+ }
+ return void_node;
+ default: break;
+ }
+ }
+ }
+
node = cast->body.nodes[cast->body.size - 1];
break;
}
@@ -1108,7 +1316,7 @@ pm_check_value_expression(pm_parser_t *parser, pm_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);
+ pm_node_t *vn = pm_check_value_expression(parser, UP(cast->statements));
if (vn == NULL) {
return NULL;
}
@@ -1123,19 +1331,19 @@ pm_check_value_expression(pm_parser_t *parser, pm_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);
+ pm_node_t *vn = pm_check_value_expression(parser, UP(cast->statements));
if (vn == NULL) {
return NULL;
}
if (void_node == NULL) {
void_node = vn;
}
- node = (pm_node_t *) cast->else_clause;
+ node = UP(cast->else_clause);
break;
}
case PM_ELSE_NODE: {
pm_else_node_t *cast = (pm_else_node_t *) node;
- node = (pm_node_t *) cast->statements;
+ node = UP(cast->statements);
break;
}
case PM_AND_NODE: {
@@ -1165,7 +1373,7 @@ pm_check_value_expression(pm_parser_t *parser, pm_node_t *node) {
return NULL;
}
-static inline void
+static PRISM_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) {
@@ -1193,7 +1401,7 @@ pm_void_statement_check(pm_parser_t *parser, const pm_node_t *node) {
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;
+ if (cast->call_operator_loc.length > 0 || cast->message_loc.length == 0) break;
const pm_constant_t *message = pm_constant_pool_id_to_constant(&parser->constant_pool, cast->name);
switch (message->length) {
@@ -1406,7 +1614,7 @@ pm_conditional_predicate_warn_write_literal_p(const pm_node_t *node) {
* 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
+static PRISM_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);
@@ -1547,26 +1755,6 @@ pm_conditional_predicate(pm_parser_t *parser, pm_node_t *node, pm_conditional_pr
}
/**
- * 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
@@ -1592,22 +1780,29 @@ typedef struct {
/**
* Retrieve the end location of a `pm_arguments_t` object.
*/
-static inline const uint8_t *
+static PRISM_INLINE const pm_location_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;
+ uint32_t end = PM_NODE_END(arguments->block);
+
+ if (arguments->closing_loc.length > 0) {
+ uint32_t arguments_end = PM_LOCATION_END(&arguments->closing_loc);
+ if (arguments_end > end) {
+ return &arguments->closing_loc;
+ }
}
- return end;
+ return &arguments->block->location;
}
- if (arguments->closing_loc.start != NULL) {
- return arguments->closing_loc.end;
+ if (arguments->closing_loc.length > 0) {
+ return &arguments->closing_loc;
}
if (arguments->arguments != NULL) {
- return arguments->arguments->base.location.end;
+ return &arguments->arguments->base.location;
+ }
+ if (arguments->opening_loc.length > 0) {
+ return &arguments->opening_loc;
}
- return arguments->closing_loc.end;
+ return NULL;
}
/**
@@ -1618,7 +1813,7 @@ 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) {
+ if (arguments->arguments == NULL || arguments->closing_loc.length > 0) {
return;
}
@@ -1635,7 +1830,7 @@ pm_arguments_validate_block(pm_parser_t *parser, pm_arguments_t *arguments, pm_b
// 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);
+ pm_parser_err_node(parser, UP(block), PM_ERR_ARGUMENT_UNEXPECTED_BLOCK);
}
/******************************************************************************/
@@ -1648,7 +1843,7 @@ pm_arguments_validate_block(pm_parser_t *parser, pm_arguments_t *arguments, pm_b
* 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
+static PRISM_INLINE size_t
char_is_identifier_start(const pm_parser_t *parser, const uint8_t *b, ptrdiff_t n) {
if (n <= 0) return 0;
@@ -1675,7 +1870,7 @@ char_is_identifier_start(const pm_parser_t *parser, const uint8_t *b, ptrdiff_t
* Similar to char_is_identifier but this function assumes that the encoding
* has not been changed.
*/
-static inline size_t
+static PRISM_INLINE size_t
char_is_identifier_utf8(const uint8_t *b, ptrdiff_t n) {
if (n <= 0) {
return 0;
@@ -1687,11 +1882,189 @@ char_is_identifier_utf8(const uint8_t *b, ptrdiff_t n) {
}
/**
+ * Scan forward through ASCII identifier characters (a-z, A-Z, 0-9, _) using
+ * wide operations. Returns the number of leading ASCII identifier bytes.
+ * Callers must handle any remaining bytes (short tail or non-ASCII/UTF-8)
+ * with a byte-at-a-time loop.
+ *
+ * Up to three optimized implementations are selected at compile time, with a
+ * no-op fallback for unsupported platforms:
+ * 1. NEON — processes 16 bytes per iteration on aarch64.
+ * 2. SSSE3 — processes 16 bytes per iteration on x86-64.
+ * 3. SWAR — little-endian fallback, processes 8 bytes per iteration.
+ */
+
+#if defined(PRISM_HAS_NEON)
+#include <arm_neon.h>
+
+static PRISM_INLINE size_t
+scan_identifier_ascii(const uint8_t *start, const uint8_t *end) {
+ const uint8_t *cursor = start;
+
+ // Nibble-based lookup tables for classifying [a-zA-Z0-9_].
+ // Each high nibble is assigned a unique bit; the low nibble table
+ // contains the OR of bits for all high nibbles that have an
+ // identifier character at that low nibble position. A byte is an
+ // identifier character iff (low_lut[lo] & high_lut[hi]) != 0.
+ static const uint8_t low_lut_data[16] = {
+ 0x15, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F,
+ 0x1F, 0x1F, 0x1E, 0x0A, 0x0A, 0x0A, 0x0A, 0x0E
+ };
+ static const uint8_t high_lut_data[16] = {
+ 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x08, 0x10,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+ };
+ const uint8x16_t low_lut = vld1q_u8(low_lut_data);
+ const uint8x16_t high_lut = vld1q_u8(high_lut_data);
+ const uint8x16_t mask_0f = vdupq_n_u8(0x0F);
+
+ while (cursor + 16 <= end) {
+ uint8x16_t v = vld1q_u8(cursor);
+
+ uint8x16_t lo_class = vqtbl1q_u8(low_lut, vandq_u8(v, mask_0f));
+ uint8x16_t hi_class = vqtbl1q_u8(high_lut, vshrq_n_u8(v, 4));
+ uint8x16_t ident = vandq_u8(lo_class, hi_class);
+
+ // Fast check: if the per-byte minimum is nonzero, every byte matched.
+ if (vminvq_u8(ident) != 0) {
+ cursor += 16;
+ continue;
+ }
+
+ // Find the first non-identifier byte (zero in ident).
+ uint8x16_t is_zero = vceqq_u8(ident, vdupq_n_u8(0));
+ uint64_t lo = vgetq_lane_u64(vreinterpretq_u64_u8(is_zero), 0);
+
+ if (lo != 0) {
+ cursor += pm_ctzll(lo) / 8;
+ } else {
+ uint64_t hi = vgetq_lane_u64(vreinterpretq_u64_u8(is_zero), 1);
+ cursor += 8 + pm_ctzll(hi) / 8;
+ }
+
+ return (size_t) (cursor - start);
+ }
+
+ return (size_t) (cursor - start);
+}
+
+#elif defined(PRISM_HAS_SSSE3)
+#include <tmmintrin.h>
+
+static PRISM_INLINE size_t
+scan_identifier_ascii(const uint8_t *start, const uint8_t *end) {
+ const uint8_t *cursor = start;
+
+ while (cursor + 16 <= end) {
+ __m128i v = _mm_loadu_si128((const __m128i *) cursor);
+ __m128i zero = _mm_setzero_si128();
+
+ // Unsigned range check via saturating subtraction:
+ // byte >= lo ⟺ saturate(lo - byte) == 0
+ // byte <= hi ⟺ saturate(byte - hi) == 0
+
+ // Fold case: OR with 0x20 maps A-Z to a-z.
+ __m128i lowered = _mm_or_si128(v, _mm_set1_epi8(0x20));
+ __m128i letter = _mm_and_si128(
+ _mm_cmpeq_epi8(_mm_subs_epu8(_mm_set1_epi8(0x61), lowered), zero),
+ _mm_cmpeq_epi8(_mm_subs_epu8(lowered, _mm_set1_epi8(0x7A)), zero));
+
+ __m128i digit = _mm_and_si128(
+ _mm_cmpeq_epi8(_mm_subs_epu8(_mm_set1_epi8(0x30), v), zero),
+ _mm_cmpeq_epi8(_mm_subs_epu8(v, _mm_set1_epi8(0x39)), zero));
+
+ __m128i underscore = _mm_cmpeq_epi8(v, _mm_set1_epi8(0x5F));
+
+ __m128i ident = _mm_or_si128(_mm_or_si128(letter, digit), underscore);
+ int mask = _mm_movemask_epi8(ident);
+
+ if (mask == 0xFFFF) {
+ cursor += 16;
+ continue;
+ }
+
+ cursor += pm_ctzll((uint64_t) (~mask & 0xFFFF));
+ return (size_t) (cursor - start);
+ }
+
+ return (size_t) (cursor - start);
+}
+
+// The SWAR path uses pm_ctzll to find the first non-matching byte within a
+// word, which only yields the correct byte index on little-endian targets.
+// We gate on a positive little-endian check so that unknown-endianness
+// platforms safely fall through to the no-op fallback.
+#elif defined(PRISM_HAS_SWAR)
+
+/**
+ * Portable SWAR fallback — processes 8 bytes per iteration.
+ *
+ * The byte-wise range checks avoid cross-byte borrows by pre-setting the high
+ * bit of each byte before subtraction: (byte | 0x80) - lo has a minimum value
+ * of 0x80 - 0x7F = 1, so underflow (and thus a borrow into the next byte) is
+ * impossible. The result has bit 7 set if and only if byte >= lo. The same
+ * reasoning applies to the upper-bound direction.
+ */
+static PRISM_INLINE size_t
+scan_identifier_ascii(const uint8_t *start, const uint8_t *end) {
+ static const uint64_t ones = 0x0101010101010101ULL;
+ static const uint64_t highs = 0x8080808080808080ULL;
+ const uint8_t *cursor = start;
+
+ while (cursor + 8 <= end) {
+ uint64_t word;
+ memcpy(&word, cursor, 8);
+
+ // Bail on any non-ASCII byte.
+ if (word & highs) break;
+
+ uint64_t digit = ((word | highs) - ones * 0x30) & ((ones * 0x39 | highs) - word) & highs;
+
+ // Fold upper- and lowercase together by forcing bit 5 (OR 0x20),
+ // then check the lowercase range once. A-Z maps to a-z; the
+ // only non-letter byte that could alias into [0x61,0x7A] is one
+ // whose original value was in [0x41,0x5A] — which is exactly
+ // the uppercase letters we want to match.
+ uint64_t lowered = word | (ones * 0x20);
+ uint64_t letter = ((lowered | highs) - ones * 0x61) & ((ones * 0x7A | highs) - lowered) & highs;
+
+ // Standard SWAR "has zero byte" idiom on (word XOR 0x5F) to find
+ // bytes equal to underscore. Safe from cross-byte borrows because
+ // the ASCII guard above ensures all bytes are < 0x80.
+ uint64_t xor_us = word ^ (ones * 0x5F);
+ uint64_t underscore = (xor_us - ones) & ~xor_us & highs;
+
+ uint64_t ident = digit | letter | underscore;
+
+ if (ident == highs) {
+ cursor += 8;
+ continue;
+ }
+
+ // Find the first non-identifier byte. On little-endian the first
+ // byte sits in the least-significant position.
+ uint64_t not_ident = ~ident & highs;
+ cursor += pm_ctzll(not_ident) / 8;
+ return (size_t) (cursor - start);
+ }
+
+ return (size_t) (cursor - start);
+}
+
+#else
+
+// No-op fallback for big-endian or other unsupported platforms.
+// The caller's byte-at-a-time loop handles everything.
+#define scan_identifier_ascii(start, end) ((size_t) 0)
+
+#endif
+
+/**
* 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
+static PRISM_INLINE size_t
char_is_identifier(const pm_parser_t *parser, const uint8_t *b, ptrdiff_t n) {
if (n <= 0) {
return 0;
@@ -1729,7 +2102,7 @@ const unsigned int pm_global_name_punctuation_hash[(0x7e - 0x20 + 31) / 32] = {
#undef BIT
#undef PUNCT
-static inline bool
+static PRISM_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;
@@ -1737,7 +2110,7 @@ char_is_global_name_punctuation(const uint8_t b) {
return (pm_global_name_punctuation_hash[(i - 0x20) / 32] >> (i % 32)) & 1;
}
-static inline bool
+static PRISM_INLINE bool
token_is_setter_name(pm_token_t *token) {
return (
(token->type == PM_TOKEN_BRACKET_LEFT_RIGHT_EQUAL) ||
@@ -1825,7 +2198,7 @@ pm_local_is_keyword(const char *source, size_t length) {
/**
* Set the given flag on the given node.
*/
-static inline void
+static PRISM_INLINE void
pm_node_flag_set(pm_node_t *node, pm_node_flags_t flag) {
node->flags |= flag;
}
@@ -1833,7 +2206,7 @@ pm_node_flag_set(pm_node_t *node, pm_node_flags_t flag) {
/**
* Remove the given flag from the given node.
*/
-static inline void
+static PRISM_INLINE void
pm_node_flag_unset(pm_node_t *node, pm_node_flags_t flag) {
node->flags &= (pm_node_flags_t) ~flag;
}
@@ -1841,7 +2214,7 @@ pm_node_flag_unset(pm_node_t *node, pm_node_flags_t flag) {
/**
* Set the repeated parameter flag on the given node.
*/
-static inline void
+static PRISM_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 ||
@@ -1869,7 +2242,7 @@ pm_node_flag_set_repeated_parameter(pm_node_t *node) {
/**
* Parse out the options for a regular expression.
*/
-static inline pm_node_flags_t
+static PRISM_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;
@@ -1895,9 +2268,9 @@ pm_regular_expression_flags_create(pm_parser_t *parser, const pm_token_t *closin
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_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);
+ pm_buffer_cleanup(&unknown_flags);
}
return flags;
@@ -1915,36 +2288,45 @@ 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.
+ * Move an integer's values array into the arena. If the integer has heap-
+ * allocated values, copy them to the arena and free the original.
*/
-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();
+static PRISM_INLINE void
+pm_integer_arena_move(pm_arena_t *arena, pm_integer_t *integer) {
+ if (integer->values != NULL) {
+ size_t byte_size = integer->length * sizeof(uint32_t);
+ uint32_t *old_values = integer->values;
+ integer->values = (uint32_t *) pm_arena_memdup(arena, old_values, byte_size, PRISM_ALIGNOF(uint32_t));
+ xfree(old_values);
}
- 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.
+ * Allocate a new ErrorRecoveryNode node with no unexpected child.
*/
-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 }
- }};
+static pm_error_recovery_node_t *
+pm_error_recovery_node_create(pm_parser_t *parser, uint32_t start, uint32_t length) {
+ return pm_error_recovery_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ ((pm_location_t) { .start = start, .length = length }),
+ NULL
+ );
+}
- return node;
+/**
+ * Allocate a new ErrorRecoveryNode node wrapping an unexpected child node.
+ */
+static pm_error_recovery_node_t *
+pm_error_recovery_node_create_unexpected(pm_parser_t *parser, pm_node_t *unexpected) {
+ return pm_error_recovery_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ unexpected->location,
+ unexpected
+ );
}
/**
@@ -1953,23 +2335,16 @@ pm_missing_node_create(pm_parser_t *parser, const uint8_t *start, const uint8_t
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;
+ return pm_alias_global_variable_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_TOKEN_NODE(parser, keyword, old_name),
+ new_name,
+ old_name,
+ TOK2LOC(parser, keyword)
+ );
}
/**
@@ -1978,23 +2353,16 @@ pm_alias_global_variable_node_create(pm_parser_t *parser, const pm_token_t *keyw
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;
+ return pm_alias_method_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_TOKEN_NODE(parser, keyword, old_name),
+ new_name,
+ old_name,
+ TOK2LOC(parser, keyword)
+ );
}
/**
@@ -2002,23 +2370,15 @@ pm_alias_method_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_n
*/
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;
+ return pm_alternation_pattern_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_NODES(left, right),
+ left,
+ right,
+ TOK2LOC(parser, operator)
+ );
}
/**
@@ -2028,23 +2388,15 @@ 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;
+ return pm_and_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_NODES(left, right),
+ left,
+ right,
+ TOK2LOC(parser, operator)
+ );
}
/**
@@ -2052,18 +2404,13 @@ pm_and_node_create(pm_parser_t *parser, pm_node_t *left, const pm_token_t *opera
*/
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 pm_arguments_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_UNSET,
+ ((pm_node_list_t) { 0 })
+ );
}
/**
@@ -2078,19 +2425,22 @@ pm_arguments_node_size(pm_arguments_node_t *node) {
* Append an argument to an arguments node.
*/
static void
-pm_arguments_node_arguments_append(pm_arguments_node_t *node, pm_node_t *argument) {
+pm_arguments_node_arguments_append(pm_arena_t *arena, pm_arguments_node_t *node, pm_node_t *argument) {
if (pm_arguments_node_size(node) == 0) {
- node->base.location.start = argument->location.start;
+ PM_NODE_START_SET_NODE(node, argument);
+ }
+
+ if (PM_NODE_END(node) < PM_NODE_END(argument)) {
+ PM_NODE_LENGTH_SET_NODE(node, argument);
}
- node->base.location.end = argument->location.end;
- pm_node_list_append(&node->arguments, argument);
+ pm_node_list_append(arena, &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);
+ pm_node_flag_set(UP(node), PM_ARGUMENTS_NODE_FLAGS_CONTAINS_MULTIPLE_SPLATS);
} else {
- pm_node_flag_set((pm_node_t *) node, PM_ARGUMENTS_NODE_FLAGS_CONTAINS_SPLAT);
+ pm_node_flag_set(UP(node), PM_ARGUMENTS_NODE_FLAGS_CONTAINS_SPLAT);
}
}
}
@@ -2100,43 +2450,49 @@ pm_arguments_node_arguments_append(pm_arguments_node_t *node, pm_node_t *argumen
*/
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;
+ if (opening == NULL) {
+ return pm_array_node_new(
+ parser->arena,
+ ++parser->node_id,
+ PM_NODE_FLAG_STATIC_LITERAL,
+ PM_LOCATION_INIT_UNSET,
+ ((pm_node_list_t) { 0 }),
+ ((pm_location_t) { 0 }),
+ ((pm_location_t) { 0 })
+ );
+ } else {
+ return pm_array_node_new(
+ parser->arena,
+ ++parser->node_id,
+ PM_NODE_FLAG_STATIC_LITERAL,
+ PM_LOCATION_INIT_TOKEN(parser, opening),
+ ((pm_node_list_t) { 0 }),
+ TOK2LOC(parser, opening),
+ TOK2LOC(parser, opening)
+ );
+ }
}
/**
* 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;
+static PRISM_INLINE void
+pm_array_node_elements_append(pm_arena_t *arena, pm_array_node_t *node, pm_node_t *element) {
+ if (!node->elements.size && !node->opening_loc.length) {
+ PM_NODE_START_SET_NODE(node, element);
}
- pm_node_list_append(&node->elements, element);
- node->base.location.end = element->location.end;
+ pm_node_list_append(arena, &node->elements, element);
+ PM_NODE_LENGTH_SET_NODE(node, element);
// 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);
+ pm_node_flag_unset(UP(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);
+ pm_node_flag_set(UP(node), PM_ARRAY_NODE_FLAGS_CONTAINS_SPLAT);
}
}
@@ -2144,10 +2500,10 @@ pm_array_node_elements_append(pm_array_node_t *node, pm_node_t *element) {
* 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);
+pm_array_node_close_set(const pm_parser_t *parser, 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 == 0);
+ PM_NODE_LENGTH_SET_TOKEN(parser, node, closing);
+ node->closing_loc = TOK2LOC(parser, closing);
}
/**
@@ -2156,24 +2512,18 @@ pm_array_node_close_set(pm_array_node_t *node, const pm_token_t *closing) {
*/
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
- };
+ pm_array_pattern_node_t *node = pm_array_pattern_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_NODES(nodes->nodes[0], nodes->nodes[nodes->size - 1]),
+ NULL,
+ ((pm_node_list_t) { 0 }),
+ NULL,
+ ((pm_node_list_t) { 0 }),
+ ((pm_location_t) { 0 }),
+ ((pm_location_t) { 0 })
+ );
// 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.
@@ -2185,9 +2535,9 @@ pm_array_pattern_node_node_list_create(pm_parser_t *parser, pm_node_list_t *node
node->rest = child;
found_rest = true;
} else if (found_rest) {
- pm_node_list_append(&node->posts, child);
+ pm_node_list_append(parser->arena, &node->posts, child);
} else {
- pm_node_list_append(&node->requireds, child);
+ pm_node_list_append(parser->arena, &node->requireds, child);
}
}
@@ -2199,23 +2549,18 @@ pm_array_pattern_node_node_list_create(pm_parser_t *parser, pm_node_list_t *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;
+ return pm_array_pattern_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_NODE(rest),
+ NULL,
+ ((pm_node_list_t) { 0 }),
+ rest,
+ ((pm_node_list_t) { 0 }),
+ ((pm_location_t) { 0 }),
+ ((pm_location_t) { 0 })
+ );
}
/**
@@ -2224,26 +2569,18 @@ pm_array_pattern_node_rest_create(pm_parser_t *parser, pm_node_t *rest) {
*/
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;
+ return pm_array_pattern_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_NODE_TOKEN(parser, constant, closing),
+ constant,
+ ((pm_node_list_t) { 0 }),
+ NULL,
+ ((pm_node_list_t) { 0 }),
+ TOK2LOC(parser, opening),
+ TOK2LOC(parser, closing)
+ );
}
/**
@@ -2252,31 +2589,23 @@ pm_array_pattern_node_constant_create(pm_parser_t *parser, pm_node_t *constant,
*/
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;
+ return pm_array_pattern_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_TOKENS(parser, opening, closing),
+ NULL,
+ ((pm_node_list_t) { 0 }),
+ NULL,
+ ((pm_node_list_t) { 0 }),
+ TOK2LOC(parser, opening),
+ TOK2LOC(parser, closing)
+ );
}
-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);
+static PRISM_INLINE void
+pm_array_pattern_node_requireds_append(pm_arena_t *arena, pm_array_pattern_node_t *node, pm_node_t *inner) {
+ pm_node_list_append(arena, &node->requireds, inner);
}
/**
@@ -2284,15 +2613,14 @@ pm_array_pattern_node_requireds_append(pm_array_pattern_node_t *node, pm_node_t
*/
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;
+ uint32_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;
+ if (value != NULL && PM_NODE_END(value) > PM_NODE_END(key)) {
+ end = PM_NODE_END(value);
+ } else if (operator != NULL) {
+ end = PM_TOKEN_END(parser, operator);
} else {
- end = key->location.end;
+ end = PM_NODE_END(key);
}
// Hash string keys will be frozen, so we can mark them as frozen here so
@@ -2312,22 +2640,15 @@ pm_assoc_node_create(pm_parser_t *parser, pm_node_t *key, const pm_token_t *oper
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;
+ return pm_assoc_node_new(
+ parser->arena,
+ ++parser->node_id,
+ flags,
+ ((pm_location_t) { .start = PM_NODE_START(key), .length = U32(end - PM_NODE_START(key)) }),
+ key,
+ value,
+ NTOK2LOC(parser, operator)
+ );
}
/**
@@ -2336,22 +2657,15 @@ pm_assoc_node_create(pm_parser_t *parser, pm_node_t *key, const pm_token_t *oper
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;
+ return pm_assoc_splat_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ (value == NULL) ? PM_LOCATION_INIT_TOKEN(parser, operator) : PM_LOCATION_INIT_TOKEN_NODE(parser, operator, value),
+ value,
+ TOK2LOC(parser, operator)
+ );
}
/**
@@ -2360,18 +2674,14 @@ pm_assoc_splat_node_create(pm_parser_t *parser, pm_node_t *value, const pm_token
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;
+ return pm_back_reference_read_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_TOKEN(parser, name),
+ pm_parser_constant_id_token(parser, name)
+ );
}
/**
@@ -2379,23 +2689,21 @@ pm_back_reference_read_node_create(pm_parser_t *parser, const pm_token_t *name)
*/
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;
+ uint32_t start = begin_keyword == NULL ? 0 : PM_TOKEN_START(parser, begin_keyword);
+ uint32_t end = statements == NULL ? (begin_keyword == NULL ? 0 : PM_TOKEN_END(parser, begin_keyword)) : PM_NODE_END(statements);
+
+ return pm_begin_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ ((pm_location_t) { .start = start, .length = U32(end - start) }),
+ NTOK2LOC(parser, begin_keyword),
+ statements,
+ NULL,
+ NULL,
+ NULL,
+ ((pm_location_t) { 0 })
+ );
}
/**
@@ -2403,11 +2711,10 @@ pm_begin_node_create(pm_parser_t *parser, const pm_token_t *begin_keyword, pm_st
*/
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;
+ if (node->begin_keyword_loc.length == 0) {
+ PM_NODE_START_SET_NODE(node, rescue_clause);
}
- node->base.location.end = rescue_clause->base.location.end;
+ PM_NODE_LENGTH_SET_NODE(node, rescue_clause);
node->rescue_clause = rescue_clause;
}
@@ -2416,7 +2723,10 @@ pm_begin_node_rescue_clause_set(pm_begin_node_t *node, pm_rescue_node_t *rescue_
*/
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;
+ if ((node->begin_keyword_loc.length == 0) && PM_NODE_START(node) == 0) {
+ PM_NODE_START_SET_NODE(node, else_clause);
+ }
+ PM_NODE_LENGTH_SET_NODE(node, else_clause);
node->else_clause = else_clause;
}
@@ -2425,7 +2735,10 @@ pm_begin_node_else_clause_set(pm_begin_node_t *node, pm_else_node_t *else_clause
*/
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;
+ if ((node->begin_keyword_loc.length == 0) && PM_NODE_START(node) == 0) {
+ PM_NODE_START_SET_NODE(node, ensure_clause);
+ }
+ PM_NODE_LENGTH_SET_NODE(node, ensure_clause);
node->ensure_clause = ensure_clause;
}
@@ -2433,11 +2746,10 @@ pm_begin_node_ensure_clause_set(pm_begin_node_t *node, pm_ensure_node_t *ensure_
* 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);
+pm_begin_node_end_keyword_set(const pm_parser_t *parser, pm_begin_node_t *node, const pm_token_t *end_keyword) {
+ assert(end_keyword->type == PM_TOKEN_KEYWORD_END || end_keyword->type == 0);
+ PM_NODE_LENGTH_SET_TOKEN(parser, node, end_keyword);
+ node->end_keyword_loc = TOK2LOC(parser, end_keyword);
}
/**
@@ -2445,22 +2757,16 @@ pm_begin_node_end_keyword_set(pm_begin_node_t *node, const pm_token_t *end_keywo
*/
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;
+ assert(operator->type == PM_TOKEN_UAMPERSAND);
+
+ return pm_block_argument_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ (expression == NULL) ? PM_LOCATION_INIT_TOKEN(parser, operator) : PM_LOCATION_INIT_TOKEN_NODE(parser, operator, expression),
+ expression,
+ TOK2LOC(parser, operator)
+ );
}
/**
@@ -2468,22 +2774,17 @@ pm_block_argument_node_create(pm_parser_t *parser, const pm_token_t *operator, p
*/
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;
+ return pm_block_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_TOKENS(parser, opening, closing),
+ *locals,
+ parameters,
+ body,
+ TOK2LOC(parser, opening),
+ TOK2LOC(parser, closing)
+ );
}
/**
@@ -2491,24 +2792,17 @@ pm_block_node_create(pm_parser_t *parser, pm_constant_id_list_t *locals, const p
*/
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;
+ assert(operator->type == PM_TOKEN_UAMPERSAND || operator->type == PM_TOKEN_AMPERSAND);
+
+ return pm_block_parameter_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ (name == NULL) ? PM_LOCATION_INIT_TOKEN(parser, operator) : PM_LOCATION_INIT_TOKENS(parser, operator, name),
+ name == NULL ? 0 : pm_parser_constant_id_token(parser, name),
+ NTOK2LOC(parser, name),
+ TOK2LOC(parser, operator)
+ );
}
/**
@@ -2516,53 +2810,44 @@ pm_block_parameter_node_create(pm_parser_t *parser, const pm_token_t *name, cons
*/
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;
+ uint32_t start;
+ if (opening != NULL) {
+ start = PM_TOKEN_START(parser, opening);
} else if (parameters != NULL) {
- start = parameters->base.location.start;
+ start = PM_NODE_START(parameters);
} else {
- start = NULL;
+ start = 0;
}
- const uint8_t *end;
+ uint32_t end;
if (parameters != NULL) {
- end = parameters->base.location.end;
- } else if (opening->type != PM_TOKEN_NOT_PROVIDED) {
- end = opening->end;
+ end = PM_NODE_END(parameters);
+ } else if (opening != NULL) {
+ end = PM_TOKEN_END(parser, opening);
} 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;
+ end = 0;
+ }
+
+ return pm_block_parameters_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ ((pm_location_t) { .start = start, .length = U32(end - start) }),
+ parameters,
+ ((pm_node_list_t) { 0 }),
+ NTOK2LOC(parser, opening),
+ ((pm_location_t) { 0 })
+ );
}
/**
* 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);
+pm_block_parameters_node_closing_set(const pm_parser_t *parser, 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 == 0);
+ PM_NODE_LENGTH_SET_TOKEN(parser, node, closing);
+ node->closing_loc = TOK2LOC(parser, closing);
}
/**
@@ -2570,29 +2855,27 @@ pm_block_parameters_node_closing_set(pm_block_parameters_node_t *node, const pm_
*/
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;
+ return pm_block_local_variable_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_TOKEN(parser, name),
+ pm_parser_constant_id_token(parser, name)
+ );
}
/**
* 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);
+pm_block_parameters_node_append_local(pm_arena_t *arena, pm_block_parameters_node_t *node, const pm_block_local_variable_node_t *local) {
+ pm_node_list_append(arena, &node->locals, UP(local));
+
+ if (PM_NODE_LENGTH(node) == 0) {
+ PM_NODE_START_SET_NODE(node, local);
+ }
- if (node->base.location.start == NULL) node->base.location.start = local->base.location.start;
- node->base.location.end = local->base.location.end;
+ PM_NODE_LENGTH_SET_NODE(node, local);
}
/**
@@ -2601,66 +2884,55 @@ pm_block_parameters_node_append_local(pm_block_parameters_node_t *node, const pm
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;
+ return pm_break_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ (arguments == NULL) ? PM_LOCATION_INIT_TOKEN(parser, keyword) : PM_LOCATION_INIT_TOKEN_NODE(parser, keyword, arguments),
+ arguments,
+ TOK2LOC(parser, keyword)
+ );
}
// 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;
+static const pm_node_flags_t PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY = (1 << 2);
+
+static const pm_node_flags_t PM_CALL_NODE_FLAGS_IMPLICIT_ARRAY = ((PM_CALL_NODE_FLAGS_LAST - 1) << 1);
+static const pm_node_flags_t PM_CALL_NODE_FLAGS_COMPARISON = ((PM_CALL_NODE_FLAGS_LAST - 1) << 2);
+static const pm_node_flags_t PM_CALL_NODE_FLAGS_INDEX = ((PM_CALL_NODE_FLAGS_LAST - 1) << 3);
/**
- * 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.
+ * Allocate and initialize a new CallNode node. This sets everything to NULL
+ * 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;
+ return pm_call_node_new(
+ parser->arena,
+ ++parser->node_id,
+ flags,
+ PM_LOCATION_INIT_UNSET,
+ NULL,
+ ((pm_location_t) { 0 }),
+ 0,
+ ((pm_location_t) { 0 }),
+ ((pm_location_t) { 0 }),
+ NULL,
+ ((pm_location_t) { 0 }),
+ ((pm_location_t) { 0 }),
+ NULL
+ );
}
/**
* Returns the value that the ignore visibility flag should be set to for the
* given receiver.
*/
-static inline pm_node_flags_t
+static PRISM_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;
}
@@ -2680,12 +2952,15 @@ pm_call_node_aref_create(pm_parser_t *parser, pm_node_t *receiver, pm_arguments_
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);
+ PM_NODE_START_SET_NODE(node, receiver);
+
+ const pm_location_t *end = pm_arguments_end(arguments);
+ assert(end != NULL && "unreachable");
+ PM_NODE_LENGTH_SET_LOCATION(node, end);
node->receiver = receiver;
node->message_loc.start = arguments->opening_loc.start;
- node->message_loc.end = arguments->closing_loc.end;
+ node->message_loc.length = (arguments->closing_loc.start + arguments->closing_loc.length) - arguments->opening_loc.start;
node->opening_loc = arguments->opening_loc;
node->arguments = arguments->arguments;
@@ -2706,20 +2981,22 @@ pm_call_node_binary_create(pm_parser_t *parser, pm_node_t *receiver, pm_token_t
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);
+ PM_NODE_START_SET_NODE(node, PM_NODE_START(receiver) < PM_NODE_START(argument) ? receiver : argument);
+ PM_NODE_LENGTH_SET_NODE(node, PM_NODE_END(receiver) > PM_NODE_END(argument) ? receiver : argument);
node->receiver = receiver;
- node->message_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator);
+ node->message_loc = TOK2LOC(parser, operator);
pm_arguments_node_t *arguments = pm_arguments_node_create(parser);
- pm_arguments_node_arguments_append(arguments, argument);
+ pm_arguments_node_arguments_append(parser->arena, arguments, argument);
node->arguments = arguments;
node->name = pm_parser_constant_id_token(parser, operator);
return node;
}
+static const uint8_t * parse_operator_symbol_name(const pm_token_t *);
+
/**
* Allocate and initialize a new CallNode node from a call expression.
*/
@@ -2729,26 +3006,31 @@ pm_call_node_call_create(pm_parser_t *parser, pm_node_t *receiver, pm_token_t *o
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);
+ PM_NODE_START_SET_NODE(node, receiver);
+ const pm_location_t *end = pm_arguments_end(arguments);
if (end == NULL) {
- end = message->end;
+ PM_NODE_LENGTH_SET_TOKEN(parser, node, message);
+ } else {
+ PM_NODE_LENGTH_SET_LOCATION(node, 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->call_operator_loc = TOK2LOC(parser, operator);
+ node->message_loc = TOK2LOC(parser, 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);
+ pm_node_flag_set(UP(node), PM_CALL_NODE_FLAGS_SAFE_NAVIGATION);
}
- node->name = pm_parser_constant_id_token(parser, message);
+ /**
+ * If the final character is `@` as is the case for `foo.~@`,
+ * we should ignore the @ in the same way we do for symbols.
+ */
+ node->name = pm_parser_constant_id_raw(parser, message->start, parse_operator_symbol_name(message));
return node;
}
@@ -2758,12 +3040,9 @@ pm_call_node_call_create(pm_parser_t *parser, pm_node_t *receiver, pm_token_t *o
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->base.location = (pm_location_t) { .start = 0, .length = U32(parser->end - parser->start) };
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));
@@ -2778,10 +3057,12 @@ 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);
+ PM_NODE_START_SET_TOKEN(parser, node, message);
+ const pm_location_t *end = pm_arguments_end(arguments);
+ assert(end != NULL && "unreachable");
+ PM_NODE_LENGTH_SET_LOCATION(node, end);
- node->message_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(message);
+ node->message_loc = TOK2LOC(parser, message);
node->opening_loc = arguments->opening_loc;
node->arguments = arguments->arguments;
node->closing_loc = arguments->closing_loc;
@@ -2799,7 +3080,7 @@ 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->base.location = (pm_location_t) { 0 };
node->arguments = arguments;
node->name = name;
@@ -2816,16 +3097,16 @@ pm_call_node_not_create(pm_parser_t *parser, pm_node_t *receiver, pm_token_t *me
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;
+ PM_NODE_START_SET_TOKEN(parser, node, message);
+ if (arguments->closing_loc.length > 0) {
+ PM_NODE_LENGTH_SET_LOCATION(node, &arguments->closing_loc);
} else {
assert(receiver != NULL);
- node->base.location.end = receiver->location.end;
+ PM_NODE_LENGTH_SET_NODE(node, receiver);
}
node->receiver = receiver;
- node->message_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(message);
+ node->message_loc = TOK2LOC(parser, message);
node->opening_loc = arguments->opening_loc;
node->arguments = arguments->arguments;
node->closing_loc = arguments->closing_loc;
@@ -2843,18 +3124,20 @@ pm_call_node_shorthand_create(pm_parser_t *parser, pm_node_t *receiver, pm_token
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);
+ PM_NODE_START_SET_NODE(node, receiver);
+ const pm_location_t *end = pm_arguments_end(arguments);
+ assert(end != NULL && "unreachable");
+ PM_NODE_LENGTH_SET_LOCATION(node, end);
node->receiver = receiver;
- node->call_operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator);
+ node->call_operator_loc = TOK2LOC(parser, 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);
+ pm_node_flag_set(UP(node), PM_CALL_NODE_FLAGS_SAFE_NAVIGATION);
}
node->name = pm_parser_constant_id_constant(parser, "call", 4);
@@ -2870,11 +3153,11 @@ pm_call_node_unary_create(pm_parser_t *parser, pm_token_t *operator, pm_node_t *
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;
+ PM_NODE_START_SET_TOKEN(parser, node, operator);
+ PM_NODE_LENGTH_SET_NODE(node, receiver);
node->receiver = receiver;
- node->message_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator);
+ node->message_loc = TOK2LOC(parser, operator);
node->name = pm_parser_constant_id_constant(parser, name, strlen(name));
return node;
@@ -2888,8 +3171,8 @@ 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->base.location = TOK2LOC(parser, message);
+ node->message_loc = TOK2LOC(parser, message);
node->name = pm_parser_constant_id_token(parser, message);
return node;
@@ -2899,14 +3182,14 @@ pm_call_node_variable_call_create(pm_parser_t *parser, pm_token_t *message) {
* Returns whether or not this call can be used on the left-hand side of an
* operator assignment.
*/
-static inline bool
+static PRISM_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, parser->end - node->message_loc.start) &&
- (node->opening_loc.start == NULL) &&
+ (node->message_loc.length > 0) &&
+ (parser->start[node->message_loc.start + node->message_loc.length - 1] != '!') &&
+ (parser->start[node->message_loc.start + node->message_loc.length - 1] != '?') &&
+ char_is_identifier_start(parser, parser->start + node->message_loc.start, (ptrdiff_t) node->message_loc.length) &&
+ (node->opening_loc.length == 0) &&
(node->arguments == NULL) &&
(node->block == NULL)
);
@@ -2922,10 +3205,10 @@ pm_call_write_read_name_init(pm_parser_t *parser, pm_constant_id_t *read_name, p
if (write_constant->length > 0) {
size_t length = write_constant->length - 1;
- void *memory = xmalloc(length);
+ uint8_t *memory = (uint8_t *) pm_arena_alloc(parser->arena, length, 1);
memcpy(memory, write_constant->start, length);
- *read_name = pm_constant_pool_insert_owned(&parser->constant_pool, (uint8_t *) memory, length);
+ *read_name = pm_constant_pool_insert_owned(&parser->metadata_arena, &parser->constant_pool, 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);
@@ -2939,33 +3222,25 @@ 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_and_write_node_t *node = pm_call_and_write_node_new(
+ parser->arena,
+ ++parser->node_id,
+ FL(target),
+ PM_LOCATION_INIT_NODES(target, value),
+ target->receiver,
+ target->call_operator_loc,
+ target->message_loc,
+ 0,
+ target->name,
+ TOK2LOC(parser, operator),
+ 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);
+ // The target is no longer necessary because we've reused its children.
+ // It is arena-allocated so no explicit free is needed.
return node;
}
@@ -2999,35 +3274,28 @@ pm_index_arguments_check(pm_parser_t *parser, const pm_arguments_node_t *argumen
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);
+ pm_index_and_write_node_t *node = pm_index_and_write_node_new(
+ parser->arena,
+ ++parser->node_id,
+ FL(target),
+ PM_LOCATION_INIT_NODES(target, value),
+ target->receiver,
+ target->call_operator_loc,
+ target->opening_loc,
+ target->arguments,
+ target->closing_loc,
+ (pm_block_argument_node_t *) target->block,
+ TOK2LOC(parser, operator),
+ value
+ );
+
+ // The target is no longer necessary because we've reused its children.
+ // It is arena-allocated so no explicit free is needed.
return node;
}
@@ -3038,34 +3306,26 @@ pm_index_and_write_node_create(pm_parser_t *parser, pm_call_node_t *target, cons
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_operator_write_node_t *node = pm_call_operator_write_node_new(
+ parser->arena,
+ ++parser->node_id,
+ FL(target),
+ PM_LOCATION_INIT_NODES(target, value),
+ target->receiver,
+ target->call_operator_loc,
+ target->message_loc,
+ 0,
+ target->name,
+ pm_parser_constant_id_raw(parser, operator->start, operator->end - 1),
+ TOK2LOC(parser, operator),
+ 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);
+ // The target is no longer necessary because we've reused its children.
+ // It is arena-allocated so no explicit free is needed.
return node;
}
@@ -3075,36 +3335,28 @@ pm_call_operator_write_node_create(pm_parser_t *parser, pm_call_node_t *target,
*/
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);
+ pm_index_operator_write_node_t *node = pm_index_operator_write_node_new(
+ parser->arena,
+ ++parser->node_id,
+ FL(target),
+ PM_LOCATION_INIT_NODES(target, value),
+ target->receiver,
+ target->call_operator_loc,
+ target->opening_loc,
+ target->arguments,
+ target->closing_loc,
+ (pm_block_argument_node_t *) target->block,
+ pm_parser_constant_id_raw(parser, operator->start, operator->end - 1),
+ TOK2LOC(parser, operator),
+ value
+ );
+
+ // The target is no longer necessary because we've reused its children.
+ // It is arena-allocated so no explicit free is needed.
return node;
}
@@ -3116,33 +3368,25 @@ 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_or_write_node_t *node = pm_call_or_write_node_new(
+ parser->arena,
+ ++parser->node_id,
+ FL(target),
+ PM_LOCATION_INIT_NODES(target, value),
+ target->receiver,
+ target->call_operator_loc,
+ target->message_loc,
+ 0,
+ target->name,
+ TOK2LOC(parser, operator),
+ 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);
+ // The target is no longer necessary because we've reused its children.
+ // It is arena-allocated so no explicit free is needed.
return node;
}
@@ -3153,35 +3397,28 @@ pm_call_or_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const
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);
+ pm_index_or_write_node_t *node = pm_index_or_write_node_new(
+ parser->arena,
+ ++parser->node_id,
+ FL(target),
+ PM_LOCATION_INIT_NODES(target, value),
+ target->receiver,
+ target->call_operator_loc,
+ target->opening_loc,
+ target->arguments,
+ target->closing_loc,
+ (pm_block_argument_node_t *) target->block,
+ TOK2LOC(parser, operator),
+ value
+ );
+
+ // The target is no longer necessary because we've reused its children.
+ // It is arena-allocated so no explicit free is needed.
return node;
}
@@ -3192,25 +3429,27 @@ pm_index_or_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const
*/
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);
+ pm_call_target_node_t *node = pm_call_target_node_new(
+ parser->arena,
+ ++parser->node_id,
+ FL(target),
+ PM_LOCATION_INIT_NODE(target),
+ target->receiver,
+ target->call_operator_loc,
+ target->name,
+ target->message_loc
+ );
- *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
- };
+ /* It is possible to get here where we have parsed an invalid syntax tree
+ * where the call operator was not present. In that case we will have a
+ * problem because it is a required location. In this case we need to fill
+ * it in with a fake location so that the syntax tree remains valid. */
+ if (node->call_operator_loc.length == 0) {
+ node->call_operator_loc = target->base.location;
+ }
- // 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);
+ // The target is no longer necessary because we've reused its children.
+ // It is arena-allocated so no explicit free is needed.
return node;
}
@@ -3221,30 +3460,23 @@ pm_call_target_node_create(pm_parser_t *parser, pm_call_node_t *target) {
*/
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);
+ pm_index_target_node_t *node = pm_index_target_node_new(
+ parser->arena,
+ ++parser->node_id,
+ FL(target) | PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE,
+ PM_LOCATION_INIT_NODE(target),
+ target->receiver,
+ target->opening_loc,
+ target->arguments,
+ target->closing_loc,
+ (pm_block_argument_node_t *) target->block
+ );
+
+ // The target is no longer necessary because we've reused its children.
+ // It is arena-allocated so no explicit free is needed.
return node;
}
@@ -3254,23 +3486,15 @@ pm_index_target_node_create(pm_parser_t *parser, pm_call_node_t *target) {
*/
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;
+ return pm_capture_pattern_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_NODES(value, target),
+ value,
+ target,
+ TOK2LOC(parser, operator)
+ );
}
/**
@@ -3278,36 +3502,28 @@ pm_capture_pattern_node_create(pm_parser_t *parser, pm_node_t *value, pm_local_v
*/
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;
+ return pm_case_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_TOKENS(parser, case_keyword, end_keyword == NULL ? case_keyword : end_keyword),
+ predicate,
+ ((pm_node_list_t) { 0 }),
+ NULL,
+ TOK2LOC(parser, case_keyword),
+ NTOK2LOC(parser, end_keyword)
+ );
}
/**
* Append a new condition to a CaseNode node.
*/
static void
-pm_case_node_condition_append(pm_case_node_t *node, pm_node_t *condition) {
+pm_case_node_condition_append(pm_arena_t *arena, 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;
+ pm_node_list_append(arena, &node->conditions, condition);
+ PM_NODE_LENGTH_SET_NODE(node, condition);
}
/**
@@ -3316,53 +3532,45 @@ pm_case_node_condition_append(pm_case_node_t *node, pm_node_t *condition) {
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;
+ PM_NODE_LENGTH_SET_NODE(node, else_clause);
}
/**
* 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);
+pm_case_node_end_keyword_loc_set(const pm_parser_t *parser, pm_case_node_t *node, const pm_token_t *end_keyword) {
+ PM_NODE_LENGTH_SET_TOKEN(parser, node, end_keyword);
+ node->end_keyword_loc = TOK2LOC(parser, 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;
+pm_case_match_node_create(pm_parser_t *parser, const pm_token_t *case_keyword, pm_node_t *predicate) {
+ return pm_case_match_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_TOKEN(parser, case_keyword),
+ predicate,
+ ((pm_node_list_t) { 0 }),
+ NULL,
+ TOK2LOC(parser, case_keyword),
+ ((pm_location_t) { 0 })
+ );
}
/**
* 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) {
+pm_case_match_node_condition_append(pm_arena_t *arena, 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;
+ pm_node_list_append(arena, &node->conditions, condition);
+ PM_NODE_LENGTH_SET_NODE(node, condition);
}
/**
@@ -3371,16 +3579,16 @@ pm_case_match_node_condition_append(pm_case_match_node_t *node, pm_node_t *condi
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;
+ PM_NODE_LENGTH_SET_NODE(node, else_clause);
}
/**
* 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);
+pm_case_match_node_end_keyword_loc_set(const pm_parser_t *parser, pm_case_match_node_t *node, const pm_token_t *end_keyword) {
+ PM_NODE_LENGTH_SET_TOKEN(parser, node, end_keyword);
+ node->end_keyword_loc = TOK2LOC(parser, end_keyword);
}
/**
@@ -3388,25 +3596,20 @@ pm_case_match_node_end_keyword_loc_set(pm_case_match_node_t *node, const pm_toke
*/
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;
+ return pm_class_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_TOKENS(parser, class_keyword, end_keyword),
+ *locals,
+ TOK2LOC(parser, class_keyword),
+ constant_path,
+ NTOK2LOC(parser, inheritance_operator),
+ superclass,
+ body,
+ TOK2LOC(parser, end_keyword),
+ pm_parser_constant_id_token(parser, name)
+ );
}
/**
@@ -3415,24 +3618,17 @@ pm_class_node_create(pm_parser_t *parser, pm_constant_id_list_t *locals, const p
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;
+ return pm_class_variable_and_write_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_NODES(target, value),
+ target->name,
+ target->base.location,
+ TOK2LOC(parser, operator),
+ value
+ );
}
/**
@@ -3440,25 +3636,17 @@ pm_class_variable_and_write_node_create(pm_parser_t *parser, pm_class_variable_r
*/
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;
+ return pm_class_variable_operator_write_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_NODES(target, value),
+ target->name,
+ target->base.location,
+ TOK2LOC(parser, operator),
+ value,
+ pm_parser_constant_id_raw(parser, operator->start, operator->end - 1)
+ );
}
/**
@@ -3467,24 +3655,17 @@ pm_class_variable_operator_write_node_create(pm_parser_t *parser, pm_class_varia
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;
+ return pm_class_variable_or_write_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_NODES(target, value),
+ target->name,
+ target->base.location,
+ TOK2LOC(parser, operator),
+ value
+ );
}
/**
@@ -3493,18 +3674,14 @@ pm_class_variable_or_write_node_create(pm_parser_t *parser, pm_class_variable_re
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;
+ return pm_class_variable_read_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_TOKEN(parser, token),
+ pm_parser_constant_id_token(parser, token)
+ );
}
/**
@@ -3513,9 +3690,9 @@ pm_class_variable_read_node_create(pm_parser_t *parser, const pm_token_t *token)
* a = *b
* a = 1, 2, 3
*/
-static inline pm_node_flags_t
+static PRISM_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) {
+ if (PM_NODE_TYPE_P(node, PM_ARRAY_NODE) && ((const pm_array_node_t *) node)->opening_loc.length == 0) {
return flags;
}
return 0;
@@ -3526,25 +3703,16 @@ pm_implicit_array_write_flags(const pm_node_t *node, pm_node_flags_t flags) {
*/
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;
+ return pm_class_variable_write_node_new(
+ parser->arena,
+ ++parser->node_id,
+ pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
+ PM_LOCATION_INIT_NODES(read_node, value),
+ read_node->name,
+ read_node->base.location,
+ value,
+ TOK2LOC(parser, operator)
+ );
}
/**
@@ -3553,23 +3721,16 @@ pm_class_variable_write_node_create(pm_parser_t *parser, pm_class_variable_read_
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;
+ return pm_constant_path_and_write_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_NODES(target, value),
+ target,
+ TOK2LOC(parser, operator),
+ value
+ );
}
/**
@@ -3577,24 +3738,16 @@ pm_constant_path_and_write_node_create(pm_parser_t *parser, pm_constant_path_nod
*/
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;
+ return pm_constant_path_operator_write_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_NODES(target, value),
+ target,
+ TOK2LOC(parser, operator),
+ value,
+ pm_parser_constant_id_raw(parser, operator->start, operator->end - 1)
+ );
}
/**
@@ -3603,23 +3756,16 @@ pm_constant_path_operator_write_node_create(pm_parser_t *parser, pm_constant_pat
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;
+ return pm_constant_path_or_write_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_NODES(target, value),
+ target,
+ TOK2LOC(parser, operator),
+ value
+ );
}
/**
@@ -3628,29 +3774,22 @@ pm_constant_path_or_write_node_create(pm_parser_t *parser, pm_constant_path_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;
+ return pm_constant_path_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ (parent == NULL) ? PM_LOCATION_INIT_TOKENS(parser, delimiter, name_token) : PM_LOCATION_INIT_NODE_TOKEN(parser, parent, name_token),
+ parent,
+ name,
+ TOK2LOC(parser, delimiter),
+ TOK2LOC(parser, name_token)
+ );
}
/**
@@ -3658,24 +3797,15 @@ pm_constant_path_node_create(pm_parser_t *parser, pm_node_t *parent, const pm_to
*/
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;
+ return pm_constant_path_write_node_new(
+ parser->arena,
+ ++parser->node_id,
+ pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
+ PM_LOCATION_INIT_NODES(target, value),
+ target,
+ TOK2LOC(parser, operator),
+ value
+ );
}
/**
@@ -3684,24 +3814,17 @@ pm_constant_path_write_node_create(pm_parser_t *parser, pm_constant_path_node_t
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;
+ return pm_constant_and_write_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_NODES(target, value),
+ target->name,
+ target->base.location,
+ TOK2LOC(parser, operator),
+ value
+ );
}
/**
@@ -3709,25 +3832,17 @@ pm_constant_and_write_node_create(pm_parser_t *parser, pm_constant_read_node_t *
*/
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;
+ return pm_constant_operator_write_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_NODES(target, value),
+ target->name,
+ target->base.location,
+ TOK2LOC(parser, operator),
+ value,
+ pm_parser_constant_id_raw(parser, operator->start, operator->end - 1)
+ );
}
/**
@@ -3736,24 +3851,17 @@ pm_constant_operator_write_node_create(pm_parser_t *parser, pm_constant_read_nod
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;
+ return pm_constant_or_write_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_NODES(target, value),
+ target->name,
+ target->base.location,
+ TOK2LOC(parser, operator),
+ value
+ );
}
/**
@@ -3761,19 +3869,15 @@ pm_constant_or_write_node_create(pm_parser_t *parser, pm_constant_read_node_t *t
*/
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;
+ assert(name->type == PM_TOKEN_CONSTANT || name->type == 0);
+
+ return pm_constant_read_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_TOKEN(parser, name),
+ pm_parser_constant_id_token(parser, name)
+ );
}
/**
@@ -3781,25 +3885,16 @@ pm_constant_read_node_create(pm_parser_t *parser, const pm_token_t *name) {
*/
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;
+ return pm_constant_write_node_new(
+ parser->arena,
+ ++parser->node_id,
+ pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
+ PM_LOCATION_INIT_NODES(target, value),
+ target->name,
+ target->base.location,
+ value,
+ TOK2LOC(parser, operator)
+ );
}
/**
@@ -3810,7 +3905,7 @@ 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);
+ if (cast->statements != NULL) pm_def_node_receiver_check(parser, UP(cast->statements));
break;
}
case PM_PARENTHESES_NODE: {
@@ -3865,65 +3960,45 @@ pm_def_node_create(
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_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;
+ return pm_def_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ (end_keyword == NULL) ? PM_LOCATION_INIT_TOKEN_NODE(parser, def_keyword, body) : PM_LOCATION_INIT_TOKENS(parser, def_keyword, end_keyword),
+ name,
+ TOK2LOC(parser, name_loc),
+ receiver,
+ parameters,
+ body,
+ *locals,
+ TOK2LOC(parser, def_keyword),
+ NTOK2LOC(parser, operator),
+ NTOK2LOC(parser, lparen),
+ NTOK2LOC(parser, rparen),
+ NTOK2LOC(parser, equal),
+ NTOK2LOC(parser, end_keyword)
+ );
}
/**
* 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;
+pm_defined_node_create(pm_parser_t *parser, const pm_token_t *lparen, pm_node_t *value, const pm_token_t *rparen, const pm_token_t *keyword) {
+ return pm_defined_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ (rparen == NULL) ? PM_LOCATION_INIT_TOKEN_NODE(parser, keyword, value) : PM_LOCATION_INIT_TOKENS(parser, keyword, rparen),
+ NTOK2LOC(parser, lparen),
+ value,
+ NTOK2LOC(parser, rparen),
+ TOK2LOC(parser, keyword)
+ );
}
/**
@@ -3931,29 +4006,15 @@ pm_defined_node_create(pm_parser_t *parser, const pm_token_t *lparen, pm_node_t
*/
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;
+ return pm_else_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ ((end_keyword == NULL) && (statements != NULL)) ? PM_LOCATION_INIT_TOKEN_NODE(parser, else_keyword, statements) : PM_LOCATION_INIT_TOKENS(parser, else_keyword, end_keyword),
+ TOK2LOC(parser, else_keyword),
+ statements,
+ NTOK2LOC(parser, end_keyword)
+ );
}
/**
@@ -3961,23 +4022,15 @@ pm_else_node_create(pm_parser_t *parser, const pm_token_t *else_keyword, pm_stat
*/
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;
+ return pm_embedded_statements_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_TOKENS(parser, opening, closing),
+ TOK2LOC(parser, opening),
+ statements,
+ TOK2LOC(parser, closing)
+ );
}
/**
@@ -3985,22 +4038,14 @@ pm_embedded_statements_node_create(pm_parser_t *parser, const pm_token_t *openin
*/
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;
+ return pm_embedded_variable_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_TOKEN_NODE(parser, operator, variable),
+ TOK2LOC(parser, operator),
+ variable
+ );
}
/**
@@ -4008,23 +4053,15 @@ pm_embedded_variable_node_create(pm_parser_t *parser, const pm_token_t *operator
*/
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;
+ return pm_ensure_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_TOKENS(parser, ensure_keyword, end_keyword),
+ TOK2LOC(parser, ensure_keyword),
+ statements,
+ TOK2LOC(parser, end_keyword)
+ );
}
/**
@@ -4033,16 +4070,13 @@ pm_ensure_node_create(pm_parser_t *parser, const pm_token_t *ensure_keyword, pm_
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;
+ return pm_false_node_new(
+ parser->arena,
+ ++parser->node_id,
+ PM_NODE_FLAG_STATIC_LITERAL,
+ PM_LOCATION_INIT_TOKEN(parser, token)
+ );
}
/**
@@ -4051,50 +4085,31 @@ pm_false_node_create(pm_parser_t *parser, const pm_token_t *token) {
*/
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);
-
+ assert(nodes->size >= 2);
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 = nodes->nodes[nodes->size - 1];
- 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
- };
+ assert(PM_NODE_TYPE_P(left, PM_SPLAT_NODE));
+ assert(PM_NODE_TYPE_P(right, PM_SPLAT_NODE));
+
+ pm_find_pattern_node_t *node = pm_find_pattern_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_NODES(left, right),
+ NULL,
+ (pm_splat_node_t *) left,
+ ((pm_node_list_t) { 0 }),
+ (pm_splat_node_t *) right,
+ ((pm_location_t) { 0 }),
+ ((pm_location_t) { 0 })
+ );
// 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]);
+ pm_node_list_append(parser->arena, &node->requireds, nodes->nodes[index]);
}
return node;
@@ -4111,7 +4126,8 @@ pm_double_parse(pm_parser_t *parser, const pm_token_t *token) {
// First, get a buffer of the content.
size_t length = (size_t) diff;
- char *buffer = xmalloc(sizeof(char) * (length + 1));
+ const size_t buffer_size = sizeof(char) * (length + 1);
+ char *buffer = xmalloc(buffer_size);
memcpy((void *) buffer, token->start, length);
// Next, determine if we need to replace the decimal point because of
@@ -4145,8 +4161,8 @@ pm_double_parse(pm_parser_t *parser, const pm_token_t *token) {
// 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);
+ PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, token, PM_ERR_FLOAT_PARSE);
+ xfree_sized(buffer, buffer_size);
return 0.0;
}
@@ -4164,12 +4180,12 @@ pm_double_parse(pm_parser_t *parser, const pm_token_t *token) {
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);
+ pm_diagnostic_list_append_format(&parser->metadata_arena, &parser->warning_list, PM_TOKEN_START(parser, token), PM_TOKEN_LENGTH(token), 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);
+ xfree_sized(buffer, buffer_size);
return value;
}
@@ -4179,19 +4195,14 @@ pm_double_parse(pm_parser_t *parser, const pm_token_t *token) {
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;
+ return pm_float_node_new(
+ parser->arena,
+ ++parser->node_id,
+ PM_NODE_FLAG_STATIC_LITERAL,
+ PM_LOCATION_INIT_TOKEN(parser, token),
+ pm_double_parse(parser, token)
+ );
}
/**
@@ -4201,22 +4212,17 @@ 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) {
+ return pm_imaginary_node_new(
+ parser->arena,
+ ++parser->node_id,
+ PM_NODE_FLAG_STATIC_LITERAL,
+ PM_LOCATION_INIT_TOKEN(parser, token),
+ UP(pm_float_node_create(parser, &((pm_token_t) {
.type = PM_TOKEN_FLOAT,
.start = token->start,
.end = token->end - 1
- }))
- };
-
- return node;
+ })))
+ );
}
/**
@@ -4226,17 +4232,14 @@ 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 }
- };
+ pm_rational_node_t *node = pm_rational_node_new(
+ parser->arena,
+ ++parser->node_id,
+ PM_INTEGER_BASE_FLAGS_DECIMAL | PM_NODE_FLAG_STATIC_LITERAL,
+ PM_LOCATION_INIT_TOKEN(parser, token),
+ ((pm_integer_t) { 0 }),
+ ((pm_integer_t) { 0 })
+ );
const uint8_t *start = token->start;
const uint8_t *end = token->end - 1; // r
@@ -4263,12 +4266,18 @@ pm_float_node_rational_create(pm_parser_t *parser, const pm_token_t *token) {
memcpy(digits + (point - start), point + 1, (unsigned long) (end - point - 1));
pm_integer_parse(&node->numerator, PM_INTEGER_BASE_DEFAULT, digits, digits + length - 1);
+ size_t fract_length = 0;
+ for (const uint8_t *fract = point; fract < end; ++fract) {
+ if (*fract != '_') ++fract_length;
+ }
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));
- xfree(digits);
+ if (fract_length > 1) memset(digits + 1, '0', fract_length - 1);
+ pm_integer_parse(&node->denominator, PM_INTEGER_BASE_DEFAULT, digits, digits + fract_length);
+ xfree_sized(digits, length);
pm_integers_reduce(&node->numerator, &node->denominator);
+ pm_integer_arena_move(parser->arena, &node->numerator);
+ pm_integer_arena_move(parser->arena, &node->denominator);
return node;
}
@@ -4280,22 +4289,17 @@ 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) {
+ return pm_imaginary_node_new(
+ parser->arena,
+ ++parser->node_id,
+ PM_NODE_FLAG_STATIC_LITERAL,
+ PM_LOCATION_INIT_TOKEN(parser, token),
+ UP(pm_float_node_rational_create(parser, &((pm_token_t) {
.type = PM_TOKEN_FLOAT_RATIONAL,
.start = token->start,
.end = token->end - 1
- }))
- };
-
- return node;
+ })))
+ );
}
/**
@@ -4312,27 +4316,19 @@ pm_for_node_create(
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;
+ return pm_for_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_TOKENS(parser, for_keyword, end_keyword),
+ index,
+ collection,
+ statements,
+ TOK2LOC(parser, for_keyword),
+ TOK2LOC(parser, in_keyword),
+ NTOK2LOC(parser, do_keyword),
+ TOK2LOC(parser, end_keyword)
+ );
}
/**
@@ -4341,15 +4337,13 @@ pm_for_node_create(
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;
+ return pm_forwarding_arguments_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_TOKEN(parser, token)
+ );
}
/**
@@ -4358,15 +4352,13 @@ pm_forwarding_arguments_node_create(pm_parser_t *parser, const pm_token_t *token
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;
+ return pm_forwarding_parameter_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_TOKEN(parser, token)
+ );
}
/**
@@ -4376,26 +4368,20 @@ 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;
+ return pm_forwarding_super_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ (block == NULL) ? PM_LOCATION_INIT_TOKEN(parser, token) : PM_LOCATION_INIT_TOKEN_NODE(parser, token, block),
+ PM_LOCATION_INIT_TOKEN(parser, token),
+ block
+ );
}
/**
@@ -4404,25 +4390,17 @@ pm_forwarding_super_node_create(pm_parser_t *parser, const pm_token_t *token, pm
*/
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;
+ return pm_hash_pattern_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_TOKENS(parser, opening, closing),
+ NULL,
+ ((pm_node_list_t) { 0 }),
+ NULL,
+ TOK2LOC(parser, opening),
+ TOK2LOC(parser, closing)
+ );
}
/**
@@ -4430,46 +4408,36 @@ pm_hash_pattern_node_empty_create(pm_parser_t *parser, const pm_token_t *opening
*/
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;
+ uint32_t start;
+ uint32_t end;
if (elements->size > 0) {
if (rest) {
- start = elements->nodes[0]->location.start;
- end = rest->location.end;
+ start = MIN(PM_NODE_START(rest), PM_NODE_START(elements->nodes[0]));
+ end = MAX(PM_NODE_END(rest), PM_NODE_END(elements->nodes[elements->size - 1]));
} else {
- start = elements->nodes[0]->location.start;
- end = elements->nodes[elements->size - 1]->location.end;
+ start = PM_NODE_START(elements->nodes[0]);
+ end = PM_NODE_END(elements->nodes[elements->size - 1]);
}
} 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);
- }
+ start = PM_NODE_START(rest);
+ end = PM_NODE_END(rest);
+ }
+
+ pm_hash_pattern_node_t *node = pm_hash_pattern_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ ((pm_location_t) { .start = start, .length = U32(end - start) }),
+ NULL,
+ ((pm_node_list_t) { 0 }),
+ rest,
+ ((pm_location_t) { 0 }),
+ ((pm_location_t) { 0 })
+ );
+ pm_node_list_concat(parser->arena, &node->elements, elements);
return node;
}
@@ -4486,7 +4454,7 @@ pm_global_variable_write_name(pm_parser_t *parser, const pm_node_t *target) {
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);
+ return pm_parser_constant_id_raw(parser, parser->start + PM_NODE_START(target), parser->start + PM_NODE_END(target));
default:
assert(false && "unreachable");
return (pm_constant_id_t) -1;
@@ -4499,24 +4467,17 @@ pm_global_variable_write_name(pm_parser_t *parser, const pm_node_t *target) {
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;
+ return pm_global_variable_and_write_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_NODES(target, value),
+ pm_global_variable_write_name(parser, target),
+ target->location,
+ TOK2LOC(parser, operator),
+ value
+ );
}
/**
@@ -4524,25 +4485,17 @@ pm_global_variable_and_write_node_create(pm_parser_t *parser, pm_node_t *target,
*/
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;
+ return pm_global_variable_operator_write_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_NODES(target, value),
+ pm_global_variable_write_name(parser, target),
+ target->location,
+ TOK2LOC(parser, operator),
+ value,
+ pm_parser_constant_id_raw(parser, operator->start, operator->end - 1)
+ );
}
/**
@@ -4551,24 +4504,17 @@ pm_global_variable_operator_write_node_create(pm_parser_t *parser, pm_node_t *ta
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;
+ return pm_global_variable_or_write_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_NODES(target, value),
+ pm_global_variable_write_name(parser, target),
+ target->location,
+ TOK2LOC(parser, operator),
+ value
+ );
}
/**
@@ -4576,18 +4522,13 @@ pm_global_variable_or_write_node_create(pm_parser_t *parser, pm_node_t *target,
*/
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;
+ return pm_global_variable_read_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_TOKEN(parser, name),
+ pm_parser_constant_id_token(parser, name)
+ );
}
/**
@@ -4595,18 +4536,13 @@ pm_global_variable_read_node_create(pm_parser_t *parser, const pm_token_t *name)
*/
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;
+ return pm_global_variable_read_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_UNSET,
+ name
+ );
}
/**
@@ -4614,25 +4550,16 @@ pm_global_variable_read_node_synthesized_create(pm_parser_t *parser, pm_constant
*/
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;
+ return pm_global_variable_write_node_new(
+ parser->arena,
+ ++parser->node_id,
+ pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
+ PM_LOCATION_INIT_NODES(target, value),
+ pm_global_variable_write_name(parser, target),
+ target->location,
+ value,
+ TOK2LOC(parser, operator)
+ );
}
/**
@@ -4640,21 +4567,16 @@ pm_global_variable_write_node_create(pm_parser_t *parser, pm_node_t *target, con
*/
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;
+ return pm_global_variable_write_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_UNSET,
+ name,
+ ((pm_location_t) { 0 }),
+ value,
+ ((pm_location_t) { 0 })
+ );
}
/**
@@ -4663,29 +4585,24 @@ pm_global_variable_write_node_synthesized_create(pm_parser_t *parser, pm_constan
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;
+ return pm_hash_node_new(
+ parser->arena,
+ ++parser->node_id,
+ PM_NODE_FLAG_STATIC_LITERAL,
+ PM_LOCATION_INIT_TOKEN(parser, opening),
+ TOK2LOC(parser, opening),
+ ((pm_node_list_t) { 0 }),
+ ((pm_location_t) { 0 })
+ );
}
/**
* 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);
+static PRISM_INLINE void
+pm_hash_node_elements_append(pm_arena_t *arena, pm_hash_node_t *hash, pm_node_t *element) {
+ pm_node_list_append(arena, &hash->elements, element);
bool static_literal = PM_NODE_TYPE_P(element, PM_ASSOC_NODE);
if (static_literal) {
@@ -4696,14 +4613,14 @@ pm_hash_node_elements_append(pm_hash_node_t *hash, pm_node_t *element) {
}
if (!static_literal) {
- pm_node_flag_unset((pm_node_t *)hash, PM_NODE_FLAG_STATIC_LITERAL);
+ pm_node_flag_unset(UP(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);
+static PRISM_INLINE void
+pm_hash_node_closing_loc_set(const pm_parser_t *parser, pm_hash_node_t *hash, pm_token_t *token) {
+ PM_NODE_LENGTH_SET_TOKEN(parser, hash, token);
+ hash->closing_loc = TOK2LOC(parser, token);
}
/**
@@ -4719,38 +4636,32 @@ pm_if_node_create(pm_parser_t *parser,
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;
+ uint32_t start = PM_TOKEN_START(parser, if_keyword);
+ uint32_t end;
+
+ if (end_keyword != NULL) {
+ end = PM_TOKEN_END(parser, end_keyword);
} else if (subsequent != NULL) {
- end = subsequent->location.end;
+ end = PM_NODE_END(subsequent);
} else if (pm_statements_node_body_length(statements) != 0) {
- end = statements->base.location.end;
+ end = PM_NODE_END(statements);
} 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;
+ end = PM_NODE_END(predicate);
+ }
+
+ return pm_if_node_new(
+ parser->arena,
+ ++parser->node_id,
+ PM_NODE_FLAG_NEWLINE,
+ ((pm_location_t) { .start = start, .length = U32(end - start) }),
+ TOK2LOC(parser, if_keyword),
+ predicate,
+ NTOK2LOC(parser, then_keyword),
+ statements,
+ subsequent,
+ NTOK2LOC(parser, end_keyword)
+ );
}
/**
@@ -4759,30 +4670,22 @@ pm_if_node_create(pm_parser_t *parser,
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;
+ return pm_if_node_new(
+ parser->arena,
+ ++parser->node_id,
+ PM_NODE_FLAG_NEWLINE,
+ PM_LOCATION_INIT_NODES(statement, predicate),
+ TOK2LOC(parser, if_keyword),
+ predicate,
+ ((pm_location_t) { 0 }),
+ statements,
+ NULL,
+ ((pm_location_t) { 0 })
+ );
}
/**
@@ -4799,43 +4702,31 @@ pm_if_node_ternary_create(pm_parser_t *parser, pm_node_t *predicate, const pm_to
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;
-
+ pm_else_node_t *else_node = pm_else_node_create(parser, colon, else_statements, NULL);
+ return pm_if_node_new(
+ parser->arena,
+ ++parser->node_id,
+ PM_NODE_FLAG_NEWLINE,
+ PM_LOCATION_INIT_NODES(predicate, false_expression),
+ ((pm_location_t) { 0 }),
+ predicate,
+ TOK2LOC(parser, qmark),
+ if_statements,
+ UP(else_node),
+ ((pm_location_t) { 0 })
+ );
}
-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 PRISM_INLINE void
+pm_if_node_end_keyword_loc_set(const pm_parser_t *parser, pm_if_node_t *node, const pm_token_t *keyword) {
+ PM_NODE_LENGTH_SET_TOKEN(parser, node, keyword);
+ node->end_keyword_loc = TOK2LOC(parser, 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);
+static PRISM_INLINE void
+pm_else_node_end_keyword_loc_set(const pm_parser_t *parser, pm_else_node_t *node, const pm_token_t *keyword) {
+ PM_NODE_LENGTH_SET_TOKEN(parser, node, keyword);
+ node->end_keyword_loc = TOK2LOC(parser, keyword);
}
/**
@@ -4843,18 +4734,13 @@ pm_else_node_end_keyword_loc_set(pm_else_node_t *node, const pm_token_t *keyword
*/
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;
+ return pm_implicit_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_NODE(value),
+ value
+ );
}
/**
@@ -4864,17 +4750,12 @@ 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;
+ return pm_implicit_rest_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_TOKEN(parser, token)
+ );
}
/**
@@ -4883,28 +4764,33 @@ pm_implicit_rest_node_create(pm_parser_t *parser, const pm_token_t *token) {
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_node_t *node = pm_integer_node_new(
+ parser->arena,
+ ++parser->node_id,
+ base | PM_NODE_FLAG_STATIC_LITERAL,
+ PM_LOCATION_INIT_TOKEN(parser, token),
+ ((pm_integer_t) { 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;
+ if (parser->integer.lexed) {
+ // The value was already computed during lexing.
+ node->value.value = parser->integer.value;
+ parser->integer.lexed = false;
+ } else {
+ 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);
+ pm_integer_arena_move(parser->arena, &node->value);
}
- pm_integer_parse(&node->value, integer_base, token->start, token->end);
return node;
}
@@ -4916,22 +4802,17 @@ 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) {
+ return pm_imaginary_node_new(
+ parser->arena,
+ ++parser->node_id,
+ PM_NODE_FLAG_STATIC_LITERAL,
+ PM_LOCATION_INIT_TOKEN(parser, token),
+ UP(pm_integer_node_create(parser, base, &((pm_token_t) {
.type = PM_TOKEN_INTEGER,
.start = token->start,
.end = token->end - 1
- }))
- };
-
- return node;
+ })))
+ );
}
/**
@@ -4942,17 +4823,14 @@ 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_rational_node_t *node = pm_rational_node_new(
+ parser->arena,
+ ++parser->node_id,
+ base | PM_NODE_FLAG_STATIC_LITERAL,
+ PM_LOCATION_INIT_TOKEN(parser, token),
+ ((pm_integer_t) { 0 }),
+ ((pm_integer_t) { .value = 1 })
+ );
pm_integer_base_t integer_base = PM_INTEGER_BASE_DECIMAL;
switch (base) {
@@ -4964,6 +4842,7 @@ pm_integer_node_rational_create(pm_parser_t *parser, pm_node_flags_t base, const
}
pm_integer_parse(&node->numerator, integer_base, token->start, token->end - 1);
+ pm_integer_arena_move(parser->arena, &node->numerator);
return node;
}
@@ -4976,22 +4855,17 @@ 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) {
+ return pm_imaginary_node_new(
+ parser->arena,
+ ++parser->node_id,
+ PM_NODE_FLAG_STATIC_LITERAL,
+ PM_LOCATION_INIT_TOKEN(parser, token),
+ UP(pm_integer_node_rational_create(parser, base, &((pm_token_t) {
.type = PM_TOKEN_INTEGER_RATIONAL,
.start = token->start,
.end = token->end - 1
- }))
- };
-
- return node;
+ })))
+ );
}
/**
@@ -4999,33 +4873,27 @@ pm_integer_node_rational_imaginary_create(pm_parser_t *parser, pm_node_flags_t b
*/
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);
+ uint32_t start = PM_TOKEN_START(parser, in_keyword);
+ uint32_t end;
- 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;
+ end = PM_NODE_END(statements);
+ } else if (then_keyword != NULL) {
+ end = PM_TOKEN_END(parser, then_keyword);
} 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;
+ end = PM_NODE_END(pattern);
+ }
+
+ return pm_in_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ ((pm_location_t) { .start = start, .length = U32(end - start) }),
+ pattern,
+ statements,
+ TOK2LOC(parser, in_keyword),
+ NTOK2LOC(parser, then_keyword)
+ );
}
/**
@@ -5034,24 +4902,17 @@ pm_in_node_create(pm_parser_t *parser, pm_node_t *pattern, pm_statements_node_t
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;
+ return pm_instance_variable_and_write_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_NODES(target, value),
+ target->name,
+ target->base.location,
+ TOK2LOC(parser, operator),
+ value
+ );
}
/**
@@ -5059,25 +4920,17 @@ pm_instance_variable_and_write_node_create(pm_parser_t *parser, pm_instance_vari
*/
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;
+ return pm_instance_variable_operator_write_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_NODES(target, value),
+ target->name,
+ target->base.location,
+ TOK2LOC(parser, operator),
+ value,
+ pm_parser_constant_id_raw(parser, operator->start, operator->end - 1)
+ );
}
/**
@@ -5086,24 +4939,17 @@ pm_instance_variable_operator_write_node_create(pm_parser_t *parser, pm_instance
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;
+ return pm_instance_variable_or_write_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_NODES(target, value),
+ target->name,
+ target->base.location,
+ TOK2LOC(parser, operator),
+ value
+ );
}
/**
@@ -5112,18 +4958,14 @@ pm_instance_variable_or_write_node_create(pm_parser_t *parser, pm_instance_varia
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;
+ return pm_instance_variable_read_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_TOKEN(parser, token),
+ pm_parser_constant_id_token(parser, token)
+ );
}
/**
@@ -5132,24 +4974,16 @@ pm_instance_variable_read_node_create(pm_parser_t *parser, const pm_token_t *tok
*/
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;
+ return pm_instance_variable_write_node_new(
+ parser->arena,
+ ++parser->node_id,
+ pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
+ PM_LOCATION_INIT_NODES(read_node, value),
+ read_node->name,
+ read_node->base.location,
+ value,
+ TOK2LOC(parser, operator)
+ );
}
/**
@@ -5158,7 +4992,7 @@ pm_instance_variable_write_node_create(pm_parser_t *parser, pm_instance_variable
* literals.
*/
static void
-pm_interpolated_node_append(pm_node_t *node, pm_node_list_t *parts, pm_node_t *part) {
+pm_interpolated_node_append(pm_arena_t *arena, 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);
@@ -5186,14 +5020,14 @@ pm_interpolated_node_append(pm_node_t *node, pm_node_list_t *parts, pm_node_t *p
break;
}
case PM_EMBEDDED_VARIABLE_NODE:
- pm_node_flag_unset((pm_node_t *) node, PM_NODE_FLAG_STATIC_LITERAL);
+ pm_node_flag_unset(UP(node), PM_NODE_FLAG_STATIC_LITERAL);
break;
default:
assert(false && "unexpected node type");
break;
}
- pm_node_list_append(parts, part);
+ pm_node_list_append(arena, parts, part);
}
/**
@@ -5201,43 +5035,34 @@ pm_interpolated_node_append(pm_node_t *node, pm_node_list_t *parts, pm_node_t *p
*/
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;
+ return pm_interpolated_regular_expression_node_new(
+ parser->arena,
+ ++parser->node_id,
+ PM_NODE_FLAG_STATIC_LITERAL,
+ PM_LOCATION_INIT_TOKEN(parser, opening),
+ TOK2LOC(parser, opening),
+ ((pm_node_list_t) { 0 }),
+ TOK2LOC(parser, opening)
+ );
}
-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;
+static PRISM_INLINE void
+pm_interpolated_regular_expression_node_append(pm_arena_t *arena, pm_interpolated_regular_expression_node_t *node, pm_node_t *part) {
+ if (PM_NODE_START(node) > PM_NODE_START(part)) {
+ PM_NODE_START_SET_NODE(node, part);
}
- if (node->base.location.end < part->location.end) {
- node->base.location.end = part->location.end;
+ if (PM_NODE_END(node) < PM_NODE_END(part)) {
+ PM_NODE_LENGTH_SET_NODE(node, part);
}
- pm_interpolated_node_append((pm_node_t *) node, &node->parts, part);
+ pm_interpolated_node_append(arena, UP(node), &node->parts, part);
}
-static inline void
+static PRISM_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));
+ node->closing_loc = TOK2LOC(parser, closing);
+ PM_NODE_LENGTH_SET_TOKEN(parser, node, closing);
+ pm_node_flag_set(UP(node), pm_regular_expression_flags_create(parser, closing));
}
/**
@@ -5249,7 +5074,7 @@ pm_interpolated_regular_expression_node_closing_set(pm_parser_t *parser, pm_inte
* 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,
+ * not; the instructions in CRuby will be either putobject, dupstring or dupchilledstring,
* depending on the combination of `--enable-frozen-string-literal`,
* `# frozen_string_literal: true`, and whether or not there is interpolation.
*
@@ -5263,25 +5088,30 @@ pm_interpolated_regular_expression_node_closing_set(pm_parser_t *parser, pm_inte
* 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) {
+static PRISM_INLINE void
+pm_interpolated_string_node_append(pm_parser_t *parser, pm_interpolated_string_node_t *node, pm_node_t *part) {
+ pm_arena_t *arena = parser->arena;
#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))
+ node->base.flags = (pm_node_flags_t) (FL(node) & ~(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);
+ node->base.flags = (pm_node_flags_t) ((FL(node) | 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;
+ if (node->parts.size == 0 && node->opening_loc.length == 0) {
+ PM_NODE_START_SET_NODE(node, part);
}
- node->base.location.end = MAX(node->base.location.end, part->location.end);
+ if (PM_NODE_END(part) > PM_NODE_END(node)) {
+ PM_NODE_LENGTH_SET_NODE(node, part);
+ }
switch (PM_NODE_TYPE(part)) {
case PM_STRING_NODE:
- // If inner string is not frozen, clear flags for this string
+ // If inner string is not frozen, it stops being a static literal. We should *not* clear other flags,
+ // because concatenating two frozen strings (`'foo' 'bar'`) is still frozen. This holds true for
+ // as long as this interpolation only consists of other string literals.
if (!PM_NODE_FLAG_P(part, PM_STRING_FLAGS_FROZEN)) {
- CLEAR_FLAGS(node);
+ pm_node_flag_unset(UP(node), PM_NODE_FLAG_STATIC_LITERAL);
}
part->flags = (pm_node_flags_t) ((part->flags | PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN) & ~PM_STRING_FLAGS_MUTABLE);
break;
@@ -5334,8 +5164,14 @@ pm_interpolated_string_node_append(pm_interpolated_string_node_t *node, pm_node_
break;
case PM_X_STRING_NODE:
case PM_INTERPOLATED_X_STRING_NODE:
- // If this is an x string, then this is a syntax error. But we want
- // to handle it here so that we don't fail the assertion.
+ case PM_SYMBOL_NODE:
+ case PM_INTERPOLATED_SYMBOL_NODE:
+ // These will only happen in error cases. But we want to handle it
+ // here so that we don't fail the assertion.
+ CLEAR_FLAGS(node);
+ pm_node_list_append(arena, &node->parts, UP(pm_error_recovery_node_create_unexpected(parser, part)));
+ return;
+ case PM_ERROR_RECOVERY_NODE:
CLEAR_FLAGS(node);
break;
default:
@@ -5343,7 +5179,7 @@ pm_interpolated_string_node_append(pm_interpolated_string_node_t *node, pm_node_
break;
}
- pm_node_list_append(&node->parts, part);
+ pm_node_list_append(arena, &node->parts, part);
#undef CLEAR_FLAGS
#undef MUTABLE_FLAGS
@@ -5354,7 +5190,6 @@ pm_interpolated_string_node_append(pm_interpolated_string_node_t *node, pm_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) {
@@ -5366,25 +5201,23 @@ pm_interpolated_string_node_create(pm_parser_t *parser, const pm_token_t *openin
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 }
- };
+ uint32_t start = opening == NULL ? 0 : PM_TOKEN_START(parser, opening);
+ uint32_t end = closing == NULL ? 0 : PM_TOKEN_END(parser, closing);
+
+ pm_interpolated_string_node_t *node = pm_interpolated_string_node_new(
+ parser->arena,
+ ++parser->node_id,
+ flags,
+ ((pm_location_t) { .start = start, .length = U32(end - start) }),
+ NTOK2LOC(parser, opening),
+ ((pm_node_list_t) { 0 }),
+ NTOK2LOC(parser, closing)
+ );
if (parts != NULL) {
pm_node_t *part;
PM_NODE_LIST_FOREACH(parts, index, part) {
- pm_interpolated_string_node_append(node, part);
+ pm_interpolated_string_node_append(parser, node, part);
}
}
@@ -5395,25 +5228,28 @@ pm_interpolated_string_node_create(pm_parser_t *parser, const pm_token_t *openin
* 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;
+pm_interpolated_string_node_closing_set(const pm_parser_t *parser, pm_interpolated_string_node_t *node, const pm_token_t *closing) {
+ node->closing_loc = TOK2LOC(parser, closing);
+ PM_NODE_LENGTH_SET_TOKEN(parser, node, closing);
}
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_symbol_node_append(pm_arena_t *arena, pm_interpolated_symbol_node_t *node, pm_node_t *part) {
+ if (node->parts.size == 0 && node->opening_loc.length == 0) {
+ PM_NODE_START_SET_NODE(node, part);
}
- pm_interpolated_node_append((pm_node_t *) node, &node->parts, part);
- node->base.location.end = MAX(node->base.location.end, part->location.end);
+ pm_interpolated_node_append(arena, UP(node), &node->parts, part);
+
+ if (PM_NODE_END(part) > PM_NODE_END(node)) {
+ PM_NODE_LENGTH_SET_NODE(node, part);
+ }
}
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;
+pm_interpolated_symbol_node_closing_loc_set(const pm_parser_t *parser, pm_interpolated_symbol_node_t *node, const pm_token_t *closing) {
+ node->closing_loc = TOK2LOC(parser, closing);
+ PM_NODE_LENGTH_SET_TOKEN(parser, node, closing);
}
/**
@@ -5421,27 +5257,23 @@ pm_interpolated_symbol_node_closing_loc_set(pm_interpolated_symbol_node_t *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 }
- };
+ uint32_t start = opening == NULL ? 0 : PM_TOKEN_START(parser, opening);
+ uint32_t end = closing == NULL ? 0 : PM_TOKEN_END(parser, closing);
+
+ pm_interpolated_symbol_node_t *node = pm_interpolated_symbol_node_new(
+ parser->arena,
+ ++parser->node_id,
+ PM_NODE_FLAG_STATIC_LITERAL,
+ ((pm_location_t) { .start = start, .length = U32(end - start) }),
+ NTOK2LOC(parser, opening),
+ ((pm_node_list_t) { 0 }),
+ NTOK2LOC(parser, closing)
+ );
if (parts != NULL) {
pm_node_t *part;
PM_NODE_LIST_FOREACH(parts, index, part) {
- pm_interpolated_symbol_node_append(node, part);
+ pm_interpolated_symbol_node_append(parser->arena, node, part);
}
}
@@ -5453,35 +5285,27 @@ pm_interpolated_symbol_node_create(pm_parser_t *parser, const pm_token_t *openin
*/
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;
+ return pm_interpolated_x_string_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_TOKENS(parser, opening, closing),
+ TOK2LOC(parser, opening),
+ ((pm_node_list_t) { 0 }),
+ TOK2LOC(parser, closing)
+ );
}
-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 PRISM_INLINE void
+pm_interpolated_xstring_node_append(pm_arena_t *arena, pm_interpolated_x_string_node_t *node, pm_node_t *part) {
+ pm_interpolated_node_append(arena, UP(node), &node->parts, part);
+ PM_NODE_LENGTH_SET_NODE(node, part);
}
-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;
+static PRISM_INLINE void
+pm_interpolated_xstring_node_closing_set(const pm_parser_t *parser, pm_interpolated_x_string_node_t *node, const pm_token_t *closing) {
+ node->closing_loc = TOK2LOC(parser, closing);
+ PM_NODE_LENGTH_SET_TOKEN(parser, node, closing);
}
/**
@@ -5489,17 +5313,12 @@ pm_interpolated_xstring_node_closing_set(pm_interpolated_x_string_node_t *node,
*/
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;
+ return pm_it_local_variable_read_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_TOKEN(parser, name)
+ );
}
/**
@@ -5507,20 +5326,12 @@ pm_it_local_variable_read_node_create(pm_parser_t *parser, const pm_token_t *nam
*/
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;
+ return pm_it_parameters_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_TOKENS(parser, opening, closing)
+ );
}
/**
@@ -5528,37 +5339,31 @@ pm_it_parameters_node_create(pm_parser_t *parser, const pm_token_t *opening, con
*/
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;
+ return pm_keyword_hash_node_new(
+ parser->arena,
+ ++parser->node_id,
+ PM_KEYWORD_HASH_NODE_FLAGS_SYMBOL_KEYS,
+ PM_LOCATION_INIT_UNSET,
+ ((pm_node_list_t) { 0 })
+ );
}
/**
* 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) {
+pm_keyword_hash_node_elements_append(pm_arena_t *arena, 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_flag_unset(UP(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;
+ pm_node_list_append(arena, &hash->elements, element);
+ if (PM_NODE_LENGTH(hash) == 0) {
+ PM_NODE_START_SET_NODE(hash, element);
}
- hash->base.location.end = element->location.end;
+ PM_NODE_LENGTH_SET_NODE(hash, element);
}
/**
@@ -5566,22 +5371,14 @@ pm_keyword_hash_node_elements_append(pm_keyword_hash_node_t *hash, pm_node_t *el
*/
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;
+ return pm_required_keyword_parameter_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_TOKEN(parser, name),
+ pm_parser_constant_id_raw(parser, name->start, name->end - 1),
+ TOK2LOC(parser, name)
+ );
}
/**
@@ -5589,23 +5386,15 @@ pm_required_keyword_parameter_node_create(pm_parser_t *parser, const pm_token_t
*/
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;
+ return pm_optional_keyword_parameter_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_TOKEN_NODE(parser, name, value),
+ pm_parser_constant_id_raw(parser, name->start, name->end - 1),
+ TOK2LOC(parser, name),
+ value
+ );
}
/**
@@ -5613,23 +5402,15 @@ pm_optional_keyword_parameter_node_create(pm_parser_t *parser, const pm_token_t
*/
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;
+ return pm_keyword_rest_parameter_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ (name == NULL) ? PM_LOCATION_INIT_TOKEN(parser, operator) : PM_LOCATION_INIT_TOKENS(parser, operator, name),
+ name == NULL ? 0 : pm_parser_constant_id_token(parser, name),
+ NTOK2LOC(parser, name),
+ TOK2LOC(parser, operator)
+ );
}
/**
@@ -5645,26 +5426,18 @@ pm_lambda_node_create(
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;
+ return pm_lambda_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_TOKENS(parser, operator, closing),
+ *locals,
+ TOK2LOC(parser, operator),
+ TOK2LOC(parser, opening),
+ TOK2LOC(parser, closing),
+ parameters,
+ body
+ );
}
/**
@@ -5674,25 +5447,18 @@ 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_IT_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;
+ return pm_local_variable_and_write_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_NODES(target, value),
+ target->location,
+ TOK2LOC(parser, operator),
+ value,
+ name,
+ depth
+ );
}
/**
@@ -5700,26 +5466,18 @@ pm_local_variable_and_write_node_create(pm_parser_t *parser, pm_node_t *target,
*/
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;
+ return pm_local_variable_operator_write_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_NODES(target, value),
+ target->location,
+ TOK2LOC(parser, operator),
+ value,
+ name,
+ pm_parser_constant_id_raw(parser, operator->start, operator->end - 1),
+ depth
+ );
}
/**
@@ -5729,25 +5487,18 @@ 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_IT_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;
+ return pm_local_variable_or_write_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_NODES(target, value),
+ target->location,
+ TOK2LOC(parser, operator),
+ value,
+ name,
+ depth
+ );
}
/**
@@ -5757,19 +5508,14 @@ 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;
+ return pm_local_variable_read_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_TOKEN(parser, name),
+ name_id,
+ depth
+ );
}
/**
@@ -5796,32 +5542,23 @@ pm_local_variable_read_node_missing_create(pm_parser_t *parser, const pm_token_t
*/
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;
+ return pm_local_variable_write_node_new(
+ parser->arena,
+ ++parser->node_id,
+ pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
+ ((pm_location_t) { .start = name_loc->start, .length = PM_NODE_END(value) - name_loc->start }),
+ name,
+ depth,
+ *name_loc,
+ value,
+ TOK2LOC(parser, operator)
+ );
}
/**
* Returns true if the given bounds comprise `it`.
*/
-static inline bool
+static PRISM_INLINE bool
pm_token_is_it(const uint8_t *start, const uint8_t *end) {
return (end - start == 2) && (start[0] == 'i') && (start[1] == 't');
}
@@ -5830,19 +5567,24 @@ pm_token_is_it(const uint8_t *start, const uint8_t *end) {
* 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]));
+static PRISM_INLINE bool
+pm_token_is_numbered_parameter(const pm_parser_t *parser, uint32_t start, uint32_t length) {
+ return (
+ (length == 2) &&
+ (parser->start[start] == '_') &&
+ (parser->start[start + 1] != '0') &&
+ pm_char_is_decimal_digit(parser->start[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);
+static PRISM_INLINE void
+pm_refute_numbered_parameter(pm_parser_t *parser, uint32_t start, uint32_t length) {
+ if (pm_token_is_numbered_parameter(parser, start, length)) {
+ PM_PARSER_ERR_FORMAT(parser, start, length, PM_ERR_PARAMETER_NUMBERED_RESERVED, parser->start + start);
}
}
@@ -5852,20 +5594,16 @@ pm_refute_numbered_parameter(pm_parser_t *parser, const uint8_t *start, const ui
*/
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;
+ pm_refute_numbered_parameter(parser, location->start, location->length);
+
+ return pm_local_variable_target_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ ((pm_location_t) { .start = location->start, .length = location->length }),
+ name,
+ depth
+ );
}
/**
@@ -5875,23 +5613,15 @@ 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;
+ return pm_match_predicate_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_NODES(value, pattern),
+ value,
+ pattern,
+ TOK2LOC(parser, operator)
+ );
}
/**
@@ -5901,23 +5631,15 @@ 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;
+ return pm_match_required_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_NODES(value, pattern),
+ value,
+ pattern,
+ TOK2LOC(parser, operator)
+ );
}
/**
@@ -5925,19 +5647,14 @@ pm_match_required_node_create(pm_parser_t *parser, pm_node_t *value, pm_node_t *
*/
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;
+ return pm_match_write_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_NODE(call),
+ call,
+ ((pm_node_list_t) { 0 })
+ );
}
/**
@@ -5945,26 +5662,18 @@ pm_match_write_node_create(pm_parser_t *parser, pm_call_node_t *call) {
*/
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;
+ return pm_module_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_TOKENS(parser, module_keyword, end_keyword),
+ (locals == NULL ? ((pm_constant_id_list_t) { .ids = NULL, .size = 0, .capacity = 0 }) : *locals),
+ TOK2LOC(parser, module_keyword),
+ constant_path,
+ body,
+ TOK2LOC(parser, end_keyword),
+ pm_parser_constant_id_token(parser, name)
+ );
}
/**
@@ -5972,22 +5681,17 @@ pm_module_node_create(pm_parser_t *parser, pm_constant_id_list_t *locals, const
*/
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;
+ return pm_multi_target_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_UNSET,
+ ((pm_node_list_t) { 0 }),
+ NULL,
+ ((pm_node_list_t) { 0 }),
+ ((pm_location_t) { 0 }),
+ ((pm_location_t) { 0 })
+ );
}
/**
@@ -6000,27 +5704,27 @@ pm_multi_target_node_targets_append(pm_parser_t *parser, pm_multi_target_node_t
node->rest = target;
} else {
pm_parser_err_node(parser, target, PM_ERR_MULTI_ASSIGN_MULTI_SPLATS);
- pm_node_list_append(&node->rights, target);
+ pm_node_list_append(parser->arena, &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);
+ PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, &parser->current, PM_ERR_MULTI_ASSIGN_UNEXPECTED_REST);
+ pm_node_list_append(parser->arena, &node->rights, target);
}
} else if (node->rest == NULL) {
- pm_node_list_append(&node->lefts, target);
+ pm_node_list_append(parser->arena, &node->lefts, target);
} else {
- pm_node_list_append(&node->rights, target);
+ pm_node_list_append(parser->arena, &node->rights, target);
}
- if (node->base.location.start == NULL || (node->base.location.start > target->location.start)) {
- node->base.location.start = target->location.start;
+ if (PM_NODE_LENGTH(node) == 0 || (PM_NODE_START(node) > PM_NODE_START(target))) {
+ PM_NODE_START_SET_NODE(node, target);
}
- if (node->base.location.end == NULL || (node->base.location.end < target->location.end)) {
- node->base.location.end = target->location.end;
+ if (PM_NODE_LENGTH(node) == 0 || (PM_NODE_END(node) < PM_NODE_END(target))) {
+ PM_NODE_LENGTH_SET_NODE(node, target);
}
}
@@ -6028,18 +5732,19 @@ pm_multi_target_node_targets_append(pm_parser_t *parser, pm_multi_target_node_t
* 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);
+pm_multi_target_node_opening_set(const pm_parser_t *parser, pm_multi_target_node_t *node, const pm_token_t *lparen) {
+ PM_NODE_START_SET_TOKEN(parser, node, lparen);
+ PM_NODE_LENGTH_SET_TOKEN(parser, node, lparen);
+ node->lparen_loc = TOK2LOC(parser, 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);
+pm_multi_target_node_closing_set(const pm_parser_t *parser, pm_multi_target_node_t *node, const pm_token_t *rparen) {
+ PM_NODE_LENGTH_SET_TOKEN(parser, node, rparen);
+ node->rparen_loc = TOK2LOC(parser, rparen);
}
/**
@@ -6047,32 +5752,21 @@ pm_multi_target_node_closing_set(pm_multi_target_node_t *node, const pm_token_t
*/
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;
+ /* The target is no longer necessary because we have reused its children. It
+ * is arena-allocated so no explicit free is needed. */
+ return pm_multi_write_node_new(
+ parser->arena,
+ ++parser->node_id,
+ pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
+ PM_LOCATION_INIT_NODES(target, value),
+ target->lefts,
+ target->rest,
+ target->rights,
+ target->lparen_loc,
+ target->rparen_loc,
+ TOK2LOC(parser, operator),
+ value
+ );
}
/**
@@ -6081,22 +5775,15 @@ pm_multi_write_node_create(pm_parser_t *parser, pm_multi_target_node_t *target,
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;
+ return pm_next_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ (arguments == NULL) ? PM_LOCATION_INIT_TOKEN(parser, keyword) : PM_LOCATION_INIT_TOKEN_NODE(parser, keyword, arguments),
+ arguments,
+ TOK2LOC(parser, keyword)
+ );
}
/**
@@ -6105,16 +5792,31 @@ pm_next_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_arguments
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 pm_nil_node_new(
+ parser->arena,
+ ++parser->node_id,
+ PM_NODE_FLAG_STATIC_LITERAL,
+ PM_LOCATION_INIT_TOKEN(parser, token)
+ );
+}
- return node;
+/**
+ * Allocate and initialize a new NoKeywordsParameterNode node.
+ */
+static pm_no_block_parameter_node_t *
+pm_no_block_parameter_node_create(pm_parser_t *parser, const pm_token_t *operator, const pm_token_t *keyword) {
+ assert(operator->type == PM_TOKEN_AMPERSAND || operator->type == PM_TOKEN_UAMPERSAND);
+ assert(keyword->type == PM_TOKEN_KEYWORD_NIL);
+
+ return pm_no_block_parameter_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_TOKENS(parser, operator, keyword),
+ TOK2LOC(parser, operator),
+ TOK2LOC(parser, keyword)
+ );
}
/**
@@ -6124,41 +5826,29 @@ 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;
+ return pm_no_keywords_parameter_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_TOKENS(parser, operator, keyword),
+ TOK2LOC(parser, operator),
+ TOK2LOC(parser, keyword)
+ );
}
/**
* 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;
+pm_numbered_parameters_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *closing, uint8_t maximum) {
+ return pm_numbered_parameters_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_TOKENS(parser, opening, closing),
+ maximum
+ );
}
/**
@@ -6194,14 +5884,14 @@ pm_numbered_reference_read_node_number(pm_parser_t *parser, const pm_token_t *to
unsigned long value = strtoul(digits, &endptr, 10);
if ((digits == endptr) || (*endptr != '\0')) {
- pm_parser_err(parser, start, end, PM_ERR_INVALID_NUMBER_DECIMAL);
+ pm_parser_err(parser, U32(start - parser->start), U32(length), PM_ERR_INVALID_NUMBER_DECIMAL);
value = 0;
}
- xfree(digits);
+ xfree_sized(digits, sizeof(char) * (length + 1));
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);
+ PM_PARSER_WARN_FORMAT(parser, U32(start - parser->start), U32(length), PM_WARN_INVALID_NUMBERED_REFERENCE, (int) (length + 1), (const char *) token->start);
value = 0;
}
@@ -6216,18 +5906,14 @@ pm_numbered_reference_read_node_number(pm_parser_t *parser, const pm_token_t *to
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;
+ return pm_numbered_reference_read_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_TOKEN(parser, name),
+ pm_numbered_reference_read_node_number(parser, name)
+ );
}
/**
@@ -6235,24 +5921,16 @@ pm_numbered_reference_read_node_create(pm_parser_t *parser, const pm_token_t *na
*/
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;
+ return pm_optional_parameter_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_TOKEN_NODE(parser, name, value),
+ pm_parser_constant_id_token(parser, name),
+ TOK2LOC(parser, name),
+ TOK2LOC(parser, operator),
+ value
+ );
}
/**
@@ -6262,23 +5940,15 @@ 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;
+ return pm_or_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_NODES(left, right),
+ left,
+ right,
+ TOK2LOC(parser, operator)
+ );
}
/**
@@ -6286,24 +5956,19 @@ pm_or_node_create(pm_parser_t *parser, pm_node_t *left, const pm_token_t *operat
*/
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;
+ return pm_parameters_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_UNSET,
+ ((pm_node_list_t) { 0 }),
+ ((pm_node_list_t) { 0 }),
+ NULL,
+ ((pm_node_list_t) { 0 }),
+ ((pm_node_list_t) { 0 }),
+ NULL,
+ NULL
+ );
}
/**
@@ -6311,16 +5976,12 @@ pm_parameters_node_create(pm_parser_t *parser) {
*/
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.length == 0) || PM_NODE_START(params) > PM_NODE_START(param)) {
+ PM_NODE_START_SET_NODE(params, param);
}
- 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;
+ if ((params->base.location.length == 0) || (PM_NODE_END(params) < PM_NODE_END(param))) {
+ PM_NODE_LENGTH_SET_NODE(params, param);
}
}
@@ -6328,27 +5989,27 @@ pm_parameters_node_location_set(pm_parameters_node_t *params, pm_node_t *param)
* 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_requireds_append(pm_arena_t *arena, pm_parameters_node_t *params, pm_node_t *param) {
pm_parameters_node_location_set(params, param);
- pm_node_list_append(&params->requireds, param);
+ pm_node_list_append(arena, &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);
+pm_parameters_node_optionals_append(pm_arena_t *arena, pm_parameters_node_t *params, pm_optional_parameter_node_t *param) {
+ pm_parameters_node_location_set(params, UP(param));
+ pm_node_list_append(arena, &params->optionals, UP(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_posts_append(pm_arena_t *arena, pm_parameters_node_t *params, pm_node_t *param) {
pm_parameters_node_location_set(params, param);
- pm_node_list_append(&params->posts, param);
+ pm_node_list_append(arena, &params->posts, param);
}
/**
@@ -6364,9 +6025,9 @@ pm_parameters_node_rest_set(pm_parameters_node_t *params, pm_node_t *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_keywords_append(pm_arena_t *arena, pm_parameters_node_t *params, pm_node_t *param) {
pm_parameters_node_location_set(params, param);
- pm_node_list_append(&params->keywords, param);
+ pm_node_list_append(arena, &params->keywords, param);
}
/**
@@ -6383,9 +6044,9 @@ pm_parameters_node_keyword_rest_set(pm_parameters_node_t *params, pm_node_t *par
* 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) {
+pm_parameters_node_block_set(pm_parameters_node_t *params, pm_node_t *param) {
assert(params->block == NULL);
- pm_parameters_node_location_set(params, (pm_node_t *) param);
+ pm_parameters_node_location_set(params, param);
params->block = param;
}
@@ -6394,22 +6055,14 @@ pm_parameters_node_block_set(pm_parameters_node_t *params, pm_block_parameter_no
*/
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;
+ return pm_program_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_NODE(statements),
+ *locals,
+ statements
+ );
}
/**
@@ -6417,24 +6070,15 @@ pm_program_node_create(pm_parser_t *parser, pm_constant_id_list_t *locals, pm_st
*/
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_node_flags_t flags) {
- pm_parentheses_node_t *node = PM_NODE_ALLOC(parser, pm_parentheses_node_t);
-
- *node = (pm_parentheses_node_t) {
- {
- .type = PM_PARENTHESES_NODE,
- .flags = flags,
- .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;
+ return pm_parentheses_node_new(
+ parser->arena,
+ ++parser->node_id,
+ flags,
+ PM_LOCATION_INIT_TOKENS(parser, opening, closing),
+ body,
+ TOK2LOC(parser, opening),
+ TOK2LOC(parser, closing)
+ );
}
/**
@@ -6442,24 +6086,16 @@ pm_parentheses_node_create(pm_parser_t *parser, const pm_token_t *opening, pm_no
*/
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;
+ return pm_pinned_expression_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_TOKENS(parser, operator, rparen),
+ expression,
+ TOK2LOC(parser, operator),
+ TOK2LOC(parser, lparen),
+ TOK2LOC(parser, rparen)
+ );
}
/**
@@ -6467,22 +6103,14 @@ pm_pinned_expression_node_create(pm_parser_t *parser, pm_node_t *expression, con
*/
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;
+ return pm_pinned_variable_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_TOKEN_NODE(parser, operator, variable),
+ variable,
+ TOK2LOC(parser, operator)
+ );
}
/**
@@ -6490,24 +6118,16 @@ pm_pinned_variable_node_create(pm_parser_t *parser, const pm_token_t *operator,
*/
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;
+ return pm_post_execution_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_TOKENS(parser, keyword, closing),
+ statements,
+ TOK2LOC(parser, keyword),
+ TOK2LOC(parser, opening),
+ TOK2LOC(parser, closing)
+ );
}
/**
@@ -6515,24 +6135,16 @@ pm_post_execution_node_create(pm_parser_t *parser, const pm_token_t *keyword, co
*/
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;
+ return pm_pre_execution_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_TOKENS(parser, keyword, closing),
+ statements,
+ TOK2LOC(parser, keyword),
+ TOK2LOC(parser, opening),
+ TOK2LOC(parser, closing)
+ );
}
/**
@@ -6542,8 +6154,6 @@ 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 `...`.
@@ -6561,22 +6171,18 @@ pm_range_node_create(pm_parser_t *parser, pm_node_t *left, const pm_token_t *ope
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)
- };
+ uint32_t start = left == NULL ? PM_TOKEN_START(parser, operator) : PM_NODE_START(left);
+ uint32_t end = right == NULL ? PM_TOKEN_END(parser, operator) : PM_NODE_END(right);
- return node;
+ return pm_range_node_new(
+ parser->arena,
+ ++parser->node_id,
+ flags,
+ ((pm_location_t) { .start = start, .length = U32(end - start) }),
+ left,
+ right,
+ TOK2LOC(parser, operator)
+ );
}
/**
@@ -6585,15 +6191,13 @@ pm_range_node_create(pm_parser_t *parser, pm_node_t *left, const pm_token_t *ope
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;
+ return pm_redo_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_TOKEN(parser, token)
+ );
}
/**
@@ -6602,31 +6206,22 @@ pm_redo_node_create(pm_parser_t *parser, const pm_token_t *token) {
*/
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;
+ return pm_regular_expression_node_new(
+ parser->arena,
+ ++parser->node_id,
+ pm_regular_expression_flags_create(parser, closing) | PM_NODE_FLAG_STATIC_LITERAL,
+ PM_LOCATION_INIT_TOKENS(parser, opening, closing),
+ TOK2LOC(parser, opening),
+ TOK2LOC(parser, content),
+ TOK2LOC(parser, closing),
+ *unescaped
+ );
}
/**
* Allocate a new initialize a new RegularExpressionNode node.
*/
-static inline pm_regular_expression_node_t *
+static PRISM_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);
}
@@ -6636,18 +6231,13 @@ pm_regular_expression_node_create(pm_parser_t *parser, const pm_token_t *opening
*/
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;
+ return pm_required_parameter_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_TOKEN(parser, token),
+ pm_parser_constant_id_token(parser, token)
+ );
}
/**
@@ -6655,23 +6245,15 @@ pm_required_parameter_node_create(pm_parser_t *parser, const pm_token_t *token)
*/
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;
+ return pm_rescue_modifier_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_NODES(expression, rescue_expression),
+ expression,
+ TOK2LOC(parser, keyword),
+ rescue_expression
+ );
}
/**
@@ -6679,29 +6261,24 @@ pm_rescue_modifier_node_create(pm_parser_t *parser, pm_node_t *expression, const
*/
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,
- .then_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
- .reference = NULL,
- .statements = NULL,
- .subsequent = NULL,
- .exceptions = { 0 }
- };
-
- return node;
+ return pm_rescue_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_TOKEN(parser, keyword),
+ TOK2LOC(parser, keyword),
+ ((pm_node_list_t) { 0 }),
+ ((pm_location_t) { 0 }),
+ NULL,
+ ((pm_location_t) { 0 }),
+ NULL,
+ NULL
+ );
}
-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);
+static PRISM_INLINE void
+pm_rescue_node_operator_set(const pm_parser_t *parser, pm_rescue_node_t *node, const pm_token_t *operator) {
+ node->operator_loc = TOK2LOC(parser, operator);
}
/**
@@ -6710,7 +6287,7 @@ pm_rescue_node_operator_set(pm_rescue_node_t *node, const pm_token_t *operator)
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;
+ PM_NODE_LENGTH_SET_NODE(node, reference);
}
/**
@@ -6720,7 +6297,7 @@ 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;
+ PM_NODE_LENGTH_SET_NODE(node, statements);
}
}
@@ -6730,16 +6307,16 @@ pm_rescue_node_statements_set(pm_rescue_node_t *node, pm_statements_node_t *stat
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;
+ PM_NODE_LENGTH_SET_NODE(node, subsequent);
}
/**
* 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;
+pm_rescue_node_exceptions_append(pm_arena_t *arena, pm_rescue_node_t *node, pm_node_t *exception) {
+ pm_node_list_append(arena, &node->exceptions, exception);
+ PM_NODE_LENGTH_SET_NODE(node, exception);
}
/**
@@ -6747,23 +6324,15 @@ pm_rescue_node_exceptions_append(pm_rescue_node_t *node, pm_node_t *exception) {
*/
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;
+ return pm_rest_parameter_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ (name == NULL) ? PM_LOCATION_INIT_TOKEN(parser, operator) : PM_LOCATION_INIT_TOKENS(parser, operator, name),
+ name == NULL ? 0 : pm_parser_constant_id_token(parser, name),
+ NTOK2LOC(parser, name),
+ TOK2LOC(parser, operator)
+ );
}
/**
@@ -6772,15 +6341,13 @@ pm_rest_parameter_node_create(pm_parser_t *parser, const pm_token_t *operator, c
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;
+ return pm_retry_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_TOKEN(parser, token)
+ );
}
/**
@@ -6788,22 +6355,14 @@ pm_retry_node_create(pm_parser_t *parser, const pm_token_t *token) {
*/
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;
+ return pm_return_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ (arguments == NULL) ? PM_LOCATION_INIT_TOKEN(parser, keyword) : PM_LOCATION_INIT_TOKEN_NODE(parser, keyword, arguments),
+ TOK2LOC(parser, keyword),
+ arguments
+ );
}
/**
@@ -6812,15 +6371,13 @@ pm_return_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_argumen
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;
+ return pm_self_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_TOKEN(parser, token)
+ );
}
/**
@@ -6828,19 +6385,13 @@ pm_self_node_create(pm_parser_t *parser, const pm_token_t *token) {
*/
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;
+ return pm_shareable_constant_node_new(
+ parser->arena,
+ ++parser->node_id,
+ (pm_node_flags_t) value,
+ PM_LOCATION_INIT_NODE(write),
+ write
+ );
}
/**
@@ -6848,26 +6399,18 @@ pm_shareable_constant_node_create(pm_parser_t *parser, pm_node_t *write, pm_shar
*/
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;
+ return pm_singleton_class_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_TOKENS(parser, class_keyword, end_keyword),
+ *locals,
+ TOK2LOC(parser, class_keyword),
+ TOK2LOC(parser, operator),
+ expression,
+ body,
+ TOK2LOC(parser, end_keyword)
+ );
}
/**
@@ -6876,16 +6419,13 @@ pm_singleton_class_node_create(pm_parser_t *parser, pm_constant_id_list_t *local
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;
+ return pm_source_encoding_node_new(
+ parser->arena,
+ ++parser->node_id,
+ PM_NODE_FLAG_STATIC_LITERAL,
+ PM_LOCATION_INIT_TOKEN(parser, token)
+ );
}
/**
@@ -6893,7 +6433,6 @@ pm_source_encoding_node_create(pm_parser_t *parser, const pm_token_t *token) {
*/
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;
@@ -6907,17 +6446,13 @@ pm_source_file_node_create(pm_parser_t *parser, const pm_token_t *file_keyword)
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;
+ return pm_source_file_node_new(
+ parser->arena,
+ ++parser->node_id,
+ flags,
+ PM_LOCATION_INIT_TOKEN(parser, file_keyword),
+ parser->filepath
+ );
}
/**
@@ -6926,16 +6461,13 @@ pm_source_file_node_create(pm_parser_t *parser, const pm_token_t *file_keyword)
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;
+ return pm_source_line_node_new(
+ parser->arena,
+ ++parser->node_id,
+ PM_NODE_FLAG_STATIC_LITERAL,
+ PM_LOCATION_INIT_TOKEN(parser, token)
+ );
}
/**
@@ -6943,22 +6475,14 @@ pm_source_line_node_create(pm_parser_t *parser, const pm_token_t *token) {
*/
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;
+ return pm_splat_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ (expression == NULL) ? PM_LOCATION_INIT_TOKEN(parser, operator) : PM_LOCATION_INIT_TOKEN_NODE(parser, operator, expression),
+ TOK2LOC(parser, operator),
+ expression
+ );
}
/**
@@ -6966,18 +6490,13 @@ pm_splat_node_create(pm_parser_t *parser, const pm_token_t *operator, pm_node_t
*/
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;
+ return pm_statements_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_UNSET,
+ ((pm_node_list_t) { 0 })
+ );
}
/**
@@ -6989,25 +6508,17 @@ pm_statements_node_body_length(pm_statements_node_t *node) {
}
/**
- * 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
+static PRISM_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 (pm_statements_node_body_length(node) == 0 || PM_NODE_START(statement) < PM_NODE_START(node)) {
+ PM_NODE_START_SET_NODE(node, statement);
}
- if (statement->location.end > node->base.location.end) {
- node->base.location.end = statement->location.end;
+ if (PM_NODE_END(statement) > PM_NODE_END(node)) {
+ PM_NODE_LENGTH_SET_NODE(node, statement);
}
}
@@ -7034,7 +6545,7 @@ pm_statements_node_body_append(pm_parser_t *parser, pm_statements_node_t *node,
}
}
- pm_node_list_append(&node->body, statement);
+ pm_node_list_append(parser->arena, &node->body, statement);
if (newline) pm_node_flag_set(statement, PM_NODE_FLAG_NEWLINE);
}
@@ -7042,18 +6553,17 @@ pm_statements_node_body_append(pm_parser_t *parser, pm_statements_node_t *node,
* 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_prepend(pm_arena_t *arena, 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_list_prepend(arena, &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 *
+static PRISM_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) {
@@ -7065,23 +6575,19 @@ pm_string_node_create_unescaped(pm_parser_t *parser, const pm_token_t *opening,
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
- };
+ uint32_t start = PM_TOKEN_START(parser, opening == NULL ? content : opening);
+ uint32_t end = PM_TOKEN_END(parser, closing == NULL ? content : closing);
- return node;
+ return pm_string_node_new(
+ parser->arena,
+ ++parser->node_id,
+ flags,
+ ((pm_location_t) { .start = start, .length = U32(end - start) }),
+ NTOK2LOC(parser, opening),
+ TOK2LOC(parser, content),
+ NTOK2LOC(parser, closing),
+ *string
+ );
}
/**
@@ -7109,30 +6615,21 @@ pm_string_node_create_current_string(pm_parser_t *parser, const pm_token_t *open
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;
+ const pm_location_t *end = pm_arguments_end(arguments);
+ assert(end != NULL && "unreachable");
+
+ return pm_super_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ ((pm_location_t) { .start = PM_TOKEN_START(parser, keyword), .length = PM_LOCATION_END(end) - PM_TOKEN_START(parser, keyword) }),
+ TOK2LOC(parser, keyword),
+ arguments->opening_loc,
+ arguments->arguments,
+ arguments->closing_loc,
+ arguments->block
+ );
}
/**
@@ -7160,7 +6657,7 @@ parse_symbol_encoding_validate_utf8(pm_parser_t *parser, const pm_token_t *locat
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);
+ pm_parser_err(parser, PM_TOKEN_START(parser, location), PM_TOKEN_LENGTH(location), PM_ERR_INVALID_SYMBOL);
break;
}
@@ -7180,7 +6677,7 @@ parse_symbol_encoding_validate_other(pm_parser_t *parser, const pm_token_t *loca
size_t width = encoding->char_width(cursor, end - cursor);
if (width == 0) {
- pm_parser_err(parser, location->start, location->end, PM_ERR_INVALID_SYMBOL);
+ pm_parser_err(parser, PM_TOKEN_START(parser, location), PM_TOKEN_LENGTH(location), PM_ERR_INVALID_SYMBOL);
break;
}
@@ -7197,7 +6694,7 @@ parse_symbol_encoding_validate_other(pm_parser_t *parser, const pm_token_t *loca
* 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
+static PRISM_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
@@ -7222,160 +6719,31 @@ parse_symbol_encoding(pm_parser_t *parser, const pm_token_t *location, const pm_
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;
+ uint32_t start = opening == NULL ? PM_TOKEN_START(parser, value) : PM_TOKEN_START(parser, opening);
+ uint32_t end = closing == NULL ? PM_TOKEN_END(parser, value) : PM_TOKEN_END(parser, closing);
+
+ return pm_symbol_node_new(
+ parser->arena,
+ ++parser->node_id,
+ PM_NODE_FLAG_STATIC_LITERAL | flags,
+ ((pm_location_t) { .start = start, .length = U32(end - start) }),
+ NTOK2LOC(parser, opening),
+ NTOK2LOC(parser, value),
+ NTOK2LOC(parser, closing),
+ *unescaped
+ );
}
/**
* Allocate and initialize a new SymbolNode node.
*/
-static inline pm_symbol_node_t *
+static PRISM_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);
}
@@ -7395,35 +6763,15 @@ pm_symbol_node_create_current_string(pm_parser_t *parser, const pm_token_t *open
*/
static pm_symbol_node_t *
pm_symbol_node_label_create(pm_parser_t *parser, const pm_token_t *token) {
- pm_symbol_node_t *node;
+ assert(token->type == PM_TOKEN_LABEL);
- 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));
+ 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 };
+ pm_symbol_node_t *node = pm_symbol_node_create(parser, NULL, &label, &closing);
- 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;
- }
+ assert((label.end - label.start) >= 0);
+ pm_string_shared_init(&node->unescaped, label.start, label.end);
+ pm_node_flag_set(UP(node), parse_symbol_encoding(parser, &label, &node->unescaped, false));
return node;
}
@@ -7433,18 +6781,16 @@ pm_symbol_node_label_create(pm_parser_t *parser, const pm_token_t *token) {
*/
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_symbol_node_t *node = pm_symbol_node_new(
+ parser->arena,
+ ++parser->node_id,
+ PM_NODE_FLAG_STATIC_LITERAL | PM_SYMBOL_FLAGS_FORCED_US_ASCII_ENCODING,
+ PM_LOCATION_INIT_UNSET,
+ ((pm_location_t) { 0 }),
+ ((pm_location_t) { 0 }),
+ ((pm_location_t) { 0 }),
+ ((pm_string_t) { 0 })
+ );
pm_string_constant_init(&node->unescaped, content, strlen(content));
return node;
@@ -7454,21 +6800,29 @@ pm_symbol_node_synthesized_create(pm_parser_t *parser, const char *content) {
* 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;
+pm_symbol_node_label_p(const pm_parser_t *parser, const pm_node_t *node) {
+ const pm_location_t *location = NULL;
switch (PM_NODE_TYPE(node)) {
- case PM_SYMBOL_NODE:
- end = ((pm_symbol_node_t *) node)->closing_loc.end;
+ case PM_SYMBOL_NODE: {
+ const pm_symbol_node_t *cast = (pm_symbol_node_t *) node;
+ if (cast->closing_loc.length > 0) {
+ location = &cast->closing_loc;
+ }
break;
- case PM_INTERPOLATED_SYMBOL_NODE:
- end = ((pm_interpolated_symbol_node_t *) node)->closing_loc.end;
+ }
+ case PM_INTERPOLATED_SYMBOL_NODE: {
+ const pm_interpolated_symbol_node_t *cast = (pm_interpolated_symbol_node_t *) node;
+ if (cast->closing_loc.length > 0) {
+ location = &cast->closing_loc;
+ }
break;
+ }
default:
return false;
}
- return (end != NULL) && (end[-1] == ':');
+ return (location != NULL) && (parser->start[PM_LOCATION_END(location) - 1] == ':');
}
/**
@@ -7476,32 +6830,26 @@ pm_symbol_node_label_p(pm_node_t *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);
+ pm_symbol_node_t *new_node = pm_symbol_node_new(
+ parser->arena,
+ ++parser->node_id,
+ PM_NODE_FLAG_STATIC_LITERAL,
+ PM_LOCATION_INIT_TOKENS(parser, opening, closing),
+ TOK2LOC(parser, opening),
+ node->content_loc,
+ TOK2LOC(parser, closing),
+ node->unescaped
+ );
- *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 = parser->start + node->content_loc.start,
+ .end = parser->start + node->content_loc.start + node->content_loc.length
};
- 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);
+ pm_node_flag_set(UP(new_node), parse_symbol_encoding(parser, &content, &node->unescaped, true));
+ /* The old node is arena-allocated so no explicit free is needed. */
return new_node;
}
@@ -7510,7 +6858,6 @@ pm_string_node_to_symbol_node(pm_parser_t *parser, pm_string_node_t *node, const
*/
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) {
@@ -7522,24 +6869,18 @@ pm_symbol_node_to_string_node(pm_parser_t *parser, pm_symbol_node_t *node) {
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);
+ pm_string_node_t *new_node = pm_string_node_new(
+ parser->arena,
+ ++parser->node_id,
+ flags,
+ PM_LOCATION_INIT_NODE(node),
+ node->opening_loc,
+ node->value_loc,
+ node->closing_loc,
+ node->unescaped
+ );
+ /* The old node is arena-allocated so no explicit free is needed. */
return new_node;
}
@@ -7549,16 +6890,13 @@ pm_symbol_node_to_string_node(pm_parser_t *parser, pm_symbol_node_t *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;
+ return pm_true_node_new(
+ parser->arena,
+ ++parser->node_id,
+ PM_NODE_FLAG_STATIC_LITERAL,
+ PM_LOCATION_INIT_TOKEN(parser, token)
+ );
}
/**
@@ -7566,16 +6904,12 @@ pm_true_node_create(pm_parser_t *parser, const pm_token_t *token) {
*/
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;
+ return pm_true_node_new(
+ parser->arena,
+ ++parser->node_id,
+ PM_NODE_FLAG_STATIC_LITERAL,
+ PM_LOCATION_INIT_UNSET
+ );
}
/**
@@ -7584,28 +6918,24 @@ pm_true_node_synthesized_create(pm_parser_t *parser) {
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;
+ return pm_undef_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_TOKEN(parser, token),
+ ((pm_node_list_t) { 0 }),
+ TOK2LOC(parser, token)
+ );
}
/**
* 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);
+pm_undef_node_append(pm_arena_t *arena, pm_undef_node_t *node, pm_node_t *name) {
+ PM_NODE_LENGTH_SET_NODE(node, name);
+ pm_node_list_append(arena, &node->names, name);
}
/**
@@ -7614,34 +6944,20 @@ pm_undef_node_append(pm_undef_node_t *node, pm_node_t *name) {
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;
+ pm_node_t *end = statements == NULL ? predicate : UP(statements);
+
+ return pm_unless_node_new(
+ parser->arena,
+ ++parser->node_id,
+ PM_NODE_FLAG_NEWLINE,
+ PM_LOCATION_INIT_TOKEN_NODE(parser, keyword, end),
+ TOK2LOC(parser, keyword),
+ predicate,
+ NTOK2LOC(parser, then_keyword),
+ statements,
+ NULL,
+ ((pm_location_t) { 0 })
+ );
}
/**
@@ -7650,36 +6966,28 @@ pm_unless_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_node_t
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;
+ return pm_unless_node_new(
+ parser->arena,
+ ++parser->node_id,
+ PM_NODE_FLAG_NEWLINE,
+ PM_LOCATION_INIT_NODES(statement, predicate),
+ TOK2LOC(parser, unless_keyword),
+ predicate,
+ ((pm_location_t) { 0 }),
+ statements,
+ NULL,
+ ((pm_location_t) { 0 })
+ );
}
-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;
+static PRISM_INLINE void
+pm_unless_node_end_keyword_loc_set(const pm_parser_t *parser, pm_unless_node_t *node, const pm_token_t *end_keyword) {
+ node->end_keyword_loc = TOK2LOC(parser, end_keyword);
+ PM_NODE_LENGTH_SET_TOKEN(parser, node, end_keyword);
}
/**
@@ -7694,7 +7002,7 @@ pm_loop_modifier_block_exits(pm_parser_t *parser, pm_statements_node_t *statemen
// 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;
+ uint32_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];
@@ -7710,27 +7018,19 @@ pm_loop_modifier_block_exits(pm_parser_t *parser, pm_statements_node_t *statemen
*/
static pm_until_node_t *
pm_until_node_create(pm_parser_t *parser, const pm_token_t *keyword, const pm_token_t *do_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),
- .do_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(do_keyword),
- .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
- .predicate = predicate,
- .statements = statements
- };
-
- return node;
+ return pm_until_node_new(
+ parser->arena,
+ ++parser->node_id,
+ flags,
+ PM_LOCATION_INIT_TOKENS(parser, keyword, closing),
+ TOK2LOC(parser, keyword),
+ NTOK2LOC(parser, do_keyword),
+ TOK2LOC(parser, closing),
+ predicate,
+ statements
+ );
}
/**
@@ -7738,28 +7038,20 @@ pm_until_node_create(pm_parser_t *parser, const pm_token_t *keyword, const pm_to
*/
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),
- .do_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
- .closing_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
- .predicate = predicate,
- .statements = statements
- };
-
- return node;
+ return pm_until_node_new(
+ parser->arena,
+ ++parser->node_id,
+ flags,
+ PM_LOCATION_INIT_NODES(statements, predicate),
+ TOK2LOC(parser, keyword),
+ ((pm_location_t) { 0 }),
+ ((pm_location_t) { 0 }),
+ predicate,
+ statements
+ );
}
/**
@@ -7767,42 +7059,34 @@ pm_until_node_modifier_create(pm_parser_t *parser, const pm_token_t *keyword, pm
*/
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;
+ return pm_when_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_TOKEN(parser, keyword),
+ TOK2LOC(parser, keyword),
+ ((pm_node_list_t) { 0 }),
+ ((pm_location_t) { 0 }),
+ NULL
+ );
}
/**
* 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);
+pm_when_node_conditions_append(pm_arena_t *arena, pm_when_node_t *node, pm_node_t *condition) {
+ PM_NODE_LENGTH_SET_NODE(node, condition);
+ pm_node_list_append(arena, &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);
+static PRISM_INLINE void
+pm_when_node_then_keyword_loc_set(const pm_parser_t *parser, pm_when_node_t *node, const pm_token_t *then_keyword) {
+ PM_NODE_LENGTH_SET_TOKEN(parser, node, then_keyword);
+ node->then_keyword_loc = TOK2LOC(parser, then_keyword);
}
/**
@@ -7810,8 +7094,8 @@ pm_when_node_then_keyword_loc_set(pm_when_node_t *node, const pm_token_t *then_k
*/
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;
+ if (PM_NODE_END(statements) > PM_NODE_END(node)) {
+ PM_NODE_LENGTH_SET_NODE(node, statements);
}
node->statements = statements;
@@ -7822,27 +7106,19 @@ pm_when_node_statements_set(pm_when_node_t *node, pm_statements_node_t *statemen
*/
static pm_while_node_t *
pm_while_node_create(pm_parser_t *parser, const pm_token_t *keyword, const pm_token_t *do_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),
- .do_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(do_keyword),
- .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
- .predicate = predicate,
- .statements = statements
- };
-
- return node;
+ return pm_while_node_new(
+ parser->arena,
+ ++parser->node_id,
+ flags,
+ PM_LOCATION_INIT_TOKENS(parser, keyword, closing),
+ TOK2LOC(parser, keyword),
+ NTOK2LOC(parser, do_keyword),
+ TOK2LOC(parser, closing),
+ predicate,
+ statements
+ );
}
/**
@@ -7850,28 +7126,20 @@ pm_while_node_create(pm_parser_t *parser, const pm_token_t *keyword, const pm_to
*/
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),
- .do_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
- .closing_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
- .predicate = predicate,
- .statements = statements
- };
-
- return node;
+ return pm_while_node_new(
+ parser->arena,
+ ++parser->node_id,
+ flags,
+ PM_LOCATION_INIT_NODES(statements, predicate),
+ TOK2LOC(parser, keyword),
+ ((pm_location_t) { 0 }),
+ ((pm_location_t) { 0 }),
+ predicate,
+ statements
+ );
}
/**
@@ -7879,22 +7147,17 @@ pm_while_node_modifier_create(pm_parser_t *parser, const pm_token_t *keyword, pm
*/
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),
- .do_keyword_loc = PM_LOCATION_NULL_VALUE(parser),
- .closing_loc = PM_LOCATION_NULL_VALUE(parser),
- .predicate = predicate,
- .statements = statements
- };
-
- return node;
+ return pm_while_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_UNSET,
+ ((pm_location_t) { 0 }),
+ ((pm_location_t) { 0 }),
+ ((pm_location_t) { 0 }),
+ predicate,
+ statements
+ );
}
/**
@@ -7903,31 +7166,22 @@ pm_while_node_synthesized_create(pm_parser_t *parser, pm_node_t *predicate, pm_s
*/
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;
+ return pm_x_string_node_new(
+ parser->arena,
+ ++parser->node_id,
+ PM_STRING_FLAGS_FROZEN,
+ PM_LOCATION_INIT_TOKENS(parser, opening, closing),
+ TOK2LOC(parser, opening),
+ TOK2LOC(parser, content),
+ TOK2LOC(parser, closing),
+ *unescaped
+ );
}
/**
* Allocate and initialize a new XStringNode node.
*/
-static inline pm_x_string_node_t *
+static PRISM_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);
}
@@ -7937,40 +7191,31 @@ pm_xstring_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_
*/
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);
+ uint32_t start = PM_TOKEN_START(parser, keyword);
+ uint32_t end;
- const uint8_t *end;
- if (rparen_loc->start != NULL) {
- end = rparen_loc->end;
+ if (rparen_loc->length > 0) {
+ end = PM_LOCATION_END(rparen_loc);
} else if (arguments != NULL) {
- end = arguments->base.location.end;
- } else if (lparen_loc->start != NULL) {
- end = lparen_loc->end;
+ end = PM_NODE_END(arguments);
+ } else if (lparen_loc->length > 0) {
+ end = PM_LOCATION_END(lparen_loc);
} 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;
+ end = PM_TOKEN_END(parser, keyword);
+ }
+
+ return pm_yield_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ ((pm_location_t) { .start = start, .length = U32(end - start) }),
+ TOK2LOC(parser, keyword),
+ *lparen_loc,
+ arguments,
+ *rparen_loc
+ );
}
-#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.
@@ -7996,7 +7241,7 @@ pm_parser_local_depth_constant_id(pm_parser_t *parser, pm_constant_id_t constant
* described by the given token. This function implicitly inserts a constant
* into the constant pool.
*/
-static inline int
+static PRISM_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));
}
@@ -8004,27 +7249,35 @@ pm_parser_local_depth(pm_parser_t *parser, pm_token_t *token) {
/**
* Add a constant id to the local table of the current scope.
*/
-static inline void
+static PRISM_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);
+ pm_locals_write(&parser->current_scope->locals, constant_id, U32(start - parser->start), U32(end - start), 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);
+pm_parser_local_add_raw(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_raw(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 location to the current scope.
+ */
+static PRISM_INLINE pm_constant_id_t
+pm_parser_local_add_location(pm_parser_t *parser, pm_location_t *location, uint32_t reads) {
+ return pm_parser_local_add_raw(parser, parser->start + location->start, parser->start + location->start + location->length, reads);
+}
+
+/**
* Add a local variable from a token to the current scope.
*/
-static inline pm_constant_id_t
+static PRISM_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);
+ return pm_parser_local_add_raw(parser, token->start, token->end, reads);
}
/**
@@ -8058,7 +7311,7 @@ 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);
+ pm_refute_numbered_parameter(parser, PM_TOKEN_START(parser, name), PM_TOKEN_LENGTH(name));
// Otherwise we'll fetch the constant id for the parameter name and check
// whether it's already in the current scope.
@@ -8082,8 +7335,7 @@ 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);
+ xfree_sized(scope, sizeof(pm_scope_t));
}
/******************************************************************************/
@@ -8093,7 +7345,7 @@ pm_parser_scope_pop(pm_parser_t *parser) {
/**
* Pushes a value onto the stack.
*/
-static inline void
+static PRISM_INLINE void
pm_state_stack_push(pm_state_stack_t *stack, bool value) {
*stack = (*stack << 1) | (value & 1);
}
@@ -8101,7 +7353,7 @@ pm_state_stack_push(pm_state_stack_t *stack, bool value) {
/**
* Pops a value off the stack.
*/
-static inline void
+static PRISM_INLINE void
pm_state_stack_pop(pm_state_stack_t *stack) {
*stack >>= 1;
}
@@ -8109,38 +7361,38 @@ pm_state_stack_pop(pm_state_stack_t *stack) {
/**
* Returns the value at the top of the stack.
*/
-static inline bool
+static PRISM_INLINE bool
pm_state_stack_p(const pm_state_stack_t *stack) {
return *stack & 1;
}
-static inline void
+static PRISM_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
+static PRISM_INLINE void
pm_accepts_block_stack_pop(pm_parser_t *parser) {
pm_state_stack_pop(&parser->accepts_block_stack);
}
-static inline bool
+static PRISM_INLINE bool
pm_accepts_block_stack_p(pm_parser_t *parser) {
return !pm_state_stack_p(&parser->accepts_block_stack);
}
-static inline void
+static PRISM_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
+static PRISM_INLINE void
pm_do_loop_stack_pop(pm_parser_t *parser) {
pm_state_stack_pop(&parser->do_loop_stack);
}
-static inline bool
+static PRISM_INLINE bool
pm_do_loop_stack_p(pm_parser_t *parser) {
return pm_state_stack_p(&parser->do_loop_stack);
}
@@ -8153,7 +7405,7 @@ pm_do_loop_stack_p(pm_parser_t *parser) {
* 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
+static PRISM_INLINE uint8_t
peek_at(const pm_parser_t *parser, const uint8_t *cursor) {
if (cursor < parser->end) {
return *cursor;
@@ -8167,7 +7419,7 @@ peek_at(const pm_parser_t *parser, const uint8_t *cursor) {
* adding the given offset. If that position is beyond the end of the source
* then return '\0'.
*/
-static inline uint8_t
+static PRISM_INLINE uint8_t
peek_offset(pm_parser_t *parser, ptrdiff_t offset) {
return peek_at(parser, parser->current.end + offset);
}
@@ -8176,7 +7428,7 @@ peek_offset(pm_parser_t *parser, ptrdiff_t 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
+static PRISM_INLINE uint8_t
peek(const pm_parser_t *parser) {
return peek_at(parser, parser->current.end);
}
@@ -8185,7 +7437,7 @@ peek(const pm_parser_t *parser) {
* If the character to be read matches the given value, then returns true and
* advances the current pointer.
*/
-static inline bool
+static PRISM_INLINE bool
match(pm_parser_t *parser, uint8_t value) {
if (peek(parser) == value) {
parser->current.end++;
@@ -8198,7 +7450,7 @@ match(pm_parser_t *parser, uint8_t value) {
* 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
+static PRISM_INLINE size_t
match_eol_at(pm_parser_t *parser, const uint8_t *cursor) {
if (peek_at(parser, cursor) == '\n') {
return 1;
@@ -8214,7 +7466,7 @@ match_eol_at(pm_parser_t *parser, const uint8_t *cursor) {
* `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
+static PRISM_INLINE size_t
match_eol_offset(pm_parser_t *parser, ptrdiff_t offset) {
return match_eol_at(parser, parser->current.end + offset);
}
@@ -8224,7 +7476,7 @@ match_eol_offset(pm_parser_t *parser, ptrdiff_t offset) {
* or 0 if it is not a line ending. This function is intended to be CRLF/LF
* agnostic.
*/
-static inline size_t
+static PRISM_INLINE size_t
match_eol(pm_parser_t *parser) {
return match_eol_at(parser, parser->current.end);
}
@@ -8232,7 +7484,7 @@ match_eol(pm_parser_t *parser) {
/**
* Skip to the next newline character or NUL byte.
*/
-static inline const uint8_t *
+static PRISM_INLINE const uint8_t *
next_newline(const uint8_t *cursor, ptrdiff_t length) {
assert(length >= 0);
@@ -8245,7 +7497,7 @@ next_newline(const uint8_t *cursor, ptrdiff_t length) {
/**
* This is equivalent to the predicate of warn_balanced in CRuby.
*/
-static inline bool
+static PRISM_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));
}
@@ -8323,7 +7575,7 @@ parser_lex_magic_comment_encoding(pm_parser_t *parser) {
// 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);
+ pm_parser_err(parser, U32(value_start - parser->start), U32(cursor - value_start), PM_ERR_INVALID_ENCODING_MAGIC_COMMENT);
}
}
@@ -8348,7 +7600,7 @@ parser_lex_magic_comment_boolean_value(const uint8_t *value_start, uint32_t valu
}
}
-static inline bool
+static PRISM_INLINE bool
pm_char_is_magic_comment_key_delimiter(const uint8_t b) {
return b == '\'' || b == '"' || b == ':' || b == ';';
}
@@ -8358,13 +7610,15 @@ pm_char_is_magic_comment_key_delimiter(const uint8_t b) {
* found, it returns a pointer to the start of the marker. Otherwise it returns
* NULL.
*/
-static inline const uint8_t *
+static PRISM_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;
+ // Scan for '*' as the middle character, since it is rarer than '-' in
+ // typical comments and avoids repeated memchr calls for '-' that hit
+ // dashes in words like "foo-bar".
+ while ((cursor + 3 <= end) && (cursor = pm_memchr(cursor + 1, '*', (size_t) (end - cursor - 1), parser->encoding_changed, parser->encoding)) != NULL) {
+ if (cursor[-1] == '-' && cursor + 1 < end && cursor[1] == '-') {
+ return cursor - 1;
}
- cursor++;
}
return NULL;
}
@@ -8379,7 +7633,7 @@ parser_lex_magic_comment_emacs_marker(pm_parser_t *parser, const uint8_t *cursor
* It returns true if it consumes the entire comment. Otherwise it returns
* false.
*/
-static inline bool
+static PRISM_INLINE bool
parser_lex_magic_comment(pm_parser_t *parser, bool semantic_token_seen) {
bool result = true;
@@ -8401,11 +7655,24 @@ parser_lex_magic_comment(pm_parser_t *parser, bool semantic_token_seen) {
// have a magic comment.
return false;
}
+ } else {
+ // Non-emacs magic comments must contain a colon for `key: value`.
+ // Reject early if there is no colon to avoid scanning the entire
+ // comment character-by-character.
+ if (pm_memchr(start, ':', (size_t) (end - start), parser->encoding_changed, parser->encoding) == NULL) {
+ return false;
+ }
+
+ // Advance start past leading whitespace so the main loop begins
+ // directly at the key, avoiding a redundant whitespace scan.
+ start += pm_strspn_whitespace(start, end - start);
}
cursor = start;
while (cursor < end) {
- while (cursor < end && (pm_char_is_magic_comment_key_delimiter(*cursor) || pm_char_is_whitespace(*cursor))) cursor++;
+ if (indicator) {
+ 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++;
@@ -8433,7 +7700,7 @@ parser_lex_magic_comment(pm_parser_t *parser, bool semantic_token_seen) {
if (*cursor == '\\' && (cursor + 1 < end)) cursor++;
}
value_end = cursor;
- if (*cursor == '"') cursor++;
+ if (cursor < end && *cursor == '"') cursor++;
} else {
value_start = cursor;
while (cursor < end && *cursor != '"' && *cursor != ';' && !pm_char_is_whitespace(*cursor)) cursor++;
@@ -8491,7 +7758,7 @@ parser_lex_magic_comment(pm_parser_t *parser, bool semantic_token_seen) {
case PM_MAGIC_COMMENT_BOOLEAN_VALUE_INVALID:
PM_PARSER_WARN_TOKEN_FORMAT(
parser,
- parser->current,
+ &parser->current,
PM_WARN_INVALID_MAGIC_COMMENT_VALUE,
(int) key_length,
(const char *) key_source,
@@ -8518,7 +7785,7 @@ parser_lex_magic_comment(pm_parser_t *parser, bool semantic_token_seen) {
case PM_MAGIC_COMMENT_BOOLEAN_VALUE_INVALID:
PM_PARSER_WARN_TOKEN_FORMAT(
parser,
- parser->current,
+ &parser->current,
PM_WARN_INVALID_MAGIC_COMMENT_VALUE,
(int) key_length,
(const char *) key_source,
@@ -8553,7 +7820,7 @@ parser_lex_magic_comment(pm_parser_t *parser, bool semantic_token_seen) {
} else {
PM_PARSER_WARN_TOKEN_FORMAT(
parser,
- parser->current,
+ &parser->current,
PM_WARN_INVALID_MAGIC_COMMENT_VALUE,
(int) key_length,
(const char *) key_source,
@@ -8566,17 +7833,14 @@ parser_lex_magic_comment(pm_parser_t *parser, bool semantic_token_seen) {
// When we're done, we want to free the string in case we had to
// allocate memory for it.
- pm_string_free(&key);
+ pm_string_cleanup(&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);
- }
+ pm_magic_comment_t *magic_comment = (pm_magic_comment_t *) pm_arena_alloc(&parser->metadata_arena, sizeof(pm_magic_comment_t), PRISM_ALIGNOF(pm_magic_comment_t));
+ magic_comment->node.next = NULL;
+ magic_comment->key = (pm_location_t) { .start = U32(key_start - parser->start), .length = U32(key_length) };
+ magic_comment->value = (pm_location_t) { .start = U32(value_start - parser->start), .length = value_length };
+ pm_list_append(&parser->magic_comment_list, (pm_list_node_t *) magic_comment);
}
return result;
@@ -8588,64 +7852,65 @@ parser_lex_magic_comment(pm_parser_t *parser, bool semantic_token_seen) {
static const uint32_t context_terminators[] = {
[PM_CONTEXT_NONE] = 0,
- [PM_CONTEXT_BEGIN] = (1 << PM_TOKEN_KEYWORD_ENSURE) | (1 << PM_TOKEN_KEYWORD_RESCUE) | (1 << PM_TOKEN_KEYWORD_ELSE) | (1 << PM_TOKEN_KEYWORD_END),
- [PM_CONTEXT_BEGIN_ENSURE] = (1 << PM_TOKEN_KEYWORD_END),
- [PM_CONTEXT_BEGIN_ELSE] = (1 << PM_TOKEN_KEYWORD_ENSURE) | (1 << PM_TOKEN_KEYWORD_END),
- [PM_CONTEXT_BEGIN_RESCUE] = (1 << PM_TOKEN_KEYWORD_ENSURE) | (1 << PM_TOKEN_KEYWORD_RESCUE) | (1 << PM_TOKEN_KEYWORD_ELSE) | (1 << PM_TOKEN_KEYWORD_END),
- [PM_CONTEXT_BLOCK_BRACES] = (1 << PM_TOKEN_BRACE_RIGHT),
- [PM_CONTEXT_BLOCK_KEYWORDS] = (1 << PM_TOKEN_KEYWORD_END) | (1 << PM_TOKEN_KEYWORD_RESCUE) | (1 << PM_TOKEN_KEYWORD_ENSURE),
- [PM_CONTEXT_BLOCK_ENSURE] = (1 << PM_TOKEN_KEYWORD_END),
- [PM_CONTEXT_BLOCK_ELSE] = (1 << PM_TOKEN_KEYWORD_ENSURE) | (1 << PM_TOKEN_KEYWORD_END),
- [PM_CONTEXT_BLOCK_RESCUE] = (1 << PM_TOKEN_KEYWORD_ENSURE) | (1 << PM_TOKEN_KEYWORD_RESCUE) | (1 << PM_TOKEN_KEYWORD_ELSE) | (1 << PM_TOKEN_KEYWORD_END),
- [PM_CONTEXT_CASE_WHEN] = (1 << PM_TOKEN_KEYWORD_WHEN) | (1 << PM_TOKEN_KEYWORD_END) | (1 << PM_TOKEN_KEYWORD_ELSE),
- [PM_CONTEXT_CASE_IN] = (1 << PM_TOKEN_KEYWORD_IN) | (1 << PM_TOKEN_KEYWORD_END) | (1 << PM_TOKEN_KEYWORD_ELSE),
- [PM_CONTEXT_CLASS] = (1 << PM_TOKEN_KEYWORD_END) | (1 << PM_TOKEN_KEYWORD_RESCUE) | (1 << PM_TOKEN_KEYWORD_ENSURE),
- [PM_CONTEXT_CLASS_ENSURE] = (1 << PM_TOKEN_KEYWORD_END),
- [PM_CONTEXT_CLASS_ELSE] = (1 << PM_TOKEN_KEYWORD_ENSURE) | (1 << PM_TOKEN_KEYWORD_END),
- [PM_CONTEXT_CLASS_RESCUE] = (1 << PM_TOKEN_KEYWORD_ENSURE) | (1 << PM_TOKEN_KEYWORD_RESCUE) | (1 << PM_TOKEN_KEYWORD_ELSE) | (1 << PM_TOKEN_KEYWORD_END),
- [PM_CONTEXT_DEF] = (1 << PM_TOKEN_KEYWORD_END) | (1 << PM_TOKEN_KEYWORD_RESCUE) | (1 << PM_TOKEN_KEYWORD_ENSURE),
- [PM_CONTEXT_DEF_ENSURE] = (1 << PM_TOKEN_KEYWORD_END),
- [PM_CONTEXT_DEF_ELSE] = (1 << PM_TOKEN_KEYWORD_ENSURE) | (1 << PM_TOKEN_KEYWORD_END),
- [PM_CONTEXT_DEF_RESCUE] = (1 << PM_TOKEN_KEYWORD_ENSURE) | (1 << PM_TOKEN_KEYWORD_RESCUE) | (1 << PM_TOKEN_KEYWORD_ELSE) | (1 << PM_TOKEN_KEYWORD_END),
- [PM_CONTEXT_DEF_PARAMS] = (1 << PM_TOKEN_EOF),
- [PM_CONTEXT_DEFINED] = (1 << PM_TOKEN_EOF),
- [PM_CONTEXT_DEFAULT_PARAMS] = (1 << PM_TOKEN_COMMA) | (1 << PM_TOKEN_PARENTHESIS_RIGHT),
- [PM_CONTEXT_ELSE] = (1 << PM_TOKEN_KEYWORD_END),
- [PM_CONTEXT_ELSIF] = (1 << PM_TOKEN_KEYWORD_ELSE) | (1 << PM_TOKEN_KEYWORD_ELSIF) | (1 << PM_TOKEN_KEYWORD_END),
- [PM_CONTEXT_EMBEXPR] = (1 << PM_TOKEN_EMBEXPR_END),
- [PM_CONTEXT_FOR] = (1 << PM_TOKEN_KEYWORD_END),
- [PM_CONTEXT_FOR_INDEX] = (1 << PM_TOKEN_KEYWORD_IN),
- [PM_CONTEXT_IF] = (1 << PM_TOKEN_KEYWORD_ELSE) | (1 << PM_TOKEN_KEYWORD_ELSIF) | (1 << PM_TOKEN_KEYWORD_END),
- [PM_CONTEXT_LAMBDA_BRACES] = (1 << PM_TOKEN_BRACE_RIGHT),
- [PM_CONTEXT_LAMBDA_DO_END] = (1 << PM_TOKEN_KEYWORD_END) | (1 << PM_TOKEN_KEYWORD_RESCUE) | (1 << PM_TOKEN_KEYWORD_ENSURE),
- [PM_CONTEXT_LAMBDA_ENSURE] = (1 << PM_TOKEN_KEYWORD_END),
- [PM_CONTEXT_LAMBDA_ELSE] = (1 << PM_TOKEN_KEYWORD_ENSURE) | (1 << PM_TOKEN_KEYWORD_END),
- [PM_CONTEXT_LAMBDA_RESCUE] = (1 << PM_TOKEN_KEYWORD_ENSURE) | (1 << PM_TOKEN_KEYWORD_RESCUE) | (1 << PM_TOKEN_KEYWORD_ELSE) | (1 << PM_TOKEN_KEYWORD_END),
- [PM_CONTEXT_LOOP_PREDICATE] = (1 << PM_TOKEN_KEYWORD_DO) | (1 << PM_TOKEN_KEYWORD_THEN),
- [PM_CONTEXT_MAIN] = (1 << PM_TOKEN_EOF),
- [PM_CONTEXT_MODULE] = (1 << PM_TOKEN_KEYWORD_END) | (1 << PM_TOKEN_KEYWORD_RESCUE) | (1 << PM_TOKEN_KEYWORD_ENSURE),
- [PM_CONTEXT_MODULE_ENSURE] = (1 << PM_TOKEN_KEYWORD_END),
- [PM_CONTEXT_MODULE_ELSE] = (1 << PM_TOKEN_KEYWORD_ENSURE) | (1 << PM_TOKEN_KEYWORD_END),
- [PM_CONTEXT_MODULE_RESCUE] = (1 << PM_TOKEN_KEYWORD_ENSURE) | (1 << PM_TOKEN_KEYWORD_RESCUE) | (1 << PM_TOKEN_KEYWORD_ELSE) | (1 << PM_TOKEN_KEYWORD_END),
- [PM_CONTEXT_MULTI_TARGET] = (1 << PM_TOKEN_EOF),
- [PM_CONTEXT_PARENS] = (1 << PM_TOKEN_PARENTHESIS_RIGHT),
- [PM_CONTEXT_POSTEXE] = (1 << PM_TOKEN_BRACE_RIGHT),
- [PM_CONTEXT_PREDICATE] = (1 << PM_TOKEN_KEYWORD_THEN) | (1 << PM_TOKEN_NEWLINE) | (1 << PM_TOKEN_SEMICOLON),
- [PM_CONTEXT_PREEXE] = (1 << PM_TOKEN_BRACE_RIGHT),
- [PM_CONTEXT_RESCUE_MODIFIER] = (1 << PM_TOKEN_EOF),
- [PM_CONTEXT_SCLASS] = (1 << PM_TOKEN_KEYWORD_END) | (1 << PM_TOKEN_KEYWORD_RESCUE) | (1 << PM_TOKEN_KEYWORD_ENSURE),
- [PM_CONTEXT_SCLASS_ENSURE] = (1 << PM_TOKEN_KEYWORD_END),
- [PM_CONTEXT_SCLASS_ELSE] = (1 << PM_TOKEN_KEYWORD_ENSURE) | (1 << PM_TOKEN_KEYWORD_END),
- [PM_CONTEXT_SCLASS_RESCUE] = (1 << PM_TOKEN_KEYWORD_ENSURE) | (1 << PM_TOKEN_KEYWORD_RESCUE) | (1 << PM_TOKEN_KEYWORD_ELSE) | (1 << PM_TOKEN_KEYWORD_END),
- [PM_CONTEXT_TERNARY] = (1 << PM_TOKEN_EOF),
- [PM_CONTEXT_UNLESS] = (1 << PM_TOKEN_KEYWORD_ELSE) | (1 << PM_TOKEN_KEYWORD_END),
- [PM_CONTEXT_UNTIL] = (1 << PM_TOKEN_KEYWORD_END),
- [PM_CONTEXT_WHILE] = (1 << PM_TOKEN_KEYWORD_END),
+ [PM_CONTEXT_BEGIN] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
+ [PM_CONTEXT_BEGIN_ENSURE] = (1U << PM_TOKEN_KEYWORD_END),
+ [PM_CONTEXT_BEGIN_ELSE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_END),
+ [PM_CONTEXT_BEGIN_RESCUE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
+ [PM_CONTEXT_BLOCK_BRACES] = (1U << PM_TOKEN_BRACE_RIGHT),
+ [PM_CONTEXT_BLOCK_KEYWORDS] = (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ENSURE),
+ [PM_CONTEXT_BLOCK_ENSURE] = (1U << PM_TOKEN_KEYWORD_END),
+ [PM_CONTEXT_BLOCK_ELSE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_END),
+ [PM_CONTEXT_BLOCK_PARAMETERS] = (1U << PM_TOKEN_PIPE),
+ [PM_CONTEXT_BLOCK_RESCUE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
+ [PM_CONTEXT_CASE_WHEN] = (1U << PM_TOKEN_KEYWORD_WHEN) | (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_ELSE),
+ [PM_CONTEXT_CASE_IN] = (1U << PM_TOKEN_KEYWORD_IN) | (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_ELSE),
+ [PM_CONTEXT_CLASS] = (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ENSURE),
+ [PM_CONTEXT_CLASS_ENSURE] = (1U << PM_TOKEN_KEYWORD_END),
+ [PM_CONTEXT_CLASS_ELSE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_END),
+ [PM_CONTEXT_CLASS_RESCUE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
+ [PM_CONTEXT_DEF] = (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ENSURE),
+ [PM_CONTEXT_DEF_ENSURE] = (1U << PM_TOKEN_KEYWORD_END),
+ [PM_CONTEXT_DEF_ELSE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_END),
+ [PM_CONTEXT_DEF_RESCUE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
+ [PM_CONTEXT_DEF_PARAMS] = (1U << PM_TOKEN_EOF),
+ [PM_CONTEXT_DEFINED] = (1U << PM_TOKEN_EOF),
+ [PM_CONTEXT_DEFAULT_PARAMS] = (1U << PM_TOKEN_COMMA) | (1U << PM_TOKEN_PARENTHESIS_RIGHT),
+ [PM_CONTEXT_ELSE] = (1U << PM_TOKEN_KEYWORD_END),
+ [PM_CONTEXT_ELSIF] = (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_ELSIF) | (1U << PM_TOKEN_KEYWORD_END),
+ [PM_CONTEXT_EMBEXPR] = (1U << PM_TOKEN_EMBEXPR_END),
+ [PM_CONTEXT_FOR] = (1U << PM_TOKEN_KEYWORD_END),
+ [PM_CONTEXT_FOR_INDEX] = (1U << PM_TOKEN_KEYWORD_IN),
+ [PM_CONTEXT_IF] = (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_ELSIF) | (1U << PM_TOKEN_KEYWORD_END),
+ [PM_CONTEXT_LAMBDA_BRACES] = (1U << PM_TOKEN_BRACE_RIGHT),
+ [PM_CONTEXT_LAMBDA_DO_END] = (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ENSURE),
+ [PM_CONTEXT_LAMBDA_ENSURE] = (1U << PM_TOKEN_KEYWORD_END),
+ [PM_CONTEXT_LAMBDA_ELSE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_END),
+ [PM_CONTEXT_LAMBDA_RESCUE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
+ [PM_CONTEXT_LOOP_PREDICATE] = (1U << PM_TOKEN_KEYWORD_DO) | (1U << PM_TOKEN_KEYWORD_THEN),
+ [PM_CONTEXT_MAIN] = (1U << PM_TOKEN_EOF),
+ [PM_CONTEXT_MODULE] = (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ENSURE),
+ [PM_CONTEXT_MODULE_ENSURE] = (1U << PM_TOKEN_KEYWORD_END),
+ [PM_CONTEXT_MODULE_ELSE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_END),
+ [PM_CONTEXT_MODULE_RESCUE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
+ [PM_CONTEXT_MULTI_TARGET] = (1U << PM_TOKEN_EOF),
+ [PM_CONTEXT_PARENS] = (1U << PM_TOKEN_PARENTHESIS_RIGHT),
+ [PM_CONTEXT_POSTEXE] = (1U << PM_TOKEN_BRACE_RIGHT),
+ [PM_CONTEXT_PREDICATE] = (1U << PM_TOKEN_KEYWORD_THEN) | (1U << PM_TOKEN_NEWLINE) | (1U << PM_TOKEN_SEMICOLON),
+ [PM_CONTEXT_PREEXE] = (1U << PM_TOKEN_BRACE_RIGHT),
+ [PM_CONTEXT_RESCUE_MODIFIER] = (1U << PM_TOKEN_EOF),
+ [PM_CONTEXT_SCLASS] = (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ENSURE),
+ [PM_CONTEXT_SCLASS_ENSURE] = (1U << PM_TOKEN_KEYWORD_END),
+ [PM_CONTEXT_SCLASS_ELSE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_END),
+ [PM_CONTEXT_SCLASS_RESCUE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
+ [PM_CONTEXT_TERNARY] = (1U << PM_TOKEN_EOF),
+ [PM_CONTEXT_UNLESS] = (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
+ [PM_CONTEXT_UNTIL] = (1U << PM_TOKEN_KEYWORD_END),
+ [PM_CONTEXT_WHILE] = (1U << PM_TOKEN_KEYWORD_END),
};
-static inline bool
+static PRISM_INLINE bool
context_terminator(pm_context_t context, pm_token_t *token) {
- return token->type < 32 && (context_terminators[context] & (1 << token->type));
+ return token->type < 32 && (context_terminators[context] & (1U << token->type));
}
/**
@@ -8684,7 +7949,7 @@ context_push(pm_parser_t *parser, pm_context_t context) {
static void
context_pop(pm_parser_t *parser) {
pm_context_node_t *prev = parser->current_context->prev;
- xfree(parser->current_context);
+ xfree_sized(parser->current_context, sizeof(pm_context_node_t));
parser->current_context = prev;
}
@@ -8746,6 +8011,7 @@ context_human(pm_context_t context) {
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_BLOCK_PARAMETERS: return "'|'..'|' block parameter";
case PM_CONTEXT_CASE_WHEN: return "'when' clause";
case PM_CONTEXT_CASE_IN: return "'in' clause";
case PM_CONTEXT_CLASS: return "class definition";
@@ -8806,11 +8072,11 @@ context_human(pm_context_t context) {
/* Specific token lexers */
/******************************************************************************/
-static inline void
+static PRISM_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);
+ pm_parser_err(parser, U32(invalid - parser->start), 1, diag_id);
}
}
@@ -8921,7 +8187,7 @@ lex_numeric_prefix(pm_parser_t *parser, bool* seen_e) {
pm_parser_err_current(parser, PM_ERR_INVALID_NUMBER_BINARY);
}
- parser->integer_base = PM_INTEGER_BASE_FLAGS_BINARY;
+ parser->integer.base = PM_INTEGER_BASE_FLAGS_BINARY;
break;
// 0o1111 is an octal number
@@ -8935,7 +8201,7 @@ lex_numeric_prefix(pm_parser_t *parser, bool* seen_e) {
pm_parser_err_current(parser, PM_ERR_INVALID_NUMBER_OCTAL);
}
- parser->integer_base = PM_INTEGER_BASE_FLAGS_OCTAL;
+ parser->integer.base = PM_INTEGER_BASE_FLAGS_OCTAL;
break;
// 01111 is an octal number
@@ -8949,7 +8215,7 @@ lex_numeric_prefix(pm_parser_t *parser, bool* seen_e) {
case '6':
case '7':
parser->current.end += pm_strspn_octal_number_validate(parser, parser->current.end);
- parser->integer_base = PM_INTEGER_BASE_FLAGS_OCTAL;
+ parser->integer.base = PM_INTEGER_BASE_FLAGS_OCTAL;
break;
// 0x1111 is a hexadecimal number
@@ -8963,7 +8229,7 @@ lex_numeric_prefix(pm_parser_t *parser, bool* seen_e) {
pm_parser_err_current(parser, PM_ERR_INVALID_NUMBER_HEXADECIMAL);
}
- parser->integer_base = PM_INTEGER_BASE_FLAGS_HEXADECIMAL;
+ parser->integer.base = PM_INTEGER_BASE_FLAGS_HEXADECIMAL;
break;
// 0.xxx is a float
@@ -8981,11 +8247,62 @@ lex_numeric_prefix(pm_parser_t *parser, bool* seen_e) {
}
} 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);
+ // decimal number. We compute the integer value inline to avoid
+ // re-scanning the digits later in pm_integer_parse.
+ {
+ const uint8_t *cursor = parser->current.end;
+ const uint8_t *end = parser->end;
+ uint64_t value = (uint64_t) (cursor[-1] - '0');
+
+ bool has_underscore = false;
+ bool prev_underscore = false;
+ const uint8_t *invalid = NULL;
+
+ while (cursor < end) {
+ uint8_t c = *cursor;
+ if (c >= '0' && c <= '9') {
+ if (value <= UINT32_MAX) value = value * 10 + (uint64_t) (c - '0');
+ prev_underscore = false;
+ cursor++;
+ } else if (c == '_') {
+ has_underscore = true;
+ if (prev_underscore && invalid == NULL) invalid = cursor;
+ prev_underscore = true;
+ cursor++;
+ } else {
+ break;
+ }
+ }
+
+ if (has_underscore) {
+ if (prev_underscore && invalid == NULL) invalid = cursor - 1;
+ pm_strspn_number_validate(parser, parser->current.end, (size_t) (cursor - parser->current.end), invalid);
+ }
+
+ if (value <= UINT32_MAX) {
+ parser->integer.value = (uint32_t) value;
+ parser->integer.lexed = true;
+ }
+
+ parser->current.end = cursor;
+ }
// Afterward, we'll lex as far as we can into an optional float suffix.
- type = lex_optional_float_suffix(parser, seen_e);
+ // Guard the function call: the vast majority of decimal numbers are
+ // plain integers, so avoid the call when the next byte cannot start a
+ // float suffix.
+ {
+ uint8_t next = peek(parser);
+ if (next == '.' || next == 'e' || next == 'E') {
+ type = lex_optional_float_suffix(parser, seen_e);
+
+ // If it turned out to be a float, the cached integer value is
+ // invalid.
+ if (type != PM_TOKEN_INTEGER) {
+ parser->integer.lexed = false;
+ }
+ }
+ }
}
// At this point we have a completed number, but we want to provide the user
@@ -8995,7 +8312,7 @@ lex_numeric_prefix(pm_parser_t *parser, bool* seen_e) {
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);
+ pm_parser_err(parser, U32(fraction_start - parser->start), U32(fraction_end - fraction_start), PM_ERR_INVALID_NUMBER_FRACTION);
}
return type;
@@ -9004,7 +8321,8 @@ lex_numeric_prefix(pm_parser_t *parser, bool* seen_e) {
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;
+ parser->integer.base = PM_INTEGER_BASE_FLAGS_DECIMAL;
+ parser->integer.lexed = false;
if (parser->current.end < parser->end) {
bool seen_e = false;
@@ -9095,7 +8413,7 @@ lex_global_variable(pm_parser_t *parser) {
// $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);
+ PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, &parser->current, diag_id);
}
return PM_TOKEN_GLOBAL_VARIABLE;
@@ -9132,8 +8450,8 @@ lex_global_variable(pm_parser_t *parser) {
// 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);
+ size_t width = parser->encoding->char_width(parser->current.end, parser->end - parser->current.end);
+ PM_PARSER_ERR_FORMAT(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current) + U32(width), diag_id, (int) (PM_TOKEN_LENGTH(&parser->current) + U32(width)), (const char *) parser->current.start);
}
return PM_TOKEN_GLOBAL_VARIABLE;
@@ -9153,7 +8471,7 @@ lex_global_variable(pm_parser_t *parser) {
* * `type` - the expected token type
* * `modifier_type` - the expected modifier token type
*/
-static inline pm_token_type_t
+static PRISM_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;
@@ -9192,6 +8510,10 @@ lex_identifier(pm_parser_t *parser, bool previous_command_start) {
current_end += width;
}
} else {
+ // Fast path: scan ASCII identifier bytes using wide operations.
+ current_end += scan_identifier_ascii(current_end, end);
+
+ // Byte-at-a-time fallback for the tail and any UTF-8 sequences.
while ((width = char_is_identifier_utf8(current_end, end - current_end)) > 0) {
current_end += width;
}
@@ -9251,9 +8573,15 @@ lex_identifier(pm_parser_t *parser, bool previous_command_start) {
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 (parser->enclosure_nesting == parser->lambda_enclosure_nesting) {
+ return PM_TOKEN_KEYWORD_DO;
+ }
if (pm_do_loop_stack_p(parser)) {
return PM_TOKEN_KEYWORD_DO_LOOP;
}
+ if (!pm_accepts_block_stack_p(parser)) {
+ return PM_TOKEN_KEYWORD_DO_BLOCK;
+ }
return PM_TOKEN_KEYWORD_DO;
}
@@ -9332,8 +8660,8 @@ current_token_starts_line(pm_parser_t *parser) {
* 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.
+ * * 0 - 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
@@ -9350,9 +8678,9 @@ lex_interpolation(pm_parser_t *parser, const uint8_t *pound) {
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.
+ // Now we'll check against the character that follows the #. If it
+ // constitutes valid interplation, we'll handle that, otherwise we'll return
+ // 0.
switch (pound[1]) {
case '@': {
// In this case we may have hit an embedded instance or class variable.
@@ -9386,7 +8714,7 @@ lex_interpolation(pm_parser_t *parser, const uint8_t *pound) {
// 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;
+ return 0;
}
case '$':
// In this case we may have hit an embedded global variable. If there's
@@ -9436,7 +8764,7 @@ lex_interpolation(pm_parser_t *parser, const uint8_t *pound) {
// 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;
+ return 0;
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
@@ -9460,7 +8788,7 @@ lex_interpolation(pm_parser_t *parser, const uint8_t *pound) {
// 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;
+ return 0;
}
}
@@ -9484,7 +8812,7 @@ static const bool ascii_printable_chars[] = {
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0
};
-static inline bool
+static PRISM_INLINE bool
char_is_ascii_printable(const uint8_t b) {
return (b < 0x80) && ascii_printable_chars[b];
}
@@ -9493,7 +8821,7 @@ char_is_ascii_printable(const uint8_t b) {
* Return the value that a hexadecimal digit character represents. For example,
* transform 'a' into 10, 'b' into 11, etc.
*/
-static inline uint8_t
+static PRISM_INLINE uint8_t
escape_hexadecimal_digit(const uint8_t value) {
return (uint8_t) ((value <= '9') ? (value - '0') : (value & 0x7) + 9);
}
@@ -9503,8 +8831,8 @@ escape_hexadecimal_digit(const uint8_t value) {
* 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) {
+static PRISM_INLINE uint32_t
+escape_unicode(pm_parser_t *parser, const uint8_t *string, size_t length, const pm_location_t *error_location, const uint8_t flags) {
uint32_t value = 0;
for (size_t index = 0; index < length; index++) {
if (index != 0) value <<= 4;
@@ -9514,7 +8842,14 @@ escape_unicode(pm_parser_t *parser, const uint8_t *string, size_t length) {
// 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);
+ if (flags & PM_ESCAPE_FLAG_REGEXP) {
+ // In regexp context, defer the error to regexp encoding
+ // validation where we can produce a regexp-specific message.
+ } else if (error_location != NULL) {
+ pm_parser_err(parser, error_location->start, error_location->length, PM_ERR_ESCAPE_INVALID_UNICODE);
+ } else {
+ pm_parser_err(parser, U32(string - parser->start), U32(length), PM_ERR_ESCAPE_INVALID_UNICODE);
+ }
return 0xFFFD;
}
@@ -9524,7 +8859,7 @@ escape_unicode(pm_parser_t *parser, const uint8_t *string, size_t length) {
/**
* Escape a single character value based on the given flags.
*/
-static inline uint8_t
+static PRISM_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;
@@ -9534,21 +8869,32 @@ escape_byte(uint8_t value, const uint8_t flags) {
/**
* Write a unicode codepoint to the given buffer.
*/
-static inline void
+static PRISM_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);
+ if (flags & PM_ESCAPE_FLAG_REGEXP) {
+ // In regexp context, suppress this error — the regexp encoding
+ // validation will produce a more specific error message.
+ } else {
+ PM_PARSER_ERR_FORMAT(parser, U32(start - parser->start), U32(end - start), PM_ERR_MIXED_ENCODING, parser->explicit_encoding->name);
+ }
}
parser->explicit_encoding = PM_ENCODING_UTF_8_ENTRY;
}
if (!pm_buffer_append_unicode_codepoint(buffer, value)) {
- pm_parser_err(parser, start, end, PM_ERR_ESCAPE_INVALID_UNICODE);
+ if (flags & PM_ESCAPE_FLAG_REGEXP) {
+ // In regexp context, defer the error to the regexp encoding
+ // validation which produces a regexp-specific message.
+ } else {
+ pm_parser_err(parser, U32(start - parser->start), U32(end - start), PM_ERR_ESCAPE_INVALID_UNICODE);
+ }
+
pm_buffer_append_byte(buffer, 0xEF);
pm_buffer_append_byte(buffer, 0xBF);
pm_buffer_append_byte(buffer, 0xBD);
@@ -9559,11 +8905,16 @@ escape_write_unicode(pm_parser_t *parser, pm_buffer_t *buffer, const uint8_t fla
* 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) {
+static PRISM_INLINE void
+escape_write_byte_encoded(pm_parser_t *parser, pm_buffer_t *buffer, const uint8_t flags, 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);
+ if (flags & PM_ESCAPE_FLAG_REGEXP) {
+ // In regexp context, suppress this error — the regexp encoding
+ // validation will produce a more specific error message.
+ } else {
+ PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_MIXED_ENCODING, parser->encoding->name);
+ }
}
parser->explicit_encoding = parser->encoding;
@@ -9587,19 +8938,19 @@ escape_write_byte_encoded(pm_parser_t *parser, pm_buffer_t *buffer, uint8_t byte
* 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
+static PRISM_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);
+ escape_write_byte_encoded(parser, buffer, flags, byte);
}
/**
* Write each byte of the given escaped character into the buffer.
*/
-static inline void
+static PRISM_INLINE void
escape_write_escape_encoded(pm_parser_t *parser, pm_buffer_t *buffer, pm_buffer_t *regular_expression_buffer, uint8_t flags) {
size_t width;
if (parser->encoding_changed) {
@@ -9609,6 +8960,7 @@ escape_write_escape_encoded(pm_parser_t *parser, pm_buffer_t *buffer, pm_buffer_
}
if (width == 1) {
+ if (*parser->current.end == '\n') pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, PM_TOKEN_END(parser, &parser->current) + 1);
escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(*parser->current.end++, flags));
} else if (width > 1) {
// Valid multibyte character. Just ignore escape.
@@ -9634,7 +8986,7 @@ escape_read_warn(pm_parser_t *parser, uint8_t flags, uint8_t flag, const char *t
PM_PARSER_WARN_TOKEN_FORMAT(
parser,
- parser->current,
+ &parser->current,
PM_WARN_INVALID_CHARACTER,
FLAG(flags),
FLAG(flag),
@@ -9749,7 +9101,7 @@ escape_read(pm_parser_t *parser, pm_buffer_t *buffer, pm_buffer_t *regular_expre
}
}
- escape_write_byte_encoded(parser, buffer, value);
+ escape_write_byte_encoded(parser, buffer, flags, value);
} else {
pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_HEXADECIMAL);
}
@@ -9762,7 +9114,7 @@ escape_read(pm_parser_t *parser, pm_buffer_t *buffer, pm_buffer_t *regular_expre
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);
+ PM_PARSER_ERR_FORMAT(parser, U32(start - parser->start), U32(parser->current.end - start), 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++;
@@ -9791,18 +9143,19 @@ escape_read(pm_parser_t *parser, pm_buffer_t *buffer, pm_buffer_t *regular_expre
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);
+ pm_parser_err(parser, U32(unicode_start - parser->start), U32(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.
+ // error instead of us because we don't know at this
+ // point if we're inside a comment in /x mode.
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);
+ pm_parser_err(parser, PM_TOKEN_END(parser, &parser->current), 0, PM_ERR_ESCAPE_INVALID_UNICODE);
+ pm_parser_err(parser, PM_TOKEN_END(parser, &parser->current), 0, PM_ERR_ESCAPE_INVALID_UNICODE_TERM);
}
return;
@@ -9814,7 +9167,7 @@ escape_read(pm_parser_t *parser, pm_buffer_t *buffer, pm_buffer_t *regular_expre
extra_codepoints_start = unicode_start;
}
- uint32_t value = escape_unicode(parser, unicode_start, hexadecimal_length);
+ uint32_t value = escape_unicode(parser, unicode_start, hexadecimal_length, NULL, flags);
escape_write_unicode(parser, buffer, flags, unicode_start, parser->current.end, value);
parser->current.end += pm_strspn_inline_whitespace(parser->current.end, parser->end - parser->current.end);
@@ -9823,21 +9176,22 @@ escape_read(pm_parser_t *parser, pm_buffer_t *buffer, pm_buffer_t *regular_expre
// ?\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);
+ pm_parser_err(parser, U32(extra_codepoints_start - parser->start), U32(parser->current.end - 1 - extra_codepoints_start), 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);
+ PM_PARSER_ERR_FORMAT(parser, U32(start - parser->start), U32(parser->current.end - start), 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.
+ // instead of us because we don't know at this point if
+ // we're inside a comment in /x mode.
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);
+ pm_parser_err(parser, U32(unicode_codepoints_start - parser->start), U32(parser->current.end - unicode_codepoints_start), PM_ERR_ESCAPE_INVALID_UNICODE_TERM);
}
}
@@ -9852,10 +9206,10 @@ escape_read(pm_parser_t *parser, pm_buffer_t *buffer, pm_buffer_t *regular_expre
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);
+ PM_PARSER_ERR_FORMAT(parser, U32(start - parser->start), U32(parser->current.end - start), PM_ERR_ESCAPE_INVALID_UNICODE_SHORT, 2, start);
}
} else if (length == 4) {
- uint32_t value = escape_unicode(parser, parser->current.end, 4);
+ uint32_t value = escape_unicode(parser, parser->current.end, 4, NULL, flags);
if (flags & PM_ESCAPE_FLAG_REGEXP) {
pm_buffer_append_bytes(regular_expression_buffer, start, (size_t) (parser->current.end + 4 - start));
@@ -9901,7 +9255,7 @@ escape_read(pm_parser_t *parser, pm_buffer_t *buffer, pm_buffer_t *regular_expre
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);
+ pm_parser_err(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current), PM_ERR_INVALID_ESCAPE_CHARACTER);
return;
}
@@ -9923,6 +9277,7 @@ escape_read(pm_parser_t *parser, pm_buffer_t *buffer, pm_buffer_t *regular_expre
return;
}
+ if (peeked == '\n') pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, PM_TOKEN_END(parser, &parser->current) + 1);
parser->current.end++;
escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
return;
@@ -9937,7 +9292,7 @@ escape_read(pm_parser_t *parser, pm_buffer_t *buffer, pm_buffer_t *regular_expre
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);
+ pm_parser_err(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current) + U32(width), PM_ERR_ESCAPE_INVALID_CONTROL);
return;
}
@@ -9958,7 +9313,7 @@ escape_read(pm_parser_t *parser, pm_buffer_t *buffer, pm_buffer_t *regular_expre
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);
+ pm_parser_err(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current), PM_ERR_INVALID_ESCAPE_CHARACTER);
return;
}
@@ -9977,10 +9332,11 @@ escape_read(pm_parser_t *parser, pm_buffer_t *buffer, pm_buffer_t *regular_expre
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);
+ pm_parser_err(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current) + U32(width), PM_ERR_ESCAPE_INVALID_CONTROL);
return;
}
+ if (peeked == '\n') pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, PM_TOKEN_END(parser, &parser->current) + 1);
parser->current.end++;
escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
return;
@@ -9995,7 +9351,7 @@ escape_read(pm_parser_t *parser, pm_buffer_t *buffer, pm_buffer_t *regular_expre
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);
+ pm_parser_err(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current) + U32(width), PM_ERR_ESCAPE_INVALID_META);
return;
}
@@ -10011,7 +9367,7 @@ escape_read(pm_parser_t *parser, pm_buffer_t *buffer, pm_buffer_t *regular_expre
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);
+ pm_parser_err(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current), PM_ERR_INVALID_ESCAPE_CHARACTER);
return;
}
@@ -10030,10 +9386,11 @@ escape_read(pm_parser_t *parser, pm_buffer_t *buffer, pm_buffer_t *regular_expre
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);
+ pm_parser_err(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current) + U32(width), PM_ERR_ESCAPE_INVALID_META);
return;
}
+ if (peeked == '\n') pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, PM_TOKEN_END(parser, &parser->current) + 1);
parser->current.end++;
escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_META));
return;
@@ -10041,8 +9398,9 @@ escape_read(pm_parser_t *parser, pm_buffer_t *buffer, pm_buffer_t *regular_expre
}
case '\r': {
if (peek_offset(parser, 1) == '\n') {
+ pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, PM_TOKEN_END(parser, &parser->current) + 2);
parser->current.end += 2;
- escape_write_byte_encoded(parser, buffer, escape_byte('\n', flags));
+ escape_write_byte_encoded(parser, buffer, flags, escape_byte('\n', flags));
return;
}
PRISM_FALLTHROUGH
@@ -10050,7 +9408,7 @@ escape_read(pm_parser_t *parser, pm_buffer_t *buffer, pm_buffer_t *regular_expre
default: {
if ((flags & (PM_ESCAPE_FLAG_CONTROL | PM_ESCAPE_FLAG_META)) && !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);
+ pm_parser_err(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current) + U32(width), PM_ERR_ESCAPE_INVALID_META);
return;
}
if (parser->current.end < parser->end) {
@@ -10112,10 +9470,14 @@ lex_question_mark(pm_parser_t *parser) {
lex_state_set(parser, PM_LEX_STATE_END);
pm_buffer_t buffer;
- pm_buffer_init_capacity(&buffer, 3);
+ pm_buffer_init(&buffer, 3);
escape_read(parser, &buffer, NULL, PM_ESCAPE_FLAG_SINGLE);
- pm_string_owned_init(&parser->current_string, (uint8_t *) buffer.value, buffer.length);
+
+ // Copy buffer data into the arena and free the heap buffer.
+ void *arena_data = pm_arena_memdup(parser->arena, buffer.value, buffer.length, PRISM_ALIGNOF(uint8_t));
+ pm_string_constant_init(&parser->current_string, (const char *) arena_data, buffer.length);
+ pm_buffer_cleanup(&buffer);
return PM_TOKEN_CHARACTER_LITERAL;
} else {
@@ -10163,7 +9525,7 @@ lex_at_variable(pm_parser_t *parser) {
}
size_t width = parser->encoding->char_width(parser->current.end, 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);
+ 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);
@@ -10181,24 +9543,23 @@ lex_at_variable(pm_parser_t *parser) {
/**
* Optionally call out to the lex callback if one is provided.
*/
-static inline void
+static PRISM_INLINE void
parser_lex_callback(pm_parser_t *parser) {
- if (parser->lex_callback) {
- parser->lex_callback->callback(parser->lex_callback->data, parser, &parser->current);
+ if (parser->lex_callback.callback) {
+ parser->lex_callback.callback(parser, &parser->current, parser->lex_callback.data);
}
}
/**
* Return a new comment node of the specified type.
*/
-static inline pm_comment_t *
+static PRISM_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;
+ pm_comment_t *comment = (pm_comment_t *) pm_arena_alloc(&parser->metadata_arena, sizeof(pm_comment_t), PRISM_ALIGNOF(pm_comment_t));
*comment = (pm_comment_t) {
.type = type,
- .location = { parser->current.start, parser->current.end }
+ .location = TOK2LOC(parser, &parser->current)
};
return comment;
@@ -10217,7 +9578,7 @@ lex_embdoc(pm_parser_t *parser) {
if (newline == NULL) {
parser->current.end = parser->end;
} else {
- pm_newline_list_append(&parser->newline_list, newline);
+ pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, U32(newline - parser->start + 1));
parser->current.end = newline + 1;
}
@@ -10225,8 +9586,8 @@ lex_embdoc(pm_parser_t *parser) {
parser_lex_callback(parser);
// Now, create a comment that is going to be attached to the parser.
+ const uint8_t *comment_start = parser->current.start;
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.
@@ -10250,14 +9611,14 @@ lex_embdoc(pm_parser_t *parser) {
if (newline == NULL) {
parser->current.end = parser->end;
} else {
- pm_newline_list_append(&parser->newline_list, newline);
+ pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, U32(newline - parser->start + 1));
parser->current.end = newline + 1;
}
parser->current.type = PM_TOKEN_EMBDOC_END;
parser_lex_callback(parser);
- comment->location.end = parser->current.end;
+ comment->location.length = (uint32_t) (parser->current.end - comment_start);
pm_list_append(&parser->comment_list, (pm_list_node_t *) comment);
return PM_TOKEN_EMBDOC_END;
@@ -10270,7 +9631,7 @@ lex_embdoc(pm_parser_t *parser) {
if (newline == NULL) {
parser->current.end = parser->end;
} else {
- pm_newline_list_append(&parser->newline_list, newline);
+ pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, U32(newline - parser->start + 1));
parser->current.end = newline + 1;
}
@@ -10280,7 +9641,7 @@ lex_embdoc(pm_parser_t *parser) {
pm_parser_err_current(parser, PM_ERR_EMBDOC_TERM);
- comment->location.end = parser->current.end;
+ comment->location.length = (uint32_t) (parser->current.end - comment_start);
pm_list_append(&parser->comment_list, (pm_list_node_t *) comment);
return PM_TOKEN_EOF;
@@ -10291,7 +9652,7 @@ lex_embdoc(pm_parser_t *parser) {
* This happens in a couple places depending on whether or not we have already
* lexed a comment.
*/
-static inline void
+static PRISM_INLINE void
parser_lex_ignored_newline(pm_parser_t *parser) {
parser->current.type = PM_TOKEN_IGNORED_NEWLINE;
parser_lex_callback(parser);
@@ -10306,7 +9667,7 @@ parser_lex_ignored_newline(pm_parser_t *parser) {
* If it is set, then we need to skip past the heredoc body and then clear the
* heredoc_end field.
*/
-static inline void
+static PRISM_INLINE void
parser_flush_heredoc_end(pm_parser_t *parser) {
assert(parser->heredoc_end <= parser->end);
parser->next_start = parser->heredoc_end;
@@ -10382,12 +9743,12 @@ typedef struct {
/**
* Push the given byte into the token buffer.
*/
-static inline void
+static PRISM_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
+static PRISM_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);
}
@@ -10395,7 +9756,7 @@ pm_regexp_token_buffer_push_byte(pm_regexp_token_buffer_t *token_buffer, uint8_t
/**
* Return the width of the character at the end of the current token.
*/
-static inline size_t
+static PRISM_INLINE size_t
parser_char_width(const pm_parser_t *parser) {
size_t width;
if (parser->encoding_changed) {
@@ -10422,36 +9783,31 @@ pm_token_buffer_push_escaped(pm_token_buffer_t *token_buffer, pm_parser_t *parse
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);
+ const uint8_t *start = parser->current.end;
+ pm_buffer_append_bytes(&token_buffer->base.buffer, start, width);
+ pm_buffer_append_bytes(&token_buffer->regexp_buffer, start, 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
+static PRISM_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));
+ // Copy buffer data into the arena and free the heap buffer.
+ size_t len = pm_buffer_length(&token_buffer->buffer);
+ void *arena_data = pm_arena_memdup(parser->arena, pm_buffer_value(&token_buffer->buffer), len, PRISM_ALIGNOF(uint8_t));
+ pm_string_constant_init(&parser->current_string, (const char *) arena_data, len);
+ pm_buffer_cleanup(&token_buffer->buffer);
}
-static inline void
+static PRISM_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);
+ pm_token_buffer_copy(parser, &token_buffer->base);
+ pm_buffer_cleanup(&token_buffer->regexp_buffer);
}
/**
@@ -10477,10 +9833,11 @@ 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));
+ const uint8_t *cursor = token_buffer->base.cursor;
+ size_t length = (size_t) (parser->current.end - cursor);
+ pm_buffer_append_bytes(&token_buffer->base.buffer, cursor, length);
+ pm_buffer_append_bytes(&token_buffer->regexp_buffer, cursor, length);
pm_regexp_token_buffer_copy(parser, token_buffer);
}
}
@@ -10499,7 +9856,7 @@ 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);
+ pm_buffer_init(&token_buffer->buffer, PM_TOKEN_BUFFER_DEFAULT_SIZE);
start = parser->current.start;
} else {
start = token_buffer->cursor;
@@ -10516,8 +9873,8 @@ 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);
+ pm_buffer_init(&token_buffer->base.buffer, PM_TOKEN_BUFFER_DEFAULT_SIZE);
+ pm_buffer_init(&token_buffer->regexp_buffer, PM_TOKEN_BUFFER_DEFAULT_SIZE);
start = parser->current.start;
} else {
start = token_buffer->base.cursor;
@@ -10536,7 +9893,7 @@ pm_regexp_token_buffer_escape(pm_parser_t *parser, pm_regexp_token_buffer_t *tok
* 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
+static PRISM_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;
@@ -10584,7 +9941,7 @@ pm_lex_percent_delimiter(pm_parser_t *parser) {
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);
+ pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, PM_TOKEN_END(parser, &parser->current) + U32(eol_length));
}
uint8_t delimiter = *parser->current.end;
@@ -10632,6 +9989,12 @@ parser_lex(pm_parser_t *parser) {
unsigned int semantic_token_seen = parser->semantic_token_seen;
parser->semantic_token_seen = true;
+ // We'll jump to this label when we are about to encounter an EOF.
+ // If we still have lex_modes on the stack, we pop them so that cleanup
+ // can happen. For example, we should still continue parsing after a heredoc
+ // identifier, even if the heredoc body was syntax invalid.
+ switch_lex_modes:
+
switch (parser->lex_modes.current->mode) {
case PM_LEX_DEFAULT:
case PM_LEX_EMBEXPR:
@@ -10654,22 +10017,29 @@ parser_lex(pm_parser_t *parser) {
bool space_seen = false;
// First, we're going to skip past any whitespace at the front of the next
- // token.
+ // token. Skip runs of inline whitespace in bulk to avoid per-character
+ // stores back to parser->current.end.
bool chomping = true;
while (parser->current.end < parser->end && chomping) {
- switch (*parser->current.end) {
- case ' ':
- case '\t':
- case '\f':
- case '\v':
- parser->current.end++;
+ {
+ static const uint8_t inline_whitespace[256] = {
+ [' '] = 1, ['\t'] = 1, ['\f'] = 1, ['\v'] = 1
+ };
+ const uint8_t *scan = parser->current.end;
+ while (scan < parser->end && inline_whitespace[*scan]) scan++;
+ if (scan > parser->current.end) {
+ parser->current.end = scan;
space_seen = true;
- break;
+ continue;
+ }
+ }
+
+ switch (*parser->current.end) {
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);
+ pm_parser_warn(parser, PM_TOKEN_END(parser, &parser->current), 1, PM_WARN_UNEXPECTED_CARRIAGE_RETURN);
parser->current.end++;
space_seen = true;
}
@@ -10682,7 +10052,7 @@ parser_lex(pm_parser_t *parser) {
parser->heredoc_end = NULL;
} else {
parser->current.end += eol_length + 1;
- pm_newline_list_append(&parser->newline_list, parser->current.end - 1);
+ pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, PM_TOKEN_END(parser, &parser->current));
space_seen = true;
}
} else if (pm_char_is_inline_whitespace(*parser->current.end)) {
@@ -10705,6 +10075,14 @@ parser_lex(pm_parser_t *parser) {
// 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) {
+ // We may be missing closing tokens. We should pop modes one by one
+ // to do the appropriate cleanup like moving next_start for heredocs.
+ // Only when no mode is remaining will we actually emit the EOF token.
+ if (parser->lex_modes.current->mode != PM_LEX_DEFAULT) {
+ lex_mode_pop(parser);
+ goto switch_lex_modes;
+ }
+
// If we hit EOF, but the EOF came immediately after a newline,
// set the start of the token to the newline. This way any EOF
// errors will be reported as happening on that line rather than
@@ -10776,7 +10154,7 @@ parser_lex(pm_parser_t *parser) {
}
if (parser->heredoc_end == NULL) {
- pm_newline_list_append(&parser->newline_list, parser->current.end - 1);
+ pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, PM_TOKEN_END(parser, &parser->current));
}
}
@@ -10834,14 +10212,50 @@ parser_lex(pm_parser_t *parser) {
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 the lex state was ignored, we will lex the
+ // ignored newline.
+ if (lex_state_ignored_p(parser)) {
+ if (!lexed_comment) parser_lex_ignored_newline(parser);
+ lexed_comment = false;
+ goto lex_next_token;
+ }
+
+ // If we hit a '.' or a '&.' we will lex the ignored
+ // newline.
+ if (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 are parsing as CRuby 4.0 or later and we
+ // hit a '&&' or a '||' then 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) == '.')
- ))
+ (parser->version >= PM_OPTIONS_VERSION_CRUBY_4_0) &&
+ following && (
+ (peek_at(parser, following) == '&' && peek_at(parser, following + 1) == '&') ||
+ (peek_at(parser, following) == '|' && peek_at(parser, following + 1) == '|') ||
+ (
+ peek_at(parser, following) == 'a' &&
+ peek_at(parser, following + 1) == 'n' &&
+ peek_at(parser, following + 2) == 'd' &&
+ peek_at(parser, next_content + 3) != '!' &&
+ peek_at(parser, next_content + 3) != '?' &&
+ !char_is_identifier(parser, following + 3, parser->end - (following + 3))
+ ) ||
+ (
+ peek_at(parser, following) == 'o' &&
+ peek_at(parser, following + 1) == 'r' &&
+ peek_at(parser, next_content + 2) != '!' &&
+ peek_at(parser, next_content + 2) != '?' &&
+ !char_is_identifier(parser, following + 2, parser->end - (following + 2))
+ )
+ )
) {
if (!lexed_comment) parser_lex_ignored_newline(parser);
lexed_comment = false;
@@ -10881,6 +10295,67 @@ parser_lex(pm_parser_t *parser) {
parser->next_start = NULL;
LEX(PM_TOKEN_AMPERSAND_DOT);
}
+
+ if (parser->version >= PM_OPTIONS_VERSION_CRUBY_4_0) {
+ // If we hit an && then we are in a logical chain
+ // and we need to return the logical 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_BEG);
+ parser->current.start = next_content;
+ parser->current.end = next_content + 2;
+ parser->next_start = NULL;
+ LEX(PM_TOKEN_AMPERSAND_AMPERSAND);
+ }
+
+ // If we hit a || then we are in a logical chain and
+ // we need to return the logical 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_BEG);
+ parser->current.start = next_content;
+ parser->current.end = next_content + 2;
+ parser->next_start = NULL;
+ LEX(PM_TOKEN_PIPE_PIPE);
+ }
+
+ // If we hit an 'and' then we are in a logical chain
+ // and we need to return the logical operator.
+ if (
+ peek_at(parser, next_content) == 'a' &&
+ peek_at(parser, next_content + 1) == 'n' &&
+ peek_at(parser, next_content + 2) == 'd' &&
+ peek_at(parser, next_content + 3) != '!' &&
+ peek_at(parser, next_content + 3) != '?' &&
+ !char_is_identifier(parser, next_content + 3, parser->end - (next_content + 3))
+ ) {
+ if (!lexed_comment) parser_lex_ignored_newline(parser);
+ lex_state_set(parser, PM_LEX_STATE_BEG);
+ parser->current.start = next_content;
+ parser->current.end = next_content + 3;
+ parser->next_start = NULL;
+ parser->command_start = true;
+ LEX(PM_TOKEN_KEYWORD_AND);
+ }
+
+ // If we hit a 'or' then we are in a logical chain
+ // and we need to return the logical operator.
+ if (
+ peek_at(parser, next_content) == 'o' &&
+ peek_at(parser, next_content + 1) == 'r' &&
+ peek_at(parser, next_content + 2) != '!' &&
+ peek_at(parser, next_content + 2) != '?' &&
+ !char_is_identifier(parser, next_content + 2, parser->end - (next_content + 2))
+ ) {
+ if (!lexed_comment) parser_lex_ignored_newline(parser);
+ lex_state_set(parser, PM_LEX_STATE_BEG);
+ parser->current.start = next_content;
+ parser->current.end = next_content + 2;
+ parser->next_start = NULL;
+ parser->command_start = true;
+ LEX(PM_TOKEN_KEYWORD_OR);
+ }
+ }
}
// At this point we know this is a regular newline, and we can set the
@@ -10895,7 +10370,7 @@ parser_lex(pm_parser_t *parser) {
// ,
case ',':
if ((parser->previous.type == PM_TOKEN_COMMA) && (parser->enclosure_nesting > 0)) {
- PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_ARRAY_TERM, pm_token_type_human(parser->current.type));
+ PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_ARRAY_TERM, pm_token_str(parser->current.type));
}
lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
@@ -11021,7 +10496,7 @@ parser_lex(pm_parser_t *parser) {
} 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");
+ PM_PARSER_WARN_TOKEN_FORMAT(parser, &parser->current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR, "**", "argument prefix");
}
if (lex_state_operator_p(parser)) {
@@ -11046,7 +10521,7 @@ parser_lex(pm_parser_t *parser) {
} 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");
+ PM_PARSER_WARN_TOKEN_FORMAT(parser, &parser->current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR, "*", "argument prefix");
}
if (lex_state_operator_p(parser)) {
@@ -11172,7 +10647,7 @@ parser_lex(pm_parser_t *parser) {
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);
+ pm_parser_err(parser, U32(ident_start - parser->start), U32(ident_length), PM_ERR_HEREDOC_IDENTIFIER);
ident_error = true;
}
@@ -11205,7 +10680,7 @@ parser_lex(pm_parser_t *parser) {
} 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);
+ pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, U32(body_start - parser->start + 1));
body_start++;
}
@@ -11224,7 +10699,7 @@ parser_lex(pm_parser_t *parser) {
}
if (ambiguous_operator_p(parser, space_seen)) {
- PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR, "<<", "here document");
+ PM_PARSER_WARN_TOKEN_FORMAT(parser, &parser->current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR, "<<", "here document");
}
if (lex_state_operator_p(parser)) {
@@ -11350,7 +10825,7 @@ parser_lex(pm_parser_t *parser) {
} 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");
+ PM_PARSER_WARN_TOKEN_FORMAT(parser, &parser->current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR, "&", "argument prefix");
}
if (lex_state_operator_p(parser)) {
@@ -11426,7 +10901,7 @@ parser_lex(pm_parser_t *parser) {
}
if (ambiguous_operator_p(parser, space_seen)) {
- PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR, "+", "unary operator");
+ PM_PARSER_WARN_TOKEN_FORMAT(parser, &parser->current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR, "+", "unary operator");
}
lex_state_set(parser, PM_LEX_STATE_BEG);
@@ -11467,7 +10942,7 @@ parser_lex(pm_parser_t *parser) {
}
if (ambiguous_operator_p(parser, space_seen)) {
- PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR, "-", "unary operator");
+ PM_PARSER_WARN_TOKEN_FORMAT(parser, &parser->current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR, "-", "unary operator");
}
lex_state_set(parser, PM_LEX_STATE_BEG);
@@ -11566,7 +11041,7 @@ parser_lex(pm_parser_t *parser) {
}
if (ambiguous_operator_p(parser, space_seen)) {
- PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR, "/", "regexp literal");
+ PM_PARSER_WARN_TOKEN_FORMAT(parser, &parser->current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR, "/", "regexp literal");
}
if (lex_state_operator_p(parser)) {
@@ -11751,7 +11226,7 @@ parser_lex(pm_parser_t *parser) {
}
if (ambiguous_operator_p(parser, space_seen)) {
- PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR, "%", "string literal");
+ 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);
@@ -11787,40 +11262,40 @@ parser_lex(pm_parser_t *parser) {
// 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);
+ 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");
+ 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");
+ 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");
+ 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");
+ 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");
+ PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_UNEXPECTED_TOKEN_IGNORE, "escaped carriage return");
break;
}
PRISM_FALLTHROUGH
default:
- PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_UNEXPECTED_TOKEN_IGNORE, "backslash");
+ 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);
+ 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);
+ PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_INVALID_CHARACTER, *parser->current.start);
}
goto lex_next_token;
@@ -11846,15 +11321,15 @@ parser_lex(pm_parser_t *parser) {
// 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++);
+ pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, U32(++cursor - parser->start));
}
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;
+ parser->data_loc.start = PM_TOKEN_START(parser, &parser->current);
+ parser->data_loc.length = PM_TOKEN_LENGTH(&parser->current);
LEX(PM_TOKEN_EOF);
}
@@ -11879,7 +11354,7 @@ parser_lex(pm_parser_t *parser) {
!(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))
+ pm_token_is_numbered_parameter(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current)))
) {
lex_state_set(parser, PM_LEX_STATE_END | PM_LEX_STATE_LABEL);
}
@@ -11907,7 +11382,7 @@ parser_lex(pm_parser_t *parser) {
whitespace += 1;
}
} else {
- whitespace = pm_strspn_whitespace_newlines(parser->current.end, parser->end - parser->current.end, &parser->newline_list);
+ whitespace = pm_strspn_whitespace_newlines(parser->current.end, parser->end - parser->current.end, &parser->metadata_arena, &parser->line_offsets, PM_TOKEN_END(parser, &parser->current));
}
if (whitespace > 0) {
@@ -12022,7 +11497,7 @@ parser_lex(pm_parser_t *parser) {
LEX(PM_TOKEN_STRING_CONTENT);
} else {
// ... else track the newline.
- pm_newline_list_append(&parser->newline_list, parser->current.end);
+ pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, PM_TOKEN_END(parser, &parser->current) + 1);
}
parser->current.end++;
@@ -12050,7 +11525,7 @@ parser_lex(pm_parser_t *parser) {
if (*breakpoint == '#') {
pm_token_type_t type = lex_interpolation(parser, breakpoint);
- if (type == PM_TOKEN_NOT_PROVIDED) {
+ if (!type) {
// 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
@@ -12155,7 +11630,13 @@ parser_lex(pm_parser_t *parser) {
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);
+
+ // Track the newline if we're not in a heredoc that
+ // would have already have added the newline to the
+ // list.
+ if (parser->heredoc_end == NULL) {
+ pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, PM_TOKEN_END(parser, &parser->current));
+ }
} else {
parser->current.end = breakpoint + 1;
}
@@ -12201,7 +11682,7 @@ parser_lex(pm_parser_t *parser) {
// 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);
+ pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, U32(breakpoint - parser->start + 1));
parser->current.end = breakpoint + 1;
breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end, false);
break;
@@ -12249,7 +11730,7 @@ parser_lex(pm_parser_t *parser) {
LEX(PM_TOKEN_STRING_CONTENT);
} else {
// ... else track the newline.
- pm_newline_list_append(&parser->newline_list, parser->current.end);
+ pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, PM_TOKEN_END(parser, &parser->current) + 1);
}
parser->current.end++;
@@ -12296,7 +11777,7 @@ parser_lex(pm_parser_t *parser) {
// interpolation.
pm_token_type_t type = lex_interpolation(parser, breakpoint);
- if (type == PM_TOKEN_NOT_PROVIDED) {
+ if (!type) {
// 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
@@ -12409,7 +11890,13 @@ parser_lex(pm_parser_t *parser) {
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);
+
+ // Track the newline if we're not in a heredoc that
+ // would have already have added the newline to the
+ // list.
+ if (parser->heredoc_end == NULL) {
+ pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, PM_TOKEN_END(parser, &parser->current));
+ }
} else {
parser->current.end = breakpoint + 1;
}
@@ -12421,6 +11908,13 @@ parser_lex(pm_parser_t *parser) {
LEX(PM_TOKEN_LABEL_END);
}
+ // When the delimiter itself is a newline, we won't
+ // get a chance to flush heredocs in the usual places since
+ // the newline is already consumed.
+ if (term == '\n' && parser->heredoc_end) {
+ parser_flush_heredoc_end(parser);
+ }
+
lex_state_set(parser, PM_LEX_STATE_END);
lex_mode_pop(parser);
LEX(PM_TOKEN_STRING_END);
@@ -12453,7 +11947,7 @@ parser_lex(pm_parser_t *parser) {
// for the terminator in case the terminator is a
// newline character.
if (parser->heredoc_end == NULL) {
- pm_newline_list_append(&parser->newline_list, breakpoint);
+ pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, U32(breakpoint - parser->start + 1));
parser->current.end = breakpoint + 1;
breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end, true);
break;
@@ -12507,7 +12001,7 @@ parser_lex(pm_parser_t *parser) {
LEX(PM_TOKEN_STRING_CONTENT);
} else {
// ... else track the newline.
- pm_newline_list_append(&parser->newline_list, parser->current.end);
+ pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, PM_TOKEN_END(parser, &parser->current) + 1);
}
parser->current.end++;
@@ -12536,7 +12030,7 @@ parser_lex(pm_parser_t *parser) {
case '#': {
pm_token_type_t type = lex_interpolation(parser, breakpoint);
- if (type == PM_TOKEN_NOT_PROVIDED) {
+ if (!type) {
// 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
@@ -12636,7 +12130,7 @@ parser_lex(pm_parser_t *parser) {
(memcmp(terminator_start, ident_start, ident_length) == 0)
) {
if (newline != NULL) {
- pm_newline_list_append(&parser->newline_list, newline);
+ pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, U32(newline - parser->start + 1));
}
parser->current.end = terminator_end;
@@ -12667,7 +12161,7 @@ parser_lex(pm_parser_t *parser) {
// 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\\#";
+ uint8_t breakpoints[PM_STRPBRK_CACHE_SIZE] = "\r\n\\#";
pm_heredoc_quote_t quote = heredoc_lex_mode->quote;
if (quote == PM_HEREDOC_QUOTE_SINGLE) {
@@ -12708,7 +12202,7 @@ parser_lex(pm_parser_t *parser) {
LEX(PM_TOKEN_STRING_CONTENT);
}
- pm_newline_list_append(&parser->newline_list, breakpoint);
+ pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, U32(breakpoint - parser->start + 1));
// If we have a - or ~ heredoc, then we can match after
// some leading whitespace.
@@ -12826,7 +12320,10 @@ parser_lex(pm_parser_t *parser) {
// 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);
+
+ if (parser->heredoc_end == NULL) {
+ pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, U32(end - parser->start + 1));
+ }
// Here we want the buffer to only
// include up to the backslash.
@@ -12857,7 +12354,7 @@ parser_lex(pm_parser_t *parser) {
case '#': {
pm_token_type_t type = lex_interpolation(parser, breakpoint);
- if (type == PM_TOKEN_NOT_PROVIDED) {
+ if (!type) {
// 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
@@ -13082,7 +12579,7 @@ pm_binding_powers_t pm_binding_powers[PM_TOKEN_MAXIMUM] = {
/**
* Returns true if the current token is of the given type.
*/
-static inline bool
+static PRISM_INLINE bool
match1(const pm_parser_t *parser, pm_token_type_t type) {
return parser->current.type == type;
}
@@ -13090,7 +12587,7 @@ match1(const pm_parser_t *parser, pm_token_type_t type) {
/**
* Returns true if the current token is of either of the given types.
*/
-static inline bool
+static PRISM_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);
}
@@ -13098,7 +12595,7 @@ match2(const pm_parser_t *parser, pm_token_type_t type1, pm_token_type_t type2)
/**
* Returns true if the current token is any of the three given types.
*/
-static inline bool
+static PRISM_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);
}
@@ -13106,15 +12603,23 @@ match3(const pm_parser_t *parser, pm_token_type_t type1, pm_token_type_t type2,
/**
* Returns true if the current token is any of the four given types.
*/
-static inline bool
+static PRISM_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 PRISM_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
+static PRISM_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);
}
@@ -13122,7 +12627,7 @@ match7(const pm_parser_t *parser, pm_token_type_t type1, pm_token_type_t type2,
/**
* Returns true if the current token is any of the eight given types.
*/
-static inline bool
+static PRISM_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);
}
@@ -13146,7 +12651,7 @@ accept1(pm_parser_t *parser, pm_token_type_t type) {
* 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
+static PRISM_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);
@@ -13171,10 +12676,10 @@ 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);
+ pm_parser_err(parser, U32(location - parser->start), 0, diag_id);
parser->previous.start = location;
- parser->previous.type = PM_TOKEN_MISSING;
+ parser->previous.type = 0;
}
/**
@@ -13186,10 +12691,10 @@ expect2(pm_parser_t *parser, pm_token_type_t type1, pm_token_type_t type2, pm_di
if (accept2(parser, type1, type2)) return;
const uint8_t *location = parser->previous.end;
- pm_parser_err(parser, location, location, diag_id);
+ pm_parser_err(parser, U32(location - parser->start), 0, diag_id);
parser->previous.start = location;
- parser->previous.type = PM_TOKEN_MISSING;
+ parser->previous.type = 0;
}
/**
@@ -13203,20 +12708,43 @@ expect1_heredoc_term(pm_parser_t *parser, const uint8_t *ident_start, size_t ide
} else {
pm_parser_err_heredoc_term(parser, ident_start, ident_length);
parser->previous.start = parser->previous.end;
- parser->previous.type = PM_TOKEN_MISSING;
+ parser->previous.type = 0;
}
}
+/**
+ * A special expect1 that attaches the error to the opening token location
+ * rather than the current position. This is useful for errors about missing
+ * closing tokens, where we want to point to the line with the opening token
+ * (e.g., `def`, `class`, `if`, `{`) rather than the end of the file.
+ */
+static void
+expect1_opening(pm_parser_t *parser, pm_token_type_t type, pm_diagnostic_id_t diag_id, const pm_token_t *opening) {
+ if (accept1(parser, type)) return;
+
+ const uint8_t *start = opening->start;
+ pm_parser_err(parser, U32(start - parser->start), U32(opening->end - start), diag_id);
+
+ parser->previous.start = parser->previous.end;
+ parser->previous.type = 0;
+}
+
+/** Flags for controlling expression parsing behavior. */
+#define PM_PARSE_ACCEPTS_COMMAND_CALL ((uint8_t) 0x1)
+#define PM_PARSE_ACCEPTS_LABEL ((uint8_t) 0x2)
+#define PM_PARSE_ACCEPTS_DO_BLOCK ((uint8_t) 0x4)
+#define PM_PARSE_IN_ENDLESS_DEF ((uint8_t) 0x8)
+
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);
+parse_expression(pm_parser_t *parser, pm_binding_power_t binding_power, uint8_t flags, 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);
+parse_value_expression(pm_parser_t *parser, pm_binding_power_t binding_power, uint8_t flags, pm_diagnostic_id_t diag_id, uint16_t depth) {
+ pm_node_t *node = parse_expression(parser, binding_power, flags, diag_id, depth);
pm_assert_value_expression(parser, node);
return node;
}
@@ -13239,7 +12767,7 @@ parse_value_expression(pm_parser_t *parser, pm_binding_power_t binding_power, bo
* work in all cases, it may need to be refactored later. But it appears to work
* for now.
*/
-static inline bool
+static PRISM_INLINE bool
token_begins_expression_p(pm_token_type_t type) {
switch (type) {
case PM_TOKEN_EQUAL_GREATER:
@@ -13255,6 +12783,7 @@ token_begins_expression_p(pm_token_type_t type) {
case PM_TOKEN_EOF:
case PM_TOKEN_LAMBDA_BEGIN:
case PM_TOKEN_KEYWORD_DO:
+ case PM_TOKEN_KEYWORD_DO_BLOCK:
case PM_TOKEN_KEYWORD_DO_LOOP:
case PM_TOKEN_KEYWORD_END:
case PM_TOKEN_KEYWORD_ELSE:
@@ -13300,14 +12829,89 @@ token_begins_expression_p(pm_token_type_t type) {
* 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) {
+parse_starred_expression(pm_parser_t *parser, pm_binding_power_t binding_power, uint8_t flags, 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);
+ pm_node_t *expression = parse_value_expression(parser, binding_power, (uint8_t) (flags & PM_PARSE_ACCEPTS_DO_BLOCK), PM_ERR_EXPECT_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
+ return UP(pm_splat_node_create(parser, &operator, expression));
+ }
+
+ return parse_value_expression(parser, binding_power, flags, diag_id, depth);
+}
+
+static bool
+pm_node_unreference_each(const pm_node_t *node, void *data) {
+ switch (PM_NODE_TYPE(node)) {
+ /* When we are about to destroy a set of nodes that could potentially
+ * contain block exits for the current scope, we need to check if they
+ * are contained in the list of block exits and remove them if they are.
+ */
+ case PM_BREAK_NODE:
+ case PM_NEXT_NODE:
+ case PM_REDO_NODE: {
+ pm_parser_t *parser = (pm_parser_t *) data;
+ size_t index = 0;
+
+ while (index < parser->current_block_exits->size) {
+ pm_node_t *block_exit = parser->current_block_exits->nodes[index];
+
+ if (block_exit == node) {
+ if (index + 1 < parser->current_block_exits->size) {
+ memmove(
+ &parser->current_block_exits->nodes[index],
+ &parser->current_block_exits->nodes[index + 1],
+ (parser->current_block_exits->size - index - 1) * sizeof(pm_node_t *)
+ );
+ }
+ parser->current_block_exits->size--;
+
+ /* Note returning true here because these nodes could have
+ * arguments that are themselves block exits. */
+ return true;
+ }
+
+ index++;
+ }
+
+ return true;
+ }
+ /* When an implicit local variable is written to or targeted, it becomes
+ * a regular, named local variable. This branch removes it from the list
+ * of implicit parameters when that happens. */
+ case PM_LOCAL_VARIABLE_READ_NODE:
+ case PM_IT_LOCAL_VARIABLE_READ_NODE: {
+ pm_parser_t *parser = (pm_parser_t *) data;
+ 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) {
+ memmove(&implicit_parameters->nodes[index], &implicit_parameters->nodes[index + 1], (implicit_parameters->size - index - 1) * sizeof(pm_node_t *));
+ }
+
+ implicit_parameters->size--;
+ break;
+ }
+ }
+
+ return false;
+ }
+ default:
+ return true;
}
+}
- return parse_value_expression(parser, binding_power, accepts_command_call, false, diag_id, depth);
+/**
+ * When we are about to destroy a set of nodes that could potentially be
+ * referenced by one or more lists on the parser, then remove them from those
+ * lists so we don't get a use-after-free.
+ */
+static void
+pm_node_unreference(pm_parser_t *parser, const pm_node_t *node) {
+ pm_visit_node(node, pm_node_unreference_each, parser);
}
/**
@@ -13322,16 +12926,12 @@ parse_write_name(pm_parser_t *parser, pm_constant_id_t *name_field) {
// 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;
+ uint8_t *name = (uint8_t *) pm_arena_alloc(parser->arena, length + 1, 1);
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);
+ *name_field = pm_constant_pool_insert_owned(&parser->metadata_arena, &parser->constant_pool, name, length + 1);
}
/**
@@ -13353,35 +12953,10 @@ parse_unwriteable_target(pm_parser_t *parser, pm_node_t *target) {
default: break;
}
- pm_constant_id_t name = pm_parser_constant_id_location(parser, target->location.start, target->location.end);
+ pm_constant_id_t name = pm_parser_constant_id_raw(parser, parser->start + PM_NODE_START(target), parser->start + PM_NODE_END(target));
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;
- }
- }
+ return UP(result);
}
/**
@@ -13395,7 +12970,7 @@ parse_target_implicit_parameter(pm_parser_t *parser, pm_node_t *node) {
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:
+ case PM_ERROR_RECOVERY_NODE:
return target;
case PM_SOURCE_ENCODING_NODE:
case PM_FALSE_NODE:
@@ -13433,15 +13008,15 @@ parse_target(pm_parser_t *parser, pm_node_t *target, bool multiple, bool splat_p
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;
+ return UP(pm_error_recovery_node_create_unexpected(parser, 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);
+ if (pm_token_is_numbered_parameter(parser, PM_NODE_START(target), PM_NODE_LENGTH(target))) {
+ PM_PARSER_ERR_FORMAT(parser, PM_NODE_START(target), PM_NODE_LENGTH(target), PM_ERR_PARAMETER_NUMBERED_RESERVED, parser->start + PM_NODE_START(target));
+ pm_node_unreference(parser, target);
}
const pm_local_variable_read_node_t *cast = (const pm_local_variable_read_node_t *) target;
@@ -13456,10 +13031,9 @@ parse_target(pm_parser_t *parser, pm_node_t *target, bool multiple, bool splat_p
}
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);
+ pm_node_t *node = UP(pm_local_variable_target_node_create(parser, &target->location, name, 0));
- parse_target_implicit_parameter(parser, target);
- pm_node_destroy(parser, target);
+ pm_node_unreference(parser, target);
return node;
}
@@ -13482,7 +13056,7 @@ parse_target(pm_parser_t *parser, pm_node_t *target, bool multiple, bool splat_p
splat->expression = parse_target(parser, splat->expression, multiple, true);
}
- return (pm_node_t *) splat;
+ return UP(splat);
}
case PM_CALL_NODE: {
pm_call_node_t *call = (pm_call_node_t *) target;
@@ -13491,10 +13065,10 @@ parse_target(pm_parser_t *parser, pm_node_t *target, bool multiple, bool splat_p
// 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->message_loc.length > 0) &&
+ (parser->start[call->message_loc.start + call->message_loc.length - 1] != '!') &&
+ (parser->start[call->message_loc.start + call->message_loc.length - 1] != '?') &&
+ (call->opening_loc.length == 0) &&
(call->arguments == NULL) &&
(call->block == NULL)
) {
@@ -13508,21 +13082,19 @@ parse_target(pm_parser_t *parser, pm_node_t *target, bool multiple, bool splat_p
// 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);
+ pm_location_t message_loc = call->message_loc;
+ pm_constant_id_t name = pm_parser_local_add_location(parser, &message_loc, 0);
- return (pm_node_t *) pm_local_variable_target_node_create(parser, &message_loc, name, 0);
+ return UP(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 (peek_at(parser, parser->start + call->message_loc.start) == '_' || parser->encoding->alnum_char(parser->start + call->message_loc.start, (ptrdiff_t) call->message_loc.length)) {
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);
+ return UP(pm_call_target_node_create(parser, call));
}
}
@@ -13530,7 +13102,7 @@ parse_target(pm_parser_t *parser, pm_node_t *target, bool multiple, bool splat_p
// 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);
+ return UP(pm_index_target_node_create(parser, call));
}
}
PRISM_FALLTHROUGH
@@ -13573,7 +13145,7 @@ 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 UP(pm_shareable_constant_node_create(parser, write, shareable_constant));
}
return write;
@@ -13585,16 +13157,14 @@ parse_shareable_constant_write(pm_parser_t *parser, pm_node_t *write) {
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);
+ case PM_ERROR_RECOVERY_NODE:
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;
+ return UP(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);
+ pm_node_t *node = UP(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);
@@ -13603,13 +13173,12 @@ parse_write(pm_parser_t *parser, pm_node_t *target, pm_token_t *operator, pm_nod
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);
+ pm_node_t *node = UP(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:
@@ -13618,45 +13187,40 @@ parse_write(pm_parser_t *parser, pm_node_t *target, pm_token_t *operator, pm_nod
PRISM_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;
+ return UP(node);
}
case PM_LOCAL_VARIABLE_READ_NODE: {
pm_local_variable_read_node_t *local_read = (pm_local_variable_read_node_t *) target;
+ pm_location_t location = target->location;
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)) {
+ if (pm_token_is_numbered_parameter(parser, PM_NODE_START(target), PM_NODE_LENGTH(target))) {
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_PARSER_ERR_FORMAT(parser, PM_NODE_START(target), PM_NODE_LENGTH(target), diag_id, parser->start + PM_NODE_START(target));
+ pm_node_unreference(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);
+ return UP(pm_local_variable_write_node_create(parser, name, depth, value, &location, 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);
+ pm_node_t *node = UP(pm_local_variable_write_node_create(parser, name, 0, value, &target->location, operator));
- parse_target_implicit_parameter(parser, target);
- pm_node_destroy(parser, target);
+ pm_node_unreference(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);
+ pm_node_t *write_node = UP(pm_instance_variable_write_node_create(parser, (pm_instance_variable_read_node_t *) target, operator, value));
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);
+ return UP(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;
@@ -13665,9 +13229,9 @@ parse_write(pm_parser_t *parser, pm_node_t *target, pm_token_t *operator, pm_nod
}
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);
+ pm_multi_target_node_targets_append(parser, multi_target, UP(splat));
- return (pm_node_t *) pm_multi_write_node_create(parser, multi_target, operator, value);
+ return UP(pm_multi_write_node_create(parser, multi_target, operator, value));
}
case PM_CALL_NODE: {
pm_call_node_t *call = (pm_call_node_t *) target;
@@ -13676,10 +13240,10 @@ parse_write(pm_parser_t *parser, pm_node_t *target, pm_token_t *operator, pm_nod
// 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->message_loc.length > 0) &&
+ (parser->start[call->message_loc.start + call->message_loc.length - 1] != '!') &&
+ (parser->start[call->message_loc.start + call->message_loc.length - 1] != '?') &&
+ (call->opening_loc.length == 0) &&
(call->arguments == NULL) &&
(call->block == NULL)
) {
@@ -13693,19 +13257,18 @@ parse_write(pm_parser_t *parser, pm_node_t *target, pm_token_t *operator, pm_nod
// 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_location_t message_loc = call->message_loc;
- pm_parser_local_add_location(parser, message.start, message.end, 0);
- pm_node_destroy(parser, target);
+ pm_refute_numbered_parameter(parser, message_loc.start, message_loc.length);
+ pm_parser_local_add_location(parser, &message_loc, 0);
- 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_constant_id_t constant_id = pm_parser_constant_id_raw(parser, parser->start + PM_LOCATION_START(&message_loc), parser->start + PM_LOCATION_END(&message_loc));
+ target = UP(pm_local_variable_write_node_create(parser, constant_id, 0, value, &message_loc, operator));
- pm_refute_numbered_parameter(parser, message.start, message.end);
return target;
}
- if (char_is_identifier_start(parser, call->message_loc.start, parser->end - call->message_loc.start)) {
+ if (char_is_identifier_start(parser, parser->start + call->message_loc.start, (ptrdiff_t) call->message_loc.length)) {
// 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:
@@ -13719,13 +13282,14 @@ parse_write(pm_parser_t *parser, pm_node_t *target, pm_token_t *operator, pm_nod
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;
+ pm_arguments_node_arguments_append(parser->arena, arguments, value);
+ PM_NODE_LENGTH_SET_NODE(call, arguments);
+ call->equal_loc = TOK2LOC(parser, operator);
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));
+ pm_node_flag_set(UP(call), PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE | pm_implicit_array_write_flags(value, PM_CALL_NODE_FLAGS_IMPLICIT_ARRAY));
- return (pm_node_t *) call;
+ return UP(call);
}
}
@@ -13737,25 +13301,31 @@ parse_write(pm_parser_t *parser, pm_node_t *target, pm_token_t *operator, pm_nod
call->arguments = pm_arguments_node_create(parser);
}
- pm_arguments_node_arguments_append(call->arguments, value);
- target->location.end = value->location.end;
+ pm_arguments_node_arguments_append(parser->arena, call->arguments, value);
+ PM_NODE_LENGTH_SET_NODE(target, value);
// Replace the name with "[]=".
call->name = pm_parser_constant_id_constant(parser, "[]=", 3);
+ call->equal_loc = TOK2LOC(parser, operator);
// Ensure that the arguments for []= don't contain keywords
pm_index_arguments_check(parser, call->arguments, call->block);
- 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));
+ pm_node_flag_set(UP(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
+ // 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);
+ //
+ // Since it is possible for the value to contain an implicit
+ // parameter somewhere in its subtree, we need to walk it and remove
+ // any implicit parameters from the list of implicit parameters for
+ // the current scope.
+ pm_node_unreference(parser, value);
}
PRISM_FALLTHROUGH
default:
@@ -13786,11 +13356,10 @@ parse_unwriteable_write(pm_parser_t *parser, pm_node_t *target, const pm_token_t
default: break;
}
- pm_constant_id_t name = pm_parser_local_add_location(parser, target->location.start, target->location.end, 1);
+ pm_constant_id_t name = pm_parser_local_add_location(parser, &target->location, 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;
+ return UP(result);
}
/**
@@ -13823,35 +13392,35 @@ parse_targets(pm_parser_t *parser, pm_node_t *first_target, pm_binding_power_t b
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_expression(parser, binding_power, PM_PARSE_ACCEPTS_DO_BLOCK, 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_node_t *splat = UP(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));
+ pm_node_t *target = parse_expression(parser, binding_power, PM_PARSE_ACCEPTS_DO_BLOCK, 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));
+ pm_node_t *target = parse_expression(parser, binding_power, PM_PARSE_ACCEPTS_DO_BLOCK, 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_node_t *rest = UP(pm_implicit_rest_node_create(parser, &parser->previous));
pm_multi_target_node_targets_append(parser, result, rest);
break;
}
}
- return (pm_node_t *) result;
+ return UP(result);
}
/**
@@ -13861,7 +13430,13 @@ parse_targets(pm_parser_t *parser, pm_node_t *first_target, pm_binding_power_t b
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);
+
+ // If we're inside parentheses, then we allow a newline before the
+ // closing parenthesis or equals sign. Outside of parentheses, a newline
+ // is not allowed (e.g., `a, b\n= 1, 2` is not valid).
+ if (context_p(parser, PM_CONTEXT_PARENS) || context_p(parser, PM_CONTEXT_MULTI_TARGET)) {
+ 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)) {
@@ -13890,7 +13465,7 @@ parse_statements(pm_parser_t *parser, pm_context_t context, uint16_t depth) {
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_node_t *node = parse_expression(parser, PM_BINDING_POWER_STATEMENT, PM_PARSE_ACCEPTS_COMMAND_CALL | PM_PARSE_ACCEPTS_DO_BLOCK, 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
@@ -13930,7 +13505,7 @@ parse_statements(pm_parser_t *parser, pm_context_t context, uint16_t depth) {
// 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)) {
+ if (PM_NODE_TYPE_P(node, PM_ERROR_RECOVERY_NODE)) {
parser_lex(parser);
// If we are at the end of the file, then we need to stop parsing
@@ -13948,13 +13523,14 @@ parse_statements(pm_parser_t *parser, pm_context_t context, uint16_t depth) {
// 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));
+ PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(parser->current.type));
parser->previous.start = parser->previous.end;
- parser->previous.type = PM_TOKEN_MISSING;
+ parser->previous.type = 0;
}
}
context_pop(parser);
+
bool last_value = true;
switch (context) {
case PM_CONTEXT_BEGIN_ENSURE:
@@ -13975,23 +13551,24 @@ parse_statements(pm_parser_t *parser, pm_context_t context, uint16_t depth) {
*/
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);
+ const pm_node_t *duplicated = pm_static_literals_add(&parser->line_offsets, parser->start, 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_static_literal_inspect(&buffer, &parser->line_offsets, parser->start, parser->start_line, parser->encoding->name, duplicated);
pm_diagnostic_list_append_format(
+ &parser->metadata_arena,
&parser->warning_list,
duplicated->location.start,
- duplicated->location.end,
+ duplicated->location.length,
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_line_offset_list_line_column(&parser->line_offsets, PM_NODE_START(node), parser->start_line).line
);
- pm_buffer_free(&buffer);
+ pm_buffer_cleanup(&buffer);
}
}
@@ -14003,14 +13580,15 @@ 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) {
+ if ((previous = pm_static_literals_add(&parser->line_offsets, parser->start, parser->start_line, literals, node, false)) != NULL) {
pm_diagnostic_list_append_format(
+ &parser->metadata_arena,
&parser->warning_list,
- node->location.start,
- node->location.end,
+ PM_NODE_START(node),
+ PM_NODE_LENGTH(node),
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
+ pm_line_offset_list_line_column(&parser->line_offsets, PM_NODE_START(node), parser->start_line).line,
+ pm_line_offset_list_line_column(&parser->line_offsets, PM_NODE_START(previous), parser->start_line).line
);
}
}
@@ -14038,14 +13616,14 @@ parse_assocs(pm_parser_t *parser, pm_static_literals_t *literals, pm_node_t *nod
// 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));
+ value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, PM_PARSE_ACCEPTS_DO_BLOCK, 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));
+ value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, PM_PARSE_ACCEPTS_DO_BLOCK, 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);
+ element = UP(pm_assoc_splat_node_create(parser, value, &operator));
contains_keyword_splat = true;
break;
}
@@ -14053,44 +13631,43 @@ parse_assocs(pm_parser_t *parser, pm_static_literals_t *literals, pm_node_t *nod
pm_token_t label = parser->current;
parser_lex(parser);
- pm_node_t *key = (pm_node_t *) pm_symbol_node_label_create(parser, &label);
+ pm_node_t *key = UP(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));
+ value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, PM_PARSE_ACCEPTS_DO_BLOCK, 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);
+ value = UP(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);
+ 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);
+ value = UP(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 = UP(pm_local_variable_read_node_create(parser, &identifier, (uint32_t) depth));
}
}
- value->location.end++;
- value = (pm_node_t *) pm_implicit_node_create(parser, value);
+ value->location.length++;
+ value = UP(pm_implicit_node_create(parser, value));
}
- element = (pm_node_t *) pm_assoc_node_create(parser, key, &operator, value);
+ element = UP(pm_assoc_node_create(parser, key, NULL, 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));
+ pm_node_t *key = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, PM_PARSE_ACCEPTS_DO_BLOCK | PM_PARSE_ACCEPTS_LABEL, PM_ERR_HASH_KEY, (uint16_t) (depth + 1));
// Hash keys that are strings are automatically frozen. We will
// mark that here.
@@ -14100,24 +13677,22 @@ parse_assocs(pm_parser_t *parser, pm_static_literals_t *literals, pm_node_t *nod
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 {
+ pm_token_t operator = { 0 };
+ if (!pm_symbol_node_label_p(parser, key)) {
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);
+ pm_node_t *value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_HASH_VALUE, (uint16_t) (depth + 1));
+ element = UP(pm_assoc_node_create(parser, key, NTOK2PTR(operator), value));
break;
}
}
if (PM_NODE_TYPE_P(node, PM_HASH_NODE)) {
- pm_hash_node_elements_append((pm_hash_node_t *) node, element);
+ pm_hash_node_elements_append(parser->arena, (pm_hash_node_t *) node, element);
} else {
- pm_keyword_hash_node_elements_append((pm_keyword_hash_node_t *) node, element);
+ pm_keyword_hash_node_elements_append(parser->arena, (pm_keyword_hash_node_t *) node, element);
}
// If there's no comma after the element, then we're done.
@@ -14138,23 +13713,47 @@ parse_assocs(pm_parser_t *parser, pm_static_literals_t *literals, pm_node_t *nod
return contains_keyword_splat;
}
+static PRISM_INLINE bool
+argument_allowed_for_bare_hash(pm_parser_t *parser, pm_node_t *argument) {
+ if (pm_symbol_node_label_p(parser, argument)) {
+ return true;
+ }
+
+ switch (PM_NODE_TYPE(argument)) {
+ case PM_CALL_NODE: {
+ pm_call_node_t *cast = (pm_call_node_t *) argument;
+ if (cast->opening_loc.length == 0 && cast->arguments != NULL) {
+ if (PM_NODE_FLAG_P(cast->arguments, PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORDS | PM_ARGUMENTS_NODE_FLAGS_CONTAINS_SPLAT)) {
+ return false;
+ }
+ if (cast->block != NULL) {
+ return false;
+ }
+ }
+ break;
+ }
+ default: break;
+ }
+ return accept1(parser, PM_TOKEN_EQUAL_GREATER);
+}
+
/**
* Append an argument to a list of arguments.
*/
-static inline void
+static PRISM_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);
+ pm_arguments_node_arguments_append(parser->arena, 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) {
+parse_arguments(pm_parser_t *parser, pm_arguments_t *arguments, bool accepts_forwarding, pm_token_type_t terminator, uint8_t flags, 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
@@ -14187,16 +13786,16 @@ parse_arguments(pm_parser_t *parser, pm_arguments_t *arguments, bool accepts_for
}
pm_keyword_hash_node_t *hash = pm_keyword_hash_node_create(parser);
- argument = (pm_node_t *) hash;
+ argument = UP(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));
+ bool contains_keyword_splat = parse_assocs(parser, &hash_keys, UP(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_node_flags_t node_flags = PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORDS;
+ if (contains_keyword_splat) node_flags |= PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORD_SPLAT;
+ pm_node_flag_set(UP(arguments->arguments), node_flags);
pm_static_literals_free(&hash_keys);
parsed_bare_hash = true;
@@ -14209,12 +13808,12 @@ parse_arguments(pm_parser_t *parser, pm_arguments_t *arguments, bool accepts_for
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));
+ expression = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, flags & PM_PARSE_ACCEPTS_DO_BLOCK, 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);
+ argument = UP(pm_block_argument_node_create(parser, &operator, expression));
if (parsed_block_argument) {
parse_arguments_append(parser, arguments, argument);
} else {
@@ -14234,18 +13833,18 @@ parse_arguments(pm_parser_t *parser, pm_arguments_t *arguments, bool accepts_for
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);
+ argument = UP(pm_splat_node_create(parser, &operator, NULL));
if (parsed_bare_hash) {
pm_parser_err_previous(parser, PM_ERR_ARGUMENT_SPLAT_AFTER_ASSOC_SPLAT);
}
} 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));
+ pm_node_t *expression = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, flags & PM_PARSE_ACCEPTS_DO_BLOCK, 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);
+ pm_parser_err(parser, PM_TOKEN_START(parser, &operator), PM_NODE_END(expression) - PM_TOKEN_START(parser, &operator), PM_ERR_ARGUMENT_SPLAT_AFTER_ASSOC_SPLAT);
}
- argument = (pm_node_t *) pm_splat_node_create(parser, &operator, expression);
+ argument = UP(pm_splat_node_create(parser, &operator, expression));
}
parse_arguments_append(parser, arguments, argument);
@@ -14260,26 +13859,26 @@ parse_arguments(pm_parser_t *parser, pm_arguments_t *arguments, bool accepts_for
// 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));
+ pm_node_t *right = parse_expression(parser, PM_BINDING_POWER_RANGE, flags & PM_PARSE_ACCEPTS_DO_BLOCK, 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);
+ pm_parser_err(parser, range->operator_loc.start, range->operator_loc.length, PM_ERR_UNEXPECTED_RANGE_OPERATOR);
}
- argument = (pm_node_t *) pm_range_node_create(parser, NULL, &operator, right);
+ argument = UP(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);
+ argument = UP(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);
+ pm_node_flag_set(UP(arguments->arguments), PM_ARGUMENTS_NODE_FLAGS_CONTAINS_FORWARDING);
arguments->has_forwarding = true;
parsed_forwarding_arguments = true;
break;
@@ -14289,22 +13888,20 @@ parse_arguments(pm_parser_t *parser, pm_arguments_t *arguments, bool accepts_for
PRISM_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));
+ argument = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, (uint8_t) ((flags & PM_PARSE_ACCEPTS_DO_BLOCK) | (!parsed_first_argument ? PM_PARSE_ACCEPTS_COMMAND_CALL : 0u) | PM_PARSE_ACCEPTS_LABEL), 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 (argument_allowed_for_bare_hash(parser, argument)) {
if (parsed_bare_hash) {
pm_parser_err_previous(parser, PM_ERR_ARGUMENT_BARE_HASH);
}
- pm_token_t operator;
+ pm_token_t operator = { 0 };
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);
@@ -14315,18 +13912,18 @@ parse_arguments(pm_parser_t *parser, pm_arguments_t *arguments, bool accepts_for
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_node_t *value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, flags & PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_HASH_VALUE, (uint16_t) (depth + 1));
+ argument = UP(pm_assoc_node_create(parser, argument, NTOK2PTR(operator), value));
- pm_keyword_hash_node_elements_append(bare_hash, argument);
- argument = (pm_node_t *) bare_hash;
+ pm_keyword_hash_node_elements_append(parser->arena, bare_hash, argument);
+ argument = UP(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));
+ contains_keyword_splat = parse_assocs(parser, &hash_keys, UP(bare_hash), (uint16_t) (depth + 1));
}
pm_static_literals_free(&hash_keys);
@@ -14335,10 +13932,10 @@ parse_arguments(pm_parser_t *parser, pm_arguments_t *arguments, bool accepts_for
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);
+ pm_node_flags_t node_flags = 0;
+ if (contains_keywords) node_flags |= PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORDS;
+ if (contains_keyword_splat) node_flags |= PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORD_SPLAT;
+ pm_node_flag_set(UP(arguments->arguments), node_flags);
break;
}
@@ -14347,7 +13944,7 @@ parse_arguments(pm_parser_t *parser, pm_arguments_t *arguments, bool accepts_for
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 (PM_NODE_TYPE_P(argument, PM_ERROR_RECOVERY_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
@@ -14367,6 +13964,17 @@ parse_arguments(pm_parser_t *parser, pm_arguments_t *arguments, bool accepts_for
if (accepted_newline) {
pm_parser_err_previous(parser, PM_ERR_INVALID_COMMA);
}
+
+ // If this is a command call and an argument takes a block,
+ // there can be no further arguments. For example,
+ // `foo(bar 1 do end, 2)` should be rejected.
+ if (PM_NODE_TYPE_P(argument, PM_CALL_NODE)) {
+ pm_call_node_t *call = (pm_call_node_t *) argument;
+ if (call->opening_loc.length == 0 && call->arguments != NULL && call->block != NULL) {
+ pm_parser_err_previous(parser, PM_ERR_INVALID_COMMA);
+ break;
+ }
+ }
} 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.
@@ -14394,7 +14002,7 @@ 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);
+ pm_multi_target_node_opening_set(parser, node, &parser->previous);
do {
pm_node_t *param;
@@ -14404,33 +14012,33 @@ parse_required_destructured_parameter(pm_parser_t *parser) {
// 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);
+ param = UP(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);
+ param = UP(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);
+ value = UP(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);
+ param = UP(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);
+ param = UP(pm_required_parameter_node_create(parser, &name));
if (pm_parser_parameter_name_check(parser, &name)) {
pm_node_flag_set_repeated_parameter(param);
}
@@ -14442,7 +14050,7 @@ parse_required_destructured_parameter(pm_parser_t *parser) {
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);
+ pm_multi_target_node_closing_set(parser, node, &parser->previous);
return node;
}
@@ -14518,6 +14126,43 @@ update_parameter_state(pm_parser_t *parser, pm_token_t *token, pm_parameters_ord
return true;
}
+static PRISM_INLINE void
+parse_parameters_handle_trailing_comma(
+ pm_parser_t *parser,
+ pm_parameters_node_t *params,
+ pm_parameters_order_t order,
+ bool in_block,
+ bool allows_trailing_comma
+) {
+ if (!allows_trailing_comma) {
+ pm_parser_err_previous(parser, PM_ERR_PARAMETER_WILD_LOOSE_COMMA);
+ return;
+ }
+
+ if (in_block) {
+ if (order >= PM_PARAMETERS_ORDER_NAMED) {
+ // foo do |bar,|; end
+ pm_node_t *param = UP(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, UP(param), PM_ERR_PARAMETER_SPLAT_MULTI);
+ pm_parameters_node_posts_append(parser->arena, params, UP(param));
+ }
+ } else {
+ // foo do |*bar,|; end
+ pm_parser_err_previous(parser, PM_ERR_PARAMETER_WILD_LOOSE_COMMA);
+ }
+ } else {
+ // https://bugs.ruby-lang.org/issues/19107
+ // Allow `def foo(bar,); end`, `def foo(*bar,); end`, etc. but not `def foo(...,); end`
+ if (parser->version < PM_OPTIONS_VERSION_CRUBY_4_1 || order == PM_PARAMETERS_ORDER_NOTHING_AFTER) {
+ pm_parser_err_previous(parser, PM_ERR_PARAMETER_WILD_LOOSE_COMMA);
+ }
+ }
+}
+
/**
* Parse a list of parameters on a method definition.
*/
@@ -14530,6 +14175,7 @@ parse_parameters(
bool allows_forwarding_parameters,
bool accepts_blocks_in_defaults,
bool in_block,
+ pm_diagnostic_id_t diag_id_forwarding,
uint16_t depth
) {
pm_do_loop_stack_push(parser, false);
@@ -14543,12 +14189,12 @@ parse_parameters(
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);
+ pm_node_t *param = UP(parse_required_destructured_parameter(parser));
if (order > PM_PARAMETERS_ORDER_AFTER_OPTIONAL) {
- pm_parameters_node_requireds_append(params, param);
+ pm_parameters_node_requireds_append(parser->arena, params, param);
} else {
- pm_parameters_node_posts_append(params, param);
+ pm_parameters_node_posts_append(parser->arena, params, param);
}
break;
}
@@ -14558,34 +14204,40 @@ parse_parameters(
parser_lex(parser);
pm_token_t operator = parser->previous;
- pm_token_t name;
+ pm_node_t *param;
- 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);
+ if (parser->version >= PM_OPTIONS_VERSION_CRUBY_4_1 && accept1(parser, PM_TOKEN_KEYWORD_NIL)) {
+ param = (pm_node_t *) pm_no_block_parameter_node_create(parser, &operator, &parser->previous);
} else {
- name = not_provided(parser);
- parser->current_scope->parameters |= PM_SCOPE_PARAMETERS_FORWARDING_BLOCK;
- }
+ pm_token_t name = {0};
- 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);
+ 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 {
+ parser->current_scope->parameters |= PM_SCOPE_PARAMETERS_FORWARDING_BLOCK;
+ }
+
+ param = (pm_node_t *) pm_block_parameter_node_create(parser, NTOK2PTR(name), &operator);
+ if (repeated) {
+ pm_node_flag_set_repeated_parameter(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);
+ pm_parser_err_node(parser, param, PM_ERR_PARAMETER_BLOCK_MULTI);
+ pm_parameters_node_posts_append(parser->arena, params, UP(pm_error_recovery_node_create_unexpected(parser, param)));
}
break;
}
case PM_TOKEN_UDOT_DOT_DOT: {
if (!allows_forwarding_parameters) {
- pm_parser_err_current(parser, PM_ERR_ARGUMENT_NO_FORWARDING_ELLIPSES);
+ pm_parser_err_current(parser, diag_id_forwarding);
}
bool succeeded = update_parameter_state(parser, &parser->current, &order);
@@ -14598,12 +14250,12 @@ parse_parameters(
// 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);
+ pm_parameters_node_posts_append(parser->arena, params, UP(pm_error_recovery_node_create_unexpected(parser, 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);
+ pm_parameters_node_keyword_rest_set(params, UP(param));
break;
}
case PM_TOKEN_CLASS_VARIABLE:
@@ -14651,21 +14303,21 @@ parse_parameters(
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));
+ pm_node_t *value = parse_value_expression(parser, binding_power, PM_PARSE_ACCEPTS_DO_BLOCK, 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_node_flag_set_repeated_parameter(UP(param));
}
- pm_parameters_node_optionals_append(params, param);
+ pm_parameters_node_optionals_append(parser->arena, 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);
+ PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, &name, PM_ERR_PARAMETER_CIRCULAR);
}
context_pop(parser);
@@ -14680,15 +14332,15 @@ parse_parameters(
} 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_node_flag_set_repeated_parameter(UP(param));
}
- pm_parameters_node_requireds_append(params, (pm_node_t *) param);
+ pm_parameters_node_requireds_append(parser->arena, params, UP(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_node_flag_set_repeated_parameter(UP(param));
}
- pm_parameters_node_posts_append(params, (pm_node_t *) param);
+ pm_parameters_node_posts_append(parser->arena, params, UP(param));
}
break;
@@ -14705,9 +14357,9 @@ parse_parameters(
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);
+ pm_parser_err(parser, PM_TOKEN_START(parser, &local), PM_TOKEN_LENGTH(&local), 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);
+ PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, &local, PM_ERR_INVALID_LOCAL_VARIABLE_WRITE);
}
bool repeated = pm_parser_parameter_name_check(parser, &local);
@@ -14719,12 +14371,12 @@ parse_parameters(
case PM_TOKEN_PIPE: {
context_pop(parser);
- pm_node_t *param = (pm_node_t *) pm_required_keyword_parameter_node_create(parser, &name);
+ pm_node_t *param = UP(pm_required_keyword_parameter_node_create(parser, &name));
if (repeated) {
pm_node_flag_set_repeated_parameter(param);
}
- pm_parameters_node_keywords_append(params, param);
+ pm_parameters_node_keywords_append(parser->arena, params, param);
break;
}
case PM_TOKEN_SEMICOLON:
@@ -14736,12 +14388,12 @@ parse_parameters(
break;
}
- pm_node_t *param = (pm_node_t *) pm_required_keyword_parameter_node_create(parser, &name);
+ pm_node_t *param = UP(pm_required_keyword_parameter_node_create(parser, &name));
if (repeated) {
pm_node_flag_set_repeated_parameter(param);
}
- pm_parameters_node_keywords_append(params, param);
+ pm_parameters_node_keywords_append(parser->arena, params, param);
break;
}
default: {
@@ -14752,17 +14404,17 @@ parse_parameters(
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));
+ pm_node_t *value = parse_value_expression(parser, binding_power, PM_PARSE_ACCEPTS_DO_BLOCK, 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);
+ 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);
+ param = UP(pm_optional_keyword_parameter_node_create(parser, &name, value));
}
else {
- param = (pm_node_t *) pm_required_keyword_parameter_node_create(parser, &name);
+ param = UP(pm_required_keyword_parameter_node_create(parser, &name));
}
if (repeated) {
@@ -14770,7 +14422,7 @@ parse_parameters(
}
context_pop(parser);
- pm_parameters_node_keywords_append(params, param);
+ pm_parameters_node_keywords_append(parser->arena, 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
@@ -14791,7 +14443,7 @@ parse_parameters(
parser_lex(parser);
pm_token_t operator = parser->previous;
- pm_token_t name;
+ pm_token_t name = { 0 };
bool repeated = false;
if (accept1(parser, PM_TOKEN_IDENTIFIER)) {
@@ -14799,11 +14451,10 @@ parse_parameters(
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);
+ pm_node_t *param = UP(pm_rest_parameter_node_create(parser, &operator, NTOK2PTR(name)));
if (repeated) {
pm_node_flag_set_repeated_parameter(param);
}
@@ -14812,7 +14463,7 @@ parse_parameters(
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);
+ pm_parameters_node_posts_append(parser->arena, params, param);
}
break;
@@ -14831,9 +14482,9 @@ parse_parameters(
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);
+ param = UP(pm_no_keywords_parameter_node_create(parser, &operator, &parser->previous));
} else {
- pm_token_t name;
+ pm_token_t name = { 0 };
bool repeated = false;
if (accept1(parser, PM_TOKEN_IDENTIFIER)) {
@@ -14841,11 +14492,10 @@ parse_parameters(
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);
+ param = UP(pm_keyword_rest_parameter_node_create(parser, &operator, NTOK2PTR(name)));
if (repeated) {
pm_node_flag_set_repeated_parameter(param);
}
@@ -14855,27 +14505,14 @@ parse_parameters(
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);
+ pm_parameters_node_posts_append(parser->arena, params, UP(pm_error_recovery_node_create_unexpected(parser, 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);
- }
+ parse_parameters_handle_trailing_comma(parser, params, order, in_block, allows_trailing_comma);
}
parsing = false;
@@ -14907,8 +14544,7 @@ parse_parameters(
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);
+ if (PM_NODE_START(params) == PM_NODE_END(params)) {
return NULL;
}
@@ -14925,13 +14561,13 @@ token_newline_index(const pm_parser_t *parser) {
// 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;
+ return parser->line_offsets.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);
+ return (size_t) pm_line_offset_list_line(&parser->line_offsets, PM_TOKEN_START(parser, &parser->current), 0);
}
}
@@ -14941,7 +14577,7 @@ token_newline_index(const pm_parser_t *parser) {
*/
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 *cursor = parser->start + parser->line_offsets.offsets[newline_index];
const uint8_t *end = token->start;
// Skip over the BOM if it is present.
@@ -15005,8 +14641,8 @@ parser_warn_indentation_mismatch(pm_parser_t *parser, size_t opening_newline_ind
// Otherwise, add a warning.
PM_PARSER_WARN_FORMAT(
parser,
- closing_token->start,
- closing_token->end,
+ PM_TOKEN_START(parser, closing_token),
+ PM_TOKEN_LENGTH(closing_token),
PM_WARN_INDENTATION_MISMATCH,
(int) (closing_token->end - closing_token->start),
(const char *) closing_token->start,
@@ -15030,7 +14666,7 @@ typedef enum {
* 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
+static PRISM_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;
@@ -15046,9 +14682,9 @@ parse_rescues(pm_parser_t *parser, size_t opening_newline_index, const pm_token_
// 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_rescue_node_operator_set(parser, rescue, &parser->previous);
- pm_node_t *reference = parse_expression(parser, PM_BINDING_POWER_INDEX, false, false, PM_ERR_RESCUE_VARIABLE, (uint16_t) (depth + 1));
+ pm_node_t *reference = parse_expression(parser, PM_BINDING_POWER_INDEX, PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_RESCUE_VARIABLE, (uint16_t) (depth + 1));
reference = parse_target(parser, reference, false, false);
pm_rescue_node_reference_set(rescue, reference);
@@ -15067,7 +14703,7 @@ parse_rescues(pm_parser_t *parser, size_t opening_newline_index, const pm_token_
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);
+ pm_rescue_node_exceptions_append(parser->arena, rescue, expression);
// If we hit a newline, then this is the end of the rescue expression. We
// can continue on to parse the statements.
@@ -15076,9 +14712,9 @@ parse_rescues(pm_parser_t *parser, size_t opening_newline_index, const pm_token_
// 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_rescue_node_operator_set(parser, rescue, &parser->previous);
- pm_node_t *reference = parse_expression(parser, PM_BINDING_POWER_INDEX, false, false, PM_ERR_RESCUE_VARIABLE, (uint16_t) (depth + 1));
+ pm_node_t *reference = parse_expression(parser, PM_BINDING_POWER_INDEX, PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_RESCUE_VARIABLE, (uint16_t) (depth + 1));
reference = parse_target(parser, reference, false, false);
pm_rescue_node_reference_set(rescue, reference);
@@ -15091,11 +14727,11 @@ parse_rescues(pm_parser_t *parser, size_t opening_newline_index, const pm_token_
if (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
if (accept1(parser, PM_TOKEN_KEYWORD_THEN)) {
- rescue->then_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(&parser->previous);
+ rescue->then_keyword_loc = TOK2LOC(parser, &parser->previous);
}
} else {
expect1(parser, PM_TOKEN_KEYWORD_THEN, PM_ERR_RESCUE_TERM);
- rescue->then_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(&parser->previous);
+ rescue->then_keyword_loc = TOK2LOC(parser, &parser->previous);
}
if (!match3(parser, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_END)) {
@@ -15133,11 +14769,10 @@ parse_rescues(pm_parser_t *parser, size_t opening_newline_index, const pm_token_
// 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;
+ PM_NODE_LENGTH_SET_NODE(clause, current);
clause = clause->subsequent;
}
}
@@ -15180,7 +14815,7 @@ parse_rescues(pm_parser_t *parser, size_t opening_newline_index, const pm_token_
// 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 (current == NULL) pm_parser_err_node(parser, UP(else_clause), PM_ERR_BEGIN_LONELY_ELSE);
}
if (match1(parser, PM_TOKEN_KEYWORD_ENSURE)) {
@@ -15218,10 +14853,10 @@ parse_rescues(pm_parser_t *parser, size_t opening_newline_index, const pm_token_
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);
+ pm_begin_node_end_keyword_set(parser, 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);
+ pm_token_t end_keyword = (pm_token_t) { .type = PM_TOKEN_KEYWORD_END, .start = parser->previous.end, .end = parser->previous.end };
+ pm_begin_node_end_keyword_set(parser, parent_node, &end_keyword);
}
}
@@ -15231,11 +14866,11 @@ parse_rescues(pm_parser_t *parser, size_t opening_newline_index, const pm_token_
*/
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);
-
+ pm_begin_node_t *node = pm_begin_node_create(parser, NULL, statements);
parse_rescues(parser, opening_newline_index, opening, node, type, (uint16_t) (depth + 1));
- node->base.location.start = start;
+
+ node->base.location.start = U32(start - parser->start);
+ PM_NODE_LENGTH_SET_TOKEN(parser, node, &parser->current);
return node;
}
@@ -15254,6 +14889,9 @@ parse_block_parameters(
) {
pm_parameters_node_t *parameters = NULL;
if (!match1(parser, PM_TOKEN_SEMICOLON)) {
+ if (!is_lambda_literal) {
+ context_push(parser, PM_CONTEXT_BLOCK_PARAMETERS);
+ }
parameters = parse_parameters(
parser,
is_lambda_literal ? PM_BINDING_POWER_DEFINED : PM_BINDING_POWER_INDEX,
@@ -15262,12 +14900,16 @@ parse_block_parameters(
false,
accepts_blocks_in_defaults,
true,
+ is_lambda_literal ? PM_ERR_ARGUMENT_NO_FORWARDING_ELLIPSES_LAMBDA : PM_ERR_ARGUMENT_NO_FORWARDING_ELLIPSES_BLOCK,
(uint16_t) (depth + 1)
);
+ if (!is_lambda_literal) {
+ context_pop(parser);
+ }
}
pm_block_parameters_node_t *block_parameters = pm_block_parameters_node_create(parser, parameters, opening);
- if ((opening->type != PM_TOKEN_NOT_PROVIDED)) {
+ if (opening != NULL) {
accept1(parser, PM_TOKEN_NEWLINE);
if (accept1(parser, PM_TOKEN_SEMICOLON)) {
@@ -15298,9 +14940,9 @@ parse_block_parameters(
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);
+ if (repeated) pm_node_flag_set_repeated_parameter(UP(local));
- pm_block_parameters_node_append_local(block_parameters, local);
+ pm_block_parameters_node_append_local(parser->arena, block_parameters, local);
} while (accept1(parser, PM_TOKEN_COMMA));
}
}
@@ -15380,8 +15022,8 @@ parse_blocklike_parameters(pm_parser_t *parser, pm_node_t *parameters, const pm_
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 if (pm_token_is_numbered_parameter(parser, PM_NODE_START(node), PM_NODE_LENGTH(node))) {
+ numbered_parameter = MAX(numbered_parameter, (uint8_t) (parser->start[node->location.start + 1] - '0'));
} else {
assert(false && "unreachable");
}
@@ -15400,13 +15042,11 @@ parse_blocklike_parameters(pm_parser_t *parser, pm_node_t *parameters, const pm_
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);
+ return UP(pm_numbered_parameters_node_create(parser, opening, closing, numbered_parameter));
}
if (it_parameter) {
- return (pm_node_t *) pm_it_parameters_node_create(parser, opening, closing);
+ return UP(pm_it_parameters_node_create(parser, opening, closing));
}
return NULL;
@@ -15438,7 +15078,7 @@ parse_block(pm_parser_t *parser, uint16_t depth) {
expect1(parser, PM_TOKEN_PIPE, PM_ERR_BLOCK_PARAM_PIPE_TERM);
}
- pm_block_parameters_node_closing_set(block_parameters, &parser->previous);
+ pm_block_parameters_node_closing_set(parser, block_parameters, &parser->previous);
}
accept1(parser, PM_TOKEN_NEWLINE);
@@ -15446,30 +15086,30 @@ parse_block(pm_parser_t *parser, uint16_t depth) {
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));
+ statements = UP(parse_statements(parser, PM_CONTEXT_BLOCK_BRACES, (uint16_t) (depth + 1)));
}
- expect1(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_BLOCK_TERM_BRACE);
+ expect1_opening(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_BLOCK_TERM_BRACE, &opening);
} 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));
+ statements = UP(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));
+ statements = UP(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);
+ expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_BLOCK_TERM_END, &opening);
}
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_node_t *parameters = parse_blocklike_parameters(parser, UP(block_parameters), &opening, &parser->previous);
pm_parser_scope_pop(parser);
pm_accepts_block_stack_pop(parser);
@@ -15483,42 +15123,54 @@ parse_block(pm_parser_t *parser, uint16_t depth) {
* 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) {
+parse_arguments_list(pm_parser_t *parser, pm_arguments_t *arguments, bool accepts_block, uint8_t flags, uint16_t depth) {
+ /* Fast path: if the current token can't begin an expression and isn't
+ * a parenthesis, block opener, or splat/block-pass operator, there are
+ * no arguments to parse. */
+ if (
+ !token_begins_expression_p(parser->current.type) &&
+ !match6(parser, PM_TOKEN_PARENTHESIS_LEFT, PM_TOKEN_KEYWORD_DO, PM_TOKEN_KEYWORD_DO_BLOCK, PM_TOKEN_USTAR, PM_TOKEN_USTAR_STAR, PM_TOKEN_UAMPERSAND)
+ ) {
+ return false;
+ }
+
bool found = false;
+ bool parsed_command_args = false;
if (accept1(parser, PM_TOKEN_PARENTHESIS_LEFT)) {
found |= true;
- arguments->opening_loc = PM_LOCATION_TOKEN_VALUE(&parser->previous);
+ arguments->opening_loc = TOK2LOC(parser, &parser->previous);
if (accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
- arguments->closing_loc = PM_LOCATION_TOKEN_VALUE(&parser->previous);
+ arguments->closing_loc = TOK2LOC(parser, &parser->previous);
} else {
pm_accepts_block_stack_push(parser, true);
- parse_arguments(parser, arguments, accepts_block, PM_TOKEN_PARENTHESIS_RIGHT, (uint16_t) (depth + 1));
+ parse_arguments(parser, arguments, accepts_block, PM_TOKEN_PARENTHESIS_RIGHT, (uint8_t) (flags & ~PM_PARSE_ACCEPTS_DO_BLOCK), (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));
+ PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_ARGUMENT_TERM_PAREN, pm_token_str(parser->current.type));
parser->previous.start = parser->previous.end;
- parser->previous.type = PM_TOKEN_MISSING;
+ parser->previous.type = 0;
}
pm_accepts_block_stack_pop(parser);
- arguments->closing_loc = PM_LOCATION_TOKEN_VALUE(&parser->previous);
+ arguments->closing_loc = TOK2LOC(parser, &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)) {
+ } else if ((flags & PM_PARSE_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;
+ parsed_command_args = 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));
+ parse_arguments(parser, arguments, accepts_block, PM_TOKEN_EOF, flags, (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_PARSER_ERR_TOKEN_FORMAT(parser, &parser->previous, PM_ERR_EXPECT_ARGUMENT, pm_token_str(parser->current.type));
}
pm_accepts_block_stack_pop(parser);
@@ -15537,21 +15189,24 @@ parse_arguments_list(pm_parser_t *parser, pm_arguments_t *arguments, bool accept
} else if (pm_accepts_block_stack_p(parser) && accept1(parser, PM_TOKEN_KEYWORD_DO)) {
found |= true;
block = parse_block(parser, (uint16_t) (depth + 1));
+ } else if (parsed_command_args && pm_accepts_block_stack_p(parser) && (flags & PM_PARSE_ACCEPTS_DO_BLOCK) && accept1(parser, PM_TOKEN_KEYWORD_DO_BLOCK)) {
+ 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;
+ arguments->block = UP(block);
} else {
- pm_parser_err_node(parser, (pm_node_t *) block, PM_ERR_ARGUMENT_BLOCK_MULTI);
+ pm_parser_err_node(parser, UP(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);
+ pm_arguments_node_arguments_append(parser->arena, arguments->arguments, arguments->block);
}
- arguments->block = (pm_node_t *) block;
+ arguments->block = UP(block);
}
}
}
@@ -15619,6 +15274,7 @@ parse_return(pm_parser_t *parser, pm_node_t *node) {
case PM_CONTEXT_BLOCK_ENSURE:
case PM_CONTEXT_BLOCK_KEYWORDS:
case PM_CONTEXT_BLOCK_RESCUE:
+ case PM_CONTEXT_BLOCK_PARAMETERS:
case PM_CONTEXT_DEF_ELSE:
case PM_CONTEXT_DEF_ENSURE:
case PM_CONTEXT_DEF_PARAMS:
@@ -15638,7 +15294,7 @@ parse_return(pm_parser_t *parser, pm_node_t *node) {
break;
}
}
- if (in_sclass) {
+ if (in_sclass && parser->version >= PM_OPTIONS_VERSION_CRUBY_3_4) {
pm_parser_err_node(parser, node, PM_ERR_RETURN_INVALID);
}
}
@@ -15655,6 +15311,7 @@ parse_block_exit(pm_parser_t *parser, pm_node_t *node) {
case PM_CONTEXT_BLOCK_KEYWORDS:
case PM_CONTEXT_BLOCK_ELSE:
case PM_CONTEXT_BLOCK_ENSURE:
+ case PM_CONTEXT_BLOCK_PARAMETERS:
case PM_CONTEXT_BLOCK_RESCUE:
case PM_CONTEXT_DEFINED:
case PM_CONTEXT_FOR:
@@ -15664,12 +15321,19 @@ parse_block_exit(pm_parser_t *parser, pm_node_t *node) {
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_POSTEXE:
+ // https://bugs.ruby-lang.org/issues/20409
+ if (context_node->context == PM_CONTEXT_POSTEXE) {
+ if (parser->version < PM_OPTIONS_VERSION_CRUBY_4_1) {
+ return;
+ }
+ }
+ PRISM_FALLTHROUGH
case PM_CONTEXT_DEF:
case PM_CONTEXT_DEF_PARAMS:
case PM_CONTEXT_DEF_ELSE:
@@ -15691,7 +15355,7 @@ parse_block_exit(pm_parser_t *parser, pm_node_t *node) {
// 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);
+ pm_node_list_append(parser->arena, parser->current_block_exits, node);
return;
case PM_CONTEXT_BEGIN_ELSE:
case PM_CONTEXT_BEGIN_ENSURE:
@@ -15782,7 +15446,7 @@ pop_block_exits(pm_parser_t *parser, pm_node_list_t *previous_block_exits) {
// 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);
+ pm_node_list_concat(parser->arena, 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
@@ -15792,11 +15456,11 @@ pop_block_exits(pm_parser_t *parser, pm_node_list_t *previous_block_exits) {
}
}
-static inline pm_node_t *
+static PRISM_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));
+ pm_node_t *predicate = parse_value_expression(parser, binding_power, PM_PARSE_ACCEPTS_COMMAND_CALL | PM_PARSE_ACCEPTS_DO_BLOCK, 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);
@@ -15814,15 +15478,15 @@ parse_predicate(pm_parser_t *parser, pm_binding_power_t binding_power, pm_contex
return predicate;
}
-static inline pm_node_t *
+static PRISM_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_token_t then_keyword = { 0 };
- pm_node_t *predicate = parse_predicate(parser, PM_BINDING_POWER_MODIFIER, context, &then_keyword, (uint16_t) (depth + 1));
+ pm_node_t *predicate = parse_predicate(parser, PM_BINDING_POWER_COMPOSITION, 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)) {
@@ -15832,15 +15496,14 @@ parse_conditional(pm_parser_t *parser, pm_context_t context, size_t opening_newl
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);
+ parent = UP(pm_if_node_create(parser, &keyword, predicate, NTOK2PTR(then_keyword), statements, NULL, NULL));
break;
case PM_CONTEXT_UNLESS:
- parent = (pm_node_t *) pm_unless_node_create(parser, &keyword, predicate, &then_keyword, statements);
+ parent = UP(pm_unless_node_create(parser, &keyword, predicate, NTOK2PTR(then_keyword), statements));
break;
default:
assert(false && "unreachable");
@@ -15854,21 +15517,21 @@ parse_conditional(pm_parser_t *parser, pm_context_t context, size_t opening_newl
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);
+ 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_node_t *predicate = parse_predicate(parser, PM_BINDING_POWER_COMPOSITION, 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_node_t *elsif = UP(pm_if_node_create(parser, &elsif_keyword, predicate, NTOK2PTR(then_keyword), statements, NULL, NULL));
((pm_if_node_t *) current)->subsequent = elsif;
current = elsif;
}
@@ -15887,13 +15550,13 @@ parse_conditional(pm_parser_t *parser, pm_context_t context, size_t opening_newl
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);
+ expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CONDITIONAL_TERM_ELSE, &keyword);
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;
+ ((pm_if_node_t *) current)->subsequent = UP(else_node);
break;
case PM_CONTEXT_UNLESS:
((pm_unless_node_t *) parent)->else_clause = else_node;
@@ -15904,7 +15567,7 @@ parse_conditional(pm_parser_t *parser, pm_context_t context, size_t opening_newl
}
} else {
parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword, if_after_else, false);
- expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CONDITIONAL_TERM);
+ expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CONDITIONAL_TERM, &keyword);
}
// Set the appropriate end location for all of the nodes in the subtree.
@@ -15916,12 +15579,12 @@ parse_conditional(pm_parser_t *parser, pm_context_t context, size_t opening_newl
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);
+ pm_if_node_end_keyword_loc_set(parser, (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);
+ pm_else_node_end_keyword_loc_set(parser, (pm_else_node_t *) current, &parser->previous);
recursing = false;
break;
default: {
@@ -15933,7 +15596,7 @@ parse_conditional(pm_parser_t *parser, pm_context_t context, size_t opening_newl
break;
}
case PM_CONTEXT_UNLESS:
- pm_unless_node_end_keyword_loc_set((pm_unless_node_t *) parent, &parser->previous);
+ pm_unless_node_end_keyword_loc_set(parser, (pm_unless_node_t *) parent, &parser->previous);
break;
default:
assert(false && "unreachable");
@@ -15941,8 +15604,6 @@ parse_conditional(pm_parser_t *parser, pm_context_t context, size_t opening_newl
}
pop_block_exits(parser, previous_block_exits);
- pm_node_list_free(&current_block_exits);
-
return parent;
}
@@ -15953,7 +15614,7 @@ parse_conditional(pm_parser_t *parser, pm_context_t context, size_t opening_newl
#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_DEFINED: case PM_TOKEN_KEYWORD_DO: case PM_TOKEN_KEYWORD_DO_BLOCK: 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: \
@@ -16016,7 +15677,7 @@ PM_STATIC_ASSERT(__LINE__, ((int) PM_STRING_FLAGS_FORCED_UTF8_ENCODING) == ((int
* 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
+static PRISM_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) {
@@ -16048,10 +15709,7 @@ parse_string_part(pm_parser_t *parser, uint16_t depth) {
// "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_t *node = UP(pm_string_node_create_current_string(parser, NULL, &parser->current, NULL));
pm_node_flag_set(node, parse_unescaped_encoding(parser));
parser_lex(parser);
@@ -16078,7 +15736,7 @@ parse_string_part(pm_parser_t *parser, uint16_t depth) {
pm_token_t opening = parser->previous;
pm_statements_node_t *statements = NULL;
- if (!match1(parser, PM_TOKEN_EMBEXPR_END)) {
+ if (!match3(parser, PM_TOKEN_EMBEXPR_END, PM_TOKEN_HEREDOC_END, PM_TOKEN_EOF)) {
pm_accepts_block_stack_push(parser, true);
statements = parse_statements(parser, PM_CONTEXT_EMBEXPR, (uint16_t) (depth + 1));
pm_accepts_block_stack_pop(parser);
@@ -16086,9 +15744,7 @@ parse_string_part(pm_parser_t *parser, uint16_t depth) {
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
@@ -16097,7 +15753,7 @@ parse_string_part(pm_parser_t *parser, uint16_t depth) {
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);
+ return UP(pm_embedded_statements_node_create(parser, &opening, statements, &parser->previous));
}
// Here the lexer has returned the beginning of an embedded variable.
@@ -16122,42 +15778,42 @@ parse_string_part(pm_parser_t *parser, uint16_t depth) {
// 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);
+ variable = UP(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);
+ variable = UP(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);
+ variable = UP(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);
+ variable = UP(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);
+ variable = UP(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);
+ variable = UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current)));
break;
}
- return (pm_node_t *) pm_embedded_variable_node_create(parser, &operator, variable);
+ return UP(pm_embedded_variable_node_create(parser, &operator, variable));
}
default:
parser_lex(parser);
@@ -16185,18 +15841,16 @@ parse_operator_symbol_name(const pm_token_t *name) {
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);
-
+ pm_symbol_node_t *symbol = pm_symbol_node_create(parser, opening, &parser->current, NULL);
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);
+ pm_node_flag_set(UP(symbol), PM_SYMBOL_FLAGS_FORCED_US_ASCII_ENCODING);
- return (pm_node_t *) symbol;
+ return UP(symbol);
}
/**
@@ -16230,13 +15884,11 @@ parse_symbol(pm_parser_t *parser, pm_lex_mode_t *lex_mode, pm_lex_state_t next_s
break;
}
- pm_token_t closing = not_provided(parser);
- pm_symbol_node_t *symbol = pm_symbol_node_create(parser, &opening, &parser->previous, &closing);
-
+ pm_symbol_node_t *symbol = pm_symbol_node_create(parser, &opening, &parser->previous, NULL);
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));
+ pm_node_flag_set(UP(symbol), parse_symbol_encoding(parser, &parser->previous, &symbol->unescaped, false));
- return (pm_node_t *) symbol;
+ return UP(symbol);
}
if (lex_mode->as.string.interpolation) {
@@ -16244,10 +15896,13 @@ parse_symbol(pm_parser_t *parser, pm_lex_mode_t *lex_mode, pm_lex_state_t next_s
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 = {
+ .type = PM_TOKEN_STRING_CONTENT,
+ .start = parser->previous.start,
+ .end = parser->previous.start
+ };
- 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);
+ return UP(pm_symbol_node_create(parser, &opening, &content, &parser->previous));
}
// Now we can parse the first part of the symbol.
@@ -16259,15 +15914,15 @@ parse_symbol(pm_parser_t *parser, pm_lex_mode_t *lex_mode, pm_lex_state_t next_s
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);
+ return UP(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);
+ if (part) pm_interpolated_symbol_node_append(parser->arena, 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);
+ pm_interpolated_symbol_node_append(parser->arena, symbol, part);
}
}
@@ -16278,8 +15933,8 @@ parse_symbol(pm_parser_t *parser, pm_lex_mode_t *lex_mode, pm_lex_state_t next_s
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_interpolated_symbol_node_closing_loc_set(parser, symbol, &parser->previous);
+ return UP(symbol);
}
pm_token_t content;
@@ -16301,13 +15956,11 @@ parse_symbol(pm_parser_t *parser, pm_lex_mode_t *lex_mode, pm_lex_state_t next_s
// 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);
+ pm_node_t *part = UP(pm_string_node_create_unescaped(parser, NULL, &content, NULL, &unescaped));
+ pm_interpolated_symbol_node_append(parser->arena, 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);
+ part = UP(pm_string_node_create_unescaped(parser, NULL, &parser->current, NULL, &parser->current_string));
+ pm_interpolated_symbol_node_append(parser->arena, symbol, part);
if (next_state != PM_LEX_STATE_NONE) {
lex_state_set(parser, next_state);
@@ -16316,8 +15969,8 @@ parse_symbol(pm_parser_t *parser, pm_lex_mode_t *lex_mode, pm_lex_state_t next_s
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;
+ pm_interpolated_symbol_node_closing_loc_set(parser, symbol, &parser->previous);
+ return UP(symbol);
}
} else {
content = (pm_token_t) { .type = PM_TOKEN_STRING_CONTENT, .start = parser->previous.end, .end = parser->previous.end };
@@ -16334,34 +15987,29 @@ parse_symbol(pm_parser_t *parser, pm_lex_mode_t *lex_mode, pm_lex_state_t next_s
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));
+ return UP(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 *
+static PRISM_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_OPERATOR:
+ return parse_operator_symbol(parser, NULL, 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_symbol_node_t *symbol = pm_symbol_node_create(parser, NULL, &parser->previous, NULL);
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));
+ pm_node_flag_set(UP(symbol), parse_symbol_encoding(parser, &parser->previous, &symbol->unescaped, false));
- return (pm_node_t *) symbol;
+ return UP(symbol);
}
case PM_TOKEN_SYMBOL_BEGIN: {
pm_lex_mode_t lex_mode = *parser->lex_modes.current;
@@ -16371,7 +16019,7 @@ parse_undef_argument(pm_parser_t *parser, uint16_t depth) {
}
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);
+ return UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current)));
}
}
@@ -16381,13 +16029,11 @@ parse_undef_argument(pm_parser_t *parser, uint16_t depth) {
* 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 *
+static PRISM_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_OPERATOR:
+ return parse_operator_symbol(parser, NULL, 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:
@@ -16395,14 +16041,11 @@ parse_alias_argument(pm_parser_t *parser, bool first, uint16_t depth) {
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_symbol_node_t *symbol = pm_symbol_node_create(parser, NULL, &parser->previous, NULL);
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));
+ pm_node_flag_set(UP(symbol), parse_symbol_encoding(parser, &parser->previous, &symbol->unescaped, false));
- return (pm_node_t *) symbol;
+ return UP(symbol);
}
case PM_TOKEN_SYMBOL_BEGIN: {
pm_lex_mode_t lex_mode = *parser->lex_modes.current;
@@ -16412,16 +16055,16 @@ parse_alias_argument(pm_parser_t *parser, bool first, uint16_t depth) {
}
case PM_TOKEN_BACK_REFERENCE:
parser_lex(parser);
- return (pm_node_t *) pm_back_reference_read_node_create(parser, &parser->previous);
+ return UP(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);
+ return UP(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);
+ return UP(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);
+ return UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current)));
}
}
@@ -16433,10 +16076,10 @@ 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;
- bool is_numbered_param = pm_token_is_numbered_parameter(parser->previous.start, parser->previous.end);
+ bool is_numbered_param = pm_token_is_numbered_parameter(parser, PM_TOKEN_START(parser, &parser->previous), PM_TOKEN_LENGTH(&parser->previous));
if (!is_numbered_param && ((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);
+ return UP(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;
@@ -16455,13 +16098,13 @@ parse_variable(pm_parser_t *parser) {
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);
+ pm_node_t *node = UP(pm_local_variable_read_node_create_constant_id(parser, &parser->previous, name_id, 0, false));
+ pm_node_list_append(parser->arena, &current_scope->implicit_parameters, node);
return node;
} else if ((parser->version >= PM_OPTIONS_VERSION_CRUBY_3_4) && 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);
+ pm_node_t *node = UP(pm_it_local_variable_read_node_create(parser, &parser->previous));
+ pm_node_list_append(parser->arena, &current_scope->implicit_parameters, node);
return node;
}
@@ -16484,9 +16127,9 @@ parse_variable_call(pm_parser_t *parser) {
}
pm_call_node_t *node = pm_call_node_variable_call_create(parser, &parser->previous);
- pm_node_flag_set((pm_node_t *)node, flags);
+ pm_node_flag_set(UP(node), flags);
- return (pm_node_t *) node;
+ return UP(node);
}
/**
@@ -16494,7 +16137,7 @@ parse_variable_call(pm_parser_t *parser) {
* parser. If it does not match a valid method definition name, then a missing
* token is returned.
*/
-static inline pm_token_t
+static PRISM_INLINE pm_token_t
parse_method_definition_name(pm_parser_t *parser) {
switch (parser->current.type) {
case PM_CASE_KEYWORD:
@@ -16503,7 +16146,7 @@ parse_method_definition_name(pm_parser_t *parser) {
parser_lex(parser);
return parser->previous;
case PM_TOKEN_IDENTIFIER:
- pm_refute_numbered_parameter(parser, parser->current.start, parser->current.end);
+ pm_refute_numbered_parameter(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current));
parser_lex(parser);
return parser->previous;
case PM_CASE_OPERATOR:
@@ -16511,22 +16154,31 @@ parse_method_definition_name(pm_parser_t *parser) {
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 };
+ PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_DEF_NAME, pm_token_str(parser->current.type));
+ return (pm_token_t) { .type = 0, .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);
+parse_heredoc_dedent_string(pm_arena_t *arena, pm_string_t *string, size_t common_whitespace) {
+ // Make a writable copy in the arena if the string isn't already writable.
+ // We keep a mutable pointer to the arena memory so we can memmove into it
+ // below without casting away const from the string's source field.
+ uint8_t *writable;
+
+ if (string->type != PM_STRING_OWNED) {
+ size_t length = pm_string_length(string);
+ writable = (uint8_t *) pm_arena_memdup(arena, pm_string_source(string), length, PRISM_ALIGNOF(uint8_t));
+ pm_string_constant_init(string, (const char *) writable, length);
+ } else {
+ writable = (uint8_t *) string->source;
+ }
// 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_cursor = writable;
const uint8_t *source_end = source_cursor + dest_length;
// We're going to move bytes backward in the string when we get leading
@@ -16550,11 +16202,24 @@ parse_heredoc_dedent_string(pm_string_t *string, size_t common_whitespace) {
dest_length--;
}
- memmove((uint8_t *) string->source, source_cursor, (size_t) (source_end - source_cursor));
+ memmove(writable, source_cursor, (size_t) (source_end - source_cursor));
string->length = dest_length;
}
/**
+ * If we end up trimming all of the whitespace from a node and it isn't
+ * part of a line continuation, then we'll drop it from the list entirely.
+ */
+static PRISM_INLINE bool
+heredoc_dedent_discard_string_node(pm_parser_t *parser, pm_string_node_t *string_node) {
+ if (string_node->unescaped.length == 0) {
+ const uint8_t *cursor = parser->start + PM_LOCATION_START(&string_node->content_loc);
+ return pm_memchr(cursor, '\\', string_node->content_loc.length, parser->encoding_changed, parser->encoding) == NULL;
+ }
+ return false;
+}
+
+/**
* Take a heredoc node that is indented by a ~ and trim the leading whitespace.
*/
static void
@@ -16564,8 +16229,7 @@ parse_heredoc_dedent(pm_parser_t *parser, pm_node_list_t *nodes, size_t common_w
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.
+ // keep around two indices: a read and a write.
size_t write_index = 0;
pm_node_t *node;
@@ -16581,11 +16245,10 @@ parse_heredoc_dedent(pm_parser_t *parser, pm_node_list_t *nodes, size_t common_w
pm_string_node_t *string_node = ((pm_string_node_t *) node);
if (dedent_next) {
- parse_heredoc_dedent_string(&string_node->unescaped, common_whitespace);
+ parse_heredoc_dedent_string(parser->arena, &string_node->unescaped, common_whitespace);
}
- if (string_node->unescaped.length == 0) {
- pm_node_destroy(parser, node);
+ if (heredoc_dedent_discard_string_node(parser, string_node)) {
} else {
nodes->nodes[write_index++] = node;
}
@@ -16608,7 +16271,7 @@ parse_strings_empty_content(const uint8_t *location) {
/**
* Parse a set of strings that could be concatenated together.
*/
-static inline pm_node_t *
+static PRISM_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;
@@ -16635,16 +16298,14 @@ parse_strings(pm_parser_t *parser, pm_node_t *current, bool accepts_label, uint1
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;
+ node = UP(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;
+ pm_symbol_node_t *symbol = pm_symbol_node_create(parser, &opening, NULL, &parser->previous);
+ pm_string_shared_init(&symbol->unescaped, parser->previous.start, parser->previous.start);
+ node = UP(symbol);
if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL);
} else if (!lex_interpolation) {
@@ -16655,7 +16316,7 @@ parse_strings(pm_parser_t *parser, pm_node_t *current, bool accepts_label, uint1
if (match1(parser, PM_TOKEN_EOF)) {
unescaped = PM_STRING_EMPTY;
- content = not_provided(parser);
+ content = (pm_token_t) { .type = PM_TOKEN_STRING_CONTENT, .start = parser->start, .end = parser->start };
} else {
unescaped = parser->current_string;
expect1(parser, PM_TOKEN_STRING_CONTENT, PM_ERR_EXPECT_STRING_CONTENT);
@@ -16675,34 +16336,30 @@ parse_strings(pm_parser_t *parser, pm_node_t *current, bool accepts_label, uint1
// 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);
+ pm_node_t *part = UP(pm_string_node_create_unescaped(parser, NULL, &content, NULL, &unescaped));
+ pm_node_list_append(parser->arena, &parts, part);
do {
- part = (pm_node_t *) pm_string_node_create_current_string(parser, &delimiters, &parser->current, &delimiters);
- pm_node_list_append(&parts, part);
+ part = UP(pm_string_node_create_current_string(parser, NULL, &parser->current, NULL));
+ pm_node_list_append(parser->arena, &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);
+ node = UP(pm_interpolated_string_node_create(parser, &opening, &parts, &parser->previous));
} 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));
+ node = UP(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);
+ node = UP(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);
+ node = UP(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));
+ PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->previous, PM_ERR_STRING_LITERAL_TERM, pm_token_str(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);
+ parser->previous.type = 0;
+ node = UP(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
@@ -16714,7 +16371,7 @@ parse_strings(pm_parser_t *parser, pm_node_t *current, bool accepts_label, uint1
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);
+ node = UP(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
@@ -16724,43 +16381,38 @@ parse_strings(pm_parser_t *parser, pm_node_t *current, bool accepts_label, uint1
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);
+ pm_parser_err(parser, U32(location - parser->start), 0, PM_ERR_STRING_LITERAL_EOF);
parser->previous.start = parser->previous.end;
- parser->previous.type = PM_TOKEN_MISSING;
+ parser->previous.type = 0;
}
} 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));
+ node = UP(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_t *part = UP(pm_string_node_create_unescaped(parser, NULL, &parser->previous, NULL, &unescaped));
pm_node_flag_set(part, parse_unescaped_encoding(parser));
- pm_node_list_append(&parts, part);
+ pm_node_list_append(parser->arena, &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);
+ pm_node_list_append(parser->arena, &parts, part);
}
}
if (accept1(parser, PM_TOKEN_LABEL_END)) {
- node = (pm_node_t *) pm_interpolated_symbol_node_create(parser, &opening, &parts, &parser->previous);
+ node = UP(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);
+ node = UP(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);
+ node = UP(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
@@ -16771,22 +16423,20 @@ parse_strings(pm_parser_t *parser, pm_node_t *current, bool accepts_label, uint1
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);
+ pm_node_list_append(parser->arena, &parts, part);
}
}
if (accept1(parser, PM_TOKEN_LABEL_END)) {
- node = (pm_node_t *) pm_interpolated_symbol_node_create(parser, &opening, &parts, &parser->previous);
+ node = UP(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);
+ node = UP(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);
+ node = UP(pm_interpolated_string_node_create(parser, &opening, &parts, &parser->previous));
}
-
- pm_node_list_free(&parts);
}
if (current == NULL) {
@@ -16816,14 +16466,12 @@ parse_strings(pm_parser_t *parser, pm_node_t *current, bool accepts_label, uint1
}
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_t *container = pm_interpolated_string_node_create(parser, NULL, NULL, NULL);
+ pm_interpolated_string_node_append(parser, container, current);
+ current = UP(container);
}
- pm_interpolated_string_node_append((pm_interpolated_string_node_t *) current, node);
+ pm_interpolated_string_node_append(parser, (pm_interpolated_string_node_t *) current, node);
}
}
@@ -16845,12 +16493,12 @@ parse_pattern(pm_parser_t *parser, pm_constant_id_list_t *captures, uint8_t flag
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 (peek_at(parser, parser->start + location->start) == '_') return;
if (pm_constant_id_list_includes(captures, capture)) {
- pm_parser_err(parser, location->start, location->end, PM_ERR_PATTERN_CAPTURE_DUPLICATE);
+ pm_parser_err(parser, location->start, location->length, PM_ERR_PATTERN_CAPTURE_DUPLICATE);
} else {
- pm_constant_id_list_append(captures, capture);
+ pm_constant_id_list_append(parser->arena, captures, capture);
}
}
@@ -16864,7 +16512,7 @@ parse_pattern_constant_path(pm_parser_t *parser, pm_constant_id_list_t *captures
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);
+ node = UP(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
@@ -16885,7 +16533,7 @@ parse_pattern_constant_path(pm_parser_t *parser, pm_constant_id_list_t *captures
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);
+ expect1_opening(parser, PM_TOKEN_BRACKET_RIGHT, PM_ERR_PATTERN_TERM_BRACKET, &opening);
}
closing = parser->previous;
@@ -16897,7 +16545,7 @@ parse_pattern_constant_path(pm_parser_t *parser, pm_constant_id_list_t *captures
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);
+ expect1_opening(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_PATTERN_TERM_PAREN, &opening);
}
closing = parser->previous;
@@ -16906,7 +16554,7 @@ parse_pattern_constant_path(pm_parser_t *parser, pm_constant_id_list_t *captures
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);
+ return UP(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,
@@ -16917,15 +16565,15 @@ parse_pattern_constant_path(pm_parser_t *parser, pm_constant_id_list_t *captures
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;
+ if (pattern_node->constant == NULL && pattern_node->opening_loc.length == 0) {
+ PM_NODE_START_SET_NODE(pattern_node, node);
+ PM_NODE_LENGTH_SET_TOKEN(parser, pattern_node, &closing);
pattern_node->constant = node;
- pattern_node->opening_loc = PM_LOCATION_TOKEN_VALUE(&opening);
- pattern_node->closing_loc = PM_LOCATION_TOKEN_VALUE(&closing);
+ pattern_node->opening_loc = TOK2LOC(parser, &opening);
+ pattern_node->closing_loc = TOK2LOC(parser, &closing);
- return (pm_node_t *) pattern_node;
+ return UP(pattern_node);
}
break;
@@ -16933,15 +16581,15 @@ parse_pattern_constant_path(pm_parser_t *parser, pm_constant_id_list_t *captures
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;
+ if (pattern_node->constant == NULL && pattern_node->opening_loc.length == 0) {
+ PM_NODE_START_SET_NODE(pattern_node, node);
+ PM_NODE_LENGTH_SET_TOKEN(parser, pattern_node, &closing);
pattern_node->constant = node;
- pattern_node->opening_loc = PM_LOCATION_TOKEN_VALUE(&opening);
- pattern_node->closing_loc = PM_LOCATION_TOKEN_VALUE(&closing);
+ pattern_node->opening_loc = TOK2LOC(parser, &opening);
+ pattern_node->closing_loc = TOK2LOC(parser, &closing);
- return (pm_node_t *) pattern_node;
+ return UP(pattern_node);
}
break;
@@ -16949,15 +16597,15 @@ parse_pattern_constant_path(pm_parser_t *parser, pm_constant_id_list_t *captures
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;
+ if (pattern_node->constant == NULL && pattern_node->opening_loc.length == 0) {
+ PM_NODE_START_SET_NODE(pattern_node, node);
+ PM_NODE_LENGTH_SET_TOKEN(parser, pattern_node, &closing);
pattern_node->constant = node;
- pattern_node->opening_loc = PM_LOCATION_TOKEN_VALUE(&opening);
- pattern_node->closing_loc = PM_LOCATION_TOKEN_VALUE(&closing);
+ pattern_node->opening_loc = TOK2LOC(parser, &opening);
+ pattern_node->closing_loc = TOK2LOC(parser, &closing);
- return (pm_node_t *) pattern_node;
+ return UP(pattern_node);
}
break;
@@ -16970,8 +16618,8 @@ parse_pattern_constant_path(pm_parser_t *parser, pm_constant_id_list_t *captures
// 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;
+ pm_array_pattern_node_requireds_append(parser->arena, pattern_node, inner);
+ return UP(pattern_node);
}
/**
@@ -16987,21 +16635,20 @@ parse_pattern_rest(pm_parser_t *parser, pm_constant_id_list_t *captures) {
// 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);
+ 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, identifier.start, identifier.end, 0);
+ 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(&identifier));
- name = (pm_node_t *) pm_local_variable_target_node_create(
+ parse_pattern_capture(parser, captures, constant_id, &TOK2LOC(parser, &parser->previous));
+ name = UP(pm_local_variable_target_node_create(
parser,
- &PM_LOCATION_TOKEN_VALUE(&identifier),
+ &TOK2LOC(parser, &parser->previous),
constant_id,
(uint32_t) (depth == -1 ? 0 : depth)
- );
+ ));
}
// Finally we can return the created node.
@@ -17020,7 +16667,7 @@ parse_pattern_keyword_rest(pm_parser_t *parser, pm_constant_id_list_t *captures)
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);
+ return UP(pm_no_keywords_parameter_node_create(parser, &operator, &parser->previous));
}
if (accept1(parser, PM_TOKEN_IDENTIFIER)) {
@@ -17031,16 +16678,16 @@ parse_pattern_keyword_rest(pm_parser_t *parser, pm_constant_id_list_t *captures)
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(
+ parse_pattern_capture(parser, captures, constant_id, &TOK2LOC(parser, &parser->previous));
+ value = UP(pm_local_variable_target_node_create(
parser,
- &PM_LOCATION_TOKEN_VALUE(&parser->previous),
+ &TOK2LOC(parser, &parser->previous),
constant_id,
(uint32_t) (depth == -1 ? 0 : depth)
- );
+ ));
}
- return (pm_node_t *) pm_assoc_splat_node_create(parser, value, &operator);
+ return UP(pm_assoc_splat_node_create(parser, value, &operator));
}
/**
@@ -17077,22 +16724,24 @@ pm_slice_is_valid_local(const pm_parser_t *parser, const uint8_t *start, const u
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;
+ const uint8_t *start = parser->start + PM_LOCATION_START(value_loc);
+ const uint8_t *end = parser->start + PM_LOCATION_END(value_loc);
- pm_constant_id_t constant_id = pm_parser_constant_id_location(parser, value_loc->start, value_loc->end);
+ pm_constant_id_t constant_id = pm_parser_constant_id_raw(parser, start, end);
int depth = -1;
- if (pm_slice_is_valid_local(parser, value_loc->start, value_loc->end)) {
+ if (pm_slice_is_valid_local(parser, start, 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);
+ pm_parser_err(parser, PM_NODE_START(key), PM_NODE_LENGTH(key), 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 ((end > start) && ((end[-1] == '!') || (end[-1] == '?'))) {
+ PM_PARSER_ERR_FORMAT(parser, value_loc->start, value_loc->length, PM_ERR_INVALID_LOCAL_VARIABLE_WRITE, (int) (end - start), (const char *) start);
}
}
if (depth == -1) {
- pm_parser_local_add(parser, constant_id, value_loc->start, value_loc->end, 0);
+ pm_parser_local_add(parser, constant_id, start, end, 0);
}
parse_pattern_capture(parser, captures, constant_id, value_loc);
@@ -17103,7 +16752,7 @@ parse_pattern_hash_implicit_value(pm_parser_t *parser, pm_constant_id_list_t *ca
(uint32_t) (depth == -1 ? 0 : depth)
);
- return (pm_node_t *) pm_implicit_node_create(parser, (pm_node_t *) target);
+ return UP(pm_implicit_node_create(parser, UP(target)));
}
/**
@@ -17112,7 +16761,7 @@ parse_pattern_hash_implicit_value(pm_parser_t *parser, pm_constant_id_list_t *ca
*/
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) {
+ if (pm_static_literals_add(&parser->line_offsets, parser->start, parser->start_line, keys, node, true) != NULL) {
pm_parser_err_node(parser, node, PM_ERR_PATTERN_HASH_KEY_DUPLICATE);
}
}
@@ -17131,25 +16780,31 @@ parse_pattern_hash(pm_parser_t *parser, pm_constant_id_list_t *captures, pm_node
case PM_NO_KEYWORDS_PARAMETER_NODE:
rest = first_node;
break;
+ case PM_INTERPOLATED_SYMBOL_NODE:
case PM_SYMBOL_NODE: {
- if (pm_symbol_node_label_p(first_node)) {
- parse_pattern_hash_key(parser, &keys, first_node);
+ if (pm_symbol_node_label_p(parser, first_node)) {
+ if (PM_NODE_TYPE_P(first_node, PM_INTERPOLATED_SYMBOL_NODE)) {
+ pm_parser_err_node(parser, first_node, PM_ERR_PATTERN_HASH_KEY_INTERPOLATED);
+ } else {
+ 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);
+ if (PM_NODE_TYPE_P(first_node, PM_SYMBOL_NODE)) {
+ value = parse_pattern_hash_implicit_value(parser, captures, (pm_symbol_node_t *) first_node);
+ } else {
+ value = UP(pm_error_recovery_node_create(parser, PM_NODE_END(first_node), 0));
+ }
} 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);
+ pm_node_t *assoc = UP(pm_assoc_node_create(parser, first_node, NULL, value));
+ pm_node_list_append(parser->arena, &assocs, assoc);
break;
}
}
@@ -17161,11 +16816,10 @@ parse_pattern_hash(pm_parser_t *parser, pm_constant_id_list_t *captures, pm_node
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_t *value = UP(pm_error_recovery_node_create(parser, PM_NODE_START(first_node), PM_NODE_LENGTH(first_node)));
+ pm_node_t *assoc = UP(pm_assoc_node_create(parser, first_node, NULL, value));
- pm_node_list_append(&assocs, assoc);
+ pm_node_list_append(parser->arena, &assocs, assoc);
break;
}
}
@@ -17189,7 +16843,7 @@ parse_pattern_hash(pm_parser_t *parser, pm_constant_id_list_t *captures, pm_node
rest = assoc;
} else {
pm_parser_err_node(parser, assoc, PM_ERR_PATTERN_EXPRESSION_AFTER_REST);
- pm_node_list_append(&assocs, assoc);
+ pm_node_list_append(parser->arena, &assocs, assoc);
}
} else {
pm_node_t *key;
@@ -17199,36 +16853,43 @@ parse_pattern_hash(pm_parser_t *parser, pm_constant_id_list_t *captures, pm_node
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)) {
+ } else if (!pm_symbol_node_label_p(parser, key)) {
pm_parser_err_node(parser, key, PM_ERR_PATTERN_LABEL_AFTER_COMMA);
}
+ } else if (accept1(parser, PM_TOKEN_LABEL)) {
+ key = UP(pm_symbol_node_label_create(parser, &parser->previous));
} else {
expect1(parser, PM_TOKEN_LABEL, PM_ERR_PATTERN_LABEL_AFTER_COMMA);
- key = (pm_node_t *) pm_symbol_node_label_create(parser, &parser->previous);
+
+ pm_token_t label = { .type = PM_TOKEN_LABEL, .start = parser->previous.end, .end = parser->previous.end };
+ key = UP(pm_symbol_node_create(parser, NULL, &label, NULL));
}
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);
+ if (PM_NODE_TYPE_P(key, PM_SYMBOL_NODE)) {
+ value = parse_pattern_hash_implicit_value(parser, captures, (pm_symbol_node_t *) key);
+ } else {
+ value = UP(pm_error_recovery_node_create(parser, PM_NODE_END(key), 0));
+ }
} 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);
+ pm_node_t *assoc = UP(pm_assoc_node_create(parser, key, NULL, value));
if (rest != NULL) {
pm_parser_err_node(parser, assoc, PM_ERR_PATTERN_EXPRESSION_AFTER_REST);
}
- pm_node_list_append(&assocs, assoc);
+ pm_node_list_append(parser->arena, &assocs, assoc);
}
}
pm_hash_pattern_node_t *node = pm_hash_pattern_node_node_list_create(parser, &assocs, rest);
- xfree(assocs.nodes);
+ // assocs.nodes is arena-allocated; no explicit free needed.
pm_static_literals_free(&keys);
return node;
@@ -17250,13 +16911,13 @@ parse_pattern_primitive(pm_parser_t *parser, pm_constant_id_list_t *captures, pm
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(
+ parse_pattern_capture(parser, captures, constant_id, &TOK2LOC(parser, &parser->previous));
+ return UP(pm_local_variable_target_node_create(
parser,
- &PM_LOCATION_TOKEN_VALUE(&parser->previous),
+ &TOK2LOC(parser, &parser->previous),
constant_id,
(uint32_t) (depth == -1 ? 0 : depth)
- );
+ ));
}
case PM_TOKEN_BRACKET_LEFT_ARRAY: {
pm_token_t opening = parser->current;
@@ -17265,7 +16926,7 @@ parse_pattern_primitive(pm_parser_t *parser, pm_constant_id_list_t *captures, pm
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);
+ return UP(pm_array_pattern_node_empty_create(parser, &opening, &parser->previous));
}
// Otherwise, we'll parse the inner pattern, then deal with it depending
@@ -17273,34 +16934,34 @@ parse_pattern_primitive(pm_parser_t *parser, pm_constant_id_list_t *captures, pm
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);
+ expect1_opening(parser, PM_TOKEN_BRACKET_RIGHT, PM_ERR_PATTERN_TERM_BRACKET, &opening);
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;
+ if (pattern_node->opening_loc.length == 0) {
+ PM_NODE_START_SET_TOKEN(parser, pattern_node, &opening);
+ PM_NODE_LENGTH_SET_TOKEN(parser, pattern_node, &closing);
- pattern_node->opening_loc = PM_LOCATION_TOKEN_VALUE(&opening);
- pattern_node->closing_loc = PM_LOCATION_TOKEN_VALUE(&closing);
+ pattern_node->opening_loc = TOK2LOC(parser, &opening);
+ pattern_node->closing_loc = TOK2LOC(parser, &closing);
- return (pm_node_t *) pattern_node;
+ return UP(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;
+ if (pattern_node->opening_loc.length == 0) {
+ PM_NODE_START_SET_TOKEN(parser, pattern_node, &opening);
+ PM_NODE_LENGTH_SET_TOKEN(parser, pattern_node, &closing);
- pattern_node->opening_loc = PM_LOCATION_TOKEN_VALUE(&opening);
- pattern_node->closing_loc = PM_LOCATION_TOKEN_VALUE(&closing);
+ pattern_node->opening_loc = TOK2LOC(parser, &opening);
+ pattern_node->closing_loc = TOK2LOC(parser, &closing);
- return (pm_node_t *) pattern_node;
+ return UP(pattern_node);
}
break;
@@ -17310,8 +16971,8 @@ parse_pattern_primitive(pm_parser_t *parser, pm_constant_id_list_t *captures, pm
}
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;
+ pm_array_pattern_node_requireds_append(parser->arena, node, inner);
+ return UP(node);
}
case PM_TOKEN_BRACE_LEFT: {
bool previous_pattern_matching_newlines = parser->pattern_matching_newlines;
@@ -17331,19 +16992,19 @@ parse_pattern_primitive(pm_parser_t *parser, pm_constant_id_list_t *captures, pm
switch (parser->current.type) {
case PM_TOKEN_LABEL:
parser_lex(parser);
- first_node = (pm_node_t *) pm_symbol_node_label_create(parser, &parser->previous);
+ first_node = UP(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));
+ first_node = parse_expression(parser, PM_BINDING_POWER_MAX, PM_PARSE_ACCEPTS_DO_BLOCK | PM_PARSE_ACCEPTS_LABEL, 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));
+ PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_PATTERN_HASH_KEY, pm_token_str(parser->current.type));
parser_lex(parser);
- first_node = (pm_node_t *) pm_missing_node_create(parser, parser->previous.start, parser->previous.end);
+ first_node = UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &parser->previous), PM_TOKEN_LENGTH(&parser->previous)));
break;
}
}
@@ -17351,18 +17012,18 @@ parse_pattern_primitive(pm_parser_t *parser, pm_constant_id_list_t *captures, pm
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);
+ expect1_opening(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_PATTERN_TERM_BRACE, &opening);
pm_token_t closing = parser->previous;
- node->base.location.start = opening.start;
- node->base.location.end = closing.end;
+ PM_NODE_START_SET_TOKEN(parser, node, &opening);
+ PM_NODE_LENGTH_SET_TOKEN(parser, node, &closing);
- node->opening_loc = PM_LOCATION_TOKEN_VALUE(&opening);
- node->closing_loc = PM_LOCATION_TOKEN_VALUE(&closing);
+ node->opening_loc = TOK2LOC(parser, &opening);
+ node->closing_loc = TOK2LOC(parser, &closing);
}
parser->pattern_matching_newlines = previous_pattern_matching_newlines;
- return (pm_node_t *) node;
+ return UP(node);
}
case PM_TOKEN_UDOT_DOT:
case PM_TOKEN_UDOT_DOT_DOT: {
@@ -17373,28 +17034,26 @@ parse_pattern_primitive(pm_parser_t *parser, pm_constant_id_list_t *captures, pm
// 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);
+ pm_node_t *right = parse_expression(parser, PM_BINDING_POWER_MAX, PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_PATTERN_EXPRESSION_AFTER_RANGE, (uint16_t) (depth + 1));
+ return UP(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);
+ pm_node_t *right = UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &operator), PM_TOKEN_LENGTH(&operator)));
+ return UP(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));
+ pm_node_t *node = parse_expression(parser, PM_BINDING_POWER_MAX, PM_PARSE_ACCEPTS_LABEL | PM_PARSE_ACCEPTS_DO_BLOCK, 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;
+ if (pm_symbol_node_label_p(parser, node)) return node;
// Call nodes (arithmetic operations) are not allowed in patterns
if (PM_NODE_TYPE(node) == PM_CALL_NODE) {
pm_parser_err_node(parser, node, diag_id);
- pm_missing_node_t *missing_node = pm_missing_node_create(parser, node->location.start, node->location.end);
- pm_node_destroy(parser, node);
- return (pm_node_t *) missing_node;
+ return UP(pm_error_recovery_node_create_unexpected(parser, node));
}
// Now that we have a primitive, we need to check if it's part of a range.
@@ -17406,11 +17065,11 @@ parse_pattern_primitive(pm_parser_t *parser, pm_constant_id_list_t *captures, pm
// 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);
+ pm_node_t *right = parse_expression(parser, PM_BINDING_POWER_MAX, PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_PATTERN_EXPRESSION_AFTER_RANGE, (uint16_t) (depth + 1));
+ return UP(pm_range_node_create(parser, node, &operator, right));
}
default:
- return (pm_node_t *) pm_range_node_create(parser, node, &operator, NULL);
+ return UP(pm_range_node_create(parser, node, &operator, NULL));
}
}
@@ -17425,44 +17084,44 @@ parse_pattern_primitive(pm_parser_t *parser, pm_constant_id_list_t *captures, pm
switch (parser->current.type) {
case PM_TOKEN_IDENTIFIER: {
parser_lex(parser);
- pm_node_t *variable = (pm_node_t *) parse_variable(parser);
+ pm_node_t *variable = UP(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);
+ PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, &parser->previous, PM_ERR_NO_LOCAL_VARIABLE);
+ variable = UP(pm_local_variable_read_node_missing_create(parser, &parser->previous, 0));
}
- return (pm_node_t *) pm_pinned_variable_node_create(parser, &operator, variable);
+ return UP(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);
+ pm_node_t *variable = UP(pm_instance_variable_read_node_create(parser, &parser->previous));
- return (pm_node_t *) pm_pinned_variable_node_create(parser, &operator, variable);
+ return UP(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);
+ pm_node_t *variable = UP(pm_class_variable_read_node_create(parser, &parser->previous));
- return (pm_node_t *) pm_pinned_variable_node_create(parser, &operator, variable);
+ return UP(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);
+ pm_node_t *variable = UP(pm_global_variable_read_node_create(parser, &parser->previous));
- return (pm_node_t *) pm_pinned_variable_node_create(parser, &operator, variable);
+ return UP(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);
+ pm_node_t *variable = UP(pm_numbered_reference_read_node_create(parser, &parser->previous));
- return (pm_node_t *) pm_pinned_variable_node_create(parser, &operator, variable);
+ return UP(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);
+ pm_node_t *variable = UP(pm_back_reference_read_node_create(parser, &parser->previous));
- return (pm_node_t *) pm_pinned_variable_node_create(parser, &operator, variable);
+ return UP(pm_pinned_variable_node_create(parser, &operator, variable));
}
case PM_TOKEN_PARENTHESIS_LEFT: {
bool previous_pattern_matching_newlines = parser->pattern_matching_newlines;
@@ -17471,19 +17130,19 @@ parse_pattern_primitive(pm_parser_t *parser, pm_constant_id_list_t *captures, pm
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));
+ pm_node_t *expression = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION, PM_PARSE_ACCEPTS_DO_BLOCK | PM_PARSE_ACCEPTS_COMMAND_CALL, 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);
+ expect1_opening(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_PATTERN_TERM_PAREN, &lparen);
+ return UP(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);
+ pm_node_t *variable = UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &operator), PM_TOKEN_LENGTH(&operator)));
+ return UP(pm_pinned_variable_node_create(parser, &operator, variable));
}
}
}
@@ -17494,31 +17153,56 @@ parse_pattern_primitive(pm_parser_t *parser, pm_constant_id_list_t *captures, pm
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));
+ return parse_pattern_constant_path(parser, captures, UP(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);
+ pm_node_t *node = UP(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);
+ return UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current)));
+ }
+}
+
+static bool
+parse_pattern_alternation_error_each(const pm_node_t *node, void *data) {
+ switch (PM_NODE_TYPE(node)) {
+ case PM_LOCAL_VARIABLE_TARGET_NODE: {
+ pm_parser_t *parser = (pm_parser_t *) data;
+ pm_parser_err(parser, PM_NODE_START(node), PM_NODE_LENGTH(node), PM_ERR_PATTERN_CAPTURE_IN_ALTERNATIVE);
+ return false;
+ }
+ default:
+ return true;
}
}
/**
+ * When we get here, we know that we already have a syntax error, because we
+ * know we have captured a variable and that we are in an alternation.
+ */
+static void
+parse_pattern_alternation_error(pm_parser_t *parser, const pm_node_t *node) {
+ pm_visit_node(node, parse_pattern_alternation_error_each, parser);
+}
+
+/**
* 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;
+ bool alternation = false;
- while ((node == NULL) || accept1(parser, PM_TOKEN_PIPE)) {
- pm_token_t operator = parser->previous;
+ while ((node == NULL) || (alternation = accept1(parser, PM_TOKEN_PIPE))) {
+ if (alternation && !PM_NODE_TYPE_P(node, PM_ALTERNATION_PATTERN_NODE) && captures->size) {
+ parse_pattern_alternation_error(parser, node);
+ }
switch (parser->current.type) {
case PM_TOKEN_IDENTIFIER:
@@ -17530,41 +17214,47 @@ parse_pattern_primitives(pm_parser_t *parser, pm_constant_id_list_t *captures, p
case PM_TOKEN_UDOT_DOT:
case PM_TOKEN_UDOT_DOT_DOT:
case PM_CASE_PRIMITIVE: {
- if (node == NULL) {
+ if (!alternation) {
node = parse_pattern_primitive(parser, captures, diag_id, (uint16_t) (depth + 1));
} else {
+ pm_token_t operator = parser->previous;
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);
+
+ if (captures->size) parse_pattern_alternation_error(parser, right);
+ node = UP(pm_alternation_pattern_node_create(parser, node, right, &operator));
}
break;
}
case PM_TOKEN_PARENTHESIS_LEFT:
case PM_TOKEN_PARENTHESIS_LEFT_PARENTHESES: {
+ pm_token_t operator = parser->previous;
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, 0);
+ expect1_opening(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_PATTERN_TERM_PAREN, &opening);
+ pm_node_t *right = UP(pm_parentheses_node_create(parser, &opening, body, &parser->previous, 0));
- if (node == NULL) {
+ if (!alternation) {
node = right;
} else {
- node = (pm_node_t *) pm_alternation_pattern_node_create(parser, node, right, &operator);
+ if (captures->size) parse_pattern_alternation_error(parser, right);
+ node = UP(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);
+ pm_node_t *right = UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current)));
- if (node == NULL) {
+ if (!alternation) {
node = right;
} else {
- node = (pm_node_t *) pm_alternation_pattern_node_create(parser, node, right, &operator);
+ if (captures->size) parse_pattern_alternation_error(parser, right);
+ node = UP(pm_alternation_pattern_node_create(parser, node, right, &parser->previous));
}
break;
@@ -17585,15 +17275,15 @@ parse_pattern_primitives(pm_parser_t *parser, pm_constant_id_list_t *captures, p
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));
+ parse_pattern_capture(parser, captures, constant_id, &TOK2LOC(parser, &parser->previous));
pm_local_variable_target_node_t *target = pm_local_variable_target_node_create(
parser,
- &PM_LOCATION_TOKEN_VALUE(&parser->previous),
+ &TOK2LOC(parser, &parser->previous),
constant_id,
(uint32_t) (depth == -1 ? 0 : depth)
);
- node = (pm_node_t *) pm_capture_pattern_node_create(parser, node, target, &operator);
+ node = UP(pm_capture_pattern_node_create(parser, node, target, &operator));
}
return node;
@@ -17612,8 +17302,8 @@ parse_pattern(pm_parser_t *parser, pm_constant_id_list_t *captures, uint8_t flag
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));
+ pm_node_t *key = UP(pm_symbol_node_label_create(parser, &parser->previous));
+ node = UP(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);
@@ -17623,7 +17313,7 @@ parse_pattern(pm_parser_t *parser, pm_constant_id_list_t *captures, uint8_t flag
}
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));
+ node = UP(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);
@@ -17636,8 +17326,8 @@ parse_pattern(pm_parser_t *parser, pm_constant_id_list_t *captures, uint8_t flag
// 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 (pm_symbol_node_label_p(parser, node)) {
+ node = UP(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);
@@ -17652,7 +17342,7 @@ parse_pattern(pm_parser_t *parser, pm_constant_id_list_t *captures, uint8_t flag
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);
+ node = UP(parse_pattern_rest(parser, captures));
leading_rest = true;
break;
}
@@ -17665,8 +17355,8 @@ parse_pattern(pm_parser_t *parser, pm_constant_id_list_t *captures, uint8_t flag
// 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 (pm_symbol_node_label_p(parser, node)) {
+ return UP(parse_pattern_hash(parser, captures, node, (uint16_t) (depth + 1)));
}
if ((flags & PM_PARSE_PATTERN_MULTI) && match1(parser, PM_TOKEN_COMMA)) {
@@ -17674,20 +17364,20 @@ parse_pattern(pm_parser_t *parser, pm_constant_id_list_t *captures, uint8_t flag
// 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);
+ pm_node_list_append(parser->arena, &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 (match7(parser, PM_TOKEN_KEYWORD_THEN, PM_TOKEN_BRACE_RIGHT, PM_TOKEN_BRACKET_RIGHT, PM_TOKEN_PARENTHESIS_RIGHT, PM_TOKEN_SEMICOLON, PM_TOKEN_KEYWORD_AND, PM_TOKEN_KEYWORD_OR)) {
- node = (pm_node_t *) pm_implicit_rest_node_create(parser, &parser->previous);
- pm_node_list_append(&nodes, node);
+ node = UP(pm_implicit_rest_node_create(parser, &parser->previous));
+ pm_node_list_append(parser->arena, &nodes, node);
trailing_rest = true;
break;
}
if (accept1(parser, PM_TOKEN_USTAR)) {
- node = (pm_node_t *) parse_pattern_rest(parser, captures);
+ node = UP(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,
@@ -17701,7 +17391,7 @@ parse_pattern(pm_parser_t *parser, pm_constant_id_list_t *captures, uint8_t flag
node = parse_pattern_primitives(parser, captures, NULL, PM_ERR_PATTERN_EXPRESSION_AFTER_COMMA, (uint16_t) (depth + 1));
}
- pm_node_list_append(&nodes, node);
+ pm_node_list_append(parser->arena, &nodes, node);
}
// If the first pattern and the last pattern are rest patterns, then we
@@ -17709,24 +17399,24 @@ parse_pattern(pm_parser_t *parser, pm_constant_id_list_t *captures, uint8_t flag
// 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);
+ node = UP(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);
+ node = UP(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);
+ // nodes.nodes is arena-allocated; no explicit free needed.
} 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);
+ node = UP(pm_array_pattern_node_rest_create(parser, node));
}
return node;
@@ -17737,29 +17427,33 @@ parse_pattern(pm_parser_t *parser, pm_constant_id_list_t *captures, uint8_t flag
* from its start bounds. If it's a compound node, then we will recursively
* apply this function to its value.
*/
-static inline void
+static PRISM_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->base.location.length++;
cast->value.negative = true;
break;
}
case PM_FLOAT_NODE: {
pm_float_node_t *cast = (pm_float_node_t *) node;
cast->base.location.start--;
+ cast->base.location.length++;
cast->value = -cast->value;
break;
}
case PM_RATIONAL_NODE: {
pm_rational_node_t *cast = (pm_rational_node_t *) node;
cast->base.location.start--;
+ cast->base.location.length++;
cast->numerator.negative = true;
break;
}
case PM_IMAGINARY_NODE:
node->location.start--;
+ node->location.length++;
parse_negative_numeric(((pm_imaginary_node_t *) node)->numeric);
break;
default:
@@ -17777,22 +17471,22 @@ 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));
+ PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->previous, diag_id, pm_token_str(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));
+ PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, diag_id, pm_token_str(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]);
+ const char *human = (parser->current.type == PM_TOKEN_EOF ? "end-of-input" : pm_token_str(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));
+ PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, diag_id, pm_token_str(parser->current.type));
break;
}
default:
@@ -17872,6 +17566,7 @@ parse_retry(pm_parser_t *parser, const pm_node_t *node) {
case PM_CONTEXT_BEGIN:
case PM_CONTEXT_BLOCK_BRACES:
case PM_CONTEXT_BLOCK_KEYWORDS:
+ case PM_CONTEXT_BLOCK_PARAMETERS:
case PM_CONTEXT_CASE_IN:
case PM_CONTEXT_CASE_WHEN:
case PM_CONTEXT_DEFAULT_PARAMS:
@@ -17952,6 +17647,7 @@ parse_yield(pm_parser_t *parser, const pm_node_t *node) {
case PM_CONTEXT_BLOCK_KEYWORDS:
case PM_CONTEXT_BLOCK_ELSE:
case PM_CONTEXT_BLOCK_ENSURE:
+ case PM_CONTEXT_BLOCK_PARAMETERS:
case PM_CONTEXT_BLOCK_RESCUE:
case PM_CONTEXT_CASE_IN:
case PM_CONTEXT_CASE_WHEN:
@@ -17988,67 +17684,1383 @@ parse_yield(pm_parser_t *parser, const pm_node_t *node) {
}
/**
- * This struct is used to pass information between the regular expression parser
- * and the error callback.
+ * Determine if a given call node looks like a "command", which means it has
+ * arguments but does not have parentheses.
*/
-typedef struct {
- /** The parser that we are parsing the regular expression for. */
- pm_parser_t *parser;
+static PRISM_INLINE bool
+pm_call_node_command_p(const pm_call_node_t *node) {
+ return (
+ (node->opening_loc.length == 0) &&
+ (node->block == NULL || PM_NODE_TYPE_P(node->block, PM_BLOCK_ARGUMENT_NODE)) &&
+ (node->arguments != NULL || node->block != NULL)
+ );
+}
- /** The start of the regular expression. */
- const uint8_t *start;
+/**
+ * Returns true if the given node is a command-style call (a method call without
+ * parentheses that has arguments), excluding operator calls (e.g., a + b) which
+ * satisfy the same structural criteria but are not commands.
+ */
+static bool
+pm_command_call_value_p(const pm_node_t *node) {
+ switch (PM_NODE_TYPE(node)) {
+ case PM_CALL_NODE: {
+ const pm_call_node_t *call = (const pm_call_node_t *) node;
- /** The end of the regular expression. */
- const uint8_t *end;
+ // Command-style calls (e.g., foo bar, obj.foo bar).
+ // Attribute writes (e.g., a.b = 1) are not commands.
+ if (pm_call_node_command_p(call) && !PM_NODE_FLAG_P(node, PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE) && (call->receiver == NULL || call->call_operator_loc.length > 0)) {
+ return true;
+ }
- /**
- * 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;
+ // A `!` or `not` prefix wrapping a command call (e.g.,
+ // `!foo bar`, `not foo bar`) is also a command-call value.
+ if (call->receiver != NULL && call->arguments == NULL && call->opening_loc.length == 0 && call->call_operator_loc.length == 0) {
+ return pm_command_call_value_p(call->receiver);
+ }
+
+ return false;
+ }
+ case PM_SUPER_NODE: {
+ const pm_super_node_t *cast = (const pm_super_node_t *) node;
+ return cast->lparen_loc.length == 0 && (cast->arguments != NULL || cast->block != NULL);
+ }
+ case PM_YIELD_NODE: {
+ const pm_yield_node_t *cast = (const pm_yield_node_t *) node;
+ return cast->lparen_loc.length == 0 && cast->arguments != NULL;
+ }
+ case PM_RESCUE_MODIFIER_NODE:
+ return pm_command_call_value_p(((const pm_rescue_modifier_node_t *) node)->expression);
+ case PM_DEF_NODE: {
+ const pm_def_node_t *cast = (const pm_def_node_t *) node;
+ if (cast->equal_loc.length > 0 && cast->body != NULL) {
+ const pm_node_t *body = cast->body;
+ if (PM_NODE_TYPE_P(body, PM_STATEMENTS_NODE)) {
+ body = ((const pm_statements_node_t *) body)->body.nodes[((const pm_statements_node_t *) body)->body.size - 1];
+ }
+ return pm_command_call_value_p(body);
+ }
+ return false;
+ }
+ default:
+ return false;
+ }
+}
/**
- * This callback is called when the regular expression parser encounters a
- * syntax error.
+ * Returns true if the given node is a block call: a command
+ * with a do-block, or any call chained (via `.`, `::`, `&.`) from such a node.
+ * Block calls can only be followed by call chaining, composition (and/or), and
+ * modifier operators.
*/
-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;
+static bool
+pm_block_call_p(const pm_node_t *node) {
+ while (PM_NODE_TYPE_P(node, PM_CALL_NODE)) {
+ const pm_call_node_t *call = (const pm_call_node_t *) node;
+ if (call->opening_loc.length > 0) return false;
+
+ // Root: command with do-block (e.g., `foo bar do end`).
+ if (call->arguments != NULL && call->block != NULL && PM_NODE_TYPE_P(call->block, PM_BLOCK_NODE)) {
+ return true;
+ }
+
+ // Walk up the receiver chain (e.g., `foo bar do end.baz`).
+ if (call->call_operator_loc.length > 0 && call->receiver != NULL) {
+ node = call->receiver;
+ continue;
+ }
+
+ return false;
+ }
+
+ return false;
+}
+
+/**
+ * Parse a case expression (the `case` keyword). This handles both case-when and
+ * case-in (pattern matching) forms.
+ */
+static pm_node_t *
+parse_case(pm_parser_t *parser, uint8_t flags, uint16_t depth) {
+ size_t opening_newline_index = token_newline_index(parser);
+ parser_lex(parser);
+
+ pm_token_t case_keyword = parser->previous;
+ pm_node_t *predicate = NULL;
- if (callback_data->shared) {
- location = (pm_location_t) { .start = start, .end = end };
+ 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 {
- location = (pm_location_t) { .start = callback_data->start, .end = callback_data->end };
+ predicate = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION, (uint8_t) ((flags & PM_PARSE_ACCEPTS_DO_BLOCK) | PM_PARSE_ACCEPTS_COMMAND_CALL), PM_ERR_CASE_EXPRESSION_AFTER_CASE, (uint16_t) (depth + 1));
+ while (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON));
}
- PM_PARSER_ERR_FORMAT(callback_data->parser, location.start, location.end, PM_ERR_REGEXP_PARSE_ERROR, message);
+ 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_parser_err_token(parser, &case_keyword, PM_ERR_CASE_MISSING_CONDITIONS);
+ return UP(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_node_t *node;
+
+ if (match1(parser, PM_TOKEN_KEYWORD_WHEN)) {
+ pm_case_node_t *case_node = pm_case_node_create(parser, &case_keyword, predicate, NULL);
+ 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, flags & PM_PARSE_ACCEPTS_DO_BLOCK, 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(parser->arena, when_node, UP(splat_node));
+
+ if (PM_NODE_TYPE_P(expression, PM_ERROR_RECOVERY_NODE)) break;
+ } else {
+ pm_node_t *condition = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, flags & PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_CASE_EXPRESSION_AFTER_WHEN, (uint16_t) (depth + 1));
+ pm_when_node_conditions_append(parser->arena, 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_ERROR_RECOVERY_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(parser, when_node, &parser->previous);
+ }
+ } else {
+ expect1(parser, PM_TOKEN_KEYWORD_THEN, PM_ERR_EXPECT_WHEN_DELIMITER);
+ pm_when_node_then_keyword_loc_set(parser, 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(parser->arena, case_node, UP(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 = UP(case_node);
+ } else {
+ pm_case_match_node_t *case_node = pm_case_match_node_create(parser, &case_keyword, predicate);
+
+ /* 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;
+
+ /* 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, (uint8_t) ((flags & PM_PARSE_ACCEPTS_DO_BLOCK) | PM_PARSE_ACCEPTS_COMMAND_CALL), PM_ERR_CONDITIONAL_IF_PREDICATE, (uint16_t) (depth + 1));
+ pattern = UP(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, (uint8_t) ((flags & PM_PARSE_ACCEPTS_DO_BLOCK) | PM_PARSE_ACCEPTS_COMMAND_CALL), PM_ERR_CONDITIONAL_UNLESS_PREDICATE, (uint16_t) (depth + 1));
+ pattern = UP(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 = { 0 };
+ if (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
+ if (accept1(parser, PM_TOKEN_KEYWORD_THEN)) {
+ then_keyword = parser->previous;
+ }
+ } 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 = UP(pm_in_node_create(parser, pattern, statements, &in_keyword, NTOK2PTR(then_keyword)));
+ pm_case_match_node_condition_append(parser->arena, 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 = UP(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_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CASE_TERM, &case_keyword);
+
+ if (PM_NODE_TYPE_P(node, PM_CASE_NODE)) {
+ pm_case_node_end_keyword_loc_set(parser, (pm_case_node_t *) node, &parser->previous);
+ } else {
+ pm_case_match_node_end_keyword_loc_set(parser, (pm_case_match_node_t *) node, &parser->previous);
+ }
+
+ pop_block_exits(parser, previous_block_exits);
+ return node;
}
/**
- * Parse the errors for the regular expression and add them to the parser.
+ * Parse a class definition expression (the `class` keyword). This handles both
+ * regular class definitions and singleton class definitions (`class << expr`).
*/
-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
- };
+static pm_node_t *
+parse_class(pm_parser_t *parser, uint8_t flags, uint16_t depth) {
+ 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, (uint8_t) ((flags & PM_PARSE_ACCEPTS_DO_BLOCK) | PM_PARSE_ACCEPTS_COMMAND_CALL), 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_str(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 = UP(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 = UP(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_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CLASS_TERM, &class_keyword);
+
+ 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);
+ return UP(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, flags & PM_PARSE_ACCEPTS_DO_BLOCK, 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 = { 0 };
+ 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, (uint8_t) ((flags & PM_PARSE_ACCEPTS_DO_BLOCK) | PM_PARSE_ACCEPTS_COMMAND_CALL), PM_ERR_CLASS_SUPERCLASS, (uint16_t) (depth + 1));
+ } else {
+ superclass = NULL;
+ }
+
+ pm_parser_scope_push(parser, true);
+
+ if (inheritance_operator.start != NULL) {
+ 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 = UP(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 = UP(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_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CLASS_TERM, &class_keyword);
+
+ 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);
+ if (!PM_NODE_TYPE_P(constant_path, PM_ERROR_RECOVERY_NODE)) {
+ constant_path = UP(pm_error_recovery_node_create_unexpected(parser, constant_path));
+ }
+ }
+
+ pop_block_exits(parser, previous_block_exits);
+ return UP(pm_class_node_create(parser, &locals, &class_keyword, constant_path, &name, NTOK2PTR(inheritance_operator), superclass, statements, &parser->previous));
+}
+
+/**
+ * Parse a method definition expression (the `def` keyword).
+ */
+static pm_node_t *
+parse_def(pm_parser_t *parser, pm_binding_power_t binding_power, uint8_t flags, 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 def_keyword = parser->current;
+ size_t opening_newline_index = token_newline_index(parser);
+
+ pm_node_t *receiver = NULL;
+ pm_token_t operator = { 0 };
+ 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);
+
+ /* This will be false if the method name is not a valid identifier but could
+ * be followed by an operator. */
+ bool valid_name = true;
+
+ 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, PM_TOKEN_START(parser, &parser->previous), PM_TOKEN_LENGTH(&parser->previous));
+ pm_parser_scope_push(parser, true);
+
+ name = parser->previous;
+ }
+
+ break;
+ }
+ case PM_TOKEN_INSTANCE_VARIABLE:
+ case PM_TOKEN_CLASS_VARIABLE:
+ case PM_TOKEN_GLOBAL_VARIABLE:
+ valid_name = false;
+ PRISM_FALLTHROUGH
+ case PM_TOKEN_CONSTANT:
+ 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 = UP(pm_constant_read_node_create(parser, &identifier));
+ break;
+ case PM_TOKEN_INSTANCE_VARIABLE:
+ receiver = UP(pm_instance_variable_read_node_create(parser, &identifier));
+ break;
+ case PM_TOKEN_CLASS_VARIABLE:
+ receiver = UP(pm_class_variable_read_node_create(parser, &identifier));
+ break;
+ case PM_TOKEN_GLOBAL_VARIABLE:
+ receiver = UP(pm_global_variable_read_node_create(parser, &identifier));
+ break;
+ case PM_TOKEN_KEYWORD_NIL:
+ receiver = UP(pm_nil_node_create(parser, &identifier));
+ break;
+ case PM_TOKEN_KEYWORD_SELF:
+ receiver = UP(pm_self_node_create(parser, &identifier));
+ break;
+ case PM_TOKEN_KEYWORD_TRUE:
+ receiver = UP(pm_true_node_create(parser, &identifier));
+ break;
+ case PM_TOKEN_KEYWORD_FALSE:
+ receiver = UP(pm_false_node_create(parser, &identifier));
+ break;
+ case PM_TOKEN_KEYWORD___FILE__:
+ receiver = UP(pm_source_file_node_create(parser, &identifier));
+ break;
+ case PM_TOKEN_KEYWORD___LINE__:
+ receiver = UP(pm_source_line_node_create(parser, &identifier));
+ break;
+ case PM_TOKEN_KEYWORD___ENCODING__:
+ receiver = UP(pm_source_encoding_node_create(parser, &identifier));
+ break;
+ default:
+ break;
+ }
+
+ name = parse_method_definition_name(parser);
+ } else {
+ if (!valid_name) {
+ PM_PARSER_ERR_TOKEN_FORMAT(parser, &identifier, PM_ERR_DEF_NAME, pm_token_str(identifier.type));
+ }
+
+ 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, (uint8_t) ((flags & PM_PARSE_ACCEPTS_DO_BLOCK) | PM_PARSE_ACCEPTS_COMMAND_CALL), 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 = UP(pm_parentheses_node_create(parser, &lparen, expression, &rparen, 0));
+
+ /* 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 = { 0 };
+ pm_token_t rparen = { 0 };
+ pm_parameters_node_t *params;
+
+ bool accept_endless_def = true;
+ 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 {
+ /* https://bugs.ruby-lang.org/issues/19107 */
+ bool allow_trailing_comma = parser->version >= PM_OPTIONS_VERSION_CRUBY_4_1;
+ params = parse_parameters(
+ parser,
+ PM_BINDING_POWER_DEFINED,
+ true,
+ allow_trailing_comma,
+ true,
+ true,
+ false,
+ PM_ERR_ARGUMENT_NO_FORWARDING_ELLIPSES,
+ (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_str(parser->current.type));
+ parser->previous.start = parser->previous.end;
+ parser->previous.type = 0;
+ }
+
+ 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);
+ }
+
+ params = parse_parameters(
+ parser,
+ PM_BINDING_POWER_DEFINED,
+ false,
+ false,
+ true,
+ true,
+ false,
+ PM_ERR_ARGUMENT_NO_FORWARDING_ELLIPSES,
+ (uint16_t) (depth + 1)
+ );
+
+ /* Reject `def * = 1` and similar. We have to specifically check for
+ * them because they create ambiguity with optional arguments. */
+ accept_endless_def = false;
+
+ context_pop(parser);
+ break;
+ }
+ default: {
+ params = NULL;
+ context_pop(parser);
+ break;
+ }
+ }
+
+ pm_node_t *statements = NULL;
+ pm_token_t equal = { 0 };
+ pm_token_t end_keyword = { 0 };
+
+ if (accept1(parser, PM_TOKEN_EQUAL)) {
+ if (token_is_setter_name(&name)) {
+ pm_parser_err_token(parser, &name, PM_ERR_DEF_ENDLESS_SETTER);
+ }
+ if (!accept_endless_def) {
+ pm_parser_err_previous(parser, PM_ERR_DEF_ENDLESS_PARAMETERS);
+ }
+ if (
+ parser->current_context->context == PM_CONTEXT_DEFAULT_PARAMS &&
+ parser->current_context->prev->context == PM_CONTEXT_BLOCK_PARAMETERS
+ ) {
+ PM_PARSER_ERR_FORMAT(parser, PM_TOKEN_START(parser, &def_keyword), PM_TOKENS_LENGTH(&def_keyword, &parser->previous), PM_ERR_UNEXPECTED_PARAMETER_DEFAULT_VALUE, "endless method definition");
+ }
+ equal = parser->previous;
+
+ context_push(parser, PM_CONTEXT_DEF);
+ pm_do_loop_stack_push(parser, false);
+ statements = UP(pm_statements_node_create(parser));
+
+ uint8_t allow_flags;
+ if (parser->version >= PM_OPTIONS_VERSION_CRUBY_4_0) {
+ allow_flags = flags & PM_PARSE_ACCEPTS_COMMAND_CALL;
+ } else {
+ /* Allow `def foo = puts "Hello"` but not
+ * `private def foo = puts "Hello"` */
+ allow_flags = (binding_power == PM_BINDING_POWER_ASSIGNMENT || binding_power < PM_BINDING_POWER_COMPOSITION) ? PM_PARSE_ACCEPTS_COMMAND_CALL : 0;
+ }
+
+ /* Inside a def body, we push true onto the accepts_block_stack so that
+ * `do` is lexed as PM_TOKEN_KEYWORD_DO (which can only start a block
+ * for primary-level constructs, not commands). During command argument
+ * parsing, the stack is pushed to false, causing `do` to be lexed as
+ * PM_TOKEN_KEYWORD_DO_BLOCK, which is not consumed inside the endless
+ * def body and instead left for the outer context. */
+ pm_accepts_block_stack_push(parser, true);
+ pm_node_t *statement = parse_expression(parser, PM_BINDING_POWER_DEFINED + 1, allow_flags | PM_PARSE_IN_ENDLESS_DEF, PM_ERR_DEF_ENDLESS, (uint16_t) (depth + 1));
+ pm_accepts_block_stack_pop(parser);
+
+ /* If an unconsumed PM_TOKEN_KEYWORD_DO follows the body, it is an error
+ * (e.g., `def f = 1 do end`). PM_TOKEN_KEYWORD_DO_BLOCK is
+ * intentionally not caught here — it should bubble up to the outer
+ * context (e.g., `private def f = puts "Hello" do end` where the block
+ * attaches to `private`). */
+ if (accept1(parser, PM_TOKEN_KEYWORD_DO)) {
+ pm_block_node_t *block = parse_block(parser, (uint16_t) (depth + 1));
+ pm_parser_err_node(parser, UP(block), PM_ERR_DEF_ENDLESS_DO_BLOCK);
+ }
+
+ if (accept1(parser, PM_TOKEN_KEYWORD_RESCUE_MODIFIER)) {
+ context_push(parser, PM_CONTEXT_RESCUE_MODIFIER);
+
+ pm_token_t rescue_keyword = parser->previous;
+
+ /* In the Ruby grammar, the rescue value of an endless method
+ * command excludes and/or and in/=>. */
+ pm_node_t *value = parse_expression(parser, PM_BINDING_POWER_MATCH + 1, flags & PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_RESCUE_MODIFIER_VALUE, (uint16_t) (depth + 1));
+ context_pop(parser);
+
+ statement = UP(pm_rescue_modifier_node_create(parser, statement, &rescue_keyword, value));
+ }
+
+ /* A nested endless def whose body is a command call (e.g.,
+ * `def f = def g = foo bar`) is a command assignment and cannot appear
+ * as a def body. */
+ if (PM_NODE_TYPE_P(statement, PM_DEF_NODE) && pm_command_call_value_p(statement)) {
+ PM_PARSER_ERR_NODE_FORMAT(parser, statement, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(parser->current.type));
+ }
+
+ pm_statements_node_body_append(parser, (pm_statements_node_t *) statements, statement, false);
+ pm_do_loop_stack_pop(parser);
+ context_pop(parser);
+ } else {
+ if (lparen.start == NULL) {
+ 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 = UP(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 = UP(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_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_DEF_TERM, &def_keyword);
+ 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_raw(parser, name.start, parse_operator_symbol_name(&name));
+
+ flush_block_exits(parser, previous_block_exits);
+
+ return UP(pm_def_node_create(
+ parser,
+ name_id,
+ &name,
+ receiver,
+ params,
+ statements,
+ &locals,
+ &def_keyword,
+ NTOK2PTR(operator),
+ NTOK2PTR(lparen),
+ NTOK2PTR(rparen),
+ NTOK2PTR(equal),
+ NTOK2PTR(end_keyword)
+ ));
+}
+
+/**
+ * Parse a module definition expression (the `module` keyword).
+ */
+static pm_node_t *
+parse_module(pm_parser_t *parser, uint8_t flags, 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);
+
+ 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, flags & PM_PARSE_ACCEPTS_DO_BLOCK, 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_ERROR_RECOVERY_NODE)) {
+ pop_block_exits(parser, previous_block_exits);
+
+ pm_token_t missing = (pm_token_t) { .type = 0, .start = parser->previous.end, .end = parser->previous.end };
+ return UP(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 = UP(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);
+ }
+
+ if (!PM_NODE_TYPE_P(constant_path, PM_CONSTANT_READ_NODE) && !PM_NODE_TYPE_P(constant_path, PM_CONSTANT_PATH_NODE) && !PM_NODE_TYPE_P(constant_path, PM_ERROR_RECOVERY_NODE)) {
+ constant_path = UP(pm_error_recovery_node_create_unexpected(parser, constant_path));
+ }
+
+ 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 = UP(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 = UP(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_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_MODULE_TERM, &module_keyword);
+
+ if (context_def_p(parser)) {
+ pm_parser_err_token(parser, &module_keyword, PM_ERR_MODULE_IN_METHOD);
+ }
+
+ pop_block_exits(parser, previous_block_exits);
+
+ return UP(pm_module_node_create(parser, &locals, &module_keyword, constant_path, &name, statements, &parser->previous));
+}
+
+/**
+ * Parse an interpolated word array literal (`%W[...]`).
+ */
+static pm_node_t *
+parse_string_array(pm_parser_t *parser, uint16_t depth) {
+ 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(parser->arena, array, current);
+ current = NULL;
+ }
+
+ parser_lex(parser);
+ break;
+ }
+ case PM_TOKEN_STRING_CONTENT: {
+ pm_node_t *string = UP(pm_string_node_create_current_string(parser, NULL, &parser->current, NULL));
+ 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(parser, (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, NULL, NULL, NULL);
+ pm_interpolated_string_node_append(parser, interpolated, current);
+ pm_interpolated_string_node_append(parser, interpolated, string);
+ current = UP(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. */
+ current = UP(pm_interpolated_string_node_create(parser, NULL, NULL, NULL));
+ } 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_interpolated_string_node_t *interpolated = pm_interpolated_string_node_create(parser, NULL, NULL, NULL);
+ pm_interpolated_string_node_append(parser, interpolated, current);
+ current = UP(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_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);
+ pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1));
+ pm_interpolated_string_node_append(parser, (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. */
+ current = UP(pm_interpolated_string_node_create(parser, NULL, NULL, NULL));
+ } 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_interpolated_string_node_t *interpolated = pm_interpolated_string_node_create(parser, NULL, NULL, NULL);
+ pm_interpolated_string_node_append(parser, interpolated, current);
+ current = UP(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(parser, (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(parser->arena, 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 = 0, .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(parser, array, &closing);
+ return UP(array);
+}
+
+/**
+ * Parse an interpolated symbol array literal (`%I[...]`).
+ */
+static pm_node_t *
+parse_symbol_array(pm_parser_t *parser, uint16_t depth) {
+ 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(parser->arena, array, current);
+ current = NULL;
+ }
+
+ parser_lex(parser);
+ break;
+ }
+ case PM_TOKEN_STRING_CONTENT: {
+ 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 = UP(pm_symbol_node_create_current_string(parser, NULL, &parser->current, NULL));
+ 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 = UP(pm_string_node_create_current_string(parser, NULL, &parser->current, NULL));
+ parser_lex(parser);
+
+ pm_interpolated_symbol_node_append(parser->arena, (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 content = {
+ .type = PM_TOKEN_STRING_CONTENT,
+ .start = parser->start + cast->value_loc.start,
+ .end = parser->start + cast->value_loc.start + cast->value_loc.length
+ };
+
+ pm_node_t *first_string = UP(pm_string_node_create_unescaped(parser, NULL, &content, NULL, &cast->unescaped));
+ pm_node_t *second_string = UP(pm_string_node_create_current_string(parser, NULL, &parser->previous, NULL));
+ parser_lex(parser);
+
+ pm_interpolated_symbol_node_t *interpolated = pm_interpolated_symbol_node_create(parser, NULL, NULL, NULL);
+ pm_interpolated_symbol_node_append(parser->arena, interpolated, first_string);
+ pm_interpolated_symbol_node_append(parser->arena, interpolated, second_string);
+
+ current = UP(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. */
+ current = UP(pm_interpolated_symbol_node_create(parser, NULL, NULL, NULL));
+ } 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_interpolated_symbol_node_t *interpolated = pm_interpolated_symbol_node_create(parser, NULL, NULL, NULL);
+
+ current = UP(pm_symbol_node_to_string_node(parser, (pm_symbol_node_t *) current));
+ pm_interpolated_symbol_node_append(parser->arena, interpolated, current);
+ PM_NODE_START_SET_NODE(interpolated, current);
+ start_location_set = true;
+ current = UP(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(parser->arena, (pm_interpolated_symbol_node_t *) current, part);
+ if (!start_location_set) {
+ PM_NODE_START_SET_NODE(current, part);
+ }
+ 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. */
+ current = UP(pm_interpolated_symbol_node_create(parser, NULL, NULL, NULL));
+ } 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_interpolated_symbol_node_t *interpolated = pm_interpolated_symbol_node_create(parser, NULL, NULL, NULL);
+
+ current = UP(pm_symbol_node_to_string_node(parser, (pm_symbol_node_t *) current));
+ pm_interpolated_symbol_node_append(parser->arena, interpolated, current);
+ PM_NODE_START_SET_NODE(interpolated, current);
+ start_location_set = true;
+ current = UP(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(parser->arena, (pm_interpolated_symbol_node_t *) current, part);
+ if (!start_location_set) {
+ PM_NODE_START_SET_NODE(current, part);
+ }
+ 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(parser->arena, 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 = 0, .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(parser, array, &closing);
+
+ return UP(array);
+}
+
+/**
+ * Parse a parenthesized expression, which could be a grouping, a multi-target
+ * assignment, or a set of statements.
+ */
+static pm_node_t *
+parse_parentheses(pm_parser_t *parser, pm_binding_power_t binding_power, uint16_t depth) {
+ pm_token_t opening = parser->current;
+ pm_node_flags_t paren_flags = 0;
+
+ 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 (true) {
+ if (accept1(parser, PM_TOKEN_SEMICOLON)) {
+ paren_flags |= PM_PARENTHESES_NODE_FLAGS_MULTIPLE_STATEMENTS;
+ } else if (!accept1(parser, PM_TOKEN_NEWLINE)) {
+ break;
+ }
+ }
+
+ /* 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);
+ return UP(pm_parentheses_node_create(parser, &opening, NULL, &parser->previous, paren_flags));
+ }
+
+ /* 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, PM_PARSE_ACCEPTS_COMMAND_CALL | PM_PARSE_ACCEPTS_DO_BLOCK, 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 = false;
+
+ if (accept1(parser, PM_TOKEN_SEMICOLON)) {
+ terminator_found = true;
+ paren_flags |= PM_PARENTHESES_NODE_FLAGS_MULTIPLE_STATEMENTS;
+ } else if (accept1(parser, PM_TOKEN_NEWLINE)) {
+ terminator_found = true;
+ }
+
+ if (terminator_found) {
+ while (true) {
+ if (accept1(parser, PM_TOKEN_SEMICOLON)) {
+ paren_flags |= PM_PARENTHESES_NODE_FLAGS_MULTIPLE_STATEMENTS;
+ } else if (!accept1(parser, PM_TOKEN_NEWLINE)) {
+ break;
+ }
+ }
+ }
+
+ /* 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);
+
+ 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.length == 0) {
+ 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);
+ }
+
+ multi_target->lparen_loc = TOK2LOC(parser, &opening);
+ multi_target->rparen_loc = TOK2LOC(parser, &parser->previous);
+ PM_NODE_START_SET_TOKEN(parser, multi_target, &opening);
+ PM_NODE_LENGTH_SET_TOKEN(parser, multi_target, &parser->previous);
+
+ pm_node_t *result;
+ if (match1(parser, PM_TOKEN_COMMA) && (binding_power == PM_BINDING_POWER_STATEMENT)) {
+ result = parse_targets(parser, UP(multi_target), PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
+ accept1(parser, PM_TOKEN_NEWLINE);
+ } else {
+ result = UP(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 UP(pm_parentheses_node_create(parser, &opening, UP(statements), &parser->previous, paren_flags));
+ }
+
+ /* 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);
+ paren_flags |= PM_PARENTHESES_NODE_FLAGS_MULTIPLE_STATEMENTS;
+
+ 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_str(parser->current.type));
+ }
+
+ /* Parse each statement within the parentheses. */
+ while (true) {
+ pm_node_t *node = parse_expression(parser, PM_BINDING_POWER_STATEMENT, PM_PARSE_ACCEPTS_COMMAND_CALL | PM_PARSE_ACCEPTS_DO_BLOCK, 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_ERROR_RECOVERY_NODE)) break;
+
+ /* If we successfully parsed a statement, then we are going to need a
+ * 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_str(parser->current.type));
+ }
+ }
+
+ context_pop(parser);
+ pm_accepts_block_stack_pop(parser);
+ expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN);
+
+ /* 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. */
+ {
+ pm_node_t *statement = statements->body.nodes[statements->body.size - 1];
+
+ if (PM_NODE_TYPE_P(statement, 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, statement);
+
+ statement = UP(multi_target);
+ statements->body.nodes[statements->body.size - 1] = statement;
+ }
+
+ if (PM_NODE_TYPE_P(statement, PM_MULTI_TARGET_NODE)) {
+ const uint8_t *offset = parser->start + PM_NODE_END(statement);
+ pm_token_t operator = { .type = PM_TOKEN_EQUAL, .start = offset, .end = offset };
+ pm_node_t *value = UP(pm_error_recovery_node_create(parser, PM_NODE_END(statement), 0));
+
+ statement = UP(pm_multi_write_node_create(parser, (pm_multi_target_node_t *) statement, &operator, value));
+ statements->body.nodes[statements->body.size - 1] = statement;
+
+ pm_parser_err_node(parser, statement, PM_ERR_WRITE_TARGET_UNEXPECTED);
+ }
+ }
+
+ pop_block_exits(parser, previous_block_exits);
+ pm_void_statements_check(parser, statements, true);
+ return UP(pm_parentheses_node_create(parser, &opening, UP(statements), &parser->previous, paren_flags));
}
/**
* 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) {
+static PRISM_INLINE pm_node_t *
+parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, uint8_t flags, pm_diagnostic_id_t diag_id, uint16_t depth) {
switch (parser->current.type) {
case PM_TOKEN_BRACKET_LEFT_ARRAY: {
parser_lex(parser);
@@ -18077,11 +19089,9 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
} else {
// If there was no comma, then we need to add a syntax
// error.
- 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;
+ PM_PARSER_ERR_FORMAT(parser, PM_TOKEN_END(parser, &parser->previous), 0, PM_ERR_ARRAY_SEPARATOR, pm_token_str(parser->current.type));
+ parser->previous.start = parser->previous.end;
+ parser->previous.type = 0;
}
}
@@ -18099,28 +19109,28 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
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));
+ expression = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, flags & PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_ARRAY_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
}
- element = (pm_node_t *) pm_splat_node_create(parser, &operator, expression);
+ element = UP(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);
+ element = UP(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)) {
+ if (!match8(parser, PM_TOKEN_EOF, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON, PM_TOKEN_KEYWORD_DO_BLOCK, 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));
+ element = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, (uint8_t) ((flags & PM_PARSE_ACCEPTS_DO_BLOCK) | PM_PARSE_ACCEPTS_LABEL), PM_ERR_ARRAY_EXPRESSION, (uint16_t) (depth + 1));
- if (pm_symbol_node_label_p(element) || accept1(parser, PM_TOKEN_EQUAL_GREATER)) {
+ if (pm_symbol_node_label_p(parser, element) || accept1(parser, PM_TOKEN_EQUAL_GREATER)) {
if (parsed_bare_hash) {
pm_parser_err_previous(parser, PM_ERR_EXPRESSION_BARE_HASH);
}
@@ -18129,18 +19139,16 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
pm_static_literals_t hash_keys = { 0 };
pm_hash_key_static_literals_add(parser, &hash_keys, element);
- pm_token_t operator;
+ pm_token_t operator = { 0 };
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);
+ pm_node_t *value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, flags & PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_HASH_VALUE, (uint16_t) (depth + 1));
+ pm_node_t *assoc = UP(pm_assoc_node_create(parser, element, NTOK2PTR(operator), value));
+ pm_keyword_hash_node_elements_append(parser->arena, hash, assoc);
- element = (pm_node_t *) hash;
+ element = UP(hash);
if (accept1(parser, PM_TOKEN_COMMA) && !match1(parser, PM_TOKEN_BRACKET_RIGHT)) {
parse_assocs(parser, &hash_keys, element, (uint16_t) (depth + 1));
}
@@ -18150,236 +19158,26 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
}
}
- pm_array_node_elements_append(array, element);
- if (PM_NODE_TYPE_P(element, PM_MISSING_NODE)) break;
+ pm_array_node_elements_append(parser->arena, array, element);
+ if (PM_NODE_TYPE_P(element, PM_ERROR_RECOVERY_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));
+ PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_ARRAY_TERM, pm_token_str(parser->current.type));
parser->previous.start = parser->previous.end;
- parser->previous.type = PM_TOKEN_MISSING;
+ parser->previous.type = 0;
}
- pm_array_node_close_set(array, &parser->previous);
+ pm_array_node_close_set(parser, array, &parser->previous);
pm_accepts_block_stack_pop(parser);
- return (pm_node_t *) array;
+ return UP(array);
}
case PM_TOKEN_PARENTHESIS_LEFT:
- case PM_TOKEN_PARENTHESIS_LEFT_PARENTHESES: {
- pm_token_t opening = parser->current;
- pm_node_flags_t flags = 0;
-
- 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 (true) {
- if (accept1(parser, PM_TOKEN_SEMICOLON)) {
- flags |= PM_PARENTHESES_NODE_FLAGS_MULTIPLE_STATEMENTS;
- } else if (!accept1(parser, PM_TOKEN_NEWLINE)) {
- break;
- }
- }
-
- // 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, flags);
- }
-
- // 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 = false;
-
- if (accept1(parser, PM_TOKEN_SEMICOLON)) {
- terminator_found = true;
- flags |= PM_PARENTHESES_NODE_FLAGS_MULTIPLE_STATEMENTS;
- } else if (accept1(parser, PM_TOKEN_NEWLINE)) {
- terminator_found = true;
- }
-
- if (terminator_found) {
- while (true) {
- if (accept1(parser, PM_TOKEN_SEMICOLON)) {
- flags |= PM_PARENTHESES_NODE_FLAGS_MULTIPLE_STATEMENTS;
- } else if (!accept1(parser, PM_TOKEN_NEWLINE)) {
- break;
- }
- }
- }
-
- // 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, flags);
- }
-
- // 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);
- flags |= PM_PARENTHESES_NODE_FLAGS_MULTIPLE_STATEMENTS;
-
- 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));
- }
- }
-
- context_pop(parser);
- pm_accepts_block_stack_pop(parser);
- expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN);
-
- // 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.
- {
- pm_node_t *statement = statements->body.nodes[statements->body.size - 1];
-
- if (PM_NODE_TYPE_P(statement, 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, statement);
-
- statement = (pm_node_t *) multi_target;
- statements->body.nodes[statements->body.size - 1] = statement;
- }
-
- if (PM_NODE_TYPE_P(statement, PM_MULTI_TARGET_NODE)) {
- const uint8_t *offset = statement->location.end;
- pm_token_t operator = { .type = PM_TOKEN_EQUAL, .start = offset, .end = offset };
- pm_node_t *value = (pm_node_t *) pm_missing_node_create(parser, offset, offset);
-
- statement = (pm_node_t *) pm_multi_write_node_create(parser, (pm_multi_target_node_t *) statement, &operator, value);
- statements->body.nodes[statements->body.size - 1] = statement;
-
- pm_parser_err_node(parser, statement, PM_ERR_WRITE_TARGET_UNEXPECTED);
- }
- }
-
- 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, flags);
- }
+ case PM_TOKEN_PARENTHESIS_LEFT_PARENTHESES:
+ return parse_parentheses(parser, binding_power, depth);
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
@@ -18394,14 +19192,15 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
pm_accepts_block_stack_push(parser, true);
parser_lex(parser);
- pm_hash_node_t *node = pm_hash_node_create(parser, &parser->previous);
+ pm_token_t opening = parser->previous;
+ pm_hash_node_t *node = pm_hash_node_create(parser, &opening);
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));
+ parse_assocs(parser, current_hash_keys, UP(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));
+ parse_assocs(parser, &hash_keys, UP(node), (uint16_t) (depth + 1));
pm_static_literals_free(&hash_keys);
}
@@ -18409,26 +19208,33 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
}
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);
+ expect1_opening(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_HASH_TERM, &opening);
+ pm_hash_node_closing_loc_set(parser, node, &parser->previous);
- return (pm_node_t *) node;
+ return UP(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_node_t *node = UP(pm_string_node_create_current_string(
+ parser,
+ &(pm_token_t) {
+ .type = PM_TOKEN_STRING_BEGIN,
+ .start = parser->current.start,
+ .end = parser->current.start + 1
+ },
+ &(pm_token_t) {
+ .type = PM_TOKEN_STRING_CONTENT,
+ .start = parser->current.start + 1,
+ .end = parser->current.end
+ },
+ NULL
+ ));
- 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));
+ // Skip past the character literal here, since now we have handled
+ // parser->explicit_encoding correctly.
+ parser_lex(parser);
+
// Characters can be followed by strings in which case they are
// automatically concatenated.
if (match1(parser, PM_TOKEN_STRING_BEGIN)) {
@@ -18439,7 +19245,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
}
case PM_TOKEN_CLASS_VARIABLE: {
parser_lex(parser);
- pm_node_t *node = (pm_node_t *) pm_class_variable_read_node_create(parser, &parser->previous);
+ pm_node_t *node = UP(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));
@@ -18455,16 +19261,16 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
// 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))) ||
+ ((flags & PM_PARSE_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);
+ parse_arguments_list(parser, &arguments, true, flags, (uint16_t) (depth + 1));
+ return UP(pm_call_node_fcall_create(parser, &constant, &arguments));
}
- pm_node_t *node = (pm_node_t *) pm_constant_read_node_create(parser, &parser->previous);
+ pm_node_t *node = UP(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
@@ -18479,7 +19285,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
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);
+ pm_node_t *node = UP(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));
@@ -18492,7 +19298,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
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));
+ pm_node_t *right = parse_expression(parser, pm_binding_powers[operator.type].left, flags & PM_PARSE_ACCEPTS_DO_BLOCK, 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
@@ -18502,23 +19308,23 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
pm_parser_err_current(parser, PM_ERR_UNEXPECTED_RANGE_OPERATOR);
}
- return (pm_node_t *) pm_range_node_create(parser, NULL, &operator, right);
+ return UP(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);
+ return UP(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);
+ return UP(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);
+ return UP(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);
+ return UP(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);
+ pm_node_t *node = UP(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));
@@ -18528,7 +19334,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
}
case PM_TOKEN_GLOBAL_VARIABLE: {
parser_lex(parser);
- pm_node_t *node = (pm_node_t *) pm_global_variable_read_node_create(parser, &parser->previous);
+ pm_node_t *node = UP(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));
@@ -18538,7 +19344,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
}
case PM_TOKEN_BACK_REFERENCE: {
parser_lex(parser);
- pm_node_t *node = (pm_node_t *) pm_back_reference_read_node_create(parser, &parser->previous);
+ pm_node_t *node = UP(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));
@@ -18560,26 +19366,21 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
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))) {
+ if (parse_arguments_list(parser, &arguments, true, flags, (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);
+ pm_node_flag_unset(UP(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;
- }
+ const pm_location_t *end = pm_arguments_end(&arguments);
+ if (end == NULL) {
+ PM_NODE_LENGTH_SET_LOCATION(call, &call->message_loc);
} else {
- call->base.location.end = arguments.closing_loc.end;
+ PM_NODE_LENGTH_SET_LOCATION(call, end);
}
}
} else {
@@ -18587,19 +19388,19 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
// 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))) ||
+ ((flags & PM_PARSE_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));
+ parse_arguments_list(parser, &arguments, true, flags, (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);
+ pm_node_unreference(parser, node);
} else {
// Otherwise, we're about to convert a regular local
// variable read into a method call, in which case we
@@ -18607,16 +19408,15 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
// 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);
+ if (pm_token_is_numbered_parameter(parser, PM_TOKEN_START(parser, &identifier), PM_TOKEN_LENGTH(&identifier))) {
+ pm_node_unreference(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;
+ return UP(fcall);
}
}
@@ -18648,12 +19448,12 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
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);
+ node = UP(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 = UP(pm_string_node_create_unescaped(parser, &opening, &content, &parser->previous, &PM_STRING_EMPTY));
}
- node->location.end = opening.end;
+ PM_NODE_LENGTH_SET_TOKEN(parser, node, &opening);
} 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
@@ -18661,7 +19461,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
//
// 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);
+ node = UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &parser->previous), PM_TOKEN_LENGTH(&parser->previous)));
} 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
@@ -18670,8 +19470,8 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
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->opening_loc = TOK2LOC(parser, &opening);
+ cast->closing_loc = TOK2LOC(parser, &parser->current);
cast->base.location = cast->opening_loc;
if (lex_mode.quote == PM_HEREDOC_QUOTE_BACKTICK) {
@@ -18680,21 +19480,21 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
}
if (lex_mode.indent == PM_HEREDOC_INDENT_TILDE && (common_whitespace != (size_t) -1) && (common_whitespace != 0)) {
- parse_heredoc_dedent_string(&cast->unescaped, common_whitespace);
+ parse_heredoc_dedent_string(parser->arena, &cast->unescaped, common_whitespace);
}
- node = (pm_node_t *) cast;
+ node = UP(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);
+ pm_node_list_append(parser->arena, &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);
+ pm_node_list_append(parser->arena, &parts, part);
}
}
@@ -18705,19 +19505,18 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
cast->parts = parts;
expect1_heredoc_term(parser, lex_mode.ident_start, lex_mode.ident_length);
- pm_interpolated_xstring_node_closing_set(cast, &parser->previous);
+ pm_interpolated_xstring_node_closing_set(parser, cast, &parser->previous);
cast->base.location = cast->opening_loc;
- node = (pm_node_t *) cast;
+ node = UP(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);
+ pm_interpolated_string_node_closing_set(parser, cast, &parser->previous);
cast->base.location = cast->opening_loc;
- node = (pm_node_t *) cast;
+ node = UP(cast);
}
// If this is a heredoc that is indented with a ~, then we need
@@ -18742,7 +19541,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
}
case PM_TOKEN_INSTANCE_VARIABLE: {
parser_lex(parser);
- pm_node_t *node = (pm_node_t *) pm_instance_variable_read_node_create(parser, &parser->previous);
+ pm_node_t *node = UP(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));
@@ -18751,34 +19550,34 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
return node;
}
case PM_TOKEN_INTEGER: {
- pm_node_flags_t base = parser->integer_base;
+ pm_node_flags_t base = parser->integer.base;
parser_lex(parser);
- return (pm_node_t *) pm_integer_node_create(parser, base, &parser->previous);
+ return UP(pm_integer_node_create(parser, base, &parser->previous));
}
case PM_TOKEN_INTEGER_IMAGINARY: {
- pm_node_flags_t base = parser->integer_base;
+ pm_node_flags_t base = parser->integer.base;
parser_lex(parser);
- return (pm_node_t *) pm_integer_node_imaginary_create(parser, base, &parser->previous);
+ return UP(pm_integer_node_imaginary_create(parser, base, &parser->previous));
}
case PM_TOKEN_INTEGER_RATIONAL: {
- pm_node_flags_t base = parser->integer_base;
+ pm_node_flags_t base = parser->integer.base;
parser_lex(parser);
- return (pm_node_t *) pm_integer_node_rational_create(parser, base, &parser->previous);
+ return UP(pm_integer_node_rational_create(parser, base, &parser->previous));
}
case PM_TOKEN_INTEGER_RATIONAL_IMAGINARY: {
- pm_node_flags_t base = parser->integer_base;
+ 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);
+ return UP(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);
+ return UP(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);
+ return UP(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);
+ return UP(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);
@@ -18798,245 +19597,27 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
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 {
+ } else if (!PM_NODE_TYPE_P(old_name, PM_ERROR_RECOVERY_NODE)) {
pm_parser_err_node(parser, old_name, PM_ERR_ALIAS_ARGUMENT);
+ old_name = UP(pm_error_recovery_node_create_unexpected(parser, old_name));
}
- return (pm_node_t *) pm_alias_global_variable_node_create(parser, &keyword, new_name, old_name);
+ return UP(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)) {
+ if (!PM_NODE_TYPE_P(old_name, PM_SYMBOL_NODE) && !PM_NODE_TYPE_P(old_name, PM_INTERPOLATED_SYMBOL_NODE) && !PM_NODE_TYPE_P(old_name, PM_ERROR_RECOVERY_NODE)) {
pm_parser_err_node(parser, old_name, PM_ERR_ALIAS_ARGUMENT);
+ old_name = UP(pm_error_recovery_node_create_unexpected(parser, old_name));
}
}
PRISM_FALLTHROUGH
default:
- return (pm_node_t *) pm_alias_method_node_create(parser, &keyword, new_name, old_name);
+ return UP(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_CASE:
+ return parse_case(parser, flags, depth);
case PM_TOKEN_KEYWORD_BEGIN: {
size_t opening_newline_index = token_newline_index(parser);
parser_lex(parser);
@@ -19057,15 +19638,12 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
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);
+ expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_BEGIN_TERM, &begin_keyword);
+ PM_NODE_LENGTH_SET_TOKEN(parser, begin_node, &parser->previous);
+ pm_begin_node_end_keyword_set(parser, begin_node, &parser->previous);
pop_block_exits(parser, previous_block_exits);
- pm_node_list_free(&current_block_exits);
-
- return (pm_node_t *) begin_node;
+ return UP(begin_node);
}
case PM_TOKEN_KEYWORD_BEGIN_UPCASE: {
pm_node_list_t current_block_exits = { 0 };
@@ -19082,16 +19660,14 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
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);
+ expect1_opening(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_BEGIN_UPCASE_TERM, &opening);
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);
+ return UP(pm_pre_execution_node_create(parser, &keyword, &opening, statements, &parser->previous));
}
case PM_TOKEN_KEYWORD_BREAK:
case PM_TOKEN_KEYWORD_NEXT:
@@ -19108,29 +19684,44 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
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));
+ pm_token_t next = parser->current;
+ parse_arguments(parser, &arguments, false, PM_TOKEN_EOF, flags, (uint16_t) (depth + 1));
+
+ // Reject `foo && return bar`.
+ if (!(flags & PM_PARSE_ACCEPTS_COMMAND_CALL) && arguments.arguments != NULL) {
+ PM_PARSER_ERR_TOKEN_FORMAT(parser, &next, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(next.type));
+ }
+ }
+
+ // It's possible that we've parsed a block argument through our
+ // call to parse_arguments. If we found one, we should mark it
+ // as invalid and destroy it, as we don't have a place for it.
+ if (arguments.block != NULL) {
+ pm_parser_err_node(parser, arguments.block, PM_ERR_UNEXPECTED_BLOCK_ARGUMENT);
+ pm_node_unreference(parser, arguments.block);
+ arguments.block = NULL;
}
}
switch (keyword.type) {
case PM_TOKEN_KEYWORD_BREAK: {
- pm_node_t *node = (pm_node_t *) pm_break_node_create(parser, &keyword, arguments.arguments);
+ pm_node_t *node = UP(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);
+ pm_node_t *node = UP(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);
+ pm_node_t *node = UP(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);
+ return UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &parser->previous), PM_TOKEN_LENGTH(&parser->previous)));
}
}
case PM_TOKEN_KEYWORD_SUPER: {
@@ -19138,24 +19729,24 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
pm_token_t keyword = parser->previous;
pm_arguments_t arguments = { 0 };
- parse_arguments_list(parser, &arguments, true, accepts_command_call, (uint16_t) (depth + 1));
+ parse_arguments_list(parser, &arguments, true, flags, (uint16_t) (depth + 1));
if (
- arguments.opening_loc.start == NULL &&
+ arguments.opening_loc.length == 0 &&
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 UP(pm_forwarding_super_node_create(parser, &keyword, &arguments));
}
- return (pm_node_t *) pm_super_node_create(parser, &keyword, &arguments);
+ return UP(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));
+ parse_arguments_list(parser, &arguments, false, flags, (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
@@ -19163,442 +19754,25 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
// yield node.
if (arguments.block != NULL) {
pm_parser_err_node(parser, arguments.block, PM_ERR_UNEXPECTED_BLOCK_ARGUMENT);
- pm_node_destroy(parser, arguments.block);
+ pm_node_unreference(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);
+ pm_node_t *node = UP(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);
-
- // This will be false if the method name is not a valid identifier
- // but could be followed by an operator.
- bool valid_name = true;
-
- 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_INSTANCE_VARIABLE:
- case PM_TOKEN_CLASS_VARIABLE:
- case PM_TOKEN_GLOBAL_VARIABLE:
- valid_name = false;
- PRISM_FALLTHROUGH
- case PM_TOKEN_CONSTANT:
- 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 {
- if (!valid_name) {
- PM_PARSER_ERR_TOKEN_FORMAT(parser, identifier, PM_ERR_DEF_NAME, pm_token_type_human(identifier.type));
- }
-
- 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, 0);
-
- // 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, false, (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, false, (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);
-
- // In endless method bodies, we need to handle command calls carefully.
- // We want to allow command calls in assignment context but maintain
- // the same binding power to avoid changing how operators are parsed.
- // Note that we're intentionally NOT allowing code like `private def foo = puts "Hello"`
- // because the original parser, parse.y, can't handle it and we want to maintain the same behavior
- bool allow_command_call = (binding_power == PM_BINDING_POWER_ASSIGNMENT) ||
- (binding_power < PM_BINDING_POWER_COMPOSITION);
-
- pm_node_t *statement = parse_expression(parser, PM_BINDING_POWER_DEFINED + 1, allow_command_call, 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, pm_binding_powers[PM_TOKEN_KEYWORD_RESCUE_MODIFIER].right, 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_CLASS:
+ return parse_class(parser, flags, depth);
+ case PM_TOKEN_KEYWORD_DEF:
+ return parse_def(parser, binding_power, flags, depth);
case PM_TOKEN_KEYWORD_DEFINED: {
parser_lex(parser);
- pm_token_t keyword = parser->previous;
- pm_token_t lparen;
- pm_token_t rparen;
+ pm_token_t keyword = parser->previous;
+ pm_token_t lparen = { 0 };
+ pm_token_t rparen = { 0 };
pm_node_t *expression;
context_push(parser, PM_CONTEXT_DEFINED);
@@ -19608,34 +19782,29 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
lparen = parser->previous;
if (newline && accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
- expression = (pm_node_t *) pm_parentheses_node_create(parser, &lparen, NULL, &parser->previous, 0);
- lparen = not_provided(parser);
- rparen = not_provided(parser);
+ expression = UP(pm_parentheses_node_create(parser, &lparen, NULL, &parser->previous, 0));
+ lparen = (pm_token_t) { 0 };
} else {
- expression = parse_expression(parser, PM_BINDING_POWER_COMPOSITION, true, false, PM_ERR_DEFINED_EXPRESSION, (uint16_t) (depth + 1));
+ expression = parse_expression(parser, PM_BINDING_POWER_COMPOSITION, PM_PARSE_ACCEPTS_COMMAND_CALL | PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_DEFINED_EXPRESSION, (uint16_t) (depth + 1));
- if (parser->recovering) {
- rparen = not_provided(parser);
- } else {
+ if (!parser->recovering) {
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));
+ expression = parse_expression(parser, PM_BINDING_POWER_DEFINED, flags & PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_DEFINED_EXPRESSION, (uint16_t) (depth + 1));
}
context_pop(parser);
- return (pm_node_t *) pm_defined_node_create(
+ return UP(pm_defined_node_create(
parser,
- &lparen,
+ NTOK2PTR(lparen),
expression,
- &rparen,
- &PM_LOCATION_TOKEN_VALUE(&keyword)
- );
+ NTOK2PTR(rparen),
+ &keyword
+ ));
}
case PM_TOKEN_KEYWORD_END_UPCASE: {
if (binding_power != PM_BINDING_POWER_STATEMENT) {
@@ -19653,12 +19822,12 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
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);
+ expect1_opening(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_END_UPCASE_TERM, &opening);
+ return UP(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);
+ return UP(pm_false_node_create(parser, &parser->previous));
case PM_TOKEN_KEYWORD_FOR: {
size_t opening_newline_index = token_newline_index(parser);
parser_lex(parser);
@@ -19674,15 +19843,15 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
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));
+ name = parse_expression(parser, PM_BINDING_POWER_INDEX, flags & PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
}
- index = (pm_node_t *) pm_splat_node_create(parser, &star_operator, name);
+ index = UP(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));
+ index = parse_expression(parser, PM_BINDING_POWER_INDEX, flags & PM_PARSE_ACCEPTS_DO_BLOCK, 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);
+ index = UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &for_keyword), PM_TOKEN_LENGTH(&for_keyword)));
}
// Now, if there are multiple index expressions, parse them out.
@@ -19698,16 +19867,15 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
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_node_t *collection = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION, (uint8_t) ((flags & PM_PARSE_ACCEPTS_DO_BLOCK) | PM_PARSE_ACCEPTS_COMMAND_CALL), PM_ERR_FOR_COLLECTION, (uint16_t) (depth + 1));
pm_do_loop_stack_pop(parser);
- pm_token_t do_keyword;
+ pm_token_t do_keyword = { 0 };
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_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_EXPECT_FOR_DELIMITER, pm_token_str(parser->current.type));
}
}
@@ -19717,13 +19885,13 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
}
parser_warn_indentation_mismatch(parser, opening_newline_index, &for_keyword, false, false);
- expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_FOR_TERM);
+ expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_FOR_TERM, &for_keyword);
- return (pm_node_t *) pm_for_node_create(parser, index, collection, statements, &for_keyword, &in_keyword, &do_keyword, &parser->previous);
+ return UP(pm_for_node_create(parser, index, collection, statements, &for_keyword, &in_keyword, NTOK2PTR(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);
+ PM_PARSER_WARN_TOKEN_FORMAT_CONTENT(parser, &parser->current, PM_WARN_KEYWORD_EOL);
}
size_t opening_newline_index = token_newline_index(parser);
@@ -19740,26 +19908,24 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
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);
+ if (PM_NODE_TYPE_P(name, PM_ERROR_RECOVERY_NODE)) {
} else {
- pm_undef_node_append(undef, name);
+ pm_undef_node_append(parser->arena, 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);
+ if (PM_NODE_TYPE_P(name, PM_ERROR_RECOVERY_NODE)) {
break;
}
- pm_undef_node_append(undef, name);
+ pm_undef_node_append(parser->arena, undef, name);
}
}
- return (pm_node_t *) undef;
+ return UP(undef);
}
case PM_TOKEN_KEYWORD_NOT: {
parser_lex(parser);
@@ -19768,18 +19934,22 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
pm_arguments_t arguments = { 0 };
pm_node_t *receiver = NULL;
- // If we do not accept a command call, then we also do not accept a
- // not without parentheses. In this case we need to reject this
- // syntax.
- if (!accepts_command_call && !match1(parser, PM_TOKEN_PARENTHESIS_LEFT)) {
+ // The `not` keyword without parentheses is only valid in contexts
+ // where it would be parsed as an expression (i.e., at or below
+ // the `not` binding power level). In other contexts (e.g., method
+ // arguments, array elements, assignment right-hand sides),
+ // parentheses are required: `not(x)`. An exception is made for
+ // endless def bodies, where `not` is valid as both `arg` and
+ // `command` (e.g., `def f = not 1`, `def f = not foo bar`).
+ if (binding_power > PM_BINDING_POWER_NOT && !(flags & PM_PARSE_IN_ENDLESS_DEF) && !match1(parser, PM_TOKEN_PARENTHESIS_LEFT)) {
if (match1(parser, PM_TOKEN_PARENTHESIS_LEFT_PARENTHESES)) {
- pm_parser_err(parser, parser->previous.end, parser->previous.end + 1, PM_ERR_EXPECT_LPAREN_AFTER_NOT_LPAREN);
+ pm_parser_err(parser, PM_TOKEN_END(parser, &parser->previous), 1, PM_ERR_EXPECT_LPAREN_AFTER_NOT_LPAREN);
} else {
accept1(parser, PM_TOKEN_NEWLINE);
pm_parser_err_current(parser, PM_ERR_EXPECT_LPAREN_AFTER_NOT_OTHER);
}
- return (pm_node_t *) pm_missing_node_create(parser, parser->current.start, parser->current.end);
+ return UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current)));
}
accept1(parser, PM_TOKEN_NEWLINE);
@@ -19788,22 +19958,22 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
pm_token_t lparen = parser->previous;
if (accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
- receiver = (pm_node_t *) pm_parentheses_node_create(parser, &lparen, NULL, &parser->previous, 0);
+ receiver = UP(pm_parentheses_node_create(parser, &lparen, NULL, &parser->previous, 0));
} else {
- arguments.opening_loc = PM_LOCATION_TOKEN_VALUE(&lparen);
- receiver = parse_expression(parser, PM_BINDING_POWER_COMPOSITION, true, false, PM_ERR_NOT_EXPRESSION, (uint16_t) (depth + 1));
+ arguments.opening_loc = TOK2LOC(parser, &lparen);
+ receiver = parse_expression(parser, PM_BINDING_POWER_COMPOSITION, PM_PARSE_ACCEPTS_COMMAND_CALL | PM_PARSE_ACCEPTS_DO_BLOCK, 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);
+ arguments.closing_loc = TOK2LOC(parser, &parser->previous);
}
}
} else {
- receiver = parse_expression(parser, PM_BINDING_POWER_NOT, true, false, PM_ERR_NOT_EXPRESSION, (uint16_t) (depth + 1));
+ receiver = parse_expression(parser, PM_BINDING_POWER_NOT, (uint8_t) ((flags & PM_PARSE_ACCEPTS_DO_BLOCK) | PM_PARSE_ACCEPTS_COMMAND_CALL), PM_ERR_NOT_EXPRESSION, (uint16_t) (depth + 1));
}
- return (pm_node_t *) pm_call_node_not_create(parser, receiver, &message, &arguments);
+ return UP(pm_call_node_not_create(parser, receiver, &message, &arguments));
}
case PM_TOKEN_KEYWORD_UNLESS: {
size_t opening_newline_index = token_newline_index(parser);
@@ -19811,81 +19981,15 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
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_MODULE:
+ return parse_module(parser, flags, depth);
case PM_TOKEN_KEYWORD_NIL:
parser_lex(parser);
- return (pm_node_t *) pm_nil_node_create(parser, &parser->previous);
+ return UP(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);
+ pm_node_t *node = UP(pm_redo_node_create(parser, &parser->previous));
if (!parser->partial_script) parse_block_exit(parser, node);
return node;
@@ -19893,17 +19997,17 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
case PM_TOKEN_KEYWORD_RETRY: {
parser_lex(parser);
- pm_node_t *node = (pm_node_t *) pm_retry_node_create(parser, &parser->previous);
+ pm_node_t *node = UP(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);
+ return UP(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);
+ return UP(pm_true_node_create(parser, &parser->previous));
case PM_TOKEN_KEYWORD_UNTIL: {
size_t opening_newline_index = token_newline_index(parser);
@@ -19912,16 +20016,15 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
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_node_t *predicate = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION, (uint8_t) ((flags & PM_PARSE_ACCEPTS_DO_BLOCK) | PM_PARSE_ACCEPTS_COMMAND_CALL), PM_ERR_CONDITIONAL_UNTIL_PREDICATE, (uint16_t) (depth + 1));
pm_do_loop_stack_pop(parser);
context_pop(parser);
- pm_token_t do_keyword;
+ pm_token_t do_keyword = { 0 };
if (accept1(parser, PM_TOKEN_KEYWORD_DO_LOOP)) {
do_keyword = parser->previous;
} else {
- do_keyword = not_provided(parser);
expect2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON, PM_ERR_CONDITIONAL_UNTIL_PREDICATE);
}
@@ -19934,9 +20037,9 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
}
parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword, false, false);
- expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_UNTIL_TERM);
+ expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_UNTIL_TERM, &keyword);
- return (pm_node_t *) pm_until_node_create(parser, &keyword, &do_keyword, &parser->previous, predicate, statements, 0);
+ return UP(pm_until_node_create(parser, &keyword, NTOK2PTR(do_keyword), &parser->previous, predicate, statements, 0));
}
case PM_TOKEN_KEYWORD_WHILE: {
size_t opening_newline_index = token_newline_index(parser);
@@ -19946,16 +20049,15 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
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_node_t *predicate = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION, (uint8_t) ((flags & PM_PARSE_ACCEPTS_DO_BLOCK) | PM_PARSE_ACCEPTS_COMMAND_CALL), PM_ERR_CONDITIONAL_WHILE_PREDICATE, (uint16_t) (depth + 1));
pm_do_loop_stack_pop(parser);
context_pop(parser);
- pm_token_t do_keyword;
+ pm_token_t do_keyword = { 0 };
if (accept1(parser, PM_TOKEN_KEYWORD_DO_LOOP)) {
do_keyword = parser->previous;
} else {
- do_keyword = not_provided(parser);
expect2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON, PM_ERR_CONDITIONAL_WHILE_PREDICATE);
}
@@ -19968,381 +20070,122 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
}
parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword, false, false);
- expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_WHILE_TERM);
+ expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_WHILE_TERM, &keyword);
- return (pm_node_t *) pm_while_node_create(parser, &keyword, &do_keyword, &parser->previous, predicate, statements, 0);
+ return UP(pm_while_node_create(parser, &keyword, NTOK2PTR(do_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);
+ pm_node_t *current = NULL;
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;
- }
-
+ // Interpolation is not possible but nested heredocs can still lead to
+ // consecutive (disjoint) string tokens when the final newline is escaped.
+ while (match1(parser, PM_TOKEN_STRING_CONTENT)) {
+ // Record the string node, moving to interpolation if needed.
+ if (current == NULL) {
+ current = UP(pm_symbol_node_create_current_string(parser, NULL, &parser->current, NULL));
+ parser_lex(parser);
+ } else if (PM_NODE_TYPE_P(current, PM_INTERPOLATED_SYMBOL_NODE)) {
+ pm_node_t *string = UP(pm_string_node_create_current_string(parser, NULL, &parser->current, NULL));
+ parser_lex(parser);
+ pm_interpolated_symbol_node_append(parser->arena, (pm_interpolated_symbol_node_t *) current, string);
+ } else if (PM_NODE_TYPE_P(current, PM_SYMBOL_NODE)) {
+ pm_symbol_node_t *cast = (pm_symbol_node_t *) current;
+ pm_token_t content = { .type = PM_TOKEN_STRING_CONTENT, .start = parser->start + cast->value_loc.start, .end = parser->start + cast->value_loc.start + cast->value_loc.length };
+ pm_node_t *first_string = UP(pm_string_node_create_unescaped(parser, NULL, &content, NULL, &cast->unescaped));
+ pm_node_t *second_string = UP(pm_string_node_create_current_string(parser, NULL, &parser->previous, 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_interpolated_symbol_node_t *interpolated = pm_interpolated_symbol_node_create(parser, NULL, NULL, NULL);
+ pm_interpolated_symbol_node_append(parser->arena, interpolated, first_string);
+ pm_interpolated_symbol_node_append(parser->arena, interpolated, second_string);
- 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;
+ // current is arena-allocated so no explicit free is needed.
+ current = UP(interpolated);
+ } else {
+ assert(false && "unreachable");
}
- 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);
+ if (current) {
+ pm_array_node_elements_append(parser->arena, array, current);
+ current = NULL;
+ } else {
+ 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_UPPER_TERM);
- closing = (pm_token_t) { .type = PM_TOKEN_MISSING, .start = parser->previous.end, .end = parser->previous.end };
+ pm_parser_err_token(parser, &opening, PM_ERR_LIST_I_LOWER_TERM);
+ closing = (pm_token_t) { .type = 0, .start = parser->previous.end, .end = parser->previous.end };
} else {
- expect1(parser, PM_TOKEN_STRING_END, PM_ERR_LIST_I_UPPER_TERM);
+ expect1(parser, PM_TOKEN_STRING_END, PM_ERR_LIST_I_LOWER_TERM);
}
- pm_array_node_close_set(array, &closing);
+ pm_array_node_close_set(parser, array, &closing);
- return (pm_node_t *) array;
+ return UP(array);
}
+ case PM_TOKEN_PERCENT_UPPER_I:
+ return parse_symbol_array(parser, depth);
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);
+ pm_node_t *current = NULL;
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);
+ // Interpolation is not possible but nested heredocs can still lead to
+ // consecutive (disjoint) string tokens when the final newline is escaped.
+ while (match1(parser, PM_TOKEN_STRING_CONTENT)) {
+ pm_node_t *string = UP(pm_string_node_create_current_string(parser, NULL, &parser->current, NULL));
+
+ // Record the string node, moving to interpolation if needed.
+ if (current == NULL) {
+ current = string;
+ } else if (PM_NODE_TYPE_P(current, PM_INTERPOLATED_STRING_NODE)) {
+ pm_interpolated_string_node_append(parser, (pm_interpolated_string_node_t *) current, string);
+ } else if (PM_NODE_TYPE_P(current, PM_STRING_NODE)) {
+ pm_interpolated_string_node_t *interpolated = pm_interpolated_string_node_create(parser, NULL, NULL, NULL);
+ pm_interpolated_string_node_append(parser, interpolated, current);
+ pm_interpolated_string_node_append(parser, interpolated, string);
+ current = UP(interpolated);
+ } else {
+ assert(false && "unreachable");
+ }
+ parser_lex(parser);
}
- expect1(parser, PM_TOKEN_STRING_CONTENT, PM_ERR_LIST_W_LOWER_ELEMENT);
+ if (current) {
+ pm_array_node_elements_append(parser->arena, array, current);
+ current = NULL;
+ } else {
+ 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 };
+ closing = (pm_token_t) { .type = 0, .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;
+ pm_array_node_close_set(parser, array, &closing);
+ return UP(array);
}
+ case PM_TOKEN_PERCENT_UPPER_W:
+ return parse_string_array(parser, depth);
case PM_TOKEN_REGEXP_BEGIN: {
pm_token_t opening = parser->current;
parser_lex(parser);
@@ -20359,10 +20202,9 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
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_regular_expression_node_t *node = pm_regular_expression_node_create(parser, &opening, &content, &parser->previous);
+ pm_node_flag_set(UP(node), pm_regexp_parse(parser, node, NULL, NULL));
+ return UP(node);
}
pm_interpolated_regular_expression_node_t *interpolated;
@@ -20374,7 +20216,6 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
// 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
@@ -20383,26 +20224,22 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
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 we're not immediately followed by a =~, then we
+ // parse and validate now. If it is followed by a =~,
+ // then it will get parsed in the =~ handler where
+ // named captures can also be extracted.
if (!match1(parser, PM_TOKEN_EQUAL_TILDE)) {
- parse_regular_expression_errors(parser, node);
+ pm_node_flag_set(UP(node), pm_regexp_parse(parser, node, NULL, NULL));
}
- 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;
+ return UP(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);
-
+ pm_node_t *part = UP(pm_string_node_create_unescaped(parser, NULL, &parser->previous, NULL, &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
@@ -20410,7 +20247,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
pm_node_flag_set(part, PM_STRING_FLAGS_FORCED_BINARY_ENCODING);
}
- pm_interpolated_regular_expression_node_append(interpolated, part);
+ pm_interpolated_regular_expression_node_append(parser->arena, 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
@@ -20423,20 +20260,20 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
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_interpolated_regular_expression_node_append(parser->arena, 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 };
+ closing = (pm_token_t) { .type = 0, .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;
+ return UP(interpolated);
}
case PM_TOKEN_BACKTICK:
case PM_TOKEN_PERCENT_LOWER_X: {
@@ -20458,7 +20295,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
};
parser_lex(parser);
- return (pm_node_t *) pm_xstring_node_create(parser, &opening, &content, &parser->previous);
+ return UP(pm_xstring_node_create(parser, &opening, &content, &parser->previous));
}
pm_interpolated_x_string_node_t *node;
@@ -20473,7 +20310,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
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_t *node = UP(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;
@@ -20483,13 +20320,10 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
// 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_t *part = UP(pm_string_node_create_unescaped(parser, NULL, &parser->previous, NULL, &unescaped));
pm_node_flag_set(part, parse_unescaped_encoding(parser));
- pm_interpolated_xstring_node_append(node, part);
+ pm_interpolated_xstring_node_append(parser->arena, 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
@@ -20500,20 +20334,20 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
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_interpolated_xstring_node_append(parser->arena, 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 };
+ closing = (pm_token_t) { .type = 0, .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);
+ pm_interpolated_xstring_node_closing_set(parser, node, &closing);
- return (pm_node_t *) node;
+ return UP(node);
}
case PM_TOKEN_USTAR: {
parser_lex(parser);
@@ -20523,17 +20357,17 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
// 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);
+ return UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &parser->previous), PM_TOKEN_LENGTH(&parser->previous)));
}
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));
+ name = parse_expression(parser, PM_BINDING_POWER_INDEX, flags & PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
}
- pm_node_t *splat = (pm_node_t *) pm_splat_node_create(parser, &operator, name);
+ pm_node_t *splat = UP(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));
@@ -20549,11 +20383,11 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
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_node_t *receiver = parse_expression(parser, pm_binding_powers[parser->previous.type].right, (uint8_t) ((flags & PM_PARSE_ACCEPTS_DO_BLOCK) | (binding_power < PM_BINDING_POWER_MATCH ? PM_PARSE_ACCEPTS_COMMAND_CALL : 0)), 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;
+ return UP(node);
}
case PM_TOKEN_TILDE: {
if (binding_power > PM_BINDING_POWER_UNARY) {
@@ -20562,10 +20396,10 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
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_node_t *receiver = parse_expression(parser, pm_binding_powers[parser->previous.type].right, flags & PM_PARSE_ACCEPTS_DO_BLOCK, 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;
+ return UP(node);
}
case PM_TOKEN_UMINUS: {
if (binding_power > PM_BINDING_POWER_UNARY) {
@@ -20574,22 +20408,22 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
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_node_t *receiver = parse_expression(parser, pm_binding_powers[parser->previous.type].right, flags & PM_PARSE_ACCEPTS_DO_BLOCK, 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;
+ return UP(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));
+ pm_node_t *node = parse_expression(parser, pm_binding_powers[parser->previous.type].right, flags & PM_PARSE_ACCEPTS_DO_BLOCK, 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, "-@");
+ pm_node_t *exponent = parse_expression(parser, pm_binding_powers[exponent_operator.type].right, flags & PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_EXPECT_ARGUMENT, (uint16_t) (depth + 1));
+ node = UP(pm_call_node_binary_create(parser, node, &exponent_operator, exponent, 0));
+ node = UP(pm_call_node_unary_create(parser, &operator, node, "-@"));
} else {
switch (PM_NODE_TYPE(node)) {
case PM_INTEGER_NODE:
@@ -20599,7 +20433,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
parse_negative_numeric(node);
break;
default:
- node = (pm_node_t *) pm_call_node_unary_create(parser, &operator, node, "-@");
+ node = UP(pm_call_node_unary_create(parser, &operator, node, "-@"));
break;
}
}
@@ -20633,13 +20467,12 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
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);
+ pm_block_parameters_node_closing_set(parser, 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));
+ block_parameters = parse_block_parameters(parser, false, NULL, true, false, (uint16_t) (depth + 1));
pm_accepts_block_stack_pop(parser);
break;
}
@@ -20657,39 +20490,37 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
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));
+ body = UP(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);
+ expect1_opening(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_LAMBDA_TERM_BRACE, &opening);
} 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);
+ body = UP(parse_statements(parser, PM_CONTEXT_LAMBDA_DO_END, (uint16_t) (depth + 1)));
}
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));
+ body = UP(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);
+ expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_LAMBDA_TERM_END, &operator);
}
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_node_t *parameters = parse_blocklike_parameters(parser, UP(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);
+ return UP(pm_lambda_node_create(parser, &locals, &operator, &opening, &parser->previous, parameters, body));
}
case PM_TOKEN_UPLUS: {
if (binding_power > PM_BINDING_POWER_UNARY) {
@@ -20698,13 +20529,13 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
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_node_t *receiver = parse_expression(parser, pm_binding_powers[parser->previous.type].right, flags & PM_PARSE_ACCEPTS_DO_BLOCK, 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;
+ return UP(node);
}
case PM_TOKEN_STRING_BEGIN:
- return parse_strings(parser, NULL, accepts_label, (uint16_t) (depth + 1));
+ return parse_strings(parser, NULL, flags & PM_PARSE_ACCEPTS_LABEL, (uint16_t) (depth + 1));
case PM_TOKEN_SYMBOL_BEGIN: {
pm_lex_mode_t lex_mode = *parser->lex_modes.current;
parser_lex(parser);
@@ -20727,17 +20558,17 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
// 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));
+ PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_UNEXPECTED_TOKEN_CLOSE_CONTEXT, pm_token_str(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));
+ PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_UNEXPECTED_TOKEN_IGNORE, pm_token_str(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);
+ return UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &parser->previous), PM_TOKEN_LENGTH(&parser->previous)));
}
}
}
@@ -20752,8 +20583,18 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
* 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));
+parse_assignment_value(pm_parser_t *parser, pm_binding_power_t previous_binding_power, pm_binding_power_t binding_power, uint8_t flags, pm_diagnostic_id_t diag_id, uint16_t depth) {
+ pm_node_t *value = parse_value_expression(parser, binding_power, (uint8_t) ((flags & PM_PARSE_ACCEPTS_DO_BLOCK) | (previous_binding_power == PM_BINDING_POWER_ASSIGNMENT ? (flags & PM_PARSE_ACCEPTS_COMMAND_CALL) : (previous_binding_power < PM_BINDING_POWER_MATCH ? PM_PARSE_ACCEPTS_COMMAND_CALL : 0))), diag_id, (uint16_t) (depth + 1));
+
+ // Assignments whose value is a command call (e.g., a = b c) can only
+ // be followed by modifiers (if/unless/while/until/rescue) and not by
+ // operators with higher binding power. If we find one, emit an error
+ // and skip the operator and its right-hand side.
+ if (pm_binding_powers[parser->current.type].left > PM_BINDING_POWER_MODIFIER && (pm_command_call_value_p(value) || pm_block_call_p(value))) {
+ PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(parser->current.type));
+ parser_lex(parser);
+ parse_expression(parser, pm_binding_powers[parser->previous.type].right, flags & PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
+ }
// Contradicting binding powers, the right-hand-side value of the assignment
// allows the `rescue` modifier.
@@ -20763,10 +20604,10 @@ parse_assignment_value(pm_parser_t *parser, pm_binding_power_t previous_binding_
pm_token_t rescue = parser->current;
parser_lex(parser);
- pm_node_t *right = parse_expression(parser, pm_binding_powers[PM_TOKEN_KEYWORD_RESCUE_MODIFIER].right, false, false, PM_ERR_RESCUE_MODIFIER_VALUE, (uint16_t) (depth + 1));
+ pm_node_t *right = parse_expression(parser, pm_binding_powers[PM_TOKEN_KEYWORD_RESCUE_MODIFIER].right, flags & PM_PARSE_ACCEPTS_DO_BLOCK, 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 UP(pm_rescue_modifier_node_create(parser, value, &rescue, right));
}
return value;
@@ -20821,35 +20662,46 @@ parse_assignment_value_local(pm_parser_t *parser, const pm_node_t *node) {
* 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) {
+parse_assignment_values(pm_parser_t *parser, pm_binding_power_t previous_binding_power, pm_binding_power_t binding_power, uint8_t flags, 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));
+ pm_node_t *value = parse_starred_expression(parser, binding_power, (uint8_t) ((flags & PM_PARSE_ACCEPTS_DO_BLOCK) | (previous_binding_power == PM_BINDING_POWER_ASSIGNMENT ? (flags & PM_PARSE_ACCEPTS_COMMAND_CALL) : (previous_binding_power < PM_BINDING_POWER_MODIFIER ? PM_PARSE_ACCEPTS_COMMAND_CALL : 0))), 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))) {
+ // Block calls (command call + do block, e.g., `foo bar do end`) cannot
+ // be followed by a comma to form a multi-value RHS because each element
+ // of a multi-value assignment must be an `arg`, not a `block_call`.
+ if (previous_binding_power == PM_BINDING_POWER_STATEMENT && !pm_block_call_p(value) && (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;
+ pm_array_node_t *array = pm_array_node_create(parser, NULL);
+ pm_array_node_elements_append(parser->arena, array, value);
+ value = UP(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;
+ pm_array_node_elements_append(parser->arena, array, element);
+ if (PM_NODE_TYPE_P(element, PM_ERROR_RECOVERY_NODE)) break;
parse_assignment_value_local(parser, element);
}
}
+ // Assignments whose value is a command call (e.g., a = b c) can only
+ // be followed by modifiers (if/unless/while/until/rescue) and not by
+ // operators with higher binding power. If we find one, emit an error
+ // and skip the operator and its right-hand side.
+ if (single_value && pm_binding_powers[parser->current.type].left > PM_BINDING_POWER_MODIFIER && (pm_command_call_value_p(value) || pm_block_call_p(value))) {
+ PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(parser->current.type));
+ parser_lex(parser);
+ parse_expression(parser, pm_binding_powers[parser->previous.type].right, flags & PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
+ }
+
// 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)) {
@@ -20864,15 +20716,15 @@ parse_assignment_values(pm_parser_t *parser, pm_binding_power_t previous_binding
// 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)) {
+ if ((call_node->arguments != NULL) && (call_node->opening_loc.length == 0)) {
accepts_command_call_inner = true;
}
}
- pm_node_t *right = parse_expression(parser, pm_binding_powers[PM_TOKEN_KEYWORD_RESCUE_MODIFIER].right, accepts_command_call_inner, false, PM_ERR_RESCUE_MODIFIER_VALUE, (uint16_t) (depth + 1));
+ pm_node_t *right = parse_expression(parser, pm_binding_powers[PM_TOKEN_KEYWORD_RESCUE_MODIFIER].right, (uint8_t) ((flags & PM_PARSE_ACCEPTS_DO_BLOCK) | (accepts_command_call_inner ? PM_PARSE_ACCEPTS_COMMAND_CALL : 0)), 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 UP(pm_rescue_modifier_node_create(parser, value, &rescue, right));
}
return value;
@@ -20889,43 +20741,18 @@ 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);
+ pm_node_unreference(parser, UP(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);
+ pm_node_unreference(parser, UP(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;
-
-static inline const uint8_t *
+static PRISM_INLINE const uint8_t *
pm_named_capture_escape_hex(pm_buffer_t *unescaped, const uint8_t *cursor, const uint8_t *end) {
cursor++;
@@ -20946,7 +20773,7 @@ pm_named_capture_escape_hex(pm_buffer_t *unescaped, const uint8_t *cursor, const
return cursor;
}
-static inline const uint8_t *
+static PRISM_INLINE const uint8_t *
pm_named_capture_escape_octal(pm_buffer_t *unescaped, const uint8_t *cursor, const uint8_t *end) {
uint8_t value = (uint8_t) (*cursor - '0');
cursor++;
@@ -20965,8 +20792,8 @@ pm_named_capture_escape_octal(pm_buffer_t *unescaped, const uint8_t *cursor, con
return cursor;
}
-static inline const uint8_t *
-pm_named_capture_escape_unicode(pm_parser_t *parser, pm_buffer_t *unescaped, const uint8_t *cursor, const uint8_t *end) {
+static PRISM_INLINE const uint8_t *
+pm_named_capture_escape_unicode(pm_parser_t *parser, pm_buffer_t *unescaped, const uint8_t *cursor, const uint8_t *end, const pm_location_t *error_location) {
const uint8_t *start = cursor - 1;
cursor++;
@@ -20977,7 +20804,7 @@ pm_named_capture_escape_unicode(pm_parser_t *parser, pm_buffer_t *unescaped, con
if (*cursor != '{') {
size_t length = pm_strspn_hexadecimal_digit(cursor, MIN(end - cursor, 4));
- uint32_t value = escape_unicode(parser, cursor, length);
+ uint32_t value = escape_unicode(parser, cursor, length, error_location, 0);
if (!pm_buffer_append_unicode_codepoint(unescaped, value)) {
pm_buffer_append_string(unescaped, (const char *) start, (size_t) ((cursor + length) - start));
@@ -20997,7 +20824,10 @@ pm_named_capture_escape_unicode(pm_parser_t *parser, pm_buffer_t *unescaped, con
}
size_t length = pm_strspn_hexadecimal_digit(cursor, end - cursor);
- uint32_t value = escape_unicode(parser, cursor, length);
+ if (length == 0) {
+ break;
+ }
+ uint32_t value = escape_unicode(parser, cursor, length, error_location, 0);
(void) pm_buffer_append_unicode_codepoint(unescaped, value);
cursor += length;
@@ -21007,7 +20837,7 @@ pm_named_capture_escape_unicode(pm_parser_t *parser, pm_buffer_t *unescaped, con
}
static void
-pm_named_capture_escape(pm_parser_t *parser, pm_buffer_t *unescaped, const uint8_t *source, const size_t length, const uint8_t *cursor) {
+pm_named_capture_escape(pm_parser_t *parser, pm_buffer_t *unescaped, const uint8_t *source, const size_t length, const uint8_t *cursor, const pm_location_t *error_location) {
const uint8_t *end = source + length;
pm_buffer_append_string(unescaped, (const char *) source, (size_t) (cursor - source));
@@ -21025,7 +20855,7 @@ pm_named_capture_escape(pm_parser_t *parser, pm_buffer_t *unescaped, const uint8
cursor = pm_named_capture_escape_octal(unescaped, cursor, end);
break;
case 'u':
- cursor = pm_named_capture_escape_unicode(parser, unescaped, cursor, end);
+ cursor = pm_named_capture_escape_unicode(parser, unescaped, cursor, end, error_location);
break;
default:
pm_buffer_append_byte(unescaped, '\\');
@@ -21047,10 +20877,7 @@ pm_named_capture_escape(pm_parser_t *parser, pm_buffer_t *unescaped, const uint8
* 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;
+parse_regular_expression_named_capture(pm_parser_t *parser, const pm_string_t *capture, bool shared, pm_regexp_name_data_t *callback_data) {
pm_call_node_t *call = callback_data->call;
pm_constant_id_list_t *names = &callback_data->names;
@@ -21068,55 +20895,56 @@ parse_regular_expression_named_capture(const pm_string_t *capture, void *data) {
// unescaped, which is what we need.
const uint8_t *cursor = pm_memchr(source, '\\', length, parser->encoding_changed, parser->encoding);
if (PRISM_UNLIKELY(cursor != NULL)) {
- pm_named_capture_escape(parser, &unescaped, source, length, cursor);
+ pm_named_capture_escape(parser, &unescaped, source, length, cursor, shared ? NULL : &call->receiver->location);
source = (const uint8_t *) pm_buffer_value(&unescaped);
length = pm_buffer_length(&unescaped);
}
- pm_location_t location;
+ const uint8_t *start;
+ const uint8_t *end;
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)) {
- pm_buffer_free(&unescaped);
+ pm_buffer_cleanup(&unescaped);
return;
}
- if (callback_data->shared) {
+ if (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);
+ start = source;
+ end = source + length;
+ name = pm_parser_constant_id_raw(parser, start, 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();
+ start = parser->start + PM_NODE_START(call->receiver);
+ end = parser->start + PM_NODE_END(call->receiver);
+ uint8_t *memory = (uint8_t *) pm_arena_alloc(parser->arena, length, 1);
memcpy(memory, source, length);
- name = pm_parser_constant_id_owned(parser, (uint8_t *) memory, length);
+ name = pm_parser_constant_id_owned(parser, 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);
+ pm_constant_id_list_append(parser->arena, 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)) {
- pm_buffer_free(&unescaped);
+ pm_buffer_cleanup(&unescaped);
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);
+ pm_parser_local_add(parser, name, start, end, 0);
}
// Here we lazily create the MatchWriteNode since we know we're
@@ -21127,45 +20955,37 @@ parse_regular_expression_named_capture(const pm_string_t *capture, void *data) {
// 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);
+ pm_node_t *target = UP(pm_local_variable_target_node_create(parser, &TOK2LOC(parser, &((pm_token_t) { .type = 0, .start = start, .end = end })), name, depth == -1 ? 0 : (uint32_t) depth));
+ pm_node_list_append(parser->arena, &callback_data->match->targets, target);
}
- pm_buffer_free(&unescaped);
+ pm_buffer_cleanup(&unescaped);
}
/**
- * Potentially change a =~ with a regular expression with named captures into a
- * match write node.
+ * Potentially change a =~ with an interpolated regular expression with named
+ * captures into a match write node. This is for the interpolated case where
+ * we have concatenated content rather than a regular expression 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,
+parse_interpolated_regular_expression_named_captures(pm_parser_t *parser, const pm_string_t *content, pm_call_node_t *call, bool extended_mode) {
+ pm_regexp_name_data_t callback_data = {
.call = call,
+ .match = NULL,
.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);
+ pm_regexp_parse_named_captures(parser, pm_string_source(content), pm_string_length(content), false, extended_mode, parse_regular_expression_named_capture, &callback_data);
if (callback_data.match != NULL) {
- return (pm_node_t *) callback_data.match;
+ return UP(callback_data.match);
} else {
- return (pm_node_t *) call;
+ return UP(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) {
+static PRISM_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, uint8_t flags, uint16_t depth) {
pm_token_t token = parser->current;
switch (token.type) {
@@ -21178,7 +20998,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
// 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);
+ pm_parser_local_add_location(parser, &call_node->message_loc, 0);
}
}
PRISM_FALLTHROUGH
@@ -21187,11 +21007,11 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
// variable before parsing the value, in case the value
// references the variable.
if (PM_NODE_TYPE_P(node, PM_IT_LOCAL_VARIABLE_READ_NODE)) {
- pm_parser_local_add_location(parser, node->location.start, node->location.end, 0);
+ pm_parser_local_add_location(parser, &node->location, 0);
}
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));
+ 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, flags, 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);
@@ -21204,8 +21024,8 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
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);
+ pm_node_t *value = parse_assignment_values(parser, previous_binding_power, PM_BINDING_POWER_MULTI_ASSIGNMENT + 1, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_EQUAL, (uint16_t) (depth + 1));
+ return parse_write(parser, UP(multi_target), &token, value);
}
case PM_SOURCE_ENCODING_NODE:
case PM_FALSE_NODE:
@@ -21217,7 +21037,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
// 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));
+ pm_node_t *value = parse_assignment_values(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_EQUAL, (uint16_t) (depth + 1));
return parse_unwriteable_write(parser, node, &token, value);
}
default:
@@ -21238,71 +21058,65 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
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_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
+ pm_node_t *result = UP(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_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
+ pm_node_t *result = UP(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);
+ pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
+ pm_node_t *write = UP(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_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
+ pm_node_t *write = UP(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_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
+ pm_node_t *result = UP(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_IT_LOCAL_VARIABLE_READ_NODE: {
pm_constant_id_t name = pm_parser_local_add_constant(parser, "it", 2);
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, name, 0);
+ pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
+ pm_node_t *result = UP(pm_local_variable_and_write_node_create(parser, node, &token, value, name, 0));
- parse_target_implicit_parameter(parser, node);
- pm_node_destroy(parser, node);
+ pm_node_unreference(parser, node);
return result;
}
case PM_LOCAL_VARIABLE_READ_NODE: {
- if (pm_token_is_numbered_parameter(node->location.start, node->location.end)) {
- PM_PARSER_ERR_FORMAT(parser, node->location.start, node->location.end, PM_ERR_PARAMETER_NUMBERED_RESERVED, node->location.start);
- parse_target_implicit_parameter(parser, node);
+ if (pm_token_is_numbered_parameter(parser, PM_NODE_START(node), PM_NODE_LENGTH(node))) {
+ PM_PARSER_ERR_FORMAT(parser, node->location.start, node->location.length, PM_ERR_PARAMETER_NUMBERED_RESERVED, parser->start + node->location.start);
+ pm_node_unreference(parser, 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_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
+ pm_node_t *result = UP(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: {
@@ -21312,16 +21126,13 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
// 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_refute_numbered_parameter(parser, cast->message_loc.start, cast->message_loc.length);
+ pm_constant_id_t constant_id = pm_parser_local_add_location(parser, &cast->message_loc, 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_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
+ pm_node_t *result = UP(pm_local_variable_and_write_node_create(parser, UP(cast), &token, value, constant_id, 0));
- pm_node_destroy(parser, (pm_node_t *) cast);
return result;
}
@@ -21333,8 +21144,8 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
// 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);
+ pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
+ return UP(pm_index_and_write_node_create(parser, cast, &token, value));
}
// If this node cannot be writable, then we have an error.
@@ -21345,8 +21156,8 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
}
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);
+ pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
+ return UP(pm_call_and_write_node_create(parser, cast, &token, value));
}
case PM_MULTI_WRITE_NODE: {
parser_lex(parser);
@@ -21372,71 +21183,65 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
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_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
+ pm_node_t *result = UP(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_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
+ pm_node_t *result = UP(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);
+ pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
+ pm_node_t *write = UP(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_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
+ pm_node_t *write = UP(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_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
+ pm_node_t *result = UP(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_IT_LOCAL_VARIABLE_READ_NODE: {
pm_constant_id_t name = pm_parser_local_add_constant(parser, "it", 2);
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, name, 0);
+ pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
+ pm_node_t *result = UP(pm_local_variable_or_write_node_create(parser, node, &token, value, name, 0));
- parse_target_implicit_parameter(parser, node);
- pm_node_destroy(parser, node);
+ pm_node_unreference(parser, node);
return result;
}
case PM_LOCAL_VARIABLE_READ_NODE: {
- if (pm_token_is_numbered_parameter(node->location.start, node->location.end)) {
- PM_PARSER_ERR_FORMAT(parser, node->location.start, node->location.end, PM_ERR_PARAMETER_NUMBERED_RESERVED, node->location.start);
- parse_target_implicit_parameter(parser, node);
+ if (pm_token_is_numbered_parameter(parser, PM_NODE_START(node), PM_NODE_LENGTH(node))) {
+ PM_PARSER_ERR_FORMAT(parser, PM_NODE_START(node), PM_NODE_LENGTH(node), PM_ERR_PARAMETER_NUMBERED_RESERVED, parser->start + PM_NODE_START(node));
+ pm_node_unreference(parser, 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_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
+ pm_node_t *result = UP(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: {
@@ -21446,16 +21251,13 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
// 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_refute_numbered_parameter(parser, cast->message_loc.start, cast->message_loc.length);
+ pm_constant_id_t constant_id = pm_parser_local_add_location(parser, &cast->message_loc, 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_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
+ pm_node_t *result = UP(pm_local_variable_or_write_node_create(parser, UP(cast), &token, value, constant_id, 0));
- pm_node_destroy(parser, (pm_node_t *) cast);
return result;
}
@@ -21467,8 +21269,8 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
// 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);
+ pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
+ return UP(pm_index_or_write_node_create(parser, cast, &token, value));
}
// If this node cannot be writable, then we have an error.
@@ -21479,8 +21281,8 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
}
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);
+ pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
+ return UP(pm_call_or_write_node_create(parser, cast, &token, value));
}
case PM_MULTI_WRITE_NODE: {
parser_lex(parser);
@@ -21516,71 +21318,65 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
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_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
+ pm_node_t *result = UP(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_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
+ pm_node_t *result = UP(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);
+ pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
+ pm_node_t *write = UP(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_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
+ pm_node_t *write = UP(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_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
+ pm_node_t *result = UP(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_IT_LOCAL_VARIABLE_READ_NODE: {
pm_constant_id_t name = pm_parser_local_add_constant(parser, "it", 2);
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, name, 0);
+ pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
+ pm_node_t *result = UP(pm_local_variable_operator_write_node_create(parser, node, &token, value, name, 0));
- parse_target_implicit_parameter(parser, node);
- pm_node_destroy(parser, node);
+ pm_node_unreference(parser, node);
return result;
}
case PM_LOCAL_VARIABLE_READ_NODE: {
- if (pm_token_is_numbered_parameter(node->location.start, node->location.end)) {
- PM_PARSER_ERR_FORMAT(parser, node->location.start, node->location.end, PM_ERR_PARAMETER_NUMBERED_RESERVED, node->location.start);
- parse_target_implicit_parameter(parser, node);
+ if (pm_token_is_numbered_parameter(parser, PM_NODE_START(node), PM_NODE_LENGTH(node))) {
+ PM_PARSER_ERR_FORMAT(parser, PM_NODE_START(node), PM_NODE_LENGTH(node), PM_ERR_PARAMETER_NUMBERED_RESERVED, parser->start + PM_NODE_START(node));
+ pm_node_unreference(parser, 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_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
+ pm_node_t *result = UP(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: {
@@ -21591,14 +21387,11 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
// 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_refute_numbered_parameter(parser, cast->message_loc.start, cast->message_loc.length);
+ pm_constant_id_t constant_id = pm_parser_local_add_location(parser, &cast->message_loc, 1);
+ pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
+ pm_node_t *result = UP(pm_local_variable_operator_write_node_create(parser, UP(cast), &token, value, constant_id, 0));
- pm_node_destroy(parser, (pm_node_t *) cast);
return result;
}
@@ -21606,8 +21399,8 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
// 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);
+ pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
+ return UP(pm_index_operator_write_node_create(parser, cast, &token, value));
}
// If this node cannot be writable, then we have an error.
@@ -21618,8 +21411,8 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
}
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);
+ pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
+ return UP(pm_call_operator_write_node_create(parser, cast, &token, value));
}
case PM_MULTI_WRITE_NODE: {
parser_lex(parser);
@@ -21632,7 +21425,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
// 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));
+ PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->previous, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, pm_token_str(parser->current.type));
return node;
}
}
@@ -21640,15 +21433,15 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
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);
+ pm_node_t *right = parse_expression(parser, binding_power, (uint8_t) ((flags & PM_PARSE_ACCEPTS_DO_BLOCK) | (parser->previous.type == PM_TOKEN_KEYWORD_AND ? PM_PARSE_ACCEPTS_COMMAND_CALL : 0)), PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
+ return UP(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);
+ pm_node_t *right = parse_expression(parser, binding_power, (uint8_t) ((flags & PM_PARSE_ACCEPTS_DO_BLOCK) | (parser->previous.type == PM_TOKEN_KEYWORD_OR ? PM_PARSE_ACCEPTS_COMMAND_CALL : 0)), PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
+ return UP(pm_or_node_create(parser, node, &token, right));
}
case PM_TOKEN_EQUAL_TILDE: {
// Note that we _must_ parse the value before adding the local
@@ -21659,11 +21452,11 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
//
// 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));
+ pm_node_t *argument = parse_expression(parser, binding_power, flags & PM_PARSE_ACCEPTS_DO_BLOCK, 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;
+ pm_node_t *result = UP(call);
// If the receiver of this =~ is a regular expression node, then we
// need to introduce local variables for it based on its named
@@ -21704,14 +21497,25 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
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);
+ result = parse_interpolated_regular_expression_named_captures(parser, &owned, call, PM_NODE_FLAG_P(node, PM_REGULAR_EXPRESSION_FLAGS_EXTENDED));
+ pm_string_cleanup(&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));
+ // If we have a regular expression node, then we can parse
+ // the named captures and validate encoding in one pass.
+ pm_regular_expression_node_t *regexp = (pm_regular_expression_node_t *) node;
+
+ pm_regexp_name_data_t name_data = {
+ .call = call,
+ .match = NULL,
+ .names = { 0 },
+ };
+
+ pm_node_flag_set(UP(regexp), pm_regexp_parse(parser, regexp, parse_regular_expression_named_capture, &name_data));
+
+ if (name_data.match != NULL) {
+ result = UP(name_data.match);
+ }
}
return result;
@@ -21743,21 +21547,21 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
case PM_RESCUE_MODIFIER_NODE: {
pm_rescue_modifier_node_t *cast = (pm_rescue_modifier_node_t *) node;
if (PM_NODE_TYPE_P(cast->rescue_expression, PM_MATCH_PREDICATE_NODE) || PM_NODE_TYPE_P(cast->rescue_expression, PM_MATCH_REQUIRED_NODE)) {
- PM_PARSER_ERR_TOKEN_FORMAT(parser, operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_type_human(operator.type));
+ PM_PARSER_ERR_TOKEN_FORMAT(parser, &operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(operator.type));
}
break;
}
case PM_AND_NODE: {
pm_and_node_t *cast = (pm_and_node_t *) node;
if (PM_NODE_TYPE_P(cast->right, PM_MATCH_PREDICATE_NODE) || PM_NODE_TYPE_P(cast->right, PM_MATCH_REQUIRED_NODE)) {
- PM_PARSER_ERR_TOKEN_FORMAT(parser, operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_type_human(operator.type));
+ PM_PARSER_ERR_TOKEN_FORMAT(parser, &operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(operator.type));
}
break;
}
case PM_OR_NODE: {
pm_or_node_t *cast = (pm_or_node_t *) node;
if (PM_NODE_TYPE_P(cast->right, PM_MATCH_PREDICATE_NODE) || PM_NODE_TYPE_P(cast->right, PM_MATCH_REQUIRED_NODE)) {
- PM_PARSER_ERR_TOKEN_FORMAT(parser, operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_type_human(operator.type));
+ PM_PARSER_ERR_TOKEN_FORMAT(parser, &operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(operator.type));
}
break;
}
@@ -21765,20 +21569,20 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
break;
}
- 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);
+ pm_node_t *argument = parse_expression(parser, binding_power, flags & PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
+ return UP(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);
+ 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);
+ pm_node_t *argument = parse_expression(parser, binding_power, flags & PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
+ return UP(pm_call_node_binary_create(parser, node, &token, argument, PM_CALL_NODE_FLAGS_COMPARISON));
}
case PM_TOKEN_AMPERSAND_DOT:
case PM_TOKEN_DOT: {
@@ -21789,28 +21593,28 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
// 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);
+ return UP(pm_call_node_shorthand_create(parser, node, &operator, &arguments));
}
switch (PM_NODE_TYPE(node)) {
case PM_RESCUE_MODIFIER_NODE: {
pm_rescue_modifier_node_t *cast = (pm_rescue_modifier_node_t *) node;
if (PM_NODE_TYPE_P(cast->rescue_expression, PM_MATCH_PREDICATE_NODE) || PM_NODE_TYPE_P(cast->rescue_expression, PM_MATCH_REQUIRED_NODE)) {
- PM_PARSER_ERR_TOKEN_FORMAT(parser, operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_type_human(operator.type));
+ PM_PARSER_ERR_TOKEN_FORMAT(parser, &operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(operator.type));
}
break;
}
case PM_AND_NODE: {
pm_and_node_t *cast = (pm_and_node_t *) node;
if (PM_NODE_TYPE_P(cast->right, PM_MATCH_PREDICATE_NODE) || PM_NODE_TYPE_P(cast->right, PM_MATCH_REQUIRED_NODE)) {
- PM_PARSER_ERR_TOKEN_FORMAT(parser, operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_type_human(operator.type));
+ PM_PARSER_ERR_TOKEN_FORMAT(parser, &operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(operator.type));
}
break;
}
case PM_OR_NODE: {
pm_or_node_t *cast = (pm_or_node_t *) node;
if (PM_NODE_TYPE_P(cast->right, PM_MATCH_PREDICATE_NODE) || PM_NODE_TYPE_P(cast->right, PM_MATCH_REQUIRED_NODE)) {
- PM_PARSER_ERR_TOKEN_FORMAT(parser, operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_type_human(operator.type));
+ PM_PARSER_ERR_TOKEN_FORMAT(parser, &operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(operator.type));
}
break;
}
@@ -21831,23 +21635,23 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
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 };
+ PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_EXPECT_MESSAGE, pm_token_str(parser->current.type));
+ message = (pm_token_t) { .type = 0, .start = parser->previous.end, .end = parser->previous.end };
}
}
- parse_arguments_list(parser, &arguments, true, accepts_command_call, (uint16_t) (depth + 1));
+ parse_arguments_list(parser, &arguments, true, flags, (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 &&
+ arguments.opening_loc.length == 0 &&
match1(parser, PM_TOKEN_COMMA)
) {
- return parse_targets_validate(parser, (pm_node_t *) call, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
+ return parse_targets_validate(parser, UP(call), PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
} else {
- return (pm_node_t *) call;
+ return UP(call);
}
}
case PM_TOKEN_DOT_DOT:
@@ -21856,40 +21660,40 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
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));
+ right = parse_expression(parser, binding_power, flags & PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
}
- return (pm_node_t *) pm_range_node_create(parser, node, &token, right);
+ return UP(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);
+ pm_node_t *predicate = parse_value_expression(parser, binding_power, (uint8_t) ((flags & PM_PARSE_ACCEPTS_DO_BLOCK) | PM_PARSE_ACCEPTS_COMMAND_CALL), PM_ERR_CONDITIONAL_IF_PREDICATE, (uint16_t) (depth + 1));
+ return UP(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);
+ pm_node_t *predicate = parse_value_expression(parser, binding_power, (uint8_t) ((flags & PM_PARSE_ACCEPTS_DO_BLOCK) | PM_PARSE_ACCEPTS_COMMAND_CALL), PM_ERR_CONDITIONAL_UNLESS_PREDICATE, (uint16_t) (depth + 1));
+ return UP(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);
+ pm_node_t *predicate = parse_value_expression(parser, binding_power, (uint8_t) ((flags & PM_PARSE_ACCEPTS_DO_BLOCK) | PM_PARSE_ACCEPTS_COMMAND_CALL), PM_ERR_CONDITIONAL_UNTIL_PREDICATE, (uint16_t) (depth + 1));
+ return UP(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);
+ pm_node_t *predicate = parse_value_expression(parser, binding_power, (uint8_t) ((flags & PM_PARSE_ACCEPTS_DO_BLOCK) | PM_PARSE_ACCEPTS_COMMAND_CALL), PM_ERR_CONDITIONAL_WHILE_PREDICATE, (uint16_t) (depth + 1));
+ return UP(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);
@@ -21899,7 +21703,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
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));
+ pm_node_t *true_expression = parse_expression(parser, PM_BINDING_POWER_DEFINED, flags & PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_TERNARY_EXPRESSION_TRUE, (uint16_t) (depth + 1));
if (parser->recovering) {
// If parsing the true expression of this ternary resulted in a syntax
@@ -21908,27 +21712,23 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
// 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);
+ pm_token_t colon = (pm_token_t) { .type = 0, .start = parser->previous.end, .end = parser->previous.end };
+ pm_node_t *false_expression = UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &colon), PM_TOKEN_LENGTH(&colon)));
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);
+ return UP(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));
+ pm_node_t *false_expression = parse_expression(parser, PM_BINDING_POWER_DEFINED, flags & PM_PARSE_ACCEPTS_DO_BLOCK, 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);
+ return UP(pm_if_node_ternary_create(parser, node, &qmark, true_expression, &colon, false_expression));
}
case PM_TOKEN_COLON_COLON: {
parser_lex(parser);
@@ -21941,7 +21741,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
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)))
+ ((flags & PM_PARSE_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
@@ -21952,11 +21752,11 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
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);
+ parse_arguments_list(parser, &arguments, true, flags, (uint16_t) (depth + 1));
+ path = UP(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);
+ path = UP(pm_constant_path_node_create(parser, node, &delimiter, &parser->previous));
}
// If this is followed by a comma then it is a multiple assignment.
@@ -21976,15 +21776,15 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
// 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));
+ parse_arguments_list(parser, &arguments, true, flags, (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 parse_targets_validate(parser, UP(call), PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
}
- return (pm_node_t *) call;
+ return UP(call);
}
case PM_TOKEN_PARENTHESIS_LEFT: {
// If we have a parenthesis following a '::' operator, then it is the
@@ -21992,11 +21792,11 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
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);
+ return UP(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);
+ return UP(pm_constant_path_node_create(parser, node, &delimiter, &parser->previous));
}
}
}
@@ -22005,31 +21805,31 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
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));
+ pm_node_t *value = parse_expression(parser, binding_power, (uint8_t) ((flags & PM_PARSE_ACCEPTS_DO_BLOCK) | PM_PARSE_ACCEPTS_COMMAND_CALL), 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);
+ return UP(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);
+ arguments.opening_loc = TOK2LOC(parser, &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));
+ parse_arguments(parser, &arguments, false, PM_TOKEN_BRACKET_RIGHT, (uint8_t) (flags & ~PM_PARSE_ACCEPTS_DO_BLOCK), (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);
+ arguments.closing_loc = TOK2LOC(parser, &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));
+ return parse_targets_validate(parser, UP(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
@@ -22045,17 +21845,17 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
if (block != NULL) {
if (arguments.block != NULL) {
- pm_parser_err_node(parser, (pm_node_t *) block, PM_ERR_ARGUMENT_AFTER_BLOCK);
+ pm_parser_err_node(parser, UP(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);
+ pm_arguments_node_arguments_append(parser->arena, arguments.arguments, arguments.block);
}
- arguments.block = (pm_node_t *) block;
+ arguments.block = UP(block);
}
- return (pm_node_t *) pm_call_node_aref_create(parser, node, &arguments);
+ return UP(pm_call_node_aref_create(parser, node, &arguments));
}
case PM_TOKEN_KEYWORD_IN: {
bool previous_pattern_matching_newlines = parser->pattern_matching_newlines;
@@ -22070,9 +21870,8 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
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);
+ return UP(pm_match_predicate_node_create(parser, node, pattern, &operator));
}
case PM_TOKEN_EQUAL_GREATER: {
bool previous_pattern_matching_newlines = parser->pattern_matching_newlines;
@@ -22087,9 +21886,8 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
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);
+ return UP(pm_match_required_node_create(parser, node, pattern, &operator));
}
default:
assert(false && "unreachable");
@@ -22102,16 +21900,83 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
#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.
+ * Some nodes act as statements and limit which operators can follow. This
+ * function inspects the node and the upcoming token to determine whether the
+ * expression loop should stop. It is called both after prefix parsing and after
+ * each infix operator.
+ *
+ * As a side effect, this function also attaches do-blocks to command-style call
+ * nodes when appropriate.
+ *
+ * Returns true if the expression loop should stop (i.e., the next operator
+ * should not be consumed).
*/
-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)
- );
+static bool
+parse_expression_terminator(pm_parser_t *parser, pm_node_t *node) {
+ pm_binding_power_t left = pm_binding_powers[parser->current.type].left;
+
+ switch (PM_NODE_TYPE(node)) {
+ case PM_MULTI_WRITE_NODE:
+ case PM_RETURN_NODE:
+ case PM_BREAK_NODE:
+ case PM_NEXT_NODE:
+ return left > PM_BINDING_POWER_MODIFIER;
+ 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:
+ return PM_NODE_FLAG_P(node, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY) && left > PM_BINDING_POWER_MODIFIER;
+ case PM_CALL_NODE: {
+ // Calls with an implicit array on the right-hand side are
+ // statements and can only be followed by modifiers.
+ if (PM_NODE_FLAG_P(node, PM_CALL_NODE_FLAGS_IMPLICIT_ARRAY)) {
+ return left > PM_BINDING_POWER_MODIFIER;
+ }
+
+ // Command-style calls (including block commands like
+ // `foo bar do end`) can only be followed by composition
+ // (and/or) and modifier (if/unless/etc.) operators.
+ if (pm_command_call_value_p(node)) {
+ return left > PM_BINDING_POWER_COMPOSITION;
+ }
+
+ // A block call (command with do-block, or any call chained
+ // from one) can only be followed by call chaining (., ::,
+ // &.), composition (and/or), and modifier operators.
+ if (pm_block_call_p(node)) {
+ return left > PM_BINDING_POWER_COMPOSITION && left < PM_BINDING_POWER_CALL;
+ }
+
+ return false;
+ }
+ case PM_SUPER_NODE:
+ case PM_YIELD_NODE:
+ // Command-style super/yield (without parens) can only be followed
+ // by composition and modifier operators.
+ if (pm_command_call_value_p(node)) {
+ return left > PM_BINDING_POWER_COMPOSITION;
+ }
+ return false;
+ case PM_DEF_NODE:
+ // An endless method whose body is a command-style call (e.g.,
+ // `def f = foo bar`) is a command assignment and can only be
+ // followed by modifiers.
+ return left > PM_BINDING_POWER_MODIFIER && pm_command_call_value_p(node);
+ case PM_RESCUE_MODIFIER_NODE:
+ // A rescue modifier whose handler is a pattern match (=> or in)
+ // produces a statement and cannot be followed by operators above
+ // the modifier level.
+ if (left > PM_BINDING_POWER_MODIFIER) {
+ pm_rescue_modifier_node_t *cast = (pm_rescue_modifier_node_t *) node;
+ pm_node_t *rescue_expression = cast->rescue_expression;
+ return PM_NODE_TYPE_P(rescue_expression, PM_MATCH_REQUIRED_NODE) || PM_NODE_TYPE_P(rescue_expression, PM_MATCH_PREDICATE_NODE);
+ }
+ return false;
+ default:
+ return false;
+ }
}
/**
@@ -22123,46 +21988,40 @@ pm_call_node_command_p(const pm_call_node_t *node) {
* 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) {
+parse_expression(pm_parser_t *parser, pm_binding_power_t binding_power, uint8_t flags, 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);
+ return UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current)));
}
- pm_node_t *node = parse_expression_prefix(parser, binding_power, accepts_command_call, accepts_label, diag_id, depth);
+ pm_node_t *node = parse_expression_prefix(parser, binding_power, flags, diag_id, depth);
+ // Some prefix nodes are statements and can only be followed by modifiers
+ // (if/unless/while/until/rescue) or nothing at all. We check these cheaply
+ // here before entering the infix loop.
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.
+ case PM_ERROR_RECOVERY_NODE:
return node;
case PM_PRE_EXECUTION_NODE:
+ return 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)) {
+ case PM_SUPER_NODE:
+ case PM_YIELD_NODE:
+ case PM_DEF_NODE:
+ if (parse_expression_terminator(parser, 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)) {
+ if (pm_symbol_node_label_p(parser, node)) {
return node;
}
break;
@@ -22170,8 +22029,8 @@ parse_expression(pm_parser_t *parser, pm_binding_power_t binding_power, bool acc
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.
+ // 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;
pm_token_type_t current_token_type;
@@ -22181,45 +22040,8 @@ parse_expression(pm_parser_t *parser, pm_binding_power_t binding_power, bool acc
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));
-
- if (context_terminator(parser->current_context->context, &parser->current)) {
- // If this token terminates the current context, then we need to
- // stop parsing the expression, as it has become a statement.
- return node;
- }
-
- 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;
- }
+ node = parse_expression_infix(parser, node, binding_power, current_binding_powers.right, flags, (uint16_t) (depth + 1));
+ if (parse_expression_terminator(parser, node)) return node;
// If the operator is nonassoc and we should not be able to parse the
// upcoming infix operator, break.
@@ -22227,7 +22049,7 @@ parse_expression(pm_parser_t *parser, pm_binding_power_t binding_power, bool acc
// If this is a non-assoc operator and we are about to parse the
// exact same operator, then we need to add an error.
if (match1(parser, current_token_type)) {
- PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_NON_ASSOCIATIVE_OPERATOR, pm_token_type_human(parser->current.type), pm_token_type_human(current_token_type));
+ PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_NON_ASSOCIATIVE_OPERATOR, pm_token_str(parser->current.type), pm_token_str(current_token_type));
break;
}
@@ -22240,7 +22062,7 @@ parse_expression(pm_parser_t *parser, pm_binding_power_t binding_power, bool acc
//
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(current_token_type));
+ PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_NON_ASSOCIATIVE_OPERATOR, pm_token_str(parser->current.type), pm_token_str(current_token_type));
break;
}
@@ -22252,7 +22074,7 @@ parse_expression(pm_parser_t *parser, pm_binding_power_t binding_power, bool acc
}
}
- if (accepts_command_call) {
+ if (flags & PM_PARSE_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:
@@ -22267,29 +22089,29 @@ parse_expression(pm_parser_t *parser, pm_binding_power_t binding_power, bool acc
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] == ']'
+ cast->call_operator_loc.length == 0 &&
+ cast->message_loc.length > 0 &&
+ parser->start[cast->message_loc.start] == '[' &&
+ parser->start[cast->message_loc.start + cast->message_loc.length - 1] == ']'
) &&
// (2) foo.bar
!(
- cast->call_operator_loc.start != NULL &&
+ cast->call_operator_loc.length > 0 &&
cast->arguments == NULL &&
cast->block == NULL &&
- cast->opening_loc.start == NULL
+ cast->opening_loc.length == 0
) &&
// (3) foo.bar(1)
!(
- cast->call_operator_loc.start != NULL &&
- cast->opening_loc.start != NULL
+ cast->call_operator_loc.length > 0 &&
+ cast->opening_loc.length > 0
) &&
// (4) foo.bar do end
!(
cast->block != NULL && PM_NODE_TYPE_P(cast->block, PM_BLOCK_NODE)
)
) {
- accepts_command_call = false;
+ flags &= (uint8_t) ~PM_PARSE_ACCEPTS_COMMAND_CALL;
}
break;
}
@@ -22297,10 +22119,21 @@ parse_expression(pm_parser_t *parser, pm_binding_power_t binding_power, bool acc
case PM_CONSTANT_PATH_NODE:
break;
default:
- accepts_command_call = false;
+ flags &= (uint8_t) ~PM_PARSE_ACCEPTS_COMMAND_CALL;
break;
}
}
+
+ if (context_terminator(parser->current_context->context, &parser->current)) {
+ pm_binding_powers_t next_binding_powers = pm_binding_powers[parser->current.type];
+ if (
+ !next_binding_powers.binary ||
+ binding_power > next_binding_powers.left ||
+ (PM_NODE_TYPE_P(node, PM_CALL_NODE) && pm_call_node_command_p((pm_call_node_t *) node))
+ ) {
+ return node;
+ }
+ }
}
return node;
@@ -22319,15 +22152,16 @@ wrap_statements(pm_parser_t *parser, pm_statements_node_t *statements) {
pm_arguments_node_t *arguments = pm_arguments_node_create(parser);
pm_arguments_node_arguments_append(
+ parser->arena,
arguments,
- (pm_node_t *) pm_global_variable_read_node_synthesized_create(parser, pm_parser_constant_id_constant(parser, "$_", 2))
+ UP(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(
+ pm_statements_node_body_append(parser, statements, UP(pm_call_node_fcall_synthesized_create(
parser,
arguments,
pm_parser_constant_id_constant(parser, "print", 5)
- ), true);
+ )), true);
}
if (PM_PARSER_COMMAND_LINE_OPTION_N(parser)) {
@@ -22338,47 +22172,49 @@ wrap_statements(pm_parser_t *parser, pm_statements_node_t *statements) {
pm_arguments_node_t *arguments = pm_arguments_node_create(parser);
pm_arguments_node_arguments_append(
+ parser->arena,
arguments,
- (pm_node_t *) pm_global_variable_read_node_synthesized_create(parser, pm_parser_constant_id_constant(parser, "$;", 2))
+ UP(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_call_node_t *call = pm_call_node_call_synthesized_create(parser, UP(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
+ UP(call)
);
- pm_statements_node_body_prepend(statements, (pm_node_t *) write);
+ pm_statements_node_body_prepend(parser->arena, statements, UP(write));
}
pm_arguments_node_t *arguments = pm_arguments_node_create(parser);
pm_arguments_node_arguments_append(
+ parser->arena,
arguments,
- (pm_node_t *) pm_global_variable_read_node_synthesized_create(parser, pm_parser_constant_id_constant(parser, "$/", 2))
+ UP(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(
+ pm_keyword_hash_node_elements_append(parser->arena, keywords, UP(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)
- ));
+ UP(pm_symbol_node_synthesized_create(parser, "chomp")),
+ NULL,
+ UP(pm_true_node_synthesized_create(parser))
+ )));
- pm_arguments_node_arguments_append(arguments, (pm_node_t *) keywords);
- pm_node_flag_set((pm_node_t *) arguments, PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORDS);
+ pm_arguments_node_arguments_append(parser->arena, arguments, UP(keywords));
+ pm_node_flag_set(UP(arguments), PM_ARGUMENTS_NODE_FLAGS_CONTAINS_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(
+ pm_statements_node_body_append(parser, wrapped_statements, UP(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)),
+ UP(pm_call_node_fcall_synthesized_create(parser, arguments, pm_parser_constant_id_constant(parser, "gets", 4))),
statements
- ), true);
+ )), true);
statements = wrapped_statements;
}
@@ -22422,7 +22258,6 @@ parse_program(pm_parser_t *parser) {
statements = wrap_statements(parser, statements);
} else {
flush_block_exits(parser, previous_block_exits);
- pm_node_list_free(&current_block_exits);
}
// If this is an empty file, then we're still going to parse all of the
@@ -22430,10 +22265,10 @@ parse_program(pm_parser_t *parser) {
// correct the location information.
if (statements == NULL) {
statements = pm_statements_node_create(parser);
- pm_statements_node_location_set(statements, parser->start, parser->start);
+ statements->base.location = (pm_location_t) { 0 };
}
- return (pm_node_t *) pm_program_node_create(parser, &locals, statements);
+ return UP(pm_program_node_create(parser, &locals, statements));
}
/******************************************************************************/
@@ -22442,8 +22277,8 @@ parse_program(pm_parser_t *parser) {
/**
* 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.
+ * string with a given length. This function is used to search for "ruby"
+ * 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
@@ -22453,7 +22288,7 @@ 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++) {
+ for (const char *max = big + big_length - little_length; big <= max; big++) {
if (*big == *little && memcmp(big, little, little_length) == 0) return big;
}
@@ -22471,7 +22306,7 @@ pm_strnstr(const char *big, const char *little, size_t big_length) {
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);
+ pm_parser_warn(parser, U32(start - parser->start), U32(length), PM_WARN_SHEBANG_CARRIAGE_RETURN);
}
}
#endif
@@ -22506,11 +22341,14 @@ pm_parser_init_shebang(pm_parser_t *parser, const pm_options_t *options, const c
/**
* 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) {
+void
+pm_parser_init(pm_arena_t *arena, pm_parser_t *parser, const uint8_t *source, size_t size, const pm_options_t *options) {
+ assert(arena != NULL);
assert(source != NULL);
*parser = (pm_parser_t) {
+ .arena = arena,
+ .metadata_arena = { 0 },
.node_id = 0,
.lex_state = PM_LEX_STATE_BEG,
.enclosure_nesting = 0,
@@ -22529,7 +22367,7 @@ pm_parser_init(pm_parser_t *parser, const uint8_t *source, size_t size, const pm
.current = { .type = PM_TOKEN_EOF, .start = source, .end = source },
.next_start = NULL,
.heredoc_end = NULL,
- .data_loc = { .start = NULL, .end = NULL },
+ .data_loc = { 0 },
.comment_list = { 0 },
.magic_comment_list = { 0 },
.warning_list = { 0 },
@@ -22539,11 +22377,11 @@ pm_parser_init(pm_parser_t *parser, const uint8_t *source, size_t size, const pm
.encoding = PM_ENCODING_UTF_8_ENTRY,
.encoding_changed_callback = NULL,
.encoding_comment_start = source,
- .lex_callback = NULL,
+ .lex_callback = { 0 },
.filepath = { 0 },
.constant_pool = { 0 },
- .newline_list = { 0 },
- .integer_base = 0,
+ .line_offsets = { 0 },
+ .integer = { 0 },
.current_string = PM_STRING_EMPTY,
.start_line = 1,
.explicit_encoding = NULL,
@@ -22552,6 +22390,7 @@ pm_parser_init(pm_parser_t *parser, const uint8_t *source, size_t size, const pm
.partial_script = false,
.command_start = true,
.recovering = false,
+ .continuable = true,
.encoding_locked = false,
.encoding_changed = false,
.pattern_matching_newlines = false,
@@ -22559,32 +22398,30 @@ pm_parser_init(pm_parser_t *parser, const uint8_t *source, size_t size, const pm
.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.
+ /* Pre-size the arenas based on input size to reduce the number of block
+ * allocations (and the kernel page zeroing they trigger). The ratios were
+ * measured empirically: AST arena ~3.3x input, metadata arena ~1.1x input.
+ * The reserve call is a no-op when the capacity is at or below the default
+ * arena block size, so small inputs don't waste an extra allocation. */
+ if (size <= SIZE_MAX / 4) pm_arena_reserve(arena, size * 4);
+ if (size <= SIZE_MAX / 5 * 4) pm_arena_reserve(&parser->metadata_arena, size + size / 4);
+
+ /* Initialize the constant pool. Measured across 1532 Ruby stdlib files, the
+ * bytes/constant ratio has a median of ~56 and a 90th percentile of ~135.
+ * We use 120 as a balance between over-allocation waste and resize
+ * frequency. Resizes are cheap with arena allocation, so we lean toward
+ * under-estimating. */
+ uint32_t constant_size = ((uint32_t) size) / 120;
+ pm_constant_pool_init(&parser->metadata_arena, &parser->constant_pool, constant_size < 4 ? 4 : constant_size);
+
+ /* Initialize the line offset list. Similar to the constant pool, we are
+ * going to estimate the number of newlines that we will 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);
+ pm_line_offset_list_init(&parser->metadata_arena, &parser->line_offsets, newline_size < 4 ? 4 : newline_size);
// If options were provided to this parse, establish them here.
if (options != NULL) {
@@ -22621,7 +22458,7 @@ pm_parser_init(pm_parser_t *parser, const uint8_t *source, size_t size, const pm
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);
+ const pm_options_scope_t *scope = pm_options_scope(options, scope_index);
pm_parser_scope_push(parser, scope_index == 0);
// Scopes given from the outside are not allowed to have numbered
@@ -22629,16 +22466,14 @@ pm_parser_init(pm_parser_t *parser, const uint8_t *source, size_t size, const pm
parser->current_scope->parameters = ((pm_scope_parameters_t) scope->forwarding) | 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 pm_string_t *local = pm_options_scope_local(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;
-
+ uint8_t *allocated = (uint8_t *) pm_arena_alloc(&parser->metadata_arena, length, 1);
memcpy(allocated, source, length);
- pm_parser_local_add_owned(parser, (uint8_t *) allocated, length);
+ pm_parser_local_add_owned(parser, allocated, length);
}
}
}
@@ -22682,8 +22517,8 @@ pm_parser_init(pm_parser_t *parser, const uint8_t *source, size_t size, const pm
// 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);
+ const uint8_t *newline = next_newline(parser->current.end, parser->end - parser->current.end);
+ size_t length = (size_t) ((newline != NULL ? newline : parser->end) - parser->current.end);
if (length > 2 && parser->current.end[0] == '#' && parser->current.end[1] == '!') {
const char *engine;
@@ -22723,7 +22558,7 @@ pm_parser_init(pm_parser_t *parser, const uint8_t *source, size_t size, const pm
const uint8_t *newline = next_newline(cursor, parser->end - cursor);
while (newline != NULL) {
- pm_newline_list_append(&parser->newline_list, newline);
+ pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, U32(newline - parser->start + 1));
cursor = newline + 1;
newline = next_newline(cursor, parser->end - cursor);
@@ -22752,8 +22587,8 @@ pm_parser_init(pm_parser_t *parser, const uint8_t *source, size_t size, const pm
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);
+ pm_parser_err(parser, 0, 0, PM_ERR_SCRIPT_NOT_FOUND);
+ pm_line_offset_list_clear(&parser->line_offsets);
}
}
@@ -22764,56 +22599,28 @@ pm_parser_init(pm_parser_t *parser, const uint8_t *source, size_t size, const pm
}
/**
- * 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.
+ * Allocate and initialize a parser with the given start and end pointers.
+ *
+ * The resulting parser must eventually be freed with `pm_parser_free()`. The
+ * arena is caller-owned and must outlive the parser — `pm_parser_cleanup()`
+ * does not free the arena.
*/
-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_parser_t *
+pm_parser_new(pm_arena_t *arena, const uint8_t *source, size_t size, const pm_options_t *options) {
+ pm_parser_t *parser = (pm_parser_t *) xmalloc(sizeof(pm_parser_t));
+ if (parser == NULL) abort();
- 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);
- }
+ pm_parser_init(arena, parser, source, size, options);
+ return parser;
}
/**
* 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);
+void
+pm_parser_cleanup(pm_parser_t *parser) {
+ pm_string_cleanup(&parser->filepath);
+ pm_arena_cleanup(&parser->metadata_arena);
while (parser->current_scope != NULL) {
// Normally, popping the scope doesn't free the locals since it is
@@ -22829,152 +22636,224 @@ pm_parser_free(pm_parser_t *parser) {
}
/**
- * Parse the Ruby source associated with the given parser and return the tree.
+ * Free both the memory held by the given parser and the parser itself.
*/
-PRISM_EXPORTED_FUNCTION pm_node_t *
-pm_parse(pm_parser_t *parser) {
- return parse_program(parser);
+void
+pm_parser_free(pm_parser_t *parser) {
+ pm_parser_cleanup(parser);
+ xfree_sized(parser, sizeof(pm_parser_t));
}
/**
- * 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.
+ * Returns true if the given diagnostic ID represents an error that cannot be
+ * fixed by appending more input. These are errors where the existing source
+ * contains definitively invalid syntax (as opposed to merely incomplete input).
*/
static bool
-pm_parse_stream_read(pm_buffer_t *buffer, void *stream, pm_parse_stream_fgets_t *stream_fgets, pm_parse_stream_feof_t *stream_feof) {
-#define LINE_SIZE 4096
- char line[LINE_SIZE];
-
- while (memset(line, '\n', LINE_SIZE), stream_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;
- }
+pm_parse_err_is_fatal(pm_diagnostic_id_t diag_id) {
+ switch (diag_id) {
+ case PM_ERR_ARRAY_EXPRESSION_AFTER_STAR:
+ case PM_ERR_BEGIN_UPCASE_BRACE:
+ case PM_ERR_CLASS_VARIABLE_BARE:
+ case PM_ERR_END_UPCASE_BRACE:
+ case PM_ERR_ESCAPE_INVALID_HEXADECIMAL:
+ case PM_ERR_ESCAPE_INVALID_UNICODE_LIST:
+ case PM_ERR_ESCAPE_INVALID_UNICODE_SHORT:
+ case PM_ERR_EXPRESSION_NOT_WRITABLE:
+ case PM_ERR_EXPRESSION_NOT_WRITABLE_SELF:
+ case PM_ERR_FLOAT_PARSE:
+ case PM_ERR_GLOBAL_VARIABLE_BARE:
+ case PM_ERR_HASH_KEY:
+ case PM_ERR_HEREDOC_IDENTIFIER:
+ case PM_ERR_INSTANCE_VARIABLE_BARE:
+ case PM_ERR_INVALID_BLOCK_EXIT:
+ case PM_ERR_INVALID_ENCODING_MAGIC_COMMENT:
+ case PM_ERR_INVALID_FLOAT_EXPONENT:
+ case PM_ERR_INVALID_NUMBER_BINARY:
+ case PM_ERR_INVALID_NUMBER_DECIMAL:
+ case PM_ERR_INVALID_NUMBER_HEXADECIMAL:
+ case PM_ERR_INVALID_NUMBER_OCTAL:
+ case PM_ERR_INVALID_NUMBER_UNDERSCORE_TRAILING:
+ case PM_ERR_NO_LOCAL_VARIABLE:
+ case PM_ERR_PARAMETER_ORDER:
+ case PM_ERR_STATEMENT_UNDEF:
+ case PM_ERR_VOID_EXPRESSION:
+ return true;
+ default:
+ return false;
+ }
+}
+
+/**
+ * Determine whether the source parsed by the given parser could become valid if
+ * more input were appended. This is used by tools like IRB to decide whether to
+ * prompt for continuation or to display an error.
+ *
+ * The parser starts with continuable=true. This function scans all errors to
+ * detect two categories of non-continuable errors:
+ *
+ * 1. Fatal errors: errors like invalid number literals or bare global variables
+ * that indicate definitively invalid syntax. These are only considered fatal
+ * if they occur before EOF (at EOF they could be from truncated input, e.g.
+ * `"\x` is an incomplete hex escape).
+ *
+ * 2. Stray tokens: unexpected_token_ignore and unexpected_token_close_context
+ * errors indicate tokens that don't belong. A stray token is a cascade
+ * effect (and does not prevent continuability) if:
+ *
+ * a. A non-stray, non-fatal error appeared earlier in the error list at a
+ * strictly earlier source position (the stray was caused by a preceding
+ * parse failure, e.g. a truncated heredoc), OR
+ * b. The stray token is at EOF, starts after position 0 (there is valid
+ * code before it), and either is a single byte (likely a truncated
+ * token like `\`) or there are non-stray errors elsewhere.
+ *
+ * Closing delimiters (`)`, `]`, `}`) at EOF are always genuinely stray —
+ * they are complete tokens and cannot become part of a longer valid
+ * construct by appending more input.
+ *
+ * c. The stray token is `=` at the start of a line, which could be the
+ * beginning of `=begin` (an embedded document). The remaining bytes
+ * after `=` may parse as an identifier, so the error is not at EOF,
+ * but the construct is genuinely incomplete.
+ */
+static void
+pm_parse_continuable(pm_parser_t *parser) {
+ // If there are no errors then there is nothing to continue.
+ if (parser->error_list.size == 0) {
+ parser->continuable = false;
+ return;
+ }
- // Append the line to the buffer.
- length--;
- pm_buffer_append_string(buffer, line, length);
+ if (!parser->continuable) return;
- // 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;
- }
+ size_t source_length = (size_t) (parser->end - parser->start);
- // All data should be read via gets. If the string returned by gets
- // _doesn't_ end with a newline, then we assume we hit EOF condition.
- if (stream_feof(stream)) {
+ // First pass: check if there are any non-stray, non-fatal errors.
+ bool has_non_stray_error = false;
+ for (pm_diagnostic_t *error = (pm_diagnostic_t *) parser->error_list.head; error != NULL; error = (pm_diagnostic_t *) error->node.next) {
+ if (error->diag_id != PM_ERR_UNEXPECTED_TOKEN_IGNORE && error->diag_id != PM_ERR_UNEXPECTED_TOKEN_CLOSE_CONTEXT && !pm_parse_err_is_fatal(error->diag_id)) {
+ has_non_stray_error = true;
break;
}
}
- return true;
-#undef LINE_SIZE
-}
+ // Second pass: check each error. We track the minimum source position
+ // among non-stray, non-fatal errors seen so far in list order, which
+ // lets us detect cascade stray tokens.
+ size_t non_stray_min_start = SIZE_MAX;
-/**
- * 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 (pm_diagnostic_t *error = (pm_diagnostic_t *) parser->error_list.head; error != NULL; error = (pm_diagnostic_t *) error->node.next) {
+ size_t error_start = (size_t) error->location.start;
+ size_t error_end = error_start + (size_t) error->location.length;
+ bool at_eof = error_end >= source_length;
- for (; diagnostic != NULL; diagnostic = (pm_diagnostic_t *) diagnostic->node.next) {
- if (diagnostic->diag_id == PM_ERR_HEREDOC_TERM) {
- return true;
+ // Fatal errors are non-continuable unless they occur at EOF.
+ if (pm_parse_err_is_fatal(error->diag_id) && !at_eof) {
+ parser->continuable = false;
+ return;
}
- }
- return false;
-}
+ // Track non-stray, non-fatal error positions in list order.
+ if (error->diag_id != PM_ERR_UNEXPECTED_TOKEN_IGNORE &&
+ error->diag_id != PM_ERR_UNEXPECTED_TOKEN_CLOSE_CONTEXT) {
+ if (error_start < non_stray_min_start) non_stray_min_start = error_start;
+ continue;
+ }
-/**
- * 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 *stream_fgets, pm_parse_stream_feof_t *stream_feof, const pm_options_t *options) {
- pm_buffer_init(buffer);
+ // This is a stray token. Determine if it is a cascade effect
+ // of a preceding error or genuinely stray.
+
+ // Rule (a): a non-stray error was seen earlier in the list at a
+ // strictly earlier position — this stray is a cascade effect.
+ if (non_stray_min_start < error_start) continue;
+
+ // Rule (b): this stray is at EOF with valid code before it.
+ // Single-byte stray tokens at EOF (like `\` for line continuation)
+ // are likely truncated tokens. Multi-byte stray tokens (like the
+ // keyword `end`) need additional evidence that they are cascade
+ // effects (i.e. non-stray errors exist elsewhere).
+ if (at_eof && error_start > 0) {
+ // Exception: closing delimiters at EOF are genuinely stray.
+ if (error->location.length == 1) {
+ const uint8_t *byte = parser->start + error_start;
+ if (*byte == ')' || *byte == ']' || *byte == '}') {
+ parser->continuable = false;
+ return;
+ }
- bool eof = pm_parse_stream_read(buffer, stream, stream_fgets, stream_feof);
+ // Single-byte non-delimiter stray at EOF: cascade.
+ continue;
+ }
- pm_parser_init(parser, (const uint8_t *) pm_buffer_value(buffer), pm_buffer_length(buffer), options);
- pm_node_t *node = pm_parse(parser);
+ // Multi-byte stray at EOF: cascade only if there are
+ // non-stray errors (evidence of a preceding parse failure).
+ if (has_non_stray_error) continue;
+ }
- 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, stream_fgets, stream_feof);
+ // Rule (c): a stray `=` at the start of a line could be the
+ // beginning of an embedded document (`=begin`). The remaining
+ // bytes after `=` parse as an identifier, so the error is not
+ // at EOF, but the construct is genuinely incomplete.
+ if (error->location.length == 1) {
+ const uint8_t *byte = parser->start + error_start;
+ if (*byte == '=' && (error_start == 0 || *(byte - 1) == '\n')) continue;
+ }
- pm_parser_free(parser);
- pm_parser_init(parser, (const uint8_t *) pm_buffer_value(buffer), pm_buffer_length(buffer), options);
- node = pm_parse(parser);
+ // This stray token is genuinely non-continuable.
+ parser->continuable = false;
+ return;
}
+}
+/**
+ * Parse the Ruby source associated with the given parser and return the tree.
+ */
+pm_node_t *
+pm_parse(pm_parser_t *parser) {
+ pm_node_t *node = parse_program(parser);
+ pm_parse_continuable(parser);
return node;
}
/**
- * Parse the source and return true if it parses without errors or warnings.
+ * 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 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_node_t *
+pm_parse_stream(pm_parser_t **parser, pm_arena_t *arena, pm_source_t *source, const pm_options_t *options) {
+ bool eof = pm_source_stream_read(source);
- pm_parser_t parser;
- pm_parser_init(&parser, source, size, &options);
+ pm_parser_t *tmp = pm_parser_new(arena, pm_source_source(source), pm_source_length(source), options);
+ pm_node_t *node = pm_parse(tmp);
- pm_node_t *node = pm_parse(&parser);
- pm_node_destroy(&parser, node);
+ while (!eof && tmp->error_list.size > 0) {
+ eof = pm_source_stream_read(source);
- bool result = parser.error_list.size == 0;
- pm_parser_free(&parser);
- pm_options_free(&options);
+ pm_parser_free(tmp);
+ pm_arena_cleanup(arena);
- return result;
+ tmp = pm_parser_new(arena, pm_source_source(source), pm_source_length(source), options);
+ node = pm_parse(tmp);
+ }
+
+ *parser = tmp;
+ return node;
}
#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
+static PRISM_INLINE void
pm_serialize_header(pm_buffer_t *buffer) {
pm_buffer_append_string(buffer, "PRISM", 5);
pm_buffer_append_byte(buffer, PRISM_VERSION_MAJOR);
@@ -22986,7 +22865,7 @@ pm_serialize_header(pm_buffer_t *buffer) {
/**
* Serialize the AST represented by the given node to the given buffer.
*/
-PRISM_EXPORTED_FUNCTION void
+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);
@@ -22997,13 +22876,14 @@ pm_serialize(pm_parser_t *parser, pm_node_t *node, pm_buffer_t *buffer) {
* Parse and serialize the AST represented by the given source to the given
* buffer.
*/
-PRISM_EXPORTED_FUNCTION void
+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_arena_t arena = { 0 };
pm_parser_t parser;
- pm_parser_init(&parser, source, size, &options);
+ pm_parser_init(&arena, &parser, source, size, &options);
pm_node_t *node = pm_parse(&parser);
@@ -23011,216 +22891,53 @@ pm_serialize_parse(pm_buffer_t *buffer, const uint8_t *source, size_t size, cons
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);
+ pm_parser_cleanup(&parser);
+ pm_arena_cleanup(&arena);
+ pm_options_cleanup(&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 *stream_fgets, pm_parse_stream_feof_t *stream_feof, const char *data) {
- pm_parser_t parser;
+void
+pm_serialize_parse_stream(pm_buffer_t *buffer, pm_source_t *source, const char *data) {
+ pm_arena_t arena = { 0 };
+ 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, stream_fgets, stream_feof, &options);
+ pm_node_t *node = pm_parse_stream(&parser, &arena, source, &options);
pm_serialize_header(buffer);
- pm_serialize_content(&parser, node, 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);
+ pm_parser_free(parser);
+ pm_arena_cleanup(&arena);
+ pm_options_cleanup(&options);
}
/**
* Parse and serialize the comments in the given source to the given buffer.
*/
-PRISM_EXPORTED_FUNCTION void
+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_arena_t arena = { 0 };
pm_parser_t parser;
- pm_parser_init(&parser, source, size, &options);
+ pm_parser_init(&arena, &parser, source, size, &options);
- pm_node_t *node = pm_parse(&parser);
+ 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_serialize_comment_list(&parser.comment_list, buffer);
- pm_node_destroy(&parser, node);
- pm_parser_free(&parser);
- pm_options_free(&options);
+ pm_parser_cleanup(&parser);
+ pm_arena_cleanup(&arena);
+ pm_options_cleanup(&options);
}
#endif
-
-/******************************************************************************/
-/* Slice queries for the Ruby API */
-/******************************************************************************/
-
-/** The category of slice returned from pm_slice_type. */
-typedef enum {
- /** Returned when the given encoding name is invalid. */
- PM_SLICE_TYPE_ERROR = -1,
-
- /** Returned when no other types apply to the slice. */
- PM_SLICE_TYPE_NONE,
-
- /** Returned when the slice is a valid local variable name. */
- PM_SLICE_TYPE_LOCAL,
-
- /** Returned when the slice is a valid constant name. */
- PM_SLICE_TYPE_CONSTANT,
-
- /** Returned when the slice is a valid method name. */
- PM_SLICE_TYPE_METHOD_NAME
-} pm_slice_type_t;
-
-/**
- * Check that the slice is a valid local variable name or constant.
- */
-pm_slice_type_t
-pm_slice_type(const uint8_t *source, size_t length, const char *encoding_name) {
- // first, get the right encoding object
- const pm_encoding_t *encoding = pm_encoding_find((const uint8_t *) encoding_name, (const uint8_t *) (encoding_name + strlen(encoding_name)));
- if (encoding == NULL) return PM_SLICE_TYPE_ERROR;
-
- // check that there is at least one character
- if (length == 0) return PM_SLICE_TYPE_NONE;
-
- size_t width;
- if ((width = encoding->alpha_char(source, (ptrdiff_t) length)) != 0) {
- // valid because alphabetical
- } else if (*source == '_') {
- // valid because underscore
- width = 1;
- } else if ((*source >= 0x80) && ((width = encoding->char_width(source, (ptrdiff_t) length)) > 0)) {
- // valid because multibyte
- } else {
- // invalid because no match
- return PM_SLICE_TYPE_NONE;
- }
-
- // determine the type of the slice based on the first character
- const uint8_t *end = source + length;
- pm_slice_type_t result = encoding->isupper_char(source, end - source) ? PM_SLICE_TYPE_CONSTANT : PM_SLICE_TYPE_LOCAL;
-
- // next, iterate through all of the bytes of the string to ensure that they
- // are all valid identifier characters
- source += width;
-
- while (source < end) {
- if ((width = encoding->alnum_char(source, end - source)) != 0) {
- // valid because alphanumeric
- source += width;
- } else if (*source == '_') {
- // valid because underscore
- source++;
- } else if ((*source >= 0x80) && ((width = encoding->char_width(source, end - source)) > 0)) {
- // valid because multibyte
- source += width;
- } else {
- // invalid because no match
- break;
- }
- }
-
- // accept a ! or ? at the end of the slice as a method name
- if (*source == '!' || *source == '?' || *source == '=') {
- source++;
- result = PM_SLICE_TYPE_METHOD_NAME;
- }
-
- // valid if we are at the end of the slice
- return source == end ? result : PM_SLICE_TYPE_NONE;
-}
-
-/**
- * Check that the slice is a valid local variable name.
- */
-PRISM_EXPORTED_FUNCTION pm_string_query_t
-pm_string_query_local(const uint8_t *source, size_t length, const char *encoding_name) {
- switch (pm_slice_type(source, length, encoding_name)) {
- case PM_SLICE_TYPE_ERROR:
- return PM_STRING_QUERY_ERROR;
- case PM_SLICE_TYPE_NONE:
- case PM_SLICE_TYPE_CONSTANT:
- case PM_SLICE_TYPE_METHOD_NAME:
- return PM_STRING_QUERY_FALSE;
- case PM_SLICE_TYPE_LOCAL:
- return PM_STRING_QUERY_TRUE;
- }
-
- assert(false && "unreachable");
- return PM_STRING_QUERY_FALSE;
-}
-
-/**
- * Check that the slice is a valid constant name.
- */
-PRISM_EXPORTED_FUNCTION pm_string_query_t
-pm_string_query_constant(const uint8_t *source, size_t length, const char *encoding_name) {
- switch (pm_slice_type(source, length, encoding_name)) {
- case PM_SLICE_TYPE_ERROR:
- return PM_STRING_QUERY_ERROR;
- case PM_SLICE_TYPE_NONE:
- case PM_SLICE_TYPE_LOCAL:
- case PM_SLICE_TYPE_METHOD_NAME:
- return PM_STRING_QUERY_FALSE;
- case PM_SLICE_TYPE_CONSTANT:
- return PM_STRING_QUERY_TRUE;
- }
-
- assert(false && "unreachable");
- return PM_STRING_QUERY_FALSE;
-}
-
-/**
- * Check that the slice is a valid method name.
- */
-PRISM_EXPORTED_FUNCTION pm_string_query_t
-pm_string_query_method_name(const uint8_t *source, size_t length, const char *encoding_name) {
-#define B(p) ((p) ? PM_STRING_QUERY_TRUE : PM_STRING_QUERY_FALSE)
-#define C1(c) (*source == c)
-#define C2(s) (memcmp(source, s, 2) == 0)
-#define C3(s) (memcmp(source, s, 3) == 0)
-
- switch (pm_slice_type(source, length, encoding_name)) {
- case PM_SLICE_TYPE_ERROR:
- return PM_STRING_QUERY_ERROR;
- case PM_SLICE_TYPE_NONE:
- break;
- case PM_SLICE_TYPE_LOCAL:
- // numbered parameters are not valid method names
- return B((length != 2) || (source[0] != '_') || (source[1] == '0') || !pm_char_is_decimal_digit(source[1]));
- case PM_SLICE_TYPE_CONSTANT:
- // all constants are valid method names
- case PM_SLICE_TYPE_METHOD_NAME:
- // all method names are valid method names
- return PM_STRING_QUERY_TRUE;
- }
-
- switch (length) {
- case 1:
- return B(C1('&') || C1('`') || C1('!') || C1('^') || C1('>') || C1('<') || C1('-') || C1('%') || C1('|') || C1('+') || C1('/') || C1('*') || C1('~'));
- case 2:
- return B(C2("!=") || C2("!~") || C2("[]") || C2("==") || C2("=~") || C2(">=") || C2(">>") || C2("<=") || C2("<<") || C2("**"));
- case 3:
- return B(C3("===") || C3("<=>") || C3("[]="));
- default:
- return PM_STRING_QUERY_FALSE;
- }
-
-#undef B
-#undef C1
-#undef C2
-#undef C3
-}
diff --git a/prism/prism.h b/prism/prism.h
index a6f22f1a5a..b342bb32c6 100644
--- a/prism/prism.h
+++ b/prism/prism.h
@@ -6,290 +6,25 @@
#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"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "prism/arena.h"
#include "prism/ast.h"
+#include "prism/buffer.h"
#include "prism/diagnostic.h"
+#include "prism/json.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/serialize.h"
+#include "prism/source.h"
+#include "prism/stream.h"
+#include "prism/string_query.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);
-
-/**
- * This function is used in pm_parse_stream to check whether a stream is EOF.
- * It closely mirrors that of feof so that feof can be used as the
- * default implementation.
- */
-typedef int (pm_parse_stream_feof_t)(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 stream_fgets The function to use to read from the stream.
- * @param stream_feof The function to use to determine if the stream has hit eof.
- * @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 *stream_fgets, pm_parse_stream_feof_t *stream_feof, 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 stream_fgets The function to use to read from the stream.
- * @param stream_feof The function to use to tell if the stream has hit eof.
- * @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 *stream_fgets, pm_parse_stream_feof_t *stream_feof, 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
-
-/**
- * Represents the results of a slice query.
- */
-typedef enum {
- /** Returned if the encoding given to a slice query was invalid. */
- PM_STRING_QUERY_ERROR = -1,
-
- /** Returned if the result of the slice query is false. */
- PM_STRING_QUERY_FALSE,
-
- /** Returned if the result of the slice query is true. */
- PM_STRING_QUERY_TRUE
-} pm_string_query_t;
-
-/**
- * Check that the slice is a valid local variable name.
- *
- * @param source The source to check.
- * @param length The length of the source.
- * @param encoding_name The name of the encoding of the source.
- * @return PM_STRING_QUERY_TRUE if the query is true, PM_STRING_QUERY_FALSE if
- * the query is false, and PM_STRING_QUERY_ERROR if the encoding was invalid.
- */
-PRISM_EXPORTED_FUNCTION pm_string_query_t pm_string_query_local(const uint8_t *source, size_t length, const char *encoding_name);
-
-/**
- * Check that the slice is a valid constant name.
- *
- * @param source The source to check.
- * @param length The length of the source.
- * @param encoding_name The name of the encoding of the source.
- * @return PM_STRING_QUERY_TRUE if the query is true, PM_STRING_QUERY_FALSE if
- * the query is false, and PM_STRING_QUERY_ERROR if the encoding was invalid.
- */
-PRISM_EXPORTED_FUNCTION pm_string_query_t pm_string_query_constant(const uint8_t *source, size_t length, const char *encoding_name);
-
-/**
- * Check that the slice is a valid method name.
- *
- * @param source The source to check.
- * @param length The length of the source.
- * @param encoding_name The name of the encoding of the source.
- * @return PM_STRING_QUERY_TRUE if the query is true, PM_STRING_QUERY_FALSE if
- * the query is false, and PM_STRING_QUERY_ERROR if the encoding was invalid.
- */
-PRISM_EXPORTED_FUNCTION pm_string_query_t pm_string_query_method_name(const uint8_t *source, size_t length, const char *encoding_name);
-
/**
* @mainpage
*
@@ -298,7 +33,7 @@ PRISM_EXPORTED_FUNCTION pm_string_query_t pm_string_query_method_name(const uint
* 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),
+ * [TruffleRuby](https://github.com/truffleruby/truffleruby),
* [Sorbet](https://github.com/sorbet/sorbet), and
* [Syntax Tree](https://github.com/ruby-syntax-tree/syntax_tree).
*
@@ -312,32 +47,32 @@ PRISM_EXPORTED_FUNCTION pm_string_query_t pm_string_query_method_name(const uint
*
* @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:
+ * In order to parse Ruby code, the functions that you are 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
+ * * `pm_arena_new()` - create a new arena to hold all AST-lifetime allocations
+ * * `pm_parser_new()` - allocate and initialize a new parser
+ * * `pm_parse()` - parse and return the root node
+ * * `pm_parser_free()` - free the parser and its internal memory
+ * * `pm_arena_free()` - free all AST-lifetime memory
*
* 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_arena_t *arena = pm_arena_new();
+ * pm_parser_t *parser = pm_parser_new(arena, source, length, NULL);
*
- * pm_node_t *root = pm_parse(&parser);
+ * pm_node_t *root = pm_parse(parser);
* printf("PARSED!\n");
*
- * pm_node_destroy(&parser, root);
- * pm_parser_free(&parser);
+ * pm_parser_free(parser);
+ * pm_arena_free(arena);
* }
* ```
*
- * 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
+ * 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
@@ -345,48 +80,51 @@ PRISM_EXPORTED_FUNCTION pm_string_query_t pm_string_query_method_name(const uint
* 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:
+ * parse Ruby code. The functions that you are 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
+ * * `pm_buffer_new()` - create a new buffer
+ * * `pm_buffer_free()` - free the buffer and its internal memory
+ * * `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_buffer_t *buffer = pm_buffer_new();
*
- * pm_serialize_parse(&buffer, source, length, NULL);
+ * pm_serialize_parse(buffer, source, length, NULL);
* printf("SERIALIZED!\n");
*
- * pm_buffer_free(&buffer);
+ * 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:
+ * 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_arena_t *arena = pm_arena_new();
+ * pm_parser_t *parser = pm_parser_new(arena, source, length, NULL);
*
- * pm_node_t *root = pm_parse(&parser);
- * pm_buffer_t buffer = { 0 };
+ * pm_node_t *root = pm_parse(parser);
+ * pm_buffer_t *buffer = pm_buffer_new();
*
- * pm_prettyprint(&buffer, &parser, root);
- * printf("%*.s\n", (int) buffer.length, buffer.value);
+ * pm_prettyprint(buffer, parser, root);
+ * printf("%*.s\n", (int) pm_buffer_length(buffer), pm_buffer_value(buffer));
*
- * pm_buffer_free(&buffer);
- * pm_node_destroy(&parser, root);
- * pm_parser_free(&parser);
+ * pm_buffer_free(buffer);
+ * pm_parser_free(parser);
+ * pm_arena_free(arena);
* }
* ```
*/
+#ifdef __cplusplus
+}
+#endif
+
#endif
diff --git a/prism/regexp.c b/prism/regexp.c
index dcc7476244..cc17aa4d09 100644
--- a/prism/regexp.c
+++ b/prism/regexp.c
@@ -1,5 +1,20 @@
-#include "prism/regexp.h"
-
+#include "prism/internal/regexp.h"
+
+#include "prism/compiler/inline.h"
+#include "prism/compiler/fallthrough.h"
+#include "prism/internal/buffer.h"
+#include "prism/internal/char.h"
+#include "prism/internal/diagnostic.h"
+#include "prism/internal/encoding.h"
+#include "prism/internal/memchr.h"
+#include "prism/internal/parser.h"
+#include "prism/internal/stringy.h"
+#include "prism/internal/strncasecmp.h"
+
+#include <assert.h>
+#include <string.h>
+
+/** The maximum depth of nested groups allowed in a regular expression. */
#define PM_REGEXP_PARSE_DEPTH_MAX 4096
/**
@@ -18,6 +33,54 @@ typedef struct {
/** A pointer to the end of the source that we are parsing. */
const uint8_t *end;
+ /** 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. */
+ pm_regexp_name_data_t *name_data;
+
+ /** The start of the regexp node (for error locations). */
+ const uint8_t *node_start;
+
+ /** The end of the regexp node (for error locations). */
+ const uint8_t *node_end;
+
+ /**
+ * The explicit encoding determined by escape sequences. NULL if no
+ * encoding-setting escape has been seen, UTF-8 for `\u` escapes, or the
+ * source encoding for `\x` escapes.
+ */
+ const pm_encoding_t *explicit_encoding;
+
+ /**
+ * Pointer to the first non-POSIX property name (for /n error messages).
+ * POSIX properties (Alnum, Alpha, etc.) work in all encodings.
+ * Script properties (Hiragana, Katakana, etc.) work in /e, /s, /u.
+ * Unicode-only properties (L, Ll, etc.) work only in /u.
+ */
+ const uint8_t *property_name;
+
+ /** Length of the first non-POSIX property name found. */
+ size_t property_name_length;
+
+ /**
+ * Pointer to the first Unicode-only property name (for /e, /s error
+ * messages). NULL if only POSIX or script properties have been seen.
+ */
+ const uint8_t *unicode_property_name;
+
+ /** Length of the first Unicode-only property name found. */
+ size_t unicode_property_name_length;
+
+ /** Buffer of hex escape byte values >= 0x80, separated by 0x00 sentinels. */
+ pm_buffer_t hex_escape_buffer;
+
+ /** Count of non-ASCII literal bytes (not from escapes). */
+ uint32_t non_ascii_literal_count;
+
/**
* Whether or not the regular expression currently being parsed is in
* extended mode, wherein whitespace is ignored and comments are allowed.
@@ -27,31 +90,77 @@ typedef struct {
/** Whether the encoding has changed from the default. */
bool encoding_changed;
- /** The encoding of the source. */
- const pm_encoding_t *encoding;
+ /** Whether the source content is shared (for named capture callback). */
+ bool shared;
- /** The callback to call when a named capture group is found. */
- pm_regexp_name_callback_t name_callback;
+ /** Whether a `\u{...}` escape with value >= 0x80 was seen. */
+ bool has_unicode_escape;
- /** The data to pass to the name callback. */
- void *name_data;
+ /** Whether a `\xNN` escape (or `\M-x`, etc.) with value >= 0x80 was seen. */
+ bool has_hex_escape;
+
+ /**
+ * Tracks whether the last encoding-setting escape was `\u` (true) or `\x`
+ * (false). This matters for error messages when both types are mixed.
+ */
+ bool last_escape_was_unicode;
+
+ /** Whether any `\p{...}` or `\P{...}` property escape was found. */
+ bool has_property_escape;
+
+ /** Whether a Unicode-only property escape was found (not POSIX or script). */
+ bool has_unicode_property_escape;
- /** The callback to call when a parse error is found. */
- pm_regexp_error_callback_t error_callback;
+ /** Whether a `\u` escape with invalid range (surrogate or > 0x10FFFF) was seen. */
+ bool invalid_unicode_range;
- /** The data to pass to the error callback. */
- void *error_data;
+ /** Whether we are accumulating consecutive hex escape bytes. */
+ bool hex_group_active;
+
+ /** Whether an invalid multibyte character was found during parsing. */
+ bool has_invalid_multibyte;
} pm_regexp_parser_t;
/**
- * Append an error to the parser.
+ * Append a syntax error to the parser's error list. If the source is shared
+ * (points into the original source), we can point to the exact error location.
+ * Otherwise, we point to the whole regexp node.
*/
-static inline void
+static PRISM_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);
+ pm_parser_t *pm = parser->parser;
+ uint32_t loc_start, loc_length;
+
+ if (parser->shared) {
+ loc_start = (uint32_t) (start - pm->start);
+ loc_length = (uint32_t) (end - start);
+ } else {
+ loc_start = (uint32_t) (parser->node_start - pm->start);
+ loc_length = (uint32_t) (parser->node_end - parser->node_start);
+ }
+
+ pm_diagnostic_list_append_format(&pm->metadata_arena, &pm->error_list, loc_start, loc_length, PM_ERR_REGEXP_PARSE_ERROR, message);
}
/**
+ * Append a formatted diagnostic error with proper shared/non-shared location
+ * handling. This is a macro because we need variadic args for the format string.
+ */
+#define pm_regexp_parse_error_format(parser_, err_start_, err_end_, diag_id, ...) \
+ do { \
+ pm_parser_t *pm__ = (parser_)->parser; \
+ uint32_t loc_start__, loc_length__; \
+ if ((parser_)->shared) { \
+ loc_start__ = (uint32_t) ((err_start_) - pm__->start); \
+ loc_length__ = (uint32_t) ((err_end_) - (err_start_)); \
+ } else { \
+ loc_start__ = (uint32_t) ((parser_)->node_start - pm__->start); \
+ loc_length__ = (uint32_t) ((parser_)->node_end - (parser_)->node_start); \
+ } \
+ pm_diagnostic_list_append_format(&pm__->metadata_arena, &pm__->error_list, loc_start__, loc_length__, diag_id, __VA_ARGS__); \
+ } while (0)
+
+/**
* 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.
*/
@@ -59,14 +168,14 @@ 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);
+ parser->name_callback(parser->parser, &string, parser->shared, parser->name_data);
+ pm_string_cleanup(&string);
}
/**
* Returns true if the next character is the end of the source.
*/
-static inline bool
+static PRISM_INLINE bool
pm_regexp_char_is_eof(pm_regexp_parser_t *parser) {
return parser->cursor >= parser->end;
}
@@ -74,7 +183,7 @@ pm_regexp_char_is_eof(pm_regexp_parser_t *parser) {
/**
* Optionally accept a char and consume it if it exists.
*/
-static inline bool
+static PRISM_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++;
@@ -86,7 +195,7 @@ pm_regexp_char_accept(pm_regexp_parser_t *parser, uint8_t value) {
/**
* Expect a character to be present and consume it.
*/
-static inline bool
+static PRISM_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++;
@@ -114,6 +223,47 @@ pm_regexp_char_find(pm_regexp_parser_t *parser, uint8_t value) {
}
/**
+ * Mark a group boundary in the hex escape byte buffer. When consecutive hex
+ * escape bytes >= 0x80 are followed by a non-hex-escape, this appends a 0x00
+ * sentinel to separate the groups for later multibyte validation.
+ */
+static PRISM_INLINE void
+pm_regexp_hex_group_boundary(pm_regexp_parser_t *parser) {
+ if (parser->hex_group_active) {
+ pm_buffer_append_byte(&parser->hex_escape_buffer, 0x00);
+ parser->hex_group_active = false;
+ }
+}
+
+/**
+ * Track a hex escape byte value >= 0x80 for multibyte validation.
+ */
+static PRISM_INLINE void
+pm_regexp_track_hex_escape(pm_regexp_parser_t *parser, uint8_t byte) {
+ if (byte >= 0x80) {
+ pm_buffer_append_byte(&parser->hex_escape_buffer, byte);
+ parser->hex_group_active = true;
+ parser->has_hex_escape = true;
+
+ parser->explicit_encoding = parser->encoding;
+ parser->last_escape_was_unicode = false;
+ } else {
+ pm_regexp_hex_group_boundary(parser);
+ }
+}
+
+/**
+ * Parse a hex digit character and return its value, or -1 if not a hex digit.
+ */
+static PRISM_INLINE int
+pm_regexp_hex_digit_value(uint8_t byte) {
+ if (byte >= '0' && byte <= '9') return byte - '0';
+ if (byte >= 'a' && byte <= 'f') return byte - 'a' + 10;
+ if (byte >= 'A' && byte <= 'F') return byte - 'A' + 10;
+ return -1;
+}
+
+/**
* Range quantifiers are a special class of quantifiers that look like
*
* * {digit}
@@ -121,13 +271,12 @@ pm_regexp_char_find(pm_regexp_parser_t *parser, uint8_t value) {
* * {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.
+ * 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.
+ * To properly track everything, we're going to build a little state machine.
* It looks something like the following:
*
* +-------+ +---------+ ------------+
@@ -275,11 +424,393 @@ pm_regexp_parse_posix_class(pm_regexp_parser_t *parser) {
);
}
+/**
+ * Property escape classification. Onigmo supports three tiers of property
+ * names depending on the encoding:
+ *
+ * - POSIX properties (Alnum, Alpha, ASCII, Blank, Cntrl, Digit, Graph, Lower,
+ * Print, Punct, Space, Upper, XDigit, Word): valid in all encodings.
+ * - Script properties (Hiragana, Katakana, Han, Latin, Greek, Cyrillic): valid
+ * in EUC-JP (/e), Windows-31J (/s), and UTF-8 (/u), but not ASCII-8BIT (/n).
+ * - Unicode-only properties (general categories like L, Ll, Lu, etc., plus
+ * Any, Assigned): valid only in UTF-8 (/u).
+ */
+typedef enum {
+ PM_REGEXP_PROPERTY_POSIX,
+ PM_REGEXP_PROPERTY_SCRIPT,
+ PM_REGEXP_PROPERTY_UNICODE
+} pm_regexp_property_type_t;
+
+/**
+ * Classify a property name. The name may start with '^' for negation, which
+ * is skipped before matching.
+ */
+static pm_regexp_property_type_t
+pm_regexp_classify_property(const uint8_t *name, size_t length) {
+ // Skip leading '^' for negated properties like \p{^Hiragana}.
+ if (length > 0 && name[0] == '^') {
+ name++;
+ length--;
+ }
+
+#define PM_REGEXP_CASECMP(str_) (pm_strncasecmp(name, (const uint8_t *) (str_), length) == 0)
+
+ switch (length) {
+ case 3:
+ if (PM_REGEXP_CASECMP("Han")) return PM_REGEXP_PROPERTY_SCRIPT;
+ break;
+ case 4:
+ if (PM_REGEXP_CASECMP("Word")) return PM_REGEXP_PROPERTY_POSIX;
+ break;
+ case 5:
+ /* Most properties are length 5, so dispatch on first character. */
+ switch (name[0] | 0x20) {
+ case 'a':
+ if (PM_REGEXP_CASECMP("Alnum")) return PM_REGEXP_PROPERTY_POSIX;
+ if (PM_REGEXP_CASECMP("Alpha")) return PM_REGEXP_PROPERTY_POSIX;
+ if (PM_REGEXP_CASECMP("ASCII")) return PM_REGEXP_PROPERTY_POSIX;
+ break;
+ case 'b':
+ if (PM_REGEXP_CASECMP("Blank")) return PM_REGEXP_PROPERTY_POSIX;
+ break;
+ case 'c':
+ if (PM_REGEXP_CASECMP("Cntrl")) return PM_REGEXP_PROPERTY_POSIX;
+ break;
+ case 'd':
+ if (PM_REGEXP_CASECMP("Digit")) return PM_REGEXP_PROPERTY_POSIX;
+ break;
+ case 'g':
+ if (PM_REGEXP_CASECMP("Graph")) return PM_REGEXP_PROPERTY_POSIX;
+ if (PM_REGEXP_CASECMP("Greek")) return PM_REGEXP_PROPERTY_SCRIPT;
+ break;
+ case 'l':
+ if (PM_REGEXP_CASECMP("Lower")) return PM_REGEXP_PROPERTY_POSIX;
+ if (PM_REGEXP_CASECMP("Latin")) return PM_REGEXP_PROPERTY_SCRIPT;
+ break;
+ case 'p':
+ if (PM_REGEXP_CASECMP("Print")) return PM_REGEXP_PROPERTY_POSIX;
+ if (PM_REGEXP_CASECMP("Punct")) return PM_REGEXP_PROPERTY_POSIX;
+ break;
+ case 's':
+ if (PM_REGEXP_CASECMP("Space")) return PM_REGEXP_PROPERTY_POSIX;
+ break;
+ case 'u':
+ if (PM_REGEXP_CASECMP("Upper")) return PM_REGEXP_PROPERTY_POSIX;
+ break;
+ }
+ break;
+ case 6:
+ if (PM_REGEXP_CASECMP("XDigit")) return PM_REGEXP_PROPERTY_POSIX;
+ break;
+ case 8:
+ if (PM_REGEXP_CASECMP("Hiragana")) return PM_REGEXP_PROPERTY_SCRIPT;
+ if (PM_REGEXP_CASECMP("Katakana")) return PM_REGEXP_PROPERTY_SCRIPT;
+ if (PM_REGEXP_CASECMP("Cyrillic")) return PM_REGEXP_PROPERTY_SCRIPT;
+ break;
+ }
+
+#undef PM_REGEXP_CASECMP
+
+ // Everything else is Unicode-only (general categories, other scripts, etc.).
+ return PM_REGEXP_PROPERTY_UNICODE;
+}
+
+/**
+ * Check for and skip a `\p{...}` or `\P{...}` Unicode property escape. The
+ * cursor should be pointing at 'p' or 'P' when this is called. If a property
+ * escape is found, record it on the regexp parser and advance past the closing
+ * '}'.
+ *
+ * Properties are classified into three tiers (POSIX, script, Unicode-only) to
+ * determine which encoding modifiers they are valid with.
+ */
+static bool
+pm_regexp_parse_property_escape(pm_regexp_parser_t *parser) {
+ assert(*parser->cursor == 'p' || *parser->cursor == 'P');
+
+ if (parser->cursor + 1 < parser->end && parser->cursor[1] == '{') {
+ const uint8_t *name_start = parser->cursor + 2;
+ const uint8_t *search = name_start;
+
+ while (search < parser->end && *search != '}') search++;
+
+ if (search < parser->end) {
+ size_t name_length = (size_t) (search - name_start);
+ parser->has_property_escape = true;
+
+ pm_regexp_property_type_t type = pm_regexp_classify_property(name_start, name_length);
+
+ // Track the first non-POSIX property name (for /n error messages).
+ if (type >= PM_REGEXP_PROPERTY_SCRIPT && parser->property_name == NULL) {
+ parser->property_name = name_start;
+ parser->property_name_length = name_length;
+ }
+
+ // Track the first Unicode-only property name (for /e, /s error messages).
+ if (type == PM_REGEXP_PROPERTY_UNICODE) {
+ parser->has_unicode_property_escape = true;
+ if (parser->unicode_property_name == NULL) {
+ parser->unicode_property_name = name_start;
+ parser->unicode_property_name_length = name_length;
+ }
+ }
+
+ parser->cursor = search + 1; // skip past '}'
+ return true;
+ }
+ }
+
+ // Not a property escape, just skip the single character after '\'.
+ parser->cursor++;
+ return false;
+}
+
+/**
+ * Validate and skip a \u escape sequence in a regular expression. The cursor
+ * should be pointing at the character after 'u' when this is called. This
+ * handles both the \u{NNNN MMMM} and \uNNNN forms. Also tracks encoding
+ * state for validation.
+ */
+static void
+pm_regexp_parse_unicode_escape(pm_regexp_parser_t *parser) {
+ const uint8_t *escape_start = parser->cursor - 2; // points to '\'
+
+ if (pm_regexp_char_is_eof(parser)) {
+ pm_regexp_parse_error(parser, escape_start, parser->cursor, "invalid Unicode escape");
+ return;
+ }
+
+ if (*parser->cursor == '{') {
+ parser->cursor++; // skip '{'
+
+ // Skip leading whitespace.
+ while (!pm_regexp_char_is_eof(parser) && pm_char_is_whitespace(*parser->cursor)) {
+ parser->cursor++;
+ }
+
+ bool has_codepoint = false;
+
+ while (!pm_regexp_char_is_eof(parser) && *parser->cursor != '}') {
+ // Parse the hex digits to compute the codepoint value.
+ uint32_t value = 0;
+ size_t hex_count = 0;
+
+ int digit;
+ while (!pm_regexp_char_is_eof(parser) && (digit = pm_regexp_hex_digit_value(*parser->cursor)) >= 0) {
+ value = (value << 4) | (uint32_t) digit;
+ hex_count++;
+ parser->cursor++;
+ }
+
+ if (hex_count == 0) {
+ // Skip to '}' or end of regexp to find the full extent.
+ while (!pm_regexp_char_is_eof(parser) && *parser->cursor != '}') {
+ parser->cursor++;
+ }
+
+ const uint8_t *escape_end = parser->cursor;
+ if (!pm_regexp_char_is_eof(parser)) {
+ escape_end++;
+ parser->cursor++; // skip '}'
+ }
+
+ pm_regexp_parse_error_format(parser, escape_start, escape_end, PM_ERR_ESCAPE_INVALID_UNICODE_LIST, (int) (escape_end - escape_start), (const char *) escape_start);
+ return;
+ }
+
+ if (hex_count > 6) {
+ pm_regexp_parse_error(parser, escape_start, parser->cursor, "invalid Unicode range");
+ }
+
+ // Track encoding state for this codepoint.
+ if (value >= 0x80) {
+ parser->has_unicode_escape = true;
+ parser->explicit_encoding = PM_ENCODING_UTF_8_ENTRY;
+ parser->last_escape_was_unicode = true;
+ pm_regexp_hex_group_boundary(parser);
+ }
+
+ // Check for invalid Unicode range (surrogates or > 0x10FFFF).
+ if (value > 0x10FFFF || (value >= 0xD800 && value <= 0xDFFF)) {
+ parser->invalid_unicode_range = true;
+ }
+
+ has_codepoint = true;
+
+ // Skip whitespace between codepoints.
+ while (!pm_regexp_char_is_eof(parser) && pm_char_is_whitespace(*parser->cursor)) {
+ parser->cursor++;
+ }
+ }
+
+ if (pm_regexp_char_is_eof(parser)) {
+ pm_regexp_parse_error(parser, escape_start, parser->cursor, "unterminated Unicode escape");
+ } else {
+ if (!has_codepoint) {
+ pm_regexp_parse_error_format(parser, escape_start, parser->cursor + 1, PM_ERR_ESCAPE_INVALID_UNICODE_LIST, (int) (parser->cursor + 1 - escape_start), (const char *) escape_start);
+ }
+ parser->cursor++; // skip '}'
+ }
+ } else {
+ // \uNNNN form — need exactly 4 hex digits.
+ uint32_t value = 0;
+ size_t hex_count = 0;
+
+ int digit;
+ while (hex_count < 4 && !pm_regexp_char_is_eof(parser) && (digit = pm_regexp_hex_digit_value(*parser->cursor)) >= 0) {
+ value = (value << 4) | (uint32_t) digit;
+ hex_count++;
+ parser->cursor++;
+ }
+
+ if (hex_count < 4) {
+ pm_regexp_parse_error(parser, escape_start, parser->cursor, "invalid Unicode escape");
+ } else if (value >= 0x80) {
+ parser->has_unicode_escape = true;
+ parser->explicit_encoding = PM_ENCODING_UTF_8_ENTRY;
+ parser->last_escape_was_unicode = true;
+ pm_regexp_hex_group_boundary(parser);
+ }
+
+ // Check for invalid Unicode range.
+ if (hex_count == 4 && (value > 0x10FFFF || (value >= 0xD800 && value <= 0xDFFF))) {
+ parser->invalid_unicode_range = true;
+ }
+ }
+}
+
// Forward declaration because character sets can be nested.
static bool
pm_regexp_parse_lbracket(pm_regexp_parser_t *parser, uint16_t depth);
/**
+ * Parse a \x escape and return the byte value. The cursor should be pointing
+ * at the character after 'x'. Returns -1 if no hex digits follow.
+ */
+static int
+pm_regexp_parse_hex_escape(pm_regexp_parser_t *parser) {
+ int value = -1;
+
+ if (!pm_regexp_char_is_eof(parser)) {
+ int digit = pm_regexp_hex_digit_value(*parser->cursor);
+ if (digit >= 0) {
+ value = digit;
+ parser->cursor++;
+
+ if (!pm_regexp_char_is_eof(parser)) {
+ digit = pm_regexp_hex_digit_value(*parser->cursor);
+ if (digit >= 0) {
+ value = (value << 4) | digit;
+ parser->cursor++;
+ }
+ }
+ }
+ }
+
+ if (value >= 0) {
+ pm_regexp_track_hex_escape(parser, (uint8_t) value);
+ }
+
+ return value;
+}
+
+/**
+ * Parse a backslash escape sequence in a regexp, handling \u (unicode),
+ * \p/\P (property), \x (hex), and other single-character escapes. Also
+ * tracks encoding state for \M-x and \C-\M-x escapes.
+ */
+static void
+pm_regexp_parse_backslash_escape(pm_regexp_parser_t *parser) {
+ if (pm_regexp_char_is_eof(parser)) return;
+
+ switch (*parser->cursor) {
+ case 'u':
+ parser->cursor++; // skip 'u'
+ pm_regexp_parse_unicode_escape(parser);
+ break;
+ case 'p':
+ case 'P':
+ pm_regexp_parse_property_escape(parser);
+ break;
+ case 'x':
+ parser->cursor++; // skip 'x'
+ pm_regexp_parse_hex_escape(parser);
+ break;
+ case 'M':
+ // \M-x produces (x | 0x80), always >= 0x80
+ if (parser->cursor + 2 < parser->end && parser->cursor[1] == '-') {
+ parser->cursor += 2; // skip 'M-'
+ if (!pm_regexp_char_is_eof(parser)) {
+ if (*parser->cursor == '\\') {
+ parser->cursor++;
+ // \M-\C-x or \M-\cx — the resulting byte is always >= 0x80
+ // We just need to track it as a hex escape >= 0x80.
+ pm_regexp_parse_backslash_escape(parser);
+ } else {
+ parser->cursor++;
+ }
+ // \M-x always produces a byte >= 0x80
+ pm_regexp_track_hex_escape(parser, 0x80);
+ }
+ } else {
+ parser->cursor++;
+ }
+ break;
+ case 'C':
+ // \C-x produces (x & 0x1F)
+ if (parser->cursor + 2 < parser->end && parser->cursor[1] == '-') {
+ parser->cursor += 2; // skip 'C-'
+ if (!pm_regexp_char_is_eof(parser)) {
+ if (*parser->cursor == '\\') {
+ parser->cursor++;
+ pm_regexp_parse_backslash_escape(parser);
+ } else {
+ parser->cursor++;
+ }
+ }
+ } else {
+ parser->cursor++;
+ }
+ break;
+ case 'c':
+ // \cx produces (x & 0x1F)
+ parser->cursor++; // skip 'c'
+ if (!pm_regexp_char_is_eof(parser)) {
+ if (*parser->cursor == '\\') {
+ parser->cursor++;
+ pm_regexp_parse_backslash_escape(parser);
+ } else {
+ parser->cursor++;
+ }
+ }
+ break;
+ default:
+ pm_regexp_hex_group_boundary(parser);
+ parser->cursor++;
+ break;
+ }
+}
+
+/**
+ * Check if a byte at the current position is a non-ASCII byte in a multibyte
+ * encoding that produces an invalid character. If so, emit an error at the
+ * byte location immediately.
+ */
+static void
+pm_regexp_parse_invalid_multibyte(pm_regexp_parser_t *parser, const uint8_t *cursor) {
+ uint8_t byte = *cursor;
+ if (byte >= 0x80 && parser->encoding_changed && parser->encoding->multibyte) {
+ size_t width = parser->encoding->char_width(cursor, (ptrdiff_t) (parser->end - cursor));
+ if (width > 1) {
+ parser->cursor += width - 1;
+ } else if (width == 0) {
+ parser->has_invalid_multibyte = true;
+ pm_regexp_parse_error_format(parser, cursor, cursor + 1, PM_ERR_INVALID_MULTIBYTE_CHAR, parser->encoding->name);
+ }
+ }
+}
+
+/**
* match-char-set : '[' '^'? (match-range | match-char)* ']'
* ;
*/
@@ -293,12 +824,16 @@ pm_regexp_parse_character_set(pm_regexp_parser_t *parser, uint16_t depth) {
pm_regexp_parse_lbracket(parser, (uint16_t) (depth + 1));
break;
case '\\':
- if (!pm_regexp_char_is_eof(parser)) {
- parser->cursor++;
- }
+ pm_regexp_parse_backslash_escape(parser);
break;
default:
- // do nothing, we've already advanced the cursor
+ // We've already advanced the cursor by one byte. If the byte
+ // was >= 0x80 in a multibyte encoding, we may need to consume
+ // additional continuation bytes and validate the character.
+ if (*(parser->cursor - 1) >= 0x80) {
+ parser->non_ascii_literal_count++;
+ }
+ pm_regexp_parse_invalid_multibyte(parser, parser->cursor - 1);
break;
}
}
@@ -354,8 +889,13 @@ typedef enum {
// These are the options that are configurable on the regular expression (or
// from within a group).
+/** The minimum character value for a regexp option slot. */
#define PRISM_REGEXP_OPTION_STATE_SLOT_MINIMUM 'a'
+
+/** The maximum character value for a regexp option slot. */
#define PRISM_REGEXP_OPTION_STATE_SLOT_MAXIMUM 'x'
+
+/** The number of regexp option slots. */
#define PRISM_REGEXP_OPTION_STATE_SLOTS (PRISM_REGEXP_OPTION_STATE_SLOT_MAXIMUM - PRISM_REGEXP_OPTION_STATE_SLOT_MINIMUM + 1)
/**
@@ -498,7 +1038,15 @@ pm_regexp_parse_group(pm_regexp_parser_t *parser, uint16_t depth) {
}
size_t width = parser->encoding->char_width(parser->cursor, (ptrdiff_t) (parser->end - parser->cursor));
- if (width == 0) return false;
+ if (width == 0) {
+ if (*parser->cursor >= 0x80) {
+ parser->has_invalid_multibyte = true;
+ pm_regexp_parse_error_format(parser, parser->cursor, parser->cursor + 1, PM_ERR_INVALID_MULTIBYTE_CHAR, parser->encoding->name);
+ parser->cursor++;
+ continue;
+ }
+ return false;
+ }
escaped = (width == 1) && (*parser->cursor == '\\');
parser->cursor += width;
@@ -686,9 +1234,7 @@ pm_regexp_parse_item(pm_regexp_parser_t *parser, uint16_t depth) {
return pm_regexp_parse_quantifier(parser);
case '\\':
parser->cursor++;
- if (!pm_regexp_char_is_eof(parser)) {
- parser->cursor++;
- }
+ pm_regexp_parse_backslash_escape(parser);
return pm_regexp_parse_quantifier(parser);
case '(':
parser->cursor++;
@@ -720,9 +1266,30 @@ pm_regexp_parse_item(pm_regexp_parser_t *parser, uint16_t depth) {
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;
+ if (width == 0) {
+ if (*parser->cursor >= 0x80 && parser->encoding_changed) {
+ if (parser->encoding->multibyte) {
+ // Invalid multibyte character in a multibyte encoding.
+ // Emit the error at the byte location immediately.
+ parser->has_invalid_multibyte = true;
+ pm_regexp_parse_error_format(parser, parser->cursor, parser->cursor + 1, PM_ERR_INVALID_MULTIBYTE_CHAR, parser->encoding->name);
+ } else {
+ // Non-ASCII byte in a single-byte encoding (e.g.,
+ // US-ASCII). Count it for later error reporting.
+ parser->non_ascii_literal_count++;
+ }
+ parser->cursor++;
+ return pm_regexp_parse_quantifier(parser);
+ }
+ return false;
+ }
+
+ // Count non-ASCII literal bytes.
+ for (size_t i = 0; i < width; i++) {
+ if (parser->cursor[i] >= 0x80) parser->non_ascii_literal_count++;
+ }
+ parser->cursor += width;
return pm_regexp_parse_quantifier(parser);
}
}
@@ -768,13 +1335,354 @@ pm_regexp_parse_pattern(pm_regexp_parser_t *parser) {
return pm_regexp_char_is_eof(parser);
}
+// ---------------------------------------------------------------------------
+// Encoding validation
+// ---------------------------------------------------------------------------
+
/**
- * Parse a regular expression and extract the names of all of the named capture
- * groups.
+ * Validate that groups of hex escape bytes in the buffer form valid multibyte
+ * characters in the given encoding. Groups are separated by 0x00 sentinels.
+ */
+static bool
+pm_regexp_validate_hex_escapes(const pm_encoding_t *encoding, const pm_buffer_t *buffer) {
+ const uint8_t *data = (const uint8_t *) pm_buffer_value(buffer);
+ size_t len = pm_buffer_length(buffer);
+ size_t i = 0;
+
+ while (i < len) {
+ size_t group_start = i;
+ while (i < len && data[i] != 0x00) i++;
+
+ for (size_t j = group_start; j < i; ) {
+ size_t width = encoding->char_width(data + j, (ptrdiff_t) (i - j));
+ if (width == 0) return false;
+ j += width;
+ }
+
+ if (i < len) i++; // skip sentinel
+ }
+
+ return true;
+}
+
+/**
+ * Format regexp source content for use in error messages, hex-escaping
+ * non-ASCII bytes.
+ */
+static void
+pm_regexp_format_for_error(pm_buffer_t *buffer, const pm_encoding_t *encoding, const uint8_t *source, size_t length) {
+ size_t index = 0;
+
+ if (encoding == PM_ENCODING_UTF_8_ENTRY) {
+ pm_buffer_append_string(buffer, (const char *) source, length);
+ return;
+ }
+
+ while (index < length) {
+ if (source[index] < 0x80) {
+ pm_buffer_append_byte(buffer, source[index]);
+ index++;
+ } else if (encoding->multibyte) {
+ size_t width = encoding->char_width(source + index, (ptrdiff_t) (length - index));
+
+ if (width > 1) {
+ pm_buffer_append_string(buffer, "\\x{", 3);
+ for (size_t i = 0; i < width; i++) {
+ pm_buffer_append_format(buffer, "%02X", source[index + i]);
+ }
+ pm_buffer_append_byte(buffer, '}');
+ index += width;
+ } else {
+ pm_buffer_append_format(buffer, "\\x%02X", source[index]);
+ index++;
+ }
+ } else {
+ pm_buffer_append_format(buffer, "\\x%02X", source[index]);
+ index++;
+ }
+ }
+}
+
+/**
+ * Emit an encoding validation error on the regexp node.
+ */
+#define PM_REGEXP_ENCODING_ERROR(parser, diag_id, ...) \
+ pm_diagnostic_list_append_format( \
+ &(parser)->parser->metadata_arena, \
+ &(parser)->parser->error_list, \
+ (uint32_t) ((parser)->node_start - (parser)->parser->start), \
+ (uint32_t) ((parser)->node_end - (parser)->node_start), \
+ diag_id, __VA_ARGS__)
+
+/**
+ * Validate encoding for a regexp with an encoding modifier (/e, /s, /u, /n).
+ *
+ * The decision tree is:
+ *
+ * 1. No escape-set encoding (explicit_encoding == NULL):
+ * a. ASCII-only content: validate property escapes, return forced US-ASCII
+ * for /n or the modifier flags for others.
+ * b. US-ASCII source with non-ASCII literals: emit per-byte errors.
+ * c. Source encoding differs from modifier encoding: emit mismatch error.
+ *
+ * 2. Mixed \u and \x escapes: emit the appropriate conflict error depending
+ * on the modifier and which escape type was last.
+ *
+ * 3. \u escape with non-/u modifier: incompatible encoding error.
+ *
+ * 4. Validate that hex escape byte sequences form valid multibyte characters
+ * in the modifier's encoding.
+ */
+static pm_node_flags_t
+pm_regexp_validate_encoding_modifier(pm_regexp_parser_t *parser, bool ascii_only, pm_node_flags_t flags, char modifier, const pm_encoding_t *modifier_encoding, const char *source_start, int source_length) {
+
+ if (parser->explicit_encoding == NULL) {
+ if (ascii_only) {
+ // Check property escapes against the modifier's encoding tier.
+ // /n (ASCII-8BIT): only POSIX properties are valid.
+ // /e, /s: POSIX and script properties are valid.
+ // /u: all properties are valid.
+ if (modifier == 'n' && parser->property_name != NULL) {
+ PM_REGEXP_ENCODING_ERROR(parser, PM_ERR_REGEXP_INVALID_CHAR_PROPERTY,
+ (int) parser->property_name_length, (const char *) parser->property_name,
+ source_length, source_start);
+ } else if (modifier != 'u' && parser->has_unicode_property_escape) {
+ PM_REGEXP_ENCODING_ERROR(parser, PM_ERR_REGEXP_INVALID_CHAR_PROPERTY,
+ (int) parser->unicode_property_name_length, (const char *) parser->unicode_property_name,
+ source_length, source_start);
+ }
+ return modifier == 'n' ? PM_REGULAR_EXPRESSION_FLAGS_FORCED_US_ASCII_ENCODING : flags;
+ }
+
+ if (parser->encoding == PM_ENCODING_US_ASCII_ENTRY) {
+ for (uint32_t i = 0; i < parser->non_ascii_literal_count; i++) {
+ PM_REGEXP_ENCODING_ERROR(parser, PM_ERR_INVALID_MULTIBYTE_CHAR, parser->encoding->name);
+ }
+ } else if (parser->encoding != modifier_encoding) {
+ PM_REGEXP_ENCODING_ERROR(parser, PM_ERR_REGEXP_ENCODING_OPTION_MISMATCH, modifier, parser->encoding->name);
+
+ if (modifier == 'n' && !ascii_only) {
+ pm_buffer_t formatted = { 0 };
+ pm_regexp_format_for_error(&formatted, parser->encoding, (const uint8_t *) source_start, (size_t) source_length);
+ PM_REGEXP_ENCODING_ERROR(parser, PM_ERR_REGEXP_NON_ESCAPED_MBC, (int) formatted.length, (const char *) formatted.value);
+ pm_buffer_cleanup(&formatted);
+ }
+ }
+
+ return flags;
+ }
+
+ // Mixed unicode + hex escapes.
+ if (parser->has_unicode_escape && parser->has_hex_escape) {
+ if (modifier == 'n') {
+ if (parser->last_escape_was_unicode) {
+ PM_REGEXP_ENCODING_ERROR(parser, PM_ERR_REGEXP_UTF8_CHAR_NON_UTF8_REGEXP, source_length, source_start);
+ } else {
+ PM_REGEXP_ENCODING_ERROR(parser, PM_ERR_REGEXP_ESCAPED_NON_ASCII_IN_UTF8, source_length, source_start);
+ }
+ } else {
+ if (!pm_regexp_validate_hex_escapes(modifier_encoding, &parser->hex_escape_buffer)) {
+ PM_REGEXP_ENCODING_ERROR(parser, PM_ERR_INVALID_MULTIBYTE_ESCAPE, source_length, source_start);
+ }
+ }
+
+ return flags;
+ }
+
+ if (modifier != 'u' && parser->explicit_encoding == PM_ENCODING_UTF_8_ENTRY) {
+ if (parser->last_escape_was_unicode) {
+ PM_REGEXP_ENCODING_ERROR(parser, PM_ERR_REGEXP_INCOMPAT_CHAR_ENCODING, source_length, source_start);
+ } else if (parser->encoding != PM_ENCODING_UTF_8_ENTRY) {
+ PM_REGEXP_ENCODING_ERROR(parser, PM_ERR_REGEXP_INCOMPAT_CHAR_ENCODING, source_length, source_start);
+ }
+ }
+
+ if (modifier != 'n' && !pm_regexp_validate_hex_escapes(modifier_encoding, &parser->hex_escape_buffer)) {
+ PM_REGEXP_ENCODING_ERROR(parser, PM_ERR_INVALID_MULTIBYTE_ESCAPE, source_length, source_start);
+ }
+
+ return flags;
+}
+
+/**
+ * Validate encoding for a regexp without a modifier and compute the encoding
+ * flags to set on the node.
+ *
+ * The decision tree is:
+ *
+ * 1. If a modifier (/n, /u, /e, /s) is present, delegate to
+ * pm_regexp_validate_encoding_modifier.
+ * 2. Invalid multibyte chars or unicode ranges: suppress further checks (errors
+ * were already emitted during parsing).
+ * 3. US-ASCII source with non-ASCII literals: emit per-byte errors.
+ * 4. ASCII-only content: return forced US-ASCII (or forced UTF-8 if \p{...}).
+ * 5. Escape-set encoding present: validate hex escapes against the target
+ * encoding, handle mixed \u + \x conflicts, and return the appropriate
+ * forced encoding flag.
+ */
+static pm_node_flags_t
+pm_regexp_validate_encoding(pm_regexp_parser_t *parser, bool ascii_only, pm_node_flags_t flags, const char *source_start, int source_length) {
+
+ // Invalid multibyte characters suppress further validation.
+ // Errors were already emitted at the byte locations during parsing.
+ if (parser->has_invalid_multibyte) {
+ return flags;
+ }
+
+ if (parser->invalid_unicode_range) {
+ PM_REGEXP_ENCODING_ERROR(parser, PM_ERR_REGEXP_INVALID_UNICODE_RANGE, source_length, source_start);
+ return flags;
+ }
+
+ // Check modifier flags first.
+ if (flags & PM_REGULAR_EXPRESSION_FLAGS_ASCII_8BIT) {
+ return pm_regexp_validate_encoding_modifier(parser, ascii_only, flags, 'n', PM_ENCODING_ASCII_8BIT_ENTRY, source_start, source_length);
+ }
+ if (flags & PM_REGULAR_EXPRESSION_FLAGS_UTF_8) {
+ return pm_regexp_validate_encoding_modifier(parser, ascii_only, flags, 'u', PM_ENCODING_UTF_8_ENTRY, source_start, source_length);
+ }
+ if (flags & PM_REGULAR_EXPRESSION_FLAGS_EUC_JP) {
+ return pm_regexp_validate_encoding_modifier(parser, ascii_only, flags, 'e', PM_ENCODING_EUC_JP_ENTRY, source_start, source_length);
+ }
+ if (flags & PM_REGULAR_EXPRESSION_FLAGS_WINDOWS_31J) {
+ return pm_regexp_validate_encoding_modifier(parser, ascii_only, flags, 's', PM_ENCODING_WINDOWS_31J_ENTRY, source_start, source_length);
+ }
+
+ // No modifier — check for non-ASCII literals in US-ASCII encoding.
+ if (parser->encoding == PM_ENCODING_US_ASCII_ENTRY && parser->explicit_encoding == NULL && !ascii_only) {
+ for (uint32_t i = 0; i < parser->non_ascii_literal_count; i++) {
+ PM_REGEXP_ENCODING_ERROR(parser, PM_ERR_INVALID_MULTIBYTE_CHAR, parser->encoding->name);
+ }
+ }
+
+ // ASCII-only regexps get downgraded to US-ASCII, unless property escapes
+ // force UTF-8.
+ if (ascii_only) {
+ if (parser->has_property_escape) {
+ return PM_REGULAR_EXPRESSION_FLAGS_FORCED_UTF8_ENCODING;
+ }
+ return PM_REGULAR_EXPRESSION_FLAGS_FORCED_US_ASCII_ENCODING;
+ }
+
+ // Check explicit encoding from escape sequences.
+ if (parser->explicit_encoding != NULL) {
+ // Mixed unicode + hex escapes without modifier.
+ if (parser->has_unicode_escape && parser->has_hex_escape && parser->encoding != PM_ENCODING_UTF_8_ENTRY) {
+ if (parser->encoding != PM_ENCODING_US_ASCII_ENTRY &&
+ parser->encoding != PM_ENCODING_ASCII_8BIT_ENTRY &&
+ !pm_regexp_validate_hex_escapes(parser->encoding, &parser->hex_escape_buffer)) {
+ PM_REGEXP_ENCODING_ERROR(parser, PM_ERR_INVALID_MULTIBYTE_ESCAPE, source_length, source_start);
+ } else if (parser->last_escape_was_unicode) {
+ PM_REGEXP_ENCODING_ERROR(parser, PM_ERR_REGEXP_UTF8_CHAR_NON_UTF8_REGEXP, source_length, source_start);
+ } else {
+ PM_REGEXP_ENCODING_ERROR(parser, PM_ERR_REGEXP_ESCAPED_NON_ASCII_IN_UTF8, source_length, source_start);
+ }
+
+ return 0;
+ }
+
+ if (parser->explicit_encoding == PM_ENCODING_UTF_8_ENTRY) {
+ if (!pm_regexp_validate_hex_escapes(parser->explicit_encoding, &parser->hex_escape_buffer)) {
+ PM_REGEXP_ENCODING_ERROR(parser, PM_ERR_INVALID_MULTIBYTE_ESCAPE, source_length, source_start);
+ }
+
+ 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;
+ } else {
+ if (!pm_regexp_validate_hex_escapes(parser->explicit_encoding, &parser->hex_escape_buffer)) {
+ PM_REGEXP_ENCODING_ERROR(parser, PM_ERR_INVALID_MULTIBYTE_ESCAPE, source_length, source_start);
+ }
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * Parse a regular expression, validate its encoding, and optionally extract
+ * named capture groups. Encoding validation walks the raw source (content_loc)
+ * to distinguish escape-produced bytes from literal bytes. Named capture
+ * extraction walks the unescaped content since escape sequences in group names
+ * (e.g., line continuations) have already been processed by the lexer.
+ */
+pm_node_flags_t
+pm_regexp_parse(pm_parser_t *parser, pm_regular_expression_node_t *node, pm_regexp_name_callback_t name_callback, pm_regexp_name_data_t *name_data) {
+ const uint8_t *source = parser->start + node->content_loc.start;
+ size_t size = node->content_loc.length;
+ bool extended_mode = PM_NODE_FLAG_P(node, PM_REGULAR_EXPRESSION_FLAGS_EXTENDED);
+ pm_node_flags_t flags = PM_NODE_FLAGS(node);
+
+ const uint8_t *node_start = parser->start + node->base.location.start;
+ const uint8_t *node_end = parser->start + node->base.location.start + node->base.location.length;
+
+ // First pass: walk raw source for encoding validation (no name extraction).
+ pm_regexp_parser_t regexp_parser = {
+ .parser = parser,
+ .start = source,
+ .cursor = source,
+ .end = source + size,
+ .extended_mode = extended_mode,
+ .encoding_changed = parser->encoding_changed,
+ .encoding = parser->encoding,
+ .name_callback = NULL,
+ .name_data = NULL,
+ .shared = true,
+ .node_start = node_start,
+ .node_end = node_end,
+ .has_unicode_escape = false,
+ .has_hex_escape = false,
+ .last_escape_was_unicode = false,
+ .explicit_encoding = NULL,
+ .has_property_escape = false,
+ .has_unicode_property_escape = false,
+ .property_name = NULL,
+ .property_name_length = 0,
+ .unicode_property_name = NULL,
+ .unicode_property_name_length = 0,
+ .non_ascii_literal_count = 0,
+ .invalid_unicode_range = false,
+ .hex_escape_buffer = { 0 },
+ .hex_group_active = false,
+ .has_invalid_multibyte = false,
+ };
+
+ pm_regexp_parse_pattern(&regexp_parser);
+
+ // Compute ascii_only from the regexp parser's tracked state. We cannot
+ // use node->unescaped for this because regexp unescaped content preserves
+ // escape text (e.g., \x80 is 4 ASCII chars), not the binary values.
+ bool ascii_only = !regexp_parser.has_hex_escape && !regexp_parser.has_unicode_escape && regexp_parser.non_ascii_literal_count == 0;
+ // Use the unescaped content for error messages to match CRuby's format,
+ // where Ruby escapes like \M-\C-? are resolved to bytes but regexp escapes
+ // like \u{80} are preserved as text.
+ const char *error_source = (const char *) pm_string_source(&node->unescaped);
+ int error_source_length = (int) pm_string_length(&node->unescaped);
+ pm_node_flags_t encoding_flags = pm_regexp_validate_encoding(&regexp_parser, ascii_only, flags, error_source, error_source_length);
+ pm_buffer_cleanup(&regexp_parser.hex_escape_buffer);
+
+ // Second pass: walk unescaped content for named capture extraction.
+ if (name_callback != NULL) {
+ bool shared = node->unescaped.type == PM_STRING_SHARED;
+ pm_regexp_parse_named_captures(parser, pm_string_source(&node->unescaped), pm_string_length(&node->unescaped), shared, extended_mode, name_callback, name_data);
+ }
+
+ return encoding_flags;
+}
+
+/**
+ * Parse an interpolated regular expression for named capture groups only.
+ * This is used for the =~ operator with interpolated regexps where we don't
+ * have a pm_regular_expression_node_t. No encoding validation is performed.
+ *
+ * Note: The encoding-tracking fields (has_unicode_escape, has_hex_escape, etc.)
+ * are initialized but not used for the result. They exist because the parsing
+ * functions (pm_regexp_parse_backslash_escape, etc.) unconditionally update
+ * them as they walk through the content.
*/
-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) {
+void
+pm_regexp_parse_named_captures(pm_parser_t *parser, const uint8_t *source, size_t size, bool shared, bool extended_mode, pm_regexp_name_callback_t name_callback, pm_regexp_name_data_t *name_data) {
+ pm_regexp_parser_t regexp_parser = {
.parser = parser,
.start = source,
.cursor = source,
@@ -784,7 +1692,26 @@ pm_regexp_parse(pm_parser_t *parser, const uint8_t *source, size_t size, bool ex
.encoding = parser->encoding,
.name_callback = name_callback,
.name_data = name_data,
- .error_callback = error_callback,
- .error_data = error_data
- });
+ .shared = shared,
+ .node_start = source,
+ .node_end = source + size,
+ .has_unicode_escape = false,
+ .has_hex_escape = false,
+ .last_escape_was_unicode = false,
+ .explicit_encoding = NULL,
+ .has_property_escape = false,
+ .has_unicode_property_escape = false,
+ .property_name = NULL,
+ .property_name_length = 0,
+ .unicode_property_name = NULL,
+ .unicode_property_name_length = 0,
+ .non_ascii_literal_count = 0,
+ .invalid_unicode_range = false,
+ .hex_escape_buffer = { 0 },
+ .hex_group_active = false,
+ .has_invalid_multibyte = false,
+ };
+
+ pm_regexp_parse_pattern(&regexp_parser);
+ pm_buffer_cleanup(&regexp_parser.hex_escape_buffer);
}
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/serialize.h b/prism/serialize.h
new file mode 100644
index 0000000000..786a1514bc
--- /dev/null
+++ b/prism/serialize.h
@@ -0,0 +1,96 @@
+/**
+ * @file serialize.h
+ *
+ * The functions related to serializing the AST to a binary format.
+ */
+#ifndef PRISM_SERIALIZE_H
+#define PRISM_SERIALIZE_H
+
+#include "prism/excludes.h"
+
+/* We optionally support serializing to a binary string. For systems that do not
+ * want or need this functionality, it can be turned off with the
+ * PRISM_EXCLUDE_SERIALIZATION define. */
+#ifndef PRISM_EXCLUDE_SERIALIZATION
+
+#include "prism/compiler/exported.h"
+#include "prism/compiler/nonnull.h"
+
+#include "prism/buffer.h"
+#include "prism/parser.h"
+#include "prism/source.h"
+#include "prism/stream.h"
+
+/**
+ * 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) PRISM_NONNULL(1, 2, 3);
+
+/**
+ * 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) PRISM_NONNULL(1, 2);
+
+/**
+ * Parse and serialize the AST represented by the given source into the given
+ * buffer.
+ *
+ * @param buffer The buffer to serialize to.
+ * @param source The source to parse.
+ * @param data The optional data to pass to the parser.
+ */
+PRISM_EXPORTED_FUNCTION void pm_serialize_parse_stream(pm_buffer_t *buffer, pm_source_t *source, const char *data) PRISM_NONNULL(1, 2);
+
+/**
+ * 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) PRISM_NONNULL(1, 2);
+
+/**
+ * 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) PRISM_NONNULL(1, 2);
+
+/**
+ * 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) PRISM_NONNULL(1, 2);
+
+/**
+ * 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.
+ * @returns True if the source parses without errors or warnings.
+ */
+PRISM_EXPORTED_FUNCTION bool pm_serialize_parse_success_p(const uint8_t *source, size_t size, const char *data) PRISM_NONNULL(1);
+
+#endif
+
+#endif
diff --git a/prism/source.c b/prism/source.c
new file mode 100644
index 0000000000..f61cb19c1b
--- /dev/null
+++ b/prism/source.c
@@ -0,0 +1,491 @@
+#include "prism/internal/source.h"
+
+#include "prism/internal/allocator.h"
+#include "prism/internal/buffer.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
+
+static const uint8_t empty_source[] = "";
+
+/**
+ * Allocate and initialize a pm_source_t with the given fields.
+ */
+static pm_source_t *
+pm_source_alloc(const uint8_t *source, size_t length, pm_source_type_t type) {
+ pm_source_t *result = xmalloc(sizeof(pm_source_t));
+ if (result == NULL) abort();
+
+ *result = (struct pm_source_t) {
+ .source = source,
+ .length = length,
+ .type = type
+ };
+
+ return result;
+}
+
+/**
+ * Create a new source that wraps existing constant memory.
+ */
+pm_source_t *
+pm_source_constant_new(const uint8_t *data, size_t length) {
+ return pm_source_alloc(data, length, PM_SOURCE_CONSTANT);
+}
+
+/**
+ * Create a new source that wraps existing shared memory.
+ */
+pm_source_t *
+pm_source_shared_new(const uint8_t *data, size_t length) {
+ return pm_source_alloc(data, length, PM_SOURCE_SHARED);
+}
+
+/**
+ * Create a new source that owns its memory.
+ */
+pm_source_t *
+pm_source_owned_new(uint8_t *data, size_t length) {
+ return pm_source_alloc(data, length, PM_SOURCE_OWNED);
+}
+
+#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 size of the allocated path in bytes. */
+ size_t path_size;
+
+ /** The handle to the file, which will start as uninitialized memory. */
+ HANDLE file;
+} pm_source_file_handle_t;
+
+/**
+ * Open the file indicated by the filepath parameter for reading on Windows.
+ */
+static pm_source_init_result_t
+pm_source_file_handle_open(pm_source_file_handle_t *handle, const char *filepath) {
+ int length = MultiByteToWideChar(CP_UTF8, 0, filepath, -1, NULL, 0);
+ if (length == 0) return PM_SOURCE_INIT_ERROR_GENERIC;
+
+ handle->path_size = sizeof(WCHAR) * ((size_t) length);
+ handle->path = xmalloc(handle->path_size);
+ if ((handle->path == NULL) || (MultiByteToWideChar(CP_UTF8, 0, filepath, -1, handle->path, length) == 0)) {
+ xfree_sized(handle->path, handle->path_size);
+ return PM_SOURCE_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_source_init_result_t result = PM_SOURCE_INIT_ERROR_GENERIC;
+
+ if (GetLastError() == ERROR_ACCESS_DENIED) {
+ DWORD attributes = GetFileAttributesW(handle->path);
+ if ((attributes != INVALID_FILE_ATTRIBUTES) && (attributes & FILE_ATTRIBUTE_DIRECTORY)) {
+ result = PM_SOURCE_INIT_ERROR_DIRECTORY;
+ }
+ }
+
+ xfree_sized(handle->path, handle->path_size);
+ return result;
+ }
+
+ return PM_SOURCE_INIT_SUCCESS;
+}
+
+/**
+ * Close the file handle and free the path.
+ */
+static void
+pm_source_file_handle_close(pm_source_file_handle_t *handle) {
+ xfree_sized(handle->path, handle->path_size);
+ CloseHandle(handle->file);
+}
+#endif
+
+/**
+ * Create a new source by memory-mapping a file.
+ */
+pm_source_t *
+pm_source_mapped_new(const char *filepath, int open_flags, pm_source_init_result_t *result) {
+#ifdef _WIN32
+ (void) open_flags;
+
+ /* Open the file for reading. */
+ pm_source_file_handle_t handle;
+ *result = pm_source_file_handle_open(&handle, filepath);
+ if (*result != PM_SOURCE_INIT_SUCCESS) return NULL;
+
+ /* Get the file size. */
+ DWORD file_size = GetFileSize(handle.file, NULL);
+ if (file_size == INVALID_FILE_SIZE) {
+ pm_source_file_handle_close(&handle);
+ *result = PM_SOURCE_INIT_ERROR_GENERIC;
+ return NULL;
+ }
+
+ /* If the file is empty, then return a constant source. */
+ if (file_size == 0) {
+ pm_source_file_handle_close(&handle);
+ *result = PM_SOURCE_INIT_SUCCESS;
+ return pm_source_alloc(empty_source, 0, PM_SOURCE_CONSTANT);
+ }
+
+ /* Create a mapping of the file. */
+ HANDLE mapping = CreateFileMapping(handle.file, NULL, PAGE_READONLY, 0, 0, NULL);
+ if (mapping == NULL) {
+ pm_source_file_handle_close(&handle);
+ *result = PM_SOURCE_INIT_ERROR_GENERIC;
+ return NULL;
+ }
+
+ /* Map the file into memory. */
+ uint8_t *source = (uint8_t *) MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, 0);
+ CloseHandle(mapping);
+ pm_source_file_handle_close(&handle);
+
+ if (source == NULL) {
+ *result = PM_SOURCE_INIT_ERROR_GENERIC;
+ return NULL;
+ }
+
+ *result = PM_SOURCE_INIT_SUCCESS;
+ return pm_source_alloc(source, (size_t) file_size, PM_SOURCE_MAPPED);
+#elif defined(_POSIX_MAPPED_FILES)
+ /* Open the file for reading. */
+ int fd = open(filepath, O_RDONLY | open_flags);
+ if (fd == -1) {
+ *result = PM_SOURCE_INIT_ERROR_GENERIC;
+ return NULL;
+ }
+
+ /* Stat the file to get the file size. */
+ struct stat sb;
+ if (fstat(fd, &sb) == -1) {
+ close(fd);
+ *result = PM_SOURCE_INIT_ERROR_GENERIC;
+ return NULL;
+ }
+
+ /* Ensure it is a file and not a directory. */
+ if (S_ISDIR(sb.st_mode)) {
+ close(fd);
+ *result = PM_SOURCE_INIT_ERROR_DIRECTORY;
+ return NULL;
+ }
+
+ /*
+ * For non-regular files (pipes, character devices), return a specific
+ * error so the caller can handle reading through their own I/O layer.
+ */
+ if (!S_ISREG(sb.st_mode)) {
+ close(fd);
+ *result = PM_SOURCE_INIT_ERROR_NON_REGULAR;
+ return NULL;
+ }
+
+ /* mmap the file descriptor to virtually get the contents. */
+ size_t size = (size_t) sb.st_size;
+
+ if (size == 0) {
+ close(fd);
+ *result = PM_SOURCE_INIT_SUCCESS;
+ return pm_source_alloc(empty_source, 0, PM_SOURCE_CONSTANT);
+ }
+
+ uint8_t *source = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
+ if (source == MAP_FAILED) {
+ close(fd);
+ *result = PM_SOURCE_INIT_ERROR_GENERIC;
+ return NULL;
+ }
+
+ close(fd);
+ *result = PM_SOURCE_INIT_SUCCESS;
+ return pm_source_alloc(source, size, PM_SOURCE_MAPPED);
+#else
+ (void) open_flags;
+ return pm_source_file_new(filepath, result);
+#endif
+}
+
+/**
+ * Create a new source by reading a file into a heap-allocated buffer.
+ */
+pm_source_t *
+pm_source_file_new(const char *filepath, pm_source_init_result_t *result) {
+#ifdef _WIN32
+ /* Open the file for reading. */
+ pm_source_file_handle_t handle;
+ *result = pm_source_file_handle_open(&handle, filepath);
+ if (*result != PM_SOURCE_INIT_SUCCESS) return NULL;
+
+ /* Get the file size. */
+ const DWORD file_size = GetFileSize(handle.file, NULL);
+ if (file_size == INVALID_FILE_SIZE) {
+ pm_source_file_handle_close(&handle);
+ *result = PM_SOURCE_INIT_ERROR_GENERIC;
+ return NULL;
+ }
+
+ /* If the file is empty, return a constant source. */
+ if (file_size == 0) {
+ pm_source_file_handle_close(&handle);
+ *result = PM_SOURCE_INIT_SUCCESS;
+ return pm_source_alloc(empty_source, 0, PM_SOURCE_CONSTANT);
+ }
+
+ /* Create a buffer to read the file into. */
+ uint8_t *source = xmalloc(file_size);
+ if (source == NULL) {
+ pm_source_file_handle_close(&handle);
+ *result = PM_SOURCE_INIT_ERROR_GENERIC;
+ return NULL;
+ }
+
+ /* Read the contents of the file. */
+ DWORD bytes_read;
+ if (!ReadFile(handle.file, source, file_size, &bytes_read, NULL)) {
+ xfree_sized(source, file_size);
+ pm_source_file_handle_close(&handle);
+ *result = PM_SOURCE_INIT_ERROR_GENERIC;
+ return NULL;
+ }
+
+ /* Check the number of bytes read. */
+ if (bytes_read != file_size) {
+ xfree_sized(source, file_size);
+ pm_source_file_handle_close(&handle);
+ *result = PM_SOURCE_INIT_ERROR_GENERIC;
+ return NULL;
+ }
+
+ pm_source_file_handle_close(&handle);
+ *result = PM_SOURCE_INIT_SUCCESS;
+ return pm_source_alloc(source, (size_t) file_size, PM_SOURCE_OWNED);
+#elif defined(PRISM_HAS_FILESYSTEM)
+ /* Open the file for reading. */
+ int fd = open(filepath, O_RDONLY);
+ if (fd == -1) {
+ *result = PM_SOURCE_INIT_ERROR_GENERIC;
+ return NULL;
+ }
+
+ /* Stat the file to get the file size. */
+ struct stat sb;
+ if (fstat(fd, &sb) == -1) {
+ close(fd);
+ *result = PM_SOURCE_INIT_ERROR_GENERIC;
+ return NULL;
+ }
+
+ /* Ensure it is a file and not a directory. */
+ if (S_ISDIR(sb.st_mode)) {
+ close(fd);
+ *result = PM_SOURCE_INIT_ERROR_DIRECTORY;
+ return NULL;
+ }
+
+ /* Check the size to see if it's empty. */
+ size_t size = (size_t) sb.st_size;
+ if (size == 0) {
+ close(fd);
+ *result = PM_SOURCE_INIT_SUCCESS;
+ return pm_source_alloc(empty_source, 0, PM_SOURCE_CONSTANT);
+ }
+
+ const size_t length = (size_t) size;
+ uint8_t *source = xmalloc(length);
+ if (source == NULL) {
+ close(fd);
+ *result = PM_SOURCE_INIT_ERROR_GENERIC;
+ return NULL;
+ }
+
+ ssize_t bytes_read = read(fd, source, length);
+ close(fd);
+
+ if (bytes_read == -1 || (size_t) bytes_read != length) {
+ xfree_sized(source, length);
+ *result = PM_SOURCE_INIT_ERROR_GENERIC;
+ return NULL;
+ }
+
+ *result = PM_SOURCE_INIT_SUCCESS;
+ return pm_source_alloc(source, length, PM_SOURCE_OWNED);
+#else
+ (void) filepath;
+ *result = PM_SOURCE_INIT_ERROR_GENERIC;
+ perror("pm_source_file_new is not implemented for this platform");
+ return NULL;
+#endif
+}
+
+/**
+ * Create a new source by reading from a stream. This allocates the source
+ * but does not read from the stream yet. Use pm_source_stream_read to read
+ * data.
+ */
+pm_source_t *
+pm_source_stream_new(void *stream, pm_source_stream_fgets_t *fgets, pm_source_stream_feof_t *feof) {
+ pm_source_t *source = pm_source_alloc(NULL, 0, PM_SOURCE_STREAM);
+ source->stream.buffer = pm_buffer_new();
+ source->stream.stream = stream;
+ source->stream.fgets = fgets;
+ source->stream.feof = feof;
+ source->stream.eof = false;
+
+ return source;
+}
+
+/**
+ * Read from the stream into the source's internal buffer until __END__ is
+ * encountered or EOF is reached. Updates the source pointer and length.
+ *
+ * Returns true if EOF was reached, false if __END__ was encountered.
+ */
+bool
+pm_source_stream_read(pm_source_t *source) {
+ pm_buffer_t *buffer = source->stream.buffer;
+
+#define LINE_SIZE 4096
+ char line[LINE_SIZE];
+
+ while (memset(line, '\n', LINE_SIZE), source->stream.fgets(line, LINE_SIZE, source->stream.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) {
+ source->source = (const uint8_t *) pm_buffer_value(buffer);
+ source->length = pm_buffer_length(buffer);
+ return false;
+ }
+ break;
+ case 8:
+ if (strncmp(line, "__END__\n", 8) == 0) {
+ source->source = (const uint8_t *) pm_buffer_value(buffer);
+ source->length = pm_buffer_length(buffer);
+ return false;
+ }
+ break;
+ case 9:
+ if (strncmp(line, "__END__\r\n", 9) == 0) {
+ source->source = (const uint8_t *) pm_buffer_value(buffer);
+ source->length = pm_buffer_length(buffer);
+ return false;
+ }
+ break;
+ }
+
+ /*
+ * All data should be read via gets. If the string returned by gets
+ * _doesn't_ end with a newline, then we assume we hit EOF condition.
+ */
+ if (source->stream.feof(source->stream.stream)) {
+ break;
+ }
+ }
+
+#undef LINE_SIZE
+
+ source->stream.eof = true;
+ source->source = (const uint8_t *) pm_buffer_value(buffer);
+ source->length = pm_buffer_length(buffer);
+ return true;
+}
+
+/**
+ * Returns whether the stream source has reached EOF.
+ */
+bool
+pm_source_stream_eof(const pm_source_t *source) {
+ return source->stream.eof;
+}
+
+/**
+ * Free the given source and any memory it owns.
+ */
+void
+pm_source_free(pm_source_t *source) {
+ switch (source->type) {
+ case PM_SOURCE_CONSTANT:
+ case PM_SOURCE_SHARED:
+ /* No cleanup needed for the data. */
+ break;
+ case PM_SOURCE_OWNED:
+ xfree_sized((void *) source->source, source->length);
+ break;
+ case PM_SOURCE_MAPPED:
+#if defined(_WIN32)
+ if (source->length > 0) {
+ UnmapViewOfFile((void *) source->source);
+ }
+#elif defined(_POSIX_MAPPED_FILES)
+ if (source->length > 0) {
+ munmap((void *) source->source, source->length);
+ }
+#endif
+ break;
+ case PM_SOURCE_STREAM:
+ pm_buffer_free(source->stream.buffer);
+ break;
+ }
+
+ xfree_sized(source, sizeof(pm_source_t));
+}
+
+/**
+ * Returns the length of the source data in bytes.
+ */
+size_t
+pm_source_length(const pm_source_t *source) {
+ return source->length;
+}
+
+/**
+ * Returns a pointer to the source data.
+ */
+const uint8_t *
+pm_source_source(const pm_source_t *source) {
+ return source->source;
+}
diff --git a/prism/source.h b/prism/source.h
new file mode 100644
index 0000000000..c79987d3fb
--- /dev/null
+++ b/prism/source.h
@@ -0,0 +1,148 @@
+/**
+ * @file source.h
+ *
+ * An opaque type representing the source code being parsed, regardless of
+ * origin (constant memory, file, memory-mapped file, or stream).
+ */
+#ifndef PRISM_SOURCE_H
+#define PRISM_SOURCE_H
+
+#include "prism/compiler/exported.h"
+#include "prism/compiler/filesystem.h"
+#include "prism/compiler/nodiscard.h"
+#include "prism/compiler/nonnull.h"
+
+#include <stddef.h>
+#include <stdint.h>
+
+/**
+ * An opaque type representing source code being parsed.
+ */
+typedef struct pm_source_t pm_source_t;
+
+/**
+ * This function is used 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_source_stream_fgets_t)(char *string, int size, void *stream);
+
+/**
+ * This function is used to check whether a stream is at EOF. It closely mirrors
+ * that of feof so that feof can be used as the default implementation.
+ */
+typedef int (pm_source_stream_feof_t)(void *stream);
+
+/**
+ * Represents the result of initializing a source from a file.
+ */
+typedef enum {
+ /** Indicates that the source was successfully initialized. */
+ PM_SOURCE_INIT_SUCCESS = 0,
+
+ /**
+ * Indicates a generic error from a source init function, where the type
+ * of error should be read from `errno` or `GetLastError()`.
+ */
+ PM_SOURCE_INIT_ERROR_GENERIC = 1,
+
+ /**
+ * Indicates that the file that was attempted to be opened was a directory.
+ */
+ PM_SOURCE_INIT_ERROR_DIRECTORY = 2,
+
+ /**
+ * Indicates that the file is not a regular file (e.g. a pipe or character
+ * device) and the caller should handle reading it.
+ */
+ PM_SOURCE_INIT_ERROR_NON_REGULAR = 3
+} pm_source_init_result_t;
+
+/**
+ * Create a new source that wraps existing constant memory. The memory is not
+ * owned and will not be freed.
+ *
+ * @param data The pointer to the source data.
+ * @param length The length of the source data in bytes.
+ * @returns A new source. Aborts on allocation failure.
+ */
+PRISM_EXPORTED_FUNCTION PRISM_NODISCARD pm_source_t * pm_source_constant_new(const uint8_t *data, size_t length);
+
+/**
+ * Create a new source that wraps existing shared memory. The memory is not
+ * owned and will not be freed. Semantically a "slice" of another source.
+ *
+ * @param data The pointer to the source data.
+ * @param length The length of the source data in bytes.
+ * @returns A new source. Aborts on allocation failure.
+ */
+PRISM_EXPORTED_FUNCTION PRISM_NODISCARD pm_source_t * pm_source_shared_new(const uint8_t *data, size_t length);
+
+/**
+ * Create a new source that owns its memory. The memory will be freed with
+ * xfree when the source is freed.
+ *
+ * @param data The pointer to the heap-allocated source data.
+ * @param length The length of the source data in bytes.
+ * @returns A new source. Aborts on allocation failure.
+ */
+PRISM_EXPORTED_FUNCTION PRISM_NODISCARD pm_source_t * pm_source_owned_new(uint8_t *data, size_t length);
+
+/**
+ * Create a new source by reading a file into a heap-allocated buffer.
+ *
+ * @param filepath The path to the file to read.
+ * @param result Out parameter for the result of the initialization.
+ * @returns A new source, or NULL on error (with result written to out param).
+ */
+PRISM_EXPORTED_FUNCTION PRISM_NODISCARD pm_source_t * pm_source_file_new(const char *filepath, pm_source_init_result_t *result) PRISM_NONNULL(1, 2);
+
+/**
+ * Create a new source by memory-mapping a file. Falls back to file reading on
+ * platforms without mmap support.
+ *
+ * If the file is a non-regular file (e.g. a pipe or character device),
+ * PM_SOURCE_INIT_ERROR_NON_REGULAR is returned, allowing the caller to handle
+ * it appropriately (e.g. by reading it through their own I/O layer).
+ *
+ * @param filepath The path to the file to read.
+ * @param open_flags Additional flags to pass to open(2) (e.g. O_NONBLOCK).
+ * @param result Out parameter for the result of the initialization.
+ * @returns A new source, or NULL on error (with result written to out param).
+ */
+PRISM_EXPORTED_FUNCTION PRISM_NODISCARD pm_source_t * pm_source_mapped_new(const char *filepath, int open_flags, pm_source_init_result_t *result) PRISM_NONNULL(1, 3);
+
+/**
+ * Create a new source by reading from a stream using the provided callbacks.
+ *
+ * @param stream The stream to read from.
+ * @param fgets The function to use to read from the stream.
+ * @param feof The function to use to check if the stream is at EOF.
+ * @returns A new source. Aborts on allocation failure.
+ */
+PRISM_EXPORTED_FUNCTION PRISM_NODISCARD pm_source_t * pm_source_stream_new(void *stream, pm_source_stream_fgets_t *fgets, pm_source_stream_feof_t *feof);
+
+/**
+ * Free the given source and any memory it owns.
+ *
+ * @param source The source to free.
+ */
+PRISM_EXPORTED_FUNCTION void pm_source_free(pm_source_t *source) PRISM_NONNULL(1);
+
+/**
+ * Returns the length of the source data in bytes.
+ *
+ * @param source The source to get the length of.
+ * @returns The length of the source data.
+ */
+PRISM_EXPORTED_FUNCTION size_t pm_source_length(const pm_source_t *source) PRISM_NONNULL(1);
+
+/**
+ * Returns a pointer to the source data.
+ *
+ * @param source The source to get the data of.
+ * @returns A pointer to the source data.
+ */
+PRISM_EXPORTED_FUNCTION const uint8_t * pm_source_source(const pm_source_t *source) PRISM_NONNULL(1);
+
+#endif
diff --git a/prism/srcs.mk b/prism/srcs.mk
index aa5c0fa2b5..93ad8f579f 100644
--- a/prism/srcs.mk
+++ b/prism/srcs.mk
@@ -4,139 +4,157 @@ PRISM_CONFIG = $(PRISM_SRCDIR)/config.yml
srcs uncommon.mk: prism/.srcs.mk.time
-prism/.srcs.mk.time:
+prism/.srcs.mk.time: $(order_only) $(PRISM_BUILD_DIR)/.time
+prism/$(HAVE_BASERUBY:no=.srcs.mk.time):
+ touch $@
prism/$(HAVE_BASERUBY:yes=.srcs.mk.time): \
$(PRISM_SRCDIR)/templates/template.rb \
$(PRISM_SRCDIR)/srcs.mk.in
$(BASERUBY) $(tooldir)/generic_erb.rb -c -t$@ -o $(PRISM_SRCDIR)/srcs.mk $(PRISM_SRCDIR)/srcs.mk.in
-realclean-prism-srcs::
+distclean-prism-srcs::
+ $(RM) prism/.srcs.mk.time
+ $(RMDIRS) prism || $(NULLCMD)
+
+distclean-srcs-local:: distclean-prism-srcs
+
+realclean-prism-srcs:: distclean-prism-srcs
$(RM) $(PRISM_SRCDIR)/srcs.mk
realclean-srcs-local:: realclean-prism-srcs
-main srcs: $(srcdir)/prism/api_node.c
+main srcs: prism-srcs
+main incs: prism-incs
+
+prism-srcs: $(srcdir)/prism/api_node.c
$(srcdir)/prism/api_node.c: $(PRISM_CONFIG) $(PRISM_TEMPLATE) $(PRISM_TEMPLATES_DIR)/ext/prism/api_node.c.erb
$(Q) $(BASERUBY) $(PRISM_TEMPLATE) ext/prism/api_node.c $@
realclean-prism-srcs::
$(RM) $(srcdir)/prism/api_node.c
-main incs: $(srcdir)/prism/ast.h
+prism-incs: $(srcdir)/prism/ast.h
$(srcdir)/prism/ast.h: $(PRISM_CONFIG) $(PRISM_TEMPLATE) $(PRISM_TEMPLATES_DIR)/include/prism/ast.h.erb
$(Q) $(BASERUBY) $(PRISM_TEMPLATE) include/prism/ast.h $@
realclean-prism-srcs::
$(RM) $(srcdir)/prism/ast.h
-main incs: $(srcdir)/prism/diagnostic.h
-$(srcdir)/prism/diagnostic.h: $(PRISM_CONFIG) $(PRISM_TEMPLATE) $(PRISM_TEMPLATES_DIR)/include/prism/diagnostic.h.erb
- $(Q) $(BASERUBY) $(PRISM_TEMPLATE) include/prism/diagnostic.h $@
+prism-incs: $(srcdir)/prism/internal/diagnostic.h
+$(srcdir)/prism/internal/diagnostic.h: $(PRISM_CONFIG) $(PRISM_TEMPLATE) $(PRISM_TEMPLATES_DIR)/include/prism/internal/diagnostic.h.erb
+ $(Q) $(BASERUBY) $(PRISM_TEMPLATE) include/prism/internal/diagnostic.h $@
realclean-prism-srcs::
- $(RM) $(srcdir)/prism/diagnostic.h
+ $(RM) $(srcdir)/prism/internal/diagnostic.h
-main srcs: $(srcdir)/lib/prism/compiler.rb
+prism-srcs: $(srcdir)/lib/prism/compiler.rb
$(srcdir)/lib/prism/compiler.rb: $(PRISM_CONFIG) $(PRISM_TEMPLATE) $(PRISM_TEMPLATES_DIR)/lib/prism/compiler.rb.erb
$(Q) $(BASERUBY) $(PRISM_TEMPLATE) lib/prism/compiler.rb $@
realclean-prism-srcs::
$(RM) $(srcdir)/lib/prism/compiler.rb
-main srcs: $(srcdir)/lib/prism/dispatcher.rb
+prism-srcs: $(srcdir)/lib/prism/dispatcher.rb
$(srcdir)/lib/prism/dispatcher.rb: $(PRISM_CONFIG) $(PRISM_TEMPLATE) $(PRISM_TEMPLATES_DIR)/lib/prism/dispatcher.rb.erb
$(Q) $(BASERUBY) $(PRISM_TEMPLATE) lib/prism/dispatcher.rb $@
realclean-prism-srcs::
$(RM) $(srcdir)/lib/prism/dispatcher.rb
-main srcs: $(srcdir)/lib/prism/dot_visitor.rb
+prism-srcs: $(srcdir)/lib/prism/dot_visitor.rb
$(srcdir)/lib/prism/dot_visitor.rb: $(PRISM_CONFIG) $(PRISM_TEMPLATE) $(PRISM_TEMPLATES_DIR)/lib/prism/dot_visitor.rb.erb
$(Q) $(BASERUBY) $(PRISM_TEMPLATE) lib/prism/dot_visitor.rb $@
realclean-prism-srcs::
$(RM) $(srcdir)/lib/prism/dot_visitor.rb
-main srcs: $(srcdir)/lib/prism/dsl.rb
+prism-srcs: $(srcdir)/lib/prism/dsl.rb
$(srcdir)/lib/prism/dsl.rb: $(PRISM_CONFIG) $(PRISM_TEMPLATE) $(PRISM_TEMPLATES_DIR)/lib/prism/dsl.rb.erb
$(Q) $(BASERUBY) $(PRISM_TEMPLATE) lib/prism/dsl.rb $@
realclean-prism-srcs::
$(RM) $(srcdir)/lib/prism/dsl.rb
-main srcs: $(srcdir)/lib/prism/inspect_visitor.rb
+prism-srcs: $(srcdir)/lib/prism/inspect_visitor.rb
$(srcdir)/lib/prism/inspect_visitor.rb: $(PRISM_CONFIG) $(PRISM_TEMPLATE) $(PRISM_TEMPLATES_DIR)/lib/prism/inspect_visitor.rb.erb
$(Q) $(BASERUBY) $(PRISM_TEMPLATE) lib/prism/inspect_visitor.rb $@
realclean-prism-srcs::
$(RM) $(srcdir)/lib/prism/inspect_visitor.rb
-main srcs: $(srcdir)/lib/prism/mutation_compiler.rb
+prism-srcs: $(srcdir)/lib/prism/mutation_compiler.rb
$(srcdir)/lib/prism/mutation_compiler.rb: $(PRISM_CONFIG) $(PRISM_TEMPLATE) $(PRISM_TEMPLATES_DIR)/lib/prism/mutation_compiler.rb.erb
$(Q) $(BASERUBY) $(PRISM_TEMPLATE) lib/prism/mutation_compiler.rb $@
realclean-prism-srcs::
$(RM) $(srcdir)/lib/prism/mutation_compiler.rb
-main srcs: $(srcdir)/lib/prism/node.rb
+prism-srcs: $(srcdir)/lib/prism/node.rb
$(srcdir)/lib/prism/node.rb: $(PRISM_CONFIG) $(PRISM_TEMPLATE) $(PRISM_TEMPLATES_DIR)/lib/prism/node.rb.erb
$(Q) $(BASERUBY) $(PRISM_TEMPLATE) lib/prism/node.rb $@
realclean-prism-srcs::
$(RM) $(srcdir)/lib/prism/node.rb
-main srcs: $(srcdir)/lib/prism/reflection.rb
+prism-srcs: $(srcdir)/lib/prism/reflection.rb
$(srcdir)/lib/prism/reflection.rb: $(PRISM_CONFIG) $(PRISM_TEMPLATE) $(PRISM_TEMPLATES_DIR)/lib/prism/reflection.rb.erb
$(Q) $(BASERUBY) $(PRISM_TEMPLATE) lib/prism/reflection.rb $@
realclean-prism-srcs::
$(RM) $(srcdir)/lib/prism/reflection.rb
-main srcs: $(srcdir)/lib/prism/serialize.rb
+prism-srcs: $(srcdir)/lib/prism/serialize.rb
$(srcdir)/lib/prism/serialize.rb: $(PRISM_CONFIG) $(PRISM_TEMPLATE) $(PRISM_TEMPLATES_DIR)/lib/prism/serialize.rb.erb
$(Q) $(BASERUBY) $(PRISM_TEMPLATE) lib/prism/serialize.rb $@
realclean-prism-srcs::
$(RM) $(srcdir)/lib/prism/serialize.rb
-main srcs: $(srcdir)/lib/prism/visitor.rb
+prism-srcs: $(srcdir)/lib/prism/visitor.rb
$(srcdir)/lib/prism/visitor.rb: $(PRISM_CONFIG) $(PRISM_TEMPLATE) $(PRISM_TEMPLATES_DIR)/lib/prism/visitor.rb.erb
$(Q) $(BASERUBY) $(PRISM_TEMPLATE) lib/prism/visitor.rb $@
realclean-prism-srcs::
$(RM) $(srcdir)/lib/prism/visitor.rb
-main srcs: $(srcdir)/prism/diagnostic.c
+prism-srcs: $(srcdir)/prism/diagnostic.c
$(srcdir)/prism/diagnostic.c: $(PRISM_CONFIG) $(PRISM_TEMPLATE) $(PRISM_TEMPLATES_DIR)/src/diagnostic.c.erb
$(Q) $(BASERUBY) $(PRISM_TEMPLATE) src/diagnostic.c $@
realclean-prism-srcs::
$(RM) $(srcdir)/prism/diagnostic.c
-main srcs: $(srcdir)/prism/node.c
+prism-srcs: $(srcdir)/prism/json.c
+$(srcdir)/prism/json.c: $(PRISM_CONFIG) $(PRISM_TEMPLATE) $(PRISM_TEMPLATES_DIR)/src/json.c.erb
+ $(Q) $(BASERUBY) $(PRISM_TEMPLATE) src/json.c $@
+
+realclean-prism-srcs::
+ $(RM) $(srcdir)/prism/json.c
+
+prism-srcs: $(srcdir)/prism/node.c
$(srcdir)/prism/node.c: $(PRISM_CONFIG) $(PRISM_TEMPLATE) $(PRISM_TEMPLATES_DIR)/src/node.c.erb
$(Q) $(BASERUBY) $(PRISM_TEMPLATE) src/node.c $@
realclean-prism-srcs::
$(RM) $(srcdir)/prism/node.c
-main srcs: $(srcdir)/prism/prettyprint.c
+prism-srcs: $(srcdir)/prism/prettyprint.c
$(srcdir)/prism/prettyprint.c: $(PRISM_CONFIG) $(PRISM_TEMPLATE) $(PRISM_TEMPLATES_DIR)/src/prettyprint.c.erb
$(Q) $(BASERUBY) $(PRISM_TEMPLATE) src/prettyprint.c $@
realclean-prism-srcs::
$(RM) $(srcdir)/prism/prettyprint.c
-main srcs: $(srcdir)/prism/serialize.c
+prism-srcs: $(srcdir)/prism/serialize.c
$(srcdir)/prism/serialize.c: $(PRISM_CONFIG) $(PRISM_TEMPLATE) $(PRISM_TEMPLATES_DIR)/src/serialize.c.erb
$(Q) $(BASERUBY) $(PRISM_TEMPLATE) src/serialize.c $@
realclean-prism-srcs::
$(RM) $(srcdir)/prism/serialize.c
-main srcs: $(srcdir)/prism/token_type.c
-$(srcdir)/prism/token_type.c: $(PRISM_CONFIG) $(PRISM_TEMPLATE) $(PRISM_TEMPLATES_DIR)/src/token_type.c.erb
- $(Q) $(BASERUBY) $(PRISM_TEMPLATE) src/token_type.c $@
+prism-srcs: $(srcdir)/prism/tokens.c
+$(srcdir)/prism/tokens.c: $(PRISM_CONFIG) $(PRISM_TEMPLATE) $(PRISM_TEMPLATES_DIR)/src/tokens.c.erb
+ $(Q) $(BASERUBY) $(PRISM_TEMPLATE) src/tokens.c $@
realclean-prism-srcs::
- $(RM) $(srcdir)/prism/token_type.c
+ $(RM) $(srcdir)/prism/tokens.c
diff --git a/prism/srcs.mk.in b/prism/srcs.mk.in
index 655de155d5..6149e4ae9d 100644
--- a/prism/srcs.mk.in
+++ b/prism/srcs.mk.in
@@ -1,4 +1,5 @@
<% # -*- ruby -*-
+# :stopdoc:
require_relative 'templates/template'
script = File.basename(__FILE__)
@@ -12,16 +13,27 @@ PRISM_CONFIG = $(PRISM_SRCDIR)/config.yml
srcs <%=%><%=mk%>: prism/.srcs.mk.time
-prism/.srcs.mk.time:
+prism/.srcs.mk.time: $(order_only) $(PRISM_BUILD_DIR)/.time
+prism/$(HAVE_BASERUBY:no=.srcs.mk.time):
+ touch $@
prism/$(HAVE_BASERUBY:yes=.srcs.mk.time): \
$(PRISM_SRCDIR)/templates/template.rb \
$(PRISM_SRCDIR)/<%=%><%=script%>
$(BASERUBY) $(tooldir)/generic_erb.rb -c -t$@ -o $(PRISM_SRCDIR)/<%=%><%=srcs%> $(PRISM_SRCDIR)/<%=%><%=script%>
-realclean-prism-srcs::
+distclean-prism-srcs::
+ $(RM) prism/.srcs.mk.time
+ $(RMDIRS) prism || $(NULLCMD)
+
+distclean-srcs-local:: distclean-prism-srcs
+
+realclean-prism-srcs:: distclean-prism-srcs
$(RM) $(PRISM_SRCDIR)/<%=%><%=srcs%>
realclean-srcs-local:: realclean-prism-srcs
+
+main srcs: prism-srcs
+main incs: prism-incs
<% Prism::Template::TEMPLATES.map do |t|
/\.(?:[ch]|rb)\z/ =~ t or next
s = '$(srcdir)/' + t.sub(%r[\A(?:(src)|ext|include)/]) {$1 && 'prism/'}
@@ -29,7 +41,7 @@ realclean-srcs-local:: realclean-prism-srcs
target = s.end_with?('.h') ? 'incs' : 'srcs'
# %>
-main <%=%><%=target%>: <%=%><%=s%>
+prism-<%=%><%=target%>: <%=%><%=s%>
<%=%><%=s%>: $(PRISM_CONFIG) $(PRISM_TEMPLATE) $(PRISM_TEMPLATES_DIR)/<%=%><%=t%>.erb
$(Q) $(BASERUBY) $(PRISM_TEMPLATE) <%=%><%=t%> $@
diff --git a/prism/static_literals.c b/prism/static_literals.c
index 9fa37b999a..9af1eadf5d 100644
--- a/prism/static_literals.c
+++ b/prism/static_literals.c
@@ -1,4 +1,18 @@
-#include "prism/static_literals.h"
+#include "prism/internal/static_literals.h"
+
+#include "prism/compiler/inline.h"
+#include "prism/compiler/unused.h"
+
+#include "prism/internal/allocator.h"
+#include "prism/internal/buffer.h"
+#include "prism/internal/integer.h"
+#include "prism/internal/isinf.h"
+#include "prism/internal/stringy.h"
+
+#include <assert.h>
+#include <math.h>
+#include <stdlib.h>
+#include <string.h>
/**
* A small struct used for passing around a subset of the information that is
@@ -7,7 +21,10 @@
*/
typedef struct {
/** The list of newline offsets to use to calculate line numbers. */
- const pm_newline_list_t *newline_list;
+ const pm_line_offset_list_t *line_offsets;
+
+ /** The start of the source being parsed. */
+ const uint8_t *start;
/** The line number that the parser starts on. */
int32_t start_line;
@@ -16,7 +33,7 @@ typedef struct {
const char *encoding_name;
} pm_static_literals_metadata_t;
-static inline uint32_t
+static PRISM_INLINE uint32_t
murmur_scramble(uint32_t value) {
value *= 0xcc9e2d51;
value = (value << 15) | (value >> 17);
@@ -92,7 +109,7 @@ node_hash(const pm_static_literals_metadata_t *metadata, const pm_node_t *node)
}
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 pm_line_column_t line_column = pm_line_offset_list_line_column(metadata->line_offsets, node->location.start, metadata->start_line);
const int32_t *value = &line_column.line;
return murmur_hash((const uint8_t *) value, sizeof(int32_t));
}
@@ -180,7 +197,7 @@ pm_node_hash_insert(pm_node_hash_t *hash, const pm_static_literals_metadata_t *m
}
// Finally, free the old node list and update the hash.
- xfree(hash->nodes);
+ xfree_sized(hash->nodes, hash->capacity * sizeof(pm_node_t *));
hash->nodes = new_nodes;
hash->capacity = new_capacity;
}
@@ -218,7 +235,7 @@ pm_node_hash_insert(pm_node_hash_t *hash, const pm_static_literals_metadata_t *m
*/
static void
pm_node_hash_free(pm_node_hash_t *hash) {
- if (hash->capacity > 0) xfree(hash->nodes);
+ if (hash->capacity > 0) xfree_sized(hash->nodes, hash->capacity * sizeof(pm_node_t *));
}
/**
@@ -240,7 +257,7 @@ pm_int64_value(const pm_static_literals_metadata_t *metadata, const pm_node_t *n
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;
+ return (int64_t) pm_line_offset_list_line_column(metadata->line_offsets, node->location.start, metadata->start_line).line;
default:
assert(false && "unreachable");
return 0;
@@ -268,7 +285,7 @@ pm_compare_integer_nodes(const pm_static_literals_metadata_t *metadata, const pm
* 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) {
+pm_compare_float_nodes(PRISM_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);
@@ -327,7 +344,7 @@ pm_string_value(const pm_node_t *node) {
* 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) {
+pm_compare_string_nodes(PRISM_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);
@@ -337,7 +354,7 @@ pm_compare_string_nodes(PRISM_ATTRIBUTE_UNUSED const pm_static_literals_metadata
* 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) {
+pm_compare_regular_expression_nodes(PRISM_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;
@@ -353,14 +370,15 @@ pm_compare_regular_expression_nodes(PRISM_ATTRIBUTE_UNUSED const pm_static_liter
* 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) {
+pm_static_literals_add(const pm_line_offset_list_t *line_offsets, const uint8_t *start, 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,
+ .line_offsets = line_offsets,
+ .start = start,
.start_line = start_line,
.encoding_name = NULL
},
@@ -372,7 +390,8 @@ pm_static_literals_add(const pm_newline_list_t *newline_list, int32_t start_line
return pm_node_hash_insert(
&literals->float_nodes,
&(pm_static_literals_metadata_t) {
- .newline_list = newline_list,
+ .line_offsets = line_offsets,
+ .start = start,
.start_line = start_line,
.encoding_name = NULL
},
@@ -385,7 +404,8 @@ pm_static_literals_add(const pm_newline_list_t *newline_list, int32_t start_line
return pm_node_hash_insert(
&literals->number_nodes,
&(pm_static_literals_metadata_t) {
- .newline_list = newline_list,
+ .line_offsets = line_offsets,
+ .start = start,
.start_line = start_line,
.encoding_name = NULL
},
@@ -398,7 +418,8 @@ pm_static_literals_add(const pm_newline_list_t *newline_list, int32_t start_line
return pm_node_hash_insert(
&literals->string_nodes,
&(pm_static_literals_metadata_t) {
- .newline_list = newline_list,
+ .line_offsets = line_offsets,
+ .start = start,
.start_line = start_line,
.encoding_name = NULL
},
@@ -410,7 +431,8 @@ pm_static_literals_add(const pm_newline_list_t *newline_list, int32_t start_line
return pm_node_hash_insert(
&literals->regexp_nodes,
&(pm_static_literals_metadata_t) {
- .newline_list = newline_list,
+ .line_offsets = line_offsets,
+ .start = start,
.start_line = start_line,
.encoding_name = NULL
},
@@ -422,7 +444,8 @@ pm_static_literals_add(const pm_newline_list_t *newline_list, int32_t start_line
return pm_node_hash_insert(
&literals->symbol_nodes,
&(pm_static_literals_metadata_t) {
- .newline_list = newline_list,
+ .line_offsets = line_offsets,
+ .start = start,
.start_line = start_line,
.encoding_name = NULL
},
@@ -492,7 +515,7 @@ pm_static_literal_positive_p(const pm_node_t *node) {
/**
* Create a string-based representation of the given static literal.
*/
-static inline void
+static PRISM_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:
@@ -502,12 +525,12 @@ pm_static_literal_inspect_node(pm_buffer_t *buffer, const pm_static_literals_met
const double value = ((const pm_float_node_t *) node)->value;
if (PRISM_ISINF(value)) {
- if (*node->location.start == '-') {
+ if (metadata->start[node->location.start] == '-') {
pm_buffer_append_byte(buffer, '-');
}
pm_buffer_append_string(buffer, "Infinity", 8);
} else if (value == 0.0) {
- if (*node->location.start == '-') {
+ if (metadata->start[node->location.start] == '-') {
pm_buffer_append_byte(buffer, '-');
}
pm_buffer_append_string(buffer, "0.0", 3);
@@ -576,7 +599,7 @@ pm_static_literal_inspect_node(pm_buffer_t *buffer, const pm_static_literals_met
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);
+ pm_buffer_append_format(buffer, "%d", pm_line_offset_list_line_column(metadata->line_offsets, node->location.start, metadata->start_line).line);
break;
case PM_STRING_NODE: {
const pm_string_t *unescaped = &((const pm_string_node_t *) node)->unescaped;
@@ -604,11 +627,12 @@ pm_static_literal_inspect_node(pm_buffer_t *buffer, const pm_static_literals_met
* 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(pm_buffer_t *buffer, const pm_line_offset_list_t *line_offsets, const uint8_t *start, 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,
+ .line_offsets = line_offsets,
+ .start = start,
.start_line = start_line,
.encoding_name = encoding_name
},
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/stream.h b/prism/stream.h
new file mode 100644
index 0000000000..678322b442
--- /dev/null
+++ b/prism/stream.h
@@ -0,0 +1,28 @@
+/**
+ * @file stream.h
+ *
+ * Functions for parsing streams.
+ */
+#ifndef PRISM_STREAM_H
+#define PRISM_STREAM_H
+
+#include "prism/compiler/exported.h"
+#include "prism/compiler/nonnull.h"
+
+#include "prism/arena.h"
+#include "prism/options.h"
+#include "prism/parser.h"
+#include "prism/source.h"
+
+/**
+ * Parse a stream of Ruby source and return the tree.
+ *
+ * @param parser The out parameter to write the parser to.
+ * @param arena The arena to use for all AST-lifetime allocations.
+ * @param source The source to use, created via pm_source_stream_new.
+ * @param options The optional options to use when parsing.
+ * @returns The AST representing the source.
+ */
+PRISM_EXPORTED_FUNCTION pm_node_t * pm_parse_stream(pm_parser_t **parser, pm_arena_t *arena, pm_source_t *source, const pm_options_t *options) PRISM_NONNULL(1, 2, 3);
+
+#endif
diff --git a/prism/string_query.c b/prism/string_query.c
new file mode 100644
index 0000000000..ccedaf9c00
--- /dev/null
+++ b/prism/string_query.c
@@ -0,0 +1,166 @@
+#include "prism/string_query.h"
+
+#include "prism/internal/char.h"
+#include "prism/internal/encoding.h"
+
+#include <assert.h>
+#include <string.h>
+
+/** The category of slice returned from pm_slice_type. */
+typedef enum {
+ /** Returned when the given encoding name is invalid. */
+ PM_SLICE_TYPE_ERROR = -1,
+
+ /** Returned when no other types apply to the slice. */
+ PM_SLICE_TYPE_NONE,
+
+ /** Returned when the slice is a valid local variable name. */
+ PM_SLICE_TYPE_LOCAL,
+
+ /** Returned when the slice is a valid constant name. */
+ PM_SLICE_TYPE_CONSTANT,
+
+ /** Returned when the slice is a valid method name. */
+ PM_SLICE_TYPE_METHOD_NAME
+} pm_slice_type_t;
+
+/**
+ * Check that the slice is a valid local variable name or constant.
+ */
+static pm_slice_type_t
+pm_slice_type(const uint8_t *source, size_t length, const char *encoding_name) {
+ // first, get the right encoding object
+ const pm_encoding_t *encoding = pm_encoding_find((const uint8_t *) encoding_name, (const uint8_t *) (encoding_name + strlen(encoding_name)));
+ if (encoding == NULL) return PM_SLICE_TYPE_ERROR;
+
+ // check that there is at least one character
+ if (length == 0) return PM_SLICE_TYPE_NONE;
+
+ size_t width;
+ if ((width = encoding->alpha_char(source, (ptrdiff_t) length)) != 0) {
+ // valid because alphabetical
+ } else if (*source == '_') {
+ // valid because underscore
+ width = 1;
+ } else if ((*source >= 0x80) && ((width = encoding->char_width(source, (ptrdiff_t) length)) > 0)) {
+ // valid because multibyte
+ } else {
+ // invalid because no match
+ return PM_SLICE_TYPE_NONE;
+ }
+
+ // determine the type of the slice based on the first character
+ const uint8_t *end = source + length;
+ pm_slice_type_t result = encoding->isupper_char(source, end - source) ? PM_SLICE_TYPE_CONSTANT : PM_SLICE_TYPE_LOCAL;
+
+ // next, iterate through all of the bytes of the string to ensure that they
+ // are all valid identifier characters
+ source += width;
+
+ while (source < end) {
+ if ((width = encoding->alnum_char(source, end - source)) != 0) {
+ // valid because alphanumeric
+ source += width;
+ } else if (*source == '_') {
+ // valid because underscore
+ source++;
+ } else if ((*source >= 0x80) && ((width = encoding->char_width(source, end - source)) > 0)) {
+ // valid because multibyte
+ source += width;
+ } else {
+ // invalid because no match
+ break;
+ }
+ }
+
+ // accept a ! or ? at the end of the slice as a method name
+ if (*source == '!' || *source == '?' || *source == '=') {
+ source++;
+ result = PM_SLICE_TYPE_METHOD_NAME;
+ }
+
+ // valid if we are at the end of the slice
+ return source == end ? result : PM_SLICE_TYPE_NONE;
+}
+
+/**
+ * Check that the slice is a valid local variable name.
+ */
+pm_string_query_t
+pm_string_query_local(const uint8_t *source, size_t length, const char *encoding_name) {
+ switch (pm_slice_type(source, length, encoding_name)) {
+ case PM_SLICE_TYPE_ERROR:
+ return PM_STRING_QUERY_ERROR;
+ case PM_SLICE_TYPE_NONE:
+ case PM_SLICE_TYPE_CONSTANT:
+ case PM_SLICE_TYPE_METHOD_NAME:
+ return PM_STRING_QUERY_FALSE;
+ case PM_SLICE_TYPE_LOCAL:
+ return PM_STRING_QUERY_TRUE;
+ }
+
+ assert(false && "unreachable");
+ return PM_STRING_QUERY_FALSE;
+}
+
+/**
+ * Check that the slice is a valid constant name.
+ */
+pm_string_query_t
+pm_string_query_constant(const uint8_t *source, size_t length, const char *encoding_name) {
+ switch (pm_slice_type(source, length, encoding_name)) {
+ case PM_SLICE_TYPE_ERROR:
+ return PM_STRING_QUERY_ERROR;
+ case PM_SLICE_TYPE_NONE:
+ case PM_SLICE_TYPE_LOCAL:
+ case PM_SLICE_TYPE_METHOD_NAME:
+ return PM_STRING_QUERY_FALSE;
+ case PM_SLICE_TYPE_CONSTANT:
+ return PM_STRING_QUERY_TRUE;
+ }
+
+ assert(false && "unreachable");
+ return PM_STRING_QUERY_FALSE;
+}
+
+/**
+ * Check that the slice is a valid method name.
+ */
+pm_string_query_t
+pm_string_query_method_name(const uint8_t *source, size_t length, const char *encoding_name) {
+#define B(p) ((p) ? PM_STRING_QUERY_TRUE : PM_STRING_QUERY_FALSE)
+#define C1(c) (*source == c)
+#define C2(s) (memcmp(source, s, 2) == 0)
+#define C3(s) (memcmp(source, s, 3) == 0)
+
+ switch (pm_slice_type(source, length, encoding_name)) {
+ case PM_SLICE_TYPE_ERROR:
+ return PM_STRING_QUERY_ERROR;
+ case PM_SLICE_TYPE_NONE:
+ break;
+ case PM_SLICE_TYPE_LOCAL:
+ // numbered parameters are not valid method names
+ return B((length != 2) || (source[0] != '_') || (source[1] == '0') || !pm_char_is_decimal_digit(source[1]));
+ case PM_SLICE_TYPE_CONSTANT:
+ // all constants are valid method names
+ case PM_SLICE_TYPE_METHOD_NAME:
+ // all method names are valid method names
+ return PM_STRING_QUERY_TRUE;
+ }
+
+ switch (length) {
+ case 1:
+ return B(C1('&') || C1('`') || C1('!') || C1('^') || C1('>') || C1('<') || C1('-') || C1('%') || C1('|') || C1('+') || C1('/') || C1('*') || C1('~'));
+ case 2:
+ return B(C2("!=") || C2("!~") || C2("[]") || C2("==") || C2("=~") || C2(">=") || C2(">>") || C2("<=") || C2("<<") || C2("**"));
+ case 3:
+ return B(C3("===") || C3("<=>") || C3("[]="));
+ default:
+ return PM_STRING_QUERY_FALSE;
+ }
+
+#undef B
+#undef C1
+#undef C2
+#undef C3
+}
diff --git a/prism/string_query.h b/prism/string_query.h
new file mode 100644
index 0000000000..6ee1a9d9b6
--- /dev/null
+++ b/prism/string_query.h
@@ -0,0 +1,63 @@
+/**
+ * @file string_query.h
+ *
+ * Functions for querying properties of strings, such as whether they are valid
+ * local variable names, constant names, or method names.
+ */
+#ifndef PRISM_STRING_QUERY_H
+#define PRISM_STRING_QUERY_H
+
+#include "prism/compiler/exported.h"
+#include "prism/compiler/nonnull.h"
+
+#include <stddef.h>
+#include <stdint.h>
+
+/**
+ * Represents the results of a slice query.
+ */
+typedef enum {
+ /** Returned if the encoding given to a slice query was invalid. */
+ PM_STRING_QUERY_ERROR = -1,
+
+ /** Returned if the result of the slice query is false. */
+ PM_STRING_QUERY_FALSE,
+
+ /** Returned if the result of the slice query is true. */
+ PM_STRING_QUERY_TRUE
+} pm_string_query_t;
+
+/**
+ * Check that the slice is a valid local variable name.
+ *
+ * @param source The source to check.
+ * @param length The length of the source.
+ * @param encoding_name The name of the encoding of the source.
+ * @returns PM_STRING_QUERY_TRUE if the query is true, PM_STRING_QUERY_FALSE if
+ * the query is false, and PM_STRING_QUERY_ERROR if the encoding was invalid.
+ */
+PRISM_EXPORTED_FUNCTION pm_string_query_t pm_string_query_local(const uint8_t *source, size_t length, const char *encoding_name) PRISM_NONNULL(1, 3);
+
+/**
+ * Check that the slice is a valid constant name.
+ *
+ * @param source The source to check.
+ * @param length The length of the source.
+ * @param encoding_name The name of the encoding of the source.
+ * @returns PM_STRING_QUERY_TRUE if the query is true, PM_STRING_QUERY_FALSE if
+ * the query is false, and PM_STRING_QUERY_ERROR if the encoding was invalid.
+ */
+PRISM_EXPORTED_FUNCTION pm_string_query_t pm_string_query_constant(const uint8_t *source, size_t length, const char *encoding_name) PRISM_NONNULL(1, 3);
+
+/**
+ * Check that the slice is a valid method name.
+ *
+ * @param source The source to check.
+ * @param length The length of the source.
+ * @param encoding_name The name of the encoding of the source.
+ * @returns PM_STRING_QUERY_TRUE if the query is true, PM_STRING_QUERY_FALSE if
+ * the query is false, and PM_STRING_QUERY_ERROR if the encoding was invalid.
+ */
+PRISM_EXPORTED_FUNCTION pm_string_query_t pm_string_query_method_name(const uint8_t *source, size_t length, const char *encoding_name) PRISM_NONNULL(1, 3);
+
+#endif
diff --git a/prism/stringy.c b/prism/stringy.c
new file mode 100644
index 0000000000..d6f4c4a777
--- /dev/null
+++ b/prism/stringy.c
@@ -0,0 +1,91 @@
+#include "prism/internal/stringy.h"
+
+#include "prism/internal/allocator.h"
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+/**
+ * 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
+ };
+}
+
+/**
+ * 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.
+ */
+size_t
+pm_string_length(const pm_string_t *string) {
+ return string->length;
+}
+
+/**
+ * Returns the start pointer associated with the string.
+ */
+const uint8_t *
+pm_string_source(const pm_string_t *string) {
+ return string->source;
+}
+
+/**
+ * Free the associated memory of the given string.
+ */
+void
+pm_string_cleanup(pm_string_t *string) {
+ if (string->type == PM_STRING_OWNED) {
+ xfree_sized((void *) string->source, string->length);
+ }
+}
diff --git a/prism/stringy.h b/prism/stringy.h
new file mode 100644
index 0000000000..0d64387ac3
--- /dev/null
+++ b/prism/stringy.h
@@ -0,0 +1,72 @@
+/**
+ * @file stringy.h
+ *
+ * A generic string type that can have various ownership semantics.
+ */
+#ifndef PRISM_STRINGY_H
+#define PRISM_STRINGY_H
+
+#include "prism/compiler/exported.h"
+#include "prism/compiler/nonnull.h"
+
+#include <stddef.h>
+#include <stdint.h>
+
+/**
+ * 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 internally. */
+ PM_STRING_OWNED
+ } type;
+} pm_string_t;
+
+/**
+ * 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.
+ */
+PRISM_EXPORTED_FUNCTION void pm_string_constant_init(pm_string_t *string, const char *source, size_t length) PRISM_NONNULL(1);
+
+/**
+ * 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.
+ */
+PRISM_EXPORTED_FUNCTION void pm_string_owned_init(pm_string_t *string, uint8_t *source, size_t length) PRISM_NONNULL(1, 2);
+
+/**
+ * Returns the length associated with the string.
+ *
+ * @param string The string to get the length of.
+ * @returns The length of the string.
+ */
+PRISM_EXPORTED_FUNCTION size_t pm_string_length(const pm_string_t *string) PRISM_NONNULL(1);
+
+/**
+ * Returns the start pointer associated with the string.
+ *
+ * @param string The string to get the start pointer of.
+ * @returns The start pointer of the string.
+ */
+PRISM_EXPORTED_FUNCTION const uint8_t * pm_string_source(const pm_string_t *string) PRISM_NONNULL(1);
+
+#endif
diff --git a/prism/strncasecmp.c b/prism/strncasecmp.c
new file mode 100644
index 0000000000..a373cad6d7
--- /dev/null
+++ b/prism/strncasecmp.c
@@ -0,0 +1,37 @@
+#include "prism/internal/strncasecmp.h"
+
+#include "prism/compiler/inline.h"
+
+/**
+ * A locale-insensitive version of `tolower(3)`
+ */
+static PRISM_INLINE int
+pm_tolower(int c) {
+ if ('A' <= c && c <= 'Z') {
+ return c | 0x20;
+ }
+ return c;
+}
+
+/**
+ * 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 = pm_tolower(string1[offset]) - pm_tolower(string2[offset])) != 0) return difference;
+ offset++;
+ }
+
+ return difference;
+}
diff --git a/prism/strpbrk.c b/prism/strpbrk.c
new file mode 100644
index 0000000000..383707eb72
--- /dev/null
+++ b/prism/strpbrk.c
@@ -0,0 +1,439 @@
+#include "prism/internal/strpbrk.h"
+
+#include "prism/compiler/accel.h"
+#include "prism/compiler/inline.h"
+#include "prism/compiler/unused.h"
+
+#include "prism/internal/bit.h"
+#include "prism/internal/diagnostic.h"
+#include "prism/internal/encoding.h"
+#include "prism/internal/parser.h"
+
+#include <assert.h>
+#include <stdbool.h>
+#include <string.h>
+
+/**
+ * Add an invalid multibyte character error to the parser.
+ */
+static PRISM_INLINE void
+pm_strpbrk_invalid_multibyte_character(pm_parser_t *parser, uint32_t start, uint32_t length) {
+ pm_diagnostic_list_append_format(&parser->metadata_arena, &parser->error_list, start, length, PM_ERR_INVALID_MULTIBYTE_CHARACTER, parser->start[start]);
+}
+
+/**
+ * Set the explicit encoding for the parser to the current encoding.
+ */
+static PRISM_INLINE void
+pm_strpbrk_explicit_encoding_set(pm_parser_t *parser, uint32_t start, uint32_t length) {
+ 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->metadata_arena, &parser->error_list, start, length, PM_ERR_MIXED_ENCODING, parser->encoding->name);
+ } else {
+ // Should not be anything else.
+ assert(false && "unreachable");
+ }
+ }
+
+ parser->explicit_encoding = parser->encoding;
+}
+
+/**
+ * Scan forward through ASCII bytes looking for a byte that is in the given
+ * charset. Returns true if a match was found, storing its offset in *index.
+ * Returns false if no match was found, storing the number of ASCII bytes
+ * consumed in *index (so the caller can skip past them).
+ *
+ * All charset characters must be ASCII (< 0x80). The scanner stops at non-ASCII
+ * bytes, returning control to the caller's encoding-aware loop.
+ *
+ * Up to three optimized implementations are selected at compile time, with a
+ * no-op fallback for unsupported platforms:
+ * 1. NEON — processes 16 bytes per iteration on aarch64.
+ * 2. SSSE3 — processes 16 bytes per iteration on x86-64.
+ * 3. SWAR — little-endian fallback, processes 8 bytes per iteration.
+ */
+
+#if defined(PRISM_HAS_NEON) || defined(PRISM_HAS_SSSE3) || defined(PRISM_HAS_SWAR)
+
+/**
+ * Update the cached strpbrk lookup tables if the charset has changed. The
+ * parser caches the last charset's precomputed tables so that repeated calls
+ * with the same breakpoints (the common case during string/regex/list lexing)
+ * skip table construction entirely.
+ *
+ * Builds three structures:
+ * - low_lut/high_lut: nibble-based lookup tables for SIMD matching (NEON/SSSE3)
+ * - table: 256-bit bitmap for scalar fallback matching (all platforms)
+ */
+static PRISM_INLINE void
+pm_strpbrk_cache_update(pm_parser_t *parser, const uint8_t *charset) {
+ // The cache key is the full charset buffer (PM_STRPBRK_CACHE_SIZE bytes).
+ // Since it is always NUL-padded, a fixed-size comparison covers both
+ // content and length.
+ if (memcmp(parser->strpbrk_cache.charset, charset, sizeof(parser->strpbrk_cache.charset)) == 0) return;
+
+ memset(parser->strpbrk_cache.low_lut, 0, sizeof(parser->strpbrk_cache.low_lut));
+ memset(parser->strpbrk_cache.high_lut, 0, sizeof(parser->strpbrk_cache.high_lut));
+ memset(parser->strpbrk_cache.table, 0, sizeof(parser->strpbrk_cache.table));
+
+ // Always include NUL in the tables. The slow path uses strchr, which
+ // always matches NUL (it finds the C string terminator), so NUL is
+ // effectively always a breakpoint. Replicating that here lets the fast
+ // scanner handle NUL at full speed instead of bailing to the slow path.
+ parser->strpbrk_cache.low_lut[0x00] |= (uint8_t) (1 << 0);
+ parser->strpbrk_cache.high_lut[0x00] = (uint8_t) (1 << 0);
+ parser->strpbrk_cache.table[0] |= (uint64_t) 1;
+
+ size_t charset_len = 0;
+ for (const uint8_t *c = charset; *c != '\0'; c++) {
+ parser->strpbrk_cache.low_lut[*c & 0x0F] |= (uint8_t) (1 << (*c >> 4));
+ parser->strpbrk_cache.high_lut[*c >> 4] = (uint8_t) (1 << (*c >> 4));
+ parser->strpbrk_cache.table[*c >> 6] |= (uint64_t) 1 << (*c & 0x3F);
+ charset_len++;
+ }
+
+ // Store the new charset key, NUL-padded to the full buffer size.
+ memcpy(parser->strpbrk_cache.charset, charset, charset_len + 1);
+ memset(parser->strpbrk_cache.charset + charset_len + 1, 0, sizeof(parser->strpbrk_cache.charset) - charset_len - 1);
+}
+
+#endif
+
+#if defined(PRISM_HAS_NEON)
+#include <arm_neon.h>
+
+static PRISM_INLINE bool
+scan_strpbrk_ascii(pm_parser_t *parser, const uint8_t *source, size_t maximum, const uint8_t *charset, size_t *index) {
+ pm_strpbrk_cache_update(parser, charset);
+
+ uint8x16_t low_lut = vld1q_u8(parser->strpbrk_cache.low_lut);
+ uint8x16_t high_lut = vld1q_u8(parser->strpbrk_cache.high_lut);
+ uint8x16_t mask_0f = vdupq_n_u8(0x0F);
+ uint8x16_t mask_80 = vdupq_n_u8(0x80);
+
+ size_t idx = 0;
+
+ while (idx + 16 <= maximum) {
+ uint8x16_t v = vld1q_u8(source + idx);
+
+ // If any byte has the high bit set, we have non-ASCII data.
+ // Return to let the caller's encoding-aware loop handle it.
+ if (vmaxvq_u8(vandq_u8(v, mask_80)) != 0) break;
+
+ uint8x16_t lo_class = vqtbl1q_u8(low_lut, vandq_u8(v, mask_0f));
+ uint8x16_t hi_class = vqtbl1q_u8(high_lut, vshrq_n_u8(v, 4));
+ uint8x16_t matched = vtstq_u8(lo_class, hi_class);
+
+ if (vmaxvq_u8(matched) == 0) {
+ idx += 16;
+ continue;
+ }
+
+ // Find the position of the first matching byte.
+ uint64_t lo64 = vgetq_lane_u64(vreinterpretq_u64_u8(matched), 0);
+ if (lo64 != 0) {
+ *index = idx + pm_ctzll(lo64) / 8;
+ return true;
+ }
+ uint64_t hi64 = vgetq_lane_u64(vreinterpretq_u64_u8(matched), 1);
+ *index = idx + 8 + pm_ctzll(hi64) / 8;
+ return true;
+ }
+
+ // Scalar tail for remaining < 16 ASCII bytes.
+ while (idx < maximum && source[idx] < 0x80) {
+ uint8_t byte = source[idx];
+ if (parser->strpbrk_cache.table[byte >> 6] & ((uint64_t) 1 << (byte & 0x3F))) {
+ *index = idx;
+ return true;
+ }
+ idx++;
+ }
+
+ *index = idx;
+ return false;
+}
+
+#elif defined(PRISM_HAS_SSSE3)
+#include <tmmintrin.h>
+
+static PRISM_INLINE bool
+scan_strpbrk_ascii(pm_parser_t *parser, const uint8_t *source, size_t maximum, const uint8_t *charset, size_t *index) {
+ pm_strpbrk_cache_update(parser, charset);
+
+ __m128i low_lut = _mm_loadu_si128((const __m128i *) parser->strpbrk_cache.low_lut);
+ __m128i high_lut = _mm_loadu_si128((const __m128i *) parser->strpbrk_cache.high_lut);
+ __m128i mask_0f = _mm_set1_epi8(0x0F);
+
+ size_t idx = 0;
+
+ while (idx + 16 <= maximum) {
+ __m128i v = _mm_loadu_si128((const __m128i *) (source + idx));
+
+ // If any byte has the high bit set, stop.
+ if (_mm_movemask_epi8(v) != 0) break;
+
+ // Nibble-based classification using pshufb (SSSE3), same as NEON
+ // vqtbl1q_u8. A byte matches iff (low_lut[lo_nib] & high_lut[hi_nib]) != 0.
+ __m128i lo_class = _mm_shuffle_epi8(low_lut, _mm_and_si128(v, mask_0f));
+ __m128i hi_class = _mm_shuffle_epi8(high_lut, _mm_and_si128(_mm_srli_epi16(v, 4), mask_0f));
+ __m128i matched = _mm_and_si128(lo_class, hi_class);
+
+ // Check if any byte matched.
+ int mask = _mm_movemask_epi8(_mm_cmpeq_epi8(matched, _mm_setzero_si128()));
+
+ if (mask == 0xFFFF) {
+ // All bytes were zero — no match in this chunk.
+ idx += 16;
+ continue;
+ }
+
+ // Find the first matching byte (first non-zero in matched).
+ *index = idx + pm_ctzll((uint64_t) (~mask & 0xFFFF));
+ return true;
+ }
+
+ // Scalar tail.
+ while (idx < maximum && source[idx] < 0x80) {
+ uint8_t byte = source[idx];
+ if (parser->strpbrk_cache.table[byte >> 6] & ((uint64_t) 1 << (byte & 0x3F))) {
+ *index = idx;
+ return true;
+ }
+ idx++;
+ }
+
+ *index = idx;
+ return false;
+}
+
+#elif defined(PRISM_HAS_SWAR)
+
+static PRISM_INLINE bool
+scan_strpbrk_ascii(pm_parser_t *parser, const uint8_t *source, size_t maximum, const uint8_t *charset, size_t *index) {
+ pm_strpbrk_cache_update(parser, charset);
+
+ static const uint64_t highs = 0x8080808080808080ULL;
+ size_t idx = 0;
+
+ while (idx + 8 <= maximum) {
+ uint64_t word;
+ memcpy(&word, source + idx, 8);
+
+ // Bail on any non-ASCII byte.
+ if (word & highs) break;
+
+ // Check each byte against the charset table.
+ for (size_t j = 0; j < 8; j++) {
+ uint8_t byte = source[idx + j];
+ if (parser->strpbrk_cache.table[byte >> 6] & ((uint64_t) 1 << (byte & 0x3F))) {
+ *index = idx + j;
+ return true;
+ }
+ }
+
+ idx += 8;
+ }
+
+ // Scalar tail.
+ while (idx < maximum && source[idx] < 0x80) {
+ uint8_t byte = source[idx];
+ if (parser->strpbrk_cache.table[byte >> 6] & ((uint64_t) 1 << (byte & 0x3F))) {
+ *index = idx;
+ return true;
+ }
+ idx++;
+ }
+
+ *index = idx;
+ return false;
+}
+
+#else
+
+static PRISM_INLINE bool
+scan_strpbrk_ascii(PRISM_UNUSED pm_parser_t *parser, PRISM_UNUSED const uint8_t *source, PRISM_UNUSED size_t maximum, PRISM_UNUSED const uint8_t *charset, size_t *index) {
+ *index = 0;
+ return false;
+}
+
+#endif
+
+/**
+ * This is the default path.
+ */
+static PRISM_INLINE const uint8_t *
+pm_strpbrk_utf8(pm_parser_t *parser, const uint8_t *source, const uint8_t *charset, size_t index, size_t maximum, bool validate) {
+ 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, (uint32_t) ((source + start) - parser->start), (uint32_t) (index - start));
+ }
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ * This is the path when the encoding is ASCII-8BIT.
+ */
+static PRISM_INLINE const uint8_t *
+pm_strpbrk_ascii_8bit(pm_parser_t *parser, const uint8_t *source, const uint8_t *charset, size_t index, size_t maximum, bool validate) {
+ 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, (uint32_t) (source - parser->start), 1);
+ index++;
+ }
+
+ return NULL;
+}
+
+/**
+ * This is the slow path that does care about the encoding.
+ */
+static PRISM_INLINE const uint8_t *
+pm_strpbrk_multi_byte(pm_parser_t *parser, const uint8_t *source, const uint8_t *charset, size_t index, size_t maximum, bool validate) {
+ 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, (uint32_t) (source - parser->start), (uint32_t) 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, (uint32_t) ((source + start) - parser->start), (uint32_t) (index - start));
+ }
+ }
+ }
+
+ 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 PRISM_INLINE const uint8_t *
+pm_strpbrk_single_byte(pm_parser_t *parser, const uint8_t *source, const uint8_t *charset, size_t index, size_t maximum, bool validate) {
+ 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, (uint32_t) (source - parser->start), (uint32_t) 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, (uint32_t) ((source + start) - parser->start), (uint32_t) (index - start));
+ }
+ }
+ }
+
+ 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;
+
+ size_t maximum = (size_t) length;
+ size_t index = 0;
+ if (scan_strpbrk_ascii(parser, source, maximum, charset, &index)) return source + index;
+
+ if (!parser->encoding_changed) {
+ return pm_strpbrk_utf8(parser, source, charset, index, maximum, validate);
+ } else if (parser->encoding == PM_ENCODING_ASCII_8BIT_ENTRY) {
+ return pm_strpbrk_ascii_8bit(parser, source, charset, index, maximum, validate);
+ } else if (parser->encoding->multibyte) {
+ return pm_strpbrk_multi_byte(parser, source, charset, index, maximum, validate);
+ } else {
+ return pm_strpbrk_single_byte(parser, source, charset, index, maximum, validate);
+ }
+}
diff --git a/prism/templates/ext/prism/api_node.c.erb b/prism/templates/ext/prism/api_node.c.erb
index 23af8886a7..41d7165930 100644
--- a/prism/templates/ext/prism/api_node.c.erb
+++ b/prism/templates/ext/prism/api_node.c.erb
@@ -1,5 +1,9 @@
#line <%= __LINE__ + 1 %> "prism/templates/ext/prism/<%= File.basename(__FILE__) %>"
#include "prism/extension.h"
+#include "prism/internal/allocator.h"
+#include "prism/internal/arena.h"
+
+#include <assert.h>
extern VALUE rb_cPrism;
extern VALUE rb_cPrismNode;
@@ -12,25 +16,20 @@ 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, VALUE source, bool freeze) {
+pm_location_new(const uint32_t start, const uint32_t length, VALUE source, bool freeze) {
if (freeze) {
- VALUE location_argv[] = {
- source,
- LONG2FIX(start - parser->start),
- LONG2FIX(end - start)
- };
-
+ VALUE location_argv[] = { source, LONG2FIX(start), LONG2FIX(length) };
return rb_obj_freeze(rb_class_new_instance(3, location_argv, rb_cPrismLocation));
} else {
- uint64_t value = ((((uint64_t) (start - parser->start)) << 32) | ((uint32_t) (end - start)));
+ uint64_t value = ((((uint64_t) start) << 32) | ((uint64_t) length));
return ULL2NUM(value);
}
}
VALUE
pm_token_new(const pm_parser_t *parser, const pm_token_t *token, rb_encoding *encoding, VALUE source, bool freeze) {
- ID type = rb_intern(pm_token_type_name(token->type));
- VALUE location = pm_location_new(parser, token->start, token->end, source, freeze);
+ ID type = rb_intern(pm_token_type(token->type));
+ VALUE location = pm_location_new((uint32_t) (token->start - pm_parser_start(parser)), (uint32_t) (token->end - token->start), source, freeze);
VALUE slice = rb_enc_str_new((const char *) token->start, token->end - token->start, encoding);
if (freeze) rb_obj_freeze(slice);
@@ -79,19 +78,25 @@ pm_integer_new(const pm_integer_t *integer) {
// 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, bool freeze) {
- VALUE source_string = rb_enc_str_new((const char *) parser->start, parser->end - parser->start, encoding);
+ const uint8_t *start = pm_parser_start(parser);
+ VALUE source_string = rb_enc_str_new((const char *) start, pm_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]));
- }
+ const pm_line_offset_list_t *line_offsets = pm_parser_line_offsets(parser);
+ VALUE offsets;
if (freeze) {
+ offsets = rb_ary_new_capa(line_offsets->size);
+ for (size_t index = 0; index < line_offsets->size; index++) {
+ rb_ary_push(offsets, ULONG2NUM(line_offsets->offsets[index]));
+ }
+
rb_obj_freeze(source_string);
rb_obj_freeze(offsets);
+ } else {
+ offsets = rb_str_new((const char *) line_offsets->offsets, line_offsets->size * sizeof(uint32_t));
}
- VALUE source = rb_funcall(rb_cPrismSource, rb_intern("for"), 3, source_string, LONG2NUM(parser->start_line), offsets);
+ VALUE source = rb_funcall(rb_cPrismSource, rb_intern("for"), 3, source_string, LONG2NUM(pm_parser_start_line(parser)), offsets);
if (freeze) rb_obj_freeze(source);
return source;
@@ -104,8 +109,8 @@ typedef struct pm_node_stack_node {
} 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));
+pm_node_stack_push(pm_arena_t *arena, pm_node_stack_node_t **stack, const pm_node_t *visit) {
+ pm_node_stack_node_t *node = (pm_node_stack_node_t *) pm_arena_alloc(arena, sizeof(pm_node_stack_node_t), PRISM_ALIGNOF(pm_node_stack_node_t));
node->prev = *stack;
node->visit = visit;
node->visited = false;
@@ -118,32 +123,40 @@ pm_node_stack_pop(pm_node_stack_node_t **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, bool freeze) {
- 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;
+typedef struct {
+ VALUE constants;
+ rb_encoding *encoding;
+} pm_ast_constants_each_data_t;
- VALUE string = rb_enc_str_new((const char *) constant->start, constant->length, encoding);
- VALUE value = rb_protect(rb_str_intern, string, &state);
+static void
+pm_ast_constants_each(const pm_constant_t *constant, void *data) {
+ pm_ast_constants_each_data_t *constants_data = (pm_ast_constants_each_data_t *) data;
+ int state = 0;
- if (state != 0) {
- value = ID2SYM(rb_intern_const("?"));
- rb_set_errinfo(Qnil);
- }
+ VALUE string = rb_enc_str_new((const char *) pm_constant_start(constant), pm_constant_length(constant), constants_data->encoding);
+ VALUE value = rb_protect(rb_str_intern, string, &state);
- rb_ary_push(constants, value);
+ if (state != 0) {
+ value = ID2SYM(rb_intern_const("?"));
+ rb_set_errinfo(Qnil);
}
+ rb_ary_push(constants_data->constants, value);
+}
+
+VALUE
+pm_ast_new(const pm_parser_t *parser, const pm_node_t *node, rb_encoding *encoding, VALUE source, bool freeze) {
+ VALUE constants = rb_ary_new_capa(pm_parser_constants_size(parser));
+ pm_ast_constants_each_data_t constants_data = { .constants = constants, .encoding = encoding };
+ pm_parser_constants_each(parser, pm_ast_constants_each, &constants_data);
+
+ pm_arena_t *node_arena = pm_arena_new();
pm_node_stack_node_t *node_stack = NULL;
- pm_node_stack_push(&node_stack, node);
+ pm_node_stack_push(node_arena, &node_stack, node);
VALUE value_stack = rb_ary_new();
while (node_stack != NULL) {
@@ -166,10 +179,10 @@ pm_ast_new(const pm_parser_t *parser, const pm_node_t *node, rb_encoding *encodi
<%- 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 %>);
+ pm_node_stack_push(node_arena, &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]);
+ pm_node_stack_push(node_arena, &node_stack, (pm_node_t *) cast-><%= field.name %>.nodes[index]);
}
<%- end -%>
<%- end -%>
@@ -200,7 +213,7 @@ pm_ast_new(const pm_parser_t *parser, const pm_node_t *node, rb_encoding *encodi
argv[1] = ULONG2NUM(node->node_id);
// location
- argv[2] = pm_location_new(parser, node->location.start, node->location.end, source, freeze);
+ argv[2] = pm_location_new(node->location.start, node->location.length, source, freeze);
// flags
argv[3] = ULONG2NUM(node->flags);
@@ -237,10 +250,10 @@ pm_ast_new(const pm_parser_t *parser, const pm_node_t *node, rb_encoding *encodi
if (freeze) rb_obj_freeze(argv[<%= index %>]);
<%- 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, source, freeze);
+ argv[<%= index %>] = pm_location_new(cast-><%= field.name %>.start, cast-><%= field.name %>.length, source, freeze);
<%- 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, source, freeze);
+ argv[<%= index %>] = cast-><%= field.name %>.length == 0 ? Qnil : pm_location_new(cast-><%= field.name %>.start, cast-><%= field.name %>.length, source, freeze);
<%- when Prism::Template::UInt8Field -%>
#line <%= __LINE__ + 1 %> "prism/templates/ext/prism/<%= File.basename(__FILE__) %>"
argv[<%= index %>] = UINT2NUM(cast-><%= field.name %>);
@@ -271,6 +284,7 @@ pm_ast_new(const pm_parser_t *parser, const pm_node_t *node, rb_encoding *encodi
}
}
+ pm_arena_free(node_arena);
return rb_ary_pop(value_stack);
}
diff --git a/prism/templates/include/prism/ast.h.erb b/prism/templates/include/prism/ast.h.erb
index 087eb81890..3b3be25e76 100644
--- a/prism/templates/include/prism/ast.h.erb
+++ b/prism/templates/include/prism/ast.h.erb
@@ -8,12 +8,14 @@
#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 "prism/compiler/align.h"
+#include "prism/compiler/exported.h"
+
+#include "prism/arena.h"
+#include "prism/constant_pool.h"
+#include "prism/integer.h"
+#include "prism/stringy.h"
-#include <assert.h>
#include <stddef.h>
#include <stdint.h>
@@ -22,7 +24,7 @@
*/
typedef enum pm_token_type {
<%- tokens.each do |token| -%>
- /** <%= token.comment %> */
+ /** <%= Prism::Template::Doxygen.verbatim(token.comment) %> */
PM_TOKEN_<%= token.name %><%= " = #{token.value}" if token.value %>,
<%- end -%>
@@ -46,15 +48,28 @@ typedef struct {
} pm_token_t;
/**
- * This represents a range of bytes in the source string to which a node or
- * token corresponds.
+ * Returns a string representation of the given token type.
+ *
+ * @param token_type The type of the token to get the string representation of.
+ * @returns A string representation of the given token type. This is meant for
+ * debugging purposes and is not guaranteed to be stable across versions.
+ */
+PRISM_EXPORTED_FUNCTION const char * pm_token_type(pm_token_type_t token_type);
+
+/**
+ * This struct represents a slice in the source code, defined by an offset and
+ * a length. Note that we have confirmation that we can represent all locations
+ * within Ruby source files using 32-bit integers per:
+ *
+ * https://bugs.ruby-lang.org/issues/20488#note-1
+ *
*/
typedef struct {
- /** A pointer to the start location of the range in the source. */
- const uint8_t *start;
+ /** The offset of the location from the start of the source. */
+ uint32_t start;
- /** A pointer to the end location of the range in the source. */
- const uint8_t *end;
+ /** The length of the location. */
+ uint32_t length;
} pm_location_t;
struct pm_node;
@@ -106,29 +121,13 @@ 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.
+ * existed in the original grammar and ripper, but it is not a 1:1 mapping.
*/
pm_node_type_t type;
@@ -145,11 +144,46 @@ typedef struct pm_node {
uint32_t node_id;
/**
- * This is the location of the node in the source. It's a range of bytes
+ * This is the location of the node in the source. It is a range of bytes
* containing a start and an end.
*/
pm_location_t location;
} pm_node_t;
+
+/**
+ * Cast the given node to the base pm_node_t type.
+ */
+#define PM_NODE_UPCAST(node_) ((pm_node_t *) (node_))
+
+/**
+ * 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 the flags associated with the given node.
+ */
+#define PM_NODE_FLAGS(node_) (PM_NODE_UPCAST(node_)->flags)
+
+/**
+ * Return true if the given flag is set on the given node.
+ */
+#define PM_NODE_FLAG_P(node_, flag_) ((PM_NODE_FLAGS(node_) & (flag_)) != 0)
+
+/**
+ * The alignment required for a child node within a parent node.
+ */
+#ifdef _MSC_VER
+#define PM_NODE_ALIGNAS __declspec(align(8))
+#else
+#define PM_NODE_ALIGNAS PRISM_ALIGNAS(PRISM_ALIGNOF(void *))
+#endif
<%- nodes.each do |node| -%>
/**
@@ -172,7 +206,6 @@ typedef struct pm_node {
typedef struct pm_<%= node.human %> {
/** The embedded base node. */
pm_node_t base;
-
<%- node.fields.each do |field| -%>
/**
@@ -185,7 +218,7 @@ typedef struct pm_<%= node.human %> {
<%- end -%>
*/
<%= case field
- when Prism::Template::NodeField, Prism::Template::OptionalNodeField then "struct #{field.c_type} *#{field.name}"
+ when Prism::Template::NodeField, Prism::Template::OptionalNodeField then "PM_NODE_ALIGNAS 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}"
@@ -212,8 +245,27 @@ typedef enum pm_<%= flag.human %> {
/** <%= value.comment %> */
PM_<%= flag.human.upcase %>_<%= value.name %> = <%= 1 << (index + Prism::Template::COMMON_FLAGS_COUNT) %>,
<%- end -%>
+
+ PM_<%= flag.human.upcase %>_LAST,
} pm_<%= flag.human %>_t;
<%- end -%>
+<%- nodes.each do |node| -%>
+
+<%- params = node.fields.map(&:c_param) -%>
+/**
+ * Allocate and initialize a new <%= node.name %> node.
+ *
+ * @param arena The arena to allocate from.
+ * @param node_id The unique identifier for this node.
+ * @param flags The flags for this node.
+ * @param location The location of this node in the source.
+<%- node.fields.each do |field| -%>
+ * @param <%= field.name %> <%= field.comment ? Prism::Template::Doxygen.verbatim(field.comment.lines.first.strip) : "The #{field.name} field." %>
+<%- end -%>
+ * @returns The newly allocated and initialized node.
+ */
+PRISM_EXPORTED_FUNCTION pm_<%= node.human %>_t * pm_<%= node.human %>_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location<%= params.empty? ? "" : ", #{params.join(", ")}" %>);
+<%- end -%>
/**
* When we're serializing to Java, we want to skip serializing the location
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/include/prism/internal/diagnostic.h.erb b/prism/templates/include/prism/internal/diagnostic.h.erb
new file mode 100644
index 0000000000..ee44ff5382
--- /dev/null
+++ b/prism/templates/include/prism/internal/diagnostic.h.erb
@@ -0,0 +1,60 @@
+#ifndef PRISM_INTERNAL_DIAGNOSTIC_H
+#define PRISM_INTERNAL_DIAGNOSTIC_H
+
+#include "prism/internal/list.h"
+
+#include "prism/arena.h"
+#include "prism/diagnostic.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.
+ */
+struct pm_diagnostic_t {
+ /* 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;
+
+ /*
+ * The level of the diagnostic, see `pm_error_level_t` and
+ * `pm_warning_level_t` for possible values.
+ */
+ uint8_t level;
+};
+
+/*
+ * Append a diagnostic to the given list of diagnostics that is using shared
+ * memory for its message.
+ */
+void pm_diagnostic_list_append(pm_arena_t *arena, pm_list_t *list, uint32_t start, uint32_t length, pm_diagnostic_id_t diag_id);
+
+/*
+ * Append a diagnostic to the given list of diagnostics that is using a format
+ * string for its message.
+ */
+void pm_diagnostic_list_append_format(pm_arena_t *arena, pm_list_t *list, uint32_t start, uint32_t length, pm_diagnostic_id_t diag_id, ...);
+
+#endif
diff --git a/prism/templates/lib/prism/compiler.rb.erb b/prism/templates/lib/prism/compiler.rb.erb
index 9102025c20..13317cac04 100644
--- a/prism/templates/lib/prism/compiler.rb.erb
+++ b/prism/templates/lib/prism/compiler.rb.erb
@@ -1,3 +1,6 @@
+#--
+# rbs_inline: enabled
+
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
@@ -18,25 +21,31 @@ module Prism
#
class Compiler < Visitor
# Visit an individual node.
- def visit(node)
+ #--
+ #: (node?) -> untyped
+ def visit(node) # :nodoc:
node&.accept(self)
end
# Visit a list of nodes.
- def visit_all(nodes)
+ #--
+ #: (Array[node?]) -> untyped
+ def visit_all(nodes) # :nodoc:
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) }
+ #--
+ #: (node) -> Array[untyped]
+ def visit_child_nodes(node) # :nodoc:
+ node.each_child_node.map { |node| node.accept(self) }
end
<%- nodes.each_with_index do |node, index| -%>
<%= "\n" if index != 0 -%>
- # Compile a <%= node.name %> node
- def visit_<%= node.human %>(node)
- node.compact_child_nodes.map { |node| node.accept(self) }
+ #: (<%= node.name %>) -> Array[untyped]
+ def visit_<%= node.human %>(node) # :nodoc:
+ node.each_child_node.map { |node| node.accept(self) }
end
<%- end -%>
end
diff --git a/prism/templates/lib/prism/dispatcher.rb.erb b/prism/templates/lib/prism/dispatcher.rb.erb
index 52478451c9..5991b0c904 100644
--- a/prism/templates/lib/prism/dispatcher.rb.erb
+++ b/prism/templates/lib/prism/dispatcher.rb.erb
@@ -1,3 +1,6 @@
+#--
+# rbs_inline: enabled
+
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
@@ -32,50 +35,52 @@ module Prism
# dispatcher.dispatch_once(integer)
#
class Dispatcher < Visitor
- # attr_reader listeners: Hash[Symbol, Array[Listener]]
- attr_reader :listeners
+ # A hash mapping event names to arrays of listeners that should be notified
+ # when that event is fired.
+ attr_reader :listeners #: Hash[Symbol, Array[untyped]]
# Initialize a new dispatcher.
+ #--
+ #: () -> void
def initialize
@listeners = {}
end
# Register a listener for one or more events.
- #
- # def register: (Listener, *Symbol) -> void
+ #--
+ #: (untyped, *Symbol) -> void
def register(listener, *events)
register_events(listener, events)
end
# Register all public methods of a listener that match the pattern
# `on_<node_name>_(enter|leave)`.
- #
- # def register_public_methods: (Listener) -> void
+ #--
+ #: (untyped) -> void
def register_public_methods(listener)
register_events(listener, listener.public_methods(false).grep(/\Aon_.+_(?:enter|leave)\z/))
end
# Register a listener for the given events.
- private def register_events(listener, events)
+ #--
+ #: (untyped, Array[Symbol]) -> void
+ private def register_events(listener, events) # :nodoc:
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
+ #--
+ #: (node 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)
+ #: (<%= node.name %> node) -> void
+ def visit_<%= node.human %>(node) # :nodoc:
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) }
@@ -83,14 +88,17 @@ module Prism
<%- end -%>
class DispatchOnce < Visitor # :nodoc:
- attr_reader :listeners
+ attr_reader :listeners #: Hash[Symbol, Array[untyped]]
+ #: (Hash[Symbol, Array[untyped]] listeners) -> void
def initialize(listeners)
@listeners = listeners
end
<%- nodes.each do |node| -%>
# Dispatch enter and leave events for <%= node.name %> nodes.
+ #--
+ #: (<%= node.name %> node) -> void
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) }
diff --git a/prism/templates/lib/prism/dot_visitor.rb.erb b/prism/templates/lib/prism/dot_visitor.rb.erb
index cd2998fe61..88ef1e1f36 100644
--- a/prism/templates/lib/prism/dot_visitor.rb.erb
+++ b/prism/templates/lib/prism/dot_visitor.rb.erb
@@ -1,3 +1,6 @@
+#--
+# rbs_inline: enabled
+
require "cgi/escape"
require "cgi/util" unless defined?(CGI::EscapeExt)
@@ -6,14 +9,18 @@ module Prism
# subtree into a graphviz dot graph.
class DotVisitor < Visitor
class Field # :nodoc:
- attr_reader :name, :value, :port
+ attr_reader :name #: String
+ attr_reader :value #: String?
+ attr_reader :port #: bool
+ #: (String name, String? value, bool port) -> void
def initialize(name, value, port)
@name = name
@value = value
@port = port
end
+ #: () -> String
def to_dot
if port
"<tr><td align=\"left\" colspan=\"2\" port=\"#{name}\">#{name}</td></tr>"
@@ -24,17 +31,21 @@ module Prism
end
class Table # :nodoc:
- attr_reader :name, :fields
+ attr_reader :name #: String
+ attr_reader :fields #: Array[Field]
+ #: (String name) -> void
def initialize(name)
@name = name
@fields = []
end
+ #: (String name, ?String? value, ?port: bool) -> void
def field(name, value = nil, port: false)
fields << Field.new(name, value, port)
end
+ #: () -> String
def to_dot
dot = <<~DOT
<table border="0" cellborder="1" cellspacing="0" cellpadding="4">
@@ -50,26 +61,31 @@ module Prism
end
class Digraph # :nodoc:
- attr_reader :nodes, :waypoints, :edges
+ attr_reader :nodes, :waypoints, :edges #: Array[String]
+ #: () -> void
def initialize
@nodes = []
@waypoints = []
@edges = []
end
+ #: (String value) -> void
def node(value)
nodes << value
end
+ #: (String value) -> void
def waypoint(value)
waypoints << value
end
+ #: (String value) -> void
def edge(value)
edges << value
end
+ #: () -> String
def to_dot
<<~DOT
digraph "Prism" {
@@ -93,21 +109,25 @@ module Prism
private_constant :Field, :Table, :Digraph
# The digraph that is being built.
- attr_reader :digraph
+ attr_reader :digraph #: Digraph
# Initialize a new dot visitor.
+ #--
+ #: () -> void
def initialize
@digraph = Digraph.new
end
# Convert this visitor into a graphviz dot graph string.
+ #--
+ #: () -> String
def to_dot
digraph.to_dot
end
<%- nodes.each do |node| -%>
- # Visit a <%= node.name %> node.
- def visit_<%= node.human %>(node)
+ #: (<%= node.name %>) -> void
+ def visit_<%= node.human %>(node) # :nodoc:
table = Table.new("<%= node.name %>")
id = node_id(node)
<%- if (node_flags = node.flags) -%>
@@ -152,7 +172,7 @@ module Prism
<%- end -%>
<%- end -%>
- digraph.nodes << <<~DOT
+ digraph.node(<<~DOT)
#{id} [
label=<#{table.to_dot.gsub(/\n/, "\n ")}>
];
@@ -165,19 +185,25 @@ module Prism
private
# Generate a unique node ID for a node throughout the digraph.
- def node_id(node)
+ #--
+ #: (node) -> String
+ def node_id(node) # :nodoc:
"Node_#{node.object_id}"
end
- # Inspect a location to display the start and end line and column numbers.
- def location_inspect(location)
+ # Inspect a location to display the start and end line and columns in bytes.
+ #--
+ #: (Location) -> String
+ def location_inspect(location) # :nodoc:
"(#{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)
+ #--
+ #: (<%= nodes.filter_map { |node| node.name if node.flags == flag }.join(" | ") %> node) -> String
+ def <%= flag.human %>_inspect(node) # :nodoc:
flags = [] #: Array[String]
<%- flag.values.each do |value| -%>
flags << "<%= value.name.downcase %>" if node.<%= value.name.downcase %>?
diff --git a/prism/templates/lib/prism/dsl.rb.erb b/prism/templates/lib/prism/dsl.rb.erb
index e16ebb7110..be7dc6d9c1 100644
--- a/prism/templates/lib/prism/dsl.rb.erb
+++ b/prism/templates/lib/prism/dsl.rb.erb
@@ -1,8 +1,11 @@
+#--
+# rbs_inline: enabled
+
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]")
+ # source = Prism::Source.for("[1]", 1, [0])
#
# Prism::ArrayNode.new(
# source,
@@ -56,17 +59,31 @@ module Prism
extend self
# Create a new Source object.
+ #--
+ #: (String string) -> Source
def source(string)
- Source.for(string)
+ Source.for(string, 1, build_offsets(string))
end
# Create a new Location object.
+ #--
+ #: (?source: Source, ?start_offset: Integer, ?length: Integer) -> Location
def location(source: default_source, start_offset: 0, length: 0)
Location.new(source, start_offset, length)
end
<%- nodes.each do |node| -%>
+ <%-
+ params = [
+ ["source", "Source"],
+ ["node_id", "Integer"],
+ ["location", "Location"],
+ ["flags", "Integer"]
+ ].concat(node.fields.map { |field| [field.name, field.rbs_class] })
+ -%>
# Create a new <%= node.name %> node.
+ #--
+ #: (<%= params.map { |(name, type)| "?#{name}: #{type}" }.join(", ") %>) -> <%= node.name %>
def <%= node.human %>(<%= ["source: default_source", "node_id: 0", "location: default_location", "flags: 0", *node.fields.map { |field|
case field
when Prism::Template::NodeField
@@ -100,6 +117,8 @@ module Prism
<%- flags.each do |flag| -%>
# Retrieve the value of one of the <%= flag.name %> flags.
+ #--
+ #: (Symbol name) -> Integer
def <%= flag.human.chomp("s") %>(name)
case name
<%- flag.values.each do |value| -%>
@@ -114,20 +133,40 @@ module Prism
# The default source object that gets attached to nodes and locations if no
# source is specified.
+ #--
+ #: () -> Source
def default_source
- Source.for("")
+ Source.for("", 1, [0])
end
# The default location object that gets attached to nodes if no location is
# specified, which uses the given source.
+ #--
+ #: () -> Location
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.
+ #--
+ #: (Source source, Location location) -> node
def default_node(source, location)
- MissingNode.new(source, -1, location, 0)
+ ErrorRecoveryNode.new(source, -1, location, 0, nil)
+ end
+
+ private
+
+ # Build the newline byte offset array for the given source string.
+ #--
+ #: (String source) -> Array[Integer]
+ def build_offsets(source)
+ offsets = [0]
+ start = 0
+ while (index = source.byteindex("\n", start))
+ offsets << (start = index + 1)
+ end
+ offsets
end
end
end
diff --git a/prism/templates/lib/prism/inspect_visitor.rb.erb b/prism/templates/lib/prism/inspect_visitor.rb.erb
index 3cfe615d85..820f5ae75f 100644
--- a/prism/templates/lib/prism/inspect_visitor.rb.erb
+++ b/prism/templates/lib/prism/inspect_visitor.rb.erb
@@ -1,3 +1,6 @@
+#--
+# rbs_inline: enabled
+
module Prism
# This visitor is responsible for composing the strings that get returned by
# the various #inspect methods defined on each of the nodes.
@@ -7,8 +10,9 @@ module Prism
# 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
+ attr_reader :value #: String
+ #: (String value) -> void
def initialize(value)
@value = value
end
@@ -17,19 +21,25 @@ module Prism
private_constant :Replace
# The current prefix string.
- attr_reader :indent
+ # :stopdoc:
+ attr_reader :indent #: String
+ # :startdoc:
# The list of commands that we need to execute in order to compose the
# final string.
- attr_reader :commands
+ #: stopdoc:
+ attr_reader :commands #: Array[[String | node | Replace, String]]
+ # :startdoc:
- # Initializes a new instance of the InspectVisitor.
- def initialize(indent = +"")
+ #: (?String indent) -> void
+ def initialize(indent = +"") # :nodoc:
@indent = indent
@commands = []
end
# Compose an inspect string for the given node.
+ #--
+ #: (node node) -> String
def self.compose(node)
visitor = new
node.accept(visitor)
@@ -37,7 +47,9 @@ module Prism
end
# Compose the final string.
- def compose
+ #--
+ #: () -> String
+ def compose # :nodoc:
buffer = +""
replace = nil
@@ -66,8 +78,8 @@ module Prism
end
<%- nodes.each do |node| -%>
- # Inspect a <%= node.name %> node.
- def visit_<%= node.human %>(node)
+ #: (<%= node.name %> node) -> void
+ def visit_<%= node.human %>(node) # :nodoc:
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 ? "└── " : "├── " -%>
@@ -114,13 +126,17 @@ module Prism
private
# Compose a header for the given node.
- def inspect_node(name, node)
+ #--
+ #: (String name, node node) -> String
+ def inspect_node(name, node) # :nodoc:
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)
+ #--
+ #: (Location? location) -> String
+ def inspect_location(location) # :nodoc:
if location
"(#{location.start_line},#{location.start_column})-(#{location.end_line},#{location.end_column}) = #{location.slice.inspect}"
else
diff --git a/prism/templates/lib/prism/mutation_compiler.rb.erb b/prism/templates/lib/prism/mutation_compiler.rb.erb
index 565ee4e315..2d555048d2 100644
--- a/prism/templates/lib/prism/mutation_compiler.rb.erb
+++ b/prism/templates/lib/prism/mutation_compiler.rb.erb
@@ -1,3 +1,6 @@
+#--
+# rbs_inline: enabled
+
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
@@ -5,8 +8,8 @@ module Prism
class MutationCompiler < Compiler
<%- nodes.each_with_index do |node, index| -%>
<%= "\n" if index != 0 -%>
- # Copy a <%= node.name %> node
- def visit_<%= node.human %>(node)
+ #: (<%= node.name %>) -> node?
+ def visit_<%= node.human %>(node) # :nodoc:
<%- 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(", ") %>)
diff --git a/prism/templates/lib/prism/node.rb.erb b/prism/templates/lib/prism/node.rb.erb
index ceee2b0ffe..fb13051aba 100644
--- a/prism/templates/lib/prism/node.rb.erb
+++ b/prism/templates/lib/prism/node.rb.erb
@@ -1,24 +1,49 @@
+#--
+# rbs_inline: enabled
+
module Prism
+ # @rbs!
+ # interface _Repository
+ # def enter: (Integer node_id, Symbol field_name) -> Relocation::Entry
+ # end
+ #
+ # interface _Node
+ # def deconstruct: () -> Array[Prism::node?]
+ # def inspect: () -> String
+ # end
+ #
+ # type node = Node & _Node
+
# 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
+ # :stopdoc:
+ attr_reader :source #: Source
private :source
+ # :startdoc:
# 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
+ attr_reader :node_id #: Integer
+
+ # The location associated with this node. For lazily loading Location
+ # objects, we keep it as a packed integer until it is accessed.
+ # @rbs @location: Location | Integer
# Save this node using a saved source so that it can be retrieved later.
+ #--
+ #: (_Repository repository) -> Relocation::Entry
def save(repository)
repository.enter(node_id, :itself)
end
# A Location instance that represents the location of this node in the
# source.
+ #--
+ #: () -> Location
def location
location = @location
return location if location.is_a?(Location)
@@ -26,104 +51,151 @@ module Prism
end
# Save the location using a saved source so that it can be retrieved later.
+ #--
+ #: (_Repository repository) -> Relocation::Entry
def save_location(repository)
repository.enter(node_id, :location)
end
- # Delegates to the start_line of the associated location object.
+ # --------------------------------------------------------------------------
+ # :section: Location Delegators
+ # These methods provide convenient access to the underlying Location object.
+ # --------------------------------------------------------------------------
+
+ # Delegates to [`start_line`](rdoc-ref:Location#start_line) of the associated location object.
+ #--
+ #: () -> Integer
def start_line
location.start_line
end
- # Delegates to the end_line of the associated location object.
+ # Delegates to [`end_line`](rdoc-ref:Location#end_line) of the associated location object.
+ #--
+ #: () -> Integer
def end_line
location.end_line
end
- # The start offset of the node in the source. This method is effectively a
- # delegate method to the location object.
+ # Delegates to [`start_offset`](rdoc-ref:Location#start_offset) of the associated location object.
+ #--
+ #: () -> Integer
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.
+ # Delegates to [`end_offset`](rdoc-ref:Location#end_offset) of the associated location object.
+ #--
+ #: () -> Integer
def end_offset
location = @location
location.is_a?(Location) ? location.end_offset : ((location >> 32) + (location & 0xFFFFFFFF))
end
- # Delegates to the start_character_offset of the associated location object.
+ # Delegates to [`start_character_offset`](rdoc-ref:Location#start_character_offset)
+ # of the associated location object.
+ #--
+ #: () -> Integer
def start_character_offset
location.start_character_offset
end
- # Delegates to the end_character_offset of the associated location object.
+ # Delegates to [`end_character_offset`](rdoc-ref:Location#end_character_offset)
+ # of the associated location object.
+ #--
+ #: () -> Integer
def end_character_offset
location.end_character_offset
end
- # Delegates to the cached_start_code_units_offset of the associated location
- # object.
+ # Delegates to [`cached_start_code_units_offset`](rdoc-ref:Location#cached_start_code_units_offset)
+ # of the associated location object.
+ #--
+ #: (_CodeUnitsCache cache) -> Integer
def cached_start_code_units_offset(cache)
location.cached_start_code_units_offset(cache)
end
- # Delegates to the cached_end_code_units_offset of the associated location
- # object.
+ # Delegates to [`cached_end_code_units_offset`](rdoc-ref:Location#cached_end_code_units_offset)
+ # of the associated location object.
+ #--
+ #: (_CodeUnitsCache cache) -> Integer
def cached_end_code_units_offset(cache)
location.cached_end_code_units_offset(cache)
end
- # Delegates to the start_column of the associated location object.
+ # Delegates to [`start_column`](rdoc-ref:Location#start_column) of the associated location object.
+ #--
+ #: () -> Integer
def start_column
location.start_column
end
- # Delegates to the end_column of the associated location object.
+ # Delegates to [`end_column`](rdoc-ref:Location#end_column) of the associated location object.
+ #--
+ #: () -> Integer
def end_column
location.end_column
end
- # Delegates to the start_character_column of the associated location object.
+ # Delegates to [`start_character_column`](rdoc-ref:Location#start_character_column)
+ # of the associated location object.
+ #--
+ #: () -> Integer
def start_character_column
location.start_character_column
end
- # Delegates to the end_character_column of the associated location object.
+ # Delegates to [`end_character_column`](rdoc-ref:Location#end_character_column)
+ # of the associated location object.
+ #--
+ #: () -> Integer
def end_character_column
location.end_character_column
end
- # Delegates to the cached_start_code_units_column of the associated location
- # object.
+ # Delegates to [`cached_start_code_units_column`](rdoc-ref:Location#cached_start_code_units_column)
+ # of the associated location object.
+ #--
+ #: (_CodeUnitsCache cache) -> Integer
def cached_start_code_units_column(cache)
location.cached_start_code_units_column(cache)
end
- # Delegates to the cached_end_code_units_column of the associated location
- # object.
+ # Delegates to [`cached_end_code_units_column`](rdoc-ref:Location#cached_end_code_units_column)
+ # of the associated location object.
+ #--
+ #: (_CodeUnitsCache cache) -> Integer
def cached_end_code_units_column(cache)
location.cached_end_code_units_column(cache)
end
- # Delegates to the leading_comments of the associated location object.
+ # Delegates to [`leading_comments`](rdoc-ref:Location#leading_comments) of the associated location object.
+ #--
+ #: () -> Array[Comment]
def leading_comments
location.leading_comments
end
- # Delegates to the trailing_comments of the associated location object.
+ # Delegates to [`trailing_comments`](rdoc-ref:Location#trailing_comments) of the associated location object.
+ #--
+ #: () -> Array[Comment]
def trailing_comments
location.trailing_comments
end
- # Delegates to the comments of the associated location object.
+ # Delegates to [`comments`](rdoc-ref:Location#comments) of the associated location object.
+ #--
+ #: () -> Array[Comment]
def comments
location.comments
end
+ # :section:
+
# Returns all of the lines of the source code associated with this node.
+ #--
+ #: () -> Array[String]
def source_lines
location.source_lines
end
@@ -133,6 +205,8 @@ module Prism
alias script_lines source_lines
# Slice the location of the node from the source.
+ #--
+ #: () -> String
def slice
location.slice
end
@@ -140,28 +214,38 @@ module Prism
# 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.
+ #--
+ #: () -> String
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
+ # :stopdoc:
+ attr_reader :flags #: Integer
protected :flags
+ # :startdoc:
# Returns true if the node has the newline flag set.
+ #--
+ #: () -> bool
def newline?
flags.anybits?(NodeFlags::NEWLINE)
end
# Returns true if the node has the static literal flag set.
+ #--
+ #: () -> bool
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)
+ #--
+ #: (PP q) -> void
+ def pretty_print(q) # :nodoc:
q.seplist(inspect.chomp.each_line, -> { q.breakable }) do |line|
q.text(line.chomp)
end
@@ -169,6 +253,8 @@ module Prism
end
# Convert this node into a graphviz dot graph string.
+ #--
+ #: () -> String
def to_dot
# @type self: node
DotVisitor.new.tap { |visitor| accept(visitor) }.to_dot
@@ -180,28 +266,18 @@ module Prism
#
# Important to note is that the column given to this method should be in
# bytes, as opposed to characters or code units.
+ #--
+ #: (Integer line, Integer column) -> Array[node]
def tunnel(line, column)
- queue = [self] #: Array[Prism::node]
- result = [] #: Array[Prism::node]
+ queue = [self] #: Array[node]
+ result = [] #: Array[node]
+ offset = source.byte_offset(line, column)
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
+ node.each_child_node do |child_node|
+ if child_node.start_offset <= offset && offset < child_node.end_offset
queue << child_node
break
end
@@ -212,13 +288,14 @@ module Prism
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
+ # breadth-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]
+ #--
+ #: () { (node) -> bool } -> node?
+ def breadth_first_search(&blk)
+ queue = [self] #: Array[node]
while (node = queue.shift)
return node if yield node
@@ -227,10 +304,33 @@ module Prism
nil
end
+ alias find breadth_first_search
+
+ # Returns all of the nodes that match the given block when visited in a
+ # breadth-first search. This is useful for finding all nodes that match a
+ # particular condition.
+ #
+ # node.breadth_first_search_all { |node| node.is_a?(Prism::CallNode) }
+ #--
+ #: () { (node) -> bool } -> Array[node]
+ def breadth_first_search_all(&blk)
+ queue = [self] #: Array[Prism::node]
+ results = [] #: Array[Prism::node]
+
+ while (node = queue.shift)
+ results << node if yield node
+ queue.concat(node.compact_child_nodes)
+ end
+
+ results
+ end
+ alias find_all breadth_first_search_all
# 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.
+ #--
+ #: () -> Array[Reflection::Field]
def self.fields
# This method should only be called on subclasses of Node, not Node
# itself.
@@ -240,38 +340,57 @@ module Prism
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.
+ # :section: Node Interface
+ # These methods are effectively abstract methods that are implemented by
+ # the various subclasses of Node.
# --------------------------------------------------------------------------
# Accepts a visitor and calls back into the specialized visit function.
+ #--
+ #: (_Visitor visitor) -> untyped
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.
+ #--
+ #: () -> Array[node?]
def child_nodes
raise NoMethodError, "undefined method `child_nodes' for #{inspect}"
end
alias deconstruct child_nodes
+ # With a block given, yields each child node. Without a block, returns
+ # an enumerator that contains each child node. Excludes any `nil`s in
+ # the place of optional nodes that were not present.
+ #--
+ #: () -> Enumerator[node, void]
+ #: () { (node) -> void } -> void
+ def each_child_node(&blk)
+ raise NoMethodError, "undefined method `each_child_node' for #{inspect}"
+ end
+
# Returns an array of child nodes, excluding any `nil`s in the place of
# optional nodes that were not present.
+ #--
+ #: () -> Array[node]
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.
+ #--
+ #: () -> Array[node | Location]
def comment_targets
raise NoMethodError, "undefined method `comment_targets' for #{inspect}"
end
# Returns a string representation of the node.
+ #--
+ #: () -> String
def inspect
raise NoMethodError, "undefined method `inspect' for #{inspect}"
end
@@ -288,6 +407,8 @@ module Prism
# 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.
+ #--
+ #: () -> Symbol
def type
raise NoMethodError, "undefined method `type' for #{inspect}"
end
@@ -296,6 +417,8 @@ module Prism
# 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.
+ #--
+ #: () -> Symbol
def self.type
raise NoMethodError, "undefined method `type' for #{inspect}"
end
@@ -306,7 +429,13 @@ module Prism
#<%= line %>
<%- end -%>
class <%= node.name -%> < Node
+ <%- node.fields.each do |field| -%>
+ # @rbs @<%= field.name %>: <%= field.rbs_class %>
+ <%- end -%>
+
# Initialize a new <%= node.name %> node.
+ #--
+ #: (Source source, Integer node_id, Location location, Integer flags, <%= node.fields.map { |field| "#{field.rbs_class} #{field.name}" }.join(", ") %>) -> void
def initialize(<%= ["source", "node_id", "location", "flags", *node.fields.map(&:name)].join(", ") %>)
@source = source
@node_id = node_id
@@ -320,12 +449,27 @@ module Prism
<%- end -%>
end
- # def accept: (Visitor visitor) -> void
+ # ---------
+ # :section: Repository
+ # Methods related to Relocation.
+ # ---------
+
+ # ----------------------------------------------------------------------------------
+ # :section: Node Interface
+ # These methods are present on all subclasses of Node.
+ # Read the [node interface docs](Node.html#node-interface) for more information.
+ # ----------------------------------------------------------------------------------
+
+ # See Node.accept.
+ #--
+ #: (_Visitor visitor) -> untyped
def accept(visitor)
visitor.visit_<%= node.human %>(self)
end
- # def child_nodes: () -> Array[Node?]
+ # See Node.child_nodes.
+ #--
+ #: () -> Array[node?]
def child_nodes
[<%= node.fields.map { |field|
case field
@@ -335,7 +479,28 @@ module Prism
}.compact.join(", ") %>]
end
- # def compact_child_nodes: () -> Array[Node]
+ # See Node.each_child_node.
+ #--
+ #: () -> Enumerator[node, void]
+ #: () { (node) -> void } -> void
+ def each_child_node(&blk)
+ return to_enum(:each_child_node) unless block_given?
+
+ <%- node.fields.each do |field| -%>
+ <%- case field -%>
+ <%- when Prism::Template::NodeField -%>
+ yield <%= field.name %>
+ <%- when Prism::Template::OptionalNodeField -%>
+ if (<%= field.name %> = self.<%= field.name %>); yield <%= field.name %>; end
+ <%- when Prism::Template::NodeListField -%>
+ <%= field.name %>.each { |node| yield node }
+ <%- end -%>
+ <%- end -%>
+ end
+
+ # See Node.compact_child_nodes.
+ #--
+ #: () -> Array[node]
def compact_child_nodes
<%- if node.fields.any? { |field| field.is_a?(Prism::Template::OptionalNodeField) } -%>
compact = [] #: Array[Prism::node]
@@ -344,7 +509,7 @@ module Prism
<%- when Prism::Template::NodeField -%>
compact << <%= field.name %>
<%- when Prism::Template::OptionalNodeField -%>
- compact << <%= field.name %> if <%= field.name %>
+ if (<%= field.name %> = self.<%= field.name %>); compact << <%= field.name %>; end
<%- when Prism::Template::NodeListField -%>
compact.concat(<%= field.name %>)
<%- end -%>
@@ -360,7 +525,9 @@ module Prism
<%- end -%>
end
- # def comment_targets: () -> Array[Node | Location]
+ # See Node.comment_targets.
+ #--
+ #: () -> Array[node | Location]
def comment_targets
[<%= node.fields.map { |field|
case field
@@ -370,50 +537,101 @@ module Prism
}.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 %>
+ # :call-seq:
+ # copy(**fields) -> <%= node.name %>
+ #
+ # Creates a copy of self with the given fields, using self as the template.
+ #--
+ #: (?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[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)
+ #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
+ def deconstruct_keys(keys) # :nodoc:
{ <%= (["node_id: node_id", "location: location"] + node.fields.map { |field| "#{field.name}: #{field.name}" }).join(", ") %> }
end
+
+ # See `Node#type`.
+ #--
+ #: () -> :<%= node.human %>
+ def type
+ :<%= node.human %>
+ end
+
+ # See `Node.type`.
+ #--
+ #: () -> :<%= node.human %>
+ def self.type
+ :<%= node.human %>
+ end
+
+ #: () -> String
+ def inspect # :nodoc:
+ InspectVisitor.compose(self)
+ end
+
+ # :section:
+
<%- if (node_flags = node.flags) -%>
<%- node_flags.values.each do |value| -%>
-
- # def <%= value.name.downcase %>?: () -> bool
+ # :category: Flags
+ # <%= value.comment %>
+ #--
+ #: () -> bool
def <%= value.name.downcase %>?
flags.anybits?(<%= node_flags.name %>::<%= value.name %>)
end
+
<%- end -%>
<%- end -%>
<%- node.fields.each do |field| -%>
-
+ <%- case field -%>
+ <%- when Prism::Template::LocationField -%>
+ # :category: Locations
+ # :call-seq:
+ # <%= field.name %> -> <%= field.call_seq_type %>
+ #
<%- if field.comment.nil? -%>
- # attr_reader <%= field.name %>: <%= field.rbs_class %>
+ # Returns the Location represented by `<%= field.name %>`.
<%- else -%>
<%- field.each_comment_line do |line| -%>
#<%= line %>
<%- end -%>
<%- end -%>
- <%- case field -%>
- <%- when Prism::Template::LocationField -%>
+ #--
+ #: () -> Location
def <%= field.name %>
location = @<%= field.name %>
return location if location.is_a?(Location)
@<%= field.name %> = Location.new(source, location >> 32, location & 0xFFFFFFFF)
end
+ # :category: Repository
# Save the <%= field.name %> location using the given saved source so that
# it can be retrieved later.
+ #--
+ #: (_Repository repository) -> Relocation::Entry
def save_<%= field.name %>(repository)
repository.enter(node_id, :<%= field.name %>)
end
+
<%- when Prism::Template::OptionalLocationField -%>
+ # :category: Locations
+ # :call-seq:
+ # <%= field.name %> -> <%= field.call_seq_type %>
+ #
+ <%- if field.comment.nil? -%>
+ # Returns the Location represented by `<%= field.name %>`.
+ <%- else -%>
+ <%- field.each_comment_line do |line| -%>
+ #<%= line %>
+ <%- end -%>
+ <%- end -%>
+ #--
+ #: () -> Location?
def <%= field.name %>
location = @<%= field.name %>
case location
@@ -426,54 +644,69 @@ module Prism
end
end
+ # :category: Repository
# Save the <%= field.name %> location using the given saved source so that
# it can be retrieved later.
+ #--
+ #: (_Repository repository) -> Relocation::Entry?
def save_<%= field.name %>(repository)
repository.enter(node_id, :<%= field.name %>) unless @<%= field.name %>.nil?
end
<%- else -%>
- attr_reader :<%= field.name %>
+ # :call-seq:
+ # <%= field.name %> -> <%= field.call_seq_type %>
+ #
+ <%- if field.comment.nil? -%>
+ # Returns the `<%= field.name %>` attribute.
+ <%- else -%>
+ <%- field.each_comment_line do |line| -%>
+ #<%= line %>
<%- end -%>
<%- end -%>
+ #--
+ #: () -> <%= field.rbs_class %>
+ def <%= field.name %>
+ @<%= field.name %>
+ end
+
+ <%- end -%>
+ <%- end -%>
+ # :section: Slicing
+
<%- 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
+ # :call-seq:
+ # <%= field.name.delete_suffix("_loc") %> -> String
+ #
+ # Slice the location of <%= field.name %> from the source.
+ #--
+ #: () -> 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?
+ # :call-seq:
+ # <%= field.name.delete_suffix("_loc") %> -> String | nil
+ #
+ # Slice the location of <%= field.name %> from the source.
+ #--
+ #: () -> String?
def <%= field.name.delete_suffix("_loc") %>
<%= field.name %>&.slice
end
+
<%- end -%>
<%- end -%>
+ # :section:
- # 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)
+ #: (untyped other) -> boolish
+ def ===(other) # :nodoc:
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) -%>
diff --git a/prism/templates/lib/prism/reflection.rb.erb b/prism/templates/lib/prism/reflection.rb.erb
index 6c8b2f4d25..0012f120b2 100644
--- a/prism/templates/lib/prism/reflection.rb.erb
+++ b/prism/templates/lib/prism/reflection.rb.erb
@@ -1,3 +1,6 @@
+#--
+# rbs_inline: enabled
+
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
@@ -7,9 +10,11 @@ module Prism
# for all other field types.
class Field
# The name of the field.
- attr_reader :name
+ attr_reader :name #: Symbol
# Initializes the field with the given name.
+ #--
+ #: (Symbol name) -> void
def initialize(name)
@name = name
end
@@ -83,9 +88,11 @@ module Prism
# the bitset should be accessed through their query methods.
class FlagsField < Field
# The names of the flags in the bitset.
- attr_reader :flags
+ attr_reader :flags #: Array[Symbol]
# Initializes the flags field with the given name and flags.
+ #--
+ #: (Symbol name, Array[Symbol] flags) -> void
def initialize(name, flags)
super(name)
@flags = flags
@@ -93,6 +100,8 @@ module Prism
end
# Returns the fields for the given node.
+ #--
+ #: (singleton(Node) node) -> Array[Field]
def self.fields_for(node)
case node.type
<%- nodes.each do |node| -%>
diff --git a/prism/templates/lib/prism/serialize.rb.erb b/prism/templates/lib/prism/serialize.rb.erb
index 104b60f484..a676f957af 100644
--- a/prism/templates/lib/prism/serialize.rb.erb
+++ b/prism/templates/lib/prism/serialize.rb.erb
@@ -1,16 +1,19 @@
+#--
+# rbs_inline: enabled
+
require "stringio"
require_relative "polyfill/unpack1"
module Prism
# A module responsible for deserializing parse results.
- module Serialize
+ module Serialize # :nodoc:
# 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 = 4
+ MINOR_VERSION = 9
# The patch version of prism that we are expecting to find in the serialized
# strings.
@@ -20,9 +23,11 @@ module Prism
#
# The formatting of the source of this method is purposeful to illustrate
# the structure of the serialized data.
+ #--
+ #: (String input, String serialized, bool freeze) -> ParseResult
def self.load_parse(input, serialized, freeze)
input = input.dup
- source = Source.for(input)
+ source = Source.for(input, 1, [])
loader = Loader.new(source, serialized)
loader.load_header
@@ -38,16 +43,17 @@ module Prism
data_loc = loader.load_optional_location_object(freeze)
errors = loader.load_errors(encoding, freeze)
warnings = loader.load_warnings(encoding, freeze)
+ continuable = loader.load_bool
cpool_base = loader.load_uint32
cpool_size = loader.load_varuint
- constant_pool = ConstantPool.new(input, serialized, cpool_base, cpool_size)
+ constant_pool = ConstantPool.new(serialized, cpool_base, cpool_size)
- node = loader.load_node(constant_pool, encoding, freeze)
+ node = loader.load_node(constant_pool, encoding, freeze) #: ProgramNode
loader.load_constant_pool(constant_pool)
raise unless loader.eof?
- result = ParseResult.new(node, comments, magic_comments, data_loc, errors, warnings, source)
+ result = ParseResult.new(node, comments, magic_comments, data_loc, errors, warnings, continuable, source)
result.freeze if freeze
input.force_encoding(encoding)
@@ -73,8 +79,10 @@ module Prism
#
# The formatting of the source of this method is purposeful to illustrate
# the structure of the serialized data.
+ #--
+ #: (String input, String serialized, bool freeze) -> LexResult
def self.load_lex(input, serialized, freeze)
- source = Source.for(input)
+ source = Source.for(input, 1, [])
loader = Loader.new(source, serialized)
tokens = loader.load_tokens
@@ -90,9 +98,10 @@ module Prism
data_loc = loader.load_optional_location_object(freeze)
errors = loader.load_errors(encoding, freeze)
warnings = loader.load_warnings(encoding, freeze)
+ continuable = loader.load_bool
raise unless loader.eof?
- result = LexResult.new(tokens, comments, magic_comments, data_loc, errors, warnings, source)
+ result = LexResult.new(tokens, comments, magic_comments, data_loc, errors, warnings, continuable, source)
tokens.each do |token|
token[0].value.force_encoding(encoding)
@@ -117,8 +126,10 @@ module Prism
#
# The formatting of the source of this method is purposeful to illustrate
# the structure of the serialized data.
+ #--
+ #: (String input, String serialized, bool freeze) -> Array[Comment]
def self.load_parse_comments(input, serialized, freeze)
- source = Source.for(input)
+ source = Source.for(input, 1, [])
loader = Loader.new(source, serialized)
loader.load_header
@@ -139,8 +150,10 @@ module Prism
#
# The formatting of the source of this method is purposeful to illustrate
# the structure of the serialized data.
+ #--
+ #: (String input, String serialized, bool freeze) -> ParseLexResult
def self.load_parse_lex(input, serialized, freeze)
- source = Source.for(input)
+ source = Source.for(input, 1, [])
loader = Loader.new(source, serialized)
tokens = loader.load_tokens
@@ -157,17 +170,18 @@ module Prism
data_loc = loader.load_optional_location_object(freeze)
errors = loader.load_errors(encoding, freeze)
warnings = loader.load_warnings(encoding, freeze)
+ continuable = loader.load_bool
cpool_base = loader.load_uint32
cpool_size = loader.load_varuint
- constant_pool = ConstantPool.new(input, serialized, cpool_base, cpool_size)
+ constant_pool = ConstantPool.new(serialized, cpool_base, cpool_size)
- node = loader.load_node(constant_pool, encoding, freeze)
+ node = loader.load_node(constant_pool, encoding, freeze) #: ProgramNode
loader.load_constant_pool(constant_pool)
raise unless loader.eof?
- value = [node, tokens]
- result = ParseLexResult.new(value, comments, magic_comments, data_loc, errors, warnings, source)
+ value = [node, tokens] #: [ProgramNode, Array[[Token, Integer]]]
+ result = ParseLexResult.new(value, comments, magic_comments, data_loc, errors, warnings, continuable, source)
tokens.each do |token|
token[0].value.force_encoding(encoding)
@@ -189,34 +203,36 @@ module Prism
end
class ConstantPool # :nodoc:
- attr_reader :size
+ attr_reader :size #: Integer
+
+ # @rbs @serialized: String
+ # @rbs @base: Integer
+ # @rbs @pool: Array[Symbol?]
- def initialize(input, serialized, base, size)
- @input = input
+ #: (String serialized, Integer base, Integer size) -> void
+ def initialize(serialized, base, size)
@serialized = serialized
@base = base
@size = size
@pool = Array.new(size, nil)
end
+ #: (Integer index, Encoding encoding) -> Symbol
def get(index, encoding)
@pool[index] ||=
begin
offset = @base + index * 8
- start = @serialized.unpack1("L", offset: offset)
- length = @serialized.unpack1("L", offset: offset + 4)
+ start = @serialized.unpack1("L", offset: offset) #: Integer
+ length = @serialized.unpack1("L", offset: offset + 4) #: Integer
- 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
+ (@serialized.byteslice(start, length) or raise).force_encoding(encoding).to_sym
end
end
end
if RUBY_ENGINE == "truffleruby"
# StringIO is synchronized and that adds a high overhead on TruffleRuby.
+ # @rbs skip
class FastStringIO # :nodoc:
attr_accessor :pos
@@ -246,8 +262,11 @@ module Prism
end
class Loader # :nodoc:
- attr_reader :input, :io, :source
+ attr_reader :input #: String
+ attr_reader :io #: StringIO
+ attr_reader :source #: Source
+ #: (Source source, String serialized) -> void
def initialize(source, serialized)
@input = source.source.dup
raise unless serialized.encoding == Encoding::BINARY
@@ -256,40 +275,46 @@ module Prism
define_load_node_lambdas if RUBY_ENGINE != "ruby"
end
+ #: () -> bool
def eof?
io.getbyte
io.eof?
end
+ #: (ConstantPool constant_pool) -> void
def load_constant_pool(constant_pool)
trailer = 0
constant_pool.size.times do |index|
- start, length = io.read(8).unpack("L2")
- trailer += length if start.anybits?(1 << 31)
+ length = (io.read(8) or raise).unpack1("L", offset: 4) #: Integer
+ trailer += length
end
io.read(trailer)
end
+ #: () -> void
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]
+ raise "Invalid serialization" if (io.read(3) or raise).unpack("C3") != [MAJOR_VERSION, MINOR_VERSION, PATCH_VERSION]
raise "Invalid serialization (location fields must be included but are not)" if io.getbyte != 0
end
+ #: () -> Encoding
def load_encoding
- encoding = Encoding.find(io.read(load_varuint))
+ encoding = Encoding.find((io.read(load_varuint) or raise)) or raise
@input = input.force_encoding(encoding).freeze
encoding
end
+ #: (bool freeze) -> Array[Integer]
def load_line_offsets(freeze)
offsets = Array.new(load_varuint) { load_varuint }
offsets.freeze if freeze
offsets
end
+ #: (bool freeze) -> Array[Comment]
def load_comments(freeze)
comments =
Array.new(load_varuint) do
@@ -297,6 +322,7 @@ module Prism
case load_varuint
when 0 then InlineComment.new(load_location_object(freeze))
when 1 then EmbDocComment.new(load_location_object(freeze))
+ else raise
end
comment.freeze if freeze
@@ -307,6 +333,7 @@ module Prism
comments
end
+ #: (bool freeze) -> Array[MagicComment]
def load_magic_comments(freeze)
magic_comments =
Array.new(load_varuint) do
@@ -331,10 +358,11 @@ module Prism
<%- warnings.each do |warning| -%>
<%= warning.name.downcase.to_sym.inspect %>,
<%- end -%>
- ].freeze
+ ].freeze #: Array[Symbol]
private_constant :DIAGNOSTIC_TYPES
+ #: () -> Symbol
def load_error_level
level = io.getbyte
@@ -350,13 +378,14 @@ module Prism
end
end
+ #: (Encoding encoding, bool freeze) -> Array[ParseError]
def load_errors(encoding, freeze)
errors =
Array.new(load_varuint) do
error =
ParseError.new(
DIAGNOSTIC_TYPES.fetch(load_varuint),
- load_embedded_string(encoding),
+ load_string(encoding),
load_location_object(freeze),
load_error_level
)
@@ -369,6 +398,7 @@ module Prism
errors
end
+ #: () -> Symbol
def load_warning_level
level = io.getbyte
@@ -382,13 +412,14 @@ module Prism
end
end
+ #: (Encoding encoding, bool freeze) -> Array[ParseWarning]
def load_warnings(encoding, freeze)
warnings =
Array.new(load_varuint) do
warning =
ParseWarning.new(
DIAGNOSTIC_TYPES.fetch(load_varuint),
- load_embedded_string(encoding),
+ load_string(encoding),
load_location_object(freeze),
load_warning_level
)
@@ -401,15 +432,15 @@ module Prism
warnings
end
+ #: () -> Array[[Token, Integer]]
def load_tokens
- tokens = []
+ tokens = [] #: Array[[Token, Integer]]
while (type = TOKEN_TYPES.fetch(load_varuint))
- start = load_varuint
- length = load_varuint
+ location = load_location_object(false)
+
lex_state = load_varuint
- location = Location.new(@source, start, length)
token = Token.new(@source, type, location.slice, location)
tokens << [token, lex_state]
@@ -420,25 +451,29 @@ module Prism
# variable-length integer using https://en.wikipedia.org/wiki/LEB128
# This is also what protobuf uses: https://protobuf.dev/programming-guides/encoding/#varints
+ #--
+ #: () -> Integer
def load_varuint
- n = io.getbyte
+ n = (io.getbyte or raise)
if n < 128
n
else
n -= 128
shift = 0
- while (b = io.getbyte) >= 128
+ while (b = (io.getbyte or raise)) >= 128
n += (b - 128) << (shift += 7)
end
n + (b << (shift + 7))
end
end
+ #: () -> Integer
def load_varsint
n = load_varuint
(n >> 1) ^ (-(n & 1))
end
+ #: () -> Integer
def load_integer
negative = io.getbyte != 0
length = load_varuint
@@ -450,14 +485,22 @@ module Prism
value
end
+ #: () -> Float
def load_double
- io.read(8).unpack1("D")
+ (io.read(8) or raise).unpack1("D") #: Float
end
+ #: () -> bool
+ def load_bool
+ (io.getbyte or raise) != 0
+ end
+
+ #: () -> Integer
def load_uint32
- io.read(4).unpack1("L")
+ (io.read(4) or raise).unpack1("L") #: Integer
end
+ #: (ConstantPool constant_pool, Encoding encoding, bool freeze) -> node?
def load_optional_node(constant_pool, encoding, freeze)
if io.getbyte != 0
io.pos -= 1
@@ -465,90 +508,121 @@ module Prism
end
end
- def load_embedded_string(encoding)
- io.read(load_varuint).force_encoding(encoding).freeze
- end
-
+ #: (Encoding encoding) -> String
def load_string(encoding)
- case (type = io.getbyte)
- when 1
- input.byteslice(load_varuint, load_varuint).force_encoding(encoding).freeze
- when 2
- load_embedded_string(encoding)
- else
- raise "Unknown serialized string type: #{type}"
- end
+ (io.read(load_varuint) or raise).force_encoding(encoding).freeze
end
+ #: (bool freeze) -> Location
def load_location_object(freeze)
location = Location.new(source, load_varuint, load_varuint)
location.freeze if freeze
location
end
+ # Load a location object from the serialized data. Note that we are lying
+ # about the signature a bit here, because we sometimes load it as a packed
+ # integer instead of an object.
+ #--
+ #: (bool freeze) -> Location
def load_location(freeze)
return load_location_object(freeze) if freeze
- (load_varuint << 32) | load_varuint
+ (load_varuint << 32) | load_varuint #: Location
end
+ # Load an optional location object from the serialized data if it is
+ # present. Note that we are lying about the signature a bit here, because
+ # we sometimes load it as a packed integer instead of an object.
+ #--
+ #: (bool freeze) -> Location?
def load_optional_location(freeze)
load_location(freeze) if io.getbyte != 0
end
+ #: (bool freeze) -> Location?
def load_optional_location_object(freeze)
load_location_object(freeze) if io.getbyte != 0
end
+ #: (ConstantPool constant_pool, Encoding encoding) -> Symbol
def load_constant(constant_pool, encoding)
index = load_varuint
constant_pool.get(index - 1, encoding)
end
+ #: (ConstantPool constant_pool, Encoding encoding) -> Symbol?
def load_optional_constant(constant_pool, encoding)
index = load_varuint
constant_pool.get(index - 1, encoding) if index != 0
end
if RUBY_ENGINE == "ruby"
+ #: (ConstantPool constant_pool, Encoding encoding, bool freeze) -> node
def load_node(constant_pool, encoding, freeze)
type = io.getbyte
node_id = load_varuint
- location = load_location(freeze)
- value = 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(constant_pool, encoding, freeze)"
- when Prism::Template::OptionalNodeField then "load_optional_node(constant_pool, encoding, freeze)"
- when Prism::Template::StringField then "load_string(encoding)"
- when Prism::Template::NodeListField then "Array.new(load_varuint) { load_node(constant_pool, encoding, freeze) }.tap { |nodes| nodes.freeze if freeze }"
- when Prism::Template::ConstantField then "load_constant(constant_pool, encoding)"
- when Prism::Template::OptionalConstantField then "load_optional_constant(constant_pool, encoding)"
- when Prism::Template::ConstantListField then "Array.new(load_varuint) { load_constant(constant_pool, encoding) }.tap { |constants| constants.freeze if freeze }"
- when Prism::Template::LocationField then "load_location(freeze)"
- when Prism::Template::OptionalLocationField then "load_optional_location(freeze)"
- 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(", ") -%>)
+ location = load_location(freeze) #: Location
+ value =
+ case type
+ <%- nodes.each_with_index do |node, index| -%>
+ when <%= index + 1 %>
+ <%- if node.needs_serialized_length? -%>
+ load_uint32
+ <%- end -%>
+ <%= node.name %>.new(
+ source,
+ node_id,
+ location,
+ load_varuint,
+ <%- node.fields.each do |field| -%>
+ <%- case field -%>
+ <%- when Prism::Template::NodeField -%>
+ load_node(constant_pool, encoding, freeze), #: <%= field.rbs_class %>
+ <%- when Prism::Template::OptionalNodeField -%>
+ load_optional_node(constant_pool, encoding, freeze), #: <%= field.rbs_class %>
+ <%- when Prism::Template::StringField -%>
+ load_string(encoding),
+ <%- when Prism::Template::NodeListField -%>
+ Array.new(load_varuint) do
+ load_node(constant_pool, encoding, freeze) #: <%= field.element_rbs_class %>
+ end.tap { |nodes| nodes.freeze if freeze },
+ <%- when Prism::Template::ConstantField -%>
+ load_constant(constant_pool, encoding),
+ <%- when Prism::Template::OptionalConstantField -%>
+ load_optional_constant(constant_pool, encoding),
+ <%- when Prism::Template::ConstantListField -%>
+ Array.new(load_varuint) { load_constant(constant_pool, encoding) }.tap { |constants| constants.freeze if freeze },
+ <%- when Prism::Template::LocationField -%>
+ load_location(freeze),
+ <%- when Prism::Template::OptionalLocationField -%>
+ load_optional_location(freeze),
+ <%- when Prism::Template::UInt8Field -%>
+ (io.getbyte or raise),
+ <%- when Prism::Template::UInt32Field -%>
+ load_varuint,
+ <%- when Prism::Template::IntegerField -%>
+ load_integer,
+ <%- when Prism::Template::DoubleField -%>
+ load_double,
+ <%- else raise -%>
+ <%- end -%>
+ <%- end -%>
+ )
<%- end -%>
- end
+ else
+ raise "Unknown node type: #{type}"
+ end
value.freeze if freeze
value
end
else
+ # @rbs skip
def load_node(constant_pool, encoding, freeze)
- @load_node_lambdas[io.getbyte].call(constant_pool, encoding, freeze)
+ @load_node_lambdas[(io.getbyte or raise)].call(constant_pool, encoding, freeze)
end
+ # @rbs skip
def define_load_node_lambdas
@load_node_lambdas = [
nil,
@@ -559,24 +633,46 @@ module Prism
<%- if node.needs_serialized_length? -%>
load_uint32
<%- end -%>
- value = <%= node.name %>.new(<%= ["source", "node_id", "location", "load_varuint", *node.fields.map { |field|
- case field
- when Prism::Template::NodeField then "load_node(constant_pool, encoding, freeze)"
- when Prism::Template::OptionalNodeField then "load_optional_node(constant_pool, encoding, freeze)"
- when Prism::Template::StringField then "load_string(encoding)"
- when Prism::Template::NodeListField then "Array.new(load_varuint) { load_node(constant_pool, encoding, freeze) }"
- when Prism::Template::ConstantField then "load_constant(constant_pool, encoding)"
- when Prism::Template::OptionalConstantField then "load_optional_constant(constant_pool, encoding)"
- when Prism::Template::ConstantListField then "Array.new(load_varuint) { load_constant(constant_pool, encoding) }"
- when Prism::Template::LocationField then "load_location(freeze)"
- when Prism::Template::OptionalLocationField then "load_optional_location(freeze)"
- 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(", ") -%>)
+ value =
+ <%= node.name %>.new(
+ source,
+ node_id,
+ location,
+ load_varuint,
+ <%- node.fields.map do |field| -%>
+ <%- case field -%>
+ <%- when Prism::Template::NodeField -%>
+ load_node(constant_pool, encoding, freeze), #: <%= field.rbs_class %>
+ <%- when Prism::Template::OptionalNodeField -%>
+ load_optional_node(constant_pool, encoding, freeze), #: <%= field.rbs_class %>
+ <%- when Prism::Template::StringField -%>
+ load_string(encoding),
+ <%- when Prism::Template::NodeListField -%>
+ Array.new(load_varuint) do
+ load_node(constant_pool, encoding, freeze) #: <%= field.element_rbs_class %>
+ end,
+ <%- when Prism::Template::ConstantField -%>
+ load_constant(constant_pool, encoding),
+ <%- when Prism::Template::OptionalConstantField -%>
+ load_optional_constant(constant_pool, encoding),
+ <%- when Prism::Template::ConstantListField -%>
+ Array.new(load_varuint) { load_constant(constant_pool, encoding) },
+ <%- when Prism::Template::LocationField -%>
+ load_location(freeze),
+ <%- when Prism::Template::OptionalLocationField -%>
+ load_optional_location(freeze),
+ <%- when Prism::Template::UInt8Field -%>
+ (io.getbyte or raise),
+ <%- when Prism::Template::UInt32Field -%>
+ load_varuint,
+ <%- when Prism::Template::IntegerField -%>
+ load_integer,
+ <%- when Prism::Template::DoubleField -%>
+ load_double,
+ <%- else raise -%>
+ <%- end -%>
+ <%- end -%>
+ )
value.freeze if freeze
value
},
@@ -584,6 +680,10 @@ module Prism
]
end
end
+
+ # @rbs!
+ # @load_node_lambdas: Array[Proc]
+ # def define_load_node_lambdas: () -> void
end
# The token types that can be indexed by their enum values.
@@ -592,7 +692,7 @@ module Prism
<%- tokens.each do |token| -%>
<%= token.name.to_sym.inspect %>,
<%- end -%>
- ].freeze
+ ].freeze #: Array[Symbol?]
private_constant :MAJOR_VERSION, :MINOR_VERSION, :PATCH_VERSION
private_constant :ConstantPool, :FastStringIO, :Loader, :TOKEN_TYPES
diff --git a/prism/templates/lib/prism/visitor.rb.erb b/prism/templates/lib/prism/visitor.rb.erb
index b1a03c3f1a..f23e87d99e 100644
--- a/prism/templates/lib/prism/visitor.rb.erb
+++ b/prism/templates/lib/prism/visitor.rb.erb
@@ -1,4 +1,14 @@
+#--
+# rbs_inline: enabled
+
module Prism
+ # @rbs!
+ # interface _Visitor
+ # <% nodes.each do |node| %>
+ # def visit_<%= node.human %>: (<%= node.name %>) -> void
+ # <% end %>
+ # end
+
# 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
@@ -6,21 +16,27 @@ module Prism
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.
+ #--
+ #: (node? node) -> void
def visit(node)
# @type self: _Visitor
node&.accept(self)
end
# Visits each node in `nodes` by calling `accept` on each one.
+ #--
+ #: (Array[node?] nodes) -> void
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.
+ #--
+ #: (node node) -> void
def visit_child_nodes(node)
# @type self: _Visitor
- node.compact_child_nodes.each { |node| node.accept(self) }
+ node.each_child_node { |node| node.accept(self) }
end
end
@@ -47,8 +63,10 @@ module Prism
<%- nodes.each_with_index do |node, index| -%>
<%= "\n" if index != 0 -%>
# Visit a <%= node.name %> node
+ #--
+ #: (<%= node.name %> node) -> void
def visit_<%= node.human %>(node)
- node.compact_child_nodes.each { |node| node.accept(self) }
+ node.each_child_node { |node| node.accept(self) }
end
<%- end -%>
end
diff --git a/prism/templates/src/diagnostic.c.erb b/prism/templates/src/diagnostic.c.erb
index 9a30a57e3b..0dea732869 100644
--- a/prism/templates/src/diagnostic.c.erb
+++ b/prism/templates/src/diagnostic.c.erb
@@ -1,4 +1,16 @@
-#include "prism/diagnostic.h"
+#include "prism/internal/diagnostic.h"
+
+#include "prism/compiler/inline.h"
+
+#include "prism/internal/allocator.h"
+#include "prism/internal/arena.h"
+#include "prism/internal/list.h"
+
+#include <assert.h>
+#include <inttypes.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
#define PM_DIAGNOSTIC_ID_MAX <%= errors.length + warnings.length %>
@@ -75,16 +87,16 @@ typedef struct {
* * `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
+ /* 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
+ /* 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
+ /* 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
+ /* 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 },
@@ -102,6 +114,8 @@ static const pm_diagnostic_data_t diagnostic_messages[PM_DIAGNOSTIC_ID_MAX] = {
[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_ELLIPSES_LAMBDA] = { "unexpected ... in lambda argument", PM_ERROR_LEVEL_SYNTAX },
+ [PM_ERR_ARGUMENT_NO_FORWARDING_ELLIPSES_BLOCK] = { "unexpected ... in block argument", 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 },
@@ -144,7 +158,9 @@ static const pm_diagnostic_data_t diagnostic_messages[PM_DIAGNOSTIC_ID_MAX] = {
[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_PARAMETERS] = { "could not parse the endless method parameters", 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_ENDLESS_DO_BLOCK] = { "unexpected `do` for block 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 },
@@ -300,6 +316,7 @@ static const pm_diagnostic_data_t diagnostic_messages[PM_DIAGNOSTIC_ID_MAX] = {
[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_CAPTURE_IN_ALTERNATIVE] = { "variable capture in alternative pattern", 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 },
@@ -325,13 +342,15 @@ static const pm_diagnostic_data_t diagnostic_messages[PM_DIAGNOSTIC_ID_MAX] = {
[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_ESCAPED_NON_ASCII_IN_UTF8] = { "escaped non ASCII character in UTF-8 regexp: /%.*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_CHAR_PROPERTY] = { "invalid character property name {%.*s}: /%.*s/", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_REGEXP_INVALID_UNICODE_RANGE] = { "invalid Unicode range: /%.*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_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_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 },
@@ -346,7 +365,7 @@ static const pm_diagnostic_data_t diagnostic_messages[PM_DIAGNOSTIC_ID_MAX] = {
[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_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 },
@@ -360,6 +379,7 @@ static const pm_diagnostic_data_t diagnostic_messages[PM_DIAGNOSTIC_ID_MAX] = {
[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_PARAMETER_DEFAULT_VALUE] = { "unexpected %s; expected a default value for a parameter", 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 },
@@ -372,7 +392,7 @@ static const pm_diagnostic_data_t diagnostic_messages[PM_DIAGNOSTIC_ID_MAX] = {
[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
+ /* 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 },
@@ -408,8 +428,8 @@ static const pm_diagnostic_data_t diagnostic_messages[PM_DIAGNOSTIC_ID_MAX] = {
/**
* Get the human-readable name of the given diagnostic ID.
*/
-const char *
-pm_diagnostic_id_human(pm_diagnostic_id_t diag_id) {
+static const char *
+pm_diagnostic_id_name(pm_diagnostic_id_t diag_id) {
switch (diag_id) {
<%- errors.each do |error| -%>
case PM_ERR_<%= error.name %>: return "<%= error.name.downcase %>";
@@ -423,8 +443,8 @@ pm_diagnostic_id_human(pm_diagnostic_id_t diag_id) {
return "";
}
-static inline const char *
-pm_diagnostic_message(pm_diagnostic_id_t diag_id) {
+static PRISM_INLINE const char *
+pm_diagnostic_id_message(pm_diagnostic_id_t diag_id) {
assert(diag_id < PM_DIAGNOSTIC_ID_MAX);
const char *message = diagnostic_messages[diag_id].message;
@@ -433,91 +453,102 @@ pm_diagnostic_message(pm_diagnostic_id_t diag_id) {
return message;
}
-static inline uint8_t
-pm_diagnostic_level(pm_diagnostic_id_t diag_id) {
+static PRISM_INLINE uint8_t
+pm_diagnostic_id_level(pm_diagnostic_id_t diag_id) {
assert(diag_id < PM_DIAGNOSTIC_ID_MAX);
return (uint8_t) diagnostic_messages[diag_id].level;
}
/**
+ * Get the type of the given diagnostic.
+ */
+const char *
+pm_diagnostic_type(const pm_diagnostic_t *diagnostic) {
+ return pm_diagnostic_id_name(diagnostic->diag_id);
+}
+
+/**
+ * Get the location of the given diagnostic.
+ */
+pm_location_t
+pm_diagnostic_location(const pm_diagnostic_t *diagnostic) {
+ return diagnostic->location;
+}
+
+/**
+ * Get the message of the given diagnostic.
+ */
+const char *
+pm_diagnostic_message(const pm_diagnostic_t *diagnostic) {
+ return diagnostic->message;
+}
+
+/**
+ * Get the error level associated with the given diagnostic.
+ */
+pm_error_level_t
+pm_diagnostic_error_level(const pm_diagnostic_t *diagnostic) {
+ return (pm_error_level_t) pm_diagnostic_id_level(diagnostic->diag_id);
+}
+
+/**
+ * Get the warning level associated with the given diagnostic.
+ */
+pm_warning_level_t
+pm_diagnostic_warning_level(const pm_diagnostic_t *diagnostic) {
+ return (pm_warning_level_t) pm_diagnostic_id_level(diagnostic->diag_id);
+}
+
+/**
* 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;
+void
+pm_diagnostic_list_append(pm_arena_t *arena, pm_list_t *list, uint32_t start, uint32_t length, pm_diagnostic_id_t diag_id) {
+ pm_diagnostic_t *diagnostic = (pm_diagnostic_t *) pm_arena_zalloc(arena, sizeof(pm_diagnostic_t), PRISM_ALIGNOF(pm_diagnostic_t));
*diagnostic = (pm_diagnostic_t) {
- .location = { start, end },
+ .location = { .start = start, .length = length },
.diag_id = diag_id,
- .message = pm_diagnostic_message(diag_id),
- .owned = false,
- .level = pm_diagnostic_level(diag_id)
+ .message = pm_diagnostic_id_message(diag_id),
+ .level = pm_diagnostic_id_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, ...) {
+void
+pm_diagnostic_list_append_format(pm_arena_t *arena, pm_list_t *list, uint32_t start, uint32_t length, pm_diagnostic_id_t diag_id, ...) {
va_list arguments;
va_start(arguments, diag_id);
- const char *format = pm_diagnostic_message(diag_id);
+ const char *format = pm_diagnostic_id_message(diag_id);
int result = vsnprintf(NULL, 0, format, arguments);
va_end(arguments);
if (result < 0) {
- return false;
+ return;
}
- pm_diagnostic_t *diagnostic = (pm_diagnostic_t *) xcalloc(1, sizeof(pm_diagnostic_t));
- if (diagnostic == NULL) {
- return false;
- }
+ pm_diagnostic_t *diagnostic = (pm_diagnostic_t *) pm_arena_zalloc(arena, sizeof(pm_diagnostic_t), PRISM_ALIGNOF(pm_diagnostic_t));
- size_t length = (size_t) (result + 1);
- char *message = (char *) xmalloc(length);
- if (message == NULL) {
- xfree(diagnostic);
- return false;
- }
+ size_t message_length = (size_t) (result + 1);
+ char *message = (char *) pm_arena_alloc(arena, message_length, 1);
va_start(arguments, diag_id);
- vsnprintf(message, length, format, arguments);
+ vsnprintf(message, message_length, format, arguments);
va_end(arguments);
*diagnostic = (pm_diagnostic_t) {
- .location = { start, end },
+ .location = { .start = start, .length = length },
.diag_id = diag_id,
.message = message,
- .owned = true,
- .level = pm_diagnostic_level(diag_id)
+ .level = pm_diagnostic_id_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/json.c.erb b/prism/templates/src/json.c.erb
new file mode 100644
index 0000000000..5c4ab8d92a
--- /dev/null
+++ b/prism/templates/src/json.c.erb
@@ -0,0 +1,130 @@
+#include "prism/json.h"
+
+// Ensure this translation unit is never empty, even when JSON is excluded.
+typedef int pm_json_unused_t;
+
+#ifndef PRISM_EXCLUDE_JSON
+
+#include "prism/internal/buffer.h"
+#include "prism/internal/constant_pool.h"
+#include "prism/internal/integer.h"
+#include "prism/internal/parser.h"
+
+#include <inttypes.h>
+
+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_location_t *location) {
+ pm_buffer_append_format(buffer, "{\"start\":%" PRIu32 ",\"length\":%" PRIu32 "}", location->start, location->length);
+}
+
+/**
+ * Dump JSON to the given buffer.
+ */
+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, &cast->base.location);
+ <%- [*node.flags, *node.fields].each_with_index do |field, index| -%>
+
+ // Dump the <%= field.name %> field
+ pm_buffer_append_byte(buffer, ',');
+ <%- if field.is_a?(Prism::Template::Flags) -%>
+ pm_buffer_append_string(buffer, "\"flags\":", 8);
+ <%- else -%>
+ pm_buffer_append_string(buffer, "\"<%= field.name %>\":", <%= field.name.bytesize + 3 %>);
+ <%- end -%>
+ <%- 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, &cast-><%= field.name %>);
+ <%- when Prism::Template::OptionalLocationField -%>
+ if (cast-><%= field.name %>.length != 0) {
+ pm_dump_json_location(buffer, &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/node.c.erb b/prism/templates/src/node.c.erb
index 2357e55200..f51aff6e53 100644
--- a/prism/templates/src/node.c.erb
+++ b/prism/templates/src/node.c.erb
@@ -1,153 +1,85 @@
#line <%= __LINE__ + 1 %> "prism/templates/src/<%= File.basename(__FILE__) %>"
-#include "prism/node.h"
+#include "prism/internal/node.h"
+
+#include "prism/internal/arena.h"
+
+#include <stdlib.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.
+ * capacity in the list, this function does nothing. Otherwise it allocates a
+ * new array from the arena (abandon-and-copy strategy) and copies the existing
+ * data into it.
*/
-static bool
-pm_node_list_grow(pm_node_list_t *list, size_t size) {
+static void
+pm_node_list_grow(pm_arena_t *arena, 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;
+ // Guard against overflow on the addition.
+ if (requested_size < list->size) abort();
- // If the requested size is within the existing capacity, return true.
- if (requested_size < list->capacity) return true;
+ // If the requested size is within the existing capacity, return.
+ if (requested_size <= list->capacity) return;
- // Otherwise, reallocate the list to be twice as large as it was before.
+ // Otherwise, compute the next capacity by doubling.
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.
+ // Guard against overflow on the doubling.
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;
+ if (next_capacity == 0) abort();
+ next_capacity *= 2;
}
- pm_node_t **nodes = (pm_node_t **) xrealloc(list->nodes, sizeof(pm_node_t *) * next_capacity);
- if (nodes == NULL) return false;
+ // Allocate a new array from the arena (old array is abandoned).
+ pm_node_t **nodes = (pm_node_t **) pm_arena_alloc(arena, sizeof(pm_node_t *) * next_capacity, PRISM_ALIGNOF(pm_node_t *));
+
+ // Copy old data into the new array.
+ if (list->size > 0) {
+ memcpy(nodes, list->nodes, list->size * sizeof(pm_node_t *));
+ }
list->nodes = nodes;
list->capacity = next_capacity;
- return true;
}
/**
- * Append a new node onto the end of the node list.
+ * Slow path for pm_node_list_append: grow the list and append the node.
+ * Do not call directly - use pm_node_list_append instead.
*/
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;
- }
+pm_node_list_append_slow(pm_arena_t *arena, pm_node_list_t *list, pm_node_t *node) {
+ pm_node_list_grow(arena, 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++;
- }
+pm_node_list_prepend(pm_arena_t *arena, pm_node_list_t *list, pm_node_t *node) {
+ pm_node_list_grow(arena, 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)) {
+pm_node_list_concat(pm_arena_t *arena, pm_node_list_t *list, pm_node_list_t *other) {
+ if (other->size > 0) {
+ pm_node_list_grow(arena, 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)
+const char *
+pm_node_type(pm_node_type_t node_type)
{
switch (node_type) {
<%- nodes.each do |node| -%>
@@ -166,7 +98,7 @@ pm_node_type_to_str(pm_node_type_t node_type)
* pointer and is passed to the visitor callback for consumers to use as they
* see fit.
*/
-PRISM_EXPORTED_FUNCTION void
+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);
}
@@ -176,7 +108,7 @@ pm_visit_node(const pm_node_t *node, bool (*visitor)(const pm_node_t *node, void
* default behavior for walking the tree that is called from pm_visit_node if
* the callback returns true.
*/
-PRISM_EXPORTED_FUNCTION void
+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| -%>
@@ -212,122 +144,23 @@ pm_visit_child_nodes(const pm_node_t *node, bool (*visitor)(const pm_node_t *nod
break;
}
}
+<%- nodes.each do |node| -%>
-// 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);
-}
-
+<%- params = node.fields.map(&:c_param) -%>
/**
- * Dump JSON to the given buffer.
+ * Allocate and initialize a new <%= node.name %> node.
*/
-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_<%= node.human %>_t *
+pm_<%= node.human %>_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location<%= params.empty? ? "" : ", #{params.join(", ")}" %>) {
+ pm_<%= node.human %>_t *node = (pm_<%= node.human %>_t *) pm_arena_alloc(arena, sizeof(pm_<%= node.human %>_t), PRISM_ALIGNOF(pm_<%= node.human %>_t));
+
+ *node = (pm_<%= node.human %>_t) {
+ .base = { .type = <%= node.type %>, .flags = flags, .node_id = node_id, .location = location }<%= node.fields.empty? ? "" : "," %>
+<%- node.fields.each_with_index do |field, index| -%>
+ .<%= field.name %> = <%= field.name %><%= index < node.fields.size - 1 ? "," : "" %>
+<%- end -%>
+ };
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- <%- end -%>
- case PM_SCOPE_NODE:
- break;
- }
+ return node;
}
-
-#endif
+<%- end -%>
diff --git a/prism/templates/src/prettyprint.c.erb b/prism/templates/src/prettyprint.c.erb
index 639c2fecf3..f12531d934 100644
--- a/prism/templates/src/prettyprint.c.erb
+++ b/prism/templates/src/prettyprint.c.erb
@@ -1,23 +1,34 @@
<%# 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.
+/* 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) {}
+/* Ensure this translation unit is never empty, even when prettyprint is
+ * excluded. */
+typedef int pm_prettyprint_unused_t;
#else
-static inline void
+#include "prism/compiler/inline.h"
+#include "prism/internal/buffer.h"
+#include "prism/internal/constant_pool.h"
+#include "prism/internal/integer.h"
+#include "prism/internal/parser.h"
+#include "prism/line_offset_list.h"
+
+#include <inttypes.h>
+
+static PRISM_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_line_column_t start = pm_line_offset_list_line_column(&parser->line_offsets, location->start, parser->start_line);
+ pm_line_column_t end = pm_line_offset_list_line_column(&parser->line_offsets, location->start + location->length, parser->start_line);
pm_buffer_append_format(output_buffer, "(%" PRIi32 ",%" PRIu32 ")-(%" PRIi32 ",%" PRIu32 ")", start.line, start.column, end.line, end.column);
}
-static inline void
+static PRISM_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);
@@ -106,17 +117,17 @@ prettyprint_node(pm_buffer_t *output_buffer, const pm_parser_t *parser, const pm
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_source(output_buffer, parser->start + location->start, (size_t) location->length, 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) {
+ if (location->length == 0) {
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_source(output_buffer, parser->start + location->start, (size_t) location->length, PM_BUFFER_ESCAPING_RUBY);
pm_buffer_append_string(output_buffer, "\"\n", 2);
}
<%- when Prism::Template::UInt8Field -%>
@@ -156,11 +167,11 @@ prettyprint_node(pm_buffer_t *output_buffer, const pm_parser_t *parser, const pm
/**
* Pretty-prints the AST represented by the given node to the given buffer.
*/
-PRISM_EXPORTED_FUNCTION void
+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);
+ pm_buffer_cleanup(&prefix_buffer);
}
#endif
diff --git a/prism/templates/src/serialize.c.erb b/prism/templates/src/serialize.c.erb
index 3e15a11039..3d9811e5db 100644
--- a/prism/templates/src/serialize.c.erb
+++ b/prism/templates/src/serialize.c.erb
@@ -1,57 +1,58 @@
-#include "prism.h"
+#include "prism/excludes.h"
+
+/* We optionally support serializing to a binary string. For systems that do not
+ * want or need this functionality, it can be turned off with the
+ * PRISM_EXCLUDE_SERIALIZATION define. */
+#ifdef PRISM_EXCLUDE_SERIALIZATION
+
+/* Ensure this translation unit is never empty, even when serialization is
+ * excluded. */
+typedef int pm_serialize_unused_t;
+
+#else
+
+#include "prism/compiler/inline.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 "prism/internal/buffer.h"
+#include "prism/internal/comments.h"
+#include "prism/internal/diagnostic.h"
+#include "prism/internal/encoding.h"
+#include "prism/internal/list.h"
+#include "prism/internal/magic_comments.h"
+#include "prism/internal/options.h"
+#include "prism/internal/parser.h"
+#include "prism.h"
+#include "prism/ast.h"
+#include "prism/line_offset_list.h"
+
+#include <assert.h>
#include <stdio.h>
+#include <string.h>
-static inline uint32_t
+static PRISM_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
+static PRISM_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));
+pm_serialize_location(const pm_location_t *location, pm_buffer_t *buffer) {
+ pm_buffer_append_varuint(buffer, location->start);
+ pm_buffer_append_varuint(buffer, location->length);
}
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
- }
+pm_serialize_string(const pm_string_t *string, pm_buffer_t *buffer) {
+ uint32_t length = pm_sizet_to_u32(pm_string_length(string));
+ pm_buffer_append_varuint(buffer, length);
+ pm_buffer_append_bytes(buffer, pm_string_source(string), length);
}
static void
@@ -72,12 +73,10 @@ 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;
-
<%- if Prism::Template::INCLUDE_NODE_ID -%>
pm_buffer_append_varuint(buffer, node->node_id);
<%- end -%>
- pm_serialize_location(parser, &node->location, buffer);
+ pm_serialize_location(&node->location, buffer);
switch (PM_NODE_TYPE(node)) {
// We do not need to serialize a ScopeNode ever as
@@ -106,7 +105,7 @@ pm_serialize_node(pm_parser_t *parser, pm_node_t *node, pm_buffer_t *buffer) {
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);
+ pm_serialize_string(&((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);
@@ -123,15 +122,15 @@ pm_serialize_node(pm_parser_t *parser, pm_node_t *node, pm_buffer_t *buffer) {
}
<%- when Prism::Template::LocationField -%>
<%- if field.should_be_serialized? -%>
- pm_serialize_location(parser, &((pm_<%= node.human %>_t *)node)-><%= field.name %>, buffer);
+ pm_serialize_location(&((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) {
+ if (((pm_<%= node.human %>_t *)node)-><%= field.name %>.length == 0) {
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);
+ pm_serialize_location(&((pm_<%= node.human %>_t *)node)-><%= field.name %>, buffer);
}
<%- end -%>
<%- when Prism::Template::UInt8Field -%>
@@ -148,7 +147,7 @@ pm_serialize_node(pm_parser_t *parser, pm_node_t *node, pm_buffer_t *buffer) {
<%- end -%>
<%- if node.needs_serialized_length? -%>
// serialize length
- uint32_t length = pm_sizet_to_u32(buffer->length - offset - sizeof(uint32_t));
+ uint32_t length = pm_sizet_to_u32(buffer->length - length_offset);
memcpy(buffer->value + length_offset, &length, sizeof(uint32_t));
<%- end -%>
break;
@@ -158,7 +157,7 @@ pm_serialize_node(pm_parser_t *parser, pm_node_t *node, pm_buffer_t *buffer) {
}
static void
-pm_serialize_newline_list(pm_newline_list_t *list, pm_buffer_t *buffer) {
+pm_serialize_line_offset_list(pm_line_offset_list_t *list, pm_buffer_t *buffer) {
uint32_t size = pm_sizet_to_u32(list->size);
pm_buffer_append_varuint(buffer, size);
@@ -169,60 +168,60 @@ pm_serialize_newline_list(pm_newline_list_t *list, pm_buffer_t *buffer) {
}
static void
-pm_serialize_comment(pm_parser_t *parser, pm_comment_t *comment, pm_buffer_t *buffer) {
+pm_serialize_comment(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);
+ pm_serialize_location(&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_serialize_comment_list(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);
+ pm_serialize_comment(comment, buffer);
}
}
static void
-pm_serialize_magic_comment(pm_parser_t *parser, pm_magic_comment_t *magic_comment, pm_buffer_t *buffer) {
+pm_serialize_magic_comment(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));
+ pm_buffer_append_varuint(buffer, magic_comment->key.start);
+ pm_buffer_append_varuint(buffer, 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));
+ pm_buffer_append_varuint(buffer, magic_comment->value.start);
+ pm_buffer_append_varuint(buffer, magic_comment->value.length);
}
static void
-pm_serialize_magic_comment_list(pm_parser_t *parser, pm_list_t *list, pm_buffer_t *buffer) {
+pm_serialize_magic_comment_list(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);
+ pm_serialize_magic_comment(magic_comment, buffer);
}
}
static void
pm_serialize_data_loc(const pm_parser_t *parser, pm_buffer_t *buffer) {
- if (parser->data_loc.end == NULL) {
+ if (parser->data_loc.length == 0) {
pm_buffer_append_byte(buffer, 0);
} else {
pm_buffer_append_byte(buffer, 1);
- pm_serialize_location(parser, &parser->data_loc, buffer);
+ pm_serialize_location(&parser->data_loc, buffer);
}
}
static void
-pm_serialize_diagnostic(pm_parser_t *parser, pm_diagnostic_t *diagnostic, pm_buffer_t *buffer) {
+pm_serialize_diagnostic(pm_diagnostic_t *diagnostic, pm_buffer_t *buffer) {
// serialize the type
pm_buffer_append_varuint(buffer, (uint32_t) diagnostic->diag_id);
@@ -232,18 +231,18 @@ pm_serialize_diagnostic(pm_parser_t *parser, pm_diagnostic_t *diagnostic, pm_buf
pm_buffer_append_string(buffer, diagnostic->message, message_length);
// serialize location
- pm_serialize_location(parser, &diagnostic->location, buffer);
+ pm_serialize_location(&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_serialize_diagnostic_list(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);
+ pm_serialize_diagnostic(diagnostic, buffer);
}
}
@@ -261,14 +260,15 @@ 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);
+ pm_serialize_line_offset_list(&parser->line_offsets, buffer);
<%- unless Prism::Template::SERIALIZE_ONLY_SEMANTICS_FIELDS -%>
- pm_serialize_comment_list(parser, &parser->comment_list, buffer);
+ pm_serialize_comment_list(&parser->comment_list, buffer);
<%- end -%>
- pm_serialize_magic_comment_list(parser, &parser->magic_comment_list, buffer);
+ pm_serialize_magic_comment_list(&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);
+ pm_serialize_diagnostic_list(&parser->error_list, buffer);
+ pm_serialize_diagnostic_list(&parser->warning_list, buffer);
+ pm_buffer_append_byte(buffer, (uint8_t) parser->continuable);
}
#line <%= __LINE__ + 1 %> "prism/templates/src/<%= File.basename(__FILE__) %>"
@@ -308,28 +308,12 @@ pm_serialize_content(pm_parser_t *parser, pm_node_t *node, pm_buffer_t *buffer)
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);
+ // Write the constant contents into the buffer after the constant
+ // pool. In place of the source offset, we store a buffer offset.
+ uint32_t content_offset = pm_sizet_to_u32(buffer->length);
+ memcpy(buffer->value + buffer_offset, &content_offset, 4);
+ pm_buffer_append_bytes(buffer, constant->start, constant->length);
- 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);
}
@@ -337,7 +321,7 @@ pm_serialize_content(pm_parser_t *parser, pm_node_t *node, pm_buffer_t *buffer)
}
static void
-serialize_token(void *data, pm_parser_t *parser, pm_token_t *token) {
+serialize_token(pm_parser_t *parser, pm_token_t *token, void *data) {
pm_buffer_t *buffer = (pm_buffer_t *) data;
pm_buffer_append_varuint(buffer, token->type);
@@ -349,58 +333,72 @@ serialize_token(void *data, pm_parser_t *parser, pm_token_t *token) {
/**
* Lex the given source and serialize to the given buffer.
*/
-PRISM_EXPORTED_FUNCTION void
+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_arena_t arena = { 0 };
pm_parser_t parser;
- pm_parser_init(&parser, source, size, &options);
+ pm_parser_init(&arena, &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_parser_lex_callback_set(&parser, serialize_token, buffer);
+ 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);
+ pm_parser_cleanup(&parser);
+ pm_arena_cleanup(&arena);
+ pm_options_cleanup(&options);
}
/**
* Parse and serialize both the AST and the tokens represented by the given
* source to the given buffer.
*/
-PRISM_EXPORTED_FUNCTION void
+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_arena_t arena = { 0 };
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,
- };
+ pm_parser_init(&arena, &parser, source, size, &options);
- parser.lex_callback = &lex_callback;
+ pm_parser_lex_callback_set(&parser, serialize_token, buffer);
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);
+ pm_parser_cleanup(&parser);
+ pm_arena_cleanup(&arena);
+ pm_options_cleanup(&options);
+}
+
+/**
+ * Parse the source and return true if it parses without errors or warnings.
+ */
+bool
+pm_serialize_parse_success_p(const uint8_t *source, size_t size, const char *data) {
+ pm_options_t options = { 0 };
+ pm_options_read(&options, data);
+
+ pm_arena_t arena = { 0 };
+ pm_parser_t parser;
+ pm_parser_init(&arena, &parser, source, size, &options);
+
+ pm_parse(&parser);
+
+ bool result = parser.error_list.size == 0;
+ pm_parser_cleanup(&parser);
+ pm_arena_cleanup(&arena);
+ pm_options_cleanup(&options);
+
+ return result;
}
#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/src/tokens.c.erb b/prism/templates/src/tokens.c.erb
new file mode 100644
index 0000000000..1e82954738
--- /dev/null
+++ b/prism/templates/src/tokens.c.erb
@@ -0,0 +1,367 @@
+#include "prism/ast.h"
+
+#include <assert.h>
+
+/**
+ * Returns a string representation of the given token type.
+ */
+const char *
+pm_token_type(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_str(pm_token_type_t token_type) {
+ switch (token_type) {
+ case PM_TOKEN_EOF:
+ return "end-of-input";
+ 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_BLOCK:
+ 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 cannot determine that the above
+ * switch is exhaustive. */
+ assert(false && "unreachable");
+ return "";
+}
diff --git a/prism/templates/template.rb b/prism/templates/template.rb
index 6c3efd7e6c..0fdeda561f 100755
--- a/prism/templates/template.rb
+++ b/prism/templates/template.rb
@@ -6,13 +6,12 @@ require "fileutils"
require "yaml"
module Prism
- module Template
+ module Template # :nodoc: all
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"
+ JAVA_BACKEND = ENV["PRISM_JAVA_BACKEND"] || "default"
+ JAVA_IDENTIFIER_TYPE = JAVA_BACKEND == "truffleruby" ? "String" : "byte[]"
INCLUDE_NODE_ID = !SERIALIZE_ONLY_SEMANTICS_FIELDS || JAVA_BACKEND == "jruby"
COMMON_FLAGS_COUNT = 2
@@ -49,6 +48,14 @@ module Prism
end
end
+ # This module contains methods for escaping characters in Doxygen comments.
+ module Doxygen
+ # Similar to /verbatim ... /endverbatim but doesn't wrap the result in a code block.
+ def self.verbatim(value)
+ value.gsub(/[*%!`#<>_+@-]/, '\\\\\0')
+ end
+ end
+
# A comment attached to a field or node.
class ConfigComment
attr_reader :value
@@ -97,6 +104,11 @@ module Prism
# Some node fields can be specialized if they point to a specific kind of
# node and not just a generic node.
class NodeKindField < Field
+ # The C type to use for this field as a function parameter.
+ def c_param
+ "struct #{c_type} *#{name}"
+ end
+
def initialize(kind:, **options)
@kind = kind
super(**options)
@@ -142,27 +154,27 @@ module Prism
if specific_kind
specific_kind
elsif union_kind
- union_kind.join(" | ")
+ "(#{union_kind.join(" | ")})"
else
"Prism::node"
end
end
- def rbi_class
+ def call_seq_type
if specific_kind
- "Prism::#{specific_kind}"
+ specific_kind
elsif union_kind
- "T.any(#{union_kind.map { |kind| "Prism::#{kind}" }.join(", ")})"
+ union_kind.join(" | ")
else
- "Prism::Node"
+ "Node"
end
end
def check_field_kind
if union_kind
- "[#{union_kind.join(', ')}].include?(#{name}.class)"
+ "[#{union_kind.join(', ')}, ErrorRecoveryNode].include?(#{name}.class)"
else
- "#{name}.is_a?(#{ruby_type})"
+ "#{name}.is_a?(#{ruby_type}) || #{name}.is_a?(ErrorRecoveryNode)"
end
end
end
@@ -174,27 +186,27 @@ module Prism
if specific_kind
"#{specific_kind}?"
elsif union_kind
- [*union_kind, "nil"].join(" | ")
+ "(#{union_kind.join(" | ")})?"
else
"Prism::node?"
end
end
- def rbi_class
+ def call_seq_type
if specific_kind
- "T.nilable(Prism::#{specific_kind})"
+ "#{specific_kind} | nil"
elsif union_kind
- "T.nilable(T.any(#{union_kind.map { |kind| "Prism::#{kind}" }.join(", ")}))"
+ [*union_kind, "nil"].join(" | ")
else
- "T.nilable(Prism::Node)"
+ "Node | nil"
end
end
def check_field_kind
if union_kind
- "[#{union_kind.join(', ')}, NilClass].include?(#{name}.class)"
+ "[#{union_kind.join(', ')}, ErrorRecoveryNode, NilClass].include?(#{name}.class)"
else
- "#{name}.nil? || #{name}.is_a?(#{ruby_type})"
+ "#{name}.nil? || #{name}.is_a?(#{ruby_type}) || #{name}.is_a?(ErrorRecoveryNode)"
end
end
end
@@ -202,23 +214,31 @@ module Prism
# 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
+ def c_param
+ "pm_node_list_t #{name}"
+ end
+
+ def element_rbs_class
if specific_kind
- "Array[#{specific_kind}]"
+ "#{specific_kind}"
elsif union_kind
- "Array[#{union_kind.join(" | ")}]"
+ "#{union_kind.join(" | ")}"
else
- "Array[Prism::node]"
+ "Prism::node"
end
end
- def rbi_class
+ def rbs_class
+ "Array[#{element_rbs_class}]"
+ end
+
+ def call_seq_type
if specific_kind
- "T::Array[Prism::#{specific_kind}]"
+ "Array[#{specific_kind}]"
elsif union_kind
- "T::Array[T.any(#{union_kind.map { |kind| "Prism::#{kind}" }.join(", ")})]"
+ "Array[#{union_kind.join(" | ")}]"
else
- "T::Array[Prism::Node]"
+ "Array[Node]"
end
end
@@ -228,9 +248,9 @@ module Prism
def check_field_kind
if union_kind
- "#{name}.all? { |n| [#{union_kind.join(', ')}].include?(n.class) }"
+ "#{name}.all? { |n| [#{union_kind.join(', ')}, ErrorRecoveryNode].include?(n.class) }"
else
- "#{name}.all? { |n| n.is_a?(#{ruby_type}) }"
+ "#{name}.all? { |n| n.is_a?(#{ruby_type}) || n.is_a?(ErrorRecoveryNode) }"
end
end
end
@@ -238,58 +258,74 @@ module Prism
# 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 c_param
+ "pm_constant_id_t #{name}"
+ end
+
def rbs_class
"Symbol"
end
- def rbi_class
+ def call_seq_type
"Symbol"
end
def java_type
- JAVA_STRING_TYPE
+ JAVA_IDENTIFIER_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 c_param
+ "pm_constant_id_t #{name}"
+ end
+
def rbs_class
"Symbol?"
end
- def rbi_class
- "T.nilable(Symbol)"
+ def call_seq_type
+ "Symbol | nil"
end
def java_type
- JAVA_STRING_TYPE
+ JAVA_IDENTIFIER_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 c_param
+ "pm_constant_id_list_t #{name}"
+ end
+
def rbs_class
"Array[Symbol]"
end
- def rbi_class
- "T::Array[Symbol]"
+ def call_seq_type
+ "Array[Symbol]"
end
def java_type
- "#{JAVA_STRING_TYPE}[]"
+ "#{JAVA_IDENTIFIER_TYPE}[]"
end
end
# This represents a field on a node that is a string.
class StringField < Field
+ def c_param
+ "pm_string_t #{name}"
+ end
+
def rbs_class
"String"
end
- def rbi_class
+ def call_seq_type
"String"
end
@@ -300,6 +336,10 @@ module Prism
# This represents a field on a node that is a location.
class LocationField < Field
+ def c_param
+ "pm_location_t #{name}"
+ end
+
def semantic_field?
false
end
@@ -308,8 +348,8 @@ module Prism
"Location"
end
- def rbi_class
- "Prism::Location"
+ def call_seq_type
+ "Location"
end
def java_type
@@ -319,6 +359,10 @@ module Prism
# This represents a field on a node that is a location that is optional.
class OptionalLocationField < Field
+ def c_param
+ "pm_location_t #{name}"
+ end
+
def semantic_field?
false
end
@@ -327,8 +371,8 @@ module Prism
"Location?"
end
- def rbi_class
- "T.nilable(Prism::Location)"
+ def call_seq_type
+ "Location | nil"
end
def java_type
@@ -338,11 +382,15 @@ module Prism
# This represents an integer field.
class UInt8Field < Field
+ def c_param
+ "uint8_t #{name}"
+ end
+
def rbs_class
"Integer"
end
- def rbi_class
+ def call_seq_type
"Integer"
end
@@ -353,11 +401,15 @@ module Prism
# This represents an integer field.
class UInt32Field < Field
+ def c_param
+ "uint32_t #{name}"
+ end
+
def rbs_class
"Integer"
end
- def rbi_class
+ def call_seq_type
"Integer"
end
@@ -369,11 +421,15 @@ module Prism
# This represents an arbitrarily-sized integer. When it gets to Ruby it will
# be an Integer.
class IntegerField < Field
+ def c_param
+ "pm_integer_t #{name}"
+ end
+
def rbs_class
"Integer"
end
- def rbi_class
+ def call_seq_type
"Integer"
end
@@ -385,11 +441,15 @@ module Prism
# This represents a double-precision floating point number. When it gets to
# Ruby it will be a Float.
class DoubleField < Field
+ def c_param
+ "double #{name}"
+ end
+
def rbs_class
"Float"
end
- def rbi_class
+ def call_seq_type
"Float"
end
@@ -432,9 +492,6 @@ module Prism
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
@@ -547,8 +604,7 @@ module Prism
extension = File.extname(filepath.gsub(".erb", ""))
heading =
- case extension
- when ".rb"
+ if extension == ".rb"
<<~HEADING
# frozen_string_literal: true
# :markup: markdown
@@ -562,28 +618,8 @@ module Prism
=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
- /* :markup: markdown */
-
/*----------------------------------------------------------------------------*/
/* This file is generated by the templates/template.rb script and should not */
/* be modified manually. See */
@@ -607,8 +643,14 @@ module Prism
end
end
- FileUtils.mkdir_p(File.dirname(write_to))
- File.write(write_to, contents)
+ begin
+ FileUtils.mkdir_p(File.dirname(write_to))
+ File.write(write_to, contents)
+ rescue SystemCallError # EACCES, EPERM, EROFS, etc.
+ # Fall back to the current directory
+ FileUtils.mkdir_p(File.dirname(name))
+ File.write(name, contents)
+ end
end
private
@@ -644,13 +686,13 @@ module Prism
TEMPLATES = [
"ext/prism/api_node.c",
"include/prism/ast.h",
- "include/prism/diagnostic.h",
+ "include/prism/internal/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",
+ "java/api/src/main/java-templates/org/ruby_lang/prism/Loader.java",
+ "java/api/src/main/java-templates/org/ruby_lang/prism/Nodes.java",
+ "java/api/src/main/java-templates/org/ruby_lang/prism/AbstractNodeVisitor.java",
"lib/prism/compiler.rb",
"lib/prism/dispatcher.rb",
"lib/prism/dot_visitor.rb",
@@ -662,19 +704,11 @@ module Prism
"lib/prism/serialize.rb",
"lib/prism/visitor.rb",
"src/diagnostic.c",
+ "src/json.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"
+ "src/tokens.c"
]
end
end
diff --git a/prism/util/pm_buffer.c b/prism/util/pm_buffer.c
deleted file mode 100644
index 2136a7c43e..0000000000
--- a/prism/util/pm_buffer.c
+++ /dev/null
@@ -1,357 +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 unicode codepoint to the buffer.
- */
-bool
-pm_buffer_append_unicode_codepoint(pm_buffer_t *buffer, uint32_t value) {
- if (value <= 0x7F) {
- pm_buffer_append_byte(buffer, (uint8_t) value); // 0xxxxxxx
- return true;
- } else if (value <= 0x7FF) {
- uint8_t bytes[] = {
- (uint8_t) (0xC0 | ((value >> 6) & 0x3F)), // 110xxxxx
- (uint8_t) (0x80 | (value & 0x3F)) // 10xxxxxx
- };
-
- pm_buffer_append_bytes(buffer, bytes, 2);
- return true;
- } else if (value <= 0xFFFF) {
- uint8_t bytes[] = {
- (uint8_t) (0xE0 | ((value >> 12) & 0x3F)), // 1110xxxx
- (uint8_t) (0x80 | ((value >> 6) & 0x3F)), // 10xxxxxx
- (uint8_t) (0x80 | (value & 0x3F)) // 10xxxxxx
- };
-
- pm_buffer_append_bytes(buffer, bytes, 3);
- return true;
- } else if (value <= 0x10FFFF) {
- uint8_t bytes[] = {
- (uint8_t) (0xF0 | ((value >> 18) & 0x3F)), // 11110xxx
- (uint8_t) (0x80 | ((value >> 12) & 0x3F)), // 10xxxxxx
- (uint8_t) (0x80 | ((value >> 6) & 0x3F)), // 10xxxxxx
- (uint8_t) (0x80 | (value & 0x3F)) // 10xxxxxx
- };
-
- pm_buffer_append_bytes(buffer, bytes, 4);
- return true;
- } else {
- return false;
- }
-}
-
-/**
- * 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 f3c20ab2a5..0000000000
--- a/prism/util/pm_buffer.h
+++ /dev/null
@@ -1,228 +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);
-
-/**
- * Append a unicode codepoint to the buffer.
- *
- * @param buffer The buffer to append to.
- * @param value The character to append.
- * @returns True if the codepoint was valid and appended successfully, false
- * otherwise.
- */
-bool pm_buffer_append_unicode_codepoint(pm_buffer_t *buffer, uint32_t 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 a51dc11645..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 (size > 0 && 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 38ea01a228..0000000000
--- a/prism/util/pm_constant_pool.c
+++ /dev/null
@@ -1,342 +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) {
- if (capacity) {
- list->ids = xcalloc(capacity, sizeof(pm_constant_id_t));
- if (list->ids == NULL) abort();
- } else {
- list->ids = NULL;
- }
-
- 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 75422fbdf2..0000000000
--- a/prism/util/pm_string.c
+++ /dev/null
@@ -1,383 +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) {
- close(fd);
- 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 3f58421554..0000000000
--- a/prism/util/pm_strncasecmp.c
+++ /dev/null
@@ -1,36 +0,0 @@
-#include "prism/util/pm_strncasecmp.h"
-
-/**
- * A locale-insensitive version of `tolower(3)`
- */
-static inline int
-pm_tolower(int c)
-{
- if ('A' <= c && c <= 'Z') {
- return c | 0x20;
- }
- return c;
-}
-
-/**
- * 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 = pm_tolower(string1[offset]) - pm_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
index 0a2a8c8fce..181b398462 100644
--- a/prism/version.h
+++ b/prism/version.h
@@ -6,6 +6,8 @@
#ifndef PRISM_VERSION_H
#define PRISM_VERSION_H
+#include "prism/compiler/exported.h"
+
/**
* The major version of the Prism library as an int.
*/
@@ -14,7 +16,7 @@
/**
* The minor version of the Prism library as an int.
*/
-#define PRISM_VERSION_MINOR 4
+#define PRISM_VERSION_MINOR 9
/**
* The patch version of the Prism library as an int.
@@ -24,6 +26,13 @@
/**
* The version of the Prism library as a constant string.
*/
-#define PRISM_VERSION "1.4.0"
+#define PRISM_VERSION "1.9.0"
+
+/**
+ * The prism version and the serialization format.
+ *
+ * @returns The prism version as a constant string.
+ */
+PRISM_EXPORTED_FUNCTION const char * pm_version(void);
#endif
diff --git a/prism_compile.c b/prism_compile.c
index 2f5bb4ebe3..45e1de8a9c 100644
--- a/prism_compile.c
+++ b/prism_compile.c
@@ -1,4 +1,7 @@
#include "prism.h"
+#include "ruby/version.h"
+
+#include <fcntl.h>
/**
* This compiler defines its own concept of the location of a node. We do this
@@ -101,6 +104,7 @@ pm_iseq_add_setlocal(rb_iseq_t *iseq, LINK_ANCHOR *const seq, int line, int node
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)));
}
+ update_lvar_state(iseq, level, idx);
if (level > 0) access_outer_variables(iseq, level, iseq_lvar_id(iseq, idx, level), Qtrue);
}
@@ -138,33 +142,127 @@ pm_iseq_add_setlocal(rb_iseq_t *iseq, LINK_ANCHOR *const seq, int line, int node
#define PM_COMPILE_NOT_POPPED(node) \
pm_compile_node(iseq, (node), ret, false, scope_node)
-#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 })
+// Direct-indexed lookup table. -1 means "not present".
+#define PM_INDEX_LOOKUP_TABLE_INIT { .values = NULL, .capacity = 0, .owned = false }
-#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 })
+static inline void
+pm_index_lookup_table_init(pm_index_lookup_table_t *table, int constants_size, rb_iseq_t *iseq)
+{
+ int capacity = constants_size + PM_INDEX_LOOKUP_SPECIALS;
+ table->values = compile_data_alloc2_type(iseq, int, capacity);
+ memset(table->values, -1, capacity * sizeof(int));
+ table->capacity = capacity;
+ table->owned = false;
+}
-#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 })
+/**
+ * Cached line lookup that avoids repeated binary searches. Since the compiler
+ * walks the AST roughly in source order, consecutive lookups tend to be for
+ * nearby byte offsets. We cache the last result index in the scope node and
+ * try a short linear probe from there before falling back to binary search.
+ */
+static inline pm_line_column_t
+pm_line_offset_list_line_column_cached(const pm_line_offset_list_t *list, uint32_t cursor, int32_t start_line, size_t *last_line)
+{
+ size_t hint = *last_line;
+ size_t size = list->size;
+ const uint32_t *offsets = list->offsets;
-#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)
+ RUBY_ASSERT(hint < size);
-#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)
+ /* Check if the cursor is on the same line as the hint. */
+ if (offsets[hint] <= cursor) {
+ if (hint + 1 >= size || offsets[hint + 1] > cursor) {
+ *last_line = hint;
+ return ((pm_line_column_t) {
+ .line = ((int32_t) hint) + start_line,
+ .column = cursor - offsets[hint]
+ });
+ }
-#define PM_LOCATION_START_LINE_COLUMN(parser, location) \
- pm_newline_list_line_column(&(parser)->newline_list, (location)->start, (parser)->start_line)
+ /* Linear scan forward (up to 8 lines before giving up). */
+ size_t limit = hint + 9;
+ if (limit > size) limit = size;
+ for (size_t idx = hint + 1; idx < limit; idx++) {
+ if (offsets[idx] > cursor) {
+ *last_line = idx - 1;
+ return ((pm_line_column_t) {
+ .line = ((int32_t) (idx - 1)) + start_line,
+ .column = cursor - offsets[idx - 1]
+ });
+ }
+ if (offsets[idx] == cursor) {
+ *last_line = idx;
+ return ((pm_line_column_t) { ((int32_t) idx) + start_line, 0 });
+ }
+ }
+ }
+ else {
+ /* Linear scan backward (up to 8 lines before giving up). */
+ size_t limit = hint > 8 ? hint - 8 : 0;
+ for (size_t idx = hint; idx > limit; idx--) {
+ if (offsets[idx - 1] <= cursor) {
+ *last_line = idx - 1;
+ return ((pm_line_column_t) {
+ .line = ((int32_t) (idx - 1)) + start_line,
+ .column = cursor - offsets[idx - 1]
+ });
+ }
+ }
+ }
-static int
-pm_node_line_number(const pm_parser_t *parser, const pm_node_t *node)
+ /* Fall back to binary search. */
+ pm_line_column_t result = pm_line_offset_list_line_column(list, cursor, start_line);
+ *last_line = (size_t) (result.line - start_line);
+ return result;
+}
+
+/**
+ * The same as pm_line_offset_list_line_column_cached, but returning only the
+ * line number.
+ */
+static inline int32_t
+pm_line_offset_list_line_cached(const pm_line_offset_list_t *list, uint32_t cursor, int32_t start_line, size_t *last_line)
{
- return (int) pm_newline_list_line(&parser->newline_list, node->location.start, parser->start_line);
+ return pm_line_offset_list_line_column_cached(list, cursor, start_line, last_line).line;
}
+#define PM_NODE_START_LOCATION(node) \
+ ((pm_node_location_t) { .line = pm_line_offset_list_line_cached(scope_node->line_offsets, ((const pm_node_t *) (node))->location.start, scope_node->start_line, &scope_node->last_line), .node_id = ((const pm_node_t *) (node))->node_id })
+
+#define PM_NODE_END_LOCATION(node) \
+ ((pm_node_location_t) { .line = pm_line_offset_list_line_cached(scope_node->line_offsets, ((const pm_node_t *) (node))->location.start + ((const pm_node_t *) (node))->location.length, scope_node->start_line, &scope_node->last_line), .node_id = ((const pm_node_t *) (node))->node_id })
+
+#define PM_LOCATION_START_LOCATION(location, id) \
+ ((pm_node_location_t) { .line = pm_line_offset_list_line_cached(scope_node->line_offsets, (location)->start, scope_node->start_line, &scope_node->last_line), .node_id = id })
+
+#define PM_NODE_START_LINE_COLUMN(node) \
+ pm_line_offset_list_line_column_cached(scope_node->line_offsets, ((const pm_node_t *) (node))->location.start, scope_node->start_line, &scope_node->last_line)
+
+#define PM_NODE_END_LINE_COLUMN(node) \
+ pm_line_offset_list_line_column_cached(scope_node->line_offsets, ((const pm_node_t *) (node))->location.start + ((const pm_node_t *) (node))->location.length, scope_node->start_line, &scope_node->last_line)
+
+#define PM_LOCATION_START_LINE_COLUMN(location) \
+ pm_line_offset_list_line_column_cached(scope_node->line_offsets, (location)->start, scope_node->start_line, &scope_node->last_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);
+ return (int) pm_line_offset_list_line_column(pm_parser_line_offsets(parser), location->start, pm_parser_start_line(parser)).line;
+}
+
+/**
+ * Cached variants that use the scope node's hint for fast lookups during
+ * compilation (where access patterns are roughly sequential).
+ */
+static inline int
+pm_node_line_number_cached(const pm_node_t *node, pm_scope_node_t *scope_node)
+{
+ return (int) pm_line_offset_list_line_cached(scope_node->line_offsets, node->location.start, scope_node->start_line, &scope_node->last_line);
+}
+
+static inline int
+pm_location_line_number_cached(const pm_location_t *location, pm_scope_node_t *scope_node) {
+ return (int) pm_line_offset_list_line_cached(scope_node->line_offsets, location->start, scope_node->start_line, &scope_node->last_line);
}
/**
@@ -179,24 +277,25 @@ parse_integer_value(const pm_integer_t *integer)
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));
+ // The pm_integer_t stores values as an array of uint32_t in
+ // least-significant-word-first order (base 2^32). We can convert
+ // directly to a Ruby Integer using rb_integer_unpack, avoiding the
+ // overhead of constructing a hex string and calling rb_funcall.
+ result = rb_integer_unpack(
+ integer->values,
+ integer->length,
+ sizeof(uint32_t),
+ 0,
+ INTEGER_PACK_LSWORD_FIRST | INTEGER_PACK_NATIVE_BYTE_ORDER
+ );
}
if (integer->negative) {
- result = rb_funcall(result, rb_intern("-@"), 0);
+ result = rb_int_uminus(result);
+ }
+
+ if (!SPECIAL_CONST_P(result)) {
+ RB_OBJ_SET_SHAREABLE(result); // bignum
}
return result;
@@ -217,7 +316,11 @@ parse_integer(const pm_integer_node_t *node)
static VALUE
parse_float(const pm_float_node_t *node)
{
- return DBL2NUM(node->value);
+ VALUE val = DBL2NUM(node->value);
+ if (!FLONUM_P(val)) {
+ RB_OBJ_SET_SHAREABLE(val);
+ }
+ return val;
}
/**
@@ -231,7 +334,8 @@ 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);
+
+ return rb_ractor_make_shareable(rb_rational_new(numerator, denominator));
}
/**
@@ -258,10 +362,10 @@ parse_imaginary(const pm_imaginary_node_t *node)
break;
}
default:
- rb_bug("Unexpected numeric type on imaginary number %s\n", pm_node_type_to_str(PM_NODE_TYPE(node->numeric)));
+ rb_bug("Unexpected numeric type on imaginary number %s\n", pm_node_type(PM_NODE_TYPE(node->numeric)));
}
- return rb_complex_raw(INT2FIX(0), imaginary_part);
+ return RB_OBJ_SET_SHAREABLE(rb_complex_raw(INT2FIX(0), imaginary_part));
}
static inline VALUE
@@ -294,7 +398,7 @@ parse_string_encoded(const pm_node_t *node, const pm_string_t *string, rb_encodi
}
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)
+parse_static_literal_string(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_node_t *node, const pm_string_t *string)
{
rb_encoding *encoding;
@@ -312,8 +416,8 @@ parse_static_literal_string(rb_iseq_t *iseq, const pm_scope_node_t *scope_node,
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 = rb_str_with_debug_created_info(value, rb_iseq_path(iseq), line_number);
+ int line_number = pm_node_line_number_cached(node, scope_node);
+ value = rb_ractor_make_shareable(rb_str_with_debug_created_info(value, rb_iseq_path(iseq), line_number));
}
return value;
@@ -357,7 +461,7 @@ parse_regexp_error(rb_iseq_t *iseq, int32_t line_number, const char *fmt, ...)
}
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)
+parse_regexp_string_part(rb_iseq_t *iseq, 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.
@@ -379,12 +483,12 @@ parse_regexp_string_part(rb_iseq_t *iseq, const pm_scope_node_t *scope_node, con
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));
+ if (error != Qnil) parse_regexp_error(iseq, pm_node_line_number_cached(node, scope_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)
+pm_static_literal_concat(rb_iseq_t *iseq, const pm_node_list_t *nodes, pm_scope_node_t *scope_node, rb_encoding *implicit_regexp_encoding, rb_encoding *explicit_regexp_encoding, bool top)
{
VALUE current = Qnil;
@@ -401,7 +505,7 @@ pm_static_literal_concat(rb_iseq_t *iseq, const pm_node_list_t *nodes, const pm_
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));
+ if (error != Qnil) parse_regexp_error(iseq, pm_node_line_number_cached(part, scope_node), "%" PRIsVALUE, rb_obj_as_string(error));
}
}
else {
@@ -514,12 +618,12 @@ parse_regexp_encoding(const pm_scope_node_t *scope_node, const pm_node_t *node)
}
static VALUE
-parse_regexp(rb_iseq_t *iseq, const pm_scope_node_t *scope_node, const pm_node_t *node, VALUE string)
+parse_regexp(rb_iseq_t *iseq, 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);
+ int32_t line_number = pm_node_line_number_cached(node, scope_node);
+ VALUE regexp = rb_reg_compile(string, parse_regexp_flags(node), (const char *) pm_string_source(pm_parser_filepath(scope_node->parser)), line_number);
if (NIL_P(regexp)) {
VALUE message = rb_attr_get(rb_errinfo(), idMesg);
@@ -529,22 +633,22 @@ parse_regexp(rb_iseq_t *iseq, const pm_scope_node_t *scope_node, const pm_node_t
return Qnil;
}
- rb_obj_freeze(regexp);
- return regexp;
+ return RB_OBJ_SET_SHAREABLE(rb_obj_freeze(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)
+parse_regexp_literal(rb_iseq_t *iseq, 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);
+ RB_OBJ_SET_SHAREABLE(string);
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)
+parse_regexp_concat(rb_iseq_t *iseq, 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;
@@ -556,7 +660,7 @@ parse_regexp_concat(rb_iseq_t *iseq, const pm_scope_node_t *scope_node, const pm
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, bool mutable_result)
+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, bool mutable_result, bool frozen_result)
{
int stack_size = 0;
size_t parts_size = parts->size;
@@ -585,7 +689,7 @@ pm_interpolated_node_compile(rb_iseq_t *iseq, const pm_node_list_t *parts, const
}
else {
current_string = string_value;
- if (index != 0) current_location = PM_NODE_END_LOCATION(scope_node->parser, part);
+ if (index != 0) current_location = PM_NODE_END_LOCATION(part);
}
}
else {
@@ -612,7 +716,7 @@ pm_interpolated_node_compile(rb_iseq_t *iseq, const pm_node_list_t *parts, const
}
else {
current_string = string_value;
- current_location = PM_NODE_START_LOCATION(scope_node->parser, part);
+ current_location = PM_NODE_START_LOCATION(part);
}
}
else {
@@ -623,7 +727,7 @@ pm_interpolated_node_compile(rb_iseq_t *iseq, const pm_node_list_t *parts, const
if (explicit_regexp_encoding != NULL) {
encoding = explicit_regexp_encoding;
}
- else if (scope_node->parser->encoding == PM_ENCODING_US_ASCII_ENTRY) {
+ else if (pm_parser_encoding_us_ascii(scope_node->parser)) {
encoding = rb_ascii8bit_encoding();
}
else {
@@ -647,7 +751,7 @@ pm_interpolated_node_compile(rb_iseq_t *iseq, const pm_node_list_t *parts, const
PM_COMPILE_NOT_POPPED(part);
- const pm_node_location_t current_location = PM_NODE_START_LOCATION(scope_node->parser, part);
+ const pm_node_location_t current_location = PM_NODE_START_LOCATION(part);
PUSH_INSN(ret, current_location, dup);
{
@@ -666,10 +770,15 @@ pm_interpolated_node_compile(rb_iseq_t *iseq, const pm_node_list_t *parts, const
if (RTEST(current_string)) {
current_string = rb_fstring(current_string);
- if (stack_size == 0 && (interpolated || mutable_result)) {
- PUSH_INSN1(ret, current_location, putstring, current_string);
- }
- else {
+ if (stack_size == 0) {
+ if (frozen_result) {
+ PUSH_INSN1(ret, current_location, putobject, current_string);
+ } else if (mutable_result || interpolated) {
+ PUSH_INSN1(ret, current_location, dupstring, current_string);
+ } else {
+ PUSH_INSN1(ret, current_location, dupchilledstring, current_string);
+ }
+ } else {
PUSH_INSN1(ret, current_location, putobject, current_string);
}
@@ -690,7 +799,7 @@ pm_compile_regexp_dynamic(rb_iseq_t *iseq, const pm_node_t *node, const pm_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, false);
+ int length = pm_interpolated_node_compile(iseq, parts, node_location, ret, popped, scope_node, implicit_regexp_encoding, explicit_regexp_encoding, false, false);
PUSH_INSN2(ret, *node_location, toregexp, INT2FIX(parse_regexp_flags(node) & 0xFF), INT2FIX(length));
}
@@ -717,7 +826,9 @@ 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)) {
- return rb_str_with_debug_created_info(string, rb_iseq_path(iseq), line_number);
+ VALUE str = rb_str_with_debug_created_info(string, rb_iseq_path(iseq), line_number);
+ RB_OBJ_SET_SHAREABLE(str);
+ return str;
}
else {
return rb_fstring(string);
@@ -730,7 +841,7 @@ pm_static_literal_string(rb_iseq_t *iseq, VALUE string, int line_number)
* 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)
+pm_static_literal_value(rb_iseq_t *iseq, const pm_node_t *node, 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.
@@ -746,7 +857,7 @@ pm_static_literal_value(rb_iseq_t *iseq, const pm_node_t *node, const pm_scope_n
rb_ary_push(value, pm_static_literal_value(iseq, elements->nodes[index], scope_node));
}
- OBJ_FREEZE(value);
+ RB_OBJ_SET_FROZEN_SHAREABLE(value);
return value;
}
case PM_FALSE_NODE:
@@ -765,11 +876,11 @@ pm_static_literal_value(rb_iseq_t *iseq, const pm_node_t *node, const pm_scope_n
rb_ary_cat(array, pair, 2);
}
- VALUE value = rb_hash_new_with_size(elements->size);
+ VALUE value = rb_hash_alloc_fixed_size(Qfalse, elements->size);
rb_hash_bulk_insert(RARRAY_LEN(array), RARRAY_CONST_PTR(array), value);
+ RB_GC_GUARD(array);
- value = rb_obj_hide(value);
- OBJ_FREEZE(value);
+ RB_OBJ_SET_FROZEN_SHAREABLE(value);
return value;
}
case PM_IMAGINARY_NODE:
@@ -786,7 +897,7 @@ pm_static_literal_value(rb_iseq_t *iseq, const pm_node_t *node, const pm_scope_n
}
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);
+ int line_number = pm_node_line_number_cached(node, scope_node);
return pm_static_literal_string(iseq, string, line_number);
}
case PM_INTERPOLATED_SYMBOL_NODE: {
@@ -814,7 +925,7 @@ pm_static_literal_value(rb_iseq_t *iseq, const pm_node_t *node, const pm_scope_n
return pm_source_file_value(cast, scope_node);
}
case PM_SOURCE_LINE_NODE:
- return INT2FIX(pm_node_line_number(scope_node->parser, node));
+ return INT2FIX(pm_node_line_number_cached(node, scope_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);
@@ -824,7 +935,7 @@ pm_static_literal_value(rb_iseq_t *iseq, const pm_node_t *node, const pm_scope_n
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)));
+ rb_bug("Don't have a literal value for node type %s", pm_node_type(PM_NODE_TYPE(node)));
return Qfalse;
}
}
@@ -833,10 +944,10 @@ pm_static_literal_value(rb_iseq_t *iseq, const pm_node_t *node, const pm_scope_n
* 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)
+pm_code_location(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);
+ const pm_line_column_t start_location = PM_NODE_START_LINE_COLUMN(node);
+ const pm_line_column_t end_location = PM_NODE_END_LINE_COLUMN(node);
return (rb_code_location_t) {
.beg_pos = { .lineno = start_location.line, .column = start_location.column },
@@ -853,12 +964,12 @@ pm_code_location(const pm_scope_node_t *scope_node, const pm_node_t *node)
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);
+ LABEL *then_label, LABEL *else_label, 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)
+pm_compile_logical(rb_iseq_t *iseq, LINK_ANCHOR *const ret, pm_node_t *cond, LABEL *then_label, LABEL *else_label, pm_scope_node_t *scope_node)
{
- const pm_node_location_t location = PM_NODE_START_LOCATION(scope_node->parser, cond);
+ const pm_node_location_t location = PM_NODE_START_LOCATION(cond);
DECL_ANCHOR(seq);
@@ -866,17 +977,14 @@ pm_compile_logical(rb_iseq_t *iseq, LINK_ANCHOR *const ret, pm_node_t *cond, LAB
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);
+ pm_compile_branch_condition(iseq, seq, cond, then_label, else_label, 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 {
+ if (label->refcnt) {
PUSH_LABEL(seq, label);
}
@@ -887,7 +995,7 @@ pm_compile_logical(rb_iseq_t *iseq, LINK_ANCHOR *const ret, pm_node_t *cond, LAB
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 = PM_NODE_START_LOCATION(scope_node->parser, node);
+ const pm_node_location_t location = PM_NODE_START_LOCATION(node);
if (PM_NODE_TYPE_P(node, PM_INTEGER_NODE)) {
PM_COMPILE_NOT_POPPED(node);
@@ -948,22 +1056,22 @@ pm_compile_flip_flop(const pm_flip_flop_node_t *flip_flop_node, LABEL *else_labe
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)
+pm_compile_branch_condition(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const pm_node_t *cond, LABEL *then_label, LABEL *else_label, pm_scope_node_t *scope_node)
{
- const pm_node_location_t location = PM_NODE_START_LOCATION(scope_node->parser, cond);
+ const pm_node_location_t location = PM_NODE_START_LOCATION(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);
+ pm_compile_logical(iseq, ret, cast->left, NULL, else_label, 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);
+ pm_compile_logical(iseq, ret, cast->left, then_label, NULL, scope_node);
cond = cast->right;
goto again;
@@ -984,11 +1092,11 @@ again:
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);
+ pm_compile_flip_flop((const pm_flip_flop_node_t *) cond, else_label, then_label, iseq, location.line, ret, false, 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);
+ pm_compile_defined_expr(iseq, cast->value, &location, ret, false, scope_node, true);
break;
}
default: {
@@ -1032,7 +1140,7 @@ pm_compile_conditional(rb_iseq_t *iseq, const pm_node_location_t *node_location,
LABEL *end_label = NULL;
DECL_ANCHOR(cond_seq);
- pm_compile_branch_condition(iseq, cond_seq, predicate, then_label, else_label, false, scope_node);
+ pm_compile_branch_condition(iseq, cond_seq, predicate, then_label, else_label, scope_node);
PUSH_SEQ(ret, cond_seq);
rb_code_location_t conditional_location = { 0 };
@@ -1063,7 +1171,7 @@ pm_compile_conditional(rb_iseq_t *iseq, const pm_node_location_t *node_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);
+ pm_line_column_t predicate_end = PM_NODE_END_LINE_COLUMN(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 }
@@ -1180,10 +1288,10 @@ pm_compile_loop(rb_iseq_t *iseq, const pm_node_location_t *node_location, pm_nod
PUSH_LABEL(ret, next_label);
if (type == PM_WHILE_NODE) {
- pm_compile_branch_condition(iseq, ret, predicate, redo_label, end_label, popped, scope_node);
+ pm_compile_branch_condition(iseq, ret, predicate, redo_label, end_label, scope_node);
}
else if (type == PM_UNTIL_NODE) {
- pm_compile_branch_condition(iseq, ret, predicate, end_label, redo_label, popped, scope_node);
+ pm_compile_branch_condition(iseq, ret, predicate, end_label, redo_label, scope_node);
}
PUSH_LABEL(ret, end_label);
@@ -1212,14 +1320,15 @@ 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 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)) {
+ while (!pm_index_lookup_table_lookup(&scope_node->index_lookup_table, constant_id, &local_index))
+ {
level++;
if (scope_node->previous) {
@@ -1243,12 +1352,10 @@ pm_lookup_local_index(rb_iseq_t *iseq, const pm_scope_node_t *scope_node, pm_con
// 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
+static inline 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);
- }
+ RUBY_ASSERT(constant_id >= 1 && constant_id <= pm_parser_constants_size(scope_node->parser));
return scope_node->constants[constant_id - 1];
}
@@ -1257,32 +1364,46 @@ pm_new_child_iseq(rb_iseq_t *iseq, pm_scope_node_t *node, VALUE name, const rb_i
{
debugs("[new_child_iseq]> ---------------------------------------\n");
int isolated_depth = ISEQ_COMPILE_DATA(iseq)->isolated_depth;
- int error_state;
- rb_iseq_t *ret_iseq = pm_iseq_new_with_opt(node, name,
+ rb_iseq_t *ret_iseq = pm_iseq_build(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, &error_state);
-
- if (error_state) {
- pm_scope_node_destroy(node);
- RUBY_ASSERT(ret_iseq == NULL);
- rb_jump_tag(error_state);
- }
+ type, ISEQ_COMPILE_DATA(iseq)->option);
debugs("[new_child_iseq]< ---------------------------------------\n");
return ret_iseq;
}
static int
+pm_cpath_const_p(const pm_node_t *node)
+{
+ switch (PM_NODE_TYPE(node)) {
+ case PM_CONSTANT_READ_NODE:
+ return TRUE;
+ case PM_CONSTANT_PATH_NODE:
+ {
+ const pm_node_t *parent = ((const pm_constant_path_node_t *) node)->parent;
+ if (!parent) return TRUE; /* ::Foo */
+ return pm_cpath_const_p(parent);
+ }
+ default:
+ return FALSE;
+ }
+}
+
+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 */
+ /* Bar::Foo or expr::Foo */
PM_COMPILE(parent);
- return VM_DEFINECLASS_FLAG_SCOPED;
+ int flags = VM_DEFINECLASS_FLAG_SCOPED;
+ if (!pm_cpath_const_p(parent)) {
+ flags |= VM_DEFINECLASS_FLAG_DYNAMIC_CREF;
+ }
+ return flags;
}
else {
/* toplevel class ::Foo */
@@ -1362,7 +1483,7 @@ static void pm_compile_shareable_constant_value(rb_iseq_t *iseq, const pm_node_t
static void
pm_compile_hash_elements(rb_iseq_t *iseq, const pm_node_t *node, const pm_node_list_t *elements, const pm_node_flags_t shareability, VALUE path, 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);
+ const pm_node_location_t location = PM_NODE_START_LOCATION(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
@@ -1435,10 +1556,10 @@ pm_compile_hash_elements(rb_iseq_t *iseq, const pm_node_t *node, const pm_node_l
}
index --;
- VALUE hash = rb_hash_new_with_size(RARRAY_LEN(ary) / 2);
+ VALUE hash = rb_hash_alloc_fixed_size(Qfalse, RARRAY_LEN(ary) / 2);
rb_hash_bulk_insert(RARRAY_LEN(ary), RARRAY_CONST_PTR(ary), hash);
- hash = rb_obj_hide(hash);
- OBJ_FREEZE(hash);
+ RB_GC_GUARD(ary);
+ RB_OBJ_SET_FROZEN_SHAREABLE(hash);
// Emit optimized code.
FLUSH_CHUNK;
@@ -1815,6 +1936,10 @@ pm_setup_args_core(const pm_arguments_node_t *arguments_node, const pm_node_t *b
// foo(*a, b, c: :d)
// foo(*a, b, **c)
//
+ // If the next node is a forwarding argument:
+ //
+ // foo(*a, b, ...)
+ //
// If the next node is NULL (we have hit the end):
//
// foo(*a, b)
@@ -1837,6 +1962,10 @@ pm_setup_args_core(const pm_arguments_node_t *arguments_node, const pm_node_t *b
PUSH_INSN(ret, location, concatarray);
break;
}
+ case PM_FORWARDING_ARGUMENTS_NODE: {
+ PUSH_INSN1(ret, location, pushtoarray, INT2FIX(post_splat_counter));
+ break;
+ }
default:
break;
}
@@ -2270,7 +2399,7 @@ pm_compile_index_control_flow_write_node(rb_iseq_t *iseq, const pm_node_t *node,
// 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);
+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 use_deconstructed_cache, unsigned int base_index);
/**
* This function generates the code to set up the error string and error_p
@@ -2279,7 +2408,7 @@ static int pm_compile_pattern(rb_iseq_t *iseq, pm_scope_node_t *scope_node, cons
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);
+ const pm_node_location_t location = PM_NODE_START_LOCATION(node);
LABEL *match_succeeded_label = NEW_LABEL(location.line);
PUSH_INSN(ret, location, dup);
@@ -2309,7 +2438,7 @@ pm_compile_pattern_generic_error(rb_iseq_t *iseq, pm_scope_node_t *scope_node, c
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);
+ const pm_node_location_t location = PM_NODE_START_LOCATION(node);
LABEL *match_succeeded_label = NEW_LABEL(location.line);
PUSH_INSN(ret, location, dup);
@@ -2342,7 +2471,7 @@ pm_compile_pattern_length_error(rb_iseq_t *iseq, pm_scope_node_t *scope_node, co
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);
+ const pm_node_location_t location = PM_NODE_START_LOCATION(node);
LABEL *match_succeeded_label = NEW_LABEL(location.line);
PUSH_INSN(ret, location, dup);
@@ -2376,10 +2505,10 @@ pm_compile_pattern_eqq_error(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const
* 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)
+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 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));
+ LABEL *matched_label = NEW_LABEL(pm_node_line_number_cached(node, scope_node));
+ CHECK(pm_compile_pattern(iseq, scope_node, node, ret, matched_label, unmatched_label, in_single_pattern, use_deconstructed_cache, base_index));
PUSH_LABEL(ret, matched_label);
return COMPILE_OK;
}
@@ -2392,7 +2521,7 @@ pm_compile_pattern_match(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_
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);
+ const pm_node_location_t location = PM_NODE_START_LOCATION(node);
if (use_deconstructed_cache) {
PUSH_INSN1(ret, location, topn, INT2FIX(base_index + PM_PATTERN_BASE_INDEX_OFFSET_DECONSTRUCTED_CACHE));
@@ -2446,7 +2575,7 @@ pm_compile_pattern_deconstruct(rb_iseq_t *iseq, pm_scope_node_t *scope_node, con
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);
+ const pm_node_location_t location = PM_NODE_START_LOCATION(node);
PUSH_INSN(ret, location, dup);
PM_COMPILE_NOT_POPPED(node);
@@ -2467,9 +2596,9 @@ pm_compile_pattern_constant(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const
* 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)
+pm_compile_pattern_error_handler(rb_iseq_t *iseq, 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);
+ const pm_node_location_t location = PM_NODE_START_LOCATION(node);
LABEL *key_error_label = NEW_LABEL(location.line);
LABEL *cleanup_label = NEW_LABEL(location.line);
@@ -2526,9 +2655,9 @@ pm_compile_pattern_error_handler(rb_iseq_t *iseq, const pm_scope_node_t *scope_n
* 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)
+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 use_deconstructed_cache, unsigned int base_index)
{
- const pm_node_location_t location = PM_NODE_START_LOCATION(scope_node->parser, node);
+ const pm_node_location_t location = PM_NODE_START_LOCATION(node);
switch (PM_NODE_TYPE(node)) {
case PM_ARRAY_PATTERN_NODE: {
@@ -2586,7 +2715,7 @@ pm_compile_pattern(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_node_t
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));
+ CHECK(pm_compile_pattern_match(iseq, scope_node, required, ret, match_failed_label, in_single_pattern, false, base_index + 1));
}
if (cast->rest != NULL) {
@@ -2599,7 +2728,7 @@ pm_compile_pattern(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_node_t
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));
+ CHECK(pm_compile_pattern_match(iseq, scope_node, ((const pm_splat_node_t *) cast->rest)->expression, ret, match_failed_label, in_single_pattern, false, base_index + 1));
}
else if (posts_size > 0) {
PUSH_INSN(ret, location, dup);
@@ -2619,7 +2748,7 @@ pm_compile_pattern(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_node_t
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));
+ CHECK(pm_compile_pattern_match(iseq, scope_node, post, ret, match_failed_label, in_single_pattern, false, base_index + 1));
}
PUSH_INSN(ret, location, pop);
@@ -2716,7 +2845,7 @@ pm_compile_pattern(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_node_t
}
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));
+ CHECK(pm_compile_pattern_match(iseq, scope_node, cast->requireds.nodes[index], ret, next_loop_label, in_single_pattern, false, base_index + 4));
}
const pm_splat_node_t *left = cast->left;
@@ -2726,11 +2855,10 @@ pm_compile_pattern(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_node_t
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));
+ CHECK(pm_compile_pattern_match(iseq, scope_node, left->expression, ret, find_failed_label, in_single_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;
+ const pm_splat_node_t *right = cast->right;
if (right->expression != NULL) {
PUSH_INSN1(ret, location, topn, INT2FIX(3));
@@ -2739,7 +2867,7 @@ pm_compile_pattern(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_node_t
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);
+ pm_compile_pattern_match(iseq, scope_node, right->expression, ret, find_failed_label, in_single_pattern, false, base_index + 4);
}
PUSH_INSNL(ret, location, jump, find_succeeded_label);
@@ -2853,8 +2981,10 @@ pm_compile_pattern(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_node_t
PUSH_INSN(ret, location, putnil);
}
else {
+ rb_obj_hide(keys);
+ RB_OBJ_SET_FROZEN_SHAREABLE(keys);
PUSH_INSN1(ret, location, duparray, keys);
- RB_OBJ_WRITTEN(iseq, Qundef, rb_obj_hide(keys));
+ RB_OBJ_WRITTEN(iseq, Qundef, keys);
}
PUSH_SEND(ret, location, rb_intern("deconstruct_keys"), INT2FIX(1));
@@ -2890,6 +3020,7 @@ pm_compile_pattern(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_node_t
{
VALUE operand = rb_str_freeze(rb_sprintf("key not found: %+"PRIsVALUE, symbol));
+ RB_OBJ_SET_SHAREABLE(operand);
PUSH_INSN1(ret, location, putobject, operand);
}
@@ -2915,7 +3046,7 @@ pm_compile_pattern(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_node_t
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));
+ CHECK(pm_compile_pattern_match(iseq, scope_node, value, match_values, match_failed_label, in_single_pattern, false, base_index + 1));
}
PUSH_SEQ(ret, match_values);
@@ -2943,7 +3074,7 @@ pm_compile_pattern(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_node_t
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);
+ pm_compile_pattern_match(iseq, scope_node, splat->value, ret, match_failed_label, in_single_pattern, false, base_index + 1);
break;
}
default:
@@ -2988,8 +3119,8 @@ pm_compile_pattern(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_node_t
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));
+ CHECK(pm_compile_pattern_match(iseq, scope_node, cast->value, ret, match_failed_label, in_single_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, false, base_index));
PUSH_INSN(ret, location, putnil);
PUSH_LABEL(ret, match_failed_label);
@@ -3005,20 +3136,6 @@ pm_compile_pattern(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_node_t
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;
@@ -3034,7 +3151,7 @@ pm_compile_pattern(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_node_t
// 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, use_deconstructed_cache, base_index + 1));
+ CHECK(pm_compile_pattern(iseq, scope_node, cast->left, ret, matched_left_label, unmatched_left_label, in_single_pattern, use_deconstructed_cache, 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
@@ -3047,7 +3164,7 @@ pm_compile_pattern(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_node_t
// 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, use_deconstructed_cache, base_index));
+ CHECK(pm_compile_pattern(iseq, scope_node, cast->right, ret, matched_label, unmatched_label, in_single_pattern, use_deconstructed_cache, base_index));
break;
}
case PM_PARENTHESES_NODE:
@@ -3055,7 +3172,7 @@ pm_compile_pattern(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_node_t
// 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);
+ return pm_compile_pattern(iseq, scope_node, ((const pm_parentheses_node_t *) node)->body, ret, matched_label, unmatched_label, in_single_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:
@@ -3116,7 +3233,7 @@ pm_compile_pattern(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_node_t
// 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));
+ CHECK(pm_compile_pattern(iseq, scope_node, cast->variable, ret, matched_label, unmatched_label, in_single_pattern, true, base_index));
break;
}
case PM_IF_NODE:
@@ -3150,7 +3267,7 @@ pm_compile_pattern(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_node_t
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));
+ CHECK(pm_compile_pattern_match(iseq, scope_node, statement, ret, unmatched_label, in_single_pattern, use_deconstructed_cache, base_index));
PM_COMPILE_NOT_POPPED(predicate);
if (in_single_pattern) {
@@ -3193,7 +3310,7 @@ pm_compile_pattern(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_node_t
// 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)));
+ rb_bug("Unexpected node type in pattern matching expression: %s", pm_node_type(PM_NODE_TYPE(node)));
break;
}
@@ -3210,26 +3327,27 @@ pm_compile_pattern(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_node_t
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));
+ if (previous) {
+ // Copy inherited fields from the parent scope in one shot, then
+ // zero out the fields that are scope-specific.
+ *scope = *previous;
+ scope->locals = (pm_constant_id_list_t) { 0 };
+ scope->parameters = NULL;
+ scope->body = NULL;
+ scope->local_table_for_iseq_size = 0;
+ scope->index_lookup_table = (pm_index_lookup_table_t) PM_INDEX_LOOKUP_TABLE_INIT;
+ scope->pre_execution_anchor = NULL;
+ }
+ else {
+ 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->base.location.length = node->location.length;
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;
@@ -3257,7 +3375,7 @@ pm_scope_node_init(const pm_node_t *node, pm_scope_node_t *scope, pm_scope_node_
if (cast->statements != NULL) {
scope->base.location.start = cast->statements->base.location.start;
- scope->base.location.end = cast->statements->base.location.end;
+ scope->base.location.length = cast->statements->base.location.length;
}
break;
@@ -3277,13 +3395,6 @@ pm_scope_node_init(const pm_node_t *node, pm_scope_node_t *scope, pm_scope_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: {
@@ -3333,8 +3444,8 @@ pm_scope_node_init(const pm_node_t *node, pm_scope_node_t *scope, pm_scope_node_
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);
+ if (scope_node->index_lookup_table.owned) {
+ xfree(scope_node->index_lookup_table.values);
}
}
@@ -3403,7 +3514,7 @@ pm_iseq_builtin_function_name(const pm_scope_node_t *scope_node, const pm_node_t
// 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)
+pm_compile_builtin_attr(rb_iseq_t *iseq, 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");
@@ -3413,7 +3524,7 @@ pm_compile_builtin_attr(rb_iseq_t *iseq, const pm_scope_node_t *scope_node, cons
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)));
+ COMPILE_ERROR(iseq, node_location->line, "non symbol argument to attr!: %s", pm_node_type(PM_NODE_TYPE(argument)));
return COMPILE_NG;
}
@@ -3433,6 +3544,9 @@ pm_compile_builtin_attr(rb_iseq_t *iseq, const pm_scope_node_t *scope_node, cons
// Let the iseq act like a C method in backtraces
ISEQ_BODY(iseq)->builtin_attrs |= BUILTIN_ATTR_C_TRACE;
}
+ else if (strcmp(RSTRING_PTR(string), "without_interrupts") == 0) {
+ ISEQ_BODY(iseq)->builtin_attrs |= BUILTIN_ATTR_WITHOUT_INTERRUPTS;
+ }
else {
COMPILE_ERROR(iseq, node_location->line, "unknown argument to attr!: %s", RSTRING_PTR(string));
return COMPILE_NG;
@@ -3457,7 +3571,7 @@ pm_compile_builtin_arg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const pm_scope_n
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)));
+ COMPILE_ERROR(iseq, node_location->line, "non symbol argument to arg!: %s", pm_node_type(PM_NODE_TYPE(argument)));
return COMPILE_NG;
}
@@ -3521,8 +3635,7 @@ pm_compile_builtin_mandatory_only_method(rb_iseq_t *iseq, pm_scope_node_t *scope
pm_scope_node_t next_scope_node;
pm_scope_node_init(&def.base, &next_scope_node, scope_node);
- int error_state;
- const rb_iseq_t *mandatory_only_iseq = pm_iseq_new_with_opt(
+ const rb_iseq_t *mandatory_only_iseq = pm_iseq_build(
&next_scope_node,
rb_iseq_base_label(iseq),
rb_iseq_path(iseq),
@@ -3531,16 +3644,10 @@ pm_compile_builtin_mandatory_only_method(rb_iseq_t *iseq, pm_scope_node_t *scope
NULL,
0,
ISEQ_TYPE_METHOD,
- ISEQ_COMPILE_DATA(iseq)->option,
- &error_state
+ ISEQ_COMPILE_DATA(iseq)->option
);
RB_OBJ_WRITE(iseq, &ISEQ_BODY(iseq)->mandatory_only_iseq, (VALUE)mandatory_only_iseq);
- if (error_state) {
- RUBY_ASSERT(ISEQ_BODY(iseq)->mandatory_only_iseq == NULL);
- rb_jump_tag(error_state);
- }
-
pm_scope_node_destroy(&next_scope_node);
return COMPILE_OK;
}
@@ -3644,9 +3751,9 @@ 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;
+ if (message_loc->length == 0) 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);
+ const pm_node_location_t location = PM_LOCATION_START_LOCATION(message_loc, call_node->base.node_id);
LABEL *else_label = NEW_LABEL(location.line);
LABEL *end_label = NEW_LABEL(location.line);
@@ -3658,19 +3765,37 @@ pm_compile_call(rb_iseq_t *iseq, const pm_call_node_t *call_node, LINK_ANCHOR *c
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
- };
+ uint32_t end_cursor = 0;
+ bool end_found = false;
- 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]);
- if (!end_cursor) end_cursor = call_node->closing_loc.end;
+ if (call_node->closing_loc.length > 0) {
+ uint32_t cursor = call_node->closing_loc.start + call_node->closing_loc.length;
+ end_cursor = cursor;
+ end_found = true;
+ }
- 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);
+ if (call_node->arguments != NULL) {
+ uint32_t cursor = call_node->arguments->base.location.start + call_node->arguments->base.location.length;
+ if (!end_found || cursor > end_cursor) {
+ end_cursor = cursor;
+ end_found = true;
+ }
+ }
+
+ if (call_node->message_loc.length > 0) {
+ uint32_t cursor = call_node->message_loc.start + call_node->message_loc.length;
+ if (!end_found || cursor > end_cursor) {
+ end_cursor = cursor;
+ end_found = true;
+ }
+ }
+
+ if (!end_found) {
+ end_cursor = call_node->closing_loc.start + call_node->closing_loc.length;
+ }
+
+ const pm_line_column_t start_location = PM_NODE_START_LINE_COLUMN(call_node);
+ const pm_line_column_t end_location = pm_line_offset_list_line_column_cached(scope_node->line_offsets, end_cursor, scope_node->start_line, &scope_node->last_line);
code_location = (rb_code_location_t) {
.beg_pos = { .lineno = start_location.line, .column = start_location.column },
@@ -3700,7 +3825,7 @@ pm_compile_call(rb_iseq_t *iseq, const pm_call_node_t *call_node, LINK_ANCHOR *c
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));
+ block_iseq = NEW_CHILD_ISEQ(&next_scope_node, make_name_for_block(iseq), ISEQ_TYPE_BLOCK, pm_node_line_number_cached(call_node->block, scope_node));
pm_scope_node_destroy(&next_scope_node);
ISEQ_COMPILE_DATA(iseq)->current_block = block_iseq;
}
@@ -3814,9 +3939,9 @@ pm_compile_call(rb_iseq_t *iseq, const pm_call_node_t *call_node, LINK_ANCHOR *c
* node.
*/
static inline VALUE
-pm_compile_back_reference_ref(const pm_back_reference_read_node_t *node)
+pm_compile_back_reference_ref(const pm_scope_node_t *scope_node, const pm_back_reference_read_node_t *node)
{
- const char *type = (const char *) (node->base.location.start + 1);
+ const char *type = (const char *) (pm_parser_start(scope_node->parser) + node->base.location.start + 1);
// Since a back reference is `$<char>`, Ruby represents the ID as an
// rb_intern on the value after the `$`.
@@ -4207,7 +4332,7 @@ pm_compile_defined_expr0(rb_iseq_t *iseq, const pm_node_t *node, const pm_node_l
// defined?($+)
// ^^
const pm_back_reference_read_node_t *cast = (const pm_back_reference_read_node_t *) node;
- VALUE ref = pm_compile_back_reference_ref(cast);
+ VALUE ref = pm_compile_back_reference_ref(scope_node, cast);
PUSH_INSN(ret, location, putnil);
PUSH_INSN3(ret, location, defined, INT2FIX(DEFINED_REF), ref, PUSH_VAL(DEFINED_GVAR));
@@ -4495,6 +4620,7 @@ pm_compile_defined_expr0(rb_iseq_t *iseq, const pm_node_t *node, const pm_node_l
case PM_PARAMETERS_NODE:
case PM_KEYWORD_REST_PARAMETER_NODE:
case PM_NO_KEYWORDS_PARAMETER_NODE:
+ case PM_NO_BLOCK_PARAMETER_NODE:
case PM_NUMBERED_PARAMETERS_NODE:
case PM_OPTIONAL_KEYWORD_PARAMETER_NODE:
case PM_OPTIONAL_PARAMETER_NODE:
@@ -4529,12 +4655,12 @@ pm_compile_defined_expr0(rb_iseq_t *iseq, const pm_node_t *node, const pm_node_l
case PM_BLOCK_NODE:
case PM_EMBEDDED_STATEMENTS_NODE:
case PM_EMBEDDED_VARIABLE_NODE:
- case PM_MISSING_NODE:
+ case PM_ERROR_RECOVERY_NODE:
case PM_PRE_EXECUTION_NODE:
case PM_PROGRAM_NODE:
case PM_SCOPE_NODE:
case PM_STATEMENTS_NODE:
- rb_bug("Unreachable node in defined?: %s", pm_node_type_to_str(PM_NODE_TYPE(node)));
+ rb_bug("Unreachable node in defined?: %s", pm_node_type(PM_NODE_TYPE(node)));
}
RUBY_ASSERT(dtype != DEFINED_NOT_DEFINED);
@@ -4639,33 +4765,7 @@ pm_add_ensure_iseq(LINK_ANCHOR *const ret, rb_iseq_t *iseq, int is_return, pm_sc
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
@@ -4673,24 +4773,23 @@ pm_local_table_insert_func(st_data_t *key, st_data_t *value, st_data_t arg, int
* 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)
+pm_insert_local_index(pm_constant_id_t constant_id, int local_index, pm_index_lookup_table_t *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);
+ pm_index_lookup_table_insert(index_lookup_table, constant_id, local_index);
}
/**
- * Insert a local into the local table for the iseq that is a special forwarding
- * local variable.
+ * Insert a special forwarding local (*, **, &, ...) into the local table.
*/
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)
+pm_insert_local_special(pm_constant_id_t special_id, ID local_name, int local_index, pm_index_lookup_table_t *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);
+ pm_index_lookup_table_insert(index_lookup_table, special_id, local_index);
}
/**
@@ -4700,7 +4799,7 @@ pm_insert_local_special(ID local_name, int local_index, st_table *index_lookup_t
* 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)
+pm_compile_destructured_param_locals(const pm_multi_target_node_t *node, pm_index_lookup_table_t *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];
@@ -4753,9 +4852,9 @@ pm_compile_destructured_param_locals(const pm_multi_target_node_t *node, st_tabl
* 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)
+pm_compile_destructured_param_write(rb_iseq_t *iseq, const pm_required_parameter_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);
+ const pm_node_location_t location = PM_NODE_START_LOCATION(node);
pm_local_index_t index = pm_lookup_local_index(iseq, scope_node, node->name, 0);
PUSH_SETLOCAL(ret, location, index.index, index.level);
}
@@ -4769,9 +4868,9 @@ pm_compile_destructured_param_write(rb_iseq_t *iseq, const pm_required_parameter
* 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)
+pm_compile_destructured_param_writes(rb_iseq_t *iseq, const pm_multi_target_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);
+ const pm_node_location_t location = PM_NODE_START_LOCATION(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;
@@ -4930,7 +5029,7 @@ pm_multi_target_state_update(pm_multi_target_state_t *state)
previous = current;
current = current->next;
- xfree(previous);
+ SIZED_FREE(previous);
}
}
@@ -4968,7 +5067,7 @@ pm_compile_multi_target_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR
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);
+ const pm_node_location_t location = PM_NODE_START_LOCATION(node);
switch (PM_NODE_TYPE(node)) {
case PM_LOCAL_VARIABLE_TARGET_NODE: {
@@ -5205,7 +5304,7 @@ pm_compile_target_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *cons
break;
}
default:
- rb_bug("Unexpected node type: %s", pm_node_type_to_str(PM_NODE_TYPE(node)));
+ rb_bug("Unexpected node type: %s", pm_node_type(PM_NODE_TYPE(node)));
break;
}
}
@@ -5218,7 +5317,7 @@ pm_compile_target_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *cons
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_location_t location = PM_NODE_START_LOCATION(node);
const pm_node_list_t *lefts;
const pm_node_t *rest;
const pm_node_list_t *rights;
@@ -5239,7 +5338,7 @@ pm_compile_multi_target_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR
break;
}
default:
- rb_bug("Unsupported node %s", pm_node_type_to_str(PM_NODE_TYPE(node)));
+ rb_bug("Unsupported node %s", pm_node_type(PM_NODE_TYPE(node)));
break;
}
@@ -5301,7 +5400,7 @@ pm_compile_multi_target_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR
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);
+ const pm_node_location_t location = PM_NODE_START_LOCATION(node);
switch (PM_NODE_TYPE(node)) {
case PM_LOCAL_VARIABLE_TARGET_NODE: {
@@ -5317,8 +5416,7 @@ pm_compile_for_node_index(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *c
case PM_INSTANCE_VARIABLE_TARGET_NODE:
case PM_CONSTANT_PATH_TARGET_NODE:
case PM_CALL_TARGET_NODE:
- case PM_INDEX_TARGET_NODE:
- case PM_SPLAT_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.
@@ -5338,6 +5436,7 @@ pm_compile_for_node_index(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *c
pm_multi_target_state_update(&state);
break;
}
+ case PM_SPLAT_NODE:
case PM_MULTI_TARGET_NODE: {
DECL_ANCHOR(writes);
DECL_ANCHOR(cleanup);
@@ -5373,12 +5472,18 @@ pm_compile_for_node_index(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *c
PUSH_INSN(ret, location, pop);
PUSH_LABEL(ret, not_single);
+
+ if (PM_NODE_TYPE_P(node, PM_SPLAT_NODE)) {
+ const pm_splat_node_t *cast = (const pm_splat_node_t *) node;
+ PUSH_INSN2(ret, location, expandarray, INT2FIX(0), INT2FIX(cast->expression == NULL ? 0 : 1));
+ }
+
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)));
+ rb_bug("Unexpected node type for index in for node: %s", pm_node_type(PM_NODE_TYPE(node)));
break;
}
}
@@ -5386,8 +5491,6 @@ pm_compile_for_node_index(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *c
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);
@@ -5399,7 +5502,7 @@ pm_compile_rescue(rb_iseq_t *iseq, const pm_begin_node_t *cast, const pm_node_lo
&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_node_line_number_cached((const pm_node_t *) cast->rescue_clause, scope_node)
);
pm_scope_node_destroy(&rescue_scope_node);
@@ -5415,7 +5518,7 @@ pm_compile_rescue(rb_iseq_t *iseq, const pm_begin_node_t *cast, const pm_node_lo
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);
+ const pm_node_location_t location = PM_NODE_START_LOCATION(cast->rescue_clause);
PUSH_INSN(ret, location, putnil);
}
@@ -5438,12 +5541,11 @@ pm_compile_rescue(rb_iseq_t *iseq, const pm_begin_node_t *cast, const pm_node_lo
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);
+ location = PM_NODE_START_LOCATION(statements);
}
else {
location = *node_location;
@@ -5527,55 +5629,18 @@ pm_opt_str_freeze_p(const rb_iseq_t *iseq, const pm_call_node_t *node)
}
/**
- * 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)
+pm_compile_constant_read(rb_iseq_t *iseq, VALUE name, const pm_location_t *name_loc, uint32_t node_id, LINK_ANCHOR *const ret, pm_scope_node_t *scope_node)
{
- const pm_node_location_t location = PM_LOCATION_START_LOCATION(scope_node->parser, name_loc, node_id);
+ const pm_node_location_t location = PM_LOCATION_START_LOCATION(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);
+ RB_OBJ_SET_SHAREABLE(segments);
PUSH_INSN1(ret, location, opt_getconstant_path, segments);
}
else {
@@ -5630,7 +5695,7 @@ pm_constant_path_parts(const pm_node_t *node, const pm_scope_node_t *scope_node)
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);
+ const pm_node_location_t location = PM_NODE_START_LOCATION(node);
switch (PM_NODE_TYPE(node)) {
case PM_CONSTANT_READ_NODE: {
@@ -5668,7 +5733,7 @@ pm_compile_constant_path(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *co
* 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)
+pm_compile_shareable_constant_literal(rb_iseq_t *iseq, const pm_node_t *node, pm_scope_node_t *scope_node)
{
switch (PM_NODE_TYPE(node)) {
case PM_TRUE_NODE:
@@ -5702,7 +5767,7 @@ pm_compile_shareable_constant_literal(rb_iseq_t *iseq, const pm_node_t *node, co
}
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);
+ VALUE result = rb_hash_alloc_fixed_size(rb_cHash, cast->elements.size);
for (size_t index = 0; index < cast->elements.size; index++) {
const pm_node_t *element = cast->elements.nodes[index];
@@ -5735,12 +5800,12 @@ pm_compile_shareable_constant_value(rb_iseq_t *iseq, const pm_node_t *node, cons
{
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);
+ const pm_node_location_t location = PM_NODE_START_LOCATION(node);
PUSH_INSN1(ret, location, putobject, literal);
return;
}
- const pm_node_location_t location = PM_NODE_START_LOCATION(scope_node->parser, node);
+ const pm_node_location_t location = PM_NODE_START_LOCATION(node);
switch (PM_NODE_TYPE(node)) {
case PM_ARRAY_NODE: {
const pm_array_node_t *cast = (const pm_array_node_t *) node;
@@ -5789,6 +5854,9 @@ pm_compile_shareable_constant_value(rb_iseq_t *iseq, const pm_node_t *node, cons
if (shareability & PM_SHAREABLE_CONSTANT_NODE_FLAGS_LITERAL) {
PUSH_INSN1(ret, location, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
PUSH_SEQ(ret, value_seq);
+ if (!RB_OBJ_SHAREABLE_P(path)) {
+ RB_OBJ_SET_SHAREABLE(path);
+ }
PUSH_INSN1(ret, location, putobject, path);
PUSH_SEND_WITH_FLAG(ret, location, rb_intern("ensure_shareable"), INT2FIX(2), INT2FIX(VM_CALL_ARGS_SIMPLE));
}
@@ -6202,7 +6270,7 @@ pm_compile_scope_node(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_nod
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)));
+ rb_bug("Unexpected node type for parameters: %s", pm_node_type(PM_NODE_TYPE(scope_node->parameters)));
}
}
@@ -6227,8 +6295,9 @@ pm_compile_scope_node(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_nod
// 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();
+ // Index lookup table buffer size is only the number of the locals.
+ // We'll initialize it after computing table_size below.
+ pm_index_lookup_table_t index_lookup_table = PM_INDEX_LOOKUP_TABLE_INIT;
int table_size = (int) locals_size;
@@ -6339,7 +6408,7 @@ pm_compile_scope_node(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_nod
}
}
- if (parameters_node && parameters_node->block) {
+ if (parameters_node && parameters_node->block && PM_NODE_TYPE_P(parameters_node->block, PM_BLOCK_PARAMETER_NODE)) {
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) {
@@ -6352,6 +6421,10 @@ pm_compile_scope_node(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_nod
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;
+ // Init the direct-indexed lookup table. The capacity is based on the
+ // parser's constant pool size (for regular locals) plus special slots.
+ pm_index_lookup_table_init(&index_lookup_table, (int) pm_parser_constants_size(scope_node->parser), iseq);
+
//********END OF STEP 1**********
//********STEP 2**********
@@ -6404,13 +6477,13 @@ pm_compile_scope_node(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_nod
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);
+ 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)));
+ rb_bug("Unsupported node in requireds in parameters %s", pm_node_type(PM_NODE_TYPE(required)));
}
}
@@ -6419,8 +6492,7 @@ pm_compile_scope_node(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_nod
}
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;
+ local_table_for_iseq->ids[local_index++] = idItImplicit;
}
// def foo(a, (b, *c, d), e = 1, *f, g, (h, *i, j), k:, l: 1, **m, &n)
@@ -6438,7 +6510,7 @@ pm_compile_scope_node(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_nod
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);
+ pm_insert_local_index(name, local_index, &index_lookup_table, local_table_for_iseq, scope_node);
}
}
}
@@ -6464,14 +6536,14 @@ pm_compile_scope_node(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_nod
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);
+ 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);
+ pm_insert_local_special(PM_CONSTANT_MULT, idMULT, local_index, &index_lookup_table, local_table_for_iseq);
}
local_index++;
@@ -6511,12 +6583,12 @@ pm_compile_scope_node(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_nod
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);
+ 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)));
+ rb_bug("Unsupported node in posts in parameters %s", pm_node_type(PM_NODE_TYPE(post_node)));
}
}
}
@@ -6546,7 +6618,7 @@ pm_compile_scope_node(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_nod
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);
+ pm_insert_local_index(name, local_index, &index_lookup_table, local_table_for_iseq, scope_node);
}
local_index++;
}
@@ -6576,7 +6648,7 @@ pm_compile_scope_node(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_nod
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);
+ pm_insert_local_index(name, local_index, &index_lookup_table, local_table_for_iseq, scope_node);
}
local_index++;
}
@@ -6638,12 +6710,12 @@ pm_compile_scope_node(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_nod
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);
+ 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);
+ pm_insert_local_special(PM_CONSTANT_POW, idPow, local_index, &index_lookup_table, local_table_for_iseq);
}
local_index++;
@@ -6657,7 +6729,7 @@ pm_compile_scope_node(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_nod
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);
+ pm_insert_local_special(PM_CONSTANT_MULT, idMULT, local_index++, &index_lookup_table, local_table_for_iseq);
// Add the anonymous **
RUBY_ASSERT(!body->param.flags.has_kw);
@@ -6666,46 +6738,58 @@ pm_compile_scope_node(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_nod
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);
+ pm_insert_local_special(PM_CONSTANT_POW, 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);
+ pm_insert_local_special(PM_CONSTANT_AND, 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);
+ pm_insert_local_special(PM_CONSTANT_DOT3, 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)));
+ rb_bug("node type %s not expected as keyword_rest", pm_node_type(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);
+ switch (PM_NODE_TYPE(parameters_node->block)) {
+ case PM_BLOCK_PARAMETER_NODE: {
+ body->param.block_start = local_index;
+ body->param.flags.has_block = true;
- pm_constant_id_t name = ((const pm_block_parameter_node_t *) parameters_node->block)->name;
+ iseq_set_use_block(iseq);
- 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;
+ 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_index(name, local_index, index_lookup_table, local_table_for_iseq, scope_node);
+ pm_insert_local_special(PM_CONSTANT_AND, idAnd, local_index, &index_lookup_table, local_table_for_iseq);
}
- }
- else {
- pm_insert_local_special(idAnd, local_index, index_lookup_table, local_table_for_iseq);
- }
- local_index++;
+ local_index++;
+ break;
+ }
+ case PM_NO_BLOCK_PARAMETER_NODE: {
+ body->param.flags.accepts_no_block = true;
+ break;
+ }
+ default:
+ rb_bug("node type %s not expected as block parameter", pm_node_type(PM_NODE_TYPE(parameters_node->block)));
+ }
}
}
@@ -6729,7 +6813,7 @@ pm_compile_scope_node(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_nod
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);
+ 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);
}
}
}
@@ -6743,7 +6827,7 @@ pm_compile_scope_node(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_nod
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);
+ 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);
}
}
}
@@ -6769,14 +6853,20 @@ pm_compile_scope_node(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_nod
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);
+ pm_constant_id_t constant_id = pm_parser_constant_find(scope_node->parser, 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);
+ 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;
}
+ // Fill in the anonymous `it` parameter, if it exists
+ if (scope_node->parameters && PM_NODE_TYPE_P(scope_node->parameters, PM_IT_PARAMETERS_NODE)) {
+ body->param.lead_num = 1;
+ body->param.flags.has_lead = true;
+ }
+
//********END OF STEP 3**********
//********STEP 4**********
@@ -6788,7 +6878,7 @@ pm_compile_scope_node(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_nod
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);
+ pm_insert_local_index(constant_id, local_index, &index_lookup_table, local_table_for_iseq, scope_node);
}
}
@@ -6797,14 +6887,13 @@ pm_compile_scope_node(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_nod
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;
+ int existing;
+ if (!pm_index_lookup_table_lookup(&index_lookup_table, constant_id, &existing)) {
+ ID local = pm_constant_id_lookup(scope_node, constant_id);
+ local_table_for_iseq->ids[local_index] = local;
+ pm_index_lookup_table_insert(&index_lookup_table, constant_id, local_index);
+ local_index++;
+ }
}
}
}
@@ -6812,10 +6901,7 @@ pm_compile_scope_node(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_nod
//********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);
- }
+ // refer to the parameters correctly.
scope_node->index_lookup_table = index_lookup_table;
iseq_calc_param_size(iseq);
@@ -6827,6 +6913,8 @@ pm_compile_scope_node(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_nod
// FIXME: args?
iseq_set_local_table(iseq, local_table_for_iseq, 0);
+ iseq_set_parameters_lvar_state(iseq);
+
scope_node->local_table_for_iseq_size = local_table_for_iseq->size;
if (keyword != NULL) {
@@ -6894,7 +6982,7 @@ pm_compile_scope_node(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_nod
// ^^
break;
default:
- rb_bug("Unexpected keyword parameter node type %s", pm_node_type_to_str(PM_NODE_TYPE(keyword_parameter_node)));
+ rb_bug("Unexpected keyword parameter node type %s", pm_node_type(PM_NODE_TYPE(keyword_parameter_node)));
}
}
}
@@ -6996,7 +7084,7 @@ pm_compile_scope_node(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_nod
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);
+ const pm_node_location_t statements_location = (scope_node->body != NULL ? PM_NODE_START_LOCATION(scope_node->body) : location);
iseq_set_exception_local_table(iseq);
if (scope_node->body != NULL) {
@@ -7059,7 +7147,7 @@ pm_compile_scope_node(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_nod
}
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);
+ const pm_node_location_t end_location = PM_NODE_END_LOCATION(scope_node->ast_node);
PUSH_TRACE(ret, RUBY_EVENT_END);
ISEQ_COMPILE_DATA(iseq)->last_line = end_location.line;
}
@@ -7079,13 +7167,13 @@ pm_compile_alias_global_variable_node(rb_iseq_t *iseq, const pm_alias_global_var
{
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));
+ VALUE operand = ID2SYM(rb_intern3((const char *) (pm_parser_start(scope_node->parser) + name_loc->start), name_loc->length, 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));
+ VALUE operand = ID2SYM(rb_intern3((const char *) (pm_parser_start(scope_node->parser) + name_loc->start), name_loc->length, scope_node->encoding));
PUSH_INSN1(ret, *location, putobject, operand);
}
@@ -7131,6 +7219,7 @@ pm_compile_array_node(rb_iseq_t *iseq, const pm_node_t *node, const pm_node_list
if (!popped) {
if (elements->size) {
VALUE value = pm_static_literal_value(iseq, node, scope_node);
+ RB_OBJ_SET_FROZEN_SHAREABLE(value);
PUSH_INSN1(ret, *location, duparray, value);
}
else {
@@ -7261,7 +7350,7 @@ pm_compile_array_node(rb_iseq_t *iseq, const pm_node_t *node, const pm_node_list
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);
+ RB_OBJ_SET_FROZEN_SHAREABLE(tmp_array);
// Emit the optimized code.
FLUSH_CHUNK;
@@ -7363,9 +7452,9 @@ pm_compile_call_node(rb_iseq_t *iseq, const pm_call_node_t *node, LINK_ANCHOR *c
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;
+ if (message_loc->length == 0) 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 pm_node_location_t location = PM_LOCATION_START_LOCATION(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) {
@@ -7397,44 +7486,6 @@ pm_compile_call_node(rb_iseq_t *iseq, const pm_call_node_t *node, LINK_ANCHOR *c
}
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) {
@@ -7523,10 +7574,9 @@ pm_compile_call_operator_write_node(rb_iseq_t *iseq, const pm_call_operator_writ
* 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)
+pm_compile_case_node_dispatch(rb_iseq_t *iseq, VALUE dispatch, const pm_node_t *node, LABEL *label, 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);
@@ -7556,10 +7606,7 @@ pm_compile_case_node_dispatch(rb_iseq_t *iseq, VALUE dispatch, const pm_node_t *
return Qundef;
}
- if (NIL_P(rb_hash_lookup(dispatch, key))) {
- rb_hash_aset(dispatch, key, ((VALUE) label) | 1);
- }
-
+ cdhash_aset_if_missing(dispatch, key, (VALUE)label);
return dispatch;
}
@@ -7569,7 +7616,6 @@ pm_compile_case_node_dispatch(rb_iseq_t *iseq, VALUE dispatch, const pm_node_t *
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;
@@ -7608,7 +7654,7 @@ pm_compile_case_node(rb_iseq_t *iseq, const pm_case_node_t *cast, const pm_node_
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);
+ int clause_lineno = pm_node_line_number_cached((const pm_node_t *) clause, scope_node);
LABEL *label = NEW_LABEL(clause_lineno);
PUSH_LABEL(body_seq, label);
@@ -7634,15 +7680,15 @@ pm_compile_case_node(rb_iseq_t *iseq, const pm_case_node_t *cast, const pm_node_
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);
+ pm_node_location_t cond_location = PM_NODE_START_LOCATION(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);
+ LABEL *next_label = NEW_LABEL(pm_node_line_number_cached(condition, scope_node));
+ pm_compile_branch_condition(iseq, cond_seq, condition, label, next_label, scope_node);
PUSH_LABEL(cond_seq, next_label);
}
}
@@ -7699,8 +7745,7 @@ pm_compile_case_node(rb_iseq_t *iseq, const pm_case_node_t *cast, const pm_node_
// 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;
+ dispatch = cdhash_new(0);
}
// We're going to loop through each of the conditions in the case
@@ -7713,7 +7758,7 @@ pm_compile_case_node(rb_iseq_t *iseq, const pm_case_node_t *cast, const pm_node_
// 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);
+ pm_node_location_t clause_location = PM_NODE_START_LOCATION((const pm_node_t *) clause);
const pm_node_list_t *conditions = &clause->conditions;
LABEL *label = NEW_LABEL(clause_location.line);
@@ -7723,7 +7768,7 @@ pm_compile_case_node(rb_iseq_t *iseq, const pm_case_node_t *cast, const pm_node_
// 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);
+ const pm_node_location_t condition_location = PM_NODE_START_LOCATION(condition);
// If we haven't already abandoned the optimization, then
// we're going to try to compile the condition into the
@@ -7787,6 +7832,7 @@ pm_compile_case_node(rb_iseq_t *iseq, const pm_case_node_t *cast, const pm_node_
// optimization.
if (dispatch != Qundef) {
PUSH_INSN(ret, location, dup);
+ RB_OBJ_SET_SHAREABLE(dispatch); // it is special that the hash is shareable but not frozen, because compile.c modify them. This Hahs instance is not accessible so it is safe to leave it.
PUSH_INSN2(ret, location, opt_case_dispatch, dispatch, else_label);
LABEL_REF(else_label);
}
@@ -7798,7 +7844,7 @@ pm_compile_case_node(rb_iseq_t *iseq, const pm_case_node_t *cast, const pm_node_
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));
+ pm_node_location_t else_location = PM_NODE_START_LOCATION(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.
@@ -7887,8 +7933,8 @@ pm_compile_case_match_node(rb_iseq_t *iseq, const pm_case_match_node_t *node, co
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);
+ const pm_node_location_t in_location = PM_NODE_START_LOCATION(in_node);
+ const pm_node_location_t pattern_location = PM_NODE_START_LOCATION(in_node->pattern);
if (branch_id) {
PUSH_INSN(body_seq, in_location, putnil);
@@ -7915,7 +7961,7 @@ pm_compile_case_match_node(rb_iseq_t *iseq, const pm_case_match_node_t *node, co
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);
+ pm_compile_pattern(iseq, scope_node, in_node->pattern, cond_seq, body_label, next_pattern_label, in_single_pattern, true, 2);
PUSH_LABEL(cond_seq, next_pattern_label);
LABEL_UNREMOVABLE(next_pattern_label);
}
@@ -8163,7 +8209,7 @@ pm_compile_match_required_node(rb_iseq_t *iseq, const pm_match_required_node_t *
// 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);
+ pm_compile_pattern(iseq, scope_node, node->pattern, ret, matched_label, unmatched_label, true, 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
@@ -8666,8 +8712,7 @@ pm_compile_yield_node(rb_iseq_t *iseq, const pm_yield_node_t *node, const pm_nod
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);
+ const pm_node_location_t location = PM_NODE_START_LOCATION(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)) {
@@ -8675,7 +8720,7 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret,
// 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;
+ lineno = (int) PM_NODE_START_LINE_COLUMN(((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) {
@@ -8770,7 +8815,7 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret,
// ^^
if (!popped) {
const pm_back_reference_read_node_t *cast = (const pm_back_reference_read_node_t *) node;
- VALUE backref = pm_compile_back_reference_ref(cast);
+ VALUE backref = pm_compile_back_reference_ref(scope_node, cast);
PUSH_INSN2(ret, location, getspecial, INT2FIX(1), backref);
}
@@ -9014,6 +9059,7 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret,
if (ISEQ_COMPILE_DATA(iseq)->option->inline_const_cache && ((parts = pm_constant_path_parts(node, scope_node)) != Qnil)) {
ISEQ_BODY(iseq)->ic_size++;
+ RB_OBJ_SET_SHAREABLE(parts);
PUSH_INSN1(ret, location, opt_getconstant_path, parts);
}
else {
@@ -9628,16 +9674,16 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret,
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);
+ PUSH_INSN1(ret, location, dupstring, string);
}
else {
- PUSH_INSN1(ret, location, putchilledstring, string);
+ PUSH_INSN1(ret, location, dupchilledstring, 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, !PM_NODE_FLAG_P(cast, PM_INTERPOLATED_STRING_NODE_FLAGS_FROZEN));
+ int length = pm_interpolated_node_compile(iseq, &cast->parts, &location, ret, popped, scope_node, NULL, NULL, PM_NODE_FLAG_P(cast, PM_INTERPOLATED_STRING_NODE_FLAGS_MUTABLE), PM_NODE_FLAG_P(cast, PM_INTERPOLATED_STRING_NODE_FLAGS_FROZEN));
if (length > 1) PUSH_INSN1(ret, location, concatstrings, INT2FIX(length));
if (popped) PUSH_INSN(ret, location, pop);
}
@@ -9648,7 +9694,7 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret,
// :"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, false);
+ int length = pm_interpolated_node_compile(iseq, &cast->parts, &location, ret, popped, scope_node, NULL, NULL, false, false);
if (length > 1) {
PUSH_INSN1(ret, location, concatstrings, INT2FIX(length));
@@ -9670,7 +9716,7 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret,
PUSH_INSN(ret, location, putself);
- int length = pm_interpolated_node_compile(iseq, &cast->parts, &location, ret, false, scope_node, NULL, NULL, false);
+ int length = pm_interpolated_node_compile(iseq, &cast->parts, &location, ret, false, scope_node, NULL, NULL, false, false);
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));
@@ -9721,7 +9767,7 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret,
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);
+ int opening_lineno = pm_location_line_number_cached(&cast->opening_loc, scope_node);
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);
@@ -9851,7 +9897,7 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret,
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);
+ pm_compile_pattern(iseq, scope_node, cast->pattern, ret, matched_label, unmatched_label, 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.
@@ -9898,8 +9944,8 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret,
// 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.");
+ case PM_ERROR_RECOVERY_NODE:
+ rb_bug("A pm_error_recovery_node_t should not exist in prism's AST.");
return;
case PM_MODULE_NODE: {
// module Foo; end
@@ -9984,6 +10030,12 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret,
return;
}
+ case PM_NO_BLOCK_PARAMETER_NODE: {
+ // def foo(&nil); end
+ // ^^^^
+ ISEQ_BODY(iseq)->param.flags.accepts_no_block = TRUE;
+ return;
+ }
case PM_NO_KEYWORDS_PARAMETER_NODE: {
// def foo(**nil); end
// ^^^^^
@@ -10129,6 +10181,7 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret,
exclude_end
);
+ RB_OBJ_SET_SHAREABLE(val);
PUSH_INSN1(ret, location, putobject, val);
}
}
@@ -10192,7 +10245,7 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret,
&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_node_line_number_cached(cast->rescue_expression, scope_node)
);
pm_scope_node_destroy(&rescue_scope_node);
@@ -10281,7 +10334,7 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret,
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)));
+ rb_bug("Unexpected node type for shareable constant write: %s", pm_node_type(PM_NODE_TYPE(cast->write)));
break;
}
@@ -10302,7 +10355,17 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret,
ID singletonclass;
CONST_ID(singletonclass, "singletonclass");
- PUSH_INSN3(ret, location, defineclass, ID2SYM(singletonclass), child_iseq, INT2FIX(VM_DEFINECLASS_TYPE_SINGLETON_CLASS));
+
+ /* `class << self` in a class body and `class << Foo` (constant
+ receiver) are stable. All other forms are potentially dynamic. */
+ int sclass_flags = VM_DEFINECLASS_TYPE_SINGLETON_CLASS;
+ if (!(PM_NODE_TYPE_P(cast->expression, PM_SELF_NODE) &&
+ ISEQ_BODY(iseq)->type == ISEQ_TYPE_CLASS) &&
+ !pm_cpath_const_p(cast->expression)) {
+ sclass_flags |= VM_DEFINECLASS_FLAG_DYNAMIC_CREF;
+ }
+
+ PUSH_INSN3(ret, location, defineclass, ID2SYM(singletonclass), child_iseq, INT2FIX(sclass_flags));
if (popped) PUSH_INSN(ret, location, pop);
RB_OBJ_WRITTEN(iseq, Qundef, (VALUE) child_iseq);
@@ -10329,10 +10392,10 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret,
PUSH_INSN1(ret, location, putobject, string);
}
else if (PM_NODE_FLAG_P(cast, PM_STRING_FLAGS_MUTABLE)) {
- PUSH_INSN1(ret, location, putstring, string);
+ PUSH_INSN1(ret, location, dupstring, string);
}
else {
- PUSH_INSN1(ret, location, putchilledstring, string);
+ PUSH_INSN1(ret, location, dupchilledstring, string);
}
}
return;
@@ -10386,10 +10449,10 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret,
PUSH_INSN1(ret, location, putobject, value);
}
else if (PM_NODE_FLAG_P(node, PM_STRING_FLAGS_MUTABLE)) {
- PUSH_INSN1(ret, location, putstring, value);
+ PUSH_INSN1(ret, location, dupstring, value);
}
else {
- PUSH_INSN1(ret, location, putchilledstring, value);
+ PUSH_INSN1(ret, location, dupchilledstring, value);
}
}
return;
@@ -10495,7 +10558,7 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret,
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)));
+ rb_raise(rb_eNotImpError, "node type %s not implemented", pm_node_type(PM_NODE_TYPE(node)));
return;
}
}
@@ -10557,6 +10620,15 @@ pm_iseq_compile_node(rb_iseq_t *iseq, pm_scope_node_t *node)
return iseq_setup(iseq, ret);
}
+void
+pm_parse_result_init(pm_parse_result_t *result)
+{
+ memset(result, 0, sizeof(pm_parse_result_t));
+ result->arena = pm_arena_new();
+ result->options = pm_options_new();
+ pm_options_line_set(result->options, 1);
+}
+
/**
* Free the internal memory associated with a pm_parse_result_t struct.
* Importantly this does not free the struct itself.
@@ -10564,24 +10636,21 @@ pm_iseq_compile_node(rb_iseq_t *iseq, pm_scope_node_t *node)
void
pm_parse_result_free(pm_parse_result_t *result)
{
- if (result->node.ast_node != NULL) {
- pm_node_destroy(&result->parser, result->node.ast_node);
- }
-
if (result->parsed) {
- xfree(result->node.constants);
+ SIZED_FREE_N(result->node.constants, pm_parser_constants_size(result->node.parser));
pm_scope_node_destroy(&result->node);
}
- pm_parser_free(&result->parser);
- pm_string_free(&result->input);
- pm_options_free(&result->options);
+ if (result->parser) pm_parser_free(result->parser);
+ pm_arena_free(result->arena);
+ if (result->source) pm_source_free(result->source);
+ 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;
+ const pm_diagnostic_t *error;
/** The start line of the diagnostic message. */
int32_t line;
@@ -10617,125 +10686,151 @@ typedef struct {
#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;
+/** Context struct for collecting errors via callback. */
+typedef struct {
+ pm_parse_error_t *errors;
+ size_t count;
+ size_t capacity;
+ const pm_line_offset_list_t *line_offsets;
+ int32_t start_line;
+} pm_error_collect_t;
- int32_t start_line = parser->start_line;
- pm_diagnostic_t *finish = (pm_diagnostic_t * )error_list->tail->next;
-
- for (pm_diagnostic_t *error = (pm_diagnostic_t *) error_list->head; error != finish; 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);
- }
+static void
+pm_error_collect_callback(const pm_diagnostic_t *diagnostic, void *data)
+{
+ pm_error_collect_t *ctx = (pm_error_collect_t *) data;
+ pm_location_t loc = pm_diagnostic_location(diagnostic);
- // Ensure we have at least one column of error.
- if (start.column == column_end) column_end++;
+ pm_line_column_t start = pm_line_offset_list_line_column(ctx->line_offsets, loc.start, ctx->start_line);
+ pm_line_column_t end = pm_line_offset_list_line_column(ctx->line_offsets, loc.start + loc.length, ctx->start_line);
- errors[index] = (pm_parse_error_t) {
- .error = error,
- .line = start.line,
- .column_start = start.column,
- .column_end = column_end
- };
+ uint32_t column_end;
+ if (start.line == end.line) {
+ column_end = end.column;
+ } else {
+ column_end = (uint32_t) (ctx->line_offsets->offsets[start.line - ctx->start_line + 1] - ctx->line_offsets->offsets[start.line - ctx->start_line] - 1);
}
- return errors;
+ // Ensure we have at least one column of error.
+ if (start.column == column_end) column_end++;
+
+ // Insert into sorted position (insertion sort).
+ size_t index = 0;
+ while (
+ (index < ctx->count) &&
+ (
+ (ctx->errors[index].line < start.line) ||
+ ((ctx->errors[index].line == start.line) && (ctx->errors[index].column_start < start.column))
+ )
+ ) index++;
+
+ if (index < ctx->count) {
+ memmove(&ctx->errors[index + 1], &ctx->errors[index], sizeof(pm_parse_error_t) * (ctx->count - index));
+ }
+
+ ctx->errors[index] = (pm_parse_error_t) {
+ .error = diagnostic,
+ .line = start.line,
+ .column_start = start.column,
+ .column_end = column_end
+ };
+ ctx->count++;
}
-/* Append a literal string to the buffer. */
-#define pm_buffer_append_literal(buffer, str) pm_buffer_append_string(buffer, str, rb_strlen_lit(str))
+static inline pm_parse_error_t *
+pm_parse_errors_format_sort(const pm_parser_t *parser, size_t error_count, const pm_line_offset_list_t *line_offsets) {
+ pm_parse_error_t *errors = xcalloc(error_count, sizeof(pm_parse_error_t));
+ if (errors == NULL) return NULL;
+
+ pm_error_collect_t ctx = {
+ .errors = errors,
+ .count = 0,
+ .capacity = error_count,
+ .line_offsets = line_offsets,
+ .start_line = pm_parser_start_line(parser)
+ };
+
+ pm_parser_errors_each(parser, pm_error_collect_callback, &ctx);
+
+ 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;
+pm_parse_errors_format_line(const pm_parser_t *parser, const pm_line_offset_list_t *line_offsets, const char *number_prefix, int32_t line, uint32_t column_start, uint32_t column_end, VALUE buffer) {
+ int32_t line_delta = line - pm_parser_start_line(parser);
assert(line_delta >= 0);
size_t index = (size_t) line_delta;
- assert(index < newline_list->size);
+ assert(index < line_offsets->size);
- const uint8_t *start = &parser->start[newline_list->offsets[index]];
+ const uint8_t *start = &pm_parser_start(parser)[line_offsets->offsets[index]];
const uint8_t *end;
- if (index >= newline_list->size - 1) {
- end = parser->end;
+ if (index >= line_offsets->size - 1) {
+ end = pm_parser_end(parser);
} else {
- end = &parser->start[newline_list->offsets[index + 1]];
+ end = &pm_parser_start(parser)[line_offsets->offsets[index + 1]];
}
- pm_buffer_append_format(buffer, number_prefix, line);
+ rb_str_catf(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;
+ const uint8_t *end_candidate = start + column_end + PM_ERROR_TRUNCATE;
+
+ for (const uint8_t *ptr = start; ptr < end_candidate;) {
+ size_t char_width = pm_parser_encoding_char_width(parser, ptr, pm_parser_end(parser) - ptr);
+
+ // If we failed to decode a character, then just bail out and
+ // truncate at the fixed width.
+ if (char_width == 0) break;
+
+ // If this next character would go past the end candidate,
+ // then we need to truncate before it.
+ if (ptr + char_width > end_candidate) {
+ end_candidate = ptr;
+ break;
+ }
+
+ ptr += char_width;
+ }
+
+ end = end_candidate;
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);
+ rb_str_cat(buffer, "... ", 4);
start += column_start;
}
- pm_buffer_append_string(buffer, (const char *) start, (size_t) (end - start));
+ rb_str_cat(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);
+ rb_str_cat(buffer, " ...\n", 5);
+ } else if (end == pm_parser_end(parser) && end[-1] != '\n') {
+ rb_str_cat(buffer, "\n", 1);
}
}
/**
- * Format the errors on the parser into the given buffer.
+ * Format a pre-sorted array of errors 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, int highlight, bool inline_messages) {
- assert(error_list->size != 0);
+pm_parse_errors_format_with(const pm_parser_t *parser, pm_parse_error_t *errors, size_t error_count, VALUE buffer, int highlight, bool inline_messages) {
+ assert(error_count != 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;
+ const int32_t start_line = pm_parser_start_line(parser);
+ const pm_line_offset_list_t *line_offsets = pm_parser_line_offsets(parser);
// 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;
+ int32_t last_line_number = errors[error_count - 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
@@ -10824,11 +10919,10 @@ pm_parse_errors_format(const pm_parser_t *parser, const pm_list_t *error_list, p
// 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;
+ int32_t last_line = pm_parser_start_line(parser) - 1;
uint32_t last_column_start = 0;
- const pm_encoding_t *encoding = parser->encoding;
- for (size_t index = 0; index < error_list->size; index++) {
+ for (size_t index = 0; index < error_count; index++) {
pm_parse_error_t *error = &errors[index];
// Here we determine how many lines of padding of the source to display,
@@ -10836,42 +10930,42 @@ pm_parse_errors_format(const pm_parser_t *parser, const pm_list_t *error_list, p
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);
+ rb_str_cat(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);
+ rb_str_cat(buffer, " ", 2);
+ pm_parse_errors_format_line(parser, line_offsets, 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);
+ rb_str_cat(buffer, " ", 2);
+ pm_parse_errors_format_line(parser, line_offsets, 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 (highlight > 1) {
- pm_buffer_append_literal(buffer, PM_COLOR_RED "> " PM_COLOR_RESET);
+ rb_str_cat_cstr(buffer, PM_COLOR_RED "> " PM_COLOR_RESET);
} else if (highlight > 0) {
- pm_buffer_append_literal(buffer, PM_COLOR_BOLD "> " PM_COLOR_RESET);
+ rb_str_cat_cstr(buffer, PM_COLOR_BOLD "> " PM_COLOR_RESET);
} else {
- pm_buffer_append_literal(buffer, "> ");
+ rb_str_cat_cstr(buffer, "> ");
}
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++) {
+ for (size_t next_index = index + 1; next_index < error_count; 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);
+ pm_parse_errors_format_line(parser, line_offsets, 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');
+ const uint8_t *start = &pm_parser_start(parser)[line_offsets->offsets[error->line - start_line]];
+ if (start == pm_parser_end(parser)) rb_str_cat(buffer, "\n", 1);
// 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
@@ -10882,59 +10976,59 @@ pm_parse_errors_format(const pm_parser_t *parser, const pm_list_t *error_list, p
// 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);
+ rb_str_cat(buffer, " ", 2);
+ rb_str_cat(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);
+ rb_str_cat(buffer, " ", 4);
column = last_column_start;
}
while (column < error->column_start) {
- pm_buffer_append_byte(buffer, ' ');
+ rb_str_cat(buffer, " ", 1);
- size_t char_width = encoding->char_width(start + column, parser->end - (start + column));
+ size_t char_width = pm_parser_encoding_char_width(parser, start + column, pm_parser_end(parser) - (start + column));
column += (char_width == 0 ? 1 : char_width);
}
- if (highlight > 1) pm_buffer_append_literal(buffer, PM_COLOR_RED);
- else if (highlight > 0) pm_buffer_append_literal(buffer, PM_COLOR_BOLD);
- pm_buffer_append_byte(buffer, '^');
+ if (highlight > 1) rb_str_cat_cstr(buffer, PM_COLOR_RED);
+ else if (highlight > 0) rb_str_cat_cstr(buffer, PM_COLOR_BOLD);
+ rb_str_cat(buffer, "^", 1);
- size_t char_width = encoding->char_width(start + column, parser->end - (start + column));
+ size_t char_width = pm_parser_encoding_char_width(parser, start + column, pm_parser_end(parser) - (start + column));
column += (char_width == 0 ? 1 : char_width);
while (column < error->column_end) {
- pm_buffer_append_byte(buffer, '~');
+ rb_str_cat(buffer, "~", 1);
- size_t char_width = encoding->char_width(start + column, parser->end - (start + column));
+ size_t char_width = pm_parser_encoding_char_width(parser, start + column, pm_parser_end(parser) - (start + column));
column += (char_width == 0 ? 1 : char_width);
}
- if (highlight > 0) pm_buffer_append_literal(buffer, PM_COLOR_RESET);
+ if (highlight > 0) rb_str_cat_cstr(buffer, PM_COLOR_RESET);
if (inline_messages) {
- pm_buffer_append_byte(buffer, ' ');
+ rb_str_cat(buffer, " ", 1);
assert(error->error != NULL);
- const char *message = error->error->message;
- pm_buffer_append_string(buffer, message, strlen(message));
+ const char *message = pm_diagnostic_message(error->error);
+ rb_str_cat(buffer, message, strlen(message));
}
- pm_buffer_append_byte(buffer, '\n');
+ rb_str_cat(buffer, "\n", 1);
// 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;
- if (index == error_list->size - 1) {
- next_line = (((int32_t) newline_list->size) + parser->start_line);
+ if (index == error_count - 1) {
+ next_line = (((int32_t) line_offsets->size) + pm_parser_start_line(parser));
// If the file ends with a newline, subtract one from our "next_line"
// so that we don't output an extra line at the end of the file
- if ((parser->start + newline_list->offsets[newline_list->size - 1]) == parser->end) {
+ if ((pm_parser_start(parser) + line_offsets->offsets[line_offsets->size - 1]) == pm_parser_end(parser)) {
next_line--;
}
}
@@ -10943,18 +11037,30 @@ pm_parse_errors_format(const pm_parser_t *parser, const pm_list_t *error_list, p
}
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);
+ rb_str_cat(buffer, " ", 2);
+ pm_parse_errors_format_line(parser, line_offsets, 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);
+ rb_str_cat(buffer, " ", 2);
+ pm_parse_errors_format_line(parser, line_offsets, error_format.number_prefix, ++last_line, 0, 0, buffer);
}
}
- // Finally, we'll free the array of errors that we allocated.
- xfree(errors);
+}
+
+/**
+ * Format the errors on the parser into the given buffer.
+ */
+static void
+pm_parse_errors_format(const pm_parser_t *parser, size_t error_count, VALUE buffer, int highlight, bool inline_messages) {
+ const pm_line_offset_list_t *line_offsets = pm_parser_line_offsets(parser);
+
+ pm_parse_error_t *errors = pm_parse_errors_format_sort(parser, error_count, line_offsets);
+ if (errors == NULL) return;
+
+ pm_parse_errors_format_with(parser, errors, error_count, buffer, highlight, inline_messages);
+ SIZED_FREE_N(errors, error_count);
}
#undef PM_ERROR_TRUNCATE
@@ -10969,23 +11075,136 @@ pm_parse_errors_format(const pm_parser_t *parser, const pm_list_t *error_list, p
* as well.
*/
static bool
-pm_parse_process_error_utf8_p(const pm_parser_t *parser, const pm_location_t *location)
+pm_parse_process_error_utf8_p(const pm_parser_t *parser, 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 size_t start_line = pm_line_offset_list_line_column(pm_parser_line_offsets(parser), location.start, 1).line;
+ const size_t end_line = pm_line_offset_list_line_column(pm_parser_line_offsets(parser), location.start + location.length, 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;
+ const pm_line_offset_list_t *line_offsets = pm_parser_line_offsets(parser);
+ const uint8_t *start = pm_parser_start(parser) + line_offsets->offsets[start_line - 1];
+ const uint8_t *end = ((end_line == line_offsets->size) ? pm_parser_end(parser) : (pm_parser_start(parser) + line_offsets->offsets[end_line]));
+ rb_encoding *utf8 = rb_utf8_encoding();
while (start < end) {
- if ((width = pm_encoding_utf_8_char_width(start, end - start)) == 0) return false;
- start += width;
+ int width = rb_enc_precise_mbclen((const char *) start, (const char *) end, utf8);
+ if (!MBCLEN_CHARFOUND_P(width)) return false;
+ start += MBCLEN_CHARFOUND_LEN(width);
}
return true;
}
+/** Context for the error processing callback used in pm_parse_process_error. */
+typedef struct {
+ const pm_parse_result_t *result;
+ const pm_parser_t *parser;
+ const pm_string_t *filepath;
+ VALUE buffer;
+ int highlight;
+ bool valid_utf8;
+ bool found_argument_error;
+ bool found_load_error;
+ VALUE early_return;
+ const pm_diagnostic_t *first_error;
+ size_t error_count;
+} pm_process_error_ctx_t;
+
+static void
+pm_process_error_check_callback(const pm_diagnostic_t *diagnostic, void *data)
+{
+ pm_process_error_ctx_t *ctx = (pm_process_error_ctx_t *) data;
+ pm_location_t loc = pm_diagnostic_location(diagnostic);
+
+ if (ctx->first_error == NULL) ctx->first_error = diagnostic;
+ ctx->error_count++;
+
+ switch (pm_diagnostic_error_level(diagnostic)) {
+ case PM_ERROR_LEVEL_SYNTAX:
+ if (ctx->valid_utf8 && !pm_parse_process_error_utf8_p(ctx->parser, loc)) {
+ ctx->valid_utf8 = false;
+ }
+ break;
+ case PM_ERROR_LEVEL_ARGUMENT: {
+ if (ctx->found_argument_error || ctx->found_load_error) break;
+ ctx->found_argument_error = true;
+
+ int32_t line_number = (int32_t) pm_location_line_number(ctx->parser, &loc);
+
+ rb_str_catf(
+ ctx->buffer,
+ "%.*s:%" PRIi32 ": %s",
+ (int) pm_string_length(ctx->filepath),
+ pm_string_source(ctx->filepath),
+ line_number,
+ pm_diagnostic_message(diagnostic)
+ );
+
+ if (pm_parse_process_error_utf8_p(ctx->parser, loc)) {
+ rb_str_cat(ctx->buffer, "\n", 1);
+ // Format just this one error. We construct a single-element sorted
+ // array manually and call the format function with count=1.
+ const pm_line_offset_list_t *line_offsets = pm_parser_line_offsets(ctx->parser);
+ int32_t start_line = pm_parser_start_line(ctx->parser);
+ pm_line_column_t start_lc = pm_line_offset_list_line_column(line_offsets, loc.start, start_line);
+ pm_line_column_t end_lc = pm_line_offset_list_line_column(line_offsets, loc.start + loc.length, start_line);
+
+ uint32_t col_end;
+ if (start_lc.line == end_lc.line) {
+ col_end = end_lc.column;
+ } else {
+ col_end = (uint32_t) (line_offsets->offsets[start_lc.line - start_line + 1] - line_offsets->offsets[start_lc.line - start_line] - 1);
+ }
+ if (start_lc.column == col_end) col_end++;
+
+ pm_parse_error_t single_error = {
+ .error = diagnostic,
+ .line = start_lc.line,
+ .column_start = start_lc.column,
+ .column_end = col_end
+ };
+ pm_parse_errors_format_with(ctx->parser, &single_error, 1, ctx->buffer, ctx->highlight, false);
+ }
+
+ ctx->early_return = rb_exc_new_str(rb_eArgError, ctx->buffer);
+ break;
+ }
+ case PM_ERROR_LEVEL_LOAD: {
+ if (ctx->found_argument_error || ctx->found_load_error) break;
+ ctx->found_load_error = true;
+
+ VALUE message = rb_enc_str_new_cstr(pm_diagnostic_message(diagnostic), rb_locale_encoding());
+ VALUE value = rb_exc_new3(rb_eLoadError, message);
+ rb_ivar_set(value, rb_intern_const("@path"), Qnil);
+ ctx->early_return = value;
+ break;
+ }
+ }
+}
+
+/** Callback for formatting non-UTF8 errors. */
+typedef struct {
+ const pm_parser_t *parser;
+ const pm_string_t *filepath;
+ VALUE buffer;
+ bool first;
+} pm_error_simple_format_ctx_t;
+
+static void
+pm_error_simple_format_callback(const pm_diagnostic_t *diagnostic, void *data)
+{
+ pm_error_simple_format_ctx_t *ctx = (pm_error_simple_format_ctx_t *) data;
+ pm_location_t loc = pm_diagnostic_location(diagnostic);
+
+ if (!ctx->first) rb_str_cat(ctx->buffer, "\n", 1);
+ ctx->first = false;
+
+ rb_str_catf(ctx->buffer, "%.*s:%" PRIi32 ": %s",
+ (int) pm_string_length(ctx->filepath),
+ pm_string_source(ctx->filepath),
+ (int32_t) pm_location_line_number(ctx->parser, &loc),
+ pm_diagnostic_message(diagnostic));
+}
+
/**
* Generate an error object from the given parser that contains as much
* information as possible about the errors that were encountered.
@@ -10993,12 +11212,11 @@ pm_parse_process_error_utf8_p(const pm_parser_t *parser, const pm_location_t *lo
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;
+ const pm_parser_t *parser = result->parser;
+ size_t error_count = pm_parser_errors_size(parser);
- pm_buffer_t buffer = { 0 };
- const pm_string_t *filepath = &parser->filepath;
+ VALUE buffer = rb_str_buf_new(0);
+ const pm_string_t *filepath = pm_parser_filepath(parser);
int highlight = rb_stderr_tty_p();
if (highlight) {
@@ -11006,90 +11224,98 @@ pm_parse_process_error(const pm_parse_result_t *result)
highlight = (no_color == NULL || no_color[0] == '\0') ? 2 : 1;
}
- 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, highlight, false);
- }
+ // First pass: check for argument/load errors and UTF-8 validity.
+ pm_process_error_ctx_t ctx = {
+ .result = result,
+ .parser = parser,
+ .filepath = filepath,
+ .buffer = buffer,
+ .highlight = highlight,
+ .valid_utf8 = true,
+ .found_argument_error = false,
+ .found_load_error = false,
+ .early_return = Qundef,
+ .first_error = NULL,
+ .error_count = 0
+ };
- VALUE value = rb_exc_new(rb_eArgError, pm_buffer_value(&buffer), pm_buffer_length(&buffer));
- pm_buffer_free(&buffer);
+ pm_parser_errors_each(parser, pm_process_error_check_callback, &ctx);
- 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;
- }
- }
+ // If we found an argument or load error, return it immediately.
+ if (ctx.early_return != Qundef) {
+ return ctx.early_return;
}
- pm_buffer_append_format(
- &buffer,
+ // Format the header line.
+ pm_location_t first_loc = pm_diagnostic_location(ctx.first_error);
+ rb_str_catf(
+ 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" : ""
+ (int32_t) pm_location_line_number(parser, &first_loc),
+ (error_count > 1) ? "s" : ""
);
- if (valid_utf8) {
- pm_parse_errors_format(parser, &parser->error_list, &buffer, highlight, true);
+ if (ctx.valid_utf8) {
+ pm_parse_errors_format(parser, error_count, buffer, highlight, 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);
- }
+ pm_error_simple_format_ctx_t simple_ctx = {
+ .parser = parser,
+ .filepath = filepath,
+ .buffer = buffer,
+ .first = true
+ };
+ pm_parser_errors_each(parser, pm_error_simple_format_callback, &simple_ctx);
}
- 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_enc_associate(buffer, result->node.encoding);
+ VALUE error = rb_exc_new_str(rb_eSyntaxError, buffer);
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;
}
+/** Context for interning constants via callback. */
+typedef struct {
+ ID *constants;
+ rb_encoding *encoding;
+ size_t index;
+} pm_intern_constants_ctx_t;
+
+static void
+pm_intern_constants_callback(const pm_constant_t *constant, void *data)
+{
+ pm_intern_constants_ctx_t *ctx = (pm_intern_constants_ctx_t *) data;
+ ctx->constants[ctx->index++] = rb_intern3((const char *) pm_constant_start(constant), pm_constant_length(constant), ctx->encoding);
+}
+
+/** Context for emitting warnings via callback. */
+typedef struct {
+ const pm_parser_t *parser;
+ rb_encoding *encoding;
+ const char *filepath;
+} pm_warning_emit_ctx_t;
+
+static void
+pm_warning_emit_callback(const pm_diagnostic_t *diagnostic, void *data) {
+ pm_warning_emit_ctx_t *ctx = (pm_warning_emit_ctx_t *) data;
+ pm_location_t loc = pm_diagnostic_location(diagnostic);
+ int line = pm_location_line_number(ctx->parser, &loc);
+
+ if (pm_diagnostic_warning_level(diagnostic) == PM_WARNING_LEVEL_VERBOSE) {
+ rb_enc_compile_warning(ctx->encoding, ctx->filepath, line, "%s", pm_diagnostic_message(diagnostic));
+ }
+ else {
+ rb_enc_compile_warn(ctx->encoding, ctx->filepath, line, "%s", pm_diagnostic_message(diagnostic));
+ }
+}
+
/**
* 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
@@ -11098,7 +11324,7 @@ pm_parse_process_error(const pm_parse_result_t *result)
static VALUE
pm_parse_process(pm_parse_result_t *result, pm_node_t *node, VALUE *script_lines)
{
- pm_parser_t *parser = &result->parser;
+ 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.
@@ -11109,42 +11335,37 @@ pm_parse_process(pm_parse_result_t *result, pm_node_t *node, VALUE *script_lines
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);
+ const char *encoding_name = pm_parser_encoding_name(parser);
+ scope_node->encoding = rb_enc_find(encoding_name);
+ if (!scope_node->encoding) rb_bug("Encoding not found %s!", 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);
+ const pm_line_offset_list_t *line_offsets = pm_parser_line_offsets(parser);
+ *script_lines = rb_ary_new_capa(line_offsets->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));
+ for (size_t index = 0; index < line_offsets->size; index++) {
+ size_t offset = line_offsets->offsets[index];
+ size_t length = index == line_offsets->size - 1 ? ((size_t) (pm_parser_end(parser) - (pm_parser_start(parser) + offset))) : (line_offsets->offsets[index + 1] - offset);
+ rb_ary_push(*script_lines, rb_enc_str_new((const char *) pm_parser_start(parser) + 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);
- }
- }
+ pm_warning_emit_ctx_t warning_ctx = {
+ .parser = parser,
+ .encoding = scope_node->encoding,
+ .filepath = (const char *) pm_string_source(pm_parser_filepath(parser))
+ };
+ pm_parser_warnings_each(parser, pm_warning_emit_callback, &warning_ctx);
// If there are errors, raise an appropriate error and free the result.
- if (parser->error_list.size > 0) {
+ if (pm_parser_errors_size(parser) > 0) {
VALUE error = pm_parse_process_error(result);
// TODO: We need to set the backtrace.
@@ -11155,18 +11376,14 @@ pm_parse_process(pm_parse_result_t *result, pm_node_t *node, VALUE *script_lines
// Now set up the constant pool and intern all of the various constants into
// their corresponding IDs.
scope_node->parser = parser;
- scope_node->constants = parser->constant_pool.size ? xcalloc(parser->constant_pool.size, sizeof(ID)) : NULL;
+ scope_node->options = result->options;
+ scope_node->line_offsets = pm_parser_line_offsets(parser);
+ scope_node->start_line = pm_parser_start_line(parser);
+ size_t constants_size = pm_parser_constants_size(parser);
+ scope_node->constants = constants_size ? xmalloc(constants_size * sizeof(ID)) : NULL;
- 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);
- }
+ pm_intern_constants_ctx_t intern_ctx = { .constants = scope_node->constants, .encoding = scope_node->encoding, .index = 0 };
+ pm_parser_constants_each(parser, pm_intern_constants_callback, &intern_ctx);
// If we got here, this is a success and we can return Qnil to indicate that
// no error should be raised.
@@ -11205,22 +11422,22 @@ pm_options_frozen_string_literal_init(pm_options_t *options)
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;
+ const pm_line_offset_list_t *line_offsets = pm_parser_line_offsets(parser);
+ const char *start = (const char *) pm_parser_start(parser);
+ const char *end = (const char *) pm_parser_end(parser);
// 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];
+ size_t last_offset = line_offsets->offsets[line_offsets->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));
+ VALUE lines = rb_ary_new_capa(line_offsets->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;
+ for (size_t index = 0; index < line_offsets->size - 1; index++) {
+ size_t offset = line_offsets->offsets[index];
+ size_t length = line_offsets->offsets[index + 1] - offset;
rb_ary_push(lines, rb_enc_str_new(start + offset, length, scope_node->encoding));
}
@@ -11233,145 +11450,35 @@ pm_parse_file_script_lines(const pm_scope_node_t *scope_node, const pm_parser_t
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 = malloc(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;
+struct load_from_fd_args {
+ VALUE path;
+ VALUE io;
+ int open_mode;
+ int fd;
+};
- 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;
+static VALUE
+close_file(VALUE args)
+{
+ struct load_from_fd_args *arg = (void *)args;
+ if (arg->fd != -1) {
+ close(arg->fd);
}
-
- source = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
- if (source == MAP_FAILED) {
- close(fd);
- return PM_STRING_INIT_ERROR_GENERIC;
+ else if (!NIL_P(arg->io)) {
+ rb_io_close(arg->io);
}
+ return Qnil;
+}
- 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
+static VALUE
+load_content(VALUE args)
+{
+ struct load_from_fd_args *arg = (void *)args;
+ VALUE io = rb_io_fdopen(arg->fd, arg->open_mode, RSTRING_PTR(arg->path));
+ arg->io = io;
+ arg->fd = -1;
+ rb_io_wait(io, RB_INT2NUM(RUBY_IO_READABLE), Qnil);
+ return rb_funcall(io, rb_intern("read"), 0);
}
/**
@@ -11381,17 +11488,46 @@ pm_read_file(pm_string_t *string, const char *filepath)
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));
+ pm_source_init_result_t init_result;
+ result->source = pm_source_mapped_new(RSTRING_PTR(filepath), O_RDONLY | O_NONBLOCK, &init_result);
- if (init_result == PM_STRING_INIT_SUCCESS) {
- pm_options_frozen_string_literal_init(&result->options);
+ if (init_result == PM_SOURCE_INIT_SUCCESS) {
+ pm_options_frozen_string_literal_init(result->options);
return Qnil;
}
int err;
- if (init_result == PM_STRING_INIT_ERROR_DIRECTORY) {
+
+ // For non-regular files (pipes, character devices), we need to read
+ // through Ruby IO to properly release the GVL while waiting for data.
+ if (init_result == PM_SOURCE_INIT_ERROR_NON_REGULAR) {
+ struct load_from_fd_args args = {
+ .path = filepath,
+ .open_mode = O_RDONLY | O_NONBLOCK,
+ .fd = rb_cloexec_open(RSTRING_PTR(filepath), args.open_mode, 0),
+ .io = Qnil,
+ };
+ if (args.fd == -1) goto error_generic;
+ VALUE contents = rb_ensure(load_content, (VALUE)&args, close_file, (VALUE)&args);
+
+ if (!RB_TYPE_P(contents, T_STRING)) goto error_generic;
+
+ long len = RSTRING_LEN(contents);
+ if (len < 0) goto error_generic;
+
+ size_t length = (size_t) len;
+ uint8_t *source_data = xmalloc(length);
+ memcpy(source_data, RSTRING_PTR(contents), length);
+ result->source = pm_source_owned_new(source_data, length);
+
+ pm_options_frozen_string_literal_init(result->options);
+ return Qnil;
+ }
+
+ if (init_result == PM_SOURCE_INIT_ERROR_DIRECTORY) {
err = EISDIR;
} else {
+error_generic:
#ifdef _WIN32
err = rb_w32_map_errno(GetLastError());
#else
@@ -11425,11 +11561,13 @@ 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));
+ 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);
+ pm_options_version_for_current_ruby_set(result->options);
+
+ result->parser = pm_parser_new(result->arena, pm_source_source(result->source), pm_source_length(result->source), result->options);
+ pm_node_t *node = pm_parse(result->parser);
VALUE error = pm_parse_process(result, node, script_lines);
@@ -11442,7 +11580,7 @@ pm_parse_file(pm_parse_result_t *result, VALUE filepath, VALUE *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));
+ rb_hash_aset(constant_script_lines, filepath, pm_parse_file_script_lines(&result->node, result->parser));
}
}
@@ -11478,16 +11616,18 @@ pm_parse_string(pm_parse_result_t *result, VALUE source, VALUE filepath, VALUE *
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));
+ pm_options_frozen_string_literal_init(result->options);
+ result->source = pm_source_constant_new((const uint8_t *) RSTRING_PTR(source), (size_t) 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));
+ 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);
+ pm_options_version_for_current_ruby_set(result->options);
+
+ result->parser = pm_parser_new(result->arena, pm_source_source(result->source), pm_source_length(result->source), result->options);
+ pm_node_t *node = pm_parse(result->parser);
return pm_parse_process(result, node, script_lines);
}
@@ -11504,6 +11644,8 @@ pm_parse_stdin_eof(void *stream)
return wrapped_stdin->eof_seen;
}
+VALUE rb_io_gets_limit_internal(VALUE io, long limit);
+
/**
* An implementation of fgets that is suitable for use with Ruby IO objects.
*/
@@ -11514,7 +11656,7 @@ pm_parse_stdin_fgets(char *string, int size, void *stream)
struct rb_stdin_wrapper * wrapped_stdin = (struct rb_stdin_wrapper *)stream;
- VALUE line = rb_funcall(wrapped_stdin->rb_stdin, rb_intern("gets"), 1, INT2FIX(size - 1));
+ VALUE line = rb_io_gets_limit_internal(wrapped_stdin->rb_stdin, size - 1);
if (NIL_P(line)) {
return NULL;
}
@@ -11546,20 +11688,15 @@ void rb_reset_argf_lineno(long n);
VALUE
pm_parse_stdin(pm_parse_result_t *result)
{
- pm_options_frozen_string_literal_init(&result->options);
+ pm_options_frozen_string_literal_init(result->options);
struct rb_stdin_wrapper wrapped_stdin = {
rb_stdin,
0
};
- pm_buffer_t buffer;
- pm_node_t *node = pm_parse_stream(&result->parser, &buffer, (void *) &wrapped_stdin, pm_parse_stdin_fgets, pm_parse_stdin_eof, &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));
+ result->source = pm_source_stream_new((void *) &wrapped_stdin, pm_parse_stdin_fgets, pm_parse_stdin_eof);
+ pm_node_t *node = pm_parse_stream(&result->parser, result->arena, result->source, result->options);
// 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.
@@ -11568,6 +11705,14 @@ pm_parse_stdin(pm_parse_result_t *result)
return pm_parse_process(result, node, NULL);
}
+#define PM_VERSION_FOR_RELEASE(major, minor) PM_VERSION_FOR_RELEASE_IMPL(major, minor)
+#define PM_VERSION_FOR_RELEASE_IMPL(major, minor) #major "." #minor
+
+void pm_options_version_for_current_ruby_set(pm_options_t *options) {
+ const char *version = PM_VERSION_FOR_RELEASE(RUBY_API_VERSION_MAJOR, RUBY_API_VERSION_MINOR);
+ pm_options_version_set(options, version, strlen(version));
+}
+
#undef NEW_ISEQ
#define NEW_ISEQ OLD_ISEQ
diff --git a/prism_compile.h b/prism_compile.h
index c032449bd6..4485793902 100644
--- a/prism_compile.h
+++ b/prism_compile.h
@@ -16,6 +16,82 @@ typedef struct pm_local_index_struct {
// A declaration for the struct that lives in compile.c.
struct iseq_link_anchor;
+/**
+ * A direct-indexed lookup table mapping constant IDs to local variable indices.
+ * Regular constant IDs (1..constants_size) index directly. Special forwarding
+ * parameter IDs (idMULT|FLAG, etc.) are mapped to 4 extra slots at the end.
+ *
+ * All lookups are O(1) — a single array dereference.
+ * The table is arena-allocated for child scopes (no explicit free needed).
+ */
+typedef struct {
+ /** Array of local indices, indexed by constant_id. -1 means not present. */
+ int *values;
+
+ /** Total number of slots (constants_size + PM_INDEX_LOOKUP_SPECIALS). */
+ int capacity;
+
+ /** Whether the values array is heap-allocated and needs explicit free. */
+ bool owned;
+} pm_index_lookup_table_t;
+
+/** Number of extra slots for special forwarding parameter IDs. */
+#define PM_INDEX_LOOKUP_SPECIALS 4
+
+/** Slot offsets for special forwarding parameters (relative to constants_size). */
+#define PM_SPECIAL_CONSTANT_FLAG ((pm_constant_id_t) (1 << 31))
+#define PM_INDEX_LOOKUP_SPECIAL_MULT 0
+#define PM_INDEX_LOOKUP_SPECIAL_POW 1
+#define PM_INDEX_LOOKUP_SPECIAL_AND 2
+#define PM_INDEX_LOOKUP_SPECIAL_DOT3 3
+
+/**
+ * Special constant IDs for forwarding parameters. These use bit 31 to
+ * distinguish them from regular prism constant pool IDs. The lower bits
+ * encode which special slot (0-3) they map to in the lookup table.
+ */
+#define PM_CONSTANT_MULT ((pm_constant_id_t) (PM_SPECIAL_CONSTANT_FLAG | PM_INDEX_LOOKUP_SPECIAL_MULT))
+#define PM_CONSTANT_POW ((pm_constant_id_t) (PM_SPECIAL_CONSTANT_FLAG | PM_INDEX_LOOKUP_SPECIAL_POW))
+#define PM_CONSTANT_AND ((pm_constant_id_t) (PM_SPECIAL_CONSTANT_FLAG | PM_INDEX_LOOKUP_SPECIAL_AND))
+#define PM_CONSTANT_DOT3 ((pm_constant_id_t) (PM_SPECIAL_CONSTANT_FLAG | PM_INDEX_LOOKUP_SPECIAL_DOT3))
+
+static inline int
+pm_index_lookup_table_index(const pm_index_lookup_table_t *table, pm_constant_id_t key)
+{
+ if (LIKELY(!(key & PM_SPECIAL_CONSTANT_FLAG))) {
+ return (int) key - 1;
+ }
+ return table->capacity - PM_INDEX_LOOKUP_SPECIALS + (int)(key & ~PM_SPECIAL_CONSTANT_FLAG);
+}
+
+static inline void
+pm_index_lookup_table_insert(pm_index_lookup_table_t *table, pm_constant_id_t key, int value)
+{
+ int idx = pm_index_lookup_table_index(table, key);
+ RUBY_ASSERT(idx >= 0 && idx < table->capacity);
+ table->values[idx] = value;
+}
+
+static inline int
+pm_index_lookup_table_lookup(const pm_index_lookup_table_t *table, pm_constant_id_t key, int *value)
+{
+ int idx = pm_index_lookup_table_index(table, key);
+ RUBY_ASSERT(idx >= 0 && idx < table->capacity);
+ if (table->values[idx] == -1) return 0;
+ *value = table->values[idx];
+ return 1;
+}
+
+static inline void
+pm_index_lookup_table_init_heap(pm_index_lookup_table_t *table, int constants_size)
+{
+ int cap = constants_size + PM_INDEX_LOOKUP_SPECIALS;
+ table->values = (int *) ruby_xmalloc(cap * sizeof(int));
+ memset(table->values, -1, cap * sizeof(int));
+ table->capacity = cap;
+ table->owned = true;
+}
+
// 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 {
@@ -27,6 +103,9 @@ typedef struct pm_scope_node {
pm_constant_id_list_t locals;
const pm_parser_t *parser;
+ const pm_options_t *options;
+ const pm_line_offset_list_t *line_offsets;
+ int32_t start_line;
rb_encoding *encoding;
/**
@@ -51,7 +130,14 @@ typedef struct pm_scope_node {
int local_table_for_iseq_size;
ID *constants;
- st_table *index_lookup_table;
+
+ /**
+ * A flat lookup table mapping constant IDs (or special IDs) to local
+ * variable indices. When allocated from the compile data arena (child
+ * scopes), no explicit free is needed. When heap-allocated (top-level
+ * scope in pm_parse_process), owned is set to true so destroy can free it.
+ */
+ pm_index_lookup_table_t index_lookup_table;
// The current coverage setting, passed down through the various scopes.
int coverage_enabled;
@@ -61,20 +147,30 @@ typedef struct pm_scope_node {
* the instructions pertaining to BEGIN{} nodes.
*/
struct iseq_link_anchor *pre_execution_anchor;
+
+ /**
+ * Cached line hint for line offset list lookups. Since the compiler walks
+ * the AST roughly in source order, consecutive lookups tend to be for
+ * nearby byte offsets. This avoids repeated binary searches.
+ */
+ size_t last_line;
} 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 arena allocator for AST-lifetime memory. */
+ pm_arena_t *arena;
+
/** The parser that will do the actual parsing. */
- pm_parser_t parser;
+ pm_parser_t *parser;
/** The options that will be passed to the parser. */
- pm_options_t options;
+ pm_options_t *options;
- /** The input that represents the source to be parsed. */
- pm_string_t input;
+ /** The source backing the parse (file, string, or stream). */
+ pm_source_t *source;
/** The resulting scope node that will hold the generated AST. */
pm_scope_node_t node;
@@ -83,17 +179,13 @@ typedef struct {
bool parsed;
} pm_parse_result_t;
-#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))
-
+void pm_parse_result_init(pm_parse_result_t *result);
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_options_version_for_current_ruby_set(pm_options_t *options);
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, int *error_state);
@@ -101,5 +193,6 @@ rb_iseq_t *pm_iseq_new_top(pm_scope_node_t *node, VALUE name, VALUE path, VALUE
rb_iseq_t *pm_iseq_new_main(pm_scope_node_t *node, VALUE path, VALUE realpath, const rb_iseq_t *parent, int opt, int *error_state);
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, int *error_state);
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 *option, int *error_state);
+rb_iseq_t *pm_iseq_build(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 *option);
VALUE pm_iseq_compile_node(rb_iseq_t *iseq, pm_scope_node_t *node);
diff --git a/prism_xallocator.h b/prism_xallocator.h
new file mode 100644
index 0000000000..b1fcce48d8
--- /dev/null
+++ b/prism_xallocator.h
@@ -0,0 +1,6 @@
+#ifndef PRISM_XALLOCATOR_H
+#define PRISM_XALLOCATOR_H
+
+#include "ruby/internal/xmalloc.h"
+
+#endif /* PRISM_XALLOCATOR_H */
diff --git a/proc.c b/proc.c
index ae1068e24f..bfdc2cc25b 100644
--- a/proc.c
+++ b/proc.c
@@ -98,7 +98,7 @@ proc_memsize(const void *ptr)
return sizeof(rb_proc_t);
}
-static const rb_data_type_t proc_data_type = {
+const rb_data_type_t ruby_proc_data_type = {
"proc",
{
proc_mark_and_move,
@@ -109,6 +109,8 @@ static const rb_data_type_t proc_data_type = {
0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED
};
+#define proc_data_type ruby_proc_data_type
+
VALUE
rb_proc_alloc(VALUE klass)
{
@@ -256,7 +258,7 @@ static void
binding_free(void *ptr)
{
RUBY_FREE_ENTER("binding");
- ruby_xfree(ptr);
+ SIZED_FREE((rb_binding_t *)ptr);
RUBY_FREE_LEAVE("binding");
}
@@ -357,7 +359,7 @@ rb_binding_new(void)
*
* # evaluate template in context of the object
* eval(template, user.get_binding)
- * #=> {:name=>"Joan", :position=>"manager"}
+ * #=> {name: "Joan", position: "manager"}
*
* Binding#local_variable_get can be used to access the variables
* whose names are reserved Ruby keywords:
@@ -383,19 +385,31 @@ rb_f_binding(VALUE self)
}
/*
- * call-seq:
- * binding.eval(string [, filename [,lineno]]) -> obj
+ * call-seq:
+ * binding.eval(string, filename = default_filename, lineno = 1) -> obj
*
- * Evaluates the Ruby expression(s) in <em>string</em>, in the
- * <em>binding</em>'s context. If the optional <em>filename</em> and
- * <em>lineno</em> parameters are present, they will be used when
- * reporting syntax errors.
+ * Evaluates the Ruby expression(s) in +string+ in the context of
+ * +self+. Returns the result of the last expression:
*
- * def get_binding(param)
- * binding
- * end
+ * def get_binding(param) = binding
* b = get_binding("hello")
* b.eval("param") #=> "hello"
+ *
+ * If the optional +filename+ is given, it will be used as the
+ * filename of the evaluation (for <tt>__FILE__</tt> and errors).
+ * Otherwise, it will default to <tt>(eval at __FILE__:__LINE__)</tt>
+ * where <tt>__FILE__</tt> and <tt>__LINE__</tt> are the filename and
+ * line number of the caller, respectively:
+ *
+ * b.eval("puts __FILE__") # => "(eval at test.rb:4)"
+ * b.eval("puts __FILE__", "foobar.rb") # => "foobar.rb"
+ *
+ * If the optional +lineno+ is given, it will be used as the
+ * line number of the evaluation (for <tt>__LINE__</tt> and errors).
+ * Otherwise, it will default to 1:
+ *
+ * b.eval("puts __LINE__") # => 1
+ * b.eval("puts __LINE__", "foobar.rb", 10) # => 10
*/
static VALUE
@@ -409,7 +423,7 @@ bind_eval(int argc, VALUE *argv, VALUE bindval)
}
static const VALUE *
-get_local_variable_ptr(const rb_env_t **envp, ID lid)
+get_local_variable_ptr(const rb_env_t **envp, ID lid, bool search_outer)
{
const rb_env_t *env = *envp;
do {
@@ -446,7 +460,7 @@ get_local_variable_ptr(const rb_env_t **envp, ID lid)
*envp = NULL;
return NULL;
}
- } while ((env = rb_vm_env_prev_env(env)) != NULL);
+ } while (search_outer && (env = rb_vm_env_prev_env(env)) != NULL);
*envp = NULL;
return NULL;
@@ -514,6 +528,12 @@ rb_numparam_id_p(ID id)
return (tNUMPARAM_1 << ID_SCOPE_SHIFT) <= id && id < ((tNUMPARAM_1 + 9) << ID_SCOPE_SHIFT);
}
+int
+rb_implicit_param_p(ID id)
+{
+ return id == idItImplicit || rb_numparam_id_p(id);
+}
+
/*
* call-seq:
* binding.local_variable_get(symbol) -> obj
@@ -548,7 +568,7 @@ bind_local_variable_get(VALUE bindval, VALUE sym)
GetBindingPtr(bindval, bind);
env = VM_ENV_ENVVAL_PTR(vm_block_ep(&bind->block));
- if ((ptr = get_local_variable_ptr(&env, lid)) != NULL) {
+ if ((ptr = get_local_variable_ptr(&env, lid, TRUE)) != NULL) {
return *ptr;
}
@@ -600,7 +620,7 @@ bind_local_variable_set(VALUE bindval, VALUE sym, VALUE val)
GetBindingPtr(bindval, bind);
env = VM_ENV_ENVVAL_PTR(vm_block_ep(&bind->block));
- if ((ptr = get_local_variable_ptr(&env, lid)) == NULL) {
+ if ((ptr = get_local_variable_ptr(&env, lid, TRUE)) == NULL) {
/* not found. create new env */
ptr = rb_binding_add_dynavars(bindval, bind, 1, &lid);
env = VM_ENV_ENVVAL_PTR(vm_block_ep(&bind->block));
@@ -640,10 +660,140 @@ bind_local_variable_defined_p(VALUE bindval, VALUE sym)
const rb_env_t *env;
if (!lid) return Qfalse;
+ if (rb_numparam_id_p(lid)) {
+ rb_name_err_raise("numbered parameter '%1$s' is not a local variable",
+ bindval, ID2SYM(lid));
+ }
+
+ GetBindingPtr(bindval, bind);
+ env = VM_ENV_ENVVAL_PTR(vm_block_ep(&bind->block));
+ return RBOOL(get_local_variable_ptr(&env, lid, TRUE));
+}
+
+/*
+ * call-seq:
+ * binding.implicit_parameters -> Array
+ *
+ * Returns the names of numbered parameters and "it" parameter
+ * that are defined in the binding.
+ *
+ * def foo
+ * [42].each do
+ * it
+ * binding.implicit_parameters #=> [:it]
+ * end
+ *
+ * { k: 42 }.each do
+ * _2
+ * binding.implicit_parameters #=> [:_1, :_2]
+ * end
+ * end
+ *
+ */
+static VALUE
+bind_implicit_parameters(VALUE bindval)
+{
+ const rb_binding_t *bind;
+ const rb_env_t *env;
+
+ GetBindingPtr(bindval, bind);
+ env = VM_ENV_ENVVAL_PTR(vm_block_ep(&bind->block));
+
+ if (get_local_variable_ptr(&env, idItImplicit, FALSE)) {
+ return rb_ary_new_from_args(1, ID2SYM(idIt));
+ }
+
+ env = VM_ENV_ENVVAL_PTR(vm_block_ep(&bind->block));
+ return rb_vm_env_numbered_parameters(env);
+}
+
+/*
+ * call-seq:
+ * binding.implicit_parameter_get(symbol) -> obj
+ *
+ * Returns the value of the numbered parameter or "it" parameter.
+ *
+ * def foo
+ * [42].each do
+ * it
+ * binding.implicit_parameter_get(:it) #=> 42
+ * end
+ *
+ * { k: 42 }.each do
+ * _2
+ * binding.implicit_parameter_get(:_1) #=> :k
+ * binding.implicit_parameter_get(:_2) #=> 42
+ * end
+ * end
+ *
+ */
+static VALUE
+bind_implicit_parameter_get(VALUE bindval, VALUE sym)
+{
+ ID lid = check_local_id(bindval, &sym);
+ const rb_binding_t *bind;
+ const VALUE *ptr;
+ const rb_env_t *env;
+
+ if (lid == idIt) lid = idItImplicit;
+
+ if (!lid || !rb_implicit_param_p(lid)) {
+ rb_name_err_raise("'%1$s' is not an implicit parameter",
+ bindval, sym);
+ }
+
+ GetBindingPtr(bindval, bind);
+
+ env = VM_ENV_ENVVAL_PTR(vm_block_ep(&bind->block));
+ if ((ptr = get_local_variable_ptr(&env, lid, FALSE)) != NULL) {
+ return *ptr;
+ }
+
+ if (lid == idItImplicit) lid = idIt;
+ rb_name_err_raise("implicit parameter '%1$s' is not defined for %2$s", bindval, ID2SYM(lid));
+ UNREACHABLE_RETURN(Qundef);
+}
+
+/*
+ * call-seq:
+ * binding.implicit_parameter_defined?(symbol) -> obj
+ *
+ * Returns +true+ if the numbered parameter or "it" parameter exists.
+ *
+ * def foo
+ * [42].each do
+ * it
+ * binding.implicit_parameter_defined?(:it) #=> true
+ * binding.implicit_parameter_defined?(:_1) #=> false
+ * end
+ *
+ * { k: 42 }.each do
+ * _2
+ * binding.implicit_parameter_defined?(:_1) #=> true
+ * binding.implicit_parameter_defined?(:_2) #=> true
+ * binding.implicit_parameter_defined?(:_3) #=> false
+ * binding.implicit_parameter_defined?(:it) #=> false
+ * end
+ * end
+ *
+ */
+static VALUE
+bind_implicit_parameter_defined_p(VALUE bindval, VALUE sym)
+{
+ ID lid = check_local_id(bindval, &sym);
+ const rb_binding_t *bind;
+ const rb_env_t *env;
+
+ if (lid == idIt) lid = idItImplicit;
+
+ if (!lid || !rb_implicit_param_p(lid)) {
+ rb_name_err_raise("'%1$s' is not an implicit parameter",
+ bindval, sym);
+ }
GetBindingPtr(bindval, bind);
env = VM_ENV_ENVVAL_PTR(vm_block_ep(&bind->block));
- return RBOOL(get_local_variable_ptr(&env, lid));
+ return RBOOL(get_local_variable_ptr(&env, lid, FALSE));
}
/*
@@ -683,7 +833,6 @@ cfunc_proc_new(VALUE klass, VALUE ifunc)
{
rb_proc_t *proc;
cfunc_proc_t *sproc;
- const rb_namespace_t *ns = rb_current_namespace();
VALUE procval = TypedData_Make_Struct(klass, cfunc_proc_t, &proc_data_type, sproc);
VALUE *ep;
@@ -698,7 +847,6 @@ cfunc_proc_new(VALUE klass, VALUE ifunc)
/* self? */
RB_OBJ_WRITE(procval, &proc->block.as.captured.code.ifunc, ifunc);
- proc->ns = ns;
proc->is_lambda = TRUE;
return procval;
}
@@ -737,7 +885,6 @@ sym_proc_new(VALUE klass, VALUE sym)
GetProcPtr(procval, proc);
vm_block_type_set(&proc->block, block_type_symbol);
- // No namespace specified: similar to built-in methods
proc->is_lambda = TRUE;
RB_OBJ_WRITE(procval, &proc->block.as.symbol, sym);
return procval;
@@ -765,6 +912,9 @@ rb_vm_ifunc_new(rb_block_call_func_t func, const void *data, int min_argc, int m
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));
+
+ rb_gc_register_pinning_obj((VALUE)ifunc);
+
ifunc->func = func;
ifunc->data = data;
ifunc->argc.min = min_argc;
@@ -935,13 +1085,12 @@ f_lambda(VALUE _)
* Document-method: Proc#yield
*
* call-seq:
- * prc.call(params,...) -> obj
- * prc[params,...] -> obj
- * prc.(params,...) -> obj
- * prc.yield(params,...) -> obj
+ * call(...) -> obj
+ * self[...] -> obj
+ * yield(...) -> obj
*
- * Invokes the block, setting the block's parameters to the values in
- * <i>params</i> using something close to method calling semantics.
+ * Invokes the block, setting the block's parameters to the arguments
+ * using something close to method calling semantics.
* Returns the value of the last expression evaluated in the block.
*
* a_proc = Proc.new {|scalar, *values| values.map {|value| value*scalar } }
@@ -995,7 +1144,12 @@ rb_proc_call_kw(VALUE self, VALUE args, int kw_splat)
VALUE vret;
rb_proc_t *proc;
int argc = check_argc(RARRAY_LEN(args));
- const VALUE *argv = RARRAY_CONST_PTR(args);
+
+ // rb_vm_invoke_proc may end up modifying argv as part of calling and so we
+ // must use RARRAY_PTR, which marks the array as WB_UNPROTECTED instead of
+ // RARRAY_CONST_PTR. Unfortunately this is worse for GC.
+ // See invoke_block_from_c_proc
+ VALUE *argv = RARRAY_PTR(args);
GetProcPtr(self, proc);
vret = rb_vm_invoke_proc(GET_EC(), proc, argc, argv,
kw_splat, VM_BLOCK_HANDLER_NONE);
@@ -1288,10 +1442,10 @@ rb_proc_get_iseq(VALUE self, int *is_proc)
}
/* call-seq:
- * prc == other -> true or false
- * prc.eql?(other) -> true or false
+ * self == other -> true or false
+ * eql?(other) -> true or false
*
- * Two procs are the same if, and only if, they were created from the same code block.
+ * Returns whether +self+ and +other+ were created from the same code block:
*
* def return_block(&block)
* block
@@ -1378,20 +1532,14 @@ proc_eq(VALUE self, VALUE other)
static VALUE
iseq_location(const rb_iseq_t *iseq)
{
- VALUE loc[5];
- int i = 0;
+ VALUE loc[2];
if (!iseq) return Qnil;
rb_iseq_check(iseq);
- loc[i++] = rb_iseq_path(iseq);
- const rb_code_location_t *cl = &ISEQ_BODY(iseq)->location.code_location;
- loc[i++] = RB_INT2NUM(cl->beg_pos.lineno);
- loc[i++] = RB_INT2NUM(cl->beg_pos.column);
- loc[i++] = RB_INT2NUM(cl->end_pos.lineno);
- loc[i++] = RB_INT2NUM(cl->end_pos.column);
- RUBY_ASSERT_ALWAYS(i == numberof(loc));
+ loc[0] = rb_iseq_path(iseq);
+ loc[1] = RB_INT2NUM(ISEQ_BODY(iseq)->location.first_lineno);
- return rb_ary_new_from_values(i, loc);
+ return rb_ary_new4(2, loc);
}
VALUE
@@ -1402,17 +1550,10 @@ rb_iseq_location(const rb_iseq_t *iseq)
/*
* call-seq:
- * prc.source_location -> [String, Integer, Integer, Integer, Integer]
- *
- * Returns the location where the Proc was defined.
- * The returned Array contains:
- * (1) the Ruby source filename
- * (2) the line number where the definition starts
- * (3) the column number where the definition starts
- * (4) the line number where the definition ends
- * (5) the column number where the definitions ends
+ * prc.source_location -> [String, Integer]
*
- * This method will return +nil+ if the Proc was not defined in Ruby (i.e. native).
+ * Returns the Ruby source filename and line number containing this proc
+ * or +nil+ if this proc was not defined in Ruby (i.e. native).
*/
VALUE
@@ -1671,7 +1812,7 @@ static const rb_data_type_t method_data_type = {
NULL, // No external memory to report,
bm_mark_and_move,
},
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_EMBEDDABLE
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_EMBEDDABLE | RUBY_TYPED_FROZEN_SHAREABLE_NO_REC
};
VALUE
@@ -1724,6 +1865,8 @@ mnew_missing_by_name(VALUE klass, VALUE obj, VALUE *name, int scope, VALUE mclas
return mnew_missing(klass, obj, SYM2ID(vid), mclass);
}
+VALUE rb_zsuper_to_super(int argc, VALUE *argv, VALUE self);
+
static VALUE
mnew_internal(const rb_method_entry_t *me, VALUE klass, VALUE iclass,
VALUE obj, ID id, VALUE mclass, int scope, int error)
@@ -1749,8 +1892,9 @@ mnew_internal(const rb_method_entry_t *me, VALUE klass, VALUE iclass,
rb_print_inaccessible(klass, id, visi);
}
}
- if (me->def->type == VM_METHOD_TYPE_ZSUPER) {
- if (me->defined_class) {
+ if (me->def->type == VM_METHOD_TYPE_ZSUPER ||
+ (me->def->type == VM_METHOD_TYPE_CFUNC && me->def->body.cfunc.func == (rb_cfunc_t)rb_zsuper_to_super)) {
+ if (me->def->type == VM_METHOD_TYPE_ZSUPER && me->defined_class) {
VALUE klass = RCLASS_SUPER(RCLASS_ORIGIN(me->defined_class));
id = me->def->original_id;
me = (rb_method_entry_t *)rb_callable_method_entry_with_refinements(klass, id, &iclass);
@@ -1845,10 +1989,9 @@ method_entry_defined_class(const rb_method_entry_t *me)
/*
* call-seq:
- * meth.eql?(other_meth) -> true or false
- * meth == other_meth -> true or false
+ * self == other -> true or false
*
- * Two method objects are equal if they are bound to the same
+ * Returns whether +self+ and +other+ are bound to the same
* object and refer to the same method definition and the classes
* defining the methods are the same class or module.
*/
@@ -1870,6 +2013,8 @@ method_eq(VALUE method, VALUE other)
klass1 = method_entry_defined_class(m1->me);
klass2 = method_entry_defined_class(m2->me);
+ if (RB_TYPE_P(klass1, T_ICLASS)) klass1 = RBASIC_CLASS(klass1);
+ if (RB_TYPE_P(klass2, T_ICLASS)) klass2 = RBASIC_CLASS(klass2);
if (!rb_method_entry_eq(m1->me, m2->me) ||
klass1 != klass2 ||
@@ -2030,24 +2175,23 @@ method_owner(VALUE obj)
}
/*
- * call-see:
- * meth.namespace -> namespace or nil
+ * call-seq:
+ * meth.box -> box or nil
*
- * Returns the namespace where +meth+ is defined in.
+ * Returns the Ruby::Box where +meth+ is defined in.
*/
static VALUE
-method_namespace(VALUE obj)
+method_box(VALUE obj)
{
struct METHOD *data;
- const rb_namespace_t *ns;
+ const rb_box_t *box;
TypedData_Get_Struct(obj, struct METHOD, &method_data_type, data);
- ns = data->me->def->ns;
- if (!ns) return Qfalse;
- if (ns->ns_object) return ns->ns_object;
- // This should not happen
- rb_bug("Unexpected namespace on the method definition: %p", (void*) ns);
- return Qtrue;
+ box = data->me->def->box;
+ if (!box) return Qnil;
+ if (box->box_object) return box->box_object;
+ rb_bug("Unexpected box on the method definition: %p", (void*) box);
+ UNREACHABLE_RETURN(Qnil);
}
void
@@ -2238,29 +2382,29 @@ rb_obj_singleton_method(VALUE obj, VALUE vid)
*
* Returns an +UnboundMethod+ representing the given
* instance method in _mod_.
+ * See +UnboundMethod+ about how to utilize it
*
- * class Interpreter
- * def do_a() print "there, "; end
- * def do_d() print "Hello "; end
- * def do_e() print "!\n"; end
- * def do_v() print "Dave"; end
- * Dispatcher = {
- * "a" => instance_method(:do_a),
- * "d" => instance_method(:do_d),
- * "e" => instance_method(:do_e),
- * "v" => instance_method(:do_v)
- * }
- * def interpret(string)
- * string.each_char {|b| Dispatcher[b].bind(self).call }
- * end
- * end
+ * class Person
+ * def initialize(name)
+ * @name = name
+ * end
+ *
+ * def hi
+ * puts "Hi, I'm #{@name}!"
+ * end
+ * end
*
- * interpreter = Interpreter.new
- * interpreter.interpret('dave')
+ * dave = Person.new('Dave')
+ * thomas = Person.new('Thomas')
+ *
+ * hi = Person.instance_method(:hi)
+ * hi.bind_call(dave)
+ * hi.bind_call(thomas)
*
* <em>produces:</em>
*
- * Hello there, Dave!
+ * Hi, I'm Dave!
+ * Hi, I'm Thomas!
*/
static VALUE
@@ -2489,7 +2633,7 @@ method_clone(VALUE self)
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);
+ clone = TypedData_Make_Struct(rb_obj_class(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);
@@ -2507,7 +2651,7 @@ method_dup(VALUE self)
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);
+ clone = TypedData_Make_Struct(rb_obj_class(self), struct METHOD, &method_data_type, data);
rb_obj_dup_setup(self, clone);
RB_OBJ_WRITE(clone, &data->recv, orig->recv);
RB_OBJ_WRITE(clone, &data->klass, orig->klass);
@@ -2517,13 +2661,20 @@ method_dup(VALUE self)
return clone;
}
-/* Document-method: Method#===
- *
+/*
* call-seq:
- * method === obj -> result_of_method
+ * call(...) -> obj
+ * self[...] -> obj
+ * self === obj -> result_of_method
+ *
+ * Invokes +self+ with the specified arguments, returning the
+ * method's return value.
*
- * Invokes the method with +obj+ as the parameter like #call.
- * This allows a method object to be the target of a +when+ clause
+ * m = 12.method("+")
+ * m.call(3) #=> 15
+ * m.call(20) #=> 32
+ *
+ * Using Method#=== allows a method object to be the target of a +when+ clause
* in a case statement.
*
* require 'prime'
@@ -2534,32 +2685,6 @@ method_dup(VALUE self)
* end
*/
-
-/* Document-method: Method#[]
- *
- * call-seq:
- * meth[args, ...] -> obj
- *
- * Invokes the <i>meth</i> with the specified arguments, returning the
- * method's return value, like #call.
- *
- * m = 12.method("+")
- * m[3] #=> 15
- * m[20] #=> 32
- */
-
-/*
- * call-seq:
- * meth.call(args, ...) -> obj
- *
- * Invokes the <i>meth</i> with the specified arguments, returning the
- * method's return value.
- *
- * m = 12.method("+")
- * m.call(3) #=> 15
- * m.call(20) #=> 32
- */
-
static VALUE
rb_method_call_pass_called_kw(int argc, const VALUE *argv, VALUE method)
{
@@ -2961,7 +3086,11 @@ original_method_entry(VALUE mod, ID id)
while ((me = rb_method_entry(mod, id)) != 0) {
const rb_method_definition_t *def = me->def;
- if (def->type != VM_METHOD_TYPE_ZSUPER) break;
+
+ if (def->type != VM_METHOD_TYPE_ZSUPER &&
+ (def->type != VM_METHOD_TYPE_CFUNC ||
+ def->body.cfunc.func != (rb_cfunc_t)rb_zsuper_to_super)) break;
+
mod = RCLASS_SUPER(me->owner);
id = def->original_id;
}
@@ -3082,17 +3211,18 @@ rb_method_entry_location(const rb_method_entry_t *me)
/*
* call-seq:
- * meth.source_location -> [String, Integer, Integer, Integer, Integer]
+ * source_location -> location
+ *
+ * Returns a two-element array containing the Ruby source filename
+ * as a string and the line number integer where +self+ is defined:
+ *
+ * def greeting = "hello"
+ * method(:greeting).source_location # => ["test.rb", 1]
*
- * Returns the location where the method was defined.
- * The returned Array contains:
- * (1) the Ruby source filename
- * (2) the line number where the definition starts
- * (3) the column number where the definition starts
- * (4) the line number where the definition ends
- * (5) the column number where the definitions ends
+ * Returns nil if +self+ is not a method defined in Ruby (i.e. defined
+ * using native code):
*
- * This method will return +nil+ if the method was not defined in Ruby (i.e. native).
+ * Kernel.method(:puts).source_location # => nil
*/
VALUE
@@ -3189,6 +3319,18 @@ rb_method_parameters(VALUE method)
return method_def_parameters(rb_method_def(method));
}
+static inline VALUE
+append_param_name(VALUE str, VALUE name, const char *unnamed)
+{
+ if (!NIL_P(name)) {
+ rb_str_append(str, rb_sym2str(name));
+ }
+ else if (unnamed) {
+ rb_str_cat_cstr(str, unnamed);
+ }
+ return str;
+}
+
/*
* call-seq:
* meth.to_s -> string
@@ -3315,6 +3457,7 @@ method_inspect(VALUE method)
const VALUE keyrest = ID2SYM(rb_intern("keyrest"));
const VALUE block = ID2SYM(rb_intern("block"));
const VALUE nokey = ID2SYM(rb_intern("nokey"));
+ const VALUE noblock = ID2SYM(rb_intern("noblock"));
int forwarding = 0;
rb_str_buf_cat2(str, "(");
@@ -3332,47 +3475,34 @@ method_inspect(VALUE method)
for (int i = 0; i < RARRAY_LEN(params); i++) {
pair = RARRAY_AREF(params, i);
kind = RARRAY_AREF(pair, 0);
- name = RARRAY_AREF(pair, 1);
- // FIXME: in tests it turns out that kind, name = [:req] produces name to be false. Why?..
- if (NIL_P(name) || name == Qfalse) {
- // FIXME: can it be reduced to switch/case?
- if (kind == req || kind == opt) {
- name = rb_str_new2("_");
- }
- else if (kind == rest || kind == keyrest) {
- name = rb_str_new2("");
- }
- else if (kind == block) {
- name = rb_str_new2("block");
- }
- else if (kind == nokey) {
- name = rb_str_new2("nil");
- }
+ if (RARRAY_LEN(pair) > 1) {
+ name = RARRAY_AREF(pair, 1);
+ }
+ else {
+ name = Qnil;
}
if (kind == req) {
- rb_str_catf(str, "%"PRIsVALUE, name);
+ append_param_name(str, name, "_");
}
else if (kind == opt) {
- rb_str_catf(str, "%"PRIsVALUE"=...", name);
+ rb_str_cat_cstr(append_param_name(str, name, "_"), "=...");
}
else if (kind == keyreq) {
- rb_str_catf(str, "%"PRIsVALUE":", name);
+ rb_str_cat_cstr(append_param_name(str, name, NULL), ":");
}
else if (kind == key) {
- rb_str_catf(str, "%"PRIsVALUE": ...", name);
+ rb_str_cat_cstr(append_param_name(str, name, NULL), ": ...");
}
else if (kind == rest) {
- if (name == ID2SYM('*')) {
- rb_str_cat_cstr(str, forwarding ? "..." : "*");
- }
- else {
- rb_str_catf(str, "*%"PRIsVALUE, name);
+ rb_str_cat_cstr(str, forwarding ? "..." : "*");
+ if (name != ID2SYM('*')) {
+ append_param_name(str, name, NULL);
}
}
else if (kind == keyrest) {
if (name != ID2SYM(idPow)) {
- rb_str_catf(str, "**%"PRIsVALUE, name);
+ append_param_name(rb_str_cat_cstr(str, "**"), name, NULL);
}
else if (i > 0) {
rb_str_set_len(str, RSTRING_LEN(str) - 2);
@@ -3391,12 +3521,15 @@ method_inspect(VALUE method)
}
}
else {
- rb_str_catf(str, "&%"PRIsVALUE, name);
+ append_param_name(rb_str_cat_cstr(str, "&"), name, NULL);
}
}
else if (kind == nokey) {
rb_str_buf_cat2(str, "**nil");
}
+ else if (kind == noblock) {
+ rb_str_buf_cat2(str, "&nil");
+ }
if (i < RARRAY_LEN(params) - 1) {
rb_str_buf_cat2(str, ", ");
@@ -3462,6 +3595,8 @@ method_to_proc(VALUE method)
}
extern VALUE rb_find_defined_class_by_owner(VALUE current_class, VALUE target_owner);
+extern int rb_method_definition_eq(const rb_method_definition_t *d1, const rb_method_definition_t *d2);
+rb_cref_t * rb_vm_get_cref(const VALUE *ep);
/*
* call-seq:
@@ -3488,11 +3623,76 @@ method_super_method(VALUE method)
mid = data->me->def->body.alias.original_me->def->original_id;
}
else {
- super_class = RCLASS_SUPER(RCLASS_ORIGIN(iclass));
+ VALUE klass = iclass;
+ if (RICLASS_FOR_REFINEMENT_P(klass)) {
+ // Refined methods need this check before superclass determination
+ klass = RBASIC(klass)->klass;
+ }
+ super_class = RCLASS_SUPER(RCLASS_ORIGIN(klass));
mid = data->me->def->original_id;
}
if (!super_class) return Qnil;
- me = (rb_method_entry_t *)rb_callable_method_entry_with_refinements(super_class, mid, &iclass);
+
+ // For refined methods, skip refinements for the same definition, but consider
+ // refinements for superclass methods
+ const rb_method_definition_t *skip_def = RICLASS_FOR_REFINEMENT_P(iclass) ? data->me->def : NULL;
+
+ // Use the CREF of the Method/UnboundMethod, not the CREF of the caller of super_method.
+ // We must avoid the use of rb_callable_method_entry_with_refinements, as that will
+ // implicitly use the refinements activated in of the caller of super_method.
+ const rb_cref_t *cref = NULL;
+ switch (data->me->def->type) {
+ case VM_METHOD_TYPE_ISEQ:
+ cref = data->me->def->body.iseq.cref;
+ break;
+ case VM_METHOD_TYPE_BMETHOD: {
+ const rb_proc_t *proc;
+ GetProcPtr(data->me->def->body.bmethod.proc, proc);
+ const struct rb_block *block = &proc->block;
+ if (vm_block_type(block) == block_type_iseq)
+ cref = rb_vm_get_cref(block->as.captured.ep);
+ break;
+ }
+ default:
+ break;
+ }
+ VALUE klass = super_class;
+ me = NULL;
+ while (klass) {
+ const rb_callable_method_entry_t *cme = rb_callable_method_entry(klass, mid);
+ if (!cme) break;
+ if (cme->def->type != VM_METHOD_TYPE_REFINED) {
+ me = (rb_method_entry_t *)cme;
+ iclass = cme->defined_class;
+ break;
+ }
+ // Look through all CREF scopes for a refinement for cme->owner, mirroring
+ // the loop in search_refined_method.
+ const rb_cref_t *c;
+ for (c = cref; c; c = CREF_NEXT(c)) {
+ VALUE refs = CREF_REFINEMENTS(c);
+ if (NIL_P(refs)) continue;
+ VALUE r = rb_hash_lookup(refs, cme->owner);
+ if (NIL_P(r)) continue;
+ const rb_callable_method_entry_t *ref_cme = rb_callable_method_entry(r, mid);
+ if (!ref_cme) break;
+ if (ref_cme->def->type == VM_METHOD_TYPE_REFINED) continue;
+ if (skip_def && rb_method_definition_eq(ref_cme->def, skip_def)) continue;
+ me = (rb_method_entry_t *)ref_cme;
+ iclass = ref_cme->defined_class;
+ break;
+ }
+ if (me) break;
+ // No refined method found. Use orig_me if available, or normal method lookup
+ // in superclass otherwise.
+ const rb_method_entry_t *orig_me = cme->def->body.refined.orig_me;
+ if (orig_me) {
+ me = (rb_method_entry_t *)orig_me;
+ iclass = orig_me->defined_class ? orig_me->defined_class : cme->defined_class;
+ break;
+ }
+ klass = RCLASS_SUPER(cme->defined_class);
+ }
if (!me) return Qnil;
return mnew_internal(me, me->owner, iclass, data->recv, mid, rb_obj_class(method), FALSE, FALSE);
}
@@ -3918,19 +4118,18 @@ rb_proc_compose_to_right(VALUE self, VALUE g)
/*
* call-seq:
- * meth << g -> a_proc
+ * self << g -> a_proc
*
- * Returns a proc that is the composition of this method and the given <i>g</i>.
- * The returned proc takes a variable number of arguments, calls <i>g</i> with them
- * then calls this method with the result.
+ * Returns a proc that is the composition of the given +g+ and this method.
*
- * def f(x)
- * x * x
- * end
+ * The returned proc takes a variable number of arguments. It first calls +g+
+ * with the arguments, then calls +self+ with the return value of +g+.
+ *
+ * def f(ary) = ary << 'in f'
*
* f = self.method(:f)
- * g = proc {|x| x + x }
- * p (f << g).call(2) #=> 16
+ * g = proc { |ary| ary << 'in proc' }
+ * (f << g).call([]) # => ["in proc", "in f"]
*/
static VALUE
rb_method_compose_to_left(VALUE self, VALUE g)
@@ -3942,19 +4141,18 @@ rb_method_compose_to_left(VALUE self, VALUE g)
/*
* call-seq:
- * meth >> g -> a_proc
+ * self >> g -> a_proc
*
- * Returns a proc that is the composition of this method and the given <i>g</i>.
- * The returned proc takes a variable number of arguments, calls this method
- * with them then calls <i>g</i> with the result.
+ * Returns a proc that is the composition of this method and the given +g+.
*
- * def f(x)
- * x * x
- * end
+ * The returned proc takes a variable number of arguments. It first calls +self+
+ * with the arguments, then calls +g+ with the return value of +self+.
+ *
+ * def f(ary) = ary << 'in f'
*
* f = self.method(:f)
- * g = proc {|x| x + x }
- * p (f >> g).call(2) #=> 8
+ * g = proc { |ary| ary << 'in proc' }
+ * (f >> g).call([]) # => ["in f", "in proc"]
*/
static VALUE
rb_method_compose_to_right(VALUE self, VALUE g)
@@ -4518,7 +4716,7 @@ Init_Proc(void)
rb_define_method(rb_mKernel, "public_method", rb_obj_public_method, 1);
rb_define_method(rb_mKernel, "singleton_method", rb_obj_singleton_method, 1);
- rb_define_method(rb_cMethod, "namespace", method_namespace, 0);
+ rb_define_method(rb_cMethod, "box", method_box, 0);
/* UnboundMethod */
rb_cUnboundMethod = rb_define_class("UnboundMethod", rb_cObject);
@@ -4603,6 +4801,9 @@ Init_Binding(void)
rb_define_method(rb_cBinding, "local_variable_get", bind_local_variable_get, 1);
rb_define_method(rb_cBinding, "local_variable_set", bind_local_variable_set, 2);
rb_define_method(rb_cBinding, "local_variable_defined?", bind_local_variable_defined_p, 1);
+ rb_define_method(rb_cBinding, "implicit_parameters", bind_implicit_parameters, 0);
+ rb_define_method(rb_cBinding, "implicit_parameter_get", bind_implicit_parameter_get, 1);
+ rb_define_method(rb_cBinding, "implicit_parameter_defined?", bind_implicit_parameter_defined_p, 1);
rb_define_method(rb_cBinding, "receiver", bind_receiver, 0);
rb_define_method(rb_cBinding, "source_location", bind_location, 0);
rb_define_global_function("binding", rb_f_binding, 0);
diff --git a/process.c b/process.c
index da9ce74027..e443ccbe49 100644
--- a/process.c
+++ b/process.c
@@ -1575,8 +1575,8 @@ after_exec(void)
static void
before_fork_ruby(void)
{
- rb_gc_before_fork();
before_exec();
+ rb_gc_before_fork();
}
static void
@@ -2204,7 +2204,7 @@ check_exec_options_i(st_data_t st_key, st_data_t st_val, st_data_t arg)
if (SYMBOL_P(key))
rb_raise(rb_eArgError, "wrong exec option symbol: % "PRIsVALUE,
key);
- rb_raise(rb_eArgError, "wrong exec option");
+ rb_raise(rb_eArgError, "wrong exec option: %"PRIsVALUE, rb_obj_class(key));
}
return ST_CONTINUE;
}
@@ -2635,7 +2635,7 @@ rb_exec_fillarg(VALUE prog, int argc, VALUE *argv, VALUE env, VALUE opthash, VAL
}
rb_str_buf_cat(argv_str, (char *)&null, sizeof(null)); /* terminator for execve. */
eargp->invoke.cmd.argv_str =
- rb_imemo_tmpbuf_auto_free_pointer_new_from_an_RString(argv_str);
+ rb_imemo_tmpbuf_new_from_an_RString(argv_str);
}
RB_GC_GUARD(execarg_obj);
}
@@ -2726,9 +2726,7 @@ open_func(void *ptr)
static void
rb_execarg_allocate_dup2_tmpbuf(struct rb_execarg *eargp, long len)
{
- VALUE tmpbuf = rb_imemo_tmpbuf_auto_free_pointer();
- rb_imemo_tmpbuf_set_ptr(tmpbuf, ruby_xmalloc(run_exec_dup2_tmpbuf_size(len)));
- eargp->dup2_tmpbuf = tmpbuf;
+ rb_alloc_tmp_buffer(&eargp->dup2_tmpbuf, run_exec_dup2_tmpbuf_size(len));
}
static VALUE
@@ -2830,7 +2828,7 @@ rb_execarg_parent_start1(VALUE execarg_obj)
p = NULL;
rb_str_buf_cat(envp_str, (char *)&p, sizeof(p));
eargp->envp_str =
- rb_imemo_tmpbuf_auto_free_pointer_new_from_an_RString(envp_str);
+ rb_imemo_tmpbuf_new_from_an_RString(envp_str);
eargp->envp_buf = envp_buf;
/*
@@ -2890,7 +2888,6 @@ void
rb_execarg_parent_end(VALUE execarg_obj)
{
execarg_parent_end(execarg_obj);
- RB_GC_GUARD(execarg_obj);
}
static void
@@ -2957,7 +2954,7 @@ NORETURN(static VALUE f_exec(int c, const VALUE *a, VALUE _));
* - 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].
+ * see {Command Injection}[rdoc-ref:security/command_injection.rdoc].
*
* The new process is created using the
* {exec system call}[https://pubs.opengroup.org/onlinepubs/9699919799.2018edition/functions/execve.html];
@@ -3183,8 +3180,7 @@ run_exec_dup2(VALUE ary, VALUE tmpbuf, struct rb_execarg *sargp, char *errmsg, s
long n, i;
int ret;
int extra_fd = -1;
- struct rb_imemo_tmpbuf_struct *buf = (void *)tmpbuf;
- struct run_exec_dup2_fd_pair *pairs = (void *)buf->ptr;
+ struct run_exec_dup2_fd_pair *pairs = RB_IMEMO_TMPBUF_PTR(tmpbuf);
n = RARRAY_LEN(ary);
@@ -4011,7 +4007,10 @@ retry_fork_async_signal_safe(struct rb_process_status *status, int *ep,
while (1) {
prefork();
disable_child_handler_before_fork(&old);
-#ifdef HAVE_WORKING_VFORK
+
+ // Older versions of ASAN does not work with vfork
+ // See https://github.com/google/sanitizers/issues/925
+#if defined(HAVE_WORKING_VFORK) && !defined(RUBY_ASAN_ENABLED)
if (!has_privilege())
pid = vfork();
else
@@ -4230,7 +4229,7 @@ rb_proc__fork(VALUE _obj)
* puts "Before the fork: #{Process.pid}"
* fork do
* puts "In the child process: #{Process.pid}"
- * end # => 382141
+ * end # => 420520
* puts "After the fork: #{Process.pid}"
*
* Output:
@@ -4639,7 +4638,7 @@ rb_spawn(int argc, const VALUE *argv)
* - 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].
+ * see {Command Injection}[rdoc-ref:security/command_injection.rdoc].
*
* Returns:
*
@@ -4819,7 +4818,7 @@ rb_f_system(int argc, VALUE *argv, VALUE _)
* - 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].
+ * see {Command Injection}[rdoc-ref:security/command_injection.rdoc].
*
* Returns the process ID (pid) of the new process,
* without waiting for it to complete.
@@ -8227,7 +8226,7 @@ ruby_real_ms_time(void)
* - +: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.
+ * - +:second+: Number of seconds as an integer.
*
* Examples:
*
diff --git a/ractor.c b/ractor.c
index c4d748e69c..f94c06cc73 100644
--- a/ractor.c
+++ b/ractor.c
@@ -3,9 +3,9 @@
#include "ruby/ruby.h"
#include "ruby/thread.h"
#include "ruby/ractor.h"
+#include "ruby/re.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"
@@ -16,6 +16,7 @@
#include "internal/ractor.h"
#include "internal/rational.h"
#include "internal/struct.h"
+#include "internal/st.h"
#include "internal/thread.h"
#include "variable.h"
#include "yjit.h"
@@ -72,10 +73,17 @@ ractor_lock(rb_ractor_t *r, const char *file, int line)
ASSERT_ractor_unlocking(r);
rb_native_mutex_lock(&r->sync.lock);
+ const rb_execution_context_t *ec = rb_current_ec_noinline();
+ if (ec) {
+ rb_ractor_t *cr = rb_ec_ractor_ptr(ec);
+ VM_ASSERT(!cr->malloc_gc_disabled);
+ cr->malloc_gc_disabled = true;
+ }
+
#if RACTOR_CHECK_MODE > 0
- if (rb_current_execution_context(false) != NULL) {
- rb_ractor_t *cr = rb_current_ractor_raw(false);
- r->sync.locked_by = cr ? rb_ractor_self(cr) : Qundef;
+ if (ec != NULL) {
+ rb_ractor_t *cr = rb_ec_ractor_ptr(ec);
+ r->sync.locked_by = rb_ractor_self(cr);
}
#endif
@@ -99,6 +107,14 @@ ractor_unlock(rb_ractor_t *r, const char *file, int line)
#if RACTOR_CHECK_MODE > 0
r->sync.locked_by = Qnil;
#endif
+
+ const rb_execution_context_t *ec = rb_current_ec_noinline();
+ if (ec) {
+ rb_ractor_t *cr = rb_ec_ractor_ptr(ec);
+ VM_ASSERT(cr->malloc_gc_disabled);
+ cr->malloc_gc_disabled = false;
+ }
+
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)" : "");
@@ -192,30 +208,73 @@ static void ractor_sync_free(rb_ractor_t *r);
static size_t ractor_sync_memsize(const rb_ractor_t *r);
static void ractor_sync_init(rb_ractor_t *r);
+static int
+mark_targeted_hook_list(st_data_t key, st_data_t value, st_data_t _arg)
+{
+ rb_hook_list_t *hook_list = (rb_hook_list_t*)value;
+
+ if (hook_list->type == hook_list_type_targeted_iseq) {
+ rb_gc_mark((VALUE)key);
+ }
+ else {
+ rb_method_definition_t *def = (rb_method_definition_t*)key;
+ RUBY_ASSERT(hook_list->type == hook_list_type_targeted_def);
+ rb_gc_mark(def->body.bmethod.proc);
+ }
+ rb_hook_list_mark(hook_list);
+
+ return ST_CONTINUE;
+}
+
static void
ractor_mark(void *ptr)
{
rb_ractor_t *r = (rb_ractor_t *)ptr;
-
- // mark received messages
- ractor_sync_mark(r);
+ bool checking_shareable = rb_gc_checking_shareable();
rb_gc_mark(r->loc);
rb_gc_mark(r->name);
- rb_gc_mark(r->r_stdin);
- rb_gc_mark(r->r_stdout);
- rb_gc_mark(r->r_stderr);
- rb_hook_list_mark(&r->pub.hooks);
-
- if (r->threads.cnt > 0) {
- rb_thread_t *th = 0;
- ccan_list_for_each(&r->threads.set, th, lt_node) {
- VM_ASSERT(th != NULL);
- rb_gc_mark(th->self);
+
+ if (!checking_shareable) {
+ // may unshareable objects
+ rb_gc_mark(r->r_stdin);
+ rb_gc_mark(r->r_stdout);
+ rb_gc_mark(r->r_stderr);
+ rb_gc_mark(r->verbose);
+ rb_gc_mark(r->debug);
+
+ // mark received messages
+ ractor_sync_mark(r);
+
+ rb_hook_list_mark(&r->pub.hooks);
+ if (r->pub.targeted_hooks.num_entries) {
+ st_foreach(&r->pub.targeted_hooks, mark_targeted_hook_list, 0);
+ }
+
+ if (r->threads.cnt > 0) {
+ rb_thread_t *th = 0;
+ ccan_list_for_each(&r->threads.set, th, lt_node) {
+ VM_ASSERT(th != NULL);
+ rb_gc_mark(th->self);
+ }
}
+
+ ractor_local_storage_mark(r);
}
+}
- ractor_local_storage_mark(r);
+static int
+free_targeted_hook_lists(st_data_t key, st_data_t val, st_data_t _arg)
+{
+ rb_hook_list_t *hook_list = (rb_hook_list_t*)val;
+ rb_hook_list_free(hook_list);
+ return ST_DELETE;
+}
+
+static void
+free_targeted_hooks(st_table *hooks_tbl)
+{
+ st_foreach(hooks_tbl, free_targeted_hook_lists, 0);
}
static void
@@ -223,12 +282,14 @@ ractor_free(void *ptr)
{
rb_ractor_t *r = (rb_ractor_t *)ptr;
RUBY_DEBUG_LOG("free r:%d", rb_ractor_id(r));
+ free_targeted_hooks(&r->pub.targeted_hooks);
rb_native_mutex_destroy(&r->sync.lock);
#ifdef RUBY_THREAD_WIN32_H
rb_native_cond_destroy(&r->sync.wakeup_cond);
#endif
ractor_local_storage_free(r);
rb_hook_list_free(&r->pub.hooks);
+ rb_st_free_embedded_table(&r->pub.targeted_hooks);
if (r->newobj_cache) {
RUBY_ASSERT(r == ruby_single_main_ractor);
@@ -238,7 +299,9 @@ ractor_free(void *ptr)
}
ractor_sync_free(r);
- ruby_xfree(r);
+ if (!r->main_ractor) {
+ SIZED_FREE(r);
+ }
}
static size_t
@@ -280,7 +343,8 @@ RACTOR_PTR(VALUE self)
return r;
}
-static rb_atomic_t ractor_last_id;
+#define MAIN_RACTOR_ID 1
+static rb_atomic_t ractor_last_id = MAIN_RACTOR_ID;
#if RACTOR_CHECK_MODE > 0
uint32_t
@@ -399,22 +463,24 @@ ractor_alloc(VALUE klass)
VALUE rv = TypedData_Make_Struct(klass, rb_ractor_t, &ractor_data_type, r);
FL_SET_RAW(rv, RUBY_FL_SHAREABLE);
r->pub.self = rv;
+ r->next_ec_serial = 1;
VM_ASSERT(ractor_status_p(r, ractor_created));
return rv;
}
+static rb_ractor_t _main_ractor = {
+ .loc = Qnil,
+ .name = Qnil,
+ .pub.id = MAIN_RACTOR_ID,
+ .pub.self = Qnil,
+ .next_ec_serial = 1,
+ .main_ractor = true,
+};
+
rb_ractor_t *
rb_ractor_main_alloc(void)
{
- rb_ractor_t *r = ruby_mimcalloc(1, sizeof(rb_ractor_t));
- if (r == NULL) {
- fprintf(stderr, "[FATAL] failed to allocate memory for main ractor\n");
- exit(EXIT_FAILURE);
- }
- r->pub.id = ++ractor_last_id;
- r->loc = Qnil;
- r->name = Qnil;
- r->pub.self = Qnil;
+ rb_ractor_t *r = &_main_ractor;
r->newobj_cache = rb_gc_ractor_cache_alloc(r);
ruby_single_main_ractor = r;
@@ -464,6 +530,8 @@ static void
ractor_init(rb_ractor_t *r, VALUE name, VALUE loc)
{
ractor_sync_init(r);
+ st_init_existing_numtable_with_size(&r->pub.targeted_hooks, 0);
+ r->pub.hooks.type = hook_list_type_ractor_local;
// thread management
rb_thread_sched_init(&r->threads.sched, false);
@@ -478,10 +546,12 @@ ractor_init(rb_ractor_t *r, VALUE name, VALUE loc)
rb_raise(rb_eArgError, "ASCII incompatible encoding (%s)",
rb_enc_name(enc));
}
- name = rb_str_new_frozen(name);
+ name = RB_OBJ_SET_SHAREABLE(rb_str_new_frozen(name));
}
- r->name = name;
+
+ if (!SPECIAL_CONST_P(loc)) RB_OBJ_SET_SHAREABLE(loc);
r->loc = loc;
+ r->name = name;
}
void
@@ -503,7 +573,6 @@ ractor_create(rb_execution_context_t *ec, VALUE self, VALUE loc, VALUE name, VAL
rb_ractor_t *r = RACTOR_PTR(rv);
ractor_init(r, name, loc);
- // can block here
r->pub.id = ractor_next_id();
RUBY_DEBUG_LOG("r:%u", r->pub.id);
@@ -812,13 +881,11 @@ rb_ractor_terminate_all(void)
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
- }
- RB_VM_UNLOCK();
+ RB_VM_LOCK();
+ {
+ 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
RB_VM_LOCK();
@@ -831,6 +898,17 @@ rb_ractor_terminate_all(void)
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 */);
+#ifdef RUBY_THREAD_PTHREAD_H
+ while (vm->ractor.sched.barrier_waiting) {
+ // A barrier is waiting. Threads relinquish the VM lock before joining the barrier and
+ // since we just acquired the VM lock back, we're blocking other threads from joining it.
+ // We loop until the barrier is over. We can't join this barrier because our thread isn't added to
+ // running_threads until the call below to `rb_add_running_thread`.
+ RB_VM_UNLOCK();
+ unsigned int lev;
+ RB_VM_LOCK_ENTER_LEV_NB(&lev);
+ }
+#endif
rb_add_running_thread(rb_ec_thread_ptr(cr->threads.running_ec));
rb_vm_ractor_blocking_cnt_dec(vm, cr, __FILE__, __LINE__);
@@ -879,36 +957,16 @@ ractor_moved_missing(int argc, VALUE *argv, VALUE self)
*
* Raised when an attempt is made to send a message to a closed port,
* or to retrieve a message from a closed and empty port.
- * Ports may be closed explicitly with Ractor#close_outgoing/close_incoming
+ * Ports may be closed explicitly with Ractor::Port#close
* and are closed implicitly when a Ractor terminates.
*
- * r = Ractor.new { sleep(500) }
- * r.close_outgoing
- * r.take # Ractor::ClosedError
- *
- * ClosedError is a descendant of StopIteration, so the closing of the ractor will break
- * the loops without propagating the error:
+ * port = Ractor::Port.new
+ * port.close
+ * port << "test" # Ractor::ClosedError
+ * port.receive # Ractor::ClosedError
*
- * r = Ractor.new do
- * loop do
- * msg = receive # raises ClosedError and loop traps it
- * puts "Received: #{msg}"
- * end
- * puts "loop exited"
- * end
- *
- * 3.times{|i| r << i}
- * r.close_incoming
- * r.take
- * puts "Continue successfully"
- *
- * This will print:
- *
- * Received: 0
- * Received: 1
- * Received: 2
- * loop exited
- * Continue successfully
+ * ClosedError is a descendant of StopIteration, so the closing of a port will break
+ * out of loops without propagating the error.
*/
/*
@@ -921,14 +979,14 @@ ractor_moved_missing(int argc, VALUE *argv, VALUE self)
/*
* Document-class: Ractor::RemoteError
*
- * Raised on attempt to Ractor#take if there was an uncaught exception in the Ractor.
+ * Raised on Ractor#join or Ractor#value if there was an uncaught exception in the Ractor.
* Its +cause+ will contain the original exception, and +ractor+ is the original ractor
* it was raised in.
*
* r = Ractor.new { raise "Something weird happened" }
*
* begin
- * r.take
+ * r.value
* rescue => e
* p e # => #<Ractor::RemoteError: thrown by remote Ractor.>
* p e.ractor == r # => true
@@ -940,7 +998,7 @@ ractor_moved_missing(int argc, VALUE *argv, VALUE self)
/*
* Document-class: Ractor::MovedError
*
- * Raised on an attempt to access an object which was moved in Ractor#send or Ractor.yield.
+ * Raised on an attempt to access an object which was moved in Ractor#send or Ractor::Port#send.
*
* r = Ractor.new { sleep }
*
@@ -955,7 +1013,7 @@ ractor_moved_missing(int argc, VALUE *argv, VALUE self)
* Document-class: Ractor::MovedObject
*
* A special object which replaces any value that was moved to another ractor in Ractor#send
- * or Ractor.yield. Any attempt to access the object results in Ractor::MovedError.
+ * or Ractor::Port#send. Any attempt to access the object results in Ractor::MovedError.
*
* r = Ractor.new { receive }
*
@@ -1101,6 +1159,50 @@ rb_ractor_hooks(rb_ractor_t *cr)
return &cr->pub.hooks;
}
+st_table *
+rb_ractor_targeted_hooks(rb_ractor_t *cr)
+{
+ return &cr->pub.targeted_hooks;
+}
+
+static void
+rb_obj_set_shareable_no_assert(VALUE obj)
+{
+ FL_SET_RAW(obj, FL_SHAREABLE);
+
+ if (rb_obj_gen_fields_p(obj)) {
+ VALUE fields = rb_obj_fields_no_ractor_check(obj);
+ if (imemo_type_p(fields, imemo_fields)) {
+ // no recursive mark
+ FL_SET_RAW(fields, FL_SHAREABLE);
+ }
+ }
+}
+
+#ifndef STRICT_VERIFY_SHAREABLE
+#define STRICT_VERIFY_SHAREABLE 0
+#endif
+
+bool
+rb_ractor_verify_shareable(VALUE obj)
+{
+#if STRICT_VERIFY_SHAREABLE
+ rb_gc_verify_shareable(obj);
+#endif
+ return true;
+}
+
+VALUE
+rb_obj_set_shareable(VALUE obj)
+{
+ RUBY_ASSERT(!RB_SPECIAL_CONST_P(obj));
+
+ rb_obj_set_shareable_no_assert(obj);
+ RUBY_ASSERT(rb_ractor_verify_shareable(obj));
+
+ return obj;
+}
+
/// traverse function
// 2: stop search
@@ -1168,6 +1270,7 @@ obj_traverse_rec(struct obj_traverse_data *data)
{
if (UNLIKELY(!data->rec)) {
data->rec_hash = rb_ident_hash_new();
+ rb_obj_hide(data->rec_hash);
data->rec = RHASH_ST_TABLE(data->rec_hash);
}
return data->rec;
@@ -1218,7 +1321,6 @@ obj_traverse_i(VALUE obj, struct obj_traverse_data *data)
case T_REGEXP:
case T_FILE:
case T_SYMBOL:
- case T_MATCH:
break;
case T_OBJECT:
@@ -1227,6 +1329,8 @@ obj_traverse_i(VALUE obj, struct obj_traverse_data *data)
case T_ARRAY:
{
+ rb_ary_cancel_sharing(obj);
+
for (int i = 0; i < RARRAY_LENINT(obj); i++) {
VALUE e = rb_ary_entry(obj, i);
if (obj_traverse_i(e, data)) return 1;
@@ -1249,7 +1353,7 @@ obj_traverse_i(VALUE obj, struct obj_traverse_data *data)
case T_STRUCT:
{
- long len = RSTRUCT_LEN(obj);
+ long len = RSTRUCT_LEN_RAW(obj);
const VALUE *ptr = RSTRUCT_CONST_PTR(obj);
for (long i=0; i<len; i++) {
@@ -1258,6 +1362,10 @@ obj_traverse_i(VALUE obj, struct obj_traverse_data *data)
}
break;
+ case T_MATCH:
+ if (obj_traverse_i(RMATCH(obj)->str, data)) return 1;
+ break;
+
case T_RATIONAL:
if (obj_traverse_i(RRATIONAL(obj)->num, data)) return 1;
if (obj_traverse_i(RRATIONAL(obj)->den, data)) return 1;
@@ -1343,7 +1451,7 @@ allow_frozen_shareable_p(VALUE obj)
if (!RB_TYPE_P(obj, T_DATA)) {
return true;
}
- else if (RTYPEDDATA_P(obj)) {
+ else {
const rb_data_type_t *type = RTYPEDDATA_TYPE(obj);
if (type->flags & RUBY_TYPED_FROZEN_SHAREABLE) {
return true;
@@ -1354,6 +1462,26 @@ allow_frozen_shareable_p(VALUE obj)
}
static enum obj_traverse_iterator_result
+make_shareable_check_shareable_freeze(VALUE obj, enum obj_traverse_iterator_result result)
+{
+ if (!RB_OBJ_FROZEN_RAW(obj)) {
+ rb_funcall(obj, idFreeze, 0);
+
+ if (UNLIKELY(!RB_OBJ_FROZEN_RAW(obj))) {
+ rb_raise(rb_eRactorError, "#freeze does not freeze object correctly");
+ }
+
+ if (RB_OBJ_SHAREABLE_P(obj)) {
+ return traverse_skip;
+ }
+ }
+
+ return result;
+}
+
+static int obj_refer_only_shareables_p(VALUE obj);
+
+static enum obj_traverse_iterator_result
make_shareable_check_shareable(VALUE obj)
{
VM_ASSERT(!SPECIAL_CONST_P(obj));
@@ -1362,8 +1490,22 @@ make_shareable_check_shareable(VALUE obj)
return traverse_skip;
}
else if (!allow_frozen_shareable_p(obj)) {
- if (rb_obj_is_proc(obj)) {
- rb_proc_ractor_make_shareable(obj);
+ VM_ASSERT(RB_TYPE_P(obj, T_DATA));
+ const rb_data_type_t *type = RTYPEDDATA_TYPE(obj);
+
+ if (type->flags & RUBY_TYPED_FROZEN_SHAREABLE_NO_REC) {
+ if (obj_refer_only_shareables_p(obj)) {
+ make_shareable_check_shareable_freeze(obj, traverse_skip);
+ RB_OBJ_SET_SHAREABLE(obj);
+ return traverse_skip;
+ }
+ else {
+ rb_raise(rb_eRactorError,
+ "can not make shareable object for %+"PRIsVALUE" because it refers unshareable objects", obj);
+ }
+ }
+ else if (rb_obj_is_proc(obj)) {
+ rb_proc_ractor_make_shareable(obj, Qundef);
return traverse_cont;
}
else {
@@ -1392,25 +1534,17 @@ make_shareable_check_shareable(VALUE obj)
break;
}
- if (!RB_OBJ_FROZEN_RAW(obj)) {
- rb_funcall(obj, idFreeze, 0);
-
- if (UNLIKELY(!RB_OBJ_FROZEN_RAW(obj))) {
- rb_raise(rb_eRactorError, "#freeze does not freeze object correctly");
- }
-
- if (RB_OBJ_SHAREABLE_P(obj)) {
- return traverse_skip;
- }
- }
-
- return traverse_cont;
+ return make_shareable_check_shareable_freeze(obj, traverse_cont);
}
static enum obj_traverse_iterator_result
mark_shareable(VALUE obj)
{
- FL_SET_RAW(obj, RUBY_FL_SHAREABLE);
+ if (RB_TYPE_P(obj, T_STRING)) {
+ rb_str_make_independent(obj);
+ }
+
+ rb_obj_set_shareable_no_assert(obj);
return traverse_cont;
}
@@ -1672,10 +1806,10 @@ obj_traverse_replace_i(VALUE obj, struct obj_traverse_replace_data *data)
else if (data->replacement != _val) { RB_OBJ_WRITE(parent_obj, &v, data->replacement); } \
} while (0)
- if (UNLIKELY(rb_obj_exivar_p(obj))) {
+ if (UNLIKELY(rb_obj_gen_fields_p(obj))) {
VALUE fields_obj = rb_obj_fields_no_ractor_check(obj);
- if (UNLIKELY(rb_shape_obj_too_complex_p(obj))) {
+ if (UNLIKELY(rb_obj_shape_complex_p(obj))) {
struct obj_traverse_replace_callback_data d = {
.stop = false,
.data = data,
@@ -1705,7 +1839,6 @@ obj_traverse_replace_i(VALUE obj, struct obj_traverse_replace_data *data)
case T_REGEXP:
case T_FILE:
case T_SYMBOL:
- case T_MATCH:
break;
case T_STRING:
rb_str_make_independent(obj);
@@ -1713,7 +1846,7 @@ obj_traverse_replace_i(VALUE obj, struct obj_traverse_replace_data *data)
case T_OBJECT:
{
- if (rb_shape_obj_too_complex_p(obj)) {
+ if (rb_obj_shape_complex_p(obj)) {
struct obj_traverse_replace_callback_data d = {
.stop = false,
.data = data,
@@ -1728,7 +1861,7 @@ obj_traverse_replace_i(VALUE obj, struct obj_traverse_replace_data *data)
if (d.stop) return 1;
}
else {
- uint32_t len = ROBJECT_FIELDS_COUNT(obj);
+ uint32_t len = ROBJECT_FIELDS_COUNT_NOT_COMPLEX(obj);
VALUE *ptr = ROBJECT_FIELDS(obj);
for (uint32_t i = 0; i < len; i++) {
@@ -1781,7 +1914,7 @@ obj_traverse_replace_i(VALUE obj, struct obj_traverse_replace_data *data)
case T_STRUCT:
{
- long len = RSTRUCT_LEN(obj);
+ long len = RSTRUCT_LEN_RAW(obj);
const VALUE *ptr = RSTRUCT_CONST_PTR(obj);
for (long i=0; i<len; i++) {
@@ -1790,6 +1923,10 @@ obj_traverse_replace_i(VALUE obj, struct obj_traverse_replace_data *data)
}
break;
+ case T_MATCH:
+ CHECK_AND_REPLACE(obj, RMATCH(obj)->str);
+ break;
+
case T_RATIONAL:
CHECK_AND_REPLACE(obj, RRATIONAL(obj)->num);
CHECK_AND_REPLACE(obj, RRATIONAL(obj)->den);
@@ -1856,16 +1993,16 @@ rb_obj_traverse_replace(VALUE obj,
}
static const bool wb_protected_types[RUBY_T_MASK] = {
- [T_OBJECT] = RGENGC_WB_PROTECTED_OBJECT,
- [T_HASH] = RGENGC_WB_PROTECTED_HASH,
- [T_ARRAY] = RGENGC_WB_PROTECTED_ARRAY,
- [T_STRING] = RGENGC_WB_PROTECTED_STRING,
- [T_STRUCT] = RGENGC_WB_PROTECTED_STRUCT,
- [T_COMPLEX] = RGENGC_WB_PROTECTED_COMPLEX,
- [T_REGEXP] = RGENGC_WB_PROTECTED_REGEXP,
- [T_MATCH] = RGENGC_WB_PROTECTED_MATCH,
- [T_FLOAT] = RGENGC_WB_PROTECTED_FLOAT,
- [T_RATIONAL] = RGENGC_WB_PROTECTED_RATIONAL,
+ [T_OBJECT] = true,
+ [T_HASH] = true,
+ [T_ARRAY] = true,
+ [T_STRING] = true,
+ [T_STRUCT] = true,
+ [T_COMPLEX] = true,
+ [T_REGEXP] = true,
+ [T_MATCH] = true,
+ [T_FLOAT] = true,
+ [T_RATIONAL] = true,
};
static enum obj_traverse_iterator_result
@@ -1877,8 +2014,9 @@ move_enter(VALUE obj, struct obj_traverse_replace_data *data)
}
else {
VALUE type = RB_BUILTIN_TYPE(obj);
- type |= wb_protected_types[type] ? FL_WB_PROTECTED : 0;
- NEWOBJ_OF(moved, struct RBasic, 0, type, rb_gc_obj_slot_size(obj), 0);
+ size_t slot_size = rb_gc_obj_slot_size(obj);
+ VALUE moved = rb_newobj(GET_EC(), 0, type, RBASIC_SHAPE_ID(obj), wb_protected_types[type], slot_size);
+ MEMZERO(((struct RBasic *)moved) + 1, char, slot_size - sizeof(struct RBasic));
data->replacement = (VALUE)moved;
return traverse_cont;
}
@@ -1901,14 +2039,13 @@ move_leave(VALUE obj, struct obj_traverse_replace_data *data)
rb_gc_writebarrier_remember(data->replacement);
void rb_replace_generic_ivar(VALUE clone, VALUE obj); // variable.c
-
- rb_gc_obj_id_moved(data->replacement);
-
- if (UNLIKELY(rb_obj_exivar_p(obj))) {
+ if (UNLIKELY(rb_obj_gen_fields_p(obj))) {
rb_replace_generic_ivar(data->replacement, obj);
}
- VALUE flags = T_OBJECT | FL_FREEZE | ROBJECT_EMBED | (RBASIC(obj)->flags & FL_PROMOTED);
+ rb_gc_obj_id_moved(data->replacement);
+
+ VALUE flags = T_OBJECT | FL_FREEZE | (RBASIC(obj)->flags & FL_PROMOTED);
// Avoid mutations using bind_call, etc.
MEMZERO((char *)obj, char, sizeof(struct RBasic));
@@ -1929,6 +2066,31 @@ ractor_move(VALUE obj)
}
}
+static VALUE
+ractor_call_clone_try(VALUE obj)
+{
+ return rb_funcall(obj, idClone, 0);
+}
+
+static VALUE
+ractor_call_clone_rescue(VALUE obj, VALUE exc)
+{
+ rb_raise(rb_eRactorError, "can't clone unshareable instance of %"PRIsVALUE, rb_class_of(obj));
+ UNREACHABLE_RETURN(Qnil);
+}
+
+static VALUE
+ractor_obj_clone(VALUE obj)
+{
+ VALUE clone = rb_rescue(ractor_call_clone_try, obj, ractor_call_clone_rescue, obj);
+
+ if (obj == clone) {
+ rb_raise(rb_eRactorError, "#clone returned self");
+ }
+
+ return clone;
+}
+
static enum obj_traverse_iterator_result
copy_enter(VALUE obj, struct obj_traverse_replace_data *data)
{
@@ -1937,7 +2099,7 @@ copy_enter(VALUE obj, struct obj_traverse_replace_data *data)
return traverse_skip;
}
else {
- data->replacement = rb_obj_clone(obj);
+ data->replacement = ractor_obj_clone(obj);
return traverse_cont;
}
}
@@ -2074,7 +2236,7 @@ rb_ractor_local_storage_delkey(rb_ractor_local_key_t key)
RB_VM_LOCKING() {
if (freed_ractor_local_keys.cnt == freed_ractor_local_keys.capa) {
freed_ractor_local_keys.capa = freed_ractor_local_keys.capa ? freed_ractor_local_keys.capa * 2 : 4;
- REALLOC_N(freed_ractor_local_keys.keys, rb_ractor_local_key_t, freed_ractor_local_keys.capa);
+ SIZED_REALLOC_N(freed_ractor_local_keys.keys, rb_ractor_local_key_t, freed_ractor_local_keys.capa, freed_ractor_local_keys.cnt);
}
freed_ractor_local_keys.keys[freed_ractor_local_keys.cnt++] = key;
}
@@ -2173,12 +2335,12 @@ void
rb_ractor_finish_marking(void)
{
for (int i=0; i<freed_ractor_local_keys.cnt; i++) {
- ruby_xfree(freed_ractor_local_keys.keys[i]);
+ SIZED_FREE(freed_ractor_local_keys.keys[i]);
}
freed_ractor_local_keys.cnt = 0;
if (freed_ractor_local_keys.capa > DEFAULT_KEYS_CAPA) {
freed_ractor_local_keys.capa = DEFAULT_KEYS_CAPA;
- REALLOC_N(freed_ractor_local_keys.keys, rb_ractor_local_key_t, DEFAULT_KEYS_CAPA);
+ SIZED_REALLOC_N(freed_ractor_local_keys.keys, rb_ractor_local_key_t, DEFAULT_KEYS_CAPA, freed_ractor_local_keys.capa);
}
}
@@ -2262,29 +2424,43 @@ ractor_local_value_store_if_absent(rb_execution_context_t *ec, VALUE self, VALUE
return rb_mutex_synchronize(cr->local_storage_store_lock, ractor_local_value_store_i, (VALUE)&data);
}
+// shareable_proc
+
+static VALUE
+ractor_shareable_proc(rb_execution_context_t *ec, VALUE replace_self, bool is_lambda)
+{
+ if (!rb_ractor_shareable_p(replace_self)) {
+ rb_raise(rb_eRactorIsolationError, "self should be shareable: %" PRIsVALUE, replace_self);
+ }
+ else {
+ VALUE proc = is_lambda ? rb_block_lambda() : rb_block_proc();
+ return rb_proc_ractor_make_shareable(rb_proc_dup(proc), replace_self);
+ }
+}
+
// Ractor#require
struct cross_ractor_require {
VALUE port;
- VALUE result;
- VALUE exception;
+ bool raised;
- // require
- VALUE feature;
+ union {
+ struct {
+ VALUE feature;
+ } require;
- // autoload
- VALUE module;
- ID name;
+ struct {
+ VALUE module;
+ ID name;
+ } autoload;
+ } as;
bool silent;
};
RUBY_REFERENCES(cross_ractor_require_refs) = {
RUBY_REF_EDGE(struct cross_ractor_require, port),
- RUBY_REF_EDGE(struct cross_ractor_require, result),
- RUBY_REF_EDGE(struct cross_ractor_require, exception),
- RUBY_REF_EDGE(struct cross_ractor_require, feature),
- RUBY_REF_EDGE(struct cross_ractor_require, module),
+ RUBY_REF_EDGE(struct cross_ractor_require, as.require.feature),
RUBY_REF_END
};
@@ -2304,20 +2480,18 @@ require_body(VALUE crr_obj)
{
struct cross_ractor_require *crr;
TypedData_Get_Struct(crr_obj, struct cross_ractor_require, &cross_ractor_require_data_type, crr);
+ VALUE feature = crr->as.require.feature;
ID require;
CONST_ID(require, "require");
if (crr->silent) {
int rb_require_internal_silent(VALUE fname);
-
- RB_OBJ_WRITE(crr_obj, &crr->result, INT2NUM(rb_require_internal_silent(crr->feature)));
+ return INT2NUM(rb_require_internal_silent(feature));
}
else {
- RB_OBJ_WRITE(crr_obj, &crr->result, rb_funcallv(Qnil, require, 1, &crr->feature));
+ return rb_funcallv(Qnil, require, 1, &feature);
}
-
- return Qnil;
}
static VALUE
@@ -2325,38 +2499,27 @@ require_rescue(VALUE crr_obj, VALUE errinfo)
{
struct cross_ractor_require *crr;
TypedData_Get_Struct(crr_obj, struct cross_ractor_require, &cross_ractor_require_data_type, crr);
-
- RB_OBJ_WRITE(crr_obj, &crr->exception, errinfo);
-
- return Qundef;
+ crr->raised = true;
+ return errinfo;
}
static VALUE
-require_result_copy_body(VALUE crr_obj)
+require_result_send_body(VALUE ary)
{
- struct cross_ractor_require *crr;
- TypedData_Get_Struct(crr_obj, struct cross_ractor_require, &cross_ractor_require_data_type, crr);
+ VALUE port = RARRAY_AREF(ary, 0);
+ VALUE results = RARRAY_AREF(ary, 1);
- if (crr->exception != Qundef) {
- VM_ASSERT(crr->result == Qundef);
- RB_OBJ_WRITE(crr_obj, &crr->exception, ractor_copy(crr->exception));
- }
- else{
- VM_ASSERT(crr->result != Qundef);
- RB_OBJ_WRITE(crr_obj, &crr->result, ractor_copy(crr->result));
- }
+ rb_execution_context_t *ec = GET_EC();
+ ractor_port_send(ec, port, results, Qfalse);
return Qnil;
}
static VALUE
-require_result_copy_resuce(VALUE crr_obj, VALUE errinfo)
+require_result_send_resuce(VALUE port, VALUE errinfo)
{
- struct cross_ractor_require *crr;
- TypedData_Get_Struct(crr_obj, struct cross_ractor_require, &cross_ractor_require_data_type, crr);
-
- RB_OBJ_WRITE(crr_obj, &crr->exception, errinfo);
-
+ // TODO: need rescue?
+ ractor_port_send(GET_EC(), port, errinfo, Qfalse);
return Qnil;
}
@@ -2367,25 +2530,26 @@ ractor_require_protect(VALUE crr_obj, VALUE (*func)(VALUE))
TypedData_Get_Struct(crr_obj, struct cross_ractor_require, &cross_ractor_require_data_type, crr);
const bool silent = crr->silent;
+
VALUE debug, errinfo;
if (silent) {
debug = ruby_debug;
errinfo = rb_errinfo();
}
- // catch any error
- rb_rescue2(func, crr_obj,
- require_rescue, crr_obj, rb_eException, 0);
+ // get normal result or raised exception (with crr->raised == true)
+ VALUE result = rb_rescue2(func, crr_obj, require_rescue, crr_obj, rb_eException, 0);
if (silent) {
ruby_debug = debug;
rb_set_errinfo(errinfo);
}
- rb_rescue2(require_result_copy_body, crr_obj,
- require_result_copy_resuce, crr_obj, rb_eException, 0);
+ rb_rescue2(require_result_send_body,
+ // [port, [result, raised]]
+ rb_ary_new_from_args(2, crr->port, rb_ary_new_from_args(2, result, crr->raised ? Qtrue : Qfalse)),
+ require_result_send_resuce, rb_eException, crr->port);
- ractor_port_send(GET_EC(), crr->port, Qtrue, Qfalse);
RB_GC_GUARD(crr_obj);
return Qnil;
}
@@ -2404,13 +2568,12 @@ rb_ractor_require(VALUE feature, bool silent)
struct cross_ractor_require *crr;
VALUE crr_obj = TypedData_Make_Struct(0, struct cross_ractor_require, &cross_ractor_require_data_type, crr);
- FL_SET_RAW(crr_obj, RUBY_FL_SHAREABLE);
+ RB_OBJ_SET_SHAREABLE(crr_obj); // TODO: internal data?
// Convert feature to proper file path and make it shareable as fstring
- RB_OBJ_WRITE(crr_obj, &crr->feature, rb_fstring(FilePathValue(feature)));
- RB_OBJ_WRITE(crr_obj, &crr->port, ractor_port_new(GET_RACTOR()));
- crr->result = Qundef;
- crr->exception = Qundef;
+ RB_OBJ_WRITE(crr_obj, &crr->as.require.feature, rb_fstring(FilePathValue(feature)));
+ RB_OBJ_WRITE(crr_obj, &crr->port, rb_ractor_make_shareable(ractor_port_new(GET_RACTOR())));
+ crr->raised = false;
crr->silent = silent;
rb_execution_context_t *ec = GET_EC();
@@ -2418,20 +2581,17 @@ rb_ractor_require(VALUE feature, bool silent)
rb_ractor_interrupt_exec(main_r, ractor_require_func, (void *)crr_obj, rb_interrupt_exec_flag_value_data);
// wait for require done
- ractor_port_receive(ec, crr->port);
+ VALUE results = ractor_port_receive(ec, crr->port);
ractor_port_close(ec, crr->port);
- VALUE exc = crr->exception;
- VALUE result = crr->result;
+ VALUE exc = rb_ary_pop(results);
+ VALUE result = rb_ary_pop(results);
RB_GC_GUARD(crr_obj);
- if (exc != Qundef) {
- ractor_reset_belonging(exc);
- rb_exc_raise(exc);
+ if (RTEST(exc)) {
+ rb_exc_raise(result);
}
else {
- RUBY_ASSERT(result != Qundef);
- ractor_reset_belonging(result);
return result;
}
}
@@ -2447,10 +2607,7 @@ autoload_load_body(VALUE crr_obj)
{
struct cross_ractor_require *crr;
TypedData_Get_Struct(crr_obj, struct cross_ractor_require, &cross_ractor_require_data_type, crr);
-
- RB_OBJ_WRITE(crr_obj, &crr->result, rb_autoload_load(crr->module, crr->name));
-
- return Qnil;
+ return rb_autoload_load(crr->as.autoload.module, crr->as.autoload.name);
}
static VALUE
@@ -2464,27 +2621,26 @@ rb_ractor_autoload_load(VALUE module, ID name)
{
struct cross_ractor_require *crr;
VALUE crr_obj = TypedData_Make_Struct(0, struct cross_ractor_require, &cross_ractor_require_data_type, crr);
- FL_SET_RAW(crr_obj, RUBY_FL_SHAREABLE);
- RB_OBJ_WRITE(crr_obj, &crr->module, module);
- RB_OBJ_WRITE(crr_obj, &crr->name, name);
- RB_OBJ_WRITE(crr_obj, &crr->port, ractor_port_new(GET_RACTOR()));
- crr->result = Qundef;
- crr->exception = Qundef;
+ RB_OBJ_SET_SHAREABLE(crr_obj); // TODO: internal data?
+
+ RB_OBJ_WRITE(crr_obj, &crr->as.autoload.module, module);
+ RB_OBJ_WRITE(crr_obj, &crr->as.autoload.name, name);
+ RB_OBJ_WRITE(crr_obj, &crr->port, rb_ractor_make_shareable(ractor_port_new(GET_RACTOR())));
rb_execution_context_t *ec = GET_EC();
rb_ractor_t *main_r = GET_VM()->ractor.main_ractor;
rb_ractor_interrupt_exec(main_r, ractor_autoload_load_func, (void *)crr_obj, rb_interrupt_exec_flag_value_data);
// wait for require done
- ractor_port_receive(ec, crr->port);
+ VALUE results = ractor_port_receive(ec, crr->port);
ractor_port_close(ec, crr->port);
- VALUE exc = crr->exception;
- VALUE result = crr->result;
+ VALUE exc = rb_ary_pop(results);
+ VALUE result = rb_ary_pop(results);
RB_GC_GUARD(crr_obj);
- if (exc != Qundef) {
- rb_exc_raise(exc);
+ if (RTEST(exc)) {
+ rb_exc_raise(result);
}
else {
return result;
diff --git a/ractor.rb b/ractor.rb
index 5827f6672b..2dc60f5ff6 100644
--- a/ractor.rb
+++ b/ractor.rb
@@ -1,6 +1,4 @@
-# \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 creates a new \Ractor, which can run in parallel with other ractors.
#
# # The simplest ractor
# r = Ractor.new {puts "I am in Ractor!"}
@@ -11,28 +9,27 @@
# concerns such as data-races and race-conditions are not possible. The other benefit is parallelism.
#
# 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
+# Unlike in threads, ractors can't access all the objects available in other ractors. For example, objects normally
# available through variables in the outer scope are prohibited from being used across ractors.
#
# 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).)
+# # Ractor::IsolationError (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.
+# On CRuby (the default implementation), the Global Virtual Machine Lock (GVL) is held per ractor, so
+# ractors can run in parallel. This is unlike the situation with threads on CRuby.
#
# Instead of accessing shared state, objects should be passed to and from ractors by
# sending and receiving them 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 the Thread until our default port gets sent a message
# puts "I am in Ractor! a=#{a_in_ractor}"
# end
# r.send(a) # pass it
@@ -44,14 +41,14 @@
#
# == Shareable and unshareable objects
#
-# When an object is sent to and from a ractor, it's important to understand whether the
+# When an object is sent to 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.
#
-# Shareable objects are those which can be used by several threads without compromising
+# Shareable objects are those which can be used by several ractors at once 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
+# 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.
#
# Ractor.shareable?(1) #=> true -- numbers and other immutable basic values are shareable
@@ -67,12 +64,12 @@
# 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
+# When a shareable object is sent via #send, no additional processing occurs
+# on it and it becomes usable by both ractors. When an unshareable object is sent, it can be
+# either _copied_ or _moved_. Copying is the default, and it copies the object fully by
# deep cloning (Object#clone) the non-shareable parts of its structure.
#
-# data = ['foo', 'bar'.freeze]
+# data = ['foo'.dup, 'bar'.freeze]
# r = Ractor.new do
# data2 = Ractor.receive
# puts "In ractor: #{data2.object_id}, #{data2[0].object_id}, #{data2[1].object_id}"
@@ -83,8 +80,8 @@
#
# This will output something like:
#
-# In ractor: 340, 360, 320
-# Outside : 380, 400, 320
+# In ractor: 8, 16, 24
+# Outside : 32, 40, 24
#
# 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
@@ -110,12 +107,12 @@
# Outside: moved? true
# test.rb:9:in `method_missing': can not send any methods to a moved object (Ractor::MovedError)
#
-# Notice that even +inspect+ (and more basic methods like <tt>__id__</tt>) is inaccessible
+# Notice that even +inspect+ and more basic methods like <tt>__id__</tt> are 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
-# will be kept. We can not define mutable shareable objects in Ruby, but C extensions can introduce them.
+# +Class+ and +Module+ objects are shareable and their class/module definitions are shared between ractors.
+# \Ractor objects are also shareable. All operations on shareable objects are thread-safe across ractors.
+# Defining mutable, shareable objects in Ruby is not possible, 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
@@ -180,15 +177,16 @@
#
# == 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 the examples below, sometimes we use the following method to wait for ractors
+# to make progress or finish.
#
# 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, #join is used to wait for ractors to finish.
+# This is **only for demonstration purposes** and shouldn't be used in a real code.
+# Most of the time, #join is used to wait for ractors to finish and Ractor.receive is used
+# to wait for messages.
#
# == Reference
#
@@ -199,9 +197,9 @@ class Ractor
# call-seq:
# Ractor.new(*args, name: nil) {|*args| block } -> ractor
#
- # Create a new \Ractor with args and a block.
+ # Creates a new \Ractor with args and a block.
#
- # The given block (Proc) will be isolated (can't access any outer variables). +self+
+ # The given block (Proc) is isolated (can't access any outer variables). +self+
# inside the block will refer to the current \Ractor.
#
# r = Ractor.new { puts "Hi, I am #{self.inspect}" }
@@ -232,8 +230,8 @@ class Ractor
b = block # TODO: builtin bug
raise ArgumentError, "must be called with a block" unless block
if __builtin_cexpr!("RBOOL(ruby_single_main_ractor)")
- Kernel.warn("Ractor is experimental, and the behavior may change in future versions of Ruby! " \
- "Also there are many implementation issues.", uplevel: 0, category: :experimental)
+ Kernel.warn("Ractor API is experimental and may change in future versions of Ruby.",
+ uplevel: 0, category: :experimental)
end
loc = caller_locations(1, 1).first
loc = "#{loc.path}:#{loc.lineno}"
@@ -249,7 +247,7 @@ class Ractor
}
end
- # Returns the number of Ractors currently running or blocking (waiting).
+ # Returns the number of ractors currently running or blocking (waiting).
#
# Ractor.count #=> 1
# r = Ractor.new(name: 'example') { Ractor.receive }
@@ -265,11 +263,50 @@ class Ractor
#
# call-seq:
- # Ractor.select(*ports) -> [...]
+ # Ractor.select(*ractors_or_ports) -> [ractor or port, obj]
+ #
+ # Blocks the current Thread until one of the given ports has received a message. Returns an
+ # array of two elements where the first element is the Port and the second is the received object.
+ # This method can also accept Ractor objects themselves, and in that case will wait until one
+ # has terminated and return a two-element array where the first element is the ractor and the
+ # second is its termination value.
+ #
+ # p1, p2 = Ractor::Port.new, Ractor::Port.new
+ # ps = [p1, p2]
+ # rs = 2.times.map do |i|
+ # Ractor.new(ps.shift, i) do |p, i|
+ # sleep rand(0.99)
+ # p.send("r#{i}")
+ # sleep rand(0.99)
+ # "r#{i} done"
+ # end
+ # end
+ #
+ # waiting_on = [p1, p2, *rs]
+ # until waiting_on.empty?
+ # received_on, obj = Ractor.select(*waiting_on)
+ # waiting_on.delete(received_on)
+ # puts obj
+ # end
+ #
+ # # r0
+ # # r1
+ # # r1 done
+ # # r0 done
+ #
+ # The following example is almost equivalent to <code>ractors.map(&:value)</code> except the thread
+ # is unblocked when any of the ractors has terminated as opposed to waiting for their termination in
+ # the array element order.
+ #
+ # values = []
+ # until ractors.empty?
+ # r, val = Ractor.select(*ractors)
+ # ractors.delete(r)
+ # values << val
+ # end
#
- # TBD
def self.select(*ports)
- raise ArgumentError, 'specify at least one ractor or `yield_value`' if ports.empty?
+ raise ArgumentError, 'specify at least one Ractor::Port or Ractor' if ports.empty?
monitors = {} # Ractor::Port => Ractor
@@ -308,7 +345,7 @@ class Ractor
# call-seq:
# Ractor.receive -> obj
#
- # Receive a message from the default port.
+ # Receives a message from the current ractor's default port.
def self.receive
Ractor.current.default_port.receive
end
@@ -325,9 +362,9 @@ class Ractor
#
# call-seq:
- # ractor.send(msg) -> self
+ # ractor.send(msg, move: false) -> self
#
- # It is equivalent to default_port.send(msg)
+ # This is equivalent to Port#send to the ractor's #default_port.
def send(...)
default_port.send(...)
self
@@ -346,22 +383,22 @@ class Ractor
alias to_s inspect
- # The name set in Ractor.new, or +nil+.
+ # Returns the name set in Ractor.new, or +nil+.
def name
__builtin_cexpr! %q{RACTOR_PTR(self)->name}
end
class RemoteError
- # The Ractor an uncaught exception is raised in.
+ # The Ractor in which the uncaught exception was raised.
attr_reader :ractor
end
#
# call-seq:
- # Ractor.current.close -> true | false
+ # ractor.close -> true | false
#
- # Closes default_port. Closing port is allowed only by the ractor which creates this port.
- # So this close method also allowed by the current Ractor.
+ # Closes the default port. Closing a port is allowed only by the ractor which created the port.
+ # Therefore, the receiver must be the current ractor.
#
def close
default_port.close
@@ -373,7 +410,7 @@ class Ractor
#
# Checks if the object is shareable by ractors.
#
- # Ractor.shareable?(1) #=> true -- numbers and other immutable basic values are frozen
+ # Ractor.shareable?(1) #=> true -- numbers are shareable
# Ractor.shareable?('foo') #=> false, unless the string is frozen due to # frozen_string_literal: true
# Ractor.shareable?('foo'.freeze) #=> true
#
@@ -388,7 +425,7 @@ class Ractor
# call-seq:
# Ractor.make_shareable(obj, copy: false) -> shareable_obj
#
- # Make +obj+ shareable between ractors.
+ # Makes +obj+ shareable between ractors.
#
# +obj+ and all the objects it refers to will be frozen, unless they are
# already shareable.
@@ -431,8 +468,8 @@ class Ractor
end
end
- # get a value from ractor-local storage for current Ractor
- # Obsolete and use Ractor.[] instead.
+ # Gets a value from ractor-local storage for the current Ractor.
+ # Obsolete, use Ractor.[] instead.
def [](sym)
if (self != Ractor.current)
raise RuntimeError, "Cannot get ractor local storage for non-current ractor"
@@ -440,8 +477,8 @@ class Ractor
Primitive.ractor_local_value(sym)
end
- # set a value in ractor-local storage for current Ractor
- # Obsolete and use Ractor.[]= instead.
+ # Sets a value in ractor-local storage for the current Ractor.
+ # Obsolete, use Ractor.[]= instead.
def []=(sym, val)
if (self != Ractor.current)
raise RuntimeError, "Cannot set ractor local storage for non-current ractor"
@@ -449,12 +486,12 @@ class Ractor
Primitive.ractor_local_value_set(sym, val)
end
- # get a value from ractor-local storage of current Ractor
+ # Gets a value from ractor-local storage for the current Ractor.
def self.[](sym)
Primitive.ractor_local_value(sym)
end
- # set a value in ractor-local storage of current Ractor
+ # Sets a value in ractor-local storage for the current Ractor.
def self.[]=(sym, val)
Primitive.ractor_local_value_set(sym, val)
end
@@ -462,9 +499,9 @@ class Ractor
# call-seq:
# Ractor.store_if_absent(key){ init_block }
#
- # If the corresponding value is not set, yield a value with
- # init_block and store the value in thread-safe manner.
- # This method returns corresponding stored value.
+ # If the corresponding ractor-local value is not set, yields a value with
+ # init_block and stores the value in a thread-safe manner.
+ # This method returns the stored value.
#
# (1..10).map{
# Thread.new(it){|i|
@@ -474,17 +511,18 @@ class Ractor
# }.map(&:value).uniq.size #=> 1 and f() is called only once
#
def self.store_if_absent(sym)
+ Primitive.attr! :use_block
Primitive.ractor_local_value_store_if_absent(sym)
end
- # returns main ractor
+ # Returns the main ractor.
def self.main
__builtin_cexpr! %q{
rb_ractor_self(GET_VM()->ractor.main_ractor);
}
end
- # return true if the current ractor is main ractor
+ # Returns true if the current ractor is the main ractor.
def self.main?
__builtin_cexpr! %q{
RBOOL(GET_VM()->ractor.main_ractor == rb_ec_ractor_ptr(ec))
@@ -523,7 +561,7 @@ class Ractor
# call-seq:
# ractor.default_port -> port object
#
- # return default port of the Ractor.
+ # Returns the default port of the Ractor.
#
def default_port
__builtin_cexpr! %q{
@@ -535,14 +573,14 @@ class Ractor
# call-seq:
# ractor.join -> self
#
- # Wait for the termination of the Ractor.
- # If the Ractor was aborted (terminated with an exception),
- # Ractor#value is called to raise an exception.
+ # Waits for the termination of the Ractor.
+ # If the Ractor was aborted (terminated by an unhandled exception),
+ # the exception is raised in the current ractor.
#
# Ractor.new{}.join #=> ractor
#
# Ractor.new{ raise "foo" }.join
- # #=> raise an exception "foo (RuntimeError)"
+ # #=> raises the exception "foo (RuntimeError)"
#
def join
port = Port.new
@@ -561,9 +599,9 @@ class Ractor
# call-seq:
# ractor.value -> obj
#
- # Waits for +ractor+ to complete, using #join, and return its value or raise
- # the exception which terminated the Ractor. The value will not be copied even
- # if it is unshareable object. Therefore at most 1 Ractor can get a value.
+ # Waits for +ractor+ to complete and returns its value or raises the exception
+ # which terminated the Ractor. The termination value will be moved to the calling
+ # Ractor. Therefore, at most 1 Ractor can receive another ractor's termination value.
#
# r = Ractor.new{ [1, 2] }
# r.value #=> [1, 2] (unshareable object)
@@ -575,20 +613,15 @@ class Ractor
__builtin_ractor_value
end
- # keep it for compatibility
- def take
- Kernel.warn("Ractor#take was deprecated and use Ractor#value instead. This method will be removed after the end of Aug 2025", uplevel: 0)
- self.value
- end
-
#
# call-seq:
# ractor.monitor(port) -> self
#
- # Register port as a monitoring port. If the ractor terminated,
- # the port received a Symbol object.
- # :exited will be sent if the ractor terminated without an exception.
- # :aborted will be sent if the ractor terminated with a exception.
+ # Registers the port as a monitoring port for this ractor. When the ractor terminates,
+ # the port receives a Symbol object.
+ #
+ # * +:exited+ is sent if the ractor terminates without an unhandled exception.
+ # * +:aborted+ is sent if the ractor terminates by an unhandled exception.
#
# r = Ractor.new{ some_task() }
# r.monitor(port = Ractor::Port.new)
@@ -596,7 +629,7 @@ class Ractor
#
# r = Ractor.new{ raise "foo" }
# r.monitor(port = Ractor::Port.new)
- # port.receive #=> :terminated and r is terminated with an exception "foo"
+ # port.receive #=> :aborted and r is terminated by the RuntimeError "foo"
#
def monitor port
__builtin_ractor_monitor(port)
@@ -606,19 +639,61 @@ class Ractor
# call-seq:
# ractor.unmonitor(port) -> self
#
- # Unregister port from the monitoring ports.
+ # Unregisters the port from the monitoring ports for this ractor.
#
def unmonitor port
__builtin_ractor_unmonitor(port)
end
+ #
+ # call-seq:
+ # Ractor.shareable_proc(self: nil){} -> shareable proc
+ #
+ # Returns a shareable copy of the given block's Proc. The value of +self+
+ # in the Proc will be replaced with the value passed via the `self:` keyword,
+ # or +nil+ if not given.
+ #
+ # In a shareable Proc, access to any outer variables is prohibited.
+ #
+ # a = 42
+ # Ractor.shareable_proc{ p a }
+ # #=> can not isolate a Proc because it accesses outer variables (a). (Ractor::IsolationError)
+ #
+ # The value of `self` in the Proc must be a shareable object.
+ #
+ # Ractor.shareable_proc(self: self){}
+ # #=> self should be shareable: main (Ractor::IsolationError)
+ #
+ def self.shareable_proc self: nil
+ Primitive.attr! :use_block
+
+ __builtin_cexpr!(%Q{
+ ractor_shareable_proc(ec, *LOCAL_PTR(self), false)
+ })
+ end
+
+ #
+ # call-seq:
+ # Ractor.shareable_lambda(self: nil){} -> shareable lambda
+ #
+ # Same as Ractor.shareable_proc, but returns a lambda Proc.
+ #
+ def self.shareable_lambda self: nil
+ Primitive.attr! :use_block
+
+ __builtin_cexpr!(%Q{
+ ractor_shareable_proc(ec, *LOCAL_PTR(self), true)
+ })
+ end
+
# \Port objects transmit messages between Ractors.
class Port
#
# call-seq:
# port.receive -> msg
#
- # Receive a message to the port (which was sent there by Port#send).
+ # Receives a message from the port (which was sent there by Port#send). Only the ractor
+ # that created the port can receive messages this way.
#
# port = Ractor::Port.new
# r = Ractor.new port do |port|
@@ -628,9 +703,9 @@ class Ractor
# v1 = port.receive
# puts "Received: #{v1}"
# r.join
- # # Here will be printed: "Received: message1"
+ # # This will print: "Received: message1"
#
- # The method blocks if the message queue is empty.
+ # The method blocks the current Thread if the message queue is empty.
#
# port = Ractor::Port.new
# r = Ractor.new port do |port|
@@ -656,8 +731,8 @@ class Ractor
# Still received only one
# Received: message2
#
- # If close_incoming was called on the ractor, the method raises Ractor::ClosedError
- # if there are no more messages in the message queue:
+ # If the port is closed and there are no more messages in the message queue,
+ # the method raises Ractor::ClosedError.
#
# port = Ractor::Port.new
# port.close
@@ -673,27 +748,27 @@ class Ractor
# call-seq:
# port.send(msg, move: false) -> self
#
- # Send a message to a port to be accepted by port.receive.
+ # Sends a message to the port to be accepted by port.receive.
#
# port = Ractor::Port.new
- # r = Ractor.new do
- # r.send 'message'
+ # r = Ractor.new(port) do |port|
+ # port.send 'message'
# end
# value = port.receive
# puts "Received #{value}"
# # Prints: "Received: message"
#
- # The method is non-blocking (will return immediately even if the ractor is not ready
+ # The method is non-blocking (it will return immediately even if the ractor that created the port is not ready
# to receive anything):
#
# port = Ractor::Port.new
# r = Ractor.new(port) do |port|
- # port.send 'test'}
+ # port.send 'test'
# puts "Sent successfully"
# # Prints: "Sent successfully" immediately
# end
#
- # An attempt to send to a port which already closed its execution will raise Ractor::ClosedError.
+ # An attempt to send to a closed port will raise Ractor::ClosedError.
#
# r = Ractor.new {Ractor::Port.new}
# r.join
@@ -704,7 +779,7 @@ class Ractor
#
# If the +obj+ is unshareable, by default it will be copied into the receiving ractor by deep cloning.
#
- # If the object is shareable, it only send a reference to the object without cloning.
+ # If the object is shareable, a reference to the object will be sent to the receiving ractor.
#
def send obj, move: false
__builtin_cexpr! %q{
@@ -718,22 +793,10 @@ class Ractor
# call-seq:
# port.close
#
- # Close the port. On the closed port, sending is not prohibited.
- # Receiving is also not allowed if there is no sent messages arrived before closing.
- #
- # port = Ractor::Port.new
- # Ractor.new port do |port|
- # port.send 1 # OK
- # port.send 2 # OK
- # port.close
- # port.send 3 # raise Ractor::ClosedError
- # end
- #
- # port.receive #=> 1
- # port.receive #=> 2
- # port.receive #=> raise Ractor::ClosedError
+ # Closes the port. Sending to a closed port is prohibited.
+ # Receiving is also prohibited if there are no messages in its message queue.
#
- # Now, only a Ractor which creates the port is allowed to close ports.
+ # Only the Ractor which created the port is allowed to close it.
#
# port = Ractor::Port.new
# Ractor.new port do |port|
@@ -750,7 +813,7 @@ class Ractor
# call-seq:
# port.closed? -> true/false
#
- # Return the port is closed or not.
+ # Returns whether or not the port is closed.
def closed?
__builtin_cexpr! %q{
ractor_port_closed_p(ec, self);
diff --git a/ractor_core.h b/ractor_core.h
index 0656ce00a0..c692ebbbbf 100644
--- a/ractor_core.h
+++ b/ractor_core.h
@@ -9,6 +9,9 @@
#define RACTOR_CHECK_MODE (VM_CHECK_MODE || RUBY_DEBUG) && (SIZEOF_UINT64_T == SIZEOF_VALUE)
#endif
+// experimental flag because it is not sure it is the common pattern
+#define RUBY_TYPED_FROZEN_SHAREABLE_NO_REC RUBY_FL_FINALIZE
+
struct rb_ractor_sync {
// ractor lock
rb_nativethread_lock_t lock;
@@ -88,6 +91,8 @@ struct rb_ractor_struct {
// ractor local data
+ rb_serial_t next_ec_serial;
+
st_table *local_storage;
struct rb_id_table *idkey_local_storage;
VALUE local_storage_store_lock;
@@ -98,9 +103,24 @@ struct rb_ractor_struct {
VALUE verbose;
VALUE debug;
+ bool malloc_gc_disabled;
+ bool main_ractor;
void *newobj_cache;
}; // rb_ractor_t is defined in vm_core.h
+enum ractor_wakeup_status {
+ wakeup_none,
+ wakeup_by_send,
+ wakeup_by_interrupt,
+ // wakeup_by_close,
+};
+
+struct ractor_waiter {
+ enum ractor_wakeup_status wakeup_status;
+ rb_thread_t *th;
+ struct ccan_list_node node;
+ rb_atomic_t event_serial;
+};
static inline VALUE
rb_ractor_self(const rb_ractor_t *r)
@@ -138,6 +158,7 @@ VALUE rb_ractor_require(VALUE feature, bool silent);
VALUE rb_ractor_autoload_load(VALUE space, ID id);
VALUE rb_ractor_ensure_shareable(VALUE obj, VALUE name);
+st_table *rb_ractor_targeted_hooks(rb_ractor_t *cr);
RUBY_SYMBOL_EXPORT_BEGIN
void rb_ractor_finish_marking(void);
@@ -244,6 +265,25 @@ rb_ractor_id(const rb_ractor_t *r)
return r->pub.id;
}
+static inline void
+rb_ractor_targeted_hooks_incr(rb_ractor_t *cr)
+{
+ cr->pub.targeted_hooks_cnt++;
+}
+
+static inline void
+rb_ractor_targeted_hooks_decr(rb_ractor_t *cr)
+{
+ RUBY_ASSERT(cr->pub.targeted_hooks_cnt > 0);
+ cr->pub.targeted_hooks_cnt--;
+}
+
+static inline unsigned int
+rb_ractor_targeted_hooks_cnt(rb_ractor_t *cr)
+{
+ return cr->pub.targeted_hooks_cnt;
+}
+
#if RACTOR_CHECK_MODE > 0
# define RACTOR_BELONGING_ID(obj) (*(uint32_t *)(((uintptr_t)(obj)) + rb_gc_obj_slot_size(obj)))
diff --git a/ractor_sync.c b/ractor_sync.c
index 52ce953851..44c84ded92 100644
--- a/ractor_sync.c
+++ b/ractor_sync.c
@@ -1,4 +1,3 @@
-
// this file is included by ractor.c
struct ractor_port {
@@ -29,27 +28,15 @@ ractor_port_mark(void *ptr)
}
}
-static void
-ractor_port_free(void *ptr)
-{
- xfree(ptr);
-}
-
-static size_t
-ractor_port_memsize(const void *ptr)
-{
- return sizeof(struct ractor_port);
-}
-
static const rb_data_type_t ractor_port_data_type = {
"ractor/port",
{
ractor_port_mark,
- ractor_port_free,
- ractor_port_memsize,
+ RUBY_TYPED_DEFAULT_FREE,
+ NULL, // memsize
NULL, // update
},
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FROZEN_SHAREABLE | RUBY_TYPED_EMBEDDABLE,
};
static st_data_t
@@ -63,8 +50,7 @@ static struct ractor_port *
RACTOR_PORT_PTR(VALUE self)
{
VM_ASSERT(rb_typeddata_is_kind_of(self, &ractor_port_data_type));
- struct ractor_port *rp = DATA_PTR(self);
- return rp;
+ return RTYPEDDATA_GET_DATA(self);
}
static VALUE
@@ -72,6 +58,7 @@ ractor_port_alloc(VALUE klass)
{
struct ractor_port *rp;
VALUE rpv = TypedData_Make_Struct(klass, struct ractor_port, &ractor_port_data_type, rp);
+ rb_obj_freeze(rpv);
return rpv;
}
@@ -230,7 +217,7 @@ ractor_basket_mark(const struct ractor_basket *b)
static void
ractor_basket_free(struct ractor_basket *b)
{
- xfree(b);
+ SIZED_FREE(b);
}
static struct ractor_basket *
@@ -284,7 +271,7 @@ ractor_queue_free(struct ractor_queue *rq)
VM_ASSERT(ccan_list_empty(&rq->set));
- xfree(rq);
+ SIZED_FREE(rq);
}
RBIMPL_ATTR_MAYBE_UNUSED()
@@ -395,7 +382,6 @@ ractor_add_port(rb_ractor_t *r, st_data_t id)
RACTOR_LOCK(r);
{
- // memo: can cause GC, but GC doesn't use ractor locking.
st_insert(r->sync.ports, id, (st_data_t)rq);
}
RACTOR_UNLOCK(r);
@@ -575,7 +561,7 @@ ractor_monitor(rb_execution_context_t *ec, VALUE self, VALUE port)
RACTOR_UNLOCK(r);
if (terminated) {
- xfree(rm);
+ SIZED_FREE(rm);
ractor_port_send(ec, port, ractor_exit_token(r->sync.legacy_exc), Qfalse);
return Qfalse;
@@ -603,7 +589,7 @@ ractor_unmonitor(rb_execution_context_t *ec, VALUE self, VALUE port)
(unsigned int)ractor_port_id(&rm->port),
(unsigned int)rb_ractor_id(rm->port.r));
ccan_list_del(&rm->node);
- xfree(rm);
+ SIZED_FREE(rm);
}
}
}
@@ -641,7 +627,7 @@ ractor_notify_exit(rb_execution_context_t *ec, rb_ractor_t *cr, VALUE legacy, bo
ractor_try_send(ec, &rm->port, token, false);
ccan_list_del(&rm->node);
- xfree(rm);
+ SIZED_FREE(rm);
}
VM_ASSERT(ccan_list_empty(&cr->sync.monitors));
@@ -699,7 +685,12 @@ ractor_sync_free(rb_ractor_t *r)
static size_t
ractor_sync_memsize(const rb_ractor_t *r)
{
- return st_table_size(r->sync.ports);
+ if (r->sync.ports) {
+ return st_table_size(r->sync.ports);
+ }
+ else {
+ return 0;
+ }
}
static void
@@ -844,20 +835,6 @@ ractor_basket_accept(struct ractor_basket *b)
// Ractor blocking by receive
-enum ractor_wakeup_status {
- wakeup_none,
- wakeup_by_send,
- wakeup_by_interrupt,
-
- // wakeup_by_close,
-};
-
-struct ractor_waiter {
- enum ractor_wakeup_status wakeup_status;
- rb_thread_t *th;
- struct ccan_list_node node;
-};
-
#if VM_CHECK_MODE > 0
static bool
ractor_waiter_included(rb_ractor_t *cr, rb_thread_t *th)
@@ -1000,6 +977,7 @@ ubf_ractor_wait(void *ptr)
rb_thread_t *th = waiter->th;
rb_ractor_t *r = th->ractor;
+ rb_atomic_t event_serial = waiter->event_serial;
// clear ubf and nobody can kick UBF
th->unblock.func = NULL;
@@ -1009,7 +987,7 @@ ubf_ractor_wait(void *ptr)
{
RACTOR_LOCK(r);
{
- if (waiter->wakeup_status == wakeup_none) {
+ if (RUBY_ATOMIC_LOAD(th->unblock.event_serial) == event_serial && waiter->wakeup_status == wakeup_none) {
RUBY_DEBUG_LOG("waiter:%p", (void *)waiter);
waiter->wakeup_status = wakeup_by_interrupt;
@@ -1255,14 +1233,18 @@ ractor_selector_free(void *ptr)
{
struct ractor_selector *s = ptr;
st_free_table(s->ports);
- ruby_xfree(ptr);
+ SIZED_FREE(s);
}
static size_t
ractor_selector_memsize(const void *ptr)
{
const struct ractor_selector *s = ptr;
- return sizeof(struct ractor_selector) + st_memsize(s->ports);
+ size_t size = sizeof(struct ractor_selector);
+ if (s->ports) {
+ size += st_memsize(s->ports);
+ }
+ return size;
}
static const rb_data_type_t ractor_selector_data_type = {
diff --git a/random.c b/random.c
index 9b8cec40b4..63f43a161a 100644
--- a/random.c
+++ b/random.c
@@ -230,7 +230,7 @@ int_pair_to_real_inclusive(uint32_t a, uint32_t b)
const uint128_t m = ((uint128_t)1 << dig) | 1;
uint128_t x = ((uint128_t)a << 32) | b;
r = (double)(uint64_t)((x * m) >> 64);
-#elif defined HAVE_UINT64_T && !MSC_VERSION_BEFORE(1300)
+#elif defined HAVE_UINT64_T
uint64_t x = ((uint64_t)a << dig_u) +
(((uint64_t)b + (a >> dig_u)) >> dig_r64);
r = (double)x;
@@ -315,31 +315,24 @@ get_rnd_mt(VALUE obj)
}
static rb_random_t *
-try_get_rnd(VALUE obj)
+try_get_rnd(VALUE obj, const rb_random_interface_t **rng_p)
{
if (obj == rb_cRandom) {
+ *rng_p = &random_mt_if;
return default_rand_start();
}
if (!rb_typeddata_is_kind_of(obj, &rb_random_data_type)) return NULL;
- if (RTYPEDDATA_TYPE(obj) == &random_mt_type)
- return rand_start(DATA_PTR(obj), obj);
- rb_random_t *rnd = DATA_PTR(obj);
+ const struct rb_data_type_struct *type = RTYPEDDATA_TYPE(obj);
+ *rng_p = type->data;
+ void *rnd = DATA_PTR(obj);
if (!rnd) {
rb_raise(rb_eArgError, "uninitialized random: %s",
RTYPEDDATA_TYPE(obj)->wrap_struct_name);
}
+ if (type == &random_mt_type) rnd = rand_start(rnd, obj);
return rnd;
}
-static const rb_random_interface_t *
-try_rand_if(VALUE obj, rb_random_t *rnd)
-{
- if (rnd == &default_rand()->base) {
- return &random_mt_if;
- }
- return rb_rand_if(obj);
-}
-
/* :nodoc: */
void
rb_random_base_init(rb_random_t *rnd)
@@ -360,15 +353,23 @@ random_alloc(VALUE klass)
static VALUE
rand_init_default(const rb_random_interface_t *rng, rb_random_t *rnd)
{
- VALUE seed, buf0 = 0;
+ VALUE seed;
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);
- rng->init(rnd, buf, len);
- seed = make_seed_value(buf, len);
- explicit_bzero(buf, len * sizeof(*buf));
- ALLOCV_END(buf0);
+ if (LIKELY(len)) {
+ VALUE buf0 = 0;
+ uint32_t *buf = ALLOCV_N(uint32_t, buf0, len);
+ fill_random_seed(buf, len, true);
+ rng->init(rnd, buf, len);
+ seed = make_seed_value(buf, len);
+ explicit_bzero(buf, len * sizeof(*buf));
+ ALLOCV_END(buf0);
+ }
+ else {
+ uint32_t minimul[1] = {0};
+ rng->init(rnd, minimul, 0);
+ seed = INT2FIX(0);
+ }
return seed;
}
@@ -412,8 +413,8 @@ rand_init(const rb_random_interface_t *rng, rb_random_t *rnd, VALUE seed)
static VALUE
random_init(int argc, VALUE *argv, VALUE obj)
{
- rb_random_t *rnd = try_get_rnd(obj);
- const rb_random_interface_t *rng = rb_rand_if(obj);
+ const rb_random_interface_t *rng = NULL;
+ rb_random_t *rnd = try_get_rnd(obj, &rng);
if (!rng) {
rb_raise(rb_eTypeError, "undefined random interface: %s",
@@ -565,36 +566,29 @@ fill_random_bytes_lib(void *buf, size_t size)
static const HCRYPTPROV INVALID_HCRYPTPROV = (HCRYPTPROV)INVALID_HANDLE_VALUE;
static void
-release_crypt(void *p)
+release_crypt(VALUE arg)
{
- HCRYPTPROV *ptr = p;
+ HCRYPTPROV *ptr = (void *)arg;
HCRYPTPROV prov = (HCRYPTPROV)ATOMIC_PTR_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);
if (LIKELY(!old_prov)) { /* no other threads acquired */
if (prov != INVALID_HCRYPTPROV) {
- DATA_PTR(wrapper) = (void *)prov;
- rb_vm_register_global_object(wrapper);
+ /* register only once; perm_prov == 0 at the first call only */
+ rb_set_end_proc(release_crypt, (VALUE)&perm_prov);
}
}
else { /* another thread acquired */
@@ -606,7 +600,7 @@ fill_random_bytes_crypt(void *seed, size_t size)
}
if (prov == INVALID_HCRYPTPROV) return -1;
while (size > 0) {
- DWORD n = (size > (size_t)DWORD_MAX) ? DWORD_MAX : (DWORD)size;
+ DWORD n = (size > (size_t)DWORD_MAX) ? DWORD_MAX/2+1 : (DWORD)size;
if (!CryptGenRandom(prov, n, seed)) return -1;
seed = (char *)seed + n;
size -= n;
@@ -621,7 +615,7 @@ static int
fill_random_bytes_bcrypt(void *seed, size_t size)
{
while (size > 0) {
- ULONG n = (size > (size_t)ULONG_MAX) ? LONG_MAX : (ULONG)size;
+ ULONG n = (size > (size_t)ULONG_MAX) ? ULONG_MAX/2+1 : (ULONG)size;
if (BCryptGenRandom(NULL, seed, n, BCRYPT_USE_SYSTEM_PREFERRED_RNG))
return -1;
seed = (char *)seed + n;
@@ -1130,17 +1124,18 @@ random_int32(const rb_random_interface_t *rng, rb_random_t *rnd)
unsigned int
rb_random_int32(VALUE obj)
{
- rb_random_t *rnd = try_get_rnd(obj);
+ const rb_random_interface_t *rng;
+ rb_random_t *rnd = try_get_rnd(obj, &rng);
if (!rnd) {
uint32_t x;
obj_random_bytes(obj, &x, sizeof(x));
return (unsigned int)x;
}
- return random_int32(try_rand_if(obj, rnd), rnd);
+ return random_int32(rng, rnd);
}
static double
-random_real(VALUE obj, rb_random_t *rnd, int excl)
+random_real(VALUE obj, const rb_random_interface_t *rng, rb_random_t *rnd, int excl)
{
uint32_t a, b;
@@ -1151,7 +1146,6 @@ random_real(VALUE obj, rb_random_t *rnd, int excl)
b = x[1];
}
else {
- const rb_random_interface_t *rng = try_rand_if(obj, rnd);
if (rng->get_real) return rng->get_real(rnd, excl);
a = random_int32(rng, rnd);
b = random_int32(rng, rnd);
@@ -1173,7 +1167,8 @@ rb_int_pair_to_real(uint32_t a, uint32_t b, int excl)
double
rb_random_real(VALUE obj)
{
- rb_random_t *rnd = try_get_rnd(obj);
+ const rb_random_interface_t *rng;
+ rb_random_t *rnd = try_get_rnd(obj, &rng);
if (!rnd) {
VALUE v = rb_funcallv(obj, id_rand, 0, 0);
double d = NUM2DBL(v);
@@ -1185,7 +1180,7 @@ rb_random_real(VALUE obj)
}
return d;
}
- return random_real(obj, rnd, TRUE);
+ return random_real(obj, rng, rnd, TRUE);
}
static inline VALUE
@@ -1202,7 +1197,7 @@ ulong_to_num_plus_1(unsigned long n)
}
static unsigned long
-random_ulong_limited(VALUE obj, rb_random_t *rnd, unsigned long limit)
+random_ulong_limited(VALUE obj, const rb_random_interface_t *rng, rb_random_t *rnd, unsigned long limit)
{
if (!limit) return 0;
if (!rnd) {
@@ -1227,13 +1222,14 @@ random_ulong_limited(VALUE obj, rb_random_t *rnd, unsigned long limit)
} while (limit < val);
return val;
}
- return limited_rand(try_rand_if(obj, rnd), rnd, limit);
+ return limited_rand(rng, rnd, limit);
}
unsigned long
rb_random_ulong_limited(VALUE obj, unsigned long limit)
{
- rb_random_t *rnd = try_get_rnd(obj);
+ const rb_random_interface_t *rng;
+ rb_random_t *rnd = try_get_rnd(obj, &rng);
if (!rnd) {
VALUE lim = ulong_to_num_plus_1(limit);
VALUE v = rb_to_int(rb_funcallv_public(obj, id_rand, 1, &lim));
@@ -1246,11 +1242,11 @@ rb_random_ulong_limited(VALUE obj, unsigned long limit)
}
return r;
}
- return limited_rand(try_rand_if(obj, rnd), rnd, limit);
+ return limited_rand(rng, rnd, limit);
}
static VALUE
-random_ulong_limited_big(VALUE obj, rb_random_t *rnd, VALUE vmax)
+random_ulong_limited_big(VALUE obj, const rb_random_interface_t *rng, rb_random_t *rnd, VALUE vmax)
{
if (!rnd) {
VALUE v, vtmp;
@@ -1275,7 +1271,7 @@ random_ulong_limited_big(VALUE obj, rb_random_t *rnd, VALUE vmax)
ALLOCV_END(vtmp);
return v;
}
- return limited_big_rand(try_rand_if(obj, rnd), rnd, vmax);
+ return limited_big_rand(rng, rnd, vmax);
}
static VALUE
@@ -1301,8 +1297,9 @@ rand_bytes(const rb_random_interface_t *rng, rb_random_t *rnd, long n)
static VALUE
random_bytes(VALUE obj, VALUE len)
{
- rb_random_t *rnd = try_get_rnd(obj);
- return rand_bytes(rb_rand_if(obj), rnd, NUM2LONG(rb_to_int(len)));
+ const rb_random_interface_t *rng = NULL;
+ rb_random_t *rnd = try_get_rnd(obj, &rng);
+ return rand_bytes(rng, rnd, NUM2LONG(rb_to_int(len)));
}
void
@@ -1331,11 +1328,12 @@ rb_rand_bytes_int32(rb_random_get_int32_func *get_int32,
VALUE
rb_random_bytes(VALUE obj, long n)
{
- rb_random_t *rnd = try_get_rnd(obj);
+ const rb_random_interface_t *rng;
+ rb_random_t *rnd = try_get_rnd(obj, &rng);
if (!rnd) {
return obj_random_bytes(obj, NULL, n);
}
- return rand_bytes(try_rand_if(obj, rnd), rnd, n);
+ return rand_bytes(rng, rnd, n);
}
/*
@@ -1387,7 +1385,7 @@ range_values(VALUE vmax, VALUE *begp, VALUE *endp, int *exclp)
}
static VALUE
-rand_int(VALUE obj, rb_random_t *rnd, VALUE vmax, int restrictive)
+rand_int(VALUE obj, const rb_random_interface_t *rng, rb_random_t *rnd, VALUE vmax, int restrictive)
{
/* mt must be initialized */
unsigned long r;
@@ -1399,7 +1397,7 @@ rand_int(VALUE obj, rb_random_t *rnd, VALUE vmax, int restrictive)
if (restrictive) return Qnil;
max = -max;
}
- r = random_ulong_limited(obj, rnd, (unsigned long)max - 1);
+ r = random_ulong_limited(obj, rng, rnd, (unsigned long)max - 1);
return ULONG2NUM(r);
}
else {
@@ -1413,10 +1411,10 @@ rand_int(VALUE obj, rb_random_t *rnd, VALUE vmax, int restrictive)
if (FIXNUM_P(vmax)) {
long max = FIX2LONG(vmax);
if (max == -1) return Qnil;
- r = random_ulong_limited(obj, rnd, max);
+ r = random_ulong_limited(obj, rng, rnd, max);
return LONG2NUM(r);
}
- ret = random_ulong_limited_big(obj, rnd, vmax);
+ ret = random_ulong_limited_big(obj, rng, rnd, vmax);
RB_GC_GUARD(vmax);
return ret;
}
@@ -1460,7 +1458,7 @@ float_value(VALUE v)
}
static inline VALUE
-rand_range(VALUE obj, rb_random_t* rnd, VALUE range)
+rand_range(VALUE obj, const rb_random_interface_t *rng, rb_random_t* rnd, VALUE range)
{
VALUE beg = Qundef, end = Qundef, vmax, v;
int excl = 0;
@@ -1475,7 +1473,7 @@ rand_range(VALUE obj, rb_random_t* rnd, VALUE range)
fixnum:
if (FIXNUM_P(vmax)) {
if ((max = FIX2LONG(vmax) - excl) >= 0) {
- unsigned long r = random_ulong_limited(obj, rnd, (unsigned long)max);
+ unsigned long r = random_ulong_limited(obj, rng, rnd, (unsigned long)max);
v = ULONG2NUM(r);
}
}
@@ -1485,7 +1483,7 @@ rand_range(VALUE obj, rb_random_t* rnd, VALUE range)
excl = 0;
goto fixnum;
}
- v = random_ulong_limited_big(obj, rnd, vmax);
+ v = random_ulong_limited_big(obj, rng, rnd, vmax);
}
}
else if (v = rb_check_to_float(vmax), !NIL_P(v)) {
@@ -1503,7 +1501,7 @@ rand_range(VALUE obj, rb_random_t* rnd, VALUE range)
}
v = Qnil;
if (max > 0.0) {
- r = random_real(obj, rnd, excl);
+ r = random_real(obj, rng, rnd, excl);
if (scale > 1) {
return rb_float_new(+(+(+(r - 0.5) * max) * scale) + mid);
}
@@ -1536,7 +1534,7 @@ rand_range(VALUE obj, rb_random_t* rnd, VALUE range)
return v;
}
-static VALUE rand_random(int argc, VALUE *argv, VALUE obj, rb_random_t *rnd);
+static VALUE rand_random(int argc, VALUE *argv, VALUE obj, const rb_random_interface_t *rng, rb_random_t *rnd);
/*
* call-seq:
@@ -1552,9 +1550,11 @@ static VALUE rand_random(int argc, VALUE *argv, VALUE obj, rb_random_t *rnd);
* prng.rand(100) # => 42
*
* When +max+ is a Float, +rand+ returns a random floating point number
- * between 0.0 and +max+, including 0.0 and excluding +max+.
+ * between 0.0 and +max+, including 0.0 and excluding +max+. Note that it
+ * behaves differently from Kernel.rand.
*
- * prng.rand(1.5) # => 1.4600282860034115
+ * prng.rand(1.5) # => 1.4600282860034115
+ * rand(1.5) # => 0
*
* When +range+ is a Range, +rand+ returns a random number where
* <code>range.member?(number) == true</code>.
@@ -1571,24 +1571,26 @@ static VALUE rand_random(int argc, VALUE *argv, VALUE obj, rb_random_t *rnd);
static VALUE
random_rand(int argc, VALUE *argv, VALUE obj)
{
- VALUE v = rand_random(argc, argv, obj, try_get_rnd(obj));
+ const rb_random_interface_t *rng = NULL;
+ rb_random_t *rnd = try_get_rnd(obj, &rng);
+ VALUE v = rand_random(argc, argv, obj, rng, rnd);
check_random_number(v, argv);
return v;
}
static VALUE
-rand_random(int argc, VALUE *argv, VALUE obj, rb_random_t *rnd)
+rand_random(int argc, VALUE *argv, VALUE obj, const rb_random_interface_t *rng, rb_random_t *rnd)
{
VALUE vmax, v;
if (rb_check_arity(argc, 0, 1) == 0) {
- return rb_float_new(random_real(obj, rnd, TRUE));
+ return rb_float_new(random_real(obj, rng, rnd, TRUE));
}
vmax = argv[0];
if (NIL_P(vmax)) return Qnil;
if (!RB_FLOAT_TYPE_P(vmax)) {
v = rb_check_to_int(vmax);
- if (!NIL_P(v)) return rand_int(obj, rnd, v, 1);
+ if (!NIL_P(v)) return rand_int(obj, rng, rnd, v, 1);
}
v = rb_check_to_float(vmax);
if (!NIL_P(v)) {
@@ -1597,12 +1599,12 @@ rand_random(int argc, VALUE *argv, VALUE obj, rb_random_t *rnd)
return Qnil;
}
else {
- double r = random_real(obj, rnd, TRUE);
+ double r = random_real(obj, rng, rnd, TRUE);
if (max > 0.0) r *= max;
return rb_float_new(r);
}
}
- return rand_range(obj, rnd, vmax);
+ return rand_range(obj, rng, rnd, vmax);
}
/*
@@ -1620,9 +1622,10 @@ rand_random(int argc, VALUE *argv, VALUE obj, rb_random_t *rnd)
static VALUE
rand_random_number(int argc, VALUE *argv, VALUE obj)
{
- rb_random_t *rnd = try_get_rnd(obj);
- VALUE v = rand_random(argc, argv, obj, rnd);
- if (NIL_P(v)) v = rand_random(0, 0, obj, rnd);
+ const rb_random_interface_t *rng = NULL;
+ rb_random_t *rnd = try_get_rnd(obj, &rng);
+ VALUE v = rand_random(argc, argv, obj, rng, rnd);
+ if (NIL_P(v)) v = rand_random(0, 0, obj, rng, rnd);
else if (!v) invalid_argument(argv[0]);
return v;
}
@@ -1692,25 +1695,28 @@ rand_mt_equal(VALUE self, VALUE other)
* Kernel.srand may be used to ensure that sequences of random numbers are
* reproducible between different runs of a program.
*
- * See also Random.rand.
+ * Related: Random.rand.
+ * rand(100.0) # => 64 (Integer because max.to_i is 100)
+ * Random.rand(100.0) # => 30.315320967824523
*/
static VALUE
rb_f_rand(int argc, VALUE *argv, VALUE obj)
{
VALUE vmax;
+ const rb_random_interface_t *rng = &random_mt_if;
rb_random_t *rnd = default_rand_start();
if (rb_check_arity(argc, 0, 1) && !NIL_P(vmax = argv[0])) {
- VALUE v = rand_range(obj, rnd, vmax);
+ VALUE v = rand_range(obj, rng, rnd, vmax);
if (v != Qfalse) return v;
vmax = rb_to_int(vmax);
if (vmax != INT2FIX(0)) {
- v = rand_int(obj, rnd, vmax, 0);
+ v = rand_int(obj, rng, rnd, vmax, 0);
if (!NIL_P(v)) return v;
}
}
- return DBL2NUM(random_real(obj, rnd, TRUE));
+ return DBL2NUM(random_real(obj, rng, rnd, TRUE));
}
/*
@@ -1726,7 +1732,7 @@ rb_f_rand(int argc, VALUE *argv, VALUE obj)
static VALUE
random_s_rand(int argc, VALUE *argv, VALUE obj)
{
- VALUE v = rand_random(argc, argv, Qnil, default_rand_start());
+ VALUE v = rand_random(argc, argv, Qnil, &random_mt_if, default_rand_start());
check_random_number(v, argv);
return v;
}
@@ -1778,8 +1784,10 @@ st_index_t
rb_memhash(const void *ptr, long len)
{
sip_uint64_t h = sip_hash13(hash_salt.key.sip, ptr, len);
-#ifdef HAVE_UINT64_T
+#if SIZEOF_ST_INDEX_T >= 8
return (st_index_t)h;
+#elif defined HAVE_UINT64_T
+ return (st_index_t)((h >> 32) ^ h);
#else
return (st_index_t)(h.u32[0] ^ h.u32[1]);
#endif
diff --git a/range.c b/range.c
index 615154be4c..041cd93f73 100644
--- a/range.c
+++ b/range.c
@@ -154,14 +154,14 @@ recursive_equal(VALUE range, VALUE obj, int recur)
* call-seq:
* self == other -> true or false
*
- * Returns +true+ if and only if:
+ * Returns whether all of the following are true:
*
* - +other+ is a range.
* - <tt>other.begin == self.begin</tt>.
* - <tt>other.end == self.end</tt>.
* - <tt>other.exclude_end? == self.exclude_end?</tt>.
*
- * Otherwise returns +false+.
+ * Examples:
*
* r = (1..5)
* r == (1..5) # => true
@@ -200,11 +200,10 @@ range_eq(VALUE range, VALUE obj)
static int
r_less(VALUE a, VALUE b)
{
- VALUE r = rb_funcall(a, id_cmp, 1, b);
-
- if (NIL_P(r))
- return INT_MAX;
- return rb_cmpint(r, a, b);
+ VALUE r;
+#define rb_cmpint(cmp, a, b) (NIL_P(r = (cmp)) ? INT_MAX : rb_cmpint(r, (a), (b)))
+ return OPTIMIZED_CMP(a, b);
+#undef rb_cmpint
}
static VALUE
@@ -784,7 +783,7 @@ bsearch_integer_range(VALUE beg, VALUE end, int excl)
*
* Returns an element from +self+ selected by a binary search.
*
- * See {Binary Searching}[rdoc-ref:bsearch.rdoc].
+ * See {Binary Searching}[rdoc-ref:language/bsearch.rdoc].
*
*/
@@ -1018,6 +1017,29 @@ range_to_a(VALUE range)
return rb_call_super(0, 0);
}
+/*
+ * call-seq:
+ * to_set -> set
+ *
+ * Returns a set containing the elements in +self+, if a finite collection;
+ * raises an exception otherwise.
+ *
+ * (1..4).to_set # => Set[1, 2, 3, 4]
+ * (1...4).to_set # => Set[1, 2, 3]
+ *
+ * (1..).to_set
+ * # in 'Range#to_set': cannot convert endless range to a set (RangeError)
+ *
+ */
+static VALUE
+range_to_set(VALUE range)
+{
+ if (NIL_P(RANGE_END(range))) {
+ rb_raise(rb_eRangeError, "cannot convert endless range to a set");
+ }
+ return rb_call_super(0, NULL);
+}
+
static VALUE
range_enum_size(VALUE range, VALUE args, VALUE eobj)
{
@@ -2031,10 +2053,9 @@ VALUE rb_str_include_range_p(VALUE beg, VALUE end, VALUE val, VALUE exclusive);
/*
* call-seq:
- * self === object -> true or false
+ * self === other -> true or false
*
- * Returns +true+ if +object+ is between <tt>self.begin</tt> and <tt>self.end</tt>.
- * +false+ otherwise:
+ * Returns whether +other+ is between <tt>self.begin</tt> and <tt>self.end</tt>:
*
* (1..4) === 2 # => true
* (1..4) === 5 # => false
@@ -2589,12 +2610,12 @@ range_overlap(VALUE range, VALUE other)
*
* - Method Range.new:
*
- * # Ranges that by default include the given end value.
- * Range.new(1, 4).to_a # => [1, 2, 3, 4]
- * Range.new('a', 'd').to_a # => ["a", "b", "c", "d"]
- * # Ranges that use third argument +exclude_end+ to exclude the given end value.
- * Range.new(1, 4, true).to_a # => [1, 2, 3]
- * Range.new('a', 'd', true).to_a # => ["a", "b", "c"]
+ * # Ranges that by default include the given end value.
+ * Range.new(1, 4).to_a # => [1, 2, 3, 4]
+ * Range.new('a', 'd').to_a # => ["a", "b", "c", "d"]
+ * # Ranges that use third argument +exclude_end+ to exclude the given end value.
+ * Range.new(1, 4, true).to_a # => [1, 2, 3]
+ * Range.new('a', 'd', true).to_a # => ["a", "b", "c"]
*
* == Beginless Ranges
*
@@ -2746,8 +2767,8 @@ range_overlap(VALUE range, VALUE other)
*
* First, what's elsewhere. Class \Range:
*
- * - Inherits from {class Object}[rdoc-ref:Object@What-27s+Here].
- * - Includes {module Enumerable}[rdoc-ref:Enumerable@What-27s+Here],
+ * - Inherits from {class Object}[rdoc-ref:Object@Whats+Here].
+ * - Includes {module Enumerable}[rdoc-ref:Enumerable@Whats+Here],
* which provides dozens of additional methods.
*
* Here, class \Range provides methods that are useful for:
@@ -2845,6 +2866,7 @@ Init_Range(void)
rb_define_method(rb_cRange, "minmax", range_minmax, 0);
rb_define_method(rb_cRange, "size", range_size, 0);
rb_define_method(rb_cRange, "to_a", range_to_a, 0);
+ rb_define_method(rb_cRange, "to_set", range_to_set, 0);
rb_define_method(rb_cRange, "entries", range_to_a, 0);
rb_define_method(rb_cRange, "to_s", range_to_s, 0);
rb_define_method(rb_cRange, "inspect", range_inspect, 0);
diff --git a/rational.c b/rational.c
index 89e74c328d..b031838d69 100644
--- a/rational.c
+++ b/rational.c
@@ -27,6 +27,7 @@
#include "internal.h"
#include "internal/array.h"
#include "internal/complex.h"
+#include "internal/error.h"
#include "internal/gc.h"
#include "internal/numeric.h"
#include "internal/object.h"
@@ -175,22 +176,6 @@ f_idiv(VALUE x, VALUE y)
#define f_expt10(x) rb_int_pow(INT2FIX(10), x)
inline static int
-f_zero_p(VALUE x)
-{
- if (RB_INTEGER_TYPE_P(x)) {
- return FIXNUM_ZERO_P(x);
- }
- else if (RB_TYPE_P(x, T_RATIONAL)) {
- VALUE num = RRATIONAL(x)->num;
-
- return FIXNUM_ZERO_P(num);
- }
- return (int)rb_equal(x, ZERO);
-}
-
-#define f_nonzero_p(x) (!f_zero_p(x))
-
-inline static int
f_one_p(VALUE x)
{
if (RB_INTEGER_TYPE_P(x)) {
@@ -419,8 +404,7 @@ 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, sizeof(struct RRational));
RATIONAL_SET_NUM((VALUE)obj, num);
RATIONAL_SET_DEN((VALUE)obj, den);
@@ -609,9 +593,13 @@ nurat_denominator(VALUE self)
/*
* call-seq:
- * -rat -> rational
+ * -self -> rational
+ *
+ * Returns +self+, negated:
+ *
+ * -(1/3r) # => (-1/3)
+ * -(-1/3r) # => (1/3)
*
- * Negates +rat+.
*/
VALUE
rb_rational_uminus(VALUE self)
@@ -715,16 +703,27 @@ f_addsub(VALUE self, VALUE anum, VALUE aden, VALUE bnum, VALUE bden, int k)
static double nurat_to_double(VALUE self);
/*
- * call-seq:
- * rat + numeric -> numeric
+ * call-seq:
+ * self + other -> numeric
*
- * Performs addition.
+ * Returns the sum of +self+ and +other+:
+ *
+ * Rational(2, 3) + 0 # => (2/3)
+ * Rational(2, 3) + 1 # => (5/3)
+ * Rational(2, 3) + -1 # => (-1/3)
+ *
+ * Rational(2, 3) + Complex(1, 0) # => ((5/3)+0i)
+ *
+ * Rational(2, 3) + Rational(1, 1) # => (5/3)
+ * Rational(2, 3) + Rational(3, 2) # => (13/6)
+ * Rational(2, 3) + Rational(3.0, 2.0) # => (13/6)
+ * Rational(2, 3) + Rational(3.1, 2.1) # => (30399297484750849/14186338826217063)
+ *
+ * For a computation involving Floats, the result may be inexact (see Float#+):
+ *
+ * Rational(2, 3) + 1.0 # => 1.6666666666666665
+ * Rational(2, 3) + Complex(1.0, 0.0) # => (1.6666666666666665+0.0i)
*
- * Rational(2, 3) + Rational(2, 3) #=> (4/3)
- * Rational(900) + Rational(1) #=> (901/1)
- * Rational(-2, 9) + Rational(-9, 2) #=> (-85/18)
- * Rational(9, 8) + 4 #=> (41/8)
- * Rational(20, 9) + 9.8 #=> 12.022222222222222
*/
VALUE
rb_rational_plus(VALUE self, VALUE other)
@@ -757,9 +756,9 @@ rb_rational_plus(VALUE self, VALUE other)
/*
* call-seq:
- * rat - numeric -> numeric
+ * self - other -> numeric
*
- * Performs subtraction.
+ * Returns the difference of +self+ and +other+:
*
* Rational(2, 3) - Rational(2, 3) #=> (0/1)
* Rational(900) - Rational(1) #=> (899/1)
@@ -853,15 +852,17 @@ f_muldiv(VALUE self, VALUE anum, VALUE aden, VALUE bnum, VALUE bden, int k)
/*
* call-seq:
- * rat * numeric -> numeric
+ * self * other -> numeric
+ *
+ * Returns the numeric product of +self+ and +other+:
*
- * Performs multiplication.
+ * Rational(9, 8) * 4 #=> (9/2)
+ * Rational(20, 9) * 9.8 #=> 21.77777777777778
+ * Rational(9, 8) * Complex(1, 2) # => ((9/8)+(9/4)*i)
+ * Rational(2, 3) * Rational(2, 3) #=> (4/9)
+ * Rational(900) * Rational(1) #=> (900/1)
+ * Rational(-2, 9) * Rational(-9, 2) #=> (1/1)
*
- * Rational(2, 3) * Rational(2, 3) #=> (4/9)
- * Rational(900) * Rational(1) #=> (900/1)
- * Rational(-2, 9) * Rational(-9, 2) #=> (1/1)
- * Rational(9, 8) * 4 #=> (9/2)
- * Rational(20, 9) * 9.8 #=> 21.77777777777778
*/
VALUE
rb_rational_mul(VALUE self, VALUE other)
@@ -894,10 +895,9 @@ rb_rational_mul(VALUE self, VALUE other)
/*
* call-seq:
- * rat / numeric -> numeric
- * rat.quo(numeric) -> numeric
+ * self / other -> numeric
*
- * Performs division.
+ * Returns the quotient of +self+ and +other+:
*
* Rational(2, 3) / Rational(2, 3) #=> (1/1)
* Rational(900) / Rational(1) #=> (900/1)
@@ -953,8 +953,8 @@ rb_rational_div(VALUE self, VALUE other)
* Rational(2, 3).fdiv(0.5) #=> 1.3333333333333333
* Rational(2).fdiv(3) #=> 0.6666666666666666
*/
-static VALUE
-nurat_fdiv(VALUE self, VALUE other)
+VALUE
+rb_rational_fdiv(VALUE self, VALUE other)
{
VALUE div;
if (f_zero_p(other))
@@ -971,9 +971,9 @@ nurat_fdiv(VALUE self, VALUE other)
/*
* call-seq:
- * rat ** numeric -> numeric
+ * self ** exponent -> numeric
*
- * Performs exponentiation.
+ * Returns +self+ raised to the power +exponent+:
*
* Rational(2) ** Rational(3) #=> (8/1)
* Rational(10) ** -2 #=> (1/100)
@@ -1061,20 +1061,30 @@ rb_rational_pow(VALUE self, VALUE other)
/*
* call-seq:
- * rational <=> numeric -> -1, 0, +1, or nil
+ * self <=> other -> -1, 0, 1, or nil
+ *
+ * Compares +self+ and +other+.
+ *
+ * Returns:
+ *
+ * - +-1+, if +self+ is less than +other+.
+ * - +0+, if the two values are the same.
+ * - +1+, if +self+ is greater than +other+.
+ * - +nil+, if the two values are incomparable.
*
- * Returns -1, 0, or +1 depending on whether +rational+ is
- * less than, equal to, or greater than +numeric+.
+ * Examples:
*
- * +nil+ is returned if the two values are incomparable.
+ * Rational(2, 3) <=> Rational(4, 3) # => -1
+ * Rational(2, 1) <=> Rational(2, 1) # => 0
+ * Rational(2, 1) <=> 2 # => 0
+ * Rational(2, 1) <=> 2.0 # => 0
+ * Rational(2, 1) <=> Complex(2, 0) # => 0
+ * Rational(4, 3) <=> Rational(2, 3) # => 1
+ * Rational(4, 3) <=> :foo # => nil
*
- * Rational(2, 3) <=> Rational(2, 3) #=> 0
- * Rational(5) <=> 5 #=> 0
- * Rational(2, 3) <=> Rational(1, 3) #=> 1
- * Rational(1, 3) <=> 1 #=> -1
- * Rational(1, 3) <=> 0.3 #=> 1
+ * \Class \Rational includes module Comparable,
+ * each of whose methods uses Rational#<=> for comparison.
*
- * Rational(1, 3) <=> "0.3" #=> nil
*/
VALUE
rb_rational_cmp(VALUE self, VALUE other)
@@ -1119,9 +1129,9 @@ rb_rational_cmp(VALUE self, VALUE other)
/*
* call-seq:
- * rat == object -> true or false
+ * self == other -> true or false
*
- * Returns +true+ if +rat+ equals +object+ numerically.
+ * Returns whether +self+ and +other+ are numerically equal:
*
* Rational(2, 3) == Rational(2, 3) #=> true
* Rational(5) == 5 #=> true
@@ -1364,10 +1374,12 @@ nurat_round_half_even(VALUE self)
return num;
}
+static VALUE f_round_n(VALUE self, VALUE n, VALUE (*func)(VALUE)) ;
+
static VALUE
f_round_common(int argc, VALUE *argv, VALUE self, VALUE (*func)(VALUE))
{
- VALUE n, b, s;
+ VALUE n;
if (rb_check_arity(argc, 0, 1) == 0)
return (*func)(self);
@@ -1377,6 +1389,14 @@ f_round_common(int argc, VALUE *argv, VALUE self, VALUE (*func)(VALUE))
if (!k_integer_p(n))
rb_raise(rb_eTypeError, "not an integer");
+ return f_round_n(self, n, func);
+}
+
+static VALUE
+f_round_n(VALUE self, VALUE n, VALUE (*func)(VALUE))
+{
+ VALUE b, s;
+
b = f_expt10(n);
s = rb_rational_mul(self, b);
@@ -1407,8 +1427,7 @@ rb_rational_floor(VALUE self, int ndigits)
return nurat_floor(self);
}
else {
- VALUE n = INT2NUM(ndigits);
- return f_round_common(1, &n, self, nurat_floor);
+ return f_round_n(self, INT2NUM(ndigits), nurat_floor);
}
}
@@ -1551,9 +1570,22 @@ nurat_round_n(int argc, VALUE *argv, VALUE self)
}
VALUE
-rb_flo_round_by_rational(int argc, VALUE *argv, VALUE num)
+rb_flo_round_by_rational(VALUE num, int ndigits, enum ruby_num_rounding_mode mode)
{
- return nurat_to_f(nurat_round_n(argc, argv, float_to_r(num)));
+ VALUE (*round_func)(VALUE) = ROUND_FUNC(mode, nurat_round);
+ return nurat_to_f(f_round_n(float_to_r(num), INT2NUM(ndigits), round_func));
+}
+
+VALUE
+rb_flo_ceil_by_rational(VALUE num, int ndigits)
+{
+ return nurat_to_f(f_round_n(float_to_r(num), INT2NUM(ndigits), nurat_ceil));
+}
+
+VALUE
+rb_flo_floor_by_rational(VALUE num, int ndigits)
+{
+ return nurat_to_f(f_round_n(float_to_r(num), INT2NUM(ndigits), nurat_floor));
}
static double
@@ -2294,6 +2326,12 @@ islettere(int c)
return (c == 'e' || c == 'E');
}
+inline static int
+isletterr(int c)
+{
+ return (c == 'r' || c == 'R');
+}
+
static VALUE
negate_num(VALUE num)
{
@@ -2343,7 +2381,13 @@ read_num(const char **s, const char *const end, VALUE *num, VALUE *nexp)
ok = 1;
}
- if (ok && *s + 1 < end && islettere(**s)) {
+ if (!ok || *s >= end) {
+ /* failed or finish */
+ }
+ else if (isletterr(**s)) {
+ (*s)++;
+ }
+ else if (*s + 1 < end && islettere(**s)) {
(*s)++;
expsign = read_sign(s, end);
exp = rb_int_parse_cstr(*s, end-*s, &e, NULL,
@@ -2467,31 +2511,32 @@ string_to_r_strict(VALUE self, int raise)
/*
* call-seq:
- * str.to_r -> rational
- *
- * Returns the result of interpreting leading characters in +str+
- * as a rational. Leading whitespace and extraneous characters
- * past the end of a valid number are ignored.
- * Digit sequences can be separated by an underscore.
- * If there is not a valid number at the start of +str+,
- * zero is returned. This method never raises an exception.
- *
- * ' 2 '.to_r #=> (2/1)
- * '300/2'.to_r #=> (150/1)
- * '-9.2'.to_r #=> (-46/5)
- * '-9.2e2'.to_r #=> (-920/1)
- * '1_234_567'.to_r #=> (1234567/1)
- * '21 June 09'.to_r #=> (21/1)
- * '21/06/09'.to_r #=> (7/2)
- * 'BWV 1079'.to_r #=> (0/1)
- *
- * NOTE: "0.3".to_r isn't the same as 0.3.to_r. The former is
- * equivalent to "3/10".to_r, but the latter isn't so.
+ * str.to_r -> rational
*
- * "0.3".to_r == 3/10r #=> true
- * 0.3.to_r == 3/10r #=> false
+ * Returns the result of interpreting leading characters in +self+ as a rational value:
+ *
+ * '123'.to_r # => (123/1) # Integer literal.
+ * '300/2'.to_r # => (150/1) # Rational literal.
+ * '-9.2'.to_r # => (-46/5) # Float literal.
+ * '-9.2e2'.to_r # => (-920/1) # Float literal.
+ *
+ * Ignores leading and trailing whitespace, and trailing non-numeric characters:
+ *
+ * ' 2 '.to_r # => (2/1)
+ * '21-Jun-09'.to_r # => (21/1)
+ *
+ * Returns \Rational zero if there are no leading numeric characters.
+ *
+ * 'BWV 1079'.to_r # => (0/1)
+ *
+ * NOTE: <tt>'0.3'.to_r</tt> is equivalent to <tt>3/10r</tt>,
+ * but is different from <tt>0.3.to_r</tt>:
+ *
+ * '0.3'.to_r # => (3/10)
+ * 3/10r # => (3/10)
+ * 0.3.to_r # => (5404319552844595/18014398509481984)
*
- * See also Kernel#Rational.
+ * Related: see {Converting to Non-String}[rdoc-ref:String@Converting+to+Non--5CString].
*/
static VALUE
string_to_r(VALUE self)
@@ -2535,7 +2580,7 @@ nurat_convert(VALUE klass, VALUE numv, VALUE denv, int raise)
if (NIL_P(a1) || NIL_P(a2)) {
if (!raise) return Qnil;
- rb_raise(rb_eTypeError, "can't convert nil into Rational");
+ rb_cant_convert(Qnil, "Rational");
}
if (RB_TYPE_P(a1, T_COMPLEX)) {
@@ -2746,7 +2791,7 @@ Init_Rational(void)
rb_define_method(rb_cRational, "*", rb_rational_mul, 1);
rb_define_method(rb_cRational, "/", rb_rational_div, 1);
rb_define_method(rb_cRational, "quo", rb_rational_div, 1);
- rb_define_method(rb_cRational, "fdiv", nurat_fdiv, 1);
+ rb_define_method(rb_cRational, "fdiv", rb_rational_fdiv, 1);
rb_define_method(rb_cRational, "**", nurat_expt, 1);
rb_define_method(rb_cRational, "<=>", rb_rational_cmp, 1);
diff --git a/re.c b/re.c
index 13d7f0ef9e..63e2db81ac 100644
--- a/re.c
+++ b/re.c
@@ -16,7 +16,9 @@
#include "encindex.h"
#include "hrtime.h"
#include "internal.h"
+#include "internal/bignum.h"
#include "internal/encoding.h"
+#include "internal/error.h"
#include "internal/hash.h"
#include "internal/imemo.h"
#include "internal/re.h"
@@ -35,9 +37,6 @@ VALUE rb_eRegexpError, rb_eRegexpTimeoutError;
typedef char onig_errmsg_buffer[ONIG_MAX_ERROR_MESSAGE_LEN];
#define errcpy(err, msg) strlcpy((err), (msg), ONIG_MAX_ERROR_MESSAGE_LEN)
-#define BEG(no) (regs->beg[(no)])
-#define END(no) (regs->end[(no)])
-
#if 'a' == 97 /* it's ascii */
static const char casetable[] = {
'\000', '\001', '\002', '\003', '\004', '\005', '\006', '\007',
@@ -105,7 +104,7 @@ rb_memcicmp(const void *x, const void *y, long len)
return 0;
}
-#ifdef HAVE_MEMMEM
+#if defined(HAVE_MEMMEM) && !defined(__APPLE__)
static inline long
rb_memsearch_ss(const unsigned char *xs, long m, const unsigned char *ys, long n)
{
@@ -963,19 +962,33 @@ make_regexp(const char *s, long len, rb_encoding *enc, int flags, onig_errmsg_bu
VALUE rb_cMatch;
static VALUE
-match_alloc(VALUE klass)
+match_alloc_n(VALUE klass, int num_regs)
{
- 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);
+ int capa = num_regs * 2;
+ size_t alloc_size = offsetof(struct RMatch, as) + sizeof(OnigPosition) * capa;
+ if (alloc_size < sizeof(struct RMatch)) {
+ alloc_size = sizeof(struct RMatch);
+ }
- match->str = Qfalse;
- match->regexp = Qfalse;
- memset(RMATCH_EXT(match), 0, sizeof(rb_matchext_t));
+ VALUE flags = T_MATCH;
+ if (!rb_gc_size_allocatable_p(alloc_size)) {
+ alloc_size = sizeof(struct RMatch);
+ flags |= RMATCH_ONIG;
+ capa = 0;
+ }
+ NEWOBJ_OF(match, struct RMatch, klass, flags, alloc_size);
+ memset(((char *)match) + sizeof(struct RBasic), 0, alloc_size - sizeof(struct RBasic));
+ match->capa = capa;
return (VALUE)match;
}
+static VALUE
+match_alloc(VALUE klass)
+{
+ return match_alloc_n(klass, 0);
+}
+
int
rb_reg_region_copy(struct re_registers *to, const struct re_registers *from)
{
@@ -987,6 +1000,54 @@ rb_reg_region_copy(struct re_registers *to, const struct re_registers *from)
return ONIGERR_MEMORY;
}
+static void
+match_to_onig(VALUE match, int num_regs, const OnigPosition *src_beg, const OnigPosition *src_end)
+{
+ struct RMatch *rm = RMATCH(match);
+ struct re_registers tmp = {0};
+ if (onig_region_resize(&tmp, num_regs)) {
+ rb_memerror();
+ }
+ memcpy(tmp.beg, src_beg, num_regs * sizeof(OnigPosition));
+ memcpy(tmp.end, src_end, num_regs * sizeof(OnigPosition));
+ rm->as.onig = tmp;
+ FL_SET_RAW(match, RMATCH_ONIG);
+}
+
+void
+rb_match_ensure_onig(VALUE match)
+{
+ if (FL_TEST_RAW(match, RMATCH_ONIG)) return;
+ struct RMatch *rm = RMATCH(match);
+ int n = rm->num_regs;
+ match_to_onig(match, n, &rm->as.embed[0], &rm->as.embed[n]);
+}
+
+/* Replace `match`'s registers with a copy of (num_regs, beg, end). If the
+ * data does not fit in the embed form, the match is evicted to onig form.
+ * Raises on OOM. */
+static void
+match_set_regs(VALUE match, int num_regs, const OnigPosition *beg, const OnigPosition *end)
+{
+ struct RMatch *rm = RMATCH(match);
+
+ if (FL_TEST_RAW(match, RMATCH_ONIG)) {
+ if (onig_region_resize(&rm->as.onig, num_regs)) {
+ rb_memerror();
+ }
+ memcpy(rm->as.onig.beg, beg, num_regs * sizeof(OnigPosition));
+ memcpy(rm->as.onig.end, end, num_regs * sizeof(OnigPosition));
+ }
+ else if (num_regs * 2 <= rm->capa) {
+ memcpy(&rm->as.embed[0], beg, num_regs * sizeof(OnigPosition));
+ memcpy(&rm->as.embed[num_regs], end, num_regs * sizeof(OnigPosition));
+ }
+ else {
+ match_to_onig(match, num_regs, beg, end);
+ }
+ rm->num_regs = num_regs;
+}
+
typedef struct {
long byte_pos;
long char_pos;
@@ -1006,41 +1067,41 @@ pair_byte_cmp(const void *pair1, const void *pair2)
static void
update_char_offset(VALUE match)
{
- rb_matchext_t *rm = RMATCH_EXT(match);
- struct re_registers *regs;
+ struct RMatch *rm = RMATCH(match);
int i, num_regs, num_pos;
long c;
char *s, *p, *q;
rb_encoding *enc;
pair_t *pairs;
+ VALUE pairs_obj = Qnil;
if (rm->char_offset_num_allocated)
return;
- regs = &rm->regs;
- num_regs = rm->regs.num_regs;
+ num_regs = RMATCH_NREGS(match);
if (rm->char_offset_num_allocated < num_regs) {
- REALLOC_N(rm->char_offset, struct rmatch_offset, num_regs);
+ SIZED_REALLOC_N(rm->char_offset, struct rmatch_offset, num_regs, rm->char_offset_num_allocated);
rm->char_offset_num_allocated = num_regs;
+ FL_SET_RAW(match, RMATCH_OFFSETS_EXTERNAL);
}
enc = rb_enc_get(RMATCH(match)->str);
if (rb_enc_mbmaxlen(enc) == 1) {
for (i = 0; i < num_regs; i++) {
- rm->char_offset[i].beg = BEG(i);
- rm->char_offset[i].end = END(i);
+ rm->char_offset[i].beg = RMATCH_BEG(match, i);
+ rm->char_offset[i].end = RMATCH_END(match, i);
}
return;
}
- pairs = ALLOCA_N(pair_t, num_regs*2);
+ pairs = RB_ALLOCV_N(pair_t, pairs_obj, num_regs * 2);
num_pos = 0;
for (i = 0; i < num_regs; i++) {
- if (BEG(i) < 0)
+ if (RMATCH_BEG(match, i) < 0)
continue;
- pairs[num_pos++].byte_pos = BEG(i);
- pairs[num_pos++].byte_pos = END(i);
+ pairs[num_pos++].byte_pos = RMATCH_BEG(match, i);
+ pairs[num_pos++].byte_pos = RMATCH_END(match, i);
}
qsort(pairs, num_pos, sizeof(pair_t), pair_byte_cmp);
@@ -1055,20 +1116,22 @@ update_char_offset(VALUE match)
for (i = 0; i < num_regs; i++) {
pair_t key, *found;
- if (BEG(i) < 0) {
+ if (RMATCH_BEG(match, i) < 0) {
rm->char_offset[i].beg = -1;
rm->char_offset[i].end = -1;
continue;
}
- key.byte_pos = BEG(i);
+ key.byte_pos = RMATCH_BEG(match, i);
found = bsearch(&key, pairs, num_pos, sizeof(pair_t), pair_byte_cmp);
rm->char_offset[i].beg = found->char_pos;
- key.byte_pos = END(i);
+ key.byte_pos = RMATCH_END(match, i);
found = bsearch(&key, pairs, num_pos, sizeof(pair_t), pair_byte_cmp);
rm->char_offset[i].end = found->char_pos;
}
+
+ RB_ALLOCV_END(pairs_obj);
}
static VALUE
@@ -1084,24 +1147,23 @@ match_check(VALUE match)
static VALUE
match_init_copy(VALUE obj, VALUE orig)
{
- rb_matchext_t *rm;
+ struct RMatch *rm = RMATCH(obj);
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);
+ RB_OBJ_WRITE(obj, &rm->str, RMATCH(orig)->str);
+ RB_OBJ_WRITE(obj, &rm->regexp, RMATCH(orig)->regexp);
- rm = RMATCH_EXT(obj);
- if (rb_reg_region_copy(&rm->regs, RMATCH_REGS(orig)))
- rb_memerror();
+ match_set_regs(obj, RMATCH_NREGS(orig), RMATCH_BEG_PTR(orig), RMATCH_END_PTR(orig));
- if (RMATCH_EXT(orig)->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;
+ if (RMATCH(orig)->char_offset_num_allocated) {
+ if (rm->char_offset_num_allocated < rm->num_regs) {
+ SIZED_REALLOC_N(rm->char_offset, struct rmatch_offset, rm->num_regs, rm->char_offset_num_allocated);
+ rm->char_offset_num_allocated = rm->num_regs;
+ FL_SET_RAW(obj, RMATCH_OFFSETS_EXTERNAL);
}
- MEMCPY(rm->char_offset, RMATCH_EXT(orig)->char_offset,
- struct rmatch_offset, rm->regs.num_regs);
+ MEMCPY(rm->char_offset, RMATCH(orig)->char_offset,
+ struct rmatch_offset, rm->num_regs);
RB_GC_GUARD(orig);
}
@@ -1180,10 +1242,10 @@ static VALUE
match_size(VALUE match)
{
match_check(match);
- return INT2FIX(RMATCH_REGS(match)->num_regs);
+ return INT2FIX(RMATCH_NREGS(match));
}
-static int name_to_backref_number(struct re_registers *, VALUE, const char*, const char*);
+static int match_name_to_backref_number(VALUE match, VALUE name);
NORETURN(static void name_to_backref_error(VALUE name));
static void
@@ -1194,21 +1256,17 @@ name_to_backref_error(VALUE name)
}
static void
-backref_number_check(struct re_registers *regs, int i)
+backref_number_check(VALUE match, int i)
{
- if (i < 0 || regs->num_regs <= i)
+ if (i < 0 || RMATCH_NREGS(match) <= i)
rb_raise(rb_eIndexError, "index %d out of matches", i);
}
static int
match_backref_number(VALUE match, VALUE backref)
{
- const char *name;
int num;
- struct re_registers *regs = RMATCH_REGS(match);
- VALUE regexp = RMATCH(match)->regexp;
-
match_check(match);
if (SYMBOL_P(backref)) {
backref = rb_sym2str(backref);
@@ -1216,9 +1274,8 @@ match_backref_number(VALUE match, VALUE backref)
else if (!RB_TYPE_P(backref, T_STRING)) {
return NUM2INT(backref);
}
- name = StringValueCStr(backref);
- num = name_to_backref_number(regs, regexp, name, name + RSTRING_LEN(backref));
+ num = match_name_to_backref_number(match, backref);
if (num < 1) {
name_to_backref_error(backref);
@@ -1246,17 +1303,16 @@ static VALUE
match_offset(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);
+ backref_number_check(match, i);
- if (BEG(i) < 0)
+ if (RMATCH_BEG(match, i) < 0)
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)->char_offset[i].beg),
+ LONG2NUM(RMATCH(match)->char_offset[i].end));
}
/*
@@ -1281,14 +1337,13 @@ static VALUE
match_byteoffset(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);
+ backref_number_check(match, i);
- if (BEG(i) < 0)
+ if (RMATCH_BEG(match, i) < 0)
return rb_assoc_new(Qnil, Qnil);
- return rb_assoc_new(LONG2NUM(BEG(i)), LONG2NUM(END(i)));
+ return rb_assoc_new(LONG2NUM(RMATCH_BEG(match, i)), LONG2NUM(RMATCH_END(match, i)));
}
@@ -1305,14 +1360,13 @@ 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);
+ backref_number_check(match, i);
- if (BEG(i) < 0)
+ if (RMATCH_BEG(match, i) < 0)
return Qnil;
- return LONG2NUM(BEG(i));
+ return LONG2NUM(RMATCH_BEG(match, i));
}
@@ -1329,14 +1383,13 @@ 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);
+ backref_number_check(match, i);
- if (BEG(i) < 0)
+ if (RMATCH_BEG(match, i) < 0)
return Qnil;
- return LONG2NUM(END(i));
+ return LONG2NUM(RMATCH_END(match, i));
}
@@ -1353,16 +1406,15 @@ static VALUE
match_begin(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);
+ backref_number_check(match, i);
- if (BEG(i) < 0)
+ if (RMATCH_BEG(match, i) < 0)
return Qnil;
update_char_offset(match);
- return LONG2NUM(RMATCH_EXT(match)->char_offset[i].beg);
+ return LONG2NUM(RMATCH(match)->char_offset[i].beg);
}
@@ -1379,16 +1431,15 @@ static VALUE
match_end(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);
+ backref_number_check(match, i);
- if (BEG(i) < 0)
+ if (RMATCH_BEG(match, i) < 0)
return Qnil;
update_char_offset(match);
- return LONG2NUM(RMATCH_EXT(match)->char_offset[i].end);
+ return LONG2NUM(RMATCH(match)->char_offset[i].end);
}
/*
@@ -1421,11 +1472,10 @@ static VALUE
match_nth(VALUE match, VALUE n)
{
int i = match_backref_number(match, n);
- struct re_registers *regs = RMATCH_REGS(match);
- backref_number_check(regs, i);
+ backref_number_check(match, i);
- long start = BEG(i), end = END(i);
+ long start = RMATCH_BEG(match, i), end = RMATCH_END(match, i);
if (start < 0)
return Qnil;
@@ -1465,17 +1515,16 @@ static VALUE
match_nth_length(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);
+ backref_number_check(match, i);
- if (BEG(i) < 0)
+ if (RMATCH_BEG(match, i) < 0)
return Qnil;
update_char_offset(match);
const struct rmatch_offset *const ofs =
- &RMATCH_EXT(match)->char_offset[i];
+ &RMATCH(match)->char_offset[i];
return LONG2NUM(ofs->end - ofs->beg);
}
@@ -1496,34 +1545,36 @@ rb_match_unbusy(VALUE match)
int
rb_match_count(VALUE match)
{
- struct re_registers *regs;
if (NIL_P(match)) return -1;
- regs = RMATCH_REGS(match);
- if (!regs) return -1;
- return regs->num_regs;
+ return RMATCH_NREGS(match);
+}
+
+static VALUE
+match_alloc_or_reuse(VALUE existing, int num_regs)
+{
+ if (!NIL_P(existing) &&
+ !FL_TEST(existing, MATCH_BUSY) &&
+ RMATCH(existing)->capa >= num_regs * 2) {
+ return existing;
+ }
+ return match_alloc_n(rb_cMatch, num_regs);
}
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);
- RB_OBJ_WRITE(match, &RMATCH(match)->str, string);
- RB_OBJ_WRITE(match, &RMATCH(match)->regexp, Qnil);
- int err = onig_region_resize(&rmatch->regs, 1);
- if (err) rb_memerror();
- rmatch->regs.beg[0] = pos;
- rmatch->regs.end[0] = pos + len;
+ RB_OBJ_WRITE(match, &match->str, string);
+ RB_OBJ_WRITE(match, &match->regexp, Qnil);
+ OnigPosition beg = pos, end = pos + len;
+ match_set_regs(m, 1, &beg, &end);
}
VALUE
rb_backref_set_string(VALUE string, long pos, long len)
{
- VALUE match = rb_backref_get();
- if (NIL_P(match) || FL_TEST(match, MATCH_BUSY)) {
- match = match_alloc(rb_cMatch);
- }
+ VALUE match = match_alloc_or_reuse(rb_backref_get(), 1);
match_set_string(match, string, pos, len);
rb_backref_set(match);
return match;
@@ -1579,21 +1630,11 @@ reg_enc_error(VALUE re, VALUE str)
rb_enc_inspect_name(rb_enc_get(str)));
}
-static inline int
-str_coderange(VALUE str)
-{
- int cr = ENC_CODERANGE(str);
- if (cr == ENC_CODERANGE_UNKNOWN) {
- cr = rb_enc_str_coderange(str);
- }
- return cr;
-}
-
static rb_encoding*
rb_reg_prepare_enc(VALUE re, VALUE str, int warn)
{
rb_encoding *enc = 0;
- int cr = str_coderange(str);
+ int cr = rb_enc_str_coderange(str);
if (cr == ENC_CODERANGE_BROKEN) {
rb_raise(rb_eArgError,
@@ -1714,8 +1755,6 @@ rb_reg_onig_match(VALUE re, VALUE str,
}
if (result < 0) {
- onig_region_free(regs, 0);
-
switch (result) {
case ONIG_MISMATCH:
break;
@@ -1800,37 +1839,35 @@ rb_reg_search_set_match(VALUE re, VALUE str, long pos, int reverse, int set_back
.pos = pos,
.range = reverse ? 0 : len,
};
- struct re_registers regs = {0};
+
+ rb_reg_check(re);
+
+ /* Stack-backed regs sized to max(num_mem+1, ONIG_NREGION) so
+ * onig_region_resize_clear takes its no-op branch. */
+ int n = RREGEXP_PTR(re)->num_mem + 1;
+ int cap = n < ONIG_NREGION ? ONIG_NREGION : n;
+ VALUE regs_buf;
+ OnigPosition *buf = ALLOCV_N(OnigPosition, regs_buf, (size_t)cap * 2);
+ struct re_registers regs = {
+ .allocated = cap,
+ .num_regs = 0,
+ .beg = buf,
+ .end = buf + cap,
+ };
OnigPosition result = rb_reg_onig_match(re, str, reg_onig_search, &args, &regs);
if (result == ONIG_MISMATCH) {
+ ALLOCV_END(regs_buf);
rb_backref_set(Qnil);
return ONIG_MISMATCH;
}
- VALUE match = Qnil;
- if (set_match) {
- match = *set_match;
- }
-
- if (NIL_P(match)) {
- match = rb_backref_get();
- }
+ VALUE existing = (set_match && !NIL_P(*set_match)) ? *set_match : rb_backref_get();
+ VALUE match = match_alloc_or_reuse(existing, regs.num_regs);
- if (!NIL_P(match) && FL_TEST(match, MATCH_BUSY)) {
- match = Qnil;
- }
-
- if (NIL_P(match)) {
- match = match_alloc(rb_cMatch);
- }
- else {
- onig_region_free(&RMATCH_EXT(match)->regs, false);
- }
-
- rb_matchext_t *rm = RMATCH_EXT(match);
- rm->regs = regs;
+ match_set_regs(match, regs.num_regs, regs.beg, regs.end);
+ ALLOCV_END(regs_buf);
if (set_backref_str) {
RB_OBJ_WRITE(match, &RMATCH(match)->str, rb_str_new4(str));
@@ -1882,18 +1919,29 @@ reg_onig_match(regex_t *reg, VALUE str, struct re_registers *regs, void *_)
bool
rb_reg_start_with_p(VALUE re, VALUE str)
{
- VALUE match = rb_backref_get();
- if (NIL_P(match) || FL_TEST(match, MATCH_BUSY)) {
- match = match_alloc(rb_cMatch);
- }
+ rb_reg_check(re);
- struct re_registers *regs = RMATCH_REGS(match);
+ int n = RREGEXP_PTR(re)->num_mem + 1;
+ int cap = n < ONIG_NREGION ? ONIG_NREGION : n;
+ VALUE regs_buf;
+ OnigPosition *buf = ALLOCV_N(OnigPosition, regs_buf, (size_t)cap * 2);
+ struct re_registers regs = {
+ .allocated = cap,
+ .num_regs = 0,
+ .beg = buf,
+ .end = buf + cap,
+ };
- if (rb_reg_onig_match(re, str, reg_onig_match, NULL, regs) == ONIG_MISMATCH) {
+ if (rb_reg_onig_match(re, str, reg_onig_match, NULL, &regs) == ONIG_MISMATCH) {
+ ALLOCV_END(regs_buf);
rb_backref_set(Qnil);
return false;
}
+ VALUE match = match_alloc_or_reuse(rb_backref_get(), regs.num_regs);
+ match_set_regs(match, regs.num_regs, regs.beg, regs.end);
+ ALLOCV_END(regs_buf);
+
RB_OBJ_WRITE(match, &RMATCH(match)->str, rb_str_new4(str));
RB_OBJ_WRITE(match, &RMATCH(match)->regexp, re);
rb_backref_set(match);
@@ -1904,18 +1952,17 @@ rb_reg_start_with_p(VALUE re, VALUE str)
VALUE
rb_reg_nth_defined(int nth, VALUE match)
{
- struct re_registers *regs;
if (NIL_P(match)) return Qnil;
match_check(match);
- regs = RMATCH_REGS(match);
- if (nth >= regs->num_regs) {
+ int num_regs = RMATCH_NREGS(match);
+ if (nth >= num_regs) {
return Qnil;
}
if (nth < 0) {
- nth += regs->num_regs;
+ nth += num_regs;
if (nth <= 0) return Qnil;
}
- return RBOOL(BEG(nth) != -1);
+ return RBOOL(RMATCH_BEG(match, nth) != -1);
}
VALUE
@@ -1923,21 +1970,20 @@ rb_reg_nth_match(int nth, VALUE match)
{
VALUE str;
long start, end, len;
- struct re_registers *regs;
if (NIL_P(match)) return Qnil;
match_check(match);
- regs = RMATCH_REGS(match);
- if (nth >= regs->num_regs) {
+ int num_regs = RMATCH_NREGS(match);
+ if (nth >= num_regs) {
return Qnil;
}
if (nth < 0) {
- nth += regs->num_regs;
+ nth += num_regs;
if (nth <= 0) return Qnil;
}
- start = BEG(nth);
+ start = RMATCH_BEG(match, nth);
if (start == -1) return Qnil;
- end = END(nth);
+ end = RMATCH_END(match, nth);
len = end - start;
str = rb_str_subseq(RMATCH(match)->str, start, len);
return str;
@@ -1971,13 +2017,11 @@ VALUE
rb_reg_match_pre(VALUE match)
{
VALUE str;
- struct re_registers *regs;
if (NIL_P(match)) return Qnil;
match_check(match);
- regs = RMATCH_REGS(match);
- if (BEG(0) == -1) return Qnil;
- str = rb_str_subseq(RMATCH(match)->str, 0, BEG(0));
+ if (RMATCH_BEG(match, 0) == -1) return Qnil;
+ str = rb_str_subseq(RMATCH(match)->str, 0, RMATCH_BEG(match, 0));
return str;
}
@@ -2005,14 +2049,12 @@ rb_reg_match_post(VALUE match)
{
VALUE str;
long pos;
- struct re_registers *regs;
if (NIL_P(match)) return Qnil;
match_check(match);
- regs = RMATCH_REGS(match);
- if (BEG(0) == -1) return Qnil;
+ if (RMATCH_BEG(match, 0) == -1) return Qnil;
str = RMATCH(match)->str;
- pos = END(0);
+ pos = RMATCH_END(match, 0);
str = rb_str_subseq(str, pos, RSTRING_LEN(str) - pos);
return str;
}
@@ -2021,14 +2063,12 @@ static int
match_last_index(VALUE match)
{
int i;
- struct re_registers *regs;
if (NIL_P(match)) return -1;
match_check(match);
- regs = RMATCH_REGS(match);
- if (BEG(0) == -1) return -1;
+ if (RMATCH_BEG(match, 0) == -1) return -1;
- for (i=regs->num_regs-1; BEG(i) == -1 && i > 0; i--)
+ for (i = RMATCH_NREGS(match) - 1; RMATCH_BEG(match, i) == -1 && i > 0; i--)
;
return i;
}
@@ -2038,8 +2078,8 @@ 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));
+ long start = RMATCH_BEG(match, i);
+ return rb_str_subseq(RMATCH(match)->str, start, RMATCH_END(match, i) - start);
}
VALUE
@@ -2077,22 +2117,22 @@ last_paren_match_getter(ID _x, VALUE *_y)
static VALUE
match_array(VALUE match, int start)
{
- struct re_registers *regs;
VALUE ary;
VALUE target;
int i;
match_check(match);
- regs = RMATCH_REGS(match);
- ary = rb_ary_new2(regs->num_regs);
+ int num_regs = RMATCH_NREGS(match);
+ ary = rb_ary_new2(num_regs);
target = RMATCH(match)->str;
- for (i=start; i<regs->num_regs; i++) {
- if (regs->beg[i] == -1) {
+ for (i = start; i < num_regs; i++) {
+ long beg = RMATCH_BEG(match, i);
+ if (beg == -1) {
rb_ary_push(ary, Qnil);
}
else {
- VALUE str = rb_str_subseq(target, regs->beg[i], regs->end[i]-regs->beg[i]);
+ VALUE str = rb_str_subseq(target, beg, RMATCH_END(match, i) - beg);
rb_ary_push(ary, str);
}
}
@@ -2143,7 +2183,7 @@ match_captures(VALUE match)
}
static int
-name_to_backref_number(struct re_registers *regs, VALUE regexp, const char* name, const char* name_end)
+name_to_backref_number(const struct re_registers *regs, VALUE regexp, const char* name, const char* name_end)
{
if (NIL_P(regexp)) return -1;
return onig_name_to_backref_number(RREGEXP_PTR(regexp),
@@ -2156,7 +2196,27 @@ name_to_backref_number(struct re_registers *regs, VALUE regexp, const char* name
name_to_backref_number((regs), (re), (name_ptr), (name_end)))
static int
-namev_to_backref_number(struct re_registers *regs, VALUE re, VALUE name)
+match_name_to_backref_number(VALUE match, VALUE name)
+{
+ VALUE regexp = RMATCH(match)->regexp;
+ if (NIL_P(regexp)) return -1;
+
+ int *nums;
+ int n = onig_name_to_group_numbers(RREGEXP_PTR(regexp),
+ (const unsigned char *)RSTRING_PTR(name),
+ (const unsigned char *)RSTRING_END(name), &nums);
+ if (n < 0) return n;
+ if (n == 0) return ONIGERR_PARSER_BUG;
+ if (n == 1) return nums[0];
+ for (int i = n - 1; i >= 0; i--) {
+ if (RMATCH_BEG(match, nums[i]) != ONIG_REGION_NOTPOS)
+ return nums[i];
+ }
+ return nums[n - 1];
+}
+
+static int
+namev_to_backref_number(VALUE match, VALUE name)
{
int num;
@@ -2166,8 +2226,14 @@ namev_to_backref_number(struct re_registers *regs, VALUE re, VALUE name)
else if (!RB_TYPE_P(name, T_STRING)) {
return -1;
}
- num = NAME_TO_NUMBER(regs, re, name,
- RSTRING_PTR(name), RSTRING_END(name));
+
+ VALUE re = RMATCH(match)->regexp;
+ if (NIL_P(re) || !rb_enc_compatible(RREGEXP_SRC(re), name)) {
+ num = 0;
+ }
+ else {
+ num = match_name_to_backref_number(match, name);
+ }
if (num < 1) {
name_to_backref_error(name);
}
@@ -2177,7 +2243,7 @@ namev_to_backref_number(struct re_registers *regs, VALUE re, VALUE name)
static VALUE
match_ary_subseq(VALUE match, long beg, long len, VALUE result)
{
- long olen = RMATCH_REGS(match)->num_regs;
+ long olen = RMATCH_NREGS(match);
long j, end = olen < beg+len ? olen : beg+len;
if (NIL_P(result)) result = rb_ary_new_capa(len);
if (len == 0) return result;
@@ -2195,7 +2261,7 @@ static VALUE
match_ary_aref(VALUE match, VALUE idx, VALUE result)
{
long beg, len;
- int num_regs = RMATCH_REGS(match)->num_regs;
+ int num_regs = RMATCH_NREGS(match);
/* check if idx is Range */
switch (rb_range_beg_len(idx, &beg, &len, (long)num_regs, !NIL_P(result))) {
@@ -2212,12 +2278,12 @@ match_ary_aref(VALUE match, VALUE idx, VALUE result)
/*
* call-seq:
- * matchdata[index] -> string or nil
- * matchdata[start, length] -> array
- * matchdata[range] -> array
- * matchdata[name] -> string or nil
+ * self[offset] -> string or nil
+ * self[offset, size] -> array
+ * self[range] -> array
+ * self[name] -> string or nil
*
- * When arguments +index+, +start and +length+, or +range+ are given,
+ * When arguments +offset+, +offset+ and +size+, or +range+ are given,
* returns match and captures in the style of Array#[]:
*
* m = /(.)(.)(\d+)(\d)/.match("THX1138.")
@@ -2261,7 +2327,7 @@ match_aref(int argc, VALUE *argv, VALUE match)
return rb_reg_nth_match(FIX2INT(idx), match);
}
else {
- int num = namev_to_backref_number(RMATCH_REGS(match), RMATCH(match)->regexp, idx);
+ int num = namev_to_backref_number(match, idx);
if (num >= 0) {
return rb_reg_nth_match(num, match);
}
@@ -2273,7 +2339,7 @@ match_aref(int argc, VALUE *argv, VALUE match)
else {
long beg = NUM2LONG(idx);
long len = NUM2LONG(length);
- long num_regs = RMATCH_REGS(match)->num_regs;
+ long num_regs = RMATCH_NREGS(match);
if (len < 0) {
return Qnil;
}
@@ -2331,7 +2397,7 @@ match_values_at(int argc, VALUE *argv, VALUE match)
rb_ary_push(result, rb_reg_nth_match(FIX2INT(argv[i]), match));
}
else {
- int num = namev_to_backref_number(RMATCH_REGS(match), RMATCH(match)->regexp, argv[i]);
+ int num = namev_to_backref_number(match, argv[i]);
if (num >= 0) {
rb_ary_push(result, rb_reg_nth_match(num, match));
}
@@ -2371,18 +2437,23 @@ match_to_s(VALUE match)
return str;
}
+struct named_captures_data {
+ VALUE hash;
+ VALUE match;
+ int symbolize;
+};
+
static int
match_named_captures_iter(const OnigUChar *name, const OnigUChar *name_end,
int back_num, int *back_refs, OnigRegex regex, void *arg)
{
- struct MEMO *memo = MEMO_CAST(arg);
- VALUE hash = memo->v1;
- VALUE match = memo->v2;
- long symbolize = memo->u3.state;
+ struct named_captures_data *data = arg;
+ VALUE hash = data->hash;
+ VALUE match = data->match;
VALUE key = rb_enc_str_new((const char *)name, name_end-name, regex->enc);
- if (symbolize > 0) {
+ if (data->symbolize) {
key = rb_str_intern(key);
}
@@ -2442,14 +2513,13 @@ static VALUE
match_named_captures(int argc, VALUE *argv, VALUE match)
{
VALUE hash;
- struct MEMO *memo;
match_check(match);
if (NIL_P(RMATCH(match)->regexp))
return rb_hash_new();
VALUE opt;
- VALUE symbolize_names = 0;
+ int symbolize_names = 0;
rb_scan_args(argc, argv, "0:", &opt);
@@ -2468,9 +2538,9 @@ match_named_captures(int argc, VALUE *argv, VALUE match)
}
hash = rb_hash_new();
- memo = MEMO_NEW(hash, match, symbolize_names);
+ struct named_captures_data data = { hash, match, symbolize_names };
- onig_foreach_name(RREGEXP(RMATCH(match)->regexp)->ptr, match_named_captures_iter, (void*)memo);
+ onig_foreach_name(RREGEXP(RMATCH(match)->regexp)->ptr, match_named_captures_iter, &data);
return hash;
}
@@ -2506,10 +2576,9 @@ match_deconstruct_keys(VALUE match, VALUE keys)
if (NIL_P(keys)) {
h = rb_hash_new_with_size(onig_number_of_names(RREGEXP_PTR(RMATCH(match)->regexp)));
- struct MEMO *memo;
- memo = MEMO_NEW(h, match, 1);
+ struct named_captures_data data = { h, match, 1 };
- onig_foreach_name(RREGEXP_PTR(RMATCH(match)->regexp), match_named_captures_iter, (void*)memo);
+ onig_foreach_name(RREGEXP_PTR(RMATCH(match)->regexp), match_named_captures_iter, &data);
return h;
}
@@ -2530,8 +2599,7 @@ match_deconstruct_keys(VALUE match, VALUE keys)
name = rb_sym2str(key);
- int num = NAME_TO_NUMBER(RMATCH_REGS(match), RMATCH(match)->regexp, RMATCH(match)->regexp,
- RSTRING_PTR(name), RSTRING_END(name));
+ int num = match_name_to_backref_number(match, name);
if (num >= 0) {
rb_hash_aset(h, key, rb_reg_nth_match(num, match));
@@ -2610,9 +2678,9 @@ match_inspect(VALUE match)
VALUE cname = rb_class_path(rb_obj_class(match));
VALUE str;
int i;
- struct re_registers *regs = RMATCH_REGS(match);
- int num_regs = regs->num_regs;
+ int num_regs = RMATCH_NREGS(match);
struct backref_name_tag *names;
+ VALUE names_obj = Qnil;
VALUE regexp = RMATCH(match)->regexp;
if (regexp == 0) {
@@ -2623,7 +2691,7 @@ match_inspect(VALUE match)
cname, rb_reg_nth_match(0, match));
}
- names = ALLOCA_N(struct backref_name_tag, num_regs);
+ names = RB_ALLOCV_N(struct backref_name_tag, names_obj, num_regs);
MEMZERO(names, struct backref_name_tag, num_regs);
onig_foreach_name(RREGEXP_PTR(regexp),
@@ -2651,6 +2719,7 @@ match_inspect(VALUE match)
}
rb_str_buf_cat2(str, ">");
+ RB_ALLOCV_END(names_obj);
return str;
}
@@ -3269,7 +3338,7 @@ rb_reg_preprocess_dregexp(VALUE ary, int options)
src_enc = rb_enc_get(str);
if (options & ARG_ENCODING_NONE &&
src_enc != ascii8bit) {
- if (str_coderange(str) != ENC_CODERANGE_7BIT)
+ if (rb_enc_str_coderange(str) != ENC_CODERANGE_7BIT)
rb_raise(rb_eRegexpError, "/.../n has a non escaped non ASCII character in non ASCII-8BIT script");
else
src_enc = ascii8bit;
@@ -3361,6 +3430,9 @@ rb_reg_initialize(VALUE obj, const char *s, long len, rb_encoding *enc,
options & ARG_REG_OPTION_MASK, err,
sourcefile, sourceline);
if (!re->ptr) return -1;
+ if (RBASIC_CLASS(obj) == rb_cRegexp) {
+ OBJ_FREEZE(obj);
+ }
RB_GC_GUARD(unescaped);
return 0;
}
@@ -3369,10 +3441,13 @@ static void
reg_set_source(VALUE reg, VALUE str, rb_encoding *enc)
{
rb_encoding *regenc = rb_enc_get(reg);
+
if (regenc != enc) {
- str = rb_enc_associate(rb_str_dup(str), enc = regenc);
+ VALUE dup = rb_str_dup(str);
+ str = rb_enc_associate(dup, enc = regenc);
}
- RB_OBJ_WRITE(reg, &RREGEXP(reg)->src, rb_fstring(str));
+ str = rb_fstring(str);
+ RB_OBJ_WRITE(reg, &RREGEXP(reg)->src, str);
}
static int
@@ -3384,7 +3459,7 @@ rb_reg_initialize_str(VALUE obj, VALUE str, int options, onig_errmsg_buffer err,
if (options & ARG_ENCODING_NONE) {
rb_encoding *ascii8bit = rb_ascii8bit_encoding();
if (enc != ascii8bit) {
- if (str_coderange(str) != ENC_CODERANGE_7BIT) {
+ if (rb_enc_str_coderange(str) != ENC_CODERANGE_7BIT) {
errcpy(err, "/.../n has a non escaped non ASCII character in non ASCII-8BIT script");
return -1;
}
@@ -3397,10 +3472,10 @@ rb_reg_initialize_str(VALUE obj, VALUE str, int options, onig_errmsg_buffer err,
return ret;
}
-static VALUE
+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, sizeof(struct RRegexp));
re->ptr = 0;
RB_OBJ_WRITE(re, &re->src, 0);
@@ -3448,11 +3523,12 @@ rb_reg_init_str_enc(VALUE re, VALUE s, rb_encoding *enc, int options)
}
VALUE
-rb_reg_new_ary(VALUE ary, int opt)
+rb_reg_new_from_values(long cnt, const VALUE *elements, int opt)
{
- VALUE re = rb_reg_new_str(rb_reg_preprocess_dregexp(ary, opt), opt);
- rb_obj_freeze(re);
- return re;
+ const VALUE ary = rb_ary_tmp_new_from_values(0, cnt, elements);
+ VALUE val = rb_reg_new_str(rb_reg_preprocess_dregexp(ary, opt), opt);
+ rb_ary_clear(ary);
+ return val;
}
VALUE
@@ -3486,7 +3562,6 @@ rb_reg_compile(VALUE str, int options, const char *sourcefile, int sourceline)
rb_set_errinfo(rb_reg_error_desc(str, options, err));
return Qnil;
}
- rb_obj_freeze(re);
return re;
}
@@ -3540,10 +3615,10 @@ reg_hash(VALUE re)
/*
* call-seq:
- * regexp == object -> true or false
+ * self == other -> true or false
*
- * Returns +true+ if +object+ is another \Regexp whose pattern,
- * flags, and encoding are the same as +self+, +false+ otherwise:
+ * Returns whether +other+ is another \Regexp whose pattern,
+ * flags, and encoding are the same as +self+:
*
* /foo/ == Regexp.new('foo') # => true
* /foo/ == /foo/i # => false
@@ -3579,47 +3654,113 @@ rb_reg_equal(VALUE re1, VALUE re2)
static VALUE
match_hash(VALUE match)
{
- const struct re_registers *regs;
st_index_t hashval;
match_check(match);
hashval = rb_hash_start(rb_str_hash(RMATCH(match)->str));
hashval = rb_hash_uint(hashval, reg_hash(match_regexp(match)));
- regs = RMATCH_REGS(match);
- hashval = rb_hash_uint(hashval, regs->num_regs);
- hashval = rb_hash_uint(hashval, rb_memhash(regs->beg, regs->num_regs * sizeof(*regs->beg)));
- hashval = rb_hash_uint(hashval, rb_memhash(regs->end, regs->num_regs * sizeof(*regs->end)));
+ int num_regs = RMATCH_NREGS(match);
+ hashval = rb_hash_uint(hashval, num_regs);
+ hashval = rb_hash_uint(hashval, rb_memhash(RMATCH_BEG_PTR(match), num_regs * sizeof(OnigPosition)));
+ hashval = rb_hash_uint(hashval, rb_memhash(RMATCH_END_PTR(match), num_regs * sizeof(OnigPosition)));
hashval = rb_hash_end(hashval);
return ST2FIX(hashval);
}
/*
* call-seq:
- * matchdata == object -> true or false
+ * self == other -> true or false
*
- * Returns +true+ if +object+ is another \MatchData object
+ * Returns whether +other+ is another \MatchData object
* whose target string, regexp, match, and captures
- * are the same as +self+, +false+ otherwise.
+ * are the same as +self+.
*/
static VALUE
match_equal(VALUE match1, VALUE match2)
{
- const struct re_registers *regs1, *regs2;
-
if (match1 == match2) return Qtrue;
if (!RB_TYPE_P(match2, T_MATCH)) return Qfalse;
if (!RMATCH(match1)->regexp || !RMATCH(match2)->regexp) return Qfalse;
if (!rb_str_equal(RMATCH(match1)->str, RMATCH(match2)->str)) return Qfalse;
if (!rb_reg_equal(match_regexp(match1), match_regexp(match2))) return Qfalse;
- regs1 = RMATCH_REGS(match1);
- regs2 = RMATCH_REGS(match2);
- if (regs1->num_regs != regs2->num_regs) return Qfalse;
- if (memcmp(regs1->beg, regs2->beg, regs1->num_regs * sizeof(*regs1->beg))) return Qfalse;
- if (memcmp(regs1->end, regs2->end, regs1->num_regs * sizeof(*regs1->end))) return Qfalse;
+ int num_regs = RMATCH_NREGS(match1);
+ if (num_regs != RMATCH_NREGS(match2)) return Qfalse;
+ if (memcmp(RMATCH_BEG_PTR(match1), RMATCH_BEG_PTR(match2), num_regs * sizeof(OnigPosition))) return Qfalse;
+ if (memcmp(RMATCH_END_PTR(match1), RMATCH_END_PTR(match2), num_regs * sizeof(OnigPosition))) return Qfalse;
return Qtrue;
}
+/*
+ * call-seq:
+ * integer_at(index, base = 10) -> integer or nil
+ * integer_at(name, base = 10) -> integer or nil
+ *
+ * Converts the matched substring to integer and return the result.
+ * +$~.integer_at(N)+ is equivalent to +$N&.to_i+.
+ *
+ * m = /(\d+{4})(\d+{2})(\d+{2})/.match("20260308")
+ * # => #<MatchData "20260308" 1:"2026" 2:"03" 3:"08">
+ * m.integer_at(0) # => 20260308
+ * m.integer_at(1) # => 2026
+ * m.integer_at(2) # => 3
+ * m.integer_at(3) # => 8
+ *
+ * m = /(?<y>\d+{4})(?<m>\d+{2})(?<d>\d+{2})/.match("20260308")
+ * m.integer_at("y") # => 2026
+ * m.integer_at("m") # => 3
+ * m.integer_at("d") # => 8
+ *
+ * If the substring does not match, returns +nil+.
+ *
+ * re = /(\d+)?/
+ * re.match("123").integer_at(1) #=> 123
+ * re.match("abc").integer_at(1) #=> nil
+ *
+ * The string is converted in decimal by default.
+ *
+ * /\d+/.match("011").integer_at(0) #=> 10
+ * /\d+/.match("011").integer_at(0, 12) #=> 13
+ * /\d+/.match("011").integer_at(0, 0) #=> 9
+ *
+ * See also MatchData#[], String#to_i.
+ */
+static VALUE
+match_integer_at(int argc, VALUE *argv, VALUE match)
+{
+ match_check(match);
+
+ int base = 10;
+ VALUE idx;
+ int nth;
+
+ argc = rb_check_arity(argc, 1, 2);
+ if (FIXNUM_P(idx = argv[0])) {
+ nth = NUM2INT(idx);
+ }
+ else if ((nth = namev_to_backref_number(match, idx)) < 0) {
+ name_to_backref_error(idx);
+ }
+
+ if (argc > 1 && (base = NUM2INT(argv[1])) < 0) {
+ rb_raise(rb_eArgError, "invalid radix %d", base);
+ }
+
+ if (nth >= RMATCH_NREGS(match)) return Qnil;
+ if (nth < 0 && (nth += RMATCH_NREGS(match)) <= 0) return Qnil;
+
+ long start = RMATCH_BEG(match, nth), end = RMATCH_END(match, nth);
+ if (start < 0) return Qnil;
+ RUBY_ASSERT(start <= end, "%ld > %ld", start, end);
+
+ VALUE str = RMATCH(match)->str;
+ RUBY_ASSERT(end <= RSTRING_LEN(str), "%ld > %ld", end, RSTRING_LEN(str));
+
+ char *endp;
+ return rb_int_parse_cstr(RSTRING_PTR(str) + start, end - start, &endp, NULL,
+ base, RB_INT_PARSE_DEFAULT);
+}
+
static VALUE
reg_operand(VALUE s, int check)
{
@@ -3659,12 +3800,11 @@ reg_match_pos(VALUE re, VALUE *strp, long pos, VALUE* set_match)
/*
* call-seq:
- * regexp =~ string -> integer or nil
+ * self =~ other -> integer or nil
*
* 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]:
+ * for +self+ and +other+, or +nil+ if none;
+ * updates {Regexp-related global variables}[rdoc-ref:Regexp@Global+Variables].
*
* /at/ =~ 'input data' # => 7
* $~ # => #<MatchData "at">
@@ -3724,9 +3864,9 @@ rb_reg_match(VALUE re, VALUE str)
/*
* call-seq:
- * regexp === string -> true or false
+ * self === other -> true or false
*
- * Returns +true+ if +self+ finds a match in +string+:
+ * Returns whether +self+ finds a match in +other+:
*
* /^[a-z]*$/ === 'HELLO' # => false
* /^[A-Z]*$/ === 'HELLO' # => true
@@ -3932,7 +4072,7 @@ static void
set_timeout(rb_hrtime_t *hrt, VALUE timeout)
{
double timeout_d = NIL_P(timeout) ? 0.0 : NUM2DBL(timeout);
- if (!NIL_P(timeout) && timeout_d <= 0) {
+ if (!NIL_P(timeout) && !(timeout_d > 0)) {
rb_raise(rb_eArgError, "invalid timeout: %"PRIsVALUE, timeout);
}
double2hrtime(hrt, timeout_d);
@@ -3954,6 +4094,9 @@ reg_copy(VALUE copy, VALUE orig)
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));
+ if (RBASIC_CLASS(copy) == rb_cRegexp) {
+ OBJ_FREEZE(copy);
+ }
return copy;
}
@@ -3967,7 +4110,6 @@ struct reg_init_args {
static VALUE reg_extract_args(int argc, VALUE *argv, struct reg_init_args *args);
static VALUE reg_init_args(VALUE self, VALUE str, rb_encoding *enc, int flags);
-void rb_warn_deprecated_to_remove(const char *removal, const char *fmt, const char *suggest, ...);
/*
* call-seq:
@@ -4037,6 +4179,9 @@ rb_reg_initialize_m(int argc, VALUE *argv, VALUE self)
}
set_timeout(&RREGEXP_PTR(self)->timelimit, args.timeout);
+ if (RBASIC_CLASS(self) == rb_cRegexp) {
+ OBJ_FREEZE(self);
+ }
return self;
}
@@ -4460,8 +4605,8 @@ rb_reg_init_copy(VALUE copy, VALUE re)
return reg_copy(copy, re);
}
-VALUE
-rb_reg_regsub(VALUE str, VALUE src, struct re_registers *regs, VALUE regexp)
+static VALUE
+do_regsub(VALUE str, VALUE src, VALUE regexp, int num_regs, const OnigPosition *beg, const OnigPosition *end)
{
VALUE val = 0;
char *p, *s, *e;
@@ -4528,7 +4673,13 @@ rb_reg_regsub(VALUE str, VALUE src, struct re_registers *regs, VALUE regexp)
if (name_end < e) {
VALUE n = rb_str_subseq(str, (long)(name - RSTRING_PTR(str)),
(long)(name_end - name));
- if ((no = NAME_TO_NUMBER(regs, regexp, n, name, name_end)) < 1) {
+ struct re_registers tmp = {
+ .allocated = num_regs,
+ .num_regs = num_regs,
+ .beg = (OnigPosition *)beg,
+ .end = (OnigPosition *)end,
+ };
+ if ((no = NAME_TO_NUMBER(&tmp, regexp, n, name, name_end)) < 1) {
name_to_backref_error(n);
}
p = s = name_end + clen;
@@ -4548,16 +4699,16 @@ rb_reg_regsub(VALUE str, VALUE src, struct re_registers *regs, VALUE regexp)
break;
case '`':
- rb_enc_str_buf_cat(val, RSTRING_PTR(src), BEG(0), src_enc);
+ rb_enc_str_buf_cat(val, RSTRING_PTR(src), beg[0], src_enc);
continue;
case '\'':
- rb_enc_str_buf_cat(val, RSTRING_PTR(src)+END(0), RSTRING_LEN(src)-END(0), src_enc);
+ rb_enc_str_buf_cat(val, RSTRING_PTR(src)+end[0], RSTRING_LEN(src)-end[0], src_enc);
continue;
case '+':
- no = regs->num_regs-1;
- while (BEG(no) == -1 && no > 0) no--;
+ no = num_regs-1;
+ while (beg[no] == -1 && no > 0) no--;
if (no == 0) continue;
break;
@@ -4571,9 +4722,9 @@ rb_reg_regsub(VALUE str, VALUE src, struct re_registers *regs, VALUE regexp)
}
if (no >= 0) {
- if (no >= regs->num_regs) continue;
- if (BEG(no) == -1) continue;
- rb_enc_str_buf_cat(val, RSTRING_PTR(src)+BEG(no), END(no)-BEG(no), src_enc);
+ if (no >= num_regs) continue;
+ if (beg[no] == -1) continue;
+ rb_enc_str_buf_cat(val, RSTRING_PTR(src)+beg[no], end[no]-beg[no], src_enc);
}
}
@@ -4583,6 +4734,20 @@ rb_reg_regsub(VALUE str, VALUE src, struct re_registers *regs, VALUE regexp)
}
return val;
+#undef ASCGET
+}
+
+VALUE
+rb_reg_regsub(VALUE str, VALUE src, struct re_registers *regs, VALUE regexp)
+{
+ return do_regsub(str, src, regexp, regs->num_regs, regs->beg, regs->end);
+}
+
+VALUE
+rb_reg_regsub_match(VALUE str, VALUE src, VALUE match)
+{
+ return do_regsub(str, src, RMATCH(match)->regexp,
+ RMATCH_NREGS(match), RMATCH_BEG_PTR(match), RMATCH_END_PTR(match));
}
static VALUE
@@ -4816,6 +4981,11 @@ Init_Regexp(void)
rb_gvar_ractor_local("$`");
rb_gvar_ractor_local("$'");
rb_gvar_ractor_local("$+");
+ rb_gvar_box_dynamic("$~");
+ rb_gvar_box_ready("$&");
+ rb_gvar_box_ready("$`");
+ rb_gvar_box_ready("$'");
+ rb_gvar_box_ready("$+");
rb_define_virtual_variable("$=", ignorecase_getter, ignorecase_setter);
@@ -4901,4 +5071,5 @@ Init_Regexp(void)
rb_define_method(rb_cMatch, "hash", match_hash, 0);
rb_define_method(rb_cMatch, "eql?", match_equal, 1);
rb_define_method(rb_cMatch, "==", match_equal, 1);
+ rb_define_method(rb_cMatch, "integer_at", match_integer_at, -1);
}
diff --git a/regcomp.c b/regcomp.c
index e389e6f120..1895ac24ed 100644
--- a/regcomp.c
+++ b/regcomp.c
@@ -2,8 +2,8 @@
regcomp.c - Onigmo (Oniguruma-mod) (regular expression library)
**********************************************************************/
/*-
- * Copyright (c) 2002-2013 K.Kosako <sndgk393 AT ybb DOT ne DOT jp>
- * Copyright (c) 2011-2016 K.Takata <kentkt AT csc DOT jp>
+ * Copyright (c) 2002-2018 K.Kosako <sndgk393 AT ybb DOT ne DOT jp>
+ * Copyright (c) 2011-2019 K.Takata <kentkt AT csc DOT jp>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -394,6 +394,7 @@ compile_tree_empty_check(Node* node, regex_t* reg, int empty_info)
r = add_mem_num(reg, reg->num_null_check); /* NULL CHECK ID */
if (r) return r;
reg->num_null_check++;
+ if ((MemNumType)reg->num_null_check <= 0) return ONIGERR_TOO_MANY_NULL_CHECK;
}
r = compile_tree(node, reg);
@@ -703,6 +704,7 @@ compile_range_repeat_node(QtfrNode* qn, int target_len, int empty_info,
if (r) return r;
r = add_mem_num(reg, num_repeat); /* OP_REPEAT ID */
reg->num_repeat++;
+ if ((MemNumType)reg->num_repeat <= 0) return ONIGERR_TOO_MANY_RANGE_REPEAT;
if (r) return r;
r = add_rel_addr(reg, target_len + SIZE_OP_REPEAT_INC);
if (r) return r;
@@ -2803,14 +2805,11 @@ get_head_value_node(Node* node, int exact, regex_t* reg)
case NT_STR:
{
StrNode* sn = NSTR(node);
-
if (sn->end <= sn->s)
break;
- if (exact != 0 &&
- !NSTRING_IS_RAW(node) && IS_IGNORECASE(reg->options)) {
- }
- else {
+ if (exact == 0 ||
+ NSTRING_IS_RAW(node) || !IS_IGNORECASE(reg->options)) {
n = node;
}
}
@@ -3301,6 +3300,14 @@ setup_subexp_call(Node* node, ScanEnv* env)
}
#endif
+#define IN_ALT (1<<0)
+#define IN_NOT (1<<1)
+#define IN_REPEAT (1<<2)
+#define IN_VAR_REPEAT (1<<3)
+#define IN_CALL (1<<4)
+#define IN_RECCALL (1<<5)
+#define IN_LOOK_BEHIND (1<<6)
+
/* divide different length alternatives in look-behind.
(?<=A|B) ==> (?<=A)|(?<=B)
(?<!A|B) ==> (?<!A)(?<!B)
@@ -3597,24 +3604,29 @@ expand_case_fold_string_alt(int item_num, OnigCaseFoldCodeItem items[],
return ONIGERR_MEMORY;
}
-static int
-expand_case_fold_string(Node* node, regex_t* reg)
-{
#define THRESHOLD_CASE_FOLD_ALT_FOR_EXPANSION 8
+static int
+expand_case_fold_string(Node* node, regex_t* reg, int state)
+{
int r, n, len, alt_num;
int varlen = 0;
+ int is_in_look_behind;
UChar *start, *end, *p;
Node *top_root, *root, *snode, *prev_node;
OnigCaseFoldCodeItem items[ONIGENC_GET_CASE_FOLD_CODES_MAX_NUM];
- StrNode* sn = NSTR(node);
+ StrNode* sn;
if (NSTRING_IS_AMBIG(node)) return 0;
+ sn = NSTR(node);
+
start = sn->s;
end = sn->end;
if (start >= end) return 0;
+ is_in_look_behind = (state & IN_LOOK_BEHIND) != 0;
+
r = 0;
top_root = root = prev_node = snode = NULL_NODE;
alt_num = 1;
@@ -3630,7 +3642,7 @@ expand_case_fold_string(Node* node, regex_t* reg)
len = enclen(reg->enc, p, end);
varlen = is_case_fold_variable_len(n, items, len);
- if (n == 0 || varlen == 0) {
+ if (n == 0 || varlen == 0 || is_in_look_behind) {
if (IS_NULL(snode)) {
if (IS_NULL(root) && IS_NOT_NULL(prev_node)) {
onig_node_free(top_root);
@@ -3889,13 +3901,6 @@ setup_comb_exp_check(Node* node, int state, ScanEnv* env)
}
#endif
-#define IN_ALT (1<<0)
-#define IN_NOT (1<<1)
-#define IN_REPEAT (1<<2)
-#define IN_VAR_REPEAT (1<<3)
-#define IN_CALL (1<<4)
-#define IN_RECCALL (1<<5)
-
/* setup_tree does the following work.
1. check empty loop. (set qn->target_empty_info)
2. expand ignore-case in char class.
@@ -3937,7 +3942,7 @@ restart:
case NT_STR:
if (IS_IGNORECASE(reg->options) && !NSTRING_IS_RAW(node)) {
- r = expand_case_fold_string(node, reg);
+ r = expand_case_fold_string(node, reg, state);
}
break;
@@ -4180,7 +4185,7 @@ restart:
if (r < 0) return r;
if (r > 0) return ONIGERR_INVALID_LOOK_BEHIND_PATTERN;
if (NTYPE(node) != NT_ANCHOR) goto restart;
- r = setup_tree(an->target, reg, state, env);
+ r = setup_tree(an->target, reg, (state | IN_LOOK_BEHIND), env);
if (r != 0) return r;
r = setup_look_behind(node, reg, env);
}
@@ -4193,7 +4198,8 @@ restart:
if (r < 0) return r;
if (r > 0) return ONIGERR_INVALID_LOOK_BEHIND_PATTERN;
if (NTYPE(node) != NT_ANCHOR) goto restart;
- r = setup_tree(an->target, reg, (state | IN_NOT), env);
+ r = setup_tree(an->target, reg, (state | IN_NOT | IN_LOOK_BEHIND),
+ env);
if (r != 0) return r;
r = setup_look_behind(node, reg, env);
}
@@ -4209,169 +4215,73 @@ restart:
return r;
}
-#ifndef USE_SUNDAY_QUICK_SEARCH
-/* set skip map for Boyer-Moore search */
+/* set skip map for Sunday's quick search */
static int
set_bm_skip(UChar* s, UChar* end, regex_t* reg,
- UChar skip[], int** int_skip, int ignore_case)
+ UChar skip[], int ignore_case)
{
OnigDistance i, len;
int clen, flen, n, j, k;
- UChar *p, buf[ONIGENC_GET_CASE_FOLD_CODES_MAX_NUM][ONIGENC_MBC_CASE_FOLD_MAXLEN];
+ UChar *p, buf[ONIGENC_MBC_CASE_FOLD_MAXLEN];
OnigCaseFoldCodeItem items[ONIGENC_GET_CASE_FOLD_CODES_MAX_NUM];
OnigEncoding enc = reg->enc;
len = end - s;
- if (len < ONIG_CHAR_TABLE_SIZE) {
- for (i = 0; i < ONIG_CHAR_TABLE_SIZE; i++) skip[i] = (UChar )len;
-
- n = 0;
- for (i = 0; i < len - 1; i += clen) {
- p = s + i;
- if (ignore_case)
- n = ONIGENC_GET_CASE_FOLD_CODES_BY_STR(enc, reg->case_fold_flag,
- p, end, items);
- clen = enclen(enc, p, end);
- if (p + clen > end)
- clen = (int )(end - p);
-
- for (j = 0; j < n; j++) {
- if ((items[j].code_len != 1) || (items[j].byte_len != clen))
- return 1; /* different length isn't supported. */
- flen = ONIGENC_CODE_TO_MBC(enc, items[j].code[0], buf[j]);
- if (flen != clen)
- return 1; /* different length isn't supported. */
- }
- for (j = 0; j < clen; j++) {
- skip[s[i + j]] = (UChar )(len - 1 - i - j);
- for (k = 0; k < n; k++) {
- skip[buf[k][j]] = (UChar )(len - 1 - i - j);
- }
- }
- }
- }
- else {
-# if OPT_EXACT_MAXLEN < ONIG_CHAR_TABLE_SIZE
+ if (len >= ONIG_CHAR_TABLE_SIZE) {
/* This should not happen. */
return ONIGERR_TYPE_BUG;
-# else
- if (IS_NULL(*int_skip)) {
- *int_skip = (int* )xmalloc(sizeof(int) * ONIG_CHAR_TABLE_SIZE);
- if (IS_NULL(*int_skip)) return ONIGERR_MEMORY;
- }
- for (i = 0; i < ONIG_CHAR_TABLE_SIZE; i++) (*int_skip)[i] = (int )len;
-
- n = 0;
- for (i = 0; i < len - 1; i += clen) {
- p = s + i;
- if (ignore_case)
- n = ONIGENC_GET_CASE_FOLD_CODES_BY_STR(enc, reg->case_fold_flag,
- p, end, items);
- clen = enclen(enc, p, end);
- if (p + clen > end)
- clen = (int )(end - p);
-
- for (j = 0; j < n; j++) {
- if ((items[j].code_len != 1) || (items[j].byte_len != clen))
- return 1; /* different length isn't supported. */
- flen = ONIGENC_CODE_TO_MBC(enc, items[j].code[0], buf[j]);
- if (flen != clen)
- return 1; /* different length isn't supported. */
- }
- for (j = 0; j < clen; j++) {
- (*int_skip)[s[i + j]] = (int )(len - 1 - i - j);
- for (k = 0; k < n; k++) {
- (*int_skip)[buf[k][j]] = (int )(len - 1 - i - j);
- }
- }
- }
-# endif
}
- return 0;
-}
-
-#else /* USE_SUNDAY_QUICK_SEARCH */
-
-/* set skip map for Sunday's quick search */
-static int
-set_bm_skip(UChar* s, UChar* end, regex_t* reg,
- UChar skip[], int** int_skip, int ignore_case)
-{
- OnigDistance i, len;
- int clen, flen, n, j, k;
- UChar *p, buf[ONIGENC_GET_CASE_FOLD_CODES_MAX_NUM][ONIGENC_MBC_CASE_FOLD_MAXLEN];
- OnigCaseFoldCodeItem items[ONIGENC_GET_CASE_FOLD_CODES_MAX_NUM];
- OnigEncoding enc = reg->enc;
- len = end - s;
- if (len < ONIG_CHAR_TABLE_SIZE) {
- for (i = 0; i < ONIG_CHAR_TABLE_SIZE; i++) skip[i] = (UChar )(len + 1);
-
- n = 0;
+ if (ignore_case) {
for (i = 0; i < len; i += clen) {
p = s + i;
- if (ignore_case)
- n = ONIGENC_GET_CASE_FOLD_CODES_BY_STR(enc, reg->case_fold_flag,
- p, end, items);
+ n = ONIGENC_GET_CASE_FOLD_CODES_BY_STR(enc, reg->case_fold_flag,
+ p, end, items);
clen = enclen(enc, p, end);
if (p + clen > end)
clen = (int )(end - p);
for (j = 0; j < n; j++) {
- if ((items[j].code_len != 1) || (items[j].byte_len != clen))
- return 1; /* different length isn't supported. */
- flen = ONIGENC_CODE_TO_MBC(enc, items[j].code[0], buf[j]);
- if (flen != clen)
- return 1; /* different length isn't supported. */
- }
- for (j = 0; j < clen; j++) {
- skip[s[i + j]] = (UChar )(len - i - j);
- for (k = 0; k < n; k++) {
- skip[buf[k][j]] = (UChar )(len - i - j);
- }
+ if ((items[j].code_len != 1) || (items[j].byte_len != clen)) {
+ /* Different length isn't supported. Stop optimization at here. */
+ end = p;
+ goto endcheck;
+ }
+ flen = ONIGENC_CODE_TO_MBC(enc, items[j].code[0], buf);
+ if (flen != clen) {
+ /* Different length isn't supported. Stop optimization at here. */
+ end = p;
+ goto endcheck;
+ }
}
}
+endcheck:
+ len = end - s;
}
- else {
-# if OPT_EXACT_MAXLEN < ONIG_CHAR_TABLE_SIZE
- /* This should not happen. */
- return ONIGERR_TYPE_BUG;
-# else
- if (IS_NULL(*int_skip)) {
- *int_skip = (int* )xmalloc(sizeof(int) * ONIG_CHAR_TABLE_SIZE);
- if (IS_NULL(*int_skip)) return ONIGERR_MEMORY;
- }
- for (i = 0; i < ONIG_CHAR_TABLE_SIZE; i++) (*int_skip)[i] = (int )(len + 1);
-
- n = 0;
- for (i = 0; i < len; i += clen) {
- p = s + i;
- if (ignore_case)
- n = ONIGENC_GET_CASE_FOLD_CODES_BY_STR(enc, reg->case_fold_flag,
- p, end, items);
- clen = enclen(enc, p, end);
- if (p + clen > end)
- clen = (int )(end - p);
- for (j = 0; j < n; j++) {
- if ((items[j].code_len != 1) || (items[j].byte_len != clen))
- return 1; /* different length isn't supported. */
- flen = ONIGENC_CODE_TO_MBC(enc, items[j].code[0], buf[j]);
- if (flen != clen)
- return 1; /* different length isn't supported. */
- }
- for (j = 0; j < clen; j++) {
- (*int_skip)[s[i + j]] = (int )(len - i - j);
- for (k = 0; k < n; k++) {
- (*int_skip)[buf[k][j]] = (int )(len - i - j);
- }
+ for (i = 0; i < ONIG_CHAR_TABLE_SIZE; i++)
+ skip[i] = (UChar )(len + 1);
+ n = 0;
+ for (i = 0; i < len; i += clen) {
+ p = s + i;
+ if (ignore_case)
+ n = ONIGENC_GET_CASE_FOLD_CODES_BY_STR(enc, reg->case_fold_flag,
+ p, end, items);
+ clen = enclen(enc, p, end);
+ if (p + clen > end)
+ clen = (int )(end - p);
+
+ for (j = 0; j < clen; j++) {
+ skip[s[i + j]] = (UChar )(len - i - j);
+ for (k = 0; k < n; k++) {
+ ONIGENC_CODE_TO_MBC(enc, items[k].code[0], buf);
+ skip[buf[j]] = (UChar )(len - i - j);
}
}
-# endif
}
- return 0;
+
+ return (int )len;
}
-#endif /* USE_SUNDAY_QUICK_SEARCH */
typedef struct {
OnigDistance min; /* min byte length */
@@ -5049,7 +4959,7 @@ optimize_node_left(Node* node, NodeOptInfo* opt, OptEnv* env)
if (NSTRING_IS_DONT_GET_OPT_INFO(node)) {
int n = onigenc_strlen(env->enc, sn->s, sn->end);
- max = ONIGENC_MBC_MAXLEN_DIST(env->enc) * (OnigDistance)n;
+ max = (OnigDistance )ONIGENC_MBC_MAXLEN_DIST(env->enc) * (OnigDistance)n;
}
else {
concat_opt_exact_info_str(&opt->exb, sn->s, sn->end,
@@ -5232,7 +5142,7 @@ optimize_node_left(Node* node, NodeOptInfo* opt, OptEnv* env)
r = optimize_node_left(qn->target, &nopt, env);
if (r) break;
- if (/*qn->lower == 0 &&*/ IS_REPEAT_INFINITE(qn->upper)) {
+ if (qn->lower == 0 && IS_REPEAT_INFINITE(qn->upper)) {
if (env->mmd.max == 0 &&
NTYPE(qn->target) == NT_CANY && qn->greedy) {
if (IS_MULTILINE(env->options))
@@ -5342,7 +5252,6 @@ optimize_node_left(Node* node, NodeOptInfo* opt, OptEnv* env)
static int
set_optimize_exact_info(regex_t* reg, OptExactInfo* e)
{
- int r;
int allow_reverse;
if (e->len == 0) return 0;
@@ -5357,13 +5266,22 @@ set_optimize_exact_info(regex_t* reg, OptExactInfo* e)
if (e->ignore_case > 0) {
if (e->len >= 3 || (e->len >= 2 && allow_reverse)) {
- r = set_bm_skip(reg->exact, reg->exact_end, reg,
- reg->map, &(reg->int_map), 1);
- if (r == 0) {
+ int orig_len = e->len;
+ e->len = set_bm_skip(reg->exact, reg->exact_end, reg,
+ reg->map, 1);
+ if (e->len >= 3) {
+ reg->exact_end = reg->exact + e->len;
reg->optimize = (allow_reverse != 0
? ONIG_OPTIMIZE_EXACT_BM_IC : ONIG_OPTIMIZE_EXACT_BM_NOT_REV_IC);
}
else {
+ /* Even if BM skip table can't be built (e.g., pattern starts with
+ 's' or 'k' which have multi-byte case fold variants), we should
+ still use EXACT_IC optimization with the original pattern.
+ Without this fallback, patterns like /slackware/i have no
+ optimization at all, causing severe performance regression
+ especially with non-ASCII strings. See [Bug #21824] */
+ e->len = orig_len; /* Restore original length for EXACT_IC */
reg->optimize = ONIG_OPTIMIZE_EXACT_IC;
}
}
@@ -5373,15 +5291,10 @@ set_optimize_exact_info(regex_t* reg, OptExactInfo* e)
}
else {
if (e->len >= 3 || (e->len >= 2 && allow_reverse)) {
- r = set_bm_skip(reg->exact, reg->exact_end, reg,
- reg->map, &(reg->int_map), 0);
- if (r == 0) {
- reg->optimize = (allow_reverse != 0
- ? ONIG_OPTIMIZE_EXACT_BM : ONIG_OPTIMIZE_EXACT_BM_NOT_REV);
- }
- else {
- reg->optimize = ONIG_OPTIMIZE_EXACT;
- }
+ set_bm_skip(reg->exact, reg->exact_end, reg,
+ reg->map, 0);
+ reg->optimize = (allow_reverse != 0
+ ? ONIG_OPTIMIZE_EXACT_BM : ONIG_OPTIMIZE_EXACT_BM_NOT_REV);
}
else {
reg->optimize = ONIG_OPTIMIZE_EXACT;
@@ -5662,8 +5575,6 @@ 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);
@@ -5710,14 +5621,6 @@ onig_reg_copy(regex_t** nreg, regex_t* oreg)
(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;
@@ -5744,10 +5647,6 @@ onig_reg_copy(regex_t** nreg, regex_t* oreg)
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);
@@ -5764,8 +5663,6 @@ onig_memsize(const regex_t *reg)
if (IS_NULL(reg)) return 0;
if (IS_NOT_NULL(reg->p)) size += reg->alloc;
if (IS_NOT_NULL(reg->exact)) size += reg->exact_end - reg->exact;
- if (IS_NOT_NULL(reg->int_map)) size += sizeof(int) * ONIG_CHAR_TABLE_SIZE;
- if (IS_NOT_NULL(reg->int_map_backward)) size += sizeof(int) * ONIG_CHAR_TABLE_SIZE;
if (IS_NOT_NULL(reg->repeat_range)) size += reg->repeat_range_alloc * sizeof(OnigRepeatRange);
if (IS_NOT_NULL(reg->chain)) size += onig_memsize(reg->chain);
@@ -6030,6 +5927,12 @@ onig_reg_init(regex_t* reg, OnigOptionType option,
if (IS_NULL(reg))
return ONIGERR_INVALID_ARGUMENT;
+ (reg)->exact = (UChar* )NULL;
+ (reg)->chain = (regex_t* )NULL;
+ (reg)->p = (UChar* )NULL;
+ (reg)->name_table = (void* )NULL;
+ (reg)->repeat_range = (OnigRepeatRange* )NULL;
+
if (ONIGENC_IS_UNDEF(enc))
return ONIGERR_DEFAULT_ENCODING_IS_NOT_SET;
@@ -6049,15 +5952,9 @@ onig_reg_init(regex_t* reg, OnigOptionType option,
(reg)->options = option;
(reg)->syntax = syntax;
(reg)->optimize = 0;
- (reg)->exact = (UChar* )NULL;
- (reg)->int_map = (int* )NULL;
- (reg)->int_map_backward = (int* )NULL;
- (reg)->chain = (regex_t* )NULL;
- (reg)->p = (UChar* )NULL;
(reg)->alloc = 0;
(reg)->used = 0;
- (reg)->name_table = (void* )NULL;
(reg)->case_fold_flag = case_fold_flag;
diff --git a/regenc.c b/regenc.c
index 0afdf22cb7..c595f44b29 100644
--- a/regenc.c
+++ b/regenc.c
@@ -3,7 +3,7 @@
**********************************************************************/
/*-
* Copyright (c) 2002-2007 K.Kosako <sndgk393 AT ybb DOT ne DOT jp>
- * Copyright (c) 2011-2016 K.Takata <kentkt AT csc DOT jp>
+ * Copyright (c) 2011-2019 K.Takata <kentkt AT csc DOT jp>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -640,18 +640,19 @@ onigenc_single_byte_mbc_to_code(const UChar* p, const UChar* end ARG_UNUSED,
}
extern int
-onigenc_single_byte_code_to_mbclen(OnigCodePoint code ARG_UNUSED, OnigEncoding enc ARG_UNUSED)
+onigenc_single_byte_code_to_mbclen(OnigCodePoint code, OnigEncoding enc ARG_UNUSED)
{
+ if (code > 0xff)
+ return ONIGERR_INVALID_CODE_POINT_VALUE;
return 1;
}
extern int
onigenc_single_byte_code_to_mbc(OnigCodePoint code, UChar *buf, OnigEncoding enc ARG_UNUSED)
{
-#ifdef RUBY
- if (code > 0xff)
- rb_raise(rb_eRangeError, "%u out of char range", code);
-#endif
+ if (code > 0xff) {
+ return ONIGERR_INVALID_CODE_POINT_VALUE;
+ }
*buf = (UChar )(code & 0xff);
return 1;
}
@@ -966,6 +967,7 @@ onigenc_property_list_add_property(UChar* name, const OnigCodePoint* prop,
}
#endif
+#ifdef USE_CASE_MAP_API
extern int
onigenc_ascii_only_case_map(OnigCaseFoldType* flagP, const OnigUChar** pp, const OnigUChar* end,
OnigUChar* to, OnigUChar* to_end, const struct OnigEncodingTypeST* enc)
@@ -984,7 +986,7 @@ onigenc_ascii_only_case_map(OnigCaseFoldType* flagP, const OnigUChar** pp, const
if (code >= 'a' && code <= 'z' && (flags & ONIGENC_CASE_UPCASE)) {
flags |= ONIGENC_CASE_MODIFIED;
- code += 'A' - 'a';
+ code -= 'a' - 'A';
}
else if (code >= 'A' && code <= 'Z' &&
(flags & (ONIGENC_CASE_DOWNCASE | ONIGENC_CASE_FOLD))) {
@@ -1013,7 +1015,7 @@ onigenc_single_byte_ascii_only_case_map(OnigCaseFoldType* flagP, const OnigUChar
if (code >= 'a' && code <= 'z' && (flags & ONIGENC_CASE_UPCASE)) {
flags |= ONIGENC_CASE_MODIFIED;
- code += 'A' - 'a';
+ code -= 'a' - 'A';
}
else if (code >= 'A' && code <= 'Z' &&
(flags & (ONIGENC_CASE_DOWNCASE | ONIGENC_CASE_FOLD))) {
@@ -1027,3 +1029,4 @@ onigenc_single_byte_ascii_only_case_map(OnigCaseFoldType* flagP, const OnigUChar
*flagP = flags;
return (int )(to - to_start);
}
+#endif
diff --git a/regenc.h b/regenc.h
index 4fbe403b63..fe0440dd74 100644
--- a/regenc.h
+++ b/regenc.h
@@ -5,7 +5,7 @@
**********************************************************************/
/*-
* Copyright (c) 2002-2008 K.Kosako <sndgk393 AT ybb DOT ne DOT jp>
- * Copyright (c) 2011-2016 K.Takata <kentkt AT csc DOT jp>
+ * Copyright (c) 2011-2019 K.Takata <kentkt AT csc DOT jp>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -134,11 +134,13 @@ typedef struct {
#define roomof(x, y) (((x) + (y) - 1) / (y))
#define type_roomof(x, y) roomof(sizeof(x), sizeof(y))
+/* config */
#define USE_CRNL_AS_LINE_TERMINATOR
#define USE_UNICODE_PROPERTIES
#define USE_UNICODE_AGE_PROPERTIES
/* #define USE_UNICODE_CASE_FOLD_TURKISH_AZERI */
/* #define USE_UNICODE_ALL_LINE_TERMINATORS */ /* see Unicode.org UTS #18 */
+#define USE_CASE_MAP_API
#define ONIG_ENCODING_INIT_DEFAULT ONIG_ENCODING_ASCII
diff --git a/regerror.c b/regerror.c
index 8667084d41..c61797564b 100644
--- a/regerror.c
+++ b/regerror.c
@@ -3,7 +3,7 @@
**********************************************************************/
/*-
* Copyright (c) 2002-2007 K.Kosako <sndgk393 AT ybb DOT ne DOT jp>
- * Copyright (c) 2011-2016 K.Takata <kentkt AT csc DOT jp>
+ * Copyright (c) 2011-2019 K.Takata <kentkt AT csc DOT jp>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -63,14 +63,18 @@ onig_error_code_to_format(OnigPosition code)
p = "parse depth limit over"; break;
case ONIGERR_DEFAULT_ENCODING_IS_NOT_SET:
p = "default multibyte-encoding is not set"; break;
+#if 0
case ONIGERR_SPECIFIED_ENCODING_CANT_CONVERT_TO_WIDE_CHAR:
p = "can't convert to wide-char on specified multibyte-encoding"; break;
+#endif
case ONIGERR_INVALID_ARGUMENT:
p = "invalid argument"; break;
case ONIGERR_END_PATTERN_AT_LEFT_BRACE:
p = "end pattern at left brace"; break;
+#if 0
case ONIGERR_END_PATTERN_AT_LEFT_BRACKET:
p = "end pattern at left bracket"; break;
+#endif
case ONIGERR_EMPTY_CHAR_CLASS:
p = "empty char-class"; break;
case ONIGERR_PREMATURE_END_OF_CHAR_CLASS:
@@ -87,16 +91,20 @@ onig_error_code_to_format(OnigPosition code)
p = "invalid control-code syntax"; break;
case ONIGERR_CHAR_CLASS_VALUE_AT_END_OF_RANGE:
p = "char-class value at end of range"; break;
+#if 0
case ONIGERR_CHAR_CLASS_VALUE_AT_START_OF_RANGE:
p = "char-class value at start of range"; break;
+#endif
case ONIGERR_UNMATCHED_RANGE_SPECIFIER_IN_CHAR_CLASS:
p = "unmatched range specifier in char-class"; break;
case ONIGERR_TARGET_OF_REPEAT_OPERATOR_NOT_SPECIFIED:
p = "target of repeat operator is not specified"; break;
case ONIGERR_TARGET_OF_REPEAT_OPERATOR_INVALID:
p = "target of repeat operator is invalid"; break;
+#if 0
case ONIGERR_NESTED_REPEAT_OPERATOR:
p = "nested repeat operator"; break;
+#endif
case ONIGERR_UNMATCHED_CLOSE_PARENTHESIS:
p = "unmatched close parenthesis"; break;
case ONIGERR_END_PATTERN_WITH_UNMATCHED_PARENTHESIS:
@@ -121,14 +129,18 @@ onig_error_code_to_format(OnigPosition code)
p = "upper is smaller than lower in repeat range"; break;
case ONIGERR_EMPTY_RANGE_IN_CHAR_CLASS:
p = "empty range in char class"; break;
+#if 0
case ONIGERR_MISMATCH_CODE_LENGTH_IN_CLASS_RANGE:
p = "mismatch multibyte code length in char-class range"; break;
+#endif
case ONIGERR_TOO_MANY_MULTI_BYTE_RANGES:
p = "too many multibyte code ranges are specified"; break;
case ONIGERR_TOO_SHORT_MULTI_BYTE_STRING:
p = "too short multibyte code string"; break;
+#if 0
case ONIGERR_TOO_BIG_BACKREF_NUMBER:
p = "too big backref number"; break;
+#endif
case ONIGERR_INVALID_BACKREF:
#ifdef USE_NAMED_GROUP
p = "invalid backref number/name"; break;
@@ -161,10 +173,16 @@ onig_error_code_to_format(OnigPosition code)
p = "multiplex definition name <%n> call"; break;
case ONIGERR_NEVER_ENDING_RECURSION:
p = "never ending recursion"; break;
+#ifdef USE_CAPTURE_HISTORY
case ONIGERR_GROUP_NUMBER_OVER_FOR_CAPTURE_HISTORY:
p = "group number is too big for capture history"; break;
+#endif
case ONIGERR_INVALID_CHAR_PROPERTY_NAME:
p = "invalid character property name {%n}"; break;
+ case ONIGERR_TOO_MANY_RANGE_REPEAT:
+ p = "too many range repeat"; break;
+ case ONIGERR_TOO_MANY_NULL_CHECK:
+ p = "too many null check"; break;
case ONIGERR_TOO_MANY_CAPTURE_GROUPS:
p = "too many capture groups are specified"; break;
case ONIGERR_INVALID_CODE_POINT_VALUE:
diff --git a/regexec.c b/regexec.c
index b8d174ec8e..3210c7cc1b 100644
--- a/regexec.c
+++ b/regexec.c
@@ -2,8 +2,8 @@
regexec.c - Onigmo (Oniguruma-mod) (regular expression library)
**********************************************************************/
/*-
- * Copyright (c) 2002-2008 K.Kosako <sndgk393 AT ybb DOT ne DOT jp>
- * Copyright (c) 2011-2016 K.Takata <kentkt AT csc DOT jp>
+ * Copyright (c) 2002-2018 K.Kosako <sndgk393 AT ybb DOT ne DOT jp>
+ * Copyright (c) 2011-2019 K.Takata <kentkt AT csc DOT jp>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -2742,7 +2742,6 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
/* default behavior: return first-matching result. */
goto finish;
- NEXT;
CASE(OP_EXACT1) MOP_IN(OP_EXACT1);
DATA_ENSURE(1);
@@ -3316,40 +3315,36 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
if (ON_STR_BEGIN(s) || !ONIGENC_IS_MBC_WORD(encode, sprev, end)) {
MOP_OUT;
JUMP;
- }
+ }
}
goto fail;
- NEXT;
CASE(OP_ASCII_WORD_BEGIN) MOP_IN(OP_ASCII_WORD_BEGIN);
if (DATA_ENSURE_CHECK1 && ONIGENC_IS_MBC_ASCII_WORD(encode, s, end)) {
if (ON_STR_BEGIN(s) || !ONIGENC_IS_MBC_ASCII_WORD(encode, sprev, end)) {
MOP_OUT;
JUMP;
- }
+ }
}
goto fail;
- NEXT;
CASE(OP_WORD_END) MOP_IN(OP_WORD_END);
if (!ON_STR_BEGIN(s) && ONIGENC_IS_MBC_WORD(encode, sprev, end)) {
if (ON_STR_END(s) || !ONIGENC_IS_MBC_WORD(encode, s, end)) {
MOP_OUT;
JUMP;
- }
+ }
}
goto fail;
- NEXT;
CASE(OP_ASCII_WORD_END) MOP_IN(OP_ASCII_WORD_END);
if (!ON_STR_BEGIN(s) && ONIGENC_IS_MBC_ASCII_WORD(encode, sprev, end)) {
if (ON_STR_END(s) || !ONIGENC_IS_MBC_ASCII_WORD(encode, s, end)) {
MOP_OUT;
JUMP;
- }
+ }
}
goto fail;
- NEXT;
#endif
CASE(OP_BEGIN_BUF) MOP_IN(OP_BEGIN_BUF);
@@ -3379,10 +3374,9 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
#endif
&& !ON_STR_END(s)) {
MOP_OUT;
- JUMP;
+ JUMP;
}
goto fail;
- NEXT;
CASE(OP_END_LINE) MOP_IN(OP_END_LINE);
if (ON_STR_END(s)) {
@@ -3398,10 +3392,9 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
}
else if (ONIGENC_IS_MBC_NEWLINE_EX(encode, s, str, end, option, 1)) {
MOP_OUT;
- JUMP;
+ JUMP;
}
goto fail;
- NEXT;
CASE(OP_SEMI_END_BUF) MOP_IN(OP_SEMI_END_BUF);
if (ON_STR_END(s)) {
@@ -3433,7 +3426,6 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
#endif
}
goto fail;
- NEXT;
CASE(OP_BEGIN_POSITION) MOP_IN(OP_BEGIN_POSITION);
if (s != msa->gpos)
@@ -3499,12 +3491,10 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
CASE(OP_BACKREF1) MOP_IN(OP_BACKREF1);
mem = 1;
goto backref;
- NEXT;
CASE(OP_BACKREF2) MOP_IN(OP_BACKREF2);
mem = 2;
goto backref;
- NEXT;
CASE(OP_BACKREFN) MOP_IN(OP_BACKREFN);
GET_MEMNUM_INC(mem, p);
@@ -3934,7 +3924,6 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
STACK_GET_REPEAT(mem, stkp);
si = GET_STACK_INDEX(stkp);
goto repeat_inc;
- NEXT;
CASE(OP_REPEAT_INC_NG) MOP_IN(OP_REPEAT_INC_NG);
GET_MEMNUM_INC(mem, p); /* mem: OP_REPEAT ID */
@@ -3970,7 +3959,6 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
STACK_GET_REPEAT(mem, stkp);
si = GET_STACK_INDEX(stkp);
goto repeat_inc_ng;
- NEXT;
CASE(OP_PUSH_POS) MOP_IN(OP_PUSH_POS);
STACK_PUSH_POS(s, sprev, pkeep);
@@ -3995,7 +3983,6 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
CASE(OP_FAIL_POS) MOP_IN(OP_FAIL_POS);
STACK_POP_TIL_POS_NOT;
goto fail;
- NEXT;
CASE(OP_PUSH_STOP_BT) MOP_IN(OP_PUSH_STOP_BT);
STACK_PUSH_STOP_BT;
@@ -4036,7 +4023,6 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
CASE(OP_FAIL_LOOK_BEHIND_NOT) MOP_IN(OP_FAIL_LOOK_BEHIND_NOT);
STACK_POP_TIL_LOOK_BEHIND_NOT;
goto fail;
- NEXT;
CASE(OP_PUSH_ABSENT_POS) MOP_IN(OP_PUSH_ABSENT_POS);
/* Save the absent-start-pos and the original end-pos. */
@@ -4098,7 +4084,6 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
#endif
STACK_POP_TIL_ABSENT;
goto fail;
- NEXT;
#ifdef USE_SUBEXP_CALL
CASE(OP_CALL) MOP_IN(OP_CALL);
@@ -4128,7 +4113,6 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
CASE(OP_FINISH)
goto finish;
- NEXT;
CASE(OP_FAIL)
if (0) {
@@ -4393,219 +4377,6 @@ slow_search_backward_ic(OnigEncoding enc, int case_fold_flag,
return (UChar* )NULL;
}
-#ifndef USE_SUNDAY_QUICK_SEARCH
-/* Boyer-Moore-Horspool search applied to a multibyte string */
-static UChar*
-bm_search_notrev(regex_t* reg, const UChar* target, const UChar* target_end,
- const UChar* text, const UChar* text_end,
- const UChar* text_range)
-{
- const UChar *s, *se, *t, *p, *end;
- const UChar *tail;
- ptrdiff_t skip, tlen1;
-
-# ifdef ONIG_DEBUG_SEARCH
- fprintf(stderr, "bm_search_notrev: text: %"PRIuPTR" (%p), text_end: %"PRIuPTR" (%p), text_range: %"PRIuPTR" (%p)\n",
- (uintptr_t )text, text, (uintptr_t )text_end, text_end, (uintptr_t )text_range, text_range);
-# endif
-
- tail = target_end - 1;
- tlen1 = tail - target;
- end = text_range;
- if (end + tlen1 > text_end)
- end = text_end - tlen1;
-
- s = text;
-
- if (IS_NULL(reg->int_map)) {
- while (s < end) {
- p = se = s + tlen1;
- t = tail;
- while (*p == *t) {
- if (t == target) return (UChar* )s;
- p--; t--;
- }
- skip = reg->map[*se];
- t = s;
- do {
- s += enclen(reg->enc, s, end);
- } while ((s - t) < skip && s < end);
- }
- }
- else {
-# if OPT_EXACT_MAXLEN >= ONIG_CHAR_TABLE_SIZE
- while (s < end) {
- p = se = s + tlen1;
- t = tail;
- while (*p == *t) {
- if (t == target) return (UChar* )s;
- p--; t--;
- }
- skip = reg->int_map[*se];
- t = s;
- do {
- s += enclen(reg->enc, s, end);
- } while ((s - t) < skip && s < end);
- }
-# endif
- }
-
- return (UChar* )NULL;
-}
-
-/* Boyer-Moore-Horspool search */
-static UChar*
-bm_search(regex_t* reg, const UChar* target, const UChar* target_end,
- const UChar* text, const UChar* text_end, const UChar* text_range)
-{
- const UChar *s, *t, *p, *end;
- const UChar *tail;
-
-# ifdef ONIG_DEBUG_SEARCH
- fprintf(stderr, "bm_search: text: %"PRIuPTR" (%p), text_end: %"PRIuPTR" (%p), text_range: %"PRIuPTR" (%p)\n",
- (uintptr_t )text, text, (uintptr_t )text_end, text_end, (uintptr_t )text_range, text_range);
-# endif
-
- end = text_range + (target_end - target) - 1;
- if (end > text_end)
- end = text_end;
-
- tail = target_end - 1;
- s = text + (target_end - target) - 1;
- if (IS_NULL(reg->int_map)) {
- while (s < end) {
- p = s;
- t = tail;
-# ifdef ONIG_DEBUG_SEARCH
- fprintf(stderr, "bm_search_loop: pos: %"PRIdPTR" %s\n",
- (intptr_t )(s - text), s);
-# endif
- while (*p == *t) {
- if (t == target) return (UChar* )p;
- p--; t--;
- }
- s += reg->map[*s];
- }
- }
- else { /* see int_map[] */
-# if OPT_EXACT_MAXLEN >= ONIG_CHAR_TABLE_SIZE
- while (s < end) {
- p = s;
- t = tail;
- while (*p == *t) {
- if (t == target) return (UChar* )p;
- p--; t--;
- }
- s += reg->int_map[*s];
- }
-# endif
- }
- return (UChar* )NULL;
-}
-
-/* Boyer-Moore-Horspool search applied to a multibyte string (ignore case) */
-static UChar*
-bm_search_notrev_ic(regex_t* reg, const UChar* target, const UChar* target_end,
- const UChar* text, const UChar* text_end,
- const UChar* text_range)
-{
- const UChar *s, *se, *t, *end;
- const UChar *tail;
- ptrdiff_t skip, tlen1;
- OnigEncoding enc = reg->enc;
- int case_fold_flag = reg->case_fold_flag;
-
-# ifdef ONIG_DEBUG_SEARCH
- fprintf(stderr, "bm_search_notrev_ic: text: %d (%p), text_end: %d (%p), text_range: %d (%p)\n",
- (int )text, text, (int )text_end, text_end, (int )text_range, text_range);
-# endif
-
- tail = target_end - 1;
- tlen1 = tail - target;
- end = text_range;
- if (end + tlen1 > text_end)
- end = text_end - tlen1;
-
- s = text;
-
- if (IS_NULL(reg->int_map)) {
- while (s < end) {
- se = s + tlen1;
- if (str_lower_case_match(enc, case_fold_flag, target, target_end,
- s, se + 1))
- return (UChar* )s;
- skip = reg->map[*se];
- t = s;
- do {
- s += enclen(reg->enc, s, end);
- } while ((s - t) < skip && s < end);
- }
- }
- else {
-# if OPT_EXACT_MAXLEN >= ONIG_CHAR_TABLE_SIZE
- while (s < end) {
- se = s + tlen1;
- if (str_lower_case_match(enc, case_fold_flag, target, target_end,
- s, se + 1))
- return (UChar* )s;
- skip = reg->int_map[*se];
- t = s;
- do {
- s += enclen(reg->enc, s, end);
- } while ((s - t) < skip && s < end);
- }
-# endif
- }
-
- return (UChar* )NULL;
-}
-
-/* Boyer-Moore-Horspool search (ignore case) */
-static UChar*
-bm_search_ic(regex_t* reg, const UChar* target, const UChar* target_end,
- const UChar* text, const UChar* text_end, const UChar* text_range)
-{
- const UChar *s, *p, *end;
- const UChar *tail;
- OnigEncoding enc = reg->enc;
- int case_fold_flag = reg->case_fold_flag;
-
-# ifdef ONIG_DEBUG_SEARCH
- fprintf(stderr, "bm_search_ic: text: %d (%p), text_end: %d (%p), text_range: %d (%p)\n",
- (int )text, text, (int )text_end, text_end, (int )text_range, text_range);
-# endif
-
- end = text_range + (target_end - target) - 1;
- if (end > text_end)
- end = text_end;
-
- tail = target_end - 1;
- s = text + (target_end - target) - 1;
- if (IS_NULL(reg->int_map)) {
- while (s < end) {
- p = s - (target_end - target) + 1;
- if (str_lower_case_match(enc, case_fold_flag, target, target_end,
- p, s + 1))
- return (UChar* )p;
- s += reg->map[*s];
- }
- }
- else { /* see int_map[] */
-# if OPT_EXACT_MAXLEN >= ONIG_CHAR_TABLE_SIZE
- while (s < end) {
- p = s - (target_end - target) + 1;
- if (str_lower_case_match(enc, case_fold_flag, target, target_end,
- p, s + 1))
- return (UChar* )p;
- s += reg->int_map[*s];
- }
-# endif
- }
- return (UChar* )NULL;
-}
-
-#else /* USE_SUNDAY_QUICK_SEARCH */
-
/* Sunday's quick search applied to a multibyte string */
static UChar*
bm_search_notrev(regex_t* reg, const UChar* target, const UChar* target_end,
@@ -4630,39 +4401,19 @@ bm_search_notrev(regex_t* reg, const UChar* target, const UChar* target_end,
s = text;
- if (IS_NULL(reg->int_map)) {
- while (s < end) {
- p = se = s + tlen1;
- t = tail;
- while (*p == *t) {
- if (t == target) return (UChar* )s;
- p--; t--;
- }
- if (s + 1 >= end) break;
- skip = reg->map[se[1]];
- t = s;
- do {
- s += enclen(enc, s, end);
- } while ((s - t) < skip && s < end);
- }
- }
- else {
-# if OPT_EXACT_MAXLEN >= ONIG_CHAR_TABLE_SIZE
- while (s < end) {
- p = se = s + tlen1;
- t = tail;
- while (*p == *t) {
- if (t == target) return (UChar* )s;
- p--; t--;
- }
- if (s + 1 >= end) break;
- skip = reg->int_map[se[1]];
- t = s;
- do {
- s += enclen(enc, s, end);
- } while ((s - t) < skip && s < end);
+ while (s < end) {
+ p = se = s + tlen1;
+ t = tail;
+ while (*p == *t) {
+ if (t == target) return (UChar* )s;
+ p--; t--;
}
-# endif
+ if (s + 1 >= end) break;
+ skip = reg->map[se[1]];
+ t = s;
+ do {
+ s += enclen(enc, s, end);
+ } while ((s - t) < skip && s < end);
}
return (UChar* )NULL;
@@ -4689,32 +4440,17 @@ bm_search(regex_t* reg, const UChar* target, const UChar* target_end,
end = text_end;
s = text + tlen1;
- if (IS_NULL(reg->int_map)) {
- while (s < end) {
- p = s;
- t = tail;
- while (*p == *t) {
- if (t == target) return (UChar* )p;
- p--; t--;
- }
- if (s + 1 >= end) break;
- s += reg->map[s[1]];
- }
- }
- else { /* see int_map[] */
-# if OPT_EXACT_MAXLEN >= ONIG_CHAR_TABLE_SIZE
- while (s < end) {
- p = s;
- t = tail;
- while (*p == *t) {
- if (t == target) return (UChar* )p;
- p--; t--;
- }
- if (s + 1 >= end) break;
- s += reg->int_map[s[1]];
+ while (s < end) {
+ p = s;
+ t = tail;
+ while (*p == *t) {
+ if (t == target) return (UChar* )p;
+ p--; t--;
}
-# endif
+ if (s + 1 >= end) break;
+ s += reg->map[s[1]];
}
+
return (UChar* )NULL;
}
@@ -4743,35 +4479,17 @@ bm_search_notrev_ic(regex_t* reg, const UChar* target, const UChar* target_end,
s = text;
- if (IS_NULL(reg->int_map)) {
- while (s < end) {
- se = s + tlen1;
- if (str_lower_case_match(enc, case_fold_flag, target, target_end,
- s, se + 1))
- return (UChar* )s;
- if (s + 1 >= end) break;
- skip = reg->map[se[1]];
- t = s;
- do {
- s += enclen(enc, s, end);
- } while ((s - t) < skip && s < end);
- }
- }
- else {
-# if OPT_EXACT_MAXLEN >= ONIG_CHAR_TABLE_SIZE
- while (s < end) {
- se = s + tlen1;
- if (str_lower_case_match(enc, case_fold_flag, target, target_end,
- s, se + 1))
- return (UChar* )s;
- if (s + 1 >= end) break;
- skip = reg->int_map[se[1]];
- t = s;
- do {
- s += enclen(enc, s, end);
- } while ((s - t) < skip && s < end);
- }
-# endif
+ while (s < end) {
+ se = s + tlen1;
+ if (str_lower_case_match(enc, case_fold_flag, target, target_end,
+ s, se + 1))
+ return (UChar* )s;
+ if (s + 1 >= end) break;
+ skip = reg->map[se[1]];
+ t = s;
+ do {
+ s += enclen(enc, s, end);
+ } while ((s - t) < skip && s < end);
}
return (UChar* )NULL;
@@ -4800,83 +4518,17 @@ bm_search_ic(regex_t* reg, const UChar* target, const UChar* target_end,
end = text_end;
s = text + tlen1;
- if (IS_NULL(reg->int_map)) {
- while (s < end) {
- p = s - tlen1;
- if (str_lower_case_match(enc, case_fold_flag, target, target_end,
- p, s + 1))
- return (UChar* )p;
- if (s + 1 >= end) break;
- s += reg->map[s[1]];
- }
- }
- else { /* see int_map[] */
-# if OPT_EXACT_MAXLEN >= ONIG_CHAR_TABLE_SIZE
- while (s < end) {
- p = s - tlen1;
- if (str_lower_case_match(enc, case_fold_flag, target, target_end,
- p, s + 1))
- return (UChar* )p;
- if (s + 1 >= end) break;
- s += reg->int_map[s[1]];
- }
-# endif
- }
- return (UChar* )NULL;
-}
-#endif /* USE_SUNDAY_QUICK_SEARCH */
-
-#ifdef USE_INT_MAP_BACKWARD
-static int
-set_bm_backward_skip(UChar* s, UChar* end, OnigEncoding enc ARG_UNUSED,
- int** skip)
-{
- int i, len;
-
- if (IS_NULL(*skip)) {
- *skip = (int* )xmalloc(sizeof(int) * ONIG_CHAR_TABLE_SIZE);
- if (IS_NULL(*skip)) return ONIGERR_MEMORY;
- }
-
- len = (int )(end - s);
- for (i = 0; i < ONIG_CHAR_TABLE_SIZE; i++)
- (*skip)[i] = len;
-
- for (i = len - 1; i > 0; i--)
- (*skip)[s[i]] = i;
-
- return 0;
-}
-
-static UChar*
-bm_search_backward(regex_t* reg, const UChar* target, const UChar* target_end,
- const UChar* text, const UChar* adjust_text,
- const UChar* text_end, const UChar* text_start)
-{
- const UChar *s, *t, *p;
-
- s = text_end - (target_end - target);
- if (text_start < s)
- s = text_start;
- else
- s = ONIGENC_LEFT_ADJUST_CHAR_HEAD(reg->enc, adjust_text, s, text_end);
-
- while (s >= text) {
- p = s;
- t = target;
- while (t < target_end && *p == *t) {
- p++; t++;
- }
- if (t == target_end)
- return (UChar* )s;
-
- s -= reg->int_map_backward[*s];
- s = ONIGENC_LEFT_ADJUST_CHAR_HEAD(reg->enc, adjust_text, s, text_end);
+ while (s < end) {
+ p = s - tlen1;
+ if (str_lower_case_match(enc, case_fold_flag, target, target_end,
+ p, s + 1))
+ return (UChar* )p;
+ if (s + 1 >= end) break;
+ s += reg->map[s[1]];
}
return (UChar* )NULL;
}
-#endif
static UChar*
map_search(OnigEncoding enc, UChar map[],
@@ -5124,21 +4776,7 @@ backward_search_range(regex_t* reg, const UChar* str, const UChar* end,
case ONIG_OPTIMIZE_EXACT_BM:
case ONIG_OPTIMIZE_EXACT_BM_NOT_REV:
-#ifdef USE_INT_MAP_BACKWARD
- if (IS_NULL(reg->int_map_backward)) {
- int r;
- if (s - range < BM_BACKWARD_SEARCH_LENGTH_THRESHOLD)
- goto exact_method;
-
- r = set_bm_backward_skip(reg->exact, reg->exact_end, reg->enc,
- &(reg->int_map_backward));
- if (r) return r;
- }
- p = bm_search_backward(reg, reg->exact, reg->exact_end, range, adjrange,
- end, p);
-#else
goto exact_method;
-#endif
break;
case ONIG_OPTIMIZE_MAP:
diff --git a/regint.h b/regint.h
index 75abfba235..3f4aa919e5 100644
--- a/regint.h
+++ b/regint.h
@@ -5,7 +5,7 @@
**********************************************************************/
/*-
* Copyright (c) 2002-2013 K.Kosako <sndgk393 AT ybb DOT ne DOT jp>
- * Copyright (c) 2011-2016 K.Takata <kentkt AT csc DOT jp>
+ * Copyright (c) 2011-2019 K.Takata <kentkt AT csc DOT jp>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -86,13 +86,12 @@
/* #define USE_OP_PUSH_OR_JUMP_EXACT */
#define USE_QTFR_PEEK_NEXT
#define USE_ST_LIBRARY
-#define USE_SUNDAY_QUICK_SEARCH
#define INIT_MATCH_STACK_SIZE 160
#define DEFAULT_MATCH_STACK_LIMIT_SIZE 0 /* unlimited */
#define DEFAULT_PARSE_DEPTH_LIMIT 4096
-#define OPT_EXACT_MAXLEN 24
+#define OPT_EXACT_MAXLEN 24 /* This must be smaller than ONIG_CHAR_TABLE_SIZE. */
/* check config */
#if defined(USE_PERL_SUBEXP_CALL) || defined(USE_CAPITAL_P_NAMED_GROUP)
@@ -216,9 +215,7 @@
#define xmemcpy memcpy
#define xmemmove memmove
-#if ((defined(RUBY_MSVCRT_VERSION) && RUBY_MSVCRT_VERSION >= 90) \
- || (!defined(RUBY_MSVCRT_VERSION) && defined(_WIN32))) \
- && !defined(__GNUC__)
+#if defined(_WIN32) && !defined(__GNUC__)
# define xalloca _alloca
# define xvsnprintf(buf,size,fmt,args) _vsnprintf_s(buf,size,_TRUNCATE,fmt,args)
# define xsnprintf sprintf_s
@@ -267,19 +264,6 @@
# include <stdio.h>
#endif
-#ifdef _WIN32
-# if defined(_MSC_VER) && (_MSC_VER < 1300)
-# ifndef _INTPTR_T_DEFINED
-# define _INTPTR_T_DEFINED
-typedef int intptr_t;
-# endif
-# ifndef _UINTPTR_T_DEFINED
-# define _UINTPTR_T_DEFINED
-typedef unsigned int uintptr_t;
-# endif
-# endif
-#endif /* _WIN32 */
-
#ifndef PRIdPTR
# ifdef _WIN64
# define PRIdPTR "I64d"
diff --git a/regparse.c b/regparse.c
index 418bd38140..123b3015a5 100644
--- a/regparse.c
+++ b/regparse.c
@@ -3,7 +3,7 @@
**********************************************************************/
/*-
* Copyright (c) 2002-2008 K.Kosako <sndgk393 AT ybb DOT ne DOT jp>
- * Copyright (c) 2011-2016 K.Takata <kentkt AT csc DOT jp>
+ * Copyright (c) 2011-2019 K.Takata <kentkt AT csc DOT jp>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -4043,7 +4043,11 @@ fetch_token(OnigToken* tok, UChar** src, UChar* end, ScanEnv* env)
if (c == 'R' || c == '0') {
PINC; /* skip 'R' / '0' */
- if (!PPEEK_IS(')')) return ONIGERR_INVALID_GROUP_NAME;
+ if (!PPEEK_IS(')')) {
+ r = ONIGERR_INVALID_GROUP_NAME;
+ onig_scan_env_set_error_string(env, r, p - 1, p + 1);
+ return r;
+ }
PINC; /* skip ')' */
name_end = name = p;
gnum = 0;
@@ -6309,11 +6313,14 @@ parse_exp(Node** np, OnigToken* tok, int term,
int r, len, group = 0;
Node* qn;
Node** targetp;
+ unsigned int parse_depth;
*np = NULL;
if (tok->type == (enum TokenSyms )term)
goto end_of_token;
+ parse_depth = env->parse_depth;
+
switch (tok->type) {
case TK_ALT:
case TK_EOT:
@@ -6624,6 +6631,10 @@ parse_exp(Node** np, OnigToken* tok, int term,
if (is_invalid_quantifier_target(*targetp))
return ONIGERR_TARGET_OF_REPEAT_OPERATOR_INVALID;
+ parse_depth++;
+ if (parse_depth > ParseDepthLimit)
+ return ONIGERR_PARSE_DEPTH_LIMIT_OVER;
+
qn = node_new_quantifier(tok->u.repeat.lower, tok->u.repeat.upper,
(r == TK_INTERVAL ? 1 : 0));
CHECK_NULL_RETURN_MEMERR(qn);
diff --git a/regparse.h b/regparse.h
index dd35d48525..65da835a55 100644
--- a/regparse.h
+++ b/regparse.h
@@ -5,7 +5,7 @@
**********************************************************************/
/*-
* Copyright (c) 2002-2007 K.Kosako <sndgk393 AT ybb DOT ne DOT jp>
- * Copyright (c) 2011-2016 K.Takata <kentkt AT csc DOT jp>
+ * Copyright (c) 2011-2019 K.Takata <kentkt AT csc DOT jp>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/ruby.c b/ruby.c
index 5a78a7c764..162287ca71 100644
--- a/ruby.c
+++ b/ruby.c
@@ -119,7 +119,11 @@ enum feature_flag_bits {
EACH_FEATURES(DEFINE_FEATURE, COMMA),
DEFINE_FEATURE(frozen_string_literal_set),
feature_debug_flag_first,
+#if !USE_YJIT && USE_ZJIT
+ DEFINE_FEATURE(jit) = feature_zjit,
+#else
DEFINE_FEATURE(jit) = feature_yjit,
+#endif
feature_jit_mask = FEATURE_BIT(yjit) | FEATURE_BIT(zjit),
feature_debug_flag_begin = feature_debug_flag_first - 1,
@@ -322,7 +326,7 @@ usage(const char *name, int help, int highlight, int columns)
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("-d", ", --debug", "Set debugging flag ($DEBUG) and $VERBOSE 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."),
@@ -406,9 +410,6 @@ usage(const char *name, int help, int highlight, int columns)
#define SHOW(m) show_usage_line(&(m), help, highlight, w, columns)
printf("%sUsage:%s %s [options] [--] [filepath] [arguments]\n", sb, se, name);
- printf("\n""Details and examples at https://docs.ruby-lang.org/en/%s/ruby/options_md.html\n",
- ruby_api_version_name);
-
for (i = 0; i < num; ++i)
SHOW(usage_msg[i]);
@@ -445,7 +446,7 @@ ruby_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;
+ VALUE load_path = rb_root_box()->load_path;
#ifdef __CYGWIN__
char rubylib[FILENAME_MAX];
VALUE buf = 0;
@@ -750,7 +751,7 @@ ruby_init_loadpath(void)
rb_gc_register_address(&ruby_archlibdir_path);
ruby_archlibdir_path = archlibdir;
- load_path = GET_VM()->load_path;
+ load_path = rb_root_box()->load_path;
ruby_push_include(getenv("RUBYLIB"), identical_path);
@@ -797,6 +798,25 @@ require_libraries(VALUE *req_list)
*req_list = 0;
}
+static void
+require_libraries_in_main_box(VALUE *req_list)
+{
+ const rb_box_t *main_box = rb_main_box();
+ VALUE list = *req_list;
+ ID require;
+ rb_encoding *extenc = rb_default_external_encoding();
+
+ CONST_ID(require, "require");
+ while (list && RARRAY_LEN(list) > 0) {
+ VALUE feature = rb_ary_shift(list);
+ rb_enc_associate(feature, extenc);
+ RBASIC_SET_CLASS_RAW(feature, rb_cString);
+ OBJ_FREEZE(feature);
+ rb_funcallv(main_box->box_object, require, 1, &feature);
+ }
+ *req_list = 0;
+}
+
static const struct rb_block*
toplevel_context(rb_binding_t *bind)
{
@@ -912,7 +932,9 @@ moreswitches(const char *s, ruby_cmdline_options_t *opt, int envopt)
argc = RSTRING_LEN(argary) / sizeof(ap);
ap = 0;
rb_str_cat(argary, (char *)&ap, sizeof(ap));
- argv = ptr = ALLOC_N(char *, argc);
+
+ VALUE ptr_obj;
+ argv = ptr = RB_ALLOCV_N(char *, ptr_obj, argc);
MEMMOVE(argv, RSTRING_PTR(argary), char *, argc);
while ((i = proc_options(argc, argv, opt, envopt)) > 1 && envopt && (argc -= i) > 0) {
@@ -944,7 +966,8 @@ moreswitches(const char *s, ruby_cmdline_options_t *opt, int envopt)
opt->crash_report = crash_report;
}
- ruby_xfree(ptr);
+ RB_ALLOCV_END(ptr_obj);
+
/* get rid of GC */
rb_str_resize(argary, 0);
rb_str_resize(argstr, 0);
@@ -1369,7 +1392,7 @@ proc_0_option(ruby_cmdline_options_t *opt, const char *s)
static void
proc_encoding_option(ruby_cmdline_options_t *opt, const char *s, const char *opt_name)
{
- char *p;
+ const char *p;
# define set_encoding_part(type) \
if (!(p = strchr(s, ':'))) { \
set_##type##_encoding_once(opt, s, 0); \
@@ -1466,7 +1489,7 @@ proc_long_options(ruby_cmdline_options_t *opt, const char *s, long argc, char **
ruby_verbose = Qtrue;
}
else if (strcmp("jit", s) == 0) {
-#if USE_YJIT
+#if USE_YJIT || USE_ZJIT
FEATURE_SET(opt->features, FEATURE_BIT(jit));
#else
rb_warn("Ruby was built without JIT support");
@@ -1767,6 +1790,7 @@ proc_options(long argc, char **argv, ruby_cmdline_options_t *opt, int envopt)
return argc0 - argc;
}
+VALUE rb_define_gem_modules(VALUE, VALUE);
void Init_builtin_features(void);
static void
@@ -1794,26 +1818,6 @@ ruby_opt_init(ruby_cmdline_options_t *opt)
if (opt->dump & dump_exit_bits) return;
- if (FEATURE_SET_P(opt->features, gems)) {
- rb_define_module("Gem");
- if (opt->features.set & FEATURE_BIT(error_highlight)) {
- rb_define_module("ErrorHighlight");
- }
- if (opt->features.set & FEATURE_BIT(did_you_mean)) {
- rb_define_module("DidYouMean");
- }
- if (opt->features.set & FEATURE_BIT(syntax_suggest)) {
- rb_define_module("SyntaxSuggest");
- }
- }
-
- /* [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");
- }
-
Init_ext(); /* load statically linked extensions before rubygems */
Init_extra_exts();
@@ -1822,24 +1826,67 @@ ruby_opt_init(ruby_cmdline_options_t *opt)
GET_VM()->running = 1;
memset(ruby_vm_redefined_flag, 0, sizeof(ruby_vm_redefined_flag));
- if (rb_namespace_available())
- rb_initialize_main_namespace();
- rb_namespace_init_done();
+ // Register JIT-optimized builtin CMEs before the prelude, which may
+ // redefine core methods (e.g. Kernel.prepend via bundler/setup).
+#if USE_YJIT
+ rb_yjit_init_builtin_cmes();
+#endif
+#if USE_ZJIT
+ extern void rb_zjit_init_builtin_cmes(void);
+ rb_zjit_init_builtin_cmes();
+#endif
+
+ /**
+ * Initialize the root/main boxes before loading libraries to run them
+ * (including RubyGems, written in Ruby) in those boxes themselves
+ */
+ if (rb_box_available()) {
+ rb_initialize_mandatory_boxes();
+ }
+
+ rb_box_init_done();
+
+ if (FEATURE_SET_P(opt->features, gems)) {
+ rb_box_gem_flags_t gem_flags = {
+ .gem = FEATURE_SET_P(opt->features, gems),
+ .error_highlight = opt->features.set & FEATURE_BIT(error_highlight),
+ .did_you_mean = opt->features.set & FEATURE_BIT(did_you_mean),
+ .syntax_suggest = opt->features.set & FEATURE_BIT(syntax_suggest)
+ };
+
+ if (rb_box_available()) {
+ rb_vm_call_cfunc_in_box(Qnil, rb_define_gem_modules, (VALUE)&gem_flags, Qnil,
+ rb_str_new_cstr("before_prelude.root.dummy"), rb_root_box());
+ rb_vm_call_cfunc_in_box(Qnil, rb_define_gem_modules, (VALUE)&gem_flags, Qnil,
+ rb_str_new_cstr("before_prelude.main.dummy"), rb_main_box());
+
+ rb_box_set_gem_flags(&gem_flags);
+ }
+ else {
+ rb_define_gem_modules((VALUE)&gem_flags, Qnil);
+ }
+ }
+
+ // The root/main boxes load gem_prelude here.
+ // User boxes will load it in those #initialize instead.
ruby_init_prelude();
- // Initialize JITs after ruby_init_prelude() because JITing prelude is typically not optimal.
+ // Enable JITs after ruby_init_prelude() to avoid JITing prelude code.
#if USE_YJIT
rb_yjit_init(opt->yjit);
#endif
#if USE_ZJIT
- if (opt->zjit) {
- extern void rb_zjit_init(void);
- rb_zjit_init();
- }
+ extern void rb_zjit_init(bool);
+ rb_zjit_init(opt->zjit);
#endif
ruby_set_script_name(opt->script_name);
- require_libraries(&opt->req_list);
+ if (rb_box_available()) {
+ require_libraries_in_main_box(&opt->req_list);
+ }
+ else {
+ require_libraries(&opt->req_list);
+ }
}
static int
@@ -2173,10 +2220,8 @@ prism_script_shebang_callback(pm_options_t *options, const uint8_t *source, size
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_parse_result_init(result);
+ pm_options_t *options = result->options;
pm_options_main_script_set(options, true);
const bool read_stdin = (strcmp(opt->script, "-") == 0);
@@ -2202,7 +2247,7 @@ prism_script(ruby_cmdline_options_t *opt, pm_parse_result_t *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) {
+ if (NIL_P(error) && pm_parser_data_loc(result->parser)->length != 0) {
rb_define_global_const("DATA", rb_stdin);
}
}
@@ -2239,17 +2284,20 @@ prism_script(ruby_cmdline_options_t *opt, pm_parse_result_t *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) {
+ if (NIL_P(error) && pm_parser_data_loc(result->parser)->length != 0) {
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;
+ const pm_parser_t *parser = result->parser;
+ const pm_location_t *data_loc = pm_parser_data_loc(parser);
+ const uint8_t *start = pm_parser_start(parser);
+ const uint8_t *end = pm_parser_end(parser);
+ uint32_t offset = data_loc->start + 7;
- if ((parser->start + offset < parser->end) && parser->start[offset] == '\r') offset++;
- if ((parser->start + offset < parser->end) && parser->start[offset] == '\n') offset++;
+ if ((start + offset < end) && start[offset] == '\r') offset++;
+ if ((start + offset < end) && start[offset] == '\n') offset++;
- rb_funcall(file, rb_intern_const("seek"), 2, SIZET2NUM(offset), INT2FIX(SEEK_SET));
+ rb_funcall(file, rb_intern_const("seek"), 2, UINT2NUM(offset), INT2FIX(SEEK_SET));
rb_define_global_const("DATA", file);
}
}
@@ -2263,11 +2311,11 @@ prism_script(ruby_cmdline_options_t *opt, pm_parse_result_t *result)
static VALUE
prism_dump_tree(pm_parse_result_t *result)
{
- pm_buffer_t output_buffer = { 0 };
+ pm_buffer_t *output_buffer = pm_buffer_new();
- 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);
+ pm_prettyprint(output_buffer, result->parser, result->node.ast_node);
+ VALUE tree = rb_str_new(pm_buffer_value(output_buffer), pm_buffer_length(output_buffer));
+ pm_buffer_free(output_buffer);
return tree;
}
@@ -2303,6 +2351,16 @@ process_options_global_setup(const ruby_cmdline_options_t *opt, const rb_iseq_t
rb_exec_event_hook_script_compiled(ec, iseq, script);
}
+static bool
+has_dir_sep(const char *path)
+{
+ if (strchr(path, '/')) return true;
+#ifdef _WIN32
+ if (strchr(path, '\\')) return true;
+#endif
+ return false;
+}
+
static VALUE
process_options(int argc, char **argv, ruby_cmdline_options_t *opt)
{
@@ -2324,8 +2382,8 @@ process_options(int argc, char **argv, ruby_cmdline_options_t *opt)
char fbuf[MAXPATHLEN];
int i = (int)proc_options(argc, argv, opt, 0);
unsigned int dump = opt->dump & dump_exit_bits;
- rb_vm_t *vm = GET_VM();
- const long loaded_before_enc = RARRAY_LEN(vm->loaded_features);
+ const rb_box_t *box = rb_root_box();
+ const long loaded_before_enc = RARRAY_LEN(box->loaded_features);
if (opt->dump & (DUMP_BIT(usage)|DUMP_BIT(help))) {
const char *const progname =
@@ -2358,6 +2416,12 @@ process_options(int argc, char **argv, ruby_cmdline_options_t *opt)
#if USE_ZJIT
if (!FEATURE_USED_P(opt->features, zjit) && env_var_truthy("RUBY_ZJIT_ENABLE")) {
FEATURE_SET(opt->features, FEATURE_BIT(zjit));
+
+ // When the --zjit flag is specified, we would have call setup_zjit_options(""),
+ // which would have called rb_zjit_prepare_options() internally. This ensures we
+ // go through the same set up but with less overhead than setup_zjit_options("").
+ extern void rb_zjit_prepare_options();
+ rb_zjit_prepare_options();
}
#endif
}
@@ -2373,10 +2437,9 @@ process_options(int argc, char **argv, ruby_cmdline_options_t *opt)
}
#endif
#if USE_ZJIT
- if (FEATURE_SET_P(opt->features, zjit) && !opt->zjit) {
- extern void rb_zjit_prepare_options(void);
- rb_zjit_prepare_options();
- opt->zjit = true;
+ if (FEATURE_SET_P(opt->features, zjit)) {
+ bool rb_zjit_option_enable(void);
+ opt->zjit = rb_zjit_option_enable(); // set opt->zjit for Init_ruby_description() and calling rb_zjit_init()
}
#endif
@@ -2403,7 +2466,7 @@ process_options(int argc, char **argv, ruby_cmdline_options_t *opt)
if (!opt->script || opt->script[0] == '\0') {
opt->script = "-";
}
- else if (opt->do_search) {
+ else if (opt->do_search && !has_dir_sep(opt->script)) {
const char *path = getenv("RUBYPATH");
opt->script = 0;
@@ -2473,7 +2536,7 @@ process_options(int argc, char **argv, ruby_cmdline_options_t *opt)
rb_obj_freeze(opt->script_name);
if (IF_UTF8_PATH(uenc != lenc, 1)) {
long i;
- VALUE load_path = vm->load_path;
+ VALUE load_path = box->load_path;
const ID id_initial_load_path_mark = INITIAL_LOAD_PATH_MARK;
int modifiable = FALSE;
@@ -2496,11 +2559,11 @@ process_options(int argc, char **argv, ruby_cmdline_options_t *opt)
RARRAY_ASET(load_path, i, path);
}
if (modifiable) {
- rb_ary_replace(vm->load_path_snapshot, load_path);
+ rb_ary_replace(box->load_path_snapshot, load_path);
}
}
{
- VALUE loaded_features = vm->loaded_features;
+ VALUE loaded_features = box->loaded_features;
bool modified = false;
for (long i = loaded_before_enc; i < RARRAY_LEN(loaded_features); ++i) {
VALUE path = RARRAY_AREF(loaded_features, i);
@@ -2512,7 +2575,7 @@ process_options(int argc, char **argv, ruby_cmdline_options_t *opt)
RARRAY_ASET(loaded_features, i, path);
}
if (modified) {
- rb_ary_replace(vm->loaded_features_snapshot, loaded_features);
+ rb_ary_replace(box->loaded_features_snapshot, loaded_features);
}
}
diff --git a/jit.rs b/ruby.rs
index b66b2d21ca..b66b2d21ca 100644
--- a/jit.rs
+++ b/ruby.rs
diff --git a/ruby_atomic.h b/ruby_atomic.h
index ad53356f06..409b9bcfd2 100644
--- a/ruby_atomic.h
+++ b/ruby_atomic.h
@@ -2,6 +2,9 @@
#define INTERNAL_ATOMIC_H
#include "ruby/atomic.h"
+#ifdef HAVE_STDATOMIC_H
+# include <stdatomic.h>
+#endif
#define RUBY_ATOMIC_VALUE_LOAD(x) rbimpl_atomic_value_load(&(x), RBIMPL_ATOMIC_SEQ_CST)
@@ -43,6 +46,8 @@ rbimpl_atomic_u64_load_relaxed(const volatile rbimpl_atomic_uint64_t *value)
uint64_t val = *value;
return atomic_cas_64(value, val, val);
#else
+ // TODO: stdatomic
+
return *value;
#endif
}
@@ -58,9 +63,51 @@ rbimpl_atomic_u64_set_relaxed(volatile rbimpl_atomic_uint64_t *address, uint64_t
#elif defined(__sun) && defined(HAVE_ATOMIC_H) && (defined(_LP64) || defined(_I32LPx))
atomic_swap_64(address, value);
#else
+ // TODO: stdatomic
+
*address = value;
#endif
}
#define ATOMIC_U64_SET_RELAXED(var, val) rbimpl_atomic_u64_set_relaxed(&(var), val)
+static inline uint64_t
+rbimpl_atomic_u64_fetch_add_relaxed(volatile rbimpl_atomic_uint64_t *value, uint64_t addend)
+{
+#if defined(HAVE_GCC_ATOMIC_BUILTINS_64)
+ return __atomic_fetch_add(value, addend, __ATOMIC_RELAXED);
+#elif defined(_WIN32)
+ return (uint64_t)InterlockedExchangeAdd64((LONG64 *)value, (LONG64)addend);
+#elif defined(__sun) && defined(HAVE_ATOMIC_H) && (defined(_LP64) || defined(_I32LPx))
+ return atomic_add_64_nv(value, addend) - addend;
+#else
+ // TODO: stdatomic
+ uint64_t prev = *value;
+ *value = prev + addend;
+ return prev;
+#endif
+}
+#define ATOMIC_U64_FETCH_ADD_RELAXED(var, val) rbimpl_atomic_u64_fetch_add_relaxed(&(var), val)
+
+static inline uint64_t
+rbimpl_atomic_u64_load_acquire(const volatile rbimpl_atomic_uint64_t *value)
+{
+#if defined(HAVE_GCC_ATOMIC_BUILTINS_64)
+ return __atomic_load_n(value, __ATOMIC_ACQUIRE);
+#else
+ return rbimpl_atomic_u64_load_relaxed(value);
+#endif
+}
+#define ATOMIC_U64_LOAD_ACQUIRE(var) rbimpl_atomic_u64_load_acquire(&(var))
+
+static inline void
+rbimpl_atomic_u64_set_release(volatile rbimpl_atomic_uint64_t *address, uint64_t value)
+{
+#if defined(HAVE_GCC_ATOMIC_BUILTINS_64)
+ __atomic_store_n(address, value, __ATOMIC_RELEASE);
+#else
+ rbimpl_atomic_u64_set_relaxed(address, value);
+#endif
+}
+#define ATOMIC_U64_SET_RELEASE(var, val) rbimpl_atomic_u64_set_release(&(var), val)
+
#endif
diff --git a/ruby_parser.c b/ruby_parser.c
index 267f619bf9..a96fc4974b 100644
--- a/ruby_parser.c
+++ b/ruby_parser.c
@@ -407,7 +407,7 @@ static const rb_parser_config_t rb_global_parser_config = {
.set_errinfo = rb_set_errinfo,
.make_exception = rb_make_exception,
- .sized_xfree = ruby_sized_xfree,
+ .sized_xfree = ruby_xfree_sized,
.sized_realloc_n = ruby_sized_realloc_n,
.gc_guard = gc_guard,
.gc_mark = rb_gc_mark,
diff --git a/rubyparser.h b/rubyparser.h
index cc63efd3f8..2ed93e9894 100644
--- a/rubyparser.h
+++ b/rubyparser.h
@@ -248,6 +248,7 @@ typedef struct RNode_SCOPE {
rb_ast_id_table_t *nd_tbl;
struct RNode *nd_body;
+ struct RNode *nd_parent;
struct RNode_ARGS *nd_args;
} rb_node_scope_t;
@@ -288,25 +289,7 @@ typedef struct RNode_CASE {
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;
+} rb_node_case_t, rb_node_case2_t, rb_node_case3_t;
typedef struct RNode_WHEN {
NODE node;
@@ -781,7 +764,7 @@ struct rb_args_info {
struct RNode_OPT_ARG *opt_args;
unsigned int no_kwarg: 1;
- unsigned int ruby2_keywords: 1;
+ unsigned int no_blockarg: 1;
unsigned int forwarding: 1;
};
@@ -913,6 +896,9 @@ typedef struct RNode_SCLASS {
struct RNode *nd_recv;
struct RNode *nd_body;
+ rb_code_location_t class_keyword_loc;
+ rb_code_location_t operator_loc;
+ rb_code_location_t end_keyword_loc;
} rb_node_sclass_t;
typedef struct RNode_COLON2 {
diff --git a/sample/openssl/c_rehash.rb b/sample/openssl/c_rehash.rb
index de4b66e902..8b005bbb84 100644
--- a/sample/openssl/c_rehash.rb
+++ b/sample/openssl/c_rehash.rb
@@ -156,7 +156,7 @@ private
end
def hash_name(name)
- sprintf("%x", name.hash)
+ sprintf("%08x", name.hash)
end
def fingerprint(der)
diff --git a/sample/uumerge.rb b/sample/uumerge.rb
index 1b81582c24..23f95ba465 100644
--- a/sample/uumerge.rb
+++ b/sample/uumerge.rb
@@ -22,7 +22,7 @@ while line = gets()
end
end
-raise "missing begin" unless $sawbegin
+raise "missing begin" unless $sawbegin > 0
out.binmode
while line = gets()
diff --git a/scheduler.c b/scheduler.c
index ddb205da88..7efd4274cb 100644
--- a/scheduler.c
+++ b/scheduler.c
@@ -9,6 +9,7 @@
**********************************************************************/
#include "vm_core.h"
+#include "eval_intern.h"
#include "ruby/fiber/scheduler.h"
#include "ruby/io.h"
#include "ruby/io/buffer.h"
@@ -27,6 +28,8 @@ static ID id_scheduler_close;
static ID id_block;
static ID id_unblock;
+static ID id_yield;
+
static ID id_timeout_after;
static ID id_kernel_sleep;
static ID id_process_wait;
@@ -74,19 +77,6 @@ struct rb_fiber_scheduler_blocking_operation {
volatile rb_atomic_t status;
};
-static void
-blocking_operation_mark(void *ptr)
-{
- // No Ruby objects to mark in our struct
-}
-
-static void
-blocking_operation_free(void *ptr)
-{
- rb_fiber_scheduler_blocking_operation_t *blocking_operation = (rb_fiber_scheduler_blocking_operation_t *)ptr;
- ruby_xfree(blocking_operation);
-}
-
static size_t
blocking_operation_memsize(const void *ptr)
{
@@ -96,11 +86,11 @@ blocking_operation_memsize(const void *ptr)
static const rb_data_type_t blocking_operation_data_type = {
"Fiber::Scheduler::BlockingOperation",
{
- blocking_operation_mark,
- blocking_operation_free,
+ NULL, // nothing to mark
+ RUBY_DEFAULT_FREE,
blocking_operation_memsize,
},
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_EMBEDDABLE
};
/*
@@ -290,13 +280,15 @@ rb_fiber_scheduler_blocking_operation_new(void *(*function)(void *), void *data,
*
* Hook methods are:
*
- * * #io_wait, #io_read, #io_write, #io_pread, #io_pwrite, and #io_select, #io_close
+ * * #io_wait, #io_read, #io_write, #io_pread, #io_pwrite #io_select, and #io_close
* * #process_wait
* * #kernel_sleep
* * #timeout_after
* * #address_resolve
* * #block and #unblock
* * #blocking_operation_wait
+ * * #fiber_interrupt
+ * * #yield
* * (the list is expanded as Ruby developers make more methods having non-blocking calls)
*
* When not specified otherwise, the hook implementations are mandatory: if they are not
@@ -320,6 +312,7 @@ Init_Fiber_Scheduler(void)
id_block = rb_intern_const("block");
id_unblock = rb_intern_const("unblock");
+ id_yield = rb_intern_const("yield");
id_timeout_after = rb_intern_const("timeout_after");
id_kernel_sleep = rb_intern_const("kernel_sleep");
@@ -367,6 +360,9 @@ Init_Fiber_Scheduler(void)
rb_define_method(rb_cFiberScheduler, "unblock", rb_fiber_scheduler_unblock, 2);
rb_define_method(rb_cFiberScheduler, "fiber", rb_fiber_scheduler_fiber, -2);
rb_define_method(rb_cFiberScheduler, "blocking_operation_wait", rb_fiber_scheduler_blocking_operation_wait, -2);
+ rb_define_method(rb_cFiberScheduler, "yield", rb_fiber_scheduler_yield, 0);
+ rb_define_method(rb_cFiberScheduler, "fiber_interrupt", rb_fiber_scheduler_fiber_interrupt, 2);
+ rb_define_method(rb_cFiberScheduler, "io_close", rb_fiber_scheduler_io_close, 1);
#endif
}
@@ -447,7 +443,7 @@ rb_fiber_scheduler_set(VALUE scheduler)
}
static VALUE
-rb_fiber_scheduler_current_for_threadptr(rb_thread_t *thread)
+fiber_scheduler_current_for_threadptr(rb_thread_t *thread)
{
RUBY_ASSERT(thread);
@@ -459,15 +455,22 @@ rb_fiber_scheduler_current_for_threadptr(rb_thread_t *thread)
}
}
-VALUE
-rb_fiber_scheduler_current(void)
+VALUE rb_fiber_scheduler_current(void)
{
- return rb_fiber_scheduler_current_for_threadptr(GET_THREAD());
+ RUBY_ASSERT(ruby_thread_has_gvl_p());
+
+ return fiber_scheduler_current_for_threadptr(GET_THREAD());
}
+// This function is allowed to be called without holding the GVL.
VALUE rb_fiber_scheduler_current_for_thread(VALUE thread)
{
- return rb_fiber_scheduler_current_for_threadptr(rb_thread_ptr(thread));
+ return fiber_scheduler_current_for_threadptr(rb_thread_ptr(thread));
+}
+
+VALUE rb_fiber_scheduler_current_for_threadptr(rb_thread_t *thread)
+{
+ return fiber_scheduler_current_for_threadptr(thread);
}
/*
@@ -516,7 +519,7 @@ rb_fiber_scheduler_make_timeout(struct timeval *timeout)
* Document-method: Fiber::Scheduler#kernel_sleep
* call-seq: kernel_sleep(duration = nil)
*
- * Invoked by Kernel#sleep and Mutex#sleep and is expected to provide
+ * Invoked by Kernel#sleep and Thread::Mutex#sleep and is expected to provide
* an implementation of sleeping in a non-blocking way. Implementation might
* register the current fiber in some list of "which fiber wait until what
* moment", call Fiber.yield to pass control, and then in #close resume
@@ -535,6 +538,23 @@ rb_fiber_scheduler_kernel_sleepv(VALUE scheduler, int argc, VALUE * argv)
return rb_funcallv(scheduler, id_kernel_sleep, argc, argv);
}
+/**
+ * Document-method: Fiber::Scheduler#yield
+ * call-seq: yield
+ *
+ * Yield to the scheduler, to be resumed on the next scheduling cycle.
+ */
+VALUE
+rb_fiber_scheduler_yield(VALUE scheduler)
+{
+ // First try to call the scheduler's yield method, if it exists:
+ VALUE result = rb_check_funcall(scheduler, id_yield, 0, NULL);
+ if (!UNDEF_P(result)) return result;
+
+ // Otherwise, we can emulate yield by sleeping for 0 seconds:
+ return rb_fiber_scheduler_kernel_sleep(scheduler, RB_INT2NUM(0));
+}
+
#if 0
/*
* Document-method: Fiber::Scheduler#timeout_after
@@ -558,7 +578,7 @@ rb_fiber_scheduler_kernel_sleepv(VALUE scheduler, int argc, VALUE * argv)
* However, as a result of this design, if the +block+ does not invoke any
* non-blocking operations, it will be impossible to interrupt it. If you
* desire to provide predictable points for timeouts, consider adding
- * +sleep(0)+.
+ * <tt>sleep(0)</tt>.
*
* If the block is executed successfully, its result will be returned.
*
@@ -613,7 +633,7 @@ rb_fiber_scheduler_process_wait(VALUE scheduler, rb_pid_t pid, int flags)
* Document-method: Fiber::Scheduler#block
* call-seq: block(blocker, timeout = nil)
*
- * Invoked by methods like Thread.join, and by Mutex, to signify that current
+ * Invoked by methods like Thread.join, and by Thread::Mutex, to signify that current
* Fiber is blocked until further notice (e.g. #unblock) or until +timeout+ has
* elapsed.
*
@@ -633,8 +653,8 @@ rb_fiber_scheduler_block(VALUE scheduler, VALUE blocker, VALUE timeout)
* Document-method: Fiber::Scheduler#unblock
* call-seq: unblock(blocker, fiber)
*
- * Invoked to wake up Fiber previously blocked with #block (for example, Mutex#lock
- * calls #block and Mutex#unlock calls #unblock). The scheduler should use
+ * Invoked to wake up Fiber previously blocked with #block (for example, Thread::Mutex#lock
+ * calls #block and Thread::Mutex#unlock calls #unblock). The scheduler should use
* the +fiber+ parameter to understand which fiber is unblocked.
*
* +blocker+ is what was awaited for, but it is informational only (for debugging
@@ -647,18 +667,36 @@ rb_fiber_scheduler_unblock(VALUE scheduler, VALUE blocker, VALUE fiber)
{
RUBY_ASSERT(rb_obj_is_fiber(fiber));
+ VALUE result;
+ enum ruby_tag_type state;
+
// `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;
-#ifdef RUBY_DEBUG
+ // We must prevent interrupts while invoking the unblock method, because otherwise fibers can be left permanently blocked if an interrupt occurs during the execution of user code. See also `rb_fiber_scheduler_fiber_interrupt`.
rb_execution_context_t *ec = GET_EC();
- if (RUBY_VM_INTERRUPTED(ec)) {
- rb_bug("rb_fiber_scheduler_unblock called with pending interrupt");
+ int saved_interrupt_mask = ec->interrupt_mask;
+ ec->interrupt_mask |= PENDING_INTERRUPT_MASK;
+
+ rb_control_frame_t *volatile cfp = ec->cfp;
+ EC_PUSH_TAG(ec);
+ if ((state = EC_EXEC_TAG()) == TAG_NONE) {
+ result = rb_funcall(scheduler, id_unblock, 2, blocker, fiber);
}
-#endif
+ else {
+ rb_vm_rewind_cfp(ec, cfp);
+ }
+ EC_POP_TAG();
- VALUE result = rb_funcall(scheduler, id_unblock, 2, blocker, fiber);
+ ec->interrupt_mask = saved_interrupt_mask;
+
+ if (state) {
+ EC_JUMP_TAG(ec, state);
+ }
+
+ RUBY_VM_CHECK_INTS(ec);
errno = saved_errno;
@@ -914,6 +952,8 @@ fiber_scheduler_io_pwrite(VALUE _argument) {
VALUE
rb_fiber_scheduler_io_pwrite(VALUE scheduler, VALUE io, rb_off_t from, VALUE buffer, size_t length, size_t offset)
{
+
+
if (!rb_respond_to(scheduler, id_io_pwrite)) {
return RUBY_Qundef;
}
@@ -977,6 +1017,14 @@ rb_fiber_scheduler_io_pwrite_memory(VALUE scheduler, VALUE io, rb_off_t from, co
return result;
}
+/*
+ * Document-method: Fiber::Scheduler#io_close
+ * call-seq: io_close(fd)
+ *
+ * Invoked by Ruby's core methods to notify scheduler that the IO object is closed. Note that
+ * the method will receive an integer file descriptor of the closed object, not an object
+ * itself.
+ */
VALUE
rb_fiber_scheduler_io_close(VALUE scheduler, VALUE io)
{
@@ -1032,7 +1080,8 @@ rb_fiber_scheduler_address_resolve(VALUE scheduler, VALUE hostname)
* call-seq: blocking_operation_wait(blocking_operation)
*
* Invoked by Ruby's core methods to run a blocking operation in a non-blocking way.
- * The blocking_operation is a Fiber::Scheduler::BlockingOperation that encapsulates the blocking operation.
+ * The blocking_operation is an opaque object that encapsulates the blocking operation
+ * and responds to a <tt>#call</tt> method without any arguments.
*
* If the scheduler doesn't implement this method, or if the scheduler doesn't execute
* the blocking operation, Ruby will fall back to the non-scheduler implementation.
@@ -1066,6 +1115,9 @@ VALUE rb_fiber_scheduler_blocking_operation_wait(VALUE scheduler, void* (*functi
operation->data2 = NULL;
operation->unblock_function = NULL;
+ // Ensure that the blocking operation remains visible until this point:
+ RB_GC_GUARD(blocking_operation);
+
// If the blocking operation was never executed, return Qundef to signal the caller to use rb_nogvl instead
if (current_status == RB_FIBER_SCHEDULER_BLOCKING_OPERATION_STATUS_QUEUED) {
return Qundef;
@@ -1074,20 +1126,48 @@ VALUE rb_fiber_scheduler_blocking_operation_wait(VALUE scheduler, void* (*functi
return result;
}
+/*
+ * Document-method: Fiber::Scheduler#fiber_interrupt
+ * call-seq: fiber_interrupt(fiber, exception)
+ *
+ * Invoked by Ruby's core methods to notify the scheduler that the blocked fiber should be interrupted
+ * with an exception. For example, IO#close uses this method to interrupt fibers that are performing
+ * blocking IO operations.
+ *
+ */
VALUE rb_fiber_scheduler_fiber_interrupt(VALUE scheduler, VALUE fiber, VALUE exception)
{
VALUE arguments[] = {
fiber, exception
};
-#ifdef RUBY_DEBUG
+ VALUE result;
+ enum ruby_tag_type state;
+
+ // We must prevent interrupts while invoking the fiber_interrupt method, because otherwise fibers can be left permanently blocked if an interrupt occurs during the execution of user code. See also `rb_fiber_scheduler_unblock`.
rb_execution_context_t *ec = GET_EC();
- if (RUBY_VM_INTERRUPTED(ec)) {
- rb_bug("rb_fiber_scheduler_fiber_interrupt called with pending interrupt");
+ int saved_interrupt_mask = ec->interrupt_mask;
+ ec->interrupt_mask |= PENDING_INTERRUPT_MASK;
+
+ rb_control_frame_t *volatile cfp = ec->cfp;
+ EC_PUSH_TAG(ec);
+ if ((state = EC_EXEC_TAG()) == TAG_NONE) {
+ result = rb_check_funcall(scheduler, id_fiber_interrupt, 2, arguments);
}
-#endif
+ else {
+ rb_vm_rewind_cfp(ec, cfp);
+ }
+ EC_POP_TAG();
+
+ ec->interrupt_mask = saved_interrupt_mask;
+
+ if (state) {
+ EC_JUMP_TAG(ec, state);
+ }
+
+ RUBY_VM_CHECK_INTS(ec);
- return rb_check_funcall(scheduler, id_fiber_interrupt, 2, arguments);
+ return result;
}
/*
diff --git a/set.c b/set.c
index 60c099bf49..8d6f33329b 100644
--- a/set.c
+++ b/set.c
@@ -102,6 +102,8 @@ static ID id_any_p;
static ID id_new;
static ID id_i_hash;
static ID id_set_iter_lev;
+static ID id_subclass_compatible;
+static ID id_class_methods;
#define RSET_INITIALIZED FL_USER1
#define RSET_LEV_MASK (FL_USER13 | FL_USER14 | FL_USER15 | /* FL 13..19 */ \
@@ -114,7 +116,7 @@ static ID id_set_iter_lev;
#define RSET_SIZE(set) set_table_size(RSET_TABLE(set))
#define RSET_EMPTY(set) (RSET_SIZE(set) == 0)
#define RSET_SIZE_NUM(set) SIZET2NUM(RSET_SIZE(set))
-#define RSET_IS_MEMBER(sobj, item) set_table_lookup(RSET_TABLE(set), (st_data_t)(item))
+#define RSET_IS_MEMBER(set, item) set_table_lookup(RSET_TABLE(set), (st_data_t)(item))
#define RSET_COMPARE_BY_IDENTITY(set) (RSET_TABLE(set)->type == &identhash)
struct set_object {
@@ -122,6 +124,14 @@ struct set_object {
};
static int
+mark_and_pin_key(st_data_t key, st_data_t data)
+{
+ rb_gc_mark((VALUE)key);
+
+ return ST_CONTINUE;
+}
+
+static int
mark_key(st_data_t key, st_data_t data)
{
rb_gc_mark_movable((VALUE)key);
@@ -133,21 +143,21 @@ static void
set_mark(void *ptr)
{
struct set_object *sobj = ptr;
- if (sobj->table.entries) set_table_foreach(&sobj->table, mark_key, 0);
-}
-
-static void
-set_free_embedded(struct set_object *sobj)
-{
- free((&sobj->table)->entries);
+ if (sobj->table.entries) {
+ if (sobj->table.type == &identhash) {
+ set_table_foreach(&sobj->table, mark_and_pin_key, 0);
+ }
+ else {
+ set_table_foreach(&sobj->table, mark_key, 0);
+ }
+ }
}
static void
set_free(void *ptr)
{
struct set_object *sobj = ptr;
- set_free_embedded(sobj);
- memset(&sobj->table, 0, sizeof(sobj->table));
+ set_free_embedded_table(&sobj->table);
}
static size_t
@@ -367,11 +377,10 @@ set_compact_after_delete(VALUE set)
}
static int
-set_table_insert_wb(set_table *tab, VALUE set, VALUE key, VALUE *key_addr)
+set_table_insert_wb(set_table *tab, VALUE set, VALUE key)
{
if (tab->type != &identhash && rb_obj_class(key) == rb_cString && !RB_OBJ_FROZEN(key)) {
key = rb_hash_key_str(key);
- if (key_addr) *key_addr = key;
}
int ret = set_insert(tab, (st_data_t)key);
if (ret == 0) RB_OBJ_WRITTEN(set, Qundef, key);
@@ -379,9 +388,9 @@ set_table_insert_wb(set_table *tab, VALUE set, VALUE key, VALUE *key_addr)
}
static int
-set_insert_wb(VALUE set, VALUE key, VALUE *key_addr)
+set_insert_wb(VALUE set, VALUE key)
{
- return set_table_insert_wb(RSET_TABLE(set), set, key, key_addr);
+ return set_table_insert_wb(RSET_TABLE(set), set, key);
}
static VALUE
@@ -418,12 +427,25 @@ set_s_create(int argc, VALUE *argv, VALUE klass)
int i;
for (i=0; i < argc; i++) {
- set_table_insert_wb(table, set, argv[i], NULL);
+ set_table_insert_wb(table, set, argv[i]);
}
return set;
}
+static VALUE
+set_s_inherited(VALUE klass, VALUE subclass)
+{
+ if (klass == rb_cSet) {
+ // When subclassing directly from Set, include the compatibility layer
+ rb_require("set/subclass_compatible.rb");
+ VALUE subclass_compatible = rb_const_get(klass, id_subclass_compatible);
+ rb_include_module(subclass, subclass_compatible);
+ rb_extend_object(subclass, rb_const_get(subclass_compatible, id_class_methods));
+ }
+ return Qnil;
+}
+
static void
check_set(VALUE arg)
{
@@ -456,7 +478,7 @@ static VALUE
set_initialize_without_block(RB_BLOCK_CALL_FUNC_ARGLIST(i, set))
{
VALUE element = i;
- set_insert_wb(set, element, &element);
+ set_insert_wb(set, element);
return element;
}
@@ -464,27 +486,41 @@ static VALUE
set_initialize_with_block(RB_BLOCK_CALL_FUNC_ARGLIST(i, set))
{
VALUE element = rb_yield(i);
- set_insert_wb(set, element, &element);
+ set_insert_wb(set, element);
return element;
}
/*
- * call-seq:
- * Set.new -> new_set
- * Set.new(enum) -> new_set
- * Set.new(enum) { |elem| ... } -> new_set
+ * call-seq:
+ * Set.new(object = nil) -> new_set
+ * Set.new(object = nil) {|element| ... } -> new_set
+ *
+ * Returns a new \Set object based on the given +object+,
+ * which must be an Enumerable or +nil+.
+ *
+ * With argument +object+ given as +nil+,
+ * returns a new empty \Set object:
+ *
+ * Set.new # => Set[]
+ * Set.new { fail 'Cannot happen' } # => Set[] # Block not called.
+ *
+ * With no block given and +object+ given as an Enumerable,
+ * populates the new set with the elements of +object+:
*
- * Creates a new set containing the elements of the given enumerable
- * object.
+ * Set.new(%w[ a b c ]) # => Set["a", "b", "c"]
+ * Set.new({foo: 0, bar: 1}) # => Set[[:foo, 0], [:bar, 1]]
+ * Set.new(4..10) # => Set[4, 5, 6, 7, 8, 9, 10]
+ * Set.new(Dir.new('lib')).take(5)
+ * # => [".", "..", "bundled_gems.rb", "bundler", "bundler.rb"]
+ * Set.new(File.new('doc/NEWS/NEWS-4.0.0.md')).take(3)
+ * # => ["# NEWS for Ruby 4.0.0\n", "\n", "This document is a list of user-visible feature changes\n"]
*
- * If a block is given, the elements of enum are preprocessed by the
- * given block.
+ * With a block given and +object+ given as an Enumerable,
+ * calls the block with each element of +object+;
+ * adds the block's return value to the new set:
+ *
+ * Set.new(4..10) {|i| i * 2 } # => Set[8, 10, 12, 14, 16, 18, 20]
*
- * Set.new([1, 2]) #=> #<Set: {1, 2}>
- * Set.new([1, 2, 1]) #=> #<Set: {1, 2}>
- * Set.new([1, 'c', :s]) #=> #<Set: {1, "c", :s}>
- * Set.new(1..5) #=> #<Set: {1, 2, 3, 4, 5}>
- * Set.new([1, 2, 3]) { |x| x * x } #=> #<Set: {1, 4, 9}>
*/
static VALUE
set_i_initialize(int argc, VALUE *argv, VALUE set)
@@ -505,18 +541,10 @@ set_i_initialize(int argc, VALUE *argv, VALUE set)
for (i=0; i<RARRAY_LEN(other); i++) {
VALUE key = RARRAY_AREF(other, i);
if (block_given) key = rb_yield(key);
- set_table_insert_wb(into, set, key, NULL);
+ set_table_insert_wb(into, set, key);
}
}
else {
- ID id_size = rb_intern("size");
- if (rb_obj_is_kind_of(other, rb_mEnumerable) && rb_respond_to(other, id_size)) {
- VALUE size = rb_funcall(other, id_size, 0);
- if (RB_TYPE_P(size, T_FLOAT) && RFLOAT_VALUE(size) == INFINITY) {
- rb_raise(rb_eArgError, "cannot initialize Set from an object with infinite size");
- }
- }
-
rb_block_call(other, enum_method_id(other), 0, 0,
rb_block_given_p() ? set_initialize_with_block : set_initialize_without_block,
set);
@@ -539,7 +567,7 @@ set_i_initialize_copy(VALUE set, VALUE other)
struct set_object *sobj;
TypedData_Get_Struct(set, struct set_object, &set_data_type, sobj);
- set_free_embedded(sobj);
+ set_free_embedded_table(&sobj->table);
set_copy(&sobj->table, RSET_TABLE(other));
rb_gc_writebarrier_remember(set);
@@ -588,11 +616,11 @@ set_inspect(VALUE set, VALUE dummy, int recur)
* Returns a new string containing the set entries:
*
* s = Set.new
- * s.inspect # => "#<Set: {}>"
+ * s.inspect # => "Set[]"
* s.add(1)
- * s.inspect # => "#<Set: {1}>"
+ * s.inspect # => "Set[1]"
* s.add(2)
- * s.inspect # => "#<Set: {1, 2}>"
+ * s.inspect # => "Set[1, 2]"
*
* Related: see {Methods for Converting}[rdoc-ref:Set@Methods+for+Converting].
*/
@@ -641,36 +669,19 @@ set_i_to_a(VALUE set)
/*
* call-seq:
- * to_set(klass = Set, *args, &block) -> self or new_set
- *
- * Returns self if receiver is an instance of +Set+ and no arguments or
- * block are given. Otherwise, converts the set to another with
- * <tt>klass.new(self, *args, &block)</tt>.
+ * to_set(&block) -> self or new_set
*
- * In subclasses, returns `klass.new(self, *args, &block)` unless overridden.
+ * Without a block, if +self+ is an instance of +Set+, returns +self+.
+ * Otherwise, calls <tt>Set.new(self, &block)</tt>.
*/
static VALUE
-set_i_to_set(int argc, VALUE *argv, VALUE set)
+set_i_to_set(VALUE set)
{
- VALUE klass;
-
- if (argc == 0) {
- klass = rb_cSet;
- argv = &set;
- argc = 1;
- }
- else {
- rb_warn_deprecated("passing arguments to Set#to_set", NULL);
- klass = argv[0];
- argv[0] = set;
- }
-
- if (klass == rb_cSet && rb_obj_is_instance_of(set, rb_cSet) &&
- argc == 1 && !rb_block_given_p()) {
+ if (rb_obj_is_instance_of(set, rb_cSet) && !rb_block_given_p()) {
return set;
}
- return rb_funcall_passing_block(klass, id_new, argc, argv);
+ return rb_funcall_passing_block(rb_cSet, id_new, 1, &set);
}
/*
@@ -690,12 +701,12 @@ set_i_join(int argc, VALUE *argv, VALUE set)
* call-seq:
* add(obj) -> self
*
- * Adds the given object to the set and returns self. Use `merge` to
+ * Adds the given object to the set and returns self. Use Set#merge to
* add many elements at once.
*
- * Set[1, 2].add(3) #=> #<Set: {1, 2, 3}>
- * Set[1, 2].add([3, 4]) #=> #<Set: {1, 2, [3, 4]}>
- * Set[1, 2].add(2) #=> #<Set: {1, 2}>
+ * Set[1, 2].add(3) #=> Set[1, 2, 3]
+ * Set[1, 2].add([3, 4]) #=> Set[1, 2, [3, 4]]
+ * Set[1, 2].add(2) #=> Set[1, 2]
*/
static VALUE
set_i_add(VALUE set, VALUE item)
@@ -707,7 +718,7 @@ set_i_add(VALUE set, VALUE item)
}
}
else {
- set_insert_wb(set, item, NULL);
+ set_insert_wb(set, item);
}
return set;
}
@@ -719,8 +730,8 @@ set_i_add(VALUE set, VALUE item)
* Adds the given object to the set and returns self. If the object is
* already in the set, returns nil.
*
- * Set[1, 2].add?(3) #=> #<Set: {1, 2, 3}>
- * Set[1, 2].add?([3, 4]) #=> #<Set: {1, 2, [3, 4]}>
+ * Set[1, 2].add?(3) #=> Set[1, 2, 3]
+ * Set[1, 2].add?([3, 4]) #=> Set[1, 2, [3, 4]]
* Set[1, 2].add?(2) #=> nil
*/
static VALUE
@@ -734,7 +745,7 @@ set_i_add_p(VALUE set, VALUE item)
return Qnil;
}
else {
- return set_insert_wb(set, item, NULL) ? Qnil : set;
+ return set_insert_wb(set, item) ? Qnil : set;
}
}
@@ -849,9 +860,9 @@ set_classify_i(st_data_t key, st_data_t tmp)
*
* files = Set.new(Dir.glob("*.rb"))
* hash = files.classify { |f| File.mtime(f).year }
- * hash #=> {2000 => #<Set: {"a.rb", "b.rb"}>,
- * # 2001 => #<Set: {"c.rb", "d.rb", "e.rb"}>,
- * # 2002 => #<Set: {"f.rb"}>}
+ * hash #=> {2000 => Set["a.rb", "b.rb"],
+ * # 2001 => Set["c.rb", "d.rb", "e.rb"],
+ * # 2002 => Set["f.rb"]}
*
* Returns an enumerator if no block is given.
*/
@@ -952,10 +963,10 @@ static void set_merge_enum_into(VALUE set, VALUE arg);
*
* numbers = Set[1, 3, 4, 6, 9, 10, 11]
* set = numbers.divide { |i,j| (i - j).abs == 1 }
- * set #=> #<Set: {#<Set: {1}>,
- * # #<Set: {3, 4}>,
- * # #<Set: {6}>}>
- * # #<Set: {9, 10, 11}>,
+ * set #=> Set[Set[1],
+ * # Set[3, 4],
+ * # Set[6],
+ * # Set[9, 10, 11]]
*
* Returns an enumerator if no block is given.
*/
@@ -986,9 +997,9 @@ set_clear_i(st_data_t key, st_data_t dummy)
*
* Removes all elements and returns self.
*
- * set = Set[1, 'c', :s] #=> #<Set: {1, "c", :s}>
- * set.clear #=> #<Set: {}>
- * set #=> #<Set: {}>
+ * set = Set[1, 'c', :s] #=> Set[1, "c", :s]
+ * set.clear #=> Set[]
+ * set #=> Set[]
*/
static VALUE
set_i_clear(VALUE set)
@@ -1016,7 +1027,7 @@ set_intersection_i(st_data_t key, st_data_t tmp)
{
struct set_intersection_data *data = (struct set_intersection_data *)tmp;
if (set_table_lookup(data->other, key)) {
- set_table_insert_wb(data->into, data->set, key, NULL);
+ set_table_insert_wb(data->into, data->set, key);
}
return ST_CONTINUE;
@@ -1036,8 +1047,8 @@ set_intersection_block(RB_BLOCK_CALL_FUNC_ARGLIST(i, data))
* Returns a new set containing elements common to the set and the given
* enumerable object.
*
- * Set[1, 3, 5] & Set[3, 2, 1] #=> #<Set: {3, 1}>
- * Set['a', 'b', 'z'] & ['a', 'b', 'c'] #=> #<Set: {"a", "b"}>
+ * Set[1, 3, 5] & Set[3, 2, 1] #=> Set[3, 1]
+ * Set['a', 'b', 'z'] & ['a', 'b', 'c'] #=> Set["a", "b"]
*/
static VALUE
set_i_intersection(VALUE set, VALUE other)
@@ -1112,7 +1123,7 @@ static int
set_merge_i(st_data_t key, st_data_t data)
{
struct set_merge_args *args = (struct set_merge_args *)data;
- set_table_insert_wb(args->into, args->set, key, NULL);
+ set_table_insert_wb(args->into, args->set, key);
return ST_CONTINUE;
}
@@ -1120,7 +1131,7 @@ static VALUE
set_merge_block(RB_BLOCK_CALL_FUNC_ARGLIST(key, set))
{
VALUE element = key;
- set_insert_wb(set, element, &element);
+ set_insert_wb(set, element);
return element;
}
@@ -1138,7 +1149,7 @@ set_merge_enum_into(VALUE set, VALUE arg)
long i;
set_table *into = RSET_TABLE(set);
for (i=0; i<RARRAY_LEN(arg); i++) {
- set_table_insert_wb(into, set, RARRAY_AREF(arg, i), NULL);
+ set_table_insert_wb(into, set, RARRAY_AREF(arg, i));
}
}
else {
@@ -1192,9 +1203,9 @@ set_reset_table_with_type(VALUE set, const struct st_hash_type *type)
.into = new
};
set_iter(set, set_merge_i, (st_data_t)&args);
- set_free_embedded(sobj);
+ set_free_embedded_table(&sobj->table);
memcpy(&sobj->table, new, sizeof(*new));
- free(new);
+ SIZED_FREE(new);
}
else {
sobj->table.type = type;
@@ -1264,7 +1275,7 @@ set_xor_i(st_data_t key, st_data_t data)
VALUE element = (VALUE)key;
VALUE set = (VALUE)data;
set_table *table = RSET_TABLE(set);
- if (set_table_insert_wb(table, set, element, &element)) {
+ if (set_table_insert_wb(table, set, element)) {
set_table_delete(table, &element);
}
return ST_CONTINUE;
@@ -1278,21 +1289,23 @@ set_xor_i(st_data_t key, st_data_t data)
* given enumerable object. <tt>(set ^ enum)</tt> is equivalent to
* <tt>((set | enum) - (set & enum))</tt>.
*
- * Set[1, 2] ^ Set[2, 3] #=> #<Set: {3, 1}>
- * Set[1, 'b', 'c'] ^ ['b', 'd'] #=> #<Set: {"d", 1, "c"}>
+ * Set[1, 2] ^ Set[2, 3] #=> Set[3, 1]
+ * Set[1, 'b', 'c'] ^ ['b', 'd'] #=> Set["d", 1, "c"]
*/
static VALUE
set_i_xor(VALUE set, VALUE other)
{
- VALUE new_set;
+ VALUE new_set = rb_obj_dup(set);
+
if (rb_obj_is_kind_of(other, rb_cSet)) {
- new_set = other;
+ set_iter(other, set_xor_i, (st_data_t)new_set);
}
else {
- new_set = set_s_alloc(rb_obj_class(set));
- set_merge_enum_into(new_set, other);
+ VALUE tmp = set_s_alloc(rb_cSet);
+ set_merge_enum_into(tmp, other);
+ set_iter(tmp, set_xor_i, (st_data_t)new_set);
}
- set_iter(set, set_xor_i, (st_data_t)new_set);
+
return new_set;
}
@@ -1303,8 +1316,8 @@ set_i_xor(VALUE set, VALUE other)
* Returns a new set built by merging the set and the elements of the
* given enumerable object.
*
- * Set[1, 2, 3] | Set[2, 4, 5] #=> #<Set: {1, 2, 3, 4, 5}>
- * Set[1, 5, 'z'] | (1..6) #=> #<Set: {1, 5, "z", 2, 3, 4, 6}>
+ * Set[1, 2, 3] | Set[2, 4, 5] #=> Set[1, 2, 3, 4, 5]
+ * Set[1, 5, 'z'] | (1..6) #=> Set[1, 5, "z", 2, 3, 4, 6]
*/
static VALUE
set_i_union(VALUE set, VALUE other)
@@ -1362,8 +1375,8 @@ set_i_subtract(VALUE set, VALUE other)
* Returns a new set built by duplicating the set, removing every
* element that appears in the given enumerable object.
*
- * Set[1, 3, 5] - Set[1, 5] #=> #<Set: {3}>
- * Set['a', 'b', 'z'] - ['a', 'c'] #=> #<Set: {"b", "z"}>
+ * Set[1, 3, 5] - Set[1, 5] #=> Set[3]
+ * Set['a', 'b', 'z'] - ['a', 'c'] #=> Set["b", "z"]
*/
static VALUE
set_i_difference(VALUE set, VALUE other)
@@ -1398,7 +1411,7 @@ set_i_each(VALUE set)
static int
set_collect_i(st_data_t key, st_data_t data)
{
- set_insert_wb((VALUE)data, rb_yield((VALUE)key), NULL);
+ set_insert_wb((VALUE)data, rb_yield((VALUE)key));
return ST_CONTINUE;
}
@@ -1479,9 +1492,9 @@ set_i_select(VALUE set)
* Replaces the contents of the set with the contents of the given
* enumerable object and returns self.
*
- * set = Set[1, 'c', :s] #=> #<Set: {1, "c", :s}>
- * set.replace([1, 2]) #=> #<Set: {1, 2}>
- * set #=> #<Set: {1, 2}>
+ * set = Set[1, 'c', :s] #=> Set[1, "c", :s]
+ * set.replace([1, 2]) #=> Set[1, 2]
+ * set #=> Set[1, 2]
*/
static VALUE
set_i_replace(VALUE set, VALUE other)
@@ -1757,7 +1770,7 @@ set_i_disjoint(VALUE set, VALUE other)
* set <=> other -> -1, 0, 1, or nil
*
* Returns 0 if the set are equal, -1 / 1 if the set is a
- * proper subset / superset of the given set, or or nil if
+ * proper subset / superset of the given set, or nil if
* they both have unique elements.
*/
static VALUE
@@ -1979,21 +1992,14 @@ rb_set_size(VALUE set)
/*
* Document-class: Set
*
- * Copyright (c) 2002-2024 Akinori MUSHA <knu@iDaemons.org>
- *
- * Documentation by Akinori MUSHA and Gavin Sinclair.
- *
- * All rights reserved. You can redistribute and/or modify it under the same
- * terms as Ruby.
- *
* The Set class implements a collection of unordered values with no
* duplicates. It 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`).
+ * 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
- * can be converted to Set using the `to_set` method.
+ * can be converted to Set using the +to_set+ method.
*
* Set uses a data structure similar to Hash for storage, except that
* it only has keys and no values.
@@ -2017,11 +2023,11 @@ rb_set_size(VALUE set)
*
* == Example
*
- * s1 = Set[1, 2] #=> #<Set: {1, 2}>
- * s2 = [1, 2].to_set #=> #<Set: {1, 2}>
+ * s1 = Set[1, 2] #=> Set[1, 2]
+ * s2 = [1, 2].to_set #=> Set[1, 2]
* s1 == s2 #=> true
- * s1.add("foo") #=> #<Set: {1, 2, "foo"}>
- * s1.merge([2, 6]) #=> #<Set: {1, 2, "foo", 6}>
+ * s1.add("foo") #=> Set[1, 2, "foo"]
+ * s1.merge([2, 6]) #=> Set[1, 2, "foo", 6]
* s1.subset?(s2) #=> false
* s2.subset?(s1) #=> true
*
@@ -2029,12 +2035,42 @@ rb_set_size(VALUE set)
*
* - Akinori MUSHA <knu@iDaemons.org> (current maintainer)
*
- * == What's Here
+ * == Inheriting from \Set
+ *
+ * Before Ruby 4.0 (released December 2025), \Set had a different, less
+ * efficient implementation. It was reimplemented in C, and the behavior
+ * of some of the core methods were adjusted.
+ *
+ * To keep backward compatibility, when a class is inherited from \Set,
+ * additional module +Set::SubclassCompatible+ is included, which makes
+ * the inherited class behavior, as well as internal method names,
+ * closer to what it was before Ruby 4.0.
+ *
+ * It can be easily seen, for example, in the #inspect method behavior:
+ *
+ * p Set[1, 2, 3]
+ * # prints "Set[1, 2, 3]"
+ *
+ * class MySet < Set
+ * end
+ * p MySet[1, 2, 3]
+ * # prints "#<MySet: {1, 2, 3}>", like it was in Ruby 3.4
+ *
+ * For new code, if backward compatibility is not necessary,
+ * it is recommended to instead inherit from +Set::CoreSet+, which
+ * avoids including the "compatibility" layer:
+ *
+ * class MyCoreSet < Set::CoreSet
+ * end
+ * p MyCoreSet[1, 2, 3]
+ * # prints "MyCoreSet[1, 2, 3]"
+ *
+ * == Set's methods
*
- * First, what's elsewhere. \Class \Set:
+ * First, what's elsewhere. \Class \Set:
*
- * - Inherits from {class Object}[rdoc-ref:Object@What-27s+Here].
- * - Includes {module Enumerable}[rdoc-ref:Enumerable@What-27s+Here],
+ * - Inherits from {class Object}[rdoc-ref:Object@Whats+Here].
+ * - Includes {module Enumerable}[rdoc-ref:Enumerable@Whats+Here],
* which provides dozens of additional methods.
*
* In particular, class \Set does not have many methods of its own
@@ -2043,16 +2079,15 @@ rb_set_size(VALUE set)
*
* Here, class \Set provides methods that are useful for:
*
- * - {Creating an Array}[rdoc-ref:Array@Methods+for+Creating+an+Array]
- * - {Creating a Set}[rdoc-ref:Array@Methods+for+Creating+a+Set]
- * - {Set Operations}[rdoc-ref:Array@Methods+for+Set+Operations]
- * - {Comparing}[rdoc-ref:Array@Methods+for+Comparing]
- * - {Querying}[rdoc-ref:Array@Methods+for+Querying]
- * - {Assigning}[rdoc-ref:Array@Methods+for+Assigning]
- * - {Deleting}[rdoc-ref:Array@Methods+for+Deleting]
- * - {Converting}[rdoc-ref:Array@Methods+for+Converting]
- * - {Iterating}[rdoc-ref:Array@Methods+for+Iterating]
- * - {And more....}[rdoc-ref:Array@Other+Methods]
+ * - {Creating a Set}[rdoc-ref:Set@Methods+for+Creating+a+Set]
+ * - {Set Operations}[rdoc-ref:Set@Methods+for+Set+Operations]
+ * - {Comparing}[rdoc-ref:Set@Methods+for+Comparing]
+ * - {Querying}[rdoc-ref:Set@Methods+for+Querying]
+ * - {Assigning}[rdoc-ref:Set@Methods+for+Assigning]
+ * - {Deleting}[rdoc-ref:Set@Methods+for+Deleting]
+ * - {Converting}[rdoc-ref:Set@Methods+for+Converting]
+ * - {Iterating}[rdoc-ref:Set@Methods+for+Iterating]
+ * - {And more....}[rdoc-ref:Set@Other+Methods]
*
* === Methods for Creating a \Set
*
@@ -2195,6 +2230,8 @@ Init_Set(void)
id_any_p = rb_intern_const("any?");
id_new = rb_intern_const("new");
id_i_hash = rb_intern_const("@hash");
+ id_subclass_compatible = rb_intern_const("SubclassCompatible");
+ id_class_methods = rb_intern_const("ClassMethods");
id_set_iter_lev = rb_make_internal_id();
rb_define_alloc_func(rb_cSet, set_s_alloc);
@@ -2259,11 +2296,16 @@ Init_Set(void)
rb_define_method(rb_cSet, "superset?", set_i_superset, 1);
rb_define_alias(rb_cSet, ">=", "superset?");
rb_define_method(rb_cSet, "to_a", set_i_to_a, 0);
- rb_define_method(rb_cSet, "to_set", set_i_to_set, -1);
+ rb_define_method(rb_cSet, "to_set", set_i_to_set, 0);
/* :nodoc: */
VALUE compat = rb_define_class_under(rb_cSet, "compatible", rb_cObject);
rb_marshal_define_compat(rb_cSet, compat, compat_dumper, compat_loader);
+ // Create Set::CoreSet before defining inherited, so it does not include
+ // the backwards compatibility layer.
+ rb_define_class_under(rb_cSet, "CoreSet", rb_cSet);
+ rb_define_private_method(rb_singleton_class(rb_cSet), "inherited", set_s_inherited, 1);
+
rb_provide("set.rb");
}
diff --git a/shape.c b/shape.c
index 4345654f84..7a02b23073 100644
--- a/shape.c
+++ b/shape.c
@@ -30,15 +30,34 @@
#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 MAX_SHAPE_ID (INVALID_SHAPE_ID - 1)
#define ANCESTOR_SEARCH_MAX_DEPTH 2
static ID id_object_id;
+// Should be on its own cache line
+static RUBY_ALIGNAS(128) rb_atomic_t redblack_cache_size;
+
+struct redblack_node {
+ ID key;
+ rb_shape_t *value;
+ redblack_id_t l;
+ redblack_id_t r;
+};
+typedef struct redblack_node redblack_node_t;
+
+static redblack_node_t *redblack_cache;
+
#define LEAF 0
#define BLACK 0x0
#define RED 0x1
+static inline redblack_node_t *
+redblack_node(redblack_id_t id)
+{
+ return id ? &redblack_cache[id - 1] : LEAF;
+}
+
static redblack_node_t *
redblack_left(redblack_node_t *node)
{
@@ -46,8 +65,8 @@ redblack_left(redblack_node_t *node)
return LEAF;
}
else {
- RUBY_ASSERT(node->l < rb_shape_tree.cache_size);
- redblack_node_t *left = &rb_shape_tree.shape_cache[node->l - 1];
+ RUBY_ASSERT(node->l < redblack_cache_size);
+ redblack_node_t *left = redblack_node(node->l);
return left;
}
}
@@ -59,14 +78,14 @@ redblack_right(redblack_node_t *node)
return LEAF;
}
else {
- RUBY_ASSERT(node->r < rb_shape_tree.cache_size);
- redblack_node_t *right = &rb_shape_tree.shape_cache[node->r - 1];
+ RUBY_ASSERT(node->r < redblack_cache_size);
+ redblack_node_t *right = redblack_node(node->r);
return right;
}
}
static redblack_node_t *
-redblack_find(redblack_node_t *tree, ID key)
+redblack_find0(redblack_node_t *tree, ID key)
{
if (tree == LEAF) {
return LEAF;
@@ -80,15 +99,21 @@ redblack_find(redblack_node_t *tree, ID key)
}
else {
if (key < tree->key) {
- return redblack_find(redblack_left(tree), key);
+ return redblack_find0(redblack_left(tree), key);
}
else {
- return redblack_find(redblack_right(tree), key);
+ return redblack_find0(redblack_right(tree), key);
}
}
}
}
+static redblack_node_t *
+redblack_find(redblack_id_t tree_id, ID key)
+{
+ return redblack_find0(redblack_node(tree_id), key);
+}
+
static inline rb_shape_t *
redblack_value(redblack_node_t *node)
{
@@ -118,7 +143,7 @@ redblack_id_for(redblack_node_t *node)
return 0;
}
else {
- redblack_node_t *redblack_nodes = rb_shape_tree.shape_cache;
+ redblack_node_t *redblack_nodes = redblack_cache;
redblack_id_t id = (redblack_id_t)(node - redblack_nodes);
return id + 1;
}
@@ -127,7 +152,7 @@ redblack_id_for(redblack_node_t *node)
static redblack_node_t *
redblack_new(char color, ID key, rb_shape_t *value, redblack_node_t *left, redblack_node_t *right)
{
- if (rb_shape_tree.cache_size + 1 >= REDBLACK_CACHE_SIZE) {
+ if (redblack_cache_size + 1 >= REDBLACK_CACHE_SIZE) {
// We're out of cache, just quit
return LEAF;
}
@@ -135,8 +160,8 @@ redblack_new(char color, ID key, rb_shape_t *value, redblack_node_t *left, redbl
RUBY_ASSERT(left == LEAF || left->key < key);
RUBY_ASSERT(right == LEAF || right->key > key);
- redblack_node_t *redblack_nodes = rb_shape_tree.shape_cache;
- redblack_node_t *node = &redblack_nodes[(rb_shape_tree.cache_size)++];
+ redblack_node_t *redblack_nodes = redblack_cache;
+ redblack_node_t *node = &redblack_nodes[RUBY_ATOMIC_FETCH_ADD(redblack_cache_size, 1)];
node->key = key;
node->value = (rb_shape_t *)((uintptr_t)value | color);
node->l = redblack_id_for(left);
@@ -272,34 +297,37 @@ redblack_force_black(redblack_node_t *node)
return node;
}
-static redblack_node_t *
+static redblack_id_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);
+ return redblack_id_for(redblack_force_black(root));
}
else {
- return root;
+ return redblack_id_for(root);
}
}
#endif
-rb_shape_tree_t rb_shape_tree = { 0 };
static VALUE shape_tree_obj = Qfalse;
+rb_shape_tree_t rb_shape_tree = { 0 };
+
+// Should be on its own cache line
+static RUBY_ALIGNAS(128) rb_atomic_t shape_next_id;
rb_shape_t *
rb_shape_get_root_shape(void)
{
- return rb_shape_tree.root_shape;
+ return rb_shape_tree.shape_list;
}
static void
shape_tree_mark_and_move(void *data)
{
rb_shape_t *cursor = rb_shape_get_root_shape();
- rb_shape_t *end = RSHAPE(rb_shape_tree.next_shape_id - 1);
+ rb_shape_t *end = RSHAPE(shape_next_id - 1);
while (cursor <= end) {
if (cursor->edges && !SINGLE_CHILD_P(cursor->edges)) {
rb_gc_mark_and_move(&cursor->edges);
@@ -308,10 +336,25 @@ shape_tree_mark_and_move(void *data)
}
}
+size_t
+rb_shapes_cache_size(void)
+{
+ return redblack_cache ? redblack_cache_size : 0;
+}
+
+size_t
+rb_shapes_count(void)
+{
+ return (size_t)RUBY_ATOMIC_LOAD(shape_next_id);
+}
+
static size_t
shape_tree_memsize(const void *data)
{
- return rb_shape_tree.cache_size * sizeof(redblack_node_t);
+ if (redblack_cache) {
+ return redblack_cache_size * sizeof(redblack_node_t);
+ }
+ return 0;
}
static const rb_data_type_t shape_tree_type = {
@@ -331,34 +374,26 @@ static const rb_data_type_t shape_tree_type = {
*/
static inline shape_id_t
-raw_shape_id(rb_shape_t *shape)
+SHAPE_OFFSET(rb_shape_t *shape)
{
RUBY_ASSERT(shape);
return (shape_id_t)(shape - rb_shape_tree.shape_list);
}
static inline shape_id_t
-shape_id(rb_shape_t *shape, shape_id_t previous_shape_id)
+SHAPE_ID(rb_shape_t *shape, shape_id_t previous_shape_id)
{
RUBY_ASSERT(shape);
- shape_id_t raw_id = (shape_id_t)(shape - rb_shape_tree.shape_list);
- return raw_id | (previous_shape_id & SHAPE_ID_FLAGS_MASK);
-}
-
-#if RUBY_DEBUG
-static inline bool
-shape_frozen_p(shape_id_t shape_id)
-{
- return shape_id & SHAPE_ID_FL_FROZEN;
+ shape_id_t offset = (shape_id_t)(shape - rb_shape_tree.shape_list);
+ return offset | RSHAPE_FLAGS(previous_shape_id);
}
-#endif
void
rb_shape_each_shape_id(each_shape_callback callback, void *data)
{
rb_shape_t *start = rb_shape_get_root_shape();
rb_shape_t *cursor = start;
- rb_shape_t *end = RSHAPE(rb_shapes_count());
+ rb_shape_t *end = RSHAPE(RUBY_ATOMIC_LOAD(shape_next_id));
while (cursor < end) {
callback((shape_id_t)(cursor - start), data);
cursor += 1;
@@ -374,10 +409,14 @@ rb_obj_shape_id(VALUE obj)
if (BUILTIN_TYPE(obj) == T_CLASS || BUILTIN_TYPE(obj) == T_MODULE) {
VALUE fields_obj = RCLASS_WRITABLE_FIELDS_OBJ(obj);
+ shape_id_t base = ROOT_SHAPE_ID;
if (fields_obj) {
- return RBASIC_SHAPE_ID(fields_obj);
+ // Remove the layout from the fields object. We want to
+ // combine the shape of the fields object with the layout of the
+ // class / module object.
+ base = RBASIC_SHAPE_ID(fields_obj) & ~SHAPE_ID_LAYOUT_MASK;
}
- return ROOT_SHAPE_ID;
+ return rb_shape_layout(RBASIC_SHAPE_ID(obj)) | base;
}
return RBASIC_SHAPE_ID(obj);
}
@@ -388,9 +427,9 @@ rb_shape_depth(shape_id_t shape_id)
size_t depth = 1;
rb_shape_t *shape = RSHAPE(shape_id);
- while (shape->parent_id != INVALID_SHAPE_ID) {
+ while (shape->parent_offset != INVALID_SHAPE_ID) {
depth++;
- shape = RSHAPE(shape->parent_id);
+ shape = RSHAPE(shape->parent_offset);
}
return depth;
@@ -402,25 +441,25 @@ shape_alloc(void)
shape_id_t current, new_id;
do {
- current = RUBY_ATOMIC_LOAD(rb_shape_tree.next_shape_id);
+ current = RUBY_ATOMIC_LOAD(shape_next_id);
if (current > MAX_SHAPE_ID) {
return NULL; // Out of shapes
}
new_id = current + 1;
- } while (current != RUBY_ATOMIC_CAS(rb_shape_tree.next_shape_id, current, new_id));
+ } while (current != RUBY_ATOMIC_CAS(shape_next_id, current, new_id));
return &rb_shape_tree.shape_list[current];
}
static rb_shape_t *
-rb_shape_alloc_with_parent_id(ID edge_name, shape_id_t parent_id)
+rb_shape_alloc_with_parent_offset(ID edge_name, shape_id_t parent_offset)
{
rb_shape_t *shape = shape_alloc();
if (!shape) return NULL;
shape->edge_name = edge_name;
shape->next_field_index = 0;
- shape->parent_id = parent_id;
+ shape->parent_offset = parent_offset;
shape->edges = 0;
return shape;
@@ -429,7 +468,7 @@ rb_shape_alloc_with_parent_id(ID edge_name, shape_id_t parent_id)
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, raw_shape_id(parent));
+ rb_shape_t *shape = rb_shape_alloc_with_parent_offset(edge_name, SHAPE_OFFSET(parent));
if (!shape) return NULL;
shape->type = (uint8_t)type;
@@ -442,13 +481,11 @@ rb_shape_alloc(ID edge_name, rb_shape_t *parent, enum shape_type type)
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(RSHAPE(shape->parent_id));
+ if (!(shape->ancestor_index || shape->parent_offset == INVALID_SHAPE_ID)) {
+ redblack_node_t *parent_index_node = redblack_cache_ancestors(RSHAPE(shape->parent_offset));
if (shape->type == SHAPE_IVAR) {
- shape->ancestor_index = redblack_insert(parent_index, shape->edge_name, shape);
+ shape->ancestor_index = redblack_insert(parent_index_node, shape->edge_name, shape);
#if RUBY_DEBUG
if (shape->ancestor_index) {
@@ -459,11 +496,11 @@ redblack_cache_ancestors(rb_shape_t *shape)
#endif
}
else {
- shape->ancestor_index = parent_index;
+ shape->ancestor_index = redblack_id_for(parent_index_node);
}
}
- return shape->ancestor_index;
+ return redblack_node(shape->ancestor_index);
}
#else
static redblack_node_t *
@@ -477,17 +514,16 @@ static attr_index_t
shape_grow_capa(attr_index_t current_capa)
{
const attr_index_t *capacities = rb_shape_tree.capacities;
+ size_t heaps_count = rb_shape_tree.heaps_count;
// First try to use the next size that will be embeddable in a larger object slot.
- attr_index_t capa;
- while ((capa = *capacities)) {
+ for (size_t i = 0; i < heaps_count; i++) {
+ attr_index_t capa = capacities[i];
if (capa > current_capa) {
return capa;
}
- capacities++;
}
-
- return (attr_index_t)rb_malloc_grow_capa(current_capa, sizeof(VALUE));
+ return capacities[rb_shape_tree.heaps_count - 1];
}
static rb_shape_t *
@@ -503,6 +539,7 @@ rb_shape_alloc_new_child(ID id, rb_shape_t *shape, enum shape_type shape_type)
RUBY_ASSERT(shape->next_field_index == shape->capacity);
new_shape->capacity = shape_grow_capa(shape->capacity);
}
+
RUBY_ASSERT(new_shape->capacity > shape->next_field_index);
new_shape->next_field_index = shape->next_field_index + 1;
if (new_shape->next_field_index > ANCESTOR_CACHE_THRESHOLD) {
@@ -625,7 +662,7 @@ get_next_shape_internal(rb_shape_t *shape, ID id, enum shape_type shape_type, bo
// 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.
+ // we return COMPLEX_SHAPE.
if (!new_variations_allowed || rb_shapes_count() > MAX_SHAPE_ID) {
res = NULL;
}
@@ -656,64 +693,19 @@ get_next_shape_internal(rb_shape_t *shape, ID id, enum shape_type shape_type, bo
return res;
}
-static rb_shape_t *
-remove_shape_recursive(rb_shape_t *shape, ID id, rb_shape_t **removed_shape)
-{
- if (shape->parent_id == INVALID_SHAPE_ID) {
- // We've hit the top of the shape tree and couldn't find the
- // IV we wanted to remove, so return NULL
- *removed_shape = NULL;
- return NULL;
- }
- else {
- if (shape->type == SHAPE_IVAR && shape->edge_name == id) {
- *removed_shape = shape;
-
- return RSHAPE(shape->parent_id);
- }
- else {
- // This isn't the IV we want to remove, keep walking up.
- rb_shape_t *new_parent = remove_shape_recursive(RSHAPE(shape->parent_id), id, removed_shape);
-
- // We found a new parent. Create a child of the new parent that
- // has the same attributes as this shape.
- if (new_parent) {
- bool dont_care;
- rb_shape_t *new_child = get_next_shape_internal(new_parent, shape->edge_name, shape->type, &dont_care, true);
- RUBY_ASSERT(!new_child || new_child->capacity <= shape->capacity);
- return new_child;
- }
- else {
- // We went all the way to the top of the shape tree and couldn't
- // find an IV to remove so return NULL.
- return NULL;
- }
- }
- }
-}
-
-static inline shape_id_t transition_complex(shape_id_t shape_id);
-
-static shape_id_t
-shape_transition_object_id(shape_id_t original_shape_id)
+shape_id_t
+rb_shape_transition_object_id(shape_id_t original_shape_id)
{
RUBY_ASSERT(!rb_shape_has_object_id(original_shape_id));
bool dont_care;
rb_shape_t *shape = get_next_shape_internal(RSHAPE(original_shape_id), id_object_id, SHAPE_OBJ_ID, &dont_care, true);
if (!shape) {
- shape = RSHAPE(ROOT_SHAPE_WITH_OBJ_ID);
- return transition_complex(shape_id(shape, original_shape_id) | SHAPE_ID_FL_HAS_OBJECT_ID);
+ return rb_shape_layout(original_shape_id) | ROOT_COMPLEX_WITH_OBJ_ID | RSHAPE_FLAGS(original_shape_id);
}
RUBY_ASSERT(shape);
- return shape_id(shape, original_shape_id) | SHAPE_ID_FL_HAS_OBJECT_ID;
-}
-
-shape_id_t
-rb_shape_transition_object_id(VALUE obj)
-{
- return shape_transition_object_id(RBASIC_SHAPE_ID(obj));
+ return SHAPE_ID(shape, original_shape_id) | SHAPE_ID_FL_HAS_OBJECT_ID;
}
shape_id_t
@@ -723,96 +715,13 @@ rb_shape_object_id(shape_id_t original_shape_id)
rb_shape_t *shape = RSHAPE(original_shape_id);
while (shape->type != SHAPE_OBJ_ID) {
- if (UNLIKELY(shape->parent_id == INVALID_SHAPE_ID)) {
+ if (UNLIKELY(shape->parent_offset == INVALID_SHAPE_ID)) {
rb_bug("Missing object_id in shape tree");
}
- shape = RSHAPE(shape->parent_id);
- }
-
- return shape_id(shape, original_shape_id) | SHAPE_ID_FL_HAS_OBJECT_ID;
-}
-
-static inline shape_id_t
-transition_complex(shape_id_t shape_id)
-{
- uint8_t heap_index = rb_shape_heap_index(shape_id);
- shape_id_t next_shape_id;
-
- if (heap_index) {
- next_shape_id = rb_shape_root(heap_index - 1) | SHAPE_ID_FL_TOO_COMPLEX;
- if (rb_shape_has_object_id(shape_id)) {
- next_shape_id = shape_transition_object_id(next_shape_id);
- }
- }
- else {
- if (rb_shape_has_object_id(shape_id)) {
- next_shape_id = ROOT_TOO_COMPLEX_WITH_OBJ_ID | (shape_id & SHAPE_ID_FLAGS_MASK);
- }
- else {
- next_shape_id = ROOT_TOO_COMPLEX_SHAPE_ID | (shape_id & SHAPE_ID_FLAGS_MASK);
- }
+ shape = RSHAPE(shape->parent_offset);
}
- RUBY_ASSERT(rb_shape_has_object_id(shape_id) == rb_shape_has_object_id(next_shape_id));
-
- return next_shape_id;
-}
-
-shape_id_t
-rb_shape_transition_remove_ivar(VALUE obj, ID id, shape_id_t *removed_shape_id)
-{
- shape_id_t original_shape_id = RBASIC_SHAPE_ID(obj);
-
- RUBY_ASSERT(!rb_shape_too_complex_p(original_shape_id));
- RUBY_ASSERT(!shape_frozen_p(original_shape_id));
-
- rb_shape_t *removed_shape = NULL;
- rb_shape_t *new_shape = remove_shape_recursive(RSHAPE(original_shape_id), id, &removed_shape);
-
- if (removed_shape) {
- *removed_shape_id = raw_shape_id(removed_shape);
- }
-
- if (new_shape) {
- return shape_id(new_shape, original_shape_id);
- }
- else if (removed_shape) {
- // We found the shape to remove, but couldn't create a new variation.
- // We must transition to TOO_COMPLEX.
- shape_id_t next_shape_id = transition_complex(original_shape_id);
- RUBY_ASSERT(rb_shape_has_object_id(next_shape_id) == rb_shape_has_object_id(original_shape_id));
- return next_shape_id;
- }
- return original_shape_id;
-}
-
-shape_id_t
-rb_shape_transition_frozen(VALUE obj)
-{
- RUBY_ASSERT(RB_OBJ_FROZEN(obj));
-
- shape_id_t shape_id = rb_obj_shape_id(obj);
- return shape_id | SHAPE_ID_FL_FROZEN;
-}
-
-shape_id_t
-rb_shape_transition_complex(VALUE obj)
-{
- return transition_complex(RBASIC_SHAPE_ID(obj));
-}
-
-shape_id_t
-rb_shape_transition_heap(VALUE obj, size_t heap_index)
-{
- return (RBASIC_SHAPE_ID(obj) & (~SHAPE_ID_HEAP_INDEX_MASK)) | rb_shape_root(heap_index);
-}
-
-void
-rb_set_namespaced_class_shape_id(VALUE obj, shape_id_t shape_id)
-{
- RBASIC_SET_SHAPE_ID(RCLASS_WRITABLE_ENSURE_FIELDS_OBJ(obj), shape_id);
- // FIXME: How to do multi-shape?
- RBASIC_SET_SHAPE_ID(obj, shape_id);
+ return SHAPE_ID(shape, original_shape_id) | SHAPE_ID_FL_HAS_OBJECT_ID;
}
/*
@@ -835,13 +744,13 @@ rb_shape_get_next_iv_shape(shape_id_t shape_id, ID id)
if (!next_shape) {
return INVALID_SHAPE_ID;
}
- return raw_shape_id(next_shape);
+ return SHAPE_OFFSET(next_shape);
}
static bool
shape_get_iv_index(rb_shape_t *shape, ID id, attr_index_t *value)
{
- while (shape->parent_id != INVALID_SHAPE_ID) {
+ while (shape->parent_offset != INVALID_SHAPE_ID) {
if (shape->edge_name == id) {
enum shape_type shape_type;
shape_type = (enum shape_type)shape->type;
@@ -858,14 +767,14 @@ shape_get_iv_index(rb_shape_t *shape, ID id, attr_index_t *value)
}
}
- shape = RSHAPE(shape->parent_id);
+ shape = RSHAPE(shape->parent_offset);
}
return false;
}
static inline rb_shape_t *
-shape_get_next(rb_shape_t *shape, VALUE obj, ID id, bool emit_warnings)
+shape_get_next(rb_shape_t *shape, enum shape_type shape_type, VALUE klass, ID id, bool emit_warnings)
{
RUBY_ASSERT(!is_instance_id(id) || RTEST(rb_sym2str(ID2SYM(id))));
@@ -876,34 +785,22 @@ shape_get_next(rb_shape_t *shape, VALUE obj, ID id, bool emit_warnings)
}
#endif
- VALUE klass;
- if (IMEMO_TYPE_P(obj, imemo_fields)) {
- VALUE owner = rb_imemo_fields_owner(obj);
- switch (BUILTIN_TYPE(owner)) {
- case T_CLASS:
- case T_MODULE:
- klass = rb_singleton_class(owner);
- break;
- default:
- klass = rb_obj_class(owner);
- break;
- }
- }
- else {
- klass = rb_obj_class(obj);
+ RUBY_ASSERT(rb_shape_tree.max_capacity > 0);
+ if (UNLIKELY(shape->next_field_index >= rb_shape_tree.max_capacity)) {
+ return NULL;
}
bool allow_new_shape = RCLASS_VARIATION_COUNT(klass) < SHAPE_MAX_VARIATIONS;
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_type, &variation_created, allow_new_shape);
if (!new_shape) {
- // We could create a new variation, transitioning to TOO_COMPLEX.
+ // We could create a new variation, transitioning to COMPLEX.
return NULL;
}
// Check if we should update max_iv_count on the object's class
- if (obj != klass && new_shape->next_field_index > RCLASS_MAX_IV_COUNT(klass)) {
+ if (new_shape->next_field_index > RCLASS_MAX_IV_COUNT(klass) && !RCLASS_EXPECT_NO_IVAR(klass)) {
RCLASS_SET_MAX_IV_COUNT(klass, new_shape->next_field_index);
}
@@ -926,33 +823,121 @@ shape_get_next(rb_shape_t *shape, VALUE obj, ID id, bool emit_warnings)
return new_shape;
}
+static VALUE
+obj_get_owner_class(VALUE obj)
+{
+ VALUE klass;
+ if (IMEMO_TYPE_P(obj, imemo_fields)) {
+ VALUE owner = rb_imemo_fields_owner(obj);
+ switch (BUILTIN_TYPE(owner)) {
+ case T_CLASS:
+ case T_MODULE:
+ klass = rb_singleton_class(owner);
+ break;
+ default:
+ klass = rb_obj_class(owner);
+ break;
+ }
+ }
+ else {
+ klass = rb_obj_class(obj);
+ }
+ return klass;
+}
+
+static rb_shape_t *
+remove_shape_recursive(VALUE obj, rb_shape_t *shape, ID id, rb_shape_t **removed_shape)
+{
+ if (shape->parent_offset == INVALID_SHAPE_ID) {
+ // We've hit the top of the shape tree and couldn't find the
+ // IV we wanted to remove, so return NULL
+ *removed_shape = NULL;
+ return NULL;
+ }
+ else {
+ if (shape->type == SHAPE_IVAR && shape->edge_name == id) {
+ *removed_shape = shape;
+
+ return RSHAPE(shape->parent_offset);
+ }
+ else {
+ // This isn't the IV we want to remove, keep walking up.
+ rb_shape_t *new_parent = remove_shape_recursive(obj, RSHAPE(shape->parent_offset), id, removed_shape);
+
+ // We found a new parent. Create a child of the new parent that
+ // has the same attributes as this shape.
+ if (new_parent) {
+ VALUE klass = obj_get_owner_class(obj);
+ rb_shape_t *new_child = shape_get_next(new_parent, shape->type, klass, shape->edge_name, true);
+ RUBY_ASSERT(!new_child || new_child->capacity <= shape->capacity);
+ return new_child;
+ }
+ else {
+ // We went all the way to the top of the shape tree and couldn't
+ // find an IV to remove so return NULL.
+ return NULL;
+ }
+ }
+ }
+}
+
shape_id_t
-rb_shape_transition_add_ivar(VALUE obj, ID id)
+rb_obj_shape_transition_remove_ivar(VALUE obj, ID id, shape_id_t *removed_shape_id)
{
shape_id_t original_shape_id = RBASIC_SHAPE_ID(obj);
- RUBY_ASSERT(!shape_frozen_p(original_shape_id));
+ RUBY_ASSERT(!rb_shape_frozen_p(original_shape_id));
- rb_shape_t *next_shape = shape_get_next(RSHAPE(original_shape_id), obj, id, true);
+ if (rb_shape_complex_p(original_shape_id)) {
+ return original_shape_id;
+ }
+
+ rb_shape_t *removed_shape = NULL;
+ rb_shape_t *new_shape = remove_shape_recursive(obj, RSHAPE(original_shape_id), id, &removed_shape);
+
+ if (removed_shape) {
+ *removed_shape_id = SHAPE_OFFSET(removed_shape);
+ }
+
+ if (new_shape) {
+ return SHAPE_ID(new_shape, original_shape_id);
+ }
+ else if (removed_shape) {
+ // We found the shape to remove, but couldn't create a new variation.
+ // We must transition to COMPLEX.
+ shape_id_t next_shape_id = rb_shape_transition_complex(original_shape_id);
+ RUBY_ASSERT(rb_shape_has_object_id(next_shape_id) == rb_shape_has_object_id(original_shape_id));
+ return next_shape_id;
+ }
+ return original_shape_id;
+}
+
+shape_id_t
+rb_obj_shape_transition_add_ivar(VALUE obj, ID id)
+{
+ shape_id_t original_shape_id = RBASIC_SHAPE_ID(obj);
+ RUBY_ASSERT(!rb_shape_frozen_p(original_shape_id));
+
+ VALUE klass = obj_get_owner_class(obj);
+ rb_shape_t *next_shape = shape_get_next(RSHAPE(original_shape_id), SHAPE_IVAR, klass, id, true);
if (next_shape) {
- return shape_id(next_shape, original_shape_id);
+ return SHAPE_ID(next_shape, original_shape_id);
}
else {
- return transition_complex(original_shape_id);
+ return rb_shape_transition_complex(original_shape_id);
}
}
shape_id_t
-rb_shape_transition_add_ivar_no_warnings(VALUE obj, ID id)
+rb_shape_transition_add_ivar_no_warnings(shape_id_t original_shape_id, ID id, VALUE klass)
{
- shape_id_t original_shape_id = RBASIC_SHAPE_ID(obj);
- RUBY_ASSERT(!shape_frozen_p(original_shape_id));
+ RUBY_ASSERT(!rb_shape_frozen_p(original_shape_id));
- rb_shape_t *next_shape = shape_get_next(RSHAPE(original_shape_id), obj, id, false);
+ rb_shape_t *next_shape = shape_get_next(RSHAPE(original_shape_id), SHAPE_IVAR, klass, id, false);
if (next_shape) {
- return shape_id(next_shape, original_shape_id);
+ return SHAPE_ID(next_shape, original_shape_id);
}
else {
- return transition_complex(original_shape_id);
+ return rb_shape_transition_complex(original_shape_id);
}
}
@@ -983,23 +968,23 @@ rb_shape_get_iv_index_with_hint(shape_id_t shape_id, ID id, attr_index_t *value,
while (depth > 0 && shape->next_field_index > index_hint) {
while (shape_hint->next_field_index > shape->next_field_index) {
- shape_hint = RSHAPE(shape_hint->parent_id);
+ shape_hint = RSHAPE(shape_hint->parent_offset);
}
if (shape_hint == shape) {
// We've found a common ancestor so use the index hint
*value = index_hint;
- *shape_id_hint = raw_shape_id(shape);
+ *shape_id_hint = SHAPE_OFFSET(shape);
return true;
}
if (shape->edge_name == id) {
// We found the matching id before a common ancestor
*value = shape->next_field_index - 1;
- *shape_id_hint = raw_shape_id(shape);
+ *shape_id_hint = SHAPE_OFFSET(shape);
return true;
}
- shape = RSHAPE(shape->parent_id);
+ shape = RSHAPE(shape->parent_offset);
depth--;
}
@@ -1030,14 +1015,14 @@ shape_cache_find_ivar(rb_shape_t *shape, ID id, rb_shape_t **ivar_shape)
static bool
shape_find_ivar(rb_shape_t *shape, ID id, rb_shape_t **ivar_shape)
{
- while (shape->parent_id != INVALID_SHAPE_ID) {
+ while (shape->parent_offset != INVALID_SHAPE_ID) {
if (shape->edge_name == id) {
RUBY_ASSERT(shape->type == SHAPE_IVAR);
*ivar_shape = shape;
return true;
}
- shape = RSHAPE(shape->parent_id);
+ shape = RSHAPE(shape->parent_offset);
}
return false;
@@ -1046,7 +1031,7 @@ shape_find_ivar(rb_shape_t *shape, ID id, rb_shape_t **ivar_shape)
bool
rb_shape_find_ivar(shape_id_t current_shape_id, ID id, shape_id_t *ivar_shape_id)
{
- RUBY_ASSERT(!rb_shape_too_complex_p(current_shape_id));
+ RUBY_ASSERT(!rb_shape_complex_p(current_shape_id));
rb_shape_t *shape = RSHAPE(current_shape_id);
rb_shape_t *ivar_shape;
@@ -1063,7 +1048,7 @@ rb_shape_find_ivar(shape_id_t current_shape_id, ID id, shape_id_t *ivar_shape_id
}
}
- *ivar_shape_id = shape_id(ivar_shape, current_shape_id);
+ *ivar_shape_id = SHAPE_ID(ivar_shape, current_shape_id);
return true;
}
@@ -1073,7 +1058,7 @@ rb_shape_get_iv_index(shape_id_t shape_id, ID id, attr_index_t *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_too_complex_p(shape_id));
+ RUBY_ASSERT(!rb_shape_complex_p(shape_id));
shape_id_t ivar_shape_id;
if (rb_shape_find_ivar(shape_id, id, &ivar_shape_id)) {
@@ -1089,9 +1074,8 @@ rb_shape_id_offset(void)
return sizeof(uintptr_t) - SHAPE_ID_NUM_BITS / sizeof(uintptr_t);
}
-// Rebuild a similar shape with the same ivars but starting from
-// a different SHAPE_T_OBJECT, and don't cary over non-canonical transitions
-// such as SHAPE_OBJ_ID.
+// Rebuild a similar shape with the same ivars but without "non-canonical"
+// edges such as SHAPE_OBJ_ID.
static rb_shape_t *
shape_rebuild(rb_shape_t *initial_shape, rb_shape_t *dest_shape)
{
@@ -1100,7 +1084,7 @@ shape_rebuild(rb_shape_t *initial_shape, rb_shape_t *dest_shape)
RUBY_ASSERT(initial_shape->type == SHAPE_ROOT);
if (dest_shape->type != initial_shape->type) {
- midway_shape = shape_rebuild(initial_shape, RSHAPE(dest_shape->parent_id));
+ midway_shape = shape_rebuild(initial_shape, RSHAPE(dest_shape->parent_offset));
if (UNLIKELY(!midway_shape)) {
return NULL;
}
@@ -1126,16 +1110,25 @@ shape_rebuild(rb_shape_t *initial_shape, rb_shape_t *dest_shape)
shape_id_t
rb_shape_rebuild(shape_id_t initial_shape_id, shape_id_t dest_shape_id)
{
- RUBY_ASSERT(!rb_shape_too_complex_p(initial_shape_id));
- RUBY_ASSERT(!rb_shape_too_complex_p(dest_shape_id));
+ RUBY_ASSERT(!rb_shape_complex_p(initial_shape_id));
+ RUBY_ASSERT(!rb_shape_complex_p(dest_shape_id));
- rb_shape_t *next_shape = shape_rebuild(RSHAPE(initial_shape_id), RSHAPE(dest_shape_id));
- if (next_shape) {
- return shape_id(next_shape, initial_shape_id);
+ shape_id_t next_shape_id;
+ // The shape has a SHAPE_OBJ_ID edge, it needs to be rebuilt.
+ if (dest_shape_id & SHAPE_ID_FL_HAS_OBJECT_ID) {
+ rb_shape_t *next_shape = shape_rebuild(RSHAPE(initial_shape_id), RSHAPE(dest_shape_id));
+ if (next_shape) {
+ next_shape_id = SHAPE_ID(next_shape, initial_shape_id & ~SHAPE_ID_FL_NON_CANONICAL_MASK);
+ }
+ else {
+ return rb_shape_transition_complex(initial_shape_id | (dest_shape_id & ~SHAPE_ID_FL_NON_CANONICAL_MASK));
+ }
}
else {
- return transition_complex(initial_shape_id | (dest_shape_id & SHAPE_ID_FL_HAS_OBJECT_ID));
+ // Happy path, we have nothing to do other than change the flags.
+ next_shape_id = RSHAPE_OFFSET(dest_shape_id) | RSHAPE_FLAGS(initial_shape_id);
}
+ return next_shape_id;
}
void
@@ -1154,18 +1147,18 @@ rb_shape_copy_fields(VALUE dest, VALUE *dest_buf, shape_id_t dest_shape_id, VALU
}
}
else {
- while (src_shape->parent_id != INVALID_SHAPE_ID) {
+ while (src_shape->parent_offset != INVALID_SHAPE_ID) {
if (src_shape->type == SHAPE_IVAR) {
while (dest_shape->edge_name != src_shape->edge_name) {
- if (UNLIKELY(dest_shape->parent_id == INVALID_SHAPE_ID)) {
+ if (UNLIKELY(dest_shape->parent_offset == INVALID_SHAPE_ID)) {
rb_bug("Lost field %s", rb_id2name(src_shape->edge_name));
}
- dest_shape = RSHAPE(dest_shape->parent_id);
+ dest_shape = RSHAPE(dest_shape->parent_offset);
}
RB_OBJ_WRITE(dest, &dest_buf[dest_shape->next_field_index - 1], src_buf[src_shape->next_field_index - 1]);
}
- src_shape = RSHAPE(src_shape->parent_id);
+ src_shape = RSHAPE(src_shape->parent_offset);
}
}
}
@@ -1173,13 +1166,13 @@ rb_shape_copy_fields(VALUE dest, VALUE *dest_buf, shape_id_t dest_shape_id, VALU
void
rb_shape_copy_complex_ivars(VALUE dest, VALUE obj, shape_id_t src_shape_id, st_table *fields_table)
{
- // obj is TOO_COMPLEX so we can copy its iv_hash
+ // obj is COMPLEX so we can copy its iv_hash
st_table *table = st_copy(fields_table);
if (rb_shape_has_object_id(src_shape_id)) {
st_data_t id = (st_data_t)id_object_id;
st_delete(table, &id, NULL);
}
- rb_obj_init_too_complex(dest, table);
+ rb_obj_init_complex(dest, table);
rb_gc_writebarrier_remember(dest);
}
@@ -1213,16 +1206,16 @@ rb_shape_memsize(shape_id_t shape_id)
bool
rb_shape_foreach_field(shape_id_t initial_shape_id, rb_shape_foreach_transition_callback func, void *data)
{
- RUBY_ASSERT(!rb_shape_too_complex_p(initial_shape_id));
+ RUBY_ASSERT(!rb_shape_complex_p(initial_shape_id));
rb_shape_t *shape = RSHAPE(initial_shape_id);
if (shape->type == SHAPE_ROOT) {
return true;
}
- shape_id_t parent_id = shape_id(RSHAPE(shape->parent_id), initial_shape_id);
- if (rb_shape_foreach_field(parent_id, func, data)) {
- switch (func(shape_id(shape, initial_shape_id), data)) {
+ shape_id_t parent_offset = SHAPE_ID(RSHAPE(shape->parent_offset), initial_shape_id);
+ if (rb_shape_foreach_field(parent_offset, func, data)) {
+ switch (func(SHAPE_ID(shape, initial_shape_id), data)) {
case ST_STOP:
return false;
case ST_CHECK:
@@ -1236,6 +1229,37 @@ rb_shape_foreach_field(shape_id_t initial_shape_id, rb_shape_foreach_transition_
}
#if RUBY_DEBUG
+/*
+ * Get the layout of this object. The "layout" indicates what strategy
+ * we should use for fetching instance variables from `obj`. It's based
+ * on the C struct layout for each particular object.
+ *
+ * TODO: make Struct have a similar layout to RDATA
+ */
+static shape_id_t
+rb_shape_expected_layout(VALUE obj)
+{
+ switch (BUILTIN_TYPE(obj)) {
+ case T_OBJECT:
+ return SHAPE_ID_LAYOUT_ROBJECT;
+ case T_CLASS:
+ case T_MODULE:
+ if (FL_TEST_RAW(obj, RCLASS_BOXABLE)) {
+ return SHAPE_ID_LAYOUT_OTHER;
+ }
+ return SHAPE_ID_LAYOUT_RCLASS;
+ case T_DATA:
+ return SHAPE_ID_LAYOUT_RDATA;
+ case T_IMEMO:
+ if (IMEMO_TYPE_P(obj, imemo_fields)) {
+ return SHAPE_ID_LAYOUT_ROBJECT;
+ }
+ return SHAPE_ID_LAYOUT_OTHER;
+ default:
+ return SHAPE_ID_LAYOUT_OTHER;
+ }
+}
+
bool
rb_shape_verify_consistency(VALUE obj, shape_id_t shape_id)
{
@@ -1243,33 +1267,47 @@ rb_shape_verify_consistency(VALUE obj, shape_id_t shape_id)
rb_bug("Can't set INVALID_SHAPE_ID on an object");
}
+ shape_id_t actual_layout = rb_shape_layout(rb_obj_shape_id(obj));
+ shape_id_t expected_layout = rb_shape_expected_layout(obj);
+ if (actual_layout != expected_layout) {
+ rb_bug("shape_id layout mismatch: expected=%x actual=%x shape_id=%u obj=%s",
+ expected_layout, actual_layout, shape_id, rb_obj_info(obj));
+ }
+
+ if (shape_id == ROOT_SHAPE_ID) {
+ return true;
+ }
+
rb_shape_t *shape = RSHAPE(shape_id);
bool has_object_id = false;
- while (shape->parent_id != INVALID_SHAPE_ID) {
+ while (shape->parent_offset != INVALID_SHAPE_ID) {
if (shape->type == SHAPE_OBJ_ID) {
has_object_id = true;
break;
}
- shape = RSHAPE(shape->parent_id);
+ shape = RSHAPE(shape->parent_offset);
}
if (rb_shape_has_object_id(shape_id)) {
if (!has_object_id) {
- rb_p(obj);
rb_bug("shape_id claim having obj_id but doesn't shape_id=%u, obj=%s", shape_id, rb_obj_info(obj));
}
}
else {
if (has_object_id) {
- rb_p(obj);
rb_bug("shape_id claim not having obj_id but it does shape_id=%u, obj=%s", shape_id, rb_obj_info(obj));
}
}
// Make sure SHAPE_ID_HAS_IVAR_MASK is valid.
- if (rb_shape_too_complex_p(shape_id)) {
+ if (rb_shape_complex_p(shape_id)) {
RUBY_ASSERT(shape_id & SHAPE_ID_HAS_IVAR_MASK);
+
+ // Ensure complex object don't appear as embedded
+ if (RB_TYPE_P(obj, T_OBJECT) || IMEMO_TYPE_P(obj, imemo_fields)) {
+ RUBY_ASSERT(FL_TEST_RAW(obj, ROBJECT_HEAP));
+ }
}
else {
attr_index_t ivar_count = RSHAPE_LEN(shape_id);
@@ -1311,10 +1349,10 @@ rb_shape_verify_consistency(VALUE obj, shape_id_t shape_id)
*/
static VALUE
-shape_too_complex(VALUE self)
+shape_complex(VALUE self)
{
shape_id_t shape_id = NUM2INT(rb_struct_getmember(self, rb_intern("id")));
- return RBOOL(rb_shape_too_complex_p(shape_id));
+ return RBOOL(rb_shape_complex_p(shape_id));
}
static VALUE
@@ -1332,6 +1370,25 @@ shape_has_object_id_p(VALUE self)
}
static VALUE
+shape_layout(VALUE self)
+{
+ shape_id_t shape_id = NUM2UINT(rb_struct_getmember(self, rb_intern("id")));
+
+ switch (rb_shape_layout(shape_id)) {
+ case SHAPE_ID_LAYOUT_ROBJECT:
+ return ID2SYM(rb_intern("robject"));
+ case SHAPE_ID_LAYOUT_RCLASS:
+ return ID2SYM(rb_intern("rclass"));
+ case SHAPE_ID_LAYOUT_RDATA:
+ return ID2SYM(rb_intern("rdata"));
+ case SHAPE_ID_LAYOUT_OTHER:
+ return ID2SYM(rb_intern("other"));
+ default:
+ rb_bug("unknown shape layout: %u", rb_shape_layout(shape_id));
+ }
+}
+
+static VALUE
parse_key(ID key)
{
if (is_instance_id(key)) {
@@ -1350,8 +1407,8 @@ shape_id_t_to_rb_cShape(shape_id_t shape_id)
VALUE obj = rb_struct_new(rb_cShape,
INT2NUM(shape_id),
- INT2NUM(shape_id & SHAPE_ID_OFFSET_MASK),
- INT2NUM(shape->parent_id),
+ INT2NUM(RSHAPE_OFFSET(shape_id)),
+ INT2NUM(shape->parent_offset),
rb_shape_edge_name(shape),
INT2NUM(shape->next_field_index),
INT2NUM(rb_shape_heap_index(shape_id)),
@@ -1364,7 +1421,7 @@ shape_id_t_to_rb_cShape(shape_id_t shape_id)
static enum rb_id_table_iterator_result
rb_edges_to_hash(ID key, VALUE value, void *ref)
{
- rb_hash_aset(*(VALUE *)ref, parse_key(key), shape_id_t_to_rb_cShape(raw_shape_id((rb_shape_t *)value)));
+ rb_hash_aset(*(VALUE *)ref, parse_key(key), shape_id_t_to_rb_cShape(SHAPE_OFFSET((rb_shape_t *)value)));
return ID_TABLE_CONTINUE;
}
@@ -1414,8 +1471,8 @@ rb_shape_parent(VALUE self)
{
rb_shape_t *shape;
shape = RSHAPE(NUM2INT(rb_struct_getmember(self, rb_intern("id"))));
- if (shape->parent_id != INVALID_SHAPE_ID) {
- return shape_id_t_to_rb_cShape(shape->parent_id);
+ if (shape->parent_offset != INVALID_SHAPE_ID) {
+ return shape_id_t_to_rb_cShape(shape->parent_offset);
}
else {
return Qnil;
@@ -1440,7 +1497,7 @@ rb_shape_root_shape(VALUE self)
static VALUE
rb_shape_shapes_available(VALUE self)
{
- return INT2NUM(MAX_SHAPE_ID - (rb_shapes_count() - 1));
+ return ULL2NUM(MAX_SHAPE_ID - (rb_shapes_count() - 1));
}
static VALUE
@@ -1448,10 +1505,16 @@ rb_shape_exhaust(int argc, VALUE *argv, VALUE self)
{
rb_check_arity(argc, 0, 1);
int offset = argc == 1 ? NUM2INT(argv[0]) : 0;
- RUBY_ATOMIC_SET(rb_shape_tree.next_shape_id, MAX_SHAPE_ID - offset + 1);
+ RUBY_ATOMIC_SET(shape_next_id, MAX_SHAPE_ID - offset + 1);
return Qnil;
}
+static VALUE
+rb_shape_class_max_iv_count(VALUE self, VALUE klass)
+{
+ return INT2NUM(RCLASS_MAX_IV_COUNT(klass));
+}
+
static VALUE shape_to_h(rb_shape_t *shape);
static enum rb_id_table_iterator_result collect_keys_and_values(ID key, VALUE value, void *ref)
@@ -1480,14 +1543,14 @@ shape_to_h(rb_shape_t *shape)
{
VALUE rb_shape = rb_hash_new();
- rb_hash_aset(rb_shape, ID2SYM(rb_intern("id")), INT2NUM(raw_shape_id(shape)));
+ rb_hash_aset(rb_shape, ID2SYM(rb_intern("id")), INT2NUM(SHAPE_OFFSET(shape)));
rb_hash_aset(rb_shape, ID2SYM(rb_intern("edges")), edges(shape->edges));
if (shape == rb_shape_get_root_shape()) {
- rb_hash_aset(rb_shape, ID2SYM(rb_intern("parent_id")), INT2NUM(ROOT_SHAPE_ID));
+ rb_hash_aset(rb_shape, ID2SYM(rb_intern("parent_offset")), INT2NUM(ROOT_SHAPE_ID));
}
else {
- rb_hash_aset(rb_shape, ID2SYM(rb_intern("parent_id")), INT2NUM(shape->parent_id));
+ rb_hash_aset(rb_shape, ID2SYM(rb_intern("parent_offset")), INT2NUM(shape->parent_offset));
}
rb_hash_aset(rb_shape, ID2SYM(rb_intern("edge_name")), rb_id2str(shape->edge_name));
@@ -1523,13 +1586,24 @@ Init_default_shapes(void)
while (heap_sizes[heaps_count]) {
heaps_count++;
}
- attr_index_t *capacities = ALLOC_N(attr_index_t, heaps_count + 1);
- capacities[heaps_count] = 0;
+
+ if (heaps_count > SHAPE_ID_HEAP_INDEX_MAX) {
+ rb_bug("Init_default_shapes initialized with %zu heaps, only up to %u are supported", heaps_count, SHAPE_ID_HEAP_INDEX_MAX);
+ }
+
size_t index;
for (index = 0; index < heaps_count; index++) {
- capacities[index] = (heap_sizes[index] - sizeof(struct RBasic)) / sizeof(VALUE);
+ if (heap_sizes[index] > sizeof(struct RBasic)) {
+ size_t capa = (heap_sizes[index] - sizeof(struct RBasic)) / sizeof(VALUE);
+ RUBY_ASSERT(capa < ATTR_INDEX_NOT_SET);
+ rb_shape_tree.capacities[index] = (attr_index_t)capa;
+ }
+ else {
+ rb_shape_tree.capacities[index] = 0;
+ }
}
- rb_shape_tree.capacities = capacities;
+ rb_shape_tree.heaps_count = heaps_count;
+ rb_shape_tree.max_capacity = rb_shape_tree.capacities[heaps_count - 1];
#ifdef HAVE_MMAP
size_t shape_list_mmap_size = rb_size_mul_or_raise(SHAPE_BUFFER_SIZE, sizeof(rb_shape_t), rb_eRuntimeError);
@@ -1553,19 +1627,19 @@ Init_default_shapes(void)
#ifdef HAVE_MMAP
size_t shape_cache_mmap_size = rb_size_mul_or_raise(REDBLACK_CACHE_SIZE, sizeof(redblack_node_t), rb_eRuntimeError);
- rb_shape_tree.shape_cache = (redblack_node_t *)mmap(NULL, shape_cache_mmap_size,
+ redblack_cache = (redblack_node_t *)mmap(NULL, shape_cache_mmap_size,
PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
- rb_shape_tree.cache_size = 0;
+ redblack_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 (rb_shape_tree.shape_cache == MAP_FAILED) {
- rb_shape_tree.shape_cache = 0;
- rb_shape_tree.cache_size = REDBLACK_CACHE_SIZE;
+ if (redblack_cache == MAP_FAILED) {
+ redblack_cache = NULL;
+ redblack_cache_size = REDBLACK_CACHE_SIZE;
}
else {
- ruby_annotate_mmap(rb_shape_tree.shape_cache, shape_cache_mmap_size, "Ruby:Init_default_shapes:shape_cache");
+ ruby_annotate_mmap(redblack_cache, shape_cache_mmap_size, "Ruby:Init_default_shapes:shape_cache");
}
#endif
@@ -1573,31 +1647,24 @@ Init_default_shapes(void)
shape_tree_obj = TypedData_Wrap_Struct(0, &shape_tree_type, (void *)1);
// Root shape
- rb_shape_t *root = rb_shape_alloc_with_parent_id(0, INVALID_SHAPE_ID);
+ rb_shape_t *root = rb_shape_alloc_with_parent_offset(0, INVALID_SHAPE_ID);
root->capacity = 0;
root->type = SHAPE_ROOT;
- rb_shape_tree.root_shape = root;
- RUBY_ASSERT(raw_shape_id(rb_shape_tree.root_shape) == ROOT_SHAPE_ID);
- RUBY_ASSERT(!(raw_shape_id(rb_shape_tree.root_shape) & SHAPE_ID_HAS_IVAR_MASK));
+ RUBY_ASSERT(SHAPE_OFFSET(root) == ROOT_SHAPE_ID);
+ RUBY_ASSERT(!(SHAPE_OFFSET(root) & SHAPE_ID_HAS_IVAR_MASK));
bool dontcare;
rb_shape_t *root_with_obj_id = get_next_shape_internal(root, id_object_id, SHAPE_OBJ_ID, &dontcare, true);
RUBY_ASSERT(root_with_obj_id);
- RUBY_ASSERT(raw_shape_id(root_with_obj_id) == ROOT_SHAPE_WITH_OBJ_ID);
+ RUBY_ASSERT(SHAPE_OFFSET(root_with_obj_id) == ROOT_SHAPE_WITH_OBJ_ID);
RUBY_ASSERT(root_with_obj_id->type == SHAPE_OBJ_ID);
RUBY_ASSERT(root_with_obj_id->edge_name == id_object_id);
RUBY_ASSERT(root_with_obj_id->next_field_index == 1);
- RUBY_ASSERT(!(raw_shape_id(root_with_obj_id) & SHAPE_ID_HAS_IVAR_MASK));
+ RUBY_ASSERT(!(SHAPE_OFFSET(root_with_obj_id) & SHAPE_ID_HAS_IVAR_MASK));
(void)root_with_obj_id;
}
void
-rb_shape_free_all(void)
-{
- xfree((void *)rb_shape_tree.capacities);
-}
-
-void
Init_shape(void)
{
#if SHAPE_DEBUG
@@ -1605,8 +1672,8 @@ Init_shape(void)
* :nodoc: */
VALUE rb_cShape = rb_struct_define_under(rb_cRubyVM, "Shape",
"id",
- "raw_id",
- "parent_id",
+ "offset",
+ "parent_offset",
"edge_name",
"next_field_index",
"heap_index",
@@ -1617,15 +1684,17 @@ Init_shape(void)
rb_define_method(rb_cShape, "parent", rb_shape_parent, 0);
rb_define_method(rb_cShape, "edges", rb_shape_edges, 0);
rb_define_method(rb_cShape, "depth", rb_shape_export_depth, 0);
- rb_define_method(rb_cShape, "too_complex?", shape_too_complex, 0);
+ rb_define_method(rb_cShape, "complex?", shape_complex, 0);
rb_define_method(rb_cShape, "shape_frozen?", shape_frozen, 0);
rb_define_method(rb_cShape, "has_object_id?", shape_has_object_id_p, 0);
+ rb_define_method(rb_cShape, "layout", shape_layout, 0);
rb_define_const(rb_cShape, "SHAPE_ROOT", INT2NUM(SHAPE_ROOT));
rb_define_const(rb_cShape, "SHAPE_IVAR", INT2NUM(SHAPE_IVAR));
rb_define_const(rb_cShape, "SHAPE_ID_NUM_BITS", INT2NUM(SHAPE_ID_NUM_BITS));
rb_define_const(rb_cShape, "SHAPE_FLAG_SHIFT", INT2NUM(SHAPE_FLAG_SHIFT));
rb_define_const(rb_cShape, "SHAPE_MAX_VARIATIONS", INT2NUM(SHAPE_MAX_VARIATIONS));
+ rb_define_const(rb_cShape, "SHAPE_MAX_FIELDS", INT2NUM(rb_shape_tree.max_capacity));
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));
@@ -1637,5 +1706,6 @@ Init_shape(void)
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);
+ rb_define_singleton_method(rb_cShape, "class_max_iv_count", rb_shape_class_max_iv_count, 1);
#endif
}
diff --git a/shape.h b/shape.h
index 8eb1d2c2d6..a319449988 100644
--- a/shape.h
+++ b/shape.h
@@ -2,8 +2,9 @@
#define RUBY_SHAPE_H
#include "internal/gc.h"
+#include "internal/struct.h"
-typedef uint16_t attr_index_t;
+typedef uint8_t attr_index_t;
typedef uint32_t shape_id_t;
#define SHAPE_ID_NUM_BITS 32
#define SHAPE_ID_OFFSET_NUM_BITS 19
@@ -13,129 +14,129 @@ STATIC_ASSERT(shape_id_num_bits, SHAPE_ID_NUM_BITS == sizeof(shape_id_t) * CHAR_
#define SHAPE_BUFFER_SIZE (1 << SHAPE_ID_OFFSET_NUM_BITS)
#define SHAPE_ID_OFFSET_MASK (SHAPE_BUFFER_SIZE - 1)
-#define SHAPE_ID_HEAP_INDEX_BITS 3
-#define SHAPE_ID_HEAP_INDEX_MAX ((1 << SHAPE_ID_HEAP_INDEX_BITS) - 1)
+#define SHAPE_ID_HEAP_INDEX_BITS 4
+#define SHAPE_ID_HEAP_INDEX_MAX (((attr_index_t)1 << SHAPE_ID_HEAP_INDEX_BITS) - 1)
+#define SHAPE_ID_HEAP_INDEX_OFFSET SHAPE_ID_OFFSET_NUM_BITS
#define SHAPE_ID_FL_USHIFT (SHAPE_ID_OFFSET_NUM_BITS + SHAPE_ID_HEAP_INDEX_BITS)
-#define SHAPE_ID_HEAP_INDEX_OFFSET SHAPE_ID_FL_USHIFT
// shape_id_t bits:
// 0-18 SHAPE_ID_OFFSET_MASK
// index in rb_shape_tree.shape_list. Allow to access `rb_shape_t *`.
-// 19-21 SHAPE_ID_HEAP_INDEX_MASK
+// This is the part that describe how fields are laid out in memory.
+// 19-22 SHAPE_ID_HEAP_INDEX_MASK
// index in rb_shape_tree.capacities. Allow to access slot size.
-// 22 SHAPE_ID_FL_FROZEN
+// Currently always 0 except for T_OBJECT.
+// 23 SHAPE_ID_FL_COMPLEX
+// The object is backed by a `st_table`.
+// 24 SHAPE_ID_FL_FROZEN
// Whether the object is frozen or not.
-// 23 SHAPE_ID_FL_HAS_OBJECT_ID
+// 25 SHAPE_ID_FL_HAS_OBJECT_ID
// Whether the object has an `SHAPE_OBJ_ID` transition.
-// 24 SHAPE_ID_FL_TOO_COMPLEX
-// The object is backed by a `st_table`.
+// 26-27 SHAPE_ID_LAYOUT_MASK
+// The object's physical field layout.
enum shape_id_fl_type {
#define RBIMPL_SHAPE_ID_FL(n) (1<<(SHAPE_ID_FL_USHIFT+n))
- SHAPE_ID_HEAP_INDEX_MASK = RBIMPL_SHAPE_ID_FL(0) | RBIMPL_SHAPE_ID_FL(1) | RBIMPL_SHAPE_ID_FL(2),
+ SHAPE_ID_HEAP_INDEX_MASK = ((1 << SHAPE_ID_HEAP_INDEX_BITS) - 1) << SHAPE_ID_HEAP_INDEX_OFFSET,
+
+ SHAPE_ID_FL_COMPLEX = RBIMPL_SHAPE_ID_FL(0),
+ SHAPE_ID_FL_FROZEN = RBIMPL_SHAPE_ID_FL(1),
+ SHAPE_ID_FL_HAS_OBJECT_ID = RBIMPL_SHAPE_ID_FL(2),
+
+ // Means IVs are found at an offset from the object's addr, or in a
+ // malloc allocated side table
+ SHAPE_ID_LAYOUT_ROBJECT = 0,
+
+ // Means this object is a class/module that is NOT RCLASS_BOXABLE, and IV's
+ // are found in the fields_obj found on the rclass struct
+ SHAPE_ID_LAYOUT_RCLASS = RBIMPL_SHAPE_ID_FL(3),
+
+ // Means this object is an RData or RTypedData and IVs are found in the
+ // fields_obj found on the RData/RTypedData struct
+ SHAPE_ID_LAYOUT_RDATA = RBIMPL_SHAPE_ID_FL(4),
- SHAPE_ID_FL_FROZEN = RBIMPL_SHAPE_ID_FL(3),
- SHAPE_ID_FL_HAS_OBJECT_ID = RBIMPL_SHAPE_ID_FL(4),
- SHAPE_ID_FL_TOO_COMPLEX = RBIMPL_SHAPE_ID_FL(5),
+ // Means this is a complicated object: boxable classes, structs, objects
+ // that store IVs on the geniv table
+ SHAPE_ID_LAYOUT_OTHER = SHAPE_ID_LAYOUT_RCLASS | SHAPE_ID_LAYOUT_RDATA,
+
+ SHAPE_ID_LAYOUT_MASK = SHAPE_ID_LAYOUT_OTHER,
SHAPE_ID_FL_NON_CANONICAL_MASK = SHAPE_ID_FL_FROZEN | SHAPE_ID_FL_HAS_OBJECT_ID,
- SHAPE_ID_FLAGS_MASK = SHAPE_ID_HEAP_INDEX_MASK | SHAPE_ID_FL_NON_CANONICAL_MASK | SHAPE_ID_FL_TOO_COMPLEX,
+ SHAPE_ID_FLAGS_MASK = SHAPE_ID_HEAP_INDEX_MASK | SHAPE_ID_FL_NON_CANONICAL_MASK | SHAPE_ID_FL_COMPLEX | SHAPE_ID_LAYOUT_MASK,
#undef RBIMPL_SHAPE_ID_FL
};
-// This masks allows to check if a shape_id contains any ivar.
-// It rely on ROOT_SHAPE_WITH_OBJ_ID==1.
-enum {
- SHAPE_ID_HAS_IVAR_MASK = SHAPE_ID_FL_TOO_COMPLEX | (SHAPE_ID_OFFSET_MASK - 1),
+// This mask allows to check if a shape_id contains any ivar.
+// It relies on ROOT_SHAPE_WITH_OBJ_ID==1.
+enum shape_id_mask {
+ SHAPE_ID_HAS_IVAR_MASK = SHAPE_ID_FL_COMPLEX | (SHAPE_ID_OFFSET_MASK - 1),
};
-// The interpreter doesn't care about frozen status or slot size when reading ivars.
+// The interpreter doesn't care about frozen status, slot size, or object id, and
+// has its own checks for physical field layout when reading ivars.
// So we normalize shape_id by clearing these bits to improve cache hits.
-// JITs however might care about it.
-#define SHAPE_ID_READ_ONLY_MASK (~(SHAPE_ID_FL_FROZEN | SHAPE_ID_HEAP_INDEX_MASK))
+// JITs however might care about some of it.
+#define SHAPE_ID_READ_ONLY_MASK (~(SHAPE_ID_FL_FROZEN | SHAPE_ID_HEAP_INDEX_MASK | SHAPE_ID_FL_HAS_OBJECT_ID | SHAPE_ID_LAYOUT_MASK))
+// For write it's the same idea, but here we do care about frozen status.
+#define SHAPE_ID_WRITE_MASK (~(SHAPE_ID_HEAP_INDEX_MASK | SHAPE_ID_FL_HAS_OBJECT_ID | SHAPE_ID_LAYOUT_MASK))
typedef uint32_t redblack_id_t;
-#define SHAPE_MAX_FIELDS (attr_index_t)(-1)
#define SHAPE_FLAG_SHIFT ((SIZEOF_VALUE * CHAR_BIT) - SHAPE_ID_NUM_BITS)
#define SHAPE_FLAG_MASK (((VALUE)-1) >> SHAPE_ID_NUM_BITS)
#define SHAPE_MAX_VARIATIONS 8
-#define INVALID_SHAPE_ID ((shape_id_t)-1)
+#define INVALID_SHAPE_ID (SHAPE_BUFFER_SIZE - 1)
#define ATTR_INDEX_NOT_SET ((attr_index_t)-1)
#define ROOT_SHAPE_ID 0x0
#define ROOT_SHAPE_WITH_OBJ_ID 0x1
-#define ROOT_TOO_COMPLEX_SHAPE_ID (ROOT_SHAPE_ID | SHAPE_ID_FL_TOO_COMPLEX)
-#define ROOT_TOO_COMPLEX_WITH_OBJ_ID (ROOT_SHAPE_WITH_OBJ_ID | SHAPE_ID_FL_TOO_COMPLEX | SHAPE_ID_FL_HAS_OBJECT_ID)
+#define ROOT_COMPLEX_SHAPE_ID (ROOT_SHAPE_ID | SHAPE_ID_FL_COMPLEX)
+#define ROOT_COMPLEX_WITH_OBJ_ID (ROOT_SHAPE_WITH_OBJ_ID | SHAPE_ID_FL_COMPLEX | SHAPE_ID_FL_HAS_OBJECT_ID)
-typedef struct redblack_node redblack_node_t;
+enum shape_type {
+ SHAPE_ROOT,
+ SHAPE_IVAR,
+ SHAPE_OBJ_ID,
+};
struct rb_shape {
VALUE edges; // id_table from ID (ivar) to next shape
ID edge_name; // ID (ivar) for transition from parent to rb_shape
- redblack_node_t *ancestor_index;
- shape_id_t parent_id;
+ redblack_id_t ancestor_index;
+ shape_id_t parent_offset;
attr_index_t next_field_index; // Fields are either ivars or internal properties like `object_id`
attr_index_t capacity; // Total capacity of the object with this shape
- uint8_t type;
+ enum shape_type type : 8;
};
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_OBJ_ID,
-};
-
enum shape_flags {
SHAPE_FL_FROZEN = 1 << 0,
SHAPE_FL_HAS_OBJECT_ID = 1 << 1,
- SHAPE_FL_TOO_COMPLEX = 1 << 2,
+ SHAPE_FL_COMPLEX = 1 << 2,
SHAPE_FL_NON_CANONICAL_MASK = SHAPE_FL_FROZEN | SHAPE_FL_HAS_OBJECT_ID,
};
typedef struct {
- /* object shapes */
rb_shape_t *shape_list;
- rb_shape_t *root_shape;
- const attr_index_t *capacities;
- rb_atomic_t next_shape_id;
-
- redblack_node_t *shape_cache;
- unsigned int cache_size;
+ attr_index_t max_capacity;
+ attr_index_t heaps_count;
+ attr_index_t capacities[SHAPE_ID_HEAP_INDEX_MAX];
} rb_shape_tree_t;
RUBY_SYMBOL_EXPORT_BEGIN
RUBY_EXTERN rb_shape_tree_t rb_shape_tree;
RUBY_SYMBOL_EXPORT_END
-static inline shape_id_t
-rb_shapes_count(void)
-{
- return (shape_id_t)RUBY_ATOMIC_LOAD(rb_shape_tree.next_shape_id);
-}
-
-union rb_attr_index_cache {
- uint64_t pack;
- struct {
- shape_id_t shape_id;
- attr_index_t index;
- } unpack;
-};
+size_t rb_shapes_cache_size(void);
+size_t rb_shapes_count(void);
static inline shape_id_t
RBASIC_SHAPE_ID(VALUE obj)
@@ -162,10 +163,8 @@ bool rb_shape_verify_consistency(VALUE obj, shape_id_t shape_id);
#endif
static inline void
-RBASIC_SET_SHAPE_ID(VALUE obj, shape_id_t shape_id)
+RBASIC_SET_SHAPE_ID_NO_CHECKS(VALUE obj, shape_id_t shape_id)
{
- RUBY_ASSERT(!RB_SPECIAL_CONST_P(obj));
- RUBY_ASSERT(!RB_TYPE_P(obj, T_IMEMO) || IMEMO_TYPE_P(obj, imemo_fields));
#if RBASIC_SHAPE_ID_FIELD
RBASIC(obj)->shape_id = (VALUE)shape_id;
#else
@@ -173,31 +172,43 @@ RBASIC_SET_SHAPE_ID(VALUE obj, shape_id_t shape_id)
RBASIC(obj)->flags &= SHAPE_FLAG_MASK;
RBASIC(obj)->flags |= ((VALUE)(shape_id) << SHAPE_FLAG_SHIFT);
#endif
- RUBY_ASSERT(rb_shape_verify_consistency(obj, shape_id));
}
-void rb_set_namespaced_class_shape_id(VALUE obj, shape_id_t shape_id);
+static inline shape_id_t
+rb_shape_layout(shape_id_t shape_id)
+{
+ return shape_id & SHAPE_ID_LAYOUT_MASK;
+}
static inline void
-RB_SET_SHAPE_ID(VALUE obj, shape_id_t shape_id)
+RBASIC_SET_SHAPE_ID(VALUE obj, shape_id_t shape_id)
{
- switch (BUILTIN_TYPE(obj)) {
- case T_CLASS:
- case T_MODULE:
- rb_set_namespaced_class_shape_id(obj, shape_id);
- break;
- default:
- RBASIC_SET_SHAPE_ID(obj, shape_id);
- break;
- }
+ RUBY_ASSERT(!RB_SPECIAL_CONST_P(obj));
+ RUBY_ASSERT(!RB_TYPE_P(obj, T_IMEMO) || IMEMO_TYPE_P(obj, imemo_fields));
+ RUBY_ASSERT(!IMEMO_TYPE_P(obj, imemo_fields) || rb_shape_layout(shape_id) == SHAPE_ID_LAYOUT_ROBJECT);
+
+ RBASIC_SET_SHAPE_ID_NO_CHECKS(obj, shape_id);
+
+ RUBY_ASSERT(rb_shape_verify_consistency(obj, shape_id));
+}
+
+static inline shape_id_t
+RSHAPE_FLAGS(shape_id_t shape_id)
+{
+ return shape_id & SHAPE_ID_FLAGS_MASK;
+}
+
+static inline shape_id_t
+RSHAPE_OFFSET(shape_id_t shape_id)
+{
+ return shape_id & SHAPE_ID_OFFSET_MASK;
}
static inline rb_shape_t *
RSHAPE(shape_id_t shape_id)
{
- uint32_t offset = (shape_id & SHAPE_ID_OFFSET_MASK);
+ shape_id_t offset = RSHAPE_OFFSET(shape_id);
RUBY_ASSERT(offset != INVALID_SHAPE_ID);
-
return &rb_shape_tree.shape_list[offset];
}
@@ -212,31 +223,29 @@ bool rb_shape_find_ivar(shape_id_t shape_id, ID id, shape_id_t *ivar_shape);
typedef int rb_shape_foreach_transition_callback(shape_id_t shape_id, void *data);
bool rb_shape_foreach_field(shape_id_t shape_id, rb_shape_foreach_transition_callback func, void *data);
-shape_id_t rb_shape_transition_frozen(VALUE obj);
-shape_id_t rb_shape_transition_complex(VALUE obj);
-shape_id_t rb_shape_transition_remove_ivar(VALUE obj, ID id, shape_id_t *removed_shape_id);
-shape_id_t rb_shape_transition_add_ivar(VALUE obj, ID id);
-shape_id_t rb_shape_transition_add_ivar_no_warnings(VALUE obj, ID id);
-shape_id_t rb_shape_transition_object_id(VALUE obj);
-shape_id_t rb_shape_transition_heap(VALUE obj, size_t heap_index);
-shape_id_t rb_shape_object_id(shape_id_t original_shape_id);
-
-void rb_shape_free_all(void);
+shape_id_t rb_shape_transition_add_ivar_no_warnings(shape_id_t shape_id, ID id, VALUE klass);
+shape_id_t rb_shape_object_id(shape_id_t original_shape_id);
shape_id_t rb_shape_rebuild(shape_id_t initial_shape_id, shape_id_t dest_shape_id);
void rb_shape_copy_fields(VALUE dest, VALUE *dest_buf, shape_id_t dest_shape_id, VALUE *src_buf, shape_id_t src_shape_id);
void rb_shape_copy_complex_ivars(VALUE dest, VALUE obj, shape_id_t src_shape_id, st_table *fields_table);
static inline bool
-rb_shape_too_complex_p(shape_id_t shape_id)
+rb_shape_frozen_p(shape_id_t shape_id)
+{
+ return shape_id & SHAPE_ID_FL_FROZEN;
+}
+
+static inline bool
+rb_shape_complex_p(shape_id_t shape_id)
{
- return shape_id & SHAPE_ID_FL_TOO_COMPLEX;
+ return shape_id & SHAPE_ID_FL_COMPLEX;
}
static inline bool
-rb_shape_obj_too_complex_p(VALUE obj)
+rb_obj_shape_complex_p(VALUE obj)
{
- return !RB_SPECIAL_CONST_P(obj) && rb_shape_too_complex_p(RBASIC_SHAPE_ID(obj));
+ return !RB_SPECIAL_CONST_P(obj) && rb_shape_complex_p(RBASIC_SHAPE_ID(obj));
}
static inline bool
@@ -251,6 +260,12 @@ rb_shape_canonical_p(shape_id_t shape_id)
return !(shape_id & SHAPE_ID_FL_NON_CANONICAL_MASK);
}
+static inline shape_id_t
+rb_shape_id_with_robject_layout(shape_id_t shape_id)
+{
+ return (shape_id & ~SHAPE_ID_LAYOUT_MASK) | SHAPE_ID_LAYOUT_ROBJECT;
+}
+
static inline uint8_t
rb_shape_heap_index(shape_id_t shape_id)
{
@@ -270,16 +285,15 @@ rb_shape_root(size_t heap_id)
}
static inline shape_id_t
-RSHAPE_PARENT_RAW_ID(shape_id_t shape_id)
+RSHAPE_PARENT_OFFSET(shape_id_t shape_id)
{
- return RSHAPE(shape_id)->parent_id;
+ return RSHAPE(shape_id)->parent_offset;
}
static inline bool
-RSHAPE_DIRECT_CHILD_P(shape_id_t parent_id, shape_id_t child_id)
+RSHAPE_DIRECT_CHILD_P(shape_id_t parent_offset, shape_id_t child_id)
{
- return (parent_id & SHAPE_ID_FLAGS_MASK) == (child_id & SHAPE_ID_FLAGS_MASK) &&
- RSHAPE(child_id)->parent_id == (parent_id & SHAPE_ID_OFFSET_MASK);
+ return RSHAPE_PARENT_OFFSET(child_id) == RSHAPE_OFFSET(parent_offset);
}
static inline enum shape_type
@@ -326,6 +340,7 @@ RSHAPE_LEN(shape_id_t shape_id)
static inline attr_index_t
RSHAPE_INDEX(shape_id_t shape_id)
{
+ RUBY_ASSERT(RSHAPE_LEN(shape_id) > 0);
return RSHAPE_LEN(shape_id) - 1;
}
@@ -341,7 +356,7 @@ ROBJECT_FIELDS_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_p(obj));
+ RUBY_ASSERT(!rb_obj_shape_complex_p(obj));
return RSHAPE_CAPACITY(RBASIC_SHAPE_ID(obj));
}
@@ -349,41 +364,55 @@ static inline st_table *
ROBJECT_FIELDS_HASH(VALUE obj)
{
RBIMPL_ASSERT_TYPE(obj, RUBY_T_OBJECT);
- RUBY_ASSERT(rb_shape_obj_too_complex_p(obj));
- return (st_table *)ROBJECT(obj)->as.heap.fields;
+ RUBY_ASSERT(rb_obj_shape_complex_p(obj));
+ RUBY_ASSERT(FL_TEST_RAW(obj, ROBJECT_HEAP));
+
+ return ROBJECT(obj)->as.hash;
}
static inline void
-ROBJECT_SET_FIELDS_HASH(VALUE obj, const st_table *tbl)
+ROBJECT_SET_FIELDS_HASH(VALUE obj, st_table *tbl)
+{
+ RBIMPL_ASSERT_TYPE(obj, RUBY_T_OBJECT);
+ RUBY_ASSERT(rb_obj_shape_complex_p(obj));
+ RUBY_ASSERT(FL_TEST_RAW(obj, ROBJECT_HEAP));
+
+ ROBJECT(obj)->as.hash = tbl;
+}
+
+static inline uint32_t
+ROBJECT_FIELDS_COUNT_COMPLEX(VALUE obj)
+{
+ return (uint32_t)rb_st_table_size(ROBJECT_FIELDS_HASH(obj));
+}
+
+static inline uint32_t
+ROBJECT_FIELDS_COUNT_NOT_COMPLEX(VALUE obj)
{
RBIMPL_ASSERT_TYPE(obj, RUBY_T_OBJECT);
- RUBY_ASSERT(rb_shape_obj_too_complex_p(obj));
- ROBJECT(obj)->as.heap.fields = (VALUE *)tbl;
+ RUBY_ASSERT(!rb_obj_shape_complex_p(obj));
+ return RSHAPE(RBASIC_SHAPE_ID(obj))->next_field_index;
}
static inline uint32_t
ROBJECT_FIELDS_COUNT(VALUE obj)
{
- if (rb_shape_obj_too_complex_p(obj)) {
- return (uint32_t)rb_st_table_size(ROBJECT_FIELDS_HASH(obj));
+ if (rb_obj_shape_complex_p(obj)) {
+ return ROBJECT_FIELDS_COUNT_COMPLEX(obj);
}
else {
- RBIMPL_ASSERT_TYPE(obj, RUBY_T_OBJECT);
- RUBY_ASSERT(!rb_shape_obj_too_complex_p(obj));
- return RSHAPE(RBASIC_SHAPE_ID(obj))->next_field_index;
+ return ROBJECT_FIELDS_COUNT_NOT_COMPLEX(obj);
}
}
static inline uint32_t
RBASIC_FIELDS_COUNT(VALUE obj)
{
- return RSHAPE(rb_obj_shape_id(obj))->next_field_index;
+ return RSHAPE(RBASIC_SHAPE_ID(obj))->next_field_index;
}
-bool rb_obj_set_shape_id(VALUE obj, shape_id_t shape_id);
-
static inline bool
-rb_shape_obj_has_id(VALUE obj)
+rb_obj_shape_has_id(VALUE obj)
{
return rb_shape_has_object_id(RBASIC_SHAPE_ID(obj));
}
@@ -395,7 +424,7 @@ rb_shape_has_ivars(shape_id_t shape_id)
}
static inline bool
-rb_shape_obj_has_ivars(VALUE obj)
+rb_obj_shape_has_ivars(VALUE obj)
{
return rb_shape_has_ivars(RBASIC_SHAPE_ID(obj));
}
@@ -403,17 +432,17 @@ rb_shape_obj_has_ivars(VALUE obj)
static inline bool
rb_shape_has_fields(shape_id_t shape_id)
{
- return shape_id & (SHAPE_ID_OFFSET_MASK | SHAPE_ID_FL_TOO_COMPLEX);
+ return shape_id & (SHAPE_ID_OFFSET_MASK | SHAPE_ID_FL_COMPLEX);
}
static inline bool
-rb_shape_obj_has_fields(VALUE obj)
+rb_obj_shape_has_fields(VALUE obj)
{
return rb_shape_has_fields(RBASIC_SHAPE_ID(obj));
}
static inline bool
-rb_obj_exivar_p(VALUE obj)
+rb_obj_gen_fields_p(VALUE obj)
{
switch (TYPE(obj)) {
case T_NONE:
@@ -425,9 +454,96 @@ rb_obj_exivar_p(VALUE obj)
default:
break;
}
- return rb_shape_obj_has_fields(obj);
+ return rb_obj_shape_has_fields(obj);
}
+static inline bool
+rb_obj_using_gen_fields_table_p(VALUE obj)
+{
+ switch (BUILTIN_TYPE(obj)) {
+ case T_DATA:
+ return false;
+
+ case T_STRUCT:
+ if (!FL_TEST_RAW(obj, RSTRUCT_GEN_FIELDS)) return false;
+ break;
+
+ default:
+ break;
+ }
+
+ return rb_obj_gen_fields_p(obj);
+}
+
+static inline shape_id_t
+rb_shape_transition_frozen(shape_id_t shape_id)
+{
+ return shape_id | SHAPE_ID_FL_FROZEN;
+}
+
+static inline shape_id_t
+rb_shape_transition_complex(shape_id_t shape_id)
+{
+ shape_id_t next_shape_id = rb_shape_layout(shape_id) | ROOT_COMPLEX_SHAPE_ID;
+
+ if (rb_shape_has_object_id(shape_id)) {
+ next_shape_id = rb_shape_layout(shape_id) | ROOT_COMPLEX_WITH_OBJ_ID;
+ }
+
+ uint8_t heap_index = rb_shape_heap_index(shape_id);
+ if (heap_index) {
+ next_shape_id |= rb_shape_root(heap_index - 1);
+ }
+
+ RUBY_ASSERT(rb_shape_has_object_id(shape_id) == rb_shape_has_object_id(next_shape_id));
+
+ return next_shape_id;
+}
+
+static inline shape_id_t
+rb_shape_transition_offset(shape_id_t shape_id, shape_id_t offset)
+{
+ offset = RSHAPE_OFFSET(offset);
+ RUBY_ASSERT(RSHAPE_OFFSET(shape_id) == offset || RSHAPE_DIRECT_CHILD_P(shape_id, offset));
+ return RSHAPE_FLAGS(shape_id) | offset;
+}
+
+static inline shape_id_t
+rb_shape_transition_heap(shape_id_t shape_id, size_t heap_index)
+{
+ return (shape_id & (~SHAPE_ID_HEAP_INDEX_MASK)) | rb_shape_root(heap_index);
+}
+
+shape_id_t rb_shape_transition_object_id(shape_id_t shape_id);
+
+static inline shape_id_t
+rb_obj_shape_transition_frozen(VALUE obj)
+{
+ RUBY_ASSERT(RB_OBJ_FROZEN(obj));
+ return rb_shape_transition_frozen(RBASIC_SHAPE_ID(obj));
+}
+
+static inline shape_id_t
+rb_obj_shape_transition_complex(VALUE obj)
+{
+ return rb_shape_transition_complex(RBASIC_SHAPE_ID(obj));
+}
+
+static inline shape_id_t
+rb_obj_shape_transition_heap(VALUE obj, size_t heap_index)
+{
+ return rb_shape_transition_heap(RBASIC_SHAPE_ID(obj), heap_index);
+}
+
+static inline shape_id_t
+rb_obj_shape_transition_object_id(VALUE obj)
+{
+ return rb_shape_transition_object_id(RBASIC_SHAPE_ID(obj));
+}
+
+shape_id_t rb_obj_shape_transition_remove_ivar(VALUE obj, ID id, shape_id_t *removed_shape_id);
+shape_id_t rb_obj_shape_transition_add_ivar(VALUE obj, ID id);
+
// For ext/objspace
RUBY_SYMBOL_EXPORT_BEGIN
typedef void each_shape_callback(shape_id_t shape_id, void *data);
@@ -437,4 +553,107 @@ size_t rb_shape_edges_count(shape_id_t shape_id);
size_t rb_shape_depth(shape_id_t shape_id);
RUBY_SYMBOL_EXPORT_END
+// Inline cache helpers
+
+typedef struct {
+ attr_index_t index;
+ shape_id_t shape_offset;
+} rb_getivar_cache;
+
+union rb_getivar_cache {
+ uint64_t pack;
+ rb_getivar_cache unpack;
+};
+STATIC_ASSERT(rb_getivar_cache_size, sizeof(union rb_getivar_cache) <= sizeof(uint64_t));
+
+#define IVAR_CACHE_INIT ((uint64_t)-1)
+#define ATTR_INDEX_T_NUM_BITS (sizeof(attr_index_t) * CHAR_BIT)
+
+static inline rb_getivar_cache
+rb_getivar_cache_unpack(uint64_t packed)
+{
+ union rb_getivar_cache cache = {
+ .pack = packed,
+ };
+
+ // Because caches may initialized with all bits set (IVAR_CACHE_INIT), and `shape_offset` if 32bits,
+ // we need to remove any potential extra bits set in the "padding".
+ cache.unpack.shape_offset &= SHAPE_ID_OFFSET_MASK;
+ return cache.unpack;
+}
+
+static inline uint64_t
+rb_getivar_cache_pack(shape_id_t shape_offset, attr_index_t index)
+{
+ RUBY_ASSERT(shape_offset == RSHAPE_OFFSET(shape_offset));
+ RUBY_ASSERT(shape_offset != INVALID_SHAPE_ID);
+
+ union rb_getivar_cache cache = {
+ .unpack = {
+ .shape_offset = shape_offset,
+ .index = index,
+ },
+ };
+ return cache.pack;
+}
+
+typedef struct {
+ attr_index_t index;
+ shape_id_t source_shape_offset;
+ shape_id_t dest_shape_offset;
+} rb_setivar_cache;
+
+static inline rb_setivar_cache
+rb_setivar_cache_unpack(uint64_t packed)
+{
+ rb_setivar_cache cache = {
+ .index = (attr_index_t)packed,
+ .source_shape_offset = RSHAPE_OFFSET((shape_id_t)(packed >> ATTR_INDEX_T_NUM_BITS)),
+ .dest_shape_offset = RSHAPE_OFFSET((shape_id_t)(packed >> (ATTR_INDEX_T_NUM_BITS + SHAPE_ID_OFFSET_NUM_BITS))),
+ };
+ return cache;
+}
+
+static inline uint64_t
+rb_setivar_cache_pack(shape_id_t shape_offset, shape_id_t dest_shape_offset, attr_index_t index)
+{
+ RUBY_ASSERT(shape_offset == RSHAPE_OFFSET(shape_offset));
+ RUBY_ASSERT(dest_shape_offset == RSHAPE_OFFSET(dest_shape_offset));
+ RUBY_ASSERT(shape_offset == dest_shape_offset || RSHAPE_DIRECT_CHILD_P(shape_offset, dest_shape_offset));
+
+ uint64_t packed_cache = (uint64_t)dest_shape_offset << (ATTR_INDEX_T_NUM_BITS + SHAPE_ID_OFFSET_NUM_BITS);
+ packed_cache |= (uint64_t)shape_offset << ATTR_INDEX_T_NUM_BITS;
+ packed_cache |= (uint64_t)index;
+ return packed_cache;
+}
+
+
+ALWAYS_INLINE(static shape_id_t rb_setivar_cache_revalidate(shape_id_t shape_id, rb_setivar_cache cache));
+static shape_id_t
+rb_setivar_cache_revalidate(shape_id_t shape_id, rb_setivar_cache cache)
+{
+ RUBY_ASSERT(shape_id != INVALID_SHAPE_ID);
+ RUBY_ASSERT(cache.dest_shape_offset == INVALID_SHAPE_ID || cache.dest_shape_offset == RSHAPE_OFFSET(cache.dest_shape_offset));
+
+ shape_id_t normalized_shape_id = shape_id & SHAPE_ID_WRITE_MASK;
+ if (UNLIKELY(normalized_shape_id != cache.source_shape_offset)) {
+ return INVALID_SHAPE_ID;
+ }
+
+ if (UNLIKELY(cache.index >= RSHAPE_CAPACITY(shape_id))) {
+ // That's still a hit in term of layout, but the object will need to be resized,
+ // so unfortunately we'll have to go through the slow path regardless...
+ return INVALID_SHAPE_ID;
+ }
+
+ // Cache hit case
+ RUBY_ASSERT(cache.source_shape_offset == cache.dest_shape_offset || RSHAPE_DIRECT_CHILD_P(shape_id, cache.dest_shape_offset));
+ RUBY_ASSERT(cache.index < RSHAPE_CAPACITY(shape_id));
+ RUBY_ASSERT(!rb_shape_frozen_p(shape_id));
+ RUBY_ASSERT(!rb_shape_complex_p(shape_id));
+
+ // We use the cached offset, but combined with the current shape flags.
+ return rb_shape_transition_offset(shape_id, cache.dest_shape_offset);
+}
+
#endif
diff --git a/signal.c b/signal.c
index f6b62b3014..f37aaf971a 100644
--- a/signal.c
+++ b/signal.c
@@ -949,6 +949,20 @@ sigsegv(int sig SIGINFO_ARG)
}
#endif
+#ifdef SIGABRT
+
+static sighandler_t default_sigabrt_handler;
+NORETURN(static ruby_sigaction_t sigabrt);
+
+static void
+sigabrt(int sig SIGINFO_ARG)
+{
+ check_reserved_signal("ABRT");
+ CHECK_STACK_OVERFLOW();
+ rb_bug_for_fatal_signal(default_sigabrt_handler, sig, SIGINFO_CTX, "Aborted" MESSAGE_FAULT_ADDRESS);
+}
+#endif
+
#ifdef SIGILL
static sighandler_t default_sigill_handler;
@@ -1006,8 +1020,20 @@ check_reserved_signal_(const char *name, size_t name_len, int signo)
#if __has_feature(address_sanitizer) || \
__has_feature(memory_sanitizer) || \
defined(HAVE_VALGRIND_MEMCHECK_H)
- ruby_posix_signal(signo, SIG_DFL);
+# define SANITIZING true
+#else
+# define SANITIZING false
+#endif
+
+#ifdef SIGABRT
+// Avoid infinite loop when already aborting
+# define RECURSIVE (signo == SIGABRT)
+#else
+# define RECURSIVE false
#endif
+ if (SANITIZING || RECURSIVE) ruby_signal(signo, SIG_DFL);
+# undef SANITIZING
+# undef RECURSIVE
W(name, name_len);
W(msg1, sizeof(msg1));
W(prev, strlen(prev));
@@ -1052,7 +1078,7 @@ signal_exec(VALUE cmd, int sig)
EC_PUSH_TAG(ec);
if ((state = EC_EXEC_TAG()) == TAG_NONE) {
VALUE signum = INT2NUM(sig);
- rb_eval_cmd_kw(cmd, rb_ary_new3(1, signum), RB_NO_KEYWORDS);
+ rb_eval_cmd_call_kw(cmd, 1, &signum, RB_NO_KEYWORDS);
}
EC_POP_TAG();
ec = GET_EC();
@@ -1238,11 +1264,6 @@ trap_handler(VALUE *cmd, int sig)
break;
}
}
- else {
- rb_proc_t *proc;
- GetProcPtr(*cmd, proc);
- (void)proc;
- }
}
return func;
@@ -1337,31 +1358,36 @@ reserved_signal_p(int signo)
/*
* call-seq:
- * Signal.trap( signal, command ) -> obj
- * Signal.trap( signal ) {| | block } -> obj
+ * Signal.trap(signal, command) -> obj
+ * Signal.trap(signal) { ... } -> obj
+ *
+ * Specifies the handling of signals. Returns the previous handler for
+ * the given signal.
*
- * Specifies the handling of signals. The first parameter is a signal
- * name (a string such as ``SIGALRM'', ``SIGUSR1'', and so on) or a
- * signal number. The characters ``SIG'' may be omitted from the
- * signal name. The command or block specifies code to be run when the
+ * Argument +signal+ is a signal name (a string or symbol such
+ * as +SIGALRM+ or +SIGUSR1+) or an integer signal number. When +signal+
+ * is a string or symbol, the leading characters +SIG+ may be omitted.
+ *
+ * Argument +command+ or block provided specifies code to be run when the
* signal is raised.
- * If the command is the string ``IGNORE'' or ``SIG_IGN'', the signal
- * will be ignored.
- * If the command is ``DEFAULT'' or ``SIG_DFL'', the Ruby's default handler
- * will be invoked.
- * If the command is ``EXIT'', the script will be terminated by the signal.
- * If the command is ``SYSTEM_DEFAULT'', the operating system's default
- * handler will be invoked.
- * Otherwise, the given command or block will be run.
- * The special signal name ``EXIT'' or signal number zero will be
- * invoked just prior to program termination.
- * trap returns the previous handler for the given signal.
+ *
+ * Argument +command+ may also be a string or symbol with the following special
+ * values:
+ *
+ * - +IGNORE+, +SIG_IGN+: the signal will be ignored.
+ * - +DEFAULT+, +SIG_DFL+: Ruby's default handler will be invoked.
+ * - +EXIT+: the process will be terminated by the signal.
+ * - +SYSTEM_DEFAULT+: the operating system's default handler will be invoked.
+ *
+ * The special signal name +EXIT+ or signal number zero will be
+ * invoked just prior to program termination:
*
* Signal.trap(0, proc { puts "Terminating: #{$$}" })
* Signal.trap("CLD") { puts "Child died" }
* fork && Process.wait
*
- * <em>produces:</em>
+ * Outputs:
+ *
* Terminating: 27461
* Child died
* Terminating: 27460
@@ -1558,6 +1584,10 @@ Init_signal(void)
RB_ALTSTACK_INIT(GET_VM()->main_altstack, rb_allocate_sigaltstack());
force_install_sighandler(SIGSEGV, (sighandler_t)sigsegv, &default_sigsegv_handler);
#endif
+
+#ifdef SIGABRT
+ force_install_sighandler(SIGABRT, (sighandler_t)sigabrt, &default_sigabrt_handler);
+#endif
}
#ifdef SIGPIPE
install_sighandler(SIGPIPE, sig_do_nothing);
diff --git a/spec/bin/rspec b/spec/bin/rspec
index 1f61e3c64c..a41aa4896a 100755
--- a/spec/bin/rspec
+++ b/spec/bin/rspec
@@ -1,6 +1,7 @@
#!/usr/bin/env ruby
# frozen_string_literal: true
+require_relative "../bundler/support/switch_rubygems"
require_relative "../bundler/support/rubygems_ext"
Spec::Rubygems.gem_load("rspec-core", "rspec")
diff --git a/spec/bundled_gems_spec.rb b/spec/bundled_gems_spec.rb
index c362881850..9af06dd181 100644
--- a/spec/bundled_gems_spec.rb
+++ b/spec/bundled_gems_spec.rb
@@ -22,18 +22,12 @@ RSpec.configure do |config|
Gem.ruby = ENV["RUBY"] if ENV["RUBY"]
require_relative "bundler/support/rubygems_ext"
- Spec::Rubygems.test_setup
Spec::Helpers.install_dev_bundler
FileUtils.mkdir_p Spec::Path.gem_path
end
config.around(:each) do |example|
FileUtils.cp_r Spec::Path.pristine_system_gem_path, Spec::Path.system_gem_path
- FileUtils.mkdir_p Spec::Path.base_system_gem_path.join("gems")
- %w[sinatra rack tilt rack-protection rack-session rack-test mustermann base64 logger compact_index].each do |gem|
- path = Dir[File.expand_path("../.bundle/gems/#{gem}-*", __dir__)].map(&:to_s).first
- FileUtils.cp_r path, Spec::Path.base_system_gem_path.join("gems")
- end
with_gem_path_as(system_gem_path) do
Bundler.ui.silence { example.run }
@@ -57,11 +51,12 @@ end
RSpec.describe "bundled_gems.rb" do
let(:stub_code) {
+ source_lib_dir = File.realpath(Spec::Path.source_lib_dir.to_s)
<<~STUB
Gem::BUNDLED_GEMS.send(:remove_const, :LIBDIR)
Gem::BUNDLED_GEMS.send(:remove_const, :ARCHDIR)
Gem::BUNDLED_GEMS.send(:remove_const, :SINCE)
- Gem::BUNDLED_GEMS.const_set(:LIBDIR, File.expand_path(File.join(__dir__, "../../..", "lib")) + "/")
+ Gem::BUNDLED_GEMS.const_set(:LIBDIR, "#{source_lib_dir}/")
Gem::BUNDLED_GEMS.const_set(:ARCHDIR, File.expand_path($LOAD_PATH.find{|path| path.include?(".ext/common") }) + "/")
Gem::BUNDLED_GEMS.const_set(:SINCE, { "openssl" => RUBY_VERSION, "fileutils" => RUBY_VERSION, "csv" => "3.4.0", "net-smtp" => "3.1.0" })
STUB
@@ -113,7 +108,7 @@ RSpec.describe "bundled_gems.rb" do
require "active_support/all"
RUBY
- expect(err).to include(/openssl used to be loaded from (.*) since Ruby 3.5.0/)
+ expect(err).to include(/openssl used to be loaded from (.*) since Ruby #{RUBY_VERSION}/)
expect(err).to include(/lib\/active_support\/all\.rb:1/)
end
@@ -159,7 +154,7 @@ RSpec.describe "bundled_gems.rb" do
bundle "exec ruby script.rb"
- expect(err).to include(/openssl used to be loaded from (.*) since Ruby 3.5.0/)
+ expect(err).to include(/openssl used to be loaded from (.*) since Ruby #{RUBY_VERSION}/)
expect(err).to include(/script\.rb:8/)
end
@@ -177,7 +172,7 @@ RSpec.describe "bundled_gems.rb" do
bundle "exec ./script.rb"
- expect(err).to include(/openssl used to be loaded from (.*) since Ruby 3.5.0/)
+ expect(err).to include(/openssl used to be loaded from (.*) since Ruby #{RUBY_VERSION}/)
expect(err).to include(/script\.rb:9/)
end
@@ -186,7 +181,7 @@ RSpec.describe "bundled_gems.rb" do
create_file("Gemfile", "source 'https://rubygems.org'")
bundle "exec ruby -r./stub -ropenssl -e ''"
- expect(err).to include(/openssl used to be loaded from (.*) since Ruby 3.5.0/)
+ expect(err).to include(/openssl used to be loaded from (.*) since Ruby #{RUBY_VERSION}/)
end
it "Show warning when warn is not the standard one in the current scope" do
@@ -209,7 +204,7 @@ RSpec.describe "bundled_gems.rb" do
My.my
RUBY
- expect(err).to include(/openssl used to be loaded from (.*) since Ruby 3.5.0/)
+ expect(err).to include(/openssl used to be loaded from (.*) since Ruby #{RUBY_VERSION}/)
expect(err).to include(/-e:19/)
end
@@ -251,7 +246,7 @@ RSpec.describe "bundled_gems.rb" do
require Gem::BUNDLED_GEMS::ARCHDIR + 'openssl'
RUBY
- expect(err).to include(/openssl used to be loaded from (.*) since Ruby 3.5.0/)
+ expect(err).to include(/openssl used to be loaded from (.*) since Ruby #{RUBY_VERSION}/)
# TODO: We should assert caller location like below:
# test_warn_bootsnap.rb:14: warning: ...
end
@@ -280,7 +275,7 @@ RSpec.describe "bundled_gems.rb" do
# Original issue is childprocess 5.0.0 and logger.
build_lib "fileutils2", "5.0.0" do |s|
# bootsnap expand required feature to full path
- rubylibpath = File.expand_path(File.join(__dir__, "..", "lib"))
+ rubylibpath = File.realpath(File.join(__dir__, "..", "lib"))
s.write "lib/fileutils2.rb", "require '#{rubylibpath}/fileutils'"
end
@@ -320,7 +315,7 @@ RSpec.describe "bundled_gems.rb" do
create_file("Gemfile", "source 'https://rubygems.org'")
bundle "exec ruby script.rb"
- expect(err).to include(/openssl used to be loaded from (.*) since Ruby 3.5.0/)
+ expect(err).to include(/openssl used to be loaded from (.*) since Ruby #{RUBY_VERSION}/)
expect(err).to include(/script\.rb:13/)
end
@@ -393,6 +388,30 @@ RSpec.describe "bundled_gems.rb" do
end
end
+ context "with bundler/inline" do
+ it "foo is available on LOAD_PATH" do
+ build_lib "foo", "1.0.0" do |s|
+ s.write "lib/foo.rb", "puts :foo"
+ end
+
+ script <<-RUBY, env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo1.to_s }
+ #!/usr/bin/env ruby
+ gemfile do
+ source "https://gem.repo1"
+ path "#{lib_path}" do
+ gem "foo", "1.0.0"
+ end
+ end
+
+ Gem::BUNDLED_GEMS.force_activate("csv")
+ puts $LOAD_PATH
+ RUBY
+
+ expect(err).to include("gem install csv")
+ expect(out).to include("foo-1.0.0/lib")
+ end
+ end
+
context "without bundle environment" do
it "warns about installation requirement" do
expect_any_instance_of(Object).to receive(:warn)
diff --git a/spec/bundler/bundler/bundler_spec.rb b/spec/bundler/bundler/bundler_spec.rb
index 4db8c00e52..bddcbdaef3 100644
--- a/spec/bundler/bundler/bundler_spec.rb
+++ b/spec/bundler/bundler/bundler_spec.rb
@@ -52,10 +52,10 @@ RSpec.describe Bundler do
s.description = "Bundler manages an application's dependencies through its entire life, across many machines, systematically and repeatably"
s.email = ["team@bundler.io"]
s.homepage = "https://bundler.io"
- s.metadata = { "bug_tracker_uri" => "https://github.com/rubygems/rubygems/issues?q=is%3Aopen+is%3Aissue+label%3ABundler",
- "changelog_uri" => "https://github.com/rubygems/rubygems/blob/master/bundler/CHANGELOG.md",
+ s.metadata = { "bug_tracker_uri" => "https://github.com/ruby/rubygems/issues?q=is%3Aopen+is%3Aissue+label%3ABundler",
+ "changelog_uri" => "https://github.com/ruby/rubygems/blob/master/bundler/CHANGELOG.md",
"homepage_uri" => "https://bundler.io/",
- "source_code_uri" => "https://github.com/rubygems/rubygems/tree/master/bundler" }
+ "source_code_uri" => "https://github.com/ruby/rubygems/tree/master/bundler" }
s.require_paths = ["lib"]
s.required_ruby_version = Gem::Requirement.new([">= 2.6.0"])
s.required_rubygems_version = Gem::Requirement.new([">= 3.0.1"])
diff --git a/spec/bundler/bundler/cli_common_spec.rb b/spec/bundler/bundler/cli_common_spec.rb
new file mode 100644
index 0000000000..015894b3a1
--- /dev/null
+++ b/spec/bundler/bundler/cli_common_spec.rb
@@ -0,0 +1,22 @@
+# frozen_string_literal: true
+
+require "bundler/cli"
+
+RSpec.describe Bundler::CLI::Common do
+ describe "gem_not_found_message" do
+ it "should suggest alternate gem names" do
+ message = subject.gem_not_found_message("ralis", ["BOGUS"])
+ expect(message).to match("Could not find gem 'ralis'.$")
+ message = subject.gem_not_found_message("ralis", ["rails"])
+ expect(message).to match("Did you mean 'rails'?")
+ message = subject.gem_not_found_message("Rails", ["rails"])
+ expect(message).to match("Did you mean 'rails'?")
+ message = subject.gem_not_found_message("meail", %w[email fail eval])
+ expect(message).to match("Did you mean 'email'?")
+ message = subject.gem_not_found_message("nokogri", %w[nokogiri rails sidekiq dog])
+ expect(message).to match("Did you mean 'nokogiri'?")
+ message = subject.gem_not_found_message("methosd", %w[method methods bogus])
+ expect(message).to match(/Did you mean 'method(|s)' or 'method(|s)'?/)
+ end
+ end
+end
diff --git a/spec/bundler/bundler/cli_spec.rb b/spec/bundler/bundler/cli_spec.rb
index 41cd8c636d..56caf9937e 100644
--- a/spec/bundler/bundler/cli_spec.rb
+++ b/spec/bundler/bundler/cli_spec.rb
@@ -87,15 +87,25 @@ RSpec.describe "bundle executable" do
end
context "with no arguments" do
- it "prints a concise help message", bundler: "4" do
- bundle ""
- expect(err).to be_empty
+ it "tries to installs by default but print help on missing Gemfile" do
+ bundle "", raise_on_error: false
+ expect(err).to include("Could not locate Gemfile")
+ expect(out).to include("In a future version of Bundler")
+
expect(out).to include("Bundler version #{Bundler::VERSION}").
and include("\n\nBundler commands:\n\n").
and include("\n\n Primary commands:\n").
and include("\n\n Utilities:\n").
and include("\n\nOptions:\n")
end
+
+ it "runs bundle install when default_cli_command set to install" do
+ bundle_config "default_cli_command install"
+ bundle "", raise_on_error: false
+ expect(out).to_not include("In a future version of Bundler")
+ expect(err).to include("Could not locate Gemfile")
+ expect(exitstatus).to_not be_zero
+ end
end
context "when ENV['BUNDLE_GEMFILE'] is set to an empty string" do
@@ -125,7 +135,7 @@ RSpec.describe "bundle executable" do
end
it "prints the simulated version too when setting is enabled" do
- bundle "config simulate_version 4", verbose: true
+ bundle "config set simulate_version 4", verbose: true
bundle "info bundler", verbose: true
expect(out).to start_with("Running `bundle info bundler --verbose` with bundler #{Bundler::VERSION} (simulating Bundler 4)")
end
@@ -133,7 +143,7 @@ RSpec.describe "bundle executable" do
context "with verbose configuration" do
before do
- bundle "config verbose true"
+ bundle_config "verbose true"
end
it "prints the running command" do
@@ -200,7 +210,7 @@ RSpec.describe "bundle executable" do
let(:bundler_version) { "2.0" }
let(:latest_version) { nil }
before do
- bundle "config set --global disable_version_check false"
+ bundle_config_global "disable_version_check false"
pristine_system_gems "bundler-#{bundler_version}"
if latest_version
@@ -241,8 +251,10 @@ To update to the most recent version, run `bundle update --bundler`
context "running a parseable command" do
it "prints no warning" do
+ bundle "config set foo value", env: { "BUNDLER_VERSION" => bundler_version }
bundle "config get --parseable foo", env: { "BUNDLER_VERSION" => bundler_version }
- expect(stdboth).to eq ""
+ expect(out).to eq "foo=value"
+ expect(err).to eq ""
bundle "platform --ruby", env: { "BUNDLER_VERSION" => bundler_version }, raise_on_error: false
expect(stdboth).to eq "Could not locate Gemfile"
@@ -266,10 +278,21 @@ end
RSpec.describe "bundler executable" do
it "shows the bundler version just as the `bundle` executable does" do
bundler "--version"
- expect(out).to eq("Bundler version #{Bundler::VERSION}")
+ expect(out).to eq(Bundler::VERSION.to_s)
- bundle "config simulate_version 4"
+ bundle_config "simulate_version 5"
bundler "--version"
- expect(out).to eq("#{Bundler::VERSION} (simulating Bundler 4)")
+ expect(out).to eq("#{Bundler::VERSION} (simulating Bundler 5)")
+ end
+
+ it "shows cli_help when bundler install and no Gemfile is found" do
+ bundler "install", raise_on_error: false
+ expect(err).to include("Could not locate Gemfile")
+
+ expect(out).to include("Bundler version #{Bundler::VERSION}").
+ and include("\n\nBundler commands:\n\n").
+ and include("\n\n Primary commands:\n").
+ and include("\n\n Utilities:\n").
+ and include("\n\nOptions:\n")
end
end
diff --git a/spec/bundler/bundler/compact_index_client/parser_spec.rb b/spec/bundler/bundler/compact_index_client/parser_spec.rb
index 1f6b9e593b..6aa867f058 100644
--- a/spec/bundler/bundler/compact_index_client/parser_spec.rb
+++ b/spec/bundler/bundler/compact_index_client/parser_spec.rb
@@ -47,7 +47,7 @@ RSpec.describe Bundler::CompactIndexClient::Parser do
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
+ 3.3.3 a:>= 1.1.0,b:~> 2.0|checksum:ccc3,ruby:>= 3.0.0,rubygems:>= 3.2.3,created_at:2026-05-12T10:00:00Z
INFO
describe "#available?" do
@@ -195,7 +195,7 @@ RSpec.describe Bundler::CompactIndexClient::Parser do
"3.3.3",
nil,
[["a", [">= 1.1.0"]], ["b", ["~> 2.0"]]],
- [["checksum", ["ccc3"]], ["ruby", [">= 3.0.0"]], ["rubygems", [">= 3.2.3"]]],
+ [["checksum", ["ccc3"]], ["ruby", [">= 3.0.0"]], ["rubygems", [">= 3.2.3"]], ["created_at", ["2026-05-12T10:00:00Z"]]],
],
]
end
@@ -233,5 +233,17 @@ RSpec.describe Bundler::CompactIndexClient::Parser do
VERSIONS
expect(parser.info("a")).to eq(a_result)
end
+
+ it "handles lines without a checksum" 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
+ c 3.0.0,3.0.3,3.3.3 ccc333
+ VERSIONS
+
+ expect(parser.info("a")).to eq(a_result)
+ end
end
end
diff --git a/spec/bundler/bundler/current_ruby_spec.rb b/spec/bundler/bundler/current_ruby_spec.rb
index 8764c4971f..79eb802aa5 100644
--- a/spec/bundler/bundler/current_ruby_spec.rb
+++ b/spec/bundler/bundler/current_ruby_spec.rb
@@ -22,7 +22,8 @@ RSpec.describe Bundler::CurrentRuby do
ruby_32: Gem::Platform::RUBY,
ruby_33: Gem::Platform::RUBY,
ruby_34: Gem::Platform::RUBY,
- ruby_35: Gem::Platform::RUBY,
+ ruby_40: Gem::Platform::RUBY,
+ ruby_41: Gem::Platform::RUBY,
mri: Gem::Platform::RUBY,
mri_18: Gem::Platform::RUBY,
mri_19: Gem::Platform::RUBY,
@@ -39,7 +40,8 @@ RSpec.describe Bundler::CurrentRuby do
mri_32: Gem::Platform::RUBY,
mri_33: Gem::Platform::RUBY,
mri_34: Gem::Platform::RUBY,
- mri_35: Gem::Platform::RUBY,
+ mri_40: Gem::Platform::RUBY,
+ mri_41: Gem::Platform::RUBY,
rbx: Gem::Platform::RUBY,
truffleruby: Gem::Platform::RUBY,
jruby: Gem::Platform::JAVA,
@@ -61,7 +63,8 @@ RSpec.describe Bundler::CurrentRuby do
windows_32: Gem::Platform::WINDOWS,
windows_33: Gem::Platform::WINDOWS,
windows_34: Gem::Platform::WINDOWS,
- windows_35: Gem::Platform::WINDOWS }
+ windows_40: Gem::Platform::WINDOWS,
+ windows_41: Gem::Platform::WINDOWS }
end
let(:deprecated) do
@@ -81,7 +84,8 @@ RSpec.describe Bundler::CurrentRuby do
mswin_32: Gem::Platform::MSWIN,
mswin_33: Gem::Platform::MSWIN,
mswin_34: Gem::Platform::MSWIN,
- mswin_35: Gem::Platform::MSWIN,
+ mswin_40: Gem::Platform::MSWIN,
+ mswin_41: Gem::Platform::MSWIN,
mswin64: Gem::Platform::MSWIN64,
mswin64_19: Gem::Platform::MSWIN64,
mswin64_20: Gem::Platform::MSWIN64,
@@ -97,7 +101,8 @@ RSpec.describe Bundler::CurrentRuby do
mswin64_32: Gem::Platform::MSWIN64,
mswin64_33: Gem::Platform::MSWIN64,
mswin64_34: Gem::Platform::MSWIN64,
- mswin64_35: Gem::Platform::MSWIN64,
+ mswin64_40: Gem::Platform::MSWIN64,
+ mswin64_41: Gem::Platform::MSWIN64,
mingw: Gem::Platform::UNIVERSAL_MINGW,
mingw_18: Gem::Platform::UNIVERSAL_MINGW,
mingw_19: Gem::Platform::UNIVERSAL_MINGW,
@@ -114,7 +119,8 @@ RSpec.describe Bundler::CurrentRuby do
mingw_32: Gem::Platform::UNIVERSAL_MINGW,
mingw_33: Gem::Platform::UNIVERSAL_MINGW,
mingw_34: Gem::Platform::UNIVERSAL_MINGW,
- mingw_35: Gem::Platform::UNIVERSAL_MINGW,
+ mingw_40: Gem::Platform::UNIVERSAL_MINGW,
+ mingw_41: Gem::Platform::UNIVERSAL_MINGW,
x64_mingw: Gem::Platform::UNIVERSAL_MINGW,
x64_mingw_20: Gem::Platform::UNIVERSAL_MINGW,
x64_mingw_21: Gem::Platform::UNIVERSAL_MINGW,
@@ -129,7 +135,8 @@ RSpec.describe Bundler::CurrentRuby do
x64_mingw_32: Gem::Platform::UNIVERSAL_MINGW,
x64_mingw_33: Gem::Platform::UNIVERSAL_MINGW,
x64_mingw_34: Gem::Platform::UNIVERSAL_MINGW,
- x64_mingw_35: Gem::Platform::UNIVERSAL_MINGW }
+ x64_mingw_40: Gem::Platform::UNIVERSAL_MINGW,
+ x64_mingw_41: Gem::Platform::UNIVERSAL_MINGW }
end
# rubocop:enable Naming/VariableNumber
@@ -139,18 +146,12 @@ RSpec.describe Bundler::CurrentRuby do
end
describe "Deprecated platform" do
- it "Outputs a deprecation warning when calling maglev?" do
- expect(Bundler.ui).to receive(:warn).with(/`CurrentRuby#maglev\?` is deprecated with no replacement./)
-
- Bundler.current_ruby.maglev?
+ it "outputs an error and aborts when calling maglev?" do
+ expect { Bundler.current_ruby.maglev? }.to raise_error(Bundler::RemovedError, /`CurrentRuby#maglev\?` was removed with no replacement./)
end
- it "Outputs a deprecation warning when calling maglev_31?" do
- expect(Bundler.ui).to receive(:warn).with(/`CurrentRuby#maglev_31\?` is deprecated with no replacement./)
-
- Bundler.current_ruby.maglev_31?
+ it "outputs an error and aborts when calling maglev_31?" do
+ expect { Bundler.current_ruby.maglev_31? }.to raise_error(Bundler::RemovedError, /`CurrentRuby#maglev_31\?` was removed with no replacement./)
end
-
- pending "is removed and shows a helpful error message about it", bundler: "4"
end
end
diff --git a/spec/bundler/bundler/definition_spec.rb b/spec/bundler/bundler/definition_spec.rb
index 8f796877fd..8c4a5a0331 100644
--- a/spec/bundler/bundler/definition_spec.rb
+++ b/spec/bundler/bundler/definition_spec.rb
@@ -3,6 +3,24 @@
require "bundler/definition"
RSpec.describe Bundler::Definition do
+ describe "#overrides" do
+ before do
+ allow(Bundler::SharedHelpers).to receive(:find_gemfile) { bundled_app_gemfile }
+ end
+
+ subject { Bundler::Definition.new(bundled_app_lock, [], Bundler::SourceList.new, {}) }
+
+ it "defaults to an empty array" do
+ expect(subject.overrides).to eq([])
+ end
+
+ it "is writable" do
+ override = Bundler::Override.new("rails", :version, ">= 8.0")
+ subject.overrides = [override]
+ expect(subject.overrides).to eq([override])
+ end
+ end
+
describe "#lock" do
before do
allow(Bundler::SharedHelpers).to receive(:find_gemfile) { bundled_app_gemfile }
@@ -80,7 +98,7 @@ RSpec.describe Bundler::Definition do
foo!
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
G
end
@@ -137,7 +155,7 @@ RSpec.describe Bundler::Definition do
foo!
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
G
expect(lockfile).to eq(expected_lockfile)
@@ -175,7 +193,7 @@ RSpec.describe Bundler::Definition do
only_java
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
G
end
@@ -205,7 +223,7 @@ RSpec.describe Bundler::Definition do
foo
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
G
end
end
@@ -289,6 +307,57 @@ RSpec.describe Bundler::Definition do
end
end
+ describe "#precompute_source_requirements_for_indirect_dependencies?" do
+ before do
+ allow(Bundler::SharedHelpers).to receive(:find_gemfile) { Pathname.new("Gemfile") }
+ end
+
+ let(:sources) { Bundler::SourceList.new }
+ subject { Bundler::Definition.new(nil, [], sources, []) }
+
+ before do
+ allow(sources).to receive(:non_global_rubygems_sources).and_return(non_global_rubygems_sources)
+ end
+
+ context "when all the scoped sources implement a dependency API" do
+ let(:non_global_rubygems_sources) do
+ [
+ double("non-global-source-0", "dependency_api_available?":true, to_s:"a"),
+ double("non-global-source-1", "dependency_api_available?":true, to_s:"b"),
+ ]
+ end
+
+ it "returns true without warning" do
+ expect(subject).not_to receive(:non_dependency_api_warning)
+
+ expect(subject.send(:precompute_source_requirements_for_indirect_dependencies?)).to be_truthy
+ end
+ end
+
+ context "when some scoped sources do not implement a dependency API" do
+ let(:non_global_rubygems_sources) do
+ [
+ double("non-global-source-0", "dependency_api_available?":true, to_s:"a"),
+ double("non-global-source-1", "dependency_api_available?":false, to_s:"b"),
+ double("non-global-source-2", "dependency_api_available?":false, to_s:"c"),
+ ]
+ end
+
+ it "returns false and warns about the non-API sources" do
+ expect(Bundler.ui).to receive(:warn).with(<<-W.strip)
+Your Gemfile contains scoped sources that don't implement a dependency API, namely:
+
+ * b
+ * c
+
+Using the above gem servers may result in installing unexpected gems. To resolve this warning, make sure you use gem servers that implement dependency APIs, such as gemstash or geminabox gem servers.
+ W
+
+ expect(subject.send(:precompute_source_requirements_for_indirect_dependencies?)).to be_falsy
+ end
+ end
+ end
+
def mock_source_list
Class.new do
def all_sources
@@ -299,10 +368,6 @@ RSpec.describe Bundler::Definition do
[]
end
- def rubygems_remotes
- []
- end
-
def replace_sources!(arg)
nil
end
diff --git a/spec/bundler/bundler/dsl_spec.rb b/spec/bundler/bundler/dsl_spec.rb
index ac28aea4d7..b6e67a312c 100644
--- a/spec/bundler/bundler/dsl_spec.rb
+++ b/spec/bundler/bundler/dsl_spec.rb
@@ -162,7 +162,7 @@ RSpec.describe Bundler::Dsl do
describe "#method_missing" do
it "raises an error for unknown DSL methods" do
- expect(Bundler).to receive(:read_file).with(source_root.join("Gemfile").to_s).
+ expect(Bundler).to receive(:read_file).with(git_root.join("Gemfile").to_s).
and_return("unknown")
error_msg = "There was an error parsing `Gemfile`: Undefined local variable or method `unknown' for Gemfile. Bundler cannot continue."
@@ -173,13 +173,13 @@ RSpec.describe Bundler::Dsl do
describe "#eval_gemfile" 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(Bundler).to receive(:read_file).with(git_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)
end
it "distinguishes syntax errors from evaluation errors" do
- expect(Bundler).to receive(:read_file).with(source_root.join("Gemfile").to_s).and_return(
+ expect(Bundler).to receive(:read_file).with(git_root.join("Gemfile").to_s).and_return(
"ruby '2.1.5', :engine => 'ruby', :engine_version => '1.2.4'"
)
expect { subject.eval_gemfile("Gemfile") }.
@@ -187,13 +187,13 @@ RSpec.describe Bundler::Dsl do
end
it "populates __dir__ and __FILE__ correctly" do
- abs_path = source_root.join("../fragment.rb").to_s
+ abs_path = git_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_dir)).to eq(git_root.dirname.to_s)
expect(subject.instance_variable_get(:@fragment_file)).to eq(abs_path)
end
end
@@ -201,8 +201,8 @@ RSpec.describe Bundler::Dsl do
describe "#gem" do
# rubocop:disable Naming/VariableNumber
[:ruby, :ruby_18, :ruby_19, :ruby_20, :ruby_21, :ruby_22, :ruby_23, :ruby_24, :ruby_25, :ruby_26, :ruby_27,
- :ruby_30, :ruby_31, :ruby_32, :ruby_33, :ruby_34, :ruby_35, :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, :mri_34, :mri_35, :jruby, :rbx, :truffleruby].each do |platform|
+ :ruby_30, :ruby_31, :ruby_32, :ruby_33, :ruby_34, :ruby_40, :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, :mri_34, :mri_40, :jruby, :rbx, :truffleruby].each do |platform|
it "allows #{platform} as a valid platform" do
subject.gem("foo", platform: platform)
end
@@ -221,8 +221,8 @@ RSpec.describe Bundler::Dsl do
to raise_error(Bundler::GemfileError, /is not a valid platform/)
end
- it "raises a deprecation warning for legacy windows platforms" do
- expect(Bundler::SharedHelpers).to receive(:major_deprecation).with(2, /\APlatform :mswin, :x64_mingw is deprecated/, removed_message: /\APlatform :mswin, :x64_mingw has been removed/)
+ it "warn for legacy windows platforms" do
+ expect(Bundler::SharedHelpers).to receive(:feature_deprecated!).with(/\APlatform :mswin, :x64_mingw will be removed in the future./)
subject.gem("foo", platforms: [:mswin, :jruby, :x64_mingw])
end
@@ -291,8 +291,8 @@ RSpec.describe Bundler::Dsl do
end
describe "#platforms" do
- it "raises a deprecation warning for legacy windows platforms" do
- expect(Bundler::SharedHelpers).to receive(:major_deprecation).with(2, /\APlatform :mswin64, :mingw is deprecated/, removed_message: /\APlatform :mswin64, :mingw has been removed/)
+ it "warn for legacy windows platforms" do
+ expect(Bundler::SharedHelpers).to receive(:feature_deprecated!).with(/\APlatform :mswin64, :mingw will be removed in the future./)
subject.platforms(:mswin64, :jruby, :mingw) do
subject.gem("foo")
end
@@ -366,4 +366,193 @@ RSpec.describe Bundler::Dsl do
end
end
end
+
+ describe "#source with cooldown" do
+ before do
+ allow(@rubygems).to receive(:add_remote)
+ end
+
+ it "accepts a non-negative integer" do
+ expect do
+ subject.source("https://rubygems.org", cooldown: 7)
+ end.not_to raise_error
+ end
+
+ it "accepts 0 as an explicit disable" do
+ expect do
+ subject.source("https://rubygems.org", cooldown: 0)
+ end.not_to raise_error
+ end
+
+ it "rejects a string" do
+ expect do
+ subject.source("https://rubygems.org", cooldown: "7")
+ end.to raise_error(Bundler::InvalidOption, /non-negative integer/)
+ end
+
+ it "rejects a float" do
+ expect do
+ subject.source("https://rubygems.org", cooldown: 7.5)
+ end.to raise_error(Bundler::InvalidOption, /non-negative integer/)
+ end
+
+ it "rejects a negative integer" do
+ expect do
+ subject.source("https://rubygems.org", cooldown: -7)
+ end.to raise_error(Bundler::InvalidOption, /non-negative integer/)
+ end
+
+ it "rejects an array" do
+ expect do
+ subject.source("https://rubygems.org", cooldown: [7])
+ end.to raise_error(Bundler::InvalidOption, /non-negative integer/)
+ end
+ end
+
+ describe "#override" do
+ it "stores an Override for a gem with a version: operation" do
+ subject.override("rails", version: ">= 8.0")
+
+ expect(subject.overrides.size).to eq(1)
+ override = subject.overrides.first
+ expect(override.target).to eq("rails")
+ expect(override.field).to eq(:version)
+ expect(override.operation).to eq(">= 8.0")
+ end
+
+ it "accepts :ignore_upper as the operation" do
+ subject.override("nokogiri", version: :ignore_upper)
+ expect(subject.overrides.first.operation).to eq(:ignore_upper)
+ end
+
+ it "accepts nil as the operation" do
+ subject.override("legacy", version: nil)
+ expect(subject.overrides.first.operation).to be_nil
+ end
+
+ it "appends to overrides across multiple statements" do
+ subject.override("rails", version: ">= 8.0")
+ subject.override("nokogiri", version: :ignore_upper)
+ expect(subject.overrides.map(&:target)).to eq(["rails", "nokogiri"])
+ end
+
+ it "is empty by default" do
+ expect(subject.overrides).to eq([])
+ end
+
+ it "raises ArgumentError when target is :all and version: is given" do
+ expect do
+ subject.override(:all, version: ">= 8.0")
+ end.to raise_error(ArgumentError, /`override :all, version:` is not allowed/)
+ end
+
+ it "rejects :all + version: even when other fields are also given" do
+ expect do
+ subject.override(:all, required_ruby_version: :ignore_upper, version: ">= 8.0")
+ end.to raise_error(ArgumentError, /`override :all, version:` is not allowed/)
+ end
+
+ it "does not record any override when :all + version: is rejected" do
+ expect do
+ subject.override(:all, version: ">= 8.0")
+ end.to raise_error(ArgumentError)
+ expect(subject.overrides).to eq([])
+ end
+
+ it "raises ArgumentError when target is neither :all nor a string" do
+ expect do
+ subject.override(:rails, version: ">= 8.0")
+ end.to raise_error(ArgumentError, /target must be :all or a gem name string/)
+ end
+
+ it "raises ArgumentError for an unsupported field" do
+ expect do
+ subject.override("rails", as: "y")
+ end.to raise_error(ArgumentError, /unsupported override field `as:`/)
+ end
+
+ it "stores an Override for a gem with a required_ruby_version: operation" do
+ subject.override("rails", required_ruby_version: :ignore_upper)
+ override = subject.overrides.first
+ expect(override.target).to eq("rails")
+ expect(override.field).to eq(:required_ruby_version)
+ expect(override.operation).to eq(:ignore_upper)
+ end
+
+ it "stores an Override for a gem with a required_rubygems_version: operation" do
+ subject.override("rails", required_rubygems_version: nil)
+ override = subject.overrides.first
+ expect(override.field).to eq(:required_rubygems_version)
+ expect(override.operation).to be_nil
+ end
+
+ it "stores an Override targeting :all with a metadata field" do
+ subject.override(:all, required_ruby_version: :ignore_upper)
+ override = subject.overrides.first
+ expect(override.target).to eq(:all)
+ expect(override.field).to eq(:required_ruby_version)
+ expect(override.operation).to eq(:ignore_upper)
+ end
+
+ it "stores an Override targeting :all with required_rubygems_version" do
+ subject.override(:all, required_rubygems_version: nil)
+ override = subject.overrides.first
+ expect(override.target).to eq(:all)
+ expect(override.field).to eq(:required_rubygems_version)
+ end
+
+ it "raises ArgumentError for a non-string, non-symbol, non-nil operation" do
+ expect do
+ subject.override("rails", version: 42)
+ end.to raise_error(ArgumentError, /override operation must be a String, Symbol, or nil/)
+ end
+
+ it "raises ArgumentError for an unsupported symbol operation" do
+ expect do
+ subject.override("rails", version: :explode)
+ end.to raise_error(ArgumentError, /unsupported override operation/)
+ end
+
+ it "raises ArgumentError for an unparsable version string" do
+ expect do
+ subject.override("rails", version: "not a version")
+ end.to raise_error(ArgumentError, /invalid override version requirement/)
+ end
+
+ it "does not record an override when the version string is invalid" do
+ expect do
+ subject.override("rails", version: "not a version")
+ end.to raise_error(ArgumentError)
+ expect(subject.overrides).to eq([])
+ end
+
+ it "rejects atomically when one field in a multi-field call is invalid" do
+ expect do
+ subject.override("rails", version: ">= 8.0", as: "y")
+ end.to raise_error(ArgumentError, /unsupported override field/)
+ expect(subject.overrides).to eq([])
+ end
+
+ it "raises ArgumentError when the same target and field are overridden twice" do
+ subject.override("rails", version: ">= 8.0")
+ expect do
+ subject.override("rails", version: :ignore_upper)
+ end.to raise_error(ArgumentError, /duplicate override for "rails" `version:`/)
+ end
+
+ it "keeps the original override when a duplicate is rejected" do
+ subject.override("rails", version: ">= 8.0")
+ expect do
+ subject.override("rails", version: :ignore_upper)
+ end.to raise_error(ArgumentError)
+ expect(subject.overrides.size).to eq(1)
+ expect(subject.overrides.first.operation).to eq(">= 8.0")
+ end
+
+ it "allows different targets with the same field" do
+ subject.override("rails", version: ">= 8.0")
+ subject.override("nokogiri", version: :ignore_upper)
+ expect(subject.overrides.size).to eq(2)
+ end
+ end
end
diff --git a/spec/bundler/bundler/endpoint_specification_spec.rb b/spec/bundler/bundler/endpoint_specification_spec.rb
index 6518f125ba..4fbd59d48f 100644
--- a/spec/bundler/bundler/endpoint_specification_spec.rb
+++ b/spec/bundler/bundler/endpoint_specification_spec.rb
@@ -46,6 +46,46 @@ RSpec.describe Bundler::EndpointSpecification do
)
end
end
+
+ context "when the metadata has created_at" do
+ let(:metadata) { { "created_at" => ["2026-05-12T10:00:00Z"] } }
+
+ it "parses created_at as a Time" do
+ expect(subject.created_at).to eq(Time.utc(2026, 5, 12, 10, 0, 0))
+ end
+ end
+
+ context "when the metadata has a string created_at (older rubygems shape)" do
+ let(:metadata) { { "created_at" => "2026-05-12T10:00:00Z" } }
+
+ it "still parses created_at" do
+ expect(subject.created_at).to eq(Time.utc(2026, 5, 12, 10, 0, 0))
+ end
+ end
+
+ context "when created_at is truncated (older rubygems splits on colons)" do
+ let(:metadata) { { "created_at" => "2026-05-12T10" } }
+
+ it "leaves created_at as nil instead of raising" do
+ expect(subject.created_at).to be_nil
+ end
+ end
+
+ context "when the metadata has no created_at" do
+ let(:metadata) { { "checksum" => ["abc"] } }
+ let(:spec_fetcher) { double(:spec_fetcher, uri: "https://rubygems.org") }
+
+ it "leaves created_at as nil" do
+ allow(Bundler::Checksum).to receive(:from_api).and_return(nil)
+ expect(subject.created_at).to be_nil
+ end
+ end
+
+ context "when the metadata is nil" do
+ it "leaves created_at as nil" do
+ expect(subject.created_at).to be_nil
+ end
+ end
end
describe "#required_ruby_version" do
diff --git a/spec/bundler/bundler/env_spec.rb b/spec/bundler/bundler/env_spec.rb
index e0ab0a45e3..2b7dbde217 100644
--- a/spec/bundler/bundler/env_spec.rb
+++ b/spec/bundler/bundler/env_spec.rb
@@ -217,20 +217,21 @@ RSpec.describe Bundler::Env do
context "when the git version is OS specific" do
it "includes OS specific information with the version number" do
- expect(git_proxy_stub).to receive(:git_local).with("--version").
- and_return("git version 1.2.3 (Apple Git-BS)")
+ status = double("success?" => true)
+ expect(Open3).to receive(:capture3).with("git", "--version").
+ and_return(["git version 1.2.3 (Apple Git-BS)", "", status])
expect(Bundler::Source::Git::GitProxy).to receive(:new).and_return(git_proxy_stub)
- expect(described_class.report).to include("Git 1.2.3 (Apple Git-BS)")
+ expect(described_class.report).to include("Git 1.2.3 (Apple Git-BS)")
end
end
- end
-
- describe ".version_of" do
- let(:parsed_version) { described_class.send(:version_of, "ruby") }
- it "strips version of new line characters" do
- expect(parsed_version).to_not end_with("\n")
+ it "no longer reports the Tools section or external tool versions" do
+ report = described_class.report
+ expect(report).not_to include("Tools")
+ ["rbenv", "RVM", "chruby"].each do |tool|
+ expect(report).not_to include(tool)
+ end
end
end
end
diff --git a/spec/bundler/bundler/errors_spec.rb b/spec/bundler/bundler/errors_spec.rb
new file mode 100644
index 0000000000..b62d85d32b
--- /dev/null
+++ b/spec/bundler/bundler/errors_spec.rb
@@ -0,0 +1,91 @@
+# frozen_string_literal: true
+
+RSpec.describe Bundler::IncorrectLockfileDependencies do
+ describe "#message" do
+ let(:spec) do
+ double("LazySpecification", full_name: "rubocop-1.82.0")
+ end
+
+ context "without dependency details" do
+ subject { described_class.new(spec) }
+
+ it "provides a basic error message" do
+ expect(subject.message).to include("Bundler found incorrect dependencies in the lockfile for rubocop-1.82.0")
+ expect(subject.message).to include("Please run `bundle install` to regenerate the lockfile.")
+ end
+ end
+
+ context "with dependency details" do
+ let(:actual_dependencies) do
+ [
+ Gem::Dependency.new("json", [">= 2.3", "< 4.0"]),
+ Gem::Dependency.new("parallel", ["~> 1.10"]),
+ Gem::Dependency.new("parser", [">= 3.3.0.2"]),
+ ]
+ end
+
+ let(:lockfile_dependencies) do
+ [
+ Gem::Dependency.new("json", [">= 2.3", "< 3.0"]),
+ Gem::Dependency.new("parallel", ["~> 1.10"]),
+ Gem::Dependency.new("parser", [">= 3.2.0.0"]),
+ ]
+ end
+
+ subject { described_class.new(spec, actual_dependencies, lockfile_dependencies) }
+
+ it "shows only mismatched dependencies" do
+ message = subject.message
+
+ expect(message).to include("json: gemspec specifies")
+ expect(message).to include("parser: gemspec specifies")
+ expect(message).not_to include("parallel")
+ end
+ end
+
+ context "when gemspec has dependencies but lockfile has none" do
+ let(:actual_dependencies) do
+ [
+ Gem::Dependency.new("myrack-test", ["~> 1.0"]),
+ ]
+ end
+
+ let(:lockfile_dependencies) { [] }
+
+ subject { described_class.new(spec, actual_dependencies, lockfile_dependencies) }
+
+ it "shows the dependency as not in lockfile" do
+ message = subject.message
+
+ expect(message).to include("myrack-test: gemspec specifies ~> 1.0, not in lockfile")
+ end
+ end
+
+ context "when gemspec has no dependencies but lockfile has some" do
+ let(:actual_dependencies) { [] }
+
+ let(:lockfile_dependencies) do
+ [
+ Gem::Dependency.new("unexpected", ["~> 1.0"]),
+ ]
+ end
+
+ subject { described_class.new(spec, actual_dependencies, lockfile_dependencies) }
+
+ it "shows the dependency as not in gemspec" do
+ message = subject.message
+
+ expect(message).to include("unexpected: not in gemspec, lockfile has ~> 1.0")
+ end
+ end
+ end
+
+ describe "#status_code" do
+ let(:spec) { double("LazySpecification", full_name: "test-1.0.0") }
+ subject { described_class.new(spec) }
+
+ it "returns 41" do
+ expect(subject.status_code).to eq(41)
+ end
+ end
+end
diff --git a/spec/bundler/bundler/fetcher/dependency_spec.rb b/spec/bundler/bundler/fetcher/dependency_spec.rb
index c420b7c07f..501bc269a5 100644
--- a/spec/bundler/bundler/fetcher/dependency_spec.rb
+++ b/spec/bundler/bundler/fetcher/dependency_spec.rb
@@ -212,7 +212,7 @@ RSpec.describe Bundler::Fetcher::Dependency do
let(:dep_api_uri) { double(:dep_api_uri) }
let(:unmarshalled_gems) { double(:unmarshalled_gems) }
let(:fetch_response) { double(:fetch_response, body: double(:body)) }
- let(:rubygems_limit) { 50 }
+ let(:rubygems_limit) { 100 }
before { allow(subject).to receive(:dependency_api_uri).with(gem_names).and_return(dep_api_uri) }
@@ -222,6 +222,18 @@ RSpec.describe Bundler::Fetcher::Dependency do
expect(Bundler).to receive(:safe_load_marshal).with(fetch_response.body).and_return([unmarshalled_gems])
expect(subject.unmarshalled_dep_gems(gem_names)).to eq([unmarshalled_gems])
end
+
+ it "should fetch as many dependencies as specified" do
+ allow(subject).to receive(:dependency_api_uri).with([%w[foo bar]]).and_return(dep_api_uri)
+ allow(subject).to receive(:dependency_api_uri).with([%w[bundler rubocop]]).and_return(dep_api_uri)
+
+ expect(downloader).to receive(:fetch).twice.with(dep_api_uri).and_return(fetch_response)
+ expect(Bundler).to receive(:safe_load_marshal).twice.with(fetch_response.body).and_return([unmarshalled_gems])
+
+ Bundler.settings.temporary(api_request_size: 1) do
+ expect(subject.unmarshalled_dep_gems(gem_names)).to eq([unmarshalled_gems, unmarshalled_gems])
+ end
+ end
end
describe "#get_formatted_specs_and_deps" do
diff --git a/spec/bundler/bundler/fetcher/downloader_spec.rb b/spec/bundler/bundler/fetcher/downloader_spec.rb
index 36b9b94990..edf426328a 100644
--- a/spec/bundler/bundler/fetcher/downloader_spec.rb
+++ b/spec/bundler/bundler/fetcher/downloader_spec.rb
@@ -126,6 +126,38 @@ RSpec.describe Bundler::Fetcher::Downloader do
end
end
+ context "when the request response is a Gem::Net::HTTPRequestedRangeNotSatisfiable" do
+ let(:http_response) { Gem::Net::HTTPRequestedRangeNotSatisfiable.new("1.1", 416, "Range Not Satisfiable") }
+ let(:success_response) { Gem::Net::HTTPSuccess.new("1.1", 200, "Success") }
+ let(:options) { { "Range" => "bytes=1000-", "If-None-Match" => "some-etag" } }
+
+ before do
+ # First request returns 416, retry request returns success
+ allow(subject).to receive(:request).with(uri, options).and_return(http_response)
+ allow(subject).to receive(:request).with(uri, { "If-None-Match" => "some-etag" }).and_return(success_response)
+ end
+
+ # The 416 handler removes the Range header and retries without incrementing the counter.
+ # Importantly, it does NOT add Accept-Encoding header, which would break Ruby's
+ # automatic gzip decompression (see issue #9271 for details on that bug).
+ it "should retry the request without the Range header" do
+ expect(subject).to receive(:request).with(uri, options).ordered
+ expect(subject).to receive(:request).with(uri, hash_excluding("Range", "Accept-Encoding")).ordered
+ subject.fetch(uri, options, counter)
+ end
+
+ it "should preserve other headers on retry" do
+ expect(subject).to receive(:request).with(uri, options).ordered
+ expect(subject).to receive(:request).with(uri, hash_including("If-None-Match" => "some-etag")).ordered
+ subject.fetch(uri, options, counter)
+ end
+
+ it "should return the successful response" do
+ result = subject.fetch(uri, options, counter)
+ expect(result).to eq(success_response)
+ end
+ end
+
context "when the request response is some other type" do
let(:http_response) { Gem::Net::HTTPBadGateway.new("1.1", 500, "Fatal Error") }
diff --git a/spec/bundler/bundler/fetcher/gem_remote_fetcher_spec.rb b/spec/bundler/bundler/fetcher/gem_remote_fetcher_spec.rb
new file mode 100644
index 0000000000..df1a58d843
--- /dev/null
+++ b/spec/bundler/bundler/fetcher/gem_remote_fetcher_spec.rb
@@ -0,0 +1,60 @@
+# frozen_string_literal: true
+
+require "rubygems/remote_fetcher"
+require "bundler/fetcher/gem_remote_fetcher"
+require_relative "../../support/artifice/helpers/artifice"
+require "bundler/vendored_persistent.rb"
+
+RSpec.describe Bundler::Fetcher::GemRemoteFetcher do
+ describe "Parallel download" do
+ it "download using multiple connections from the pool" do
+ unless Bundler.rubygems.provides?(">= 4.0.0.dev")
+ skip "This example can only run when RubyGems supports multiple http connection pool"
+ end
+
+ require_relative "../../support/artifice/helpers/endpoint"
+ concurrent_ruby_path = Dir[scoped_base_system_gem_path.join("gems/concurrent-ruby-*/lib/concurrent-ruby")].first
+ $LOAD_PATH.unshift(concurrent_ruby_path)
+ require "concurrent-ruby"
+
+ require_rack_test
+ responses = []
+
+ latch1 = Concurrent::CountDownLatch.new
+ latch2 = Concurrent::CountDownLatch.new
+ previous_client = Gem::Request::ConnectionPools.client
+ dummy_endpoint = Class.new(Endpoint) do
+ get "/foo" do
+ latch2.count_down
+ latch1.wait
+
+ responses << "foo"
+ end
+
+ get "/bar" do
+ responses << "bar"
+
+ latch1.count_down
+ end
+ end
+
+ Artifice.activate_with(dummy_endpoint)
+ Gem::Request::ConnectionPools.client = Gem::Net::HTTP
+
+ first_request = Thread.new do
+ subject.fetch_path("https://example.org/foo")
+ end
+ second_request = Thread.new do
+ latch2.wait
+ subject.fetch_path("https://example.org/bar")
+ end
+
+ [first_request, second_request].each(&:join)
+
+ expect(responses).to eq(["bar", "foo"])
+ ensure
+ Artifice.deactivate
+ Gem::Request::ConnectionPools.client = previous_client
+ end
+ end
+end
diff --git a/spec/bundler/bundler/friendly_errors_spec.rb b/spec/bundler/bundler/friendly_errors_spec.rb
index d6a9d4813d..426e3c856d 100644
--- a/spec/bundler/bundler/friendly_errors_spec.rb
+++ b/spec/bundler/bundler/friendly_errors_spec.rb
@@ -197,7 +197,7 @@ RSpec.describe Bundler, "friendly errors" do
it "generates a search URL for the exception message" do
exception = Exception.new("Exception message")
- expect(Bundler::FriendlyErrors.issues_url(exception)).to eq("https://github.com/rubygems/rubygems/search?q=Exception+message&type=Issues")
+ expect(Bundler::FriendlyErrors.issues_url(exception)).to eq("https://github.com/ruby/rubygems/search?q=Exception+message&type=Issues")
end
it "generates a search URL for only the first line of a multi-line exception message" do
@@ -206,7 +206,7 @@ First line of the exception message
Second line of the exception message
END
- expect(Bundler::FriendlyErrors.issues_url(exception)).to eq("https://github.com/rubygems/rubygems/search?q=First+line+of+the+exception+message&type=Issues")
+ expect(Bundler::FriendlyErrors.issues_url(exception)).to eq("https://github.com/ruby/rubygems/search?q=First+line+of+the+exception+message&type=Issues")
end
it "generates the url without colons" do
@@ -215,7 +215,7 @@ Exception ::: with ::: colons :::
END
issues_url = Bundler::FriendlyErrors.issues_url(exception)
expect(issues_url).not_to include("%3A")
- expect(issues_url).to eq("https://github.com/rubygems/rubygems/search?q=#{CGI.escape("Exception with colons ")}&type=Issues")
+ expect(issues_url).to eq("https://github.com/ruby/rubygems/search?q=#{CGI.escape("Exception with colons ")}&type=Issues")
end
it "removes information after - for Errono::EACCES" do
@@ -225,7 +225,7 @@ END
allow(exception).to receive(:is_a?).with(Errno).and_return(true)
issues_url = Bundler::FriendlyErrors.issues_url(exception)
expect(issues_url).not_to include("/Users/foo/bar")
- expect(issues_url).to eq("https://github.com/rubygems/rubygems/search?q=#{CGI.escape("Errno EACCES Permission denied @ dir_s_mkdir ")}&type=Issues")
+ expect(issues_url).to eq("https://github.com/ruby/rubygems/search?q=#{CGI.escape("Errno EACCES Permission denied @ dir_s_mkdir ")}&type=Issues")
end
end
end
diff --git a/spec/bundler/bundler/gem_helper_spec.rb b/spec/bundler/bundler/gem_helper_spec.rb
index 94f66537d3..b4ae2abdc5 100644
--- a/spec/bundler/bundler/gem_helper_spec.rb
+++ b/spec/bundler/bundler/gem_helper_spec.rb
@@ -9,8 +9,12 @@ RSpec.describe Bundler::GemHelper do
let(:app_gemspec_path) { app_path.join("#{app_name}.gemspec") }
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"
+ bundle_config_global "gem.mit false"
+ bundle_config_global "gem.test false"
+ bundle_config_global "gem.coc false"
+ bundle_config_global "gem.linter false"
+ bundle_config_global "gem.ci false"
+ bundle_config_global "gem.changelog false"
git("config --global init.defaultBranch main")
bundle "gem #{app_name}"
prepare_gemspec(app_gemspec_path)
@@ -222,7 +226,7 @@ RSpec.describe Bundler::GemHelper do
mock_confirm_message "#{app_name} (#{app_version}) installed."
subject.install_gem(nil, :local)
expect(app_gem_path).to exist
- gem_command :list
+ installed_gems_list
expect(out).to include("#{app_name} (#{app_version})")
end
end
@@ -386,6 +390,7 @@ RSpec.describe Bundler::GemHelper do
credentials = double("credentials", "file?" => true)
allow(Bundler.user_home).to receive(:join).
with(".gem/credentials").and_return(credentials)
+ allow(Bundler.user_home).to receive(:join).and_call_original
end
describe "success messaging" do
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..49bcb5310b
--- /dev/null
+++ b/spec/bundler/bundler/installer/parallel_installer_spec.rb
@@ -0,0 +1,79 @@
+# frozen_string_literal: true
+
+require "bundler/installer/parallel_installer"
+require "bundler/rubygems_gem_installer"
+require "rubygems/remote_fetcher"
+require "bundler"
+
+RSpec.describe Bundler::ParallelInstaller do
+ describe "priority queue" do
+ before do
+ require "support/artifice/compact_index"
+
+ @previous_client = Gem::Request::ConnectionPools.client
+ Gem::Request::ConnectionPools.client = Gem::Net::HTTP
+ Gem::RemoteFetcher.fetcher.close_all
+
+ build_repo2 do
+ build_gem "gem_with_extension", &:add_c_extension
+ build_gem "gem_without_extension"
+ end
+
+ gemfile <<~G
+ source "https://gem.repo2"
+
+ gem "gem_with_extension"
+ gem "gem_without_extension"
+ G
+ lockfile <<~L
+ GEM
+ remote: https://gem.repo2/
+ specs:
+ gem_with_extension (1.0)
+ gem_without_extension (1.0)
+
+ DEPENDENCIES
+ gem_with_extension
+ gem_without_extension
+ L
+
+ @old_ui = Bundler.ui
+ Bundler.ui = Bundler::UI::Silent.new
+ end
+
+ after do
+ Bundler.ui = @old_ui
+ Gem::Request::ConnectionPools.client = @previous_client
+ Artifice.deactivate
+ end
+
+ let(:definition) do
+ allow(Bundler).to receive(:root) { bundled_app }
+
+ definition = Bundler::Definition.build(bundled_app.join("Gemfile"), bundled_app.join("Gemfile.lock"), false)
+ definition.tap(&:setup_domain!)
+ end
+ let(:installer) { Bundler::Installer.new(bundled_app, definition) }
+
+ it "queues native extensions in priority" do
+ parallel_installer = Bundler::ParallelInstaller.new(installer, definition.specs, 2, false, true)
+ worker_pool = parallel_installer.send(:worker_pool)
+ expected = 6 # Enqueue to download bundler and the 2 gems. Enqueue to install Bundler and the 2 gems.
+
+ expect(worker_pool).to receive(:enq).exactly(expected).times.and_wrap_original do |original_enq, spec, opts|
+ unless opts.nil? # Enqueued for download, no priority
+ if spec.name == "gem_with_extension"
+ expect(opts).to eq({ priority: true })
+ else
+ expect(opts).to eq({ priority: false })
+ end
+ end
+
+ opts ||= {}
+ original_enq.call(spec, **opts)
+ end
+
+ parallel_installer.call
+ 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..57868766d9 100644
--- a/spec/bundler/bundler/installer/spec_installation_spec.rb
+++ b/spec/bundler/bundler/installer/spec_installation_spec.rb
@@ -3,18 +3,17 @@
require "bundler/installer/parallel_installer"
RSpec.describe Bundler::ParallelInstaller::SpecInstallation do
- let!(:dep) do
- a_spec = Object.new
- def a_spec.name
- "I like tests"
- end
-
- def a_spec.full_name
- "I really like tests"
- end
- a_spec
+ def build_spec(name, extensions: [])
+ spec = Object.new
+ spec.define_singleton_method(:name) { name }
+ spec.define_singleton_method(:full_name) { "#{name}-1.0" }
+ spec.define_singleton_method(:extensions) { extensions }
+ spec.define_singleton_method(:dependencies) { [] }
+ spec
end
+ let!(:dep) { build_spec("I like tests") }
+
describe "#ready_to_enqueue?" do
context "when in enqueued state" do
it "is falsey" do
@@ -39,29 +38,51 @@ RSpec.describe Bundler::ParallelInstaller::SpecInstallation do
end
describe "#dependencies_installed?" 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)]
+ it "returns true when all dependencies are installed" do
+ alpha = described_class.new(build_spec("alpha"))
+ alpha.dependencies = []
+
+ beta = described_class.new(build_spec("beta"))
+ beta.dependencies = [alpha]
+
+ gamma = described_class.new(build_spec("gamma"))
+ gamma.dependencies = [beta]
+
+ expect(gamma.dependencies_installed?({})).to be_falsey
+ expect(gamma.dependencies_installed?({ "beta" => true })).to be_falsey
+ expect(gamma.dependencies_installed?({ "alpha" => true, "beta" => true })).to be_truthy
+ end
+ end
+
+ describe "#ready_to_install?" do
+ context "when spec has no extensions" do
+ it "returns true regardless of dependencies" do
+ beta = described_class.new(build_spec("beta"))
+ beta.dependencies = []
+
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
+ spec.state = :downloaded
+ spec.dependencies = [beta]
+
+ expect(spec.ready_to_install?({})).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)]
- 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
+ context "when spec has extensions" do
+ it "returns true when all dependencies are installed" do
+ alpha = described_class.new(build_spec("alpha"))
+ alpha.dependencies = []
+
+ beta = described_class.new(build_spec("beta"))
+ beta.dependencies = [alpha]
+
+ gamma = described_class.new(build_spec("gamma", extensions: ["ext/Rakefile"]))
+ gamma.state = :downloaded
+ gamma.dependencies = [beta]
+
+ expect(gamma.ready_to_install?({})).to be_falsey
+ expect(gamma.ready_to_install?({ "beta" => true })).to be_falsey
+ expect(gamma.ready_to_install?({ "alpha" => true, "beta" => true })).to be_truthy
end
end
end
diff --git a/spec/bundler/bundler/lockfile_parser_spec.rb b/spec/bundler/bundler/lockfile_parser_spec.rb
index 54aa6a0bfe..7364ab98e5 100644
--- a/spec/bundler/bundler/lockfile_parser_spec.rb
+++ b/spec/bundler/bundler/lockfile_parser_spec.rb
@@ -95,134 +95,6 @@ RSpec.describe Bundler::LockfileParser do
end
end
- describe "X64_MINGW_LEGACY platform handling" do
- before { allow(Bundler::SharedHelpers).to receive(:find_gemfile).and_return(bundled_app("gems.rb")) }
-
- describe "when X64_MINGW_LEGACY is present alone" do
- let(:lockfile_with_legacy_platform) { <<~L }
- GEM
- remote: https://rubygems.org/
- specs:
- rake (10.3.2)
-
- PLATFORMS
- ruby
- x64-mingw32
-
- DEPENDENCIES
- rake
-
- BUNDLED WITH
- 3.6.9
- L
-
- context "when bundle is not frozen" do
- before { allow(Bundler).to receive(:frozen_bundle?).and_return(false) }
- subject { described_class.new(lockfile_with_legacy_platform) }
-
- it "replaces X64_MINGW_LEGACY with X64_MINGW" do
- allow(Bundler::SharedHelpers).to receive(:major_deprecation)
- expect(subject.platforms.map(&:to_s)).to contain_exactly("ruby", "x64-mingw-ucrt")
- expect(subject.platforms.map(&:to_s)).not_to include("x64-mingw32")
- end
-
- it "shows deprecation warning for replacement" do
- expect(Bundler::SharedHelpers).to receive(:major_deprecation).with(
- 2,
- "Found x64-mingw32 in lockfile, which is deprecated. Using x64-mingw-ucrt, the replacement for x64-mingw32 in modern rubies, instead. Support for x64-mingw32 will be removed in Bundler 4.0.",
- removed_message: "Found x64-mingw32 in lockfile, which is no longer supported as of Bundler 4.0."
- )
- subject
- end
- end
-
- context "when bundle is frozen" do
- before { allow(Bundler).to receive(:frozen_bundle?).and_return(true) }
- subject { described_class.new(lockfile_with_legacy_platform) }
-
- it "preserves X64_MINGW_LEGACY platform without replacement" do
- expect(subject.platforms.map(&:to_s)).to contain_exactly("ruby", "x64-mingw32")
- end
-
- it "does not show any deprecation warnings" do
- expect(Bundler::SharedHelpers).not_to receive(:major_deprecation)
- subject
- end
- end
- end
-
- describe "when both X64_MINGW_LEGACY and X64_MINGW are present" do
- let(:lockfile_with_both_platforms) { <<~L }
- GEM
- remote: https://rubygems.org/
- specs:
- rake (10.3.2)
-
- PLATFORMS
- ruby
- x64-mingw32
- x64-mingw-ucrt
-
- DEPENDENCIES
- rake
-
- BUNDLED WITH
- 3.6.9
- L
-
- context "when bundle is not frozen" do
- before { allow(Bundler).to receive(:frozen_bundle?).and_return(false) }
- subject { described_class.new(lockfile_with_both_platforms) }
-
- it "removes X64_MINGW_LEGACY and keeps X64_MINGW" do
- allow(Bundler::SharedHelpers).to receive(:major_deprecation)
- expect(subject.platforms.map(&:to_s)).to contain_exactly("ruby", "x64-mingw-ucrt")
- expect(subject.platforms.map(&:to_s)).not_to include("x64-mingw32")
- end
-
- it "shows deprecation warning for removing legacy platform" do
- expect(Bundler::SharedHelpers).to receive(:major_deprecation).with(
- 2,
- "Found x64-mingw32 in lockfile, which is deprecated. Removing it. Support for x64-mingw32 will be removed in Bundler 4.0.",
- removed_message: "Found x64-mingw32 in lockfile, which is no longer supported as of Bundler 4.0."
- )
- subject
- end
- end
- end
-
- describe "when no X64_MINGW_LEGACY platform is present" do
- let(:lockfile_with_modern_platforms) { <<~L }
- GEM
- remote: https://rubygems.org/
- specs:
- rake (10.3.2)
-
- PLATFORMS
- ruby
- x64-mingw-ucrt
-
- DEPENDENCIES
- rake
-
- BUNDLED WITH
- 3.6.9
- L
-
- before { allow(Bundler).to receive(:frozen_bundle?).and_return(false) }
- subject { described_class.new(lockfile_with_modern_platforms) }
-
- it "preserves all modern platforms without changes" do
- expect(subject.platforms.map(&:to_s)).to contain_exactly("ruby", "x64-mingw-ucrt")
- end
-
- it "does not show any deprecation warnings" do
- expect(Bundler::SharedHelpers).not_to receive(:major_deprecation)
- subject
- end
- end
- end
-
describe "#initialize" do
before { allow(Bundler::SharedHelpers).to receive(:find_gemfile).and_return(bundled_app("gems.rb")) }
subject { described_class.new(lockfile_contents) }
@@ -257,6 +129,7 @@ RSpec.describe Bundler::LockfileParser do
shared_examples_for "parsing" do
it "parses correctly" do
+ expect(subject.valid?).to be(true)
expect(subject.sources).to eq sources
expect(subject.dependencies).to eq dependencies
expect(subject.specs).to eq specs
@@ -319,6 +192,87 @@ RSpec.describe Bundler::LockfileParser do
include_examples "parsing"
end
+ context "when the content does not contain any recognized lockfile sections" do
+ let(:lockfile_contents) { "hello world\nlorem ipsum\n" }
+
+ it "does not raise, is not valid, and deprecates" do
+ expect(Bundler::SharedHelpers).to receive(:feature_deprecated!).with(
+ /does not appear to be a valid lockfile.*future version of Bundler/m
+ )
+ parser = described_class.new(lockfile_contents)
+ expect(parser.valid?).to be(false)
+ expect(parser.specs).to eq([])
+ expect(parser.dependencies).to eq({})
+ end
+
+ it "does not raise when strict: true, and still deprecates" do
+ expect(Bundler::SharedHelpers).to receive(:feature_deprecated!).with(
+ /does not appear to be a valid lockfile.*future version of Bundler/m
+ )
+ parser = described_class.new(lockfile_contents, strict: true)
+ expect(parser.valid?).to be(false)
+ expect(parser.specs).to eq([])
+ expect(parser.dependencies).to eq({})
+ end
+ end
+
+ context "when the content looks like a Gemfile DSL" do
+ let(:lockfile_contents) { <<~G }
+ source "https://rubygems.org"
+ gem "rake"
+ G
+
+ it "does not raise, is not valid, and deprecates" do
+ expect(Bundler::SharedHelpers).to receive(:feature_deprecated!).with(
+ /does not appear to be a valid lockfile.*future version of Bundler/m
+ )
+ parser = described_class.new(lockfile_contents)
+ expect(parser.valid?).to be(false)
+ expect(parser.specs).to eq([])
+ expect(parser.dependencies).to eq({})
+ end
+
+ it "does not raise when strict: true, and still deprecates" do
+ expect(Bundler::SharedHelpers).to receive(:feature_deprecated!).with(
+ /does not appear to be a valid lockfile.*future version of Bundler/m
+ )
+ parser = described_class.new(lockfile_contents, strict: true)
+ expect(parser.valid?).to be(false)
+ expect(parser.specs).to eq([])
+ expect(parser.dependencies).to eq({})
+ end
+ end
+
+ context "when the content is empty" do
+ let(:lockfile_contents) { "" }
+
+ it "does not raise and is valid" do
+ expect { subject }.not_to raise_error
+ expect(subject.valid?).to be(true)
+ end
+ end
+
+ context "when lockfile_path is given" do
+ it "uses the provided path in error messages instead of looking up Bundler.default_lockfile" do
+ expect(Bundler::SharedHelpers).not_to receive(:relative_lockfile_path)
+ parser = described_class.new(lockfile_contents, lockfile_path: "custom/path.lock")
+ expect(parser.valid?).to be(true)
+ rake_spec = parser.specs.last
+ checksums = parser.sources.last.checksum_store.to_lock(rake_spec)
+ expected_checksum = Bundler::Checksum.from_lock(
+ "sha256=814828c34f1315d7e7b7e8295184577cc4e969bad6156ac069d02d63f58d82e8",
+ "custom/path.lock:20:17"
+ )
+ expect(checksums).to eq("#{rake_spec.lock_name} #{expected_checksum.to_lock}")
+ end
+
+ it "raises with the provided path when the lockfile contains merge conflicts" do
+ expect do
+ described_class.new("<<<<<<<\n", lockfile_path: "custom/path.lock")
+ end.to raise_error(Bundler::LockfileError, %r{custom/path\.lock contains merge conflicts})
+ end
+ 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 }
diff --git a/spec/bundler/bundler/override_spec.rb b/spec/bundler/bundler/override_spec.rb
new file mode 100644
index 0000000000..ad8be75520
--- /dev/null
+++ b/spec/bundler/bundler/override_spec.rb
@@ -0,0 +1,175 @@
+# frozen_string_literal: true
+
+RSpec.describe "MatchMetadata override-aware checks" do
+ let(:spec_class) do
+ Class.new do
+ include Bundler::MatchMetadata
+ attr_accessor :name
+ def initialize(name, ruby_req, rubygems_req)
+ @name = name
+ @required_ruby_version = ruby_req
+ @required_rubygems_version = rubygems_req
+ end
+ end
+ end
+
+ it "matches_current_metadata? ignores overrides (strict path)" do
+ spec = spec_class.new("rails", Gem::Requirement.new("< #{Gem.ruby_version}"), Gem::Requirement.default)
+ overrides = [Bundler::Override.new("rails", :required_ruby_version, :ignore_upper)]
+ # Strict method MUST NOT apply overrides; guards SelfManager and other generic callers.
+ expect(spec.matches_current_metadata?).to be(false)
+ expect(spec.matches_current_metadata_with_overrides?(overrides)).to be(true)
+ end
+
+ it "matches_current_ruby_with_overrides? returns the strict result for an empty override list" do
+ spec = spec_class.new("rails", Gem::Requirement.new(">= #{Gem.ruby_version}"), Gem::Requirement.default)
+ expect(spec.matches_current_ruby_with_overrides?([])).to be(true)
+ expect(spec.matches_current_ruby_with_overrides?(nil)).to be(true)
+ end
+
+ it "matches_current_rubygems_with_overrides? honors :all override" do
+ spec = spec_class.new("rails", Gem::Requirement.default, Gem::Requirement.new("< #{Gem.rubygems_version}"))
+ overrides = [Bundler::Override.new(:all, :required_rubygems_version, :ignore_upper)]
+ expect(spec.matches_current_rubygems_with_overrides?(overrides)).to be(true)
+ end
+end
+
+RSpec.describe "LazySpecification override propagation" do
+ let(:overrides) { [Bundler::Override.new("rails", :required_ruby_version, :ignore_upper)] }
+
+ it "carries overrides forward from a source LazySpec via from_spec" do
+ src = Bundler::LazySpecification.new("rails", "8.0", Gem::Platform::RUBY)
+ src.overrides = overrides
+ derived = Bundler::LazySpecification.from_spec(src)
+ expect(derived.overrides).to eq(overrides)
+ end
+
+ it "does not call respond_to? on the source spec, avoiding gemspec lazy load" do
+ # If from_spec used respond_to?(:overrides), a RemoteSpec source would
+ # force-load the backing gemspec. Use a stand-in object whose
+ # respond_to? raises to prove it is never asked.
+ src = Object.new
+ src.define_singleton_method(:name) { "rails" }
+ src.define_singleton_method(:version) { Gem::Version.new("8.0") }
+ src.define_singleton_method(:platform) { Gem::Platform::RUBY }
+ src.define_singleton_method(:source) { nil }
+ src.define_singleton_method(:runtime_dependencies) { [] }
+ src.define_singleton_method(:required_ruby_version) { Gem::Requirement.default }
+ src.define_singleton_method(:required_rubygems_version) { Gem::Requirement.default }
+ src.define_singleton_method(:respond_to?) {|*| raise "from_spec must not call respond_to?" }
+ expect { Bundler::LazySpecification.from_spec(src) }.not_to raise_error
+ end
+end
+
+RSpec.describe Bundler::Override do
+ describe ".find_for" do
+ it "returns the matching override by target and field" do
+ a = described_class.new("rails", :version, ">= 8.0")
+ b = described_class.new("nokogiri", :version, :ignore_upper)
+ expect(described_class.find_for([a, b], "rails", :version)).to be(a)
+ end
+
+ it "returns nil when no override matches the target" do
+ a = described_class.new("rails", :version, ">= 8.0")
+ expect(described_class.find_for([a], "sinatra", :version)).to be_nil
+ end
+
+ it "returns nil when no override matches the field" do
+ a = described_class.new("rails", :version, ">= 8.0")
+ expect(described_class.find_for([a], "rails", :required_ruby_version)).to be_nil
+ end
+
+ it "returns nil for an empty overrides list" do
+ expect(described_class.find_for([], "rails", :version)).to be_nil
+ end
+
+ it "falls back to an :all override on the same field" do
+ a = described_class.new(:all, :required_ruby_version, :ignore_upper)
+ expect(described_class.find_for([a], "rails", :required_ruby_version)).to be(a)
+ end
+
+ it "prefers a per-gem override over a matching :all override" do
+ per_gem = described_class.new("rails", :required_ruby_version, ">= 3.4")
+ all_target = described_class.new(:all, :required_ruby_version, :ignore_upper)
+ expect(described_class.find_for([all_target, per_gem], "rails", :required_ruby_version)).to be(per_gem)
+ end
+
+ it "does not fall back to :all when the field differs" do
+ a = described_class.new(:all, :required_ruby_version, :ignore_upper)
+ expect(described_class.find_for([a], "rails", :required_rubygems_version)).to be_nil
+ end
+ end
+
+ describe "#apply_to" do
+ context "when operation is a version spec string" do
+ it "replaces the existing requirement entirely" do
+ override = described_class.new("rails", :version, ">= 8.0")
+ result = override.apply_to(Gem::Requirement.new(">= 1.0", "< 2.0"))
+ expect(result).to eq(Gem::Requirement.new(">= 8.0"))
+ end
+
+ it "ignores the existing requirement regardless of its content" do
+ override = described_class.new("rails", :version, "= 1.0")
+ result = override.apply_to(Gem::Requirement.new(">= 99.0"))
+ expect(result).to eq(Gem::Requirement.new("= 1.0"))
+ end
+ end
+
+ context "when operation is :ignore_upper" do
+ it "removes < and <= operators" do
+ override = described_class.new("rails", :version, :ignore_upper)
+ result = override.apply_to(Gem::Requirement.new(">= 1.0", "< 2.0"))
+ expect(result).to eq(Gem::Requirement.new(">= 1.0"))
+ end
+
+ it "keeps >, >=, = operators" do
+ override = described_class.new("rails", :version, :ignore_upper)
+ result = override.apply_to(Gem::Requirement.new("> 1.0", "<= 2.0"))
+ expect(result).to eq(Gem::Requirement.new("> 1.0"))
+ end
+
+ it "converts ~> to >= preserving the lower bound" do
+ override = described_class.new("rails", :version, :ignore_upper)
+ result = override.apply_to(Gem::Requirement.new("~> 1.5"))
+ expect(result).to eq(Gem::Requirement.new(">= 1.5"))
+ end
+
+ it "preserves != exclusion constraints" do
+ override = described_class.new("rails", :version, :ignore_upper)
+ result = override.apply_to(Gem::Requirement.new(">= 1.0", "!= 1.5.0", "< 2.0"))
+ expect(result).to eq(Gem::Requirement.new(">= 1.0", "!= 1.5.0"))
+ end
+
+ it "returns the default requirement when only upper bounds remain" do
+ override = described_class.new("rails", :version, :ignore_upper)
+ result = override.apply_to(Gem::Requirement.new("< 2.0"))
+ expect(result).to eq(Gem::Requirement.default)
+ end
+
+ it "returns the default requirement when the input is nil" do
+ override = described_class.new("rails", :version, :ignore_upper)
+ expect(override.apply_to(nil)).to eq(Gem::Requirement.default)
+ end
+
+ it "returns the default requirement when the input is already the default" do
+ override = described_class.new("rails", :version, :ignore_upper)
+ expect(override.apply_to(Gem::Requirement.default)).to eq(Gem::Requirement.default)
+ end
+ end
+
+ context "when operation is nil" do
+ it "returns the default requirement" do
+ override = described_class.new("rails", :version, nil)
+ result = override.apply_to(Gem::Requirement.new(">= 1.0", "< 2.0"))
+ expect(result).to eq(Gem::Requirement.default)
+ end
+ end
+
+ context "when operation is unsupported" do
+ it "raises ArgumentError" do
+ override = described_class.new("rails", :version, 42)
+ expect { override.apply_to(Gem::Requirement.default) }.to raise_error(ArgumentError, /unsupported override operation/)
+ end
+ end
+ end
+end
diff --git a/spec/bundler/bundler/plugin/events_spec.rb b/spec/bundler/bundler/plugin/events_spec.rb
index 28d70c6fdd..77e5fdb74c 100644
--- a/spec/bundler/bundler/plugin/events_spec.rb
+++ b/spec/bundler/bundler/plugin/events_spec.rb
@@ -2,7 +2,17 @@
RSpec.describe Bundler::Plugin::Events do
context "plugin events" do
- before { Bundler::Plugin::Events.send :reset }
+ before do
+ @old_constants = Bundler::Plugin::Events.constants.map {|name| [name, Bundler::Plugin::Events.const_get(name)] }
+ Bundler::Plugin::Events.send :reset
+ end
+
+ after do
+ Bundler::Plugin::Events.send(:reset)
+ Hash[@old_constants].each do |name, value|
+ Bundler::Plugin::Events.send(:define, name, value)
+ end
+ end
describe "#define" do
it "raises when redefining a constant" do
diff --git a/spec/bundler/bundler/plugin/index_spec.rb b/spec/bundler/bundler/plugin/index_spec.rb
index 565fc9b088..a28934269b 100644
--- a/spec/bundler/bundler/plugin/index_spec.rb
+++ b/spec/bundler/bundler/plugin/index_spec.rb
@@ -193,4 +193,83 @@ RSpec.describe Bundler::Plugin::Index do
include_examples "it cleans up"
end
end
+
+ describe "relative plugin paths" do
+ let(:plugin_name) { "relative-plugin" }
+
+ before do
+ Bundler::Plugin.reset!
+ allow(Bundler::SharedHelpers).to receive(:find_gemfile).and_return(bundled_app_gemfile)
+
+ plugin_root = Bundler::Plugin.root
+ FileUtils.mkdir_p(plugin_root)
+
+ path = plugin_root.join(plugin_name)
+ FileUtils.mkdir_p(path.join("lib"))
+
+ index.register_plugin(plugin_name, path.to_s, [path.join("lib").to_s], [], [], [])
+ end
+
+ it "stores plugin paths relative to the plugin root" do
+ require "yaml"
+ data = YAML.load_file(index.index_file)
+
+ expect(data["plugin_paths"][plugin_name]).to eq(plugin_name)
+ expect(data["load_paths"][plugin_name]).to eq([File.join(plugin_name, "lib")])
+ end
+
+ it "expands relative paths to absolute on load" do
+ require "bundler/yaml_serializer"
+
+ plugin_root = Bundler::Plugin.root
+
+ relative_index = {
+ "commands" => {},
+ "hooks" => {},
+ "load_paths" => { plugin_name => [File.join(plugin_name, "lib")] },
+ "plugin_paths" => { plugin_name => plugin_name },
+ "sources" => {},
+ }
+
+ File.open(index.index_file, "w") {|f| f.puts Bundler::YAMLSerializer.dump(relative_index) }
+
+ new_index = Index.new
+ expect(new_index.plugin_path(plugin_name)).to eq(plugin_root.join(plugin_name))
+ expect(new_index.load_paths(plugin_name)).to eq([plugin_root.join(plugin_name, "lib").to_s])
+ end
+
+ it "keeps paths outside the plugin root as absolute" do
+ outside_path = tmp.join("outside", "external-plugin")
+ FileUtils.mkdir_p(outside_path.join("lib"))
+
+ index.register_plugin("external-plugin", outside_path.to_s, [outside_path.join("lib").to_s], [], [], [])
+
+ require "yaml"
+ data = YAML.load_file(index.index_file)
+
+ expect(data["plugin_paths"]["external-plugin"]).to eq(outside_path.to_s)
+ expect(data["load_paths"]["external-plugin"]).to eq([outside_path.join("lib").to_s])
+ end
+
+ it "reads legacy index files with absolute paths" do
+ require "bundler/yaml_serializer"
+
+ plugin_root = Bundler::Plugin.root
+ absolute_path = plugin_root.join(plugin_name).to_s
+
+ legacy_index = {
+ "commands" => {},
+ "hooks" => {},
+ "load_paths" => { plugin_name => [File.join(absolute_path, "lib")] },
+ "plugin_paths" => { plugin_name => absolute_path },
+ "sources" => {},
+ }
+
+ File.open(index.index_file, "w") {|f| f.puts Bundler::YAMLSerializer.dump(legacy_index) }
+
+ new_index = Index.new
+ expect(new_index.plugin_path(plugin_name)).to eq(Pathname.new(absolute_path))
+ expect(new_index.load_paths(plugin_name)).to eq([File.join(absolute_path, "lib")])
+ end
+ end
end
diff --git a/spec/bundler/bundler/plugin/installer_spec.rb b/spec/bundler/bundler/plugin/installer_spec.rb
index 8e1879395a..c200a98afa 100644
--- a/spec/bundler/bundler/plugin/installer_spec.rb
+++ b/spec/bundler/bundler/plugin/installer_spec.rb
@@ -47,6 +47,13 @@ RSpec.describe Bundler::Plugin::Installer do
build_plugin "re-plugin"
build_plugin "ma-plugin"
end
+
+ @previous_ui = Bundler.ui
+ Bundler.ui = Bundler::UI::Silent.new
+ end
+
+ after do
+ Bundler.ui = @previous_ui
end
context "git plugins" do
diff --git a/spec/bundler/bundler/plugin_spec.rb b/spec/bundler/bundler/plugin_spec.rb
index fea3925000..b379594c6f 100644
--- a/spec/bundler/bundler/plugin_spec.rb
+++ b/spec/bundler/bundler/plugin_spec.rb
@@ -65,8 +65,8 @@ RSpec.describe Bundler::Plugin do
end
it "passes the name and options to installer" do
- allow(index).to receive(:installed?).
- with("new-plugin")
+ allow(index).to receive(:up_to_date?).
+ with(spec)
allow(installer).to receive(:install).with(["new-plugin"], opts) do
{ "new-plugin" => spec }
end.once
@@ -75,8 +75,8 @@ RSpec.describe Bundler::Plugin do
end
it "validates the installed plugin" do
- allow(index).to receive(:installed?).
- with("new-plugin")
+ allow(index).to receive(:up_to_date?).
+ with(spec)
allow(subject).
to receive(:validate_plugin!).with(lib_path("new-plugin")).once
@@ -84,8 +84,8 @@ RSpec.describe Bundler::Plugin do
end
it "registers the plugin with index" do
- allow(index).to receive(:installed?).
- with("new-plugin")
+ allow(index).to receive(:up_to_date?).
+ with(spec)
allow(index).to receive(:register_plugin).
with("new-plugin", lib_path("new-plugin").to_s, [lib_path("new-plugin").join("lib").to_s], []).once
subject.install ["new-plugin"], opts
@@ -102,7 +102,7 @@ RSpec.describe Bundler::Plugin do
end.once
allow(subject).to receive(:validate_plugin!).twice
- allow(index).to receive(:installed?).twice
+ allow(index).to receive(:up_to_date?).twice
allow(index).to receive(:register_plugin).twice
subject.install ["new-plugin", "another-plugin"], opts
end
@@ -138,7 +138,7 @@ RSpec.describe Bundler::Plugin do
end
before do
- allow(index).to receive(:installed?) { nil }
+ allow(index).to receive(:up_to_date?) { nil }
allow(definition).to receive(:dependencies) { [Bundler::Dependency.new("new-plugin", ">=0"), Bundler::Dependency.new("another-plugin", ">=0")] }
allow(installer).to receive(:install_definition) { plugin_specs }
end
@@ -279,6 +279,7 @@ RSpec.describe Bundler::Plugin do
s.write "plugins.rb", code
end
+ @old_constants = Bundler::Plugin::Events.constants.map {|name| [name, Bundler::Plugin::Events.const_get(name)] }
Bundler::Plugin::Events.send(:reset)
Bundler::Plugin::Events.send(:define, :EVENT1, "event-1")
Bundler::Plugin::Events.send(:define, :EVENT2, "event-2")
@@ -291,6 +292,13 @@ RSpec.describe Bundler::Plugin do
allow(index).to receive(:load_paths).with("foo-plugin").and_return([])
end
+ after do
+ Bundler::Plugin::Events.send(:reset)
+ Hash[@old_constants].each do |name, value|
+ Bundler::Plugin::Events.send(:define, name, value)
+ end
+ end
+
let(:code) { <<-RUBY }
Bundler::Plugin::API.hook("event-1") { puts "hook for event 1" }
RUBY
diff --git a/spec/bundler/bundler/resolver/cooldown_spec.rb b/spec/bundler/bundler/resolver/cooldown_spec.rb
new file mode 100644
index 0000000000..37ec158cba
--- /dev/null
+++ b/spec/bundler/bundler/resolver/cooldown_spec.rb
@@ -0,0 +1,148 @@
+# frozen_string_literal: true
+
+RSpec.describe Bundler::Resolver do
+ let(:resolver) { described_class.allocate }
+
+ def remote(cooldown:)
+ instance_double(Bundler::Source::Rubygems::Remote, effective_cooldown: cooldown)
+ end
+
+ def spec(created_at:, remote:, name: "myrack", version: "1.0.0")
+ Struct.new(:name, :version, :created_at, :remote).new(name, Gem::Version.new(version), created_at, remote)
+ end
+
+ describe "#filter_cooldown" do
+ let(:now) { Time.now }
+
+ context "with a 7-day cooldown" do
+ let(:r) { remote(cooldown: 7) }
+
+ it "rejects versions published within the window" do
+ recent = spec(version: "1.1.0", created_at: now - (2 * 86_400), remote: r)
+ old = spec(version: "1.0.0", created_at: now - (30 * 86_400), remote: r)
+
+ expect(resolver.send(:filter_cooldown, [recent, old])).to eq([old])
+ end
+
+ it "keeps versions published exactly at the threshold" do
+ boundary = spec(created_at: now - (7 * 86_400), remote: r)
+
+ expect(resolver.send(:filter_cooldown, [boundary])).to eq([boundary])
+ end
+
+ it "leaves rolling-delay history intact" do
+ # 7-day cooldown with frequent releases must still expose an older candidate.
+ in_cooldown = spec(version: "1.2.0", created_at: now - 86_400, remote: r)
+ also_in_cooldown = spec(version: "1.1.0", created_at: now - (3 * 86_400), remote: r)
+ eligible = spec(version: "1.0.0", created_at: now - (10 * 86_400), remote: r)
+
+ result = resolver.send(:filter_cooldown, [in_cooldown, also_in_cooldown, eligible])
+
+ expect(result).to eq([eligible])
+ end
+
+ it "drops every spec sharing an excluded [name, version] tuple" do
+ # The cooldown check is by version, not per-spec: a StubSpecification for an
+ # in-cooldown release would otherwise slip through on local install paths.
+ endpoint = spec(version: "2.0.0", created_at: now - 86_400, remote: r)
+ local_stub = Struct.new(:name, :version).new("myrack", Gem::Version.new("2.0.0"))
+ eligible = spec(version: "1.0.0", created_at: now - (30 * 86_400), remote: r)
+
+ result = resolver.send(:filter_cooldown, [endpoint, local_stub, eligible])
+
+ expect(result).to eq([eligible])
+ end
+
+ it "keeps stub-only versions that no endpoint marks as in cooldown" do
+ # If no remote spec carries created_at for a version, cooldown cannot judge it;
+ # the stub stays in.
+ local_only = Struct.new(:name, :version).new("myrack", Gem::Version.new("2.0.0"))
+ eligible = spec(version: "1.0.0", created_at: now - (30 * 86_400), remote: r)
+
+ result = resolver.send(:filter_cooldown, [local_only, eligible])
+
+ expect(result).to eq([local_only, eligible])
+ end
+ end
+
+ context "when created_at is missing (blank metadata)" do
+ it "keeps the spec regardless of cooldown" do
+ s = spec(created_at: nil, remote: remote(cooldown: 7))
+
+ expect(resolver.send(:filter_cooldown, [s])).to eq([s])
+ end
+ end
+
+ context "when the remote has no cooldown" do
+ it "keeps every spec" do
+ s = spec(created_at: now - 3600, remote: remote(cooldown: nil))
+
+ expect(resolver.send(:filter_cooldown, [s])).to eq([s])
+ end
+ end
+
+ context "when cooldown is 0" do
+ it "keeps every spec (escape hatch)" do
+ s = spec(created_at: now - 3600, remote: remote(cooldown: 0))
+
+ expect(resolver.send(:filter_cooldown, [s])).to eq([s])
+ end
+ end
+
+ context "when the spec does not respond to created_at" do
+ it "keeps the spec" do
+ bare = Struct.new(:version).new("1.0.0")
+
+ expect(resolver.send(:filter_cooldown, [bare])).to eq([bare])
+ end
+ end
+
+ context "when the spec has no remote" do
+ it "keeps the spec" do
+ s = spec(created_at: now - 86_400, remote: nil)
+
+ expect(resolver.send(:filter_cooldown, [s])).to eq([s])
+ end
+ end
+
+ it "returns the same array when input is empty" do
+ expect(resolver.send(:filter_cooldown, [])).to eq([])
+ end
+ end
+
+ describe "#cooldown_hint" do
+ let(:now) { Time.now }
+ let(:r) { remote(cooldown: 7) }
+
+ it "returns nil when no spec is excluded" do
+ expect(resolver.send(:cooldown_hint, [])).to be_nil
+ end
+
+ it "returns nil when every spec is outside the cooldown window" do
+ eligible = [spec(created_at: now - (30 * 86_400), remote: r)]
+
+ expect(resolver.send(:cooldown_hint, eligible)).to be_nil
+ end
+
+ it "mentions the count and the bypass flag for one excluded version" do
+ excluded = [spec(created_at: now - 86_400, remote: r)]
+
+ hint = resolver.send(:cooldown_hint, excluded)
+
+ expect(hint).to match(/1 version excluded by the cooldown setting/)
+ expect(hint).to match(/--cooldown 0/)
+ end
+
+ it "uses plural wording when multiple versions are excluded" do
+ excluded = %w[1.0.0 1.1.0 1.2.0].map {|v| spec(version: v, created_at: now - 86_400, remote: r) }
+
+ expect(resolver.send(:cooldown_hint, excluded)).to match(/3 versions excluded/)
+ end
+
+ it "counts each unique version once even when multiple spec instances share it" do
+ duplicates = Array.new(3) { spec(created_at: now - 86_400, remote: r) }
+
+ expect(resolver.send(:cooldown_hint, duplicates)).to match(/1 version excluded/)
+ end
+ end
+end
diff --git a/spec/bundler/bundler/retry_spec.rb b/spec/bundler/bundler/retry_spec.rb
index ffbc078074..5c84d0bea5 100644
--- a/spec/bundler/bundler/retry_spec.rb
+++ b/spec/bundler/bundler/retry_spec.rb
@@ -12,7 +12,7 @@ RSpec.describe Bundler::Retry do
end
it "returns the first valid result" do
- jobs = [proc { raise "foo" }, proc { :bar }, proc { raise "foo" }]
+ jobs = [proc { raise "job 1 failed" }, proc { :bar }, proc { raise "job 2 failed" }]
attempts = 0
result = Bundler::Retry.new(nil, nil, 3).attempt do
attempts += 1
@@ -78,4 +78,113 @@ RSpec.describe Bundler::Retry do
end
end
end
+
+ context "exponential backoff" do
+ it "can be disabled by setting base_delay to 0" do
+ attempts = 0
+ expect do
+ Bundler::Retry.new("test", [], 2, base_delay: 0).attempt do
+ attempts += 1
+ raise "error"
+ end
+ end.to raise_error(StandardError)
+
+ # Verify no sleep was called (implicitly - if sleep was called, timing would be different)
+ expect(attempts).to eq(3)
+ end
+
+ it "is enabled by default with 1 second base delay" do
+ original_base_delay = Bundler::Retry.default_base_delay
+ Bundler::Retry.default_base_delay = 1.0
+
+ attempts = 0
+ sleep_times = []
+
+ allow_any_instance_of(Bundler::Retry).to receive(:sleep) do |_instance, delay|
+ sleep_times << delay
+ end
+
+ expect do
+ Bundler::Retry.new("test", [], 2, jitter: 0).attempt do
+ attempts += 1
+ raise "error"
+ end
+ end.to raise_error(StandardError)
+
+ expect(attempts).to eq(3)
+ expect(sleep_times.length).to eq(2)
+ # First retry: 1.0 * 2^0 = 1.0
+ expect(sleep_times[0]).to eq(1.0)
+ # Second retry: 1.0 * 2^1 = 2.0
+ expect(sleep_times[1]).to eq(2.0)
+ ensure
+ Bundler::Retry.default_base_delay = original_base_delay
+ end
+
+ it "sleeps with exponential backoff when base_delay is set" do
+ attempts = 0
+ sleep_times = []
+
+ allow_any_instance_of(Bundler::Retry).to receive(:sleep) do |_instance, delay|
+ sleep_times << delay
+ end
+
+ expect do
+ Bundler::Retry.new("test", [], 2, base_delay: 1.0, jitter: 0).attempt do
+ attempts += 1
+ raise "error"
+ end
+ end.to raise_error(StandardError)
+
+ expect(attempts).to eq(3)
+ expect(sleep_times.length).to eq(2)
+ # First retry: 1.0 * 2^0 = 1.0
+ expect(sleep_times[0]).to eq(1.0)
+ # Second retry: 1.0 * 2^1 = 2.0
+ expect(sleep_times[1]).to eq(2.0)
+ end
+
+ it "respects max_delay" do
+ sleep_times = []
+
+ allow_any_instance_of(Bundler::Retry).to receive(:sleep) do |_instance, delay|
+ sleep_times << delay
+ end
+
+ expect do
+ Bundler::Retry.new("test", [], 3, base_delay: 10.0, max_delay: 15.0, jitter: 0).attempt do
+ raise "error"
+ end
+ end.to raise_error(StandardError)
+
+ # First retry: 10.0 * 2^0 = 10.0
+ expect(sleep_times[0]).to eq(10.0)
+ # Second retry: 10.0 * 2^1 = 20.0, capped at 15.0
+ expect(sleep_times[1]).to eq(15.0)
+ # Third retry: 10.0 * 2^2 = 40.0, capped at 15.0
+ expect(sleep_times[2]).to eq(15.0)
+ end
+
+ it "adds jitter to delay" do
+ sleep_times = []
+
+ allow_any_instance_of(Bundler::Retry).to receive(:sleep) do |_instance, delay|
+ sleep_times << delay
+ end
+
+ expect do
+ Bundler::Retry.new("test", [], 2, base_delay: 1.0, jitter: 0.5).attempt do
+ raise "error"
+ end
+ end.to raise_error(StandardError)
+
+ expect(sleep_times.length).to eq(2)
+ # First retry should be between 1.0 and 1.5 (base + jitter)
+ expect(sleep_times[0]).to be >= 1.0
+ expect(sleep_times[0]).to be <= 1.5
+ # Second retry should be between 2.0 and 2.5
+ expect(sleep_times[1]).to be >= 2.0
+ expect(sleep_times[1]).to be <= 2.5
+ end
+ end
end
diff --git a/spec/bundler/bundler/ruby_dsl_spec.rb b/spec/bundler/bundler/ruby_dsl_spec.rb
index 2607f746e7..45a37c5795 100644
--- a/spec/bundler/bundler/ruby_dsl_spec.rb
+++ b/spec/bundler/bundler/ruby_dsl_spec.rb
@@ -178,11 +178,34 @@ RSpec.describe Bundler::RubyDsl do
let(:file_content) do
<<~TOML
[tools]
- ruby = "#{version}"
+ ruby = #{quote}#{version}#{quote}
TOML
end
- it_behaves_like "it stores the ruby version"
+ context "with double quotes" do
+ let(:quote) { '"' }
+
+ it_behaves_like "it stores the ruby version"
+ end
+
+ context "with single quotes" do
+ let(:quote) { "'" }
+
+ it_behaves_like "it stores the ruby version"
+ end
+
+ context "with mismatched quotes" do
+ let(:file_content) do
+ <<~TOML
+ [tools]
+ ruby = "#{version}'
+ TOML
+ end
+
+ it "raises an error" do
+ expect { subject }.to raise_error(Bundler::InvalidArgumentError, "= is not a valid requirement on the Ruby version")
+ end
+ end
end
context "with a .tool-versions file format" do
@@ -210,6 +233,16 @@ RSpec.describe Bundler::RubyDsl do
it_behaves_like "it stores the ruby version"
end
end
+
+ context "when the file does not exist" do
+ let(:ruby_version_file_path) { nil }
+ let(:ruby_version_arg) { nil }
+ let(:file) { "nonexistent.txt" }
+
+ it "raises an error" do
+ expect { subject }.to raise_error(Bundler::GemfileError, /Could not find version file nonexistent.txt/)
+ end
+ end
end
end
end
diff --git a/spec/bundler/bundler/ruby_version_spec.rb b/spec/bundler/bundler/ruby_version_spec.rb
index 39d0571361..0d41ec9901 100644
--- a/spec/bundler/bundler/ruby_version_spec.rb
+++ b/spec/bundler/bundler/ruby_version_spec.rb
@@ -100,7 +100,7 @@ RSpec.describe "Bundler::RubyVersion and its subclasses" do
describe "#to_s" do
it "should return info string with the ruby version, patchlevel, engine, and engine version" do
- expect(subject.to_s).to eq("ruby 2.0.0p645 (jruby 2.0.1)")
+ expect(subject.to_s).to eq("ruby 2.0.0 (jruby 2.0.1)")
end
context "no patchlevel" do
@@ -115,7 +115,7 @@ RSpec.describe "Bundler::RubyVersion and its subclasses" do
let(:engine) { "ruby" }
it "should return info string with the ruby version and patchlevel" do
- expect(subject.to_s).to eq("ruby 2.0.0p645")
+ expect(subject.to_s).to eq("ruby 2.0.0")
end
end
@@ -137,7 +137,7 @@ RSpec.describe "Bundler::RubyVersion and its subclasses" do
end
end
- context "the versions, pathlevels, engines, and engine_versions match" do
+ shared_examples_for "the versions, engines, and engine_versions match" do
it "should return true" do
expect(subject).to eq(other_ruby_version)
end
@@ -152,7 +152,7 @@ RSpec.describe "Bundler::RubyVersion and its subclasses" do
context "the patchlevels do not match" do
let(:other_patchlevel) { "21" }
- it_behaves_like "two ruby versions are not equal"
+ it_behaves_like "the versions, engines, and engine_versions match"
end
context "the engines do not match" do
@@ -228,9 +228,9 @@ RSpec.describe "Bundler::RubyVersion and its subclasses" do
end
end
- shared_examples_for "there is a difference in the patchlevels" do
- it "should return a tuple with :patchlevel and the two different patchlevels" do
- expect(ruby_version.diff(other_ruby_version)).to eq([:patchlevel, patchlevel, other_patchlevel])
+ shared_examples_for "even there is a difference in the patchlevels" do
+ it "should return nil" do
+ expect(ruby_version.diff(other_ruby_version)).to be_nil
end
end
@@ -287,10 +287,10 @@ RSpec.describe "Bundler::RubyVersion and its subclasses" do
it_behaves_like "there is a difference in the engine versions"
end
- context "detects patchlevel discrepancies last" do
+ context "ignores patchlevel discrepancies last" do
let(:other_patchlevel) { "643" }
- it_behaves_like "there is a difference in the patchlevels"
+ it_behaves_like "even there is a difference in the patchlevels"
end
context "successfully matches gem requirements" do
@@ -355,7 +355,7 @@ RSpec.describe "Bundler::RubyVersion and its subclasses" do
let(:other_engine) { "ruby" }
let(:other_engine_version) { "2.0.5" }
- it_behaves_like "there is a difference in the patchlevels"
+ it_behaves_like "even there is a difference in the patchlevels"
end
context "successfully detects bad gem requirements with engine versions" do
@@ -389,7 +389,7 @@ RSpec.describe "Bundler::RubyVersion and its subclasses" do
context "and comparing with a patchlevel that is not -1" do
let(:other_patchlevel) { "642" }
- it_behaves_like "there is a difference in the patchlevels"
+ it_behaves_like "even there is a difference in the patchlevels"
end
end
end
diff --git a/spec/bundler/bundler/rubygems_ext_spec.rb b/spec/bundler/bundler/rubygems_ext_spec.rb
new file mode 100644
index 0000000000..0fc528f78c
--- /dev/null
+++ b/spec/bundler/bundler/rubygems_ext_spec.rb
@@ -0,0 +1,39 @@
+# frozen_string_literal: true
+
+require "bundler/rubygems_ext"
+
+RSpec.describe Gem::SplitCompactIndexEntryOnFirstColon do
+ # Reproduces the RubyGems < 4.0.13 `Gem::Resolver::APISet::GemParser` that
+ # split each compact index entry on every colon, corrupting metadata values
+ # that themselves contain colons.
+ let(:legacy_parser_class) do
+ Class.new do
+ def parse_dependency(string)
+ dependency = string.split(":")
+ dependency[-1] = dependency[-1].split("&") if dependency.size > 1
+ dependency[0] = -dependency[0]
+ dependency
+ end
+ end
+ end
+
+ before { legacy_parser_class.prepend(described_class) }
+
+ it "preserves colon-bearing metadata values such as created_at timestamps" do
+ parser = legacy_parser_class.new
+
+ expect(parser.send(:parse_dependency, "created_at:2026-05-12T10:00:00Z")).to eq(["created_at", ["2026-05-12T10:00:00Z"]])
+ end
+
+ it "still parses ordinary name:requirement entries" do
+ parser = legacy_parser_class.new
+
+ expect(parser.send(:parse_dependency, "myrack:>= 1.0")).to eq(["myrack", [">= 1.0"]])
+ end
+
+ it "keeps parse_dependency private" do
+ parser = legacy_parser_class.new
+
+ expect { parser.parse_dependency("created_at:x") }.to raise_error(NoMethodError, /private method/)
+ end
+end
diff --git a/spec/bundler/bundler/settings_spec.rb b/spec/bundler/bundler/settings_spec.rb
index 592db81e9b..5e1aaaa555 100644
--- a/spec/bundler/bundler/settings_spec.rb
+++ b/spec/bundler/bundler/settings_spec.rb
@@ -119,6 +119,11 @@ that would suck --ehhh=oh geez it looks like i might have broken bundler somehow
settings.set_local :ssl_verify_mode, "1"
expect(settings[:ssl_verify_mode]).to be 1
end
+
+ it "coerces cooldown to integer" do
+ settings.set_local :cooldown, "7"
+ expect(settings[:cooldown]).to be 7
+ end
end
context "when it's not possible to create the settings directory" do
@@ -318,12 +323,12 @@ 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")
+ bundle_config("BUNDLE_MY__PERSONAL.MYRACK" => "~/Work/git/myrack")
expect(settings["my.personal.myrack"]).to eq("~/Work/git/myrack")
end
it "converts older keys without trailing slashes and double underscore" do
- config("BUNDLE_MIRROR__HTTPS://RUBYGEMS.ORG" => "http://example-mirror.rubygems.org")
+ bundle_config("BUNDLE_MIRROR__HTTPS://RUBYGEMS.ORG" => "http://example-mirror.rubygems.org")
expect(settings["mirror.https://rubygems.org/"]).to eq("http://example-mirror.rubygems.org")
end
@@ -337,7 +342,7 @@ that would suck --ehhh=oh geez it looks like i might have broken bundler somehow
end
it "converts older keys with dashes" do
- config("BUNDLE_MY-PERSONAL-SERVER__ORG" => "my-personal-server.org")
+ bundle_config("BUNDLE_MY-PERSONAL-SERVER__ORG" => "my-personal-server.org")
expect(Bundler.ui).to receive(:warn).with(
"Your #{bundled_app(".bundle/config")} config includes `BUNDLE_MY-PERSONAL-SERVER__ORG`, which contains the dash character (`-`).\n" \
"This is deprecated, because configuration through `ENV` should be possible, but `ENV` keys cannot include dashes.\n" \
@@ -347,8 +352,29 @@ that would suck --ehhh=oh geez it looks like i might have broken bundler somehow
end
it "reads newer keys format properly" do
- config("BUNDLE_MIRROR__HTTPS://RUBYGEMS__ORG/" => "http://example-mirror.rubygems.org")
+ bundle_config("BUNDLE_MIRROR__HTTPS://RUBYGEMS__ORG/" => "http://example-mirror.rubygems.org")
expect(settings["mirror.https://rubygems.org/"]).to eq("http://example-mirror.rubygems.org")
end
end
+
+ describe "default_cli_command validation" do
+ it "accepts 'install' as a valid value" do
+ expect { settings.set_local("default_cli_command", "install") }.not_to raise_error
+ end
+
+ it "accepts 'cli_help' as a valid value" do
+ expect { settings.set_local("default_cli_command", "cli_help") }.not_to raise_error
+ end
+
+ it "rejects invalid values" do
+ expect { settings.set_local("default_cli_command", "invalid") }.to raise_error(
+ Bundler::InvalidOption,
+ /Setting `default_cli_command` to "invalid" failed:\n - default_cli_command must be either 'install' or 'cli_help'\n - must be one of: install, cli_help/
+ )
+ end
+
+ it "accepts nil values" do
+ expect { settings.set_local("default_cli_command", nil) }.not_to raise_error
+ end
+ end
end
diff --git a/spec/bundler/bundler/shared_helpers_spec.rb b/spec/bundler/bundler/shared_helpers_spec.rb
index 3568580701..41115aa667 100644
--- a/spec/bundler/bundler/shared_helpers_spec.rb
+++ b/spec/bundler/bundler/shared_helpers_spec.rb
@@ -159,7 +159,7 @@ RSpec.describe Bundler::SharedHelpers do
let(:pwd_stub) { nil }
it "returns the current absolute path" do
- expect(subject.pwd).to eq(source_root)
+ expect(subject.pwd).to eq(git_root.to_s)
end
end
@@ -515,34 +515,4 @@ RSpec.describe Bundler::SharedHelpers do
end
end
end
-
- describe "#major_deprecation" do
- before { allow(Bundler).to receive(:feature_flag).and_return(Bundler::FeatureFlag.new(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 492eee6444..1f10ca4b07 100644
--- a/spec/bundler/bundler/source/git/git_proxy_spec.rb
+++ b/spec/bundler/bundler/source/git/git_proxy_spec.rb
@@ -2,7 +2,7 @@
RSpec.describe Bundler::Source::Git::GitProxy do
let(:path) { Pathname("path") }
- let(:uri) { "https://github.com/rubygems/rubygems.git" }
+ let(:uri) { "https://github.com/ruby/rubygems.git" }
let(:ref) { nil }
let(:branch) { nil }
let(:tag) { nil }
@@ -10,7 +10,9 @@ RSpec.describe Bundler::Source::Git::GitProxy do
let(:revision) { nil }
let(:git_source) { nil }
let(:clone_result) { double(Process::Status, success?: true) }
+ let(:fail_result) { double(Process::Status, success?: false) }
let(:base_clone_args) { ["clone", "--bare", "--no-hardlinks", "--quiet", "--no-tags", "--depth", "1", "--single-branch"] }
+ let(:base_fetch_args) { ["fetch", "--force", "--quiet", "--no-tags", "--depth", "1"] }
subject(:git_proxy) { described_class.new(path, uri, options, revision, git_source) }
context "with explicit ref" do
@@ -64,7 +66,7 @@ RSpec.describe Bundler::Source::Git::GitProxy 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])
+ expect(git_proxy).to receive(:capture).with([*base_clone_args, "--", "https://u:p@github.com/ruby/rubygems.git", path.to_s], nil).and_return(["", "", clone_result])
subject.checkout
end
end
@@ -72,13 +74,13 @@ RSpec.describe Bundler::Source::Git::GitProxy do
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])
+ expect(git_proxy).to receive(:capture).with([*base_clone_args, "--", "https://u:p@github.com/ruby/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
+ Bundler.settings.temporary("https://u:p@github.com/ruby/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])
subject.checkout
@@ -87,7 +89,7 @@ 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"
+ original = "https://orig:info@github.com/ruby/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])
@@ -99,7 +101,7 @@ 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(described_class).to receive(:full_version).
and_return("git version 1.2.3")
end
@@ -114,7 +116,7 @@ RSpec.describe Bundler::Source::Git::GitProxy do
context "with a OSX version number" do
before do
- expect(git_proxy).to receive(:git_local).with("--version").
+ expect(described_class).to receive(:full_version).
and_return("git version 1.2.3 (Apple Git-BS)")
end
@@ -129,7 +131,7 @@ RSpec.describe Bundler::Source::Git::GitProxy do
context "with a msysgit version number" do
before do
- expect(git_proxy).to receive(:git_local).with("--version").
+ expect(described_class).to receive(:full_version).
and_return("git version 1.2.3.msysgit.0")
end
@@ -146,8 +148,9 @@ 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").
- and_return("git version 1.2.3")
+ status = double("success?" => true)
+ expect(Open3).to receive(:capture3).with("git", "--version").
+ and_return(["git version 1.2.3", "", status])
end
it "returns the git version number" do
@@ -157,8 +160,9 @@ RSpec.describe Bundler::Source::Git::GitProxy do
context "with a OSX version number" do
before do
- expect(git_proxy).to receive(:git_local).with("--version").
- and_return("git version 1.2.3 (Apple Git-BS)")
+ status = double("success?" => true)
+ expect(Open3).to receive(:capture3).with("git", "--version").
+ and_return(["git version 1.2.3 (Apple Git-BS)", "", status])
end
it "does not strip out OSX specific additions in the version string" do
@@ -168,8 +172,9 @@ RSpec.describe Bundler::Source::Git::GitProxy do
context "with a msysgit version number" do
before do
- expect(git_proxy).to receive(:git_local).with("--version").
- and_return("git version 1.2.3.msysgit.0")
+ status = double("success?" => true)
+ expect(Open3).to receive(:capture3).with("git", "--version").
+ and_return(["git version 1.2.3.msysgit.0", "", status])
end
it "does not strip out msysgit specific additions in the version string" do
@@ -199,14 +204,13 @@ RSpec.describe Bundler::Source::Git::GitProxy do
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) }
+ let(:uri) { "http://github.com/ruby/rubygems.git" }
+ let(:clone_args_without_depth) { ["clone", "--bare", "--no-hardlinks", "--quiet", "--no-tags", "--single-branch"] }
- it "retries without --depth when git url is http and fails" do
+ it "retries clone without --depth when dumb http transport 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])
+ expect(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_result])
+ expect(git_proxy).to receive(:capture).with([*clone_args_without_depth, "--", uri, path.to_s], nil).and_return(["", "", clone_result])
subject.checkout
end
@@ -332,6 +336,19 @@ RSpec.describe Bundler::Source::Git::GitProxy do
subject.checkout
end
end
+
+ context "URI is HTTP" do
+ let(:uri) { "http://github.com/ruby/rubygems.git" }
+
+ it "retries fetch without --depth when dumb http transport fails" do
+ parsed_revision = Digest::SHA1.hexdigest("ruby")
+ allow(git_proxy).to receive(:git_local).with("rev-parse", "--abbrev-ref", "HEAD", dir: path).and_return(parsed_revision)
+ allow(git_proxy).to receive(:git_local).with("--version").and_return("git version 2.14.0")
+ expect(git_proxy).to receive(:capture).with([*base_fetch_args, "--", uri, "refs/heads/#{parsed_revision}:refs/heads/#{parsed_revision}"], path).and_return(["", "dumb http transport does not support shallow capabilities", fail_result])
+ expect(git_proxy).to receive(:capture).with(["fetch", "--force", "--quiet", "--no-tags", "--", uri, "refs/heads/#{parsed_revision}:refs/heads/#{parsed_revision}"], path).and_return(["", "", clone_result])
+ subject.checkout
+ end
+ end
end
end
end
diff --git a/spec/bundler/bundler/source/rubygems/remote_spec.rb b/spec/bundler/bundler/source/rubygems/remote_spec.rb
index f2214ca8fe..27430d4a3b 100644
--- a/spec/bundler/bundler/source/rubygems/remote_spec.rb
+++ b/spec/bundler/bundler/source/rubygems/remote_spec.rb
@@ -169,4 +169,39 @@ RSpec.describe Bundler::Source::Rubygems::Remote do
end
end
end
+
+ describe "#cooldown" do
+ it "is nil by default" do
+ expect(remote(uri_no_auth).cooldown).to be_nil
+ end
+
+ it "returns the value passed to the constructor" do
+ r = Bundler::Source::Rubygems::Remote.new(uri_no_auth, cooldown: 7)
+ expect(r.cooldown).to eq(7)
+ end
+ end
+
+ describe "#effective_cooldown" do
+ it "returns the per-remote value when no override is set" do
+ r = Bundler::Source::Rubygems::Remote.new(uri_no_auth, cooldown: 7)
+ expect(r.effective_cooldown).to eq(7)
+ end
+
+ it "returns nil when neither override nor per-remote value is set" do
+ expect(remote(uri_no_auth).effective_cooldown).to be_nil
+ end
+
+ it "settings override per-remote value" do
+ r = Bundler::Source::Rubygems::Remote.new(uri_no_auth, cooldown: 7)
+ Bundler.settings.temporary(cooldown: 14) do
+ expect(r.effective_cooldown).to eq(14)
+ end
+ end
+
+ it "settings override even when per-remote value is absent" do
+ Bundler.settings.temporary(cooldown: 14) do
+ expect(remote(uri_no_auth).effective_cooldown).to eq(14)
+ end
+ end
+ end
end
diff --git a/spec/bundler/bundler/source/rubygems_spec.rb b/spec/bundler/bundler/source/rubygems_spec.rb
index 884fa81046..feb787498e 100644
--- a/spec/bundler/bundler/source/rubygems_spec.rb
+++ b/spec/bundler/bundler/source/rubygems_spec.rb
@@ -44,4 +44,61 @@ RSpec.describe Bundler::Source::Rubygems do
end
end
end
+
+ describe "#clear_cache" do
+ it "invalidates memoized indexes so subsequent reads rebuild them" do
+ source = described_class.new
+
+ first_specs = source.specs
+ first_installed = source.send(:installed_specs)
+ first_default = source.send(:default_specs)
+ first_cached = source.send(:cached_specs)
+
+ expect(source.specs).to equal(first_specs)
+ expect(source.send(:installed_specs)).to equal(first_installed)
+ expect(source.send(:default_specs)).to equal(first_default)
+ expect(source.send(:cached_specs)).to equal(first_cached)
+
+ source.clear_cache
+
+ expect(source.specs).not_to equal(first_specs)
+ expect(source.send(:installed_specs)).not_to equal(first_installed)
+ expect(source.send(:default_specs)).not_to equal(first_default)
+ expect(source.send(:cached_specs)).not_to equal(first_cached)
+ end
+
+ it "reflects newly-discovered installed gems after clear_cache" do
+ source = described_class.new
+ foo = Gem::Specification.new("foo", "1.0.0")
+ bar = Gem::Specification.new("bar", "1.0.0")
+
+ allow(Bundler.rubygems).to receive(:installed_specs).and_return([foo])
+ expect(source.send(:installed_specs).search("bar")).to be_empty
+
+ allow(Bundler.rubygems).to receive(:installed_specs).and_return([foo, bar])
+ expect(source.send(:installed_specs).search("bar")).to be_empty
+
+ source.clear_cache
+
+ expect(source.send(:installed_specs).search("bar")).not_to be_empty
+ end
+ end
+
+ describe "log debug information" do
+ it "log the time spent downloading and installing a gem" do
+ build_repo2 do
+ build_gem "warning"
+ end
+
+ gemfile_content = <<~G
+ source "https://gem.repo2"
+ gem "warning"
+ G
+
+ stdout = install_gemfile(gemfile_content, env: { "DEBUG" => "1" })
+
+ expect(stdout).to match(/Downloaded warning in: \d+\.\d+s/)
+ expect(stdout).to match(/Installed warning in: \d+\.\d+s/)
+ end
+ end
end
diff --git a/spec/bundler/bundler/source_list_spec.rb b/spec/bundler/bundler/source_list_spec.rb
index 13453cb2a3..61bd99b063 100644
--- a/spec/bundler/bundler/source_list_spec.rb
+++ b/spec/bundler/bundler/source_list_spec.rb
@@ -11,7 +11,7 @@ RSpec.describe Bundler::SourceList do
subject(:source_list) { Bundler::SourceList.new }
- let(:rubygems_aggregate) { Bundler::Source::Rubygems.new }
+ let(:global_rubygems_source) { Bundler::Source::Rubygems.new }
let(:metadata_source) { Bundler::Source::Metadata.new }
describe "adding sources" do
@@ -118,17 +118,23 @@ RSpec.describe Bundler::SourceList do
describe "#add_global_rubygems_remote" do
let!(:returned_source) { source_list.add_global_rubygems_remote("https://rubygems.org/") }
- it "returns the aggregate rubygems source" do
+ it "returns the global rubygems source" do
expect(returned_source).to be_instance_of(Bundler::Source::Rubygems)
end
- it "adds the provided remote to the beginning of the aggregate source" do
+ it "adds the provided remote to the beginning of the global 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/"),
]
end
+
+ it "records the per-remote cooldown when supplied" do
+ source_list.add_global_rubygems_remote("https://othersource.org", cooldown: 7)
+ expect(returned_source.cooldown_for(Gem::URI("https://othersource.org/"))).to eq(7)
+ expect(returned_source.cooldown_for(Gem::URI("https://rubygems.org/"))).to be_nil
+ end
end
describe "#add_plugin_source" do
@@ -156,21 +162,21 @@ RSpec.describe Bundler::SourceList do
end
describe "#all_sources" do
- it "includes the aggregate rubygems source when rubygems sources have been added" do
+ it "includes the global rubygems source when rubygems sources have been added" do
source_list.add_git_source("uri" => "git://host/path.git")
source_list.add_rubygems_source("remotes" => ["https://rubygems.org"])
source_list.add_path_source("path" => "/path/to/gem")
source_list.add_plugin_source("new_source", "uri" => "https://some.url/a")
- expect(source_list.all_sources).to include rubygems_aggregate
+ expect(source_list.all_sources).to include global_rubygems_source
end
- it "includes the aggregate rubygems source when no rubygems sources have been added" do
+ it "includes the global rubygems source when no rubygems sources have been added" do
source_list.add_git_source("uri" => "git://host/path.git")
source_list.add_path_source("path" => "/path/to/gem")
source_list.add_plugin_source("new_source", "uri" => "https://some.url/a")
- expect(source_list.all_sources).to include rubygems_aggregate
+ expect(source_list.all_sources).to include global_rubygems_source
end
it "returns sources of the same type in the reverse order that they were added" do
@@ -204,7 +210,7 @@ RSpec.describe Bundler::SourceList do
Bundler::Source::Rubygems.new("remotes" => ["https://third-rubygems.org"]),
Bundler::Source::Rubygems.new("remotes" => ["https://fourth-rubygems.org"]),
Bundler::Source::Rubygems.new("remotes" => ["https://fifth-rubygems.org"]),
- rubygems_aggregate,
+ global_rubygems_source,
metadata_source,
]
end
@@ -297,19 +303,19 @@ RSpec.describe Bundler::SourceList do
end
describe "#rubygems_sources" do
- it "includes the aggregate rubygems source when rubygems sources have been added" do
+ it "includes the global rubygems source when rubygems sources have been added" do
source_list.add_git_source("uri" => "git://host/path.git")
source_list.add_rubygems_source("remotes" => ["https://rubygems.org"])
source_list.add_path_source("path" => "/path/to/gem")
- expect(source_list.rubygems_sources).to include rubygems_aggregate
+ expect(source_list.rubygems_sources).to include global_rubygems_source
end
- it "returns only the aggregate rubygems source when no rubygems sources have been added" do
+ it "returns only the global rubygems source when no rubygems sources have been added" do
source_list.add_git_source("uri" => "git://host/path.git")
source_list.add_path_source("path" => "/path/to/gem")
- expect(source_list.rubygems_sources).to eq [rubygems_aggregate]
+ expect(source_list.rubygems_sources).to eq [global_rubygems_source]
end
it "returns rubygems sources in the reverse order that they were added" do
@@ -331,7 +337,7 @@ RSpec.describe Bundler::SourceList do
Bundler::Source::Rubygems.new("remotes" => ["https://third-rubygems.org"]),
Bundler::Source::Rubygems.new("remotes" => ["https://fourth-rubygems.org"]),
Bundler::Source::Rubygems.new("remotes" => ["https://fifth-rubygems.org"]),
- rubygems_aggregate,
+ global_rubygems_source,
]
end
end
@@ -442,6 +448,16 @@ RSpec.describe Bundler::SourceList do
end
end
+ describe "#clear_cache" do
+ let(:rubygems_source) { source_list.add_rubygems_source("remotes" => ["https://rubygems.org"]) }
+
+ it "calls #clear_cache on all rubygems sources" do
+ expect(rubygems_source).to receive(:clear_cache)
+ expect(source_list.global_rubygems_source).to receive(:clear_cache)
+ source_list.clear_cache
+ end
+ end
+
describe "implicit_global_source?" do
context "when a global rubygem source provided" do
it "returns a falsy value" do
diff --git a/spec/bundler/bundler/spec_set_spec.rb b/spec/bundler/bundler/spec_set_spec.rb
index c4b6676223..1e1ceadf26 100644
--- a/spec/bundler/bundler/spec_set_spec.rb
+++ b/spec/bundler/bundler/spec_set_spec.rb
@@ -43,6 +43,30 @@ RSpec.describe Bundler::SpecSet do
spec = described_class.new(specs).find_by_name_and_platform("b", platform)
expect(spec).to eq platform_spec
end
+
+ it "returns nil when the name is not present" do
+ spec = described_class.new(specs).find_by_name_and_platform("missing", platform)
+ expect(spec).to be_nil
+ end
+
+ it "returns nil when the name exists but no spec is installable on the requested platform" do
+ incompatible_platform = Gem::Platform.new("java")
+ incompatible_spec = build_spec("a", "1.0", incompatible_platform).first
+
+ spec = described_class.new([incompatible_spec]).find_by_name_and_platform("a", platform)
+ expect(spec).to be_nil
+ end
+
+ it "returns the first installable spec for the given name in insertion order" do
+ later_platform_spec = build_spec("b", "3.0", platform).first
+ specs = [
+ platform_spec,
+ later_platform_spec,
+ ]
+
+ spec = described_class.new(specs).find_by_name_and_platform("b", platform)
+ expect(spec).to eq platform_spec
+ end
end
describe "#to_a" do
@@ -55,5 +79,70 @@ RSpec.describe Bundler::SpecSet do
d-2.0
]
end
+
+ it "puts rake first when present" do
+ specs = [
+ build_spec("a", "1.0") {|s| s.dep "rake", ">= 0" },
+ build_spec("rake", "13.0"),
+ ].flatten
+
+ expect(described_class.new(specs).to_a.map(&:full_name)).to eq %w[
+ rake-13.0
+ a-1.0
+ ]
+ end
+ end
+
+ describe "#complete_platform" do
+ let(:platform) { Gem::Platform.new("x86_64-linux") }
+
+ let(:platform_variant) do
+ build_spec("needs_old_ruby", "1.0", platform).first.tap do |s|
+ s.required_ruby_version = Gem::Requirement.new("< #{Gem.ruby_version}")
+ end
+ end
+
+ let(:lazy_spec) do
+ lazy = Bundler::LazySpecification.new("needs_old_ruby", Gem::Version.new("1.0"), Gem::Platform::RUBY)
+ lazy.required_ruby_version = Gem::Requirement.new("< #{Gem.ruby_version}")
+ source = double("source")
+ source_specs = double("source_specs")
+ allow(source).to receive(:specs).and_return(source_specs)
+ allow(source_specs).to receive(:search).
+ with(["needs_old_ruby", Gem::Version.new("1.0")]).and_return([platform_variant])
+ lazy.source = source
+ lazy
+ end
+
+ it "rejects a platform variant whose strict metadata is incompatible when no override is attached" do
+ set = described_class.new([lazy_spec])
+ expect(set.send(:complete_platform, platform)).to be(false)
+ end
+
+ it "accepts a platform variant when the LazySpec carries an override that allows it" do
+ lazy_spec.overrides = [Bundler::Override.new("needs_old_ruby", :required_ruby_version, :ignore_upper)]
+ set = described_class.new([lazy_spec])
+ expect(set.send(:complete_platform, platform)).to be(true)
+ end
+
+ it "carries overrides onto a synthesized LazySpec so a follow-up complete_platform still honors them" do
+ override = Bundler::Override.new("needs_old_ruby", :required_ruby_version, :ignore_upper)
+ lazy_spec.overrides = [override]
+ second_platform = Gem::Platform.new("aarch64-linux")
+ second_variant = build_spec("needs_old_ruby", "1.0", second_platform).first.tap do |s|
+ s.required_ruby_version = Gem::Requirement.new("< #{Gem.ruby_version}")
+ end
+ allow(lazy_spec.source.specs).to receive(:search).
+ with(["needs_old_ruby", Gem::Version.new("1.0")]).and_return([platform_variant, second_variant])
+
+ set = described_class.new([lazy_spec])
+ expect(set.send(:complete_platform, platform)).to be(true)
+ # The synthesized x86_64-linux variant is now in the set. If lookup
+ # picks it as exemplar for the next platform check, the override list
+ # must still be reachable via its overrides accessor.
+ synthesized = set.to_a.find {|s| s.platform == platform }
+ expect(synthesized.overrides).to eq([override])
+ expect(set.send(:complete_platform, second_platform)).to be(true)
+ end
end
end
diff --git a/spec/bundler/bundler/stub_specification_spec.rb b/spec/bundler/bundler/stub_specification_spec.rb
index beb966b3ce..f2faa2ea64 100644
--- a/spec/bundler/bundler/stub_specification_spec.rb
+++ b/spec/bundler/bundler/stub_specification_spec.rb
@@ -49,10 +49,14 @@ RSpec.describe Bundler::StubSpecification do
expect(stub.missing_extensions?).to be false
end
- it "returns true if not manually_installed?" do
+ it "returns #{RUBY_ENGINE == "jruby" ? "false" : "true"} if not manually_installed?" do
stub = described_class.from_stub(with_bundler_stub_spec)
stub.installed_by_version = Gem::Version.new(1)
- expect(stub.missing_extensions?).to be true
+ if RUBY_ENGINE == "jruby"
+ expect(stub.missing_extensions?).to be false
+ else
+ expect(stub.missing_extensions?).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..83f147191e 100644
--- a/spec/bundler/bundler/ui/shell_spec.rb
+++ b/spec/bundler/bundler/ui/shell_spec.rb
@@ -81,4 +81,32 @@ RSpec.describe Bundler::UI::Shell do
end
end
end
+
+ describe "threads" do
+ it "is thread safe when using with_level" do
+ stop_thr1 = false
+ stop_thr2 = false
+
+ expect(subject.level).to eq("debug")
+
+ thr1 = Thread.new do
+ subject.silence do
+ sleep(0.1) until stop_thr1
+ end
+
+ stop_thr2 = true
+ end
+
+ thr2 = Thread.new do
+ subject.silence do
+ stop_thr1 = true
+ sleep(0.1) until stop_thr2
+ end
+ end
+
+ [thr1, thr2].each(&:join)
+
+ expect(subject.level).to eq("debug")
+ end
+ end
end
diff --git a/spec/bundler/bundler/uri_normalizer_spec.rb b/spec/bundler/bundler/uri_normalizer_spec.rb
new file mode 100644
index 0000000000..1308e86014
--- /dev/null
+++ b/spec/bundler/bundler/uri_normalizer_spec.rb
@@ -0,0 +1,25 @@
+# frozen_string_literal: true
+
+RSpec.describe Bundler::URINormalizer do
+ describe ".normalize_suffix" do
+ context "when trailing_slash is true" do
+ it "adds a trailing slash when missing" do
+ expect(described_class.normalize_suffix("https://example.com", trailing_slash: true)).to eq("https://example.com/")
+ end
+
+ it "keeps the trailing slash when present" do
+ expect(described_class.normalize_suffix("https://example.com/", trailing_slash: true)).to eq("https://example.com/")
+ end
+ end
+
+ context "when trailing_slash is false" do
+ it "removes a trailing slash when present" do
+ expect(described_class.normalize_suffix("https://example.com/", trailing_slash: false)).to eq("https://example.com")
+ end
+
+ it "keeps the value unchanged when no trailing slash exists" do
+ expect(described_class.normalize_suffix("https://example.com", trailing_slash: false)).to eq("https://example.com")
+ end
+ end
+ end
+end
diff --git a/spec/bundler/bundler/worker_spec.rb b/spec/bundler/bundler/worker_spec.rb
index e4ebbd2932..2ad2845e37 100644
--- a/spec/bundler/bundler/worker_spec.rb
+++ b/spec/bundler/bundler/worker_spec.rb
@@ -20,6 +20,26 @@ RSpec.describe Bundler::Worker do
end
end
+ describe "priority queue" do
+ it "process elements from the priority queue first" do
+ processed_elements = []
+
+ function = proc do |element, _|
+ processed_elements << element
+ end
+
+ worker = described_class.new(1, "Spec Worker", function)
+ worker.instance_variable_set(:@threads, []) # Prevent the enqueueing from starting work.
+ worker.enq("Normal element")
+ worker.enq("Priority element", priority: true)
+ worker.send(:create_threads)
+
+ worker.stop
+
+ expect(processed_elements).to eq(["Priority element", "Normal element"])
+ end
+ end
+
describe "handling interrupts" do
let(:status) do
pid = Process.fork do
diff --git a/spec/bundler/cache/cache_path_spec.rb b/spec/bundler/cache/cache_path_spec.rb
index d5bd14965b..2a280ea858 100644
--- a/spec/bundler/cache/cache_path_spec.rb
+++ b/spec/bundler/cache/cache_path_spec.rb
@@ -17,7 +17,7 @@ RSpec.describe "bundle package" do
context "with config cache_path" do
it "caches gems at given path" do
- bundle "config set cache_path vendor/cache-foo"
+ bundle_config "cache_path vendor/cache-foo"
bundle :cache
expect(bundled_app("vendor/cache-foo/myrack-1.0.0.gem")).to exist
end
diff --git a/spec/bundler/cache/gems_spec.rb b/spec/bundler/cache/gems_spec.rb
index b23d475a5f..198279d84c 100644
--- a/spec/bundler/cache/gems_spec.rb
+++ b/spec/bundler/cache/gems_spec.rb
@@ -78,13 +78,13 @@ RSpec.describe "bundle cache" do
end
context "using system gems" do
- before { bundle "config set path.system true" }
+ before { bundle_config "path.system true" }
let(:path) { system_gem_path }
it_behaves_like "when there are only gemsources"
end
context "installing into a local path" do
- before { bundle "config set path ./.bundle" }
+ before { bundle_config "path ./.bundle" }
let(:path) { local_gem_path }
it_behaves_like "when there are only gemsources"
end
@@ -136,7 +136,7 @@ RSpec.describe "bundle cache" do
gem "json"
G
- bundle "config set cache_all_platforms true"
+ bundle_config "cache_all_platforms true"
bundle :cache
expect(bundled_app("vendor/cache/json-#{default_json_version}.gem")).to exist
@@ -157,14 +157,14 @@ RSpec.describe "bundle cache" do
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"
+ bundle_config "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"
+ bundle_config "path.system true"
install_gemfile <<-G
source "https://gem.repo1"
@@ -226,7 +226,7 @@ RSpec.describe "bundle cache" do
it "re-caches during install" do
setup_main_repo
- cached_gem("myrack-1.0.0").rmtree
+ FileUtils.rm_rf cached_gem("myrack-1.0.0")
bundle :install
expect(out).to include("Updating files in vendor/cache")
expect(cached_gem("myrack-1.0.0")).to exist
@@ -307,7 +307,7 @@ RSpec.describe "bundle cache" do
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
+ FileUtils.rm_rf cached_myrack
build_gem "myrack", "1.0.0",
path: cached_myrack.parent,
rubygems_version: "1.3.2"
@@ -338,7 +338,7 @@ RSpec.describe "bundle cache" do
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
+ FileUtils.rm_rf cached_gem("myrack-1.0.0")
build_gem "myrack", "1.0.0", path: bundled_app("vendor/cache")
checksums = checksums_section do |c|
@@ -362,14 +362,14 @@ RSpec.describe "bundle cache" do
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
+ FileUtils.rm_rf cached_gem("myrack-1.0.0")
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
+ FileUtils.rm_rf cached_gem("myrack-1.0.0")
build_gem "myrack", "1.0.0", path: bundled_app("vendor/cache")
pristine_system_gems
diff --git a/spec/bundler/cache/git_spec.rb b/spec/bundler/cache/git_spec.rb
index 66eaf65dd1..f0976ecac7 100644
--- a/spec/bundler/cache/git_spec.rb
+++ b/spec/bundler/cache/git_spec.rb
@@ -13,6 +13,22 @@ RSpec.describe "git base name" do
end
RSpec.describe "bundle cache with git" do
+ it "does not copy repository to vendor cache when cache_all set to false" do
+ git = build_git "foo"
+ ref = git.ref_for("main", 11)
+
+ install_gemfile <<-G
+ source "https://gem.repo1"
+ gem "foo", :git => '#{lib_path("foo-1.0")}'
+ G
+
+ bundle_config "cache_all false"
+ bundle :cache
+ expect(bundled_app("vendor/cache/foo-1.0-#{ref}")).not_to exist
+
+ expect(the_bundle).to include_gems "foo 1.0"
+ end
+
it "copies repository to vendor cache and uses it" do
git = build_git "foo"
ref = git.ref_for("main", 11)
@@ -22,7 +38,6 @@ RSpec.describe "bundle cache with git" do
gem "foo", :git => '#{lib_path("foo-1.0")}'
G
- bundle "config set cache_all true"
bundle :cache
expect(bundled_app("vendor/cache/foo-1.0-#{ref}")).to exist
expect(bundled_app("vendor/cache/foo-1.0-#{ref}/.git")).not_to exist
@@ -41,9 +56,8 @@ RSpec.describe "bundle cache with git" do
gem "foo", :git => '#{lib_path("foo-1.0")}'
G
- bundle "config set --local path vendor/bundle"
+ bundle_config "path vendor/bundle"
bundle "install"
- bundle "config set cache_all true"
bundle :cache
expect(bundled_app("vendor/cache/foo-1.0-#{ref}")).to exist
@@ -61,7 +75,6 @@ RSpec.describe "bundle cache with git" do
gem "foo", :git => '#{lib_path("foo-1.0")}'
G
- bundle "config set cache_all true"
bundle :cache
bundle :cache
@@ -79,7 +92,6 @@ RSpec.describe "bundle cache with git" do
gem "foo", :git => '#{lib_path("foo-1.0")}'
G
- bundle "config set cache_all true"
bundle :cache
update_git "foo" do |s|
@@ -109,7 +121,6 @@ RSpec.describe "bundle cache with git" do
gem "foo", :git => '#{lib_path("foo-1.0")}'
G
- bundle "config set cache_all true"
bundle :cache
update_git "foo" do |s|
@@ -140,7 +151,6 @@ RSpec.describe "bundle cache with git" do
bundle %(config set local.foo #{lib_path("foo-1.0")})
bundle "install"
- bundle "config set cache_all true"
bundle :cache
expect(bundled_app("vendor/cache/foo-invalid-#{ref}")).to exist
@@ -161,12 +171,12 @@ RSpec.describe "bundle cache with git" do
source "https://gem.repo1"
gem "foo", :git => '#{lib_path("foo-1.0")}'
G
- bundle "config set path vendor/bundle"
+ bundle_config "path vendor/bundle"
bundle :install
pristine_system_gems
with_path_as "" do
- bundle "config set deployment true"
+ bundle_config "deployment true"
bundle "install --local"
expect(the_bundle).to include_gem "foo 1.0"
end
@@ -179,11 +189,10 @@ RSpec.describe "bundle cache with git" do
source "https://gem.repo1"
gem "foo", :git => '#{lib_path("foo-1.0")}'
G
- bundle "config set cache_all true"
bundle :cache, "all-platforms" => true
pristine_system_gems
- bundle "config set frozen true"
+ bundle_config "frozen true"
bundle "install --local --verbose"
expect(out).to_not include("Fetching")
expect(the_bundle).to include_gem "foo 1.0"
@@ -196,11 +205,10 @@ RSpec.describe "bundle cache with git" do
source "https://gem.repo1"
gem "foo", :git => '#{lib_path("foo-1.0")}'
G
- bundle "config set cache_all true"
bundle :cache, "all-platforms" => true
pristine_system_gems
- bundle "config set frozen true"
+ bundle_config "frozen true"
bundle "install --local --verbose"
expect(out).to_not include("Fetching")
expect(the_bundle).to include_gem "foo 1.0"
@@ -213,11 +221,10 @@ RSpec.describe "bundle cache with git" do
source "https://gem.repo1"
gem "foo", :git => '#{lib_path("foo-1.0")}'
G
- bundle "config set cache_all true"
bundle :cache, "all-platforms" => true
pristine_system_gems
- bundle "config set frozen true"
+ bundle_config "frozen true"
# Remove untracked files (including the empty refs dir in the cache)
Dir.chdir(bundled_app) do
@@ -241,9 +248,8 @@ RSpec.describe "bundle cache with git" do
source "https://gem.repo1"
gem "foo", :git => '#{lib_path("foo-1.0")}'
G
- bundle "config set global_gem_cache false"
- bundle "config set cache_all true"
- bundle "config path vendor/bundle"
+ bundle_config "global_gem_cache false"
+ bundle_config "path vendor/bundle"
bundle :install
# Simulate old cache by copying the real cache folder to vendor/cache
@@ -273,9 +279,8 @@ RSpec.describe "bundle cache with git" do
source "https://gem.repo1"
gem "foo", :git => '#{lib_path("foo-1.0")}'
G
- bundle "config set global_gem_cache false"
- bundle "config set cache_all true"
- bundle "config path vendor/bundle"
+ bundle_config "global_gem_cache false"
+ bundle_config "path vendor/bundle"
bundle :install
# Simulate old cache by copying the real cache folder to vendor/cache
@@ -303,9 +308,8 @@ RSpec.describe "bundle cache with git" do
source "https://gem.repo1"
gem "foo", :git => '#{lib_path("foo-1.0")}'
G
- bundle "config set global_gem_cache false"
- bundle "config set cache_all true"
- bundle "config path vendor/bundle"
+ bundle_config "global_gem_cache false"
+ bundle_config "path vendor/bundle"
bundle :install
# Simulate old cache by copying the real cache folder to vendor/cache
@@ -342,7 +346,6 @@ RSpec.describe "bundle cache with git" do
G
ref = git.ref_for("main", 11)
- bundle "config set cache_all true"
bundle :cache
expect(bundled_app("vendor/cache/has_submodule-1.0-#{ref}")).to exist
@@ -362,7 +365,6 @@ RSpec.describe "bundle cache with git" do
source "https://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)
@@ -377,12 +379,11 @@ RSpec.describe "bundle cache with git" do
source "https://gem.repo1"
gem "foo", :git => '#{lib_path("foo-1.0")}'
G
- bundle "config set cache_all true"
bundle :cache, "all-platforms" => true, :install => false
pristine_system_gems
with_path_as "" do
- bundle "config set deployment true"
+ bundle_config "deployment true"
bundle :install, local: true
expect(the_bundle).to include_gem "foo 1.0"
end
@@ -417,7 +418,7 @@ RSpec.describe "bundle cache with git" do
foo!
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
# Simulate an old incorrect situation where vendor/cache would be the install location of git gems
@@ -436,7 +437,6 @@ RSpec.describe "bundle cache with git" do
source "https://gem.repo1"
gem "foo", :git => '#{lib_path("foo-1.0")}'
G
- bundle "config set cache_all true"
# The algorithm for the cache location for a git checkout is
# in Bundle::Source::Git#cache_path
@@ -498,7 +498,6 @@ RSpec.describe "bundle cache with git" do
end
FileUtils.mkdir_p(bundled_app("vendor/cache"))
- bundle "config set cache_all all"
install_gemfile <<-G
source "https://gem.repo1"
diff --git a/spec/bundler/cache/path_spec.rb b/spec/bundler/cache/path_spec.rb
index 526b7369ef..42648aea1f 100644
--- a/spec/bundler/cache/path_spec.rb
+++ b/spec/bundler/cache/path_spec.rb
@@ -9,7 +9,6 @@ RSpec.describe "bundle cache with path" do
gem "foo", :path => '#{bundled_app("lib/foo")}'
G
- bundle "config set cache_all true"
bundle :cache
expect(bundled_app("vendor/cache/foo-1.0")).not_to exist
expect(the_bundle).to include_gems "foo 1.0"
@@ -23,7 +22,6 @@ RSpec.describe "bundle cache with path" do
gem "foo", :path => '#{lib_path("foo-1.0")}'
G
- bundle "config set cache_all true"
bundle :cache
expect(bundled_app("vendor/cache/foo-1.0")).to exist
expect(bundled_app("vendor/cache/foo-1.0/.bundlecache")).to be_file
@@ -42,7 +40,6 @@ RSpec.describe "bundle cache with path" do
gem "#{libname}", :path => '#{libpath}'
G
- bundle "config set cache_all true"
bundle :cache
expect(bundled_app("vendor/cache/#{libname}")).to exist
expect(bundled_app("vendor/cache/#{libname}/.bundlecache")).to be_file
@@ -58,7 +55,6 @@ RSpec.describe "bundle cache with path" do
gem "foo", :path => '#{lib_path("foo-1.0")}'
G
- bundle "config set cache_all true"
bundle :cache
build_lib "foo" do |s|
@@ -81,7 +77,6 @@ RSpec.describe "bundle cache with path" do
gem "foo", :path => '#{lib_path("foo-1.0")}'
G
- bundle "config set cache_all true"
bundle :cache
expect(bundled_app("vendor/cache/foo-1.0")).to exist
@@ -97,20 +92,21 @@ 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" do
+ it "does not cache path gems if cache_all is set to false" do
build_lib "foo"
install_gemfile <<-G
source "https://gem.repo1"
gem "foo", :path => '#{lib_path("foo-1.0")}'
G
+ bundle_config "cache_all false"
bundle :cache
expect(err).to be_empty
expect(bundled_app("vendor/cache/foo-1.0")).not_to exist
end
- it "caches path gems by default", bundler: "4" do
+ it "caches path gems by default" do
build_lib "foo"
install_gemfile <<-G
@@ -122,48 +118,4 @@ RSpec.describe "bundle cache with path" do
expect(err).to be_empty
expect(bundled_app("vendor/cache/foo-1.0")).to exist
end
-
- it "stores the given flag" do
- build_lib "foo"
-
- install_gemfile <<-G
- source "https://gem.repo1"
- gem "foo", :path => '#{lib_path("foo-1.0")}'
- G
-
- bundle "config set cache_all true"
- bundle :cache
- build_lib "bar"
-
- install_gemfile <<-G
- source "https://gem.repo1"
- gem "foo", :path => '#{lib_path("foo-1.0")}'
- gem "bar", :path => '#{lib_path("bar-1.0")}'
- G
-
- bundle :cache
- expect(bundled_app("vendor/cache/bar-1.0")).to exist
- end
-
- it "can rewind chosen configuration" do
- build_lib "foo"
-
- install_gemfile <<-G
- source "https://gem.repo1"
- gem "foo", :path => '#{lib_path("foo-1.0")}'
- G
-
- bundle "config set cache_all true"
- bundle :cache
- build_lib "baz"
-
- gemfile <<-G
- source "https://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
- expect(bundled_app("vendor/cache/baz-1.0")).not_to exist
- end
end
diff --git a/spec/bundler/commands/add_spec.rb b/spec/bundler/commands/add_spec.rb
index 00aa6415e1..162650f2e5 100644
--- a/spec/bundler/commands/add_spec.rb
+++ b/spec/bundler/commands/add_spec.rb
@@ -38,34 +38,34 @@ RSpec.describe "bundle add" do
end
describe "without version specified" do
- it "version requirement becomes ~> major.minor.patch when resolved version is < 1.0" do
+ it "version requirement becomes >= major.minor.patch when resolved version is < 1.0" do
bundle "add 'bar'"
- expect(bundled_app_gemfile.read).to match(/gem "bar", "~> 0.12.3"/)
+ expect(bundled_app_gemfile.read).to match(/gem "bar", ">= 0.12.3"/)
expect(the_bundle).to include_gems "bar 0.12.3"
end
- it "version requirement becomes ~> major.minor when resolved version is > 1.0" do
+ it "version requirement becomes >= major.minor when resolved version is > 1.0" do
bundle "add 'baz'"
- expect(bundled_app_gemfile.read).to match(/gem "baz", "~> 1.2"/)
+ expect(bundled_app_gemfile.read).to match(/gem "baz", ">= 1.2"/)
expect(the_bundle).to include_gems "baz 1.2.3"
end
- it "version requirement becomes ~> major.minor.patch.pre when resolved version is < 1.0" do
+ it "version requirement becomes >= major.minor.patch.pre when resolved version is < 1.0" do
bundle "add 'cat'"
- expect(bundled_app_gemfile.read).to match(/gem "cat", "~> 0.12.3.pre"/)
+ expect(bundled_app_gemfile.read).to match(/gem "cat", ">= 0.12.3.pre"/)
expect(the_bundle).to include_gems "cat 0.12.3.pre"
end
- it "version requirement becomes ~> major.minor.pre when resolved version is > 1.0.pre" do
+ it "version requirement becomes >= major.minor.pre when resolved version is >= 1.0.pre" do
bundle "add 'dog'"
- expect(bundled_app_gemfile.read).to match(/gem "dog", "~> 1.1.pre"/)
+ 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
+ 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(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
@@ -100,13 +100,13 @@ RSpec.describe "bundle add" do
describe "with --group" do
it "adds dependency for the specified group" do
bundle "add 'foo' --group='development'"
- expect(bundled_app_gemfile.read).to match(/gem "foo", "~> 2.0", group: :development/)
+ expect(bundled_app_gemfile.read).to match(/gem "foo", ">= 2.0", group: :development/)
expect(the_bundle).to include_gems "foo 2.0"
end
it "adds dependency to more than one group" do
bundle "add 'foo' --group='development, test'"
- expect(bundled_app_gemfile.read).to match(/gem "foo", "~> 2.0", groups: \[:development, :test\]/)
+ expect(bundled_app_gemfile.read).to match(/gem "foo", ">= 2.0", groups: \[:development, :test\]/)
expect(the_bundle).to include_gems "foo 2.0"
end
end
@@ -115,7 +115,7 @@ RSpec.describe "bundle add" do
it "adds dependency with specified source" do
bundle "add 'foo' --source='https://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(%r{gem "foo", ">= 2.0", source: "https://gem.repo2"})
expect(the_bundle).to include_gems "foo 2.0"
end
end
@@ -124,7 +124,7 @@ RSpec.describe "bundle add" do
it "adds dependency with specified path" do
bundle "add 'foo' --path='#{lib_path("foo-2.0")}'"
- expect(bundled_app_gemfile.read).to match(/gem "foo", "~> 2.0", path: "#{lib_path("foo-2.0")}"/)
+ expect(bundled_app_gemfile.read).to match(/gem "foo", ">= 2.0", path: "#{lib_path("foo-2.0")}"/)
expect(the_bundle).to include_gems "foo 2.0"
end
end
@@ -133,7 +133,7 @@ RSpec.describe "bundle add" do
it "adds dependency with specified git source" do
bundle "add foo --git=#{lib_path("foo-2.0")}"
- expect(bundled_app_gemfile.read).to match(/gem "foo", "~> 2.0", git: "#{lib_path("foo-2.0")}"/)
+ expect(bundled_app_gemfile.read).to match(/gem "foo", ">= 2.0", git: "#{lib_path("foo-2.0")}"/)
expect(the_bundle).to include_gems "foo 2.0"
end
end
@@ -146,7 +146,7 @@ RSpec.describe "bundle add" do
it "adds dependency with specified git source and branch" do
bundle "add foo --git=#{lib_path("foo-2.0")} --branch=test"
- expect(bundled_app_gemfile.read).to match(/gem "foo", "~> 2.0", git: "#{lib_path("foo-2.0")}", branch: "test"/)
+ expect(bundled_app_gemfile.read).to match(/gem "foo", ">= 2.0", git: "#{lib_path("foo-2.0")}", branch: "test"/)
expect(the_bundle).to include_gems "foo 2.0"
end
end
@@ -155,7 +155,7 @@ RSpec.describe "bundle add" 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"))}"
- expect(bundled_app_gemfile.read).to match(/gem "foo", "~> 2\.0", git: "#{lib_path("foo-2.0")}", ref: "#{revision_for(lib_path("foo-2.0"))}"/)
+ expect(bundled_app_gemfile.read).to match(/gem "foo", ">= 2\.0", git: "#{lib_path("foo-2.0")}", ref: "#{revision_for(lib_path("foo-2.0"))}"/)
expect(the_bundle).to include_gems "foo 2.0"
end
end
@@ -169,39 +169,39 @@ RSpec.describe "bundle add" do
it "adds dependency with specified github source" 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\.\d+", github: "ruby\/rake"})
end
it "adds dependency with specified github source and branch" do
bundle "add rake --github=ruby/rake --branch=main"
- expect(bundled_app_gemfile.read).to match(%r{gem "rake", "~> 13\.\d+", github: "ruby\/rake", branch: "main"})
+ expect(bundled_app_gemfile.read).to match(%r{gem "rake", ">= 13\.\d+", github: "ruby\/rake", branch: "main"})
end
it "adds dependency with specified github source and ref" do
ref = revision_for(lib_path("rake-13.0"))
bundle "add rake --github=ruby/rake --ref=#{ref}"
- expect(bundled_app_gemfile.read).to match(%r{gem "rake", "~> 13\.\d+", github: "ruby\/rake", ref: "#{ref}"})
+ expect(bundled_app_gemfile.read).to match(%r{gem "rake", ">= 13\.\d+", github: "ruby\/rake", ref: "#{ref}"})
end
it "adds dependency with specified github source and glob" 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"})
+ expect(bundled_app_gemfile.read).to match(%r{gem "rake", ">= 13\.\d+", github: "ruby\/rake", glob: "\.\/\*\.gemspec"})
end
it "adds dependency with specified github source, branch and glob" do
bundle "add rake --github=ruby/rake --branch=main --glob='./*.gemspec'"
- expect(bundled_app_gemfile.read).to match(%r{gem "rake", "~> 13\.\d+", github: "ruby\/rake", branch: "main", glob: "\.\/\*\.gemspec"})
+ expect(bundled_app_gemfile.read).to match(%r{gem "rake", ">= 13\.\d+", github: "ruby\/rake", branch: "main", glob: "\.\/\*\.gemspec"})
end
it "adds dependency with specified github source, ref and glob" do
ref = revision_for(lib_path("rake-13.0"))
bundle "add rake --github=ruby/rake --ref=#{ref} --glob='./*.gemspec'"
- expect(bundled_app_gemfile.read).to match(%r{gem "rake", "~> 13\.\d+", github: "ruby\/rake", ref: "#{ref}", glob: "\.\/\*\.gemspec"})
+ expect(bundled_app_gemfile.read).to match(%r{gem "rake", ">= 13\.\d+", github: "ruby\/rake", ref: "#{ref}", glob: "\.\/\*\.gemspec"})
end
end
@@ -209,7 +209,7 @@ RSpec.describe "bundle add" 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(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
@@ -222,7 +222,7 @@ RSpec.describe "bundle add" do
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(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
@@ -231,11 +231,45 @@ RSpec.describe "bundle add" 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(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 mismatched pair in --git/--github, --branch/--ref" do
+ describe "with --git and --github" do
+ it "throws error" do
+ bundle "add 'foo' --git x --github y", raise_on_error: false
+
+ expect(err).to include("You cannot specify `--git` and `--github` at the same time.")
+ end
+ end
+
+ describe "with --branch and --ref with --git" do
+ it "throws error" do
+ bundle "add 'foo' --branch x --ref y --git file://git", raise_on_error: false
+
+ expect(err).to include("You cannot specify `--branch` and `--ref` at the same time.")
+ end
+ end
+
+ describe "with --branch but without --git or --github" do
+ it "throws error" do
+ bundle "add 'foo' --branch x", raise_on_error: false
+
+ expect(err).to include("You cannot specify `--branch` unless `--git` or `--github` is specified.")
+ end
+ end
+
+ describe "with --ref but without --git or --github" do
+ it "throws error" do
+ bundle "add 'foo' --ref y", raise_on_error: false
+
+ expect(err).to include("You cannot specify `--ref` unless `--git` or `--github` is specified.")
+ end
+ end
+ end
+
describe "with --skip-install" do
it "adds gem to Gemfile but is not installed" do
bundle "add foo --skip-install --version=2.0"
@@ -257,7 +291,7 @@ RSpec.describe "bundle add" do
end
it "shows error message when gem cannot be found" do
- bundle "config set force_ruby_platform true"
+ bundle_config "force_ruby_platform true"
bundle "add 'werk_it'", raise_on_error: false
expect(err).to match("Could not find gem 'werk_it' in")
@@ -274,13 +308,21 @@ RSpec.describe "bundle add" do
end
describe "with --optimistic" do
- it "adds optimistic version" do
+ it "ignores option" do
bundle "add 'foo' --optimistic"
expect(bundled_app_gemfile.read).to include %(gem "foo", ">= 2.0")
expect(the_bundle).to include_gems "foo 2.0"
end
end
+ describe "with --pessimistic" do
+ it "adds pessimistic version" do
+ bundle "add 'foo' --pessimistic"
+ expect(bundled_app_gemfile.read).to include %(gem "foo", "~> 2.0")
+ expect(the_bundle).to include_gems "foo 2.0"
+ end
+ end
+
describe "with --quiet option" do
it "is quiet when there are no warnings" do
bundle "add 'foo' --quiet"
@@ -322,18 +364,18 @@ RSpec.describe "bundle add" do
end
describe "with no option" do
- it "adds pessimistic version" do
+ it "adds optimistic version" do
bundle "add 'foo'"
- expect(bundled_app_gemfile.read).to include %(gem "foo", "~> 2.0")
+ expect(bundled_app_gemfile.read).to include %(gem "foo", ">= 2.0")
expect(the_bundle).to include_gems "foo 2.0"
end
end
- describe "with --optimistic and --strict" do
+ describe "with --pessimistic and --strict" do
it "throws error" do
- bundle "add 'foo' --strict --optimistic", raise_on_error: false
+ bundle "add 'foo' --strict --pessimistic", raise_on_error: false
- expect(err).to include("You cannot specify `--strict` and `--optimistic` at the same time")
+ expect(err).to include("You cannot specify `--strict` and `--pessimistic` at the same time")
end
end
@@ -341,8 +383,8 @@ RSpec.describe "bundle add" do
it "adds multiple gems to gemfile" do
bundle "add bar baz"
- expect(bundled_app_gemfile.read).to match(/gem "bar", "~> 0.12.3"/)
- expect(bundled_app_gemfile.read).to match(/gem "baz", "~> 1.2"/)
+ expect(bundled_app_gemfile.read).to match(/gem "bar", ">= 0.12.3"/)
+ expect(bundled_app_gemfile.read).to match(/gem "baz", ">= 1.2"/)
end
it "throws error if any of the specified gems are present in the gemfile with different version" do
diff --git a/spec/bundler/commands/binstubs_spec.rb b/spec/bundler/commands/binstubs_spec.rb
index e0424dcba4..af4d24a9e8 100644
--- a/spec/bundler/commands/binstubs_spec.rb
+++ b/spec/bundler/commands/binstubs_spec.rb
@@ -156,29 +156,20 @@ RSpec.describe "bundle binstubs <gem>" do
end
end
- context "--path" do
- it "sets the binstubs dir" do
- install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
- G
-
- bundle "binstubs myrack --path exec"
-
- expect(bundled_app("exec/myrackup")).to exist
+ context "with the binstubs dir configured" do
+ before do
+ bundle_config "bin exec"
end
- it "setting is saved for bundle install" do
+ it "creates the binstubs in the configured dir" do
install_gemfile <<-G
source "https://gem.repo1"
gem "myrack"
- gem "rails"
G
- bundle "binstubs myrack", path: "exec"
- bundle :install
+ bundle "binstubs myrack"
- expect(bundled_app("exec/rails")).to exist
+ expect(bundled_app("exec/myrackup")).to exist
end
end
@@ -201,11 +192,10 @@ RSpec.describe "bundle binstubs <gem>" do
expect(File.read(bundled_app("bin/myrackup"))).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
- end
+ it "generates a standalone binstub at the given path when configured" do
+ bundle_config "bin foo"
+ bundle "binstubs myrack --standalone"
+ expect(bundled_app("foo/myrackup")).to exist
end
context "when specified --all-platforms option" do
@@ -323,7 +313,7 @@ RSpec.describe "bundle binstubs <gem>" do
gem "myrack"
G
- bundle "config set auto_install 1"
+ bundle_config "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"
@@ -335,7 +325,7 @@ RSpec.describe "bundle binstubs <gem>" do
gem "myrack"
G
- bundle "config set auto_install 1"
+ bundle_config "auto_install 1"
bundle "binstubs myrack", env: { "BUNDLE_INSTALL" => "1" }
expect(out).not_to include("Installing myrack 1.0.0")
end
diff --git a/spec/bundler/commands/cache_spec.rb b/spec/bundler/commands/cache_spec.rb
index 20d817a47d..e223d07f7f 100644
--- a/spec/bundler/commands/cache_spec.rb
+++ b/spec/bundler/commands/cache_spec.rb
@@ -28,7 +28,7 @@ RSpec.describe "bundle cache" do
end
end
- context "with --all" do
+ context "with cache_all configured" do
context "without a gemspec" do
it "caches all dependencies except bundler itself" do
gemfile <<-D
@@ -37,7 +37,7 @@ RSpec.describe "bundle cache" do
gem 'bundler'
D
- bundle "config set cache_all true"
+ bundle_config "cache_all true"
bundle :cache
expect(bundled_app("vendor/cache/myrack-1.0.0.gem")).to exist
@@ -68,7 +68,7 @@ RSpec.describe "bundle cache" do
gemspec
D
- bundle "config set cache_all true"
+ bundle_config "cache_all true"
bundle :cache
expect(bundled_app("vendor/cache/myrack-1.0.0.gem")).to exist
@@ -100,7 +100,7 @@ RSpec.describe "bundle cache" do
gemspec
D
- bundle "config set cache_all true"
+ bundle_config "cache_all true"
bundle :cache
expect(bundled_app("vendor/cache/myrack-1.0.0.gem")).to exist
@@ -145,7 +145,7 @@ RSpec.describe "bundle cache" do
gemspec :name => 'mygem_test'
D
- bundle "config set cache_all true"
+ bundle_config "cache_all true"
bundle :cache
expect(bundled_app("vendor/cache/myrack-1.0.0.gem")).to exist
@@ -158,20 +158,6 @@ RSpec.describe "bundle cache" do
end
end
- context "with --path" do
- it "sets root directory for gems" do
- gemfile <<-D
- source "https://gem.repo1"
- gem 'myrack'
- D
-
- bundle "cache --path #{bundled_app("test")}"
-
- expect(the_bundle).to include_gems "myrack 1.0.0"
- expect(bundled_app("test/vendor/cache/")).to exist
- end
- end
-
context "with --no-install" do
it "puts the gems in vendor/cache but does not install them" do
gemfile <<-D
@@ -221,26 +207,15 @@ RSpec.describe "bundle cache" do
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, but prints a warning" do
- gemfile <<-D
- source "https://gem.repo1"
- gem 'myrack', :platforms => [:ruby_20, :x64_mingw_20]
- D
-
- bundle "cache --all-platforms"
- expect(err).to include("deprecated")
- expect(bundled_app("vendor/cache/myrack-1.0.0.gem")).to exist
- end
-
- it "prints an error when using legacy windows rubies", bundler: "4" do
+ it "prints a warn when using legacy windows rubies" do
gemfile <<-D
source "https://gem.repo1"
gem 'myrack', :platforms => [:ruby_20, :x64_mingw_20]
D
bundle "cache --all-platforms", raise_on_error: false
- expect(err).to include("removed")
- expect(bundled_app("vendor/cache/myrack-1.0.0.gem")).not_to exist
+ expect(err).to include("will be removed in the future")
+ expect(bundled_app("vendor/cache/myrack-1.0.0.gem")).to exist
end
it "does not attempt to install gems in without groups" do
@@ -252,7 +227,7 @@ RSpec.describe "bundle cache" do
end
end
- bundle "config set --local without wo"
+ bundle_config "without wo"
install_gemfile <<-G, artifice: "compact_index_extra_api"
source "https://main.repo"
gem "myrack"
@@ -268,14 +243,14 @@ RSpec.describe "bundle cache" do
expect(the_bundle).to include_gem "myrack 1.0"
expect(the_bundle).not_to include_gems "weakling", "uninstallable"
- bundle "config set --local without wo"
+ bundle_config "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"
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"
+ bundle_config "without wo"
gemfile <<-G
source "https://gem.repo1"
gem "myrack"
@@ -291,33 +266,107 @@ RSpec.describe "bundle cache" do
end
context "with frozen configured" do
+ let(:app_cache) { bundled_app("vendor/cache") }
+
before do
+ bundle_config "frozen true"
+ end
+
+ it "tries to install but fails when the lockfile is out of sync" do
gemfile <<-G
source "https://gem.repo1"
gem "myrack"
G
- bundle "install"
- end
+ lockfile <<-L
+ GEM
+ remote: https://gem.repo1/
+ specs:
+ myrack (1.0.0)
+ myrack-obama (1.0)
+ myrack
+
+ PLATFORMS
+ #{lockfile_platforms}
- subject do
- bundle "config set --local frozen true"
+ DEPENDENCIES
+ myrack
+ myrack-obama
+
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
bundle :cache, raise_on_error: false
+ expect(exitstatus).to eq(16)
+ expect(err).to include("frozen mode")
+ expect(err).to include("You have deleted from the Gemfile")
+ expect(err).to include("* myrack-obama")
+ bundle "env"
+ expect(out).to include("frozen")
end
- it "tries to install with frozen" do
- bundle "config set deployment true"
+ it "caches gems without installing when lockfile is in sync, and --no-install is passed, even if vendor/cache directory is initially empty" do
gemfile <<-G
source "https://gem.repo1"
gem "myrack"
- gem "myrack-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")
- bundle "env"
- expect(out).to include("frozen").or include("deployment")
+ lockfile <<-L
+ GEM
+ remote: https://gem.repo1/
+ specs:
+ myrack (1.0.0)
+
+ PLATFORMS
+ #{lockfile_platforms}
+
+ DEPENDENCIES
+ myrack
+
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+ FileUtils.mkdir_p app_cache
+
+ bundle "cache --no-install"
+ expect(out).not_to include("Installing myrack 1.0.0")
+ expect(out).to include("Fetching myrack 1.0.0")
+ expect(app_cache.join("myrack-1.0.0.gem")).to exist
+ end
+
+ it "completes a partial cache when lockfile is in sync, even if the already cached gem is no longer available remotely" do
+ build_repo4 do
+ build_gem "foo", "1.0.0"
+ end
+
+ build_gem "bar", "1.0.0", path: bundled_app("vendor/cache")
+
+ gemfile <<-G
+ source "https://gem.repo4"
+ gem "foo"
+ gem "bar"
+ G
+ lockfile <<-L
+ GEM
+ remote: https://gem.repo4/
+ specs:
+ foo (1.0.0)
+ bar (1.0.0)
+
+ PLATFORMS
+ #{lockfile_platforms}
+
+ DEPENDENCIES
+ foo
+ bar
+
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+
+ bundle "cache --no-install"
+ expect(out).to include("Fetching foo 1.0.0")
+ expect(out).not_to include("Fetching bar 1.0.0")
+ expect(app_cache.join("foo-1.0.0.gem")).to exist
+ expect(app_cache.join("bar-1.0.0.gem")).to exist
end
end
@@ -340,7 +389,7 @@ RSpec.describe "bundle cache" do
it "installs them properly from cache to a different path" do
bundle "cache"
- bundle "config set --local path vendor/bundle"
+ bundle_config "path vendor/bundle"
bundle "install --local"
end
end
@@ -374,8 +423,24 @@ RSpec.describe "bundle install with gem sources" do
pristine_system_gems
FileUtils.rm_r gem_repo2
- bundle "config set --local deployment true"
- bundle "config set --local path vendor/bundle"
+ bundle_config "deployment true"
+ bundle_config "path vendor/bundle"
+ bundle :install
+ expect(the_bundle).to include_gems "myrack 1.0.0"
+ end
+
+ it "does not hit the remote at all in non frozen mode either" do
+ build_repo2
+ install_gemfile <<-G
+ source "https://gem.repo2"
+ gem "myrack"
+ G
+
+ bundle :cache
+ pristine_system_gems
+ FileUtils.rm_r gem_repo2
+
+ bundle_config "path vendor/bundle"
bundle :install
expect(the_bundle).to include_gems "myrack 1.0.0"
end
@@ -391,8 +456,8 @@ RSpec.describe "bundle install with gem sources" do
pristine_system_gems
FileUtils.rm_r gem_repo2
- bundle "config set --local cache_all_platforms true"
- bundle "config set --local path vendor/bundle"
+ bundle_config "cache_all_platforms true"
+ bundle_config "path vendor/bundle"
bundle "install --local"
expect(out).not_to include("Fetching gem metadata")
expect(the_bundle).to include_gems "myrack 1.0.0"
@@ -437,12 +502,12 @@ RSpec.describe "bundle install with gem sources" do
foo
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
simulate_platform "x86_64-linux" do
- bundle "config set cache_all_platforms true"
- bundle "config set path vendor/bundle"
+ bundle_config "cache_all_platforms true"
+ bundle_config "path vendor/bundle"
bundle :cache, artifice: "compact_index", env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s }
# simulate removal of all remote gems
@@ -484,7 +549,7 @@ RSpec.describe "bundle install with gem sources" do
pristine_system_gems
- bundle "config set --local force_ruby_platform true"
+ bundle_config "force_ruby_platform true"
install_gemfile <<-G
source "https://gem.repo1"
@@ -507,7 +572,7 @@ RSpec.describe "bundle install with gem sources" do
FileUtils.cp gem_repo4("gems/bcrypt_pbkdf-1.1.1-arm64-darwin.gem"), app_cache
FileUtils.cp gem_repo4("gems/bcrypt_pbkdf-1.1.1.gem"), app_cache
- bundle "config cache_all_platforms true"
+ bundle_config "cache_all_platforms true"
lockfile <<~L
GEM
@@ -524,7 +589,7 @@ RSpec.describe "bundle install with gem sources" do
bcrypt_pbkdf
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
simulate_platform "arm64-darwin-23" do
diff --git a/spec/bundler/commands/check_spec.rb b/spec/bundler/commands/check_spec.rb
index 4793210e97..7fe6897ae3 100644
--- a/spec/bundler/commands/check_spec.rb
+++ b/spec/bundler/commands/check_spec.rb
@@ -88,7 +88,7 @@ RSpec.describe "bundle check" do
it "prints a generic error if gem git source is not checked out" do
build_git "foo", path: lib_path("foo")
- bundle "config path vendor/bundle"
+ bundle_config "path vendor/bundle"
install_gemfile <<-G
source "https://gem.repo1"
@@ -123,21 +123,8 @@ RSpec.describe "bundle check" do
expect(err).to include("Bundler can't satisfy your Gemfile's dependencies.")
end
- it "remembers --without option from install" do
- gemfile <<-G
- source "https://gem.repo1"
- group :foo do
- gem "myrack"
- end
- G
-
- bundle "install --without foo"
- bundle "check"
- expect(out).to include("The Gemfile's dependencies are satisfied")
- end
-
it "uses the without setting" do
- bundle "config set without foo"
+ bundle_config "without foo"
install_gemfile <<-G
source "https://gem.repo1"
group :foo do
@@ -155,7 +142,7 @@ RSpec.describe "bundle check" do
gem "myrack", :group => :foo
G
- bundle "config set --local without foo"
+ bundle_config "without foo"
bundle :install
gemfile <<-G
@@ -174,10 +161,10 @@ RSpec.describe "bundle check" do
gem "myrack"
G
- bundle "config set --local path vendor/bundle"
+ bundle_config "path vendor/bundle"
bundle :cache
- gem_command "uninstall myrack", env: { "GEM_HOME" => vendored_gems.to_s }
+ uninstall_gem("myrack", env: { "GEM_HOME" => vendored_gems.to_s })
bundle "check", raise_on_error: false
expect(err).to include("* myrack (1.0.0)")
@@ -264,7 +251,7 @@ RSpec.describe "bundle check" do
gem "foo"
G
- bundle "config set --local deployment true"
+ bundle_config "deployment true"
bundle "install"
FileUtils.rm(bundled_app_lock)
@@ -272,46 +259,6 @@ RSpec.describe "bundle check" do
expect(last_command).to be_failure
end
- context "--path" do
- context "after installing gems in the proper directory" do
- before do
- gemfile <<-G
- source "https://gem.repo1"
- gem "rails"
- G
- bundle "install --path vendor/bundle"
-
- FileUtils.rm_r(bundled_app(".bundle"))
- end
-
- it "returns success" do
- bundle "check --path vendor/bundle"
- expect(out).to include("The Gemfile's dependencies are satisfied")
- end
-
- it "should write to .bundle/config" do
- bundle "check --path vendor/bundle"
- bundle "check"
- end
- end
-
- context "after installing gems on a different directory" do
- before do
- install_gemfile <<-G
- source "https://gem.repo1"
- gem "rails"
- G
-
- bundle "check --path vendor/bundle", raise_on_error: false
- end
-
- it "returns false" do
- expect(exitstatus).to eq(1)
- expect(err).to match(/The following gems are missing/)
- end
- end
- end
-
describe "when locked" do
before :each do
system_gems "myrack-1.0.0"
@@ -389,7 +336,7 @@ RSpec.describe "bundle check" do
myrack
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
@@ -464,7 +411,7 @@ RSpec.describe "bundle check" do
depends_on_myrack!
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
end
@@ -535,7 +482,7 @@ RSpec.describe "bundle check" do
dex-dispatch-engine!
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
end
@@ -552,7 +499,7 @@ RSpec.describe "bundle check" do
build_gem "bar"
end
- bundle "config set path.system true"
+ bundle_config "path.system true"
# Add all gems to ensure all gems are installed so that a bundle check
# would be successful
@@ -617,7 +564,7 @@ RSpec.describe "bundle check" do
end
before do
- bundle "config set --local path vendor/bundle"
+ bundle_config "path vendor/bundle"
install_gemfile <<-G
source "https://gem.repo1"
diff --git a/spec/bundler/commands/clean_spec.rb b/spec/bundler/commands/clean_spec.rb
index fd5a0fdbca..c77859d378 100644
--- a/spec/bundler/commands/clean_spec.rb
+++ b/spec/bundler/commands/clean_spec.rb
@@ -25,8 +25,8 @@ RSpec.describe "bundle clean" do
gem "foo"
G
- bundle "config set path vendor/bundle"
- bundle "config set clean false"
+ bundle_config "path vendor/bundle"
+ bundle_config "clean false"
bundle "install"
gemfile <<-G
@@ -54,8 +54,8 @@ RSpec.describe "bundle clean" do
gem "foo"
G
- bundle "config set path vendor/bundle"
- bundle "config set clean false"
+ bundle_config "path vendor/bundle"
+ bundle_config "clean false"
bundle "install"
gemfile <<-G
@@ -84,8 +84,8 @@ RSpec.describe "bundle clean" do
gem "foo"
G
- bundle "config set path vendor/bundle"
- bundle "config set clean false"
+ bundle_config "path vendor/bundle"
+ bundle_config "clean false"
bundle "install"
gemfile <<-G
@@ -117,9 +117,9 @@ RSpec.describe "bundle clean" do
end
G
- bundle "config set path vendor/bundle"
+ bundle_config "path vendor/bundle"
bundle "install"
- bundle "config set without test_group"
+ bundle_config "without test_group"
bundle "install"
bundle :clean
@@ -145,7 +145,7 @@ RSpec.describe "bundle clean" do
end
G
- bundle "config set path vendor/bundle"
+ bundle_config "path vendor/bundle"
bundle "install"
bundle :clean
@@ -169,7 +169,7 @@ RSpec.describe "bundle clean" do
end
G
- bundle "config set path vendor/bundle"
+ bundle_config "path vendor/bundle"
bundle "install"
gemfile <<-G
@@ -210,7 +210,7 @@ RSpec.describe "bundle clean" do
FileUtils.mkdir_p(bundled_app("real-path"))
File.symlink(bundled_app("real-path"), bundled_app("symlink-path"))
- bundle "config set path #{bundled_app("symlink-path")}"
+ bundle_config "path #{bundled_app("symlink-path")}"
bundle "install"
bundle :clean
@@ -220,7 +220,7 @@ RSpec.describe "bundle clean" do
expect(bundled_app("symlink-path/#{Bundler.ruby_scope}/bundler/gems/foo-#{revision[0..11]}")).to exist
end
- it "removes old git gems" do
+ it "removes old git gems on bundle update" do
build_git "foo-bar", path: lib_path("foo-bar")
revision = revision_for(lib_path("foo-bar"))
@@ -233,7 +233,7 @@ RSpec.describe "bundle clean" do
end
G
- bundle "config set path vendor/bundle"
+ bundle_config "path vendor/bundle"
bundle "install"
update_git "foo-bar", path: lib_path("foo-bar")
@@ -265,7 +265,7 @@ RSpec.describe "bundle clean" do
gem "activesupport", :git => "#{lib_path("rails")}", :ref => '#{revision}'
G
- bundle "config set path vendor/bundle"
+ bundle_config "path vendor/bundle"
bundle "install"
bundle :clean
expect(out).to include("")
@@ -288,8 +288,8 @@ RSpec.describe "bundle clean" do
end
end
G
- bundle "config set path vendor/bundle"
- bundle "config set without test"
+ bundle_config "path vendor/bundle"
+ bundle_config "without test"
bundle "install"
bundle :clean
@@ -311,15 +311,15 @@ RSpec.describe "bundle clean" do
end
G
- bundle "config set path vendor/bundle"
- bundle "config set without development"
+ bundle_config "path vendor/bundle"
+ bundle_config "without development"
bundle "install"
bundle :clean
end
it "displays an error when used without --path" do
- bundle "config set path.system true"
+ bundle_config "path.system true"
install_gemfile <<-G
source "https://gem.repo1"
@@ -341,7 +341,7 @@ RSpec.describe "bundle clean" do
gem "foo"
G
- bundle "config set path vendor/bundle"
+ bundle_config "path vendor/bundle"
bundle "install"
gemfile <<-G
@@ -364,7 +364,7 @@ RSpec.describe "bundle clean" do
end
it "does not call clean automatically when using system gems" do
- bundle "config set path.system true"
+ bundle_config "path.system true"
install_gemfile <<-G
source "https://gem.repo1"
@@ -379,43 +379,18 @@ RSpec.describe "bundle clean" do
gem "myrack"
G
- gem_command :list
+ installed_gems_list
expect(out).to include("myrack (1.0.0)").and include("thin (1.0)")
end
- it "--clean should override the bundle setting on install" do
- gemfile <<-G
- source "https://gem.repo1"
-
- gem "thin"
- gem "myrack"
- G
- bundle "config set path vendor/bundle"
- bundle "config set clean false"
- bundle "install --clean true"
-
- gemfile <<-G
- source "https://gem.repo1"
-
- gem "myrack"
- G
- bundle "install"
-
- should_have_gems "myrack-1.0.0"
- should_not_have_gems "thin-1.0"
- end
-
- it "--clean should override the bundle setting on update" do
+ it "does not clean on bundle update when path has not been set" do
build_repo2
- gemfile <<-G
+ install_gemfile <<-G
source "https://gem.repo2"
gem "foo"
G
- bundle "config set path vendor/bundle"
- bundle "config set clean false"
- bundle "install --clean true"
update_repo2 do
build_gem "foo", "1.0.1"
@@ -423,11 +398,27 @@ RSpec.describe "bundle clean" do
bundle "update", all: true
- should_have_gems "foo-1.0.1"
- should_not_have_gems "foo-1.0"
+ files = Pathname.glob(default_bundle_path("*", "*"))
+ files.map! {|f| f.to_s.sub(default_bundle_path.to_s, "") }
+ expected_files = %W[
+ /bin/bundle
+ /bin/bundler
+ /cache/bundler-#{Bundler::VERSION}.gem
+ /cache/foo-1.0.1.gem
+ /cache/foo-1.0.gem
+ /gems/bundler-#{Bundler::VERSION}
+ /gems/foo-1.0
+ /gems/foo-1.0.1
+ /specifications/bundler-#{Bundler::VERSION}.gemspec
+ /specifications/foo-1.0.1.gemspec
+ /specifications/foo-1.0.gemspec
+ ]
+ expected_files += ["/bin/bundle.bat", "/bin/bundler.bat"] if Gem.win_platform?
+
+ expect(files.sort).to eq(expected_files.sort)
end
- it "automatically cleans when path has not been set", bundler: "5" do
+ it "will automatically clean on bundle update when path has not been set", bundler: "5" do
build_repo2
install_gemfile <<-G
@@ -442,8 +433,8 @@ RSpec.describe "bundle clean" do
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, "") }
+ files = Pathname.glob(local_gem_path("*", "*"))
+ files.map! {|f| f.to_s.sub(local_gem_path.to_s, "") }
expect(files.sort).to eq %w[
/cache/foo-1.0.1.gem
/gems/foo-1.0.1
@@ -451,14 +442,14 @@ RSpec.describe "bundle clean" do
]
end
- it "does not clean automatically on --path" do
+ it "does not clean automatically when path configured" do
gemfile <<-G
source "https://gem.repo1"
gem "thin"
gem "myrack"
G
- bundle "config set path vendor/bundle"
+ bundle_config "path vendor/bundle"
bundle "install"
gemfile <<-G
@@ -471,7 +462,7 @@ RSpec.describe "bundle clean" do
should_have_gems "myrack-1.0.0", "thin-1.0"
end
- it "does not clean on bundle update with --path" do
+ it "does not clean on bundle update when path configured" do
build_repo2
gemfile <<-G
@@ -479,7 +470,7 @@ RSpec.describe "bundle clean" do
gem "foo"
G
- bundle "config set path vendor/bundle"
+ bundle_config "path vendor/bundle"
bundle "install"
update_repo2 do
@@ -490,8 +481,8 @@ RSpec.describe "bundle clean" do
should_have_gems "foo-1.0", "foo-1.0.1"
end
- it "does not clean on bundle update when using --system" do
- bundle "config set path.system true"
+ it "does not clean on bundle update when installing to system gems" do
+ bundle_config "path.system true"
build_repo2
@@ -507,12 +498,12 @@ RSpec.describe "bundle clean" do
end
bundle :update, all: true
- gem_command :list
+ installed_gems_list
expect(out).to include("foo (1.0.1, 1.0)")
end
it "cleans system gems when --force is used" do
- bundle "config set path.system true"
+ bundle_config "path.system true"
gemfile <<-G
source "https://gem.repo1"
@@ -531,7 +522,7 @@ RSpec.describe "bundle clean" do
bundle "clean --force"
expect(out).to include("Removing foo (1.0)")
- gem_command :list
+ installed_gems_list
expect(out).not_to include("foo (1.0)")
expect(out).to include("myrack (1.0.0)")
end
@@ -565,7 +556,7 @@ RSpec.describe "bundle clean" do
expect(err).to include(system_gem_path.to_s)
expect(err).to include("grant write permissions")
- gem_command :list
+ installed_gems_list
expect(out).to include("foo (1.0)")
expect(out).to include("myrack (1.0.0)")
end
@@ -581,7 +572,7 @@ RSpec.describe "bundle clean" do
gem "foo", :git => "#{lib_path("foo-1.0")}"
G
- bundle "config set path vendor/bundle"
+ bundle_config "path vendor/bundle"
bundle "install"
# mimic 7 length git revisions in Gemfile.lock
@@ -591,7 +582,7 @@ RSpec.describe "bundle clean" do
end
lockfile(bundled_app_lock, gemfile_lock.join("\n"))
- bundle "config set path vendor/bundle"
+ bundle_config "path vendor/bundle"
bundle "install"
bundle :clean
@@ -602,7 +593,7 @@ RSpec.describe "bundle clean" do
end
it "when using --force on system gems, it doesn't remove binaries" do
- bundle "config set path.system true"
+ bundle_config "path.system true"
build_repo2 do
build_gem "bindir" do |s|
@@ -658,7 +649,7 @@ RSpec.describe "bundle clean" do
gem "bar", "1.0", :path => "#{relative_path}"
G
- bundle "config set path vendor/bundle"
+ bundle_config "path vendor/bundle"
bundle "install"
bundle :clean
end
@@ -671,8 +662,8 @@ RSpec.describe "bundle clean" do
gem "foo"
G
- bundle "config set path vendor/bundle"
- bundle "config set clean false"
+ bundle_config "path vendor/bundle"
+ bundle_config "clean false"
bundle "install"
gemfile <<-G
@@ -701,8 +692,8 @@ RSpec.describe "bundle clean" do
gem "foo"
G
- bundle "config set path vendor/bundle"
- bundle "config set clean false"
+ bundle_config "path vendor/bundle"
+ bundle_config "clean false"
bundle "install"
gemfile <<-G
@@ -731,10 +722,10 @@ RSpec.describe "bundle clean" do
gem "foo"
G
- bundle "config set path vendor/bundle"
- bundle "config set clean false"
+ bundle_config "path vendor/bundle"
+ bundle_config "clean false"
bundle "install"
- bundle "config set dry_run false"
+ bundle_config "dry_run false"
gemfile <<-G
source "https://gem.repo1"
@@ -763,8 +754,8 @@ RSpec.describe "bundle clean" do
gem "foo"
G
- bundle "config set path vendor/bundle"
- bundle "config set clean false"
+ bundle_config "path vendor/bundle"
+ bundle_config "clean false"
bundle "install"
gemfile <<-G
@@ -774,7 +765,7 @@ RSpec.describe "bundle clean" do
gem "weakling"
G
- bundle "config set auto_install 1"
+ bundle_config "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"
@@ -792,7 +783,7 @@ RSpec.describe "bundle clean" do
gem "very_simple_git_binary", :git => "#{lib_path("very_simple_git_binary-1.0")}", :ref => "#{revision}"
G
- bundle "config set path vendor/bundle"
+ bundle_config "path vendor/bundle"
bundle "install"
expect(vendored_gems("bundler/gems/extensions")).to exist
expect(vendored_gems("bundler/gems/very_simple_git_binary-1.0-#{revision[0..11]}")).to exist
@@ -813,7 +804,7 @@ RSpec.describe "bundle clean" do
gem "simple_binary"
G
- bundle "config set path vendor/bundle"
+ bundle_config "path vendor/bundle"
bundle "install"
very_simple_binary_extensions_dir =
@@ -853,7 +844,7 @@ RSpec.describe "bundle clean" do
gem "very_simple_git_binary", :git => "#{lib_path("very_simple_git_binary-1.0")}", :ref => "#{revision}"
G
- bundle "config set path vendor/bundle"
+ bundle_config "path vendor/bundle"
bundle "install"
very_simple_binary_extensions_dir =
@@ -897,8 +888,8 @@ RSpec.describe "bundle clean" do
G
bundle :lock
- bundle "config set without development"
- bundle "config set path vendor/bundle"
+ bundle_config "without development"
+ bundle_config "path vendor/bundle"
bundle "install", verbose: true
bundle :clean
@@ -907,4 +898,39 @@ RSpec.describe "bundle clean" do
expect(very_simple_binary_extensions_dir).to be_nil
end
+
+ it "does not remove the bundler version currently running" do
+ gemfile <<-G
+ source "https://gem.repo1"
+
+ gem "myrack"
+ G
+
+ bundle_config "path vendor/bundle"
+ bundle "install"
+
+ version = Bundler.gem_version.to_s
+ # Simulate that the locked bundler version is installed in the bundle path
+ # by creating the gem directory and gemspec (as would happen after bundle install with that version)
+ Pathname(vendored_gems("cache/bundler-#{version}.gem")).tap do |path|
+ FileUtils.touch(path)
+ end
+ FileUtils.touch(vendored_gems("gems/bundler-#{version}"))
+ Pathname(vendored_gems("specifications/bundler-#{version}.gemspec")).tap do |path|
+ path.write(<<~GEMSPEC)
+ Gem::Specification.new do |s|
+ s.name = "bundler"
+ s.version = "#{version}"
+ s.authors = ["bundler team"]
+ s.summary = "The best way to manage your application's dependencies"
+ end
+ GEMSPEC
+ end
+
+ should_have_gems "bundler-#{version}"
+
+ bundle :clean
+
+ should_have_gems "bundler-#{version}"
+ end
end
diff --git a/spec/bundler/commands/config_spec.rb b/spec/bundler/commands/config_spec.rb
index 1392b17315..e8ab32ca5d 100644
--- a/spec/bundler/commands/config_spec.rb
+++ b/spec/bundler/commands/config_spec.rb
@@ -313,9 +313,10 @@ RSpec.describe ".bundle/config" do
describe "parseable option" do
it "prints an empty string" do
- bundle "config get foo --parseable"
+ bundle "config get foo --parseable", raise_on_error: false
expect(out).to eq ""
+ expect(last_command).to be_failure
end
it "only prints the value of the config" do
@@ -501,8 +502,9 @@ E
it "get" do
ENV["BUNDLE_BAR"] = "bar_val"
- bundle "config get foo"
+ bundle "config get foo", raise_on_error: false
expect(out).to eq "Settings for `foo` in order of priority. The top value will be used\nYou have not configured a value for `foo`"
+ expect(last_command).to be_failure
ENV["BUNDLE_FOO"] = "foo_val"
@@ -547,7 +549,8 @@ E
bundle "config unset foo"
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`"
+ expect(bundle("config get foo", raise_on_error: false)).to eq "Settings for `foo` in order of priority. The top value will be used\nYou have not configured a value for `foo`"
+ expect(last_command).to be_failure
bundle "config set --local foo 1"
bundle "config set --global foo 2"
@@ -557,7 +560,8 @@ E
expect(bundle("config get foo")).to eq "Settings for `foo` in order of priority. The top value will be used\nSet for the current user (#{home(".bundle/config")}): \"2\""
bundle "config unset foo --global"
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`"
+ expect(bundle("config get foo", raise_on_error: false)).to eq "Settings for `foo` in order of priority. The top value will be used\nYou have not configured a value for `foo`"
+ expect(last_command).to be_failure
bundle "config set --local foo 1"
bundle "config set --global foo 2"
@@ -567,7 +571,8 @@ E
expect(bundle("config get foo")).to eq "Settings for `foo` in order of priority. The top value will be used\nSet for your local app (#{bundled_app(".bundle/config")}): \"1\""
bundle "config unset foo --local"
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`"
+ expect(bundle("config get foo", raise_on_error: false)).to eq "Settings for `foo` in order of priority. The top value will be used\nYou have not configured a value for `foo`"
+ expect(last_command).to be_failure
bundle "config unset foo --local --global", raise_on_error: false
expect(last_command).to be_failure
@@ -577,6 +582,36 @@ E
end
RSpec.describe "setting gemfile via config" do
+ context "when a default Gemfile exists" do
+ before do
+ gemfile <<-G
+ source "https://gem.repo1"
+ G
+
+ gemfile bundled_app("foo/bar_gemfile"), <<-G
+ source "https://gem.repo1"
+ G
+ end
+
+ it "reports the local gemfile setting without promoting it to the environment" do
+ bundle "config set gemfile foo/bar_gemfile"
+
+ bundle "config list"
+ expect(out).to include("Set for your local app (#{bundled_app(".bundle/config")}): \"foo/bar_gemfile\"")
+ expect(out).not_to include("Set via BUNDLE_GEMFILE")
+ end
+
+ it "unsets the local gemfile setting from the app config" do
+ bundle "config set gemfile foo/bar_gemfile"
+
+ bundle "config unset gemfile"
+ bundle "config get gemfile", raise_on_error: false
+
+ expect(out).to include("You have not configured a value for `gemfile`")
+ expect(File.read(bundled_app(".bundle/config"))).not_to include("BUNDLE_GEMFILE")
+ end
+ end
+
context "when only the non-default Gemfile exists" do
it "persists the gemfile location to .bundle/config" do
gemfile bundled_app("NotGemfile"), <<-G
@@ -592,3 +627,20 @@ RSpec.describe "setting gemfile via config" do
end
end
end
+
+RSpec.describe "setting lockfile via config" do
+ it "persists the lockfile location to .bundle/config" do
+ gemfile bundled_app("NotGemfile"), <<-G
+ source "https://gem.repo1"
+ gem 'myrack'
+ G
+
+ bundle "config set --local gemfile #{bundled_app("NotGemfile")}"
+ bundle "config set --local lockfile #{bundled_app("ReallyNotGemfile.lock")}"
+ expect(File.exist?(bundled_app(".bundle/config"))).to eq(true)
+
+ bundle "config list"
+ expect(out).to include("NotGemfile")
+ expect(out).to include("ReallyNotGemfile.lock")
+ end
+end
diff --git a/spec/bundler/commands/console_spec.rb b/spec/bundler/commands/console_spec.rb
index ec44fe59f3..a44f607546 100644
--- a/spec/bundler/commands/console_spec.rb
+++ b/spec/bundler/commands/console_spec.rb
@@ -124,7 +124,7 @@ RSpec.describe "bundle console", readline: true do
gem "irb"
gem "pry"
G
- bundle "config set console pry"
+ bundle_config "console pry"
bundle "console" do |input, _, _|
input.puts("__method__")
@@ -136,7 +136,7 @@ RSpec.describe "bundle console", readline: true do
it "falls back to IRB if the other REPL isn't available" do
skip "Does not work in a ruby-core context if irb is in the default $LOAD_PATH because it enables the real IRB, not our dummy one" if ruby_core? && Gem.ruby_version < Gem::Version.new("3.5.0.a")
- bundle "config set console pry"
+ bundle_config "console pry"
# make sure pry isn't there
bundle "console" do |input, _, _|
@@ -201,7 +201,7 @@ RSpec.describe "bundle console", readline: true do
gem "foo"
G
- bundle "config set auto_install 1"
+ bundle_config "auto_install 1"
bundle :console do |input, _, _|
input.puts("puts 'hello'")
input.puts("exit")
diff --git a/spec/bundler/commands/doctor_spec.rb b/spec/bundler/commands/doctor_spec.rb
index 5ceaf37f29..d350b4b3d1 100644
--- a/spec/bundler/commands/doctor_spec.rb
+++ b/spec/bundler/commands/doctor_spec.rb
@@ -34,6 +34,8 @@ RSpec.describe "bundle doctor" do
allow(Bundler::SharedHelpers).to receive(:find_gemfile).and_return(bundled_app_gemfile)
allow(Find).to receive(:find).with(Bundler.bundle_path.to_s) { [unwritable_file] }
allow(File).to receive(:exist?).and_call_original
+ allow(File).to receive(:writable?).and_call_original
+ allow(File).to receive(:readable?).and_call_original
allow(File).to receive(:exist?).with(unwritable_file).and_return(true)
allow(File).to receive(:stat).with(unwritable_file) { stat }
allow(stat).to receive(:uid) { Process.uid }
@@ -108,6 +110,8 @@ RSpec.describe "bundle doctor" do
allow(Bundler::SharedHelpers).to receive(:find_gemfile).and_return(bundled_app_gemfile)
allow(Find).to receive(:find).with(Bundler.bundle_path.to_s) { [@unwritable_file] }
allow(File).to receive(:exist?).and_call_original
+ allow(File).to receive(:writable?).and_call_original
+ allow(File).to receive(:readable?).and_call_original
allow(File).to receive(:exist?).with(@unwritable_file) { true }
allow(File).to receive(:stat).with(@unwritable_file) { @stat }
end
diff --git a/spec/bundler/commands/exec_spec.rb b/spec/bundler/commands/exec_spec.rb
index cad1ac4ba3..aa35685be8 100644
--- a/spec/bundler/commands/exec_spec.rb
+++ b/spec/bundler/commands/exec_spec.rb
@@ -95,7 +95,7 @@ RSpec.describe "bundle exec" do
end
it "respects custom process title when loading through ruby" do
- skip "https://github.com/rubygems/rubygems/issues/3351" if Gem.win_platform?
+ skip "https://github.com/ruby/rubygems/issues/3351" if Gem.win_platform?
script_that_changes_its_own_title_and_checks_if_picked_up_by_ps_unix_utility = <<~'RUBY'
Process.setproctitle("1-2-3-4-5-6-7")
@@ -120,7 +120,7 @@ RSpec.describe "bundle exec" do
end
it "handles --keep-file-descriptors" do
- skip "https://github.com/rubygems/rubygems/issues/3351" if Gem.win_platform?
+ skip "https://github.com/ruby/rubygems/issues/3351" if Gem.win_platform?
require "tempfile"
@@ -153,7 +153,7 @@ RSpec.describe "bundle exec" do
end
it "can run a command named --verbose" do
- skip "https://github.com/rubygems/rubygems/issues/3351" if Gem.win_platform?
+ skip "https://github.com/ruby/rubygems/issues/3351" if Gem.win_platform?
install_gemfile "source \"https://gem.repo1\"; gem \"myrack\""
File.open(bundled_app("--verbose"), "w") do |f|
@@ -268,7 +268,7 @@ RSpec.describe "bundle exec" do
end
end
- bundle "config set --global path.system true"
+ bundle_config_global "path.system true"
install_gemfile <<-G
source "https://gem.repo1"
@@ -289,7 +289,7 @@ RSpec.describe "bundle exec" do
end
it "handles gems installed with --without" do
- bundle "config set --local without middleware"
+ bundle_config "without middleware"
install_gemfile <<-G
source "https://gem.repo1"
gem "myrack" # myrack 0.9.1 and 1.0 exist
@@ -379,13 +379,13 @@ RSpec.describe "bundle exec" do
it "raises a helpful error when exec'ing to something outside of the bundle" do
system_gems(%w[myrack-1.0.0 myrack-0.9.1], path: default_bundle_path)
- bundle "config set clean false" # want to keep the myrackup binstub
+ bundle_config "clean false" # want to keep the myrackup binstub
install_gemfile <<-G
source "https://gem.repo1"
gem "foo"
G
[true, false].each do |l|
- bundle "config set disable_exec_load #{l}"
+ bundle_config "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?"
end
@@ -582,7 +582,7 @@ RSpec.describe "bundle exec" do
gem "foo"
G
- bundle "config set auto_install 1"
+ bundle_config "auto_install 1"
bundle "exec myrackup", artifice: "compact_index"
expect(out).to include("Installing foo 1.0")
end
@@ -597,7 +597,7 @@ RSpec.describe "bundle exec" do
gem "foo", :git => "#{lib_path("foo-1.0")}"
G
- bundle "config set auto_install 1"
+ bundle_config "auto_install 1"
bundle "exec foo", artifice: "compact_index"
expect(out).to include("Fetching myrack 0.9.1")
expect(out).to include("Fetching #{lib_path("foo-1.0")}")
@@ -617,8 +617,8 @@ RSpec.describe "bundle exec" do
system_gems "optparse-999.999.998", gem_repo: gem_repo4
- bundle "config set auto_install 1"
- bundle "config set --local path vendor/bundle"
+ bundle_config "auto_install 1"
+ bundle_config "path vendor/bundle"
gemfile <<~G
source "https://gem.repo4"
@@ -661,8 +661,6 @@ RSpec.describe "bundle exec" do
describe "with gems bundled for deployment" do
it "works when calling bundler from another script" do
- skip "https://github.com/rubygems/rubygems/issues/3351" if Gem.win_platform?
-
gemfile <<-G
source "https://gem.repo1"
@@ -673,7 +671,7 @@ RSpec.describe "bundle exec" do
end
Bundler.rubygems.extend(Monkey)
G
- bundle "config set path.system true"
+ bundle_config "path.system true"
bundle "install"
bundle "exec ruby -e '`bundle -v`; puts $?.success?'", env: { "BUNDLER_VERSION" => Bundler::VERSION }
expect(out).to match("true")
@@ -730,13 +728,16 @@ RSpec.describe "bundle exec" do
puts "EXEC: \#{caller.grep(/load/).empty? ? 'exec' : 'load'}"
puts "ARGS: \#{$0} \#{ARGV.join(' ')}"
puts "MYRACK: \#{MYRACK}"
- process_title = `ps -o args -p \#{Process.pid}`.split("\n", 2).last.strip
+ if Gem.win_platform?
+ process_title = "ruby"
+ else
+ process_title = `ps -o args -p \#{Process.pid}`.split("\n", 2).last.strip
+ end
puts "PROCESS: \#{process_title}"
RUBY
before do
- bundled_app(path).open("w") {|f| f << executable }
- bundled_app(path).chmod(0o755)
+ create_file(bundled_app(path), executable)
install_gemfile <<-G
source "https://gem.repo1"
@@ -748,9 +749,11 @@ RSpec.describe "bundle exec" do
let(:args) { "ARGS: #{path} arg1 arg2" }
let(:myrack) { "MYRACK: 1.0.0" }
let(:process) do
- title = "PROCESS: #{path}"
- title += " arg1 arg2"
- title
+ if Gem.win_platform?
+ "PROCESS: ruby"
+ else
+ "PROCESS: #{path} arg1 arg2"
+ end
end
let(:exit_code) { 0 }
let(:expected) { [exec, args, myrack, process].join("\n") }
@@ -759,8 +762,6 @@ RSpec.describe "bundle exec" do
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?
-
subject
expect(exitstatus).to eq(exit_code)
expect(err).to eq(expected_err)
@@ -772,8 +773,6 @@ RSpec.describe "bundle exec" do
context "with exit 0" do
it "runs" do
- skip "https://github.com/rubygems/rubygems/issues/3351" if Gem.win_platform?
-
subject
expect(exitstatus).to eq(exit_code)
expect(err).to eq(expected_err)
@@ -785,8 +784,6 @@ RSpec.describe "bundle exec" do
let(:exit_code) { 99 }
it "runs" do
- skip "https://github.com/rubygems/rubygems/issues/3351" if Gem.win_platform?
-
subject
expect(exitstatus).to eq(exit_code)
expect(err).to eq(expected_err)
@@ -808,7 +805,7 @@ RSpec.describe "bundle exec" do
end
it "runs" do
- skip "https://github.com/rubygems/rubygems/issues/3351" if Gem.win_platform?
+ skip "https://github.com/ruby/rubygems/issues/3351" if Gem.win_platform?
subject
expect(exitstatus).to eq(exit_code)
@@ -825,7 +822,12 @@ RSpec.describe "bundle exec" do
let(:expected) { "" }
it "runs" do
- skip "https://github.com/rubygems/rubygems/issues/3351" if Gem.win_platform?
+ # it's empty, so `create_file` won't add executable permission and bat scripts on Windows
+ bundled_app(path).chmod(0o755)
+ path.sub_ext(".bat").write <<~SCRIPT if Gem.win_platform?
+ @ECHO OFF
+ @"ruby.exe" "%~dpn0" %*
+ SCRIPT
subject
expect(exitstatus).to eq(exit_code)
@@ -838,12 +840,10 @@ 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\)/
+ /\Abundler: failed to load command: #{Regexp.quote(path.to_s)} \(#{Regexp.quote(path.to_s)}\)\n#{Regexp.quote(path.to_s)}:[0-9]+:in [`']<top \(required\)>': ERROR \(RuntimeError\)/
end
it "runs like a normally executed executable" do
- skip "https://github.com/rubygems/rubygems/issues/3351" if Gem.win_platform?
-
subject
expect(exitstatus).to eq(exit_code)
expect(err).to match(expected_err)
@@ -858,8 +858,6 @@ RSpec.describe "bundle exec" do
let(:expected) { super() }
it "runs" do
- skip "https://github.com/rubygems/rubygems/issues/3351" if Gem.win_platform?
-
subject
expect(exitstatus).to eq(exit_code)
expect(err).to eq(expected_err)
@@ -871,8 +869,6 @@ RSpec.describe "bundle exec" do
let(:shebang) { "#!#{Gem.ruby}" }
it "runs" do
- skip "https://github.com/rubygems/rubygems/issues/3351" if Gem.win_platform?
-
subject
expect(exitstatus).to eq(exit_code)
expect(err).to eq(expected_err)
@@ -903,8 +899,6 @@ RSpec.describe "bundle exec" do
EOS
it "runs" do
- skip "https://github.com/rubygems/rubygems/issues/3351" if Gem.win_platform?
-
subject
expect(exitstatus).to eq(exit_code)
expect(err).to eq(expected_err)
@@ -927,8 +921,6 @@ RSpec.describe "bundle exec" do
let(:expected) { "" }
it "prints proper suggestion" do
- skip "https://github.com/rubygems/rubygems/issues/3351" if Gem.win_platform?
-
subject
expect(exitstatus).to eq(exit_code)
expect(err).to include("Run `bundle install --gemfile CustomGemfile` to install missing gems.")
@@ -941,8 +933,6 @@ RSpec.describe "bundle exec" do
let(:exit_code) { 1 }
it "runs" do
- skip "https://github.com/rubygems/rubygems/issues/3351" if Gem.win_platform?
-
subject
expect(exitstatus).to eq(exit_code)
expect(err).to eq(expected_err)
@@ -952,15 +942,19 @@ RSpec.describe "bundle exec" do
context "when disable_exec_load is set" do
let(:exec) { "EXEC: exec" }
- let(:process) { "PROCESS: ruby #{path} arg1 arg2" }
+ let(:process) do
+ if Gem.win_platform?
+ "PROCESS: ruby"
+ else
+ "PROCESS: ruby #{path} arg1 arg2"
+ end
+ end
before do
- bundle "config set disable_exec_load true"
+ bundle_config "disable_exec_load true"
end
it "runs" do
- skip "https://github.com/rubygems/rubygems/issues/3351" if Gem.win_platform?
-
subject
expect(exitstatus).to eq(exit_code)
expect(err).to eq(expected_err)
@@ -983,8 +977,6 @@ RSpec.describe "bundle exec" do
EOS
it "runs" do
- skip "https://github.com/rubygems/rubygems/issues/3351" if Gem.win_platform?
-
subject
expect(exitstatus).to eq(exit_code)
expect(err).to eq(expected_err)
@@ -1001,8 +993,6 @@ RSpec.describe "bundle exec" do
EOS
it "runs" do
- skip "https://github.com/rubygems/rubygems/issues/3351" if Gem.win_platform?
-
subject
expect(exitstatus).to eq(exit_code)
expect(err).to eq(expected_err)
@@ -1019,8 +1009,6 @@ RSpec.describe "bundle exec" do
EOS
it "runs" do
- skip "https://github.com/rubygems/rubygems/issues/3351" if Gem.win_platform?
-
subject
expect(exitstatus).to eq(exit_code)
expect(err).to eq(expected_err)
@@ -1032,7 +1020,7 @@ RSpec.describe "bundle exec" do
context "signal handling" do
let(:test_signals) do
open3_reserved_signals = %w[CHLD CLD PIPE]
- reserved_signals = %w[SEGV BUS ILL FPE VTALRM KILL STOP EXIT]
+ reserved_signals = %w[SEGV BUS ILL FPE ABRT IOT VTALRM KILL STOP EXIT]
bundler_signals = %w[INT]
Signal.list.keys - (bundler_signals + reserved_signals + open3_reserved_signals)
@@ -1046,7 +1034,7 @@ RSpec.describe "bundle exec" do
puts 'Started' # For process sync
STDOUT.flush
sleep 1 # ignore quality_spec
- raise "Didn't receive INT at all"
+ raise RuntimeError, "Didn't receive expected INT"
end.join
rescue Interrupt
puts "foo"
@@ -1054,7 +1042,7 @@ RSpec.describe "bundle exec" do
RUBY
it "receives the signal" do
- skip "https://github.com/rubygems/rubygems/issues/3351" if Gem.win_platform?
+ skip "https://github.com/ruby/rubygems/issues/3351" if Gem.win_platform?
bundle("exec #{path}") do |_, o, thr|
o.gets # Consumes 'Started' and ensures that thread has started
@@ -1077,7 +1065,7 @@ RSpec.describe "bundle exec" do
RUBY
it "makes sure no unexpected signals are restored to DEFAULT" do
- skip "https://github.com/rubygems/rubygems/issues/3351" if Gem.win_platform?
+ skip "https://github.com/ruby/rubygems/issues/3351" if Gem.win_platform?
test_signals.each do |n|
Signal.trap(n, "IGNORE")
@@ -1094,13 +1082,13 @@ RSpec.describe "bundle exec" do
context "nested bundle exec" do
context "when bundle in a local path" do
before do
- skip "https://github.com/rubygems/rubygems/issues/3351" if Gem.win_platform?
+ skip "https://github.com/ruby/rubygems/issues/3351" if Gem.win_platform?
gemfile <<-G
source "https://gem.repo1"
gem "myrack"
G
- bundle "config set path vendor/bundler"
+ bundle_config "path vendor/bundler"
bundle :install
end
@@ -1118,7 +1106,7 @@ RSpec.describe "bundle exec" do
context "when Kernel.require uses extra monkeypatches" do
before do
- skip "https://github.com/rubygems/rubygems/issues/3351" if Gem.win_platform?
+ skip "https://github.com/ruby/rubygems/issues/3351" if Gem.win_platform?
install_gemfile "source \"https://gem.repo1\""
end
@@ -1161,16 +1149,14 @@ RSpec.describe "bundle exec" do
context "when gemfile and path are configured", :ruby_repo do
before do
- skip "https://github.com/rubygems/rubygems/issues/3351" if Gem.win_platform?
-
build_repo2 do
build_gem "rails", "6.1.0" do |s|
s.executables = "rails"
end
end
- bundle "config set path vendor/bundle"
- bundle "config set gemfile gemfiles/myrack_6_1.gemfile"
+ bundle_config "path vendor/bundle"
+ bundle_config "gemfile gemfiles/myrack_6_1.gemfile"
gemfile(bundled_app("gemfiles/myrack_6_1.gemfile"), <<~RUBY)
source "https://gem.repo2"
@@ -1225,14 +1211,14 @@ RSpec.describe "bundle exec" do
it "only leaves the default gem in the stdlib available" do
default_openssl_version = ruby "require 'openssl'; puts OpenSSL::VERSION"
- skip "https://github.com/rubygems/rubygems/issues/3351" if Gem.win_platform?
+ skip "https://github.com/ruby/rubygems/issues/3351" if Gem.win_platform?
install_gemfile "source \"https://gem.repo1\"" # must happen before installing the broken system gem
build_repo4 do
build_gem "openssl", openssl_version do |s|
s.write("lib/openssl.rb", <<-RUBY)
- raise "custom openssl should not be loaded, it's not in the gemfile!"
+ raise ArgumentError, "custom openssl should not be loaded"
RUBY
end
end
@@ -1266,7 +1252,7 @@ RSpec.describe "bundle exec" do
context "with a git gem that includes extensions", :ruby_repo do
before do
build_git "simple_git_binary", &:add_c_extension
- bundle "config set --local path .bundle"
+ bundle_config "path .bundle"
install_gemfile <<-G
source "https://gem.repo1"
gem "simple_git_binary", :git => '#{lib_path("simple_git_binary-1.0")}'
diff --git a/spec/bundler/commands/fund_spec.rb b/spec/bundler/commands/fund_spec.rb
index 6f4e61da30..5883b8a63a 100644
--- a/spec/bundler/commands/fund_spec.rb
+++ b/spec/bundler/commands/fund_spec.rb
@@ -73,7 +73,7 @@ RSpec.describe "bundle fund" do
end
it "considers fund information for installed optional dependencies" do
- bundle "config set with whatever"
+ bundle_config "with whatever"
install_gemfile <<-G
source "https://gem.repo2"
diff --git a/spec/bundler/commands/info_spec.rb b/spec/bundler/commands/info_spec.rb
index f403db684f..a26b1696fb 100644
--- a/spec/bundler/commands/info_spec.rb
+++ b/spec/bundler/commands/info_spec.rb
@@ -57,7 +57,7 @@ RSpec.describe "bundle info" do
end
it "doesn't claim that bundler is missing, even if using a custom path without bundler there" do
- bundle "config set --local path vendor/bundle"
+ bundle_config "path vendor/bundle"
bundle "install"
bundle "info bundler"
expect(out).to include("\tPath: #{root}")
@@ -235,7 +235,7 @@ RSpec.describe "bundle info" do
context "with without configured" do
it "does not find the gem, but gives a helpful error" do
- bundle "config without test"
+ bundle_config "without test"
install_gemfile <<-G
source "https://gem.repo1"
diff --git a/spec/bundler/commands/init_spec.rb b/spec/bundler/commands/init_spec.rb
index 538e61fd47..989d6fa812 100644
--- a/spec/bundler/commands/init_spec.rb
+++ b/spec/bundler/commands/init_spec.rb
@@ -119,7 +119,7 @@ RSpec.describe "bundle init" do
end
context "when init_gems_rb setting is enabled" do
- before { bundle "config set init_gems_rb true" }
+ before { bundle_config "init_gems_rb true" }
it "generates a gems.rb" do
bundle :init
diff --git a/spec/bundler/commands/inject_spec.rb b/spec/bundler/commands/inject_spec.rb
deleted file mode 100644
index c39c2ae35b..0000000000
--- a/spec/bundler/commands/inject_spec.rb
+++ /dev/null
@@ -1,113 +0,0 @@
-# frozen_string_literal: true
-
-RSpec.describe "bundle inject" do
- before :each do
- gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
- 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/)
- end
- end
-
- context "with a lockfile" do
- before do
- bundle "install"
- 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/)
- 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/)
- 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
- 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
- expect(err).to eq(<<-E.strip)
-ERROR: "bundle inject" was called with arguments ["gem_name", "1", "v"]
-Usage: "bundle inject GEM VERSION"
- E
- end
- end
-
- context "with source option" do
- it "add gem with source option in gemfile" do
- bundle "inject 'foo' '>0' --source https://gem.repo1"
- gemfile = bundled_app_gemfile.read
- str = "gem \"foo\", \"> 0\", source: \"https://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"
- gemfile = bundled_app_gemfile.read
- str = "gem \"myrack-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"
- gemfile = bundled_app_gemfile.read
- str = "gem \"myrack-obama\", \"> 0\", groups: [:development, :test]"
- expect(gemfile).to include str
- end
- end
-
- context "when frozen" do
- before do
- bundle "install"
- bundle "config set --local frozen true"
- end
-
- it "injects anyway" do
- bundle "inject 'myrack-obama' '> 0'"
- expect(bundled_app_gemfile.read).to match(/myrack-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/)
- end
-
- it "restores frozen afterwards" do
- bundle "inject 'myrack-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"
- G
- bundle "inject 'myrack' '> 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/)
- end
- end
-end
diff --git a/spec/bundler/commands/install_spec.rb b/spec/bundler/commands/install_spec.rb
index e7c1f5e456..3b24434dc7 100644
--- a/spec/bundler/commands/install_spec.rb
+++ b/spec/bundler/commands/install_spec.rb
@@ -29,6 +29,53 @@ RSpec.describe "bundle install with gem sources" do
expect(bundled_app_lock).to exist
end
+ it "creates lockfile based on the lockfile method in Gemfile" do
+ install_gemfile <<-G
+ lockfile "OmgFile.lock"
+ source "https://gem.repo1"
+ gem "myrack", "1.0"
+ G
+
+ bundle "install"
+
+ expect(bundled_app("OmgFile.lock")).to exist
+ end
+
+ it "creates lockfile using BUNDLE_LOCKFILE instead of lockfile method" do
+ ENV["BUNDLE_LOCKFILE"] = "ReallyOmgFile.lock"
+ install_gemfile <<-G
+ lockfile "OmgFile.lock"
+ source "https://gem.repo1"
+ gem "myrack", "1.0"
+ G
+
+ expect(bundled_app("ReallyOmgFile.lock")).to exist
+ expect(bundled_app("OmgFile.lock")).not_to exist
+ ensure
+ ENV.delete("BUNDLE_LOCKFILE")
+ end
+
+ it "creates lockfile based on --lockfile option is given" do
+ gemfile bundled_app("OmgFile"), <<-G
+ source "https://gem.repo1"
+ gem "myrack", "1.0"
+ G
+
+ bundle "install --gemfile OmgFile --lockfile ReallyOmgFile.lock"
+
+ expect(bundled_app("ReallyOmgFile.lock")).to exist
+ end
+
+ it "does not make a lockfile if lockfile false is used in Gemfile" do
+ install_gemfile <<-G
+ lockfile false
+ source "https://gem.repo1"
+ gem 'myrack'
+ G
+
+ expect(bundled_app_lock).not_to exist
+ end
+
it "does not create ./.bundle by default" do
install_gemfile <<-G
source "https://gem.repo1"
@@ -67,6 +114,29 @@ RSpec.describe "bundle install with gem sources" do
expect(bundled_app("OmgFile.lock")).to exist
end
+ it "doesn't create a lockfile if --no-lock option is given" do
+ gemfile bundled_app("OmgFile"), <<-G
+ source "https://gem.repo1"
+ gem "myrack", "1.0"
+ G
+
+ bundle "install --gemfile OmgFile --no-lock"
+
+ expect(bundled_app("OmgFile.lock")).not_to exist
+ end
+
+ it "doesn't create a lockfile if --no-lock and --lockfile options are given" do
+ gemfile bundled_app("OmgFile"), <<-G
+ source "https://gem.repo1"
+ gem "myrack", "1.0"
+ G
+
+ bundle "install --gemfile OmgFile --no-lock --lockfile ReallyOmgFile.lock"
+
+ expect(bundled_app("OmgFile.lock")).not_to exist
+ expect(bundled_app("ReallyOmgFile.lock")).not_to exist
+ end
+
it "doesn't delete the lockfile if one already exists" do
install_gemfile <<-G
source "https://gem.repo1"
@@ -118,7 +188,7 @@ RSpec.describe "bundle install with gem sources" do
it "does not state that it's constantly reinstalling empty gems" do
build_repo4 do
- build_gem "empty", "1.0.0", no_default: true, allowed_warning: "no files specified"
+ build_gem "empty", "1.0.0", no_default: true
end
install_gemfile <<~G
@@ -327,53 +397,6 @@ RSpec.describe "bundle install with gem sources" do
end
end
- describe "doing bundle install foo" do
- before do
- gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
- G
- end
-
- it "works" do
- bundle "config set --local path vendor"
- bundle "install"
- expect(the_bundle).to include_gems "myrack 1.0"
- end
-
- it "allows running bundle install --system without deleting foo" do
- bundle "install --path vendor"
- bundle "install --system"
- FileUtils.rm_r(bundled_app("vendor"))
- expect(the_bundle).to include_gems "myrack 1.0"
- end
-
- it "allows running bundle install --system after deleting foo" do
- bundle "install --path vendor"
- FileUtils.rm_r(bundled_app("vendor"))
- bundle "install --system"
- expect(the_bundle).to include_gems "myrack 1.0"
- end
- end
-
- it "finds gems in multiple sources" do
- build_repo2 do
- build_gem "myrack", "1.2" do |s|
- s.executables = "myrackup"
- end
- end
-
- install_gemfile <<-G, artifice: "compact_index_extra"
- source "https://gemserver.test"
- source "https://gemserver.test/extra"
-
- gem "activesupport", "1.2.3"
- gem "myrack", "1.2"
- G
-
- expect(the_bundle).to include_gems "myrack 1.2", "activesupport 1.2.3"
- end
-
it "gives useful errors if no global sources are set, and gems not installed locally, with and without a lockfile" do
install_gemfile <<-G, raise_on_error: false
gem "myrack"
@@ -393,7 +416,7 @@ RSpec.describe "bundle install with gem sources" do
myrack
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
bundle "install", raise_on_error: false
@@ -615,6 +638,30 @@ RSpec.describe "bundle install with gem sources" do
expect(err).to include("Two gemspec development dependencies have conflicting requirements on the same gem: rubocop (~> 1.36.0) and rubocop (~> 2.0). Bundler cannot continue.")
end
+ it "errors out if a gem is specified in a gemspec and in the Gemfile" do
+ gem = tmp("my-gem-1")
+
+ build_lib "rubocop", path: gem do |s|
+ s.add_development_dependency "rubocop", "~> 1.0"
+ end
+
+ build_repo4 do
+ build_gem "rubocop"
+ end
+
+ gemfile <<~G
+ source "https://gem.repo4"
+
+ gem "rubocop", :path => "#{gem}"
+ gemspec path: "#{gem}"
+ G
+
+ bundle :install, raise_on_error: false
+
+ expect(err).to include("There was an error parsing `Gemfile`: You cannot specify the same gem twice coming from different sources.")
+ expect(err).to include("You specified that rubocop (>= 0) should come from source at `#{gem}` and gemspec at `#{gem}`")
+ 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"
@@ -711,13 +758,12 @@ RSpec.describe "bundle install with gem sources" do
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|
- bad_deps = [["ruby-ajp", ">= 0.2.0"], ["rails", ">= 0.14"]]
+ invalid_deps = [["ruby-ajp", ">= 0.2.0"], ["rails", ">= 0.14"]]
s.
instance_variable_get(:@spec).
- instance_variable_set(:@dependencies, bad_deps)
-
- raise "failed to set bad deps" unless s.dependencies == bad_deps
+ instance_variable_set(:@dependencies, invalid_deps)
end
+
build_gem "ruby-ajp", "1.0.0"
end
@@ -787,10 +833,10 @@ RSpec.describe "bundle install with gem sources" do
DEPENDENCIES
#{checksums}
RUBY VERSION
- #{Bundler::RubyVersion.system}
+ #{Bundler::RubyVersion.system}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
@@ -813,10 +859,10 @@ RSpec.describe "bundle install with gem sources" do
DEPENDENCIES
#{checksums}
RUBY VERSION
- #{Bundler::RubyVersion.system}
+ #{Bundler::RubyVersion.system}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
@@ -871,7 +917,7 @@ RSpec.describe "bundle install with gem sources" do
describe "when requesting a quiet install via --quiet" do
it "should be quiet if there are no warnings" do
- bundle "config set force_ruby_platform true"
+ bundle_config "force_ruby_platform true"
gemfile <<-G
source "https://gem.repo1"
@@ -884,7 +930,7 @@ RSpec.describe "bundle install with gem sources" do
end
it "should still display warnings and errors" do
- bundle "config set force_ruby_platform true"
+ bundle_config "force_ruby_platform true"
create_file("install_with_warning.rb", <<~RUBY)
require "#{lib_dir}/bundler"
@@ -929,7 +975,7 @@ RSpec.describe "bundle install with gem sources" do
it "should display a proper message to explain the problem" do
FileUtils.chmod(0o500, bundle_path)
- bundle "config set --local path vendor"
+ bundle_config "path vendor"
bundle :install, raise_on_error: false
expect(err).to include(bundle_path.to_s)
expect(err).to include("grant executable permissions")
@@ -949,7 +995,7 @@ RSpec.describe "bundle install with gem sources" do
it "should display a proper message to explain the problem" do
FileUtils.chmod("-x", gems_path)
- bundle "config set --local path vendor"
+ bundle_config "path vendor"
begin
bundle :install, raise_on_error: false
@@ -979,7 +1025,7 @@ RSpec.describe "bundle install with gem sources" do
it "should display a proper message to explain the problem" do
FileUtils.chmod("-x", full_gem_path)
- bundle "config set --local path vendor"
+ bundle_config "path vendor"
begin
bundle :install, raise_on_error: false
@@ -1009,7 +1055,7 @@ RSpec.describe "bundle install with gem sources" do
it "should display a proper message to explain the problem" do
FileUtils.chmod("-x", bin_dir)
- bundle "config set --local path vendor"
+ bundle_config "path vendor"
begin
bundle :install, raise_on_error: false
@@ -1039,7 +1085,7 @@ RSpec.describe "bundle install with gem sources" do
it "should display a proper message to explain the problem" do
FileUtils.chmod("-w", bin_dir)
- bundle "config set --local path vendor"
+ bundle_config "path vendor"
begin
bundle :install, raise_on_error: false
@@ -1069,7 +1115,7 @@ RSpec.describe "bundle install with gem sources" do
it "should display a proper message to explain the problem" do
FileUtils.chmod("-x", extensions_path)
- bundle "config set --local path vendor"
+ bundle_config "path vendor"
begin
bundle :install, raise_on_error: false
@@ -1104,7 +1150,7 @@ RSpec.describe "bundle install with gem sources" do
end
it "should display a proper message to explain the problem" do
- bundle "config set --local path vendor"
+ bundle_config "path vendor"
bundle :install
expect(out).to include("Bundle complete!")
expect(err).to be_empty
@@ -1140,7 +1186,7 @@ RSpec.describe "bundle install with gem sources" do
end
it "should still work" do
- bundle "config set --local path vendor"
+ bundle_config "path vendor"
bundle :install
expect(out).to include("Bundle complete!")
expect(err).to be_empty
@@ -1175,7 +1221,7 @@ RSpec.describe "bundle install with gem sources" do
end
it "should display a proper message to explain the problem" do
- bundle "config set --local path vendor"
+ bundle_config "path vendor"
bundle :install
expect(out).to include("Bundle complete!")
expect(err).to be_empty
@@ -1206,7 +1252,7 @@ RSpec.describe "bundle install with gem sources" do
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"
+ bundle_config "path vendor"
FileUtils.mkdir_p(gems_path)
FileUtils.chmod(0o777, gems_path)
@@ -1230,7 +1276,7 @@ RSpec.describe "bundle install with gem sources" do
it "should display a proper message to explain the problem" do
FileUtils.chmod(0o500, cache_path)
- bundle "config set --local path vendor"
+ bundle_config "path vendor"
bundle :install, raise_on_error: false
expect(err).to include(cache_path.to_s)
expect(err).to include("grant write permissions")
@@ -1245,7 +1291,7 @@ RSpec.describe "bundle install with gem sources" do
source "https://gem.repo1"
gem 'myrack'
G
- bundle "config path vendor/bundle"
+ bundle_config "path vendor/bundle"
bundle :install
expect(out).to include("Bundle complete!")
expect(err).to be_empty
@@ -1260,6 +1306,158 @@ RSpec.describe "bundle install with gem sources" do
end
end
+ describe "when using umask 002 and setgid bit", :permissions do
+ let(:gems_path) { bundled_app("vendor/#{Bundler.ruby_scope}/gems") }
+ let(:foo_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
+
+ FileUtils.mkdir_p(gems_path)
+ FileUtils.chmod("g+s", gems_path)
+ end
+
+ it "should create the gem directory with proper permissions" do
+ with_umask(0o002) do
+ bundle_config "path vendor"
+ bundle :install
+ expect(out).to include("Bundle complete!")
+ expect(err).to be_empty
+ # Linux's SysV-derived mkdir(2) propagates the set-group-ID bit
+ # from the parent directory to newly created subdirectories. BSD
+ # (including macOS) inherits the parent's group via mkdir(2) but
+ # does not copy the set-group-ID bit itself, so the expected
+ # mode differs by platform.
+ expected = RUBY_PLATFORM.include?("darwin") ? 0o0775 : 0o2775
+ expect(File.stat(foo_path).mode & 0o7777).to eq(expected)
+ end
+ end
+ end
+
+ describe "parallel make" do
+ before do
+ unless Gem::Installer.private_method_defined?(:build_jobs)
+ skip "This example is runnable when RubyGems::Installer implements `build_jobs`"
+ end
+
+ @old_makeflags = ENV["MAKEFLAGS"]
+ @gemspec = nil
+
+ extconf_code = <<~CODE
+ require "mkmf"
+ create_makefile("foo")
+ CODE
+
+ build_repo4 do
+ build_gem "mypsych", "4.0.6" do |s|
+ @gemspec = s
+ extension = "ext/mypsych/extconf.rb"
+ s.extensions = extension
+
+ s.write(extension, extconf_code)
+ end
+ end
+ end
+
+ after do
+ if @old_makeflags
+ ENV["MAKEFLAGS"] = @old_makeflags
+ else
+ ENV.delete("MAKEFLAGS")
+ end
+ end
+
+ it "doesn't pass down -j to make when MAKEFLAGS is set" do
+ ENV["MAKEFLAGS"] = "-j1"
+
+ install_gemfile(<<~G, env: { "BUNDLE_JOBS" => "8" })
+ source "https://gem.repo4"
+ gem "mypsych"
+ G
+
+ gem_make_out = File.read(File.join(@gemspec.extension_dir, "gem_make.out"))
+
+ expect(gem_make_out).not_to include("make -j8")
+ end
+
+ it "pass down the BUNDLE_JOBS to RubyGems when running the compilation of an extension" do
+ ENV.delete("MAKEFLAGS")
+
+ install_gemfile(<<~G, env: { "BUNDLE_JOBS" => "8" })
+ source "https://gem.repo4"
+ gem "mypsych"
+ G
+
+ gem_make_out = File.read(File.join(@gemspec.extension_dir, "gem_make.out"))
+
+ expect(gem_make_out).to include("make -j8")
+ end
+
+ it "uses nprocessors by default" do
+ ENV.delete("MAKEFLAGS")
+
+ install_gemfile(<<~G)
+ source "https://gem.repo4"
+ gem "mypsych"
+ G
+
+ gem_make_out = File.read(File.join(@gemspec.extension_dir, "gem_make.out"))
+
+ expect(gem_make_out).to include("make -j#{Etc.nprocessors + 1}")
+ end
+ end
+
+ describe "when a native extension requires a transitive dependency at build time" do
+ before do
+ build_repo4 do
+ build_gem "alpha", "1.0.0" do |s|
+ extension = "ext/alpha/extconf.rb"
+ s.extensions = extension
+ s.write(extension, <<~CODE)
+ require "mkmf"
+ sleep 1
+ create_makefile("alpha")
+ CODE
+ s.write "lib/alpha.rb", "ALPHA = '1.0.0'"
+ end
+
+ build_gem "beta", "1.0.0" do |s|
+ s.add_dependency "alpha"
+ s.write "lib/beta.rb", "require 'alpha'\nBETA = '1.0.0'"
+ end
+
+ build_gem "gamma", "1.0.0" do |s|
+ s.add_dependency "beta"
+ extension = "ext/gamma/extconf.rb"
+ s.extensions = extension
+ s.write(extension, <<~EXTCONF)
+ require "beta"
+ require "mkmf"
+ create_makefile("gamma")
+ EXTCONF
+ end
+ end
+ end
+
+ it "installs successfully" do
+ install_gemfile <<~G
+ source "https://gem.repo4"
+ gem "gamma"
+ G
+
+ expect(the_bundle).to include_gems "alpha 1.0.0", "beta 1.0.0", "gamma 1.0.0"
+ end
+ end
+
describe "when configured path is UTF-8 and a file inside a gem package too" do
let(:app_path) do
path = tmp("♥")
@@ -1280,7 +1478,7 @@ RSpec.describe "bundle install with gem sources" do
end
it "works" do
- bundle "config path #{app_path}/vendor/bundle", dir: app_path
+ bundle "config set path #{app_path}/vendor/bundle", dir: app_path
install_gemfile app_path.join("Gemfile"),<<~G, dir: app_path
source "https://gem.repo4"
@@ -1295,7 +1493,7 @@ RSpec.describe "bundle install with gem sources" do
source "https://gem.repo1"
gem "myrack"
G
- bundle "config set --local path bundle"
+ bundle_config "path bundle"
bundle "install", standalone: true
end
@@ -1353,7 +1551,7 @@ RSpec.describe "bundle install with gem sources" do
libv8
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
simulate_platform("x86_64-linux", &example)
@@ -1380,12 +1578,12 @@ RSpec.describe "bundle install with gem sources" do
libv8
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
it "fails loudly if frozen mode set" do
- bundle "config set --local deployment true"
+ bundle_config "deployment true"
bundle "install", raise_on_error: false
expect(err).to eq(
@@ -1456,12 +1654,12 @@ RSpec.describe "bundle install with gem sources" do
#{Bundler::RubyVersion.system}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
it "automatically fixes the lockfile" do
- bundle "config set --local path vendor/bundle"
+ bundle_config "path vendor/bundle"
simulate_platform "x86_64-linux" do
bundle "install", artifice: "compact_index"
@@ -1497,10 +1695,10 @@ RSpec.describe "bundle install with gem sources" do
loofah (~> 2.12.0)
#{checksums}
RUBY VERSION
- #{Bundler::RubyVersion.system}
+ #{Bundler::RubyVersion.system}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
end
@@ -1530,23 +1728,24 @@ RSpec.describe "bundle install with gem sources" do
myrack_middleware
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
it "raises a clear error message when frozen" do
- bundle "config set frozen true"
+ bundle_config "frozen true"
bundle "install", raise_on_error: false
expect(exitstatus).to eq(41)
- expect(err).to eq("Bundler found incorrect dependencies in the lockfile for myrack_middleware-1.0")
+ expect(err).to include("Bundler found incorrect dependencies in the lockfile for myrack_middleware-1.0")
+ expect(err).to include("myrack: gemspec specifies = 0.9.1, not in lockfile")
end
it "updates the lockfile when not frozen" do
missing_dep = "myrack (0.9.1)"
expect(lockfile).not_to include(missing_dep)
- bundle "config set frozen false"
+ bundle_config "frozen false"
bundle :install
expect(lockfile).to include(missing_dep)
@@ -1574,7 +1773,7 @@ RSpec.describe "bundle install with gem sources" do
context "with only option" do
before do
- bundle "config set only a:b"
+ bundle_config "only a:b"
end
it "installs only gems of the specified groups" do
@@ -1688,7 +1887,7 @@ RSpec.describe "bundle install with gem sources" do
before do
symlinked_bundled_app = tmp("bundled_app-symlink")
File.symlink(bundled_app, symlinked_bundled_app)
- bundle "config path #{File.join(symlinked_bundled_app, ".vendor")}"
+ bundle_config "path #{File.join(symlinked_bundled_app, ".vendor")}"
binman_path = tmp("binman")
FileUtils.mkdir_p binman_path
@@ -1777,7 +1976,7 @@ RSpec.describe "bundle install with gem sources" do
zzz!
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
@@ -1827,7 +2026,7 @@ RSpec.describe "bundle install with gem sources" do
end
it "only installs executable files in bin" do
- bundle "config set --local path vendor/bundle"
+ bundle_config "path vendor/bundle"
install_gemfile <<~G
source "https://gem.repo1"
@@ -1839,6 +2038,25 @@ RSpec.describe "bundle install with gem sources" do
expect(Dir.glob(vendored_gems("bin/*"))).to eq(expected_executables)
end
+ it "prevents removing binstubs when BUNDLE_CLEAN is set" do
+ build_repo4 do
+ build_gem "kamal", "4.0.6" do |s|
+ s.executables = ["kamal"]
+ end
+ end
+
+ gemfile = <<~G
+ source "https://gem.repo4"
+ gem "kamal"
+ G
+
+ install_gemfile(gemfile, env: { "BUNDLE_CLEAN" => "true", "BUNDLE_PATH" => "vendor/bundle" })
+
+ expected_executables = [vendored_gems("bin/kamal").to_s]
+ expected_executables << vendored_gems("bin/kamal.bat").to_s if Gem.win_platform?
+ expect(Dir.glob(vendored_gems("bin/*"))).to eq(expected_executables)
+ end
+
it "preserves lockfile versions conservatively" do
build_repo4 do
build_gem "mypsych", "4.0.6" do |s|
@@ -1868,7 +2086,7 @@ RSpec.describe "bundle install with gem sources" do
mypsych (~> 4.0)
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
install_gemfile <<~G
@@ -1891,7 +2109,7 @@ RSpec.describe "bundle install with gem sources" do
mypsych (~> 5.0)
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
end
diff --git a/spec/bundler/commands/licenses_spec.rb b/spec/bundler/commands/licenses_spec.rb
index bfec938efd..ebfad5ed4a 100644
--- a/spec/bundler/commands/licenses_spec.rb
+++ b/spec/bundler/commands/licenses_spec.rb
@@ -30,7 +30,7 @@ RSpec.describe "bundle licenses" do
gem "foo"
G
- bundle "config set auto_install 1"
+ bundle_config "auto_install 1"
bundle :licenses
expect(out).to include("Installing foo 1.0")
end
diff --git a/spec/bundler/commands/lock_spec.rb b/spec/bundler/commands/lock_spec.rb
index 19c1a5ca8b..8ab3cc7e8d 100644
--- a/spec/bundler/commands/lock_spec.rb
+++ b/spec/bundler/commands/lock_spec.rb
@@ -46,7 +46,7 @@ RSpec.describe "bundle lock" do
weakling
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
@@ -95,7 +95,7 @@ RSpec.describe "bundle lock" do
weakling
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
@@ -294,7 +294,7 @@ RSpec.describe "bundle lock" do
foo
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
expect(out).to match(/Writing lockfile to.+CustomGemfile\.lock/)
expect(read_lockfile("CustomGemfile.lock")).to eq(lockfile)
@@ -311,6 +311,44 @@ RSpec.describe "bundle lock" do
expect { read_lockfile }.to raise_error(Errno::ENOENT)
end
+ it "updates a specific gem and write to a custom location" do
+ build_repo4 do
+ build_gem "foo", %w[1.0.2 1.0.3]
+ build_gem "warning", %w[1.4.0 1.5.0]
+ end
+
+ gemfile <<~G
+ source "https://gem.repo4"
+
+ gem "foo"
+ gem "warning"
+ G
+
+ lockfile <<~L
+ GEM
+ remote: https://gem.repo4
+ specs:
+ foo (1.0.2)
+ warning (1.4.0)
+
+ PLATFORMS
+ #{lockfile_platforms}
+
+ DEPENDENCIES
+ uri
+ warning
+
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+
+ bundle "lock --update foo --lockfile=lock"
+
+ lockfile_content = read_lockfile("lock")
+ expect(lockfile_content).to include("foo (1.0.3)")
+ expect(lockfile_content).to include("warning (1.4.0)")
+ end
+
it "writes to custom location using --lockfile when a default lockfile is present" do
gemfile_with_rails_weakling_and_foo_from_repo4
@@ -361,7 +399,7 @@ RSpec.describe "bundle lock" do
weakling
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
expect(out).to match(/Writing lockfile to.+lock/)
@@ -415,7 +453,7 @@ RSpec.describe "bundle lock" do
weakling
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
lockfile lockfile_with_outdated_rails_and_rake
@@ -472,7 +510,7 @@ RSpec.describe "bundle lock" do
tapioca
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
bundle "lock --update tapioca --verbose"
@@ -538,7 +576,7 @@ RSpec.describe "bundle lock" do
tapioca
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
bundle "lock --update tapioca"
@@ -611,7 +649,7 @@ RSpec.describe "bundle lock" do
rake
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
bundle "lock --update rake --verbose"
@@ -639,8 +677,8 @@ RSpec.describe "bundle lock" do
gem "thin"
gem "myrack_middleware", :group => "test"
G
- bundle "config set without test"
- bundle "config set path vendor/bundle"
+ bundle_config "without test"
+ bundle_config "path vendor/bundle"
bundle "lock", verbose: true
expect(bundled_app("vendor/bundle")).not_to exist
end
@@ -768,7 +806,7 @@ RSpec.describe "bundle lock" do
sequel
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
allow(Bundler::SharedHelpers).to receive(:find_gemfile).and_return(bundled_app_gemfile)
@@ -794,14 +832,14 @@ RSpec.describe "bundle lock" do
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 }
- expect(lockfile).to end_with("BUNDLED WITH\n 55\n")
+ expect(lockfile).to end_with("BUNDLED WITH\n 55\n")
- update_repo4 do
+ build_repo4 do
build_gem "bundler", "99"
end
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")
+ expect(lockfile).to end_with("BUNDLED WITH\n 99\n")
end
it "supports adding new platforms when there's no previous lockfile" do
@@ -856,7 +894,7 @@ RSpec.describe "bundle lock" do
foo
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
bundle "lock --add-platform java"
@@ -876,7 +914,7 @@ RSpec.describe "bundle lock" do
foo
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
end
@@ -899,7 +937,7 @@ RSpec.describe "bundle lock" do
platform_specific
L
- bundle "config set force_ruby_platform true"
+ bundle_config "force_ruby_platform true"
bundle "lock --add-platform java x86-mingw32"
allow(Bundler::SharedHelpers).to receive(:find_gemfile).and_return(bundled_app_gemfile)
@@ -972,7 +1010,7 @@ RSpec.describe "bundle lock" do
nokogiri
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
checksums.delete("nokogiri", Gem::Platform::RUBY)
@@ -994,7 +1032,7 @@ RSpec.describe "bundle lock" do
nokogiri
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
@@ -1071,10 +1109,10 @@ RSpec.describe "bundle lock" do
mixlib-shellout
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
G
- bundle "config set --local force_ruby_platform true"
+ bundle_config "force_ruby_platform true"
bundle :lock
checksums.checksum gem_repo4, "ffi", "1.9.14"
@@ -1103,7 +1141,7 @@ RSpec.describe "bundle lock" do
mixlib-shellout
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
G
end
@@ -1140,7 +1178,7 @@ RSpec.describe "bundle lock" do
libv8
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
G
simulate_platform("x86_64-darwin-19") { bundle "lock --update" }
@@ -1187,7 +1225,7 @@ RSpec.describe "bundle lock" do
libv8
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
G
end
@@ -1227,7 +1265,7 @@ RSpec.describe "bundle lock" do
libv8
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
G
previous_lockfile = lockfile
@@ -1280,7 +1318,7 @@ RSpec.describe "bundle lock" do
raygun-apm
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
bundle "lock --add-platform x86_64-linux"
@@ -1314,7 +1352,7 @@ RSpec.describe "bundle lock" do
nokogiri
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
simulate_platform "x86_64-linux" do
@@ -1336,7 +1374,7 @@ RSpec.describe "bundle lock" do
nokogiri
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
@@ -1366,7 +1404,7 @@ RSpec.describe "bundle lock" do
sorbet-static
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
simulate_platform "x86_64-linux" do
@@ -1408,7 +1446,7 @@ RSpec.describe "bundle lock" do
our_private_gem
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
bundle "install", artifice: "compact_index", env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s }
@@ -1418,7 +1456,7 @@ RSpec.describe "bundle lock" do
before do
gemfile_with_rails_weakling_and_foo_from_repo4
- update_repo4 do
+ build_repo4 do
build_gem "foo", "2.0"
end
@@ -1472,7 +1510,7 @@ RSpec.describe "bundle lock" do
weakling
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
expect(read_lockfile).to eq(expected_lockfile)
@@ -1526,7 +1564,7 @@ RSpec.describe "bundle lock" do
weakling
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
expect(read_lockfile).to eq(expected_lockfile)
@@ -1580,7 +1618,7 @@ RSpec.describe "bundle lock" do
debug
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
simulate_platform "arm64-darwin-22" do
@@ -1603,7 +1641,7 @@ RSpec.describe "bundle lock" do
debug
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
end
@@ -1661,7 +1699,7 @@ RSpec.describe "bundle lock" do
foo
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
end
@@ -1764,7 +1802,7 @@ RSpec.describe "bundle lock" do
ransack (= 3.1.0)
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
expected_error = <<~ERR.strip
@@ -1906,7 +1944,7 @@ RSpec.describe "bundle lock" do
nogokiri
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
simulate_platform "x86_64-linux" do
@@ -1933,7 +1971,7 @@ RSpec.describe "bundle lock" do
nokogiri
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
@@ -1966,7 +2004,7 @@ RSpec.describe "bundle lock" do
nokogiri
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
simulate_platform "x86_64-linux" do
@@ -1993,7 +2031,57 @@ RSpec.describe "bundle lock" do
nokogiri
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
+ L
+ end
+
+ it "adds checksums when source is not specified" do
+ system_gems(%w[myrack-1.0.0], path: default_bundle_path)
+
+ gemfile <<-G
+ gem "myrack"
+ G
+
+ lockfile <<~L
+ GEM
+ specs:
+ myrack (1.0.0)
+
+ PLATFORMS
+ ruby
+ x86_64-linux
+
+ DEPENDENCIES
+ myrack
+
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+
+ simulate_platform "x86_64-linux" do
+ bundle "lock --add-checksums"
+ end
+
+ # myrack is coming from gem_repo1
+ # but it's simulated to install in the system gems path
+ checksums = checksums_section do |c|
+ c.checksum gem_repo1, "myrack", "1.0.0"
+ end
+
+ expect(lockfile).to eq <<~L
+ GEM
+ specs:
+ myrack (1.0.0)
+
+ PLATFORMS
+ ruby
+ x86_64-linux
+
+ DEPENDENCIES
+ myrack
+ #{checksums}
+ BUNDLED WITH
+ #{Bundler::VERSION}
L
end
@@ -2026,7 +2114,7 @@ RSpec.describe "bundle lock" do
nokogiri
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
simulate_platform "x86_64-linux" do
@@ -2055,11 +2143,11 @@ RSpec.describe "bundle lock" do
nokogiri
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
- it "generates checksums by default if configured to do so" do
+ it "generates checksums by default" do
build_repo4 do
build_gem "nokogiri", "1.14.2"
build_gem "nokogiri", "1.14.2" do |s|
@@ -2067,8 +2155,6 @@ RSpec.describe "bundle lock" do
end
end
- bundle "config lockfile_checksums true"
-
simulate_platform "x86_64-linux" do
install_gemfile <<-G
source "https://gem.repo4"
@@ -2097,7 +2183,136 @@ RSpec.describe "bundle lock" do
nokogiri
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
+ L
+ end
+
+ it "disables checksums if configured to do so" do
+ build_repo4 do
+ build_gem "nokogiri", "1.14.2"
+ build_gem "nokogiri", "1.14.2" do |s|
+ s.platform = "x86_64-linux"
+ end
+ end
+
+ bundle_config "lockfile_checksums false"
+
+ simulate_platform "x86_64-linux" do
+ install_gemfile <<-G
+ source "https://gem.repo4"
+
+ gem "nokogiri"
+ G
+ end
+
+ expect(lockfile).to eq <<~L
+ GEM
+ remote: https://gem.repo4/
+ specs:
+ nokogiri (1.14.2)
+ nokogiri (1.14.2-x86_64-linux)
+
+ PLATFORMS
+ ruby
+ x86_64-linux
+
+ DEPENDENCIES
+ nokogiri
+
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+ end
+
+ it "add checksums for gems installed on disk" do
+ build_repo4 do
+ build_gem "warning", "18.0.0"
+ end
+
+ bundle_config "lockfile_checksums false"
+
+ simulate_platform "x86_64-linux" do
+ install_gemfile(<<-G, artifice: "endpoint")
+ source "https://gem.repo4"
+
+ gem "warning"
+ G
+
+ bundle "config --delete lockfile_checksums"
+ bundle("lock --add-checksums", artifice: "endpoint")
+ end
+
+ checksums = checksums_section do |c|
+ c.checksum gem_repo4, "warning", "18.0.0"
+ end
+
+ expect(lockfile).to eq <<~L
+ GEM
+ remote: https://gem.repo4/
+ specs:
+ warning (18.0.0)
+
+ PLATFORMS
+ ruby
+ x86_64-linux
+
+ DEPENDENCIES
+ warning
+ #{checksums}
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+ end
+
+ it "doesn't add checksum for gems not installed on disk" do
+ lockfile(<<~L)
+ GEM
+ remote: https://gem.repo4/
+ specs:
+ warning (18.0.0)
+
+ PLATFORMS
+ #{local_platform}
+
+ DEPENDENCIES
+ warning
+
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+
+ gemfile(<<~G)
+ source "https://gem.repo4"
+
+ gem "warning"
+ G
+
+ build_repo4 do
+ build_gem "warning", "18.0.0"
+ end
+
+ FileUtils.rm_rf("#{gem_repo4}/gems")
+
+ bundle("lock --add-checksums", artifice: "endpoint")
+
+ checksums = checksums_section_when_enabled do |c|
+ c.no_checksum "warning", "18.0.0"
+ end
+
+ expect(lockfile).to eq <<~L
+ GEM
+ remote: https://gem.repo4/
+ specs:
+ warning (18.0.0)
+
+ PLATFORMS
+ #{local_platform}
+
+ DEPENDENCIES
+ warning
+ #{checksums}
+ BUNDLED WITH
+ #{Bundler::VERSION}
L
end
@@ -2178,7 +2393,7 @@ RSpec.describe "bundle lock" do
foo!
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
@@ -2208,7 +2423,7 @@ RSpec.describe "bundle lock" do
foo!
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
@@ -2243,7 +2458,7 @@ RSpec.describe "bundle lock" do
foo!
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
end
@@ -2298,7 +2513,7 @@ RSpec.describe "bundle lock" do
govuk_app_config
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
@@ -2334,7 +2549,7 @@ RSpec.describe "bundle lock" do
govuk_app_config
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
end
@@ -2370,7 +2585,7 @@ RSpec.describe "bundle lock" do
ffi
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
@@ -2394,7 +2609,7 @@ RSpec.describe "bundle lock" do
ffi
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
end
@@ -2416,7 +2631,7 @@ RSpec.describe "bundle lock" do
irb
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
@@ -2465,7 +2680,7 @@ RSpec.describe "bundle lock" do
irb
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
@@ -2496,7 +2711,7 @@ RSpec.describe "bundle lock" do
irb
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
@@ -2545,7 +2760,7 @@ RSpec.describe "bundle lock" do
irb
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
@@ -2573,7 +2788,7 @@ RSpec.describe "bundle lock" do
irb
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
@@ -2601,7 +2816,7 @@ RSpec.describe "bundle lock" do
irb
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
@@ -2631,7 +2846,7 @@ RSpec.describe "bundle lock" do
sorbet-static
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
diff --git a/spec/bundler/commands/newgem_spec.rb b/spec/bundler/commands/newgem_spec.rb
index 40bc1c3ff4..65fbad05aa 100644
--- a/spec/bundler/commands/newgem_spec.rb
+++ b/spec/bundler/commands/newgem_spec.rb
@@ -31,6 +31,13 @@ RSpec.describe "bundle gem" do
matched[:ignored]&.split(" ")
end
+ def installed_go?
+ sys_exec("go version", raise_on_error: true)
+ true
+ rescue StandardError
+ false
+ end
+
let(:generated_gemspec) { Bundler.load_gemspec_uncached(bundled_app(gem_name).join("#{gem_name}.gemspec")) }
let(:gem_name) { "mygem" }
@@ -40,8 +47,13 @@ RSpec.describe "bundle gem" do
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", "BUNDLE_GEM__BUNDLE" => "false"
+ bundle_config_global "gem.mit false"
+ bundle_config_global "gem.test false"
+ bundle_config_global "gem.coc false"
+ bundle_config_global "gem.linter false"
+ bundle_config_global "gem.ci false"
+ bundle_config_global "gem.changelog false"
+ bundle_config_global "gem.bundle false"
end
describe "git repo initialization" do
@@ -175,75 +187,6 @@ RSpec.describe "bundle gem" do
end
end
- shared_examples_for "--rubocop flag" do
- context "is deprecated" do
- before do
- global_config "BUNDLE_GEM__LINTER" => nil
- bundle "gem #{gem_name} --rubocop"
- end
-
- it "generates a gem skeleton with rubocop" do
- gem_skeleton_assertions
- expect(bundled_app("#{gem_name}/Rakefile")).to read_as(
- include("# frozen_string_literal: true").
- and(include('require "rubocop/rake_task"').
- and(include("RuboCop::RakeTask.new").
- and(match(/default:.+:rubocop/))))
- )
- end
-
- it "includes rubocop in generated Gemfile" do
- allow(Bundler::SharedHelpers).to receive(:find_gemfile).and_return(bundled_app_gemfile)
- builder = Bundler::Dsl.new
- builder.eval_gemfile(bundled_app("#{gem_name}/Gemfile"))
- builder.dependencies
- rubocop_dep = builder.dependencies.find {|d| d.name == "rubocop" }
- expect(rubocop_dep).not_to be_nil
- end
-
- it "generates a default .rubocop.yml" do
- expect(bundled_app("#{gem_name}/.rubocop.yml")).to exist
- end
-
- it "includes .rubocop.yml into ignore list" do
- expect(ignore_paths).to include(".rubocop.yml")
- end
- end
- end
-
- shared_examples_for "--no-rubocop flag" do
- context "is deprecated" do
- define_negated_matcher :exclude, :include
-
- before do
- bundle "gem #{gem_name} --no-rubocop"
- end
-
- it "generates a gem skeleton without rubocop" do
- gem_skeleton_assertions
- expect(bundled_app("#{gem_name}/Rakefile")).to read_as(exclude("rubocop"))
- expect(bundled_app("#{gem_name}/#{gem_name}.gemspec")).to read_as(exclude("rubocop"))
- end
-
- it "does not include rubocop in generated Gemfile" do
- allow(Bundler::SharedHelpers).to receive(:find_gemfile).and_return(bundled_app_gemfile)
- builder = Bundler::Dsl.new
- builder.eval_gemfile(bundled_app("#{gem_name}/Gemfile"))
- builder.dependencies
- rubocop_dep = builder.dependencies.find {|d| d.name == "rubocop" }
- expect(rubocop_dep).to be_nil
- end
-
- it "doesn't generate a default .rubocop.yml" do
- expect(bundled_app("#{gem_name}/.rubocop.yml")).to_not exist
- end
-
- it "does not add .rubocop.yml into ignore list" do
- expect(ignore_paths).not_to include(".rubocop.yml")
- end
- end
- end
-
shared_examples_for "--linter=rubocop flag" do
before do
bundle "gem #{gem_name} --linter=rubocop"
@@ -265,7 +208,8 @@ RSpec.describe "bundle gem" do
builder.eval_gemfile(bundled_app("#{gem_name}/Gemfile"))
builder.dependencies
rubocop_dep = builder.dependencies.find {|d| d.name == "rubocop" }
- expect(rubocop_dep).not_to be_nil
+ expect(rubocop_dep).not_to be_specific
+ expect(rubocop_dep.requirement).to eq(Gem::Requirement.new([">= 0"]))
end
it "generates a default .rubocop.yml" do
@@ -296,7 +240,8 @@ RSpec.describe "bundle gem" do
builder.eval_gemfile(bundled_app("#{gem_name}/Gemfile"))
builder.dependencies
standard_dep = builder.dependencies.find {|d| d.name == "standard" }
- expect(standard_dep).not_to be_nil
+ expect(standard_dep).not_to be_specific
+ expect(standard_dep.requirement).to eq(Gem::Requirement.new([">= 0"]))
end
it "generates a default .standard.yml" do
@@ -586,7 +531,7 @@ RSpec.describe "bundle gem" do
shared_examples_for "github_username configuration" do
context "with github_username setting set to some value" do
before do
- global_config "BUNDLE_GEM__GITHUB_USERNAME" => "different_username"
+ bundle_config_global "gem.github_username different_username"
bundle "gem #{gem_name}"
end
@@ -602,7 +547,7 @@ RSpec.describe "bundle gem" do
context "with github_username setting set to false" do
before do
- global_config "BUNDLE_GEM__GITHUB_USERNAME" => "false"
+ bundle_config_global "gem.github_username false"
bundle "gem #{gem_name}"
end
@@ -707,6 +652,15 @@ RSpec.describe "bundle gem" do
to match(/example\.com/)
end
+ it "includes a commented-out rubygems_mfa_required metadata hint" do
+ bundle "gem #{gem_name}"
+
+ gemspec_contents = bundled_app("#{gem_name}/#{gem_name}.gemspec").read
+
+ expect(gemspec_contents).to include('# spec.metadata["rubygems_mfa_required"] = "true"')
+ expect(gemspec_contents).to include("https://guides.rubygems.org/mfa-requirement-opt-in/")
+ end
+
it "sets a minimum ruby version" do
bundle "gem #{gem_name}"
@@ -794,19 +748,20 @@ RSpec.describe "bundle gem" do
expect(ignore_paths).to include("spec/")
end
- it "depends on a specific version of rspec in generated Gemfile" do
+ it "depends on a non-specific version of rspec in generated Gemfile" do
allow(Bundler::SharedHelpers).to receive(:find_gemfile).and_return(bundled_app_gemfile)
builder = Bundler::Dsl.new
builder.eval_gemfile(bundled_app("#{gem_name}/Gemfile"))
builder.dependencies
rspec_dep = builder.dependencies.find {|d| d.name == "rspec" }
- expect(rspec_dep).to be_specific
+ expect(rspec_dep).not_to be_specific
+ expect(rspec_dep.requirement).to eq(Gem::Requirement.new([">= 0"]))
end
end
context "init_gems_rb setting to true" do
before do
- bundle "config set init_gems_rb true"
+ bundle_config "init_gems_rb true"
bundle "gem #{gem_name}"
end
@@ -824,7 +779,7 @@ RSpec.describe "bundle gem" do
context "init_gems_rb setting to false" do
before do
- bundle "config set init_gems_rb false"
+ bundle_config "init_gems_rb false"
bundle "gem #{gem_name}"
end
@@ -842,7 +797,7 @@ RSpec.describe "bundle gem" do
context "gem.test setting set to rspec" do
before do
- bundle "config set gem.test rspec"
+ bundle_config "gem.test rspec"
bundle "gem #{gem_name}"
end
@@ -860,7 +815,7 @@ RSpec.describe "bundle gem" do
context "gem.test setting set to rspec and --test is set to minitest" do
before do
- bundle "config set gem.test rspec"
+ bundle_config "gem.test rspec"
bundle "gem #{gem_name} --test=minitest"
end
@@ -879,13 +834,14 @@ RSpec.describe "bundle gem" do
bundle "gem #{gem_name} --test=minitest"
end
- it "depends on a specific version of minitest" do
+ it "depends on a non-specific version of minitest" do
allow(Bundler::SharedHelpers).to receive(:find_gemfile).and_return(bundled_app_gemfile)
builder = Bundler::Dsl.new
builder.eval_gemfile(bundled_app("#{gem_name}/Gemfile"))
builder.dependencies
minitest_dep = builder.dependencies.find {|d| d.name == "minitest" }
- expect(minitest_dep).to be_specific
+ expect(minitest_dep).not_to be_specific
+ expect(minitest_dep.requirement).to eq(Gem::Requirement.new([">= 0"]))
end
it "builds spec skeleton" do
@@ -915,7 +871,7 @@ RSpec.describe "bundle gem" do
context "gem.test setting set to minitest" do
before do
- bundle "config set gem.test minitest"
+ bundle_config "gem.test minitest"
bundle "gem #{gem_name}"
end
@@ -940,13 +896,14 @@ RSpec.describe "bundle gem" do
bundle "gem #{gem_name} --test=test-unit"
end
- it "depends on a specific version of test-unit" do
+ it "depends on a non-specific version of test-unit" do
allow(Bundler::SharedHelpers).to receive(:find_gemfile).and_return(bundled_app_gemfile)
builder = Bundler::Dsl.new
builder.eval_gemfile(bundled_app("#{gem_name}/Gemfile"))
builder.dependencies
test_unit_dep = builder.dependencies.find {|d| d.name == "test-unit" }
- expect(test_unit_dep).to be_specific
+ expect(test_unit_dep).not_to be_specific
+ expect(test_unit_dep.requirement).to eq(Gem::Requirement.new([">= 0"]))
end
it "builds spec skeleton" do
@@ -991,7 +948,7 @@ RSpec.describe "bundle gem" do
context "gem.test set to rspec and --test with no arguments" do
before do
- bundle "config set gem.test rspec"
+ bundle_config "gem.test rspec"
bundle "gem #{gem_name} --test"
end
@@ -1013,7 +970,7 @@ RSpec.describe "bundle gem" do
context "gem.test setting set to false and --test with no arguments", :readline do
before do
- bundle "config set gem.test false"
+ bundle_config "gem.test false"
bundle "gem #{gem_name} --test" do |input, _, _|
input.puts
end
@@ -1032,7 +989,7 @@ RSpec.describe "bundle gem" do
context "gem.test setting not set and --test with no arguments", :readline do
before do
- global_config "BUNDLE_GEM__TEST" => nil
+ bundle_config_global "BUNDLE_GEM__TEST" => nil
bundle "gem #{gem_name} --test" do |input, _, _|
input.puts
end
@@ -1053,7 +1010,7 @@ RSpec.describe "bundle gem" do
context "gem.test setting set to a test framework and --no-test" do
before do
- bundle "config set gem.test rspec"
+ bundle_config "gem.test rspec"
bundle "gem #{gem_name} --no-test"
end
@@ -1141,7 +1098,7 @@ RSpec.describe "bundle gem" do
context "gem.ci setting set to github" do
it "generates a GitHub Actions config file" do
- bundle "config set gem.ci github"
+ bundle_config "gem.ci github"
bundle "gem #{gem_name}"
expect(bundled_app("#{gem_name}/.github/workflows/main.yml")).to exist
@@ -1150,7 +1107,7 @@ RSpec.describe "bundle gem" do
context "gem.ci setting set to gitlab" do
it "generates a GitLab CI config file" do
- bundle "config set gem.ci gitlab"
+ bundle_config "gem.ci gitlab"
bundle "gem #{gem_name}"
expect(bundled_app("#{gem_name}/.gitlab-ci.yml")).to exist
@@ -1159,7 +1116,7 @@ RSpec.describe "bundle gem" do
context "gem.ci setting set to circle" do
it "generates a CircleCI config file" do
- bundle "config set gem.ci circle"
+ bundle_config "gem.ci circle"
bundle "gem #{gem_name}"
expect(bundled_app("#{gem_name}/.circleci/config.yml")).to exist
@@ -1168,7 +1125,7 @@ RSpec.describe "bundle gem" do
context "gem.ci set to github and --ci with no arguments" do
before do
- bundle "config set gem.ci github"
+ bundle_config "gem.ci github"
bundle "gem #{gem_name} --ci"
end
@@ -1183,7 +1140,7 @@ RSpec.describe "bundle gem" do
context "gem.ci setting set to false and --ci with no arguments", :readline do
before do
- bundle "config set gem.ci false"
+ bundle_config "gem.ci false"
bundle "gem #{gem_name} --ci" do |input, _, _|
input.puts "github"
end
@@ -1200,7 +1157,7 @@ RSpec.describe "bundle gem" do
context "gem.ci setting not set and --ci with no arguments", :readline do
before do
- global_config "BUNDLE_GEM__CI" => nil
+ bundle_config_global "BUNDLE_GEM__CI" => nil
bundle "gem #{gem_name} --ci" do |input, _, _|
input.puts "github"
end
@@ -1219,7 +1176,7 @@ RSpec.describe "bundle gem" do
context "gem.ci setting set to a CI service and --no-ci" do
before do
- bundle "config set gem.ci github"
+ bundle_config "gem.ci github"
bundle "gem #{gem_name} --no-ci"
end
@@ -1307,7 +1264,7 @@ RSpec.describe "bundle gem" do
context "gem.linter setting set to rubocop" do
before do
- bundle "config set gem.linter rubocop"
+ bundle_config "gem.linter rubocop"
bundle "gem #{gem_name}"
end
@@ -1322,7 +1279,7 @@ RSpec.describe "bundle gem" do
context "gem.linter setting set to standard" do
before do
- bundle "config set gem.linter standard"
+ bundle_config "gem.linter standard"
bundle "gem #{gem_name}"
end
@@ -1335,35 +1292,9 @@ RSpec.describe "bundle gem" do
end
end
- context "gem.rubocop setting set to true" do
- before do
- global_config "BUNDLE_GEM__LINTER" => nil
- bundle "config set gem.rubocop true"
- bundle "gem #{gem_name}"
- end
-
- it "generates rubocop config" do
- expect(bundled_app("#{gem_name}/.rubocop.yml")).to exist
- end
-
- it "includes .rubocop.yml into ignore list" do
- expect(ignore_paths).to include(".rubocop.yml")
- end
-
- it "unsets gem.rubocop" do
- bundle "config gem.rubocop"
- expect(out).to include("You have not configured a value for `gem.rubocop`")
- end
-
- it "sets gem.linter=rubocop instead" do
- bundle "config gem.linter"
- expect(out).to match(/Set for the current user .*: "rubocop"/)
- end
- end
-
context "gem.linter set to rubocop and --linter with no arguments" do
before do
- bundle "config set gem.linter rubocop"
+ bundle_config "gem.linter rubocop"
bundle "gem #{gem_name} --linter"
end
@@ -1382,7 +1313,7 @@ RSpec.describe "bundle gem" do
context "gem.linter setting set to false and --linter with no arguments", :readline do
before do
- bundle "config set gem.linter false"
+ bundle_config "gem.linter false"
bundle "gem #{gem_name} --linter" do |input, _, _|
input.puts "rubocop"
end
@@ -1399,7 +1330,7 @@ RSpec.describe "bundle gem" do
context "gem.linter setting not set and --linter with no arguments", :readline do
before do
- global_config "BUNDLE_GEM__LINTER" => nil
+ bundle_config_global "BUNDLE_GEM__LINTER" => nil
bundle "gem #{gem_name} --linter" do |input, _, _|
input.puts "rubocop"
end
@@ -1418,7 +1349,7 @@ RSpec.describe "bundle gem" do
context "gem.linter setting set to a linter and --no-linter" do
before do
- bundle "config set gem.linter rubocop"
+ bundle_config "gem.linter rubocop"
bundle "gem #{gem_name} --no-linter"
end
@@ -1521,7 +1452,7 @@ RSpec.describe "bundle gem" do
context "with mit option in bundle config settings set to true" do
before do
- global_config "BUNDLE_GEM__MIT" => "true"
+ bundle_config_global "gem.mit true"
end
it_behaves_like "--mit flag"
it_behaves_like "--no-mit flag"
@@ -1529,7 +1460,7 @@ RSpec.describe "bundle gem" do
context "with mit option in bundle config settings set to false" do
before do
- global_config "BUNDLE_GEM__MIT" => "false"
+ bundle_config_global "gem.mit false"
end
it_behaves_like "--mit flag"
it_behaves_like "--no-mit flag"
@@ -1537,7 +1468,7 @@ RSpec.describe "bundle gem" do
context "with coc option in bundle config settings set to true" do
before do
- global_config "BUNDLE_GEM__COC" => "true"
+ bundle_config_global "gem.coc true"
end
it_behaves_like "--coc flag"
it_behaves_like "--no-coc flag"
@@ -1545,7 +1476,7 @@ RSpec.describe "bundle gem" do
context "with coc option in bundle config settings set to false" do
before do
- global_config "BUNDLE_GEM__COC" => "false"
+ bundle_config_global "gem.coc false"
end
it_behaves_like "--coc flag"
it_behaves_like "--no-coc flag"
@@ -1553,29 +1484,25 @@ RSpec.describe "bundle gem" do
context "with rubocop option in bundle config settings set to true" do
before do
- global_config "BUNDLE_GEM__RUBOCOP" => "true"
+ bundle_config_global "gem.rubocop true"
end
it_behaves_like "--linter=rubocop flag"
it_behaves_like "--linter=standard flag"
it_behaves_like "--no-linter flag"
- it_behaves_like "--rubocop flag"
- it_behaves_like "--no-rubocop flag"
end
context "with rubocop option in bundle config settings set to false" do
before do
- global_config "BUNDLE_GEM__RUBOCOP" => "false"
+ bundle_config_global "gem.rubocop false"
end
it_behaves_like "--linter=rubocop flag"
it_behaves_like "--linter=standard flag"
it_behaves_like "--no-linter flag"
- it_behaves_like "--rubocop flag"
- it_behaves_like "--no-rubocop flag"
end
context "with linter option in bundle config settings set to rubocop" do
before do
- global_config "BUNDLE_GEM__LINTER" => "rubocop"
+ bundle_config_global "gem.linter rubocop"
end
it_behaves_like "--linter=rubocop flag"
it_behaves_like "--linter=standard flag"
@@ -1584,7 +1511,7 @@ RSpec.describe "bundle gem" do
context "with linter option in bundle config settings set to standard" do
before do
- global_config "BUNDLE_GEM__LINTER" => "standard"
+ bundle_config_global "gem.linter standard"
end
it_behaves_like "--linter=rubocop flag"
it_behaves_like "--linter=standard flag"
@@ -1593,7 +1520,7 @@ RSpec.describe "bundle gem" do
context "with linter option in bundle config settings set to false" do
before do
- global_config "BUNDLE_GEM__LINTER" => "false"
+ bundle_config_global "gem.linter false"
end
it_behaves_like "--linter=rubocop flag"
it_behaves_like "--linter=standard flag"
@@ -1602,7 +1529,7 @@ RSpec.describe "bundle gem" do
context "with changelog option in bundle config settings set to true" do
before do
- global_config "BUNDLE_GEM__CHANGELOG" => "true"
+ bundle_config_global "gem.changelog true"
end
it_behaves_like "--changelog flag"
it_behaves_like "--no-changelog flag"
@@ -1610,7 +1537,7 @@ RSpec.describe "bundle gem" do
context "with changelog option in bundle config settings set to false" do
before do
- global_config "BUNDLE_GEM__CHANGELOG" => "false"
+ bundle_config_global "gem.changelog false"
end
it_behaves_like "--changelog flag"
it_behaves_like "--no-changelog flag"
@@ -1618,7 +1545,7 @@ RSpec.describe "bundle gem" do
context "with bundle option in bundle config settings set to true" do
before do
- global_config "BUNDLE_GEM__BUNDLE" => "true"
+ bundle_config_global "gem.bundle true"
end
it_behaves_like "--bundle flag"
it_behaves_like "--no-bundle flag"
@@ -1631,7 +1558,7 @@ RSpec.describe "bundle gem" do
context "with bundle option in bundle config settings set to false" do
before do
- global_config "BUNDLE_GEM__BUNDLE" => "false"
+ bundle_config_global "gem.bundle false"
end
it_behaves_like "--bundle flag"
it_behaves_like "--no-bundle flag"
@@ -1648,7 +1575,7 @@ RSpec.describe "bundle gem" do
end
context "with github-username option in bundle config settings set to some value" do
before do
- global_config "BUNDLE_GEM__GITHUB_USERNAME" => "different_username"
+ bundle_config_global "gem.github_username different_username"
end
it_behaves_like "--github-username option", "gh_user"
end
@@ -1657,7 +1584,7 @@ RSpec.describe "bundle gem" do
context "with github-username option in bundle config settings set to false" do
before do
- global_config "BUNDLE_GEM__GITHUB_USERNAME" => "false"
+ bundle_config_global "gem.github_username false"
end
it_behaves_like "--github-username option", "gh_user"
end
@@ -1689,7 +1616,7 @@ RSpec.describe "bundle gem" do
context "with git config github.user set" do
context "with github-username option in bundle config settings set to some value" do
before do
- global_config "BUNDLE_GEM__GITHUB_USERNAME" => "different_username"
+ bundle_config_global "gem.github_username different_username"
end
it_behaves_like "--github-username option", "gh_user"
end
@@ -1698,7 +1625,7 @@ RSpec.describe "bundle gem" do
context "with github-username option in bundle config settings set to false" do
before do
- global_config "BUNDLE_GEM__GITHUB_USERNAME" => "false"
+ bundle_config_global "gem.github_username false"
end
it_behaves_like "--github-username option", "gh_user"
end
@@ -1760,24 +1687,6 @@ RSpec.describe "bundle gem" do
include_examples "paths that depend on gem name"
- context "--ext parameter with no value" do
- context "is deprecated" do
- it "prints deprecation when used after gem name" do
- bundle ["gem", "--ext", gem_name].compact.join(" ")
- expect(err).to include "[DEPRECATED]"
- expect(err).to include "`--ext` with no arguments has been deprecated"
- expect(bundled_app("#{gem_name}/ext/#{gem_name}/#{gem_name}.c")).to exist
- end
-
- it "prints deprecation when used before gem name" do
- bundle ["gem", gem_name, "--ext"].compact.join(" ")
- expect(err).to include "[DEPRECATED]"
- expect(err).to include "`--ext` with no arguments has been deprecated"
- expect(bundled_app("#{gem_name}/ext/#{gem_name}/#{gem_name}.c")).to exist
- end
- end
- end
-
context "--ext parameter set with C" do
let(:flags) { "--ext=c" }
@@ -1785,16 +1694,19 @@ RSpec.describe "bundle gem" do
bundle ["gem", gem_name, flags].compact.join(" ")
end
- it "is not deprecated" do
- expect(err).not_to include "[DEPRECATED] Option `--ext` without explicit value is deprecated."
- end
-
it "builds ext skeleton" do
expect(bundled_app("#{gem_name}/ext/#{gem_name}/extconf.rb")).to exist
expect(bundled_app("#{gem_name}/ext/#{gem_name}/#{gem_name}.h")).to exist
expect(bundled_app("#{gem_name}/ext/#{gem_name}/#{gem_name}.c")).to exist
end
+ it "generates native extension loading code" do
+ expect(bundled_app("#{gem_name}/lib/#{gem_name}.rb").read).to include(<<~RUBY)
+ require_relative "test_gem/version"
+ require "#{gem_name}/#{gem_name}"
+ RUBY
+ end
+
it "includes rake-compiler, but no Rust related changes" do
expect(bundled_app("#{gem_name}/Gemfile").read).to include('gem "rake-compiler"')
@@ -1840,12 +1752,12 @@ RSpec.describe "bundle gem" do
expect(bundled_app("#{gem_name}/ext/#{gem_name}/Cargo.toml")).to exist
expect(bundled_app("#{gem_name}/ext/#{gem_name}/extconf.rb")).to exist
expect(bundled_app("#{gem_name}/ext/#{gem_name}/src/lib.rs")).to exist
+ expect(bundled_app("#{gem_name}/ext/#{gem_name}/build.rs")).to exist
end
- it "includes rake-compiler, rb_sys gems and required_rubygems_version constraint" do
+ it "includes rake-compiler and rb_sys gems constraint" do
expect(bundled_app("#{gem_name}/Gemfile").read).to include('gem "rake-compiler"')
expect(bundled_app("#{gem_name}/#{gem_name}.gemspec").read).to include('spec.add_dependency "rb_sys"')
- expect(bundled_app("#{gem_name}/#{gem_name}.gemspec").read).to include('spec.required_rubygems_version = ">= ')
end
it "depends on compile task for build" do
@@ -1868,6 +1780,182 @@ RSpec.describe "bundle gem" do
expect(bundled_app("#{gem_name}/Rakefile").read).to eq(rakefile)
end
+
+ it "configures the crate such that `cargo test` works", :ruby_repo, :mri_only do
+ env = setup_rust_env
+ gem_path = bundled_app(gem_name)
+ result = sys_exec("cargo test", env: env, dir: gem_path, timeout: 300)
+
+ expect(result).to include("1 passed")
+ end
+
+ def setup_rust_env
+ skip "rust toolchain of mingw is broken" if RUBY_PLATFORM.match?("mingw")
+
+ env = {
+ "CARGO_HOME" => ENV.fetch("CARGO_HOME", File.join(ENV["HOME"], ".cargo")),
+ "RUSTUP_HOME" => ENV.fetch("RUSTUP_HOME", File.join(ENV["HOME"], ".rustup")),
+ "RUSTUP_TOOLCHAIN" => ENV.fetch("RUSTUP_TOOLCHAIN", "stable"),
+ }
+
+ system(env, "cargo", "-V", out: IO::NULL, err: [:child, :out])
+ skip "cargo not present" unless $?.success?
+ # Hermetic Cargo setup
+ RbConfig::CONFIG.each {|k, v| env["RBCONFIG_#{k}"] = v }
+ env
+ end
+ end
+
+ context "--ext parameter set with go" do
+ let(:flags) { "--ext=go" }
+
+ before do
+ bundle ["gem", gem_name, flags].compact.join(" ")
+ end
+
+ after do
+ sys_exec("go clean -modcache", raise_on_error: true) if installed_go?
+ end
+
+ it "is not deprecated" do
+ expect(err).not_to include "[DEPRECATED] Option `--ext` without explicit value is deprecated."
+ end
+
+ it "builds ext skeleton" do
+ expect(bundled_app("#{gem_name}/ext/#{gem_name}/#{gem_name}.c")).to exist
+ expect(bundled_app("#{gem_name}/ext/#{gem_name}/#{gem_name}.go")).to exist
+ expect(bundled_app("#{gem_name}/ext/#{gem_name}/#{gem_name}.h")).to exist
+ expect(bundled_app("#{gem_name}/ext/#{gem_name}/extconf.rb")).to exist
+ expect(bundled_app("#{gem_name}/ext/#{gem_name}/go.mod")).to exist
+ end
+
+ it "includes extconf.rb in gem_name.gemspec" do
+ expect(bundled_app("#{gem_name}/#{gem_name}.gemspec").read).to include(%(spec.extensions = ["ext/#{gem_name}/extconf.rb"]))
+ end
+
+ it "includes go_gem in gem_name.gemspec" do
+ expect(bundled_app("#{gem_name}/#{gem_name}.gemspec").read).to include('spec.add_dependency "go_gem", ">= 0.2"')
+ end
+
+ it "includes go_gem extension in extconf.rb" do
+ expect(bundled_app("#{gem_name}/ext/#{gem_name}/extconf.rb").read).to include(<<~RUBY)
+ require "mkmf"
+ require "go_gem/mkmf"
+ RUBY
+
+ expect(bundled_app("#{gem_name}/ext/#{gem_name}/extconf.rb").read).to include(%(create_go_makefile("#{gem_name}/#{gem_name}")))
+ expect(bundled_app("#{gem_name}/ext/#{gem_name}/extconf.rb").read).not_to include("create_makefile")
+ end
+
+ it "includes go_gem extension in gem_name.c" do
+ expect(bundled_app("#{gem_name}/ext/#{gem_name}/#{gem_name}.c").read).to eq(<<~C)
+ #include "#{gem_name}.h"
+ #include "_cgo_export.h"
+ C
+ end
+
+ it "includes skeleton code in gem_name.go" do
+ expect(bundled_app("#{gem_name}/ext/#{gem_name}/#{gem_name}.go").read).to include(<<~GO)
+ /*
+ #include "#{gem_name}.h"
+
+ VALUE rb_#{gem_name}_sum(VALUE self, VALUE a, VALUE b);
+ */
+ import "C"
+ GO
+
+ expect(bundled_app("#{gem_name}/ext/#{gem_name}/#{gem_name}.go").read).to include(<<~GO)
+ //export rb_#{gem_name}_sum
+ func rb_#{gem_name}_sum(_ C.VALUE, a C.VALUE, b C.VALUE) C.VALUE {
+ GO
+
+ expect(bundled_app("#{gem_name}/ext/#{gem_name}/#{gem_name}.go").read).to include(<<~GO)
+ //export Init_#{gem_name}
+ func Init_#{gem_name}() {
+ GO
+ end
+
+ it "includes valid module name in go.mod" do
+ expect(bundled_app("#{gem_name}/ext/#{gem_name}/go.mod").read).to include("module github.com/bundleuser/#{gem_name}")
+ end
+
+ it "includes go_gem extension in Rakefile" do
+ expect(bundled_app("#{gem_name}/Rakefile").read).to include(<<~RUBY)
+ require "go_gem/rake_task"
+
+ GoGem::RakeTask.new("#{gem_name}")
+ RUBY
+ end
+
+ context "with --no-ci" do
+ let(:flags) { "--ext=go --no-ci" }
+
+ it_behaves_like "CI config is absent"
+ end
+
+ context "--ci set to github" do
+ let(:flags) { "--ext=go --ci=github" }
+
+ it "generates .github/workflows/main.yml" do
+ expect(bundled_app("#{gem_name}/.github/workflows/main.yml")).to exist
+ expect(bundled_app("#{gem_name}/.github/workflows/main.yml").read).to include("go-version-file: ext/#{gem_name}/go.mod")
+ end
+ end
+
+ context "--ci set to circle" do
+ let(:flags) { "--ext=go --ci=circle" }
+
+ it "generates a .circleci/config.yml" do
+ expect(bundled_app("#{gem_name}/.circleci/config.yml")).to exist
+
+ expect(bundled_app("#{gem_name}/.circleci/config.yml").read).to include(<<-YAML.strip)
+ environment:
+ GO_VERSION:
+ YAML
+
+ expect(bundled_app("#{gem_name}/.circleci/config.yml").read).to include(<<-YAML)
+ - run:
+ name: Install Go
+ command: |
+ wget https://go.dev/dl/go$GO_VERSION.linux-amd64.tar.gz -O /tmp/go.tar.gz
+ tar -C /usr/local -xzf /tmp/go.tar.gz
+ echo 'export PATH=/usr/local/go/bin:"$PATH"' >> "$BASH_ENV"
+ YAML
+ end
+ end
+
+ context "--ci set to gitlab" do
+ let(:flags) { "--ext=go --ci=gitlab" }
+
+ it "generates a .gitlab-ci.yml" do
+ expect(bundled_app("#{gem_name}/.gitlab-ci.yml")).to exist
+
+ expect(bundled_app("#{gem_name}/.gitlab-ci.yml").read).to include(<<-YAML)
+ - wget https://go.dev/dl/go$GO_VERSION.linux-amd64.tar.gz -O /tmp/go.tar.gz
+ - tar -C /usr/local -xzf /tmp/go.tar.gz
+ - export PATH=/usr/local/go/bin:$PATH
+ YAML
+
+ expect(bundled_app("#{gem_name}/.gitlab-ci.yml").read).to include(<<-YAML.strip)
+ variables:
+ GO_VERSION:
+ YAML
+ end
+ end
+
+ context "without github.user" do
+ before do
+ # FIXME: GitHub Actions Windows Runner hang up here for some reason...
+ skip "Workaround for hung up" if Gem.win_platform?
+
+ git("config --global --unset github.user")
+ bundle ["gem", gem_name, flags].compact.join(" ")
+ end
+
+ it "includes valid module name in go.mod" do
+ expect(bundled_app("#{gem_name}/ext/#{gem_name}/go.mod").read).to include("module github.com/username/#{gem_name}")
+ end
+ end
end
end
@@ -1937,6 +2025,19 @@ Usage: "bundle gem NAME [OPTIONS]"
it { expect(err).to include("Invalid gem name #{subject}") }
end
+ context "starting with a number" do
+ subject { "1gem" }
+ it { expect(err).to include("Invalid gem name #{subject}") }
+ end
+
+ context "including capital letter" do
+ subject { "CAPITAL" }
+ it "should warn but not error" do
+ expect(err).to include("Gem names with capital letters are not recommended")
+ expect(bundled_app("#{subject}/#{subject}.gemspec")).to exist
+ end
+ end
+
context "starting with an existing const name" do
subject { "gem-somenewconstantname" }
it { expect(err).not_to include("Invalid gem name #{subject}") }
@@ -1950,7 +2051,7 @@ Usage: "bundle gem NAME [OPTIONS]"
context "on first run", :readline do
it "asks about test framework" do
- global_config "BUNDLE_GEM__TEST" => nil
+ bundle_config_global "BUNDLE_GEM__TEST" => nil
bundle "gem foobar" do |input, _, _|
input.puts "rspec"
@@ -1973,7 +2074,7 @@ Usage: "bundle gem NAME [OPTIONS]"
end
it "asks about CI service" do
- global_config "BUNDLE_GEM__CI" => nil
+ bundle_config_global "BUNDLE_GEM__CI" => nil
bundle "gem foobar" do |input, _, _|
input.puts "github"
@@ -1983,7 +2084,7 @@ Usage: "bundle gem NAME [OPTIONS]"
end
it "asks about MIT license just once" do
- global_config "BUNDLE_GEM__MIT" => nil
+ bundle_config_global "BUNDLE_GEM__MIT" => nil
bundle "config list"
@@ -1996,7 +2097,7 @@ Usage: "bundle gem NAME [OPTIONS]"
end
it "asks about CoC just once" do
- global_config "BUNDLE_GEM__COC" => nil
+ bundle_config_global "BUNDLE_GEM__COC" => nil
bundle "gem foobar" do |input, _, _|
input.puts "yes"
@@ -2007,7 +2108,7 @@ Usage: "bundle gem NAME [OPTIONS]"
end
it "asks about CHANGELOG just once" do
- global_config "BUNDLE_GEM__CHANGELOG" => nil
+ bundle_config_global "BUNDLE_GEM__CHANGELOG" => nil
bundle "gem foobar" do |input, _, _|
input.puts "yes"
diff --git a/spec/bundler/commands/open_spec.rb b/spec/bundler/commands/open_spec.rb
index e0c79aa407..664dc58919 100644
--- a/spec/bundler/commands/open_spec.rb
+++ b/spec/bundler/commands/open_spec.rb
@@ -49,7 +49,7 @@ RSpec.describe "bundle open" do
it "suggests alternatives for similar-sounding gems" do
bundle "open Rails", env: { "EDITOR" => "echo editor", "VISUAL" => "", "BUNDLER_EDITOR" => "" }, raise_on_error: false
- expect(err).to match(/did you mean rails\?/i)
+ expect(err).to match(/did you mean 'rails'\?/i)
end
it "opens the gem with short words" do
@@ -80,12 +80,12 @@ RSpec.describe "bundle open" do
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
- expect(err).to match(/did you mean rails\?/i)
+ 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
- expect(err).to match(/did you mean rails\?/i)
+ expect(err).to match(/did you mean 'rails'\?/i)
end
it "opens subpath of the short worded gem" do
@@ -139,7 +139,7 @@ RSpec.describe "bundle open" do
gem "foo"
G
- bundle "config set auto_install 1"
+ bundle_config "auto_install 1"
bundle "open rails", env: { "EDITOR" => "echo editor", "VISUAL" => "", "BUNDLER_EDITOR" => "" }
expect(out).to include("Installing foo 1.0")
end
diff --git a/spec/bundler/commands/outdated_spec.rb b/spec/bundler/commands/outdated_spec.rb
index b66b8c9e53..28ed51d61e 100644
--- a/spec/bundler/commands/outdated_spec.rb
+++ b/spec/bundler/commands/outdated_spec.rb
@@ -30,7 +30,7 @@ RSpec.describe "bundle outdated" do
bundle "outdated", raise_on_error: false
expected_output = <<~TABLE.gsub("x", "\\\h").tr(".", "\.").strip
- Gem Current Latest Requested Groups
+ Gem Current Latest Requested Groups Release Date
activesupport 2.3.5 3.0 = 2.3.5 default
foo 1.0 xxxxxxx 1.0 xxxxxxx >= 0 default
weakling 0.0.3 0.2 ~> 0.0.1 default
@@ -53,7 +53,7 @@ RSpec.describe "bundle outdated" do
bundle "outdated", raise_on_error: false
expected_output = <<~TABLE
- Gem Current Latest Requested Groups
+ Gem Current Latest Requested Groups Release Date
AAA 1.0.0 2.0.0 = 1.0.0 default
TABLE
@@ -92,7 +92,7 @@ RSpec.describe "bundle outdated" do
bundle "outdated", raise_on_error: false
expected_output = <<~TABLE.strip
- Gem Current Latest Requested Groups
+ Gem Current Latest Requested Groups Release Date
activesupport 2.3.5 3.0 = 2.3.5 development, test
terranova 8 9 = 8 default
TABLE
@@ -120,7 +120,7 @@ RSpec.describe "bundle outdated" do
end
it "shows the location of the latest version's gemspec if installed" do
- bundle "config set clean false"
+ bundle_config "clean false"
update_repo2 { build_gem "activesupport", "3.0" }
update_repo2 { build_gem "terranova", "9" }
@@ -142,81 +142,15 @@ RSpec.describe "bundle outdated" do
bundle "outdated --verbose", raise_on_error: false
expected_output = <<~TABLE.strip
- Gem Current Latest Requested Groups Path
+ Gem Current Latest Requested Groups Release Date Path
activesupport 2.3.5 3.0 = 2.3.5 default
- terranova 8 9 = 8 default #{default_bundle_path("specifications/terranova-9.gemspec")}
+ terranova 8 9 = 8 default #{default_bundle_path("specifications/terranova-9.gemspec")}
TABLE
expect(out).to end_with(expected_output)
end
end
- describe "with multiple, duplicated sources, with lockfile in old format" do
- before do
- build_repo2 do
- build_gem "dotenv", "2.7.6"
-
- build_gem "oj", "3.11.3"
- build_gem "oj", "3.11.5"
-
- build_gem "vcr", "6.0.0"
- end
-
- build_repo3 do
- build_gem "pkg-gem-flowbyte-with-dep", "1.0.0" do |s|
- s.add_dependency "oj"
- end
- end
-
- gemfile <<~G
- source "https://gem.repo2"
-
- gem "dotenv"
-
- source "https://gem.repo3" do
- gem 'pkg-gem-flowbyte-with-dep'
- end
-
- gem "vcr",source: "https://gem.repo2"
- G
-
- lockfile <<~L
- GEM
- remote: https://gem.repo2/
- remote: https://gem.repo3/
- specs:
- dotenv (2.7.6)
- oj (3.11.3)
- pkg-gem-flowbyte-with-dep (1.0.0)
- oj
- vcr (6.0.0)
-
- PLATFORMS
- #{local_platform}
-
- DEPENDENCIES
- dotenv
- pkg-gem-flowbyte-with-dep!
- vcr!
-
- BUNDLED WITH
- #{Bundler::VERSION}
- L
- end
-
- it "works" do
- bundle :install, artifice: "compact_index"
- bundle :outdated, artifice: "compact_index", raise_on_error: false
-
- expected_output = <<~TABLE
- Gem Current Latest Requested Groups
- oj 3.11.3 3.11.5
- TABLE
-
- expect(out).to include(expected_output.strip)
- end
- end
-
describe "with --group option" do
before do
build_repo2 do
@@ -263,7 +197,7 @@ RSpec.describe "bundle outdated" do
test_group_option("default")
expected_output = <<~TABLE.strip
- Gem Current Latest Requested Groups
+ Gem Current Latest Requested Groups Release Date
terranova 8 9 = 8 default
TABLE
@@ -274,7 +208,7 @@ RSpec.describe "bundle outdated" do
test_group_option("development")
expected_output = <<~TABLE.strip
- Gem Current Latest Requested Groups
+ Gem Current Latest Requested Groups Release Date
activesupport 2.3.5 3.0 = 2.3.5 development, test
duradura 7.0 8.0 = 7.0 development, test
TABLE
@@ -286,7 +220,7 @@ RSpec.describe "bundle outdated" do
test_group_option("test")
expected_output = <<~TABLE.strip
- Gem Current Latest Requested Groups
+ Gem Current Latest Requested Groups Release Date
activesupport 2.3.5 3.0 = 2.3.5 development, test
duradura 7.0 8.0 = 7.0 development, test
TABLE
@@ -323,7 +257,7 @@ RSpec.describe "bundle outdated" do
bundle "outdated --groups", raise_on_error: false
expected_output = <<~TABLE.strip
- Gem Current Latest Requested Groups
+ Gem Current Latest Requested Groups Release Date
bar 2.0.0 3.0.0
TABLE
@@ -365,7 +299,7 @@ RSpec.describe "bundle outdated" do
bundle "outdated --groups", raise_on_error: false
expected_output = <<~TABLE.strip
- Gem Current Latest Requested Groups
+ Gem Current Latest Requested Groups Release Date
activesupport 2.3.5 3.0 = 2.3.5 development, test
duradura 7.0 8.0 = 7.0 development, test
terranova 8 9 = 8 default
@@ -399,7 +333,7 @@ RSpec.describe "bundle outdated" do
build_gem "activesupport", "2.3.4"
end
- bundle "config set clean false"
+ bundle_config "clean false"
install_gemfile <<-G
source "https://gem.repo2"
@@ -409,7 +343,7 @@ RSpec.describe "bundle outdated" do
bundle "outdated --local", raise_on_error: false
expected_output = <<~TABLE.strip
- Gem Current Latest Requested Groups
+ Gem Current Latest Requested Groups Release Date
activesupport 2.3.4 2.3.5 = 2.3.4 default
TABLE
@@ -520,7 +454,7 @@ RSpec.describe "bundle outdated" do
bundle "outdated foo", raise_on_error: false
expected_output = <<~TABLE.gsub("x", "\\\h").tr(".", "\.").strip
- Gem Current Latest Requested Groups
+ Gem Current Latest Requested Groups Release Date
foo 1.0 xxxxxxx 1.0 xxxxxxx >= 0 default
TABLE
@@ -551,13 +485,13 @@ RSpec.describe "bundle outdated" do
zeitwerk
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
bundle "outdated zeitwerk", raise_on_error: false
expected_output = <<~TABLE.tr(".", "\.").strip
- Gem Current Latest Requested Groups
+ Gem Current Latest Requested Groups Release Date
zeitwerk 1.0.0 2.0.0 >= 0 default
TABLE
@@ -605,7 +539,7 @@ RSpec.describe "bundle outdated" do
bundle "outdated --pre", raise_on_error: false
expected_output = <<~TABLE.strip
- Gem Current Latest Requested Groups
+ Gem Current Latest Requested Groups Release Date
activesupport 2.3.5 3.0.0.beta = 2.3.5 default
TABLE
@@ -628,7 +562,7 @@ RSpec.describe "bundle outdated" do
bundle "outdated", raise_on_error: false
expected_output = <<~TABLE.strip
- Gem Current Latest Requested Groups
+ Gem Current Latest Requested Groups Release Date
activesupport 3.0.0.beta.1 3.0.0.beta.2 = 3.0.0.beta.1 default
TABLE
@@ -664,7 +598,7 @@ RSpec.describe "bundle outdated" do
bundle :outdated, "filter-strict": true, raise_on_error: false
expected_output = <<~TABLE.strip
- Gem Current Latest Requested Groups
+ Gem Current Latest Requested Groups Release Date
weakling 0.0.3 0.0.5 ~> 0.0.1 default
TABLE
@@ -680,7 +614,7 @@ RSpec.describe "bundle outdated" do
bundle :outdated, strict: true, raise_on_error: false
expected_output = <<~TABLE.strip
- Gem Current Latest Requested Groups
+ Gem Current Latest Requested Groups Release Date
weakling 0.0.3 0.0.5 ~> 0.0.1 default
TABLE
@@ -725,7 +659,7 @@ RSpec.describe "bundle outdated" do
bundle :outdated, :"filter-strict" => true, "filter-patch" => true, :raise_on_error => false
expected_output = <<~TABLE.strip
- Gem Current Latest Requested Groups
+ Gem Current Latest Requested Groups Release Date
weakling 0.0.3 0.0.5 >= 0.0.1 default
TABLE
@@ -747,7 +681,7 @@ RSpec.describe "bundle outdated" do
bundle :outdated, :"filter-strict" => true, "filter-minor" => true, :raise_on_error => false
expected_output = <<~TABLE.strip
- Gem Current Latest Requested Groups
+ Gem Current Latest Requested Groups Release Date
weakling 0.0.3 0.1.5 >= 0.0.1 default
TABLE
@@ -769,7 +703,7 @@ RSpec.describe "bundle outdated" do
bundle :outdated, :"filter-strict" => true, "filter-major" => true, :raise_on_error => false
expected_output = <<~TABLE.strip
- Gem Current Latest Requested Groups
+ Gem Current Latest Requested Groups Release Date
weakling 0.0.3 1.1.5 >= 0.0.1 default
TABLE
@@ -814,12 +748,12 @@ RSpec.describe "bundle outdated" do
gem "foo"
G
- bundle "config set auto_install 1"
+ bundle_config "auto_install 1"
bundle :outdated, raise_on_error: false
expect(out).to include("Installing foo 1.0")
end
- context "after bundle install --deployment" do
+ context "in deployment mode" do
before do
build_repo2
@@ -830,7 +764,7 @@ RSpec.describe "bundle outdated" do
gem "foo"
G
bundle :lock
- bundle :install, deployment: true
+ bundle_config "deployment true"
end
it "outputs a helpful message about being in deployment mode" do
@@ -858,7 +792,7 @@ RSpec.describe "bundle outdated" do
gem "myrack"
gem "foo"
G
- bundle "config set --local deployment true"
+ bundle_config "deployment true"
end
it "outputs a helpful message about being in deployment mode" do
@@ -913,7 +847,7 @@ RSpec.describe "bundle outdated" do
bundle "outdated", raise_on_error: false
expected_output = <<~TABLE.strip
- Gem Current Latest Requested Groups
+ Gem Current Latest Requested Groups Release Date
laduradura 5.15.2 5.15.3 = 5.15.2 default
TABLE
@@ -1215,7 +1149,7 @@ RSpec.describe "bundle outdated" do
bundle "outdated --patch --filter-patch", raise_on_error: false
expected_output = <<~TABLE.strip
- Gem Current Latest Requested Groups
+ Gem Current Latest Requested Groups Release Date
major 1.0.0 1.0.1 >= 0 default
minor 1.0.0 1.0.1 >= 0 default
patch 1.0.0 1.0.1 >= 0 default
@@ -1228,7 +1162,7 @@ RSpec.describe "bundle outdated" do
bundle "outdated --minor --filter-minor", raise_on_error: false
expected_output = <<~TABLE.strip
- Gem Current Latest Requested Groups
+ Gem Current Latest Requested Groups Release Date
major 1.0.0 1.1.0 >= 0 default
minor 1.0.0 1.1.0 >= 0 default
TABLE
@@ -1282,7 +1216,7 @@ RSpec.describe "bundle outdated" do
bundle "outdated --patch --filter-patch", raise_on_error: false, env: { "DEBUG_RESOLVER" => "1" }
expected_output = <<~TABLE.strip
- Gem Current Latest Requested Groups
+ Gem Current Latest Requested Groups Release Date
bar 2.0.3 2.0.5
foo 1.4.3 1.4.4 >= 0 default
TABLE
@@ -1294,7 +1228,7 @@ RSpec.describe "bundle outdated" do
bundle "outdated --patch --filter-patch", raise_on_error: false, env: { "DEBUG" => "1" }
expected_output = <<~TABLE.strip
- Gem Current Latest Requested Groups Path
+ Gem Current Latest Requested Groups Release Date Path
bar 2.0.3 2.0.5
foo 1.4.3 1.4.4 >= 0 default
TABLE
@@ -1326,7 +1260,7 @@ RSpec.describe "bundle outdated" do
bundle "outdated --only-explicit", raise_on_error: false
expected_output = <<~TABLE.strip
- Gem Current Latest Requested Groups
+ Gem Current Latest Requested Groups Release Date
weakling 0.2 0.3 >= 0 default
TABLE
@@ -1363,7 +1297,7 @@ RSpec.describe "bundle outdated" do
nokogiri
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
gemfile <<-G
@@ -1376,7 +1310,7 @@ RSpec.describe "bundle outdated" do
bundle "outdated", raise_on_error: false
expected_output = <<~TABLE.strip
- Gem Current Latest Requested Groups
+ Gem Current Latest Requested Groups Release Date
nokogiri 1.11.1 1.11.2 >= 0 default
TABLE
@@ -1417,7 +1351,7 @@ RSpec.describe "bundle outdated" do
mini_portile2
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
@@ -1425,7 +1359,7 @@ RSpec.describe "bundle outdated" do
bundle "outdated", raise_on_error: false
expected_output = <<~TABLE.strip
- Gem Current Latest Requested Groups
+ Gem Current Latest Requested Groups Release Date
mini_portile2 2.5.2 2.5.3 >= 0 default
TABLE
diff --git a/spec/bundler/commands/platform_spec.rb b/spec/bundler/commands/platform_spec.rb
index d42fa2adb3..9d7354c54f 100644
--- a/spec/bundler/commands/platform_spec.rb
+++ b/spec/bundler/commands/platform_spec.rb
@@ -227,7 +227,7 @@ G
ruby 1.0.0p127
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
bundle "platform --ruby"
@@ -250,7 +250,7 @@ G
DEPENDENCIES
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
bundle "platform --ruby"
@@ -302,9 +302,9 @@ G
expect(err).to be_include("Your #{local_ruby_engine} version is #{local_engine_version}, but your Gemfile specified #{local_ruby_engine} #{not_local_engine_version}")
end
- def should_be_patchlevel_incorrect
- expect(exitstatus).to eq(18)
- expect(err).to be_include("Your Ruby patchlevel is #{RUBY_PATCHLEVEL}, but your Gemfile specified #{not_local_patchlevel}")
+ def should_ignore_patchlevel
+ expect(exitstatus).to eq(0)
+ expect(err).to eq("")
end
def should_be_patchlevel_fixnum
@@ -382,7 +382,7 @@ G
should_be_engine_version_incorrect
end
- it "doesn't install when patchlevel doesn't match" do
+ it "does install even when patchlevel doesn't match" do
install_gemfile <<-G, raise_on_error: false
source "https://gem.repo1"
gem "myrack"
@@ -390,8 +390,8 @@ G
#{patchlevel_incorrect}
G
- expect(bundled_app_lock).not_to exist
- should_be_patchlevel_incorrect
+ expect(bundled_app_lock).to exist
+ should_ignore_patchlevel
end
end
@@ -481,7 +481,7 @@ G
should_be_engine_version_incorrect
end
- it "fails when patchlevel doesn't match" do
+ it "checks fine even when patchlevel doesn't match" do
install_gemfile <<-G
source "https://gem.repo1"
gem "myrack"
@@ -494,8 +494,8 @@ G
#{patchlevel_incorrect}
G
- bundle :check, raise_on_error: false
- should_be_patchlevel_incorrect
+ bundle :check
+ should_ignore_patchlevel
end
end
@@ -598,10 +598,10 @@ G
should_be_engine_version_incorrect
end
- it "fails when patchlevel doesn't match" do
+ it "updates fine even when patchlevel doesn't match" do
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "https://gem.repo2"
+ gem "activesupport"
#{patchlevel_incorrect}
G
@@ -609,8 +609,9 @@ G
build_gem "activesupport", "3.0"
end
- bundle :update, all: true, raise_on_error: false
- should_be_patchlevel_incorrect
+ bundle :update, all: true
+ should_ignore_patchlevel
+ expect(the_bundle).to include_gems "activesupport 3.0"
end
end
@@ -682,19 +683,17 @@ G
should_be_engine_version_incorrect
end
- it "fails when patchlevel doesn't match" do
+ it "prints path even when patchlevel doesn't match" do
gemfile <<-G
source "https://gem.repo1"
- gem "myrack"
+ gem "rails"
#{patchlevel_incorrect}
G
- update_repo2 do
- build_gem "activesupport", "3.0"
- end
- bundle "show rails", raise_on_error: false
- should_be_patchlevel_incorrect
+ bundle "show rails"
+ should_ignore_patchlevel
+ expect(out).to eq(default_bundle_path("gems", "rails-2.3.2").to_s)
end
end
@@ -766,7 +765,7 @@ G
should_be_engine_version_incorrect
end
- it "fails when patchlevel doesn't match" do
+ it "copies the .gem file to vendor/cache even when patchlevel doesn't match" do
gemfile <<-G
source "https://gem.repo1"
gem "myrack"
@@ -774,8 +773,9 @@ G
#{patchlevel_incorrect}
G
- bundle :cache, raise_on_error: false
- should_be_patchlevel_incorrect
+ bundle :cache
+ should_ignore_patchlevel
+ expect(bundled_app("vendor/cache/myrack-1.0.0.gem")).to exist
end
end
@@ -847,7 +847,7 @@ G
should_be_engine_version_incorrect
end
- it "fails when patchlevel doesn't match" do
+ it "copies the .gem file to vendor/cache even when patchlevel doesn't match" do
gemfile <<-G
source "https://gem.repo1"
gem "myrack"
@@ -855,8 +855,9 @@ G
#{patchlevel_incorrect}
G
- bundle :cache, raise_on_error: false
- should_be_patchlevel_incorrect
+ bundle :cache
+ should_ignore_patchlevel
+ expect(bundled_app("vendor/cache/myrack-1.0.0.gem")).to exist
end
end
@@ -926,7 +927,7 @@ G
should_be_engine_version_incorrect
end
- it "fails when patchlevel doesn't match" do
+ it "activates the correct gem even when patchlevel doesn't match" do
gemfile <<-G
source "https://gem.repo1"
gem "myrack"
@@ -934,8 +935,9 @@ G
#{patchlevel_incorrect}
G
- bundle "exec myrackup", raise_on_error: false
- should_be_patchlevel_incorrect
+ bundle "exec myrackup"
+ should_ignore_patchlevel
+ expect(out).to include("1.0.0")
end
end
@@ -995,11 +997,15 @@ G
should_be_engine_version_incorrect
end
- it "fails when patchlevel doesn't match" do
+ it "starts IRB with the default group loaded even when patchlevel doesn't match", :readline do
gemfile gemfile + "\n\n#{patchlevel_incorrect}\n"
- bundle "console", raise_on_error: false
- should_be_patchlevel_incorrect
+ bundle "console" do |input, _, _|
+ input.puts("puts MYRACK")
+ input.puts("exit")
+ end
+ should_ignore_patchlevel
+ expect(out).to include("0.9.1")
end
end
@@ -1095,7 +1101,7 @@ G
should_be_engine_version_incorrect
end
- it "fails when patchlevel doesn't match" do
+ it "makes a Gemfile.lock even when patchlevel doesn't match" do
install_gemfile <<-G, raise_on_error: false
source "https://gem.repo1"
gem "yard"
@@ -1106,10 +1112,10 @@ 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 }
- expect(bundled_app_lock).not_to exist
- should_be_patchlevel_incorrect
+ should_ignore_patchlevel
+ expect(bundled_app_lock).to exist
end
end
@@ -1143,7 +1149,7 @@ G
bundle "outdated", raise_on_error: false
expected_output = <<~TABLE.gsub("x", "\\\h").tr(".", "\.").strip
- Gem Current Latest Requested Groups
+ Gem Current Latest Requested Groups Release Date
activesupport 2.3.5 3.0 = 2.3.5 default
foo 1.0 xxxxxxx 1.0 xxxxxxx >= 0 default
TABLE
@@ -1169,7 +1175,7 @@ G
bundle "outdated", raise_on_error: false
expected_output = <<~TABLE.gsub("x", "\\\h").tr(".", "\.").strip
- Gem Current Latest Requested Groups
+ Gem Current Latest Requested Groups Release Date
activesupport 2.3.5 3.0 = 2.3.5 default
foo 1.0 xxxxxxx 1.0 xxxxxxx >= 0 default
TABLE
@@ -1231,7 +1237,7 @@ G
should_be_engine_version_incorrect
end
- it "fails when the patchlevel doesn't match", :jruby_only do
+ it "reports outdated gems even when patchlevel doesn't match" do
update_repo2 do
build_gem "activesupport", "3.0"
update_git "foo", path: lib_path("foo")
@@ -1246,25 +1252,9 @@ G
G
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")
- end
-
- gemfile <<-G
- source "https://gem.repo2"
- gem "activesupport", "2.3.5"
- gem "foo", :git => "#{lib_path("foo")}"
-
- #{patchlevel_fixnum}
- G
-
- bundle "outdated", raise_on_error: false
- should_be_patchlevel_fixnum
+ expect(err).not_to include("patchlevel")
+ expect(out).to include("activesupport")
+ expect(out).to include("foo")
end
end
end
diff --git a/spec/bundler/commands/post_bundle_message_spec.rb b/spec/bundler/commands/post_bundle_message_spec.rb
index 1dfa58dfd7..088fc29fe1 100644
--- a/spec/bundler/commands/post_bundle_message_spec.rb
+++ b/spec/bundler/commands/post_bundle_message_spec.rb
@@ -18,11 +18,11 @@ RSpec.describe "post bundle message" do
let(:bundle_show_path_message) { "Bundled gems are installed into `#{bundle_path}`" }
let(:bundle_complete_message) { "Bundle complete!" }
let(:bundle_updated_message) { "Bundle updated!" }
- let(:installed_gems_stats) { "4 Gemfile dependencies, 5 gems now installed." }
+ let(:installed_gems_stats) { "4 Gemfile dependencies, 4 gems now installed." }
describe "when installing to system gems" do
before do
- bundle "config set --local path.system true"
+ bundle_config "path.system true"
end
it "shows proper messages according to the configured groups" do
@@ -32,26 +32,26 @@ RSpec.describe "post bundle message" do
expect(out).to include(bundle_complete_message)
expect(out).to include(installed_gems_stats)
- bundle "config set --local without emo"
+ bundle_config "without emo"
bundle :install
expect(out).to include(bundle_show_system_message)
expect(out).to include("Gems in the group 'emo' were not installed")
expect(out).to include(bundle_complete_message)
expect(out).to include(installed_gems_stats)
- bundle "config set --local without emo test"
+ bundle_config "without emo test"
bundle :install
expect(out).to include(bundle_show_system_message)
expect(out).to include("Gems in the groups 'emo' and 'test' were not installed")
expect(out).to include(bundle_complete_message)
- expect(out).to include("4 Gemfile dependencies, 3 gems now installed.")
+ expect(out).to include("4 Gemfile dependencies, 2 gems now installed.")
- bundle "config set --local without emo obama test"
+ bundle_config "without emo obama test"
bundle :install
expect(out).to include(bundle_show_system_message)
expect(out).to include("Gems in the groups 'emo', 'obama' and 'test' were not installed")
expect(out).to include(bundle_complete_message)
- expect(out).to include("4 Gemfile dependencies, 2 gems now installed.")
+ expect(out).to include("4 Gemfile dependencies, 1 gem now installed.")
end
describe "for second bundle install run" do
@@ -69,28 +69,28 @@ RSpec.describe "post bundle message" do
let(:bundle_path) { "./vendor" }
it "shows proper messages according to the configured groups" do
- bundle "config set --local path vendor"
+ bundle_config "path vendor"
bundle :install
expect(out).to include(bundle_show_path_message)
expect(out).to_not include("Gems in the group")
expect(out).to include(bundle_complete_message)
- bundle "config set --local path vendor"
- bundle "config set --local without emo"
+ bundle_config "path vendor"
+ bundle_config "without emo"
bundle :install
expect(out).to include(bundle_show_path_message)
expect(out).to include("Gems in the group 'emo' were not installed")
expect(out).to include(bundle_complete_message)
- bundle "config set --local path vendor"
- bundle "config set --local without emo test"
+ bundle_config "path vendor"
+ bundle_config "without emo test"
bundle :install
expect(out).to include(bundle_show_path_message)
expect(out).to include("Gems in the groups 'emo' and 'test' were not installed")
expect(out).to include(bundle_complete_message)
- bundle "config set --local path vendor"
- bundle "config set --local without emo obama test"
+ bundle_config "path vendor"
+ bundle_config "without emo obama test"
bundle :install
expect(out).to include(bundle_show_path_message)
expect(out).to include("Gems in the groups 'emo', 'obama' and 'test' were not installed")
@@ -102,7 +102,7 @@ RSpec.describe "post bundle message" do
let(:bundle_path) { bundled_app("cache") }
it "shows proper messages according to the configured groups" do
- bundle "config set --local path #{bundle_path}"
+ bundle_config "path #{bundle_path}"
bundle :install
expect(out).to include("Bundled gems are installed into `./cache`")
expect(out).to_not include("Gems in the group")
@@ -114,7 +114,7 @@ RSpec.describe "post bundle message" do
let(:bundle_path) { tmp("not_bundled_app") }
it "shows proper messages according to the configured groups" do
- bundle "config set --local path #{bundle_path}"
+ bundle_config "path #{bundle_path}"
bundle :install
expect(out).to include("Bundled gems are installed into `#{tmp("not_bundled_app")}`")
expect(out).to_not include("Gems in the group")
@@ -124,7 +124,7 @@ RSpec.describe "post bundle message" do
describe "with misspelled or non-existent gem name" do
before do
- bundle "config set force_ruby_platform true"
+ bundle_config "force_ruby_platform true"
end
it "should report a helpful error message" do
@@ -155,52 +155,25 @@ RSpec.describe "post bundle message" do
end
end
- describe "for second bundle install run after first run using --without" do
- it "with --without one group" do
- bundle "install --without emo"
- bundle :install
- expect(out).to include(bundle_show_system_message)
- expect(out).to include("Gems in the group 'emo' were not installed")
- expect(out).to include(bundle_complete_message)
- expect(out).to include(installed_gems_stats)
- end
-
- it "with --without two groups" do
- bundle "install --without emo test"
- bundle :install
- expect(out).to include(bundle_show_system_message)
- expect(out).to include("Gems in the groups 'emo' and 'test' were not installed")
- expect(out).to include(bundle_complete_message)
- end
-
- it "with --without more groups" do
- bundle "install --without emo obama test"
- bundle :install
- expect(out).to include(bundle_show_system_message)
- expect(out).to include("Gems in the groups 'emo', 'obama' and 'test' were not installed")
- expect(out).to include(bundle_complete_message)
- end
- end
-
describe "for bundle update" do
it "shows proper messages according to the configured groups" do
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_config "without emo"
bundle :install
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_config "without emo test"
bundle :install
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_config "without emo obama test"
bundle :install
bundle :update, all: true
expect(out).to include("Gems in the groups 'emo', 'obama' and 'test' were not updated")
diff --git a/spec/bundler/commands/pristine_spec.rb b/spec/bundler/commands/pristine_spec.rb
index da61dc8199..5f80b9e534 100644
--- a/spec/bundler/commands/pristine_spec.rb
+++ b/spec/bundler/commands/pristine_spec.rb
@@ -79,7 +79,7 @@ RSpec.describe "bundle pristine" do
it "displays warning and ignores changes when a local config exists" do
spec = find_spec("foo")
- bundle "config set local.#{spec.name} #{lib_path(spec.name)}"
+ bundle_config "local.#{spec.name} #{lib_path(spec.name)}"
changes_txt = Pathname.new(spec.full_gem_path).join("lib/changes.txt")
FileUtils.touch(changes_txt)
@@ -89,6 +89,66 @@ RSpec.describe "bundle pristine" do
expect(changes_txt).to be_file
expect(err).to include("Cannot pristine #{spec.name} (#{spec.version}#{spec.git_version}). Gem is locally overridden.")
end
+
+ it "doesn't run multiple git processes for the same repository" do
+ nested_gems = [
+ "actioncable",
+ "actionmailer",
+ "actionpack",
+ "actionview",
+ "activejob",
+ "activemodel",
+ "activerecord",
+ "activestorage",
+ "activesupport",
+ "railties",
+ ]
+
+ build_repo2 do
+ nested_gems.each do |gem|
+ build_lib gem, path: lib_path("rails/#{gem}")
+ end
+
+ build_git "rails", path: lib_path("rails") do |s|
+ nested_gems.each do |gem|
+ s.add_dependency gem
+ end
+ end
+ end
+
+ install_gemfile <<-G
+ source 'https://rubygems.org'
+
+ git "#{lib_path("rails")}" do
+ gem "rails"
+ gem "actioncable"
+ gem "actionmailer"
+ gem "actionpack"
+ gem "actionview"
+ gem "activejob"
+ gem "activemodel"
+ gem "activerecord"
+ gem "activestorage"
+ gem "activesupport"
+ gem "railties"
+ end
+ G
+
+ changed_files = []
+ diff = "#Pristine spec changes"
+
+ nested_gems.each do |gem|
+ spec = find_spec(gem)
+ changed_files << Pathname.new(spec.full_gem_path).join("lib/#{gem}.rb")
+ File.open(changed_files.last, "a") {|f| f.puts diff }
+ end
+
+ bundle "pristine"
+
+ changed_files.each do |changed_file|
+ expect(File.read(changed_file)).to_not include(diff)
+ end
+ end
end
context "when sourced from gemspec" do
@@ -167,7 +227,7 @@ RSpec.describe "bundle pristine" do
let(:very_simple_binary) { find_spec("very_simple_binary") }
let(:c_ext_dir) { Pathname.new(very_simple_binary.full_gem_path).join("ext") }
let(:build_opt) { "--with-ext-lib=#{c_ext_dir}" }
- before { bundle "config set build.very_simple_binary -- #{build_opt}" }
+ before { bundle_config "build.very_simple_binary -- #{build_opt}" }
# This just verifies that the generated Makefile from the c_ext gem makes
# use of the build_args from the bundle config
@@ -184,7 +244,7 @@ RSpec.describe "bundle pristine" do
let(:git_with_ext) { find_spec("git_with_ext") }
let(:c_ext_dir) { Pathname.new(git_with_ext.full_gem_path).join("ext") }
let(:build_opt) { "--with-ext-lib=#{c_ext_dir}" }
- before { bundle "config set build.git_with_ext -- #{build_opt}" }
+ before { bundle_config "build.git_with_ext -- #{build_opt}" }
# This just verifies that the generated Makefile from the c_ext gem makes
# use of the build_args from the bundle config
diff --git a/spec/bundler/commands/remove_spec.rb b/spec/bundler/commands/remove_spec.rb
index 3e16346195..8a2e6778ea 100644
--- a/spec/bundler/commands/remove_spec.rb
+++ b/spec/bundler/commands/remove_spec.rb
@@ -43,21 +43,6 @@ RSpec.describe "bundle remove" do
end
end
- context "when --install flag is specified" do
- it "removes gems from .bundle" do
- gemfile <<-G
- source "https://gem.repo1"
-
- gem "myrack"
- G
-
- bundle "remove myrack --install"
-
- expect(out).to include("myrack was removed.")
- expect(the_bundle).to_not include_gems "myrack"
- end
- end
-
describe "remove single gem from gemfile" do
context "when gem is present in gemfile" do
it "shows success for removed gem" do
diff --git a/spec/bundler/commands/show_spec.rb b/spec/bundler/commands/show_spec.rb
index ba903ac495..d0d55ffbb9 100644
--- a/spec/bundler/commands/show_spec.rb
+++ b/spec/bundler/commands/show_spec.rb
@@ -179,7 +179,7 @@ RSpec.describe "bundle show" do
gem "foo"
G
- bundle "config set auto_install 1"
+ bundle_config "auto_install 1"
bundle :show
expect(out).to include("Installing foo 1.0")
end
@@ -210,33 +210,6 @@ RSpec.describe "bundle show" do
expect(err).to include("Could not find gem '#{invalid_regexp}'.")
end
end
-
- context "--outdated option" do
- # Regression test for https://github.com/rubygems/bundler/issues/5375
- before do
- build_repo2
- end
-
- it "doesn't update gems to newer versions" do
- install_gemfile <<-G
- source "https://gem.repo2"
- gem "rails"
- G
-
- expect(the_bundle).to include_gem("rails 2.3.2")
-
- update_repo2 do
- build_gem "rails", "3.0.0" do |s|
- s.executables = "rails"
- end
- end
-
- bundle "show --outdated"
-
- bundle "install"
- expect(the_bundle).to include_gem("rails 2.3.2")
- end
- end
end
RSpec.describe "bundle show", bundler: "5" do
diff --git a/spec/bundler/commands/ssl_spec.rb b/spec/bundler/commands/ssl_spec.rb
index b4aca55194..4220731b69 100644
--- a/spec/bundler/commands/ssl_spec.rb
+++ b/spec/bundler/commands/ssl_spec.rb
@@ -16,16 +16,17 @@ RSpec.describe "bundle doctor ssl" do
end
end
- @previous_level = Bundler.ui.level
- Bundler.ui.instance_variable_get(:@warning_history).clear
- @previous_client = Gem::Request::ConnectionPools.client
+ @previous_ui = Bundler.ui
+ Bundler.ui = Bundler::UI::Shell.new
Bundler.ui.level = "info"
+
+ @previous_client = Gem::Request::ConnectionPools.client
Artifice.activate_with(@dummy_endpoint)
Gem::Request::ConnectionPools.client = Gem::Net::HTTP
end
after(:each) do
- Bundler.ui.level = @previous_level
+ Bundler.ui = @previous_ui
Artifice.deactivate
Gem::Request::ConnectionPools.client = @previous_client
end
diff --git a/spec/bundler/commands/update_spec.rb b/spec/bundler/commands/update_spec.rb
index 7702c72397..03a3786d80 100644
--- a/spec/bundler/commands/update_spec.rb
+++ b/spec/bundler/commands/update_spec.rb
@@ -110,7 +110,7 @@ RSpec.describe "bundle update" do
end
context "when update_requires_all_flag is set" do
- before { bundle "config set update_requires_all_flag true" }
+ before { bundle_config "update_requires_all_flag true" }
it "errors when passed nothing" do
install_gemfile "source 'https://gem.repo1'"
@@ -193,7 +193,7 @@ RSpec.describe "bundle update" do
end
it "should suggest alternatives" do
bundle "update platformspecific", raise_on_error: false
- expect(err).to include "Did you mean platform_specific?"
+ expect(err).to include "Did you mean 'platform_specific'?"
end
end
@@ -247,7 +247,7 @@ RSpec.describe "bundle update" do
expect(the_bundle).to include_gems("slim 3.0.9", "slim-rails 3.1.3", "slim_lint 0.16.1")
- update_repo4 do
+ build_repo4 do
build_gem "slim", "4.0.0" do |s|
s.add_dependency "tilt", [">= 2.0.6", "< 2.1"]
end
@@ -313,7 +313,7 @@ RSpec.describe "bundle update" do
country_select
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
previous_lockfile = lockfile
@@ -374,7 +374,7 @@ RSpec.describe "bundle update" do
quickbooks-ruby
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
bundle "update --conservative --verbose"
@@ -435,7 +435,7 @@ RSpec.describe "bundle update" do
sneakers
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
bundle "update --verbose"
@@ -480,7 +480,7 @@ RSpec.describe "bundle update" do
solargraph (~> 0.56.0)
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
bundle "lock --update solargraph"
@@ -544,7 +544,7 @@ RSpec.describe "bundle update" do
sidekiq (~> 6.5)
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
lockfile original_lockfile
@@ -572,7 +572,7 @@ RSpec.describe "bundle update" do
expect(the_bundle).to include_gems("a 1.0", "b 1.0", "c 2.0")
- update_repo4 do
+ build_repo4 do
build_gem "b", "2.0" do |s|
s.add_dependency "c", "< 2"
end
@@ -656,7 +656,7 @@ RSpec.describe "bundle update" do
activesupport (~> 6.0.0)
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
bundle "update activesupport"
@@ -708,7 +708,7 @@ RSpec.describe "bundle update" do
myrack-obama
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
bundle "install"
@@ -816,7 +816,7 @@ RSpec.describe "bundle update" do
end
it "should fail loudly" do
- bundle "install --deployment"
+ bundle_config "deployment true"
bundle "update", all: true, raise_on_error: false
expect(last_command).to be_failure
@@ -828,7 +828,7 @@ RSpec.describe "bundle update" do
end
it "should fail loudly when frozen is set globally" do
- bundle "config set --global frozen 1"
+ bundle_config_global "frozen 1"
bundle "update", all: true, raise_on_error: false
expect(err).to eq <<~ERROR.strip
Bundler is unlocking, but the lockfile can't be updated because frozen mode is set
@@ -838,7 +838,7 @@ RSpec.describe "bundle update" do
end
it "should fail loudly when deployment is set globally" do
- bundle "config set --global deployment true"
+ bundle_config_global "deployment true"
bundle "update", all: true, raise_on_error: false
expect(err).to eq <<~ERROR.strip
Bundler is unlocking, but the lockfile can't be updated because frozen mode is set
@@ -976,7 +976,7 @@ RSpec.describe "bundle update" do
bundle "update", all: true
expect(out).to match(/Resolving dependencies\.\.\.\.*\nBundle updated!/)
- update_repo4 do
+ build_repo4 do
build_gem "foo", "2.0"
end
@@ -1037,7 +1037,7 @@ RSpec.describe "bundle update" do
request_store
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
@@ -1074,71 +1074,9 @@ RSpec.describe "bundle update" do
request_store
BUNDLED WITH
- #{Bundler::VERSION}
- L
- end
- end
-
- context "with multiple, duplicated sources, with lockfile in old format" do
- before do
- build_repo2 do
- build_gem "dotenv", "2.7.6"
-
- build_gem "oj", "3.11.3"
- build_gem "oj", "3.11.5"
-
- build_gem "vcr", "6.0.0"
- end
-
- build_repo3 do
- build_gem "pkg-gem-flowbyte-with-dep", "1.0.0" do |s|
- s.add_dependency "oj"
- end
- end
-
- gemfile <<~G
- source "https://gem.repo2"
-
- gem "dotenv"
-
- source "https://gem.repo3" do
- gem 'pkg-gem-flowbyte-with-dep'
- end
-
- gem "vcr",source: "https://gem.repo2"
- G
-
- lockfile <<~L
- GEM
- remote: https://gem.repo2/
- remote: https://gem.repo3/
- specs:
- dotenv (2.7.6)
- oj (3.11.3)
- pkg-gem-flowbyte-with-dep (1.0.0)
- oj
- vcr (6.0.0)
-
- PLATFORMS
- #{local_platform}
-
- DEPENDENCIES
- dotenv
- pkg-gem-flowbyte-with-dep!
- vcr!
-
- BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
-
- it "works" do
- 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"
- end
end
end
@@ -1383,7 +1321,7 @@ RSpec.describe "bundle update --ruby" do
DEPENDENCIES
#{checksums_section_when_enabled}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
end
@@ -1415,10 +1353,10 @@ RSpec.describe "bundle update --ruby" do
DEPENDENCIES
#{checksums_section_when_enabled}
RUBY VERSION
- #{Bundler::RubyVersion.system}
+ #{Bundler::RubyVersion.system}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
end
@@ -1460,7 +1398,7 @@ RSpec.describe "bundle update --ruby" do
ruby 2.1.4p222
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
gemfile <<-G
@@ -1481,14 +1419,12 @@ RSpec.describe "bundle update --ruby" do
#{lockfile_platforms}
DEPENDENCIES
-
- CHECKSUMS
-
+ #{checksums_section_when_enabled}
RUBY VERSION
- #{Bundler::RubyVersion.system}
+ #{Bundler::RubyVersion.system}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
end
@@ -1522,7 +1458,7 @@ RSpec.describe "bundle update --bundler" do
myrack
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
lockfile lockfile.sub(/(^\s*)#{Bundler::VERSION}($)/, '\11.0.0\2')
@@ -1542,7 +1478,7 @@ RSpec.describe "bundle update --bundler" do
myrack
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
expect(the_bundle).to include_gem "myrack 1.0"
@@ -1580,14 +1516,14 @@ RSpec.describe "bundle update --bundler" do
myrack
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
expect(the_bundle).to include_gem "myrack 1.0"
end
it "updates the bundler version in the lockfile even if the latest version is not installed", :ruby_repo do
- bundle "config path.system true"
+ bundle_config "path.system true"
pristine_system_gems "bundler-9.0.0"
@@ -1599,6 +1535,7 @@ RSpec.describe "bundle update --bundler" do
checksums = checksums_section do |c|
c.checksum(gem_repo4, "myrack", "1.0")
+ c.checksum(gem_repo4, "bundler", "999.0.0")
end
install_gemfile <<-G
@@ -1625,7 +1562,7 @@ RSpec.describe "bundle update --bundler" do
myrack
#{checksums}
BUNDLED WITH
- 999.0.0
+ 999.0.0
L
expect(the_bundle).to include_gems "bundler 999.0.0"
@@ -1633,12 +1570,12 @@ RSpec.describe "bundle update --bundler" do
end
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"
+ pristine_system_gems "bundler-4.99.0"
build_repo4 do
build_gem "myrack", "3.0.9.1"
- build_bundler "2.99.0"
+ build_bundler "4.99.0"
end
gemfile <<~G
@@ -1683,6 +1620,7 @@ RSpec.describe "bundle update --bundler" do
checksums = checksums_section do |c|
c.checksum(gem_repo4, "myrack", "1.0")
+ c.checksum(gem_repo4, "bundler", "9.9.9")
end
install_gemfile <<-G
@@ -1707,7 +1645,7 @@ RSpec.describe "bundle update --bundler" do
myrack
#{checksums}
BUNDLED WITH
- 9.9.9
+ 9.9.9
L
expect(the_bundle).to include_gems "bundler 9.9.9"
@@ -1768,6 +1706,7 @@ RSpec.describe "bundle update --bundler" do
checksums = checksums_section_when_enabled do |c|
c.checksum(gem_repo4, "myrack", "1.0")
end
+ checksums.delete("bundler")
expect(lockfile).to eq <<~L
GEM
@@ -1782,7 +1721,7 @@ RSpec.describe "bundle update --bundler" do
myrack
#{checksums}
BUNDLED WITH
- 9.0.0.dev
+ 9.0.0.dev
L
expect(out).to include("Using bundler 9.0.0.dev")
@@ -1807,6 +1746,7 @@ RSpec.describe "bundle update --bundler" do
# Only updates properly on modern RubyGems.
checksums = checksums_section_when_enabled do |c|
c.checksum(gem_repo4, "myrack", "1.0")
+ c.checksum(local_gem_path, "bundler", "9.0.0", Gem::Platform::RUBY, "cache")
end
expect(lockfile).to eq <<~L
@@ -1822,7 +1762,7 @@ RSpec.describe "bundle update --bundler" do
myrack
#{checksums}
BUNDLED WITH
- 9.0.0
+ 9.0.0
L
expect(out).to include("Using bundler 9.0.0")
@@ -1896,7 +1836,7 @@ RSpec.describe "bundle update conservative" do
context "with patch set as default update level in config" do
it "should do a patch level update" do
- bundle "config set --local prefer_patch true"
+ bundle_config "prefer_patch true"
bundle "update foo"
expect(the_bundle).to include_gems "foo 1.4.5", "bar 2.1.1", "qux 1.0.0"
@@ -2015,7 +1955,7 @@ RSpec.describe "bundle update conservative" do
CHECKSUMS
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
@@ -2076,7 +2016,7 @@ RSpec.describe "bundle update conservative" do
shared_owner_b
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
@@ -2130,7 +2070,7 @@ RSpec.describe "bundle update conservative" do
nokogiri (>= 1.16.4)
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
diff --git a/spec/bundler/commands/version_spec.rb b/spec/bundler/commands/version_spec.rb
index 1019803c87..4320ad0611 100644
--- a/spec/bundler/commands/version_spec.rb
+++ b/spec/bundler/commands/version_spec.rb
@@ -12,53 +12,53 @@ RSpec.describe "bundle version" do
context "with -v" do
it "outputs the version and virtual version if set" do
bundle "-v"
- expect(out).to eq("Bundler version #{Bundler::VERSION}")
+ expect(out).to eq(Bundler::VERSION.to_s)
- bundle "config simulate_version 4"
+ bundle_config "simulate_version 5"
bundle "-v"
- expect(out).to eq("#{Bundler::VERSION} (simulating Bundler 4)")
+ expect(out).to eq("#{Bundler::VERSION} (simulating Bundler 5)")
end
end
context "with --version" do
it "outputs the version and virtual version if set" do
bundle "--version"
- expect(out).to eq("Bundler version #{Bundler::VERSION}")
+ expect(out).to eq(Bundler::VERSION.to_s)
- bundle "config simulate_version 4"
+ bundle_config "simulate_version 5"
bundle "--version"
- expect(out).to eq("#{Bundler::VERSION} (simulating Bundler 4)")
+ expect(out).to eq("#{Bundler::VERSION} (simulating Bundler 5)")
end
end
context "with version" do
context "when released", :ruby_repo do
before do
- system_gems "bundler-2.9.9", released: true
+ system_gems "bundler-4.9.9", released: true
end
it "outputs the version, virtual version if set, and build metadata" do
bundle "version"
- expect(out).to match(/\ABundler version 2\.9\.9 \(2100-01-01 commit #{COMMIT_HASH}\)\z/)
+ expect(out).to match(/\A4\.9\.9 \(2100-01-01 commit #{COMMIT_HASH}\)\z/)
- bundle "config simulate_version 4"
+ bundle_config "simulate_version 5"
bundle "version"
- expect(out).to match(/\A2\.9\.9 \(simulating Bundler 4\) \(2100-01-01 commit #{COMMIT_HASH}\)\z/)
+ expect(out).to match(/\A4\.9\.9 \(simulating Bundler 5\) \(2100-01-01 commit #{COMMIT_HASH}\)\z/)
end
end
context "when not released" do
before do
- system_gems "bundler-2.9.9", released: false
+ system_gems "bundler-4.9.9", released: false
end
it "outputs the version, virtual version if set, and build metadata" do
bundle "version"
- expect(out).to match(/\ABundler version 2\.9\.9 \(20\d{2}-\d{2}-\d{2} commit #{COMMIT_HASH}\)\z/)
+ expect(out).to match(/\A4\.9\.9 \(20\d{2}-\d{2}-\d{2} commit #{COMMIT_HASH}\)\z/)
- bundle "config simulate_version 4"
+ bundle_config "simulate_version 5"
bundle "version"
- expect(out).to match(/\A2\.9\.9 \(simulating Bundler 4\) \(20\d{2}-\d{2}-\d{2} commit #{COMMIT_HASH}\)\z/)
+ expect(out).to match(/\A4\.9\.9 \(simulating Bundler 5\) \(20\d{2}-\d{2}-\d{2} commit #{COMMIT_HASH}\)\z/)
end
end
end
diff --git a/spec/bundler/commands/viz_spec.rb b/spec/bundler/commands/viz_spec.rb
deleted file mode 100644
index 0ad285104c..0000000000
--- a/spec/bundler/commands/viz_spec.rb
+++ /dev/null
@@ -1,144 +0,0 @@
-# frozen_string_literal: true
-
-RSpec.describe "bundle viz", if: Bundler.which("dot") do
- before do
- base_system_gems "rexml", "ruby-graphviz"
- end
-
- it "graphs gems from the Gemfile" do
- install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
- gem "myrack-obama"
- G
-
- bundle "viz"
- expect(out).to include("gem_graph.png")
-
- bundle "viz", format: "debug"
- expect(out).to eq(<<~DOT.strip)
- digraph Gemfile {
- concentrate = "true";
- normalize = "true";
- nodesep = "0.55";
- edge[ weight = "2"];
- 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;
- }
- debugging bundle viz...
- DOT
- end
-
- it "graphs gems that are prereleases" do
- build_repo2 do
- build_gem "myrack", "1.3.pre"
- end
-
- install_gemfile <<-G
- source "https://gem.repo2"
- gem "myrack", "= 1.3.pre"
- gem "myrack-obama"
- G
-
- bundle "viz"
- expect(out).to include("gem_graph.png")
-
- bundle "viz", format: :debug, version: true
- expect(out).to eq(<<~EOS.strip)
- digraph Gemfile {
- concentrate = "true";
- normalize = "true";
- nodesep = "0.55";
- edge[ weight = "2"];
- 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;
- }
- debugging bundle viz...
- EOS
- end
-
- context "with another gem that has a graphviz file" do
- before do
- update_repo4 do
- build_gem "graphviz", "999" do |s|
- s.write("lib/graphviz.rb", "abort 'wrong graphviz gem loaded'")
- end
- end
-
- 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"
- G
-
- bundle "viz", format: "debug"
- expect(out).to eq(<<~DOT.strip)
- digraph Gemfile {
- concentrate = "true";
- normalize = "true";
- nodesep = "0.55";
- edge[ weight = "2"];
- 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;
- }
- debugging bundle viz...
- DOT
- end
- end
-
- context "--without option" do
- it "one group" do
- install_gemfile <<-G
- source "https://gem.repo1"
- gem "activesupport"
-
- group :rails do
- gem "rails"
- end
- G
-
- bundle "viz --without=rails"
- expect(out).to include("gem_graph.png")
- end
-
- it "two groups" do
- install_gemfile <<-G
- source "https://gem.repo1"
- gem "activesupport"
-
- group :myrack do
- gem "myrack"
- end
-
- group :rails do
- gem "rails"
- end
- G
-
- bundle "viz --without=rails:myrack"
- expect(out).to include("gem_graph.png")
- end
- end
-end
diff --git a/spec/bundler/install/allow_offline_install_spec.rb b/spec/bundler/install/allow_offline_install_spec.rb
index abe6009c08..c7ab7c3d7e 100644
--- a/spec/bundler/install/allow_offline_install_spec.rb
+++ b/spec/bundler/install/allow_offline_install_spec.rb
@@ -1,10 +1,6 @@
# frozen_string_literal: true
-RSpec.describe "bundle install with :allow_offline_install" do
- before do
- bundle "config set allow_offline_install true"
- end
-
+RSpec.describe "bundle install allows offline install" do
context "with no cached data locally" do
it "still installs" do
install_gemfile <<-G, artifice: "compact_index"
@@ -28,7 +24,7 @@ RSpec.describe "bundle install with :allow_offline_install" do
it "will install from the compact index" do
system_gems ["myrack-1.0.0"], path: default_bundle_path
- bundle "config set clean false"
+ bundle_config "clean false"
install_gemfile <<-G, artifice: "compact_index"
source "http://testgemserver.local"
gem "myrack-obama"
diff --git a/spec/bundler/install/binstubs_spec.rb b/spec/bundler/install/binstubs_spec.rb
index 00765ac6dd..c2eccb3ef2 100644
--- a/spec/bundler/install/binstubs_spec.rb
+++ b/spec/bundler/install/binstubs_spec.rb
@@ -10,7 +10,7 @@ RSpec.describe "bundle install" do
gem "myrack"
G
- config "BUNDLE_SYSTEM_BINDIR" => system_gem_path("altbin").to_s
+ bundle_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
diff --git a/spec/bundler/install/bundler_spec.rb b/spec/bundler/install/bundler_spec.rb
index 56f8431181..86c22dad55 100644
--- a/spec/bundler/install/bundler_spec.rb
+++ b/spec/bundler/install/bundler_spec.rb
@@ -135,7 +135,7 @@ RSpec.describe "bundle install" do
end
it "causes a conflict if child dependencies conflict" do
- bundle "config set force_ruby_platform true"
+ bundle_config "force_ruby_platform true"
update_repo2 do
build_gem "rails_pinned_to_old_activesupport" do |s|
@@ -163,7 +163,7 @@ RSpec.describe "bundle install" do
end
it "causes a conflict if a child dependency conflicts with the Gemfile" do
- bundle "config set force_ruby_platform true"
+ bundle_config "force_ruby_platform true"
update_repo2 do
build_gem "rails_pinned_to_old_activesupport" do |s|
@@ -216,7 +216,7 @@ RSpec.describe "bundle install" do
build_gem "rails", "7.0.4"
end
- bundle "config set path.system true"
+ bundle_config "path.system true"
install_gemfile <<-G
source "https://gem.repo4"
@@ -238,7 +238,7 @@ RSpec.describe "bundle install" do
end
it "can install dependencies with newer bundler version with system gems" do
- bundle "config set path.system true"
+ bundle_config "path.system true"
system_gems "bundler-99999999.99.1"
@@ -252,7 +252,7 @@ RSpec.describe "bundle install" do
end
it "can install dependencies with newer bundler version with a local path" do
- bundle "config set path .bundle"
+ bundle_config "path .bundle"
system_gems "bundler-99999999.99.1"
diff --git a/spec/bundler/install/cooldown_spec.rb b/spec/bundler/install/cooldown_spec.rb
new file mode 100644
index 0000000000..bad7b7cf34
--- /dev/null
+++ b/spec/bundler/install/cooldown_spec.rb
@@ -0,0 +1,433 @@
+# frozen_string_literal: true
+
+RSpec.describe "bundle install with the cooldown setting" do
+ before do
+ build_repo2
+ end
+
+ context "Gemfile DSL" do
+ it "accepts `source ..., cooldown: N` without error" do
+ install_gemfile <<-G, artifice: "compact_index"
+ source "https://gem.repo2", cooldown: 5
+ gem "myrack"
+ G
+
+ expect(the_bundle).to include_gems("myrack 1.0.0")
+ end
+
+ it "accepts `cooldown: 0` to disable cooldown for a source" do
+ install_gemfile <<-G, artifice: "compact_index"
+ source "https://gem.repo2", cooldown: 0
+ gem "myrack"
+ G
+
+ expect(the_bundle).to include_gems("myrack 1.0.0")
+ end
+ end
+
+ context "CLI flag" do
+ before do
+ gemfile <<-G
+ source "https://gem.repo2"
+ gem "myrack"
+ G
+ end
+
+ it "accepts --cooldown N on install" do
+ bundle "install --cooldown 7", artifice: "compact_index"
+
+ expect(the_bundle).to include_gems("myrack 1.0.0")
+ end
+
+ it "accepts --cooldown 0 as an escape hatch" do
+ bundle "install --cooldown 0", artifice: "compact_index"
+
+ expect(the_bundle).to include_gems("myrack 1.0.0")
+ end
+
+ it "rejects a negative --cooldown value" do
+ bundle "install --cooldown=-7", artifice: "compact_index", raise_on_error: false
+
+ expect(err).to match(/non-negative integer/)
+ end
+ end
+
+ context "configuration" do
+ it "reads BUNDLE_COOLDOWN as an integer" do
+ gemfile <<-G
+ source "https://gem.repo2"
+ gem "myrack"
+ G
+
+ bundle "install", env: { "BUNDLE_COOLDOWN" => "7" }, artifice: "compact_index"
+
+ expect(the_bundle).to include_gems("myrack 1.0.0")
+ end
+
+ it "reads `bundle config set cooldown N`" do
+ gemfile <<-G
+ source "https://gem.repo2"
+ gem "myrack"
+ G
+
+ bundle "config set cooldown 7"
+ bundle "install", artifice: "compact_index"
+
+ expect(the_bundle).to include_gems("myrack 1.0.0")
+ end
+ end
+
+ context "end-to-end with v2 compact index" do
+ before do
+ now = Time.now.utc
+ build_repo3 do
+ build_gem "ripe_gem", "1.0.0" do |s|
+ s.date = now - (30 * 86_400)
+ end
+ build_gem "ripe_gem", "2.0.0" do |s|
+ s.date = now - (1 * 86_400)
+ end
+
+ # parent only resolves with the in-cooldown child 2.0.0
+ build_gem "child", "1.0.0" do |s|
+ s.date = now - (30 * 86_400)
+ end
+ build_gem "child", "2.0.0" do |s|
+ s.date = now - (1 * 86_400)
+ end
+ build_gem "parent", "1.0.0" do |s|
+ s.add_dependency "child", ">= 2.0.0"
+ s.date = now - (30 * 86_400)
+ end
+
+ # a cooldown-eligible version exists above the in-cooldown locked one
+ build_gem "upgradable", "2.0.0" do |s|
+ s.date = now - (1 * 86_400)
+ end
+ build_gem "upgradable", "3.0.0" do |s|
+ s.date = now - (30 * 86_400)
+ end
+ end
+ end
+
+ it "excludes versions within the cooldown window" do
+ gemfile <<-G
+ source "https://gem.repo3"
+ gem "ripe_gem"
+ G
+
+ bundle "install --cooldown 7", artifice: "compact_index_cooldown"
+
+ expect(the_bundle).to include_gems("ripe_gem 1.0.0")
+ end
+
+ it "selects the latest version when --cooldown 0 is passed" do
+ gemfile <<-G
+ source "https://gem.repo3"
+ gem "ripe_gem"
+ G
+
+ bundle "install --cooldown 0", artifice: "compact_index_cooldown"
+
+ expect(the_bundle).to include_gems("ripe_gem 2.0.0")
+ end
+
+ it "applies cooldown declared per-source in the Gemfile" do
+ gemfile <<-G
+ source "https://gem.repo3", cooldown: 7
+ gem "ripe_gem"
+ G
+
+ bundle "install", artifice: "compact_index_cooldown"
+
+ expect(the_bundle).to include_gems("ripe_gem 1.0.0")
+ end
+
+ it "is overridden by CLI --cooldown when Gemfile sets a different per-source value" do
+ gemfile <<-G
+ source "https://gem.repo3", cooldown: 0
+ gem "ripe_gem"
+ G
+
+ bundle "install --cooldown 7", artifice: "compact_index_cooldown"
+
+ expect(the_bundle).to include_gems("ripe_gem 1.0.0")
+ end
+
+ it "bypasses cooldown when bundle install uses an existing lockfile" do
+ gemfile <<-G
+ source "https://gem.repo3"
+ gem "ripe_gem"
+ G
+
+ lockfile <<-L
+ GEM
+ remote: https://gem.repo3/
+ specs:
+ ripe_gem (2.0.0)
+
+ PLATFORMS
+ #{lockfile_platforms}
+
+ DEPENDENCIES
+ ripe_gem
+
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+
+ bundle "install --cooldown 7", artifice: "compact_index_cooldown"
+
+ expect(the_bundle).to include_gems("ripe_gem 2.0.0")
+ end
+
+ it "annotates in-cooldown versions in bundle outdated table output" do
+ gemfile <<-G
+ source "https://gem.repo3"
+ gem "ripe_gem", "1.0.0"
+ G
+
+ lockfile <<-L
+ GEM
+ remote: https://gem.repo3/
+ specs:
+ ripe_gem (1.0.0)
+
+ PLATFORMS
+ #{lockfile_platforms}
+
+ DEPENDENCIES
+ ripe_gem (= 1.0.0)
+
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+
+ bundle "outdated --cooldown 7", artifice: "compact_index_cooldown", raise_on_error: false
+
+ expect(out).to match(/ripe_gem.*\(cooldown \d+d\)/)
+ end
+
+ it "annotates in-cooldown versions in bundle outdated --parseable output" do
+ gemfile <<-G
+ source "https://gem.repo3"
+ gem "ripe_gem", "1.0.0"
+ G
+
+ lockfile <<-L
+ GEM
+ remote: https://gem.repo3/
+ specs:
+ ripe_gem (1.0.0)
+
+ PLATFORMS
+ #{lockfile_platforms}
+
+ DEPENDENCIES
+ ripe_gem (= 1.0.0)
+
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+
+ bundle "outdated --cooldown 7 --parseable", artifice: "compact_index_cooldown", raise_on_error: false
+
+ expect(out).to match(/ripe_gem.*in cooldown for \d+ more day/)
+ end
+
+ it "excludes a locally-installed version that is still within the cooldown window" do
+ system_gems "ripe_gem-2.0.0", gem_repo: gem_repo3
+
+ gemfile <<-G
+ source "https://gem.repo3"
+ gem "ripe_gem"
+ G
+
+ bundle "install --cooldown 7", artifice: "compact_index_cooldown"
+
+ expect(the_bundle).to include_gems("ripe_gem 1.0.0")
+ end
+
+ it "selects a locally-installed in-cooldown version when --cooldown 0 bypasses the filter" do
+ system_gems "ripe_gem-2.0.0", gem_repo: gem_repo3
+
+ gemfile <<-G
+ source "https://gem.repo3"
+ gem "ripe_gem"
+ G
+
+ bundle "install --cooldown 0", artifice: "compact_index_cooldown"
+
+ expect(the_bundle).to include_gems("ripe_gem 2.0.0")
+ end
+
+ it "surfaces a cooldown hint when bundle update filters every candidate" do
+ gemfile <<-G
+ source "https://gem.repo3"
+ gem "ripe_gem"
+ G
+
+ lockfile <<-L
+ GEM
+ remote: https://gem.repo3/
+ specs:
+ ripe_gem (1.0.0)
+
+ PLATFORMS
+ #{lockfile_platforms}
+
+ DEPENDENCIES
+ ripe_gem
+
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+
+ bundle "update ripe_gem --cooldown 99999", artifice: "compact_index_cooldown", raise_on_error: false
+
+ expect(err).to match(/excluded by the cooldown setting/)
+ expect(err).to match(/--cooldown 0/)
+ end
+
+ it "keeps an in-cooldown locked version on bundle update --all instead of failing" do
+ # Lockfile written before cooldown was enabled pins the now-in-cooldown
+ # latest version. A full update must not downgrade below it, and cooldown
+ # must not filter it out, otherwise resolution becomes impossible (#9598).
+ gemfile <<-G
+ source "https://gem.repo3"
+ gem "ripe_gem"
+ G
+
+ lockfile <<-L
+ GEM
+ remote: https://gem.repo3/
+ specs:
+ ripe_gem (2.0.0)
+
+ PLATFORMS
+ #{lockfile_platforms}
+
+ DEPENDENCIES
+ ripe_gem
+
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+
+ bundle "update --all --cooldown 7", artifice: "compact_index_cooldown"
+
+ expect(the_bundle).to include_gems("ripe_gem 2.0.0")
+ end
+
+ it "does not fail bundle outdated when the locked version is in cooldown" do
+ gemfile <<-G
+ source "https://gem.repo3"
+ gem "ripe_gem"
+ G
+
+ lockfile <<-L
+ GEM
+ remote: https://gem.repo3/
+ specs:
+ ripe_gem (2.0.0)
+
+ PLATFORMS
+ #{lockfile_platforms}
+
+ DEPENDENCIES
+ ripe_gem
+
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+
+ bundle "outdated --cooldown 7", artifice: "compact_index_cooldown", raise_on_error: false
+
+ # exit 0 means no outdated gems and, crucially, no resolution failure (exit 7)
+ expect(exitstatus).to eq(0)
+ end
+
+ it "still applies cooldown and downgrades a gem that is updated explicitly" do
+ gemfile <<-G
+ source "https://gem.repo3"
+ gem "ripe_gem"
+ G
+
+ lockfile <<-L
+ GEM
+ remote: https://gem.repo3/
+ specs:
+ ripe_gem (2.0.0)
+
+ PLATFORMS
+ #{lockfile_platforms}
+
+ DEPENDENCIES
+ ripe_gem
+
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+
+ bundle "update ripe_gem --cooldown 7", artifice: "compact_index_cooldown"
+
+ expect(the_bundle).to include_gems("ripe_gem 1.0.0")
+ end
+
+ it "keeps an in-cooldown transitive dependency on bundle update --all" do
+ gemfile <<-G
+ source "https://gem.repo3"
+ gem "parent"
+ G
+
+ lockfile <<-L
+ GEM
+ remote: https://gem.repo3/
+ specs:
+ child (2.0.0)
+ parent (1.0.0)
+ child (>= 2.0.0)
+
+ PLATFORMS
+ #{lockfile_platforms}
+
+ DEPENDENCIES
+ parent
+
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+
+ bundle "update --all --cooldown 7", artifice: "compact_index_cooldown"
+
+ expect(the_bundle).to include_gems("parent 1.0.0", "child 2.0.0")
+ end
+
+ it "still upgrades to a cooldown-eligible version above the locked one" do
+ gemfile <<-G
+ source "https://gem.repo3"
+ gem "upgradable"
+ G
+
+ lockfile <<-L
+ GEM
+ remote: https://gem.repo3/
+ specs:
+ upgradable (2.0.0)
+
+ PLATFORMS
+ #{lockfile_platforms}
+
+ DEPENDENCIES
+ upgradable
+
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+
+ bundle "update --all --cooldown 7", artifice: "compact_index_cooldown"
+
+ expect(the_bundle).to include_gems("upgradable 3.0.0")
+ end
+ end
+end
diff --git a/spec/bundler/install/deploy_spec.rb b/spec/bundler/install/deploy_spec.rb
index 3560a3965c..a3b4a87ecf 100644
--- a/spec/bundler/install/deploy_spec.rb
+++ b/spec/bundler/install/deploy_spec.rb
@@ -8,80 +8,14 @@ RSpec.describe "install in deployment or frozen mode" do
G
end
- context "with CLI flags" 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")
- 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")
- end
-
- it "disallows --deployment --system" do
- 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
- 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")
- expect(exitstatus).to eq(15)
- 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
- expect(the_bundle).to include_gems "myrack 1.0"
- end
-
- it "installs gems by default to vendor/bundle" do
- bundle :lock
- bundle "install --deployment"
- expect(out).to include("vendor/bundle")
- end
-
- it "installs gems to custom path if specified" do
- bundle :lock
- bundle "install --path vendor/bundle2 --deployment"
- expect(out).to include("vendor/bundle2")
- end
-
- it "works with the --frozen flag" do
- bundle :lock
- bundle "install --frozen"
- end
-
- 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"
- G
-
- 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).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_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_config "frozen true"
bundle "install", raise_on_error: false
expect(err).to include("The frozen setting requires a lockfile")
end
@@ -89,8 +23,8 @@ RSpec.describe "install in deployment or frozen mode" do
it "still works if you are not in the app directory and specify --gemfile" do
bundle "install"
pristine_system_gems
- bundle "config set --local deployment true"
- bundle "config set --local path vendor/bundle"
+ bundle_config "deployment true"
+ bundle_config "path vendor/bundle"
bundle "install --gemfile #{tmp}/bundled_app/Gemfile", dir: tmp
expect(the_bundle).to include_gems "myrack 1.0"
end
@@ -104,8 +38,8 @@ RSpec.describe "install in deployment or frozen mode" do
end
G
bundle :install
- bundle "config set --local deployment true"
- bundle "config set --local without test"
+ bundle_config "deployment true"
+ bundle_config "without test"
bundle :install
end
@@ -113,7 +47,7 @@ RSpec.describe "install in deployment or frozen mode" do
skip "doesn't find bundle" if Gem.win_platform?
bundle :install
- bundle "config set --local deployment true"
+ bundle_config "deployment true"
bundle :install
bundle "exec bundle check", env: { "PATH" => path }
end
@@ -128,7 +62,7 @@ RSpec.describe "install in deployment or frozen mode" do
G
bundle :install
- bundle "config set --local deployment true"
+ bundle_config "deployment true"
bundle :install
end
@@ -141,7 +75,7 @@ RSpec.describe "install in deployment or frozen mode" do
G
bundle :install
- bundle "config set --local deployment true"
+ bundle_config "deployment true"
bundle :install
end
@@ -152,7 +86,7 @@ RSpec.describe "install in deployment or frozen mode" do
gem "myrack-obama", ">= 1.0"
G
- bundle "config set --local deployment true"
+ bundle_config "deployment true"
bundle :install, artifice: "endpoint_strict_basic_authentication"
end
@@ -164,7 +98,7 @@ RSpec.describe "install in deployment or frozen mode" do
end
G
- bundle "config set --local deployment true"
+ bundle_config "deployment true"
bundle :install
expect(the_bundle).to include_gems "myrack 1.0"
@@ -172,7 +106,7 @@ RSpec.describe "install in deployment or frozen mode" do
context "when replacing a host with the same host with credentials" do
before do
- bundle "config set --local path vendor/bundle"
+ bundle_config "path vendor/bundle"
bundle "install"
gemfile <<-G
source "http://user_name:password@localgemserver.test/"
@@ -192,7 +126,7 @@ RSpec.describe "install in deployment or frozen mode" do
myrack
G
- bundle "config set --local deployment true"
+ bundle_config "deployment true"
end
it "allows the replace" do
@@ -208,7 +142,7 @@ RSpec.describe "install in deployment or frozen mode" do
end
it "installs gems by default to vendor/bundle" do
- bundle "config set deployment true"
+ bundle_config "deployment true"
expect do
bundle "install"
end.not_to change { bundled_app_lock.mtime }
@@ -216,20 +150,20 @@ RSpec.describe "install in deployment or frozen mode" do
end
it "installs gems to custom path if specified" do
- bundle "config set path vendor/bundle2"
- bundle "config set deployment true"
+ bundle_config "path vendor/bundle2"
+ bundle_config "deployment true"
bundle "install"
expect(out).to include("vendor/bundle2")
end
it "installs gems to custom path if specified, even when configured through ENV" do
- bundle "config set deployment true"
+ bundle_config "deployment true"
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"
+ bundle_config "frozen true"
expect do
bundle "install"
end.not_to change { bundled_app_lock.mtime }
@@ -248,7 +182,7 @@ RSpec.describe "install in deployment or frozen mode" do
gem "myrack-obama"
G
- bundle "config set --local deployment true"
+ bundle_config "deployment true"
bundle :install, raise_on_error: false
expect(err).to include("frozen mode")
expect(err).to include("You have added to the Gemfile")
@@ -267,9 +201,9 @@ RSpec.describe "install in deployment or frozen mode" do
expect(the_bundle).to include_gems "path_gem 1.0"
FileUtils.rm_r lib_path("path_gem-1.0")
- bundle "config set --local path .bundle"
- bundle "config set --local without development"
- bundle "config set --local deployment true"
+ bundle_config "path .bundle"
+ bundle_config "without development"
+ bundle_config "deployment true"
bundle :install, env: { "DEBUG" => "1" }
run "puts :WIN"
expect(out).to eq("WIN")
@@ -317,7 +251,7 @@ RSpec.describe "install in deployment or frozen mode" do
bar
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
bundle :install, env: { "BUNDLE_FROZEN" => "true" }, raise_on_error: false, artifice: "compact_index"
@@ -334,8 +268,8 @@ RSpec.describe "install in deployment or frozen mode" do
expect(the_bundle).to include_gems "path_gem 1.0"
FileUtils.rm_r lib_path("path_gem-1.0")
- bundle "config set --local path .bundle"
- bundle "config set --local deployment true"
+ bundle_config "path .bundle"
+ bundle_config "deployment true"
bundle :install, raise_on_error: false
expect(err).to include("The path `#{lib_path("path_gem-1.0")}` does not exist.")
end
@@ -406,7 +340,7 @@ RSpec.describe "install in deployment or frozen mode" do
gem "activesupport"
G
- bundle "config set --local deployment true"
+ bundle_config "deployment true"
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")
@@ -417,7 +351,7 @@ RSpec.describe "install in deployment or frozen mode" do
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_config "deployment true"
bundle :install, raise_on_error: false
expect(err).to include("Some dependencies were deleted")
expect(err).to include("frozen mode")
@@ -431,7 +365,7 @@ RSpec.describe "install in deployment or frozen mode" do
gem "myrack", :git => "git://hubz.com"
G
- bundle "config set --local deployment true"
+ bundle_config "deployment true"
bundle :install, raise_on_error: false
expect(err).to include("frozen mode")
expect(err).not_to include("You have added to the Gemfile")
@@ -451,7 +385,7 @@ RSpec.describe "install in deployment or frozen mode" do
gem "myrack"
G
- bundle "config set --local deployment true"
+ bundle_config "deployment true"
bundle :install, raise_on_error: false
expect(err).to include("frozen mode")
expect(err).not_to include("You have deleted from the Gemfile")
@@ -475,7 +409,7 @@ RSpec.describe "install in deployment or frozen mode" do
gem "foo", :git => "#{lib_path("myrack")}"
G
- bundle "config set --local deployment true"
+ bundle_config "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`")
@@ -496,7 +430,7 @@ RSpec.describe "install in deployment or frozen mode" do
gem "myrack", :git => "https:/my-git-repo-for-myrack"
G
- bundle "config set --local frozen true"
+ bundle_config "frozen 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 `https:/my-git-repo-for-myrack`")
@@ -507,7 +441,7 @@ RSpec.describe "install in deployment or frozen mode" do
it "remembers that the bundle is frozen at runtime" do
bundle :lock
- bundle "config set --local deployment true"
+ bundle_config "deployment true"
gemfile <<-G
source "https://gem.repo1"
@@ -540,7 +474,6 @@ RSpec.describe "install in deployment or frozen mode" do
bundle :install
expect(the_bundle).to include_gems "foo 1.0"
- bundle "config set cache_all true"
bundle :cache
expect(bundled_app("vendor/cache/foo")).to be_directory
@@ -548,7 +481,7 @@ RSpec.describe "install in deployment or frozen mode" do
expect(out).to include("Updating files in vendor/cache")
pristine_system_gems
- bundle "config set --local deployment true"
+ bundle_config "deployment true"
bundle "install --verbose"
expect(out).not_to include("can't be updated because frozen mode is set")
expect(out).not_to include("You have added to the Gemfile")
diff --git a/spec/bundler/install/failure_spec.rb b/spec/bundler/install/failure_spec.rb
index 2c2773e849..32ca455439 100644
--- a/spec/bundler/install/failure_spec.rb
+++ b/spec/bundler/install/failure_spec.rb
@@ -48,4 +48,38 @@ In Gemfile:
end
end
end
+
+ context "when lockfile dependencies don't match the gemspec" do
+ before do
+ build_repo4 do
+ build_gem "myrack", "1.0.0" do |s|
+ s.add_dependency "myrack-test", "~> 1.0"
+ end
+
+ build_gem "myrack-test", "1.0.0"
+ end
+
+ gemfile <<-G
+ source "https://gem.repo4"
+ gem "myrack"
+ G
+
+ # First install to generate lockfile
+ bundle :install
+
+ # Manually edit lockfile to have incorrect dependencies
+ lockfile_content = File.read(bundled_app_lock)
+ # Remove the myrack-test dependency from myrack
+ lockfile_content.gsub!(/^ myrack \(1\.0\.0\)\n myrack-test \(~> 1\.0\)\n/, " myrack (1.0.0)\n")
+ File.write(bundled_app_lock, lockfile_content)
+ end
+
+ it "reports the mismatch with detailed information" do
+ bundle :install, raise_on_error: false, env: { "BUNDLE_FROZEN" => "true" }
+
+ expect(err).to include("Bundler found incorrect dependencies in the lockfile for myrack-1.0.0")
+ expect(err).to include("myrack-test: gemspec specifies ~> 1.0, not in lockfile")
+ expect(err).to include("Please run `bundle install` to regenerate the lockfile.")
+ end
+ end
end
diff --git a/spec/bundler/install/gemfile/eval_gemfile_spec.rb b/spec/bundler/install/gemfile/eval_gemfile_spec.rb
index a507e52485..3afa4f5daa 100644
--- a/spec/bundler/install/gemfile/eval_gemfile_spec.rb
+++ b/spec/bundler/install/gemfile/eval_gemfile_spec.rb
@@ -85,7 +85,7 @@ RSpec.describe "bundle install with gemfile that uses eval_gemfile" do
# parsed lockfile and the evaluated gemfile.
it "bundles with deployment mode configured" do
bundle :install
- bundle "config set --local deployment true"
+ bundle_config "deployment true"
bundle :install
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..bcc1f36823 100644
--- a/spec/bundler/install/gemfile/force_ruby_platform_spec.rb
+++ b/spec/bundler/install/gemfile/force_ruby_platform_spec.rb
@@ -117,7 +117,7 @@ RSpec.describe "bundle install with force_ruby_platform DSL option", :jruby do
platform_specific
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
simulate_platform "x86-darwin-100" do
diff --git a/spec/bundler/install/gemfile/gemspec_spec.rb b/spec/bundler/install/gemfile/gemspec_spec.rb
index d9469e5ca8..e51fc9247d 100644
--- a/spec/bundler/install/gemfile/gemspec_spec.rb
+++ b/spec/bundler/install/gemfile/gemspec_spec.rb
@@ -126,7 +126,7 @@ RSpec.describe "bundle install from an existing gemspec" do
# 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"
+ bundle_config "deployment true"
output = bundle("install", dir: tmp("foo"), artifice: "compact_index", env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo1.to_s })
expect(output).not_to match(/You have added to the Gemfile/)
expect(output).not_to match(/You have deleted from the Gemfile/)
@@ -312,7 +312,7 @@ RSpec.describe "bundle install from an existing gemspec" do
s.add_dependency "activesupport", ">= 1.0.1"
end
- bundle "config set --local deployment true"
+ bundle_config "deployment true"
bundle :install, raise_on_error: false
expect(err).to include("changed")
@@ -380,7 +380,7 @@ RSpec.describe "bundle install from an existing gemspec" do
foo!
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
@@ -420,12 +420,13 @@ RSpec.describe "bundle install from an existing gemspec" do
end
build_lib "foo", path: bundled_app do |s|
- if platform_specific_type == :runtime
+ case platform_specific_type
+ when :runtime
s.add_runtime_dependency dependency
- elsif platform_specific_type == :development
+ when :development
s.add_development_dependency dependency
else
- raise "wrong dependency type #{platform_specific_type}, can only be :development or :runtime"
+ raise ArgumentError, "wrong dependency type #{platform_specific_type}, can only be :development or :runtime"
end
end
@@ -434,7 +435,7 @@ RSpec.describe "bundle install from an existing gemspec" do
gemspec
G
- bundle "config set --local force_ruby_platform true"
+ bundle_config "force_ruby_platform true"
bundle "install"
simulate_new_machine
@@ -445,7 +446,7 @@ RSpec.describe "bundle install from an existing gemspec" do
context "on ruby" do
before do
- bundle "config set --local force_ruby_platform true"
+ bundle_config "force_ruby_platform true"
bundle :install
end
@@ -483,7 +484,7 @@ RSpec.describe "bundle install from an existing gemspec" do
foo!
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
end
@@ -524,7 +525,7 @@ RSpec.describe "bundle install from an existing gemspec" do
platform_specific
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
end
@@ -569,7 +570,7 @@ RSpec.describe "bundle install from an existing gemspec" do
indirect_platform_specific
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
end
@@ -587,7 +588,7 @@ RSpec.describe "bundle install from an existing gemspec" do
end
it "installs the ruby platform gemspec" do
- bundle "config set --local force_ruby_platform true"
+ bundle_config "force_ruby_platform true"
install_gemfile <<-G
source "https://gem.repo1"
@@ -598,9 +599,9 @@ RSpec.describe "bundle install from an existing gemspec" do
end
it "installs the ruby platform gemspec and skips dev deps with `without development` configured" do
- bundle "config set --local force_ruby_platform true"
+ bundle_config "force_ruby_platform true"
- bundle "config set --local without development"
+ bundle_config "without development"
install_gemfile <<-G
source "https://gem.repo1"
gemspec :path => '#{tmp("foo")}', :name => 'foo'
@@ -657,7 +658,7 @@ RSpec.describe "bundle install from an existing gemspec" do
chef!
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
lockfile initial_lockfile
@@ -720,7 +721,7 @@ RSpec.describe "bundle install from an existing gemspec" do
jruby-openssl
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
gemspec = tmp("activeadmin/activeadmin.gemspec")
diff --git a/spec/bundler/install/gemfile/git_spec.rb b/spec/bundler/install/gemfile/git_spec.rb
index 216548cf27..b2a82caf01 100644
--- a/spec/bundler/install/gemfile/git_spec.rb
+++ b/spec/bundler/install/gemfile/git_spec.rb
@@ -35,7 +35,7 @@ RSpec.describe "bundle install with git sources" do
build_git "foo"
revision = revision_for(lib_path("foo-1.0"))
- bundle "config set lockfile_checksums true"
+ bundle_config "lockfile_checksums true"
gemfile base_gemfile
lockfile <<~L
@@ -59,10 +59,10 @@ RSpec.describe "bundle install with git sources" do
foo (1.0)
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
- bundle "config set frozen true"
+ bundle_config "frozen true"
bundle "install"
expect(the_bundle).to include_gems("foo 1.0")
@@ -70,7 +70,7 @@ RSpec.describe "bundle install with git sources" do
it "caches the git repo" do
install_base_gemfile
- expect(Dir["#{default_bundle_path}/cache/bundler/git/foo-1.0-*"]).to have_attributes size: 1
+ expect(Dir["#{default_cache_path}/git/foo-1.0-*"]).to have_attributes size: 1
end
it "does not write to cache on bundler/setup" do
@@ -83,7 +83,7 @@ RSpec.describe "bundle install with git sources" do
it "caches the git repo globally and properly uses the cached repo on the next invocation" do
install_base_gemfile
pristine_system_gems
- bundle "config set global_gem_cache true"
+ bundle_config "global_gem_cache true"
bundle :install
expect(Dir["#{home}/.bundle/cache/git/foo-1.0-*"]).to have_attributes size: 1
@@ -183,7 +183,7 @@ RSpec.describe "bundle install with git sources" do
end
it "still works after moving the application directory" do
- bundle "config set --local path vendor/bundle"
+ bundle_config "path vendor/bundle"
install_base_gemfile
FileUtils.mv bundled_app, tmp("bundled_app.bck")
@@ -192,7 +192,7 @@ RSpec.describe "bundle install with git sources" do
end
it "can still install after moving the application directory" do
- bundle "config set --local path vendor/bundle"
+ bundle_config "path vendor/bundle"
install_base_gemfile
FileUtils.mv bundled_app, tmp("bundled_app.bck")
@@ -381,7 +381,7 @@ RSpec.describe "bundle install with git sources" do
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"))
- bundle "config set global_gem_cache true"
+ bundle_config "global_gem_cache true"
install_gemfile <<-G
source "https://gem.repo1"
@@ -478,7 +478,7 @@ RSpec.describe "bundle install with git sources" do
update_git("foo", path: repo, tag: tag)
install_gemfile <<-G
- source "https://gem.repo1"
+ source "https://gem.repo1"
git "#{repo}", :tag => #{tag.dump} do
gem "foo"
end
@@ -1078,7 +1078,7 @@ RSpec.describe "bundle install with git sources" do
expect(out).to eq("WIN")
end
- it "does not to a remote fetch if the revision is cached locally" do
+ it "does not do a remote fetch if the revision is cached locally" do
build_git "foo"
install_gemfile <<-G
@@ -1291,7 +1291,7 @@ RSpec.describe "bundle install with git sources" do
pristine_system_gems
- bundle "config set --local deployment true"
+ bundle_config "deployment true"
bundle :install
end
end
@@ -1404,7 +1404,7 @@ RSpec.describe "bundle install with git sources" do
File.open(git_reader.path.join("ext/foo.c"), "w") do |file|
file.write <<-C
#include "ruby.h"
- VALUE foo() { return INT2FIX(#{i}); }
+ VALUE foo(VALUE self) { return INT2FIX(#{i}); }
void Init_foo() { rb_define_global_function("foo", &foo, 0); }
C
end
@@ -1638,7 +1638,7 @@ In Gemfile:
rake!
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
with_path_as("") do
@@ -1674,7 +1674,7 @@ In Gemfile:
gem 'foo'
end
G
- bundle "config set --global path vendor/bundle"
+ bundle_config_global "path vendor/bundle"
bundle :install
pristine_system_gems
@@ -1685,7 +1685,7 @@ In Gemfile:
describe "when the git source is overridden with a local git repo" do
before do
- bundle "config set --global local.foo #{lib_path("foo")}"
+ bundle_config_global "local.foo #{lib_path("foo")}"
end
describe "and git output is colorized" do
diff --git a/spec/bundler/install/gemfile/groups_spec.rb b/spec/bundler/install/gemfile/groups_spec.rb
index 52a3471578..4013b112ec 100644
--- a/spec/bundler/install/gemfile/groups_spec.rb
+++ b/spec/bundler/install/gemfile/groups_spec.rb
@@ -25,7 +25,7 @@ RSpec.describe "bundle install with groups" do
puts ACTIVESUPPORT
R
- expect(err_without_deprecations).to eq("ZOMG LOAD ERROR")
+ expect(err_without_deprecations).to match(/cannot load such file -- activesupport/)
end
it "installs gems with inline :groups into those groups" do
@@ -36,7 +36,7 @@ RSpec.describe "bundle install with groups" do
puts THIN
R
- expect(err_without_deprecations).to eq("ZOMG LOAD ERROR")
+ expect(err_without_deprecations).to match(/cannot load such file -- thin/)
end
it "sets up everything if Bundler.setup is used with no groups" do
@@ -57,7 +57,7 @@ RSpec.describe "bundle install with groups" do
puts THIN
RUBY
- expect(err_without_deprecations).to eq("ZOMG LOAD ERROR")
+ expect(err_without_deprecations).to match(/cannot load such file -- thin/)
end
it "sets up old groups when they have previously been removed" do
@@ -86,13 +86,13 @@ RSpec.describe "bundle install with groups" do
end
it "installs gems in the default group" do
- bundle "config set --local without emo"
+ bundle_config "without emo"
bundle :install
expect(the_bundle).to include_gems "myrack 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_config_global "without emo"
bundle :install
expect(the_bundle).to include_gems "myrack 1.0.0", groups: [:default]
bundle "config list"
@@ -101,33 +101,26 @@ RSpec.describe "bundle install with groups" do
end
it "allows running application where groups where configured by a different user" do
- bundle "config set without emo"
+ bundle_config "without emo"
bundle :install
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_config "without emo"
bundle :install
expect(the_bundle).not_to include_gems "activesupport 2.3.5", groups: [:default]
end
- it "remembers previous exclusion with `--without`" do
- bundle "install --without emo"
- expect(the_bundle).not_to include_gems "activesupport 2.3.5"
- bundle :install
- expect(the_bundle).not_to include_gems "activesupport 2.3.5"
- end
-
it "does not say it installed gems from the excluded group" do
- bundle "config set --local without emo"
+ bundle_config "without emo"
bundle :install
expect(out).not_to include("activesupport")
end
it "allows Bundler.setup for specific groups" do
- bundle "config set --local without emo"
+ bundle_config "without emo"
bundle :install
run("require 'myrack'; puts MYRACK", :default)
expect(out).to eq("1.0.0")
@@ -142,7 +135,7 @@ RSpec.describe "bundle install with groups" do
end
G
- bundle "config set --local without emo"
+ bundle_config "without emo"
bundle :install
expect(the_bundle).to include_gems "activesupport 2.3.2", groups: [:default]
end
@@ -159,34 +152,13 @@ RSpec.describe "bundle install with groups" do
ENV["BUNDLE_WITHOUT"] = nil
end
- it "clears --without when passed an empty list" 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" do
- bundle "install --without emo"
-
- bundle :install
- expect(the_bundle).not_to include_gems "activesupport 2.3.5"
- end
-
it "does not install gems from the optional group" do
bundle :install
expect(the_bundle).not_to include_gems "thin 1.0"
end
it "installs gems from the optional group when requested" do
- bundle "config set --local with debugging"
- bundle :install
- expect(the_bundle).to include_gems "thin 1.0"
- end
-
- it "installs gems from the previously requested group" do
- bundle "install --with debugging"
- expect(the_bundle).to include_gems "thin 1.0"
+ bundle_config "with debugging"
bundle :install
expect(the_bundle).to include_gems "thin 1.0"
end
@@ -198,30 +170,6 @@ RSpec.describe "bundle install with groups" do
ENV["BUNDLE_WITH"] = nil
end
- it "clears --with when passed an empty list" 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" 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" do
- bundle "config set --local with debugging"
- 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" 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
-
it "allows the BUNDLE_WITH setting to override BUNDLE_WITHOUT" do
ENV["BUNDLE_WITH"] = "debugging"
@@ -235,20 +183,14 @@ 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" 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"
- end
-
it "has no effect when listing a not optional group in with" do
- bundle "config set --local with emo"
+ bundle_config "with emo"
bundle :install
expect(the_bundle).to include_gems "activesupport 2.3.5"
end
it "has no effect when listing an optional group in without" do
- bundle "config set --local without debugging"
+ bundle_config "without debugging"
bundle :install
expect(the_bundle).not_to include_gems "thin 1.0"
end
@@ -266,13 +208,13 @@ RSpec.describe "bundle install with groups" do
end
it "installs gems in the default group" do
- bundle "config set --local without emo lolercoaster"
+ bundle_config "without emo lolercoaster"
bundle :install
expect(the_bundle).to include_gems "myrack 1.0.0"
end
it "installs the gem if any of its groups are installed" do
- bundle "config set --local without emo"
+ bundle_config "without emo"
bundle :install
expect(the_bundle).to include_gems "myrack 1.0.0", "activesupport 2.3.5"
end
@@ -294,15 +236,15 @@ RSpec.describe "bundle install with groups" do
end
it "installs the gem unless all groups are excluded" do
- bundle "config set --local without emo"
+ bundle_config "without emo"
bundle :install
expect(the_bundle).to include_gems "activesupport 2.3.5"
- bundle "config set --local without lolercoaster"
+ bundle_config "without lolercoaster"
bundle :install
expect(the_bundle).to include_gems "activesupport 2.3.5"
- bundle "config set --local without emo lolercoaster"
+ bundle_config "without emo lolercoaster"
bundle :install
expect(the_bundle).not_to include_gems "activesupport 2.3.5"
@@ -327,13 +269,13 @@ RSpec.describe "bundle install with groups" do
end
it "installs gems in the default group" do
- bundle "config set --local without emo lolercoaster"
+ bundle_config "without emo lolercoaster"
bundle :install
expect(the_bundle).to include_gems "myrack 1.0.0"
end
it "installs the gem if any of its groups are installed" do
- bundle "config set --local without emo"
+ bundle_config "without emo"
bundle :install
expect(the_bundle).to include_gems "myrack 1.0.0", "activesupport 2.3.5"
end
@@ -365,13 +307,13 @@ RSpec.describe "bundle install with groups" do
end
end
- describe "when locked and installed with `without` option" do
+ describe "when locked and installed with `without` setting" do
before(:each) do
build_repo2
system_gems "myrack-0.9.1"
- bundle "config set --local without myrack"
+ bundle_config "without myrack"
install_gemfile <<-G
source "https://gem.repo2"
gem "myrack"
@@ -382,7 +324,7 @@ RSpec.describe "bundle install with groups" do
G
end
- it "uses the correct versions even if --without was used on the original" do
+ it "uses versions from excluded gems in a machine without the without configuration" do
expect(the_bundle).to include_gems "myrack 0.9.1"
expect(the_bundle).not_to include_gems "myrack_middleware 1.0"
simulate_new_machine
@@ -395,7 +337,7 @@ RSpec.describe "bundle install with groups" do
it "does not hit the remote a second time" do
FileUtils.rm_r gem_repo2
- bundle "config set --local without myrack"
+ bundle_config "without myrack"
bundle :install, verbose: true
expect(stdboth).not_to match(/fetching/i)
end
diff --git a/spec/bundler/install/gemfile/install_if_spec.rb b/spec/bundler/install/gemfile/install_if_spec.rb
index 170b58c4c0..05a6d15129 100644
--- a/spec/bundler/install/gemfile/install_if_spec.rb
+++ b/spec/bundler/install/gemfile/install_if_spec.rb
@@ -45,7 +45,7 @@ RSpec.describe "bundle install with install_if conditionals" do
thin
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
end
diff --git a/spec/bundler/install/gemfile/lockfile_spec.rb b/spec/bundler/install/gemfile/lockfile_spec.rb
index ee747c05de..19bd7074b2 100644
--- a/spec/bundler/install/gemfile/lockfile_spec.rb
+++ b/spec/bundler/install/gemfile/lockfile_spec.rb
@@ -17,7 +17,7 @@ RSpec.describe "bundle install with a lockfile present" do
context "with plugins disabled" do
before do
- bundle "config set plugins false"
+ bundle_config "plugins false"
end
it "does not evaluate the gemfile twice when the gem is already installed" do
diff --git a/spec/bundler/install/gemfile/override_spec.rb b/spec/bundler/install/gemfile/override_spec.rb
new file mode 100644
index 0000000000..02b0e7d772
--- /dev/null
+++ b/spec/bundler/install/gemfile/override_spec.rb
@@ -0,0 +1,401 @@
+# frozen_string_literal: true
+
+RSpec.describe "override DSL" do
+ context "with a version: string operation" do
+ it "replaces a direct dependency requirement with the override version spec" do
+ install_gemfile <<-G
+ source "https://gem.repo1"
+ override "myrack", version: "= 0.9.1"
+ gem "myrack"
+ G
+
+ expect(the_bundle).to include_gems "myrack 0.9.1"
+ end
+
+ it "replaces a transitive dependency requirement" do
+ install_gemfile <<-G
+ source "https://gem.repo1"
+ override "myrack", version: "= 1.0.0"
+ gem "myrack_middleware"
+ G
+
+ expect(the_bundle).to include_gems "myrack 1.0.0", "myrack_middleware 1.0"
+ end
+
+ it "replaces the requirement even when the Gemfile pins a different version" do
+ install_gemfile <<-G
+ source "https://gem.repo1"
+ override "myrack", version: "= 0.9.1"
+ gem "myrack", "= 1.0.0"
+ G
+
+ expect(the_bundle).to include_gems "myrack 0.9.1"
+ end
+
+ it "applies the override against an existing lockfile" do
+ install_gemfile <<-G
+ source "https://gem.repo1"
+ gem "myrack"
+ G
+
+ expect(the_bundle).to include_gems "myrack 1.0.0"
+
+ gemfile <<-G
+ source "https://gem.repo1"
+ override "myrack", version: "= 0.9.1"
+ gem "myrack"
+ G
+
+ bundle :install
+
+ expect(the_bundle).to include_gems "myrack 0.9.1"
+ end
+
+ it "pins a prerelease version that the Gemfile dependency would otherwise filter out" do
+ build_repo2 do
+ build_gem "has_prerelease", "1.0"
+ build_gem "has_prerelease", "1.1.pre"
+ end
+
+ install_gemfile <<-G
+ source "https://gem.repo2"
+ override "has_prerelease", version: "= 1.1.pre"
+ gem "has_prerelease"
+ G
+
+ expect(the_bundle).to include_gems "has_prerelease 1.1.pre"
+ end
+ end
+
+ context "with a version: :ignore_upper operation" do
+ it "strips a < upper bound on a direct dependency" do
+ install_gemfile <<-G
+ source "https://gem.repo1"
+ override "myrack", version: :ignore_upper
+ gem "myrack", "< 1.0"
+ G
+
+ expect(the_bundle).to include_gems "myrack 1.0.0"
+ end
+
+ it "folds ~> into >= so newer versions become reachable" do
+ install_gemfile <<-G
+ source "https://gem.repo1"
+ override "myrack", version: :ignore_upper
+ gem "myrack", "~> 0.9.1"
+ G
+
+ expect(the_bundle).to include_gems "myrack 1.0.0"
+ end
+ end
+
+ context "with a version: nil operation" do
+ it "drops a direct dependency's pin entirely" do
+ install_gemfile <<-G
+ source "https://gem.repo1"
+ override "myrack", version: nil
+ gem "myrack", "= 0.9.1"
+ G
+
+ expect(the_bundle).to include_gems "myrack 1.0.0"
+ end
+
+ it "drops a transitive dependency's pin entirely" do
+ install_gemfile <<-G
+ source "https://gem.repo1"
+ override "myrack", version: nil
+ gem "myrack_middleware"
+ G
+
+ expect(the_bundle).to include_gems "myrack 1.0.0", "myrack_middleware 1.0"
+ end
+
+ it "applies a transitive-only override against an existing lockfile" do
+ install_gemfile <<-G
+ source "https://gem.repo1"
+ gem "myrack_middleware"
+ G
+
+ expect(the_bundle).to include_gems "myrack 0.9.1", "myrack_middleware 1.0"
+
+ gemfile <<-G
+ source "https://gem.repo1"
+ override "myrack", version: "= 1.0.0"
+ gem "myrack_middleware"
+ G
+
+ bundle :install
+
+ expect(the_bundle).to include_gems "myrack 1.0.0", "myrack_middleware 1.0"
+ end
+ end
+
+ context "lockfile contents" do
+ it "does not record the override directive in Gemfile.lock" do
+ install_gemfile <<-G
+ source "https://gem.repo1"
+ override "myrack", version: "= 0.9.1"
+ gem "myrack"
+ G
+
+ expect(lockfile).not_to match(/override/i)
+ end
+ end
+
+ context "with a required_ruby_version: operation" do
+ it "lets the resolver pick a gem whose required_ruby_version excludes the current Ruby with :ignore_upper" do
+ build_repo2 do
+ build_gem "needs_old_ruby", "1.0" do |s|
+ s.required_ruby_version = "< #{Gem.ruby_version}"
+ end
+ end
+
+ gemfile <<-G
+ source "https://gem.repo2"
+ override "needs_old_ruby", required_ruby_version: :ignore_upper
+ gem "needs_old_ruby"
+ G
+
+ bundle :lock
+ expect(lockfile).to include("needs_old_ruby (1.0)")
+ end
+
+ it "lets the resolver pick the gem with required_ruby_version: nil" do
+ build_repo2 do
+ build_gem "needs_old_ruby", "1.0" do |s|
+ s.required_ruby_version = "< #{Gem.ruby_version}"
+ end
+ end
+
+ gemfile <<-G
+ source "https://gem.repo2"
+ override "needs_old_ruby", required_ruby_version: nil
+ gem "needs_old_ruby"
+ G
+
+ bundle :lock
+ expect(lockfile).to include("needs_old_ruby (1.0)")
+ end
+
+ it "applies to a transitive dependency's required_ruby_version" do
+ build_repo2 do
+ build_gem "needs_old_ruby", "1.0" do |s|
+ s.required_ruby_version = "< #{Gem.ruby_version}"
+ end
+ build_gem "wraps_old", "1.0" do |s|
+ s.add_dependency "needs_old_ruby"
+ end
+ end
+
+ gemfile <<-G
+ source "https://gem.repo2"
+ override "needs_old_ruby", required_ruby_version: :ignore_upper
+ gem "wraps_old"
+ G
+
+ bundle :lock
+ expect(lockfile).to include("needs_old_ruby (1.0)")
+ expect(lockfile).to include("wraps_old (1.0)")
+ end
+
+ it "re-resolves a direct dep when a metadata override is added against an existing lockfile" do
+ build_repo2 do
+ build_gem "selectable", "1.0"
+ build_gem "selectable", "2.0" do |s|
+ s.required_ruby_version = "< #{Gem.ruby_version}"
+ end
+ end
+
+ gemfile <<-G
+ source "https://gem.repo2"
+ gem "selectable"
+ G
+
+ bundle :lock
+ expect(lockfile).to include("selectable (1.0)")
+
+ gemfile <<-G
+ source "https://gem.repo2"
+ override "selectable", required_ruby_version: :ignore_upper
+ gem "selectable"
+ G
+
+ bundle :lock
+ expect(lockfile).to include("selectable (2.0)")
+ end
+ end
+
+ context "with a required_rubygems_version: operation" do
+ it "lets the resolver pick a gem whose required_rubygems_version excludes the current RubyGems with :ignore_upper" do
+ build_repo2 do
+ build_gem "needs_old_rubygems", "1.0" do |s|
+ s.required_rubygems_version = "< #{Gem.rubygems_version}"
+ end
+ end
+
+ gemfile <<-G
+ source "https://gem.repo2"
+ override "needs_old_rubygems", required_rubygems_version: :ignore_upper
+ gem "needs_old_rubygems"
+ G
+
+ bundle :lock
+ expect(lockfile).to include("needs_old_rubygems (1.0)")
+ end
+ end
+
+ context "with an :all target" do
+ it "applies required_ruby_version: :ignore_upper to every gem" do
+ build_repo2 do
+ build_gem "needs_old_ruby_a", "1.0" do |s|
+ s.required_ruby_version = "< #{Gem.ruby_version}"
+ end
+ build_gem "needs_old_ruby_b", "1.0" do |s|
+ s.required_ruby_version = "< #{Gem.ruby_version}"
+ end
+ end
+
+ gemfile <<-G
+ source "https://gem.repo2"
+ override :all, required_ruby_version: :ignore_upper
+ gem "needs_old_ruby_a"
+ gem "needs_old_ruby_b"
+ G
+
+ bundle :lock
+ expect(lockfile).to include("needs_old_ruby_a (1.0)")
+ expect(lockfile).to include("needs_old_ruby_b (1.0)")
+ end
+
+ it "is overridden by a per-gem override on the same field" do
+ build_repo2 do
+ build_gem "permissive", "1.0" do |s|
+ s.required_ruby_version = "< #{Gem.ruby_version}"
+ end
+ build_gem "still_blocked", "1.0" do |s|
+ s.required_ruby_version = "= #{Gem.ruby_version}.999"
+ end
+ end
+
+ # :all says ignore_upper (would unblock both), but per-gem on
+ # still_blocked nails it to a hard requirement that still fails.
+ gemfile <<-G
+ source "https://gem.repo2"
+ override :all, required_ruby_version: :ignore_upper
+ override "still_blocked", required_ruby_version: "= #{Gem.ruby_version}.999"
+ gem "permissive"
+ gem "still_blocked"
+ G
+
+ bundle :lock, raise_on_error: false
+ expect(err).to include("still_blocked")
+ end
+
+ it "preserves locked versions when an :all metadata override is added without bundle update" do
+ build_repo2 do
+ build_gem "selectable", "1.0"
+ build_gem "selectable", "2.0" do |s|
+ s.required_ruby_version = "< #{Gem.ruby_version}"
+ end
+ end
+
+ gemfile <<-G
+ source "https://gem.repo2"
+ gem "selectable"
+ G
+
+ bundle :lock
+ expect(lockfile).to include("selectable (1.0)")
+
+ gemfile <<-G
+ source "https://gem.repo2"
+ override :all, required_ruby_version: :ignore_upper
+ gem "selectable"
+ G
+
+ # :all override alone does not pre-unlock locked specs; narrow change
+ # should not trigger unrelated lockfile churn.
+ bundle :lock
+ expect(lockfile).to include("selectable (1.0)")
+
+ # bundle update opts the user into re-resolution under the override.
+ bundle "update selectable"
+ expect(lockfile).to include("selectable (2.0)")
+ end
+ end
+
+ context "diagnostic on resolve failure" do
+ it "lists active overrides with their Gemfile location" do
+ build_repo2 do
+ build_gem "needs_old_ruby", "1.0" do |s|
+ s.required_ruby_version = "= #{Gem.ruby_version}.999"
+ end
+ end
+
+ gemfile <<-G
+ source "https://gem.repo2"
+ override "needs_old_ruby", required_ruby_version: "= #{Gem.ruby_version}.999"
+ gem "needs_old_ruby"
+ G
+
+ bundle :lock, raise_on_error: false
+ expect(err).to include("Bundler applied the following overrides")
+ expect(err).to include("override \"needs_old_ruby\", required_ruby_version:")
+ expect(err).to match(/declared at Gemfile:\d+/)
+ end
+ end
+
+ context "install-time compatibility" do
+ it "installs a gem whose required_ruby_version excludes the current Ruby when an override removes the constraint" do
+ build_repo2 do
+ build_gem "needs_old_ruby", "1.0" do |s|
+ s.required_ruby_version = "< #{Gem.ruby_version}"
+ end
+ end
+
+ install_gemfile <<-G
+ source "https://gem.repo2"
+ override "needs_old_ruby", required_ruby_version: nil
+ gem "needs_old_ruby"
+ G
+
+ expect(the_bundle).to include_gems "needs_old_ruby 1.0"
+ end
+
+ it "installs a gem whose required_rubygems_version excludes the current RubyGems when an override removes it" do
+ build_repo2 do
+ build_gem "needs_old_rubygems", "1.0" do |s|
+ s.required_rubygems_version = "< #{Gem.rubygems_version}"
+ end
+ end
+
+ install_gemfile <<-G
+ source "https://gem.repo2"
+ override "needs_old_rubygems", required_rubygems_version: nil
+ gem "needs_old_rubygems"
+ G
+
+ expect(the_bundle).to include_gems "needs_old_rubygems 1.0"
+ end
+
+ it "installs every gem when :all required_ruby_version override is in effect" do
+ build_repo2 do
+ build_gem "needs_old_ruby_a", "1.0" do |s|
+ s.required_ruby_version = "< #{Gem.ruby_version}"
+ end
+ build_gem "needs_old_ruby_b", "1.0" do |s|
+ s.required_ruby_version = "< #{Gem.ruby_version}"
+ end
+ end
+
+ install_gemfile <<-G
+ source "https://gem.repo2"
+ override :all, required_ruby_version: :ignore_upper
+ gem "needs_old_ruby_a"
+ gem "needs_old_ruby_b"
+ G
+
+ expect(the_bundle).to include_gems "needs_old_ruby_a 1.0", "needs_old_ruby_b 1.0"
+ end
+ end
+end
diff --git a/spec/bundler/install/gemfile/path_spec.rb b/spec/bundler/install/gemfile/path_spec.rb
index 55bf11928d..b069488531 100644
--- a/spec/bundler/install/gemfile/path_spec.rb
+++ b/spec/bundler/install/gemfile/path_spec.rb
@@ -1,17 +1,6 @@
# frozen_string_literal: true
RSpec.describe "bundle install with explicit source paths" do
- it "fetches gems with a global path source" do
- build_lib "foo"
-
- install_gemfile <<-G
- path "#{lib_path("foo-1.0")}"
- gem 'foo'
- G
-
- expect(the_bundle).to include_gems("foo 1.0")
- end
-
it "fetches gems" do
build_lib "foo"
@@ -120,7 +109,7 @@ RSpec.describe "bundle install with explicit source paths" do
demo!
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
bundle :install, dir: lib_path("demo")
@@ -136,7 +125,7 @@ RSpec.describe "bundle install with explicit source paths" do
gem 'foo', :path => File.expand_path("foo-1.0", __dir__)
G
- bundle "config set --local frozen true"
+ bundle_config "frozen true"
bundle :install
end
@@ -357,7 +346,7 @@ RSpec.describe "bundle install with explicit source paths" do
foo!
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
lockfile lockfile_path, original_lockfile
@@ -465,7 +454,7 @@ RSpec.describe "bundle install with explicit source paths" do
it "handles directories in bin/" do
build_lib "foo"
- lib_path("foo-1.0").join("foo.gemspec").rmtree
+ FileUtils.rm_rf lib_path("foo-1.0").join("foo.gemspec")
lib_path("foo-1.0").join("bin/performance").mkpath
install_gemfile <<-G
@@ -672,7 +661,7 @@ RSpec.describe "bundle install with explicit source paths" do
foo!
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
G
build_lib "foo", "1.0", path: lib_path("foo") do |s|
@@ -700,7 +689,7 @@ RSpec.describe "bundle install with explicit source paths" do
foo!
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
G
expect(the_bundle).to include_gems "myrack 0.9.1"
@@ -739,7 +728,7 @@ RSpec.describe "bundle install with explicit source paths" do
foo!
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
G
build_lib "foo", "1.0", path: lib_path("foo") do |s|
@@ -772,7 +761,7 @@ RSpec.describe "bundle install with explicit source paths" do
foo!
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
G
expect(the_bundle).to include_gems "myrack 0.9.1"
@@ -800,7 +789,7 @@ RSpec.describe "bundle install with explicit source paths" do
foo!
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
bundle "lock"
@@ -826,8 +815,57 @@ RSpec.describe "bundle install with explicit source paths" do
foo!
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
+ G
+ end
+ end
+
+ context "when platform specific version locked, and having less dependencies that the generic version that's actually installed" do
+ before do
+ build_repo4 do
+ build_gem "racc", "1.8.1"
+ build_gem "mini_portile2", "2.8.2"
+ end
+
+ build_lib "nokogiri", "1.18.9", path: lib_path("nokogiri") do |s|
+ s.add_dependency "mini_portile2", "~> 2.8.2"
+ s.add_dependency "racc", "~> 1.4"
+ end
+
+ gemfile <<~G
+ source "https://gem.repo4"
+
+ gem "nokogiri", path: "#{lib_path("nokogiri")}"
G
+
+ lockfile <<~L
+ PATH
+ remote: #{lib_path("nokogiri")}
+ specs:
+ nokogiri (1.18.9)
+ mini_portile2 (~> 2.8.2)
+ racc (~> 1.4)
+ nokogiri (1.18.9-arm64-darwin)
+ racc (~> 1.4)
+
+ GEM
+ remote: https://rubygems.org/
+ specs:
+ racc (1.8.1)
+
+ PLATFORMS
+ #{lockfile_platforms}
+
+ DEPENDENCIES
+ nokogiri!
+
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+ end
+
+ it "works" do
+ bundle "install"
end
end
diff --git a/spec/bundler/install/gemfile/platform_spec.rb b/spec/bundler/install/gemfile/platform_spec.rb
index 5ed5e66185..e12933ebcf 100644
--- a/spec/bundler/install/gemfile/platform_spec.rb
+++ b/spec/bundler/install/gemfile/platform_spec.rb
@@ -65,7 +65,7 @@ RSpec.describe "bundle install across platforms" do
platform_specific
G
- bundle "config set --local frozen true"
+ bundle_config "frozen true"
install_gemfile <<-G
source "https://gem.repo1"
@@ -162,7 +162,7 @@ RSpec.describe "bundle install across platforms" do
expect(the_bundle).to include_gems "nokogiri 1.4.2 java", "weakling 0.0.3"
pristine_system_gems
- bundle "config set --local force_ruby_platform true"
+ bundle_config "force_ruby_platform true"
bundle "install"
expect(the_bundle).to include_gems "nokogiri 1.4.2"
@@ -235,7 +235,7 @@ RSpec.describe "bundle install across platforms" do
pry
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
bundle "lock --add-platform ruby"
@@ -269,7 +269,7 @@ RSpec.describe "bundle install across platforms" do
pry
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
expect(lockfile).to eq good_lockfile
@@ -365,7 +365,7 @@ RSpec.describe "bundle install across platforms" do
gem "myrack", "1.0.0"
G
- bundle "config set --local path vendor/bundle"
+ bundle_config "path vendor/bundle"
bundle :install
FileUtils.mv(vendored_gems, bundled_app("vendor/bundle", Gem.ruby_engine, "1.8"))
@@ -394,7 +394,7 @@ RSpec.describe "bundle install across platforms" do
#{checksums}
G
- bundle "config set --local force_ruby_platform true"
+ bundle_config "force_ruby_platform true"
install_gemfile <<-G
source "https://gem.repo1"
@@ -420,7 +420,7 @@ RSpec.describe "bundle install across platforms" do
platform_specific
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
G
end
end
@@ -486,7 +486,7 @@ RSpec.describe "bundle install with platform conditionals" do
tzinfo (~> 1.2)
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
bundle "install --verbose"
@@ -542,7 +542,7 @@ RSpec.describe "bundle install with platform conditionals" do
end
it "does not attempt to install gems from :rbx when using --local" do
- bundle "config set --local force_ruby_platform true"
+ bundle_config "force_ruby_platform true"
gemfile <<-G
source "https://gem.repo1"
@@ -554,7 +554,7 @@ RSpec.describe "bundle install with platform conditionals" do
end
it "does not attempt to install gems from other rubies when using --local" do
- bundle "config set --local force_ruby_platform true"
+ bundle_config "force_ruby_platform true"
gemfile <<-G
source "https://gem.repo1"
gem "some_gem", platform: :ruby_22
@@ -565,7 +565,7 @@ RSpec.describe "bundle install with platform conditionals" do
end
it "does not print a warning when a dependency is unused on a platform different from the current one" do
- bundle "config set --local force_ruby_platform true"
+ bundle_config "force_ruby_platform true"
gemfile <<-G
source "https://gem.repo1"
@@ -589,12 +589,12 @@ RSpec.describe "bundle install with platform conditionals" do
myrack
#{checksums_section_when_enabled}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
it "resolves fine when a dependency is unused on a platform different from the current one, but reintroduced transitively" do
- bundle "config set --local force_ruby_platform true"
+ bundle_config "force_ruby_platform true"
build_repo4 do
build_gem "listen", "3.7.1" do |s|
diff --git a/spec/bundler/install/gemfile/ruby_spec.rb b/spec/bundler/install/gemfile/ruby_spec.rb
index 3e15d82bbe..d937abd714 100644
--- a/spec/bundler/install/gemfile/ruby_spec.rb
+++ b/spec/bundler/install/gemfile/ruby_spec.rb
@@ -83,10 +83,10 @@ RSpec.describe "ruby requirement" do
myrack
RUBY VERSION
- ruby 2.1.4p422
+ ruby 2.1.4
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
allow(Bundler::SharedHelpers).to receive(:find_gemfile).and_return(bundled_app_gemfile)
diff --git a/spec/bundler/install/gemfile/sources_spec.rb b/spec/bundler/install/gemfile/sources_spec.rb
index 406d881541..654d638e1f 100644
--- a/spec/bundler/install/gemfile/sources_spec.rb
+++ b/spec/bundler/install/gemfile/sources_spec.rb
@@ -4,153 +4,6 @@ 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
- context "without source affinity" do
- before do
- # Oh no! Someone evil is trying to hijack myrack :(
- # 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'"
- end
- end
- end
-
- context "with multiple toplevel sources" do
- let(:repo3_myrack_version) { "1.0.0" }
-
- before do
- gemfile <<-G
- source "https://gem.repo3"
- source "https://gem.repo1"
- gem "myrack-obama"
- gem "myrack"
- G
- end
-
- it "refuses to install mismatched checksum because one gem has been tampered with" 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
-
- 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
- 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" 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" 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: "4" 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 "when different versions of the same gem are in multiple sources" do
- let(:repo3_myrack_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
- G
- end
-
- it "warns about ambiguous gems, but installs anyway" 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 "fails", bundler: "4" 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" 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
@@ -189,7 +42,7 @@ RSpec.describe "bundle install with gems on multiple sources" do
expect(bundled_app("vendor/cache/myrack-1.0.0.gem")).to exist
expect(bundled_app("vendor/cache/myrack-obama-1.0.gem")).to exist
- bundle "config set --local deployment true"
+ bundle_config "deployment true"
bundle :install, artifice: "compact_index"
expect(the_bundle).to include_gems("myrack-obama 1.0.0", "myrack 1.0.0")
@@ -313,189 +166,6 @@ RSpec.describe "bundle install with gems on multiple sources" do
expect(the_bundle).to include_gems("depends_on_myrack 1.0.1", "myrack 1.0.0")
end
end
-
- context "and in yet another source" do
- before do
- gemfile <<-G
- source "https://gem.repo1"
- source "https://gem.repo2"
- source "https://gem.repo3" do
- gem "depends_on_myrack"
- end
- G
- end
-
- it "fails when the two sources don't have the same checksum" 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" 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" 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.")
- 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)
-
- 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(lockfile).to eq(previous_lockfile)
- end
-
- it "installs from the other source and warns about ambiguous gems when checksum validation is disabled" 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)
-
- 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(lockfile).to eq(previous_lockfile)
- end
-
- it "fails", bundler: "4" 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 "and only the dependency is pinned" 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'"
- end
- end
-
- gemfile <<-G
- source "https://gem.repo3" # contains depends_on_myrack
- source "https://gem.repo2" # contains broken myrack
-
- gem "depends_on_myrack" # installed from gem_repo3
- gem "myrack", :source => "https://gem.repo1"
- G
- end
-
- it "installs the dependency from the pinned source without warning" 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")
-
- # In https://github.com/rubygems/bundler/issues/3585 this failed
- # when there is already a lockfile, and the gems are missing, so try again
- system_gems []
- 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")
- end
-
- it "fails", bundler: "4" 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 "when a top-level gem can only be found in an scoped source" do
@@ -524,39 +194,6 @@ RSpec.describe "bundle install with gems on multiple sources" do
end
end
- context "when an indirect dependency can't be found in the aggregate rubygems source" do
- before do
- build_repo2
-
- build_repo3 do
- build_gem "depends_on_missing", "1.0.1" do |s|
- s.add_dependency "missing"
- end
- end
-
- gemfile <<-G
- source "https://gem.repo2"
-
- source "https://gem.repo3"
-
- gem "depends_on_missing"
- G
- end
-
- it "fails" do
- 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_missing depends on missing >= 0
- and missing >= 0 could not be found in any of the sources,
- depends_on_missing cannot be used.
- So, because Gemfile depends on depends_on_missing >= 0,
- version solving has failed.
- E
- end
- end
-
context "when a top-level gem has an indirect dependency" do
before do
build_repo gem_repo2 do
@@ -714,337 +351,6 @@ RSpec.describe "bundle install with gems on multiple sources" do
end
end
- context "when the lockfile has aggregated rubygems sources and newer versions of dependencies are available" do
- before do
- build_repo gem_repo2 do
- build_gem "activesupport", "6.0.3.4" do |s|
- s.add_dependency "concurrent-ruby", "~> 1.0", ">= 1.0.2"
- s.add_dependency "i18n", ">= 0.7", "< 2"
- s.add_dependency "minitest", "~> 5.1"
- s.add_dependency "tzinfo", "~> 1.1"
- s.add_dependency "zeitwerk", "~> 2.2", ">= 2.2.2"
- end
-
- build_gem "activesupport", "6.1.2.1" do |s|
- s.add_dependency "concurrent-ruby", "~> 1.0", ">= 1.0.2"
- s.add_dependency "i18n", ">= 1.6", "< 2"
- s.add_dependency "minitest", ">= 5.1"
- s.add_dependency "tzinfo", "~> 2.0"
- s.add_dependency "zeitwerk", "~> 2.3"
- end
-
- build_gem "concurrent-ruby", "1.1.8"
- build_gem "concurrent-ruby", "1.1.9"
- build_gem "connection_pool", "2.2.3"
-
- build_gem "i18n", "1.8.9" do |s|
- s.add_dependency "concurrent-ruby", "~> 1.0"
- end
-
- build_gem "minitest", "5.14.3"
- build_gem "myrack", "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 "redis", ">= 4.2.0"
- end
-
- build_gem "thread_safe", "0.3.6"
-
- build_gem "tzinfo", "1.2.9" do |s|
- s.add_dependency "thread_safe", "~> 0.1"
- end
-
- build_gem "tzinfo", "2.0.4" do |s|
- s.add_dependency "concurrent-ruby", "~> 1.0"
- end
-
- build_gem "zeitwerk", "2.4.2"
- end
-
- build_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"
- end
- end
-
- gemfile <<-G
- # frozen_string_literal: true
-
- source "https://gem.repo2"
-
- gem "activesupport"
-
- source "https://gem.repo3" do
- gem "sidekiq-pro"
- 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/
- remote: https://gem.repo3/
- specs:
- activesupport (6.0.3.4)
- concurrent-ruby (~> 1.0, >= 1.0.2)
- i18n (>= 0.7, < 2)
- minitest (~> 5.1)
- tzinfo (~> 1.1)
- zeitwerk (~> 2.2, >= 2.2.2)
- concurrent-ruby (1.1.8)
- connection_pool (2.2.3)
- i18n (1.8.9)
- concurrent-ruby (~> 1.0)
- minitest (5.14.3)
- myrack (2.2.3)
- redis (4.2.5)
- sidekiq (6.1.3)
- connection_pool (>= 2.2.2)
- myrack (~> 2.0)
- redis (>= 4.2.0)
- sidekiq-pro (5.2.1)
- connection_pool (>= 2.2.3)
- sidekiq (>= 6.1.0)
- thread_safe (0.3.6)
- tzinfo (1.2.9)
- thread_safe (~> 0.1)
- zeitwerk (2.4.2)
-
- PLATFORMS
- #{lockfile_platforms}
-
- 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"
- expect(err).to be_empty
-
- expect(the_bundle).to include_gems("activesupport 6.0.3.4")
- expect(the_bundle).not_to include_gems("activesupport 6.1.2.1")
- expect(the_bundle).to include_gems("tzinfo 1.2.9")
- expect(the_bundle).not_to include_gems("tzinfo 2.0.4")
- expect(the_bundle).to include_gems("concurrent-ruby 1.1.8")
- expect(the_bundle).not_to include_gems("concurrent-ruby 1.1.9")
-
- expect(lockfile).to eq <<~L
- GEM
- remote: https://gem.repo2/
- specs:
- activesupport (6.0.3.4)
- concurrent-ruby (~> 1.0, >= 1.0.2)
- i18n (>= 0.7, < 2)
- minitest (~> 5.1)
- tzinfo (~> 1.1)
- zeitwerk (~> 2.2, >= 2.2.2)
- concurrent-ruby (1.1.8)
- connection_pool (2.2.3)
- i18n (1.8.9)
- concurrent-ruby (~> 1.0)
- minitest (5.14.3)
- myrack (2.2.3)
- redis (4.2.5)
- sidekiq (6.1.3)
- connection_pool (>= 2.2.2)
- myrack (~> 2.0)
- redis (>= 4.2.0)
- thread_safe (0.3.6)
- tzinfo (1.2.9)
- thread_safe (~> 0.1)
- zeitwerk (2.4.2)
-
- GEM
- remote: https://gem.repo3/
- specs:
- sidekiq-pro (5.2.1)
- connection_pool (>= 2.2.3)
- sidekiq (>= 6.1.0)
-
- PLATFORMS
- #{lockfile_platforms}
-
- 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" do
- initial_lockfile = lockfile
-
- bundle "config set --local frozen true"
- bundle :install, artifice: "compact_index"
-
- expect(err).to include("Your lockfile contains a single rubygems source section with multiple remotes, which is insecure.")
-
- expect(the_bundle).to include_gems("activesupport 6.0.3.4")
- expect(the_bundle).not_to include_gems("activesupport 6.1.2.1")
- expect(the_bundle).to include_gems("tzinfo 1.2.9")
- expect(the_bundle).not_to include_gems("tzinfo 2.0.4")
- expect(the_bundle).to include_gems("concurrent-ruby 1.1.8")
- expect(the_bundle).not_to include_gems("concurrent-ruby 1.1.9")
-
- expect(lockfile).to eq(initial_lockfile)
- end
-
- it "fails when running bundle install in frozen mode", bundler: "4" do
- initial_lockfile = lockfile
-
- bundle "config set --local frozen true"
- 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.")
-
- expect(lockfile).to eq(initial_lockfile)
- end
-
- it "splits sections and upgrades gems when running bundle update, and doesn't warn" do
- 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
- remote: https://gem.repo2/
- specs:
- activesupport (6.1.2.1)
- concurrent-ruby (~> 1.0, >= 1.0.2)
- i18n (>= 1.6, < 2)
- minitest (>= 5.1)
- tzinfo (~> 2.0)
- zeitwerk (~> 2.3)
- concurrent-ruby (1.1.9)
- connection_pool (2.2.3)
- i18n (1.8.9)
- concurrent-ruby (~> 1.0)
- minitest (5.14.3)
- myrack (2.2.3)
- redis (4.2.5)
- sidekiq (6.1.3)
- connection_pool (>= 2.2.2)
- myrack (~> 2.0)
- redis (>= 4.2.0)
- tzinfo (2.0.4)
- concurrent-ruby (~> 1.0)
- zeitwerk (2.4.2)
-
- GEM
- remote: https://gem.repo3/
- specs:
- sidekiq-pro (5.2.1)
- connection_pool (>= 2.2.3)
- sidekiq (>= 6.1.0)
-
- PLATFORMS
- #{lockfile_platforms}
-
- 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"
- expect(err).to be_empty
-
- expect(the_bundle).to include_gems("activesupport 6.0.3.4")
- expect(the_bundle).not_to include_gems("activesupport 6.1.2.1")
- expect(the_bundle).to include_gems("tzinfo 1.2.9")
- expect(the_bundle).not_to include_gems("tzinfo 2.0.4")
- 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/
- specs:
- activesupport (6.0.3.4)
- concurrent-ruby (~> 1.0, >= 1.0.2)
- i18n (>= 0.7, < 2)
- minitest (~> 5.1)
- tzinfo (~> 1.1)
- zeitwerk (~> 2.2, >= 2.2.2)
- concurrent-ruby (1.1.9)
- connection_pool (2.2.3)
- i18n (1.8.9)
- concurrent-ruby (~> 1.0)
- minitest (5.14.3)
- myrack (2.2.3)
- redis (4.2.5)
- sidekiq (6.1.3)
- connection_pool (>= 2.2.2)
- myrack (~> 2.0)
- redis (>= 4.2.0)
- thread_safe (0.3.6)
- tzinfo (1.2.9)
- thread_safe (~> 0.1)
- zeitwerk (2.4.2)
-
- GEM
- remote: https://gem.repo3/
- specs:
- sidekiq-pro (5.2.1)
- connection_pool (>= 2.2.3)
- sidekiq (>= 6.1.0)
-
- PLATFORMS
- #{lockfile_platforms}
-
- DEPENDENCIES
- activesupport
- sidekiq-pro!
- #{@locked_checksums}
- BUNDLED WITH
- #{Bundler::VERSION}
- L
- end
- end
-
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")
@@ -1134,7 +440,7 @@ RSpec.describe "bundle install with gems on multiple sources" do
nokogiri
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
bundle "install --verbose", artifice: "compact_index"
@@ -1207,112 +513,6 @@ RSpec.describe "bundle install with gems on multiple sources" do
end
end
- context "with a lockfile with aggregated rubygems sources" do
- let(:aggregate_gem_section_lockfile) do
- <<~L
- GEM
- remote: https://gem.repo1/
- remote: https://gem.repo3/
- specs:
- myrack (0.9.1)
-
- PLATFORMS
- #{lockfile_platforms}
-
- DEPENDENCIES
- myrack!
-
- BUNDLED WITH
- #{Bundler::VERSION}
- L
- end
-
- let(:split_gem_section_lockfile) do
- <<~L
- GEM
- remote: https://gem.repo1/
- specs:
-
- GEM
- remote: https://gem.repo3/
- specs:
- myrack (0.9.1)
-
- PLATFORMS
- #{lockfile_platforms}
-
- DEPENDENCIES
- myrack!
-
- BUNDLED WITH
- #{Bundler::VERSION}
- L
- end
-
- before do
- build_repo3 do
- build_gem "myrack", "0.9.1"
- end
-
- gemfile <<-G
- source "https://gem.repo1"
- source "https://gem.repo3" do
- gem 'myrack'
- end
- G
-
- lockfile aggregate_gem_section_lockfile
- end
-
- it "installs the existing lockfile but prints a warning when checksum validation is disabled" do
- bundle "config set --local deployment true"
- bundle "config set --local disable_checksum_validation true"
-
- 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" 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
- end
-
- it "refuses to install the existing lockfile and prints an error", bundler: "4" do
- bundle "config set --local deployment true"
-
- 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.")
- expect(out).to be_empty
- end
- end
-
context "with a path gem in the same Gemfile" do
before do
build_lib "foo"
@@ -1366,11 +566,11 @@ RSpec.describe "bundle install with gems on multiple sources" do
gem 'bar', '~> 0.1', :source => 'https://gem.repo4'
G
- bundle "config set --local path ../gems/system"
+ bundle_config "path ../gems/system"
bundle :install, artifice: "compact_index"
# And then we add some new versions...
- update_repo4 do
+ build_repo4 do
build_gem "foo", "0.2"
build_gem "bar", "0.3"
end
@@ -1584,37 +784,6 @@ RSpec.describe "bundle install with gems on multiple sources" do
end
context "when an indirect dependency is available from multiple ambiguous sources" do
- it "succeeds but warns, suggesting a source block" do
- build_repo4 do
- build_gem "depends_on_myrack" do |s|
- s.add_dependency "myrack"
- end
- build_gem "myrack"
- 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"
- end
-
- source "https://scoped.source" 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/
- 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
- expect(the_bundle).to be_locked
- end
- end
-
- context "when an indirect dependency is available from multiple ambiguous sources", bundler: "4" do
it "raises, suggesting a source block" do
build_repo4 do
build_gem "depends_on_myrack" do |s|
@@ -1645,83 +814,6 @@ RSpec.describe "bundle install with gems on multiple sources" do
end
end
- context "when upgrading a lockfile suffering from dependency confusion" do
- before do
- build_repo4 do
- build_gem "mime-types", "3.0.0"
- end
-
- build_repo2 do
- build_gem "capybara", "2.5.0" do |s|
- s.add_dependency "mime-types", ">= 1.16"
- end
-
- build_gem "mime-types", "3.3.1"
- end
-
- gemfile <<~G
- source "https://gem.repo2"
-
- gem "capybara", "~> 2.5.0"
-
- source "https://gem.repo4" do
- gem "mime-types", "~> 3.0"
- end
- G
-
- lockfile <<-L
- GEM
- remote: https://gem.repo2/
- remote: https://gem.repo4/
- specs:
- capybara (2.5.0)
- mime-types (>= 1.16)
- mime-types (3.3.1)
-
- PLATFORMS
- #{lockfile_platforms}
-
- 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
-
- expect(lockfile).to eq <<~L
- GEM
- remote: https://gem.repo2/
- specs:
- capybara (2.5.0)
- mime-types (>= 1.16)
-
- GEM
- remote: https://gem.repo4/
- specs:
- mime-types (3.0.0)
-
- PLATFORMS
- #{lockfile_platforms}
-
- DEPENDENCIES
- capybara (~> 2.5.0)
- mime-types (~> 3.0)!
- #{checksums}
- BUNDLED WITH
- #{Bundler::VERSION}
- L
- end
- end
-
context "when default source includes old gems with nil required_ruby_version" do
before do
build_repo2 do
@@ -1775,7 +867,7 @@ RSpec.describe "bundle install with gems on multiple sources" do
ruport (= 1.7.0.3)!
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
end
@@ -1833,7 +925,7 @@ RSpec.describe "bundle install with gems on multiple sources" do
ruport (= 1.7.0.3)!
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
end
@@ -1878,7 +970,7 @@ RSpec.describe "bundle install with gems on multiple sources" do
pdf-writer (= 1.1.8)
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
end
@@ -1946,7 +1038,7 @@ RSpec.describe "bundle install with gems on multiple sources" do
foo!
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
@@ -1987,4 +1079,235 @@ RSpec.describe "bundle install with gems on multiple sources" do
expect(lockfile).to eq original_lockfile.gsub("bigdecimal (1.0.0)", "bigdecimal (3.3.1)")
end
end
+
+ context "when switching a gem with components from rubygems to git source" do
+ before do
+ build_repo2 do
+ build_gem "rails", "7.0.0" do |s|
+ s.add_dependency "actionpack", "7.0.0"
+ s.add_dependency "activerecord", "7.0.0"
+ end
+ build_gem "actionpack", "7.0.0"
+ build_gem "activerecord", "7.0.0"
+ # propshaft also depends on actionpack, creating the conflict
+ build_gem "propshaft", "1.0.0" do |s|
+ s.add_dependency "actionpack", ">= 7.0.0"
+ end
+ end
+
+ build_git "rails", "7.0.0", path: lib_path("rails") do |s|
+ s.add_dependency "actionpack", "7.0.0"
+ s.add_dependency "activerecord", "7.0.0"
+ end
+
+ build_git "actionpack", "7.0.0", path: lib_path("rails")
+ build_git "activerecord", "7.0.0", path: lib_path("rails")
+
+ install_gemfile <<-G
+ source "https://gem.repo2"
+ gem "rails", "7.0.0"
+ gem "propshaft"
+ G
+ end
+
+ it "moves component gems to the git source in the lockfile" do
+ expect(lockfile).to include("remote: https://gem.repo2")
+ expect(lockfile).to include("rails (7.0.0)")
+ expect(lockfile).to include("actionpack (7.0.0)")
+ expect(lockfile).to include("activerecord (7.0.0)")
+ expect(lockfile).to include("propshaft (1.0.0)")
+
+ gemfile <<-G
+ source "https://gem.repo2"
+ gem "rails", git: "#{lib_path("rails")}"
+ gem "propshaft"
+ G
+
+ bundle "install"
+
+ expect(lockfile).to include("remote: #{lib_path("rails")}")
+ expect(lockfile).to include("rails (7.0.0)")
+ expect(lockfile).to include("actionpack (7.0.0)")
+ expect(lockfile).to include("activerecord (7.0.0)")
+
+ # Component gems should NOT remain in the GEM section
+ # Extract just the GEM section by splitting on GIT first, then GEM
+ gem_section = lockfile.split("GEM\n").last.split(/\n(PLATFORMS|DEPENDENCIES)/)[0]
+ expect(gem_section).not_to include("actionpack (7.0.0)")
+ expect(gem_section).not_to include("activerecord (7.0.0)")
+ end
+ end
+
+ context "when switching a gem with components from rubygems to path source" do
+ before do
+ build_repo2 do
+ build_gem "rails", "7.0.0" do |s|
+ s.add_dependency "actionpack", "7.0.0"
+ s.add_dependency "activerecord", "7.0.0"
+ end
+ build_gem "actionpack", "7.0.0"
+ build_gem "activerecord", "7.0.0"
+ # propshaft also depends on actionpack, creating the conflict
+ build_gem "propshaft", "1.0.0" do |s|
+ s.add_dependency "actionpack", ">= 7.0.0"
+ end
+ end
+
+ build_lib "rails", "7.0.0", path: lib_path("rails") do |s|
+ s.add_dependency "actionpack", "7.0.0"
+ s.add_dependency "activerecord", "7.0.0"
+ end
+
+ build_lib "actionpack", "7.0.0", path: lib_path("rails")
+ build_lib "activerecord", "7.0.0", path: lib_path("rails")
+
+ install_gemfile <<-G
+ source "https://gem.repo2"
+ gem "rails", "7.0.0"
+ gem "propshaft"
+ G
+ end
+
+ it "moves component gems to the path source in the lockfile" do
+ expect(lockfile).to include("remote: https://gem.repo2")
+ expect(lockfile).to include("rails (7.0.0)")
+ expect(lockfile).to include("actionpack (7.0.0)")
+ expect(lockfile).to include("activerecord (7.0.0)")
+ expect(lockfile).to include("propshaft (1.0.0)")
+
+ gemfile <<-G
+ source "https://gem.repo2"
+ gem "rails", path: "#{lib_path("rails")}"
+ gem "propshaft"
+ G
+
+ bundle "install"
+
+ expect(lockfile).to include("remote: #{lib_path("rails")}")
+ expect(lockfile).to include("rails (7.0.0)")
+ expect(lockfile).to include("actionpack (7.0.0)")
+ expect(lockfile).to include("activerecord (7.0.0)")
+
+ # Component gems should NOT remain in the GEM section
+ # Extract just the GEM section by splitting appropriately
+ gem_section = lockfile.split("GEM\n").last.split(/\n(PLATFORMS|DEPENDENCIES)/)[0]
+ expect(gem_section).not_to include("actionpack (7.0.0)")
+ expect(gem_section).not_to include("activerecord (7.0.0)")
+ end
+ end
+
+ context "when a scoped rubygems source is missing a transitive dependency" do
+ before do
+ build_repo2 do
+ build_gem "fallback_dep", "1.0.0"
+ build_gem "foo", "1.0.0"
+ end
+
+ build_repo3 do
+ build_gem "private_parent", "1.0.0" do |s|
+ s.add_dependency "fallback_dep"
+ end
+ end
+
+ gemfile <<-G
+ source "https://gem.repo2"
+
+ gem "foo"
+
+ source "https://gem.repo3" do
+ gem "private_parent", "1.0.0"
+ end
+ G
+
+ bundle :install, artifice: "compact_index"
+ end
+
+ it "falls back to the default rubygems source for that dependency" do
+ build_repo2 do
+ build_gem "foo", "2.0.0"
+ end
+
+ system_gems []
+
+ bundle "update foo", artifice: "compact_index"
+
+ expect(the_bundle).to include_gems("private_parent 1.0.0", "fallback_dep 1.0.0", "foo 2.0.0")
+ expect(the_bundle).to include_gems("private_parent 1.0.0", source: "remote3")
+ expect(the_bundle).to include_gems("fallback_dep 1.0.0", source: "remote2")
+ end
+ end
+
+ context "when a path gem has a transitive dependency that does not exist in the path source" do
+ before do
+ build_repo2 do
+ build_gem "missing_dep", "1.0.0"
+ build_gem "foo", "1.0.0"
+ end
+
+ build_lib "parent_gem", "1.0.0", path: lib_path("parent_gem") do |s|
+ s.add_dependency "missing_dep"
+ end
+
+ gemfile <<-G
+ source "https://gem.repo2"
+
+ gem "foo"
+
+ gem "parent_gem", path: "#{lib_path("parent_gem")}"
+ G
+
+ bundle :install, artifice: "compact_index"
+ end
+
+ it "falls back to the default rubygems source for that dependency when updating" do
+ build_repo2 do
+ build_gem "foo", "2.0.0"
+ end
+
+ system_gems []
+
+ bundle "update foo", artifice: "compact_index"
+
+ expect(the_bundle).to include_gems("parent_gem 1.0.0", "missing_dep 1.0.0", "foo 2.0.0")
+ expect(the_bundle).to include_gems("parent_gem 1.0.0", source: "path@#{lib_path("parent_gem")}")
+ expect(the_bundle).to include_gems("missing_dep 1.0.0", source: "remote2")
+ end
+ end
+
+ context "when a git gem has a transitive dependency that does not exist in the git source" do
+ before do
+ build_repo2 do
+ build_gem "missing_dep", "1.0.0"
+ build_gem "foo", "1.0.0"
+ end
+
+ build_git "parent_gem", "1.0.0", path: lib_path("parent_gem") do |s|
+ s.add_dependency "missing_dep"
+ end
+
+ gemfile <<-G
+ source "https://gem.repo2"
+
+ gem "foo"
+
+ gem "parent_gem", git: "#{lib_path("parent_gem")}"
+ G
+
+ bundle :install, artifice: "compact_index"
+ end
+
+ it "falls back to the default rubygems source for that dependency when updating" do
+ build_repo2 do
+ build_gem "foo", "2.0.0"
+ end
+
+ system_gems []
+
+ bundle "update foo", artifice: "compact_index"
+
+ expect(the_bundle).to include_gems("parent_gem 1.0.0", "missing_dep 1.0.0", "foo 2.0.0")
+ expect(the_bundle).to include_gems("parent_gem 1.0.0", source: "git@#{lib_path("parent_gem")}")
+ expect(the_bundle).to include_gems("missing_dep 1.0.0", source: "remote2")
+ end
+ end
end
diff --git a/spec/bundler/install/gemfile/specific_platform_spec.rb b/spec/bundler/install/gemfile/specific_platform_spec.rb
index 62540f0488..97b1d233bf 100644
--- a/spec/bundler/install/gemfile/specific_platform_spec.rb
+++ b/spec/bundler/install/gemfile/specific_platform_spec.rb
@@ -54,7 +54,7 @@ RSpec.describe "bundle install with specific platforms" do
sass-embedded
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
bundle "install --verbose"
@@ -70,7 +70,7 @@ RSpec.describe "bundle install with specific platforms" do
setup_multiplatform_gem
# Consistent location to install and look for gems
- bundle "config set --local path vendor/bundle"
+ bundle_config "path vendor/bundle"
install_gemfile(google_protobuf)
@@ -88,11 +88,11 @@ RSpec.describe "bundle install with specific platforms" do
google-protobuf
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
# force strict usage of the lockfile by setting frozen mode
- bundle "config set --local frozen true"
+ bundle_config "frozen true"
# 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")
@@ -104,7 +104,7 @@ RSpec.describe "bundle install with specific platforms" do
setup_multiplatform_gem
# Consistent location to install and look for gems
- bundle "config set --local path vendor/bundle"
+ bundle_config "path vendor/bundle"
gemfile google_protobuf
@@ -126,7 +126,7 @@ RSpec.describe "bundle install with specific platforms" do
google-protobuf
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
bundle "update"
@@ -151,12 +151,17 @@ RSpec.describe "bundle install with specific platforms" do
google-protobuf
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
end
context "when running on a legacy lockfile locked only to ruby" do
+ # Exercises the legacy lockfile path (use_exact_resolved_specifications? = false)
+ # because most_specific_locked_platform is ruby, matching the generic platform.
+ # Key insight: when target (arm64-darwin-22) != platform (ruby), the code tries
+ # both platforms before falling back, preserving lockfile integrity.
+
around do |example|
build_repo4 do
build_gem "nokogiri", "1.3.10"
@@ -185,20 +190,76 @@ RSpec.describe "bundle install with specific platforms" do
nokogiri
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
simulate_platform "arm64-darwin-22", &example
end
it "still installs the generic ruby variant if necessary" do
- bundle "install --verbose"
- expect(out).to include("Installing nokogiri 1.3.10")
+ bundle "install"
+ expect(the_bundle).to include_gem("nokogiri 1.3.10")
+ expect(the_bundle).not_to include_gem("nokogiri 1.3.10 arm64-darwin")
end
it "still installs the generic ruby variant if necessary, even in frozen mode" do
- bundle "install --verbose", env: { "BUNDLE_FROZEN" => "true" }
- expect(out).to include("Installing nokogiri 1.3.10")
+ bundle "install", env: { "BUNDLE_FROZEN" => "true" }
+ expect(the_bundle).to include_gem("nokogiri 1.3.10")
+ expect(the_bundle).not_to include_gem("nokogiri 1.3.10 arm64-darwin")
+ end
+ end
+
+ context "when platform-specific gem has incompatible required_ruby_version" do
+ # Key insight: candidate_platforms tries [target, platform, ruby] in order.
+ # Ruby platform is last since it requires compilation, but works when
+ # precompiled gems are incompatible with the current Ruby version.
+ #
+ # Note: This fix requires the lockfile to include both ruby and platform-
+ # specific variants (typical after `bundle lock --add-platform`). If the
+ # lockfile only has platform-specific gems, frozen mode cannot help because
+ # Bundler.setup would still expect the locked (incompatible) gem.
+
+ # Exercises the exact spec path (use_exact_resolved_specifications? = true)
+ # because lockfile has platform-specific entry as most_specific_locked_platform
+ it "falls back to ruby platform in frozen mode when lockfile includes both variants" do
+ build_repo4 do
+ build_gem "nokogiri", "1.18.10"
+ build_gem "nokogiri", "1.18.10" do |s|
+ s.platform = "x86_64-linux"
+ s.required_ruby_version = "< #{Gem.ruby_version}"
+ end
+ end
+
+ gemfile <<~G
+ source "https://gem.repo4"
+
+ gem "nokogiri"
+ G
+
+ # Lockfile has both ruby and platform-specific gem (typical after `bundle lock --add-platform`)
+ lockfile <<-L
+ GEM
+ remote: https://gem.repo4/
+ specs:
+ nokogiri (1.18.10)
+ nokogiri (1.18.10-x86_64-linux)
+
+ PLATFORMS
+ ruby
+ x86_64-linux
+
+ DEPENDENCIES
+ nokogiri
+
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+
+ simulate_platform "x86_64-linux" do
+ bundle "install", env: { "BUNDLE_FROZEN" => "true" }
+ expect(the_bundle).to include_gem("nokogiri 1.18.10")
+ expect(the_bundle).not_to include_gem("nokogiri 1.18.10 x86_64-linux")
+ end
end
end
@@ -214,7 +275,7 @@ RSpec.describe "bundle install with specific platforms" do
end
# Consistent location to install and look for gems
- bundle "config set --local path vendor/bundle"
+ bundle_config "path vendor/bundle"
gemfile <<-G
source "https://gem.repo2"
@@ -235,7 +296,7 @@ RSpec.describe "bundle install with specific platforms" do
libv8
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
bundle "install --verbose"
@@ -273,7 +334,7 @@ RSpec.describe "bundle install with specific platforms" do
grpc
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
bundle "install --verbose", artifice: "compact_index_precompiled_before"
@@ -298,7 +359,7 @@ RSpec.describe "bundle install with specific platforms" do
simulate_platform "x86_64-darwin-15" do
setup_multiplatform_gem
gemfile(google_protobuf)
- bundle "config set --local cache_all_platforms true"
+ bundle_config "cache_all_platforms true"
bundle "cache"
expect(cached_gem("google-protobuf-3.0.0.alpha.5.0.5.1-universal-darwin")).to exist
@@ -333,10 +394,9 @@ RSpec.describe "bundle install with specific platforms" do
pg_array_parser!
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
- bundle "config set --local cache_all true"
bundle "cache --all-platforms"
expect(err).to be_empty
@@ -434,7 +494,7 @@ RSpec.describe "bundle install with specific platforms" do
sorbet-static (= 0.5.6403)
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
bundle "install --verbose"
@@ -475,6 +535,41 @@ RSpec.describe "bundle install with specific platforms" do
expect(err).to include(error_message).once
end
+ it "shows a platform mismatch hint when the current platform is not in the lockfile's platforms" do
+ build_repo4 do
+ build_gem("sorbet-static", "0.5.6433") {|s| s.platform = "x86_64-linux-musl" }
+ end
+
+ gemfile <<~G
+ source "https://gem.repo4"
+
+ gem "sorbet-static", "0.5.6433"
+ G
+
+ lockfile <<~L
+ GEM
+ remote: https://gem.repo4/
+ specs:
+ sorbet-static (0.5.6433-x86_64-linux-musl)
+
+ PLATFORMS
+ x86_64-linux-musl
+
+ DEPENDENCIES
+ sorbet-static (= 0.5.6433)
+
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+
+ simulate_platform "x86_64-linux" do
+ bundle "install", raise_on_error: false
+ end
+
+ expect(err).to include("Your current platform (x86_64-linux) is not included in the lockfile's platforms (x86_64-linux-musl)")
+ expect(err).to include("bundle lock --add-platform x86_64-linux")
+ end
+
it "does not resolve if the current platform does not match any of available platform specific variants for a transitive dependency" do
build_repo4 do
build_gem("sorbet", "0.5.6433") {|s| s.add_dependency "sorbet-static", "= 0.5.6433" }
@@ -581,7 +676,7 @@ RSpec.describe "bundle install with specific platforms" do
sorbet-static-and-runtime
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
bundle "update"
@@ -612,7 +707,7 @@ RSpec.describe "bundle install with specific platforms" do
sorbet-static-and-runtime
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
@@ -664,7 +759,7 @@ RSpec.describe "bundle install with specific platforms" do
sorbet-static
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
simulate_platform "x86_64-darwin-22" do
@@ -686,7 +781,7 @@ RSpec.describe "bundle install with specific platforms" do
sorbet-static
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
@@ -733,7 +828,7 @@ RSpec.describe "bundle install with specific platforms" do
sorbet-static-and-runtime
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
bundle "update"
@@ -764,7 +859,7 @@ RSpec.describe "bundle install with specific platforms" do
sorbet-static-and-runtime
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
@@ -808,7 +903,7 @@ RSpec.describe "bundle install with specific platforms" do
nokogiri
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
bundle "lock"
@@ -837,7 +932,7 @@ RSpec.describe "bundle install with specific platforms" do
sorbet
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
end
@@ -882,7 +977,7 @@ RSpec.describe "bundle install with specific platforms" do
sorbet-static
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
bundle "update"
@@ -907,7 +1002,7 @@ RSpec.describe "bundle install with specific platforms" do
sorbet-static
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
end
@@ -950,7 +1045,7 @@ RSpec.describe "bundle install with specific platforms" do
sorbet-static (= 0.5.10549)
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
bundle "install"
@@ -969,7 +1064,7 @@ RSpec.describe "bundle install with specific platforms" do
sorbet-static (= 0.5.10549)
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
end
@@ -1006,7 +1101,7 @@ RSpec.describe "bundle install with specific platforms" do
ibandit (~> 0.7.0)
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
bundle "lock --update i18n"
@@ -1026,7 +1121,7 @@ RSpec.describe "bundle install with specific platforms" do
ibandit (~> 0.7.0)
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
end
@@ -1067,7 +1162,7 @@ RSpec.describe "bundle install with specific platforms" do
tzinfo (~> 1.2)
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
lockfile original_lockfile
@@ -1111,7 +1206,7 @@ RSpec.describe "bundle install with specific platforms" do
tzinfo (~> 1.2)
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
lockfile original_lockfile
@@ -1154,7 +1249,7 @@ RSpec.describe "bundle install with specific platforms" do
concurrent-ruby
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
bundle "lock"
@@ -1174,7 +1269,7 @@ RSpec.describe "bundle install with specific platforms" do
myrack
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
@@ -1205,7 +1300,7 @@ RSpec.describe "bundle install with specific platforms" do
my-precompiled-gem
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
bundle :install
@@ -1250,7 +1345,7 @@ RSpec.describe "bundle install with specific platforms" do
nokogiri (= 1.14.0)
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
bundle :install
@@ -1274,7 +1369,7 @@ RSpec.describe "bundle install with specific platforms" do
nokogiri (= 1.14.0)
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
end
@@ -1308,7 +1403,7 @@ RSpec.describe "bundle install with specific platforms" do
DEPENDENCIES
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
bundle "lock"
@@ -1328,7 +1423,7 @@ RSpec.describe "bundle install with specific platforms" do
sorbet
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
end
@@ -1390,7 +1485,7 @@ RSpec.describe "bundle install with specific platforms" do
nokogiri
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
gemfile <<~G
@@ -1427,7 +1522,7 @@ RSpec.describe "bundle install with specific platforms" do
sorbet-static
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
end
@@ -1482,7 +1577,7 @@ RSpec.describe "bundle install with specific platforms" do
sass-embedded
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
end
@@ -1524,7 +1619,7 @@ RSpec.describe "bundle install with specific platforms" do
nokogiri
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
end
@@ -1571,7 +1666,7 @@ RSpec.describe "bundle install with specific platforms" do
rcee_precompiled (= 0.5.0)
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
end
@@ -1618,7 +1713,7 @@ RSpec.describe "bundle install with specific platforms" do
rcee_precompiled (= 0.5.0)
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
end
@@ -1656,7 +1751,7 @@ RSpec.describe "bundle install with specific platforms" do
rcee_precompiled (= 0.5.0)
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
end
@@ -1685,7 +1780,7 @@ RSpec.describe "bundle install with specific platforms" do
nokogiri!
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
simulate_platform "arm64-darwin-23" do
@@ -1728,7 +1823,7 @@ RSpec.describe "bundle install with specific platforms" do
nokogiri
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
lockfile original_lockfile
@@ -1779,7 +1874,7 @@ RSpec.describe "bundle install with specific platforms" do
nokogiri
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
lockfile original_lockfile
@@ -1821,7 +1916,7 @@ RSpec.describe "bundle install with specific platforms" do
google-protobuf (~> 3.0)
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
lockfile original_lockfile
diff --git a/spec/bundler/install/gemfile_spec.rb b/spec/bundler/install/gemfile_spec.rb
index 0e3b847767..83875a3d0e 100644
--- a/spec/bundler/install/gemfile_spec.rb
+++ b/spec/bundler/install/gemfile_spec.rb
@@ -27,6 +27,35 @@ RSpec.describe "bundle install" do
ENV["BUNDLE_GEMFILE"] = "NotGemfile"
expect(the_bundle).to include_gems "myrack 1.0.0"
end
+
+ it "respects lockfile and BUNDLE_LOCKFILE" do
+ gemfile bundled_app("NotGemfile"), <<-G
+ lockfile "ReallyNotGemfile.lock"
+ source "https://gem.repo1"
+ gem 'myrack'
+ G
+
+ bundle :install, gemfile: bundled_app("NotGemfile")
+
+ ENV["BUNDLE_GEMFILE"] = "NotGemfile"
+ ENV["BUNDLE_LOCKFILE"] = "ReallyNotGemfile.lock"
+ expect(the_bundle).to include_gems "myrack 1.0.0"
+ end
+
+ it "respects BUNDLE_LOCKFILE during bundle install" do
+ ENV["BUNDLE_LOCKFILE"] = "ReallyNotGemfile.lock"
+
+ gemfile bundled_app("NotGemfile"), <<-G
+ source "https://gem.repo1"
+ gem 'myrack'
+ G
+
+ bundle :install, gemfile: bundled_app("NotGemfile")
+ expect(bundled_app("ReallyNotGemfile.lock")).to exist
+
+ ENV["BUNDLE_GEMFILE"] = "NotGemfile"
+ expect(the_bundle).to include_gems "myrack 1.0.0"
+ end
end
context "with gemfile set via config" do
@@ -36,7 +65,7 @@ RSpec.describe "bundle install" do
gem 'myrack'
G
- bundle "config set --local gemfile #{bundled_app("NotGemfile")}"
+ bundle_config "gemfile #{bundled_app("NotGemfile")}"
end
it "uses the gemfile to install" do
bundle "install"
diff --git a/spec/bundler/install/gems/compact_index_spec.rb b/spec/bundler/install/gems/compact_index_spec.rb
index e5f7380855..9db73b84b5 100644
--- a/spec/bundler/install/gems/compact_index_spec.rb
+++ b/spec/bundler/install/gems/compact_index_spec.rb
@@ -95,7 +95,7 @@ RSpec.describe "compact index api" do
G
bundle :install, artifice: "compact_index"
- bundle "config set --local deployment true"
+ bundle_config "deployment true"
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"
@@ -132,7 +132,7 @@ RSpec.describe "compact index api" do
bundle :install, artifice: "compact_index"
- bundle "config set --local deployment true"
+ bundle_config "deployment true"
bundle :install, artifice: "compact_index"
expect(the_bundle).to include_gems("rails 2.3.2")
@@ -146,7 +146,7 @@ RSpec.describe "compact index api" do
G
bundle "install", artifice: "compact_index"
- bundle "config set --local deployment true"
+ bundle_config "deployment true"
bundle :install, artifice: "compact_index"
expect(the_bundle).to include_gems("foo 1.0")
@@ -302,7 +302,7 @@ RSpec.describe "compact index api" do
end
system_gems %w[myrack-1.0.0 thin-1.0 net_a-1.0], gem_repo: gem_repo2
- bundle "config set --local path.system true"
+ bundle_config "path.system true"
ENV["BUNDLER_SPEC_ALL_REQUESTS"] = <<~EOS.strip
#{source_uri}/versions
#{source_uri}/info/myrack
@@ -324,24 +324,6 @@ RSpec.describe "compact index api" do
FileUtils.rm_r Dir[gem_repo2("gems/foo-*.gem")]
end
- gemfile <<-G
- source "#{source_uri}"
- source "#{source_uri}/extra"
- gem "back_deps"
- G
-
- bundle :install, artifice: "compact_index_extra"
- expect(the_bundle).to include_gems "back_deps 1.0", "foo 1.0"
- end
-
- it "fetches again when more dependencies are found in subsequent sources with source blocks" do
- build_repo2 do
- build_gem "back_deps" do |s|
- s.add_dependency "foo"
- end
- FileUtils.rm_r Dir[gem_repo2("gems/foo-*.gem")]
- end
-
install_gemfile <<-G, artifice: "compact_index_extra", verbose: true
source "#{source_uri}"
source "#{source_uri}/extra" do
@@ -375,11 +357,13 @@ RSpec.describe "compact index api" do
expect(the_bundle).to include_gems "myrack 1.2"
end
- it "considers all possible versions of dependencies from all api gem sources" 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
- # repo and installs it.
+ it "resolves indirect dependencies to the most scoped source that includes them" 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 tries to
+ # use the version in the most scoped source, even if not compatible, and
+ # gives a resolution error
build_repo4 do
build_gem "activesupport", "1.2.0"
build_gem "somegem", "1.0.0" do |s|
@@ -389,14 +373,14 @@ RSpec.describe "compact index api" do
gemfile <<-G
source "#{source_uri}"
- source "#{source_uri}/extra"
- gem 'somegem', '1.0.0'
+ source "#{source_uri}/extra" do
+ gem 'somegem', '1.0.0'
+ end
G
- bundle :install, artifice: "compact_index_extra_api"
+ bundle :install, artifice: "compact_index_extra_api", raise_on_error: false
- expect(the_bundle).to include_gems "somegem 1.0.0"
- expect(the_bundle).to include_gems "activesupport 1.2.3"
+ expect(err).to include("Could not find compatible versions")
end
it "prints API output properly with back deps" do
@@ -481,33 +465,13 @@ RSpec.describe "compact index api" do
gemfile <<-G
source "#{source_uri}"
- source "#{source_uri}/extra"
- gem "back_deps"
- G
-
- bundle :install, artifice: "compact_index_extra"
- bundle "config --set local deployment true"
- bundle :install, artifice: "compact_index_extra"
- 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 with blocks" do
- build_repo2 do
- build_gem "back_deps" do |s|
- s.add_dependency "foo"
- end
- FileUtils.rm_r Dir[gem_repo2("gems/foo-*.gem")]
- end
-
- gemfile <<-G
- source "#{source_uri}"
source "#{source_uri}/extra" do
gem "back_deps"
end
G
bundle :install, artifice: "compact_index_extra"
- bundle "config set --local deployment true"
+ bundle_config "deployment true"
bundle :install, artifice: "compact_index_extra"
expect(the_bundle).to include_gems "back_deps 1.0"
end
@@ -529,40 +493,6 @@ RSpec.describe "compact index api" do
expect(out).to include("Fetching gem metadata from #{source_uri}")
end
- it "installs the binstubs" do
- gemfile <<-G
- source "#{source_uri}"
- gem "myrack"
- G
-
- bundle "install --binstubs", artifice: "compact_index"
-
- gembin "myrackup"
- expect(out).to eq("1.0.0")
- end
-
- it "installs the bins when using --path and uses autoclean" do
- gemfile <<-G
- source "#{source_uri}"
- gem "myrack"
- G
-
- bundle "install --path vendor/bundle", artifice: "compact_index"
-
- expect(vendored_gems("bin/myrackup")).to exist
- end
-
- it "installs the bins when using --path and uses bundle clean" do
- gemfile <<-G
- source "#{source_uri}"
- gem "myrack"
- G
-
- bundle "install --path vendor/bundle --no-clean", artifice: "compact_index"
-
- expect(vendored_gems("bin/myrackup")).to exist
- end
-
it "prints post_install_messages" do
gemfile <<-G
source "#{source_uri}"
@@ -617,19 +547,6 @@ RSpec.describe "compact index api" do
expect(the_bundle).to include_gems "myrack 1.0.0"
end
- it "strips http basic auth creds when warning about ambiguous sources" do
- gemfile <<-G
- source "#{basic_auth_source_uri}"
- source "#{file_uri_for(gem_repo1)}"
- gem "myrack"
- G
-
- bundle :install, artifice: "compact_index_basic_authentication"
- expect(err).to include("Warning: the gem 'myrack' was found in multiple sources.")
- expect(err).not_to include("#{user}:#{password}")
- expect(the_bundle).to include_gems "myrack 1.0.0"
- end
-
it "does not pass the user / password to different hosts on redirect" do
gemfile <<-G
source "#{basic_auth_source_uri}"
@@ -781,7 +698,7 @@ RSpec.describe "compact index api" do
bundle :install, artifice: "compact_index_forbidden"
ensure
- home(".gemrc").rmtree
+ FileUtils.rm_rf home(".gemrc")
end
end
end
@@ -853,7 +770,7 @@ RSpec.describe "compact index api" do
gem 'myrack', '0.9.1'
G
- update_repo4 do
+ build_repo4 do
build_gem "myrack", "1.0.0"
end
@@ -894,7 +811,7 @@ RSpec.describe "compact index api" do
gem 'myrack', '0.9.1'
G
- update_repo4 do
+ build_repo4 do
build_gem "myrack", "1.0.0"
end
@@ -916,7 +833,7 @@ RSpec.describe "compact index api" do
gem 'myrack', '0.9.1'
G
- update_repo4 do
+ build_repo4 do
build_gem "myrack", "1.0.0"
end
@@ -988,7 +905,7 @@ RSpec.describe "compact index api" do
DEPENDENCIES
#{checksums_section}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
@@ -1039,7 +956,7 @@ RSpec.describe "compact index api" do
end
it "does not raise when disable_checksum_validation is set" do
- bundle "config set disable_checksum_validation true"
+ bundle_config "disable_checksum_validation true"
install_gemfile <<-G, artifice: "compact_index_wrong_gem_checksum"
source "#{source_uri}"
gem "myrack"
@@ -1080,7 +997,7 @@ Running `bundle update rails` should fix the problem.
gem "activemerchant"
end
G
- gem_command "uninstall activemerchant"
+ uninstall_gem("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)
diff --git a/spec/bundler/install/gems/dependency_api_fallback_spec.rb b/spec/bundler/install/gems/dependency_api_fallback_spec.rb
index 7890cbdb99..c7b0c537e4 100644
--- a/spec/bundler/install/gems/dependency_api_fallback_spec.rb
+++ b/spec/bundler/install/gems/dependency_api_fallback_spec.rb
@@ -3,7 +3,7 @@
RSpec.describe "gemcutter's dependency API" do
context "when Gemcutter API takes too long to respond" do
before do
- bundle "config set timeout 1"
+ bundle_config "timeout 1"
end
it "times out and falls back on the modern index" do
diff --git a/spec/bundler/install/gems/dependency_api_spec.rb b/spec/bundler/install/gems/dependency_api_spec.rb
index b7953b3d61..32a1b98b6d 100644
--- a/spec/bundler/install/gems/dependency_api_spec.rb
+++ b/spec/bundler/install/gems/dependency_api_spec.rb
@@ -60,7 +60,7 @@ RSpec.describe "gemcutter's dependency API" do
G
bundle :install, artifice: "endpoint"
- bundle "config set --local deployment true"
+ bundle_config "deployment true"
bundle :install, artifice: "endpoint"
expect(out).to include("Fetching gem metadata from #{source_uri}")
expect(the_bundle).to include_gems "myrack 1.0.0"
@@ -97,7 +97,7 @@ RSpec.describe "gemcutter's dependency API" do
bundle :install, artifice: "endpoint"
- bundle "config set --local deployment true"
+ bundle_config "deployment true"
bundle :install, artifice: "endpoint"
expect(the_bundle).to include_gems("rails 2.3.2")
@@ -111,7 +111,7 @@ RSpec.describe "gemcutter's dependency API" do
G
bundle "install", artifice: "endpoint"
- bundle "config set --local deployment true"
+ bundle_config "deployment true"
bundle :install, artifice: "endpoint"
expect(the_bundle).to include_gems("foo 1.0")
@@ -264,24 +264,6 @@ RSpec.describe "gemcutter's dependency API" do
gemfile <<-G
source "#{source_uri}"
- source "#{source_uri}/extra"
- gem "back_deps"
- G
-
- bundle :install, artifice: "endpoint_extra"
- expect(the_bundle).to include_gems "back_deps 1.0", "foo 1.0"
- end
-
- it "fetches again when more dependencies are found in subsequent sources using blocks" do
- build_repo2 do
- build_gem "back_deps" do |s|
- s.add_dependency "foo"
- end
- FileUtils.rm_r Dir[gem_repo2("gems/foo-*.gem")]
- end
-
- gemfile <<-G
- source "#{source_uri}"
source "#{source_uri}/extra" do
gem "back_deps"
end
@@ -313,11 +295,13 @@ RSpec.describe "gemcutter's dependency API" do
expect(the_bundle).to include_gems "myrack 1.2"
end
- it "considers all possible versions of dependencies from all api gem sources" 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
- # repo and installs it.
+ it "resolves indirect dependencies to the most scoped source that includes them" 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 tries to
+ # use the version in the most scoped source, even if not compatible, and
+ # gives a resolution error
build_repo4 do
build_gem "activesupport", "1.2.0"
build_gem "somegem", "1.0.0" do |s|
@@ -327,14 +311,14 @@ RSpec.describe "gemcutter's dependency API" do
gemfile <<-G
source "#{source_uri}"
- source "#{source_uri}/extra"
- gem 'somegem', '1.0.0'
+ source "#{source_uri}/extra" do
+ gem 'somegem', '1.0.0'
+ end
G
- bundle :install, artifice: "endpoint_extra_api"
+ bundle :install, artifice: "compact_index_extra_api", raise_on_error: false
- expect(the_bundle).to include_gems "somegem 1.0.0"
- expect(the_bundle).to include_gems "activesupport 1.2.3"
+ expect(err).to include("Could not find compatible versions")
end
it "prints API output properly with back deps" do
@@ -370,25 +354,6 @@ RSpec.describe "gemcutter's dependency API" do
install_gemfile <<-G, artifice: "endpoint_extra_missing"
source "#{source_uri}"
- source "#{source_uri}/extra"
- gem "back_deps"
- G
-
- expect(the_bundle).to include_gems "back_deps 1.0"
- end
-
- it "does not fetch every spec when doing back deps using blocks" do
- build_repo2 do
- build_gem "back_deps" do |s|
- s.add_dependency "foo"
- end
- build_gem "missing"
-
- FileUtils.rm_r Dir[gem_repo2("gems/foo-*.gem")]
- end
-
- install_gemfile <<-G, artifice: "endpoint_extra_missing"
- source "#{source_uri}"
source "#{source_uri}/extra" do
gem "back_deps"
end
@@ -407,33 +372,13 @@ RSpec.describe "gemcutter's dependency API" do
gemfile <<-G
source "#{source_uri}"
- source "#{source_uri}/extra"
- gem "back_deps"
- G
-
- bundle :install, artifice: "endpoint_extra"
- bundle "config set --local deployment true"
- bundle :install, artifice: "endpoint_extra"
- 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 with blocks" do
- build_repo2 do
- build_gem "back_deps" do |s|
- s.add_dependency "foo"
- end
- FileUtils.rm_r Dir[gem_repo2("gems/foo-*.gem")]
- end
-
- gemfile <<-G
- source "#{source_uri}"
source "#{source_uri}/extra" do
gem "back_deps"
end
G
bundle :install, artifice: "endpoint_extra"
- bundle "config set --local deployment true"
+ bundle_config "deployment true"
bundle "install", artifice: "endpoint_extra"
expect(the_bundle).to include_gems "back_deps 1.0"
end
@@ -471,40 +416,6 @@ RSpec.describe "gemcutter's dependency API" do
expect(out).to include("Fetching gem metadata from #{source_uri}")
end
- it "installs the binstubs" do
- gemfile <<-G
- source "#{source_uri}"
- gem "myrack"
- G
-
- bundle "install --binstubs", artifice: "endpoint"
-
- gembin "myrackup"
- expect(out).to eq("1.0.0")
- end
-
- it "installs the bins when using --path and uses autoclean" do
- gemfile <<-G
- source "#{source_uri}"
- gem "myrack"
- G
-
- bundle "install --path vendor/bundle", artifice: "endpoint"
-
- expect(vendored_gems("bin/myrackup")).to exist
- end
-
- it "installs the bins when using --path and uses bundle clean" do
- gemfile <<-G
- source "#{source_uri}"
- gem "myrack"
- G
-
- bundle "install --path vendor/bundle --no-clean", artifice: "endpoint"
-
- expect(vendored_gems("bin/myrackup")).to exist
- end
-
it "prints post_install_messages" do
gemfile <<-G
source "#{source_uri}"
@@ -580,19 +491,6 @@ RSpec.describe "gemcutter's dependency API" do
expect(out).not_to include("#{user}:#{password}")
end
- it "strips http basic auth creds when warning about ambiguous sources" do
- gemfile <<-G
- source "#{basic_auth_source_uri}"
- source "#{file_uri_for(gem_repo1)}"
- gem "myrack"
- G
-
- bundle :install, artifice: "endpoint_basic_authentication"
- expect(err).to include("Warning: the gem 'myrack' was found in multiple sources.")
- expect(err).not_to include("#{user}:#{password}")
- expect(the_bundle).to include_gems "myrack 1.0.0"
- end
-
it "does not pass the user / password to different hosts on redirect" do
gemfile <<-G
source "#{basic_auth_source_uri}"
@@ -751,7 +649,7 @@ RSpec.describe "gemcutter's dependency API" do
bundle "install", artifice: "endpoint_marshal_fail"
ensure
- home(".gemrc").rmtree
+ FileUtils.rm_rf home(".gemrc")
end
end
end
diff --git a/spec/bundler/install/gems/flex_spec.rb b/spec/bundler/install/gems/flex_spec.rb
index 522ee6b779..a30b53d6ad 100644
--- a/spec/bundler/install/gems/flex_spec.rb
+++ b/spec/bundler/install/gems/flex_spec.rb
@@ -191,7 +191,7 @@ RSpec.describe "bundle flex_install" do
end
it "discards the locked gems when the Gemfile requires different versions than the lock" do
- bundle "config set force_ruby_platform true"
+ bundle_config "force_ruby_platform true"
nice_error = <<~E.strip
Could not find compatible versions
@@ -208,7 +208,7 @@ RSpec.describe "bundle flex_install" do
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"
+ bundle_config "force_ruby_platform true"
bad_error = <<~E.strip
Bundler could not find compatible versions for gem "myrack-obama":
@@ -289,7 +289,7 @@ RSpec.describe "bundle flex_install" do
myrack-obama
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
@@ -317,7 +317,7 @@ RSpec.describe "bundle flex_install" do
myrack-obama
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
end
@@ -358,7 +358,7 @@ RSpec.describe "bundle flex_install" do
myrack
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
end
diff --git a/spec/bundler/install/gems/fund_spec.rb b/spec/bundler/install/gems/fund_spec.rb
index 0855a62b86..8a3a51270a 100644
--- a/spec/bundler/install/gems/fund_spec.rb
+++ b/spec/bundler/install/gems/fund_spec.rb
@@ -54,7 +54,7 @@ RSpec.describe "bundle install" do
context "when gems include a fund URI but `ignore_funding_requests` is configured" do
before do
- bundle "config set ignore_funding_requests true"
+ bundle_config "ignore_funding_requests true"
end
it "does not display the plural fund message after installing" do
diff --git a/spec/bundler/install/gems/gemfile_source_header_spec.rb b/spec/bundler/install/gems/gemfile_source_header_spec.rb
index 9e63fa7551..dc35c8d741 100644
--- a/spec/bundler/install/gems/gemfile_source_header_spec.rb
+++ b/spec/bundler/install/gems/gemfile_source_header_spec.rb
@@ -11,7 +11,7 @@ RSpec.describe "fetching dependencies with a mirrored source" do
gem 'weakling'
G
- bundle "config set --local mirror.#{mirror} https://gem.repo2"
+ bundle_config "mirror.#{mirror} https://gem.repo2"
end
it "sets the 'X-Gemfile-Source' and 'User-Agent' headers and bundles successfully" do
diff --git a/spec/bundler/install/gems/mirror_probe_spec.rb b/spec/bundler/install/gems/mirror_probe_spec.rb
index 436f116cac..564062ccf6 100644
--- a/spec/bundler/install/gems/mirror_probe_spec.rb
+++ b/spec/bundler/install/gems/mirror_probe_spec.rb
@@ -12,8 +12,8 @@ RSpec.describe "fetching dependencies with a not available mirror" do
context "with a specific fallback timeout" do
before do
- global_config("BUNDLE_MIRROR__HTTPS://GEM__REPO2/__FALLBACK_TIMEOUT/" => "true",
- "BUNDLE_MIRROR__HTTPS://GEM__REPO2/" => "https://gem.mirror")
+ bundle_config_global("BUNDLE_MIRROR__HTTPS://GEM__REPO2/__FALLBACK_TIMEOUT/" => "true",
+ "BUNDLE_MIRROR__HTTPS://GEM__REPO2/" => "https://gem.mirror")
end
it "install a gem using the original uri when the mirror is not responding" do
@@ -27,8 +27,8 @@ RSpec.describe "fetching dependencies with a not available mirror" do
context "with a global fallback timeout" do
before do
- global_config("BUNDLE_MIRROR__ALL__FALLBACK_TIMEOUT/" => "1",
- "BUNDLE_MIRROR__ALL" => "https://gem.mirror")
+ bundle_config_global("BUNDLE_MIRROR__ALL__FALLBACK_TIMEOUT/" => "1",
+ "BUNDLE_MIRROR__ALL" => "https://gem.mirror")
end
it "install a gem using the original uri when the mirror is not responding" do
@@ -42,7 +42,7 @@ RSpec.describe "fetching dependencies with a not available mirror" do
context "with a specific mirror without a fallback timeout" do
before do
- global_config("BUNDLE_MIRROR__HTTPS://GEM__REPO2/" => "https://gem.mirror")
+ bundle_config_global("BUNDLE_MIRROR__HTTPS://GEM__REPO2/" => "https://gem.mirror")
end
it "fails to install the gem with a timeout error when the mirror is not responding" do
@@ -55,7 +55,7 @@ RSpec.describe "fetching dependencies with a not available mirror" do
context "with a global mirror without a fallback timeout" do
before do
- global_config("BUNDLE_MIRROR__ALL" => "https://gem.mirror")
+ bundle_config_global("BUNDLE_MIRROR__ALL" => "https://gem.mirror")
end
it "fails to install the gem with a timeout error when the mirror is not responding" do
diff --git a/spec/bundler/install/gems/mirror_spec.rb b/spec/bundler/install/gems/mirror_spec.rb
index 70c0da50ef..e1fbeac454 100644
--- a/spec/bundler/install/gems/mirror_spec.rb
+++ b/spec/bundler/install/gems/mirror_spec.rb
@@ -8,7 +8,7 @@ RSpec.describe "bundle install with a mirror configured" do
gem "myrack"
G
- bundle "config set --local mirror.http://gems.example.org http://gem-mirror.example.org"
+ bundle_config "mirror.http://gems.example.org http://gem-mirror.example.org"
end
it "installs from the normal location" do
@@ -26,7 +26,7 @@ RSpec.describe "bundle install with a mirror configured" do
gem "myrack"
G
- bundle "config set --local mirror.https://gem.repo2 https://gem.repo1"
+ bundle_config "mirror.https://gem.repo2 https://gem.repo1"
end
it "installs the gem from the mirror" do
diff --git a/spec/bundler/install/gems/native_extensions_spec.rb b/spec/bundler/install/gems/native_extensions_spec.rb
index 874818fa87..d5b10d2c8f 100644
--- a/spec/bundler/install/gems/native_extensions_spec.rb
+++ b/spec/bundler/install/gems/native_extensions_spec.rb
@@ -9,7 +9,7 @@ RSpec.describe "installing a gem with native extensions" do
require "mkmf"
name = "c_extension_bundle"
dir_config(name)
- raise "OMG" unless with_config("c_extension") == "hello"
+ raise ArgumentError unless with_config("c_extension") == "hello"
create_makefile(name)
E
@@ -37,7 +37,7 @@ RSpec.describe "installing a gem with native extensions" do
gem "c_extension"
G
- bundle "config set build.c_extension --with-c_extension=hello"
+ bundle_config "build.c_extension --with-c_extension=hello"
bundle "install"
expect(out).to include("Installing c_extension 1.0 with native extensions")
@@ -53,7 +53,7 @@ RSpec.describe "installing a gem with native extensions" do
require "mkmf"
name = "c_extension_bundle"
dir_config(name)
- raise "OMG" unless with_config("c_extension") == "hello"
+ raise ArgumentError unless with_config("c_extension") == "hello"
create_makefile(name)
E
@@ -75,7 +75,7 @@ RSpec.describe "installing a gem with native extensions" do
C
end
- bundle "config set build.c_extension --with-c_extension=hello"
+ bundle_config "build.c_extension --with-c_extension=hello"
install_gemfile <<-G
source "https://gem.repo1"
@@ -97,7 +97,7 @@ RSpec.describe "installing a gem with native extensions" do
require "mkmf"
name = "c_extension_bundle_#{n}"
dir_config(name)
- raise "OMG" unless with_config("c_extension_#{n}") == "#{n}"
+ raise ArgumentError unless with_config("c_extension_#{n}") == "#{n}"
create_makefile(name)
E
@@ -122,8 +122,8 @@ RSpec.describe "installing a gem with native extensions" do
build_git "gems", path: lib_path("gems"), gemspec: false
end
- bundle "config set build.c_extension_one --with-c_extension_one=one"
- bundle "config set build.c_extension_two --with-c_extension_two=two"
+ bundle_config "build.c_extension_one --with-c_extension_one=one"
+ bundle_config "build.c_extension_two --with-c_extension_two=two"
# 1st time, require only one gem -- only one of the extensions gets built.
install_gemfile <<-G
@@ -149,7 +149,7 @@ RSpec.describe "installing a gem with native extensions" do
require "mkmf"
name = "c_extension_bundle"
dir_config(name)
- raise "OMG" unless with_config("c_extension") == "hello" && with_config("c_extension_bundle-dir") == "hola"
+ raise ArgumentError unless with_config("c_extension") == "hello" && with_config("c_extension_bundle-dir") == "hola"
create_makefile(name)
E
@@ -171,7 +171,7 @@ RSpec.describe "installing a gem with native extensions" do
C
end
- bundle "config set build.c_extension --with-c_extension=hello --with-c_extension_bundle-dir=hola"
+ bundle_config "build.c_extension --with-c_extension=hello --with-c_extension_bundle-dir=hola"
install_gemfile <<-G
source "https://gem.repo1"
diff --git a/spec/bundler/install/gems/no_build_extension_spec.rb b/spec/bundler/install/gems/no_build_extension_spec.rb
new file mode 100644
index 0000000000..31f0170433
--- /dev/null
+++ b/spec/bundler/install/gems/no_build_extension_spec.rb
@@ -0,0 +1,54 @@
+# frozen_string_literal: true
+
+RSpec.describe "bundle install with --no-build-extension" do
+ before do
+ build_repo2 do
+ build_gem "with_extension" do |s|
+ s.extensions << "Rakefile"
+ s.write "Rakefile", <<-RUBY
+ task :default do
+ path = File.expand_path("lib", __dir__)
+ FileUtils.mkdir_p(path)
+ File.open("\#{path}/with_extension.rb", "w") do |f|
+ f.puts "WITH_EXTENSION = 'YES'"
+ end
+ end
+ RUBY
+ end
+ end
+ end
+
+ it "skips building native extensions and warns when no_build_extension is set" do
+ bundle_config "no_build_extension true"
+
+ gemfile <<-G
+ source "https://gem.repo2"
+ gem "with_extension"
+ gem "rake"
+ G
+
+ bundle :install
+
+ build_complete = default_bundle_path("extensions").join(
+ Gem::Platform.local.to_s,
+ Gem.extension_api_version.to_s,
+ "with_extension-1.0",
+ "gem.build_complete"
+ )
+ expect(build_complete).not_to exist
+ expect(err).to include("with_extension-1.0 contains native extensions that were not built")
+ expect(err).to include("unset no_build_extension and run `bundle pristine with_extension`")
+ end
+
+ it "builds native extensions by default" do
+ gemfile <<-G
+ source "https://gem.repo2"
+ gem "with_extension"
+ gem "rake"
+ G
+
+ bundle :install
+
+ expect(out).to include("Installing with_extension 1.0 with native extensions")
+ end
+end
diff --git a/spec/bundler/install/gems/no_install_plugin_spec.rb b/spec/bundler/install/gems/no_install_plugin_spec.rb
new file mode 100644
index 0000000000..e040e6b813
--- /dev/null
+++ b/spec/bundler/install/gems/no_install_plugin_spec.rb
@@ -0,0 +1,53 @@
+# frozen_string_literal: true
+
+RSpec.describe "bundle install with --no-install-plugin" do
+ before do
+ build_repo2 do
+ build_gem "with_plugin", "1.0" do |s|
+ s.write "lib/rubygems_plugin.rb", "# plugin code"
+ end
+
+ build_gem "with_plugin", "2.0"
+ end
+ end
+
+ let(:plugin_path) { default_bundle_path("plugins", "with_plugin_plugin.rb") }
+
+ it "does not generate the plugin wrapper and warns when no_install_plugin is set" do
+ bundle_config "no_install_plugin true"
+
+ install_gemfile <<-G
+ source "https://gem.repo2"
+ gem "with_plugin", "1.0"
+ G
+
+ expect(plugin_path).not_to exist
+ expect(err).to include("with_plugin-1.0 contains plugins that were not installed")
+ expect(err).to include("unset no_install_plugin and run `bundle pristine with_plugin`")
+ end
+
+ it "removes a stale plugin wrapper from a prior version when no_install_plugin is set" do
+ install_gemfile <<-G
+ source "https://gem.repo2"
+ gem "with_plugin", "1.0"
+ G
+ expect(plugin_path).to exist
+
+ bundle_config "no_install_plugin true"
+ install_gemfile <<-G
+ source "https://gem.repo2"
+ gem "with_plugin", "2.0"
+ G
+
+ expect(plugin_path).not_to exist
+ end
+
+ it "generates the plugin wrapper by default" do
+ install_gemfile <<-G
+ source "https://gem.repo2"
+ gem "with_plugin", "1.0"
+ G
+
+ expect(plugin_path).to exist
+ end
+end
diff --git a/spec/bundler/install/gems/post_install_spec.rb b/spec/bundler/install/gems/post_install_spec.rb
index af753dba3e..e49fd2a9a3 100644
--- a/spec/bundler/install/gems/post_install_spec.rb
+++ b/spec/bundler/install/gems/post_install_spec.rb
@@ -127,7 +127,7 @@ RSpec.describe "bundle install" do
gem "myrack"
G
- bundle "config set ignore_messages.myrack true"
+ bundle_config "ignore_messages.myrack true"
bundle :install
expect(out).not_to include("Post-install message")
@@ -141,7 +141,7 @@ RSpec.describe "bundle install" do
gem "myrack"
G
- bundle "config set ignore_messages true"
+ bundle_config "ignore_messages true"
bundle :install
expect(out).not_to include("Post-install message")
diff --git a/spec/bundler/install/gems/resolving_spec.rb b/spec/bundler/install/gems/resolving_spec.rb
index 21e4a12107..111d361aab 100644
--- a/spec/bundler/install/gems/resolving_spec.rb
+++ b/spec/bundler/install/gems/resolving_spec.rb
@@ -275,7 +275,7 @@ RSpec.describe "bundle install with install-time dependencies" do
parallel_tests
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
@@ -299,7 +299,7 @@ RSpec.describe "bundle install with install-time dependencies" do
parallel_tests
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
@@ -358,10 +358,10 @@ RSpec.describe "bundle install with install-time dependencies" do
#{lockfile_platforms}
DEPENDENCIES
- parallel_tests
+ rubocop
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
@@ -388,7 +388,7 @@ RSpec.describe "bundle install with install-time dependencies" do
rubocop
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
end
@@ -425,7 +425,7 @@ RSpec.describe "bundle install with install-time dependencies" do
sorbet (= 0.5.10554)
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
@@ -440,7 +440,9 @@ RSpec.describe "bundle install with install-time dependencies" do
The source contains the following gems matching 'sorbet-static (= 0.5.10554)':
* sorbet-static-0.5.10554-universal-darwin-21
E
- expect(err).to end_with(nice_error)
+ expect(err).to include(nice_error)
+ expect(err).to include("Your current platform (aarch64-linux) is not included in the lockfile's platforms (arm64-darwin-21)")
+ expect(err).to include("bundle lock --add-platform aarch64-linux")
end
end
@@ -475,7 +477,7 @@ RSpec.describe "bundle install with install-time dependencies" do
nokogiri
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
gemfile <<~G
@@ -517,7 +519,7 @@ RSpec.describe "bundle install with install-time dependencies" do
nokogiri
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
@@ -776,7 +778,7 @@ RSpec.describe "bundle install with install-time dependencies" do
foo
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
end
diff --git a/spec/bundler/install/gems/standalone_spec.rb b/spec/bundler/install/gems/standalone_spec.rb
index d9c2225479..96a305bb76 100644
--- a/spec/bundler/install/gems/standalone_spec.rb
+++ b/spec/bundler/install/gems/standalone_spec.rb
@@ -125,7 +125,7 @@ RSpec.describe "bundle install --standalone" do
source "https://gem.repo1"
gem "rails"
G
- bundle "config set --local path #{bundled_app("bundle")}"
+ bundle_config "path #{bundled_app("bundle")}"
bundle :install, standalone: true, dir: cwd
end
@@ -164,7 +164,7 @@ RSpec.describe "bundle install --standalone" do
bundle "lock", dir: cwd
- bundle "config set --local path #{bundled_app("bundle")}"
+ bundle_config "path #{bundled_app("bundle")}"
bundle :install, standalone: true, dir: cwd, env: { "BUNDLER_GEM_DEFAULT_DIR" => system_gem_path.to_s }
@@ -191,7 +191,7 @@ RSpec.describe "bundle install --standalone" do
gem "baz"
G
- bundle "config set --local path #{bundled_app("bundle")}"
+ bundle_config "path #{bundled_app("bundle")}"
bundle "lock", dir: cwd
@@ -270,7 +270,7 @@ RSpec.describe "bundle install --standalone" do
describe "with gems with native extension" do
before do
- bundle "config set --local path #{bundled_app("bundle")}"
+ bundle_config "path #{bundled_app("bundle")}"
install_gemfile <<-G, standalone: true, dir: cwd
source "https://gem.repo1"
gem "very_simple_binary"
@@ -308,7 +308,7 @@ RSpec.describe "bundle install --standalone" do
end
G
end
- bundle "config set --local path #{bundled_app("bundle")}"
+ bundle_config "path #{bundled_app("bundle")}"
install_gemfile <<-G, standalone: true, dir: cwd, raise_on_error: false
source "https://gem.repo1"
gem "bar", :git => "#{lib_path("bar-1.0")}"
@@ -330,7 +330,7 @@ RSpec.describe "bundle install --standalone" do
gem "rails"
gem "devise", :git => "#{lib_path("devise-1.0")}"
G
- bundle "config set --local path #{bundled_app("bundle")}"
+ bundle_config "path #{bundled_app("bundle")}"
bundle :install, standalone: true, dir: cwd
end
@@ -358,7 +358,7 @@ RSpec.describe "bundle install --standalone" do
gem "myrack-test"
end
G
- bundle "config set --local path #{bundled_app("bundle")}"
+ bundle_config "path #{bundled_app("bundle")}"
bundle :install, standalone: true, dir: cwd
end
@@ -372,7 +372,7 @@ RSpec.describe "bundle install --standalone" do
include_examples "common functionality"
it "allows creating a standalone file with limited groups" do
- bundle "config set --local path #{bundled_app("bundle")}"
+ bundle_config "path #{bundled_app("bundle")}"
bundle :install, standalone: "default", dir: cwd
load_error_ruby <<-RUBY, "spec"
@@ -385,12 +385,12 @@ RSpec.describe "bundle install --standalone" do
RUBY
expect(out).to eq("2.3.2")
- expect(err).to eq("ZOMG LOAD ERROR")
+ expect(err_without_deprecations).to match(/cannot load such file -- spec/)
end
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_config "path #{bundled_app("bundle")}"
+ bundle_config "without test"
bundle :install, standalone: true, dir: cwd
load_error_ruby <<-RUBY, "spec"
@@ -403,11 +403,11 @@ RSpec.describe "bundle install --standalone" do
RUBY
expect(out).to eq("2.3.2")
- expect(err).to eq("ZOMG LOAD ERROR")
+ expect(err_without_deprecations).to match(/cannot load such file -- spec/)
end
it "allows `path` configuration to change the location of the standalone bundle" do
- bundle "config set --local path path/to/bundle"
+ bundle_config "path path/to/bundle"
bundle "install", standalone: true, dir: cwd
ruby <<-RUBY
@@ -422,9 +422,9 @@ RSpec.describe "bundle install --standalone" do
end
it "allows `without` to limit the groups used in a standalone" do
- bundle "config set --local without test"
+ bundle_config "without test"
bundle :install, dir: cwd
- bundle "config set --local path #{bundled_app("bundle")}"
+ bundle_config "path #{bundled_app("bundle")}"
bundle :install, standalone: true, dir: cwd
load_error_ruby <<-RUBY, "spec"
@@ -437,7 +437,7 @@ RSpec.describe "bundle install --standalone" do
RUBY
expect(out).to eq("2.3.2")
- expect(err).to eq("ZOMG LOAD ERROR")
+ expect(err_without_deprecations).to match(/cannot load such file -- spec/)
end
end
@@ -450,7 +450,7 @@ RSpec.describe "bundle install --standalone" do
source "#{source_uri}"
gem "rails"
G
- bundle "config set --local path #{bundled_app("bundle")}"
+ bundle_config "path #{bundled_app("bundle")}"
bundle :install, standalone: true, artifice: "endpoint", dir: cwd
end
@@ -464,53 +464,6 @@ RSpec.describe "bundle install --standalone" do
include_examples "common functionality"
end
end
-
- describe "with --binstubs" do
- before do
- gemfile <<-G
- source "https://gem.repo1"
- gem "rails"
- G
- bundle "config set --local path #{bundled_app("bundle")}"
- bundle :install, standalone: true, binstubs: true, dir: cwd
- end
-
- let(:expected_gems) do
- {
- "actionpack" => "2.3.2",
- "rails" => "2.3.2",
- }
- end
-
- include_examples "common functionality"
-
- it "creates stubs that use the standalone load path" do
- expect(in_bundled_app("bin/rails -v").chomp).to eql "2.3.2"
- end
-
- it "creates stubs that can be executed from anywhere" do
- require "tmpdir"
- sys_exec(%(#{bundled_app("bin/rails")} -v), dir: Dir.tmpdir)
- expect(out).to eq("2.3.2")
- end
-
- it "creates stubs that can be symlinked" do
- skip "symlinks unsupported" if Gem.win_platform?
-
- symlink_dir = tmp("symlink")
- FileUtils.mkdir_p(symlink_dir)
- symlink = File.join(symlink_dir, "rails")
-
- File.symlink(bundled_app("bin/rails"), symlink)
- sys_exec("#{symlink} -v")
- expect(out).to eq("2.3.2")
- end
-
- it "creates stubs with the correct load path" do
- extension_line = File.read(bundled_app("bin/rails")).each_line.find {|line| line.include? "$:.unshift" }.strip
- expect(extension_line).to eq %($:.unshift File.expand_path "../bundle", __dir__)
- end
- end
end
RSpec.describe "bundle install --standalone run in a subdirectory" do
@@ -531,7 +484,7 @@ RSpec.describe "bundle install --standalone run in a subdirectory" do
context "when path set to a relative path" do
before do
- bundle "config set --local path bundle"
+ bundle_config "path bundle"
end
it "generates the script in the proper place" do
@@ -566,6 +519,6 @@ RSpec.describe "bundle install --standalone --local" do
RUBY
expect(out).to eq("1.0.0")
- expect(err).to eq("ZOMG LOAD ERROR")
+ expect(err_without_deprecations).to match(/cannot load such file -- spec/)
end
end
diff --git a/spec/bundler/install/gemspecs_spec.rb b/spec/bundler/install/gemspecs_spec.rb
index dee8e547e4..fb2271c830 100644
--- a/spec/bundler/install/gemspecs_spec.rb
+++ b/spec/bundler/install/gemspecs_spec.rb
@@ -122,7 +122,7 @@ RSpec.describe "bundle install" do
expect(the_bundle).to include_gems "foo 1.0"
end
- it "fails and complains about patchlevel on patchlevel mismatch",
+ it "installs gems ignoring the mismatch even when patchlevel is mismatch",
if: RUBY_PATCHLEVEL >= 0 do
patchlevel = RUBY_PATCHLEVEL.to_i + 1
build_lib("foo", path: bundled_app) do |s|
@@ -135,9 +135,7 @@ RSpec.describe "bundle install" do
gemspec
G
- expect(err).to include("Ruby patchlevel")
- expect(err).to include("but your Gemfile specified")
- expect(exitstatus).to eq(18)
+ expect(the_bundle).to include_gems "foo 1.0"
end
it "fails and complains about version on version mismatch" do
diff --git a/spec/bundler/install/git_spec.rb b/spec/bundler/install/git_spec.rb
index f9d96e488f..1172d661ae 100644
--- a/spec/bundler/install/git_spec.rb
+++ b/spec/bundler/install/git_spec.rb
@@ -85,8 +85,8 @@ RSpec.describe "bundle install" do
foo!
L
- bundle "config set --local path vendor/bundle"
- bundle "config set --local without development"
+ bundle_config "path vendor/bundle"
+ bundle_config "without development"
bundle :install
expect(out).to include("Bundle complete!")
@@ -157,7 +157,7 @@ RSpec.describe "bundle install" do
test!
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
# If GH#6743 is present, the first `bundle install` will change the
@@ -188,8 +188,8 @@ RSpec.describe "bundle install" 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"
+ bundle_config "path vendor/bundle"
+ bundle_config "clean true"
install_gemfile <<-G, verbose: true
source "https://gem.repo1"
gem "foo", :git => "#{lib_path("foo")}"
@@ -290,4 +290,80 @@ RSpec.describe "bundle install" do
end
end
end
+
+ describe "with excluded groups" do
+ it "works if you exclude a group with a git gem", ruby: ">= 3.3" do
+ build_git "production_gem", "1.0"
+ build_git "development_gem", "1.0"
+
+ gemfile <<-G
+ source "https://gem.repo1"
+
+ gem "production_gem", :git => "#{lib_path("production_gem-1.0")}"
+
+ group :development do
+ gem "development_gem", :git => "#{lib_path("development_gem-1.0")}"
+ end
+ G
+
+ # First install all groups to create lockfile
+ bundle :install
+
+ # Set without and reinstall
+ bundle_config "without development"
+ bundle :install
+
+ # Verify only production gem is available
+ expect(the_bundle).to include_gems("production_gem 1.0")
+ expect(the_bundle).not_to include_gems("development_gem 1.0")
+ end
+
+ it "resolves indirect dependencies from a git source not in the requested groups" do
+ build_lib "activesupport", "1.0", path: lib_path("rails/activesupport")
+ build_git "activerecord", "1.0", path: lib_path("rails") do |s|
+ s.add_dependency "activesupport", "= 1.0"
+ end
+
+ gemfile <<-G
+ source "https://gem.repo1"
+
+ gem "activerecord", :git => "#{lib_path("rails")}"
+
+ group :ci do
+ gem "myrack"
+ end
+ G
+
+ bundle_config "only ci"
+ bundle :install
+
+ expect(the_bundle).to include_gems("myrack 1.0.0")
+ expect(the_bundle).not_to include_gems("activerecord 1.0")
+ end
+
+ it "resolves indirect dependencies from a git source not in the requested groups (without compact_index dependency API)" do
+ build_lib "activesupport", "1.0", path: lib_path("rails/activesupport")
+ build_git "activerecord", "1.0", path: lib_path("rails") do |s|
+ s.add_dependency "activesupport", "= 1.0"
+ end
+
+ gemfile <<-G
+ source "https://gem.repo1"
+
+ gem "activerecord", :git => "#{lib_path("rails")}"
+
+ group :ci do
+ gem "myrack"
+ end
+ G
+
+ # Force the RubygemsAggregate code path in find_source_requirements by
+ # making the dependency API unavailable.
+ bundle_config "only ci"
+ bundle :install, artifice: "endpoint_api_forbidden"
+
+ expect(the_bundle).to include_gems("myrack 1.0.0")
+ expect(the_bundle).not_to include_gems("activerecord 1.0")
+ end
+ end
end
diff --git a/spec/bundler/install/global_cache_spec.rb b/spec/bundler/install/global_cache_spec.rb
index 0a7daf173c..4cffa65b2a 100644
--- a/spec/bundler/install/global_cache_spec.rb
+++ b/spec/bundler/install/global_cache_spec.rb
@@ -1,6 +1,7 @@
# frozen_string_literal: true
RSpec.describe "global gem caching" do
+ # Uses subprocess because this setting must apply across multiple app directories (bundled_app and bundled_app2)
before { bundle "config set global_gem_cache true" }
describe "using the cross-application user cache" do
@@ -8,7 +9,13 @@ RSpec.describe "global gem caching" do
let(:source2) { "http://gemserver.example.org" }
def cache_base
- home(".bundle", "cache", "gems")
+ # Use the unified global gem cache path if available (from RubyGems),
+ # otherwise fall back to the Bundler-specific cache location
+ if Gem.respond_to?(:global_gem_cache_path)
+ Pathname.new(Gem.global_gem_cache_path)
+ else
+ home(".bundle", "cache", "gems")
+ end
end
def source_global_cache(*segments)
@@ -42,6 +49,8 @@ RSpec.describe "global gem caching" do
end
it "shows a proper error message if a cached gem is corrupted" do
+ skip "This example is not working on ruby/ruby repo" if ruby_core?
+
source_global_cache.mkpath
FileUtils.touch(source_global_cache("myrack-1.0.0.gem"))
@@ -88,7 +97,7 @@ RSpec.describe "global gem caching" do
describe "when the same gem from different sources is installed" do
it "should use the appropriate one from the global cache" do
- bundle "config path.system true"
+ bundle_config "path.system true"
install_gemfile <<-G, artifice: "compact_index"
source "#{source}"
@@ -133,7 +142,7 @@ RSpec.describe "global gem caching" do
end
it "should not install if the wrong source is provided" do
- bundle "config path.system true"
+ bundle_config "path.system true"
gemfile <<-G
source "#{source}"
@@ -191,7 +200,7 @@ RSpec.describe "global gem caching" do
describe "when installing gems from a different directory" do
it "uses the global cache as a source" do
- bundle "config path.system true"
+ bundle_config "path.system true"
install_gemfile <<-G, artifice: "compact_index"
source "#{source}"
@@ -281,7 +290,7 @@ RSpec.describe "global gem caching" do
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__)" }
- bundle "config set --local path different_path"
+ bundle_config "path different_path"
bundle :install
expect(Dir[home(".bundle", "cache", "extensions", "**", "*binary_c*")]).to all(end_with(".rb"))
diff --git a/spec/bundler/install/path_spec.rb b/spec/bundler/install/path_spec.rb
index 0ede8df8ff..49360e511e 100644
--- a/spec/bundler/install/path_spec.rb
+++ b/spec/bundler/install/path_spec.rb
@@ -14,14 +14,14 @@ RSpec.describe "bundle install" do
end
it "does not use available system gems with `vendor/bundle" do
- bundle "config set --local path vendor/bundle"
+ bundle_config "path vendor/bundle"
bundle :install
expect(the_bundle).to include_gems "myrack 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_config "path.system true"
+ bundle_config_global "path vendor/bundle"
bundle :install
run "require 'myrack'", raise_on_error: false
expect(out).to include("FAIL")
@@ -31,36 +31,21 @@ RSpec.describe "bundle install" do
dir = bundled_app("bun++dle")
dir.mkpath
- bundle "config set --local path #{dir.join("vendor/bundle")}"
+ bundle_config "path #{dir.join("vendor/bundle")}"
bundle :install, dir: dir
expect(out).to include("installed into `./vendor/bundle`")
- dir.rmtree
+ FileUtils.rm_rf dir
end
it "prints a message to let the user know where gems where installed" do
- bundle "config set --local path vendor/bundle"
+ bundle_config "path vendor/bundle"
bundle :install
expect(out).to include("gems are installed into `./vendor/bundle`")
end
- it "disallows --path vendor/bundle --system" 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" do
- bundle "install --path vendor/bundle"
- FileUtils.rm_r 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"
- end
-
it "installs the bundle relatively to repository root, when Bundler run from the same directory" do
- bundle "config path vendor/bundle", dir: bundled_app.parent
+ bundle "config set path vendor/bundle", dir: bundled_app.parent
bundle "install --gemfile='#{bundled_app}/Gemfile'", dir: bundled_app.parent
expect(out).to include("installed into `./bundled_app/vendor/bundle`")
expect(bundled_app("vendor/bundle")).to be_directory
@@ -68,28 +53,19 @@ RSpec.describe "bundle install" do
end
it "installs the bundle relatively to repository root, when Bundler run from a different directory" do
- bundle "config path vendor/bundle", dir: bundled_app
+ bundle "config set path vendor/bundle", dir: bundled_app
bundle "install --gemfile='#{bundled_app}/Gemfile'", dir: bundled_app.parent
expect(out).to include("installed into `./bundled_app/vendor/bundle`")
expect(bundled_app("vendor/bundle")).to be_directory
expect(the_bundle).to include_gems "myrack 1.0.0"
end
- it "installs the bundle relatively to Gemfile folder, when repository root can't be inferred from settings" do
- bundle "install --gemfile='#{bundled_app}/Gemfile' --path vendor/bundle", dir: bundled_app.parent
- expect(out).to include("installed into `./bundled_app/vendor/bundle`")
- expect(bundled_app("vendor/bundle")).to be_directory
- expect(the_bundle).to include_gems "myrack 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
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)
expect(out).to include("installed into `../bundle`")
expect(bundled_app("bundle")).to be_directory
@@ -121,7 +97,7 @@ RSpec.describe "bundle install" do
context "when set via #{type}" do
it "installs gems to a path if one is specified" do
set_bundle_path(type, bundled_app("vendor2").to_s)
- bundle "config set --local path vendor/bundle"
+ bundle_config "path vendor/bundle"
bundle :install
expect(vendored_gems("gems/myrack-1.0.0")).to be_directory
@@ -131,7 +107,7 @@ RSpec.describe "bundle install" do
it "installs gems to ." do
set_bundle_path(type, ".")
- bundle "config set --global disable_shared_gems true"
+ bundle_config_global "disable_shared_gems true"
bundle :install
@@ -162,7 +138,7 @@ RSpec.describe "bundle install" do
end
it "installs gems to BUNDLE_PATH from .bundle/config" do
- config "BUNDLE_PATH" => bundled_app("vendor/bundle").to_s
+ bundle_config "BUNDLE_PATH" => bundled_app("vendor/bundle").to_s
bundle :install
@@ -171,7 +147,7 @@ RSpec.describe "bundle install" do
end
it "sets BUNDLE_PATH as the first argument to bundle install" do
- bundle "config set --local path ./vendor/bundle"
+ bundle_config "path ./vendor/bundle"
bundle :install
expect(vendored_gems("gems/myrack-1.0.0")).to be_directory
@@ -181,7 +157,7 @@ RSpec.describe "bundle install" do
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
- bundle "config set --local path ./vendor/bundle"
+ bundle_config "path ./vendor/bundle"
bundle :install
expect(vendored_gems("gems/myrack-1.0.0")).to be_directory
@@ -198,19 +174,19 @@ RSpec.describe "bundle install" do
gem "very_simple_binary"
G
- bundle "config set --local path ./vendor/bundle"
+ bundle_config "path ./vendor/bundle"
bundle :install
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"
- vendored_gems("extensions").rmtree
+ FileUtils.rm_rf vendored_gems("extensions")
run "require 'very_simple_binary_c'", raise_on_error: false
expect(err).to include("Bundler::GemNotFound")
- bundle "config set --local path ./vendor/bundle"
+ bundle_config "path ./vendor/bundle"
bundle :install
expect(vendored_gems("gems/very_simple_binary-1.0")).to be_directory
@@ -230,7 +206,7 @@ RSpec.describe "bundle install" do
gem "myrack"
G
- bundle "config set --local path bundle"
+ bundle_config "path bundle"
bundle :install, raise_on_error: false
expect(err).to include("file already exists")
end
diff --git a/spec/bundler/install/process_lock_spec.rb b/spec/bundler/install/process_lock_spec.rb
index 344caa3a93..b096291d1a 100644
--- a/spec/bundler/install/process_lock_spec.rb
+++ b/spec/bundler/install/process_lock_spec.rb
@@ -53,5 +53,61 @@ RSpec.describe "process lock spec" do
expect(processed).to eq true
end
end
+
+ it "refreshes gem specification cache after waiting for lock" do
+ build_repo2 do
+ build_gem "myrack", "1.0.0"
+ end
+
+ gemfile <<-G
+ source "https://gem.repo2"
+ gem "myrack"
+ G
+
+ # First, install the gem so it's available
+ bundle "install"
+ expect(out).to include("Installing myrack")
+
+ # Queue for thread-safe communication
+ lock_acquired = Queue.new
+ can_release_lock = Queue.new
+ install_output = Queue.new
+
+ # Thread holds lock (simulating another bundle process that just finished installing)
+ thread = Thread.new do
+ Bundler::ProcessLock.lock(default_bundle_path) do
+ # Signal that we have the lock
+ lock_acquired << true
+ # Wait until main thread signals we can release
+ can_release_lock.pop
+ end
+ end
+
+ # Wait for thread to acquire lock
+ lock_acquired.pop
+
+ # Start another install in a thread - it will wait for the lock
+ install_thread = Thread.new do
+ bundle "install", verbose: true
+ install_output << out
+ end
+
+ # Give subprocess time to start and begin waiting for lock
+ sleep 0.5
+
+ # Signal thread to release the lock
+ can_release_lock << true
+
+ # Wait for both threads to complete
+ thread.join
+ install_thread.join
+
+ second_install_out = install_output.pop
+
+ expect(the_bundle).to include_gems "myrack 1.0.0"
+ # The second install should have refreshed its cache after acquiring
+ # the lock and seen that myrack was already installed
+ expect(second_install_out).to include("Using myrack")
+ end
end
end
diff --git a/spec/bundler/install/yanked_spec.rb b/spec/bundler/install/yanked_spec.rb
index ffe962d9f3..c92af7bfb0 100644
--- a/spec/bundler/install/yanked_spec.rb
+++ b/spec/bundler/install/yanked_spec.rb
@@ -47,7 +47,7 @@ RSpec.context "when installing a bundle that includes yanked gems" do
foo (= 1.0.0)
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
@@ -118,7 +118,7 @@ RSpec.context "when installing a bundle that includes yanked gems" do
build_gem "foo", "9.0.0"
end
- bundle "config set force_ruby_platform true"
+ bundle_config "force_ruby_platform true"
install_gemfile <<-G, raise_on_error: false
source "https://gem.repo4"
@@ -154,7 +154,7 @@ RSpec.context "when resolving a bundle that includes yanked gems, but unlocking
bar
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
gemfile <<-G
@@ -182,7 +182,7 @@ RSpec.context "when resolving a bundle that includes yanked gems, but unlocking
foo
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
end
diff --git a/spec/bundler/lock/git_spec.rb b/spec/bundler/lock/git_spec.rb
index 49c0a2af1c..c9f76115dc 100644
--- a/spec/bundler/lock/git_spec.rb
+++ b/spec/bundler/lock/git_spec.rb
@@ -60,7 +60,7 @@ RSpec.describe "bundle lock with git gems" do
foo!
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
bundle "install", raise_on_error: false
@@ -123,7 +123,7 @@ RSpec.describe "bundle lock with git gems" do
foo!
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
bundle "install"
@@ -161,7 +161,7 @@ RSpec.describe "bundle lock with git gems" do
foo!
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
bundle "install"
@@ -206,7 +206,7 @@ RSpec.describe "bundle lock with git gems" do
activesupport
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
gemfile <<~G
@@ -220,4 +220,39 @@ RSpec.describe "bundle lock with git gems" do
expect(lockfile).to include("securerandom (0.3.2)")
end
+
+ it "does not lock versions that don't exist in the repository when changing a GIT direct dep to a GEM direct dep" do
+ build_repo4 do
+ build_gem "ruby-lsp", "0.16.1"
+ end
+
+ path = lib_path("ruby-lsp")
+ revision = build_git("ruby-lsp", "0.16.2", path: path).ref_for("HEAD")
+
+ lockfile <<~L
+ GIT
+ remote: #{path}
+ revision: #{revision}
+ specs:
+ ruby-lsp (0.16.2)
+
+ PLATFORMS
+ #{lockfile_platforms}
+
+ DEPENDENCIES
+ ruby-lsp!
+
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+
+ gemfile <<~G
+ source "https://gem.repo4"
+ gem "ruby-lsp"
+ G
+
+ bundle "lock"
+
+ expect(lockfile).to include("ruby-lsp (0.16.1)")
+ end
end
diff --git a/spec/bundler/lock/lockfile_spec.rb b/spec/bundler/lock/lockfile_spec.rb
index 6b98e0924e..654ac02aa7 100644
--- a/spec/bundler/lock/lockfile_spec.rb
+++ b/spec/bundler/lock/lockfile_spec.rb
@@ -29,7 +29,7 @@ RSpec.describe "the lockfile format" do
myrack
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
G
end
@@ -80,7 +80,7 @@ RSpec.describe "the lockfile format" do
myrack
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
G
end
@@ -168,7 +168,7 @@ RSpec.describe "the lockfile format" do
myrack (> 0)
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
G
end
@@ -215,7 +215,7 @@ RSpec.describe "the lockfile format" do
myrack
BUNDLED WITH
- #{current_version}
+ #{current_version}
G
end
@@ -246,7 +246,7 @@ RSpec.describe "the lockfile format" do
myrack-obama
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
G
end
@@ -277,7 +277,7 @@ RSpec.describe "the lockfile format" do
myrack-obama (>= 1.0)
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
G
end
@@ -324,7 +324,7 @@ RSpec.describe "the lockfile format" do
myrack-obama (>= 1.0)!
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
G
end
@@ -371,7 +371,7 @@ RSpec.describe "the lockfile format" do
myrack-obama (>= 1.0)!
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
lockfile lockfile_without_credentials
@@ -432,7 +432,7 @@ RSpec.describe "the lockfile format" do
myrack-obama (>= 1.0)!
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
lockfile lockfile_with_credentials
@@ -468,7 +468,7 @@ RSpec.describe "the lockfile format" do
net-sftp
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
G
expect(the_bundle).to include_gems "net-sftp 1.1.1", "net-ssh 1.0.0"
@@ -504,7 +504,7 @@ RSpec.describe "the lockfile format" do
foo!
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
G
end
@@ -540,7 +540,7 @@ RSpec.describe "the lockfile format" do
myrack
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
bundle "install"
@@ -579,7 +579,7 @@ RSpec.describe "the lockfile format" do
foo!
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
G
end
@@ -615,7 +615,7 @@ RSpec.describe "the lockfile format" do
foo!
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
G
end
@@ -651,7 +651,7 @@ RSpec.describe "the lockfile format" do
foo!
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
G
end
@@ -710,7 +710,7 @@ RSpec.describe "the lockfile format" do
ckeditor!
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
bundle "lock"
@@ -737,7 +737,7 @@ RSpec.describe "the lockfile format" do
ckeditor!
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
@@ -770,7 +770,7 @@ RSpec.describe "the lockfile format" do
foo!
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
G
end
@@ -786,7 +786,6 @@ RSpec.describe "the lockfile format" do
c.no_checksum "foo", "1.0"
end
- bundle "config set cache_all true"
bundle :cache
bundle :install, local: true
@@ -807,7 +806,7 @@ RSpec.describe "the lockfile format" do
foo!
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
G
end
@@ -855,7 +854,7 @@ RSpec.describe "the lockfile format" do
myrack
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
G
end
@@ -883,7 +882,7 @@ RSpec.describe "the lockfile format" do
myrack!
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
G
end
@@ -926,7 +925,7 @@ RSpec.describe "the lockfile format" do
thin
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
G
end
@@ -975,7 +974,7 @@ RSpec.describe "the lockfile format" do
rails
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
G
end
@@ -983,7 +982,7 @@ RSpec.describe "the lockfile format" do
update_repo2 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
+ # See https://github.com/ruby/rubygems/commit/03dbac93a3396a80db258d9bc63500333c25bd2f
build_gem "double_deps", "1.0", skip_validation: true do |s|
s.add_dependency "net-ssh", ">= 1.0.0"
s.add_dependency "net-ssh"
@@ -1016,7 +1015,7 @@ RSpec.describe "the lockfile format" do
double_deps
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
G
end
@@ -1047,7 +1046,7 @@ RSpec.describe "the lockfile format" do
myrack-obama (>= 1.0)
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
G
end
@@ -1078,7 +1077,7 @@ RSpec.describe "the lockfile format" do
myrack-obama (>= 1.0)
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
G
end
@@ -1113,7 +1112,7 @@ RSpec.describe "the lockfile format" do
foo!
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
G
end
@@ -1148,7 +1147,7 @@ RSpec.describe "the lockfile format" do
foo!
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
G
end
@@ -1183,7 +1182,7 @@ RSpec.describe "the lockfile format" do
foo!
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
G
end
@@ -1216,7 +1215,7 @@ RSpec.describe "the lockfile format" do
foo!
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
G
end
@@ -1238,7 +1237,7 @@ RSpec.describe "the lockfile format" do
myrack
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
G
install_gemfile <<-G
@@ -1262,7 +1261,7 @@ RSpec.describe "the lockfile format" do
myrack
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
G
end
@@ -1306,7 +1305,7 @@ RSpec.describe "the lockfile format" do
google-protobuf
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
end
@@ -1341,7 +1340,7 @@ RSpec.describe "the lockfile format" do
platform_specific
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
G
end
end
@@ -1378,7 +1377,7 @@ RSpec.describe "the lockfile format" do
myrack
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
G
end
@@ -1406,7 +1405,7 @@ RSpec.describe "the lockfile format" do
myrack
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
G
end
@@ -1434,7 +1433,7 @@ RSpec.describe "the lockfile format" do
myrack (= 1.0)
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
G
end
@@ -1462,7 +1461,7 @@ RSpec.describe "the lockfile format" do
myrack (= 1.0)
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
G
end
@@ -1511,7 +1510,7 @@ RSpec.describe "the lockfile format" do
myrack (> 0.9, < 1.0)
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
G
end
@@ -1539,10 +1538,10 @@ RSpec.describe "the lockfile format" do
myrack (> 0.9, < 1.0)
#{checksums}
RUBY VERSION
- #{Bundler::RubyVersion.system}
+ #{Bundler::RubyVersion.system}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
G
end
@@ -1560,7 +1559,7 @@ RSpec.describe "the lockfile format" do
myrack_middleware
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
install_gemfile <<-G
@@ -1583,7 +1582,7 @@ RSpec.describe "the lockfile format" do
myrack_middleware
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
@@ -1601,7 +1600,7 @@ RSpec.describe "the lockfile format" do
myrack_middleware
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
install_gemfile <<-G, env: { "BUNDLE_FROZEN" => "true" }, raise_on_error: false
@@ -1609,7 +1608,8 @@ RSpec.describe "the lockfile format" do
gem "myrack_middleware"
G
- expect(err).to eq("Bundler found incorrect dependencies in the lockfile for myrack_middleware-1.0")
+ expect(err).to include("Bundler found incorrect dependencies in the lockfile for myrack_middleware-1.0")
+ expect(err).to include("myrack: gemspec specifies = 0.9.1, not in lockfile")
expect(the_bundle).not_to include_gems "myrack_middleware 1.0"
end
@@ -1629,7 +1629,7 @@ RSpec.describe "the lockfile format" do
CHECKSUMS
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
install_gemfile <<-G, env: { "BUNDLE_FROZEN" => "true" }, raise_on_error: false
@@ -1663,7 +1663,7 @@ RSpec.describe "the lockfile format" do
myrack (0.9.1)
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
install_gemfile <<-G, env: { "BUNDLE_FROZEN" => "true" }, raise_on_error: false
@@ -1708,7 +1708,7 @@ RSpec.describe "the lockfile format" do
other_dep
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
install_gemfile <<-G
@@ -1735,7 +1735,7 @@ RSpec.describe "the lockfile format" do
other_dep
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
@@ -1770,7 +1770,7 @@ RSpec.describe "the lockfile format" do
another_dep_middleware
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
install_gemfile <<-G
@@ -1798,7 +1798,7 @@ RSpec.describe "the lockfile format" do
myrack_middleware
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
@@ -1830,7 +1830,7 @@ RSpec.describe "the lockfile format" do
other_dep
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
install_gemfile <<-G, raise_on_error: false
@@ -1873,7 +1873,7 @@ RSpec.describe "the lockfile format" do
direct_dependency
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
G
install_gemfile <<-G
@@ -1897,7 +1897,7 @@ RSpec.describe "the lockfile format" do
direct_dependency
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
G
end
@@ -1915,7 +1915,7 @@ RSpec.describe "the lockfile format" do
myrack_middleware
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
install_gemfile <<-G
@@ -1938,7 +1938,7 @@ RSpec.describe "the lockfile format" do
myrack_middleware
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
@@ -1972,7 +1972,7 @@ RSpec.describe "the lockfile format" do
foo!
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
bundle "install"
@@ -1995,7 +1995,7 @@ RSpec.describe "the lockfile format" do
foo!
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
@@ -2029,7 +2029,7 @@ RSpec.describe "the lockfile format" do
foo (= 1.0)!
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
bundle "install"
@@ -2052,7 +2052,7 @@ RSpec.describe "the lockfile format" do
foo (= 1.0)!
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
@@ -2088,7 +2088,7 @@ RSpec.describe "the lockfile format" do
net-smtp
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
bundle "install"
@@ -2108,7 +2108,75 @@ RSpec.describe "the lockfile format" do
net-smtp
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
+ L
+ end
+
+ it "successfully updates the lockfile when a new gem is added in the Gemfile includes a gem that shouldn't be included" do
+ build_repo4 do
+ build_gem "logger", "1.7.0"
+ build_gem "rack", "3.2.0"
+ build_gem "net-smtp", "0.5.0"
+ end
+
+ gemfile <<~G
+ source "#{file_uri_for(gem_repo4)}"
+ gem "logger"
+ gem "net-smtp"
+
+ install_if -> { false } do
+ gem 'rack', github: 'rack/rack'
+ end
+ G
+
+ lockfile <<~L
+ GIT
+ remote: https://github.com/rack/rack.git
+ revision: 2fface9ac09fc582a81386becd939c987ad33f99
+ specs:
+ rack (3.2.0)
+
+ GEM
+ remote: #{file_uri_for(gem_repo4)}/
+ specs:
+ logger (1.7.0)
+
+ PLATFORMS
+ #{lockfile_platforms}
+
+ DEPENDENCIES
+ logger
+ rack!
+
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+
+ bundle "install"
+
+ expect(lockfile).to eq <<~L
+ GIT
+ remote: https://github.com/rack/rack.git
+ revision: 2fface9ac09fc582a81386becd939c987ad33f99
+ specs:
+ rack (3.2.0)
+
+ GEM
+ remote: #{file_uri_for(gem_repo4)}/
+ specs:
+ logger (1.7.0)
+ net-smtp (0.5.0)
+
+ PLATFORMS
+ #{lockfile_platforms}
+
+ DEPENDENCIES
+ logger
+ net-smtp
+ rack!
+
+ BUNDLED WITH
+ #{Bundler::VERSION}
L
end
@@ -2141,7 +2209,7 @@ RSpec.describe "the lockfile format" do
minitest-bisect
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
cache_gems "minitest-bisect-1.6.0", "path_expander-1.1.1", gem_repo: gem_repo4
@@ -2162,7 +2230,7 @@ RSpec.describe "the lockfile format" do
minitest-bisect
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
end
@@ -2207,7 +2275,7 @@ RSpec.describe "the lockfile format" do
minitest-bisect
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
bundle "install --verbose"
@@ -2228,7 +2296,7 @@ RSpec.describe "the lockfile format" do
minitest-bisect
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
@@ -2328,7 +2396,7 @@ RSpec.describe "the lockfile format" do
myrack
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
install_gemfile <<-G, raise_on_error: false
diff --git a/spec/bundler/other/cli_dispatch_spec.rb b/spec/bundler/other/cli_dispatch_spec.rb
index 1039737b99..a2c745b070 100644
--- a/spec/bundler/other/cli_dispatch_spec.rb
+++ b/spec/bundler/other/cli_dispatch_spec.rb
@@ -15,6 +15,6 @@ RSpec.describe "bundle command names" do
it "print a friendly error when ambiguous" do
bundle "in", raise_on_error: false
- expect(err).to eq("Ambiguous command in matches [info, init, inject, install]")
+ expect(err).to eq("Ambiguous command in matches [info, init, install]")
end
end
diff --git a/spec/bundler/other/cli_man_pages_spec.rb b/spec/bundler/other/cli_man_pages_spec.rb
index 6efd2904d6..4e8f155309 100644
--- a/spec/bundler/other/cli_man_pages_spec.rb
+++ b/spec/bundler/other/cli_man_pages_spec.rb
@@ -13,9 +13,11 @@ RSpec.describe "bundle commands" do
def check_commands!(command_class)
command_class.commands.each do |command_name, command|
- next if command.is_a?(Bundler::Thor::HiddenCommand)
-
- if command_class == Bundler::CLI
+ if command.is_a?(Bundler::Thor::HiddenCommand)
+ man_page = man_page(command_name)
+ expect(man_page).not_to exist
+ expect(main_man_page.read).not_to include("bundle #{command_name}")
+ elsif command_class == Bundler::CLI
man_page = man_page(command_name)
expect(man_page).to exist
@@ -61,7 +63,11 @@ RSpec.describe "bundle commands" do
"* #{names.map {|name| "`#{name}#{value}`" }.join(", ")}:"
end
- expect(man_page_content).to include(help)
+ if option.banner.include?("(removed)")
+ expect(man_page_content).not_to include(help)
+ else
+ expect(man_page_content).to include(help)
+ end
end
def check_subcommand!(name, man_page)
@@ -87,4 +93,8 @@ RSpec.describe "bundle commands" do
def man_page(command_name)
source_root.join("lib/bundler/man/bundle-#{command_name}.1.ronn")
end
+
+ def main_man_page
+ source_root.join("lib/bundler/man/bundle.1.ronn")
+ end
end
diff --git a/spec/bundler/other/major_deprecation_spec.rb b/spec/bundler/other/major_deprecation_spec.rb
index d57abe45f3..ab7589d698 100644
--- a/spec/bundler/other/major_deprecation_spec.rb
+++ b/spec/bundler/other/major_deprecation_spec.rb
@@ -14,81 +14,67 @@ RSpec.describe "major deprecations" do
describe ".clean_env" do
before do
source = "Bundler.clean_env"
- bundle "exec ruby -e #{source.dump}"
+ bundle "exec ruby -e #{source.dump}", raise_on_error: false
end
- it "is deprecated in favor of .unbundled_env" 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)"
+ it "is removed in favor of .unbundled_env and shows a helpful error message about it" do
+ expect(err).to include \
+ "`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`" \
end
-
- pending "is removed and shows a helpful error message about it", bundler: "4"
end
describe ".with_clean_env" do
before do
source = "Bundler.with_clean_env {}"
- bundle "exec ruby -e #{source.dump}"
+ bundle "exec ruby -e #{source.dump}", raise_on_error: false
end
- it "is deprecated in favor of .unbundled_env" 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` " \
- "(called at -e:1)"
+ it "is removed in favor of .unbundled_env and shows a helpful error message about it" do
+ expect(err).to include(
+ "`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`"
)
end
-
- pending "is removed and shows a helpful error message about it", bundler: "4"
end
describe ".clean_system" do
before do
source = "Bundler.clean_system('ls')"
- bundle "exec ruby -e #{source.dump}"
+ bundle "exec ruby -e #{source.dump}", raise_on_error: false
end
- it "is deprecated in favor of .unbundled_system" 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` " \
- "(called at -e:1)"
+ it "is removed in favor of .unbundled_system and shows a helpful error message about it" do
+ expect(err).to include(
+ "`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`" \
)
end
-
- pending "is removed and shows a helpful error message about it", bundler: "4"
end
describe ".clean_exec" do
before do
source = "Bundler.clean_exec('ls')"
- bundle "exec ruby -e #{source.dump}"
+ bundle "exec ruby -e #{source.dump}", raise_on_error: false
end
- it "is deprecated in favor of .unbundled_exec" 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` " \
- "(called at -e:1)"
+ it "is removed in favor of .unbundled_exec and shows a helpful error message about it" do
+ expect(err).to include(
+ "`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`" \
)
end
-
- pending "is removed and shows a helpful error message about it", bundler: "4"
end
describe ".environment" do
before do
source = "Bundler.environment"
- bundle "exec ruby -e #{source.dump}"
+ bundle "exec ruby -e #{source.dump}", raise_on_error: false
end
- it "is deprecated in favor of .load" do
- expect(deprecations).to include "Bundler.environment has been removed in favor of Bundler.load (called at -e:1)"
+ it "is removed in favor of .load and shows a helpful error message about it" do
+ expect(err).to include "Bundler.environment has been removed in favor of Bundler.load"
end
-
- pending "is removed and shows a helpful error message about it", bundler: "4"
end
end
@@ -97,11 +83,9 @@ RSpec.describe "major deprecations" do
bundle "exec --no-keep-file-descriptors -e 1", raise_on_error: false
end
- it "is deprecated" 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"
+ it "is removed and shows a helpful error message about it" do
+ expect(err).to include "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"
end
-
- pending "is removed and shows a helpful error message about it", bundler: "4"
end
describe "bundle update --quiet" do
@@ -121,16 +105,14 @@ RSpec.describe "major deprecations" do
bundle "check --path vendor/bundle", raise_on_error: false
end
- it "should print a deprecation warning" 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 " \
- "path 'vendor/bundle'`, and stop using this flag"
+ it "fails with a helpful error" do
+ expect(err).to include(
+ "The `--path` flag has been removed because it relied on being " \
+ "remembered across bundler invocations, which bundler no longer " \
+ "does. Instead please use `bundle config set path 'vendor/bundle'`, " \
+ "and stop using this flag"
)
end
-
- pending "fails with a helpful error", bundler: "4"
end
context "bundle check --path=" do
@@ -143,16 +125,14 @@ RSpec.describe "major deprecations" do
bundle "check --path=vendor/bundle", raise_on_error: false
end
- it "should print a deprecation warning" 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 " \
- "path 'vendor/bundle'`, and stop using this flag"
+ it "fails with a helpful error" do
+ expect(err).to include(
+ "The `--path` flag has been removed because it relied on being " \
+ "remembered across bundler invocations, which bundler no longer " \
+ "does. Instead please use `bundle config set path 'vendor/bundle'`, " \
+ "and stop using this flag"
)
end
-
- pending "fails with a helpful error", bundler: "4"
end
context "bundle binstubs --path=" do
@@ -165,16 +145,14 @@ RSpec.describe "major deprecations" do
bundle "binstubs myrack --path=binpath", raise_on_error: false
end
- it "should print a deprecation warning" 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 " \
- "bin 'binpath'`, and stop using this flag"
+ it "fails with a helpful error" do
+ expect(err).to include(
+ "The `--path` flag has been removed because it relied on being " \
+ "remembered across bundler invocations, which bundler no longer " \
+ "does. Instead please use `bundle config set bin 'binpath'`, " \
+ "and stop using this flag"
)
end
-
- pending "fails with a helpful error", bundler: "4"
end
context "bundle cache --all" do
@@ -184,19 +162,17 @@ RSpec.describe "major deprecations" do
gem "myrack"
G
- bundle "cache --all", raise_on_error: false
+ bundle "cache --all --verbose", raise_on_error: false
end
- it "should print a deprecation warning" do
- expect(deprecations).to include(
- "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"
+ it "fails with a helpful error" do
+ expect(err).to include(
+ "The `--all` flag has been removed because it relied on being " \
+ "remembered across bundler invocations, which bundler no longer " \
+ "does. Instead please use `bundle config set cache_all true`, " \
+ "and stop using this flag"
)
end
-
- pending "fails with a helpful error", bundler: "4"
end
context "bundle cache --no-all" do
@@ -209,16 +185,14 @@ RSpec.describe "major deprecations" do
bundle "cache --no-all", raise_on_error: false
end
- it "should print a deprecation warning" do
- expect(deprecations).to include(
- "The `--no-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 false`, and stop using this flag"
+ it "fails with a helpful error" do
+ expect(err).to include(
+ "The `--no-all` flag has been removed because it relied on being " \
+ "remembered across bundler invocations, which bundler no longer " \
+ "does. Instead please use `bundle config set cache_all false`, " \
+ "and stop using this flag"
)
end
-
- pending "fails with a helpful error", bundler: "4"
end
context "bundle cache --path" do
@@ -231,16 +205,14 @@ RSpec.describe "major deprecations" do
bundle "cache --path foo", raise_on_error: false
end
- it "should print a deprecation warning" do
- expect(deprecations).to include(
- "The `--path` flag is deprecated because its semantics are unclear. " \
+ it "should print a removal error" do
+ expect(err).to include(
+ "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, " \
"and stop using this flag"
)
end
-
- pending "fails with a helpful error", bundler: "4"
end
context "bundle cache --path=" do
@@ -254,15 +226,53 @@ RSpec.describe "major deprecations" do
end
it "should print a deprecation warning" do
- expect(deprecations).to include(
- "The `--path` flag is deprecated because its semantics are unclear. " \
+ expect(err).to include(
+ "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, " \
"and stop using this flag"
)
end
+ end
+
+ context "bundle cache --frozen" do
+ before do
+ install_gemfile <<-G
+ source "https://gem.repo1"
+ gem "myrack"
+ G
+
+ bundle "cache --frozen", raise_on_error: false
+ end
- pending "fails with a helpful error", bundler: "4"
+ it "fails with a helpful error" do
+ expect(err).to include(
+ "The `--frozen` flag has been removed because it relied on being " \
+ "remembered across bundler invocations, which bundler no longer " \
+ "does. Instead please use `bundle config set frozen true`, " \
+ "and stop using this flag"
+ )
+ end
+ end
+
+ context "bundle cache --no-prune" do
+ before do
+ install_gemfile <<-G
+ source "https://gem.repo1"
+ gem "myrack"
+ G
+
+ bundle "cache --no-prune", raise_on_error: false
+ end
+
+ it "fails with a helpful error" do
+ expect(err).to include(
+ "The `--no-prune` flag has been removed because it relied on being " \
+ "remembered across bundler invocations, which bundler no longer " \
+ "does. Instead please use `bundle config set no_prune true`, " \
+ "and stop using this flag"
+ )
+ end
end
describe "bundle config" do
@@ -280,7 +290,7 @@ RSpec.describe "major deprecations" do
describe "old get interface" do
before do
- bundle "config waka"
+ bundle "config waka", raise_on_error: false
end
it "warns", bundler: "4" do
@@ -386,17 +396,15 @@ RSpec.describe "major deprecations" do
describe "bundle install --binstubs" do
before do
- install_gemfile <<-G, binstubs: true
+ install_gemfile <<-G, binstubs: true, raise_on_error: false
source "https://gem.repo1"
gem "myrack"
G
end
- it "should output a deprecation warning" do
- expect(deprecations).to include("The --binstubs option will be removed in favor of `bundle binstubs --all`")
+ it "fails with a helpful error" do
+ expect(err).to include("The --binstubs option has been removed in favor of `bundle binstubs --all`")
end
-
- pending "fails with a helpful error", bundler: "4"
end
context "bundle install with both gems.rb and Gemfile present" do
@@ -427,7 +435,7 @@ RSpec.describe "major deprecations" do
context "bundle install with flags" do
before do
- bundle "config set --local path vendor/bundle"
+ bundle_config "path vendor/bundle"
install_gemfile <<-G
source "https://gem.repo1"
@@ -449,76 +457,85 @@ RSpec.describe "major deprecations" do
}.each do |name, expectations|
option_name, value = *expectations
flag_name = "--#{name}"
+ args = %w[true false].include?(value) ? flag_name : "#{flag_name} #{value}"
context "with the #{flag_name} flag" do
before do
bundle "install" # to create a lockfile, which deployment or frozen need
- bundle "install #{flag_name} #{value}"
+
+ bundle "install #{args}", raise_on_error: false
end
- it "should print a deprecation warning" 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"
+ it "fails with a helpful error" do
+ expect(err).to include(
+ "The `#{flag_name}` flag has been removed because it relied on " \
+ "being remembered across bundler invocations, which bundler no " \
+ "longer does. Instead please use `bundle config set " \
+ "#{option_name} #{value}`, and stop using this flag"
)
end
-
- pending "fails with a helpful error", bundler: "4"
end
end
end
context "bundle install with multiple sources" do
before do
- install_gemfile <<-G
+ install_gemfile <<-G, raise_on_error: false
source "https://gem.repo3"
source "https://gem.repo1"
G
end
- it "shows a deprecation" do
- expect(deprecations).to include(
- "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."
+ it "fails with a helpful error" do
+ expect(err).to include(
+ "This Gemfile contains multiple global sources. " \
+ "Each source after the first must include a block to indicate which gems " \
+ "should come from that source"
)
end
it "doesn't show lockfile deprecations if there's a lockfile" do
- bundle "install"
+ lockfile <<~L
+ GEM
+ remote: https://gem.repo3/
+ remote: https://gem.repo1/
+ specs:
+
+ PLATFORMS
+ #{lockfile_platforms}
- expect(deprecations).to include(
- "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."
+ DEPENDENCIES
+
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+ bundle "install", raise_on_error: false
+
+ expect(err).to include(
+ "This Gemfile contains multiple global sources. " \
+ "Each source after the first must include a block to indicate which gems " \
+ "should come from that source"
)
- expect(deprecations).not_to include(
+ expect(err).not_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."
)
- bundle "config set --local frozen true"
- bundle "install"
-
- expect(deprecations).to include(
- "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."
+ bundle_config "frozen true"
+ bundle "install", raise_on_error: false
+
+ expect(err).to include(
+ "This Gemfile contains multiple global sources. " \
+ "Each source after the first must include a block to indicate which gems " \
+ "should come from that source"
)
- expect(deprecations).not_to include(
+ expect(err).not_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: "4"
end
- context "bundle install in frozen mode with a lockfile with a single rubygems section with multiple remotes" do
+ context "bundle install with a lockfile with a single rubygems section with multiple remotes" do
before do
build_repo3 do
build_gem "myrack", "0.9.1"
@@ -545,19 +562,62 @@ RSpec.describe "major deprecations" do
myrack!
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
+ end
- bundle "config set --local frozen true"
+ it "shows an error" do
+ bundle "install", raise_on_error: false
+
+ expect(err).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
+ end
+
+ context "bundle install with a lockfile including X64_MINGW_LEGACY platform" do
+ before do
+ gemfile <<~G
+ source "https://gem.repo1"
+ gem "rake"
+ G
+
+ lockfile <<~L
+ GEM
+ remote: https://rubygems.org/
+ specs:
+ rake (10.3.2)
- it "shows a deprecation" do
- bundle "install"
+ PLATFORMS
+ ruby
+ x64-mingw32
- 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.")
+ DEPENDENCIES
+ rake
+
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
end
- pending "fails with a helpful error", bundler: "4"
+ it "warns a helpful error" do
+ bundle "install", raise_on_error: false
+
+ expect(err).to include("Found x64-mingw32 in lockfile, which is deprecated and will be removed in the future.")
+ end
+ end
+
+ context "with a global path source" do
+ before do
+ build_lib "foo"
+
+ install_gemfile <<-G, raise_on_error: false
+ path "#{lib_path("foo-1.0")}"
+ gem 'foo'
+ G
+ end
+
+ it "shows an error" do
+ expect(err).to include("You can no longer specify a path source by itself")
+ end
end
context "when Bundler.setup is run in a ruby script" do
@@ -585,19 +645,41 @@ RSpec.describe "major deprecations" do
context "when `bundler/deployment` is required in a ruby script" do
before do
- ruby <<-RUBY
+ ruby <<-RUBY, raise_on_error: false
require 'bundler/deployment'
RUBY
end
it "should print a capistrano deprecation warning" do
- expect(deprecations).to include("Bundler no longer integrates " \
+ expect(err).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
+ end
+
+ context "when `bundler/capistrano` is required in a ruby script" do
+ before do
+ ruby <<-RUBY, raise_on_error: false
+ require 'bundler/capistrano'
+ RUBY
+ end
+
+ it "fails with a helpful error" do
+ expect(err).to include("[REMOVED] The Bundler task for Capistrano. Please use https://github.com/capistrano/bundler")
+ end
+ end
- pending "fails with a helpful error", bundler: "4"
+ context "when `bundler/vlad` is required in a ruby script" do
+ before do
+ ruby <<-RUBY, raise_on_error: false
+ require 'bundler/vlad'
+ RUBY
+ end
+
+ it "fails with a helpful error" do
+ expect(err).to include("[REMOVED] The Bundler task for Vlad")
+ end
end
context "bundle show" do
@@ -610,14 +692,12 @@ RSpec.describe "major deprecations" do
context "with --outdated flag" do
before do
- bundle "show --outdated"
+ bundle "show --outdated", raise_on_error: false
end
- it "prints a deprecation warning informing about its removal" do
- expect(deprecations).to include("the `--outdated` flag to `bundle show` will be removed in favor of `bundle show --verbose`")
+ it "fails with a helpful message" do
+ expect(err).to include("the `--outdated` flag to `bundle show` has been removed in favor of `bundle show --verbose`")
end
-
- pending "fails with a helpful message", bundler: "4"
end
end
@@ -630,27 +710,32 @@ RSpec.describe "major deprecations" do
end
context "with --install" do
- it "shows a deprecation warning" do
- bundle "remove myrack --install"
+ it "fails with a helpful message" do
+ bundle "remove myrack --install", raise_on_error: false
- expect(err).to include "[DEPRECATED] The `--install` flag has been deprecated. `bundle install` is triggered by default."
+ expect(err).to include "The `--install` flag has been removed. `bundle install` is triggered by default."
end
-
- pending "fails with a helpful message", bundler: "4"
end
end
context "bundle viz" do
before do
- create_file "gems.rb", "source 'https://gem.repo1'"
- bundle "viz"
+ bundle "viz", raise_on_error: false
end
- it "prints a deprecation warning" 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"
+ it "fails with a helpful message" do
+ expect(err).to include "The `viz` command has been renamed to `graph` and moved to a plugin. See https://github.com/rubygems/bundler-graph"
+ end
+ end
+
+ context "bundle inject" do
+ before do
+ bundle "inject", raise_on_error: false
end
- pending "fails with a helpful message", bundler: "4"
+ it "fails with a helpful message" do
+ expect(err).to include "The `inject` command has been replaced by the `add` command"
+ end
end
context "bundle plugin install --local_git" do
@@ -660,20 +745,20 @@ RSpec.describe "major deprecations" do
end
end
- it "prints a deprecation warning" do
- bundle "plugin install foo --local_git #{lib_path("foo-1.0")}"
+ it "fails with a helpful message" do
+ bundle "plugin install foo --local_git #{lib_path("foo-1.0")}", raise_on_error: false
- expect(out).to include("Installed plugin foo")
- expect(deprecations).to include "--local_git is deprecated, use --git"
+ expect(err).to include "--local_git has been removed, use --git"
end
-
- pending "fails with a helpful message", bundler: "4"
end
- describe "deprecating rubocop" do
+ describe "removing 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"
+ bundle_config_global "gem.mit false"
+ bundle_config_global "gem.test false"
+ bundle_config_global "gem.coc false"
+ bundle_config_global "gem.ci false"
+ bundle_config_global "gem.changelog false"
end
context "bundle gem --rubocop" do
@@ -681,9 +766,9 @@ RSpec.describe "major deprecations" do
bundle "gem my_new_gem --rubocop", raise_on_error: false
end
- it "prints a deprecation warning" do
- expect(deprecations).to include \
- "--rubocop is deprecated, use --linter=rubocop"
+ it "prints an error" do
+ expect(err).to include \
+ "--rubocop has been removed, use --linter=rubocop"
end
end
@@ -692,32 +777,22 @@ RSpec.describe "major deprecations" do
bundle "gem my_new_gem --no-rubocop", raise_on_error: false
end
- it "prints a deprecation warning" do
- expect(deprecations).to include \
- "--no-rubocop is deprecated, use --linter"
+ it "prints an error" do
+ expect(err).to include \
+ "--no-rubocop has been removed, use --no-linter"
end
end
+ end
- 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
- end
-
- it "prints a deprecation warning" do
- expect(deprecations).to include \
- "config gem.rubocop is deprecated; we've updated your config to use gem.linter instead"
- end
+ context " bundle gem --ext parameter with no value" do
+ it "prints error when used before gem name" do
+ bundle "gem --ext foo", raise_on_error: false
+ expect(err).to include "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."
end
- 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
- end
-
- it "prints a deprecation warning" do
- expect(deprecations).to include \
- "config gem.rubocop is deprecated; we've updated your config to use gem.linter instead"
- end
+ it "prints error when used after gem name" do
+ bundle "gem foo --ext", raise_on_error: false
+ expect(err).to include "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."
end
end
end
diff --git a/spec/bundler/plugins/command_spec.rb b/spec/bundler/plugins/command_spec.rb
index f8dacb0e51..05d535a70c 100644
--- a/spec/bundler/plugins/command_spec.rb
+++ b/spec/bundler/plugins/command_spec.rb
@@ -53,6 +53,40 @@ RSpec.describe "command plugins" do
expect(out).to eq("You gave me tacos, tofu, lasange")
end
+ it "passes help flag to plugin" do
+ update_repo2 do
+ build_plugin "helpful" do |s|
+ s.write "plugins.rb", <<-RUBY
+ module Helpful
+ class Command
+ Bundler::Plugin::API.command "greet", self
+
+ def exec(command, args)
+ if args.include?("--help") || args.include?("-h")
+ puts "Usage: bundle greet [NAME]"
+ else
+ puts "Hello"
+ end
+ end
+ end
+ end
+ RUBY
+ end
+ end
+
+ bundle "plugin install helpful --source https://gem.repo2"
+ expect(out).to include("Installed plugin helpful")
+
+ bundle "greet --help"
+ expect(out).to eq("Usage: bundle greet [NAME]")
+
+ bundle "greet -h"
+ expect(out).to eq("Usage: bundle greet [NAME]")
+
+ bundle "help greet"
+ expect(out).to eq("Usage: bundle greet [NAME]")
+ end
+
it "raises error on redeclaration of command" do
update_repo2 do
build_plugin "copycat" do |s|
diff --git a/spec/bundler/plugins/hook_spec.rb b/spec/bundler/plugins/hook_spec.rb
index 3f9053bbc8..ad8a4daeff 100644
--- a/spec/bundler/plugins/hook_spec.rb
+++ b/spec/bundler/plugins/hook_spec.rb
@@ -193,6 +193,129 @@ RSpec.describe "hook plugins" do
end
end
+ context "before-eval hook" do
+ before do
+ build_repo2 do
+ build_plugin "before-eval-plugin" do |s|
+ s.write "plugins.rb", <<-RUBY
+ Bundler::Plugin::API.hook Bundler::Plugin::Events::GEM_BEFORE_EVAL do |gemfile, lockfile|
+ puts "hooked eval start of \#{File.basename(gemfile)} to \#{File.basename(lockfile)}"
+ end
+ RUBY
+ end
+ end
+
+ bundle "plugin install before-eval-plugin --source https://gem.repo2"
+ end
+
+ it "runs before the Gemfile is evaluated" do
+ install_gemfile <<-G
+ source "https://gem.repo1"
+ gem "rake"
+ G
+
+ expect(out).to include "hooked eval start of Gemfile to Gemfile.lock"
+ end
+ end
+
+ context "after-eval hook" do
+ before do
+ build_repo2 do
+ build_plugin "after-eval-plugin" do |s|
+ s.write "plugins.rb", <<-RUBY
+ Bundler::Plugin::API.hook Bundler::Plugin::Events::GEM_AFTER_EVAL do |defn|
+ puts "hooked eval after with gems \#{defn.dependencies.map(&:name).join(", ")}"
+ end
+ RUBY
+ end
+ end
+
+ bundle "plugin install after-eval-plugin --source https://gem.repo2"
+ end
+
+ it "runs after the Gemfile is evaluated" do
+ install_gemfile <<-G
+ source "https://gem.repo1"
+ gem "myrack"
+ gem "rake"
+ G
+
+ expect(out).to include "hooked eval after with gems myrack, rake"
+ end
+ end
+
+ context "before-fetch and after-fetch hooks" do
+ before do
+ build_repo2 do
+ build_plugin "fetch-timing-plugin" do |s|
+ s.write "plugins.rb", <<-RUBY
+ @timing_start = nil
+ Bundler::Plugin::API.hook Bundler::Plugin::Events::GEM_BEFORE_FETCH do |spec|
+ @timing_start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
+ puts "gem \#{spec.name} started fetch at \#{@timing_start}"
+ end
+ Bundler::Plugin::API.hook Bundler::Plugin::Events::GEM_AFTER_FETCH do |spec|
+ timing_end = Process.clock_gettime(Process::CLOCK_MONOTONIC)
+ puts "gem \#{spec.name} took \#{timing_end - @timing_start} to fetch"
+ @timing_start = nil
+ end
+ RUBY
+ end
+ end
+
+ bundle "plugin install fetch-timing-plugin --source https://gem.repo2"
+ end
+
+ it "runs around each gem download" do
+ install_gemfile <<-G
+ source "https://gem.repo1"
+ gem "rake"
+ gem "myrack"
+ G
+
+ expect(out).to include "gem rake started fetch at"
+ expect(out).to match(/gem rake took \d+\.\d+ to fetch/)
+ expect(out).to include "gem myrack started fetch at"
+ expect(out).to match(/gem myrack took \d+\.\d+ to fetch/)
+ end
+ end
+
+ context "before-git-fetch and after-git-fetch hooks" do
+ before do
+ build_repo2 do
+ build_plugin "git-fetch-timing-plugin" do |s|
+ s.write "plugins.rb", <<-RUBY
+ @timing_start = nil
+ Bundler::Plugin::API.hook Bundler::Plugin::Events::GIT_BEFORE_FETCH do |source|
+ @timing_start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
+ puts "git source \#{source.name} started fetch at \#{@timing_start}"
+ end
+ Bundler::Plugin::API.hook Bundler::Plugin::Events::GIT_AFTER_FETCH do |source|
+ timing_end = Process.clock_gettime(Process::CLOCK_MONOTONIC)
+ puts "git source \#{source.name} took \#{timing_end - @timing_start} to fetch"
+ @timing_start = nil
+ end
+ RUBY
+ end
+ end
+
+ bundle "plugin install git-fetch-timing-plugin --source https://gem.repo2"
+ end
+
+ it "runs around each git source fetch" do
+ build_git "foo", "1.0", path: lib_path("foo")
+
+ relative_path = lib_path("foo").relative_path_from(bundled_app)
+ install_gemfile <<-G, verbose: true
+ source "https://gem.repo1"
+ gem "foo", :git => "#{relative_path}"
+ G
+
+ expect(out).to include "git source foo started fetch at"
+ expect(out).to match(/git source foo took \d+\.\d+ to fetch/)
+ end
+ end
+
def install_gemfile_and_bundler_require
install_gemfile <<-G
source "https://gem.repo1"
diff --git a/spec/bundler/plugins/install_spec.rb b/spec/bundler/plugins/install_spec.rb
index 1ccefabc0b..dcacf764be 100644
--- a/spec/bundler/plugins/install_spec.rb
+++ b/spec/bundler/plugins/install_spec.rb
@@ -168,7 +168,7 @@ RSpec.describe "bundler plugin install" do
build_repo2 do
build_plugin "chaplin" do |s|
s.write "plugins.rb", <<-RUBY
- raise "I got you man"
+ raise RuntimeError, "threw exception on load"
RUBY
end
end
@@ -203,13 +203,6 @@ RSpec.describe "bundler plugin install" do
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" do
- bundle "plugin install foo --git /phony/path/project --local_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
@@ -272,6 +265,43 @@ RSpec.describe "bundler plugin install" do
plugin_should_be_installed("foo")
end
+ it "overrides the index with the new plugin version" do
+ gemfile <<-G
+ source 'https://gem.repo2'
+ plugin 'foo', "1.0"
+ gem 'myrack', "1.0.0"
+ G
+
+ bundle "install"
+
+ update_repo2 do
+ build_plugin "foo", "2.0.0"
+ end
+
+ gemfile <<-G
+ source 'https://gem.repo2'
+ plugin 'foo', "2.0"
+ gem 'myrack', "1.0.0"
+ G
+
+ bundle "install"
+
+ expected = local_plugin_gem("foo-2.0.0", "lib").to_s
+ expect(Bundler::Plugin.index.load_paths("foo")).to eq([expected])
+ end
+
+ it "respects bundler groups" do
+ gemfile <<-G
+ source 'https://gem.repo2'
+ plugin 'foo'
+ gem 'myrack', "1.0.0"
+ G
+
+ bundle "install", env: { "BUNDLE_WITHOUT" => "default" }
+
+ expect(out).to include("Bundle complete! 1 Gemfile dependency, 0 gems now installed.")
+ end
+
it "accepts plugin version" do
update_repo2 do
build_plugin "foo", "1.1.0"
@@ -341,7 +371,7 @@ RSpec.describe "bundler plugin install" do
gem 'myrack', "1.0.0"
G
- bundle "config set --local deployment true"
+ bundle_config "deployment true"
install_gemfile <<-G
source 'https://gem.repo2'
plugin 'foo'
diff --git a/spec/bundler/plugins/source/example_spec.rb b/spec/bundler/plugins/source/example_spec.rb
index f962446314..4cd4a1a931 100644
--- a/spec/bundler/plugins/source/example_spec.rb
+++ b/spec/bundler/plugins/source/example_spec.rb
@@ -92,7 +92,7 @@ RSpec.describe "real source plugins" do
a-path-gem!
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
G
end
@@ -124,7 +124,6 @@ RSpec.describe "real source plugins" do
let(:uri_hash) { Digest(:SHA1).hexdigest(lib_path("a-path-gem-1.0").to_s) }
it "copies repository to vendor cache and uses it" do
bundle "install"
- bundle "config set cache_all true"
bundle :cache
expect(bundled_app("vendor/cache/a-path-gem-1.0-#{uri_hash}")).to exist
@@ -136,9 +135,8 @@ RSpec.describe "real source plugins" do
end
it "copies repository to vendor cache and uses it even when installed with `path` configured" do
- bundle "config set --local path vendor/bundle"
+ bundle_config "path vendor/bundle"
bundle :install
- bundle "config set cache_all true"
bundle :cache
expect(bundled_app("vendor/cache/a-path-gem-1.0-#{uri_hash}")).to exist
@@ -148,9 +146,8 @@ RSpec.describe "real source plugins" do
end
it "bundler package copies repository to vendor cache" do
- bundle "config set --local path vendor/bundle"
+ bundle_config "path vendor/bundle"
bundle :install
- bundle "config set cache_all true"
bundle :cache
expect(bundled_app("vendor/cache/a-path-gem-1.0-#{uri_hash}")).to exist
@@ -180,7 +177,7 @@ RSpec.describe "real source plugins" do
a-path-gem!
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
G
end
@@ -363,7 +360,7 @@ RSpec.describe "real source plugins" do
ma-gitp-gem!
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
G
end
@@ -389,7 +386,7 @@ RSpec.describe "real source plugins" do
ma-gitp-gem!
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
G
end
@@ -446,7 +443,6 @@ RSpec.describe "real source plugins" do
end
G
- bundle "config set cache_all true"
bundle :cache
expect(bundled_app("vendor/cache/foo-1.0-#{ref}")).to exist
expect(bundled_app("vendor/cache/foo-1.0-#{ref}/.git")).not_to exist
diff --git a/spec/bundler/quality_es_spec.rb b/spec/bundler/quality_es_spec.rb
index 0dbd77e451..e68674c030 100644
--- a/spec/bundler/quality_es_spec.rb
+++ b/spec/bundler/quality_es_spec.rb
@@ -17,7 +17,7 @@ RSpec.describe "La biblioteca si misma" do
]
pattern = /\b#{Regexp.union(useless_words)}\b/i
- File.readlines(filename).each_with_index do |line, number|
+ File.readlines(File.expand_path(filename, source_root)).each_with_index do |line, number|
next unless word_found = pattern.match(line)
failing_line_message << "#{filename}:#{number.succ} contiene '#{word_found}'. Esta palabra tiene un significado subjetivo y es mejor obviarla en textos técnicos."
end
@@ -29,7 +29,7 @@ RSpec.describe "La biblioteca si misma" do
failing_line_message = []
specific_pronouns = /\b(él|ella|ellos|ellas)\b/i
- File.readlines(filename).each_with_index do |line, number|
+ File.readlines(File.expand_path(filename, source_root)).each_with_index do |line, number|
next unless word_found = specific_pronouns.match(line)
failing_line_message << "#{filename}:#{number.succ} contiene '#{word_found}'. Use pronombres más genéricos en la documentación."
end
diff --git a/spec/bundler/quality_spec.rb b/spec/bundler/quality_spec.rb
index 3e5a960a96..16b7f18788 100644
--- a/spec/bundler/quality_spec.rb
+++ b/spec/bundler/quality_spec.rb
@@ -20,6 +20,9 @@ RSpec.describe "The library itself" do
end
def check_for_tab_characters(filename)
+ # Because Go uses hard tabs
+ return if filename.end_with?(".go.tt")
+
failing_lines = []
each_line(filename) do |line, number|
failing_lines << number + 1 if line.include?("\t")
@@ -106,7 +109,7 @@ RSpec.describe "The library itself" do
it "does not include any unresolved merge conflicts" do
error_messages = []
- exempt = %r{lock/lockfile_spec|quality_spec|vcr_cassettes|\.ronn|lockfile_parser\.rb}
+ exempt = %r{lock/lockfile_spec|quality_spec|vcr_cassettes|\.ronn|lockfile_parser}
tracked_files.each do |filename|
next if filename&.match?(exempt)
error_messages << check_for_git_merge_conflicts(filename)
@@ -136,7 +139,6 @@ RSpec.describe "The library itself" do
it "documents all used settings" do
exemptions = %w[
- forget_cli_options
gem.changelog
gem.ci
gem.coc
@@ -164,7 +166,7 @@ RSpec.describe "The library itself" do
line.scan(/Bundler\.settings\[:#{key_pattern}\]/).flatten.each {|s| all_settings[s] << "referenced at `#{filename}:#{number.succ}`" }
end
end
- settings_section = File.read("lib/bundler/man/bundle-config.1.ronn").split(/^## /).find {|section| section.start_with?("LIST OF AVAILABLE KEYS") }
+ settings_section = File.read(source_root.join("lib/bundler/man/bundle-config.1.ronn")).split(/^## /).find {|section| section.start_with?("LIST OF AVAILABLE KEYS") }
documented_settings = settings_section.scan(/^\* `#{key_pattern}`/).flatten
documented_settings.each do |s|
@@ -185,8 +187,8 @@ RSpec.describe "The library itself" do
end
it "can still be built" do
- with_built_bundler do |_gem_path|
- expect(err).to be_empty, "bundler should build as a gem without warnings, but\n#{err}"
+ with_built_bundler do |gem_path|
+ expect(File.exist?(gem_path)).to be true
end
end
@@ -254,6 +256,6 @@ RSpec.describe "The library itself" do
private
def each_line(filename, &block)
- File.readlines(filename, encoding: "UTF-8").each_with_index(&block)
+ File.readlines(File.expand_path(filename, source_root), encoding: "UTF-8").each_with_index(&block)
end
end
diff --git a/spec/bundler/realworld/edgecases_spec.rb b/spec/bundler/realworld/edgecases_spec.rb
index 86b4c91a07..391aa0cef6 100644
--- a/spec/bundler/realworld/edgecases_spec.rb
+++ b/spec/bundler/realworld/edgecases_spec.rb
@@ -16,7 +16,7 @@ RSpec.describe "real world edgecases", realworld: true do
index.search(#{name.dump}).select {|spec| requirement.satisfied_by?(spec.version) }.last
end
if rubygem.nil?
- raise "Could not find #{name} (#{requirement}) on rubygems.org!\n" \
+ raise ArgumentError, "Could not find #{name} (#{requirement}) on rubygems.org!\n" \
"Found specs:\n\#{index.send(:specs).inspect}"
end
puts "#{name} (\#{rubygem.version})"
diff --git a/spec/bundler/realworld/fixtures/tapioca/Gemfile.lock b/spec/bundler/realworld/fixtures/tapioca/Gemfile.lock
index ccb51b6fd3..c2df2f9229 100644
--- a/spec/bundler/realworld/fixtures/tapioca/Gemfile.lock
+++ b/spec/bundler/realworld/fixtures/tapioca/Gemfile.lock
@@ -32,7 +32,7 @@ GEM
thor (>= 1.2.0)
yard-sorbet
thor (1.4.0)
- yard (0.9.37)
+ yard (0.9.42)
yard-sorbet (0.9.0)
sorbet-runtime
yard
@@ -46,4 +46,4 @@ DEPENDENCIES
tapioca
BUNDLED WITH
- 2.8.0.dev
+ 4.1.0.dev
diff --git a/spec/bundler/realworld/fixtures/warbler/Gemfile b/spec/bundler/realworld/fixtures/warbler/Gemfile
index 07dc301d03..5687bbd975 100644
--- a/spec/bundler/realworld/fixtures/warbler/Gemfile
+++ b/spec/bundler/realworld/fixtures/warbler/Gemfile
@@ -4,4 +4,4 @@ source "https://rubygems.org"
gem "demo", path: "./demo"
gem "jruby-jars", "~> 10.0"
-gem "warbler", github: "https://github.com/jruby/warbler/pull/557"
+gem "warbler", "~> 2.1"
diff --git a/spec/bundler/realworld/fixtures/warbler/Gemfile.lock b/spec/bundler/realworld/fixtures/warbler/Gemfile.lock
index 15f9a224e5..05f3bc4e3f 100644
--- a/spec/bundler/realworld/fixtures/warbler/Gemfile.lock
+++ b/spec/bundler/realworld/fixtures/warbler/Gemfile.lock
@@ -1,15 +1,3 @@
-GIT
- remote: https://github.com/jruby/warbler.git
- revision: 3a3a89e9a055ab1badb4e6fee860e8617b4acfe1
- ref: refs/pull/557/head
- specs:
- warbler (2.0.5)
- jruby-jars (>= 9.0.0)
- jruby-rack (>= 1.1.1, < 1.3)
- rake (>= 13.0.3)
- rexml (~> 3.0)
- rubyzip (>= 1.0.0)
-
PATH
remote: demo
specs:
@@ -19,10 +7,18 @@ GEM
remote: https://rubygems.org/
specs:
jruby-jars (10.0.0.1)
- jruby-rack (1.2.2)
+ jruby-rack (1.2.7)
+ ostruct (0.6.3)
rake (13.3.0)
- rexml (3.4.1)
- rubyzip (2.4.1)
+ rexml (3.4.2)
+ rubyzip (3.3.0)
+ warbler (2.1.0)
+ jruby-jars (>= 9.4, < 10.1)
+ jruby-rack (>= 1.2.3, < 1.3)
+ ostruct (~> 0.6.2)
+ rake (~> 13.0, >= 13.0.3)
+ rexml (~> 3.0)
+ rubyzip (>= 3.0.0)
PLATFORMS
arm64-darwin
@@ -33,7 +29,7 @@ PLATFORMS
DEPENDENCIES
demo!
jruby-jars (~> 10.0)
- warbler!
+ warbler (~> 2.1)
BUNDLED WITH
- 2.8.0.dev
+ 4.1.0.dev
diff --git a/spec/bundler/runtime/env_helpers_spec.rb b/spec/bundler/runtime/env_helpers_spec.rb
index 42605b6ea0..c4ebdd1fd2 100644
--- a/spec/bundler/runtime/env_helpers_spec.rb
+++ b/spec/bundler/runtime/env_helpers_spec.rb
@@ -71,10 +71,10 @@ RSpec.describe "env helpers" do
end
end
- shared_examples_for "an unbundling helper" do
+ describe "Bundler.unbundled_env" do
it "should delete BUNDLE_PATH" do
create_file("source.rb", <<-RUBY)
- print #{modified_env}.has_key?('BUNDLE_PATH')
+ print Bundler.unbundled_env.has_key?('BUNDLE_PATH')
RUBY
ENV["BUNDLE_PATH"] = "./foo"
bundle_exec_ruby bundled_app("source.rb")
@@ -83,7 +83,7 @@ RSpec.describe "env helpers" do
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']
+ print Bundler.unbundled_env['RUBYOPT']
RUBY
setup_require = "-r#{lib_dir}/bundler/setup"
ENV["BUNDLER_ORIG_RUBYOPT"] = "-W2 #{setup_require} #{ENV["RUBYOPT"]}"
@@ -93,7 +93,7 @@ RSpec.describe "env helpers" do
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']
+ print Bundler.unbundled_env['RUBYOPT']
RUBY
ENV["BUNDLER_ORIG_RUBYOPT"] = "-W2 -rbundler/setup #{ENV["RUBYOPT"]}"
bundle_exec_ruby bundled_app("source.rb")
@@ -102,7 +102,7 @@ RSpec.describe "env helpers" do
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')
+ print Bundler.unbundled_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")
@@ -111,7 +111,7 @@ RSpec.describe "env helpers" do
it "should restore RUBYLIB", :ruby_repo do
create_file("source.rb", <<-RUBY)
- print #{modified_env}['RUBYLIB']
+ print Bundler.unbundled_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"
@@ -121,7 +121,7 @@ RSpec.describe "env helpers" do
it "should restore the original MANPATH" do
create_file("source.rb", <<-RUBY)
- print #{modified_env}['MANPATH']
+ print Bundler.unbundled_env['MANPATH']
RUBY
ENV["MANPATH"] = "/foo"
ENV["BUNDLER_ORIG_MANPATH"] = "/foo-original"
@@ -130,18 +130,6 @@ RSpec.describe "env helpers" do
end
end
- describe "Bundler.unbundled_env" do
- let(:modified_env) { "Bundler.unbundled_env" }
-
- it_behaves_like "an unbundling helper"
- end
-
- describe "Bundler.clean_env" 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
@@ -158,26 +146,6 @@ RSpec.describe "env helpers" do
end
end
- describe "Bundler.with_clean_env" 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
@@ -209,21 +177,6 @@ RSpec.describe "env helpers" do
end
end
- describe "Bundler.clean_system" 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')
@@ -260,27 +213,6 @@ RSpec.describe "env helpers" do
end
end
- describe "Bundler.clean_exec" 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')
@@ -294,7 +226,7 @@ RSpec.describe "env helpers" do
RUBY
end
- it "runs exec inside with_clean_env" do
+ it "runs exec inside with_unbundled_env" do
skip "Fork not implemented" if Gem.win_platform?
run_bundler_script({ "BUNDLE_FOO" => "bar" }, bundled_app("source.rb"))
diff --git a/spec/bundler/runtime/executable_spec.rb b/spec/bundler/runtime/executable_spec.rb
index 7cab24218f..89cee21b00 100644
--- a/spec/bundler/runtime/executable_spec.rb
+++ b/spec/bundler/runtime/executable_spec.rb
@@ -19,8 +19,9 @@ RSpec.describe "Running bin/* commands" do
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"
+ it "allows the location of the gem stubs to be configured" do
+ bundle_config "bin gbin"
+ bundle "binstubs myrack"
expect(bundled_app("bin")).not_to exist
expect(bundled_app("gbin/myrackup")).to exist
@@ -30,7 +31,8 @@ RSpec.describe "Running bin/* commands" do
end
it "allows absolute paths as a specification of where to install bin stubs" do
- bundle "binstubs myrack", path: tmp("bin")
+ bundle_config "bin #{tmp("bin")}"
+ bundle "binstubs myrack"
gembin tmp("bin/myrackup")
expect(out).to eq("1.0.0")
@@ -96,38 +98,6 @@ RSpec.describe "Running bin/* commands" do
expect(bundled_app("bin/myrackup")).not_to exist
end
- it "allows you to stop installing binstubs" do
- skip "delete permission error" if Gem.win_platform?
-
- bundle "install --binstubs bin/"
- bundled_app("bin/myrackup").rmtree
- bundle "install --binstubs \"\""
-
- expect(bundled_app("bin/myrackup")).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" do
- gemfile <<-G
- source "https://gem.repo1"
- gem "activesupport"
- G
-
- bundle :install, binstubs: "bin"
-
- gemfile <<-G
- source "https://gem.repo1"
- gem "activesupport"
- gem "myrack"
- G
-
- bundle "install"
-
- expect(bundled_app("bin/myrackup")).to exist
- end
-
it "rewrites bins on binstubs with --force option" do
install_gemfile <<-G
source "https://gem.repo1"
diff --git a/spec/bundler/runtime/gem_tasks_spec.rb b/spec/bundler/runtime/gem_tasks_spec.rb
index f87207f0ab..b855142e60 100644
--- a/spec/bundler/runtime/gem_tasks_spec.rb
+++ b/spec/bundler/runtime/gem_tasks_spec.rb
@@ -132,7 +132,7 @@ RSpec.describe "require 'bundler/gem_tasks'" do
before do
define_local_gem_using_gem_tasks
- bundle "config set path vendor/bundle"
+ bundle_config "path vendor/bundle"
end
it "works", :ruby_repo do
diff --git a/spec/bundler/runtime/inline_spec.rb b/spec/bundler/runtime/inline_spec.rb
index cffaab3579..c6f9bbdbd7 100644
--- a/spec/bundler/runtime/inline_spec.rb
+++ b/spec/bundler/runtime/inline_spec.rb
@@ -380,7 +380,7 @@ RSpec.describe "bundler/inline#gemfile" do
rake
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
G
script <<-RUBY
@@ -414,7 +414,7 @@ RSpec.describe "bundler/inline#gemfile" do
rake
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
G
script <<-RUBY
@@ -499,7 +499,7 @@ RSpec.describe "bundler/inline#gemfile" do
end
it "skips platform warnings" do
- bundle "config set --local force_ruby_platform true"
+ bundle_config "force_ruby_platform true"
script <<-RUBY
gemfile(true) do
@@ -512,7 +512,7 @@ RSpec.describe "bundler/inline#gemfile" do
end
it "still installs if the application has `bundle package` no_install config set" do
- bundle "config set --local no_install true"
+ bundle_config "no_install true"
script <<-RUBY
gemfile do
@@ -678,8 +678,54 @@ RSpec.describe "bundler/inline#gemfile" do
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")
+ if Gem.respond_to?(:use_psych?) && Gem.use_psych?
+ expect(out).to include("The psych gem was resolved to 999")
+ expect(out).to include("The stringio gem was resolved to 999")
+ end
+ end
+
+ it "installs a conflicting default gem and non-default gems together" do
+ build_repo4 do
+ build_gem "securerandom", "999"
+ build_gem "myrack", "1.0.0"
+ end
+
+ script <<-RUBY, env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s }
+ gemfile(true) do
+ source "https://gem.repo4"
+ gem "securerandom"
+ gem "myrack"
+ end
+
+ puts MYRACK
+ RUBY
+
+ expect(out).to include("Installing securerandom 999")
+ expect(out).to include("Installing myrack 1.0.0")
+ expect(out).to include("1.0.0")
+ expect(err).to be_empty
+ end
+
+ it "installs a conflicting default gem alongside git sources" do
+ build_repo4 do
+ build_gem "securerandom", "999"
+ end
+
+ build_git "foo", "1.0.0"
+
+ script <<-RUBY, env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s }
+ gemfile(true) do
+ source "https://gem.repo4"
+ gem "securerandom"
+ gem "foo", :git => #{lib_path("foo-1.0.0").to_s.dump}
+ end
+
+ puts FOO
+ RUBY
+
+ expect(out).to include("Installing securerandom 999")
+ expect(out).to include("1.0.0")
+ expect(err).to be_empty
end
it "leaves a lockfile in the same directory as the inline script alone" do
diff --git a/spec/bundler/runtime/load_spec.rb b/spec/bundler/runtime/load_spec.rb
index 15f3d0eb5b..472cde87c5 100644
--- a/spec/bundler/runtime/load_spec.rb
+++ b/spec/bundler/runtime/load_spec.rb
@@ -68,7 +68,7 @@ RSpec.describe "Bundler.load" do
begin
expect { Bundler.load }.to raise_error(Bundler::GemfileNotFound)
ensure
- bundler_gemfile.rmtree if @remove_bundler_gemfile
+ FileUtils.rm_rf bundler_gemfile if @remove_bundler_gemfile
end
end
end
diff --git a/spec/bundler/runtime/platform_spec.rb b/spec/bundler/runtime/platform_spec.rb
index cf1f85286f..6d96758956 100644
--- a/spec/bundler/runtime/platform_spec.rb
+++ b/spec/bundler/runtime/platform_spec.rb
@@ -100,7 +100,7 @@ RSpec.describe "Bundler.setup with multi platform stuff" do
nokogiri (~> 1.11)
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
gemfile <<-G
@@ -143,7 +143,7 @@ RSpec.describe "Bundler.setup with multi platform stuff" do
nokogiri
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
bundle "install"
@@ -219,7 +219,7 @@ RSpec.describe "Bundler.setup with multi platform stuff" do
gem "platform_specific"
G
- bundle "config set force_ruby_platform true"
+ bundle_config "force_ruby_platform true"
bundle "install"
@@ -233,7 +233,7 @@ RSpec.describe "Bundler.setup with multi platform stuff" do
gem "platform_specific"
G
- bundle "config set force_ruby_platform true"
+ bundle_config "force_ruby_platform true"
bundle "install"
@@ -247,7 +247,7 @@ RSpec.describe "Bundler.setup with multi platform stuff" do
gem "platform_specific"
G
- bundle "config set force_ruby_platform true"
+ bundle_config "force_ruby_platform true"
bundle "install"
@@ -282,7 +282,7 @@ RSpec.describe "Bundler.setup with multi platform stuff" do
platform_specific
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
bundle "install"
@@ -316,7 +316,7 @@ RSpec.describe "Bundler.setup with multi platform stuff" do
libv8
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
bundle "install"
@@ -344,7 +344,7 @@ RSpec.describe "Bundler.setup with multi platform stuff" do
platform_specific
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
bundle "install"
@@ -377,7 +377,7 @@ RSpec.describe "Bundler.setup with multi platform stuff" do
gem "platform_specific"
G
- bundle "config set force_ruby_platform true"
+ bundle_config "force_ruby_platform true"
bundle "install"
@@ -398,7 +398,7 @@ RSpec.describe "Bundler.setup with multi platform stuff" do
bundle :lock
simulate_platform "x86-mswin32" do
- bundle "config set force_ruby_platform true"
+ bundle_config "force_ruby_platform true"
bundle "install"
expect(the_bundle).to include_gems "myrack 1.0"
diff --git a/spec/bundler/runtime/self_management_spec.rb b/spec/bundler/runtime/self_management_spec.rb
index fbffd2dca2..176c2a3121 100644
--- a/spec/bundler/runtime/self_management_spec.rb
+++ b/spec/bundler/runtime/self_management_spec.rb
@@ -31,7 +31,7 @@ RSpec.describe "Self management" do
it "installs locked version when using system path and uses it" do
lockfile_bundled_with(previous_minor)
- bundle "config set --local path.system true"
+ bundle_config "path.system true"
bundle "install"
expect(out).to include("Bundler #{current_version} is running, but your lockfile was generated with #{previous_minor}. Installing Bundler #{previous_minor} and restarting using that version.")
@@ -67,7 +67,7 @@ RSpec.describe "Self management" do
it "installs locked version when using local path and uses it" do
lockfile_bundled_with(previous_minor)
- bundle "config set --local path vendor/bundle"
+ bundle_config "path vendor/bundle"
bundle "install"
expect(out).to include("Bundler #{current_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
@@ -108,7 +108,7 @@ RSpec.describe "Self management" do
it "installs locked version when using deployment option and uses it" do
lockfile_bundled_with(previous_minor)
- bundle "config set --local deployment true"
+ bundle_config "deployment true"
bundle "install"
expect(out).to include("Bundler #{current_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
@@ -163,7 +163,7 @@ RSpec.describe "Self management" do
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_config "version #{previous_minor}"
bundle "install"
expect(out).to include("Bundler #{current_version} is running, but your configuration was #{previous_minor}. Installing Bundler #{previous_minor} and restarting using that version.")
@@ -171,10 +171,28 @@ RSpec.describe "Self management" do
expect(out).to eq(previous_minor)
end
+ it "requires the right bundler version from the config and run bundle CLI without re-exec" do
+ unless Bundler.rubygems.provides?(">= 4.1.0.dev")
+ skip "This spec can only run when Gem::BundlerVersionFinder.bundler_versions reads bundler configs"
+ end
+
+ lockfile_bundled_with(current_version)
+
+ bundle_config "version #{previous_minor}"
+ bundle_config "path.system true"
+ bundle "install"
+
+ script = bundled_app("script.rb")
+ create_file(script, "p 'executed once'")
+
+ bundle "-v", env: { "RUBYOPT" => "-r#{script}" }
+ expect(out).to eq(%("executed once"\n9.3.0))
+ 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_config "version system"
bundle "install"
expect(out).not_to match(/restarting using that version/)
@@ -185,7 +203,7 @@ RSpec.describe "Self management" do
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_config "version #{previous_minor}.dev"
bundle "install"
expect(out).not_to match(/restarting using that version/)
diff --git a/spec/bundler/runtime/setup_spec.rb b/spec/bundler/runtime/setup_spec.rb
index 74ada2f8b3..ceb6fcf66a 100644
--- a/spec/bundler/runtime/setup_spec.rb
+++ b/spec/bundler/runtime/setup_spec.rb
@@ -135,7 +135,7 @@ RSpec.describe "Bundler.setup" do
end
it "orders the load path correctly when there are dependencies" do
- bundle "config set path.system true"
+ bundle_config "path.system true"
install_gemfile <<-G
source "https://gem.repo1"
@@ -163,7 +163,7 @@ RSpec.describe "Bundler.setup" do
end
it "falls back to order the load path alphabetically for backwards compatibility" do
- bundle "config set path.system true"
+ bundle_config "path.system true"
install_gemfile <<-G
source "https://gem.repo1"
@@ -286,7 +286,7 @@ RSpec.describe "Bundler.setup" do
G
bundle "install"
- bundle "config set --local deployment true"
+ bundle_config "deployment true"
ENV["BUNDLE_GEMFILE"] = "Gemfile"
ruby <<-R
@@ -303,6 +303,32 @@ RSpec.describe "Bundler.setup" do
expect(out).to eq("WIN")
end
end
+
+ context "user sets it via `config set --local gemfile`" do
+ it "uses the value in the config" do
+ gemfile <<-G
+ source "https://gem.repo1"
+ gem "myrack"
+ G
+
+ gemfile bundled_app("CustomGemfile"), <<-G
+ source "https://gem.repo1"
+ gem "activesupport", "2.3.5"
+ G
+
+ bundle_config "gemfile #{bundled_app("CustomGemfile")}"
+ bundle "install"
+
+ ruby <<-R
+ require 'bundler'
+ Bundler.setup
+ require 'activesupport'
+ puts ACTIVESUPPORT
+ R
+
+ expect(out).to eq("2.3.5")
+ end
+ end
end
it "prioritizes gems in BUNDLE_PATH over gems in GEM_HOME" do
@@ -464,7 +490,7 @@ RSpec.describe "Bundler.setup" do
end
it "does not randomly change the path when specifying --path and the bundle directory becomes read only" do
- bundle "config set --local path vendor/bundle"
+ bundle_config "path vendor/bundle"
bundle :install
with_read_only("#{bundled_app}/**/*") do
@@ -473,7 +499,7 @@ RSpec.describe "Bundler.setup" do
end
it "finds git gem when default bundle path becomes read only" do
- bundle "config set --local path .bundle"
+ bundle_config "path .bundle"
bundle "install"
with_read_only("#{bundled_app(".bundle")}/**/*") do
@@ -568,7 +594,7 @@ RSpec.describe "Bundler.setup" do
describe "when excluding groups" do
it "doesn't change the resolve if --without is used" do
- bundle "config set --local without rails"
+ bundle_config "without rails"
install_gemfile <<-G
source "https://gem.repo1"
gem "activesupport"
@@ -584,7 +610,7 @@ RSpec.describe "Bundler.setup" do
end
it "remembers --without and does not bail on bare Bundler.setup" do
- bundle "config set --local without rails"
+ bundle_config "without rails"
install_gemfile <<-G
source "https://gem.repo1"
gem "activesupport"
@@ -600,7 +626,7 @@ RSpec.describe "Bundler.setup" do
end
it "remembers --without and does not bail on bare Bundler.setup, even in the case of path gems no longer available" do
- bundle "config set --local without development"
+ bundle_config "without development"
path = bundled_app(File.join("vendor", "foo"))
build_lib "foo", path: path
@@ -666,7 +692,7 @@ RSpec.describe "Bundler.setup" do
end
it "remembers --without and does not include groups passed to Bundler.setup" do
- bundle "config set --local without rails"
+ bundle_config "without rails"
install_gemfile <<-G
source "https://gem.repo1"
gem "activesupport"
@@ -728,46 +754,52 @@ RSpec.describe "Bundler.setup" do
G
run <<-R
- File.open(File.join(Gem.dir, "specifications", "broken.gemspec"), "w") do |f|
+ File.open(File.join(Gem.dir, "specifications", "invalid.gemspec"), "w") do |f|
f.write <<-RUBY
# -*- encoding: utf-8 -*-
-# stub: broken 1.0.0 ruby lib
+# stub: invalid 1.0.0 ruby lib
Gem::Specification.new do |s|
- s.name = "broken"
+ s.name = "invalid"
s.version = "1.0.0"
- raise "BROKEN GEMSPEC"
+ s.authors = ["Invalid Author"]
+ s.files = ["lib/invalid.rb"]
+ s.add_dependency "nonexistent-gem", "~> 999.999.999"
+ s.validate!
end
RUBY
end
R
run <<-R
- File.open(File.join(Gem.dir, "specifications", "broken-ext.gemspec"), "w") do |f|
+ File.open(File.join(Gem.dir, "specifications", "invalid-ext.gemspec"), "w") do |f|
f.write <<-RUBY
# -*- encoding: utf-8 -*-
-# stub: broken-ext 1.0.0 ruby lib
+# stub: invalid-ext 1.0.0 ruby lib
# stub: a.ext\\0b.ext
Gem::Specification.new do |s|
- s.name = "broken-ext"
+ s.name = "invalid-ext"
s.version = "1.0.0"
- raise "BROKEN GEMSPEC EXT"
+ s.authors = ["Invalid Author"]
+ s.files = ["lib/invalid.rb"]
+ s.required_ruby_version = "~> 0.8.0"
+ s.validate!
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") {}
+ Bundler::FileUtils.mkdir_p(File.join(extensions_dir, "invalid-ext-1.0.0"))
+ File.open(File.join(extensions_dir, "invalid-ext-1.0.0", "gem.build_complete"), "w") {}
R
run <<-R
- puts "WIN"
+ puts "Success"
R
- expect(out).to eq("WIN")
+ expect(out).to eq("Success")
end
it "ignores empty gem paths" do
@@ -1082,7 +1114,7 @@ end
describe "with system gems in the bundle" do
before :each do
- bundle "config set path.system true"
+ bundle_config "path.system true"
system_gems "myrack-1.0.0"
install_gemfile <<-G
@@ -1151,7 +1183,7 @@ end
bundler_module = class << Bundler; self; end
bundler_module.send(:remove_method, :require)
def Bundler.require(path)
- raise "LOSE"
+ raise StandardError, "didn't use binding from top level"
end
Bundler.load
RUBY
@@ -1196,7 +1228,7 @@ end
end
before do
- bundle "config set --local path.system true"
+ bundle_config "path.system true"
install_gemfile <<-G
source "https://gem.repo1"
@@ -1261,7 +1293,7 @@ end
lock += <<~L
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
lock
@@ -1277,7 +1309,12 @@ end
end
context "is not present" do
- it "does not change the lock" do
+ # Skipped on ruby-core because `ruby "require 'bundler/setup'"` does not
+ # activate bundler as a gem there, so Source::Metadata falls back to a
+ # synthetic spec whose cache_file does not exist on disk and
+ # LockfileGenerator#bundler_checksum drops the bundler checksum, while
+ # the on-disk lockfile still has it.
+ it "does not change the lock", :ruby_repo do
expect { ruby "require 'bundler/setup'" }.not_to change { lockfile }
end
end
@@ -1323,7 +1360,7 @@ end
gem "bar", :git => "#{lib_path("bar-1.0")}"
G
- bundle :install
+ bundle :install, env: { "BUNDLE_LOCKFILE_CHECKSUMS" => "false" }
ruby <<-RUBY, artifice: nil
require 'bundler/setup'
@@ -1480,7 +1517,7 @@ end
gem "net-http-pipeline", "1.0.1"
G
- bundle "config set --local path vendor/bundle"
+ bundle_config "path vendor/bundle"
bundle :install
@@ -1631,7 +1668,7 @@ end
gem "myrack", :group => :test
G
- bundle "config set auto_install 1"
+ bundle_config "auto_install 1"
ruby <<-RUBY, artifice: "compact_index"
require 'bundler/setup'
@@ -1656,7 +1693,7 @@ end
DEPENDENCIES
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
diff --git a/spec/bundler/spec_helper.rb b/spec/bundler/spec_helper.rb
index 87bdf8b9f3..27ddc6a771 100644
--- a/spec/bundler/spec_helper.rb
+++ b/spec/bundler/spec_helper.rb
@@ -19,10 +19,16 @@ ENV["VISUAL"] = nil
ENV["BUNDLER_EDITOR"] = nil
require "bundler"
+# If we use shared GEM_HOME and install multiple versions, it may cause
+# unexpected test failures.
+gem "diff-lcs", "< 2.0"
+
require "rspec/core"
require "rspec/expectations"
require "rspec/mocks"
require "rspec/support/differ"
+gem "rubygems-generate_index"
+require "rubygems/indexer"
require_relative "support/builders"
require_relative "support/checksums"
@@ -32,6 +38,38 @@ require_relative "support/indexes"
require_relative "support/matchers"
require_relative "support/permissions"
require_relative "support/platforms"
+require_relative "support/shards"
+
+begin
+ raise LoadError if File.exist?(File.expand_path("../../lib/bundler/bundler.gemspec", __dir__))
+
+ gem "simplecov_json_formatter"
+ require "simplecov"
+
+ SimpleCov.start do
+ command_name "bundler:#{Process.pid}"
+ root File.expand_path("../bundler", __dir__)
+ coverage_dir File.expand_path("../coverage", __dir__)
+
+ add_filter "/spec/"
+ add_filter "/test/"
+ add_filter "/lib/rubygems/"
+ add_filter "/lib/bundler/vendor/"
+ add_filter "/tool/"
+ add_filter "/tmp/"
+ add_filter ".gemspec"
+ end
+
+ SimpleCov.print_error_status = false
+ SimpleCov.at_exit do
+ $stdout = File.open(File::NULL, "w")
+ SimpleCov.result.format!
+ ensure
+ $stdout = STDOUT
+ end
+rescue LoadError
+ # SimpleCov is not installed
+end
$debug = false
@@ -50,6 +88,7 @@ RSpec.configure do |config|
config.include Spec::Path
config.include Spec::Platforms
config.include Spec::Permissions
+ config.include Spec::Shards
# Enable flags like --only-failures and --next-failure
config.example_status_persistence_file_path = ".rspec_status"
@@ -85,6 +124,9 @@ RSpec.configure do |config|
require_relative "support/rubygems_ext"
Spec::Rubygems.test_setup
+ # Disable retry delays in tests to speed them up
+ Bundler::Retry.default_base_delay = 0
+
# Simulate bundler has not yet been loaded
ENV.replace(ENV.to_hash.delete_if {|k, _v| k.start_with?(Bundler::EnvironmentPreserver::BUNDLER_PREFIX) })
@@ -94,8 +136,17 @@ RSpec.configure do |config|
ENV["BUNDLE_SILENCE_ROOT_WARNING"] = nil
ENV["RUBYGEMS_GEMDEPS"] = nil
ENV["XDG_CONFIG_HOME"] = nil
+ ENV["XDG_CACHE_HOME"] = nil
ENV["GEMRC"] = nil
+ # Prevent tests from modifying the user's global git config.
+ # GIT_CONFIG_GLOBAL and GIT_CONFIG_NOSYSTEM are available since Git 2.32.
+ git_version = `git --version`[/(\d+\.\d+\.\d+)/, 1]
+ if Gem::Version.new(git_version) >= Gem::Version.new("2.32")
+ ENV["GIT_CONFIG_GLOBAL"] = File.join(ENV["HOME"], ".gitconfig")
+ ENV["GIT_CONFIG_NOSYSTEM"] = "1"
+ end
+
# Don't wrap output in tests
ENV["THOR_COLUMNS"] = "10000"
@@ -123,4 +174,19 @@ RSpec.configure do |config|
ensure
reset!
end
+
+ Spec::Shards::EXAMPLE_MAPPINGS.each do |tag, file_paths|
+ file_pattern = Regexp.union(file_paths.map {|path| Regexp.new(Regexp.escape(path) + "$") })
+
+ config.define_derived_metadata(file_path: file_pattern) do |metadata|
+ metadata[tag] = true
+ end
+ end
+
+ config.before(:context) do |example|
+ metadata = example.class.metadata
+ if metadata[:type] != :aruba && !metadata[:realworld] && metadata.keys.none? {|k| Spec::Shards::EXAMPLE_MAPPINGS.keys.include?(k) }
+ warn "#{metadata[:file_path]} is not assigned to any shard. see spec/support/shards.rb for details."
+ end
+ end unless Spec::Path.ruby_core?
end
diff --git a/spec/bundler/support/artifice/compact_index_cooldown.rb b/spec/bundler/support/artifice/compact_index_cooldown.rb
new file mode 100644
index 0000000000..85e3173c98
--- /dev/null
+++ b/spec/bundler/support/artifice/compact_index_cooldown.rb
@@ -0,0 +1,6 @@
+# frozen_string_literal: true
+
+require_relative "helpers/compact_index_cooldown"
+require_relative "helpers/artifice"
+
+Artifice.activate_with(CompactIndexCooldownAPI)
diff --git a/spec/bundler/support/artifice/compact_index_etag_match.rb b/spec/bundler/support/artifice/compact_index_etag_match.rb
index 08d7b5ec53..6c62166051 100644
--- a/spec/bundler/support/artifice/compact_index_etag_match.rb
+++ b/spec/bundler/support/artifice/compact_index_etag_match.rb
@@ -4,7 +4,7 @@ require_relative "helpers/compact_index"
class CompactIndexEtagMatch < CompactIndexAPI
get "/versions" do
- raise "ETag header should be present" unless env["HTTP_IF_NONE_MATCH"]
+ raise ArgumentError, "ETag header should be present" unless env["HTTP_IF_NONE_MATCH"]
headers "ETag" => env["HTTP_IF_NONE_MATCH"]
status 304
body ""
diff --git a/spec/bundler/support/artifice/helpers/compact_index.rb b/spec/bundler/support/artifice/helpers/compact_index.rb
index e61fe921ec..e684aa8628 100644
--- a/spec/bundler/support/artifice/helpers/compact_index.rb
+++ b/spec/bundler/support/artifice/helpers/compact_index.rb
@@ -2,7 +2,7 @@
require_relative "endpoint"
-$LOAD_PATH.unshift Dir[Spec::Path.scoped_base_system_gem_path.join("gems/compact_index*/lib")].first.to_s
+$LOAD_PATH.unshift Spec::Path.tmp_root.join("compact_index/lib").to_s
require "compact_index"
require "digest"
@@ -90,13 +90,17 @@ class CompactIndexAPI < Endpoint
rescue StandardError
checksum = 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)
+ build_gem_version(spec, deps, checksum)
end
CompactIndex::Gem.new(name, gem_versions)
end
end
end
+
+ def build_gem_version(spec, deps, checksum)
+ 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
end
get "/names" do
diff --git a/spec/bundler/support/artifice/helpers/compact_index_cooldown.rb b/spec/bundler/support/artifice/helpers/compact_index_cooldown.rb
new file mode 100644
index 0000000000..9920fd2c95
--- /dev/null
+++ b/spec/bundler/support/artifice/helpers/compact_index_cooldown.rb
@@ -0,0 +1,13 @@
+# frozen_string_literal: true
+
+require_relative "compact_index"
+
+class CompactIndexCooldownAPI < CompactIndexAPI
+ helpers do
+ def build_gem_version(spec, deps, checksum)
+ created_at = spec.date&.utc&.iso8601
+ CompactIndex::GemVersionV2.new(spec.version.version, spec.platform.to_s, checksum, nil,
+ deps, spec.required_ruby_version.to_s, spec.required_rubygems_version.to_s, created_at)
+ end
+ end
+end
diff --git a/spec/bundler/support/artifice/vcr.rb b/spec/bundler/support/artifice/vcr.rb
index 2386a4c6b7..0bf5ade8f6 100644
--- a/spec/bundler/support/artifice/vcr.rb
+++ b/spec/bundler/support/artifice/vcr.rb
@@ -24,7 +24,7 @@ class BundlerVCRHTTP < Gem::Net::HTTP
end
File.open(USED_CASSETTES_PATH, "a+") do |f|
- f.puts request_pair_paths.map {|path| Pathname.new(path).relative_path_from(Spec::Path.source_root).to_s }.join("\n")
+ f.puts request_pair_paths.map {|path| Pathname.new(path).relative_path_from(Spec::Path.git_root).to_s }.join("\n")
end
if recorded_response?
diff --git a/spec/bundler/support/builders.rb b/spec/bundler/support/builders.rb
index 50fedd38f1..43ab7e053d 100644
--- a/spec/bundler/support/builders.rb
+++ b/spec/bundler/support/builders.rb
@@ -2,6 +2,8 @@
require "bundler/shared_helpers"
require "shellwords"
+require "fileutils"
+require "rubygems/package"
require_relative "build_metadata"
@@ -185,17 +187,25 @@ module Spec
# A repo that has no pre-installed gems included. (The caller completely
# determines the contents with the block.)
+ #
+ # If the repo already exists, `#update_repo` will be called.
def build_repo3(**kwargs, &blk)
- raise "gem_repo3 already exists -- use update_repo3 instead" if File.exist?(gem_repo3)
- build_repo gem_repo3, **kwargs, &blk
+ if File.exist?(gem_repo3)
+ update_repo(gem_repo3, &blk)
+ else
+ build_repo gem_repo3, **kwargs, &blk
+ end
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.
+ #
+ # If the repo already exists, `#udpate_repo` will be called
def build_repo4(**kwargs, &blk)
- raise "gem_repo4 already exists -- use update_repo4 instead" if File.exist?(gem_repo4)
- build_repo gem_repo4, **kwargs, &blk
+ if File.exist?(gem_repo4)
+ update_repo gem_repo4, &blk
+ else
+ build_repo gem_repo4, **kwargs, &blk
+ end
end
def update_repo2(**kwargs, &blk)
@@ -206,10 +216,6 @@ module Spec
update_repo(gem_repo3, &blk)
end
- def update_repo4(&blk)
- update_repo(gem_repo4, &blk)
- end
-
def build_security_repo
build_repo security_repo do
build_gem "myrack"
@@ -277,14 +283,8 @@ module Spec
@_build_path = "#{path}/gems"
@_build_repo = File.basename(path)
yield
- with_gem_path_as scoped_base_system_gem_path do
- Dir[scoped_base_system_gem_path.join("gems/rubygems-generate_index*/lib")].first ||
- raise("Could not find rubygems-generate_index lib directory in #{scoped_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
- end
+ options = { build_compact: build_compact_index }
+ Gem::Indexer.new(path, options).generate_index
ensure
@_build_path = nil
@_build_repo = nil
@@ -423,21 +423,25 @@ module Spec
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
+ @spec = Spec::Path.loaded_gemspec.dup
+ @spec.version = version || Bundler::VERSION
+ end
+
+ def required_ruby_version
+ @spec.required_ruby_version
+ end
+
+ def required_ruby_version=(x)
+ @spec.required_ruby_version = x
end
def _build(options = {})
- full_name = "bundler-#{@version}"
+ full_name = "bundler-#{@spec.version}"
build_path = (options[:build_path] || @context.tmp) + full_name
bundler_path = build_path + "#{full_name}.gem"
- require "fileutils"
FileUtils.mkdir_p build_path
@context.shipped_files.each do |shipped_file|
@@ -449,13 +453,16 @@ module Spec
FileUtils.cp File.expand_path(shipped_file, @context.source_root), target_shipped_file, preserve: true
end
- @context.replace_version_file(@version, dir: build_path)
- @context.replace_changelog(@version, dir: build_path) if options[:released]
- @context.replace_required_ruby_version(@required_ruby_version, dir: build_path) if @required_ruby_version
+ @context.replace_version_file(@spec.version, dir: build_path)
+ @context.replace_changelog(@spec.version, dir: build_path) if options[:released]
- Spec::BuildMetadata.write_build_metadata(dir: build_path, version: @version)
+ Spec::BuildMetadata.write_build_metadata(dir: build_path, version: @spec.version.to_s)
- @context.gem_command "build #{@context.relative_gemspec}", dir: build_path
+ Dir.chdir build_path do
+ Gem::DefaultUserInteraction.use_ui(Gem::SilentUI.new) do
+ Gem::Package.build(@spec)
+ end
+ end
if block_given?
yield(bundler_path)
@@ -463,7 +470,7 @@ module Spec
FileUtils.mv bundler_path, options[:path]
end
ensure
- build_path.rmtree
+ FileUtils.rm_rf build_path
end
end
@@ -657,9 +664,9 @@ module Spec
Bundler.rubygems.build(@spec, opts[:skip_validation])
end
elsif opts[:skip_validation]
- @context.gem_command "build --force #{@spec.name}", dir: lib_path
+ Dir.chdir(lib_path) { Gem::Package.build(@spec, true) }
else
- @context.gem_command "build #{@spec.name}", dir: lib_path, allowed_warning: opts[:allowed_warning]
+ Dir.chdir(lib_path) { Gem::Package.build(@spec) }
end
gem_path = File.expand_path("#{@spec.full_name}.gem", lib_path)
@@ -688,54 +695,54 @@ module Spec
TEST_CERT = <<~CERT
-----BEGIN CERTIFICATE-----
- MIIDMjCCAhqgAwIBAgIBATANBgkqhkiG9w0BAQUFADAnMQwwCgYDVQQDDAN5b3Ux
+ MIIDNTCCAh2gAwIBAgIBATANBgkqhkiG9w0BAQsFADAnMQwwCgYDVQQDDAN5b3Ux
FzAVBgoJkiaJk/IsZAEZFgdleGFtcGxlMB4XDTE1MDIwODAwMTIyM1oXDTQyMDYy
NTAwMTIyM1owJzEMMAoGA1UEAwwDeW91MRcwFQYKCZImiZPyLGQBGRYHZXhhbXBs
- ZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANlvFdpN43c4DMS9Jo06
- m0a7k3bQ3HWQ1yrYhZMi77F1F73NpBknYHIzDktQpGn6hs/4QFJT4m4zNEBF47UL
- jHU5nTK5rjkS3niGYUjvh3ZEzVeo9zHUlD/UwflDo4ALl3TSo2KY/KdPS/UTdLXL
- ajkQvaVJtEDgBPE3DPhlj5whp+Ik3mDHej7qpV6F502leAwYaFyOtlEG/ZGNG+nZ
- L0clH0j77HpP42AylHDi+vakEM3xcjo9BeWQ6Vkboic93c9RTt6CWBWxMQP7Nol1
- MOebz9XOSQclxpxWteXNfPRtMdAhmRl76SMI8ywzThNPpa4EH/yz34ftebVOgKyM
- nd0CAwEAAaNpMGcwCQYDVR0TBAIwADALBgNVHQ8EBAMCBLAwHQYDVR0OBBYEFA7D
- n9qo0np23qi3aOYuAAPn/5IdMBYGA1UdEQQPMA2BC3lvdUBleGFtcGxlMBYGA1Ud
- EgQPMA2BC3lvdUBleGFtcGxlMA0GCSqGSIb3DQEBBQUAA4IBAQA7Gyk62sWOUX/N
- vk4tJrgKESph6Ns8+E36A7n3jt8zCep8ldzMvwTWquf9iqhsC68FilEoaDnUlWw7
- d6oNuaFkv7zfrWGLlvqQJC+cu2X5EpcCksg5oRp8VNbwJysJ6JgwosxzROII8eXc
- R+j1j6mDvQYqig2QOnzf480pjaqbP+tspfDFZbhKPrgM3Blrb3ZYuFpv4zkqI7aB
- 6fuk2DUhNO1CuwrJA84TqC+jGo73bDKaT5hrIDiaJRrN5+zcWja2uEWrj5jSbep4
- oXdEdyH73hOHMBP40uds3PqnUsxEJhzjB2sCCe1geV24kw9J4m7EQXPVkUKDgKrt
- LlpDmOoo
+ ZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMkupYkg3Nd1oXM3fo0d
+ mVJBWNrni88lKDuIIQXwcKe6XCgiloZG708ecLTOws9+o9MkTl9Wtpf/WGXT98NK
+ EPUYakd2Fv1SuD1jWYlP7iDR6hB3RkWBm5ziujYftVJ4ZrPD42PLjDASvlh75Tvr
+ MeM7yq/qkcgNsd9dQyUvMNPks3tla9je7Dt7Auli2IN3CNXys7gIOfwJH0Bb/M6t
+ y7oUfpoUKAfLzwe61abztgDu1lSNgdFBM1kcxYflyh/FkX5TlAcWeAXzLrnxAXGR
+ UxXrxW4oPC+kZi/pDRBd7X4zQDx7bCmr1+FsS3M05i3w5E08Tt9iKRk4V8nCmE4i
+ k6UCAwEAAaNsMGowCQYDVR0TBAIwADAOBgNVHQ8BAf8EBAMCB4AwHQYDVR0OBBYE
+ FOOOFw5TNAqt/TcRRZEU3Dg/58XuMBYGA1UdEQQPMA2BC3lvdUBleGFtcGxlMBYG
+ A1UdEgQPMA2BC3lvdUBleGFtcGxlMA0GCSqGSIb3DQEBCwUAA4IBAQAy3xnmobxU
+ 1SyhHvoIXTJmG0wt1DQ/Dqwjy362LpEf1UHt29wtg1Mph58eVtl93z5Vd2t4/O77
+ E2BHpSu9ujc6/Br4+2uA/Qk/xRyLBtZAwty6J4uFvOOg985HonN+RCUZbKSUTmtA
+ TZvNtIDAZFQ8Tu75K4gIBxDcz7biGi4i1VJ3F3GNCNeossr9IQwKvb+UWFq14U5R
+ IzUnGgMIzcjUG2kKQvddRD1CjS+egtcLvShbOfm5bs4w4rfQ2FPF+Aaf9v7fxa/c
+ Jrf3K+cB19eAy7O4nlPG1xurvnZd0QpqRk++werrBuKe1Pgga7YBLePfJhzwqcZv
+ wVOSsB870yeO
-----END CERTIFICATE-----
CERT
TEST_PKEY = <<~PKEY
-----BEGIN RSA PRIVATE KEY-----
- MIIEowIBAAKCAQEA2W8V2k3jdzgMxL0mjTqbRruTdtDcdZDXKtiFkyLvsXUXvc2k
- GSdgcjMOS1CkafqGz/hAUlPibjM0QEXjtQuMdTmdMrmuORLeeIZhSO+HdkTNV6j3
- MdSUP9TB+UOjgAuXdNKjYpj8p09L9RN0tctqORC9pUm0QOAE8TcM+GWPnCGn4iTe
- YMd6PuqlXoXnTaV4DBhoXI62UQb9kY0b6dkvRyUfSPvsek/jYDKUcOL69qQQzfFy
- Oj0F5ZDpWRuiJz3dz1FO3oJYFbExA/s2iXUw55vP1c5JByXGnFa15c189G0x0CGZ
- GXvpIwjzLDNOE0+lrgQf/LPfh+15tU6ArIyd3QIDAQABAoIBACbDqz20TS1gDMa2
- gj0DidNedbflHKjJHdNBru7Ad8NHgOgR1YO2hXdWquG6itVqGMbTF4SV9/R1pIcg
- 7qvEV1I+50u31tvOBWOvcYCzU48+TO2n7gowQA3xPHPYHzog1uu48fAOHl0lwgD7
- av9OOK3b0jO5pC08wyTOD73pPWU0NrkTh2+N364leIi1pNuI1z4V+nEuIIm7XpVd
- 5V4sXidMTiEMJwE6baEDfTjHKaoRndXrrPo3ryIXmcX7Ag1SwAQwF5fBCRToCgIx
- dszEZB1bJD5gA6r+eGnJLB/F60nK607az5o3EdguoB2LKa6q6krpaRCmZU5svvoF
- J7xgBPECgYEA8RIzHAQ3zbaibKdnllBLIgsqGdSzebTLKheFuigRotEV3Or/z5Lg
- k/nVnThWVkTOSRqXTNpJAME6a4KTdcVSxYP+SdZVO1esazHrGb7xPVb7MWSE1cqp
- WEk3Yy8OUOPoPQMc4dyGzd30Mi8IBB6gnFIYOTrpUo0XtkBv8rGGhfsCgYEA5uYn
- 6QgL4NqNT84IXylmMb5ia3iBt6lhxI/A28CDtQvfScl4eYK0IjBwdfG6E1vJgyzg
- nJzv3xEVo9bz+Kq7CcThWpK5JQaPnsV0Q74Wjk0ShHet15txOdJuKImnh5F6lylC
- GTLR9gnptytfMH/uuw4ws0Q2kcg4l5NHKOWOnAcCgYEAvAwIVkhsB0n59Wu4gCZu
- FUZENxYWUk/XUyQ6KnZrG2ih90xQ8+iMyqFOIm/52R2fFKNrdoWoALC6E3ct8+ZS
- pMRLrelFXx8K3it4SwMJR2H8XBEfFW4bH0UtsW7Zafv+AunUs9LETP5gKG1LgXsq
- qgXX43yy2LQ61O365YPZfdUCgYBVbTvA3MhARbvYldrFEnUL3GtfZbNgdxuD9Mee
- xig0eJMBIrgfBLuOlqtVB70XYnM4xAbKCso4loKSHnofO1N99siFkRlM2JOUY2tz
- kMWZmmxKdFjuF0WZ5f/5oYxI/QsFGC+rUQEbbWl56mMKd5qkvEhKWudxoklF0yiV
- ufC8SwKBgDWb8iWqWN5a/kfvKoxFcDM74UHk/SeKMGAL+ujKLf58F+CbweM5pX9C
- EUsxeoUEraVWTiyFVNqD81rCdceus9TdBj0ZIK1vUttaRZyrMAwF0uQSfjtxsOpd
- l69BkyvzjgDPkmOHVGiSZDLi3YDvypbUpo6LOy4v5rVg5U2F/A0v
+ MIIEowIBAAKCAQEAyS6liSDc13Whczd+jR2ZUkFY2ueLzyUoO4ghBfBwp7pcKCKW
+ hkbvTx5wtM7Cz36j0yROX1a2l/9YZdP3w0oQ9RhqR3YW/VK4PWNZiU/uINHqEHdG
+ RYGbnOK6Nh+1Unhms8PjY8uMMBK+WHvlO+sx4zvKr+qRyA2x311DJS8w0+Sze2Vr
+ 2N7sO3sC6WLYg3cI1fKzuAg5/AkfQFv8zq3LuhR+mhQoB8vPB7rVpvO2AO7WVI2B
+ 0UEzWRzFh+XKH8WRflOUBxZ4BfMuufEBcZFTFevFbig8L6RmL+kNEF3tfjNAPHts
+ KavX4WxLczTmLfDkTTxO32IpGThXycKYTiKTpQIDAQABAoIBABpyrHEWRed5X7aN
+ kXCBzKSN/LLChT8VNnB6bppLnV501yVbmV2hDlg2EJZkfCMvwIptwnPcKs2uqZ4G
+ u2gMC6X9Bgkg/YK4u4nZJBiIzoMNYEUL48wYGYS1dcokaapO3nQ8M1+XjyAexrFL
+ 5btL1IIisScRTQWiGe6FtzcN43sSNkBISyDF5zG4Kodynqi0ekITmMl2q5XLWcsM
+ KBnmZcRFEmFae2YYczVy8SXNApkZEvN69znvAX1iDNnZ3sJFchXo1nRPt4stOOKw
+ mydgIYqaNQ22aF3OkblvoA4Y4m+X2Qt1sfkryKa5xTT7DSE81GmmazNI64EWqtES
+ 6Xde6P0CgYEA+V1vuSnE5fWX188abWMbVwNMC71WfHbntFmI+qwWYPEpickm+RGX
+ DDfXs5unlVX4KUmjfplgavO29op1GZTuD9TlRnUAV0+0aJnNq4DY6XsHfD84qsBr
+ gQGEHeJ1cMGNDnZR/EV3eudMalj9Qjpx9NoXNzMykb0/SUYZQemiqwcCgYEAzokC
+ s0GoHVJqan4dfU0h0G5QPncrajW9DGG1ySxK/A2eqbVB8W2ZQx39OS26/Gydb31p
+ cR7zm8PZpNbzLqlIMEbD4F6q22xxvYVtDx/HHPjxHMi87yxwQ9uLDUHoMa/LciTO
+ djv3D1xTDDGxbpjmsdmINetunAs3htxku7JY5PMCgYBs3/TVvXzwgmhHm28Ib4sS
+ VKgxP/uw4CGORsFd4SDsNp9SP3c6rAltFjyheMaUlzKApFwz/DdyuvIZdp5mCvZe
+ BzALsS3y8SPtv6lixiDu3/6GqvvM4bKOYuESQzvPfVJfDB4DrTjben2MuUnqTqZO
+ p6IXQc1EgIJPNcH1W1LgpQKBgAKZlPAevngIBpDqn4JpSyititMOevxuSr/yJvCu
+ Xw9HOJ0YTAk3APvoT7y9h6IP1/eEU6R56EUotP+vOQZ4WRFKgsK7TllOxyvElzfe
+ hYom1BoxqLc2Dv+7rsdu8fZWKTB5qCOy44xM9DquEXa79AN/IojTOuQ5++v1sErw
+ ls/jAoGBANneGe9ogN51mYkrLyg1fhU1i24gFRq+sPGEvsCUoE6Vjw/lawQQ80T8
+ v45TFqvhoGpgznqy3qxDJyguquZg6HN2yW6HE2Dvk7uk3XogcjdXgNDmWqb2j0eE
+ z9pKzHCqfwNVPuYf44Znyo2YeyZ2kHn42MU73oXuFshUs3QHcH+P
-----END RSA PRIVATE KEY-----
PKEY
end
diff --git a/spec/bundler/support/checksums.rb b/spec/bundler/support/checksums.rb
index 8e0dea4a71..7b69bba668 100644
--- a/spec/bundler/support/checksums.rb
+++ b/spec/bundler/support/checksums.rb
@@ -3,6 +3,8 @@
module Spec
module Checksums
class ChecksumsBuilder
+ attr_reader :bundler_registered
+
def initialize(enabled = true, &block)
@enabled = enabled
@checksums = {}
@@ -14,9 +16,11 @@ module Spec
@checksums = @checksums.dup
end
- def checksum(repo, name, version, platform = Gem::Platform::RUBY)
+ def checksum(repo, name, version, platform = Gem::Platform::RUBY, folder = "gems")
+ @bundler_registered = true if name == "bundler"
+
name_tuple = Gem::NameTuple.new(name, version, platform)
- gem_file = File.join(repo, "gems", "#{name_tuple.full_name}.gem")
+ gem_file = File.join(repo, folder, "#{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
@@ -50,21 +54,26 @@ module Spec
end
end
- def checksums_section(enabled = true, &block)
- ChecksumsBuilder.new(enabled, &block)
+ def checksums_section(enabled = true, bundler_checksum: true, &block)
+ ChecksumsBuilder.new(enabled, &block).tap do |builder|
+ next if builder.bundler_registered || !bundler_checksum
+
+ next if Bundler::VERSION.to_s.end_with?(".dev")
+ builder.checksum(system_gem_path, "bundler", Bundler::VERSION, Gem::Platform::RUBY, "cache")
+ end
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_4_mode?
+ enabled = true
end
checksums_section(enabled, &block)
end
def checksum_to_lock(*args)
- checksums_section do |c|
+ checksums_section(true, bundler_checksum: false) do |c|
c.checksum(*args)
end.to_s.sub(/^CHECKSUMS\n/, "").strip
end
diff --git a/spec/bundler/support/command_execution.rb b/spec/bundler/support/command_execution.rb
index 979a46549a..e2915b996d 100644
--- a/spec/bundler/support/command_execution.rb
+++ b/spec/bundler/support/command_execution.rb
@@ -72,7 +72,7 @@ module Spec
attr_reader :failure_reason
def normalize(string)
- string.force_encoding(Encoding::UTF_8).strip.gsub("\r\n", "\n")
+ string.dup.force_encoding(Encoding::UTF_8).scrub.strip.gsub("\r\n", "\n")
end
end
end
diff --git a/spec/bundler/support/filters.rb b/spec/bundler/support/filters.rb
index 6e94b10e32..2be25b4a78 100644
--- a/spec/bundler/support/filters.rb
+++ b/spec/bundler/support/filters.rb
@@ -18,10 +18,13 @@ class RequirementChecker < Proc
end
end
+git_version = Gem::Version.new(`git --version`[/(\d+\.\d+\.\d+)/, 1])
+
RSpec.configure do |config|
config.filter_run_excluding realworld: true
config.filter_run_excluding rubygems: RequirementChecker.against(Gem.rubygems_version)
+ config.filter_run_excluding git: RequirementChecker.against(git_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?
@@ -29,10 +32,11 @@ RSpec.configure do |config|
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 mri_only: RUBY_ENGINE != "ruby"
config.filter_run_when_matching :focus unless ENV["CI"]
config.before(:each, :bundler) do |example|
- bundle "config simulate_version #{example.metadata[:bundler]}"
+ bundle_config "simulate_version #{example.metadata[:bundler]}"
end
end
diff --git a/spec/bundler/support/helpers.rb b/spec/bundler/support/helpers.rb
index 438037e08c..b0d4b5008b 100644
--- a/spec/bundler/support/helpers.rb
+++ b/spec/bundler/support/helpers.rb
@@ -25,11 +25,12 @@ module Spec
FileUtils.mkdir_p(home)
FileUtils.mkdir_p(tmpdir)
Bundler.reset!
+ Bundler::Source::Git::GitProxy.reset
Gem.clear_paths
end
- def the_bundle(*args)
- TheBundle.new(*args)
+ def the_bundle
+ TheBundle.new
end
MAJOR_DEPRECATION = /^\[DEPRECATED\]\s*/
@@ -39,7 +40,7 @@ module Spec
end
def deprecations
- err.split("\n").select {|l| l =~ MAJOR_DEPRECATION }.join("\n").split(MAJOR_DEPRECATION)
+ err.split("\n").filter_map {|l| l.sub(MAJOR_DEPRECATION, "") if l.match?(MAJOR_DEPRECATION) }
end
def run(cmd, *args)
@@ -54,7 +55,7 @@ module Spec
begin
#{ruby}
rescue LoadError => e
- warn "ZOMG LOAD ERROR" if e.message.include?("-- #{name}")
+ warn e.message if e.message.include?("-- #{name}")
end
RUBY
opts = args.last.is_a?(Hash) ? args.pop : {}
@@ -132,7 +133,7 @@ module Spec
begin
#{ruby}
rescue LoadError => e
- warn "ZOMG LOAD ERROR" if e.message.include?("-- #{name}")
+ warn e.message if e.message.include?("-- #{name}")
end
R
end
@@ -182,25 +183,6 @@ module Spec
sys_exec(cmd.to_s, options)
end
- def gem_command(command, options = {})
- env = options[:env] || {}
- env["RUBYOPT"] = opt_add(opt_add("-r#{hax}", env["RUBYOPT"]), ENV["RUBYOPT"])
- options[:env] = env
-
- # Sometimes `gem install` commands hang at dns resolution, which has a
- # default timeout of 60 seconds. When that happens, the timeout for a
- # command is expired too. So give `gem install` commands a bit more time.
- options[:timeout] = 120
-
- allowed_warning = options.delete(:allowed_warning)
-
- output = sys_exec("#{Path.gem_bin} #{command}", options)
- stderr = last_command.stderr
-
- raise stderr if stderr.include?("WARNING") && !allowed_rubygems_warning?(stderr, allowed_warning)
- output
- end
-
def sys_exec(cmd, options = {}, &block)
env = options[:env] || {}
env["RUBYOPT"] = opt_add(opt_add("-r#{spec_dir}/support/switch_rubygems.rb", env["RUBYOPT"]), ENV["RUBYOPT"])
@@ -209,7 +191,12 @@ module Spec
sh(cmd, options, &block)
end
- def config(config = nil, path = bundled_app(".bundle/config"))
+ def bundle_config(config = nil, path = bundled_app(".bundle/config"))
+ if config.is_a?(String)
+ key, value = config.split(" ", 2)
+ config = { Bundler::Settings.key_for(key) => value }
+ end
+
current = File.exist?(path) ? Psych.load_file(path) : {}
return current unless config
@@ -226,8 +213,8 @@ module Spec
new_config
end
- def global_config(config = nil)
- config(config, home(".bundle/config"))
+ def bundle_config_global(config = nil)
+ bundle_config(config, home(".bundle/config"))
end
def create_file(path, contents = "")
@@ -330,12 +317,86 @@ module Spec
end
def install_gem(path, install_dir, default = false)
- raise "OMG `#{path}` does not exist!" unless File.exist?(path)
+ raise ArgumentError, "`#{path}` does not exist!" unless File.exist?(path)
+
+ require "rubygems/installer"
+
+ with_simulated_platform do
+ installer = Gem::Installer.at(
+ path.to_s,
+ install_dir: install_dir.to_s,
+ document: [],
+ ignore_dependencies: true,
+ wrappers: true,
+ env_shebang: true,
+ force: true
+ )
+ installer.install
+ end
+
+ if default
+ gem = Pathname.new(path).basename.to_s.match(/(.*)\.gem/)[1]
+
+ # Revert Gem::Installer#write_spec and apply Gem::Installer#write_default_spec
+ FileUtils.mkdir_p File.join(install_dir, "specifications", "default")
+ File.rename File.join(install_dir, "specifications", gem + ".gemspec"),
+ File.join(install_dir, "specifications", "default", gem + ".gemspec")
+
+ # Revert Gem::Installer#write_cache_file
+ File.delete File.join(install_dir, "cache", gem + ".gem")
+ end
+ end
+
+ def uninstall_gem(name, options = {})
+ require "rubygems/uninstaller"
+
+ gem_home = options.dig(:env, "GEM_HOME") || system_gem_path.to_s
+
+ with_env_vars("GEM_HOME" => gem_home) do
+ Gem.clear_paths
+
+ uninstaller = Gem::Uninstaller.new(
+ name,
+ ignore: true,
+ executables: true,
+ all: true
+ )
+ uninstaller.uninstall
+ ensure
+ Gem.clear_paths
+ end
+ end
+
+ def installed_gems_list(options = {})
+ gem_home = options.dig(:env, "GEM_HOME") || system_gem_path.to_s
+
+ # Temporarily set GEM_HOME for the command
+ old_gem_home = ENV["GEM_HOME"]
+ ENV["GEM_HOME"] = gem_home
+ Gem.clear_paths
- args = "--no-document --ignore-dependencies --verbose --local --install-dir #{install_dir}"
- args += " --default" if default
+ begin
+ require "rubygems/commands/list_command"
+
+ # Capture output from the list command
+ require "stringio"
+ output_io = StringIO.new
+ cmd = Gem::Commands::ListCommand.new
+ cmd.ui = Gem::StreamUI.new(StringIO.new, output_io, StringIO.new, false)
+ cmd.invoke
+ output = output_io.string.strip
+ ensure
+ ENV["GEM_HOME"] = old_gem_home
+ Gem.clear_paths
+ end
- gem_command "install #{args} '#{path}'"
+ # Create a fake command execution so `out` helper works
+ command_execution = Spec::CommandExecution.new("gem list", timeout: 60)
+ command_execution.original_stdout << output
+ command_execution.exitstatus = 0
+ command_executions << command_execution
+
+ output
end
def with_built_bundler(version = nil, opts = {}, &block)
@@ -369,6 +430,36 @@ module Spec
ENV.replace(backup)
end
+ # Simulate the platform set by BUNDLER_SPEC_PLATFORM for in-process
+ # operations, mirroring what hax.rb does for subprocesses.
+ def with_simulated_platform
+ spec_platform = ENV["BUNDLER_SPEC_PLATFORM"]
+ unless spec_platform
+ return yield
+ end
+
+ old_arch = RbConfig::CONFIG["arch"]
+ old_host_os = RbConfig::CONFIG["host_os"]
+
+ if /mingw|mswin/.match?(spec_platform)
+ Gem.class_variable_set(:@@win_platform, nil) # rubocop:disable Style/ClassVars
+ RbConfig::CONFIG["host_os"] = spec_platform.gsub(/^[^-]+-/, "").tr("-", "_")
+ end
+
+ RbConfig::CONFIG["arch"] = spec_platform
+ Gem::Platform.instance_variable_set(:@local, nil)
+ Gem.instance_variable_set(:@platforms, [])
+
+ yield
+ ensure
+ if spec_platform
+ RbConfig::CONFIG["arch"] = old_arch
+ RbConfig::CONFIG["host_os"] = old_host_os
+ Gem::Platform.instance_variable_set(:@local, nil)
+ Gem.instance_variable_set(:@platforms, [])
+ end
+ end
+
def with_path_added(path)
with_path_as([path.to_s, ENV["PATH"]].join(File::PATH_SEPARATOR)) do
yield
@@ -410,7 +501,7 @@ module Spec
gems.each do |g|
path = "#{gem_repo}/gems/#{g}.gem"
- raise "OMG `#{path}` does not exist!" unless File.exist?(path)
+ raise ArgumentError, "`#{path}` does not exist!" unless File.exist?(path)
FileUtils.cp(path, "#{bundled_app}/vendor/cache")
end
end
@@ -526,14 +617,6 @@ module Spec
private
- def allowed_rubygems_warning?(text, extra_allowed_warning)
- allowed_warnings = ["open-ended", "is a symlink", "rake based", "expected RubyGems version"]
- allowed_warnings << extra_allowed_warning if extra_allowed_warning
- allowed_warnings.any? do |warning|
- text.include?(warning)
- end
- end
-
def match_source(contents)
match = /source ["']?(?<source>http[^"']+)["']?/.match(contents)
return unless match
diff --git a/spec/bundler/support/matchers.rb b/spec/bundler/support/matchers.rb
index 9f311fc0d7..5a3c38a4db 100644
--- a/spec/bundler/support/matchers.rb
+++ b/spec/bundler/support/matchers.rb
@@ -52,7 +52,7 @@ module Spec
end
def self.define_compound_matcher(matcher, preconditions, &declarations)
- raise "Must have preconditions to define a compound matcher" if preconditions.empty?
+ raise ArgumentError, "Must have preconditions to define a compound matcher" if preconditions.empty?
define_method(matcher) do |*expected, &block_arg|
Precondition.new(
RSpec::Matchers::DSL::Matcher.new(matcher, declarations, self, *expected, &block_arg),
diff --git a/spec/bundler/support/path.rb b/spec/bundler/support/path.rb
index cc750f55d8..2e6486412f 100644
--- a/spec/bundler/support/path.rb
+++ b/spec/bundler/support/path.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require "pathname"
+require "pathname" unless defined?(Pathname)
require "rbconfig"
require_relative "env"
@@ -10,7 +10,7 @@ module Spec
include Spec::Env
def source_root
- @source_root ||= Pathname.new(ruby_core? ? "../../.." : "../..").expand_path(__dir__)
+ @source_root ||= Pathname.new(ruby_core? ? "../../.." : "../../bundler").expand_path(__dir__)
end
def root
@@ -50,7 +50,7 @@ module Spec
end
def bindir
- @bindir ||= source_root.join(ruby_core? ? "spec/bin" : "bin")
+ @bindir ||= source_root.join(ruby_core? ? "spec/bin" : "../bin")
end
def exedir
@@ -76,7 +76,7 @@ module Spec
end
def spec_dir
- @spec_dir ||= source_root.join(ruby_core? ? "spec/bundler" : "spec")
+ @spec_dir ||= source_root.join(ruby_core? ? "spec/bundler" : "../spec")
end
def man_dir
@@ -114,7 +114,17 @@ module Spec
end
def tmp_root
- source_root.join("tmp")
+ if ruby_core? && (tmpdir = ENV["TMPDIR"])
+ # Use realpath to resolve any symlinks in TMPDIR (e.g., on macOS /var -> /private/var)
+ real = begin
+ File.realpath(tmpdir)
+ rescue Errno::ENOENT, Errno::EACCES
+ tmpdir
+ end
+ Pathname(real)
+ else
+ (ruby_core? ? source_root : source_root.parent).join("tmp")
+ end
end
# Bump this version whenever you make a breaking change to the spec setup
@@ -303,14 +313,23 @@ module Spec
deps = %w[
mustermann
rack
+ rack-protection
+ rack-session
tilt
sinatra
- ruby2_keywords
base64
logger
- cgi
+ compact_index
]
- Dir[scoped_base_system_gem_path.join("gems/{#{deps.join(",")}}-*/lib")].map(&:to_s)
+ path = if deps.all? {|dep| !Dir[scoped_base_system_gem_path.join("gems/#{dep}-*")].empty? }
+ scoped_base_system_gem_path
+ elsif ruby_core? && deps.all? {|dep| !Dir[source_root.join(".bundle/gems/#{dep}-*")].empty? }
+ source_root.join(".bundle")
+ else
+ scoped_base_system_gem_path
+ end
+
+ Dir[path.join("gems/{#{deps.join(",")}}-*/lib")].map(&:to_s)
end
private
@@ -326,7 +345,7 @@ module Spec
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? ? "libexec/bundle* lib/bundler lib/bundler.rb spec/bundler man/bundle*" : "lib exe CHANGELOG.md LICENSE.md README.md bundler.gemspec"
end
def lib_tracked_files_glob
diff --git a/spec/bundler/support/rubygems_ext.rb b/spec/bundler/support/rubygems_ext.rb
index 2d681529aa..812dc4deaa 100644
--- a/spec/bundler/support/rubygems_ext.rb
+++ b/spec/bundler/support/rubygems_ext.rb
@@ -43,7 +43,18 @@ module Spec
# 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
+ if Path.ruby_core?
+ if (tmpdir = ENV["TMPDIR"])
+ tmpdir_real = begin
+ File.realpath(tmpdir)
+ rescue Errno::ENOENT, Errno::EACCES
+ tmpdir
+ end
+ ENV["TMPDIR"] = tmpdir_real if tmpdir_real != tmpdir
+ end
+ else
+ ENV["TMPDIR"] = Path.tmpdir.to_s
+ end
require "rubygems/user_interaction"
Gem::DefaultUserInteraction.ui = Gem::SilentUI.new
@@ -62,6 +73,48 @@ module Spec
require_relative "helpers"
Helpers.install_dev_bundler
+
+ install_vendored_compact_index
+ end
+
+ # Vendor `rubygems/rubygems.org#lib/compact_index/` under `tmp/compact_index/`
+ # so the artifice can serve compact-index responses without a runtime gem
+ # dependency. Pinned to a reviewed commit; override with COMPACT_INDEX_REF
+ # to refresh against another ref (the existing vendor copy is discarded).
+ def install_vendored_compact_index
+ target_root = Path.tmp_root.join("compact_index")
+ require "fileutils"
+ FileUtils.mkdir_p(Path.tmp_root)
+
+ files = %w[
+ lib/compact_index.rb
+ lib/compact_index/dependency.rb
+ lib/compact_index/gem.rb
+ lib/compact_index/gem_version.rb
+ lib/compact_index/versions_file.rb
+ ]
+
+ # Serialize installs so parallel test setups don't race on the same
+ # vendor tree, and only skip the download when every file is present so
+ # an interrupted run can't leave a partial copy behind.
+ File.open(Path.tmp_root.join("compact_index.lock"), File::CREAT | File::RDWR) do |lock|
+ lock.flock(File::LOCK_EX)
+
+ FileUtils.rm_rf(target_root) if ENV["COMPACT_INDEX_REF"]
+
+ next if files.all? {|path| File.exist?(target_root.join(path)) }
+
+ require "open-uri"
+ ref = ENV["COMPACT_INDEX_REF"] || "7c68a7b39761c61a66f9299f85b889ec39afc02c"
+ files.each do |path|
+ url = "https://raw.githubusercontent.com/rubygems/rubygems.org/#{ref}/#{path}"
+ target = target_root.join(path)
+ FileUtils.mkdir_p(File.dirname(target))
+ tmp = "#{target}.tmp"
+ File.write(tmp, URI.parse(url).open(&:read))
+ File.rename(tmp, target)
+ end
+ end
end
def check_source_control_changes(success_message:, error_message:)
diff --git a/spec/bundler/support/shards.rb b/spec/bundler/support/shards.rb
new file mode 100644
index 0000000000..ce33896539
--- /dev/null
+++ b/spec/bundler/support/shards.rb
@@ -0,0 +1,200 @@
+# frozen_string_literal: true
+
+# This classifies test files into 4 shards by running `bin/rspec --profile 10000`
+# to ensure balanced execution times. When adding new test files, it is recommended to
+# re-aggregate and adjust the shards to keep them balanced.
+# For now, please add new files to shard 'shard_d'.
+
+module Spec
+ module Shards
+ EXAMPLE_MAPPINGS = {
+ shard_a: [
+ "spec/runtime/setup_spec.rb",
+ "spec/commands/install_spec.rb",
+ "spec/commands/add_spec.rb",
+ "spec/install/gems/compact_index_spec.rb",
+ "spec/commands/config_spec.rb",
+ "spec/commands/pristine_spec.rb",
+ "spec/install/gemfile/path_spec.rb",
+ "spec/update/git_spec.rb",
+ "spec/commands/open_spec.rb",
+ "spec/commands/remove_spec.rb",
+ "spec/commands/show_spec.rb",
+ "spec/plugins/source/example_spec.rb",
+ "spec/commands/console_spec.rb",
+ "spec/runtime/require_spec.rb",
+ "spec/runtime/env_helpers_spec.rb",
+ "spec/runtime/gem_tasks_spec.rb",
+ "spec/install/gemfile_spec.rb",
+ "spec/commands/fund_spec.rb",
+ "spec/commands/init_spec.rb",
+ "spec/bundler/ruby_dsl_spec.rb",
+ "spec/bundler/mirror_spec.rb",
+ "spec/bundler/source/git/git_proxy_spec.rb",
+ "spec/bundler/source_list_spec.rb",
+ "spec/bundler/plugin/installer_spec.rb",
+ "spec/bundler/errors_spec.rb",
+ "spec/bundler/friendly_errors_spec.rb",
+ "spec/resolver/platform_spec.rb",
+ "spec/bundler/fetcher/downloader_spec.rb",
+ "spec/update/force_spec.rb",
+ "spec/bundler/env_spec.rb",
+ "spec/install/gems/mirror_spec.rb",
+ "spec/install/failure_spec.rb",
+ "spec/bundler/yaml_serializer_spec.rb",
+ "spec/bundler/environment_preserver_spec.rb",
+ "spec/install/gemfile/install_if_spec.rb",
+ "spec/install/gems/gemfile_source_header_spec.rb",
+ "spec/bundler/fetcher/base_spec.rb",
+ "spec/bundler/rubygems_integration_spec.rb",
+ "spec/bundler/worker_spec.rb",
+ "spec/bundler/dependency_spec.rb",
+ "spec/bundler/ui_spec.rb",
+ "spec/bundler/plugin/source_list_spec.rb",
+ "spec/bundler/source/path_spec.rb",
+ ],
+ shard_b: [
+ "spec/install/gemfile/git_spec.rb",
+ "spec/install/gems/standalone_spec.rb",
+ "spec/commands/lock_spec.rb",
+ "spec/cache/gems_spec.rb",
+ "spec/other/major_deprecation_spec.rb",
+ "spec/install/gems/dependency_api_spec.rb",
+ "spec/install/gemfile/gemspec_spec.rb",
+ "spec/plugins/install_spec.rb",
+ "spec/commands/binstubs_spec.rb",
+ "spec/install/gems/flex_spec.rb",
+ "spec/runtime/inline_spec.rb",
+ "spec/commands/post_bundle_message_spec.rb",
+ "spec/runtime/executable_spec.rb",
+ "spec/lock/git_spec.rb",
+ "spec/plugins/hook_spec.rb",
+ "spec/install/allow_offline_install_spec.rb",
+ "spec/install/gems/post_install_spec.rb",
+ "spec/install/gemfile/ruby_spec.rb",
+ "spec/install/security_policy_spec.rb",
+ "spec/install/yanked_spec.rb",
+ "spec/update/gemfile_spec.rb",
+ "spec/runtime/load_spec.rb",
+ "spec/plugins/command_spec.rb",
+ "spec/commands/version_spec.rb",
+ "spec/install/prereleases_spec.rb",
+ "spec/bundler/uri_credentials_filter_spec.rb",
+ "spec/bundler/plugin_spec.rb",
+ "spec/install/gems/mirror_probe_spec.rb",
+ "spec/plugins/list_spec.rb",
+ "spec/bundler/compact_index_client/parser_spec.rb",
+ "spec/bundler/gem_version_promoter_spec.rb",
+ "spec/other/cli_dispatch_spec.rb",
+ "spec/bundler/source/rubygems_spec.rb",
+ "spec/cache/platform_spec.rb",
+ "spec/update/gems/fund_spec.rb",
+ "spec/bundler/stub_specification_spec.rb",
+ "spec/bundler/retry_spec.rb",
+ "spec/bundler/installer/spec_installation_spec.rb",
+ "spec/bundler/spec_set_spec.rb",
+ "spec/quality_es_spec.rb",
+ "spec/bundler/index_spec.rb",
+ "spec/other/cli_man_pages_spec.rb",
+ ],
+ shard_c: [
+ "spec/commands/newgem_spec.rb",
+ "spec/commands/exec_spec.rb",
+ "spec/commands/clean_spec.rb",
+ "spec/commands/platform_spec.rb",
+ "spec/cache/git_spec.rb",
+ "spec/install/gemfile/groups_spec.rb",
+ "spec/commands/cache_spec.rb",
+ "spec/commands/check_spec.rb",
+ "spec/commands/list_spec.rb",
+ "spec/install/path_spec.rb",
+ "spec/bundler/cli_spec.rb",
+ "spec/install/bundler_spec.rb",
+ "spec/install/git_spec.rb",
+ "spec/commands/doctor_spec.rb",
+ "spec/bundler/dsl_spec.rb",
+ "spec/install/gems/fund_spec.rb",
+ "spec/install/gems/env_spec.rb",
+ "spec/bundler/ruby_version_spec.rb",
+ "spec/bundler/definition_spec.rb",
+ "spec/install/gemfile/eval_gemfile_spec.rb",
+ "spec/plugins/source_spec.rb",
+ "spec/install/gems/dependency_api_fallback_spec.rb",
+ "spec/plugins/uninstall_spec.rb",
+ "spec/bundler/plugin/index_spec.rb",
+ "spec/bundler/bundler_spec.rb",
+ "spec/bundler/fetcher_spec.rb",
+ "spec/bundler/source/rubygems/remote_spec.rb",
+ "spec/bundler/lockfile_parser_spec.rb",
+ "spec/cache/cache_path_spec.rb",
+ "spec/bundler/source/git_spec.rb",
+ "spec/bundler/source_spec.rb",
+ "spec/commands/ssl_spec.rb",
+ "spec/bundler/fetcher/compact_index_spec.rb",
+ "spec/bundler/plugin/api_spec.rb",
+ "spec/bundler/endpoint_specification_spec.rb",
+ "spec/bundler/fetcher/index_spec.rb",
+ "spec/bundler/settings/validator_spec.rb",
+ "spec/bundler/build_metadata_spec.rb",
+ "spec/bundler/current_ruby_spec.rb",
+ "spec/bundler/installer/gem_installer_spec.rb",
+ "spec/bundler/installer/parallel_installer_spec.rb",
+ "spec/bundler/cli_common_spec.rb",
+ "spec/bundler/ci_detector_spec.rb",
+ ],
+ shard_d: [
+ "spec/bundler/rubygems_ext_spec.rb",
+ "spec/bundler/resolver/cooldown_spec.rb",
+ "spec/install/cooldown_spec.rb",
+ "spec/commands/outdated_spec.rb",
+ "spec/commands/update_spec.rb",
+ "spec/lock/lockfile_spec.rb",
+ "spec/install/deploy_spec.rb",
+ "spec/install/gemfile/sources_spec.rb",
+ "spec/runtime/self_management_spec.rb",
+ "spec/install/gemfile/specific_platform_spec.rb",
+ "spec/commands/info_spec.rb",
+ "spec/install/gems/resolving_spec.rb",
+ "spec/install/gemfile/platform_spec.rb",
+ "spec/bundler/gem_helper_spec.rb",
+ "spec/install/global_cache_spec.rb",
+ "spec/runtime/platform_spec.rb",
+ "spec/update/gems/post_install_spec.rb",
+ "spec/install/gems/native_extensions_spec.rb",
+ "spec/install/force_spec.rb",
+ "spec/cache/path_spec.rb",
+ "spec/install/gemspecs_spec.rb",
+ "spec/commands/help_spec.rb",
+ "spec/bundler/shared_helpers_spec.rb",
+ "spec/bundler/settings_spec.rb",
+ "spec/resolver/basic_spec.rb",
+ "spec/install/gemfile/force_ruby_platform_spec.rb",
+ "spec/commands/licenses_spec.rb",
+ "spec/install/gemfile/lockfile_spec.rb",
+ "spec/bundler/fetcher/dependency_spec.rb",
+ "spec/quality_spec.rb",
+ "spec/bundler/remote_specification_spec.rb",
+ "spec/install/process_lock_spec.rb",
+ "spec/install/binstubs_spec.rb",
+ "spec/bundler/compact_index_client/updater_spec.rb",
+ "spec/bundler/ui/shell_spec.rb",
+ "spec/other/ext_spec.rb",
+ "spec/commands/issue_spec.rb",
+ "spec/update/path_spec.rb",
+ "spec/bundler/plugin/api/source_spec.rb",
+ "spec/install/gems/win32_spec.rb",
+ "spec/bundler/plugin/dsl_spec.rb",
+ "spec/runtime/requiring_spec.rb",
+ "spec/bundler/plugin/events_spec.rb",
+ "spec/bundler/resolver/candidate_spec.rb",
+ "spec/bundler/digest_spec.rb",
+ "spec/bundler/fetcher/gem_remote_fetcher_spec.rb",
+ "spec/bundler/uri_normalizer_spec.rb",
+ "spec/install/gems/no_build_extension_spec.rb",
+ "spec/install/gems/no_install_plugin_spec.rb",
+ "spec/bundler/override_spec.rb",
+ "spec/install/gemfile/override_spec.rb",
+ ],
+ }.freeze
+ end
+end
diff --git a/spec/bundler/support/switch_rubygems.rb b/spec/bundler/support/switch_rubygems.rb
index a138d22333..640b9f83b7 100644
--- a/spec/bundler/support/switch_rubygems.rb
+++ b/spec/bundler/support/switch_rubygems.rb
@@ -1,4 +1,5 @@
# frozen_string_literal: true
require_relative "rubygems_version_manager"
+ENV["RGV"] ||= "."
RubygemsVersionManager.new(ENV["RGV"]).switch
diff --git a/spec/bundler/support/the_bundle.rb b/spec/bundler/support/the_bundle.rb
index bda717f3b0..452abd7d41 100644
--- a/spec/bundler/support/the_bundle.rb
+++ b/spec/bundler/support/the_bundle.rb
@@ -8,10 +8,8 @@ module Spec
attr_accessor :bundle_dir
- def initialize(opts = {})
- opts = opts.dup
- @bundle_dir = Pathname.new(opts.delete(:bundle_dir) { bundled_app })
- raise "Too many options! #{opts}" unless opts.empty?
+ def initialize
+ @bundle_dir = Pathname.new(bundled_app)
end
def to_s
@@ -28,7 +26,7 @@ module Spec
end
def locked_gems
- raise "Cannot read lockfile if it doesn't exist" unless locked?
+ raise ArgumentError, "Cannot read lockfile if it doesn't exist" unless locked?
Bundler::LockfileParser.new(lockfile.read)
end
diff --git a/spec/bundler/update/gemfile_spec.rb b/spec/bundler/update/gemfile_spec.rb
index cb94799061..f8849640b6 100644
--- a/spec/bundler/update/gemfile_spec.rb
+++ b/spec/bundler/update/gemfile_spec.rb
@@ -25,7 +25,7 @@ RSpec.describe "bundle update" do
gem 'myrack'
G
- bundle "config set --local gemfile #{bundled_app("NotGemfile")}"
+ bundle_config "gemfile #{bundled_app("NotGemfile")}"
bundle :install
end
diff --git a/spec/bundler/update/git_spec.rb b/spec/bundler/update/git_spec.rb
index 2cb0abe02f..526e988ab7 100644
--- a/spec/bundler/update/git_spec.rb
+++ b/spec/bundler/update/git_spec.rb
@@ -199,7 +199,7 @@ RSpec.describe "bundle update" do
gem "foo", :git => "#{lib_path("foo-1.0")}"
G
- lib_path("foo-1.0").join(".git").rmtree
+ FileUtils.rm_rf lib_path("foo-1.0").join(".git")
bundle :update, all: true, raise_on_error: false
expect(err).to include(lib_path("foo-1.0").to_s).
@@ -334,7 +334,7 @@ RSpec.describe "bundle update" do
myrack
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
G
end
end
diff --git a/spec/default.mspec b/spec/default.mspec
index 058835cd10..d756dc31ff 100644
--- a/spec/default.mspec
+++ b/spec/default.mspec
@@ -9,6 +9,7 @@ ENV["CHECK_CONSTANT_LEAKS"] ||= "true"
require "./rbconfig" unless defined?(RbConfig)
require_relative "../tool/test-coverage" if ENV.key?("COVERAGE")
+require_relative "../tool/lib/test/jobserver"
load File.dirname(__FILE__) + '/ruby/default.mspec'
OBJDIR = File.expand_path("spec/ruby/optional/capi/ext") unless defined?(OBJDIR)
class MSpecScript
@@ -50,34 +51,10 @@ end
module MSpecScript::JobServer
def cores(max = 1)
- if max > 1 and /(?:\A|\s)--jobserver-(?:auth|fds)=(\d+),(\d+)/ =~ ENV["MAKEFLAGS"]
- cores = 1
- begin
- r = IO.for_fd($1.to_i(10), "rb", autoclose: false)
- w = IO.for_fd($2.to_i(10), "wb", autoclose: false)
- jobtokens = r.read_nonblock(max - 1)
- cores = jobtokens.size
- if cores > 0
- cores += 1
- jobserver = w
- w = nil
- at_exit {
- jobserver.print(jobtokens)
- jobserver.close
- }
- MSpecScript::JobServer.module_eval do
- remove_method :cores
- define_method(:cores) do
- cores
- end
- end
- return cores
- end
- rescue Errno::EBADF
- ensure
- r&.close
- w&.close
- end
+ MSpecScript::JobServer.remove_method :cores
+ if cores = Test::JobServer.max_jobs(max)
+ MSpecScript::JobServer.define_method(:cores) { cores }
+ return cores
end
super
end
diff --git a/spec/mspec/Gemfile b/spec/mspec/Gemfile
index 617a995cad..e57acd6435 100644
--- a/spec/mspec/Gemfile
+++ b/spec/mspec/Gemfile
@@ -1,4 +1,4 @@
source 'https://rubygems.org'
-gem "rake", "~> 12.3"
+gem "rake"
gem "rspec", "~> 3.0"
diff --git a/spec/mspec/Gemfile.lock b/spec/mspec/Gemfile.lock
index cd39906044..075337d671 100644
--- a/spec/mspec/Gemfile.lock
+++ b/spec/mspec/Gemfile.lock
@@ -2,7 +2,7 @@ GEM
remote: https://rubygems.org/
specs:
diff-lcs (1.4.4)
- rake (12.3.3)
+ rake (13.4.2)
rspec (3.10.0)
rspec-core (~> 3.10.0)
rspec-expectations (~> 3.10.0)
@@ -22,5 +22,5 @@ PLATFORMS
ruby
DEPENDENCIES
- rake (~> 12.3)
+ rake
rspec (~> 3.0)
diff --git a/spec/mspec/lib/mspec/commands/mspec-ci.rb b/spec/mspec/lib/mspec/commands/mspec-ci.rb
index 9959059ca1..8951572f69 100644
--- a/spec/mspec/lib/mspec/commands/mspec-ci.rb
+++ b/spec/mspec/lib/mspec/commands/mspec-ci.rb
@@ -18,6 +18,7 @@ class MSpecCI < MSpecScript
options.chdir
options.prefix
options.configure { |f| load f }
+ options.repeat
options.pretend
options.interrupt
options.timeout
diff --git a/spec/mspec/lib/mspec/commands/mspec-tag.rb b/spec/mspec/lib/mspec/commands/mspec-tag.rb
index 8b1cb83809..9ce9f048c6 100644
--- a/spec/mspec/lib/mspec/commands/mspec-tag.rb
+++ b/spec/mspec/lib/mspec/commands/mspec-tag.rb
@@ -112,6 +112,7 @@ class MSpecTag < MSpecScript
MSpec.register_mode :pretend
MSpec.register_mode :unguarded
config[:formatter] = false
+ config[:xtags] = []
else
raise ArgumentError, "No recognized action given"
end
diff --git a/spec/mspec/lib/mspec/matchers/base.rb b/spec/mspec/lib/mspec/matchers/base.rb
index d9d7f6fec0..4056e73a81 100644
--- a/spec/mspec/lib/mspec/matchers/base.rb
+++ b/spec/mspec/lib/mspec/matchers/base.rb
@@ -1,3 +1,5 @@
+require 'mspec/utils/deprecate'
+
module MSpecMatchers
end
@@ -36,6 +38,14 @@ class SpecPositiveOperatorMatcher < BasicObject
end
end
+ def raise(exception = ::Exception, message = nil, options = nil, &block)
+ matcher = ::RaiseErrorMatcher.new(exception, message, options, &block)
+ unless matcher.matches? @actual
+ expected, actual = matcher.failure_message
+ ::SpecExpectation.fail_with(expected, actual)
+ end
+ end
+
def method_missing(name, *args, &block)
result = @actual.__send__(name, *args, &block)
unless result
@@ -70,6 +80,14 @@ class SpecNegativeOperatorMatcher < BasicObject
end
end
+ def raise(exception = ::Exception, message = nil, options = nil, &block)
+ matcher = ::RaiseErrorMatcher.new(exception, message, options, &block)
+ if matcher.matches? @actual
+ expected, actual = matcher.negative_failure_message
+ ::SpecExpectation.fail_with(expected, actual)
+ end
+ end
+
def method_missing(name, *args, &block)
result = @actual.__send__(name, *args, &block)
if result
diff --git a/spec/mspec/lib/mspec/matchers/be_an_instance_of.rb b/spec/mspec/lib/mspec/matchers/be_an_instance_of.rb
index fdf3736ac2..230cea2e9b 100644
--- a/spec/mspec/lib/mspec/matchers/be_an_instance_of.rb
+++ b/spec/mspec/lib/mspec/matchers/be_an_instance_of.rb
@@ -21,6 +21,7 @@ end
module MSpecMatchers
private def be_an_instance_of(expected)
+ MSpec.deprecate __method__, '.should.instance_of?'
BeAnInstanceOfMatcher.new(expected)
end
end
diff --git a/spec/mspec/lib/mspec/matchers/be_ancestor_of.rb b/spec/mspec/lib/mspec/matchers/be_ancestor_of.rb
index 05f72099e4..b428a153bf 100644
--- a/spec/mspec/lib/mspec/matchers/be_ancestor_of.rb
+++ b/spec/mspec/lib/mspec/matchers/be_ancestor_of.rb
@@ -19,6 +19,7 @@ end
module MSpecMatchers
private def be_ancestor_of(expected)
+ MSpec.deprecate __method__, '.ancestors.should.include?'
BeAncestorOfMatcher.new(expected)
end
end
diff --git a/spec/mspec/lib/mspec/matchers/be_empty.rb b/spec/mspec/lib/mspec/matchers/be_empty.rb
index 5abd5c9485..aac175ffb4 100644
--- a/spec/mspec/lib/mspec/matchers/be_empty.rb
+++ b/spec/mspec/lib/mspec/matchers/be_empty.rb
@@ -15,6 +15,7 @@ end
module MSpecMatchers
private def be_empty
+ MSpec.deprecate __method__, '.should.empty?'
BeEmptyMatcher.new
end
end
diff --git a/spec/mspec/lib/mspec/matchers/be_false.rb b/spec/mspec/lib/mspec/matchers/be_false.rb
index 9e9a2608e1..4fa0bba8a3 100644
--- a/spec/mspec/lib/mspec/matchers/be_false.rb
+++ b/spec/mspec/lib/mspec/matchers/be_false.rb
@@ -15,6 +15,7 @@ end
module MSpecMatchers
private def be_false
+ MSpec.deprecate __method__, '.should == false'
BeFalseMatcher.new
end
end
diff --git a/spec/mspec/lib/mspec/matchers/be_kind_of.rb b/spec/mspec/lib/mspec/matchers/be_kind_of.rb
index a69906f210..d0b23086aa 100644
--- a/spec/mspec/lib/mspec/matchers/be_kind_of.rb
+++ b/spec/mspec/lib/mspec/matchers/be_kind_of.rb
@@ -19,6 +19,7 @@ end
module MSpecMatchers
private def be_kind_of(expected)
+ MSpec.deprecate __method__, '.should.is_a?'
BeKindOfMatcher.new(expected)
end
end
diff --git a/spec/mspec/lib/mspec/matchers/be_nan.rb b/spec/mspec/lib/mspec/matchers/be_nan.rb
index b279d8f1cf..8ba2a3cafe 100644
--- a/spec/mspec/lib/mspec/matchers/be_nan.rb
+++ b/spec/mspec/lib/mspec/matchers/be_nan.rb
@@ -15,6 +15,7 @@ end
module MSpecMatchers
private def be_nan
+ MSpec.deprecate __method__, '.should.nan?'
BeNaNMatcher.new
end
end
diff --git a/spec/mspec/lib/mspec/matchers/be_nil.rb b/spec/mspec/lib/mspec/matchers/be_nil.rb
index 049b1e3a53..c79a50a3f9 100644
--- a/spec/mspec/lib/mspec/matchers/be_nil.rb
+++ b/spec/mspec/lib/mspec/matchers/be_nil.rb
@@ -15,6 +15,7 @@ end
module MSpecMatchers
private def be_nil
+ MSpec.deprecate __method__, '.should == nil'
BeNilMatcher.new
end
end
diff --git a/spec/mspec/lib/mspec/matchers/be_true.rb b/spec/mspec/lib/mspec/matchers/be_true.rb
index 52f5013752..91020cc3fe 100644
--- a/spec/mspec/lib/mspec/matchers/be_true.rb
+++ b/spec/mspec/lib/mspec/matchers/be_true.rb
@@ -15,6 +15,7 @@ end
module MSpecMatchers
private def be_true
+ MSpec.deprecate __method__, '.should == true'
BeTrueMatcher.new
end
end
diff --git a/spec/mspec/lib/mspec/matchers/eql.rb b/spec/mspec/lib/mspec/matchers/eql.rb
index bcab88ebee..3b132f9ae3 100644
--- a/spec/mspec/lib/mspec/matchers/eql.rb
+++ b/spec/mspec/lib/mspec/matchers/eql.rb
@@ -21,6 +21,7 @@ end
module MSpecMatchers
private def eql(expected)
+ MSpec.deprecate __method__, '.should.eql?'
EqlMatcher.new(expected)
end
end
diff --git a/spec/mspec/lib/mspec/matchers/equal.rb b/spec/mspec/lib/mspec/matchers/equal.rb
index 5ba4856d82..1ca5172e0b 100644
--- a/spec/mspec/lib/mspec/matchers/equal.rb
+++ b/spec/mspec/lib/mspec/matchers/equal.rb
@@ -21,6 +21,7 @@ end
module MSpecMatchers
private def equal(expected)
+ MSpec.deprecate __method__, '.should.equal?'
EqualMatcher.new(expected)
end
end
diff --git a/spec/mspec/lib/mspec/matchers/have_class_variable.rb b/spec/mspec/lib/mspec/matchers/have_class_variable.rb
index dd43ced621..576f43793b 100644
--- a/spec/mspec/lib/mspec/matchers/have_class_variable.rb
+++ b/spec/mspec/lib/mspec/matchers/have_class_variable.rb
@@ -7,6 +7,7 @@ end
module MSpecMatchers
private def have_class_variable(variable)
+ MSpec.deprecate __method__, '.should.class_variable_defined?'
HaveClassVariableMatcher.new(variable)
end
end
diff --git a/spec/mspec/lib/mspec/matchers/have_constant.rb b/spec/mspec/lib/mspec/matchers/have_constant.rb
index 6ec7c75b85..c796d742e0 100644
--- a/spec/mspec/lib/mspec/matchers/have_constant.rb
+++ b/spec/mspec/lib/mspec/matchers/have_constant.rb
@@ -7,6 +7,7 @@ end
module MSpecMatchers
private def have_constant(variable)
+ MSpec.deprecate __method__, '.should.const_defined?'
HaveConstantMatcher.new(variable)
end
end
diff --git a/spec/mspec/lib/mspec/matchers/have_instance_method.rb b/spec/mspec/lib/mspec/matchers/have_instance_method.rb
index 9a5a31aa0f..76dde482d5 100644
--- a/spec/mspec/lib/mspec/matchers/have_instance_method.rb
+++ b/spec/mspec/lib/mspec/matchers/have_instance_method.rb
@@ -19,6 +19,7 @@ end
module MSpecMatchers
private def have_instance_method(method, include_super = true)
+ MSpec.deprecate __method__, '.should.method_defined?'
HaveInstanceMethodMatcher.new method, include_super
end
end
diff --git a/spec/mspec/lib/mspec/matchers/have_instance_variable.rb b/spec/mspec/lib/mspec/matchers/have_instance_variable.rb
index de51b3209d..f49595ff7e 100644
--- a/spec/mspec/lib/mspec/matchers/have_instance_variable.rb
+++ b/spec/mspec/lib/mspec/matchers/have_instance_variable.rb
@@ -7,6 +7,7 @@ end
module MSpecMatchers
private def have_instance_variable(variable)
+ MSpec.deprecate __method__, '.should.instance_variable_defined?'
HaveInstanceVariableMatcher.new(variable)
end
end
diff --git a/spec/mspec/lib/mspec/matchers/have_method.rb b/spec/mspec/lib/mspec/matchers/have_method.rb
index e962e69e0a..3db01a7235 100644
--- a/spec/mspec/lib/mspec/matchers/have_method.rb
+++ b/spec/mspec/lib/mspec/matchers/have_method.rb
@@ -19,6 +19,7 @@ end
module MSpecMatchers
private def have_method(method, include_super = true)
+ MSpec.deprecate __method__, '.should.respond_to?'
HaveMethodMatcher.new method, include_super
end
end
diff --git a/spec/mspec/lib/mspec/matchers/have_private_instance_method.rb b/spec/mspec/lib/mspec/matchers/have_private_instance_method.rb
index d32db76c6a..bae01e846e 100644
--- a/spec/mspec/lib/mspec/matchers/have_private_instance_method.rb
+++ b/spec/mspec/lib/mspec/matchers/have_private_instance_method.rb
@@ -19,6 +19,7 @@ end
module MSpecMatchers
private def have_private_instance_method(method, include_super = true)
+ MSpec.deprecate __method__, '.private_instance_methods(false).should.include?'
HavePrivateInstanceMethodMatcher.new method, include_super
end
end
diff --git a/spec/mspec/lib/mspec/matchers/have_private_method.rb b/spec/mspec/lib/mspec/matchers/have_private_method.rb
index c74165cfc7..32efd5a155 100644
--- a/spec/mspec/lib/mspec/matchers/have_private_method.rb
+++ b/spec/mspec/lib/mspec/matchers/have_private_method.rb
@@ -19,6 +19,7 @@ end
module MSpecMatchers
private def have_private_method(method, include_super = true)
+ MSpec.deprecate __method__, '.private_methods(false).should.include?'
HavePrivateMethodMatcher.new method, include_super
end
end
diff --git a/spec/mspec/lib/mspec/matchers/have_protected_instance_method.rb b/spec/mspec/lib/mspec/matchers/have_protected_instance_method.rb
index 1deb2f995d..9f09e8b529 100644
--- a/spec/mspec/lib/mspec/matchers/have_protected_instance_method.rb
+++ b/spec/mspec/lib/mspec/matchers/have_protected_instance_method.rb
@@ -19,6 +19,7 @@ end
module MSpecMatchers
private def have_protected_instance_method(method, include_super = true)
+ MSpec.deprecate __method__, '.protected_instance_methods(false).should.include?'
HaveProtectedInstanceMethodMatcher.new method, include_super
end
end
diff --git a/spec/mspec/lib/mspec/matchers/have_public_instance_method.rb b/spec/mspec/lib/mspec/matchers/have_public_instance_method.rb
index 0e620532c0..69abadfafa 100644
--- a/spec/mspec/lib/mspec/matchers/have_public_instance_method.rb
+++ b/spec/mspec/lib/mspec/matchers/have_public_instance_method.rb
@@ -19,6 +19,7 @@ end
module MSpecMatchers
private def have_public_instance_method(method, include_super = true)
+ MSpec.deprecate __method__, '.public_instance_methods(false).should.include?'
HavePublicInstanceMethodMatcher.new method, include_super
end
end
diff --git a/spec/mspec/lib/mspec/matchers/have_singleton_method.rb b/spec/mspec/lib/mspec/matchers/have_singleton_method.rb
index b60dd2536b..2d2707c528 100644
--- a/spec/mspec/lib/mspec/matchers/have_singleton_method.rb
+++ b/spec/mspec/lib/mspec/matchers/have_singleton_method.rb
@@ -19,6 +19,7 @@ end
module MSpecMatchers
private def have_singleton_method(method, include_super = true)
+ MSpec.deprecate __method__, '.singleton_methods(false).should.include?'
HaveSingletonMethodMatcher.new method, include_super
end
end
diff --git a/spec/mspec/lib/mspec/matchers/include.rb b/spec/mspec/lib/mspec/matchers/include.rb
index 3f07f35548..05d5079f13 100644
--- a/spec/mspec/lib/mspec/matchers/include.rb
+++ b/spec/mspec/lib/mspec/matchers/include.rb
@@ -26,6 +26,7 @@ end
# Cannot override #include at the toplevel in MRI
module MSpecMatchers
private def include(*expected)
+ MSpec.deprecate __method__, '.should.include?'
IncludeMatcher.new(*expected)
end
end
diff --git a/spec/mspec/lib/mspec/matchers/infinity.rb b/spec/mspec/lib/mspec/matchers/infinity.rb
index 8bfa6dbd10..0a4c95c7cc 100644
--- a/spec/mspec/lib/mspec/matchers/infinity.rb
+++ b/spec/mspec/lib/mspec/matchers/infinity.rb
@@ -19,10 +19,12 @@ end
module MSpecMatchers
private def be_positive_infinity
+ MSpec.deprecate __method__, '.should.infinite? == 1'
InfinityMatcher.new(1)
end
private def be_negative_infinity
+ MSpec.deprecate __method__, '.should.infinite? == -1'
InfinityMatcher.new(-1)
end
end
diff --git a/spec/mspec/lib/mspec/matchers/raise_error.rb b/spec/mspec/lib/mspec/matchers/raise_error.rb
index 54378bb34c..17ea47148b 100644
--- a/spec/mspec/lib/mspec/matchers/raise_error.rb
+++ b/spec/mspec/lib/mspec/matchers/raise_error.rb
@@ -1,11 +1,18 @@
class RaiseErrorMatcher
FAILURE_MESSAGE_FOR_EXCEPTION = {}.compare_by_identity
+ UNDEF_CAUSE = Object.new
attr_writer :block
- def initialize(exception, message, &block)
+ def initialize(exception, message = nil, options = nil, &block)
+ if message.is_a? Hash
+ @message = nil
+ options = message
+ else
+ @message = message
+ end
+ @cause = options ? options.fetch(:cause, UNDEF_CAUSE) : UNDEF_CAUSE
@exception = exception
- @message = message
@block = block
@actual = nil
end
@@ -45,24 +52,45 @@ class RaiseErrorMatcher
end
end
+ def matching_cause?(exc)
+ case @cause
+ when UNDEF_CAUSE
+ true
+ else
+ @cause == exc.cause
+ end
+ end
+
def matching_exception?(exc)
- matching_class?(exc) and matching_message?(exc)
+ matching_class?(exc) and matching_message?(exc) and matching_cause?(exc)
end
- def exception_class_and_message(exception_class, message)
- if message
- "#{exception_class} (#{message})"
- else
- "#{exception_class}"
+ def exception_class_and_message_and_cause(exception_class, message, cause)
+ string = "#{exception_class}"
+ prefixed = false
+ prefix = -> { prefixed ? ", " : prefixed = "(" }
+
+ if message != nil
+ string << "#{prefix.()}#{message.inspect}"
+ end
+
+ if cause != UNDEF_CAUSE
+ string << "#{prefix.()}cause: #{cause.inspect}"
end
+
+ string << ")" if prefixed
+
+ string
end
def format_expected_exception
- exception_class_and_message(@exception, @message)
+ exception_class_and_message_and_cause(@exception, @message, @cause)
end
def format_exception(exception)
- exception_class_and_message(exception.class, exception.message)
+ exception_class_and_message_and_cause(exception.class,
+ @message == nil ? nil : exception.message,
+ @cause == UNDEF_CAUSE ? UNDEF_CAUSE : exception.cause)
end
def failure_message
@@ -87,7 +115,19 @@ class RaiseErrorMatcher
end
module MSpecMatchers
- private def raise_error(exception = Exception, message = nil, &block)
- RaiseErrorMatcher.new(exception, message, &block)
+ private def raise_error(exception = Exception, message = nil, options = nil, &block)
+ MSpec.deprecate __method__, '.should.raise'
+ RaiseErrorMatcher.new(exception, message, options, &block)
+ end
+
+ # CRuby < 4.1 has inconsistent coercion errors:
+ # https://bugs.ruby-lang.org/issues/21864
+ # This matcher ignores the message on CRuby < 4.1
+ # and checks the message for all other cases, including other Rubies
+ private def raise_consistent_error(exception = Exception, message = nil, options = nil, &block)
+ if RUBY_ENGINE == "ruby" and ruby_version_is ""..."4.1"
+ message = nil
+ end
+ RaiseErrorMatcher.new(exception, message, options, &block)
end
end
diff --git a/spec/mspec/lib/mspec/matchers/respond_to.rb b/spec/mspec/lib/mspec/matchers/respond_to.rb
index 6b35ae2d3c..a36bf8aee2 100644
--- a/spec/mspec/lib/mspec/matchers/respond_to.rb
+++ b/spec/mspec/lib/mspec/matchers/respond_to.rb
@@ -19,6 +19,7 @@ end
module MSpecMatchers
private def respond_to(expected)
+ MSpec.deprecate __method__, '.should.respond_to?'
RespondToMatcher.new(expected)
end
end
diff --git a/spec/mspec/lib/mspec/runner/formatters/base.rb b/spec/mspec/lib/mspec/runner/formatters/base.rb
index e3b5bb23e0..882e15c8c2 100644
--- a/spec/mspec/lib/mspec/runner/formatters/base.rb
+++ b/spec/mspec/lib/mspec/runner/formatters/base.rb
@@ -46,7 +46,7 @@ class BaseFormatter
LeakCheckerAction.new.register
end
- if ENV['CHECK_LEAKS'] || ENV['CHECK_CONSTANT_LEAKS']
+ if (ENV['CHECK_LEAKS'] || ENV['CHECK_CONSTANT_LEAKS']) && ENV['CHECK_CONSTANT_LEAKS'] != 'false'
save = ENV['CHECK_LEAKS'] == 'save' || ENV['CHECK_CONSTANT_LEAKS'] == 'save'
ConstantsLeakCheckerAction.new(save).register
end
diff --git a/spec/mspec/lib/mspec/runner/mspec.rb b/spec/mspec/lib/mspec/runner/mspec.rb
index 97c3f365bc..0e016c67a7 100644
--- a/spec/mspec/lib/mspec/runner/mspec.rb
+++ b/spec/mspec/lib/mspec/runner/mspec.rb
@@ -365,6 +365,7 @@ module MSpec
# Writes each tag in +tags+ to the tag file. Overwrites the
# tag file if it exists.
def self.write_tags(tags)
+ return delete_tags if tags.empty?
file = tags_file
make_tag_dir(file)
File.open(file, "w:utf-8") do |f|
diff --git a/spec/mspec/lib/mspec/utils/name_map.rb b/spec/mspec/lib/mspec/utils/name_map.rb
index bf70e651a2..9b04112e2e 100644
--- a/spec/mspec/lib/mspec/utils/name_map.rb
+++ b/spec/mspec/lib/mspec/utils/name_map.rb
@@ -66,10 +66,17 @@ class NameMap
end
def class_or_module(c)
- const = Object.const_get(c, false)
+ begin
+ const = Object.const_get(c, false)
+ rescue NameError, RuntimeError
+ # Either the constant doesn't exist or it is
+ # explicitly raising an error, like `SortedSet`.
+ return nil
+ end
+ return nil unless Module === const
+
filtered = @filter && EXCLUDED.include?(const.name)
- return const if Module === const and !filtered
- rescue NameError
+ return const unless filtered
end
def namespace(mod, const)
diff --git a/spec/mspec/spec/commands/mspec_ci_spec.rb b/spec/mspec/spec/commands/mspec_ci_spec.rb
index bcbc5b4224..b8dc9d062f 100644
--- a/spec/mspec/spec/commands/mspec_ci_spec.rb
+++ b/spec/mspec/spec/commands/mspec_ci_spec.rb
@@ -78,6 +78,11 @@ RSpec.describe MSpecCI, "#options" do
@script.options []
end
+ it "enables the repeat option" do
+ expect(@options).to receive(:repeat)
+ @script.options @argv
+ end
+
it "calls #custom_options" do
expect(@script).to receive(:custom_options).with(@options)
@script.options []
diff --git a/spec/mspec/spec/commands/mspec_run_spec.rb b/spec/mspec/spec/commands/mspec_run_spec.rb
index 62acd49d7f..f96be2b43e 100644
--- a/spec/mspec/spec/commands/mspec_run_spec.rb
+++ b/spec/mspec/spec/commands/mspec_run_spec.rb
@@ -105,6 +105,11 @@ RSpec.describe MSpecRun, "#options" do
@script.options @argv
end
+ it "enables the repeat option" do
+ expect(@options).to receive(:repeat)
+ @script.options @argv
+ end
+
it "exits if there are no files to process and './spec' is not a directory" do
expect(File).to receive(:directory?).with("./spec").and_return(false)
expect(@options).to receive(:parse).and_return([])
diff --git a/spec/mspec/spec/fixtures/should.rb b/spec/mspec/spec/fixtures/should.rb
index f494775c5f..6eb156da25 100644
--- a/spec/mspec/spec/fixtures/should.rb
+++ b/spec/mspec/spec/fixtures/should.rb
@@ -40,7 +40,7 @@ MSpec.setup_env
# Specs
describe "MSpec expectation method #should" do
it "accepts a matcher" do
- :sym.should be_kind_of(Symbol)
+ 0.4.should be_close(0.5, 0.2)
end
it "causes a failure to be recorded" do
@@ -59,7 +59,7 @@ end
describe "MSpec expectation method #should_not" do
it "accepts a matcher" do
- "sym".should_not be_kind_of(Symbol)
+ 0.1.should_not be_close(0.5, 0.2)
end
it "causes a failure to be recorded" do
diff --git a/spec/mspec/spec/matchers/raise_error_spec.rb b/spec/mspec/spec/matchers/raise_error_spec.rb
index 8613eee118..957baa087d 100644
--- a/spec/mspec/spec/matchers/raise_error_spec.rb
+++ b/spec/mspec/spec/matchers/raise_error_spec.rb
@@ -19,7 +19,7 @@ RSpec.describe RaiseErrorMatcher do
ensure_mspec_method(-> {}.method(:should))
run = false
- -> { raise ExpectedException }.should PublicMSpecMatchers.raise_error { |error|
+ -> { raise ExpectedException }.should.raise { |error|
expect(error.class).to eq(ExpectedException)
run = true
}
@@ -30,7 +30,7 @@ RSpec.describe RaiseErrorMatcher do
ensure_mspec_method(-> {}.method(:should))
run = false
- -> { raise ExpectedException }.should PublicMSpecMatchers.raise_error do |error|
+ -> { raise ExpectedException }.should.raise do |error|
expect(error.class).to eq(ExpectedException)
run = true
end
@@ -84,10 +84,10 @@ RSpec.describe RaiseErrorMatcher do
matcher.matches?(Proc.new { raise exc })
rescue UnexpectedException => e
expect(matcher.failure_message).to eq(
- ["Expected ExpectedException (message)", "but got: UnexpectedException (message)"]
+ ['Expected ExpectedException("message")', 'but got: UnexpectedException("message")']
)
expect(ExceptionState.new(nil, nil, e).message).to eq(
- "Expected ExpectedException (message)\nbut got: UnexpectedException (message)"
+ "Expected ExpectedException(\"message\")\nbut got: UnexpectedException(\"message\")"
)
else
raise "no exception"
@@ -103,10 +103,10 @@ RSpec.describe RaiseErrorMatcher do
matcher.matches?(Proc.new { raise exc })
rescue ExpectedException => e
expect(matcher.failure_message).to eq(
- ["Expected ExpectedException (expected)", "but got: ExpectedException (unexpected)"]
+ ['Expected ExpectedException("expected")', 'but got: ExpectedException("unexpected")']
)
expect(ExceptionState.new(nil, nil, e).message).to eq(
- "Expected ExpectedException (expected)\nbut got: ExpectedException (unexpected)"
+ "Expected ExpectedException(\"expected\")\nbut got: ExpectedException(\"unexpected\")"
)
else
raise "no exception"
@@ -122,10 +122,10 @@ RSpec.describe RaiseErrorMatcher do
matcher.matches?(Proc.new { raise exc })
rescue UnexpectedException => e
expect(matcher.failure_message).to eq(
- ["Expected ExpectedException (expected)", "but got: UnexpectedException (unexpected)"]
+ ['Expected ExpectedException("expected")', 'but got: UnexpectedException("unexpected")']
)
expect(ExceptionState.new(nil, nil, e).message).to eq(
- "Expected ExpectedException (expected)\nbut got: UnexpectedException (unexpected)"
+ "Expected ExpectedException(\"expected\")\nbut got: UnexpectedException(\"unexpected\")"
)
else
raise "no exception"
@@ -137,7 +137,7 @@ RSpec.describe RaiseErrorMatcher do
matcher = RaiseErrorMatcher.new(ExpectedException, "expected")
matcher.matches?(proc)
expect(matcher.failure_message).to eq(
- ["Expected ExpectedException (expected)", "but no exception was raised (120 was returned)"]
+ ['Expected ExpectedException("expected")', "but no exception was raised (120 was returned)"]
)
end
@@ -146,7 +146,7 @@ RSpec.describe RaiseErrorMatcher do
matcher = RaiseErrorMatcher.new(ExpectedException, "expected")
matcher.matches?(proc)
expect(matcher.failure_message).to eq(
- ["Expected ExpectedException (expected)", "but no exception was raised (nil was returned)"]
+ ['Expected ExpectedException("expected")', "but no exception was raised (nil was returned)"]
)
end
@@ -159,7 +159,7 @@ RSpec.describe RaiseErrorMatcher do
matcher = RaiseErrorMatcher.new(ExpectedException, "expected")
matcher.matches?(proc)
expect(matcher.failure_message).to eq(
- ["Expected ExpectedException (expected)", "but no exception was raised (#<Object>(#pretty_inspect raised #<ArgumentError: bad>) was returned)"]
+ ['Expected ExpectedException("expected")', 'but no exception was raised (#<Object>(#pretty_inspect raised #<ArgumentError: bad>) was returned)']
)
end
@@ -168,7 +168,7 @@ RSpec.describe RaiseErrorMatcher do
matcher = RaiseErrorMatcher.new(ExpectedException, "expected")
matcher.matches?(proc)
expect(matcher.negative_failure_message).to eq(
- ["Expected to not get ExpectedException (expected)", ""]
+ ['Expected to not get ExpectedException("expected")', ""]
)
end
@@ -177,7 +177,58 @@ RSpec.describe RaiseErrorMatcher do
matcher = RaiseErrorMatcher.new(Exception, nil)
matcher.matches?(proc)
expect(matcher.negative_failure_message).to eq(
- ["Expected to not get Exception", "but got: UnexpectedException (unexpected)"]
+ ['Expected to not get Exception', 'but got: UnexpectedException']
)
end
+
+ it "matches cause if given" do
+ cause = RuntimeError.new("foo")
+ proc = -> do
+ raise cause
+ rescue
+ raise "bar"
+ end
+
+ matcher = RaiseErrorMatcher.new(RuntimeError, cause: cause)
+ expect(matcher.matches?(proc)).to eq(true)
+ end
+
+ it "matches message and cause if given" do
+ cause = RuntimeError.new("foo")
+ proc = -> do
+ raise cause
+ rescue
+ raise "bar"
+ end
+
+ matcher = RaiseErrorMatcher.new(RuntimeError, "bar", cause: cause)
+ expect(matcher.matches?(proc)).to eq(true)
+ end
+
+ it "provides useful negative failure message when cause does not match" do
+ cause = RuntimeError.new("bar")
+ proc = -> do
+ raise "foo"
+ end
+
+ matcher = RaiseErrorMatcher.new(RuntimeError, cause: cause)
+
+ begin
+ matcher.matches?(proc)
+ rescue RuntimeError
+ expect(matcher.failure_message).to eq(
+ ['Expected RuntimeError(cause: #<RuntimeError: bar>)', 'but got: RuntimeError(cause: nil)']
+ )
+ end
+
+ matcher = RaiseErrorMatcher.new(RuntimeError, "foo", cause: cause)
+
+ begin
+ matcher.matches?(proc)
+ rescue RuntimeError
+ expect(matcher.failure_message).to eq(
+ ['Expected RuntimeError("foo", cause: #<RuntimeError: bar>)', 'but got: RuntimeError("foo", cause: nil)']
+ )
+ end
+ end
end
diff --git a/spec/mspec/spec/spec_helper.rb b/spec/mspec/spec/spec_helper.rb
index 5cabfe5626..8ea38b644f 100644
--- a/spec/mspec/spec/spec_helper.rb
+++ b/spec/mspec/spec/spec_helper.rb
@@ -62,9 +62,4 @@ def ensure_mspec_method(method)
expect(file).to start_with(File.expand_path('../../lib/mspec', __FILE__ ))
end
-PublicMSpecMatchers = Class.new {
- include MSpecMatchers
- public :raise_error
-}.new
-
BACKTRACE_QUOTE = RUBY_VERSION >= "3.4" ? "'" : "`"
diff --git a/spec/mspec/spec/utils/fixtures/this_file_raises.rb b/spec/mspec/spec/utils/fixtures/this_file_raises.rb
new file mode 100644
index 0000000000..8e37a587bf
--- /dev/null
+++ b/spec/mspec/spec/utils/fixtures/this_file_raises.rb
@@ -0,0 +1 @@
+raise "This is a BAD file"
diff --git a/spec/mspec/spec/utils/fixtures/this_file_raises2.rb b/spec/mspec/spec/utils/fixtures/this_file_raises2.rb
new file mode 100644
index 0000000000..8efc10199a
--- /dev/null
+++ b/spec/mspec/spec/utils/fixtures/this_file_raises2.rb
@@ -0,0 +1 @@
+raise "This is a BAD file 2"
diff --git a/spec/mspec/spec/utils/name_map_spec.rb b/spec/mspec/spec/utils/name_map_spec.rb
index a18a481500..a42dc9ffec 100644
--- a/spec/mspec/spec/utils/name_map_spec.rb
+++ b/spec/mspec/spec/utils/name_map_spec.rb
@@ -21,6 +21,9 @@ module NameMapSpecs
def f; end
end
+ autoload :BadFile, "#{__dir__}/fixtures/this_file_raises.rb"
+ autoload :BadFile2, "#{__dir__}/fixtures/this_file_raises2.rb"
+
def self.n; end
def n; end
end
@@ -84,6 +87,15 @@ RSpec.describe NameMap, "#class_or_module" do
expect(@map.class_or_module("Hell")).to eq(nil)
expect(@map.class_or_module("Bush::Brain")).to eq(nil)
end
+
+ it "returns nil if accessing the constant raises RuntimeError" do
+ expect { NameMapSpecs::BadFile }.to raise_error(RuntimeError)
+ expect(@map.class_or_module("NameMapSpecs::BadFile")).to eq(nil)
+ end
+
+ it "returns nil if accessing the constant raises RuntimeError when not triggering the autoload before" do
+ expect(@map.class_or_module("NameMapSpecs::BadFile2")).to eq(nil)
+ end
end
RSpec.describe NameMap, "#dir_name" do
diff --git a/spec/mspec/tool/remove_old_guards.rb b/spec/mspec/tool/remove_old_guards.rb
index 75c48e0584..bc5612c78d 100755
--- a/spec/mspec/tool/remove_old_guards.rb
+++ b/spec/mspec/tool/remove_old_guards.rb
@@ -31,6 +31,12 @@ def each_spec_file(&block)
Dir["*/**/*.rb"].each(&block)
end
+def each_file(&block)
+ Dir["**/*"].each { |path|
+ yield path if File.file?(path)
+ }
+end
+
def remove_guards(guard, keep)
each_spec_file do |file|
contents = File.binread(file)
@@ -109,7 +115,7 @@ def remove_unused_shared_specs
end
def search(regexp)
- each_spec_file do |file|
+ each_file do |file|
contents = File.binread(file)
if contents =~ regexp
puts file
@@ -136,3 +142,4 @@ remove_unused_shared_specs
puts "Search:"
search(/(["'])#{version}\1/)
search(/^\s*#.+#{version}/)
+search(/RUBY_VERSION_IS_#{version.tr('.', '_')}/)
diff --git a/spec/mspec/tool/sync/sync-rubyspec.rb b/spec/mspec/tool/sync/sync-rubyspec.rb
index effccc1567..86c43d0dc8 100644
--- a/spec/mspec/tool/sync/sync-rubyspec.rb
+++ b/spec/mspec/tool/sync/sync-rubyspec.rb
@@ -3,7 +3,7 @@
IMPLS = {
truffleruby: {
- git: "https://github.com/oracle/truffleruby.git",
+ git: "https://github.com/truffleruby/truffleruby.git",
from_commit: "f10ab6988d",
},
jruby: {
@@ -34,6 +34,13 @@ raise RUBYSPEC_REPO unless Dir.exist?(RUBYSPEC_REPO)
SOURCE_REPO = MSPEC ? MSPEC_REPO : RUBYSPEC_REPO
+# LAST_MERGE is a commit of ruby/spec or ruby/mspec
+# which is the spec/mspec commit that was last imported in the Ruby implementation
+# (i.e. the commit in "Update to ruby/spec@commit").
+# It is normally automatically computed, but can be manually set when
+# e.g. the last update of specs wasn't merged in the Ruby implementation.
+LAST_MERGE = ENV["LAST_MERGE"]
+
NOW = Time.now
BRIGHT_RED = "\e[31;1m"
@@ -142,8 +149,8 @@ def rebase_commits(impl)
else
sh "git", "checkout", impl.name
- if ENV["LAST_MERGE"]
- last_merge = `git log -n 1 --format='%H %ct' #{ENV["LAST_MERGE"]}`
+ if LAST_MERGE
+ last_merge = `git log -n 1 --format='%H %ct' #{LAST_MERGE}`
else
last_merge = `git log --grep='^#{impl.last_merge_message}' -n 1 --format='%H %ct'`
end
@@ -183,30 +190,20 @@ def test_new_specs
Dir.chdir(SOURCE_REPO) do
workflow = YAML.load_file(".github/workflows/ci.yml")
job_name = MSPEC ? "test" : "specs"
- versions = workflow.dig("jobs", job_name, "strategy", "matrix", "ruby")
+ versions = workflow.dig("jobs", job_name, "strategy", "matrix", "ruby").map(&:to_s)
versions = versions.grep(/^\d+\./) # Test on MRI
min_version, max_version = versions.minmax
test_command = MSPEC ? "bundle install && bundle exec rspec" : "../mspec/bin/mspec -j"
run_test = -> version {
- command = "chruby #{version} && #{test_command}"
+ command = "chruby ruby-#{version} && #{test_command}"
sh ENV["SHELL"], "-c", command
}
run_test[min_version]
run_test[max_version]
- run_test["ruby-master"] if TEST_MASTER
- end
-end
-
-def verify_commits(impl)
- puts
- Dir.chdir(SOURCE_REPO) do
- puts "Manually check commit messages:"
- print "Press enter >"
- STDIN.gets
- system "git", "log", "master..."
+ run_test["master"] if TEST_MASTER
end
end
@@ -236,7 +233,6 @@ def main(impls)
rebase_commits(impl)
if new_commits?(impl)
test_new_specs
- verify_commits(impl)
fast_forward_master(impl)
check_ci
else
diff --git a/spec/mspec/tool/tag_from_output.rb b/spec/mspec/tool/tag_from_output.rb
index b6b4603855..41aa70f932 100755
--- a/spec/mspec/tool/tag_from_output.rb
+++ b/spec/mspec/tool/tag_from_output.rb
@@ -20,7 +20,7 @@ end
NUMBER = /^\d+\)$/
ERROR_OR_FAILED = / (ERROR|FAILED)$/
-SPEC_FILE = /^(\/.+_spec\.rb)\:\d+/
+SPEC_FILE = /^((?:\/|[CD]:\/).+_spec\.rb)\:\d+/
output.slice_before(NUMBER).select { |number, *rest|
number =~ NUMBER and rest.any? { |line| line =~ ERROR_OR_FAILED }
diff --git a/spec/ruby/.rubocop.yml b/spec/ruby/.rubocop.yml
index 68cce31280..0b5dcb80a2 100644
--- a/spec/ruby/.rubocop.yml
+++ b/spec/ruby/.rubocop.yml
@@ -54,10 +54,6 @@ Lint/RedundantRequireStatement:
- library/fiber/**/*.rb
- optional/capi/fiber_spec.rb
-Lint/RedundantSafeNavigation:
- Exclude:
- - language/safe_navigator_spec.rb
-
Lint/RedundantSplatExpansion:
Enabled: false
@@ -197,6 +193,7 @@ Style/Lambda:
- 'language/lambda_spec.rb'
- 'language/proc_spec.rb'
- 'language/numbered_parameters_spec.rb'
+ - 'language/it_parameter_spec.rb'
- 'core/kernel/lambda_spec.rb'
Style/EmptyLambdaParameter:
diff --git a/spec/ruby/.rubocop_todo.yml b/spec/ruby/.rubocop_todo.yml
index 6b43db9b9a..f998002c6d 100644
--- a/spec/ruby/.rubocop_todo.yml
+++ b/spec/ruby/.rubocop_todo.yml
@@ -1,6 +1,6 @@
# This configuration was generated by
# `rubocop --auto-gen-config`
-# on 2024-10-12 16:01:45 UTC using RuboCop version 1.66.1.
+# on 2026-05-29 08:10:07 UTC using RuboCop version 1.86.2.
# The point is for the user to remove these configuration records
# one by one as the offenses are removed from the code base.
# Note that changes in the inspected code, or installation of new
@@ -11,17 +11,22 @@ Lint/DuplicateCaseCondition:
Exclude:
- 'language/case_spec.rb'
-# Offense count: 6
+# Offense count: 20
Lint/DuplicateMethods:
Exclude:
- 'core/array/fixtures/encoded_strings.rb'
- 'core/method/fixtures/classes.rb'
+ - 'core/module/const_added_spec.rb'
+ - 'core/module/define_method_spec.rb'
- 'core/module/fixtures/classes.rb'
+ - 'core/module/method_added_spec.rb'
+ - 'core/module/name_spec.rb'
+ - 'core/proc/new_spec.rb'
- 'core/unboundmethod/fixtures/classes.rb'
- 'fixtures/class.rb'
+ - 'language/assignments_spec.rb'
# Offense count: 8
-# This cop supports safe autocorrection (--autocorrect).
Lint/EnsureReturn:
Exclude:
- 'language/fixtures/ensure.rb'
@@ -39,10 +44,11 @@ Lint/FloatOutOfRange:
Exclude:
- 'core/string/modulo_spec.rb'
-# Offense count: 2
+# Offense count: 3
# This cop supports safe autocorrection (--autocorrect).
Lint/ImplicitStringConcatenation:
Exclude:
+ - 'core/string/chilled_string_spec.rb'
- 'language/string_spec.rb'
# Offense count: 4
@@ -52,12 +58,11 @@ Lint/IneffectiveAccessModifier:
- 'core/module/fixtures/classes.rb'
- 'language/fixtures/private.rb'
-# Offense count: 71
+# Offense count: 12
# This cop supports safe autocorrection (--autocorrect).
Lint/LiteralInInterpolation:
Exclude:
- 'core/module/refine_spec.rb'
- - 'core/regexp/shared/new.rb'
- 'core/string/shared/to_sym.rb'
- 'language/alias_spec.rb'
- 'language/defined_spec.rb'
@@ -79,6 +84,16 @@ Lint/ParenthesesAsGroupedExpression:
- 'language/block_spec.rb'
- 'language/method_spec.rb'
+# Offense count: 1
+# This cop supports unsafe autocorrection (--autocorrect-all).
+# Configuration parameters: AllowedMethods, InferNonNilReceiver, AdditionalNilMethods.
+# AllowedMethods: instance_of?, kind_of?, is_a?, eql?, respond_to?, equal?
+# AdditionalNilMethods: present?, blank?, try, try!
+Lint/RedundantSafeNavigation:
+ Exclude:
+ - 'language/safe_navigator_spec.rb'
+ - 'language/fixtures/rescue_captures.rb'
+
# Offense count: 2
# This cop supports safe autocorrection (--autocorrect).
Lint/RedundantStringCoercion:
@@ -86,6 +101,7 @@ Lint/RedundantStringCoercion:
- 'core/io/print_spec.rb'
# Offense count: 1
+# Configuration parameters: AllowRBSInlineAnnotation.
Lint/SelfAssignment:
Exclude:
- 'core/gc/auto_compact_spec.rb'
@@ -96,7 +112,7 @@ Lint/ShadowedArgument:
Exclude:
- 'language/fixtures/super.rb'
-# Offense count: 45
+# Offense count: 49
# Configuration parameters: AllowComments, AllowNil.
Lint/SuppressedException:
Enabled: false
@@ -109,13 +125,14 @@ Lint/UnderscorePrefixedVariableName:
- 'core/io/popen_spec.rb'
- 'language/block_spec.rb'
-# Offense count: 7
+# Offense count: 9
# This cop supports safe autocorrection (--autocorrect).
-# Configuration parameters: AutoCorrect, ContextCreatingMethods, MethodCreatingMethods.
+# Configuration parameters: ContextCreatingMethods, MethodCreatingMethods.
Lint/UselessAccessModifier:
Exclude:
- 'core/module/define_method_spec.rb'
- 'core/module/fixtures/classes.rb'
- 'core/module/module_function_spec.rb'
- 'core/module/private_class_method_spec.rb'
+ - 'language/fixtures/def.rb'
- 'language/fixtures/send.rb'
diff --git a/spec/ruby/CONTRIBUTING.md b/spec/ruby/CONTRIBUTING.md
index 366b484bad..a474e205f0 100644
--- a/spec/ruby/CONTRIBUTING.md
+++ b/spec/ruby/CONTRIBUTING.md
@@ -55,6 +55,11 @@ which indicates the file was generated but the method unspecified.
Here is a list of frequently-used matchers, which should be enough for most specs.
There are a few extra specific matchers used in the couple specs that need it.
+The general idea is: add `.should` just before the predicate you expect to be truthy, and done!
+This works for most needs and provides a great error when it fails.
+It's immediately clear which method is used and there no need to remember a mapping like in RSpec between e.g. `eq` and `==`.
+See [this blog post](https://eregon.me/blog/2019/10/07/a-new-should-syntax.html) for the motivation behind that syntax.
+
#### Comparison matchers
```ruby
@@ -83,43 +88,37 @@ File.should.equal?(File) # Calls #equal? (tests identity)
(0.1 + 0.2).should be_close(0.3, TOLERANCE) # (0.2-0.1).abs < TOLERANCE
(0.0/0.0).should.nan?
-(1.0/0.0).should be_positive_infinity
-(-1.0/0.0).should be_negative_infinity
-3.14.should be_an_instance_of(Float) # Calls #instance_of?
-3.14.should be_kind_of(Numeric) # Calls #is_a?
-Numeric.should be_ancestor_of(Float) # Float.ancestors.include?(Numeric)
+3.14.should.instance_of?(Float) # Calls #instance_of?
+3.14.should.is_a?(Numeric) # Calls #is_a?
3.14.should.respond_to?(:to_i)
-Integer.should have_instance_method(:+)
-Array.should have_method(:new)
+Integer.should.method_defined?(:+, false)
```
-Also `have_constant`, `have_private_instance_method`, `have_singleton_method`, etc.
-
#### Exception matchers
```ruby
-> {
raise "oops"
-}.should raise_error(RuntimeError, /oops/)
+}.should.raise(RuntimeError, /oops/)
-> {
raise "oops"
-}.should raise_error(RuntimeError) { |e|
+}.should.raise(RuntimeError) { |e|
# Custom checks on the Exception object
e.message.should.include?("oops")
e.cause.should == nil
}
```
-##### `should_not raise_error`
+##### `should_not.raise`
**Avoid this!** Instead, use an expectation testing what the code in the lambda does.
If an exception is raised, it will fail the example anyway.
```ruby
--> { ... }.should_not raise_error
+-> { ... }.should_not.raise
```
#### Warning matcher
@@ -230,7 +229,7 @@ to avoid duplication of specs, we have shared specs that are re-used in other sp
bit tricky however, so let's go over it.
Commonly, if a shared spec is only reused within its own module, the shared spec will live within a
-shared directory inside that module's directory. For example, the `core/hash/shared/key.rb` spec is
+shared directory inside that module's directory. For example, the `core/hash/shared/iteration.rb` spec is
only used by `Hash` specs, and so it lives inside `core/hash/shared/`.
When a shared spec is used across multiple modules or classes, it lives within the `shared/` directory.
@@ -244,25 +243,25 @@ variables from the implementor spec: `@method` and `@object`, which the implemen
Here's an example of a snippet of a shared spec and two specs which integrates it:
```ruby
-# core/hash/shared/key.rb
-describe :hash_key_p, shared: true do
- it "returns true if the key's matching value was false" do
- { xyz: false }.send(@method, :xyz).should == true
+# core/hash/shared/iteration.rb
+describe :hash_iteration_no_block, shared: true do
+ it "returns an Enumerator if called on a non-empty hash without a block" do
+ { 1 => 2 }.send(@method).should.instance_of?(Enumerator)
end
end
-# core/hash/key_spec.rb
-describe "Hash#key?" do
- it_behaves_like :hash_key_p, :key?
+# core/hash/select_spec.rb
+describe "Hash#select" do
+ it_behaves_like :hash_iteration_no_block, :select
end
-# core/hash/include_spec.rb
-describe "Hash#include?" do
- it_behaves_like :hash_key_p, :include?
+# core/hash/reject_spec.rb
+describe "Hash#reject" do
+ it_behaves_like :hash_iteration_no_block, :reject
end
```
-In the example, the first `describe` defines the shared spec `:hash_key_p`, which defines a spec that
+In the example, the first `describe` defines the shared spec `:hash_iteration_no_block`, which defines a spec that
calls the `@method` method with an expectation. In the implementor spec, we use `it_behaves_like` to
integrate the shared spec. `it_behaves_like` takes 3 parameters: the key of the shared spec, a method,
and an object. These last two parameters are accessible via `@method` and `@object` in the shared spec.
@@ -274,7 +273,7 @@ how this is used currently:
```ruby
describe :kernel_sprintf, shared: true do
it "raises TypeError exception if cannot convert to Integer" do
- -> { @method.call("%b", Object.new) }.should raise_error(TypeError)
+ -> { @method.call("%b", Object.new) }.should.raise(TypeError)
end
end
diff --git a/spec/ruby/README.md b/spec/ruby/README.md
index 56d6c3c542..b259a97e21 100644
--- a/spec/ruby/README.md
+++ b/spec/ruby/README.md
@@ -26,12 +26,12 @@ ruby/spec is known to be tested in these implementations for every commit:
* [MRI](https://rubyci.org/) on 30 platforms and 4 versions
* [JRuby](https://github.com/jruby/jruby/tree/master/spec/ruby) for both 1.7 and 9.x
-* [TruffleRuby](https://github.com/oracle/truffleruby/tree/master/spec/ruby)
+* [TruffleRuby](https://github.com/truffleruby/truffleruby/tree/master/spec/ruby)
* [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.2 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.2.x, 3.3.x, etc), and those are tested in CI.
+ruby/spec describes the behavior of Ruby 3.3 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.3.x, 3.4.x, etc), and those are tested in CI.
### Synchronization with Ruby Implementations
@@ -64,6 +64,7 @@ For older specs try these commits:
* Ruby 2.7.8 - [Suite](https://github.com/ruby/spec/commit/93787e6035c925b593a9c0c6fb0e7e07a6f1df1f) using [MSpec](https://github.com/ruby/mspec/commit/1d8cf64722d8a7529f7cd205be5f16a89b7a67fd)
* Ruby 3.0.7 - [Suite](https://github.com/ruby/spec/commit/affef93d9940f615e4836f64b011da211f570913) using [MSpec](https://github.com/ruby/mspec/commit/0aabb3e548eb5ea6cad0125f8f46cee34542b6b7)
* Ruby 3.1.6 - [Suite](https://github.com/ruby/spec/commit/ec960f2389d1c2265d32397fa8afa6d462014efc) using [MSpec](https://github.com/ruby/mspec/commit/484310dbed35b84c74484fd674602f88c42d063a)
+* Ruby 3.2.9 - [Suite](https://github.com/ruby/spec/commit/97f076242b7fc6e60703e6a6053365065cd6fc30) using [MSpec](https://github.com/ruby/mspec/commit/54704795e21128a930af2021c72c49cb87065134)
### Running the specs
diff --git a/spec/ruby/bin/rubocop b/spec/ruby/bin/rubocop
index 38254f13e4..0937c47906 100755
--- a/spec/ruby/bin/rubocop
+++ b/spec/ruby/bin/rubocop
@@ -6,7 +6,7 @@ require 'bundler/inline'
gemfile do
source 'https://rubygems.org'
- gem 'rubocop', '1.66.1'
+ gem 'rubocop', '1.86.2'
end
exec(Gem.bin_path('rubocop', 'rubocop'), *ARGV)
diff --git a/spec/ruby/command_line/dash_0_spec.rb b/spec/ruby/command_line/dash_0_spec.rb
index 73c5e29004..2ce4f49b5e 100755
--- a/spec/ruby/command_line/dash_0_spec.rb
+++ b/spec/ruby/command_line/dash_0_spec.rb
@@ -5,7 +5,7 @@ describe "The -0 command line option" do
ruby_exe("puts $/, $-0", options: "-072").should == ":\n:\n"
end
- ruby_version_is "3.5" do
+ ruby_version_is "4.0" do
it "sets $/ and $-0 as a frozen string" do
ruby_exe("puts $/.frozen?, $-0.frozen?", options: "-072").should == "true\ntrue\n"
end
diff --git a/spec/ruby/command_line/dash_r_spec.rb b/spec/ruby/command_line/dash_r_spec.rb
index 9f673c53dc..0de9ba2e24 100644
--- a/spec/ruby/command_line/dash_r_spec.rb
+++ b/spec/ruby/command_line/dash_r_spec.rb
@@ -8,18 +8,15 @@ describe "The -r command line option" do
it "requires the specified file" do
out = ruby_exe(@script, options: "-r #{@test_file}")
- out.should include("REQUIRED")
- out.should include(@test_file + ".rb")
+ out.should.include?("REQUIRED")
+ out.should.include?(@test_file + ".rb")
end
it "requires the file before parsing the main script" 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?("REQUIRED")
+ out.should.include?("SyntaxError")
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_i_spec.rb b/spec/ruby/command_line/dash_upper_i_spec.rb
index 4cafb724e3..4005a27d23 100644
--- a/spec/ruby/command_line/dash_upper_i_spec.rb
+++ b/spec/ruby/command_line/dash_upper_i_spec.rb
@@ -6,7 +6,7 @@ describe "The -I command line option" do
end
it "adds the path to the load path ($:)" do
- ruby_exe(@script, options: "-I fixtures").should include("fixtures")
+ ruby_exe(@script, options: "-I fixtures").should.include?("fixtures")
end
it "adds the path at the front of $LOAD_PATH" do
@@ -18,16 +18,16 @@ describe "The -I command line option" do
idx.should < 2
idx.should < lines.size-1
else
- lines[0].should include("fixtures")
+ lines[0].should.include?("fixtures")
end
end
it "adds the path expanded from CWD to $LOAD_PATH" do
- ruby_exe(@script, options: "-I fixtures").lines.should include "#{Dir.pwd}/fixtures\n"
+ ruby_exe(@script, options: "-I fixtures").lines.should.include? "#{Dir.pwd}/fixtures\n"
end
it "expands a path from CWD even if it does not exist" do
- ruby_exe(@script, options: "-I not_exist/not_exist").lines.should include "#{Dir.pwd}/not_exist/not_exist\n"
+ ruby_exe(@script, options: "-I not_exist/not_exist").lines.should.include? "#{Dir.pwd}/not_exist/not_exist\n"
end
end
@@ -45,7 +45,7 @@ platform_is_not :windows do
end
it "does not expand symlinks" do
- ruby_exe(@script, options: "-I #{@symlink}").lines.should include "#{@symlink}\n"
+ ruby_exe(@script, options: "-I #{@symlink}").lines.should.include? "#{@symlink}\n"
end
end
end
diff --git a/spec/ruby/command_line/dash_upper_s_spec.rb b/spec/ruby/command_line/dash_upper_s_spec.rb
index 17991503f1..71c6016659 100644
--- a/spec/ruby/command_line/dash_upper_s_spec.rb
+++ b/spec/ruby/command_line/dash_upper_s_spec.rb
@@ -2,7 +2,8 @@ require_relative '../spec_helper'
describe 'The -S command line option' do
before :each do
- @path = [ENV['PATH'], fixture(__FILE__, "bin")].join(':')
+ @bin = fixture(__FILE__, "bin")
+ @path = [ENV['PATH'], @bin].join(File::PATH_SEPARATOR)
end
platform_is_not :windows do
@@ -10,20 +11,57 @@ describe 'The -S command line option' do
# and MRI shows warning when including world writable path in ENV['PATH'].
# This is why we are using /success$/ matching in the following cases.
+ it "runs launcher found in RUBYPATH, but only code after the first /\#!.*ruby.*/-ish line in target file" do
+ result = ruby_exe(nil, options: '-S hybrid_launcher.sh', env: { 'RUBYPATH' => @bin }, args: '2>&1')
+ result.should =~ /success$/
+ end
+
it "runs launcher found in PATH, but only code after the first /\#!.*ruby.*/-ish line in target file" do
result = ruby_exe(nil, options: '-S hybrid_launcher.sh', env: { 'PATH' => @path }, args: '2>&1')
result.should =~ /success$/
end
+ it "runs launcher found in RUBYPATH" do
+ result = ruby_exe(nil, options: '-S launcher.rb', env: { 'RUBYPATH' => @bin }, args: '2>&1')
+ result.should =~ /success$/
+ end
+
it "runs launcher found in PATH" do
result = ruby_exe(nil, options: '-S launcher.rb', env: { 'PATH' => @path }, args: '2>&1')
result.should =~ /success$/
end
+ it "runs launcher found in RUBYPATH and sets the exit status to 1 if it fails" do
+ result = ruby_exe(nil, options: '-S dash_s_fail', env: { 'RUBYPATH' => @bin }, args: '2>&1', exit_status: 1)
+ result.should =~ /\bdie\b/
+ $?.exitstatus.should == 1
+ end
+
it "runs launcher found in PATH and sets the exit status to 1 if it fails" do
result = ruby_exe(nil, options: '-S dash_s_fail', env: { 'PATH' => @path }, args: '2>&1', exit_status: 1)
result.should =~ /\bdie\b/
$?.exitstatus.should == 1
end
+
+ ruby_version_is "4.1" do
+ describe "if the script name contains separator" do
+ before(:each) do
+ @bin = File.dirname(@bin)
+ @path = [ENV['PATH'], @bin].join(File::PATH_SEPARATOR)
+ end
+
+ it "does not search launcher in RUBYPATH" do
+ result = ruby_exe(nil, options: '-S bin/launcher.rb', env: { 'RUBYPATH' => @bin }, args: '2>&1', exit_status: 1)
+ result.should =~ /LoadError/
+ $?.should_not.success?
+ end
+
+ it "does not search launcher in PATH" do
+ result = ruby_exe(nil, options: '-S bin/launcher.rb', env: { 'PATH' => @path }, args: '2>&1', exit_status: 1)
+ result.should =~ /LoadError/
+ $?.should_not.success?
+ end
+ end
+ end
end
end
diff --git a/spec/ruby/command_line/dash_v_spec.rb b/spec/ruby/command_line/dash_v_spec.rb
index b13350404c..6a4f7d3a15 100644
--- a/spec/ruby/command_line/dash_v_spec.rb
+++ b/spec/ruby/command_line/dash_v_spec.rb
@@ -6,7 +6,7 @@ describe "The -v command line option" do
describe "when used alone" do
it "prints version and ends" do
- ruby_exe(nil, args: '-v').gsub("+PRISM ", "").should include(RUBY_DESCRIPTION.gsub("+PRISM ", ""))
+ ruby_exe(nil, args: '-v').gsub("+PRISM ", "").should.include?(RUBY_DESCRIPTION.gsub("+PRISM ", ""))
end unless (defined?(RubyVM::YJIT) && RubyVM::YJIT.enabled?) ||
(defined?(RubyVM::RJIT) && RubyVM::RJIT.enabled?) ||
(ENV['RUBY_GC_LIBRARY'] && ENV['RUBY_GC_LIBRARY'].length > 0) ||
diff --git a/spec/ruby/command_line/dash_x_spec.rb b/spec/ruby/command_line/dash_x_spec.rb
index ae14b61070..38f97a5ab1 100644
--- a/spec/ruby/command_line/dash_x_spec.rb
+++ b/spec/ruby/command_line/dash_x_spec.rb
@@ -10,7 +10,7 @@ describe "The -x command line option" do
it "fails when /\#!.*ruby.*/-ish line in target file is not found" do
bad_embedded_ruby = fixture __FILE__, "bin/bad_embedded_ruby.txt"
result = ruby_exe(bad_embedded_ruby, options: '-x', args: '2>&1', exit_status: 1)
- result.should include "no Ruby script found in input"
+ result.should.include? "no Ruby script found in input"
end
it "behaves as -x was set when non-ruby shebang is encountered on first line" do
diff --git a/spec/ruby/command_line/error_message_spec.rb b/spec/ruby/command_line/error_message_spec.rb
index 02150f30ce..157cb8969c 100644
--- a/spec/ruby/command_line/error_message_spec.rb
+++ b/spec/ruby/command_line/error_message_spec.rb
@@ -8,4 +8,9 @@ describe "The error message caused by an exception" do
out = ruby_exe("end #syntax error", args: "2> #{File::NULL}", exit_status: 1)
out.chomp.should.empty?
end
+
+ it "is not modified with extra escaping of control characters and backslashes" do
+ out = ruby_exe('raise "\e[31mRed\e[0m error\\\\message"', args: "2>&1", exit_status: 1)
+ out.chomp.should.include?("\e[31mRed\e[0m error\\message")
+ end
end
diff --git a/spec/ruby/command_line/feature_spec.rb b/spec/ruby/command_line/feature_spec.rb
index 4a24cc6795..0a3252b88d 100644
--- a/spec/ruby/command_line/feature_spec.rb
+++ b/spec/ruby/command_line/feature_spec.rb
@@ -51,7 +51,7 @@ describe "The --enable and --disable flags" do
env = {'RUBYOPT' => '-w'}
# Use a single variant here because it can be quite slow as it might enable jit, etc
ruby_exe(e, options: "--enable-all", env: env).chomp.should == "[\"constant\", \"constant\", true, true]"
- end
+ end unless defined?(RubyVM::YJIT) && defined?(RubyVM::ZJIT) && RubyVM::ZJIT.enabled? # You're not supposed to enable YJIT with --enable-all when ZJIT options are passed.
end
it "can be used with all for disable" do
@@ -62,10 +62,10 @@ describe "The --enable and --disable flags" do
end
it "prints a warning for unknown features" do
- ruby_exe("p 14", options: "--enable=ruby-spec-feature-does-not-exist 2>&1").chomp.should include('warning: unknown argument for --enable')
- ruby_exe("p 14", options: "--disable=ruby-spec-feature-does-not-exist 2>&1").chomp.should include('warning: unknown argument for --disable')
- ruby_exe("p 14", options: "--enable-ruby-spec-feature-does-not-exist 2>&1").chomp.should include('warning: unknown argument for --enable')
- ruby_exe("p 14", options: "--disable-ruby-spec-feature-does-not-exist 2>&1").chomp.should include('warning: unknown argument for --disable')
+ ruby_exe("p 14", options: "--enable=ruby-spec-feature-does-not-exist 2>&1").chomp.should.include?('warning: unknown argument for --enable')
+ ruby_exe("p 14", options: "--disable=ruby-spec-feature-does-not-exist 2>&1").chomp.should.include?('warning: unknown argument for --disable')
+ ruby_exe("p 14", options: "--enable-ruby-spec-feature-does-not-exist 2>&1").chomp.should.include?('warning: unknown argument for --enable')
+ ruby_exe("p 14", options: "--disable-ruby-spec-feature-does-not-exist 2>&1").chomp.should.include?('warning: unknown argument for --disable')
end
end
diff --git a/spec/ruby/command_line/fixtures/bin/bad_embedded_ruby.txt b/spec/ruby/command_line/fixtures/bin/bad_embedded_ruby.txt
index a2b7ad085f..61b946977a 100644
--- a/spec/ruby/command_line/fixtures/bin/bad_embedded_ruby.txt
+++ b/spec/ruby/command_line/fixtures/bin/bad_embedded_ruby.txt
@@ -1,3 +1,3 @@
-@@@This line is not value Ruby
+@@@This line is not valid Ruby
#!rub_y
puts 'success'
diff --git a/spec/ruby/command_line/fixtures/bin/embedded_ruby.txt b/spec/ruby/command_line/fixtures/bin/embedded_ruby.txt
index 1da779b1b9..0ec0f358db 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
+@@@This line is not valid Ruby
#!ruby
puts 'success'
diff --git a/spec/ruby/command_line/frozen_strings_spec.rb b/spec/ruby/command_line/frozen_strings_spec.rb
index 014153e0b4..32ff7d0371 100644
--- a/spec/ruby/command_line/frozen_strings_spec.rb
+++ b/spec/ruby/command_line/frozen_strings_spec.rb
@@ -42,8 +42,28 @@ describe "With neither --enable-frozen-string-literal nor --disable-frozen-strin
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"
+ context "if file has no frozen_string_literal comment" do
+ it "produce different mutable strings each time" do
+ ruby_exe(fixture(__FILE__, "string_literal_raw.rb")).chomp.should == "frozen:false interned:false"
+ end
+
+ guard -> { ruby_version_is "3.4" and !"test".frozen? } do
+ it "complain about modification of produced mutable strings" do
+ -> { eval(<<~RUBY) }.should complain(/warning: literal string will be frozen in the future \(run with --debug-frozen-string-literal for more information\)/)
+ "test" << "!"
+ RUBY
+ end
+
+ it "does not complain about modification if Warning[:deprecated] is false" do
+ deprecated = Warning[:deprecated]
+ Warning[:deprecated] = false
+ -> { eval(<<~RUBY) }.should_not complain
+ "test" << "!"
+ RUBY
+ ensure
+ Warning[:deprecated] = deprecated
+ end
+ end
end
it "if file has frozen_string_literal:true comment produce same frozen strings each time" do
@@ -58,17 +78,17 @@ 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: '--enable-frozen-string-literal --debug', args: "2>&1")
- error_str.should include("can't modify frozen String")
- error_str.should include("created at")
- error_str.should include("command_line/fixtures/debug_info.rb:1")
+ error_str.should.include?("can't modify frozen String")
+ error_str.should.include?("created at")
+ error_str.should.include?("command_line/fixtures/debug_info.rb:1")
end
guard -> { ruby_version_is "3.4" and !"test".frozen? } do
it "debugging info on mutating chilled string" do
error_str = ruby_exe(fixture(__FILE__, 'debug_info.rb'), options: '-w --debug', args: "2>&1")
- error_str.should include("literal string will be frozen in the future")
- error_str.should include("the string was created here")
- error_str.should include("command_line/fixtures/debug_info.rb:1")
+ error_str.should.include?("literal string will be frozen in the future")
+ error_str.should.include?("the string was created here")
+ error_str.should.include?("command_line/fixtures/debug_info.rb:1")
end
end
end
diff --git a/spec/ruby/command_line/rubylib_spec.rb b/spec/ruby/command_line/rubylib_spec.rb
index b45919b997..1bedd146e3 100644
--- a/spec/ruby/command_line/rubylib_spec.rb
+++ b/spec/ruby/command_line/rubylib_spec.rb
@@ -14,15 +14,15 @@ describe "The RUBYLIB environment variable" do
dir = tmp("rubylib/incl")
ENV["RUBYLIB"] = @pre + dir
paths = ruby_exe("puts $LOAD_PATH").lines.map(&:chomp)
- paths.should include(dir)
+ paths.should.include?(dir)
end
it "adds a File::PATH_SEPARATOR-separated list of directories to $LOAD_PATH" do
dir1, dir2 = tmp("rubylib/incl1"), tmp("rubylib/incl2")
ENV["RUBYLIB"] = @pre + "#{dir1}#{File::PATH_SEPARATOR}#{dir2}"
paths = ruby_exe("puts $LOAD_PATH").lines.map(&:chomp)
- paths.should include(dir1)
- paths.should include(dir2)
+ paths.should.include?(dir1)
+ paths.should.include?(dir2)
paths.index(dir1).should < paths.index(dir2)
end
@@ -46,8 +46,8 @@ describe "The RUBYLIB environment variable" do
rubylib_dir = tmp("rubylib_include")
ENV["RUBYLIB"] = @pre + rubylib_dir
paths = ruby_exe("puts $LOAD_PATH", options: "-I #{dash_i_dir}").lines.map(&:chomp)
- paths.should include(dash_i_dir)
- paths.should include(rubylib_dir)
+ paths.should.include?(dash_i_dir)
+ paths.should.include?(rubylib_dir)
paths.index(dash_i_dir).should < paths.index(rubylib_dir)
end
@@ -56,14 +56,14 @@ describe "The RUBYLIB environment variable" do
rubylib_dir = tmp("rubylib_include")
ENV["RUBYLIB"] = @pre + rubylib_dir
paths = ruby_exe("puts $LOAD_PATH", env: { "RUBYOPT" => "-I#{rubyopt_dir}" }).lines.map(&:chomp)
- paths.should include(rubyopt_dir)
- paths.should include(rubylib_dir)
+ paths.should.include?(rubyopt_dir)
+ paths.should.include?(rubylib_dir)
paths.index(rubyopt_dir).should < paths.index(rubylib_dir)
end
it "keeps spaces in the value" do
ENV["RUBYLIB"] = @pre + " rubylib/incl "
out = ruby_exe("puts $LOAD_PATH")
- out.should include(" rubylib/incl ")
+ out.should.include?(" rubylib/incl ")
end
end
diff --git a/spec/ruby/command_line/rubyopt_spec.rb b/spec/ruby/command_line/rubyopt_spec.rb
index e1163ffcfc..eb297cd6fe 100644
--- a/spec/ruby/command_line/rubyopt_spec.rb
+++ b/spec/ruby/command_line/rubyopt_spec.rb
@@ -25,12 +25,12 @@ describe "Processing RUBYOPT" do
guard -> { RbConfig::CONFIG["CROSS_COMPILING"] != "yes" } do
it "prints the version number for '-v'" do
ENV["RUBYOPT"] = '-v'
- ruby_exe("")[/\A.*/].gsub(/\s\+(PRISM|GC(\[\w+\])?)(?=\s)/, "").should == RUBY_DESCRIPTION.gsub(/\s\+(PRISM|GC(\[\w+\])?)(?=\s)/, "")
+ ruby_exe("")[/\A.*/].gsub(/\s\+(YJIT( \w+)?|ZJIT( \w+)?|PRISM|GC(\[\w+\])?)(?=\s)/, "").should == RUBY_DESCRIPTION.gsub(/\s\+(YJIT( \w+)?|ZJIT( \w+)?|PRISM|GC(\[\w+\])?)(?=\s)/, "")
end
it "ignores whitespace around the option" do
ENV["RUBYOPT"] = ' -v '
- ruby_exe("")[/\A.*/].gsub(/\s\+(PRISM|GC(\[\w+\])?)(?=\s)/, "").should == RUBY_DESCRIPTION.gsub(/\s\+(PRISM|GC(\[\w+\])?)(?=\s)/, "")
+ ruby_exe("")[/\A.*/].gsub(/\s\+(YJIT( \w+)?|ZJIT( \w+)?|PRISM|GC(\[\w+\])?)(?=\s)/, "").should == RUBY_DESCRIPTION.gsub(/\s\+(YJIT( \w+)?|ZJIT( \w+)?|PRISM|GC(\[\w+\])?)(?=\s)/, "")
end
end
diff --git a/spec/ruby/command_line/syntax_error_spec.rb b/spec/ruby/command_line/syntax_error_spec.rb
index 9ba87b9e22..88864c048e 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?("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)
-
- # 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?("SyntaxError")
end
end
diff --git a/spec/ruby/core/argf/argf_spec.rb b/spec/ruby/core/argf/argf_spec.rb
index af67170b98..f9468539bb 100644
--- a/spec/ruby/core/argf/argf_spec.rb
+++ b/spec/ruby/core/argf/argf_spec.rb
@@ -2,10 +2,10 @@ require_relative '../../spec_helper'
describe "ARGF" do
it "is extended by the Enumerable module" do
- ARGF.should be_kind_of(Enumerable)
+ ARGF.should.is_a?(Enumerable)
end
it "is an instance of ARGF.class" do
- ARGF.should be_an_instance_of(ARGF.class)
+ ARGF.should.instance_of?(ARGF.class)
end
end
diff --git a/spec/ruby/core/argf/argv_spec.rb b/spec/ruby/core/argf/argv_spec.rb
index eab03c450f..77dfe78c21 100644
--- a/spec/ruby/core/argf/argv_spec.rb
+++ b/spec/ruby/core/argf/argv_spec.rb
@@ -7,7 +7,7 @@ describe "ARGF.argv" do
end
it "returns ARGV for the initial ARGF" do
- ARGF.argv.should equal ARGV
+ ARGF.argv.should.equal? ARGV
end
it "returns the remaining arguments to treat" do
diff --git a/spec/ruby/core/argf/binmode_spec.rb b/spec/ruby/core/argf/binmode_spec.rb
index e083a30a27..5288e3199d 100644
--- a/spec/ruby/core/argf/binmode_spec.rb
+++ b/spec/ruby/core/argf/binmode_spec.rb
@@ -9,7 +9,7 @@ describe "ARGF.binmode" do
it "returns self" do
argf [@bin_file] do
- @argf.binmode.should equal @argf
+ @argf.binmode.should.equal? @argf
end
end
diff --git a/spec/ruby/core/argf/close_spec.rb b/spec/ruby/core/argf/close_spec.rb
index d4d6a51e72..8ca7d71dc2 100644
--- a/spec/ruby/core/argf/close_spec.rb
+++ b/spec/ruby/core/argf/close_spec.rb
@@ -10,20 +10,20 @@ describe "ARGF.close" do
argf [@file1_name, @file2_name] do
io = @argf.to_io
@argf.close
- io.closed?.should be_true
+ io.closed?.should == true
end
end
it "returns self" do
argf [@file1_name, @file2_name] do
- @argf.close.should equal(@argf)
+ @argf.close.should.equal?(@argf)
end
end
it "doesn't raise an IOError if called on a closed stream" do
argf [@file1_name] do
- -> { @argf.close }.should_not raise_error
- -> { @argf.close }.should_not raise_error
+ -> { @argf.close }.should_not.raise
+ -> { @argf.close }.should_not.raise
end
end
end
diff --git a/spec/ruby/core/argf/closed_spec.rb b/spec/ruby/core/argf/closed_spec.rb
index e2dd6134e5..769381e8c3 100644
--- a/spec/ruby/core/argf/closed_spec.rb
+++ b/spec/ruby/core/argf/closed_spec.rb
@@ -11,7 +11,7 @@ describe "ARGF.closed?" do
stream = @argf.to_io
stream.close
- @argf.closed?.should be_true
+ @argf.closed?.should == true
stream.reopen(@argf.filename, 'r')
end
end
diff --git a/spec/ruby/core/argf/each_byte_spec.rb b/spec/ruby/core/argf/each_byte_spec.rb
index c5cce9f250..d9e4e7fe5b 100644
--- a/spec/ruby/core/argf/each_byte_spec.rb
+++ b/spec/ruby/core/argf/each_byte_spec.rb
@@ -1,6 +1,60 @@
require_relative '../../spec_helper'
-require_relative 'shared/each_byte'
describe "ARGF.each_byte" do
- it_behaves_like :argf_each_byte, :each_byte
+ before :each do
+ @file1_name = fixture __FILE__, "file1.txt"
+ @file2_name = fixture __FILE__, "file2.txt"
+
+ @bytes = []
+ File.read(@file1_name).each_byte { |b| @bytes << b }
+ File.read(@file2_name).each_byte { |b| @bytes << b }
+ end
+
+ it "yields each byte of all streams to the passed block" do
+ argf [@file1_name, @file2_name] do
+ bytes = []
+ @argf.each_byte { |b| bytes << b }
+ bytes.should == @bytes
+ end
+ end
+
+ it "returns self when passed a block" do
+ argf [@file1_name, @file2_name] do
+ @argf.each_byte {}.should.equal?(@argf)
+ end
+ end
+
+ it "returns an Enumerator when passed no block" do
+ argf [@file1_name, @file2_name] do
+ enum = @argf.each_byte
+ enum.should.instance_of?(Enumerator)
+
+ bytes = []
+ enum.each { |b| bytes << b }
+ bytes.should == @bytes
+ end
+ end
+
+ describe "when no block is given" do
+ it "returns an Enumerator" do
+ argf [@file1_name, @file2_name] do
+ enum = @argf.each_byte
+ enum.should.instance_of?(Enumerator)
+
+ bytes = []
+ enum.each { |b| bytes << b }
+ bytes.should == @bytes
+ end
+ end
+
+ describe "returned Enumerator" do
+ describe "size" do
+ it "should return nil" do
+ argf [@file1_name, @file2_name] do
+ @argf.each_byte.size.should == nil
+ end
+ end
+ end
+ end
+ end
end
diff --git a/spec/ruby/core/argf/each_char_spec.rb b/spec/ruby/core/argf/each_char_spec.rb
index 724e5e6e3e..62d19b6574 100644
--- a/spec/ruby/core/argf/each_char_spec.rb
+++ b/spec/ruby/core/argf/each_char_spec.rb
@@ -1,6 +1,60 @@
require_relative '../../spec_helper'
-require_relative 'shared/each_char'
describe "ARGF.each_char" do
- it_behaves_like :argf_each_char, :each_char
+ before :each do
+ @file1_name = fixture __FILE__, "file1.txt"
+ @file2_name = fixture __FILE__, "file2.txt"
+
+ @chars = []
+ File.read(@file1_name).each_char { |c| @chars << c }
+ File.read(@file2_name).each_char { |c| @chars << c }
+ end
+
+ it "yields each char of all streams to the passed block" do
+ argf [@file1_name, @file2_name] do
+ chars = []
+ @argf.each_char { |c| chars << c }
+ chars.should == @chars
+ end
+ end
+
+ it "returns self when passed a block" do
+ argf [@file1_name, @file2_name] do
+ @argf.each_char {}.should.equal?(@argf)
+ end
+ end
+
+ it "returns an Enumerator when passed no block" do
+ argf [@file1_name, @file2_name] do
+ enum = @argf.each_char
+ enum.should.instance_of?(Enumerator)
+
+ chars = []
+ enum.each { |c| chars << c }
+ chars.should == @chars
+ end
+ end
+
+ describe "when no block is given" do
+ it "returns an Enumerator" do
+ argf [@file1_name, @file2_name] do
+ enum = @argf.each_char
+ enum.should.instance_of?(Enumerator)
+
+ chars = []
+ enum.each { |c| chars << c }
+ chars.should == @chars
+ end
+ end
+
+ describe "returned Enumerator" do
+ describe "size" do
+ it "should return nil" do
+ argf [@file1_name, @file2_name] do
+ @argf.each_char.size.should == nil
+ end
+ end
+ end
+ end
+ end
end
diff --git a/spec/ruby/core/argf/each_codepoint_spec.rb b/spec/ruby/core/argf/each_codepoint_spec.rb
index 0bf8bf9764..ad55785cba 100644
--- a/spec/ruby/core/argf/each_codepoint_spec.rb
+++ b/spec/ruby/core/argf/each_codepoint_spec.rb
@@ -1,6 +1,60 @@
require_relative '../../spec_helper'
-require_relative 'shared/each_codepoint'
describe "ARGF.each_codepoint" do
- it_behaves_like :argf_each_codepoint, :each_codepoint
+ before :each do
+ file1_name = fixture __FILE__, "file1.txt"
+ file2_name = fixture __FILE__, "file2.txt"
+ @filenames = [file1_name, file2_name]
+
+ @codepoints = File.read(file1_name).codepoints
+ @codepoints.concat File.read(file2_name).codepoints
+ end
+
+ it "is a public method" do
+ argf @filenames do
+ @argf.public_methods(false).should.include?(:each_codepoint)
+ end
+ end
+
+ it "does not require arguments" do
+ argf @filenames do
+ @argf.method(:each_codepoint).arity.should == 0
+ end
+ end
+
+ it "returns self when passed a block" do
+ argf @filenames do
+ @argf.each_codepoint {}.should.equal?(@argf)
+ end
+ end
+
+ it "returns an Enumerator when passed no block" do
+ argf @filenames do
+ @argf.each_codepoint.should.instance_of?(Enumerator)
+ end
+ end
+
+ it "yields each codepoint of all streams" do
+ argf @filenames do
+ @argf.each_codepoint.to_a.should == @codepoints
+ end
+ end
+
+ describe "when no block is given" do
+ it "returns an Enumerator" do
+ argf @filenames do
+ @argf.each_codepoint.should.instance_of?(Enumerator)
+ end
+ end
+
+ describe "returned Enumerator" do
+ describe "size" do
+ it "should return nil" do
+ argf @filenames do
+ @argf.each_codepoint.size.should == nil
+ end
+ end
+ end
+ end
+ end
end
diff --git a/spec/ruby/core/argf/each_line_spec.rb b/spec/ruby/core/argf/each_line_spec.rb
index 52a7e5c411..fc4d6433b8 100644
--- a/spec/ruby/core/argf/each_line_spec.rb
+++ b/spec/ruby/core/argf/each_line_spec.rb
@@ -1,6 +1,64 @@
require_relative '../../spec_helper'
-require_relative 'shared/each_line'
describe "ARGF.each_line" do
- it_behaves_like :argf_each_line, :each_line
+ before :each do
+ @file1_name = fixture __FILE__, "file1.txt"
+ @file2_name = fixture __FILE__, "file2.txt"
+
+ @lines = File.readlines @file1_name
+ @lines += File.readlines @file2_name
+ end
+
+ it "is a public method" do
+ argf [@file1_name, @file2_name] do
+ @argf.public_methods(false).should.include?(:each_line)
+ end
+ end
+
+ it "requires multiple arguments" do
+ argf [@file1_name, @file2_name] do
+ @argf.method(:each_line).arity.should < 0
+ end
+ end
+
+ it "reads each line of files" do
+ argf [@file1_name, @file2_name] do
+ lines = []
+ @argf.each_line { |b| lines << b }
+ lines.should == @lines
+ end
+ end
+
+ it "returns self when passed a block" do
+ argf [@file1_name, @file2_name] do
+ @argf.each_line {}.should.equal?(@argf)
+ end
+ end
+
+ describe "with a separator" do
+ it "yields each separated section of all streams" do
+ argf [@file1_name, @file2_name] do
+ @argf.send(:each_line, '.').to_a.should ==
+ (File.readlines(@file1_name, '.') + File.readlines(@file2_name, '.'))
+ end
+ end
+ end
+
+ describe "when no block is given" do
+ it "returns an Enumerator" do
+ argf [@file1_name, @file2_name] do
+ @argf.each_line.should.instance_of?(Enumerator)
+ end
+ end
+
+ describe "returned Enumerator" do
+ describe "size" do
+ it "should return nil" do
+ argf [@file1_name, @file2_name] do
+ @argf.each_line.size.should == nil
+ end
+ end
+ end
+ end
+ end
end
diff --git a/spec/ruby/core/argf/each_spec.rb b/spec/ruby/core/argf/each_spec.rb
index 5742ba43bd..25f60b31d2 100644
--- a/spec/ruby/core/argf/each_spec.rb
+++ b/spec/ruby/core/argf/each_spec.rb
@@ -1,6 +1,7 @@
require_relative '../../spec_helper'
-require_relative 'shared/each_line'
describe "ARGF.each" do
- it_behaves_like :argf_each_line, :each
+ it "is an alias of ARGF.each_line" do
+ ARGF.method(:each).should == ARGF.method(:each_line)
+ end
end
diff --git a/spec/ruby/core/argf/eof_spec.rb b/spec/ruby/core/argf/eof_spec.rb
index 518f6e566e..940d104d69 100644
--- a/spec/ruby/core/argf/eof_spec.rb
+++ b/spec/ruby/core/argf/eof_spec.rb
@@ -1,10 +1,32 @@
require_relative '../../spec_helper'
-require_relative 'shared/eof'
describe "ARGF.eof" do
- it_behaves_like :argf_eof, :eof
+ it "is an alias of ARGF.eof?" do
+ ARGF.method(:eof).should == ARGF.method(:eof?)
+ end
end
describe "ARGF.eof?" do
- it_behaves_like :argf_eof, :eof?
+ before :each do
+ @file1 = fixture __FILE__, "file1.txt"
+ @file2 = fixture __FILE__, "file2.txt"
+ end
+
+ # NOTE: this test assumes that fixtures files have two lines each
+ it "returns true when reaching the end of a file" do
+ argf [@file1, @file2] do
+ result = []
+ while @argf.gets
+ result << @argf.eof?
+ end
+ result.should == [false, true, false, true]
+ end
+ end
+
+ it "raises IOError when called on a closed stream" do
+ argf [@file1] do
+ @argf.read
+ -> { @argf.eof? }.should.raise(IOError)
+ end
+ end
end
diff --git a/spec/ruby/core/argf/filename_spec.rb b/spec/ruby/core/argf/filename_spec.rb
index 7c0446269d..f4b6e922c6 100644
--- a/spec/ruby/core/argf/filename_spec.rb
+++ b/spec/ruby/core/argf/filename_spec.rb
@@ -1,6 +1,30 @@
require_relative '../../spec_helper'
-require_relative 'shared/filename'
describe "ARGF.filename" do
- it_behaves_like :argf_filename, :filename
+ before :each do
+ @file1 = fixture __FILE__, "file1.txt"
+ @file2 = fixture __FILE__, "file2.txt"
+ end
+
+ # NOTE: this test assumes that fixtures files have two lines each
+ it "returns the current file name on each file" do
+ argf [@file1, @file2] do
+ result = []
+ # returns first current file even when not yet open
+ result << @argf.filename
+ result << @argf.filename while @argf.gets
+ # returns last current file even when closed
+ result << @argf.filename
+
+ result.map! { |f| File.expand_path(f) }
+ result.should == [@file1, @file1, @file1, @file2, @file2, @file2]
+ end
+ end
+
+ # NOTE: this test assumes that fixtures files have two lines each
+ it "sets the $FILENAME global variable with the current file name on each file" do
+ script = fixture __FILE__, "filename.rb"
+ out = ruby_exe(script, args: [@file1, @file2])
+ out.should == "#{@file1}\n#{@file1}\n#{@file2}\n#{@file2}\n#{@file2}\n"
+ end
end
diff --git a/spec/ruby/core/argf/fileno_spec.rb b/spec/ruby/core/argf/fileno_spec.rb
index 29d50c3582..99245f043c 100644
--- a/spec/ruby/core/argf/fileno_spec.rb
+++ b/spec/ruby/core/argf/fileno_spec.rb
@@ -1,6 +1,26 @@
require_relative '../../spec_helper'
-require_relative 'shared/fileno'
describe "ARGF.fileno" do
- it_behaves_like :argf_fileno, :fileno
+ before :each do
+ @file1 = fixture __FILE__, "file1.txt"
+ @file2 = fixture __FILE__, "file2.txt"
+ end
+
+ # NOTE: this test assumes that fixtures files have two lines each
+ it "returns the current file number on each file" do
+ argf [@file1, @file2] do
+ result = []
+ # returns first current file even when not yet open
+ result << @argf.fileno while @argf.gets
+ # returns last current file even when closed
+ result.map { |d| d.class }.should == [Integer, Integer, Integer, Integer]
+ end
+ end
+
+ it "raises an ArgumentError when called on a closed stream" do
+ argf [@file1] do
+ @argf.read
+ -> { @argf.fileno }.should.raise(ArgumentError)
+ end
+ end
end
diff --git a/spec/ruby/core/argf/inspect_spec.rb b/spec/ruby/core/argf/inspect_spec.rb
new file mode 100644
index 0000000000..df0e3ba8dc
--- /dev/null
+++ b/spec/ruby/core/argf/inspect_spec.rb
@@ -0,0 +1,7 @@
+require_relative '../../spec_helper'
+
+describe "ARGF.inspect" do
+ it "is an alias of ARGF.to_s" do
+ ARGF.method(:inspect).should == ARGF.method(:to_s)
+ end
+end
diff --git a/spec/ruby/core/argf/path_spec.rb b/spec/ruby/core/argf/path_spec.rb
index 7120f7d0e3..2f7b91999f 100644
--- a/spec/ruby/core/argf/path_spec.rb
+++ b/spec/ruby/core/argf/path_spec.rb
@@ -1,6 +1,7 @@
require_relative '../../spec_helper'
-require_relative 'shared/filename'
describe "ARGF.path" do
- it_behaves_like :argf_filename, :path
+ it "is an alias of ARGF.filename" do
+ ARGF.method(:path).should == ARGF.method(:filename)
+ end
end
diff --git a/spec/ruby/core/argf/pos_spec.rb b/spec/ruby/core/argf/pos_spec.rb
index fb3f25b945..1ff16e4f17 100644
--- a/spec/ruby/core/argf/pos_spec.rb
+++ b/spec/ruby/core/argf/pos_spec.rb
@@ -1,8 +1,35 @@
require_relative '../../spec_helper'
-require_relative 'shared/pos'
describe "ARGF.pos" do
- it_behaves_like :argf_pos, :pos
+ before :each do
+ @file1 = fixture __FILE__, "file1.txt"
+ @file2 = fixture __FILE__, "file2.txt"
+ end
+
+ it "gives the correct position for each read operation" do
+ argf [@file1, @file2] do
+ size1 = File.size(@file1)
+ size2 = File.size(@file2)
+
+ @argf.read(2)
+ @argf.pos.should == 2
+ @argf.read(size1-2)
+ @argf.pos.should == size1
+ @argf.read(6)
+ @argf.pos.should == 6
+ @argf.rewind
+ @argf.pos.should == 0
+ @argf.read(size2)
+ @argf.pos.should == size2
+ end
+ end
+
+ it "raises an ArgumentError when called on a closed stream" do
+ argf [@file1] do
+ @argf.read
+ -> { @argf.pos }.should.raise(ArgumentError)
+ end
+ end
end
describe "ARGF.pos=" do
diff --git a/spec/ruby/core/argf/read_nonblock_spec.rb b/spec/ruby/core/argf/read_nonblock_spec.rb
index 804a459a62..5c6bd52d80 100644
--- a/spec/ruby/core/argf/read_nonblock_spec.rb
+++ b/spec/ruby/core/argf/read_nonblock_spec.rb
@@ -66,7 +66,7 @@ platform_is_not :windows do
argf ['-'] do
-> {
@argf.read_nonblock(4)
- }.should raise_error(IO::EAGAINWaitReadable)
+ }.should.raise(IO::EAGAINWaitReadable)
end
end
diff --git a/spec/ruby/core/argf/readchar_spec.rb b/spec/ruby/core/argf/readchar_spec.rb
index 4eca2efcf7..63632721ec 100644
--- a/spec/ruby/core/argf/readchar_spec.rb
+++ b/spec/ruby/core/argf/readchar_spec.rb
@@ -13,7 +13,7 @@ describe "ARGF.readchar" do
it "raises EOFError when end of stream reached" do
argf [@file1, @file2] do
- -> { while @argf.readchar; end }.should raise_error(EOFError)
+ -> { while @argf.readchar; end }.should.raise(EOFError)
end
end
end
diff --git a/spec/ruby/core/argf/readline_spec.rb b/spec/ruby/core/argf/readline_spec.rb
index db53c499e9..8c23549b1b 100644
--- a/spec/ruby/core/argf/readline_spec.rb
+++ b/spec/ruby/core/argf/readline_spec.rb
@@ -17,7 +17,7 @@ describe "ARGF.readline" do
it "raises an EOFError when reaching end of files" do
argf [@file1, @file2] do
- -> { while @argf.readline; end }.should raise_error(EOFError)
+ -> { while @argf.readline; end }.should.raise(EOFError)
end
end
end
diff --git a/spec/ruby/core/argf/readlines_spec.rb b/spec/ruby/core/argf/readlines_spec.rb
index 30be936dab..156bb6a33f 100644
--- a/spec/ruby/core/argf/readlines_spec.rb
+++ b/spec/ruby/core/argf/readlines_spec.rb
@@ -1,6 +1,24 @@
require_relative '../../spec_helper'
-require_relative 'shared/readlines'
describe "ARGF.readlines" do
- it_behaves_like :argf_readlines, :readlines
+ before :each do
+ @file1 = fixture __FILE__, "file1.txt"
+ @file2 = fixture __FILE__, "file2.txt"
+
+ @lines = File.readlines(@file1)
+ @lines += File.readlines(@file2)
+ end
+
+ it "reads all lines of all files" do
+ argf [@file1, @file2] do
+ @argf.readlines.should == @lines
+ end
+ end
+
+ it "returns an empty Array when end of stream reached" do
+ argf [@file1, @file2] do
+ @argf.read
+ @argf.readlines.should == []
+ end
+ end
end
diff --git a/spec/ruby/core/argf/readpartial_spec.rb b/spec/ruby/core/argf/readpartial_spec.rb
index ea4301f25c..9f04e72cc2 100644
--- a/spec/ruby/core/argf/readpartial_spec.rb
+++ b/spec/ruby/core/argf/readpartial_spec.rb
@@ -16,7 +16,7 @@ describe "ARGF.readpartial" do
it "raises an ArgumentError if called without a maximum read length" do
argf [@file1_name] do
- -> { @argf.readpartial }.should raise_error(ArgumentError)
+ -> { @argf.readpartial }.should.raise(ArgumentError)
end
end
@@ -59,8 +59,8 @@ describe "ARGF.readpartial" do
@argf.readpartial(@file1.size)
@argf.readpartial(1)
@argf.readpartial(@file2.size)
- -> { @argf.readpartial(1) }.should raise_error(EOFError)
- -> { @argf.readpartial(1) }.should raise_error(EOFError)
+ -> { @argf.readpartial(1) }.should.raise(EOFError)
+ -> { @argf.readpartial(1) }.should.raise(EOFError)
end
end
diff --git a/spec/ruby/core/argf/rewind_spec.rb b/spec/ruby/core/argf/rewind_spec.rb
index b29f0b75b7..9255f790fe 100644
--- a/spec/ruby/core/argf/rewind_spec.rb
+++ b/spec/ruby/core/argf/rewind_spec.rb
@@ -33,7 +33,7 @@ describe "ARGF.rewind" do
it "raises an ArgumentError when end of stream reached" do
argf [@file1_name, @file2_name] do
@argf.read
- -> { @argf.rewind }.should raise_error(ArgumentError)
+ -> { @argf.rewind }.should.raise(ArgumentError)
end
end
end
diff --git a/spec/ruby/core/argf/seek_spec.rb b/spec/ruby/core/argf/seek_spec.rb
index 2b73bd46fb..c1ea1ea438 100644
--- a/spec/ruby/core/argf/seek_spec.rb
+++ b/spec/ruby/core/argf/seek_spec.rb
@@ -57,7 +57,7 @@ describe "ARGF.seek" do
it "takes at least one argument (offset)" do
argf [@file1_name] do
- -> { @argf.seek }.should raise_error(ArgumentError)
+ -> { @argf.seek }.should.raise(ArgumentError)
end
end
end
diff --git a/spec/ruby/core/argf/shared/each_byte.rb b/spec/ruby/core/argf/shared/each_byte.rb
deleted file mode 100644
index 6b1dc1dae2..0000000000
--- a/spec/ruby/core/argf/shared/each_byte.rb
+++ /dev/null
@@ -1,58 +0,0 @@
-describe :argf_each_byte, shared: true do
- before :each do
- @file1_name = fixture __FILE__, "file1.txt"
- @file2_name = fixture __FILE__, "file2.txt"
-
- @bytes = []
- File.read(@file1_name).each_byte { |b| @bytes << b }
- File.read(@file2_name).each_byte { |b| @bytes << b }
- end
-
- it "yields each byte of all streams to the passed block" do
- argf [@file1_name, @file2_name] do
- bytes = []
- @argf.send(@method) { |b| bytes << b }
- bytes.should == @bytes
- end
- end
-
- it "returns self when passed a block" do
- argf [@file1_name, @file2_name] do
- @argf.send(@method) {}.should equal(@argf)
- end
- end
-
- it "returns an Enumerator when passed no block" do
- argf [@file1_name, @file2_name] do
- enum = @argf.send(@method)
- enum.should be_an_instance_of(Enumerator)
-
- bytes = []
- enum.each { |b| bytes << b }
- bytes.should == @bytes
- end
- end
-
- describe "when no block is given" do
- it "returns an Enumerator" do
- argf [@file1_name, @file2_name] do
- enum = @argf.send(@method)
- enum.should be_an_instance_of(Enumerator)
-
- bytes = []
- enum.each { |b| bytes << b }
- bytes.should == @bytes
- end
- end
-
- describe "returned Enumerator" do
- describe "size" do
- it "should return nil" do
- argf [@file1_name, @file2_name] do
- @argf.send(@method).size.should == nil
- end
- end
- end
- end
- end
-end
diff --git a/spec/ruby/core/argf/shared/each_char.rb b/spec/ruby/core/argf/shared/each_char.rb
deleted file mode 100644
index 9e333ecc5b..0000000000
--- a/spec/ruby/core/argf/shared/each_char.rb
+++ /dev/null
@@ -1,58 +0,0 @@
-describe :argf_each_char, shared: true do
- before :each do
- @file1_name = fixture __FILE__, "file1.txt"
- @file2_name = fixture __FILE__, "file2.txt"
-
- @chars = []
- File.read(@file1_name).each_char { |c| @chars << c }
- File.read(@file2_name).each_char { |c| @chars << c }
- end
-
- it "yields each char of all streams to the passed block" do
- argf [@file1_name, @file2_name] do
- chars = []
- @argf.send(@method) { |c| chars << c }
- chars.should == @chars
- end
- end
-
- it "returns self when passed a block" do
- argf [@file1_name, @file2_name] do
- @argf.send(@method) {}.should equal(@argf)
- end
- end
-
- it "returns an Enumerator when passed no block" do
- argf [@file1_name, @file2_name] do
- enum = @argf.send(@method)
- enum.should be_an_instance_of(Enumerator)
-
- chars = []
- enum.each { |c| chars << c }
- chars.should == @chars
- end
- end
-
- describe "when no block is given" do
- it "returns an Enumerator" do
- argf [@file1_name, @file2_name] do
- enum = @argf.send(@method)
- enum.should be_an_instance_of(Enumerator)
-
- chars = []
- enum.each { |c| chars << c }
- chars.should == @chars
- end
- end
-
- describe "returned Enumerator" do
- describe "size" do
- it "should return nil" do
- argf [@file1_name, @file2_name] do
- @argf.send(@method).size.should == nil
- end
- end
- end
- end
- end
-end
diff --git a/spec/ruby/core/argf/shared/each_codepoint.rb b/spec/ruby/core/argf/shared/each_codepoint.rb
deleted file mode 100644
index e2a2dfff46..0000000000
--- a/spec/ruby/core/argf/shared/each_codepoint.rb
+++ /dev/null
@@ -1,58 +0,0 @@
-describe :argf_each_codepoint, shared: true do
- before :each do
- file1_name = fixture __FILE__, "file1.txt"
- file2_name = fixture __FILE__, "file2.txt"
- @filenames = [file1_name, file2_name]
-
- @codepoints = File.read(file1_name).codepoints
- @codepoints.concat File.read(file2_name).codepoints
- end
-
- it "is a public method" do
- argf @filenames do
- @argf.public_methods(false).should include(@method)
- end
- end
-
- it "does not require arguments" do
- argf @filenames do
- @argf.method(@method).arity.should == 0
- end
- end
-
- it "returns self when passed a block" do
- argf @filenames do
- @argf.send(@method) {}.should equal(@argf)
- end
- end
-
- it "returns an Enumerator when passed no block" do
- argf @filenames do
- @argf.send(@method).should be_an_instance_of(Enumerator)
- end
- end
-
- it "yields each codepoint of all streams" do
- argf @filenames do
- @argf.send(@method).to_a.should == @codepoints
- end
- end
-
- describe "when no block is given" do
- it "returns an Enumerator" do
- argf @filenames do
- @argf.send(@method).should be_an_instance_of(Enumerator)
- end
- end
-
- describe "returned Enumerator" do
- describe "size" do
- it "should return nil" do
- argf @filenames do
- @argf.send(@method).size.should == nil
- end
- end
- end
- end
- end
-end
diff --git a/spec/ruby/core/argf/shared/each_line.rb b/spec/ruby/core/argf/shared/each_line.rb
deleted file mode 100644
index c0ef77dc54..0000000000
--- a/spec/ruby/core/argf/shared/each_line.rb
+++ /dev/null
@@ -1,62 +0,0 @@
-describe :argf_each_line, shared: true do
- before :each do
- @file1_name = fixture __FILE__, "file1.txt"
- @file2_name = fixture __FILE__, "file2.txt"
-
- @lines = File.readlines @file1_name
- @lines += File.readlines @file2_name
- end
-
- it "is a public method" do
- argf [@file1_name, @file2_name] do
- @argf.public_methods(false).should include(@method)
- end
- end
-
- it "requires multiple arguments" do
- argf [@file1_name, @file2_name] do
- @argf.method(@method).arity.should < 0
- end
- end
-
- it "reads each line of files" do
- argf [@file1_name, @file2_name] do
- lines = []
- @argf.send(@method) { |b| lines << b }
- lines.should == @lines
- end
- end
-
- it "returns self when passed a block" do
- argf [@file1_name, @file2_name] do
- @argf.send(@method) {}.should equal(@argf)
- end
- end
-
- describe "with a separator" do
- it "yields each separated section of all streams" do
- argf [@file1_name, @file2_name] do
- @argf.send(@method, '.').to_a.should ==
- (File.readlines(@file1_name, '.') + File.readlines(@file2_name, '.'))
- end
- end
- end
-
- describe "when no block is given" do
- it "returns an Enumerator" do
- argf [@file1_name, @file2_name] do
- @argf.send(@method).should be_an_instance_of(Enumerator)
- end
- end
-
- describe "returned Enumerator" do
- describe "size" do
- it "should return nil" do
- argf [@file1_name, @file2_name] do
- @argf.send(@method).size.should == nil
- end
- end
- end
- end
- end
-end
diff --git a/spec/ruby/core/argf/shared/eof.rb b/spec/ruby/core/argf/shared/eof.rb
deleted file mode 100644
index 0e684f943f..0000000000
--- a/spec/ruby/core/argf/shared/eof.rb
+++ /dev/null
@@ -1,24 +0,0 @@
-describe :argf_eof, shared: true do
- before :each do
- @file1 = fixture __FILE__, "file1.txt"
- @file2 = fixture __FILE__, "file2.txt"
- end
-
- # NOTE: this test assumes that fixtures files have two lines each
- it "returns true when reaching the end of a file" do
- argf [@file1, @file2] do
- result = []
- while @argf.gets
- result << @argf.send(@method)
- end
- result.should == [false, true, false, true]
- end
- end
-
- it "raises IOError when called on a closed stream" do
- argf [@file1] do
- @argf.read
- -> { @argf.send(@method) }.should raise_error(IOError)
- end
- end
-end
diff --git a/spec/ruby/core/argf/shared/filename.rb b/spec/ruby/core/argf/shared/filename.rb
deleted file mode 100644
index f47c673dc0..0000000000
--- a/spec/ruby/core/argf/shared/filename.rb
+++ /dev/null
@@ -1,28 +0,0 @@
-describe :argf_filename, shared: true do
- before :each do
- @file1 = fixture __FILE__, "file1.txt"
- @file2 = fixture __FILE__, "file2.txt"
- end
-
- # NOTE: this test assumes that fixtures files have two lines each
- it "returns the current file name on each file" do
- argf [@file1, @file2] do
- result = []
- # returns first current file even when not yet open
- result << @argf.send(@method)
- result << @argf.send(@method) while @argf.gets
- # returns last current file even when closed
- result << @argf.send(@method)
-
- result.map! { |f| File.expand_path(f) }
- result.should == [@file1, @file1, @file1, @file2, @file2, @file2]
- end
- end
-
- # NOTE: this test assumes that fixtures files have two lines each
- it "sets the $FILENAME global variable with the current file name on each file" do
- script = fixture __FILE__, "filename.rb"
- out = ruby_exe(script, args: [@file1, @file2])
- out.should == "#{@file1}\n#{@file1}\n#{@file2}\n#{@file2}\n#{@file2}\n"
- end
-end
diff --git a/spec/ruby/core/argf/shared/fileno.rb b/spec/ruby/core/argf/shared/fileno.rb
deleted file mode 100644
index 4350d43747..0000000000
--- a/spec/ruby/core/argf/shared/fileno.rb
+++ /dev/null
@@ -1,24 +0,0 @@
-describe :argf_fileno, shared: true do
- before :each do
- @file1 = fixture __FILE__, "file1.txt"
- @file2 = fixture __FILE__, "file2.txt"
- end
-
- # NOTE: this test assumes that fixtures files have two lines each
- it "returns the current file number on each file" do
- argf [@file1, @file2] do
- result = []
- # returns first current file even when not yet open
- result << @argf.send(@method) while @argf.gets
- # returns last current file even when closed
- result.map { |d| d.class }.should == [Integer, Integer, Integer, Integer]
- end
- end
-
- it "raises an ArgumentError when called on a closed stream" do
- argf [@file1] do
- @argf.read
- -> { @argf.send(@method) }.should raise_error(ArgumentError)
- end
- end
-end
diff --git a/spec/ruby/core/argf/shared/pos.rb b/spec/ruby/core/argf/shared/pos.rb
deleted file mode 100644
index 9836d5f1e4..0000000000
--- a/spec/ruby/core/argf/shared/pos.rb
+++ /dev/null
@@ -1,31 +0,0 @@
-describe :argf_pos, shared: true do
- before :each do
- @file1 = fixture __FILE__, "file1.txt"
- @file2 = fixture __FILE__, "file2.txt"
- end
-
- it "gives the correct position for each read operation" do
- argf [@file1, @file2] do
- size1 = File.size(@file1)
- size2 = File.size(@file2)
-
- @argf.read(2)
- @argf.send(@method).should == 2
- @argf.read(size1-2)
- @argf.send(@method).should == size1
- @argf.read(6)
- @argf.send(@method).should == 6
- @argf.rewind
- @argf.send(@method).should == 0
- @argf.read(size2)
- @argf.send(@method).should == size2
- end
- end
-
- it "raises an ArgumentError when called on a closed stream" do
- argf [@file1] do
- @argf.read
- -> { @argf.send(@method) }.should raise_error(ArgumentError)
- end
- end
-end
diff --git a/spec/ruby/core/argf/shared/readlines.rb b/spec/ruby/core/argf/shared/readlines.rb
deleted file mode 100644
index 505fa94acb..0000000000
--- a/spec/ruby/core/argf/shared/readlines.rb
+++ /dev/null
@@ -1,22 +0,0 @@
-describe :argf_readlines, shared: true do
- before :each do
- @file1 = fixture __FILE__, "file1.txt"
- @file2 = fixture __FILE__, "file2.txt"
-
- @lines = File.readlines(@file1)
- @lines += File.readlines(@file2)
- end
-
- it "reads all lines of all files" do
- argf [@file1, @file2] do
- @argf.send(@method).should == @lines
- end
- end
-
- it "returns an empty Array when end of stream reached" do
- argf [@file1, @file2] do
- @argf.read
- @argf.send(@method).should == []
- end
- end
-end
diff --git a/spec/ruby/core/argf/skip_spec.rb b/spec/ruby/core/argf/skip_spec.rb
index 0181801c2d..bb1c0ae110 100644
--- a/spec/ruby/core/argf/skip_spec.rb
+++ b/spec/ruby/core/argf/skip_spec.rb
@@ -37,6 +37,6 @@ describe "ARGF.skip" do
# which as a side-effect calls argf.file which will initialize
# internals of ARGF enough for this to work.
it "has no effect when nothing has been processed yet" do
- -> { ARGF.class.new(@file1_name).skip }.should_not raise_error
+ -> { ARGF.class.new(@file1_name).skip }.should_not.raise
end
end
diff --git a/spec/ruby/core/argf/tell_spec.rb b/spec/ruby/core/argf/tell_spec.rb
index 16d9f29920..bb28df74a2 100644
--- a/spec/ruby/core/argf/tell_spec.rb
+++ b/spec/ruby/core/argf/tell_spec.rb
@@ -1,6 +1,7 @@
require_relative '../../spec_helper'
-require_relative 'shared/pos'
describe "ARGF.tell" do
- it_behaves_like :argf_pos, :tell
+ it "is an alias of ARGF.pos" do
+ ARGF.method(:tell).should == ARGF.method(:pos)
+ end
end
diff --git a/spec/ruby/core/argf/to_a_spec.rb b/spec/ruby/core/argf/to_a_spec.rb
index b17a93db33..d95dc732ec 100644
--- a/spec/ruby/core/argf/to_a_spec.rb
+++ b/spec/ruby/core/argf/to_a_spec.rb
@@ -1,6 +1,7 @@
require_relative '../../spec_helper'
-require_relative 'shared/readlines'
describe "ARGF.to_a" do
- it_behaves_like :argf_readlines, :to_a
+ it "is an alias of ARGF.readlines" do
+ ARGF.method(:to_a).should == ARGF.method(:readlines)
+ end
end
diff --git a/spec/ruby/core/argf/to_i_spec.rb b/spec/ruby/core/argf/to_i_spec.rb
index 2183de6cd4..e8df378f4e 100644
--- a/spec/ruby/core/argf/to_i_spec.rb
+++ b/spec/ruby/core/argf/to_i_spec.rb
@@ -1,6 +1,7 @@
require_relative '../../spec_helper'
-require_relative 'shared/fileno'
describe "ARGF.to_i" do
- it_behaves_like :argf_fileno, :to_i
+ it "is an alias of ARGF.fileno" do
+ ARGF.method(:to_i).should == ARGF.method(:fileno)
+ end
end
diff --git a/spec/ruby/core/argf/to_io_spec.rb b/spec/ruby/core/argf/to_io_spec.rb
index 062383d291..ab5de58bcf 100644
--- a/spec/ruby/core/argf/to_io_spec.rb
+++ b/spec/ruby/core/argf/to_io_spec.rb
@@ -15,7 +15,7 @@ describe "ARGF.to_io" do
result << @argf.to_io
end
- result.each { |io| io.should be_kind_of(IO) }
+ result.each { |io| io.should.is_a?(IO) }
result[0].should == result[1]
result[2].should == result[3]
end
diff --git a/spec/ruby/core/array/allocate_spec.rb b/spec/ruby/core/array/allocate_spec.rb
index 04f7c0d0ad..c9eceef590 100644
--- a/spec/ruby/core/array/allocate_spec.rb
+++ b/spec/ruby/core/array/allocate_spec.rb
@@ -3,7 +3,7 @@ require_relative '../../spec_helper'
describe "Array.allocate" do
it "returns an instance of Array" do
ary = Array.allocate
- ary.should be_an_instance_of(Array)
+ ary.should.instance_of?(Array)
end
it "returns a fully-formed instance of Array" do
@@ -14,6 +14,6 @@ describe "Array.allocate" do
end
it "does not accept any arguments" do
- -> { Array.allocate(1) }.should raise_error(ArgumentError)
+ -> { Array.allocate(1) }.should.raise(ArgumentError)
end
end
diff --git a/spec/ruby/core/array/append_spec.rb b/spec/ruby/core/array/append_spec.rb
index c12473dc07..5480d9f65e 100644
--- a/spec/ruby/core/array/append_spec.rb
+++ b/spec/ruby/core/array/append_spec.rb
@@ -1,6 +1,5 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
-require_relative 'shared/push'
describe "Array#<<" do
it "pushes the object onto the end of the array" do
@@ -10,8 +9,8 @@ describe "Array#<<" do
it "returns self to allow chaining" do
a = []
b = a
- (a << 1).should equal(b)
- (a << 2 << 3).should equal(b)
+ (a << 1).should.equal?(b)
+ (a << 2 << 3).should.equal?(b)
end
it "correctly resizes the Array" do
@@ -31,10 +30,12 @@ describe "Array#<<" do
end
it "raises a FrozenError on a frozen array" do
- -> { ArraySpecs.frozen_array << 5 }.should raise_error(FrozenError)
+ -> { ArraySpecs.frozen_array << 5 }.should.raise(FrozenError)
end
end
describe "Array#append" do
- it_behaves_like :array_push, :append
+ it "is an alias of Array#push" do
+ Array.instance_method(:append).should == Array.instance_method(:push)
+ end
end
diff --git a/spec/ruby/core/array/assoc_spec.rb b/spec/ruby/core/array/assoc_spec.rb
index f0be3de795..a5026cf5d4 100644
--- a/spec/ruby/core/array/assoc_spec.rb
+++ b/spec/ruby/core/array/assoc_spec.rb
@@ -10,14 +10,14 @@ describe "Array#assoc" do
s5 = [:letters, "a", "i", "u"]
s_nil = [nil, nil]
a = [s1, s2, s3, s4, s5, s_nil]
- a.assoc(s1.first).should equal(s1)
- a.assoc(s2.first).should equal(s2)
- a.assoc(s3.first).should equal(s3)
- a.assoc(s4.first).should equal(s1)
- a.assoc(s5.first).should equal(s2)
- a.assoc(s_nil.first).should equal(s_nil)
- a.assoc(4).should equal(s3)
- a.assoc("key not in array").should be_nil
+ a.assoc(s1.first).should.equal?(s1)
+ a.assoc(s2.first).should.equal?(s2)
+ a.assoc(s3.first).should.equal?(s3)
+ a.assoc(s4.first).should.equal?(s1)
+ a.assoc(s5.first).should.equal?(s2)
+ a.assoc(s_nil.first).should.equal?(s_nil)
+ a.assoc(4).should.equal?(s3)
+ a.assoc("key not in array").should == nil
end
it "calls == on first element of each array" do
@@ -25,17 +25,17 @@ describe "Array#assoc" do
key2 = mock('key2')
items = [['not it', 1], [ArraySpecs::AssocKey.new, 2], ['na', 3]]
- items.assoc(key1).should equal(items[1])
- items.assoc(key2).should be_nil
+ items.assoc(key1).should.equal?(items[1])
+ items.assoc(key2).should == nil
end
it "ignores any non-Array elements" do
- [1, 2, 3].assoc(2).should be_nil
+ [1, 2, 3].assoc(2).should == nil
s1 = [4]
s2 = [5, 4, 3]
a = ["foo", [], s1, s2, nil, []]
- a.assoc(s1.first).should equal(s1)
- a.assoc(s2.first).should equal(s2)
+ a.assoc(s1.first).should.equal?(s1)
+ a.assoc(s2.first).should.equal?(s2)
end
it "calls to_ary on non-array elements" do
@@ -44,9 +44,9 @@ describe "Array#assoc" do
a = [s1, s2]
s1.should_not_receive(:to_ary)
- a.assoc(s1.first).should equal(s1)
+ a.assoc(s1.first).should.equal?(s1)
a.assoc(2).should == [2, 3]
- s2.called.should equal(:to_ary)
+ s2.called.should.equal?(:to_ary)
end
end
diff --git a/spec/ruby/core/array/at_spec.rb b/spec/ruby/core/array/at_spec.rb
index 8bc789fef7..3c7c99fdff 100644
--- a/spec/ruby/core/array/at_spec.rb
+++ b/spec/ruby/core/array/at_spec.rb
@@ -47,10 +47,10 @@ describe "Array#at" do
end
it "raises a TypeError when the passed argument can't be coerced to Integer" do
- -> { [].at("cat") }.should raise_error(TypeError)
+ -> { [].at("cat") }.should.raise(TypeError)
end
it "raises an ArgumentError when 2 or more arguments are passed" do
- -> { [:a, :b].at(0,1) }.should raise_error(ArgumentError)
+ -> { [:a, :b].at(0,1) }.should.raise(ArgumentError)
end
end
diff --git a/spec/ruby/core/array/bsearch_index_spec.rb b/spec/ruby/core/array/bsearch_index_spec.rb
index 94d85b37f3..e1d5eb66bb 100644
--- a/spec/ruby/core/array/bsearch_index_spec.rb
+++ b/spec/ruby/core/array/bsearch_index_spec.rb
@@ -8,11 +8,11 @@ describe "Array#bsearch_index" do
end
it "returns an Enumerator" do
- @enum.should be_an_instance_of(Enumerator)
+ @enum.should.instance_of?(Enumerator)
end
it "returns an Enumerator with unknown size" do
- @enum.size.should be_nil
+ @enum.size.should == nil
end
it "returns index of element when block condition is satisfied" do
@@ -21,11 +21,11 @@ describe "Array#bsearch_index" do
end
it "raises a TypeError when block returns a String" do
- -> { [1, 2, 3].bsearch_index { "not ok" } }.should raise_error(TypeError)
+ -> { [1, 2, 3].bsearch_index { "not ok" } }.should.raise(TypeError)
end
it "returns nil when block is empty" do
- [1, 2, 3].bsearch_index {}.should be_nil
+ [1, 2, 3].bsearch_index {}.should == nil
end
context "minimum mode" do
@@ -40,8 +40,8 @@ describe "Array#bsearch_index" do
end
it "returns nil when block condition is never satisfied" do
- @array.bsearch_index { false }.should be_nil
- @array.bsearch_index { |x| x >= 100 }.should be_nil
+ @array.bsearch_index { false }.should == nil
+ @array.bsearch_index { |x| x >= 100 }.should == nil
end
end
@@ -51,30 +51,30 @@ describe "Array#bsearch_index" do
end
it "returns the index of any matched elements where element is between 4 <= x < 8" do
- [1, 2].should include(@array.bsearch_index { |x| 1 - x / 4 })
+ [1, 2].should.include?(@array.bsearch_index { |x| 1 - x / 4 })
end
it "returns the index of any matched elements where element is between 8 <= x < 10" do
- @array.bsearch_index { |x| 4 - x / 2 }.should be_nil
+ @array.bsearch_index { |x| 4 - x / 2 }.should == nil
end
it "returns nil when block never returns 0" do
- @array.bsearch_index { |x| 1 }.should be_nil
- @array.bsearch_index { |x| -1 }.should be_nil
+ @array.bsearch_index { |x| 1 }.should == nil
+ @array.bsearch_index { |x| -1 }.should == nil
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) })
+ [1, 2].should.include?(@array.bsearch_index { |x| (1 - x / 4) * (2**100) })
end
it "returns nil when block never returns 0" do
- @array.bsearch_index { |x| 1 * (2**100) }.should be_nil
- @array.bsearch_index { |x| (-1) * (2**100) }.should be_nil
+ @array.bsearch_index { |x| 1 * (2**100) }.should == nil
+ @array.bsearch_index { |x| (-1) * (2**100) }.should == nil
end
it "handles values from Integer#coerce" do
- [1, 2].should include(@array.bsearch_index { |x| (2**100).coerce((1 - x / 4) * (2**100)).first })
+ [1, 2].should.include?(@array.bsearch_index { |x| (2**100).coerce((1 - x / 4) * (2**100)).first })
end
end
end
diff --git a/spec/ruby/core/array/bsearch_spec.rb b/spec/ruby/core/array/bsearch_spec.rb
index 8fa6245dbf..12aec60654 100644
--- a/spec/ruby/core/array/bsearch_spec.rb
+++ b/spec/ruby/core/array/bsearch_spec.rb
@@ -3,26 +3,26 @@ require_relative '../enumerable/shared/enumeratorized'
describe "Array#bsearch" do
it "returns an Enumerator when not passed a block" do
- [1].bsearch.should be_an_instance_of(Enumerator)
+ [1].bsearch.should.instance_of?(Enumerator)
end
it_behaves_like :enumeratorized_with_unknown_size, :bsearch, [1,2,3]
it "raises a TypeError if the block returns an Object" do
- -> { [1].bsearch { Object.new } }.should raise_error(TypeError)
+ -> { [1].bsearch { Object.new } }.should.raise(TypeError)
end
it "raises a TypeError if the block returns a String" do
- -> { [1].bsearch { "1" } }.should raise_error(TypeError)
+ -> { [1].bsearch { "1" } }.should.raise(TypeError)
end
context "with a block returning true or false" do
it "returns nil if the block returns false for every element" do
- [0, 1, 2, 3].bsearch { |x| x > 3 }.should be_nil
+ [0, 1, 2, 3].bsearch { |x| x > 3 }.should == nil
end
it "returns nil if the block returns nil for every element" do
- [0, 1, 2, 3].bsearch { |x| nil }.should be_nil
+ [0, 1, 2, 3].bsearch { |x| nil }.should == nil
end
it "returns element at zero if the block returns true for every element" do
@@ -38,21 +38,21 @@ describe "Array#bsearch" do
context "with a block returning negative, zero, positive numbers" do
it "returns nil if the block returns less than zero for every element" do
- [0, 1, 2, 3].bsearch { |x| x <=> 5 }.should be_nil
+ [0, 1, 2, 3].bsearch { |x| x <=> 5 }.should == nil
end
it "returns nil if the block returns greater than zero for every element" do
- [0, 1, 2, 3].bsearch { |x| x <=> -1 }.should be_nil
+ [0, 1, 2, 3].bsearch { |x| x <=> -1 }.should == nil
end
it "returns nil if the block never returns zero" do
- [0, 1, 3, 4].bsearch { |x| x <=> 2 }.should be_nil
+ [0, 1, 3, 4].bsearch { |x| x <=> 2 }.should == nil
end
it "accepts (+/-)Float::INFINITY from the block" do
- [0, 1, 3, 4].bsearch { |x| Float::INFINITY }.should be_nil
- [0, 1, 3, 4].bsearch { |x| -Float::INFINITY }.should be_nil
+ [0, 1, 3, 4].bsearch { |x| Float::INFINITY }.should == nil
+ [0, 1, 3, 4].bsearch { |x| -Float::INFINITY }.should == nil
end
it "returns an element at an index for which block returns 0.0" do
@@ -62,17 +62,17 @@ describe "Array#bsearch" do
it "returns an element at an index for which block returns 0" do
result = [0, 1, 2, 3, 4].bsearch { |x| x < 1 ? 1 : x > 3 ? -1 : 0 }
- [1, 2].should include(result)
+ [1, 2].should.include?(result)
end
end
context "with a block that calls break" do
it "returns nil if break is called without a value" do
- ['a', 'b', 'c'].bsearch { |v| break }.should be_nil
+ ['a', 'b', 'c'].bsearch { |v| break }.should == nil
end
it "returns nil if break is called with a nil value" do
- ['a', 'b', 'c'].bsearch { |v| break nil }.should be_nil
+ ['a', 'b', 'c'].bsearch { |v| break nil }.should == nil
end
it "returns object if break is called with an object" do
diff --git a/spec/ruby/core/array/clear_spec.rb b/spec/ruby/core/array/clear_spec.rb
index 81ba56e01e..15778f864f 100644
--- a/spec/ruby/core/array/clear_spec.rb
+++ b/spec/ruby/core/array/clear_spec.rb
@@ -4,13 +4,13 @@ require_relative 'fixtures/classes'
describe "Array#clear" do
it "removes all elements" do
a = [1, 2, 3, 4]
- a.clear.should equal(a)
+ a.clear.should.equal?(a)
a.should == []
end
it "returns self" do
a = [1]
- a.should equal a.clear
+ a.should.equal? a.clear
end
it "leaves the Array empty" do
@@ -21,12 +21,12 @@ describe "Array#clear" do
end
it "does not accept any arguments" do
- -> { [1].clear(true) }.should raise_error(ArgumentError)
+ -> { [1].clear(true) }.should.raise(ArgumentError)
end
it "raises a FrozenError on a frozen array" do
a = [1]
a.freeze
- -> { a.clear }.should raise_error(FrozenError)
+ -> { a.clear }.should.raise(FrozenError)
end
end
diff --git a/spec/ruby/core/array/clone_spec.rb b/spec/ruby/core/array/clone_spec.rb
index e22a6c6d53..7ce9d40a81 100644
--- a/spec/ruby/core/array/clone_spec.rb
+++ b/spec/ruby/core/array/clone_spec.rb
@@ -23,9 +23,9 @@ describe "Array#clone" do
aa = a.clone
bb = b.clone
- a.respond_to?(:a_singleton_method).should be_true
- b.respond_to?(:a_singleton_method).should be_false
- aa.respond_to?(:a_singleton_method).should be_true
- bb.respond_to?(:a_singleton_method).should be_false
+ a.respond_to?(:a_singleton_method).should == true
+ b.respond_to?(:a_singleton_method).should == false
+ aa.respond_to?(:a_singleton_method).should == true
+ bb.respond_to?(:a_singleton_method).should == false
end
end
diff --git a/spec/ruby/core/array/collect_spec.rb b/spec/ruby/core/array/collect_spec.rb
index 0ad4c283b1..bdee5c240a 100644
--- a/spec/ruby/core/array/collect_spec.rb
+++ b/spec/ruby/core/array/collect_spec.rb
@@ -1,11 +1,13 @@
require_relative '../../spec_helper'
-require_relative 'fixtures/classes'
-require_relative 'shared/collect'
describe "Array#collect" do
- it_behaves_like :array_collect, :collect
+ it "is an alias of Array#map" do
+ Array.instance_method(:collect).should == Array.instance_method(:map)
+ end
end
describe "Array#collect!" do
- it_behaves_like :array_collect_b, :collect!
+ it "is an alias of Array#map!" do
+ Array.instance_method(:collect!).should == Array.instance_method(:map!)
+ end
end
diff --git a/spec/ruby/core/array/combination_spec.rb b/spec/ruby/core/array/combination_spec.rb
index f16d6f98fc..ac570687ca 100644
--- a/spec/ruby/core/array/combination_spec.rb
+++ b/spec/ruby/core/array/combination_spec.rb
@@ -6,11 +6,11 @@ describe "Array#combination" do
end
it "returns an enumerator when no block is provided" do
- @array.combination(2).should be_an_instance_of(Enumerator)
+ @array.combination(2).should.instance_of?(Enumerator)
end
it "returns self when a block is given" do
- @array.combination(2){}.should equal(@array)
+ @array.combination(2){}.should.equal?(@array)
end
it "yields nothing for out of bounds length and return self" do
@@ -30,7 +30,7 @@ describe "Array#combination" do
it "yields a copy of self if the argument is the size of the receiver" do
r = @array.combination(4).to_a
r.should == [@array]
- r[0].should_not equal(@array)
+ r[0].should_not.equal?(@array)
end
it "yields [] when length is 0" do
diff --git a/spec/ruby/core/array/compact_spec.rb b/spec/ruby/core/array/compact_spec.rb
index 83b3fa2a89..dbcd16da35 100644
--- a/spec/ruby/core/array/compact_spec.rb
+++ b/spec/ruby/core/array/compact_spec.rb
@@ -15,30 +15,30 @@ describe "Array#compact" do
it "does not return self" do
a = [1, 2, 3]
- a.compact.should_not equal(a)
+ a.compact.should_not.equal?(a)
end
it "does not return subclass instance for Array subclasses" do
- ArraySpecs::MyArray[1, 2, 3, nil].compact.should be_an_instance_of(Array)
+ ArraySpecs::MyArray[1, 2, 3, nil].compact.should.instance_of?(Array)
end
end
describe "Array#compact!" do
it "removes all nil elements" do
a = ['a', nil, 'b', false, 'c']
- a.compact!.should equal(a)
+ a.compact!.should.equal?(a)
a.should == ["a", "b", false, "c"]
a = [nil, 'a', 'b', false, 'c']
- a.compact!.should equal(a)
+ a.compact!.should.equal?(a)
a.should == ["a", "b", false, "c"]
a = ['a', 'b', false, 'c', nil]
- a.compact!.should equal(a)
+ a.compact!.should.equal?(a)
a.should == ["a", "b", false, "c"]
end
it "returns self if some nil elements are removed" do
a = ['a', nil, 'b', false, 'c']
- a.compact!.should equal a
+ a.compact!.should.equal? a
end
it "returns nil if there are no nil elements to remove" do
@@ -46,6 +46,6 @@ describe "Array#compact!" do
end
it "raises a FrozenError on a frozen array" do
- -> { ArraySpecs.frozen_array.compact! }.should raise_error(FrozenError)
+ -> { ArraySpecs.frozen_array.compact! }.should.raise(FrozenError)
end
end
diff --git a/spec/ruby/core/array/comparison_spec.rb b/spec/ruby/core/array/comparison_spec.rb
index 5d1c3265f1..14e8931e5a 100644
--- a/spec/ruby/core/array/comparison_spec.rb
+++ b/spec/ruby/core/array/comparison_spec.rb
@@ -92,6 +92,6 @@ describe "Array#<=>" do
end
it "returns nil when the argument is not array-like" do
- ([] <=> false).should be_nil
+ ([] <=> false).should == nil
end
end
diff --git a/spec/ruby/core/array/concat_spec.rb b/spec/ruby/core/array/concat_spec.rb
index f3cab9c17c..1e8d20c36c 100644
--- a/spec/ruby/core/array/concat_spec.rb
+++ b/spec/ruby/core/array/concat_spec.rb
@@ -4,12 +4,12 @@ require_relative 'fixtures/classes'
describe "Array#concat" do
it "returns the array itself" do
ary = [1,2,3]
- ary.concat([4,5,6]).equal?(ary).should be_true
+ ary.concat([4,5,6]).equal?(ary).should == true
end
it "appends the elements in the other array" do
ary = [1, 2, 3]
- ary.concat([9, 10, 11]).should equal(ary)
+ ary.concat([9, 10, 11]).should.equal?(ary)
ary.should == [1, 2, 3, 9, 10, 11]
ary.concat([])
ary.should == [1, 2, 3, 9, 10, 11]
@@ -33,12 +33,12 @@ describe "Array#concat" do
end
it "raises a FrozenError when Array is frozen and modification occurs" do
- -> { ArraySpecs.frozen_array.concat [1] }.should raise_error(FrozenError)
+ -> { ArraySpecs.frozen_array.concat [1] }.should.raise(FrozenError)
end
# see [ruby-core:23666]
it "raises a FrozenError when Array is frozen and no modification occurs" do
- -> { ArraySpecs.frozen_array.concat([]) }.should raise_error(FrozenError)
+ -> { ArraySpecs.frozen_array.concat([]) }.should.raise(FrozenError)
end
it "appends elements to an Array with enough capacity that has been shifted" do
@@ -68,7 +68,7 @@ describe "Array#concat" do
it "returns self when given no arguments" do
ary = [1, 2]
- ary.concat.should equal(ary)
+ ary.concat.should.equal?(ary)
ary.should == [1, 2]
end
end
diff --git a/spec/ruby/core/array/constructor_spec.rb b/spec/ruby/core/array/constructor_spec.rb
index 6f36074c45..c4398c535d 100644
--- a/spec/ruby/core/array/constructor_spec.rb
+++ b/spec/ruby/core/array/constructor_spec.rb
@@ -7,7 +7,7 @@ describe "Array.[]" do
Array.[](5, true, nil, 'a', "Ruby", obj).should == [5, true, nil, "a", "Ruby", obj]
a = ArraySpecs::MyArray.[](5, true, nil, 'a', "Ruby", obj)
- a.should be_an_instance_of(ArraySpecs::MyArray)
+ a.should.instance_of?(ArraySpecs::MyArray)
a.inspect.should == [5, true, nil, "a", "Ruby", obj].inspect
end
end
@@ -18,7 +18,7 @@ describe "Array[]" do
Array[5, true, nil, 'a', "Ruby", obj].should == Array.[](5, true, nil, "a", "Ruby", obj)
a = ArraySpecs::MyArray[5, true, nil, 'a', "Ruby", obj]
- a.should be_an_instance_of(ArraySpecs::MyArray)
+ a.should.instance_of?(ArraySpecs::MyArray)
a.inspect.should == [5, true, nil, "a", "Ruby", obj].inspect
end
end
diff --git a/spec/ruby/core/array/cycle_spec.rb b/spec/ruby/core/array/cycle_spec.rb
index 7219b49883..29284257e9 100644
--- a/spec/ruby/core/array/cycle_spec.rb
+++ b/spec/ruby/core/array/cycle_spec.rb
@@ -10,17 +10,17 @@ describe "Array#cycle" do
end
it "does not yield and returns nil when the array is empty and passed value is an integer" do
- [].cycle(6, &@prc).should be_nil
+ [].cycle(6, &@prc).should == nil
ScratchPad.recorded.should == []
end
it "does not yield and returns nil when the array is empty and passed value is nil" do
- [].cycle(nil, &@prc).should be_nil
+ [].cycle(nil, &@prc).should == nil
ScratchPad.recorded.should == []
end
it "does not yield and returns nil when passed 0" do
- @array.cycle(0, &@prc).should be_nil
+ @array.cycle(0, &@prc).should == nil
ScratchPad.recorded.should == []
end
@@ -48,13 +48,13 @@ describe "Array#cycle" do
it "does not rescue StopIteration when not passed a count" do
-> do
@array.cycle { raise StopIteration }
- end.should raise_error(StopIteration)
+ end.should.raise(StopIteration)
end
it "does not rescue StopIteration when passed a count" do
-> do
@array.cycle(3) { raise StopIteration }
- end.should raise_error(StopIteration)
+ end.should.raise(StopIteration)
end
it "iterates the array Integer(count) times when passed a Float count" do
@@ -74,23 +74,23 @@ describe "Array#cycle" do
count = mock("cycle count 2")
count.should_receive(:to_int).and_return("2")
- -> { @array.cycle(count, &@prc) }.should raise_error(TypeError)
+ -> { @array.cycle(count, &@prc) }.should.raise(TypeError)
end
it "raises a TypeError if passed a String" do
- -> { @array.cycle("4") { } }.should raise_error(TypeError)
+ -> { @array.cycle("4") { } }.should.raise(TypeError)
end
it "raises a TypeError if passed an Object" do
- -> { @array.cycle(mock("cycle count")) { } }.should raise_error(TypeError)
+ -> { @array.cycle(mock("cycle count")) { } }.should.raise(TypeError)
end
it "raises a TypeError if passed true" do
- -> { @array.cycle(true) { } }.should raise_error(TypeError)
+ -> { @array.cycle(true) { } }.should.raise(TypeError)
end
it "raises a TypeError if passed false" do
- -> { @array.cycle(false) { } }.should raise_error(TypeError)
+ -> { @array.cycle(false) { } }.should.raise(TypeError)
end
before :all do
diff --git a/spec/ruby/core/array/deconstruct_spec.rb b/spec/ruby/core/array/deconstruct_spec.rb
index ad67abe47b..11bb8e72c4 100644
--- a/spec/ruby/core/array/deconstruct_spec.rb
+++ b/spec/ruby/core/array/deconstruct_spec.rb
@@ -4,6 +4,6 @@ describe "Array#deconstruct" do
it "returns self" do
array = [1]
- array.deconstruct.should equal array
+ array.deconstruct.should.equal? array
end
end
diff --git a/spec/ruby/core/array/delete_at_spec.rb b/spec/ruby/core/array/delete_at_spec.rb
index 80ec643702..1e298b6730 100644
--- a/spec/ruby/core/array/delete_at_spec.rb
+++ b/spec/ruby/core/array/delete_at_spec.rb
@@ -36,6 +36,6 @@ describe "Array#delete_at" do
end
it "raises a FrozenError on a frozen array" do
- -> { [1,2,3].freeze.delete_at(0) }.should raise_error(FrozenError)
+ -> { [1,2,3].freeze.delete_at(0) }.should.raise(FrozenError)
end
end
diff --git a/spec/ruby/core/array/delete_if_spec.rb b/spec/ruby/core/array/delete_if_spec.rb
index 10972eee0e..701a612395 100644
--- a/spec/ruby/core/array/delete_if_spec.rb
+++ b/spec/ruby/core/array/delete_if_spec.rb
@@ -17,7 +17,7 @@ describe "Array#delete_if" do
end
it "returns self" do
- @a.delete_if{ true }.equal?(@a).should be_true
+ @a.delete_if{ true }.equal?(@a).should == true
end
it_behaves_like :enumeratorize, :delete_if
@@ -25,27 +25,27 @@ describe "Array#delete_if" do
it "returns self when called on an Array emptied with #shift" do
array = [1]
array.shift
- array.delete_if { |x| true }.should equal(array)
+ array.delete_if { |x| true }.should.equal?(array)
end
it "returns an Enumerator if no block given, and the enumerator can modify the original array" do
enum = @a.delete_if
- enum.should be_an_instance_of(Enumerator)
- @a.should_not be_empty
+ enum.should.instance_of?(Enumerator)
+ @a.should_not.empty?
enum.each { true }
- @a.should be_empty
+ @a.should.empty?
end
it "returns an Enumerator if no block given, and the array is frozen" do
- @a.freeze.delete_if.should be_an_instance_of(Enumerator)
+ @a.freeze.delete_if.should.instance_of?(Enumerator)
end
it "raises a FrozenError on a frozen array" do
- -> { ArraySpecs.frozen_array.delete_if {} }.should raise_error(FrozenError)
+ -> { ArraySpecs.frozen_array.delete_if {} }.should.raise(FrozenError)
end
it "raises a FrozenError on an empty frozen array" do
- -> { ArraySpecs.empty_frozen_array.delete_if {} }.should raise_error(FrozenError)
+ -> { ArraySpecs.empty_frozen_array.delete_if {} }.should.raise(FrozenError)
end
it "does not truncate the array is the block raises an exception" do
diff --git a/spec/ruby/core/array/delete_spec.rb b/spec/ruby/core/array/delete_spec.rb
index dddbbe6bd3..0d80b2839d 100644
--- a/spec/ruby/core/array/delete_spec.rb
+++ b/spec/ruby/core/array/delete_spec.rb
@@ -41,6 +41,6 @@ describe "Array#delete" do
end
it "raises a FrozenError on a frozen array" do
- -> { [1, 2, 3].freeze.delete(1) }.should raise_error(FrozenError)
+ -> { [1, 2, 3].freeze.delete(1) }.should.raise(FrozenError)
end
end
diff --git a/spec/ruby/core/array/difference_spec.rb b/spec/ruby/core/array/difference_spec.rb
index 9f7d4c4a1a..63e32feca0 100644
--- a/spec/ruby/core/array/difference_spec.rb
+++ b/spec/ruby/core/array/difference_spec.rb
@@ -8,11 +8,11 @@ describe "Array#difference" do
it "returns a copy when called without any parameter" do
x = [1, 2, 3, 2]
x.difference.should == x
- x.difference.should_not equal x
+ x.difference.should_not.equal? x
end
it "does not return subclass instances for Array subclasses" do
- ArraySpecs::MyArray[1, 2, 3].difference.should be_an_instance_of(Array)
+ ArraySpecs::MyArray[1, 2, 3].difference.should.instance_of?(Array)
end
it "accepts multiple arguments" do
diff --git a/spec/ruby/core/array/dig_spec.rb b/spec/ruby/core/array/dig_spec.rb
index f2d8ff47fd..4166ff9f1f 100644
--- a/spec/ruby/core/array/dig_spec.rb
+++ b/spec/ruby/core/array/dig_spec.rb
@@ -4,7 +4,7 @@ describe "Array#dig" do
it "returns #at with one arg" do
['a'].dig(0).should == 'a'
- ['a'].dig(1).should be_nil
+ ['a'].dig(1).should == nil
end
it "recurses array elements" do
@@ -22,20 +22,20 @@ describe "Array#dig" do
it "raises a TypeError for a non-numeric index" do
-> {
['a'].dig(:first)
- }.should raise_error(TypeError)
+ }.should.raise(TypeError)
end
it "raises a TypeError if any intermediate step does not respond to #dig" do
a = [1, 2]
-> {
a.dig(0, 1)
- }.should raise_error(TypeError)
+ }.should.raise(TypeError)
end
it "raises an ArgumentError if no arguments provided" do
-> {
[10].dig()
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
it "returns nil if any intermediate step is nil" do
diff --git a/spec/ruby/core/array/drop_spec.rb b/spec/ruby/core/array/drop_spec.rb
index 5926c291b8..c0e1c9edce 100644
--- a/spec/ruby/core/array/drop_spec.rb
+++ b/spec/ruby/core/array/drop_spec.rb
@@ -7,7 +7,7 @@ describe "Array#drop" do
end
it "raises an ArgumentError if the number of elements specified is negative" do
- -> { [1, 2].drop(-3) }.should raise_error(ArgumentError)
+ -> { [1, 2].drop(-3) }.should.raise(ArgumentError)
end
it "returns an empty Array if all elements are dropped" do
@@ -40,17 +40,17 @@ describe "Array#drop" do
end
it "raises a TypeError when the passed argument can't be coerced to Integer" do
- -> { [1, 2].drop("cat") }.should raise_error(TypeError)
+ -> { [1, 2].drop("cat") }.should.raise(TypeError)
end
it "raises a TypeError when the passed argument isn't an integer and #to_int returns non-Integer" do
obj = mock("to_int")
obj.should_receive(:to_int).and_return("cat")
- -> { [1, 2].drop(obj) }.should raise_error(TypeError)
+ -> { [1, 2].drop(obj) }.should.raise(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)
+ ArraySpecs::MyArray[1, 2, 3, 4, 5].drop(1).should.instance_of?(Array)
end
end
diff --git a/spec/ruby/core/array/drop_while_spec.rb b/spec/ruby/core/array/drop_while_spec.rb
index bd46e8b882..4fead3ff06 100644
--- a/spec/ruby/core/array/drop_while_spec.rb
+++ b/spec/ruby/core/array/drop_while_spec.rb
@@ -19,6 +19,6 @@ describe "Array#drop_while" do
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)
+ ArraySpecs::MyArray[1, 2, 3, 4, 5].drop_while { |n| n < 4 }.should.instance_of?(Array)
end
end
diff --git a/spec/ruby/core/array/dup_spec.rb b/spec/ruby/core/array/dup_spec.rb
index 17f467d5fc..f14aeca3b5 100644
--- a/spec/ruby/core/array/dup_spec.rb
+++ b/spec/ruby/core/array/dup_spec.rb
@@ -12,8 +12,8 @@ describe "Array#dup" do
aa = a.dup
bb = b.dup
- aa.frozen?.should be_false
- bb.frozen?.should be_false
+ aa.frozen?.should == false
+ bb.frozen?.should == false
end
it "does not copy singleton methods" do
@@ -23,9 +23,9 @@ describe "Array#dup" do
aa = a.dup
bb = b.dup
- a.respond_to?(:a_singleton_method).should be_true
- b.respond_to?(:a_singleton_method).should be_false
- aa.respond_to?(:a_singleton_method).should be_false
- bb.respond_to?(:a_singleton_method).should be_false
+ a.respond_to?(:a_singleton_method).should == true
+ b.respond_to?(:a_singleton_method).should == false
+ aa.respond_to?(:a_singleton_method).should == false
+ bb.respond_to?(:a_singleton_method).should == false
end
end
diff --git a/spec/ruby/core/array/each_index_spec.rb b/spec/ruby/core/array/each_index_spec.rb
index 3a4bca9251..b238a89d8a 100644
--- a/spec/ruby/core/array/each_index_spec.rb
+++ b/spec/ruby/core/array/each_index_spec.rb
@@ -20,7 +20,7 @@ describe "Array#each_index" do
it "returns self" do
a = [:a, :b, :c]
- a.each_index { |i| }.should equal(a)
+ a.each_index { |i| }.should.equal?(a)
end
it "is not confused by removing elements from the front" do
diff --git a/spec/ruby/core/array/each_spec.rb b/spec/ruby/core/array/each_spec.rb
index f4b5b758d0..73a4c36b17 100644
--- a/spec/ruby/core/array/each_spec.rb
+++ b/spec/ruby/core/array/each_spec.rb
@@ -13,7 +13,7 @@ describe "Array#each" do
it "yields each element to the block" do
a = []
x = [1, 2, 3]
- x.each { |item| a << item }.should equal(x)
+ x.each { |item| a << item }.should.equal?(x)
a.should == [1, 2, 3]
end
diff --git a/spec/ruby/core/array/element_reference_spec.rb b/spec/ruby/core/array/element_reference_spec.rb
index 31e5578a09..d5f4b54961 100644
--- a/spec/ruby/core/array/element_reference_spec.rb
+++ b/spec/ruby/core/array/element_reference_spec.rb
@@ -1,9 +1,862 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
-require_relative 'shared/slice'
describe "Array#[]" do
- it_behaves_like :array_slice, :[]
+ it "returns the element at index with [index]" do
+ [ "a", "b", "c", "d", "e" ][1].should == "b"
+
+ a = [1, 2, 3, 4]
+
+ a[0].should == 1
+ a[1].should == 2
+ a[2].should == 3
+ a[3].should == 4
+ a[4].should == nil
+ a[10].should == nil
+
+ a.should == [1, 2, 3, 4]
+ end
+
+ it "returns the element at index from the end of the array with [-index]" do
+ [ "a", "b", "c", "d", "e" ][-2].should == "d"
+
+ a = [1, 2, 3, 4]
+
+ a[-1].should == 4
+ a[-2].should == 3
+ a[-3].should == 2
+ a[-4].should == 1
+ a[-5].should == nil
+ a[-10].should == nil
+
+ a.should == [1, 2, 3, 4]
+ end
+
+ it "returns count elements starting from index with [index, count]" do
+ [ "a", "b", "c", "d", "e" ][2, 3].should == ["c", "d", "e"]
+
+ a = [1, 2, 3, 4]
+
+ a[0, 0].should == []
+ a[0, 1].should == [1]
+ a[0, 2].should == [1, 2]
+ a[0, 4].should == [1, 2, 3, 4]
+ a[0, 6].should == [1, 2, 3, 4]
+ a[0, -1].should == nil
+ a[0, -2].should == nil
+ a[0, -4].should == nil
+
+ a[2, 0].should == []
+ a[2, 1].should == [3]
+ a[2, 2].should == [3, 4]
+ a[2, 4].should == [3, 4]
+ a[2, -1].should == nil
+
+ a[4, 0].should == []
+ a[4, 2].should == []
+ a[4, -1].should == nil
+
+ a[5, 0].should == nil
+ a[5, 2].should == nil
+ a[5, -1].should == nil
+
+ a[6, 0].should == nil
+ a[6, 2].should == nil
+ a[6, -1].should == nil
+
+ a.should == [1, 2, 3, 4]
+ end
+
+ it "returns count elements starting at index from the end of array with [-index, count]" do
+ [ "a", "b", "c", "d", "e" ][-2, 2].should == ["d", "e"]
+
+ a = [1, 2, 3, 4]
+
+ a[-1, 0].should == []
+ a[-1, 1].should == [4]
+ a[-1, 2].should == [4]
+ a[-1, -1].should == nil
+
+ a[-2, 0].should == []
+ a[-2, 1].should == [3]
+ a[-2, 2].should == [3, 4]
+ a[-2, 4].should == [3, 4]
+ a[-2, -1].should == nil
+
+ a[-4, 0].should == []
+ a[-4, 1].should == [1]
+ a[-4, 2].should == [1, 2]
+ a[-4, 4].should == [1, 2, 3, 4]
+ a[-4, 6].should == [1, 2, 3, 4]
+ a[-4, -1].should == nil
+
+ a[-5, 0].should == nil
+ a[-5, 1].should == nil
+ a[-5, 10].should == nil
+ a[-5, -1].should == nil
+
+ a.should == [1, 2, 3, 4]
+ end
+
+ it "returns the first count elements with [0, count]" do
+ [ "a", "b", "c", "d", "e" ][0, 3].should == ["a", "b", "c"]
+ end
+
+ it "returns the subarray which is independent to self with [index,count]" do
+ a = [1, 2, 3]
+ sub = a[1, 2]
+ sub.replace([:a, :b])
+ a.should == [1, 2, 3]
+ end
+
+ it "tries to convert the passed argument to an Integer using #to_int" do
+ obj = mock('to_int')
+ obj.stub!(:to_int).and_return(2)
+
+ a = [1, 2, 3, 4]
+ a[obj].should == 3
+ a[obj, 1].should == [3]
+ a[obj, obj].should == [3, 4]
+ a[0, obj].should == [1, 2]
+ end
+
+ it "raises TypeError if to_int returns non-integer" do
+ from = mock('from')
+ to = mock('to')
+
+ # So we can construct a range out of them...
+ def from.<=>(o) 0 end
+ def to.<=>(o) 0 end
+
+ a = [1, 2, 3, 4, 5]
+
+ def from.to_int() 'cat' end
+ def to.to_int() -2 end
+
+ -> { a[from..to] }.should.raise(TypeError)
+
+ def from.to_int() 1 end
+ def to.to_int() 'cat' end
+
+ -> { a[from..to] }.should.raise(TypeError)
+ end
+
+ it "returns the elements specified by Range indexes with [m..n]" do
+ [ "a", "b", "c", "d", "e" ][1..3].should == ["b", "c", "d"]
+ [ "a", "b", "c", "d", "e" ][4..-1].should == ['e']
+ [ "a", "b", "c", "d", "e" ][3..3].should == ['d']
+ [ "a", "b", "c", "d", "e" ][3..-2].should == ['d']
+ ['a'][0..-1].should == ['a']
+
+ a = [1, 2, 3, 4]
+
+ a[0..-10].should == []
+ a[0..0].should == [1]
+ a[0..1].should == [1, 2]
+ a[0..2].should == [1, 2, 3]
+ a[0..3].should == [1, 2, 3, 4]
+ a[0..4].should == [1, 2, 3, 4]
+ a[0..10].should == [1, 2, 3, 4]
+
+ a[2..-10].should == []
+ a[2..0].should == []
+ a[2..2].should == [3]
+ a[2..3].should == [3, 4]
+ a[2..4].should == [3, 4]
+
+ a[3..0].should == []
+ a[3..3].should == [4]
+ a[3..4].should == [4]
+
+ a[4..0].should == []
+ a[4..4].should == []
+ a[4..5].should == []
+
+ a[5..0].should == nil
+ a[5..5].should == nil
+ a[5..6].should == nil
+
+ a.should == [1, 2, 3, 4]
+ end
+
+ it "returns elements specified by Range indexes except the element at index n with [m...n]" do
+ [ "a", "b", "c", "d", "e" ][1...3].should == ["b", "c"]
+
+ a = [1, 2, 3, 4]
+
+ a[0...-10].should == []
+ a[0...0].should == []
+ a[0...1].should == [1]
+ a[0...2].should == [1, 2]
+ a[0...3].should == [1, 2, 3]
+ a[0...4].should == [1, 2, 3, 4]
+ a[0...10].should == [1, 2, 3, 4]
+
+ a[2...-10].should == []
+ a[2...0].should == []
+ a[2...2].should == []
+ a[2...3].should == [3]
+ a[2...4].should == [3, 4]
+
+ a[3...0].should == []
+ a[3...3].should == []
+ a[3...4].should == [4]
+
+ a[4...0].should == []
+ a[4...4].should == []
+ a[4...5].should == []
+
+ a[5...0].should == nil
+ a[5...5].should == nil
+ a[5...6].should == nil
+
+ a.should == [1, 2, 3, 4]
+ end
+
+ it "returns elements that exist if range start is in the array but range end is not with [m..n]" do
+ [ "a", "b", "c", "d", "e" ][4..7].should == ["e"]
+ end
+
+ it "accepts Range instances having a negative m and both signs for n with [m..n] and [m...n]" do
+ a = [1, 2, 3, 4]
+
+ a[-1..-1].should == [4]
+ a[-1...-1].should == []
+ a[-1..3].should == [4]
+ a[-1...3].should == []
+ a[-1..4].should == [4]
+ a[-1...4].should == [4]
+ a[-1..10].should == [4]
+ a[-1...10].should == [4]
+ a[-1..0].should == []
+ a[-1..-4].should == []
+ a[-1...-4].should == []
+ a[-1..-6].should == []
+ a[-1...-6].should == []
+
+ a[-2..-2].should == [3]
+ a[-2...-2].should == []
+ a[-2..-1].should == [3, 4]
+ a[-2...-1].should == [3]
+ a[-2..10].should == [3, 4]
+ a[-2...10].should == [3, 4]
+
+ a[-4..-4].should == [1]
+ a[-4..-2].should == [1, 2, 3]
+ a[-4...-2].should == [1, 2]
+ a[-4..-1].should == [1, 2, 3, 4]
+ a[-4...-1].should == [1, 2, 3]
+ a[-4..3].should == [1, 2, 3, 4]
+ a[-4...3].should == [1, 2, 3]
+ a[-4..4].should == [1, 2, 3, 4]
+ a[-4...4].should == [1, 2, 3, 4]
+ a[-4...4].should == [1, 2, 3, 4]
+ a[-4..0].should == [1]
+ a[-4...0].should == []
+ a[-4..1].should == [1, 2]
+ a[-4...1].should == [1]
+
+ a[-5..-5].should == nil
+ a[-5...-5].should == nil
+ a[-5..-4].should == nil
+ a[-5..-1].should == nil
+ a[-5..10].should == nil
+
+ a.should == [1, 2, 3, 4]
+ end
+
+ it "returns the subarray which is independent to self with [m..n]" do
+ a = [1, 2, 3]
+ sub = a[1..2]
+ sub.replace([:a, :b])
+ a.should == [1, 2, 3]
+ end
+
+ it "tries to convert Range elements to Integers using #to_int with [m..n] and [m...n]" do
+ from = mock('from')
+ to = mock('to')
+
+ # So we can construct a range out of them...
+ def from.<=>(o) 0 end
+ def to.<=>(o) 0 end
+
+ def from.to_int() 1 end
+ def to.to_int() -2 end
+
+ a = [1, 2, 3, 4]
+
+ a[from..to].should == [2, 3]
+ a[from...to].should == [2]
+ a[1..0].should == []
+ a[1...0].should == []
+
+ -> { a["a" .. "b"] }.should.raise(TypeError)
+ -> { a["a" ... "b"] }.should.raise(TypeError)
+ -> { a[from .. "b"] }.should.raise(TypeError)
+ -> { a[from ... "b"] }.should.raise(TypeError)
+ end
+
+ it "returns the same elements as [m..n] and [m...n] with Range subclasses" do
+ a = [1, 2, 3, 4]
+ range_incl = ArraySpecs::MyRange.new(1, 2)
+ range_excl = ArraySpecs::MyRange.new(-3, -1, true)
+
+ a[range_incl].should == [2, 3]
+ a[range_excl].should == [2, 3]
+ end
+
+ it "returns nil for a requested index not in the array with [index]" do
+ [ "a", "b", "c", "d", "e" ][5].should == nil
+ end
+
+ it "returns [] if the index is valid but length is zero with [index, length]" do
+ [ "a", "b", "c", "d", "e" ][0, 0].should == []
+ [ "a", "b", "c", "d", "e" ][2, 0].should == []
+ end
+
+ it "returns nil if length is zero but index is invalid with [index, length]" do
+ [ "a", "b", "c", "d", "e" ][100, 0].should == nil
+ [ "a", "b", "c", "d", "e" ][-50, 0].should == nil
+ end
+
+ # This is by design. It is in the official documentation.
+ it "returns [] if index == array.size with [index, length]" do
+ %w|a b c d e|[5, 2].should == []
+ end
+
+ it "returns nil if index > array.size with [index, length]" do
+ %w|a b c d e|[6, 2].should == nil
+ end
+
+ it "returns nil if length is negative with [index, length]" do
+ %w|a b c d e|[3, -1].should == nil
+ %w|a b c d e|[2, -2].should == nil
+ %w|a b c d e|[1, -100].should == nil
+ end
+
+ it "returns nil if no requested index is in the array with [m..n]" do
+ [ "a", "b", "c", "d", "e" ][6..10].should == nil
+ end
+
+ it "returns nil if range start is not in the array with [m..n]" do
+ [ "a", "b", "c", "d", "e" ][-10..2].should == nil
+ [ "a", "b", "c", "d", "e" ][10..12].should == nil
+ end
+
+ it "returns an empty array when m == n with [m...n]" do
+ [1, 2, 3, 4, 5][1...1].should == []
+ end
+
+ it "returns an empty array with [0...0]" do
+ [1, 2, 3, 4, 5][0...0].should == []
+ end
+
+ it "returns a subarray where m, n negatives and m < n with [m..n]" do
+ [ "a", "b", "c", "d", "e" ][-3..-2].should == ["c", "d"]
+ end
+
+ it "returns an array containing the first element with [0..0]" do
+ [1, 2, 3, 4, 5][0..0].should == [1]
+ end
+
+ it "returns the entire array with [0..-1]" do
+ [1, 2, 3, 4, 5][0..-1].should == [1, 2, 3, 4, 5]
+ end
+
+ it "returns all but the last element with [0...-1]" do
+ [1, 2, 3, 4, 5][0...-1].should == [1, 2, 3, 4]
+ end
+
+ it "returns [3] for [2..-1] out of [1, 2, 3]" do
+ [1,2,3][2..-1].should == [3]
+ end
+
+ it "returns an empty array when m > n and m, n are positive with [m..n]" do
+ [1, 2, 3, 4, 5][3..2].should == []
+ end
+
+ it "returns an empty array when m > n and m, n are negative with [m..n]" do
+ [1, 2, 3, 4, 5][-2..-3].should == []
+ end
+
+ it "does not expand array when the indices are outside of the array bounds" do
+ a = [1, 2]
+ a[4].should == nil
+ a.should == [1, 2]
+ a[4, 0].should == nil
+ a.should == [1, 2]
+ a[6, 1].should == nil
+ a.should == [1, 2]
+ a[8...8].should == nil
+ a.should == [1, 2]
+ a[10..10].should == nil
+ a.should == [1, 2]
+ end
+
+ describe "with a subclass of Array" do
+ before :each do
+ ScratchPad.clear
+
+ @array = ArraySpecs::MyArray[1, 2, 3, 4, 5]
+ end
+
+ it "returns a Array instance with [n, m]" do
+ @array[0, 2].should.instance_of?(Array)
+ end
+
+ it "returns a Array instance with [-n, m]" do
+ @array[-3, 2].should.instance_of?(Array)
+ end
+
+ it "returns a Array instance with [n..m]" do
+ @array[1..3].should.instance_of?(Array)
+ end
+
+ it "returns a Array instance with [n...m]" do
+ @array[1...3].should.instance_of?(Array)
+ end
+
+ it "returns a Array instance with [-n..-m]" do
+ @array[-3..-1].should.instance_of?(Array)
+ end
+
+ it "returns a Array instance with [-n...-m]" do
+ @array[-3...-1].should.instance_of?(Array)
+ end
+
+ it "returns an empty array when m == n with [m...n]" do
+ @array[1...1].should == []
+ ScratchPad.recorded.should == nil
+ end
+
+ it "returns an empty array with [0...0]" do
+ @array[0...0].should == []
+ ScratchPad.recorded.should == nil
+ end
+
+ it "returns an empty array when m > n and m, n are positive with [m..n]" do
+ @array[3..2].should == []
+ ScratchPad.recorded.should == nil
+ end
+
+ it "returns an empty array when m > n and m, n are negative with [m..n]" do
+ @array[-2..-3].should == []
+ ScratchPad.recorded.should == nil
+ end
+
+ it "returns [] if index == array.size with [index, length]" do
+ @array[5, 2].should == []
+ ScratchPad.recorded.should == nil
+ end
+
+ it "returns [] if the index is valid but length is zero with [index, length]" do
+ @array[0, 0].should == []
+ @array[2, 0].should == []
+ ScratchPad.recorded.should == nil
+ end
+
+ it "does not call #initialize on the subclass instance" do
+ @array[0, 3].should == [1, 2, 3]
+ ScratchPad.recorded.should == nil
+ end
+ end
+
+ it "raises a RangeError when the start index is out of range of Fixnum" do
+ array = [1, 2, 3, 4, 5, 6]
+ obj = mock('large value')
+ obj.should_receive(:to_int).and_return(bignum_value)
+ -> { array[obj] }.should.raise(RangeError)
+
+ obj = 8e19
+ -> { array[obj] }.should.raise(RangeError)
+
+ # boundary value when longs are 64 bits
+ -> { array[2.0**63] }.should.raise(RangeError)
+
+ # just under the boundary value when longs are 64 bits
+ array[max_long.to_f.prev_float].should == nil
+ end
+
+ it "raises a RangeError when the length is out of range of Fixnum" do
+ array = [1, 2, 3, 4, 5, 6]
+ obj = mock('large value')
+ obj.should_receive(:to_int).and_return(bignum_value)
+ -> { array[1, obj] }.should.raise(RangeError)
+
+ obj = 8e19
+ -> { array[1, obj] }.should.raise(RangeError)
+ end
+
+ it "raises a type error if a range is passed with a length" do
+ ->{ [1, 2, 3][1..2, 1] }.should.raise(TypeError)
+ end
+
+ it "raises a RangeError if passed a range with a bound that is too large" do
+ array = [1, 2, 3, 4, 5, 6]
+ -> { array[bignum_value..(bignum_value + 1)] }.should.raise(RangeError)
+ -> { array[0..bignum_value] }.should.raise(RangeError)
+ end
+
+ it "can accept endless ranges" do
+ a = [0, 1, 2, 3, 4, 5]
+ a[eval("(2..)")].should == [2, 3, 4, 5]
+ a[eval("(2...)")].should == [2, 3, 4, 5]
+ a[eval("(-2..)")].should == [4, 5]
+ a[eval("(-2...)")].should == [4, 5]
+ a[eval("(9..)")].should == nil
+ a[eval("(9...)")].should == nil
+ a[eval("(-9..)")].should == nil
+ a[eval("(-9...)")].should == nil
+ end
+
+ 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[eval("(0..).step(1)")].should == [0, 1, 2, 3, 4, 5]
+ @array[eval("(0..).step(2)")].should == [0, 2, 4]
+ @array[eval("(0..).step(10)")].should == [0]
+
+ @array[eval("(2..).step(1)")].should == [2, 3, 4, 5]
+ @array[eval("(2..).step(2)")].should == [2, 4]
+ @array[eval("(2..).step(10)")].should == [2]
+
+ @array[eval("(-3..).step(1)")].should == [3, 4, 5]
+ @array[eval("(-3..).step(2)")].should == [3, 5]
+ @array[eval("(-3..).step(10)")].should == [3]
+ end
+
+ it "has beginless range and positive steps" do
+ # end with zero index
+ @array[(..0).step(1)].should == [0]
+ @array[(...0).step(1)].should == []
+
+ @array[(..0).step(2)].should == [0]
+ @array[(...0).step(2)].should == []
+
+ @array[(..0).step(10)].should == [0]
+ @array[(...0).step(10)].should == []
+
+ # end with positive index
+ @array[(..3).step(1)].should == [0, 1, 2, 3]
+ @array[(...3).step(1)].should == [0, 1, 2]
+
+ @array[(..3).step(2)].should == [0, 2]
+ @array[(...3).step(2)].should == [0, 2]
+
+ @array[(..3).step(10)].should == [0]
+ @array[(...3).step(10)].should == [0]
+
+ # end with negative index
+ @array[(..-2).step(1)].should == [0, 1, 2, 3, 4,]
+ @array[(...-2).step(1)].should == [0, 1, 2, 3]
+
+ @array[(..-2).step(2)].should == [0, 2, 4]
+ @array[(...-2).step(2)].should == [0, 2]
+
+ @array[(..-2).step(10)].should == [0]
+ @array[(...-2).step(10)].should == [0]
+ end
+
+ it "has endless range and negative steps" do
+ @array[eval("(0..).step(-1)")].should == [0]
+ @array[eval("(0..).step(-2)")].should == [0]
+ @array[eval("(0..).step(-10)")].should == [0]
+
+ @array[eval("(2..).step(-1)")].should == [2, 1, 0]
+ @array[eval("(2..).step(-2)")].should == [2, 0]
+
+ @array[eval("(-3..).step(-1)")].should == [3, 2, 1, 0]
+ @array[eval("(-3..).step(-2)")].should == [3, 1]
+ end
+
+ it "has closed range and positive steps" do
+ # start and end with 0
+ @array[eval("(0..0).step(1)")].should == [0]
+ @array[eval("(0...0).step(1)")].should == []
+
+ @array[eval("(0..0).step(2)")].should == [0]
+ @array[eval("(0...0).step(2)")].should == []
+
+ @array[eval("(0..0).step(10)")].should == [0]
+ @array[eval("(0...0).step(10)")].should == []
+
+ # start and end with positive index
+ @array[eval("(1..3).step(1)")].should == [1, 2, 3]
+ @array[eval("(1...3).step(1)")].should == [1, 2]
+
+ @array[eval("(1..3).step(2)")].should == [1, 3]
+ @array[eval("(1...3).step(2)")].should == [1]
+
+ @array[eval("(1..3).step(10)")].should == [1]
+ @array[eval("(1...3).step(10)")].should == [1]
+
+ # start with positive index, end with negative index
+ @array[eval("(1..-2).step(1)")].should == [1, 2, 3, 4]
+ @array[eval("(1...-2).step(1)")].should == [1, 2, 3]
+
+ @array[eval("(1..-2).step(2)")].should == [1, 3]
+ @array[eval("(1...-2).step(2)")].should == [1, 3]
+
+ @array[eval("(1..-2).step(10)")].should == [1]
+ @array[eval("(1...-2).step(10)")].should == [1]
+
+ # start with negative index, end with positive index
+ @array[eval("(-4..4).step(1)")].should == [2, 3, 4]
+ @array[eval("(-4...4).step(1)")].should == [2, 3]
+
+ @array[eval("(-4..4).step(2)")].should == [2, 4]
+ @array[eval("(-4...4).step(2)")].should == [2]
+
+ @array[eval("(-4..4).step(10)")].should == [2]
+ @array[eval("(-4...4).step(10)")].should == [2]
+
+ # start with negative index, end with negative index
+ @array[eval("(-4..-2).step(1)")].should == [2, 3, 4]
+ @array[eval("(-4...-2).step(1)")].should == [2, 3]
+
+ @array[eval("(-4..-2).step(2)")].should == [2, 4]
+ @array[eval("(-4...-2).step(2)")].should == [2]
+
+ @array[eval("(-4..-2).step(10)")].should == [2]
+ @array[eval("(-4...-2).step(10)")].should == [2]
+ end
+
+ it "has closed range and negative steps" do
+ # start and end with 0
+ @array[eval("(0..0).step(-1)")].should == [0]
+ @array[eval("(0...0).step(-1)")].should == []
+
+ @array[eval("(0..0).step(-2)")].should == [0]
+ @array[eval("(0...0).step(-2)")].should == []
+
+ @array[eval("(0..0).step(-10)")].should == [0]
+ @array[eval("(0...0).step(-10)")].should == []
+
+ # start and end with positive index
+ @array[eval("(1..3).step(-1)")].should == []
+ @array[eval("(1...3).step(-1)")].should == []
+
+ @array[eval("(1..3).step(-2)")].should == []
+ @array[eval("(1...3).step(-2)")].should == []
+
+ @array[eval("(1..3).step(-10)")].should == []
+ @array[eval("(1...3).step(-10)")].should == []
+
+ # start with positive index, end with negative index
+ @array[eval("(1..-2).step(-1)")].should == []
+ @array[eval("(1...-2).step(-1)")].should == []
+
+ @array[eval("(1..-2).step(-2)")].should == []
+ @array[eval("(1...-2).step(-2)")].should == []
+
+ @array[eval("(1..-2).step(-10)")].should == []
+ @array[eval("(1...-2).step(-10)")].should == []
+
+ # start with negative index, end with positive index
+ @array[eval("(-4..4).step(-1)")].should == []
+ @array[eval("(-4...4).step(-1)")].should == []
+
+ @array[eval("(-4..4).step(-2)")].should == []
+ @array[eval("(-4...4).step(-2)")].should == []
+
+ @array[eval("(-4..4).step(-10)")].should == []
+ @array[eval("(-4...4).step(-10)")].should == []
+
+ # start with negative index, end with negative index
+ @array[eval("(-4..-2).step(-1)")].should == []
+ @array[eval("(-4...-2).step(-1)")].should == []
+
+ @array[eval("(-4..-2).step(-2)")].should == []
+ @array[eval("(-4...-2).step(-2)")].should == []
+
+ @array[eval("(-4..-2).step(-10)")].should == []
+ @array[eval("(-4...-2).step(-10)")].should == []
+ end
+
+ it "has inverted closed range and positive steps" do
+ # start and end with positive index
+ @array[eval("(3..1).step(1)")].should == []
+ @array[eval("(3...1).step(1)")].should == []
+
+ @array[eval("(3..1).step(2)")].should == []
+ @array[eval("(3...1).step(2)")].should == []
+
+ @array[eval("(3..1).step(10)")].should == []
+ @array[eval("(3...1).step(10)")].should == []
+
+ # start with negative index, end with positive index
+ @array[eval("(-2..1).step(1)")].should == []
+ @array[eval("(-2...1).step(1)")].should == []
+
+ @array[eval("(-2..1).step(2)")].should == []
+ @array[eval("(-2...1).step(2)")].should == []
+
+ @array[eval("(-2..1).step(10)")].should == []
+ @array[eval("(-2...1).step(10)")].should == []
+
+ # start with positive index, end with negative index
+ @array[eval("(4..-4).step(1)")].should == []
+ @array[eval("(4...-4).step(1)")].should == []
+
+ @array[eval("(4..-4).step(2)")].should == []
+ @array[eval("(4...-4).step(2)")].should == []
+
+ @array[eval("(4..-4).step(10)")].should == []
+ @array[eval("(4...-4).step(10)")].should == []
+
+ # start with negative index, end with negative index
+ @array[eval("(-2..-4).step(1)")].should == []
+ @array[eval("(-2...-4).step(1)")].should == []
+
+ @array[eval("(-2..-4).step(2)")].should == []
+ @array[eval("(-2...-4).step(2)")].should == []
+
+ @array[eval("(-2..-4).step(10)")].should == []
+ @array[eval("(-2...-4).step(10)")].should == []
+ end
+
+ it "has range with bounds outside of array" do
+ # end is equal to array's length
+ @array[(0..6).step(1)].should == [0, 1, 2, 3, 4, 5]
+ -> { @array[(0..6).step(2)] }.should.raise(RangeError)
+
+ # end is greater than length with positive steps
+ @array[(1..6).step(2)].should == [1, 3, 5]
+ @array[(2..7).step(2)].should == [2, 4]
+ -> { @array[(2..8).step(2)] }.should.raise(RangeError)
+
+ # begin is greater than length with negative steps
+ @array[(6..1).step(-2)].should == [5, 3, 1]
+ @array[(7..2).step(-2)].should == [5, 3]
+ -> { @array[(8..2).step(-2)] }.should.raise(RangeError)
+ end
+
+ it "has endless range with start outside of array's bounds" do
+ @array[eval("(6..).step(1)")].should == []
+ @array[eval("(7..).step(1)")].should == nil
+
+ @array[eval("(6..).step(2)")].should == []
+ -> { @array[eval("(7..).step(2)")] }.should.raise(RangeError)
+ end
+ end
+
+ it "can accept beginless ranges" do
+ a = [0, 1, 2, 3, 4, 5]
+ a[(..3)].should == [0, 1, 2, 3]
+ a[(...3)].should == [0, 1, 2]
+ a[(..-3)].should == [0, 1, 2, 3]
+ a[(...-3)].should == [0, 1, 2]
+ a[(..0)].should == [0]
+ a[(...0)].should == []
+ a[(..9)].should == [0, 1, 2, 3, 4, 5]
+ a[(...9)].should == [0, 1, 2, 3, 4, 5]
+ a[(..-9)].should == []
+ a[(...-9)].should == []
+ end
+
+ describe "can be sliced with Enumerator::ArithmeticSequence" do
+ it "with infinite/inverted ranges and negative steps" do
+ array = [0, 1, 2, 3, 4, 5]
+ array[(2..).step(-1)].should == [2, 1, 0]
+ array[(2..).step(-2)].should == [2, 0]
+ array[(2..).step(-3)].should == [2]
+ array[(2..).step(-4)].should == [2]
+
+ array[(-3..).step(-1)].should == [3, 2, 1, 0]
+ array[(-3..).step(-2)].should == [3, 1]
+ array[(-3..).step(-3)].should == [3, 0]
+ array[(-3..).step(-4)].should == [3]
+ array[(-3..).step(-5)].should == [3]
+
+ array[(..0).step(-1)].should == [5, 4, 3, 2, 1, 0]
+ array[(..0).step(-2)].should == [5, 3, 1]
+ array[(..0).step(-3)].should == [5, 2]
+ array[(..0).step(-4)].should == [5, 1]
+ array[(..0).step(-5)].should == [5, 0]
+ array[(..0).step(-6)].should == [5]
+ array[(..0).step(-7)].should == [5]
+
+ array[(...0).step(-1)].should == [5, 4, 3, 2, 1]
+ array[(...0).step(-2)].should == [5, 3, 1]
+ array[(...0).step(-3)].should == [5, 2]
+ array[(...0).step(-4)].should == [5, 1]
+ array[(...0).step(-5)].should == [5]
+ array[(...0).step(-6)].should == [5]
+
+ array[(...1).step(-1)].should == [5, 4, 3, 2]
+ array[(...1).step(-2)].should == [5, 3]
+ array[(...1).step(-3)].should == [5, 2]
+ array[(...1).step(-4)].should == [5]
+ array[(...1).step(-5)].should == [5]
+
+ array[(..-5).step(-1)].should == [5, 4, 3, 2, 1]
+ array[(..-5).step(-2)].should == [5, 3, 1]
+ array[(..-5).step(-3)].should == [5, 2]
+ array[(..-5).step(-4)].should == [5, 1]
+ array[(..-5).step(-5)].should == [5]
+ array[(..-5).step(-6)].should == [5]
+
+ array[(...-5).step(-1)].should == [5, 4, 3, 2]
+ array[(...-5).step(-2)].should == [5, 3]
+ array[(...-5).step(-3)].should == [5, 2]
+ array[(...-5).step(-4)].should == [5]
+ array[(...-5).step(-5)].should == [5]
+
+ array[(4..1).step(-1)].should == [4, 3, 2, 1]
+ array[(4..1).step(-2)].should == [4, 2]
+ array[(4..1).step(-3)].should == [4, 1]
+ array[(4..1).step(-4)].should == [4]
+ array[(4..1).step(-5)].should == [4]
+
+ array[(4...1).step(-1)].should == [4, 3, 2]
+ array[(4...1).step(-2)].should == [4, 2]
+ array[(4...1).step(-3)].should == [4]
+ array[(4...1).step(-4)].should == [4]
+
+ array[(-2..1).step(-1)].should == [4, 3, 2, 1]
+ array[(-2..1).step(-2)].should == [4, 2]
+ array[(-2..1).step(-3)].should == [4, 1]
+ array[(-2..1).step(-4)].should == [4]
+ array[(-2..1).step(-5)].should == [4]
+
+ array[(-2...1).step(-1)].should == [4, 3, 2]
+ array[(-2...1).step(-2)].should == [4, 2]
+ array[(-2...1).step(-3)].should == [4]
+ array[(-2...1).step(-4)].should == [4]
+
+ array[(4..-5).step(-1)].should == [4, 3, 2, 1]
+ array[(4..-5).step(-2)].should == [4, 2]
+ array[(4..-5).step(-3)].should == [4, 1]
+ array[(4..-5).step(-4)].should == [4]
+ array[(4..-5).step(-5)].should == [4]
+
+ array[(4...-5).step(-1)].should == [4, 3, 2]
+ array[(4...-5).step(-2)].should == [4, 2]
+ array[(4...-5).step(-3)].should == [4]
+ array[(4...-5).step(-4)].should == [4]
+
+ array[(-2..-5).step(-1)].should == [4, 3, 2, 1]
+ array[(-2..-5).step(-2)].should == [4, 2]
+ array[(-2..-5).step(-3)].should == [4, 1]
+ array[(-2..-5).step(-4)].should == [4]
+ array[(-2..-5).step(-5)].should == [4]
+
+ array[(-2...-5).step(-1)].should == [4, 3, 2]
+ array[(-2...-5).step(-2)].should == [4, 2]
+ array[(-2...-5).step(-3)].should == [4]
+ array[(-2...-5).step(-4)].should == [4]
+ end
+ end
+
+ it "can accept nil...nil ranges" do
+ a = [0, 1, 2, 3, 4, 5]
+ a[eval("(nil...nil)")].should == a
+ a[(...nil)].should == a
+ a[eval("(nil..)")].should == a
+ end
end
describe "Array.[]" do
@@ -39,12 +892,12 @@ describe "Array.[]" do
end
it "returns an instance of the subclass" do
- ArraySpecs::MyArray[1, 2, 3].should be_an_instance_of(ArraySpecs::MyArray)
+ ArraySpecs::MyArray[1, 2, 3].should.instance_of?(ArraySpecs::MyArray)
end
it "does not call #initialize on the subclass instance" do
ArraySpecs::MyArray[1, 2, 3].should == [1, 2, 3]
- ScratchPad.recorded.should be_nil
+ ScratchPad.recorded.should == nil
end
end
end
diff --git a/spec/ruby/core/array/element_set_spec.rb b/spec/ruby/core/array/element_set_spec.rb
index df5ca9582e..671e4338de 100644
--- a/spec/ruby/core/array/element_set_spec.rb
+++ b/spec/ruby/core/array/element_set_spec.rb
@@ -95,8 +95,8 @@ describe "Array#[]=" do
it "checks frozen before attempting to coerce arguments" do
a = [1,2,3,4].freeze
- -> {a[:foo] = 1}.should raise_error(FrozenError)
- -> {a[:foo, :bar] = 1}.should raise_error(FrozenError)
+ -> {a[:foo] = 1}.should.raise(FrozenError)
+ -> {a[:foo, :bar] = 1}.should.raise(FrozenError)
end
it "sets elements in the range arguments when passed ranges" do
@@ -197,25 +197,25 @@ describe "Array#[]=" do
a[to .. from] = ["x"]
a.should == [1, "a", "b", "x", "c", 4]
- -> { a["a" .. "b"] = [] }.should raise_error(TypeError)
- -> { a[from .. "b"] = [] }.should raise_error(TypeError)
+ -> { a["a" .. "b"] = [] }.should.raise(TypeError)
+ -> { a[from .. "b"] = [] }.should.raise(TypeError)
end
it "raises an IndexError when passed indexes out of bounds" do
a = [1, 2, 3, 4]
- -> { a[-5] = "" }.should raise_error(IndexError)
- -> { a[-5, -1] = "" }.should raise_error(IndexError)
- -> { a[-5, 0] = "" }.should raise_error(IndexError)
- -> { a[-5, 1] = "" }.should raise_error(IndexError)
- -> { a[-5, 2] = "" }.should raise_error(IndexError)
- -> { a[-5, 10] = "" }.should raise_error(IndexError)
-
- -> { a[-5..-5] = "" }.should raise_error(RangeError)
- -> { a[-5...-5] = "" }.should raise_error(RangeError)
- -> { a[-5..-4] = "" }.should raise_error(RangeError)
- -> { a[-5...-4] = "" }.should raise_error(RangeError)
- -> { a[-5..10] = "" }.should raise_error(RangeError)
- -> { a[-5...10] = "" }.should raise_error(RangeError)
+ -> { a[-5] = "" }.should.raise(IndexError)
+ -> { a[-5, -1] = "" }.should.raise(IndexError)
+ -> { a[-5, 0] = "" }.should.raise(IndexError)
+ -> { a[-5, 1] = "" }.should.raise(IndexError)
+ -> { a[-5, 2] = "" }.should.raise(IndexError)
+ -> { a[-5, 10] = "" }.should.raise(IndexError)
+
+ -> { a[-5..-5] = "" }.should.raise(RangeError)
+ -> { a[-5...-5] = "" }.should.raise(RangeError)
+ -> { a[-5..-4] = "" }.should.raise(RangeError)
+ -> { a[-5...-4] = "" }.should.raise(RangeError)
+ -> { a[-5..10] = "" }.should.raise(RangeError)
+ -> { a[-5...10] = "" }.should.raise(RangeError)
# ok
a[0..-9] = [1]
@@ -239,7 +239,7 @@ describe "Array#[]=" do
end
it "raises a FrozenError on a frozen array" do
- -> { ArraySpecs.frozen_array[0, 0] = [] }.should raise_error(FrozenError)
+ -> { ArraySpecs.frozen_array[0, 0] = [] }.should.raise(FrozenError)
end
end
@@ -349,12 +349,12 @@ describe "Array#[]= with [index, count]" do
it "raises an IndexError when passed start and negative length" do
a = [1, 2, 3, 4]
- -> { a[-2, -1] = "" }.should raise_error(IndexError)
- -> { a[0, -1] = "" }.should raise_error(IndexError)
- -> { a[2, -1] = "" }.should raise_error(IndexError)
- -> { a[4, -1] = "" }.should raise_error(IndexError)
- -> { a[10, -1] = "" }.should raise_error(IndexError)
- -> { [1, 2, 3, 4, 5][2, -1] = [7, 8] }.should raise_error(IndexError)
+ -> { a[-2, -1] = "" }.should.raise(IndexError)
+ -> { a[0, -1] = "" }.should.raise(IndexError)
+ -> { a[2, -1] = "" }.should.raise(IndexError)
+ -> { a[4, -1] = "" }.should.raise(IndexError)
+ -> { a[10, -1] = "" }.should.raise(IndexError)
+ -> { [1, 2, 3, 4, 5][2, -1] = [7, 8] }.should.raise(IndexError)
end
end
diff --git a/spec/ruby/core/array/eql_spec.rb b/spec/ruby/core/array/eql_spec.rb
index 8565b94c60..9a7447c2e8 100644
--- a/spec/ruby/core/array/eql_spec.rb
+++ b/spec/ruby/core/array/eql_spec.rb
@@ -6,7 +6,7 @@ describe "Array#eql?" do
it_behaves_like :array_eql, :eql?
it "returns false if any corresponding elements are not #eql?" do
- [1, 2, 3, 4].should_not eql([1, 2, 3, 4.0])
+ [1, 2, 3, 4].should_not.eql?([1, 2, 3, 4.0])
end
it "returns false if other is not a kind of Array" do
@@ -14,6 +14,6 @@ describe "Array#eql?" do
obj.should_not_receive(:to_ary)
obj.should_not_receive(:eql?)
- [1, 2, 3].should_not eql(obj)
+ [1, 2, 3].should_not.eql?(obj)
end
end
diff --git a/spec/ruby/core/array/equal_value_spec.rb b/spec/ruby/core/array/equal_value_spec.rb
index a82e07b218..4f7c0ce5e3 100644
--- a/spec/ruby/core/array/equal_value_spec.rb
+++ b/spec/ruby/core/array/equal_value_spec.rb
@@ -10,17 +10,17 @@ describe "Array#==" do
obj.should_receive(:respond_to?).at_least(1).with(:to_ary).and_return(true)
obj.should_receive(:==).with([1]).at_least(1).and_return(true)
- ([1] == obj).should be_true
- ([[1]] == [obj]).should be_true
- ([[[1], 3], 2] == [[obj, 3], 2]).should be_true
+ ([1] == obj).should == true
+ ([[1]] == [obj]).should == true
+ ([[[1], 3], 2] == [[obj, 3], 2]).should == true
# recursive arrays
arr1 = [[1]]
arr1 << arr1
arr2 = [obj]
arr2 << arr2
- (arr1 == arr2).should be_true
- (arr2 == arr1).should be_true
+ (arr1 == arr2).should == true
+ (arr2 == arr1).should == true
end
it "returns false if any corresponding elements are not #==" do
diff --git a/spec/ruby/core/array/fetch_spec.rb b/spec/ruby/core/array/fetch_spec.rb
index b81c0b48d7..ee94cfcbb2 100644
--- a/spec/ruby/core/array/fetch_spec.rb
+++ b/spec/ruby/core/array/fetch_spec.rb
@@ -12,9 +12,9 @@ describe "Array#fetch" do
end
it "raises an IndexError if there is no element at index" do
- -> { [1, 2, 3].fetch(3) }.should raise_error(IndexError)
- -> { [1, 2, 3].fetch(-4) }.should raise_error(IndexError)
- -> { [].fetch(0) }.should raise_error(IndexError)
+ -> { [1, 2, 3].fetch(3) }.should.raise(IndexError, "index 3 outside of array bounds: -3...3")
+ -> { [1, 2, 3].fetch(-4) }.should.raise(IndexError, "index -4 outside of array bounds: -3...3")
+ -> { [].fetch(0) }.should.raise(IndexError, "index 0 outside of array bounds: 0...0")
end
it "returns default if there is no element at index if passed a default value" do
@@ -33,7 +33,7 @@ describe "Array#fetch" do
o = mock('5')
def o.to_int(); 5; end
- [1, 2, 3].fetch(o) { |i| i }.should equal(o)
+ [1, 2, 3].fetch(o) { |i| i }.should.equal?(o)
end
it "gives precedence to the default block over the default argument" do
@@ -50,6 +50,6 @@ describe "Array#fetch" do
end
it "raises a TypeError when the passed argument can't be coerced to Integer" do
- -> { [].fetch("cat") }.should raise_error(TypeError)
+ -> { [].fetch("cat") }.should.raise(TypeError, "no implicit conversion of String into Integer")
end
end
diff --git a/spec/ruby/core/array/fetch_values_spec.rb b/spec/ruby/core/array/fetch_values_spec.rb
index cf377b3b71..237d6ad7f7 100644
--- a/spec/ruby/core/array/fetch_values_spec.rb
+++ b/spec/ruby/core/array/fetch_values_spec.rb
@@ -21,7 +21,7 @@ describe "Array#fetch_values" do
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, "index 44 outside of array bounds: -3...3")
+ -> { @array.fetch_values(0, 1, 44) }.should.raise(IndexError, "index 44 outside of array bounds: -3...3")
end
it "returns the default value from block" do
@@ -45,11 +45,11 @@ describe "Array#fetch_values" do
it "does not support a Range object as argument" do
-> {
@array.fetch_values(1..2)
- }.should raise_error(TypeError, "no implicit conversion of Range into Integer")
+ }.should.raise(TypeError, "no implicit conversion of Range into Integer")
end
it "raises a TypeError when the passed argument can't be coerced to Integer" do
- -> { [].fetch_values("cat") }.should raise_error(TypeError, "no implicit conversion of String into Integer")
+ -> { [].fetch_values("cat") }.should.raise(TypeError, "no implicit conversion of String into Integer")
end
end
end
diff --git a/spec/ruby/core/array/fill_spec.rb b/spec/ruby/core/array/fill_spec.rb
index 2c3b5d9e84..e4d51bd998 100644
--- a/spec/ruby/core/array/fill_spec.rb
+++ b/spec/ruby/core/array/fill_spec.rb
@@ -10,7 +10,7 @@ describe "Array#fill" do
it "returns self" do
ary = [1, 2, 3]
- ary.fill(:a).should equal(ary)
+ ary.fill(:a).should.equal?(ary)
end
it "is destructive" do
@@ -25,10 +25,10 @@ describe "Array#fill" do
ary.fill(str).should == [str, str, str, str]
str << "y"
ary.should == [str, str, str, str]
- ary[0].should equal(str)
- ary[1].should equal(str)
- ary[2].should equal(str)
- ary[3].should equal(str)
+ ary[0].should.equal?(str)
+ ary[1].should.equal?(str)
+ ary[2].should.equal?(str)
+ ary[3].should.equal?(str)
end
it "replaces all elements in the array with the filler if not given a index nor a length" do
@@ -44,29 +44,29 @@ describe "Array#fill" do
end
it "raises a FrozenError on a frozen array" do
- -> { ArraySpecs.frozen_array.fill('x') }.should raise_error(FrozenError)
+ -> { ArraySpecs.frozen_array.fill('x') }.should.raise(FrozenError)
end
it "raises a FrozenError on an empty frozen array" do
- -> { ArraySpecs.empty_frozen_array.fill('x') }.should raise_error(FrozenError)
+ -> { ArraySpecs.empty_frozen_array.fill('x') }.should.raise(FrozenError)
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', 1, 2, true) }.should raise_error(ArgumentError)
+ -> { [].fill('a', 1, 2, true) }.should.raise(ArgumentError)
end
it "raises an ArgumentError if no argument passed and no block given" do
- -> { [].fill }.should raise_error(ArgumentError)
+ -> { [].fill }.should.raise(ArgumentError)
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)
+ -> { [].fill(1, 2, true) {|i|} }.should.raise(ArgumentError)
end
it "does not truncate the array is the block raises an exception" do
@@ -237,24 +237,24 @@ describe "Array#fill with (filler, index, length)" do
end
it "raises a TypeError if the index is not numeric" do
- -> { [].fill 'a', true }.should raise_error(TypeError)
+ -> { [].fill 'a', true }.should.raise(TypeError)
obj = mock('nonnumeric')
- -> { [].fill('a', obj) }.should raise_error(TypeError)
+ -> { [].fill('a', obj) }.should.raise(TypeError)
end
it "raises a TypeError when the length is not numeric" do
- -> { [1, 2, 3].fill("x", 1, "foo") }.should raise_error(TypeError, /no implicit conversion of String into Integer/)
- -> { [1, 2, 3].fill("x", 1, :"foo") }.should raise_error(TypeError, /no implicit conversion of Symbol into Integer/)
- -> { [1, 2, 3].fill("x", 1, Object.new) }.should raise_error(TypeError, /no implicit conversion of Object into Integer/)
+ -> { [1, 2, 3].fill("x", 1, "foo") }.should.raise(TypeError, /no implicit conversion of String into Integer/)
+ -> { [1, 2, 3].fill("x", 1, :"foo") }.should.raise(TypeError, /no implicit conversion of Symbol into Integer/)
+ -> { [1, 2, 3].fill("x", 1, Object.new) }.should.raise(TypeError, /no implicit conversion of Object into Integer/)
end
not_supported_on :opal do
it "raises an ArgumentError or RangeError for too-large sizes" do
error_types = [RangeError, ArgumentError]
arr = [1, 2, 3]
- -> { arr.fill(10, 1, fixnum_max) }.should raise_error { |err| error_types.should include(err.class) }
- -> { arr.fill(10, 1, bignum_value) }.should raise_error(RangeError)
+ -> { arr.fill(10, 1, fixnum_max) }.should.raise { |err| error_types.should.include?(err.class) }
+ -> { arr.fill(10, 1, bignum_value) }.should.raise(RangeError)
end
end
end
@@ -284,7 +284,7 @@ describe "Array#fill with (filler, range)" do
end
it "raises a TypeError with range and length argument" do
- -> { [].fill('x', 0 .. 2, 5) }.should raise_error(TypeError)
+ -> { [].fill('x', 0 .. 2, 5) }.should.raise(TypeError)
end
it "replaces elements between the (-m)th to the last and the (n+1)th from the first if given an range m..n where m < 0 and n >= 0" do
@@ -336,13 +336,13 @@ describe "Array#fill with (filler, range)" do
end
it "raises an exception if some of the given range lies before the first of the array" do
- -> { [1, 2, 3].fill('x', -5..-3) }.should raise_error(RangeError)
- -> { [1, 2, 3].fill('x', -5...-3) }.should raise_error(RangeError)
- -> { [1, 2, 3].fill('x', -5..-4) }.should raise_error(RangeError)
+ -> { [1, 2, 3].fill('x', -5..-3) }.should.raise(RangeError)
+ -> { [1, 2, 3].fill('x', -5...-3) }.should.raise(RangeError)
+ -> { [1, 2, 3].fill('x', -5..-4) }.should.raise(RangeError)
- -> { [1, 2, 3].fill(-5..-3, &@never_passed) }.should raise_error(RangeError)
- -> { [1, 2, 3].fill(-5...-3, &@never_passed) }.should raise_error(RangeError)
- -> { [1, 2, 3].fill(-5..-4, &@never_passed) }.should raise_error(RangeError)
+ -> { [1, 2, 3].fill(-5..-3, &@never_passed) }.should.raise(RangeError)
+ -> { [1, 2, 3].fill(-5...-3, &@never_passed) }.should.raise(RangeError)
+ -> { [1, 2, 3].fill(-5..-4, &@never_passed) }.should.raise(RangeError)
end
it "tries to convert the start and end of the passed range to Integers using #to_int" do
@@ -357,7 +357,7 @@ describe "Array#fill with (filler, range)" do
it "raises a TypeError if the start or end of the passed range is not numeric" do
obj = mock('nonnumeric')
def obj.<=>(rhs); rhs == self ? 0 : nil end
- -> { [].fill('a', obj..obj) }.should raise_error(TypeError)
+ -> { [].fill('a', obj..obj) }.should.raise(TypeError)
end
it "works with endless ranges" do
diff --git a/spec/ruby/core/array/filter_spec.rb b/spec/ruby/core/array/filter_spec.rb
index 156ad14f9c..6ebda61069 100644
--- a/spec/ruby/core/array/filter_spec.rb
+++ b/spec/ruby/core/array/filter_spec.rb
@@ -1,14 +1,13 @@
require_relative '../../spec_helper'
-require_relative 'shared/select'
describe "Array#filter" do
- it_behaves_like :array_select, :filter
+ it "is an alias of Array#select" do
+ Array.instance_method(:filter).should == Array.instance_method(:select)
+ end
end
describe "Array#filter!" do
- it "returns nil if no changes were made in the array" do
- [1, 2, 3].filter! { true }.should be_nil
+ it "is an alias of Array#select!" do
+ Array.instance_method(:filter!).should == Array.instance_method(:select!)
end
-
- it_behaves_like :keep_if, :filter!
end
diff --git a/spec/ruby/core/array/find_index_spec.rb b/spec/ruby/core/array/find_index_spec.rb
index 759472024a..17ff6c04a7 100644
--- a/spec/ruby/core/array/find_index_spec.rb
+++ b/spec/ruby/core/array/find_index_spec.rb
@@ -1,6 +1,42 @@
require_relative '../../spec_helper'
-require_relative 'shared/index'
+require_relative 'shared/iterable_and_tolerating_size_increasing'
describe "Array#find_index" do
- it_behaves_like :array_index, :find_index
+ it "returns the index of the first element == to object" do
+ x = mock('3')
+ def x.==(obj) 3 == obj; end
+
+ [2, x, 3, 1, 3, 1].find_index(3).should == 1
+ [2, 3.0, 3, x, 1, 3, 1].find_index(x).should == 1
+ end
+
+ it "returns 0 if first element == to object" do
+ [2, 1, 3, 2, 5].find_index(2).should == 0
+ end
+
+ it "returns size-1 if only last element == to object" do
+ [2, 1, 3, 1, 5].find_index(5).should == 4
+ end
+
+ it "returns nil if no element == to object" do
+ [2, 1, 1, 1, 1].find_index(3).should == nil
+ end
+
+ it "accepts a block instead of an argument" do
+ [4, 2, 1, 5, 1, 3].find_index {|x| x < 2}.should == 2
+ end
+
+ it "ignores the block if there is an argument" do
+ -> {
+ [4, 2, 1, 5, 1, 3].find_index(5) {|x| x < 2}.should == 3
+ }.should complain(/given block not used/)
+ end
+
+ describe "given no argument and no block" do
+ it "produces an Enumerator" do
+ [].find_index.should.instance_of?(Enumerator)
+ end
+ end
+
+ it_behaves_like :array_iterable_and_tolerating_size_increasing, :find_index
end
diff --git a/spec/ruby/core/array/first_spec.rb b/spec/ruby/core/array/first_spec.rb
index 66eeba6565..2c343ac8f6 100644
--- a/spec/ruby/core/array/first_spec.rb
+++ b/spec/ruby/core/array/first_spec.rb
@@ -30,11 +30,11 @@ describe "Array#first" do
end
it "raises an ArgumentError when count is negative" do
- -> { [1, 2].first(-1) }.should raise_error(ArgumentError)
+ -> { [1, 2].first(-1) }.should.raise(ArgumentError)
end
it "raises a RangeError when count is a Bignum" do
- -> { [].first(bignum_value) }.should raise_error(RangeError)
+ -> { [].first(bignum_value) }.should.raise(RangeError)
end
it "returns the entire array when count > length" do
@@ -53,10 +53,10 @@ describe "Array#first" do
it "properly handles recursive arrays" do
empty = ArraySpecs.empty_recursive_array
- empty.first.should equal(empty)
+ empty.first.should.equal?(empty)
ary = ArraySpecs.head_recursive_array
- ary.first.should equal(ary)
+ ary.first.should.equal?(ary)
end
it "tries to convert the passed argument to an Integer using #to_int" do
@@ -66,19 +66,19 @@ describe "Array#first" do
end
it "raises a TypeError if the passed argument is not numeric" do
- -> { [1,2].first(nil) }.should raise_error(TypeError)
- -> { [1,2].first("a") }.should raise_error(TypeError)
+ -> { [1,2].first(nil) }.should.raise(TypeError)
+ -> { [1,2].first("a") }.should.raise(TypeError)
obj = mock("nonnumeric")
- -> { [1,2].first(obj) }.should raise_error(TypeError)
+ -> { [1,2].first(obj) }.should.raise(TypeError)
end
it "does not return subclass instance when passed count on Array subclasses" do
- ArraySpecs::MyArray[].first(0).should be_an_instance_of(Array)
- ArraySpecs::MyArray[].first(2).should be_an_instance_of(Array)
- ArraySpecs::MyArray[1, 2, 3].first(0).should be_an_instance_of(Array)
- ArraySpecs::MyArray[1, 2, 3].first(1).should be_an_instance_of(Array)
- ArraySpecs::MyArray[1, 2, 3].first(2).should be_an_instance_of(Array)
+ ArraySpecs::MyArray[].first(0).should.instance_of?(Array)
+ ArraySpecs::MyArray[].first(2).should.instance_of?(Array)
+ ArraySpecs::MyArray[1, 2, 3].first(0).should.instance_of?(Array)
+ ArraySpecs::MyArray[1, 2, 3].first(1).should.instance_of?(Array)
+ ArraySpecs::MyArray[1, 2, 3].first(2).should.instance_of?(Array)
end
it "is not destructive" do
diff --git a/spec/ruby/core/array/flatten_spec.rb b/spec/ruby/core/array/flatten_spec.rb
index 8c97000c79..272406b8f9 100644
--- a/spec/ruby/core/array/flatten_spec.rb
+++ b/spec/ruby/core/array/flatten_spec.rb
@@ -13,7 +13,7 @@ describe "Array#flatten" do
it "returns dup when the level of recursion is 0" do
a = [ 1, 2, [3, [4, 5] ] ]
a.flatten(0).should == a
- a.flatten(0).should_not equal(a)
+ a.flatten(0).should_not.equal?(a)
end
it "ignores negative levels" do
@@ -30,7 +30,7 @@ describe "Array#flatten" do
it "raises a TypeError when the passed Object can't be converted to an Integer" do
obj = mock("Not converted")
- -> { [ 1, 2, [3, [4, 5] ] ].flatten(obj) }.should raise_error(TypeError)
+ -> { [ 1, 2, [3, [4, 5] ] ].flatten(obj) }.should.raise(TypeError)
end
it "does not call flatten on elements" do
@@ -46,13 +46,13 @@ describe "Array#flatten" do
it "raises an ArgumentError on recursive arrays" do
x = []
x << x
- -> { x.flatten }.should raise_error(ArgumentError)
+ -> { x.flatten }.should.raise(ArgumentError)
x = []
y = []
x << y
y << x
- -> { x.flatten }.should raise_error(ArgumentError)
+ -> { x.flatten }.should.raise(ArgumentError)
end
it "flattens any element which responds to #to_ary, using the return value of said method" do
@@ -76,11 +76,11 @@ describe "Array#flatten" do
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[].flatten.should.instance_of?(Array)
+ ArraySpecs::MyArray[1, 2, 3].flatten.should.instance_of?(Array)
+ ArraySpecs::MyArray[1, [2], 3].flatten.should.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)
+ [ArraySpecs::MyArray[1, 2, 3]].flatten.should.instance_of?(Array)
end
it "is not destructive" do
@@ -106,7 +106,7 @@ describe "Array#flatten" do
it "raises a TypeError if #to_ary does not return an Array" do
@obj.should_receive(:to_ary).and_return(1)
- -> { [@obj].flatten }.should raise_error(TypeError)
+ -> { [@obj].flatten }.should.raise(TypeError)
end
it "calls respond_to_missing?(:to_ary, true) to try coercing" do
@@ -125,7 +125,7 @@ describe "Array#flatten" do
it "calls #to_ary if not defined when #respond_to_missing? returns true" do
def @obj.respond_to_missing?(name, priv) ScratchPad << name; true end
- -> { [@obj].flatten }.should raise_error(NoMethodError)
+ -> { [@obj].flatten }.should.raise(NoMethodError)
ScratchPad.recorded.should == [:to_ary]
end
@@ -168,7 +168,7 @@ describe "Array#flatten!" do
it "returns self if made some modifications" do
a = [[[1, [2, 3]],[2, 3, [4, [4, [5, 5]], [1, 2, 3]]], [4]], []]
- a.flatten!.should equal(a)
+ a.flatten!.should.equal?(a)
end
it "returns nil if no modifications took place" do
@@ -208,7 +208,7 @@ describe "Array#flatten!" do
it "raises a TypeError when the passed Object can't be converted to an Integer" do
obj = mock("Not converted")
- -> { [ 1, 2, [3, [4, 5] ] ].flatten!(obj) }.should raise_error(TypeError)
+ -> { [ 1, 2, [3, [4, 5] ] ].flatten!(obj) }.should.raise(TypeError)
end
it "does not call flatten! on elements" do
@@ -224,13 +224,13 @@ describe "Array#flatten!" do
it "raises an ArgumentError on recursive arrays" do
x = []
x << x
- -> { x.flatten! }.should raise_error(ArgumentError)
+ -> { x.flatten! }.should.raise(ArgumentError)
x = []
y = []
x << y
y << x
- -> { x.flatten! }.should raise_error(ArgumentError)
+ -> { x.flatten! }.should.raise(ArgumentError)
end
it "flattens any elements which responds to #to_ary, using the return value of said method" do
@@ -248,19 +248,19 @@ describe "Array#flatten!" do
ary = [ArraySpecs::MyArray[1, 2, 3]]
ary.flatten!
- ary.should be_an_instance_of(Array)
+ ary.should.instance_of?(Array)
ary.should == [1, 2, 3]
end
it "raises a FrozenError on frozen arrays when the array is modified" do
nested_ary = [1, 2, []]
nested_ary.freeze
- -> { nested_ary.flatten! }.should raise_error(FrozenError)
+ -> { nested_ary.flatten! }.should.raise(FrozenError)
end
# see [ruby-core:23663]
it "raises a FrozenError on frozen arrays when the array would not be modified" do
- -> { ArraySpecs.frozen_array.flatten! }.should raise_error(FrozenError)
- -> { ArraySpecs.empty_frozen_array.flatten! }.should raise_error(FrozenError)
+ -> { ArraySpecs.frozen_array.flatten! }.should.raise(FrozenError)
+ -> { ArraySpecs.empty_frozen_array.flatten! }.should.raise(FrozenError)
end
end
diff --git a/spec/ruby/core/array/hash_spec.rb b/spec/ruby/core/array/hash_spec.rb
index f3bcc83fce..3b7b6d5bed 100644
--- a/spec/ruby/core/array/hash_spec.rb
+++ b/spec/ruby/core/array/hash_spec.rb
@@ -7,16 +7,16 @@ describe "Array#hash" do
[[], [1, 2, 3]].each do |ary|
ary.hash.should == ary.dup.hash
- ary.hash.should be_an_instance_of(Integer)
+ ary.hash.should.instance_of?(Integer)
end
end
it "properly handles recursive arrays" do
empty = ArraySpecs.empty_recursive_array
- -> { empty.hash }.should_not raise_error
+ -> { empty.hash }.should_not.raise
array = ArraySpecs.recursive_array
- -> { array.hash }.should_not raise_error
+ -> { array.hash }.should_not.raise
end
it "returns the same hash for equal recursive arrays" do
@@ -74,7 +74,7 @@ describe "Array#hash" do
a.fill 'a', 0..3
b = %w|a a a a|
a.hash.should == b.hash
- a.should eql(b)
+ a.should.eql?(b)
end
it "produces different hashes for nested arrays with different values and empty terminator" do
diff --git a/spec/ruby/core/array/index_spec.rb b/spec/ruby/core/array/index_spec.rb
index 3acb7d0ef3..b66cb6eb53 100644
--- a/spec/ruby/core/array/index_spec.rb
+++ b/spec/ruby/core/array/index_spec.rb
@@ -1,6 +1,7 @@
require_relative '../../spec_helper'
-require_relative 'shared/index'
describe "Array#index" do
- it_behaves_like :array_index, :index
+ it "is an alias of Array#find_index" do
+ Array.instance_method(:index).should == Array.instance_method(:find_index)
+ end
end
diff --git a/spec/ruby/core/array/initialize_spec.rb b/spec/ruby/core/array/initialize_spec.rb
index b9fa77b16e..19ee37825e 100644
--- a/spec/ruby/core/array/initialize_spec.rb
+++ b/spec/ruby/core/array/initialize_spec.rb
@@ -7,7 +7,7 @@ describe "Array#initialize" do
end
it "is private" do
- Array.should have_private_instance_method("initialize")
+ Array.private_instance_methods(false).should.include?(:initialize)
end
it "is called on subclasses" do
@@ -19,26 +19,26 @@ describe "Array#initialize" do
it "preserves the object's identity even when changing its value" do
a = [1, 2, 3]
- a.send(:initialize).should equal(a)
+ a.send(:initialize).should.equal?(a)
a.should_not == [1, 2, 3]
end
it "raises an ArgumentError if passed 3 or more arguments" do
-> do
[1, 2].send :initialize, 1, 'x', true
- end.should raise_error(ArgumentError)
+ end.should.raise(ArgumentError)
-> do
[1, 2].send(:initialize, 1, 'x', true) {}
- end.should raise_error(ArgumentError)
+ end.should.raise(ArgumentError)
end
it "raises a FrozenError on frozen arrays" do
-> do
ArraySpecs.frozen_array.send :initialize
- end.should raise_error(FrozenError)
+ end.should.raise(FrozenError)
-> do
ArraySpecs.frozen_array.send :initialize, ArraySpecs.frozen_array
- end.should raise_error(FrozenError)
+ end.should.raise(FrozenError)
end
it "calls #to_ary to convert the value to an array, even if it's private" do
@@ -49,12 +49,12 @@ end
describe "Array#initialize with no arguments" do
it "makes the array empty" do
- [1, 2, 3].send(:initialize).should be_empty
+ [1, 2, 3].send(:initialize).should.empty?
end
it "does not use the given block" do
-> {
- -> { [1, 2, 3].send(:initialize) { raise } }.should_not raise_error
+ -> { [1, 2, 3].send(:initialize) { raise } }.should_not.raise
}.should complain(/#{__FILE__}:#{__LINE__-1}: warning: given block not used/, verbose: true)
end
end
@@ -66,7 +66,7 @@ describe "Array#initialize with (array)" do
end
it "does not use the given block" do
- ->{ [1, 2, 3].send(:initialize) { raise } }.should_not raise_error
+ ->{ [1, 2, 3].send(:initialize) { raise } }.should_not.raise
end
it "calls #to_ary to convert the value to an array" do
@@ -83,7 +83,7 @@ describe "Array#initialize with (array)" do
end
it "raises a TypeError if an Array type argument and a default object" do
- -> { [].send(:initialize, [1, 2], 1) }.should raise_error(TypeError)
+ -> { [].send(:initialize, [1, 2], 1) }.should.raise(TypeError)
end
end
@@ -92,8 +92,8 @@ describe "Array#initialize with (size, object=nil)" do
a = []
obj = [3]
a.send(:initialize, 2, obj).should == [obj, obj]
- a[0].should equal(obj)
- a[1].should equal(obj)
+ a[0].should.equal?(obj)
+ a[1].should.equal?(obj)
b = []
b.send(:initialize, 3, 14).should == [14, 14, 14]
@@ -105,12 +105,12 @@ describe "Array#initialize with (size, object=nil)" do
end
it "raises an ArgumentError if size is negative" do
- -> { [].send(:initialize, -1, :a) }.should raise_error(ArgumentError)
- -> { [].send(:initialize, -1) }.should raise_error(ArgumentError)
+ -> { [].send(:initialize, -1, :a) }.should.raise(ArgumentError)
+ -> { [].send(:initialize, -1) }.should.raise(ArgumentError)
end
it "raises an ArgumentError if size is too large" do
- -> { [].send(:initialize, fixnum_max+1) }.should raise_error(ArgumentError)
+ -> { [].send(:initialize, fixnum_max+1) }.should.raise(ArgumentError)
end
it "calls #to_int to convert the size argument to an Integer when object is given" do
@@ -128,7 +128,7 @@ describe "Array#initialize with (size, object=nil)" do
it "raises a TypeError if the size argument is not an Integer type" do
obj = mock('nonnumeric')
obj.stub!(:to_ary).and_return([1, 2])
- ->{ [].send(:initialize, obj, :a) }.should raise_error(TypeError)
+ ->{ [].send(:initialize, obj, :a) }.should.raise(TypeError)
end
it "yields the index of the element and sets the element to the value of the block" do
diff --git a/spec/ruby/core/array/insert_spec.rb b/spec/ruby/core/array/insert_spec.rb
index 9e1757f68b..38e132fd25 100644
--- a/spec/ruby/core/array/insert_spec.rb
+++ b/spec/ruby/core/array/insert_spec.rb
@@ -4,8 +4,8 @@ require_relative 'fixtures/classes'
describe "Array#insert" do
it "returns self" do
ary = []
- ary.insert(0).should equal(ary)
- ary.insert(0, :a).should equal(ary)
+ ary.insert(0).should.equal?(ary)
+ ary.insert(0, :a).should.equal?(ary)
end
it "inserts objects before the element at index for non-negative index" do
@@ -46,8 +46,8 @@ describe "Array#insert" do
end
it "raises an IndexError if the negative index is out of bounds" do
- -> { [].insert(-2, 1) }.should raise_error(IndexError)
- -> { [1].insert(-3, 2) }.should raise_error(IndexError)
+ -> { [].insert(-2, 1) }.should.raise(IndexError)
+ -> { [1].insert(-3, 2) }.should.raise(IndexError)
end
it "does nothing of no object is passed" do
@@ -64,15 +64,15 @@ describe "Array#insert" do
end
it "raises an ArgumentError if no argument passed" do
- -> { [].insert() }.should raise_error(ArgumentError)
+ -> { [].insert() }.should.raise(ArgumentError)
end
it "raises a FrozenError on frozen arrays when the array is modified" do
- -> { ArraySpecs.frozen_array.insert(0, 'x') }.should raise_error(FrozenError)
+ -> { ArraySpecs.frozen_array.insert(0, 'x') }.should.raise(FrozenError)
end
# see [ruby-core:23666]
it "raises a FrozenError on frozen arrays when the array would not be modified" do
- -> { ArraySpecs.frozen_array.insert(0) }.should raise_error(FrozenError)
+ -> { ArraySpecs.frozen_array.insert(0) }.should.raise(FrozenError)
end
end
diff --git a/spec/ruby/core/array/inspect_spec.rb b/spec/ruby/core/array/inspect_spec.rb
index 0832224f5a..e5dca82889 100644
--- a/spec/ruby/core/array/inspect_spec.rb
+++ b/spec/ruby/core/array/inspect_spec.rb
@@ -1,7 +1,108 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
-require_relative 'shared/inspect'
describe "Array#inspect" do
- it_behaves_like :array_inspect, :inspect
+ it "returns a string" do
+ [1, 2, 3].inspect.should.instance_of?(String)
+ end
+
+ it "returns '[]' for an empty Array" do
+ [].inspect.should == "[]"
+ end
+
+ it "calls inspect on its elements and joins the results with commas" do
+ items = Array.new(3) do |i|
+ obj = mock(i.to_s)
+ obj.should_receive(:inspect).and_return(i.to_s)
+ obj
+ end
+ items.inspect.should == "[0, 1, 2]"
+ end
+
+ it "does not call #to_s on a String returned from #inspect" do
+ str = +"abc"
+ str.should_not_receive(:to_s)
+
+ [str].inspect.should == '["abc"]'
+ end
+
+ it "calls #to_s on the object returned from #inspect if the Object isn't a String" do
+ obj = mock("Array#inspect/to_s calls #to_s")
+ obj.should_receive(:inspect).and_return(obj)
+ obj.should_receive(:to_s).and_return("abc")
+
+ [obj].inspect.should == "[abc]"
+ end
+
+ it "does not call #to_str on the object returned from #inspect when it is not a String" do
+ obj = mock("Array#inspect/to_s does not call #to_str")
+ obj.should_receive(:inspect).and_return(obj)
+ obj.should_not_receive(:to_str)
+
+ [obj].inspect.should =~ /^\[#<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
+ obj = mock("Array#inspect/to_s does not call #to_str on #to_s result")
+ obj.should_receive(:inspect).and_return(obj)
+ obj.should_receive(:to_s).and_return(obj)
+ obj.should_not_receive(:to_str)
+
+ [obj].inspect.should =~ /^\[#<MockObject:0x[0-9a-f]+>\]$/
+ end
+
+ it "does not swallow exceptions raised by #to_s" do
+ obj = mock("Array#inspect/to_s does not swallow #to_s exceptions")
+ obj.should_receive(:inspect).and_return(obj)
+ obj.should_receive(:to_s).and_raise(Exception)
+
+ -> { [obj].inspect }.should.raise(Exception)
+ end
+
+ it "represents a recursive element with '[...]'" do
+ ArraySpecs.recursive_array.inspect.should == "[1, \"two\", 3.0, [...], [...], [...], [...], [...]]"
+ ArraySpecs.head_recursive_array.inspect.should == "[[...], [...], [...], [...], [...], 1, \"two\", 3.0]"
+ ArraySpecs.empty_recursive_array.inspect.should == "[[...]]"
+ end
+
+ describe "with encoding" do
+ before :each do
+ @default_external_encoding = Encoding.default_external
+ end
+
+ after :each do
+ Encoding.default_external = @default_external_encoding
+ end
+
+ it "returns a US-ASCII string for an empty Array" do
+ [].inspect.encoding.should == Encoding::US_ASCII
+ end
+
+ it "use the default external encoding if it is ascii compatible" do
+ Encoding.default_external = Encoding.find('UTF-8')
+
+ utf8 = "utf8".encode("UTF-8")
+ jp = "jp".encode("EUC-JP")
+ array = [jp, utf8]
+
+ array.inspect.encoding.name.should == "UTF-8"
+ end
+
+ it "use US-ASCII encoding if the default external encoding is not ascii compatible" do
+ Encoding.default_external = Encoding.find('UTF-32')
+
+ utf8 = "utf8".encode("UTF-8")
+ jp = "jp".encode("EUC-JP")
+ array = [jp, utf8]
+
+ array.inspect.encoding.name.should == "US-ASCII"
+ 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].inspect.should == '["utf_16be \u3042"]'
+ end
+ end
end
diff --git a/spec/ruby/core/array/join_spec.rb b/spec/ruby/core/array/join_spec.rb
index e78ea6f9e1..3b4946a99f 100644
--- a/spec/ruby/core/array/join_spec.rb
+++ b/spec/ruby/core/array/join_spec.rb
@@ -4,7 +4,6 @@ require_relative 'shared/join'
describe "Array#join" do
it_behaves_like :array_join_with_string_separator, :join
- it_behaves_like :array_join_with_default_separator, :join
it "does not separate elements when the passed separator is nil" do
[1, 2, 3].join(nil).should == '123'
@@ -24,11 +23,108 @@ describe "Array#join" do
it "raises a TypeError if the separator cannot be coerced to a String by calling #to_str" do
obj = mock("not a string")
- -> { [1, 2].join(obj) }.should raise_error(TypeError)
+ -> { [1, 2].join(obj) }.should.raise(TypeError)
end
it "raises a TypeError if passed false as the separator" do
- -> { [1, 2].join(false) }.should raise_error(TypeError)
+ -> { [1, 2].join(false) }.should.raise(TypeError)
+ end
+end
+
+describe "Array#join with default separator" do
+ before :each do
+ @separator = $,
+ end
+
+ after :each do
+ $, = @separator
+ end
+
+ it "returns an empty string if the Array is empty" do
+ [].join.should == ''
+ end
+
+ it "returns a US-ASCII string for an empty Array" do
+ [].join.encoding.should == Encoding::US_ASCII
+ end
+
+ it "returns a string formed by concatenating each String element separated by $," do
+ suppress_warning {
+ $, = " | "
+ ["1", "2", "3"].join.should == "1 | 2 | 3"
+ }
+ end
+
+ it "attempts coercion via #to_str first" do
+ obj = mock('foo')
+ obj.should_receive(:to_str).any_number_of_times.and_return("foo")
+ [obj].join.should == "foo"
+ end
+
+ it "attempts coercion via #to_ary second" do
+ obj = mock('foo')
+ obj.should_receive(:to_str).any_number_of_times.and_return(nil)
+ obj.should_receive(:to_ary).any_number_of_times.and_return(["foo"])
+ [obj].join.should == "foo"
+ end
+
+ it "attempts coercion via #to_s third" do
+ obj = mock('foo')
+ obj.should_receive(:to_str).any_number_of_times.and_return(nil)
+ obj.should_receive(:to_ary).any_number_of_times.and_return(nil)
+ obj.should_receive(:to_s).any_number_of_times.and_return("foo")
+ [obj].join.should == "foo"
+ end
+
+ it "raises a NoMethodError if an element does not respond to #to_str, #to_ary, or #to_s" do
+ obj = mock('o')
+ class << obj; undef :to_s; end
+ -> { [1, obj].join }.should.raise(NoMethodError)
+ end
+
+ it "raises an ArgumentError when the Array is recursive" do
+ -> { ArraySpecs.recursive_array.join }.should.raise(ArgumentError)
+ -> { ArraySpecs.head_recursive_array.join }.should.raise(ArgumentError)
+ -> { ArraySpecs.empty_recursive_array.join }.should.raise(ArgumentError)
+ end
+
+ it "uses the first encoding when other strings are compatible" do
+ ary1 = ArraySpecs.array_with_7bit_utf8_and_usascii_strings
+ ary2 = ArraySpecs.array_with_usascii_and_7bit_utf8_strings
+ ary3 = ArraySpecs.array_with_utf8_and_7bit_binary_strings
+ ary4 = ArraySpecs.array_with_usascii_and_7bit_binary_strings
+
+ ary1.join.encoding.should == Encoding::UTF_8
+ ary2.join.encoding.should == Encoding::US_ASCII
+ ary3.join.encoding.should == Encoding::UTF_8
+ ary4.join.encoding.should == Encoding::US_ASCII
+ end
+
+ it "uses the widest common encoding when other strings are incompatible" do
+ ary1 = ArraySpecs.array_with_utf8_and_usascii_strings
+ ary2 = ArraySpecs.array_with_usascii_and_utf8_strings
+
+ ary1.join.encoding.should == Encoding::UTF_8
+ ary2.join.encoding.should == Encoding::UTF_8
+ end
+
+ it "fails for arrays with incompatibly-encoded strings" do
+ ary_utf8_bad_binary = ArraySpecs.array_with_utf8_and_binary_strings
+
+ -> { ary_utf8_bad_binary.join }.should.raise(EncodingError)
+ end
+
+ context "when $, is not nil" do
+ before do
+ suppress_warning do
+ $, = '*'
+ end
+ end
+
+ it "warns" do
+ -> { [].join }.should complain(/warning: \$, is set to non-nil value/)
+ -> { [].join(nil) }.should complain(/warning: \$, is set to non-nil value/)
+ end
end
end
diff --git a/spec/ruby/core/array/keep_if_spec.rb b/spec/ruby/core/array/keep_if_spec.rb
index 40f7329b7c..62a65a04e8 100644
--- a/spec/ruby/core/array/keep_if_spec.rb
+++ b/spec/ruby/core/array/keep_if_spec.rb
@@ -4,7 +4,7 @@ require_relative 'shared/keep_if'
describe "Array#keep_if" do
it "returns the same array if no changes were made" do
array = [1, 2, 3]
- array.keep_if { true }.should equal(array)
+ array.keep_if { true }.should.equal?(array)
end
it_behaves_like :keep_if, :keep_if
diff --git a/spec/ruby/core/array/last_spec.rb b/spec/ruby/core/array/last_spec.rb
index d6fefada09..ed417bcd2a 100644
--- a/spec/ruby/core/array/last_spec.rb
+++ b/spec/ruby/core/array/last_spec.rb
@@ -28,7 +28,7 @@ describe "Array#last" do
end
it "raises an ArgumentError when count is negative" do
- -> { [1, 2].last(-1) }.should raise_error(ArgumentError)
+ -> { [1, 2].last(-1) }.should.raise(ArgumentError)
end
it "returns the entire array when count > length" do
@@ -47,10 +47,10 @@ describe "Array#last" do
it "properly handles recursive arrays" do
empty = ArraySpecs.empty_recursive_array
- empty.last.should equal(empty)
+ empty.last.should.equal?(empty)
array = ArraySpecs.recursive_array
- array.last.should equal(array)
+ array.last.should.equal?(array)
end
it "tries to convert the passed argument to an Integer using #to_int" do
@@ -60,19 +60,19 @@ describe "Array#last" do
end
it "raises a TypeError if the passed argument is not numeric" do
- -> { [1,2].last(nil) }.should raise_error(TypeError)
- -> { [1,2].last("a") }.should raise_error(TypeError)
+ -> { [1,2].last(nil) }.should.raise(TypeError)
+ -> { [1,2].last("a") }.should.raise(TypeError)
obj = mock("nonnumeric")
- -> { [1,2].last(obj) }.should raise_error(TypeError)
+ -> { [1,2].last(obj) }.should.raise(TypeError)
end
it "does not return subclass instance on Array subclasses" do
- ArraySpecs::MyArray[].last(0).should be_an_instance_of(Array)
- ArraySpecs::MyArray[].last(2).should be_an_instance_of(Array)
- ArraySpecs::MyArray[1, 2, 3].last(0).should be_an_instance_of(Array)
- ArraySpecs::MyArray[1, 2, 3].last(1).should be_an_instance_of(Array)
- ArraySpecs::MyArray[1, 2, 3].last(2).should be_an_instance_of(Array)
+ ArraySpecs::MyArray[].last(0).should.instance_of?(Array)
+ ArraySpecs::MyArray[].last(2).should.instance_of?(Array)
+ ArraySpecs::MyArray[1, 2, 3].last(0).should.instance_of?(Array)
+ ArraySpecs::MyArray[1, 2, 3].last(1).should.instance_of?(Array)
+ ArraySpecs::MyArray[1, 2, 3].last(2).should.instance_of?(Array)
end
it "is not destructive" do
diff --git a/spec/ruby/core/array/length_spec.rb b/spec/ruby/core/array/length_spec.rb
index a90c001300..e45abb2138 100644
--- a/spec/ruby/core/array/length_spec.rb
+++ b/spec/ruby/core/array/length_spec.rb
@@ -1,7 +1,7 @@
require_relative '../../spec_helper'
-require_relative 'fixtures/classes'
-require_relative 'shared/length'
describe "Array#length" do
- it_behaves_like :array_length, :length
+ it "is an alias of Array#size" do
+ Array.instance_method(:length).should == Array.instance_method(:size)
+ end
end
diff --git a/spec/ruby/core/array/map_spec.rb b/spec/ruby/core/array/map_spec.rb
index 0c7f3afa8c..0cc394663a 100644
--- a/spec/ruby/core/array/map_spec.rb
+++ b/spec/ruby/core/array/map_spec.rb
@@ -1,11 +1,143 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
-require_relative 'shared/collect'
+require_relative '../enumerable/shared/enumeratorized'
+require_relative 'shared/iterable_and_tolerating_size_increasing'
describe "Array#map" do
- it_behaves_like :array_collect, :map
+ it "returns a copy of array with each element replaced by the value returned by block" do
+ a = ['a', 'b', 'c', 'd']
+ b = a.map { |i| i + '!' }
+ b.should == ["a!", "b!", "c!", "d!"]
+ b.should_not.equal? a
+ end
+
+ it "does not return subclass instance" do
+ ArraySpecs::MyArray[1, 2, 3].map { |x| x + 1 }.should.instance_of?(Array)
+ end
+
+ it "does not change self" do
+ a = ['a', 'b', 'c', 'd']
+ a.map { |i| i + '!' }
+ a.should == ['a', 'b', 'c', 'd']
+ end
+
+ it "returns the evaluated value of block if it broke in the block" do
+ a = ['a', 'b', 'c', 'd']
+ b = a.map {|i|
+ if i == 'c'
+ break 0
+ else
+ i + '!'
+ end
+ }
+ b.should == 0
+ end
+
+ it "returns an Enumerator when no block given" do
+ a = [1, 2, 3]
+ a.map.should.instance_of?(Enumerator)
+ end
+
+ it "raises an ArgumentError when no block and with arguments" do
+ a = [1, 2, 3]
+ -> {
+ a.map(:foo)
+ }.should.raise(ArgumentError)
+ end
+
+ before :each do
+ @object = [1, 2, 3, 4]
+ end
+ it_behaves_like :enumeratorized_with_origin_size, :map
+
+ it_behaves_like :array_iterable_and_tolerating_size_increasing, :map
end
describe "Array#map!" do
- it_behaves_like :array_collect_b, :map!
+ it "replaces each element with the value returned by block" do
+ a = [7, 9, 3, 5]
+ a.map! { |i| i - 1 }.should.equal?(a)
+ a.should == [6, 8, 2, 4]
+ end
+
+ it "returns self" do
+ a = [1, 2, 3, 4, 5]
+ b = a.map! {|i| i+1 }
+ a.should.equal? b
+ end
+
+ it "returns the evaluated value of block but its contents is partially modified, if it broke in the block" do
+ a = ['a', 'b', 'c', 'd']
+ b = a.map! {|i|
+ if i == 'c'
+ break 0
+ else
+ i + '!'
+ end
+ }
+ b.should == 0
+ a.should == ['a!', 'b!', 'c', 'd']
+ end
+
+ it "returns an Enumerator when no block given, and the enumerator can modify the original array" do
+ a = [1, 2, 3]
+ enum = a.map!
+ enum.should.instance_of?(Enumerator)
+ enum.each{|i| "#{i}!" }
+ a.should == ["1!", "2!", "3!"]
+ end
+
+ describe "when frozen" do
+ it "raises a FrozenError" do
+ -> { ArraySpecs.frozen_array.map! {} }.should.raise(FrozenError)
+ end
+
+ it "raises a FrozenError when empty" do
+ -> { ArraySpecs.empty_frozen_array.map! {} }.should.raise(FrozenError)
+ end
+
+ it "raises a FrozenError when calling #each on the returned Enumerator" do
+ enumerator = ArraySpecs.frozen_array.map!
+ -> { enumerator.each {|x| x } }.should.raise(FrozenError)
+ end
+
+ it "raises a FrozenError when calling #each on the returned Enumerator when empty" do
+ enumerator = ArraySpecs.empty_frozen_array.map!
+ -> { enumerator.each {|x| x } }.should.raise(FrozenError)
+ end
+ end
+
+ it "does not truncate the array is the block raises an exception" do
+ a = [1, 2, 3]
+ begin
+ a.map! { 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.map! 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 :each do
+ @object = [1, 2, 3, 4]
+ end
+ it_behaves_like :enumeratorized_with_origin_size, :map!
+
+ it_behaves_like :array_iterable_and_tolerating_size_increasing, :map!
end
diff --git a/spec/ruby/core/array/max_spec.rb b/spec/ruby/core/array/max_spec.rb
index d1c64519d0..868275a748 100644
--- a/spec/ruby/core/array/max_spec.rb
+++ b/spec/ruby/core/array/max_spec.rb
@@ -2,7 +2,7 @@ require_relative '../../spec_helper'
describe "Array#max" do
it "is defined on Array" do
- [1].method(:max).owner.should equal Array
+ [1].method(:max).owner.should.equal? Array
end
it "returns nil with no values" do
@@ -70,16 +70,16 @@ describe "Array#max" do
it "raises a NoMethodError for elements without #<=>" do
-> do
[BasicObject.new, BasicObject.new].max
- end.should raise_error(NoMethodError)
+ end.should.raise(NoMethodError)
end
it "raises an ArgumentError for incomparable elements" do
-> do
[11,"22"].max
- end.should raise_error(ArgumentError)
+ end.should.raise(ArgumentError)
-> do
[11,12,22,33].max{|a, b| nil}
- end.should raise_error(ArgumentError)
+ end.should.raise(ArgumentError)
end
it "returns the maximum element (with block)" do
diff --git a/spec/ruby/core/array/min_spec.rb b/spec/ruby/core/array/min_spec.rb
index 3bdef0dd00..5913e08cf8 100644
--- a/spec/ruby/core/array/min_spec.rb
+++ b/spec/ruby/core/array/min_spec.rb
@@ -2,7 +2,7 @@ require_relative '../../spec_helper'
describe "Array#min" do
it "is defined on Array" do
- [1].method(:max).owner.should equal Array
+ [1].method(:max).owner.should.equal? Array
end
it "returns nil with no values" do
@@ -64,22 +64,22 @@ describe "Array#min" do
end
it "returns nil for an empty Enumerable" do
- [].min.should be_nil
+ [].min.should == nil
end
it "raises a NoMethodError for elements without #<=>" do
-> do
[BasicObject.new, BasicObject.new].min
- end.should raise_error(NoMethodError)
+ end.should.raise(NoMethodError)
end
it "raises an ArgumentError for incomparable elements" do
-> do
[11,"22"].min
- end.should raise_error(ArgumentError)
+ end.should.raise(ArgumentError)
-> do
[11,12,22,33].min{|a, b| nil}
- end.should raise_error(ArgumentError)
+ end.should.raise(ArgumentError)
end
it "returns the minimum when using a block rule" do
diff --git a/spec/ruby/core/array/multiply_spec.rb b/spec/ruby/core/array/multiply_spec.rb
index eca51142fb..1ac14e1b09 100644
--- a/spec/ruby/core/array/multiply_spec.rb
+++ b/spec/ruby/core/array/multiply_spec.rb
@@ -17,7 +17,7 @@ describe "Array#*" do
it "raises a TypeError if the argument can neither be converted to a string nor an integer" do
obj = mock('not a string or integer')
- ->{ [1,2] * obj }.should raise_error(TypeError)
+ ->{ [1,2] * obj }.should.raise(TypeError)
end
it "converts the passed argument to a String rather than an Integer" do
@@ -28,15 +28,15 @@ describe "Array#*" do
end
it "raises a TypeError is the passed argument is nil" do
- ->{ [1,2] * nil }.should raise_error(TypeError)
+ ->{ [1,2] * nil }.should.raise(TypeError)
end
it "raises an ArgumentError when passed 2 or more arguments" do
- ->{ [1,2].send(:*, 1, 2) }.should raise_error(ArgumentError)
+ ->{ [1,2].send(:*, 1, 2) }.should.raise(ArgumentError)
end
it "raises an ArgumentError when passed no arguments" do
- ->{ [1,2].send(:*) }.should raise_error(ArgumentError)
+ ->{ [1,2].send(:*) }.should.raise(ArgumentError)
end
end
@@ -50,7 +50,7 @@ describe "Array#* with an integer" do
it "does not return self even if the passed integer is 1" do
ary = [1, 2, 3]
- (ary * 1).should_not equal(ary)
+ (ary * 1).should_not.equal?(ary)
end
it "properly handles recursive arrays" do
@@ -65,8 +65,8 @@ describe "Array#* with an integer" do
end
it "raises an ArgumentError when passed a negative integer" do
- -> { [ 1, 2, 3 ] * -1 }.should raise_error(ArgumentError)
- -> { [] * -1 }.should raise_error(ArgumentError)
+ -> { [ 1, 2, 3 ] * -1 }.should.raise(ArgumentError)
+ -> { [] * -1 }.should.raise(ArgumentError)
end
describe "with a subclass of Array" do
@@ -77,14 +77,14 @@ describe "Array#* with an integer" do
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)
+ (@array * 0).should.instance_of?(Array)
+ (@array * 1).should.instance_of?(Array)
+ (@array * 2).should.instance_of?(Array)
end
it "does not call #initialize on the subclass instance" do
(@array * 2).should == [1, 2, 3, 4, 5, 1, 2, 3, 4, 5]
- ScratchPad.recorded.should be_nil
+ ScratchPad.recorded.should == nil
end
end
end
diff --git a/spec/ruby/core/array/new_spec.rb b/spec/ruby/core/array/new_spec.rb
index b50a4857b0..b2f23e2f6b 100644
--- a/spec/ruby/core/array/new_spec.rb
+++ b/spec/ruby/core/array/new_spec.rb
@@ -3,31 +3,31 @@ require_relative 'fixtures/classes'
describe "Array.new" do
it "returns an instance of Array" do
- Array.new.should be_an_instance_of(Array)
+ Array.new.should.instance_of?(Array)
end
it "returns an instance of a subclass" do
- ArraySpecs::MyArray.new(1, 2).should be_an_instance_of(ArraySpecs::MyArray)
+ ArraySpecs::MyArray.new(1, 2).should.instance_of?(ArraySpecs::MyArray)
end
it "raises an ArgumentError if passed 3 or more arguments" do
-> do
[1, 2].send :initialize, 1, 'x', true
- end.should raise_error(ArgumentError)
+ end.should.raise(ArgumentError)
-> do
[1, 2].send(:initialize, 1, 'x', true) {}
- end.should raise_error(ArgumentError)
+ end.should.raise(ArgumentError)
end
end
describe "Array.new with no arguments" do
it "returns an empty array" do
- Array.new.should be_empty
+ Array.new.should.empty?
end
it "does not use the given block" do
-> {
- -> { Array.new { raise } }.should_not raise_error
+ -> { Array.new { raise } }.should_not.raise
}.should complain(/warning: given block not used/, verbose: true)
end
end
@@ -39,7 +39,7 @@ describe "Array.new with (array)" do
end
it "does not use the given block" do
- ->{ Array.new([1, 2]) { raise } }.should_not raise_error
+ ->{ Array.new([1, 2]) { raise } }.should_not.raise
end
it "calls #to_ary to convert the value to an array" do
@@ -56,7 +56,7 @@ describe "Array.new with (array)" do
end
it "raises a TypeError if an Array type argument and a default object" do
- -> { Array.new([1, 2], 1) }.should raise_error(TypeError)
+ -> { Array.new([1, 2], 1) }.should.raise(TypeError)
end
end
@@ -65,8 +65,8 @@ describe "Array.new with (size, object=nil)" do
obj = [3]
a = Array.new(2, obj)
a.should == [obj, obj]
- a[0].should equal(obj)
- a[1].should equal(obj)
+ a[0].should.equal?(obj)
+ a[1].should.equal?(obj)
Array.new(3, 14).should == [14, 14, 14]
end
@@ -76,12 +76,12 @@ describe "Array.new with (size, object=nil)" do
end
it "raises an ArgumentError if size is negative" do
- -> { Array.new(-1, :a) }.should raise_error(ArgumentError)
- -> { Array.new(-1) }.should raise_error(ArgumentError)
+ -> { Array.new(-1, :a) }.should.raise(ArgumentError)
+ -> { Array.new(-1) }.should.raise(ArgumentError)
end
it "raises an ArgumentError if size is too large" do
- -> { Array.new(fixnum_max+1) }.should raise_error(ArgumentError)
+ -> { Array.new(fixnum_max+1) }.should.raise(ArgumentError)
end
it "calls #to_int to convert the size argument to an Integer when object is given" do
@@ -99,7 +99,7 @@ describe "Array.new with (size, object=nil)" do
it "raises a TypeError if the size argument is not an Integer type" do
obj = mock('nonnumeric')
obj.stub!(:to_ary).and_return([1, 2])
- ->{ Array.new(obj, :a) }.should raise_error(TypeError)
+ ->{ Array.new(obj, :a) }.should.raise(TypeError)
end
it "yields the index of the element and sets the element to the value of the block" do
diff --git a/spec/ruby/core/array/pack/a_spec.rb b/spec/ruby/core/array/pack/a_spec.rb
index 8245cd5470..03bfd8214c 100644
--- a/spec/ruby/core/array/pack/a_spec.rb
+++ b/spec/ruby/core/array/pack/a_spec.rb
@@ -19,8 +19,8 @@ describe "Array#pack with format 'A'" do
end
it "will not implicitly convert a number to a string" do
- -> { [0].pack('A') }.should raise_error(TypeError)
- -> { [0].pack('a') }.should raise_error(TypeError)
+ -> { [0].pack('A') }.should.raise(TypeError)
+ -> { [0].pack('a') }.should.raise(TypeError)
end
it "adds all the bytes to the output when passed the '*' modifier" do
diff --git a/spec/ruby/core/array/pack/b_spec.rb b/spec/ruby/core/array/pack/b_spec.rb
index 247a9ca023..f7576846ef 100644
--- a/spec/ruby/core/array/pack/b_spec.rb
+++ b/spec/ruby/core/array/pack/b_spec.rb
@@ -19,8 +19,8 @@ describe "Array#pack with format 'B'" do
end
it "will not implicitly convert a number to a string" do
- -> { [0].pack('B') }.should raise_error(TypeError)
- -> { [0].pack('b') }.should raise_error(TypeError)
+ -> { [0].pack('B') }.should.raise(TypeError)
+ -> { [0].pack('b') }.should.raise(TypeError)
end
it "encodes one bit for each character starting with the most significant bit" do
diff --git a/spec/ruby/core/array/pack/buffer_spec.rb b/spec/ruby/core/array/pack/buffer_spec.rb
index b77b2d1efa..d104c80186 100644
--- a/spec/ruby/core/array/pack/buffer_spec.rb
+++ b/spec/ruby/core/array/pack/buffer_spec.rb
@@ -7,7 +7,7 @@ describe "Array#pack with :buffer option" do
n = [ 65, 66, 67 ]
buffer = " "*3
result = n.pack("ccc", buffer: buffer) #=> "ABC"
- result.should equal(buffer)
+ result.should.equal?(buffer)
end
it "adds result at the end of buffer content" do
@@ -24,12 +24,12 @@ describe "Array#pack with :buffer option" do
end
it "raises TypeError exception if buffer is not String" do
- -> { [65].pack("ccc", buffer: []) }.should raise_error(
+ -> { [65].pack("ccc", buffer: []) }.should.raise(
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)
+ -> { [65].pack("c", buffer: "frozen-string".freeze) }.should.raise(FrozenError)
end
it "preserves the encoding of the given buffer" do
diff --git a/spec/ruby/core/array/pack/c_spec.rb b/spec/ruby/core/array/pack/c_spec.rb
index 47b71b663d..de06207a23 100644
--- a/spec/ruby/core/array/pack/c_spec.rb
+++ b/spec/ruby/core/array/pack/c_spec.rb
@@ -45,20 +45,10 @@ describe :array_pack_8bit, shared: true do
[1, 2, 3, 4, 5].pack(pack_format('*')).should == "\x01\x02\x03\x04\x05"
end
- 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
- end
- end
-
- ruby_version_is "3.3" do
- it "raise ArgumentError for NULL bytes between directives" do
- -> {
- [1, 2, 3].pack(pack_format("\000", 2))
- }.should raise_error(ArgumentError, /unknown pack directive/)
- end
+ it "raise ArgumentError for NULL bytes between directives" do
+ -> {
+ [1, 2, 3].pack(pack_format("\000", 2))
+ }.should.raise(ArgumentError, /unknown pack directive/)
end
it "ignores spaces between directives" do
diff --git a/spec/ruby/core/array/pack/h_spec.rb b/spec/ruby/core/array/pack/h_spec.rb
index ba188874ba..1492d02b1f 100644
--- a/spec/ruby/core/array/pack/h_spec.rb
+++ b/spec/ruby/core/array/pack/h_spec.rb
@@ -19,8 +19,8 @@ describe "Array#pack with format 'H'" do
end
it "will not implicitly convert a number to a string" do
- -> { [0].pack('H') }.should raise_error(TypeError)
- -> { [0].pack('h') }.should raise_error(TypeError)
+ -> { [0].pack('H') }.should.raise(TypeError)
+ -> { [0].pack('h') }.should.raise(TypeError)
end
it "encodes the first character as the most significant nibble when passed no count modifier" do
diff --git a/spec/ruby/core/array/pack/m_spec.rb b/spec/ruby/core/array/pack/m_spec.rb
index a80f91275c..fb670d120e 100644
--- a/spec/ruby/core/array/pack/m_spec.rb
+++ b/spec/ruby/core/array/pack/m_spec.rb
@@ -155,7 +155,7 @@ describe "Array#pack with format 'M'" do
it "encodes a recursive array" do
empty = ArraySpecs.empty_recursive_array
- empty.pack('M').should be_an_instance_of(String)
+ empty.pack('M').should.instance_of?(String)
array = ArraySpecs.recursive_array
array.pack('M').should == "1=\n"
@@ -172,7 +172,7 @@ describe "Array#pack with format 'M'" do
obj = mock("pack M non-string")
obj.should_receive(:to_s).and_return(2)
- [obj].pack("M").should be_an_instance_of(String)
+ [obj].pack("M").should.instance_of?(String)
end
it "encodes a Symbol as a String" do
@@ -293,16 +293,16 @@ describe "Array#pack with format 'm'" do
it "raises a TypeError if #to_str does not return a String" do
obj = mock("pack m non-string")
- -> { [obj].pack("m") }.should raise_error(TypeError)
+ -> { [obj].pack("m") }.should.raise(TypeError)
end
it "raises a TypeError if passed nil" do
- -> { [nil].pack("m") }.should raise_error(TypeError)
+ -> { [nil].pack("m") }.should.raise(TypeError)
end
it "raises a TypeError if passed an Integer" do
- -> { [0].pack("m") }.should raise_error(TypeError)
- -> { [bignum_value].pack("m") }.should raise_error(TypeError)
+ -> { [0].pack("m") }.should.raise(TypeError)
+ -> { [bignum_value].pack("m") }.should.raise(TypeError)
end
it "does not emit a newline if passed zero as the count modifier" do
diff --git a/spec/ruby/core/array/pack/percent_spec.rb b/spec/ruby/core/array/pack/percent_spec.rb
index 5d56dea5fe..29b119732a 100644
--- a/spec/ruby/core/array/pack/percent_spec.rb
+++ b/spec/ruby/core/array/pack/percent_spec.rb
@@ -2,6 +2,6 @@ require_relative '../../../spec_helper'
describe "Array#pack with format '%'" do
it "raises an Argument Error" do
- -> { [1].pack("%") }.should raise_error(ArgumentError)
+ -> { [1].pack("%") }.should.raise(ArgumentError)
end
end
diff --git a/spec/ruby/core/array/pack/r_spec.rb b/spec/ruby/core/array/pack/r_spec.rb
new file mode 100644
index 0000000000..cefe1388d2
--- /dev/null
+++ b/spec/ruby/core/array/pack/r_spec.rb
@@ -0,0 +1,89 @@
+# encoding: binary
+require_relative '../../../spec_helper'
+require_relative '../fixtures/classes'
+require_relative 'shared/basic'
+require_relative 'shared/numeric_basic'
+require_relative 'shared/integer'
+
+ruby_version_is "4.1" do
+ describe "Array#pack with format 'R'" do
+ it_behaves_like :array_pack_basic, 'R'
+ it_behaves_like :array_pack_basic_non_float, 'R'
+ it_behaves_like :array_pack_arguments, 'R'
+ it_behaves_like :array_pack_numeric_basic, 'R'
+ it_behaves_like :array_pack_integer, 'R'
+
+ it "encodes a ULEB128 integer" do
+ [ [[0], "\x00"],
+ [[1], "\x01"],
+ [[127], "\x7f"],
+ [[128], "\x80\x01"],
+ [[0x3fff], "\xff\x7f"],
+ [[0x4000], "\x80\x80\x01"],
+ [[0xffffffff], "\xff\xff\xff\xff\x0f"],
+ [[0x100000000], "\x80\x80\x80\x80\x10"],
+ [[0xffff_ffff_ffff_ffff], "\xff\xff\xff\xff\xff\xff\xff\xff\xff\x01"],
+ [[0xffff_ffff_ffff_ffff_ffff_ffff], "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x1f"],
+ ].should be_computed_by(:pack, "R")
+ end
+
+ it "encodes multiple values with '*' modifier" do
+ [1, 2].pack("R*").should == "\x01\x02"
+ [127, 128].pack("R*").should == "\x7f\x80\x01"
+ end
+
+ it "raises an ArgumentError when passed a negative value" do
+ -> { [-1].pack("R") }.should.raise(ArgumentError)
+ -> { [-100].pack("R") }.should.raise(ArgumentError)
+ end
+
+ it "round-trips values through pack and unpack" do
+ values = [0, 1, 127, 128, 0x3fff, 0x4000, 0xffffffff, 0x100000000]
+ values.pack("R*").unpack("R*").should == values
+ end
+ end
+
+ describe "Array#pack with format 'r'" do
+ it_behaves_like :array_pack_basic, 'r'
+ it_behaves_like :array_pack_basic_non_float, 'r'
+ it_behaves_like :array_pack_arguments, 'r'
+ it_behaves_like :array_pack_numeric_basic, 'r'
+ it_behaves_like :array_pack_integer, 'r'
+
+ it "encodes a SLEB128 integer" do
+ [ [[0], "\x00"],
+ [[1], "\x01"],
+ [[-1], "\x7f"],
+ [[-2], "\x7e"],
+ [[127], "\xff\x00"],
+ [[128], "\x80\x01"],
+ [[-127], "\x81\x7f"],
+ [[-128], "\x80\x7f"],
+ ].should be_computed_by(:pack, "r")
+ end
+
+ it "encodes larger positive numbers" do
+ [0x3fff].pack("r").should == "\xff\xff\x00"
+ [0x4000].pack("r").should == "\x80\x80\x01"
+ end
+
+ it "encodes larger negative numbers" do
+ [-0x3fff].pack("r").should == "\x81\x80\x7f"
+ [-0x4000].pack("r").should == "\x80\x80\x7f"
+ end
+
+ it "encodes very large numbers" do
+ [0xffff_ffff_ffff_ffff_ffff_ffff].pack("r").should == "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x1F"
+ [-0xffff_ffff_ffff_ffff_ffff_ffff].pack("r").should == "\x81\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x60"
+ end
+
+ it "encodes multiple values with '*' modifier" do
+ [0, 1, -1].pack("r*").should == "\x00\x01\x7f"
+ end
+
+ it "round-trips values through pack and unpack" do
+ values = [0, 1, -1, 127, -127, 128, -128, 0x3fff, -0x3fff, 0x4000, -0x4000]
+ values.pack("r*").unpack("r*").should == values
+ end
+ end
+end
diff --git a/spec/ruby/core/array/pack/shared/basic.rb b/spec/ruby/core/array/pack/shared/basic.rb
index ebd9f75d9d..2894369c71 100644
--- a/spec/ruby/core/array/pack/shared/basic.rb
+++ b/spec/ruby/core/array/pack/shared/basic.rb
@@ -1,6 +1,6 @@
describe :array_pack_arguments, shared: true do
it "raises an ArgumentError if there are fewer elements than the format requires" do
- -> { [].pack(pack_format(1)) }.should raise_error(ArgumentError)
+ -> { [].pack(pack_format(1)) }.should.raise(ArgumentError)
end
end
@@ -10,11 +10,11 @@ describe :array_pack_basic, shared: true do
end
it "raises a TypeError when passed nil" do
- -> { [@obj].pack(nil) }.should raise_error(TypeError)
+ -> { [@obj].pack(nil) }.should.raise(TypeError)
end
it "raises a TypeError when passed an Integer" do
- -> { [@obj].pack(1) }.should raise_error(TypeError)
+ -> { [@obj].pack(1) }.should.raise(TypeError)
end
end
@@ -24,65 +24,50 @@ describe :array_pack_basic_non_float, shared: true do
end
it "ignores whitespace in the format string" do
- [@obj, @obj].pack("a \t\n\v\f\r"+pack_format).should be_an_instance_of(String)
+ [@obj, @obj].pack("a \t\n\v\f\r"+pack_format).should.instance_of?(String)
end
it "ignores comments in the format string" 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)
+ [@obj, @obj, @obj, @obj].pack("aa #{pack_format} # some comment \n#{pack_format}").should.instance_of?(String)
end
- ruby_version_is ""..."3.3" do
- # https://bugs.ruby-lang.org/issues/19150
- # NOTE: it's just a plan of the Ruby core team
- it "warns that a directive is unknown" do
- # additional directive ('a') is required for the X directive
- -> { [@obj, @obj].pack("a R" + pack_format) }.should complain(/unknown pack directive 'R'/)
- -> { [@obj, @obj].pack("a 0" + pack_format) }.should complain(/unknown pack directive '0'/)
- -> { [@obj, @obj].pack("a :" + pack_format) }.should complain(/unknown pack directive ':'/)
- end
- end
-
- ruby_version_is "3.3" do
- # https://bugs.ruby-lang.org/issues/19150
- # NOTE: Added this case just to not forget about the decision in the ticket
- it "raise ArgumentError when a directive is unknown" do
- # additional directive ('a') is required for the X directive
- -> { [@obj, @obj].pack("a R" + pack_format) }.should raise_error(ArgumentError, /unknown pack directive 'R'/)
- -> { [@obj, @obj].pack("a 0" + pack_format) }.should raise_error(ArgumentError, /unknown pack directive '0'/)
- -> { [@obj, @obj].pack("a :" + pack_format) }.should raise_error(ArgumentError, /unknown pack directive ':'/)
- end
+ it "raise ArgumentError when a directive is unknown" do
+ # additional directive ('a') is required for the X directive
+ -> { [@obj, @obj].pack("a K" + pack_format) }.should.raise(ArgumentError, /unknown pack directive 'K'/)
+ -> { [@obj, @obj].pack("a 0" + pack_format) }.should.raise(ArgumentError, /unknown pack directive '0'/)
+ -> { [@obj, @obj].pack("a :" + pack_format) }.should.raise(ArgumentError, /unknown pack directive ':'/)
end
it "calls #to_str to coerce the directives string" do
d = mock("pack directive")
d.should_receive(:to_str).and_return("x"+pack_format)
- [@obj, @obj].pack(d).should be_an_instance_of(String)
+ [@obj, @obj].pack(d).should.instance_of?(String)
end
end
describe :array_pack_basic_float, shared: true do
it "ignores whitespace in the format string" do
- [9.3, 4.7].pack(" \t\n\v\f\r"+pack_format).should be_an_instance_of(String)
+ [9.3, 4.7].pack(" \t\n\v\f\r"+pack_format).should.instance_of?(String)
end
it "ignores comments in the format string" do
- [9.3, 4.7].pack(pack_format + "# some comment \n" + pack_format).should be_an_instance_of(String)
+ [9.3, 4.7].pack(pack_format + "# some comment \n" + pack_format).should.instance_of?(String)
end
it "calls #to_str to coerce the directives string" do
d = mock("pack directive")
d.should_receive(:to_str).and_return("x"+pack_format)
- [1.2, 4.7].pack(d).should be_an_instance_of(String)
+ [1.2, 4.7].pack(d).should.instance_of?(String)
end
end
describe :array_pack_no_platform, shared: true do
it "raises ArgumentError when the format modifier is '_'" do
- ->{ [1].pack(pack_format("_")) }.should raise_error(ArgumentError)
+ ->{ [1].pack(pack_format("_")) }.should.raise(ArgumentError)
end
it "raises ArgumentError when the format modifier is '!'" do
- ->{ [1].pack(pack_format("!")) }.should raise_error(ArgumentError)
+ ->{ [1].pack(pack_format("!")) }.should.raise(ArgumentError)
end
end
diff --git a/spec/ruby/core/array/pack/shared/encodings.rb b/spec/ruby/core/array/pack/shared/encodings.rb
index 6b7ffac764..0b5a5cc8a0 100644
--- a/spec/ruby/core/array/pack/shared/encodings.rb
+++ b/spec/ruby/core/array/pack/shared/encodings.rb
@@ -5,12 +5,12 @@ describe :array_pack_hex, shared: true do
it "raises a TypeError if the object does not respond to #to_str" do
obj = mock("pack hex non-string")
- -> { [obj].pack(pack_format) }.should raise_error(TypeError)
+ -> { [obj].pack(pack_format) }.should.raise(TypeError)
end
it "raises a TypeError if #to_str does not return a String" do
obj = mock("pack hex non-string")
obj.should_receive(:to_str).and_return(1)
- -> { [obj].pack(pack_format) }.should raise_error(TypeError)
+ -> { [obj].pack(pack_format) }.should.raise(TypeError)
end
end
diff --git a/spec/ruby/core/array/pack/shared/float.rb b/spec/ruby/core/array/pack/shared/float.rb
index 76c800b74d..c1efcd7677 100644
--- a/spec/ruby/core/array/pack/shared/float.rb
+++ b/spec/ruby/core/array/pack/shared/float.rb
@@ -14,7 +14,7 @@ describe :array_pack_float_le, shared: true do
end
it "raises a TypeError if passed a String representation of a floating point number" do
- -> { ["13"].pack(pack_format) }.should raise_error(TypeError)
+ -> { ["13"].pack(pack_format) }.should.raise(TypeError)
end
it "encodes the number of array elements specified by the count modifier" do
@@ -25,20 +25,10 @@ describe :array_pack_float_le, shared: true do
[2.9, 1.4, 8.2].pack(pack_format("*")).should == "\x9a\x999@33\xb3?33\x03A"
end
- 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
- end
- end
-
- ruby_version_is "3.3" do
- it "raise ArgumentError for NULL bytes between directives" do
- -> {
- [5.3, 9.2].pack(pack_format("\000", 2))
- }.should raise_error(ArgumentError, /unknown pack directive/)
- end
+ it "raise ArgumentError for NULL bytes between directives" do
+ -> {
+ [5.3, 9.2].pack(pack_format("\000", 2))
+ }.should.raise(ArgumentError, /unknown pack directive/)
end
it "ignores spaces between directives" do
@@ -55,7 +45,7 @@ describe :array_pack_float_le, shared: true do
it "encodes NaN" do
nans = ["\x00\x00\xc0\xff", "\x00\x00\xc0\x7f", "\xFF\xFF\xFF\x7F"]
- nans.should include([nan_value].pack(pack_format))
+ nans.should.include?([nan_value].pack(pack_format))
end
it "encodes a positive Float outside the range of a single precision float" do
@@ -94,7 +84,7 @@ describe :array_pack_float_be, shared: true do
end
it "raises a TypeError if passed a String representation of a floating point number" do
- -> { ["13"].pack(pack_format) }.should raise_error(TypeError)
+ -> { ["13"].pack(pack_format) }.should.raise(TypeError)
end
it "encodes the number of array elements specified by the count modifier" do
@@ -105,20 +95,10 @@ describe :array_pack_float_be, shared: true do
[2.9, 1.4, 8.2].pack(pack_format("*")).should == "@9\x99\x9a?\xb333A\x0333"
end
- 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
- end
- end
-
- ruby_version_is "3.3" do
- it "raise ArgumentError for NULL bytes between directives" do
- -> {
- [5.3, 9.2].pack(pack_format("\000", 2))
- }.should raise_error(ArgumentError, /unknown pack directive/)
- end
+ it "raise ArgumentError for NULL bytes between directives" do
+ -> {
+ [5.3, 9.2].pack(pack_format("\000", 2))
+ }.should.raise(ArgumentError, /unknown pack directive/)
end
it "ignores spaces between directives" do
@@ -135,7 +115,7 @@ describe :array_pack_float_be, shared: true do
it "encodes NaN" do
nans = ["\xff\xc0\x00\x00", "\x7f\xc0\x00\x00", "\x7F\xFF\xFF\xFF"]
- nans.should include([nan_value].pack(pack_format))
+ nans.should.include?([nan_value].pack(pack_format))
end
it "encodes a positive Float outside the range of a single precision float" do
@@ -166,7 +146,7 @@ describe :array_pack_double_le, shared: true do
end
it "raises a TypeError if passed a String representation of a floating point number" do
- -> { ["13"].pack(pack_format) }.should raise_error(TypeError)
+ -> { ["13"].pack(pack_format) }.should.raise(TypeError)
end
it "encodes the number of array elements specified by the count modifier" do
@@ -177,20 +157,10 @@ describe :array_pack_double_le, shared: true do
[2.9, 1.4, 8.2].pack(pack_format("*")).should == "333333\x07@ffffff\xf6?ffffff\x20@"
end
- 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
- end
- end
-
- ruby_version_is "3.3" do
- it "raise ArgumentError for NULL bytes between directives" do
- -> {
- [5.3, 9.2].pack(pack_format("\000", 2))
- }.should raise_error(ArgumentError, /unknown pack directive/)
- end
+ it "raise ArgumentError for NULL bytes between directives" do
+ -> {
+ [5.3, 9.2].pack(pack_format("\000", 2))
+ }.should.raise(ArgumentError, /unknown pack directive/)
end
it "ignores spaces between directives" do
@@ -211,7 +181,7 @@ describe :array_pack_double_le, shared: true do
"\x00\x00\x00\x00\x00\x00\xf8\x7f",
"\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x7F"
]
- nans.should include([nan_value].pack(pack_format))
+ nans.should.include?([nan_value].pack(pack_format))
end
it "encodes a positive Float outside the range of a single precision float" do
@@ -237,7 +207,7 @@ describe :array_pack_double_be, shared: true do
end
it "raises a TypeError if passed a String representation of a floating point number" do
- -> { ["13"].pack(pack_format) }.should raise_error(TypeError)
+ -> { ["13"].pack(pack_format) }.should.raise(TypeError)
end
it "encodes the number of array elements specified by the count modifier" do
@@ -248,20 +218,10 @@ describe :array_pack_double_be, shared: true do
[2.9, 1.4, 8.2].pack(pack_format("*")).should == "@\x07333333?\xf6ffffff@\x20ffffff"
end
- 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
- end
- end
-
- ruby_version_is "3.3" do
- it "raise ArgumentError for NULL bytes between directives" do
- -> {
- [5.3, 9.2].pack(pack_format("\000", 2))
- }.should raise_error(ArgumentError, /unknown pack directive/)
- end
+ it "raise ArgumentError for NULL bytes between directives" do
+ -> {
+ [5.3, 9.2].pack(pack_format("\000", 2))
+ }.should.raise(ArgumentError, /unknown pack directive/)
end
it "ignores spaces between directives" do
@@ -282,7 +242,7 @@ describe :array_pack_double_be, shared: true do
"\x7f\xf8\x00\x00\x00\x00\x00\x00",
"\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
]
- nans.should include([nan_value].pack(pack_format))
+ nans.should.include?([nan_value].pack(pack_format))
end
it "encodes a positive Float outside the range of a single precision float" do
diff --git a/spec/ruby/core/array/pack/shared/integer.rb b/spec/ruby/core/array/pack/shared/integer.rb
index 61f7cca184..1cdd386cc1 100644
--- a/spec/ruby/core/array/pack/shared/integer.rb
+++ b/spec/ruby/core/array/pack/shared/integer.rb
@@ -41,21 +41,10 @@ describe :array_pack_16bit_le, shared: true do
str.should == "\x78\x65\xcd\xab\x21\x43"
end
- 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
- end
- end
-
- ruby_version_is "3.3" do
- it "raise ArgumentError for NULL bytes between directives" do
- -> {
- [0x1243_6578, 0xdef0_abcd].pack(pack_format("\000", 2))
- }.should raise_error(ArgumentError, /unknown pack directive/)
- end
+ it "raise ArgumentError for NULL bytes between directives" do
+ -> {
+ [0x1243_6578, 0xdef0_abcd].pack(pack_format("\000", 2))
+ }.should.raise(ArgumentError, /unknown pack directive/)
end
it "ignores spaces between directives" do
@@ -105,21 +94,10 @@ describe :array_pack_16bit_be, shared: true do
str.should == "\x65\x78\xab\xcd\x43\x21"
end
- 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
- end
- end
-
- ruby_version_is "3.3" do
- it "raise ArgumentError for NULL bytes between directives" do
- -> {
- [0x1243_6578, 0xdef0_abcd].pack(pack_format("\000", 2))
- }.should raise_error(ArgumentError, /unknown pack directive/)
- end
+ it "raise ArgumentError for NULL bytes between directives" do
+ -> {
+ [0x1243_6578, 0xdef0_abcd].pack(pack_format("\000", 2))
+ }.should.raise(ArgumentError, /unknown pack directive/)
end
it "ignores spaces between directives" do
@@ -169,21 +147,10 @@ describe :array_pack_32bit_le, shared: true do
str.should == "\x78\x65\x43\x12\xcd\xab\xf0\xde\x21\x43\x65\x78"
end
- 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
- end
- end
-
- ruby_version_is "3.3" do
- it "raise ArgumentError for NULL bytes between directives" do
- -> {
- [0x1243_6578, 0xdef0_abcd].pack(pack_format("\000", 2))
- }.should raise_error(ArgumentError, /unknown pack directive/)
- end
+ it "raise ArgumentError for NULL bytes between directives" do
+ -> {
+ [0x1243_6578, 0xdef0_abcd].pack(pack_format("\000", 2))
+ }.should.raise(ArgumentError, /unknown pack directive/)
end
it "ignores spaces between directives" do
@@ -233,21 +200,10 @@ describe :array_pack_32bit_be, shared: true do
str.should == "\x12\x43\x65\x78\xde\xf0\xab\xcd\x78\x65\x43\x21"
end
- 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
- end
- end
-
- ruby_version_is "3.3" do
- it "raise ArgumentError for NULL bytes between directives" do
- -> {
- [0x1243_6578, 0xdef0_abcd].pack(pack_format("\000", 2))
- }.should raise_error(ArgumentError, /unknown pack directive/)
- end
+ it "raise ArgumentError for NULL bytes between directives" do
+ -> {
+ [0x1243_6578, 0xdef0_abcd].pack(pack_format("\000", 2))
+ }.should.raise(ArgumentError, /unknown pack directive/)
end
it "ignores spaces between directives" do
@@ -357,21 +313,10 @@ describe :array_pack_64bit_le, shared: true do
str.should == "\x56\x78\x12\x34\xcd\xab\xf0\xde\xf0\xde\xba\xdc\x21\x43\x65\x78"
end
- 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
- end
- end
-
- ruby_version_is "3.3" do
- it "raise ArgumentError for NULL bytes between directives" do
- -> {
- [0xdef0_abcd_3412_7856, 0x7865_4321_dcba_def0].pack(pack_format("\000", 2))
- }.should raise_error(ArgumentError, /unknown pack directive/)
- end
+ it "raise ArgumentError for NULL bytes between directives" do
+ -> {
+ [0xdef0_abcd_3412_7856, 0x7865_4321_dcba_def0].pack(pack_format("\000", 2))
+ }.should.raise(ArgumentError, /unknown pack directive/)
end
it "ignores spaces between directives" do
@@ -429,21 +374,10 @@ describe :array_pack_64bit_be, shared: true do
str.should == "\xde\xf0\xab\xcd\x34\x12\x78\x56\x78\x65\x43\x21\xdc\xba\xde\xf0"
end
- 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
- end
- end
-
- ruby_version_is "3.3" do
- it "raise ArgumentError for NULL bytes between directives" do
- -> {
- [0xdef0_abcd_3412_7856, 0x7865_4321_dcba_def0].pack(pack_format("\000", 2))
- }.should raise_error(ArgumentError, /unknown pack directive/)
- end
+ it "raise ArgumentError for NULL bytes between directives" do
+ -> {
+ [0xdef0_abcd_3412_7856, 0x7865_4321_dcba_def0].pack(pack_format("\000", 2))
+ }.should.raise(ArgumentError, /unknown pack directive/)
end
it "ignores spaces between directives" do
diff --git a/spec/ruby/core/array/pack/shared/numeric_basic.rb b/spec/ruby/core/array/pack/shared/numeric_basic.rb
index 545e215e64..6594914933 100644
--- a/spec/ruby/core/array/pack/shared/numeric_basic.rb
+++ b/spec/ruby/core/array/pack/shared/numeric_basic.rb
@@ -4,15 +4,15 @@ describe :array_pack_numeric_basic, shared: true do
end
it "raises a TypeError when passed nil" do
- -> { [nil].pack(pack_format) }.should raise_error(TypeError)
+ -> { [nil].pack(pack_format) }.should.raise(TypeError)
end
it "raises a TypeError when passed true" do
- -> { [true].pack(pack_format) }.should raise_error(TypeError)
+ -> { [true].pack(pack_format) }.should.raise(TypeError)
end
it "raises a TypeError when passed false" do
- -> { [false].pack(pack_format) }.should raise_error(TypeError)
+ -> { [false].pack(pack_format) }.should.raise(TypeError)
end
it "returns a binary string" do
@@ -24,27 +24,27 @@ end
describe :array_pack_integer, shared: true do
it "raises a TypeError when the object does not respond to #to_int" do
obj = mock('not an integer')
- -> { [obj].pack(pack_format) }.should raise_error(TypeError)
+ -> { [obj].pack(pack_format) }.should.raise(TypeError)
end
it "raises a TypeError when passed a String" do
- -> { ["5"].pack(pack_format) }.should raise_error(TypeError)
+ -> { ["5"].pack(pack_format) }.should.raise(TypeError)
end
end
describe :array_pack_float, shared: true do
it "raises a TypeError if a String does not represent a floating point number" do
- -> { ["a"].pack(pack_format) }.should raise_error(TypeError)
+ -> { ["a"].pack(pack_format) }.should.raise(TypeError)
end
it "raises a TypeError when the object is not Numeric" do
obj = Object.new
- -> { [obj].pack(pack_format) }.should raise_error(TypeError, /can't convert Object into Float/)
+ -> { [obj].pack(pack_format) }.should.raise(TypeError, /can't convert Object into Float/)
end
it "raises a TypeError when the Numeric object does not respond to #to_f" do
klass = Class.new(Numeric)
obj = klass.new
- -> { [obj].pack(pack_format) }.should raise_error(TypeError)
+ -> { [obj].pack(pack_format) }.should.raise(TypeError)
end
end
diff --git a/spec/ruby/core/array/pack/shared/string.rb b/spec/ruby/core/array/pack/shared/string.rb
index 805f78b53b..b02257059f 100644
--- a/spec/ruby/core/array/pack/shared/string.rb
+++ b/spec/ruby/core/array/pack/shared/string.rb
@@ -17,11 +17,11 @@ describe :array_pack_string, shared: true do
end
it "raises an ArgumentError when the Array is empty" do
- -> { [].pack(pack_format) }.should raise_error(ArgumentError)
+ -> { [].pack(pack_format) }.should.raise(ArgumentError)
end
it "raises an ArgumentError when the Array has too few elements" do
- -> { ["a"].pack(pack_format(nil, 2)) }.should raise_error(ArgumentError)
+ -> { ["a"].pack(pack_format(nil, 2)) }.should.raise(ArgumentError)
end
it "calls #to_str to convert the element to a String" do
@@ -33,7 +33,7 @@ describe :array_pack_string, shared: true do
it "raises a TypeError when the object does not respond to #to_str" do
obj = mock("not a string")
- -> { [obj].pack(pack_format) }.should raise_error(TypeError)
+ -> { [obj].pack(pack_format) }.should.raise(TypeError)
end
it "returns a string in encoding of common to the concatenated results" do
diff --git a/spec/ruby/core/array/pack/shared/unicode.rb b/spec/ruby/core/array/pack/shared/unicode.rb
index 4d8eaef323..58ba8a8b23 100644
--- a/spec/ruby/core/array/pack/shared/unicode.rb
+++ b/spec/ruby/core/array/pack/shared/unicode.rb
@@ -26,7 +26,7 @@ describe :array_pack_unicode, shared: true do
it "constructs strings with valid encodings" do
str = [0x85].pack("U*")
str.should == "\xc2\x85"
- str.valid_encoding?.should be_true
+ str.valid_encoding?.should == true
end
it "encodes values larger than UTF-8 max codepoints" do
@@ -64,23 +64,13 @@ describe :array_pack_unicode, shared: true do
it "raises a TypeError if #to_int does not return an Integer" do
obj = mock('to_int')
obj.should_receive(:to_int).and_return("5")
- -> { [obj].pack("U") }.should raise_error(TypeError)
+ -> { [obj].pack("U") }.should.raise(TypeError)
end
- 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
- end
- end
-
- ruby_version_is "3.3" do
- it "raise ArgumentError for NULL bytes between directives" do
- -> {
- [1, 2, 3].pack("U\x00U")
- }.should raise_error(ArgumentError, /unknown pack directive/)
- end
+ it "raise ArgumentError for NULL bytes between directives" do
+ -> {
+ [1, 2, 3].pack("U\x00U")
+ }.should.raise(ArgumentError, /unknown pack directive/)
end
it "ignores spaces between directives" do
@@ -88,11 +78,11 @@ describe :array_pack_unicode, shared: true do
end
it "raises a RangeError if passed a negative number" do
- -> { [-1].pack("U") }.should raise_error(RangeError)
+ -> { [-1].pack("U") }.should.raise(RangeError)
end
it "raises a RangeError if passed a number larger than an unsigned 32-bit integer" do
- -> { [2**32].pack("U") }.should raise_error(RangeError)
+ -> { [2**32].pack("U") }.should.raise(RangeError)
end
it "sets the output string to UTF-8 encoding" do
diff --git a/spec/ruby/core/array/pack/u_spec.rb b/spec/ruby/core/array/pack/u_spec.rb
index 1f84095ac4..c6a0d77eb2 100644
--- a/spec/ruby/core/array/pack/u_spec.rb
+++ b/spec/ruby/core/array/pack/u_spec.rb
@@ -25,7 +25,7 @@ describe "Array#pack with format 'u'" do
end
it "will not implicitly convert a number to a string" do
- -> { [0].pack('u') }.should raise_error(TypeError)
+ -> { [0].pack('u') }.should.raise(TypeError)
end
it "encodes an empty string as an empty string" do
@@ -122,16 +122,16 @@ describe "Array#pack with format 'u'" do
it "raises a TypeError if #to_str does not return a String" do
obj = mock("pack m non-string")
- -> { [obj].pack("u") }.should raise_error(TypeError)
+ -> { [obj].pack("u") }.should.raise(TypeError)
end
it "raises a TypeError if passed nil" do
- -> { [nil].pack("u") }.should raise_error(TypeError)
+ -> { [nil].pack("u") }.should.raise(TypeError)
end
it "raises a TypeError if passed an Integer" do
- -> { [0].pack("u") }.should raise_error(TypeError)
- -> { [bignum_value].pack("u") }.should raise_error(TypeError)
+ -> { [0].pack("u") }.should.raise(TypeError)
+ -> { [bignum_value].pack("u") }.should.raise(TypeError)
end
it "sets the output string to US-ASCII encoding" do
diff --git a/spec/ruby/core/array/pack/w_spec.rb b/spec/ruby/core/array/pack/w_spec.rb
index e770288d67..263e2a2288 100644
--- a/spec/ruby/core/array/pack/w_spec.rb
+++ b/spec/ruby/core/array/pack/w_spec.rb
@@ -24,20 +24,10 @@ describe "Array#pack with format 'w'" do
[obj].pack("w").should == "\x05"
end
- 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
- end
- end
-
- ruby_version_is "3.3" do
- it "raise ArgumentError for NULL bytes between directives" do
- -> {
- [1, 2, 3].pack("w\x00w")
- }.should raise_error(ArgumentError, /unknown pack directive/)
- end
+ it "raise ArgumentError for NULL bytes between directives" do
+ -> {
+ [1, 2, 3].pack("w\x00w")
+ }.should.raise(ArgumentError, /unknown pack directive/)
end
it "ignores spaces between directives" do
@@ -45,7 +35,7 @@ describe "Array#pack with format 'w'" do
end
it "raises an ArgumentError when passed a negative value" do
- -> { [-1].pack("w") }.should raise_error(ArgumentError)
+ -> { [-1].pack("w") }.should.raise(ArgumentError)
end
it "returns a binary string" do
diff --git a/spec/ruby/core/array/pack/x_spec.rb b/spec/ruby/core/array/pack/x_spec.rb
index 012fe4567f..7ff587a01e 100644
--- a/spec/ruby/core/array/pack/x_spec.rb
+++ b/spec/ruby/core/array/pack/x_spec.rb
@@ -56,10 +56,10 @@ describe "Array#pack with format 'X'" do
end
it "raises an ArgumentError if the output string is empty" do
- -> { [1, 2, 3].pack("XC") }.should raise_error(ArgumentError)
+ -> { [1, 2, 3].pack("XC") }.should.raise(ArgumentError)
end
it "raises an ArgumentError if the count modifier is greater than the bytes in the string" do
- -> { [1, 2, 3].pack("C2X3") }.should raise_error(ArgumentError)
+ -> { [1, 2, 3].pack("C2X3") }.should.raise(ArgumentError)
end
end
diff --git a/spec/ruby/core/array/pack/z_spec.rb b/spec/ruby/core/array/pack/z_spec.rb
index 60f8f7bf10..5cd084c825 100644
--- a/spec/ruby/core/array/pack/z_spec.rb
+++ b/spec/ruby/core/array/pack/z_spec.rb
@@ -19,7 +19,7 @@ describe "Array#pack with format 'Z'" do
end
it "will not implicitly convert a number to a string" do
- -> { [0].pack('Z') }.should raise_error(TypeError)
+ -> { [0].pack('Z') }.should.raise(TypeError)
end
it "adds all the bytes and appends a NULL byte when passed the '*' modifier" do
diff --git a/spec/ruby/core/array/partition_spec.rb b/spec/ruby/core/array/partition_spec.rb
index be36fffcab..bd3f3a6b6f 100644
--- a/spec/ruby/core/array/partition_spec.rb
+++ b/spec/ruby/core/array/partition_spec.rb
@@ -36,8 +36,8 @@ describe "Array#partition" do
it "does not return subclass instances on Array subclasses" do
result = ArraySpecs::MyArray[1, 2, 3].partition { |x| x % 2 == 0 }
- result.should be_an_instance_of(Array)
- result[0].should be_an_instance_of(Array)
- result[1].should be_an_instance_of(Array)
+ result.should.instance_of?(Array)
+ result[0].should.instance_of?(Array)
+ result[1].should.instance_of?(Array)
end
end
diff --git a/spec/ruby/core/array/permutation_spec.rb b/spec/ruby/core/array/permutation_spec.rb
index f15bd76639..b5df84b52b 100644
--- a/spec/ruby/core/array/permutation_spec.rb
+++ b/spec/ruby/core/array/permutation_spec.rb
@@ -11,7 +11,7 @@ describe "Array#permutation" do
it "returns an Enumerator of all permutations when called without a block or arguments" do
enum = @numbers.permutation
- enum.should be_an_instance_of(Enumerator)
+ enum.should.instance_of?(Enumerator)
enum.to_a.sort.should == [
[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]
].sort
@@ -19,13 +19,13 @@ describe "Array#permutation" do
it "returns an Enumerator of permutations of given length when called with an argument but no block" do
enum = @numbers.permutation(1)
- enum.should be_an_instance_of(Enumerator)
+ enum.should.instance_of?(Enumerator)
enum.to_a.sort.should == [[1],[2],[3]]
end
it "yields all permutations to the block then returns self when called with block but no arguments" do
array = @numbers.permutation {|n| @yielded << n}
- array.should be_an_instance_of(Array)
+ array.should.instance_of?(Array)
array.sort.should == @numbers.sort
@yielded.sort.should == [
[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]
@@ -34,7 +34,7 @@ describe "Array#permutation" do
it "yields all permutations of given length to the block then returns self when called with block and argument" do
array = @numbers.permutation(2) {|n| @yielded << n}
- array.should be_an_instance_of(Array)
+ array.should.instance_of?(Array)
array.sort.should == @numbers.sort
@yielded.sort.should == [[1,2],[1,3],[2,1],[2,3],[3,1],[3,2]].sort
end
@@ -78,7 +78,7 @@ describe "Array#permutation" do
[3, 1], [3, 2], [3, [4, 5]],
[[4, 5], 1], [[4, 5], 2], [[4, 5], 3]
]
- expected.each {|e| got.include?(e).should be_true}
+ expected.each {|e| got.include?(e).should == true}
got.size.should == expected.size
end
diff --git a/spec/ruby/core/array/plus_spec.rb b/spec/ruby/core/array/plus_spec.rb
index b7153fd3ef..7ead927fc0 100644
--- a/spec/ruby/core/array/plus_spec.rb
+++ b/spec/ruby/core/array/plus_spec.rb
@@ -22,14 +22,14 @@ describe "Array#+" do
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)
+ -> { [1, 2, 3] + nil }.should.raise(TypeError)
+ -> { [1, 2, 3] + "abc" }.should.raise(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)
+ -> { [1, 2, 3] + obj }.should.raise(NoMethodError)
end
end
@@ -45,9 +45,9 @@ describe "Array#+" do
end
it "does return subclass instances with Array subclasses" do
- (ArraySpecs::MyArray[1, 2, 3] + []).should be_an_instance_of(Array)
- (ArraySpecs::MyArray[1, 2, 3] + ArraySpecs::MyArray[]).should be_an_instance_of(Array)
- ([1, 2, 3] + ArraySpecs::MyArray[]).should be_an_instance_of(Array)
+ (ArraySpecs::MyArray[1, 2, 3] + []).should.instance_of?(Array)
+ (ArraySpecs::MyArray[1, 2, 3] + ArraySpecs::MyArray[]).should.instance_of?(Array)
+ ([1, 2, 3] + ArraySpecs::MyArray[]).should.instance_of?(Array)
end
it "does not call to_ary on array subclasses" do
diff --git a/spec/ruby/core/array/pop_spec.rb b/spec/ruby/core/array/pop_spec.rb
index 2a19408660..069083331c 100644
--- a/spec/ruby/core/array/pop_spec.rb
+++ b/spec/ruby/core/array/pop_spec.rb
@@ -31,11 +31,11 @@ describe "Array#pop" do
end
it "raises a FrozenError on a frozen array" do
- -> { ArraySpecs.frozen_array.pop }.should raise_error(FrozenError)
+ -> { ArraySpecs.frozen_array.pop }.should.raise(FrozenError)
end
it "raises a FrozenError on an empty frozen array" do
- -> { ArraySpecs.empty_frozen_array.pop }.should raise_error(FrozenError)
+ -> { ArraySpecs.empty_frozen_array.pop }.should.raise(FrozenError)
end
describe "passed a number n as an argument" do
@@ -71,7 +71,7 @@ describe "Array#pop" do
popped2.should == []
a.should == []
- popped1.should_not equal(popped2)
+ popped1.should_not.equal?(popped2)
end
it "returns whole elements if n exceeds size of the array" do
@@ -82,14 +82,14 @@ describe "Array#pop" do
it "does not return self even when it returns whole elements" do
a = [1, 2, 3, 4, 5]
- a.pop(5).should_not equal(a)
+ a.pop(5).should_not.equal?(a)
a = [1, 2, 3, 4, 5]
- a.pop(6).should_not equal(a)
+ a.pop(6).should_not.equal?(a)
end
it "raises an ArgumentError if n is negative" do
- ->{ [1, 2, 3].pop(-1) }.should raise_error(ArgumentError)
+ ->{ [1, 2, 3].pop(-1) }.should.raise(ArgumentError)
end
it "tries to convert n to an Integer using #to_int" do
@@ -104,21 +104,21 @@ describe "Array#pop" do
end
it "raises a TypeError when the passed n cannot be coerced to Integer" do
- ->{ [1, 2].pop("cat") }.should raise_error(TypeError)
- ->{ [1, 2].pop(nil) }.should raise_error(TypeError)
+ ->{ [1, 2].pop("cat") }.should.raise(TypeError)
+ ->{ [1, 2].pop(nil) }.should.raise(TypeError)
end
it "raises an ArgumentError if more arguments are passed" do
- ->{ [1, 2].pop(1, 2) }.should raise_error(ArgumentError)
+ ->{ [1, 2].pop(1, 2) }.should.raise(ArgumentError)
end
it "does not return subclass instances with Array subclass" do
- ArraySpecs::MyArray[1, 2, 3].pop(2).should be_an_instance_of(Array)
+ ArraySpecs::MyArray[1, 2, 3].pop(2).should.instance_of?(Array)
end
it "raises a FrozenError on a frozen array" do
- -> { ArraySpecs.frozen_array.pop(2) }.should raise_error(FrozenError)
- -> { ArraySpecs.frozen_array.pop(0) }.should raise_error(FrozenError)
+ -> { ArraySpecs.frozen_array.pop(2) }.should.raise(FrozenError)
+ -> { ArraySpecs.frozen_array.pop(0) }.should.raise(FrozenError)
end
end
end
diff --git a/spec/ruby/core/array/prepend_spec.rb b/spec/ruby/core/array/prepend_spec.rb
index 368b8dcfcd..2d0ce31c71 100644
--- a/spec/ruby/core/array/prepend_spec.rb
+++ b/spec/ruby/core/array/prepend_spec.rb
@@ -1,7 +1,7 @@
require_relative '../../spec_helper'
-require_relative 'fixtures/classes'
-require_relative 'shared/unshift'
describe "Array#prepend" do
- it_behaves_like :array_unshift, :prepend
+ it "is an alias of Array#unshift" do
+ Array.instance_method(:prepend).should == Array.instance_method(:unshift)
+ end
end
diff --git a/spec/ruby/core/array/product_spec.rb b/spec/ruby/core/array/product_spec.rb
index 6fb3818508..837f0eaf34 100644
--- a/spec/ruby/core/array/product_spec.rb
+++ b/spec/ruby/core/array/product_spec.rb
@@ -3,7 +3,7 @@ require_relative 'fixtures/classes'
describe "Array#product" do
it "returns converted arguments using :to_ary" do
- ->{ [1].product(2..3) }.should raise_error(TypeError)
+ ->{ [1].product(2..3) }.should.raise(TypeError)
ar = ArraySpecs::ArrayConvertible.new(2,3)
[1].product(ar).should == [[1,2],[1,3]]
ar.called.should == :to_ary
@@ -31,7 +31,7 @@ describe "Array#product" do
a = (0..100).to_a
-> do
a.product(a, a, a, a, a, a, a, a, a, a)
- end.should raise_error(RangeError)
+ end.should.raise(RangeError)
end
describe "when given a block" do
@@ -43,7 +43,7 @@ describe "Array#product" do
acc = []
[1,2].product([3,4,5],[],[6,8]){|array| acc << array}
- acc.should be_empty
+ acc.should.empty?
end
it "returns self" do
@@ -56,18 +56,18 @@ describe "Array#product" do
a = (0..100).to_a
-> do
a.product(a, a, a, a, a, a, a, a, a, a)
- end.should raise_error(RangeError)
+ end.should.raise(RangeError)
end
end
describe "when given an empty block" do
it "returns self" do
arr = [1,2]
- arr.product([3,4,5],[6,8]){}.should equal(arr)
+ arr.product([3,4,5],[6,8]){}.should.equal?(arr)
arr = []
- arr.product([3,4,5],[6,8]){}.should equal(arr)
+ arr.product([3,4,5],[6,8]){}.should.equal?(arr)
arr = [1,2]
- arr.product([]){}.should equal(arr)
+ arr.product([]){}.should.equal?(arr)
end
end
end
diff --git a/spec/ruby/core/array/push_spec.rb b/spec/ruby/core/array/push_spec.rb
index 607cbc7b4d..6255a84371 100644
--- a/spec/ruby/core/array/push_spec.rb
+++ b/spec/ruby/core/array/push_spec.rb
@@ -1,7 +1,36 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
-require_relative 'shared/push'
describe "Array#push" do
- it_behaves_like :array_push, :push
+ it "appends the arguments to the array" do
+ a = [ "a", "b", "c" ]
+ a.push("d", "e", "f").should.equal?(a)
+ a.push.should == ["a", "b", "c", "d", "e", "f"]
+ a.push(5)
+ a.should == ["a", "b", "c", "d", "e", "f", 5]
+
+ a = [0, 1]
+ a.push(2)
+ a.should == [0, 1, 2]
+ end
+
+ it "isn't confused by previous shift" do
+ a = [ "a", "b", "c" ]
+ a.shift
+ a.push("foo")
+ a.should == ["b", "c", "foo"]
+ end
+
+ it "properly handles recursive arrays" do
+ empty = ArraySpecs.empty_recursive_array
+ empty.push(:last).should == [empty, :last]
+
+ array = ArraySpecs.recursive_array
+ array.push(:last).should == [1, 'two', 3.0, array, array, array, array, array, :last]
+ end
+
+ it "raises a FrozenError on a frozen array" do
+ -> { ArraySpecs.frozen_array.push(1) }.should.raise(FrozenError)
+ -> { ArraySpecs.frozen_array.push }.should.raise(FrozenError)
+ end
end
diff --git a/spec/ruby/core/array/rassoc_spec.rb b/spec/ruby/core/array/rassoc_spec.rb
index 632a05e8b3..95e4ed1892 100644
--- a/spec/ruby/core/array/rassoc_spec.rb
+++ b/spec/ruby/core/array/rassoc_spec.rb
@@ -12,11 +12,11 @@ describe "Array#rassoc" do
it "properly handles recursive arrays" do
empty = ArraySpecs.empty_recursive_array
- empty.rassoc([]).should be_nil
+ empty.rassoc([]).should == nil
[[empty, empty]].rassoc(empty).should == [empty, empty]
array = ArraySpecs.recursive_array
- array.rassoc(array).should be_nil
+ array.rassoc(array).should == nil
[[empty, array]].rassoc(array).should == [empty, array]
end
@@ -36,17 +36,15 @@ 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]
+ 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)
+ 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
+ a.rassoc(3).should == [2, 3]
+ s2.called.should.equal?(:to_ary)
end
end
diff --git a/spec/ruby/core/array/reject_spec.rb b/spec/ruby/core/array/reject_spec.rb
index 81a467e364..8d237b3a75 100644
--- a/spec/ruby/core/array/reject_spec.rb
+++ b/spec/ruby/core/array/reject_spec.rb
@@ -10,9 +10,9 @@ describe "Array#reject" do
ary = [1, 2, 3, 4, 5]
ary.reject { true }.should == []
ary.reject { false }.should == ary
- ary.reject { false }.should_not equal ary
+ ary.reject { false }.should_not.equal? ary
ary.reject { nil }.should == ary
- ary.reject { nil }.should_not equal ary
+ ary.reject { nil }.should_not.equal? ary
ary.reject { 5 }.should == []
ary.reject { |i| i < 3 }.should == [3, 4, 5]
ary.reject { |i| i % 2 == 0 }.should == [1, 3, 5]
@@ -35,7 +35,7 @@ describe "Array#reject" do
end
it "does not return subclass instance on Array subclasses" do
- ArraySpecs::MyArray[1, 2, 3].reject { |x| x % 2 == 0 }.should be_an_instance_of(Array)
+ ArraySpecs::MyArray[1, 2, 3].reject { |x| x % 2 == 0 }.should.instance_of?(Array)
end
it "does not retain instance variables" do
@@ -55,7 +55,7 @@ end
describe "Array#reject!" do
it "removes elements for which block is true" do
a = [3, 4, 5, 6, 7, 8, 9, 10, 11]
- a.reject! { |i| i % 2 == 0 }.should equal(a)
+ a.reject! { |i| i % 2 == 0 }.should.equal?(a)
a.should == [3, 5, 7, 9, 11]
a.reject! { |i| i > 8 }
a.should == [3, 5, 7]
@@ -105,20 +105,20 @@ describe "Array#reject!" do
end
it "returns an Enumerator if no block given, and the array is frozen" do
- ArraySpecs.frozen_array.reject!.should be_an_instance_of(Enumerator)
+ ArraySpecs.frozen_array.reject!.should.instance_of?(Enumerator)
end
it "raises a FrozenError on a frozen array" do
- -> { ArraySpecs.frozen_array.reject! {} }.should raise_error(FrozenError)
+ -> { ArraySpecs.frozen_array.reject! {} }.should.raise(FrozenError)
end
it "raises a FrozenError on an empty frozen array" do
- -> { ArraySpecs.empty_frozen_array.reject! {} }.should raise_error(FrozenError)
+ -> { ArraySpecs.empty_frozen_array.reject! {} }.should.raise(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)
+ -> { enum.each {} }.should.raise(FrozenError)
end
it "does not truncate the array is the block raises an exception" do
diff --git a/spec/ruby/core/array/repeated_combination_spec.rb b/spec/ruby/core/array/repeated_combination_spec.rb
index b62382024a..a714f05f54 100644
--- a/spec/ruby/core/array/repeated_combination_spec.rb
+++ b/spec/ruby/core/array/repeated_combination_spec.rb
@@ -6,16 +6,16 @@ describe "Array#repeated_combination" do
end
it "returns an enumerator when no block is provided" do
- @array.repeated_combination(2).should be_an_instance_of(Enumerator)
+ @array.repeated_combination(2).should.instance_of?(Enumerator)
end
it "returns self when a block is given" do
- @array.repeated_combination(2){}.should equal(@array)
+ @array.repeated_combination(2){}.should.equal?(@array)
end
it "yields nothing for negative length and return self" do
- @array.repeated_combination(-1){ fail }.should equal(@array)
- @array.repeated_combination(-10){ fail }.should equal(@array)
+ @array.repeated_combination(-1){ fail }.should.equal?(@array)
+ @array.repeated_combination(-10){ fail }.should.equal?(@array)
end
it "yields the expected repeated_combinations" do
diff --git a/spec/ruby/core/array/repeated_permutation_spec.rb b/spec/ruby/core/array/repeated_permutation_spec.rb
index a165fda09e..c54a8c0c2b 100644
--- a/spec/ruby/core/array/repeated_permutation_spec.rb
+++ b/spec/ruby/core/array/repeated_permutation_spec.rb
@@ -10,13 +10,13 @@ describe "Array#repeated_permutation" do
it "returns an Enumerator of all repeated permutations of given length when called without a block" do
enum = @numbers.repeated_permutation(2)
- enum.should be_an_instance_of(Enumerator)
+ enum.should.instance_of?(Enumerator)
enum.to_a.sort.should == @permutations
end
it "yields all repeated_permutations to the block then returns self when called with block but no arguments" do
yielded = []
- @numbers.repeated_permutation(2) {|n| yielded << n}.should equal(@numbers)
+ @numbers.repeated_permutation(2) {|n| yielded << n}.should.equal?(@numbers)
yielded.sort.should == @permutations
end
diff --git a/spec/ruby/core/array/replace_spec.rb b/spec/ruby/core/array/replace_spec.rb
index 2f53338f5e..ee6a98a646 100644
--- a/spec/ruby/core/array/replace_spec.rb
+++ b/spec/ruby/core/array/replace_spec.rb
@@ -1,7 +1,63 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
-require_relative 'shared/replace'
describe "Array#replace" do
- it_behaves_like :array_replace, :replace
+ it "replaces the elements with elements from other array" do
+ a = [1, 2, 3, 4, 5]
+ b = ['a', 'b', 'c']
+ a.replace(b).should.equal?(a)
+ a.should == b
+ a.should_not.equal?(b)
+
+ a.replace([4] * 10)
+ a.should == [4] * 10
+
+ a.replace([])
+ a.should == []
+ end
+
+ it "properly handles recursive arrays" do
+ orig = [1, 2, 3]
+ empty = ArraySpecs.empty_recursive_array
+ orig.replace(empty)
+ orig.should == empty
+
+ array = ArraySpecs.recursive_array
+ orig.replace(array)
+ orig.should == array
+ end
+
+ it "returns self" do
+ ary = [1, 2, 3]
+ other = [:a, :b, :c]
+ ary.replace(other).should.equal?(ary)
+ end
+
+ it "does not make self dependent to the original array" do
+ ary = [1, 2, 3]
+ other = [:a, :b, :c]
+ ary.replace(other)
+ ary.should == [:a, :b, :c]
+ ary << :d
+ ary.should == [:a, :b, :c, :d]
+ other.should == [:a, :b, :c]
+ end
+
+ it "tries to convert the passed argument to an Array using #to_ary" do
+ obj = mock('to_ary')
+ obj.stub!(:to_ary).and_return([1, 2, 3])
+ [].replace(obj).should == [1, 2, 3]
+ end
+
+ it "does not call #to_ary on Array subclasses" do
+ obj = ArraySpecs::ToAryArray[5, 6, 7]
+ obj.should_not_receive(:to_ary)
+ [].replace(ArraySpecs::ToAryArray[5, 6, 7]).should == [5, 6, 7]
+ end
+
+ it "raises a FrozenError on a frozen array" do
+ -> {
+ ArraySpecs.frozen_array.replace(ArraySpecs.frozen_array)
+ }.should.raise(FrozenError)
+ end
end
diff --git a/spec/ruby/core/array/reverse_each_spec.rb b/spec/ruby/core/array/reverse_each_spec.rb
index 59dabcd33d..8fa5ce6da1 100644
--- a/spec/ruby/core/array/reverse_each_spec.rb
+++ b/spec/ruby/core/array/reverse_each_spec.rb
@@ -19,7 +19,7 @@ describe "Array#reverse_each" do
it "returns self" do
a = [:a, :b, :c]
- a.reverse_each { |x| }.should equal(a)
+ a.reverse_each { |x| }.should.equal?(a)
end
it "yields only the top level element of an empty recursive arrays" do
diff --git a/spec/ruby/core/array/reverse_spec.rb b/spec/ruby/core/array/reverse_spec.rb
index 05dbd2efcf..f25a484be8 100644
--- a/spec/ruby/core/array/reverse_spec.rb
+++ b/spec/ruby/core/array/reverse_spec.rb
@@ -16,14 +16,14 @@ describe "Array#reverse" do
end
it "does not return subclass instance on Array subclasses" do
- ArraySpecs::MyArray[1, 2, 3].reverse.should be_an_instance_of(Array)
+ ArraySpecs::MyArray[1, 2, 3].reverse.should.instance_of?(Array)
end
end
describe "Array#reverse!" do
it "reverses the elements in place" do
a = [6, 3, 4, 2, 1]
- a.reverse!.should equal(a)
+ a.reverse!.should.equal?(a)
a.should == [1, 2, 4, 3, 6]
[].reverse!.should == []
end
@@ -37,6 +37,6 @@ describe "Array#reverse!" do
end
it "raises a FrozenError on a frozen array" do
- -> { ArraySpecs.frozen_array.reverse! }.should raise_error(FrozenError)
+ -> { ArraySpecs.frozen_array.reverse! }.should.raise(FrozenError)
end
end
diff --git a/spec/ruby/core/array/rindex_spec.rb b/spec/ruby/core/array/rindex_spec.rb
index 13de88818c..858c39dc92 100644
--- a/spec/ruby/core/array/rindex_spec.rb
+++ b/spec/ruby/core/array/rindex_spec.rb
@@ -41,7 +41,7 @@ describe "Array#rindex" do
it "properly handles empty recursive arrays" do
empty = ArraySpecs.empty_recursive_array
empty.rindex(empty).should == 0
- empty.rindex(1).should be_nil
+ empty.rindex(1).should == nil
end
it "properly handles recursive arrays" do
@@ -86,7 +86,7 @@ describe "Array#rindex" do
describe "given no argument and no block" do
it "produces an Enumerator" do
enum = [4, 2, 1, 5, 1, 3].rindex
- enum.should be_an_instance_of(Enumerator)
+ enum.should.instance_of?(Enumerator)
enum.each { |x| x < 2 }.should == 4
end
end
diff --git a/spec/ruby/core/array/rotate_spec.rb b/spec/ruby/core/array/rotate_spec.rb
index 60dcc8b113..009ce5ed49 100644
--- a/spec/ruby/core/array/rotate_spec.rb
+++ b/spec/ruby/core/array/rotate_spec.rb
@@ -29,10 +29,10 @@ describe "Array#rotate" do
it "raises a TypeError if not passed an integer-like argument" do
-> {
[1, 2].rotate(nil)
- }.should raise_error(TypeError)
+ }.should.raise(TypeError)
-> {
[1, 2].rotate("4")
- }.should raise_error(TypeError)
+ }.should.raise(TypeError)
end
end
@@ -50,18 +50,18 @@ describe "Array#rotate" do
[].freeze.rotate
[2].freeze.rotate(2)
[1,2,3].freeze.rotate(-3)
- }.should_not raise_error
+ }.should_not.raise
end
it "does not return self" do
a = [1, 2, 3]
- a.rotate.should_not equal(a)
+ a.rotate.should_not.equal?(a)
a = []
- a.rotate(0).should_not equal(a)
+ a.rotate(0).should_not.equal?(a)
end
it "does not return subclass instance for Array subclasses" do
- ArraySpecs::MyArray[1, 2, 3].rotate.should be_an_instance_of(Array)
+ ArraySpecs::MyArray[1, 2, 3].rotate.should.instance_of?(Array)
end
end
@@ -69,7 +69,7 @@ describe "Array#rotate!" do
describe "when passed no argument" do
it "moves the first element to the end and returns self" do
a = [1, 2, 3, 4, 5]
- a.rotate!.should equal(a)
+ a.rotate!.should.equal?(a)
a.should == [2, 3, 4, 5, 1]
end
end
@@ -77,11 +77,11 @@ describe "Array#rotate!" do
describe "with an argument n" do
it "moves the first (n % size) elements at the end and returns self" do
a = [1, 2, 3, 4, 5]
- a.rotate!(2).should equal(a)
+ a.rotate!(2).should.equal?(a)
a.should == [3, 4, 5, 1, 2]
- a.rotate!(-12).should equal(a)
+ a.rotate!(-12).should.equal?(a)
a.should == [1, 2, 3, 4, 5]
- a.rotate!(13).should equal(a)
+ a.rotate!(13).should.equal?(a)
a.should == [4, 5, 1, 2, 3]
end
@@ -96,34 +96,34 @@ describe "Array#rotate!" do
it "raises a TypeError if not passed an integer-like argument" do
-> {
[1, 2].rotate!(nil)
- }.should raise_error(TypeError)
+ }.should.raise(TypeError)
-> {
[1, 2].rotate!("4")
- }.should raise_error(TypeError)
+ }.should.raise(TypeError)
end
end
it "does nothing and returns self when the length is zero or one" do
a = [1]
- a.rotate!.should equal(a)
+ a.rotate!.should.equal?(a)
a.should == [1]
- a.rotate!(2).should equal(a)
+ a.rotate!(2).should.equal?(a)
a.should == [1]
- a.rotate!(-21).should equal(a)
+ a.rotate!(-21).should.equal?(a)
a.should == [1]
a = []
- a.rotate!.should equal(a)
+ a.rotate!.should.equal?(a)
a.should == []
- a.rotate!(2).should equal(a)
+ a.rotate!(2).should.equal?(a)
a.should == []
- a.rotate!(-21).should equal(a)
+ a.rotate!(-21).should.equal?(a)
a.should == []
end
it "raises a FrozenError on a frozen array" do
- -> { [1, 2, 3].freeze.rotate!(0) }.should raise_error(FrozenError)
- -> { [1].freeze.rotate!(42) }.should raise_error(FrozenError)
- -> { [].freeze.rotate! }.should raise_error(FrozenError)
+ -> { [1, 2, 3].freeze.rotate!(0) }.should.raise(FrozenError)
+ -> { [1].freeze.rotate!(42) }.should.raise(FrozenError)
+ -> { [].freeze.rotate! }.should.raise(FrozenError)
end
end
diff --git a/spec/ruby/core/array/sample_spec.rb b/spec/ruby/core/array/sample_spec.rb
index d4e945152d..fd443b47de 100644
--- a/spec/ruby/core/array/sample_spec.rb
+++ b/spec/ruby/core/array/sample_spec.rb
@@ -14,23 +14,23 @@ describe "Array#sample" do
end
it "returns nil for an empty Array" do
- [].sample.should be_nil
+ [].sample.should == nil
end
it "returns nil for an empty array when called without n and a Random is given" do
- [].sample(random: Random.new(42)).should be_nil
+ [].sample(random: Random.new(42)).should == nil
end
it "returns a single value when not passed a count" do
- [4].sample.should equal(4)
+ [4].sample.should.equal?(4)
end
it "returns a single value when not passed a count and a Random is given" do
- [4].sample(random: Random.new(42)).should equal(4)
+ [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)
+ [4].sample(random: Random).should.equal?(4)
end
it "returns an empty Array when passed zero" do
@@ -38,12 +38,12 @@ describe "Array#sample" do
end
it "returns an Array of elements when passed a count" do
- [1, 2, 3, 4].sample(3).should be_an_instance_of(Array)
+ [1, 2, 3, 4].sample(3).should.instance_of?(Array)
end
it "returns elements from the Array" do
array = [1, 2, 3, 4]
- array.sample(3).all? { |x| array.should include(x) }
+ array.sample(3).all? { |x| array.should.include?(x) }
end
it "returns at most the number of elements in the Array" do
@@ -67,11 +67,11 @@ describe "Array#sample" do
end
it "raises ArgumentError when passed a negative count" do
- -> { [1, 2].sample(-1) }.should raise_error(ArgumentError)
+ -> { [1, 2].sample(-1) }.should.raise(ArgumentError)
end
it "does not return subclass instances with Array subclass" do
- ArraySpecs::MyArray[1, 2, 3].sample(2).should be_an_instance_of(Array)
+ ArraySpecs::MyArray[1, 2, 3].sample(2).should.instance_of?(Array)
end
describe "with options" do
@@ -79,13 +79,13 @@ describe "Array#sample" do
obj = mock("array_sample_random")
obj.should_receive(:rand).and_return(0.5)
- [1, 2].sample(random: obj).should be_an_instance_of(Integer)
+ [1, 2].sample(random: obj).should.instance_of?(Integer)
end
it "raises a NoMethodError if an object passed for the RNG does not define #rand" do
obj = BasicObject.new
- -> { [1, 2].sample(random: obj) }.should raise_error(NoMethodError)
+ -> { [1, 2].sample(random: obj) }.should.raise(NoMethodError)
end
describe "when the object returned by #rand is an Integer" do
@@ -105,21 +105,21 @@ describe "Array#sample" do
random = mock("array_sample_random")
random.should_receive(:rand).and_return(-1)
- -> { [1, 2].sample(random: random) }.should raise_error(RangeError)
+ -> { [1, 2].sample(random: random) }.should.raise(RangeError)
end
it "raises a RangeError if the value is equal to the Array size" do
random = mock("array_sample_random")
random.should_receive(:rand).and_return(2)
- -> { [1, 2].sample(random: random) }.should raise_error(RangeError)
+ -> { [1, 2].sample(random: random) }.should.raise(RangeError)
end
it "raises a RangeError if the value is greater than the Array size" do
random = mock("array_sample_random")
random.should_receive(:rand).and_return(3)
- -> { [1, 2].sample(random: random) }.should raise_error(RangeError)
+ -> { [1, 2].sample(random: random) }.should.raise(RangeError)
end
end
end
@@ -140,7 +140,7 @@ describe "Array#sample" do
random = mock("array_sample_random")
random.should_receive(:rand).and_return(value)
- -> { [1, 2].sample(random: random) }.should raise_error(RangeError)
+ -> { [1, 2].sample(random: random) }.should.raise(RangeError)
end
it "raises a RangeError if the value is equal to the Array size" do
@@ -149,7 +149,7 @@ describe "Array#sample" do
random = mock("array_sample_random")
random.should_receive(:rand).and_return(value)
- -> { [1, 2].sample(random: random) }.should raise_error(RangeError)
+ -> { [1, 2].sample(random: random) }.should.raise(RangeError)
end
end
end
diff --git a/spec/ruby/core/array/select_spec.rb b/spec/ruby/core/array/select_spec.rb
index 298b591744..57ec0b2540 100644
--- a/spec/ruby/core/array/select_spec.rb
+++ b/spec/ruby/core/array/select_spec.rb
@@ -1,13 +1,42 @@
require_relative '../../spec_helper'
-require_relative 'shared/select'
+require_relative '../enumerable/shared/enumeratorized'
+require_relative 'fixtures/classes'
+require_relative 'shared/enumeratorize'
+require_relative 'shared/iterable_and_tolerating_size_increasing'
+require_relative 'shared/keep_if'
describe "Array#select" do
- it_behaves_like :array_select, :select
+ it_behaves_like :enumeratorize, :select
+
+ it_behaves_like :array_iterable_and_tolerating_size_increasing, :select
+
+ before :each do
+ @object = [1,2,3]
+ end
+ it_behaves_like :enumeratorized_with_origin_size, :select
+
+ it "returns a new array of elements for which block is true" do
+ [1, 3, 4, 5, 6, 9].select { |i| i % ((i + 1) / 2) == 0}.should == [1, 4, 6]
+ end
+
+ it "does not return subclass instance on Array subclasses" do
+ ArraySpecs::MyArray[1, 2, 3].select { true }.should.instance_of?(Array)
+ end
+
+ it "properly handles recursive arrays" do
+ empty = ArraySpecs.empty_recursive_array
+ empty.select { true }.should == empty
+ empty.select { false }.should == []
+
+ array = ArraySpecs.recursive_array
+ array.select { true }.should == [1, 'two', 3.0, array, array, array, array, array]
+ array.select { false }.should == []
+ end
end
describe "Array#select!" do
it "returns nil if no changes were made in the array" do
- [1, 2, 3].select! { true }.should be_nil
+ [1, 2, 3].select! { true }.should == nil
end
it_behaves_like :keep_if, :select!
diff --git a/spec/ruby/core/array/shared/clone.rb b/spec/ruby/core/array/shared/clone.rb
index 035b45ec99..1a45c2fe2c 100644
--- a/spec/ruby/core/array/shared/clone.rb
+++ b/spec/ruby/core/array/shared/clone.rb
@@ -1,14 +1,14 @@
describe :array_clone, shared: true do
it "returns an Array or a subclass instance" do
- [].send(@method).should be_an_instance_of(Array)
- ArraySpecs::MyArray[1, 2].send(@method).should be_an_instance_of(ArraySpecs::MyArray)
+ [].send(@method).should.instance_of?(Array)
+ ArraySpecs::MyArray[1, 2].send(@method).should.instance_of?(ArraySpecs::MyArray)
end
it "produces a shallow copy where the references are directly copied" do
a = [mock('1'), mock('2')]
b = a.send @method
- b.first.should equal a.first
- b.last.should equal a.last
+ b.first.should.equal? a.first
+ b.last.should.equal? a.last
end
it "creates a new array containing all elements or the original" do
diff --git a/spec/ruby/core/array/shared/collect.rb b/spec/ruby/core/array/shared/collect.rb
deleted file mode 100644
index 030302ced6..0000000000
--- a/spec/ruby/core/array/shared/collect.rb
+++ /dev/null
@@ -1,141 +0,0 @@
-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
- a = ['a', 'b', 'c', 'd']
- b = a.send(@method) { |i| i + '!' }
- b.should == ["a!", "b!", "c!", "d!"]
- b.should_not equal a
- end
-
- it "does not return subclass instance" do
- ArraySpecs::MyArray[1, 2, 3].send(@method) { |x| x + 1 }.should be_an_instance_of(Array)
- end
-
- it "does not change self" do
- a = ['a', 'b', 'c', 'd']
- a.send(@method) { |i| i + '!' }
- a.should == ['a', 'b', 'c', 'd']
- end
-
- it "returns the evaluated value of block if it broke in the block" do
- a = ['a', 'b', 'c', 'd']
- b = a.send(@method) {|i|
- if i == 'c'
- break 0
- else
- i + '!'
- end
- }
- b.should == 0
- end
-
- it "returns an Enumerator when no block given" do
- a = [1, 2, 3]
- a.send(@method).should be_an_instance_of(Enumerator)
- end
-
- it "raises an ArgumentError when no block and with arguments" do
- a = [1, 2, 3]
- -> {
- a.send(@method, :foo)
- }.should raise_error(ArgumentError)
- 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
-
-describe :array_collect_b, shared: true do
- it "replaces each element with the value returned by block" do
- a = [7, 9, 3, 5]
- a.send(@method) { |i| i - 1 }.should equal(a)
- a.should == [6, 8, 2, 4]
- end
-
- it "returns self" do
- a = [1, 2, 3, 4, 5]
- b = a.send(@method) {|i| i+1 }
- a.should equal b
- end
-
- it "returns the evaluated value of block but its contents is partially modified, if it broke in the block" do
- a = ['a', 'b', 'c', 'd']
- b = a.send(@method) {|i|
- if i == 'c'
- break 0
- else
- i + '!'
- end
- }
- b.should == 0
- a.should == ['a!', 'b!', 'c', 'd']
- end
-
- it "returns an Enumerator when no block given, and the enumerator can modify the original array" do
- a = [1, 2, 3]
- enum = a.send(@method)
- enum.should be_an_instance_of(Enumerator)
- enum.each{|i| "#{i}!" }
- a.should == ["1!", "2!", "3!"]
- end
-
- describe "when frozen" do
- it "raises a FrozenError" do
- -> { ArraySpecs.frozen_array.send(@method) {} }.should raise_error(FrozenError)
- end
-
- it "raises a FrozenError when empty" do
- -> { ArraySpecs.empty_frozen_array.send(@method) {} }.should raise_error(FrozenError)
- end
-
- it "raises a FrozenError when calling #each on the returned Enumerator" do
- enumerator = ArraySpecs.frozen_array.send(@method)
- -> { enumerator.each {|x| x } }.should raise_error(FrozenError)
- end
-
- it "raises a FrozenError when calling #each on the returned Enumerator when empty" do
- enumerator = ArraySpecs.empty_frozen_array.send(@method)
- -> { enumerator.each {|x| x } }.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 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/difference.rb b/spec/ruby/core/array/shared/difference.rb
index 3e69050d82..3fe22331bd 100644
--- a/spec/ruby/core/array/shared/difference.rb
+++ b/spec/ruby/core/array/shared/difference.rb
@@ -27,13 +27,13 @@ describe :array_binary_difference, shared: true do
it "raises a TypeError if the argument cannot be coerced to an Array by calling #to_ary" do
obj = mock('not an array')
- -> { [1, 2, 3].send(@method, obj) }.should raise_error(TypeError)
+ -> { [1, 2, 3].send(@method, obj) }.should.raise(TypeError)
end
it "does not return subclass instance for Array subclasses" do
- ArraySpecs::MyArray[1, 2, 3].send(@method, []).should be_an_instance_of(Array)
- ArraySpecs::MyArray[1, 2, 3].send(@method, ArraySpecs::MyArray[]).should be_an_instance_of(Array)
- [1, 2, 3].send(@method, ArraySpecs::MyArray[]).should be_an_instance_of(Array)
+ ArraySpecs::MyArray[1, 2, 3].send(@method, []).should.instance_of?(Array)
+ ArraySpecs::MyArray[1, 2, 3].send(@method, ArraySpecs::MyArray[]).should.instance_of?(Array)
+ [1, 2, 3].send(@method, ArraySpecs::MyArray[]).should.instance_of?(Array)
end
it "does not call to_ary on array subclasses" do
diff --git a/spec/ruby/core/array/shared/enumeratorize.rb b/spec/ruby/core/array/shared/enumeratorize.rb
index a19a5d3b9b..5beab5c4c4 100644
--- a/spec/ruby/core/array/shared/enumeratorize.rb
+++ b/spec/ruby/core/array/shared/enumeratorize.rb
@@ -1,5 +1,5 @@
describe :enumeratorize, shared: true do
it "returns an Enumerator if no block given" do
- [1,2].send(@method).should be_an_instance_of(Enumerator)
+ [1,2].send(@method).should.instance_of?(Enumerator)
end
end
diff --git a/spec/ruby/core/array/shared/eql.rb b/spec/ruby/core/array/shared/eql.rb
index b5d9128434..5e770bf167 100644
--- a/spec/ruby/core/array/shared/eql.rb
+++ b/spec/ruby/core/array/shared/eql.rb
@@ -1,59 +1,59 @@
describe :array_eql, shared: true do
it "returns true if other is the same array" do
a = [1]
- a.send(@method, a).should be_true
+ a.send(@method, a).should == true
end
it "returns true if corresponding elements are #eql?" do
- [].send(@method, []).should be_true
- [1, 2, 3, 4].send(@method, [1, 2, 3, 4]).should be_true
+ [].send(@method, []).should == true
+ [1, 2, 3, 4].send(@method, [1, 2, 3, 4]).should == true
end
it "returns false if other is shorter than self" do
- [1, 2, 3, 4].send(@method, [1, 2, 3]).should be_false
+ [1, 2, 3, 4].send(@method, [1, 2, 3]).should == false
end
it "returns false if other is longer than self" do
- [1, 2, 3, 4].send(@method, [1, 2, 3, 4, 5]).should be_false
+ [1, 2, 3, 4].send(@method, [1, 2, 3, 4, 5]).should == false
end
it "returns false immediately when sizes of the arrays differ" do
obj = mock('1')
obj.should_not_receive(@method)
- [] .send(@method, [obj] ).should be_false
- [obj] .send(@method, [] ).should be_false
+ [] .send(@method, [obj] ).should == false
+ [obj] .send(@method, [] ).should == false
end
it "handles well recursive arrays" do
a = ArraySpecs.empty_recursive_array
- a .send(@method, [a] ).should be_true
- a .send(@method, [[a]] ).should be_true
- [a] .send(@method, a ).should be_true
- [[a]] .send(@method, a ).should be_true
+ a .send(@method, [a] ).should == true
+ a .send(@method, [[a]] ).should == true
+ [a] .send(@method, a ).should == true
+ [[a]] .send(@method, a ).should == true
# These may be surprising, but no difference can be
# found between these arrays, so they are ==.
# There is no "path" that will lead to a difference
# (contrary to other examples below)
a2 = ArraySpecs.empty_recursive_array
- a .send(@method, a2 ).should be_true
- a .send(@method, [a2] ).should be_true
- a .send(@method, [[a2]] ).should be_true
- [a] .send(@method, a2 ).should be_true
- [[a]] .send(@method, a2 ).should be_true
+ a .send(@method, a2 ).should == true
+ a .send(@method, [a2] ).should == true
+ a .send(@method, [[a2]] ).should == true
+ [a] .send(@method, a2 ).should == true
+ [[a]] .send(@method, a2 ).should == true
back = []
forth = [back]; back << forth;
- back .send(@method, a ).should be_true
+ back .send(@method, a ).should == true
x = []; x << x << x
- x .send(@method, a ).should be_false # since x.size != a.size
- x .send(@method, [a, a] ).should be_false # since x[0].size != [a, a][0].size
- x .send(@method, [x, a] ).should be_false # since x[1].size != [x, a][1].size
- [x, a] .send(@method, [a, x] ).should be_false # etc...
- x .send(@method, [x, x] ).should be_true
- x .send(@method, [[x, x], [x, x]] ).should be_true
+ x .send(@method, a ).should == false # since x.size != a.size
+ x .send(@method, [a, a] ).should == false # since x[0].size != [a, a][0].size
+ x .send(@method, [x, a] ).should == false # since x[1].size != [x, a][1].size
+ [x, a] .send(@method, [a, x] ).should == false # etc...
+ x .send(@method, [x, x] ).should == true
+ x .send(@method, [[x, x], [x, x]] ).should == true
tree = [];
branch = []; branch << tree << tree; tree << branch
@@ -62,31 +62,31 @@ describe :array_eql, shared: true do
forest = [tree, branch, :bird, a]; forest << forest
forest2 = [tree2, branch2, :bird, a2]; forest2 << forest2
- forest .send(@method, forest2 ).should be_true
- forest .send(@method, [tree2, branch, :bird, a, forest2]).should be_true
+ forest .send(@method, forest2 ).should == true
+ forest .send(@method, [tree2, branch, :bird, a, forest2]).should == true
diffforest = [branch2, tree2, :bird, a2]; diffforest << forest2
- forest .send(@method, diffforest ).should be_false # since forest[0].size == 1 != 3 == diffforest[0]
- forest .send(@method, [nil] ).should be_false
- forest .send(@method, [forest] ).should be_false
+ forest .send(@method, diffforest ).should == false # since forest[0].size == 1 != 3 == diffforest[0]
+ forest .send(@method, [nil] ).should == false
+ forest .send(@method, [forest] ).should == false
end
it "does not call #to_ary on its argument" do
obj = mock('to_ary')
obj.should_not_receive(:to_ary)
- [1, 2, 3].send(@method, obj).should be_false
+ [1, 2, 3].send(@method, obj).should == false
end
it "does not call #to_ary on Array subclasses" do
ary = ArraySpecs::ToAryArray[5, 6, 7]
ary.should_not_receive(:to_ary)
- [5, 6, 7].send(@method, ary).should be_true
+ [5, 6, 7].send(@method, ary).should == true
end
it "ignores array class differences" do
- ArraySpecs::MyArray[1, 2, 3].send(@method, [1, 2, 3]).should be_true
- ArraySpecs::MyArray[1, 2, 3].send(@method, ArraySpecs::MyArray[1, 2, 3]).should be_true
- [1, 2, 3].send(@method, ArraySpecs::MyArray[1, 2, 3]).should be_true
+ ArraySpecs::MyArray[1, 2, 3].send(@method, [1, 2, 3]).should == true
+ ArraySpecs::MyArray[1, 2, 3].send(@method, ArraySpecs::MyArray[1, 2, 3]).should == true
+ [1, 2, 3].send(@method, ArraySpecs::MyArray[1, 2, 3]).should == true
end
end
diff --git a/spec/ruby/core/array/shared/index.rb b/spec/ruby/core/array/shared/index.rb
deleted file mode 100644
index a4a0adbab6..0000000000
--- a/spec/ruby/core/array/shared/index.rb
+++ /dev/null
@@ -1,41 +0,0 @@
-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')
- def x.==(obj) 3 == obj; end
-
- [2, x, 3, 1, 3, 1].send(@method, 3).should == 1
- [2, 3.0, 3, x, 1, 3, 1].send(@method, x).should == 1
- end
-
- it "returns 0 if first element == to object" do
- [2, 1, 3, 2, 5].send(@method, 2).should == 0
- end
-
- it "returns size-1 if only last element == to object" do
- [2, 1, 3, 1, 5].send(@method, 5).should == 4
- end
-
- it "returns nil if no element == to object" do
- [2, 1, 1, 1, 1].send(@method, 3).should == nil
- end
-
- it "accepts a block instead of an argument" do
- [4, 2, 1, 5, 1, 3].send(@method) {|x| x < 2}.should == 2
- end
-
- it "ignores the block if there is an argument" do
- -> {
- [4, 2, 1, 5, 1, 3].send(@method, 5) {|x| x < 2}.should == 3
- }.should complain(/given block not used/)
- end
-
- describe "given no argument and no block" do
- it "produces an Enumerator" 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
deleted file mode 100644
index af5128c645..0000000000
--- a/spec/ruby/core/array/shared/inspect.rb
+++ /dev/null
@@ -1,107 +0,0 @@
-require_relative '../fixtures/encoded_strings'
-
-describe :array_inspect, shared: true do
- it "returns a string" do
- [1, 2, 3].send(@method).should be_an_instance_of(String)
- end
-
- it "returns '[]' for an empty Array" do
- [].send(@method).should == "[]"
- end
-
- it "calls inspect on its elements and joins the results with commas" do
- items = Array.new(3) do |i|
- obj = mock(i.to_s)
- obj.should_receive(:inspect).and_return(i.to_s)
- obj
- end
- items.send(@method).should == "[0, 1, 2]"
- end
-
- it "does not call #to_s on a String returned from #inspect" do
- str = +"abc"
- str.should_not_receive(:to_s)
-
- [str].send(@method).should == '["abc"]'
- end
-
- it "calls #to_s on the object returned from #inspect if the Object isn't a String" do
- obj = mock("Array#inspect/to_s calls #to_s")
- obj.should_receive(:inspect).and_return(obj)
- obj.should_receive(:to_s).and_return("abc")
-
- [obj].send(@method).should == "[abc]"
- end
-
- it "does not call #to_str on the object returned from #inspect when it is not a String" do
- obj = mock("Array#inspect/to_s does not call #to_str")
- obj.should_receive(:inspect).and_return(obj)
- obj.should_not_receive(:to_str)
-
- [obj].send(@method).should =~ /^\[#<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
- obj = mock("Array#inspect/to_s does not call #to_str on #to_s result")
- obj.should_receive(:inspect).and_return(obj)
- obj.should_receive(:to_s).and_return(obj)
- obj.should_not_receive(:to_str)
-
- [obj].send(@method).should =~ /^\[#<MockObject:0x[0-9a-f]+>\]$/
- end
-
- it "does not swallow exceptions raised by #to_s" do
- obj = mock("Array#inspect/to_s does not swallow #to_s exceptions")
- obj.should_receive(:inspect).and_return(obj)
- obj.should_receive(:to_s).and_raise(Exception)
-
- -> { [obj].send(@method) }.should raise_error(Exception)
- end
-
- it "represents a recursive element with '[...]'" do
- ArraySpecs.recursive_array.send(@method).should == "[1, \"two\", 3.0, [...], [...], [...], [...], [...]]"
- ArraySpecs.head_recursive_array.send(@method).should == "[[...], [...], [...], [...], [...], 1, \"two\", 3.0]"
- ArraySpecs.empty_recursive_array.send(@method).should == "[[...]]"
- end
-
- describe "with encoding" do
- before :each do
- @default_external_encoding = Encoding.default_external
- end
-
- after :each do
- Encoding.default_external = @default_external_encoding
- end
-
- it "returns a US-ASCII string for an empty Array" do
- [].send(@method).encoding.should == Encoding::US_ASCII
- end
-
- it "use the default external encoding if it is ascii compatible" do
- Encoding.default_external = Encoding.find('UTF-8')
-
- utf8 = "utf8".encode("UTF-8")
- jp = "jp".encode("EUC-JP")
- array = [jp, utf8]
-
- array.send(@method).encoding.name.should == "UTF-8"
- end
-
- it "use US-ASCII encoding if the default external encoding is not ascii compatible" do
- Encoding.default_external = Encoding.find('UTF-32')
-
- utf8 = "utf8".encode("UTF-8")
- jp = "jp".encode("EUC-JP")
- array = [jp, utf8]
-
- array.send(@method).encoding.name.should == "US-ASCII"
- 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].send(@method).should == '["utf_16be \u3042"]'
- end
- end
-end
diff --git a/spec/ruby/core/array/shared/intersection.rb b/spec/ruby/core/array/shared/intersection.rb
index 0b4166ab63..dda72e8bd7 100644
--- a/spec/ruby/core/array/shared/intersection.rb
+++ b/spec/ruby/core/array/shared/intersection.rb
@@ -66,9 +66,9 @@ describe :array_intersection, shared: true do
end
it "does return subclass instances for Array subclasses" do
- ArraySpecs::MyArray[1, 2, 3].send(@method, []).should be_an_instance_of(Array)
- ArraySpecs::MyArray[1, 2, 3].send(@method, ArraySpecs::MyArray[1, 2, 3]).should be_an_instance_of(Array)
- [].send(@method, ArraySpecs::MyArray[1, 2, 3]).should be_an_instance_of(Array)
+ ArraySpecs::MyArray[1, 2, 3].send(@method, []).should.instance_of?(Array)
+ ArraySpecs::MyArray[1, 2, 3].send(@method, ArraySpecs::MyArray[1, 2, 3]).should.instance_of?(Array)
+ [].send(@method, ArraySpecs::MyArray[1, 2, 3]).should.instance_of?(Array)
end
it "does not call to_ary on array subclasses" do
diff --git a/spec/ruby/core/array/shared/join.rb b/spec/ruby/core/array/shared/join.rb
index 507b13e3c8..93d5329ee3 100644
--- a/spec/ruby/core/array/shared/join.rb
+++ b/spec/ruby/core/array/shared/join.rb
@@ -1,103 +1,6 @@
require_relative '../fixtures/classes'
require_relative '../fixtures/encoded_strings'
-describe :array_join_with_default_separator, shared: true do
- before :each do
- @separator = $,
- end
-
- after :each do
- $, = @separator
- end
-
- it "returns an empty string if the Array is empty" do
- [].send(@method).should == ''
- end
-
- it "returns a US-ASCII string for an empty Array" do
- [].send(@method).encoding.should == Encoding::US_ASCII
- end
-
- it "returns a string formed by concatenating each String element separated by $," do
- suppress_warning {
- $, = " | "
- ["1", "2", "3"].send(@method).should == "1 | 2 | 3"
- }
- end
-
- it "attempts coercion via #to_str first" do
- obj = mock('foo')
- obj.should_receive(:to_str).any_number_of_times.and_return("foo")
- [obj].send(@method).should == "foo"
- end
-
- it "attempts coercion via #to_ary second" do
- obj = mock('foo')
- obj.should_receive(:to_str).any_number_of_times.and_return(nil)
- obj.should_receive(:to_ary).any_number_of_times.and_return(["foo"])
- [obj].send(@method).should == "foo"
- end
-
- it "attempts coercion via #to_s third" do
- obj = mock('foo')
- obj.should_receive(:to_str).any_number_of_times.and_return(nil)
- obj.should_receive(:to_ary).any_number_of_times.and_return(nil)
- obj.should_receive(:to_s).any_number_of_times.and_return("foo")
- [obj].send(@method).should == "foo"
- end
-
- it "raises a NoMethodError if an element does not respond to #to_str, #to_ary, or #to_s" do
- obj = mock('o')
- class << obj; undef :to_s; end
- -> { [1, obj].send(@method) }.should raise_error(NoMethodError)
- end
-
- it "raises an ArgumentError when the Array is recursive" do
- -> { ArraySpecs.recursive_array.send(@method) }.should raise_error(ArgumentError)
- -> { ArraySpecs.head_recursive_array.send(@method) }.should raise_error(ArgumentError)
- -> { ArraySpecs.empty_recursive_array.send(@method) }.should raise_error(ArgumentError)
- end
-
- it "uses the first encoding when other strings are compatible" do
- ary1 = ArraySpecs.array_with_7bit_utf8_and_usascii_strings
- ary2 = ArraySpecs.array_with_usascii_and_7bit_utf8_strings
- ary3 = ArraySpecs.array_with_utf8_and_7bit_binary_strings
- ary4 = ArraySpecs.array_with_usascii_and_7bit_binary_strings
-
- ary1.send(@method).encoding.should == Encoding::UTF_8
- ary2.send(@method).encoding.should == Encoding::US_ASCII
- ary3.send(@method).encoding.should == Encoding::UTF_8
- ary4.send(@method).encoding.should == Encoding::US_ASCII
- end
-
- it "uses the widest common encoding when other strings are incompatible" do
- ary1 = ArraySpecs.array_with_utf8_and_usascii_strings
- ary2 = ArraySpecs.array_with_usascii_and_utf8_strings
-
- ary1.send(@method).encoding.should == Encoding::UTF_8
- ary2.send(@method).encoding.should == Encoding::UTF_8
- end
-
- it "fails for arrays with incompatibly-encoded strings" do
- ary_utf8_bad_binary = ArraySpecs.array_with_utf8_and_binary_strings
-
- -> { ary_utf8_bad_binary.send(@method) }.should raise_error(EncodingError)
- end
-
- context "when $, is not nil" do
- before do
- suppress_warning do
- $, = '*'
- end
- end
-
- it "warns" do
- -> { [].join }.should complain(/warning: \$, is set to non-nil value/)
- -> { [].join(nil) }.should complain(/warning: \$, is set to non-nil value/)
- end
- end
-end
-
describe :array_join_with_string_separator, shared: true do
it "returns a string formed by concatenating each element.to_str separated by separator" do
obj = mock('foo')
diff --git a/spec/ruby/core/array/shared/keep_if.rb b/spec/ruby/core/array/shared/keep_if.rb
index 43a047c0a7..44625eebd1 100644
--- a/spec/ruby/core/array/shared/keep_if.rb
+++ b/spec/ruby/core/array/shared/keep_if.rb
@@ -4,12 +4,12 @@ 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
array = [1, 2, 3, 4, 5]
- array.send(@method) {|item| item > 3 }.should equal(array)
+ array.send(@method) {|item| item > 3 }.should.equal?(array)
array.should == [4, 5]
end
it "returns an enumerator if no block is given" do
- [1, 2, 3].send(@method).should be_an_instance_of(Enumerator)
+ [1, 2, 3].send(@method).should.instance_of?(Enumerator)
end
it "updates the receiver after all blocks" do
@@ -33,34 +33,34 @@ describe :keep_if, shared: true do
end
it "returns an Enumerator if no block is given" do
- @frozen.send(@method).should be_an_instance_of(Enumerator)
+ @frozen.send(@method).should.instance_of?(Enumerator)
end
describe "with truthy block" do
it "keeps elements after any exception" do
- -> { @frozen.send(@method) { true } }.should raise_error(Exception)
+ -> { @frozen.send(@method) { true } }.should.raise(Exception)
@frozen.should == @origin
end
it "raises a FrozenError" do
- -> { @frozen.send(@method) { true } }.should raise_error(FrozenError)
+ -> { @frozen.send(@method) { true } }.should.raise(FrozenError)
end
end
describe "with falsy block" do
it "keeps elements after any exception" do
- -> { @frozen.send(@method) { false } }.should raise_error(Exception)
+ -> { @frozen.send(@method) { false } }.should.raise(Exception)
@frozen.should == @origin
end
it "raises a FrozenError" do
- -> { @frozen.send(@method) { false } }.should raise_error(FrozenError)
+ -> { @frozen.send(@method) { false } }.should.raise(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)
+ -> { enum.each {} }.should.raise(FrozenError)
end
end
diff --git a/spec/ruby/core/array/shared/length.rb b/spec/ruby/core/array/shared/length.rb
deleted file mode 100644
index f84966d0ba..0000000000
--- a/spec/ruby/core/array/shared/length.rb
+++ /dev/null
@@ -1,11 +0,0 @@
-describe :array_length, shared: true do
- it "returns the number of elements" do
- [].send(@method).should == 0
- [1, 2, 3].send(@method).should == 3
- end
-
- it "properly handles recursive arrays" do
- ArraySpecs.empty_recursive_array.send(@method).should == 1
- ArraySpecs.recursive_array.send(@method).should == 8
- end
-end
diff --git a/spec/ruby/core/array/shared/push.rb b/spec/ruby/core/array/shared/push.rb
deleted file mode 100644
index ac790fb6a4..0000000000
--- a/spec/ruby/core/array/shared/push.rb
+++ /dev/null
@@ -1,33 +0,0 @@
-describe :array_push, shared: true do
- it "appends the arguments to the array" do
- a = [ "a", "b", "c" ]
- a.send(@method, "d", "e", "f").should equal(a)
- a.send(@method).should == ["a", "b", "c", "d", "e", "f"]
- a.send(@method, 5)
- a.should == ["a", "b", "c", "d", "e", "f", 5]
-
- a = [0, 1]
- a.send(@method, 2)
- a.should == [0, 1, 2]
- end
-
- it "isn't confused by previous shift" do
- a = [ "a", "b", "c" ]
- a.shift
- a.send(@method, "foo")
- a.should == ["b", "c", "foo"]
- end
-
- it "properly handles recursive arrays" do
- empty = ArraySpecs.empty_recursive_array
- empty.send(@method, :last).should == [empty, :last]
-
- array = ArraySpecs.recursive_array
- array.send(@method, :last).should == [1, 'two', 3.0, array, array, array, array, array, :last]
- end
-
- it "raises a FrozenError on a frozen array" do
- -> { ArraySpecs.frozen_array.send(@method, 1) }.should raise_error(FrozenError)
- -> { ArraySpecs.frozen_array.send(@method) }.should raise_error(FrozenError)
- end
-end
diff --git a/spec/ruby/core/array/shared/replace.rb b/spec/ruby/core/array/shared/replace.rb
deleted file mode 100644
index 9a6e60c1b0..0000000000
--- a/spec/ruby/core/array/shared/replace.rb
+++ /dev/null
@@ -1,60 +0,0 @@
-describe :array_replace, shared: true do
- it "replaces the elements with elements from other array" do
- a = [1, 2, 3, 4, 5]
- b = ['a', 'b', 'c']
- a.send(@method, b).should equal(a)
- a.should == b
- a.should_not equal(b)
-
- a.send(@method, [4] * 10)
- a.should == [4] * 10
-
- a.send(@method, [])
- a.should == []
- end
-
- it "properly handles recursive arrays" do
- orig = [1, 2, 3]
- empty = ArraySpecs.empty_recursive_array
- orig.send(@method, empty)
- orig.should == empty
-
- array = ArraySpecs.recursive_array
- orig.send(@method, array)
- orig.should == array
- end
-
- it "returns self" do
- ary = [1, 2, 3]
- other = [:a, :b, :c]
- ary.send(@method, other).should equal(ary)
- end
-
- it "does not make self dependent to the original array" do
- ary = [1, 2, 3]
- other = [:a, :b, :c]
- ary.send(@method, other)
- ary.should == [:a, :b, :c]
- ary << :d
- ary.should == [:a, :b, :c, :d]
- other.should == [:a, :b, :c]
- end
-
- it "tries to convert the passed argument to an Array using #to_ary" do
- obj = mock('to_ary')
- obj.stub!(:to_ary).and_return([1, 2, 3])
- [].send(@method, obj).should == [1, 2, 3]
- end
-
- it "does not call #to_ary on Array subclasses" do
- obj = ArraySpecs::ToAryArray[5, 6, 7]
- obj.should_not_receive(:to_ary)
- [].send(@method, ArraySpecs::ToAryArray[5, 6, 7]).should == [5, 6, 7]
- end
-
- it "raises a FrozenError on a frozen array" do
- -> {
- ArraySpecs.frozen_array.send(@method, ArraySpecs.frozen_array)
- }.should raise_error(FrozenError)
- end
-end
diff --git a/spec/ruby/core/array/shared/select.rb b/spec/ruby/core/array/shared/select.rb
deleted file mode 100644
index 9c2cbf76c4..0000000000
--- a/spec/ruby/core/array/shared/select.rb
+++ /dev/null
@@ -1,35 +0,0 @@
-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
- it_should_behave_like :enumeratorized_with_origin_size
-
- it "returns a new array of elements for which block is true" do
- [1, 3, 4, 5, 6, 9].send(@method) { |i| i % ((i + 1) / 2) == 0}.should == [1, 4, 6]
- end
-
- it "does not return subclass instance on Array subclasses" do
- ArraySpecs::MyArray[1, 2, 3].send(@method) { true }.should be_an_instance_of(Array)
- end
-
- it "properly handles recursive arrays" do
- empty = ArraySpecs.empty_recursive_array
- empty.send(@method) { true }.should == empty
- empty.send(@method) { false }.should == []
-
- array = ArraySpecs.recursive_array
- array.send(@method) { true }.should == [1, 'two', 3.0, array, array, array, array, array]
- array.send(@method) { false }.should == []
- end
-end
diff --git a/spec/ruby/core/array/shared/slice.rb b/spec/ruby/core/array/shared/slice.rb
deleted file mode 100644
index b80261d32f..0000000000
--- a/spec/ruby/core/array/shared/slice.rb
+++ /dev/null
@@ -1,857 +0,0 @@
-describe :array_slice, shared: true do
- it "returns the element at index with [index]" do
- [ "a", "b", "c", "d", "e" ].send(@method, 1).should == "b"
-
- a = [1, 2, 3, 4]
-
- a.send(@method, 0).should == 1
- a.send(@method, 1).should == 2
- a.send(@method, 2).should == 3
- a.send(@method, 3).should == 4
- a.send(@method, 4).should == nil
- a.send(@method, 10).should == nil
-
- a.should == [1, 2, 3, 4]
- end
-
- it "returns the element at index from the end of the array with [-index]" do
- [ "a", "b", "c", "d", "e" ].send(@method, -2).should == "d"
-
- a = [1, 2, 3, 4]
-
- a.send(@method, -1).should == 4
- a.send(@method, -2).should == 3
- a.send(@method, -3).should == 2
- a.send(@method, -4).should == 1
- a.send(@method, -5).should == nil
- a.send(@method, -10).should == nil
-
- a.should == [1, 2, 3, 4]
- end
-
- it "returns count elements starting from index with [index, count]" do
- [ "a", "b", "c", "d", "e" ].send(@method, 2, 3).should == ["c", "d", "e"]
-
- a = [1, 2, 3, 4]
-
- a.send(@method, 0, 0).should == []
- a.send(@method, 0, 1).should == [1]
- a.send(@method, 0, 2).should == [1, 2]
- a.send(@method, 0, 4).should == [1, 2, 3, 4]
- a.send(@method, 0, 6).should == [1, 2, 3, 4]
- a.send(@method, 0, -1).should == nil
- a.send(@method, 0, -2).should == nil
- a.send(@method, 0, -4).should == nil
-
- a.send(@method, 2, 0).should == []
- a.send(@method, 2, 1).should == [3]
- a.send(@method, 2, 2).should == [3, 4]
- a.send(@method, 2, 4).should == [3, 4]
- a.send(@method, 2, -1).should == nil
-
- a.send(@method, 4, 0).should == []
- a.send(@method, 4, 2).should == []
- a.send(@method, 4, -1).should == nil
-
- a.send(@method, 5, 0).should == nil
- a.send(@method, 5, 2).should == nil
- a.send(@method, 5, -1).should == nil
-
- a.send(@method, 6, 0).should == nil
- a.send(@method, 6, 2).should == nil
- a.send(@method, 6, -1).should == nil
-
- a.should == [1, 2, 3, 4]
- end
-
- it "returns count elements starting at index from the end of array with [-index, count]" do
- [ "a", "b", "c", "d", "e" ].send(@method, -2, 2).should == ["d", "e"]
-
- a = [1, 2, 3, 4]
-
- a.send(@method, -1, 0).should == []
- a.send(@method, -1, 1).should == [4]
- a.send(@method, -1, 2).should == [4]
- a.send(@method, -1, -1).should == nil
-
- a.send(@method, -2, 0).should == []
- a.send(@method, -2, 1).should == [3]
- a.send(@method, -2, 2).should == [3, 4]
- a.send(@method, -2, 4).should == [3, 4]
- a.send(@method, -2, -1).should == nil
-
- a.send(@method, -4, 0).should == []
- a.send(@method, -4, 1).should == [1]
- a.send(@method, -4, 2).should == [1, 2]
- a.send(@method, -4, 4).should == [1, 2, 3, 4]
- a.send(@method, -4, 6).should == [1, 2, 3, 4]
- a.send(@method, -4, -1).should == nil
-
- a.send(@method, -5, 0).should == nil
- a.send(@method, -5, 1).should == nil
- a.send(@method, -5, 10).should == nil
- a.send(@method, -5, -1).should == nil
-
- a.should == [1, 2, 3, 4]
- end
-
- it "returns the first count elements with [0, count]" do
- [ "a", "b", "c", "d", "e" ].send(@method, 0, 3).should == ["a", "b", "c"]
- end
-
- it "returns the subarray which is independent to self with [index,count]" do
- a = [1, 2, 3]
- sub = a.send(@method, 1,2)
- sub.replace([:a, :b])
- a.should == [1, 2, 3]
- end
-
- it "tries to convert the passed argument to an Integer using #to_int" do
- obj = mock('to_int')
- obj.stub!(:to_int).and_return(2)
-
- a = [1, 2, 3, 4]
- a.send(@method, obj).should == 3
- a.send(@method, obj, 1).should == [3]
- a.send(@method, obj, obj).should == [3, 4]
- a.send(@method, 0, obj).should == [1, 2]
- end
-
- it "raises TypeError if to_int returns non-integer" do
- from = mock('from')
- to = mock('to')
-
- # So we can construct a range out of them...
- def from.<=>(o) 0 end
- def to.<=>(o) 0 end
-
- a = [1, 2, 3, 4, 5]
-
- def from.to_int() 'cat' end
- def to.to_int() -2 end
-
- -> { a.send(@method, from..to) }.should raise_error(TypeError)
-
- def from.to_int() 1 end
- def to.to_int() 'cat' end
-
- -> { a.send(@method, from..to) }.should raise_error(TypeError)
- end
-
- it "returns the elements specified by Range indexes with [m..n]" do
- [ "a", "b", "c", "d", "e" ].send(@method, 1..3).should == ["b", "c", "d"]
- [ "a", "b", "c", "d", "e" ].send(@method, 4..-1).should == ['e']
- [ "a", "b", "c", "d", "e" ].send(@method, 3..3).should == ['d']
- [ "a", "b", "c", "d", "e" ].send(@method, 3..-2).should == ['d']
- ['a'].send(@method, 0..-1).should == ['a']
-
- a = [1, 2, 3, 4]
-
- a.send(@method, 0..-10).should == []
- a.send(@method, 0..0).should == [1]
- a.send(@method, 0..1).should == [1, 2]
- a.send(@method, 0..2).should == [1, 2, 3]
- a.send(@method, 0..3).should == [1, 2, 3, 4]
- a.send(@method, 0..4).should == [1, 2, 3, 4]
- a.send(@method, 0..10).should == [1, 2, 3, 4]
-
- a.send(@method, 2..-10).should == []
- a.send(@method, 2..0).should == []
- a.send(@method, 2..2).should == [3]
- a.send(@method, 2..3).should == [3, 4]
- a.send(@method, 2..4).should == [3, 4]
-
- a.send(@method, 3..0).should == []
- a.send(@method, 3..3).should == [4]
- a.send(@method, 3..4).should == [4]
-
- a.send(@method, 4..0).should == []
- a.send(@method, 4..4).should == []
- a.send(@method, 4..5).should == []
-
- a.send(@method, 5..0).should == nil
- a.send(@method, 5..5).should == nil
- a.send(@method, 5..6).should == nil
-
- a.should == [1, 2, 3, 4]
- end
-
- it "returns elements specified by Range indexes except the element at index n with [m...n]" do
- [ "a", "b", "c", "d", "e" ].send(@method, 1...3).should == ["b", "c"]
-
- a = [1, 2, 3, 4]
-
- a.send(@method, 0...-10).should == []
- a.send(@method, 0...0).should == []
- a.send(@method, 0...1).should == [1]
- a.send(@method, 0...2).should == [1, 2]
- a.send(@method, 0...3).should == [1, 2, 3]
- a.send(@method, 0...4).should == [1, 2, 3, 4]
- a.send(@method, 0...10).should == [1, 2, 3, 4]
-
- a.send(@method, 2...-10).should == []
- a.send(@method, 2...0).should == []
- a.send(@method, 2...2).should == []
- a.send(@method, 2...3).should == [3]
- a.send(@method, 2...4).should == [3, 4]
-
- a.send(@method, 3...0).should == []
- a.send(@method, 3...3).should == []
- a.send(@method, 3...4).should == [4]
-
- a.send(@method, 4...0).should == []
- a.send(@method, 4...4).should == []
- a.send(@method, 4...5).should == []
-
- a.send(@method, 5...0).should == nil
- a.send(@method, 5...5).should == nil
- a.send(@method, 5...6).should == nil
-
- a.should == [1, 2, 3, 4]
- end
-
- it "returns elements that exist if range start is in the array but range end is not with [m..n]" do
- [ "a", "b", "c", "d", "e" ].send(@method, 4..7).should == ["e"]
- end
-
- it "accepts Range instances having a negative m and both signs for n with [m..n] and [m...n]" do
- a = [1, 2, 3, 4]
-
- a.send(@method, -1..-1).should == [4]
- a.send(@method, -1...-1).should == []
- a.send(@method, -1..3).should == [4]
- a.send(@method, -1...3).should == []
- a.send(@method, -1..4).should == [4]
- a.send(@method, -1...4).should == [4]
- a.send(@method, -1..10).should == [4]
- a.send(@method, -1...10).should == [4]
- a.send(@method, -1..0).should == []
- a.send(@method, -1..-4).should == []
- a.send(@method, -1...-4).should == []
- a.send(@method, -1..-6).should == []
- a.send(@method, -1...-6).should == []
-
- a.send(@method, -2..-2).should == [3]
- a.send(@method, -2...-2).should == []
- a.send(@method, -2..-1).should == [3, 4]
- a.send(@method, -2...-1).should == [3]
- a.send(@method, -2..10).should == [3, 4]
- a.send(@method, -2...10).should == [3, 4]
-
- a.send(@method, -4..-4).should == [1]
- a.send(@method, -4..-2).should == [1, 2, 3]
- a.send(@method, -4...-2).should == [1, 2]
- a.send(@method, -4..-1).should == [1, 2, 3, 4]
- a.send(@method, -4...-1).should == [1, 2, 3]
- a.send(@method, -4..3).should == [1, 2, 3, 4]
- a.send(@method, -4...3).should == [1, 2, 3]
- a.send(@method, -4..4).should == [1, 2, 3, 4]
- a.send(@method, -4...4).should == [1, 2, 3, 4]
- a.send(@method, -4...4).should == [1, 2, 3, 4]
- a.send(@method, -4..0).should == [1]
- a.send(@method, -4...0).should == []
- a.send(@method, -4..1).should == [1, 2]
- a.send(@method, -4...1).should == [1]
-
- a.send(@method, -5..-5).should == nil
- a.send(@method, -5...-5).should == nil
- a.send(@method, -5..-4).should == nil
- a.send(@method, -5..-1).should == nil
- a.send(@method, -5..10).should == nil
-
- a.should == [1, 2, 3, 4]
- end
-
- it "returns the subarray which is independent to self with [m..n]" do
- a = [1, 2, 3]
- sub = a.send(@method, 1..2)
- sub.replace([:a, :b])
- a.should == [1, 2, 3]
- end
-
- it "tries to convert Range elements to Integers using #to_int with [m..n] and [m...n]" do
- from = mock('from')
- to = mock('to')
-
- # So we can construct a range out of them...
- def from.<=>(o) 0 end
- def to.<=>(o) 0 end
-
- def from.to_int() 1 end
- def to.to_int() -2 end
-
- a = [1, 2, 3, 4]
-
- a.send(@method, from..to).should == [2, 3]
- a.send(@method, from...to).should == [2]
- a.send(@method, 1..0).should == []
- a.send(@method, 1...0).should == []
-
- -> { a.send(@method, "a" .. "b") }.should raise_error(TypeError)
- -> { a.send(@method, "a" ... "b") }.should raise_error(TypeError)
- -> { a.send(@method, from .. "b") }.should raise_error(TypeError)
- -> { a.send(@method, from ... "b") }.should raise_error(TypeError)
- end
-
- it "returns the same elements as [m..n] and [m...n] with Range subclasses" do
- a = [1, 2, 3, 4]
- range_incl = ArraySpecs::MyRange.new(1, 2)
- range_excl = ArraySpecs::MyRange.new(-3, -1, true)
-
- a.send(@method, range_incl).should == [2, 3]
- a.send(@method, range_excl).should == [2, 3]
- end
-
- it "returns nil for a requested index not in the array with [index]" do
- [ "a", "b", "c", "d", "e" ].send(@method, 5).should == nil
- end
-
- it "returns [] if the index is valid but length is zero with [index, length]" do
- [ "a", "b", "c", "d", "e" ].send(@method, 0, 0).should == []
- [ "a", "b", "c", "d", "e" ].send(@method, 2, 0).should == []
- end
-
- it "returns nil if length is zero but index is invalid with [index, length]" do
- [ "a", "b", "c", "d", "e" ].send(@method, 100, 0).should == nil
- [ "a", "b", "c", "d", "e" ].send(@method, -50, 0).should == nil
- end
-
- # This is by design. It is in the official documentation.
- it "returns [] if index == array.size with [index, length]" do
- %w|a b c d e|.send(@method, 5, 2).should == []
- end
-
- it "returns nil if index > array.size with [index, length]" do
- %w|a b c d e|.send(@method, 6, 2).should == nil
- end
-
- it "returns nil if length is negative with [index, length]" do
- %w|a b c d e|.send(@method, 3, -1).should == nil
- %w|a b c d e|.send(@method, 2, -2).should == nil
- %w|a b c d e|.send(@method, 1, -100).should == nil
- end
-
- it "returns nil if no requested index is in the array with [m..n]" do
- [ "a", "b", "c", "d", "e" ].send(@method, 6..10).should == nil
- end
-
- it "returns nil if range start is not in the array with [m..n]" do
- [ "a", "b", "c", "d", "e" ].send(@method, -10..2).should == nil
- [ "a", "b", "c", "d", "e" ].send(@method, 10..12).should == nil
- end
-
- it "returns an empty array when m == n with [m...n]" do
- [1, 2, 3, 4, 5].send(@method, 1...1).should == []
- end
-
- it "returns an empty array with [0...0]" do
- [1, 2, 3, 4, 5].send(@method, 0...0).should == []
- end
-
- it "returns a subarray where m, n negatives and m < n with [m..n]" do
- [ "a", "b", "c", "d", "e" ].send(@method, -3..-2).should == ["c", "d"]
- end
-
- it "returns an array containing the first element with [0..0]" do
- [1, 2, 3, 4, 5].send(@method, 0..0).should == [1]
- end
-
- it "returns the entire array with [0..-1]" do
- [1, 2, 3, 4, 5].send(@method, 0..-1).should == [1, 2, 3, 4, 5]
- end
-
- it "returns all but the last element with [0...-1]" do
- [1, 2, 3, 4, 5].send(@method, 0...-1).should == [1, 2, 3, 4]
- end
-
- it "returns [3] for [2..-1] out of [1, 2, 3]" do
- [1,2,3].send(@method, 2..-1).should == [3]
- end
-
- it "returns an empty array when m > n and m, n are positive with [m..n]" do
- [1, 2, 3, 4, 5].send(@method, 3..2).should == []
- end
-
- it "returns an empty array when m > n and m, n are negative with [m..n]" do
- [1, 2, 3, 4, 5].send(@method, -2..-3).should == []
- end
-
- it "does not expand array when the indices are outside of the array bounds" do
- a = [1, 2]
- a.send(@method, 4).should == nil
- a.should == [1, 2]
- a.send(@method, 4, 0).should == nil
- a.should == [1, 2]
- a.send(@method, 6, 1).should == nil
- a.should == [1, 2]
- a.send(@method, 8...8).should == nil
- a.should == [1, 2]
- a.send(@method, 10..10).should == nil
- a.should == [1, 2]
- end
-
- describe "with a subclass of Array" do
- before :each do
- ScratchPad.clear
-
- @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
-
- 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
-
- it "returns an empty array when m == n with [m...n]" do
- @array.send(@method, 1...1).should == []
- ScratchPad.recorded.should be_nil
- end
-
- it "returns an empty array with [0...0]" do
- @array.send(@method, 0...0).should == []
- ScratchPad.recorded.should be_nil
- end
-
- it "returns an empty array when m > n and m, n are positive with [m..n]" do
- @array.send(@method, 3..2).should == []
- ScratchPad.recorded.should be_nil
- end
-
- it "returns an empty array when m > n and m, n are negative with [m..n]" do
- @array.send(@method, -2..-3).should == []
- ScratchPad.recorded.should be_nil
- end
-
- it "returns [] if index == array.size with [index, length]" do
- @array.send(@method, 5, 2).should == []
- ScratchPad.recorded.should be_nil
- end
-
- it "returns [] if the index is valid but length is zero with [index, length]" do
- @array.send(@method, 0, 0).should == []
- @array.send(@method, 2, 0).should == []
- ScratchPad.recorded.should be_nil
- end
-
- it "does not call #initialize on the subclass instance" do
- @array.send(@method, 0, 3).should == [1, 2, 3]
- ScratchPad.recorded.should be_nil
- end
- end
-
- it "raises a RangeError when the start index is out of range of Fixnum" do
- array = [1, 2, 3, 4, 5, 6]
- obj = mock('large value')
- obj.should_receive(:to_int).and_return(bignum_value)
- -> { array.send(@method, obj) }.should raise_error(RangeError)
-
- obj = 8e19
- -> { array.send(@method, obj) }.should raise_error(RangeError)
-
- # boundary value when longs are 64 bits
- -> { array.send(@method, 2.0**63) }.should raise_error(RangeError)
-
- # just under the boundary value when longs are 64 bits
- array.send(@method, max_long.to_f.prev_float).should == nil
- end
-
- it "raises a RangeError when the length is out of range of Fixnum" do
- array = [1, 2, 3, 4, 5, 6]
- obj = mock('large value')
- obj.should_receive(:to_int).and_return(bignum_value)
- -> { array.send(@method, 1, obj) }.should raise_error(RangeError)
-
- obj = 8e19
- -> { array.send(@method, 1, obj) }.should raise_error(RangeError)
- end
-
- it "raises a type error if a range is passed with a length" do
- ->{ [1, 2, 3].send(@method, 1..2, 1) }.should raise_error(TypeError)
- end
-
- it "raises a RangeError if passed a range with a bound that is too large" do
- array = [1, 2, 3, 4, 5, 6]
- -> { array.send(@method, bignum_value..(bignum_value + 1)) }.should raise_error(RangeError)
- -> { array.send(@method, 0..bignum_value) }.should raise_error(RangeError)
- end
-
- it "can accept endless ranges" do
- a = [0, 1, 2, 3, 4, 5]
- a.send(@method, eval("(2..)")).should == [2, 3, 4, 5]
- a.send(@method, eval("(2...)")).should == [2, 3, 4, 5]
- a.send(@method, eval("(-2..)")).should == [4, 5]
- a.send(@method, eval("(-2...)")).should == [4, 5]
- a.send(@method, eval("(9..)")).should == nil
- a.send(@method, eval("(9...)")).should == nil
- a.send(@method, eval("(-9..)")).should == nil
- 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
-
- 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("(-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 == []
-
- @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 == []
-
- # 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(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]
-
- @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
-
- 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("(-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 == []
-
- @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 == []
-
- # 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(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]
-
- @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]
-
- # 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(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]
-
- @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
-
- 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(-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 == []
-
- @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 == []
-
- # 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(-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 == []
-
- @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 == []
-
- # 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(-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 == []
-
- @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 == []
-
- # 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(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 == []
-
- @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 == []
-
- # 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(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)
-
- # 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
-
- 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)
- end
- end
-
- it "can accept beginless ranges" do
- a = [0, 1, 2, 3, 4, 5]
- a.send(@method, (..3)).should == [0, 1, 2, 3]
- a.send(@method, (...3)).should == [0, 1, 2]
- a.send(@method, (..-3)).should == [0, 1, 2, 3]
- a.send(@method, (...-3)).should == [0, 1, 2]
- a.send(@method, (..0)).should == [0]
- a.send(@method, (...0)).should == []
- a.send(@method, (..9)).should == [0, 1, 2, 3, 4, 5]
- a.send(@method, (...9)).should == [0, 1, 2, 3, 4, 5]
- a.send(@method, (..-9)).should == []
- a.send(@method, (...-9)).should == []
- end
-
- describe "can be sliced with Enumerator::ArithmeticSequence" do
- it "with infinite/inverted ranges and negative steps" do
- @array = [0, 1, 2, 3, 4, 5]
- @array.send(@method, (2..).step(-1)).should == [2, 1, 0]
- @array.send(@method, (2..).step(-2)).should == [2, 0]
- @array.send(@method, (2..).step(-3)).should == [2]
- @array.send(@method, (2..).step(-4)).should == [2]
-
- @array.send(@method, (-3..).step(-1)).should == [3, 2, 1, 0]
- @array.send(@method, (-3..).step(-2)).should == [3, 1]
- @array.send(@method, (-3..).step(-3)).should == [3, 0]
- @array.send(@method, (-3..).step(-4)).should == [3]
- @array.send(@method, (-3..).step(-5)).should == [3]
-
- @array.send(@method, (..0).step(-1)).should == [5, 4, 3, 2, 1, 0]
- @array.send(@method, (..0).step(-2)).should == [5, 3, 1]
- @array.send(@method, (..0).step(-3)).should == [5, 2]
- @array.send(@method, (..0).step(-4)).should == [5, 1]
- @array.send(@method, (..0).step(-5)).should == [5, 0]
- @array.send(@method, (..0).step(-6)).should == [5]
- @array.send(@method, (..0).step(-7)).should == [5]
-
- @array.send(@method, (...0).step(-1)).should == [5, 4, 3, 2, 1]
- @array.send(@method, (...0).step(-2)).should == [5, 3, 1]
- @array.send(@method, (...0).step(-3)).should == [5, 2]
- @array.send(@method, (...0).step(-4)).should == [5, 1]
- @array.send(@method, (...0).step(-5)).should == [5]
- @array.send(@method, (...0).step(-6)).should == [5]
-
- @array.send(@method, (...1).step(-1)).should == [5, 4, 3, 2]
- @array.send(@method, (...1).step(-2)).should == [5, 3]
- @array.send(@method, (...1).step(-3)).should == [5, 2]
- @array.send(@method, (...1).step(-4)).should == [5]
- @array.send(@method, (...1).step(-5)).should == [5]
-
- @array.send(@method, (..-5).step(-1)).should == [5, 4, 3, 2, 1]
- @array.send(@method, (..-5).step(-2)).should == [5, 3, 1]
- @array.send(@method, (..-5).step(-3)).should == [5, 2]
- @array.send(@method, (..-5).step(-4)).should == [5, 1]
- @array.send(@method, (..-5).step(-5)).should == [5]
- @array.send(@method, (..-5).step(-6)).should == [5]
-
- @array.send(@method, (...-5).step(-1)).should == [5, 4, 3, 2]
- @array.send(@method, (...-5).step(-2)).should == [5, 3]
- @array.send(@method, (...-5).step(-3)).should == [5, 2]
- @array.send(@method, (...-5).step(-4)).should == [5]
- @array.send(@method, (...-5).step(-5)).should == [5]
-
- @array.send(@method, (4..1).step(-1)).should == [4, 3, 2, 1]
- @array.send(@method, (4..1).step(-2)).should == [4, 2]
- @array.send(@method, (4..1).step(-3)).should == [4, 1]
- @array.send(@method, (4..1).step(-4)).should == [4]
- @array.send(@method, (4..1).step(-5)).should == [4]
-
- @array.send(@method, (4...1).step(-1)).should == [4, 3, 2]
- @array.send(@method, (4...1).step(-2)).should == [4, 2]
- @array.send(@method, (4...1).step(-3)).should == [4]
- @array.send(@method, (4...1).step(-4)).should == [4]
-
- @array.send(@method, (-2..1).step(-1)).should == [4, 3, 2, 1]
- @array.send(@method, (-2..1).step(-2)).should == [4, 2]
- @array.send(@method, (-2..1).step(-3)).should == [4, 1]
- @array.send(@method, (-2..1).step(-4)).should == [4]
- @array.send(@method, (-2..1).step(-5)).should == [4]
-
- @array.send(@method, (-2...1).step(-1)).should == [4, 3, 2]
- @array.send(@method, (-2...1).step(-2)).should == [4, 2]
- @array.send(@method, (-2...1).step(-3)).should == [4]
- @array.send(@method, (-2...1).step(-4)).should == [4]
-
- @array.send(@method, (4..-5).step(-1)).should == [4, 3, 2, 1]
- @array.send(@method, (4..-5).step(-2)).should == [4, 2]
- @array.send(@method, (4..-5).step(-3)).should == [4, 1]
- @array.send(@method, (4..-5).step(-4)).should == [4]
- @array.send(@method, (4..-5).step(-5)).should == [4]
-
- @array.send(@method, (4...-5).step(-1)).should == [4, 3, 2]
- @array.send(@method, (4...-5).step(-2)).should == [4, 2]
- @array.send(@method, (4...-5).step(-3)).should == [4]
- @array.send(@method, (4...-5).step(-4)).should == [4]
-
- @array.send(@method, (-2..-5).step(-1)).should == [4, 3, 2, 1]
- @array.send(@method, (-2..-5).step(-2)).should == [4, 2]
- @array.send(@method, (-2..-5).step(-3)).should == [4, 1]
- @array.send(@method, (-2..-5).step(-4)).should == [4]
- @array.send(@method, (-2..-5).step(-5)).should == [4]
-
- @array.send(@method, (-2...-5).step(-1)).should == [4, 3, 2]
- @array.send(@method, (-2...-5).step(-2)).should == [4, 2]
- @array.send(@method, (-2...-5).step(-3)).should == [4]
- @array.send(@method, (-2...-5).step(-4)).should == [4]
- end
- end
-
- it "can accept nil...nil ranges" do
- a = [0, 1, 2, 3, 4, 5]
- a.send(@method, eval("(nil...nil)")).should == a
- a.send(@method, (...nil)).should == a
- a.send(@method, eval("(nil..)")).should == a
- end
-end
diff --git a/spec/ruby/core/array/shared/union.rb b/spec/ruby/core/array/shared/union.rb
index 0b60df9ca4..0b225b9a31 100644
--- a/spec/ruby/core/array/shared/union.rb
+++ b/spec/ruby/core/array/shared/union.rb
@@ -60,9 +60,9 @@ describe :array_binary_union, shared: true do
end
it "does not return subclass instances for Array subclasses" do
- ArraySpecs::MyArray[1, 2, 3].send(@method, []).should be_an_instance_of(Array)
- ArraySpecs::MyArray[1, 2, 3].send(@method, ArraySpecs::MyArray[1, 2, 3]).should be_an_instance_of(Array)
- [].send(@method, ArraySpecs::MyArray[1, 2, 3]).should be_an_instance_of(Array)
+ ArraySpecs::MyArray[1, 2, 3].send(@method, []).should.instance_of?(Array)
+ ArraySpecs::MyArray[1, 2, 3].send(@method, ArraySpecs::MyArray[1, 2, 3]).should.instance_of?(Array)
+ [].send(@method, ArraySpecs::MyArray[1, 2, 3]).should.instance_of?(Array)
end
it "does not call to_ary on array subclasses" do
diff --git a/spec/ruby/core/array/shared/unshift.rb b/spec/ruby/core/array/shared/unshift.rb
deleted file mode 100644
index 4941e098f6..0000000000
--- a/spec/ruby/core/array/shared/unshift.rb
+++ /dev/null
@@ -1,64 +0,0 @@
-describe :array_unshift, shared: true do
- it "prepends object to the original array" do
- a = [1, 2, 3]
- a.send(@method, "a").should equal(a)
- a.should == ['a', 1, 2, 3]
- a.send(@method).should equal(a)
- a.should == ['a', 1, 2, 3]
- a.send(@method, 5, 4, 3)
- a.should == [5, 4, 3, 'a', 1, 2, 3]
-
- # shift all but one element
- a = [1, 2]
- a.shift
- a.send(@method, 3, 4)
- a.should == [3, 4, 2]
-
- # now shift all elements
- a.shift
- a.shift
- a.shift
- a.send(@method, 3, 4)
- a.should == [3, 4]
- end
-
- it "returns self" do
- a = [1, 2, 3]
- a.send(@method, "a").should.equal?(a)
- end
-
- it "quietly ignores unshifting nothing" do
- [].send(@method).should == []
- end
-
- it "properly handles recursive arrays" do
- empty = ArraySpecs.empty_recursive_array
- empty.send(@method, :new).should == [:new, empty]
-
- array = ArraySpecs.recursive_array
- array.send(@method, :new)
- array[0..5].should == [:new, 1, 'two', 3.0, array, array]
- end
-
- it "raises a FrozenError on a frozen array when the array is modified" do
- -> { ArraySpecs.frozen_array.send(@method, 1) }.should raise_error(FrozenError)
- end
-
- # see [ruby-core:23666]
- it "raises a FrozenError on a frozen array when the array would not be modified" do
- -> { ArraySpecs.frozen_array.send(@method) }.should raise_error(FrozenError)
- end
-
- # https://github.com/oracle/truffleruby/issues/2772
- it "doesn't rely on Array#[]= so it can be overridden" do
- subclass = Class.new(Array) do
- def []=(*)
- raise "[]= is called"
- end
- end
-
- array = subclass.new
- array.send(@method, 1)
- array.should == [1]
- end
-end
diff --git a/spec/ruby/core/array/shift_spec.rb b/spec/ruby/core/array/shift_spec.rb
index 6b4ef39f77..09dfa79c45 100644
--- a/spec/ruby/core/array/shift_spec.rb
+++ b/spec/ruby/core/array/shift_spec.rb
@@ -31,10 +31,10 @@ describe "Array#shift" do
end
it "raises a FrozenError on a frozen array" do
- -> { ArraySpecs.frozen_array.shift }.should raise_error(FrozenError)
+ -> { ArraySpecs.frozen_array.shift }.should.raise(FrozenError)
end
it "raises a FrozenError on an empty frozen array" do
- -> { ArraySpecs.empty_frozen_array.shift }.should raise_error(FrozenError)
+ -> { ArraySpecs.empty_frozen_array.shift }.should.raise(FrozenError)
end
describe "passed a number n as an argument" do
@@ -72,7 +72,7 @@ describe "Array#shift" do
popped2.should == []
a.should == []
- popped1.should_not equal(popped2)
+ popped1.should_not.equal?(popped2)
end
it "returns whole elements if n exceeds size of the array" do
@@ -83,14 +83,14 @@ describe "Array#shift" do
it "does not return self even when it returns whole elements" do
a = [1, 2, 3, 4, 5]
- a.shift(5).should_not equal(a)
+ a.shift(5).should_not.equal?(a)
a = [1, 2, 3, 4, 5]
- a.shift(6).should_not equal(a)
+ a.shift(6).should_not.equal?(a)
end
it "raises an ArgumentError if n is negative" do
- ->{ [1, 2, 3].shift(-1) }.should raise_error(ArgumentError)
+ ->{ [1, 2, 3].shift(-1) }.should.raise(ArgumentError)
end
it "tries to convert n to an Integer using #to_int" do
@@ -105,16 +105,16 @@ describe "Array#shift" do
end
it "raises a TypeError when the passed n cannot be coerced to Integer" do
- ->{ [1, 2].shift("cat") }.should raise_error(TypeError)
- ->{ [1, 2].shift(nil) }.should raise_error(TypeError)
+ ->{ [1, 2].shift("cat") }.should.raise(TypeError)
+ ->{ [1, 2].shift(nil) }.should.raise(TypeError)
end
it "raises an ArgumentError if more arguments are passed" do
- ->{ [1, 2].shift(1, 2) }.should raise_error(ArgumentError)
+ ->{ [1, 2].shift(1, 2) }.should.raise(ArgumentError)
end
it "does not return subclass instances with Array subclass" do
- ArraySpecs::MyArray[1, 2, 3].shift(2).should be_an_instance_of(Array)
+ ArraySpecs::MyArray[1, 2, 3].shift(2).should.instance_of?(Array)
end
end
end
diff --git a/spec/ruby/core/array/shuffle_spec.rb b/spec/ruby/core/array/shuffle_spec.rb
index b84394bcb5..9bc9df73ac 100644
--- a/spec/ruby/core/array/shuffle_spec.rb
+++ b/spec/ruby/core/array/shuffle_spec.rb
@@ -10,7 +10,7 @@ describe "Array#shuffle" do
s.sort.should == a
different ||= (a != s)
end
- different.should be_true # Will fail once in a blue moon (4!^10)
+ different.should == true # Will fail once in a blue moon (4!^10)
end
it "is not destructive" do
@@ -22,7 +22,7 @@ describe "Array#shuffle" do
end
it "does not return subclass instances with Array subclass" do
- ArraySpecs::MyArray[1, 2, 3].shuffle.should be_an_instance_of(Array)
+ ArraySpecs::MyArray[1, 2, 3].shuffle.should.instance_of?(Array)
end
it "calls #rand on the Object passed by the :random key in the arguments Hash" do
@@ -31,24 +31,24 @@ describe "Array#shuffle" do
result = [1, 2].shuffle(random: obj)
result.size.should == 2
- result.should include(1, 2)
+ result.sort.should == [1, 2]
end
it "raises a NoMethodError if an object passed for the RNG does not define #rand" do
obj = BasicObject.new
- -> { [1, 2].shuffle(random: obj) }.should raise_error(NoMethodError)
+ -> { [1, 2].shuffle(random: obj) }.should.raise(NoMethodError)
end
it "accepts a Float for the value returned by #rand" do
random = mock("array_shuffle_random")
random.should_receive(:rand).at_least(1).times.and_return(0.3)
- [1, 2].shuffle(random: random).should be_an_instance_of(Array)
+ [1, 2].shuffle(random: random).should.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)
+ [1, 2].shuffle(random: Random).should.instance_of?(Array)
end
it "calls #to_int on the Object returned by #rand" do
@@ -57,7 +57,7 @@ describe "Array#shuffle" do
random = mock("array_shuffle_random")
random.should_receive(:rand).at_least(1).times.and_return(value)
- [1, 2].shuffle(random: random).should be_an_instance_of(Array)
+ [1, 2].shuffle(random: random).should.instance_of?(Array)
end
it "raises a RangeError if the value is less than zero" do
@@ -66,7 +66,7 @@ describe "Array#shuffle" do
random = mock("array_shuffle_random")
random.should_receive(:rand).and_return(value)
- -> { [1, 2].shuffle(random: random) }.should raise_error(RangeError)
+ -> { [1, 2].shuffle(random: random) }.should.raise(RangeError)
end
it "raises a RangeError if the value is equal to the Array size" do
@@ -75,7 +75,7 @@ describe "Array#shuffle" do
random = mock("array_shuffle_random")
random.should_receive(:rand).at_least(1).times.and_return(value)
- -> { [1, 2].shuffle(random: random) }.should raise_error(RangeError)
+ -> { [1, 2].shuffle(random: random) }.should.raise(RangeError)
end
it "raises a RangeError if the value is greater than the Array size" do
@@ -84,7 +84,7 @@ describe "Array#shuffle" do
random = mock("array_shuffle_random")
random.should_receive(:rand).at_least(1).times.and_return(value)
- -> { [1, 2].shuffle(random: random) }.should raise_error(RangeError)
+ -> { [1, 2].shuffle(random: random) }.should.raise(RangeError)
end
end
@@ -98,13 +98,13 @@ describe "Array#shuffle!" do
a.sort.should == [1, 2, 3, 4]
different ||= (a != [1, 2, 3, 4])
end
- different.should be_true # Will fail once in a blue moon (4!^10)
- a.should equal(original)
+ different.should == true # Will fail once in a blue moon (4!^10)
+ a.should.equal?(original)
end
it "raises a FrozenError on a frozen array" do
- -> { ArraySpecs.frozen_array.shuffle! }.should raise_error(FrozenError)
- -> { ArraySpecs.empty_frozen_array.shuffle! }.should raise_error(FrozenError)
+ -> { ArraySpecs.frozen_array.shuffle! }.should.raise(FrozenError)
+ -> { ArraySpecs.empty_frozen_array.shuffle! }.should.raise(FrozenError)
end
it "matches CRuby with random:" do
diff --git a/spec/ruby/core/array/size_spec.rb b/spec/ruby/core/array/size_spec.rb
index d68f956a83..710754ed62 100644
--- a/spec/ruby/core/array/size_spec.rb
+++ b/spec/ruby/core/array/size_spec.rb
@@ -1,7 +1,14 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
-require_relative 'shared/length'
describe "Array#size" do
- it_behaves_like :array_length, :size
+ it "returns the number of elements" do
+ [].size.should == 0
+ [1, 2, 3].size.should == 3
+ end
+
+ it "properly handles recursive arrays" do
+ ArraySpecs.empty_recursive_array.size.should == 1
+ ArraySpecs.recursive_array.size.should == 8
+ end
end
diff --git a/spec/ruby/core/array/slice_spec.rb b/spec/ruby/core/array/slice_spec.rb
index 731c129251..230d1dc5d1 100644
--- a/spec/ruby/core/array/slice_spec.rb
+++ b/spec/ruby/core/array/slice_spec.rb
@@ -1,6 +1,5 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
-require_relative 'shared/slice'
describe "Array#slice!" do
it "removes and return the element at index" do
@@ -116,8 +115,8 @@ describe "Array#slice!" do
a.slice!(from .. to).should == [2, 3, 4]
a.should == [1, 5]
- -> { a.slice!("a" .. "b") }.should raise_error(TypeError)
- -> { a.slice!(from .. "b") }.should raise_error(TypeError)
+ -> { a.slice!("a" .. "b") }.should.raise(TypeError)
+ -> { a.slice!(from .. "b") }.should.raise(TypeError)
end
it "returns last element for consecutive calls at zero index" do
@@ -151,7 +150,7 @@ describe "Array#slice!" do
end
it "raises a FrozenError on a frozen array" do
- -> { ArraySpecs.frozen_array.slice!(0, 0) }.should raise_error(FrozenError)
+ -> { ArraySpecs.frozen_array.slice!(0, 0) }.should.raise(FrozenError)
end
it "works with endless ranges" do
@@ -188,31 +187,33 @@ describe "Array#slice!" do
end
it "returns a Array instance with [n, m]" do
- @array.slice!(0, 2).should be_an_instance_of(Array)
+ @array.slice!(0, 2).should.instance_of?(Array)
end
it "returns a Array instance with [-n, m]" do
- @array.slice!(-3, 2).should be_an_instance_of(Array)
+ @array.slice!(-3, 2).should.instance_of?(Array)
end
it "returns a Array instance with [n..m]" do
- @array.slice!(1..3).should be_an_instance_of(Array)
+ @array.slice!(1..3).should.instance_of?(Array)
end
it "returns a Array instance with [n...m]" do
- @array.slice!(1...3).should be_an_instance_of(Array)
+ @array.slice!(1...3).should.instance_of?(Array)
end
it "returns a Array instance with [-n..-m]" do
- @array.slice!(-3..-1).should be_an_instance_of(Array)
+ @array.slice!(-3..-1).should.instance_of?(Array)
end
it "returns a Array instance with [-n...-m]" do
- @array.slice!(-3...-1).should be_an_instance_of(Array)
+ @array.slice!(-3...-1).should.instance_of?(Array)
end
end
end
describe "Array#slice" do
- it_behaves_like :array_slice, :slice
+ it "is an alias of Array#[]" do
+ Array.instance_method(:slice).should == Array.instance_method(:[])
+ end
end
diff --git a/spec/ruby/core/array/sort_by_spec.rb b/spec/ruby/core/array/sort_by_spec.rb
index 0334f953f6..132abb028a 100644
--- a/spec/ruby/core/array/sort_by_spec.rb
+++ b/spec/ruby/core/array/sort_by_spec.rb
@@ -11,30 +11,30 @@ describe "Array#sort_by!" do
end
it "returns an Enumerator if not given a block" do
- (1..10).to_a.sort_by!.should be_an_instance_of(Enumerator)
+ (1..10).to_a.sort_by!.should.instance_of?(Enumerator)
end
it "completes when supplied a block that always returns the same result" do
a = [2, 3, 5, 1, 4]
a.sort_by!{ 1 }
- a.should be_an_instance_of(Array)
+ a.should.instance_of?(Array)
a.sort_by!{ 0 }
- a.should be_an_instance_of(Array)
+ a.should.instance_of?(Array)
a.sort_by!{ -1 }
- a.should be_an_instance_of(Array)
+ a.should.instance_of?(Array)
end
it "raises a FrozenError on a frozen array" do
- -> { ArraySpecs.frozen_array.sort_by! {}}.should raise_error(FrozenError)
+ -> { ArraySpecs.frozen_array.sort_by! {}}.should.raise(FrozenError)
end
it "raises a FrozenError on an empty frozen array" do
- -> { ArraySpecs.empty_frozen_array.sort_by! {}}.should raise_error(FrozenError)
+ -> { ArraySpecs.empty_frozen_array.sort_by! {}}.should.raise(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)
+ -> { enum.each {} }.should.raise(FrozenError)
end
it "returns the specified value when it would break in the given block" do
@@ -47,7 +47,7 @@ describe "Array#sort_by!" do
ary.sort_by!{|x,y| break if x==i; x<=>y}
ary
}
- partially_sorted.any?{|ary| ary != [1, 2, 3, 4, 5]}.should be_true
+ partially_sorted.any?{|ary| ary != [1, 2, 3, 4, 5]}.should == true
end
it "changes nothing when called on a single element array" do
diff --git a/spec/ruby/core/array/sort_spec.rb b/spec/ruby/core/array/sort_spec.rb
index e20b650516..27300c3385 100644
--- a/spec/ruby/core/array/sort_spec.rb
+++ b/spec/ruby/core/array/sort_spec.rb
@@ -42,7 +42,7 @@ describe "Array#sort" do
a = [1, 2, 3]
sorted = a.sort
sorted.should == a
- sorted.should_not equal(a)
+ sorted.should_not.equal?(a)
end
it "properly handles recursive arrays" do
@@ -68,7 +68,7 @@ describe "Array#sort" do
-> {
[o, 1].sort
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
it "may take a block which is used to determine the order of objects a and b described as -1, 0 or +1" do
@@ -78,28 +78,28 @@ describe "Array#sort" do
end
it "raises an error when a given block returns nil" do
- -> { [1, 2].sort {} }.should raise_error(ArgumentError)
+ -> { [1, 2].sort {} }.should.raise(ArgumentError)
end
it "does not call #<=> on contained objects when invoked with a block" do
a = Array.new(25)
(0...25).each {|i| a[i] = ArraySpecs::UFOSceptic.new }
- a.sort { -1 }.should be_an_instance_of(Array)
+ a.sort { -1 }.should.instance_of?(Array)
end
it "does not call #<=> on elements when invoked with a block even if Array is large (Rubinius #412)" do
a = Array.new(1500)
(0...1500).each {|i| a[i] = ArraySpecs::UFOSceptic.new }
- a.sort { -1 }.should be_an_instance_of(Array)
+ a.sort { -1 }.should.instance_of?(Array)
end
it "completes when supplied a block that always returns the same result" do
a = [2, 3, 5, 1, 4]
- a.sort { 1 }.should be_an_instance_of(Array)
- a.sort { 0 }.should be_an_instance_of(Array)
- a.sort { -1 }.should be_an_instance_of(Array)
+ a.sort { 1 }.should.instance_of?(Array)
+ a.sort { 0 }.should.instance_of?(Array)
+ a.sort { -1 }.should.instance_of?(Array)
end
it "does not freezes self during being sorted" do
@@ -136,7 +136,7 @@ describe "Array#sort" do
}.should == [-4, 1, 2, 5, 7, 10, 12]
-> {
a.sort { |n, m| (n - m).to_s }
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
it "sorts an array that has a value shifted off without a block" do
@@ -155,7 +155,7 @@ describe "Array#sort" do
it "raises an error if objects can't be compared" do
a=[ArraySpecs::Uncomparable.new, ArraySpecs::Uncomparable.new]
- -> {a.sort}.should raise_error(ArgumentError)
+ -> {a.sort}.should.raise(ArgumentError)
end
# From a strange Rubinius bug
@@ -166,7 +166,7 @@ describe "Array#sort" do
it "does not return subclass instance on Array subclasses" do
ary = ArraySpecs::MyArray[1, 2, 3]
- ary.sort.should be_an_instance_of(Array)
+ ary.sort.should.instance_of?(Array)
end
end
@@ -184,13 +184,13 @@ describe "Array#sort!" do
it "returns self if the order of elements changed" do
a = [6, 7, 2, 3, 7]
- a.sort!.should equal(a)
+ a.sort!.should.equal?(a)
a.should == [2, 3, 6, 7, 7]
end
it "returns self even if makes no modification" do
a = [1, 2, 3, 4, 5]
- a.sort!.should equal(a)
+ a.sort!.should.equal?(a)
a.should == [1, 2, 3, 4, 5]
end
@@ -216,25 +216,25 @@ describe "Array#sort!" do
a = Array.new(25)
(0...25).each {|i| a[i] = ArraySpecs::UFOSceptic.new }
- a.sort! { -1 }.should be_an_instance_of(Array)
+ a.sort! { -1 }.should.instance_of?(Array)
end
it "does not call #<=> on elements when invoked with a block even if Array is large (Rubinius #412)" do
a = Array.new(1500)
(0...1500).each {|i| a[i] = ArraySpecs::UFOSceptic.new }
- a.sort! { -1 }.should be_an_instance_of(Array)
+ a.sort! { -1 }.should.instance_of?(Array)
end
it "completes when supplied a block that always returns the same result" do
a = [2, 3, 5, 1, 4]
- a.sort!{ 1 }.should be_an_instance_of(Array)
- a.sort!{ 0 }.should be_an_instance_of(Array)
- a.sort!{ -1 }.should be_an_instance_of(Array)
+ a.sort!{ 1 }.should.instance_of?(Array)
+ a.sort!{ 0 }.should.instance_of?(Array)
+ a.sort!{ -1 }.should.instance_of?(Array)
end
it "raises a FrozenError on a frozen array" do
- -> { ArraySpecs.frozen_array.sort! }.should raise_error(FrozenError)
+ -> { ArraySpecs.frozen_array.sort! }.should.raise(FrozenError)
end
it "returns the specified value when it would break in the given block" do
@@ -247,6 +247,6 @@ describe "Array#sort!" do
ary.sort!{|x,y| break if x==i; x<=>y}
ary
}
- partially_sorted.any?{|ary| ary != [1, 2, 3, 4, 5]}.should be_true
+ partially_sorted.any?{|ary| ary != [1, 2, 3, 4, 5]}.should == true
end
end
diff --git a/spec/ruby/core/array/sum_spec.rb b/spec/ruby/core/array/sum_spec.rb
index 06abe06135..cd4ba4c2d8 100644
--- a/spec/ruby/core/array/sum_spec.rb
+++ b/spec/ruby/core/array/sum_spec.rb
@@ -60,11 +60,11 @@ describe "Array#sum" do
end
it 'raises TypeError if any element are not numeric' do
- -> { ["a"].sum }.should raise_error(TypeError)
+ -> { ["a"].sum }.should.raise(TypeError)
end
it 'raises TypeError if any element cannot be added to init value' do
- -> { [1].sum([]) }.should raise_error(TypeError)
+ -> { [1].sum([]) }.should.raise(TypeError)
end
it "calls + to sum the elements" do
@@ -74,13 +74,11 @@ describe "Array#sum" do
[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
+ 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
diff --git a/spec/ruby/core/array/take_spec.rb b/spec/ruby/core/array/take_spec.rb
index c4f0ac9aa4..837c734b77 100644
--- a/spec/ruby/core/array/take_spec.rb
+++ b/spec/ruby/core/array/take_spec.rb
@@ -23,10 +23,10 @@ describe "Array#take" do
end
it "raises an ArgumentError when the argument is negative" do
- ->{ [1].take(-3) }.should raise_error(ArgumentError)
+ ->{ [1].take(-3) }.should.raise(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)
+ ArraySpecs::MyArray[1, 2, 3, 4, 5].take(1).should.instance_of?(Array)
end
end
diff --git a/spec/ruby/core/array/take_while_spec.rb b/spec/ruby/core/array/take_while_spec.rb
index 8f50260b42..7811edab9e 100644
--- a/spec/ruby/core/array/take_while_spec.rb
+++ b/spec/ruby/core/array/take_while_spec.rb
@@ -16,7 +16,7 @@ describe "Array#take_while" do
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)
+ ArraySpecs::MyArray[1, 2, 3, 4, 5].take_while { |n| n < 4 }.should.instance_of?(Array)
end
end
diff --git a/spec/ruby/core/array/to_a_spec.rb b/spec/ruby/core/array/to_a_spec.rb
index 49d0a4782e..078de1638a 100644
--- a/spec/ruby/core/array/to_a_spec.rb
+++ b/spec/ruby/core/array/to_a_spec.rb
@@ -5,12 +5,12 @@ describe "Array#to_a" do
it "returns self" do
a = [1, 2, 3]
a.to_a.should == [1, 2, 3]
- a.should equal(a.to_a)
+ a.should.equal?(a.to_a)
end
it "does not return subclass instance on Array subclasses" do
e = ArraySpecs::MyArray.new(1, 2)
- e.to_a.should be_an_instance_of(Array)
+ e.to_a.should.instance_of?(Array)
e.to_a.should == [1, 2]
end
diff --git a/spec/ruby/core/array/to_ary_spec.rb b/spec/ruby/core/array/to_ary_spec.rb
index 314699b709..dc5193158d 100644
--- a/spec/ruby/core/array/to_ary_spec.rb
+++ b/spec/ruby/core/array/to_ary_spec.rb
@@ -4,9 +4,9 @@ require_relative 'fixtures/classes'
describe "Array#to_ary" do
it "returns self" do
a = [1, 2, 3]
- a.should equal(a.to_ary)
+ a.should.equal?(a.to_ary)
a = ArraySpecs::MyArray[1, 2, 3]
- a.should equal(a.to_ary)
+ a.should.equal?(a.to_ary)
end
it "properly handles recursive arrays" do
diff --git a/spec/ruby/core/array/to_h_spec.rb b/spec/ruby/core/array/to_h_spec.rb
index 1c814f3d01..1d626763c2 100644
--- a/spec/ruby/core/array/to_h_spec.rb
+++ b/spec/ruby/core/array/to_h_spec.rb
@@ -25,19 +25,19 @@ describe "Array#to_h" do
end
it "raises TypeError if an element is not an array" do
- -> { [:x].to_h }.should raise_error(TypeError)
+ -> { [:x].to_h }.should.raise(TypeError)
end
it "raises ArgumentError if an element is not a [key, value] pair" do
- -> { [[:x]].to_h }.should raise_error(ArgumentError)
+ -> { [[:x]].to_h }.should.raise(ArgumentError)
end
it "does not accept arguments" do
- -> { [].to_h(:a, :b) }.should raise_error(ArgumentError)
+ -> { [].to_h(:a, :b) }.should.raise(ArgumentError)
end
it "produces a hash that returns nil for a missing element" do
- [[:a, 1], [:b, 2]].to_h[:c].should be_nil
+ [[:a, 1], [:b, 2]].to_h[:c].should == nil
end
context "with block" do
@@ -54,17 +54,17 @@ describe "Array#to_h" do
it "raises ArgumentError if block returns longer or shorter array" do
-> do
[:a, :b].to_h { |k| [k, k.to_s, 1] }
- end.should raise_error(ArgumentError, /wrong array length at 0/)
+ end.should.raise(ArgumentError, /wrong array length at 0/)
-> do
[:a, :b].to_h { |k| [k] }
- end.should raise_error(ArgumentError, /wrong array length at 0/)
+ end.should.raise(ArgumentError, /wrong array length at 0/)
end
it "raises TypeError if block returns something other than Array" do
-> do
[:a, :b].to_h { |k| "not-array" }
- end.should raise_error(TypeError, /wrong element type String at 0/)
+ end.should.raise(TypeError, /wrong element type String at 0/)
end
it "coerces returned pair to Array with #to_ary" do
@@ -80,7 +80,7 @@ describe "Array#to_h" do
-> do
[:a].to_h { |k| x }
- end.should raise_error(TypeError, /wrong element type MockObject at 0/)
+ end.should.raise(TypeError, /wrong element type MockObject at 0/)
end
end
end
diff --git a/spec/ruby/core/array/to_s_spec.rb b/spec/ruby/core/array/to_s_spec.rb
index e8476702ec..483e14f902 100644
--- a/spec/ruby/core/array/to_s_spec.rb
+++ b/spec/ruby/core/array/to_s_spec.rb
@@ -1,8 +1,7 @@
require_relative '../../spec_helper'
-require_relative 'fixtures/classes'
-require_relative 'shared/join'
-require_relative 'shared/inspect'
describe "Array#to_s" do
- it_behaves_like :array_inspect, :to_s
+ it "is an alias of Array#inspect" do
+ Array.instance_method(:to_s).should == Array.instance_method(:inspect)
+ end
end
diff --git a/spec/ruby/core/array/transpose_spec.rb b/spec/ruby/core/array/transpose_spec.rb
index b39077f4c9..d45e9c351c 100644
--- a/spec/ruby/core/array/transpose_spec.rb
+++ b/spec/ruby/core/array/transpose_spec.rb
@@ -32,7 +32,7 @@ describe "Array#transpose" do
end
it "raises a TypeError if the passed Argument does not respond to #to_ary" do
- -> { [Object.new, [:a, :b]].transpose }.should raise_error(TypeError)
+ -> { [Object.new, [:a, :b]].transpose }.should.raise(TypeError)
end
it "does not call to_ary on array subclass elements" do
@@ -41,13 +41,13 @@ describe "Array#transpose" do
end
it "raises an IndexError if the arrays are not of the same length" do
- -> { [[1, 2], [:a]].transpose }.should raise_error(IndexError)
+ -> { [[1, 2], [:a]].transpose }.should.raise(IndexError)
end
it "does not return subclass instance on Array subclasses" do
result = ArraySpecs::MyArray[ArraySpecs::MyArray[1, 2, 3], ArraySpecs::MyArray[4, 5, 6]].transpose
- result.should be_an_instance_of(Array)
- result[0].should be_an_instance_of(Array)
- result[1].should be_an_instance_of(Array)
+ result.should.instance_of?(Array)
+ result[0].should.instance_of?(Array)
+ result[1].should.instance_of?(Array)
end
end
diff --git a/spec/ruby/core/array/try_convert_spec.rb b/spec/ruby/core/array/try_convert_spec.rb
index bea8815006..3eaa0f4b7c 100644
--- a/spec/ruby/core/array/try_convert_spec.rb
+++ b/spec/ruby/core/array/try_convert_spec.rb
@@ -4,47 +4,47 @@ require_relative 'fixtures/classes'
describe "Array.try_convert" do
it "returns the argument if it's an Array" do
x = Array.new
- Array.try_convert(x).should equal(x)
+ Array.try_convert(x).should.equal?(x)
end
it "returns the argument if it's a kind of Array" do
x = ArraySpecs::MyArray[]
- Array.try_convert(x).should equal(x)
+ Array.try_convert(x).should.equal?(x)
end
it "returns nil when the argument does not respond to #to_ary" do
- Array.try_convert(Object.new).should be_nil
+ Array.try_convert(Object.new).should == nil
end
it "sends #to_ary to the argument and returns the result if it's nil" do
obj = mock("to_ary")
obj.should_receive(:to_ary).and_return(nil)
- Array.try_convert(obj).should be_nil
+ Array.try_convert(obj).should == nil
end
it "sends #to_ary to the argument and returns the result if it's an Array" do
x = Array.new
obj = mock("to_ary")
obj.should_receive(:to_ary).and_return(x)
- Array.try_convert(obj).should equal(x)
+ Array.try_convert(obj).should.equal?(x)
end
it "sends #to_ary to the argument and returns the result if it's a kind of Array" do
x = ArraySpecs::MyArray[]
obj = mock("to_ary")
obj.should_receive(:to_ary).and_return(x)
- Array.try_convert(obj).should equal(x)
+ Array.try_convert(obj).should.equal?(x)
end
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_consistent_error(TypeError, "can't convert MockObject into Array (MockObject#to_ary gives Object)")
end
it "does not rescue exceptions raised by #to_ary" do
obj = mock("to_ary")
obj.should_receive(:to_ary).and_raise(RuntimeError)
- -> { Array.try_convert obj }.should raise_error(RuntimeError)
+ -> { Array.try_convert obj }.should.raise(RuntimeError)
end
end
diff --git a/spec/ruby/core/array/union_spec.rb b/spec/ruby/core/array/union_spec.rb
index ba2cc0d6b7..110894e83d 100644
--- a/spec/ruby/core/array/union_spec.rb
+++ b/spec/ruby/core/array/union_spec.rb
@@ -15,7 +15,7 @@ describe "Array#union" do
end
it "does not return subclass instances for Array subclasses" do
- ArraySpecs::MyArray[1, 2, 3].union.should be_an_instance_of(Array)
+ ArraySpecs::MyArray[1, 2, 3].union.should.instance_of?(Array)
end
it "accepts multiple arguments" do
diff --git a/spec/ruby/core/array/uniq_spec.rb b/spec/ruby/core/array/uniq_spec.rb
index d5d826db15..0289bee7c2 100644
--- a/spec/ruby/core/array/uniq_spec.rb
+++ b/spec/ruby/core/array/uniq_spec.rb
@@ -86,7 +86,7 @@ describe "Array#uniq" do
end
it "returns Array instance on Array subclasses" do
- ArraySpecs::MyArray[1, 2, 3].uniq.should be_an_instance_of(Array)
+ ArraySpecs::MyArray[1, 2, 3].uniq.should.instance_of?(Array)
end
it "properly handles an identical item even when its #eql? isn't reflexive" do
@@ -138,7 +138,7 @@ describe "Array#uniq!" do
it "returns self" do
a = [ "a", "a", "b", "b", "c" ]
- a.should equal(a.uniq!)
+ a.should.equal?(a.uniq!)
end
it "properly handles recursive arrays" do
@@ -185,17 +185,17 @@ describe "Array#uniq!" do
it "raises a FrozenError on a frozen array when the array is modified" do
dup_ary = [1, 1, 2]
dup_ary.freeze
- -> { dup_ary.uniq! }.should raise_error(FrozenError)
+ -> { dup_ary.uniq! }.should.raise(FrozenError)
end
# see [ruby-core:23666]
it "raises a FrozenError on a frozen array when the array would not be modified" do
- -> { ArraySpecs.frozen_array.uniq!}.should raise_error(FrozenError)
- -> { ArraySpecs.empty_frozen_array.uniq!}.should raise_error(FrozenError)
+ -> { ArraySpecs.frozen_array.uniq!}.should.raise(FrozenError)
+ -> { ArraySpecs.empty_frozen_array.uniq!}.should.raise(FrozenError)
end
it "doesn't yield to the block on a frozen array" do
- -> { ArraySpecs.frozen_array.uniq!{ raise RangeError, "shouldn't yield"}}.should raise_error(FrozenError)
+ -> { ArraySpecs.frozen_array.uniq!{ raise RangeError, "shouldn't yield"}}.should.raise(FrozenError)
end
it "compares elements based on the value returned from the block" do
diff --git a/spec/ruby/core/array/unshift_spec.rb b/spec/ruby/core/array/unshift_spec.rb
index b8b675e5f8..c190db4d02 100644
--- a/spec/ruby/core/array/unshift_spec.rb
+++ b/spec/ruby/core/array/unshift_spec.rb
@@ -1,7 +1,67 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
-require_relative 'shared/unshift'
describe "Array#unshift" do
- it_behaves_like :array_unshift, :unshift
+ it "prepends object to the original array" do
+ a = [1, 2, 3]
+ a.unshift("a").should.equal?(a)
+ a.should == ['a', 1, 2, 3]
+ a.unshift.should.equal?(a)
+ a.should == ['a', 1, 2, 3]
+ a.unshift(5, 4, 3)
+ a.should == [5, 4, 3, 'a', 1, 2, 3]
+
+ # shift all but one element
+ a = [1, 2]
+ a.shift
+ a.unshift(3, 4)
+ a.should == [3, 4, 2]
+
+ # now shift all elements
+ a.shift
+ a.shift
+ a.shift
+ a.unshift(3, 4)
+ a.should == [3, 4]
+ end
+
+ it "returns self" do
+ a = [1, 2, 3]
+ a.unshift("a").should.equal?(a)
+ end
+
+ it "quietly ignores unshifting nothing" do
+ [].unshift.should == []
+ end
+
+ it "properly handles recursive arrays" do
+ empty = ArraySpecs.empty_recursive_array
+ empty.unshift(:new).should == [:new, empty]
+
+ array = ArraySpecs.recursive_array
+ array.unshift(:new)
+ array[0..5].should == [:new, 1, 'two', 3.0, array, array]
+ end
+
+ it "raises a FrozenError on a frozen array when the array is modified" do
+ -> { ArraySpecs.frozen_array.unshift(1) }.should.raise(FrozenError)
+ end
+
+ # see [ruby-core:23666]
+ it "raises a FrozenError on a frozen array when the array would not be modified" do
+ -> { ArraySpecs.frozen_array.unshift }.should.raise(FrozenError)
+ end
+
+ # https://github.com/truffleruby/truffleruby/issues/2772
+ it "doesn't rely on Array#[]= so it can be overridden" do
+ subclass = Class.new(Array) do
+ def []=(*)
+ raise "[]= is called"
+ end
+ end
+
+ array = subclass.new
+ array.unshift(1)
+ array.should == [1]
+ end
end
diff --git a/spec/ruby/core/array/values_at_spec.rb b/spec/ruby/core/array/values_at_spec.rb
index e85bbee400..e11e7e4451 100644
--- a/spec/ruby/core/array/values_at_spec.rb
+++ b/spec/ruby/core/array/values_at_spec.rb
@@ -59,7 +59,7 @@ describe "Array#values_at" do
end
it "does not return subclass instance on Array subclasses" do
- ArraySpecs::MyArray[1, 2, 3].values_at(0, 1..2, 1).should be_an_instance_of(Array)
+ ArraySpecs::MyArray[1, 2, 3].values_at(0, 1..2, 1).should.instance_of?(Array)
end
it "works when given endless ranges" do
diff --git a/spec/ruby/core/array/zip_spec.rb b/spec/ruby/core/array/zip_spec.rb
index 2a0f64cb49..3ccdf143d6 100644
--- a/spec/ruby/core/array/zip_spec.rb
+++ b/spec/ruby/core/array/zip_spec.rb
@@ -60,12 +60,12 @@ describe "Array#zip" do
end
it "does not return subclass instance on Array subclasses" do
- ArraySpecs::MyArray[1, 2, 3].zip(["a", "b"]).should be_an_instance_of(Array)
+ ArraySpecs::MyArray[1, 2, 3].zip(["a", "b"]).should.instance_of?(Array)
end
it "raises TypeError when some argument isn't Array and doesn't respond to #to_ary and #to_enum" do
- -> { [1, 2, 3].zip(Object.new) }.should raise_error(TypeError, "wrong argument type Object (must respond to :each)")
- -> { [1, 2, 3].zip(1) }.should raise_error(TypeError, "wrong argument type Integer (must respond to :each)")
- -> { [1, 2, 3].zip(true) }.should raise_error(TypeError, "wrong argument type TrueClass (must respond to :each)")
+ -> { [1, 2, 3].zip(Object.new) }.should.raise(TypeError, "wrong argument type Object (must respond to :each)")
+ -> { [1, 2, 3].zip(1) }.should.raise(TypeError, "wrong argument type Integer (must respond to :each)")
+ -> { [1, 2, 3].zip(true) }.should.raise(TypeError, "wrong argument type TrueClass (must respond to :each)")
end
end
diff --git a/spec/ruby/core/basicobject/__send___spec.rb b/spec/ruby/core/basicobject/__send___spec.rb
index 005b1d0d90..2f814e448c 100644
--- a/spec/ruby/core/basicobject/__send___spec.rb
+++ b/spec/ruby/core/basicobject/__send___spec.rb
@@ -3,7 +3,7 @@ require_relative '../../shared/basicobject/send'
describe "BasicObject#__send__" do
it "is a public instance method" do
- BasicObject.should have_public_instance_method(:__send__)
+ BasicObject.public_instance_methods(false).should.include?(:__send__)
end
it_behaves_like :basicobject_send, :__send__
diff --git a/spec/ruby/core/basicobject/basicobject_spec.rb b/spec/ruby/core/basicobject/basicobject_spec.rb
index 27a322e72c..af28de0687 100644
--- a/spec/ruby/core/basicobject/basicobject_spec.rb
+++ b/spec/ruby/core/basicobject/basicobject_spec.rb
@@ -8,23 +8,23 @@ describe "BasicObject" do
end
it "raises NameError when referencing built-in constants" do
- -> { class BasicObjectSpecs::BOSubclass; Kernel; end }.should raise_error(NameError)
+ -> { class BasicObjectSpecs::BOSubclass; Kernel; end }.should.raise(NameError)
end
it "does not define built-in constants (according to const_defined?)" do
- BasicObject.const_defined?(:Kernel).should be_false
+ BasicObject.const_defined?(:Kernel).should == false
end
it "does not define built-in constants (according to defined?)" do
- BasicObjectSpecs::BOSubclass.kernel_defined?.should be_nil
+ BasicObjectSpecs::BOSubclass.kernel_defined?.should == nil
end
it "is included in Object's list of constants" do
- Object.constants(false).should include(:BasicObject)
+ Object.constants(false).should.include?(:BasicObject)
end
it "includes itself in its list of constants" do
- BasicObject.constants(false).should include(:BasicObject)
+ BasicObject.constants(false).should.include?(:BasicObject)
end
end
@@ -34,11 +34,11 @@ describe "BasicObject metaclass" do
end
it "is an instance of Class" do
- @meta.should be_an_instance_of(Class)
+ @meta.should.instance_of?(Class)
end
it "has Class as superclass" do
- @meta.superclass.should equal(Class)
+ @meta.superclass.should.equal?(Class)
end
it "contains methods for the BasicObject class" do
@@ -57,11 +57,11 @@ describe "BasicObject instance metaclass" do
end
it "is an instance of Class" do
- @meta.should be_an_instance_of(Class)
+ @meta.should.instance_of?(Class)
end
it "has BasicObject as superclass" do
- @meta.superclass.should equal(BasicObject)
+ @meta.superclass.should.equal?(BasicObject)
end
it "contains methods defined for the BasicObject instance" do
@@ -85,7 +85,7 @@ describe "BasicObject subclass" do
describe "BasicObject references" do
it "can refer to BasicObject from within itself" do
- -> { BasicObject::BasicObject }.should_not raise_error
+ -> { BasicObject::BasicObject }.should_not.raise
end
end
end
diff --git a/spec/ruby/core/basicobject/equal_spec.rb b/spec/ruby/core/basicobject/equal_spec.rb
index ce28eaed95..f27f0d7aca 100644
--- a/spec/ruby/core/basicobject/equal_spec.rb
+++ b/spec/ruby/core/basicobject/equal_spec.rb
@@ -1,54 +1,7 @@
require_relative '../../spec_helper'
-require_relative '../../shared/kernel/equal'
describe "BasicObject#equal?" do
- it "is a public instance method" do
- BasicObject.should have_public_instance_method(:equal?)
- end
-
- it_behaves_like :object_equal, :equal?
-
- it "is unaffected by overriding __id__" do
- o1 = mock("object")
- o2 = mock("object")
- suppress_warning {
- def o1.__id__; 10; end
- def o2.__id__; 10; end
- }
- o1.equal?(o2).should be_false
- end
-
- it "is unaffected by overriding object_id" do
- o1 = mock("object")
- o1.stub!(:object_id).and_return(10)
- o2 = mock("object")
- o2.stub!(:object_id).and_return(10)
- o1.equal?(o2).should be_false
- end
-
- it "is unaffected by overriding ==" do
- # different objects, overriding == to return true
- o1 = mock("object")
- o1.stub!(:==).and_return(true)
- o2 = mock("object")
- o1.equal?(o2).should be_false
-
- # same objects, overriding == to return false
- o3 = mock("object")
- o3.stub!(:==).and_return(false)
- o3.equal?(o3).should be_true
- end
-
- it "is unaffected by overriding eql?" do
- # different objects, overriding eql? to return true
- o1 = mock("object")
- o1.stub!(:eql?).and_return(true)
- o2 = mock("object")
- o1.equal?(o2).should be_false
-
- # same objects, overriding eql? to return false
- o3 = mock("object")
- o3.stub!(:eql?).and_return(false)
- o3.equal?(o3).should be_true
+ it "is an alias of BasicObject#==" do
+ BasicObject.instance_method(:equal?).should == BasicObject.instance_method(:==)
end
end
diff --git a/spec/ruby/core/basicobject/equal_value_spec.rb b/spec/ruby/core/basicobject/equal_value_spec.rb
index 6c825513c1..15755a44a2 100644
--- a/spec/ruby/core/basicobject/equal_value_spec.rb
+++ b/spec/ruby/core/basicobject/equal_value_spec.rb
@@ -3,8 +3,52 @@ require_relative '../../shared/kernel/equal'
describe "BasicObject#==" do
it "is a public instance method" do
- BasicObject.should have_public_instance_method(:==)
+ BasicObject.public_instance_methods(false).should.include?(:==)
end
it_behaves_like :object_equal, :==
+
+ it "is unaffected by overriding __id__" do
+ o1 = mock("object")
+ o2 = mock("object")
+ suppress_warning {
+ def o1.__id__; 10; end
+ def o2.__id__; 10; end
+ }
+ (o1 == o2).should == false
+ end
+
+ it "is unaffected by overriding object_id" do
+ o1 = mock("object")
+ o1.stub!(:object_id).and_return(10)
+ o2 = mock("object")
+ o2.stub!(:object_id).and_return(10)
+ (o1 == o2).should == false
+ end
+
+ it "is unaffected by overriding equal?" do
+ # different objects, overriding equal? to return true
+ o1 = mock("object")
+ o1.stub!(:equal?).and_return(true)
+ o2 = mock("object")
+ (o1 == o2).should == false
+
+ # same objects, overriding equal? to return false
+ o3 = mock("object")
+ o3.stub!(:equal?).and_return(false)
+ (o3 == o3).should == true
+ end
+
+ it "is unaffected by overriding eql?" do
+ # different objects, overriding eql? to return true
+ o1 = mock("object")
+ o1.stub!(:eql?).and_return(true)
+ o2 = mock("object")
+ (o1 == o2).should == false
+
+ # same objects, overriding eql? to return false
+ o3 = mock("object")
+ o3.stub!(:eql?).and_return(false)
+ (o3 == o3).should == true
+ end
end
diff --git a/spec/ruby/core/basicobject/initialize_spec.rb b/spec/ruby/core/basicobject/initialize_spec.rb
index b7ce73ffd5..09e86676b6 100644
--- a/spec/ruby/core/basicobject/initialize_spec.rb
+++ b/spec/ruby/core/basicobject/initialize_spec.rb
@@ -2,12 +2,12 @@ require_relative '../../spec_helper'
describe "BasicObject#initialize" do
it "is a private instance method" do
- BasicObject.should have_private_instance_method(:initialize)
+ BasicObject.private_instance_methods(false).should.include?(:initialize)
end
it "does not accept arguments" do
-> {
BasicObject.new("This", "makes it easier", "to call super", "from other constructors")
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
end
diff --git a/spec/ruby/core/basicobject/instance_eval_spec.rb b/spec/ruby/core/basicobject/instance_eval_spec.rb
index 633b5c2cb1..124d179b5a 100644
--- a/spec/ruby/core/basicobject/instance_eval_spec.rb
+++ b/spec/ruby/core/basicobject/instance_eval_spec.rb
@@ -7,31 +7,31 @@ describe "BasicObject#instance_eval" do
end
it "is a public instance method" do
- BasicObject.should have_public_instance_method(:instance_eval)
+ BasicObject.public_instance_methods(false).should.include?(:instance_eval)
end
it "sets self to the receiver in the context of the passed block" do
a = BasicObject.new
- a.instance_eval { self }.equal?(a).should be_true
+ a.instance_eval { self }.equal?(a).should == true
end
it "evaluates strings" do
a = BasicObject.new
- a.instance_eval('self').equal?(a).should be_true
+ a.instance_eval('self').equal?(a).should == true
end
it "raises an ArgumentError when no arguments and no block are given" do
- -> { "hola".instance_eval }.should raise_error(ArgumentError, "wrong number of arguments (given 0, expected 1..3)")
+ -> { "hola".instance_eval }.should.raise(ArgumentError, "wrong number of arguments (given 0, expected 1..3)")
end
it "raises an ArgumentError when a block and normal arguments are given" do
- -> { "hola".instance_eval(4, 5) {|a,b| a + b } }.should raise_error(ArgumentError, "wrong number of arguments (given 2, expected 0)")
+ -> { "hola".instance_eval(4, 5) {|a,b| a + b } }.should.raise(ArgumentError, "wrong number of arguments (given 2, expected 0)")
end
it "raises an ArgumentError when more than 3 arguments are given" do
-> {
"hola".instance_eval("1 + 1", "some file", 0, "bogus")
- }.should raise_error(ArgumentError, "wrong number of arguments (given 4, expected 1..3)")
+ }.should.raise(ArgumentError, "wrong number of arguments (given 4, expected 1..3)")
end
it "yields the object to the block" do
@@ -51,7 +51,7 @@ describe "BasicObject#instance_eval" do
end
end
f.foo.should == 1
- -> { Object.new.foo }.should raise_error(NoMethodError)
+ -> { Object.new.foo }.should.raise(NoMethodError)
end
it "preserves self in the original block when passed a block argument" do
@@ -71,9 +71,9 @@ describe "BasicObject#instance_eval" do
it "binds self to the receiver" do
s = "hola"
- (s == s.instance_eval { self }).should be_true
+ (s == s.instance_eval { self }).should == true
o = mock('o')
- (o == o.instance_eval("self")).should be_true
+ (o == o.instance_eval("self")).should == true
end
it "executes in the context of the receiver" do
@@ -84,11 +84,9 @@ 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
+ it "uses the caller location as default location" do
+ f = Object.new
+ f.instance_eval("[__FILE__, __LINE__]").should == ["(eval at #{__FILE__}:#{__LINE__})", 1]
end
it "has access to receiver's instance variables" do
@@ -97,15 +95,15 @@ describe "BasicObject#instance_eval" do
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")
+ -> { nil.instance_eval { @foo = 42 } }.should.raise(FrozenError, "can't modify frozen NilClass: nil")
+ -> { true.instance_eval { @foo = 42 } }.should.raise(FrozenError, "can't modify frozen TrueClass: true")
+ -> { false.instance_eval { @foo = 42 } }.should.raise(FrozenError, "can't modify frozen FalseClass: false")
+ -> { 1.instance_eval { @foo = 42 } }.should.raise(FrozenError, "can't modify frozen Integer: 1")
+ -> { :symbol.instance_eval { @foo = 42 } }.should.raise(FrozenError, "can't modify frozen Symbol: :symbol")
obj = Object.new
obj.freeze
- -> { obj.instance_eval { @foo = 42 } }.should raise_error(FrozenError)
+ -> { obj.instance_eval { @foo = 42 } }.should.raise(FrozenError)
end
it "treats block-local variables as local to the block" do
@@ -130,7 +128,7 @@ describe "BasicObject#instance_eval" do
class B; end
B
}
- obj.singleton_class.const_get(:B).should be_an_instance_of(Class)
+ obj.singleton_class.const_get(:B).should.instance_of?(Class)
end
describe "constants lookup when a String given" do
@@ -171,16 +169,16 @@ describe "BasicObject#instance_eval" do
end
it "doesn't get constants in the receiver if a block given" do
- BasicObjectSpecs::InstEvalOuter::Inner::X_BY_BLOCK.should be_nil
+ BasicObjectSpecs::InstEvalOuter::Inner::X_BY_BLOCK.should == nil
end
it "raises a TypeError when defining methods on an immediate" do
-> do
1.instance_eval { def foo; end }
- end.should raise_error(TypeError)
+ end.should.raise(TypeError)
-> do
:foo.instance_eval { def foo; end }
- end.should raise_error(TypeError)
+ end.should.raise(TypeError)
end
describe "class variables lookup" do
@@ -219,23 +217,23 @@ describe "BasicObject#instance_eval" do
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/)
+ -> { caller.get_class_variable_with_string(receiver) }.should.raise(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/)
+ -> { caller.get_class_variable_with_string(receiver) }.should.raise(NameError, /uninitialized class variable @@cvar/)
end
end
it "raises a TypeError when defining methods on numerics" do
-> do
(1.0).instance_eval { def foo; end }
- end.should raise_error(TypeError)
+ end.should.raise(TypeError)
-> do
(1 << 64).instance_eval { def foo; end }
- end.should raise_error(TypeError)
+ end.should.raise(TypeError)
end
it "evaluates procs originating from methods" do
@@ -286,7 +284,7 @@ describe "BasicObject#instance_eval" do
def source_code.to_str() :symbol end
a = BasicObject.new
- -> { a.instance_eval(source_code) }.should raise_error(TypeError, /can't convert Object to String/)
+ -> { a.instance_eval(source_code) }.should raise_consistent_error(TypeError, /can't convert Object into String/)
end
it "converts filename argument with #to_str method" do
@@ -305,7 +303,7 @@ describe "BasicObject#instance_eval" do
filename = Object.new
def filename.to_str() :symbol end
- -> { Object.new.instance_eval("raise", filename) }.should raise_error(TypeError, /can't convert Object to String/)
+ -> { Object.new.instance_eval("raise", filename) }.should raise_consistent_error(TypeError, /can't convert Object into String/)
end
it "converts lineno argument with #to_int method" do
@@ -324,6 +322,6 @@ describe "BasicObject#instance_eval" do
lineno = Object.new
def lineno.to_int() :symbol end
- -> { Object.new.instance_eval("raise", "file.rb", lineno) }.should raise_error(TypeError, /can't convert Object to Integer/)
+ -> { Object.new.instance_eval("raise", "file.rb", lineno) }.should raise_consistent_error(TypeError, /can't convert Object into Integer/)
end
end
diff --git a/spec/ruby/core/basicobject/instance_exec_spec.rb b/spec/ruby/core/basicobject/instance_exec_spec.rb
index 370f03d33c..cfce9a65ad 100644
--- a/spec/ruby/core/basicobject/instance_exec_spec.rb
+++ b/spec/ruby/core/basicobject/instance_exec_spec.rb
@@ -3,21 +3,21 @@ require_relative 'fixtures/classes'
describe "BasicObject#instance_exec" do
it "is a public instance method" do
- BasicObject.should have_public_instance_method(:instance_exec)
+ BasicObject.public_instance_methods(false).should.include?(:instance_exec)
end
it "sets self to the receiver in the context of the passed block" do
a = BasicObject.new
- a.instance_exec { self }.equal?(a).should be_true
+ a.instance_exec { self }.equal?(a).should == true
end
it "passes arguments to the block" do
a = BasicObject.new
- a.instance_exec(1) { |b| b }.should equal(1)
+ a.instance_exec(1) { |b| b }.should.equal?(1)
end
it "raises a LocalJumpError unless given a block" do
- -> { "hola".instance_exec }.should raise_error(LocalJumpError)
+ -> { "hola".instance_exec }.should.raise(LocalJumpError)
end
it "has an arity of -1" do
@@ -25,17 +25,23 @@ describe "BasicObject#instance_exec" do
end
it "accepts arguments with a block" do
- -> { "hola".instance_exec(4, 5) { |a,b| a + b } }.should_not raise_error
+ -> { "hola".instance_exec(4, 5) { |a,b| a + b } }.should_not.raise
end
it "doesn't pass self to the block as an argument" do
- "hola".instance_exec { |o| o }.should be_nil
+ "hola".instance_exec { |o| o }.should == nil
end
it "passes any arguments to the block" do
Object.new.instance_exec(1,2) {|one, two| one + two}.should == 3
end
+ describe "with optional argument" do
+ it "does not destructure a single array argument" do
+ Object.new.instance_exec([1, 2, 3]) { |a = 99| a }.should == [1, 2, 3]
+ end
+ end
+
it "only binds the exec to the receiver" do
f = Object.new
f.instance_exec do
@@ -44,7 +50,7 @@ describe "BasicObject#instance_exec" do
end
end
f.foo.should == 1
- -> { Object.new.foo }.should raise_error(NoMethodError)
+ -> { Object.new.foo }.should.raise(NoMethodError)
end
# TODO: This should probably be replaced with a "should behave like" that uses
@@ -71,17 +77,17 @@ describe "BasicObject#instance_exec" do
end
it "sets class variables in the receiver" do
- BasicObjectSpecs::InstExec.class_variables.should include(:@@count)
+ BasicObjectSpecs::InstExec.class_variables.should.include?(:@@count)
BasicObjectSpecs::InstExec.send(:class_variable_get, :@@count).should == 2
end
it "raises a TypeError when defining methods on an immediate" do
-> do
1.instance_exec { def foo; end }
- end.should raise_error(TypeError)
+ end.should.raise(TypeError)
-> do
:foo.instance_exec { def foo; end }
- end.should raise_error(TypeError)
+ end.should.raise(TypeError)
end
quarantine! do # Not clean, leaves cvars lying around to break other specs
@@ -99,9 +105,9 @@ describe "BasicObject#instance_exec" do
it "raises a TypeError when defining methods on numerics" do
-> do
(1.0).instance_exec { def foo; end }
- end.should raise_error(TypeError)
+ end.should.raise(TypeError)
-> do
(1 << 64).instance_exec { def foo; end }
- end.should raise_error(TypeError)
+ end.should.raise(TypeError)
end
end
diff --git a/spec/ruby/core/basicobject/method_missing_spec.rb b/spec/ruby/core/basicobject/method_missing_spec.rb
index a29d4375bc..8785b41b21 100644
--- a/spec/ruby/core/basicobject/method_missing_spec.rb
+++ b/spec/ruby/core/basicobject/method_missing_spec.rb
@@ -3,7 +3,7 @@ require_relative '../../shared/basicobject/method_missing'
describe "BasicObject#method_missing" do
it "is a private method" do
- BasicObject.should have_private_instance_method(:method_missing)
+ BasicObject.private_instance_methods(false).should.include?(:method_missing)
end
end
diff --git a/spec/ruby/core/basicobject/not_equal_spec.rb b/spec/ruby/core/basicobject/not_equal_spec.rb
index 9329128c43..29b14b0fff 100644
--- a/spec/ruby/core/basicobject/not_equal_spec.rb
+++ b/spec/ruby/core/basicobject/not_equal_spec.rb
@@ -2,24 +2,24 @@ require_relative '../../spec_helper'
describe "BasicObject#!=" do
it "is a public instance method" do
- BasicObject.should have_public_instance_method(:'!=')
+ BasicObject.public_instance_methods(false).should.include?(:'!=')
end
it "returns true if other is not identical to self" do
a = BasicObject.new
b = BasicObject.new
- (a != b).should be_true
+ (a != b).should == true
end
it "returns true if other is an Object" do
a = BasicObject.new
b = Object.new
- (a != b).should be_true
+ (a != b).should == true
end
it "returns false if other is identical to self" do
a = BasicObject.new
- (a != a).should be_false
+ (a != a).should == false
end
it "dispatches to #==" do
@@ -27,19 +27,19 @@ describe "BasicObject#!=" do
b = BasicObject.new
a.should_receive(:==).and_return(true)
- (a != b).should be_false
+ (a != b).should == false
end
describe "when invoked using Kernel#send" do
it "returns true if other is not identical to self" do
a = Object.new
b = Object.new
- a.send(:!=, b).should be_true
+ a.send(:!=, b).should == true
end
it "returns false if other is identical to self" do
a = Object.new
- a.send(:!=, a).should be_false
+ a.send(:!=, a).should == false
end
it "dispatches to #==" do
@@ -47,7 +47,7 @@ describe "BasicObject#!=" do
b = Object.new
a.should_receive(:==).and_return(true)
- a.send(:!=, b).should be_false
+ a.send(:!=, b).should == false
end
end
end
diff --git a/spec/ruby/core/basicobject/not_spec.rb b/spec/ruby/core/basicobject/not_spec.rb
index ca4cb6f5ff..a6f58ae6f5 100644
--- a/spec/ruby/core/basicobject/not_spec.rb
+++ b/spec/ruby/core/basicobject/not_spec.rb
@@ -2,10 +2,10 @@ require_relative '../../spec_helper'
describe "BasicObject#!" do
it "is a public instance method" do
- BasicObject.should have_public_instance_method(:'!')
+ BasicObject.public_instance_methods(false).should.include?(:'!')
end
it "returns false" do
- (!BasicObject.new).should be_false
+ (!BasicObject.new).should == false
end
end
diff --git a/spec/ruby/core/basicobject/singleton_method_added_spec.rb b/spec/ruby/core/basicobject/singleton_method_added_spec.rb
index bd21458ea7..f39b91768c 100644
--- a/spec/ruby/core/basicobject/singleton_method_added_spec.rb
+++ b/spec/ruby/core/basicobject/singleton_method_added_spec.rb
@@ -7,7 +7,7 @@ describe "BasicObject#singleton_method_added" do
end
it "is a private method" do
- BasicObject.should have_private_instance_method(:singleton_method_added)
+ BasicObject.private_instance_methods(false).should.include?(:singleton_method_added)
end
it "is called when a singleton method is defined on an object" do
@@ -35,7 +35,7 @@ describe "BasicObject#singleton_method_added" do
end
end
- ScratchPad.recorded.should_not include(:new_instance_method)
+ ScratchPad.recorded.should_not.include?(:new_instance_method)
end
it "is called when a singleton method is defined on a module" do
@@ -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(NoMethodError, /undefined method [`']singleton_method_added' for/)
end
ensure
BasicObjectSpecs.send(:remove_const, :NoSingletonMethodAdded)
@@ -108,16 +108,16 @@ describe "BasicObject#singleton_method_added" do
-> {
def foo
end
- }.should raise_error(NoMethodError, /undefined method [`']singleton_method_added' for #<Object:/)
+ }.should.raise(NoMethodError, /undefined method [`']singleton_method_added' for #<Object:/)
-> {
define_method(:bar) {}
- }.should raise_error(NoMethodError, /undefined method [`']singleton_method_added' for #<Object:/)
+ }.should.raise(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(NoMethodError, /undefined method [`']singleton_method_added' for #<Object:/)
end
it "calls #method_missing" do
diff --git a/spec/ruby/core/basicobject/singleton_method_removed_spec.rb b/spec/ruby/core/basicobject/singleton_method_removed_spec.rb
index 46f9a6894c..1831e3c070 100644
--- a/spec/ruby/core/basicobject/singleton_method_removed_spec.rb
+++ b/spec/ruby/core/basicobject/singleton_method_removed_spec.rb
@@ -6,7 +6,7 @@ describe "BasicObject#singleton_method_removed" do
end
it "is a private method" do
- BasicObject.should have_private_instance_method(:singleton_method_removed)
+ BasicObject.private_instance_methods(false).should.include?(:singleton_method_removed)
end
it "is called when a method is removed on self" do
diff --git a/spec/ruby/core/basicobject/singleton_method_undefined_spec.rb b/spec/ruby/core/basicobject/singleton_method_undefined_spec.rb
index 7d6c7207db..cc47341878 100644
--- a/spec/ruby/core/basicobject/singleton_method_undefined_spec.rb
+++ b/spec/ruby/core/basicobject/singleton_method_undefined_spec.rb
@@ -6,7 +6,7 @@ describe "BasicObject#singleton_method_undefined" do
end
it "is a private method" do
- BasicObject.should have_private_instance_method(:singleton_method_undefined)
+ BasicObject.private_instance_methods(false).should.include?(:singleton_method_undefined)
end
it "is called when a method is removed on self" do
diff --git a/spec/ruby/core/binding/dup_spec.rb b/spec/ruby/core/binding/dup_spec.rb
index 4eff66bd9a..f5f0c72d5d 100644
--- a/spec/ruby/core/binding/dup_spec.rb
+++ b/spec/ruby/core/binding/dup_spec.rb
@@ -21,7 +21,7 @@ describe "Binding#dup" do
eval("a", bind2).should == 2
eval("b = 2", bind2)
- -> { eval("b", bind1) }.should raise_error(NameError)
+ -> { eval("b", bind1) }.should.raise(NameError)
eval("b", bind2).should == 2
bind1.local_variables.sort.should == [:a, :bind1, :bind2]
diff --git a/spec/ruby/core/binding/eval_spec.rb b/spec/ruby/core/binding/eval_spec.rb
index bb2036f739..f1d8591320 100644
--- a/spec/ruby/core/binding/eval_spec.rb
+++ b/spec/ruby/core/binding/eval_spec.rb
@@ -7,7 +7,7 @@ describe "Binding#eval" do
bind = obj.get_binding
bind.eval("@secret += square(3)").should == 10
- bind.eval("a").should be_true
+ bind.eval("a").should == true
bind.eval("class Inside; end")
bind.eval("Inside.name").should == "BindingSpecs::Demo::Inside"
@@ -60,14 +60,6 @@ describe "Binding#eval" do
bind.eval("#foo\n__LINE__", "(test)", 88).should == 89
end
- ruby_version_is ""..."3.3" 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
@@ -107,9 +99,7 @@ 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
+ it "uses the caller location as default filename" do
+ binding.eval("[__FILE__, __LINE__]").should == ["(eval at #{__FILE__}:#{__LINE__})", 1]
end
end
diff --git a/spec/ruby/core/binding/local_variable_get_spec.rb b/spec/ruby/core/binding/local_variable_get_spec.rb
index 005670becc..d97100deda 100644
--- a/spec/ruby/core/binding/local_variable_get_spec.rb
+++ b/spec/ruby/core/binding/local_variable_get_spec.rb
@@ -13,7 +13,7 @@ describe "Binding#local_variable_get" do
-> {
bind.local_variable_get(:no_such_variable)
- }.should raise_error(NameError)
+ }.should.raise(NameError)
end
it "reads variables added later to the binding" do
@@ -21,7 +21,7 @@ describe "Binding#local_variable_get" do
-> {
bind.local_variable_get(:a)
- }.should raise_error(NameError)
+ }.should.raise(NameError)
bind.local_variable_set(:a, 42)
@@ -45,12 +45,12 @@ describe "Binding#local_variable_get" do
it "raises a NameError on global access" do
bind = binding
- -> { bind.local_variable_get(:$0) }.should raise_error(NameError)
+ -> { bind.local_variable_get(:$0) }.should.raise(NameError)
end
it "raises a NameError on special variable access" do
bind = binding
- -> { bind.local_variable_get(:$~) }.should raise_error(NameError)
- -> { bind.local_variable_get(:$_) }.should raise_error(NameError)
+ -> { bind.local_variable_get(:$~) }.should.raise(NameError)
+ -> { bind.local_variable_get(:$_) }.should.raise(NameError)
end
end
diff --git a/spec/ruby/core/binding/local_variable_set_spec.rb b/spec/ruby/core/binding/local_variable_set_spec.rb
index 1456c6dda1..3e4f407fc3 100644
--- a/spec/ruby/core/binding/local_variable_set_spec.rb
+++ b/spec/ruby/core/binding/local_variable_set_spec.rb
@@ -38,7 +38,7 @@ describe "Binding#local_variable_set" do
bind = binding
bind.local_variable_set(:number, 10)
- -> { number }.should raise_error(NameError)
+ -> { number }.should.raise(NameError)
end
it 'overwrites an existing local variable defined before a Binding' do
@@ -59,13 +59,13 @@ describe "Binding#local_variable_set" do
it "raises a NameError on global access" do
bind = binding
- -> { bind.local_variable_set(:$0, "") }.should raise_error(NameError)
+ -> { bind.local_variable_set(:$0, "") }.should.raise(NameError)
end
it "raises a NameError on special variable access" do
bind = binding
- -> { bind.local_variable_set(:$~, "") }.should raise_error(NameError)
- -> { bind.local_variable_set(:$_, "") }.should raise_error(NameError)
+ -> { bind.local_variable_set(:$~, "") }.should.raise(NameError)
+ -> { bind.local_variable_set(:$_, "") }.should.raise(NameError)
end
end
diff --git a/spec/ruby/core/binding/local_variables_spec.rb b/spec/ruby/core/binding/local_variables_spec.rb
index 92c817b9a8..0f59681342 100644
--- a/spec/ruby/core/binding/local_variables_spec.rb
+++ b/spec/ruby/core/binding/local_variables_spec.rb
@@ -2,7 +2,7 @@ require_relative '../../spec_helper'
describe "Binding#local_variables" do
it "returns an Array" do
- binding.local_variables.should be_kind_of(Array)
+ binding.local_variables.should.is_a?(Array)
end
it "includes local variables in the current scope" do
diff --git a/spec/ruby/core/builtin_constants/builtin_constants_spec.rb b/spec/ruby/core/builtin_constants/builtin_constants_spec.rb
index eaf311783a..67b3339aa6 100644
--- a/spec/ruby/core/builtin_constants/builtin_constants_spec.rb
+++ b/spec/ruby/core/builtin_constants/builtin_constants_spec.rb
@@ -2,7 +2,7 @@ require_relative '../../spec_helper'
describe "RUBY_VERSION" do
it "is a String" do
- RUBY_VERSION.should be_kind_of(String)
+ RUBY_VERSION.should.is_a?(String)
end
it "is frozen" do
@@ -12,13 +12,13 @@ end
describe "RUBY_PATCHLEVEL" do
it "is an Integer" do
- RUBY_PATCHLEVEL.should be_kind_of(Integer)
+ RUBY_PATCHLEVEL.should.is_a?(Integer)
end
end
describe "RUBY_COPYRIGHT" do
it "is a String" do
- RUBY_COPYRIGHT.should be_kind_of(String)
+ RUBY_COPYRIGHT.should.is_a?(String)
end
it "is frozen" do
@@ -28,7 +28,7 @@ end
describe "RUBY_DESCRIPTION" do
it "is a String" do
- RUBY_DESCRIPTION.should be_kind_of(String)
+ RUBY_DESCRIPTION.should.is_a?(String)
end
it "is frozen" do
@@ -38,7 +38,7 @@ end
describe "RUBY_ENGINE" do
it "is a String" do
- RUBY_ENGINE.should be_kind_of(String)
+ RUBY_ENGINE.should.is_a?(String)
end
it "is frozen" do
@@ -46,9 +46,19 @@ describe "RUBY_ENGINE" do
end
end
+describe "RUBY_ENGINE_VERSION" do
+ it "is a String" do
+ RUBY_ENGINE_VERSION.should.is_a?(String)
+ end
+
+ it "is frozen" do
+ RUBY_ENGINE_VERSION.should.frozen?
+ end
+end
+
describe "RUBY_PLATFORM" do
it "is a String" do
- RUBY_PLATFORM.should be_kind_of(String)
+ RUBY_PLATFORM.should.is_a?(String)
end
it "is frozen" do
@@ -58,7 +68,7 @@ end
describe "RUBY_RELEASE_DATE" do
it "is a String" do
- RUBY_RELEASE_DATE.should be_kind_of(String)
+ RUBY_RELEASE_DATE.should.is_a?(String)
end
it "is frozen" do
@@ -68,10 +78,72 @@ end
describe "RUBY_REVISION" do
it "is a String" do
- RUBY_REVISION.should be_kind_of(String)
+ RUBY_REVISION.should.is_a?(String)
end
it "is frozen" do
RUBY_REVISION.should.frozen?
end
end
+
+ruby_version_is "4.0" do
+ describe "Ruby" do
+ it "is a Module" do
+ Ruby.should.instance_of?(Module)
+ end
+ end
+
+ describe "Ruby::VERSION" do
+ it "is equal to RUBY_VERSION" do
+ Ruby::VERSION.should.equal?(RUBY_VERSION)
+ end
+ end
+
+ describe "RUBY::PATCHLEVEL" do
+ it "is equal to RUBY_PATCHLEVEL" do
+ Ruby::PATCHLEVEL.should.equal?(RUBY_PATCHLEVEL)
+ end
+ end
+
+ describe "Ruby::COPYRIGHT" do
+ it "is equal to RUBY_COPYRIGHT" do
+ Ruby::COPYRIGHT.should.equal?(RUBY_COPYRIGHT)
+ end
+ end
+
+ describe "Ruby::DESCRIPTION" do
+ it "is equal to RUBY_DESCRIPTION" do
+ Ruby::DESCRIPTION.should.equal?(RUBY_DESCRIPTION)
+ end
+ end
+
+ describe "Ruby::ENGINE" do
+ it "is equal to RUBY_ENGINE" do
+ Ruby::ENGINE.should.equal?(RUBY_ENGINE)
+ end
+ end
+
+ describe "Ruby::ENGINE_VERSION" do
+ it "is equal to RUBY_ENGINE_VERSION" do
+ Ruby::ENGINE_VERSION.should.equal?(RUBY_ENGINE_VERSION)
+ end
+ end
+
+ describe "Ruby::PLATFORM" do
+ it "is equal to RUBY_PLATFORM" do
+ Ruby::PLATFORM.should.equal?(RUBY_PLATFORM)
+ end
+ end
+
+ describe "Ruby::RELEASE_DATE" do
+ it "is equal to RUBY_RELEASE_DATE" do
+ Ruby::RELEASE_DATE.should.equal?(RUBY_RELEASE_DATE)
+ end
+ end
+
+ describe "Ruby::REVISION" do
+ it "is equal to RUBY_REVISION" do
+ Ruby::REVISION.should.equal?(RUBY_REVISION)
+ end
+ end
+end
diff --git a/spec/ruby/core/class/allocate_spec.rb b/spec/ruby/core/class/allocate_spec.rb
index b39622e06a..b8950a678e 100644
--- a/spec/ruby/core/class/allocate_spec.rb
+++ b/spec/ruby/core/class/allocate_spec.rb
@@ -3,7 +3,7 @@ require_relative '../../spec_helper'
describe "Class#allocate" do
it "returns an instance of self" do
klass = Class.new
- klass.allocate.should be_an_instance_of(klass)
+ klass.allocate.should.instance_of?(klass)
end
it "returns a fully-formed instance of Module" do
@@ -16,7 +16,7 @@ describe "Class#allocate" do
klass = Class.allocate
-> do
klass.new
- end.should raise_error(Exception)
+ end.should.raise(Exception)
end
it "does not call initialize on the new instance" do
@@ -36,6 +36,6 @@ describe "Class#allocate" do
it "raises TypeError for #superclass" do
-> do
Class.allocate.superclass
- end.should raise_error(TypeError)
+ end.should.raise(TypeError)
end
end
diff --git a/spec/ruby/core/class/attached_object_spec.rb b/spec/ruby/core/class/attached_object_spec.rb
index 8f8a0734c6..b75e61ca07 100644
--- a/spec/ruby/core/class/attached_object_spec.rb
+++ b/spec/ruby/core/class/attached_object_spec.rb
@@ -18,12 +18,12 @@ describe "Class#attached_object" 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(TypeError, /is not a singleton class/)
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(TypeError, /[`']NilClass' is not a singleton class/)
+ -> { true.singleton_class.attached_object }.should.raise(TypeError, /[`']TrueClass' is not a singleton class/)
+ -> { false.singleton_class.attached_object }.should.raise(TypeError, /[`']FalseClass' is not a singleton class/)
end
end
diff --git a/spec/ruby/core/class/dup_spec.rb b/spec/ruby/core/class/dup_spec.rb
index 1ff9abf7b4..17c0171ceb 100644
--- a/spec/ruby/core/class/dup_spec.rb
+++ b/spec/ruby/core/class/dup_spec.rb
@@ -53,7 +53,7 @@ describe "Class#dup" do
it "sets the name from the class to nil if not assigned to a constant" do
copy = CoreClassSpecs::Record.dup
- copy.name.should be_nil
+ copy.name.should == nil
end
it "stores the new name if assigned to a constant" do
@@ -64,6 +64,6 @@ describe "Class#dup" do
end
it "raises TypeError if called on BasicObject" do
- -> { BasicObject.dup }.should raise_error(TypeError, "can't copy the root class")
+ -> { BasicObject.dup }.should.raise(TypeError, "can't copy the root class")
end
end
diff --git a/spec/ruby/core/class/inherited_spec.rb b/spec/ruby/core/class/inherited_spec.rb
index 2a8d1ff813..c9acc740a1 100644
--- a/spec/ruby/core/class/inherited_spec.rb
+++ b/spec/ruby/core/class/inherited_spec.rb
@@ -92,10 +92,10 @@ describe "Class.inherited" do
end
class << top; private :inherited; end
- -> { Class.new(top) }.should_not raise_error
+ -> { Class.new(top) }.should_not.raise
class << top; protected :inherited; end
- -> { Class.new(top) }.should_not raise_error
+ -> { Class.new(top) }.should_not.raise
end
it "if the subclass is assigned to a constant, it is all set" do
diff --git a/spec/ruby/core/class/initialize_spec.rb b/spec/ruby/core/class/initialize_spec.rb
index 6348758485..ab8f0a157e 100644
--- a/spec/ruby/core/class/initialize_spec.rb
+++ b/spec/ruby/core/class/initialize_spec.rb
@@ -2,24 +2,24 @@ require_relative '../../spec_helper'
describe "Class#initialize" do
it "is private" do
- Class.should have_private_method(:initialize)
+ Class.private_methods(false).should.include?(:initialize)
end
it "raises a TypeError when called on already initialized classes" do
->{
Integer.send :initialize
- }.should raise_error(TypeError)
+ }.should.raise(TypeError)
->{
Object.send :initialize
- }.should raise_error(TypeError)
+ }.should.raise(TypeError)
end
# See [redmine:2601]
it "raises a TypeError when called on BasicObject" do
->{
BasicObject.send :initialize
- }.should raise_error(TypeError)
+ }.should.raise(TypeError)
end
describe "when given the Class" do
@@ -28,7 +28,7 @@ describe "Class#initialize" do
end
it "raises a TypeError" do
- ->{@uninitialized.send(:initialize, Class)}.should raise_error(TypeError)
+ ->{@uninitialized.send(:initialize, Class)}.should.raise(TypeError)
end
end
end
diff --git a/spec/ruby/core/class/new_spec.rb b/spec/ruby/core/class/new_spec.rb
index 6fe54c3209..111e31252e 100644
--- a/spec/ruby/core/class/new_spec.rb
+++ b/spec/ruby/core/class/new_spec.rb
@@ -7,7 +7,7 @@ describe "Class.new with a block given" do
klass = Class.new do
self_in_block = self
end
- self_in_block.should equal klass
+ self_in_block.should.equal? klass
end
it "uses the given block as the class' body" do
@@ -70,11 +70,11 @@ describe "Class.new" do
it "raises a TypeError if passed a metaclass" do
obj = mock("Class.new metaclass")
meta = obj.singleton_class
- -> { Class.new meta }.should raise_error(TypeError)
+ -> { Class.new meta }.should.raise(TypeError)
end
it "creates a class without a name" do
- Class.new.name.should be_nil
+ Class.new.name.should == nil
end
it "creates a class that can be given a name by assigning it to a constant" do
@@ -98,12 +98,12 @@ describe "Class.new" do
it "raises a TypeError when given a non-Class" do
error_msg = /superclass must be a.*Class/
- -> { Class.new("") }.should raise_error(TypeError, error_msg)
- -> { Class.new(1) }.should raise_error(TypeError, error_msg)
- -> { Class.new(:symbol) }.should raise_error(TypeError, error_msg)
- -> { Class.new(mock('o')) }.should raise_error(TypeError, error_msg)
- -> { Class.new(Module.new) }.should raise_error(TypeError, error_msg)
- -> { Class.new(BasicObject.new) }.should raise_error(TypeError, error_msg)
+ -> { Class.new("") }.should.raise(TypeError, error_msg)
+ -> { Class.new(1) }.should.raise(TypeError, error_msg)
+ -> { Class.new(:symbol) }.should.raise(TypeError, error_msg)
+ -> { Class.new(mock('o')) }.should.raise(TypeError, error_msg)
+ -> { Class.new(Module.new) }.should.raise(TypeError, error_msg)
+ -> { Class.new(BasicObject.new) }.should.raise(TypeError, error_msg)
end
end
@@ -141,8 +141,8 @@ describe "Class#new" do
end
instance = klass.new
- instance.should be_kind_of klass
- instance.class.should equal klass
+ instance.should.is_a? klass
+ instance.class.should.equal? klass
end
it "passes the block to #initialize" do
diff --git a/spec/ruby/core/class/subclasses_spec.rb b/spec/ruby/core/class/subclasses_spec.rb
index f692152787..c3d7b07e12 100644
--- a/spec/ruby/core/class/subclasses_spec.rb
+++ b/spec/ruby/core/class/subclasses_spec.rb
@@ -50,7 +50,7 @@ describe "Class#subclasses" do
42
end
- a.subclasses.should_not include(a_obj.singleton_class)
+ a.subclasses.should_not.include?(a_obj.singleton_class)
end
it "has 1 entry per module or class" do
@@ -76,7 +76,7 @@ describe "Class#subclasses" do
classes = threads.map(&:value)
superclass.subclasses.size.should == t * n
- superclass.subclasses.each { |c| c.should be_kind_of(Class) }
+ superclass.subclasses.each { |c| c.should.is_a?(Class) }
end
def assert_subclasses(mod,subclasses)
diff --git a/spec/ruby/core/class/superclass_spec.rb b/spec/ruby/core/class/superclass_spec.rb
index 00579238a6..87d9b20490 100644
--- a/spec/ruby/core/class/superclass_spec.rb
+++ b/spec/ruby/core/class/superclass_spec.rb
@@ -3,7 +3,7 @@ require_relative 'fixtures/classes'
describe "Class#superclass" do
it "returns the superclass of self" do
- BasicObject.superclass.should be_nil
+ BasicObject.superclass.should == nil
Object.superclass.should == BasicObject
Class.superclass.should == Module
Class.new.superclass.should == Object
diff --git a/spec/ruby/core/comparable/clamp_spec.rb b/spec/ruby/core/comparable/clamp_spec.rb
index 796d4a18c1..eb1dc1ff98 100644
--- a/spec/ruby/core/comparable/clamp_spec.rb
+++ b/spec/ruby/core/comparable/clamp_spec.rb
@@ -7,9 +7,9 @@ describe 'Comparable#clamp' do
two = ComparableSpecs::WithOnlyCompareDefined.new(2)
c = ComparableSpecs::Weird.new(3)
- -> { c.clamp(two, one) }.should raise_error(ArgumentError)
+ -> { c.clamp(two, one) }.should.raise(ArgumentError)
one.should_receive(:<=>).any_number_of_times.and_return(nil)
- -> { c.clamp(one, two) }.should raise_error(ArgumentError)
+ -> { c.clamp(one, two) }.should.raise(ArgumentError)
end
it 'returns self if within the given parameters' do
@@ -18,18 +18,18 @@ describe 'Comparable#clamp' do
three = ComparableSpecs::WithOnlyCompareDefined.new(3)
c = ComparableSpecs::Weird.new(2)
- c.clamp(one, two).should equal(c)
- c.clamp(two, two).should equal(c)
- c.clamp(one, three).should equal(c)
- c.clamp(two, three).should equal(c)
+ c.clamp(one, two).should.equal?(c)
+ c.clamp(two, two).should.equal?(c)
+ c.clamp(one, three).should.equal?(c)
+ c.clamp(two, three).should.equal?(c)
end
- it 'returns the min parameter if smaller than it' do
+ it 'returns the min parameter if less than it' do
one = ComparableSpecs::WithOnlyCompareDefined.new(1)
two = ComparableSpecs::WithOnlyCompareDefined.new(2)
c = ComparableSpecs::Weird.new(0)
- c.clamp(one, two).should equal(one)
+ c.clamp(one, two).should.equal?(one)
end
it 'returns the max parameter if greater than it' do
@@ -37,7 +37,40 @@ describe 'Comparable#clamp' do
two = ComparableSpecs::WithOnlyCompareDefined.new(2)
c = ComparableSpecs::Weird.new(3)
- c.clamp(one, two).should equal(two)
+ c.clamp(one, two).should.equal?(two)
+ end
+
+ context 'max is nil' do
+ it 'returns min if less than it' do
+ one = ComparableSpecs::WithOnlyCompareDefined.new(1)
+ c = ComparableSpecs::Weird.new(0)
+ c.clamp(one, nil).should.equal?(one)
+ end
+
+ it 'always returns self if greater than min' do
+ one = ComparableSpecs::WithOnlyCompareDefined.new(1)
+ c = ComparableSpecs::Weird.new(2)
+ c.clamp(one, nil).should.equal?(c)
+ end
+ end
+
+ context 'min is nil' do
+ it 'returns max if greater than it' do
+ one = ComparableSpecs::WithOnlyCompareDefined.new(1)
+ c = ComparableSpecs::Weird.new(2)
+ c.clamp(nil, one).should.equal?(one)
+ end
+
+ it 'always returns self if less than max' do
+ one = ComparableSpecs::WithOnlyCompareDefined.new(1)
+ c = ComparableSpecs::Weird.new(0)
+ c.clamp(nil, one).should.equal?(c)
+ end
+ end
+
+ it 'always returns self when min is nil and max is nil' do
+ c = ComparableSpecs::Weird.new(1)
+ c.clamp(nil, nil).should.equal?(c)
end
it 'returns self if within the given range parameters' do
@@ -46,18 +79,18 @@ describe 'Comparable#clamp' do
three = ComparableSpecs::WithOnlyCompareDefined.new(3)
c = ComparableSpecs::Weird.new(2)
- c.clamp(one..two).should equal(c)
- c.clamp(two..two).should equal(c)
- c.clamp(one..three).should equal(c)
- c.clamp(two..three).should equal(c)
+ c.clamp(one..two).should.equal?(c)
+ c.clamp(two..two).should.equal?(c)
+ c.clamp(one..three).should.equal?(c)
+ c.clamp(two..three).should.equal?(c)
end
- it 'returns the minimum value of the range parameters if smaller than it' do
+ it 'returns the minimum value of the range parameters if less than it' do
one = ComparableSpecs::WithOnlyCompareDefined.new(1)
two = ComparableSpecs::WithOnlyCompareDefined.new(2)
c = ComparableSpecs::Weird.new(0)
- c.clamp(one..two).should equal(one)
+ c.clamp(one..two).should.equal?(one)
end
it 'returns the maximum value of the range parameters if greater than it' do
@@ -65,7 +98,7 @@ describe 'Comparable#clamp' do
two = ComparableSpecs::WithOnlyCompareDefined.new(2)
c = ComparableSpecs::Weird.new(3)
- c.clamp(one..two).should equal(two)
+ c.clamp(one..two).should.equal?(two)
end
it 'raises an Argument error if the range parameter is exclusive' do
@@ -73,6 +106,118 @@ describe 'Comparable#clamp' do
two = ComparableSpecs::WithOnlyCompareDefined.new(2)
c = ComparableSpecs::Weird.new(3)
- -> { c.clamp(one...two) }.should raise_error(ArgumentError)
+ -> { c.clamp(one...two) }.should.raise(ArgumentError)
+ end
+
+ context 'with nil as the max argument' do
+ it 'returns min argument if less than it' do
+ one = ComparableSpecs::WithOnlyCompareDefined.new(1)
+ zero = ComparableSpecs::WithOnlyCompareDefined.new(0)
+ c = ComparableSpecs::Weird.new(0)
+
+ c.clamp(one, nil).should.equal?(one)
+ c.clamp(zero, nil).should.equal?(c)
+ end
+
+ it 'always returns self if greater than min argument' do
+ one = ComparableSpecs::WithOnlyCompareDefined.new(1)
+ two = ComparableSpecs::WithOnlyCompareDefined.new(2)
+ c = ComparableSpecs::Weird.new(2)
+
+ c.clamp(one, nil).should.equal?(c)
+ c.clamp(two, nil).should.equal?(c)
+ end
+ end
+
+ context 'with endless range' do
+ it 'returns minimum value of the range parameters if less than it' do
+ one = ComparableSpecs::WithOnlyCompareDefined.new(1)
+ zero = ComparableSpecs::WithOnlyCompareDefined.new(0)
+ c = ComparableSpecs::Weird.new(0)
+
+ c.clamp(one..).should.equal?(one)
+ c.clamp(zero..).should.equal?(c)
+ end
+
+ it 'always returns self if greater than minimum value of the range parameters' do
+ one = ComparableSpecs::WithOnlyCompareDefined.new(1)
+ two = ComparableSpecs::WithOnlyCompareDefined.new(2)
+ c = ComparableSpecs::Weird.new(2)
+
+ c.clamp(one..).should.equal?(c)
+ c.clamp(two..).should.equal?(c)
+ end
+
+ it 'works with exclusive range' do
+ one = ComparableSpecs::WithOnlyCompareDefined.new(1)
+ c = ComparableSpecs::Weird.new(2)
+
+ c.clamp(one...).should.equal?(c)
+ end
+ end
+
+ context 'with nil as the min argument' do
+ it 'returns max argument if greater than it' do
+ one = ComparableSpecs::WithOnlyCompareDefined.new(1)
+ c = ComparableSpecs::Weird.new(2)
+
+ c.clamp(nil, one).should.equal?(one)
+ end
+
+ it 'always returns self if less than max argument' do
+ one = ComparableSpecs::WithOnlyCompareDefined.new(1)
+ zero = ComparableSpecs::WithOnlyCompareDefined.new(0)
+ c = ComparableSpecs::Weird.new(0)
+
+ c.clamp(nil, one).should.equal?(c)
+ c.clamp(nil, zero).should.equal?(c)
+ end
+ end
+
+ context 'with beginless range' do
+ it 'returns maximum value of the range parameters if greater than it' do
+ one = ComparableSpecs::WithOnlyCompareDefined.new(1)
+ c = ComparableSpecs::Weird.new(2)
+
+ c.clamp(..one).should.equal?(one)
+ end
+
+ it 'always returns self if less than maximum value of the range parameters' do
+ one = ComparableSpecs::WithOnlyCompareDefined.new(1)
+ zero = ComparableSpecs::WithOnlyCompareDefined.new(0)
+ c = ComparableSpecs::Weird.new(0)
+
+ c.clamp(..one).should.equal?(c)
+ c.clamp(..zero).should.equal?(c)
+ end
+
+ it 'raises an Argument error if the range parameter is exclusive' do
+ one = ComparableSpecs::WithOnlyCompareDefined.new(1)
+ c = ComparableSpecs::Weird.new(0)
+
+ -> { c.clamp(...one) }.should.raise(ArgumentError)
+ end
+ end
+
+ context 'with nil as the min and the max argument' do
+ it 'always returns self' do
+ c = ComparableSpecs::Weird.new(1)
+
+ c.clamp(nil, nil).should.equal?(c)
+ end
+ end
+
+ context 'with beginless-and-endless range' do
+ it 'always returns self' do
+ c = ComparableSpecs::Weird.new(1)
+
+ c.clamp(nil..nil).should.equal?(c)
+ end
+
+ it 'works with exclusive range' do
+ c = ComparableSpecs::Weird.new(2)
+
+ c.clamp(nil...nil).should.equal?(c)
+ end
end
end
diff --git a/spec/ruby/core/comparable/equal_value_spec.rb b/spec/ruby/core/comparable/equal_value_spec.rb
index ddcc03cb41..3af40d1c7e 100644
--- a/spec/ruby/core/comparable/equal_value_spec.rb
+++ b/spec/ruby/core/comparable/equal_value_spec.rb
@@ -39,7 +39,7 @@ describe "Comparable#==" do
end
it "returns false" do
- (a == b).should be_false
+ (a == b).should == false
end
end
@@ -49,7 +49,7 @@ describe "Comparable#==" do
end
it "raises an ArgumentError" do
- -> { (a == b) }.should raise_error(ArgumentError)
+ -> { (a == b) }.should.raise(ArgumentError)
end
end
@@ -60,7 +60,7 @@ describe "Comparable#==" do
end
it "lets it go through" do
- -> { (a == b) }.should raise_error(StandardError)
+ -> { (a == b) }.should.raise(StandardError)
end
end
@@ -71,13 +71,13 @@ describe "Comparable#==" do
end
it "lets it go through" do
- -> { (a == b) }.should raise_error(TypeError)
+ -> { (a == b) }.should.raise(TypeError)
end
end
it "lets it go through if it is not a StandardError" do
a.should_receive(:<=>).once.and_raise(Exception)
- -> { (a == b) }.should raise_error(Exception)
+ -> { (a == b) }.should.raise(Exception)
end
end
diff --git a/spec/ruby/core/comparable/fixtures/classes.rb b/spec/ruby/core/comparable/fixtures/classes.rb
index 4239a47d2f..2bdabbf014 100644
--- a/spec/ruby/core/comparable/fixtures/classes.rb
+++ b/spec/ruby/core/comparable/fixtures/classes.rb
@@ -7,6 +7,7 @@ module ComparableSpecs
end
def <=>(other)
+ return nil if other.nil?
self.value <=> other.value
end
end
diff --git a/spec/ruby/core/comparable/gt_spec.rb b/spec/ruby/core/comparable/gt_spec.rb
index 150e653dc7..cebb5464ad 100644
--- a/spec/ruby/core/comparable/gt_spec.rb
+++ b/spec/ruby/core/comparable/gt_spec.rb
@@ -38,6 +38,6 @@ describe "Comparable#>" do
b = ComparableSpecs::Weird.new(20)
a.should_receive(:<=>).any_number_of_times.and_return(nil)
- -> { (a > b) }.should raise_error(ArgumentError)
+ -> { (a > b) }.should.raise(ArgumentError)
end
end
diff --git a/spec/ruby/core/comparable/gte_spec.rb b/spec/ruby/core/comparable/gte_spec.rb
index 328f58c66c..16da81b3ea 100644
--- a/spec/ruby/core/comparable/gte_spec.rb
+++ b/spec/ruby/core/comparable/gte_spec.rb
@@ -42,6 +42,6 @@ describe "Comparable#>=" do
b = ComparableSpecs::Weird.new(20)
a.should_receive(:<=>).any_number_of_times.and_return(nil)
- -> { (a >= b) }.should raise_error(ArgumentError)
+ -> { (a >= b) }.should.raise(ArgumentError)
end
end
diff --git a/spec/ruby/core/comparable/lt_spec.rb b/spec/ruby/core/comparable/lt_spec.rb
index bca95f8d25..175646d0d7 100644
--- a/spec/ruby/core/comparable/lt_spec.rb
+++ b/spec/ruby/core/comparable/lt_spec.rb
@@ -38,12 +38,12 @@ describe "Comparable#<" do
b = ComparableSpecs::Weird.new(20)
a.should_receive(:<=>).any_number_of_times.and_return(nil)
- -> { (a < b) }.should raise_error(ArgumentError)
+ -> { (a < b) }.should.raise(ArgumentError)
end
it "raises an argument error with a message containing the value" do
- -> { ("foo" < 7) }.should raise_error(ArgumentError) { |e|
- e.message.should == "comparison of String with 7 failed"
+ -> { ("foo" < 7) }.should.raise(ArgumentError) { |e|
+ e.message.should.include? "String with 7 failed"
}
end
end
diff --git a/spec/ruby/core/comparable/lte_spec.rb b/spec/ruby/core/comparable/lte_spec.rb
index b5cb9cc4e7..8cbbd5ebb4 100644
--- a/spec/ruby/core/comparable/lte_spec.rb
+++ b/spec/ruby/core/comparable/lte_spec.rb
@@ -41,6 +41,6 @@ describe "Comparable#<=" do
b = ComparableSpecs::Weird.new(20)
a.should_receive(:<=>).any_number_of_times.and_return(nil)
- -> { (a <= b) }.should raise_error(ArgumentError)
+ -> { (a <= b) }.should.raise(ArgumentError)
end
end
diff --git a/spec/ruby/core/complex/abs_spec.rb b/spec/ruby/core/complex/abs_spec.rb
index 43912c517f..ed5aebb11d 100644
--- a/spec/ruby/core/complex/abs_spec.rb
+++ b/spec/ruby/core/complex/abs_spec.rb
@@ -1,6 +1,12 @@
require_relative '../../spec_helper'
-require_relative 'shared/abs'
describe "Complex#abs" do
- it_behaves_like :complex_abs, :abs
+ it "returns the modulus: |a + bi| = sqrt((a ^ 2) + (b ^ 2))" do
+ Complex(0, 0).abs.should == 0
+ Complex(3, 4).abs.should == 5 # well-known integer case
+ Complex(-3, 4).abs.should == 5
+ Complex(1, -1).abs.should be_close(Math.sqrt(2), TOLERANCE)
+ Complex(6.5, 0).abs.should be_close(6.5, TOLERANCE)
+ Complex(0, -7.2).abs.should be_close(7.2, TOLERANCE)
+ end
end
diff --git a/spec/ruby/core/complex/angle_spec.rb b/spec/ruby/core/complex/angle_spec.rb
index 4aa176956f..7551214d2b 100644
--- a/spec/ruby/core/complex/angle_spec.rb
+++ b/spec/ruby/core/complex/angle_spec.rb
@@ -1,6 +1,7 @@
require_relative '../../spec_helper'
-require_relative 'shared/arg'
describe "Complex#angle" do
- it_behaves_like :complex_arg, :angle
+ it "is an alias of Complex#arg" do
+ Complex.instance_method(:angle).should == Complex.instance_method(:arg)
+ end
end
diff --git a/spec/ruby/core/complex/arg_spec.rb b/spec/ruby/core/complex/arg_spec.rb
index 009f19429f..dd64102d77 100644
--- a/spec/ruby/core/complex/arg_spec.rb
+++ b/spec/ruby/core/complex/arg_spec.rb
@@ -1,6 +1,11 @@
require_relative '../../spec_helper'
-require_relative 'shared/arg'
describe "Complex#arg" do
- it_behaves_like :complex_arg, :arg
+ it "returns the argument -- i.e., the angle from (1, 0) in the complex plane" do
+ two_pi = 2 * Math::PI
+ (Complex(1, 0).arg % two_pi).should be_close(0, TOLERANCE)
+ (Complex(0, 2).arg % two_pi).should be_close(Math::PI * 0.5, TOLERANCE)
+ (Complex(-100, 0).arg % two_pi).should be_close(Math::PI, TOLERANCE)
+ (Complex(0, -75.3).arg % two_pi).should be_close(Math::PI * 1.5, TOLERANCE)
+ end
end
diff --git a/spec/ruby/core/complex/coerce_spec.rb b/spec/ruby/core/complex/coerce_spec.rb
index a30a6c1d5f..d4ea85a713 100644
--- a/spec/ruby/core/complex/coerce_spec.rb
+++ b/spec/ruby/core/complex/coerce_spec.rb
@@ -8,37 +8,37 @@ describe "Complex#coerce" do
it "returns an array containing other and self as Complex when other is an Integer" do
result = @one.coerce(2)
result.should == [2, 1]
- result.first.should be_kind_of(Complex)
- result.last.should be_kind_of(Complex)
+ result.first.should.is_a?(Complex)
+ result.last.should.is_a?(Complex)
end
it "returns an array containing other and self as Complex when other is a Float" do
result = @one.coerce(20.5)
result.should == [20.5, 1]
- result.first.should be_kind_of(Complex)
- result.last.should be_kind_of(Complex)
+ result.first.should.is_a?(Complex)
+ result.last.should.is_a?(Complex)
end
it "returns an array containing other and self as Complex when other is a Bignum" do
result = @one.coerce(4294967296)
result.should == [4294967296, 1]
- result.first.should be_kind_of(Complex)
- result.last.should be_kind_of(Complex)
+ result.first.should.is_a?(Complex)
+ result.last.should.is_a?(Complex)
end
it "returns an array containing other and self as Complex when other is a Rational" do
result = @one.coerce(Rational(5,6))
result.should == [Rational(5,6), 1]
- result.first.should be_kind_of(Complex)
- result.last.should be_kind_of(Complex)
+ result.first.should.is_a?(Complex)
+ result.last.should.is_a?(Complex)
end
it "returns an array containing other and self when other is a Complex" do
other = Complex(2)
result = @one.coerce(other)
result.should == [other, @one]
- result.first.should equal(other)
- result.last.should equal(@one)
+ result.first.should.equal?(other)
+ result.last.should.equal?(@one)
end
it "returns an array containing other as Complex and self when other is a Numeric which responds to #real? with true" do
@@ -46,25 +46,25 @@ describe "Complex#coerce" do
other.should_receive(:real?).any_number_of_times.and_return(true)
result = @one.coerce(other)
result.should == [other, @one]
- result.first.should eql(Complex(other))
- result.last.should equal(@one)
+ result.first.should.eql?(Complex(other))
+ result.last.should.equal?(@one)
end
it "raises TypeError when other is a Numeric which responds to #real? with false" do
other = mock_numeric('other')
other.should_receive(:real?).any_number_of_times.and_return(false)
- -> { @one.coerce(other) }.should raise_error(TypeError)
+ -> { @one.coerce(other) }.should.raise(TypeError)
end
it "raises a TypeError when other is a String" do
- -> { @one.coerce("20") }.should raise_error(TypeError)
+ -> { @one.coerce("20") }.should.raise(TypeError)
end
it "raises a TypeError when other is nil" do
- -> { @one.coerce(nil) }.should raise_error(TypeError)
+ -> { @one.coerce(nil) }.should.raise(TypeError)
end
it "raises a TypeError when other is false" do
- -> { @one.coerce(false) }.should raise_error(TypeError)
+ -> { @one.coerce(false) }.should.raise(TypeError)
end
end
diff --git a/spec/ruby/core/complex/comparison_spec.rb b/spec/ruby/core/complex/comparison_spec.rb
index 3a3142f234..3115f4e205 100644
--- a/spec/ruby/core/complex/comparison_spec.rb
+++ b/spec/ruby/core/complex/comparison_spec.rb
@@ -2,15 +2,15 @@ require_relative '../../spec_helper'
describe "Complex#<=>" do
it "returns nil if either self or argument has imaginary part" do
- (Complex(5, 1) <=> Complex(2)).should be_nil
- (Complex(1) <=> Complex(2, 1)).should be_nil
- (5 <=> Complex(2, 1)).should be_nil
+ (Complex(5, 1) <=> Complex(2)).should == nil
+ (Complex(1) <=> Complex(2, 1)).should == nil
+ (5 <=> Complex(2, 1)).should == nil
end
it "returns nil if argument is not numeric" do
- (Complex(5, 1) <=> "cmp").should be_nil
- (Complex(1) <=> "cmp").should be_nil
- (Complex(1) <=> Object.new).should be_nil
+ (Complex(5, 1) <=> "cmp").should == nil
+ (Complex(1) <=> "cmp").should == nil
+ (Complex(1) <=> Object.new).should == nil
end
it "returns 0, 1, or -1 if self and argument do not have imaginary part" do
diff --git a/spec/ruby/core/complex/conj_spec.rb b/spec/ruby/core/complex/conj_spec.rb
index 5e3bc1acb8..063c85faec 100644
--- a/spec/ruby/core/complex/conj_spec.rb
+++ b/spec/ruby/core/complex/conj_spec.rb
@@ -1,6 +1,7 @@
require_relative '../../spec_helper'
-require_relative 'shared/conjugate'
describe "Complex#conj" do
- it_behaves_like :complex_conjugate, :conj
+ it "is an alias of Complex#conjugate" do
+ Complex.instance_method(:conj).should == Complex.instance_method(:conjugate)
+ end
end
diff --git a/spec/ruby/core/complex/conjugate_spec.rb b/spec/ruby/core/complex/conjugate_spec.rb
index f658bab4da..256fe4b3be 100644
--- a/spec/ruby/core/complex/conjugate_spec.rb
+++ b/spec/ruby/core/complex/conjugate_spec.rb
@@ -1,6 +1,10 @@
require_relative '../../spec_helper'
-require_relative 'shared/conjugate'
describe "Complex#conjugate" do
- it_behaves_like :complex_conjugate, :conjugate
+ it "returns the complex conjugate: conj a + bi = a - bi" do
+ Complex(3, 5).conjugate.should == Complex(3, -5)
+ Complex(3, -5).conjugate.should == Complex(3, 5)
+ Complex(-3.0, 5.2).conjugate.should be_close(Complex(-3.0, -5.2), TOLERANCE)
+ Complex(3.0, -5.2).conjugate.should be_close(Complex(3.0, 5.2), TOLERANCE)
+ end
end
diff --git a/spec/ruby/core/complex/constants_spec.rb b/spec/ruby/core/complex/constants_spec.rb
index 50303de16c..200e97731a 100644
--- a/spec/ruby/core/complex/constants_spec.rb
+++ b/spec/ruby/core/complex/constants_spec.rb
@@ -2,6 +2,6 @@ require_relative '../../spec_helper'
describe "Complex::I" do
it "is Complex(0, 1)" do
- Complex::I.should eql(Complex(0, 1))
+ Complex::I.should.eql?(Complex(0, 1))
end
end
diff --git a/spec/ruby/core/complex/divide_spec.rb b/spec/ruby/core/complex/divide_spec.rb
index bebf862312..d5b4aa3885 100644
--- a/spec/ruby/core/complex/divide_spec.rb
+++ b/spec/ruby/core/complex/divide_spec.rb
@@ -1,6 +1,84 @@
require_relative '../../spec_helper'
-require_relative 'shared/divide'
describe "Complex#/" do
- it_behaves_like :complex_divide, :/
+ describe "with Complex" do
+ it "divides according to the usual rule for complex numbers" do
+ a = Complex((1 * 10) - (2 * 20), (1 * 20) + (2 * 10))
+ b = Complex(1, 2)
+ (a / b).should == Complex(10, 20)
+
+ c = Complex((1.5 * 100.2) - (2.1 * -30.3), (1.5 * -30.3) + (2.1 * 100.2))
+ d = Complex(1.5, 2.1)
+ # remember the floating-point arithmetic
+ (c / d).should be_close(Complex(100.2, -30.3), TOLERANCE)
+ end
+ end
+
+ describe "with Fixnum" do
+ it "divides both parts of the Complex number" do
+ (Complex(20, 40) / 2).should == Complex(10, 20)
+ (Complex(30, 30) / 10).should == Complex(3, 3)
+ end
+
+ it "raises a ZeroDivisionError when given zero" do
+ -> { Complex(20, 40) / 0 }.should.raise(ZeroDivisionError)
+ end
+
+ it "produces Rational parts" do
+ (Complex(5, 9) / 2).should.eql?(Complex(Rational(5,2), Rational(9,2)))
+ end
+ end
+
+ describe "with Bignum" do
+ it "divides both parts of the Complex number" do
+ (Complex(20, 40) / 2).should == Complex(10, 20)
+ (Complex(15, 16) / 2.0).should be_close(Complex(7.5, 8), TOLERANCE)
+ end
+ end
+
+ describe "with Float" do
+ it "divides both parts of the Complex number" do
+ (Complex(3, 9) / 1.5).should == Complex(2, 6)
+ (Complex(15, 16) / 2.0).should be_close(Complex(7.5, 8), TOLERANCE)
+ end
+
+ it "returns Complex(Infinity, Infinity) when given zero" do
+ (Complex(20, 40) / 0.0).real.infinite?.should == 1
+ (Complex(20, 40) / 0.0).imag.infinite?.should == 1
+ (Complex(-20, 40) / 0.0).real.infinite?.should == -1
+ (Complex(-20, 40) / 0.0).imag.infinite?.should == 1
+ end
+ end
+
+ describe "with Object" do
+ it "tries to coerce self into other" do
+ value = Complex(3, 9)
+
+ obj = mock("Object")
+ obj.should_receive(:coerce).with(value).and_return([4, 2])
+ (value / obj).should == 2
+ end
+ end
+
+ describe "with a Numeric which responds to #real? with true" do
+ it "returns Complex(real.quo(other), imag.quo(other))" do
+ other = mock_numeric('other')
+ real = mock_numeric('real')
+ imag = mock_numeric('imag')
+ other.should_receive(:real?).and_return(true)
+ real.should_receive(:quo).with(other).and_return(1)
+ imag.should_receive(:quo).with(other).and_return(2)
+ (Complex(real, imag) / other).should == Complex(1, 2)
+ end
+ end
+
+ describe "with a Numeric which responds to #real? with false" do
+ it "coerces the passed argument to Complex and divides the resulting elements" do
+ complex = Complex(3, 0)
+ other = mock_numeric('other')
+ other.should_receive(:real?).any_number_of_times.and_return(false)
+ other.should_receive(:coerce).with(complex).and_return([5, 2])
+ (complex / other).should.eql?(Rational(5, 2))
+ end
+ end
end
diff --git a/spec/ruby/core/complex/eql_spec.rb b/spec/ruby/core/complex/eql_spec.rb
index 9194efc074..2082a22feb 100644
--- a/spec/ruby/core/complex/eql_spec.rb
+++ b/spec/ruby/core/complex/eql_spec.rb
@@ -2,23 +2,23 @@ require_relative '../../spec_helper'
describe "Complex#eql?" do
it "returns false if other is not Complex" do
- Complex(1).eql?(1).should be_false
+ Complex(1).eql?(1).should == false
end
it "returns true when the respective parts are of the same classes and self == other" do
- Complex(1, 2).eql?(Complex(1, 2)).should be_true
+ Complex(1, 2).eql?(Complex(1, 2)).should == true
end
it "returns false when the real parts are of different classes" do
- Complex(1).eql?(Complex(1.0)).should be_false
+ Complex(1).eql?(Complex(1.0)).should == false
end
it "returns false when the imaginary parts are of different classes" do
- Complex(1, 2).eql?(Complex(1, 2.0)).should be_false
+ Complex(1, 2).eql?(Complex(1, 2.0)).should == false
end
it "returns false when self == other is false" do
- Complex(1, 2).eql?(Complex(2, 3)).should be_false
+ Complex(1, 2).eql?(Complex(2, 3)).should == false
end
it "does NOT send #eql? to real or imaginary parts" do
@@ -26,6 +26,6 @@ describe "Complex#eql?" do
imag = mock_numeric('imag')
real.should_not_receive(:eql?)
imag.should_not_receive(:eql?)
- Complex(real, imag).eql?(Complex(real, imag)).should be_true
+ Complex(real, imag).eql?(Complex(real, imag)).should == true
end
end
diff --git a/spec/ruby/core/complex/equal_value_spec.rb b/spec/ruby/core/complex/equal_value_spec.rb
index 97c486d820..b3562ff3fb 100644
--- a/spec/ruby/core/complex/equal_value_spec.rb
+++ b/spec/ruby/core/complex/equal_value_spec.rb
@@ -60,7 +60,7 @@ describe "Complex#==" do
obj = mock("Object")
obj.should_receive(:==).with(value).and_return(:expected)
- (value == obj).should_not be_false
+ (value == obj).should_not == false
end
end
@@ -73,11 +73,11 @@ describe "Complex#==" do
it "returns real == other when the imaginary part is zero" do
real = mock_numeric('real')
real.should_receive(:==).with(@other).and_return(true)
- (Complex(real, 0) == @other).should be_true
+ (Complex(real, 0) == @other).should == true
end
it "returns false when the imaginary part is not zero" do
- (Complex(3, 1) == @other).should be_false
+ (Complex(3, 1) == @other).should == false
end
end
@@ -87,7 +87,7 @@ describe "Complex#==" do
other = mock_numeric('other')
other.should_receive(:real?).any_number_of_times.and_return(false)
other.should_receive(:==).with(complex).and_return(true)
- (complex == other).should be_true
+ (complex == other).should == true
end
end
end
diff --git a/spec/ruby/core/complex/exponent_spec.rb b/spec/ruby/core/complex/exponent_spec.rb
index 86f827aece..d0db0a40c2 100644
--- a/spec/ruby/core/complex/exponent_spec.rb
+++ b/spec/ruby/core/complex/exponent_spec.rb
@@ -3,13 +3,13 @@ require_relative '../../spec_helper'
describe "Complex#**" do
describe "with Integer 0" do
it "returns Complex(1)" do
- (Complex(3, 4) ** 0).should eql(Complex(1))
+ (Complex(3, 4) ** 0).should.eql?(Complex(1))
end
end
describe "with Float 0.0" do
it "returns Complex(1.0, 0.0)" do
- (Complex(3, 4) ** 0.0).should eql(Complex(1.0, 0.0))
+ (Complex(3, 4) ** 0.0).should.eql?(Complex(1.0, 0.0))
end
end
diff --git a/spec/ruby/core/complex/fdiv_spec.rb b/spec/ruby/core/complex/fdiv_spec.rb
index 68f7d1b309..fdcbc6a95d 100644
--- a/spec/ruby/core/complex/fdiv_spec.rb
+++ b/spec/ruby/core/complex/fdiv_spec.rb
@@ -2,44 +2,44 @@ require_relative '../../spec_helper'
describe "Complex#fdiv" do
it "accepts a numeric argument" do
- -> { Complex(20).fdiv(2) }.should_not raise_error(TypeError)
- -> { Complex(20).fdiv(2.0) }.should_not raise_error(TypeError)
- -> { Complex(20).fdiv(bignum_value) }.should_not raise_error(TypeError)
+ -> { Complex(20).fdiv(2) }.should_not.raise(TypeError)
+ -> { Complex(20).fdiv(2.0) }.should_not.raise(TypeError)
+ -> { Complex(20).fdiv(bignum_value) }.should_not.raise(TypeError)
end
it "accepts a negative numeric argument" do
- -> { Complex(20).fdiv(-2) }.should_not raise_error(TypeError)
- -> { Complex(20).fdiv(-2.0) }.should_not raise_error(TypeError)
- -> { Complex(20).fdiv(-bignum_value) }.should_not raise_error(TypeError)
+ -> { Complex(20).fdiv(-2) }.should_not.raise(TypeError)
+ -> { Complex(20).fdiv(-2.0) }.should_not.raise(TypeError)
+ -> { Complex(20).fdiv(-bignum_value) }.should_not.raise(TypeError)
end
it "raises a TypeError if passed a non-numeric argument" do
- -> { Complex(20).fdiv([]) }.should raise_error(TypeError)
- -> { Complex(20).fdiv(:sym) }.should raise_error(TypeError)
- -> { Complex(20).fdiv('s') }.should raise_error(TypeError)
+ -> { Complex(20).fdiv([]) }.should.raise(TypeError)
+ -> { Complex(20).fdiv(:sym) }.should.raise(TypeError)
+ -> { Complex(20).fdiv('s') }.should.raise(TypeError)
end
it "sets the real part to NaN if self's real part is NaN" do
- Complex(nan_value).fdiv(2).real.nan?.should be_true
+ Complex(nan_value).fdiv(2).real.nan?.should == true
end
it "sets the imaginary part to NaN if self's imaginary part is NaN" do
- Complex(2, nan_value).fdiv(2).imag.nan?.should be_true
+ Complex(2, nan_value).fdiv(2).imag.nan?.should == true
end
it "sets the real and imaginary part to NaN if self's real and imaginary parts are NaN" do
- Complex(nan_value, nan_value).fdiv(2).imag.nan?.should be_true
- Complex(nan_value, nan_value).fdiv(2).real.nan?.should be_true
+ Complex(nan_value, nan_value).fdiv(2).imag.nan?.should == true
+ Complex(nan_value, nan_value).fdiv(2).real.nan?.should == true
end
it "sets the real and imaginary part to NaN if self's real part and the argument are both NaN" do
- Complex(nan_value, 2).fdiv(nan_value).imag.nan?.should be_true
- Complex(nan_value, 2).fdiv(nan_value).real.nan?.should be_true
+ Complex(nan_value, 2).fdiv(nan_value).imag.nan?.should == true
+ Complex(nan_value, 2).fdiv(nan_value).real.nan?.should == true
end
it "sets the real and imaginary part to NaN if self's real part, self's imaginary part, and the argument are NaN" do
- Complex(nan_value, nan_value).fdiv(nan_value).imag.nan?.should be_true
- Complex(nan_value, nan_value).fdiv(nan_value).real.nan?.should be_true
+ Complex(nan_value, nan_value).fdiv(nan_value).imag.nan?.should == true
+ Complex(nan_value, nan_value).fdiv(nan_value).real.nan?.should == true
end
it "sets the real part to Infinity if self's real part is Infinity" do
@@ -58,8 +58,8 @@ describe "Complex#fdiv" do
end
it "sets the real part to NaN and the imaginary part to NaN if self's imaginary part, self's real part, and the argument are Infinity" do
- Complex(infinity_value, infinity_value).fdiv(infinity_value).real.nan?.should be_true
- Complex(infinity_value, infinity_value).fdiv(infinity_value).imag.nan?.should be_true
+ Complex(infinity_value, infinity_value).fdiv(infinity_value).real.nan?.should == true
+ Complex(infinity_value, infinity_value).fdiv(infinity_value).imag.nan?.should == true
end
end
@@ -71,7 +71,7 @@ describe "Complex#fdiv with no imaginary part" do
it "returns a Complex number" do
@numbers.each do |real|
@numbers.each do |other|
- Complex(real).fdiv(other).should be_an_instance_of(Complex)
+ Complex(real).fdiv(other).should.instance_of?(Complex)
end
end
end
@@ -103,7 +103,7 @@ describe "Complex#fdiv with an imaginary part" do
@numbers.each_with_index do |other,idx|
Complex(
real,@numbers[idx == 0 ? -1 : idx-1]
- ).fdiv(other).should be_an_instance_of(Complex)
+ ).fdiv(other).should.instance_of?(Complex)
end
end
end
diff --git a/spec/ruby/core/complex/imag_spec.rb b/spec/ruby/core/complex/imag_spec.rb
index 2bafd1ab54..225f168e78 100644
--- a/spec/ruby/core/complex/imag_spec.rb
+++ b/spec/ruby/core/complex/imag_spec.rb
@@ -1,6 +1,7 @@
require_relative '../../spec_helper'
-require_relative 'shared/image'
describe "Complex#imag" do
- it_behaves_like :complex_image, :imag
+ it "is an alias of Complex#imaginary" do
+ Complex.instance_method(:imag).should == Complex.instance_method(:imaginary)
+ end
end
diff --git a/spec/ruby/core/complex/imaginary_spec.rb b/spec/ruby/core/complex/imaginary_spec.rb
index a8a1bfea90..ac9284e934 100644
--- a/spec/ruby/core/complex/imaginary_spec.rb
+++ b/spec/ruby/core/complex/imaginary_spec.rb
@@ -1,6 +1,10 @@
require_relative '../../spec_helper'
-require_relative 'shared/image'
describe "Complex#imaginary" do
- it_behaves_like :complex_image, :imaginary
+ it "returns the imaginary part of self" do
+ Complex(1, 0).imaginary.should == 0
+ Complex(2, 1).imaginary.should == 1
+ Complex(6.7, 8.9).imaginary.should == 8.9
+ Complex(1, bignum_value).imaginary.should == bignum_value
+ end
end
diff --git a/spec/ruby/core/complex/integer_spec.rb b/spec/ruby/core/complex/integer_spec.rb
index 0957accb70..559bfbccfd 100644
--- a/spec/ruby/core/complex/integer_spec.rb
+++ b/spec/ruby/core/complex/integer_spec.rb
@@ -2,10 +2,10 @@ require_relative '../../spec_helper'
describe "Complex#integer?" do
it "returns false for a Complex with no imaginary part" do
- Complex(20).integer?.should be_false
+ Complex(20).integer?.should == false
end
it "returns false for a Complex with an imaginary part" do
- Complex(20,3).integer?.should be_false
+ Complex(20,3).integer?.should == false
end
end
diff --git a/spec/ruby/core/complex/magnitude_spec.rb b/spec/ruby/core/complex/magnitude_spec.rb
index 86f3b29868..6341b4eec8 100644
--- a/spec/ruby/core/complex/magnitude_spec.rb
+++ b/spec/ruby/core/complex/magnitude_spec.rb
@@ -1,6 +1,7 @@
require_relative '../../spec_helper'
-require_relative 'shared/abs'
describe "Complex#magnitude" do
- it_behaves_like :complex_abs, :magnitude
+ it "is an alias of Complex#abs" do
+ Complex.instance_method(:magnitude).should == Complex.instance_method(:abs)
+ end
end
diff --git a/spec/ruby/core/complex/marshal_dump_spec.rb b/spec/ruby/core/complex/marshal_dump_spec.rb
index 116899b0ad..201d55e9e5 100644
--- a/spec/ruby/core/complex/marshal_dump_spec.rb
+++ b/spec/ruby/core/complex/marshal_dump_spec.rb
@@ -2,7 +2,7 @@ require_relative '../../spec_helper'
describe "Complex#marshal_dump" do
it "is a private method" do
- Complex.should have_private_instance_method(:marshal_dump, false)
+ Complex.private_instance_methods(false).should.include?(:marshal_dump)
end
it "dumps real and imaginary parts" do
diff --git a/spec/ruby/core/complex/negative_spec.rb b/spec/ruby/core/complex/negative_spec.rb
index 62ab89c04a..566975b8e1 100644
--- a/spec/ruby/core/complex/negative_spec.rb
+++ b/spec/ruby/core/complex/negative_spec.rb
@@ -4,10 +4,10 @@ describe "Complex#negative?" do
it "is undefined" do
c = Complex(1)
- c.methods.should_not include(:negative?)
+ c.methods.should_not.include?(:negative?)
-> {
c.negative?
- }.should raise_error(NoMethodError)
+ }.should.raise(NoMethodError)
end
end
diff --git a/spec/ruby/core/complex/phase_spec.rb b/spec/ruby/core/complex/phase_spec.rb
index 89574bf533..2ab90989e1 100644
--- a/spec/ruby/core/complex/phase_spec.rb
+++ b/spec/ruby/core/complex/phase_spec.rb
@@ -1,6 +1,7 @@
require_relative '../../spec_helper'
-require_relative 'shared/arg'
describe "Complex#phase" do
- it_behaves_like :complex_arg, :phase
+ it "is an alias of Complex#arg" do
+ Complex.instance_method(:phase).should == Complex.instance_method(:arg)
+ end
end
diff --git a/spec/ruby/core/complex/polar_spec.rb b/spec/ruby/core/complex/polar_spec.rb
index 56335584ef..824211fcd0 100644
--- a/spec/ruby/core/complex/polar_spec.rb
+++ b/spec/ruby/core/complex/polar_spec.rb
@@ -7,22 +7,22 @@ describe "Complex.polar" do
end
it "raises a TypeError when given non real arguments" do
- ->{ Complex.polar(nil) }.should raise_error(TypeError)
- ->{ Complex.polar(nil, nil) }.should raise_error(TypeError)
+ ->{ Complex.polar(nil) }.should.raise(TypeError)
+ ->{ Complex.polar(nil, nil) }.should.raise(TypeError)
end
it "computes the real values of the real & imaginary parts from the polar form" do
a = Complex.polar(1.0+0.0i, Math::PI/2+0.0i)
a.real.should be_close(0.0, TOLERANCE)
a.imag.should be_close(1.0, TOLERANCE)
- a.real.real?.should be_true
- a.imag.real?.should be_true
+ a.real.real?.should == true
+ a.imag.real?.should == true
b = Complex.polar(1+0.0i)
b.real.should be_close(1.0, TOLERANCE)
b.imag.should be_close(0.0, TOLERANCE)
- b.real.real?.should be_true
- b.imag.real?.should be_true
+ b.real.real?.should == true
+ b.imag.real?.should == true
end
end
diff --git a/spec/ruby/core/complex/positive_spec.rb b/spec/ruby/core/complex/positive_spec.rb
index f1bad8608c..d2fb256538 100644
--- a/spec/ruby/core/complex/positive_spec.rb
+++ b/spec/ruby/core/complex/positive_spec.rb
@@ -4,10 +4,10 @@ describe "Complex#positive?" do
it "is undefined" do
c = Complex(1)
- c.methods.should_not include(:positive?)
+ c.methods.should_not.include?(:positive?)
-> {
c.positive?
- }.should raise_error(NoMethodError)
+ }.should.raise(NoMethodError)
end
end
diff --git a/spec/ruby/core/complex/quo_spec.rb b/spec/ruby/core/complex/quo_spec.rb
index ee6fd65c79..be0a44d532 100644
--- a/spec/ruby/core/complex/quo_spec.rb
+++ b/spec/ruby/core/complex/quo_spec.rb
@@ -1,6 +1,7 @@
require_relative '../../spec_helper'
-require_relative 'shared/divide'
describe "Complex#quo" do
- it_behaves_like :complex_divide, :quo
+ it "is an alias of Complex#/" do
+ Complex.instance_method(:quo).should == Complex.instance_method(:/)
+ end
end
diff --git a/spec/ruby/core/complex/rationalize_spec.rb b/spec/ruby/core/complex/rationalize_spec.rb
index 043b8ddf2a..d49bb52def 100644
--- a/spec/ruby/core/complex/rationalize_spec.rb
+++ b/spec/ruby/core/complex/rationalize_spec.rb
@@ -2,11 +2,11 @@ require_relative '../../spec_helper'
describe "Complex#rationalize" do
it "raises RangeError if self has non-zero imaginary part" do
- -> { Complex(1,5).rationalize }.should raise_error(RangeError)
+ -> { Complex(1,5).rationalize }.should.raise(RangeError)
end
it "raises RangeError if self has 0.0 imaginary part" do
- -> { Complex(1,0.0).rationalize }.should raise_error(RangeError)
+ -> { Complex(1,0.0).rationalize }.should.raise(RangeError)
end
it "returns a Rational if self has zero imaginary part" do
@@ -25,7 +25,7 @@ describe "Complex#rationalize" do
end
it "raises ArgumentError when passed more than one argument" do
- -> { Complex(1,0).rationalize(0.1, 0.1) }.should raise_error(ArgumentError)
- -> { Complex(1,0).rationalize(0.1, 0.1, 2) }.should raise_error(ArgumentError)
+ -> { Complex(1,0).rationalize(0.1, 0.1) }.should.raise(ArgumentError)
+ -> { Complex(1,0).rationalize(0.1, 0.1, 2) }.should.raise(ArgumentError)
end
end
diff --git a/spec/ruby/core/complex/real_spec.rb b/spec/ruby/core/complex/real_spec.rb
index 2ea791c005..41734b23f0 100644
--- a/spec/ruby/core/complex/real_spec.rb
+++ b/spec/ruby/core/complex/real_spec.rb
@@ -11,18 +11,18 @@ end
describe "Complex#real?" do
it "returns false if there is an imaginary part" do
- Complex(2,3).real?.should be_false
+ Complex(2,3).real?.should == false
end
it "returns false if there is not an imaginary part" do
- Complex(2).real?.should be_false
+ Complex(2).real?.should == false
end
it "returns false if the real part is Infinity" do
- Complex(infinity_value).real?.should be_false
+ Complex(infinity_value).real?.should == false
end
it "returns false if the real part is NaN" do
- Complex(nan_value).real?.should be_false
+ Complex(nan_value).real?.should == false
end
end
diff --git a/spec/ruby/core/complex/rect_spec.rb b/spec/ruby/core/complex/rect_spec.rb
index 9e95f3efc2..bf3467c611 100644
--- a/spec/ruby/core/complex/rect_spec.rb
+++ b/spec/ruby/core/complex/rect_spec.rb
@@ -1,10 +1,13 @@
require_relative '../../spec_helper'
-require_relative 'shared/rect'
describe "Complex#rect" do
- it_behaves_like :complex_rect, :rect
+ it "is an alias of Complex#rectangular" do
+ Complex.instance_method(:rect).should == Complex.instance_method(:rectangular)
+ end
end
describe "Complex.rect" do
- it_behaves_like :complex_rect_class, :rect
+ it "is an alias of Complex.rectangular" do
+ Complex.method(:rect).should == Complex.method(:rectangular)
+ end
end
diff --git a/spec/ruby/core/complex/rectangular_spec.rb b/spec/ruby/core/complex/rectangular_spec.rb
index d4b8ad9782..7789bf925e 100644
--- a/spec/ruby/core/complex/rectangular_spec.rb
+++ b/spec/ruby/core/complex/rectangular_spec.rb
@@ -1,10 +1,114 @@
require_relative '../../spec_helper'
-require_relative 'shared/rect'
describe "Complex#rectangular" do
- it_behaves_like :complex_rect, :rectangular
+ before :each do
+ @numbers = [
+ Complex(1),
+ Complex(0, 20),
+ Complex(0, 0),
+ Complex(0.0),
+ Complex(9999999**99),
+ Complex(-20),
+ Complex.polar(76, 10)
+ ]
+ end
+
+ it "returns an Array" do
+ @numbers.each do |number|
+ number.rectangular.should.instance_of?(Array)
+ end
+ end
+
+ it "returns a two-element Array" do
+ @numbers.each do |number|
+ number.rectangular.size.should == 2
+ end
+ end
+
+ it "returns the real part of self as the first element" do
+ @numbers.each do |number|
+ number.rectangular.first.should == number.real
+ end
+ end
+
+ it "returns the imaginary part of self as the last element" do
+ @numbers.each do |number|
+ number.rectangular.last.should == number.imaginary
+ end
+ end
+
+ it "raises an ArgumentError if given any arguments" do
+ @numbers.each do |number|
+ -> { number.rectangular(number) }.should.raise(ArgumentError)
+ end
+ end
end
describe "Complex.rectangular" do
- it_behaves_like :complex_rect_class, :rectangular
+ describe "passed a Numeric n which responds to #real? with true" do
+ it "returns a Complex with real part n and imaginary part 0" do
+ n = mock_numeric('n')
+ n.should_receive(:real?).any_number_of_times.and_return(true)
+ result = Complex.rectangular(n)
+ result.real.should == n
+ result.imag.should == 0
+ end
+ end
+
+ describe "passed a Numeric which responds to #real? with false" do
+ it "raises TypeError" do
+ n = mock_numeric('n')
+ n.should_receive(:real?).any_number_of_times.and_return(false)
+ -> { Complex.rectangular(n) }.should.raise(TypeError)
+ end
+ end
+
+ describe "passed Numerics n1 and n2 and at least one responds to #real? with false" do
+ [[false, false], [false, true], [true, false]].each do |r1, r2|
+ it "raises TypeError" do
+ n1 = mock_numeric('n1')
+ n2 = mock_numeric('n2')
+ n1.should_receive(:real?).any_number_of_times.and_return(r1)
+ n2.should_receive(:real?).any_number_of_times.and_return(r2)
+ -> { Complex.rectangular(n1, n2) }.should.raise(TypeError)
+ end
+ end
+ end
+
+ describe "passed Numerics n1 and n2 and both respond to #real? with true" do
+ it "returns a Complex with real part n1 and imaginary part n2" do
+ n1 = mock_numeric('n1')
+ n2 = mock_numeric('n2')
+ n1.should_receive(:real?).any_number_of_times.and_return(true)
+ n2.should_receive(:real?).any_number_of_times.and_return(true)
+ result = Complex.rectangular(n1, n2)
+ result.real.should == n1
+ result.imag.should == n2
+ end
+ end
+
+ describe "when passed a Complex" do
+ it "raises a TypeError when the imaginary part is not zero" do
+ -> {
+ Complex.rectangular(1.0+1i, 2)
+ }.should.raise(TypeError)
+
+ -> {
+ Complex.rectangular(1.0, 2i)
+ }.should.raise(TypeError)
+ end
+
+ it "ignores the imaginary part if it is zero" do
+ result = Complex.rectangular(1.0+0i, 2+0.0i)
+ result.real.should == 1.0
+ result.imag.should == 2
+ end
+ end
+
+ describe "passed a non-Numeric" do
+ it "raises TypeError" do
+ -> { Complex.rectangular(:sym) }.should.raise(TypeError)
+ -> { Complex.rectangular(0, :sym) }.should.raise(TypeError)
+ end
+ end
end
diff --git a/spec/ruby/core/complex/shared/abs.rb b/spec/ruby/core/complex/shared/abs.rb
deleted file mode 100644
index 2299479341..0000000000
--- a/spec/ruby/core/complex/shared/abs.rb
+++ /dev/null
@@ -1,10 +0,0 @@
-describe :complex_abs, shared: true do
- it "returns the modulus: |a + bi| = sqrt((a ^ 2) + (b ^ 2))" do
- Complex(0, 0).send(@method).should == 0
- Complex(3, 4).send(@method).should == 5 # well-known integer case
- Complex(-3, 4).send(@method).should == 5
- Complex(1, -1).send(@method).should be_close(Math.sqrt(2), TOLERANCE)
- Complex(6.5, 0).send(@method).should be_close(6.5, TOLERANCE)
- Complex(0, -7.2).send(@method).should be_close(7.2, TOLERANCE)
- end
-end
diff --git a/spec/ruby/core/complex/shared/arg.rb b/spec/ruby/core/complex/shared/arg.rb
deleted file mode 100644
index c81f197433..0000000000
--- a/spec/ruby/core/complex/shared/arg.rb
+++ /dev/null
@@ -1,9 +0,0 @@
-describe :complex_arg, shared: true do
- it "returns the argument -- i.e., the angle from (1, 0) in the complex plane" do
- two_pi = 2 * Math::PI
- (Complex(1, 0).send(@method) % two_pi).should be_close(0, TOLERANCE)
- (Complex(0, 2).send(@method) % two_pi).should be_close(Math::PI * 0.5, TOLERANCE)
- (Complex(-100, 0).send(@method) % two_pi).should be_close(Math::PI, TOLERANCE)
- (Complex(0, -75.3).send(@method) % two_pi).should be_close(Math::PI * 1.5, TOLERANCE)
- end
-end
diff --git a/spec/ruby/core/complex/shared/conjugate.rb b/spec/ruby/core/complex/shared/conjugate.rb
deleted file mode 100644
index d1ae47bcb6..0000000000
--- a/spec/ruby/core/complex/shared/conjugate.rb
+++ /dev/null
@@ -1,8 +0,0 @@
-describe :complex_conjugate, shared: true do
- it "returns the complex conjugate: conj a + bi = a - bi" do
- Complex(3, 5).send(@method).should == Complex(3, -5)
- Complex(3, -5).send(@method).should == Complex(3, 5)
- Complex(-3.0, 5.2).send(@method).should be_close(Complex(-3.0, -5.2), TOLERANCE)
- Complex(3.0, -5.2).send(@method).should be_close(Complex(3.0, 5.2), TOLERANCE)
- end
-end
diff --git a/spec/ruby/core/complex/shared/divide.rb b/spec/ruby/core/complex/shared/divide.rb
deleted file mode 100644
index a60802c74c..0000000000
--- a/spec/ruby/core/complex/shared/divide.rb
+++ /dev/null
@@ -1,82 +0,0 @@
-describe :complex_divide, shared: true do
- describe "with Complex" do
- it "divides according to the usual rule for complex numbers" do
- a = Complex((1 * 10) - (2 * 20), (1 * 20) + (2 * 10))
- b = Complex(1, 2)
- a.send(@method, b).should == Complex(10, 20)
-
- c = Complex((1.5 * 100.2) - (2.1 * -30.3), (1.5 * -30.3) + (2.1 * 100.2))
- d = Complex(1.5, 2.1)
- # remember the floating-point arithmetic
- c.send(@method, d).should be_close(Complex(100.2, -30.3), TOLERANCE)
- end
- end
-
- describe "with Fixnum" do
- it "divides both parts of the Complex number" do
- Complex(20, 40).send(@method, 2).should == Complex(10, 20)
- Complex(30, 30).send(@method, 10).should == Complex(3, 3)
- end
-
- it "raises a ZeroDivisionError when given zero" do
- -> { Complex(20, 40).send(@method, 0) }.should raise_error(ZeroDivisionError)
- end
-
- it "produces Rational parts" do
- Complex(5, 9).send(@method, 2).should eql(Complex(Rational(5,2), Rational(9,2)))
- end
- end
-
- describe "with Bignum" do
- it "divides both parts of the Complex number" do
- Complex(20, 40).send(@method, 2).should == Complex(10, 20)
- Complex(15, 16).send(@method, 2.0).should be_close(Complex(7.5, 8), TOLERANCE)
- end
- end
-
- describe "with Float" do
- it "divides both parts of the Complex number" do
- Complex(3, 9).send(@method, 1.5).should == Complex(2, 6)
- Complex(15, 16).send(@method, 2.0).should be_close(Complex(7.5, 8), TOLERANCE)
- end
-
- it "returns Complex(Infinity, Infinity) when given zero" do
- Complex(20, 40).send(@method, 0.0).real.infinite?.should == 1
- Complex(20, 40).send(@method, 0.0).imag.infinite?.should == 1
- Complex(-20, 40).send(@method, 0.0).real.infinite?.should == -1
- Complex(-20, 40).send(@method, 0.0).imag.infinite?.should == 1
- end
- end
-
- describe "with Object" do
- it "tries to coerce self into other" do
- value = Complex(3, 9)
-
- obj = mock("Object")
- obj.should_receive(:coerce).with(value).and_return([4, 2])
- value.send(@method, obj).should == 2
- end
- end
-
- describe "with a Numeric which responds to #real? with true" do
- it "returns Complex(real.quo(other), imag.quo(other))" do
- other = mock_numeric('other')
- real = mock_numeric('real')
- imag = mock_numeric('imag')
- other.should_receive(:real?).and_return(true)
- real.should_receive(:quo).with(other).and_return(1)
- imag.should_receive(:quo).with(other).and_return(2)
- Complex(real, imag).send(@method, other).should == Complex(1, 2)
- end
- end
-
- describe "with a Numeric which responds to #real? with false" do
- it "coerces the passed argument to Complex and divides the resulting elements" do
- complex = Complex(3, 0)
- other = mock_numeric('other')
- other.should_receive(:real?).any_number_of_times.and_return(false)
- other.should_receive(:coerce).with(complex).and_return([5, 2])
- complex.send(@method, other).should eql(Rational(5, 2))
- end
- end
-end
diff --git a/spec/ruby/core/complex/shared/image.rb b/spec/ruby/core/complex/shared/image.rb
deleted file mode 100644
index f839dbcaf9..0000000000
--- a/spec/ruby/core/complex/shared/image.rb
+++ /dev/null
@@ -1,8 +0,0 @@
-describe :complex_image, shared: true do
- it "returns the imaginary part of self" do
- Complex(1, 0).send(@method).should == 0
- Complex(2, 1).send(@method).should == 1
- Complex(6.7, 8.9).send(@method).should == 8.9
- Complex(1, bignum_value).send(@method).should == bignum_value
- end
-end
diff --git a/spec/ruby/core/complex/shared/rect.rb b/spec/ruby/core/complex/shared/rect.rb
deleted file mode 100644
index 4ac294e771..0000000000
--- a/spec/ruby/core/complex/shared/rect.rb
+++ /dev/null
@@ -1,94 +0,0 @@
-describe :complex_rect, shared: true do
- before :each do
- @numbers = [
- Complex(1),
- Complex(0, 20),
- Complex(0, 0),
- Complex(0.0),
- Complex(9999999**99),
- Complex(-20),
- Complex.polar(76, 10)
- ]
- end
-
- it "returns an Array" do
- @numbers.each do |number|
- number.send(@method).should be_an_instance_of(Array)
- end
- end
-
- it "returns a two-element Array" do
- @numbers.each do |number|
- number.send(@method).size.should == 2
- end
- end
-
- it "returns the real part of self as the first element" do
- @numbers.each do |number|
- number.send(@method).first.should == number.real
- end
- end
-
- it "returns the imaginary part of self as the last element" do
- @numbers.each do |number|
- number.send(@method).last.should == number.imaginary
- end
- end
-
- it "raises an ArgumentError if given any arguments" do
- @numbers.each do |number|
- -> { number.send(@method, number) }.should raise_error(ArgumentError)
- end
- end
-end
-
-describe :complex_rect_class, shared: true do
- describe "passed a Numeric n which responds to #real? with true" do
- it "returns a Complex with real part n and imaginary part 0" do
- n = mock_numeric('n')
- n.should_receive(:real?).any_number_of_times.and_return(true)
- result = Complex.send(@method, n)
- result.real.should == n
- result.imag.should == 0
- end
- end
-
- describe "passed a Numeric which responds to #real? with false" do
- it "raises TypeError" do
- n = mock_numeric('n')
- n.should_receive(:real?).any_number_of_times.and_return(false)
- -> { Complex.send(@method, n) }.should raise_error(TypeError)
- end
- end
-
- describe "passed Numerics n1 and n2 and at least one responds to #real? with false" do
- [[false, false], [false, true], [true, false]].each do |r1, r2|
- it "raises TypeError" do
- n1 = mock_numeric('n1')
- n2 = mock_numeric('n2')
- n1.should_receive(:real?).any_number_of_times.and_return(r1)
- n2.should_receive(:real?).any_number_of_times.and_return(r2)
- -> { Complex.send(@method, n1, n2) }.should raise_error(TypeError)
- end
- end
- end
-
- describe "passed Numerics n1 and n2 and both respond to #real? with true" do
- it "returns a Complex with real part n1 and imaginary part n2" do
- n1 = mock_numeric('n1')
- n2 = mock_numeric('n2')
- n1.should_receive(:real?).any_number_of_times.and_return(true)
- n2.should_receive(:real?).any_number_of_times.and_return(true)
- result = Complex.send(@method, n1, n2)
- result.real.should == n1
- result.imag.should == n2
- end
- end
-
- describe "passed a non-Numeric" do
- it "raises TypeError" do
- -> { Complex.send(@method, :sym) }.should raise_error(TypeError)
- -> { Complex.send(@method, 0, :sym) }.should raise_error(TypeError)
- end
- end
-end
diff --git a/spec/ruby/core/complex/to_c_spec.rb b/spec/ruby/core/complex/to_c_spec.rb
index 5ce01d9d4e..cd7195556c 100644
--- a/spec/ruby/core/complex/to_c_spec.rb
+++ b/spec/ruby/core/complex/to_c_spec.rb
@@ -3,7 +3,7 @@ require_relative '../../spec_helper'
describe "Complex#to_c" do
it "returns self" do
value = Complex(1, 5)
- value.to_c.should equal(value)
+ value.to_c.should.equal?(value)
end
it 'returns the same value' do
diff --git a/spec/ruby/core/complex/to_f_spec.rb b/spec/ruby/core/complex/to_f_spec.rb
index b53471c1fc..9f3265cdb9 100644
--- a/spec/ruby/core/complex/to_f_spec.rb
+++ b/spec/ruby/core/complex/to_f_spec.rb
@@ -29,13 +29,13 @@ describe "Complex#to_f" do
describe "when the imaginary part is non-zero" do
it "raises RangeError" do
- -> { Complex(0, 1).to_f }.should raise_error(RangeError)
+ -> { Complex(0, 1).to_f }.should.raise(RangeError)
end
end
describe "when the imaginary part is Float 0.0" do
it "raises RangeError" do
- -> { Complex(0, 0.0).to_f }.should raise_error(RangeError)
+ -> { Complex(0, 0.0).to_f }.should.raise(RangeError)
end
end
end
diff --git a/spec/ruby/core/complex/to_i_spec.rb b/spec/ruby/core/complex/to_i_spec.rb
index 1e78f5ec0e..9149ffbbaa 100644
--- a/spec/ruby/core/complex/to_i_spec.rb
+++ b/spec/ruby/core/complex/to_i_spec.rb
@@ -29,13 +29,13 @@ describe "Complex#to_i" do
describe "when the imaginary part is non-zero" do
it "raises RangeError" do
- -> { Complex(0, 1).to_i }.should raise_error(RangeError)
+ -> { Complex(0, 1).to_i }.should.raise(RangeError)
end
end
describe "when the imaginary part is Float 0.0" do
it "raises RangeError" do
- -> { Complex(0, 0.0).to_i }.should raise_error(RangeError)
+ -> { Complex(0, 0.0).to_i }.should.raise(RangeError)
end
end
end
diff --git a/spec/ruby/core/complex/to_r_spec.rb b/spec/ruby/core/complex/to_r_spec.rb
index 788027a500..6587ae9e2e 100644
--- a/spec/ruby/core/complex/to_r_spec.rb
+++ b/spec/ruby/core/complex/to_r_spec.rb
@@ -29,14 +29,14 @@ describe "Complex#to_r" do
describe "when the imaginary part is non-zero" do
it "raises RangeError" do
- -> { Complex(0, 1).to_r }.should raise_error(RangeError)
+ -> { Complex(0, 1).to_r }.should.raise(RangeError)
end
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)
+ -> { Complex(0, 0.0).to_r }.should.raise(RangeError)
end
end
diff --git a/spec/ruby/core/conditionvariable/broadcast_spec.rb b/spec/ruby/core/conditionvariable/broadcast_spec.rb
index 55a7b89c72..16c7b4cc8d 100644
--- a/spec/ruby/core/conditionvariable/broadcast_spec.rb
+++ b/spec/ruby/core/conditionvariable/broadcast_spec.rb
@@ -24,7 +24,7 @@ describe "ConditionVariable#broadcast" do
# wait until all threads are sleeping (ie waiting)
Thread.pass until threads.all?(&:stop?)
- r2.should be_empty
+ r2.should.empty?
m.synchronize do
cv.broadcast
end
diff --git a/spec/ruby/core/conditionvariable/marshal_dump_spec.rb b/spec/ruby/core/conditionvariable/marshal_dump_spec.rb
index 88b1cc38c1..594c178e88 100644
--- a/spec/ruby/core/conditionvariable/marshal_dump_spec.rb
+++ b/spec/ruby/core/conditionvariable/marshal_dump_spec.rb
@@ -3,6 +3,6 @@ require_relative '../../spec_helper'
describe "ConditionVariable#marshal_dump" do
it "raises a TypeError" do
cv = ConditionVariable.new
- -> { cv.marshal_dump }.should raise_error(TypeError, /can't dump/)
+ -> { cv.marshal_dump }.should.raise(TypeError, /can't dump/)
end
end
diff --git a/spec/ruby/core/conditionvariable/signal_spec.rb b/spec/ruby/core/conditionvariable/signal_spec.rb
index 43a9cc611b..3b266cf8c6 100644
--- a/spec/ruby/core/conditionvariable/signal_spec.rb
+++ b/spec/ruby/core/conditionvariable/signal_spec.rb
@@ -24,7 +24,7 @@ describe "ConditionVariable#signal" do
# wait until all threads are sleeping (ie waiting)
Thread.pass until threads.all?(&:stop?)
- r2.should be_empty
+ r2.should.empty?
100.times do |i|
m.synchronize do
cv.signal
diff --git a/spec/ruby/core/conditionvariable/wait_spec.rb b/spec/ruby/core/conditionvariable/wait_spec.rb
index fe73e513c0..1af53a15a2 100644
--- a/spec/ruby/core/conditionvariable/wait_spec.rb
+++ b/spec/ruby/core/conditionvariable/wait_spec.rb
@@ -163,7 +163,7 @@ describe "ConditionVariable#wait" do
# On TruffleRuby, this causes a safepoint which has interesting
# interactions with the ConditionVariable.
bt = t.backtrace
- bt.should be_kind_of(Array)
+ bt.should.is_a?(Array)
bt.size.should >= 2
}
end
diff --git a/spec/ruby/core/data/deconstruct_keys_spec.rb b/spec/ruby/core/data/deconstruct_keys_spec.rb
index df378f8b98..7e81f966ea 100644
--- a/spec/ruby/core/data/deconstruct_keys_spec.rb
+++ b/spec/ruby/core/data/deconstruct_keys_spec.rb
@@ -15,7 +15,7 @@ describe "Data#deconstruct_keys" do
-> {
d.deconstruct_keys
- }.should raise_error(ArgumentError, /wrong number of arguments \(given 0, expected 1\)/)
+ }.should.raise(ArgumentError, /wrong number of arguments \(given 0, expected 1\)/)
end
it "returns only specified keys" do
@@ -34,29 +34,6 @@ describe "Data#deconstruct_keys" do
d.deconstruct_keys(['x', 'y']).should == {'x' => 1, 'y' => 2}
end
- it "accepts argument position number as well but returns them as keys" do
- klass = Data.define(:x, :y)
- d = klass.new(1, 2)
-
- d.deconstruct_keys([0, 1]).should == {0 => 1, 1 => 2}
- d.deconstruct_keys([0] ).should == {0 => 1}
- d.deconstruct_keys([-1] ).should == {-1 => 2}
- end
-
- it "ignores incorrect position numbers" do
- klass = Data.define(:x, :y)
- d = klass.new(1, 2)
-
- d.deconstruct_keys([0, 3]).should == {0 => 1}
- end
-
- it "support mixing attribute names and argument position numbers" do
- klass = Data.define(:x, :y)
- d = klass.new(1, 2)
-
- d.deconstruct_keys([0, :x]).should == {0 => 1, :x => 1}
- end
-
it "returns an empty hash when there are more keys than attributes" do
klass = Data.define(:x, :y)
d = klass.new(1, 2)
@@ -72,14 +49,6 @@ describe "Data#deconstruct_keys" do
d.deconstruct_keys([:x, :a]).should == {x: 1}
end
- it "returns at first not existing argument position number" do
- klass = Data.define(:x, :y)
- d = klass.new(1, 2)
-
- d.deconstruct_keys([3, 0]).should == {}
- d.deconstruct_keys([0, 3]).should == {0 => 1}
- end
-
it "accepts nil argument and return all the attributes" do
klass = Data.define(:x, :y)
d = klass.new(1, 2)
@@ -87,44 +56,55 @@ describe "Data#deconstruct_keys" do
d.deconstruct_keys(nil).should == {x: 1, y: 2}
end
- it "tries to convert a key with #to_int if index is not a String nor a Symbol, but responds to #to_int" do
- klass = Data.define(:x, :y)
- d = klass.new(1, 2)
+ ruby_version_is "4.0" do # https://bugs.ruby-lang.org/issues/21844
+ it "tries to convert a key with #to_str if index is not a String nor a Symbol, but responds to #to_str" do
+ klass = Data.define(:x, :y)
+ d = klass.new(1, 2)
- key = mock("to_int")
- key.should_receive(:to_int).and_return(1)
+ key = mock("to_str")
+ key.should_receive(:to_str).and_return("y")
- d.deconstruct_keys([key]).should == { key => 2 }
- end
+ d.deconstruct_keys([key]).should == { "y" => 2 }
+ end
- it "raises a TypeError if the conversion with #to_int does not return an Integer" do
- klass = Data.define(:x, :y)
- d = klass.new(1, 2)
+ it "raise an error on argument position number" do
+ klass = Data.define(:x, :y)
+ d = klass.new(1, 2)
- key = mock("to_int")
- key.should_receive(:to_int).and_return("not an Integer")
+ -> {
+ d.deconstruct_keys([0, 1])
+ }.should.raise(TypeError, "0 is not a symbol nor a string")
+ end
- -> {
- d.deconstruct_keys([key])
- }.should raise_error(TypeError, /can't convert MockObject to Integer/)
- end
+ it "raises a TypeError if the conversion with #to_str does not return a String" do
+ klass = Data.define(:x, :y)
+ d = klass.new(1, 2)
- it "raises TypeError if index is not a String, a Symbol and not convertible to Integer " do
- klass = Data.define(:x, :y)
- d = klass.new(1, 2)
+ key = mock("to_str")
+ key.should_receive(:to_str).and_return(0)
- -> {
- d.deconstruct_keys([0, []])
- }.should raise_error(TypeError, "no implicit conversion of Array into Integer")
+ -> {
+ d.deconstruct_keys([key])
+ }.should raise_consistent_error(TypeError, /can't convert MockObject into String/)
+ end
+
+ it "raises TypeError if index is not a Symbol and not convertible to String" do
+ klass = Data.define(:x, :y)
+ d = klass.new(1, 2)
+
+ -> {
+ d.deconstruct_keys([0, []])
+ }.should.raise(TypeError, "0 is not a symbol nor a string")
+ end
end
it "raise TypeError if passed anything except nil or array" do
klass = Data.define(:x, :y)
d = klass.new(1, 2)
- -> { d.deconstruct_keys('x') }.should raise_error(TypeError, /expected Array or nil/)
- -> { d.deconstruct_keys(1) }.should raise_error(TypeError, /expected Array or nil/)
- -> { d.deconstruct_keys(:x) }.should raise_error(TypeError, /expected Array or nil/)
- -> { d.deconstruct_keys({}) }.should raise_error(TypeError, /expected Array or nil/)
+ -> { d.deconstruct_keys('x') }.should.raise(TypeError, /expected Array or nil/)
+ -> { d.deconstruct_keys(1) }.should.raise(TypeError, /expected Array or nil/)
+ -> { d.deconstruct_keys(:x) }.should.raise(TypeError, /expected Array or nil/)
+ -> { d.deconstruct_keys({}) }.should.raise(TypeError, /expected Array or nil/)
end
end
diff --git a/spec/ruby/core/data/fixtures/classes.rb b/spec/ruby/core/data/fixtures/classes.rb
index ffd361d781..147293ee45 100644
--- a/spec/ruby/core/data/fixtures/classes.rb
+++ b/spec/ruby/core/data/fixtures/classes.rb
@@ -1,6 +1,7 @@
module DataSpecs
if Data.respond_to?(:define)
Measure = Data.define(:amount, :unit)
+ Single = Data.define(:value)
class MeasureWithOverriddenName < Measure
def self.name
@@ -8,6 +9,12 @@ module DataSpecs
end
end
+ class SingleWithOverriddenName < Single
+ def self.name
+ "A"
+ end
+ end
+
class DataSubclass < Data; end
MeasureSubclass = Class.new(Measure) do
@@ -24,5 +31,11 @@ module DataSpecs
ScratchPad.record [:initialize, rest, kw]
end
end
+
+ Area = Data.define(:width, :height, :area) do
+ def initialize(width:, height:)
+ super(width: width, height: height, area: width * height)
+ end
+ end
end
end
diff --git a/spec/ruby/core/data/hash_spec.rb b/spec/ruby/core/data/hash_spec.rb
index c23f08a71d..bab146c92e 100644
--- a/spec/ruby/core/data/hash_spec.rb
+++ b/spec/ruby/core/data/hash_spec.rb
@@ -6,7 +6,7 @@ describe "Data#hash" do
a = DataSpecs::Measure.new(42, "km")
b = DataSpecs::Measure.new(42, "km")
a.hash.should == b.hash
- a.hash.should be_an_instance_of(Integer)
+ a.hash.should.instance_of?(Integer)
end
it "returns different hashes for objects with different values" do
diff --git a/spec/ruby/core/data/initialize_spec.rb b/spec/ruby/core/data/initialize_spec.rb
index 9d272780a8..0320ca880c 100644
--- a/spec/ruby/core/data/initialize_spec.rb
+++ b/spec/ruby/core/data/initialize_spec.rb
@@ -2,6 +2,16 @@ require_relative '../../spec_helper'
require_relative 'fixtures/classes'
describe "Data#initialize" do
+ context "with no members" do
+ ruby_bug "#21819", ""..."4.0.1" do
+ it "is frozen" do
+ data = Data.define
+
+ data.new.should.frozen?
+ end
+ end
+ end
+
it "accepts positional arguments" do
data = DataSpecs::Measure.new(42, "km")
@@ -37,10 +47,27 @@ describe "Data#initialize" do
data.unit.should == "km"
end
+ it "accepts the last entry when a keyword is given as both String and Symbol" do
+ data = DataSpecs::Single.new("value" => -1, value: 42)
+
+ data.value.should == 42
+ end
+
+ it "accepts positional arguments with empty keyword arguments" do
+ data = DataSpecs::Single.new(42, **{})
+
+ data.value.should == 42
+
+ data = DataSpecs::Measure.new(42, "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|
+ }.should.raise(ArgumentError) { |e|
e.message.should.include?("missing keywords: :amount, :unit")
}
end
@@ -48,19 +75,61 @@ describe "Data#initialize" do
it "raises ArgumentError if at least one argument is missing" do
-> {
DataSpecs::Measure.new(unit: "km")
- }.should raise_error(ArgumentError) { |e|
+ }.should.raise(ArgumentError) { |e|
e.message.should.include?("missing keyword: :amount")
}
end
+ ruby_version_is "4.0" do # https://bugs.ruby-lang.org/issues/21844
+ it "raises ArgumentError if at least one argument is missing and other is provided as both String and Symbol" do
+ -> {
+ DataSpecs::Measure.new(unit: "km", "unit" => "km")
+ }.should.raise(ArgumentError) { |e|
+ e.message.should.include?("missing keyword: :amount")
+ }
+ end
+ end
+
it "raises ArgumentError if unknown keyword is given" do
-> {
DataSpecs::Measure.new(amount: 42, unit: "km", system: "metric")
- }.should raise_error(ArgumentError) { |e|
+ }.should.raise(ArgumentError) { |e|
e.message.should.include?("unknown keyword: :system")
}
end
+ ruby_version_is "4.0" do # https://bugs.ruby-lang.org/issues/21844
+ it "raises ArgumentError if unknown keyword is given which is convertable to String" do
+ key = mock("to_str")
+ key.should_receive(:to_str).and_return("system")
+
+ -> {
+ DataSpecs::Measure.new(amount: 42, unit: "km", key => "metric")
+ }.should.raise(ArgumentError) { |e|
+ e.message.should.include?('unknown keyword: "system"')
+ }
+ end
+
+ it "raises TypeError when the keyword is not convertable to String" do
+ -> {
+ DataSpecs::Measure.new(1 => 2)
+ }.should.raise(TypeError) { |e|
+ e.message.should == "1 is not a symbol nor a string"
+ }
+ end
+
+ it "raises TypeError if the conversion with #to_str does not return a String" do
+ klass = Data.define(:x, :y)
+
+ key = mock("to_str")
+ key.should_receive(:to_str).and_return(0)
+
+ -> {
+ klass.new(key => 2)
+ }.should raise_consistent_error(TypeError, /can't convert MockObject into String/)
+ end
+ end
+
it "supports super from a subclass" do
ms = DataSpecs::MeasureSubclass.new(amount: 1, unit: "km")
@@ -69,7 +138,7 @@ describe "Data#initialize" do
end
it "supports Data with no fields" do
- -> { DataSpecs::Empty.new }.should_not raise_error
+ -> { DataSpecs::Empty.new }.should_not.raise
end
it "can be overridden" do
@@ -110,5 +179,26 @@ describe "Data#initialize" do
DataSpecs::DataWithOverriddenInitialize[amount: 42, unit: "m"]
ScratchPad.recorded.should == [:initialize, [], {amount: 42, unit: "m"}]
end
+
+ it "accepts positional arguments with empty keyword arguments" do
+ data = DataSpecs::SingleWithOverriddenName.new(42, **{})
+
+ data.value.should == 42
+
+ data = DataSpecs::MeasureWithOverriddenName.new(42, "km", **{})
+
+ data.amount.should == 42
+ data.unit.should == "km"
+ end
+
+ # See https://github.com/ruby/psych/pull/765
+ it "can be deserialized by calling Data.instance_method(:initialize)" do
+ d1 = DataSpecs::Area.new(width: 2, height: 3)
+ d1.area.should == 6
+
+ d2 = DataSpecs::Area.allocate
+ Data.instance_method(:initialize).bind_call(d2, **d1.to_h)
+ d2.should == d1
+ end
end
end
diff --git a/spec/ruby/core/data/inspect_spec.rb b/spec/ruby/core/data/inspect_spec.rb
index 38642910a0..e5b9689ca5 100644
--- a/spec/ruby/core/data/inspect_spec.rb
+++ b/spec/ruby/core/data/inspect_spec.rb
@@ -1,6 +1,8 @@
require_relative '../../spec_helper'
-require_relative 'shared/inspect'
+require_relative 'fixtures/classes'
describe "Data#inspect" do
- it_behaves_like :data_inspect, :inspect
+ it "is an alias of Data#to_s" do
+ DataSpecs::Measure.instance_method(:inspect).should == DataSpecs::Measure.instance_method(:to_s)
+ end
end
diff --git a/spec/ruby/core/data/shared/inspect.rb b/spec/ruby/core/data/shared/inspect.rb
deleted file mode 100644
index 6cd5664da7..0000000000
--- a/spec/ruby/core/data/shared/inspect.rb
+++ /dev/null
@@ -1,62 +0,0 @@
-require_relative '../fixtures/classes'
-
-describe :data_inspect, shared: true do
- it "returns a string representation showing members and values" do
- a = DataSpecs::Measure.new(42, "km")
- a.send(@method).should == '#<data DataSpecs::Measure amount=42, unit="km">'
- end
-
- it "returns a string representation without the class name for anonymous structs" do
- Data.define(:a).new("").send(@method).should == '#<data 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
- Foo = Data.define(:a)
- DOC
-
- c::Foo.new("").send(@method).should == '#<data a="">'
- end
-
- it "returns a string representation without the class name for structs nested in anonymous modules" do
- m = Module.new
- m.class_eval <<~DOC
- Foo = Data.define(:a)
- DOC
-
- m::Foo.new("").send(@method).should == '#<data a="">'
- end
-
- it "does not call #name method" do
- struct = DataSpecs::MeasureWithOverriddenName.new(42, "km")
- struct.send(@method).should == '#<data DataSpecs::MeasureWithOverriddenName amount=42, unit="km">'
- end
-
- it "does not call #name method when struct is anonymous" do
- klass = Class.new(DataSpecs::Measure) do
- def self.name
- "A"
- end
- end
- struct = klass.new(42, "km")
- struct.send(@method).should == '#<data amount=42, unit="km">'
- end
-
- context "recursive structure" do
- it "returns string representation with recursive attribute replaced with ..." do
- a = DataSpecs::Measure.allocate
- a.send(:initialize, amount: 42, unit: a)
-
- a.send(@method).should == "#<data DataSpecs::Measure amount=42, unit=#<data DataSpecs::Measure:...>>"
- end
-
- it "returns string representation with recursive attribute replaced with ... when an anonymous class" do
- klass = Class.new(DataSpecs::Measure)
- a = klass.allocate
- a.send(:initialize, amount: 42, unit: a)
-
- a.send(@method).should =~ /#<data amount=42, unit=#<data #<Class:0x.+?>:\.\.\.>>/
- end
- end
-end
diff --git a/spec/ruby/core/data/to_h_spec.rb b/spec/ruby/core/data/to_h_spec.rb
index 64816b7251..41925cf3b2 100644
--- a/spec/ruby/core/data/to_h_spec.rb
+++ b/spec/ruby/core/data/to_h_spec.rb
@@ -28,18 +28,18 @@ describe "Data#to_h" do
data = DataSpecs::Measure.new(amount: 42, unit: 'km')
-> do
data.to_h { |k, v| [k.to_s, v*v, 1] }
- end.should raise_error(ArgumentError, /element has wrong array length/)
+ end.should.raise(ArgumentError, /element has wrong array length/)
-> do
data.to_h { |k, v| [k] }
- end.should raise_error(ArgumentError, /element has wrong array length/)
+ end.should.raise(ArgumentError, /element has wrong array length/)
end
it "raises TypeError if block returns something other than Array" do
data = DataSpecs::Measure.new(amount: 42, unit: 'km')
-> do
data.to_h { |k, v| "not-array" }
- end.should raise_error(TypeError, /wrong element type String/)
+ end.should.raise(TypeError, /wrong element type String/)
end
it "coerces returned pair to Array with #to_ary" do
@@ -57,7 +57,7 @@ describe "Data#to_h" do
-> do
data.to_h { |k| x }
- end.should raise_error(TypeError, /wrong element type MockObject/)
+ end.should.raise(TypeError, /wrong element type MockObject/)
end
end
end
diff --git a/spec/ruby/core/data/to_s_spec.rb b/spec/ruby/core/data/to_s_spec.rb
index 2b4a670e8e..e436c21109 100644
--- a/spec/ruby/core/data/to_s_spec.rb
+++ b/spec/ruby/core/data/to_s_spec.rb
@@ -1,6 +1,63 @@
require_relative '../../spec_helper'
-require_relative 'shared/inspect'
+require_relative 'fixtures/classes'
describe "Data#to_s" do
- it_behaves_like :data_inspect, :to_s
+ it "returns a string representation showing members and values" do
+ a = DataSpecs::Measure.new(42, "km")
+ a.to_s.should == '#<data DataSpecs::Measure amount=42, unit="km">'
+ end
+
+ it "returns a string representation without the class name for anonymous structs" do
+ Data.define(:a).new("").to_s.should == '#<data 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
+ Foo = Data.define(:a)
+ DOC
+
+ c::Foo.new("").to_s.should == '#<data a="">'
+ end
+
+ it "returns a string representation without the class name for structs nested in anonymous modules" do
+ m = Module.new
+ m.class_eval <<~DOC
+ Foo = Data.define(:a)
+ DOC
+
+ m::Foo.new("").to_s.should == '#<data a="">'
+ end
+
+ it "does not call #name method" do
+ struct = DataSpecs::MeasureWithOverriddenName.new(42, "km")
+ struct.to_s.should == '#<data DataSpecs::MeasureWithOverriddenName amount=42, unit="km">'
+ end
+
+ it "does not call #name method when struct is anonymous" do
+ klass = Class.new(DataSpecs::Measure) do
+ def self.name
+ "A"
+ end
+ end
+ struct = klass.new(42, "km")
+ struct.to_s.should == '#<data amount=42, unit="km">'
+ end
+
+ context "recursive structure" do
+ it "returns string representation with recursive attribute replaced with ..." do
+ a = DataSpecs::Measure.allocate
+ a.send(:initialize, amount: 42, unit: a)
+
+ a.to_s.should == "#<data DataSpecs::Measure amount=42, unit=#<data DataSpecs::Measure:...>>"
+ end
+
+ it "returns string representation with recursive attribute replaced with ... when an anonymous class" do
+ klass = Class.new(DataSpecs::Measure)
+ a = klass.allocate
+ a.send(:initialize, amount: 42, unit: a)
+
+ a.to_s.should =~ /#<data amount=42, unit=#<data #<Class:0x.+?>:\.\.\.>>/
+ end
+ end
end
diff --git a/spec/ruby/core/data/with_spec.rb b/spec/ruby/core/data/with_spec.rb
index fd0a99d1fa..b74df185c7 100644
--- a/spec/ruby/core/data/with_spec.rb
+++ b/spec/ruby/core/data/with_spec.rb
@@ -28,7 +28,7 @@ describe "Data#with" do
-> {
data.with(4, "m")
- }.should raise_error(ArgumentError, "wrong number of arguments (given 2, expected 0)")
+ }.should.raise(ArgumentError, "wrong number of arguments (given 2, expected 0)")
end
it "does not depend on the Data.new method" do
@@ -44,14 +44,12 @@ describe "Data#with" do
data_copy.unit.should == "m"
end
- ruby_version_is "3.3" do
- it "calls #initialize" do
- data = DataSpecs::DataWithOverriddenInitialize.new(42, "m")
- ScratchPad.clear
+ it "calls #initialize" do
+ data = DataSpecs::DataWithOverriddenInitialize.new(42, "m")
+ ScratchPad.clear
- data.with(amount: 0)
+ data.with(amount: 0)
- ScratchPad.recorded.should == [:initialize, [], {amount: 0, unit: "m"}]
- end
+ ScratchPad.recorded.should == [:initialize, [], {amount: 0, unit: "m"}]
end
end
diff --git a/spec/ruby/core/dir/chdir_spec.rb b/spec/ruby/core/dir/chdir_spec.rb
index 015386a902..2dc598e2a9 100644
--- a/spec/ruby/core/dir/chdir_spec.rb
+++ b/spec/ruby/core/dir/chdir_spec.rb
@@ -90,8 +90,8 @@ describe "Dir.chdir" do
end
it "raises an Errno::ENOENT if the directory does not exist" do
- -> { Dir.chdir DirSpecs.nonexistent }.should raise_error(Errno::ENOENT)
- -> { Dir.chdir(DirSpecs.nonexistent) { } }.should raise_error(Errno::ENOENT)
+ -> { Dir.chdir DirSpecs.nonexistent }.should.raise(Errno::ENOENT)
+ -> { Dir.chdir(DirSpecs.nonexistent) { } }.should.raise(Errno::ENOENT)
end
it "raises an Errno::ENOENT if the original directory no longer exists" do
@@ -106,7 +106,7 @@ describe "Dir.chdir" do
Dir.chdir dir1 do
Dir.chdir(dir2) { Dir.unlink dir1 }
end
- }.should raise_error(Errno::ENOENT)
+ }.should.raise(Errno::ENOENT)
ensure
Dir.unlink dir1 if Dir.exist?(dir1)
Dir.unlink dir2 if Dir.exist?(dir2)
@@ -125,96 +125,94 @@ describe "Dir.chdir" do
end
end
-ruby_version_is '3.3' do
- describe "Dir#chdir" do
- before :all do
- DirSpecs.create_mock_dirs
- end
+describe "Dir#chdir" do
+ before :all do
+ DirSpecs.create_mock_dirs
+ end
- after :all do
- DirSpecs.delete_mock_dirs
- end
+ after :all do
+ DirSpecs.delete_mock_dirs
+ end
- before :each do
- @original = Dir.pwd
- end
+ before :each do
+ @original = Dir.pwd
+ end
- after :each do
- Dir.chdir(@original)
- end
+ after :each do
+ Dir.chdir(@original)
+ end
- it "changes the current working directory to self" do
- dir = Dir.new(DirSpecs.mock_dir)
- dir.chdir
- Dir.pwd.should == DirSpecs.mock_dir
- ensure
- dir.close
- end
+ it "changes the current working directory to self" do
+ dir = Dir.new(DirSpecs.mock_dir)
+ dir.chdir
+ Dir.pwd.should == DirSpecs.mock_dir
+ ensure
+ dir.close
+ end
- it "changes the current working directory to self for duration of the block when a block is given" do
- dir = Dir.new(DirSpecs.mock_dir)
- pwd_in_block = nil
+ it "changes the current working directory to self for duration of the block when a block is given" do
+ dir = Dir.new(DirSpecs.mock_dir)
+ pwd_in_block = nil
- dir.chdir { pwd_in_block = Dir.pwd }
+ dir.chdir { pwd_in_block = Dir.pwd }
- pwd_in_block.should == DirSpecs.mock_dir
- Dir.pwd.should == @original
- ensure
- dir.close
- end
+ pwd_in_block.should == DirSpecs.mock_dir
+ Dir.pwd.should == @original
+ ensure
+ dir.close
+ end
- it "returns 0 when successfully changing directory" do
- dir = Dir.new(DirSpecs.mock_dir)
- dir.chdir.should == 0
- ensure
- dir.close
- end
+ it "returns 0 when successfully changing directory" do
+ dir = Dir.new(DirSpecs.mock_dir)
+ dir.chdir.should == 0
+ ensure
+ dir.close
+ end
- it "returns the value of the block when a block is given" do
- dir = Dir.new(DirSpecs.mock_dir)
- dir.chdir { :block_value }.should == :block_value
- ensure
- dir.close
- end
+ it "returns the value of the block when a block is given" do
+ dir = Dir.new(DirSpecs.mock_dir)
+ dir.chdir { :block_value }.should == :block_value
+ ensure
+ dir.close
+ end
+
+ platform_is_not :windows do
+ it "does not raise an Errno::ENOENT if the original directory no longer exists" do
+ dir_name1 = tmp('testdir1')
+ dir_name2 = tmp('testdir2')
+ Dir.should_not.exist?(dir_name1)
+ Dir.should_not.exist?(dir_name2)
+ Dir.mkdir dir_name1
+ Dir.mkdir dir_name2
- platform_is_not :windows do
- it "does not raise an Errno::ENOENT if the original directory no longer exists" do
- dir_name1 = tmp('testdir1')
- dir_name2 = tmp('testdir2')
- Dir.should_not.exist?(dir_name1)
- Dir.should_not.exist?(dir_name2)
- Dir.mkdir dir_name1
- Dir.mkdir dir_name2
-
- dir2 = Dir.new(dir_name2)
-
- begin
- Dir.chdir(dir_name1) do
- dir2.chdir { Dir.unlink dir_name1 }
- end
- Dir.pwd.should == @original
- ensure
- Dir.unlink dir_name1 if Dir.exist?(dir_name1)
- Dir.unlink dir_name2 if Dir.exist?(dir_name2)
+ dir2 = Dir.new(dir_name2)
+
+ begin
+ Dir.chdir(dir_name1) do
+ dir2.chdir { Dir.unlink dir_name1 }
end
+ Dir.pwd.should == @original
ensure
- dir2.close
+ Dir.unlink dir_name1 if Dir.exist?(dir_name1)
+ Dir.unlink dir_name2 if Dir.exist?(dir_name2)
end
+ ensure
+ dir2.close
end
+ end
- it "always returns to the original directory when given a block" do
- dir = Dir.new(DirSpecs.mock_dir)
+ it "always returns to the original directory when given a block" do
+ dir = Dir.new(DirSpecs.mock_dir)
- begin
- dir.chdir do
- raise StandardError, "something bad happened"
- end
- rescue StandardError
+ begin
+ dir.chdir do
+ raise StandardError, "something bad happened"
end
-
- Dir.pwd.should == @original
- ensure
- dir.close
+ rescue StandardError
end
+
+ Dir.pwd.should == @original
+ ensure
+ dir.close
end
end
diff --git a/spec/ruby/core/dir/children_spec.rb b/spec/ruby/core/dir/children_spec.rb
index 0ad3df4669..6e6da1dd44 100644
--- a/spec/ruby/core/dir/children_spec.rb
+++ b/spec/ruby/core/dir/children_spec.rb
@@ -47,25 +47,25 @@ 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".dup.force_encoding(encoding))
end
- children.first.encoding.should equal(Encoding.find("filesystem"))
+ children.first.encoding.should.equal?(Encoding.find("filesystem"))
end
it "returns children encoded with the specified encoding" do
dir = File.join(DirSpecs.mock_dir, 'special')
children = Dir.children(dir, encoding: "euc-jp").sort
- children.first.encoding.should equal(Encoding::EUC_JP)
+ children.first.encoding.should.equal?(Encoding::EUC_JP)
end
it "returns children transcoded to the default internal encoding" do
Encoding.default_internal = Encoding::EUC_KR
children = Dir.children(File.join(DirSpecs.mock_dir, 'special')).sort
- children.first.encoding.should equal(Encoding::EUC_KR)
+ children.first.encoding.should.equal?(Encoding::EUC_KR)
end
it "raises a SystemCallError if called with a nonexistent directory" do
- -> { Dir.children DirSpecs.nonexistent }.should raise_error(SystemCallError)
+ -> { Dir.children DirSpecs.nonexistent }.should.raise(SystemCallError)
end
end
@@ -113,23 +113,23 @@ 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".dup.force_encoding(encoding))
end
- children.first.encoding.should equal(Encoding.find("filesystem"))
+ children.first.encoding.should.equal?(Encoding.find("filesystem"))
end
it "returns children encoded with the specified encoding" do
path = File.join(DirSpecs.mock_dir, 'special')
@dir = Dir.new(path, encoding: "euc-jp")
children = @dir.children.sort
- children.first.encoding.should equal(Encoding::EUC_JP)
+ children.first.encoding.should.equal?(Encoding::EUC_JP)
end
it "returns children transcoded to the default internal encoding" do
Encoding.default_internal = Encoding::EUC_KR
@dir = Dir.new(File.join(DirSpecs.mock_dir, 'special'))
children = @dir.children.sort
- children.first.encoding.should equal(Encoding::EUC_KR)
+ children.first.encoding.should.equal?(Encoding::EUC_KR)
end
it "returns the same result when called repeatedly" do
diff --git a/spec/ruby/core/dir/chroot_spec.rb b/spec/ruby/core/dir/chroot_spec.rb
index a5ca8943fc..79ad9759b0 100644
--- a/spec/ruby/core/dir/chroot_spec.rb
+++ b/spec/ruby/core/dir/chroot_spec.rb
@@ -21,17 +21,17 @@ platform_is_not :windows do
end
it "raises an Errno::EPERM exception if the directory exists" do
- -> { Dir.chroot('.') }.should raise_error(Errno::EPERM)
+ -> { Dir.chroot('.') }.should.raise(Errno::EPERM)
end
it "raises a SystemCallError if the directory doesn't exist" do
- -> { Dir.chroot('xgwhwhsjai2222jg') }.should raise_error(SystemCallError)
+ -> { Dir.chroot('xgwhwhsjai2222jg') }.should.raise(SystemCallError)
end
it "calls #to_path on non-String argument" do
p = mock('path')
p.should_receive(:to_path).and_return('.')
- -> { Dir.chroot(p) }.should raise_error(Errno::EPERM)
+ -> { Dir.chroot(p) }.should.raise(Errno::EPERM)
end
end
end
diff --git a/spec/ruby/core/dir/close_spec.rb b/spec/ruby/core/dir/close_spec.rb
index f7cce318b8..9902d98934 100644
--- a/spec/ruby/core/dir/close_spec.rb
+++ b/spec/ruby/core/dir/close_spec.rb
@@ -15,7 +15,7 @@ describe "Dir#close" do
dir.close.should == nil
platform_is_not :windows do
- -> { dir.fileno }.should raise_error(IOError, /closed directory/)
+ -> { dir.fileno }.should.raise(IOError, /closed directory/)
end
end
@@ -24,7 +24,7 @@ describe "Dir#close" do
dir.close.should == nil
end
- ruby_version_is '3.3'...'3.4' do
+ ruby_version_is ''...'3.4' do
platform_is_not :windows do
it "does not raise an error even if the file descriptor is closed with another Dir instance" do
dir = Dir.open DirSpecs.mock_dir
@@ -33,8 +33,8 @@ describe "Dir#close" do
dir.close
dir_new.close
- -> { dir.fileno }.should raise_error(IOError, /closed directory/)
- -> { dir_new.fileno }.should raise_error(IOError, /closed directory/)
+ -> { dir.fileno }.should.raise(IOError, /closed directory/)
+ -> { dir_new.fileno }.should.raise(IOError, /closed directory/)
end
end
end
@@ -46,7 +46,7 @@ describe "Dir#close" do
dir_new = Dir.for_fd(dir.fileno)
dir.close
- -> { dir_new.close }.should raise_error(Errno::EBADF, 'Bad file descriptor - closedir')
+ -> { dir_new.close }.should.raise(Errno::EBADF, 'Bad file descriptor - closedir')
end
end
end
diff --git a/spec/ruby/core/dir/delete_spec.rb b/spec/ruby/core/dir/delete_spec.rb
index a0020788ca..2dbd461c94 100644
--- a/spec/ruby/core/dir/delete_spec.rb
+++ b/spec/ruby/core/dir/delete_spec.rb
@@ -1,6 +1,5 @@
require_relative '../../spec_helper'
require_relative 'fixtures/common'
-require_relative 'shared/delete'
describe "Dir.delete" do
before :all do
@@ -11,5 +10,55 @@ describe "Dir.delete" do
DirSpecs.delete_mock_dirs
end
- it_behaves_like :dir_delete, :delete
+ before :each do
+ DirSpecs.rmdir_dirs true
+ end
+
+ after :each do
+ DirSpecs.rmdir_dirs false
+ end
+
+ it "removes empty directories" do
+ Dir.delete(DirSpecs.mock_rmdir("empty")).should == 0
+ end
+
+ it "calls #to_path on non-String arguments" do
+ p = mock('path')
+ p.should_receive(:to_path).and_return(DirSpecs.mock_rmdir("empty"))
+ Dir.delete(p)
+ end
+
+ it "raises an Errno::ENOTEMPTY when trying to remove a nonempty directory" do
+ -> do
+ Dir.delete DirSpecs.mock_rmdir("nonempty")
+ end.should.raise(Errno::ENOTEMPTY)
+ end
+
+ it "raises an Errno::ENOENT when trying to remove a non-existing directory" do
+ -> do
+ Dir.delete DirSpecs.nonexistent
+ end.should.raise(Errno::ENOENT)
+ end
+
+ it "raises an Errno::ENOTDIR when trying to remove a non-directory" do
+ file = DirSpecs.mock_rmdir("nonempty/regular")
+ touch(file)
+ -> do
+ Dir.delete file
+ end.should.raise(Errno::ENOTDIR)
+ end
+
+ # this won't work on Windows, since chmod(0000) does not remove all permissions
+ platform_is_not :windows do
+ as_user do
+ it "raises an Errno::EACCES if lacking adequate permissions to remove the directory" do
+ parent = DirSpecs.mock_rmdir("noperm")
+ child = DirSpecs.mock_rmdir("noperm", "child")
+ File.chmod(0000, parent)
+ -> do
+ Dir.delete child
+ end.should.raise(Errno::EACCES)
+ end
+ end
+ end
end
diff --git a/spec/ruby/core/dir/each_child_spec.rb b/spec/ruby/core/dir/each_child_spec.rb
index 7194273b95..4d6575df39 100644
--- a/spec/ruby/core/dir/each_child_spec.rb
+++ b/spec/ruby/core/dir/each_child_spec.rb
@@ -36,12 +36,12 @@ describe "Dir.each_child" do
end
it "raises a SystemCallError if passed a nonexistent directory" do
- -> { Dir.each_child(DirSpecs.nonexistent) {} }.should raise_error(SystemCallError)
+ -> { Dir.each_child(DirSpecs.nonexistent) {} }.should.raise(SystemCallError)
end
describe "when no block is given" do
it "returns an Enumerator" do
- Dir.each_child(DirSpecs.mock_dir).should be_an_instance_of(Enumerator)
+ Dir.each_child(DirSpecs.mock_dir).should.instance_of?(Enumerator)
Dir.each_child(DirSpecs.mock_dir).to_a.sort.should == DirSpecs.expected_paths - %w[. ..]
end
@@ -103,7 +103,7 @@ describe "Dir#each_child" do
it "returns an Enumerator" do
@dir = Dir.new(DirSpecs.mock_dir)
- @dir.each_child.should be_an_instance_of(Enumerator)
+ @dir.each_child.should.instance_of?(Enumerator)
@dir.each_child.to_a.sort.should == DirSpecs.expected_paths - %w|. ..|
end
diff --git a/spec/ruby/core/dir/each_spec.rb b/spec/ruby/core/dir/each_spec.rb
index 7674663d82..e997e340b1 100644
--- a/spec/ruby/core/dir/each_spec.rb
+++ b/spec/ruby/core/dir/each_spec.rb
@@ -32,7 +32,7 @@ describe "Dir#each" do
@dir.each {}.should == @dir
@dir.read.should == nil
@dir.rewind
- ls.should include(@dir.read)
+ ls.should.include?(@dir.read)
end
it "returns the same result when called repeatedly" do
@@ -48,7 +48,7 @@ describe "Dir#each" do
describe "when no block is given" do
it "returns an Enumerator" do
- @dir.each.should be_an_instance_of(Enumerator)
+ @dir.each.should.instance_of?(Enumerator)
@dir.each.to_a.sort.should == DirSpecs.expected_paths
end
diff --git a/spec/ruby/core/dir/empty_spec.rb b/spec/ruby/core/dir/empty_spec.rb
index 8cc8757798..3b6b2bac85 100644
--- a/spec/ruby/core/dir/empty_spec.rb
+++ b/spec/ruby/core/dir/empty_spec.rb
@@ -12,20 +12,20 @@ describe "Dir.empty?" do
it "returns true for empty directories" do
result = Dir.empty? @empty_dir
- result.should be_true
+ result.should == true
end
it "returns false for non-empty directories" do
result = Dir.empty? __dir__
- result.should be_false
+ result.should == false
end
it "returns false for a non-directory" do
result = Dir.empty? __FILE__
- result.should be_false
+ result.should == false
end
it "raises ENOENT for nonexistent directories" do
- -> { Dir.empty? tmp("nonexistent") }.should raise_error(Errno::ENOENT)
+ -> { Dir.empty? tmp("nonexistent") }.should.raise(Errno::ENOENT)
end
end
diff --git a/spec/ruby/core/dir/entries_spec.rb b/spec/ruby/core/dir/entries_spec.rb
index 7462542acf..f3ca49b26d 100644
--- a/spec/ruby/core/dir/entries_spec.rb
+++ b/spec/ruby/core/dir/entries_spec.rb
@@ -47,24 +47,24 @@ 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".dup.force_encoding(encoding))
end
- entries.first.encoding.should equal(Encoding.find("filesystem"))
+ entries.first.encoding.should.equal?(Encoding.find("filesystem"))
end
it "returns entries encoded with the specified encoding" do
dir = File.join(DirSpecs.mock_dir, 'special')
entries = Dir.entries(dir, encoding: "euc-jp").sort
- entries.first.encoding.should equal(Encoding::EUC_JP)
+ entries.first.encoding.should.equal?(Encoding::EUC_JP)
end
it "returns entries transcoded to the default internal encoding" do
Encoding.default_internal = Encoding::EUC_KR
entries = Dir.entries(File.join(DirSpecs.mock_dir, 'special')).sort
- entries.first.encoding.should equal(Encoding::EUC_KR)
+ entries.first.encoding.should.equal?(Encoding::EUC_KR)
end
it "raises a SystemCallError if called with a nonexistent directory" do
- -> { Dir.entries DirSpecs.nonexistent }.should raise_error(SystemCallError)
+ -> { Dir.entries DirSpecs.nonexistent }.should.raise(SystemCallError)
end
end
diff --git a/spec/ruby/core/dir/exist_spec.rb b/spec/ruby/core/dir/exist_spec.rb
index 0b8e521894..05ad67dd03 100644
--- a/spec/ruby/core/dir/exist_spec.rb
+++ b/spec/ruby/core/dir/exist_spec.rb
@@ -1,6 +1,5 @@
require_relative '../../spec_helper'
require_relative 'fixtures/common'
-require_relative 'shared/exist'
describe "Dir.exist?" do
before :all do
@@ -11,7 +10,61 @@ describe "Dir.exist?" do
DirSpecs.delete_mock_dirs
end
- it_behaves_like :dir_exist, :exist?
+ it "returns true if the given directory exists" do
+ Dir.exist?(__dir__).should == true
+ end
+
+ it "returns true for '.'" do
+ Dir.exist?('.').should == true
+ end
+
+ it "returns true for '..'" do
+ Dir.exist?('..').should == true
+ end
+
+ it "understands non-ASCII paths" do
+ subdir = File.join(tmp("\u{9876}\u{665}"))
+ Dir.exist?(subdir).should == false
+ Dir.mkdir(subdir)
+ Dir.exist?(subdir).should == true
+ Dir.rmdir(subdir)
+ end
+
+ it "understands relative paths" do
+ Dir.exist?(__dir__ + '/../').should == true
+ end
+
+ it "returns false if the given directory doesn't exist" do
+ Dir.exist?('y26dg27n2nwjs8a/').should == false
+ end
+
+ it "doesn't require the name to have a trailing slash" do
+ dir = __dir__
+ dir.sub!(/\/$/,'')
+ Dir.exist?(dir).should == true
+ end
+
+ it "doesn't expand paths" do
+ skip "$HOME not valid directory" unless ENV['HOME'] && File.directory?(ENV['HOME'])
+ Dir.exist?(File.expand_path('~')).should == true
+ Dir.exist?('~').should == false
+ end
+
+ it "returns false if the argument exists but is a file" do
+ File.should.exist?(__FILE__)
+ Dir.exist?(__FILE__).should == false
+ end
+
+ it "doesn't set $! when file doesn't exist" do
+ Dir.exist?("/path/to/non/existent/dir")
+ $!.should == nil
+ end
+
+ it "calls #to_path on non String arguments" do
+ p = mock('path')
+ p.should_receive(:to_path).and_return(__dir__)
+ Dir.exist?(p)
+ end
end
describe "Dir.exists?" do
diff --git a/spec/ruby/core/dir/fchdir_spec.rb b/spec/ruby/core/dir/fchdir_spec.rb
index 52600a95f2..bd1a92b05e 100644
--- a/spec/ruby/core/dir/fchdir_spec.rb
+++ b/spec/ruby/core/dir/fchdir_spec.rb
@@ -1,73 +1,71 @@
require_relative '../../spec_helper'
require_relative 'fixtures/common'
-ruby_version_is '3.3' do
- platform_is_not :windows do
- describe "Dir.fchdir" do
- before :all do
- DirSpecs.create_mock_dirs
- end
+platform_is_not :windows do
+ describe "Dir.fchdir" do
+ before :all do
+ DirSpecs.create_mock_dirs
+ end
- after :all do
- DirSpecs.delete_mock_dirs
- end
+ after :all do
+ DirSpecs.delete_mock_dirs
+ end
- before :each do
- @original = Dir.pwd
- end
+ before :each do
+ @original = Dir.pwd
+ end
- after :each do
- Dir.chdir(@original)
- end
+ after :each do
+ Dir.chdir(@original)
+ end
- it "changes the current working directory to the directory specified by the integer file descriptor" do
- dir = Dir.new(DirSpecs.mock_dir)
- Dir.fchdir dir.fileno
- Dir.pwd.should == DirSpecs.mock_dir
- ensure
- dir.close
- end
+ it "changes the current working directory to the directory specified by the integer file descriptor" do
+ dir = Dir.new(DirSpecs.mock_dir)
+ Dir.fchdir dir.fileno
+ Dir.pwd.should == DirSpecs.mock_dir
+ ensure
+ dir.close
+ end
- it "returns 0 when successfully changing directory" do
- dir = Dir.new(DirSpecs.mock_dir)
- Dir.fchdir(dir.fileno).should == 0
- ensure
- dir.close
- end
+ it "returns 0 when successfully changing directory" do
+ dir = Dir.new(DirSpecs.mock_dir)
+ Dir.fchdir(dir.fileno).should == 0
+ ensure
+ dir.close
+ end
- it "returns the value of the block when a block is given" do
- dir = Dir.new(DirSpecs.mock_dir)
- Dir.fchdir(dir.fileno) { :block_value }.should == :block_value
- ensure
- dir.close
- end
+ it "returns the value of the block when a block is given" do
+ dir = Dir.new(DirSpecs.mock_dir)
+ Dir.fchdir(dir.fileno) { :block_value }.should == :block_value
+ ensure
+ dir.close
+ end
- it "changes to the specified directory for the duration of the block" do
- dir = Dir.new(DirSpecs.mock_dir)
- Dir.fchdir(dir.fileno) { Dir.pwd }.should == DirSpecs.mock_dir
- Dir.pwd.should == @original
- ensure
- dir.close
- end
+ it "changes to the specified directory for the duration of the block" do
+ dir = Dir.new(DirSpecs.mock_dir)
+ Dir.fchdir(dir.fileno) { Dir.pwd }.should == DirSpecs.mock_dir
+ Dir.pwd.should == @original
+ ensure
+ dir.close
+ end
- it "raises a SystemCallError if the file descriptor given is not valid" do
- -> { Dir.fchdir(-1) }.should raise_error(SystemCallError, "Bad file descriptor - fchdir")
- -> { Dir.fchdir(-1) { } }.should raise_error(SystemCallError, "Bad file descriptor - fchdir")
- end
+ it "raises a SystemCallError if the file descriptor given is not valid" do
+ -> { Dir.fchdir(-1) }.should.raise(SystemCallError, "Bad file descriptor - fchdir")
+ -> { Dir.fchdir(-1) { } }.should.raise(SystemCallError, "Bad file descriptor - fchdir")
+ end
- it "raises a SystemCallError if the file descriptor given is not for a directory" do
- -> { Dir.fchdir $stdout.fileno }.should raise_error(SystemCallError, /(Not a directory|Invalid argument) - fchdir/)
- -> { Dir.fchdir($stdout.fileno) { } }.should raise_error(SystemCallError, /(Not a directory|Invalid argument) - fchdir/)
- end
+ it "raises a SystemCallError if the file descriptor given is not for a directory" do
+ -> { Dir.fchdir $stdout.fileno }.should.raise(SystemCallError, /(Not a directory|Invalid argument) - fchdir/)
+ -> { Dir.fchdir($stdout.fileno) { } }.should.raise(SystemCallError, /(Not a directory|Invalid argument) - fchdir/)
end
end
+end
- platform_is :windows do
- describe "Dir.fchdir" do
- it "raises NotImplementedError" do
- -> { Dir.fchdir 1 }.should raise_error(NotImplementedError)
- -> { Dir.fchdir(1) { } }.should raise_error(NotImplementedError)
- end
+platform_is :windows do
+ describe "Dir.fchdir" do
+ it "raises NotImplementedError" do
+ -> { Dir.fchdir 1 }.should.raise(NotImplementedError)
+ -> { Dir.fchdir(1) { } }.should.raise(NotImplementedError)
end
end
end
diff --git a/spec/ruby/core/dir/fileno_spec.rb b/spec/ruby/core/dir/fileno_spec.rb
index bb84ef5378..3b563eb18f 100644
--- a/spec/ruby/core/dir/fileno_spec.rb
+++ b/spec/ruby/core/dir/fileno_spec.rb
@@ -27,11 +27,11 @@ describe "Dir#fileno" do
if has_dir_fileno
it "returns the file descriptor of the dir" do
- @dir.fileno.should be_kind_of(Integer)
+ @dir.fileno.should.is_a?(Integer)
end
else
it "raises an error when not implemented on the platform" do
- -> { @dir.fileno }.should raise_error(NotImplementedError)
+ -> { @dir.fileno }.should.raise(NotImplementedError)
end
end
end
diff --git a/spec/ruby/core/dir/fixtures/common.rb b/spec/ruby/core/dir/fixtures/common.rb
index 848656c9b9..cfec91f68f 100644
--- a/spec/ruby/core/dir/fixtures/common.rb
+++ b/spec/ruby/core/dir/fixtures/common.rb
@@ -115,6 +115,7 @@ module DirSpecs
end
def self.create_mock_dirs
+ delete_mock_dirs
mock_dir_files.each do |name|
file = File.join mock_dir, name
mkdir_p File.dirname(file)
@@ -172,24 +173,28 @@ module DirSpecs
end
end
+ def self.expected_paths_with_type
+ [
+ [".", :directory],
+ ["..", :directory],
+ [".dotfile", :file],
+ [".dotsubdir", :directory],
+ ["brace", :directory],
+ ["deeply", :directory],
+ ["dir", :directory],
+ ["dir_filename_ordering", :file],
+ ["file_one.ext", :file],
+ ["file_two.ext", :file],
+ ["nested", :directory],
+ ["nondotfile", :file],
+ ["special", :directory],
+ ["subdir_one", :directory],
+ ["subdir_two", :directory],
+ ]
+ end
+
def self.expected_paths
- %w[
- .
- ..
- .dotfile
- .dotsubdir
- brace
- deeply
- dir
- dir_filename_ordering
- file_one.ext
- file_two.ext
- nested
- nondotfile
- special
- subdir_one
- subdir_two
- ]
+ expected_paths_with_type.map(&:first)
end
def self.expected_glob_paths
diff --git a/spec/ruby/core/dir/for_fd_spec.rb b/spec/ruby/core/dir/for_fd_spec.rb
index ba467f2f86..bbc75e0f8f 100644
--- a/spec/ruby/core/dir/for_fd_spec.rb
+++ b/spec/ruby/core/dir/for_fd_spec.rb
@@ -2,77 +2,75 @@ require_relative '../../spec_helper'
require_relative 'fixtures/common'
quarantine! do # leads to "Errno::EBADF: Bad file descriptor - closedir" in DirSpecs.delete_mock_dirs
-ruby_version_is '3.3' do
- platform_is_not :windows do
- describe "Dir.for_fd" do
- before :all do
- DirSpecs.create_mock_dirs
- end
+platform_is_not :windows do
+ describe "Dir.for_fd" do
+ before :all do
+ DirSpecs.create_mock_dirs
+ end
- after :all do
- DirSpecs.delete_mock_dirs
- end
+ after :all do
+ DirSpecs.delete_mock_dirs
+ end
- before :each do
- @original = Dir.pwd
- end
+ before :each do
+ @original = Dir.pwd
+ end
- after :each do
- Dir.chdir(@original)
- end
+ after :each do
+ Dir.chdir(@original)
+ end
- it "returns a new Dir object representing the directory specified by the given integer directory file descriptor" do
- dir = Dir.new(DirSpecs.mock_dir)
- dir_new = Dir.for_fd(dir.fileno)
+ it "returns a new Dir object representing the directory specified by the given integer directory file descriptor" do
+ dir = Dir.new(DirSpecs.mock_dir)
+ dir_new = Dir.for_fd(dir.fileno)
- dir_new.should.instance_of?(Dir)
- dir_new.children.should == dir.children
- dir_new.fileno.should == dir.fileno
- ensure
- dir.close
- end
+ dir_new.should.instance_of?(Dir)
+ dir_new.children.should == dir.children
+ dir_new.fileno.should == dir.fileno
+ ensure
+ dir.close
+ end
- it "returns a new Dir object without associated path" do
- dir = Dir.new(DirSpecs.mock_dir)
- dir_new = Dir.for_fd(dir.fileno)
+ it "returns a new Dir object without associated path" do
+ dir = Dir.new(DirSpecs.mock_dir)
+ dir_new = Dir.for_fd(dir.fileno)
- dir_new.path.should == nil
- ensure
- dir.close
- end
+ dir_new.path.should == nil
+ ensure
+ dir.close
+ end
- it "calls #to_int to convert a value to an Integer" do
- dir = Dir.new(DirSpecs.mock_dir)
- obj = mock("fd")
- obj.should_receive(:to_int).and_return(dir.fileno)
+ it "calls #to_int to convert a value to an Integer" do
+ dir = Dir.new(DirSpecs.mock_dir)
+ obj = mock("fd")
+ obj.should_receive(:to_int).and_return(dir.fileno)
- dir_new = Dir.for_fd(obj)
- dir_new.fileno.should == dir.fileno
- ensure
- dir.close
- end
+ dir_new = Dir.for_fd(obj)
+ dir_new.fileno.should == dir.fileno
+ ensure
+ dir.close
+ end
- it "raises TypeError when value cannot be converted to Integer" do
- -> {
- Dir.for_fd(nil)
- }.should raise_error(TypeError, "no implicit conversion from nil to integer")
- end
+ it "raises TypeError when value cannot be converted to Integer" do
+ -> {
+ Dir.for_fd(nil)
+ }.should raise_consistent_error(TypeError, "no implicit conversion of nil into Integer")
+ end
- it "raises a SystemCallError if the file descriptor given is not valid" do
- -> { Dir.for_fd(-1) }.should raise_error(SystemCallError, "Bad file descriptor - fdopendir")
- end
+ it "raises a SystemCallError if the file descriptor given is not valid" do
+ -> { Dir.for_fd(-1) }.should.raise(SystemCallError, "Bad file descriptor - fdopendir")
+ end
- it "raises a SystemCallError if the file descriptor given is not for a directory" do
- -> { Dir.for_fd $stdout.fileno }.should raise_error(SystemCallError, "Not a directory - fdopendir")
- end
+ it "raises a SystemCallError if the file descriptor given is not for a directory" do
+ -> { Dir.for_fd $stdout.fileno }.should.raise(SystemCallError, "Not a directory - fdopendir")
end
end
+end
- platform_is :windows do
- describe "Dir.for_fd" do
- it "raises NotImplementedError" do
- -> { Dir.for_fd 1 }.should raise_error(NotImplementedError)
- end
+platform_is :windows do
+ describe "Dir.for_fd" do
+ it "raises NotImplementedError" do
+ -> { Dir.for_fd 1 }.should.raise(NotImplementedError)
end
end
end
diff --git a/spec/ruby/core/dir/foreach_spec.rb b/spec/ruby/core/dir/foreach_spec.rb
index 9cf34b1d71..2a2265a029 100644
--- a/spec/ruby/core/dir/foreach_spec.rb
+++ b/spec/ruby/core/dir/foreach_spec.rb
@@ -31,11 +31,11 @@ describe "Dir.foreach" do
end
it "raises a SystemCallError if passed a nonexistent directory" do
- -> { Dir.foreach(DirSpecs.nonexistent) {} }.should raise_error(SystemCallError)
+ -> { Dir.foreach(DirSpecs.nonexistent) {} }.should.raise(SystemCallError)
end
it "returns an Enumerator if no block given" do
- Dir.foreach(DirSpecs.mock_dir).should be_an_instance_of(Enumerator)
+ Dir.foreach(DirSpecs.mock_dir).should.instance_of?(Enumerator)
Dir.foreach(DirSpecs.mock_dir).to_a.sort.should == DirSpecs.expected_paths
end
@@ -53,7 +53,7 @@ describe "Dir.foreach" do
describe "when no block is given" do
it "returns an Enumerator" do
- Dir.foreach(DirSpecs.mock_dir).should be_an_instance_of(Enumerator)
+ Dir.foreach(DirSpecs.mock_dir).should.instance_of?(Enumerator)
Dir.foreach(DirSpecs.mock_dir).to_a.sort.should == DirSpecs.expected_paths
end
diff --git a/spec/ruby/core/dir/getwd_spec.rb b/spec/ruby/core/dir/getwd_spec.rb
index 132634347c..138481821f 100644
--- a/spec/ruby/core/dir/getwd_spec.rb
+++ b/spec/ruby/core/dir/getwd_spec.rb
@@ -1,15 +1,7 @@
require_relative '../../spec_helper'
-require_relative 'fixtures/common'
-require_relative 'shared/pwd'
describe "Dir.getwd" do
- before :all do
- DirSpecs.create_mock_dirs
+ it "is an alias of Dir.pwd" do
+ Dir.method(:getwd).should == Dir.method(:pwd)
end
-
- after :all do
- DirSpecs.delete_mock_dirs
- end
-
- it_behaves_like :dir_pwd, :getwd
end
diff --git a/spec/ruby/core/dir/glob_spec.rb b/spec/ruby/core/dir/glob_spec.rb
index a60b233bc0..9e81feb15f 100644
--- a/spec/ruby/core/dir/glob_spec.rb
+++ b/spec/ruby/core/dir/glob_spec.rb
@@ -149,7 +149,7 @@ describe "Dir.glob" do
it "accepts a block and yields it with each elements" do
ary = []
ret = Dir.glob(["file_o*", "file_t*"]) { |t| ary << t }
- ret.should be_nil
+ ret.should == nil
ary.should == %w!file_one.ext file_two.ext!
end
diff --git a/spec/ruby/core/dir/home_spec.rb b/spec/ruby/core/dir/home_spec.rb
index 966ac38af3..f0b20e0687 100644
--- a/spec/ruby/core/dir/home_spec.rb
+++ b/spec/ruby/core/dir/home_spec.rb
@@ -74,7 +74,7 @@ describe "Dir.home" do
end
it "raises an ArgumentError if the named user doesn't exist" do
- -> { Dir.home('geuw2n288dh2k') }.should raise_error(ArgumentError)
+ -> { Dir.home('geuw2n288dh2k') }.should.raise(ArgumentError)
end
describe "when called with a nil user name" do
diff --git a/spec/ruby/core/dir/inspect_spec.rb b/spec/ruby/core/dir/inspect_spec.rb
index 37338a97d4..eabaa54ce0 100644
--- a/spec/ruby/core/dir/inspect_spec.rb
+++ b/spec/ruby/core/dir/inspect_spec.rb
@@ -11,7 +11,7 @@ describe "Dir#inspect" do
end
it "returns a String" do
- @dir.inspect.should be_an_instance_of(String)
+ @dir.inspect.should.instance_of?(String)
end
it "includes the class name" do
@@ -19,6 +19,6 @@ describe "Dir#inspect" do
end
it "includes the directory name" do
- @dir.inspect.should include(Dir.getwd)
+ @dir.inspect.should.include?(Dir.getwd)
end
end
diff --git a/spec/ruby/core/dir/mkdir_spec.rb b/spec/ruby/core/dir/mkdir_spec.rb
index 076ec19dd9..37513e417a 100644
--- a/spec/ruby/core/dir/mkdir_spec.rb
+++ b/spec/ruby/core/dir/mkdir_spec.rb
@@ -67,19 +67,19 @@ describe "Dir.mkdir" do
path = DirSpecs.mock_dir('nonexisting')
permissions = Object.new
- -> { Dir.mkdir(path, permissions) }.should raise_error(TypeError, 'no implicit conversion of Object into Integer')
+ -> { Dir.mkdir(path, permissions) }.should.raise(TypeError, 'no implicit conversion of Object into Integer')
end
it "raises a SystemCallError if any of the directories in the path before the last does not exist" do
- -> { Dir.mkdir "#{DirSpecs.nonexistent}/subdir" }.should raise_error(SystemCallError)
+ -> { Dir.mkdir "#{DirSpecs.nonexistent}/subdir" }.should.raise(SystemCallError)
end
it "raises Errno::EEXIST if the specified directory already exists" do
- -> { Dir.mkdir("#{DirSpecs.mock_dir}/dir") }.should raise_error(Errno::EEXIST)
+ -> { Dir.mkdir("#{DirSpecs.mock_dir}/dir") }.should.raise(Errno::EEXIST)
end
it "raises Errno::EEXIST if the argument points to the existing file" do
- -> { Dir.mkdir("#{DirSpecs.mock_dir}/file_one.ext") }.should raise_error(Errno::EEXIST)
+ -> { Dir.mkdir("#{DirSpecs.mock_dir}/file_one.ext") }.should.raise(Errno::EEXIST)
end
end
@@ -100,7 +100,7 @@ platform_is_not :windows do
it "raises a SystemCallError when lacking adequate permissions in the parent dir" do
Dir.mkdir @dir, 0000
- -> { Dir.mkdir "#{@dir}/subdir" }.should raise_error(SystemCallError)
+ -> { Dir.mkdir "#{@dir}/subdir" }.should.raise(SystemCallError)
end
end
end
diff --git a/spec/ruby/core/dir/open_spec.rb b/spec/ruby/core/dir/open_spec.rb
index 27f362320b..be01638fbc 100644
--- a/spec/ruby/core/dir/open_spec.rb
+++ b/spec/ruby/core/dir/open_spec.rb
@@ -1,6 +1,5 @@
require_relative '../../spec_helper'
require_relative 'fixtures/common'
-require_relative 'shared/open'
describe "Dir.open" do
before :all do
@@ -11,5 +10,75 @@ describe "Dir.open" do
DirSpecs.delete_mock_dirs
end
- it_behaves_like :dir_open, :open
+ it "returns a Dir instance representing the specified directory" do
+ dir = Dir.open(DirSpecs.mock_dir)
+ dir.should.is_a?(Dir)
+ dir.close
+ end
+
+ it "raises a SystemCallError if the directory does not exist" do
+ -> do
+ Dir.open(DirSpecs.nonexistent)
+ end.should.raise(SystemCallError)
+ end
+
+ it "may take a block which is yielded to with the Dir instance" do
+ Dir.open(DirSpecs.mock_dir) {|dir| dir.should.is_a?(Dir)}
+ end
+
+ it "returns the value of the block if a block is given" do
+ Dir.open(DirSpecs.mock_dir) {|dir| :value }.should == :value
+ end
+
+ it "closes the Dir instance when the block exits if given a block" do
+ closed_dir = Dir.open(DirSpecs.mock_dir) { |dir| dir }
+ -> { closed_dir.read }.should.raise(IOError)
+ end
+
+ it "closes the Dir instance when the block exits the block even due to an exception" do
+ closed_dir = nil
+
+ -> do
+ Dir.open(DirSpecs.mock_dir) do |dir|
+ closed_dir = dir
+ raise "dir specs"
+ end
+ end.should.raise(RuntimeError, "dir specs")
+
+ -> { closed_dir.read }.should.raise(IOError)
+ end
+
+ it "calls #to_path on non-String arguments" do
+ p = mock('path')
+ p.should_receive(:to_path).and_return(DirSpecs.mock_dir)
+ Dir.open(p) { true }
+ end
+
+ it "accepts an options Hash" do
+ dir = Dir.open(DirSpecs.mock_dir, encoding: "utf-8") {|d| d }
+ dir.should.is_a?(Dir)
+ end
+
+ it "calls #to_hash to convert the options object" do
+ options = mock("dir_open")
+ options.should_receive(:to_hash).and_return({ encoding: Encoding::UTF_8 })
+
+ dir = Dir.open(DirSpecs.mock_dir, **options) {|d| d }
+ dir.should.is_a?(Dir)
+ end
+
+ it "ignores the :encoding option if it is nil" do
+ dir = Dir.open(DirSpecs.mock_dir, encoding: nil) {|d| d }
+ dir.should.is_a?(Dir)
+ end
+
+ platform_is_not :windows do
+ it 'sets the close-on-exec flag for the directory file descriptor' do
+ Dir.open(DirSpecs.mock_dir) do |dir|
+ io = IO.for_fd(dir.fileno)
+ io.autoclose = false
+ io.should.close_on_exec?
+ end
+ end
+ end
end
diff --git a/spec/ruby/core/dir/path_spec.rb b/spec/ruby/core/dir/path_spec.rb
index b1c24c406b..e506db1222 100644
--- a/spec/ruby/core/dir/path_spec.rb
+++ b/spec/ruby/core/dir/path_spec.rb
@@ -1,15 +1,7 @@
require_relative '../../spec_helper'
-require_relative 'fixtures/common'
-require_relative 'shared/path'
describe "Dir#path" do
- before :all do
- DirSpecs.create_mock_dirs
+ it "is an alias of Dir#to_path" do
+ Dir.instance_method(:path).should == Dir.instance_method(:to_path)
end
-
- after :all do
- DirSpecs.delete_mock_dirs
- end
-
- it_behaves_like :dir_path, :path
end
diff --git a/spec/ruby/core/dir/pos_spec.rb b/spec/ruby/core/dir/pos_spec.rb
index b382bff81f..1e364fbe3c 100644
--- a/spec/ruby/core/dir/pos_spec.rb
+++ b/spec/ruby/core/dir/pos_spec.rb
@@ -12,19 +12,32 @@ describe "Dir#pos" do
DirSpecs.delete_mock_dirs
end
- it_behaves_like :dir_pos, :pos
-end
+ it_behaves_like :dir_closed, :pos
-describe "Dir#pos" do
- before :all do
- DirSpecs.create_mock_dirs
+ before :each do
+ @dir = Dir.open DirSpecs.mock_dir
end
- after :all do
- DirSpecs.delete_mock_dirs
+ after :each do
+ @dir.close rescue nil
end
- it_behaves_like :dir_closed, :pos
+ it "returns an Integer representing the current position in the directory" do
+ @dir.pos.should.is_a?(Integer)
+ @dir.pos.should.is_a?(Integer)
+ @dir.pos.should.is_a?(Integer)
+ end
+
+ it "returns a different Integer if moved from previous position" do
+ a = @dir.pos
+ @dir.read
+ b = @dir.pos
+
+ a.should.is_a?(Integer)
+ b.should.is_a?(Integer)
+
+ a.should_not == b
+ end
end
describe "Dir#pos=" do
diff --git a/spec/ruby/core/dir/pwd_spec.rb b/spec/ruby/core/dir/pwd_spec.rb
index ad01286c90..70208b03d6 100644
--- a/spec/ruby/core/dir/pwd_spec.rb
+++ b/spec/ruby/core/dir/pwd_spec.rb
@@ -1,7 +1,6 @@
# -*- encoding: utf-8 -*-
require_relative '../../spec_helper'
require_relative 'fixtures/common'
-require_relative 'shared/pwd'
describe "Dir.pwd" do
before :all do
@@ -12,7 +11,49 @@ describe "Dir.pwd" do
DirSpecs.delete_mock_dirs
end
- it_behaves_like :dir_pwd, :pwd
+ before :each do
+ @fs_encoding = Encoding.find('filesystem')
+ end
+
+ it "returns the current working directory" do
+ pwd = Dir.pwd
+
+ File.directory?(pwd).should == true
+
+ # On ubuntu gutsy, for example, /bin/pwd does not
+ # understand -P. With just `pwd -P`, /bin/pwd is run.
+
+ # The following uses inode rather than file names to account for
+ # case insensitive file systems like default OS/X file systems
+ platform_is_not :windows do
+ File.stat(pwd).ino.should == File.stat(`/bin/sh -c "pwd -P"`.chomp).ino
+ end
+ platform_is :windows do
+ File.stat(pwd).ino.should == File.stat(File.expand_path(`cd`.chomp)).ino
+ end
+ end
+
+ it "returns an absolute path" do
+ pwd = Dir.pwd
+ pwd.should == File.expand_path(pwd)
+ end
+
+ it "returns an absolute path even when chdir to a relative path" do
+ Dir.chdir(".") do
+ pwd = Dir.pwd
+ File.directory?(pwd).should == true
+ pwd.should == File.expand_path(pwd)
+ end
+ end
+
+ it "returns a String with the filesystem encoding" do
+ enc = Dir.pwd.encoding
+ if @fs_encoding == Encoding::US_ASCII
+ [Encoding::US_ASCII, Encoding::BINARY].should.include?(enc)
+ else
+ enc.should.equal?(@fs_encoding)
+ end
+ end
end
describe "Dir.pwd" do
diff --git a/spec/ruby/core/dir/read_spec.rb b/spec/ruby/core/dir/read_spec.rb
index 276930c6b7..3f842457f4 100644
--- a/spec/ruby/core/dir/read_spec.rb
+++ b/spec/ruby/core/dir/read_spec.rb
@@ -15,7 +15,7 @@ describe "Dir#read" do
# an FS does not necessarily impose order
ls = Dir.entries DirSpecs.mock_dir
dir = Dir.open DirSpecs.mock_dir
- ls.should include(dir.read)
+ ls.should.include?(dir.read)
dir.close
end
@@ -61,7 +61,7 @@ describe "Dir#read" do
while entry = d.read
shift_jis_entries << entry
end
- }.should_not raise_error
+ }.should_not.raise
end
ensure
Encoding.default_internal = old_internal_encoding
diff --git a/spec/ruby/core/dir/rmdir_spec.rb b/spec/ruby/core/dir/rmdir_spec.rb
index 08cd1a5bc6..c31067ca29 100644
--- a/spec/ruby/core/dir/rmdir_spec.rb
+++ b/spec/ruby/core/dir/rmdir_spec.rb
@@ -1,15 +1,7 @@
require_relative '../../spec_helper'
-require_relative 'fixtures/common'
-require_relative 'shared/delete'
describe "Dir.rmdir" do
- before :all do
- DirSpecs.create_mock_dirs
+ it "is an alias of Dir.delete" do
+ Dir.method(:rmdir).should == Dir.method(:delete)
end
-
- after :all do
- DirSpecs.delete_mock_dirs
- end
-
- it_behaves_like :dir_delete, :rmdir
end
diff --git a/spec/ruby/core/dir/scan_spec.rb b/spec/ruby/core/dir/scan_spec.rb
new file mode 100644
index 0000000000..3aa071337b
--- /dev/null
+++ b/spec/ruby/core/dir/scan_spec.rb
@@ -0,0 +1,224 @@
+# encoding: utf-8
+
+require_relative '../../spec_helper'
+require_relative 'fixtures/common'
+require_relative '../file/fixtures/file_types'
+
+ruby_version_is "4.1" do
+ describe "Dir.scan" do
+ before :all do
+ FileSpecs.configure_types
+ end
+
+ before :all do
+ DirSpecs.create_mock_dirs
+ end
+
+ after :all do
+ DirSpecs.delete_mock_dirs
+ end
+
+ before :each do
+ @internal = Encoding.default_internal
+ end
+
+ after :each do
+ Encoding.default_internal = @internal
+ end
+
+ it "returns an Array of filename and type pairs in an existing directory including dotfiles" do
+ a = Dir.scan(DirSpecs.mock_dir).sort
+
+ a.should == DirSpecs.expected_paths_with_type - [[".", :directory], ["..", :directory]]
+
+ a = Dir.scan("#{DirSpecs.mock_dir}/deeply/nested").sort
+ a.should == [[".dotfile.ext", :file], ["directory", :directory]]
+ end
+
+ it "yields filename and type in an existing directory including dotfiles" do
+ a = []
+ Dir.scan(DirSpecs.mock_dir) do |n, t|
+ a << [n, t]
+ end
+ a.sort!
+ a.should == DirSpecs.expected_paths_with_type - [[".", :directory], ["..", :directory]]
+
+ a = []
+ Dir.scan("#{DirSpecs.mock_dir}/deeply/nested") do |n, t|
+ a << [n, t]
+ end
+ a.sort!
+ a.should == [[".dotfile.ext", :file], ["directory", :directory]]
+ end
+
+ it "calls #to_path on non-String arguments" do
+ p = mock('path')
+ p.should_receive(:to_path).and_return(DirSpecs.mock_dir)
+ Dir.scan(p)
+ end
+
+ it "accepts an options Hash" do
+ a = Dir.scan("#{DirSpecs.mock_dir}/deeply/nested", encoding: "utf-8").sort
+ a.should == [[".dotfile.ext", :file], ["directory", :directory]]
+ end
+
+ it "returns children names encoded with the filesystem encoding by default" do
+ # This spec depends on the locale not being US-ASCII because if it is, the
+ # children that are not ascii_only? will be BINARY encoded.
+ children = Dir.scan(File.join(DirSpecs.mock_dir, 'special')).sort
+ 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), :file])
+ end
+ children.first.first.encoding.should.equal?(Encoding.find("filesystem"))
+ end
+
+ it "returns children names encoded with the specified encoding" do
+ dir = File.join(DirSpecs.mock_dir, 'special')
+ children = Dir.scan(dir, encoding: "euc-jp").sort
+ children.first.first.encoding.should.equal?(Encoding::EUC_JP)
+ end
+
+ it "returns children names transcoded to the default internal encoding" do
+ Encoding.default_internal = Encoding::EUC_KR
+ children = Dir.scan(File.join(DirSpecs.mock_dir, 'special')).sort
+ children.first.first.encoding.should.equal?(Encoding::EUC_KR)
+ end
+
+ it "raises a SystemCallError if called with a nonexistent directory" do
+ -> { Dir.scan DirSpecs.nonexistent }.should.raise(SystemCallError)
+ end
+
+ it "handles symlink" do
+ FileSpecs.symlink do |path|
+ Dir.scan(File.dirname(path)).map(&:last).should.include?(:link)
+ end
+ end
+
+ platform_is_not :windows do
+ it "handles socket" do
+ FileSpecs.socket do |path|
+ Dir.scan(File.dirname(path)).map(&:last).should.include?(:socket)
+ end
+ end
+
+ it "handles FIFO" do
+ FileSpecs.fifo do |path|
+ Dir.scan(File.dirname(path)).map(&:last).should.include?(:fifo)
+ end
+ end
+
+ it "handles character devices" do
+ FileSpecs.character_device do |path|
+ Dir.scan(File.dirname(path)).map(&:last).should.include?(:characterSpecial)
+ end
+ end
+ end
+
+ platform_is_not :freebsd, :windows do
+ with_block_device do
+ it "handles block devices" do
+ FileSpecs.block_device do |path|
+ Dir.scan(File.dirname(path)).map(&:last).should.include?(:blockSpecial)
+ end
+ end
+ end
+ end
+ end
+
+ describe "Dir#scan" do
+ before :all do
+ DirSpecs.create_mock_dirs
+ end
+
+ after :all do
+ DirSpecs.delete_mock_dirs
+ end
+
+ before :each do
+ @internal = Encoding.default_internal
+ end
+
+ after :each do
+ Encoding.default_internal = @internal
+ @dir.close if @dir
+ end
+
+ it "returns an Array of filenames in an existing directory including dotfiles" do
+ @dir = Dir.new(DirSpecs.mock_dir)
+ a = @dir.scan.sort
+ @dir.close
+
+ a.should == DirSpecs.expected_paths_with_type - [[".", :directory], ["..", :directory]]
+
+ @dir = Dir.new("#{DirSpecs.mock_dir}/deeply/nested")
+ a = @dir.scan.sort
+ a.should == [[".dotfile.ext", :file], ["directory", :directory]]
+ end
+
+ it "yields filename and type in an existing directory including dotfiles" do
+ @dir = Dir.new(DirSpecs.mock_dir)
+ a = []
+ @dir.scan do |n, t|
+ a << [n, t]
+ end
+ a.sort!
+ a.should == DirSpecs.expected_paths_with_type - [[".", :directory], ["..", :directory]]
+
+ @dir = Dir.new("#{DirSpecs.mock_dir}/deeply/nested")
+ a = []
+ @dir.scan do |n, t|
+ a << [n, t]
+ end
+ a.sort!
+ a.should == [[".dotfile.ext", :file], ["directory", :directory]]
+ end
+
+ it "accepts an encoding keyword for the encoding of the entries" do
+ @dir = Dir.new("#{DirSpecs.mock_dir}/deeply/nested", encoding: "utf-8")
+ dirs = @dir.to_a.sort
+ dirs.each { |d| d.encoding.should == Encoding::UTF_8 }
+ end
+
+ it "returns children names encoded with the filesystem encoding by default" do
+ # This spec depends on the locale not being US-ASCII because if it is, the
+ # children that are not ascii_only? will be BINARY encoded.
+ @dir = Dir.new(File.join(DirSpecs.mock_dir, 'special'))
+ children = @dir.scan.sort
+ 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), :file])
+ end
+ children.first.first.encoding.should.equal?(Encoding.find("filesystem"))
+ end
+
+ it "returns children names encoded with the specified encoding" do
+ path = File.join(DirSpecs.mock_dir, 'special')
+ @dir = Dir.new(path, encoding: "euc-jp")
+ children = @dir.children.sort
+ children.first.encoding.should.equal?(Encoding::EUC_JP)
+ end
+
+ it "returns children names transcoded to the default internal encoding" do
+ Encoding.default_internal = Encoding::EUC_KR
+ @dir = Dir.new(File.join(DirSpecs.mock_dir, 'special'))
+ children = @dir.scan.sort
+ children.first.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
+end
diff --git a/spec/ruby/core/dir/shared/chroot.rb b/spec/ruby/core/dir/shared/chroot.rb
index a8f7c10a19..e4e6103799 100644
--- a/spec/ruby/core/dir/shared/chroot.rb
+++ b/spec/ruby/core/dir/shared/chroot.rb
@@ -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, __dir__) }.should_not.raise
File.should.exist?("/#{File.basename(__FILE__)}")
end unless compilations_ci
@@ -27,7 +27,7 @@ describe :dir_chroot_as_root, shared: true do
end
it "raises an Errno::ENOENT exception if the directory doesn't exist" do
- -> { Dir.send(@method, 'xgwhwhsjai2222jg') }.should raise_error(Errno::ENOENT)
+ -> { Dir.send(@method, 'xgwhwhsjai2222jg') }.should.raise(Errno::ENOENT)
end
it "can be escaped from with ../" do
diff --git a/spec/ruby/core/dir/shared/closed.rb b/spec/ruby/core/dir/shared/closed.rb
index 17d8332c2a..c868fd6e6d 100644
--- a/spec/ruby/core/dir/shared/closed.rb
+++ b/spec/ruby/core/dir/shared/closed.rb
@@ -4,6 +4,6 @@ describe :dir_closed, shared: true do
dir = Dir.open DirSpecs.mock_dir
dir.close
dir.send(@method) {}
- }.should raise_error(IOError)
+ }.should.raise(IOError)
end
end
diff --git a/spec/ruby/core/dir/shared/delete.rb b/spec/ruby/core/dir/shared/delete.rb
deleted file mode 100644
index a81b059759..0000000000
--- a/spec/ruby/core/dir/shared/delete.rb
+++ /dev/null
@@ -1,53 +0,0 @@
-describe :dir_delete, shared: true do
- before :each do
- DirSpecs.rmdir_dirs true
- end
-
- after :each do
- DirSpecs.rmdir_dirs false
- end
-
- it "removes empty directories" do
- Dir.send(@method, DirSpecs.mock_rmdir("empty")).should == 0
- end
-
- it "calls #to_path on non-String arguments" do
- p = mock('path')
- p.should_receive(:to_path).and_return(DirSpecs.mock_rmdir("empty"))
- Dir.send(@method, p)
- end
-
- it "raises an Errno::ENOTEMPTY when trying to remove a nonempty directory" do
- -> do
- Dir.send @method, DirSpecs.mock_rmdir("nonempty")
- end.should raise_error(Errno::ENOTEMPTY)
- end
-
- it "raises an Errno::ENOENT when trying to remove a non-existing directory" do
- -> do
- Dir.send @method, DirSpecs.nonexistent
- end.should raise_error(Errno::ENOENT)
- end
-
- it "raises an Errno::ENOTDIR when trying to remove a non-directory" do
- file = DirSpecs.mock_rmdir("nonempty/regular")
- touch(file)
- -> do
- Dir.send @method, file
- end.should raise_error(Errno::ENOTDIR)
- end
-
- # this won't work on Windows, since chmod(0000) does not remove all permissions
- platform_is_not :windows do
- as_user do
- it "raises an Errno::EACCES if lacking adequate permissions to remove the directory" do
- parent = DirSpecs.mock_rmdir("noperm")
- child = DirSpecs.mock_rmdir("noperm", "child")
- File.chmod(0000, parent)
- -> do
- Dir.send @method, child
- end.should raise_error(Errno::EACCES)
- end
- end
- end
-end
diff --git a/spec/ruby/core/dir/shared/exist.rb b/spec/ruby/core/dir/shared/exist.rb
deleted file mode 100644
index 3097f57715..0000000000
--- a/spec/ruby/core/dir/shared/exist.rb
+++ /dev/null
@@ -1,57 +0,0 @@
-describe :dir_exist, shared: true do
- it "returns true if the given directory exists" do
- Dir.send(@method, __dir__).should be_true
- end
-
- it "returns true for '.'" do
- Dir.send(@method, '.').should be_true
- end
-
- it "returns true for '..'" do
- Dir.send(@method, '..').should be_true
- end
-
- it "understands non-ASCII paths" do
- subdir = File.join(tmp("\u{9876}\u{665}"))
- Dir.send(@method, subdir).should be_false
- Dir.mkdir(subdir)
- Dir.send(@method, subdir).should be_true
- Dir.rmdir(subdir)
- end
-
- it "understands relative paths" do
- Dir.send(@method, __dir__ + '/../').should be_true
- end
-
- it "returns false if the given directory doesn't exist" do
- Dir.send(@method, 'y26dg27n2nwjs8a/').should be_false
- end
-
- it "doesn't require the name to have a trailing slash" do
- dir = __dir__
- 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
-
- it "returns false if the argument exists but is a file" do
- File.should.exist?(__FILE__)
- Dir.send(@method, __FILE__).should be_false
- end
-
- it "doesn't set $! when file doesn't exist" do
- Dir.send(@method, "/path/to/non/existent/dir")
- $!.should be_nil
- end
-
- it "calls #to_path on non String arguments" do
- p = mock('path')
- p.should_receive(:to_path).and_return(__dir__)
- 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 b1fc924f08..86aa105259 100644
--- a/spec/ruby/core/dir/shared/glob.rb
+++ b/spec/ruby/core/dir/shared/glob.rb
@@ -13,7 +13,7 @@ describe :dir_glob, shared: true do
it "raises an Encoding::CompatibilityError if the argument encoding is not compatible with US-ASCII" do
pattern = "files*".dup.force_encoding Encoding::UTF_16BE
- -> { Dir.send(@method, pattern) }.should raise_error(Encoding::CompatibilityError)
+ -> { Dir.send(@method, pattern) }.should.raise(Encoding::CompatibilityError)
end
it "calls #to_path to convert a pattern" do
@@ -24,7 +24,7 @@ describe :dir_glob, shared: true do
end
it "raises an ArgumentError if the string contains \\0" do
- -> {Dir.send(@method, "file_o*\0file_t*")}.should raise_error ArgumentError, /nul-separated/
+ -> {Dir.send(@method, "file_o*\0file_t*")}.should.raise ArgumentError, /nul-separated/
end
it "result is sorted by default" do
@@ -43,9 +43,9 @@ describe :dir_glob, shared: true do
end
it "raises an ArgumentError if sort: is not true or false" do
- -> { Dir.send(@method, '*', sort: 0) }.should raise_error ArgumentError, /expected true or false/
- -> { Dir.send(@method, '*', sort: nil) }.should raise_error ArgumentError, /expected true or false/
- -> { Dir.send(@method, '*', sort: 'false') }.should raise_error ArgumentError, /expected true or false/
+ -> { Dir.send(@method, '*', sort: 0) }.should.raise ArgumentError, /expected true or false/
+ -> { Dir.send(@method, '*', sort: nil) }.should.raise ArgumentError, /expected true or false/
+ -> { Dir.send(@method, '*', sort: 'false') }.should.raise ArgumentError, /expected true or false/
end
it "matches non-dotfiles with '*'" do
@@ -373,7 +373,7 @@ describe :dir_glob, shared: true do
it "raises TypeError when cannot convert value to string" do
-> {
Dir.send(@method, "*", base: [])
- }.should raise_error(TypeError)
+ }.should.raise(TypeError)
end
it "handles '' as current directory path" do
diff --git a/spec/ruby/core/dir/shared/open.rb b/spec/ruby/core/dir/shared/open.rb
deleted file mode 100644
index 920845cba1..0000000000
--- a/spec/ruby/core/dir/shared/open.rb
+++ /dev/null
@@ -1,73 +0,0 @@
-describe :dir_open, shared: true do
- it "returns a Dir instance representing the specified directory" do
- dir = Dir.send(@method, DirSpecs.mock_dir)
- dir.should be_kind_of(Dir)
- dir.close
- end
-
- it "raises a SystemCallError if the directory does not exist" do
- -> do
- Dir.send @method, DirSpecs.nonexistent
- end.should raise_error(SystemCallError)
- end
-
- it "may take a block which is yielded to with the Dir instance" do
- Dir.send(@method, DirSpecs.mock_dir) {|dir| dir.should be_kind_of(Dir)}
- end
-
- it "returns the value of the block if a block is given" do
- Dir.send(@method, DirSpecs.mock_dir) {|dir| :value }.should == :value
- end
-
- it "closes the Dir instance when the block exits if given a block" do
- closed_dir = Dir.send(@method, DirSpecs.mock_dir) { |dir| dir }
- -> { closed_dir.read }.should raise_error(IOError)
- end
-
- it "closes the Dir instance when the block exits the block even due to an exception" do
- closed_dir = nil
-
- -> do
- Dir.send(@method, DirSpecs.mock_dir) do |dir|
- closed_dir = dir
- raise "dir specs"
- end
- end.should raise_error(RuntimeError, "dir specs")
-
- -> { closed_dir.read }.should raise_error(IOError)
- end
-
- it "calls #to_path on non-String arguments" do
- p = mock('path')
- p.should_receive(:to_path).and_return(DirSpecs.mock_dir)
- Dir.send(@method, p) { true }
- end
-
- it "accepts an options Hash" do
- dir = Dir.send(@method, DirSpecs.mock_dir, encoding: "utf-8") {|d| d }
- dir.should be_kind_of(Dir)
- end
-
- it "calls #to_hash to convert the options object" do
- options = mock("dir_open")
- options.should_receive(:to_hash).and_return({ encoding: Encoding::UTF_8 })
-
- dir = Dir.send(@method, DirSpecs.mock_dir, **options) {|d| d }
- dir.should be_kind_of(Dir)
- end
-
- it "ignores the :encoding option if it is nil" do
- dir = Dir.send(@method, DirSpecs.mock_dir, encoding: nil) {|d| d }
- dir.should be_kind_of(Dir)
- end
-
- platform_is_not :windows do
- it 'sets the close-on-exec flag for the directory file descriptor' do
- Dir.send(@method, DirSpecs.mock_dir) do |dir|
- io = IO.for_fd(dir.fileno)
- io.autoclose = false
- io.should.close_on_exec?
- end
- end
- end
-end
diff --git a/spec/ruby/core/dir/shared/path.rb b/spec/ruby/core/dir/shared/path.rb
deleted file mode 100644
index 494dcca775..0000000000
--- a/spec/ruby/core/dir/shared/path.rb
+++ /dev/null
@@ -1,30 +0,0 @@
-require_relative '../../../spec_helper'
-require_relative '../fixtures/common'
-require_relative 'closed'
-
-describe :dir_path, shared: true do
- it "returns the path that was supplied to .new or .open" do
- dir = Dir.open DirSpecs.mock_dir
- begin
- dir.send(@method).should == DirSpecs.mock_dir
- ensure
- dir.close rescue nil
- end
- end
-
- it "returns the path even when called on a closed Dir instance" do
- dir = Dir.open DirSpecs.mock_dir
- dir.close
- dir.send(@method).should == DirSpecs.mock_dir
- end
-
- it "returns a String with the same encoding as the argument to .open" do
- path = DirSpecs.mock_dir.force_encoding Encoding::IBM866
- dir = Dir.open path
- begin
- dir.send(@method).encoding.should equal(Encoding::IBM866)
- ensure
- dir.close
- end
- end
-end
diff --git a/spec/ruby/core/dir/shared/pos.rb b/spec/ruby/core/dir/shared/pos.rb
index 2165932d99..741de8918c 100644
--- a/spec/ruby/core/dir/shared/pos.rb
+++ b/spec/ruby/core/dir/shared/pos.rb
@@ -1,30 +1,3 @@
-describe :dir_pos, shared: true do
- before :each do
- @dir = Dir.open DirSpecs.mock_dir
- end
-
- after :each do
- @dir.close rescue nil
- end
-
- it "returns an Integer representing the current position in the directory" do
- @dir.send(@method).should be_kind_of(Integer)
- @dir.send(@method).should be_kind_of(Integer)
- @dir.send(@method).should be_kind_of(Integer)
- end
-
- it "returns a different Integer if moved from previous position" do
- a = @dir.send(@method)
- @dir.read
- b = @dir.send(@method)
-
- a.should be_kind_of(Integer)
- b.should be_kind_of(Integer)
-
- a.should_not == b
- end
-end
-
describe :dir_pos_set, shared: true do
before :each do
@dir = Dir.open DirSpecs.mock_dir
diff --git a/spec/ruby/core/dir/shared/pwd.rb b/spec/ruby/core/dir/shared/pwd.rb
deleted file mode 100644
index 2a8d7fe790..0000000000
--- a/spec/ruby/core/dir/shared/pwd.rb
+++ /dev/null
@@ -1,45 +0,0 @@
-describe :dir_pwd, shared: true do
- before :each do
- @fs_encoding = Encoding.find('filesystem')
- end
-
- it "returns the current working directory" do
- pwd = Dir.send(@method)
-
- File.directory?(pwd).should == true
-
- # On ubuntu gutsy, for example, /bin/pwd does not
- # understand -P. With just `pwd -P`, /bin/pwd is run.
-
- # The following uses inode rather than file names to account for
- # case insensitive file systems like default OS/X file systems
- platform_is_not :windows do
- File.stat(pwd).ino.should == File.stat(`/bin/sh -c "pwd -P"`.chomp).ino
- end
- platform_is :windows do
- File.stat(pwd).ino.should == File.stat(File.expand_path(`cd`.chomp)).ino
- end
- end
-
- it "returns an absolute path" do
- pwd = Dir.send(@method)
- pwd.should == File.expand_path(pwd)
- end
-
- it "returns an absolute path even when chdir to a relative path" do
- Dir.chdir(".") do
- pwd = Dir.send(@method)
- File.directory?(pwd).should == true
- pwd.should == File.expand_path(pwd)
- end
- end
-
- it "returns a String with the filesystem encoding" do
- enc = Dir.send(@method).encoding
- if @fs_encoding == Encoding::US_ASCII
- [Encoding::US_ASCII, Encoding::BINARY].should include(enc)
- else
- enc.should equal(@fs_encoding)
- end
- end
-end
diff --git a/spec/ruby/core/dir/tell_spec.rb b/spec/ruby/core/dir/tell_spec.rb
index af86dc1598..04f92a8ade 100644
--- a/spec/ruby/core/dir/tell_spec.rb
+++ b/spec/ruby/core/dir/tell_spec.rb
@@ -1,18 +1,9 @@
require_relative '../../spec_helper'
require_relative 'fixtures/common'
-require_relative 'shared/closed'
require_relative 'shared/pos'
describe "Dir#tell" do
- before :all do
- DirSpecs.create_mock_dirs
+ it "is an alias of Dir#pos" do
+ Dir.instance_method(:tell).should == Dir.instance_method(:pos)
end
-
- after :all do
- DirSpecs.delete_mock_dirs
- end
-
- it_behaves_like :dir_pos, :tell
-
- it_behaves_like :dir_closed, :tell
end
diff --git a/spec/ruby/core/dir/to_path_spec.rb b/spec/ruby/core/dir/to_path_spec.rb
index 77404a3dc8..43e349c50e 100644
--- a/spec/ruby/core/dir/to_path_spec.rb
+++ b/spec/ruby/core/dir/to_path_spec.rb
@@ -1,6 +1,5 @@
require_relative '../../spec_helper'
require_relative 'fixtures/common'
-require_relative 'shared/path'
describe "Dir#to_path" do
before :all do
@@ -11,5 +10,28 @@ describe "Dir#to_path" do
DirSpecs.delete_mock_dirs
end
- it_behaves_like :dir_path, :to_path
+ it "returns the to_path that was supplied to .new or .open" do
+ dir = Dir.open DirSpecs.mock_dir
+ begin
+ dir.to_path.should == DirSpecs.mock_dir
+ ensure
+ dir.close rescue nil
+ end
+ end
+
+ it "returns the to_path even when called on a closed Dir instance" do
+ dir = Dir.open DirSpecs.mock_dir
+ dir.close
+ dir.to_path.should == DirSpecs.mock_dir
+ end
+
+ it "returns a String with the same encoding as the argument to .open" do
+ to_path = DirSpecs.mock_dir.force_encoding Encoding::IBM866
+ dir = Dir.open to_path
+ begin
+ dir.to_path.encoding.should.equal?(Encoding::IBM866)
+ ensure
+ dir.close
+ end
+ end
end
diff --git a/spec/ruby/core/dir/unlink_spec.rb b/spec/ruby/core/dir/unlink_spec.rb
index 79027e020c..d9cd1b1a87 100644
--- a/spec/ruby/core/dir/unlink_spec.rb
+++ b/spec/ruby/core/dir/unlink_spec.rb
@@ -1,15 +1,7 @@
require_relative '../../spec_helper'
-require_relative 'fixtures/common'
-require_relative 'shared/delete'
describe "Dir.unlink" do
- before :all do
- DirSpecs.create_mock_dirs
+ it "is an alias of Dir.delete" do
+ Dir.method(:unlink).should == Dir.method(:delete)
end
-
- after :all do
- DirSpecs.delete_mock_dirs
- end
-
- it_behaves_like :dir_delete, :unlink
end
diff --git a/spec/ruby/core/encoding/aliases_spec.rb b/spec/ruby/core/encoding/aliases_spec.rb
index 786157981a..12c6c6cf85 100644
--- a/spec/ruby/core/encoding/aliases_spec.rb
+++ b/spec/ruby/core/encoding/aliases_spec.rb
@@ -2,24 +2,24 @@ require_relative '../../spec_helper'
describe "Encoding.aliases" do
it "returns a Hash" do
- Encoding.aliases.should be_an_instance_of(Hash)
+ Encoding.aliases.should.instance_of?(Hash)
end
it "has Strings as keys" do
Encoding.aliases.keys.each do |key|
- key.should be_an_instance_of(String)
+ key.should.instance_of?(String)
end
end
it "has Strings as values" do
Encoding.aliases.values.each do |value|
- value.should be_an_instance_of(String)
+ value.should.instance_of?(String)
end
end
it "has alias names as its keys" do
- Encoding.aliases.key?('BINARY').should be_true
- Encoding.aliases.key?('ASCII').should be_true
+ Encoding.aliases.key?('BINARY').should == true
+ Encoding.aliases.key?('ASCII').should == true
end
it "has the names of the aliased encoding as its values" do
diff --git a/spec/ruby/core/encoding/ascii_compatible_spec.rb b/spec/ruby/core/encoding/ascii_compatible_spec.rb
index 4804300e85..04fc159bb8 100644
--- a/spec/ruby/core/encoding/ascii_compatible_spec.rb
+++ b/spec/ruby/core/encoding/ascii_compatible_spec.rb
@@ -2,10 +2,21 @@ require_relative '../../spec_helper'
describe "Encoding#ascii_compatible?" do
it "returns true if self represents an ASCII-compatible encoding" do
- Encoding::UTF_8.ascii_compatible?.should be_true
+ Encoding::UTF_8.ascii_compatible?.should == true
end
it "returns false if self does not represent an ASCII-compatible encoding" do
- Encoding::UTF_16LE.ascii_compatible?.should be_false
+ Encoding::UTF_16LE.ascii_compatible?.should == false
+ end
+
+ it "returns false for UTF_16 and UTF_32" do
+ Encoding::UTF_16.should_not.ascii_compatible?
+ Encoding::UTF_32.should_not.ascii_compatible?
+ end
+
+ it "is always false for dummy encodings" do
+ Encoding.list.select(&:dummy?).each do |encoding|
+ encoding.should_not.ascii_compatible?
+ end
end
end
diff --git a/spec/ruby/core/encoding/compatible_spec.rb b/spec/ruby/core/encoding/compatible_spec.rb
index 31376a3b75..0d620e5bf3 100644
--- a/spec/ruby/core/encoding/compatible_spec.rb
+++ b/spec/ruby/core/encoding/compatible_spec.rb
@@ -55,7 +55,7 @@ describe "Encoding.compatible? String, String" do
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")
- Encoding.compatible?(a, b).should be_nil
+ Encoding.compatible?(a, b).should == nil
end
end
@@ -69,7 +69,7 @@ describe "Encoding.compatible? String, String" do
end
it "returns nil if the second encoding is ASCII compatible but neither String's encoding is ASCII only" do
- Encoding.compatible?("\xff", "\u3042".encode("utf-8")).should be_nil
+ Encoding.compatible?("\xff", "\u3042".encode("utf-8")).should == nil
end
end
@@ -79,15 +79,15 @@ describe "Encoding.compatible? String, String" do
end
it "returns nil when the second String is US-ASCII" do
- Encoding.compatible?(@str, "def".encode("us-ascii")).should be_nil
+ Encoding.compatible?(@str, "def".encode("us-ascii")).should == nil
end
it "returns nil when the second String is BINARY and ASCII only" do
- Encoding.compatible?(@str, "\x7f").should be_nil
+ Encoding.compatible?(@str, "\x7f").should == nil
end
it "returns nil when the second String is BINARY but not ASCII only" do
- Encoding.compatible?(@str, "\xff").should be_nil
+ Encoding.compatible?(@str, "\xff").should == nil
end
it "returns the Encoding when the second's Encoding is not ASCII compatible but the same as the first's Encoding" do
@@ -110,15 +110,15 @@ describe "Encoding.compatible? String, String" do
end
it "returns nil when the second's Encoding is BINARY but not ASCII only" do
- Encoding.compatible?(@str, "\xff").should be_nil
+ Encoding.compatible?(@str, "\xff").should == nil
end
it "returns nil when the second's Encoding is invalid and ASCII only" do
- Encoding.compatible?(@str, "\x7f\x7f".dup.force_encoding("utf-16be")).should be_nil
+ Encoding.compatible?(@str, "\x7f\x7f".dup.force_encoding("utf-16be")).should == nil
end
it "returns nil when the second's Encoding is invalid and not ASCII only" do
- Encoding.compatible?(@str, "\xff\xff".dup.force_encoding("utf-16be")).should be_nil
+ Encoding.compatible?(@str, "\xff\xff".dup.force_encoding("utf-16be")).should == nil
end
it "returns the Encoding when the second's Encoding is invalid but the same as the first" do
@@ -557,6 +557,11 @@ describe "Encoding.compatible? String, Regexp" do
[Encoding, "\x82\xa0".dup.force_encoding("shift_jis"), Encoding::Shift_JIS],
].should be_computed_by(:compatible?, /abc/)
end
+
+ it "returns the Regexp's Encoding if the String is ASCII only and the Regexp is not" do
+ r = Regexp.new("\xa4\xa2".dup.force_encoding("euc-jp"))
+ Encoding.compatible?("hello".dup.force_encoding("utf-8"), r).should == Encoding::EUC_JP
+ end
end
describe "Encoding.compatible? String, Symbol" do
@@ -584,11 +589,11 @@ end
describe "Encoding.compatible? String, Encoding" do
it "returns nil if the String's encoding is not ASCII compatible" do
- Encoding.compatible?("abc".encode("utf-32le"), Encoding::US_ASCII).should be_nil
+ Encoding.compatible?("abc".encode("utf-32le"), Encoding::US_ASCII).should == nil
end
it "returns nil if the Encoding is not ASCII compatible" do
- Encoding.compatible?("abc".encode("us-ascii"), Encoding::UTF_32LE).should be_nil
+ Encoding.compatible?("abc".encode("us-ascii"), Encoding::UTF_32LE).should == nil
end
it "returns the String's encoding if the Encoding is US-ASCII" do
@@ -609,7 +614,7 @@ describe "Encoding.compatible? String, Encoding" do
end
it "returns nil if the String's encoding is ASCII compatible but the string is not ASCII only" do
- Encoding.compatible?("\u3042".encode("utf-8"), Encoding::BINARY).should be_nil
+ Encoding.compatible?("\u3042".encode("utf-8"), Encoding::BINARY).should == nil
end
end
@@ -619,6 +624,15 @@ describe "Encoding.compatible? Regexp, String" do
Encoding.compatible?(/abc/, str).should == Encoding::US_ASCII
end
+ it "returns the String's Encoding when the String is ASCII only with a different encoding" do
+ r = Regexp.new("\xa4\xa2".dup.force_encoding("euc-jp"))
+ Encoding.compatible?(r, "hello".dup.force_encoding("utf-8")).should == Encoding::UTF_8
+ end
+
+ it "returns the Regexp's Encoding if the String has the same non-ASCII encoding" do
+ r = Regexp.new("\xa4\xa2".dup.force_encoding("euc-jp"))
+ Encoding.compatible?(r, "hello".dup.force_encoding("euc-jp")).should == Encoding::EUC_JP
+ end
end
describe "Encoding.compatible? Regexp, Regexp" do
@@ -727,32 +741,32 @@ end
describe "Encoding.compatible? Object, Object" do
it "returns nil for Object, String" do
- Encoding.compatible?(Object.new, "abc").should be_nil
+ Encoding.compatible?(Object.new, "abc").should == nil
end
it "returns nil for Object, Regexp" do
- Encoding.compatible?(Object.new, /./).should be_nil
+ Encoding.compatible?(Object.new, /./).should == nil
end
it "returns nil for Object, Symbol" do
- Encoding.compatible?(Object.new, :sym).should be_nil
+ Encoding.compatible?(Object.new, :sym).should == nil
end
it "returns nil for String, Object" do
- Encoding.compatible?("abc", Object.new).should be_nil
+ Encoding.compatible?("abc", Object.new).should == nil
end
it "returns nil for Regexp, Object" do
- Encoding.compatible?(/./, Object.new).should be_nil
+ Encoding.compatible?(/./, Object.new).should == nil
end
it "returns nil for Symbol, Object" do
- Encoding.compatible?(:sym, Object.new).should be_nil
+ Encoding.compatible?(:sym, Object.new).should == nil
end
end
describe "Encoding.compatible? nil, nil" do
it "returns nil" do
- Encoding.compatible?(nil, nil).should be_nil
+ Encoding.compatible?(nil, nil).should == nil
end
end
diff --git a/spec/ruby/core/encoding/converter/asciicompat_encoding_spec.rb b/spec/ruby/core/encoding/converter/asciicompat_encoding_spec.rb
index 1beb40af3f..7fa867a57e 100644
--- a/spec/ruby/core/encoding/converter/asciicompat_encoding_spec.rb
+++ b/spec/ruby/core/encoding/converter/asciicompat_encoding_spec.rb
@@ -1,11 +1,6 @@
require_relative '../../../spec_helper'
describe "Encoding::Converter.asciicompat_encoding" do
- it "accepts an encoding name as a String argument" do
- -> { Encoding::Converter.asciicompat_encoding('UTF-8') }.
- should_not raise_error
- end
-
it "coerces non-String/Encoding objects with #to_str" do
str = mock('string')
str.should_receive(:to_str).at_least(1).times.and_return('string')
@@ -13,9 +8,8 @@ describe "Encoding::Converter.asciicompat_encoding" do
end
it "accepts an Encoding object as an argument" do
- Encoding::Converter.
- asciicompat_encoding(Encoding.find("ISO-2022-JP")).
- should == Encoding::Converter.asciicompat_encoding("ISO-2022-JP")
+ Encoding::Converter.asciicompat_encoding(Encoding.find("ISO-2022-JP")).should ==
+ Encoding::Converter.asciicompat_encoding("ISO-2022-JP")
end
it "returns a corresponding ASCII compatible encoding for ASCII-incompatible encodings" do
@@ -24,14 +18,14 @@ describe "Encoding::Converter.asciicompat_encoding" do
end
it "returns nil when the given encoding is ASCII compatible" do
- Encoding::Converter.asciicompat_encoding('ASCII').should be_nil
- Encoding::Converter.asciicompat_encoding('UTF-8').should be_nil
+ Encoding::Converter.asciicompat_encoding('ASCII').should == nil
+ Encoding::Converter.asciicompat_encoding('UTF-8').should == nil
end
it "handles encoding names who resolve to nil encodings" do
internal = Encoding.default_internal
Encoding.default_internal = nil
- Encoding::Converter.asciicompat_encoding('internal').should be_nil
+ Encoding::Converter.asciicompat_encoding('internal').should == nil
Encoding.default_internal = internal
end
end
diff --git a/spec/ruby/core/encoding/converter/constants_spec.rb b/spec/ruby/core/encoding/converter/constants_spec.rb
index 7d29bdb278..e2d21b5429 100644
--- a/spec/ruby/core/encoding/converter/constants_spec.rb
+++ b/spec/ruby/core/encoding/converter/constants_spec.rb
@@ -2,130 +2,130 @@ require_relative '../../../spec_helper'
describe "Encoding::Converter::INVALID_MASK" do
it "exists" do
- Encoding::Converter.should have_constant(:INVALID_MASK)
+ Encoding::Converter.should.const_defined?(:INVALID_MASK, false)
end
it "has an Integer value" do
- Encoding::Converter::INVALID_MASK.should be_an_instance_of(Integer)
+ Encoding::Converter::INVALID_MASK.should.instance_of?(Integer)
end
end
describe "Encoding::Converter::INVALID_REPLACE" do
it "exists" do
- Encoding::Converter.should have_constant(:INVALID_REPLACE)
+ Encoding::Converter.should.const_defined?(:INVALID_REPLACE, false)
end
it "has an Integer value" do
- Encoding::Converter::INVALID_REPLACE.should be_an_instance_of(Integer)
+ Encoding::Converter::INVALID_REPLACE.should.instance_of?(Integer)
end
end
describe "Encoding::Converter::UNDEF_MASK" do
it "exists" do
- Encoding::Converter.should have_constant(:UNDEF_MASK)
+ Encoding::Converter.should.const_defined?(:UNDEF_MASK, false)
end
it "has an Integer value" do
- Encoding::Converter::UNDEF_MASK.should be_an_instance_of(Integer)
+ Encoding::Converter::UNDEF_MASK.should.instance_of?(Integer)
end
end
describe "Encoding::Converter::UNDEF_REPLACE" do
it "exists" do
- Encoding::Converter.should have_constant(:UNDEF_REPLACE)
+ Encoding::Converter.should.const_defined?(:UNDEF_REPLACE, false)
end
it "has an Integer value" do
- Encoding::Converter::UNDEF_REPLACE.should be_an_instance_of(Integer)
+ Encoding::Converter::UNDEF_REPLACE.should.instance_of?(Integer)
end
end
describe "Encoding::Converter::UNDEF_HEX_CHARREF" do
it "exists" do
- Encoding::Converter.should have_constant(:UNDEF_HEX_CHARREF)
+ Encoding::Converter.should.const_defined?(:UNDEF_HEX_CHARREF, false)
end
it "has an Integer value" do
- Encoding::Converter::UNDEF_HEX_CHARREF.should be_an_instance_of(Integer)
+ Encoding::Converter::UNDEF_HEX_CHARREF.should.instance_of?(Integer)
end
end
describe "Encoding::Converter::PARTIAL_INPUT" do
it "exists" do
- Encoding::Converter.should have_constant(:PARTIAL_INPUT)
+ Encoding::Converter.should.const_defined?(:PARTIAL_INPUT, false)
end
it "has an Integer value" do
- Encoding::Converter::PARTIAL_INPUT.should be_an_instance_of(Integer)
+ Encoding::Converter::PARTIAL_INPUT.should.instance_of?(Integer)
end
end
describe "Encoding::Converter::AFTER_OUTPUT" do
it "exists" do
- Encoding::Converter.should have_constant(:AFTER_OUTPUT)
+ Encoding::Converter.should.const_defined?(:AFTER_OUTPUT, false)
end
it "has an Integer value" do
- Encoding::Converter::AFTER_OUTPUT.should be_an_instance_of(Integer)
+ Encoding::Converter::AFTER_OUTPUT.should.instance_of?(Integer)
end
end
describe "Encoding::Converter::UNIVERSAL_NEWLINE_DECORATOR" do
it "exists" do
- Encoding::Converter.should have_constant(:UNIVERSAL_NEWLINE_DECORATOR)
+ Encoding::Converter.should.const_defined?(:UNIVERSAL_NEWLINE_DECORATOR, false)
end
it "has an Integer value" do
- Encoding::Converter::UNIVERSAL_NEWLINE_DECORATOR.should be_an_instance_of(Integer)
+ Encoding::Converter::UNIVERSAL_NEWLINE_DECORATOR.should.instance_of?(Integer)
end
end
describe "Encoding::Converter::CRLF_NEWLINE_DECORATOR" do
it "exists" do
- Encoding::Converter.should have_constant(:CRLF_NEWLINE_DECORATOR)
+ Encoding::Converter.should.const_defined?(:CRLF_NEWLINE_DECORATOR, false)
end
it "has an Integer value" do
- Encoding::Converter::CRLF_NEWLINE_DECORATOR.should be_an_instance_of(Integer)
+ Encoding::Converter::CRLF_NEWLINE_DECORATOR.should.instance_of?(Integer)
end
end
describe "Encoding::Converter::CR_NEWLINE_DECORATOR" do
it "exists" do
- Encoding::Converter.should have_constant(:CR_NEWLINE_DECORATOR)
+ Encoding::Converter.should.const_defined?(:CR_NEWLINE_DECORATOR, false)
end
it "has an Integer value" do
- Encoding::Converter::CR_NEWLINE_DECORATOR.should be_an_instance_of(Integer)
+ Encoding::Converter::CR_NEWLINE_DECORATOR.should.instance_of?(Integer)
end
end
describe "Encoding::Converter::XML_TEXT_DECORATOR" do
it "exists" do
- Encoding::Converter.should have_constant(:XML_TEXT_DECORATOR)
+ Encoding::Converter.should.const_defined?(:XML_TEXT_DECORATOR, false)
end
it "has an Integer value" do
- Encoding::Converter::XML_TEXT_DECORATOR.should be_an_instance_of(Integer)
+ Encoding::Converter::XML_TEXT_DECORATOR.should.instance_of?(Integer)
end
end
describe "Encoding::Converter::XML_ATTR_CONTENT_DECORATOR" do
it "exists" do
- Encoding::Converter.should have_constant(:XML_ATTR_CONTENT_DECORATOR)
+ Encoding::Converter.should.const_defined?(:XML_ATTR_CONTENT_DECORATOR, false)
end
it "has an Integer value" do
- Encoding::Converter::XML_ATTR_CONTENT_DECORATOR.should be_an_instance_of(Integer)
+ Encoding::Converter::XML_ATTR_CONTENT_DECORATOR.should.instance_of?(Integer)
end
end
describe "Encoding::Converter::XML_ATTR_QUOTE_DECORATOR" do
it "exists" do
- Encoding::Converter.should have_constant(:XML_ATTR_QUOTE_DECORATOR)
+ Encoding::Converter.should.const_defined?(:XML_ATTR_QUOTE_DECORATOR, false)
end
it "has an Integer value" do
- Encoding::Converter::XML_ATTR_QUOTE_DECORATOR.should be_an_instance_of(Integer)
+ Encoding::Converter::XML_ATTR_QUOTE_DECORATOR.should.instance_of?(Integer)
end
end
diff --git a/spec/ruby/core/encoding/converter/convert_spec.rb b/spec/ruby/core/encoding/converter/convert_spec.rb
index 8533af4565..c95e88a491 100644
--- a/spec/ruby/core/encoding/converter/convert_spec.rb
+++ b/spec/ruby/core/encoding/converter/convert_spec.rb
@@ -5,7 +5,7 @@ require_relative '../../../spec_helper'
describe "Encoding::Converter#convert" do
it "returns a String" do
ec = Encoding::Converter.new('ascii', 'utf-8')
- ec.convert('glark').should be_an_instance_of(String)
+ ec.convert('glark').should.instance_of?(String)
end
it "sets the encoding of the result to the target encoding" do
@@ -34,13 +34,12 @@ describe "Encoding::Converter#convert" do
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 \
- raise_error(Encoding::UndefinedConversionError)
+ -> { ec.convert("\u{6543}".dup.force_encoding('UTF-8')) }.should.raise(Encoding::UndefinedConversionError)
end
it "raises an ArgumentError if called on a finished stream" do
ec = Encoding::Converter.new('UTF-8', Encoding.find('macCyrillic'))
ec.finish
- -> { ec.convert("\u{65}") }.should raise_error(ArgumentError)
+ -> { ec.convert("\u{65}") }.should.raise(ArgumentError)
end
end
diff --git a/spec/ruby/core/encoding/converter/finish_spec.rb b/spec/ruby/core/encoding/converter/finish_spec.rb
index 22e66df38c..e13b7415f8 100644
--- a/spec/ruby/core/encoding/converter/finish_spec.rb
+++ b/spec/ruby/core/encoding/converter/finish_spec.rb
@@ -7,7 +7,7 @@ describe "Encoding::Converter#finish" do
it "returns a String" do
@ec.convert('foo')
- @ec.finish.should be_an_instance_of(String)
+ @ec.finish.should.instance_of?(String)
end
it "returns an empty String if there is nothing more to convert" do
diff --git a/spec/ruby/core/encoding/converter/last_error_spec.rb b/spec/ruby/core/encoding/converter/last_error_spec.rb
index ff2a2b4cbe..3984a628f5 100644
--- a/spec/ruby/core/encoding/converter/last_error_spec.rb
+++ b/spec/ruby/core/encoding/converter/last_error_spec.rb
@@ -4,51 +4,51 @@ require_relative '../../../spec_helper'
describe "Encoding::Converter#last_error" do
it "returns nil when the no conversion has been attempted" do
ec = Encoding::Converter.new('ascii','utf-8')
- ec.last_error.should be_nil
+ ec.last_error.should == nil
end
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.last_error.should be_nil
+ ec.last_error.should == 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) \
.should == :destination_buffer_full
- ec.last_error.should be_nil
+ ec.last_error.should == 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.last_error.should be_nil
+ ec.last_error.should == 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.last_error.should be_nil
+ ec.last_error.should == 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.last_error.should be_an_instance_of(Encoding::InvalidByteSequenceError)
+ ec.last_error.should.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.last_error.should be_an_instance_of(Encoding::UndefinedConversionError)
+ ec.last_error.should.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.last_error.should be_an_instance_of(Encoding::InvalidByteSequenceError)
+ ec.last_error.should.instance_of?(Encoding::InvalidByteSequenceError)
end
it "returns an Encoding::InvalidByteSequenceError when the last call to #convert produced one" do
@@ -56,10 +56,10 @@ describe "Encoding::Converter#last_error" do
exception = nil
-> {
ec.convert("\xf1abcd")
- }.should raise_error(Encoding::InvalidByteSequenceError) { |e|
+ }.should.raise(Encoding::InvalidByteSequenceError) { |e|
exception = e
}
- ec.last_error.should be_an_instance_of(Encoding::InvalidByteSequenceError)
+ ec.last_error.should.instance_of?(Encoding::InvalidByteSequenceError)
ec.last_error.message.should == exception.message
end
@@ -68,12 +68,12 @@ describe "Encoding::Converter#last_error" do
exception = nil
-> {
ec.convert("\u{9899}")
- }.should raise_error(Encoding::UndefinedConversionError) { |e|
+ }.should.raise(Encoding::UndefinedConversionError) { |e|
exception = e
}
- ec.last_error.should be_an_instance_of(Encoding::UndefinedConversionError)
+ ec.last_error.should.instance_of?(Encoding::UndefinedConversionError)
ec.last_error.message.should == exception.message
- ec.last_error.message.should include "from UTF-8 to ISO-8859-1"
+ ec.last_error.message.should.include? "from UTF-8 to ISO-8859-1"
end
it "returns the last error of #convert with a message showing the transcoding path" do
@@ -81,11 +81,11 @@ describe "Encoding::Converter#last_error" do
exception = nil
-> {
ec.convert("\xE9") # é in ISO-8859-1
- }.should raise_error(Encoding::UndefinedConversionError) { |e|
+ }.should.raise(Encoding::UndefinedConversionError) { |e|
exception = e
}
- ec.last_error.should be_an_instance_of(Encoding::UndefinedConversionError)
+ ec.last_error.should.instance_of?(Encoding::UndefinedConversionError)
ec.last_error.message.should == exception.message
- ec.last_error.message.should include "from ISO-8859-1 to UTF-8 to Big5"
+ ec.last_error.message.should.include? "from ISO-8859-1 to UTF-8 to Big5"
end
end
diff --git a/spec/ruby/core/encoding/converter/new_spec.rb b/spec/ruby/core/encoding/converter/new_spec.rb
index a7bef53809..bbdfb48bce 100644
--- a/spec/ruby/core/encoding/converter/new_spec.rb
+++ b/spec/ruby/core/encoding/converter/new_spec.rb
@@ -25,7 +25,7 @@ describe "Encoding::Converter.new" do
it "raises an Encoding::ConverterNotFoundError if both encodings are the same" do
-> do
Encoding::Converter.new "utf-8", "utf-8"
- end.should raise_error(Encoding::ConverterNotFoundError)
+ end.should.raise(Encoding::ConverterNotFoundError)
end
it "calls #to_str to convert the source encoding argument to an encoding name" do
@@ -67,25 +67,25 @@ describe "Encoding::Converter.new" do
-> do
Encoding::Converter.new("us-ascii", "utf-8", replace: obj)
- end.should raise_error(TypeError)
+ end.should.raise(TypeError)
end
it "raises a TypeError if passed true for the replacement object" do
-> do
Encoding::Converter.new("us-ascii", "utf-8", replace: true)
- end.should raise_error(TypeError)
+ end.should.raise(TypeError)
end
it "raises a TypeError if passed false for the replacement object" do
-> do
Encoding::Converter.new("us-ascii", "utf-8", replace: false)
- end.should raise_error(TypeError)
+ end.should.raise(TypeError)
end
it "raises a TypeError if passed an Integer for the replacement object" do
-> do
Encoding::Converter.new("us-ascii", "utf-8", replace: 1)
- end.should raise_error(TypeError)
+ end.should.raise(TypeError)
end
it "accepts an empty String for the replacement object" do
diff --git a/spec/ruby/core/encoding/converter/primitive_convert_spec.rb b/spec/ruby/core/encoding/converter/primitive_convert_spec.rb
index e4aeed103e..ab9ce6a992 100644
--- a/spec/ruby/core/encoding/converter/primitive_convert_spec.rb
+++ b/spec/ruby/core/encoding/converter/primitive_convert_spec.rb
@@ -8,23 +8,23 @@ describe "Encoding::Converter#primitive_convert" do
end
it "accepts a nil source buffer" do
- -> { @ec.primitive_convert(nil,"") }.should_not raise_error
+ -> { @ec.primitive_convert(nil,"") }.should_not.raise
end
it "accepts a String as the source buffer" do
- -> { @ec.primitive_convert("","") }.should_not raise_error
+ -> { @ec.primitive_convert("","") }.should_not.raise
end
it "raises FrozenError when the destination buffer is a frozen String" do
- -> { @ec.primitive_convert("", "".freeze) }.should raise_error(FrozenError)
+ -> { @ec.primitive_convert("", "".freeze) }.should.raise(FrozenError)
end
it "accepts nil for the destination byte offset" do
- -> { @ec.primitive_convert("","", nil) }.should_not raise_error
+ -> { @ec.primitive_convert("","", nil) }.should_not.raise
end
it "accepts an integer for the destination byte offset" do
- -> { @ec.primitive_convert("","a", 1) }.should_not raise_error
+ -> { @ec.primitive_convert("","a", 1) }.should_not.raise
end
it "calls #to_int to convert the destination byte offset" do
@@ -35,10 +35,10 @@ describe "Encoding::Converter#primitive_convert" do
end
it "raises an ArgumentError if the destination byte offset is greater than the bytesize of the destination buffer" do
- -> { @ec.primitive_convert("","am", 0) }.should_not raise_error
- -> { @ec.primitive_convert("","am", 1) }.should_not raise_error
- -> { @ec.primitive_convert("","am", 2) }.should_not raise_error
- -> { @ec.primitive_convert("","am", 3) }.should raise_error(ArgumentError)
+ -> { @ec.primitive_convert("","am", 0) }.should_not.raise
+ -> { @ec.primitive_convert("","am", 1) }.should_not.raise
+ -> { @ec.primitive_convert("","am", 2) }.should_not.raise
+ -> { @ec.primitive_convert("","am", 3) }.should.raise(ArgumentError)
end
it "uses the destination byte offset to determine where to write the result in the destination buffer" do
@@ -54,19 +54,19 @@ describe "Encoding::Converter#primitive_convert" do
end
it "accepts nil for the destination bytesize" do
- -> { @ec.primitive_convert("","", nil, nil) }.should_not raise_error
+ -> { @ec.primitive_convert("","", nil, nil) }.should_not.raise
end
it "accepts an integer for the destination bytesize" do
- -> { @ec.primitive_convert("","", nil, 0) }.should_not raise_error
+ -> { @ec.primitive_convert("","", nil, 0) }.should_not.raise
end
it "allows a destination bytesize value greater than the bytesize of the source buffer" do
- -> { @ec.primitive_convert("am","", nil, 3) }.should_not raise_error
+ -> { @ec.primitive_convert("am","", nil, 3) }.should_not.raise
end
it "allows a destination bytesize value less than the bytesize of the source buffer" do
- -> { @ec.primitive_convert("am","", nil, 1) }.should_not raise_error
+ -> { @ec.primitive_convert("am","", nil, 1) }.should_not.raise
end
it "calls #to_int to convert the destination byte size" do
diff --git a/spec/ruby/core/encoding/converter/primitive_errinfo_spec.rb b/spec/ruby/core/encoding/converter/primitive_errinfo_spec.rb
index 5ee8b1fecd..580e2e37e1 100644
--- a/spec/ruby/core/encoding/converter/primitive_errinfo_spec.rb
+++ b/spec/ruby/core/encoding/converter/primitive_errinfo_spec.rb
@@ -55,7 +55,7 @@ describe "Encoding::Converter#primitive_errinfo" do
it "returns the state, source encoding, target encoding, erroneous bytes, and the read-again bytes when #convert last raised InvalidByteSequenceError" do
ec = Encoding::Converter.new("utf-8", "iso-8859-1")
- -> { ec.convert("\xf1abcd") }.should raise_error(Encoding::InvalidByteSequenceError)
+ -> { ec.convert("\xf1abcd") }.should.raise(Encoding::InvalidByteSequenceError)
ec.primitive_errinfo.should ==
[:invalid_byte_sequence, "UTF-8", "ISO-8859-1", "\xF1", "a"]
end
@@ -63,7 +63,7 @@ describe "Encoding::Converter#primitive_errinfo" do
it "returns the state, source encoding, target encoding, erroneous bytes, and the read-again bytes when #finish last raised InvalidByteSequenceError" do
ec = Encoding::Converter.new("EUC-JP", "ISO-8859-1")
ec.convert("\xa4")
- -> { ec.finish }.should raise_error(Encoding::InvalidByteSequenceError)
+ -> { ec.finish }.should.raise(Encoding::InvalidByteSequenceError)
ec.primitive_errinfo.should == [:incomplete_input, "EUC-JP", "UTF-8", "\xA4", ""]
end
end
diff --git a/spec/ruby/core/encoding/converter/putback_spec.rb b/spec/ruby/core/encoding/converter/putback_spec.rb
index 04bb565655..a85cec5145 100644
--- a/spec/ruby/core/encoding/converter/putback_spec.rb
+++ b/spec/ruby/core/encoding/converter/putback_spec.rb
@@ -8,7 +8,7 @@ describe "Encoding::Converter#putback" do
end
it "returns a String" do
- @ec.putback.should be_an_instance_of(String)
+ @ec.putback.should.instance_of?(String)
end
it "returns a String in the source encoding" do
diff --git a/spec/ruby/core/encoding/converter/replacement_spec.rb b/spec/ruby/core/encoding/converter/replacement_spec.rb
index ea514ca8dd..c25ec36517 100644
--- a/spec/ruby/core/encoding/converter/replacement_spec.rb
+++ b/spec/ruby/core/encoding/converter/replacement_spec.rb
@@ -33,7 +33,7 @@ describe "Encoding::Converter#replacement=" do
it "raises a TypeError if assigned a non-String argument" do
ec = Encoding::Converter.new("utf-8", "us-ascii")
- -> { ec.replacement = nil }.should raise_error(TypeError)
+ -> { ec.replacement = nil }.should.raise(TypeError)
end
it "sets #replacement" do
@@ -47,16 +47,14 @@ describe "Encoding::Converter#replacement=" 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
- -> { ec.replacement = utf8_q }.should \
- raise_error(Encoding::UndefinedConversionError)
+ -> { ec.replacement = utf8_q }.should.raise(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
- -> { ec.replacement = utf8_q }.should \
- raise_error(Encoding::UndefinedConversionError)
+ -> { ec.replacement = utf8_q }.should.raise(Encoding::UndefinedConversionError)
ec.replacement.should == "?".dup.force_encoding('us-ascii')
end
diff --git a/spec/ruby/core/encoding/converter/search_convpath_spec.rb b/spec/ruby/core/encoding/converter/search_convpath_spec.rb
index 59fe4520c0..cac44765f8 100644
--- a/spec/ruby/core/encoding/converter/search_convpath_spec.rb
+++ b/spec/ruby/core/encoding/converter/search_convpath_spec.rb
@@ -25,6 +25,6 @@ describe "Encoding::Converter.search_convpath" do
it "raises an Encoding::ConverterNotFoundError if no conversion path exists" do
-> do
Encoding::Converter.search_convpath(Encoding::BINARY, Encoding::Emacs_Mule)
- end.should raise_error(Encoding::ConverterNotFoundError)
+ end.should.raise(Encoding::ConverterNotFoundError)
end
end
diff --git a/spec/ruby/core/encoding/default_external_spec.rb b/spec/ruby/core/encoding/default_external_spec.rb
index 9aae4976e0..2a2bd7f6ae 100644
--- a/spec/ruby/core/encoding/default_external_spec.rb
+++ b/spec/ruby/core/encoding/default_external_spec.rb
@@ -10,7 +10,7 @@ describe "Encoding.default_external" do
end
it "returns an Encoding object" do
- Encoding.default_external.should be_an_instance_of(Encoding)
+ Encoding.default_external.should.instance_of?(Encoding)
end
it "returns the default external encoding" do
@@ -60,10 +60,10 @@ describe "Encoding.default_external=" do
end
it "raises a TypeError unless the argument is an Encoding or convertible to a String" do
- -> { Encoding.default_external = [] }.should raise_error(TypeError)
+ -> { Encoding.default_external = [] }.should.raise(TypeError)
end
it "raises an ArgumentError if the argument is nil" do
- -> { Encoding.default_external = nil }.should raise_error(ArgumentError)
+ -> { Encoding.default_external = nil }.should.raise(ArgumentError)
end
end
diff --git a/spec/ruby/core/encoding/default_internal_spec.rb b/spec/ruby/core/encoding/default_internal_spec.rb
index 855f4e9f32..38aef9dce9 100644
--- a/spec/ruby/core/encoding/default_internal_spec.rb
+++ b/spec/ruby/core/encoding/default_internal_spec.rb
@@ -10,17 +10,17 @@ describe "Encoding.default_internal" do
end
it "is nil by default" do
- Encoding.default_internal.should be_nil
+ Encoding.default_internal.should == nil
end
it "returns an Encoding object if a default internal encoding is set" do
Encoding.default_internal = Encoding::ASCII
- Encoding.default_internal.should be_an_instance_of(Encoding)
+ Encoding.default_internal.should.instance_of?(Encoding)
end
it "returns nil if no default internal encoding is set" do
Encoding.default_internal = nil
- Encoding.default_internal.should be_nil
+ Encoding.default_internal.should == nil
end
it "returns the default internal encoding" do
@@ -60,15 +60,15 @@ describe "Encoding.default_internal=" do
obj = mock('string')
obj.should_receive(:to_str).at_least(1).times.and_return(1)
- -> { Encoding.default_internal = obj }.should raise_error(TypeError)
+ -> { Encoding.default_internal = obj }.should.raise(TypeError)
end
it "raises a TypeError when passed an object not providing #to_str" do
- -> { Encoding.default_internal = mock("encoding") }.should raise_error(TypeError)
+ -> { Encoding.default_internal = mock("encoding") }.should.raise(TypeError)
end
it "accepts an argument of nil to unset the default internal encoding" do
Encoding.default_internal = nil
- Encoding.default_internal.should be_nil
+ Encoding.default_internal.should == nil
end
end
diff --git a/spec/ruby/core/encoding/dummy_spec.rb b/spec/ruby/core/encoding/dummy_spec.rb
index 75ffcd5a4e..05530a8186 100644
--- a/spec/ruby/core/encoding/dummy_spec.rb
+++ b/spec/ruby/core/encoding/dummy_spec.rb
@@ -2,13 +2,24 @@ require_relative '../../spec_helper'
describe "Encoding#dummy?" do
it "returns false for proper encodings" do
- Encoding::UTF_8.dummy?.should be_false
- Encoding::ASCII.dummy?.should be_false
+ Encoding::UTF_8.dummy?.should == false
+ Encoding::ASCII.dummy?.should == false
end
it "returns true for dummy encodings" do
- Encoding::ISO_2022_JP.dummy?.should be_true
- Encoding::CP50221.dummy?.should be_true
- Encoding::UTF_7.dummy?.should be_true
+ Encoding::ISO_2022_JP.dummy?.should == true
+ Encoding::CP50221.dummy?.should == true
+ Encoding::UTF_7.dummy?.should == true
+ end
+
+ it "returns true for UTF_16 and UTF_32" do
+ Encoding::UTF_16.should.dummy?
+ Encoding::UTF_32.should.dummy?
+ end
+
+ it "implies not #ascii_compatible?" do
+ Encoding.list.select(&:dummy?).each do |encoding|
+ encoding.should_not.ascii_compatible?
+ end
end
end
diff --git a/spec/ruby/core/encoding/find_spec.rb b/spec/ruby/core/encoding/find_spec.rb
index 8a0873070f..c5356560eb 100644
--- a/spec/ruby/core/encoding/find_spec.rb
+++ b/spec/ruby/core/encoding/find_spec.rb
@@ -7,18 +7,18 @@ describe "Encoding.find" do
it "returns the corresponding Encoding object if given a valid encoding name" do
@encodings.each do |enc|
- Encoding.find(enc).should be_an_instance_of(Encoding)
+ Encoding.find(enc).should.instance_of?(Encoding)
end
end
it "returns the corresponding Encoding object if given a valid alias name" do
Encoding.aliases.keys.each do |enc_alias|
- Encoding.find(enc_alias).should be_an_instance_of(Encoding)
+ Encoding.find(enc_alias).should.instance_of?(Encoding)
end
end
it "raises a TypeError if passed a Symbol" do
- -> { Encoding.find(:"utf-8") }.should raise_error(TypeError)
+ -> { Encoding.find(:"utf-8") }.should.raise(TypeError)
end
it "returns the passed Encoding object" do
@@ -50,7 +50,7 @@ describe "Encoding.find" do
end
it "raises an ArgumentError if the given encoding does not exist" do
- -> { Encoding.find('dh2dh278d') }.should raise_error(ArgumentError)
+ -> { Encoding.find('dh2dh278d') }.should.raise(ArgumentError, 'unknown encoding name - dh2dh278d')
end
# Not sure how to do a better test, since locale depends on weird platform-specific stuff
diff --git a/spec/ruby/core/encoding/inspect_spec.rb b/spec/ruby/core/encoding/inspect_spec.rb
index df96141db9..ab7f8cf9fc 100644
--- a/spec/ruby/core/encoding/inspect_spec.rb
+++ b/spec/ruby/core/encoding/inspect_spec.rb
@@ -2,7 +2,7 @@ require_relative '../../spec_helper'
describe "Encoding#inspect" do
it "returns a String" do
- Encoding::UTF_8.inspect.should be_an_instance_of(String)
+ Encoding::UTF_8.inspect.should.instance_of?(String)
end
ruby_version_is ""..."3.4" do
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..7d3cc77c0b 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
@@ -8,8 +8,8 @@ describe "Encoding::InvalidByteSequenceError#destination_encoding_name" do
end
it "returns a String" do
- @exception.destination_encoding_name.should be_an_instance_of(String)
- @exception2.destination_encoding_name.should be_an_instance_of(String)
+ @exception.destination_encoding_name.should.instance_of?(String)
+ @exception2.destination_encoding_name.should.instance_of?(String)
end
it "is equal to the destination encoding name of the object that raised it" 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..264c409b1c 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
@@ -8,8 +8,8 @@ describe "Encoding::InvalidByteSequenceError#destination_encoding" do
end
it "returns an Encoding object" do
- @exception.destination_encoding.should be_an_instance_of(Encoding)
- @exception2.destination_encoding.should be_an_instance_of(Encoding)
+ @exception.destination_encoding.should.instance_of?(Encoding)
+ @exception2.destination_encoding.should.instance_of?(Encoding)
end
it "is equal to the destination encoding of the object that raised it" 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 8b7e87960f..40a9a35caf 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
@@ -9,8 +9,8 @@ describe "Encoding::InvalidByteSequenceError#error_bytes" do
end
it "returns a String" do
- @exception.error_bytes.should be_an_instance_of(String)
- @exception2.error_bytes.should be_an_instance_of(String)
+ @exception.error_bytes.should.instance_of?(String)
+ @exception2.error_bytes.should.instance_of?(String)
end
it "returns the bytes that caused the exception" 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 83606f77b4..143db7b6da 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
@@ -3,7 +3,7 @@ require_relative '../../../spec_helper'
describe "Encoding::InvalidByteSequenceError#incomplete_input?" do
it "returns nil by default" do
- Encoding::InvalidByteSequenceError.new.incomplete_input?.should be_nil
+ Encoding::InvalidByteSequenceError.new.incomplete_input?.should == nil
end
it "returns true if #primitive_convert returned :incomplete_input for the same data" do
@@ -12,7 +12,7 @@ describe "Encoding::InvalidByteSequenceError#incomplete_input?" do
begin
ec.convert("\xA1")
rescue Encoding::InvalidByteSequenceError => e
- e.incomplete_input?.should be_true
+ e.incomplete_input?.should == true
end
end
@@ -22,7 +22,7 @@ describe "Encoding::InvalidByteSequenceError#incomplete_input?" do
begin
ec.convert("\xfffffffff")
rescue Encoding::InvalidByteSequenceError => e
- e.incomplete_input?.should be_false
+ e.incomplete_input?.should == false
end
end
end
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 e5ad0a61bd..e4fc81aac6 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
@@ -9,8 +9,8 @@ describe "Encoding::InvalidByteSequenceError#readagain_bytes" do
end
it "returns a String" do
- @exception.readagain_bytes.should be_an_instance_of(String)
- @exception2.readagain_bytes.should be_an_instance_of(String)
+ @exception.readagain_bytes.should.instance_of?(String)
+ @exception2.readagain_bytes.should.instance_of?(String)
end
it "returns the bytes to be read again" do
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..b00e1ad4e8 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
@@ -8,7 +8,7 @@ describe "Encoding::UndefinedConversionError#source_encoding_name" do
end
it "returns a String" do
- @exception.source_encoding_name.should be_an_instance_of(String)
+ @exception.source_encoding_name.should.instance_of?(String)
end
it "is equal to the source encoding name of the object that raised it" 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..32ad25dbb5 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
@@ -8,8 +8,8 @@ describe "Encoding::InvalidByteSequenceError#source_encoding" do
end
it "returns an Encoding object" do
- @exception.source_encoding.should be_an_instance_of(Encoding)
- @exception2.source_encoding.should be_an_instance_of(Encoding)
+ @exception.source_encoding.should.instance_of?(Encoding)
+ @exception2.source_encoding.should.instance_of?(Encoding)
end
it "is equal to the source encoding of the object that raised it" do
diff --git a/spec/ruby/core/encoding/list_spec.rb b/spec/ruby/core/encoding/list_spec.rb
index bd3d5b7bc0..9fe336c608 100644
--- a/spec/ruby/core/encoding/list_spec.rb
+++ b/spec/ruby/core/encoding/list_spec.rb
@@ -2,12 +2,12 @@ require_relative '../../spec_helper'
describe "Encoding.list" do
it "returns an Array" do
- Encoding.list.should be_an_instance_of(Array)
+ Encoding.list.should.instance_of?(Array)
end
it "returns an Array of Encoding objects" do
Encoding.list.each do |enc|
- enc.should be_an_instance_of(Encoding)
+ enc.should.instance_of?(Encoding)
end
end
@@ -17,18 +17,18 @@ describe "Encoding.list" do
end
it "includes the default external encoding" do
- Encoding.list.include?(Encoding.default_external).should be_true
+ Encoding.list.include?(Encoding.default_external).should == true
end
it "does not include any alias names" do
Encoding.aliases.keys.each do |enc_alias|
- Encoding.list.include?(enc_alias).should be_false
+ Encoding.list.include?(enc_alias).should == false
end
end
it "includes all aliased encodings" do
Encoding.aliases.values.each do |enc_alias|
- Encoding.list.include?(Encoding.find(enc_alias)).should be_true
+ Encoding.list.include?(Encoding.find(enc_alias)).should == true
end
end
diff --git a/spec/ruby/core/encoding/locale_charmap_spec.rb b/spec/ruby/core/encoding/locale_charmap_spec.rb
index 8143b9083a..0d77bf227b 100644
--- a/spec/ruby/core/encoding/locale_charmap_spec.rb
+++ b/spec/ruby/core/encoding/locale_charmap_spec.rb
@@ -2,55 +2,55 @@ require_relative '../../spec_helper'
describe "Encoding.locale_charmap" do
it "returns a String" do
- Encoding.locale_charmap.should be_an_instance_of(String)
+ Encoding.locale_charmap.should.instance_of?(String)
end
- # FIXME: Get this working on Windows
- platform_is :linux do
- platform_is_not :android do
- it "returns a value based on the LC_ALL environment variable" do
- old_lc_all = ENV['LC_ALL']
- ENV['LC_ALL'] = 'C'
- ruby_exe("print Encoding.locale_charmap").should == 'ANSI_X3.4-1968'
- ENV['LC_ALL'] = old_lc_all
+ describe "when setting LC_ALL=C" do
+ before :each do
+ @old_lc_all = ENV['LC_ALL']
+ end
+
+ after :each do
+ ENV['LC_ALL'] = @old_lc_all
+ end
+
+ # FIXME: Get this working on Windows
+ platform_is :linux do
+ platform_is_not :android do
+ it "returns a value based on the LC_ALL environment variable" do
+ ENV['LC_ALL'] = 'C'
+ ruby_exe("print Encoding.locale_charmap").should == 'ANSI_X3.4-1968'
+ end
end
end
- end
- platform_is :freebsd, :openbsd, :darwin do
- it "returns a value based on the LC_ALL environment variable" do
- old_lc_all = ENV['LC_ALL']
- ENV['LC_ALL'] = 'C'
- ruby_exe("print Encoding.locale_charmap").should == 'US-ASCII'
- ENV['LC_ALL'] = old_lc_all
+ platform_is :freebsd, :openbsd, :darwin do
+ it "returns a value based on the LC_ALL environment variable" do
+ ENV['LC_ALL'] = 'C'
+ ruby_exe("print Encoding.locale_charmap").should == 'US-ASCII'
+ end
end
- end
- platform_is :netbsd do
- it "returns a value based on the LC_ALL environment variable" do
- old_lc_all = ENV['LC_ALL']
- ENV['LC_ALL'] = 'C'
- ruby_exe("print Encoding.locale_charmap").should == '646'
- ENV['LC_ALL'] = old_lc_all
+ platform_is :netbsd do
+ it "returns a value based on the LC_ALL environment variable" do
+ ENV['LC_ALL'] = 'C'
+ ruby_exe("print Encoding.locale_charmap").should == '646'
+ end
end
- end
- platform_is :android do
- it "always returns UTF-8" do
- old_lc_all = ENV['LC_ALL']
- ENV['LC_ALL'] = 'C'
- ruby_exe("print Encoding.locale_charmap").should == 'UTF-8'
- ENV['LC_ALL'] = old_lc_all
+ platform_is :android do
+ it "always returns UTF-8" do
+ ENV['LC_ALL'] = 'C'
+ ruby_exe("print Encoding.locale_charmap").should == 'UTF-8'
+ end
end
- end
- platform_is :bsd, :darwin, :linux do
- it "is unaffected by assigning to ENV['LC_ALL'] in the same process" do
- old_charmap = Encoding.locale_charmap
- old_lc_all = ENV['LC_ALL']
- ENV['LC_ALL'] = 'C'
- Encoding.locale_charmap.should == old_charmap
- ENV['LC_ALL'] = old_lc_all
+ platform_is :bsd, :darwin, :linux do
+ it "is unaffected by assigning to ENV['LC_ALL'] in the same process" do
+ old_charmap = Encoding.locale_charmap
+ ENV['LC_ALL'] = 'C'
+ Encoding.locale_charmap.should == old_charmap
+ end
end
end
end
diff --git a/spec/ruby/core/encoding/name_list_spec.rb b/spec/ruby/core/encoding/name_list_spec.rb
index 836381c4d8..1ba8d383bc 100644
--- a/spec/ruby/core/encoding/name_list_spec.rb
+++ b/spec/ruby/core/encoding/name_list_spec.rb
@@ -2,22 +2,22 @@ require_relative '../../spec_helper'
describe "Encoding.name_list" do
it "returns an Array" do
- Encoding.name_list.should be_an_instance_of(Array)
+ Encoding.name_list.should.instance_of?(Array)
end
it "returns encoding names as Strings" do
- Encoding.name_list.each {|e| e.should be_an_instance_of(String) }
+ Encoding.name_list.each {|e| e.should.instance_of?(String) }
end
it "includes all aliases" do
Encoding.aliases.keys.each do |enc_alias|
- Encoding.name_list.include?(enc_alias).should be_true
+ Encoding.name_list.include?(enc_alias).should == true
end
end
it "includes all non-dummy encodings" do
Encoding.list.each do |enc|
- Encoding.name_list.include?(enc.name).should be_true
+ Encoding.name_list.include?(enc.name).should == true
end
end
end
diff --git a/spec/ruby/core/encoding/name_spec.rb b/spec/ruby/core/encoding/name_spec.rb
index dce9347978..1d625c9379 100644
--- a/spec/ruby/core/encoding/name_spec.rb
+++ b/spec/ruby/core/encoding/name_spec.rb
@@ -1,6 +1,15 @@
require_relative "../../spec_helper"
-require_relative 'shared/name'
describe "Encoding#name" do
- it_behaves_like :encoding_name, :name
+ it "returns a String" do
+ Encoding.list.each do |e|
+ e.name.should.instance_of?(String)
+ end
+ end
+
+ it "uniquely identifies an encoding" do
+ Encoding.list.each do |e|
+ e.should == Encoding.find(e.name)
+ end
+ end
end
diff --git a/spec/ruby/core/encoding/names_spec.rb b/spec/ruby/core/encoding/names_spec.rb
index 9ded043bbb..e6bcbf474a 100644
--- a/spec/ruby/core/encoding/names_spec.rb
+++ b/spec/ruby/core/encoding/names_spec.rb
@@ -4,7 +4,7 @@ describe "Encoding#names" do
it "returns an Array" do
Encoding.name_list.each do |name|
e = Encoding.find(name) or next
- e.names.should be_an_instance_of(Array)
+ e.names.should.instance_of?(Array)
end
end
@@ -12,7 +12,7 @@ describe "Encoding#names" do
Encoding.name_list.each do |name|
e = Encoding.find(name) or next
e.names.each do |this_name|
- this_name.should be_an_instance_of(String)
+ this_name.should.instance_of?(String)
end
end
end
@@ -29,7 +29,7 @@ describe "Encoding#names" do
e = Encoding.find(name) or next
aliases = Encoding.aliases.select{|a,n| n == name}.keys
names = e.names
- aliases.each {|a| names.include?(a).should be_true}
+ aliases.each {|a| names.include?(a).should == true}
end
end
end
diff --git a/spec/ruby/core/encoding/replicate_spec.rb b/spec/ruby/core/encoding/replicate_spec.rb
index 2da998837f..9fe0ba8747 100644
--- a/spec/ruby/core/encoding/replicate_spec.rb
+++ b/spec/ruby/core/encoding/replicate_spec.rb
@@ -2,87 +2,7 @@
require_relative '../../spec_helper'
describe "Encoding#replicate" do
- ruby_version_is ""..."3.3" do
- before :all do
- @i = 0
- end
-
- before :each do
- @i += 1
- @prefix = "RS#{@i}"
- end
-
- it "returns a replica of ASCII" do
- name = @prefix + '-ASCII'
- e = suppress_warning { Encoding::ASCII.replicate(name) }
- 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
- end
-
- it "returns a replica of UTF-8" do
- name = @prefix + 'UTF-8'
- e = suppress_warning { Encoding::UTF_8.replicate(name) }
- 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
- end
-
- it "returns a replica of UTF-16BE" do
- name = @prefix + 'UTF-16-BE'
- e = suppress_warning { Encoding::UTF_16BE.replicate(name) }
- 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
- end
-
- it "returns a replica of ISO-2022-JP" do
- name = @prefix + 'ISO-2022-JP'
- e = suppress_warning { Encoding::ISO_2022_JP.replicate(name) }
- Encoding.find(name).should == e
-
- e.name.should == name
- e.dummy?.should be_true
- end
-
- # NOTE: it's unclear of the value of this (for the complexity cost of it),
- # but it is the current CRuby behavior.
- it "can be associated with a String" do
- name = @prefix + '-US-ASCII'
- e = suppress_warning { Encoding::US_ASCII.replicate(name) }
- e.name.should == name
- Encoding.find(name).should == e
-
- s = "abc".dup.force_encoding(e)
- s.encoding.should == e
- s.encoding.name.should == name
- end
- end
-
- ruby_version_is ""..."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)
- end
+ it "has been removed" do
+ Encoding::US_ASCII.should_not.respond_to?(:replicate, true)
end
end
diff --git a/spec/ruby/core/encoding/shared/name.rb b/spec/ruby/core/encoding/shared/name.rb
deleted file mode 100644
index cd37ea06db..0000000000
--- a/spec/ruby/core/encoding/shared/name.rb
+++ /dev/null
@@ -1,15 +0,0 @@
-require_relative '../../../spec_helper'
-
-describe :encoding_name, shared: true do
- it "returns a String" do
- Encoding.list.each do |e|
- e.send(@method).should be_an_instance_of(String)
- end
- end
-
- it "uniquely identifies an encoding" do
- Encoding.list.each do |e|
- e.should == Encoding.find(e.send(@method))
- end
- end
-end
diff --git a/spec/ruby/core/encoding/to_s_spec.rb b/spec/ruby/core/encoding/to_s_spec.rb
index bab394a888..ee5e3b4abe 100644
--- a/spec/ruby/core/encoding/to_s_spec.rb
+++ b/spec/ruby/core/encoding/to_s_spec.rb
@@ -1,6 +1,7 @@
require_relative "../../spec_helper"
-require_relative 'shared/name'
describe "Encoding#to_s" do
- it_behaves_like :encoding_name, :to_s
+ it "is an alias of Encoding#name" do
+ Encoding.instance_method(:to_s).should == Encoding.instance_method(:name)
+ end
end
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..bc36695ca7 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
@@ -7,7 +7,7 @@ describe "Encoding::UndefinedConversionError#destination_encoding_name" do
end
it "returns a String" do
- @exception.destination_encoding_name.should be_an_instance_of(String)
+ @exception.destination_encoding_name.should.instance_of?(String)
end
it "is equal to the destination encoding name of the object that raised it" 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..c0fcf8de58 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
@@ -7,7 +7,7 @@ describe "Encoding::UndefinedConversionError#destination_encoding" do
end
it "returns an Encoding object" do
- @exception.destination_encoding.should be_an_instance_of(Encoding)
+ @exception.destination_encoding.should.instance_of?(Encoding)
end
it "is equal to the destination encoding of the object that raised it" 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..333acf5ee6 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
@@ -8,8 +8,8 @@ describe "Encoding::UndefinedConversionError#error_char" do
end
it "returns a String" do
- @exception.error_char.should be_an_instance_of(String)
- @exception2.error_char.should be_an_instance_of(String)
+ @exception.error_char.should.instance_of?(String)
+ @exception2.error_char.should.instance_of?(String)
end
it "returns the one-character String that caused the exception" 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..4932a25ed7 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
@@ -8,7 +8,7 @@ describe "Encoding::UndefinedConversionError#source_encoding_name" do
end
it "returns a String" do
- @exception.source_encoding_name.should be_an_instance_of(String)
+ @exception.source_encoding_name.should.instance_of?(String)
end
it "is equal to the source encoding name of the object that raised it" 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..cf12020ad2 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
@@ -8,8 +8,8 @@ describe "Encoding::UndefinedConversionError#source_encoding" do
end
it "returns an Encoding object" do
- @exception.source_encoding.should be_an_instance_of(Encoding)
- @exception2.source_encoding.should be_an_instance_of(Encoding)
+ @exception.source_encoding.should.instance_of?(Encoding)
+ @exception2.source_encoding.should.instance_of?(Encoding)
end
it "is equal to the source encoding of the object that raised it" do
diff --git a/spec/ruby/core/enumerable/all_spec.rb b/spec/ruby/core/enumerable/all_spec.rb
index 160cd52628..cbdd63f86a 100644
--- a/spec/ruby/core/enumerable/all_spec.rb
+++ b/spec/ruby/core/enumerable/all_spec.rb
@@ -21,19 +21,19 @@ describe "Enumerable#all?" do
end
it "raises an ArgumentError when more than 1 argument is provided" do
- -> { @enum.all?(1, 2, 3) }.should raise_error(ArgumentError)
- -> { [].all?(1, 2, 3) }.should raise_error(ArgumentError)
- -> { {}.all?(1, 2, 3) }.should raise_error(ArgumentError)
+ -> { @enum.all?(1, 2, 3) }.should.raise(ArgumentError)
+ -> { [].all?(1, 2, 3) }.should.raise(ArgumentError)
+ -> { {}.all?(1, 2, 3) }.should.raise(ArgumentError)
end
it "does not hide exceptions out of #each" do
-> {
EnumerableSpecs::ThrowingEach.new.all?
- }.should raise_error(RuntimeError)
+ }.should.raise(RuntimeError)
-> {
EnumerableSpecs::ThrowingEach.new.all? { false }
- }.should raise_error(RuntimeError)
+ }.should.raise(RuntimeError)
end
describe "with no block" do
@@ -60,7 +60,7 @@ describe "Enumerable#all?" do
it "gathers whole arrays as elements when each yields multiple" do
multi = EnumerableSpecs::YieldsMultiWithFalse.new
- multi.all?.should be_true
+ multi.all?.should == true
end
end
@@ -106,7 +106,7 @@ describe "Enumerable#all?" do
it "does not hide exceptions out of the block" do
-> {
@enum.all? { raise "from block" }
- }.should raise_error(RuntimeError)
+ }.should.raise(RuntimeError)
end
it "gathers initial args as elements when each yields multiple" do
@@ -125,7 +125,7 @@ describe "Enumerable#all?" do
end
describe 'when given a pattern argument' do
- it "calls `===` on the pattern the return value " do
+ it "calls `===` on the pattern the return value" do
pattern = EnumerableSpecs::Pattern.new { |x| x >= 0 }
@enum1.all?(pattern).should == false
pattern.yielded.should == [[0], [1], [2], [-1]]
@@ -140,7 +140,7 @@ describe "Enumerable#all?" do
it "does not hide exceptions out of #each" do
-> {
EnumerableSpecs::ThrowingEach.new.all?(Integer)
- }.should raise_error(RuntimeError)
+ }.should.raise(RuntimeError)
end
it "returns true if the pattern never returns false or nil" do
@@ -168,7 +168,7 @@ describe "Enumerable#all?" do
pattern = EnumerableSpecs::Pattern.new { raise "from pattern" }
-> {
@enum.all?(pattern)
- }.should raise_error(RuntimeError)
+ }.should.raise(RuntimeError)
end
it "calls the pattern with gathered array when yielded with multiple arguments" do
diff --git a/spec/ruby/core/enumerable/any_spec.rb b/spec/ruby/core/enumerable/any_spec.rb
index 243f8735d5..4405d4740a 100644
--- a/spec/ruby/core/enumerable/any_spec.rb
+++ b/spec/ruby/core/enumerable/any_spec.rb
@@ -21,19 +21,19 @@ describe "Enumerable#any?" do
end
it "raises an ArgumentError when more than 1 argument is provided" do
- -> { @enum.any?(1, 2, 3) }.should raise_error(ArgumentError)
- -> { [].any?(1, 2, 3) }.should raise_error(ArgumentError)
- -> { {}.any?(1, 2, 3) }.should raise_error(ArgumentError)
+ -> { @enum.any?(1, 2, 3) }.should.raise(ArgumentError)
+ -> { [].any?(1, 2, 3) }.should.raise(ArgumentError)
+ -> { {}.any?(1, 2, 3) }.should.raise(ArgumentError)
end
it "does not hide exceptions out of #each" do
-> {
EnumerableSpecs::ThrowingEach.new.any?
- }.should raise_error(RuntimeError)
+ }.should.raise(RuntimeError)
-> {
EnumerableSpecs::ThrowingEach.new.any? { false }
- }.should raise_error(RuntimeError)
+ }.should.raise(RuntimeError)
end
describe "with no block" do
@@ -60,7 +60,7 @@ describe "Enumerable#any?" do
it "gathers whole arrays as elements when each yields multiple" do
multi = EnumerableSpecs::YieldsMultiWithFalse.new
- multi.any?.should be_true
+ multi.any?.should == true
end
end
@@ -120,7 +120,7 @@ describe "Enumerable#any?" do
it "does not hide exceptions out of the block" do
-> {
@enum.any? { raise "from block" }
- }.should raise_error(RuntimeError)
+ }.should.raise(RuntimeError)
end
it "gathers initial args as elements when each yields multiple" do
@@ -139,7 +139,7 @@ describe "Enumerable#any?" do
end
describe 'when given a pattern argument' do
- it "calls `===` on the pattern the return value " do
+ it "calls `===` on the pattern the return value" do
pattern = EnumerableSpecs::Pattern.new { |x| x == 2 }
@enum1.any?(pattern).should == true
pattern.yielded.should == [[0], [1], [2]]
@@ -154,7 +154,7 @@ describe "Enumerable#any?" do
it "does not hide exceptions out of #each" do
-> {
EnumerableSpecs::ThrowingEach.new.any?(Integer)
- }.should raise_error(RuntimeError)
+ }.should.raise(RuntimeError)
end
it "returns true if the pattern ever returns a truthy value" do
@@ -181,7 +181,7 @@ describe "Enumerable#any?" do
pattern = EnumerableSpecs::Pattern.new { raise "from pattern" }
-> {
@enum.any?(pattern)
- }.should raise_error(RuntimeError)
+ }.should.raise(RuntimeError)
end
it "calls the pattern with gathered array when yielded with multiple arguments" do
diff --git a/spec/ruby/core/enumerable/chain_spec.rb b/spec/ruby/core/enumerable/chain_spec.rb
index 5e2105d294..a0597e46a1 100644
--- a/spec/ruby/core/enumerable/chain_spec.rb
+++ b/spec/ruby/core/enumerable/chain_spec.rb
@@ -18,6 +18,6 @@ describe "Enumerable#chain" do
end
it "returns an Enumerator::Chain if given a block" do
- EnumerableSpecs::Numerous.new.chain.should be_an_instance_of(Enumerator::Chain)
+ EnumerableSpecs::Numerous.new.chain.should.instance_of?(Enumerator::Chain)
end
end
diff --git a/spec/ruby/core/enumerable/chunk_spec.rb b/spec/ruby/core/enumerable/chunk_spec.rb
index ed6304307f..7c9b31c991 100644
--- a/spec/ruby/core/enumerable/chunk_spec.rb
+++ b/spec/ruby/core/enumerable/chunk_spec.rb
@@ -8,13 +8,13 @@ describe "Enumerable#chunk" do
it "returns an Enumerator if called without a block" do
chunk = EnumerableSpecs::Numerous.new(1, 2, 3, 1, 2).chunk
- chunk.should be_an_instance_of(Enumerator)
+ chunk.should.instance_of?(Enumerator)
result = chunk.with_index {|elt, i| elt - i }.to_a
result.should == [[1, [1, 2, 3]], [-2, [1, 2]]]
end
it "returns an Enumerator if given a block" do
- EnumerableSpecs::Numerous.new.chunk {}.should be_an_instance_of(Enumerator)
+ EnumerableSpecs::Numerous.new.chunk {}.should.instance_of?(Enumerator)
end
it "yields the current element and the current chunk to the block" do
@@ -59,14 +59,14 @@ describe "Enumerable#chunk" do
it "raises a RuntimeError if the block returns a Symbol starting with an underscore other than :_alone or :_separator" do
e = EnumerableSpecs::Numerous.new(1, 2, 3, 2, 1)
- -> { e.chunk { |x| :_arbitrary }.to_a }.should raise_error(RuntimeError)
+ -> { e.chunk { |x| :_arbitrary }.to_a }.should.raise(RuntimeError)
end
it "does not accept arguments" do
e = EnumerableSpecs::Numerous.new(1, 2, 3)
-> {
e.chunk(1) {}
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
it 'returned Enumerator size returns nil' do
diff --git a/spec/ruby/core/enumerable/chunk_while_spec.rb b/spec/ruby/core/enumerable/chunk_while_spec.rb
index 26bcc983db..286f717442 100644
--- a/spec/ruby/core/enumerable/chunk_while_spec.rb
+++ b/spec/ruby/core/enumerable/chunk_while_spec.rb
@@ -11,7 +11,7 @@ describe "Enumerable#chunk_while" do
context "when given a block" do
it "returns an enumerator" do
- @result.should be_an_instance_of(Enumerator)
+ @result.should.instance_of?(Enumerator)
end
it "splits chunks between adjacent elements i and j where the block returns false" do
@@ -30,7 +30,7 @@ describe "Enumerable#chunk_while" do
context "when not given a block" do
it "raises an ArgumentError" do
- -> { @enum.chunk_while }.should raise_error(ArgumentError)
+ -> { @enum.chunk_while }.should.raise(ArgumentError)
end
end
diff --git a/spec/ruby/core/enumerable/collect_concat_spec.rb b/spec/ruby/core/enumerable/collect_concat_spec.rb
index 59317cfe34..5024aaddab 100644
--- a/spec/ruby/core/enumerable/collect_concat_spec.rb
+++ b/spec/ruby/core/enumerable/collect_concat_spec.rb
@@ -1,7 +1,7 @@
require_relative '../../spec_helper'
-require_relative 'fixtures/classes'
-require_relative 'shared/collect_concat'
describe "Enumerable#collect_concat" do
- it_behaves_like :enumerable_collect_concat, :collect_concat
+ it "is an alias of Enumerable#flat_map" do
+ Enumerable.instance_method(:collect_concat).should == Enumerable.instance_method(:flat_map)
+ end
end
diff --git a/spec/ruby/core/enumerable/collect_spec.rb b/spec/ruby/core/enumerable/collect_spec.rb
index cfa2895cce..319b1b263d 100644
--- a/spec/ruby/core/enumerable/collect_spec.rb
+++ b/spec/ruby/core/enumerable/collect_spec.rb
@@ -1,7 +1,7 @@
require_relative '../../spec_helper'
-require_relative 'fixtures/classes'
-require_relative 'shared/collect'
describe "Enumerable#collect" do
- it_behaves_like :enumerable_collect, :collect
+ it "is an alias of Enumerable#map" do
+ Enumerable.instance_method(:collect).should == Enumerable.instance_method(:map)
+ end
end
diff --git a/spec/ruby/core/enumerable/cycle_spec.rb b/spec/ruby/core/enumerable/cycle_spec.rb
index 487086cba3..1fb3cc3d41 100644
--- a/spec/ruby/core/enumerable/cycle_spec.rb
+++ b/spec/ruby/core/enumerable/cycle_spec.rb
@@ -17,7 +17,7 @@ describe "Enumerable#cycle" do
it "returns nil if there are no elements" do
out = EnumerableSpecs::Empty.new.cycle { break :nope }
- out.should be_nil
+ out.should == nil
end
it "yields successive elements of the array repeatedly" do
@@ -44,8 +44,8 @@ describe "Enumerable#cycle" do
describe "passed a number n as an argument" do
it "returns nil and does nothing for non positive n" do
- EnumerableSpecs::ThrowingEach.new.cycle(0) {}.should be_nil
- EnumerableSpecs::NoEach.new.cycle(-22) {}.should be_nil
+ EnumerableSpecs::ThrowingEach.new.cycle(0) {}.should == nil
+ EnumerableSpecs::NoEach.new.cycle(-22) {}.should == nil
end
it "calls each at most once" do
@@ -71,12 +71,12 @@ describe "Enumerable#cycle" do
it "raises a TypeError when the passed n cannot be coerced to Integer" do
enum = EnumerableSpecs::Numerous.new
- ->{ enum.cycle("cat"){} }.should raise_error(TypeError)
+ ->{ enum.cycle("cat"){} }.should.raise(TypeError)
end
it "raises an ArgumentError if more arguments are passed" do
enum = EnumerableSpecs::Numerous.new
- ->{ enum.cycle(1, 2) {} }.should raise_error(ArgumentError)
+ ->{ enum.cycle(1, 2) {} }.should.raise(ArgumentError)
end
it "gathers whole arrays as elements when each yields multiple" do
diff --git a/spec/ruby/core/enumerable/detect_spec.rb b/spec/ruby/core/enumerable/detect_spec.rb
index 6959aadc44..0669c50c58 100644
--- a/spec/ruby/core/enumerable/detect_spec.rb
+++ b/spec/ruby/core/enumerable/detect_spec.rb
@@ -1,7 +1,7 @@
require_relative '../../spec_helper'
-require_relative 'fixtures/classes'
-require_relative 'shared/find'
describe "Enumerable#detect" do
- it_behaves_like :enumerable_find, :detect
+ it "is an alias of Enumerable#find" do
+ Enumerable.instance_method(:detect).should == Enumerable.instance_method(:find)
+ end
end
diff --git a/spec/ruby/core/enumerable/drop_spec.rb b/spec/ruby/core/enumerable/drop_spec.rb
index 423cc0088b..8d95f464b3 100644
--- a/spec/ruby/core/enumerable/drop_spec.rb
+++ b/spec/ruby/core/enumerable/drop_spec.rb
@@ -7,13 +7,13 @@ describe "Enumerable#drop" do
end
it "requires exactly one argument" do
- ->{ @enum.drop{} }.should raise_error(ArgumentError)
- ->{ @enum.drop(1, 2){} }.should raise_error(ArgumentError)
+ ->{ @enum.drop{} }.should.raise(ArgumentError)
+ ->{ @enum.drop(1, 2){} }.should.raise(ArgumentError)
end
describe "passed a number n as an argument" do
it "raises ArgumentError if n < 0" do
- ->{ @enum.drop(-1) }.should raise_error(ArgumentError)
+ ->{ @enum.drop(-1) }.should.raise(ArgumentError)
end
it "tries to convert n to an Integer using #to_int" do
@@ -35,8 +35,8 @@ describe "Enumerable#drop" do
end
it "raises a TypeError when the passed n cannot be coerced to Integer" do
- ->{ @enum.drop("hat") }.should raise_error(TypeError)
- ->{ @enum.drop(nil) }.should raise_error(TypeError)
+ ->{ @enum.drop("hat") }.should.raise(TypeError)
+ ->{ @enum.drop(nil) }.should.raise(TypeError)
end
end
diff --git a/spec/ruby/core/enumerable/drop_while_spec.rb b/spec/ruby/core/enumerable/drop_while_spec.rb
index 636c3d284a..4b4fdf2d4f 100644
--- a/spec/ruby/core/enumerable/drop_while_spec.rb
+++ b/spec/ruby/core/enumerable/drop_while_spec.rb
@@ -8,7 +8,7 @@ describe "Enumerable#drop_while" do
end
it "returns an Enumerator if no block given" do
- @enum.drop_while.should be_an_instance_of(Enumerator)
+ @enum.drop_while.should.instance_of?(Enumerator)
end
it "returns no/all elements for {true/false} block" do
@@ -38,7 +38,7 @@ describe "Enumerable#drop_while" do
it "doesn't return self when it could" do
a = [1,2,3]
- a.drop_while{false}.should_not equal(a)
+ a.drop_while{false}.should_not.equal?(a)
end
it "gathers whole arrays as elements when each yields multiple" do
diff --git a/spec/ruby/core/enumerable/each_cons_spec.rb b/spec/ruby/core/enumerable/each_cons_spec.rb
index ed77741862..c5e299fd00 100644
--- a/spec/ruby/core/enumerable/each_cons_spec.rb
+++ b/spec/ruby/core/enumerable/each_cons_spec.rb
@@ -15,14 +15,14 @@ describe "Enumerable#each_cons" do
end
it "raises an ArgumentError if there is not a single parameter > 0" do
- ->{ @enum.each_cons(0){} }.should raise_error(ArgumentError)
- ->{ @enum.each_cons(-2){} }.should raise_error(ArgumentError)
- ->{ @enum.each_cons{} }.should raise_error(ArgumentError)
- ->{ @enum.each_cons(2,2){} }.should raise_error(ArgumentError)
- ->{ @enum.each_cons(0) }.should raise_error(ArgumentError)
- ->{ @enum.each_cons(-2) }.should raise_error(ArgumentError)
- ->{ @enum.each_cons }.should raise_error(ArgumentError)
- ->{ @enum.each_cons(2,2) }.should raise_error(ArgumentError)
+ ->{ @enum.each_cons(0){} }.should.raise(ArgumentError)
+ ->{ @enum.each_cons(-2){} }.should.raise(ArgumentError)
+ ->{ @enum.each_cons{} }.should.raise(ArgumentError)
+ ->{ @enum.each_cons(2,2){} }.should.raise(ArgumentError)
+ ->{ @enum.each_cons(0) }.should.raise(ArgumentError)
+ ->{ @enum.each_cons(-2) }.should.raise(ArgumentError)
+ ->{ @enum.each_cons }.should.raise(ArgumentError)
+ ->{ @enum.each_cons(2,2) }.should.raise(ArgumentError)
end
it "tries to convert n to an Integer using #to_int" do
@@ -63,7 +63,7 @@ describe "Enumerable#each_cons" do
describe "when no block is given" do
it "returns an enumerator" do
e = @enum.each_cons(3)
- e.should be_an_instance_of(Enumerator)
+ e.should.instance_of?(Enumerator)
e.to_a.should == @in_threes
end
diff --git a/spec/ruby/core/enumerable/each_entry_spec.rb b/spec/ruby/core/enumerable/each_entry_spec.rb
index edf00f3137..9dc89ec28e 100644
--- a/spec/ruby/core/enumerable/each_entry_spec.rb
+++ b/spec/ruby/core/enumerable/each_entry_spec.rb
@@ -11,13 +11,13 @@ describe "Enumerable#each_entry" do
it "yields multiple arguments as an array" do
acc = []
- @enum.each_entry {|g| acc << g}.should equal(@enum)
+ @enum.each_entry {|g| acc << g}.should.equal?(@enum)
acc.should == @entries
end
it "returns an enumerator if no block" do
e = @enum.each_entry
- e.should be_an_instance_of(Enumerator)
+ e.should.instance_of?(Enumerator)
e.to_a.should == @entries
end
@@ -27,8 +27,8 @@ describe "Enumerable#each_entry" do
end
it "raises an ArgumentError when extra arguments" do
- -> { @enum.each_entry("one").to_a }.should raise_error(ArgumentError)
- -> { @enum.each_entry("one"){}.to_a }.should raise_error(ArgumentError)
+ -> { @enum.each_entry("one").to_a }.should.raise(ArgumentError)
+ -> { @enum.each_entry("one"){}.to_a }.should.raise(ArgumentError)
end
it "passes extra arguments to #each" do
diff --git a/spec/ruby/core/enumerable/each_slice_spec.rb b/spec/ruby/core/enumerable/each_slice_spec.rb
index 47b8c9ba33..d05abad1e9 100644
--- a/spec/ruby/core/enumerable/each_slice_spec.rb
+++ b/spec/ruby/core/enumerable/each_slice_spec.rb
@@ -15,14 +15,14 @@ describe "Enumerable#each_slice" do
end
it "raises an ArgumentError if there is not a single parameter > 0" do
- ->{ @enum.each_slice(0){} }.should raise_error(ArgumentError)
- ->{ @enum.each_slice(-2){} }.should raise_error(ArgumentError)
- ->{ @enum.each_slice{} }.should raise_error(ArgumentError)
- ->{ @enum.each_slice(2,2){} }.should raise_error(ArgumentError)
- ->{ @enum.each_slice(0) }.should raise_error(ArgumentError)
- ->{ @enum.each_slice(-2) }.should raise_error(ArgumentError)
- ->{ @enum.each_slice }.should raise_error(ArgumentError)
- ->{ @enum.each_slice(2,2) }.should raise_error(ArgumentError)
+ ->{ @enum.each_slice(0){} }.should.raise(ArgumentError)
+ ->{ @enum.each_slice(-2){} }.should.raise(ArgumentError)
+ ->{ @enum.each_slice{} }.should.raise(ArgumentError)
+ ->{ @enum.each_slice(2,2){} }.should.raise(ArgumentError)
+ ->{ @enum.each_slice(0) }.should.raise(ArgumentError)
+ ->{ @enum.each_slice(-2) }.should.raise(ArgumentError)
+ ->{ @enum.each_slice }.should.raise(ArgumentError)
+ ->{ @enum.each_slice(2,2) }.should.raise(ArgumentError)
end
it "tries to convert n to an Integer using #to_int" do
@@ -53,7 +53,7 @@ describe "Enumerable#each_slice" do
it "returns an enumerator if no block" do
e = @enum.each_slice(3)
- e.should be_an_instance_of(Enumerator)
+ e.should.instance_of?(Enumerator)
e.to_a.should == @sliced
end
@@ -69,7 +69,7 @@ describe "Enumerable#each_slice" do
describe "when no block is given" do
it "returns an enumerator" do
e = @enum.each_slice(3)
- e.should be_an_instance_of(Enumerator)
+ e.should.instance_of?(Enumerator)
e.to_a.should == @sliced
end
diff --git a/spec/ruby/core/enumerable/each_with_index_spec.rb b/spec/ruby/core/enumerable/each_with_index_spec.rb
index 122e88eab7..fcb2f82f84 100644
--- a/spec/ruby/core/enumerable/each_with_index_spec.rb
+++ b/spec/ruby/core/enumerable/each_with_index_spec.rb
@@ -26,19 +26,19 @@ describe "Enumerable#each_with_index" do
acc = []
res = @b.each_with_index {|a,i| acc << [a,i]}
[[2, 0], [5, 1], [3, 2], [6, 3], [1, 4], [4, 5]].should == acc
- res.should eql(@b)
+ res.should.eql?(@b)
end
it "binds splat arguments properly" do
acc = []
res = @b.each_with_index { |*b| c,d = b; acc << c; acc << d }
[2, 0, 5, 1, 3, 2, 6, 3, 1, 4, 4, 5].should == acc
- res.should eql(@b)
+ res.should.eql?(@b)
end
it "returns an enumerator if no block" do
e = @b.each_with_index
- e.should be_an_instance_of(Enumerator)
+ e.should.instance_of?(Enumerator)
e.to_a.should == [[2, 0], [5, 1], [3, 2], [6, 3], [1, 4], [4, 5]]
end
diff --git a/spec/ruby/core/enumerable/each_with_object_spec.rb b/spec/ruby/core/enumerable/each_with_object_spec.rb
index 35665e7019..1760d3b267 100644
--- a/spec/ruby/core/enumerable/each_with_object_spec.rb
+++ b/spec/ruby/core/enumerable/each_with_object_spec.rb
@@ -12,10 +12,10 @@ describe "Enumerable#each_with_object" do
it "passes each element and its argument to the block" do
acc = []
@enum.each_with_object(@initial) do |elem, obj|
- obj.should equal(@initial)
+ obj.should.equal?(@initial)
obj = 42
acc << elem
- end.should equal(@initial)
+ end.should.equal?(@initial)
acc.should == @values
end
@@ -23,10 +23,10 @@ describe "Enumerable#each_with_object" do
acc = []
e = @enum.each_with_object(@initial)
e.each do |elem, obj|
- obj.should equal(@initial)
+ obj.should.equal?(@initial)
obj = 42
acc << elem
- end.should equal(@initial)
+ end.should.equal?(@initial)
acc.should == @values
end
diff --git a/spec/ruby/core/enumerable/entries_spec.rb b/spec/ruby/core/enumerable/entries_spec.rb
index 2de4fc756a..8cb29b7b47 100644
--- a/spec/ruby/core/enumerable/entries_spec.rb
+++ b/spec/ruby/core/enumerable/entries_spec.rb
@@ -1,7 +1,7 @@
require_relative '../../spec_helper'
-require_relative 'fixtures/classes'
-require_relative 'shared/entries'
describe "Enumerable#entries" do
- it_behaves_like :enumerable_entries, :entries
+ it "is an alias of Enumerable#to_a" do
+ Enumerable.instance_method(:entries).should == Enumerable.instance_method(:to_a)
+ end
end
diff --git a/spec/ruby/core/enumerable/filter_map_spec.rb b/spec/ruby/core/enumerable/filter_map_spec.rb
index aa4894230b..1ed131a960 100644
--- a/spec/ruby/core/enumerable/filter_map_spec.rb
+++ b/spec/ruby/core/enumerable/filter_map_spec.rb
@@ -19,6 +19,6 @@ describe 'Enumerable#filter_map' do
end
it 'returns an enumerator when no block given' do
- @numerous.filter_map.should be_an_instance_of(Enumerator)
+ @numerous.filter_map.should.instance_of?(Enumerator)
end
end
diff --git a/spec/ruby/core/enumerable/filter_spec.rb b/spec/ruby/core/enumerable/filter_spec.rb
index 1c3a7e9ff5..d075b39396 100644
--- a/spec/ruby/core/enumerable/filter_spec.rb
+++ b/spec/ruby/core/enumerable/filter_spec.rb
@@ -1,7 +1,7 @@
require_relative '../../spec_helper'
-require_relative 'fixtures/classes'
-require_relative 'shared/find_all'
describe "Enumerable#filter" do
- it_behaves_like :enumerable_find_all, :filter
+ it "is an alias of Enumerable#select" do
+ Enumerable.instance_method(:filter).should == Enumerable.instance_method(:select)
+ end
end
diff --git a/spec/ruby/core/enumerable/find_all_spec.rb b/spec/ruby/core/enumerable/find_all_spec.rb
index 9cd635f247..1095a19569 100644
--- a/spec/ruby/core/enumerable/find_all_spec.rb
+++ b/spec/ruby/core/enumerable/find_all_spec.rb
@@ -1,7 +1,7 @@
require_relative '../../spec_helper'
-require_relative 'fixtures/classes'
-require_relative 'shared/find_all'
describe "Enumerable#find_all" do
- it_behaves_like :enumerable_find_all, :find_all
+ it "is an alias of Enumerable#select" do
+ Enumerable.instance_method(:find_all).should == Enumerable.instance_method(:select)
+ end
end
diff --git a/spec/ruby/core/enumerable/find_index_spec.rb b/spec/ruby/core/enumerable/find_index_spec.rb
index 542660fe04..2e714367ba 100644
--- a/spec/ruby/core/enumerable/find_index_spec.rb
+++ b/spec/ruby/core/enumerable/find_index_spec.rb
@@ -47,7 +47,7 @@ describe "Enumerable#find_index" do
end
it "returns an Enumerator if no block given" do
- @numerous.find_index.should be_an_instance_of(Enumerator)
+ @numerous.find_index.should.instance_of?(Enumerator)
end
it "uses #== for testing equality" do
diff --git a/spec/ruby/core/enumerable/find_spec.rb b/spec/ruby/core/enumerable/find_spec.rb
index 5ddebc05f8..4ac4b75c47 100644
--- a/spec/ruby/core/enumerable/find_spec.rb
+++ b/spec/ruby/core/enumerable/find_spec.rb
@@ -1,7 +1,78 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
-require_relative 'shared/find'
+require_relative 'shared/enumerable_enumeratorized'
describe "Enumerable#find" do
- it_behaves_like :enumerable_find, :find
+ before :each do
+ ScratchPad.record []
+ @elements = [2, 4, 6, 8, 10]
+ @numerous = EnumerableSpecs::Numerous.new(*@elements)
+ @empty = []
+ end
+
+ it "passes each entry in enum to block while block when block is false" do
+ visited_elements = []
+ @numerous.find do |element|
+ visited_elements << element
+ false
+ end
+ visited_elements.should == @elements
+ end
+
+ it "returns nil when the block is false and there is no ifnone proc given" do
+ @numerous.find {|e| false }.should == nil
+ end
+
+ it "returns the first element for which the block is not false" do
+ @elements.each do |element|
+ @numerous.find {|e| e > element - 1 }.should == element
+ end
+ end
+
+ it "returns the value of the ifnone proc if the block is false" do
+ fail_proc = -> { "cheeseburgers" }
+ @numerous.find(fail_proc) {|e| false }.should == "cheeseburgers"
+ end
+
+ it "doesn't call the ifnone proc if an element is found" do
+ fail_proc = -> { raise "This shouldn't have been called" }
+ @numerous.find(fail_proc) {|e| e == @elements.first }.should == 2
+ end
+
+ it "calls the ifnone proc only once when the block is false" do
+ times = 0
+ fail_proc = -> { times += 1; raise if times > 1; "cheeseburgers" }
+ @numerous.find(fail_proc) {|e| false }.should == "cheeseburgers"
+ end
+
+ it "calls the ifnone proc when there are no elements" do
+ fail_proc = -> { "yay" }
+ @empty.find(fail_proc) {|e| true}.should == "yay"
+ end
+
+ it "ignores the ifnone argument when nil" do
+ @numerous.find(nil) {|e| false }.should == nil
+ end
+
+ it "passes through the values yielded by #each_with_index" do
+ [:a, :b].each_with_index.find { |x, i| ScratchPad << [x, i]; nil }
+ ScratchPad.recorded.should == [[:a, 0], [:b, 1]]
+ end
+
+ it "returns an enumerator when no block given" do
+ @numerous.find.should.instance_of?(Enumerator)
+ end
+
+ it "passes the ifnone proc to the enumerator" do
+ times = 0
+ fail_proc = -> { times += 1; raise if times > 1; "cheeseburgers" }
+ @numerous.find(fail_proc).each {|e| false }.should == "cheeseburgers"
+ end
+
+ it "gathers whole arrays as elements when each yields multiple" do
+ multi = EnumerableSpecs::YieldsMulti.new
+ multi.find {|e| e == [1, 2] }.should == [1, 2]
+ end
+
+ it_behaves_like :enumerable_enumeratorized_with_unknown_size, :find
end
diff --git a/spec/ruby/core/enumerable/first_spec.rb b/spec/ruby/core/enumerable/first_spec.rb
index ed1ba599b4..592dff1ebc 100644
--- a/spec/ruby/core/enumerable/first_spec.rb
+++ b/spec/ruby/core/enumerable/first_spec.rb
@@ -19,7 +19,7 @@ describe "Enumerable#first" do
it "raises a RangeError when passed a Bignum" do
enum = EnumerableSpecs::Empty.new
- -> { enum.first(bignum_value) }.should raise_error(RangeError)
+ -> { enum.first(bignum_value) }.should.raise(RangeError)
end
describe "when passed an argument" do
diff --git a/spec/ruby/core/enumerable/flat_map_spec.rb b/spec/ruby/core/enumerable/flat_map_spec.rb
index bd07eab6c5..ef50cb2696 100644
--- a/spec/ruby/core/enumerable/flat_map_spec.rb
+++ b/spec/ruby/core/enumerable/flat_map_spec.rb
@@ -1,7 +1,56 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
-require_relative 'shared/collect_concat'
+require_relative 'shared/enumerable_enumeratorized'
describe "Enumerable#flat_map" do
- it_behaves_like :enumerable_collect_concat, :flat_map
+ it "yields elements to the block and flattens one level" do
+ numerous = EnumerableSpecs::Numerous.new(1, [2, 3], [4, [5, 6]], {foo: :bar})
+ numerous.flat_map { |i| i }.should == [1, 2, 3, 4, [5, 6], {foo: :bar}]
+ end
+
+ it "appends non-Array elements that do not define #to_ary" do
+ obj = mock("to_ary undefined")
+
+ numerous = EnumerableSpecs::Numerous.new(1, obj, 2)
+ numerous.flat_map { |i| i }.should == [1, obj, 2]
+ end
+
+ it "concatenates the result of calling #to_ary if it returns an Array" do
+ obj = mock("to_ary defined")
+ obj.should_receive(:to_ary).and_return([:a, :b])
+
+ numerous = EnumerableSpecs::Numerous.new(1, obj, 2)
+ numerous.flat_map { |i| i }.should == [1, :a, :b, 2]
+ end
+
+ it "does not call #to_a" do
+ obj = mock("to_ary undefined")
+ obj.should_not_receive(:to_a)
+
+ numerous = EnumerableSpecs::Numerous.new(1, obj, 2)
+ numerous.flat_map { |i| i }.should == [1, obj, 2]
+ end
+
+ it "appends an element that defines #to_ary that returns nil" do
+ obj = mock("to_ary defined")
+ obj.should_receive(:to_ary).and_return(nil)
+
+ numerous = EnumerableSpecs::Numerous.new(1, obj, 2)
+ numerous.flat_map { |i| i }.should == [1, obj, 2]
+ end
+
+ it "raises a TypeError if an element defining #to_ary does not return an Array or nil" do
+ obj = mock("to_ary defined")
+ obj.should_receive(:to_ary).and_return("array")
+
+ -> { [1, obj, 3].flat_map { |i| i } }.should.raise(TypeError)
+ end
+
+ it "returns an enumerator when no block given" do
+ enum = EnumerableSpecs::Numerous.new(1, 2).flat_map
+ enum.should.instance_of?(Enumerator)
+ enum.each{ |i| [i] * i }.should == [1, 2, 2]
+ end
+
+ it_behaves_like :enumerable_enumeratorized_with_origin_size, :flat_map
end
diff --git a/spec/ruby/core/enumerable/grep_spec.rb b/spec/ruby/core/enumerable/grep_spec.rb
index 989358f01b..965e183766 100644
--- a/spec/ruby/core/enumerable/grep_spec.rb
+++ b/spec/ruby/core/enumerable/grep_spec.rb
@@ -81,7 +81,7 @@ describe "Enumerable#grep" do
end
it "raises an ArgumentError when not given a pattern" do
- -> { @numerous.grep { |e| e } }.should raise_error(ArgumentError)
+ -> { @numerous.grep { |e| e } }.should.raise(ArgumentError)
end
end
end
diff --git a/spec/ruby/core/enumerable/grep_v_spec.rb b/spec/ruby/core/enumerable/grep_v_spec.rb
index ba19216968..ee99a77ac1 100644
--- a/spec/ruby/core/enumerable/grep_v_spec.rb
+++ b/spec/ruby/core/enumerable/grep_v_spec.rb
@@ -55,7 +55,7 @@ describe "Enumerable#grep_v" do
end
it "raises an ArgumentError when not given a pattern" do
- -> { @numerous.grep_v }.should raise_error(ArgumentError)
+ -> { @numerous.grep_v }.should.raise(ArgumentError)
end
end
@@ -70,7 +70,7 @@ describe "Enumerable#grep_v" do
end
it "raises an ArgumentError when not given a pattern" do
- -> { @numerous.grep_v { |e| e } }.should raise_error(ArgumentError)
+ -> { @numerous.grep_v { |e| e } }.should.raise(ArgumentError)
end
end
end
diff --git a/spec/ruby/core/enumerable/group_by_spec.rb b/spec/ruby/core/enumerable/group_by_spec.rb
index 4fd1603819..904e5d6c68 100644
--- a/spec/ruby/core/enumerable/group_by_spec.rb
+++ b/spec/ruby/core/enumerable/group_by_spec.rb
@@ -16,13 +16,13 @@ describe "Enumerable#group_by" do
it "returns a hash without default_proc" do
e = EnumerableSpecs::Numerous.new("foo", "bar", "baz")
h = e.group_by { |word| word[0..0].to_sym }
- h[:some].should be_nil
- h.default_proc.should be_nil
- h.default.should be_nil
+ h[:some].should == nil
+ h.default_proc.should == nil
+ h.default.should == nil
end
it "returns an Enumerator if called without a block" do
- EnumerableSpecs::Numerous.new.group_by.should be_an_instance_of(Enumerator)
+ EnumerableSpecs::Numerous.new.group_by.should.instance_of?(Enumerator)
end
it "gathers whole arrays as elements when each yields multiple" do
diff --git a/spec/ruby/core/enumerable/include_spec.rb b/spec/ruby/core/enumerable/include_spec.rb
index dab1b04451..d59b351486 100644
--- a/spec/ruby/core/enumerable/include_spec.rb
+++ b/spec/ruby/core/enumerable/include_spec.rb
@@ -1,7 +1,36 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
-require_relative 'shared/include'
describe "Enumerable#include?" do
- it_behaves_like :enumerable_include, :include?
+ it "returns true if any element == argument for numbers" do
+ class EnumerableSpecIncludeP; def ==(obj) obj == 5; end; end
+
+ elements = (0..5).to_a
+ EnumerableSpecs::Numerous.new(*elements).include?(5).should == true
+ EnumerableSpecs::Numerous.new(*elements).include?(10).should == false
+ EnumerableSpecs::Numerous.new(*elements).include?(EnumerableSpecIncludeP.new).should == true
+ end
+
+ it "returns true if any element == argument for other objects" do
+ class EnumerableSpecIncludeP11; def ==(obj); obj == '11'; end; end
+
+ elements = ('0'..'5').to_a + [EnumerableSpecIncludeP11.new]
+ EnumerableSpecs::Numerous.new(*elements).include?('5').should == true
+ EnumerableSpecs::Numerous.new(*elements).include?('10').should == false
+ EnumerableSpecs::Numerous.new(*elements).include?(EnumerableSpecIncludeP11.new).should == true
+ EnumerableSpecs::Numerous.new(*elements).include?('11').should == true
+ end
+
+
+ it "returns true if any member of enum equals obj when == compare different classes (legacy rubycon)" do
+ # equality is tested with ==
+ EnumerableSpecs::Numerous.new(2,4,6,8,10).include?(2.0).should == true
+ EnumerableSpecs::Numerous.new(2,4,[6,8],10).include?([6, 8]).should == true
+ EnumerableSpecs::Numerous.new(2,4,[6,8],10).include?([6.0, 8.0]).should == true
+ end
+
+ it "gathers whole arrays as elements when each yields multiple" do
+ multi = EnumerableSpecs::YieldsMulti.new
+ multi.include?([1,2]).should == true
+ end
end
diff --git a/spec/ruby/core/enumerable/inject_spec.rb b/spec/ruby/core/enumerable/inject_spec.rb
index e1fe216144..10de321395 100644
--- a/spec/ruby/core/enumerable/inject_spec.rb
+++ b/spec/ruby/core/enumerable/inject_spec.rb
@@ -1,7 +1,144 @@
require_relative '../../spec_helper'
+require_relative '../array/shared/iterable_and_tolerating_size_increasing'
require_relative 'fixtures/classes'
-require_relative 'shared/inject'
describe "Enumerable#inject" do
- it_behaves_like :enumerable_inject, :inject
+ 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 = []
+ EnumerableSpecs::Numerous.new.inject(0) { |memo, i| a << [memo, i]; i }
+ a.should == [[0, 2], [2, 5], [5, 3], [3, 6], [6, 1], [1, 4]]
+ EnumerableSpecs::EachDefiner.new(true, true, true).inject(nil) {|result, i| i && result}.should == nil
+ end
+
+ it "produces an array of the accumulator and the argument when given a block with a *arg" do
+ a = []
+ [1,2].inject(0) {|*args| a << args; args[0] + args[1]}
+ a.should == [[0, 1], [1, 2]]
+ end
+
+ it "can take two argument" do
+ EnumerableSpecs::Numerous.new(1, 2, 3).inject(10, :-).should == 4
+ EnumerableSpecs::Numerous.new(1, 2, 3).inject(10, "-").should == 4
+
+ [1, 2, 3].inject(10, :-).should == 4
+ [1, 2, 3].inject(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).inject(10, name).should == 4
+ [1, 2, 3].inject(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).inject(10, Object.new) }.should.raise(TypeError, /is not a symbol nor a string/)
+ -> { [1, 2, 3].inject(10, Object.new) }.should.raise(TypeError, /is not a symbol nor a string/)
+ end
+
+ it "ignores the block if two arguments" do
+ -> {
+ EnumerableSpecs::Numerous.new(1, 2, 3).inject(10, :-) { raise "we never get here"}.should == 4
+ }.should complain(/#{__FILE__}:#{__LINE__-1}: warning: given block not used/, verbose: true)
+
+ -> {
+ [1, 2, 3].inject(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].inject(0, :+)
+ [1, 2].inject(:+)
+ EnumerableSpecs::Numerous.new(1, 2).inject(0, :+)
+ EnumerableSpecs::Numerous.new(1, 2).inject(:+)
+ }.should_not complain(verbose: true)
+ end
+
+ it "can take a symbol argument" do
+ EnumerableSpecs::Numerous.new(10, 1, 2, 3).inject(:-).should == 4
+ [10, 1, 2, 3].inject(:-).should == 4
+ end
+
+ it "can take a String argument" do
+ EnumerableSpecs::Numerous.new(10, 1, 2, 3).inject("-").should == 4
+ [10, 1, 2, 3].inject("-").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).inject(name).should == 4
+ [10, 1, 2, 3].inject(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).inject(Object.new) }.should.raise(TypeError, /is not a symbol nor a string/)
+ -> { [10, 1, 2, 3].inject(Object.new) }.should.raise(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
+ a = []
+ EnumerableSpecs::Numerous.new.inject { |memo, i| a << [memo, i]; i }
+ 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.inject([]) {|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
+ EnumerableSpecs::EachDefiner.new().inject(1) {|acc,x| 999 }.should == 1
+ EnumerableSpecs::EachDefiner.new(2).inject(1) {|acc,x| 999 }.should == 999
+ EnumerableSpecs::EachDefiner.new(2).inject(1) {|acc,x| acc }.should == 1
+ EnumerableSpecs::EachDefiner.new(2).inject(1) {|acc,x| x }.should == 2
+
+ EnumerableSpecs::EachDefiner.new(1,2,3,4).inject(100) {|acc,x| acc + x }.should == 110
+ EnumerableSpecs::EachDefiner.new(1,2,3,4).inject(100) {|acc,x| acc * x }.should == 2400
+
+ EnumerableSpecs::EachDefiner.new('a','b','c').inject("z") {|result, i| i+result}.should == "cbaz"
+ end
+
+ it "without inject arguments(legacy rubycon)" do
+ # no inject argument
+ EnumerableSpecs::EachDefiner.new(2).inject {|acc,x| 999 }.should == 2
+ EnumerableSpecs::EachDefiner.new(2).inject {|acc,x| acc }.should == 2
+ EnumerableSpecs::EachDefiner.new(2).inject {|acc,x| x }.should == 2
+
+ EnumerableSpecs::EachDefiner.new(1,2,3,4).inject {|acc,x| acc + x }.should == 10
+ EnumerableSpecs::EachDefiner.new(1,2,3,4).inject {|acc,x| acc * x }.should == 24
+
+ EnumerableSpecs::EachDefiner.new('a','b','c').inject {|result, i| i+result}.should == "cba"
+ EnumerableSpecs::EachDefiner.new(3, 4, 5).inject {|result, i| result*i}.should == 60
+ EnumerableSpecs::EachDefiner.new([1], 2, 'a','b').inject {|r,i| r<<i}.should == [1, 2, 'a', 'b']
+ end
+
+ it "returns nil when fails(legacy rubycon)" do
+ EnumerableSpecs::EachDefiner.new().inject {|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.inject(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
+
+ it "raises an ArgumentError when no parameters or block is given" do
+ -> { [1,2].inject }.should.raise(ArgumentError)
+ -> { {one: 1, two: 2}.inject }.should.raise(ArgumentError)
+ end
end
diff --git a/spec/ruby/core/enumerable/lazy_spec.rb b/spec/ruby/core/enumerable/lazy_spec.rb
index 9a9ead81a0..935e574067 100644
--- a/spec/ruby/core/enumerable/lazy_spec.rb
+++ b/spec/ruby/core/enumerable/lazy_spec.rb
@@ -5,6 +5,6 @@ require_relative 'fixtures/classes'
describe "Enumerable#lazy" do
it "returns an instance of Enumerator::Lazy" do
- EnumerableSpecs::Numerous.new.lazy.should be_an_instance_of(Enumerator::Lazy)
+ EnumerableSpecs::Numerous.new.lazy.should.instance_of?(Enumerator::Lazy)
end
end
diff --git a/spec/ruby/core/enumerable/map_spec.rb b/spec/ruby/core/enumerable/map_spec.rb
index 98a70781cf..e6447f5c23 100644
--- a/spec/ruby/core/enumerable/map_spec.rb
+++ b/spec/ruby/core/enumerable/map_spec.rb
@@ -1,7 +1,109 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
-require_relative 'shared/collect'
+require_relative 'shared/enumerable_enumeratorized'
describe "Enumerable#map" do
- it_behaves_like :enumerable_collect, :map
+ before :each do
+ ScratchPad.record []
+ end
+
+ it "returns a new array with the results of passing each element to block" do
+ entries = [0, 1, 3, 4, 5, 6]
+ numerous = EnumerableSpecs::Numerous.new(*entries)
+ numerous.map { |i| i % 2 }.should == [0, 1, 1, 0, 1, 0]
+ numerous.map { |i| i }.should == entries
+ end
+
+ it "passes through the values yielded by #each_with_index" do
+ [:a, :b].each_with_index.map { |x, i| ScratchPad << [x, i]; nil }
+ ScratchPad.recorded.should == [[:a, 0], [:b, 1]]
+ end
+
+ it "gathers initial args as elements when each yields multiple" do
+ multi = EnumerableSpecs::YieldsMulti.new
+ multi.map {|e| e}.should == [1,3,6]
+ end
+
+ it "only yields increasing values for a Range" do
+ (1..0).map { |x| x }.should == []
+ (1..1).map { |x| x }.should == [1]
+ (1..2).map { |x| x }.should == [1, 2]
+ end
+
+ it "returns an enumerator when no block given" do
+ enum = EnumerableSpecs::Numerous.new.map
+ enum.should.instance_of?(Enumerator)
+ enum.each { |i| -i }.should == [-2, -5, -3, -6, -1, -4]
+ end
+
+ it "reports the same arity as the given block" do
+ entries = [0, 1, 3, 4, 5, 6]
+ numerous = EnumerableSpecs::Numerous.new(*entries)
+
+ def numerous.each(&block)
+ ScratchPad << block.arity
+ super
+ end
+
+ numerous.map { |a, b| a % 2 }.should == [0, 1, 1, 0, 1, 0]
+ ScratchPad.recorded.should == [2]
+ ScratchPad.clear
+ ScratchPad.record []
+ numerous.map { |i| i }.should == entries
+ ScratchPad.recorded.should == [1]
+ end
+
+ it "yields an Array of 2 elements for a Hash when block arity is 1" do
+ c = Class.new do
+ def register(a)
+ ScratchPad << a
+ end
+ end
+ m = c.new.method(:register)
+
+ ScratchPad.record []
+ { 1 => 'a', 2 => 'b' }.map(&m)
+ ScratchPad.recorded.should == [[1, 'a'], [2, 'b']]
+ end
+
+ it "yields 2 arguments for a Hash when block arity is 2" do
+ c = Class.new do
+ def register(a, b)
+ ScratchPad << [a, b]
+ end
+ end
+ m = c.new.method(:register)
+
+ ScratchPad.record []
+ { 1 => 'a', 2 => 'b' }.map(&m)
+ ScratchPad.recorded.should == [[1, 'a'], [2, 'b']]
+ end
+
+ it "raises an error for a Hash when an arity enforcing block of arity >2 is passed in" do
+ c = Class.new do
+ def register(a, b, c)
+ end
+ end
+ m = c.new.method(:register)
+
+ -> do
+ { 1 => 'a', 2 => 'b' }.map(&m)
+ end.should.raise(ArgumentError)
+ end
+
+ it "calls the each method on sub-classes" do
+ c = Class.new(Hash) do
+ def each
+ ScratchPad << 'in each'
+ super
+ end
+ end
+ h = c.new
+ h[1] = 'a'
+ ScratchPad.record []
+ h.map { |k,v| v }
+ ScratchPad.recorded.should == ['in each']
+ end
+
+ it_behaves_like :enumerable_enumeratorized_with_origin_size, :map
end
diff --git a/spec/ruby/core/enumerable/max_by_spec.rb b/spec/ruby/core/enumerable/max_by_spec.rb
index ec1738ea3b..f67b5d15ea 100644
--- a/spec/ruby/core/enumerable/max_by_spec.rb
+++ b/spec/ruby/core/enumerable/max_by_spec.rb
@@ -4,7 +4,7 @@ require_relative 'shared/enumerable_enumeratorized'
describe "Enumerable#max_by" do
it "returns an enumerator if no block" do
- EnumerableSpecs::Numerous.new(42).max_by.should be_an_instance_of(Enumerator)
+ EnumerableSpecs::Numerous.new(42).max_by.should.instance_of?(Enumerator)
end
it "returns nil if #each yields no objects" do
@@ -18,7 +18,7 @@ describe "Enumerable#max_by" do
it "returns the object that appears first in #each in case of a tie" do
a, b, c = '1', '2', '2'
- EnumerableSpecs::Numerous.new(a, b, c).max_by {|obj| obj.to_i }.should equal(b)
+ EnumerableSpecs::Numerous.new(a, b, c).max_by {|obj| obj.to_i }.should.equal?(b)
end
it "uses max.<=>(current) to determine order" do
@@ -48,7 +48,7 @@ describe "Enumerable#max_by" do
context "without a block" do
it "returns an enumerator" do
- @enum.max_by(2).should be_an_instance_of(Enumerator)
+ @enum.max_by(2).should.instance_of?(Enumerator)
end
end
@@ -67,7 +67,7 @@ describe "Enumerable#max_by" do
context "when n is negative" do
it "raises an ArgumentError" do
- -> { @enum.max_by(-1) { |i| i.to_s } }.should raise_error(ArgumentError)
+ -> { @enum.max_by(-1) { |i| i.to_s } }.should.raise(ArgumentError)
end
end
end
diff --git a/spec/ruby/core/enumerable/max_spec.rb b/spec/ruby/core/enumerable/max_spec.rb
index 0c11ca0969..d92700258b 100644
--- a/spec/ruby/core/enumerable/max_spec.rb
+++ b/spec/ruby/core/enumerable/max_spec.rb
@@ -38,16 +38,16 @@ describe "Enumerable#max" do
it "raises a NoMethodError for elements without #<=>" do
-> do
EnumerableSpecs::EachDefiner.new(BasicObject.new, BasicObject.new).max
- end.should raise_error(NoMethodError)
+ end.should.raise(NoMethodError)
end
it "raises an ArgumentError for incomparable elements" do
-> do
EnumerableSpecs::EachDefiner.new(11,"22").max
- end.should raise_error(ArgumentError)
+ end.should.raise(ArgumentError)
-> do
EnumerableSpecs::EachDefiner.new(11,12,22,33).max{|a, b| nil}
- end.should raise_error(ArgumentError)
+ end.should.raise(ArgumentError)
end
context "when passed a block" do
@@ -106,7 +106,7 @@ describe "Enumerable#max" do
context "that is negative" do
it "raises an ArgumentError" do
- -> { @e_ints.max(-1) }.should raise_error(ArgumentError)
+ -> { @e_ints.max(-1) }.should.raise(ArgumentError)
end
end
end
diff --git a/spec/ruby/core/enumerable/member_spec.rb b/spec/ruby/core/enumerable/member_spec.rb
index 1fe3cebd28..be06880ebb 100644
--- a/spec/ruby/core/enumerable/member_spec.rb
+++ b/spec/ruby/core/enumerable/member_spec.rb
@@ -1,7 +1,7 @@
require_relative '../../spec_helper'
-require_relative 'fixtures/classes'
-require_relative 'shared/include'
describe "Enumerable#member?" do
- it_behaves_like :enumerable_include, :member?
+ it "is an alias of Enumerable#include?" do
+ Enumerable.instance_method(:member?).should == Enumerable.instance_method(:include?)
+ end
end
diff --git a/spec/ruby/core/enumerable/min_by_spec.rb b/spec/ruby/core/enumerable/min_by_spec.rb
index 3ff87e49d8..4f949e2130 100644
--- a/spec/ruby/core/enumerable/min_by_spec.rb
+++ b/spec/ruby/core/enumerable/min_by_spec.rb
@@ -4,7 +4,7 @@ require_relative 'shared/enumerable_enumeratorized'
describe "Enumerable#min_by" do
it "returns an enumerator if no block" do
- EnumerableSpecs::Numerous.new(42).min_by.should be_an_instance_of(Enumerator)
+ EnumerableSpecs::Numerous.new(42).min_by.should.instance_of?(Enumerator)
end
it "returns nil if #each yields no objects" do
@@ -18,7 +18,7 @@ describe "Enumerable#min_by" do
it "returns the object that appears first in #each in case of a tie" do
a, b, c = '2', '1', '1'
- EnumerableSpecs::Numerous.new(a, b, c).min_by {|obj| obj.to_i }.should equal(b)
+ EnumerableSpecs::Numerous.new(a, b, c).min_by {|obj| obj.to_i }.should.equal?(b)
end
it "uses min.<=>(current) to determine order" do
@@ -48,7 +48,7 @@ describe "Enumerable#min_by" do
context "without a block" do
it "returns an enumerator" do
- @enum.min_by(2).should be_an_instance_of(Enumerator)
+ @enum.min_by(2).should.instance_of?(Enumerator)
end
end
@@ -67,7 +67,7 @@ describe "Enumerable#min_by" do
context "when n is negative" do
it "raises an ArgumentError" do
- -> { @enum.min_by(-1) { |i| i.to_s } }.should raise_error(ArgumentError)
+ -> { @enum.min_by(-1) { |i| i.to_s } }.should.raise(ArgumentError)
end
end
end
diff --git a/spec/ruby/core/enumerable/min_spec.rb b/spec/ruby/core/enumerable/min_spec.rb
index 4b6ae248fa..f05d59c2c9 100644
--- a/spec/ruby/core/enumerable/min_spec.rb
+++ b/spec/ruby/core/enumerable/min_spec.rb
@@ -32,22 +32,22 @@ describe "Enumerable#min" do
end
it "returns nil for an empty Enumerable" do
- EnumerableSpecs::EachDefiner.new.min.should be_nil
+ EnumerableSpecs::EachDefiner.new.min.should == nil
end
it "raises a NoMethodError for elements without #<=>" do
-> do
EnumerableSpecs::EachDefiner.new(BasicObject.new, BasicObject.new).min
- end.should raise_error(NoMethodError)
+ end.should.raise(NoMethodError)
end
it "raises an ArgumentError for incomparable elements" do
-> do
EnumerableSpecs::EachDefiner.new(11,"22").min
- end.should raise_error(ArgumentError)
+ end.should.raise(ArgumentError)
-> do
EnumerableSpecs::EachDefiner.new(11,12,22,33).min{|a, b| nil}
- end.should raise_error(ArgumentError)
+ end.should.raise(ArgumentError)
end
it "returns the minimum when using a block rule" do
@@ -110,7 +110,7 @@ describe "Enumerable#min" do
context "that is negative" do
it "raises an ArgumentError" do
- -> { @e_ints.min(-1) }.should raise_error(ArgumentError)
+ -> { @e_ints.min(-1) }.should.raise(ArgumentError)
end
end
end
diff --git a/spec/ruby/core/enumerable/minmax_by_spec.rb b/spec/ruby/core/enumerable/minmax_by_spec.rb
index a6a9249270..30c88cfcfb 100644
--- a/spec/ruby/core/enumerable/minmax_by_spec.rb
+++ b/spec/ruby/core/enumerable/minmax_by_spec.rb
@@ -4,7 +4,7 @@ require_relative 'shared/enumerable_enumeratorized'
describe "Enumerable#minmax_by" do
it "returns an enumerator if no block" do
- EnumerableSpecs::Numerous.new(42).minmax_by.should be_an_instance_of(Enumerator)
+ EnumerableSpecs::Numerous.new(42).minmax_by.should.instance_of?(Enumerator)
end
it "returns nil if #each yields no objects" do
@@ -19,8 +19,8 @@ describe "Enumerable#minmax_by" do
it "returns the object that appears first in #each in case of a tie" do
a, b, c, d = '1', '1', '2', '2'
mm = EnumerableSpecs::Numerous.new(a, b, c, d).minmax_by {|obj| obj.to_i }
- mm[0].should equal(a)
- mm[1].should equal(c)
+ mm[0].should.equal?(a)
+ mm[1].should.equal?(c)
end
it "uses min/max.<=>(current) to determine order" do
diff --git a/spec/ruby/core/enumerable/none_spec.rb b/spec/ruby/core/enumerable/none_spec.rb
index fb42f13386..d9ee0b441e 100644
--- a/spec/ruby/core/enumerable/none_spec.rb
+++ b/spec/ruby/core/enumerable/none_spec.rb
@@ -15,35 +15,35 @@ describe "Enumerable#none?" do
end
it "raises an ArgumentError when more than 1 argument is provided" do
- -> { @enum.none?(1, 2, 3) }.should raise_error(ArgumentError)
- -> { [].none?(1, 2, 3) }.should raise_error(ArgumentError)
- -> { {}.none?(1, 2, 3) }.should raise_error(ArgumentError)
+ -> { @enum.none?(1, 2, 3) }.should.raise(ArgumentError)
+ -> { [].none?(1, 2, 3) }.should.raise(ArgumentError)
+ -> { {}.none?(1, 2, 3) }.should.raise(ArgumentError)
end
it "does not hide exceptions out of #each" do
-> {
EnumerableSpecs::ThrowingEach.new.none?
- }.should raise_error(RuntimeError)
+ }.should.raise(RuntimeError)
-> {
EnumerableSpecs::ThrowingEach.new.none? { false }
- }.should raise_error(RuntimeError)
+ }.should.raise(RuntimeError)
end
describe "with no block" do
it "returns true if none of the elements in self are true" do
e = EnumerableSpecs::Numerous.new(false, nil, false)
- e.none?.should be_true
+ e.none?.should == true
end
it "returns false if at least one of the elements in self are true" do
e = EnumerableSpecs::Numerous.new(false, nil, true, false)
- e.none?.should be_false
+ e.none?.should == false
end
it "gathers whole arrays as elements when each yields multiple" do
multi = EnumerableSpecs::YieldsMultiWithFalse.new
- multi.none?.should be_false
+ multi.none?.should == false
end
end
@@ -65,17 +65,17 @@ describe "Enumerable#none?" do
end
it "returns true if the block never returns true" do
- @e.none? {|e| false }.should be_true
+ @e.none? {|e| false }.should == true
end
it "returns false if the block ever returns true" do
- @e.none? {|e| e == 3 ? true : false }.should be_false
+ @e.none? {|e| e == 3 ? true : false }.should == false
end
it "does not hide exceptions out of the block" do
-> {
@enum.none? { raise "from block" }
- }.should raise_error(RuntimeError)
+ }.should.raise(RuntimeError)
end
it "gathers initial args as elements when each yields multiple" do
@@ -94,7 +94,7 @@ describe "Enumerable#none?" do
end
describe 'when given a pattern argument' do
- it "calls `===` on the pattern the return value " do
+ it "calls `===` on the pattern the return value" do
pattern = EnumerableSpecs::Pattern.new { |x| x == 3 }
@enum1.none?(pattern).should == true
pattern.yielded.should == [[0], [1], [2], [-1]]
@@ -109,7 +109,7 @@ describe "Enumerable#none?" do
it "does not hide exceptions out of #each" do
-> {
EnumerableSpecs::ThrowingEach.new.none?(Integer)
- }.should raise_error(RuntimeError)
+ }.should.raise(RuntimeError)
end
it "returns true if the pattern never returns a truthy value" do
@@ -134,7 +134,7 @@ describe "Enumerable#none?" do
pattern = EnumerableSpecs::Pattern.new { raise "from pattern" }
-> {
@enum.none?(pattern)
- }.should raise_error(RuntimeError)
+ }.should.raise(RuntimeError)
end
it "calls the pattern with gathered array when yielded with multiple arguments" do
diff --git a/spec/ruby/core/enumerable/one_spec.rb b/spec/ruby/core/enumerable/one_spec.rb
index 4bf8623d2e..cf966d4a9b 100644
--- a/spec/ruby/core/enumerable/one_spec.rb
+++ b/spec/ruby/core/enumerable/one_spec.rb
@@ -15,57 +15,57 @@ describe "Enumerable#one?" do
end
it "raises an ArgumentError when more than 1 argument is provided" do
- -> { @enum.one?(1, 2, 3) }.should raise_error(ArgumentError)
- -> { [].one?(1, 2, 3) }.should raise_error(ArgumentError)
- -> { {}.one?(1, 2, 3) }.should raise_error(ArgumentError)
+ -> { @enum.one?(1, 2, 3) }.should.raise(ArgumentError)
+ -> { [].one?(1, 2, 3) }.should.raise(ArgumentError)
+ -> { {}.one?(1, 2, 3) }.should.raise(ArgumentError)
end
it "does not hide exceptions out of #each" do
-> {
EnumerableSpecs::ThrowingEach.new.one?
- }.should raise_error(RuntimeError)
+ }.should.raise(RuntimeError)
-> {
EnumerableSpecs::ThrowingEach.new.one? { false }
- }.should raise_error(RuntimeError)
+ }.should.raise(RuntimeError)
end
describe "with no block" do
it "returns true if only one element evaluates to true" do
- [false, nil, true].one?.should be_true
+ [false, nil, true].one?.should == true
end
it "returns false if two elements evaluate to true" do
- [false, :value, nil, true].one?.should be_false
+ [false, :value, nil, true].one?.should == false
end
it "returns false if all elements evaluate to false" do
- [false, nil, false].one?.should be_false
+ [false, nil, false].one?.should == false
end
it "gathers whole arrays as elements when each yields multiple" do
multi = EnumerableSpecs::YieldsMultiWithSingleTrue.new
- multi.one?.should be_false
+ multi.one?.should == false
end
end
describe "with a block" do
it "returns true if block returns true once" do
- [:a, :b, :c].one? { |s| s == :a }.should be_true
+ [:a, :b, :c].one? { |s| s == :a }.should == true
end
it "returns false if the block returns true more than once" do
- [:a, :b, :c].one? { |s| s == :a || s == :b }.should be_false
+ [:a, :b, :c].one? { |s| s == :a || s == :b }.should == false
end
it "returns false if the block only returns false" do
- [:a, :b, :c].one? { |s| s == :d }.should be_false
+ [:a, :b, :c].one? { |s| s == :d }.should == false
end
it "does not hide exceptions out of the block" do
-> {
@enum.one? { raise "from block" }
- }.should raise_error(RuntimeError)
+ }.should.raise(RuntimeError)
end
it "gathers initial args as elements when each yields multiple" do
@@ -84,7 +84,7 @@ describe "Enumerable#one?" do
end
describe 'when given a pattern argument' do
- it "calls `===` on the pattern the return value " do
+ it "calls `===` on the pattern the return value" do
pattern = EnumerableSpecs::Pattern.new { |x| x == 1 }
@enum1.one?(pattern).should == true
pattern.yielded.should == [[0], [1], [2], [-1]]
@@ -99,7 +99,7 @@ describe "Enumerable#one?" do
it "does not hide exceptions out of #each" do
-> {
EnumerableSpecs::ThrowingEach.new.one?(Integer)
- }.should raise_error(RuntimeError)
+ }.should.raise(RuntimeError)
end
it "returns true if the pattern returns a truthy value only once" do
@@ -135,7 +135,7 @@ describe "Enumerable#one?" do
pattern = EnumerableSpecs::Pattern.new { raise "from pattern" }
-> {
@enum.one?(pattern)
- }.should raise_error(RuntimeError)
+ }.should.raise(RuntimeError)
end
it "calls the pattern with gathered array when yielded with multiple arguments" do
diff --git a/spec/ruby/core/enumerable/partition_spec.rb b/spec/ruby/core/enumerable/partition_spec.rb
index d3d220b4b4..8272ee189e 100644
--- a/spec/ruby/core/enumerable/partition_spec.rb
+++ b/spec/ruby/core/enumerable/partition_spec.rb
@@ -8,7 +8,7 @@ describe "Enumerable#partition" do
end
it "returns an Enumerator if called without a block" do
- EnumerableSpecs::Numerous.new.partition.should be_an_instance_of(Enumerator)
+ EnumerableSpecs::Numerous.new.partition.should.instance_of?(Enumerator)
end
it "gathers whole arrays as elements when each yields multiple" do
diff --git a/spec/ruby/core/enumerable/reduce_spec.rb b/spec/ruby/core/enumerable/reduce_spec.rb
index bc8691c1b0..40452b66a1 100644
--- a/spec/ruby/core/enumerable/reduce_spec.rb
+++ b/spec/ruby/core/enumerable/reduce_spec.rb
@@ -1,7 +1,7 @@
require_relative '../../spec_helper'
-require_relative 'fixtures/classes'
-require_relative 'shared/inject'
describe "Enumerable#reduce" do
- it_behaves_like :enumerable_inject, :reduce
+ it "is an alias of Enumerable#inject" do
+ Enumerable.instance_method(:reduce).should == Enumerable.instance_method(:inject)
+ end
end
diff --git a/spec/ruby/core/enumerable/reject_spec.rb b/spec/ruby/core/enumerable/reject_spec.rb
index 0d86b49ea2..31e89f5b0e 100644
--- a/spec/ruby/core/enumerable/reject_spec.rb
+++ b/spec/ruby/core/enumerable/reject_spec.rb
@@ -13,7 +13,7 @@ describe "Enumerable#reject" do
end
it "returns an Enumerator if called without a block" do
- EnumerableSpecs::Numerous.new.reject.should be_an_instance_of(Enumerator)
+ EnumerableSpecs::Numerous.new.reject.should.instance_of?(Enumerator)
end
it "gathers whole arrays as elements when each yields multiple" do
diff --git a/spec/ruby/core/enumerable/reverse_each_spec.rb b/spec/ruby/core/enumerable/reverse_each_spec.rb
index 2b1c233488..4753956724 100644
--- a/spec/ruby/core/enumerable/reverse_each_spec.rb
+++ b/spec/ruby/core/enumerable/reverse_each_spec.rb
@@ -11,7 +11,7 @@ describe "Enumerable#reverse_each" do
it "returns an Enumerator if no block given" do
enum = EnumerableSpecs::Numerous.new.reverse_each
- enum.should be_an_instance_of(Enumerator)
+ enum.should.instance_of?(Enumerator)
enum.to_a.should == [4, 1, 6, 3, 5, 2]
end
diff --git a/spec/ruby/core/enumerable/select_spec.rb b/spec/ruby/core/enumerable/select_spec.rb
index 7fc61926f9..a53c228a44 100644
--- a/spec/ruby/core/enumerable/select_spec.rb
+++ b/spec/ruby/core/enumerable/select_spec.rb
@@ -1,7 +1,33 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
-require_relative 'shared/find_all'
+require_relative 'shared/enumerable_enumeratorized'
describe "Enumerable#select" do
- it_behaves_like :enumerable_find_all, :select
+ before :each do
+ ScratchPad.record []
+ @elements = (1..10).to_a
+ @numerous = EnumerableSpecs::Numerous.new(*@elements)
+ end
+
+ it "returns all elements for which the block is not false" do
+ @numerous.select {|i| i % 3 == 0 }.should == [3, 6, 9]
+ @numerous.select {|i| true }.should == @elements
+ @numerous.select {|i| false }.should == []
+ end
+
+ it "returns an enumerator when no block given" do
+ @numerous.select.should.instance_of?(Enumerator)
+ end
+
+ it "passes through the values yielded by #each_with_index" do
+ [:a, :b].each_with_index.select { |x, i| ScratchPad << [x, i] }
+ ScratchPad.recorded.should == [[:a, 0], [:b, 1]]
+ end
+
+ it "gathers whole arrays as elements when each yields multiple" do
+ multi = EnumerableSpecs::YieldsMulti.new
+ multi.select {|e| e == [3, 4, 5] }.should == [[3, 4, 5]]
+ end
+
+ it_behaves_like :enumerable_enumeratorized_with_origin_size, :select
end
diff --git a/spec/ruby/core/enumerable/shared/collect.rb b/spec/ruby/core/enumerable/shared/collect.rb
deleted file mode 100644
index 6df1a616eb..0000000000
--- a/spec/ruby/core/enumerable/shared/collect.rb
+++ /dev/null
@@ -1,107 +0,0 @@
-require_relative 'enumerable_enumeratorized'
-
-describe :enumerable_collect, shared: true do
- before :each do
- ScratchPad.record []
- end
-
- it "returns a new array with the results of passing each element to block" do
- entries = [0, 1, 3, 4, 5, 6]
- numerous = EnumerableSpecs::Numerous.new(*entries)
- numerous.send(@method) { |i| i % 2 }.should == [0, 1, 1, 0, 1, 0]
- numerous.send(@method) { |i| i }.should == entries
- end
-
- it "passes through the values yielded by #each_with_index" do
- [:a, :b].each_with_index.send(@method) { |x, i| ScratchPad << [x, i]; nil }
- ScratchPad.recorded.should == [[:a, 0], [:b, 1]]
- end
-
- it "gathers initial args as elements when each yields multiple" do
- multi = EnumerableSpecs::YieldsMulti.new
- multi.send(@method) {|e| e}.should == [1,3,6]
- end
-
- it "only yields increasing values for a Range" do
- (1..0).send(@method) { |x| x }.should == []
- (1..1).send(@method) { |x| x }.should == [1]
- (1..2).send(@method) { |x| x }.should == [1, 2]
- end
-
- it "returns an enumerator when no block given" do
- enum = EnumerableSpecs::Numerous.new.send(@method)
- enum.should be_an_instance_of(Enumerator)
- enum.each { |i| -i }.should == [-2, -5, -3, -6, -1, -4]
- end
-
- it "reports the same arity as the given block" do
- entries = [0, 1, 3, 4, 5, 6]
- numerous = EnumerableSpecs::Numerous.new(*entries)
-
- def numerous.each(&block)
- ScratchPad << block.arity
- super
- end
-
- numerous.send(@method) { |a, b| a % 2 }.should == [0, 1, 1, 0, 1, 0]
- ScratchPad.recorded.should == [2]
- ScratchPad.clear
- ScratchPad.record []
- numerous.send(@method) { |i| i }.should == entries
- ScratchPad.recorded.should == [1]
- end
-
- it "yields an Array of 2 elements for a Hash when block arity is 1" do
- c = Class.new do
- def register(a)
- ScratchPad << a
- end
- end
- m = c.new.method(:register)
-
- ScratchPad.record []
- { 1 => 'a', 2 => 'b' }.map(&m)
- ScratchPad.recorded.should == [[1, 'a'], [2, 'b']]
- end
-
- it "yields 2 arguments for a Hash when block arity is 2" do
- c = Class.new do
- def register(a, b)
- ScratchPad << [a, b]
- end
- end
- m = c.new.method(:register)
-
- ScratchPad.record []
- { 1 => 'a', 2 => 'b' }.map(&m)
- ScratchPad.recorded.should == [[1, 'a'], [2, 'b']]
- end
-
- it "raises an error for a Hash when an arity enforcing block of arity >2 is passed in" do
- c = Class.new do
- def register(a, b, c)
- end
- end
- m = c.new.method(:register)
-
- -> do
- { 1 => 'a', 2 => 'b' }.map(&m)
- end.should raise_error(ArgumentError)
- end
-
- it "calls the each method on sub-classes" do
- c = Class.new(Hash) do
- def each
- ScratchPad << 'in each'
- super
- end
- end
- h = c.new
- h[1] = 'a'
- ScratchPad.record []
- h.send(@method) { |k,v| v }
- ScratchPad.recorded.should == ['in each']
- end
-
- it_should_behave_like :enumerable_enumeratorized_with_origin_size
-end
diff --git a/spec/ruby/core/enumerable/shared/collect_concat.rb b/spec/ruby/core/enumerable/shared/collect_concat.rb
deleted file mode 100644
index ddd431baeb..0000000000
--- a/spec/ruby/core/enumerable/shared/collect_concat.rb
+++ /dev/null
@@ -1,54 +0,0 @@
-require_relative 'enumerable_enumeratorized'
-
-describe :enumerable_collect_concat, shared: true do
- it "yields elements to the block and flattens one level" do
- numerous = EnumerableSpecs::Numerous.new(1, [2, 3], [4, [5, 6]], {foo: :bar})
- numerous.send(@method) { |i| i }.should == [1, 2, 3, 4, [5, 6], {foo: :bar}]
- end
-
- it "appends non-Array elements that do not define #to_ary" do
- obj = mock("to_ary undefined")
-
- numerous = EnumerableSpecs::Numerous.new(1, obj, 2)
- numerous.send(@method) { |i| i }.should == [1, obj, 2]
- end
-
- it "concatenates the result of calling #to_ary if it returns an Array" do
- obj = mock("to_ary defined")
- obj.should_receive(:to_ary).and_return([:a, :b])
-
- numerous = EnumerableSpecs::Numerous.new(1, obj, 2)
- numerous.send(@method) { |i| i }.should == [1, :a, :b, 2]
- end
-
- it "does not call #to_a" do
- obj = mock("to_ary undefined")
- obj.should_not_receive(:to_a)
-
- numerous = EnumerableSpecs::Numerous.new(1, obj, 2)
- numerous.send(@method) { |i| i }.should == [1, obj, 2]
- end
-
- it "appends an element that defines #to_ary that returns nil" do
- obj = mock("to_ary defined")
- obj.should_receive(:to_ary).and_return(nil)
-
- numerous = EnumerableSpecs::Numerous.new(1, obj, 2)
- numerous.send(@method) { |i| i }.should == [1, obj, 2]
- end
-
- it "raises a TypeError if an element defining #to_ary does not return an Array or nil" do
- obj = mock("to_ary defined")
- obj.should_receive(:to_ary).and_return("array")
-
- -> { [1, obj, 3].send(@method) { |i| i } }.should raise_error(TypeError)
- end
-
- it "returns an enumerator when no block given" do
- enum = EnumerableSpecs::Numerous.new(1, 2).send(@method)
- enum.should be_an_instance_of(Enumerator)
- enum.each{ |i| [i] * i }.should == [1, 2, 2]
- end
-
- it_should_behave_like :enumerable_enumeratorized_with_origin_size
-end
diff --git a/spec/ruby/core/enumerable/shared/entries.rb b/spec/ruby/core/enumerable/shared/entries.rb
deleted file mode 100644
index e32eb23d2a..0000000000
--- a/spec/ruby/core/enumerable/shared/entries.rb
+++ /dev/null
@@ -1,16 +0,0 @@
-describe :enumerable_entries, shared: true do
- it "returns an array containing the elements" do
- numerous = EnumerableSpecs::Numerous.new(1, nil, 'a', 2, false, true)
- numerous.send(@method).should == [1, nil, "a", 2, false, true]
- end
-
- it "passes through the values yielded by #each_with_index" do
- [:a, :b].each_with_index.send(@method).should == [[:a, 0], [:b, 1]]
- end
-
- it "passes arguments to each" do
- count = EnumerableSpecs::EachCounter.new(1, 2, 3)
- count.send(@method, :hello, "world").should == [1, 2, 3]
- count.arguments_passed.should == [:hello, "world"]
- end
-end
diff --git a/spec/ruby/core/enumerable/shared/find.rb b/spec/ruby/core/enumerable/shared/find.rb
deleted file mode 100644
index 61d63ba3d5..0000000000
--- a/spec/ruby/core/enumerable/shared/find.rb
+++ /dev/null
@@ -1,77 +0,0 @@
-require_relative 'enumerable_enumeratorized'
-
-describe :enumerable_find, shared: true do
- # #detect and #find are aliases, so we only need one function
- before :each do
- ScratchPad.record []
- @elements = [2, 4, 6, 8, 10]
- @numerous = EnumerableSpecs::Numerous.new(*@elements)
- @empty = []
- end
-
- it "passes each entry in enum to block while block when block is false" do
- visited_elements = []
- @numerous.send(@method) do |element|
- visited_elements << element
- false
- end
- visited_elements.should == @elements
- end
-
- it "returns nil when the block is false and there is no ifnone proc given" do
- @numerous.send(@method) {|e| false }.should == nil
- end
-
- it "returns the first element for which the block is not false" do
- @elements.each do |element|
- @numerous.send(@method) {|e| e > element - 1 }.should == element
- end
- end
-
- it "returns the value of the ifnone proc if the block is false" do
- fail_proc = -> { "cheeseburgers" }
- @numerous.send(@method, fail_proc) {|e| false }.should == "cheeseburgers"
- end
-
- it "doesn't call the ifnone proc if an element is found" do
- fail_proc = -> { raise "This shouldn't have been called" }
- @numerous.send(@method, fail_proc) {|e| e == @elements.first }.should == 2
- end
-
- it "calls the ifnone proc only once when the block is false" do
- times = 0
- fail_proc = -> { times += 1; raise if times > 1; "cheeseburgers" }
- @numerous.send(@method, fail_proc) {|e| false }.should == "cheeseburgers"
- end
-
- it "calls the ifnone proc when there are no elements" do
- fail_proc = -> { "yay" }
- @empty.send(@method, fail_proc) {|e| true}.should == "yay"
- end
-
- it "ignores the ifnone argument when nil" do
- @numerous.send(@method, nil) {|e| false }.should == nil
- end
-
- it "passes through the values yielded by #each_with_index" do
- [:a, :b].each_with_index.send(@method) { |x, i| ScratchPad << [x, i]; nil }
- ScratchPad.recorded.should == [[:a, 0], [:b, 1]]
- end
-
- it "returns an enumerator when no block given" do
- @numerous.send(@method).should be_an_instance_of(Enumerator)
- end
-
- it "passes the ifnone proc to the enumerator" do
- times = 0
- fail_proc = -> { times += 1; raise if times > 1; "cheeseburgers" }
- @numerous.send(@method, fail_proc).each {|e| false }.should == "cheeseburgers"
- end
-
- it "gathers whole arrays as elements when each yields multiple" do
- multi = EnumerableSpecs::YieldsMulti.new
- multi.send(@method) {|e| e == [1, 2] }.should == [1, 2]
- end
-
- it_should_behave_like :enumerable_enumeratorized_with_unknown_size
-end
diff --git a/spec/ruby/core/enumerable/shared/find_all.rb b/spec/ruby/core/enumerable/shared/find_all.rb
deleted file mode 100644
index 1bbe71f372..0000000000
--- a/spec/ruby/core/enumerable/shared/find_all.rb
+++ /dev/null
@@ -1,31 +0,0 @@
-require_relative 'enumerable_enumeratorized'
-
-describe :enumerable_find_all, shared: true do
- before :each do
- ScratchPad.record []
- @elements = (1..10).to_a
- @numerous = EnumerableSpecs::Numerous.new(*@elements)
- end
-
- it "returns all elements for which the block is not false" do
- @numerous.send(@method) {|i| i % 3 == 0 }.should == [3, 6, 9]
- @numerous.send(@method) {|i| true }.should == @elements
- @numerous.send(@method) {|i| false }.should == []
- end
-
- it "returns an enumerator when no block given" do
- @numerous.send(@method).should be_an_instance_of(Enumerator)
- end
-
- it "passes through the values yielded by #each_with_index" do
- [:a, :b].each_with_index.send(@method) { |x, i| ScratchPad << [x, i] }
- ScratchPad.recorded.should == [[:a, 0], [:b, 1]]
- end
-
- it "gathers whole arrays as elements when each yields multiple" do
- multi = EnumerableSpecs::YieldsMulti.new
- multi.send(@method) {|e| e == [3, 4, 5] }.should == [[3, 4, 5]]
- end
-
- it_should_behave_like :enumerable_enumeratorized_with_origin_size
-end
diff --git a/spec/ruby/core/enumerable/shared/include.rb b/spec/ruby/core/enumerable/shared/include.rb
deleted file mode 100644
index 569f350fd5..0000000000
--- a/spec/ruby/core/enumerable/shared/include.rb
+++ /dev/null
@@ -1,34 +0,0 @@
-describe :enumerable_include, shared: true do
- it "returns true if any element == argument for numbers" do
- class EnumerableSpecIncludeP; def ==(obj) obj == 5; end; end
-
- elements = (0..5).to_a
- EnumerableSpecs::Numerous.new(*elements).send(@method,5).should == true
- EnumerableSpecs::Numerous.new(*elements).send(@method,10).should == false
- EnumerableSpecs::Numerous.new(*elements).send(@method,EnumerableSpecIncludeP.new).should == true
- end
-
- it "returns true if any element == argument for other objects" do
- class EnumerableSpecIncludeP11; def ==(obj); obj == '11'; end; end
-
- elements = ('0'..'5').to_a + [EnumerableSpecIncludeP11.new]
- EnumerableSpecs::Numerous.new(*elements).send(@method,'5').should == true
- EnumerableSpecs::Numerous.new(*elements).send(@method,'10').should == false
- EnumerableSpecs::Numerous.new(*elements).send(@method,EnumerableSpecIncludeP11.new).should == true
- EnumerableSpecs::Numerous.new(*elements).send(@method,'11').should == true
- end
-
-
- it "returns true if any member of enum equals obj when == compare different classes (legacy rubycon)" do
- # equality is tested with ==
- EnumerableSpecs::Numerous.new(2,4,6,8,10).send(@method, 2.0).should == true
- EnumerableSpecs::Numerous.new(2,4,[6,8],10).send(@method, [6, 8]).should == true
- EnumerableSpecs::Numerous.new(2,4,[6,8],10).send(@method, [6.0, 8.0]).should == true
- end
-
- it "gathers whole arrays as elements when each yields multiple" do
- multi = EnumerableSpecs::YieldsMulti.new
- multi.send(@method, [1,2]).should be_true
- end
-
-end
diff --git a/spec/ruby/core/enumerable/shared/inject.rb b/spec/ruby/core/enumerable/shared/inject.rb
deleted file mode 100644
index aae9e06c97..0000000000
--- a/spec/ruby/core/enumerable/shared/inject.rb
+++ /dev/null
@@ -1,142 +0,0 @@
-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 = []
- EnumerableSpecs::Numerous.new.send(@method, 0) { |memo, i| a << [memo, i]; i }
- a.should == [[0, 2], [2, 5], [5, 3], [3, 6], [6, 1], [1, 4]]
- EnumerableSpecs::EachDefiner.new(true, true, true).send(@method, nil) {|result, i| i && result}.should == nil
- end
-
- it "produces an array of the accumulator and the argument when given a block with a *arg" do
- a = []
- [1,2].send(@method, 0) {|*args| a << args; args[0] + args[1]}
- a.should == [[0, 1], [1, 2]]
- end
-
- 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)
- 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
- a = []
- EnumerableSpecs::Numerous.new.send(@method) { |memo, i| a << [memo, i]; i }
- 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 "with inject arguments(legacy rubycon)" do
- # with inject argument
- EnumerableSpecs::EachDefiner.new().send(@method, 1) {|acc,x| 999 }.should == 1
- EnumerableSpecs::EachDefiner.new(2).send(@method, 1) {|acc,x| 999 }.should == 999
- EnumerableSpecs::EachDefiner.new(2).send(@method, 1) {|acc,x| acc }.should == 1
- EnumerableSpecs::EachDefiner.new(2).send(@method, 1) {|acc,x| x }.should == 2
-
- EnumerableSpecs::EachDefiner.new(1,2,3,4).send(@method, 100) {|acc,x| acc + x }.should == 110
- EnumerableSpecs::EachDefiner.new(1,2,3,4).send(@method, 100) {|acc,x| acc * x }.should == 2400
-
- EnumerableSpecs::EachDefiner.new('a','b','c').send(@method, "z") {|result, i| i+result}.should == "cbaz"
- end
-
- it "without inject arguments(legacy rubycon)" do
- # no inject argument
- EnumerableSpecs::EachDefiner.new(2).send(@method) {|acc,x| 999 } .should == 2
- EnumerableSpecs::EachDefiner.new(2).send(@method) {|acc,x| acc }.should == 2
- EnumerableSpecs::EachDefiner.new(2).send(@method) {|acc,x| x }.should == 2
-
- EnumerableSpecs::EachDefiner.new(1,2,3,4).send(@method) {|acc,x| acc + x }.should == 10
- EnumerableSpecs::EachDefiner.new(1,2,3,4).send(@method) {|acc,x| acc * x }.should == 24
-
- 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
-
- it "raises an ArgumentError when no parameters or block is given" do
- -> { [1,2].send(@method) }.should raise_error(ArgumentError)
- -> { {one: 1, two: 2}.send(@method) }.should raise_error(ArgumentError)
- end
-end
diff --git a/spec/ruby/core/enumerable/shared/take.rb b/spec/ruby/core/enumerable/shared/take.rb
index ce2ace20fa..a6da06325f 100644
--- a/spec/ruby/core/enumerable/shared/take.rb
+++ b/spec/ruby/core/enumerable/shared/take.rb
@@ -25,7 +25,7 @@ describe :enumerable_take, shared: true do
end
it "raises an ArgumentError when count is negative" do
- -> { @enum.send(@method, -1) }.should raise_error(ArgumentError)
+ -> { @enum.send(@method, -1) }.should.raise(ArgumentError)
end
it "returns the entire array when count > length" do
@@ -40,11 +40,11 @@ describe :enumerable_take, shared: true do
end
it "raises a TypeError if the passed argument is not numeric" do
- -> { @enum.send(@method, nil) }.should raise_error(TypeError)
- -> { @enum.send(@method, "a") }.should raise_error(TypeError)
+ -> { @enum.send(@method, nil) }.should.raise(TypeError)
+ -> { @enum.send(@method, "a") }.should.raise(TypeError)
obj = mock("nonnumeric")
- -> { @enum.send(@method, obj) }.should raise_error(TypeError)
+ -> { @enum.send(@method, obj) }.should.raise(TypeError)
end
it "gathers whole arrays as elements when each yields multiple" do
diff --git a/spec/ruby/core/enumerable/shared/value_packing.rb b/spec/ruby/core/enumerable/shared/value_packing.rb
new file mode 100644
index 0000000000..ff77f45cdf
--- /dev/null
+++ b/spec/ruby/core/enumerable/shared/value_packing.rb
@@ -0,0 +1,26 @@
+# This is the behavior of rb_enum_values_pack() in CRuby
+describe :enumerable_value_packing, shared: true do
+ # @take must be set to a Proc that returns the take-result whose #each
+ # yields packed values (e.g. -> e { e.take(1) } or -> e { e.lazy.take(1) }).
+
+ it "yields a single nil for a zero-argument source yield" do
+ e = Enumerator.new { |y| y.yield }
+ args = nil
+ @take.call(e).each { |*a| args = a }
+ args.should == [nil]
+ end
+
+ it "yields the value for a single-argument source yield" do
+ e = Enumerator.new { |y| y.yield :v }
+ args = nil
+ @take.call(e).each { |*a| args = a }
+ args.should == [:v]
+ end
+
+ it "yields a packed Array for a multi-argument source yield" do
+ e = Enumerator.new { |y| y.yield 1, 2 }
+ args = nil
+ @take.call(e).each { |*a| args = a }
+ args.should == [[1, 2]]
+ end
+end
diff --git a/spec/ruby/core/enumerable/slice_after_spec.rb b/spec/ruby/core/enumerable/slice_after_spec.rb
index 0e46688db1..1ef37195e5 100644
--- a/spec/ruby/core/enumerable/slice_after_spec.rb
+++ b/spec/ruby/core/enumerable/slice_after_spec.rb
@@ -11,7 +11,7 @@ describe "Enumerable#slice_after" do
arg = mock("filter")
arg.should_receive(:===).and_return(false, true, false, false, false, true, false)
e = @enum.slice_after(arg)
- e.should be_an_instance_of(Enumerator)
+ e.should.instance_of?(Enumerator)
e.to_a.should == [[7, 6], [5, 4, 3, 2], [1]]
end
@@ -34,21 +34,21 @@ describe "Enumerable#slice_after" do
describe "and no argument" do
it "calls the block to determine when to yield" do
e = @enum.slice_after{ |i| i == 6 || i == 2 }
- e.should be_an_instance_of(Enumerator)
+ e.should.instance_of?(Enumerator)
e.to_a.should == [[7, 6], [5, 4, 3, 2], [1]]
end
end
describe "and an argument" do
it "raises an ArgumentError" do
- -> { @enum.slice_after(42) { |i| i == 6 } }.should raise_error(ArgumentError)
+ -> { @enum.slice_after(42) { |i| i == 6 } }.should.raise(ArgumentError)
end
end
end
it "raises an ArgumentError when given an incorrect number of arguments" do
- -> { @enum.slice_after("one", "two") }.should raise_error(ArgumentError)
- -> { @enum.slice_after }.should raise_error(ArgumentError)
+ -> { @enum.slice_after("one", "two") }.should.raise(ArgumentError)
+ -> { @enum.slice_after }.should.raise(ArgumentError)
end
end
diff --git a/spec/ruby/core/enumerable/slice_before_spec.rb b/spec/ruby/core/enumerable/slice_before_spec.rb
index f9b33f7b28..7eb4410a25 100644
--- a/spec/ruby/core/enumerable/slice_before_spec.rb
+++ b/spec/ruby/core/enumerable/slice_before_spec.rb
@@ -12,7 +12,7 @@ describe "Enumerable#slice_before" do
arg = mock "filter"
arg.should_receive(:===).and_return(false, true, false, false, false, true, false)
e = @enum.slice_before(arg)
- e.should be_an_instance_of(Enumerator)
+ e.should.instance_of?(Enumerator)
e.to_a.should == [[7], [6, 5, 4, 3], [2, 1]]
end
@@ -35,7 +35,7 @@ describe "Enumerable#slice_before" do
describe "and no argument" do
it "calls the block to determine when to yield" do
e = @enum.slice_before{|i| i == 6 || i == 2}
- e.should be_an_instance_of(Enumerator)
+ e.should.instance_of?(Enumerator)
e.to_a.should == [[7], [6, 5, 4, 3], [2, 1]]
end
end
@@ -43,13 +43,13 @@ describe "Enumerable#slice_before" do
it "does not accept arguments" do
-> {
@enum.slice_before(1) {}
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
end
it "raises an ArgumentError when given an incorrect number of arguments" do
- -> { @enum.slice_before("one", "two") }.should raise_error(ArgumentError)
- -> { @enum.slice_before }.should raise_error(ArgumentError)
+ -> { @enum.slice_before("one", "two") }.should.raise(ArgumentError)
+ -> { @enum.slice_before }.should.raise(ArgumentError)
end
describe "when an iterator method yields more than one value" do
diff --git a/spec/ruby/core/enumerable/slice_when_spec.rb b/spec/ruby/core/enumerable/slice_when_spec.rb
index 6b8ea0923e..fe1ecd31e2 100644
--- a/spec/ruby/core/enumerable/slice_when_spec.rb
+++ b/spec/ruby/core/enumerable/slice_when_spec.rb
@@ -11,7 +11,7 @@ describe "Enumerable#slice_when" do
context "when given a block" do
it "returns an enumerator" do
- @result.should be_an_instance_of(Enumerator)
+ @result.should.instance_of?(Enumerator)
end
it "splits chunks between adjacent elements i and j where the block returns true" do
@@ -39,7 +39,7 @@ describe "Enumerable#slice_when" do
context "when not given a block" do
it "raises an ArgumentError" do
- -> { @enum.slice_when }.should raise_error(ArgumentError)
+ -> { @enum.slice_when }.should.raise(ArgumentError)
end
end
diff --git a/spec/ruby/core/enumerable/sort_by_spec.rb b/spec/ruby/core/enumerable/sort_by_spec.rb
index 8fdd923fb4..62cf38ce3e 100644
--- a/spec/ruby/core/enumerable/sort_by_spec.rb
+++ b/spec/ruby/core/enumerable/sort_by_spec.rb
@@ -18,7 +18,7 @@ describe "Enumerable#sort_by" do
it "returns an Enumerator when a block is not supplied" do
a = EnumerableSpecs::Numerous.new("a","b")
- a.sort_by.should be_an_instance_of(Enumerator)
+ a.sort_by.should.instance_of?(Enumerator)
a.to_a.should == ["a", "b"]
end
diff --git a/spec/ruby/core/enumerable/sort_spec.rb b/spec/ruby/core/enumerable/sort_spec.rb
index 6fc64f325e..427b1cd8f1 100644
--- a/spec/ruby/core/enumerable/sort_spec.rb
+++ b/spec/ruby/core/enumerable/sort_spec.rb
@@ -16,7 +16,7 @@ describe "Enumerable#sort" do
it "raises a NoMethodError if elements do not define <=>" do
-> do
EnumerableSpecs::Numerous.new(BasicObject.new, BasicObject.new, BasicObject.new).sort
- end.should raise_error(NoMethodError)
+ end.should.raise(NoMethodError)
end
it "sorts enumerables that contain nils" do
@@ -35,12 +35,12 @@ describe "Enumerable#sort" do
}.should == [6, 5, 4, 3, 2, 1]
-> {
EnumerableSpecs::Numerous.new.sort { |n, m| (n <=> m).to_s }
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
it "raises an error if objects can't be compared" do
a=EnumerableSpecs::Numerous.new(EnumerableSpecs::Uncomparable.new, EnumerableSpecs::Uncomparable.new)
- -> {a.sort}.should raise_error(ArgumentError)
+ -> {a.sort}.should.raise(ArgumentError)
end
it "gathers whole arrays as elements when each yields multiple" do
diff --git a/spec/ruby/core/enumerable/take_spec.rb b/spec/ruby/core/enumerable/take_spec.rb
index 41a7438330..ca439b750d 100644
--- a/spec/ruby/core/enumerable/take_spec.rb
+++ b/spec/ruby/core/enumerable/take_spec.rb
@@ -1,13 +1,21 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
require_relative 'shared/take'
+require_relative 'shared/value_packing'
describe "Enumerable#take" do
it "requires an argument" do
- ->{ EnumerableSpecs::Numerous.new.take}.should raise_error(ArgumentError)
+ ->{ EnumerableSpecs::Numerous.new.take}.should.raise(ArgumentError)
end
describe "when passed an argument" do
it_behaves_like :enumerable_take, :take
end
+
+ describe "value packing of source yields" do
+ before :each do
+ @take = -> e { e.take(1) }
+ end
+ it_behaves_like :enumerable_value_packing, nil
+ end
end
diff --git a/spec/ruby/core/enumerable/take_while_spec.rb b/spec/ruby/core/enumerable/take_while_spec.rb
index 26db39ac4b..918bfc897d 100644
--- a/spec/ruby/core/enumerable/take_while_spec.rb
+++ b/spec/ruby/core/enumerable/take_while_spec.rb
@@ -8,7 +8,7 @@ describe "Enumerable#take_while" do
end
it "returns an Enumerator if no block given" do
- @enum.take_while.should be_an_instance_of(Enumerator)
+ @enum.take_while.should.instance_of?(Enumerator)
end
it "returns no/all elements for {true/false} block" do
@@ -38,7 +38,7 @@ describe "Enumerable#take_while" do
it "doesn't return self when it could" do
a = [1,2,3]
- a.take_while{true}.should_not equal(a)
+ a.take_while{true}.should_not.equal?(a)
end
it "calls the block with initial args when yielded with multiple arguments" do
diff --git a/spec/ruby/core/enumerable/tally_spec.rb b/spec/ruby/core/enumerable/tally_spec.rb
index 95c64c1294..deef741407 100644
--- a/spec/ruby/core/enumerable/tally_spec.rb
+++ b/spec/ruby/core/enumerable/tally_spec.rb
@@ -13,8 +13,8 @@ describe "Enumerable#tally" do
it "returns a hash without default" do
hash = EnumerableSpecs::Numerous.new('foo', 'bar', 'foo', 'baz').tally
- hash.default_proc.should be_nil
- hash.default.should be_nil
+ hash.default_proc.should == nil
+ hash.default.should == nil
end
it "returns an empty hash for empty enumerables" do
@@ -45,7 +45,7 @@ describe "Enumerable#tally with a hash" do
it "returns the given hash" do
enum = EnumerableSpecs::Numerous.new('foo', 'bar', 'foo', 'baz')
hash = { 'foo' => 1 }
- enum.tally(hash).should equal(hash)
+ enum.tally(hash).should.equal?(hash)
end
it "calls #to_hash to convert argument to Hash implicitly if passed not a Hash" do
@@ -58,14 +58,14 @@ describe "Enumerable#tally with a hash" do
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
- -> { enum.tally(hash) }.should raise_error(FrozenError)
+ -> { enum.tally(hash) }.should.raise(FrozenError)
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)
+ -> { enum.tally(hash) }.should.raise(FrozenError)
end
it "does not call given block" do
@@ -86,6 +86,6 @@ describe "Enumerable#tally with a hash" do
it "needs the values counting each elements to be an integer" do
enum = EnumerableSpecs::Numerous.new('foo')
- -> { enum.tally({ 'foo' => 'bar' }) }.should raise_error(TypeError)
+ -> { enum.tally({ 'foo' => 'bar' }) }.should.raise(TypeError)
end
end
diff --git a/spec/ruby/core/enumerable/to_a_spec.rb b/spec/ruby/core/enumerable/to_a_spec.rb
index 723f922574..f1796070f0 100644
--- a/spec/ruby/core/enumerable/to_a_spec.rb
+++ b/spec/ruby/core/enumerable/to_a_spec.rb
@@ -1,7 +1,19 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
-require_relative 'shared/entries'
describe "Enumerable#to_a" do
- it_behaves_like :enumerable_entries, :to_a
+ it "returns an array containing the elements" do
+ numerous = EnumerableSpecs::Numerous.new(1, nil, 'a', 2, false, true)
+ numerous.to_a.should == [1, nil, "a", 2, false, true]
+ end
+
+ it "passes through the values yielded by #each_with_index" do
+ [:a, :b].each_with_index.to_a.should == [[:a, 0], [:b, 1]]
+ end
+
+ it "passes arguments to each" do
+ count = EnumerableSpecs::EachCounter.new(1, 2, 3)
+ count.to_a(:hello, "world").should == [1, 2, 3]
+ count.arguments_passed.should == [:hello, "world"]
+ end
end
diff --git a/spec/ruby/core/enumerable/to_h_spec.rb b/spec/ruby/core/enumerable/to_h_spec.rb
index 11a4933c10..38847eccfb 100644
--- a/spec/ruby/core/enumerable/to_h_spec.rb
+++ b/spec/ruby/core/enumerable/to_h_spec.rb
@@ -36,12 +36,12 @@ describe "Enumerable#to_h" do
it "raises TypeError if an element is not an array" do
enum = EnumerableSpecs::EachDefiner.new(:x)
- -> { enum.to_h }.should raise_error(TypeError)
+ -> { enum.to_h }.should.raise(TypeError)
end
it "raises ArgumentError if an element is not a [key, value] pair" do
enum = EnumerableSpecs::EachDefiner.new([:x])
- -> { enum.to_h }.should raise_error(ArgumentError)
+ -> { enum.to_h }.should.raise(ArgumentError)
end
context "with block" do
@@ -64,17 +64,17 @@ describe "Enumerable#to_h" do
it "raises ArgumentError if block returns longer or shorter array" do
-> do
@enum.to_h { |k| [k, k.to_s, 1] }
- end.should raise_error(ArgumentError, /element has wrong array length/)
+ end.should.raise(ArgumentError, /element has wrong array length/)
-> do
@enum.to_h { |k| [k] }
- end.should raise_error(ArgumentError, /element has wrong array length/)
+ end.should.raise(ArgumentError, /element has wrong array length/)
end
it "raises TypeError if block returns something other than Array" do
-> do
@enum.to_h { |k| "not-array" }
- end.should raise_error(TypeError, /wrong element type String/)
+ end.should.raise(TypeError, /wrong element type String/)
end
it "coerces returned pair to Array with #to_ary" do
@@ -90,7 +90,7 @@ describe "Enumerable#to_h" do
-> do
@enum.to_h { |k| x }
- end.should raise_error(TypeError, /wrong element type MockObject/)
+ end.should.raise(TypeError, /wrong element type MockObject/)
end
end
end
diff --git a/spec/ruby/core/enumerable/to_set_spec.rb b/spec/ruby/core/enumerable/to_set_spec.rb
index e0437fea61..7b04c72bce 100644
--- a/spec/ruby/core/enumerable/to_set_spec.rb
+++ b/spec/ruby/core/enumerable/to_set_spec.rb
@@ -11,28 +11,20 @@ describe "Enumerable#to_set" do
[1, 2, 3].to_set { |x| x * x }.should == Set[1, 4, 9]
end
- ruby_version_is "3.5" do
+ ruby_version_is "4.0"..."4.1" do
it "instantiates an object of provided as the first argument set class" do
set = nil
proc{set = [1, 2, 3].to_set(EnumerableSpecs::SetSubclass)}.should complain(/Enumerable#to_set/)
- set.should be_kind_of(EnumerableSpecs::SetSubclass)
+ set.should.is_a?(EnumerableSpecs::SetSubclass)
set.to_a.sort.should == [1, 2, 3]
end
end
- ruby_version_is ""..."3.5" do
+ ruby_version_is ""..."4.0" do
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.should.is_a?(EnumerableSpecs::SetSubclass)
set.to_a.sort.should == [1, 2, 3]
end
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.to_a.inspect
- RUBY
-
- output.chomp.should == "[1, 2, 3]"
- end
end
diff --git a/spec/ruby/core/enumerable/zip_spec.rb b/spec/ruby/core/enumerable/zip_spec.rb
index ab148f2a6e..c5f9a3e4d4 100644
--- a/spec/ruby/core/enumerable/zip_spec.rb
+++ b/spec/ruby/core/enumerable/zip_spec.rb
@@ -39,8 +39,8 @@ describe "Enumerable#zip" do
end
it "raises TypeError when some argument isn't Array and doesn't respond to #to_ary and #to_enum" do
- -> { EnumerableSpecs::Numerous.new(1,2,3).zip(Object.new) }.should raise_error(TypeError, "wrong argument type Object (must respond to :each)")
- -> { EnumerableSpecs::Numerous.new(1,2,3).zip(1) }.should raise_error(TypeError, "wrong argument type Integer (must respond to :each)")
- -> { EnumerableSpecs::Numerous.new(1,2,3).zip(true) }.should raise_error(TypeError, "wrong argument type TrueClass (must respond to :each)")
+ -> { EnumerableSpecs::Numerous.new(1,2,3).zip(Object.new) }.should.raise(TypeError, "wrong argument type Object (must respond to :each)")
+ -> { EnumerableSpecs::Numerous.new(1,2,3).zip(1) }.should.raise(TypeError, "wrong argument type Integer (must respond to :each)")
+ -> { EnumerableSpecs::Numerous.new(1,2,3).zip(true) }.should.raise(TypeError, "wrong argument type TrueClass (must respond to :each)")
end
end
diff --git a/spec/ruby/core/enumerator/arithmetic_sequence/each_spec.rb b/spec/ruby/core/enumerator/arithmetic_sequence/each_spec.rb
index d4fff3e01f..0a83019d49 100644
--- a/spec/ruby/core/enumerator/arithmetic_sequence/each_spec.rb
+++ b/spec/ruby/core/enumerator/arithmetic_sequence/each_spec.rb
@@ -12,6 +12,6 @@ describe "Enumerator::ArithmeticSequence#each" do
end
it "returns self" do
- @seq.each { |item| }.should equal(@seq)
+ @seq.each { |item| }.should.equal?(@seq)
end
end
diff --git a/spec/ruby/core/enumerator/arithmetic_sequence/hash_spec.rb b/spec/ruby/core/enumerator/arithmetic_sequence/hash_spec.rb
index bdb308074b..a18c554fb3 100644
--- a/spec/ruby/core/enumerator/arithmetic_sequence/hash_spec.rb
+++ b/spec/ruby/core/enumerator/arithmetic_sequence/hash_spec.rb
@@ -2,7 +2,7 @@ require_relative '../../../spec_helper'
describe "Enumerator::ArithmeticSequence#hash" do
it "is based on begin, end, step and exclude_end?" do
- 1.step(10).hash.should be_an_instance_of(Integer)
+ 1.step(10).hash.should.instance_of?(Integer)
1.step(10).hash.should == 1.step(10).hash
1.step(10, 5).hash.should == 1.step(10, 5).hash
diff --git a/spec/ruby/core/enumerator/arithmetic_sequence/new_spec.rb b/spec/ruby/core/enumerator/arithmetic_sequence/new_spec.rb
index 2015983826..1bd2f7f0f7 100644
--- a/spec/ruby/core/enumerator/arithmetic_sequence/new_spec.rb
+++ b/spec/ruby/core/enumerator/arithmetic_sequence/new_spec.rb
@@ -4,7 +4,7 @@ describe "Enumerator::ArithmeticSequence.new" do
it "is not defined" do
-> {
Enumerator::ArithmeticSequence.new
- }.should raise_error(NoMethodError)
+ }.should.raise(NoMethodError)
end
end
@@ -12,6 +12,6 @@ describe "Enumerator::ArithmeticSequence.allocate" do
it "is not defined" do
-> {
Enumerator::ArithmeticSequence.allocate
- }.should raise_error(TypeError, 'allocator undefined for Enumerator::ArithmeticSequence')
+ }.should.raise(TypeError, 'allocator undefined for Enumerator::ArithmeticSequence')
end
end
diff --git a/spec/ruby/core/enumerator/chain/initialize_spec.rb b/spec/ruby/core/enumerator/chain/initialize_spec.rb
index daa30351d7..1df1dec5f8 100644
--- a/spec/ruby/core/enumerator/chain/initialize_spec.rb
+++ b/spec/ruby/core/enumerator/chain/initialize_spec.rb
@@ -6,26 +6,26 @@ describe "Enumerator::Chain#initialize" do
end
it "is a private method" do
- Enumerator::Chain.should have_private_instance_method(:initialize, false)
+ Enumerator::Chain.private_instance_methods(false).should.include?(:initialize)
end
it "returns self" do
- @uninitialized.send(:initialize).should equal(@uninitialized)
+ @uninitialized.send(:initialize).should.equal?(@uninitialized)
end
it "accepts many arguments" do
- @uninitialized.send(:initialize, 0..1, 2..3, 4..5).should equal(@uninitialized)
+ @uninitialized.send(:initialize, 0..1, 2..3, 4..5).should.equal?(@uninitialized)
end
it "accepts arguments that are not Enumerable nor responding to :each" do
- @uninitialized.send(:initialize, Object.new).should equal(@uninitialized)
+ @uninitialized.send(:initialize, Object.new).should.equal?(@uninitialized)
end
describe "on frozen instance" do
it "raises a FrozenError" do
-> {
@uninitialized.freeze.send(:initialize)
- }.should raise_error(FrozenError)
+ }.should.raise(FrozenError)
end
end
end
diff --git a/spec/ruby/core/enumerator/chain/rewind_spec.rb b/spec/ruby/core/enumerator/chain/rewind_spec.rb
index 5f51ce2cf1..4525b82f7b 100644
--- a/spec/ruby/core/enumerator/chain/rewind_spec.rb
+++ b/spec/ruby/core/enumerator/chain/rewind_spec.rb
@@ -10,7 +10,7 @@ describe "Enumerator::Chain#rewind" do
end
it "returns self" do
- @enum.rewind.should equal @enum
+ @enum.rewind.should.equal? @enum
end
it "does nothing if receiver has not been iterated" do
@@ -35,7 +35,7 @@ describe "Enumerator::Chain#rewind" do
@obj.should_not_receive(:rewind)
@second.should_receive(:rewind).and_raise(RuntimeError)
@enum.each {}
- -> { @enum.rewind }.should raise_error(RuntimeError)
+ -> { @enum.rewind }.should.raise(RuntimeError)
end
it "calls rewind only for objects that have actually been iterated on" do
@@ -45,7 +45,7 @@ describe "Enumerator::Chain#rewind" do
@obj.should_receive(:rewind)
@second.should_not_receive(:rewind)
- -> { @enum.each {} }.should raise_error(RuntimeError)
+ -> { @enum.each {} }.should.raise(RuntimeError)
@enum.rewind
end
end
diff --git a/spec/ruby/core/enumerator/each_spec.rb b/spec/ruby/core/enumerator/each_spec.rb
index 3af16e5587..64912b98b6 100644
--- a/spec/ruby/core/enumerator/each_spec.rb
+++ b/spec/ruby/core/enumerator/each_spec.rb
@@ -1,6 +1,21 @@
require_relative '../../spec_helper'
+require_relative 'shared/each'
describe "Enumerator#each" do
+ describe "passing source-yielded arguments to the block" do
+ before :each do
+ @object = -> e { e }
+ end
+ it_behaves_like :enum_each, nil
+ end
+
+ describe "passing source-yielded arguments to the block (lazy)" do
+ before :each do
+ @object = -> e { e.lazy }
+ end
+ it_behaves_like :enum_each, nil
+ end
+
before :each do
object_each_with_arguments = Object.new
def object_each_with_arguments.each_with_arguments(arg, *args)
@@ -51,17 +66,17 @@ describe "Enumerator#each" do
enum = Object.new.to_enum
-> do
enum.each { |e| e }
- end.should raise_error(NoMethodError)
+ end.should.raise(NoMethodError)
end
it "returns self if not given arguments and not given a block" do
- @enum_with_arguments.each.should equal(@enum_with_arguments)
+ @enum_with_arguments.each.should.equal?(@enum_with_arguments)
- @enum_with_yielder.each.should equal(@enum_with_yielder)
+ @enum_with_yielder.each.should.equal?(@enum_with_yielder)
end
it "returns the same value from receiver.each if block is given" do
- @enum_with_arguments.each {}.should equal(:method_returned)
+ @enum_with_arguments.each {}.should.equal?(:method_returned)
end
it "passes given arguments at initialized to receiver.each" do
@@ -78,12 +93,27 @@ describe "Enumerator#each" do
end
it "returns the same value from receiver.each if block and arguments are given" do
- @enum_with_arguments.each(:each1, :each2) {}.should equal(:method_returned)
+ @enum_with_arguments.each(:each1, :each2) {}.should.equal?(:method_returned)
end
it "returns new Enumerator if given arguments but not given a block" do
ret = @enum_with_arguments.each 1
- ret.should be_an_instance_of(Enumerator)
- ret.should_not equal(@enum_with_arguments)
+ ret.should.instance_of?(Enumerator)
+ ret.should_not.equal?(@enum_with_arguments)
+ end
+
+ it "does not destructure yielded array values when chaining each.map" do
+ result = [[[1]]].each.map { |a, b| [a, b] }
+ result.should == [[[1], nil]]
+ end
+
+ it "preserves array values yielded from the enumerator" do
+ result = [[1, 2]].each.map { |a| a }
+ result.should == [[1, 2]]
+ end
+
+ it "allows destructuring to occur in the block, not the enumerator" do
+ result = [[1, 2]].each.map { |a, b| a }
+ result.should == [1]
end
end
diff --git a/spec/ruby/core/enumerator/each_with_index_spec.rb b/spec/ruby/core/enumerator/each_with_index_spec.rb
index 4898e86fa9..0630b7045e 100644
--- a/spec/ruby/core/enumerator/each_with_index_spec.rb
+++ b/spec/ruby/core/enumerator/each_with_index_spec.rb
@@ -9,14 +9,14 @@ describe "Enumerator#each_with_index" do
it "returns a new Enumerator when no block is given" do
enum1 = [1,2,3].select
enum2 = enum1.each_with_index
- enum2.should be_an_instance_of(Enumerator)
+ enum2.should.instance_of?(Enumerator)
enum1.should_not == enum2
end
it "raises an ArgumentError if passed extra arguments" do
-> do
[1].to_enum.each_with_index(:glark)
- end.should raise_error(ArgumentError)
+ end.should.raise(ArgumentError)
end
it "passes on the given block's return value" do
diff --git a/spec/ruby/core/enumerator/each_with_object_spec.rb b/spec/ruby/core/enumerator/each_with_object_spec.rb
index 84a45ae89d..0e0a4496f4 100644
--- a/spec/ruby/core/enumerator/each_with_object_spec.rb
+++ b/spec/ruby/core/enumerator/each_with_object_spec.rb
@@ -1,6 +1,42 @@
require_relative '../../spec_helper'
-require_relative 'shared/with_object'
describe "Enumerator#each_with_object" do
- it_behaves_like :enum_with_object, :each_with_object
+ before :each do
+ @enum = [:a, :b].to_enum
+ @memo = ''
+ @block_params = @enum.each_with_object(@memo).to_a
+ end
+
+ it "receives an argument" do
+ @enum.method(:each_with_object).arity.should == 1
+ end
+
+ context "with block" do
+ it "returns the given object" do
+ ret = @enum.each_with_object(@memo) do |elm, memo|
+ # nothing
+ end
+ ret.should.equal?(@memo)
+ end
+
+ context "the block parameter" do
+ it "passes each element to first parameter" do
+ @block_params[0][0].should.equal?(:a)
+ @block_params[1][0].should.equal?(:b)
+ end
+
+ it "passes the given object to last parameter" do
+ @block_params[0][1].should.equal?(@memo)
+ @block_params[1][1].should.equal?(@memo)
+ end
+ end
+ end
+
+ context "without block" do
+ it "returns new Enumerator" do
+ ret = @enum.each_with_object(@memo)
+ ret.should.instance_of?(Enumerator)
+ ret.should_not.equal?(@enum)
+ end
+ end
end
diff --git a/spec/ruby/core/enumerator/enum_for_spec.rb b/spec/ruby/core/enumerator/enum_for_spec.rb
deleted file mode 100644
index fbdf98545a..0000000000
--- a/spec/ruby/core/enumerator/enum_for_spec.rb
+++ /dev/null
@@ -1,6 +0,0 @@
-require_relative '../../spec_helper'
-require_relative 'shared/enum_for'
-
-describe "Enumerator#enum_for" do
- it_behaves_like :enum_for, :enum_for
-end
diff --git a/spec/ruby/core/enumerator/feed_spec.rb b/spec/ruby/core/enumerator/feed_spec.rb
index e387c6cd39..781947a8c7 100644
--- a/spec/ruby/core/enumerator/feed_spec.rb
+++ b/spec/ruby/core/enumerator/feed_spec.rb
@@ -33,20 +33,20 @@ describe "Enumerator#feed" do
end
it "returns nil" do
- @enum.feed(:a).should be_nil
+ @enum.feed(:a).should == nil
end
it "raises a TypeError if called more than once without advancing the enumerator" do
@enum.feed :a
@enum.next
- -> { @enum.feed :b }.should raise_error(TypeError)
+ -> { @enum.feed :b }.should.raise(TypeError)
end
it "sets the return value of Yielder#yield" do
enum = Enumerator.new { |y| ScratchPad << y.yield }
enum.next
enum.feed :a
- -> { enum.next }.should raise_error(StopIteration)
+ -> { enum.next }.should.raise(StopIteration)
ScratchPad.recorded.should == [:a]
end
end
diff --git a/spec/ruby/core/enumerator/generator/each_spec.rb b/spec/ruby/core/enumerator/generator/each_spec.rb
deleted file mode 100644
index a43805dd16..0000000000
--- a/spec/ruby/core/enumerator/generator/each_spec.rb
+++ /dev/null
@@ -1,40 +0,0 @@
-require_relative '../../../spec_helper'
-
-describe "Enumerator::Generator#each" do
- before :each do
- @generator = Enumerator::Generator.new do |y, *args|
- y << 3 << 2 << 1
- y << args unless args.empty?
- :block_returned
- end
- end
-
- it "is an enumerable" do
- @generator.should be_kind_of(Enumerable)
- end
-
- it "supports enumeration with a block" do
- r = []
- @generator.each { |v| r << v }
-
- r.should == [3, 2, 1]
- end
-
- it "raises a LocalJumpError if no block given" do
- -> { @generator.each }.should raise_error(LocalJumpError)
- end
-
- it "returns the block returned value" do
- @generator.each {}.should equal(:block_returned)
- end
-
- it "requires multiple arguments" do
- Enumerator::Generator.instance_method(:each).arity.should < 0
- end
-
- it "appends given arguments to receiver.each" do
- yields = []
- @generator.each(:each0, :each1) { |yielded| yields << yielded }
- yields.should == [3, 2, 1, [:each0, :each1]]
- end
-end
diff --git a/spec/ruby/core/enumerator/generator/initialize_spec.rb b/spec/ruby/core/enumerator/generator/initialize_spec.rb
deleted file mode 100644
index acc1174253..0000000000
--- a/spec/ruby/core/enumerator/generator/initialize_spec.rb
+++ /dev/null
@@ -1,26 +0,0 @@
-# -*- encoding: us-ascii -*-
-
-require_relative '../../../spec_helper'
-
-describe "Enumerator::Generator#initialize" do
- before :each do
- @class = Enumerator::Generator
- @uninitialized = @class.allocate
- end
-
- it "is a private method" do
- @class.should have_private_instance_method(:initialize, false)
- end
-
- it "returns self when given a block" do
- @uninitialized.send(:initialize) {}.should equal(@uninitialized)
- end
-
- describe "on frozen instance" do
- it "raises a FrozenError" do
- -> {
- @uninitialized.freeze.send(:initialize) {}
- }.should raise_error(FrozenError)
- end
- end
-end
diff --git a/spec/ruby/core/enumerator/initialize_spec.rb b/spec/ruby/core/enumerator/initialize_spec.rb
index 5e0256ca46..9929494b5a 100644
--- a/spec/ruby/core/enumerator/initialize_spec.rb
+++ b/spec/ruby/core/enumerator/initialize_spec.rb
@@ -8,11 +8,11 @@ describe "Enumerator#initialize" do
end
it "is a private method" do
- Enumerator.should have_private_instance_method(:initialize, false)
+ Enumerator.private_instance_methods(false).should.include?(:initialize)
end
it "returns self when given a block" do
- @uninitialized.send(:initialize) {}.should equal(@uninitialized)
+ @uninitialized.send(:initialize) {}.should.equal?(@uninitialized)
end
# Maybe spec should be broken up?
@@ -21,22 +21,22 @@ describe "Enumerator#initialize" do
r = yielder.yield 3
yielder << r << 2 << 1
end
- @uninitialized.should be_an_instance_of(Enumerator)
+ @uninitialized.should.instance_of?(Enumerator)
r = []
@uninitialized.each{|x| r << x; x * 2}
r.should == [3, 6, 2, 1]
end
it "sets size to nil if size is not given" do
- @uninitialized.send(:initialize) {}.size.should be_nil
+ @uninitialized.send(:initialize) {}.size.should == nil
end
it "sets size to nil if the given size is nil" do
- @uninitialized.send(:initialize, nil) {}.size.should be_nil
+ @uninitialized.send(:initialize, nil) {}.size.should == nil
end
it "sets size to the given size if the given size is Float::INFINITY" do
- @uninitialized.send(:initialize, Float::INFINITY) {}.size.should equal(Float::INFINITY)
+ @uninitialized.send(:initialize, Float::INFINITY) {}.size.should.equal?(Float::INFINITY)
end
it "sets size to the given size if the given size is an Integer" do
@@ -51,7 +51,7 @@ describe "Enumerator#initialize" do
it "raises a FrozenError" do
-> {
@uninitialized.freeze.send(:initialize) {}
- }.should raise_error(FrozenError)
+ }.should.raise(FrozenError)
end
end
end
diff --git a/spec/ruby/core/enumerator/lazy/chunk_spec.rb b/spec/ruby/core/enumerator/lazy/chunk_spec.rb
index 87d2b0c206..d0179d32b6 100644
--- a/spec/ruby/core/enumerator/lazy/chunk_spec.rb
+++ b/spec/ruby/core/enumerator/lazy/chunk_spec.rb
@@ -17,8 +17,8 @@ describe "Enumerator::Lazy#chunk" do
it "returns a new instance of Enumerator::Lazy" do
ret = @yieldsmixed.chunk {}
- ret.should be_an_instance_of(Enumerator::Lazy)
- ret.should_not equal(@yieldsmixed)
+ ret.should.instance_of?(Enumerator::Lazy)
+ ret.should_not.equal?(@yieldsmixed)
end
it "sets #size to nil" do
@@ -27,7 +27,7 @@ describe "Enumerator::Lazy#chunk" do
it "returns an Enumerator if called without a block" do
chunk = @yieldsmixed.chunk
- chunk.should be_an_instance_of(Enumerator::Lazy)
+ chunk.should.instance_of?(Enumerator::Lazy)
res = chunk.each { |v| true }.force
res.should == [[true, EnumeratorLazySpecs::YieldsMixed.gathered_yields]]
diff --git a/spec/ruby/core/enumerator/lazy/chunk_while_spec.rb b/spec/ruby/core/enumerator/lazy/chunk_while_spec.rb
index 772bd42de9..edba8e1363 100644
--- a/spec/ruby/core/enumerator/lazy/chunk_while_spec.rb
+++ b/spec/ruby/core/enumerator/lazy/chunk_while_spec.rb
@@ -9,6 +9,6 @@ describe "Enumerator::Lazy#chunk_while" do
it "should return a lazy enumerator" do
s = 0..Float::INFINITY
- s.lazy.chunk_while { |a, b| false }.should be_kind_of(Enumerator::Lazy)
+ s.lazy.chunk_while { |a, b| false }.should.is_a?(Enumerator::Lazy)
end
end
diff --git a/spec/ruby/core/enumerator/lazy/collect_concat_spec.rb b/spec/ruby/core/enumerator/lazy/collect_concat_spec.rb
index 8765bb2190..d9fd576e43 100644
--- a/spec/ruby/core/enumerator/lazy/collect_concat_spec.rb
+++ b/spec/ruby/core/enumerator/lazy/collect_concat_spec.rb
@@ -1,8 +1,8 @@
-# -*- encoding: us-ascii -*-
-
require_relative '../../../spec_helper'
-require_relative 'shared/collect_concat'
describe "Enumerator::Lazy#collect_concat" do
- it_behaves_like :enumerator_lazy_collect_concat, :collect_concat
+ it "is an alias of Enumerator::Lazy#flat_map" do
+ Enumerator::Lazy.instance_method(:collect_concat).should ==
+ Enumerator::Lazy.instance_method(:flat_map)
+ end
end
diff --git a/spec/ruby/core/enumerator/lazy/collect_spec.rb b/spec/ruby/core/enumerator/lazy/collect_spec.rb
index 14b79ce16d..53a477e053 100644
--- a/spec/ruby/core/enumerator/lazy/collect_spec.rb
+++ b/spec/ruby/core/enumerator/lazy/collect_spec.rb
@@ -1,8 +1,8 @@
-# -*- encoding: us-ascii -*-
-
require_relative '../../../spec_helper'
-require_relative 'shared/collect'
describe "Enumerator::Lazy#collect" do
- it_behaves_like :enumerator_lazy_collect, :collect
+ it "is an alias of Enumerator::Lazy#map" do
+ Enumerator::Lazy.instance_method(:collect).should ==
+ Enumerator::Lazy.instance_method(:map)
+ end
end
diff --git a/spec/ruby/core/enumerator/lazy/compact_spec.rb b/spec/ruby/core/enumerator/lazy/compact_spec.rb
index 65c544f062..7305e1c9c4 100644
--- a/spec/ruby/core/enumerator/lazy/compact_spec.rb
+++ b/spec/ruby/core/enumerator/lazy/compact_spec.rb
@@ -4,7 +4,7 @@ require_relative 'fixtures/classes'
describe "Enumerator::Lazy#compact" do
it 'returns array without nil elements' do
arr = [1, nil, 3, false, 5].to_enum.lazy.compact
- arr.should be_an_instance_of(Enumerator::Lazy)
+ arr.should.instance_of?(Enumerator::Lazy)
arr.force.should == [1, 3, false, 5]
end
diff --git a/spec/ruby/core/enumerator/lazy/drop_spec.rb b/spec/ruby/core/enumerator/lazy/drop_spec.rb
index 822b8034fb..95ac7e9ecc 100644
--- a/spec/ruby/core/enumerator/lazy/drop_spec.rb
+++ b/spec/ruby/core/enumerator/lazy/drop_spec.rb
@@ -16,8 +16,8 @@ describe "Enumerator::Lazy#drop" do
it "returns a new instance of Enumerator::Lazy" do
ret = @yieldsmixed.drop(1)
- ret.should be_an_instance_of(Enumerator::Lazy)
- ret.should_not equal(@yieldsmixed)
+ ret.should.instance_of?(Enumerator::Lazy)
+ ret.should_not.equal?(@yieldsmixed)
end
it "sets difference of given count with old size to new size" do
diff --git a/spec/ruby/core/enumerator/lazy/drop_while_spec.rb b/spec/ruby/core/enumerator/lazy/drop_while_spec.rb
index 4f6e366f88..65f3007dec 100644
--- a/spec/ruby/core/enumerator/lazy/drop_while_spec.rb
+++ b/spec/ruby/core/enumerator/lazy/drop_while_spec.rb
@@ -16,8 +16,8 @@ describe "Enumerator::Lazy#drop_while" do
it "returns a new instance of Enumerator::Lazy" do
ret = @yieldsmixed.drop_while {}
- ret.should be_an_instance_of(Enumerator::Lazy)
- ret.should_not equal(@yieldsmixed)
+ ret.should.instance_of?(Enumerator::Lazy)
+ ret.should_not.equal?(@yieldsmixed)
end
it "sets #size to nil" do
@@ -40,7 +40,7 @@ describe "Enumerator::Lazy#drop_while" do
end
it "raises an ArgumentError when not given a block" do
- -> { @yieldsmixed.drop_while }.should raise_error(ArgumentError)
+ -> { @yieldsmixed.drop_while }.should.raise(ArgumentError)
end
describe "on a nested Lazy" do
diff --git a/spec/ruby/core/enumerator/lazy/enum_for_spec.rb b/spec/ruby/core/enumerator/lazy/enum_for_spec.rb
index 7e7783f6f1..b40c5d9915 100644
--- a/spec/ruby/core/enumerator/lazy/enum_for_spec.rb
+++ b/spec/ruby/core/enumerator/lazy/enum_for_spec.rb
@@ -1,8 +1,8 @@
-# -*- encoding: us-ascii -*-
-
require_relative '../../../spec_helper'
-require_relative 'shared/to_enum'
describe "Enumerator::Lazy#enum_for" do
- it_behaves_like :enumerator_lazy_to_enum, :enum_for
+ it "is an alias of Enumerator::Lazy#to_enum" do
+ Enumerator::Lazy.instance_method(:enum_for).should ==
+ Enumerator::Lazy.instance_method(:to_enum)
+ end
end
diff --git a/spec/ruby/core/enumerator/lazy/filter_spec.rb b/spec/ruby/core/enumerator/lazy/filter_spec.rb
index 43128241e0..3ca5376faa 100644
--- a/spec/ruby/core/enumerator/lazy/filter_spec.rb
+++ b/spec/ruby/core/enumerator/lazy/filter_spec.rb
@@ -1,6 +1,8 @@
require_relative '../../../spec_helper'
-require_relative 'shared/select'
describe "Enumerator::Lazy#filter" do
- it_behaves_like :enumerator_lazy_select, :filter
+ it "is an alias of Enumerator::Lazy#select" do
+ Enumerator::Lazy.instance_method(:filter).should ==
+ Enumerator::Lazy.instance_method(:select)
+ end
end
diff --git a/spec/ruby/core/enumerator/lazy/find_all_spec.rb b/spec/ruby/core/enumerator/lazy/find_all_spec.rb
index 8b05c53803..64930dc61b 100644
--- a/spec/ruby/core/enumerator/lazy/find_all_spec.rb
+++ b/spec/ruby/core/enumerator/lazy/find_all_spec.rb
@@ -1,8 +1,8 @@
-# -*- encoding: us-ascii -*-
-
require_relative '../../../spec_helper'
-require_relative 'shared/select'
describe "Enumerator::Lazy#find_all" do
- it_behaves_like :enumerator_lazy_select, :find_all
+ it "is an alias of Enumerator::Lazy#select" do
+ Enumerator::Lazy.instance_method(:find_all).should ==
+ Enumerator::Lazy.instance_method(:select)
+ end
end
diff --git a/spec/ruby/core/enumerator/lazy/flat_map_spec.rb b/spec/ruby/core/enumerator/lazy/flat_map_spec.rb
index 5dcaa8bfa1..609bf95b9e 100644
--- a/spec/ruby/core/enumerator/lazy/flat_map_spec.rb
+++ b/spec/ruby/core/enumerator/lazy/flat_map_spec.rb
@@ -1,10 +1,78 @@
-# -*- encoding: us-ascii -*-
-
require_relative '../../../spec_helper'
-require_relative 'shared/collect_concat'
+require_relative 'fixtures/classes'
describe "Enumerator::Lazy#flat_map" do
- it_behaves_like :enumerator_lazy_collect_concat, :flat_map
+ before :each do
+ @yieldsmixed = EnumeratorLazySpecs::YieldsMixed.new.to_enum.lazy
+ @eventsmixed = EnumeratorLazySpecs::EventsMixed.new.to_enum.lazy
+ ScratchPad.record []
+ end
+
+ after :each do
+ ScratchPad.clear
+ end
+
+ it "returns a new instance of Enumerator::Lazy" do
+ ret = @yieldsmixed.flat_map {}
+ ret.should.instance_of?(Enumerator::Lazy)
+ ret.should_not.equal?(@yieldsmixed)
+ end
+
+ it "sets #size to nil" do
+ Enumerator::Lazy.new(Object.new, 100) {}.flat_map { true }.size.should == nil
+ end
+
+ describe "when the returned lazy enumerator is evaluated by Enumerable#first" do
+ it "stops after specified times" do
+ (0..Float::INFINITY).lazy.flat_map { |n| (n * 10).to_s }.first(6).should == %w[0 10 20 30 40 50]
+
+ @eventsmixed.flat_map {}.first(1)
+ ScratchPad.recorded.should == [:before_yield]
+ end
+
+ it "flattens elements when the given block returned an array or responding to .each and .force" do
+ (0..Float::INFINITY).lazy.flat_map { |n| (n * 10).to_s.chars }.first(6).should == %w[0 1 0 2 0 3]
+ (0..Float::INFINITY).lazy.flat_map { |n| (n * 10).to_s.each_char }.first(6).all? { |o| o.instance_of? Enumerator }.should == true
+ (0..Float::INFINITY).lazy.flat_map { |n| (n * 10).to_s.each_char.lazy }.first(6).should == %w[0 1 0 2 0 3]
+ end
+ end
+
+ it "calls the block with initial values when yield with multiple arguments" do
+ yields = []
+ @yieldsmixed.flat_map { |v| yields << v }.force
+ yields.should == EnumeratorLazySpecs::YieldsMixed.initial_yields
+ end
+
+ it "raises an ArgumentError when not given a block" do
+ -> { @yieldsmixed.flat_map }.should.raise(ArgumentError)
+ end
+
+ describe "on a nested Lazy" do
+ it "sets #size to nil" do
+ Enumerator::Lazy.new(Object.new, 100) {}.take(50) {}.flat_map {}.size.should == nil
+ end
+
+ describe "when the returned lazy enumerator is evaluated by Enumerable#first" do
+ it "stops after specified times" do
+ (0..Float::INFINITY).lazy.map {|n| n * 10 }.flat_map { |n| n.to_s }.first(6).should == %w[0 10 20 30 40 50]
+
+ @eventsmixed.flat_map {}.flat_map {}.first(1)
+ ScratchPad.recorded.should == [:before_yield]
+ end
+
+ it "flattens elements when the given block returned an array or responding to .each and .force" do
+ (0..Float::INFINITY).lazy.map {|n| n * 10 }.flat_map { |n| n.to_s.chars }.first(6).should == %w[0 1 0 2 0 3]
+ (0..Float::INFINITY).lazy.map {|n| n * 10 }.flat_map { |n| n.to_s.each_char }.first(6).all? { |o| o.instance_of? Enumerator }.should == true
+ (0..Float::INFINITY).lazy.map {|n| n * 10 }.flat_map { |n| n.to_s.each_char.lazy }.first(6).should == %w[0 1 0 2 0 3]
+ end
+ end
+ end
+
+ it "works with an infinite enumerable" do
+ s = 0..Float::INFINITY
+ s.lazy.flat_map { |n| [-n, +n] }.first(200).should ==
+ s.first(100).flat_map { |n| [-n, +n] }.to_a
+ end
it "properly unwraps nested yields" do
s = Enumerator.new do |y| loop do y << [1, 2] end end
diff --git a/spec/ruby/core/enumerator/lazy/grep_spec.rb b/spec/ruby/core/enumerator/lazy/grep_spec.rb
index e67686c9a3..383f80a918 100644
--- a/spec/ruby/core/enumerator/lazy/grep_spec.rb
+++ b/spec/ruby/core/enumerator/lazy/grep_spec.rb
@@ -20,12 +20,12 @@ describe "Enumerator::Lazy#grep" do
it "returns a new instance of Enumerator::Lazy" do
ret = @yieldsmixed.grep(Object) {}
- ret.should be_an_instance_of(Enumerator::Lazy)
- ret.should_not equal(@yieldsmixed)
+ ret.should.instance_of?(Enumerator::Lazy)
+ ret.should_not.equal?(@yieldsmixed)
ret = @yieldsmixed.grep(Object)
- ret.should be_an_instance_of(Enumerator::Lazy)
- ret.should_not equal(@yieldsmixed)
+ ret.should.instance_of?(Enumerator::Lazy)
+ ret.should_not.equal?(@yieldsmixed)
end
it "sets #size to nil" do
diff --git a/spec/ruby/core/enumerator/lazy/grep_v_spec.rb b/spec/ruby/core/enumerator/lazy/grep_v_spec.rb
index 67173021bb..19c917f254 100644
--- a/spec/ruby/core/enumerator/lazy/grep_v_spec.rb
+++ b/spec/ruby/core/enumerator/lazy/grep_v_spec.rb
@@ -18,12 +18,12 @@ describe "Enumerator::Lazy#grep_v" do
it "returns a new instance of Enumerator::Lazy" do
ret = @yieldsmixed.grep_v(Object) {}
- ret.should be_an_instance_of(Enumerator::Lazy)
- ret.should_not equal(@yieldsmixed)
+ ret.should.instance_of?(Enumerator::Lazy)
+ ret.should_not.equal?(@yieldsmixed)
ret = @yieldsmixed.grep_v(Object)
- ret.should be_an_instance_of(Enumerator::Lazy)
- ret.should_not equal(@yieldsmixed)
+ ret.should.instance_of?(Enumerator::Lazy)
+ ret.should_not.equal?(@yieldsmixed)
end
it "sets #size to nil" do
diff --git a/spec/ruby/core/enumerator/lazy/initialize_spec.rb b/spec/ruby/core/enumerator/lazy/initialize_spec.rb
index e1e0b1d608..47765d32c3 100644
--- a/spec/ruby/core/enumerator/lazy/initialize_spec.rb
+++ b/spec/ruby/core/enumerator/lazy/initialize_spec.rb
@@ -16,11 +16,11 @@ describe "Enumerator::Lazy#initialize" do
end
it "is a private method" do
- Enumerator::Lazy.should have_private_instance_method(:initialize, false)
+ Enumerator::Lazy.private_instance_methods(false).should.include?(:initialize)
end
it "returns self" do
- @uninitialized.send(:initialize, @receiver) {}.should equal(@uninitialized)
+ @uninitialized.send(:initialize, @receiver) {}.should.equal?(@uninitialized)
end
describe "when the returned lazy enumerator is evaluated by Enumerable#first" do
@@ -32,15 +32,15 @@ describe "Enumerator::Lazy#initialize" do
end
it "sets #size to nil if not given a size" do
- @uninitialized.send(:initialize, @receiver) {}.size.should be_nil
+ @uninitialized.send(:initialize, @receiver) {}.size.should == nil
end
it "sets #size to nil if given size is nil" do
- @uninitialized.send(:initialize, @receiver, nil) {}.size.should be_nil
+ @uninitialized.send(:initialize, @receiver, nil) {}.size.should == nil
end
it "sets given size to own size if the given size is Float::INFINITY" do
- @uninitialized.send(:initialize, @receiver, Float::INFINITY) {}.size.should equal(Float::INFINITY)
+ @uninitialized.send(:initialize, @receiver, Float::INFINITY) {}.size.should.equal?(Float::INFINITY)
end
it "sets given size to own size if the given size is an Integer" do
@@ -52,12 +52,12 @@ describe "Enumerator::Lazy#initialize" do
end
it "raises an ArgumentError when block is not given" do
- -> { @uninitialized.send :initialize, @receiver }.should raise_error(ArgumentError)
+ -> { @uninitialized.send :initialize, @receiver }.should.raise(ArgumentError)
end
describe "on frozen instance" do
it "raises a FrozenError" do
- -> { @uninitialized.freeze.send(:initialize, @receiver) {} }.should raise_error(FrozenError)
+ -> { @uninitialized.freeze.send(:initialize, @receiver) {} }.should.raise(FrozenError)
end
end
end
diff --git a/spec/ruby/core/enumerator/lazy/lazy_spec.rb b/spec/ruby/core/enumerator/lazy/lazy_spec.rb
index b43864b673..12107383d6 100644
--- a/spec/ruby/core/enumerator/lazy/lazy_spec.rb
+++ b/spec/ruby/core/enumerator/lazy/lazy_spec.rb
@@ -4,24 +4,24 @@ require_relative '../../../spec_helper'
describe "Enumerator::Lazy" do
it "is a subclass of Enumerator" do
- Enumerator::Lazy.superclass.should equal(Enumerator)
+ Enumerator::Lazy.superclass.should.equal?(Enumerator)
end
it "defines lazy versions of a whitelist of Enumerator methods" do
- lazy_methods = [
+ lazy_methods = Set[
:chunk, :chunk_while, :collect, :collect_concat, :compact, :drop, :drop_while, :enum_for,
:find_all, :flat_map, :force, :grep, :grep_v, :lazy, :map, :reject,
:select, :slice_after, :slice_before, :slice_when, :take, :take_while,
:to_enum, :uniq, :zip
]
- Enumerator::Lazy.instance_methods(false).should include(*lazy_methods)
+ Enumerator::Lazy.instance_methods(false).to_set.should >= lazy_methods
end
end
describe "Enumerator::Lazy#lazy" do
it "returns self" do
lazy = (1..3).to_enum.lazy
- lazy.lazy.should equal(lazy)
+ lazy.lazy.should.equal?(lazy)
end
end
diff --git a/spec/ruby/core/enumerator/lazy/map_spec.rb b/spec/ruby/core/enumerator/lazy/map_spec.rb
index 5cb998f5f7..2c7f8efab8 100644
--- a/spec/ruby/core/enumerator/lazy/map_spec.rb
+++ b/spec/ruby/core/enumerator/lazy/map_spec.rb
@@ -1,10 +1,62 @@
-# -*- encoding: us-ascii -*-
-
require_relative '../../../spec_helper'
-require_relative 'shared/collect'
+require_relative 'fixtures/classes'
describe "Enumerator::Lazy#map" do
- it_behaves_like :enumerator_lazy_collect, :map
+ before :each do
+ @yieldsmixed = EnumeratorLazySpecs::YieldsMixed.new.to_enum.lazy
+ @eventsmixed = EnumeratorLazySpecs::EventsMixed.new.to_enum.lazy
+ ScratchPad.record []
+ end
+
+ after :each do
+ ScratchPad.clear
+ end
+
+ it "returns a new instance of Enumerator::Lazy" do
+ ret = @yieldsmixed.map {}
+ ret.should.instance_of?(Enumerator::Lazy)
+ ret.should_not.equal?(@yieldsmixed)
+ end
+
+ it "keeps size" do
+ Enumerator::Lazy.new(Object.new, 100) {}.map {}.size.should == 100
+ end
+
+ describe "when the returned lazy enumerator is evaluated by Enumerable#first" do
+ it "stops after specified times" do
+ (0..Float::INFINITY).lazy.map(&:succ).first(3).should == [1, 2, 3]
+
+ @eventsmixed.map {}.first(1)
+ ScratchPad.recorded.should == [:before_yield]
+ end
+ end
+
+ it "calls the block with initial values when yield with multiple arguments" do
+ yields = []
+ @yieldsmixed.map { |v| yields << v }.force
+ yields.should == EnumeratorLazySpecs::YieldsMixed.initial_yields
+ end
+
+ describe "on a nested Lazy" do
+ it "keeps size" do
+ Enumerator::Lazy.new(Object.new, 100) {}.map {}.map {}.size.should == 100
+ end
+
+ describe "when the returned lazy enumerator is evaluated by Enumerable#first" do
+ it "stops after specified times" do
+ (0..Float::INFINITY).lazy.map(&:succ).map(&:succ).first(3).should == [2, 3, 4]
+
+ @eventsmixed.map {}.map {}.first(1)
+ ScratchPad.recorded.should == [:before_yield]
+ end
+ end
+ end
+
+ it "works with an infinite enumerable" do
+ s = 0..Float::INFINITY
+ s.lazy.map { |n| n }.first(100).should ==
+ s.first(100).map { |n| n }.to_a
+ end
it "doesn't unwrap Arrays" do
Enumerator.new {|y| y.yield([1])}.lazy.to_a.should == [[1]]
diff --git a/spec/ruby/core/enumerator/lazy/reject_spec.rb b/spec/ruby/core/enumerator/lazy/reject_spec.rb
index 0e1632d667..374d4df14e 100644
--- a/spec/ruby/core/enumerator/lazy/reject_spec.rb
+++ b/spec/ruby/core/enumerator/lazy/reject_spec.rb
@@ -16,8 +16,8 @@ describe "Enumerator::Lazy#reject" do
it "returns a new instance of Enumerator::Lazy" do
ret = @yieldsmixed.reject {}
- ret.should be_an_instance_of(Enumerator::Lazy)
- ret.should_not equal(@yieldsmixed)
+ ret.should.instance_of?(Enumerator::Lazy)
+ ret.should_not.equal?(@yieldsmixed)
end
it "sets #size to nil" do
@@ -42,7 +42,7 @@ describe "Enumerator::Lazy#reject" do
-> {
lazy.first
- }.should raise_error(RuntimeError, "foo")
+ }.should.raise(RuntimeError, "foo")
end
it "calls the block with a gathered array when yield with multiple arguments" do
@@ -52,7 +52,7 @@ describe "Enumerator::Lazy#reject" do
end
it "raises an ArgumentError when not given a block" do
- -> { @yieldsmixed.reject }.should raise_error(ArgumentError)
+ -> { @yieldsmixed.reject }.should.raise(ArgumentError)
end
describe "on a nested Lazy" do
diff --git a/spec/ruby/core/enumerator/lazy/select_spec.rb b/spec/ruby/core/enumerator/lazy/select_spec.rb
index 3773d8f0a8..29c8f1bd80 100644
--- a/spec/ruby/core/enumerator/lazy/select_spec.rb
+++ b/spec/ruby/core/enumerator/lazy/select_spec.rb
@@ -1,10 +1,66 @@
-# -*- encoding: us-ascii -*-
-
require_relative '../../../spec_helper'
-require_relative 'shared/select'
+require_relative 'fixtures/classes'
describe "Enumerator::Lazy#select" do
- it_behaves_like :enumerator_lazy_select, :select
+ before :each do
+ @yieldsmixed = EnumeratorLazySpecs::YieldsMixed.new.to_enum.lazy
+ @eventsmixed = EnumeratorLazySpecs::EventsMixed.new.to_enum.lazy
+ ScratchPad.record []
+ end
+
+ after :each do
+ ScratchPad.clear
+ end
+
+ it "returns a new instance of Enumerator::Lazy" do
+ ret = @yieldsmixed.select {}
+ ret.should.instance_of?(Enumerator::Lazy)
+ ret.should_not.equal?(@yieldsmixed)
+ end
+
+ it "sets #size to nil" do
+ Enumerator::Lazy.new(Object.new, 100) {}.select { true }.size.should == nil
+ end
+
+ describe "when the returned lazy enumerator is evaluated by Enumerable#first" do
+ it "stops after specified times" do
+ (0..Float::INFINITY).lazy.select(&:even?).first(3).should == [0, 2, 4]
+
+ @eventsmixed.select { true }.first(1)
+ ScratchPad.recorded.should == [:before_yield]
+ end
+ end
+
+ it "calls the block with a gathered array when yield with multiple arguments" do
+ yields = []
+ @yieldsmixed.select { |v| yields << v }.force
+ yields.should == EnumeratorLazySpecs::YieldsMixed.gathered_yields
+ end
+
+ it "raises an ArgumentError when not given a block" do
+ -> { @yieldsmixed.select }.should.raise(ArgumentError)
+ end
+
+ describe "on a nested Lazy" do
+ it "sets #size to nil" do
+ Enumerator::Lazy.new(Object.new, 100) {}.take(50) {}.select { true }.size.should == nil
+ end
+
+ describe "when the returned lazy enumerator is evaluated by Enumerable#first" do
+ it "stops after specified times" do
+ (0..Float::INFINITY).lazy.select { |n| n > 5 }.select(&:even?).first(3).should == [6, 8, 10]
+
+ @eventsmixed.select { true }.select { true }.first(1)
+ ScratchPad.recorded.should == [:before_yield]
+ end
+ end
+ end
+
+ it "works with an infinite enumerable" do
+ s = 0..Float::INFINITY
+ s.lazy.select { |n| true }.first(100).should ==
+ s.first(100).select { |n| true }
+ end
it "doesn't pre-evaluate the next element" do
eval_count = 0
diff --git a/spec/ruby/core/enumerator/lazy/shared/collect.rb b/spec/ruby/core/enumerator/lazy/shared/collect.rb
deleted file mode 100644
index 5690255a0c..0000000000
--- a/spec/ruby/core/enumerator/lazy/shared/collect.rb
+++ /dev/null
@@ -1,62 +0,0 @@
-# -*- encoding: us-ascii -*-
-
-require_relative '../../../../spec_helper'
-require_relative '../fixtures/classes'
-
-describe :enumerator_lazy_collect, shared: true do
- before :each do
- @yieldsmixed = EnumeratorLazySpecs::YieldsMixed.new.to_enum.lazy
- @eventsmixed = EnumeratorLazySpecs::EventsMixed.new.to_enum.lazy
- ScratchPad.record []
- end
-
- after :each do
- ScratchPad.clear
- end
-
- it "returns a new instance of Enumerator::Lazy" do
- ret = @yieldsmixed.send(@method) {}
- ret.should be_an_instance_of(Enumerator::Lazy)
- ret.should_not equal(@yieldsmixed)
- end
-
- it "keeps size" do
- Enumerator::Lazy.new(Object.new, 100) {}.send(@method) {}.size.should == 100
- end
-
- describe "when the returned lazy enumerator is evaluated by Enumerable#first" do
- it "stops after specified times" do
- (0..Float::INFINITY).lazy.send(@method, &:succ).first(3).should == [1, 2, 3]
-
- @eventsmixed.send(@method) {}.first(1)
- ScratchPad.recorded.should == [:before_yield]
- end
- end
-
- it "calls the block with initial values when yield with multiple arguments" do
- yields = []
- @yieldsmixed.send(@method) { |v| yields << v }.force
- yields.should == EnumeratorLazySpecs::YieldsMixed.initial_yields
- end
-
- describe "on a nested Lazy" do
- it "keeps size" do
- Enumerator::Lazy.new(Object.new, 100) {}.send(@method) {}.send(@method) {}.size.should == 100
- end
-
- describe "when the returned lazy enumerator is evaluated by Enumerable#first" do
- it "stops after specified times" do
- (0..Float::INFINITY).lazy.send(@method, &:succ).send(@method, &:succ).first(3).should == [2, 3, 4]
-
- @eventsmixed.send(@method) {}.send(@method) {}.first(1)
- ScratchPad.recorded.should == [:before_yield]
- end
- end
- end
-
- it "works with an infinite enumerable" do
- s = 0..Float::INFINITY
- s.lazy.send(@method) { |n| n }.first(100).should ==
- s.first(100).send(@method) { |n| n }.to_a
- end
-end
diff --git a/spec/ruby/core/enumerator/lazy/shared/collect_concat.rb b/spec/ruby/core/enumerator/lazy/shared/collect_concat.rb
deleted file mode 100644
index 00d7941a61..0000000000
--- a/spec/ruby/core/enumerator/lazy/shared/collect_concat.rb
+++ /dev/null
@@ -1,78 +0,0 @@
-# -*- encoding: us-ascii -*-
-
-require_relative '../../../../spec_helper'
-require_relative '../fixtures/classes'
-
-describe :enumerator_lazy_collect_concat, shared: true do
- before :each do
- @yieldsmixed = EnumeratorLazySpecs::YieldsMixed.new.to_enum.lazy
- @eventsmixed = EnumeratorLazySpecs::EventsMixed.new.to_enum.lazy
- ScratchPad.record []
- end
-
- after :each do
- ScratchPad.clear
- end
-
- it "returns a new instance of Enumerator::Lazy" do
- ret = @yieldsmixed.send(@method) {}
- ret.should be_an_instance_of(Enumerator::Lazy)
- ret.should_not equal(@yieldsmixed)
- end
-
- it "sets #size to nil" do
- Enumerator::Lazy.new(Object.new, 100) {}.send(@method) { true }.size.should == nil
- end
-
- describe "when the returned lazy enumerator is evaluated by Enumerable#first" do
- it "stops after specified times" do
- (0..Float::INFINITY).lazy.send(@method) { |n| (n * 10).to_s }.first(6).should == %w[0 10 20 30 40 50]
-
- @eventsmixed.send(@method) {}.first(1)
- ScratchPad.recorded.should == [:before_yield]
- end
-
- it "flattens elements when the given block returned an array or responding to .each and .force" do
- (0..Float::INFINITY).lazy.send(@method) { |n| (n * 10).to_s.chars }.first(6).should == %w[0 1 0 2 0 3]
- (0..Float::INFINITY).lazy.send(@method) { |n| (n * 10).to_s.each_char }.first(6).all? { |o| o.instance_of? Enumerator }.should be_true
- (0..Float::INFINITY).lazy.send(@method) { |n| (n * 10).to_s.each_char.lazy }.first(6).should == %w[0 1 0 2 0 3]
- end
- end
-
- it "calls the block with initial values when yield with multiple arguments" do
- yields = []
- @yieldsmixed.send(@method) { |v| yields << v }.force
- yields.should == EnumeratorLazySpecs::YieldsMixed.initial_yields
- end
-
- it "raises an ArgumentError when not given a block" do
- -> { @yieldsmixed.send(@method) }.should raise_error(ArgumentError)
- end
-
- describe "on a nested Lazy" do
- it "sets #size to nil" do
- Enumerator::Lazy.new(Object.new, 100) {}.take(50) {}.send(@method) {}.size.should == nil
- end
-
- describe "when the returned lazy enumerator is evaluated by Enumerable#first" do
- it "stops after specified times" do
- (0..Float::INFINITY).lazy.map {|n| n * 10 }.send(@method) { |n| n.to_s }.first(6).should == %w[0 10 20 30 40 50]
-
- @eventsmixed.send(@method) {}.send(@method) {}.first(1)
- ScratchPad.recorded.should == [:before_yield]
- end
-
- it "flattens elements when the given block returned an array or responding to .each and .force" do
- (0..Float::INFINITY).lazy.map {|n| n * 10 }.send(@method) { |n| n.to_s.chars }.first(6).should == %w[0 1 0 2 0 3]
- (0..Float::INFINITY).lazy.map {|n| n * 10 }.send(@method) { |n| n.to_s.each_char }.first(6).all? { |o| o.instance_of? Enumerator }.should be_true
- (0..Float::INFINITY).lazy.map {|n| n * 10 }.send(@method) { |n| n.to_s.each_char.lazy }.first(6).should == %w[0 1 0 2 0 3]
- end
- end
- end
-
- it "works with an infinite enumerable" do
- s = 0..Float::INFINITY
- s.lazy.send(@method) { |n| [-n, +n] }.first(200).should ==
- s.first(100).send(@method) { |n| [-n, +n] }.to_a
- end
-end
diff --git a/spec/ruby/core/enumerator/lazy/shared/select.rb b/spec/ruby/core/enumerator/lazy/shared/select.rb
deleted file mode 100644
index 50a00bcbf4..0000000000
--- a/spec/ruby/core/enumerator/lazy/shared/select.rb
+++ /dev/null
@@ -1,66 +0,0 @@
-# -*- encoding: us-ascii -*-
-
-require_relative '../../../../spec_helper'
-require_relative '../fixtures/classes'
-
-describe :enumerator_lazy_select, shared: true do
- before :each do
- @yieldsmixed = EnumeratorLazySpecs::YieldsMixed.new.to_enum.lazy
- @eventsmixed = EnumeratorLazySpecs::EventsMixed.new.to_enum.lazy
- ScratchPad.record []
- end
-
- after :each do
- ScratchPad.clear
- end
-
- it "returns a new instance of Enumerator::Lazy" do
- ret = @yieldsmixed.send(@method) {}
- ret.should be_an_instance_of(Enumerator::Lazy)
- ret.should_not equal(@yieldsmixed)
- end
-
- it "sets #size to nil" do
- Enumerator::Lazy.new(Object.new, 100) {}.send(@method) { true }.size.should == nil
- end
-
- describe "when the returned lazy enumerator is evaluated by Enumerable#first" do
- it "stops after specified times" do
- (0..Float::INFINITY).lazy.send(@method, &:even?).first(3).should == [0, 2, 4]
-
- @eventsmixed.send(@method) { true }.first(1)
- ScratchPad.recorded.should == [:before_yield]
- end
- end
-
- it "calls the block with a gathered array when yield with multiple arguments" do
- yields = []
- @yieldsmixed.send(@method) { |v| yields << v }.force
- yields.should == EnumeratorLazySpecs::YieldsMixed.gathered_yields
- end
-
- it "raises an ArgumentError when not given a block" do
- -> { @yieldsmixed.send(@method) }.should raise_error(ArgumentError)
- end
-
- describe "on a nested Lazy" do
- it "sets #size to nil" do
- Enumerator::Lazy.new(Object.new, 100) {}.take(50) {}.send(@method) { true }.size.should == nil
- end
-
- describe "when the returned lazy enumerator is evaluated by Enumerable#first" do
- it "stops after specified times" do
- (0..Float::INFINITY).lazy.send(@method) { |n| n > 5 }.send(@method, &:even?).first(3).should == [6, 8, 10]
-
- @eventsmixed.send(@method) { true }.send(@method) { true }.first(1)
- ScratchPad.recorded.should == [:before_yield]
- end
- end
- end
-
- it "works with an infinite enumerable" do
- s = 0..Float::INFINITY
- s.lazy.send(@method) { |n| true }.first(100).should ==
- s.first(100).send(@method) { |n| true }
- end
-end
diff --git a/spec/ruby/core/enumerator/lazy/shared/to_enum.rb b/spec/ruby/core/enumerator/lazy/shared/to_enum.rb
deleted file mode 100644
index 0c91ea55b9..0000000000
--- a/spec/ruby/core/enumerator/lazy/shared/to_enum.rb
+++ /dev/null
@@ -1,55 +0,0 @@
-# -*- encoding: us-ascii -*-
-
-require_relative '../../../../spec_helper'
-
-describe :enumerator_lazy_to_enum, shared: true do
- before :each do
- @infinite = (0..Float::INFINITY).lazy
- end
-
- it "requires multiple arguments" do
- Enumerator::Lazy.instance_method(@method).arity.should < 0
- end
-
- it "returns a new instance of Enumerator::Lazy" do
- ret = @infinite.send @method
- ret.should be_an_instance_of(Enumerator::Lazy)
- ret.should_not equal(@infinite)
- end
-
- it "sets #size to nil when not given a block" do
- Enumerator::Lazy.new(Object.new, 100) {}.send(@method).size.should == nil
- end
-
- it "sets given block to size when given a block" do
- Enumerator::Lazy.new(Object.new, 100) {}.send(@method) { 30 }.size.should == 30
- end
-
- it "generates a lazy enumerator from the given name" do
- @infinite.send(@method, :with_index, 10).first(3).should == [[0, 10], [1, 11], [2, 12]]
- end
-
- it "passes given arguments to wrapped method" do
- @infinite.send(@method, :each_slice, 2).map { |assoc| assoc.first * assoc.last }.first(4).should == [0, 6, 20, 42]
- end
-
- it "used by some parent's methods though returning Lazy" do
- { each_with_index: [],
- with_index: [],
- cycle: [1],
- each_with_object: [Object.new],
- with_object: [Object.new],
- each_slice: [2],
- each_entry: [],
- each_cons: [2]
- }.each_pair do |method, args|
- @infinite.send(method, *args).should be_an_instance_of(Enumerator::Lazy)
- end
- end
-
- it "works with an infinite enumerable" do
- s = 0..Float::INFINITY
- s.lazy.send(@method, :with_index).first(100).should ==
- s.first(100).to_enum.send(@method, :with_index).to_a
- end
-end
diff --git a/spec/ruby/core/enumerator/lazy/slice_after_spec.rb b/spec/ruby/core/enumerator/lazy/slice_after_spec.rb
index 8b08a1ecfd..f8cd97178f 100644
--- a/spec/ruby/core/enumerator/lazy/slice_after_spec.rb
+++ b/spec/ruby/core/enumerator/lazy/slice_after_spec.rb
@@ -9,6 +9,6 @@ describe "Enumerator::Lazy#slice_after" do
it "should return a lazy enumerator" do
s = 0..Float::INFINITY
- s.lazy.slice_after { |n| true }.should be_kind_of(Enumerator::Lazy)
+ s.lazy.slice_after { |n| true }.should.is_a?(Enumerator::Lazy)
end
end
diff --git a/spec/ruby/core/enumerator/lazy/slice_before_spec.rb b/spec/ruby/core/enumerator/lazy/slice_before_spec.rb
index 9c1ec9ba4a..192e853343 100644
--- a/spec/ruby/core/enumerator/lazy/slice_before_spec.rb
+++ b/spec/ruby/core/enumerator/lazy/slice_before_spec.rb
@@ -9,6 +9,6 @@ describe "Enumerator::Lazy#slice_before" do
it "should return a lazy enumerator" do
s = 0..Float::INFINITY
- s.lazy.slice_before { |n| true }.should be_kind_of(Enumerator::Lazy)
+ s.lazy.slice_before { |n| true }.should.is_a?(Enumerator::Lazy)
end
end
diff --git a/spec/ruby/core/enumerator/lazy/slice_when_spec.rb b/spec/ruby/core/enumerator/lazy/slice_when_spec.rb
index f83403425d..fc9d5f5069 100644
--- a/spec/ruby/core/enumerator/lazy/slice_when_spec.rb
+++ b/spec/ruby/core/enumerator/lazy/slice_when_spec.rb
@@ -9,6 +9,6 @@ describe "Enumerator::Lazy#slice_when" do
it "should return a lazy enumerator" do
s = 0..Float::INFINITY
- s.lazy.slice_when { |a, b| true }.should be_kind_of(Enumerator::Lazy)
+ s.lazy.slice_when { |a, b| true }.should.is_a?(Enumerator::Lazy)
end
end
diff --git a/spec/ruby/core/enumerator/lazy/take_spec.rb b/spec/ruby/core/enumerator/lazy/take_spec.rb
index 9fc17e969f..2dd5b939e2 100644
--- a/spec/ruby/core/enumerator/lazy/take_spec.rb
+++ b/spec/ruby/core/enumerator/lazy/take_spec.rb
@@ -2,8 +2,16 @@
require_relative '../../../spec_helper'
require_relative 'fixtures/classes'
+require_relative '../../enumerable/shared/value_packing'
describe "Enumerator::Lazy#take" do
+ describe "value packing of source yields (matches Enumerable#take)" do
+ before :each do
+ @take = -> e { e.lazy.take(1) }
+ end
+ it_behaves_like :enumerable_value_packing, nil
+ end
+
before :each do
@yieldsmixed = EnumeratorLazySpecs::YieldsMixed.new.to_enum.lazy
@eventsmixed = EnumeratorLazySpecs::EventsMixed.new.to_enum.lazy
@@ -16,8 +24,8 @@ describe "Enumerator::Lazy#take" do
it "returns a new instance of Enumerator::Lazy" do
ret = @yieldsmixed.take(1)
- ret.should be_an_instance_of(Enumerator::Lazy)
- ret.should_not equal(@yieldsmixed)
+ ret.should.instance_of?(Enumerator::Lazy)
+ ret.should_not.equal?(@yieldsmixed)
end
it "sets given count to size if the given count is less than old size" do
diff --git a/spec/ruby/core/enumerator/lazy/take_while_spec.rb b/spec/ruby/core/enumerator/lazy/take_while_spec.rb
index bcea0b1419..c369712c56 100644
--- a/spec/ruby/core/enumerator/lazy/take_while_spec.rb
+++ b/spec/ruby/core/enumerator/lazy/take_while_spec.rb
@@ -16,8 +16,8 @@ describe "Enumerator::Lazy#take_while" do
it "returns a new instance of Enumerator::Lazy" do
ret = @yieldsmixed.take_while {}
- ret.should be_an_instance_of(Enumerator::Lazy)
- ret.should_not equal(@yieldsmixed)
+ ret.should.instance_of?(Enumerator::Lazy)
+ ret.should_not.equal?(@yieldsmixed)
end
it "sets #size to nil" do
@@ -40,7 +40,7 @@ describe "Enumerator::Lazy#take_while" do
end
it "raises an ArgumentError when not given a block" do
- -> { @yieldsmixed.take_while }.should raise_error(ArgumentError)
+ -> { @yieldsmixed.take_while }.should.raise(ArgumentError)
end
describe "on a nested Lazy" do
diff --git a/spec/ruby/core/enumerator/lazy/to_enum_spec.rb b/spec/ruby/core/enumerator/lazy/to_enum_spec.rb
index 210e5294b7..c0233d60fa 100644
--- a/spec/ruby/core/enumerator/lazy/to_enum_spec.rb
+++ b/spec/ruby/core/enumerator/lazy/to_enum_spec.rb
@@ -1,8 +1,54 @@
-# -*- encoding: us-ascii -*-
-
require_relative '../../../spec_helper'
-require_relative 'shared/to_enum'
+require_relative 'fixtures/classes'
describe "Enumerator::Lazy#to_enum" do
- it_behaves_like :enumerator_lazy_to_enum, :to_enum
+ before :each do
+ @infinite = (0..Float::INFINITY).lazy
+ end
+
+ it "requires multiple arguments" do
+ Enumerator::Lazy.instance_method(:to_enum).arity.should < 0
+ end
+
+ it "returns a new instance of Enumerator::Lazy" do
+ ret = @infinite.to_enum
+ ret.should.instance_of?(Enumerator::Lazy)
+ ret.should_not.equal?(@infinite)
+ end
+
+ it "sets #size to nil when not given a block" do
+ Enumerator::Lazy.new(Object.new, 100) {}.to_enum.size.should == nil
+ end
+
+ it "sets given block to size when given a block" do
+ Enumerator::Lazy.new(Object.new, 100) {}.to_enum { 30 }.size.should == 30
+ end
+
+ it "generates a lazy enumerator from the given name" do
+ @infinite.to_enum(:with_index, 10).first(3).should == [[0, 10], [1, 11], [2, 12]]
+ end
+
+ it "passes given arguments to wrapped method" do
+ @infinite.to_enum(:each_slice, 2).map { |assoc| assoc.first * assoc.last }.first(4).should == [0, 6, 20, 42]
+ end
+
+ it "used by some parent's methods though returning Lazy" do
+ { each_with_index: [],
+ with_index: [],
+ cycle: [1],
+ each_with_object: [Object.new],
+ with_object: [Object.new],
+ each_slice: [2],
+ each_entry: [],
+ each_cons: [2]
+ }.each_pair do |method, args|
+ @infinite.send(method, *args).should.instance_of?(Enumerator::Lazy)
+ end
+ end
+
+ it "works with an infinite enumerable" do
+ s = 0..Float::INFINITY
+ s.lazy.to_enum(:with_index).first(100).should ==
+ s.first(100).to_enum.to_enum(:with_index).to_a
+ end
end
diff --git a/spec/ruby/core/enumerator/lazy/uniq_spec.rb b/spec/ruby/core/enumerator/lazy/uniq_spec.rb
index ce67ace5ab..d30ed8df2f 100644
--- a/spec/ruby/core/enumerator/lazy/uniq_spec.rb
+++ b/spec/ruby/core/enumerator/lazy/uniq_spec.rb
@@ -8,7 +8,7 @@ describe 'Enumerator::Lazy#uniq' do
end
it 'returns a lazy enumerator' do
- @lazy.should be_an_instance_of(Enumerator::Lazy)
+ @lazy.should.instance_of?(Enumerator::Lazy)
@lazy.force.should == [0, 1]
end
@@ -28,7 +28,7 @@ describe 'Enumerator::Lazy#uniq' do
end
it 'returns a lazy enumerator' do
- @lazy.should be_an_instance_of(Enumerator::Lazy)
+ @lazy.should.instance_of?(Enumerator::Lazy)
@lazy.force.should == [0, 1]
end
diff --git a/spec/ruby/core/enumerator/lazy/with_index_spec.rb b/spec/ruby/core/enumerator/lazy/with_index_spec.rb
index a6b5c38777..2e983fd3b1 100644
--- a/spec/ruby/core/enumerator/lazy/with_index_spec.rb
+++ b/spec/ruby/core/enumerator/lazy/with_index_spec.rb
@@ -17,7 +17,7 @@ describe "Enumerator::Lazy#with_index" do
end
it "raises TypeError when offset does not convert to Integer" do
- -> { (0..Float::INFINITY).lazy.with_index(false).map { |i, idx| i }.first(3) }.should raise_error(TypeError)
+ -> { (0..Float::INFINITY).lazy.with_index(false).map { |i, idx| i }.first(3) }.should.raise(TypeError)
end
it "enumerates with a given block" do
diff --git a/spec/ruby/core/enumerator/lazy/zip_spec.rb b/spec/ruby/core/enumerator/lazy/zip_spec.rb
index 5a828c1dcc..9f612542d7 100644
--- a/spec/ruby/core/enumerator/lazy/zip_spec.rb
+++ b/spec/ruby/core/enumerator/lazy/zip_spec.rb
@@ -16,8 +16,8 @@ describe "Enumerator::Lazy#zip" do
it "returns a new instance of Enumerator::Lazy" do
ret = @yieldsmixed.zip []
- ret.should be_an_instance_of(Enumerator::Lazy)
- ret.should_not equal(@yieldsmixed)
+ ret.should.instance_of?(Enumerator::Lazy)
+ ret.should_not.equal?(@yieldsmixed)
end
it "keeps size" do
@@ -40,11 +40,11 @@ describe "Enumerator::Lazy#zip" do
end
it "returns a Lazy when no arguments given" do
- @yieldsmixed.zip.should be_an_instance_of(Enumerator::Lazy)
+ @yieldsmixed.zip.should.instance_of?(Enumerator::Lazy)
end
it "raises a TypeError if arguments contain non-list object" do
- -> { @yieldsmixed.zip [], Object.new, [] }.should raise_error(TypeError)
+ -> { @yieldsmixed.zip [], Object.new, [] }.should.raise(TypeError)
end
describe "on a nested Lazy" do
diff --git a/spec/ruby/core/enumerator/new_spec.rb b/spec/ruby/core/enumerator/new_spec.rb
index 671912224f..eb6c13759e 100644
--- a/spec/ruby/core/enumerator/new_spec.rb
+++ b/spec/ruby/core/enumerator/new_spec.rb
@@ -3,7 +3,7 @@ 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)
+ -> { Enumerator.new(1, :upto, 3) }.should.raise(ArgumentError)
end
end
@@ -42,35 +42,74 @@ describe "Enumerator.new" do
enum.to_a.should == ["a\n", "b\n", "c"]
end
- describe 'yielded values' do
- it 'handles yield arguments properly' do
+ describe '#yield' do
+ it 'accepts a single argument' do
Enumerator.new { |y| y.yield(1) }.to_a.should == [1]
Enumerator.new { |y| y.yield(1) }.first.should == 1
+ end
- Enumerator.new { |y| y.yield([1]) }.to_a.should == [[1]]
- Enumerator.new { |y| y.yield([1]) }.first.should == [1]
-
+ it 'accepts multiple arguments' do
Enumerator.new { |y| y.yield(1, 2) }.to_a.should == [[1, 2]]
Enumerator.new { |y| y.yield(1, 2) }.first.should == [1, 2]
+ end
+
+ it "doesn't double-wrap arrays" do
+ Enumerator.new { |y| y.yield([1]) }.to_a.should == [[1]]
+ Enumerator.new { |y| y.yield([1]) }.first.should == [1]
Enumerator.new { |y| y.yield([1, 2]) }.to_a.should == [[1, 2]]
Enumerator.new { |y| y.yield([1, 2]) }.first.should == [1, 2]
end
- it 'handles << arguments properly' do
+ it 'returns nil' do
+ ScratchPad.record []
+ Enumerator.new do |y|
+ ScratchPad << y.yield(1)
+ end.to_a
+
+ ScratchPad.recorded.should == [nil]
+ end
+
+ it 'accepts keyword arguments and treats them as a positional hash' do
+ Enumerator.new { |y| y.yield(foo: 42) }.to_a.should == [{ foo: 42 }]
+ Enumerator.new { |y| y.yield(foo: 42) }.first.should == { foo: 42 }
+
+ Enumerator.new { |y| y.yield(123, foo: 42) }.to_a.should == [[123, { foo: 42 }]]
+ Enumerator.new { |y| y.yield(123, foo: 42) }.first.should == [123, { foo: 42 }]
+ end
+ end
+
+ describe '#<<' do
+ it 'accepts a single argument' do
Enumerator.new { |y| y.<<(1) }.to_a.should == [1]
Enumerator.new { |y| y.<<(1) }.first.should == 1
+ end
+ it "doesn't double-wrap arrays" do
Enumerator.new { |y| y.<<([1]) }.to_a.should == [[1]]
Enumerator.new { |y| y.<<([1]) }.first.should == [1]
- # << doesn't accept multiple arguments
- # Enumerator.new { |y| y.<<(1, 2) }.to_a.should == [[1, 2]]
- # Enumerator.new { |y| y.<<(1, 2) }.first.should == [1, 2]
-
Enumerator.new { |y| y.<<([1, 2]) }.to_a.should == [[1, 2]]
Enumerator.new { |y| y.<<([1, 2]) }.first.should == [1, 2]
end
+
+ it 'accepts keyword arguments and treats them as a positional hash' do
+ Enumerator.new { |y| y.<<(foo: 42) }.to_a.should == [{ foo: 42 }]
+ Enumerator.new { |y| y.<<(foo: 42) }.first.should == { foo: 42 }
+ end
+
+ it 'can be chained' do
+ enum = Enumerator.new do |y|
+ y << 1 << 2
+ end
+ enum.to_a.should == [1, 2]
+ end
+
+ it 'raises ArgumentError when given more than one argument' do
+ -> {
+ Enumerator.new { |y| y.<<(1, 2) }.to_a
+ }.should.raise(ArgumentError, "wrong number of arguments (given 2, expected 1)")
+ end
end
end
end
diff --git a/spec/ruby/core/enumerator/next_spec.rb b/spec/ruby/core/enumerator/next_spec.rb
index a5e01a399d..77e79185a9 100644
--- a/spec/ruby/core/enumerator/next_spec.rb
+++ b/spec/ruby/core/enumerator/next_spec.rb
@@ -13,14 +13,14 @@ describe "Enumerator#next" do
it "raises a StopIteration exception at the end of the stream" do
3.times { @enum.next }
- -> { @enum.next }.should raise_error(StopIteration)
+ -> { @enum.next }.should.raise(StopIteration)
end
it "cannot be called again until the enumerator is rewound" do
3.times { @enum.next }
- -> { @enum.next }.should raise_error(StopIteration)
- -> { @enum.next }.should raise_error(StopIteration)
- -> { @enum.next }.should raise_error(StopIteration)
+ -> { @enum.next }.should.raise(StopIteration)
+ -> { @enum.next }.should.raise(StopIteration)
+ -> { @enum.next }.should.raise(StopIteration)
@enum.rewind
@enum.next.should == 1
end
diff --git a/spec/ruby/core/enumerator/next_values_spec.rb b/spec/ruby/core/enumerator/next_values_spec.rb
index 2202700c58..63e024e2b4 100644
--- a/spec/ruby/core/enumerator/next_values_spec.rb
+++ b/spec/ruby/core/enumerator/next_values_spec.rb
@@ -56,6 +56,6 @@ describe "Enumerator#next_values" do
it "raises StopIteration if called on a finished enumerator" do
8.times { @e.next }
- -> { @e.next_values }.should raise_error(StopIteration)
+ -> { @e.next_values }.should.raise(StopIteration)
end
end
diff --git a/spec/ruby/core/enumerator/peek_spec.rb b/spec/ruby/core/enumerator/peek_spec.rb
index 2334385437..096fd2b10c 100644
--- a/spec/ruby/core/enumerator/peek_spec.rb
+++ b/spec/ruby/core/enumerator/peek_spec.rb
@@ -31,6 +31,6 @@ describe "Enumerator#peek" do
it "raises StopIteration if called on a finished enumerator" do
5.times { @e.next }
- -> { @e.peek }.should raise_error(StopIteration)
+ -> { @e.peek }.should.raise(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..63f7988bcd 100644
--- a/spec/ruby/core/enumerator/peek_values_spec.rb
+++ b/spec/ruby/core/enumerator/peek_values_spec.rb
@@ -58,6 +58,6 @@ describe "Enumerator#peek_values" do
it "raises StopIteration if called on a finished enumerator" do
8.times { @e.next }
- -> { @e.peek_values }.should raise_error(StopIteration)
+ -> { @e.peek_values }.should.raise(StopIteration)
end
end
diff --git a/spec/ruby/core/enumerator/plus_spec.rb b/spec/ruby/core/enumerator/plus_spec.rb
index 755be5b4eb..d6c0fa93ac 100644
--- a/spec/ruby/core/enumerator/plus_spec.rb
+++ b/spec/ruby/core/enumerator/plus_spec.rb
@@ -12,7 +12,7 @@ describe "Enumerator#+" do
chain = one + two + three
- chain.should be_an_instance_of(Enumerator::Chain)
+ chain.should.instance_of?(Enumerator::Chain)
chain.each { |item| ScratchPad << item }
ScratchPad.recorded.should == [1, 2, 3]
end
diff --git a/spec/ruby/core/enumerator/produce_spec.rb b/spec/ruby/core/enumerator/produce_spec.rb
index c69fb49303..eb1b09294e 100644
--- a/spec/ruby/core/enumerator/produce_spec.rb
+++ b/spec/ruby/core/enumerator/produce_spec.rb
@@ -3,6 +3,8 @@ require_relative '../../spec_helper'
describe "Enumerator.produce" do
it "creates an infinite enumerator" do
enum = Enumerator.produce(0) { |prev| prev + 1 }
+
+ enum.size.should == Float::INFINITY
enum.take(5).should == [0, 1, 2, 3, 4]
end
@@ -31,4 +33,46 @@ describe "Enumerator.produce" do
lines.should == ["a\n", "b\n", "c\n", "d"]
end
end
+
+ it "raises ArgumentError when no block is given" do
+ -> { Enumerator.produce }.should.raise(ArgumentError, "no block given")
+ end
+
+ ruby_version_is ""..."4.0" do
+ it "accepts keyword arguments as the initial value" do
+ enum = Enumerator.produce(a: 1, b: 1) {}
+ enum.take(1).should == [{a: 1, b: 1}]
+ end
+ end
+
+ ruby_version_is "4.0" do
+ it "raises ArgumentError for unknown keyword arguments" do
+ -> { Enumerator.produce(a: 1, b: 1) {} }.should.raise(ArgumentError, /unknown keywords/)
+ end
+ end
+
+ ruby_version_is "4.0" do
+ context "with size keyword argument" do
+ it "sets the size of the enumerator" do
+ enum = Enumerator.produce(0, size: 10) { |n| n + 1 }
+
+ enum.size.should == 10
+ enum.take(5).should == [0, 1, 2, 3, 4]
+ end
+
+ it "accepts a callable" do
+ enum = Enumerator.produce(0, size: -> { 5 * 5 }) { |n| n + 1 }
+
+ enum.size.should == 25
+ enum.take(5).should == [0, 1, 2, 3, 4]
+ end
+
+ it "accepts nil" do
+ enum = Enumerator.produce(0, size: nil) { |n| n + 1 }
+
+ enum.size.should == nil
+ enum.take(5).should == [0, 1, 2, 3, 4]
+ end
+ end
+ end
end
diff --git a/spec/ruby/core/enumerator/product/each_spec.rb b/spec/ruby/core/enumerator/product/each_spec.rb
index 88f115a712..a5dced4db1 100644
--- a/spec/ruby/core/enumerator/product/each_spec.rb
+++ b/spec/ruby/core/enumerator/product/each_spec.rb
@@ -33,7 +33,7 @@ describe "Enumerator::Product#each" do
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/)
+ }.should.raise(NoMethodError, /undefined method [`']each_entry' for/)
end
it "returns enumerator if not given a block" do
@@ -68,4 +68,18 @@ describe "Enumerator::Product#each" do
enum.each { |x, y, z| acc << z }
acc.should == [nil, nil, nil, nil]
end
+
+ it "yields no element when any enumerable is empty" do
+ enum = Enumerator::Product.new([], [1])
+
+ acc = []
+ enum.each { |x| acc << x }
+ acc.should == []
+
+ enum = Enumerator::Product.new([1], [])
+
+ acc = []
+ enum.each { |x| acc << x }
+ acc.should == []
+ end
end
diff --git a/spec/ruby/core/enumerator/product/initialize_copy_spec.rb b/spec/ruby/core/enumerator/product/initialize_copy_spec.rb
index b1b9f3ca9b..b5d2b345a9 100644
--- a/spec/ruby/core/enumerator/product/initialize_copy_spec.rb
+++ b/spec/ruby/core/enumerator/product/initialize_copy_spec.rb
@@ -17,7 +17,7 @@ describe "Enumerator::Product#initialize_copy" do
end
it "is a private method" do
- Enumerator::Product.should have_private_instance_method(:initialize_copy, false)
+ Enumerator::Product.private_instance_methods(false).should.include?(:initialize_copy)
end
it "does nothing if the argument is the same as the receiver" do
@@ -32,21 +32,21 @@ describe "Enumerator::Product#initialize_copy" do
enum = Enumerator::Product.new(1..2)
enum2 = Enumerator::Product.new(3..4)
- -> { enum.freeze.send(:initialize_copy, enum2) }.should raise_error(FrozenError)
+ -> { enum.freeze.send(:initialize_copy, enum2) }.should.raise(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')
+ -> { enum.send(:initialize_copy, enum2) }.should.raise(TypeError, 'initialize_copy should take same class object')
+ -> { enum2.send(:initialize_copy, enum) }.should.raise(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')
+ -> { enum.send(:initialize_copy, enum2) }.should.raise(ArgumentError, 'uninitialized product')
end
end
diff --git a/spec/ruby/core/enumerator/product/initialize_spec.rb b/spec/ruby/core/enumerator/product/initialize_spec.rb
index ed2a8a2a13..8814f9d3c7 100644
--- a/spec/ruby/core/enumerator/product/initialize_spec.rb
+++ b/spec/ruby/core/enumerator/product/initialize_spec.rb
@@ -6,26 +6,26 @@ describe "Enumerator::Product#initialize" do
end
it "is a private method" do
- Enumerator::Product.should have_private_instance_method(:initialize, false)
+ Enumerator::Product.private_instance_methods(false).should.include?(:initialize)
end
it "returns self" do
- @uninitialized.send(:initialize).should equal(@uninitialized)
+ @uninitialized.send(:initialize).should.equal?(@uninitialized)
end
it "accepts many arguments" do
- @uninitialized.send(:initialize, 0..1, 2..3, 4..5).should equal(@uninitialized)
+ @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)
+ @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)
+ }.should.raise(FrozenError)
end
end
end
diff --git a/spec/ruby/core/enumerator/product/size_spec.rb b/spec/ruby/core/enumerator/product/size_spec.rb
index 96632d6eee..0ba427af9a 100644
--- a/spec/ruby/core/enumerator/product/size_spec.rb
+++ b/spec/ruby/core/enumerator/product/size_spec.rb
@@ -51,4 +51,14 @@ describe "Enumerator::Product#size" do
product = Enumerator::Product.new(1..2, enum)
product.size.should == nil
end
+
+ ruby_version_is "3.4" do
+ it "returns zero when any enumerable reports zero" do
+ enum = Enumerator::Product.new(1...1, ["A", "B"])
+ enum.size.should == 0
+
+ enum = Enumerator::Product.new(["A", "B"], 1...1)
+ enum.size.should == 0
+ end
+ end
end
diff --git a/spec/ruby/core/enumerator/product_spec.rb b/spec/ruby/core/enumerator/product_spec.rb
index 83c7cb8e0e..0f37ef76e7 100644
--- a/spec/ruby/core/enumerator/product_spec.rb
+++ b/spec/ruby/core/enumerator/product_spec.rb
@@ -51,7 +51,7 @@ describe "Enumerator.product" do
it "reject keyword arguments" do
-> {
Enumerator.product(1..3, foo: 1, bar: 2)
- }.should raise_error(ArgumentError, "unknown keywords: :foo, :bar")
+ }.should.raise(ArgumentError, "unknown keywords: :foo, :bar")
end
it "calls only #each_entry method on arguments" do
@@ -68,11 +68,11 @@ describe "Enumerator.product" do
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/)
+ }.should.raise(NoMethodError, /undefined method [`']each_entry' for/)
end
it "calls #each_entry lazily" do
- Enumerator.product(Object.new).should be_kind_of(Enumerator)
+ Enumerator.product(Object.new).should.is_a?(Enumerator)
end
it "iterates through consuming enumerator elements only once" do
diff --git a/spec/ruby/core/enumerator/shared/each.rb b/spec/ruby/core/enumerator/shared/each.rb
new file mode 100644
index 0000000000..18ca773207
--- /dev/null
+++ b/spec/ruby/core/enumerator/shared/each.rb
@@ -0,0 +1,46 @@
+# #each passes source-yielded values to the block by ordinary block arity
+# (rb_yield_values2 semantics in CRuby), unlike the Enumerable collection methods
+# which pack them via rb_enum_values_pack() (see enumerable/shared/value_packing.rb).
+describe :enum_each, shared: true do
+ # @object must be set to a Proc that wraps an Enumerator into the receiver
+ # under test (e.g. -> e { e } for Enumerator#each, -> e { e.lazy } for Lazy#each).
+ describe "with a source that yields multiple values" do
+ before :each do
+ @enum = @object.call(Enumerator.new { |y| y.yield 1, 2; y.yield 3, 4 })
+ end
+
+ it "yields the first value to a single-argument block" do
+ collected = []
+ @enum.each { |x| collected << x }
+ collected.should == [1, 3]
+ end
+
+ it "yields each value to a multi-argument block" do
+ collected = []
+ @enum.each { |x, y| collected << [x, y] }
+ collected.should == [[1, 2], [3, 4]]
+ end
+
+ it "gathers the values for a splat block" do
+ collected = []
+ @enum.each { |*args| collected << args }
+ collected.should == [[1, 2], [3, 4]]
+ end
+ end
+
+ describe "with a source that yields a single value" do
+ it "yields the value to a single-argument block" do
+ collected = []
+ @object.call(Enumerator.new { |y| y.yield 7; y.yield 8 }).each { |x| collected << x }
+ collected.should == [7, 8]
+ end
+ end
+
+ describe "with a source that yields no value" do
+ it "yields nil to a single-argument block" do
+ collected = []
+ @object.call(Enumerator.new { |y| y.yield; y.yield }).each { |x| collected << x }
+ collected.should == [nil, nil]
+ end
+ end
+end
diff --git a/spec/ruby/core/enumerator/shared/enum_for.rb b/spec/ruby/core/enumerator/shared/enum_for.rb
deleted file mode 100644
index a67a76c461..0000000000
--- a/spec/ruby/core/enumerator/shared/enum_for.rb
+++ /dev/null
@@ -1,57 +0,0 @@
-describe :enum_for, shared: true do
- it "is defined in Kernel" do
- Kernel.method_defined?(@method).should be_true
- end
-
- it "returns a new enumerator" do
- "abc".send(@method).should be_an_instance_of(Enumerator)
- end
-
- it "defaults the first argument to :each" do
- enum = [1,2].send(@method)
- enum.map { |v| v }.should == [1,2].each { |v| v }
- end
-
- it "sets regexp matches in the caller" do
- "wawa".send(@method, :scan, /./).map {|o| $& }.should == ["w", "a", "w", "a"]
- a = []
- "wawa".send(@method, :scan, /./).each {|o| a << $& }
- a.should == ["w", "a", "w", "a"]
- end
-
- it "exposes multi-arg yields as an array" do
- o = Object.new
- def o.each
- yield :a
- yield :b1, :b2
- yield [:c]
- yield :d1, :d2
- yield :e1, :e2, :e3
- end
-
- enum = o.send(@method)
- enum.next.should == :a
- enum.next.should == [:b1, :b2]
- enum.next.should == [:c]
- enum.next.should == [:d1, :d2]
- enum.next.should == [:e1, :e2, :e3]
- end
-
- it "uses the passed block's value to calculate the size of the enumerator" do
- Object.new.enum_for { 100 }.size.should == 100
- end
-
- it "defers the evaluation of the passed block until #size is called" do
- ScratchPad.record []
-
- enum = Object.new.enum_for do
- ScratchPad << :called
- 100
- end
-
- ScratchPad.recorded.should be_empty
-
- enum.size
- ScratchPad.recorded.should == [:called]
- end
-end
diff --git a/spec/ruby/core/enumerator/shared/with_index.rb b/spec/ruby/core/enumerator/shared/with_index.rb
index 78771ffe82..0992397e95 100644
--- a/spec/ruby/core/enumerator/shared/with_index.rb
+++ b/spec/ruby/core/enumerator/shared/with_index.rb
@@ -16,7 +16,7 @@ describe :enum_with_index, shared: true do
end
it "returns the object being enumerated when given a block" do
- @enum.send(@method) { |o, i| :glark }.should equal(@origin)
+ @enum.send(@method) { |o, i| :glark }.should.equal?(@origin)
end
it "binds splat arguments properly" do
@@ -27,7 +27,7 @@ describe :enum_with_index, shared: true do
it "returns an enumerator if no block is supplied" do
ewi = @enum.send(@method)
- ewi.should be_an_instance_of(Enumerator)
+ ewi.should.instance_of?(Enumerator)
ewi.to_a.should == [[1, 0], [2, 1], [3, 2], [4, 3]]
end
end
diff --git a/spec/ruby/core/enumerator/shared/with_object.rb b/spec/ruby/core/enumerator/shared/with_object.rb
deleted file mode 100644
index d8e9d8e9f7..0000000000
--- a/spec/ruby/core/enumerator/shared/with_object.rb
+++ /dev/null
@@ -1,42 +0,0 @@
-require_relative '../../../spec_helper'
-
-describe :enum_with_object, shared: true do
- before :each do
- @enum = [:a, :b].to_enum
- @memo = ''
- @block_params = @enum.send(@method, @memo).to_a
- end
-
- it "receives an argument" do
- @enum.method(@method).arity.should == 1
- end
-
- context "with block" do
- it "returns the given object" do
- ret = @enum.send(@method, @memo) do |elm, memo|
- # nothing
- end
- ret.should equal(@memo)
- end
-
- context "the block parameter" do
- it "passes each element to first parameter" do
- @block_params[0][0].should equal(:a)
- @block_params[1][0].should equal(:b)
- end
-
- it "passes the given object to last parameter" do
- @block_params[0][1].should equal(@memo)
- @block_params[1][1].should equal(@memo)
- end
- end
- end
-
- context "without block" do
- it "returns new Enumerator" do
- ret = @enum.send(@method, @memo)
- ret.should be_an_instance_of(Enumerator)
- ret.should_not equal(@enum)
- end
- end
-end
diff --git a/spec/ruby/core/enumerator/size_spec.rb b/spec/ruby/core/enumerator/size_spec.rb
index 6accd26a4e..4b2beffbbe 100644
--- a/spec/ruby/core/enumerator/size_spec.rb
+++ b/spec/ruby/core/enumerator/size_spec.rb
@@ -6,7 +6,7 @@ describe "Enumerator#size" do
end
it "returns nil if set size is nil" do
- Enumerator.new(nil) {}.size.should be_nil
+ Enumerator.new(nil) {}.size.should == nil
end
it "returns returning value from size.call if set size is a Proc" do
diff --git a/spec/ruby/core/enumerator/to_enum_spec.rb b/spec/ruby/core/enumerator/to_enum_spec.rb
deleted file mode 100644
index 7fb73d0c3c..0000000000
--- a/spec/ruby/core/enumerator/to_enum_spec.rb
+++ /dev/null
@@ -1,6 +0,0 @@
-require_relative '../../spec_helper'
-require_relative 'shared/enum_for'
-
-describe "Enumerator#to_enum" do
- it_behaves_like :enum_for, :to_enum
-end
diff --git a/spec/ruby/core/enumerator/with_index_spec.rb b/spec/ruby/core/enumerator/with_index_spec.rb
index e49aa7a939..ca90fd18f7 100644
--- a/spec/ruby/core/enumerator/with_index_spec.rb
+++ b/spec/ruby/core/enumerator/with_index_spec.rb
@@ -9,20 +9,20 @@ describe "Enumerator#with_index" do
it "returns a new Enumerator when no block is given" do
enum1 = [1,2,3].select
enum2 = enum1.with_index
- enum2.should be_an_instance_of(Enumerator)
+ enum2.should.instance_of?(Enumerator)
enum1.should_not === enum2
end
it "accepts an optional argument when given a block" do
-> do
@enum.with_index(1) { |f| f}
- end.should_not raise_error(ArgumentError)
+ end.should_not.raise(ArgumentError)
end
it "accepts an optional argument when not given a block" do
-> do
@enum.with_index(1)
- end.should_not raise_error(ArgumentError)
+ end.should_not.raise(ArgumentError)
end
it "numbers indices from the given index when given an offset but no block" do
@@ -38,7 +38,7 @@ describe "Enumerator#with_index" do
it "raises a TypeError when the argument cannot be converted to numeric" do
-> do
@enum.with_index('1') {|*i| i}
- end.should raise_error(TypeError)
+ end.should.raise(TypeError)
end
it "converts non-numeric arguments to Integer via #to_int" do
diff --git a/spec/ruby/core/enumerator/with_object_spec.rb b/spec/ruby/core/enumerator/with_object_spec.rb
index 58031fd765..790be66a11 100644
--- a/spec/ruby/core/enumerator/with_object_spec.rb
+++ b/spec/ruby/core/enumerator/with_object_spec.rb
@@ -1,6 +1,7 @@
require_relative '../../spec_helper'
-require_relative 'shared/with_object'
describe "Enumerator#with_object" do
- it_behaves_like :enum_with_object, :with_object
+ it "is an alias of Enumerator#each_with_object" do
+ Enumerator.instance_method(:with_object).should == Enumerator.instance_method(:each_with_object)
+ end
end
diff --git a/spec/ruby/core/enumerator/yielder/append_spec.rb b/spec/ruby/core/enumerator/yielder/append_spec.rb
deleted file mode 100644
index a36e5d64b6..0000000000
--- a/spec/ruby/core/enumerator/yielder/append_spec.rb
+++ /dev/null
@@ -1,35 +0,0 @@
-require_relative '../../../spec_helper'
-
-describe "Enumerator::Yielder#<<" do
- # TODO: There's some common behavior between yield and <<; move to a shared spec
- it "yields the value to the block" do
- ary = []
- y = Enumerator::Yielder.new {|x| ary << x}
- y << 1
-
- ary.should == [1]
- end
-
- it "doesn't double-wrap Arrays" do
- yields = []
- y = Enumerator::Yielder.new {|args| yields << args }
- y << [1]
- yields.should == [[1]]
- end
-
- it "returns self" do
- y = Enumerator::Yielder.new {|x| x + 1}
- (y << 1).should equal(y)
- end
-
- context "when multiple arguments passed" do
- it "raises an ArgumentError" do
- ary = []
- y = Enumerator::Yielder.new { |*x| ary << x }
-
- -> {
- y.<<(1, 2)
- }.should raise_error(ArgumentError, /wrong number of arguments/)
- end
- end
-end
diff --git a/spec/ruby/core/enumerator/yielder/initialize_spec.rb b/spec/ruby/core/enumerator/yielder/initialize_spec.rb
deleted file mode 100644
index 5a6eee2d0f..0000000000
--- a/spec/ruby/core/enumerator/yielder/initialize_spec.rb
+++ /dev/null
@@ -1,18 +0,0 @@
-# -*- encoding: us-ascii -*-
-
-require_relative '../../../spec_helper'
-
-describe "Enumerator::Yielder#initialize" do
- before :each do
- @class = Enumerator::Yielder
- @uninitialized = @class.allocate
- end
-
- it "is a private method" do
- @class.should have_private_instance_method(:initialize, false)
- end
-
- it "returns self when given a block" do
- @uninitialized.send(:initialize) {}.should equal(@uninitialized)
- end
-end
diff --git a/spec/ruby/core/enumerator/yielder/to_proc_spec.rb b/spec/ruby/core/enumerator/yielder/to_proc_spec.rb
deleted file mode 100644
index 1d3681ab50..0000000000
--- a/spec/ruby/core/enumerator/yielder/to_proc_spec.rb
+++ /dev/null
@@ -1,16 +0,0 @@
-require_relative '../../../spec_helper'
-
-describe "Enumerator::Yielder#to_proc" do
- it "returns a Proc object that takes an argument and yields it to the block" do
- ScratchPad.record []
- y = Enumerator::Yielder.new { |*args| ScratchPad << args; "foobar" }
-
- callable = y.to_proc
- callable.class.should == Proc
-
- result = callable.call(1, 2)
- ScratchPad.recorded.should == [[1, 2]]
-
- result.should == "foobar"
- end
-end
diff --git a/spec/ruby/core/enumerator/yielder/yield_spec.rb b/spec/ruby/core/enumerator/yielder/yield_spec.rb
deleted file mode 100644
index acfdf114b6..0000000000
--- a/spec/ruby/core/enumerator/yielder/yield_spec.rb
+++ /dev/null
@@ -1,33 +0,0 @@
-require_relative '../../../spec_helper'
-
-describe "Enumerator::Yielder#yield" do
- it "yields the value to the block" do
- ary = []
- y = Enumerator::Yielder.new {|x| ary << x}
- y.yield 1
-
- ary.should == [1]
- end
-
- it "yields with passed arguments" do
- yields = []
- y = Enumerator::Yielder.new {|*args| yields << args }
- y.yield 1, 2
- yields.should == [[1, 2]]
- end
-
- it "returns the result of the block for the given value" do
- y = Enumerator::Yielder.new {|x| x + 1}
- y.yield(1).should == 2
- end
-
- context "when multiple arguments passed" do
- it "yields the arguments list to the block" do
- ary = []
- y = Enumerator::Yielder.new { |*x| ary << x }
- y.yield(1, 2)
-
- ary.should == [[1, 2]]
- end
- end
-end
diff --git a/spec/ruby/core/env/assoc_spec.rb b/spec/ruby/core/env/assoc_spec.rb
index c7a388db75..b81be7ddf2 100644
--- a/spec/ruby/core/env/assoc_spec.rb
+++ b/spec/ruby/core/env/assoc_spec.rb
@@ -26,6 +26,6 @@ describe "ENV.assoc" do
end
it "raises TypeError if the argument is not a String and does not respond to #to_str" do
- -> { ENV.assoc(Object.new) }.should raise_error(TypeError, "no implicit conversion of Object into String")
+ -> { ENV.assoc(Object.new) }.should.raise(TypeError, "no implicit conversion of Object into String")
end
end
diff --git a/spec/ruby/core/env/clear_spec.rb b/spec/ruby/core/env/clear_spec.rb
index 48b034ba1d..c0d20193ad 100644
--- a/spec/ruby/core/env/clear_spec.rb
+++ b/spec/ruby/core/env/clear_spec.rb
@@ -4,7 +4,7 @@ describe "ENV.clear" do
it "deletes all environment variables" do
orig = ENV.to_hash
begin
- ENV.clear.should equal(ENV)
+ ENV.clear.should.equal?(ENV)
# This used 'env' the helper before. That shells out to 'env' which
# itself sets up certain environment variables before it runs, because
diff --git a/spec/ruby/core/env/clone_spec.rb b/spec/ruby/core/env/clone_spec.rb
index 01a29c6ab4..bb3c7ff2f8 100644
--- a/spec/ruby/core/env/clone_spec.rb
+++ b/spec/ruby/core/env/clone_spec.rb
@@ -4,18 +4,18 @@ 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)
+ }.should.raise(ArgumentError)
end
it "raises ArgumentError when keyword argument is not 'freeze'" do
-> {
ENV.clone(foo: nil)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
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/)
+ }.should.raise(TypeError, /Cannot clone ENV, use ENV.to_h to get a copy of ENV as a hash/)
end
end
diff --git a/spec/ruby/core/env/delete_if_spec.rb b/spec/ruby/core/env/delete_if_spec.rb
index d2de51c225..4b05064eba 100644
--- a/spec/ruby/core/env/delete_if_spec.rb
+++ b/spec/ruby/core/env/delete_if_spec.rb
@@ -22,15 +22,15 @@ describe "ENV.delete_if" do
end
it "returns ENV when block given" do
- ENV.delete_if { |k, v| ["foo", "bar"].include?(k) }.should equal(ENV)
+ ENV.delete_if { |k, v| ["foo", "bar"].include?(k) }.should.equal?(ENV)
end
it "returns ENV even if nothing deleted" do
- ENV.delete_if { false }.should equal(ENV)
+ ENV.delete_if { false }.should.equal?(ENV)
end
it "returns an Enumerator if no block given" do
- ENV.delete_if.should be_an_instance_of(Enumerator)
+ ENV.delete_if.should.instance_of?(Enumerator)
end
it "deletes pairs through enumerator" do
@@ -42,12 +42,12 @@ describe "ENV.delete_if" do
it "returns ENV from enumerator" do
enum = ENV.delete_if
- enum.each { |k, v| ["foo", "bar"].include?(k) }.should equal(ENV)
+ enum.each { |k, v| ["foo", "bar"].include?(k) }.should.equal?(ENV)
end
it "returns ENV from enumerator even if nothing deleted" do
enum = ENV.delete_if
- enum.each { false }.should equal(ENV)
+ enum.each { false }.should.equal?(ENV)
end
it_behaves_like :enumeratorized_with_origin_size, :delete_if, ENV
diff --git a/spec/ruby/core/env/delete_spec.rb b/spec/ruby/core/env/delete_spec.rb
index f28ac97911..db6d07b057 100644
--- a/spec/ruby/core/env/delete_spec.rb
+++ b/spec/ruby/core/env/delete_spec.rb
@@ -50,6 +50,6 @@ describe "ENV.delete" do
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")
+ -> { ENV.delete(Object.new) }.should.raise(TypeError, "no implicit conversion of Object into String")
end
end
diff --git a/spec/ruby/core/env/dup_spec.rb b/spec/ruby/core/env/dup_spec.rb
index ac66b455cd..d8cfac891d 100644
--- a/spec/ruby/core/env/dup_spec.rb
+++ b/spec/ruby/core/env/dup_spec.rb
@@ -4,6 +4,6 @@ describe "ENV#dup" 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/)
+ }.should.raise(TypeError, /Cannot dup ENV, use ENV.to_h to get a copy of ENV as a hash/)
end
end
diff --git a/spec/ruby/core/env/each_key_spec.rb b/spec/ruby/core/env/each_key_spec.rb
index 0efcb09900..ad2cb560a0 100644
--- a/spec/ruby/core/env/each_key_spec.rb
+++ b/spec/ruby/core/env/each_key_spec.rb
@@ -10,9 +10,9 @@ describe "ENV.each_key" do
ENV.clear
ENV["1"] = "3"
ENV["2"] = "4"
- ENV.each_key { |k| e << k }.should equal(ENV)
- e.should include("1")
- e.should include("2")
+ ENV.each_key { |k| e << k }.should.equal?(ENV)
+ e.should.include?("1")
+ e.should.include?("2")
ensure
ENV.replace orig
end
@@ -20,7 +20,7 @@ describe "ENV.each_key" do
it "returns an Enumerator if called without a block" do
enum = ENV.each_key
- enum.should be_an_instance_of(Enumerator)
+ enum.should.instance_of?(Enumerator)
enum.to_a.should == ENV.keys
end
diff --git a/spec/ruby/core/env/each_pair_spec.rb b/spec/ruby/core/env/each_pair_spec.rb
index 2d7ed5faa0..1acd2fbb00 100644
--- a/spec/ruby/core/env/each_pair_spec.rb
+++ b/spec/ruby/core/env/each_pair_spec.rb
@@ -1,6 +1,63 @@
require_relative 'spec_helper'
-require_relative 'shared/each'
+require_relative '../enumerable/shared/enumeratorized'
describe "ENV.each_pair" do
- it_behaves_like :env_each, :each_pair
+ it "returns each pair" do
+ orig = ENV.to_hash
+ e = []
+ begin
+ ENV.clear
+ ENV["foo"] = "bar"
+ ENV["baz"] = "boo"
+ ENV.each_pair { |k, v| e << [k, v] }.should.equal?(ENV)
+ e.should.include?(["foo", "bar"])
+ e.should.include?(["baz", "boo"])
+ ensure
+ ENV.replace orig
+ end
+ end
+
+ it "returns an Enumerator if called without a block" do
+ enum = ENV.each_pair
+ enum.should.instance_of?(Enumerator)
+ enum.each do |name, value|
+ ENV[name].should == value
+ end
+ end
+
+ it_behaves_like :enumeratorized_with_origin_size, :each_pair, ENV
+
+ describe "with encoding" do
+ before :each do
+ @external = Encoding.default_external
+ @internal = Encoding.default_internal
+
+ Encoding.default_external = Encoding::BINARY
+ end
+
+ after :each do
+ Encoding.default_external = @external
+ Encoding.default_internal = @internal
+ end
+
+ it "uses the locale encoding when Encoding.default_internal is nil" do
+ Encoding.default_internal = nil
+
+ ENV.each_pair do |key, value|
+ key.should.be_locale_env
+ value.should.be_locale_env
+ end
+ end
+
+ it "transcodes from the locale encoding to Encoding.default_internal if set" do
+ Encoding.default_internal = internal = Encoding::IBM437
+
+ ENV.each_pair do |key, value|
+ key.encoding.should.equal?(internal)
+ if value.ascii_only?
+ value.encoding.should.equal?(internal)
+ end
+ end
+ end
+ end
end
diff --git a/spec/ruby/core/env/each_spec.rb b/spec/ruby/core/env/each_spec.rb
index d1e06f55b6..166a0b4fc8 100644
--- a/spec/ruby/core/env/each_spec.rb
+++ b/spec/ruby/core/env/each_spec.rb
@@ -1,6 +1,7 @@
require_relative 'spec_helper'
-require_relative 'shared/each'
describe "ENV.each" do
- it_behaves_like :env_each, :each
+ it "is an alias of ENV.each_pair" do
+ ENV.method(:each).should == ENV.method(:each_pair)
+ end
end
diff --git a/spec/ruby/core/env/each_value_spec.rb b/spec/ruby/core/env/each_value_spec.rb
index cc3c9ebfb8..6f65e923e6 100644
--- a/spec/ruby/core/env/each_value_spec.rb
+++ b/spec/ruby/core/env/each_value_spec.rb
@@ -10,9 +10,9 @@ describe "ENV.each_value" do
ENV.clear
ENV["1"] = "3"
ENV["2"] = "4"
- ENV.each_value { |v| e << v }.should equal(ENV)
- e.should include("3")
- e.should include("4")
+ ENV.each_value { |v| e << v }.should.equal?(ENV)
+ e.should.include?("3")
+ e.should.include?("4")
ensure
ENV.replace orig
end
@@ -20,7 +20,7 @@ describe "ENV.each_value" do
it "returns an Enumerator if called without a block" do
enum = ENV.each_value
- enum.should be_an_instance_of(Enumerator)
+ enum.should.instance_of?(Enumerator)
enum.to_a.should == ENV.values
end
diff --git a/spec/ruby/core/env/element_reference_spec.rb b/spec/ruby/core/env/element_reference_spec.rb
index 66a9bc9690..e3ac979418 100644
--- a/spec/ruby/core/env/element_reference_spec.rb
+++ b/spec/ruby/core/env/element_reference_spec.rb
@@ -28,7 +28,7 @@ describe "ENV.[]" do
end
it "raises TypeError if the argument is not a String and does not respond to #to_str" do
- -> { ENV[Object.new] }.should raise_error(TypeError, "no implicit conversion of Object into String")
+ -> { ENV[Object.new] }.should.raise(TypeError, "no implicit conversion of Object into String")
end
platform_is :windows do
@@ -71,6 +71,6 @@ describe "ENV.[]" do
ENV[@variable] = ""
Encoding.default_internal = Encoding::IBM437
- ENV[@variable].encoding.should equal(Encoding::IBM437)
+ ENV[@variable].encoding.should.equal?(Encoding::IBM437)
end
end
diff --git a/spec/ruby/core/env/element_set_spec.rb b/spec/ruby/core/env/element_set_spec.rb
index 26dfee1ade..ca5d468009 100644
--- a/spec/ruby/core/env/element_set_spec.rb
+++ b/spec/ruby/core/env/element_set_spec.rb
@@ -1,6 +1,62 @@
require_relative '../../spec_helper'
-require_relative 'shared/store'
describe "ENV.[]=" do
- it_behaves_like :env_store, :[]=
+ before :each do
+ @saved_foo = ENV["foo"]
+ end
+
+ after :each do
+ ENV["foo"] = @saved_foo
+ end
+
+ it "sets the environment variable to the given value" do
+ ENV["foo"] = "bar"
+ ENV["foo"].should == "bar"
+ end
+
+ it "returns the value" do
+ value = "bar"
+ ENV.send(:[]=, "foo", value).should.equal?(value)
+ end
+
+ it "deletes the environment variable when the value is nil" do
+ ENV["foo"] = "bar"
+ ENV["foo"] = nil
+ ENV.key?("foo").should == false
+ end
+
+ it "coerces the key argument with #to_str" do
+ k = mock("key")
+ k.should_receive(:to_str).and_return("foo")
+ ENV[k] = "bar"
+ ENV["foo"].should == "bar"
+ end
+
+ it "coerces the value argument with #to_str" do
+ v = mock("value")
+ v.should_receive(:to_str).and_return("bar")
+ ENV["foo"] = v
+ ENV["foo"].should == "bar"
+ end
+
+ it "raises TypeError when the key is not coercible to String" do
+ -> { ENV[Object.new] = "bar" }.should.raise(TypeError, "no implicit conversion of Object into String")
+ end
+
+ it "raises TypeError when the value is not coercible to String" do
+ -> { ENV["foo"] = Object.new }.should.raise(TypeError, "no implicit conversion of Object into String")
+ end
+
+ it "raises Errno::EINVAL when the key contains the '=' character" do
+ -> { ENV["foo="] = "bar" }.should.raise(Errno::EINVAL)
+ end
+
+ it "raises Errno::EINVAL when the key is an empty string" do
+ -> { ENV[""] = "bar" }.should.raise(Errno::EINVAL)
+ end
+
+ it "does nothing when the key is not a valid environment variable key and the value is nil" do
+ ENV["foo="] = nil
+ ENV.key?("foo=").should == false
+ end
end
diff --git a/spec/ruby/core/env/fetch_spec.rb b/spec/ruby/core/env/fetch_spec.rb
index 2c5d7cc3a0..a2ec79c62b 100644
--- a/spec/ruby/core/env/fetch_spec.rb
+++ b/spec/ruby/core/env/fetch_spec.rb
@@ -16,7 +16,7 @@ describe "ENV.fetch" do
end
it "raises a TypeError if the key is not a String" do
- -> { ENV.fetch Object.new }.should raise_error(TypeError, "no implicit conversion of Object into String")
+ -> { ENV.fetch Object.new }.should.raise(TypeError, "no implicit conversion of Object into String")
end
context "when the key is not found" do
@@ -25,7 +25,7 @@ describe "ENV.fetch" do
it "formats the object with #inspect in the KeyError message" do
-> {
ENV.fetch('foo')
- }.should raise_error(KeyError, 'key not found: "foo"')
+ }.should.raise(KeyError, 'key not found: "foo"')
end
end
diff --git a/spec/ruby/core/env/fetch_values_spec.rb b/spec/ruby/core/env/fetch_values_spec.rb
new file mode 100644
index 0000000000..302cde2fd1
--- /dev/null
+++ b/spec/ruby/core/env/fetch_values_spec.rb
@@ -0,0 +1,51 @@
+require_relative '../../spec_helper'
+require_relative 'fixtures/common'
+
+ruby_version_is "4.1" do
+ describe "ENV.fetch_values" do
+ before :each do
+ @saved_foo = ENV["foo"]
+ @saved_bar = ENV["bar"]
+ ENV.delete("foo")
+ ENV.delete("bar")
+ end
+
+ after :each do
+ ENV["foo"] = @saved_foo
+ ENV["bar"] = @saved_bar
+ end
+
+ it "returns an array of the values corresponding to the given keys" do
+ ENV["foo"] = "oof"
+ ENV["bar"] = "rab"
+ ENV.fetch_values("bar", "foo").should == ["rab", "oof"]
+ end
+
+ it "returns the default value from block" do
+ ENV["foo"] = "oof"
+ ENV.fetch_values("bar") { |key| "`#{key}' is not found" }.should == ["`bar' is not found"]
+ ENV.fetch_values("bar", "foo") { |key| "`#{key}' is not found" }.should == ["`bar' is not found", "oof"]
+ end
+
+ it "returns an empty array if no keys specified" do
+ ENV.fetch_values.should == []
+ end
+
+ it "raises KeyError when there is no matching key" do
+ ENV["foo"] = "oof"
+ ENV["bar"] = "rab"
+ -> {
+ ENV.fetch_values("bar", "y", "foo", "z")
+ }.should.raise(KeyError, 'key not found: "y"')
+ end
+
+ it "uses the locale encoding" do
+ ENV.fetch_values(ENV.keys.first).first.encoding.should == ENVSpecs.encoding
+ end
+
+ it "raises TypeError when a key is not coercible to String" do
+ ENV["foo"] = "oof"
+ -> { ENV.fetch_values("foo", Object.new) }.should.raise(TypeError, "no implicit conversion of Object into String")
+ end
+ end
+end
diff --git a/spec/ruby/core/env/filter_spec.rb b/spec/ruby/core/env/filter_spec.rb
index 52f8b79a0b..54997bfda1 100644
--- a/spec/ruby/core/env/filter_spec.rb
+++ b/spec/ruby/core/env/filter_spec.rb
@@ -1,13 +1,13 @@
require_relative '../../spec_helper'
-require_relative '../enumerable/shared/enumeratorized'
-require_relative 'shared/select'
describe "ENV.filter!" do
- it_behaves_like :env_select!, :filter!
- it_behaves_like :enumeratorized_with_origin_size, :filter!, ENV
+ it "is an alias of ENV.select!" do
+ ENV.method(:filter!).should == ENV.method(:select!)
+ end
end
describe "ENV.filter" do
- it_behaves_like :env_select, :filter
- it_behaves_like :enumeratorized_with_origin_size, :filter, ENV
+ it "is an alias of ENV.select" do
+ ENV.method(:filter).should == ENV.method(:select)
+ end
end
diff --git a/spec/ruby/core/env/has_key_spec.rb b/spec/ruby/core/env/has_key_spec.rb
index 798668105d..7feeec8dfa 100644
--- a/spec/ruby/core/env/has_key_spec.rb
+++ b/spec/ruby/core/env/has_key_spec.rb
@@ -1,6 +1,7 @@
require_relative '../../spec_helper'
-require_relative 'shared/include'
describe "ENV.has_key?" do
- it_behaves_like :env_include, :has_key?
+ it "is an alias of ENV.include?" do
+ ENV.method(:has_key?).should == ENV.method(:include?)
+ end
end
diff --git a/spec/ruby/core/env/has_value_spec.rb b/spec/ruby/core/env/has_value_spec.rb
index a2bf3eb877..b76ec0dc5d 100644
--- a/spec/ruby/core/env/has_value_spec.rb
+++ b/spec/ruby/core/env/has_value_spec.rb
@@ -1,6 +1,7 @@
require_relative '../../spec_helper'
-require_relative 'shared/value'
describe "ENV.has_value?" do
- it_behaves_like :env_value, :has_value?
+ it "is an alias of ENV.value?" do
+ ENV.method(:has_value?).should == ENV.method(:value?)
+ end
end
diff --git a/spec/ruby/core/env/include_spec.rb b/spec/ruby/core/env/include_spec.rb
index 3975f095ac..8e68aa3bfd 100644
--- a/spec/ruby/core/env/include_spec.rb
+++ b/spec/ruby/core/env/include_spec.rb
@@ -1,6 +1,32 @@
require_relative '../../spec_helper'
-require_relative 'shared/include'
describe "ENV.include?" do
- it_behaves_like :env_include, :include?
+ before :each do
+ @saved_foo = ENV["foo"]
+ end
+
+ after :each do
+ ENV["foo"] = @saved_foo
+ end
+
+ it "returns true if ENV has the key" do
+ ENV["foo"] = "bar"
+ ENV.include?( "foo").should == true
+ end
+
+ it "returns false if ENV doesn't include the key" do
+ ENV.delete("foo")
+ ENV.include?( "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.include?( k).should == true
+ end
+
+ it "raises TypeError if the argument is not a String and does not respond to #to_str" do
+ -> { ENV.include?( Object.new) }.should.raise(TypeError, "no implicit conversion of Object into String")
+ end
end
diff --git a/spec/ruby/core/env/keep_if_spec.rb b/spec/ruby/core/env/keep_if_spec.rb
index 64b6a207d0..f24981e216 100644
--- a/spec/ruby/core/env/keep_if_spec.rb
+++ b/spec/ruby/core/env/keep_if_spec.rb
@@ -22,15 +22,15 @@ describe "ENV.keep_if" do
end
it "returns ENV when block given" do
- ENV.keep_if { |k, v| !["foo", "bar"].include?(k) }.should equal(ENV)
+ ENV.keep_if { |k, v| !["foo", "bar"].include?(k) }.should.equal?(ENV)
end
it "returns ENV even if nothing deleted" do
- ENV.keep_if { true }.should equal(ENV)
+ ENV.keep_if { true }.should.equal?(ENV)
end
it "returns an Enumerator if no block given" do
- ENV.keep_if.should be_an_instance_of(Enumerator)
+ ENV.keep_if.should.instance_of?(Enumerator)
end
it "deletes pairs through enumerator" do
@@ -42,12 +42,12 @@ describe "ENV.keep_if" do
it "returns ENV from enumerator" do
enum = ENV.keep_if
- enum.each { |k, v| !["foo", "bar"].include?(k) }.should equal(ENV)
+ enum.each { |k, v| !["foo", "bar"].include?(k) }.should.equal?(ENV)
end
it "returns ENV from enumerator even if nothing deleted" do
enum = ENV.keep_if
- enum.each { true }.should equal(ENV)
+ enum.each { true }.should.equal?(ENV)
end
it_behaves_like :enumeratorized_with_origin_size, :keep_if, ENV
diff --git a/spec/ruby/core/env/key_spec.rb b/spec/ruby/core/env/key_spec.rb
index cf70286409..56f5f609a7 100644
--- a/spec/ruby/core/env/key_spec.rb
+++ b/spec/ruby/core/env/key_spec.rb
@@ -1,8 +1,9 @@
require_relative '../../spec_helper'
-require_relative 'shared/include'
describe "ENV.key?" do
- it_behaves_like :env_include, :key?
+ it "is an alias of ENV.include?" do
+ ENV.method(:key?).should == ENV.method(:include?)
+ end
end
describe "ENV.key" do
@@ -21,7 +22,7 @@ describe "ENV.key" do
it "returns nil if the passed value is not found" do
ENV.delete("foo")
- ENV.key("foo").should be_nil
+ ENV.key("foo").should == nil
end
it "coerces the key element with #to_str" do
@@ -34,6 +35,6 @@ describe "ENV.key" do
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")
+ }.should.raise(TypeError, "no implicit conversion of Object into String")
end
end
diff --git a/spec/ruby/core/env/length_spec.rb b/spec/ruby/core/env/length_spec.rb
index c6f9062892..6baac6f7a4 100644
--- a/spec/ruby/core/env/length_spec.rb
+++ b/spec/ruby/core/env/length_spec.rb
@@ -1,6 +1,7 @@
require_relative '../../spec_helper'
-require_relative 'shared/length'
describe "ENV.length" do
- it_behaves_like :env_length, :length
+ it "is an alias of ENV.size" do
+ ENV.method(:length).should == ENV.method(:size)
+ end
end
diff --git a/spec/ruby/core/env/member_spec.rb b/spec/ruby/core/env/member_spec.rb
index 9119022ae5..f062d41190 100644
--- a/spec/ruby/core/env/member_spec.rb
+++ b/spec/ruby/core/env/member_spec.rb
@@ -1,6 +1,7 @@
require_relative '../../spec_helper'
-require_relative 'shared/include'
describe "ENV.member?" do
- it_behaves_like :env_include, :member?
+ it "is an alias of ENV.include?" do
+ ENV.method(:member?).should == ENV.method(:include?)
+ end
end
diff --git a/spec/ruby/core/env/merge_spec.rb b/spec/ruby/core/env/merge_spec.rb
index f10662cf79..78231afbb2 100644
--- a/spec/ruby/core/env/merge_spec.rb
+++ b/spec/ruby/core/env/merge_spec.rb
@@ -1,6 +1,106 @@
require_relative '../../spec_helper'
-require_relative 'shared/update'
describe "ENV.merge!" do
- it_behaves_like :env_update, :merge!
+ before :each do
+ @saved_foo = ENV["foo"]
+ @saved_bar = ENV["bar"]
+ end
+
+ after :each do
+ ENV["foo"] = @saved_foo
+ ENV["bar"] = @saved_bar
+ end
+
+ it "adds the parameter hash to ENV, returning ENV" do
+ ENV.merge!("foo" => "0", "bar" => "1").should.equal?(ENV)
+ ENV["foo"].should == "0"
+ ENV["bar"].should == "1"
+ end
+
+ it "adds the multiple parameter hashes to ENV, returning ENV" do
+ ENV.merge!({"foo" => "multi1"}, {"bar" => "multi2"}).should.equal?(ENV)
+ ENV["foo"].should == "multi1"
+ ENV["bar"].should == "multi2"
+ end
+
+ it "returns ENV when no block given" do
+ ENV.merge!({"foo" => "0", "bar" => "1"}).should.equal?(ENV)
+ end
+
+ it "yields key, the old value and the new value when replacing an entry" do
+ ENV.merge!({"foo" => "0", "bar" => "3"})
+ a = []
+ ENV.merge!({"foo" => "1", "bar" => "4"}) do |key, old, new|
+ a << [key, old, new]
+ new
+ end
+ a[0].should == ["foo", "0", "1"]
+ a[1].should == ["bar", "3", "4"]
+ end
+
+ it "yields key, the old value and the new value when replacing an entry" do
+ ENV.merge!({"foo" => "0", "bar" => "3"})
+ ENV.merge!({"foo" => "1", "bar" => "4"}) do |key, old, new|
+ (new.to_i + 1).to_s
+ end
+ ENV["foo"].should == "2"
+ ENV["bar"].should == "5"
+ end
+
+ # BUG: https://bugs.ruby-lang.org/issues/16192
+ it "does not evaluate the block when the name is new" do
+ ENV.delete("bar")
+ ENV.merge!({"foo" => "0"})
+ ENV.merge!("bar" => "1") { |key, old, new| fail "Should not get here" }
+ ENV["bar"].should == "1"
+ end
+
+ # BUG: https://bugs.ruby-lang.org/issues/16192
+ it "does not use the block's return value as the value when the name is new" do
+ ENV.delete("bar")
+ ENV.merge!({"foo" => "0"})
+ ENV.merge!("bar" => "1") { |key, old, new| "Should not use this value" }
+ ENV["foo"].should == "0"
+ ENV["bar"].should == "1"
+ end
+
+ it "returns ENV when block given" do
+ ENV.merge!({"foo" => "0", "bar" => "1"}){}.should.equal?(ENV)
+ end
+
+ it "raises TypeError when a name is not coercible to String" do
+ -> { ENV.merge!(Object.new => "0") }.should.raise(TypeError, "no implicit conversion of Object into String")
+ end
+
+ it "raises TypeError when a value is not coercible to String" do
+ -> { ENV.merge!("foo" => Object.new) }.should.raise(TypeError, "no implicit conversion of Object into String")
+ end
+
+ it "raises Errno::EINVAL when a name contains the '=' character" do
+ -> { ENV.merge!("foo=" => "bar") }.should.raise(Errno::EINVAL)
+ end
+
+ it "raises Errno::EINVAL when a name is an empty string" do
+ -> { ENV.merge!("" => "bar") }.should.raise(Errno::EINVAL)
+ end
+
+ it "updates good data preceding an error" do
+ ENV["foo"] = "0"
+ begin
+ ENV.merge!({"foo" => "2", Object.new => "1"})
+ rescue TypeError
+ ensure
+ ENV["foo"].should == "2"
+ end
+ end
+
+ it "does not update good data following an error" do
+ ENV["foo"] = "0"
+ begin
+ ENV.merge!({Object.new => "1", "foo" => "2"})
+ rescue TypeError
+ ensure
+ ENV["foo"].should == "0"
+ end
+ end
end
diff --git a/spec/ruby/core/env/rassoc_spec.rb b/spec/ruby/core/env/rassoc_spec.rb
index ab9fe68088..e4ac5ce5e2 100644
--- a/spec/ruby/core/env/rassoc_spec.rb
+++ b/spec/ruby/core/env/rassoc_spec.rb
@@ -22,7 +22,7 @@ describe "ENV.rassoc" do
[
["foo", "bar"],
["baz", "bar"],
- ].should include(ENV.rassoc("bar"))
+ ].should.include?(ENV.rassoc("bar"))
end
it "returns nil if no environment variable with the given value exists" do
diff --git a/spec/ruby/core/env/reject_spec.rb b/spec/ruby/core/env/reject_spec.rb
index 6a9794925d..4df864493d 100644
--- a/spec/ruby/core/env/reject_spec.rb
+++ b/spec/ruby/core/env/reject_spec.rb
@@ -25,15 +25,15 @@ describe "ENV.reject!" do
it "returns itself or nil" do
ENV.reject! { false }.should == nil
ENV["foo"] = "bar"
- ENV.reject! { |k, v| k == "foo" }.should equal(ENV)
+ ENV.reject! { |k, v| k == "foo" }.should.equal?(ENV)
ENV["foo"].should == nil
end
it "returns an Enumerator if called without a block" do
ENV["foo"] = "bar"
enum = ENV.reject!
- enum.should be_an_instance_of(Enumerator)
- enum.each { |k, v| k == "foo" }.should equal(ENV)
+ enum.should.instance_of?(Enumerator)
+ enum.each { |k, v| k == "foo" }.should.equal?(ENV)
ENV["foo"].should == nil
end
@@ -41,7 +41,7 @@ describe "ENV.reject!" do
orig = ENV.to_hash
begin
ENV.clear
- -> { ENV.reject! }.should_not raise_error(LocalJumpError)
+ -> { ENV.reject! }.should_not.raise(LocalJumpError)
ensure
ENV.replace orig
end
@@ -76,13 +76,13 @@ describe "ENV.reject" do
end
it "returns a Hash" do
- ENV.reject { false }.should be_kind_of(Hash)
+ ENV.reject { false }.should.is_a?(Hash)
end
it "returns an Enumerator if called without a block" do
ENV["foo"] = "bar"
enum = ENV.reject
- enum.should be_an_instance_of(Enumerator)
+ enum.should.instance_of?(Enumerator)
enum.each { |k, v| k == "foo"}
ENV["foo"] = nil
end
@@ -91,7 +91,7 @@ describe "ENV.reject" do
orig = ENV.to_hash
begin
ENV.clear
- -> { ENV.reject }.should_not raise_error(LocalJumpError)
+ -> { ENV.reject }.should_not.raise(LocalJumpError)
ensure
ENV.replace orig
end
diff --git a/spec/ruby/core/env/replace_spec.rb b/spec/ruby/core/env/replace_spec.rb
index 9fc67643d1..27eb3e45dd 100644
--- a/spec/ruby/core/env/replace_spec.rb
+++ b/spec/ruby/core/env/replace_spec.rb
@@ -11,41 +11,41 @@ describe "ENV.replace" do
end
it "replaces ENV with a Hash" do
- ENV.replace("foo" => "0", "bar" => "1").should equal(ENV)
+ ENV.replace("foo" => "0", "bar" => "1").should.equal?(ENV)
ENV.size.should == 2
ENV["foo"].should == "0"
ENV["bar"].should == "1"
end
it "raises TypeError if the argument is not a Hash" do
- -> { ENV.replace(Object.new) }.should raise_error(TypeError, "no implicit conversion of Object into Hash")
+ -> { ENV.replace(Object.new) }.should.raise(TypeError, "no implicit conversion of Object into Hash")
ENV.to_hash.should == @orig
end
it "raises TypeError if a key is not a String" do
- -> { ENV.replace(Object.new => "0") }.should raise_error(TypeError, "no implicit conversion of Object into String")
+ -> { ENV.replace(Object.new => "0") }.should.raise(TypeError, "no implicit conversion of Object into String")
ENV.to_hash.should == @orig
end
it "raises TypeError if a value is not a String" do
- -> { ENV.replace("foo" => Object.new) }.should raise_error(TypeError, "no implicit conversion of Object into String")
+ -> { ENV.replace("foo" => Object.new) }.should.raise(TypeError, "no implicit conversion of Object into String")
ENV.to_hash.should == @orig
end
it "raises Errno::EINVAL when the key contains the '=' character" do
- -> { ENV.replace("foo=" =>"bar") }.should raise_error(Errno::EINVAL)
+ -> { ENV.replace("foo=" =>"bar") }.should.raise(Errno::EINVAL)
end
it "raises Errno::EINVAL when the key is an empty string" do
- -> { ENV.replace("" => "bar") }.should raise_error(Errno::EINVAL)
+ -> { ENV.replace("" => "bar") }.should.raise(Errno::EINVAL)
end
it "does not accept good data preceding an error" do
- -> { ENV.replace("foo" => "1", Object.new => Object.new) }.should raise_error(TypeError, "no implicit conversion of Object into String")
+ -> { ENV.replace("foo" => "1", Object.new => Object.new) }.should.raise(TypeError, "no implicit conversion of Object into String")
end
it "does not accept good data following an error" do
- -> { ENV.replace(Object.new => Object.new, "foo" => "0") }.should raise_error(TypeError, "no implicit conversion of Object into String")
+ -> { ENV.replace(Object.new => Object.new, "foo" => "0") }.should.raise(TypeError, "no implicit conversion of Object into String")
ENV.to_hash.should == @orig
end
end
diff --git a/spec/ruby/core/env/select_spec.rb b/spec/ruby/core/env/select_spec.rb
index c3a76f4434..2b92d61551 100644
--- a/spec/ruby/core/env/select_spec.rb
+++ b/spec/ruby/core/env/select_spec.rb
@@ -1,13 +1,68 @@
require_relative '../../spec_helper'
require_relative '../enumerable/shared/enumeratorized'
-require_relative 'shared/select'
describe "ENV.select!" do
- it_behaves_like :env_select!, :select!
it_behaves_like :enumeratorized_with_origin_size, :select!, ENV
+
+ before :each do
+ @saved_foo = ENV["foo"]
+ end
+
+ after :each do
+ ENV["foo"] = @saved_foo
+ end
+
+ it "removes environment variables for which the block returns false" do
+ ENV["foo"] = "bar"
+ ENV.select! { |k, v| k != "foo" }
+ ENV["foo"].should == nil
+ end
+
+ it "returns self if any changes were made" do
+ ENV["foo"] = "bar"
+ (ENV.select! { |k, v| k != "foo" }).should == ENV
+ end
+
+ it "returns nil if no changes were made" do
+ (ENV.select! { true }).should == nil
+ end
+
+ it "returns an Enumerator if called without a block" do
+ ENV.select!.should.instance_of?(Enumerator)
+ end
+
+ it "selects via the enumerator" do
+ enum = ENV.select!
+ ENV["foo"] = "bar"
+ enum.each { |k, v| k != "foo" }
+ ENV["foo"].should == nil
+ end
end
describe "ENV.select" do
- it_behaves_like :env_select, :select
it_behaves_like :enumeratorized_with_origin_size, :select, ENV
+
+ before :each do
+ @saved_foo = ENV["foo"]
+ end
+
+ after :each do
+ ENV["foo"] = @saved_foo
+ end
+
+ it "returns a Hash of names and values for which block returns true" do
+ ENV["foo"] = "bar"
+ (ENV.select { |k, v| k == "foo" }).should == { "foo" => "bar" }
+ end
+
+ it "returns an Enumerator when no block is given" do
+ enum = ENV.select
+ enum.should.instance_of?(Enumerator)
+ end
+
+ it "selects via the enumerator" do
+ enum = ENV.select
+ ENV["foo"] = "bar"
+ enum.each { |k, v| k == "foo" }.should == { "foo" => "bar"}
+ end
end
diff --git a/spec/ruby/core/env/shared/each.rb b/spec/ruby/core/env/shared/each.rb
deleted file mode 100644
index d901b854c4..0000000000
--- a/spec/ruby/core/env/shared/each.rb
+++ /dev/null
@@ -1,65 +0,0 @@
-require_relative '../../enumerable/shared/enumeratorized'
-
-describe :env_each, shared: true do
- it "returns each pair" do
- orig = ENV.to_hash
- e = []
- begin
- ENV.clear
- ENV["foo"] = "bar"
- ENV["baz"] = "boo"
- ENV.send(@method) { |k, v| e << [k, v] }.should equal(ENV)
- e.should include(["foo", "bar"])
- e.should include(["baz", "boo"])
- ensure
- ENV.replace orig
- end
- end
-
- it "returns an Enumerator if called without a block" do
- enum = ENV.send(@method)
- enum.should be_an_instance_of(Enumerator)
- enum.each do |name, value|
- ENV[name].should == value
- end
- end
-
- before :all do
- @object = ENV
- end
- it_should_behave_like :enumeratorized_with_origin_size
-
- describe "with encoding" do
- before :each do
- @external = Encoding.default_external
- @internal = Encoding.default_internal
-
- Encoding.default_external = Encoding::BINARY
- end
-
- after :each do
- Encoding.default_external = @external
- Encoding.default_internal = @internal
- end
-
- it "uses the locale encoding when Encoding.default_internal is nil" do
- Encoding.default_internal = nil
-
- ENV.send(@method) do |key, value|
- key.should.be_locale_env
- value.should.be_locale_env
- end
- end
-
- it "transcodes from the locale encoding to Encoding.default_internal if set" do
- Encoding.default_internal = internal = Encoding::IBM437
-
- ENV.send(@method) do |key, value|
- key.encoding.should equal(internal)
- if value.ascii_only?
- value.encoding.should equal(internal)
- end
- end
- end
- end
-end
diff --git a/spec/ruby/core/env/shared/include.rb b/spec/ruby/core/env/shared/include.rb
deleted file mode 100644
index 70aa555301..0000000000
--- a/spec/ruby/core/env/shared/include.rb
+++ /dev/null
@@ -1,30 +0,0 @@
-describe :env_include, shared: true do
- before :each do
- @saved_foo = ENV["foo"]
- end
-
- after :each do
- ENV["foo"] = @saved_foo
- end
-
- it "returns true if ENV has the key" do
- ENV["foo"] = "bar"
- ENV.send(@method, "foo").should == true
- end
-
- it "returns false if ENV doesn't include the key" do
- ENV.delete("foo")
- 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
-end
diff --git a/spec/ruby/core/env/shared/length.rb b/spec/ruby/core/env/shared/length.rb
deleted file mode 100644
index 6d788a3f4a..0000000000
--- a/spec/ruby/core/env/shared/length.rb
+++ /dev/null
@@ -1,13 +0,0 @@
-describe :env_length, shared: true do
- it "returns the number of ENV entries" do
- orig = ENV.to_hash
- begin
- ENV.clear
- ENV["foo"] = "bar"
- ENV["baz"] = "boo"
- ENV.send(@method).should == 2
- ensure
- ENV.replace orig
- end
- end
-end
diff --git a/spec/ruby/core/env/shared/select.rb b/spec/ruby/core/env/shared/select.rb
deleted file mode 100644
index 75ba112a32..0000000000
--- a/spec/ruby/core/env/shared/select.rb
+++ /dev/null
@@ -1,61 +0,0 @@
-describe :env_select, shared: true do
- before :each do
- @saved_foo = ENV["foo"]
- end
-
- after :each do
- ENV["foo"] = @saved_foo
- end
-
- it "returns a Hash of names and values for which block return true" do
- ENV["foo"] = "bar"
- (ENV.send(@method) { |k, v| k == "foo" }).should == { "foo" => "bar" }
- end
-
- it "returns an Enumerator when no block is given" do
- enum = ENV.send(@method)
- enum.should be_an_instance_of(Enumerator)
- end
-
- it "selects via the enumerator" do
- enum = ENV.send(@method)
- ENV["foo"] = "bar"
- enum.each { |k, v| k == "foo" }.should == { "foo" => "bar"}
- end
-end
-
-describe :env_select!, shared: true do
- before :each do
- @saved_foo = ENV["foo"]
- end
-
- after :each do
- ENV["foo"] = @saved_foo
- end
-
- it "removes environment variables for which the block returns true" do
- ENV["foo"] = "bar"
- ENV.send(@method) { |k, v| k != "foo" }
- ENV["foo"].should == nil
- end
-
- it "returns self if any changes were made" do
- ENV["foo"] = "bar"
- (ENV.send(@method) { |k, v| k != "foo" }).should == ENV
- end
-
- it "returns nil if no changes were made" do
- (ENV.send(@method) { true }).should == nil
- end
-
- it "returns an Enumerator if called without a block" do
- ENV.send(@method).should be_an_instance_of(Enumerator)
- end
-
- it "selects via the enumerator" do
- enum = ENV.send(@method)
- ENV["foo"] = "bar"
- enum.each { |k, v| k != "foo" }
- ENV["foo"].should == nil
- end
-end
diff --git a/spec/ruby/core/env/shared/store.rb b/spec/ruby/core/env/shared/store.rb
deleted file mode 100644
index d6265c66a5..0000000000
--- a/spec/ruby/core/env/shared/store.rb
+++ /dev/null
@@ -1,60 +0,0 @@
-describe :env_store, shared: true do
- before :each do
- @saved_foo = ENV["foo"]
- end
-
- after :each do
- ENV["foo"] = @saved_foo
- end
-
- it "sets the environment variable to the given value" do
- ENV.send(@method, "foo", "bar")
- ENV["foo"].should == "bar"
- end
-
- it "returns the value" do
- value = "bar"
- ENV.send(@method, "foo", value).should equal(value)
- end
-
- it "deletes the environment variable when the value is nil" do
- ENV["foo"] = "bar"
- ENV.send(@method, "foo", nil)
- ENV.key?("foo").should be_false
- end
-
- it "coerces the key argument with #to_str" do
- k = mock("key")
- k.should_receive(:to_str).and_return("foo")
- ENV.send(@method, k, "bar")
- ENV["foo"].should == "bar"
- end
-
- it "coerces the value argument with #to_str" do
- v = mock("value")
- v.should_receive(:to_str).and_return("bar")
- ENV.send(@method, "foo", v)
- ENV["foo"].should == "bar"
- end
-
- it "raises TypeError when the key is not coercible to String" do
- -> { ENV.send(@method, Object.new, "bar") }.should raise_error(TypeError, "no implicit conversion of Object into String")
- end
-
- it "raises TypeError when the value is not coercible to String" do
- -> { ENV.send(@method, "foo", Object.new) }.should raise_error(TypeError, "no implicit conversion of Object into String")
- end
-
- it "raises Errno::EINVAL when the key contains the '=' character" do
- -> { ENV.send(@method, "foo=", "bar") }.should raise_error(Errno::EINVAL)
- end
-
- it "raises Errno::EINVAL when the key is an empty string" do
- -> { ENV.send(@method, "", "bar") }.should raise_error(Errno::EINVAL)
- end
-
- it "does nothing when the key is not a valid environment variable key and the value is nil" do
- ENV.send(@method, "foo=", nil)
- ENV.key?("foo=").should be_false
- end
-end
diff --git a/spec/ruby/core/env/shared/to_hash.rb b/spec/ruby/core/env/shared/to_hash.rb
index a0d4d7ce69..7868690c38 100644
--- a/spec/ruby/core/env/shared/to_hash.rb
+++ b/spec/ruby/core/env/shared/to_hash.rb
@@ -10,7 +10,7 @@ describe :env_to_hash, shared: true do
it "returns the ENV as a hash" do
ENV["foo"] = "bar"
h = ENV.send(@method)
- h.should be_an_instance_of(Hash)
+ h.should.instance_of?(Hash)
h["foo"].should == "bar"
end
@@ -24,7 +24,7 @@ describe :env_to_hash, shared: true do
it "duplicates the ENV when converting to a Hash" do
h = ENV.send(@method)
- h.should_not equal ENV
+ h.should_not.equal? ENV
h.size.should == ENV.size
h.each_pair do |k, v|
ENV[k].should == v
diff --git a/spec/ruby/core/env/shared/update.rb b/spec/ruby/core/env/shared/update.rb
deleted file mode 100644
index e1b1c9c290..0000000000
--- a/spec/ruby/core/env/shared/update.rb
+++ /dev/null
@@ -1,104 +0,0 @@
-describe :env_update, shared: true do
- before :each do
- @saved_foo = ENV["foo"]
- @saved_bar = ENV["bar"]
- end
-
- after :each do
- ENV["foo"] = @saved_foo
- ENV["bar"] = @saved_bar
- end
-
- it "adds the parameter hash to ENV, returning ENV" do
- ENV.send(@method, "foo" => "0", "bar" => "1").should equal(ENV)
- ENV["foo"].should == "0"
- ENV["bar"].should == "1"
- end
-
- it "adds the multiple parameter hashes to ENV, returning ENV" do
- ENV.send(@method, {"foo" => "multi1"}, {"bar" => "multi2"}).should equal(ENV)
- ENV["foo"].should == "multi1"
- ENV["bar"].should == "multi2"
- end
-
- it "returns ENV when no block given" do
- ENV.send(@method, {"foo" => "0", "bar" => "1"}).should equal(ENV)
- end
-
- it "yields key, the old value and the new value when replacing an entry" do
- ENV.send @method, {"foo" => "0", "bar" => "3"}
- a = []
- ENV.send @method, {"foo" => "1", "bar" => "4"} do |key, old, new|
- a << [key, old, new]
- new
- end
- a[0].should == ["foo", "0", "1"]
- a[1].should == ["bar", "3", "4"]
- end
-
- it "yields key, the old value and the new value when replacing an entry" do
- ENV.send @method, {"foo" => "0", "bar" => "3"}
- ENV.send @method, {"foo" => "1", "bar" => "4"} do |key, old, new|
- (new.to_i + 1).to_s
- end
- ENV["foo"].should == "2"
- ENV["bar"].should == "5"
- end
-
- # BUG: https://bugs.ruby-lang.org/issues/16192
- it "does not evaluate the block when the name is new" do
- ENV.delete("bar")
- ENV.send @method, {"foo" => "0"}
- ENV.send(@method, "bar" => "1") { |key, old, new| fail "Should not get here" }
- ENV["bar"].should == "1"
- end
-
- # BUG: https://bugs.ruby-lang.org/issues/16192
- it "does not use the block's return value as the value when the name is new" do
- ENV.delete("bar")
- ENV.send @method, {"foo" => "0"}
- ENV.send(@method, "bar" => "1") { |key, old, new| "Should not use this value" }
- ENV["foo"].should == "0"
- ENV["bar"].should == "1"
- end
-
- it "returns ENV when block given" do
- ENV.send(@method, {"foo" => "0", "bar" => "1"}){}.should equal(ENV)
- end
-
- it "raises TypeError when a name is not coercible to String" do
- -> { ENV.send @method, Object.new => "0" }.should raise_error(TypeError, "no implicit conversion of Object into String")
- end
-
- it "raises TypeError when a value is not coercible to String" do
- -> { ENV.send @method, "foo" => Object.new }.should raise_error(TypeError, "no implicit conversion of Object into String")
- end
-
- it "raises Errno::EINVAL when a name contains the '=' character" do
- -> { ENV.send(@method, "foo=" => "bar") }.should raise_error(Errno::EINVAL)
- end
-
- it "raises Errno::EINVAL when a name is an empty string" do
- -> { ENV.send(@method, "" => "bar") }.should raise_error(Errno::EINVAL)
- end
-
- it "updates good data preceding an error" do
- ENV["foo"] = "0"
- begin
- ENV.send @method, {"foo" => "2", Object.new => "1"}
- rescue TypeError
- ensure
- ENV["foo"].should == "2"
- end
- end
-
- it "does not update good data following an error" do
- ENV["foo"] = "0"
- begin
- ENV.send @method, {Object.new => "1", "foo" => "2"}
- rescue TypeError
- ensure
- ENV["foo"].should == "0"
- end
- end
-end
diff --git a/spec/ruby/core/env/shared/value.rb b/spec/ruby/core/env/shared/value.rb
deleted file mode 100644
index c2b5025465..0000000000
--- a/spec/ruby/core/env/shared/value.rb
+++ /dev/null
@@ -1,29 +0,0 @@
-describe :env_value, shared: true do
- before :each do
- @saved_foo = ENV["foo"]
- end
-
- after :each do
- ENV["foo"] = @saved_foo
- end
-
- it "returns true if ENV has the value" do
- ENV["foo"] = "bar"
- ENV.send(@method, "bar").should == true
- end
-
- it "returns false if ENV doesn't have the value" 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
-end
diff --git a/spec/ruby/core/env/shift_spec.rb b/spec/ruby/core/env/shift_spec.rb
index 1b92e5d1e4..52bd0f9139 100644
--- a/spec/ruby/core/env/shift_spec.rb
+++ b/spec/ruby/core/env/shift_spec.rb
@@ -33,15 +33,15 @@ describe "ENV.shift" do
Encoding.default_internal = nil
pair = ENV.shift
- pair.first.encoding.should equal(ENVSpecs.encoding)
- pair.last.encoding.should equal(ENVSpecs.encoding)
+ pair.first.encoding.should.equal?(ENVSpecs.encoding)
+ pair.last.encoding.should.equal?(ENVSpecs.encoding)
end
it "transcodes from the locale encoding to Encoding.default_internal if set" do
Encoding.default_internal = Encoding::IBM437
pair = ENV.shift
- pair.first.encoding.should equal(Encoding::IBM437)
- pair.last.encoding.should equal(Encoding::IBM437)
+ pair.first.encoding.should.equal?(Encoding::IBM437)
+ pair.last.encoding.should.equal?(Encoding::IBM437)
end
end
diff --git a/spec/ruby/core/env/size_spec.rb b/spec/ruby/core/env/size_spec.rb
index 7c8072481e..9c6de20df6 100644
--- a/spec/ruby/core/env/size_spec.rb
+++ b/spec/ruby/core/env/size_spec.rb
@@ -1,6 +1,15 @@
require_relative '../../spec_helper'
-require_relative 'shared/length'
describe "ENV.size" do
- it_behaves_like :env_length, :size
+ it "returns the number of ENV entries" do
+ orig = ENV.to_hash
+ begin
+ ENV.clear
+ ENV["foo"] = "bar"
+ ENV["baz"] = "boo"
+ ENV.size.should == 2
+ ensure
+ ENV.replace orig
+ end
+ end
end
diff --git a/spec/ruby/core/env/slice_spec.rb b/spec/ruby/core/env/slice_spec.rb
index 959239d2b2..4c0416547d 100644
--- a/spec/ruby/core/env/slice_spec.rb
+++ b/spec/ruby/core/env/slice_spec.rb
@@ -32,6 +32,6 @@ describe "ENV.slice" do
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")
+ -> { ENV.slice(Object.new) }.should.raise(TypeError, "no implicit conversion of Object into String")
end
end
diff --git a/spec/ruby/core/env/store_spec.rb b/spec/ruby/core/env/store_spec.rb
index b4700e0a96..a5fd7e1e26 100644
--- a/spec/ruby/core/env/store_spec.rb
+++ b/spec/ruby/core/env/store_spec.rb
@@ -1,6 +1,7 @@
require_relative '../../spec_helper'
-require_relative 'shared/store'
describe "ENV.store" do
- it_behaves_like :env_store, :store
+ it "is an alias of ENV.[]=" do
+ ENV.method(:store).should == ENV.method(:[]=)
+ end
end
diff --git a/spec/ruby/core/env/to_h_spec.rb b/spec/ruby/core/env/to_h_spec.rb
index 58ea2d2030..7e0fef2120 100644
--- a/spec/ruby/core/env/to_h_spec.rb
+++ b/spec/ruby/core/env/to_h_spec.rb
@@ -38,17 +38,17 @@ describe "ENV.to_h" do
it "raises ArgumentError if block returns longer or shorter array" do
-> do
ENV.to_h { |k, v| [k, v.upcase, 1] }
- end.should raise_error(ArgumentError, /element has wrong array length/)
+ end.should.raise(ArgumentError, /element has wrong array length/)
-> do
ENV.to_h { |k, v| [k] }
- end.should raise_error(ArgumentError, /element has wrong array length/)
+ end.should.raise(ArgumentError, /element has wrong array length/)
end
it "raises TypeError if block returns something other than Array" do
-> do
ENV.to_h { |k, v| "not-array" }
- end.should raise_error(TypeError, /wrong element type String/)
+ end.should.raise(TypeError, /wrong element type String/)
end
it "coerces returned pair to Array with #to_ary" do
@@ -64,7 +64,7 @@ describe "ENV.to_h" do
-> do
ENV.to_h { |k| x }
- end.should raise_error(TypeError, /wrong element type MockObject/)
+ end.should.raise(TypeError, /wrong element type MockObject/)
end
end
end
diff --git a/spec/ruby/core/env/update_spec.rb b/spec/ruby/core/env/update_spec.rb
index 95a8a2eb49..44d05d617f 100644
--- a/spec/ruby/core/env/update_spec.rb
+++ b/spec/ruby/core/env/update_spec.rb
@@ -1,6 +1,7 @@
require_relative '../../spec_helper'
-require_relative 'shared/update'
describe "ENV.update" do
- it_behaves_like :env_update, :update
+ it "is an alias of ENV.merge!" do
+ ENV.method(:update).should == ENV.method(:merge!)
+ end
end
diff --git a/spec/ruby/core/env/value_spec.rb b/spec/ruby/core/env/value_spec.rb
index 906e86ab39..c732cfbd15 100644
--- a/spec/ruby/core/env/value_spec.rb
+++ b/spec/ruby/core/env/value_spec.rb
@@ -1,6 +1,31 @@
require_relative '../../spec_helper'
-require_relative 'shared/value'
describe "ENV.value?" do
- it_behaves_like :env_value, :value?
+ before :each do
+ @saved_foo = ENV["foo"]
+ end
+
+ after :each do
+ ENV["foo"] = @saved_foo
+ end
+
+ it "returns true if ENV has the value" do
+ ENV["foo"] = "bar"
+ ENV.value?("bar").should == true
+ end
+
+ it "returns false if ENV doesn't have the value" do
+ ENV.value?("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.value?(v).should == true
+ end
+
+ it "returns nil if the argument is not a String and does not respond to #to_str" do
+ ENV.value?(Object.new).should == nil
+ end
end
diff --git a/spec/ruby/core/env/values_at_spec.rb b/spec/ruby/core/env/values_at_spec.rb
index 338680e820..4a733f4ed5 100644
--- a/spec/ruby/core/env/values_at_spec.rb
+++ b/spec/ruby/core/env/values_at_spec.rb
@@ -33,6 +33,6 @@ describe "ENV.values_at" do
end
it "raises TypeError when a key is not coercible to String" do
- -> { ENV.values_at("foo", Object.new) }.should raise_error(TypeError, "no implicit conversion of Object into String")
+ -> { ENV.values_at("foo", Object.new) }.should.raise(TypeError, "no implicit conversion of Object into String")
end
end
diff --git a/spec/ruby/core/exception/backtrace_locations_spec.rb b/spec/ruby/core/exception/backtrace_locations_spec.rb
index 86eb9d3413..62eab8a0f3 100644
--- a/spec/ruby/core/exception/backtrace_locations_spec.rb
+++ b/spec/ruby/core/exception/backtrace_locations_spec.rb
@@ -7,15 +7,15 @@ describe "Exception#backtrace_locations" do
end
it "returns nil if no backtrace was set" do
- Exception.new.backtrace_locations.should be_nil
+ Exception.new.backtrace_locations.should == nil
end
it "returns an Array" do
- @backtrace.should be_an_instance_of(Array)
+ @backtrace.should.instance_of?(Array)
end
it "sets each element to a Thread::Backtrace::Location" do
- @backtrace.each {|l| l.should be_an_instance_of(Thread::Backtrace::Location)}
+ @backtrace.each {|l| l.should.instance_of?(Thread::Backtrace::Location)}
end
it "produces a backtrace for an exception captured using $!" do
diff --git a/spec/ruby/core/exception/backtrace_spec.rb b/spec/ruby/core/exception/backtrace_spec.rb
index 9a65ea3820..a4a8272030 100644
--- a/spec/ruby/core/exception/backtrace_spec.rb
+++ b/spec/ruby/core/exception/backtrace_spec.rb
@@ -7,15 +7,15 @@ describe "Exception#backtrace" do
end
it "returns nil if no backtrace was set" do
- Exception.new.backtrace.should be_nil
+ Exception.new.backtrace.should == nil
end
it "returns an Array" do
- @backtrace.should be_an_instance_of(Array)
+ @backtrace.should.instance_of?(Array)
end
it "sets each element to a String" do
- @backtrace.each {|l| l.should be_an_instance_of(String)}
+ @backtrace.each {|l| l.should.instance_of?(String)}
end
it "includes the filename of the location where self raised in the first element" do
@@ -94,13 +94,13 @@ describe "Exception#backtrace" do
raise
rescue RuntimeError => err
bt = err.backtrace
- err.dup.backtrace.should equal(bt)
+ err.dup.backtrace.should.equal?(bt)
new_bt = ['hi']
err.set_backtrace new_bt
err.backtrace.should == new_bt
- err.dup.backtrace.should equal(new_bt)
+ err.dup.backtrace.should.equal?(new_bt)
end
end
end
diff --git a/spec/ruby/core/exception/cause_spec.rb b/spec/ruby/core/exception/cause_spec.rb
index cf4aaeb188..cfc15bdda3 100644
--- a/spec/ruby/core/exception/cause_spec.rb
+++ b/spec/ruby/core/exception/cause_spec.rb
@@ -4,53 +4,35 @@ describe "Exception#cause" do
it "returns the active exception when an exception is raised" do
begin
raise Exception, "the cause"
- rescue Exception
- begin
+ rescue Exception => cause
+ -> {
raise RuntimeError, "the consequence"
- rescue RuntimeError => e
- e.should be_an_instance_of(RuntimeError)
- e.message.should == "the consequence"
-
- e.cause.should be_an_instance_of(Exception)
- e.cause.message.should == "the cause"
- end
+ }.should.raise(RuntimeError, "the consequence", cause:)
end
end
it "is set for user errors caused by internal errors" do
- -> {
- begin
- 1 / 0
- rescue
- raise "foo"
- end
- }.should raise_error(RuntimeError) { |e|
- e.cause.should be_kind_of(ZeroDivisionError)
- }
+ begin
+ 1 / 0
+ rescue => cause
+ -> { raise "foo" }.should.raise(RuntimeError, cause:)
+ end
end
it "is set for internal errors caused by user errors" do
cause = RuntimeError.new "cause"
- -> {
- begin
- raise cause
- rescue
- 1 / 0
- end
- }.should raise_error(ZeroDivisionError) { |e|
- e.cause.should equal(cause)
- }
+ begin
+ raise cause
+ rescue
+ -> { 1 / 0 }.should.raise(ZeroDivisionError, cause:)
+ end
end
it "is not set to the exception itself when it is re-raised" do
- -> {
- begin
- raise RuntimeError
- rescue RuntimeError => e
- raise e
- end
- }.should raise_error(RuntimeError) { |e|
- e.cause.should == nil
- }
+ begin
+ raise RuntimeError
+ rescue RuntimeError => e
+ -> { raise e }.should.raise(RuntimeError, cause: nil)
+ end
end
end
diff --git a/spec/ruby/core/exception/dup_spec.rb b/spec/ruby/core/exception/dup_spec.rb
index edd54bfb37..b53ad79bf3 100644
--- a/spec/ruby/core/exception/dup_spec.rb
+++ b/spec/ruby/core/exception/dup_spec.rb
@@ -20,7 +20,7 @@ describe "Exception#dup" do
it "does not copy singleton methods" do
def @obj.special() :the_one end
dup = @obj.dup
- -> { dup.special }.should raise_error(NameError)
+ -> { dup.special }.should.raise(NameError)
end
it "does not copy modules included in the singleton class" do
@@ -29,7 +29,7 @@ describe "Exception#dup" do
end
dup = @obj.dup
- -> { dup.repr }.should raise_error(NameError)
+ -> { dup.repr }.should.raise(NameError)
end
it "does not copy constants defined in the singleton class" do
@@ -38,7 +38,7 @@ describe "Exception#dup" do
end
dup = @obj.dup
- -> { class << dup; CLONE; end }.should raise_error(NameError)
+ -> { class << dup; CLONE; end }.should.raise(NameError)
end
it "does copy the message" do
@@ -61,13 +61,13 @@ describe "Exception#dup" do
it "does copy the cause" do
begin
- raise StandardError, "the cause"
+ raise StandardError
rescue StandardError => cause
begin
- raise RuntimeError, "the consequence"
+ raise RuntimeError
rescue RuntimeError => e
- e.cause.should equal(cause)
- e.dup.cause.should equal(cause)
+ e.cause.should.equal?(cause)
+ e.dup.cause.should.equal?(cause)
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..b76b3bcd4a 100644
--- a/spec/ruby/core/exception/equal_value_spec.rb
+++ b/spec/ruby/core/exception/equal_value_spec.rb
@@ -31,10 +31,10 @@ describe "Exception#==" do
it "returns false if the two exceptions inherit from Exception but have different classes" do
one = RuntimeError.new("message")
one.set_backtrace [__dir__]
- one.should be_kind_of(Exception)
+ one.should.is_a?(Exception)
two = TypeError.new("message")
two.set_backtrace [__dir__]
- two.should be_kind_of(Exception)
+ two.should.is_a?(Exception)
one.should_not == two
end
diff --git a/spec/ruby/core/exception/errno_spec.rb b/spec/ruby/core/exception/errno_spec.rb
index 1ab4277700..36beae9976 100644
--- a/spec/ruby/core/exception/errno_spec.rb
+++ b/spec/ruby/core/exception/errno_spec.rb
@@ -4,21 +4,21 @@ require_relative 'fixtures/common'
describe "Errno::EINVAL.new" do
it "can be called with no arguments" do
exc = Errno::EINVAL.new
- exc.should be_an_instance_of(Errno::EINVAL)
+ exc.should.instance_of?(Errno::EINVAL)
exc.errno.should == Errno::EINVAL::Errno
exc.message.should == "Invalid argument"
end
it "accepts an optional custom message" do
exc = Errno::EINVAL.new('custom message')
- exc.should be_an_instance_of(Errno::EINVAL)
+ exc.should.instance_of?(Errno::EINVAL)
exc.errno.should == Errno::EINVAL::Errno
exc.message.should == "Invalid argument - custom message"
end
it "accepts an optional custom message and location" do
exc = Errno::EINVAL.new('custom message', 'location')
- exc.should be_an_instance_of(Errno::EINVAL)
+ exc.should.instance_of?(Errno::EINVAL)
exc.errno.should == Errno::EINVAL::Errno
exc.message.should == "Invalid argument @ location - custom message"
end
@@ -28,7 +28,7 @@ describe "Errno::EMFILE" do
it "can be subclassed" do
ExceptionSpecs::EMFILESub = Class.new(Errno::EMFILE)
exc = ExceptionSpecs::EMFILESub.new
- exc.should be_an_instance_of(ExceptionSpecs::EMFILESub)
+ exc.should.instance_of?(ExceptionSpecs::EMFILESub)
ensure
ExceptionSpecs.send(:remove_const, :EMFILESub)
end
@@ -47,7 +47,7 @@ end
describe "Errno::ENOTSUP" do
it "is defined" do
- Errno.should have_constant(:ENOTSUP)
+ Errno.should.const_defined?(:ENOTSUP, false)
end
it "is the same class as Errno::EOPNOTSUPP if they represent the same errno value" do
diff --git a/spec/ruby/core/exception/exception_spec.rb b/spec/ruby/core/exception/exception_spec.rb
index d6f5283bd9..f5424cdabd 100644
--- a/spec/ruby/core/exception/exception_spec.rb
+++ b/spec/ruby/core/exception/exception_spec.rb
@@ -20,7 +20,7 @@ describe "Exception#exception" do
it "returns an exception of the same class as self with the message given as argument" do
e = RuntimeError.new
e2 = e.exception("message")
- e2.should be_an_instance_of(RuntimeError)
+ e2.should.instance_of?(RuntimeError)
e2.message.should == "message"
end
@@ -62,7 +62,7 @@ describe "Exception#exception" do
it "returns an exception of the same class as self with the message given as argument, but without reinitializing" do
e = CustomArgumentError.new(:boom)
e2 = e.exception("message")
- e2.should be_an_instance_of(CustomArgumentError)
+ e2.should.instance_of?(CustomArgumentError)
e2.val.should == :boom
e2.message.should == "message"
end
diff --git a/spec/ruby/core/exception/exit_value_spec.rb b/spec/ruby/core/exception/exit_value_spec.rb
index 99987dd1bc..bb6cff1831 100644
--- a/spec/ruby/core/exception/exit_value_spec.rb
+++ b/spec/ruby/core/exception/exit_value_spec.rb
@@ -6,7 +6,7 @@ describe "LocalJumpError#exit_value" do
end
it "returns the value given to return" do
- -> { get_me_a_return.call }.should raise_error(LocalJumpError) { |e|
+ -> { get_me_a_return.call }.should.raise(LocalJumpError) { |e|
e.exit_value.should == 42
}
end
diff --git a/spec/ruby/core/exception/frozen_error_spec.rb b/spec/ruby/core/exception/frozen_error_spec.rb
index 51eb79cace..a28f524b54 100644
--- a/spec/ruby/core/exception/frozen_error_spec.rb
+++ b/spec/ruby/core/exception/frozen_error_spec.rb
@@ -3,7 +3,7 @@ require_relative '../../spec_helper'
describe "FrozenError.new" do
it "should take optional receiver argument" do
o = Object.new
- FrozenError.new("msg", receiver: o).receiver.should equal(o)
+ FrozenError.new("msg", receiver: o).receiver.should.equal?(o)
end
end
@@ -13,8 +13,8 @@ describe "FrozenError#receiver" do
begin
def o.x; end
rescue => e
- e.should be_kind_of(FrozenError)
- e.receiver.should equal(o)
+ e.should.is_a?(FrozenError)
+ e.receiver.should.equal?(o)
else
raise
end
@@ -26,12 +26,14 @@ describe "FrozenError#message" do
object = Object.new
object.freeze
+ msg_class = ruby_version_is("4.0") ? "Object" : "object"
+
-> {
def object.x; end
- }.should raise_error(FrozenError, "can't modify frozen object: #{object}")
+ }.should.raise(FrozenError, "can't modify frozen #{msg_class}: #{object}")
object = [].freeze
- -> { object << nil }.should raise_error(FrozenError, "can't modify frozen Array: []")
+ -> { object << nil }.should.raise(FrozenError, "can't modify frozen Array: []")
end
end
@@ -46,7 +48,7 @@ describe "Modifying a frozen object" do
# 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*.../)
+ -> { object.modify }.should.raise(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 0761d2b40c..5a5e0a2b3a 100644
--- a/spec/ruby/core/exception/full_message_spec.rb
+++ b/spec/ruby/core/exception/full_message_spec.rb
@@ -6,10 +6,10 @@ describe "Exception#full_message" do
e.set_backtrace(["a.rb:1", "b.rb:2"])
full_message = e.full_message
- full_message.should include "RuntimeError"
- full_message.should include "Some runtime error"
- full_message.should include "a.rb:1"
- full_message.should include "b.rb:2"
+ full_message.should.include? "RuntimeError"
+ full_message.should.include? "Some runtime error"
+ full_message.should.include? "a.rb:1"
+ full_message.should.include? "b.rb:2"
end
it "supports :highlight option and adds escape sequences to highlight some strings" do
@@ -141,8 +141,8 @@ describe "Exception#full_message" do
exception = e
end
- exception.full_message.should include "main exception"
- exception.full_message.should include "the cause"
+ exception.full_message.should.include? "main exception"
+ exception.full_message.should.include? "the cause"
end
it 'contains all the chain of exceptions' do
@@ -160,9 +160,9 @@ describe "Exception#full_message" do
exception = e
end
- exception.full_message.should include "last exception"
- exception.full_message.should include "intermediate exception"
- exception.full_message.should include "origin exception"
+ exception.full_message.should.include? "last exception"
+ exception.full_message.should.include? "intermediate exception"
+ exception.full_message.should.include? "origin exception"
end
it "relies on #detailed_message" do
@@ -219,8 +219,8 @@ describe "Exception#full_message" do
end
full_message = e.full_message
- full_message.should include "RuntimeError"
- full_message.should include "Some runtime error"
- full_message.should include "Some other runtime error"
+ full_message.should.include? "RuntimeError"
+ full_message.should.include? "Some runtime error"
+ full_message.should.include? "Some other runtime error"
end
end
diff --git a/spec/ruby/core/exception/io_error_spec.rb b/spec/ruby/core/exception/io_error_spec.rb
index ab8a72518f..940d5be876 100644
--- a/spec/ruby/core/exception/io_error_spec.rb
+++ b/spec/ruby/core/exception/io_error_spec.rb
@@ -3,14 +3,14 @@ require_relative '../../spec_helper'
describe "IO::EAGAINWaitReadable" do
it "combines Errno::EAGAIN and IO::WaitReadable" do
IO::EAGAINWaitReadable.superclass.should == Errno::EAGAIN
- IO::EAGAINWaitReadable.ancestors.should include IO::WaitReadable
+ IO::EAGAINWaitReadable.ancestors.should.include? IO::WaitReadable
end
it "is the same as IO::EWOULDBLOCKWaitReadable if Errno::EAGAIN is the same as Errno::EWOULDBLOCK" do
if Errno::EAGAIN.equal? Errno::EWOULDBLOCK
- IO::EAGAINWaitReadable.should equal IO::EWOULDBLOCKWaitReadable
+ IO::EAGAINWaitReadable.should.equal? IO::EWOULDBLOCKWaitReadable
else
- IO::EAGAINWaitReadable.should_not equal IO::EWOULDBLOCKWaitReadable
+ IO::EAGAINWaitReadable.should_not.equal? IO::EWOULDBLOCKWaitReadable
end
end
end
@@ -18,21 +18,21 @@ end
describe "IO::EWOULDBLOCKWaitReadable" do
it "combines Errno::EWOULDBLOCK and IO::WaitReadable" do
IO::EWOULDBLOCKWaitReadable.superclass.should == Errno::EWOULDBLOCK
- IO::EAGAINWaitReadable.ancestors.should include IO::WaitReadable
+ IO::EAGAINWaitReadable.ancestors.should.include? IO::WaitReadable
end
end
describe "IO::EAGAINWaitWritable" do
it "combines Errno::EAGAIN and IO::WaitWritable" do
IO::EAGAINWaitWritable.superclass.should == Errno::EAGAIN
- IO::EAGAINWaitWritable.ancestors.should include IO::WaitWritable
+ IO::EAGAINWaitWritable.ancestors.should.include? IO::WaitWritable
end
it "is the same as IO::EWOULDBLOCKWaitWritable if Errno::EAGAIN is the same as Errno::EWOULDBLOCK" do
if Errno::EAGAIN.equal? Errno::EWOULDBLOCK
- IO::EAGAINWaitWritable.should equal IO::EWOULDBLOCKWaitWritable
+ IO::EAGAINWaitWritable.should.equal? IO::EWOULDBLOCKWaitWritable
else
- IO::EAGAINWaitWritable.should_not equal IO::EWOULDBLOCKWaitWritable
+ IO::EAGAINWaitWritable.should_not.equal? IO::EWOULDBLOCKWaitWritable
end
end
end
@@ -40,6 +40,6 @@ end
describe "IO::EWOULDBLOCKWaitWritable" do
it "combines Errno::EWOULDBLOCK and IO::WaitWritable" do
IO::EWOULDBLOCKWaitWritable.superclass.should == Errno::EWOULDBLOCK
- IO::EAGAINWaitWritable.ancestors.should include IO::WaitWritable
+ IO::EAGAINWaitWritable.ancestors.should.include? IO::WaitWritable
end
end
diff --git a/spec/ruby/core/exception/name_spec.rb b/spec/ruby/core/exception/name_spec.rb
index c8a49b40e2..6e0e99d194 100644
--- a/spec/ruby/core/exception/name_spec.rb
+++ b/spec/ruby/core/exception/name_spec.rb
@@ -4,25 +4,25 @@ describe "NameError#name" do
it "returns a method name as a symbol" do
-> {
doesnt_exist
- }.should raise_error(NameError) {|e| e.name.should == :doesnt_exist }
+ }.should.raise(NameError) {|e| e.name.should == :doesnt_exist }
end
it "returns a constant name as a symbol" do
-> {
DoesntExist
- }.should raise_error(NameError) {|e| e.name.should == :DoesntExist }
+ }.should.raise(NameError) {|e| e.name.should == :DoesntExist }
end
it "returns a constant name without namespace as a symbol" do
-> {
Object::DoesntExist
- }.should raise_error(NameError) {|e| e.name.should == :DoesntExist }
+ }.should.raise(NameError) {|e| e.name.should == :DoesntExist }
end
it "returns a class variable name as a symbol" do
-> {
eval("class singleton_class::A; @@doesnt_exist end", binding, __FILE__, __LINE__)
- }.should raise_error(NameError) { |e| e.name.should == :@@doesnt_exist }
+ }.should.raise(NameError) { |e| e.name.should == :@@doesnt_exist }
end
it "returns the first argument passed to the method when a NameError is raised from #instance_variable_get" do
@@ -30,7 +30,7 @@ describe "NameError#name" do
-> {
Object.new.instance_variable_get(invalid_ivar_name)
- }.should raise_error(NameError) {|e| e.name.should equal(invalid_ivar_name) }
+ }.should.raise(NameError) {|e| e.name.should.equal?(invalid_ivar_name) }
end
it "returns the first argument passed to the method when a NameError is raised from #class_variable_get" do
@@ -38,6 +38,6 @@ describe "NameError#name" do
-> {
Object.class_variable_get(invalid_cvar_name)
- }.should raise_error(NameError) {|e| e.name.should equal(invalid_cvar_name) }
+ }.should.raise(NameError) {|e| e.name.should.equal?(invalid_cvar_name) }
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 772c569f67..9f92104082 100644
--- a/spec/ruby/core/exception/no_method_error_spec.rb
+++ b/spec/ruby/core/exception/no_method_error_spec.rb
@@ -35,7 +35,7 @@ describe "NoMethodError#args" do
NoMethodErrorSpecs::NoMethodErrorB.new.foo(1,a)
rescue Exception => e
e.args.should == [1,a]
- e.args[1].should equal a
+ e.args[1].should.equal? a
end
end
end
@@ -45,7 +45,7 @@ describe "NoMethodError#message" do
begin
NoMethodErrorSpecs::NoMethodErrorD.new.foo
rescue Exception => e
- e.should be_kind_of(NoMethodError)
+ e.should.is_a?(NoMethodError)
end
end
@@ -53,7 +53,7 @@ describe "NoMethodError#message" do
begin
NoMethodErrorSpecs::NoMethodErrorC.new.a_protected_method
rescue Exception => e
- e.should be_kind_of(NoMethodError)
+ e.should.is_a?(NoMethodError)
end
end
@@ -61,209 +61,150 @@ describe "NoMethodError#message" do
begin
NoMethodErrorSpecs::NoMethodErrorC.new.a_private_method
rescue Exception => e
- e.should be_kind_of(NoMethodError)
+ e.should.is_a?(NoMethodError)
e.message.lines[0].should =~ /private method [`']a_private_method' called for /
end
end
- ruby_version_is ""..."3.3" do
- it "calls #inspect 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 NoMethodError => error
- error.message.should =~ /\Aundefined method [`']bar' for <inspect>:#<Class:0x\h+>$/
- ScratchPad.recorded.should == [:inspect_called]
- end
- end
-
- it "fallbacks to a simpler representation of the receiver when receiver.inspect raises an exception" do
- test_class = Class.new do
- def inspect
- raise NoMethodErrorSpecs::InstanceException
- end
- end
- instance = test_class.new
-
- begin
- instance.bar
- rescue NoMethodError => error
- message = error.message
- message.should =~ /undefined method.+\bbar\b/
- message.should include test_class.inspect
- end
- end
-
- it "uses #name to display the receiver if it is a class" do
- klass = Class.new { def self.name; "MyClass"; end }
-
- begin
- klass.foo
- rescue NoMethodError => error
- error.message.should =~ /\Aundefined method [`']foo' for MyClass:Class$/
- end
+ it "uses a literal name when receiver is nil" do
+ begin
+ nil.foo
+ rescue NoMethodError => error
+ error.message.should =~ /\Aundefined method [`']foo' for nil\Z/
end
+ end
- it "uses #name to display the receiver if it is a module" do
- mod = Module.new { def self.name; "MyModule"; end }
-
- begin
- mod.foo
- rescue NoMethodError => error
- error.message.should =~ /\Aundefined method [`']foo' for MyModule:Module$/
- end
+ it "uses a literal name when receiver is true" do
+ begin
+ true.foo
+ rescue NoMethodError => error
+ error.message.should =~ /\Aundefined method [`']foo' for true\Z/
end
end
- ruby_version_is "3.3" do
- it "uses a literal name when receiver is nil" do
- begin
- nil.foo
- rescue NoMethodError => error
- error.message.should =~ /\Aundefined method [`']foo' for nil\Z/
- end
+ it "uses a literal name when receiver is false" do
+ begin
+ false.foo
+ rescue NoMethodError => error
+ error.message.should =~ /\Aundefined method [`']foo' for false\Z/
end
+ end
- it "uses a literal name when receiver is true" do
- begin
- true.foo
- rescue NoMethodError => error
- error.message.should =~ /\Aundefined method [`']foo' for true\Z/
- end
- end
+ it "uses #name when receiver is a class" do
+ klass = Class.new { def self.name; "MyClass"; end }
- it "uses a literal name when receiver is false" do
- begin
- false.foo
- rescue NoMethodError => error
- error.message.should =~ /\Aundefined method [`']foo' for false\Z/
- end
+ begin
+ klass.foo
+ rescue NoMethodError => error
+ error.message.should =~ /\Aundefined method [`']foo' for class MyClass\Z/
end
+ end
- it "uses #name when receiver is a class" do
- klass = Class.new { def self.name; "MyClass"; end }
+ it "uses class' string representation when receiver is an anonymous class" do
+ klass = Class.new
- begin
- klass.foo
- rescue NoMethodError => error
- error.message.should =~ /\Aundefined method [`']foo' for class MyClass\Z/
- end
+ begin
+ klass.foo
+ rescue NoMethodError => error
+ error.message.should =~ /\Aundefined method [`']foo' for class #<Class:0x\h+>\Z/
end
+ end
- it "uses class' string representation when receiver is an anonymous class" do
- klass = Class.new
+ it "uses class' string representation when receiver is a singleton class" do
+ obj = Object.new
+ singleton_class = obj.singleton_class
- begin
- klass.foo
- rescue NoMethodError => error
- error.message.should =~ /\Aundefined method [`']foo' for class #<Class:0x\h+>\Z/
- end
+ begin
+ singleton_class.foo
+ rescue NoMethodError => error
+ error.message.should =~ /\Aundefined method [`']foo' for class #<Class:#<Object:0x\h+>>\Z/
end
+ end
- it "uses class' string representation when receiver is a singleton class" do
- obj = Object.new
- singleton_class = obj.singleton_class
+ it "uses #name when receiver is a module" do
+ mod = Module.new { def self.name; "MyModule"; end }
- begin
- singleton_class.foo
- rescue NoMethodError => error
- error.message.should =~ /\Aundefined method [`']foo' for class #<Class:#<Object:0x\h+>>\Z/
- end
+ begin
+ mod.foo
+ rescue NoMethodError => error
+ error.message.should =~ /\Aundefined method [`']foo' for module MyModule\Z/
end
+ end
- it "uses #name when receiver is a module" do
- mod = Module.new { def self.name; "MyModule"; end }
+ it "uses module's string representation when receiver is an anonymous module" do
+ m = Module.new
- begin
- mod.foo
- rescue NoMethodError => error
- error.message.should =~ /\Aundefined method [`']foo' for module MyModule\Z/
- end
+ begin
+ m.foo
+ rescue NoMethodError => error
+ error.message.should =~ /\Aundefined method [`']foo' for module #<Module:0x\h+>\Z/
end
+ end
- it "uses module's string representation when receiver is an anonymous module" do
- m = Module.new
+ it "uses class #name when receiver is an ordinary object" do
+ klass = Class.new { def self.name; "MyClass"; end }
+ instance = klass.new
- begin
- m.foo
- rescue NoMethodError => error
- error.message.should =~ /\Aundefined method [`']foo' for module #<Module:0x\h+>\Z/
- end
+ begin
+ instance.bar
+ rescue NoMethodError => error
+ error.message.should =~ /\Aundefined method [`']bar' for an instance of MyClass\Z/
end
+ end
- it "uses class #name when receiver is an ordinary object" do
- klass = Class.new { def self.name; "MyClass"; end }
- instance = klass.new
+ it "uses class string representation when receiver is an instance of anonymous class" do
+ klass = Class.new
+ instance = klass.new
- begin
- instance.bar
- rescue NoMethodError => error
- error.message.should =~ /\Aundefined method [`']bar' for an instance of MyClass\Z/
- end
+ begin
+ instance.bar
+ rescue NoMethodError => error
+ error.message.should =~ /\Aundefined method [`']bar' for an instance of #<Class:0x\h+>\Z/
end
+ end
- it "uses class string representation when receiver is an instance of anonymous class" do
- klass = Class.new
- instance = klass.new
+ it "uses class name when receiver has a singleton class" do
+ instance = NoMethodErrorSpecs::NoMethodErrorA.new
+ def instance.foo; end
- begin
- instance.bar
- rescue NoMethodError => error
- error.message.should =~ /\Aundefined method [`']bar' for an instance of #<Class:0x\h+>\Z/
- end
+ begin
+ instance.bar
+ rescue NoMethodError => error
+ error.message.should =~ /\Aundefined method [`']bar' for #<NoMethodErrorSpecs::NoMethodErrorA:0x\h+>\Z/
end
+ end
- it "uses class name when receiver has a singleton class" do
- instance = NoMethodErrorSpecs::NoMethodErrorA.new
- def instance.foo; end
-
- begin
- instance.bar
- rescue NoMethodError => error
- error.message.should =~ /\Aundefined method [`']bar' for #<NoMethodErrorSpecs::NoMethodErrorA:0x\h+>\Z/
+ it "does not call #inspect when calling Exception#message" do
+ ScratchPad.record []
+ test_class = Class.new do
+ def inspect
+ ScratchPad << :inspect_called
+ "<inspect>"
end
end
+ instance = test_class.new
- it "does not call #inspect 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 NoMethodError => error
- error.message.should =~ /\Aundefined method [`']bar' for an instance of #<Class:0x\h+>\Z/
- ScratchPad.recorded.should == []
- end
+ begin
+ instance.bar
+ rescue NoMethodError => error
+ error.message.should =~ /\Aundefined method [`']bar' for an instance of #<Class:0x\h+>\Z/
+ ScratchPad.recorded.should == []
end
+ end
- it "does not truncate long class names" do
- class_name = 'ExceptionSpecs::A' + 'a'*100
+ it "does not truncate long class names" do
+ class_name = 'ExceptionSpecs::A' + 'a'*100
- begin
- eval <<~RUBY
- class #{class_name}
- end
+ begin
+ eval <<~RUBY
+ class #{class_name}
+ end
- obj = #{class_name}.new
- obj.foo
- RUBY
- rescue NoMethodError => error
- error.message.should =~ /\Aundefined method [`']foo' for an instance of #{class_name}\Z/
- end
+ obj = #{class_name}.new
+ obj.foo
+ RUBY
+ rescue NoMethodError => error
+ error.message.should =~ /\Aundefined method [`']foo' for an instance of #{class_name}\Z/
end
end
end
diff --git a/spec/ruby/core/exception/reason_spec.rb b/spec/ruby/core/exception/reason_spec.rb
index 210bbc9725..d7022768b6 100644
--- a/spec/ruby/core/exception/reason_spec.rb
+++ b/spec/ruby/core/exception/reason_spec.rb
@@ -6,7 +6,7 @@ describe "LocalJumpError#reason" do
end
it "returns 'return' for a return" do
- -> { get_me_a_return.call }.should raise_error(LocalJumpError) { |e|
+ -> { get_me_a_return.call }.should.raise(LocalJumpError) { |e|
e.reason.should == :return
}
end
diff --git a/spec/ruby/core/exception/receiver_spec.rb b/spec/ruby/core/exception/receiver_spec.rb
index d1c23b67be..6ecf640ad8 100644
--- a/spec/ruby/core/exception/receiver_spec.rb
+++ b/spec/ruby/core/exception/receiver_spec.rb
@@ -11,31 +11,31 @@ describe "NameError#receiver" do
-> {
receiver.doesnt_exist
- }.should raise_error(NameError) {|e| e.receiver.should equal(receiver) }
+ }.should.raise(NameError) {|e| e.receiver.should.equal?(receiver) }
end
it "returns the Object class when an undefined constant is called without namespace" do
-> {
DoesntExist
- }.should raise_error(NameError) {|e| e.receiver.should equal(Object) }
+ }.should.raise(NameError) {|e| e.receiver.should.equal?(Object) }
end
it "returns a class when an undefined constant is called" do
-> {
NameErrorSpecs::ReceiverClass::DoesntExist
- }.should raise_error(NameError) {|e| e.receiver.should equal(NameErrorSpecs::ReceiverClass) }
+ }.should.raise(NameError) {|e| e.receiver.should.equal?(NameErrorSpecs::ReceiverClass) }
end
it "returns the Object class when an undefined class variable is called" do
-> {
eval("class singleton_class::A; @@doesnt_exist end", binding, __FILE__, __LINE__)
- }.should raise_error(NameError) {|e| e.receiver.should equal(singleton_class::A) }
+ }.should.raise(NameError) {|e| e.receiver.should.equal?(singleton_class::A) }
end
it "returns a class when an undefined class variable is called in a subclass' namespace" do
-> {
NameErrorSpecs::ReceiverClass.new.call_undefined_class_variable
- }.should raise_error(NameError) {|e| e.receiver.should equal(NameErrorSpecs::ReceiverClass) }
+ }.should.raise(NameError) {|e| e.receiver.should.equal?(NameErrorSpecs::ReceiverClass) }
end
it "returns the receiver when raised from #instance_variable_get" do
@@ -43,16 +43,16 @@ describe "NameError#receiver" do
-> {
receiver.instance_variable_get("invalid_ivar_name")
- }.should raise_error(NameError) {|e| e.receiver.should equal(receiver) }
+ }.should.raise(NameError) {|e| e.receiver.should.equal?(receiver) }
end
it "returns the receiver when raised from #class_variable_get" do
-> {
Object.class_variable_get("invalid_cvar_name")
- }.should raise_error(NameError) {|e| e.receiver.should equal(Object) }
+ }.should.raise(NameError) {|e| e.receiver.should.equal?(Object) }
end
it "raises an ArgumentError when the receiver is none" do
- -> { NameError.new.receiver }.should raise_error(ArgumentError)
+ -> { NameError.new.receiver }.should.raise(ArgumentError)
end
end
diff --git a/spec/ruby/core/exception/result_spec.rb b/spec/ruby/core/exception/result_spec.rb
index d42fcdffcb..451ff43af5 100644
--- a/spec/ruby/core/exception/result_spec.rb
+++ b/spec/ruby/core/exception/result_spec.rb
@@ -14,8 +14,8 @@ describe "StopIteration#result" do
it "returns the method-returned-object from an Enumerator" do
@enum.next
@enum.next
- -> { @enum.next }.should raise_error(StopIteration) { |error|
- error.result.should equal(:method_returned)
+ -> { @enum.next }.should.raise(StopIteration) { |error|
+ error.result.should.equal?(:method_returned)
}
end
end
diff --git a/spec/ruby/core/exception/shared/new.rb b/spec/ruby/core/exception/shared/new.rb
index bcde8ee4b2..048fd14dd2 100644
--- a/spec/ruby/core/exception/shared/new.rb
+++ b/spec/ruby/core/exception/shared/new.rb
@@ -1,6 +1,6 @@
describe :exception_new, shared: true do
it "creates a new instance of Exception" do
- Exception.should be_ancestor_of(Exception.send(@method).class)
+ Exception.send(@method).class.ancestors.should.include?(Exception)
end
it "sets the message of the Exception when passes a message" do
@@ -12,7 +12,7 @@ describe :exception_new, shared: true do
end
it "returns the exception when it has a custom constructor" do
- ExceptionSpecs::ConstructorException.send(@method).should be_kind_of(ExceptionSpecs::ConstructorException)
+ ExceptionSpecs::ConstructorException.send(@method).should.is_a?(ExceptionSpecs::ConstructorException)
end
end
diff --git a/spec/ruby/core/exception/shared/set_backtrace.rb b/spec/ruby/core/exception/shared/set_backtrace.rb
index c6213b42b4..934bf3dc5f 100644
--- a/spec/ruby/core/exception/shared/set_backtrace.rb
+++ b/spec/ruby/core/exception/shared/set_backtrace.rb
@@ -43,22 +43,22 @@ describe :exception_set_backtrace, shared: true do
it "accepts nil" do
err = @method.call(nil)
- err.backtrace.should be_nil
+ err.backtrace.should == nil
end
it "raises a TypeError when passed a Symbol" do
- -> { @method.call(:unhappy) }.should raise_error(TypeError)
+ -> { @method.call(:unhappy) }.should.raise(TypeError)
end
it "raises a TypeError when the Array contains a Symbol" do
- -> { @method.call(["String", :unhappy]) }.should raise_error(TypeError)
+ -> { @method.call(["String", :unhappy]) }.should.raise(TypeError)
end
it "raises a TypeError when the array contains nil" do
- -> { @method.call(["String", nil]) }.should raise_error(TypeError)
+ -> { @method.call(["String", nil]) }.should.raise(TypeError)
end
it "raises a TypeError when the argument is a nested array" do
- -> { @method.call(["String", ["String"]]) }.should raise_error(TypeError)
+ -> { @method.call(["String", ["String"]]) }.should.raise(TypeError)
end
end
diff --git a/spec/ruby/core/exception/signal_exception_spec.rb b/spec/ruby/core/exception/signal_exception_spec.rb
index 1a0940743f..010181bc55 100644
--- a/spec/ruby/core/exception/signal_exception_spec.rb
+++ b/spec/ruby/core/exception/signal_exception_spec.rb
@@ -9,7 +9,7 @@ describe "SignalException.new" do
end
it "raises an exception with an invalid signal number" do
- -> { SignalException.new(100000) }.should raise_error(ArgumentError)
+ -> { SignalException.new(100000) }.should.raise(ArgumentError)
end
it "takes a signal name without SIG prefix as the first argument" do
@@ -27,11 +27,11 @@ describe "SignalException.new" do
end
it "raises an exception with an invalid signal name" do
- -> { SignalException.new("NONEXISTENT") }.should raise_error(ArgumentError)
+ -> { SignalException.new("NONEXISTENT") }.should.raise(ArgumentError)
end
it "raises an exception with an invalid first argument type" do
- -> { SignalException.new(Object.new) }.should raise_error(ArgumentError)
+ -> { SignalException.new(Object.new) }.should.raise(ArgumentError)
end
it "takes a signal symbol without SIG prefix as the first argument" do
@@ -49,7 +49,7 @@ describe "SignalException.new" do
end
it "raises an exception with an invalid signal name" do
- -> { SignalException.new(:NONEXISTENT) }.should raise_error(ArgumentError)
+ -> { SignalException.new(:NONEXISTENT) }.should.raise(ArgumentError)
end
it "takes an optional message argument with a signal number" do
@@ -60,7 +60,7 @@ describe "SignalException.new" do
end
it "raises an exception for an optional argument with a signal name" do
- -> { SignalException.new("INT","name") }.should raise_error(ArgumentError)
+ -> { SignalException.new("INT","name") }.should.raise(ArgumentError)
end
end
diff --git a/spec/ruby/core/exception/signm_spec.rb b/spec/ruby/core/exception/signm_spec.rb
index 4adff3b5ee..cabcc7ad58 100644
--- a/spec/ruby/core/exception/signm_spec.rb
+++ b/spec/ruby/core/exception/signm_spec.rb
@@ -2,7 +2,7 @@ require_relative '../../spec_helper'
describe "SignalException#signm" do
it "returns the signal name" do
- -> { Process.kill(:TERM, Process.pid) }.should raise_error(SignalException) { |e|
+ -> { Process.kill(:TERM, Process.pid) }.should.raise(SignalException) { |e|
e.signm.should == 'SIGTERM'
}
end
diff --git a/spec/ruby/core/exception/signo_spec.rb b/spec/ruby/core/exception/signo_spec.rb
index 62fc321516..46e79a8daf 100644
--- a/spec/ruby/core/exception/signo_spec.rb
+++ b/spec/ruby/core/exception/signo_spec.rb
@@ -2,7 +2,7 @@ require_relative '../../spec_helper'
describe "SignalException#signo" do
it "returns the signal number" do
- -> { Process.kill(:TERM, Process.pid) }.should raise_error(SignalException) { |e|
+ -> { Process.kill(:TERM, Process.pid) }.should.raise(SignalException) { |e|
e.signo.should == Signal.list['TERM']
}
end
diff --git a/spec/ruby/core/exception/standard_error_spec.rb b/spec/ruby/core/exception/standard_error_spec.rb
index 17e98ce7f0..b05d247f67 100644
--- a/spec/ruby/core/exception/standard_error_spec.rb
+++ b/spec/ruby/core/exception/standard_error_spec.rb
@@ -18,6 +18,6 @@ describe "StandardError" do
end
it "does not rescue superclass of StandardError" do
- -> { begin; raise Exception; rescue; end }.should raise_error(Exception)
+ -> { begin; raise Exception; rescue; end }.should.raise(Exception)
end
end
diff --git a/spec/ruby/core/exception/status_spec.rb b/spec/ruby/core/exception/status_spec.rb
index 8ace00fe10..7369b0815d 100644
--- a/spec/ruby/core/exception/status_spec.rb
+++ b/spec/ruby/core/exception/status_spec.rb
@@ -2,7 +2,7 @@ require_relative '../../spec_helper'
describe "SystemExit#status" do
it "returns the exit status" do
- -> { exit 42 }.should raise_error(SystemExit) { |e|
+ -> { exit 42 }.should.raise(SystemExit) { |e|
e.status.should == 42
}
end
diff --git a/spec/ruby/core/exception/success_spec.rb b/spec/ruby/core/exception/success_spec.rb
index 6f21743340..5ab8f94454 100644
--- a/spec/ruby/core/exception/success_spec.rb
+++ b/spec/ruby/core/exception/success_spec.rb
@@ -2,13 +2,13 @@ require_relative '../../spec_helper'
describe "SystemExit#success?" do
it "returns true if the process exited successfully" do
- -> { exit 0 }.should raise_error(SystemExit) { |e|
+ -> { exit 0 }.should.raise(SystemExit) { |e|
e.should.success?
}
end
it "returns false if the process exited unsuccessfully" do
- -> { exit(-1) }.should raise_error(SystemExit) { |e|
+ -> { exit(-1) }.should.raise(SystemExit) { |e|
e.should_not.success?
}
end
diff --git a/spec/ruby/core/exception/syntax_error_spec.rb b/spec/ruby/core/exception/syntax_error_spec.rb
index 4c713a3507..66eb5649aa 100644
--- a/spec/ruby/core/exception/syntax_error_spec.rb
+++ b/spec/ruby/core/exception/syntax_error_spec.rb
@@ -6,7 +6,7 @@ describe "SyntaxError#path" do
-> {
eval("if true", TOPLEVEL_BINDING, filename)
- }.should raise_error(SyntaxError) { |e|
+ }.should.raise(SyntaxError) { |e|
e.path.should == filename
}
end
@@ -16,7 +16,7 @@ describe "SyntaxError#path" do
-> {
require_relative "fixtures/syntax_error"
- }.should raise_error(SyntaxError) { |e| e.path.should == expected_path }
+ }.should.raise(SyntaxError) { |e| e.path.should == expected_path }
end
it "returns nil when constructed directly" do
diff --git a/spec/ruby/core/exception/system_call_error_spec.rb b/spec/ruby/core/exception/system_call_error_spec.rb
index 4fe51901c8..da01c5b6b0 100644
--- a/spec/ruby/core/exception/system_call_error_spec.rb
+++ b/spec/ruby/core/exception/system_call_error_spec.rb
@@ -14,8 +14,8 @@ describe "SystemCallError" do
end
exc = ExceptionSpecs::SCESub.new
- ScratchPad.recorded.should equal(:initialize)
- exc.should be_an_instance_of(ExceptionSpecs::SCESub)
+ ScratchPad.recorded.should.equal?(:initialize)
+ exc.should.instance_of?(ExceptionSpecs::SCESub)
ensure
ExceptionSpecs.send(:remove_const, :SCESub)
end
@@ -31,7 +31,7 @@ describe "SystemCallError.new" do
end
it "requires at least one argument" do
- -> { SystemCallError.new }.should raise_error(ArgumentError)
+ -> { SystemCallError.new }.should.raise(ArgumentError)
end
it "accepts single Integer argument as errno" do
@@ -44,16 +44,16 @@ describe "SystemCallError.new" do
end
it "constructs a SystemCallError for an unknown error number" do
- SystemCallError.new(-2**24).should be_an_instance_of(SystemCallError)
- SystemCallError.new(-1).should be_an_instance_of(SystemCallError)
- SystemCallError.new(@unknown_errno).should be_an_instance_of(SystemCallError)
- SystemCallError.new(2**24).should be_an_instance_of(SystemCallError)
+ SystemCallError.new(-2**24).should.instance_of?(SystemCallError)
+ SystemCallError.new(-1).should.instance_of?(SystemCallError)
+ SystemCallError.new(@unknown_errno).should.instance_of?(SystemCallError)
+ SystemCallError.new(2**24).should.instance_of?(SystemCallError)
end
it "constructs the appropriate Errno class" do
e = SystemCallError.new(@example_errno)
- e.should be_kind_of(SystemCallError)
- e.should be_an_instance_of(@example_errno_class)
+ e.should.is_a?(SystemCallError)
+ e.should.instance_of?(@example_errno_class)
end
it "sets an error message corresponding to an appropriate Errno class" do
@@ -63,14 +63,14 @@ describe "SystemCallError.new" do
it "accepts an optional custom message preceding the errno" do
exc = SystemCallError.new("custom message", @example_errno)
- exc.should be_an_instance_of(@example_errno_class)
+ exc.should.instance_of?(@example_errno_class)
exc.errno.should == @example_errno
exc.message.should == 'Invalid argument - custom message'
end
it "accepts an optional third argument specifying the location" do
exc = SystemCallError.new("custom message", @example_errno, "location")
- exc.should be_an_instance_of(@example_errno_class)
+ exc.should.instance_of?(@example_errno_class)
exc.errno.should == @example_errno
exc.message.should == 'Invalid argument @ location - custom message'
end
@@ -90,7 +90,7 @@ describe "SystemCallError.new" do
end
it "treats nil errno as unknown error value" do
- SystemCallError.new(nil).should be_an_instance_of(SystemCallError)
+ SystemCallError.new(nil).should.instance_of?(SystemCallError)
end
it "treats nil custom message as if it is not passed at all" do
@@ -111,15 +111,15 @@ describe "SystemCallError.new" do
end
it "raises TypeError if message is not a String" do
- -> { SystemCallError.new(:foo, 1) }.should raise_error(TypeError, /no implicit conversion of Symbol into String/)
+ -> { SystemCallError.new(:foo, 1) }.should.raise(TypeError, /no implicit conversion of Symbol into String/)
end
it "raises TypeError if errno is not an Integer" do
- -> { SystemCallError.new('foo', 'bar') }.should raise_error(TypeError, /no implicit conversion of String into Integer/)
+ -> { SystemCallError.new('foo', 'bar') }.should.raise(TypeError, /no implicit conversion of String into Integer/)
end
it "raises RangeError if errno is a Complex not convertible to Integer" do
- -> { SystemCallError.new('foo', Complex(2.9, 1)) }.should raise_error(RangeError, /can't convert/)
+ -> { SystemCallError.new('foo', Complex(2.9, 1)) }.should.raise(RangeError, /can't convert/)
end
end
diff --git a/spec/ruby/core/false/dup_spec.rb b/spec/ruby/core/false/dup_spec.rb
index 1a569a2f4f..b0eb85529e 100644
--- a/spec/ruby/core/false/dup_spec.rb
+++ b/spec/ruby/core/false/dup_spec.rb
@@ -2,6 +2,6 @@ require_relative '../../spec_helper'
describe "FalseClass#dup" do
it "returns self" do
- false.dup.should equal(false)
+ false.dup.should.equal?(false)
end
end
diff --git a/spec/ruby/core/false/falseclass_spec.rb b/spec/ruby/core/false/falseclass_spec.rb
index c018ef2421..8dfe5ae891 100644
--- a/spec/ruby/core/false/falseclass_spec.rb
+++ b/spec/ruby/core/false/falseclass_spec.rb
@@ -4,12 +4,12 @@ describe "FalseClass" do
it ".allocate raises a TypeError" do
-> do
FalseClass.allocate
- end.should raise_error(TypeError)
+ end.should.raise(TypeError)
end
it ".new is undefined" do
-> do
FalseClass.new
- end.should raise_error(NoMethodError)
+ end.should.raise(NoMethodError)
end
end
diff --git a/spec/ruby/core/false/inspect_spec.rb b/spec/ruby/core/false/inspect_spec.rb
index 4cbb55d434..70f4aa0159 100644
--- a/spec/ruby/core/false/inspect_spec.rb
+++ b/spec/ruby/core/false/inspect_spec.rb
@@ -1,7 +1,7 @@
require_relative '../../spec_helper'
describe "FalseClass#inspect" do
- it "returns the string 'false'" do
- false.inspect.should == "false"
+ it "is an alias of FalseClass#to_s" do
+ false.method(:inspect).should == false.method(:to_s)
end
end
diff --git a/spec/ruby/core/false/singleton_method_spec.rb b/spec/ruby/core/false/singleton_method_spec.rb
index 738794b46c..72aee8609a 100644
--- a/spec/ruby/core/false/singleton_method_spec.rb
+++ b/spec/ruby/core/false/singleton_method_spec.rb
@@ -1,15 +1,13 @@
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
+ it "raises regardless of whether FalseClass defines the method" do
+ -> { false.singleton_method(:foo) }.should.raise(NameError)
+ begin
+ def (false).foo; end
+ -> { false.singleton_method(:foo) }.should.raise(NameError)
+ ensure
+ FalseClass.send(:remove_method, :foo)
end
end
end
diff --git a/spec/ruby/core/false/to_s_spec.rb b/spec/ruby/core/false/to_s_spec.rb
index 62f67f6f55..9e24be26a2 100644
--- a/spec/ruby/core/false/to_s_spec.rb
+++ b/spec/ruby/core/false/to_s_spec.rb
@@ -10,6 +10,6 @@ describe "FalseClass#to_s" do
end
it "always returns the same string" do
- false.to_s.should equal(false.to_s)
+ false.to_s.should.equal?(false.to_s)
end
end
diff --git a/spec/ruby/core/false/xor_spec.rb b/spec/ruby/core/false/xor_spec.rb
index 1b87b9f412..d8432ca326 100644
--- a/spec/ruby/core/false/xor_spec.rb
+++ b/spec/ruby/core/false/xor_spec.rb
@@ -1,11 +1,7 @@
require_relative '../../spec_helper'
describe "FalseClass#^" do
- it "returns false if other is nil or false, otherwise true" do
- (false ^ false).should == false
- (false ^ true).should == true
- (false ^ nil).should == false
- (false ^ "").should == true
- (false ^ mock('x')).should == true
+ it "is an alias of FalseClass#|" do
+ false.method(:^).should == false.method(:|)
end
end
diff --git a/spec/ruby/core/fiber/alive_spec.rb b/spec/ruby/core/fiber/alive_spec.rb
index a1df582435..6fb1229d95 100644
--- a/spec/ruby/core/fiber/alive_spec.rb
+++ b/spec/ruby/core/fiber/alive_spec.rb
@@ -3,18 +3,18 @@ require_relative '../../spec_helper'
describe "Fiber#alive?" do
it "returns true for a Fiber that hasn't had #resume called" do
fiber = Fiber.new { true }
- fiber.alive?.should be_true
+ fiber.alive?.should == true
end
# FIXME: Better description?
it "returns true for a Fiber that's yielded to the caller" do
fiber = Fiber.new { Fiber.yield }
fiber.resume
- fiber.alive?.should be_true
+ fiber.alive?.should == true
end
it "returns true when called from its Fiber" do
- fiber = Fiber.new { fiber.alive?.should be_true }
+ fiber = Fiber.new { fiber.alive?.should == true }
fiber.resume
end
@@ -28,17 +28,17 @@ describe "Fiber#alive?" do
it "returns false for a Fiber that's dead" do
fiber = Fiber.new { true }
fiber.resume
- -> { fiber.resume }.should raise_error(FiberError)
- fiber.alive?.should be_false
+ -> { fiber.resume }.should.raise(FiberError)
+ fiber.alive?.should == false
end
it "always returns false for a dead Fiber" do
fiber = Fiber.new { true }
fiber.resume
- -> { fiber.resume }.should raise_error(FiberError)
- fiber.alive?.should be_false
- -> { fiber.resume }.should raise_error(FiberError)
- fiber.alive?.should be_false
- fiber.alive?.should be_false
+ -> { fiber.resume }.should.raise(FiberError)
+ fiber.alive?.should == false
+ -> { fiber.resume }.should.raise(FiberError)
+ fiber.alive?.should == false
+ fiber.alive?.should == false
end
end
diff --git a/spec/ruby/core/fiber/current_spec.rb b/spec/ruby/core/fiber/current_spec.rb
index b93df77a89..cc5c9117b6 100644
--- a/spec/ruby/core/fiber/current_spec.rb
+++ b/spec/ruby/core/fiber/current_spec.rb
@@ -3,20 +3,20 @@ require_relative '../../spec_helper'
describe "Fiber.current" do
it "returns the root Fiber when called outside of a Fiber" do
root = Fiber.current
- root.should be_an_instance_of(Fiber)
+ root.should.instance_of?(Fiber)
# We can always transfer to the root Fiber; it will never die
5.times do
- root.transfer.should be_nil
- root.alive?.should be_true
+ root.transfer.should == nil
+ root.alive?.should == true
end
end
it "returns the current Fiber when called from a Fiber" do
fiber = Fiber.new do
this = Fiber.current
- this.should be_an_instance_of(Fiber)
+ this.should.instance_of?(Fiber)
this.should == fiber
- this.alive?.should be_true
+ this.alive?.should == true
end
fiber.resume
end
@@ -26,9 +26,9 @@ describe "Fiber.current" do
fiber = Fiber.new do
states << :fiber
this = Fiber.current
- this.should be_an_instance_of(Fiber)
+ this.should.instance_of?(Fiber)
this.should == fiber
- this.alive?.should be_true
+ this.alive?.should == true
end
fiber2 = Fiber.new do
diff --git a/spec/ruby/core/fiber/fixtures/scheduler.rb b/spec/ruby/core/fiber/fixtures/scheduler.rb
new file mode 100644
index 0000000000..16bd2f6b44
--- /dev/null
+++ b/spec/ruby/core/fiber/fixtures/scheduler.rb
@@ -0,0 +1,35 @@
+module FiberSpecs
+
+ class LoggingScheduler
+ attr_reader :events
+ def initialize
+ @events = []
+ end
+
+ def block(*args)
+ @events << { event: :block, fiber: Fiber.current, args: args }
+ Fiber.yield
+ end
+
+ def io_wait(*args)
+ @events << { event: :io_wait, fiber: Fiber.current, args: args }
+ Fiber.yield
+ end
+
+ def kernel_sleep(*args)
+ @events << { event: :kernel_sleep, fiber: Fiber.current, args: args }
+ Fiber.yield
+ end
+
+ def unblock(*args)
+ @events << { event: :unblock, fiber: Fiber.current, args: args }
+ Fiber.yield
+ end
+
+ def fiber_interrupt(*args)
+ @events << { event: :fiber_interrupt, fiber: Fiber.current, args: args }
+ Fiber.yield
+ end
+ end
+
+end
diff --git a/spec/ruby/core/fiber/kill_spec.rb b/spec/ruby/core/fiber/kill_spec.rb
index 2f4c499280..abf23ff176 100644
--- a/spec/ruby/core/fiber/kill_spec.rb
+++ b/spec/ruby/core/fiber/kill_spec.rb
@@ -2,89 +2,87 @@ 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{}
+describe "Fiber#kill" do
+ it "kills a non-resumed fiber" do
+ fiber = Fiber.new{}
- fiber.alive?.should == true
+ 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
- fiber.kill
- fiber.alive?.should == false
- end
+ it "kills a resumed fiber" do
+ fiber = Fiber.new{while true; Fiber.yield; end}
+ fiber.resume
- it "can kill itself" do
- fiber = Fiber.new do
- Fiber.current.kill
- end
+ fiber.alive?.should == true
- fiber.alive?.should == true
+ fiber.kill
+ fiber.alive?.should == false
+ end
- fiber.resume
- fiber.alive?.should == false
+ it "can kill itself" do
+ fiber = Fiber.new do
+ Fiber.current.kill
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
+ fiber.alive?.should == true
+
+ fiber.resume
+ fiber.alive?.should == false
+ end
- child.resume
+ it "kills a resumed fiber from a child" do
+ parent = Fiber.new do
+ child = Fiber.new do
+ parent.kill
+ parent.alive?.should == true
end
- parent.resume
- parent.alive?.should == false
+ child.resume
end
- it "executes the ensure block" do
- ensure_executed = false
+ parent.resume
+ parent.alive?.should == false
+ end
- fiber = Fiber.new do
- while true; Fiber.yield; end
- ensure
- ensure_executed = true
- end
+ it "executes the ensure block" do
+ ensure_executed = false
- fiber.resume
- fiber.kill
- ensure_executed.should == true
+ fiber = Fiber.new do
+ while true; Fiber.yield; end
+ ensure
+ ensure_executed = true
end
- it "does not execute rescue block" do
- rescue_executed = false
+ fiber.resume
+ fiber.kill
+ ensure_executed.should == true
+ end
- fiber = Fiber.new do
- while true; Fiber.yield; end
- rescue Exception
- rescue_executed = true
- end
+ it "does not execute rescue block" do
+ rescue_executed = false
- fiber.resume
- fiber.kill
- rescue_executed.should == false
+ fiber = Fiber.new do
+ while true; Fiber.yield; end
+ rescue Exception
+ rescue_executed = true
end
- it "repeatedly kills a fiber" do
- fiber = Fiber.new do
- while true; Fiber.yield; end
- ensure
- while true; Fiber.yield; end
- end
+ fiber.resume
+ fiber.kill
+ rescue_executed.should == false
+ end
- fiber.kill
- fiber.alive?.should == false
+ 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
diff --git a/spec/ruby/core/fiber/new_spec.rb b/spec/ruby/core/fiber/new_spec.rb
index b43c1386be..d31167496d 100644
--- a/spec/ruby/core/fiber/new_spec.rb
+++ b/spec/ruby/core/fiber/new_spec.rb
@@ -4,7 +4,7 @@ describe "Fiber.new" do
it "creates a fiber from the given block" do
fiber = Fiber.new {}
fiber.resume
- fiber.should be_an_instance_of(Fiber)
+ fiber.should.instance_of?(Fiber)
end
it "creates a fiber from a subclass" do
@@ -12,17 +12,17 @@ describe "Fiber.new" do
end
fiber = MyFiber.new {}
fiber.resume
- fiber.should be_an_instance_of(MyFiber)
+ fiber.should.instance_of?(MyFiber)
end
it "raises an ArgumentError if called without a block" do
- -> { Fiber.new }.should raise_error(ArgumentError)
+ -> { Fiber.new }.should.raise(ArgumentError)
end
it "does not invoke the block" do
invoked = false
fiber = Fiber.new { invoked = true }
- invoked.should be_false
+ invoked.should == false
fiber.resume
end
diff --git a/spec/ruby/core/fiber/raise_spec.rb b/spec/ruby/core/fiber/raise_spec.rb
index 896f760290..107e5bd4ce 100644
--- a/spec/ruby/core/fiber/raise_spec.rb
+++ b/spec/ruby/core/fiber/raise_spec.rb
@@ -3,57 +3,62 @@ require_relative 'fixtures/classes'
require_relative '../../shared/kernel/raise'
describe "Fiber#raise" do
+ it "is a public method" do
+ Fiber.public_instance_methods.should.include?(:raise)
+ end
+
it_behaves_like :kernel_raise, :raise, FiberSpecs::NewFiberToRaise
it_behaves_like :kernel_raise_across_contexts, :raise, FiberSpecs::NewFiberToRaise
-end
+ ruby_version_is "4.0" do
+ it_behaves_like :kernel_raise_with_cause, :raise, FiberSpecs::NewFiberToRaise
+ end
-describe "Fiber#raise" do
it 'raises RuntimeError by default' do
- -> { FiberSpecs::NewFiberToRaise.raise }.should raise_error(RuntimeError)
+ -> { FiberSpecs::NewFiberToRaise.raise }.should.raise(RuntimeError)
end
it "raises FiberError if Fiber is not born" do
fiber = Fiber.new { true }
- -> { fiber.raise }.should raise_error(FiberError, "cannot raise exception on unborn fiber")
+ -> { fiber.raise }.should.raise(FiberError, "cannot raise exception on unborn fiber")
end
it "raises FiberError if Fiber is dead" do
fiber = Fiber.new { true }
fiber.resume
- -> { fiber.raise }.should raise_error(FiberError, /dead fiber called|attempt to resume a terminated fiber/)
+ -> { fiber.raise }.should.raise(FiberError, /dead fiber called|attempt to resume a terminated fiber/)
end
it 'accepts error class' do
- -> { FiberSpecs::NewFiberToRaise.raise FiberSpecs::CustomError }.should raise_error(FiberSpecs::CustomError)
+ -> { FiberSpecs::NewFiberToRaise.raise FiberSpecs::CustomError }.should.raise(FiberSpecs::CustomError)
end
it 'accepts error message' do
- -> { FiberSpecs::NewFiberToRaise.raise "error message" }.should raise_error(RuntimeError, "error message")
+ -> { FiberSpecs::NewFiberToRaise.raise "error message" }.should.raise(RuntimeError, "error message")
end
it 'does not accept array of backtrace information only' do
- -> { FiberSpecs::NewFiberToRaise.raise ['foo'] }.should raise_error(TypeError)
+ -> { FiberSpecs::NewFiberToRaise.raise ['foo'] }.should.raise(TypeError)
end
it 'does not accept integer' do
- -> { FiberSpecs::NewFiberToRaise.raise 100 }.should raise_error(TypeError)
+ -> { FiberSpecs::NewFiberToRaise.raise 100 }.should.raise(TypeError)
end
it 'accepts error class with error message' do
- -> { FiberSpecs::NewFiberToRaise.raise FiberSpecs::CustomError, 'test error' }.should raise_error(FiberSpecs::CustomError, 'test error')
+ -> { FiberSpecs::NewFiberToRaise.raise FiberSpecs::CustomError, 'test error' }.should.raise(FiberSpecs::CustomError, 'test error')
end
it 'accepts error class with error message and backtrace information' do
-> {
FiberSpecs::NewFiberToRaise.raise FiberSpecs::CustomError, 'test error', ['foo', 'boo']
- }.should raise_error(FiberSpecs::CustomError) { |e|
+ }.should.raise(FiberSpecs::CustomError) { |e|
e.message.should == 'test error'
e.backtrace.should == ['foo', 'boo']
}
end
it 'does not accept only error message and backtrace information' do
- -> { FiberSpecs::NewFiberToRaise.raise 'test error', ['foo', 'boo'] }.should raise_error(TypeError)
+ -> { FiberSpecs::NewFiberToRaise.raise 'test error', ['foo', 'boo'] }.should.raise(TypeError)
end
it "raises a FiberError if invoked from a different Thread" do
@@ -62,15 +67,15 @@ describe "Fiber#raise" do
Thread.new do
-> {
fiber.raise
- }.should raise_error(FiberError, "fiber called across threads")
+ }.should.raise(FiberError, "fiber called across threads")
end.join
end
it "kills Fiber" do
fiber = Fiber.new { Fiber.yield :first; :second }
fiber.resume
- -> { fiber.raise }.should raise_error
- -> { fiber.resume }.should raise_error(FiberError, /dead fiber called|attempt to resume a terminated fiber/)
+ -> { fiber.raise }.should.raise
+ -> { fiber.resume }.should.raise(FiberError, /dead fiber called|attempt to resume a terminated fiber/)
end
it "returns to calling fiber after raise" do
@@ -102,13 +107,13 @@ describe "Fiber#raise" do
-> do
f2.raise(RuntimeError, "Expected error")
- end.should raise_error(RuntimeError, "Expected error")
+ end.should.raise(RuntimeError, "Expected error")
end
it "raises on itself" do
-> do
Fiber.current.raise(RuntimeError, "Expected error")
- end.should raise_error(RuntimeError, "Expected error")
+ end.should.raise(RuntimeError, "Expected error")
end
it "should raise on parent fiber" do
@@ -123,17 +128,14 @@ describe "Fiber#raise" do
-> do
f2.resume
- end.should raise_error(RuntimeError, "Expected error")
+ end.should.raise(RuntimeError, "Expected error")
end
end
-end
-
-describe "Fiber#raise" do
it "transfers and raises on a transferring fiber" do
root = Fiber.current
fiber = Fiber.new { root.transfer }
fiber.transfer
- -> { fiber.raise "msg" }.should raise_error(RuntimeError, "msg")
+ -> { fiber.raise "msg" }.should.raise(RuntimeError, "msg")
end
end
diff --git a/spec/ruby/core/fiber/resume_spec.rb b/spec/ruby/core/fiber/resume_spec.rb
index 4b20f4b4bf..e183cc10d9 100644
--- a/spec/ruby/core/fiber/resume_spec.rb
+++ b/spec/ruby/core/fiber/resume_spec.rb
@@ -30,7 +30,7 @@ describe "Fiber#resume" 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/)
+ -> { fiber.resume }.should.raise(FiberError, /current fiber/)
end
it "returns control to the calling Fiber if called from one" do
@@ -78,6 +78,6 @@ describe "Fiber#resume" do
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/)
+ -> { fiber1.resume }.should.raise(FiberError, /attempt to resume a resuming fiber/)
end
end
diff --git a/spec/ruby/core/fiber/scheduler_spec.rb b/spec/ruby/core/fiber/scheduler_spec.rb
new file mode 100644
index 0000000000..2a517ba93b
--- /dev/null
+++ b/spec/ruby/core/fiber/scheduler_spec.rb
@@ -0,0 +1,5 @@
+require_relative '../../spec_helper'
+
+describe "Fiber.scheduler" do
+ it "is already tested in Fiber.set_scheduler"
+end
diff --git a/spec/ruby/core/fiber/set_scheduler_spec.rb b/spec/ruby/core/fiber/set_scheduler_spec.rb
new file mode 100644
index 0000000000..b34aff8734
--- /dev/null
+++ b/spec/ruby/core/fiber/set_scheduler_spec.rb
@@ -0,0 +1,55 @@
+require_relative '../../spec_helper'
+
+require "fiber"
+
+describe "Fiber.scheduler" do
+ it "validates the scheduler for required methods" do
+ required_methods = [:block, :unblock, :kernel_sleep, :io_wait]
+ required_methods.each do |missing_method|
+ scheduler = Object.new
+ required_methods.difference([missing_method]).each do |method|
+ scheduler.define_singleton_method(method) {}
+ end
+ -> {
+ suppress_warning { Fiber.set_scheduler(scheduler) }
+ }.should.raise(ArgumentError, /Scheduler must implement ##{missing_method}/)
+ end
+ end
+
+ it "can set and get the scheduler" do
+ required_methods = [:block, :unblock, :kernel_sleep, :io_wait]
+ scheduler = Object.new
+ required_methods.each do |method|
+ scheduler.define_singleton_method(method) {}
+ end
+ suppress_warning { Fiber.set_scheduler(scheduler) }
+ Fiber.scheduler.should == scheduler
+ end
+
+ it "returns the scheduler after setting it" do
+ required_methods = [:block, :unblock, :kernel_sleep, :io_wait]
+ scheduler = Object.new
+ required_methods.each do |method|
+ scheduler.define_singleton_method(method) {}
+ end
+ result = suppress_warning { Fiber.set_scheduler(scheduler) }
+ result.should == scheduler
+ end
+
+ it "can remove the scheduler" do
+ required_methods = [:block, :unblock, :kernel_sleep, :io_wait]
+ scheduler = Object.new
+ required_methods.each do |method|
+ scheduler.define_singleton_method(method) {}
+ end
+ suppress_warning { Fiber.set_scheduler(scheduler) }
+ Fiber.set_scheduler(nil)
+ Fiber.scheduler.should == nil
+ end
+
+ it "can assign a nil scheduler multiple times" do
+ Fiber.set_scheduler(nil)
+ Fiber.set_scheduler(nil)
+ Fiber.scheduler.should == nil
+ end
+end
diff --git a/spec/ruby/core/fiber/shared/resume.rb b/spec/ruby/core/fiber/shared/resume.rb
index 5ee27d1d24..ff4bb72c73 100644
--- a/spec/ruby/core/fiber/shared/resume.rb
+++ b/spec/ruby/core/fiber/shared/resume.rb
@@ -9,7 +9,7 @@ describe :fiber_resume, shared: true do
Thread.new do
-> {
fiber.send(@method)
- }.should raise_error(FiberError)
+ }.should.raise(FiberError)
end.join
# Check the Fiber can still be used
@@ -20,12 +20,12 @@ describe :fiber_resume, shared: true do
invoked = false
fiber = Fiber.new { invoked = true }
fiber.send(@method)
- invoked.should be_true
+ invoked.should == true
end
it "returns the last value encountered on first invocation" do
fiber = Fiber.new { 1+1; true }
- fiber.send(@method).should be_true
+ fiber.send(@method).should == true
end
it "runs until the end of the block" do
@@ -37,22 +37,22 @@ describe :fiber_resume, shared: true do
it "accepts any number of arguments" do
fiber = Fiber.new { |a| }
- -> { fiber.send(@method, *(1..10).to_a) }.should_not raise_error
+ -> { fiber.send(@method, *(1..10).to_a) }.should_not.raise
end
it "raises a FiberError if the Fiber is dead" do
fiber = Fiber.new { true }
fiber.send(@method)
- -> { fiber.send(@method) }.should raise_error(FiberError)
+ -> { fiber.send(@method) }.should.raise(FiberError)
end
it "raises a LocalJumpError if the block includes a return statement" do
fiber = Fiber.new { return; }
- -> { fiber.send(@method) }.should raise_error(LocalJumpError)
+ -> { fiber.send(@method) }.should.raise(LocalJumpError)
end
it "raises a LocalJumpError if the block includes a break statement" do
fiber = Fiber.new { break; }
- -> { fiber.send(@method) }.should raise_error(LocalJumpError)
+ -> { fiber.send(@method) }.should.raise(LocalJumpError)
end
end
diff --git a/spec/ruby/core/fiber/storage_spec.rb b/spec/ruby/core/fiber/storage_spec.rb
index 015caaf3bb..a3f6bf9cad 100644
--- a/spec/ruby/core/fiber/storage_spec.rb
+++ b/spec/ruby/core/fiber/storage_spec.rb
@@ -19,15 +19,15 @@ describe "Fiber.new(storage:)" do
end
it "cannot create a fiber with non-hash storage" do
- -> { Fiber.new(storage: 42) {} }.should raise_error(TypeError)
+ -> { Fiber.new(storage: 42) {} }.should.raise(TypeError)
end
it "cannot create a fiber with a frozen hash as storage" do
- -> { Fiber.new(storage: {life: 43}.freeze) {} }.should raise_error(FrozenError)
+ -> { Fiber.new(storage: {life: 43}.freeze) {} }.should.raise(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)
+ -> { Fiber.new(storage: {life: 43, Object.new => 44}) {} }.should.raise(TypeError)
end
end
@@ -36,7 +36,7 @@ describe "Fiber#storage" 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/)
+ }.should.raise(ArgumentError, /Fiber storage can only be accessed from the Fiber it belongs to/)
end
end
@@ -59,15 +59,15 @@ describe "Fiber#storage=" do
end
it "can't set the storage of the fiber to non-hash" do
- -> { Fiber.current.storage = 42 }.should raise_error(TypeError)
+ -> { Fiber.current.storage = 42 }.should.raise(TypeError)
end
it "can't set the storage of the fiber to a frozen hash" do
- -> { Fiber.current.storage = {life: 43}.freeze }.should raise_error(FrozenError)
+ -> { Fiber.current.storage = {life: 43}.freeze }.should.raise(FrozenError)
end
it "can't set the storage of the fiber to a hash with non-symbol keys" do
- -> { Fiber.current.storage = {life: 43, Object.new => 44} }.should raise_error(TypeError)
+ -> { Fiber.current.storage = {life: 43, Object.new => 44} }.should.raise(TypeError)
end
end
@@ -77,24 +77,22 @@ describe "Fiber.[]" do
end
it "returns nil if the key is not present in the storage of the current fiber" do
- Fiber.new(storage: {life: 42}) { Fiber[:death] }.resume.should be_nil
+ Fiber.new(storage: {life: 42}) { Fiber[:death] }.resume.should == nil
end
it "returns nil if the current fiber has no storage" do
- Fiber.new { Fiber[:life] }.resume.should be_nil
+ Fiber.new { Fiber[:life] }.resume.should == nil
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 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, 12]
- invalid_keys.each do |key|
- -> { Fiber[key] }.should raise_error(TypeError)
- end
+ it "can't use invalid keys" do
+ invalid_keys = [Object.new, 12]
+ invalid_keys.each do |key|
+ -> { Fiber[key] }.should.raise(TypeError)
end
end
@@ -120,7 +118,7 @@ describe "Fiber.[]" do
it "does not call #to_sym on the key" do
key = mock("key")
key.should_not_receive(:to_sym)
- -> { Fiber[key] }.should raise_error(TypeError)
+ -> { Fiber[key] }.should.raise(TypeError)
end
it "can access the storage of the parent fiber" do
@@ -131,7 +129,7 @@ describe "Fiber.[]" do
end
it "can't access the storage of the fiber with non-symbol keys" do
- -> { Fiber[Object.new] }.should raise_error(TypeError)
+ -> { Fiber[Object.new] }.should.raise(TypeError)
end
end
@@ -158,16 +156,14 @@ describe "Fiber.[]=" do
end
it "can't access the storage of the fiber with non-symbol keys" do
- -> { Fiber[Object.new] = 44 }.should raise_error(TypeError)
+ -> { Fiber[Object.new] = 44 }.should.raise(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
+ 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
diff --git a/spec/ruby/core/fiber/transfer_spec.rb b/spec/ruby/core/fiber/transfer_spec.rb
index 238721475d..d8737aeeb3 100644
--- a/spec/ruby/core/fiber/transfer_spec.rb
+++ b/spec/ruby/core/fiber/transfer_spec.rb
@@ -37,12 +37,12 @@ describe "Fiber#transfer" do
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)
+ -> { fiber2.transfer }.should.raise(FiberError)
end
it "raises a FiberError when transferring to a Fiber which resumes itself" do
fiber = Fiber.new { fiber.resume }
- -> { fiber.transfer }.should raise_error(FiberError)
+ -> { fiber.transfer }.should.raise(FiberError)
end
it "works if Fibers in different Threads each transfer to a Fiber in the same Thread" do
@@ -58,7 +58,7 @@ describe "Fiber#transfer" do
end
io_fiber.transfer(Fiber.current)
value = Object.new
- io_fiber.transfer(value).should equal value
+ io_fiber.transfer(value).should.equal? value
end.join
end
end
diff --git a/spec/ruby/core/fiber/yield_spec.rb b/spec/ruby/core/fiber/yield_spec.rb
index b010912c87..12ec6ebcef 100644
--- a/spec/ruby/core/fiber/yield_spec.rb
+++ b/spec/ruby/core/fiber/yield_spec.rb
@@ -18,7 +18,7 @@ describe "Fiber.yield" do
it "returns nil to the caller if given no arguments" do
fiber = Fiber.new { true; Fiber.yield; true }
- fiber.resume.should be_nil
+ fiber.resume.should == nil
fiber.resume
end
@@ -44,6 +44,6 @@ describe "Fiber.yield" do
end
it "raises a FiberError if called from the root Fiber" do
- ->{ Fiber.yield }.should raise_error(FiberError)
+ ->{ Fiber.yield }.should.raise(FiberError)
end
end
diff --git a/spec/ruby/core/file/absolute_path_spec.rb b/spec/ruby/core/file/absolute_path_spec.rb
index 315eead34f..fc12985a75 100644
--- a/spec/ruby/core/file/absolute_path_spec.rb
+++ b/spec/ruby/core/file/absolute_path_spec.rb
@@ -6,47 +6,47 @@ describe "File.absolute_path?" do
end
it "returns true if it's an absolute pathname" do
- File.absolute_path?(@abs).should be_true
+ File.absolute_path?(@abs).should == true
end
it "returns false if it's a relative path" do
- File.absolute_path?(File.basename(__FILE__)).should be_false
+ File.absolute_path?(File.basename(__FILE__)).should == false
end
it "returns false if it's a tricky relative path" do
- File.absolute_path?("C:foo\\bar").should be_false
+ File.absolute_path?("C:foo\\bar").should == false
end
it "does not expand '~' to a home directory." do
- File.absolute_path?('~').should be_false
+ File.absolute_path?('~').should == false
end
it "does not expand '~user' to a home directory." do
path = File.dirname(@abs)
Dir.chdir(path) do
- File.absolute_path?('~user').should be_false
+ File.absolute_path?('~user').should == false
end
end
it "calls #to_path on its argument" do
mock = mock_to_path(File.expand_path(__FILE__))
- File.absolute_path?(mock).should be_true
+ File.absolute_path?(mock).should == true
end
platform_is_not :windows do
it "takes into consideration the platform's root" do
- File.absolute_path?("C:\\foo\\bar").should be_false
- File.absolute_path?("C:/foo/bar").should be_false
- File.absolute_path?("/foo/bar\\baz").should be_true
+ File.absolute_path?("C:\\foo\\bar").should == false
+ File.absolute_path?("C:/foo/bar").should == false
+ File.absolute_path?("/foo/bar\\baz").should == true
end
end
platform_is :windows do
it "takes into consideration the platform path separator(s)" do
- File.absolute_path?("C:\\foo\\bar").should be_true
- File.absolute_path?("C:/foo/bar").should be_true
- File.absolute_path?("/foo/bar\\baz").should be_false
+ File.absolute_path?("C:\\foo\\bar").should == true
+ File.absolute_path?("C:/foo/bar").should == true
+ File.absolute_path?("/foo/bar\\baz").should == false
end
end
end
diff --git a/spec/ruby/core/file/atime_spec.rb b/spec/ruby/core/file/atime_spec.rb
index e47e70e5ac..5c6c110eec 100644
--- a/spec/ruby/core/file/atime_spec.rb
+++ b/spec/ruby/core/file/atime_spec.rb
@@ -12,7 +12,7 @@ describe "File.atime" do
it "returns the last access time for the named file as a Time object" do
File.atime(@file)
- File.atime(@file).should be_kind_of(Time)
+ File.atime(@file).should.is_a?(Time)
end
platform_is :linux, :windows do
@@ -35,7 +35,7 @@ describe "File.atime" do
end
it "raises an Errno::ENOENT exception if the file is not found" do
- -> { File.atime('a_fake_file') }.should raise_error(Errno::ENOENT)
+ -> { File.atime('a_fake_file') }.should.raise(Errno::ENOENT)
end
it "accepts an object that has a #to_path method" do
@@ -55,6 +55,6 @@ describe "File#atime" do
it "returns the last access time to self" do
@file.atime
- @file.atime.should be_kind_of(Time)
+ @file.atime.should.is_a?(Time)
end
end
diff --git a/spec/ruby/core/file/basename_spec.rb b/spec/ruby/core/file/basename_spec.rb
index 989409d76b..77afe5c22f 100644
--- a/spec/ruby/core/file/basename_spec.rb
+++ b/spec/ruby/core/file/basename_spec.rb
@@ -42,7 +42,7 @@ describe "File.basename" do
end
it "returns an string" do
- File.basename("foo").should be_kind_of(String)
+ File.basename("foo").should.is_a?(String)
end
it "returns the basename for unix format" do
@@ -105,10 +105,10 @@ describe "File.basename" do
end
it "raises a TypeError if the arguments are not String types" do
- -> { File.basename(nil) }.should raise_error(TypeError)
- -> { File.basename(1) }.should raise_error(TypeError)
- -> { File.basename("bar.txt", 1) }.should raise_error(TypeError)
- -> { File.basename(true) }.should raise_error(TypeError)
+ -> { File.basename(nil) }.should.raise(TypeError)
+ -> { File.basename(1) }.should.raise(TypeError)
+ -> { File.basename("bar.txt", 1) }.should.raise(TypeError)
+ -> { File.basename(true) }.should.raise(TypeError)
end
it "accepts an object that has a #to_path method" do
@@ -116,7 +116,7 @@ describe "File.basename" do
end
it "raises an ArgumentError if passed more than two arguments" do
- -> { File.basename('bar.txt', '.txt', '.txt') }.should raise_error(ArgumentError)
+ -> { File.basename('bar.txt', '.txt', '.txt') }.should.raise(ArgumentError)
end
# specific to MS Windows
@@ -151,8 +151,30 @@ describe "File.basename" do
File.basename("c:\\bar.txt", ".*").should == "bar"
File.basename("c:\\bar.txt.exe", ".*").should == "bar.txt"
end
+
+ it "handles Shift JIS 0x5C (\\) as second byte of a multi-byte sequence" do
+ # dir\fileソname.txt
+ path = "dir\\file\x83\x5cname.txt".b.force_encoding(Encoding::SHIFT_JIS)
+ path.valid_encoding?.should == true
+ File.basename(path).should == "file\x83\x5cname.txt".b.force_encoding(Encoding::SHIFT_JIS)
+ end
+ end
+
+ it "rejects strings encoded with non ASCII-compatible encodings" do
+ Encoding.list.reject(&:ascii_compatible?).reject(&:dummy?).each do |enc|
+ path = "/foo/bar".encode(enc)
+
+ -> {
+ File.basename(path)
+ }.should.raise(Encoding::CompatibilityError)
+ end
end
+ it "works with all ASCII-compatible encodings" do
+ Encoding.list.select(&:ascii_compatible?).each do |enc|
+ File.basename("/foo/bar".encode(enc)).should == "bar".encode(enc)
+ end
+ end
it "returns the extension for a multibyte filename" do
File.basename('/path/ОфиÑ.m4a').should == "ОфиÑ.m4a"
@@ -174,7 +196,7 @@ describe "File.basename" do
else
File.basename(original)
end
- result.should_not equal(original)
+ result.should_not.equal?(original)
result.frozen?.should == false
end
end
diff --git a/spec/ruby/core/file/birthtime_spec.rb b/spec/ruby/core/file/birthtime_spec.rb
index f82eaf7cca..039fd7572c 100644
--- a/spec/ruby/core/file/birthtime_spec.rb
+++ b/spec/ruby/core/file/birthtime_spec.rb
@@ -17,7 +17,7 @@ platform_is :windows, :darwin, :freebsd, :netbsd, :linux do
it "returns the birth time for the named file as a Time object" do
File.birthtime(@file)
- File.birthtime(@file).should be_kind_of(Time)
+ File.birthtime(@file).should.is_a?(Time)
rescue NotImplementedError => e
e.message.should.start_with?(*not_implemented_messages)
end
@@ -30,7 +30,7 @@ platform_is :windows, :darwin, :freebsd, :netbsd, :linux do
end
it "raises an Errno::ENOENT exception if the file is not found" do
- -> { File.birthtime('bogus') }.should raise_error(Errno::ENOENT)
+ -> { File.birthtime('bogus') }.should.raise(Errno::ENOENT)
rescue NotImplementedError => e
e.message.should.start_with?(*not_implemented_messages)
end
@@ -48,7 +48,7 @@ platform_is :windows, :darwin, :freebsd, :netbsd, :linux do
it "returns the birth time for self" do
@file.birthtime
- @file.birthtime.should be_kind_of(Time)
+ @file.birthtime.should.is_a?(Time)
rescue NotImplementedError => e
e.message.should.start_with?(*not_implemented_messages)
end
diff --git a/spec/ruby/core/file/chmod_spec.rb b/spec/ruby/core/file/chmod_spec.rb
index 5ca15c9748..e0fd10ceb1 100644
--- a/spec/ruby/core/file/chmod_spec.rb
+++ b/spec/ruby/core/file/chmod_spec.rb
@@ -16,8 +16,8 @@ describe "File#chmod" do
end
it "raises RangeError with too large values" do
- -> { @file.chmod(2**64) }.should raise_error(RangeError)
- -> { @file.chmod(-2**63 - 1) }.should raise_error(RangeError)
+ -> { @file.chmod(2**64) }.should.raise(RangeError)
+ -> { @file.chmod(-2**63 - 1) }.should.raise(RangeError)
end
it "invokes to_int on non-integer argument" do
@@ -97,8 +97,8 @@ describe "File.chmod" do
end
it "raises RangeError with too large values" do
- -> { File.chmod(2**64, @file) }.should raise_error(RangeError)
- -> { File.chmod(-2**63 - 1, @file) }.should raise_error(RangeError)
+ -> { File.chmod(2**64, @file) }.should.raise(RangeError)
+ -> { File.chmod(-2**63 - 1, @file) }.should.raise(RangeError)
end
it "accepts an object that has a #to_path method" do
@@ -106,13 +106,13 @@ describe "File.chmod" do
end
it "throws a TypeError if the given path is not coercible into a string" do
- -> { File.chmod(0, []) }.should raise_error(TypeError)
+ -> { File.chmod(0, []) }.should.raise(TypeError)
end
it "raises an error for a non existent path" do
-> {
File.chmod(0644, "#{@file}.not.existing")
- }.should raise_error(Errno::ENOENT)
+ }.should.raise(Errno::ENOENT)
end
it "invokes to_int on non-integer argument" do
diff --git a/spec/ruby/core/file/chown_spec.rb b/spec/ruby/core/file/chown_spec.rb
index 4db0e3712c..3353aafc70 100644
--- a/spec/ruby/core/file/chown_spec.rb
+++ b/spec/ruby/core/file/chown_spec.rb
@@ -68,7 +68,7 @@ describe "File.chown" do
it "raises an error for a non existent path" do
-> {
File.chown(nil, nil, "#{@fname}_not_existing")
- }.should raise_error(Errno::ENOENT)
+ }.should.raise(Errno::ENOENT)
end
end
diff --git a/spec/ruby/core/file/constants/constants_spec.rb b/spec/ruby/core/file/constants/constants_spec.rb
index bba248c21e..9d9c1c3b25 100644
--- a/spec/ruby/core/file/constants/constants_spec.rb
+++ b/spec/ruby/core/file/constants/constants_spec.rb
@@ -7,7 +7,7 @@ require_relative '../../../spec_helper'
"RDWR", "TRUNC", "WRONLY", "SHARE_DELETE"].each do |const|
describe "File::Constants::#{const}" do
it "is defined" do
- File::Constants.const_defined?(const).should be_true
+ File::Constants.const_defined?(const).should == true
end
end
end
@@ -15,7 +15,7 @@ end
platform_is :windows do
describe "File::Constants::BINARY" do
it "is defined" do
- File::Constants.const_defined?(:BINARY).should be_true
+ File::Constants.const_defined?(:BINARY).should == true
end
end
end
@@ -24,7 +24,7 @@ platform_is_not :windows do
["NOCTTY", "SYNC"].each do |const|
describe "File::Constants::#{const}" do
it "is defined" do
- File::Constants.const_defined?(const).should be_true
+ File::Constants.const_defined?(const).should == true
end
end
end
diff --git a/spec/ruby/core/file/ctime_spec.rb b/spec/ruby/core/file/ctime_spec.rb
index 718f26d5cc..cf37d1f4ee 100644
--- a/spec/ruby/core/file/ctime_spec.rb
+++ b/spec/ruby/core/file/ctime_spec.rb
@@ -11,7 +11,7 @@ describe "File.ctime" 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)." do
File.ctime(@file)
- File.ctime(@file).should be_kind_of(Time)
+ File.ctime(@file).should.is_a?(Time)
end
platform_is :linux, :windows do
@@ -33,7 +33,7 @@ describe "File.ctime" do
end
it "raises an Errno::ENOENT exception if the file is not found" do
- -> { File.ctime('bogus') }.should raise_error(Errno::ENOENT)
+ -> { File.ctime('bogus') }.should.raise(Errno::ENOENT)
end
end
@@ -49,6 +49,6 @@ describe "File#ctime" 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)." do
@file.ctime
- @file.ctime.should be_kind_of(Time)
+ @file.ctime.should.is_a?(Time)
end
end
diff --git a/spec/ruby/core/file/delete_spec.rb b/spec/ruby/core/file/delete_spec.rb
index 4098499942..7149b8a37d 100644
--- a/spec/ruby/core/file/delete_spec.rb
+++ b/spec/ruby/core/file/delete_spec.rb
@@ -1,6 +1,63 @@
require_relative '../../spec_helper'
-require_relative 'shared/unlink'
describe "File.delete" do
- it_behaves_like :file_unlink, :delete
+ before :each do
+ @file1 = tmp('test.txt')
+ @file2 = tmp('test2.txt')
+
+ touch @file1
+ touch @file2
+ end
+
+ after :each do
+ File.delete(@file1) if File.exist?(@file1)
+ File.delete(@file2) if File.exist?(@file2)
+
+ @file1 = nil
+ @file2 = nil
+ end
+
+ it "returns 0 when called without arguments" do
+ File.delete.should == 0
+ end
+
+ it "deletes a single file" do
+ File.delete(@file1).should == 1
+ File.should_not.exist?(@file1)
+ end
+
+ it "deletes multiple files" do
+ File.delete(@file1, @file2).should == 2
+ File.should_not.exist?(@file1)
+ File.should_not.exist?(@file2)
+ end
+
+ it "raises a TypeError if not passed a String type" do
+ -> { File.delete(1) }.should.raise(TypeError)
+ end
+
+ it "raises an Errno::ENOENT when the given file doesn't exist" do
+ -> { File.delete('bogus') }.should.raise(Errno::ENOENT)
+ end
+
+ it "coerces a given parameter into a string if possible" do
+ mock = mock("to_str")
+ mock.should_receive(:to_str).and_return(@file1)
+ File.delete(mock).should == 1
+ end
+
+ it "accepts an object that has a #to_path method" do
+ File.delete(mock_to_path(@file1)).should == 1
+ end
+
+ platform_is :windows do
+ it "allows deleting an open file with File::SHARE_DELETE" do
+ path = tmp("share_delete.txt")
+ File.open(path, mode: File::CREAT | File::WRONLY | File::BINARY | File::SHARE_DELETE) do |f|
+ File.should.exist?(path)
+ File.delete(path)
+ end
+ File.should_not.exist?(path)
+ end
+ end
end
diff --git a/spec/ruby/core/file/dirname_spec.rb b/spec/ruby/core/file/dirname_spec.rb
index 8e6016ce6f..855148a684 100644
--- a/spec/ruby/core/file/dirname_spec.rb
+++ b/spec/ruby/core/file/dirname_spec.rb
@@ -25,7 +25,7 @@ describe "File.dirname" do
it "raises ArgumentError if the level is negative" do
-> {
File.dirname('/home/jason', -1)
- }.should raise_error(ArgumentError, "negative level: -1")
+ }.should.raise(ArgumentError, "negative level: -1")
end
it "returns '/' when level exceeds the number of segments in the path" do
@@ -41,7 +41,7 @@ describe "File.dirname" do
end
it "returns a String" do
- File.dirname("foo").should be_kind_of(String)
+ File.dirname("foo").should.is_a?(String)
end
it "does not modify its argument" do
@@ -78,7 +78,33 @@ describe "File.dirname" do
File.dirname("foo/../").should == "foo"
end
+ it "rejects strings encoded with non ASCII-compatible encodings" do
+ Encoding.list.reject(&:ascii_compatible?).reject(&:dummy?).each do |enc|
+ path = "/foo/bar".encode(enc)
+ -> {
+ File.dirname(path)
+ }.should.raise(Encoding::CompatibilityError)
+ end
+ end
+
+ it "works with all ASCII-compatible encodings" do
+ Encoding.list.select(&:ascii_compatible?).each do |enc|
+ File.dirname("/foo/bar".encode(enc)).should == "/foo".encode(enc)
+ end
+ end
+
+ it "handles Shift JIS 0x5C (\\) as second byte of a multi-byte sequence" do
+ # dir/fileソname.txt
+ path = "dir/file\x83\x5cname.txt".b.force_encoding(Encoding::SHIFT_JIS)
+ path.valid_encoding?.should == true
+ File.dirname(path).should == "dir"
+ end
+
platform_is_not :windows do
+ it "ignores repeated leading / (edge cases on non-windows)" do
+ File.dirname("/////foo/bar/").should == "/foo"
+ end
+
it "returns all the components of filename except the last one (edge cases on non-windows)" do
File.dirname('/////').should == '/'
File.dirname("//foo//").should == "/"
@@ -94,6 +120,13 @@ describe "File.dirname" do
File.dirname("//foo//").should == "//foo"
File.dirname('/////').should == '//'
end
+
+ it "handles Shift JIS 0x5C (\\) as second byte of a multi-byte sequence (windows)" do
+ # dir\fileソname.txt
+ path = "dir\\file\x83\x5cname.txt".b.force_encoding(Encoding::SHIFT_JIS)
+ path.valid_encoding?.should == true
+ File.dirname(path).should == "dir"
+ end
end
it "accepts an object that has a #to_path method" do
@@ -101,10 +134,10 @@ describe "File.dirname" do
end
it "raises a TypeError if not passed a String type" do
- -> { File.dirname(nil) }.should raise_error(TypeError)
- -> { File.dirname(0) }.should raise_error(TypeError)
- -> { File.dirname(true) }.should raise_error(TypeError)
- -> { File.dirname(false) }.should raise_error(TypeError)
+ -> { File.dirname(nil) }.should.raise(TypeError)
+ -> { File.dirname(0) }.should.raise(TypeError)
+ -> { File.dirname(true) }.should.raise(TypeError)
+ -> { File.dirname(false) }.should.raise(TypeError)
end
# Windows specific tests
diff --git a/spec/ruby/core/file/expand_path_spec.rb b/spec/ruby/core/file/expand_path_spec.rb
index 1abcf93900..160494f145 100644
--- a/spec/ruby/core/file/expand_path_spec.rb
+++ b/spec/ruby/core/file/expand_path_spec.rb
@@ -92,7 +92,7 @@ describe "File.expand_path" do
end
it "raises an ArgumentError if the path is not valid" do
- -> { File.expand_path("~a_not_existing_user") }.should raise_error(ArgumentError)
+ -> { File.expand_path("~a_not_existing_user") }.should.raise(ArgumentError)
end
it "expands ~ENV['USER'] to the user's home directory" do
@@ -117,9 +117,9 @@ describe "File.expand_path" do
end
it "raises a TypeError if not passed a String type" do
- -> { File.expand_path(1) }.should raise_error(TypeError)
- -> { File.expand_path(nil) }.should raise_error(TypeError)
- -> { File.expand_path(true) }.should raise_error(TypeError)
+ -> { File.expand_path(1) }.should.raise(TypeError)
+ -> { File.expand_path(nil) }.should.raise(TypeError)
+ -> { File.expand_path(true) }.should.raise(TypeError)
end
platform_is_not :windows do
@@ -138,10 +138,10 @@ describe "File.expand_path" do
Encoding.default_external = Encoding::SHIFT_JIS
path = "./a".dup.force_encoding Encoding::CP1251
- File.expand_path(path).encoding.should equal(Encoding::CP1251)
+ File.expand_path(path).encoding.should.equal?(Encoding::CP1251)
weird_path = [222, 173, 190, 175].pack('C*')
- File.expand_path(weird_path).encoding.should equal(Encoding::BINARY)
+ File.expand_path(weird_path).encoding.should.equal?(Encoding::BINARY)
end
platform_is_not :windows do
@@ -159,7 +159,7 @@ describe "File.expand_path" do
platform_is_not :windows do
it "raises an Encoding::CompatibilityError if the external encoding is not compatible" do
Encoding.default_external = Encoding::UTF_16BE
- -> { File.expand_path("./a") }.should raise_error(Encoding::CompatibilityError)
+ -> { File.expand_path("./a") }.should.raise(Encoding::CompatibilityError)
end
end
@@ -179,7 +179,7 @@ describe "File.expand_path" do
str = FileSpecs::SubString.new "./a/b/../c"
path = File.expand_path(str, @base)
path.should == "#{@base}/a/c"
- path.should be_an_instance_of(String)
+ path.should.instance_of?(String)
end
end
@@ -244,7 +244,7 @@ platform_is_not :windows do
it "raises an ArgumentError when passed '~' if HOME == ''" do
ENV["HOME"] = ""
- -> { File.expand_path("~") }.should raise_error(ArgumentError)
+ -> { File.expand_path("~") }.should.raise(ArgumentError)
end
end
@@ -259,7 +259,7 @@ platform_is_not :windows do
it "raises an ArgumentError" do
ENV["HOME"] = "non-absolute"
- -> { File.expand_path("~") }.should raise_error(ArgumentError, 'non-absolute home')
+ -> { File.expand_path("~") }.should.raise(ArgumentError, 'non-absolute home')
end
end
end
diff --git a/spec/ruby/core/file/extname_spec.rb b/spec/ruby/core/file/extname_spec.rb
index d20cf813d9..995d0ea31a 100644
--- a/spec/ruby/core/file/extname_spec.rb
+++ b/spec/ruby/core/file/extname_spec.rb
@@ -57,15 +57,15 @@ describe "File.extname" do
end
it "raises a TypeError if not passed a String type" do
- -> { File.extname(nil) }.should raise_error(TypeError)
- -> { File.extname(0) }.should raise_error(TypeError)
- -> { File.extname(true) }.should raise_error(TypeError)
- -> { File.extname(false) }.should raise_error(TypeError)
+ -> { File.extname(nil) }.should.raise(TypeError)
+ -> { File.extname(0) }.should.raise(TypeError)
+ -> { File.extname(true) }.should.raise(TypeError)
+ -> { File.extname(false) }.should.raise(TypeError)
end
it "raises an ArgumentError if not passed one argument" do
- -> { File.extname }.should raise_error(ArgumentError)
- -> { File.extname("foo.bar", "foo.baz") }.should raise_error(ArgumentError)
+ -> { File.extname }.should.raise(ArgumentError)
+ -> { File.extname("foo.bar", "foo.baz") }.should.raise(ArgumentError)
end
diff --git a/spec/ruby/core/file/fnmatch_spec.rb b/spec/ruby/core/file/fnmatch_spec.rb
index a1b7fa12b3..44a143bddc 100644
--- a/spec/ruby/core/file/fnmatch_spec.rb
+++ b/spec/ruby/core/file/fnmatch_spec.rb
@@ -1,10 +1,302 @@
require_relative '../../spec_helper'
-require_relative 'shared/fnmatch'
describe "File.fnmatch" do
- it_behaves_like :file_fnmatch, :fnmatch
+ it "matches entire strings" do
+ File.fnmatch('cat', 'cat').should == true
+ end
+
+ it "does not match partial strings" do
+ File.fnmatch('cat', 'category').should == false
+ end
+
+ it "does not support { } patterns by default" do
+ File.fnmatch('c{at,ub}s', 'cats').should == false
+ File.fnmatch('c{at,ub}s', 'c{at,ub}s').should == true
+ end
+
+ it "supports some { } patterns when File::FNM_EXTGLOB is passed" do
+ File.fnmatch("{a,b}", "a", File::FNM_EXTGLOB).should == true
+ File.fnmatch("{a,b}", "b", File::FNM_EXTGLOB).should == true
+ File.fnmatch("c{at,ub}s", "cats", File::FNM_EXTGLOB).should == true
+ File.fnmatch("c{at,ub}s", "cubs", File::FNM_EXTGLOB).should == true
+ File.fnmatch("-c{at,ub}s-", "-cats-", File::FNM_EXTGLOB).should == true
+ File.fnmatch("-c{at,ub}s-", "-cubs-", File::FNM_EXTGLOB).should == true
+ File.fnmatch("{a,b,c}{d,e,f}{g,h}", "adg", File::FNM_EXTGLOB).should == true
+ File.fnmatch("{a,b,c}{d,e,f}{g,h}", "bdg", File::FNM_EXTGLOB).should == true
+ File.fnmatch("{a,b,c}{d,e,f}{g,h}", "ceh", File::FNM_EXTGLOB).should == true
+ File.fnmatch("{aa,bb,cc,dd}", "aa", File::FNM_EXTGLOB).should == true
+ File.fnmatch("{aa,bb,cc,dd}", "bb", File::FNM_EXTGLOB).should == true
+ File.fnmatch("{aa,bb,cc,dd}", "cc", File::FNM_EXTGLOB).should == true
+ File.fnmatch("{aa,bb,cc,dd}", "dd", File::FNM_EXTGLOB).should == true
+ File.fnmatch("{1,5{a,b{c,d}}}", "1", File::FNM_EXTGLOB).should == true
+ File.fnmatch("{1,5{a,b{c,d}}}", "5a", File::FNM_EXTGLOB).should == true
+ File.fnmatch("{1,5{a,b{c,d}}}", "5bc", File::FNM_EXTGLOB).should == true
+ File.fnmatch("{1,5{a,b{c,d}}}", "5bd", File::FNM_EXTGLOB).should == true
+ File.fnmatch("\\\\{a\\,b,b\\}c}", "\\a,b", File::FNM_EXTGLOB).should == true
+ File.fnmatch("\\\\{a\\,b,b\\}c}", "\\b}c", File::FNM_EXTGLOB).should == true
+ end
+
+ it "doesn't support some { } patterns even when File::FNM_EXTGLOB is passed" do
+ File.fnmatch("a{0..3}b", "a0b", File::FNM_EXTGLOB).should == false
+ File.fnmatch("a{0..3}b", "a1b", File::FNM_EXTGLOB).should == false
+ File.fnmatch("a{0..3}b", "a2b", File::FNM_EXTGLOB).should == false
+ File.fnmatch("a{0..3}b", "a3b", File::FNM_EXTGLOB).should == false
+ File.fnmatch("{0..12}", "0", File::FNM_EXTGLOB).should == false
+ File.fnmatch("{0..12}", "6", File::FNM_EXTGLOB).should == false
+ File.fnmatch("{0..12}", "12", File::FNM_EXTGLOB).should == false
+ File.fnmatch("{3..-2}", "3", File::FNM_EXTGLOB).should == false
+ File.fnmatch("{3..-2}", "0", File::FNM_EXTGLOB).should == false
+ File.fnmatch("{3..-2}", "-2", File::FNM_EXTGLOB).should == false
+ File.fnmatch("{a..g}", "a", File::FNM_EXTGLOB).should == false
+ File.fnmatch("{a..g}", "d", File::FNM_EXTGLOB).should == false
+ File.fnmatch("{a..g}", "g", File::FNM_EXTGLOB).should == false
+ File.fnmatch("{g..a}", "a", File::FNM_EXTGLOB).should == false
+ File.fnmatch("{g..a}", "d", File::FNM_EXTGLOB).should == false
+ File.fnmatch("{g..a}", "g", File::FNM_EXTGLOB).should == false
+ File.fnmatch("escaping: {{,\\,,\\},\\{}", "escaping: {", File::FNM_EXTGLOB).should == false
+ File.fnmatch("escaping: {{,\\,,\\},\\{}", "escaping: ,", File::FNM_EXTGLOB).should == false
+ File.fnmatch("escaping: {{,\\,,\\},\\{}", "escaping: }", File::FNM_EXTGLOB).should == false
+ File.fnmatch("escaping: {{,\\,,\\},\\{}", "escaping: {", File::FNM_EXTGLOB).should == false
+ end
+
+ it "doesn't match an extra } when File::FNM_EXTGLOB is passed" do
+ File.fnmatch('c{at,ub}}s', 'cats', File::FNM_EXTGLOB).should == false
+ end
+
+ it "matches when both FNM_EXTGLOB and FNM_PATHNAME are passed" do
+ File.fnmatch("?.md", "a.md", File::FNM_EXTGLOB | File::FNM_PATHNAME).should == true
+ end
+
+ it "matches a single character for each ? character" do
+ File.fnmatch('c?t', 'cat').should == true
+ File.fnmatch('c??t', 'cat').should == false
+ end
+
+ it "matches zero or more characters for each * character" do
+ File.fnmatch('c*', 'cats').should == true
+ File.fnmatch('c*t', 'c/a/b/t').should == true
+ end
+
+ it "does not match unterminated range of characters" do
+ File.fnmatch('abc[de', 'abcd').should == false
+ end
+
+ it "does not match unterminated range of characters as a literal" do
+ File.fnmatch('abc[de', 'abc[de').should == false
+ end
+
+ it "matches ranges of characters using bracket expression (e.g. [a-z])" do
+ File.fnmatch('ca[a-z]', 'cat').should == true
+ end
+
+ it "matches ranges of characters using bracket expression, taking case into account" do
+ File.fnmatch('[a-z]', 'D').should == false
+ File.fnmatch('[^a-z]', 'D').should == true
+ File.fnmatch('[A-Z]', 'd').should == false
+ File.fnmatch('[^A-Z]', 'd').should == true
+ File.fnmatch('[a-z]', 'D', File::FNM_CASEFOLD).should == true
+ end
+
+ it "does not match characters outside of the range of the bracket expression" do
+ File.fnmatch('ca[x-z]', 'cat').should == false
+ File.fnmatch('/ca[s][s-t]/rul[a-b]/[z]he/[x-Z]orld', '/cats/rule/the/World').should == false
+ end
+
+ it "matches ranges of characters using exclusive bracket expression (e.g. [^t] or [!t])" do
+ File.fnmatch('ca[^t]', 'cat').should == false
+ File.fnmatch('ca[^t]', 'cas').should == true
+ File.fnmatch('ca[!t]', 'cat').should == false
+ end
+
+ it "matches characters with a case sensitive comparison" do
+ File.fnmatch('cat', 'CAT').should == false
+ end
+
+ it "matches characters with case insensitive comparison when flags includes FNM_CASEFOLD" do
+ File.fnmatch('cat', 'CAT', File::FNM_CASEFOLD).should == true
+ end
+
+ platform_is_not :windows do
+ it "doesn't match case sensitive characters on platforms with case sensitive paths, when flags include FNM_SYSCASE" do
+ File.fnmatch('cat', 'CAT', File::FNM_SYSCASE).should == false
+ end
+ end
+
+ platform_is :windows do
+ it "matches case sensitive characters on platforms with case insensitive paths, when flags include FNM_SYSCASE" do
+ File.fnmatch('cat', 'CAT', File::FNM_SYSCASE).should == true
+ end
+ end
+
+ it "matches wildcard with characters when flags includes FNM_PATHNAME" do
+ File.fnmatch('*a', 'aa', File::FNM_PATHNAME).should == true
+ File.fnmatch('a*', 'aa', File::FNM_PATHNAME).should == true
+ File.fnmatch('a*', 'aaa', File::FNM_PATHNAME).should == true
+ File.fnmatch('*a', 'aaa', File::FNM_PATHNAME).should == true
+ end
+
+ it "does not match '/' characters with ? or * when flags includes FNM_PATHNAME" do
+ File.fnmatch('?', '/', File::FNM_PATHNAME).should == false
+ File.fnmatch('*', '/', File::FNM_PATHNAME).should == false
+ end
+
+ it "does not match '/' characters inside bracket expressions when flags includes FNM_PATHNAME" do
+ File.fnmatch('[/]', '/', File::FNM_PATHNAME).should == false
+ end
+
+ it "matches literal ? or * in path when pattern includes \\? or \\*" do
+ File.fnmatch('\?', '?').should == true
+ File.fnmatch('\?', 'a').should == false
+
+ File.fnmatch('\*', '*').should == true
+ File.fnmatch('\*', 'a').should == false
+ end
+
+ it "matches literal character (e.g. 'a') in path when pattern includes escaped character (e.g. \\a)" do
+ File.fnmatch('\a', 'a').should == true
+ File.fnmatch('this\b', 'thisb').should == true
+ end
+
+ it "matches '\\' characters in path when flags includes FNM_NOESCAPE" do
+ File.fnmatch('\a', '\a', File::FNM_NOESCAPE).should == true
+ File.fnmatch('\a', 'a', File::FNM_NOESCAPE).should == false
+ File.fnmatch('\[foo\]\[bar\]', '[foo][bar]', File::FNM_NOESCAPE).should == false
+ end
+
+ it "escapes special characters inside bracket expression" do
+ File.fnmatch('[\?]', '?').should == true
+ File.fnmatch('[\*]', '*').should == true
+ end
+
+ it "does not match leading periods in filenames with wildcards by default" do
+ File.should_not.fnmatch('*', '.profile')
+ File.should.fnmatch('*', 'home/.profile')
+ File.should.fnmatch('*/*', 'home/.profile')
+ File.should_not.fnmatch('*/*', 'dave/.profile', File::FNM_PATHNAME)
+ end
+
+ it "matches patterns with leading periods to dotfiles" do
+ File.fnmatch('.*', '.profile').should == true
+ File.fnmatch('.*', '.profile', File::FNM_PATHNAME).should == true
+ File.fnmatch(".*file", "nondotfile").should == false
+ File.fnmatch(".*file", "nondotfile", File::FNM_PATHNAME).should == false
+ end
+
+ it "does not match directories with leading periods by default with FNM_PATHNAME" do
+ File.fnmatch('.*', '.directory/nondotfile', File::FNM_PATHNAME).should == false
+ File.fnmatch('.*', '.directory/.profile', File::FNM_PATHNAME).should == false
+ File.fnmatch('.*', 'foo/.directory/nondotfile', File::FNM_PATHNAME).should == false
+ File.fnmatch('.*', 'foo/.directory/.profile', File::FNM_PATHNAME).should == false
+ File.fnmatch('**/.dotfile', '.dotsubdir/.dotfile', File::FNM_PATHNAME).should == false
+ end
+
+ it "matches leading periods in filenames when flags includes FNM_DOTMATCH" do
+ File.fnmatch('*', '.profile', File::FNM_DOTMATCH).should == true
+ File.fnmatch('*', 'home/.profile', File::FNM_DOTMATCH).should == true
+ end
+
+ it "matches multiple directories with ** and *" do
+ files = '**/*.rb'
+ File.fnmatch(files, 'main.rb').should == false
+ File.fnmatch(files, './main.rb').should == false
+ File.fnmatch(files, 'lib/song.rb').should == true
+ File.fnmatch('**.rb', 'main.rb').should == true
+ File.fnmatch('**.rb', './main.rb').should == false
+ File.fnmatch('**.rb', 'lib/song.rb').should == true
+ File.fnmatch('*', 'dave/.profile').should == true
+ end
+
+ it "matches multiple directories with ** when flags includes File::FNM_PATHNAME" do
+ files = '**/*.rb'
+ flags = File::FNM_PATHNAME
+
+ File.fnmatch(files, 'main.rb', flags).should == true
+ File.fnmatch(files, 'one/two/three/main.rb', flags).should == true
+ File.fnmatch(files, './main.rb', flags).should == false
+
+ flags = File::FNM_PATHNAME | File::FNM_DOTMATCH
+
+ File.fnmatch(files, './main.rb', flags).should == true
+ File.fnmatch(files, 'one/two/.main.rb', flags).should == true
+
+ File.fnmatch("**/best/*", 'lib/my/best/song.rb').should == true
+ end
+
+ it "returns false if '/' in pattern do not match '/' in path when flags includes FNM_PATHNAME" do
+ pattern = '*/*'
+ File.fnmatch(pattern, 'dave/.profile', File::FNM_PATHNAME).should == false
+
+ pattern = '**/foo'
+ File.fnmatch(pattern, 'a/.b/c/foo', File::FNM_PATHNAME).should == false
+ end
+
+ it "returns true if '/' in pattern match '/' in path when flags includes FNM_PATHNAME" do
+ pattern = '*/*'
+ File.fnmatch(pattern, 'dave/.profile', File::FNM_PATHNAME | File::FNM_DOTMATCH).should == true
+
+ pattern = '**/foo'
+ File.fnmatch(pattern, 'a/b/c/foo', File::FNM_PATHNAME).should == true
+ File.fnmatch(pattern, '/a/b/c/foo', File::FNM_PATHNAME).should == true
+ File.fnmatch(pattern, 'c:/a/b/c/foo', File::FNM_PATHNAME).should == true
+ File.fnmatch(pattern, 'a/.b/c/foo', File::FNM_PATHNAME | File::FNM_DOTMATCH).should == true
+ end
+
+ it "has special handling for ./ when using * and FNM_PATHNAME" do
+ File.fnmatch('./*', '.', File::FNM_PATHNAME).should == false
+ File.fnmatch('./*', './', File::FNM_PATHNAME).should == true
+ File.fnmatch('./*/', './', File::FNM_PATHNAME).should == false
+ File.fnmatch('./**', './', File::FNM_PATHNAME).should == true
+ File.fnmatch('./**/', './', File::FNM_PATHNAME).should == true
+ File.fnmatch('./*', '.', File::FNM_PATHNAME | File::FNM_DOTMATCH).should == false
+ File.fnmatch('./*', './', File::FNM_PATHNAME | File::FNM_DOTMATCH).should == true
+ File.fnmatch('./*/', './', File::FNM_PATHNAME | File::FNM_DOTMATCH).should == false
+ File.fnmatch('./**', './', File::FNM_PATHNAME | File::FNM_DOTMATCH).should == true
+ File.fnmatch('./**/', './', File::FNM_PATHNAME | File::FNM_DOTMATCH).should == true
+ end
+
+ it "matches **/* with FNM_PATHNAME to recurse directories" do
+ File.fnmatch('nested/**/*', 'nested/subdir', File::FNM_PATHNAME).should == true
+ File.fnmatch('nested/**/*', 'nested/subdir/file', File::FNM_PATHNAME).should == true
+ File.fnmatch('nested/**/*', 'nested/.dotsubdir', File::FNM_PATHNAME | File::FNM_DOTMATCH).should == true
+ File.fnmatch('nested/**/*', 'nested/.dotsubir/.dotfile', File::FNM_PATHNAME | File::FNM_DOTMATCH).should == true
+ end
+
+ it "matches ** with FNM_PATHNAME only in current directory" do
+ File.fnmatch('nested/**', 'nested/subdir', File::FNM_PATHNAME).should == true
+ File.fnmatch('nested/**', 'nested/subdir/file', File::FNM_PATHNAME).should == false
+ File.fnmatch('nested/**', 'nested/.dotsubdir', File::FNM_PATHNAME | File::FNM_DOTMATCH).should == true
+ File.fnmatch('nested/**', 'nested/.dotsubir/.dotfile', File::FNM_PATHNAME | File::FNM_DOTMATCH).should == false
+ end
+
+ it "accepts an object that has a #to_path method" do
+ File.fnmatch('\*', mock_to_path('a')).should == false
+ end
+
+ it "raises a TypeError if the first and second arguments are not string-like" do
+ -> { File.fnmatch(nil, nil, 0, 0) }.should.raise(ArgumentError)
+ -> { File.fnmatch(1, 'some/thing') }.should.raise(TypeError)
+ -> { File.fnmatch('some/thing', 1) }.should.raise(TypeError)
+ -> { File.fnmatch(1, 1) }.should.raise(TypeError)
+ end
+
+ it "raises a TypeError if the third argument is not an Integer" do
+ -> { File.fnmatch("*/place", "path/to/file", "flags") }.should.raise(TypeError)
+ -> { File.fnmatch("*/place", "path/to/file", nil) }.should.raise(TypeError)
+ end
+
+ it "does not raise a TypeError if the third argument can be coerced to an Integer" do
+ flags = mock("flags")
+ flags.should_receive(:to_int).and_return(10)
+ -> { File.fnmatch("*/place", "path/to/file", flags) }.should_not.raise
+ end
+
+ it "matches multibyte characters" do
+ File.fnmatch("*/ä/ø/ñ", "a/ä/ø/ñ").should == true
+ end
end
describe "File.fnmatch?" do
- it_behaves_like :file_fnmatch, :fnmatch?
+ it "is an alias of File.fnmatch" do
+ File.method(:fnmatch?).should == File.method(:fnmatch)
+ end
end
diff --git a/spec/ruby/core/file/ftype_spec.rb b/spec/ruby/core/file/ftype_spec.rb
index cdddc404dc..ab9f76b79b 100644
--- a/spec/ruby/core/file/ftype_spec.rb
+++ b/spec/ruby/core/file/ftype_spec.rb
@@ -7,19 +7,19 @@ describe "File.ftype" do
end
it "raises ArgumentError if not given exactly one filename" do
- -> { File.ftype }.should raise_error(ArgumentError)
- -> { File.ftype('blah', 'bleh') }.should raise_error(ArgumentError)
+ -> { File.ftype }.should.raise(ArgumentError)
+ -> { File.ftype('blah', 'bleh') }.should.raise(ArgumentError)
end
it "raises Errno::ENOENT if the file is not valid" do
-> {
File.ftype("/#{$$}#{Time.now.to_f}")
- }.should raise_error(Errno::ENOENT)
+ }.should.raise(Errno::ENOENT)
end
it "returns a String" do
FileSpecs.normal_file do |file|
- File.ftype(file).should be_kind_of(String)
+ File.ftype(file).should.is_a?(String)
end
end
diff --git a/spec/ruby/core/file/inspect_spec.rb b/spec/ruby/core/file/inspect_spec.rb
index 148e789c62..fe87429e8d 100644
--- a/spec/ruby/core/file/inspect_spec.rb
+++ b/spec/ruby/core/file/inspect_spec.rb
@@ -12,6 +12,6 @@ describe "File#inspect" do
end
it "returns a String" do
- @file.inspect.should be_an_instance_of(String)
+ @file.inspect.should.instance_of?(String)
end
end
diff --git a/spec/ruby/core/file/join_spec.rb b/spec/ruby/core/file/join_spec.rb
index 0feedbae93..0f0911ea31 100644
--- a/spec/ruby/core/file/join_spec.rb
+++ b/spec/ruby/core/file/join_spec.rb
@@ -52,7 +52,7 @@ describe "File.join" do
it "returns a duplicate string when given a single argument" do
str = "usr"
File.join(str).should == str
- File.join(str).should_not equal(str)
+ File.join(str).should_not.equal?(str)
end
it "supports any number of arguments" do
@@ -104,15 +104,15 @@ describe "File.join" do
it "raises an ArgumentError if passed a recursive array" do
a = ["a"]
a << a
- -> { File.join a }.should raise_error(ArgumentError)
+ -> { File.join a }.should.raise(ArgumentError)
end
it "raises a TypeError exception when args are nil" do
- -> { File.join nil }.should raise_error(TypeError)
+ -> { File.join nil }.should.raise(TypeError)
end
it "calls #to_str" do
- -> { File.join(mock('x')) }.should raise_error(TypeError)
+ -> { File.join(mock('x')) }.should.raise(TypeError)
bin = mock("bin")
bin.should_receive(:to_str).exactly(:twice).and_return("bin")
@@ -129,7 +129,7 @@ describe "File.join" do
end
it "calls #to_path" do
- -> { File.join(mock('x')) }.should raise_error(TypeError)
+ -> { File.join(mock('x')) }.should.raise(TypeError)
bin = mock("bin")
bin.should_receive(:to_path).exactly(:twice).and_return("bin")
@@ -138,10 +138,10 @@ describe "File.join" do
end
it "raises errors for null bytes" do
- -> { File.join("\x00x", "metadata.gz") }.should raise_error(ArgumentError) { |e|
+ -> { File.join("\x00x", "metadata.gz") }.should.raise(ArgumentError) { |e|
e.message.should == 'string contains null byte'
}
- -> { File.join("metadata.gz", "\x00x") }.should raise_error(ArgumentError) { |e|
+ -> { File.join("metadata.gz", "\x00x") }.should.raise(ArgumentError) { |e|
e.message.should == 'string contains null byte'
}
end
diff --git a/spec/ruby/core/file/link_spec.rb b/spec/ruby/core/file/link_spec.rb
index a5d5b4815f..768ee4b0fa 100644
--- a/spec/ruby/core/file/link_spec.rb
+++ b/spec/ruby/core/file/link_spec.rb
@@ -22,18 +22,18 @@ describe "File.link" do
it "raises an Errno::EEXIST if the target already exists" do
File.link(@file, @link)
- -> { File.link(@file, @link) }.should raise_error(Errno::EEXIST)
+ -> { File.link(@file, @link) }.should.raise(Errno::EEXIST)
end
it "raises an ArgumentError if not passed two arguments" do
- -> { File.link }.should raise_error(ArgumentError)
- -> { File.link(@file) }.should raise_error(ArgumentError)
- -> { File.link(@file, @link, @file) }.should raise_error(ArgumentError)
+ -> { File.link }.should.raise(ArgumentError)
+ -> { File.link(@file) }.should.raise(ArgumentError)
+ -> { File.link(@file, @link, @file) }.should.raise(ArgumentError)
end
it "raises a TypeError if not passed String types" do
- -> { File.link(@file, nil) }.should raise_error(TypeError)
- -> { File.link(@file, 1) }.should raise_error(TypeError)
+ -> { File.link(@file, nil) }.should.raise(TypeError)
+ -> { File.link(@file, 1) }.should.raise(TypeError)
end
end
end
diff --git a/spec/ruby/core/file/mkfifo_spec.rb b/spec/ruby/core/file/mkfifo_spec.rb
index 19298c967c..ce4a67fe31 100644
--- a/spec/ruby/core/file/mkfifo_spec.rb
+++ b/spec/ruby/core/file/mkfifo_spec.rb
@@ -19,13 +19,13 @@ describe "File.mkfifo" do
context "when path passed is not a String value" do
it "raises a TypeError" do
- -> { File.mkfifo(:"/tmp/fifo") }.should raise_error(TypeError)
+ -> { File.mkfifo(:"/tmp/fifo") }.should.raise(TypeError)
end
end
context "when path does not exist" do
it "raises an Errno::ENOENT exception" do
- -> { File.mkfifo("/bogus/path") }.should raise_error(Errno::ENOENT)
+ -> { File.mkfifo("/bogus/path") }.should.raise(Errno::ENOENT)
end
end
diff --git a/spec/ruby/core/file/mtime_spec.rb b/spec/ruby/core/file/mtime_spec.rb
index 0e9c95caee..d83725e25d 100644
--- a/spec/ruby/core/file/mtime_spec.rb
+++ b/spec/ruby/core/file/mtime_spec.rb
@@ -11,7 +11,7 @@ describe "File.mtime" do
end
it "returns the modification Time of the file" do
- File.mtime(@filename).should be_kind_of(Time)
+ File.mtime(@filename).should.is_a?(Time)
File.mtime(@filename).should be_close(@mtime, TIME_TOLERANCE)
end
@@ -34,7 +34,7 @@ describe "File.mtime" do
end
it "raises an Errno::ENOENT exception if the file is not found" do
- -> { File.mtime('bogus') }.should raise_error(Errno::ENOENT)
+ -> { File.mtime('bogus') }.should.raise(Errno::ENOENT)
end
end
@@ -50,7 +50,7 @@ describe "File#mtime" do
end
it "returns the modification Time of the file" do
- @f.mtime.should be_kind_of(Time)
+ @f.mtime.should.is_a?(Time)
end
end
diff --git a/spec/ruby/core/file/new_spec.rb b/spec/ruby/core/file/new_spec.rb
index 1e82a070b1..4cd2cb5dcb 100644
--- a/spec/ruby/core/file/new_spec.rb
+++ b/spec/ruby/core/file/new_spec.rb
@@ -16,13 +16,13 @@ describe "File.new" do
it "returns a new File with mode string" do
@fh = File.new(@file, 'w')
- @fh.should be_kind_of(File)
+ @fh.should.is_a?(File)
File.should.exist?(@file)
end
it "returns a new File with mode num" do
@fh = File.new(@file, @flags)
- @fh.should be_kind_of(File)
+ @fh.should.is_a?(File)
File.should.exist?(@file)
end
@@ -30,7 +30,7 @@ describe "File.new" do
rm_r @file
File.umask(0011)
@fh = File.new(@file, @flags, 0755)
- @fh.should be_kind_of(File)
+ @fh.should.is_a?(File)
platform_is_not :windows do
File.stat(@file).mode.to_s(8).should == "100744"
end
@@ -44,7 +44,7 @@ describe "File.new" do
rm_r @file
begin
f = File.new(@file, "w", 0444)
- -> { f.puts("test") }.should_not raise_error(IOError)
+ -> { f.puts("test") }.should_not.raise(IOError)
ensure
f.close
end
@@ -74,14 +74,14 @@ describe "File.new" do
@fh = File.new(@file)
fh_copy = File.new(@fh.fileno)
fh_copy.autoclose = false
- fh_copy.should be_kind_of(File)
+ fh_copy.should.is_a?(File)
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.puts("test") }.should.raise(IOError)
@fh.read.should == ""
File.should.exist?(@file)
end
@@ -89,68 +89,68 @@ describe "File.new" do
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.puts("test") }.should.raise(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)
+ @fh.should.is_a?(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
- -> { @fh = File.new(@file, File::CREAT|File::EXCL) }.should raise_error(Errno::EEXIST)
+ -> { @fh = File.new(@file, File::CREAT|File::EXCL) }.should.raise(Errno::EEXIST)
end
it "creates a new file when use File::WRONLY|File::APPEND mode" do
@fh = File.new(@file, File::WRONLY|File::APPEND)
- @fh.should be_kind_of(File)
+ @fh.should.is_a?(File)
File.should.exist?(@file)
end
it "returns a new File when use File::APPEND mode" do
@fh = File.new(@file, File::APPEND)
- @fh.should be_kind_of(File)
+ @fh.should.is_a?(File)
File.should.exist?(@file)
end
it "returns a new File when use File::RDONLY|File::APPEND mode" do
@fh = File.new(@file, File::RDONLY|File::APPEND)
- @fh.should be_kind_of(File)
+ @fh.should.is_a?(File)
File.should.exist?(@file)
end
it "returns a new File when use File::RDONLY|File::WRONLY mode" do
@fh = File.new(@file, File::RDONLY|File::WRONLY)
- @fh.should be_kind_of(File)
+ @fh.should.is_a?(File)
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)
+ @fh.should.is_a?(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)
+ @fh.should.is_a?(File)
File.should.exist?(@file)
# it's read-only
- -> { @fh.puts("test") }.should raise_error(IOError)
+ -> { @fh.puts("test") }.should.raise(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)
+ @fh.should.is_a?(File)
File.should.exist?(@file)
# it's read-only
- -> { @fh.puts("test") }.should raise_error(IOError)
+ -> { @fh.puts("test") }.should.raise(IOError)
@fh.read.should == ""
end
@@ -170,22 +170,22 @@ describe "File.new" do
it "accepts options as a keyword argument" do
@fh = File.new(@file, 'w', 0755, flags: @flags)
- @fh.should be_kind_of(File)
+ @fh.should.is_a?(File)
@fh.close
-> {
@fh = File.new(@file, 'w', 0755, {flags: @flags})
- }.should raise_error(ArgumentError, "wrong number of arguments (given 4, expected 1..3)")
+ }.should.raise(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/)
+ }.should.raise(Errno::EEXIST, /File exists/)
-> {
@fh = File.new(@file, mode: 'w', flags: File::EXCL)
- }.should raise_error(Errno::EEXIST, /File exists/)
+ }.should.raise(Errno::EEXIST, /File exists/)
end
it "does not use the given block and warns to use File::open" do
@@ -195,16 +195,16 @@ describe "File.new" do
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)
+ -> { File.new(true) }.should.raise(TypeError)
+ -> { File.new(false) }.should.raise(TypeError)
end
it "raises a TypeError if the first parameter is nil" do
- -> { File.new(nil) }.should raise_error(TypeError)
+ -> { File.new(nil) }.should.raise(TypeError)
end
it "raises an Errno::EBADF if the first parameter is an invalid file descriptor" do
- -> { File.new(-1) }.should raise_error(Errno::EBADF)
+ -> { File.new(-1) }.should.raise(Errno::EBADF)
end
platform_is_not :windows do
@@ -213,7 +213,7 @@ describe "File.new" do
-> {
f = File.new(@fh.fileno, @flags)
f.autoclose = false
- }.should raise_error(Errno::EINVAL)
+ }.should.raise(Errno::EINVAL)
end
end
diff --git a/spec/ruby/core/file/open_spec.rb b/spec/ruby/core/file/open_spec.rb
index 6bfc16bbf9..7318c31636 100644
--- a/spec/ruby/core/file/open_spec.rb
+++ b/spec/ruby/core/file/open_spec.rb
@@ -40,7 +40,7 @@ describe "File.open" do
it "propagates non-StandardErrors produced by close" do
-> {
File.open(@file, 'r') { |f| FileSpecs.make_closer f, Exception }
- }.should raise_error(Exception)
+ }.should.raise(Exception)
ScratchPad.recorded.should == [:file_opened, :file_closed]
end
@@ -48,7 +48,7 @@ describe "File.open" do
it "propagates StandardErrors produced by close" do
-> {
File.open(@file, 'r') { |f| FileSpecs.make_closer f, StandardError }
- }.should raise_error(StandardError)
+ }.should.raise(StandardError)
ScratchPad.recorded.should == [:file_opened, :file_closed]
end
@@ -62,13 +62,13 @@ describe "File.open" do
it "opens the file (basic case)" do
@fh = File.open(@file)
- @fh.should be_kind_of(File)
+ @fh.should.is_a?(File)
File.should.exist?(@file)
end
it "opens the file with unicode characters" do
@fh = File.open(@unicode_path, "w")
- @fh.should be_kind_of(File)
+ @fh.should.is_a?(File)
File.should.exist?(@unicode_path)
end
@@ -79,7 +79,7 @@ describe "File.open" do
it "opens with mode string" do
@fh = File.open(@file, 'w')
- @fh.should be_kind_of(File)
+ @fh.should.is_a?(File)
File.should.exist?(@file)
end
@@ -90,7 +90,7 @@ describe "File.open" do
it "opens a file with mode num" do
@fh = File.open(@file, @flags)
- @fh.should be_kind_of(File)
+ @fh.should.is_a?(File)
File.should.exist?(@file)
end
@@ -101,7 +101,7 @@ describe "File.open" do
it "opens a file with mode and permission as nil" do
@fh = File.open(@file, nil, nil)
- @fh.should be_kind_of(File)
+ @fh.should.is_a?(File)
end
# For this test we delete the file first to reset the perms
@@ -109,7 +109,7 @@ describe "File.open" do
rm_r @file
File.umask(0011)
@fh = File.open(@file, @flags, 0755)
- @fh.should be_kind_of(File)
+ @fh.should.is_a?(File)
platform_is_not :windows do
@fh.lstat.mode.to_s(8).should == "100744"
end
@@ -161,69 +161,69 @@ describe "File.open" do
@fh = File.open(@file)
fh_copy = File.open(@fh.fileno)
fh_copy.autoclose = false
- fh_copy.should be_kind_of(File)
+ fh_copy.should.is_a?(File)
File.should.exist?(@file)
end
it "opens a file that no exists when use File::WRONLY mode" do
- -> { File.open(@nonexistent, File::WRONLY) }.should raise_error(Errno::ENOENT)
+ -> { File.open(@nonexistent, File::WRONLY) }.should.raise(Errno::ENOENT)
end
it "opens a file that no exists when use File::RDONLY mode" do
- -> { File.open(@nonexistent, File::RDONLY) }.should raise_error(Errno::ENOENT)
+ -> { File.open(@nonexistent, File::RDONLY) }.should.raise(Errno::ENOENT)
end
it "opens a file that no exists when use 'r' mode" do
- -> { File.open(@nonexistent, 'r') }.should raise_error(Errno::ENOENT)
+ -> { File.open(@nonexistent, 'r') }.should.raise(Errno::ENOENT)
end
it "opens a file that no exists when use File::EXCL mode" do
- -> { File.open(@nonexistent, File::EXCL) }.should raise_error(Errno::ENOENT)
+ -> { File.open(@nonexistent, File::EXCL) }.should.raise(Errno::ENOENT)
end
it "opens a file that no exists when use File::NONBLOCK mode" do
- -> { File.open(@nonexistent, File::NONBLOCK) }.should raise_error(Errno::ENOENT)
+ -> { File.open(@nonexistent, File::NONBLOCK) }.should.raise(Errno::ENOENT)
end
platform_is_not :openbsd, :windows do
it "opens a file that no exists when use File::TRUNC mode" do
- -> { File.open(@nonexistent, File::TRUNC) }.should raise_error(Errno::ENOENT)
+ -> { File.open(@nonexistent, File::TRUNC) }.should.raise(Errno::ENOENT)
end
end
platform_is :openbsd, :windows do
it "does not open a file that does no exists when using File::TRUNC mode" do
- -> { File.open(@nonexistent, File::TRUNC) }.should raise_error(Errno::EINVAL)
+ -> { File.open(@nonexistent, File::TRUNC) }.should.raise(Errno::EINVAL)
end
end
platform_is_not :windows do
it "opens a file that no exists when use File::NOCTTY mode" do
- -> { File.open(@nonexistent, File::NOCTTY) }.should raise_error(Errno::ENOENT)
+ -> { File.open(@nonexistent, File::NOCTTY) }.should.raise(Errno::ENOENT)
end
end
it "opens a file that no exists when use File::CREAT mode" do
@fh = File.open(@nonexistent, File::CREAT) { |f| f }
- @fh.should be_kind_of(File)
+ @fh.should.is_a?(File)
File.should.exist?(@file)
end
it "opens a file that no exists when use 'a' mode" do
@fh = File.open(@nonexistent, 'a') { |f| f }
- @fh.should be_kind_of(File)
+ @fh.should.is_a?(File)
File.should.exist?(@file)
end
it "opens a file that no exists when use 'w' mode" do
@fh = File.open(@nonexistent, 'w') { |f| f }
- @fh.should be_kind_of(File)
+ @fh.should.is_a?(File)
File.should.exist?(@file)
end
# Check the grants associated to the different open modes combinations.
it "raises an ArgumentError exception when call with an unknown mode" do
- -> { File.open(@file, "q") }.should raise_error(ArgumentError)
+ -> { File.open(@file, "q") }.should.raise(ArgumentError)
end
it "can read in a block when call open with RDONLY mode" do
@@ -240,13 +240,13 @@ describe "File.open" do
it "raises an IO exception when write in a block opened with RDONLY mode" do
File.open(@file, File::RDONLY) do |f|
- -> { f.puts "writing ..." }.should raise_error(IOError)
+ -> { f.puts "writing ..." }.should.raise(IOError)
end
end
it "raises an IO exception when write in a block opened with 'r' mode" do
File.open(@file, "r") do |f|
- -> { f.puts "writing ..." }.should raise_error(IOError)
+ -> { f.puts "writing ..." }.should.raise(IOError)
end
end
@@ -261,7 +261,7 @@ describe "File.open" do
File.open(@file, File::WRONLY|File::RDONLY ) do |f|
f.gets.should == nil
end
- }.should raise_error(IOError)
+ }.should.raise(IOError)
end
it "can write in a block when call open with WRONLY mode" do
@@ -278,39 +278,39 @@ describe "File.open" do
it "raises an IOError when read in a block opened with WRONLY mode" do
File.open(@file, File::WRONLY) do |f|
- -> { f.gets }.should raise_error(IOError)
+ -> { f.gets }.should.raise(IOError)
end
end
it "raises an IOError when read in a block opened with 'w' mode" do
File.open(@file, "w") do |f|
- -> { f.gets }.should raise_error(IOError)
+ -> { f.gets }.should.raise(IOError)
end
end
it "raises an IOError when read in a block opened with 'a' mode" do
File.open(@file, "a") do |f|
- -> { f.gets }.should raise_error(IOError)
+ -> { f.gets }.should.raise(IOError)
end
end
it "raises an IOError when read in a block opened with 'a' mode" do
File.open(@file, "a") do |f|
f.puts("writing").should == nil
- -> { f.gets }.should raise_error(IOError)
+ -> { f.gets }.should.raise(IOError)
end
end
it "raises an IOError when read in a block opened with 'a' mode" do
File.open(@file, File::WRONLY|File::APPEND ) do |f|
- -> { f.gets }.should raise_error(IOError)
+ -> { f.gets }.should.raise(IOError)
end
end
it "raises an IOError when read in a block opened with File::WRONLY|File::APPEND mode" do
File.open(@file, File::WRONLY|File::APPEND ) do |f|
f.puts("writing").should == nil
- -> { f.gets }.should raise_error(IOError)
+ -> { f.gets }.should.raise(IOError)
end
end
@@ -319,7 +319,7 @@ describe "File.open" do
File.open(@file, File::RDONLY|File::APPEND ) do |f|
f.puts("writing")
end
- }.should raise_error(IOError)
+ }.should.raise(IOError)
end
it "can read and write in a block when call open with RDWR mode" do
@@ -336,7 +336,7 @@ describe "File.open" do
File.open(@file, File::EXCL) do |f|
f.puts("writing").should == nil
end
- }.should raise_error(IOError)
+ }.should.raise(IOError)
end
it "can read in a block when call open with File::EXCL mode" do
@@ -359,12 +359,12 @@ describe "File.open" do
File.open(@file, File::CREAT|File::EXCL) do |f|
f.puts("writing")
end
- }.should raise_error(Errno::EEXIST)
+ }.should.raise(Errno::EEXIST)
end
it "creates a new file when use File::WRONLY|File::APPEND mode" do
@fh = File.open(@file, File::WRONLY|File::APPEND)
- @fh.should be_kind_of(File)
+ @fh.should.is_a?(File)
File.should.exist?(@file)
end
@@ -386,7 +386,7 @@ describe "File.open" do
File.open(@file, File::RDONLY|File::APPEND) do |f|
f.puts("writing").should == nil
end
- }.should raise_error(IOError)
+ }.should.raise(IOError)
end
platform_is_not :openbsd, :windows do
@@ -407,7 +407,7 @@ describe "File.open" do
fh1 = File.open(@file, "w")
begin
@fh = File.open(@file, File::WRONLY|File::TRUNC)
- @fh.should be_kind_of(File)
+ @fh.should.is_a?(File)
File.should.exist?(@file)
ensure
fh1.close
@@ -420,7 +420,7 @@ describe "File.open" do
File.open(@file, File::TRUNC) do |f|
f.puts("writing")
end
- }.should raise_error(IOError)
+ }.should.raise(IOError)
end
it "raises an Errno::EEXIST if the file exists when open with File::RDONLY|File::TRUNC" do
@@ -428,7 +428,7 @@ describe "File.open" do
File.open(@file, File::RDONLY|File::TRUNC) do |f|
f.puts("writing").should == nil
end
- }.should raise_error(IOError)
+ }.should.raise(IOError)
end
end
@@ -438,7 +438,7 @@ describe "File.open" do
File.open(@file, File::TRUNC) do |f|
f.puts("writing")
end
- }.should raise_error(Errno::EINVAL)
+ }.should.raise(Errno::EINVAL)
end
it "raises an Errno::EEXIST if the file exists when open with File::RDONLY|File::TRUNC" do
@@ -446,7 +446,7 @@ describe "File.open" do
File.open(@file, File::RDONLY|File::TRUNC) do |f|
f.puts("writing").should == nil
end
- }.should raise_error(Errno::EINVAL)
+ }.should.raise(Errno::EINVAL)
end
end
@@ -455,7 +455,7 @@ describe "File.open" do
it "raises an Errno::EACCES when opening non-permitted file" do
@fh = File.open(@file, "w")
@fh.chmod(000)
- -> { fh1 = File.open(@file); fh1.close }.should raise_error(Errno::EACCES)
+ -> { fh1 = File.open(@file); fh1.close }.should.raise(Errno::EACCES)
end
end
end
@@ -464,19 +464,19 @@ describe "File.open" do
it "raises an Errno::EACCES when opening read-only file" do
@fh = File.open(@file, "w")
@fh.chmod(0444)
- -> { File.open(@file, "w") }.should raise_error(Errno::EACCES)
+ -> { File.open(@file, "w") }.should.raise(Errno::EACCES)
end
end
it "opens a file for binary read" do
@fh = File.open(@file, "rb")
- @fh.should be_kind_of(File)
+ @fh.should.is_a?(File)
File.should.exist?(@file)
end
it "opens a file for binary write" do
@fh = File.open(@file, "wb")
- @fh.should be_kind_of(File)
+ @fh.should.is_a?(File)
File.should.exist?(@file)
end
@@ -543,21 +543,21 @@ describe "File.open" do
end
it "raises a TypeError if passed a filename that is not a String or Integer type" do
- -> { File.open(true) }.should raise_error(TypeError)
- -> { File.open(false) }.should raise_error(TypeError)
- -> { File.open(nil) }.should raise_error(TypeError)
+ -> { File.open(true) }.should.raise(TypeError)
+ -> { File.open(false) }.should.raise(TypeError)
+ -> { File.open(nil) }.should.raise(TypeError)
end
it "raises a SystemCallError if passed an invalid Integer type" do
- -> { File.open(-1) }.should raise_error(SystemCallError)
+ -> { File.open(-1) }.should.raise(SystemCallError)
end
it "raises an ArgumentError if passed the wrong number of arguments" do
- -> { File.open(@file, File::CREAT, 0755, 'test') }.should raise_error(ArgumentError)
+ -> { File.open(@file, File::CREAT, 0755, 'test') }.should.raise(ArgumentError)
end
it "raises an ArgumentError if passed an invalid string for mode" do
- -> { File.open(@file, 'fake') }.should raise_error(ArgumentError)
+ -> { File.open(@file, 'fake') }.should.raise(ArgumentError)
end
it "defaults external_encoding to BINARY for binary modes" do
@@ -567,16 +567,16 @@ describe "File.open" do
it "accepts options as a keyword argument" do
@fh = File.open(@file, 'w', 0755, flags: File::CREAT)
- @fh.should be_an_instance_of(File)
+ @fh.should.instance_of?(File)
-> {
File.open(@file, 'w', 0755, {flags: File::CREAT})
- }.should raise_error(ArgumentError, "wrong number of arguments (given 4, expected 1..3)")
+ }.should.raise(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)
+ @fh.should.instance_of?(File)
end
it "calls #to_hash to convert the second argument to a Hash" do
@@ -589,17 +589,17 @@ describe "File.open" do
it "accepts extra flags as a keyword argument and combine with a string mode" do
-> {
File.open(@file, "w", flags: File::EXCL) { }
- }.should raise_error(Errno::EEXIST)
+ }.should.raise(Errno::EEXIST)
-> {
File.open(@file, mode: "w", flags: File::EXCL) { }
- }.should raise_error(Errno::EEXIST)
+ }.should.raise(Errno::EEXIST)
end
it "accepts extra flags as a keyword argument and combine with an integer mode" do
-> {
File.open(@file, File::WRONLY | File::CREAT, flags: File::EXCL) { }
- }.should raise_error(Errno::EEXIST)
+ }.should.raise(Errno::EEXIST)
end
platform_is_not :windows do
@@ -643,7 +643,7 @@ describe "File.open" do
it "raises ArgumentError if mixing :newline and binary mode" do
-> {
File.open(@file, "rb", newline: :universal) {}
- }.should raise_error(ArgumentError, "newline decorator with binary mode")
+ }.should.raise(ArgumentError, "newline decorator with binary mode")
end
context "'x' flag" do
@@ -663,12 +663,12 @@ describe "File.open" do
it "throws a Errno::EEXIST error if the file exists" do
touch @xfile
- -> { File.open(@xfile, "wx") }.should raise_error(Errno::EEXIST)
+ -> { File.open(@xfile, "wx") }.should.raise(Errno::EEXIST)
end
it "can't be used with 'r' and 'a' flags" do
- -> { File.open(@xfile, "rx") }.should raise_error(ArgumentError, 'invalid access mode rx')
- -> { File.open(@xfile, "ax") }.should raise_error(ArgumentError, 'invalid access mode ax')
+ -> { File.open(@xfile, "rx") }.should.raise(ArgumentError, 'invalid access mode rx')
+ -> { File.open(@xfile, "ax") }.should.raise(ArgumentError, 'invalid access mode ax')
end
end
end
@@ -688,8 +688,8 @@ describe "File.open when passed a file descriptor" do
it "opens a file" do
@file = File.open(@fd, "w")
- @file.should be_an_instance_of(File)
- @file.fileno.should equal(@fd)
+ @file.should.instance_of?(File)
+ @file.fileno.should.equal?(@fd)
@file.write @content
@file.flush
File.read(@name).should == @content
@@ -697,8 +697,8 @@ describe "File.open when passed a file descriptor" do
it "opens a file when passed a block" do
@file = File.open(@fd, "w") do |f|
- f.should be_an_instance_of(File)
- f.fileno.should equal(@fd)
+ f.should.instance_of?(File)
+ f.fileno.should.equal?(@fd)
f.write @content
f
end
diff --git a/spec/ruby/core/file/path_spec.rb b/spec/ruby/core/file/path_spec.rb
index dfa0c4ec02..f3b9b56dbe 100644
--- a/spec/ruby/core/file/path_spec.rb
+++ b/spec/ruby/core/file/path_spec.rb
@@ -1,8 +1,9 @@
require_relative '../../spec_helper'
-require_relative 'shared/path'
describe "File#path" do
- it_behaves_like :file_path, :path
+ it "is an alias of File#to_path" do
+ File.instance_method(:path).should == File.instance_method(:to_path)
+ end
end
describe "File.path" do
@@ -37,4 +38,45 @@ describe "File.path" do
path.should_receive(:to_path).and_return("abc")
File.path(path).should == "abc"
end
+
+ it "raises TypeError when #to_path result is not a string" do
+ path = mock("path")
+ path.should_receive(:to_path).and_return(nil)
+ -> { File.path(path) }.should.raise TypeError
+
+ path = mock("path")
+ path.should_receive(:to_path).and_return(42)
+ -> { File.path(path) }.should.raise TypeError
+ end
+
+ it "raises ArgumentError for string argument contains NUL character" do
+ -> { File.path("\0") }.should.raise ArgumentError
+ -> { File.path("a\0") }.should.raise ArgumentError
+ -> { File.path("a\0c") }.should.raise ArgumentError
+ end
+
+ it "raises ArgumentError when #to_path result contains NUL character" do
+ path = mock("path")
+ path.should_receive(:to_path).and_return("\0")
+ -> { File.path(path) }.should.raise ArgumentError
+
+ path = mock("path")
+ path.should_receive(:to_path).and_return("a\0")
+ -> { File.path(path) }.should.raise ArgumentError
+
+ path = mock("path")
+ path.should_receive(:to_path).and_return("a\0c")
+ -> { File.path(path) }.should.raise ArgumentError
+ end
+
+ it "raises Encoding::CompatibilityError for ASCII-incompatible string argument" do
+ path = "abc".encode(Encoding::UTF_32BE)
+ -> { File.path(path) }.should.raise Encoding::CompatibilityError
+ end
+
+ it "raises Encoding::CompatibilityError when #to_path result is ASCII-incompatible" do
+ path = mock("path")
+ path.should_receive(:to_path).and_return("abc".encode(Encoding::UTF_32BE))
+ -> { File.path(path) }.should.raise Encoding::CompatibilityError
+ end
end
diff --git a/spec/ruby/core/file/readlink_spec.rb b/spec/ruby/core/file/readlink_spec.rb
index 20741ba121..568692b9b6 100644
--- a/spec/ruby/core/file/readlink_spec.rb
+++ b/spec/ruby/core/file/readlink_spec.rb
@@ -26,12 +26,12 @@ describe "File.readlink" do
it "raises an Errno::ENOENT if there is no such file" do
# TODO: missing_file
- -> { File.readlink("/this/surely/does/not/exist") }.should raise_error(Errno::ENOENT)
+ -> { File.readlink("/this/surely/does/not/exist") }.should.raise(Errno::ENOENT)
end
it "raises an Errno::EINVAL if called with a normal file" do
touch @file
- -> { File.readlink(@file) }.should raise_error(Errno::EINVAL)
+ -> { File.readlink(@file) }.should.raise(Errno::EINVAL)
end
end
@@ -49,7 +49,7 @@ describe "File.readlink" do
it "returns the name of the file referenced by the given link" do
touch @file
result = File.readlink(@link)
- result.encoding.should equal Encoding.find('filesystem')
+ result.encoding.should.equal? Encoding.find('filesystem')
result.should == @file.dup.force_encoding(Encoding.find('filesystem'))
end
end
diff --git a/spec/ruby/core/file/realdirpath_spec.rb b/spec/ruby/core/file/realdirpath_spec.rb
index 74053afce3..ecf1e0c6d9 100644
--- a/spec/ruby/core/file/realdirpath_spec.rb
+++ b/spec/ruby/core/file/realdirpath_spec.rb
@@ -61,7 +61,7 @@ platform_is_not :windows do
it "raises an Errno::ELOOP if the symlink points to itself" do
File.unlink @link
File.symlink(@link, @link)
- -> { File.realdirpath(@link) }.should raise_error(Errno::ELOOP)
+ -> { File.realdirpath(@link) }.should.raise(Errno::ELOOP)
end
it "returns the real (absolute) pathname if the file is absent" do
@@ -69,7 +69,7 @@ platform_is_not :windows do
end
it "raises Errno::ENOENT if the directory is absent" do
- -> { File.realdirpath(@fake_file_in_fake_dir) }.should raise_error(Errno::ENOENT)
+ -> { File.realdirpath(@fake_file_in_fake_dir) }.should.raise(Errno::ENOENT)
end
it "returns the real (absolute) pathname if the symlink points to an absent file" do
@@ -77,7 +77,7 @@ platform_is_not :windows do
end
it "raises Errno::ENOENT if the symlink points to an absent directory" do
- -> { File.realdirpath(@fake_link_to_fake_dir) }.should raise_error(Errno::ENOENT)
+ -> { File.realdirpath(@fake_link_to_fake_dir) }.should.raise(Errno::ENOENT)
end
end
end
diff --git a/spec/ruby/core/file/realpath_spec.rb b/spec/ruby/core/file/realpath_spec.rb
index bd25bfdecf..ccb981eff1 100644
--- a/spec/ruby/core/file/realpath_spec.rb
+++ b/spec/ruby/core/file/realpath_spec.rb
@@ -61,15 +61,15 @@ platform_is_not :windows do
it "raises an Errno::ELOOP if the symlink points to itself" do
File.unlink @link
File.symlink(@link, @link)
- -> { File.realpath(@link) }.should raise_error(Errno::ELOOP)
+ -> { File.realpath(@link) }.should.raise(Errno::ELOOP)
end
it "raises Errno::ENOENT if the file is absent" do
- -> { File.realpath(@fake_file) }.should raise_error(Errno::ENOENT)
+ -> { File.realpath(@fake_file) }.should.raise(Errno::ENOENT)
end
it "raises Errno::ENOENT if the symlink points to an absent file" do
- -> { File.realpath(@fake_link) }.should raise_error(Errno::ENOENT)
+ -> { File.realpath(@fake_link) }.should.raise(Errno::ENOENT)
end
it "converts the argument with #to_path" do
diff --git a/spec/ruby/core/file/rename_spec.rb b/spec/ruby/core/file/rename_spec.rb
index f2c18d4905..70ea669a68 100644
--- a/spec/ruby/core/file/rename_spec.rb
+++ b/spec/ruby/core/file/rename_spec.rb
@@ -23,15 +23,15 @@ describe "File.rename" do
it "raises an Errno::ENOENT if the source does not exist" do
rm_r @old
- -> { File.rename(@old, @new) }.should raise_error(Errno::ENOENT)
+ -> { File.rename(@old, @new) }.should.raise(Errno::ENOENT)
end
it "raises an ArgumentError if not passed two arguments" do
- -> { File.rename }.should raise_error(ArgumentError)
- -> { File.rename(@file) }.should raise_error(ArgumentError)
+ -> { File.rename }.should.raise(ArgumentError)
+ -> { File.rename(@file) }.should.raise(ArgumentError)
end
it "raises a TypeError if not passed String types" do
- -> { File.rename(1, 2) }.should raise_error(TypeError)
+ -> { File.rename(1, 2) }.should.raise(TypeError)
end
end
diff --git a/spec/ruby/core/file/shared/fnmatch.rb b/spec/ruby/core/file/shared/fnmatch.rb
deleted file mode 100644
index db4b5c5d8c..0000000000
--- a/spec/ruby/core/file/shared/fnmatch.rb
+++ /dev/null
@@ -1,294 +0,0 @@
-describe :file_fnmatch, shared: true do
- it "matches entire strings" do
- File.send(@method, 'cat', 'cat').should == true
- end
-
- it "does not match partial strings" do
- File.send(@method, 'cat', 'category').should == false
- end
-
- it "does not support { } patterns by default" do
- File.send(@method, 'c{at,ub}s', 'cats').should == false
- File.send(@method, 'c{at,ub}s', 'c{at,ub}s').should == true
- end
-
- it "supports some { } patterns when File::FNM_EXTGLOB is passed" do
- File.send(@method, "{a,b}", "a", File::FNM_EXTGLOB).should == true
- File.send(@method, "{a,b}", "b", File::FNM_EXTGLOB).should == true
- File.send(@method, "c{at,ub}s", "cats", File::FNM_EXTGLOB).should == true
- File.send(@method, "c{at,ub}s", "cubs", File::FNM_EXTGLOB).should == true
- File.send(@method, "-c{at,ub}s-", "-cats-", File::FNM_EXTGLOB).should == true
- File.send(@method, "-c{at,ub}s-", "-cubs-", File::FNM_EXTGLOB).should == true
- File.send(@method, "{a,b,c}{d,e,f}{g,h}", "adg", File::FNM_EXTGLOB).should == true
- File.send(@method, "{a,b,c}{d,e,f}{g,h}", "bdg", File::FNM_EXTGLOB).should == true
- File.send(@method, "{a,b,c}{d,e,f}{g,h}", "ceh", File::FNM_EXTGLOB).should == true
- File.send(@method, "{aa,bb,cc,dd}", "aa", File::FNM_EXTGLOB).should == true
- File.send(@method, "{aa,bb,cc,dd}", "bb", File::FNM_EXTGLOB).should == true
- File.send(@method, "{aa,bb,cc,dd}", "cc", File::FNM_EXTGLOB).should == true
- File.send(@method, "{aa,bb,cc,dd}", "dd", File::FNM_EXTGLOB).should == true
- File.send(@method, "{1,5{a,b{c,d}}}", "1", File::FNM_EXTGLOB).should == true
- File.send(@method, "{1,5{a,b{c,d}}}", "5a", File::FNM_EXTGLOB).should == true
- File.send(@method, "{1,5{a,b{c,d}}}", "5bc", File::FNM_EXTGLOB).should == true
- File.send(@method, "{1,5{a,b{c,d}}}", "5bd", File::FNM_EXTGLOB).should == true
- File.send(@method, "\\\\{a\\,b,b\\}c}", "\\a,b", File::FNM_EXTGLOB).should == true
- File.send(@method, "\\\\{a\\,b,b\\}c}", "\\b}c", File::FNM_EXTGLOB).should == true
- end
-
- it "doesn't support some { } patterns even when File::FNM_EXTGLOB is passed" do
- File.send(@method, "a{0..3}b", "a0b", File::FNM_EXTGLOB).should == false
- File.send(@method, "a{0..3}b", "a1b", File::FNM_EXTGLOB).should == false
- File.send(@method, "a{0..3}b", "a2b", File::FNM_EXTGLOB).should == false
- File.send(@method, "a{0..3}b", "a3b", File::FNM_EXTGLOB).should == false
- File.send(@method, "{0..12}", "0", File::FNM_EXTGLOB).should == false
- File.send(@method, "{0..12}", "6", File::FNM_EXTGLOB).should == false
- File.send(@method, "{0..12}", "12", File::FNM_EXTGLOB).should == false
- File.send(@method, "{3..-2}", "3", File::FNM_EXTGLOB).should == false
- File.send(@method, "{3..-2}", "0", File::FNM_EXTGLOB).should == false
- File.send(@method, "{3..-2}", "-2", File::FNM_EXTGLOB).should == false
- File.send(@method, "{a..g}", "a", File::FNM_EXTGLOB).should == false
- File.send(@method, "{a..g}", "d", File::FNM_EXTGLOB).should == false
- File.send(@method, "{a..g}", "g", File::FNM_EXTGLOB).should == false
- File.send(@method, "{g..a}", "a", File::FNM_EXTGLOB).should == false
- File.send(@method, "{g..a}", "d", File::FNM_EXTGLOB).should == false
- File.send(@method, "{g..a}", "g", File::FNM_EXTGLOB).should == false
- File.send(@method, "escaping: {{,\\,,\\},\\{}", "escaping: {", File::FNM_EXTGLOB).should == false
- File.send(@method, "escaping: {{,\\,,\\},\\{}", "escaping: ,", File::FNM_EXTGLOB).should == false
- File.send(@method, "escaping: {{,\\,,\\},\\{}", "escaping: }", File::FNM_EXTGLOB).should == false
- File.send(@method, "escaping: {{,\\,,\\},\\{}", "escaping: {", File::FNM_EXTGLOB).should == false
- end
-
- it "doesn't match an extra } when File::FNM_EXTGLOB is passed" do
- File.send(@method, 'c{at,ub}}s', 'cats', File::FNM_EXTGLOB).should == false
- end
-
- it "matches when both FNM_EXTGLOB and FNM_PATHNAME are passed" do
- File.send(@method, "?.md", "a.md", File::FNM_EXTGLOB | File::FNM_PATHNAME).should == true
- end
-
- it "matches a single character for each ? character" do
- File.send(@method, 'c?t', 'cat').should == true
- File.send(@method, 'c??t', 'cat').should == false
- end
-
- it "matches zero or more characters for each * character" do
- File.send(@method, 'c*', 'cats').should == true
- File.send(@method, 'c*t', 'c/a/b/t').should == true
- end
-
- it "does not match unterminated range of characters" do
- File.send(@method, 'abc[de', 'abcd').should == false
- end
-
- it "does not match unterminated range of characters as a literal" do
- File.send(@method, 'abc[de', 'abc[de').should == false
- end
-
- it "matches ranges of characters using bracket expression (e.g. [a-z])" do
- File.send(@method, 'ca[a-z]', 'cat').should == true
- end
-
- it "matches ranges of characters using bracket expression, taking case into account" do
- File.send(@method, '[a-z]', 'D').should == false
- File.send(@method, '[^a-z]', 'D').should == true
- File.send(@method, '[A-Z]', 'd').should == false
- File.send(@method, '[^A-Z]', 'd').should == true
- File.send(@method, '[a-z]', 'D', File::FNM_CASEFOLD).should == true
- end
-
- it "does not match characters outside of the range of the bracket expression" do
- File.send(@method, 'ca[x-z]', 'cat').should == false
- File.send(@method, '/ca[s][s-t]/rul[a-b]/[z]he/[x-Z]orld', '/cats/rule/the/World').should == false
- end
-
- 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
-
- it "matches characters with a case sensitive comparison" do
- File.send(@method, 'cat', 'CAT').should == false
- end
-
- it "matches characters with case insensitive comparison when flags includes FNM_CASEFOLD" do
- File.send(@method, 'cat', 'CAT', File::FNM_CASEFOLD).should == true
- end
-
- platform_is_not :windows do
- it "doesn't match case sensitive characters on platforms with case sensitive paths, when flags include FNM_SYSCASE" do
- File.send(@method, 'cat', 'CAT', File::FNM_SYSCASE).should == false
- end
- end
-
- platform_is :windows do
- it "matches case sensitive characters on platforms with case insensitive paths, when flags include FNM_SYSCASE" do
- File.send(@method, 'cat', 'CAT', File::FNM_SYSCASE).should == true
- 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
- end
-
- it "does not match '/' characters inside bracket expressions when flags includes FNM_PATHNAME" do
- File.send(@method, '[/]', '/', File::FNM_PATHNAME).should == false
- end
-
- it "matches literal ? or * in path when pattern includes \\? or \\*" do
- File.send(@method, '\?', '?').should == true
- File.send(@method, '\?', 'a').should == false
-
- File.send(@method, '\*', '*').should == true
- File.send(@method, '\*', 'a').should == false
- end
-
- it "matches literal character (e.g. 'a') in path when pattern includes escaped character (e.g. \\a)" do
- File.send(@method, '\a', 'a').should == true
- File.send(@method, 'this\b', 'thisb').should == true
- end
-
- it "matches '\\' characters in path when flags includes FNM_NOESACPE" do
- File.send(@method, '\a', '\a', File::FNM_NOESCAPE).should == true
- File.send(@method, '\a', 'a', File::FNM_NOESCAPE).should == false
- File.send(@method, '\[foo\]\[bar\]', '[foo][bar]', File::FNM_NOESCAPE).should == false
- end
-
- it "escapes special characters inside bracket expression" do
- File.send(@method, '[\?]', '?').should == true
- File.send(@method, '[\*]', '*').should == true
- end
-
- it "does not match leading periods in filenames with wildcards by default" do
- File.should_not.send(@method, '*', '.profile')
- File.should.send(@method, '*', 'home/.profile')
- File.should.send(@method, '*/*', 'home/.profile')
- File.should_not.send(@method, '*/*', 'dave/.profile', File::FNM_PATHNAME)
- end
-
- it "matches patterns with leading periods to dotfiles" 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
- File.send(@method, '*', '.profile', File::FNM_DOTMATCH).should == true
- File.send(@method, '*', 'home/.profile', File::FNM_DOTMATCH).should == true
- end
-
- it "matches multiple directories with ** and *" do
- files = '**/*.rb'
- File.send(@method, files, 'main.rb').should == false
- File.send(@method, files, './main.rb').should == false
- File.send(@method, files, 'lib/song.rb').should == true
- File.send(@method, '**.rb', 'main.rb').should == true
- File.send(@method, '**.rb', './main.rb').should == false
- File.send(@method, '**.rb', 'lib/song.rb').should == true
- File.send(@method, '*', 'dave/.profile').should == true
- end
-
- it "matches multiple directories with ** when flags includes File::FNM_PATHNAME" do
- files = '**/*.rb'
- flags = File::FNM_PATHNAME
-
- File.send(@method, files, 'main.rb', flags).should == true
- File.send(@method, files, 'one/two/three/main.rb', flags).should == true
- File.send(@method, files, './main.rb', flags).should == false
-
- flags = File::FNM_PATHNAME | File::FNM_DOTMATCH
-
- File.send(@method, files, './main.rb', flags).should == true
- File.send(@method, files, 'one/two/.main.rb', flags).should == true
-
- File.send(@method, "**/best/*", 'lib/my/best/song.rb').should == true
- end
-
- it "returns false if '/' in pattern do not match '/' in path when flags includes FNM_PATHNAME" do
- pattern = '*/*'
- File.send(@method, pattern, 'dave/.profile', File::FNM_PATHNAME).should be_false
-
- pattern = '**/foo'
- File.send(@method, pattern, 'a/.b/c/foo', File::FNM_PATHNAME).should be_false
- end
-
- it "returns true if '/' in pattern match '/' in path when flags includes FNM_PATHNAME" do
- pattern = '*/*'
- File.send(@method, pattern, 'dave/.profile', File::FNM_PATHNAME | File::FNM_DOTMATCH).should be_true
-
- pattern = '**/foo'
- File.send(@method, pattern, 'a/b/c/foo', File::FNM_PATHNAME).should be_true
- File.send(@method, pattern, '/a/b/c/foo', File::FNM_PATHNAME).should be_true
- File.send(@method, pattern, 'c:/a/b/c/foo', File::FNM_PATHNAME).should be_true
- 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
-
- it "raises a TypeError if the first and second arguments are not string-like" do
- -> { File.send(@method, nil, nil, 0, 0) }.should raise_error(ArgumentError)
- -> { File.send(@method, 1, 'some/thing') }.should raise_error(TypeError)
- -> { File.send(@method, 'some/thing', 1) }.should raise_error(TypeError)
- -> { File.send(@method, 1, 1) }.should raise_error(TypeError)
- end
-
- it "raises a TypeError if the third argument is not an Integer" do
- -> { File.send(@method, "*/place", "path/to/file", "flags") }.should raise_error(TypeError)
- -> { File.send(@method, "*/place", "path/to/file", nil) }.should raise_error(TypeError)
- end
-
- it "does not raise a TypeError if the third argument can be coerced to an Integer" do
- flags = mock("flags")
- flags.should_receive(:to_int).and_return(10)
- -> { File.send(@method, "*/place", "path/to/file", flags) }.should_not raise_error
- end
-
- it "matches multibyte characters" do
- File.fnmatch("*/ä/ø/ñ", "a/ä/ø/ñ").should == true
- end
-end
diff --git a/spec/ruby/core/file/shared/open.rb b/spec/ruby/core/file/shared/open.rb
index 677a82a351..67149235ca 100644
--- a/spec/ruby/core/file/shared/open.rb
+++ b/spec/ruby/core/file/shared/open.rb
@@ -4,7 +4,7 @@ describe :open_directory, shared: true do
it "opens directories" do
file = File.send(@method, tmp(""))
begin
- file.should be_kind_of(File)
+ file.should.is_a?(File)
ensure
file.close
end
diff --git a/spec/ruby/core/file/shared/path.rb b/spec/ruby/core/file/shared/path.rb
deleted file mode 100644
index 5a9fe1b0c5..0000000000
--- a/spec/ruby/core/file/shared/path.rb
+++ /dev/null
@@ -1,82 +0,0 @@
-describe :file_path, shared: true do
- before :each do
- @path = tmp("file_to_path")
- @name = File.basename(@path)
- touch @path
- end
-
- after :each do
- @file.close if @file and !@file.closed?
- rm_r @path
- end
-
- it "returns a String" do
- @file = File.new @path
- @file.send(@method).should be_an_instance_of(String)
- end
-
- it "returns a different String on every call" do
- @file = File.new @path
- path1 = @file.send(@method)
- path2 = @file.send(@method)
- path1.should == path2
- path1.should_not.equal?(path2)
- end
-
- it "returns a mutable String" do
- @file = File.new @path.dup.freeze
- path = @file.send(@method)
- path.should == @path
- path.should_not.frozen?
- path << "test"
- @file.send(@method).should == @path
- end
-
- it "calls to_str on argument and returns exact value" do
- path = mock('path')
- path.should_receive(:to_str).and_return(@path)
- @file = File.new path
- @file.send(@method).should == @path
- end
-
- it "does not normalise the path it returns" do
- Dir.chdir(tmp("")) do
- unorm = "./#{@name}"
- @file = File.new unorm
- @file.send(@method).should == unorm
- end
- end
-
- it "does not canonicalize the path it returns" do
- dir = File.basename tmp("")
- path = "#{tmp("")}../#{dir}/#{@name}"
- @file = File.new path
- @file.send(@method).should == path
- end
-
- it "does not absolute-ise the path it returns" do
- Dir.chdir(tmp("")) do
- @file = File.new @name
- @file.send(@method).should == @name
- end
- end
-
- it "preserves the encoding of the path" do
- path = @path.force_encoding("euc-jp")
- @file = File.new path
- @file.send(@method).encoding.should == Encoding.find("euc-jp")
- end
-
- platform_is :linux do
- guard -> { defined?(File::TMPFILE) } do
- before :each do
- @dir = tmp("tmpfilespec")
- mkdir_p @dir
- end
-
- after :each do
- rm_r @dir
- end
- end
- end
-end
diff --git a/spec/ruby/core/file/shared/read.rb b/spec/ruby/core/file/shared/read.rb
index f232235298..f60800bb2f 100644
--- a/spec/ruby/core/file/shared/read.rb
+++ b/spec/ruby/core/file/shared/read.rb
@@ -3,13 +3,13 @@ require_relative '../../dir/fixtures/common'
describe :file_read_directory, shared: true do
platform_is :darwin, :linux, :freebsd, :openbsd, :windows do
it "raises an Errno::EISDIR when passed a path that is a directory" do
- -> { @object.send(@method, ".") }.should raise_error(Errno::EISDIR)
+ -> { @object.send(@method, ".") }.should.raise(Errno::EISDIR)
end
end
platform_is :netbsd do
it "does not raises any exception when passed a path that is a directory" do
- -> { @object.send(@method, ".") }.should_not raise_error
+ -> { @object.send(@method, ".") }.should_not.raise
end
end
end
diff --git a/spec/ruby/core/file/shared/stat.rb b/spec/ruby/core/file/shared/stat.rb
index fdaf97ea61..879a7f11ff 100644
--- a/spec/ruby/core/file/shared/stat.rb
+++ b/spec/ruby/core/file/shared/stat.rb
@@ -10,13 +10,13 @@ describe :file_stat, shared: true do
it "returns a File::Stat object if the given file exists" do
st = File.send(@method, @file)
- st.should be_an_instance_of(File::Stat)
+ st.should.instance_of?(File::Stat)
end
it "returns a File::Stat object when called on an instance of File" do
File.open(@file) do |f|
st = f.send(@method)
- st.should be_an_instance_of(File::Stat)
+ st.should.instance_of?(File::Stat)
end
end
@@ -27,6 +27,6 @@ describe :file_stat, shared: true do
it "raises an Errno::ENOENT if the file does not exist" do
-> {
File.send(@method, "fake_file")
- }.should raise_error(Errno::ENOENT)
+ }.should.raise(Errno::ENOENT)
end
end
diff --git a/spec/ruby/core/file/shared/unlink.rb b/spec/ruby/core/file/shared/unlink.rb
deleted file mode 100644
index e339e93271..0000000000
--- a/spec/ruby/core/file/shared/unlink.rb
+++ /dev/null
@@ -1,61 +0,0 @@
-describe :file_unlink, shared: true do
- before :each do
- @file1 = tmp('test.txt')
- @file2 = tmp('test2.txt')
-
- touch @file1
- touch @file2
- end
-
- after :each do
- File.send(@method, @file1) if File.exist?(@file1)
- File.send(@method, @file2) if File.exist?(@file2)
-
- @file1 = nil
- @file2 = nil
- end
-
- it "returns 0 when called without arguments" do
- File.send(@method).should == 0
- end
-
- it "deletes a single file" do
- File.send(@method, @file1).should == 1
- File.should_not.exist?(@file1)
- end
-
- it "deletes multiple files" do
- File.send(@method, @file1, @file2).should == 2
- File.should_not.exist?(@file1)
- File.should_not.exist?(@file2)
- end
-
- it "raises a TypeError if not passed a String type" do
- -> { File.send(@method, 1) }.should raise_error(TypeError)
- end
-
- it "raises an Errno::ENOENT when the given file doesn't exist" do
- -> { File.send(@method, 'bogus') }.should raise_error(Errno::ENOENT)
- end
-
- it "coerces a given parameter into a string if possible" do
- mock = mock("to_str")
- mock.should_receive(:to_str).and_return(@file1)
- File.send(@method, mock).should == 1
- end
-
- it "accepts an object that has a #to_path method" do
- File.send(@method, mock_to_path(@file1)).should == 1
- end
-
- platform_is :windows do
- it "allows deleting an open file with File::SHARE_DELETE" do
- path = tmp("share_delete.txt")
- File.open(path, mode: File::CREAT | File::WRONLY | File::BINARY | File::SHARE_DELETE) do |f|
- File.should.exist?(path)
- File.send(@method, path)
- end
- File.should_not.exist?(path)
- end
- end
-end
diff --git a/spec/ruby/core/file/size_spec.rb b/spec/ruby/core/file/size_spec.rb
index 11d20cbacb..784c18c26e 100644
--- a/spec/ruby/core/file/size_spec.rb
+++ b/spec/ruby/core/file/size_spec.rb
@@ -56,11 +56,11 @@ describe "File#size" do
end
it "is an instance method" do
- @file.respond_to?(:size).should be_true
+ @file.respond_to?(:size).should == true
end
it "returns the file's size as an Integer" do
- @file.size.should be_an_instance_of(Integer)
+ @file.size.should.instance_of?(Integer)
end
it "returns the file's size in bytes" do
@@ -81,7 +81,7 @@ describe "File#size" do
it "raises an IOError on a closed file" do
@file.close
- -> { @file.size }.should raise_error(IOError)
+ -> { @file.size }.should.raise(IOError)
end
platform_is_not :windows do
diff --git a/spec/ruby/core/file/socket_spec.rb b/spec/ruby/core/file/socket_spec.rb
index 5d12e21f55..d3f4eb013a 100644
--- a/spec/ruby/core/file/socket_spec.rb
+++ b/spec/ruby/core/file/socket_spec.rb
@@ -1,42 +1,10 @@
require_relative '../../spec_helper'
require_relative '../../shared/file/socket'
-require 'socket'
describe "File.socket?" do
it_behaves_like :file_socket, :socket?, File
-end
-describe "File.socket?" do
it "returns false if file does not exist" do
File.socket?("I_am_a_bogus_file").should == false
end
-
- it "returns false if the file is not a socket" do
- filename = tmp("i_exist")
- touch(filename)
-
- File.socket?(filename).should == false
-
- rm_r filename
- end
-end
-
-platform_is_not :windows do
- describe "File.socket?" do
- before :each do
- # We need a really short name here.
- # On Linux the path length is limited to 107, see unix(7).
- @name = tmp("s")
- @server = UNIXServer.new @name
- end
-
- after :each do
- @server.close
- rm_r @name
- end
-
- it "returns true if the file is a socket" do
- File.socket?(@name).should == true
- end
- end
end
diff --git a/spec/ruby/core/file/split_spec.rb b/spec/ruby/core/file/split_spec.rb
index 7b958621b9..e989a6b86e 100644
--- a/spec/ruby/core/file/split_spec.rb
+++ b/spec/ruby/core/file/split_spec.rb
@@ -44,12 +44,12 @@ describe "File.split" do
end
it "raises an ArgumentError when not passed a single argument" do
- -> { File.split }.should raise_error(ArgumentError)
- -> { File.split('string', 'another string') }.should raise_error(ArgumentError)
+ -> { File.split }.should.raise(ArgumentError)
+ -> { File.split('string', 'another string') }.should.raise(ArgumentError)
end
it "raises a TypeError if the argument is not a String type" do
- -> { File.split(1) }.should raise_error(TypeError)
+ -> { File.split(1) }.should.raise(TypeError)
end
it "coerces the argument with to_str if it is not a String type" do
diff --git a/spec/ruby/core/file/stat/atime_spec.rb b/spec/ruby/core/file/stat/atime_spec.rb
index 9f1111ced1..2fecaed300 100644
--- a/spec/ruby/core/file/stat/atime_spec.rb
+++ b/spec/ruby/core/file/stat/atime_spec.rb
@@ -12,7 +12,7 @@ describe "File::Stat#atime" do
it "returns the atime of a File::Stat object" do
st = File.stat(@file)
- st.atime.should be_kind_of(Time)
+ st.atime.should.is_a?(Time)
st.atime.should <= Time.now
end
end
diff --git a/spec/ruby/core/file/stat/birthtime_spec.rb b/spec/ruby/core/file/stat/birthtime_spec.rb
index adecee15b0..728f635397 100644
--- a/spec/ruby/core/file/stat/birthtime_spec.rb
+++ b/spec/ruby/core/file/stat/birthtime_spec.rb
@@ -1,7 +1,7 @@
require_relative '../../../spec_helper'
platform_is(:windows, :darwin, :freebsd, :netbsd,
- *ruby_version_is("3.5") { :linux },
+ *ruby_version_is("4.0") { :linux },
) do
not_implemented_messages = [
"birthtime() function is unimplemented", # unsupported OS/version
@@ -20,7 +20,7 @@ platform_is(:windows, :darwin, :freebsd, :netbsd,
it "returns the birthtime of a File::Stat object" do
st = File.stat(@file)
- st.birthtime.should be_kind_of(Time)
+ st.birthtime.should.is_a?(Time)
st.birthtime.should <= Time.now
rescue NotImplementedError => e
e.message.should.start_with?(*not_implemented_messages)
diff --git a/spec/ruby/core/file/stat/blocks_spec.rb b/spec/ruby/core/file/stat/blocks_spec.rb
index f3f903d0f7..5e0efc8bc2 100644
--- a/spec/ruby/core/file/stat/blocks_spec.rb
+++ b/spec/ruby/core/file/stat/blocks_spec.rb
@@ -21,7 +21,7 @@ describe "File::Stat#blocks" do
platform_is :windows do
it "returns nil" do
st = File.stat(@file)
- st.blocks.should be_nil
+ st.blocks.should == nil
end
end
end
diff --git a/spec/ruby/core/file/stat/ctime_spec.rb b/spec/ruby/core/file/stat/ctime_spec.rb
index fd50487a0a..dbf43a7453 100644
--- a/spec/ruby/core/file/stat/ctime_spec.rb
+++ b/spec/ruby/core/file/stat/ctime_spec.rb
@@ -12,7 +12,7 @@ describe "File::Stat#ctime" do
it "returns the ctime of a File::Stat object" do
st = File.stat(@file)
- st.ctime.should be_kind_of(Time)
+ st.ctime.should.is_a?(Time)
st.ctime.should <= Time.now
end
end
diff --git a/spec/ruby/core/file/stat/dev_major_spec.rb b/spec/ruby/core/file/stat/dev_major_spec.rb
index 4966d609e2..a199eaaa11 100644
--- a/spec/ruby/core/file/stat/dev_major_spec.rb
+++ b/spec/ruby/core/file/stat/dev_major_spec.rb
@@ -11,13 +11,13 @@ describe "File::Stat#dev_major" do
platform_is_not :windows do
it "returns the major part of File::Stat#dev" do
- File.stat(@name).dev_major.should be_kind_of(Integer)
+ File.stat(@name).dev_major.should.is_a?(Integer)
end
end
platform_is :windows do
it "returns nil" do
- File.stat(@name).dev_major.should be_nil
+ File.stat(@name).dev_major.should == nil
end
end
end
diff --git a/spec/ruby/core/file/stat/dev_minor_spec.rb b/spec/ruby/core/file/stat/dev_minor_spec.rb
index ea79c12b99..8ce94778ca 100644
--- a/spec/ruby/core/file/stat/dev_minor_spec.rb
+++ b/spec/ruby/core/file/stat/dev_minor_spec.rb
@@ -11,13 +11,13 @@ describe "File::Stat#dev_minor" do
platform_is_not :windows do
it "returns the minor part of File::Stat#dev" do
- File.stat(@name).dev_minor.should be_kind_of(Integer)
+ File.stat(@name).dev_minor.should.is_a?(Integer)
end
end
platform_is :windows do
it "returns nil" do
- File.stat(@name).dev_minor.should be_nil
+ File.stat(@name).dev_minor.should == nil
end
end
end
diff --git a/spec/ruby/core/file/stat/dev_spec.rb b/spec/ruby/core/file/stat/dev_spec.rb
index e953fcaa58..cd5e3d175e 100644
--- a/spec/ruby/core/file/stat/dev_spec.rb
+++ b/spec/ruby/core/file/stat/dev_spec.rb
@@ -10,6 +10,6 @@ describe "File::Stat#dev" do
end
it "returns the number of the device on which the file exists" do
- File.stat(@name).dev.should be_kind_of(Integer)
+ File.stat(@name).dev.should.is_a?(Integer)
end
end
diff --git a/spec/ruby/core/file/stat/ftype_spec.rb b/spec/ruby/core/file/stat/ftype_spec.rb
index eb892eae5f..df2e3ada1e 100644
--- a/spec/ruby/core/file/stat/ftype_spec.rb
+++ b/spec/ruby/core/file/stat/ftype_spec.rb
@@ -8,7 +8,7 @@ describe "File::Stat#ftype" do
it "returns a String" do
FileSpecs.normal_file do |file|
- File.lstat(file).ftype.should be_kind_of(String)
+ File.lstat(file).ftype.should.is_a?(String)
end
end
diff --git a/spec/ruby/core/file/stat/ino_spec.rb b/spec/ruby/core/file/stat/ino_spec.rb
index 42370aecb7..c09b6448c7 100644
--- a/spec/ruby/core/file/stat/ino_spec.rb
+++ b/spec/ruby/core/file/stat/ino_spec.rb
@@ -13,7 +13,7 @@ describe "File::Stat#ino" do
platform_is_not :windows do
it "returns the ino of a File::Stat object" do
st = File.stat(@file)
- st.ino.should be_kind_of(Integer)
+ st.ino.should.is_a?(Integer)
st.ino.should > 0
end
end
@@ -21,7 +21,7 @@ describe "File::Stat#ino" do
platform_is :windows do
it "returns BY_HANDLE_FILE_INFORMATION.nFileIndexHigh/Low of a File::Stat object" do
st = File.stat(@file)
- st.ino.should be_kind_of(Integer)
+ st.ino.should.is_a?(Integer)
st.ino.should > 0
end
end
diff --git a/spec/ruby/core/file/stat/mtime_spec.rb b/spec/ruby/core/file/stat/mtime_spec.rb
index 08a2b83463..7844491212 100644
--- a/spec/ruby/core/file/stat/mtime_spec.rb
+++ b/spec/ruby/core/file/stat/mtime_spec.rb
@@ -12,7 +12,7 @@ describe "File::Stat#mtime" do
it "returns the mtime of a File::Stat object" do
st = File.stat(@file)
- st.mtime.should be_kind_of(Time)
+ st.mtime.should.is_a?(Time)
st.mtime.should <= Time.now
end
end
diff --git a/spec/ruby/core/file/stat/new_spec.rb b/spec/ruby/core/file/stat/new_spec.rb
index c0d9432ac8..b8c3600028 100644
--- a/spec/ruby/core/file/stat/new_spec.rb
+++ b/spec/ruby/core/file/stat/new_spec.rb
@@ -15,12 +15,12 @@ describe "File::Stat#initialize" do
it "raises an exception if the file doesn't exist" do
-> {
File::Stat.new(tmp("i_am_a_dummy_file_that_doesnt_exist"))
- }.should raise_error(Errno::ENOENT)
+ }.should.raise(Errno::ENOENT)
end
it "creates a File::Stat object for the given file" do
st = File::Stat.new(@file)
- st.should be_kind_of(File::Stat)
+ st.should.is_a?(File::Stat)
st.ftype.should == 'file'
end
diff --git a/spec/ruby/core/file/stat/rdev_major_spec.rb b/spec/ruby/core/file/stat/rdev_major_spec.rb
index e08d19c03a..e1b44fc2d0 100644
--- a/spec/ruby/core/file/stat/rdev_major_spec.rb
+++ b/spec/ruby/core/file/stat/rdev_major_spec.rb
@@ -12,13 +12,13 @@ describe "File::Stat#rdev_major" do
platform_is_not :windows do
it "returns the major part of File::Stat#rdev" do
- File.stat(@name).rdev_major.should be_kind_of(Integer)
+ File.stat(@name).rdev_major.should.is_a?(Integer)
end
end
platform_is :windows do
it "returns nil" do
- File.stat(@name).rdev_major.should be_nil
+ File.stat(@name).rdev_major.should == nil
end
end
end
diff --git a/spec/ruby/core/file/stat/rdev_minor_spec.rb b/spec/ruby/core/file/stat/rdev_minor_spec.rb
index ace5b8a732..8af3b9f587 100644
--- a/spec/ruby/core/file/stat/rdev_minor_spec.rb
+++ b/spec/ruby/core/file/stat/rdev_minor_spec.rb
@@ -12,13 +12,13 @@ describe "File::Stat#rdev_minor" do
platform_is_not :windows do
it "returns the minor part of File::Stat#rdev" do
- File.stat(@name).rdev_minor.should be_kind_of(Integer)
+ File.stat(@name).rdev_minor.should.is_a?(Integer)
end
end
platform_is :windows do
it "returns nil" do
- File.stat(@name).rdev_minor.should be_nil
+ File.stat(@name).rdev_minor.should == nil
end
end
end
diff --git a/spec/ruby/core/file/stat/rdev_spec.rb b/spec/ruby/core/file/stat/rdev_spec.rb
index 9e1aee692d..7e4252fcc6 100644
--- a/spec/ruby/core/file/stat/rdev_spec.rb
+++ b/spec/ruby/core/file/stat/rdev_spec.rb
@@ -10,6 +10,6 @@ describe "File::Stat#rdev" do
end
it "returns the number of the device this file represents which the file exists" do
- File.stat(@name).rdev.should be_kind_of(Integer)
+ File.stat(@name).rdev.should.is_a?(Integer)
end
end
diff --git a/spec/ruby/core/file/stat_spec.rb b/spec/ruby/core/file/stat_spec.rb
index 6365500057..d5238b6331 100644
--- a/spec/ruby/core/file/stat_spec.rb
+++ b/spec/ruby/core/file/stat_spec.rb
@@ -28,9 +28,9 @@ platform_is_not :windows do
st.size.should == 8
st.size?.should == 8
st.blksize.should >= 0
- st.atime.should be_kind_of(Time)
- st.ctime.should be_kind_of(Time)
- st.mtime.should be_kind_of(Time)
+ st.atime.should.is_a?(Time)
+ st.ctime.should.is_a?(Time)
+ st.mtime.should.is_a?(Time)
end
end
@@ -46,9 +46,9 @@ platform_is_not :windows do
missing_path = "/missingfilepath\xE3E4".b
-> {
File.stat(missing_path)
- }.should raise_error(SystemCallError) { |e|
- [Errno::ENOENT, Errno::EILSEQ].should include(e.class)
- e.message.should include(missing_path)
+ }.should.raise(SystemCallError) { |e|
+ [Errno::ENOENT, Errno::EILSEQ].should.include?(e.class)
+ e.message.should.include?(missing_path)
}
end
end
diff --git a/spec/ruby/core/file/sticky_spec.rb b/spec/ruby/core/file/sticky_spec.rb
index 5f7b2d93eb..782541abf3 100644
--- a/spec/ruby/core/file/sticky_spec.rb
+++ b/spec/ruby/core/file/sticky_spec.rb
@@ -41,7 +41,7 @@ describe "File.sticky?" do
touch(filename)
stat = File.stat(filename)
mode = stat.mode
- raise_error(Errno::EFTYPE){File.chmod(mode|01000, filename)}
+ -> { File.chmod(mode|01000, filename) }.should.raise(Errno::EFTYPE)
File.sticky?(filename).should == false
rm_r filename
diff --git a/spec/ruby/core/file/symlink_spec.rb b/spec/ruby/core/file/symlink_spec.rb
index 0e8b0a5a20..4ceeb28c84 100644
--- a/spec/ruby/core/file/symlink_spec.rb
+++ b/spec/ruby/core/file/symlink_spec.rb
@@ -32,18 +32,18 @@ describe "File.symlink" do
it "raises an Errno::EEXIST if the target already exists" do
File.symlink(@file, @link)
- -> { File.symlink(@file, @link) }.should raise_error(Errno::EEXIST)
+ -> { File.symlink(@file, @link) }.should.raise(Errno::EEXIST)
end
it "raises an ArgumentError if not called with two arguments" do
- -> { File.symlink }.should raise_error(ArgumentError)
- -> { File.symlink(@file) }.should raise_error(ArgumentError)
+ -> { File.symlink }.should.raise(ArgumentError)
+ -> { File.symlink(@file) }.should.raise(ArgumentError)
end
it "raises a TypeError if not called with String types" do
- -> { File.symlink(@file, nil) }.should raise_error(TypeError)
- -> { File.symlink(@file, 1) }.should raise_error(TypeError)
- -> { File.symlink(1, 1) }.should raise_error(TypeError)
+ -> { File.symlink(@file, nil) }.should.raise(TypeError)
+ -> { File.symlink(@file, 1) }.should.raise(TypeError)
+ -> { File.symlink(1, 1) }.should.raise(TypeError)
end
end
end
diff --git a/spec/ruby/core/file/to_path_spec.rb b/spec/ruby/core/file/to_path_spec.rb
index 6d168a065c..b968d3b2b9 100644
--- a/spec/ruby/core/file/to_path_spec.rb
+++ b/spec/ruby/core/file/to_path_spec.rb
@@ -1,6 +1,84 @@
require_relative '../../spec_helper'
-require_relative 'shared/path'
describe "File#to_path" do
- it_behaves_like :file_path, :to_path
+ before :each do
+ @path = tmp("file_to_path")
+ @name = File.basename(@path)
+ touch @path
+ end
+
+ after :each do
+ @file.close if @file and !@file.closed?
+ rm_r @path
+ end
+
+ it "returns a String" do
+ @file = File.new @path
+ @file.to_path.should.instance_of?(String)
+ end
+
+ it "returns a different String on every call" do
+ @file = File.new @path
+ path1 = @file.to_path
+ path2 = @file.to_path
+ path1.should == path2
+ path1.should_not.equal?(path2)
+ end
+
+ it "returns a mutable String" do
+ @file = File.new @path.dup.freeze
+ path = @file.to_path
+ path.should == @path
+ path.should_not.frozen?
+ path << "test"
+ @file.to_path.should == @path
+ end
+
+ it "calls to_str on argument and returns exact value" do
+ path = mock('path')
+ path.should_receive(:to_str).and_return(@path)
+ @file = File.new path
+ @file.to_path.should == @path
+ end
+
+ it "does not normalise the path it returns" do
+ Dir.chdir(tmp("")) do
+ unorm = "./#{@name}"
+ @file = File.new unorm
+ @file.to_path.should == unorm
+ end
+ end
+
+ it "does not canonicalize the path it returns" do
+ dir = File.basename tmp("")
+ path = "#{tmp("")}../#{dir}/#{@name}"
+ @file = File.new path
+ @file.to_path.should == path
+ end
+
+ it "does not absolute-ise the path it returns" do
+ Dir.chdir(tmp("")) do
+ @file = File.new @name
+ @file.to_path.should == @name
+ end
+ end
+
+ it "preserves the encoding of the path" do
+ path = @path.force_encoding("euc-jp")
+ @file = File.new path
+ @file.to_path.encoding.should == Encoding.find("euc-jp")
+ end
+
+ platform_is :linux do
+ guard -> { defined?(File::TMPFILE) } do
+ before :each do
+ @dir = tmp("tmpfilespec")
+ mkdir_p @dir
+ end
+
+ after :each do
+ rm_r @dir
+ end
+ end
+ end
end
diff --git a/spec/ruby/core/file/truncate_spec.rb b/spec/ruby/core/file/truncate_spec.rb
index b4a2e3e577..5f37f34155 100644
--- a/spec/ruby/core/file/truncate_spec.rb
+++ b/spec/ruby/core/file/truncate_spec.rb
@@ -54,29 +54,29 @@ describe "File.truncate" do
rm_r not_existing_file
begin
- -> { File.truncate(not_existing_file, 5) }.should raise_error(Errno::ENOENT)
+ -> { File.truncate(not_existing_file, 5) }.should.raise(Errno::ENOENT)
ensure
rm_r not_existing_file
end
end
it "raises an ArgumentError if not passed two arguments" do
- -> { File.truncate }.should raise_error(ArgumentError)
- -> { File.truncate(@name) }.should raise_error(ArgumentError)
+ -> { File.truncate }.should.raise(ArgumentError)
+ -> { File.truncate(@name) }.should.raise(ArgumentError)
end
platform_is_not :netbsd, :openbsd do
it "raises an Errno::EINVAL if the length argument is not valid" do
- -> { File.truncate(@name, -1) }.should raise_error(Errno::EINVAL) # May fail
+ -> { File.truncate(@name, -1) }.should.raise(Errno::EINVAL) # May fail
end
end
it "raises a TypeError if not passed a String type for the first argument" do
- -> { File.truncate(1, 1) }.should raise_error(TypeError)
+ -> { File.truncate(1, 1) }.should.raise(TypeError)
end
it "raises a TypeError if not passed an Integer type for the second argument" do
- -> { File.truncate(@name, nil) }.should raise_error(TypeError)
+ -> { File.truncate(@name, nil) }.should.raise(TypeError)
end
it "accepts an object that has a #to_path method" do
@@ -149,29 +149,29 @@ describe "File#truncate" do
end
it "raises an ArgumentError if not passed one argument" do
- -> { @file.truncate }.should raise_error(ArgumentError)
- -> { @file.truncate(1) }.should_not raise_error(ArgumentError)
+ -> { @file.truncate }.should.raise(ArgumentError)
+ -> { @file.truncate(1) }.should_not.raise(ArgumentError)
end
platform_is_not :netbsd do
it "raises an Errno::EINVAL if the length argument is not valid" do
- -> { @file.truncate(-1) }.should raise_error(Errno::EINVAL) # May fail
+ -> { @file.truncate(-1) }.should.raise(Errno::EINVAL) # May fail
end
end
it "raises an IOError if file is closed" do
@file.close
@file.should.closed?
- -> { @file.truncate(42) }.should raise_error(IOError)
+ -> { @file.truncate(42) }.should.raise(IOError)
end
it "raises an IOError if file is not opened for writing" do
File.open(@name, 'r') do |file|
- -> { file.truncate(42) }.should raise_error(IOError)
+ -> { file.truncate(42) }.should.raise(IOError)
end
end
it "raises a TypeError if not passed an Integer type for the for the argument" do
- -> { @file.truncate(nil) }.should raise_error(TypeError)
+ -> { @file.truncate(nil) }.should.raise(TypeError)
end
end
diff --git a/spec/ruby/core/file/umask_spec.rb b/spec/ruby/core/file/umask_spec.rb
index 7f7e40abbc..fea8cf7633 100644
--- a/spec/ruby/core/file/umask_spec.rb
+++ b/spec/ruby/core/file/umask_spec.rb
@@ -13,7 +13,7 @@ describe "File.umask" do
end
it "returns an Integer" do
- File.umask.should be_kind_of(Integer)
+ File.umask.should.is_a?(Integer)
end
platform_is_not :windows do
@@ -47,11 +47,11 @@ describe "File.umask" do
end
it "raises RangeError with too large values" do
- -> { File.umask(2**64) }.should raise_error(RangeError)
- -> { File.umask(-2**63 - 1) }.should raise_error(RangeError)
+ -> { File.umask(2**64) }.should.raise(RangeError)
+ -> { File.umask(-2**63 - 1) }.should.raise(RangeError)
end
it "raises ArgumentError when more than one argument is provided" do
- -> { File.umask(022, 022) }.should raise_error(ArgumentError)
+ -> { File.umask(022, 022) }.should.raise(ArgumentError)
end
end
diff --git a/spec/ruby/core/file/unlink_spec.rb b/spec/ruby/core/file/unlink_spec.rb
index 28872d55ed..db0c08f3ae 100644
--- a/spec/ruby/core/file/unlink_spec.rb
+++ b/spec/ruby/core/file/unlink_spec.rb
@@ -1,6 +1,7 @@
require_relative '../../spec_helper'
-require_relative 'shared/unlink'
describe "File.unlink" do
- it_behaves_like :file_unlink, :unlink
+ it "is an alias of File.delete" do
+ File.method(:unlink).should == File.method(:delete)
+ end
end
diff --git a/spec/ruby/core/file/world_readable_spec.rb b/spec/ruby/core/file/world_readable_spec.rb
index 11b8e67d0b..0f5e0b13d7 100644
--- a/spec/ruby/core/file/world_readable_spec.rb
+++ b/spec/ruby/core/file/world_readable_spec.rb
@@ -7,6 +7,6 @@ describe "File.world_readable?" do
it "returns nil if the file does not exist" do
file = rand.to_s + $$.to_s
File.should_not.exist?(file)
- File.world_readable?(file).should be_nil
+ File.world_readable?(file).should == nil
end
end
diff --git a/spec/ruby/core/file/world_writable_spec.rb b/spec/ruby/core/file/world_writable_spec.rb
index d378cf2eb9..46ba6832f9 100644
--- a/spec/ruby/core/file/world_writable_spec.rb
+++ b/spec/ruby/core/file/world_writable_spec.rb
@@ -7,6 +7,6 @@ describe "File.world_writable?" do
it "returns nil if the file does not exist" do
file = rand.to_s + $$.to_s
File.should_not.exist?(file)
- File.world_writable?(file).should be_nil
+ File.world_writable?(file).should == nil
end
end
diff --git a/spec/ruby/core/file/zero_spec.rb b/spec/ruby/core/file/zero_spec.rb
index 01c7505ef2..09b0decf48 100644
--- a/spec/ruby/core/file/zero_spec.rb
+++ b/spec/ruby/core/file/zero_spec.rb
@@ -1,7 +1,7 @@
require_relative '../../spec_helper'
-require_relative '../../shared/file/zero'
describe "File.zero?" do
- it_behaves_like :file_zero, :zero?, File
- it_behaves_like :file_zero_missing, :zero?, File
+ it "is an alias of File.empty?" do
+ File.method(:zero?).should == File.method(:empty?)
+ end
end
diff --git a/spec/ruby/core/filetest/empty_spec.rb b/spec/ruby/core/filetest/empty_spec.rb
new file mode 100644
index 0000000000..2c7fbe0dcd
--- /dev/null
+++ b/spec/ruby/core/filetest/empty_spec.rb
@@ -0,0 +1,7 @@
+require_relative '../../spec_helper'
+require_relative '../../shared/file/zero'
+
+describe "FileTest.empty?" do
+ it_behaves_like :file_zero, :empty?, FileTest
+ it_behaves_like :file_zero_missing, :empty?, FileTest
+end
diff --git a/spec/ruby/core/filetest/grpowned_spec.rb b/spec/ruby/core/filetest/grpowned_spec.rb
index d073cb9770..d6bd6abd71 100644
--- a/spec/ruby/core/filetest/grpowned_spec.rb
+++ b/spec/ruby/core/filetest/grpowned_spec.rb
@@ -5,6 +5,6 @@ describe "FileTest.grpowned?" do
it_behaves_like :file_grpowned, :grpowned?, FileTest
it "returns false if the file doesn't exist" do
- FileTest.grpowned?("xxx-tmp-doesnt_exist-blah").should be_false
+ FileTest.grpowned?("xxx-tmp-doesnt_exist-blah").should == false
end
end
diff --git a/spec/ruby/core/filetest/socket_spec.rb b/spec/ruby/core/filetest/socket_spec.rb
index 63a6a31ecb..f274be6318 100644
--- a/spec/ruby/core/filetest/socket_spec.rb
+++ b/spec/ruby/core/filetest/socket_spec.rb
@@ -3,4 +3,8 @@ require_relative '../../shared/file/socket'
describe "FileTest.socket?" do
it_behaves_like :file_socket, :socket?, FileTest
+
+ it "returns false if file does not exist" do
+ FileTest.socket?("I_am_a_bogus_file").should == false
+ end
end
diff --git a/spec/ruby/core/filetest/zero_spec.rb b/spec/ruby/core/filetest/zero_spec.rb
index 92cab67f1b..de024c25ff 100644
--- a/spec/ruby/core/filetest/zero_spec.rb
+++ b/spec/ruby/core/filetest/zero_spec.rb
@@ -1,7 +1,7 @@
require_relative '../../spec_helper'
-require_relative '../../shared/file/zero'
describe "FileTest.zero?" do
- it_behaves_like :file_zero, :zero?, FileTest
- it_behaves_like :file_zero_missing, :zero?, FileTest
+ it "is an alias of FileTest.empty?" do
+ FileTest.method(:zero?).should == FileTest.method(:empty?)
+ end
end
diff --git a/spec/ruby/core/float/angle_spec.rb b/spec/ruby/core/float/angle_spec.rb
index c07249aa97..ac182c5b73 100644
--- a/spec/ruby/core/float/angle_spec.rb
+++ b/spec/ruby/core/float/angle_spec.rb
@@ -1,6 +1,7 @@
require_relative '../../spec_helper'
-require_relative 'shared/arg'
describe "Float#angle" do
- it_behaves_like :float_arg, :angle
+ it "is an alias of Float#arg" do
+ Float.instance_method(:angle).should == Float.instance_method(:arg)
+ end
end
diff --git a/spec/ruby/core/float/arg_spec.rb b/spec/ruby/core/float/arg_spec.rb
index d3a50668f8..c9c602bbf6 100644
--- a/spec/ruby/core/float/arg_spec.rb
+++ b/spec/ruby/core/float/arg_spec.rb
@@ -1,6 +1,38 @@
require_relative '../../spec_helper'
-require_relative 'shared/arg'
describe "Float#arg" do
- it_behaves_like :float_arg, :arg
+ it "returns NaN if NaN" do
+ f = nan_value
+ f.arg.nan?.should == true
+ end
+
+ it "returns self if NaN" do
+ f = nan_value
+ f.arg.should.equal?(f)
+ end
+
+ it "returns 0 if positive" do
+ 1.0.arg.should == 0
+ end
+
+ it "returns 0 if +0.0" do
+ 0.0.arg.should == 0
+ end
+
+ it "returns 0 if +Infinity" do
+ infinity_value.arg.should == 0
+ end
+
+ it "returns Pi if negative" do
+ (-1.0).arg.should == Math::PI
+ end
+
+ # This was established in r23960
+ it "returns Pi if -0.0" do
+ (-0.0).arg.should == Math::PI
+ end
+
+ it "returns Pi if -Infinity" do
+ (-infinity_value).arg.should == Math::PI
+ end
end
diff --git a/spec/ruby/core/float/case_compare_spec.rb b/spec/ruby/core/float/case_compare_spec.rb
index b902fbea18..c82803642d 100644
--- a/spec/ruby/core/float/case_compare_spec.rb
+++ b/spec/ruby/core/float/case_compare_spec.rb
@@ -1,6 +1,7 @@
require_relative '../../spec_helper'
-require_relative 'shared/equal'
describe "Float#===" do
- it_behaves_like :float_equal, :===
+ it "is an alias of Float#==" do
+ Float.instance_method(:===).should == Float.instance_method(:==)
+ end
end
diff --git a/spec/ruby/core/float/ceil_spec.rb b/spec/ruby/core/float/ceil_spec.rb
index 75f5610292..efd1e6feb2 100644
--- a/spec/ruby/core/float/ceil_spec.rb
+++ b/spec/ruby/core/float/ceil_spec.rb
@@ -2,25 +2,27 @@ require_relative '../../spec_helper'
require_relative '../integer/shared/integer_ceil_precision'
describe "Float#ceil" do
- context "with precision" do
+ context "with values equal to integers" do
it_behaves_like :integer_ceil_precision, :Float
end
it "returns the smallest Integer greater than or equal to self" do
- -1.2.ceil.should eql( -1)
- -1.0.ceil.should eql( -1)
- 0.0.ceil.should eql( 0 )
- 1.3.ceil.should eql( 2 )
- 3.0.ceil.should eql( 3 )
- -9223372036854775808.1.ceil.should eql(-9223372036854775808)
- +9223372036854775808.1.ceil.should eql(+9223372036854775808)
+ -1.2.ceil.should.eql?( -1)
+ -1.0.ceil.should.eql?( -1)
+ 0.0.ceil.should.eql?( 0 )
+ 1.3.ceil.should.eql?( 2 )
+ 3.0.ceil.should.eql?( 3 )
+ -9223372036854775808.1.ceil.should.eql?(-9223372036854775808)
+ +9223372036854775808.1.ceil.should.eql?(+9223372036854775808)
end
it "returns the smallest number greater than or equal to self with an optionally given precision" do
- 2.1679.ceil(0).should eql(3)
- 214.94.ceil(-1).should eql(220)
- 7.0.ceil(1).should eql(7.0)
- -1.234.ceil(2).should eql(-1.23)
- 5.123812.ceil(4).should eql(5.1239)
+ 2.1679.ceil(0).should.eql?(3)
+ 214.94.ceil(-1).should.eql?(220)
+ 7.0.ceil(1).should.eql?(7.0)
+ 200.0.ceil(-2).should.eql?(200)
+ -1.234.ceil(2).should.eql?(-1.23)
+ 5.123812.ceil(4).should.eql?(5.1239)
+ 10.00001.ceil(5).should.eql?(10.00001)
end
end
diff --git a/spec/ruby/core/float/comparison_spec.rb b/spec/ruby/core/float/comparison_spec.rb
index 0cd290f4ad..e9adf2fd6a 100644
--- a/spec/ruby/core/float/comparison_spec.rb
+++ b/spec/ruby/core/float/comparison_spec.rb
@@ -29,10 +29,10 @@ describe "Float#<=>" do
end
it "returns nil when the given argument is not a Float" do
- (1.0 <=> "1").should be_nil
- (1.0 <=> "1".freeze).should be_nil
- (1.0 <=> :one).should be_nil
- (1.0 <=> true).should be_nil
+ (1.0 <=> "1").should == nil
+ (1.0 <=> "1".freeze).should == nil
+ (1.0 <=> :one).should == nil
+ (1.0 <=> true).should == nil
end
it "compares using #coerce when argument is not a Float" do
@@ -62,7 +62,7 @@ describe "Float#<=>" do
bad_coercible = klass.new
-> {
4.2 <=> bad_coercible
- }.should raise_error(TypeError, "coerce must return [x, y]")
+ }.should.raise(TypeError, "coerce must return [x, y]")
end
it "returns the correct result when one side is infinite" do
diff --git a/spec/ruby/core/float/constants_spec.rb b/spec/ruby/core/float/constants_spec.rb
index 497e0ae188..1b71ee8adf 100644
--- a/spec/ruby/core/float/constants_spec.rb
+++ b/spec/ruby/core/float/constants_spec.rb
@@ -50,6 +50,6 @@ describe "Float constant" do
end
it "NAN is 'not a number'" do
- Float::NAN.nan?.should be_true
+ Float::NAN.nan?.should == true
end
end
diff --git a/spec/ruby/core/float/denominator_spec.rb b/spec/ruby/core/float/denominator_spec.rb
index 6f4fcfcf23..85beaa98cd 100644
--- a/spec/ruby/core/float/denominator_spec.rb
+++ b/spec/ruby/core/float/denominator_spec.rb
@@ -12,7 +12,7 @@ describe "Float#denominator" do
it "returns an Integer" do
@numbers.each do |number|
- number.denominator.should be_kind_of(Integer)
+ number.denominator.should.is_a?(Integer)
end
end
diff --git a/spec/ruby/core/float/divide_spec.rb b/spec/ruby/core/float/divide_spec.rb
index 72ab7527bd..68a2c550a7 100644
--- a/spec/ruby/core/float/divide_spec.rb
+++ b/spec/ruby/core/float/divide_spec.rb
@@ -16,25 +16,25 @@ describe "Float#/" do
end
it "returns +Infinity when dividing non-zero by zero of the same sign" do
- (1.0 / 0.0).should be_positive_infinity
- (-1.0 / -0.0).should be_positive_infinity
+ (1.0 / 0.0).should.infinite? == 1
+ (-1.0 / -0.0).should.infinite? == 1
end
it "returns -Infinity when dividing non-zero by zero of opposite sign" do
- (-1.0 / 0.0).should be_negative_infinity
- (1.0 / -0.0).should be_negative_infinity
+ (-1.0 / 0.0).should.infinite? == -1
+ (1.0 / -0.0).should.infinite? == -1
end
it "returns NaN when dividing zero by zero" do
- (0.0 / 0.0).should be_nan
- (-0.0 / 0.0).should be_nan
- (0.0 / -0.0).should be_nan
- (-0.0 / -0.0).should be_nan
+ (0.0 / 0.0).should.nan?
+ (-0.0 / 0.0).should.nan?
+ (0.0 / -0.0).should.nan?
+ (-0.0 / -0.0).should.nan?
end
it "raises a TypeError when given a non-Numeric" do
- -> { 13.0 / "10" }.should raise_error(TypeError)
- -> { 13.0 / :symbol }.should raise_error(TypeError)
+ -> { 13.0 / "10" }.should.raise(TypeError)
+ -> { 13.0 / :symbol }.should.raise(TypeError)
end
it "divides correctly by Rational numbers" do
diff --git a/spec/ruby/core/float/divmod_spec.rb b/spec/ruby/core/float/divmod_spec.rb
index dad45a9b89..7ed6cd3487 100644
--- a/spec/ruby/core/float/divmod_spec.rb
+++ b/spec/ruby/core/float/divmod_spec.rb
@@ -3,41 +3,41 @@ require_relative '../../spec_helper'
describe "Float#divmod" do
it "returns an [quotient, modulus] from dividing self by other" do
values = 3.14.divmod(2)
- values[0].should eql(1)
+ values[0].should.eql?(1)
values[1].should be_close(1.14, TOLERANCE)
values = 2.8284.divmod(3.1415)
- values[0].should eql(0)
+ values[0].should.eql?(0)
values[1].should be_close(2.8284, TOLERANCE)
values = -1.0.divmod(bignum_value)
- values[0].should eql(-1)
+ values[0].should.eql?(-1)
values[1].should be_close(18446744073709551616.0, TOLERANCE)
values = -1.0.divmod(1)
- values[0].should eql(-1)
- values[1].should eql(0.0)
+ values[0].should.eql?(-1)
+ values[1].should.eql?(0.0)
end
# Behaviour established as correct in r23953
it "raises a FloatDomainError if self is NaN" do
- -> { nan_value.divmod(1) }.should raise_error(FloatDomainError)
+ -> { nan_value.divmod(1) }.should.raise(FloatDomainError)
end
# Behaviour established as correct in r23953
it "raises a FloatDomainError if other is NaN" do
- -> { 1.0.divmod(nan_value) }.should raise_error(FloatDomainError)
+ -> { 1.0.divmod(nan_value) }.should.raise(FloatDomainError)
end
# Behaviour established as correct in r23953
it "raises a FloatDomainError if self is Infinity" do
- -> { infinity_value.divmod(1) }.should raise_error(FloatDomainError)
+ -> { infinity_value.divmod(1) }.should.raise(FloatDomainError)
end
it "raises a ZeroDivisionError if other is zero" do
- -> { 1.0.divmod(0) }.should raise_error(ZeroDivisionError)
- -> { 1.0.divmod(0.0) }.should raise_error(ZeroDivisionError)
+ -> { 1.0.divmod(0) }.should.raise(ZeroDivisionError)
+ -> { 1.0.divmod(0.0) }.should.raise(ZeroDivisionError)
end
# redmine #5276"
it "returns the correct [quotient, modulus] even for large quotient" do
- 0.59.divmod(7.761021455128987e-11).first.should eql(7602092113)
+ 0.59.divmod(7.761021455128987e-11).first.should.eql?(7602092113)
end
end
diff --git a/spec/ruby/core/float/dup_spec.rb b/spec/ruby/core/float/dup_spec.rb
index 294da8e2bc..b474e21325 100644
--- a/spec/ruby/core/float/dup_spec.rb
+++ b/spec/ruby/core/float/dup_spec.rb
@@ -3,6 +3,6 @@ require_relative '../../spec_helper'
describe "Float#dup" do
it "returns self" do
float = 2.4
- float.dup.should equal(float)
+ float.dup.should.equal?(float)
end
end
diff --git a/spec/ruby/core/float/eql_spec.rb b/spec/ruby/core/float/eql_spec.rb
index 6b5f91db33..cf1ad8416f 100644
--- a/spec/ruby/core/float/eql_spec.rb
+++ b/spec/ruby/core/float/eql_spec.rb
@@ -2,15 +2,15 @@ require_relative '../../spec_helper'
describe "Float#eql?" do
it "returns true if other is a Float equal to self" do
- 0.0.eql?(0.0).should be_true
+ 0.0.eql?(0.0).should == true
end
it "returns false if other is a Float not equal to self" do
- 1.0.eql?(1.1).should be_false
+ 1.0.eql?(1.1).should == false
end
it "returns false if other is not a Float" do
- 1.0.eql?(1).should be_false
- 1.0.eql?(:one).should be_false
+ 1.0.eql?(1).should == false
+ 1.0.eql?(:one).should == false
end
end
diff --git a/spec/ruby/core/float/equal_value_spec.rb b/spec/ruby/core/float/equal_value_spec.rb
index 03eea5108e..37d0e162d3 100644
--- a/spec/ruby/core/float/equal_value_spec.rb
+++ b/spec/ruby/core/float/equal_value_spec.rb
@@ -1,6 +1,40 @@
require_relative '../../spec_helper'
-require_relative 'shared/equal'
describe "Float#==" do
- it_behaves_like :float_equal, :==
+ it "returns true if self has the same value as other" do
+ (1.0 == 1).should == true
+ (2.71828 == 1.428).should == false
+ (-4.2 == 4.2).should == false
+ end
+
+ it "calls 'other == self' if coercion fails" do
+ x = mock('other')
+ def x.==(other)
+ 2.0 == other
+ end
+
+ (1.0 == x).should == false
+ (2.0 == x).should == true
+ end
+
+ it "returns false if one side is NaN" do
+ [1.0, 42, bignum_value].each { |n|
+ (nan_value == n).should == false
+ (n == nan_value).should == false
+ }
+ end
+
+ it "handles positive infinity" do
+ [1.0, 42, bignum_value].each { |n|
+ (infinity_value == n).should == false
+ (n == infinity_value).should == false
+ }
+ end
+
+ it "handles negative infinity" do
+ [1.0, 42, bignum_value].each { |n|
+ ((-infinity_value) == n).should == false
+ (n == -infinity_value).should == false
+ }
+ end
end
diff --git a/spec/ruby/core/float/fdiv_spec.rb b/spec/ruby/core/float/fdiv_spec.rb
index be25ee283b..8a3ead4880 100644
--- a/spec/ruby/core/float/fdiv_spec.rb
+++ b/spec/ruby/core/float/fdiv_spec.rb
@@ -1,6 +1,61 @@
require_relative '../../spec_helper'
-require_relative 'shared/quo'
describe "Float#fdiv" do
- it_behaves_like :float_quo, :fdiv
+ it "performs floating-point division between self and an Integer" do
+ 8.9.fdiv(7).should == 1.2714285714285716
+ end
+
+ it "performs floating-point division between self and an Integer" do
+ 8.9.fdiv(9999999999999**9).should == 8.900000000008011e-117
+ end
+
+ it "performs floating-point division between self and a Float" do
+ 2827.22.fdiv(872.111111).should == 3.2418116961704433
+ end
+
+ it "returns NaN when the argument is NaN" do
+ -1819.999999.fdiv(nan_value).nan?.should == true
+ 11109.1981271.fdiv(nan_value).nan?.should == true
+ end
+
+ it "returns Infinity when the argument is 0.0" do
+ 2827.22.fdiv(0.0).infinite?.should == 1
+ end
+
+ it "returns -Infinity when the argument is 0.0 and self is negative" do
+ -48229.282.fdiv(0.0).infinite?.should == -1
+ end
+
+ it "returns Infinity when the argument is 0" do
+ 2827.22.fdiv(0).infinite?.should == 1
+ end
+
+ it "returns -Infinity when the argument is 0 and self is negative" do
+ -48229.282.fdiv(0).infinite?.should == -1
+ end
+
+ it "returns 0.0 when the argument is Infinity" do
+ 47292.2821.fdiv(infinity_value).should == 0.0
+ end
+
+ it "returns -0.0 when the argument is -Infinity" do
+ 1.9999918.fdiv(-infinity_value).should == -0.0
+ end
+
+ it "performs floating-point division between self and a Rational" do
+ 74620.09.fdiv(Rational(2,3)).should == 111930.135
+ end
+
+ it "performs floating-point division between self and a Complex" do
+ 74620.09.fdiv(Complex(8,2)).should == Complex(
+ 8778.834117647059, -2194.7085294117646)
+ end
+
+ it "raises a TypeError when argument isn't numeric" do
+ -> { 27292.2.fdiv(mock('non-numeric')) }.should.raise(TypeError)
+ end
+
+ it "raises an ArgumentError when passed multiple arguments" do
+ -> { 272.221.fdiv(6,0.2) }.should.raise(ArgumentError)
+ end
end
diff --git a/spec/ruby/core/float/float_spec.rb b/spec/ruby/core/float/float_spec.rb
index 263ae82079..46b2eff372 100644
--- a/spec/ruby/core/float/float_spec.rb
+++ b/spec/ruby/core/float/float_spec.rb
@@ -8,12 +8,12 @@ describe "Float" do
it ".allocate raises a TypeError" do
-> do
Float.allocate
- end.should raise_error(TypeError)
+ end.should.raise(TypeError)
end
it ".new is undefined" do
-> do
Float.new
- end.should raise_error(NoMethodError)
+ end.should.raise(NoMethodError)
end
end
diff --git a/spec/ruby/core/float/floor_spec.rb b/spec/ruby/core/float/floor_spec.rb
index 8b492ef473..f77300eb04 100644
--- a/spec/ruby/core/float/floor_spec.rb
+++ b/spec/ruby/core/float/floor_spec.rb
@@ -2,25 +2,27 @@ require_relative '../../spec_helper'
require_relative '../integer/shared/integer_floor_precision'
describe "Float#floor" do
- context "with precision" do
+ context "with values equal to integers" do
it_behaves_like :integer_floor_precision, :Float
end
it "returns the largest Integer less than or equal to self" do
- -1.2.floor.should eql( -2)
- -1.0.floor.should eql( -1)
- 0.0.floor.should eql( 0 )
- 1.0.floor.should eql( 1 )
- 5.9.floor.should eql( 5 )
- -9223372036854775808.1.floor.should eql(-9223372036854775808)
- +9223372036854775808.1.floor.should eql(+9223372036854775808)
+ -1.2.floor.should.eql?( -2)
+ -1.0.floor.should.eql?( -1)
+ 0.0.floor.should.eql?( 0 )
+ 1.0.floor.should.eql?( 1 )
+ 5.9.floor.should.eql?( 5 )
+ -9223372036854775808.1.floor.should.eql?(-9223372036854775808)
+ +9223372036854775808.1.floor.should.eql?(+9223372036854775808)
end
it "returns the largest number less than or equal to self with an optionally given precision" do
- 2.1679.floor(0).should eql(2)
- 214.94.floor(-1).should eql(210)
- 7.0.floor(1).should eql(7.0)
- -1.234.floor(2).should eql(-1.24)
- 5.123812.floor(4).should eql(5.1238)
+ 2.1679.floor(0).should.eql?(2)
+ 214.94.floor(-1).should.eql?(210)
+ 7.0.floor(1).should.eql?(7.0)
+ 200.0.floor(-2).should.eql?(200)
+ -1.234.floor(2).should.eql?(-1.24)
+ 5.123812.floor(4).should.eql?(5.1238)
+ 10.00001.floor(5).should.eql?(10.00001)
end
end
diff --git a/spec/ruby/core/float/gt_spec.rb b/spec/ruby/core/float/gt_spec.rb
index 33078e07ce..5194796b46 100644
--- a/spec/ruby/core/float/gt_spec.rb
+++ b/spec/ruby/core/float/gt_spec.rb
@@ -11,8 +11,8 @@ describe "Float#>" do
end
it "raises an ArgumentError when given a non-Numeric" do
- -> { 5.0 > "4" }.should raise_error(ArgumentError)
- -> { 5.0 > mock('x') }.should raise_error(ArgumentError)
+ -> { 5.0 > "4" }.should.raise(ArgumentError)
+ -> { 5.0 > mock('x') }.should.raise(ArgumentError)
end
it "returns false if one side is NaN" do
diff --git a/spec/ruby/core/float/gte_spec.rb b/spec/ruby/core/float/gte_spec.rb
index 44c0a81b43..4a62725d53 100644
--- a/spec/ruby/core/float/gte_spec.rb
+++ b/spec/ruby/core/float/gte_spec.rb
@@ -11,8 +11,8 @@ describe "Float#>=" do
end
it "raises an ArgumentError when given a non-Numeric" do
- -> { 5.0 >= "4" }.should raise_error(ArgumentError)
- -> { 5.0 >= mock('x') }.should raise_error(ArgumentError)
+ -> { 5.0 >= "4" }.should.raise(ArgumentError)
+ -> { 5.0 >= mock('x') }.should.raise(ArgumentError)
end
it "returns false if one side is NaN" do
diff --git a/spec/ruby/core/float/inspect_spec.rb b/spec/ruby/core/float/inspect_spec.rb
index 4be1927d84..3827167c17 100644
--- a/spec/ruby/core/float/inspect_spec.rb
+++ b/spec/ruby/core/float/inspect_spec.rb
@@ -1,6 +1,7 @@
require_relative '../../spec_helper'
-require_relative 'shared/to_s'
describe "Float#inspect" do
- it_behaves_like :float_to_s, :inspect
+ it "is an alias of Float#to_s" do
+ Float.instance_method(:inspect).should == Float.instance_method(:to_s)
+ end
end
diff --git a/spec/ruby/core/float/lt_spec.rb b/spec/ruby/core/float/lt_spec.rb
index 94dcfc42f8..0f0e1752bd 100644
--- a/spec/ruby/core/float/lt_spec.rb
+++ b/spec/ruby/core/float/lt_spec.rb
@@ -11,8 +11,8 @@ describe "Float#<" do
end
it "raises an ArgumentError when given a non-Numeric" do
- -> { 5.0 < "4" }.should raise_error(ArgumentError)
- -> { 5.0 < mock('x') }.should raise_error(ArgumentError)
+ -> { 5.0 < "4" }.should.raise(ArgumentError)
+ -> { 5.0 < mock('x') }.should.raise(ArgumentError)
end
it "returns false if one side is NaN" do
diff --git a/spec/ruby/core/float/lte_spec.rb b/spec/ruby/core/float/lte_spec.rb
index 7b5a86ee76..afb64ade09 100644
--- a/spec/ruby/core/float/lte_spec.rb
+++ b/spec/ruby/core/float/lte_spec.rb
@@ -12,8 +12,8 @@ describe "Float#<=" do
end
it "raises an ArgumentError when given a non-Numeric" do
- -> { 5.0 <= "4" }.should raise_error(ArgumentError)
- -> { 5.0 <= mock('x') }.should raise_error(ArgumentError)
+ -> { 5.0 <= "4" }.should.raise(ArgumentError)
+ -> { 5.0 <= mock('x') }.should.raise(ArgumentError)
end
it "returns false if one side is NaN" do
diff --git a/spec/ruby/core/float/magnitude_spec.rb b/spec/ruby/core/float/magnitude_spec.rb
index 7cdd8ef28a..4a753267e0 100644
--- a/spec/ruby/core/float/magnitude_spec.rb
+++ b/spec/ruby/core/float/magnitude_spec.rb
@@ -2,5 +2,13 @@ require_relative "../../spec_helper"
require_relative 'shared/abs'
describe "Float#magnitude" do
- it_behaves_like :float_abs, :magnitude
+ ruby_version_is ""..."3.4" do
+ it_behaves_like :float_abs, :magnitude
+ end
+
+ ruby_version_is "3.4" do
+ it "is an alias of Float#abs" do
+ Float.instance_method(:magnitude).should == Float.instance_method(:abs)
+ end
+ end
end
diff --git a/spec/ruby/core/float/modulo_spec.rb b/spec/ruby/core/float/modulo_spec.rb
index 8ae80a0b05..8b7aedf822 100644
--- a/spec/ruby/core/float/modulo_spec.rb
+++ b/spec/ruby/core/float/modulo_spec.rb
@@ -1,10 +1,56 @@
require_relative '../../spec_helper'
-require_relative 'shared/modulo'
describe "Float#%" do
- it_behaves_like :float_modulo, :%
+ it "returns self modulo other" do
+ (6543.21 % 137).should be_close(104.21, TOLERANCE)
+ (5667.19 % bignum_value).should be_close(5667.19, TOLERANCE)
+ (6543.21 % 137.24).should be_close(92.9299999999996, TOLERANCE)
+
+ (-1.0 % 1).should == 0
+ end
+
+ it "returns self when modulus is +Infinity" do
+ (4.2 % Float::INFINITY).should == 4.2
+ end
+
+ it "returns -Infinity when modulus is -Infinity" do
+ (4.2 % -Float::INFINITY).should == -Float::INFINITY
+ end
+
+ it "returns NaN when called on NaN or Infinities" do
+ (Float::NAN % 42).should.nan?
+ (Float::INFINITY % 42).should.nan?
+ (-Float::INFINITY % 42).should.nan?
+ end
+
+ it "returns NaN when modulus is NaN" do
+ (4.2 % Float::NAN).should.nan?
+ end
+
+ it "returns -0.0 when called on -0.0 with a non zero modulus" do
+ r = -0.0 % 42
+ r.should == 0
+ (1/r).should < 0
+
+ r = -0.0 % Float::INFINITY
+ r.should == 0
+ (1/r).should < 0
+ end
+
+ it "tries to coerce the modulus" do
+ obj = mock("modulus")
+ obj.should_receive(:coerce).with(1.25).and_return([1.25, 0.5])
+ (1.25 % obj).should == 0.25
+ end
+
+ it "raises a ZeroDivisionError if other is zero" do
+ -> { 1.0 % 0 }.should.raise(ZeroDivisionError)
+ -> { 1.0 % 0.0 }.should.raise(ZeroDivisionError)
+ end
end
describe "Float#modulo" do
- it_behaves_like :float_modulo, :modulo
+ it "is an alias of Float#%" do
+ Float.instance_method(:modulo).should == Float.instance_method(:%)
+ end
end
diff --git a/spec/ruby/core/float/multiply_spec.rb b/spec/ruby/core/float/multiply_spec.rb
index 2adb8796cd..edaaba7e61 100644
--- a/spec/ruby/core/float/multiply_spec.rb
+++ b/spec/ruby/core/float/multiply_spec.rb
@@ -11,7 +11,7 @@ describe "Float#*" do
end
it "raises a TypeError when given a non-Numeric" do
- -> { 13.0 * "10" }.should raise_error(TypeError)
- -> { 13.0 * :symbol }.should raise_error(TypeError)
+ -> { 13.0 * "10" }.should.raise(TypeError)
+ -> { 13.0 * :symbol }.should.raise(TypeError)
end
end
diff --git a/spec/ruby/core/float/negative_spec.rb b/spec/ruby/core/float/negative_spec.rb
index 511d92ade6..484e636adb 100644
--- a/spec/ruby/core/float/negative_spec.rb
+++ b/spec/ruby/core/float/negative_spec.rb
@@ -3,31 +3,31 @@ require_relative '../../spec_helper'
describe "Float#negative?" do
describe "on positive numbers" do
it "returns false" do
- 0.1.negative?.should be_false
+ 0.1.negative?.should == false
end
end
describe "on zero" do
it "returns false" do
- 0.0.negative?.should be_false
+ 0.0.negative?.should == false
end
end
describe "on negative zero" do
it "returns false" do
- -0.0.negative?.should be_false
+ -0.0.negative?.should == false
end
end
describe "on negative numbers" do
it "returns true" do
- -0.1.negative?.should be_true
+ -0.1.negative?.should == true
end
end
describe "on NaN" do
it "returns false" do
- nan_value.negative?.should be_false
+ nan_value.negative?.should == false
end
end
end
diff --git a/spec/ruby/core/float/next_float_spec.rb b/spec/ruby/core/float/next_float_spec.rb
index 29e2d31146..59892be343 100644
--- a/spec/ruby/core/float/next_float_spec.rb
+++ b/spec/ruby/core/float/next_float_spec.rb
@@ -9,7 +9,7 @@ describe "Float#next_float" do
barely_positive.should < barely_positive.next_float
midpoint = barely_positive / 2
- [0.0, barely_positive].should include midpoint
+ [0.0, barely_positive].should.include? midpoint
end
it "returns Float::INFINITY for Float::INFINITY" do
diff --git a/spec/ruby/core/float/numerator_spec.rb b/spec/ruby/core/float/numerator_spec.rb
index 7832e8f056..53b32fdd3d 100644
--- a/spec/ruby/core/float/numerator_spec.rb
+++ b/spec/ruby/core/float/numerator_spec.rb
@@ -15,7 +15,7 @@ describe "Float#numerator" do
it "converts self to a Rational object then returns its numerator" do
@numbers.each do |number|
- number.infinite?.should be_nil
+ number.infinite?.should == nil
number.numerator.should == Rational(number).numerator
end
end
@@ -25,7 +25,7 @@ describe "Float#numerator" do
end
it "returns NaN for NaN" do
- nan_value.numerator.nan?.should be_true
+ nan_value.numerator.nan?.should == true
end
it "returns Infinity for Infinity" do
diff --git a/spec/ruby/core/float/phase_spec.rb b/spec/ruby/core/float/phase_spec.rb
index 2aa84024b4..ad112ac9fe 100644
--- a/spec/ruby/core/float/phase_spec.rb
+++ b/spec/ruby/core/float/phase_spec.rb
@@ -1,6 +1,7 @@
require_relative '../../spec_helper'
-require_relative 'shared/arg'
describe "Float#phase" do
- it_behaves_like :float_arg, :phase
+ it "is an alias of Float#arg" do
+ Float.instance_method(:phase).should == Float.instance_method(:arg)
+ end
end
diff --git a/spec/ruby/core/float/positive_spec.rb b/spec/ruby/core/float/positive_spec.rb
index 575f92a720..aa87c03151 100644
--- a/spec/ruby/core/float/positive_spec.rb
+++ b/spec/ruby/core/float/positive_spec.rb
@@ -3,31 +3,31 @@ require_relative '../../spec_helper'
describe "Float#positive?" do
describe "on positive numbers" do
it "returns true" do
- 0.1.positive?.should be_true
+ 0.1.positive?.should == true
end
end
describe "on zero" do
it "returns false" do
- 0.0.positive?.should be_false
+ 0.0.positive?.should == false
end
end
describe "on negative zero" do
it "returns false" do
- -0.0.positive?.should be_false
+ -0.0.positive?.should == false
end
end
describe "on negative numbers" do
it "returns false" do
- -0.1.positive?.should be_false
+ -0.1.positive?.should == false
end
end
describe "on NaN" do
it "returns false" do
- nan_value.positive?.should be_false
+ nan_value.positive?.should == false
end
end
end
diff --git a/spec/ruby/core/float/prev_float_spec.rb b/spec/ruby/core/float/prev_float_spec.rb
index 5e50269da7..2d1f136254 100644
--- a/spec/ruby/core/float/prev_float_spec.rb
+++ b/spec/ruby/core/float/prev_float_spec.rb
@@ -9,7 +9,7 @@ describe "Float#prev_float" do
barely_negative.should > barely_negative.prev_float
midpoint = barely_negative / 2
- [0.0, barely_negative].should include midpoint
+ [0.0, barely_negative].should.include? midpoint
end
it "returns -Float::INFINITY for -Float::INFINITY" do
diff --git a/spec/ruby/core/float/quo_spec.rb b/spec/ruby/core/float/quo_spec.rb
index b5c64f9d87..0e9a7a0a0c 100644
--- a/spec/ruby/core/float/quo_spec.rb
+++ b/spec/ruby/core/float/quo_spec.rb
@@ -1,6 +1,7 @@
require_relative '../../spec_helper'
-require_relative 'shared/quo'
describe "Float#quo" do
- it_behaves_like :float_quo, :quo
+ it "is an alias of Float#fdiv" do
+ Float.instance_method(:quo).should == Float.instance_method(:fdiv)
+ end
end
diff --git a/spec/ruby/core/float/rationalize_spec.rb b/spec/ruby/core/float/rationalize_spec.rb
index 0c5bef7ac4..fa8fb5c841 100644
--- a/spec/ruby/core/float/rationalize_spec.rb
+++ b/spec/ruby/core/float/rationalize_spec.rb
@@ -29,15 +29,15 @@ describe "Float#rationalize" do
end
it "raises a FloatDomainError for Infinity" do
- -> {infinity_value.rationalize}.should raise_error(FloatDomainError)
+ -> {infinity_value.rationalize}.should.raise(FloatDomainError)
end
it "raises a FloatDomainError for NaN" do
- -> { nan_value.rationalize }.should raise_error(FloatDomainError)
+ -> { nan_value.rationalize }.should.raise(FloatDomainError)
end
it "raises ArgumentError when passed more than one argument" do
- -> { 0.3.rationalize(0.1, 0.1) }.should raise_error(ArgumentError)
- -> { 0.3.rationalize(0.1, 0.1, 2) }.should raise_error(ArgumentError)
+ -> { 0.3.rationalize(0.1, 0.1) }.should.raise(ArgumentError)
+ -> { 0.3.rationalize(0.1, 0.1, 2) }.should.raise(ArgumentError)
end
end
diff --git a/spec/ruby/core/float/round_spec.rb b/spec/ruby/core/float/round_spec.rb
index 7e8c792051..63c1d5689c 100644
--- a/spec/ruby/core/float/round_spec.rb
+++ b/spec/ruby/core/float/round_spec.rb
@@ -16,17 +16,17 @@ describe "Float#round" do
end
it "raises FloatDomainError for exceptional values" do
- -> { (+infinity_value).round }.should raise_error(FloatDomainError)
- -> { (-infinity_value).round }.should raise_error(FloatDomainError)
- -> { nan_value.round }.should raise_error(FloatDomainError)
+ -> { (+infinity_value).round }.should.raise(FloatDomainError)
+ -> { (-infinity_value).round }.should.raise(FloatDomainError)
+ -> { nan_value.round }.should.raise(FloatDomainError)
end
it "rounds self to an optionally given precision" do
- 5.5.round(0).should eql(6)
- 5.7.round(1).should eql(5.7)
+ 5.5.round(0).should.eql?(6)
+ 5.7.round(1).should.eql?(5.7)
1.2345678.round(2).should == 1.23
- 123456.78.round(-2).should eql(123500) # rounded up
- -123456.78.round(-2).should eql(-123500)
+ 123456.78.round(-2).should.eql?(123500) # rounded up
+ -123456.78.round(-2).should.eql?(-123500)
12.345678.round(3.999).should == 12.346
end
@@ -36,36 +36,37 @@ describe "Float#round" do
end
it "returns zero when passed a negative argument with magnitude greater than magnitude of the whole number portion of the Float" do
- 0.8346268.round(-1).should eql(0)
+ 0.8346268.round(-1).should.eql?(0)
end
it "raises a TypeError when its argument can not be converted to an Integer" do
- -> { 1.0.round("4") }.should raise_error(TypeError)
- -> { 1.0.round(nil) }.should raise_error(TypeError)
+ -> { 1.0.round("4") }.should.raise(TypeError)
+ -> { 1.0.round(nil) }.should.raise(TypeError)
end
it "raises FloatDomainError for exceptional values when passed a non-positive precision" do
- -> { Float::INFINITY.round( 0) }.should raise_error(FloatDomainError)
- -> { Float::INFINITY.round(-2) }.should raise_error(FloatDomainError)
- -> { (-Float::INFINITY).round( 0) }.should raise_error(FloatDomainError)
- -> { (-Float::INFINITY).round(-2) }.should raise_error(FloatDomainError)
+ -> { Float::INFINITY.round( 0) }.should.raise(FloatDomainError)
+ -> { Float::INFINITY.round(-2) }.should.raise(FloatDomainError)
+ -> { (-Float::INFINITY).round( 0) }.should.raise(FloatDomainError)
+ -> { (-Float::INFINITY).round(-2) }.should.raise(FloatDomainError)
end
it "raises RangeError for NAN when passed a non-positive precision" do
- -> { Float::NAN.round(0) }.should raise_error(RangeError)
- -> { Float::NAN.round(-2) }.should raise_error(RangeError)
+ -> { Float::NAN.round(0) }.should.raise(RangeError)
+ -> { Float::NAN.round(-2) }.should.raise(RangeError)
end
it "returns self for exceptional values when passed a non-negative precision" do
Float::INFINITY.round(2).should == Float::INFINITY
(-Float::INFINITY).round(2).should == -Float::INFINITY
- Float::NAN.round(2).should be_nan
+ Float::NAN.round(2).should.nan?
end
# redmine:5227
it "works for corner cases" do
- 42.0.round(308).should eql(42.0)
- 1.0e307.round(2).should eql(1.0e307)
+ 42.0.round(308).should.eql?(42.0)
+ 1.0e307.round(2).should.eql?(1.0e307)
+ 120.0.round(-1).should.eql?(120)
end
# redmine:5271
@@ -78,114 +79,112 @@ describe "Float#round" do
end
it "returns big values rounded to nearest" do
- +2.5e20.round(-20).should eql( +3 * 10 ** 20 )
- -2.5e20.round(-20).should eql( -3 * 10 ** 20 )
+ +2.5e20.round(-20).should.eql?( +3 * 10 ** 20 )
+ -2.5e20.round(-20).should.eql?( -3 * 10 ** 20 )
end
# redmine #5272
it "returns rounded values for big values" do
- +2.4e20.round(-20).should eql( +2 * 10 ** 20 )
- -2.4e20.round(-20).should eql( -2 * 10 ** 20 )
- +2.5e200.round(-200).should eql( +3 * 10 ** 200 )
- +2.4e200.round(-200).should eql( +2 * 10 ** 200 )
- -2.5e200.round(-200).should eql( -3 * 10 ** 200 )
- -2.4e200.round(-200).should eql( -2 * 10 ** 200 )
+ +2.4e20.round(-20).should.eql?( +2 * 10 ** 20 )
+ -2.4e20.round(-20).should.eql?( -2 * 10 ** 20 )
+ +2.5e200.round(-200).should.eql?( +3 * 10 ** 200 )
+ +2.4e200.round(-200).should.eql?( +2 * 10 ** 200 )
+ -2.5e200.round(-200).should.eql?( -3 * 10 ** 200 )
+ -2.4e200.round(-200).should.eql?( -2 * 10 ** 200 )
end
it "returns different rounded values depending on the half option" do
- 2.5.round(half: nil).should eql(3)
- 2.5.round(half: :up).should eql(3)
- 2.5.round(half: :down).should eql(2)
- 2.5.round(half: :even).should eql(2)
- 3.5.round(half: nil).should eql(4)
- 3.5.round(half: :up).should eql(4)
- 3.5.round(half: :down).should eql(3)
- 3.5.round(half: :even).should eql(4)
- (-2.5).round(half: nil).should eql(-3)
- (-2.5).round(half: :up).should eql(-3)
- (-2.5).round(half: :down).should eql(-2)
- (-2.5).round(half: :even).should eql(-2)
+ 2.5.round(half: nil).should.eql?(3)
+ 2.5.round(half: :up).should.eql?(3)
+ 2.5.round(half: :down).should.eql?(2)
+ 2.5.round(half: :even).should.eql?(2)
+ 3.5.round(half: nil).should.eql?(4)
+ 3.5.round(half: :up).should.eql?(4)
+ 3.5.round(half: :down).should.eql?(3)
+ 3.5.round(half: :even).should.eql?(4)
+ (-2.5).round(half: nil).should.eql?(-3)
+ (-2.5).round(half: :up).should.eql?(-3)
+ (-2.5).round(half: :down).should.eql?(-2)
+ (-2.5).round(half: :even).should.eql?(-2)
end
it "rounds self to an optionally given precision with a half option" do
- 5.55.round(1, half: nil).should eql(5.6)
- 5.55.round(1, half: :up).should eql(5.6)
- 5.55.round(1, half: :down).should eql(5.5)
- 5.55.round(1, half: :even).should eql(5.6)
- -5.55.round(1, half: nil).should eql(-5.6)
- -5.55.round(1, half: :up).should eql(-5.6)
- -5.55.round(1, half: :down).should eql(-5.5)
- -5.55.round(1, half: :even).should eql(-5.6)
+ 5.55.round(1, half: nil).should.eql?(5.6)
+ 5.55.round(1, half: :up).should.eql?(5.6)
+ 5.55.round(1, half: :down).should.eql?(5.5)
+ 5.55.round(1, half: :even).should.eql?(5.6)
+ -5.55.round(1, half: nil).should.eql?(-5.6)
+ -5.55.round(1, half: :up).should.eql?(-5.6)
+ -5.55.round(1, half: :down).should.eql?(-5.5)
+ -5.55.round(1, half: :even).should.eql?(-5.6)
end
it "preserves cases where neighbouring floating pointer number increase the decimal places" do
- 4.8100000000000005.round(5, half: nil).should eql(4.81)
- 4.8100000000000005.round(5, half: :up).should eql(4.81)
- 4.8100000000000005.round(5, half: :down).should eql(4.81)
- 4.8100000000000005.round(5, half: :even).should eql(4.81)
- -4.8100000000000005.round(5, half: nil).should eql(-4.81)
- -4.8100000000000005.round(5, half: :up).should eql(-4.81)
- -4.8100000000000005.round(5, half: :down).should eql(-4.81)
- -4.8100000000000005.round(5, half: :even).should eql(-4.81)
- 4.81.round(5, half: nil).should eql(4.81)
- 4.81.round(5, half: :up).should eql(4.81)
- 4.81.round(5, half: :down).should eql(4.81)
- 4.81.round(5, half: :even).should eql(4.81)
- -4.81.round(5, half: nil).should eql(-4.81)
- -4.81.round(5, half: :up).should eql(-4.81)
- -4.81.round(5, half: :down).should eql(-4.81)
- -4.81.round(5, half: :even).should eql(-4.81)
- 4.809999999999999.round(5, half: nil).should eql(4.81)
- 4.809999999999999.round(5, half: :up).should eql(4.81)
- 4.809999999999999.round(5, half: :down).should eql(4.81)
- 4.809999999999999.round(5, half: :even).should eql(4.81)
- -4.809999999999999.round(5, half: nil).should eql(-4.81)
- -4.809999999999999.round(5, half: :up).should eql(-4.81)
- -4.809999999999999.round(5, half: :down).should eql(-4.81)
- -4.809999999999999.round(5, half: :even).should eql(-4.81)
- end
-
- ruby_bug "#19318", ""..."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
- # incorrect results.
- it "does not lose precision during the rounding process" do
- 767573.1875850001.round(5, half: nil).should eql(767573.18759)
- 767573.1875850001.round(5, half: :up).should eql(767573.18759)
- 767573.1875850001.round(5, half: :down).should eql(767573.18759)
- 767573.1875850001.round(5, half: :even).should eql(767573.18759)
- -767573.1875850001.round(5, half: nil).should eql(-767573.18759)
- -767573.1875850001.round(5, half: :up).should eql(-767573.18759)
- -767573.1875850001.round(5, half: :down).should eql(-767573.18759)
- -767573.1875850001.round(5, half: :even).should eql(-767573.18759)
- 767573.187585.round(5, half: nil).should eql(767573.18759)
- 767573.187585.round(5, half: :up).should eql(767573.18759)
- 767573.187585.round(5, half: :down).should eql(767573.18758)
- 767573.187585.round(5, half: :even).should eql(767573.18758)
- -767573.187585.round(5, half: nil).should eql(-767573.18759)
- -767573.187585.round(5, half: :up).should eql(-767573.18759)
- -767573.187585.round(5, half: :down).should eql(-767573.18758)
- -767573.187585.round(5, half: :even).should eql(-767573.18758)
- 767573.1875849998.round(5, half: nil).should eql(767573.18758)
- 767573.1875849998.round(5, half: :up).should eql(767573.18758)
- 767573.1875849998.round(5, half: :down).should eql(767573.18758)
- 767573.1875849998.round(5, half: :even).should eql(767573.18758)
- -767573.1875849998.round(5, half: nil).should eql(-767573.18758)
- -767573.1875849998.round(5, half: :up).should eql(-767573.18758)
- -767573.1875849998.round(5, half: :down).should eql(-767573.18758)
- -767573.1875849998.round(5, half: :even).should eql(-767573.18758)
- end
+ 4.8100000000000005.round(5, half: nil).should.eql?(4.81)
+ 4.8100000000000005.round(5, half: :up).should.eql?(4.81)
+ 4.8100000000000005.round(5, half: :down).should.eql?(4.81)
+ 4.8100000000000005.round(5, half: :even).should.eql?(4.81)
+ -4.8100000000000005.round(5, half: nil).should.eql?(-4.81)
+ -4.8100000000000005.round(5, half: :up).should.eql?(-4.81)
+ -4.8100000000000005.round(5, half: :down).should.eql?(-4.81)
+ -4.8100000000000005.round(5, half: :even).should.eql?(-4.81)
+ 4.81.round(5, half: nil).should.eql?(4.81)
+ 4.81.round(5, half: :up).should.eql?(4.81)
+ 4.81.round(5, half: :down).should.eql?(4.81)
+ 4.81.round(5, half: :even).should.eql?(4.81)
+ -4.81.round(5, half: nil).should.eql?(-4.81)
+ -4.81.round(5, half: :up).should.eql?(-4.81)
+ -4.81.round(5, half: :down).should.eql?(-4.81)
+ -4.81.round(5, half: :even).should.eql?(-4.81)
+ 4.809999999999999.round(5, half: nil).should.eql?(4.81)
+ 4.809999999999999.round(5, half: :up).should.eql?(4.81)
+ 4.809999999999999.round(5, half: :down).should.eql?(4.81)
+ 4.809999999999999.round(5, half: :even).should.eql?(4.81)
+ -4.809999999999999.round(5, half: nil).should.eql?(-4.81)
+ -4.809999999999999.round(5, half: :up).should.eql?(-4.81)
+ -4.809999999999999.round(5, half: :down).should.eql?(-4.81)
+ -4.809999999999999.round(5, half: :even).should.eql?(-4.81)
+ end
+
+ # 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
+ # incorrect results.
+ it "does not lose precision during the rounding process" do
+ 767573.1875850001.round(5, half: nil).should.eql?(767573.18759)
+ 767573.1875850001.round(5, half: :up).should.eql?(767573.18759)
+ 767573.1875850001.round(5, half: :down).should.eql?(767573.18759)
+ 767573.1875850001.round(5, half: :even).should.eql?(767573.18759)
+ -767573.1875850001.round(5, half: nil).should.eql?(-767573.18759)
+ -767573.1875850001.round(5, half: :up).should.eql?(-767573.18759)
+ -767573.1875850001.round(5, half: :down).should.eql?(-767573.18759)
+ -767573.1875850001.round(5, half: :even).should.eql?(-767573.18759)
+ 767573.187585.round(5, half: nil).should.eql?(767573.18759)
+ 767573.187585.round(5, half: :up).should.eql?(767573.18759)
+ 767573.187585.round(5, half: :down).should.eql?(767573.18758)
+ 767573.187585.round(5, half: :even).should.eql?(767573.18758)
+ -767573.187585.round(5, half: nil).should.eql?(-767573.18759)
+ -767573.187585.round(5, half: :up).should.eql?(-767573.18759)
+ -767573.187585.round(5, half: :down).should.eql?(-767573.18758)
+ -767573.187585.round(5, half: :even).should.eql?(-767573.18758)
+ 767573.1875849998.round(5, half: nil).should.eql?(767573.18758)
+ 767573.1875849998.round(5, half: :up).should.eql?(767573.18758)
+ 767573.1875849998.round(5, half: :down).should.eql?(767573.18758)
+ 767573.1875849998.round(5, half: :even).should.eql?(767573.18758)
+ -767573.1875849998.round(5, half: nil).should.eql?(-767573.18758)
+ -767573.1875849998.round(5, half: :up).should.eql?(-767573.18758)
+ -767573.1875849998.round(5, half: :down).should.eql?(-767573.18758)
+ -767573.1875849998.round(5, half: :even).should.eql?(-767573.18758)
end
it "raises FloatDomainError for exceptional values with a half option" do
- -> { (+infinity_value).round(half: :up) }.should raise_error(FloatDomainError)
- -> { (-infinity_value).round(half: :down) }.should raise_error(FloatDomainError)
- -> { nan_value.round(half: :even) }.should raise_error(FloatDomainError)
+ -> { (+infinity_value).round(half: :up) }.should.raise(FloatDomainError)
+ -> { (-infinity_value).round(half: :down) }.should.raise(FloatDomainError)
+ -> { nan_value.round(half: :even) }.should.raise(FloatDomainError)
end
it "raise for a non-existent round mode" do
- -> { 14.2.round(half: :nonsense) }.should raise_error(ArgumentError, "invalid rounding mode: nonsense")
+ -> { 14.2.round(half: :nonsense) }.should.raise(ArgumentError, "invalid rounding mode: nonsense")
end
describe "when 0.0 is given" do
@@ -197,7 +196,13 @@ describe "Float#round" do
it "returns 0 for 0 or undefined ndigits" do
(0.0).round.should == 0
(-0.0).round(0).should == 0
- (0.0).round(half: :up) == 0
+ (0.0).round(half: :up).should == 0
+ end
+
+ it "returns 0 for negative ndigits" do
+ (0.0).round(-1).should == 0
+ (-0.0).round(-1).should == 0
+ (0.0).round(-1, half: :up).should == 0
end
end
end
diff --git a/spec/ruby/core/float/shared/abs.rb b/spec/ruby/core/float/shared/abs.rb
index 607983322d..ab21480e24 100644
--- a/spec/ruby/core/float/shared/abs.rb
+++ b/spec/ruby/core/float/shared/abs.rb
@@ -16,6 +16,6 @@ describe :float_abs, shared: true do
end
it "returns NaN if NaN" do
- nan_value.send(@method).nan?.should be_true
+ nan_value.send(@method).nan?.should == true
end
end
diff --git a/spec/ruby/core/float/shared/arg.rb b/spec/ruby/core/float/shared/arg.rb
deleted file mode 100644
index 136cf19ec8..0000000000
--- a/spec/ruby/core/float/shared/arg.rb
+++ /dev/null
@@ -1,36 +0,0 @@
-describe :float_arg, shared: true do
- it "returns NaN if NaN" do
- f = nan_value
- f.send(@method).nan?.should be_true
- end
-
- it "returns self if NaN" do
- f = nan_value
- f.send(@method).should equal(f)
- end
-
- it "returns 0 if positive" do
- 1.0.send(@method).should == 0
- end
-
- it "returns 0 if +0.0" do
- 0.0.send(@method).should == 0
- end
-
- it "returns 0 if +Infinity" do
- infinity_value.send(@method).should == 0
- end
-
- it "returns Pi if negative" do
- (-1.0).send(@method).should == Math::PI
- end
-
- # This was established in r23960
- it "returns Pi if -0.0" do
- (-0.0).send(@method).should == Math::PI
- end
-
- it "returns Pi if -Infinity" do
- (-infinity_value).send(@method).should == Math::PI
- end
-end
diff --git a/spec/ruby/core/float/shared/arithmetic_exception_in_coerce.rb b/spec/ruby/core/float/shared/arithmetic_exception_in_coerce.rb
index eec92d858f..bd3bf9019f 100644
--- a/spec/ruby/core/float/shared/arithmetic_exception_in_coerce.rb
+++ b/spec/ruby/core/float/shared/arithmetic_exception_in_coerce.rb
@@ -6,6 +6,6 @@ describe :float_arithmetic_exception_in_coerce, shared: true do
b.should_receive(:coerce).and_raise(FloatSpecs::CoerceError)
# e.g. 1.0 > b
- -> { 1.0.send(@method, b) }.should raise_error(FloatSpecs::CoerceError)
+ -> { 1.0.send(@method, b) }.should.raise(FloatSpecs::CoerceError)
end
end
diff --git a/spec/ruby/core/float/shared/comparison_exception_in_coerce.rb b/spec/ruby/core/float/shared/comparison_exception_in_coerce.rb
index 3e2c1e28dd..eec5d8daf9 100644
--- a/spec/ruby/core/float/shared/comparison_exception_in_coerce.rb
+++ b/spec/ruby/core/float/shared/comparison_exception_in_coerce.rb
@@ -6,6 +6,6 @@ describe :float_comparison_exception_in_coerce, shared: true do
b.should_receive(:coerce).and_raise(FloatSpecs::CoerceError)
# e.g. 1.0 > b
- -> { 1.0.send(@method, b) }.should raise_error(FloatSpecs::CoerceError)
+ -> { 1.0.send(@method, b) }.should.raise(FloatSpecs::CoerceError)
end
end
diff --git a/spec/ruby/core/float/shared/equal.rb b/spec/ruby/core/float/shared/equal.rb
deleted file mode 100644
index 4d524e1cf2..0000000000
--- a/spec/ruby/core/float/shared/equal.rb
+++ /dev/null
@@ -1,38 +0,0 @@
-describe :float_equal, shared: true do
- it "returns true if self has the same value as other" do
- 1.0.send(@method, 1).should == true
- 2.71828.send(@method, 1.428).should == false
- -4.2.send(@method, 4.2).should == false
- end
-
- it "calls 'other == self' if coercion fails" do
- x = mock('other')
- def x.==(other)
- 2.0 == other
- end
-
- 1.0.send(@method, x).should == false
- 2.0.send(@method, x).should == true
- end
-
- it "returns false if one side is NaN" do
- [1.0, 42, bignum_value].each { |n|
- (nan_value.send(@method, n)).should == false
- (n.send(@method, nan_value)).should == false
- }
- end
-
- it "handles positive infinity" do
- [1.0, 42, bignum_value].each { |n|
- (infinity_value.send(@method, n)).should == false
- (n.send(@method, infinity_value)).should == false
- }
- end
-
- it "handles negative infinity" do
- [1.0, 42, bignum_value].each { |n|
- ((-infinity_value).send(@method, n)).should == false
- (n.send(@method, -infinity_value)).should == false
- }
- end
-end
diff --git a/spec/ruby/core/float/shared/modulo.rb b/spec/ruby/core/float/shared/modulo.rb
deleted file mode 100644
index 6700bd4f4e..0000000000
--- a/spec/ruby/core/float/shared/modulo.rb
+++ /dev/null
@@ -1,48 +0,0 @@
-describe :float_modulo, shared: true do
- it "returns self modulo other" do
- 6543.21.send(@method, 137).should be_close(104.21, TOLERANCE)
- 5667.19.send(@method, bignum_value).should be_close(5667.19, TOLERANCE)
- 6543.21.send(@method, 137.24).should be_close(92.9299999999996, TOLERANCE)
-
- -1.0.send(@method, 1).should == 0
- end
-
- it "returns self when modulus is +Infinity" do
- 4.2.send(@method, Float::INFINITY).should == 4.2
- end
-
- it "returns -Infinity when modulus is -Infinity" do
- 4.2.send(@method, -Float::INFINITY).should == -Float::INFINITY
- end
-
- it "returns NaN when called on NaN or Infinities" do
- Float::NAN.send(@method, 42).should be_nan
- Float::INFINITY.send(@method, 42).should be_nan
- (-Float::INFINITY).send(@method, 42).should be_nan
- end
-
- it "returns NaN when modulus is NaN" do
- 4.2.send(@method, Float::NAN).should be_nan
- end
-
- it "returns -0.0 when called on -0.0 with a non zero modulus" do
- r = (-0.0).send(@method, 42)
- r.should == 0
- (1/r).should < 0
-
- r = (-0.0).send(@method, Float::INFINITY)
- r.should == 0
- (1/r).should < 0
- end
-
- it "tries to coerce the modulus" do
- obj = mock("modulus")
- obj.should_receive(:coerce).with(1.25).and_return([1.25, 0.5])
- (1.25 % obj).should == 0.25
- end
-
- it "raises a ZeroDivisionError if other is zero" do
- -> { 1.0.send(@method, 0) }.should raise_error(ZeroDivisionError)
- -> { 1.0.send(@method, 0.0) }.should raise_error(ZeroDivisionError)
- end
-end
diff --git a/spec/ruby/core/float/shared/quo.rb b/spec/ruby/core/float/shared/quo.rb
deleted file mode 100644
index 0c90171b87..0000000000
--- a/spec/ruby/core/float/shared/quo.rb
+++ /dev/null
@@ -1,59 +0,0 @@
-describe :float_quo, shared: true do
- it "performs floating-point division between self and an Integer" do
- 8.9.send(@method, 7).should == 1.2714285714285716
- end
-
- it "performs floating-point division between self and an Integer" do
- 8.9.send(@method, 9999999999999**9).should == 8.900000000008011e-117
- end
-
- it "performs floating-point division between self and a Float" do
- 2827.22.send(@method, 872.111111).should == 3.2418116961704433
- end
-
- it "returns NaN when the argument is NaN" do
- -1819.999999.send(@method, nan_value).nan?.should be_true
- 11109.1981271.send(@method, nan_value).nan?.should be_true
- end
-
- it "returns Infinity when the argument is 0.0" do
- 2827.22.send(@method, 0.0).infinite?.should == 1
- end
-
- it "returns -Infinity when the argument is 0.0 and self is negative" do
- -48229.282.send(@method, 0.0).infinite?.should == -1
- end
-
- it "returns Infinity when the argument is 0" do
- 2827.22.send(@method, 0).infinite?.should == 1
- end
-
- it "returns -Infinity when the argument is 0 and self is negative" do
- -48229.282.send(@method, 0).infinite?.should == -1
- end
-
- it "returns 0.0 when the argument is Infinity" do
- 47292.2821.send(@method, infinity_value).should == 0.0
- end
-
- it "returns -0.0 when the argument is -Infinity" do
- 1.9999918.send(@method, -infinity_value).should == -0.0
- end
-
- it "performs floating-point division between self and a Rational" do
- 74620.09.send(@method, Rational(2,3)).should == 111930.135
- end
-
- it "performs floating-point division between self and a Complex" do
- 74620.09.send(@method, Complex(8,2)).should == Complex(
- 8778.834117647059, -2194.7085294117646)
- end
-
- it "raises a TypeError when argument isn't numeric" do
- -> { 27292.2.send(@method, mock('non-numeric')) }.should raise_error(TypeError)
- end
-
- it "raises an ArgumentError when passed multiple arguments" do
- -> { 272.221.send(@method, 6,0.2) }.should raise_error(ArgumentError)
- end
-end
diff --git a/spec/ruby/core/float/shared/to_i.rb b/spec/ruby/core/float/shared/to_i.rb
index 33b32ca533..1e6f941467 100644
--- a/spec/ruby/core/float/shared/to_i.rb
+++ b/spec/ruby/core/float/shared/to_i.rb
@@ -1,14 +1,14 @@
describe :float_to_i, shared: true do
it "returns self truncated to an Integer" do
- 899.2.send(@method).should eql(899)
- -1.122256e-45.send(@method).should eql(0)
- 5_213_451.9201.send(@method).should eql(5213451)
- 1.233450999123389e+12.send(@method).should eql(1233450999123)
- -9223372036854775808.1.send(@method).should eql(-9223372036854775808)
- 9223372036854775808.1.send(@method).should eql(9223372036854775808)
+ 899.2.send(@method).should.eql?(899)
+ -1.122256e-45.send(@method).should.eql?(0)
+ 5_213_451.9201.send(@method).should.eql?(5213451)
+ 1.233450999123389e+12.send(@method).should.eql?(1233450999123)
+ -9223372036854775808.1.send(@method).should.eql?(-9223372036854775808)
+ 9223372036854775808.1.send(@method).should.eql?(9223372036854775808)
end
it "raises a FloatDomainError for NaN" do
- -> { nan_value.send(@method) }.should raise_error(FloatDomainError)
+ -> { nan_value.send(@method) }.should.raise(FloatDomainError)
end
end
diff --git a/spec/ruby/core/float/shared/to_s.rb b/spec/ruby/core/float/shared/to_s.rb
deleted file mode 100644
index 0925efc0f7..0000000000
--- a/spec/ruby/core/float/shared/to_s.rb
+++ /dev/null
@@ -1,308 +0,0 @@
-describe :float_to_s, shared: true do
- it "returns 'NaN' for NaN" do
- nan_value().send(@method).should == 'NaN'
- end
-
- it "returns 'Infinity' for positive infinity" do
- infinity_value().send(@method).should == 'Infinity'
- end
-
- it "returns '-Infinity' for negative infinity" do
- (-infinity_value()).send(@method).should == '-Infinity'
- end
-
- it "returns '0.0' for 0.0" do
- 0.0.send(@method).should == "0.0"
- end
-
- platform_is_not :openbsd do
- it "emits '-' for -0.0" do
- -0.0.send(@method).should == "-0.0"
- end
- end
-
- it "emits a '-' for negative values" do
- -3.14.send(@method).should == "-3.14"
- end
-
- it "emits a trailing '.0' for a whole number" do
- 50.0.send(@method).should == "50.0"
- end
-
- it "emits a trailing '.0' for the mantissa in e format" do
- 1.0e20.send(@method).should == "1.0e+20"
- end
-
- it "uses non-e format for a positive value with fractional part having 5 significant figures" do
- 0.0001.send(@method).should == "0.0001"
- end
-
- it "uses non-e format for a negative value with fractional part having 5 significant figures" do
- -0.0001.send(@method).should == "-0.0001"
- end
-
- it "uses e format for a positive value with fractional part having 6 significant figures" do
- 0.00001.send(@method).should == "1.0e-05"
- end
-
- it "uses e format for a negative value with fractional part having 6 significant figures" do
- -0.00001.send(@method).should == "-1.0e-05"
- end
-
- it "uses non-e format for a positive value with whole part having 15 significant figures" do
- 10000000000000.0.send(@method).should == "10000000000000.0"
- end
-
- it "uses non-e format for a negative value with whole part having 15 significant figures" do
- -10000000000000.0.send(@method).should == "-10000000000000.0"
- end
-
- it "uses non-e format for a positive value with whole part having 16 significant figures" do
- 100000000000000.0.send(@method).should == "100000000000000.0"
- end
-
- it "uses non-e format for a negative value with whole part having 16 significant figures" do
- -100000000000000.0.send(@method).should == "-100000000000000.0"
- end
-
- it "uses e format for a positive value with whole part having 18 significant figures" do
- 10000000000000000.0.send(@method).should == "1.0e+16"
- end
-
- it "uses e format for a negative value with whole part having 18 significant figures" do
- -10000000000000000.0.send(@method).should == "-1.0e+16"
- end
-
- it "uses e format for a positive value with whole part having 17 significant figures" do
- 1000000000000000.0.send(@method).should == "1.0e+15"
- end
-
- it "uses e format for a negative value with whole part having 17 significant figures" do
- -1000000000000000.0.send(@method).should == "-1.0e+15"
- end
-
- # #3273
- it "outputs the minimal, unique form necessary to recreate the value" do
- value = 0.21611564636388508
- string = "0.21611564636388508"
-
- value.send(@method).should == string
- string.to_f.should == value
- end
-
- it "outputs the minimal, unique form to represent the value" do
- 0.56.send(@method).should == "0.56"
- end
-
- describe "matches" do
- it "random examples in all ranges" do
- # 50.times do
- # bytes = (0...8).map { rand(256) }
- # string = bytes.pack('C8')
- # float = string.unpack('D').first
- # puts "#{'%.20g' % float}.send(@method).should == #{float.send(@method).inspect}"
- # end
-
- 2.5540217314354050325e+163.send(@method).should == "2.554021731435405e+163"
- 2.5492588360356597544e-172.send(@method).should == "2.5492588360356598e-172"
- 1.742770260934704852e-82.send(@method).should == "1.7427702609347049e-82"
- 6.2108093676180883209e-104.send(@method).should == "6.210809367618088e-104"
- -3.3448803488331067402e-143.send(@method).should == "-3.3448803488331067e-143"
- -2.2740074343500832557e-168.send(@method).should == "-2.2740074343500833e-168"
- 7.0587971678048535732e+191.send(@method).should == "7.058797167804854e+191"
- -284438.88327586348169.send(@method).should == "-284438.8832758635"
- 3.953272468476091301e+105.send(@method).should == "3.9532724684760913e+105"
- -3.6361359552959847853e+100.send(@method).should == "-3.636135955295985e+100"
- -1.3222325865575206185e-31.send(@method).should == "-1.3222325865575206e-31"
- 1.1440138916932761366e+130.send(@method).should == "1.1440138916932761e+130"
- 4.8750891560387561157e-286.send(@method).should == "4.875089156038756e-286"
- 5.6101113356591453525e-257.send(@method).should == "5.610111335659145e-257"
- -3.829644279545809575e-100.send(@method).should == "-3.8296442795458096e-100"
- 1.5342839401396406117e-194.send(@method).should == "1.5342839401396406e-194"
- 2.2284972755169921402e-144.send(@method).should == "2.228497275516992e-144"
- 2.1825655917065601737e-61.send(@method).should == "2.1825655917065602e-61"
- -2.6672271363524338322e-62.send(@method).should == "-2.667227136352434e-62"
- -1.9257995160119059415e+21.send(@method).should == "-1.925799516011906e+21"
- -8.9096732962887121718e-198.send(@method).should == "-8.909673296288712e-198"
- 2.0202075376548644959e-90.send(@method).should == "2.0202075376548645e-90"
- -7.7341602581786258961e-266.send(@method).should == "-7.734160258178626e-266"
- 3.5134482598733635046e+98.send(@method).should == "3.5134482598733635e+98"
- -2.124411722371029134e+154.send(@method).should == "-2.124411722371029e+154"
- -4.573908787355718687e+110.send(@method).should == "-4.573908787355719e+110"
- -1.9344425934170969879e-232.send(@method).should == "-1.934442593417097e-232"
- -1.3274227399979271095e+171.send(@method).should == "-1.3274227399979271e+171"
- 9.3495270482104442383e-283.send(@method).should == "9.349527048210444e-283"
- -4.2046059371986483233e+307.send(@method).should == "-4.2046059371986483e+307"
- 3.6133547278583543004e-117.send(@method).should == "3.613354727858354e-117"
- 4.9247416523566613499e-08.send(@method).should == "4.9247416523566613e-08"
- 1.6936145488250064007e-71.send(@method).should == "1.6936145488250064e-71"
- 2.4455483206829433098e+96.send(@method).should == "2.4455483206829433e+96"
- 7.9797449851436455384e+124.send(@method).should == "7.979744985143646e+124"
- -1.3873689634457876774e-129.send(@method).should == "-1.3873689634457877e-129"
- 3.9761102037533483075e+284.send(@method).should == "3.976110203753348e+284"
- -4.2819791952139402486e-303.send(@method).should == "-4.28197919521394e-303"
- -5.7981017546689831298e-116.send(@method).should == "-5.798101754668983e-116"
- -3.953266497860534199e-28.send(@method).should == "-3.953266497860534e-28"
- -2.0659852720290440959e-243.send(@method).should == "-2.065985272029044e-243"
- 8.9670488995878688018e-05.send(@method).should == "8.967048899587869e-05"
- -1.2317943708113061768e-98.send(@method).should == "-1.2317943708113062e-98"
- -3.8930768307633080463e+248.send(@method).should == "-3.893076830763308e+248"
- 6.5854032671803925627e-239.send(@method).should == "6.5854032671803926e-239"
- 4.6257022188980878952e+177.send(@method).should == "4.625702218898088e+177"
- -1.9397155125507235603e-187.send(@method).should == "-1.9397155125507236e-187"
- 8.5752156951245705056e+117.send(@method).should == "8.57521569512457e+117"
- -2.4784875958162501671e-132.send(@method).should == "-2.4784875958162502e-132"
- -4.4125691841230058457e-203.send(@method).should == "-4.412569184123006e-203"
- end
-
- it "random examples in human ranges" do
- # 50.times do
- # formatted = ''
- # rand(1..3).times do
- # formatted << rand(10).to_s
- # end
- # formatted << '.'
- # rand(1..9).times do
- # formatted << rand(10).to_s
- # end
- # float = formatted.to_f
- # puts "#{'%.20f' % float}.send(@method).should == #{float.send(@method).inspect}"
- # end
-
- 5.17869899999999994122.send(@method).should == "5.178699"
- 905.62695729999995819526.send(@method).should == "905.6269573"
- 62.75999999999999801048.send(@method).should == "62.76"
- 6.93856795800000014651.send(@method).should == "6.938567958"
- 4.95999999999999996447.send(@method).should == "4.96"
- 32.77993899999999882766.send(@method).should == "32.779939"
- 544.12756779999995160324.send(@method).should == "544.1275678"
- 66.25801119999999855281.send(@method).should == "66.2580112"
- 7.90000000000000035527.send(@method).should == "7.9"
- 5.93100000000000004974.send(@method).should == "5.931"
- 5.21229313600000043749.send(@method).should == "5.212293136"
- 503.44173809000000119340.send(@method).should == "503.44173809"
- 79.26000000000000511591.send(@method).should == "79.26"
- 8.51524999999999998579.send(@method).should == "8.51525"
- 174.00000000000000000000.send(@method).should == "174.0"
- 50.39580000000000126192.send(@method).should == "50.3958"
- 35.28999999999999914735.send(@method).should == "35.29"
- 5.43136675399999990788.send(@method).should == "5.431366754"
- 654.07680000000004838512.send(@method).should == "654.0768"
- 6.07423700000000010846.send(@method).should == "6.074237"
- 102.25779799999999397642.send(@method).should == "102.257798"
- 5.08129999999999970584.send(@method).should == "5.0813"
- 6.00000000000000000000.send(@method).should == "6.0"
- 8.30000000000000071054.send(@method).should == "8.3"
- 32.68345999999999662577.send(@method).should == "32.68346"
- 581.11170000000004165486.send(@method).should == "581.1117"
- 76.31342999999999676675.send(@method).should == "76.31343"
- 438.30826000000001840817.send(@method).should == "438.30826"
- 482.06631994000002805478.send(@method).should == "482.06631994"
- 55.92721026899999969828.send(@method).should == "55.927210269"
- 4.00000000000000000000.send(@method).should == "4.0"
- 55.86693999999999959982.send(@method).should == "55.86694"
- 787.98299999999994724931.send(@method).should == "787.983"
- 5.73810511000000023074.send(@method).should == "5.73810511"
- 74.51926810000000500622.send(@method).should == "74.5192681"
- 892.89999999999997726263.send(@method).should == "892.9"
- 68.27299999999999613465.send(@method).should == "68.273"
- 904.10000000000002273737.send(@method).should == "904.1"
- 5.23200000000000020606.send(@method).should == "5.232"
- 4.09628000000000014325.send(@method).should == "4.09628"
- 46.05152633699999853434.send(@method).should == "46.051526337"
- 142.12884990599999923688.send(@method).should == "142.128849906"
- 3.83057023500000015659.send(@method).should == "3.830570235"
- 11.81684594699999912848.send(@method).should == "11.816845947"
- 80.50000000000000000000.send(@method).should == "80.5"
- 382.18215010000000120272.send(@method).should == "382.1821501"
- 55.38444606899999911320.send(@method).should == "55.384446069"
- 5.78000000000000024869.send(@method).should == "5.78"
- 2.88244999999999995666.send(@method).should == "2.88245"
- 43.27709999999999723741.send(@method).should == "43.2771"
- end
-
- it "random values from divisions" do
- (1.0 / 7).send(@method).should == "0.14285714285714285"
-
- # 50.times do
- # a = rand(10)
- # b = rand(10)
- # c = rand(10)
- # d = rand(10)
- # expression = "#{a}.#{b} / #{c}.#{d}"
- # puts " (#{expression}).send(@method).should == #{eval(expression).send(@method).inspect}"
- # end
-
- (1.1 / 7.1).send(@method).should == "0.15492957746478875"
- (6.5 / 8.8).send(@method).should == "0.7386363636363635"
- (4.8 / 4.3).send(@method).should == "1.1162790697674418"
- (4.0 / 1.9).send(@method).should == "2.1052631578947367"
- (9.1 / 0.8).send(@method).should == "11.374999999999998"
- (5.3 / 7.5).send(@method).should == "0.7066666666666667"
- (2.8 / 1.8).send(@method).should == "1.5555555555555554"
- (2.1 / 2.5).send(@method).should == "0.8400000000000001"
- (3.5 / 6.0).send(@method).should == "0.5833333333333334"
- (4.6 / 0.3).send(@method).should == "15.333333333333332"
- (0.6 / 2.4).send(@method).should == "0.25"
- (1.3 / 9.1).send(@method).should == "0.14285714285714288"
- (0.3 / 5.0).send(@method).should == "0.06"
- (5.0 / 4.2).send(@method).should == "1.1904761904761905"
- (3.0 / 2.0).send(@method).should == "1.5"
- (6.3 / 2.0).send(@method).should == "3.15"
- (5.4 / 6.0).send(@method).should == "0.9"
- (9.6 / 8.1).send(@method).should == "1.1851851851851851"
- (8.7 / 1.6).send(@method).should == "5.437499999999999"
- (1.9 / 7.8).send(@method).should == "0.24358974358974358"
- (0.5 / 2.1).send(@method).should == "0.23809523809523808"
- (9.3 / 5.8).send(@method).should == "1.6034482758620692"
- (2.7 / 8.0).send(@method).should == "0.3375"
- (9.7 / 7.8).send(@method).should == "1.2435897435897436"
- (8.1 / 2.4).send(@method).should == "3.375"
- (7.7 / 2.7).send(@method).should == "2.8518518518518516"
- (7.9 / 1.7).send(@method).should == "4.647058823529412"
- (6.5 / 8.2).send(@method).should == "0.7926829268292683"
- (7.8 / 9.6).send(@method).should == "0.8125"
- (2.2 / 4.6).send(@method).should == "0.47826086956521746"
- (0.0 / 1.0).send(@method).should == "0.0"
- (8.3 / 2.9).send(@method).should == "2.8620689655172415"
- (3.1 / 6.1).send(@method).should == "0.5081967213114754"
- (2.8 / 7.8).send(@method).should == "0.358974358974359"
- (8.0 / 0.1).send(@method).should == "80.0"
- (1.7 / 6.4).send(@method).should == "0.265625"
- (1.8 / 5.4).send(@method).should == "0.3333333333333333"
- (8.0 / 5.8).send(@method).should == "1.3793103448275863"
- (5.2 / 4.1).send(@method).should == "1.2682926829268295"
- (9.8 / 5.8).send(@method).should == "1.6896551724137934"
- (5.4 / 9.5).send(@method).should == "0.5684210526315789"
- (8.4 / 4.9).send(@method).should == "1.7142857142857142"
- (1.7 / 3.5).send(@method).should == "0.4857142857142857"
- (1.2 / 5.1).send(@method).should == "0.23529411764705882"
- (1.4 / 2.0).send(@method).should == "0.7"
- (4.8 / 8.0).send(@method).should == "0.6"
- (9.0 / 2.5).send(@method).should == "3.6"
- (0.2 / 0.6).send(@method).should == "0.33333333333333337"
- (7.8 / 5.2).send(@method).should == "1.5"
- (9.5 / 5.5).send(@method).should == "1.7272727272727273"
- end
- end
-
- describe 'encoding' do
- before :each do
- @internal = Encoding.default_internal
- end
-
- after :each do
- Encoding.default_internal = @internal
- end
-
- it "returns a String in US-ASCII encoding when Encoding.default_internal is nil" do
- Encoding.default_internal = nil
- 1.23.send(@method).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
- 5.47.send(@method).encoding.should equal(Encoding::US_ASCII)
- end
- end
-end
diff --git a/spec/ruby/core/float/to_int_spec.rb b/spec/ruby/core/float/to_int_spec.rb
index 084a58b431..ff70d508ff 100644
--- a/spec/ruby/core/float/to_int_spec.rb
+++ b/spec/ruby/core/float/to_int_spec.rb
@@ -1,6 +1,7 @@
require_relative '../../spec_helper'
-require_relative 'shared/to_i'
describe "Float#to_int" do
- it_behaves_like :float_to_i, :to_int
+ it "is an alias of Float#to_i" do
+ Float.instance_method(:to_int).should == Float.instance_method(:to_i)
+ end
end
diff --git a/spec/ruby/core/float/to_s_spec.rb b/spec/ruby/core/float/to_s_spec.rb
index 6727a883f8..3fd64581c2 100644
--- a/spec/ruby/core/float/to_s_spec.rb
+++ b/spec/ruby/core/float/to_s_spec.rb
@@ -1,6 +1,310 @@
require_relative '../../spec_helper'
-require_relative 'shared/to_s'
describe "Float#to_s" do
- it_behaves_like :float_to_s, :to_s
+ it "returns 'NaN' for NaN" do
+ nan_value().to_s.should == 'NaN'
+ end
+
+ it "returns 'Infinity' for positive infinity" do
+ infinity_value().to_s.should == 'Infinity'
+ end
+
+ it "returns '-Infinity' for negative infinity" do
+ (-infinity_value()).to_s.should == '-Infinity'
+ end
+
+ it "returns '0.0' for 0.0" do
+ 0.0.to_s.should == "0.0"
+ end
+
+ platform_is_not :openbsd do
+ it "emits '-' for -0.0" do
+ -0.0.to_s.should == "-0.0"
+ end
+ end
+
+ it "emits a '-' for negative values" do
+ -3.14.to_s.should == "-3.14"
+ end
+
+ it "emits a trailing '.0' for a whole number" do
+ 50.0.to_s.should == "50.0"
+ end
+
+ it "emits a trailing '.0' for the mantissa in e format" do
+ 1.0e20.to_s.should == "1.0e+20"
+ end
+
+ it "uses non-e format for a positive value with fractional part having 5 significant figures" do
+ 0.0001.to_s.should == "0.0001"
+ end
+
+ it "uses non-e format for a negative value with fractional part having 5 significant figures" do
+ -0.0001.to_s.should == "-0.0001"
+ end
+
+ it "uses e format for a positive value with fractional part having 6 significant figures" do
+ 0.00001.to_s.should == "1.0e-05"
+ end
+
+ it "uses e format for a negative value with fractional part having 6 significant figures" do
+ -0.00001.to_s.should == "-1.0e-05"
+ end
+
+ it "uses non-e format for a positive value with whole part having 15 significant figures" do
+ 10000000000000.0.to_s.should == "10000000000000.0"
+ end
+
+ it "uses non-e format for a negative value with whole part having 15 significant figures" do
+ -10000000000000.0.to_s.should == "-10000000000000.0"
+ end
+
+ it "uses non-e format for a positive value with whole part having 16 significant figures" do
+ 100000000000000.0.to_s.should == "100000000000000.0"
+ end
+
+ it "uses non-e format for a negative value with whole part having 16 significant figures" do
+ -100000000000000.0.to_s.should == "-100000000000000.0"
+ end
+
+ it "uses e format for a positive value with whole part having 18 significant figures" do
+ 10000000000000000.0.to_s.should == "1.0e+16"
+ end
+
+ it "uses e format for a negative value with whole part having 18 significant figures" do
+ -10000000000000000.0.to_s.should == "-1.0e+16"
+ end
+
+ it "uses e format for a positive value with whole part having 17 significant figures" do
+ 1000000000000000.0.to_s.should == "1.0e+15"
+ end
+
+ it "uses e format for a negative value with whole part having 17 significant figures" do
+ -1000000000000000.0.to_s.should == "-1.0e+15"
+ end
+
+ # #3273
+ it "outputs the minimal, unique form necessary to recreate the value" do
+ value = 0.21611564636388508
+ string = "0.21611564636388508"
+
+ value.to_s.should == string
+ string.to_f.should == value
+ end
+
+ it "outputs the minimal, unique form to represent the value" do
+ 0.56.to_s.should == "0.56"
+ end
+
+ describe "matches" do
+ it "random examples in all ranges" do
+ # 50.times do
+ # bytes = (0...8).map { rand(256) }
+ # string = bytes.pack('C8')
+ # float = string.unpack('D').first
+ # puts "#{'%.20g' % float}.to_s.should == #{float.to_s.inspect}"
+ # end
+
+ 2.5540217314354050325e+163.to_s.should == "2.554021731435405e+163"
+ 2.5492588360356597544e-172.to_s.should == "2.5492588360356598e-172"
+ 1.742770260934704852e-82.to_s.should == "1.7427702609347049e-82"
+ 6.2108093676180883209e-104.to_s.should == "6.210809367618088e-104"
+ -3.3448803488331067402e-143.to_s.should == "-3.3448803488331067e-143"
+ -2.2740074343500832557e-168.to_s.should == "-2.2740074343500833e-168"
+ 7.0587971678048535732e+191.to_s.should == "7.058797167804854e+191"
+ -284438.88327586348169.to_s.should == "-284438.8832758635"
+ 3.953272468476091301e+105.to_s.should == "3.9532724684760913e+105"
+ -3.6361359552959847853e+100.to_s.should == "-3.636135955295985e+100"
+ -1.3222325865575206185e-31.to_s.should == "-1.3222325865575206e-31"
+ 1.1440138916932761366e+130.to_s.should == "1.1440138916932761e+130"
+ 4.8750891560387561157e-286.to_s.should == "4.875089156038756e-286"
+ 5.6101113356591453525e-257.to_s.should == "5.610111335659145e-257"
+ -3.829644279545809575e-100.to_s.should == "-3.8296442795458096e-100"
+ 1.5342839401396406117e-194.to_s.should == "1.5342839401396406e-194"
+ 2.2284972755169921402e-144.to_s.should == "2.228497275516992e-144"
+ 2.1825655917065601737e-61.to_s.should == "2.1825655917065602e-61"
+ -2.6672271363524338322e-62.to_s.should == "-2.667227136352434e-62"
+ -1.9257995160119059415e+21.to_s.should == "-1.925799516011906e+21"
+ -8.9096732962887121718e-198.to_s.should == "-8.909673296288712e-198"
+ 2.0202075376548644959e-90.to_s.should == "2.0202075376548645e-90"
+ -7.7341602581786258961e-266.to_s.should == "-7.734160258178626e-266"
+ 3.5134482598733635046e+98.to_s.should == "3.5134482598733635e+98"
+ -2.124411722371029134e+154.to_s.should == "-2.124411722371029e+154"
+ -4.573908787355718687e+110.to_s.should == "-4.573908787355719e+110"
+ -1.9344425934170969879e-232.to_s.should == "-1.934442593417097e-232"
+ -1.3274227399979271095e+171.to_s.should == "-1.3274227399979271e+171"
+ 9.3495270482104442383e-283.to_s.should == "9.349527048210444e-283"
+ -4.2046059371986483233e+307.to_s.should == "-4.2046059371986483e+307"
+ 3.6133547278583543004e-117.to_s.should == "3.613354727858354e-117"
+ 4.9247416523566613499e-08.to_s.should == "4.9247416523566613e-08"
+ 1.6936145488250064007e-71.to_s.should == "1.6936145488250064e-71"
+ 2.4455483206829433098e+96.to_s.should == "2.4455483206829433e+96"
+ 7.9797449851436455384e+124.to_s.should == "7.979744985143646e+124"
+ -1.3873689634457876774e-129.to_s.should == "-1.3873689634457877e-129"
+ 3.9761102037533483075e+284.to_s.should == "3.976110203753348e+284"
+ -4.2819791952139402486e-303.to_s.should == "-4.28197919521394e-303"
+ -5.7981017546689831298e-116.to_s.should == "-5.798101754668983e-116"
+ -3.953266497860534199e-28.to_s.should == "-3.953266497860534e-28"
+ -2.0659852720290440959e-243.to_s.should == "-2.065985272029044e-243"
+ 8.9670488995878688018e-05.to_s.should == "8.967048899587869e-05"
+ -1.2317943708113061768e-98.to_s.should == "-1.2317943708113062e-98"
+ -3.8930768307633080463e+248.to_s.should == "-3.893076830763308e+248"
+ 6.5854032671803925627e-239.to_s.should == "6.5854032671803926e-239"
+ 4.6257022188980878952e+177.to_s.should == "4.625702218898088e+177"
+ -1.9397155125507235603e-187.to_s.should == "-1.9397155125507236e-187"
+ 8.5752156951245705056e+117.to_s.should == "8.57521569512457e+117"
+ -2.4784875958162501671e-132.to_s.should == "-2.4784875958162502e-132"
+ -4.4125691841230058457e-203.to_s.should == "-4.412569184123006e-203"
+ end
+
+ it "random examples in human ranges" do
+ # 50.times do
+ # formatted = ''
+ # rand(1..3).times do
+ # formatted << rand(10).to_s
+ # end
+ # formatted << '.'
+ # rand(1..9).times do
+ # formatted << rand(10).to_s
+ # end
+ # float = formatted.to_f
+ # puts "#{'%.20f' % float}.to_s.should == #{float.to_s.inspect}"
+ # end
+
+ 5.17869899999999994122.to_s.should == "5.178699"
+ 905.62695729999995819526.to_s.should == "905.6269573"
+ 62.75999999999999801048.to_s.should == "62.76"
+ 6.93856795800000014651.to_s.should == "6.938567958"
+ 4.95999999999999996447.to_s.should == "4.96"
+ 32.77993899999999882766.to_s.should == "32.779939"
+ 544.12756779999995160324.to_s.should == "544.1275678"
+ 66.25801119999999855281.to_s.should == "66.2580112"
+ 7.90000000000000035527.to_s.should == "7.9"
+ 5.93100000000000004974.to_s.should == "5.931"
+ 5.21229313600000043749.to_s.should == "5.212293136"
+ 503.44173809000000119340.to_s.should == "503.44173809"
+ 79.26000000000000511591.to_s.should == "79.26"
+ 8.51524999999999998579.to_s.should == "8.51525"
+ 174.00000000000000000000.to_s.should == "174.0"
+ 50.39580000000000126192.to_s.should == "50.3958"
+ 35.28999999999999914735.to_s.should == "35.29"
+ 5.43136675399999990788.to_s.should == "5.431366754"
+ 654.07680000000004838512.to_s.should == "654.0768"
+ 6.07423700000000010846.to_s.should == "6.074237"
+ 102.25779799999999397642.to_s.should == "102.257798"
+ 5.08129999999999970584.to_s.should == "5.0813"
+ 6.00000000000000000000.to_s.should == "6.0"
+ 8.30000000000000071054.to_s.should == "8.3"
+ 32.68345999999999662577.to_s.should == "32.68346"
+ 581.11170000000004165486.to_s.should == "581.1117"
+ 76.31342999999999676675.to_s.should == "76.31343"
+ 438.30826000000001840817.to_s.should == "438.30826"
+ 482.06631994000002805478.to_s.should == "482.06631994"
+ 55.92721026899999969828.to_s.should == "55.927210269"
+ 4.00000000000000000000.to_s.should == "4.0"
+ 55.86693999999999959982.to_s.should == "55.86694"
+ 787.98299999999994724931.to_s.should == "787.983"
+ 5.73810511000000023074.to_s.should == "5.73810511"
+ 74.51926810000000500622.to_s.should == "74.5192681"
+ 892.89999999999997726263.to_s.should == "892.9"
+ 68.27299999999999613465.to_s.should == "68.273"
+ 904.10000000000002273737.to_s.should == "904.1"
+ 5.23200000000000020606.to_s.should == "5.232"
+ 4.09628000000000014325.to_s.should == "4.09628"
+ 46.05152633699999853434.to_s.should == "46.051526337"
+ 142.12884990599999923688.to_s.should == "142.128849906"
+ 3.83057023500000015659.to_s.should == "3.830570235"
+ 11.81684594699999912848.to_s.should == "11.816845947"
+ 80.50000000000000000000.to_s.should == "80.5"
+ 382.18215010000000120272.to_s.should == "382.1821501"
+ 55.38444606899999911320.to_s.should == "55.384446069"
+ 5.78000000000000024869.to_s.should == "5.78"
+ 2.88244999999999995666.to_s.should == "2.88245"
+ 43.27709999999999723741.to_s.should == "43.2771"
+ end
+
+ it "random values from divisions" do
+ (1.0 / 7).to_s.should == "0.14285714285714285"
+
+ # 50.times do
+ # a = rand(10)
+ # b = rand(10)
+ # c = rand(10)
+ # d = rand(10)
+ # expression = "#{a}.#{b} / #{c}.#{d}"
+ # puts " (#{expression}).to_s.should == #{eval(expression).to_s.inspect}"
+ # end
+
+ (1.1 / 7.1).to_s.should == "0.15492957746478875"
+ (6.5 / 8.8).to_s.should == "0.7386363636363635"
+ (4.8 / 4.3).to_s.should == "1.1162790697674418"
+ (4.0 / 1.9).to_s.should == "2.1052631578947367"
+ (9.1 / 0.8).to_s.should == "11.374999999999998"
+ (5.3 / 7.5).to_s.should == "0.7066666666666667"
+ (2.8 / 1.8).to_s.should == "1.5555555555555554"
+ (2.1 / 2.5).to_s.should == "0.8400000000000001"
+ (3.5 / 6.0).to_s.should == "0.5833333333333334"
+ (4.6 / 0.3).to_s.should == "15.333333333333332"
+ (0.6 / 2.4).to_s.should == "0.25"
+ (1.3 / 9.1).to_s.should == "0.14285714285714288"
+ (0.3 / 5.0).to_s.should == "0.06"
+ (5.0 / 4.2).to_s.should == "1.1904761904761905"
+ (3.0 / 2.0).to_s.should == "1.5"
+ (6.3 / 2.0).to_s.should == "3.15"
+ (5.4 / 6.0).to_s.should == "0.9"
+ (9.6 / 8.1).to_s.should == "1.1851851851851851"
+ (8.7 / 1.6).to_s.should == "5.437499999999999"
+ (1.9 / 7.8).to_s.should == "0.24358974358974358"
+ (0.5 / 2.1).to_s.should == "0.23809523809523808"
+ (9.3 / 5.8).to_s.should == "1.6034482758620692"
+ (2.7 / 8.0).to_s.should == "0.3375"
+ (9.7 / 7.8).to_s.should == "1.2435897435897436"
+ (8.1 / 2.4).to_s.should == "3.375"
+ (7.7 / 2.7).to_s.should == "2.8518518518518516"
+ (7.9 / 1.7).to_s.should == "4.647058823529412"
+ (6.5 / 8.2).to_s.should == "0.7926829268292683"
+ (7.8 / 9.6).to_s.should == "0.8125"
+ (2.2 / 4.6).to_s.should == "0.47826086956521746"
+ (0.0 / 1.0).to_s.should == "0.0"
+ (8.3 / 2.9).to_s.should == "2.8620689655172415"
+ (3.1 / 6.1).to_s.should == "0.5081967213114754"
+ (2.8 / 7.8).to_s.should == "0.358974358974359"
+ (8.0 / 0.1).to_s.should == "80.0"
+ (1.7 / 6.4).to_s.should == "0.265625"
+ (1.8 / 5.4).to_s.should == "0.3333333333333333"
+ (8.0 / 5.8).to_s.should == "1.3793103448275863"
+ (5.2 / 4.1).to_s.should == "1.2682926829268295"
+ (9.8 / 5.8).to_s.should == "1.6896551724137934"
+ (5.4 / 9.5).to_s.should == "0.5684210526315789"
+ (8.4 / 4.9).to_s.should == "1.7142857142857142"
+ (1.7 / 3.5).to_s.should == "0.4857142857142857"
+ (1.2 / 5.1).to_s.should == "0.23529411764705882"
+ (1.4 / 2.0).to_s.should == "0.7"
+ (4.8 / 8.0).to_s.should == "0.6"
+ (9.0 / 2.5).to_s.should == "3.6"
+ (0.2 / 0.6).to_s.should == "0.33333333333333337"
+ (7.8 / 5.2).to_s.should == "1.5"
+ (9.5 / 5.5).to_s.should == "1.7272727272727273"
+ end
+ end
+
+ describe 'encoding' do
+ before :each do
+ @internal = Encoding.default_internal
+ end
+
+ after :each do
+ Encoding.default_internal = @internal
+ end
+
+ it "returns a String in US-ASCII encoding when Encoding.default_internal is nil" do
+ Encoding.default_internal = nil
+ 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
+ 5.47.to_s.encoding.should.equal?(Encoding::US_ASCII)
+ end
+ end
end
diff --git a/spec/ruby/core/float/truncate_spec.rb b/spec/ruby/core/float/truncate_spec.rb
index 2c80145f9f..1750e3fdbc 100644
--- a/spec/ruby/core/float/truncate_spec.rb
+++ b/spec/ruby/core/float/truncate_spec.rb
@@ -5,10 +5,10 @@ describe "Float#truncate" do
it_behaves_like :float_to_i, :truncate
it "returns self truncated to an optionally given precision" do
- 2.1679.truncate(0).should eql(2)
- 7.1.truncate(1).should eql(7.1)
- 214.94.truncate(-1).should eql(210)
- -1.234.truncate(2).should eql(-1.23)
- 5.123812.truncate(4).should eql(5.1238)
+ 2.1679.truncate(0).should.eql?(2)
+ 7.1.truncate(1).should.eql?(7.1)
+ 214.94.truncate(-1).should.eql?(210)
+ -1.234.truncate(2).should.eql?(-1.23)
+ 5.123812.truncate(4).should.eql?(5.1238)
end
end
diff --git a/spec/ruby/core/float/uplus_spec.rb b/spec/ruby/core/float/uplus_spec.rb
index 936123558c..b979b2717a 100644
--- a/spec/ruby/core/float/uplus_spec.rb
+++ b/spec/ruby/core/float/uplus_spec.rb
@@ -4,6 +4,6 @@ describe "Float#+@" do
it "returns the same value with same sign (twos complement)" do
34.56.send(:+@).should == 34.56
-34.56.send(:+@).should == -34.56
- 0.0.send(:+@).should eql(0.0)
+ 0.0.send(:+@).should.eql?(0.0)
end
end
diff --git a/spec/ruby/core/gc/config_spec.rb b/spec/ruby/core/gc/config_spec.rb
new file mode 100644
index 0000000000..57160f122c
--- /dev/null
+++ b/spec/ruby/core/gc/config_spec.rb
@@ -0,0 +1,97 @@
+require_relative '../../spec_helper'
+
+ruby_version_is "3.4" do
+ describe "GC.config" do
+ context "without arguments" do
+ it "returns a hash of current settings" do
+ GC.config.should.is_a?(Hash)
+ end
+
+ it "includes the name of currently loaded GC implementation as a global key" do
+ GC.config.should.include?(:implementation)
+ GC.config[:implementation].should.is_a?(String)
+ end
+ end
+
+ context "with a hash of options" do
+ it "allows to set GC implementation's options, returning the new config" do
+ config = GC.config({})
+ # Try to find a boolean setting to reliably test changing it.
+ key, _value = config.find { |_k, v| v == true }
+ skip unless key
+
+ GC.config(key => false).should == config.merge(key => false)
+ GC.config[key].should == false
+ GC.config(key => true).should == config
+ GC.config[key].should == true
+ ensure
+ GC.config(config.except(:implementation))
+ end
+
+ it "does not change settings that aren't present in the hash" do
+ previous = GC.config
+ GC.config({})
+ GC.config.should == previous
+ end
+
+ it "ignores unknown keys" do
+ previous = GC.config
+ GC.config(foo: "bar")
+ GC.config.should == previous
+ end
+
+ ruby_version_is ""..."4.0" do
+ it "returns the same as GC.config but without the :implementation key" do
+ previous = GC.config
+ GC.config({}).should == previous.except(:implementation)
+ end
+ end
+
+ ruby_version_is "4.0" do
+ it "returns the same as GC.config, including the :implementation key" do
+ previous = GC.config
+ GC.config({}).should == previous
+ end
+ end
+
+ it "raises an ArgumentError if options include global keys" do
+ -> { GC.config(implementation: "default") }.should.raise(ArgumentError, 'Attempting to set read-only key "Implementation"')
+ end
+ end
+
+ context "with a non-hash argument" do
+ it "returns current settings if argument is nil" do
+ GC.config(nil).should == GC.config
+ end
+
+ it "raises ArgumentError for all other arguments" do
+ -> { GC.config([]) }.should.raise(ArgumentError)
+ -> { GC.config("default") }.should.raise(ArgumentError)
+ -> { GC.config(1) }.should.raise(ArgumentError)
+ end
+ end
+
+ guard -> { PlatformGuard.standard? && GC.config[:implementation] == "default" } do
+ context "with default GC implementation on MRI" do
+ before do
+ @default_config = GC.config({})
+ end
+
+ after do
+ GC.config(@default_config.except(:implementation))
+ end
+
+ it "includes :rgengc_allow_full_mark option, true by default" do
+ GC.config.should.include?(:rgengc_allow_full_mark)
+ GC.config[:rgengc_allow_full_mark].should == true
+ end
+
+ it "allows to set :rgengc_allow_full_mark" do
+ # This key maps truthy and falsey values to true and false.
+ GC.config(rgengc_allow_full_mark: nil).should == @default_config.merge(rgengc_allow_full_mark: false)
+ GC.config(rgengc_allow_full_mark: 1.23).should == @default_config.merge(rgengc_allow_full_mark: true)
+ end
+ end
+ end
+ end
+end
diff --git a/spec/ruby/core/gc/count_spec.rb b/spec/ruby/core/gc/count_spec.rb
index af2fbbe713..fe20c4ed2b 100644
--- a/spec/ruby/core/gc/count_spec.rb
+++ b/spec/ruby/core/gc/count_spec.rb
@@ -2,7 +2,7 @@ require_relative '../../spec_helper'
describe "GC.count" do
it "returns an integer" do
- GC.count.should be_kind_of(Integer)
+ GC.count.should.is_a?(Integer)
end
it "increases as collections are run" do
diff --git a/spec/ruby/core/gc/profiler/enabled_spec.rb b/spec/ruby/core/gc/profiler/enabled_spec.rb
index 23677be555..cfcd0951f0 100644
--- a/spec/ruby/core/gc/profiler/enabled_spec.rb
+++ b/spec/ruby/core/gc/profiler/enabled_spec.rb
@@ -11,11 +11,11 @@ describe "GC::Profiler.enabled?" do
it "reports as enabled when enabled" do
GC::Profiler.enable
- GC::Profiler.enabled?.should be_true
+ GC::Profiler.enabled?.should == true
end
it "reports as disabled when disabled" do
GC::Profiler.disable
- GC::Profiler.enabled?.should be_false
+ GC::Profiler.enabled?.should == false
end
end
diff --git a/spec/ruby/core/gc/profiler/result_spec.rb b/spec/ruby/core/gc/profiler/result_spec.rb
index 2ab46a8371..e888f975dc 100644
--- a/spec/ruby/core/gc/profiler/result_spec.rb
+++ b/spec/ruby/core/gc/profiler/result_spec.rb
@@ -2,6 +2,6 @@ require_relative '../../../spec_helper'
describe "GC::Profiler.result" do
it "returns a string" do
- GC::Profiler.result.should be_kind_of(String)
+ GC::Profiler.result.should.is_a?(String)
end
end
diff --git a/spec/ruby/core/gc/profiler/total_time_spec.rb b/spec/ruby/core/gc/profiler/total_time_spec.rb
index 7709f168dd..a351e922af 100644
--- a/spec/ruby/core/gc/profiler/total_time_spec.rb
+++ b/spec/ruby/core/gc/profiler/total_time_spec.rb
@@ -2,6 +2,6 @@ require_relative '../../../spec_helper'
describe "GC::Profiler.total_time" do
it "returns an float" do
- GC::Profiler.total_time.should be_kind_of(Float)
+ GC::Profiler.total_time.should.is_a?(Float)
end
end
diff --git a/spec/ruby/core/gc/stat_spec.rb b/spec/ruby/core/gc/stat_spec.rb
index 3b43b28a92..6e4800b3e3 100644
--- a/spec/ruby/core/gc/stat_spec.rb
+++ b/spec/ruby/core/gc/stat_spec.rb
@@ -3,7 +3,7 @@ require_relative '../../spec_helper'
describe "GC.stat" do
it "returns hash of values" do
stat = GC.stat
- stat.should be_kind_of(Hash)
+ stat.should.is_a?(Hash)
stat.keys.should.include?(:count)
end
@@ -11,18 +11,18 @@ describe "GC.stat" do
hash = { count: "hello", __other__: "world" }
stat = GC.stat(hash)
- stat.should be_kind_of(Hash)
- stat.should equal hash
- stat[:count].should be_kind_of(Integer)
+ stat.should.is_a?(Hash)
+ stat.should.equal? hash
+ stat[:count].should.is_a?(Integer)
stat[:__other__].should == "world"
end
it "the values are all Integer since rb_gc_stat() returns size_t" do
- GC.stat.values.each { |value| value.should be_kind_of(Integer) }
+ GC.stat.values.each { |value| value.should.is_a?(Integer) }
end
it "can return a single value" do
- GC.stat(:count).should be_kind_of(Integer)
+ GC.stat(:count).should.is_a?(Integer)
end
it "increases count after GC is run" do
@@ -38,25 +38,25 @@ describe "GC.stat" do
end
it "provides some number for count" do
- GC.stat(:count).should be_kind_of(Integer)
- GC.stat[:count].should be_kind_of(Integer)
+ GC.stat(:count).should.is_a?(Integer)
+ GC.stat[:count].should.is_a?(Integer)
end
it "provides some number for heap_free_slots" do
- GC.stat(:heap_free_slots).should be_kind_of(Integer)
- GC.stat[:heap_free_slots].should be_kind_of(Integer)
+ GC.stat(:heap_free_slots).should.is_a?(Integer)
+ GC.stat[:heap_free_slots].should.is_a?(Integer)
end
it "provides some number for total_allocated_objects" do
- GC.stat(:total_allocated_objects).should be_kind_of(Integer)
- GC.stat[:total_allocated_objects].should be_kind_of(Integer)
+ GC.stat(:total_allocated_objects).should.is_a?(Integer)
+ GC.stat[:total_allocated_objects].should.is_a?(Integer)
end
it "raises an error if argument is not nil, a symbol, or a hash" do
- -> { GC.stat(7) }.should raise_error(TypeError, "non-hash or symbol given")
+ -> { GC.stat(7) }.should.raise(TypeError, "non-hash or symbol given")
end
it "raises an error if an unknown key is given" do
- -> { GC.stat(:foo) }.should raise_error(ArgumentError, "unknown key: foo")
+ -> { GC.stat(:foo) }.should.raise(ArgumentError, "unknown key: foo")
end
end
diff --git a/spec/ruby/core/gc/stress_spec.rb b/spec/ruby/core/gc/stress_spec.rb
index ca62c0cb4e..227a795e7f 100644
--- a/spec/ruby/core/gc/stress_spec.rb
+++ b/spec/ruby/core/gc/stress_spec.rb
@@ -7,11 +7,11 @@ describe "GC.stress" do
end
it "returns current status of GC stress mode" do
- GC.stress.should be_false
+ GC.stress.should == false
GC.stress = true
- GC.stress.should be_true
+ GC.stress.should == true
GC.stress = false
- GC.stress.should be_false
+ GC.stress.should == false
end
end
@@ -22,6 +22,6 @@ describe "GC.stress=" do
it "sets the stress mode" do
GC.stress = true
- GC.stress.should be_true
+ GC.stress.should == true
end
end
diff --git a/spec/ruby/core/gc/total_time_spec.rb b/spec/ruby/core/gc/total_time_spec.rb
index a8430fbe9a..f10e0ad742 100644
--- a/spec/ruby/core/gc/total_time_spec.rb
+++ b/spec/ruby/core/gc/total_time_spec.rb
@@ -2,7 +2,7 @@ require_relative '../../spec_helper'
describe "GC.total_time" do
it "returns an Integer" do
- GC.total_time.should be_kind_of(Integer)
+ GC.total_time.should.is_a?(Integer)
end
it "increases as collections are run" do
diff --git a/spec/ruby/core/hash/allocate_spec.rb b/spec/ruby/core/hash/allocate_spec.rb
index 93420de866..a92accc161 100644
--- a/spec/ruby/core/hash/allocate_spec.rb
+++ b/spec/ruby/core/hash/allocate_spec.rb
@@ -3,7 +3,7 @@ require_relative '../../spec_helper'
describe "Hash.allocate" do
it "returns an instance of Hash" do
hsh = Hash.allocate
- hsh.should be_an_instance_of(Hash)
+ hsh.should.instance_of?(Hash)
end
it "returns a fully-formed instance of Hash" do
diff --git a/spec/ruby/core/hash/assoc_spec.rb b/spec/ruby/core/hash/assoc_spec.rb
index 62b2a11b30..51af51a20f 100644
--- a/spec/ruby/core/hash/assoc_spec.rb
+++ b/spec/ruby/core/hash/assoc_spec.rb
@@ -6,7 +6,7 @@ describe "Hash#assoc" do
end
it "returns an Array if the argument is == to a key of the Hash" do
- @h.assoc(:apple).should be_an_instance_of(Array)
+ @h.assoc(:apple).should.instance_of?(Array)
end
it "returns a 2-element Array if the argument is == to a key of the Hash" do
@@ -40,11 +40,11 @@ describe "Hash#assoc" do
end
it "returns nil if the argument is not a key of the Hash" do
- @h.assoc(:green).should be_nil
+ @h.assoc(:green).should == nil
end
it "returns nil if the argument is not a key of the Hash even when there is a default" do
- Hash.new(42).merge!( foo: :bar ).assoc(42).should be_nil
- Hash.new{|h, k| h[k] = 42}.merge!( foo: :bar ).assoc(42).should be_nil
+ Hash.new(42).merge!( foo: :bar ).assoc(42).should == nil
+ Hash.new{|h, k| h[k] = 42}.merge!( foo: :bar ).assoc(42).should == nil
end
end
diff --git a/spec/ruby/core/hash/clear_spec.rb b/spec/ruby/core/hash/clear_spec.rb
index cf05e36ac9..beff925a63 100644
--- a/spec/ruby/core/hash/clear_spec.rb
+++ b/spec/ruby/core/hash/clear_spec.rb
@@ -4,7 +4,7 @@ require_relative 'fixtures/classes'
describe "Hash#clear" do
it "removes all key, value pairs" do
h = { 1 => 2, 3 => 4 }
- h.clear.should equal(h)
+ h.clear.should.equal?(h)
h.should == {}
end
@@ -26,7 +26,7 @@ describe "Hash#clear" do
end
it "raises a FrozenError if called on a frozen instance" do
- -> { HashSpecs.frozen_hash.clear }.should raise_error(FrozenError)
- -> { HashSpecs.empty_frozen_hash.clear }.should raise_error(FrozenError)
+ -> { HashSpecs.frozen_hash.clear }.should.raise(FrozenError)
+ -> { HashSpecs.empty_frozen_hash.clear }.should.raise(FrozenError)
end
end
diff --git a/spec/ruby/core/hash/clone_spec.rb b/spec/ruby/core/hash/clone_spec.rb
index 6c96fc0c67..d135a84453 100644
--- a/spec/ruby/core/hash/clone_spec.rb
+++ b/spec/ruby/core/hash/clone_spec.rb
@@ -7,6 +7,6 @@ describe "Hash#clone" do
clone = hash.clone
clone.should == hash
- clone.should_not equal hash
+ clone.should_not.equal? hash
end
end
diff --git a/spec/ruby/core/hash/compact_spec.rb b/spec/ruby/core/hash/compact_spec.rb
index 76aa43949d..de83dabed3 100644
--- a/spec/ruby/core/hash/compact_spec.rb
+++ b/spec/ruby/core/hash/compact_spec.rb
@@ -10,7 +10,7 @@ describe "Hash#compact" do
it "returns new object that rejects pair has nil value" do
ret = @hash.compact
- ret.should_not equal(@hash)
+ ret.should_not.equal?(@hash)
ret.should == @compact
end
@@ -19,28 +19,26 @@ describe "Hash#compact" do
@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 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 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
+ 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
@@ -52,7 +50,7 @@ describe "Hash#compact!" do
end
it "returns self" do
- @hash.compact!.should equal(@hash)
+ @hash.compact!.should.equal?(@hash)
end
it "rejects own pair has nil value" do
@@ -66,7 +64,7 @@ describe "Hash#compact!" do
end
it "returns nil" do
- @hash.compact!.should be_nil
+ @hash.compact!.should == nil
end
end
@@ -76,7 +74,7 @@ describe "Hash#compact!" do
end
it "keeps pairs and raises a FrozenError" do
- ->{ @hash.compact! }.should raise_error(FrozenError)
+ ->{ @hash.compact! }.should.raise(FrozenError)
@hash.should == @initial_pairs
end
end
diff --git a/spec/ruby/core/hash/compare_by_identity_spec.rb b/spec/ruby/core/hash/compare_by_identity_spec.rb
index 2975526a97..1abf9d5666 100644
--- a/spec/ruby/core/hash/compare_by_identity_spec.rb
+++ b/spec/ruby/core/hash/compare_by_identity_spec.rb
@@ -11,7 +11,7 @@ describe "Hash#compare_by_identity" do
@h[[1]] = :a
@h[[1]].should == :a
@h.compare_by_identity
- @h[[1].dup].should be_nil
+ @h[[1].dup].should == nil
end
it "rehashes internally so that old keys can be looked up" do
@@ -27,21 +27,21 @@ describe "Hash#compare_by_identity" do
it "returns self" do
h = {}
h[:foo] = :bar
- h.compare_by_identity.should equal h
+ h.compare_by_identity.should.equal? h
end
it "has no effect on an already compare_by_identity hash" do
@idh[:foo] = :bar
- @idh.compare_by_identity.should equal @idh
+ @idh.compare_by_identity.should.equal? @idh
@idh.should.compare_by_identity?
@idh[:foo].should == :bar
end
it "uses the semantics of BasicObject#equal? to determine key identity" do
- [1].should_not equal([1])
+ [1].should_not.equal?([1])
@idh[[1]] = :c
@idh[[1]] = :d
- :bar.should equal(:bar)
+ :bar.should.equal?(:bar)
@idh[:bar] = :e
@idh[:bar] = :f
@idh.values.should == [:c, :d, :f]
@@ -64,13 +64,13 @@ describe "Hash#compare_by_identity" do
it "regards #dup'd objects as having different identities" do
key = ['foo']
@idh[key.dup] = :str
- @idh[key].should be_nil
+ @idh[key].should == nil
end
it "regards #clone'd objects as having different identities" do
key = ['foo']
@idh[key.clone] = :str
- @idh[key].should be_nil
+ @idh[key].should == nil
end
it "regards references to the same object as having the same identity" do
@@ -82,7 +82,7 @@ describe "Hash#compare_by_identity" do
it "raises a FrozenError on frozen hashes" do
@h = @h.freeze
- -> { @h.compare_by_identity }.should raise_error(FrozenError)
+ -> { @h.compare_by_identity }.should.raise(FrozenError)
end
# Behaviour confirmed in https://bugs.ruby-lang.org/issues/1871
@@ -107,7 +107,7 @@ describe "Hash#compare_by_identity" do
@idh[foo] = true
@idh[foo] = true
@idh.size.should == 1
- @idh.keys.first.should equal foo
+ @idh.keys.first.should.equal? foo
end
# Check `#[]=` call with a String literal.
@@ -128,20 +128,20 @@ end
describe "Hash#compare_by_identity?" do
it "returns false by default" do
h = {}
- h.compare_by_identity?.should be_false
+ h.compare_by_identity?.should == false
end
it "returns true once #compare_by_identity has been invoked on self" do
h = {}
h.compare_by_identity
- h.compare_by_identity?.should be_true
+ h.compare_by_identity?.should == true
end
it "returns true when called multiple times on the same ident hash" do
h = {}
h.compare_by_identity
- h.compare_by_identity?.should be_true
- h.compare_by_identity?.should be_true
- h.compare_by_identity?.should be_true
+ h.compare_by_identity?.should == true
+ h.compare_by_identity?.should == true
+ h.compare_by_identity?.should == true
end
end
diff --git a/spec/ruby/core/hash/constructor_spec.rb b/spec/ruby/core/hash/constructor_spec.rb
index 8d29773909..c16f373160 100644
--- a/spec/ruby/core/hash/constructor_spec.rb
+++ b/spec/ruby/core/hash/constructor_spec.rb
@@ -44,23 +44,23 @@ describe "Hash.[]" do
it "raises for elements that are not arrays" do
-> {
- Hash[[:a]].should == {}
- }.should raise_error(ArgumentError)
+ Hash[[:a]]
+ }.should.raise(ArgumentError, "wrong element type Symbol at 0 (expected array)")
-> {
- Hash[[:nil]].should == {}
- }.should raise_error(ArgumentError)
+ Hash[[nil]]
+ }.should.raise(ArgumentError, "wrong element type nil at 0 (expected array)")
end
it "raises an ArgumentError for arrays of more than 2 elements" do
- ->{ Hash[[[:a, :b, :c]]].should == {} }.should raise_error(ArgumentError)
+ ->{
+ Hash[[[:a, :b, :c]]]
+ }.should.raise(ArgumentError, "invalid number of elements (3 for 1..2)")
end
it "raises an ArgumentError when passed a list of value-invalid-pairs in an array" do
-> {
- -> {
- Hash[[[:a, 1], [:b], 42, [:d, 2], [:e, 2, 3], []]]
- }.should complain(/ignoring wrong elements/)
- }.should raise_error(ArgumentError)
+ Hash[[[:a, 1], [:b], 42, [:d, 2], [:e, 2, 3], []]]
+ }.should.raise(ArgumentError, "wrong element type Integer at 2 (expected array)")
end
describe "passed a single argument which responds to #to_hash" do
@@ -71,13 +71,13 @@ describe "Hash.[]" do
result = Hash[to_hash]
result.should == h
- result.should_not equal(h)
+ result.should_not.equal?(h)
end
end
it "raises an ArgumentError when passed an odd number of arguments" do
- -> { Hash[1, 2, 3] }.should raise_error(ArgumentError)
- -> { Hash[1, 2, { 3 => 4 }] }.should raise_error(ArgumentError)
+ -> { Hash[1, 2, 3] }.should.raise(ArgumentError)
+ -> { Hash[1, 2, { 3 => 4 }] }.should.raise(ArgumentError)
end
it "calls to_hash" do
@@ -87,42 +87,41 @@ describe "Hash.[]" do
end
it "returns an instance of a subclass when passed an Array" do
- HashSpecs::MyHash[1,2,3,4].should be_an_instance_of(HashSpecs::MyHash)
+ HashSpecs::MyHash[1,2,3,4].should.instance_of?(HashSpecs::MyHash)
end
it "returns instances of subclasses" do
- HashSpecs::MyHash[].should be_an_instance_of(HashSpecs::MyHash)
+ HashSpecs::MyHash[].should.instance_of?(HashSpecs::MyHash)
end
it "returns an instance of the class it's called on" do
Hash[HashSpecs::MyHash[1, 2]].class.should == Hash
- HashSpecs::MyHash[Hash[1, 2]].should be_an_instance_of(HashSpecs::MyHash)
+ HashSpecs::MyHash[Hash[1, 2]].should.instance_of?(HashSpecs::MyHash)
end
it "does not call #initialize on the subclass instance" do
- HashSpecs::MyInitializerHash[Hash[1, 2]].should be_an_instance_of(HashSpecs::MyInitializerHash)
+ HashSpecs::MyInitializerHash[Hash[1, 2]].should.instance_of?(HashSpecs::MyInitializerHash)
end
- it "removes the default value" do
+ it "does not retain the default value" do
hash = Hash.new(1)
- Hash[hash].default.should be_nil
+ Hash[hash].default.should == nil
hash[:a] = 1
- Hash[hash].default.should be_nil
+ Hash[hash].default.should == nil
end
- it "removes the default_proc" do
+ it "does not retain the default_proc" do
hash = Hash.new { |h, k| h[k] = [] }
- Hash[hash].default_proc.should be_nil
+ Hash[hash].default_proc.should == nil
hash[:a] = 1
- Hash[hash].default_proc.should be_nil
+ Hash[hash].default_proc.should == 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
+ it "does not retain compare_by_identity flag" do
+ hash = { a: 1 }.compare_by_identity
+ Hash[hash].compare_by_identity?.should == false
+
+ hash = {}.compare_by_identity
+ Hash[hash].compare_by_identity?.should == false
end
end
diff --git a/spec/ruby/core/hash/deconstruct_keys_spec.rb b/spec/ruby/core/hash/deconstruct_keys_spec.rb
index bbcd8932e5..f6ff3a2818 100644
--- a/spec/ruby/core/hash/deconstruct_keys_spec.rb
+++ b/spec/ruby/core/hash/deconstruct_keys_spec.rb
@@ -4,13 +4,13 @@ describe "Hash#deconstruct_keys" do
it "returns self" do
hash = {a: 1, b: 2}
- hash.deconstruct_keys([:a, :b]).should equal hash
+ hash.deconstruct_keys([:a, :b]).should.equal? hash
end
it "requires one argument" do
-> {
{a: 1}.deconstruct_keys
- }.should raise_error(ArgumentError, /wrong number of arguments \(given 0, expected 1\)/)
+ }.should.raise(ArgumentError, /wrong number of arguments \(given 0, expected 1\)/)
end
it "ignores argument" do
diff --git a/spec/ruby/core/hash/default_proc_spec.rb b/spec/ruby/core/hash/default_proc_spec.rb
index f4e4803632..4830e02acd 100644
--- a/spec/ruby/core/hash/default_proc_spec.rb
+++ b/spec/ruby/core/hash/default_proc_spec.rb
@@ -25,24 +25,24 @@ describe "Hash#default_proc=" do
h = Hash.new { 'Paris' }
obj = mock('to_proc')
obj.should_receive(:to_proc).and_return(Proc.new { 'Montreal' })
- (h.default_proc = obj).should equal(obj)
+ (h.default_proc = obj).should.equal?(obj)
h[:cool_city].should == 'Montreal'
end
it "overrides the static default" do
h = Hash.new(42)
h.default_proc = Proc.new { 6 }
- h.default.should be_nil
+ h.default.should == nil
h.default_proc.call.should == 6
end
it "raises an error if passed stuff not convertible to procs" do
- ->{{}.default_proc = 42}.should raise_error(TypeError)
+ ->{{}.default_proc = 42}.should.raise(TypeError)
end
it "returns the passed Proc" do
new_proc = Proc.new {}
- ({}.default_proc = new_proc).should equal(new_proc)
+ ({}.default_proc = new_proc).should.equal?(new_proc)
end
it "clears the default proc if passed nil" do
@@ -53,28 +53,28 @@ describe "Hash#default_proc=" do
end
it "returns nil if passed nil" do
- ({}.default_proc = nil).should be_nil
+ ({}.default_proc = nil).should == nil
end
it "accepts a lambda with an arity of 2" do
h = {}
-> do
h.default_proc = -> a, b { }
- end.should_not raise_error(TypeError)
+ end.should_not.raise(TypeError)
end
it "raises a TypeError if passed a lambda with an arity other than 2" do
h = {}
-> do
h.default_proc = -> a { }
- end.should raise_error(TypeError)
+ end.should.raise(TypeError)
-> do
h.default_proc = -> a, b, c { }
- end.should raise_error(TypeError)
+ end.should.raise(TypeError)
end
it "raises a FrozenError if self is frozen" do
- -> { {}.freeze.default_proc = Proc.new {} }.should raise_error(FrozenError)
- -> { {}.freeze.default_proc = nil }.should raise_error(FrozenError)
+ -> { {}.freeze.default_proc = Proc.new {} }.should.raise(FrozenError)
+ -> { {}.freeze.default_proc = nil }.should.raise(FrozenError)
end
end
diff --git a/spec/ruby/core/hash/default_spec.rb b/spec/ruby/core/hash/default_spec.rb
index d8b62ea196..17ee032e2b 100644
--- a/spec/ruby/core/hash/default_spec.rb
+++ b/spec/ruby/core/hash/default_spec.rb
@@ -40,7 +40,7 @@ describe "Hash#default=" do
end
it "raises a FrozenError if called on a frozen instance" do
- -> { HashSpecs.frozen_hash.default = nil }.should raise_error(FrozenError)
- -> { HashSpecs.empty_frozen_hash.default = nil }.should raise_error(FrozenError)
+ -> { HashSpecs.frozen_hash.default = nil }.should.raise(FrozenError)
+ -> { HashSpecs.empty_frozen_hash.default = nil }.should.raise(FrozenError)
end
end
diff --git a/spec/ruby/core/hash/delete_if_spec.rb b/spec/ruby/core/hash/delete_if_spec.rb
index c9e670ffc3..3090633d88 100644
--- a/spec/ruby/core/hash/delete_if_spec.rb
+++ b/spec/ruby/core/hash/delete_if_spec.rb
@@ -12,13 +12,13 @@ describe "Hash#delete_if" do
it "removes every entry for which block is true and returns self" do
h = { a: 1, b: 2, c: 3, d: 4 }
- h.delete_if { |k,v| v % 2 == 1 }.should equal(h)
+ h.delete_if { |k,v| v % 2 == 1 }.should.equal?(h)
h.should == { b: 2, d: 4 }
end
it "removes all entries if the block is true" do
h = { a: 1, b: 2, c: 3 }
- h.delete_if { |k,v| true }.should equal(h)
+ h.delete_if { |k,v| true }.should.equal?(h)
h.should == {}
end
@@ -35,8 +35,8 @@ describe "Hash#delete_if" do
end
it "raises a FrozenError if called on a frozen instance" do
- -> { HashSpecs.frozen_hash.delete_if { false } }.should raise_error(FrozenError)
- -> { HashSpecs.empty_frozen_hash.delete_if { true } }.should raise_error(FrozenError)
+ -> { HashSpecs.frozen_hash.delete_if { false } }.should.raise(FrozenError)
+ -> { HashSpecs.empty_frozen_hash.delete_if { true } }.should.raise(FrozenError)
end
it_behaves_like :hash_iteration_no_block, :delete_if
diff --git a/spec/ruby/core/hash/delete_spec.rb b/spec/ruby/core/hash/delete_spec.rb
index 3e3479c69c..33ff01bf36 100644
--- a/spec/ruby/core/hash/delete_spec.rb
+++ b/spec/ruby/core/hash/delete_spec.rb
@@ -52,7 +52,7 @@ describe "Hash#delete" do
end
it "raises a FrozenError if called on a frozen instance" do
- -> { HashSpecs.frozen_hash.delete("foo") }.should raise_error(FrozenError)
- -> { HashSpecs.empty_frozen_hash.delete("foo") }.should raise_error(FrozenError)
+ -> { HashSpecs.frozen_hash.delete("foo") }.should.raise(FrozenError)
+ -> { HashSpecs.empty_frozen_hash.delete("foo") }.should.raise(FrozenError)
end
end
diff --git a/spec/ruby/core/hash/dig_spec.rb b/spec/ruby/core/hash/dig_spec.rb
index aa0ecadd2f..94ac94e850 100644
--- a/spec/ruby/core/hash/dig_spec.rb
+++ b/spec/ruby/core/hash/dig_spec.rb
@@ -5,16 +5,16 @@ describe "Hash#dig" do
it "returns #[] with one arg" do
h = { 0 => false, a: 1 }
h.dig(:a).should == 1
- h.dig(0).should be_false
- h.dig(1).should be_nil
+ h.dig(0).should == false
+ h.dig(1).should == nil
end
it "returns the nested value specified by the sequence of keys" do
h = { foo: { bar: { baz: 1 } } }
h.dig(:foo, :bar, :baz).should == 1
- h.dig(:foo, :bar, :nope).should be_nil
- h.dig(:foo, :baz).should be_nil
- h.dig(:bar, :baz, :foo).should be_nil
+ h.dig(:foo, :bar, :nope).should == nil
+ h.dig(:foo, :baz).should == nil
+ h.dig(:bar, :baz, :foo).should == nil
end
it "returns the nested value specified if the sequence includes an index" do
@@ -28,7 +28,7 @@ describe "Hash#dig" do
end
it "raises an ArgumentError if no arguments provided" do
- -> { { the: 'borg' }.dig() }.should raise_error(ArgumentError)
+ -> { { the: 'borg' }.dig() }.should.raise(ArgumentError)
end
it "handles type-mixed deep digging" do
@@ -47,8 +47,8 @@ describe "Hash#dig" do
it "raises TypeError if an intermediate element does not respond to #dig" do
h = {}
h[:foo] = [ { bar: [ 1 ] }, [ nil, 'str' ] ]
- -> { h.dig(:foo, 0, :bar, 0, 0) }.should raise_error(TypeError)
- -> { h.dig(:foo, 1, 1, 0) }.should raise_error(TypeError)
+ -> { h.dig(:foo, 0, :bar, 0, 0) }.should.raise(TypeError)
+ -> { h.dig(:foo, 1, 1, 0) }.should.raise(TypeError)
end
it "calls #dig on the result of #[] with the remaining arguments" do
@@ -60,7 +60,7 @@ describe "Hash#dig" do
it "respects Hash's default" do
default = {bar: 42}
h = Hash.new(default)
- h.dig(:foo).should equal default
+ h.dig(:foo).should.equal? default
h.dig(:foo, :bar).should == 42
end
end
diff --git a/spec/ruby/core/hash/each_key_spec.rb b/spec/ruby/core/hash/each_key_spec.rb
index c84dd696d5..5b2e9deb63 100644
--- a/spec/ruby/core/hash/each_key_spec.rb
+++ b/spec/ruby/core/hash/each_key_spec.rb
@@ -7,7 +7,7 @@ describe "Hash#each_key" do
it "calls block once for each key, passing key" do
r = {}
h = { 1 => -1, 2 => -2, 3 => -3, 4 => -4 }
- h.each_key { |k| r[k] = k }.should equal(h)
+ h.each_key { |k| r[k] = k }.should.equal?(h)
r.should == { 1 => 1, 2 => 2, 3 => 3, 4 => 4 }
end
diff --git a/spec/ruby/core/hash/each_pair_spec.rb b/spec/ruby/core/hash/each_pair_spec.rb
index eb6656681d..01810c130c 100644
--- a/spec/ruby/core/hash/each_pair_spec.rb
+++ b/spec/ruby/core/hash/each_pair_spec.rb
@@ -1,11 +1,111 @@
require_relative '../../spec_helper'
-require_relative 'fixtures/classes'
require_relative 'shared/iteration'
-require_relative 'shared/each'
require_relative '../enumerable/shared/enumeratorized'
describe "Hash#each_pair" do
- it_behaves_like :hash_each, :each_pair
it_behaves_like :hash_iteration_no_block, :each_pair
it_behaves_like :enumeratorized_with_origin_size, :each_pair, { 1 => 2, 3 => 4, 5 => 6 }
+
+ # This is inconsistent with below, MRI checks the block arity in rb_hash_each_pair()
+ it "yields a [[key, value]] Array for each pair to a block expecting |*args|" do
+ all_args = []
+ { 1 => 2, 3 => 4 }.each_pair { |*args| all_args << args }
+ all_args.sort.should == [[[1, 2]], [[3, 4]]]
+ end
+
+ it "yields the key and value of each pair to a block expecting |key, value|" do
+ r = {}
+ h = { a: 1, b: 2, c: 3, d: 5 }
+ h.each_pair { |k,v| r[k.to_s] = v.to_s }.should.equal?(h)
+ r.should == { "a" => "1", "b" => "2", "c" => "3", "d" => "5" }
+ end
+
+ it "yields the key only to a block expecting |key,|" do
+ ary = []
+ h = { "a" => 1, "b" => 2, "c" => 3 }
+ h.each_pair { |k,| ary << k }
+ 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
+
+ -> {
+ { "a" => 1 }.each_pair(&obj.method(:foo))
+ }.should.raise(ArgumentError)
+
+ -> {
+ { "a" => 1 }.each_pair(&-> key, value { })
+ }.should.raise(ArgumentError)
+ end
+
+ it "yields an Array of 2 elements when given a callable of arity 1" do
+ obj = Object.new
+ def obj.foo(key_value)
+ ScratchPad << key_value
+ end
+
+ ScratchPad.record([])
+ { "a" => 1 }.each_pair(&obj.method(:foo))
+ ScratchPad.recorded.should == [["a", 1]]
+ end
+
+ it "raises an error for a Hash when an arity enforcing callable of arity >2 is passed in" do
+ obj = Object.new
+ def obj.foo(key, value, extra)
+ end
+
+ -> {
+ { "a" => 1 }.each_pair(&obj.method(:foo))
+ }.should.raise(ArgumentError)
+ end
+
+ it "uses the same order as keys() and values()" do
+ h = { a: 1, b: 2, c: 3, d: 5 }
+ keys = []
+ values = []
+
+ h.each_pair do |k, v|
+ keys << k
+ values << v
+ end
+
+ keys.should == h.keys
+ values.should == h.values
+ end
+
+ # Confirming the argument-splatting works from child class for both k, v and [k, v]
+ it "properly expands (or not) child class's 'each'-yielded args" do
+ cls1 = Class.new(Hash) do
+ attr_accessor :k_v
+ def each
+ super do |k, v|
+ @k_v = [k, v]
+ yield k, v
+ end
+ end
+ end
+
+ cls2 = Class.new(Hash) do
+ attr_accessor :k_v
+ def each
+ super do |k, v|
+ @k_v = [k, v]
+ yield([k, v])
+ end
+ end
+ end
+
+ obj1 = cls1.new
+ obj1['a'] = 'b'
+ obj1.map {|k, v| [k, v]}.should == [['a', 'b']]
+ obj1.k_v.should == ['a', 'b']
+
+ obj2 = cls2.new
+ obj2['a'] = 'b'
+ obj2.map {|k, v| [k, v]}.should == [['a', 'b']]
+ obj2.k_v.should == ['a', 'b']
+ end
end
diff --git a/spec/ruby/core/hash/each_spec.rb b/spec/ruby/core/hash/each_spec.rb
index f0de0bdee5..1644b63216 100644
--- a/spec/ruby/core/hash/each_spec.rb
+++ b/spec/ruby/core/hash/each_spec.rb
@@ -1,11 +1,7 @@
require_relative '../../spec_helper'
-require_relative 'fixtures/classes'
-require_relative 'shared/iteration'
-require_relative 'shared/each'
-require_relative '../enumerable/shared/enumeratorized'
describe "Hash#each" do
- it_behaves_like :hash_each, :each
- it_behaves_like :hash_iteration_no_block, :each
- it_behaves_like :enumeratorized_with_origin_size, :each, { 1 => 2, 3 => 4, 5 => 6 }
+ it "is an alias of Hash#each_pair" do
+ Hash.instance_method(:each).should == Hash.instance_method(:each_pair)
+ end
end
diff --git a/spec/ruby/core/hash/each_value_spec.rb b/spec/ruby/core/hash/each_value_spec.rb
index 19b076730d..2df95a8789 100644
--- a/spec/ruby/core/hash/each_value_spec.rb
+++ b/spec/ruby/core/hash/each_value_spec.rb
@@ -7,7 +7,7 @@ describe "Hash#each_value" do
it "calls block once for each key, passing value" do
r = []
h = { a: -5, b: -3, c: -2, d: -1, e: -1 }
- h.each_value { |v| r << v }.should equal(h)
+ h.each_value { |v| r << v }.should.equal?(h)
r.sort.should == [-5, -3, -2, -1, -1]
end
diff --git a/spec/ruby/core/hash/element_reference_spec.rb b/spec/ruby/core/hash/element_reference_spec.rb
index d5859cb342..3d074b346d 100644
--- a/spec/ruby/core/hash/element_reference_spec.rb
+++ b/spec/ruby/core/hash/element_reference_spec.rb
@@ -36,7 +36,7 @@ describe "Hash#[]" do
b = h[:b]
a << "bar"
- a.should equal(b)
+ a.should.equal?(b)
a.should == "foobar"
b.should == "foobar"
end
diff --git a/spec/ruby/core/hash/element_set_spec.rb b/spec/ruby/core/hash/element_set_spec.rb
index 67c5a04d73..bb805477ca 100644
--- a/spec/ruby/core/hash/element_set_spec.rb
+++ b/spec/ruby/core/hash/element_set_spec.rb
@@ -1,7 +1,121 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
-require_relative 'shared/store'
describe "Hash#[]=" do
- it_behaves_like :hash_store, :[]=
+ it "associates the key with the value" do
+ h = { a: 1 }
+ h[:b] = 2
+ h.should == { b:2, a:1 }
+ end
+
+ it "returns the assigned value" do
+ h = {}
+ h.send(:[]=, 1, 2).should == 2
+ end
+
+ it "duplicates string keys using dup semantics" do
+ # dup doesn't copy singleton methods
+ key = +"foo"
+ def key.reverse() "bar" end
+ h = {}
+ h[key] = 0
+ h.keys[0].reverse.should == "oof"
+ end
+
+ it "stores unequal keys that hash to the same value" do
+ h = {}
+ k1 = ["x"]
+ k2 = ["y"]
+ # So they end up in the same bucket
+ k1.should_receive(:hash).and_return(0)
+ k2.should_receive(:hash).and_return(0)
+
+ h[k1] = 1
+ h[k2] = 2
+ h.size.should == 2
+ end
+
+ it "accepts keys with private #hash method" do
+ key = HashSpecs::KeyWithPrivateHash.new
+ h = {}
+ h[key] = "foo"
+ h[key].should == "foo"
+ end
+
+ it " accepts keys with an Integer hash" do
+ o = mock(hash: 1 << 100)
+ h = {}
+ h[o] = 1
+ h[o].should == 1
+ end
+
+ it "duplicates and freezes string keys" do
+ key = +"foo"
+ h = {}
+ h[key] = 0
+ key << "bar"
+
+ h.should == { "foo" => 0 }
+ h.keys[0].should.frozen?
+ end
+
+ it "doesn't duplicate and freeze already frozen string keys" do
+ key = "foo".freeze
+ h = {}
+ h[key] = 0
+ h.keys[0].should.equal?(key)
+ end
+
+ it "keeps the existing key in the hash if there is a matching one" do
+ h = { "a" => 1, "b" => 2, "c" => 3, "d" => 4 }
+ key1 = HashSpecs::ByValueKey.new(13)
+ key2 = HashSpecs::ByValueKey.new(13)
+ h[key1] = 41
+ key_in_hash = h.keys.last
+ key_in_hash.should.equal?(key1)
+ h[key2] = 42
+ last_key = h.keys.last
+ last_key.should.equal?(key_in_hash)
+ last_key.should_not.equal?(key2)
+ end
+
+ 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.should_not.equal?(key2)
+ h[key1] = 41
+ frozen_key = h.keys.last
+ frozen_key.should_not.equal?(key1)
+ h[key2] = 42
+ h.keys.last.should.equal?(frozen_key)
+ h.keys.last.should_not.equal?(key2)
+ end
+
+ it "raises a FrozenError if called on a frozen instance" do
+ -> { HashSpecs.frozen_hash[1] = 2 }.should.raise(FrozenError)
+ end
+
+ it "does not raise an exception if changing the value of an existing key during iteration" do
+ hash = {1 => 2, 3 => 4, 5 => 6}
+ hash.each { hash[1] = :foo }
+ hash.should == {1 => :foo, 3 => 4, 5 => 6}
+ end
+
+ it "does not dispatch to hash for Boolean, Integer, Float, String, or Symbol" do
+ code = <<-EOC
+ load '#{fixture __FILE__, "name.rb"}'
+ hash = {}
+ [true, false, 1, 2.0, "hello", :ok].each do |value|
+ hash[value] = 42
+ raise "incorrect value" unless hash[value] == 42
+ hash[value] = 43
+ raise "incorrect value" unless hash[value] == 43
+ end
+ puts "OK"
+ puts hash.size
+ EOC
+ result = ruby_exe(code, args: "2>&1")
+ result.should == "OK\n6\n"
+ end
end
diff --git a/spec/ruby/core/hash/equal_value_spec.rb b/spec/ruby/core/hash/equal_value_spec.rb
index ae13a42679..ab14f81489 100644
--- a/spec/ruby/core/hash/equal_value_spec.rb
+++ b/spec/ruby/core/hash/equal_value_spec.rb
@@ -13,6 +13,6 @@ describe "Hash#==" do
l_val.should_receive(:==).with(r_val).and_return(true)
- ({ 1 => l_val } == { 1 => r_val }).should be_true
+ ({ 1 => l_val } == { 1 => r_val }).should == true
end
end
diff --git a/spec/ruby/core/hash/except_spec.rb b/spec/ruby/core/hash/except_spec.rb
index ac84f9975c..77a020e9b7 100644
--- a/spec/ruby/core/hash/except_spec.rb
+++ b/spec/ruby/core/hash/except_spec.rb
@@ -7,7 +7,7 @@ describe "Hash#except" do
it "returns a new duplicate hash without arguments" do
ret = @hash.except
- ret.should_not equal(@hash)
+ ret.should_not.equal?(@hash)
ret.should == @hash
end
@@ -19,14 +19,24 @@ describe "Hash#except" 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 "does not retain the default value" do
+ h = Hash.new(1)
+ h.except(:a).default.should == nil
+ h[:a] = 1
+ h.except(:a).default.should == nil
+ end
+
+ it "does not retain the default_proc" do
+ pr = proc { |h, k| h[k] = [] }
+ h = Hash.new(&pr)
+ h.except(:a).default_proc.should == nil
+ h[:a] = 1
+ h.except(:a).default_proc.should == nil
+ end
+
+ it "retains compare_by_identity flag" do
+ h = { a: 9, c: 4 }.compare_by_identity
+ h2 = h.except(:a)
+ h2.compare_by_identity?.should == true
end
end
diff --git a/spec/ruby/core/hash/fetch_spec.rb b/spec/ruby/core/hash/fetch_spec.rb
index 6e0d207224..f9b80b6c49 100644
--- a/spec/ruby/core/hash/fetch_spec.rb
+++ b/spec/ruby/core/hash/fetch_spec.rb
@@ -12,7 +12,7 @@ describe "Hash#fetch" do
it "formats the object with #inspect in the KeyError message" do
-> {
{}.fetch('foo')
- }.should raise_error(KeyError, 'key not found: "foo"')
+ }.should.raise(KeyError, 'key not found: "foo"')
end
end
@@ -38,7 +38,7 @@ describe "Hash#fetch" do
end
it "raises an ArgumentError when not passed one or two arguments" do
- -> { {}.fetch() }.should raise_error(ArgumentError)
- -> { {}.fetch(1, 2, 3) }.should raise_error(ArgumentError)
+ -> { {}.fetch() }.should.raise(ArgumentError)
+ -> { {}.fetch(1, 2, 3) }.should.raise(ArgumentError)
end
end
diff --git a/spec/ruby/core/hash/filter_spec.rb b/spec/ruby/core/hash/filter_spec.rb
index 7dabe44984..625a7feb90 100644
--- a/spec/ruby/core/hash/filter_spec.rb
+++ b/spec/ruby/core/hash/filter_spec.rb
@@ -1,10 +1,13 @@
require_relative '../../spec_helper'
-require_relative 'shared/select'
describe "Hash#filter" do
- it_behaves_like :hash_select, :filter
+ it "is an alias of Hash#select" do
+ Hash.instance_method(:filter).should == Hash.instance_method(:select)
+ end
end
describe "Hash#filter!" do
- it_behaves_like :hash_select!, :filter!
+ it "is an alias of Hash#select!" do
+ Hash.instance_method(:filter!).should == Hash.instance_method(:select!)
+ end
end
diff --git a/spec/ruby/core/hash/flatten_spec.rb b/spec/ruby/core/hash/flatten_spec.rb
index 825da15bfc..18e9a7b56a 100644
--- a/spec/ruby/core/hash/flatten_spec.rb
+++ b/spec/ruby/core/hash/flatten_spec.rb
@@ -9,7 +9,7 @@ describe "Hash#flatten" do
end
it "returns an Array" do
- {}.flatten.should be_an_instance_of(Array)
+ {}.flatten.should.instance_of?(Array)
end
it "returns an empty Array for an empty Hash" do
@@ -57,6 +57,6 @@ describe "Hash#flatten" do
it "raises a TypeError if given a non-Integer argument" do
-> do
@h.flatten(Object.new)
- end.should raise_error(TypeError)
+ end.should.raise(TypeError)
end
end
diff --git a/spec/ruby/core/hash/gt_spec.rb b/spec/ruby/core/hash/gt_spec.rb
index cd541d4d83..69d23b7d29 100644
--- a/spec/ruby/core/hash/gt_spec.rb
+++ b/spec/ruby/core/hash/gt_spec.rb
@@ -8,7 +8,7 @@ describe "Hash#>" do
it "returns false if both hashes are identical" do
h = { a: 1, b: 2 }
- (h > h).should be_false
+ (h > h).should == false
end
end
diff --git a/spec/ruby/core/hash/gte_spec.rb b/spec/ruby/core/hash/gte_spec.rb
index 99b89e7217..be5060ea4f 100644
--- a/spec/ruby/core/hash/gte_spec.rb
+++ b/spec/ruby/core/hash/gte_spec.rb
@@ -8,7 +8,7 @@ describe "Hash#>=" do
it "returns true if both hashes are identical" do
h = { a: 1, b: 2 }
- (h >= h).should be_true
+ (h >= h).should == true
end
end
diff --git a/spec/ruby/core/hash/has_key_spec.rb b/spec/ruby/core/hash/has_key_spec.rb
index 4af53579e5..9a6244c6f6 100644
--- a/spec/ruby/core/hash/has_key_spec.rb
+++ b/spec/ruby/core/hash/has_key_spec.rb
@@ -1,7 +1,7 @@
require_relative '../../spec_helper'
-require_relative 'fixtures/classes'
-require_relative 'shared/key'
describe "Hash#has_key?" do
- it_behaves_like :hash_key_p, :has_key?
+ it "is an alias of Hash#include?" do
+ Hash.instance_method(:has_key?).should == Hash.instance_method(:include?)
+ end
end
diff --git a/spec/ruby/core/hash/has_value_spec.rb b/spec/ruby/core/hash/has_value_spec.rb
index 39f1627fd3..95b8390a66 100644
--- a/spec/ruby/core/hash/has_value_spec.rb
+++ b/spec/ruby/core/hash/has_value_spec.rb
@@ -1,7 +1,7 @@
require_relative '../../spec_helper'
-require_relative 'fixtures/classes'
-require_relative 'shared/value'
describe "Hash#has_value?" do
- it_behaves_like :hash_value_p, :has_value?
+ it "is an alias of Hash#value?" do
+ Hash.instance_method(:has_value?).should == Hash.instance_method(:value?)
+ end
end
diff --git a/spec/ruby/core/hash/include_spec.rb b/spec/ruby/core/hash/include_spec.rb
index f3959dc589..1c32e9fb23 100644
--- a/spec/ruby/core/hash/include_spec.rb
+++ b/spec/ruby/core/hash/include_spec.rb
@@ -1,7 +1,40 @@
require_relative '../../spec_helper'
-require_relative 'fixtures/classes'
-require_relative 'shared/key'
describe "Hash#include?" do
- it_behaves_like :hash_key_p, :include?
+ it "returns true if argument is a key" do
+ h = { a: 1, b: 2, c: 3, 4 => 0 }
+ h.include?(:a).should == true
+ h.include?(:b).should == true
+ h.include?(2).should == false
+ h.include?(4).should == true
+
+ not_supported_on :opal do
+ h.include?('b').should == false
+ h.include?(4.0).should == false
+ end
+ end
+
+ it "returns true if the key's matching value was nil" do
+ { xyz: nil }.include?(:xyz).should == true
+ end
+
+ it "returns true if the key's matching value was false" do
+ { xyz: false }.include?(:xyz).should == true
+ end
+
+ it "returns true if the key is nil" do
+ { nil => 'b' }.include?(nil).should == true
+ { nil => nil }.include?(nil).should == true
+ end
+
+ it "compares keys with the same #hash value via #eql?" do
+ x = mock('x')
+ x.stub!(:hash).and_return(42)
+
+ y = mock('y')
+ y.stub!(:hash).and_return(42)
+ y.should_receive(:eql?).and_return(false)
+
+ { x => nil }.include?(y).should == false
+ end
end
diff --git a/spec/ruby/core/hash/initialize_spec.rb b/spec/ruby/core/hash/initialize_spec.rb
index d13496ba3b..cdba598813 100644
--- a/spec/ruby/core/hash/initialize_spec.rb
+++ b/spec/ruby/core/hash/initialize_spec.rb
@@ -3,7 +3,7 @@ require_relative 'fixtures/classes'
describe "Hash#initialize" do
it "is private" do
- Hash.should have_private_instance_method("initialize")
+ Hash.private_instance_methods(false).should.include?(:initialize)
end
it "can be used to reset default_proc" do
@@ -42,20 +42,20 @@ describe "Hash#initialize" do
it "returns self" do
h = Hash.new
- h.send(:initialize).should equal(h)
+ h.send(:initialize).should.equal?(h)
end
it "raises a FrozenError if called on a frozen instance" do
block = -> { HashSpecs.frozen_hash.instance_eval { initialize() }}
- block.should raise_error(FrozenError)
+ block.should.raise(FrozenError)
block = -> { HashSpecs.frozen_hash.instance_eval { initialize(nil) } }
- block.should raise_error(FrozenError)
+ block.should.raise(FrozenError)
block = -> { HashSpecs.frozen_hash.instance_eval { initialize(5) } }
- block.should raise_error(FrozenError)
+ block.should.raise(FrozenError)
block = -> { HashSpecs.frozen_hash.instance_eval { initialize { 5 } } }
- block.should raise_error(FrozenError)
+ block.should.raise(FrozenError)
end
end
diff --git a/spec/ruby/core/hash/inspect_spec.rb b/spec/ruby/core/hash/inspect_spec.rb
index f41ebb70a6..359b13360f 100644
--- a/spec/ruby/core/hash/inspect_spec.rb
+++ b/spec/ruby/core/hash/inspect_spec.rb
@@ -1,7 +1,123 @@
require_relative '../../spec_helper'
-require_relative 'fixtures/classes'
-require_relative 'shared/to_s'
describe "Hash#inspect" do
- it_behaves_like :hash_to_s, :inspect
+ 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.inspect.should == expected
+ end
+
+ it "calls #inspect on keys and values" do
+ key = mock('key')
+ 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 }.inspect.should == expected
+ end
+
+ it "does not call #to_s on a String returned from #inspect" do
+ str = +"abc"
+ str.should_not_receive(:to_s)
+ expected = ruby_version_is("3.4") ? '{a: "abc"}' : '{:a=>"abc"}'
+ { a: str }.inspect.should == expected
+ 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 }.inspect.should == expected
+ 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 }.inspect.should =~ expected_pattern
+ end
+
+ it "does not call #to_str on the object returned from #to_s when it is not a String" do
+ obj = mock("Hash#inspect/to_s does not call #to_str on #to_s result")
+ 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 }.inspect.should =~ expected_pattern
+ end
+
+ it "does not swallow exceptions raised by #to_s" do
+ obj = mock("Hash#inspect/to_s does not swallow #to_s exceptions")
+ obj.should_receive(:inspect).and_return(obj)
+ obj.should_receive(:to_s).and_raise(Exception)
+
+ -> { { a: obj }.inspect }.should.raise(Exception)
+ end
+
+ it "handles hashes with recursive values" do
+ x = {}
+ x[0] = x
+ expected = ruby_version_is("3.4") ? '{0 => {...}}' : '{0=>{...}}'
+ x.inspect.should == expected
+
+ 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.inspect.should == expected_x
+ y.inspect.should == expected_y
+ 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}.inspect.should == expected
+ 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 }.inspect.should == expected
+ end
+
+ ruby_version_is "3.4" do
+ it "adds quotes to symbol keys that are not valid symbol literals" do
+ { "needs-quotes": 1 }.inspect.should == '{"needs-quotes": 1}'
+ end
+
+ it "can be evaled" do
+ no_quote = '{a: 1, a!: 1, a?: 1}'
+ eval(no_quote).inspect.should == no_quote
+ [
+ '{"": 1}',
+ '{"0": 1, "!": 1, "%": 1, "&": 1, "*": 1, "+": 1, "-": 1, "/": 1, "<": 1, ">": 1, "^": 1, "`": 1, "|": 1, "~": 1}',
+ '{"@a": 1, "$a": 1, "+@": 1, "a=": 1, "[]": 1}',
+ '{"a\"b": 1, "@@a": 1, "<=>": 1, "===": 1, "[]=": 1}',
+ ].each do |quote|
+ eval(quote).inspect.should == quote
+ end
+ end
+
+ it "can be evaled when Encoding.default_external is changed" do
+ external = Encoding.default_external
+
+ Encoding.default_external = Encoding::ASCII
+ utf8_ascii_hash = '{"\\u3042": 1}'
+ eval(utf8_ascii_hash).inspect.should == utf8_ascii_hash
+
+ Encoding.default_external = Encoding::UTF_8
+ utf8_hash = "{\u3042: 1}"
+ eval(utf8_hash).inspect.should == utf8_hash
+
+ Encoding.default_external = Encoding::Windows_31J
+ sjis_hash = "{\x87]: 1}".dup.force_encoding('sjis')
+ eval(sjis_hash).inspect.should == sjis_hash
+ ensure
+ Encoding.default_external = external
+ end
+ end
end
diff --git a/spec/ruby/core/hash/invert_spec.rb b/spec/ruby/core/hash/invert_spec.rb
index 73377a9e97..ea441751f2 100644
--- a/spec/ruby/core/hash/invert_spec.rb
+++ b/spec/ruby/core/hash/invert_spec.rb
@@ -24,4 +24,25 @@ describe "Hash#invert" do
HashSpecs::MyHash[1 => 2, 3 => 4].invert.class.should == Hash
HashSpecs::MyHash[].invert.class.should == Hash
end
+
+ it "does not retain the default value" do
+ h = Hash.new(1)
+ h.invert.default.should == nil
+ h[:a] = 1
+ h.invert.default.should == nil
+ end
+
+ it "does not retain the default_proc" do
+ pr = proc { |h, k| h[k] = [] }
+ h = Hash.new(&pr)
+ h.invert.default_proc.should == nil
+ h[:a] = 1
+ h.invert.default_proc.should == nil
+ end
+
+ it "does not retain compare_by_identity flag" do
+ h = { a: 9, c: 4 }.compare_by_identity
+ h2 = h.invert
+ h2.compare_by_identity?.should == false
+ end
end
diff --git a/spec/ruby/core/hash/keep_if_spec.rb b/spec/ruby/core/hash/keep_if_spec.rb
index d50d969467..c975efc5f8 100644
--- a/spec/ruby/core/hash/keep_if_spec.rb
+++ b/spec/ruby/core/hash/keep_if_spec.rb
@@ -12,24 +12,24 @@ describe "Hash#keep_if" do
it "keeps every entry for which block is true and returns self" do
h = { a: 1, b: 2, c: 3, d: 4 }
- h.keep_if { |k,v| v % 2 == 0 }.should equal(h)
+ h.keep_if { |k,v| v % 2 == 0 }.should.equal?(h)
h.should == { b: 2, d: 4 }
end
it "removes all entries if the block is false" do
h = { a: 1, b: 2, c: 3 }
- h.keep_if { |k,v| false }.should equal(h)
+ h.keep_if { |k,v| false }.should.equal?(h)
h.should == {}
end
it "returns self even if unmodified" do
h = { 1 => 2, 3 => 4 }
- h.keep_if { true }.should equal(h)
+ h.keep_if { true }.should.equal?(h)
end
it "raises a FrozenError if called on a frozen instance" do
- -> { HashSpecs.frozen_hash.keep_if { true } }.should raise_error(FrozenError)
- -> { HashSpecs.empty_frozen_hash.keep_if { false } }.should raise_error(FrozenError)
+ -> { HashSpecs.frozen_hash.keep_if { true } }.should.raise(FrozenError)
+ -> { HashSpecs.empty_frozen_hash.keep_if { false } }.should.raise(FrozenError)
end
it_behaves_like :hash_iteration_no_block, :keep_if
diff --git a/spec/ruby/core/hash/key_spec.rb b/spec/ruby/core/hash/key_spec.rb
index 73eecbc98e..c2d7049aed 100644
--- a/spec/ruby/core/hash/key_spec.rb
+++ b/spec/ruby/core/hash/key_spec.rb
@@ -1,12 +1,32 @@
require_relative '../../spec_helper'
-require_relative 'fixtures/classes'
-require_relative 'shared/key'
-require_relative 'shared/index'
describe "Hash#key?" do
- it_behaves_like :hash_key_p, :key?
+ it "is an alias of Hash#include?" do
+ Hash.instance_method(:key?).should == Hash.instance_method(:include?)
+ end
end
describe "Hash#key" do
- it_behaves_like :hash_index, :key
+ it "returns the corresponding key for value" do
+ { 2 => 'a', 1 => 'b' }.key('b').should == 1
+ end
+
+ it "returns nil if the value is not found" do
+ { a: -1, b: 3.14, c: 2.718 }.key(1).should == nil
+ end
+
+ it "doesn't return default value if the value is not found" do
+ Hash.new(5).key(5).should == nil
+ end
+
+ it "compares values using ==" do
+ { 1 => 0 }.key(0.0).should == 1
+ { 1 => 0.0 }.key(0).should == 1
+
+ needle = mock('needle')
+ inhash = mock('inhash')
+ inhash.should_receive(:==).with(needle).and_return(true)
+
+ { 1 => inhash }.key(needle).should == 1
+ end
end
diff --git a/spec/ruby/core/hash/keys_spec.rb b/spec/ruby/core/hash/keys_spec.rb
index 9a067085e5..789c413bee 100644
--- a/spec/ruby/core/hash/keys_spec.rb
+++ b/spec/ruby/core/hash/keys_spec.rb
@@ -5,11 +5,11 @@ describe "Hash#keys" do
it "returns an array with the keys in the order they were inserted" do
{}.keys.should == []
- {}.keys.should be_kind_of(Array)
+ {}.keys.should.is_a?(Array)
Hash.new(5).keys.should == []
Hash.new { 5 }.keys.should == []
{ 1 => 2, 4 => 8, 2 => 4 }.keys.should == [1, 4, 2]
- { 1 => 2, 2 => 4, 4 => 8 }.keys.should be_kind_of(Array)
+ { 1 => 2, 2 => 4, 4 => 8 }.keys.should.is_a?(Array)
{ nil => nil }.keys.should == [nil]
end
diff --git a/spec/ruby/core/hash/length_spec.rb b/spec/ruby/core/hash/length_spec.rb
index d0af0945df..325973306f 100644
--- a/spec/ruby/core/hash/length_spec.rb
+++ b/spec/ruby/core/hash/length_spec.rb
@@ -1,7 +1,7 @@
require_relative '../../spec_helper'
-require_relative 'fixtures/classes'
-require_relative 'shared/length'
describe "Hash#length" do
- it_behaves_like :hash_length, :length
+ it "is an alias of Hash#size" do
+ Hash.instance_method(:size).should == Hash.instance_method(:length)
+ end
end
diff --git a/spec/ruby/core/hash/lt_spec.rb b/spec/ruby/core/hash/lt_spec.rb
index 2219615880..4ca326d077 100644
--- a/spec/ruby/core/hash/lt_spec.rb
+++ b/spec/ruby/core/hash/lt_spec.rb
@@ -8,7 +8,7 @@ describe "Hash#<" do
it "returns false if both hashes are identical" do
h = { a: 1, b: 2 }
- (h < h).should be_false
+ (h < h).should == false
end
end
diff --git a/spec/ruby/core/hash/lte_spec.rb b/spec/ruby/core/hash/lte_spec.rb
index a166e5bca4..29e60273d1 100644
--- a/spec/ruby/core/hash/lte_spec.rb
+++ b/spec/ruby/core/hash/lte_spec.rb
@@ -8,7 +8,7 @@ describe "Hash#<=" do
it "returns true if both hashes are identical" do
h = { a: 1, b: 2 }
- (h <= h).should be_true
+ (h <= h).should == true
end
end
diff --git a/spec/ruby/core/hash/member_spec.rb b/spec/ruby/core/hash/member_spec.rb
index 37c0414559..e7309c3f7d 100644
--- a/spec/ruby/core/hash/member_spec.rb
+++ b/spec/ruby/core/hash/member_spec.rb
@@ -1,7 +1,7 @@
require_relative '../../spec_helper'
-require_relative 'fixtures/classes'
-require_relative 'shared/key'
describe "Hash#member?" do
- it_behaves_like :hash_key_p, :member?
+ it "is an alias of Hash#include?" do
+ Hash.instance_method(:member?).should == Hash.instance_method(:include?)
+ end
end
diff --git a/spec/ruby/core/hash/merge_spec.rb b/spec/ruby/core/hash/merge_spec.rb
index 5521864297..7a444f7f25 100644
--- a/spec/ruby/core/hash/merge_spec.rb
+++ b/spec/ruby/core/hash/merge_spec.rb
@@ -1,7 +1,5 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
-require_relative 'shared/iteration'
-require_relative 'shared/update'
describe "Hash#merge" do
it "returns a new hash by combining self with the contents of other" do
@@ -30,7 +28,7 @@ describe "Hash#merge" do
-> {
h1.merge(h2) { |k, x, y| raise(IndexError) }
- }.should raise_error(IndexError)
+ }.should.raise(IndexError)
r = h1.merge(h1) { |k,x,y| :x }
r.should == { a: :x, b: :x, d: :x }
@@ -47,8 +45,8 @@ describe "Hash#merge" do
end
it "returns subclass instance for subclasses" do
- HashSpecs::MyHash[1 => 2, 3 => 4].merge({ 1 => 2 }).should be_an_instance_of(HashSpecs::MyHash)
- HashSpecs::MyHash[].merge({ 1 => 2 }).should be_an_instance_of(HashSpecs::MyHash)
+ HashSpecs::MyHash[1 => 2, 3 => 4].merge({ 1 => 2 }).should.instance_of?(HashSpecs::MyHash)
+ HashSpecs::MyHash[].merge({ 1 => 2 }).should.instance_of?(HashSpecs::MyHash)
{ 1 => 2, 3 => 4 }.merge(HashSpecs::MyHash[1 => 2]).class.should == Hash
{}.merge(HashSpecs::MyHash[1 => 2]).class.should == Hash
@@ -90,11 +88,107 @@ describe "Hash#merge" do
hash = { a: 1 }
merged = hash.merge
- merged.should eql(hash)
- merged.should_not equal(hash)
+ merged.should.eql?(hash)
+ merged.should_not.equal?(hash)
+ end
+
+ it "retains the default value" do
+ h = Hash.new(1)
+ h.merge(b: 1, d: 2).default.should == 1
+ end
+
+ it "retains the default_proc" do
+ pr = proc { |h, k| h[k] = [] }
+ h = Hash.new(&pr)
+ h.merge(b: 1, d: 2).default_proc.should == pr
+ end
+
+ it "retains compare_by_identity flag" do
+ h = { a: 9, c: 4 }.compare_by_identity
+ h2 = h.merge(b: 1, d: 2)
+ h2.compare_by_identity?.should == true
+ end
+
+ it "ignores compare_by_identity flag of an argument" do
+ h = { a: 9, c: 4 }.compare_by_identity
+ h2 = { b: 1, d: 2 }.merge(h)
+ h2.compare_by_identity?.should == false
end
end
describe "Hash#merge!" do
- it_behaves_like :hash_update, :merge!
+ it "adds the entries from other, overwriting duplicate keys. Returns self" do
+ h = { _1: 'a', _2: '3' }
+ h.merge!(_1: '9', _9: 2).should.equal?(h)
+ h.should == { _1: "9", _2: "3", _9: 2 }
+ end
+
+ it "sets any duplicate key to the value of block if passed a block" do
+ h1 = { a: 2, b: -1 }
+ h2 = { a: -2, c: 1 }
+ h1.merge!(h2) { |k,x,y| 3.14 }.should.equal?(h1)
+ h1.should == { c: 1, b: -1, a: 3.14 }
+
+ h1.merge!(h1) { nil }
+ h1.should == { a: nil, b: nil, c: nil }
+ end
+
+ it "tries to convert the passed argument to a hash using #to_hash" do
+ obj = mock('{1=>2}')
+ obj.should_receive(:to_hash).and_return({ 1 => 2 })
+ { 3 => 4 }.merge!(obj).should == { 1 => 2, 3 => 4 }
+ end
+
+ it "does not call to_hash on hash subclasses" do
+ { 3 => 4 }.merge!(HashSpecs::ToHashHash[1 => 2]).should == { 1 => 2, 3 => 4 }
+ end
+
+ it "processes entries with same order as merge()" do
+ h = { 1 => 2, 3 => 4, 5 => 6, "x" => nil, nil => 5, [] => [] }
+ merge_bang_pairs = []
+ merge_pairs = []
+ h.merge(h) { |*arg| merge_pairs << arg }
+ h.merge!(h) { |*arg| merge_bang_pairs << arg }
+ merge_bang_pairs.should == merge_pairs
+ end
+
+ it "raises a FrozenError on a frozen instance that is modified" do
+ -> do
+ HashSpecs.frozen_hash.merge!(1 => 2)
+ end.should.raise(FrozenError)
+ end
+
+ it "checks frozen status before coercing an object with #to_hash" do
+ obj = mock("to_hash frozen")
+ # This is necessary because mock cleanup code cannot run on the frozen
+ # object.
+ def obj.to_hash() raise Exception, "should not receive #to_hash" end
+ obj.freeze
+
+ -> { HashSpecs.frozen_hash.merge!(obj) }.should.raise(FrozenError)
+ end
+
+ # see redmine #1571
+ it "raises a FrozenError on a frozen instance that would not be modified" do
+ -> do
+ HashSpecs.frozen_hash.merge!(HashSpecs.empty_frozen_hash)
+ end.should.raise(FrozenError)
+ end
+
+ it "does not raise an exception if changing the value of an existing key during iteration" do
+ hash = {1 => 2, 3 => 4, 5 => 6}
+ hash2 = {1 => :foo, 3 => :bar}
+ hash.each { hash.merge!(hash2) }
+ hash.should == {1 => :foo, 3 => :bar, 5 => 6}
+ end
+
+ it "accepts multiple hashes" do
+ result = { a: 1 }.merge!({ b: 2 }, { c: 3 }, { d: 4 })
+ result.should == { a: 1, b: 2, c: 3, d: 4 }
+ end
+
+ it "accepts zero arguments" do
+ hash = { a: 1 }
+ hash.merge!.should.eql?(hash)
+ end
end
diff --git a/spec/ruby/core/hash/new_spec.rb b/spec/ruby/core/hash/new_spec.rb
index 5ae3e1f98d..207fc2931f 100644
--- a/spec/ruby/core/hash/new_spec.rb
+++ b/spec/ruby/core/hash/new_spec.rb
@@ -1,6 +1,7 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
+# Actually these are specs of Hash#initialize, there is no Hash.new it's just Class.new.
describe "Hash.new" do
it "creates an empty Hash if passed no arguments" do
Hash.new.should == {}
@@ -14,7 +15,7 @@ describe "Hash.new" do
it "does not create a copy of the default argument" do
str = "foo"
- Hash.new(str).default.should equal(str)
+ Hash.new(str).default.should.equal?(str)
end
it "creates a Hash with a default_proc if passed a block" do
@@ -26,22 +27,22 @@ describe "Hash.new" do
end
it "raises an ArgumentError if more than one argument is passed" do
- -> { Hash.new(5,6) }.should raise_error(ArgumentError)
+ -> { Hash.new(5,6) }.should.raise(ArgumentError)
end
it "raises an ArgumentError if passed both default argument and default block" do
- -> { Hash.new(5) { 0 } }.should raise_error(ArgumentError)
- -> { Hash.new(nil) { 0 } }.should raise_error(ArgumentError)
+ -> { Hash.new(5) { 0 } }.should.raise(ArgumentError)
+ -> { Hash.new(nil) { 0 } }.should.raise(ArgumentError)
end
- ruby_version_is "3.3"..."3.4" do
+ ruby_version_is ""..."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(1, unknown: true) }.should.raise(ArgumentError)
+ -> { Hash.new(unknown: true) { 0 } }.should.raise(ArgumentError)
Hash.new({ unknown: true }).default.should == { unknown: true }
end
@@ -55,13 +56,13 @@ describe "Hash.new" do
end
it "ignores negative capacity" do
- -> { Hash.new(capacity: -42) }.should_not raise_error
+ -> { Hash.new(capacity: -42) }.should_not.raise
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)
+ -> { Hash.new(unknown: true) }.should.raise(ArgumentError)
+ -> { Hash.new(1, unknown: true) }.should.raise(ArgumentError)
+ -> { Hash.new(unknown: true) { 0 } }.should.raise(ArgumentError)
end
end
end
diff --git a/spec/ruby/core/hash/rassoc_spec.rb b/spec/ruby/core/hash/rassoc_spec.rb
index f3b2a6de20..73379f6867 100644
--- a/spec/ruby/core/hash/rassoc_spec.rb
+++ b/spec/ruby/core/hash/rassoc_spec.rb
@@ -6,7 +6,7 @@ describe "Hash#rassoc" do
end
it "returns an Array if the argument is a value of the Hash" do
- @h.rassoc(:green).should be_an_instance_of(Array)
+ @h.rassoc(:green).should.instance_of?(Array)
end
it "returns a 2-element Array if the argument is a value of the Hash" do
@@ -28,15 +28,15 @@ describe "Hash#rassoc" do
it "uses #== to compare the argument to the values" do
@h[:key] = 1.0
1.should == 1.0
- @h.rassoc(1).should eql [:key, 1.0]
+ @h.rassoc(1).should.eql? [:key, 1.0]
end
it "returns nil if the argument is not a value of the Hash" do
- @h.rassoc(:banana).should be_nil
+ @h.rassoc(:banana).should == nil
end
it "returns nil if the argument is not a value of the Hash even when there is a default" do
- Hash.new(42).merge!( foo: :bar ).rassoc(42).should be_nil
- Hash.new{|h, k| h[k] = 42}.merge!( foo: :bar ).rassoc(42).should be_nil
+ Hash.new(42).merge!( foo: :bar ).rassoc(42).should == nil
+ Hash.new{|h, k| h[k] = 42}.merge!( foo: :bar ).rassoc(42).should == nil
end
end
diff --git a/spec/ruby/core/hash/rehash_spec.rb b/spec/ruby/core/hash/rehash_spec.rb
index db3e91b166..fcd5a037bd 100644
--- a/spec/ruby/core/hash/rehash_spec.rb
+++ b/spec/ruby/core/hash/rehash_spec.rb
@@ -20,7 +20,7 @@ describe "Hash#rehash" do
h.keys.include?(k1).should == true
- h.rehash.should equal(h)
+ h.rehash.should.equal?(h)
h.key?(k1).should == true
h[k1].should == :v1
end
@@ -108,7 +108,7 @@ describe "Hash#rehash" do
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)
+ -> { HashSpecs.frozen_hash.rehash }.should.raise(FrozenError)
+ -> { HashSpecs.empty_frozen_hash.rehash }.should.raise(FrozenError)
end
end
diff --git a/spec/ruby/core/hash/reject_spec.rb b/spec/ruby/core/hash/reject_spec.rb
index dd8e817237..aa1a074897 100644
--- a/spec/ruby/core/hash/reject_spec.rb
+++ b/spec/ruby/core/hash/reject_spec.rb
@@ -28,8 +28,8 @@ describe "Hash#reject" do
context "with extra state" do
it "returns Hash instance for subclasses" do
- HashSpecs::MyHash[1 => 2, 3 => 4].reject { false }.should be_kind_of(Hash)
- HashSpecs::MyHash[1 => 2, 3 => 4].reject { true }.should be_kind_of(Hash)
+ HashSpecs::MyHash[1 => 2, 3 => 4].reject { false }.should.is_a?(Hash)
+ HashSpecs::MyHash[1 => 2, 3 => 4].reject { true }.should.is_a?(Hash)
end
end
@@ -44,6 +44,27 @@ describe "Hash#reject" do
reject_pairs.should == reject_bang_pairs
end
+ it "does not retain the default value" do
+ h = Hash.new(1)
+ h.reject { false }.default.should == nil
+ h[:a] = 1
+ h.reject { false }.default.should == nil
+ end
+
+ it "does not retain the default_proc" do
+ pr = proc { |h, k| h[k] = [] }
+ h = Hash.new(&pr)
+ h.reject { false }.default_proc.should == nil
+ h[:a] = 1
+ h.reject { false }.default_proc.should == nil
+ end
+
+ it "retains compare_by_identity flag" do
+ h = { a: 9, c: 4 }.compare_by_identity
+ h2 = h.reject { |k, _| k == :a }
+ h2.compare_by_identity?.should == true
+ end
+
it_behaves_like :hash_iteration_no_block, :reject
it_behaves_like :enumeratorized_with_origin_size, :reject, { 1 => 2, 3 => 4, 5 => 6 }
end
@@ -58,7 +79,7 @@ describe "Hash#reject!" do
it "removes all entries if the block is true" do
h = { a: 1, b: 2, c: 3 }
- h.reject! { |k,v| true }.should equal(h)
+ h.reject! { |k,v| true }.should.equal?(h)
h.should == {}
end
@@ -83,11 +104,11 @@ describe "Hash#reject!" do
end
it "raises a FrozenError if called on a frozen instance that is modified" do
- -> { HashSpecs.empty_frozen_hash.reject! { true } }.should raise_error(FrozenError)
+ -> { HashSpecs.empty_frozen_hash.reject! { true } }.should.raise(FrozenError)
end
it "raises a FrozenError if called on a frozen instance that would not be modified" do
- -> { HashSpecs.frozen_hash.reject! { false } }.should raise_error(FrozenError)
+ -> { HashSpecs.frozen_hash.reject! { false } }.should.raise(FrozenError)
end
it_behaves_like :hash_iteration_no_block, :reject!
diff --git a/spec/ruby/core/hash/replace_spec.rb b/spec/ruby/core/hash/replace_spec.rb
index a26a31f5f9..4dacbf9779 100644
--- a/spec/ruby/core/hash/replace_spec.rb
+++ b/spec/ruby/core/hash/replace_spec.rb
@@ -4,7 +4,7 @@ require_relative 'fixtures/classes'
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.replace(c: -1, d: -2).should.equal?(h)
h.should == { c: -1, d: -2 }
end
@@ -23,48 +23,57 @@ describe "Hash#replace" do
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?
+ it "does not retain the default value" do
+ hash = Hash.new(1)
+ hash.replace(b: 2).default.should == nil
+ end
- 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?
+ it "transfers the default value of an argument" do
+ hash = Hash.new(1)
+ { a: 1 }.replace(hash).default.should == 1
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
+ it "does not retain the default_proc" do
+ pr = proc { |h, k| h[k] = [] }
+ hash = Hash.new(&pr)
+ hash.replace(b: 2).default_proc.should == nil
+ end
- hash_a = {}
- hash_b = Hash.new { |h, k| k * 2 }
- hash_a.replace(hash_b)
- hash_a.default(5).should == 10
+ it "transfers the default_proc of an argument" do
+ pr = proc { |h, k| h[k] = [] }
+ hash = Hash.new(&pr)
+ { a: 1 }.replace(hash).default_proc.should == pr
+ end
+ it "does not call the default_proc of an argument" do
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 "transfers compare_by_identity flag of an argument" do
+ h = { a: 1, c: 3 }
+ h2 = { b: 2, d: 4 }.compare_by_identity
+ h.replace(h2)
+ h.compare_by_identity?.should == true
+ end
+
+ it "does not retain compare_by_identity flag" do
+ h = { a: 1, c: 3 }.compare_by_identity
+ h.replace(b: 2, d: 4)
+ h.compare_by_identity?.should == false
+ 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.should.raise(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.should.raise(FrozenError)
end
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..609a53f81f 100644
--- a/spec/ruby/core/hash/ruby2_keywords_hash_spec.rb
+++ b/spec/ruby/core/hash/ruby2_keywords_hash_spec.rb
@@ -16,7 +16,7 @@ describe "Hash.ruby2_keywords_hash?" do
end
it "raises TypeError for non-Hash" do
- -> { Hash.ruby2_keywords_hash?(nil) }.should raise_error(TypeError)
+ -> { Hash.ruby2_keywords_hash?(nil) }.should.raise(TypeError)
end
end
@@ -54,7 +54,7 @@ describe "Hash.ruby2_keywords_hash" do
end
it "raises TypeError for non-Hash" do
- -> { Hash.ruby2_keywords_hash(nil) }.should raise_error(TypeError)
+ -> { Hash.ruby2_keywords_hash(nil) }.should.raise(TypeError)
end
it "retains the default value" do
@@ -72,12 +72,10 @@ describe "Hash.ruby2_keywords_hash" do
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
+ 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
diff --git a/spec/ruby/core/hash/select_spec.rb b/spec/ruby/core/hash/select_spec.rb
index 38b0180b0e..60b2ce67c1 100644
--- a/spec/ruby/core/hash/select_spec.rb
+++ b/spec/ruby/core/hash/select_spec.rb
@@ -1,10 +1,112 @@
require_relative '../../spec_helper'
-require_relative 'shared/select'
+require_relative '../enumerable/shared/enumeratorized'
+require_relative 'fixtures/classes'
+require_relative 'shared/iteration'
describe "Hash#select" do
- it_behaves_like :hash_select, :select
+ before :each do
+ @hsh = { 1 => 2, 3 => 4, 5 => 6 }
+ @empty = {}
+ end
+
+ it "yields two arguments: key and value" do
+ all_args = []
+ { 1 => 2, 3 => 4 }.select { |*args| all_args << args }
+ all_args.sort.should == [[1, 2], [3, 4]]
+ end
+
+ it "returns a Hash of entries for which block is true" do
+ a_pairs = { 'a' => 9, 'c' => 4, 'b' => 5, 'd' => 2 }.select { |k,v| v % 2 == 0 }
+ a_pairs.should.instance_of?(Hash)
+ a_pairs.sort.should == [['c', 4], ['d', 2]]
+ end
+
+ it "processes entries with the same order as reject" do
+ h = { a: 9, c: 4, b: 5, d: 2 }
+
+ select_pairs = []
+ reject_pairs = []
+ h.dup.select{ |*pair| select_pairs << pair }
+ h.reject { |*pair| reject_pairs << pair }
+
+ select_pairs.should == reject_pairs
+ end
+
+ it "returns an Enumerator when called on a non-empty hash without a block" do
+ @hsh.select.should.instance_of?(Enumerator)
+ end
+
+ it "returns an Enumerator when called on an empty hash without a block" do
+ @empty.select.should.instance_of?(Enumerator)
+ end
+
+ it "does not retain the default value" do
+ h = Hash.new(1)
+ h.select { true }.default.should == nil
+ h[:a] = 1
+ h.select { true }.default.should == nil
+ end
+
+ it "does not retain the default_proc" do
+ pr = proc { |h, k| h[k] = [] }
+ h = Hash.new(&pr)
+ h.select { true }.default_proc.should == nil
+ h[:a] = 1
+ h.select { true }.default_proc.should == nil
+ end
+
+ it "retains compare_by_identity flag" do
+ h = { a: 9, c: 4 }.compare_by_identity
+ h2 = h.select { |k, _| k == :a }
+ h2.compare_by_identity?.should == true
+ end
+
+ it_behaves_like :hash_iteration_no_block, :select
+
+ before :each do
+ @object = { 1 => 2, 3 => 4, 5 => 6 }
+ end
+ it_behaves_like :enumeratorized_with_origin_size, :select
end
describe "Hash#select!" do
- it_behaves_like :hash_select!, :select!
+ before :each do
+ @hsh = { 1 => 2, 3 => 4, 5 => 6 }
+ @empty = {}
+ end
+
+ it "is equivalent to keep_if if changes are made" do
+ h = { a: 2 }
+ h.select! { |k,v| v <= 1 }.should.equal? h
+
+ h = { 1 => 2, 3 => 4 }
+ all_args_select = []
+ h.dup.select! { |*args| all_args_select << args }
+ all_args_select.should == [[1, 2], [3, 4]]
+ end
+
+ it "removes all entries if the block is false" do
+ h = { a: 1, b: 2, c: 3 }
+ h.select! { |k,v| false }.should.equal?(h)
+ h.should == {}
+ end
+
+ it "returns nil if no changes were made" do
+ { a: 1 }.select! { |k,v| v <= 1 }.should == nil
+ end
+
+ it "raises a FrozenError if called on an empty frozen instance" do
+ -> { HashSpecs.empty_frozen_hash.select! { false } }.should.raise(FrozenError)
+ end
+
+ it "raises a FrozenError if called on a frozen instance that would not be modified" do
+ -> { HashSpecs.frozen_hash.select! { true } }.should.raise(FrozenError)
+ end
+
+ it_behaves_like :hash_iteration_no_block, :select!
+
+ before :each do
+ @object = { 1 => 2, 3 => 4, 5 => 6 }
+ end
+ it_behaves_like :enumeratorized_with_origin_size, :select!
end
diff --git a/spec/ruby/core/hash/shared/comparison.rb b/spec/ruby/core/hash/shared/comparison.rb
index 07564e4cec..2b62837232 100644
--- a/spec/ruby/core/hash/shared/comparison.rb
+++ b/spec/ruby/core/hash/shared/comparison.rb
@@ -1,15 +1,15 @@
describe :hash_comparison, shared: true do
it "raises a TypeError if the right operand is not a hash" do
- -> { { a: 1 }.send(@method, 1) }.should raise_error(TypeError)
- -> { { a: 1 }.send(@method, nil) }.should raise_error(TypeError)
- -> { { a: 1 }.send(@method, []) }.should raise_error(TypeError)
+ -> { { a: 1 }.send(@method, 1) }.should.raise(TypeError)
+ -> { { a: 1 }.send(@method, nil) }.should.raise(TypeError)
+ -> { { a: 1 }.send(@method, []) }.should.raise(TypeError)
end
it "returns false if both hashes have the same keys but different values" do
h1 = { a: 1 }
h2 = { a: 2 }
- h1.send(@method, h2).should be_false
- h2.send(@method, h1).should be_false
+ h1.send(@method, h2).should == false
+ h2.send(@method, h1).should == false
end
end
diff --git a/spec/ruby/core/hash/shared/each.rb b/spec/ruby/core/hash/shared/each.rb
deleted file mode 100644
index f9839ff58f..0000000000
--- a/spec/ruby/core/hash/shared/each.rb
+++ /dev/null
@@ -1,105 +0,0 @@
-describe :hash_each, shared: true do
-
- # This is inconsistent with below, MRI checks the block arity in rb_hash_each_pair()
- it "yields a [[key, value]] Array for each pair to a block expecting |*args|" do
- all_args = []
- { 1 => 2, 3 => 4 }.send(@method) { |*args| all_args << args }
- all_args.sort.should == [[[1, 2]], [[3, 4]]]
- end
-
- it "yields the key and value of each pair to a block expecting |key, value|" do
- r = {}
- h = { a: 1, b: 2, c: 3, d: 5 }
- h.send(@method) { |k,v| r[k.to_s] = v.to_s }.should equal(h)
- r.should == { "a" => "1", "b" => "2", "c" => "3", "d" => "5" }
- end
-
- it "yields the key only to a block expecting |key,|" do
- ary = []
- h = { "a" => 1, "b" => 2, "c" => 3 }
- h.send(@method) { |k,| ary << k }
- 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
-
- -> {
- { "a" => 1 }.send(@method, &obj.method(:foo))
- }.should raise_error(ArgumentError)
-
- -> {
- { "a" => 1 }.send(@method, &-> key, value { })
- }.should raise_error(ArgumentError)
- end
-
- it "yields an Array of 2 elements when given a callable of arity 1" do
- obj = Object.new
- def obj.foo(key_value)
- ScratchPad << key_value
- end
-
- ScratchPad.record([])
- { "a" => 1 }.send(@method, &obj.method(:foo))
- ScratchPad.recorded.should == [["a", 1]]
- end
-
- it "raises an error for a Hash when an arity enforcing callable of arity >2 is passed in" do
- obj = Object.new
- def obj.foo(key, value, extra)
- end
-
- -> {
- { "a" => 1 }.send(@method, &obj.method(:foo))
- }.should raise_error(ArgumentError)
- end
-
- it "uses the same order as keys() and values()" do
- h = { a: 1, b: 2, c: 3, d: 5 }
- keys = []
- values = []
-
- h.send(@method) do |k, v|
- keys << k
- values << v
- end
-
- keys.should == h.keys
- values.should == h.values
- end
-
- # Confirming the argument-splatting works from child class for both k, v and [k, v]
- it "properly expands (or not) child class's 'each'-yielded args" do
- cls1 = Class.new(Hash) do
- attr_accessor :k_v
- def each
- super do |k, v|
- @k_v = [k, v]
- yield k, v
- end
- end
- end
-
- cls2 = Class.new(Hash) do
- attr_accessor :k_v
- def each
- super do |k, v|
- @k_v = [k, v]
- yield([k, v])
- end
- end
- end
-
- obj1 = cls1.new
- obj1['a'] = 'b'
- obj1.map {|k, v| [k, v]}.should == [['a', 'b']]
- obj1.k_v.should == ['a', 'b']
-
- obj2 = cls2.new
- obj2['a'] = 'b'
- obj2.map {|k, v| [k, v]}.should == [['a', 'b']]
- obj2.k_v.should == ['a', 'b']
- end
-end
diff --git a/spec/ruby/core/hash/shared/eql.rb b/spec/ruby/core/hash/shared/eql.rb
index 68db49f76d..512e1ad016 100644
--- a/spec/ruby/core/hash/shared/eql.rb
+++ b/spec/ruby/core/hash/shared/eql.rb
@@ -3,7 +3,7 @@ describe :hash_eql, shared: true do
value = mock('x')
value.should_not_receive(:==)
value.should_not_receive(:eql?)
- { 1 => value }.send(@method, { 2 => value }).should be_false
+ { 1 => value }.send(@method, { 2 => value }).should == false
end
it "returns false when the numbers of keys differ without comparing any elements" do
@@ -13,8 +13,8 @@ describe :hash_eql, shared: true do
obj.should_not_receive(:==)
obj.should_not_receive(:eql?)
- {}.send(@method, h).should be_false
- h.send(@method, {}).should be_false
+ {}.send(@method, h).should == false
+ h.send(@method, {}).should == false
end
it "first compares keys via hash" do
@@ -23,7 +23,7 @@ describe :hash_eql, shared: true do
y = mock('y')
y.should_receive(:hash).any_number_of_times.and_return(0)
- { x => 1 }.send(@method, { y => 1 }).should be_false
+ { x => 1 }.send(@method, { y => 1 }).should == false
end
it "does not compare keys with different hash codes via eql?" do
@@ -35,39 +35,39 @@ describe :hash_eql, shared: true do
x.should_receive(:hash).any_number_of_times.and_return(0)
y.should_receive(:hash).any_number_of_times.and_return(1)
- { x => 1 }.send(@method, { y => 1 }).should be_false
+ { x => 1 }.send(@method, { y => 1 }).should == 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
+ h.send(@method, h[:a]).should == true
+ (h == h[:a]).should == true
end
it "doesn't call to_hash on objects" do
mock_hash = mock("fake hash")
def mock_hash.to_hash() {} end
- {}.send(@method, mock_hash).should be_false
+ {}.send(@method, mock_hash).should == false
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!
+ a.send(@method, b).should == 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!
+ c.send(@method, a).should == 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.send(@method, a).should == false # not quite the same structure, as a[:other][:delta] = nil
c[:delta] = 42
- c.send(@method, a).should be_false
+ c.send(@method, a).should == false
a[:delta] = 42
- c.send(@method, a).should be_false
+ c.send(@method, a).should == false
b[:delta] = 42
- c.send(@method, a).should be_true
+ c.send(@method, a).should == true
end
it "computes equality for recursive hashes & arrays" do
@@ -76,19 +76,19 @@ describe :hash_eql, shared: true do
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
+ b.send(@method, c).should == true # they clearly have the same structure!
+ y.send(@method, z).should == true
+ a.send(@method, b).should == true # subtle, but they both have the same structure!
+ x.send(@method, y).should == true
y << x
- y.send(@method, z).should be_false
+ y.send(@method, z).should == false
z << x
- y.send(@method, z).should be_true
+ y.send(@method, z).should == true
a[:foo], a[:bar] = a[:bar], a[:foo]
- a.send(@method, b).should be_false
+ a.send(@method, b).should == false
b[:bar] = b[:foo]
- b.send(@method, c).should be_false
+ b.send(@method, c).should == false
end
end
@@ -100,7 +100,7 @@ describe :hash_eql_additional, shared: true do
def y.==(o) false end
def x.eql?(o) false end
def y.eql?(o) false end
- { 1 => x }.send(@method, { 1 => y }).should be_false
+ { 1 => x }.send(@method, { 1 => y }).should == false
x = mock('x')
y = mock('y')
@@ -108,45 +108,45 @@ describe :hash_eql_additional, shared: true do
def y.==(o) true end
def x.eql?(o) true end
def y.eql?(o) true end
- { 1 => x }.send(@method, { 1 => y }).should be_true
+ { 1 => x }.send(@method, { 1 => y }).should == true
end
it "compares keys with eql? semantics" do
- { 1.0 => "x" }.send(@method, { 1.0 => "x" }).should be_true
- { 1.0 => "x" }.send(@method, { 1.0 => "x" }).should be_true
- { 1 => "x" }.send(@method, { 1.0 => "x" }).should be_false
- { 1.0 => "x" }.send(@method, { 1 => "x" }).should be_false
+ { 1.0 => "x" }.send(@method, { 1.0 => "x" }).should == true
+ { 1.0 => "x" }.send(@method, { 1.0 => "x" }).should == true
+ { 1 => "x" }.send(@method, { 1.0 => "x" }).should == false
+ { 1.0 => "x" }.send(@method, { 1 => "x" }).should == false
end
it "returns true if and only if other Hash has the same number of keys and each key-value pair matches" do
a = { a: 5 }
b = {}
- a.send(@method, b).should be_false
+ a.send(@method, b).should == false
b[:a] = 5
- a.send(@method, b).should be_true
+ a.send(@method, b).should == true
not_supported_on :opal do
c = { "a" => 5 }
- a.send(@method, c).should be_false
+ a.send(@method, c).should == false
end
c = { "A" => 5 }
- a.send(@method, c).should be_false
+ a.send(@method, c).should == false
c = { a: 6 }
- a.send(@method, c).should be_false
+ a.send(@method, c).should == false
end
it "does not call to_hash on hash subclasses" do
- { 5 => 6 }.send(@method, HashSpecs::ToHashHash[5 => 6]).should be_true
+ { 5 => 6 }.send(@method, HashSpecs::ToHashHash[5 => 6]).should == true
end
it "ignores hash class differences" do
h = { 1 => 2, 3 => 4 }
- HashSpecs::MyHash[h].send(@method, h).should be_true
- HashSpecs::MyHash[h].send(@method, HashSpecs::MyHash[h]).should be_true
- h.send(@method, HashSpecs::MyHash[h]).should be_true
+ HashSpecs::MyHash[h].send(@method, h).should == true
+ HashSpecs::MyHash[h].send(@method, HashSpecs::MyHash[h]).should == true
+ h.send(@method, HashSpecs::MyHash[h]).should == true
end
# Why isn't this true of eql? too ?
@@ -163,7 +163,7 @@ describe :hash_eql_additional, shared: true do
obj
end
- { a[0] => 1 }.send(@method, { a[1] => 1 }).should be_false
+ { a[0] => 1 }.send(@method, { a[1] => 1 }).should == false
a = Array.new(2) do
obj = mock('0')
@@ -176,7 +176,7 @@ describe :hash_eql_additional, shared: true do
obj
end
- { a[0] => 1 }.send(@method, { a[1] => 1 }).should be_true
+ { a[0] => 1 }.send(@method, { a[1] => 1 }).should == true
end
it "compares the values in self to values in other hash" do
@@ -185,20 +185,20 @@ describe :hash_eql_additional, shared: true do
l_val.should_receive(:eql?).with(r_val).and_return(true)
- { 1 => l_val }.eql?({ 1 => r_val }).should be_true
+ { 1 => l_val }.eql?({ 1 => r_val }).should == true
end
end
describe :hash_eql_additional_more, shared: true do
it "returns true if other Hash has the same number of keys and each key-value pair matches, even though the default-value are not same" do
- Hash.new(5).send(@method, Hash.new(1)).should be_true
- Hash.new {|h, k| 1}.send(@method, Hash.new {}).should be_true
- Hash.new {|h, k| 1}.send(@method, Hash.new(2)).should be_true
+ Hash.new(5).send(@method, Hash.new(1)).should == true
+ Hash.new {|h, k| 1}.send(@method, Hash.new {}).should == true
+ Hash.new {|h, k| 1}.send(@method, Hash.new(2)).should == true
d = Hash.new {|h, k| 1}
e = Hash.new {}
d[1] = 2
e[1] = 2
- d.send(@method, e).should be_true
+ d.send(@method, e).should == true
end
end
diff --git a/spec/ruby/core/hash/shared/greater_than.rb b/spec/ruby/core/hash/shared/greater_than.rb
index 1f8b9fcfb7..dfe0b80250 100644
--- a/spec/ruby/core/hash/shared/greater_than.rb
+++ b/spec/ruby/core/hash/shared/greater_than.rb
@@ -5,11 +5,11 @@ describe :hash_greater_than, shared: true do
end
it "returns true if the other hash is a subset of self" do
- @h1.send(@method, @h2).should be_true
+ @h1.send(@method, @h2).should == true
end
it "returns false if the other hash is not a subset of self" do
- @h2.send(@method, @h1).should be_false
+ @h2.send(@method, @h1).should == false
end
it "converts the right operand to a hash before comparing" do
@@ -18,6 +18,6 @@ describe :hash_greater_than, shared: true do
{ a: 1, b: 2 }
end
- @h1.send(@method, o).should be_true
+ @h1.send(@method, o).should == true
end
end
diff --git a/spec/ruby/core/hash/shared/index.rb b/spec/ruby/core/hash/shared/index.rb
deleted file mode 100644
index 7f6a186464..0000000000
--- a/spec/ruby/core/hash/shared/index.rb
+++ /dev/null
@@ -1,37 +0,0 @@
-require_relative '../../../spec_helper'
-require_relative '../fixtures/classes'
-
-describe :hash_index, shared: true do
- it "returns the corresponding key for value" do
- suppress_warning do # for Hash#index
- { 2 => 'a', 1 => 'b' }.send(@method, 'b').should == 1
- end
- end
-
- it "returns nil if the value is not found" do
- suppress_warning do # for Hash#index
- { a: -1, b: 3.14, c: 2.718 }.send(@method, 1).should be_nil
- end
- end
-
- it "doesn't return default value if the value is not found" do
- suppress_warning do # for Hash#index
- Hash.new(5).send(@method, 5).should be_nil
- end
- end
-
- it "compares values using ==" do
- suppress_warning do # for Hash#index
- { 1 => 0 }.send(@method, 0.0).should == 1
- { 1 => 0.0 }.send(@method, 0).should == 1
- end
-
- needle = mock('needle')
- inhash = mock('inhash')
- inhash.should_receive(:==).with(needle).and_return(true)
-
- suppress_warning do # for Hash#index
- { 1 => inhash }.send(@method, needle).should == 1
- end
- end
-end
diff --git a/spec/ruby/core/hash/shared/iteration.rb b/spec/ruby/core/hash/shared/iteration.rb
index d27c2443f8..322e4b9a2f 100644
--- a/spec/ruby/core/hash/shared/iteration.rb
+++ b/spec/ruby/core/hash/shared/iteration.rb
@@ -5,15 +5,15 @@ describe :hash_iteration_no_block, shared: true do
end
it "returns an Enumerator if called on a non-empty hash without a block" do
- @hsh.send(@method).should be_an_instance_of(Enumerator)
+ @hsh.send(@method).should.instance_of?(Enumerator)
end
it "returns an Enumerator if called on an empty hash without a block" do
- @empty.send(@method).should be_an_instance_of(Enumerator)
+ @empty.send(@method).should.instance_of?(Enumerator)
end
it "returns an Enumerator if called on a frozen instance" do
@hsh.freeze
- @hsh.send(@method).should be_an_instance_of(Enumerator)
+ @hsh.send(@method).should.instance_of?(Enumerator)
end
end
diff --git a/spec/ruby/core/hash/shared/key.rb b/spec/ruby/core/hash/shared/key.rb
deleted file mode 100644
index 17f9f81457..0000000000
--- a/spec/ruby/core/hash/shared/key.rb
+++ /dev/null
@@ -1,38 +0,0 @@
-describe :hash_key_p, shared: true do
- it "returns true if argument is a key" do
- h = { a: 1, b: 2, c: 3, 4 => 0 }
- h.send(@method, :a).should == true
- h.send(@method, :b).should == true
- h.send(@method, 2).should == false
- h.send(@method, 4).should == true
-
- not_supported_on :opal do
- h.send(@method, 'b').should == false
- h.send(@method, 4.0).should == false
- end
- end
-
- it "returns true if the key's matching value was nil" do
- { xyz: nil }.send(@method, :xyz).should == true
- end
-
- it "returns true if the key's matching value was false" do
- { xyz: false }.send(@method, :xyz).should == true
- end
-
- it "returns true if the key is nil" do
- { nil => 'b' }.send(@method, nil).should == true
- { nil => nil }.send(@method, nil).should == true
- end
-
- it "compares keys with the same #hash value via #eql?" do
- x = mock('x')
- x.stub!(:hash).and_return(42)
-
- y = mock('y')
- y.stub!(:hash).and_return(42)
- y.should_receive(:eql?).and_return(false)
-
- { x => nil }.send(@method, y).should == false
- end
-end
diff --git a/spec/ruby/core/hash/shared/length.rb b/spec/ruby/core/hash/shared/length.rb
deleted file mode 100644
index 24f5563759..0000000000
--- a/spec/ruby/core/hash/shared/length.rb
+++ /dev/null
@@ -1,12 +0,0 @@
-describe :hash_length, shared: true do
- it "returns the number of entries" do
- { a: 1, b: 'c' }.send(@method).should == 2
- h = { a: 1, b: 2 }
- h[:a] = 2
- h.send(@method).should == 2
- { a: 1, b: 1, c: 1 }.send(@method).should == 3
- {}.send(@method).should == 0
- Hash.new(5).send(@method).should == 0
- Hash.new { 5 }.send(@method).should == 0
- end
-end
diff --git a/spec/ruby/core/hash/shared/less_than.rb b/spec/ruby/core/hash/shared/less_than.rb
index cdc6f14546..071b3e97bb 100644
--- a/spec/ruby/core/hash/shared/less_than.rb
+++ b/spec/ruby/core/hash/shared/less_than.rb
@@ -5,11 +5,11 @@ describe :hash_less_than, shared: true do
end
it "returns true if self is a subset of the other hash" do
- @h1.send(@method, @h2).should be_true
+ @h1.send(@method, @h2).should == true
end
it "returns false if self is not a subset of the other hash" do
- @h2.send(@method, @h1).should be_false
+ @h2.send(@method, @h1).should == false
end
it "converts the right operand to a hash before comparing" do
@@ -18,6 +18,6 @@ describe :hash_less_than, shared: true do
{ a: 1, b: 2, c: 3 }
end
- @h1.send(@method, o).should be_true
+ @h1.send(@method, o).should == true
end
end
diff --git a/spec/ruby/core/hash/shared/select.rb b/spec/ruby/core/hash/shared/select.rb
deleted file mode 100644
index 5170af50d6..0000000000
--- a/spec/ruby/core/hash/shared/select.rb
+++ /dev/null
@@ -1,91 +0,0 @@
-require_relative '../../../spec_helper'
-require_relative '../fixtures/classes'
-require_relative '../shared/iteration'
-require_relative '../../enumerable/shared/enumeratorized'
-
-describe :hash_select, shared: true do
- before :each do
- @hsh = { 1 => 2, 3 => 4, 5 => 6 }
- @empty = {}
- end
-
- it "yields two arguments: key and value" do
- all_args = []
- { 1 => 2, 3 => 4 }.send(@method) { |*args| all_args << args }
- all_args.sort.should == [[1, 2], [3, 4]]
- end
-
- it "returns a Hash of entries for which block is true" do
- a_pairs = { 'a' => 9, 'c' => 4, 'b' => 5, 'd' => 2 }.send(@method) { |k,v| v % 2 == 0 }
- a_pairs.should be_an_instance_of(Hash)
- a_pairs.sort.should == [['c', 4], ['d', 2]]
- end
-
- it "processes entries with the same order as reject" do
- h = { a: 9, c: 4, b: 5, d: 2 }
-
- select_pairs = []
- reject_pairs = []
- h.dup.send(@method) { |*pair| select_pairs << pair }
- h.reject { |*pair| reject_pairs << pair }
-
- select_pairs.should == reject_pairs
- end
-
- it "returns an Enumerator when called on a non-empty hash without a block" do
- @hsh.send(@method).should be_an_instance_of(Enumerator)
- end
-
- it "returns an Enumerator when called on an empty hash without a block" do
- @empty.send(@method).should be_an_instance_of(Enumerator)
- end
-
- it_should_behave_like :hash_iteration_no_block
-
- before :each do
- @object = { 1 => 2, 3 => 4, 5 => 6 }
- end
- it_should_behave_like :enumeratorized_with_origin_size
-end
-
-describe :hash_select!, shared: true do
- before :each do
- @hsh = { 1 => 2, 3 => 4, 5 => 6 }
- @empty = {}
- end
-
- it "is equivalent to keep_if if changes are made" do
- h = { a: 2 }
- h.send(@method) { |k,v| v <= 1 }.should equal h
-
- h = { 1 => 2, 3 => 4 }
- all_args_select = []
- h.dup.send(@method) { |*args| all_args_select << args }
- all_args_select.should == [[1, 2], [3, 4]]
- end
-
- it "removes all entries if the block is false" do
- h = { a: 1, b: 2, c: 3 }
- h.send(@method) { |k,v| false }.should equal(h)
- h.should == {}
- end
-
- it "returns nil if no changes were made" do
- { a: 1 }.send(@method) { |k,v| v <= 1 }.should == nil
- end
-
- it "raises a FrozenError if called on an empty frozen instance" do
- -> { HashSpecs.empty_frozen_hash.send(@method) { false } }.should raise_error(FrozenError)
- end
-
- it "raises a FrozenError if called on a frozen instance that would not be modified" do
- -> { HashSpecs.frozen_hash.send(@method) { true } }.should raise_error(FrozenError)
- end
-
- it_should_behave_like :hash_iteration_no_block
-
- before :each do
- @object = { 1 => 2, 3 => 4, 5 => 6 }
- end
- it_should_behave_like :enumeratorized_with_origin_size
-end
diff --git a/spec/ruby/core/hash/shared/store.rb b/spec/ruby/core/hash/shared/store.rb
deleted file mode 100644
index 72a462a42f..0000000000
--- a/spec/ruby/core/hash/shared/store.rb
+++ /dev/null
@@ -1,115 +0,0 @@
-require_relative '../fixtures/classes'
-
-describe :hash_store, shared: true do
- it "associates the key with the value and return the value" do
- h = { a: 1 }
- h.send(@method, :b, 2).should == 2
- h.should == { b:2, a:1 }
- end
-
- it "duplicates string keys using dup semantics" do
- # dup doesn't copy singleton methods
- key = +"foo"
- def key.reverse() "bar" end
- h = {}
- h.send(@method, key, 0)
- h.keys[0].reverse.should == "oof"
- end
-
- it "stores unequal keys that hash to the same value" do
- h = {}
- k1 = ["x"]
- k2 = ["y"]
- # So they end up in the same bucket
- k1.should_receive(:hash).and_return(0)
- k2.should_receive(:hash).and_return(0)
-
- h.send(@method, k1, 1)
- h.send(@method, k2, 2)
- h.size.should == 2
- end
-
- it "accepts keys with private #hash method" do
- key = HashSpecs::KeyWithPrivateHash.new
- h = {}
- h.send(@method, key, "foo")
- h[key].should == "foo"
- end
-
- it " accepts keys with an Integer hash" do
- o = mock(hash: 1 << 100)
- h = {}
- h[o] = 1
- h[o].should == 1
- end
-
- it "duplicates and freezes string keys" do
- key = +"foo"
- h = {}
- h.send(@method, key, 0)
- key << "bar"
-
- h.should == { "foo" => 0 }
- h.keys[0].should.frozen?
- end
-
- it "doesn't duplicate and freeze already frozen string keys" do
- key = "foo".freeze
- h = {}
- h.send(@method, key, 0)
- h.keys[0].should equal(key)
- end
-
- it "keeps the existing key in the hash if there is a matching one" do
- h = { "a" => 1, "b" => 2, "c" => 3, "d" => 4 }
- key1 = HashSpecs::ByValueKey.new(13)
- key2 = HashSpecs::ByValueKey.new(13)
- h[key1] = 41
- key_in_hash = h.keys.last
- key_in_hash.should equal(key1)
- h[key2] = 42
- last_key = h.keys.last
- last_key.should equal(key_in_hash)
- last_key.should_not equal(key2)
- end
-
- 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.should_not equal(key2)
- h[key1] = 41
- frozen_key = h.keys.last
- frozen_key.should_not equal(key1)
- h[key2] = 42
- h.keys.last.should equal(frozen_key)
- h.keys.last.should_not equal(key2)
- end
-
- it "raises a FrozenError if called on a frozen instance" do
- -> { HashSpecs.frozen_hash.send(@method, 1, 2) }.should raise_error(FrozenError)
- end
-
- it "does not raise an exception if changing the value of an existing key during iteration" do
- hash = {1 => 2, 3 => 4, 5 => 6}
- hash.each { hash.send(@method, 1, :foo) }
- hash.should == {1 => :foo, 3 => 4, 5 => 6}
- end
-
- it "does not dispatch to hash for Boolean, Integer, Float, String, or Symbol" do
- code = <<-EOC
- load '#{fixture __FILE__, "name.rb"}'
- hash = {}
- [true, false, 1, 2.0, "hello", :ok].each do |value|
- hash[value] = 42
- raise "incorrect value" unless hash[value] == 42
- hash[value] = 43
- raise "incorrect value" unless hash[value] == 43
- end
- puts "OK"
- puts hash.size
- EOC
- result = ruby_exe(code, args: "2>&1")
- result.should == "OK\n6\n"
- end
-end
diff --git a/spec/ruby/core/hash/shared/to_s.rb b/spec/ruby/core/hash/shared/to_s.rb
deleted file mode 100644
index e116b8878b..0000000000
--- a/spec/ruby/core/hash/shared/to_s.rb
+++ /dev/null
@@ -1,93 +0,0 @@
-require_relative '../../../spec_helper'
-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
- end
-
- it "calls #inspect on keys and values" do
- key = mock('key')
- 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
- end
-
- it "does not call #to_s on a String returned from #inspect" do
- str = +"abc"
- str.should_not_receive(:to_s)
- expected = ruby_version_is("3.4") ? '{a: "abc"}' : '{:a=>"abc"}'
- { a: str }.send(@method).should == expected
- 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
- 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
- end
-
- it "does not call #to_str on the object returned from #to_s when it is not a String" do
- obj = mock("Hash#inspect/to_s does not call #to_str on #to_s result")
- 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
- end
-
- it "does not swallow exceptions raised by #to_s" do
- obj = mock("Hash#inspect/to_s does not swallow #to_s exceptions")
- obj.should_receive(:inspect).and_return(obj)
- obj.should_receive(:to_s).and_raise(Exception)
-
- -> { { a: obj }.send(@method) }.should raise_error(Exception)
- end
-
- 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 = {}
- 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
- 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
- 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
- end
-
- ruby_version_is "3.4" do
- it "adds quotes to symbol keys that are not valid symbol literals" do
- { "needs-quotes": 1 }.send(@method).should == '{"needs-quotes": 1}'
- end
- end
-end
diff --git a/spec/ruby/core/hash/shared/update.rb b/spec/ruby/core/hash/shared/update.rb
deleted file mode 100644
index 1b0eb809bf..0000000000
--- a/spec/ruby/core/hash/shared/update.rb
+++ /dev/null
@@ -1,76 +0,0 @@
-describe :hash_update, shared: true do
- it "adds the entries from other, overwriting duplicate keys. Returns self" do
- h = { _1: 'a', _2: '3' }
- h.send(@method, _1: '9', _9: 2).should equal(h)
- h.should == { _1: "9", _2: "3", _9: 2 }
- end
-
- it "sets any duplicate key to the value of block if passed a block" do
- h1 = { a: 2, b: -1 }
- h2 = { a: -2, c: 1 }
- h1.send(@method, h2) { |k,x,y| 3.14 }.should equal(h1)
- h1.should == { c: 1, b: -1, a: 3.14 }
-
- h1.send(@method, h1) { nil }
- h1.should == { a: nil, b: nil, c: nil }
- end
-
- it "tries to convert the passed argument to a hash using #to_hash" do
- obj = mock('{1=>2}')
- obj.should_receive(:to_hash).and_return({ 1 => 2 })
- { 3 => 4 }.send(@method, obj).should == { 1 => 2, 3 => 4 }
- end
-
- it "does not call to_hash on hash subclasses" do
- { 3 => 4 }.send(@method, HashSpecs::ToHashHash[1 => 2]).should == { 1 => 2, 3 => 4 }
- end
-
- it "processes entries with same order as merge()" do
- h = { 1 => 2, 3 => 4, 5 => 6, "x" => nil, nil => 5, [] => [] }
- merge_bang_pairs = []
- merge_pairs = []
- h.merge(h) { |*arg| merge_pairs << arg }
- h.send(@method, h) { |*arg| merge_bang_pairs << arg }
- merge_bang_pairs.should == merge_pairs
- end
-
- it "raises a FrozenError on a frozen instance that is modified" do
- -> do
- HashSpecs.frozen_hash.send(@method, 1 => 2)
- end.should raise_error(FrozenError)
- end
-
- it "checks frozen status before coercing an object with #to_hash" do
- obj = mock("to_hash frozen")
- # This is necessary because mock cleanup code cannot run on the frozen
- # object.
- def obj.to_hash() raise Exception, "should not receive #to_hash" end
- obj.freeze
-
- -> { HashSpecs.frozen_hash.send(@method, obj) }.should raise_error(FrozenError)
- end
-
- # see redmine #1571
- it "raises a FrozenError on a frozen instance that would not be modified" do
- -> do
- HashSpecs.frozen_hash.send(@method, HashSpecs.empty_frozen_hash)
- end.should raise_error(FrozenError)
- end
-
- it "does not raise an exception if changing the value of an existing key during iteration" do
- hash = {1 => 2, 3 => 4, 5 => 6}
- hash2 = {1 => :foo, 3 => :bar}
- hash.each { hash.send(@method, hash2) }
- hash.should == {1 => :foo, 3 => :bar, 5 => 6}
- end
-
- it "accepts multiple hashes" do
- result = { a: 1 }.send(@method, { b: 2 }, { c: 3 }, { d: 4 })
- result.should == { a: 1, b: 2, c: 3, d: 4 }
- end
-
- it "accepts zero arguments" do
- hash = { a: 1 }
- hash.send(@method).should eql(hash)
- end
-end
diff --git a/spec/ruby/core/hash/shared/value.rb b/spec/ruby/core/hash/shared/value.rb
deleted file mode 100644
index aac76c253e..0000000000
--- a/spec/ruby/core/hash/shared/value.rb
+++ /dev/null
@@ -1,14 +0,0 @@
-describe :hash_value_p, shared: true do
- it "returns true if the value exists in the hash" do
- { a: :b }.send(@method, :a).should == false
- { 1 => 2 }.send(@method, 2).should == true
- h = Hash.new(5)
- h.send(@method, 5).should == false
- h = Hash.new { 5 }
- h.send(@method, 5).should == false
- end
-
- it "uses == semantics for comparing values" do
- { 5 => 2.0 }.send(@method, 2).should == true
- end
-end
diff --git a/spec/ruby/core/hash/shared/values_at.rb b/spec/ruby/core/hash/shared/values_at.rb
deleted file mode 100644
index ef3b0e8ba0..0000000000
--- a/spec/ruby/core/hash/shared/values_at.rb
+++ /dev/null
@@ -1,9 +0,0 @@
-describe :hash_values_at, shared: true do
- it "returns an array of values for the given keys" do
- h = { a: 9, b: 'a', c: -10, d: nil }
- h.send(@method).should be_kind_of(Array)
- h.send(@method).should == []
- h.send(@method, :a, :d, :b).should be_kind_of(Array)
- h.send(@method, :a, :d, :b).should == [9, nil, 'a']
- end
-end
diff --git a/spec/ruby/core/hash/shift_spec.rb b/spec/ruby/core/hash/shift_spec.rb
index 3f31b9864c..6095d2e55f 100644
--- a/spec/ruby/core/hash/shift_spec.rb
+++ b/spec/ruby/core/hash/shift_spec.rb
@@ -8,7 +8,7 @@ describe "Hash#shift" do
h.size.times do |i|
r = h.shift
- r.should be_kind_of(Array)
+ r.should.is_a?(Array)
h2[r.first].should == r.last
h.size.should == h2.size - i - 1
end
@@ -57,8 +57,8 @@ describe "Hash#shift" do
end
it "raises a FrozenError if called on a frozen instance" do
- -> { HashSpecs.frozen_hash.shift }.should raise_error(FrozenError)
- -> { HashSpecs.empty_frozen_hash.shift }.should raise_error(FrozenError)
+ -> { HashSpecs.frozen_hash.shift }.should.raise(FrozenError)
+ -> { HashSpecs.empty_frozen_hash.shift }.should.raise(FrozenError)
end
it "works when the hash is at capacity" do
diff --git a/spec/ruby/core/hash/size_spec.rb b/spec/ruby/core/hash/size_spec.rb
index 1e8abd8d97..5e5008a5dc 100644
--- a/spec/ruby/core/hash/size_spec.rb
+++ b/spec/ruby/core/hash/size_spec.rb
@@ -1,7 +1,14 @@
require_relative '../../spec_helper'
-require_relative 'fixtures/classes'
-require_relative 'shared/length'
describe "Hash#size" do
- it_behaves_like :hash_length, :size
+ it "returns the number of entries" do
+ { a: 1, b: 'c' }.size.should == 2
+ h = { a: 1, b: 2 }
+ h[:a] = 2
+ h.size.should == 2
+ { a: 1, b: 1, c: 1 }.size.should == 3
+ {}.size.should == 0
+ Hash.new(5).size.should == 0
+ Hash.new { 5 }.size.should == 0
+ end
end
diff --git a/spec/ruby/core/hash/slice_spec.rb b/spec/ruby/core/hash/slice_spec.rb
index e3046d83d7..fd93254517 100644
--- a/spec/ruby/core/hash/slice_spec.rb
+++ b/spec/ruby/core/hash/slice_spec.rb
@@ -7,8 +7,8 @@ describe "Hash#slice" do
it "returns a new empty hash without arguments" do
ret = @hash.slice
- ret.should_not equal(@hash)
- ret.should be_an_instance_of(Hash)
+ ret.should_not.equal?(@hash)
+ ret.should.instance_of?(Hash)
ret.should == {}
end
@@ -50,4 +50,25 @@ describe "Hash#slice" do
ScratchPad.recorded.should == []
end
+
+ it "does not retain the default value" do
+ h = Hash.new(1)
+ h.slice(:a).default.should == nil
+ h[:a] = 1
+ h.slice(:a).default.should == nil
+ end
+
+ it "does not retain the default_proc" do
+ pr = proc { |h, k| h[k] = [] }
+ h = Hash.new(&pr)
+ h.slice(:a).default_proc.should == nil
+ h[:a] = 1
+ h.slice(:a).default_proc.should == nil
+ end
+
+ it "retains compare_by_identity flag" do
+ h = { a: 9, c: 4 }.compare_by_identity
+ h2 = h.slice(:a)
+ h2.compare_by_identity?.should == true
+ end
end
diff --git a/spec/ruby/core/hash/store_spec.rb b/spec/ruby/core/hash/store_spec.rb
index 7e975380ec..7017d8ba2b 100644
--- a/spec/ruby/core/hash/store_spec.rb
+++ b/spec/ruby/core/hash/store_spec.rb
@@ -1,7 +1,7 @@
require_relative '../../spec_helper'
-require_relative 'fixtures/classes'
-require_relative 'shared/store'
describe "Hash#store" do
- it_behaves_like :hash_store, :store
+ it "is an alias of Hash#[]=" do
+ Hash.instance_method(:store).should == Hash.instance_method(:[]=)
+ end
end
diff --git a/spec/ruby/core/hash/to_a_spec.rb b/spec/ruby/core/hash/to_a_spec.rb
index 5baf677929..8c638db6c3 100644
--- a/spec/ruby/core/hash/to_a_spec.rb
+++ b/spec/ruby/core/hash/to_a_spec.rb
@@ -10,7 +10,7 @@ describe "Hash#to_a" do
pairs << [key, value]
end
- h.to_a.should be_kind_of(Array)
+ h.to_a.should.is_a?(Array)
h.to_a.should == pairs
end
@@ -23,7 +23,7 @@ describe "Hash#to_a" do
end
ent = h.entries
- ent.should be_kind_of(Array)
+ ent.should.is_a?(Array)
ent.should == pairs
end
end
diff --git a/spec/ruby/core/hash/to_h_spec.rb b/spec/ruby/core/hash/to_h_spec.rb
index e17ca7e671..5d5a280dac 100644
--- a/spec/ruby/core/hash/to_h_spec.rb
+++ b/spec/ruby/core/hash/to_h_spec.rb
@@ -4,7 +4,7 @@ require_relative 'fixtures/classes'
describe "Hash#to_h" do
it "returns self for Hash instances" do
h = {}
- h.to_h.should equal(h)
+ h.to_h.should.equal?(h)
end
describe "when called on a subclass of Hash" do
@@ -14,22 +14,27 @@ describe "Hash#to_h" do
end
it "returns a new Hash instance" do
- @h.to_h.should be_an_instance_of(Hash)
+ @h.to_h.should.instance_of?(Hash)
@h.to_h.should == @h
@h[:foo].should == :bar
end
- it "copies the default" do
+ it "retains the default" do
@h.default = 42
@h.to_h.default.should == 42
@h[:hello].should == 42
end
- it "copies the default_proc" do
+ it "retains the default_proc" do
@h.default_proc = prc = Proc.new{ |h, k| h[k] = 2 * k }
@h.to_h.default_proc.should == prc
@h[42].should == 84
end
+
+ it "retains compare_by_identity flag" do
+ @h.compare_by_identity
+ @h.to_h.compare_by_identity?.should == true
+ end
end
context "with block" do
@@ -50,17 +55,17 @@ describe "Hash#to_h" do
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] }
- end.should raise_error(ArgumentError, /element has wrong array length/)
+ end.should.raise(ArgumentError, /element has wrong array length/)
-> do
{ a: 1, b: 2 }.to_h { |k, v| [k] }
- end.should raise_error(ArgumentError, /element has wrong array length/)
+ end.should.raise(ArgumentError, /element has wrong array length/)
end
it "raises TypeError if block returns something other than Array" do
-> do
{ a: 1, b: 2 }.to_h { |k, v| "not-array" }
- end.should raise_error(TypeError, /wrong element type String/)
+ end.should.raise(TypeError, /wrong element type String/)
end
it "coerces returned pair to Array with #to_ary" do
@@ -76,7 +81,26 @@ describe "Hash#to_h" do
-> do
{ a: 1 }.to_h { |k| x }
- end.should raise_error(TypeError, /wrong element type MockObject/)
+ end.should.raise(TypeError, /wrong element type MockObject/)
+ end
+
+ it "does not retain the default value" do
+ h = Hash.new(1)
+ h2 = h.to_h { |k, v| [k.to_s, v*v]}
+ h2.default.should == nil
+ end
+
+ it "does not retain the default_proc" do
+ pr = proc { |h, k| h[k] = [] }
+ h = Hash.new(&pr)
+ h2 = h.to_h { |k, v| [k.to_s, v*v]}
+ h2.default_proc.should == nil
+ end
+
+ it "does not retain compare_by_identity flag" do
+ h = { a: 9, c: 4 }.compare_by_identity
+ h2 = h.to_h { |k, v| [k.to_s, v*v]}
+ h2.compare_by_identity?.should == false
end
end
end
diff --git a/spec/ruby/core/hash/to_hash_spec.rb b/spec/ruby/core/hash/to_hash_spec.rb
index f479fa1fb2..f5622b3d9c 100644
--- a/spec/ruby/core/hash/to_hash_spec.rb
+++ b/spec/ruby/core/hash/to_hash_spec.rb
@@ -4,11 +4,11 @@ require_relative 'fixtures/classes'
describe "Hash#to_hash" do
it "returns self for Hash instances" do
h = {}
- h.to_hash.should equal(h)
+ h.to_hash.should.equal?(h)
end
it "returns self for instances of subclasses of Hash" do
h = HashSpecs::MyHash.new
- h.to_hash.should equal(h)
+ h.to_hash.should.equal?(h)
end
end
diff --git a/spec/ruby/core/hash/to_proc_spec.rb b/spec/ruby/core/hash/to_proc_spec.rb
index 9dbc79e5eb..bc4756600d 100644
--- a/spec/ruby/core/hash/to_proc_spec.rb
+++ b/spec/ruby/core/hash/to_proc_spec.rb
@@ -11,7 +11,7 @@ describe "Hash#to_proc" do
end
it "returns an instance of Proc" do
- @hash.to_proc.should be_an_instance_of Proc
+ @hash.to_proc.should.instance_of? Proc
end
describe "the returned proc" do
@@ -30,22 +30,22 @@ describe "Hash#to_proc" do
it "raises ArgumentError if not passed exactly one argument" do
-> {
@proc.call
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
-> {
@proc.call 1, 2
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
context "with a stored key" do
it "returns the paired value" do
- @proc.call(@key).should equal(@value)
+ @proc.call(@key).should.equal?(@value)
end
end
context "passed as a block" do
it "retrieves the hash's values" do
- [@key].map(&@proc)[0].should equal(@value)
+ [@key].map(&@proc)[0].should.equal?(@value)
end
context "to instance_exec" do
@@ -63,7 +63,7 @@ describe "Hash#to_proc" do
context "with no stored key" do
it "returns nil" do
- @proc.call(@unstored).should be_nil
+ @proc.call(@unstored).should == nil
end
context "when the hash has a default value" do
@@ -72,7 +72,7 @@ describe "Hash#to_proc" do
end
it "returns the default value" do
- @proc.call(@unstored).should equal(@default)
+ @proc.call(@unstored).should.equal?(@default)
end
end
@@ -85,7 +85,7 @@ describe "Hash#to_proc" do
end
it "raises an ArgumentError when calling #call on the Proc with no arguments" do
- -> { @hash.to_proc.call }.should raise_error(ArgumentError)
+ -> { @hash.to_proc.call }.should.raise(ArgumentError)
end
end
end
diff --git a/spec/ruby/core/hash/to_s_spec.rb b/spec/ruby/core/hash/to_s_spec.rb
index e52b09962e..2915db6ef8 100644
--- a/spec/ruby/core/hash/to_s_spec.rb
+++ b/spec/ruby/core/hash/to_s_spec.rb
@@ -1,7 +1,7 @@
require_relative '../../spec_helper'
-require_relative 'fixtures/classes'
-require_relative 'shared/to_s'
describe "Hash#to_s" do
- it_behaves_like :hash_to_s, :to_s
+ it "is an alias of Hash#inspect" do
+ Hash.instance_method(:to_s).should == Hash.instance_method(:inspect)
+ end
end
diff --git a/spec/ruby/core/hash/transform_keys_spec.rb b/spec/ruby/core/hash/transform_keys_spec.rb
index f63d39ecc8..d37a2b8616 100644
--- a/spec/ruby/core/hash/transform_keys_spec.rb
+++ b/spec/ruby/core/hash/transform_keys_spec.rb
@@ -7,8 +7,8 @@ describe "Hash#transform_keys" do
it "returns new hash" do
ret = @hash.transform_keys(&:succ)
- ret.should_not equal(@hash)
- ret.should be_an_instance_of(Hash)
+ ret.should_not.equal?(@hash)
+ ret.should.instance_of?(Hash)
end
it "sets the result as transformed keys with the given block" do
@@ -22,13 +22,13 @@ describe "Hash#transform_keys" do
it "makes both hashes to share values" do
value = [1, 2, 3]
new_hash = { a: value }.transform_keys(&:upcase)
- new_hash[:A].should equal(value)
+ new_hash[:A].should.equal?(value)
end
context "when no block is given" do
it "returns a sized Enumerator" do
enumerator = @hash.transform_keys
- enumerator.should be_an_instance_of(Enumerator)
+ enumerator.should.instance_of?(Enumerator)
enumerator.size.should == @hash.size
enumerator.each(&:succ).should == { b: 1, c: 2, d: 3 }
end
@@ -54,6 +54,27 @@ describe "Hash#transform_keys" do
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
+
+ it "does not retain the default value" do
+ h = Hash.new(1)
+ h.transform_keys(&:succ).default.should == nil
+ h[:a] = 1
+ h.transform_keys(&:succ).default.should == nil
+ end
+
+ it "does not retain the default_proc" do
+ pr = proc { |h, k| h[k] = [] }
+ h = Hash.new(&pr)
+ h.transform_values(&:succ).default_proc.should == nil
+ h[:a] = 1
+ h.transform_values(&:succ).default_proc.should == nil
+ end
+
+ it "does not retain compare_by_identity flag" do
+ h = { a: 9, c: 4 }.compare_by_identity
+ h2 = h.transform_keys(&:succ)
+ h2.compare_by_identity?.should == false
+ end
end
describe "Hash#transform_keys!" do
@@ -63,7 +84,7 @@ describe "Hash#transform_keys!" do
end
it "returns self" do
- @hash.transform_keys!(&:succ).should equal(@hash)
+ @hash.transform_keys!(&:succ).should.equal?(@hash)
end
it "updates self as transformed values with the given block" do
@@ -91,7 +112,7 @@ describe "Hash#transform_keys!" do
context "when no block is given" do
it "returns a sized Enumerator" do
enumerator = @hash.transform_keys!
- enumerator.should be_an_instance_of(Enumerator)
+ enumerator.should.instance_of?(Enumerator)
enumerator.size.should == @hash.size
enumerator.each(&:upcase).should == { A: 1, B: 2, C: 3, D: 4 }
end
@@ -108,21 +129,21 @@ describe "Hash#transform_keys!" do
end
it "raises a FrozenError on an empty hash" do
- ->{ {}.freeze.transform_keys!(&:upcase) }.should raise_error(FrozenError)
+ ->{ {}.freeze.transform_keys!(&:upcase) }.should.raise(FrozenError)
end
it "keeps pairs and raises a FrozenError" do
- ->{ @hash.transform_keys!(&:upcase) }.should raise_error(FrozenError)
+ ->{ @hash.transform_keys!(&:upcase) }.should.raise(FrozenError)
@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)
+ ->{ @hash.transform_keys!({ a: :A, b: :B, c: :C }) }.should.raise(FrozenError)
end
context "when no block is given" do
it "does not raise an exception" do
- @hash.transform_keys!.should be_an_instance_of(Enumerator)
+ @hash.transform_keys!.should.instance_of?(Enumerator)
end
end
end
diff --git a/spec/ruby/core/hash/transform_values_spec.rb b/spec/ruby/core/hash/transform_values_spec.rb
index acb469416a..b19543a9f4 100644
--- a/spec/ruby/core/hash/transform_values_spec.rb
+++ b/spec/ruby/core/hash/transform_values_spec.rb
@@ -7,8 +7,8 @@ describe "Hash#transform_values" do
it "returns new hash" do
ret = @hash.transform_values(&:succ)
- ret.should_not equal(@hash)
- ret.should be_an_instance_of(Hash)
+ ret.should_not.equal?(@hash)
+ ret.should.instance_of?(Hash)
end
it "sets the result as transformed values with the given block" do
@@ -19,13 +19,13 @@ describe "Hash#transform_values" do
key = [1, 2, 3]
new_hash = { key => 1 }.transform_values(&:succ)
new_hash[key].should == 2
- new_hash.keys[0].should equal(key)
+ new_hash.keys[0].should.equal?(key)
end
context "when no block is given" do
it "returns a sized Enumerator" do
enumerator = @hash.transform_values
- enumerator.should be_an_instance_of(Enumerator)
+ enumerator.should.instance_of?(Enumerator)
enumerator.size.should == @hash.size
enumerator.each(&:succ).should == { a: 2, b: 3, c: 4 }
end
@@ -39,6 +39,27 @@ describe "Hash#transform_values" do
r[:foo].should == 84
r.class.should == Hash
end
+
+ it "does not retain the default value" do
+ h = Hash.new(1)
+ h.transform_values(&:succ).default.should == nil
+ h[:a] = 1
+ h.transform_values(&:succ).default.should == nil
+ end
+
+ it "does not retain the default_proc" do
+ pr = proc { |h, k| h[k] = [] }
+ h = Hash.new(&pr)
+ h.transform_values(&:succ).default_proc.should == nil
+ h[:a] = 1
+ h.transform_values(&:succ).default_proc.should == nil
+ end
+
+ it "retains compare_by_identity flag" do
+ h = { a: 9, c: 4 }.compare_by_identity
+ h2 = h.transform_values(&:succ)
+ h2.compare_by_identity?.should == true
+ end
end
describe "Hash#transform_values!" do
@@ -48,7 +69,7 @@ describe "Hash#transform_values!" do
end
it "returns self" do
- @hash.transform_values!(&:succ).should equal(@hash)
+ @hash.transform_values!(&:succ).should.equal?(@hash)
end
it "updates self as transformed values with the given block" do
@@ -67,7 +88,7 @@ describe "Hash#transform_values!" do
context "when no block is given" do
it "returns a sized Enumerator" do
enumerator = @hash.transform_values!
- enumerator.should be_an_instance_of(Enumerator)
+ enumerator.should.instance_of?(Enumerator)
enumerator.size.should == @hash.size
enumerator.each(&:succ)
@hash.should == { a: 2, b: 3, c: 4 }
@@ -80,17 +101,17 @@ describe "Hash#transform_values!" do
end
it "raises a FrozenError on an empty hash" do
- ->{ {}.freeze.transform_values!(&:succ) }.should raise_error(FrozenError)
+ ->{ {}.freeze.transform_values!(&:succ) }.should.raise(FrozenError)
end
it "keeps pairs and raises a FrozenError" do
- ->{ @hash.transform_values!(&:succ) }.should raise_error(FrozenError)
+ ->{ @hash.transform_values!(&:succ) }.should.raise(FrozenError)
@hash.should == @initial_pairs
end
context "when no block is given" do
it "does not raise an exception" do
- @hash.transform_values!.should be_an_instance_of(Enumerator)
+ @hash.transform_values!.should.instance_of?(Enumerator)
end
end
end
diff --git a/spec/ruby/core/hash/try_convert_spec.rb b/spec/ruby/core/hash/try_convert_spec.rb
index d359ae49d8..c321183356 100644
--- a/spec/ruby/core/hash/try_convert_spec.rb
+++ b/spec/ruby/core/hash/try_convert_spec.rb
@@ -4,47 +4,47 @@ require_relative 'fixtures/classes'
describe "Hash.try_convert" do
it "returns the argument if it's a Hash" do
x = Hash.new
- Hash.try_convert(x).should equal(x)
+ Hash.try_convert(x).should.equal?(x)
end
it "returns the argument if it's a kind of Hash" do
x = HashSpecs::MyHash.new
- Hash.try_convert(x).should equal(x)
+ Hash.try_convert(x).should.equal?(x)
end
it "returns nil when the argument does not respond to #to_hash" do
- Hash.try_convert(Object.new).should be_nil
+ Hash.try_convert(Object.new).should == nil
end
it "sends #to_hash to the argument and returns the result if it's nil" do
obj = mock("to_hash")
obj.should_receive(:to_hash).and_return(nil)
- Hash.try_convert(obj).should be_nil
+ Hash.try_convert(obj).should == nil
end
it "sends #to_hash to the argument and returns the result if it's a Hash" do
x = Hash.new
obj = mock("to_hash")
obj.should_receive(:to_hash).and_return(x)
- Hash.try_convert(obj).should equal(x)
+ Hash.try_convert(obj).should.equal?(x)
end
it "sends #to_hash to the argument and returns the result if it's a kind of Hash" do
x = HashSpecs::MyHash.new
obj = mock("to_hash")
obj.should_receive(:to_hash).and_return(x)
- Hash.try_convert(obj).should equal(x)
+ Hash.try_convert(obj).should.equal?(x)
end
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_consistent_error(TypeError, "can't convert MockObject into Hash (MockObject#to_hash gives Object)")
end
it "does not rescue exceptions raised by #to_hash" do
obj = mock("to_hash")
obj.should_receive(:to_hash).and_raise(RuntimeError)
- -> { Hash.try_convert obj }.should raise_error(RuntimeError)
+ -> { Hash.try_convert obj }.should.raise(RuntimeError)
end
end
diff --git a/spec/ruby/core/hash/update_spec.rb b/spec/ruby/core/hash/update_spec.rb
index 0975045ad1..04070baad8 100644
--- a/spec/ruby/core/hash/update_spec.rb
+++ b/spec/ruby/core/hash/update_spec.rb
@@ -1,7 +1,7 @@
require_relative '../../spec_helper'
-require_relative 'fixtures/classes'
-require_relative 'shared/update'
describe "Hash#update" do
- it_behaves_like :hash_update, :update
+ it "is an alias of Hash#merge!" do
+ Hash.instance_method(:update).should == Hash.instance_method(:merge!)
+ end
end
diff --git a/spec/ruby/core/hash/value_spec.rb b/spec/ruby/core/hash/value_spec.rb
index 0ab16a5d1b..8e4732480f 100644
--- a/spec/ruby/core/hash/value_spec.rb
+++ b/spec/ruby/core/hash/value_spec.rb
@@ -1,7 +1,16 @@
require_relative '../../spec_helper'
-require_relative 'fixtures/classes'
-require_relative 'shared/value'
describe "Hash#value?" do
- it_behaves_like :hash_value_p, :value?
+ it "returns true if the value exists in the hash" do
+ { a: :b }.value?(:a).should == false
+ { 1 => 2 }.value?(2).should == true
+ h = Hash.new(5)
+ h.value?(5).should == false
+ h = Hash.new { 5 }
+ h.value?(5).should == false
+ end
+
+ it "uses == semantics for comparing values" do
+ { 5 => 2.0 }.value?(2).should == true
+ end
end
diff --git a/spec/ruby/core/hash/values_at_spec.rb b/spec/ruby/core/hash/values_at_spec.rb
index b620a279ba..78dcd8df6a 100644
--- a/spec/ruby/core/hash/values_at_spec.rb
+++ b/spec/ruby/core/hash/values_at_spec.rb
@@ -1,7 +1,11 @@
require_relative '../../spec_helper'
-require_relative 'fixtures/classes'
-require_relative 'shared/values_at'
describe "Hash#values_at" do
- it_behaves_like :hash_values_at, :values_at
+ it "returns an array of values for the given keys" do
+ h = { a: 9, b: 'a', c: -10, d: nil }
+ h.values_at.should.is_a?(Array)
+ h.values_at.should == []
+ h.values_at(:a, :d, :b).should.is_a?(Array)
+ h.values_at(:a, :d, :b).should == [9, nil, 'a']
+ end
end
diff --git a/spec/ruby/core/hash/values_spec.rb b/spec/ruby/core/hash/values_spec.rb
index 9f2a481a48..1fe5f48ad6 100644
--- a/spec/ruby/core/hash/values_spec.rb
+++ b/spec/ruby/core/hash/values_spec.rb
@@ -4,7 +4,7 @@ require_relative 'fixtures/classes'
describe "Hash#values" do
it "returns an array of values" do
h = { 1 => :a, 'a' => :a, 'the' => 'lang' }
- h.values.should be_kind_of(Array)
+ h.values.should.is_a?(Array)
h.values.sort {|a, b| a.to_s <=> b.to_s}.should == [:a, :a, 'lang']
end
end
diff --git a/spec/ruby/core/integer/abs_spec.rb b/spec/ruby/core/integer/abs_spec.rb
index c40356db12..768eebdce2 100644
--- a/spec/ruby/core/integer/abs_spec.rb
+++ b/spec/ruby/core/integer/abs_spec.rb
@@ -1,6 +1,20 @@
require_relative '../../spec_helper'
-require_relative 'shared/abs'
describe "Integer#abs" do
- it_behaves_like :integer_abs, :abs
+ context "fixnum" do
+ it "returns self's absolute fixnum value" do
+ { 0 => [0, -0, +0], 2 => [2, -2, +2], 100 => [100, -100, +100] }.each do |key, values|
+ values.each do |value|
+ value.abs.should == key
+ end
+ end
+ end
+ end
+
+ context "bignum" do
+ it "returns the absolute bignum value" do
+ bignum_value(39).abs.should == 18446744073709551655
+ (-bignum_value(18)).abs.should == 18446744073709551634
+ end
+ end
end
diff --git a/spec/ruby/core/integer/allbits_spec.rb b/spec/ruby/core/integer/allbits_spec.rb
index edce4b15e7..6023cc32bf 100644
--- a/spec/ruby/core/integer/allbits_spec.rb
+++ b/spec/ruby/core/integer/allbits_spec.rb
@@ -30,8 +30,8 @@ describe "Integer#allbits?" do
-> {
(obj = mock('10')).should_receive(:coerce).any_number_of_times.and_return([42,10])
13.allbits?(obj)
- }.should raise_error(TypeError)
- -> { 13.allbits?("10") }.should raise_error(TypeError)
- -> { 13.allbits?(:symbol) }.should raise_error(TypeError)
+ }.should.raise(TypeError)
+ -> { 13.allbits?("10") }.should.raise(TypeError)
+ -> { 13.allbits?(:symbol) }.should.raise(TypeError)
end
end
diff --git a/spec/ruby/core/integer/anybits_spec.rb b/spec/ruby/core/integer/anybits_spec.rb
index e0449074a2..1ea47b76dc 100644
--- a/spec/ruby/core/integer/anybits_spec.rb
+++ b/spec/ruby/core/integer/anybits_spec.rb
@@ -29,8 +29,8 @@ describe "Integer#anybits?" do
-> {
(obj = mock('10')).should_receive(:coerce).any_number_of_times.and_return([42,10])
13.anybits?(obj)
- }.should raise_error(TypeError)
- -> { 13.anybits?("10") }.should raise_error(TypeError)
- -> { 13.anybits?(:symbol) }.should raise_error(TypeError)
+ }.should.raise(TypeError)
+ -> { 13.anybits?("10") }.should.raise(TypeError)
+ -> { 13.anybits?(:symbol) }.should.raise(TypeError)
end
end
diff --git a/spec/ruby/core/integer/bit_and_spec.rb b/spec/ruby/core/integer/bit_and_spec.rb
index e7face39ac..4098ad7c7b 100644
--- a/spec/ruby/core/integer/bit_and_spec.rb
+++ b/spec/ruby/core/integer/bit_and_spec.rb
@@ -35,14 +35,14 @@ describe "Integer#&" do
end
it "raises a TypeError when passed a Float" do
- -> { (3 & 3.4) }.should raise_error(TypeError)
+ -> { (3 & 3.4) }.should.raise(TypeError)
end
it "raises a TypeError and does not call #to_int when defined on an object" do
obj = mock("fixnum bit and")
obj.should_not_receive(:to_int)
- -> { 3 & obj }.should raise_error(TypeError)
+ -> { 3 & obj }.should.raise(TypeError)
end
end
@@ -84,14 +84,14 @@ describe "Integer#&" do
end
it "raises a TypeError when passed a Float" do
- -> { (@bignum & 3.4) }.should raise_error(TypeError)
+ -> { (@bignum & 3.4) }.should.raise(TypeError)
end
it "raises a TypeError and does not call #to_int when defined on an object" do
obj = mock("bignum bit and")
obj.should_not_receive(:to_int)
- -> { @bignum & obj }.should raise_error(TypeError)
+ -> { @bignum & obj }.should.raise(TypeError)
end
end
end
diff --git a/spec/ruby/core/integer/bit_or_spec.rb b/spec/ruby/core/integer/bit_or_spec.rb
index fdf8a191e5..c380cd729e 100644
--- a/spec/ruby/core/integer/bit_or_spec.rb
+++ b/spec/ruby/core/integer/bit_or_spec.rb
@@ -36,14 +36,14 @@ describe "Integer#|" do
end
it "raises a TypeError when passed a Float" do
- -> { (3 | 3.4) }.should raise_error(TypeError)
+ -> { (3 | 3.4) }.should.raise(TypeError)
end
it "raises a TypeError and does not call #to_int when defined on an object" do
obj = mock("integer bit or")
obj.should_not_receive(:to_int)
- -> { 3 | obj }.should raise_error(TypeError)
+ -> { 3 | obj }.should.raise(TypeError)
end
end
@@ -74,16 +74,16 @@ describe "Integer#|" do
not_supported_on :opal do
-> {
bignum_value | bignum_value(0xffff).to_f
- }.should raise_error(TypeError)
+ }.should.raise(TypeError)
end
- -> { @bignum | 9.9 }.should raise_error(TypeError)
+ -> { @bignum | 9.9 }.should.raise(TypeError)
end
it "raises a TypeError and does not call #to_int when defined on an object" do
obj = mock("bignum bit or")
obj.should_not_receive(:to_int)
- -> { @bignum | obj }.should raise_error(TypeError)
+ -> { @bignum | obj }.should.raise(TypeError)
end
end
end
diff --git a/spec/ruby/core/integer/bit_xor_spec.rb b/spec/ruby/core/integer/bit_xor_spec.rb
index 1f46bc52f3..c0cf8405f7 100644
--- a/spec/ruby/core/integer/bit_xor_spec.rb
+++ b/spec/ruby/core/integer/bit_xor_spec.rb
@@ -34,14 +34,14 @@ describe "Integer#^" do
end
it "raises a TypeError when passed a Float" do
- -> { (3 ^ 3.4) }.should raise_error(TypeError)
+ -> { (3 ^ 3.4) }.should.raise(TypeError)
end
it "raises a TypeError and does not call #to_int when defined on an object" do
obj = mock("integer bit xor")
obj.should_not_receive(:to_int)
- -> { 3 ^ obj }.should raise_error(TypeError)
+ -> { 3 ^ obj }.should.raise(TypeError)
end
end
@@ -78,16 +78,16 @@ describe "Integer#^" do
not_supported_on :opal do
-> {
bignum_value ^ bignum_value(0xffff).to_f
- }.should raise_error(TypeError)
+ }.should.raise(TypeError)
end
- -> { @bignum ^ 14.5 }.should raise_error(TypeError)
+ -> { @bignum ^ 14.5 }.should.raise(TypeError)
end
it "raises a TypeError and does not call #to_int when defined on an object" do
obj = mock("bignum bit xor")
obj.should_not_receive(:to_int)
- -> { @bignum ^ obj }.should raise_error(TypeError)
+ -> { @bignum ^ obj }.should.raise(TypeError)
end
end
end
diff --git a/spec/ruby/core/integer/case_compare_spec.rb b/spec/ruby/core/integer/case_compare_spec.rb
index e5dde2c64a..1e0c6cb411 100644
--- a/spec/ruby/core/integer/case_compare_spec.rb
+++ b/spec/ruby/core/integer/case_compare_spec.rb
@@ -1,6 +1,7 @@
require_relative '../../spec_helper'
-require_relative 'shared/equal'
describe "Integer#===" do
- it_behaves_like :integer_equal, :===
+ it "is an alias of Integer#==" do
+ Integer.instance_method(:===).should == Integer.instance_method(:==)
+ end
end
diff --git a/spec/ruby/core/integer/ceil_spec.rb b/spec/ruby/core/integer/ceil_spec.rb
index eb633fba78..395be58fbd 100644
--- a/spec/ruby/core/integer/ceil_spec.rb
+++ b/spec/ruby/core/integer/ceil_spec.rb
@@ -10,15 +10,4 @@ describe "Integer#ceil" do
context "with precision" do
it_behaves_like :integer_ceil_precision, :Integer
end
-
- context "precision argument specified as part of the ceil method is negative" do
- it "returns the smallest integer greater than self with at least precision.abs trailing zeros" do
- 18.ceil(-1).should eql(20)
- 18.ceil(-2).should eql(100)
- 18.ceil(-3).should eql(1000)
- -1832.ceil(-1).should eql(-1830)
- -1832.ceil(-2).should eql(-1800)
- -1832.ceil(-3).should eql(-1000)
- end
- end
end
diff --git a/spec/ruby/core/integer/ceildiv_spec.rb b/spec/ruby/core/integer/ceildiv_spec.rb
index c6e22a457d..91f63832f8 100644
--- a/spec/ruby/core/integer/ceildiv_spec.rb
+++ b/spec/ruby/core/integer/ceildiv_spec.rb
@@ -2,19 +2,19 @@ require_relative '../../spec_helper'
describe "Integer#ceildiv" 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)
+ 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)
+ 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)
+ 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)
+ (10**100-11).ceildiv(10**99-1).should.eql?(10)
+ (10**100-9).ceildiv(10**99-1).should.eql?(11)
end
end
diff --git a/spec/ruby/core/integer/chr_spec.rb b/spec/ruby/core/integer/chr_spec.rb
index 39cafe2874..72784e1833 100644
--- a/spec/ruby/core/integer/chr_spec.rb
+++ b/spec/ruby/core/integer/chr_spec.rb
@@ -2,20 +2,20 @@ require_relative '../../spec_helper'
describe "Integer#chr without argument" do
it "returns a String" do
- 17.chr.should be_an_instance_of(String)
+ 17.chr.should.instance_of?(String)
end
it "returns a new String for each call" do
- 82.chr.should_not equal(82.chr)
+ 82.chr.should_not.equal?(82.chr)
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(RangeError, /-1 out of char range/)
+ -> { (-bignum_value).chr }.should.raise(RangeError, /bignum out of char range/)
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(RangeError, /2206368128 out of char range/)
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(RangeError, /256 out of char range/)
+ -> { bignum_value.chr }.should.raise(RangeError, /bignum out of char range/)
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(RangeError, /(invalid codepoint|out of char range)/)
end
end
end
@@ -146,15 +146,15 @@ end
describe "Integer#chr with an encoding argument" do
it "returns a String" do
- 900.chr(Encoding::UTF_8).should be_an_instance_of(String)
+ 900.chr(Encoding::UTF_8).should.instance_of?(String)
end
it "returns a new String for each call" do
- 8287.chr(Encoding::UTF_8).should_not equal(8287.chr(Encoding::UTF_8))
+ 8287.chr(Encoding::UTF_8).should_not.equal?(8287.chr(Encoding::UTF_8))
end
it "accepts a String as an argument" do
- -> { 0xA4A2.chr('euc-jp') }.should_not raise_error
+ -> { 0xA4A2.chr('euc-jp') }.should_not.raise
end
it "converts a String to an Encoding as Encoding.find does" do
@@ -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(RangeError, /-1 out of char range/)
+ -> { (-bignum_value).chr(Encoding::EUC_JP) }.should.raise(RangeError, /bignum out of char range/)
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(RangeError, /2206368128 out of char range/)
end
it "returns a String with the specified encoding" do
@@ -223,25 +223,25 @@ describe "Integer#chr with an encoding argument" do
# #5864
it "raises RangeError if self is invalid as a codepoint in the specified encoding" do
- -> { 0x80.chr("US-ASCII") }.should raise_error(RangeError)
- -> { 0x0100.chr("BINARY") }.should raise_error(RangeError)
- -> { 0x0100.chr("EUC-JP") }.should raise_error(RangeError)
- -> { 0xA1A0.chr("EUC-JP") }.should raise_error(RangeError)
- -> { 0xA1.chr("EUC-JP") }.should raise_error(RangeError)
- -> { 0x80.chr("SHIFT_JIS") }.should raise_error(RangeError)
- -> { 0xE0.chr("SHIFT_JIS") }.should raise_error(RangeError)
- -> { 0x0100.chr("ISO-8859-9") }.should raise_error(RangeError)
- -> { 620.chr("TIS-620") }.should raise_error(RangeError)
+ -> { 0x80.chr("US-ASCII") }.should.raise(RangeError)
+ -> { 0x0100.chr("BINARY") }.should.raise(RangeError)
+ -> { 0x0100.chr("EUC-JP") }.should.raise(RangeError)
+ -> { 0xA1A0.chr("EUC-JP") }.should.raise(RangeError)
+ -> { 0xA1.chr("EUC-JP") }.should.raise(RangeError)
+ -> { 0x80.chr("SHIFT_JIS") }.should.raise(RangeError)
+ -> { 0xE0.chr("SHIFT_JIS") }.should.raise(RangeError)
+ -> { 0x0100.chr("ISO-8859-9") }.should.raise(RangeError)
+ -> { 620.chr("TIS-620") }.should.raise(RangeError)
# UTF-16 surrogate range
- -> { 0xD800.chr("UTF-8") }.should raise_error(RangeError)
- -> { 0xDBFF.chr("UTF-8") }.should raise_error(RangeError)
- -> { 0xDC00.chr("UTF-8") }.should raise_error(RangeError)
- -> { 0xDFFF.chr("UTF-8") }.should raise_error(RangeError)
+ -> { 0xD800.chr("UTF-8") }.should.raise(RangeError)
+ -> { 0xDBFF.chr("UTF-8") }.should.raise(RangeError)
+ -> { 0xDC00.chr("UTF-8") }.should.raise(RangeError)
+ -> { 0xDFFF.chr("UTF-8") }.should.raise(RangeError)
# UTF-16 surrogate range
- -> { 0xD800.chr("UTF-16") }.should raise_error(RangeError)
- -> { 0xDBFF.chr("UTF-16") }.should raise_error(RangeError)
- -> { 0xDC00.chr("UTF-16") }.should raise_error(RangeError)
- -> { 0xDFFF.chr("UTF-16") }.should raise_error(RangeError)
+ -> { 0xD800.chr("UTF-16") }.should.raise(RangeError)
+ -> { 0xDBFF.chr("UTF-16") }.should.raise(RangeError)
+ -> { 0xDC00.chr("UTF-16") }.should.raise(RangeError)
+ -> { 0xDFFF.chr("UTF-16") }.should.raise(RangeError)
end
it 'returns a String encoding self interpreted as a codepoint in the CESU-8 encoding' do
diff --git a/spec/ruby/core/integer/coerce_spec.rb b/spec/ruby/core/integer/coerce_spec.rb
index 1d6dc9713f..c0e642da03 100644
--- a/spec/ruby/core/integer/coerce_spec.rb
+++ b/spec/ruby/core/integer/coerce_spec.rb
@@ -11,7 +11,7 @@ describe "Integer#coerce" do
describe "when given a String" do
it "raises an ArgumentError when trying to coerce with a non-number String" do
- -> { 1.coerce(":)") }.should raise_error(ArgumentError)
+ -> { 1.coerce(":)") }.should.raise(ArgumentError)
end
it "returns an array containing two Floats" do
@@ -21,7 +21,7 @@ describe "Integer#coerce" do
end
it "raises a TypeError when trying to coerce with nil" do
- -> { 1.coerce(nil) }.should raise_error(TypeError)
+ -> { 1.coerce(nil) }.should.raise(TypeError)
end
it "tries to convert the given Object into a Float by using #to_f" do
@@ -29,13 +29,13 @@ describe "Integer#coerce" do
2.coerce(obj).should == [1.0, 2.0]
(obj = mock('0')).should_receive(:to_f).and_return('0')
- -> { 2.coerce(obj).should == [1.0, 2.0] }.should raise_error(TypeError)
+ -> { 2.coerce(obj).should == [1.0, 2.0] }.should.raise(TypeError)
end
it "raises a TypeError when given an Object that does not respond to #to_f" do
- -> { 1.coerce(mock('x')) }.should raise_error(TypeError)
- -> { 1.coerce(1..4) }.should raise_error(TypeError)
- -> { 1.coerce(:test) }.should raise_error(TypeError)
+ -> { 1.coerce(mock('x')) }.should.raise(TypeError)
+ -> { 1.coerce(1..4) }.should.raise(TypeError)
+ -> { 1.coerce(:test) }.should.raise(TypeError)
end
end
@@ -44,8 +44,8 @@ describe "Integer#coerce" do
a = bignum_value
ary = a.coerce(2)
- ary[0].should be_kind_of(Integer)
- ary[1].should be_kind_of(Integer)
+ ary[0].should.is_a?(Integer)
+ ary[1].should.is_a?(Integer)
ary.should == [2, a]
end
@@ -54,18 +54,18 @@ describe "Integer#coerce" do
b = bignum_value
ary = a.coerce(b)
- ary[0].should be_kind_of(Integer)
- ary[1].should be_kind_of(Integer)
+ ary[0].should.is_a?(Integer)
+ ary[1].should.is_a?(Integer)
ary.should == [b, a]
end
it "raises a TypeError when not passed a Fixnum or Bignum" do
a = bignum_value
- -> { a.coerce(nil) }.should raise_error(TypeError)
- -> { a.coerce(mock('str')) }.should raise_error(TypeError)
- -> { a.coerce(1..4) }.should raise_error(TypeError)
- -> { a.coerce(:test) }.should raise_error(TypeError)
+ -> { a.coerce(nil) }.should.raise(TypeError)
+ -> { a.coerce(mock('str')) }.should.raise(TypeError)
+ -> { a.coerce(1..4) }.should.raise(TypeError)
+ -> { a.coerce(:test) }.should.raise(TypeError)
end
it "coerces both values to Floats and returns [other, self] when passed a Float" do
diff --git a/spec/ruby/core/integer/comparison_spec.rb b/spec/ruby/core/integer/comparison_spec.rb
index 408c8e52ce..cc5cbe2506 100644
--- a/spec/ruby/core/integer/comparison_spec.rb
+++ b/spec/ruby/core/integer/comparison_spec.rb
@@ -128,17 +128,17 @@ describe "Integer#<=>" do
@num.should_receive(:coerce).with(@big).and_raise(RuntimeError.new("my error"))
-> {
@big <=> @num
- }.should raise_error(RuntimeError, "my error")
+ }.should.raise(RuntimeError, "my error")
end
it "raises an exception if #coerce raises a non-StandardError exception" do
@num.should_receive(:coerce).with(@big).and_raise(Exception)
- -> { @big <=> @num }.should raise_error(Exception)
+ -> { @big <=> @num }.should.raise(Exception)
end
it "returns nil if #coerce does not return an Array" do
@num.should_receive(:coerce).with(@big).and_return(nil)
- (@big <=> @num).should be_nil
+ (@big <=> @num).should == nil
end
it "returns -1 if the coerced value is larger" do
@@ -157,6 +157,14 @@ describe "Integer#<=>" do
end
end
+ describe "with a Float" do
+ it "does not lose precision for values that don't fit in a double" do
+ (bignum_value(1) <=> bignum_value.to_f).should == 1
+ (bignum_value <=> bignum_value.to_f).should == 0
+ ((bignum_value - 1) <=> bignum_value.to_f).should == -1
+ end
+ end
+
# The tests below are taken from matz's revision 23730 for Ruby trunk
it "returns 1 when self is Infinity and other is a Bignum" do
(infinity_value <=> Float::MAX.to_i*2).should == 1
diff --git a/spec/ruby/core/integer/digits_spec.rb b/spec/ruby/core/integer/digits_spec.rb
index 3d0a64c25f..c4ebf2cd88 100644
--- a/spec/ruby/core/integer/digits_spec.rb
+++ b/spec/ruby/core/integer/digits_spec.rb
@@ -19,15 +19,15 @@ describe "Integer#digits" do
end
it "raises ArgumentError when calling with a radix less than 2" do
- -> { 12345.digits(1) }.should raise_error(ArgumentError)
+ -> { 12345.digits(1) }.should.raise(ArgumentError)
end
it "raises ArgumentError when calling with a negative radix" do
- -> { 12345.digits(-2) }.should raise_error(ArgumentError)
+ -> { 12345.digits(-2) }.should.raise(ArgumentError)
end
it "raises Math::DomainError when calling digits on a negative number" do
- -> { -12345.digits(7) }.should raise_error(Math::DomainError)
+ -> { -12345.digits(7) }.should.raise(Math::DomainError)
end
it "returns integer values > 9 when base is above 10" do
diff --git a/spec/ruby/core/integer/div_spec.rb b/spec/ruby/core/integer/div_spec.rb
index 2eb9c0623b..220ca4a73e 100644
--- a/spec/ruby/core/integer/div_spec.rb
+++ b/spec/ruby/core/integer/div_spec.rb
@@ -46,21 +46,21 @@ describe "Integer#div" do
end
it "raises a ZeroDivisionError when the given argument is 0 and a Float" do
- -> { 0.div(0.0) }.should raise_error(ZeroDivisionError)
- -> { 10.div(0.0) }.should raise_error(ZeroDivisionError)
- -> { -10.div(0.0) }.should raise_error(ZeroDivisionError)
+ -> { 0.div(0.0) }.should.raise(ZeroDivisionError)
+ -> { 10.div(0.0) }.should.raise(ZeroDivisionError)
+ -> { -10.div(0.0) }.should.raise(ZeroDivisionError)
end
it "raises a ZeroDivisionError when the given argument is 0 and not a Float" do
- -> { 13.div(0) }.should raise_error(ZeroDivisionError)
- -> { 13.div(-0) }.should raise_error(ZeroDivisionError)
+ -> { 13.div(0) }.should.raise(ZeroDivisionError)
+ -> { 13.div(-0) }.should.raise(ZeroDivisionError)
end
it "raises a TypeError when given a non-numeric argument" do
- -> { 13.div(mock('10')) }.should raise_error(TypeError)
- -> { 5.div("2") }.should raise_error(TypeError)
- -> { 5.div(:"2") }.should raise_error(TypeError)
- -> { 5.div([]) }.should raise_error(TypeError)
+ -> { 13.div(mock('10')) }.should.raise(TypeError)
+ -> { 5.div("2") }.should.raise(TypeError)
+ -> { 5.div(:"2") }.should.raise(TypeError)
+ -> { 5.div([]) }.should.raise(TypeError)
end
end
@@ -118,29 +118,29 @@ describe "Integer#div" do
end
it "raises a TypeError when given a non-numeric" do
- -> { @bignum.div(mock("10")) }.should raise_error(TypeError)
- -> { @bignum.div("2") }.should raise_error(TypeError)
- -> { @bignum.div(:symbol) }.should raise_error(TypeError)
+ -> { @bignum.div(mock("10")) }.should.raise(TypeError)
+ -> { @bignum.div("2") }.should.raise(TypeError)
+ -> { @bignum.div(:symbol) }.should.raise(TypeError)
end
it "returns a result of integer division of self by a float argument" do
- @bignum.div(4294967295.5).should eql(4294967296)
+ @bignum.div(4294967295.5).should.eql?(4294967296)
not_supported_on :opal do
- @bignum.div(4294967295.0).should eql(4294967297)
- @bignum.div(bignum_value(88).to_f).should eql(1)
- @bignum.div((-bignum_value(88)).to_f).should eql(-1)
+ @bignum.div(4294967295.0).should.eql?(4294967297)
+ @bignum.div(bignum_value(88).to_f).should.eql?(1)
+ @bignum.div((-bignum_value(88)).to_f).should.eql?(-1)
end
end
# #5490
it "raises ZeroDivisionError if the argument is 0 and is a Float" do
- -> { @bignum.div(0.0) }.should raise_error(ZeroDivisionError)
- -> { @bignum.div(-0.0) }.should raise_error(ZeroDivisionError)
+ -> { @bignum.div(0.0) }.should.raise(ZeroDivisionError)
+ -> { @bignum.div(-0.0) }.should.raise(ZeroDivisionError)
end
it "raises ZeroDivisionError if the argument is 0 and is not a Float" do
- -> { @bignum.div(0) }.should raise_error(ZeroDivisionError)
- -> { @bignum.div(-0) }.should raise_error(ZeroDivisionError)
+ -> { @bignum.div(0) }.should.raise(ZeroDivisionError)
+ -> { @bignum.div(-0) }.should.raise(ZeroDivisionError)
end
end
diff --git a/spec/ruby/core/integer/divide_spec.rb b/spec/ruby/core/integer/divide_spec.rb
index 0d5e16e986..e75432fd83 100644
--- a/spec/ruby/core/integer/divide_spec.rb
+++ b/spec/ruby/core/integer/divide_spec.rb
@@ -32,7 +32,7 @@ describe "Integer#/" do
end
it "raises a ZeroDivisionError if the given argument is zero and not a Float" do
- -> { 1 / 0 }.should raise_error(ZeroDivisionError)
+ -> { 1 / 0 }.should.raise(ZeroDivisionError)
end
it "does NOT raise ZeroDivisionError if the given argument is zero and is a Float" do
@@ -46,9 +46,9 @@ describe "Integer#/" do
end
it "raises a TypeError when given a non-Integer" do
- -> { 13 / mock('10') }.should raise_error(TypeError)
- -> { 13 / "10" }.should raise_error(TypeError)
- -> { 13 / :symbol }.should raise_error(TypeError)
+ -> { 13 / mock('10') }.should.raise(TypeError)
+ -> { 13 / "10" }.should.raise(TypeError)
+ -> { 13 / :symbol }.should.raise(TypeError)
end
end
@@ -97,13 +97,13 @@ describe "Integer#/" do
end
it "raises a ZeroDivisionError if other is zero and not a Float" do
- -> { @bignum / 0 }.should raise_error(ZeroDivisionError)
+ -> { @bignum / 0 }.should.raise(ZeroDivisionError)
end
it "raises a TypeError when given a non-numeric" do
- -> { @bignum / mock('10') }.should raise_error(TypeError)
- -> { @bignum / "2" }.should raise_error(TypeError)
- -> { @bignum / :symbol }.should raise_error(TypeError)
+ -> { @bignum / mock('10') }.should.raise(TypeError)
+ -> { @bignum / "2" }.should.raise(TypeError)
+ -> { @bignum / :symbol }.should.raise(TypeError)
end
end
diff --git a/spec/ruby/core/integer/divmod_spec.rb b/spec/ruby/core/integer/divmod_spec.rb
index 7a489e9344..db470c5731 100644
--- a/spec/ruby/core/integer/divmod_spec.rb
+++ b/spec/ruby/core/integer/divmod_spec.rb
@@ -14,24 +14,24 @@ describe "Integer#divmod" do
end
it "raises a ZeroDivisionError when the given argument is 0" do
- -> { 13.divmod(0) }.should raise_error(ZeroDivisionError)
- -> { 0.divmod(0) }.should raise_error(ZeroDivisionError)
- -> { -10.divmod(0) }.should raise_error(ZeroDivisionError)
+ -> { 13.divmod(0) }.should.raise(ZeroDivisionError)
+ -> { 0.divmod(0) }.should.raise(ZeroDivisionError)
+ -> { -10.divmod(0) }.should.raise(ZeroDivisionError)
end
it "raises a ZeroDivisionError when the given argument is 0 and a Float" do
- -> { 0.divmod(0.0) }.should raise_error(ZeroDivisionError)
- -> { 10.divmod(0.0) }.should raise_error(ZeroDivisionError)
- -> { -10.divmod(0.0) }.should raise_error(ZeroDivisionError)
+ -> { 0.divmod(0.0) }.should.raise(ZeroDivisionError)
+ -> { 10.divmod(0.0) }.should.raise(ZeroDivisionError)
+ -> { -10.divmod(0.0) }.should.raise(ZeroDivisionError)
end
it "raises a TypeError when given a non-Integer" do
-> {
(obj = mock('10')).should_receive(:to_int).any_number_of_times.and_return(10)
13.divmod(obj)
- }.should raise_error(TypeError)
- -> { 13.divmod("10") }.should raise_error(TypeError)
- -> { 13.divmod(:symbol) }.should raise_error(TypeError)
+ }.should.raise(TypeError)
+ -> { 13.divmod("10") }.should.raise(TypeError)
+ -> { 13.divmod(:symbol) }.should.raise(TypeError)
end
end
@@ -94,24 +94,24 @@ describe "Integer#divmod" do
end
it "raises a ZeroDivisionError when the given argument is 0" do
- -> { @bignum.divmod(0) }.should raise_error(ZeroDivisionError)
- -> { (-@bignum).divmod(0) }.should raise_error(ZeroDivisionError)
+ -> { @bignum.divmod(0) }.should.raise(ZeroDivisionError)
+ -> { (-@bignum).divmod(0) }.should.raise(ZeroDivisionError)
end
# Behaviour established as correct in r23953
it "raises a FloatDomainError if other is NaN" do
- -> { @bignum.divmod(nan_value) }.should raise_error(FloatDomainError)
+ -> { @bignum.divmod(nan_value) }.should.raise(FloatDomainError)
end
it "raises a ZeroDivisionError when the given argument is 0 and a Float" do
- -> { @bignum.divmod(0.0) }.should raise_error(ZeroDivisionError)
- -> { (-@bignum).divmod(0.0) }.should raise_error(ZeroDivisionError)
+ -> { @bignum.divmod(0.0) }.should.raise(ZeroDivisionError)
+ -> { (-@bignum).divmod(0.0) }.should.raise(ZeroDivisionError)
end
it "raises a TypeError when the given argument is not an Integer" do
- -> { @bignum.divmod(mock('10')) }.should raise_error(TypeError)
- -> { @bignum.divmod("10") }.should raise_error(TypeError)
- -> { @bignum.divmod(:symbol) }.should raise_error(TypeError)
+ -> { @bignum.divmod(mock('10')) }.should.raise(TypeError)
+ -> { @bignum.divmod("10") }.should.raise(TypeError)
+ -> { @bignum.divmod(:symbol) }.should.raise(TypeError)
end
end
end
diff --git a/spec/ruby/core/integer/downto_spec.rb b/spec/ruby/core/integer/downto_spec.rb
index 987704b02e..a244d3df55 100644
--- a/spec/ruby/core/integer/downto_spec.rb
+++ b/spec/ruby/core/integer/downto_spec.rb
@@ -27,8 +27,8 @@ describe "Integer#downto [stop] when self and stop are Integers" do
end
it "raises an ArgumentError for invalid endpoints" do
- -> {1.downto("A") {|x| p x } }.should raise_error(ArgumentError)
- -> {1.downto(nil) {|x| p x } }.should raise_error(ArgumentError)
+ -> {1.downto("A") {|x| p x } }.should.raise(ArgumentError)
+ -> {1.downto(nil) {|x| p x } }.should.raise(ArgumentError)
end
describe "when no block is given" do
@@ -45,9 +45,9 @@ describe "Integer#downto [stop] when self and stop are Integers" do
describe "size" do
it "raises an ArgumentError for invalid endpoints" do
enum = 1.downto("A")
- -> { enum.size }.should raise_error(ArgumentError)
+ -> { enum.size }.should.raise(ArgumentError)
enum = 1.downto(nil)
- -> { enum.size }.should raise_error(ArgumentError)
+ -> { enum.size }.should.raise(ArgumentError)
end
it "returns self - stop + 1" do
diff --git a/spec/ruby/core/integer/dup_spec.rb b/spec/ruby/core/integer/dup_spec.rb
index 7f4d512465..3e5739ad37 100644
--- a/spec/ruby/core/integer/dup_spec.rb
+++ b/spec/ruby/core/integer/dup_spec.rb
@@ -3,11 +3,11 @@ require_relative '../../spec_helper'
describe "Integer#dup" do
it "returns self for small integers" do
integer = 1_000
- integer.dup.should equal(integer)
+ integer.dup.should.equal?(integer)
end
it "returns self for large integers" do
integer = 4_611_686_018_427_387_905
- integer.dup.should equal(integer)
+ integer.dup.should.equal?(integer)
end
end
diff --git a/spec/ruby/core/integer/element_reference_spec.rb b/spec/ruby/core/integer/element_reference_spec.rb
index cb7e0dc9b0..c69ec2315d 100644
--- a/spec/ruby/core/integer/element_reference_spec.rb
+++ b/spec/ruby/core/integer/element_reference_spec.rb
@@ -59,13 +59,13 @@ describe "Integer#[]" do
end
it "raises a TypeError when passed a String" do
- -> { 3["3"] }.should raise_error(TypeError)
+ -> { 3["3"] }.should.raise(TypeError)
end
it "raises a TypeError when #to_int does not return an Integer" do
obj = mock('asdf')
obj.should_receive(:to_int).and_return("asdf")
- -> { 3[obj] }.should raise_error(TypeError)
+ -> { 3[obj] }.should.raise(TypeError)
end
it "calls #to_int to coerce a String to a Bignum and returns 0" do
@@ -137,8 +137,8 @@ describe "Integer#[]" do
end
it "raises FloatDomainError if any boundary is infinity" do
- -> { 0x0001[3..Float::INFINITY] }.should raise_error(FloatDomainError, /Infinity/)
- -> { 0x0001[-Float::INFINITY..3] }.should raise_error(FloatDomainError, /-Infinity/)
+ -> { 0x0001[3..Float::INFINITY] }.should.raise(FloatDomainError, /Infinity/)
+ -> { 0x0001[-Float::INFINITY..3] }.should.raise(FloatDomainError, /-Infinity/)
end
context "when passed (..i)" do
@@ -151,7 +151,7 @@ describe "Integer#[]" do
it "raises ArgumentError if any of i bit equals 1" do
-> {
eval("0b111110[..3]")
- }.should raise_error(ArgumentError, /The beginless range for Integer#\[\] results in infinity/)
+ }.should.raise(ArgumentError, /The beginless range for Integer#\[\] results in infinity/)
end
end
end
@@ -179,10 +179,10 @@ describe "Integer#[]" do
it "raises a TypeError when the given argument can't be converted to Integer" do
obj = mock('asdf')
- -> { @bignum[obj] }.should raise_error(TypeError)
+ -> { @bignum[obj] }.should.raise(TypeError)
obj.should_receive(:to_int).and_return("asdf")
- -> { @bignum[obj] }.should raise_error(TypeError)
+ -> { @bignum[obj] }.should.raise(TypeError)
end
end
end
diff --git a/spec/ruby/core/integer/eql_spec.rb b/spec/ruby/core/integer/eql_spec.rb
new file mode 100644
index 0000000000..9c80173206
--- /dev/null
+++ b/spec/ruby/core/integer/eql_spec.rb
@@ -0,0 +1,25 @@
+require_relative '../../spec_helper'
+
+describe "Integer#eql?" do
+ context "bignum" do
+ it "returns true for the same value" do
+ bignum_value.eql?(bignum_value).should == true
+ end
+
+ it "returns false for a different Integer value" do
+ bignum_value.eql?(bignum_value(1)).should == false
+ end
+
+ it "returns false for a Float with the same numeric value" do
+ bignum_value.eql?(bignum_value.to_f).should == false
+ end
+
+ it "returns false for a Rational with the same numeric value" do
+ bignum_value.eql?(Rational(bignum_value)).should == false
+ end
+
+ it "returns false for a Fixnum-range Integer" do
+ bignum_value.eql?(42).should == false
+ end
+ end
+end
diff --git a/spec/ruby/core/integer/equal_value_spec.rb b/spec/ruby/core/integer/equal_value_spec.rb
index 67a73713af..dc73552267 100644
--- a/spec/ruby/core/integer/equal_value_spec.rb
+++ b/spec/ruby/core/integer/equal_value_spec.rb
@@ -1,6 +1,65 @@
require_relative '../../spec_helper'
-require_relative 'shared/equal'
describe "Integer#==" do
- it_behaves_like :integer_equal, :==
+ context "fixnum" do
+ it "returns true if self has the same value as other" do
+ (1 == 1).should == true
+ (9 == 5).should == false
+
+ # Actually, these call Float#==, Integer#== etc.
+ (9 == 9.0).should == true
+ (9 == 9.01).should == false
+
+ (10 == bignum_value).should == false
+ end
+
+ it "calls 'other == self' if the given argument is not an Integer" do
+ (1 == '*').should == false
+
+ obj = mock('one other')
+ obj.should_receive(:==).any_number_of_times.and_return(false)
+ (1 == obj).should == false
+
+ obj = mock('another')
+ obj.should_receive(:==).any_number_of_times.and_return(true)
+ (2 == obj).should == true
+ end
+ end
+
+ context "bignum" do
+ before :each do
+ @bignum = bignum_value
+ end
+
+ it "returns true if self has the same value as the given argument" do
+ (@bignum == @bignum).should == true
+ (@bignum == @bignum.to_f).should == true
+
+ (@bignum == @bignum + 1).should == false
+ ((@bignum + 1) == @bignum).should == false
+
+ (@bignum == 9).should == false
+ (@bignum == 9.01).should == false
+
+ (@bignum == bignum_value(10)).should == false
+ end
+
+ it "calls 'other == self' if the given argument is not an Integer" do
+ obj = mock('not integer')
+ obj.should_receive(:==).and_return(true)
+ (@bignum == obj).should == true
+ end
+
+ it "returns the result of 'other == self' as a boolean" do
+ obj = mock('not integer')
+ obj.should_receive(:==).exactly(2).times.and_return("woot", nil)
+ (@bignum == obj).should == true
+ (@bignum == obj).should == false
+ end
+
+ it "does not lose precision when comparing with a Float" do
+ ((bignum_value(1) == bignum_value.to_f)).should == false
+ ((bignum_value == bignum_value.to_f)).should == true
+ end
+ end
end
diff --git a/spec/ruby/core/integer/even_spec.rb b/spec/ruby/core/integer/even_spec.rb
index a314cc6b19..578979320e 100644
--- a/spec/ruby/core/integer/even_spec.rb
+++ b/spec/ruby/core/integer/even_spec.rb
@@ -3,38 +3,38 @@ require_relative '../../spec_helper'
describe "Integer#even?" do
context "fixnum" do
it "returns true for a Fixnum when it is an even number" do
- (-2).even?.should be_true
- (-1).even?.should be_false
+ (-2).even?.should == true
+ (-1).even?.should == false
- 0.even?.should be_true
- 1.even?.should be_false
- 2.even?.should be_true
+ 0.even?.should == true
+ 1.even?.should == false
+ 2.even?.should == true
end
it "returns true for a Bignum when it is an even number" do
- bignum_value(0).even?.should be_true
- bignum_value(1).even?.should be_false
+ bignum_value(0).even?.should == true
+ bignum_value(1).even?.should == false
- (-bignum_value(0)).even?.should be_true
- (-bignum_value(1)).even?.should be_false
+ (-bignum_value(0)).even?.should == true
+ (-bignum_value(1)).even?.should == false
end
end
context "bignum" do
it "returns true if self is even and positive" do
- (10000**10).even?.should be_true
+ (10000**10).even?.should == true
end
it "returns true if self is even and negative" do
- (-10000**10).even?.should be_true
+ (-10000**10).even?.should == true
end
it "returns false if self is odd and positive" do
- (9879**976).even?.should be_false
+ (9879**976).even?.should == false
end
it "returns false if self is odd and negative" do
- (-9879**976).even?.should be_false
+ (-9879**976).even?.should == false
end
end
end
diff --git a/spec/ruby/core/integer/fdiv_spec.rb b/spec/ruby/core/integer/fdiv_spec.rb
index d9ea2fdf8d..7854d66dec 100644
--- a/spec/ruby/core/integer/fdiv_spec.rb
+++ b/spec/ruby/core/integer/fdiv_spec.rb
@@ -65,8 +65,8 @@ describe "Integer#fdiv" do
end
it "returns NaN when the argument is NaN" do
- -1.fdiv(nan_value).nan?.should be_true
- 1.fdiv(nan_value).nan?.should be_true
+ -1.fdiv(nan_value).nan?.should == true
+ 1.fdiv(nan_value).nan?.should == true
end
it "returns Infinity when the argument is 0" do
@@ -86,11 +86,11 @@ describe "Integer#fdiv" do
end
it "raises a TypeError when argument isn't numeric" do
- -> { 1.fdiv(mock('non-numeric')) }.should raise_error(TypeError)
+ -> { 1.fdiv(mock('non-numeric')) }.should.raise(TypeError)
end
it "raises an ArgumentError when passed multiple arguments" do
- -> { 1.fdiv(6,0.2) }.should raise_error(ArgumentError)
+ -> { 1.fdiv(6,0.2) }.should.raise(ArgumentError)
end
it "follows the coercion protocol" do
diff --git a/spec/ruby/core/integer/fixtures/classes.rb b/spec/ruby/core/integer/fixtures/classes.rb
index 6ebfbd1565..65948efb9f 100644
--- a/spec/ruby/core/integer/fixtures/classes.rb
+++ b/spec/ruby/core/integer/fixtures/classes.rb
@@ -1,4 +1,14 @@
module IntegerSpecs
class CoerceError < StandardError
end
+
+ class CoercibleNumeric
+ def initialize(v) @v = v end
+ def coerce(other) [self.class.new(other), self] end
+ def >(other) @v.to_i > other.to_i end
+ def >=(other) @v.to_i >= other.to_i end
+ def <(other) @v.to_i < other.to_i end
+ def <=(other) @v.to_i <= other.to_i end
+ def to_i() @v.to_i end
+ end
end
diff --git a/spec/ruby/core/integer/gcd_spec.rb b/spec/ruby/core/integer/gcd_spec.rb
index 961f1c5c2e..1fff785927 100644
--- a/spec/ruby/core/integer/gcd_spec.rb
+++ b/spec/ruby/core/integer/gcd_spec.rb
@@ -7,8 +7,8 @@ describe "Integer#gcd" do
end
it "returns an Integer" do
- 36.gcd(6).should be_kind_of(Integer)
- 4.gcd(20981).should be_kind_of(Integer)
+ 36.gcd(6).should.is_a?(Integer)
+ 4.gcd(20981).should.is_a?(Integer)
end
it "returns the greatest common divisor of self and argument" do
@@ -33,13 +33,13 @@ describe "Integer#gcd" do
it "accepts a Bignum argument" do
bignum = 9999**99
- bignum.should be_kind_of(Integer)
+ bignum.should.is_a?(Integer)
99.gcd(bignum).should == 99
end
it "works if self is a Bignum" do
bignum = 9999**99
- bignum.should be_kind_of(Integer)
+ bignum.should.is_a?(Integer)
bignum.gcd(99).should == 99
end
@@ -55,15 +55,15 @@ describe "Integer#gcd" do
end
it "raises an ArgumentError if not given an argument" do
- -> { 12.gcd }.should raise_error(ArgumentError)
+ -> { 12.gcd }.should.raise(ArgumentError)
end
it "raises an ArgumentError if given more than one argument" do
- -> { 12.gcd(30, 20) }.should raise_error(ArgumentError)
+ -> { 12.gcd(30, 20) }.should.raise(ArgumentError)
end
it "raises a TypeError unless the argument is an Integer" do
- -> { 39.gcd(3.8) }.should raise_error(TypeError)
- -> { 45872.gcd([]) }.should raise_error(TypeError)
+ -> { 39.gcd(3.8) }.should.raise(TypeError)
+ -> { 45872.gcd([]) }.should.raise(TypeError)
end
end
diff --git a/spec/ruby/core/integer/gcdlcm_spec.rb b/spec/ruby/core/integer/gcdlcm_spec.rb
index ebf45e55a1..419bf9f275 100644
--- a/spec/ruby/core/integer/gcdlcm_spec.rb
+++ b/spec/ruby/core/integer/gcdlcm_spec.rb
@@ -7,8 +7,8 @@ describe "Integer#gcdlcm" do
end
it "returns an Array" do
- 36.gcdlcm(6).should be_kind_of(Array)
- 4.gcdlcm(20981).should be_kind_of(Array)
+ 36.gcdlcm(6).should.is_a?(Array)
+ 4.gcdlcm(20981).should.is_a?(Array)
end
it "returns a two-element Array" do
@@ -28,26 +28,26 @@ describe "Integer#gcdlcm" do
it "accepts a Bignum argument" do
bignum = 91999**99
- bignum.should be_kind_of(Integer)
+ bignum.should.is_a?(Integer)
99.gcdlcm(bignum).should == [99.gcd(bignum), 99.lcm(bignum)]
end
it "works if self is a Bignum" do
bignum = 9999**89
- bignum.should be_kind_of(Integer)
+ bignum.should.is_a?(Integer)
bignum.gcdlcm(99).should == [bignum.gcd(99), bignum.lcm(99)]
end
it "raises an ArgumentError if not given an argument" do
- -> { 12.gcdlcm }.should raise_error(ArgumentError)
+ -> { 12.gcdlcm }.should.raise(ArgumentError)
end
it "raises an ArgumentError if given more than one argument" do
- -> { 12.gcdlcm(30, 20) }.should raise_error(ArgumentError)
+ -> { 12.gcdlcm(30, 20) }.should.raise(ArgumentError)
end
it "raises a TypeError unless the argument is an Integer" do
- -> { 39.gcdlcm(3.8) }.should raise_error(TypeError)
- -> { 45872.gcdlcm([]) }.should raise_error(TypeError)
+ -> { 39.gcdlcm(3.8) }.should.raise(TypeError)
+ -> { 45872.gcdlcm([]) }.should.raise(TypeError)
end
end
diff --git a/spec/ruby/core/integer/gt_spec.rb b/spec/ruby/core/integer/gt_spec.rb
index f0179e566d..75436144cf 100644
--- a/spec/ruby/core/integer/gt_spec.rb
+++ b/spec/ruby/core/integer/gt_spec.rb
@@ -17,8 +17,8 @@ describe "Integer#>" do
end
it "raises an ArgumentError when given a non-Integer" do
- -> { 5 > "4" }.should raise_error(ArgumentError)
- -> { 5 > mock('x') }.should raise_error(ArgumentError)
+ -> { 5 > "4" }.should.raise(ArgumentError)
+ -> { 5 > mock('x') }.should.raise(ArgumentError)
end
end
@@ -36,8 +36,13 @@ describe "Integer#>" do
end
it "raises an ArgumentError when given a non-Integer" do
- -> { @bignum > "4" }.should raise_error(ArgumentError)
- -> { @bignum > mock('str') }.should raise_error(ArgumentError)
+ -> { @bignum > "4" }.should.raise(ArgumentError)
+ -> { @bignum > mock('str') }.should.raise(ArgumentError)
+ end
+
+ it "dispatches the correct operator after coercion" do
+ (bignum_value > IntegerSpecs::CoercibleNumeric.new(1)).should == true
+ (bignum_value > IntegerSpecs::CoercibleNumeric.new(bignum_value * 2)).should == false
end
end
end
diff --git a/spec/ruby/core/integer/gte_spec.rb b/spec/ruby/core/integer/gte_spec.rb
index 6237fc2c51..e5cb892efd 100644
--- a/spec/ruby/core/integer/gte_spec.rb
+++ b/spec/ruby/core/integer/gte_spec.rb
@@ -18,8 +18,8 @@ describe "Integer#>=" do
end
it "raises an ArgumentError when given a non-Integer" do
- -> { 5 >= "4" }.should raise_error(ArgumentError)
- -> { 5 >= mock('x') }.should raise_error(ArgumentError)
+ -> { 5 >= "4" }.should.raise(ArgumentError)
+ -> { 5 >= mock('x') }.should.raise(ArgumentError)
end
end
@@ -36,8 +36,13 @@ describe "Integer#>=" do
end
it "raises an ArgumentError when given a non-Integer" do
- -> { @bignum >= "4" }.should raise_error(ArgumentError)
- -> { @bignum >= mock('str') }.should raise_error(ArgumentError)
+ -> { @bignum >= "4" }.should.raise(ArgumentError)
+ -> { @bignum >= mock('str') }.should.raise(ArgumentError)
+ end
+
+ it "dispatches the correct operator after coercion" do
+ (bignum_value >= IntegerSpecs::CoercibleNumeric.new(1)).should == true
+ (bignum_value >= IntegerSpecs::CoercibleNumeric.new(bignum_value * 2)).should == false
end
end
end
diff --git a/spec/ruby/core/integer/inspect_spec.rb b/spec/ruby/core/integer/inspect_spec.rb
new file mode 100644
index 0000000000..0b0d5cc7a9
--- /dev/null
+++ b/spec/ruby/core/integer/inspect_spec.rb
@@ -0,0 +1,7 @@
+require_relative '../../spec_helper'
+
+describe "Integer#inspect" do
+ it "is an alias of Integer#to_s" do
+ Integer.instance_method(:inspect).should == Integer.instance_method(:to_s)
+ end
+end
diff --git a/spec/ruby/core/integer/integer_spec.rb b/spec/ruby/core/integer/integer_spec.rb
index 2d5d2e3e92..19a962d548 100644
--- a/spec/ruby/core/integer/integer_spec.rb
+++ b/spec/ruby/core/integer/integer_spec.rb
@@ -6,8 +6,8 @@ describe "Integer" do
end
it "is the class of both small and large integers" do
- 42.class.should equal(Integer)
- bignum_value.class.should equal(Integer)
+ 42.class.should.equal?(Integer)
+ bignum_value.class.should.equal?(Integer)
end
end
diff --git a/spec/ruby/core/integer/lcm_spec.rb b/spec/ruby/core/integer/lcm_spec.rb
index 296a001c8c..6659247d1e 100644
--- a/spec/ruby/core/integer/lcm_spec.rb
+++ b/spec/ruby/core/integer/lcm_spec.rb
@@ -7,8 +7,8 @@ describe "Integer#lcm" do
end
it "returns an Integer" do
- 36.lcm(6).should be_kind_of(Integer)
- 4.lcm(20981).should be_kind_of(Integer)
+ 36.lcm(6).should.is_a?(Integer)
+ 4.lcm(20981).should.is_a?(Integer)
end
it "returns the least common multiple of self and argument" do
@@ -33,26 +33,26 @@ describe "Integer#lcm" do
it "accepts a Bignum argument" do
bignum = 9999**99
- bignum.should be_kind_of(Integer)
+ bignum.should.is_a?(Integer)
99.lcm(bignum).should == bignum
end
it "works if self is a Bignum" do
bignum = 9999**99
- bignum.should be_kind_of(Integer)
+ bignum.should.is_a?(Integer)
bignum.lcm(99).should == bignum
end
it "raises an ArgumentError if not given an argument" do
- -> { 12.lcm }.should raise_error(ArgumentError)
+ -> { 12.lcm }.should.raise(ArgumentError)
end
it "raises an ArgumentError if given more than one argument" do
- -> { 12.lcm(30, 20) }.should raise_error(ArgumentError)
+ -> { 12.lcm(30, 20) }.should.raise(ArgumentError)
end
it "raises a TypeError unless the argument is an Integer" do
- -> { 39.lcm(3.8) }.should raise_error(TypeError)
- -> { 45872.lcm([]) }.should raise_error(TypeError)
+ -> { 39.lcm(3.8) }.should.raise(TypeError)
+ -> { 45872.lcm([]) }.should.raise(TypeError)
end
end
diff --git a/spec/ruby/core/integer/left_shift_spec.rb b/spec/ruby/core/integer/left_shift_spec.rb
index 86c2b18ae2..7eedb91228 100644
--- a/spec/ruby/core/integer/left_shift_spec.rb
+++ b/spec/ruby/core/integer/left_shift_spec.rb
@@ -58,13 +58,13 @@ describe "Integer#<< (with n << m)" do
it "returns a Bignum == fixnum_max * 2 when fixnum_max << 1 and n > 0" do
result = fixnum_max << 1
- result.should be_an_instance_of(Integer)
+ result.should.instance_of?(Integer)
result.should == fixnum_max * 2
end
it "returns a Bignum == fixnum_min * 2 when fixnum_min << 1 and n < 0" do
result = fixnum_min << 1
- result.should be_an_instance_of(Integer)
+ result.should.instance_of?(Integer)
result.should == fixnum_min * 2
end
@@ -82,15 +82,15 @@ describe "Integer#<< (with n << m)" do
obj = mock("a string")
obj.should_receive(:to_int).and_return("asdf")
- -> { 3 << obj }.should raise_error(TypeError)
+ -> { 3 << obj }.should.raise(TypeError)
end
it "raises a TypeError when passed nil" do
- -> { 3 << nil }.should raise_error(TypeError)
+ -> { 3 << nil }.should.raise(TypeError)
end
it "raises a TypeError when passed a String" do
- -> { 3 << "4" }.should raise_error(TypeError)
+ -> { 3 << "4" }.should.raise(TypeError)
end
end
@@ -129,13 +129,13 @@ describe "Integer#<< (with n << m)" do
it "returns a Fixnum == fixnum_max when (fixnum_max * 2) << -1 and n > 0" do
result = (fixnum_max * 2) << -1
- result.should be_an_instance_of(Integer)
+ result.should.instance_of?(Integer)
result.should == fixnum_max
end
it "returns a Fixnum == fixnum_min when (fixnum_min * 2) << -1 and n < 0" do
result = (fixnum_min * 2) << -1
- result.should be_an_instance_of(Integer)
+ result.should.instance_of?(Integer)
result.should == fixnum_min
end
@@ -150,15 +150,15 @@ describe "Integer#<< (with n << m)" do
obj = mock("a string")
obj.should_receive(:to_int).and_return("asdf")
- -> { @bignum << obj }.should raise_error(TypeError)
+ -> { @bignum << obj }.should.raise(TypeError)
end
it "raises a TypeError when passed nil" do
- -> { @bignum << nil }.should raise_error(TypeError)
+ -> { @bignum << nil }.should.raise(TypeError)
end
it "raises a TypeError when passed a String" do
- -> { @bignum << "4" }.should raise_error(TypeError)
+ -> { @bignum << "4" }.should.raise(TypeError)
end
end
@@ -201,10 +201,10 @@ describe "Integer#<< (with n << m)" do
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')
+ -> { (1 << exp) }.should.raise(RangeError, 'shift width too big')
+ -> { (-1 << exp) }.should.raise(RangeError, 'shift width too big')
+ -> { (bignum_value << exp) }.should.raise(RangeError, 'shift width too big')
+ -> { (-bignum_value << exp) }.should.raise(RangeError, 'shift width too big')
}
end
end
diff --git a/spec/ruby/core/integer/lt_spec.rb b/spec/ruby/core/integer/lt_spec.rb
index c182f82555..dd1391d093 100644
--- a/spec/ruby/core/integer/lt_spec.rb
+++ b/spec/ruby/core/integer/lt_spec.rb
@@ -17,8 +17,8 @@ describe "Integer#<" do
end
it "raises an ArgumentError when given a non-Integer" do
- -> { 5 < "4" }.should raise_error(ArgumentError)
- -> { 5 < mock('x') }.should raise_error(ArgumentError)
+ -> { 5 < "4" }.should.raise(ArgumentError)
+ -> { 5 < mock('x') }.should.raise(ArgumentError)
end
end
@@ -38,8 +38,13 @@ describe "Integer#<" do
end
it "raises an ArgumentError when given a non-Integer" do
- -> { @bignum < "4" }.should raise_error(ArgumentError)
- -> { @bignum < mock('str') }.should raise_error(ArgumentError)
+ -> { @bignum < "4" }.should.raise(ArgumentError)
+ -> { @bignum < mock('str') }.should.raise(ArgumentError)
+ end
+
+ it "dispatches the correct operator after coercion" do
+ (bignum_value < IntegerSpecs::CoercibleNumeric.new(bignum_value * 2)).should == true
+ (bignum_value < IntegerSpecs::CoercibleNumeric.new(1)).should == false
end
end
end
diff --git a/spec/ruby/core/integer/lte_spec.rb b/spec/ruby/core/integer/lte_spec.rb
index 65b71d77f2..9ef1c9f604 100644
--- a/spec/ruby/core/integer/lte_spec.rb
+++ b/spec/ruby/core/integer/lte_spec.rb
@@ -18,8 +18,8 @@ describe "Integer#<=" do
end
it "raises an ArgumentError when given a non-Integer" do
- -> { 5 <= "4" }.should raise_error(ArgumentError)
- -> { 5 <= mock('x') }.should raise_error(ArgumentError)
+ -> { 5 <= "4" }.should.raise(ArgumentError)
+ -> { 5 <= mock('x') }.should.raise(ArgumentError)
end
end
@@ -46,8 +46,13 @@ describe "Integer#<=" do
end
it "raises an ArgumentError when given a non-Integer" do
- -> { @bignum <= "4" }.should raise_error(ArgumentError)
- -> { @bignum <= mock('str') }.should raise_error(ArgumentError)
+ -> { @bignum <= "4" }.should.raise(ArgumentError)
+ -> { @bignum <= mock('str') }.should.raise(ArgumentError)
+ end
+
+ it "dispatches the correct operator after coercion" do
+ (bignum_value <= IntegerSpecs::CoercibleNumeric.new(bignum_value * 2)).should == true
+ (bignum_value <= IntegerSpecs::CoercibleNumeric.new(1)).should == false
end
end
end
diff --git a/spec/ruby/core/integer/magnitude_spec.rb b/spec/ruby/core/integer/magnitude_spec.rb
index 48cf1a8534..000e5be7f7 100644
--- a/spec/ruby/core/integer/magnitude_spec.rb
+++ b/spec/ruby/core/integer/magnitude_spec.rb
@@ -1,6 +1,7 @@
require_relative '../../spec_helper'
-require_relative 'shared/abs'
describe "Integer#magnitude" do
- it_behaves_like :integer_abs, :magnitude
+ it "is an alias of Integer#abs" do
+ Integer.instance_method(:magnitude).should == Integer.instance_method(:abs)
+ end
end
diff --git a/spec/ruby/core/integer/minus_spec.rb b/spec/ruby/core/integer/minus_spec.rb
index 6072ba7c8b..5fd3a81a72 100644
--- a/spec/ruby/core/integer/minus_spec.rb
+++ b/spec/ruby/core/integer/minus_spec.rb
@@ -17,9 +17,9 @@ describe "Integer#-" do
-> {
(obj = mock('10')).should_receive(:to_int).any_number_of_times.and_return(10)
13 - obj
- }.should raise_error(TypeError)
- -> { 13 - "10" }.should raise_error(TypeError)
- -> { 13 - :symbol }.should raise_error(TypeError)
+ }.should.raise(TypeError)
+ -> { 13 - "10" }.should.raise(TypeError)
+ -> { 13 - :symbol }.should.raise(TypeError)
end
end
@@ -35,9 +35,9 @@ describe "Integer#-" do
end
it "raises a TypeError when given a non-Integer" do
- -> { @bignum - mock('10') }.should raise_error(TypeError)
- -> { @bignum - "10" }.should raise_error(TypeError)
- -> { @bignum - :symbol }.should raise_error(TypeError)
+ -> { @bignum - mock('10') }.should.raise(TypeError)
+ -> { @bignum - "10" }.should.raise(TypeError)
+ -> { @bignum - :symbol }.should.raise(TypeError)
end
end
diff --git a/spec/ruby/core/integer/modulo_spec.rb b/spec/ruby/core/integer/modulo_spec.rb
index e263338e38..2680f49510 100644
--- a/spec/ruby/core/integer/modulo_spec.rb
+++ b/spec/ruby/core/integer/modulo_spec.rb
@@ -1,10 +1,122 @@
require_relative '../../spec_helper'
-require_relative 'shared/modulo'
describe "Integer#%" do
- it_behaves_like :integer_modulo, :%
+ context "fixnum" do
+ it "returns the modulus obtained from dividing self by the given argument" do
+ # test all possible combinations:
+ # - integer/double/bignum argument
+ # - positive/negative argument
+ # - positive/negative self
+ # - self greater/smaller than argument
+
+ (13 % 4).should == 1
+ (4 % 13).should == 4
+
+ (13 % 4.0).should == 1
+ (4 % 13.0).should == 4
+
+ (-200 % 256).should == 56
+ (-1000 % 512).should == 24
+
+ (-200 % -256).should == -200
+ (-1000 % -512).should == -488
+
+ (200 % -256).should == -56
+ (1000 % -512).should == -24
+
+ (13 % -4.0).should == -3.0
+ (4 % -13.0).should == -9.0
+
+ (-13 % -4.0).should == -1.0
+ (-4 % -13.0).should == -4.0
+
+ (-13 % 4.0).should == 3.0
+ (-4 % 13.0).should == 9.0
+
+ (1 % 2.0).should == 1.0
+ (200 % bignum_value).should == 200
+
+ (4 % bignum_value(10)).should == 4
+ (4 % -bignum_value(10)).should == -18446744073709551622
+ (-4 % bignum_value(10)).should == 18446744073709551622
+ (-4 % -bignum_value(10)).should == -4
+ end
+
+ it "raises a ZeroDivisionError when the given argument is 0" do
+ -> { 13 % 0 }.should.raise(ZeroDivisionError)
+ -> { 0 % 0 }.should.raise(ZeroDivisionError)
+ -> { -10 % 0 }.should.raise(ZeroDivisionError)
+ end
+
+ it "raises a ZeroDivisionError when the given argument is 0 and a Float" do
+ -> { 0 % 0.0 }.should.raise(ZeroDivisionError)
+ -> { 10 % 0.0 }.should.raise(ZeroDivisionError)
+ -> { -10 % 0.0 }.should.raise(ZeroDivisionError)
+ end
+
+ it "raises a TypeError when given a non-Integer" do
+ -> {
+ (obj = mock('10')).should_receive(:to_int).any_number_of_times.and_return(10)
+ 13 % obj
+ }.should.raise(TypeError)
+ -> { 13 % "10" }.should.raise(TypeError)
+ -> { 13 % :symbol }.should.raise(TypeError)
+ end
+ end
+
+ context "bignum" do
+ before :each do
+ @bignum = bignum_value(10)
+ end
+
+ it "returns the modulus obtained from dividing self by the given argument" do
+ # test all possible combinations:
+ # - integer/double/bignum argument
+ # - positive/negative argument
+ # - positive/negative self
+ # - self greater/smaller than argument
+
+ (@bignum % 5).should == 1
+ (@bignum % -5).should == -4
+ (-@bignum % 5).should == 4
+ (-@bignum % -5).should == -1
+
+ (@bignum % 2.22).should be_close(1.5603603603605034, TOLERANCE)
+ (@bignum % -2.22).should be_close(-0.6596396396394968, TOLERANCE)
+ (-@bignum % 2.22).should be_close(0.6596396396394968, TOLERANCE)
+ (-@bignum % -2.22).should be_close(-1.5603603603605034, TOLERANCE)
+
+ (@bignum % (@bignum + 10)).should == 18446744073709551626
+ (@bignum % -(@bignum + 10)).should == -10
+ (-@bignum % (@bignum + 10)).should == 10
+ (-@bignum % -(@bignum + 10)).should == -18446744073709551626
+
+ ((@bignum + 10) % @bignum).should == 10
+ ((@bignum + 10) % -@bignum).should == -18446744073709551616
+ (-(@bignum + 10) % @bignum).should == 18446744073709551616
+ (-(@bignum + 10) % -@bignum).should == -10
+ end
+
+ it "raises a ZeroDivisionError when the given argument is 0" do
+ -> { @bignum % 0 }.should.raise(ZeroDivisionError)
+ -> { -@bignum % 0 }.should.raise(ZeroDivisionError)
+ end
+
+ it "raises a ZeroDivisionError when the given argument is 0 and a Float" do
+ -> { @bignum % 0.0 }.should.raise(ZeroDivisionError)
+ -> { -@bignum % 0.0 }.should.raise(ZeroDivisionError)
+ end
+
+ it "raises a TypeError when given a non-Integer" do
+ -> { @bignum % mock('10') }.should.raise(TypeError)
+ -> { @bignum % "10" }.should.raise(TypeError)
+ -> { @bignum % :symbol }.should.raise(TypeError)
+ end
+ end
end
describe "Integer#modulo" do
- it_behaves_like :integer_modulo, :modulo
+ it "is an alias of Integer#%" do
+ Integer.instance_method(:modulo).should == Integer.instance_method(:%)
+ end
end
diff --git a/spec/ruby/core/integer/multiply_spec.rb b/spec/ruby/core/integer/multiply_spec.rb
index 5037d27458..7f30eebaa5 100644
--- a/spec/ruby/core/integer/multiply_spec.rb
+++ b/spec/ruby/core/integer/multiply_spec.rb
@@ -18,9 +18,9 @@ describe "Integer#*" do
-> {
(obj = mock('10')).should_receive(:to_int).any_number_of_times.and_return(10)
13 * obj
- }.should raise_error(TypeError)
- -> { 13 * "10" }.should raise_error(TypeError)
- -> { 13 * :symbol }.should raise_error(TypeError)
+ }.should.raise(TypeError)
+ -> { 13 * "10" }.should.raise(TypeError)
+ -> { 13 * :symbol }.should.raise(TypeError)
end
end
@@ -37,9 +37,9 @@ describe "Integer#*" do
end
it "raises a TypeError when given a non-Integer" do
- -> { @bignum * mock('10') }.should raise_error(TypeError)
- -> { @bignum * "10" }.should raise_error(TypeError)
- -> { @bignum * :symbol }.should raise_error(TypeError)
+ -> { @bignum * mock('10') }.should.raise(TypeError)
+ -> { @bignum * "10" }.should.raise(TypeError)
+ -> { @bignum * :symbol }.should.raise(TypeError)
end
end
end
diff --git a/spec/ruby/core/integer/next_spec.rb b/spec/ruby/core/integer/next_spec.rb
index 63c4e67893..da54dec454 100644
--- a/spec/ruby/core/integer/next_spec.rb
+++ b/spec/ruby/core/integer/next_spec.rb
@@ -1,6 +1,7 @@
require_relative '../../spec_helper'
-require_relative 'shared/next'
describe "Integer#next" do
- it_behaves_like :integer_next, :next
+ it "is an alias of Integer#succ" do
+ Integer.instance_method(:next).should == Integer.instance_method(:succ)
+ end
end
diff --git a/spec/ruby/core/integer/nobits_spec.rb b/spec/ruby/core/integer/nobits_spec.rb
index 685759ffa3..f1a3aca9d5 100644
--- a/spec/ruby/core/integer/nobits_spec.rb
+++ b/spec/ruby/core/integer/nobits_spec.rb
@@ -29,8 +29,8 @@ describe "Integer#nobits?" do
-> {
(obj = mock('10')).should_receive(:coerce).any_number_of_times.and_return([42,10])
13.nobits?(obj)
- }.should raise_error(TypeError)
- -> { 13.nobits?("10") }.should raise_error(TypeError)
- -> { 13.nobits?(:symbol) }.should raise_error(TypeError)
+ }.should.raise(TypeError)
+ -> { 13.nobits?("10") }.should.raise(TypeError)
+ -> { 13.nobits?(:symbol) }.should.raise(TypeError)
end
end
diff --git a/spec/ruby/core/integer/odd_spec.rb b/spec/ruby/core/integer/odd_spec.rb
index dd779fa44b..f9e50ec790 100644
--- a/spec/ruby/core/integer/odd_spec.rb
+++ b/spec/ruby/core/integer/odd_spec.rb
@@ -3,36 +3,36 @@ require_relative '../../spec_helper'
describe "Integer#odd?" do
context "fixnum" do
it "returns true when self is an odd number" do
- (-2).odd?.should be_false
- (-1).odd?.should be_true
+ (-2).odd?.should == false
+ (-1).odd?.should == true
- 0.odd?.should be_false
- 1.odd?.should be_true
- 2.odd?.should be_false
+ 0.odd?.should == false
+ 1.odd?.should == true
+ 2.odd?.should == false
- bignum_value(0).odd?.should be_false
- bignum_value(1).odd?.should be_true
+ bignum_value(0).odd?.should == false
+ bignum_value(1).odd?.should == true
- (-bignum_value(0)).odd?.should be_false
- (-bignum_value(1)).odd?.should be_true
+ (-bignum_value(0)).odd?.should == false
+ (-bignum_value(1)).odd?.should == true
end
end
context "bignum" do
it "returns true if self is odd and positive" do
- (987279**19).odd?.should be_true
+ (987279**19).odd?.should == true
end
it "returns true if self is odd and negative" do
- (-9873389**97).odd?.should be_true
+ (-9873389**97).odd?.should == true
end
it "returns false if self is even and positive" do
- (10000000**10).odd?.should be_false
+ (10000000**10).odd?.should == false
end
it "returns false if self is even and negative" do
- (-1000000**100).odd?.should be_false
+ (-1000000**100).odd?.should == false
end
end
end
diff --git a/spec/ruby/core/integer/ord_spec.rb b/spec/ruby/core/integer/ord_spec.rb
index bcb57bea98..8b7dfe460d 100644
--- a/spec/ruby/core/integer/ord_spec.rb
+++ b/spec/ruby/core/integer/ord_spec.rb
@@ -2,16 +2,16 @@ require_relative '../../spec_helper'
describe "Integer#ord" do
it "returns self" do
- 20.ord.should eql(20)
- 40.ord.should eql(40)
+ 20.ord.should.eql?(20)
+ 40.ord.should.eql?(40)
- 0.ord.should eql(0)
- (-10).ord.should eql(-10)
+ 0.ord.should.eql?(0)
+ (-10).ord.should.eql?(-10)
- ?a.ord.should eql(97)
- ?Z.ord.should eql(90)
+ ?a.ord.should.eql?(97)
+ ?Z.ord.should.eql?(90)
- bignum_value.ord.should eql(bignum_value)
- (-bignum_value).ord.should eql(-bignum_value)
+ bignum_value.ord.should.eql?(bignum_value)
+ (-bignum_value).ord.should.eql?(-bignum_value)
end
end
diff --git a/spec/ruby/core/integer/plus_spec.rb b/spec/ruby/core/integer/plus_spec.rb
index 38428e56c5..b684377bd5 100644
--- a/spec/ruby/core/integer/plus_spec.rb
+++ b/spec/ruby/core/integer/plus_spec.rb
@@ -17,9 +17,9 @@ describe "Integer#+" do
-> {
(obj = mock('10')).should_receive(:to_int).any_number_of_times.and_return(10)
13 + obj
- }.should raise_error(TypeError)
- -> { 13 + "10" }.should raise_error(TypeError)
- -> { 13 + :symbol }.should raise_error(TypeError)
+ }.should.raise(TypeError)
+ -> { 13 + "10" }.should.raise(TypeError)
+ -> { 13 + :symbol }.should.raise(TypeError)
end
end
@@ -35,9 +35,9 @@ describe "Integer#+" do
end
it "raises a TypeError when given a non-Integer" do
- -> { @bignum + mock('10') }.should raise_error(TypeError)
- -> { @bignum + "10" }.should raise_error(TypeError)
- -> { @bignum + :symbol}.should raise_error(TypeError)
+ -> { @bignum + mock('10') }.should.raise(TypeError)
+ -> { @bignum + "10" }.should.raise(TypeError)
+ -> { @bignum + :symbol}.should.raise(TypeError)
end
end
diff --git a/spec/ruby/core/integer/pow_spec.rb b/spec/ruby/core/integer/pow_spec.rb
index ecaca01eff..12a3839c40 100644
--- a/spec/ruby/core/integer/pow_spec.rb
+++ b/spec/ruby/core/integer/pow_spec.rb
@@ -16,10 +16,10 @@ describe "Integer#pow" do
end
it "works well with bignums" do
- 2.pow(61, 5843009213693951).should eql 3697379018277258
- 2.pow(62, 5843009213693952).should eql 1551748822859776
- 2.pow(63, 5843009213693953).should eql 3103497645717974
- 2.pow(64, 5843009213693954).should eql 363986077738838
+ 2.pow(61, 5843009213693951).should.eql? 3697379018277258
+ 2.pow(62, 5843009213693952).should.eql? 1551748822859776
+ 2.pow(63, 5843009213693953).should.eql? 3103497645717974
+ 2.pow(64, 5843009213693954).should.eql? 363986077738838
end
it "handles sign like #divmod does" do
@@ -30,22 +30,22 @@ describe "Integer#pow" do
end
it "ensures all arguments are integers" do
- -> { 2.pow(5, 12.0) }.should raise_error(TypeError, /2nd argument not allowed unless all arguments are integers/)
- -> { 2.pow(5, Rational(12, 1)) }.should raise_error(TypeError, /2nd argument not allowed unless all arguments are integers/)
+ -> { 2.pow(5, 12.0) }.should.raise(TypeError, /2nd argument not allowed unless all arguments are integers/)
+ -> { 2.pow(5, Rational(12, 1)) }.should.raise(TypeError, /2nd argument not allowed unless all arguments are integers/)
end
it "raises TypeError for non-numeric value" do
- -> { 2.pow(5, "12") }.should raise_error(TypeError)
- -> { 2.pow(5, []) }.should raise_error(TypeError)
- -> { 2.pow(5, nil) }.should raise_error(TypeError)
+ -> { 2.pow(5, "12") }.should.raise(TypeError)
+ -> { 2.pow(5, []) }.should.raise(TypeError)
+ -> { 2.pow(5, nil) }.should.raise(TypeError)
end
it "raises a ZeroDivisionError when the given argument is 0" do
- -> { 2.pow(5, 0) }.should raise_error(ZeroDivisionError)
+ -> { 2.pow(5, 0) }.should.raise(ZeroDivisionError)
end
it "raises a RangeError when the first argument is negative and the second argument is present" do
- -> { 2.pow(-5, 1) }.should raise_error(RangeError)
+ -> { 2.pow(-5, 1) }.should.raise(RangeError)
end
end
end
diff --git a/spec/ruby/core/integer/pred_spec.rb b/spec/ruby/core/integer/pred_spec.rb
index 86750ebfd1..fce536b5a2 100644
--- a/spec/ruby/core/integer/pred_spec.rb
+++ b/spec/ruby/core/integer/pred_spec.rb
@@ -2,10 +2,10 @@ require_relative '../../spec_helper'
describe "Integer#pred" do
it "returns the Integer equal to self - 1" do
- 0.pred.should eql(-1)
- -1.pred.should eql(-2)
- bignum_value.pred.should eql(bignum_value(-1))
- fixnum_min.pred.should eql(fixnum_min - 1)
- 20.pred.should eql(19)
+ 0.pred.should.eql?(-1)
+ -1.pred.should.eql?(-2)
+ bignum_value.pred.should.eql?(bignum_value(-1))
+ fixnum_min.pred.should.eql?(fixnum_min - 1)
+ 20.pred.should.eql?(19)
end
end
diff --git a/spec/ruby/core/integer/rationalize_spec.rb b/spec/ruby/core/integer/rationalize_spec.rb
index 09d741af33..272eca6911 100644
--- a/spec/ruby/core/integer/rationalize_spec.rb
+++ b/spec/ruby/core/integer/rationalize_spec.rb
@@ -12,7 +12,7 @@ describe "Integer#rationalize" do
it "returns a Rational object" do
@numbers.each do |number|
- number.rationalize.should be_an_instance_of(Rational)
+ number.rationalize.should.instance_of?(Rational)
end
end
@@ -33,7 +33,7 @@ describe "Integer#rationalize" do
end
it "raises ArgumentError when passed more than one argument" do
- -> { 1.rationalize(0.1, 0.1) }.should raise_error(ArgumentError)
- -> { 1.rationalize(0.1, 0.1, 2) }.should raise_error(ArgumentError)
+ -> { 1.rationalize(0.1, 0.1) }.should.raise(ArgumentError)
+ -> { 1.rationalize(0.1, 0.1, 2) }.should.raise(ArgumentError)
end
end
diff --git a/spec/ruby/core/integer/remainder_spec.rb b/spec/ruby/core/integer/remainder_spec.rb
index 757e42fbe8..deb81fb2a5 100644
--- a/spec/ruby/core/integer/remainder_spec.rb
+++ b/spec/ruby/core/integer/remainder_spec.rb
@@ -22,10 +22,10 @@ describe "Integer#remainder" do
end
it "raises TypeError if passed non-numeric argument" do
- -> { 5.remainder("3") }.should raise_error(TypeError)
- -> { 5.remainder(:"3") }.should raise_error(TypeError)
- -> { 5.remainder([]) }.should raise_error(TypeError)
- -> { 5.remainder(nil) }.should raise_error(TypeError)
+ -> { 5.remainder("3") }.should.raise(TypeError)
+ -> { 5.remainder(:"3") }.should.raise(TypeError)
+ -> { 5.remainder([]) }.should.raise(TypeError)
+ -> { 5.remainder(nil) }.should.raise(TypeError)
end
end
@@ -38,14 +38,14 @@ describe "Integer#remainder" do
end
it "raises a ZeroDivisionError if other is zero and not a Float" do
- -> { bignum_value(66).remainder(0) }.should raise_error(ZeroDivisionError)
+ -> { bignum_value(66).remainder(0) }.should.raise(ZeroDivisionError)
end
it "does raises ZeroDivisionError if other is zero and a Float" do
a = bignum_value(7)
b = bignum_value(32)
- -> { a.remainder(0.0) }.should raise_error(ZeroDivisionError)
- -> { b.remainder(-0.0) }.should raise_error(ZeroDivisionError)
+ -> { a.remainder(0.0) }.should.raise(ZeroDivisionError)
+ -> { b.remainder(-0.0) }.should.raise(ZeroDivisionError)
end
end
end
diff --git a/spec/ruby/core/integer/right_shift_spec.rb b/spec/ruby/core/integer/right_shift_spec.rb
index c902674e2f..4281d3b7ab 100644
--- a/spec/ruby/core/integer/right_shift_spec.rb
+++ b/spec/ruby/core/integer/right_shift_spec.rb
@@ -54,13 +54,13 @@ describe "Integer#>> (with n >> m)" do
it "returns a Bignum == fixnum_max * 2 when fixnum_max >> -1 and n > 0" do
result = fixnum_max >> -1
- result.should be_an_instance_of(Integer)
+ result.should.instance_of?(Integer)
result.should == fixnum_max * 2
end
it "returns a Bignum == fixnum_min * 2 when fixnum_min >> -1 and n < 0" do
result = fixnum_min >> -1
- result.should be_an_instance_of(Integer)
+ result.should.instance_of?(Integer)
result.should == fixnum_min * 2
end
@@ -78,15 +78,15 @@ describe "Integer#>> (with n >> m)" do
obj = mock("a string")
obj.should_receive(:to_int).and_return("asdf")
- -> { 3 >> obj }.should raise_error(TypeError)
+ -> { 3 >> obj }.should.raise(TypeError)
end
it "raises a TypeError when passed nil" do
- -> { 3 >> nil }.should raise_error(TypeError)
+ -> { 3 >> nil }.should.raise(TypeError)
end
it "raises a TypeError when passed a String" do
- -> { 3 >> "4" }.should raise_error(TypeError)
+ -> { 3 >> "4" }.should.raise(TypeError)
end
end
@@ -151,13 +151,13 @@ describe "Integer#>> (with n >> m)" do
it "returns a Fixnum == fixnum_max when (fixnum_max * 2) >> 1 and n > 0" do
result = (fixnum_max * 2) >> 1
- result.should be_an_instance_of(Integer)
+ result.should.instance_of?(Integer)
result.should == fixnum_max
end
it "returns a Fixnum == fixnum_min when (fixnum_min * 2) >> 1 and n < 0" do
result = (fixnum_min * 2) >> 1
- result.should be_an_instance_of(Integer)
+ result.should.instance_of?(Integer)
result.should == fixnum_min
end
@@ -172,15 +172,15 @@ describe "Integer#>> (with n >> m)" do
obj = mock("a string")
obj.should_receive(:to_int).and_return("asdf")
- -> { @bignum >> obj }.should raise_error(TypeError)
+ -> { @bignum >> obj }.should.raise(TypeError)
end
it "raises a TypeError when passed nil" do
- -> { @bignum >> nil }.should raise_error(TypeError)
+ -> { @bignum >> nil }.should.raise(TypeError)
end
it "raises a TypeError when passed a String" do
- -> { @bignum >> "4" }.should raise_error(TypeError)
+ -> { @bignum >> "4" }.should.raise(TypeError)
end
end
@@ -223,10 +223,10 @@ describe "Integer#>> (with n >> m)" do
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')
+ -> { (1 >> exp) }.should.raise(RangeError, 'shift width too big')
+ -> { (-1 >> exp) }.should.raise(RangeError, 'shift width too big')
+ -> { (bignum_value >> exp) }.should.raise(RangeError, 'shift width too big')
+ -> { (-bignum_value >> exp) }.should.raise(RangeError, 'shift width too big')
}
end
end
diff --git a/spec/ruby/core/integer/round_spec.rb b/spec/ruby/core/integer/round_spec.rb
index 189384f11a..a3f11e7a76 100644
--- a/spec/ruby/core/integer/round_spec.rb
+++ b/spec/ruby/core/integer/round_spec.rb
@@ -8,37 +8,37 @@ describe "Integer#round" do
# redmine:5228
it "returns itself rounded if passed a negative value" do
- +249.round(-2).should eql(+200)
- -249.round(-2).should eql(-200)
- (+25 * 10**70 - 1).round(-71).should eql(+20 * 10**70)
- (-25 * 10**70 + 1).round(-71).should eql(-20 * 10**70)
+ +249.round(-2).should.eql?(+200)
+ -249.round(-2).should.eql?(-200)
+ (+25 * 10**70 - 1).round(-71).should.eql?(+20 * 10**70)
+ (-25 * 10**70 + 1).round(-71).should.eql?(-20 * 10**70)
end
it "returns itself rounded to nearest if passed a negative value" do
- +250.round(-2).should eql(+300)
- -250.round(-2).should eql(-300)
- (+25 * 10**70).round(-71).should eql(+30 * 10**70)
- (-25 * 10**70).round(-71).should eql(-30 * 10**70)
+ +250.round(-2).should.eql?(+300)
+ -250.round(-2).should.eql?(-300)
+ (+25 * 10**70).round(-71).should.eql?(+30 * 10**70)
+ (-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)
+ -> { 42.round(min_long - 1) }.should.raise(RangeError)
end
it "raises a RangeError when passed Float::INFINITY" do
- -> { 42.round(Float::INFINITY) }.should raise_error(RangeError)
+ -> { 42.round(Float::INFINITY) }.should.raise(RangeError)
end
it "raises a RangeError when passed a beyond signed int" do
- -> { 42.round(1<<31) }.should raise_error(RangeError)
+ -> { 42.round(1<<31) }.should.raise(RangeError)
end
it "raises a TypeError when passed a String" do
- -> { 42.round("4") }.should raise_error(TypeError)
+ -> { 42.round("4") }.should.raise(TypeError)
end
it "raises a TypeError when its argument cannot be converted to an Integer" do
- -> { 42.round(nil) }.should raise_error(TypeError)
+ -> { 42.round(nil) }.should.raise(TypeError)
end
it "calls #to_int on the argument to convert it to an Integer" do
@@ -50,32 +50,32 @@ describe "Integer#round" do
it "raises a TypeError when #to_int does not return an Integer" do
obj = mock("Object")
obj.stub!(:to_int).and_return([])
- -> { 42.round(obj) }.should raise_error(TypeError)
+ -> { 42.round(obj) }.should.raise(TypeError)
end
it "returns different rounded values depending on the half option" do
- 25.round(-1, half: :up).should eql(30)
- 25.round(-1, half: :down).should eql(20)
- 25.round(-1, half: :even).should eql(20)
- 25.round(-1, half: nil).should eql(30)
- 35.round(-1, half: :up).should eql(40)
- 35.round(-1, half: :down).should eql(30)
- 35.round(-1, half: :even).should eql(40)
- 35.round(-1, half: nil).should eql(40)
- (-25).round(-1, half: :up).should eql(-30)
- (-25).round(-1, half: :down).should eql(-20)
- (-25).round(-1, half: :even).should eql(-20)
- (-25).round(-1, half: nil).should eql(-30)
+ 25.round(-1, half: :up).should.eql?(30)
+ 25.round(-1, half: :down).should.eql?(20)
+ 25.round(-1, half: :even).should.eql?(20)
+ 25.round(-1, half: nil).should.eql?(30)
+ 35.round(-1, half: :up).should.eql?(40)
+ 35.round(-1, half: :down).should.eql?(30)
+ 35.round(-1, half: :even).should.eql?(40)
+ 35.round(-1, half: nil).should.eql?(40)
+ (-25).round(-1, half: :up).should.eql?(-30)
+ (-25).round(-1, half: :down).should.eql?(-20)
+ (-25).round(-1, half: :even).should.eql?(-20)
+ (-25).round(-1, half: nil).should.eql?(-30)
end
it "returns itself if passed a positive precision and the half option" do
- 35.round(1, half: :up).should eql(35)
- 35.round(1, half: :down).should eql(35)
- 35.round(1, half: :even).should eql(35)
+ 35.round(1, half: :up).should.eql?(35)
+ 35.round(1, half: :down).should.eql?(35)
+ 35.round(1, half: :even).should.eql?(35)
end
it "raises ArgumentError for an unknown rounding mode" do
- -> { 42.round(-1, half: :foo) }.should raise_error(ArgumentError, /invalid rounding mode: foo/)
- -> { 42.round(1, half: :foo) }.should raise_error(ArgumentError, /invalid rounding mode: foo/)
+ -> { 42.round(-1, half: :foo) }.should.raise(ArgumentError, /invalid rounding mode: foo/)
+ -> { 42.round(1, half: :foo) }.should.raise(ArgumentError, /invalid rounding mode: foo/)
end
end
diff --git a/spec/ruby/core/integer/shared/abs.rb b/spec/ruby/core/integer/shared/abs.rb
deleted file mode 100644
index 43844c9065..0000000000
--- a/spec/ruby/core/integer/shared/abs.rb
+++ /dev/null
@@ -1,18 +0,0 @@
-describe :integer_abs, shared: true do
- context "fixnum" do
- it "returns self's absolute fixnum value" do
- { 0 => [0, -0, +0], 2 => [2, -2, +2], 100 => [100, -100, +100] }.each do |key, values|
- values.each do |value|
- value.send(@method).should == key
- end
- end
- end
- end
-
- context "bignum" do
- it "returns the absolute bignum value" do
- bignum_value(39).send(@method).should == 18446744073709551655
- (-bignum_value(18)).send(@method).should == 18446744073709551634
- end
- end
-end
diff --git a/spec/ruby/core/integer/shared/arithmetic_coerce.rb b/spec/ruby/core/integer/shared/arithmetic_coerce.rb
index 1260192df1..561b18fe52 100644
--- a/spec/ruby/core/integer/shared/arithmetic_coerce.rb
+++ b/spec/ruby/core/integer/shared/arithmetic_coerce.rb
@@ -6,6 +6,6 @@ describe :integer_arithmetic_coerce_not_rescue, shared: true do
b.should_receive(:coerce).and_raise(IntegerSpecs::CoerceError)
# e.g. 1 + b
- -> { 1.send(@method, b) }.should raise_error(IntegerSpecs::CoerceError)
+ -> { 1.send(@method, b) }.should.raise(IntegerSpecs::CoerceError)
end
end
diff --git a/spec/ruby/core/integer/shared/comparison_coerce.rb b/spec/ruby/core/integer/shared/comparison_coerce.rb
index af52f5e99b..4bb7404183 100644
--- a/spec/ruby/core/integer/shared/comparison_coerce.rb
+++ b/spec/ruby/core/integer/shared/comparison_coerce.rb
@@ -6,6 +6,6 @@ describe :integer_comparison_coerce_not_rescue, shared: true do
b.should_receive(:coerce).and_raise(IntegerSpecs::CoerceError)
# e.g. 1 > b
- -> { 1.send(@method, b) }.should raise_error(IntegerSpecs::CoerceError)
+ -> { 1.send(@method, b) }.should.raise(IntegerSpecs::CoerceError)
end
end
diff --git a/spec/ruby/core/integer/shared/equal.rb b/spec/ruby/core/integer/shared/equal.rb
deleted file mode 100644
index ecee17831c..0000000000
--- a/spec/ruby/core/integer/shared/equal.rb
+++ /dev/null
@@ -1,58 +0,0 @@
-describe :integer_equal, shared: true do
- context "fixnum" do
- it "returns true if self has the same value as other" do
- 1.send(@method, 1).should == true
- 9.send(@method, 5).should == false
-
- # Actually, these call Float#==, Integer#== etc.
- 9.send(@method, 9.0).should == true
- 9.send(@method, 9.01).should == false
-
- 10.send(@method, bignum_value).should == false
- end
-
- it "calls 'other == self' if the given argument is not an Integer" do
- 1.send(@method, '*').should == false
-
- obj = mock('one other')
- obj.should_receive(:==).any_number_of_times.and_return(false)
- 1.send(@method, obj).should == false
-
- obj = mock('another')
- obj.should_receive(:==).any_number_of_times.and_return(true)
- 2.send(@method, obj).should == true
- end
- end
-
- context "bignum" do
- before :each do
- @bignum = bignum_value
- end
-
- it "returns true if self has the same value as the given argument" do
- @bignum.send(@method, @bignum).should == true
- @bignum.send(@method, @bignum.to_f).should == true
-
- @bignum.send(@method, @bignum + 1).should == false
- (@bignum + 1).send(@method, @bignum).should == false
-
- @bignum.send(@method, 9).should == false
- @bignum.send(@method, 9.01).should == false
-
- @bignum.send(@method, bignum_value(10)).should == false
- end
-
- it "calls 'other == self' if the given argument is not an Integer" do
- obj = mock('not integer')
- obj.should_receive(:==).and_return(true)
- @bignum.send(@method, obj).should == true
- end
-
- it "returns the result of 'other == self' as a boolean" do
- obj = mock('not integer')
- obj.should_receive(:==).exactly(2).times.and_return("woot", nil)
- @bignum.send(@method, obj).should == true
- @bignum.send(@method, obj).should == false
- end
- end
-end
diff --git a/spec/ruby/core/integer/shared/exponent.rb b/spec/ruby/core/integer/shared/exponent.rb
index 5ef6d686d8..0be13859f9 100644
--- a/spec/ruby/core/integer/shared/exponent.rb
+++ b/spec/ruby/core/integer/shared/exponent.rb
@@ -1,51 +1,51 @@
describe :integer_exponent, shared: true do
context "fixnum" do
it "returns self raised to the given power" do
- 2.send(@method, 0).should eql 1
- 2.send(@method, 1).should eql 2
- 2.send(@method, 2).should eql 4
+ 2.send(@method, 0).should.eql? 1
+ 2.send(@method, 1).should.eql? 2
+ 2.send(@method, 2).should.eql? 4
- 9.send(@method, 0.5).should eql 3.0
- 9.send(@method, Rational(1, 2)).should eql 3.0
+ 9.send(@method, 0.5).should.eql? 3.0
+ 9.send(@method, Rational(1, 2)).should.eql? 3.0
5.send(@method, -1).to_f.to_s.should == '0.2'
- 2.send(@method, 40).should eql 1099511627776
+ 2.send(@method, 40).should.eql? 1099511627776
end
it "overflows the answer to a bignum transparently" do
- 2.send(@method, 29).should eql 536870912
- 2.send(@method, 30).should eql 1073741824
- 2.send(@method, 31).should eql 2147483648
- 2.send(@method, 32).should eql 4294967296
+ 2.send(@method, 29).should.eql? 536870912
+ 2.send(@method, 30).should.eql? 1073741824
+ 2.send(@method, 31).should.eql? 2147483648
+ 2.send(@method, 32).should.eql? 4294967296
- 2.send(@method, 61).should eql 2305843009213693952
- 2.send(@method, 62).should eql 4611686018427387904
- 2.send(@method, 63).should eql 9223372036854775808
- 2.send(@method, 64).should eql 18446744073709551616
- 8.send(@method, 23).should eql 590295810358705651712
+ 2.send(@method, 61).should.eql? 2305843009213693952
+ 2.send(@method, 62).should.eql? 4611686018427387904
+ 2.send(@method, 63).should.eql? 9223372036854775808
+ 2.send(@method, 64).should.eql? 18446744073709551616
+ 8.send(@method, 23).should.eql? 590295810358705651712
end
it "raises negative numbers to the given power" do
- (-2).send(@method, 29).should eql(-536870912)
- (-2).send(@method, 30).should eql(1073741824)
- (-2).send(@method, 31).should eql(-2147483648)
- (-2).send(@method, 32).should eql(4294967296)
- (-2).send(@method, 33).should eql(-8589934592)
+ (-2).send(@method, 29).should.eql?(-536870912)
+ (-2).send(@method, 30).should.eql?(1073741824)
+ (-2).send(@method, 31).should.eql?(-2147483648)
+ (-2).send(@method, 32).should.eql?(4294967296)
+ (-2).send(@method, 33).should.eql?(-8589934592)
- (-2).send(@method, 61).should eql(-2305843009213693952)
- (-2).send(@method, 62).should eql(4611686018427387904)
- (-2).send(@method, 63).should eql(-9223372036854775808)
- (-2).send(@method, 64).should eql(18446744073709551616)
- (-2).send(@method, 65).should eql(-36893488147419103232)
+ (-2).send(@method, 61).should.eql?(-2305843009213693952)
+ (-2).send(@method, 62).should.eql?(4611686018427387904)
+ (-2).send(@method, 63).should.eql?(-9223372036854775808)
+ (-2).send(@method, 64).should.eql?(18446744073709551616)
+ (-2).send(@method, 65).should.eql?(-36893488147419103232)
end
it "can raise 1 to a bignum safely" do
- 1.send(@method, 4611686018427387904).should eql 1
+ 1.send(@method, 4611686018427387904).should.eql? 1
end
it "can raise -1 to a bignum safely" do
- (-1).send(@method, 4611686018427387904).should eql(1)
- (-1).send(@method, 4611686018427387905).should eql(-1)
+ (-1).send(@method, 4611686018427387904).should.eql?(1)
+ (-1).send(@method, 4611686018427387905).should.eql?(-1)
end
ruby_version_is ""..."3.4" do
@@ -57,14 +57,22 @@ describe :integer_exponent, shared: true do
end
ruby_version_is "3.4" do
- it "raises an ArgumentError when the number is too big" do
- -> { 100000000.send(@method, 1000000000) }.should raise_error(ArgumentError)
+ it "returns an Integer for results larger than the old 32MB limit" do
+ # 2 ** 40000000 requires 40000001 bits
+ # This exceeds the old 32MB limit but is within the new 16GB limit
+ result = 2.send(@method, 40000000)
+ result.should.is_a?(Integer)
+ result.bit_length.should == 40000001
+ end
+
+ it "raises an ArgumentError when the result size exceeds the limit" do
+ -> { 100000000.send(@method, 1000000000) }.should.raise(ArgumentError)
end
end
it "raises a ZeroDivisionError for 0 ** -1" do
- -> { 0.send(@method, -1) }.should raise_error(ZeroDivisionError)
- -> { 0.send(@method, Rational(-1, 1)) }.should raise_error(ZeroDivisionError)
+ -> { 0.send(@method, -1) }.should.raise(ZeroDivisionError)
+ -> { 0.send(@method, Rational(-1, 1)) }.should.raise(ZeroDivisionError)
end
it "returns Float::INFINITY for 0 ** -1.0" do
@@ -72,9 +80,9 @@ describe :integer_exponent, shared: true do
end
it "raises a TypeError when given a non-numeric power" do
- -> { 13.send(@method, "10") }.should raise_error(TypeError)
- -> { 13.send(@method, :symbol) }.should raise_error(TypeError)
- -> { 13.send(@method, nil) }.should raise_error(TypeError)
+ -> { 13.send(@method, "10") }.should.raise(TypeError)
+ -> { 13.send(@method, :symbol) }.should.raise(TypeError)
+ -> { 13.send(@method, nil) }.should.raise(TypeError)
end
it "coerces power and calls #**" do
@@ -111,9 +119,9 @@ describe :integer_exponent, shared: true do
end
it "raises a TypeError when given a non-Integer" do
- -> { @bignum.send(@method, mock('10')) }.should raise_error(TypeError)
- -> { @bignum.send(@method, "10") }.should raise_error(TypeError)
- -> { @bignum.send(@method, :symbol) }.should raise_error(TypeError)
+ -> { @bignum.send(@method, mock('10')) }.should.raise(TypeError)
+ -> { @bignum.send(@method, "10") }.should.raise(TypeError)
+ -> { @bignum.send(@method, :symbol) }.should.raise(TypeError)
end
ruby_version_is ""..."3.4" do
@@ -122,16 +130,26 @@ describe :integer_exponent, shared: true do
-> {
flt = @bignum.send(@method, @bignum)
}.should complain(/warning: in a\*\*b, b may be too big/)
- flt.should be_kind_of(Float)
+ flt.should.is_a?(Float)
flt.infinite?.should == 1
end
end
ruby_version_is "3.4" do
- it "does not switch to a Float when the values is too big" do
+ it "returns an Integer for large Bignum results exceeding the old limit" do
+ # (2 ** 70) ** 500000 requires 35000001 bits
+ # This exceeds the old 32MB limit but is within the new 16GB limit
+ bignum_base = 2 ** 70
+ result = bignum_base.send(@method, 500000)
+ result.should.is_a?(Integer)
+ result.bit_length.should == 35000001
+ end
+
+ it "raises an ArgumentError when Bignum result exceeds the limit" do
+ # @bignum ** @bignum would require enormous memory
-> {
@bignum.send(@method, @bignum)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
end
diff --git a/spec/ruby/core/integer/shared/integer_ceil_precision.rb b/spec/ruby/core/integer/shared/integer_ceil_precision.rb
index 9f31c2cf61..b23c17937f 100644
--- a/spec/ruby/core/integer/shared/integer_ceil_precision.rb
+++ b/spec/ruby/core/integer/shared/integer_ceil_precision.rb
@@ -1,6 +1,6 @@
describe :integer_ceil_precision, shared: true do
context "precision is zero" do
- it "returns integer self" do
+ it "returns Integer equal to self" do
send(@method, 0).ceil(0).should.eql?(0)
send(@method, 123).ceil(0).should.eql?(123)
send(@method, -123).ceil(0).should.eql?(-123)
@@ -23,7 +23,16 @@ describe :integer_ceil_precision, shared: true do
send(@method, 0).ceil(-10).should.eql?(0)
end
- it "returns largest integer less than self with at least precision.abs trailing zeros" do
+ it "returns Integer equal to self if there are already at least precision.abs trailing zeros" do
+ send(@method, 10).ceil(-1).should.eql?(10)
+ send(@method, 100).ceil(-1).should.eql?(100)
+ send(@method, 100).ceil(-2).should.eql?(100)
+ send(@method, -10).ceil(-1).should.eql?(-10)
+ send(@method, -100).ceil(-1).should.eql?(-100)
+ send(@method, -100).ceil(-2).should.eql?(-100)
+ end
+
+ it "returns smallest Integer greater than self with at least precision.abs trailing zeros" do
send(@method, 123).ceil(-1).should.eql?(130)
send(@method, 123).ceil(-2).should.eql?(200)
send(@method, 123).ceil(-3).should.eql?(1000)
@@ -31,13 +40,15 @@ describe :integer_ceil_precision, shared: true do
send(@method, -123).ceil(-1).should.eql?(-120)
send(@method, -123).ceil(-2).should.eql?(-100)
send(@method, -123).ceil(-3).should.eql?(0)
+
+ send(@method, 100).ceil(-3).should.eql?(1000)
+ send(@method, -100).ceil(-3).should.eql?(0)
end
- ruby_bug "#20654", ""..."3.4" do
- it "returns 10**precision.abs when precision.abs is larger than the number digits of self" do
- send(@method, 123).ceil(-20).should.eql?(100000000000000000000)
- send(@method, 123).ceil(-50).should.eql?(100000000000000000000000000000000000000000000000000)
- end
+ # Bug #20654
+ it "returns 10**precision.abs when precision.abs has more digits than self" do
+ send(@method, 123).ceil(-20).should.eql?(100000000000000000000)
+ send(@method, 123).ceil(-50).should.eql?(100000000000000000000000000000000000000000000000000)
end
end
end
diff --git a/spec/ruby/core/integer/shared/integer_floor_precision.rb b/spec/ruby/core/integer/shared/integer_floor_precision.rb
index 4c5888c6c4..6247907d4c 100644
--- a/spec/ruby/core/integer/shared/integer_floor_precision.rb
+++ b/spec/ruby/core/integer/shared/integer_floor_precision.rb
@@ -33,11 +33,10 @@ describe :integer_floor_precision, shared: true do
send(@method, -123).floor(-3).should.eql?(-1000)
end
- ruby_bug "#20654", ""..."3.4" do
- it "returns -(10**precision.abs) when self is negative and precision.abs is larger than the number digits of self" do
- send(@method, -123).floor(-20).should.eql?(-100000000000000000000)
- send(@method, -123).floor(-50).should.eql?(-100000000000000000000000000000000000000000000000000)
- end
+ # Bug #20654
+ it "returns -(10**precision.abs) when self is negative and precision.abs is larger than the number digits of self" do
+ send(@method, -123).floor(-20).should.eql?(-100000000000000000000)
+ send(@method, -123).floor(-50).should.eql?(-100000000000000000000000000000000000000000000000000)
end
end
end
diff --git a/spec/ruby/core/integer/shared/integer_rounding.rb b/spec/ruby/core/integer/shared/integer_rounding.rb
index 56d1819f84..92f2a2327c 100644
--- a/spec/ruby/core/integer/shared/integer_rounding.rb
+++ b/spec/ruby/core/integer/shared/integer_rounding.rb
@@ -1,19 +1,19 @@
describe :integer_rounding_positive_precision, shared: true do
it "returns self if not passed a precision" do
[2, -4, 10**70, -10**100].each do |v|
- v.send(@method).should eql(v)
+ v.send(@method).should.eql?(v)
end
end
it "returns self if passed a precision of zero" do
[2, -4, 10**70, -10**100].each do |v|
- v.send(@method, 0).should eql(v)
+ v.send(@method, 0).should.eql?(v)
end
end
it "returns itself if passed a positive precision" do
[2, -4, 10**70, -10**100].each do |v|
- v.send(@method, 42).should eql(v)
+ v.send(@method, 42).should.eql?(v)
end
end
end
diff --git a/spec/ruby/core/integer/shared/modulo.rb b/spec/ruby/core/integer/shared/modulo.rb
deleted file mode 100644
index f678a10806..0000000000
--- a/spec/ruby/core/integer/shared/modulo.rb
+++ /dev/null
@@ -1,74 +0,0 @@
-describe :integer_modulo, shared: true do
- context "fixnum" do
- it "returns the modulus obtained from dividing self by the given argument" do
- 13.send(@method, 4).should == 1
- 4.send(@method, 13).should == 4
-
- 13.send(@method, 4.0).should == 1
- 4.send(@method, 13.0).should == 4
-
- (-200).send(@method, 256).should == 56
- (-1000).send(@method, 512).should == 24
-
- (-200).send(@method, -256).should == -200
- (-1000).send(@method, -512).should == -488
-
- (200).send(@method, -256).should == -56
- (1000).send(@method, -512).should == -24
-
- 1.send(@method, 2.0).should == 1.0
- 200.send(@method, bignum_value).should == 200
- end
-
- it "raises a ZeroDivisionError when the given argument is 0" do
- -> { 13.send(@method, 0) }.should raise_error(ZeroDivisionError)
- -> { 0.send(@method, 0) }.should raise_error(ZeroDivisionError)
- -> { -10.send(@method, 0) }.should raise_error(ZeroDivisionError)
- end
-
- it "raises a ZeroDivisionError when the given argument is 0 and a Float" do
- -> { 0.send(@method, 0.0) }.should raise_error(ZeroDivisionError)
- -> { 10.send(@method, 0.0) }.should raise_error(ZeroDivisionError)
- -> { -10.send(@method, 0.0) }.should raise_error(ZeroDivisionError)
- end
-
- it "raises a TypeError when given a non-Integer" do
- -> {
- (obj = mock('10')).should_receive(:to_int).any_number_of_times.and_return(10)
- 13.send(@method, obj)
- }.should raise_error(TypeError)
- -> { 13.send(@method, "10") }.should raise_error(TypeError)
- -> { 13.send(@method, :symbol) }.should raise_error(TypeError)
- end
- end
-
- context "bignum" do
- before :each do
- @bignum = bignum_value
- end
-
- it "returns the modulus obtained from dividing self by the given argument" do
- @bignum.send(@method, 5).should == 1
- @bignum.send(@method, -5).should == -4
- @bignum.send(@method, -100).should == -84
- @bignum.send(@method, 2.22).should be_close(1.5603603603605034, TOLERANCE)
- @bignum.send(@method, bignum_value(10)).should == 18446744073709551616
- end
-
- it "raises a ZeroDivisionError when the given argument is 0" do
- -> { @bignum.send(@method, 0) }.should raise_error(ZeroDivisionError)
- -> { (-@bignum).send(@method, 0) }.should raise_error(ZeroDivisionError)
- end
-
- it "raises a ZeroDivisionError when the given argument is 0 and a Float" do
- -> { @bignum.send(@method, 0.0) }.should raise_error(ZeroDivisionError)
- -> { -@bignum.send(@method, 0.0) }.should raise_error(ZeroDivisionError)
- end
-
- it "raises a TypeError when given a non-Integer" do
- -> { @bignum.send(@method, mock('10')) }.should raise_error(TypeError)
- -> { @bignum.send(@method, "10") }.should raise_error(TypeError)
- -> { @bignum.send(@method, :symbol) }.should raise_error(TypeError)
- end
- end
-end
diff --git a/spec/ruby/core/integer/shared/next.rb b/spec/ruby/core/integer/shared/next.rb
deleted file mode 100644
index 85b83d6965..0000000000
--- a/spec/ruby/core/integer/shared/next.rb
+++ /dev/null
@@ -1,25 +0,0 @@
-describe :integer_next, shared: true do
- it "returns the next larger positive Fixnum" do
- 2.send(@method).should == 3
- end
-
- it "returns the next larger negative Fixnum" do
- (-2).send(@method).should == -1
- end
-
- it "returns the next larger positive Bignum" do
- bignum_value.send(@method).should == bignum_value(1)
- end
-
- it "returns the next larger negative Bignum" do
- (-bignum_value(1)).send(@method).should == -bignum_value
- end
-
- it "overflows a Fixnum to a Bignum" do
- fixnum_max.send(@method).should == fixnum_max + 1
- end
-
- it "underflows a Bignum to a Fixnum" do
- (fixnum_min - 1).send(@method).should == fixnum_min
- end
-end
diff --git a/spec/ruby/core/integer/shared/to_i.rb b/spec/ruby/core/integer/shared/to_i.rb
index 7b974cd3a7..2b6a50484a 100644
--- a/spec/ruby/core/integer/shared/to_i.rb
+++ b/spec/ruby/core/integer/shared/to_i.rb
@@ -1,8 +1,8 @@
describe :integer_to_i, shared: true do
it "returns self" do
- 10.send(@method).should eql(10)
- (-15).send(@method).should eql(-15)
- bignum_value.send(@method).should eql(bignum_value)
- (-bignum_value).send(@method).should eql(-bignum_value)
+ 10.send(@method).should.eql?(10)
+ (-15).send(@method).should.eql?(-15)
+ bignum_value.send(@method).should.eql?(bignum_value)
+ (-bignum_value).send(@method).should.eql?(-bignum_value)
end
end
diff --git a/spec/ruby/core/integer/sqrt_spec.rb b/spec/ruby/core/integer/sqrt_spec.rb
index 4149ca2cc9..bf90ea747e 100644
--- a/spec/ruby/core/integer/sqrt_spec.rb
+++ b/spec/ruby/core/integer/sqrt_spec.rb
@@ -2,7 +2,7 @@ require_relative '../../spec_helper'
describe "Integer.sqrt" do
it "returns an integer" do
- Integer.sqrt(10).should be_kind_of(Integer)
+ Integer.sqrt(10).should.is_a?(Integer)
end
it "returns the integer square root of the argument" do
@@ -14,7 +14,7 @@ describe "Integer.sqrt" do
end
it "raises a Math::DomainError if the argument is negative" do
- -> { Integer.sqrt(-4) }.should raise_error(Math::DomainError)
+ -> { Integer.sqrt(-4) }.should.raise(Math::DomainError)
end
it "accepts any argument that can be coerced to Integer" do
@@ -26,6 +26,6 @@ describe "Integer.sqrt" do
end
it "raises a TypeError if the argument cannot be coerced to Integer" do
- -> { Integer.sqrt("test") }.should raise_error(TypeError)
+ -> { Integer.sqrt("test") }.should.raise(TypeError)
end
end
diff --git a/spec/ruby/core/integer/succ_spec.rb b/spec/ruby/core/integer/succ_spec.rb
index 9ae9a14fe7..2201a4c76d 100644
--- a/spec/ruby/core/integer/succ_spec.rb
+++ b/spec/ruby/core/integer/succ_spec.rb
@@ -1,6 +1,27 @@
require_relative '../../spec_helper'
-require_relative 'shared/next'
describe "Integer#succ" do
- it_behaves_like :integer_next, :succ
+ it "returns the next larger positive Fixnum" do
+ 2.succ.should == 3
+ end
+
+ it "returns the next larger negative Fixnum" do
+ (-2).succ.should == -1
+ end
+
+ it "returns the next larger positive Bignum" do
+ bignum_value.succ.should == bignum_value(1)
+ end
+
+ it "returns the next larger negative Bignum" do
+ (-bignum_value(1)).succ.should == -bignum_value
+ end
+
+ it "overflows a Fixnum to a Bignum" do
+ fixnum_max.succ.should == fixnum_max + 1
+ end
+
+ it "underflows a Bignum to a Fixnum" do
+ (fixnum_min - 1).succ.should == fixnum_min
+ end
end
diff --git a/spec/ruby/core/integer/to_f_spec.rb b/spec/ruby/core/integer/to_f_spec.rb
index 9f1df9ada9..0681236095 100644
--- a/spec/ruby/core/integer/to_f_spec.rb
+++ b/spec/ruby/core/integer/to_f_spec.rb
@@ -11,9 +11,9 @@ describe "Integer#to_f" do
context "bignum" do
it "returns self converted to a Float" do
- bignum_value(0x4000_0aa0_0bb0_0000).to_f.should eql(23_058_441_774_644_068_352.0)
- bignum_value(0x8000_0000_0000_0ccc).to_f.should eql(27_670_116_110_564_330_700.0)
- (-bignum_value(99)).to_f.should eql(-18_446_744_073_709_551_715.0)
+ bignum_value(0x4000_0aa0_0bb0_0000).to_f.should.eql?(23_058_441_774_644_068_352.0)
+ bignum_value(0x8000_0000_0000_0ccc).to_f.should.eql?(27_670_116_110_564_330_700.0)
+ (-bignum_value(99)).to_f.should.eql?(-18_446_744_073_709_551_715.0)
end
it "converts number close to Float::MAX without exceeding MAX or producing NaN" do
diff --git a/spec/ruby/core/integer/to_r_spec.rb b/spec/ruby/core/integer/to_r_spec.rb
index 7732bedca1..2649c7c78d 100644
--- a/spec/ruby/core/integer/to_r_spec.rb
+++ b/spec/ruby/core/integer/to_r_spec.rb
@@ -2,7 +2,7 @@ require_relative '../../spec_helper'
describe "Integer#to_r" do
it "returns a Rational object" do
- 309.to_r.should be_an_instance_of(Rational)
+ 309.to_r.should.instance_of?(Rational)
end
it "constructs a rational number with self as the numerator" do
@@ -15,12 +15,12 @@ describe "Integer#to_r" do
it "works even if self is a Bignum" do
bignum = 99999**999
- bignum.should be_an_instance_of(Integer)
+ bignum.should.instance_of?(Integer)
bignum.to_r.should == Rational(bignum, 1)
end
it "raises an ArgumentError if given any arguments" do
- -> { 287.to_r(2) }.should raise_error(ArgumentError)
- -> { 9102826.to_r(309, [], 71) }.should raise_error(ArgumentError)
+ -> { 287.to_r(2) }.should.raise(ArgumentError)
+ -> { 9102826.to_r(309, [], 71) }.should.raise(ArgumentError)
end
end
diff --git a/spec/ruby/core/integer/to_s_spec.rb b/spec/ruby/core/integer/to_s_spec.rb
index ca08dad95c..4970a2a12f 100644
--- a/spec/ruby/core/integer/to_s_spec.rb
+++ b/spec/ruby/core/integer/to_s_spec.rb
@@ -13,10 +13,10 @@ describe "Integer#to_s" do
end
it "raises an ArgumentError if the base is less than 2 or higher than 36" do
- -> { 123.to_s(-1) }.should raise_error(ArgumentError)
- -> { 123.to_s(0) }.should raise_error(ArgumentError)
- -> { 123.to_s(1) }.should raise_error(ArgumentError)
- -> { 123.to_s(37) }.should raise_error(ArgumentError)
+ -> { 123.to_s(-1) }.should.raise(ArgumentError)
+ -> { 123.to_s(0) }.should.raise(ArgumentError)
+ -> { 123.to_s(1) }.should.raise(ArgumentError)
+ -> { 123.to_s(37) }.should.raise(ArgumentError)
end
end
@@ -39,12 +39,12 @@ describe "Integer#to_s" do
it "returns a String in US-ASCII encoding when Encoding.default_internal is nil" do
Encoding.default_internal = nil
- 1.to_s.encoding.should equal(Encoding::US_ASCII)
+ 1.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
- 1.to_s.encoding.should equal(Encoding::US_ASCII)
+ 1.to_s.encoding.should.equal?(Encoding::US_ASCII)
end
end
@@ -59,10 +59,10 @@ describe "Integer#to_s" do
end
it "raises an ArgumentError if the base is less than 2 or higher than 36" do
- -> { 123.to_s(-1) }.should raise_error(ArgumentError)
- -> { 123.to_s(0) }.should raise_error(ArgumentError)
- -> { 123.to_s(1) }.should raise_error(ArgumentError)
- -> { 123.to_s(37) }.should raise_error(ArgumentError)
+ -> { 123.to_s(-1) }.should.raise(ArgumentError)
+ -> { 123.to_s(0) }.should.raise(ArgumentError)
+ -> { 123.to_s(1) }.should.raise(ArgumentError)
+ -> { 123.to_s(37) }.should.raise(ArgumentError)
end
end
@@ -84,12 +84,12 @@ describe "Integer#to_s" do
it "returns a String in US-ASCII encoding when Encoding.default_internal is nil" do
Encoding.default_internal = nil
- bignum_value.to_s.encoding.should equal(Encoding::US_ASCII)
+ bignum_value.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
- bignum_value.to_s.encoding.should equal(Encoding::US_ASCII)
+ bignum_value.to_s.encoding.should.equal?(Encoding::US_ASCII)
end
end
end
diff --git a/spec/ruby/core/integer/truncate_spec.rb b/spec/ruby/core/integer/truncate_spec.rb
index db16e74be4..b95c183cf3 100644
--- a/spec/ruby/core/integer/truncate_spec.rb
+++ b/spec/ruby/core/integer/truncate_spec.rb
@@ -8,12 +8,12 @@ describe "Integer#truncate" do
context "precision argument specified as part of the truncate method is negative" do
it "returns an integer with at least precision.abs trailing zeros" do
- 1832.truncate(-1).should eql(1830)
- 1832.truncate(-2).should eql(1800)
- 1832.truncate(-3).should eql(1000)
- -1832.truncate(-1).should eql(-1830)
- -1832.truncate(-2).should eql(-1800)
- -1832.truncate(-3).should eql(-1000)
+ 1832.truncate(-1).should.eql?(1830)
+ 1832.truncate(-2).should.eql?(1800)
+ 1832.truncate(-3).should.eql?(1000)
+ -1832.truncate(-1).should.eql?(-1830)
+ -1832.truncate(-2).should.eql?(-1800)
+ -1832.truncate(-3).should.eql?(-1000)
end
end
end
diff --git a/spec/ruby/core/integer/try_convert_spec.rb b/spec/ruby/core/integer/try_convert_spec.rb
index 8a0ca671a9..8c9b4276b9 100644
--- a/spec/ruby/core/integer/try_convert_spec.rb
+++ b/spec/ruby/core/integer/try_convert_spec.rb
@@ -4,24 +4,24 @@ require_relative 'fixtures/classes'
describe "Integer.try_convert" do
it "returns the argument if it's an Integer" do
x = 42
- Integer.try_convert(x).should equal(x)
+ Integer.try_convert(x).should.equal?(x)
end
it "returns nil when the argument does not respond to #to_int" do
- Integer.try_convert(Object.new).should be_nil
+ Integer.try_convert(Object.new).should == nil
end
it "sends #to_int to the argument and returns the result if it's nil" do
obj = mock("to_int")
obj.should_receive(:to_int).and_return(nil)
- Integer.try_convert(obj).should be_nil
+ Integer.try_convert(obj).should == nil
end
it "sends #to_int to the argument and returns the result if it's an Integer" do
x = 234
obj = mock("to_int")
obj.should_receive(:to_int).and_return(x)
- Integer.try_convert(obj).should equal(x)
+ Integer.try_convert(obj).should.equal?(x)
end
it "sends #to_int to the argument and raises TypeError if it's not a kind of Integer" do
@@ -29,7 +29,7 @@ describe "Integer.try_convert" do
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)")
+ }.should raise_consistent_error(TypeError, "can't convert MockObject into 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
@@ -37,12 +37,12 @@ describe "Integer.try_convert" do
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)")
+ }.should raise_consistent_error(TypeError, "can't convert MockObject into Integer (MockObject#to_int gives String)")
end
it "does not rescue exceptions raised by #to_int" do
obj = mock("to_int")
obj.should_receive(:to_int).and_raise(RuntimeError)
- -> { Integer.try_convert obj }.should raise_error(RuntimeError)
+ -> { Integer.try_convert obj }.should.raise(RuntimeError)
end
end
diff --git a/spec/ruby/core/integer/upto_spec.rb b/spec/ruby/core/integer/upto_spec.rb
index dd6995e94b..ba63dcc9ea 100644
--- a/spec/ruby/core/integer/upto_spec.rb
+++ b/spec/ruby/core/integer/upto_spec.rb
@@ -27,8 +27,8 @@ describe "Integer#upto [stop] when self and stop are Integers" do
end
it "raises an ArgumentError for non-numeric endpoints" do
- -> { 1.upto("A") {|x| p x} }.should raise_error(ArgumentError)
- -> { 1.upto(nil) {|x| p x} }.should raise_error(ArgumentError)
+ -> { 1.upto("A") {|x| p x} }.should.raise(ArgumentError)
+ -> { 1.upto(nil) {|x| p x} }.should.raise(ArgumentError)
end
describe "when no block is given" do
@@ -45,9 +45,9 @@ describe "Integer#upto [stop] when self and stop are Integers" do
describe "size" do
it "raises an ArgumentError for non-numeric endpoints" do
enum = 1.upto("A")
- -> { enum.size }.should raise_error(ArgumentError)
+ -> { enum.size }.should.raise(ArgumentError)
enum = 1.upto(nil)
- -> { enum.size }.should raise_error(ArgumentError)
+ -> { enum.size }.should.raise(ArgumentError)
end
it "returns stop - self + 1" do
diff --git a/spec/ruby/core/io/advise_spec.rb b/spec/ruby/core/io/advise_spec.rb
index 651fc52378..b77ed53ad4 100644
--- a/spec/ruby/core/io/advise_spec.rb
+++ b/spec/ruby/core/io/advise_spec.rb
@@ -14,73 +14,73 @@ describe "IO#advise" do
it "raises a TypeError if advise is not a Symbol" do
-> {
@io.advise("normal")
- }.should raise_error(TypeError)
+ }.should.raise(TypeError)
end
it "raises a TypeError if offset cannot be coerced to an Integer" do
-> {
@io.advise(:normal, "wat")
- }.should raise_error(TypeError)
+ }.should.raise(TypeError)
end
it "raises a TypeError if len cannot be coerced to an Integer" do
-> {
@io.advise(:normal, 0, "wat")
- }.should raise_error(TypeError)
+ }.should.raise(TypeError)
end
it "raises a RangeError if offset is too big" do
-> {
@io.advise(:normal, 10 ** 32)
- }.should raise_error(RangeError)
+ }.should.raise(RangeError)
end
it "raises a RangeError if len is too big" do
-> {
@io.advise(:normal, 0, 10 ** 32)
- }.should raise_error(RangeError)
+ }.should.raise(RangeError)
end
it "raises a NotImplementedError if advise is not recognized" do
->{
@io.advise(:foo)
- }.should raise_error(NotImplementedError)
+ }.should.raise(NotImplementedError)
end
it "supports the normal advice type" do
- @io.advise(:normal).should be_nil
+ @io.advise(:normal).should == nil
end
it "supports the sequential advice type" do
- @io.advise(:sequential).should be_nil
+ @io.advise(:sequential).should == nil
end
it "supports the random advice type" do
- @io.advise(:random).should be_nil
+ @io.advise(:random).should == nil
end
it "supports the dontneed advice type" do
- @io.advise(:dontneed).should be_nil
+ @io.advise(:dontneed).should == nil
end
it "supports the noreuse advice type" do
- @io.advise(:noreuse).should be_nil
+ @io.advise(:noreuse).should == nil
end
platform_is_not :linux do
it "supports the willneed advice type" do
- @io.advise(:willneed).should be_nil
+ @io.advise(:willneed).should == nil
end
end
guard -> { platform_is :linux and kernel_version_is '3.6' } do # [ruby-core:65355] tmpfs is not supported
it "supports the willneed advice type" do
- @io.advise(:willneed).should be_nil
+ @io.advise(:willneed).should == nil
end
end
it "raises an IOError if the stream is closed" do
@io.close
- -> { @io.advise(:normal) }.should raise_error(IOError)
+ -> { @io.advise(:normal) }.should.raise(IOError)
end
end
diff --git a/spec/ruby/core/io/autoclose_spec.rb b/spec/ruby/core/io/autoclose_spec.rb
index 715ada7c93..596f3d6934 100644
--- a/spec/ruby/core/io/autoclose_spec.rb
+++ b/spec/ruby/core/io/autoclose_spec.rb
@@ -17,7 +17,7 @@ describe "IO#autoclose?" do
it "cannot be queried on a closed IO object" do
@io.close
- -> { @io.autoclose? }.should raise_error(IOError, /closed stream/)
+ -> { @io.autoclose? }.should.raise(IOError, /closed stream/)
end
end
@@ -72,6 +72,6 @@ describe "IO#autoclose=" do
it "cannot be set on a closed IO object" do
@io.close
- -> { @io.autoclose = false }.should raise_error(IOError, /closed stream/)
+ -> { @io.autoclose = false }.should.raise(IOError, /closed stream/)
end
end
diff --git a/spec/ruby/core/io/binmode_spec.rb b/spec/ruby/core/io/binmode_spec.rb
index 342cac2a9b..8117229c91 100644
--- a/spec/ruby/core/io/binmode_spec.rb
+++ b/spec/ruby/core/io/binmode_spec.rb
@@ -13,11 +13,11 @@ describe "IO#binmode" do
it "returns self" do
@io = new_io(@name)
- @io.binmode.should equal(@io)
+ @io.binmode.should.equal?(@io)
end
it "raises an IOError on closed stream" do
- -> { IOSpecs.closed_io.binmode }.should raise_error(IOError)
+ -> { IOSpecs.closed_io.binmode }.should.raise(IOError)
end
it "sets external encoding to binary" do
@@ -47,9 +47,9 @@ describe "IO#binmode?" do
end
it "is true after a call to IO#binmode" do
- @file.binmode?.should be_false
+ @file.binmode?.should == false
@file.binmode
- @file.binmode?.should be_true
+ @file.binmode?.should == true
end
it "propagates to dup'ed IO objects" do
@@ -59,6 +59,6 @@ describe "IO#binmode?" do
end
it "raises an IOError on closed stream" do
- -> { IOSpecs.closed_io.binmode? }.should raise_error(IOError)
+ -> { IOSpecs.closed_io.binmode? }.should.raise(IOError)
end
end
diff --git a/spec/ruby/core/io/binread_spec.rb b/spec/ruby/core/io/binread_spec.rb
index 418e89213b..3023c7f177 100644
--- a/spec/ruby/core/io/binread_spec.rb
+++ b/spec/ruby/core/io/binread_spec.rb
@@ -38,14 +38,14 @@ describe "IO.binread" do
end
it "raises an ArgumentError when not passed a valid length" do
- -> { IO.binread @fname, -1 }.should raise_error(ArgumentError)
+ -> { IO.binread @fname, -1 }.should.raise(ArgumentError)
end
it "raises an Errno::EINVAL when not passed a valid offset" do
- -> { IO.binread @fname, 0, -1 }.should raise_error(Errno::EINVAL)
+ -> { IO.binread @fname, 0, -1 }.should.raise(Errno::EINVAL)
end
- ruby_version_is "3.3" do
+ ruby_version_is ""..."4.0" do
# https://bugs.ruby-lang.org/issues/19630
it "warns about deprecation given a path with a pipe" do
cmd = "|echo ok"
diff --git a/spec/ruby/core/io/buffer/and_spec.rb b/spec/ruby/core/io/buffer/and_spec.rb
new file mode 100644
index 0000000000..3cea163b0e
--- /dev/null
+++ b/spec/ruby/core/io/buffer/and_spec.rb
@@ -0,0 +1,62 @@
+require_relative '../../../spec_helper'
+
+describe :io_buffer_and, shared: true do
+ it "applies the argument buffer as an AND bit mask across the whole buffer" do
+ IO::Buffer.for(+"12345") do |buffer|
+ IO::Buffer.for(+"\xF8\x8F") do |mask|
+ result = buffer.send(@method, mask)
+ result.get_string.should == "\x30\x02\x30\x04\x30".b
+ result.free
+ end
+ end
+ end
+
+ it "ignores extra parts of mask if it is longer than source buffer" do
+ IO::Buffer.for(+"12345") do |buffer|
+ IO::Buffer.for(+"\xF8\x8F\x00\x00\x00\xFF\xFF") do |mask|
+ result = buffer.send(@method, mask)
+ result.get_string.should == "\x30\x02\x00\x00\x00".b
+ result.free
+ end
+ end
+ end
+
+ it "raises TypeError if mask is not an IO::Buffer" do
+ IO::Buffer.for(+"12345") do |buffer|
+ -> { buffer.send(@method, "\xF8\x8F") }.should.raise(TypeError, "wrong argument type String (expected IO::Buffer)")
+ -> { buffer.send(@method, 0xF8) }.should.raise(TypeError, "wrong argument type Integer (expected IO::Buffer)")
+ -> { buffer.send(@method, nil) }.should.raise(TypeError, "wrong argument type nil (expected IO::Buffer)")
+ end
+ end
+end
+
+describe "IO::Buffer#&" do
+ it_behaves_like :io_buffer_and, :&
+
+ it "creates a new internal buffer of the same size" do
+ IO::Buffer.for(+"12345") do |buffer|
+ IO::Buffer.for(+"\xF8\x8F") do |mask|
+ result = buffer & mask
+ result.should_not.equal? buffer
+ result.should.internal?
+ result.size.should == buffer.size
+ result.free
+ buffer.get_string.should == "12345".b
+ end
+ end
+ end
+end
+
+describe "IO::Buffer#and!" do
+ it_behaves_like :io_buffer_and, :and!
+
+ it "modifies the buffer in place" do
+ IO::Buffer.for(+"12345") do |buffer|
+ IO::Buffer.for(+"\xF8\x8F") do |mask|
+ result = buffer.and!(mask)
+ result.should.equal? buffer
+ result.should.external?
+ end
+ end
+ end
+end
diff --git a/spec/ruby/core/io/buffer/bit_count_spec.rb b/spec/ruby/core/io/buffer/bit_count_spec.rb
new file mode 100644
index 0000000000..62f56f5b98
--- /dev/null
+++ b/spec/ruby/core/io/buffer/bit_count_spec.rb
@@ -0,0 +1,64 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is "4.1" do
+ describe "IO::Buffer#bit_count" do
+ it "counts all set bits in the whole buffer" do
+ IO::Buffer.for(+"\xFF\x00\x0F") do |buffer|
+ buffer.bit_count.should == 12
+ end
+ end
+
+ it "returns 0 for a buffer of all zero bytes" do
+ IO::Buffer.for(+"\x00\x00\x00") do |buffer|
+ buffer.bit_count.should == 0
+ end
+ end
+
+ it "returns 8 * size for a buffer of all 0xFF bytes" do
+ IO::Buffer.for(+"\xFF" * 9) do |buffer|
+ buffer.bit_count.should == 72
+ end
+ end
+
+ it "returns 0 for an empty buffer" do
+ IO::Buffer.new(0).bit_count.should == 0
+ end
+
+ it "accepts an offset to start counting from (length defaults to remaining bytes)" do
+ IO::Buffer.for(+"\xFF\x00\x0F") do |buffer|
+ buffer.bit_count(0).should == 12 # offset=0 => entire buffer
+ buffer.bit_count(1).should == 4 # offset=1 => 0x00 + 0x0F
+ buffer.bit_count(2).should == 4 # offset=2 => 0x0F only
+ end
+ end
+
+ it "accepts an offset and length to restrict the counted region" do
+ IO::Buffer.for(+"\xFF\x00\x0F") do |buffer|
+ buffer.bit_count(0, 1).should == 8 # just 0xFF
+ buffer.bit_count(1, 1).should == 0 # just 0x00
+ buffer.bit_count(2, 1).should == 4 # just 0x0F
+ buffer.bit_count(1, 2).should == 4 # 0x00 + 0x0F
+ end
+ end
+
+ it "handles 8-byte aligned buffers efficiently" do
+ IO::Buffer.for(+"\xAA" * 8) do |buffer|
+ # 0xAA = 10101010 => 4 bits per byte => 32 total
+ buffer.bit_count.should == 32
+ end
+ end
+
+ it "raises ArgumentError when offset + length exceeds buffer size" do
+ IO::Buffer.for(+"\xFF") do |buffer|
+ -> { buffer.bit_count(0, 2) }.should.raise(ArgumentError)
+ -> { buffer.bit_count(1, 1) }.should.raise(ArgumentError)
+ end
+ end
+
+ it "returns an Integer" do
+ IO::Buffer.for(+"\xFF") do |buffer|
+ buffer.bit_count.should.is_a?(Integer)
+ end
+ end
+ end
+end
diff --git a/spec/ruby/core/io/buffer/empty_spec.rb b/spec/ruby/core/io/buffer/empty_spec.rb
new file mode 100644
index 0000000000..4cceb4dc0d
--- /dev/null
+++ b/spec/ruby/core/io/buffer/empty_spec.rb
@@ -0,0 +1,27 @@
+require_relative '../../../spec_helper'
+require_relative 'shared/null_and_empty'
+
+describe "IO::Buffer#empty?" do
+ after :each do
+ @buffer&.free
+ @buffer = nil
+ end
+
+ it_behaves_like :io_buffer_null_and_empty, :empty?
+
+ it "is true for a 0-length String-backed buffer created with .for" do
+ @buffer = IO::Buffer.for("")
+ @buffer.empty?.should == true
+ end
+
+ it "is true for a 0-length String-backed buffer created with .string" do
+ IO::Buffer.string(0) do |buffer|
+ buffer.empty?.should == true
+ end
+ end
+
+ it "is true for a 0-length slice of a buffer with size > 0" do
+ @buffer = IO::Buffer.new(4)
+ @buffer.slice(3, 0).empty?.should == true
+ end
+end
diff --git a/spec/ruby/core/io/buffer/external_spec.rb b/spec/ruby/core/io/buffer/external_spec.rb
new file mode 100644
index 0000000000..18b2ee0d06
--- /dev/null
+++ b/spec/ruby/core/io/buffer/external_spec.rb
@@ -0,0 +1,23 @@
+require_relative '../../../spec_helper'
+
+describe "IO::Buffer#external?" do
+ after :each do
+ @buffer&.free
+ @buffer = nil
+ end
+
+ it "is true for a buffer with externally-managed memory" do
+ @buffer = IO::Buffer.for("string")
+ @buffer.external?.should == true
+ end
+
+ it "is false for a buffer with self-managed memory" do
+ @buffer = IO::Buffer.new(12, IO::Buffer::MAPPED)
+ @buffer.external?.should == false
+ end
+
+ it "is false for a null buffer" do
+ @buffer = IO::Buffer.new(0)
+ @buffer.external?.should == false
+ end
+end
diff --git a/spec/ruby/core/io/buffer/for_spec.rb b/spec/ruby/core/io/buffer/for_spec.rb
new file mode 100644
index 0000000000..4c614f74b0
--- /dev/null
+++ b/spec/ruby/core/io/buffer/for_spec.rb
@@ -0,0 +1,95 @@
+require_relative '../../../spec_helper'
+
+describe "IO::Buffer.for" do
+ before :each do
+ @string = +"för striñg"
+ end
+
+ after :each do
+ @buffer&.free
+ @buffer = nil
+ end
+
+ context "without a block" do
+ it "copies string's contents, creating a separate read-only buffer" do
+ @buffer = IO::Buffer.for(@string)
+
+ @buffer.size.should == @string.bytesize
+ @buffer.get_string.should == @string.b
+
+ @string[0] = "d"
+ @buffer.get_string(0, 1).should == "f".b
+
+ -> { @buffer.set_string("d") }.should.raise(IO::Buffer::AccessError, "Buffer is not writable!")
+ end
+
+ it "creates an external, read-only buffer" do
+ @buffer = IO::Buffer.for(@string)
+
+ @buffer.should_not.internal?
+ @buffer.should_not.mapped?
+ @buffer.should.external?
+
+ @buffer.should_not.empty?
+ @buffer.should_not.null?
+
+ @buffer.should_not.shared?
+ @buffer.should_not.private?
+ @buffer.should.readonly?
+
+ @buffer.should_not.locked?
+ @buffer.should.valid?
+ end
+ end
+
+ context "with a block" do
+ it "returns the last value in the block" do
+ value =
+ IO::Buffer.for(@string) do |buffer|
+ buffer.size * 3
+ end
+ value.should == @string.bytesize * 3
+ end
+
+ it "frees the buffer at the end of the block" do
+ IO::Buffer.for(@string) do |buffer|
+ @buffer = buffer
+ @buffer.should_not.null?
+ end
+ @buffer.should.null?
+ end
+
+ context "if string is not frozen" do
+ it "creates a modifiable string-backed buffer" do
+ IO::Buffer.for(@string) do |buffer|
+ buffer.size.should == @string.bytesize
+ buffer.get_string.should == @string.b
+
+ buffer.should_not.readonly?
+ buffer.should_not.locked?
+
+ buffer.set_string("ghost shell")
+ @string.should == "ghost shellg"
+ end
+ end
+
+ it "locks the original string to prevent modification" do
+ IO::Buffer.for(@string) do |_buffer|
+ -> { @string[0] = "t" }.should.raise(RuntimeError, "can't modify string; temporarily locked")
+ end
+ @string[1] = "u"
+ @string.should == "fur striñg"
+ end
+ end
+
+ context "if string is frozen" do
+ it "creates a read-only string-backed buffer" do
+ IO::Buffer.for(@string.freeze) do |buffer|
+ buffer.should.readonly?
+
+ -> { buffer.set_string("ghost shell") }.should.raise(IO::Buffer::AccessError, "Buffer is not writable!")
+ end
+ end
+ end
+ end
+end
diff --git a/spec/ruby/core/io/buffer/free_spec.rb b/spec/ruby/core/io/buffer/free_spec.rb
new file mode 100644
index 0000000000..20fb7b901f
--- /dev/null
+++ b/spec/ruby/core/io/buffer/free_spec.rb
@@ -0,0 +1,102 @@
+require_relative '../../../spec_helper'
+
+describe "IO::Buffer#free" do
+ context "with a buffer created with .new" do
+ it "frees internal memory and nullifies the buffer" do
+ buffer = IO::Buffer.new(4)
+ buffer.free
+ buffer.null?.should == true
+ end
+
+ it "frees mapped memory and nullifies the buffer" do
+ buffer = IO::Buffer.new(4, IO::Buffer::MAPPED)
+ buffer.free
+ buffer.null?.should == true
+ end
+ end
+
+ context "with a file-backed buffer created with .map" do
+ it "frees mapped memory and nullifies the buffer" do
+ File.open(__FILE__, "r") do |file|
+ buffer = IO::Buffer.map(file, nil, 0, IO::Buffer::READONLY)
+ buffer.free
+ buffer.null?.should == true
+ end
+ end
+ end
+
+ context "with a String-backed buffer created with .for" do
+ context "without a block" do
+ it "disassociates the buffer from the string and nullifies the buffer" do
+ string = +"test"
+ buffer = IO::Buffer.for(string)
+ # Read-only buffer, can't modify the string.
+ buffer.free
+ buffer.null?.should == true
+ end
+ end
+
+ context "with a block" do
+ it "disassociates the buffer from the string and nullifies the buffer" do
+ string = +"test"
+ IO::Buffer.for(string) do |buffer|
+ buffer.set_string("meat")
+ buffer.free
+ buffer.null?.should == true
+ end
+ string.should == "meat"
+ end
+ end
+ end
+
+ context "with a String-backed buffer created with .string" do
+ it "disassociates the buffer from the string and nullifies the buffer" do
+ string =
+ IO::Buffer.string(4) do |buffer|
+ buffer.set_string("meat")
+ buffer.free
+ buffer.null?.should == true
+ end
+ string.should == "meat"
+ end
+ end
+
+ it "can be called repeatedly without an error" do
+ buffer = IO::Buffer.new(4)
+ buffer.free
+ buffer.null?.should == true
+ buffer.free
+ buffer.null?.should == true
+ end
+
+ it "is disallowed while locked, raising IO::Buffer::LockedError" do
+ buffer = IO::Buffer.new(4)
+ buffer.locked do
+ -> { buffer.free }.should.raise(IO::Buffer::LockedError, "Buffer is locked!")
+ end
+ buffer.free
+ buffer.null?.should == true
+ end
+
+ context "with a slice of a buffer" do
+ it "nullifies the slice, not touching the buffer" do
+ buffer = IO::Buffer.new(4)
+ slice = buffer.slice(0, 2)
+
+ slice.free
+ slice.null?.should == true
+ buffer.null?.should == false
+
+ buffer.free
+ end
+
+ it "nullifies buffer, invalidating the slice" do
+ buffer = IO::Buffer.new(4)
+ slice = buffer.slice(0, 2)
+
+ buffer.free
+ slice.null?.should == false
+ slice.valid?.should == false
+ end
+ end
+end
diff --git a/spec/ruby/core/io/buffer/initialize_spec.rb b/spec/ruby/core/io/buffer/initialize_spec.rb
new file mode 100644
index 0000000000..dba6fddc79
--- /dev/null
+++ b/spec/ruby/core/io/buffer/initialize_spec.rb
@@ -0,0 +1,119 @@
+require_relative '../../../spec_helper'
+
+describe "IO::Buffer#initialize" do
+ after :each do
+ @buffer&.free
+ @buffer = nil
+ end
+
+ it "creates a new zero-filled buffer with default size" do
+ @buffer = IO::Buffer.new
+ @buffer.size.should == IO::Buffer::DEFAULT_SIZE
+ @buffer.each(:U8).should.all? { |_offset, value| value.eql?(0) }
+ end
+
+ it "creates a buffer with default state" do
+ @buffer = IO::Buffer.new
+
+ @buffer.should_not.external?
+
+ @buffer.should_not.shared?
+ @buffer.should_not.private?
+ @buffer.should_not.readonly?
+
+ @buffer.should_not.empty?
+ @buffer.should_not.null?
+
+ @buffer.should_not.locked?
+ @buffer.should.valid?
+ end
+
+ context "with size argument" do
+ it "creates a new internal buffer if size is less than IO::Buffer::PAGE_SIZE" do
+ size = IO::Buffer::PAGE_SIZE - 1
+ @buffer = IO::Buffer.new(size)
+ @buffer.size.should == size
+ @buffer.should_not.empty?
+
+ @buffer.should.internal?
+ @buffer.should_not.mapped?
+ end
+
+ it "creates a new mapped buffer if size is greater than or equal to IO::Buffer::PAGE_SIZE" do
+ size = IO::Buffer::PAGE_SIZE
+ @buffer = IO::Buffer.new(size)
+ @buffer.size.should == size
+ @buffer.should_not.empty?
+
+ @buffer.should_not.internal?
+ @buffer.should.mapped?
+ end
+
+ it "creates a null buffer if size is 0" do
+ @buffer = IO::Buffer.new(0)
+ @buffer.should.null?
+ @buffer.should.empty?
+ end
+
+ it "raises TypeError if size is not an Integer" do
+ -> { IO::Buffer.new(nil) }.should.raise(TypeError, "not an Integer")
+ -> { IO::Buffer.new(10.0) }.should.raise(TypeError, "not an Integer")
+ end
+
+ it "raises ArgumentError if size is negative" do
+ -> { IO::Buffer.new(-1) }.should.raise(ArgumentError, "Size can't be negative!")
+ end
+ end
+
+ context "with size and flags arguments" do
+ it "forces mapped buffer with IO::Buffer::MAPPED flag" do
+ @buffer = IO::Buffer.new(IO::Buffer::PAGE_SIZE - 1, IO::Buffer::MAPPED)
+ @buffer.should.mapped?
+ @buffer.should_not.internal?
+ @buffer.should_not.empty?
+ end
+
+ it "forces internal buffer with IO::Buffer::INTERNAL flag" do
+ @buffer = IO::Buffer.new(IO::Buffer::PAGE_SIZE, IO::Buffer::INTERNAL)
+ @buffer.should.internal?
+ @buffer.should_not.mapped?
+ @buffer.should_not.empty?
+ end
+
+ it "allows extra flags" do
+ @buffer = IO::Buffer.new(10, IO::Buffer::INTERNAL | IO::Buffer::SHARED | IO::Buffer::READONLY)
+ @buffer.should.internal?
+ @buffer.should.shared?
+ @buffer.should.readonly?
+ end
+
+ it "ignores flags if size is 0" do
+ @buffer = IO::Buffer.new(0, 0xffff)
+ @buffer.should.null?
+ @buffer.should.empty?
+
+ @buffer.should_not.internal?
+ @buffer.should_not.mapped?
+ @buffer.should_not.external?
+
+ @buffer.should_not.shared?
+ @buffer.should_not.readonly?
+
+ @buffer.should_not.locked?
+ @buffer.should.valid?
+ end
+
+ it "raises IO::Buffer::AllocationError if neither IO::Buffer::MAPPED nor IO::Buffer::INTERNAL is given" do
+ -> { IO::Buffer.new(10, IO::Buffer::READONLY) }.should.raise(IO::Buffer::AllocationError, "Could not allocate buffer!")
+ -> { IO::Buffer.new(10, 0) }.should.raise(IO::Buffer::AllocationError, "Could not allocate buffer!")
+ end
+
+ it "raises ArgumentError if flags is negative" do
+ -> { IO::Buffer.new(10, -1) }.should.raise(ArgumentError, "Flags can't be negative!")
+ end
+
+ it "raises TypeError with non-Integer flags" do
+ -> { IO::Buffer.new(10, 0.0) }.should.raise(TypeError, "not an Integer")
+ end
+ end
+end
diff --git a/spec/ruby/core/io/buffer/internal_spec.rb b/spec/ruby/core/io/buffer/internal_spec.rb
new file mode 100644
index 0000000000..73e19eb85e
--- /dev/null
+++ b/spec/ruby/core/io/buffer/internal_spec.rb
@@ -0,0 +1,23 @@
+require_relative '../../../spec_helper'
+
+describe "IO::Buffer#internal?" do
+ after :each do
+ @buffer&.free
+ @buffer = nil
+ end
+
+ it "is true for an internally-allocated buffer" do
+ @buffer = IO::Buffer.new(12)
+ @buffer.internal?.should == true
+ end
+
+ it "is false for an externally-allocated buffer" do
+ @buffer = IO::Buffer.new(12, IO::Buffer::MAPPED)
+ @buffer.internal?.should == false
+ end
+
+ it "is false for a null buffer" do
+ @buffer = IO::Buffer.new(0)
+ @buffer.internal?.should == false
+ end
+end
diff --git a/spec/ruby/core/io/buffer/locked_spec.rb b/spec/ruby/core/io/buffer/locked_spec.rb
new file mode 100644
index 0000000000..249026aa8a
--- /dev/null
+++ b/spec/ruby/core/io/buffer/locked_spec.rb
@@ -0,0 +1,75 @@
+require_relative '../../../spec_helper'
+
+describe "IO::Buffer#locked" do
+ after :each do
+ @buffer&.free
+ @buffer = nil
+ end
+
+ context "when buffer is locked" do
+ it "allows reading and writing operations on the buffer" do
+ @buffer = IO::Buffer.new(4)
+ @buffer.set_string("test")
+ @buffer.locked do
+ @buffer.get_string.should == "test"
+ @buffer.set_string("meat")
+ end
+ @buffer.get_string.should == "meat"
+ end
+
+ it "disallows operations changing buffer itself, raising IO::Buffer::LockedError" do
+ @buffer = IO::Buffer.new(4)
+ @buffer.locked do
+ # Just an example, each method is responsible for checking the lock state.
+ -> { @buffer.resize(8) }.should.raise(IO::Buffer::LockedError)
+ end
+ end
+ end
+
+ it "disallows reentrant locking, raising IO::Buffer::LockedError" do
+ @buffer = IO::Buffer.new(4)
+ @buffer.locked do
+ -> { @buffer.locked {} }.should.raise(IO::Buffer::LockedError, "Buffer already locked!")
+ end
+ end
+
+ it "does not propagate to buffer's slices" do
+ @buffer = IO::Buffer.new(4)
+ slice = @buffer.slice(0, 2)
+ @buffer.locked do
+ @buffer.locked?.should == true
+ slice.locked?.should == false
+ slice.locked { slice.locked?.should == true }
+ end
+ end
+
+ it "does not propagate backwards from buffer's slices" do
+ @buffer = IO::Buffer.new(4)
+ slice = @buffer.slice(0, 2)
+ slice.locked do
+ slice.locked?.should == true
+ @buffer.locked?.should == false
+ @buffer.locked { @buffer.locked?.should == true }
+ end
+ end
+end
+
+describe "IO::Buffer#locked?" do
+ after :each do
+ @buffer&.free
+ @buffer = nil
+ end
+
+ it "is false by default" do
+ @buffer = IO::Buffer.new(4)
+ @buffer.locked?.should == false
+ end
+
+ it "is true only inside of #locked block" do
+ @buffer = IO::Buffer.new(4)
+ @buffer.locked do
+ @buffer.locked?.should == true
+ end
+ @buffer.locked?.should == false
+ end
+end
diff --git a/spec/ruby/core/io/buffer/map_spec.rb b/spec/ruby/core/io/buffer/map_spec.rb
new file mode 100644
index 0000000000..97764c2dd7
--- /dev/null
+++ b/spec/ruby/core/io/buffer/map_spec.rb
@@ -0,0 +1,347 @@
+require_relative '../../../spec_helper'
+
+describe "IO::Buffer.map" do
+ before :all do
+ @tmp_files = []
+
+ @big_file_name = nil
+ @small_file_name = nil
+ end
+
+ after :all do
+ @tmp_files.each {|file| File.delete(file)}
+ end
+
+ def open_fixture
+ unless @small_file_name
+ @small_file_name = tmp("read_text.txt")
+ File.copy_stream(fixture(__dir__, "read_text.txt"), @small_file_name)
+ @tmp_files << @small_file_name
+ end
+ File.open(@small_file_name, "rb+")
+ end
+
+ def open_big_file_fixture
+ unless @big_file_name
+ @big_file_name = tmp("big_file")
+ # Usually 4 kibibytes + 16 bytes
+ File.write(@big_file_name, "12345678" * (IO::Buffer::PAGE_SIZE / 8 + 2))
+ @tmp_files << @big_file_name
+ end
+ File.open(@big_file_name, "rb+")
+ end
+
+ after :each do
+ @buffer&.free
+ @buffer = nil
+ @file&.close
+ @file = nil
+ end
+
+ it "creates a new buffer mapped from a file" do
+ @file = open_fixture
+ @buffer = IO::Buffer.map(@file)
+
+ @buffer.size.should == 9
+ @buffer.get_string.should == "abcâdef\n".b
+ end
+
+ it "allows to close the file after creating buffer, retaining mapping" do
+ file = open_fixture
+ @buffer = IO::Buffer.map(file)
+ file.close
+
+ @buffer.get_string.should == "abcâdef\n".b
+ end
+
+ it "creates a mapped, external, shared buffer" do
+ @file = open_fixture
+ @buffer = IO::Buffer.map(@file)
+
+ @buffer.should_not.internal?
+ @buffer.should.mapped?
+ @buffer.should.external?
+
+ @buffer.should_not.empty?
+ @buffer.should_not.null?
+
+ @buffer.should.shared?
+ @buffer.should_not.private?
+ @buffer.should_not.readonly?
+
+ @buffer.should_not.locked?
+ @buffer.should.valid?
+ end
+
+ # IO::Buffer.map seems not shareable across processes on OpenBSD.
+ # See https://rubyci.s3.amazonaws.com/openbsd-current/ruby-master/log/20260129T163005Z.fail.html.gz
+ platform_is_not :openbsd do
+ guard -> { Process.respond_to?(:fork) } do
+ it "is shareable across processes" do
+ file_name = tmp("shared_buffer")
+ @file = File.open(file_name, "w+")
+ @file << "I'm private"
+ @file.rewind
+ @buffer = IO::Buffer.map(@file)
+
+ IO.popen("-") do |child_pipe|
+ if child_pipe
+ # Synchronize on child's output.
+ child_pipe.readlines.first.chomp.should == @buffer.to_s
+ @buffer.get_string.should == "I'm shared!"
+
+ @file.read.should == "I'm shared!"
+ else
+ @buffer.set_string("I'm shared!")
+ puts @buffer
+ end
+ ensure
+ child_pipe&.close
+ end
+ ensure
+ File.unlink(file_name)
+ end
+ end
+ end
+
+ context "with an empty file" do
+ ruby_version_is "4.0" do
+ it "raises ArgumentError" do
+ file_name = tmp("empty.txt")
+ @file = File.open(file_name, "wb+")
+ @tmp_files << file_name
+ -> { IO::Buffer.map(@file) }.should.raise(ArgumentError, "Invalid negative or zero file size!")
+ end
+ end
+ end
+
+ context "with a file opened only for reading" do
+ it "raises a SystemCallError unless read-only" do
+ @file = File.open(fixture(__dir__, "read_text.txt"), "rb")
+ -> { IO::Buffer.map(@file) }.should.raise(SystemCallError)
+ end
+ end
+
+ context "with size argument" do
+ it "limits the buffer to the specified size in bytes, starting from the start of the file" do
+ @file = open_fixture
+ @buffer = IO::Buffer.map(@file, 4)
+
+ @buffer.size.should == 4
+ @buffer.get_string.should == "abc\xC3".b
+ end
+
+ it "maps the whole file if size is nil" do
+ @file = open_fixture
+ @buffer = IO::Buffer.map(@file, nil)
+
+ @buffer.size.should == 9
+ end
+
+ context "if size is 0" do
+ ruby_version_is "4.0" do
+ it "raises ArgumentError" do
+ @file = open_fixture
+ -> { IO::Buffer.map(@file, 0) }.should.raise(ArgumentError, "Size can't be zero!")
+ end
+ end
+ end
+
+ it "raises TypeError if size is not an Integer or nil" do
+ @file = open_fixture
+ -> { IO::Buffer.map(@file, "10") }.should.raise(TypeError, "not an Integer")
+ -> { IO::Buffer.map(@file, 10.0) }.should.raise(TypeError, "not an Integer")
+ end
+
+ it "raises ArgumentError if size is negative" do
+ @file = open_fixture
+ -> { IO::Buffer.map(@file, -1) }.should.raise(ArgumentError, "Size can't be negative!")
+ end
+
+ ruby_version_is ""..."4.0" do
+ # May or may not cause a crash on access.
+ it "is undefined behavior if size is larger than file size"
+ end
+
+ ruby_version_is "4.0" do
+ it "raises ArgumentError if size is larger than file size" do
+ @file = open_fixture
+ -> { IO::Buffer.map(@file, 8192) }.should.raise(ArgumentError, "Size can't be larger than file size!")
+ end
+ end
+ end
+
+ context "with size and offset arguments" do
+ # Neither Windows nor macOS have clear, stable behavior with non-zero offset.
+ # https://bugs.ruby-lang.org/issues/21700
+ platform_is :linux do
+ context "if offset is an allowed value for system call" do
+ it "maps the span specified by size starting from the offset" do
+ @file = open_big_file_fixture
+ @buffer = IO::Buffer.map(@file, 14, IO::Buffer::PAGE_SIZE)
+
+ @buffer.size.should == 14
+ @buffer.get_string(0, 14).should == "12345678123456"
+ end
+
+ context "if size is nil" do
+ ruby_version_is ""..."4.0" do
+ it "maps the rest of the file" do
+ @file = open_big_file_fixture
+ @buffer = IO::Buffer.map(@file, nil, IO::Buffer::PAGE_SIZE)
+
+ @buffer.get_string(0, 1).should == "1"
+ end
+
+ it "incorrectly sets buffer's size to file's full size" do
+ @file = open_big_file_fixture
+ @buffer = IO::Buffer.map(@file, nil, IO::Buffer::PAGE_SIZE)
+
+ @buffer.size.should == @file.size
+ end
+ end
+
+ ruby_version_is "4.0" do
+ it "maps the rest of the file" do
+ @file = open_big_file_fixture
+ @buffer = IO::Buffer.map(@file, nil, IO::Buffer::PAGE_SIZE)
+
+ @buffer.get_string(0, 1).should == "1"
+ end
+
+ it "sets buffer's size to file's remaining size" do
+ @file = open_big_file_fixture
+ @buffer = IO::Buffer.map(@file, nil, IO::Buffer::PAGE_SIZE)
+
+ @buffer.size.should == (@file.size - IO::Buffer::PAGE_SIZE)
+ end
+ end
+ end
+ end
+ end
+
+ it "maps the file from the start if offset is 0" do
+ @file = open_fixture
+ @buffer = IO::Buffer.map(@file, 4, 0)
+
+ @buffer.size.should == 4
+ @buffer.get_string.should == "abc\xC3".b
+ end
+
+ ruby_version_is ""..."4.0" do
+ # May or may not cause a crash on access.
+ it "is undefined behavior if offset+size is larger than file size"
+ end
+
+ ruby_version_is "4.0" do
+ it "raises ArgumentError if offset+size is larger than file size" do
+ @file = open_big_file_fixture
+ -> { IO::Buffer.map(@file, 17, IO::Buffer::PAGE_SIZE) }.should.raise(ArgumentError, "Offset too large!")
+ ensure
+ # Windows requires the file to be closed before deletion.
+ @file.close unless @file.closed?
+ end
+ end
+
+ it "raises TypeError if offset is not convertible to Integer" do
+ @file = open_fixture
+ -> { IO::Buffer.map(@file, 4, "4096") }.should.raise(TypeError, /no implicit conversion/)
+ -> { IO::Buffer.map(@file, 4, nil) }.should.raise(TypeError, /no implicit conversion/)
+ end
+
+ ruby_version_is "4.0" do
+ it "raises ArgumentError if offset is negative" do
+ @file = open_fixture
+ -> { IO::Buffer.map(@file, 4, -1) }.should.raise(ArgumentError, "Offset can't be negative!")
+ end
+ end
+ end
+
+ context "with flags argument" do
+ context "when READONLY flag is specified" do
+ it "sets readonly flag on the buffer, allowing only reads" do
+ @file = open_fixture
+ @buffer = IO::Buffer.map(@file, nil, 0, IO::Buffer::READONLY)
+
+ @buffer.should.readonly?
+
+ @buffer.get_string.should == "abc\xC3\xA2def\n".b
+ end
+
+ it "allows mapping read-only files" do
+ @file = File.open(fixture(__dir__, "read_text.txt"), "rb")
+ @buffer = IO::Buffer.map(@file, nil, 0, IO::Buffer::READONLY)
+
+ @buffer.should.readonly?
+
+ @buffer.get_string.should == "abc\xC3\xA2def\n".b
+ end
+
+ it "causes IO::Buffer::AccessError on write" do
+ @file = open_fixture
+ @buffer = IO::Buffer.map(@file, nil, 0, IO::Buffer::READONLY)
+
+ -> { @buffer.set_string("test") }.should.raise(IO::Buffer::AccessError, "Buffer is not writable!")
+ end
+ end
+
+ context "when PRIVATE is specified" do
+ it "sets private flag on the buffer, making it freely modifiable" do
+ @file = open_fixture
+ @buffer = IO::Buffer.map(@file, nil, 0, IO::Buffer::PRIVATE)
+
+ @buffer.should.private?
+ @buffer.should_not.shared?
+ @buffer.should_not.external?
+
+ @buffer.get_string.should == "abc\xC3\xA2def\n".b
+ @buffer.set_string("test12345")
+ @buffer.get_string.should == "test12345".b
+
+ @file.read.should == "abcâdef\n".b
+ end
+
+ it "allows mapping read-only files and modifying the buffer" do
+ @file = File.open(fixture(__dir__, "read_text.txt"), "rb")
+ @buffer = IO::Buffer.map(@file, nil, 0, IO::Buffer::PRIVATE)
+
+ @buffer.should.private?
+ @buffer.should_not.shared?
+ @buffer.should_not.external?
+
+ @buffer.get_string.should == "abc\xC3\xA2def\n".b
+ @buffer.set_string("test12345")
+ @buffer.get_string.should == "test12345".b
+
+ @file.read.should == "abcâdef\n".b
+ end
+
+ guard -> { Process.respond_to?(:fork) } do
+ it "is not shared across processes" do
+ file_name = tmp("shared_buffer")
+ @file = File.open(file_name, "w+")
+ @file << "I'm private"
+ @file.rewind
+ @buffer = IO::Buffer.map(@file, nil, 0, IO::Buffer::PRIVATE)
+
+ IO.popen("-") do |child_pipe|
+ if child_pipe
+ # Synchronize on child's output.
+ child_pipe.readlines.first.chomp.should == @buffer.to_s
+ @buffer.get_string.should == "I'm private"
+
+ @file.read.should == "I'm private"
+ else
+ @buffer.set_string("I'm shared!")
+ puts @buffer
+ end
+ ensure
+ child_pipe&.close
+ end
+ ensure
+ File.unlink(file_name)
+ end
+ end
+ end
+ end
+end
diff --git a/spec/ruby/core/io/buffer/mapped_spec.rb b/spec/ruby/core/io/buffer/mapped_spec.rb
new file mode 100644
index 0000000000..0decb97704
--- /dev/null
+++ b/spec/ruby/core/io/buffer/mapped_spec.rb
@@ -0,0 +1,23 @@
+require_relative '../../../spec_helper'
+
+describe "IO::Buffer#mapped?" do
+ after :each do
+ @buffer&.free
+ @buffer = nil
+ end
+
+ it "is true for a buffer with mapped memory" do
+ @buffer = IO::Buffer.new(12, IO::Buffer::MAPPED)
+ @buffer.mapped?.should == true
+ end
+
+ it "is false for a buffer with non-mapped memory" do
+ @buffer = IO::Buffer.for("string")
+ @buffer.mapped?.should == false
+ end
+
+ it "is false for a null buffer" do
+ @buffer = IO::Buffer.new(0)
+ @buffer.mapped?.should == false
+ end
+end
diff --git a/spec/ruby/core/io/buffer/not_spec.rb b/spec/ruby/core/io/buffer/not_spec.rb
new file mode 100644
index 0000000000..4737a30bde
--- /dev/null
+++ b/spec/ruby/core/io/buffer/not_spec.rb
@@ -0,0 +1,37 @@
+require_relative '../../../spec_helper'
+
+describe :io_buffer_not, shared: true do
+ it "inverts every bit of the buffer" do
+ IO::Buffer.for(+"12345") do |buffer|
+ result = buffer.send(@method)
+ result.get_string.should == "\xCE\xCD\xCC\xCB\xCA".b
+ result.free
+ end
+ end
+end
+
+describe "IO::Buffer#~" do
+ it_behaves_like :io_buffer_not, :~
+
+ it "creates a new internal buffer of the same size" do
+ IO::Buffer.for(+"12345") do |buffer|
+ result = ~buffer
+ result.should_not.equal? buffer
+ result.should.internal?
+ result.size.should == buffer.size
+ result.free
+ end
+ end
+end
+
+describe "IO::Buffer#not!" do
+ it_behaves_like :io_buffer_not, :not!
+
+ it "modifies the buffer in place" do
+ IO::Buffer.for(+"12345") do |buffer|
+ result = buffer.not!
+ result.should.equal? buffer
+ result.should.external?
+ end
+ end
+end
diff --git a/spec/ruby/core/io/buffer/null_spec.rb b/spec/ruby/core/io/buffer/null_spec.rb
new file mode 100644
index 0000000000..380a98bde1
--- /dev/null
+++ b/spec/ruby/core/io/buffer/null_spec.rb
@@ -0,0 +1,27 @@
+require_relative '../../../spec_helper'
+require_relative 'shared/null_and_empty'
+
+describe "IO::Buffer#null?" do
+ after :each do
+ @buffer&.free
+ @buffer = nil
+ end
+
+ it_behaves_like :io_buffer_null_and_empty, :null?
+
+ it "is false for a 0-length String-backed buffer created with .for" do
+ @buffer = IO::Buffer.for("")
+ @buffer.null?.should == false
+ end
+
+ it "is false for a 0-length String-backed buffer created with .string" do
+ IO::Buffer.string(0) do |buffer|
+ buffer.null?.should == false
+ end
+ end
+
+ it "is false for a 0-length slice of a buffer with size > 0" do
+ @buffer = IO::Buffer.new(4)
+ @buffer.slice(3, 0).null?.should == false
+ end
+end
diff --git a/spec/ruby/core/io/buffer/or_spec.rb b/spec/ruby/core/io/buffer/or_spec.rb
new file mode 100644
index 0000000000..3e627c216c
--- /dev/null
+++ b/spec/ruby/core/io/buffer/or_spec.rb
@@ -0,0 +1,62 @@
+require_relative '../../../spec_helper'
+
+describe :io_buffer_or, shared: true do
+ it "applies the argument buffer as an OR bit mask across the whole buffer" do
+ IO::Buffer.for(+"12345") do |buffer|
+ IO::Buffer.for(+"\xF8\x8F") do |mask|
+ result = buffer.send(@method, mask)
+ result.get_string.should == "\xF9\xBF\xFB\xBF\xFD".b
+ result.free
+ end
+ end
+ end
+
+ it "ignores extra parts of mask if it is longer than source buffer" do
+ IO::Buffer.for(+"12345") do |buffer|
+ IO::Buffer.for(+"\xF8\x8F\x00\x00\x00\xFF\xFF") do |mask|
+ result = buffer.send(@method, mask)
+ result.get_string.should == "\xF9\xBF345".b
+ result.free
+ end
+ end
+ end
+
+ it "raises TypeError if mask is not an IO::Buffer" do
+ IO::Buffer.for(+"12345") do |buffer|
+ -> { buffer.send(@method, "\xF8\x8F") }.should.raise(TypeError, "wrong argument type String (expected IO::Buffer)")
+ -> { buffer.send(@method, 0xF8) }.should.raise(TypeError, "wrong argument type Integer (expected IO::Buffer)")
+ -> { buffer.send(@method, nil) }.should.raise(TypeError, "wrong argument type nil (expected IO::Buffer)")
+ end
+ end
+end
+
+describe "IO::Buffer#|" do
+ it_behaves_like :io_buffer_or, :|
+
+ it "creates a new internal buffer of the same size" do
+ IO::Buffer.for(+"12345") do |buffer|
+ IO::Buffer.for(+"\xF8\x8F") do |mask|
+ result = buffer | mask
+ result.should_not.equal? buffer
+ result.should.internal?
+ result.size.should == buffer.size
+ result.free
+ buffer.get_string.should == "12345".b
+ end
+ end
+ end
+end
+
+describe "IO::Buffer#or!" do
+ it_behaves_like :io_buffer_or, :or!
+
+ it "modifies the buffer in place" do
+ IO::Buffer.for(+"12345") do |buffer|
+ IO::Buffer.for(+"\xF8\x8F") do |mask|
+ result = buffer.or!(mask)
+ result.should.equal? buffer
+ result.should.external?
+ end
+ end
+ end
+end
diff --git a/spec/ruby/core/io/buffer/private_spec.rb b/spec/ruby/core/io/buffer/private_spec.rb
new file mode 100644
index 0000000000..6e6afee34c
--- /dev/null
+++ b/spec/ruby/core/io/buffer/private_spec.rb
@@ -0,0 +1,23 @@
+require_relative '../../../spec_helper'
+
+describe "IO::Buffer#private?" do
+ after :each do
+ @buffer&.free
+ @buffer = nil
+ end
+
+ it "is true for a buffer created with PRIVATE flag" do
+ @buffer = IO::Buffer.new(12, IO::Buffer::INTERNAL | IO::Buffer::PRIVATE)
+ @buffer.private?.should == true
+ end
+
+ it "is false for a buffer created without PRIVATE flag" do
+ @buffer = IO::Buffer.new(12, IO::Buffer::INTERNAL)
+ @buffer.private?.should == false
+ end
+
+ it "is false for a null buffer" do
+ @buffer = IO::Buffer.new(0)
+ @buffer.private?.should == false
+ end
+end
diff --git a/spec/ruby/core/io/buffer/readonly_spec.rb b/spec/ruby/core/io/buffer/readonly_spec.rb
new file mode 100644
index 0000000000..4eefc9f29f
--- /dev/null
+++ b/spec/ruby/core/io/buffer/readonly_spec.rb
@@ -0,0 +1,28 @@
+require_relative '../../../spec_helper'
+
+describe "IO::Buffer#readonly?" do
+ after :each do
+ @buffer&.free
+ @buffer = nil
+ end
+
+ it "is true for a buffer created with READONLY flag" do
+ @buffer = IO::Buffer.new(12, IO::Buffer::INTERNAL | IO::Buffer::READONLY)
+ @buffer.readonly?.should == true
+ end
+
+ it "is true for a buffer that is non-writable" do
+ @buffer = IO::Buffer.for("string")
+ @buffer.readonly?.should == true
+ end
+
+ it "is false for a modifiable buffer" do
+ @buffer = IO::Buffer.new(12)
+ @buffer.readonly?.should == false
+ end
+
+ it "is false for a null buffer" do
+ @buffer = IO::Buffer.new(0)
+ @buffer.readonly?.should == false
+ end
+end
diff --git a/spec/ruby/core/io/buffer/resize_spec.rb b/spec/ruby/core/io/buffer/resize_spec.rb
new file mode 100644
index 0000000000..6e684475f3
--- /dev/null
+++ b/spec/ruby/core/io/buffer/resize_spec.rb
@@ -0,0 +1,151 @@
+require_relative '../../../spec_helper'
+
+describe "IO::Buffer#resize" do
+ after :each do
+ @buffer&.free
+ @buffer = nil
+ end
+
+ context "with a buffer created with .new" do
+ it "resizes internal buffer, preserving type" do
+ @buffer = IO::Buffer.new(4)
+ @buffer.resize(IO::Buffer::PAGE_SIZE)
+ @buffer.size.should == IO::Buffer::PAGE_SIZE
+ @buffer.internal?.should == true
+ @buffer.mapped?.should == false
+ end
+
+ platform_is :linux do
+ it "resizes mapped buffer, preserving type" do
+ @buffer = IO::Buffer.new(IO::Buffer::PAGE_SIZE, IO::Buffer::MAPPED)
+ @buffer.resize(4)
+ @buffer.size.should == 4
+ @buffer.internal?.should == false
+ @buffer.mapped?.should == true
+ end
+ end
+
+ platform_is_not :linux do
+ it "resizes mapped buffer, changing type to internal" do
+ @buffer = IO::Buffer.new(IO::Buffer::PAGE_SIZE, IO::Buffer::MAPPED)
+ @buffer.resize(4)
+ @buffer.size.should == 4
+ @buffer.internal?.should == true
+ @buffer.mapped?.should == false
+ end
+ end
+ end
+
+ context "with a file-backed buffer created with .map" do
+ it "disallows resizing shared buffer, raising IO::Buffer::AccessError" do
+ File.open(__FILE__, "r+") do |file|
+ @buffer = IO::Buffer.map(file)
+ -> { @buffer.resize(10) }.should.raise(IO::Buffer::AccessError, "Cannot resize external buffer!")
+ end
+ end
+
+ it "resizes private buffer, discarding excess contents" do
+ File.open(__FILE__, "r") do |file|
+ @buffer = IO::Buffer.map(file, nil, 0, IO::Buffer::PRIVATE)
+ @buffer.resize(10)
+ @buffer.size.should == 10
+ @buffer.get_string.should == "require_re"
+ @buffer.resize(12)
+ @buffer.size.should == 12
+ @buffer.get_string.should == "require_re\0\0"
+ end
+ end
+ end
+
+ context "with a String-backed buffer created with .for" do
+ context "without a block" do
+ it "disallows resizing, raising IO::Buffer::AccessError" do
+ @buffer = IO::Buffer.for(+"test")
+ -> { @buffer.resize(10) }.should.raise(IO::Buffer::AccessError, "Cannot resize external buffer!")
+ end
+ end
+
+ context "with a block" do
+ it "disallows resizing, raising IO::Buffer::AccessError" do
+ IO::Buffer.for(+'test') do |buffer|
+ -> { buffer.resize(10) }.should.raise(IO::Buffer::AccessError, "Cannot resize external buffer!")
+ end
+ end
+ end
+ end
+
+ context "with a String-backed buffer created with .string" do
+ it "disallows resizing, raising IO::Buffer::AccessError" do
+ IO::Buffer.string(4) do |buffer|
+ -> { buffer.resize(10) }.should.raise(IO::Buffer::AccessError, "Cannot resize external buffer!")
+ end
+ end
+ end
+
+ context "with a null buffer" do
+ it "allows resizing a 0-sized buffer, creating a regular buffer according to new size" do
+ @buffer = IO::Buffer.new(0)
+ @buffer.resize(IO::Buffer::PAGE_SIZE)
+ @buffer.size.should == IO::Buffer::PAGE_SIZE
+ @buffer.internal?.should == false
+ @buffer.mapped?.should == true
+ end
+
+ it "allows resizing after a free, creating a regular buffer according to new size" do
+ @buffer = IO::Buffer.for("test")
+ @buffer.free
+ @buffer.resize(10)
+ @buffer.size.should == 10
+ @buffer.internal?.should == true
+ @buffer.mapped?.should == false
+ end
+ end
+
+ it "allows resizing to 0, freeing memory" do
+ @buffer = IO::Buffer.new(4)
+ @buffer.resize(0)
+ @buffer.null?.should == true
+ end
+
+ it "can be called repeatedly" do
+ @buffer = IO::Buffer.new(4)
+ @buffer.resize(10)
+ @buffer.resize(27)
+ @buffer.resize(1)
+ @buffer.size.should == 1
+ end
+
+ it "always clears extra memory" do
+ @buffer = IO::Buffer.new(4)
+ @buffer.set_string("test")
+ # This should not cause a re-allocation, just a technical resizing,
+ # even with very aggressive memory allocation.
+ @buffer.resize(2)
+ @buffer.resize(4)
+ @buffer.get_string.should == "te\0\0"
+ end
+
+ it "is disallowed while locked, raising IO::Buffer::LockedError" do
+ @buffer = IO::Buffer.new(4)
+ @buffer.locked do
+ -> { @buffer.resize(10) }.should.raise(IO::Buffer::LockedError, "Cannot resize locked buffer!")
+ end
+ end
+
+ it "raises ArgumentError if size is negative" do
+ @buffer = IO::Buffer.new(4)
+ -> { @buffer.resize(-1) }.should.raise(ArgumentError, "Size can't be negative!")
+ end
+
+ it "raises TypeError if size is not an Integer" do
+ @buffer = IO::Buffer.new(4)
+ -> { @buffer.resize(nil) }.should.raise(TypeError, "not an Integer")
+ -> { @buffer.resize(10.0) }.should.raise(TypeError, "not an Integer")
+ end
+
+ context "with a slice of a buffer" do
+ # Current behavior of slice resizing seems unintended (it's undocumented, too).
+ # It either creates a completely new buffer, or breaks the slice on size 0.
+ it "needs to be reviewed for spec completeness"
+ end
+end
diff --git a/spec/ruby/core/io/buffer/shared/null_and_empty.rb b/spec/ruby/core/io/buffer/shared/null_and_empty.rb
new file mode 100644
index 0000000000..f8abc5f0fc
--- /dev/null
+++ b/spec/ruby/core/io/buffer/shared/null_and_empty.rb
@@ -0,0 +1,57 @@
+describe :io_buffer_null_and_empty, shared: true do
+ it "is false for a buffer with size > 0" do
+ @buffer = IO::Buffer.new(1)
+ @buffer.send(@method).should == false
+ end
+
+ it "is false for a slice with length > 0" do
+ @buffer = IO::Buffer.new(4)
+ @buffer.slice(1, 2).send(@method).should == false
+ end
+
+ it "is false for a file-mapped buffer" do
+ File.open(__FILE__, "rb") do |file|
+ @buffer = IO::Buffer.map(file, nil, 0, IO::Buffer::READONLY)
+ @buffer.send(@method).should == false
+ end
+ end
+
+ it "is false for a non-empty String-backed buffer created with .for" do
+ @buffer = IO::Buffer.for("test")
+ @buffer.send(@method).should == false
+ end
+
+ it "is false for a non-empty String-backed buffer created with .string" do
+ IO::Buffer.string(4) do |buffer|
+ buffer.send(@method).should == false
+ end
+ end
+
+ it "is true for a 0-sized buffer" do
+ @buffer = IO::Buffer.new(0)
+ @buffer.send(@method).should == true
+ end
+
+ it "is true for a slice of a 0-sized buffer" do
+ @buffer = IO::Buffer.new(0)
+ @buffer.slice(0, 0).send(@method).should == true
+ end
+
+ it "is true for a freed buffer" do
+ @buffer = IO::Buffer.new(1)
+ @buffer.free
+ @buffer.send(@method).should == true
+ end
+
+ it "is true for a buffer resized to 0" do
+ @buffer = IO::Buffer.new(1)
+ @buffer.resize(0)
+ @buffer.send(@method).should == true
+ end
+
+ it "is true for a buffer whose memory was transferred" do
+ buffer = IO::Buffer.new(1)
+ @buffer = buffer.transfer
+ buffer.send(@method).should == true
+ end
+end
diff --git a/spec/ruby/core/io/buffer/shared_spec.rb b/spec/ruby/core/io/buffer/shared_spec.rb
new file mode 100644
index 0000000000..2cc93e6d08
--- /dev/null
+++ b/spec/ruby/core/io/buffer/shared_spec.rb
@@ -0,0 +1,33 @@
+require_relative '../../../spec_helper'
+
+describe "IO::Buffer#shared?" do
+ after :each do
+ @buffer&.free
+ @buffer = nil
+ end
+
+ it "is true for a buffer created with SHARED flag" do
+ @buffer = IO::Buffer.new(12, IO::Buffer::INTERNAL | IO::Buffer::SHARED)
+ @buffer.shared?.should == true
+ end
+
+ it "is true for a non-private buffer created with .map" do
+ path = fixture(__dir__, "read_text.txt")
+ file = File.open(path, "r+")
+ @buffer = IO::Buffer.map(file)
+ @buffer.shared?.should == true
+ ensure
+ @buffer.free
+ file.close
+ end
+
+ it "is false for an unshared buffer" do
+ @buffer = IO::Buffer.new(12)
+ @buffer.shared?.should == false
+ end
+
+ it "is false for a null buffer" do
+ @buffer = IO::Buffer.new(0)
+ @buffer.shared?.should == false
+ end
+end
diff --git a/spec/ruby/core/io/buffer/string_spec.rb b/spec/ruby/core/io/buffer/string_spec.rb
new file mode 100644
index 0000000000..4c73ba5e1e
--- /dev/null
+++ b/spec/ruby/core/io/buffer/string_spec.rb
@@ -0,0 +1,62 @@
+require_relative '../../../spec_helper'
+
+describe "IO::Buffer.string" do
+ it "creates a modifiable buffer for the duration of the block" do
+ IO::Buffer.string(7) do |buffer|
+ @buffer = buffer
+
+ buffer.size.should == 7
+ buffer.get_string.should == "\0\0\0\0\0\0\0".b
+
+ buffer.set_string("test")
+ buffer.get_string.should == "test\0\0\0"
+ end
+ @buffer.should.null?
+ end
+
+ it "returns contents of the buffer as a binary string" do
+ string =
+ IO::Buffer.string(7) do |buffer|
+ buffer.set_string("ä test")
+ end
+ string.should == "\xC3\xA4 test".b
+ end
+
+ it "creates an external buffer" do
+ IO::Buffer.string(8) do |buffer|
+ buffer.should_not.internal?
+ buffer.should_not.mapped?
+ buffer.should.external?
+
+ buffer.should_not.empty?
+ buffer.should_not.null?
+
+ buffer.should_not.shared?
+ buffer.should_not.private?
+ buffer.should_not.readonly?
+
+ buffer.should_not.locked?
+ buffer.should.valid?
+ end
+ end
+
+ it "returns an empty string if size is 0" do
+ string =
+ IO::Buffer.string(0) do |buffer|
+ buffer.size.should == 0
+ end
+ string.should == ""
+ end
+
+ it "raises ArgumentError if size is negative" do
+ -> { IO::Buffer.string(-1) {} }.should.raise(ArgumentError, "negative string size (or size too big)")
+ end
+
+ it "raises RangeError if size is too large" do
+ -> { IO::Buffer.string(2 ** 232) {} }.should.raise(RangeError, /\Abignum too big to convert into [`']long'\z/)
+ end
+
+ it "raises LocalJumpError if no block is given" do
+ -> { IO::Buffer.string(7) }.should.raise(LocalJumpError, "no block given")
+ end
+end
diff --git a/spec/ruby/core/io/buffer/transfer_spec.rb b/spec/ruby/core/io/buffer/transfer_spec.rb
new file mode 100644
index 0000000000..3bc08998dd
--- /dev/null
+++ b/spec/ruby/core/io/buffer/transfer_spec.rb
@@ -0,0 +1,117 @@
+require_relative '../../../spec_helper'
+
+describe "IO::Buffer#transfer" do
+ after :each do
+ @buffer&.free
+ @buffer = nil
+ end
+
+ context "with a buffer created with .new" do
+ it "transfers internal memory to a new buffer, nullifying the original" do
+ buffer = IO::Buffer.new(4)
+ info = buffer.to_s
+ @buffer = buffer.transfer
+ @buffer.to_s.should == info
+ buffer.null?.should == true
+ end
+
+ it "transfers mapped memory to a new buffer, nullifying the original" do
+ buffer = IO::Buffer.new(4, IO::Buffer::MAPPED)
+ info = buffer.to_s
+ @buffer = buffer.transfer
+ @buffer.to_s.should == info
+ buffer.null?.should == true
+ end
+ end
+
+ context "with a file-backed buffer created with .map" do
+ it "transfers mapped memory to a new buffer, nullifying the original" do
+ File.open(__FILE__, "r") do |file|
+ buffer = IO::Buffer.map(file, nil, 0, IO::Buffer::READONLY)
+ info = buffer.to_s
+ @buffer = buffer.transfer
+ @buffer.to_s.should == info
+ buffer.null?.should == true
+ end
+ end
+ end
+
+ context "with a String-backed buffer created with .for" do
+ context "without a block" do
+ it "transfers memory to a new buffer, nullifying the original" do
+ buffer = IO::Buffer.for("test")
+ info = buffer.to_s
+ @buffer = buffer.transfer
+ @buffer.to_s.should == info
+ buffer.null?.should == true
+ end
+ end
+
+ context "with a block" do
+ it "transfers memory to a new buffer, breaking the transaction by nullifying the original" do
+ IO::Buffer.for(+"test") do |buffer|
+ info = buffer.to_s
+ @buffer = buffer.transfer
+ @buffer.to_s.should == info
+ buffer.null?.should == true
+ end
+ @buffer.null?.should == false
+ end
+ end
+ end
+
+ context "with a String-backed buffer created with .string" do
+ it "transfers memory to a new buffer, breaking the transaction by nullifying the original" do
+ IO::Buffer.string(4) do |buffer|
+ info = buffer.to_s
+ @buffer = buffer.transfer
+ @buffer.to_s.should == info
+ buffer.null?.should == true
+ end
+ @buffer.null?.should == false
+ end
+ end
+
+ it "allows multiple transfers" do
+ buffer_1 = IO::Buffer.new(4)
+ buffer_2 = buffer_1.transfer
+ @buffer = buffer_2.transfer
+ buffer_1.null?.should == true
+ buffer_2.null?.should == true
+ @buffer.null?.should == false
+ end
+
+ it "is disallowed while locked, raising IO::Buffer::LockedError" do
+ @buffer = IO::Buffer.new(4)
+ @buffer.locked do
+ -> { @buffer.transfer }.should.raise(IO::Buffer::LockedError, "Cannot transfer ownership of locked buffer!")
+ end
+ end
+
+ context "with a slice of a buffer" do
+ it "transfers source to a new slice, not touching the buffer" do
+ @buffer = IO::Buffer.new(4)
+ @buffer.set_string("test")
+ slice = @buffer.slice(0, 2)
+ slice.get_string.should == "te"
+
+ new_slice = slice.transfer
+ slice.null?.should == true
+ new_slice.null?.should == false
+ @buffer.null?.should == false
+
+ new_slice.set_string("ea")
+ @buffer.get_string.should == "east"
+ end
+
+ it "nullifies buffer, invalidating the slice" do
+ buffer = IO::Buffer.new(4)
+ slice = buffer.slice(0, 2)
+ @buffer = buffer.transfer
+
+ slice.null?.should == false
+ slice.valid?.should == false
+ -> { slice.get_string }.should.raise(IO::Buffer::InvalidatedError, "Buffer has been invalidated!")
+ end
+ end
+end
diff --git a/spec/ruby/core/io/buffer/valid_spec.rb b/spec/ruby/core/io/buffer/valid_spec.rb
new file mode 100644
index 0000000000..b84bdd0cfd
--- /dev/null
+++ b/spec/ruby/core/io/buffer/valid_spec.rb
@@ -0,0 +1,99 @@
+require_relative '../../../spec_helper'
+
+describe "IO::Buffer#valid?" do
+ after :each do
+ @buffer&.free
+ @buffer = nil
+ end
+
+ # Non-slices are always valid
+ context "with a non-slice buffer" do
+ it "is true for a regular buffer" do
+ @buffer = IO::Buffer.new(4)
+ @buffer.valid?.should == true
+ end
+
+ it "is true for a 0-size buffer" do
+ @buffer = IO::Buffer.new(0)
+ @buffer.valid?.should == true
+ end
+
+ it "is true for a freed buffer" do
+ @buffer = IO::Buffer.new(4)
+ @buffer.free
+ @buffer.valid?.should == true
+ end
+
+ it "is true for a freed file-backed buffer" do
+ File.open(__FILE__, "r") do |file|
+ @buffer = IO::Buffer.map(file, nil, 0, IO::Buffer::READONLY)
+ @buffer.valid?.should == true
+ @buffer.free
+ @buffer.valid?.should == true
+ end
+ end
+
+ it "is true for a freed string-backed buffer" do
+ @buffer = IO::Buffer.for("hello")
+ @buffer.valid?.should == true
+ @buffer.free
+ @buffer.valid?.should == true
+ end
+ end
+
+ # "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."
+ context "with a slice" do
+ it "is true for a slice of a live buffer" do
+ @buffer = IO::Buffer.new(4)
+ slice = @buffer.slice(0, 2)
+ slice.valid?.should == true
+ end
+
+ context "when buffer is resized" do
+ it "is false when slice becomes outside the buffer" do
+ @buffer = IO::Buffer.new(4)
+ slice = @buffer.slice(2, 2)
+ @buffer.resize(3)
+ slice.valid?.should == false
+ end
+ end
+
+ it "is false for a slice of a transferred buffer" do
+ buffer = IO::Buffer.new(4)
+ slice = buffer.slice(0, 2)
+ @buffer = buffer.transfer
+ slice.valid?.should == false
+ end
+
+ it "is false for a slice of a freed buffer" do
+ @buffer = IO::Buffer.new(4)
+ slice = @buffer.slice(0, 2)
+ @buffer.free
+ slice.valid?.should == false
+ end
+
+ it "is false for a slice of a freed file-backed buffer" do
+ File.open(__FILE__, "r") do |file|
+ @buffer = IO::Buffer.map(file, nil, 0, IO::Buffer::READONLY)
+ slice = @buffer.slice(0, 2)
+ slice.valid?.should == true
+ @buffer.free
+ slice.valid?.should == false
+ end
+ end
+
+ it "is true for a slice of a freed string-backed buffer while string is alive" do
+ @buffer = IO::Buffer.for("alive")
+ slice = @buffer.slice(0, 2)
+ slice.valid?.should == true
+ @buffer.free
+ slice.valid?.should == true
+ end
+
+ # There probably should be a test with a garbage-collected string,
+ # but it's not clear how to force that.
+
+ it "needs to be reviewed for spec completeness"
+ end
+end
diff --git a/spec/ruby/core/io/buffer/xor_spec.rb b/spec/ruby/core/io/buffer/xor_spec.rb
new file mode 100644
index 0000000000..9287611f7f
--- /dev/null
+++ b/spec/ruby/core/io/buffer/xor_spec.rb
@@ -0,0 +1,62 @@
+require_relative '../../../spec_helper'
+
+describe :io_buffer_xor, shared: true do
+ it "applies the argument buffer as an XOR bit mask across the whole buffer" do
+ IO::Buffer.for(+"12345") do |buffer|
+ IO::Buffer.for(+"\xF8\x8F") do |mask|
+ result = buffer.send(@method, mask)
+ result.get_string.should == "\xC9\xBD\xCB\xBB\xCD".b
+ result.free
+ end
+ end
+ end
+
+ it "ignores extra parts of mask if it is longer than source buffer" do
+ IO::Buffer.for(+"12345") do |buffer|
+ IO::Buffer.for(+"\xF8\x8F\x00\x00\x00\xFF\xFF") do |mask|
+ result = buffer.send(@method, mask)
+ result.get_string.should == "\xC9\xBD345".b
+ result.free
+ end
+ end
+ end
+
+ it "raises TypeError if mask is not an IO::Buffer" do
+ IO::Buffer.for(+"12345") do |buffer|
+ -> { buffer.send(@method, "\xF8\x8F") }.should.raise(TypeError, "wrong argument type String (expected IO::Buffer)")
+ -> { buffer.send(@method, 0xF8) }.should.raise(TypeError, "wrong argument type Integer (expected IO::Buffer)")
+ -> { buffer.send(@method, nil) }.should.raise(TypeError, "wrong argument type nil (expected IO::Buffer)")
+ end
+ end
+end
+
+describe "IO::Buffer#^" do
+ it_behaves_like :io_buffer_xor, :^
+
+ it "creates a new internal buffer of the same size" do
+ IO::Buffer.for(+"12345") do |buffer|
+ IO::Buffer.for(+"\xF8\x8F") do |mask|
+ result = buffer ^ mask
+ result.should_not.equal? buffer
+ result.should.internal?
+ result.size.should == buffer.size
+ result.free
+ buffer.get_string.should == "12345".b
+ end
+ end
+ end
+end
+
+describe "IO::Buffer#xor!" do
+ it_behaves_like :io_buffer_xor, :xor!
+
+ it "modifies the buffer in place" do
+ IO::Buffer.for(+"12345") do |buffer|
+ IO::Buffer.for(+"\xF8\x8F") do |mask|
+ result = buffer.xor!(mask)
+ result.should.equal? buffer
+ result.should.external?
+ end
+ end
+ end
+end
diff --git a/spec/ruby/core/io/close_on_exec_spec.rb b/spec/ruby/core/io/close_on_exec_spec.rb
index 4e89e08d61..28cdb967b9 100644
--- a/spec/ruby/core/io/close_on_exec_spec.rb
+++ b/spec/ruby/core/io/close_on_exec_spec.rb
@@ -42,7 +42,7 @@ describe "IO#close_on_exec=" do
it "raises IOError if called on a closed IO" do
@io.close
- -> { @io.close_on_exec = true }.should raise_error(IOError)
+ -> { @io.close_on_exec = true }.should.raise(IOError)
end
end
end
@@ -70,7 +70,7 @@ describe "IO#close_on_exec?" do
it "raises IOError if called on a closed IO" do
@io.close
- -> { @io.close_on_exec? }.should raise_error(IOError)
+ -> { @io.close_on_exec? }.should.raise(IOError)
end
end
end
diff --git a/spec/ruby/core/io/close_read_spec.rb b/spec/ruby/core/io/close_read_spec.rb
index e700e85bd9..c505289d72 100644
--- a/spec/ruby/core/io/close_read_spec.rb
+++ b/spec/ruby/core/io/close_read_spec.rb
@@ -17,26 +17,26 @@ describe "IO#close_read" do
it "closes the read end of a duplex I/O stream" do
@io.close_read
- -> { @io.read }.should raise_error(IOError)
+ -> { @io.read }.should.raise(IOError)
end
it "does nothing on subsequent invocations" do
@io.close_read
- @io.close_read.should be_nil
+ @io.close_read.should == nil
end
it "allows subsequent invocation of close" do
@io.close_read
- -> { @io.close }.should_not raise_error
+ -> { @io.close }.should_not.raise
end
it "raises an IOError if the stream is writable and not duplexed" do
io = File.open @path, 'w'
begin
- -> { io.close_read }.should raise_error(IOError)
+ -> { io.close_read }.should.raise(IOError)
ensure
io.close unless io.closed?
end
@@ -56,6 +56,6 @@ describe "IO#close_read" do
it "does nothing on closed stream" do
@io.close
- @io.close_read.should be_nil
+ @io.close_read.should == nil
end
end
diff --git a/spec/ruby/core/io/close_spec.rb b/spec/ruby/core/io/close_spec.rb
index 3a44cc8b17..afd84ba101 100644
--- a/spec/ruby/core/io/close_spec.rb
+++ b/spec/ruby/core/io/close_spec.rb
@@ -23,25 +23,25 @@ describe "IO#close" do
it "raises an IOError reading from a closed IO" do
@io.close
- -> { @io.read }.should raise_error(IOError)
+ -> { @io.read }.should.raise(IOError)
end
it "raises an IOError writing to a closed IO" do
@io.close
- -> { @io.write "data" }.should raise_error(IOError)
+ -> { @io.write "data" }.should.raise(IOError)
end
it 'does not close the stream if autoclose is false' do
other_io = IO.new(@io.fileno)
other_io.autoclose = false
other_io.close
- -> { @io.write "data" }.should_not raise_error(IOError)
+ -> { @io.write "data" }.should_not.raise(IOError)
end
it "does nothing if already closed" do
@io.close
- @io.close.should be_nil
+ @io.close.should == nil
end
it "does not call the #flush method but flushes the stream internally" do
@@ -80,7 +80,7 @@ describe "IO#close" do
matching_exception&.tap {|ex| raise ex}
end
- end.should raise_error(IOError, IOSpecs::THREAD_CLOSE_ERROR_MESSAGE)
+ end.should.raise(IOError, IOSpecs::THREAD_CLOSE_ERROR_MESSAGE)
end
end
@@ -93,7 +93,7 @@ describe "IO#close on an IO.popen stream" do
io.close
- -> { io.pid }.should raise_error(IOError)
+ -> { io.pid }.should.raise(IOError)
end
it "sets $?" do
diff --git a/spec/ruby/core/io/close_write_spec.rb b/spec/ruby/core/io/close_write_spec.rb
index 70610a3e9d..60b41505c3 100644
--- a/spec/ruby/core/io/close_write_spec.rb
+++ b/spec/ruby/core/io/close_write_spec.rb
@@ -16,26 +16,26 @@ describe "IO#close_write" do
it "closes the write end of a duplex I/O stream" do
@io.close_write
- -> { @io.write "attempt to write" }.should raise_error(IOError)
+ -> { @io.write "attempt to write" }.should.raise(IOError)
end
it "does nothing on subsequent invocations" do
@io.close_write
- @io.close_write.should be_nil
+ @io.close_write.should == nil
end
it "allows subsequent invocation of close" do
@io.close_write
- -> { @io.close }.should_not raise_error
+ -> { @io.close }.should_not.raise
end
it "raises an IOError if the stream is readable and not duplexed" do
io = File.open @path, 'w+'
begin
- -> { io.close_write }.should raise_error(IOError)
+ -> { io.close_write }.should.raise(IOError)
ensure
io.close unless io.closed?
end
@@ -63,6 +63,6 @@ describe "IO#close_write" do
it "does nothing on closed stream" do
@io.close
- @io.close_write.should be_nil
+ @io.close_write.should == nil
end
end
diff --git a/spec/ruby/core/io/closed_spec.rb b/spec/ruby/core/io/closed_spec.rb
index 7316546a0d..1f10858e28 100644
--- a/spec/ruby/core/io/closed_spec.rb
+++ b/spec/ruby/core/io/closed_spec.rb
@@ -11,10 +11,10 @@ describe "IO#closed?" do
end
it "returns true on closed stream" do
- IOSpecs.closed_io.closed?.should be_true
+ IOSpecs.closed_io.closed?.should == true
end
it "returns false on open stream" do
- @io.closed?.should be_false
+ @io.closed?.should == false
end
end
diff --git a/spec/ruby/core/io/copy_stream_spec.rb b/spec/ruby/core/io/copy_stream_spec.rb
index ffa2ea992c..31383f9b0f 100644
--- a/spec/ruby/core/io/copy_stream_spec.rb
+++ b/spec/ruby/core/io/copy_stream_spec.rb
@@ -31,7 +31,7 @@ describe :io_copy_stream_to_file, shared: true do
obj = mock("io_copy_stream_to")
obj.should_receive(:to_path).and_return(1)
- -> { IO.copy_stream(@object.from, obj) }.should raise_error(TypeError)
+ -> { IO.copy_stream(@object.from, obj) }.should.raise(TypeError)
end
end
@@ -71,7 +71,7 @@ describe :io_copy_stream_to_io, shared: true do
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)
+ -> { IO.copy_stream @object.from, to_io }.should.raise(IOError)
ensure
to_io.close
end
@@ -79,7 +79,7 @@ describe :io_copy_stream_to_io, shared: true do
it "does not close the destination IO" do
IO.copy_stream(@object.from, @to_io)
- @to_io.closed?.should be_false
+ @to_io.closed?.should == false
end
it "copies only length bytes when specified" do
@@ -129,12 +129,12 @@ describe "IO.copy_stream" do
it "raises an IOError if the source IO is not open for reading" do
@from_io.close
@from_io = new_io @from_bigfile, "a"
- -> { IO.copy_stream @from_io, @to_name }.should raise_error(IOError)
+ -> { IO.copy_stream @from_io, @to_name }.should.raise(IOError)
end
it "does not close the source IO" do
IO.copy_stream(@from_io, @to_name)
- @from_io.closed?.should be_false
+ @from_io.closed?.should == false
end
platform_is_not :windows do
@@ -206,7 +206,7 @@ describe "IO.copy_stream" do
obj = mock("io_copy_stream_from")
obj.should_receive(:to_path).and_return(1)
- -> { IO.copy_stream(obj, @to_name) }.should raise_error(TypeError)
+ -> { IO.copy_stream(obj, @to_name) }.should.raise(TypeError)
end
describe "to a file name" do
@@ -240,12 +240,12 @@ describe "IO.copy_stream" do
it "does not close the source IO" do
IO.copy_stream(@from_io, @to_name)
- @from_io.closed?.should be_false
+ @from_io.closed?.should == false
end
platform_is_not :windows do
it "raises an error when an offset is specified" do
- -> { IO.copy_stream(@from_io, @to_name, 8, 4) }.should raise_error(Errno::ESPIPE)
+ -> { IO.copy_stream(@from_io, @to_name, 8, 4) }.should.raise(Errno::ESPIPE)
end
end
@@ -300,6 +300,14 @@ describe "IO.copy_stream" do
@io.should_not_receive(:pos)
IO.copy_stream(@io, @to_name)
end
+
+ it "does not call #read on the source or #write on the destination if zero length is given" do
+ from = mock("io_copy_stream_to_object_zero_length_read")
+ to = mock("io_copy_stream_to_object_zero_length_write")
+ from.should_not_receive(:read)
+ to.should_not_receive(:write)
+ IO.copy_stream(from, to, 0)
+ end
end
describe "with a destination that does partial reads" do
diff --git a/spec/ruby/core/io/dup_spec.rb b/spec/ruby/core/io/dup_spec.rb
index 564e007438..db4e9fe641 100644
--- a/spec/ruby/core/io/dup_spec.rb
+++ b/spec/ruby/core/io/dup_spec.rb
@@ -49,7 +49,7 @@ describe "IO#dup" do
it "allows closing the new IO without affecting the original" do
@i.close
- -> { @f.gets }.should_not raise_error(Exception)
+ -> { @f.gets }.should_not.raise(Exception)
@i.should.closed?
@f.should_not.closed?
@@ -57,14 +57,14 @@ describe "IO#dup" do
it "allows closing the original IO without affecting the new one" do
@f.close
- -> { @i.gets }.should_not raise_error(Exception)
+ -> { @i.gets }.should_not.raise(Exception)
@i.should_not.closed?
@f.should.closed?
end
it "raises IOError on closed stream" do
- -> { IOSpecs.closed_io.dup }.should raise_error(IOError)
+ -> { IOSpecs.closed_io.dup }.should.raise(IOError)
end
it "always sets the close-on-exec flag for the new IO object" do
diff --git a/spec/ruby/core/io/each_byte_spec.rb b/spec/ruby/core/io/each_byte_spec.rb
index ea618e8c0c..fe299f0fba 100644
--- a/spec/ruby/core/io/each_byte_spec.rb
+++ b/spec/ruby/core/io/each_byte_spec.rb
@@ -12,7 +12,7 @@ describe "IO#each_byte" do
end
it "raises IOError on closed stream" do
- -> { IOSpecs.closed_io.each_byte {} }.should raise_error(IOError)
+ -> { IOSpecs.closed_io.each_byte {} }.should.raise(IOError)
end
it "yields each byte" do
@@ -28,7 +28,7 @@ describe "IO#each_byte" do
describe "when no block is given" do
it "returns an Enumerator" do
enum = @io.each_byte
- enum.should be_an_instance_of(Enumerator)
+ enum.should.instance_of?(Enumerator)
enum.first(5).should == [86, 111, 105, 99, 105]
end
@@ -52,6 +52,6 @@ describe "IO#each_byte" do
end
it "returns self on an empty stream" do
- @io.each_byte { |b| }.should equal(@io)
+ @io.each_byte { |b| }.should.equal?(@io)
end
end
diff --git a/spec/ruby/core/io/each_char_spec.rb b/spec/ruby/core/io/each_char_spec.rb
index 5d460a1e7c..7c1ca4f069 100644
--- a/spec/ruby/core/io/each_char_spec.rb
+++ b/spec/ruby/core/io/each_char_spec.rb
@@ -1,12 +1,75 @@
-# -*- encoding: utf-8 -*-
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
-require_relative 'shared/chars'
describe "IO#each_char" do
- it_behaves_like :io_chars, :each_char
+ before :each do
+ @io = IOSpecs.io_fixture "lines.txt"
+ ScratchPad.record []
+ end
+
+ after :each do
+ @io.close unless @io.closed?
+ end
+
+ it "yields each character" do
+ @io.readline.should == "Voici la ligne une.\n"
+
+ count = 0
+ @io.each_char do |c|
+ ScratchPad << c
+ break if 4 < count += 1
+ end
+
+ ScratchPad.recorded.should == ["Q", "u", "i", " ", "è"]
+ end
+
+ describe "when no block is given" do
+ it "returns an Enumerator" do
+ enum = @io.each_char
+ enum.should.instance_of?(Enumerator)
+ enum.first(5).should == ["V", "o", "i", "c", "i"]
+ end
+
+ describe "returned Enumerator" do
+ describe "size" do
+ it "should return nil" do
+ @io.each_char.size.should == nil
+ end
+ end
+ end
+ end
+
+ it "returns itself" do
+ @io.each_char { |c| }.should.equal?(@io)
+ end
+
+ it "returns an enumerator for a closed stream" do
+ IOSpecs.closed_io.each_char.should.instance_of?(Enumerator)
+ end
+
+ it "raises an IOError when an enumerator created on a closed stream is accessed" do
+ -> { IOSpecs.closed_io.each_char.first }.should.raise(IOError)
+ end
+
+ it "raises IOError on closed stream" do
+ -> { IOSpecs.closed_io.each_char {} }.should.raise(IOError)
+ end
end
describe "IO#each_char" do
- it_behaves_like :io_chars_empty, :each_char
+ before :each do
+ @name = tmp("io_each_char")
+ @io = new_io @name, "w+:utf-8"
+ ScratchPad.record []
+ end
+
+ after :each do
+ @io.close unless @io.closed?
+ rm_r @name
+ end
+
+ it "does not yield any characters on an empty stream" do
+ @io.each_char { |c| ScratchPad << c }
+ ScratchPad.recorded.should == []
+ end
end
diff --git a/spec/ruby/core/io/each_codepoint_spec.rb b/spec/ruby/core/io/each_codepoint_spec.rb
index 07a4037c8a..758a524986 100644
--- a/spec/ruby/core/io/each_codepoint_spec.rb
+++ b/spec/ruby/core/io/each_codepoint_spec.rb
@@ -1,10 +1,57 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
-require_relative 'shared/codepoints'
# See redmine #1667
describe "IO#each_codepoint" do
- it_behaves_like :io_codepoints, :each_codepoint
+ before :each do
+ @io = IOSpecs.io_fixture "lines.txt"
+ @enum = @io.each_codepoint
+ end
+
+ after :each do
+ @io.close
+ end
+
+ describe "when no block is given" do
+ it "returns an Enumerator" do
+ @enum.should.instance_of?(Enumerator)
+ end
+
+ describe "returned Enumerator" do
+ describe "size" do
+ it "should return nil" do
+ @enum.size.should == nil
+ end
+ end
+ end
+ end
+
+ it "yields each codepoint" do
+ @enum.first(25).should == [
+ 86, 111, 105, 99, 105, 32, 108, 97, 32, 108, 105, 103, 110,
+ 101, 32, 117, 110, 101, 46, 10, 81, 117, 105, 32, 232
+ ]
+ end
+
+ it "yields each codepoint starting from the current position" do
+ @io.pos = 130
+ @enum.to_a.should == [101, 32, 115, 105, 120, 46, 10]
+ end
+
+ it "raises an error if reading invalid sequence" do
+ @io.pos = 60 # inside of a multibyte sequence
+ -> { @enum.first }.should.raise(ArgumentError)
+ end
+
+ it "does not change $_" do
+ $_ = "test"
+ @enum.to_a
+ $_.should == "test"
+ end
+
+ it "raises an IOError when self is not readable" do
+ -> { IOSpecs.closed_io.each_codepoint.to_a }.should.raise(IOError)
+ end
end
describe "IO#each_codepoint" do
@@ -24,7 +71,7 @@ describe "IO#each_codepoint" do
end
it "returns self" do
- @io.each_codepoint { |l| l }.should equal(@io)
+ @io.each_codepoint { |l| l }.should.equal?(@io)
end
end
@@ -38,6 +85,6 @@ describe "IO#each_codepoint" do
end
it "raises an exception at incomplete character before EOF when conversion takes place" do
- -> { @io.each_codepoint {} }.should raise_error(ArgumentError)
+ -> { @io.each_codepoint {} }.should.raise(ArgumentError)
end
end
diff --git a/spec/ruby/core/io/each_line_spec.rb b/spec/ruby/core/io/each_line_spec.rb
index 58d26b325d..bcda4040b8 100644
--- a/spec/ruby/core/io/each_line_spec.rb
+++ b/spec/ruby/core/io/each_line_spec.rb
@@ -1,11 +1,251 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
-require_relative 'shared/each'
describe "IO#each_line" do
- it_behaves_like :io_each, :each_line
+ before :each do
+ @io = IOSpecs.io_fixture "lines.txt"
+ ScratchPad.record []
+ end
+
+ after :each do
+ @io.close if @io
+ end
+
+ describe "with no separator" do
+ it "yields each line to the passed block" do
+ @io.each_line { |s| ScratchPad << s }
+ ScratchPad.recorded.should == IOSpecs.lines
+ end
+
+ it "yields each line starting from the current position" do
+ @io.pos = 41
+ @io.each_line { |s| ScratchPad << s }
+ ScratchPad.recorded.should == IOSpecs.lines[2..-1]
+ end
+
+ it "returns self" do
+ @io.each_line { |l| l }.should.equal?(@io)
+ end
+
+ it "does not change $_" do
+ $_ = "test"
+ @io.each_line { |s| s }
+ $_.should == "test"
+ end
+
+ it "raises an IOError when self is not readable" do
+ -> { IOSpecs.closed_io.each_line {} }.should.raise(IOError)
+ end
+
+ it "makes line count accessible via lineno" do
+ @io.each_line { ScratchPad << @io.lineno }
+ ScratchPad.recorded.should == [ 1,2,3,4,5,6,7,8,9 ]
+ end
+
+ it "makes line count accessible via $." do
+ @io.each_line { ScratchPad << $. }
+ ScratchPad.recorded.should == [ 1,2,3,4,5,6,7,8,9 ]
+ end
+
+ describe "when no block is given" do
+ it "returns an Enumerator" do
+ enum = @io.each_line
+ enum.should.instance_of?(Enumerator)
+
+ enum.each { |l| ScratchPad << l }
+ ScratchPad.recorded.should == IOSpecs.lines
+ end
+
+ describe "returned Enumerator" do
+ describe "size" do
+ it "should return nil" do
+ @io.each_line.size.should == nil
+ end
+ end
+ end
+ end
+ end
+
+ describe "with limit" do
+ describe "when limit is 0" do
+ it "raises an ArgumentError" do
+ # must pass block so Enumerator is evaluated and raises
+ -> { @io.each_line(0){} }.should.raise(ArgumentError)
+ end
+ end
+
+ it "does not accept Integers that don't fit in a C off_t" do
+ -> { @io.each_line(2**128){} }.should.raise(RangeError)
+ end
+ end
+
+ describe "when passed a String containing one space as a separator" do
+ it "uses the passed argument as the line separator" do
+ @io.each_line(" ") { |s| ScratchPad << s }
+ ScratchPad.recorded.should == IOSpecs.lines_space_separator
+ end
+
+ it "does not change $_" do
+ $_ = "test"
+ @io.each_line(" ") { |s| }
+ $_.should == "test"
+ end
+
+ it "tries to convert the passed separator to a String using #to_str" do
+ obj = mock("to_str")
+ obj.stub!(:to_str).and_return(" ")
+
+ @io.each_line(obj) { |l| ScratchPad << l }
+ ScratchPad.recorded.should == IOSpecs.lines_space_separator
+ end
+ end
+
+ describe "when passed nil as a separator" do
+ it "yields self's content starting from the current position when the passed separator is nil" do
+ @io.pos = 100
+ @io.each_line(nil) { |s| ScratchPad << s }
+ ScratchPad.recorded.should == ["qui a linha cinco.\nHere is line six.\n"]
+ end
+ end
+
+ describe "when passed an empty String as a separator" do
+ it "yields each paragraph" do
+ @io.each_line("") { |s| ScratchPad << s }
+ ScratchPad.recorded.should == IOSpecs.paragraphs
+ end
+
+ it "discards leading newlines" do
+ @io.readline
+ @io.readline
+ @io.each_line("") { |s| ScratchPad << s }
+ ScratchPad.recorded.should == IOSpecs.paragraphs[1..-1]
+ end
+ end
+
+ describe "with both separator and limit" do
+ describe "when no block is given" do
+ it "returns an Enumerator" do
+ enum = @io.each_line(nil, 1024)
+ enum.should.instance_of?(Enumerator)
+
+ enum.each { |l| ScratchPad << l }
+ ScratchPad.recorded.should == [IOSpecs.lines.join]
+ end
+
+ describe "returned Enumerator" do
+ describe "size" do
+ it "should return nil" do
+ @io.each_line(nil, 1024).size.should == nil
+ end
+ end
+ end
+ end
+
+ describe "when a block is given" do
+ it "accepts an empty block" do
+ @io.each_line(nil, 1024) {}.should.equal?(@io)
+ end
+
+ describe "when passed nil as a separator" do
+ it "yields self's content starting from the current position when the passed separator is nil" do
+ @io.pos = 100
+ @io.each_line(nil, 1024) { |s| ScratchPad << s }
+ ScratchPad.recorded.should == ["qui a linha cinco.\nHere is line six.\n"]
+ end
+ end
+
+ describe "when passed an empty String as a separator" do
+ it "yields each paragraph" do
+ @io.each_line("", 1024) { |s| ScratchPad << s }
+ ScratchPad.recorded.should == IOSpecs.paragraphs
+ end
+
+ it "discards leading newlines" do
+ @io.readline
+ @io.readline
+ @io.each_line("", 1024) { |s| ScratchPad << s }
+ ScratchPad.recorded.should == IOSpecs.paragraphs[1..-1]
+ end
+ end
+ end
+ end
+
+ describe "when passed chomp" do
+ it "yields each line without trailing newline characters to the passed block" do
+ @io.each_line(chomp: true) { |s| ScratchPad << s }
+ ScratchPad.recorded.should == IOSpecs.lines_without_newline_characters
+ end
+
+ it "raises exception when options passed as Hash" do
+ -> {
+ @io.each_line({ chomp: true }) { |s| }
+ }.should.raise(TypeError)
+
+ -> {
+ @io.each_line("\n", 1, { chomp: true }) { |s| }
+ }.should.raise(ArgumentError, "wrong number of arguments (given 3, expected 0..2)")
+ end
+ end
+
+ describe "when passed chomp and a separator" do
+ it "yields each line without separator to the passed block" do
+ @io.each_line(" ", chomp: true) { |s| ScratchPad << s }
+ ScratchPad.recorded.should == IOSpecs.lines_space_separator_without_trailing_spaces
+ end
+ end
+
+ describe "when passed chomp and empty line as a separator" do
+ it "yields each paragraph without trailing new line characters" do
+ @io.each_line("", 1024, chomp: true) { |s| ScratchPad << s }
+ ScratchPad.recorded.should == IOSpecs.paragraphs_without_trailing_new_line_characters
+ end
+ end
+
+ describe "when passed chomp and nil as a separator" do
+ it "yields self's content" do
+ @io.pos = 100
+ @io.each_line(nil, chomp: true) { |s| ScratchPad << s }
+ ScratchPad.recorded.should == ["qui a linha cinco.\nHere is line six.\n"]
+ end
+ end
+
+ describe "when passed chomp, nil as a separator, and a limit" do
+ it "yields each line of limit size without truncating trailing new line character" do
+ # 43 - is a size of the 1st paragraph in the file
+ @io.each_line(nil, 43, chomp: true) { |s| ScratchPad << s }
+
+ ScratchPad.recorded.should == [
+ "Voici la ligne une.\nQui è la linea due.\n\n\n",
+ "Aquí está la línea tres.\n" + "Hier ist Zeile ",
+ "vier.\n\nEstá aqui a linha cinco.\nHere is li",
+ "ne six.\n"
+ ]
+ end
+ end
+
+ describe "when passed too many arguments" do
+ it "raises ArgumentError" do
+ -> {
+ @io.each_line("", 1, "excess argument", chomp: true) {}
+ }.should.raise(ArgumentError)
+ end
+ end
end
describe "IO#each_line" do
- it_behaves_like :io_each_default_separator, :each_line
+ before :each do
+ @io = IOSpecs.io_fixture "lines.txt"
+ ScratchPad.record []
+ suppress_warning {@sep, $/ = $/, " "}
+ end
+
+ after :each do
+ @io.close if @io
+ suppress_warning {$/ = @sep}
+ end
+
+ it "uses $/ as the default line separator" do
+ @io.each_line { |s| ScratchPad << s }
+ ScratchPad.recorded.should == IOSpecs.lines_space_separator
+ end
end
diff --git a/spec/ruby/core/io/each_spec.rb b/spec/ruby/core/io/each_spec.rb
index 91ecbd19c8..594052256e 100644
--- a/spec/ruby/core/io/each_spec.rb
+++ b/spec/ruby/core/io/each_spec.rb
@@ -1,11 +1,7 @@
require_relative '../../spec_helper'
-require_relative 'fixtures/classes'
-require_relative 'shared/each'
describe "IO#each" do
- it_behaves_like :io_each, :each
-end
-
-describe "IO#each" do
- it_behaves_like :io_each_default_separator, :each
+ it "is an alias of IO#each_line" do
+ IO.instance_method(:each).should == IO.instance_method(:each_line)
+ end
end
diff --git a/spec/ruby/core/io/eof_spec.rb b/spec/ruby/core/io/eof_spec.rb
index b4850df437..561daa4ec3 100644
--- a/spec/ruby/core/io/eof_spec.rb
+++ b/spec/ruby/core/io/eof_spec.rb
@@ -18,7 +18,7 @@ describe "IO#eof?" do
it "raises IOError on stream not opened for reading" do
-> do
File.open(@name, "w") { |f| f.eof? }
- end.should raise_error(IOError)
+ end.should.raise(IOError)
end
end
@@ -67,12 +67,12 @@ describe "IO#eof?" do
end
it "raises IOError on closed stream" do
- -> { IOSpecs.closed_io.eof? }.should raise_error(IOError)
+ -> { IOSpecs.closed_io.eof? }.should.raise(IOError)
end
it "raises IOError on stream closed for reading by close_read" do
@io.close_read
- -> { @io.eof? }.should raise_error(IOError)
+ -> { @io.eof? }.should.raise(IOError)
end
it "returns true on one-byte stream after single-byte read" do
@@ -105,3 +105,9 @@ describe "IO#eof?" do
@r.should.eof?
end
end
+
+describe "IO#eof" do
+ it "is an alias of IO#eof?" do
+ IO.instance_method(:eof).should == IO.instance_method(:eof?)
+ end
+end
diff --git a/spec/ruby/core/io/external_encoding_spec.rb b/spec/ruby/core/io/external_encoding_spec.rb
index 7765c6c0f5..72d246cc2b 100644
--- a/spec/ruby/core/io/external_encoding_spec.rb
+++ b/spec/ruby/core/io/external_encoding_spec.rb
@@ -10,19 +10,19 @@ describe :io_external_encoding_write, shared: true do
it "returns nil" do
@io = new_io @name, @object
Encoding.default_external = Encoding::IBM437
- @io.external_encoding.should be_nil
+ @io.external_encoding.should == nil
end
it "returns the external encoding specified when the instance was created" do
@io = new_io @name, "#{@object}:ibm866"
Encoding.default_external = Encoding::IBM437
- @io.external_encoding.should equal(Encoding::IBM866)
+ @io.external_encoding.should.equal?(Encoding::IBM866)
end
it "returns the encoding set by #set_encoding" do
@io = new_io @name, "#{@object}:ibm866"
@io.set_encoding Encoding::EUC_JP, nil
- @io.external_encoding.should equal(Encoding::EUC_JP)
+ @io.external_encoding.should.equal?(Encoding::EUC_JP)
end
end
@@ -35,19 +35,19 @@ describe :io_external_encoding_write, shared: true do
it "returns the value of Encoding.default_external when the instance was created" do
@io = new_io @name, @object
Encoding.default_external = Encoding::UTF_8
- @io.external_encoding.should equal(Encoding::IBM437)
+ @io.external_encoding.should.equal?(Encoding::IBM437)
end
it "returns the external encoding specified when the instance was created" do
@io = new_io @name, "#{@object}:ibm866"
Encoding.default_external = Encoding::IBM437
- @io.external_encoding.should equal(Encoding::IBM866)
+ @io.external_encoding.should.equal?(Encoding::IBM866)
end
it "returns the encoding set by #set_encoding" do
@io = new_io @name, "#{@object}:ibm866"
@io.set_encoding Encoding::EUC_JP, nil
- @io.external_encoding.should equal(Encoding::EUC_JP)
+ @io.external_encoding.should.equal?(Encoding::EUC_JP)
end
end
@@ -60,19 +60,19 @@ describe :io_external_encoding_write, shared: true do
it "returns the value of Encoding.default_external when the instance was created" do
@io = new_io @name, @object
Encoding.default_external = Encoding::UTF_8
- @io.external_encoding.should equal(Encoding::IBM866)
+ @io.external_encoding.should.equal?(Encoding::IBM866)
end
it "returns the external encoding specified when the instance was created" do
@io = new_io @name, "#{@object}:ibm866"
Encoding.default_external = Encoding::IBM437
- @io.external_encoding.should equal(Encoding::IBM866)
+ @io.external_encoding.should.equal?(Encoding::IBM866)
end
it "returns the encoding set by #set_encoding" do
@io = new_io @name, "#{@object}:ibm866"
@io.set_encoding Encoding::EUC_JP, nil
- @io.external_encoding.should equal(Encoding::EUC_JP)
+ @io.external_encoding.should.equal?(Encoding::EUC_JP)
end
end
end
@@ -97,7 +97,7 @@ describe "IO#external_encoding" do
it "can be retrieved from a closed stream" do
io = IOSpecs.io_fixture("lines.txt", "r")
io.close
- io.external_encoding.should equal(Encoding.default_external)
+ io.external_encoding.should.equal?(Encoding.default_external)
end
describe "with 'r' mode" do
@@ -109,25 +109,25 @@ describe "IO#external_encoding" do
it "returns Encoding.default_external if the external encoding is not set" do
@io = new_io @name, "r"
- @io.external_encoding.should equal(Encoding::IBM866)
+ @io.external_encoding.should.equal?(Encoding::IBM866)
end
it "returns Encoding.default_external when that encoding is changed after the instance is created" do
@io = new_io @name, "r"
Encoding.default_external = Encoding::IBM437
- @io.external_encoding.should equal(Encoding::IBM437)
+ @io.external_encoding.should.equal?(Encoding::IBM437)
end
it "returns the external encoding specified when the instance was created" do
@io = new_io @name, "r:utf-8"
Encoding.default_external = Encoding::IBM437
- @io.external_encoding.should equal(Encoding::UTF_8)
+ @io.external_encoding.should.equal?(Encoding::UTF_8)
end
it "returns the encoding set by #set_encoding" do
@io = new_io @name, "r:utf-8"
@io.set_encoding Encoding::EUC_JP, nil
- @io.external_encoding.should equal(Encoding::EUC_JP)
+ @io.external_encoding.should.equal?(Encoding::EUC_JP)
end
end
@@ -140,19 +140,19 @@ describe "IO#external_encoding" do
it "returns the value of Encoding.default_external when the instance was created" do
@io = new_io @name, "r"
Encoding.default_external = Encoding::IBM437
- @io.external_encoding.should equal(Encoding::IBM866)
+ @io.external_encoding.should.equal?(Encoding::IBM866)
end
it "returns the external encoding specified when the instance was created" do
@io = new_io @name, "r:utf-8"
Encoding.default_external = Encoding::IBM437
- @io.external_encoding.should equal(Encoding::UTF_8)
+ @io.external_encoding.should.equal?(Encoding::UTF_8)
end
it "returns the encoding set by #set_encoding" do
@io = new_io @name, "r:utf-8"
@io.set_encoding Encoding::EUC_JP, nil
- @io.external_encoding.should equal(Encoding::EUC_JP)
+ @io.external_encoding.should.equal?(Encoding::EUC_JP)
end
end
@@ -166,13 +166,13 @@ describe "IO#external_encoding" do
it "returns the external encoding specified when the instance was created" do
@io = new_io @name, "r:utf-8"
Encoding.default_external = Encoding::IBM437
- @io.external_encoding.should equal(Encoding::UTF_8)
+ @io.external_encoding.should.equal?(Encoding::UTF_8)
end
it "returns the encoding set by #set_encoding" do
@io = new_io @name, "r:utf-8"
@io.set_encoding Encoding::EUC_JP, nil
- @io.external_encoding.should equal(Encoding::EUC_JP)
+ @io.external_encoding.should.equal?(Encoding::EUC_JP)
end
end
end
@@ -180,12 +180,12 @@ describe "IO#external_encoding" do
describe "with 'rb' mode" do
it "returns Encoding::BINARY" do
@io = new_io @name, "rb"
- @io.external_encoding.should equal(Encoding::BINARY)
+ @io.external_encoding.should.equal?(Encoding::BINARY)
end
it "returns the external encoding specified by the mode argument" do
@io = new_io @name, "rb:ibm437"
- @io.external_encoding.should equal(Encoding::IBM437)
+ @io.external_encoding.should.equal?(Encoding::IBM437)
end
end
@@ -200,12 +200,12 @@ describe "IO#external_encoding" do
describe "with 'wb' mode" do
it "returns Encoding::BINARY" do
@io = new_io @name, "wb"
- @io.external_encoding.should equal(Encoding::BINARY)
+ @io.external_encoding.should.equal?(Encoding::BINARY)
end
it "returns the external encoding specified by the mode argument" do
@io = new_io @name, "wb:ibm437"
- @io.external_encoding.should equal(Encoding::IBM437)
+ @io.external_encoding.should.equal?(Encoding::IBM437)
end
end
diff --git a/spec/ruby/core/io/fcntl_spec.rb b/spec/ruby/core/io/fcntl_spec.rb
index 30b4876fe3..be6d06c672 100644
--- a/spec/ruby/core/io/fcntl_spec.rb
+++ b/spec/ruby/core/io/fcntl_spec.rb
@@ -3,6 +3,6 @@ require_relative 'fixtures/classes'
describe "IO#fcntl" do
it "raises IOError on closed stream" do
- -> { IOSpecs.closed_io.fcntl(5, 5) }.should raise_error(IOError)
+ -> { IOSpecs.closed_io.fcntl(5, 5) }.should.raise(IOError)
end
end
diff --git a/spec/ruby/core/io/fileno_spec.rb b/spec/ruby/core/io/fileno_spec.rb
index 647609bf42..22fd68d166 100644
--- a/spec/ruby/core/io/fileno_spec.rb
+++ b/spec/ruby/core/io/fileno_spec.rb
@@ -7,6 +7,6 @@ describe "IO#fileno" do
end
it "raises IOError on closed stream" do
- -> { IOSpecs.closed_io.fileno }.should raise_error(IOError)
+ -> { IOSpecs.closed_io.fileno }.should.raise(IOError)
end
end
diff --git a/spec/ruby/core/io/flush_spec.rb b/spec/ruby/core/io/flush_spec.rb
index f7d5ba77fc..4c3e8d12af 100644
--- a/spec/ruby/core/io/flush_spec.rb
+++ b/spec/ruby/core/io/flush_spec.rb
@@ -3,7 +3,7 @@ require_relative 'fixtures/classes'
describe "IO#flush" do
it "raises IOError on closed stream" do
- -> { IOSpecs.closed_io.flush }.should raise_error(IOError)
+ -> { IOSpecs.closed_io.flush }.should.raise(IOError)
end
describe "on a pipe" do
@@ -29,8 +29,8 @@ describe "IO#flush" do
@w.write "foo"
@r.close
- -> { @w.flush }.should raise_error(Errno::EPIPE, /Broken pipe/)
- -> { @w.close }.should raise_error(Errno::EPIPE, /Broken pipe/)
+ -> { @w.flush }.should.raise(Errno::EPIPE, /Broken pipe/)
+ -> { @w.close }.should.raise(Errno::EPIPE, /Broken pipe/)
end
end
end
diff --git a/spec/ruby/core/io/foreach_spec.rb b/spec/ruby/core/io/foreach_spec.rb
index c361d27879..ccd2f25517 100644
--- a/spec/ruby/core/io/foreach_spec.rb
+++ b/spec/ruby/core/io/foreach_spec.rb
@@ -14,45 +14,45 @@ describe "IO.foreach" do
IO.foreach(@name) { $..should == @count += 1 }
end
- describe "when the filename starts with |" do
- it "gets data from the standard out of the subprocess" do
- cmd = "|sh -c 'echo hello;echo line2'"
- platform_is :windows do
- cmd = "|cmd.exe /C echo hello&echo line2"
- end
+ ruby_version_is ""..."4.0" do
+ describe "when the filename starts with |" do
+ it "gets data from the standard out of the subprocess" do
+ cmd = "|sh -c 'echo hello;echo line2'"
+ 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 }
+ suppress_warning do # https://bugs.ruby-lang.org/issues/19630
+ IO.foreach(cmd) { |l| ScratchPad << l }
+ end
+ ScratchPad.recorded.should == ["hello\n", "line2\n"]
end
- ScratchPad.recorded.should == ["hello\n", "line2\n"]
- end
- platform_is_not :windows do
- it "gets data from a fork when passed -" do
- parent_pid = $$
+ guard -> { Process.respond_to?(:fork) } 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
+ suppress_warning do # https://bugs.ruby-lang.org/issues/19630
+ IO.foreach("|-") { |l| ScratchPad << l }
+ end
- if $$ == parent_pid
- ScratchPad.recorded.should == ["hello\n", "from a fork\n"]
- else # child
- puts "hello"
- puts "from a fork"
- exit!
+ if $$ == parent_pid
+ ScratchPad.recorded.should == ["hello\n", "from a fork\n"]
+ else # child
+ puts "hello"
+ puts "from a fork"
+ exit!
+ end
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
+ # 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
@@ -73,12 +73,12 @@ describe "IO.foreach" do
it "sets $_ to nil" do
$_ = "test"
IO.foreach(@name) { }
- $_.should be_nil
+ $_.should == nil
end
describe "when no block is given" do
it "returns an Enumerator" do
- IO.foreach(@name).should be_an_instance_of(Enumerator)
+ IO.foreach(@name).should.instance_of?(Enumerator)
IO.foreach(@name).to_a.should == IOSpecs.lines
end
diff --git a/spec/ruby/core/io/fsync_spec.rb b/spec/ruby/core/io/fsync_spec.rb
index 6e6123de94..0317cbc805 100644
--- a/spec/ruby/core/io/fsync_spec.rb
+++ b/spec/ruby/core/io/fsync_spec.rb
@@ -12,7 +12,7 @@ describe "IO#fsync" do
end
it "raises an IOError on closed stream" do
- -> { IOSpecs.closed_io.fsync }.should raise_error(IOError)
+ -> { IOSpecs.closed_io.fsync }.should.raise(IOError)
end
it "writes the buffered data to permanent storage" do
diff --git a/spec/ruby/core/io/getbyte_spec.rb b/spec/ruby/core/io/getbyte_spec.rb
index b4351160e6..668d81519c 100644
--- a/spec/ruby/core/io/getbyte_spec.rb
+++ b/spec/ruby/core/io/getbyte_spec.rb
@@ -23,7 +23,7 @@ describe "IO#getbyte" do
end
it "raises an IOError on closed stream" do
- -> { IOSpecs.closed_io.getbyte }.should raise_error(IOError)
+ -> { IOSpecs.closed_io.getbyte }.should.raise(IOError)
end
end
@@ -53,6 +53,6 @@ describe "IO#getbyte" do
end
it "raises an IOError if the stream is not readable" do
- -> { @io.getbyte }.should raise_error(IOError)
+ -> { @io.getbyte }.should.raise(IOError)
end
end
diff --git a/spec/ruby/core/io/getc_spec.rb b/spec/ruby/core/io/getc_spec.rb
index 3949b5cb28..3be86203c0 100644
--- a/spec/ruby/core/io/getc_spec.rb
+++ b/spec/ruby/core/io/getc_spec.rb
@@ -19,11 +19,11 @@ describe "IO#getc" do
it "returns nil when invoked at the end of the stream" do
@io.read
- @io.getc.should be_nil
+ @io.getc.should == nil
end
it "raises IOError on closed stream" do
- -> { IOSpecs.closed_io.getc }.should raise_error(IOError)
+ -> { IOSpecs.closed_io.getc }.should.raise(IOError)
end
end
@@ -37,6 +37,6 @@ describe "IO#getc" do
end
it "returns nil on empty stream" do
- @io.getc.should be_nil
+ @io.getc.should == nil
end
end
diff --git a/spec/ruby/core/io/gets_spec.rb b/spec/ruby/core/io/gets_spec.rb
index ca64bf860e..ce3ee73b94 100644
--- a/spec/ruby/core/io/gets_spec.rb
+++ b/spec/ruby/core/io/gets_spec.rb
@@ -27,7 +27,7 @@ describe "IO#gets" do
it "sets $_ to nil after the last line has been read" do
while @io.gets
end
- $_.should be_nil
+ $_.should == nil
end
it "returns nil if called at the end of the stream" do
@@ -36,7 +36,7 @@ describe "IO#gets" do
end
it "raises IOError on closed stream" do
- -> { IOSpecs.closed_io.gets }.should raise_error(IOError)
+ -> { IOSpecs.closed_io.gets }.should.raise(IOError)
end
describe "with no separator" do
@@ -156,11 +156,11 @@ describe "IO#gets" do
end
it "raises exception when options passed as Hash" do
- -> { @io.gets({ chomp: true }) }.should raise_error(TypeError)
+ -> { @io.gets({ chomp: true }) }.should.raise(TypeError)
-> {
@io.gets("\n", 1, { chomp: true })
- }.should raise_error(ArgumentError, "wrong number of arguments (given 3, expected 0..2)")
+ }.should.raise(ArgumentError, "wrong number of arguments (given 3, expected 0..2)")
end
end
end
@@ -175,11 +175,11 @@ describe "IO#gets" do
end
it "raises an IOError if the stream is opened for append only" do
- -> { File.open(@name, "a:utf-8") { |f| f.gets } }.should raise_error(IOError)
+ -> { File.open(@name, "a:utf-8") { |f| f.gets } }.should.raise(IOError)
end
it "raises an IOError if the stream is opened for writing only" do
- -> { File.open(@name, "w:utf-8") { |f| f.gets } }.should raise_error(IOError)
+ -> { File.open(@name, "w:utf-8") { |f| f.gets } }.should.raise(IOError)
end
end
@@ -251,7 +251,7 @@ describe "IO#gets" do
end
it "does not accept limit that doesn't fit in a C off_t" do
- -> { @io.gets(2**128) }.should raise_error(RangeError)
+ -> { @io.gets(2**128) }.should.raise(RangeError)
end
end
@@ -338,23 +338,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 "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
end
diff --git a/spec/ruby/core/io/initialize_spec.rb b/spec/ruby/core/io/initialize_spec.rb
index 026252a13d..3425e5ac37 100644
--- a/spec/ruby/core/io/initialize_spec.rb
+++ b/spec/ruby/core/io/initialize_spec.rb
@@ -35,26 +35,26 @@ describe "IO#initialize" do
-> {
@io.send(:initialize, fd, "w", {flags: File::CREAT})
- }.should raise_error(ArgumentError, "wrong number of arguments (given 3, expected 1..2)")
+ }.should.raise(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)
+ -> { @io.send :initialize, STDOUT, 'w' }.should.raise(TypeError)
end
it "raises a TypeError when passed nil" do
- -> { @io.send :initialize, nil, 'w' }.should raise_error(TypeError)
+ -> { @io.send :initialize, nil, 'w' }.should.raise(TypeError)
end
it "raises a TypeError when passed a String" do
- -> { @io.send :initialize, "4", 'w' }.should raise_error(TypeError)
+ -> { @io.send :initialize, "4", 'w' }.should.raise(TypeError)
end
it "raises IOError on closed stream" do
- -> { @io.send :initialize, IOSpecs.closed_io.fileno }.should raise_error(IOError)
+ -> { @io.send :initialize, IOSpecs.closed_io.fileno }.should.raise(IOError)
end
it "raises an Errno::EBADF when given an invalid file descriptor" do
- -> { @io.send :initialize, -1, 'w' }.should raise_error(Errno::EBADF)
+ -> { @io.send :initialize, -1, 'w' }.should.raise(Errno::EBADF)
end
end
diff --git a/spec/ruby/core/io/inspect_spec.rb b/spec/ruby/core/io/inspect_spec.rb
index c653c307c4..37dc459f22 100644
--- a/spec/ruby/core/io/inspect_spec.rb
+++ b/spec/ruby/core/io/inspect_spec.rb
@@ -8,13 +8,13 @@ describe "IO#inspect" do
it "contains the file descriptor number" do
@r, @w = IO.pipe
- @r.inspect.should include("fd #{@r.fileno}")
+ @r.inspect.should.include?("fd #{@r.fileno}")
end
it "contains \"(closed)\" if the stream is closed" do
@r, @w = IO.pipe
@r.close
- @r.inspect.should include("(closed)")
+ @r.inspect.should.include?("(closed)")
end
it "reports IO as its Method object's owner" do
diff --git a/spec/ruby/core/io/internal_encoding_spec.rb b/spec/ruby/core/io/internal_encoding_spec.rb
index 7a583d4bcb..9963a93f33 100644
--- a/spec/ruby/core/io/internal_encoding_spec.rb
+++ b/spec/ruby/core/io/internal_encoding_spec.rb
@@ -9,25 +9,25 @@ describe :io_internal_encoding, shared: true do
it "returns nil if the internal encoding is not set" do
@io = new_io @name, @object
- @io.internal_encoding.should be_nil
+ @io.internal_encoding.should == nil
end
it "returns nil if Encoding.default_internal is changed after the instance is created" do
@io = new_io @name, @object
Encoding.default_internal = Encoding::IBM437
- @io.internal_encoding.should be_nil
+ @io.internal_encoding.should == nil
end
it "returns the value set when the instance was created" do
@io = new_io @name, "#{@object}:utf-8:euc-jp"
Encoding.default_internal = Encoding::IBM437
- @io.internal_encoding.should equal(Encoding::EUC_JP)
+ @io.internal_encoding.should.equal?(Encoding::EUC_JP)
end
it "returns the value set by #set_encoding" do
@io = new_io @name, @object
@io.set_encoding(Encoding::US_ASCII, Encoding::IBM437)
- @io.internal_encoding.should equal(Encoding::IBM437)
+ @io.internal_encoding.should.equal?(Encoding::IBM437)
end
end
@@ -39,13 +39,13 @@ describe :io_internal_encoding, shared: true do
it "returns nil" do
@io = new_io @name, @object
- @io.internal_encoding.should be_nil
+ @io.internal_encoding.should == nil
end
it "returns nil regardless of Encoding.default_internal changes" do
@io = new_io @name, @object
Encoding.default_internal = Encoding::IBM437
- @io.internal_encoding.should be_nil
+ @io.internal_encoding.should == nil
end
end
@@ -57,41 +57,41 @@ describe :io_internal_encoding, shared: true do
it "returns the value of Encoding.default_internal when the instance was created if the internal encoding is not set" do
@io = new_io @name, @object
- @io.internal_encoding.should equal(Encoding::IBM866)
+ @io.internal_encoding.should.equal?(Encoding::IBM866)
end
it "does not change when Encoding.default_internal is changed" do
@io = new_io @name, @object
Encoding.default_internal = Encoding::IBM437
- @io.internal_encoding.should equal(Encoding::IBM866)
+ @io.internal_encoding.should.equal?(Encoding::IBM866)
end
it "returns the internal encoding set when the instance was created" do
@io = new_io @name, "#{@object}:utf-8:euc-jp"
- @io.internal_encoding.should equal(Encoding::EUC_JP)
+ @io.internal_encoding.should.equal?(Encoding::EUC_JP)
end
it "does not change when set and Encoding.default_internal is changed" do
@io = new_io @name, "#{@object}:utf-8:euc-jp"
Encoding.default_internal = Encoding::IBM437
- @io.internal_encoding.should equal(Encoding::EUC_JP)
+ @io.internal_encoding.should.equal?(Encoding::EUC_JP)
end
it "returns the value set by #set_encoding" do
@io = new_io @name, @object
@io.set_encoding(Encoding::US_ASCII, Encoding::IBM437)
- @io.internal_encoding.should equal(Encoding::IBM437)
+ @io.internal_encoding.should.equal?(Encoding::IBM437)
end
it "returns nil when Encoding.default_external is BINARY and the internal encoding is not set" do
Encoding.default_external = Encoding::BINARY
@io = new_io @name, @object
- @io.internal_encoding.should be_nil
+ @io.internal_encoding.should == nil
end
it "returns nil when the external encoding is BINARY and the internal encoding is not set" do
@io = new_io @name, "#{@object}:binary"
- @io.internal_encoding.should be_nil
+ @io.internal_encoding.should == nil
end
end
end
@@ -116,7 +116,7 @@ describe "IO#internal_encoding" do
it "can be retrieved from a closed stream" do
io = IOSpecs.io_fixture("lines.txt", "r")
io.close
- io.internal_encoding.should equal(Encoding.default_internal)
+ io.internal_encoding.should.equal?(Encoding.default_internal)
end
describe "with 'r' mode" do
diff --git a/spec/ruby/core/io/ioctl_spec.rb b/spec/ruby/core/io/ioctl_spec.rb
index 3f7b5ad5d7..15a5d6ec22 100644
--- a/spec/ruby/core/io/ioctl_spec.rb
+++ b/spec/ruby/core/io/ioctl_spec.rb
@@ -4,7 +4,7 @@ require_relative 'fixtures/classes'
describe "IO#ioctl" do
platform_is_not :windows do
it "raises IOError on closed stream" do
- -> { IOSpecs.closed_io.ioctl(5, 5) }.should raise_error(IOError)
+ -> { IOSpecs.closed_io.ioctl(5, 5) }.should.raise(IOError)
end
end
@@ -15,7 +15,7 @@ describe "IO#ioctl" do
buffer = +''
# FIONREAD in /usr/include/asm-generic/ioctls.h
f.ioctl 0x541B, buffer
- buffer.unpack('I').first.should be_kind_of(Integer)
+ buffer.unpack('I').first.should.is_a?(Integer)
end
end
end
@@ -25,7 +25,7 @@ describe "IO#ioctl" do
-> {
# TIOCGWINSZ in /usr/include/asm-generic/ioctls.h
f.ioctl 0x5413, nil
- }.should raise_error(SystemCallError)
+ }.should.raise(SystemCallError)
end
end
end
diff --git a/spec/ruby/core/io/isatty_spec.rb b/spec/ruby/core/io/isatty_spec.rb
index 3b6c69b190..60b97d21be 100644
--- a/spec/ruby/core/io/isatty_spec.rb
+++ b/spec/ruby/core/io/isatty_spec.rb
@@ -1,6 +1,7 @@
require_relative '../../spec_helper'
-require_relative 'shared/tty'
describe "IO#isatty" do
- it_behaves_like :io_tty, :isatty
+ it "is an alias of IO#tty?" do
+ IO.instance_method(:isatty).should == IO.instance_method(:tty?)
+ end
end
diff --git a/spec/ruby/core/io/lineno_spec.rb b/spec/ruby/core/io/lineno_spec.rb
index e82cdd9f17..93b505652a 100644
--- a/spec/ruby/core/io/lineno_spec.rb
+++ b/spec/ruby/core/io/lineno_spec.rb
@@ -11,14 +11,14 @@ describe "IO#lineno" do
end
it "raises an IOError on a closed stream" do
- -> { IOSpecs.closed_io.lineno }.should raise_error(IOError)
+ -> { IOSpecs.closed_io.lineno }.should.raise(IOError)
end
it "raises an IOError on a write-only stream" do
name = tmp("io_lineno.txt")
begin
File.open(name, 'w') do |f|
- -> { f.lineno }.should raise_error(IOError)
+ -> { f.lineno }.should.raise(IOError)
end
ensure
rm_r name
@@ -29,7 +29,7 @@ describe "IO#lineno" do
cmd = platform_is(:windows) ? 'rem' : 'cat'
IO.popen(cmd, 'r+') do |p|
p.close_read
- -> { p.lineno }.should raise_error(IOError)
+ -> { p.lineno }.should.raise(IOError)
end
end
@@ -56,14 +56,14 @@ describe "IO#lineno=" do
end
it "raises an IOError on a closed stream" do
- -> { IOSpecs.closed_io.lineno = 5 }.should raise_error(IOError)
+ -> { IOSpecs.closed_io.lineno = 5 }.should.raise(IOError)
end
it "raises an IOError on a write-only stream" do
name = tmp("io_lineno.txt")
begin
File.open(name, 'w') do |f|
- -> { f.lineno = 0 }.should raise_error(IOError)
+ -> { f.lineno = 0 }.should.raise(IOError)
end
ensure
rm_r name
@@ -74,7 +74,7 @@ describe "IO#lineno=" do
cmd = platform_is(:windows) ? 'rem' : 'cat'
IO.popen(cmd, 'r+') do |p|
p.close_read
- -> { p.lineno = 0 }.should raise_error(IOError)
+ -> { p.lineno = 0 }.should.raise(IOError)
end
end
@@ -95,12 +95,12 @@ describe "IO#lineno=" do
end
it "raises TypeError if cannot convert argument to Integer implicitly" do
- -> { @io.lineno = "1" }.should raise_error(TypeError, 'no implicit conversion of String into Integer')
- -> { @io.lineno = nil }.should raise_error(TypeError, 'no implicit conversion from nil to integer')
+ -> { @io.lineno = "1" }.should.raise(TypeError, 'no implicit conversion of String into Integer')
+ -> { @io.lineno = nil }.should raise_consistent_error(TypeError, 'no implicit conversion of nil into Integer')
end
it "does not accept Integers that don't fit in a C int" do
- -> { @io.lineno = 2**32 }.should raise_error(RangeError)
+ -> { @io.lineno = 2**32 }.should.raise(RangeError)
end
it "sets the current line number to the given value" do
diff --git a/spec/ruby/core/io/open_spec.rb b/spec/ruby/core/io/open_spec.rb
index d151da9ce5..ff22d14685 100644
--- a/spec/ruby/core/io/open_spec.rb
+++ b/spec/ruby/core/io/open_spec.rb
@@ -32,7 +32,7 @@ describe "IO.open" do
super()
ScratchPad.record :called
end
- io.closed?.should be_false
+ io.closed?.should == false
end
ScratchPad.recorded.should == :called
end
@@ -46,7 +46,7 @@ describe "IO.open" do
end
raise Exception
end
- end.should raise_error(Exception)
+ end.should.raise(Exception)
ScratchPad.recorded.should == :called
end
@@ -59,7 +59,7 @@ describe "IO.open" do
raise Exception
end
end
- end.should raise_error(Exception)
+ end.should.raise(Exception)
ScratchPad.recorded.should == :called
end
@@ -72,7 +72,7 @@ describe "IO.open" do
raise StandardError
end
end
- end.should raise_error(StandardError)
+ end.should.raise(StandardError)
ScratchPad.recorded.should == :called
end
diff --git a/spec/ruby/core/io/output_spec.rb b/spec/ruby/core/io/output_spec.rb
index 2aafb305f4..0decf8c95b 100644
--- a/spec/ruby/core/io/output_spec.rb
+++ b/spec/ruby/core/io/output_spec.rb
@@ -16,7 +16,7 @@ describe "IO#<<" do
it "raises an error if the stream is closed" do
io = IOSpecs.closed_io
- -> { io << "test" }.should raise_error(IOError)
+ -> { io << "test" }.should.raise(IOError)
end
it "returns self" do
diff --git a/spec/ruby/core/io/pid_spec.rb b/spec/ruby/core/io/pid_spec.rb
index bc09fe7c3b..04956887ff 100644
--- a/spec/ruby/core/io/pid_spec.rb
+++ b/spec/ruby/core/io/pid_spec.rb
@@ -25,11 +25,11 @@ describe "IO#pid" do
end
it "returns the ID of a process associated with stream" do
- @io.pid.should_not be_nil
+ @io.pid.should_not == nil
end
it "raises an IOError on closed stream" do
@io.close
- -> { @io.pid }.should raise_error(IOError)
+ -> { @io.pid }.should.raise(IOError)
end
end
diff --git a/spec/ruby/core/io/pipe_spec.rb b/spec/ruby/core/io/pipe_spec.rb
index aee0d9003f..9f1b01a5cd 100644
--- a/spec/ruby/core/io/pipe_spec.rb
+++ b/spec/ruby/core/io/pipe_spec.rb
@@ -16,14 +16,14 @@ describe "IO.pipe" do
it "returns two IO objects" do
@r, @w = IO.pipe
- @r.should be_kind_of(IO)
- @w.should be_kind_of(IO)
+ @r.should.is_a?(IO)
+ @w.should.is_a?(IO)
end
it "returns instances of a subclass when called on a subclass" do
@r, @w = IOSpecs::SubIO.pipe
- @r.should be_an_instance_of(IOSpecs::SubIO)
- @w.should be_an_instance_of(IOSpecs::SubIO)
+ @r.should.instance_of?(IOSpecs::SubIO)
+ @w.should.instance_of?(IOSpecs::SubIO)
end
it "does not use IO.new method to create pipes and allows its overriding" do
@@ -33,8 +33,8 @@ describe "IO.pipe" do
@r, @w = IOSpecs::SubIOWithRedefinedNew.pipe
ScratchPad.recorded.should == [:call_original_initialize, :call_original_initialize] # called 2 times - for each pipe (r and w)
- @r.should be_an_instance_of(IOSpecs::SubIOWithRedefinedNew)
- @w.should be_an_instance_of(IOSpecs::SubIOWithRedefinedNew)
+ @r.should.instance_of?(IOSpecs::SubIOWithRedefinedNew)
+ @w.should.instance_of?(IOSpecs::SubIOWithRedefinedNew)
end
end
@@ -42,8 +42,8 @@ describe "IO.pipe" do
describe "passed a block" do
it "yields two IO objects" do
IO.pipe do |r, w|
- r.should be_kind_of(IO)
- w.should be_kind_of(IO)
+ r.should.is_a?(IO)
+ w.should.is_a?(IO)
end
end
@@ -67,7 +67,7 @@ describe "IO.pipe" do
w = _w
raise RuntimeError
end
- end.should raise_error(RuntimeError)
+ end.should.raise(RuntimeError)
r.should.closed?
w.should.closed?
end
@@ -100,7 +100,7 @@ describe "IO.pipe" do
IO.pipe do |r, w|
r.external_encoding.should == Encoding::ISO_8859_1
- r.internal_encoding.should be_nil
+ r.internal_encoding.should == nil
end
end
@@ -120,14 +120,14 @@ describe "IO.pipe" do
IO.pipe do |r, w|
r.external_encoding.should == Encoding::UTF_8
- r.internal_encoding.should be_nil
+ r.internal_encoding.should == nil
end
end
it "sets the external encoding of the read end when passed an Encoding argument" do
IO.pipe(Encoding::UTF_8) do |r, w|
r.external_encoding.should == Encoding::UTF_8
- r.internal_encoding.should be_nil
+ r.internal_encoding.should == nil
end
end
@@ -141,14 +141,14 @@ describe "IO.pipe" do
it "sets the external encoding of the read end when passed the name of an Encoding" do
IO.pipe("UTF-8") do |r, w|
r.external_encoding.should == Encoding::UTF_8
- r.internal_encoding.should be_nil
+ r.internal_encoding.should == nil
end
end
it "accepts 'bom|' prefix for external encoding" do
IO.pipe("BOM|UTF-8") do |r, w|
r.external_encoding.should == Encoding::UTF_8
- r.internal_encoding.should be_nil
+ r.internal_encoding.should == nil
end
end
@@ -213,13 +213,13 @@ describe "IO.pipe" do
it "sets no external encoding for the write end" do
IO.pipe(Encoding::UTF_8) do |r, w|
- w.external_encoding.should be_nil
+ w.external_encoding.should == nil
end
end
it "sets no internal encoding for the write end" do
IO.pipe(Encoding::UTF_8) do |r, w|
- w.external_encoding.should be_nil
+ w.external_encoding.should == nil
end
end
end
diff --git a/spec/ruby/core/io/popen_spec.rb b/spec/ruby/core/io/popen_spec.rb
index 6043862614..b5747bf255 100644
--- a/spec/ruby/core/io/popen_spec.rb
+++ b/spec/ruby/core/io/popen_spec.rb
@@ -21,7 +21,7 @@ describe "IO.popen" do
it "returns an open IO" do
@io = IO.popen(ruby_cmd('exit'), "r")
- @io.closed?.should be_false
+ @io.closed?.should == false
end
it "reads a read-only pipe" do
@@ -31,7 +31,7 @@ describe "IO.popen" do
it "raises IOError when writing a read-only pipe" do
@io = IO.popen('echo foo', "r")
- -> { @io.write('bar') }.should raise_error(IOError)
+ -> { @io.write('bar') }.should.raise(IOError)
@io.read.should == "foo\n"
end
@@ -52,7 +52,7 @@ describe "IO.popen" do
it "raises IOError when reading a write-only pipe" do
@io = IO.popen(ruby_cmd('IO.copy_stream(STDIN,STDOUT)'), "w")
- -> { @io.read }.should raise_error(IOError)
+ -> { @io.read }.should.raise(IOError)
end
it "reads and writes a read/write pipe" do
@@ -86,7 +86,7 @@ describe "IO.popen" do
it "returns an instance of a subclass when called on a subclass" do
@io = IOSpecs::SubIO.popen(ruby_cmd('exit'), "r")
- @io.should be_an_instance_of(IOSpecs::SubIO)
+ @io.should.instance_of?(IOSpecs::SubIO)
end
it "coerces mode argument with #to_str" do
@@ -114,24 +114,24 @@ describe "IO.popen" do
describe "with a block" do
it "yields an open IO to the block" do
IO.popen(ruby_cmd('exit'), "r") do |io|
- io.closed?.should be_false
+ io.closed?.should == false
end
end
it "yields an instance of a subclass when called on a subclass" do
IOSpecs::SubIO.popen(ruby_cmd('exit'), "r") do |io|
- io.should be_an_instance_of(IOSpecs::SubIO)
+ io.should.instance_of?(IOSpecs::SubIO)
end
end
it "closes the IO after yielding" do
io = IO.popen(ruby_cmd('exit'), "r") { |_io| _io }
- io.closed?.should be_true
+ io.closed?.should == true
end
it "allows the IO to be closed inside the block" do
io = IO.popen(ruby_cmd('exit'), 'r') { |_io| _io.close; _io }
- io.closed?.should be_true
+ io.closed?.should == true
end
it "returns the value of the block" do
@@ -169,7 +169,7 @@ describe "IO.popen" do
it "sets the internal encoding to nil if it's the same as the external encoding" do
@io = IO.popen(ruby_cmd('exit'), external_encoding: Encoding::EUC_JP,
internal_encoding: Encoding::EUC_JP)
- @io.internal_encoding.should be_nil
+ @io.internal_encoding.should == nil
end
context "with a leading ENV Hash" do
diff --git a/spec/ruby/core/io/pos_spec.rb b/spec/ruby/core/io/pos_spec.rb
index e6cda2643d..bbe25ce97b 100644
--- a/spec/ruby/core/io/pos_spec.rb
+++ b/spec/ruby/core/io/pos_spec.rb
@@ -3,7 +3,37 @@ require_relative 'fixtures/classes'
require_relative 'shared/pos'
describe "IO#pos" do
- it_behaves_like :io_pos, :pos
+ before :each do
+ @fname = tmp('test.txt')
+ File.open(@fname, 'w') { |f| f.write "123" }
+ end
+
+ after :each do
+ rm_r @fname
+ end
+
+ it "gets the offset" do
+ File.open @fname do |f|
+ f.pos.should == 0
+ f.read 1
+ f.pos.should == 1
+ f.read 2
+ f.pos.should == 3
+ end
+ end
+
+ it "raises IOError on closed stream" do
+ -> { IOSpecs.closed_io.pos }.should.raise(IOError)
+ end
+
+ it "resets #eof?" do
+ open @fname do |io|
+ io.read 1
+ io.read 1
+ io.pos
+ io.should_not.eof?
+ end
+ end
end
describe "IO#pos=" do
diff --git a/spec/ruby/core/io/pread_spec.rb b/spec/ruby/core/io/pread_spec.rb
index dc7bcedf3e..cfb8dc4c68 100644
--- a/spec/ruby/core/io/pread_spec.rb
+++ b/spec/ruby/core/io/pread_spec.rb
@@ -1,140 +1,138 @@
# -*- encoding: utf-8 -*-
require_relative '../../spec_helper'
-guard -> { platform_is_not :windows or ruby_version_is "3.3" } do
- describe "IO#pread" do
- before :each do
- @fname = tmp("io_pread.txt")
- @contents = "1234567890"
- touch(@fname) { |f| f.write @contents }
- @file = File.open(@fname, "r+")
- end
+describe "IO#pread" do
+ before :each do
+ @fname = tmp("io_pread.txt")
+ @contents = "1234567890"
+ touch(@fname) { |f| f.write @contents }
+ @file = File.open(@fname, "r+")
+ end
- after :each do
- @file.close
- rm_r @fname
- end
+ after :each do
+ @file.close
+ rm_r @fname
+ end
- it "accepts a length, and an offset" do
- @file.pread(4, 0).should == "1234"
- @file.pread(3, 4).should == "567"
- end
+ it "accepts a length, and an offset" do
+ @file.pread(4, 0).should == "1234"
+ @file.pread(3, 4).should == "567"
+ end
- it "accepts a length, an offset, and an output buffer" do
- buffer = +"foo"
- @file.pread(3, 4, buffer).should.equal?(buffer)
- buffer.should == "567"
- end
+ it "accepts a length, an offset, and an output buffer" do
+ buffer = +"foo"
+ @file.pread(3, 4, buffer).should.equal?(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 "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 "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)
+ 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
+ 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 "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 "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 "returns an empty string for maxlen = 0" do
+ @file.pread(0, 4).should == ""
+ end
- it "returns a buffer for maxlen = 0 when buffer specified" do
- buffer = +"foo"
- @file.pread(0, 4, buffer).should.equal?(buffer)
- buffer.should == "foo"
- end
+ it "returns a buffer for maxlen = 0 when buffer specified" do
+ buffer = +"foo"
+ @file.pread(0, 4, buffer).should.equal?(buffer)
+ buffer.should == "foo"
+ end
- it "ignores the offset for maxlen = 0, even if it is out of file bounds" do
- @file.pread(0, 400).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"
+ 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
+ @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 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 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 "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 maxlen is not an Integer and cannot be coerced into Integer" do
+ maxlen = Object.new
+ -> { @file.pread(maxlen, 0) }.should.raise(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 TypeError if offset is not an Integer and cannot be coerced into Integer" do
+ offset = Object.new
+ -> { @file.pread(4, offset) }.should.raise(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 "raises ArgumentError for negative values of maxlen" do
+ -> { @file.pread(-4, 0) }.should.raise(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 "raised Errno::EINVAL for negative values of offset" do
+ -> { @file.pread(4, -1) }.should.raise(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 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(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
+ it "raises EOFError if end-of-file is reached" do
+ -> { @file.pread(1, 10) }.should.raise(EOFError)
+ end
- it "raises IOError when file is not open in read mode" do
- File.open(@fname, "w") do |file|
- -> { file.pread(1, 1) }.should raise_error(IOError)
- end
+ it "raises IOError when file is not open in read mode" do
+ File.open(@fname, "w") do |file|
+ -> { file.pread(1, 1) }.should.raise(IOError)
end
+ end
- it "raises IOError when file is closed" do
- file = File.open(@fname, "r+")
- file.close
- -> { file.pread(1, 1) }.should raise_error(IOError)
- end
+ it "raises IOError when file is closed" do
+ file = File.open(@fname, "r+")
+ file.close
+ -> { file.pread(1, 1) }.should.raise(IOError)
end
end
diff --git a/spec/ruby/core/io/print_spec.rb b/spec/ruby/core/io/print_spec.rb
index 085852024c..065cb3b8cb 100644
--- a/spec/ruby/core/io/print_spec.rb
+++ b/spec/ruby/core/io/print_spec.rb
@@ -21,7 +21,7 @@ describe "IO#print" do
end
it "returns nil" do
- touch(@name) { |f| f.print.should be_nil }
+ touch(@name) { |f| f.print.should == nil }
end
it "writes $_.to_s followed by $\\ (if any) to the stream if no arguments given" do
@@ -61,6 +61,6 @@ describe "IO#print" do
end
it "raises IOError on closed stream" do
- -> { IOSpecs.closed_io.print("stuff") }.should raise_error(IOError)
+ -> { IOSpecs.closed_io.print("stuff") }.should.raise(IOError)
end
end
diff --git a/spec/ruby/core/io/printf_spec.rb b/spec/ruby/core/io/printf_spec.rb
index baa00f14ce..d5519bdaa3 100644
--- a/spec/ruby/core/io/printf_spec.rb
+++ b/spec/ruby/core/io/printf_spec.rb
@@ -27,6 +27,6 @@ describe "IO#printf" do
end
it "raises IOError on closed stream" do
- -> { IOSpecs.closed_io.printf("stuff") }.should raise_error(IOError)
+ -> { IOSpecs.closed_io.printf("stuff") }.should.raise(IOError)
end
end
diff --git a/spec/ruby/core/io/puts_spec.rb b/spec/ruby/core/io/puts_spec.rb
index a186ddaa5d..df526ea56a 100644
--- a/spec/ruby/core/io/puts_spec.rb
+++ b/spec/ruby/core/io/puts_spec.rb
@@ -111,7 +111,7 @@ describe "IO#puts" do
end
it "raises IOError on closed stream" do
- -> { IOSpecs.closed_io.puts("stuff") }.should raise_error(IOError)
+ -> { IOSpecs.closed_io.puts("stuff") }.should.raise(IOError)
end
it "writes crlf when IO is opened with newline: :crlf" do
diff --git a/spec/ruby/core/io/pwrite_spec.rb b/spec/ruby/core/io/pwrite_spec.rb
index 2bc508b37d..c318d551bc 100644
--- a/spec/ruby/core/io/pwrite_spec.rb
+++ b/spec/ruby/core/io/pwrite_spec.rb
@@ -1,69 +1,67 @@
# -*- encoding: utf-8 -*-
require_relative '../../spec_helper'
-guard -> { platform_is_not :windows or ruby_version_is "3.3" } do
- describe "IO#pwrite" do
- before :each do
- @fname = tmp("io_pwrite.txt")
- @file = File.open(@fname, "w+")
- end
+describe "IO#pwrite" do
+ before :each do
+ @fname = tmp("io_pwrite.txt")
+ @file = File.open(@fname, "w+")
+ end
- after :each do
- @file.close
- rm_r @fname
- end
+ after :each do
+ @file.close
+ rm_r @fname
+ end
- it "returns the number of bytes written" do
- @file.pwrite("foo", 0).should == 3
- end
+ it "returns the number of bytes written" do
+ @file.pwrite("foo", 0).should == 3
+ end
- it "accepts a string and an offset" do
- @file.pwrite("foo", 2)
- @file.pread(3, 2).should == "foo"
- end
+ it "accepts a string and an offset" do
+ @file.pwrite("foo", 2)
+ @file.pread(3, 2).should == "foo"
+ end
- it "does not advance the pointer in the file" do
- @file.pwrite("bar", 3)
- @file.write("foo")
- @file.pread(6, 0).should == "foobar"
- end
+ it "does not advance the pointer in the file" do
+ @file.pwrite("bar", 3)
+ @file.write("foo")
+ @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_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 "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")
- 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(IOError, "not opened for writing")
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 IOError when file is closed" do
+ file = File.open(@fname, "w+")
+ file.close
+ -> { file.pwrite("foo", 1) }.should.raise(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 NoMethodError if object does not respond to #to_s" do
+ -> {
+ @file.pwrite(BasicObject.new, 0)
+ }.should.raise(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")
- end
+ it "raises a TypeError if the offset cannot be converted to an Integer" do
+ -> {
+ @file.pwrite("foo", Object.new)
+ }.should.raise(TypeError, "no implicit conversion of Object into Integer")
end
end
diff --git a/spec/ruby/core/io/read_nonblock_spec.rb b/spec/ruby/core/io/read_nonblock_spec.rb
index 51e7cd6bd2..511cf03263 100644
--- a/spec/ruby/core/io/read_nonblock_spec.rb
+++ b/spec/ruby/core/io/read_nonblock_spec.rb
@@ -12,12 +12,12 @@ describe "IO#read_nonblock" do
end
it "raises an exception extending IO::WaitReadable when there is no data" do
- -> { @read.read_nonblock(5) }.should raise_error(IO::WaitReadable) { |e|
+ -> { @read.read_nonblock(5) }.should.raise(IO::WaitReadable) { |e|
platform_is_not :windows do
- e.should be_kind_of(Errno::EAGAIN)
+ e.should.is_a?(Errno::EAGAIN)
end
platform_is :windows do
- e.should be_kind_of(Errno::EWOULDBLOCK)
+ e.should.is_a?(Errno::EWOULDBLOCK)
end
}
end
@@ -36,7 +36,7 @@ describe "IO#read_nonblock" do
@read.read_nonblock(5)
- @read.read_nonblock(5, exception: false).should be_nil
+ @read.read_nonblock(5, exception: false).should == nil
end
end
end
@@ -73,7 +73,7 @@ describe "IO#read_nonblock" do
)
c = @read.getc
@read.ungetc(c)
- -> { @read.read_nonblock(3).should == "foo" }.should raise_error(IOError)
+ -> { @read.read_nonblock(3).should == "foo" }.should.raise(IOError)
end
it "returns less data if that is all that is available" do
@@ -92,7 +92,7 @@ describe "IO#read_nonblock" do
end
it "raises ArgumentError when length is less than 0" do
- -> { @read.read_nonblock(-1) }.should raise_error(ArgumentError)
+ -> { @read.read_nonblock(-1) }.should.raise(ArgumentError)
end
it "reads into the passed buffer" do
@@ -106,7 +106,7 @@ describe "IO#read_nonblock" do
buffer = +""
@write.write("1")
output = @read.read_nonblock(1, buffer)
- output.should equal(buffer)
+ output.should.equal?(buffer)
end
it "discards the existing buffer content upon successful read" do
@@ -120,12 +120,12 @@ describe "IO#read_nonblock" do
it "discards the existing buffer content upon error" do
buffer = +"existing content"
@write.close
- -> { @read.read_nonblock(1, buffer) }.should raise_error(EOFError)
- buffer.should be_empty
+ -> { @read.read_nonblock(1, buffer) }.should.raise(EOFError)
+ buffer.should.empty?
end
it "raises IOError on closed stream" do
- -> { IOSpecs.closed_io.read_nonblock(5) }.should raise_error(IOError)
+ -> { IOSpecs.closed_io.read_nonblock(5) }.should.raise(IOError)
end
it "raises EOFError when the end is reached" do
@@ -134,7 +134,7 @@ describe "IO#read_nonblock" do
@read.read_nonblock(5)
- -> { @read.read_nonblock(5) }.should raise_error(EOFError)
+ -> { @read.read_nonblock(5) }.should.raise(EOFError)
end
it "preserves the encoding of the given buffer" do
diff --git a/spec/ruby/core/io/read_spec.rb b/spec/ruby/core/io/read_spec.rb
index 567daa55df..5be969e280 100644
--- a/spec/ruby/core/io/read_spec.rb
+++ b/spec/ruby/core/io/read_spec.rb
@@ -29,7 +29,7 @@ describe "IO.read" do
-> {
IO.read(@fname, 3, 0, {mode: "r+"})
- }.should raise_error(ArgumentError, /wrong number of arguments/)
+ }.should.raise(ArgumentError, /wrong number of arguments/)
end
it "accepts an empty options Hash" do
@@ -45,11 +45,11 @@ describe "IO.read" do
end
it "raises an IOError if the options Hash specifies write mode" do
- -> { IO.read(@fname, 3, 0, mode: "w") }.should raise_error(IOError)
+ -> { IO.read(@fname, 3, 0, mode: "w") }.should.raise(IOError)
end
it "raises an IOError if the options Hash specifies append only mode" do
- -> { IO.read(@fname, mode: "a") }.should raise_error(IOError)
+ -> { IO.read(@fname, mode: "a") }.should.raise(IOError)
end
it "reads the file if the options Hash includes read mode" do
@@ -65,15 +65,6 @@ describe "IO.read" do
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
@@ -124,29 +115,20 @@ describe "IO.read" do
it "raises an Errno::ENOENT when the requested file does not exist" do
rm_r @fname
- -> { IO.read @fname }.should raise_error(Errno::ENOENT)
+ -> { IO.read @fname }.should.raise(Errno::ENOENT)
end
it "raises a TypeError when not passed a String type" do
- -> { IO.read nil }.should raise_error(TypeError)
+ -> { IO.read nil }.should.raise(TypeError)
end
it "raises an ArgumentError when not passed a valid length" 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
+ -> { IO.read @fname, -1 }.should.raise(ArgumentError)
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 ArgumentError when not passed a valid offset" do
+ -> { IO.read @fname, 0, -1 }.should.raise(ArgumentError)
+ -> { IO.read @fname, -1, -1 }.should.raise(ArgumentError)
end
it "uses the external encoding specified via the :external_encoding option" do
@@ -168,72 +150,72 @@ describe "IO.read" do
end
end
-describe "IO.read from a pipe" do
- it "runs the rest as a subprocess and returns the standard output" do
- cmd = "|sh -c 'echo hello'"
- 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
- 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("|-")
+ruby_version_is ""..."4.0" do
+ describe "IO.read from a pipe" do
+ it "runs the rest as a subprocess and returns the standard output" do
+ cmd = "|sh -c 'echo hello'"
+ platform_is :windows do
+ cmd = "|cmd.exe /C echo hello"
end
- if str # parent
- str.should == "hello from child\n"
- else #child
- puts "hello from child"
- exit!
+ suppress_warning do # https://bugs.ruby-lang.org/issues/19630
+ IO.read(cmd).should == "hello\n"
end
end
- end
- it "reads only the specified number of bytes requested" do
- cmd = "|sh -c 'echo hello'"
- platform_is :windows do
- cmd = "|cmd.exe /C echo hello"
- end
+ guard -> { Process.respond_to?(:fork) } 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
- suppress_warning do # https://bugs.ruby-lang.org/issues/19630
- IO.read(cmd, 1).should == "h"
+ if str # parent
+ str.should == "hello from child\n"
+ else #child
+ puts "hello from child"
+ exit!
+ end
+ end
end
- 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
- }.should raise_error(Errno::ESPIPE)
+ it "reads only the specified number of bytes requested" do
+ cmd = "|sh -c 'echo hello'"
+ 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
end
- end
- quarantine! do # The process tried to write to a nonexistent pipe.
- platform_is :windows do
- # TODO: It should raise Errno::ESPIPE on Windows as well
- # once https://bugs.ruby-lang.org/issues/12230 is fixed.
- it "raises Errno::EINVAL if passed an offset" do
+ 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("|cmd.exe /C echo hello", 1, 1)
+ IO.read("|sh -c 'echo hello'", 1, 1)
end
- }.should raise_error(Errno::EINVAL)
+ }.should.raise(Errno::ESPIPE)
+ end
+ end
+
+ quarantine! do # The process tried to write to a nonexistent pipe.
+ platform_is :windows do
+ # TODO: It should raise Errno::ESPIPE on Windows as well
+ # 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
+ }.should.raise(Errno::EINVAL)
+ end
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
+ it "warns about deprecation" do
cmd = "|echo ok"
-> {
IO.read(cmd)
@@ -288,7 +270,7 @@ describe "IO#read" do
end
it "raises an ArgumentError when not passed a valid length" do
- -> { @io.read(-1) }.should raise_error(ArgumentError)
+ -> { @io.read(-1) }.should.raise(ArgumentError)
end
it "clears the output buffer if there is nothing to read" do
@@ -315,16 +297,14 @@ describe "IO#read" do
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)
+ -> { @io.read(0, 'frozen-string'.freeze) }.should.raise(FrozenError)
+ -> { @io.read(1, 'frozen-string'.freeze) }.should.raise(FrozenError)
+ -> { @io.read(nil, 'frozen-string'.freeze) }.should.raise(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
+ it "raise FrozenError if the output buffer is frozen (2)" do
+ @io.read
+ -> { @io.read(1, ''.freeze) }.should.raise(FrozenError)
end
it "consumes zero bytes when reading zero bytes" do
@@ -394,14 +374,14 @@ describe "IO#read" do
it "returns the given buffer" do
buf = +""
- @io.read(nil, buf).should equal buf
+ @io.read(nil, buf).should.equal? buf
end
it "returns the given buffer when there is nothing to read" do
buf = +""
@io.read
- @io.read(nil, buf).should equal buf
+ @io.read(nil, buf).should.equal? buf
end
it "coerces the second argument to string and uses it as a buffer" do
@@ -409,7 +389,7 @@ describe "IO#read" do
obj = mock("buff")
obj.should_receive(:to_str).any_number_of_times.and_return(buf)
- @io.read(15, obj).should_not equal obj
+ @io.read(15, obj).should_not.equal? obj
buf.should == @contents
end
@@ -443,11 +423,11 @@ describe "IO#read" do
end
it "raises IOError on closed stream" do
- -> { IOSpecs.closed_io.read }.should raise_error(IOError)
+ -> { IOSpecs.closed_io.read }.should.raise(IOError)
end
it "raises ArgumentError when length is less than 0" do
- -> { @io.read(-1) }.should raise_error(ArgumentError)
+ -> { @io.read(-1) }.should.raise(ArgumentError)
end
platform_is_not :windows do
@@ -464,7 +444,7 @@ describe "IO#read" do
Thread.pass until t.stop?
r.close
t.join
- t.value.should be_kind_of(IOError)
+ t.value.should.is_a?(IOError)
w.close
end
end
@@ -598,20 +578,20 @@ describe :io_read_internal_encoding, shared: true do
end
it "sets the String encoding to the internal encoding" do
- @io.read.encoding.should equal(Encoding::UTF_8)
+ @io.read.encoding.should.equal?(Encoding::UTF_8)
end
describe "when passed nil for limit" do
it "sets the buffer to a transcoded String" do
result = @io.read(nil, buf = +"")
- buf.should equal(result)
+ 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
@io.read(nil, buf)
- buf.encoding.should equal(Encoding::UTF_8)
+ buf.encoding.should.equal?(Encoding::UTF_8)
end
end
end
@@ -622,24 +602,24 @@ describe :io_read_size_internal_encoding, shared: true do
end
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)
+ @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
@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)
+ 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
@io.read
- @io.read(1, buf).should be_nil
+ @io.read(1, buf).should == nil
buf.size.should == 0
- buf.encoding.should equal(Encoding::ISO_8859_1)
+ buf.encoding.should.equal?(Encoding::ISO_8859_1)
end
end
@@ -657,7 +637,7 @@ describe "IO#read" do
end
it "sets the String encoding to Encoding.default_external" do
- @io.read.encoding.should equal(Encoding.default_external)
+ @io.read.encoding.should.equal?(Encoding.default_external)
end
end
@@ -676,7 +656,7 @@ describe "IO#read" do
end
it "sets the String encoding to the external encoding" do
- @io.read.encoding.should equal(Encoding::EUC_JP)
+ @io.read.encoding.should.equal?(Encoding::EUC_JP)
end
it_behaves_like :io_read_size_internal_encoding, nil
diff --git a/spec/ruby/core/io/readbyte_spec.rb b/spec/ruby/core/io/readbyte_spec.rb
index 14426c28ac..07da1da919 100644
--- a/spec/ruby/core/io/readbyte_spec.rb
+++ b/spec/ruby/core/io/readbyte_spec.rb
@@ -19,6 +19,6 @@ describe "IO#readbyte" do
@io.seek(999999)
-> do
@io.readbyte
- end.should raise_error EOFError
+ end.should.raise EOFError
end
end
diff --git a/spec/ruby/core/io/readchar_spec.rb b/spec/ruby/core/io/readchar_spec.rb
index a66773851a..29d14880ff 100644
--- a/spec/ruby/core/io/readchar_spec.rb
+++ b/spec/ruby/core/io/readchar_spec.rb
@@ -7,7 +7,7 @@ describe :io_readchar_internal_encoding, shared: true do
end
it "sets the String encoding to the internal encoding" do
- @io.readchar.encoding.should equal(Encoding::UTF_8)
+ @io.readchar.encoding.should.equal?(Encoding::UTF_8)
end
end
@@ -31,11 +31,11 @@ describe "IO#readchar" do
it "raises an EOFError when invoked at the end of the stream" do
@io.read
- -> { @io.readchar }.should raise_error(EOFError)
+ -> { @io.readchar }.should.raise(EOFError)
end
it "raises IOError on closed stream" do
- -> { IOSpecs.closed_io.readchar }.should raise_error(IOError)
+ -> { IOSpecs.closed_io.readchar }.should.raise(IOError)
end
end
@@ -54,7 +54,7 @@ describe "IO#readchar with internal encoding" do
end
it "sets the String encoding to the external encoding" do
- @io.readchar.encoding.should equal(Encoding::EUC_JP)
+ @io.readchar.encoding.should.equal?(Encoding::EUC_JP)
end
end
@@ -105,6 +105,6 @@ describe "IO#readchar" do
end
it "raises EOFError on empty stream" do
- -> { @io.readchar }.should raise_error(EOFError)
+ -> { @io.readchar }.should.raise(EOFError)
end
end
diff --git a/spec/ruby/core/io/readline_spec.rb b/spec/ruby/core/io/readline_spec.rb
index a814c1be90..009687710a 100644
--- a/spec/ruby/core/io/readline_spec.rb
+++ b/spec/ruby/core/io/readline_spec.rb
@@ -29,11 +29,11 @@ describe "IO#readline" do
it "raises EOFError on end of stream" do
IOSpecs.lines.length.times { @io.readline }
- -> { @io.readline }.should raise_error(EOFError)
+ -> { @io.readline }.should.raise(EOFError)
end
it "raises IOError on closed stream" do
- -> { IOSpecs.closed_io.readline }.should raise_error(IOError)
+ -> { IOSpecs.closed_io.readline }.should.raise(IOError)
end
it "assigns the returned line to $_" do
@@ -53,7 +53,7 @@ describe "IO#readline" do
end
it "does not accept Integers that don't fit in a C off_t" do
- -> { @io.readline(2**128) }.should raise_error(RangeError)
+ -> { @io.readline(2**128) }.should.raise(RangeError)
end
end
@@ -74,11 +74,11 @@ describe "IO#readline" do
end
it "raises exception when options passed as Hash" do
- -> { @io.readline({ chomp: true }) }.should raise_error(TypeError)
+ -> { @io.readline({ chomp: true }) }.should.raise(TypeError)
-> {
@io.readline("\n", 1, { chomp: true })
- }.should raise_error(ArgumentError, "wrong number of arguments (given 3, expected 0..2)")
+ }.should.raise(ArgumentError, "wrong number of arguments (given 3, expected 0..2)")
end
end
end
diff --git a/spec/ruby/core/io/readlines_spec.rb b/spec/ruby/core/io/readlines_spec.rb
index 3a6ff3d0f3..d41d24d7d1 100644
--- a/spec/ruby/core/io/readlines_spec.rb
+++ b/spec/ruby/core/io/readlines_spec.rb
@@ -17,7 +17,7 @@ describe "IO#readlines" do
it "raises an IOError if the stream is closed" do
@io.close
- -> { @io.readlines }.should raise_error(IOError)
+ -> { @io.readlines }.should.raise(IOError)
end
describe "when passed no arguments" do
@@ -37,12 +37,12 @@ describe "IO#readlines" do
describe "when passed no arguments" do
it "updates self's position" do
@io.readlines
- @io.pos.should eql(137)
+ @io.pos.should.eql?(137)
end
it "updates self's lineno based on the number of lines read" do
@io.readlines
- @io.lineno.should eql(9)
+ @io.lineno.should.eql?(9)
end
it "does not change $_" do
@@ -81,12 +81,12 @@ describe "IO#readlines" do
it "updates self's lineno based on the number of lines read" do
@io.readlines("r")
- @io.lineno.should eql(5)
+ @io.lineno.should.eql?(5)
end
it "updates self's position based on the number of characters read" do
@io.readlines("r")
- @io.pos.should eql(137)
+ @io.pos.should.eql?(137)
end
it "does not change $_" do
@@ -104,11 +104,11 @@ describe "IO#readlines" do
describe "when passed limit" do
it "raises ArgumentError when passed 0 as a limit" do
- -> { @io.readlines(0) }.should raise_error(ArgumentError)
+ -> { @io.readlines(0) }.should.raise(ArgumentError)
end
it "does not accept Integers that don't fit in a C off_t" do
- -> { @io.readlines(2**128) }.should raise_error(RangeError)
+ -> { @io.readlines(2**128) }.should.raise(RangeError)
end
end
@@ -118,11 +118,11 @@ describe "IO#readlines" do
end
it "raises exception when options passed as Hash" do
- -> { @io.readlines({ chomp: true }) }.should raise_error(TypeError)
+ -> { @io.readlines({ chomp: true }) }.should.raise(TypeError)
-> {
@io.readlines("\n", 1, { chomp: true })
- }.should raise_error(ArgumentError, "wrong number of arguments (given 3, expected 0..2)")
+ }.should.raise(ArgumentError, "wrong number of arguments (given 3, expected 0..2)")
end
end
@@ -145,13 +145,13 @@ describe "IO#readlines" do
it "raises an IOError if the stream is opened for append only" do
-> do
File.open(@name, "a:utf-8") { |f| f.readlines }
- end.should raise_error(IOError)
+ end.should.raise(IOError)
end
it "raises an IOError if the stream is opened for write only" do
-> do
File.open(@name, "w:utf-8") { |f| f.readlines }
- end.should raise_error(IOError)
+ end.should.raise(IOError)
end
end
@@ -174,39 +174,39 @@ describe "IO.readlines" do
$_.should == "test"
end
- describe "when passed a string that starts with a |" do
- it "gets data from the standard out of the subprocess" do
- cmd = "|sh -c 'echo hello;echo line2'"
- 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.should == ["hello\n", "line2\n"]
- end
+ ruby_version_is ""..."4.0" do
+ describe "when passed a string that starts with a |" do
+ it "gets data from the standard out of the subprocess" do
+ cmd = "|sh -c 'echo hello;echo line2'"
+ platform_is :windows do
+ cmd = "|cmd.exe /C echo hello&echo line2"
+ 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("|-")
+ lines = IO.readlines(cmd)
end
+ lines.should == ["hello\n", "line2\n"]
+ end
- if lines # parent
- lines.should == ["hello\n", "from a fork\n"]
- else
- puts "hello"
- puts "from a fork"
- exit!
+ guard -> { Process.respond_to?(:fork) } 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
+
+ if lines # parent
+ lines.should == ["hello\n", "from a fork\n"]
+ else
+ puts "hello"
+ puts "from a fork"
+ exit!
+ end
end
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"
@@ -237,7 +237,7 @@ describe "IO.readlines" do
it "encodes lines using the default external encoding" do
Encoding.default_external = Encoding::UTF_8
lines = IO.readlines(@name)
- lines.all? { |s| s.encoding == Encoding::UTF_8 }.should be_true
+ lines.all? { |s| s.encoding == Encoding::UTF_8 }.should == true
end
it "encodes lines using the default internal encoding, when set" do
@@ -245,13 +245,13 @@ describe "IO.readlines" do
Encoding.default_internal = Encoding::UTF_16
suppress_warning {$/ = $/.encode Encoding::UTF_16}
lines = IO.readlines(@name)
- lines.all? { |s| s.encoding == Encoding::UTF_16 }.should be_true
+ lines.all? { |s| s.encoding == Encoding::UTF_16 }.should == true
end
it "ignores the default internal encoding if the external encoding is BINARY" do
Encoding.default_external = Encoding::BINARY
Encoding.default_internal = Encoding::UTF_8
lines = IO.readlines(@name)
- lines.all? { |s| s.encoding == Encoding::BINARY }.should be_true
+ lines.all? { |s| s.encoding == Encoding::BINARY }.should == true
end
end
diff --git a/spec/ruby/core/io/readpartial_spec.rb b/spec/ruby/core/io/readpartial_spec.rb
index 2fcfaf5203..d3f5545c8f 100644
--- a/spec/ruby/core/io/readpartial_spec.rb
+++ b/spec/ruby/core/io/readpartial_spec.rb
@@ -15,10 +15,10 @@ describe "IO#readpartial" do
end
it "raises IOError on closed stream" do
- -> { IOSpecs.closed_io.readpartial(10) }.should raise_error(IOError)
+ -> { IOSpecs.closed_io.readpartial(10) }.should.raise(IOError)
@rd.close
- -> { @rd.readpartial(10) }.should raise_error(IOError)
+ -> { @rd.readpartial(10) }.should.raise(IOError)
end
it "reads at most the specified number of bytes" do
@@ -70,29 +70,34 @@ describe "IO#readpartial" do
@wr.write("abc")
@wr.close
@rd.readpartial(10).should == 'abc'
- -> { @rd.readpartial(10) }.should raise_error(EOFError)
+ -> { @rd.readpartial(10) }.should.raise(EOFError)
end
it "discards the existing buffer content upon error" do
buffer = +'hello'
@wr.close
- -> { @rd.readpartial(1, buffer) }.should raise_error(EOFError)
- buffer.should be_empty
+ -> { @rd.readpartial(1, buffer) }.should.raise(EOFError)
+ buffer.should.empty?
end
it "raises IOError if the stream is closed" do
@wr.close
- -> { @rd.readpartial(1) }.should raise_error(IOError)
+ -> { @rd.readpartial(1) }.should.raise(IOError)
end
it "raises ArgumentError if the negative argument is provided" do
- -> { @rd.readpartial(-1) }.should raise_error(ArgumentError)
+ -> { @rd.readpartial(-1) }.should.raise(ArgumentError)
end
it "immediately returns an empty string if the length argument is 0" do
@rd.readpartial(0).should == ""
end
+ it "raises IOError if the stream is closed and the length argument is 0" do
+ @rd.close
+ -> { @rd.readpartial(0) }.should.raise(IOError, "closed stream")
+ end
+
it "clears and returns the given buffer if the length argument is 0" do
buffer = +"existing content"
@rd.readpartial(0, buffer).should == buffer
diff --git a/spec/ruby/core/io/reopen_spec.rb b/spec/ruby/core/io/reopen_spec.rb
index 8ff0f217f4..3b972d8978 100644
--- a/spec/ruby/core/io/reopen_spec.rb
+++ b/spec/ruby/core/io/reopen_spec.rb
@@ -27,35 +27,35 @@ describe "IO#reopen" do
it "changes the class of the instance to the class of the object returned by #to_io" do
obj = mock("io")
obj.should_receive(:to_io).and_return(@other_io)
- @io.reopen(obj).should be_an_instance_of(File)
+ @io.reopen(obj).should.instance_of?(File)
end
it "raises an IOError if the object returned by #to_io is closed" do
obj = mock("io")
obj.should_receive(:to_io).and_return(IOSpecs.closed_io)
- -> { @io.reopen obj }.should raise_error(IOError)
+ -> { @io.reopen obj }.should.raise(IOError)
end
it "raises a TypeError if #to_io does not return an IO instance" do
obj = mock("io")
obj.should_receive(:to_io).and_return("something else")
- -> { @io.reopen obj }.should raise_error(TypeError)
+ -> { @io.reopen obj }.should.raise(TypeError)
end
it "raises an IOError when called on a closed stream with an object" do
@io.close
obj = mock("io")
obj.should_not_receive(:to_io)
- -> { @io.reopen(STDOUT) }.should raise_error(IOError)
+ -> { @io.reopen(STDOUT) }.should.raise(IOError)
end
it "raises an IOError if the IO argument is closed" do
- -> { @io.reopen(IOSpecs.closed_io) }.should raise_error(IOError)
+ -> { @io.reopen(IOSpecs.closed_io) }.should.raise(IOError)
end
it "raises an IOError when called on a closed stream with an IO" do
@io.close
- -> { @io.reopen(STDOUT) }.should raise_error(IOError)
+ -> { @io.reopen(STDOUT) }.should.raise(IOError)
end
end
@@ -77,12 +77,12 @@ describe "IO#reopen with a String" do
it "does not raise an exception when called on a closed stream with a path" do
@io.close
@io.reopen @name, "r"
- @io.closed?.should be_false
+ @io.closed?.should == false
@io.gets.should == "Line 1: One\n"
end
it "returns self" do
- @io.reopen(@name).should equal(@io)
+ @io.reopen(@name).should.equal?(@io)
end
it "positions a newly created instance at the beginning of the new stream" do
@@ -188,7 +188,7 @@ describe "IO#reopen with a String" do
it "raises an Errno::ENOENT if the file does not exist and the IO is not opened in write mode" do
@io = new_io @name, "r"
- -> { @io.reopen(@other_name) }.should raise_error(Errno::ENOENT)
+ -> { @io.reopen(@other_name) }.should.raise(Errno::ENOENT)
end
end
@@ -214,9 +214,9 @@ describe "IO#reopen with an IO at EOF" do
end
it "resets the EOF status to false" do
- @io.eof?.should be_true
+ @io.eof?.should == true
@io.reopen @other_io
- @io.eof?.should be_false
+ @io.eof?.should == false
end
end
@@ -244,7 +244,7 @@ describe "IO#reopen with an IO" do
# MRI actually changes the class of @io in the call to #reopen
# but does not preserve the existing singleton class of @io.
def @io.to_io; flunk; end
- @io.reopen(@other_io).should be_an_instance_of(IO)
+ @io.reopen(@other_io).should.instance_of?(IO)
end
it "does not change the object_id" do
@@ -303,7 +303,7 @@ describe "IO#reopen with an IO" do
it "may change the class of the instance" do
@io.reopen @other_io
- @io.should be_an_instance_of(File)
+ @io.should.instance_of?(File)
end
it "sets path equals to the other IO's path if other IO is File" do
diff --git a/spec/ruby/core/io/rewind_spec.rb b/spec/ruby/core/io/rewind_spec.rb
index 5579cbd988..43834ef307 100644
--- a/spec/ruby/core/io/rewind_spec.rb
+++ b/spec/ruby/core/io/rewind_spec.rb
@@ -48,6 +48,6 @@ describe "IO#rewind" do
end
it "raises IOError on closed stream" do
- -> { IOSpecs.closed_io.rewind }.should raise_error(IOError)
+ -> { IOSpecs.closed_io.rewind }.should.raise(IOError)
end
end
diff --git a/spec/ruby/core/io/seek_spec.rb b/spec/ruby/core/io/seek_spec.rb
index 2fa4a73ac9..d26629fb89 100644
--- a/spec/ruby/core/io/seek_spec.rb
+++ b/spec/ruby/core/io/seek_spec.rb
@@ -17,7 +17,7 @@ describe "IO#seek" do
end
it "moves the read position relative to the current position with SEEK_CUR" do
- -> { @io.seek(-1) }.should raise_error(Errno::EINVAL)
+ -> { @io.seek(-1) }.should.raise(Errno::EINVAL)
@io.seek(10, IO::SEEK_CUR)
@io.readline.should == "igne une.\n"
@io.seek(-5, IO::SEEK_CUR)
diff --git a/spec/ruby/core/io/select_spec.rb b/spec/ruby/core/io/select_spec.rb
index 3893e7620f..0a43fc6f5f 100644
--- a/spec/ruby/core/io/select_spec.rb
+++ b/spec/ruby/core/io/select_spec.rb
@@ -18,6 +18,10 @@ describe "IO.select" do
@wr.syswrite("be ready")
IO.pipe do |_, wr|
result = IO.select [@rd], [wr], nil, 0
+ unless result
+ # On some platforms (e.g., Windows), pipe readiness may not be immediate
+ result = IO.select [@rd], [wr], nil, 2
+ end
result.should == [[@rd], [wr], []]
end
end
@@ -91,28 +95,38 @@ describe "IO.select" do
end
it "raises TypeError if supplied objects are not IO" do
- -> { IO.select([Object.new]) }.should raise_error(TypeError)
- -> { IO.select(nil, [Object.new]) }.should raise_error(TypeError)
+ -> { IO.select([Object.new]) }.should.raise(TypeError)
+ -> { IO.select(nil, [Object.new]) }.should.raise(TypeError)
obj = mock("io")
obj.should_receive(:to_io).any_number_of_times.and_return(nil)
- -> { IO.select([obj]) }.should raise_error(TypeError)
- -> { IO.select(nil, [obj]) }.should raise_error(TypeError)
+ -> { IO.select([obj]) }.should.raise(TypeError)
+ -> { IO.select(nil, [obj]) }.should.raise(TypeError)
end
it "raises a TypeError if the specified timeout value is not Numeric" do
- -> { IO.select([@rd], nil, nil, Object.new) }.should raise_error(TypeError)
+ -> { IO.select([@rd], nil, nil, Object.new) }.should.raise(TypeError)
end
it "raises TypeError if the first three arguments are not Arrays" do
- -> { IO.select(Object.new)}.should raise_error(TypeError)
- -> { IO.select(nil, Object.new)}.should raise_error(TypeError)
- -> { IO.select(nil, nil, Object.new)}.should raise_error(TypeError)
+ -> { IO.select(Object.new)}.should.raise(TypeError)
+ -> { IO.select(nil, Object.new)}.should.raise(TypeError)
+ -> { IO.select(nil, nil, Object.new)}.should.raise(TypeError)
end
it "raises an ArgumentError when passed a negative timeout" do
- -> { IO.select(nil, nil, nil, -5)}.should raise_error(ArgumentError)
+ -> { IO.select(nil, nil, nil, -5)}.should.raise(ArgumentError, "time interval must not be negative")
+ end
+
+ ruby_version_is "4.0" do
+ it "raises an ArgumentError when passed negative infinity as timeout" do
+ -> { IO.select(nil, nil, nil, -Float::INFINITY)}.should.raise(ArgumentError, "time interval must not be negative")
+ end
+ end
+
+ it "raises an RangeError when passed NaN as timeout" do
+ -> { IO.select(nil, nil, nil, Float::NAN)}.should.raise(RangeError, "NaN out of Time range")
end
describe "returns the available descriptors when the file descriptor" do
@@ -149,16 +163,28 @@ describe "IO.select" do
end
end
-describe "IO.select when passed nil for timeout" do
- it "sleeps forever and sets the thread status to 'sleep'" do
- t = Thread.new do
- IO.select(nil, nil, nil, nil)
+describe "IO.select with infinite timeout" do
+ describe :io_select_infinite_timeout, shared: true do
+ it "sleeps forever and sets the thread status to 'sleep'" do
+ t = Thread.new do
+ IO.select(nil, nil, nil, @method)
+ end
+
+ Thread.pass while t.status && t.status != "sleep"
+ t.join unless t.status
+ t.status.should == "sleep"
+ t.kill
+ t.join
end
+ end
- Thread.pass while t.status && t.status != "sleep"
- t.join unless t.status
- t.status.should == "sleep"
- t.kill
- t.join
+ describe "IO.select when passed nil for timeout" do
+ it_behaves_like :io_select_infinite_timeout, nil
+ end
+
+ ruby_version_is "4.0" do
+ describe "IO.select when passed Float::INFINITY for timeout" do
+ it_behaves_like :io_select_infinite_timeout, Float::INFINITY
+ end
end
end
diff --git a/spec/ruby/core/io/set_encoding_by_bom_spec.rb b/spec/ruby/core/io/set_encoding_by_bom_spec.rb
index 30d5ce5a5a..5436879f11 100644
--- a/spec/ruby/core/io/set_encoding_by_bom_spec.rb
+++ b/spec/ruby/core/io/set_encoding_by_bom_spec.rb
@@ -15,7 +15,7 @@ describe "IO#set_encoding_by_bom" do
it "returns nil if not readable" do
not_readable_io = new_io(@name, 'wb')
- not_readable_io.set_encoding_by_bom.should be_nil
+ not_readable_io.set_encoding_by_bom.should == nil
not_readable_io.external_encoding.should == Encoding::ASCII_8BIT
ensure
not_readable_io.close
@@ -102,7 +102,7 @@ describe "IO#set_encoding_by_bom" do
end
it "returns nil if io is empty" do
- @io.set_encoding_by_bom.should be_nil
+ @io.set_encoding_by_bom.should == nil
@io.external_encoding.should == Encoding::ASCII_8BIT
end
@@ -243,7 +243,7 @@ describe "IO#set_encoding_by_bom" do
it 'returns exception if io not in binary mode' do
not_binary_io = new_io(@name, 'r')
- -> { not_binary_io.set_encoding_by_bom }.should raise_error(ArgumentError, 'ASCII incompatible encoding needs binmode')
+ -> { not_binary_io.set_encoding_by_bom }.should.raise(ArgumentError, 'ASCII incompatible encoding needs binmode')
ensure
not_binary_io.close
end
@@ -251,12 +251,12 @@ describe "IO#set_encoding_by_bom" do
it 'returns exception if encoding already set' do
@io.set_encoding("utf-8")
- -> { @io.set_encoding_by_bom }.should raise_error(ArgumentError, 'encoding is set to UTF-8 already')
+ -> { @io.set_encoding_by_bom }.should.raise(ArgumentError, 'encoding is set to UTF-8 already')
end
it 'returns exception if encoding conversion is already set' do
@io.set_encoding(Encoding::UTF_8, Encoding::UTF_16BE)
- -> { @io.set_encoding_by_bom }.should raise_error(ArgumentError, 'encoding conversion is set')
+ -> { @io.set_encoding_by_bom }.should.raise(ArgumentError, 'encoding conversion is set')
end
end
diff --git a/spec/ruby/core/io/set_encoding_spec.rb b/spec/ruby/core/io/set_encoding_spec.rb
index 22d9017635..237251de5b 100644
--- a/spec/ruby/core/io/set_encoding_spec.rb
+++ b/spec/ruby/core/io/set_encoding_spec.rb
@@ -5,21 +5,21 @@ describe :io_set_encoding_write, shared: true do
@io = new_io @name, "#{@object}:ibm437:ibm866"
@io.set_encoding nil, nil
- @io.external_encoding.should be_nil
- @io.internal_encoding.should be_nil
+ @io.external_encoding.should == nil
+ @io.internal_encoding.should == nil
end
it "sets the encodings to nil when the IO is built with no explicit encoding" do
@io = new_io @name, @object
# Checking our assumptions first
- @io.external_encoding.should be_nil
- @io.internal_encoding.should be_nil
+ @io.external_encoding.should == nil
+ @io.internal_encoding.should == nil
@io.set_encoding nil, nil
- @io.external_encoding.should be_nil
- @io.internal_encoding.should be_nil
+ @io.external_encoding.should == nil
+ @io.internal_encoding.should == nil
end
it "prevents the encodings from changing when Encoding defaults are changed" do
@@ -29,8 +29,8 @@ describe :io_set_encoding_write, shared: true do
Encoding.default_external = Encoding::IBM437
Encoding.default_internal = Encoding::IBM866
- @io.external_encoding.should be_nil
- @io.internal_encoding.should be_nil
+ @io.external_encoding.should == nil
+ @io.internal_encoding.should == nil
end
it "sets the encodings to the current Encoding defaults" do
@@ -75,8 +75,8 @@ describe "IO#set_encoding when passed nil, nil" do
Encoding.default_internal = Encoding::IBM866
@io.set_encoding nil, nil
- @io.external_encoding.should equal(Encoding::IBM437)
- @io.internal_encoding.should equal(Encoding::IBM866)
+ @io.external_encoding.should.equal?(Encoding::IBM437)
+ @io.internal_encoding.should.equal?(Encoding::IBM866)
end
it "prevents the #internal_encoding from changing when Encoding.default_internal is changed" do
@@ -85,7 +85,7 @@ describe "IO#set_encoding when passed nil, nil" do
Encoding.default_internal = Encoding::IBM437
- @io.internal_encoding.should be_nil
+ @io.internal_encoding.should == nil
end
it "allows the #external_encoding to change when Encoding.default_external is changed" do
@@ -94,17 +94,17 @@ describe "IO#set_encoding when passed nil, nil" do
Encoding.default_external = Encoding::IBM437
- @io.external_encoding.should equal(Encoding::IBM437)
+ @io.external_encoding.should.equal?(Encoding::IBM437)
end
end
describe "with 'rb' mode" do
it "returns Encoding.default_external" do
@io = new_io @name, "rb"
- @io.external_encoding.should equal(Encoding::BINARY)
+ @io.external_encoding.should.equal?(Encoding::BINARY)
@io.set_encoding nil, nil
- @io.external_encoding.should equal(Encoding.default_external)
+ @io.external_encoding.should.equal?(Encoding.default_external)
end
end
@@ -158,13 +158,13 @@ describe "IO#set_encoding" do
end
it "returns self" do
- @io.set_encoding(Encoding::UTF_8).should equal(@io)
+ @io.set_encoding(Encoding::UTF_8).should.equal?(@io)
end
it "sets the external encoding when passed an Encoding argument" do
@io.set_encoding(Encoding::UTF_8)
@io.external_encoding.should == Encoding::UTF_8
- @io.internal_encoding.should be_nil
+ @io.internal_encoding.should == nil
end
it "sets the external and internal encoding when passed two Encoding arguments" do
@@ -176,19 +176,19 @@ describe "IO#set_encoding" do
it "sets the external encoding when passed the name of an Encoding" do
@io.set_encoding("utf-8")
@io.external_encoding.should == Encoding::UTF_8
- @io.internal_encoding.should be_nil
+ @io.internal_encoding.should == nil
end
it "ignores the internal encoding if the same as external when passed Encoding objects" do
@io.set_encoding(Encoding::UTF_8, Encoding::UTF_8)
@io.external_encoding.should == Encoding::UTF_8
- @io.internal_encoding.should be_nil
+ @io.internal_encoding.should == nil
end
it "ignores the internal encoding if the same as external when passed encoding names separated by ':'" do
@io.set_encoding("utf-8:utf-8")
@io.external_encoding.should == Encoding::UTF_8
- @io.internal_encoding.should be_nil
+ @io.internal_encoding.should == nil
end
it "sets the external and internal encoding when passed the names of Encodings separated by ':'" do
@@ -229,10 +229,10 @@ describe "IO#set_encoding" do
end
it "raises ArgumentError when no arguments are given" do
- -> { @io.set_encoding() }.should raise_error(ArgumentError)
+ -> { @io.set_encoding() }.should.raise(ArgumentError)
end
it "raises ArgumentError when too many arguments are given" do
- -> { @io.set_encoding(1, 2, 3) }.should raise_error(ArgumentError)
+ -> { @io.set_encoding(1, 2, 3) }.should.raise(ArgumentError)
end
end
diff --git a/spec/ruby/core/io/shared/binwrite.rb b/spec/ruby/core/io/shared/binwrite.rb
index e51093329b..64793b1936 100644
--- a/spec/ruby/core/io/shared/binwrite.rb
+++ b/spec/ruby/core/io/shared/binwrite.rb
@@ -26,7 +26,7 @@ describe :io_binwrite, shared: true do
-> {
IO.send(@method, @filename, "hi", 0, {flags: File::CREAT})
- }.should raise_error(ArgumentError, "wrong number of arguments (given 4, expected 2..3)")
+ }.should.raise(ArgumentError, "wrong number of arguments (given 4, expected 2..3)")
end
it "creates a file if missing" do
@@ -81,7 +81,7 @@ describe :io_binwrite, shared: true do
end
it "raises an error if readonly mode is specified" do
- -> { IO.send(@method, @filename, "abcde", mode: "r") }.should raise_error(IOError)
+ -> { IO.send(@method, @filename, "abcde", mode: "r") }.should.raise(IOError)
end
it "truncates if empty :opts provided and offset skipped" do
diff --git a/spec/ruby/core/io/shared/chars.rb b/spec/ruby/core/io/shared/chars.rb
deleted file mode 100644
index 266566f221..0000000000
--- a/spec/ruby/core/io/shared/chars.rb
+++ /dev/null
@@ -1,73 +0,0 @@
-# -*- encoding: utf-8 -*-
-describe :io_chars, shared: true do
- before :each do
- @io = IOSpecs.io_fixture "lines.txt"
- ScratchPad.record []
- end
-
- after :each do
- @io.close unless @io.closed?
- end
-
- it "yields each character" do
- @io.readline.should == "Voici la ligne une.\n"
-
- count = 0
- @io.send(@method) do |c|
- ScratchPad << c
- break if 4 < count += 1
- end
-
- ScratchPad.recorded.should == ["Q", "u", "i", " ", "è"]
- end
-
- describe "when no block is given" do
- it "returns an Enumerator" do
- enum = @io.send(@method)
- enum.should be_an_instance_of(Enumerator)
- enum.first(5).should == ["V", "o", "i", "c", "i"]
- end
-
- describe "returned Enumerator" do
- describe "size" do
- it "should return nil" do
- @io.send(@method).size.should == nil
- end
- end
- end
- end
-
- it "returns itself" do
- @io.send(@method) { |c| }.should equal(@io)
- end
-
- it "returns an enumerator for a closed stream" do
- IOSpecs.closed_io.send(@method).should be_an_instance_of(Enumerator)
- end
-
- it "raises an IOError when an enumerator created on a closed stream is accessed" do
- -> { IOSpecs.closed_io.send(@method).first }.should raise_error(IOError)
- end
-
- it "raises IOError on closed stream" do
- -> { IOSpecs.closed_io.send(@method) {} }.should raise_error(IOError)
- end
-end
-
-describe :io_chars_empty, shared: true do
- before :each do
- @name = tmp("io_each_char")
- @io = new_io @name, "w+:utf-8"
- ScratchPad.record []
- end
-
- after :each do
- @io.close unless @io.closed?
- rm_r @name
- end
-
- it "does not yield any characters on an empty stream" do
- @io.send(@method) { |c| ScratchPad << c }
- ScratchPad.recorded.should == []
- end
-end
diff --git a/spec/ruby/core/io/shared/codepoints.rb b/spec/ruby/core/io/shared/codepoints.rb
deleted file mode 100644
index 6872846c1a..0000000000
--- a/spec/ruby/core/io/shared/codepoints.rb
+++ /dev/null
@@ -1,54 +0,0 @@
-# -*- encoding: utf-8 -*-
-require_relative '../fixtures/classes'
-
-describe :io_codepoints, shared: true do
- before :each do
- @io = IOSpecs.io_fixture "lines.txt"
- @enum = @io.send(@method)
- end
-
- after :each do
- @io.close
- end
-
- describe "when no block is given" do
- it "returns an Enumerator" do
- @enum.should be_an_instance_of(Enumerator)
- end
-
- describe "returned Enumerator" do
- describe "size" do
- it "should return nil" do
- @enum.size.should == nil
- end
- end
- end
- end
-
- it "yields each codepoint" do
- @enum.first(25).should == [
- 86, 111, 105, 99, 105, 32, 108, 97, 32, 108, 105, 103, 110,
- 101, 32, 117, 110, 101, 46, 10, 81, 117, 105, 32, 232
- ]
- end
-
- it "yields each codepoint starting from the current position" do
- @io.pos = 130
- @enum.to_a.should == [101, 32, 115, 105, 120, 46, 10]
- end
-
- it "raises an error if reading invalid sequence" do
- @io.pos = 60 # inside of a multibyte sequence
- -> { @enum.first }.should raise_error(ArgumentError)
- end
-
- it "does not change $_" do
- $_ = "test"
- @enum.to_a
- $_.should == "test"
- end
-
- it "raises an IOError when self is not readable" do
- -> { IOSpecs.closed_io.send(@method).to_a }.should raise_error(IOError)
- end
-end
diff --git a/spec/ruby/core/io/shared/each.rb b/spec/ruby/core/io/shared/each.rb
deleted file mode 100644
index 0747f31b8a..0000000000
--- a/spec/ruby/core/io/shared/each.rb
+++ /dev/null
@@ -1,251 +0,0 @@
-# -*- encoding: utf-8 -*-
-require_relative '../fixtures/classes'
-
-describe :io_each, shared: true do
- before :each do
- @io = IOSpecs.io_fixture "lines.txt"
- ScratchPad.record []
- end
-
- after :each do
- @io.close if @io
- end
-
- describe "with no separator" do
- it "yields each line to the passed block" do
- @io.send(@method) { |s| ScratchPad << s }
- ScratchPad.recorded.should == IOSpecs.lines
- end
-
- it "yields each line starting from the current position" do
- @io.pos = 41
- @io.send(@method) { |s| ScratchPad << s }
- ScratchPad.recorded.should == IOSpecs.lines[2..-1]
- end
-
- it "returns self" do
- @io.send(@method) { |l| l }.should equal(@io)
- end
-
- it "does not change $_" do
- $_ = "test"
- @io.send(@method) { |s| s }
- $_.should == "test"
- end
-
- it "raises an IOError when self is not readable" do
- -> { IOSpecs.closed_io.send(@method) {} }.should raise_error(IOError)
- end
-
- it "makes line count accessible via lineno" do
- @io.send(@method) { ScratchPad << @io.lineno }
- ScratchPad.recorded.should == [ 1,2,3,4,5,6,7,8,9 ]
- end
-
- it "makes line count accessible via $." do
- @io.send(@method) { ScratchPad << $. }
- ScratchPad.recorded.should == [ 1,2,3,4,5,6,7,8,9 ]
- end
-
- describe "when no block is given" do
- it "returns an Enumerator" do
- enum = @io.send(@method)
- enum.should be_an_instance_of(Enumerator)
-
- enum.each { |l| ScratchPad << l }
- ScratchPad.recorded.should == IOSpecs.lines
- end
-
- describe "returned Enumerator" do
- describe "size" do
- it "should return nil" do
- @io.send(@method).size.should == nil
- end
- end
- end
- end
- end
-
- describe "with limit" do
- describe "when limit is 0" do
- it "raises an ArgumentError" do
- # must pass block so Enumerator is evaluated and raises
- -> { @io.send(@method, 0){} }.should raise_error(ArgumentError)
- end
- end
-
- it "does not accept Integers that don't fit in a C off_t" do
- -> { @io.send(@method, 2**128){} }.should raise_error(RangeError)
- end
- end
-
- describe "when passed a String containing one space as a separator" do
- it "uses the passed argument as the line separator" do
- @io.send(@method, " ") { |s| ScratchPad << s }
- ScratchPad.recorded.should == IOSpecs.lines_space_separator
- end
-
- it "does not change $_" do
- $_ = "test"
- @io.send(@method, " ") { |s| }
- $_.should == "test"
- end
-
- it "tries to convert the passed separator to a String using #to_str" do
- obj = mock("to_str")
- obj.stub!(:to_str).and_return(" ")
-
- @io.send(@method, obj) { |l| ScratchPad << l }
- ScratchPad.recorded.should == IOSpecs.lines_space_separator
- end
- end
-
- describe "when passed nil as a separator" do
- it "yields self's content starting from the current position when the passed separator is nil" do
- @io.pos = 100
- @io.send(@method, nil) { |s| ScratchPad << s }
- ScratchPad.recorded.should == ["qui a linha cinco.\nHere is line six.\n"]
- end
- end
-
- describe "when passed an empty String as a separator" do
- it "yields each paragraph" do
- @io.send(@method, "") { |s| ScratchPad << s }
- ScratchPad.recorded.should == IOSpecs.paragraphs
- end
-
- it "discards leading newlines" do
- @io.readline
- @io.readline
- @io.send(@method, "") { |s| ScratchPad << s }
- ScratchPad.recorded.should == IOSpecs.paragraphs[1..-1]
- end
- end
-
- describe "with both separator and limit" do
- describe "when no block is given" do
- it "returns an Enumerator" do
- enum = @io.send(@method, nil, 1024)
- enum.should be_an_instance_of(Enumerator)
-
- enum.each { |l| ScratchPad << l }
- ScratchPad.recorded.should == [IOSpecs.lines.join]
- end
-
- describe "returned Enumerator" do
- describe "size" do
- it "should return nil" do
- @io.send(@method, nil, 1024).size.should == nil
- end
- end
- end
- end
-
- describe "when a block is given" do
- it "accepts an empty block" do
- @io.send(@method, nil, 1024) {}.should equal(@io)
- end
-
- describe "when passed nil as a separator" do
- it "yields self's content starting from the current position when the passed separator is nil" do
- @io.pos = 100
- @io.send(@method, nil, 1024) { |s| ScratchPad << s }
- ScratchPad.recorded.should == ["qui a linha cinco.\nHere is line six.\n"]
- end
- end
-
- describe "when passed an empty String as a separator" do
- it "yields each paragraph" do
- @io.send(@method, "", 1024) { |s| ScratchPad << s }
- ScratchPad.recorded.should == IOSpecs.paragraphs
- end
-
- it "discards leading newlines" do
- @io.readline
- @io.readline
- @io.send(@method, "", 1024) { |s| ScratchPad << s }
- ScratchPad.recorded.should == IOSpecs.paragraphs[1..-1]
- end
- end
- end
- end
-
- describe "when passed chomp" do
- it "yields each line without trailing newline characters to the passed block" do
- @io.send(@method, chomp: true) { |s| ScratchPad << s }
- 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)
-
- -> {
- @io.send(@method, "\n", 1, { chomp: true }) { |s| }
- }.should raise_error(ArgumentError, "wrong number of arguments (given 3, expected 0..2)")
- end
- end
-
- describe "when passed chomp and a separator" do
- it "yields each line without separator to the passed block" do
- @io.send(@method, " ", chomp: true) { |s| ScratchPad << s }
- ScratchPad.recorded.should == IOSpecs.lines_space_separator_without_trailing_spaces
- end
- end
-
- describe "when passed chomp and empty line as a separator" do
- it "yields each paragraph without trailing new line characters" do
- @io.send(@method, "", 1024, chomp: true) { |s| ScratchPad << s }
- ScratchPad.recorded.should == IOSpecs.paragraphs_without_trailing_new_line_characters
- end
- end
-
- describe "when passed chomp and nil as a separator" do
- it "yields self's content" do
- @io.pos = 100
- @io.send(@method, nil, chomp: true) { |s| ScratchPad << s }
- ScratchPad.recorded.should == ["qui a linha cinco.\nHere is line six.\n"]
- end
- end
-
- describe "when passed chomp, nil as a separator, and a limit" do
- it "yields each line of limit size without truncating trailing new line character" do
- # 43 - is a size of the 1st paragraph in the file
- @io.send(@method, nil, 43, chomp: true) { |s| ScratchPad << s }
-
- ScratchPad.recorded.should == [
- "Voici la ligne une.\nQui è la linea due.\n\n\n",
- "Aquí está la línea tres.\n" + "Hier ist Zeile ",
- "vier.\n\nEstá aqui a linha cinco.\nHere is li",
- "ne six.\n"
- ]
- end
- end
-
- describe "when passed too many arguments" do
- it "raises ArgumentError" do
- -> {
- @io.send(@method, "", 1, "excess argument", chomp: true) {}
- }.should raise_error(ArgumentError)
- end
- end
-end
-
-describe :io_each_default_separator, shared: true do
- before :each do
- @io = IOSpecs.io_fixture "lines.txt"
- ScratchPad.record []
- suppress_warning {@sep, $/ = $/, " "}
- end
-
- after :each do
- @io.close if @io
- suppress_warning {$/ = @sep}
- end
-
- it "uses $/ as the default line separator" do
- @io.send(@method) { |s| ScratchPad << s }
- ScratchPad.recorded.should == IOSpecs.lines_space_separator
- end
-end
diff --git a/spec/ruby/core/io/shared/new.rb b/spec/ruby/core/io/shared/new.rb
index cba5f33ebf..6f318ddee5 100644
--- a/spec/ruby/core/io/shared/new.rb
+++ b/spec/ruby/core/io/shared/new.rb
@@ -22,7 +22,7 @@ describe :io_new, shared: true do
it "creates an IO instance from an Integer argument" do
@io = IO.send(@method, @fd, "w")
- @io.should be_an_instance_of(IO)
+ @io.should.instance_of?(IO)
end
it "creates an IO instance when STDOUT is closed" do
@@ -32,7 +32,7 @@ describe :io_new, shared: true do
begin
@io = IO.send(@method, @fd, "w")
- @io.should be_an_instance_of(IO)
+ @io.should.instance_of?(IO)
ensure
STDOUT = stdout
rm_r stdout_file
@@ -49,7 +49,7 @@ describe :io_new, shared: true do
begin
@io = IO.send(@method, @fd, "w")
- @io.should be_an_instance_of(IO)
+ @io.should.instance_of?(IO)
ensure
STDERR = stderr
rm_r stderr_file
@@ -61,7 +61,7 @@ describe :io_new, shared: true do
obj = mock("file descriptor")
obj.should_receive(:to_int).and_return(@fd)
@io = IO.send(@method, obj, "w")
- @io.should be_an_instance_of(IO)
+ @io.should.instance_of?(IO)
end
it "accepts options as keyword arguments" do
@@ -70,7 +70,7 @@ describe :io_new, shared: true do
-> {
IO.send(@method, @fd, "w", {flags: File::CREAT})
- }.should raise_error(ArgumentError, "wrong number of arguments (given 3, expected 1..2)")
+ }.should.raise(ArgumentError, "wrong number of arguments (given 3, expected 1..2)")
end
it "accepts a :mode option" do
@@ -208,10 +208,30 @@ describe :io_new, shared: true do
@io.internal_encoding.to_s.should == 'IBM866'
end
+ it "does not use binary encoding when mode encoding is specified along with binmode: true option" do
+ @io = IO.send(@method, @fd, 'w:iso-8859-1', binmode: true)
+ @io.external_encoding.to_s.should == 'ISO-8859-1'
+ end
+
+ it "does not use textmode argument when mode encoding is specified" do
+ @io = IO.send(@method, @fd, 'w:ascii-8bit', textmode: true)
+ @io.external_encoding.to_s.should == 'ASCII-8BIT'
+ end
+
+ it "does not use binmode argument when external encoding is specified via the :external_encoding option" do
+ @io = IO.send(@method, @fd, 'w', binmode: true, external_encoding: 'iso-8859-1')
+ @io.external_encoding.to_s.should == 'ISO-8859-1'
+ end
+
+ it "does not use textmode argument when external encoding is specified via the :external_encoding option" do
+ @io = IO.send(@method, @fd, 'w', textmode: true, external_encoding: 'ascii-8bit')
+ @io.external_encoding.to_s.should == 'ASCII-8BIT'
+ end
+
it "raises ArgumentError for nil options" do
-> {
IO.send(@method, @fd, 'w', nil)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
it "coerces mode with #to_str" do
@@ -294,97 +314,100 @@ describe :io_new_errors, shared: true do
end
it "raises an Errno::EBADF if the file descriptor is not valid" do
- -> { IO.send(@method, -1, "w") }.should raise_error(Errno::EBADF)
+ -> { IO.send(@method, -1, "w") }.should.raise(Errno::EBADF)
end
it "raises an IOError if passed a closed stream" do
- -> { IO.send(@method, IOSpecs.closed_io.fileno, 'w') }.should raise_error(IOError)
+ -> { IO.send(@method, IOSpecs.closed_io.fileno, 'w') }.should.raise(IOError)
end
platform_is_not :windows do
it "raises an Errno::EINVAL if the new mode is not compatible with the descriptor's current mode" do
- -> { IO.send(@method, @fd, "r") }.should raise_error(Errno::EINVAL)
+ -> { IO.send(@method, @fd, "r") }.should.raise(Errno::EINVAL)
end
end
it "raises ArgumentError if passed an empty mode string" do
- -> { IO.send(@method, @fd, "") }.should raise_error(ArgumentError)
+ -> { IO.send(@method, @fd, "") }.should.raise(ArgumentError)
end
it "raises an error if passed modes two ways" do
-> {
IO.send(@method, @fd, "w", mode: "w")
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
it "raises an error if passed encodings two ways" do
-> {
@io = IO.send(@method, @fd, 'w:ISO-8859-1', encoding: 'ISO-8859-1')
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
-> {
@io = IO.send(@method, @fd, 'w:ISO-8859-1', external_encoding: 'ISO-8859-1')
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
+ -> {
+ @io = IO.send(@method, @fd, 'w:ISO-8859-1', internal_encoding: 'ISO-8859-1')
+ }.should.raise(ArgumentError)
-> {
@io = IO.send(@method, @fd, 'w:ISO-8859-1:UTF-8', internal_encoding: 'ISO-8859-1')
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
it "raises an error if passed matching binary/text mode two ways" do
-> {
@io = IO.send(@method, @fd, "wb", binmode: true)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
-> {
@io = IO.send(@method, @fd, "wt", textmode: true)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
-> {
@io = IO.send(@method, @fd, "wb", textmode: false)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
-> {
@io = IO.send(@method, @fd, "wt", binmode: false)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
it "raises an error if passed conflicting binary/text mode two ways" do
-> {
@io = IO.send(@method, @fd, "wb", binmode: false)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
-> {
@io = IO.send(@method, @fd, "wt", textmode: false)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
-> {
@io = IO.send(@method, @fd, "wb", textmode: true)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
-> {
@io = IO.send(@method, @fd, "wt", binmode: true)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
it "raises an error when trying to set both binmode and textmode" do
-> {
@io = IO.send(@method, @fd, "w", textmode: true, binmode: true)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
-> {
@io = IO.send(@method, @fd, File::Constants::WRONLY, textmode: true, binmode: true)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
it "raises ArgumentError if not passed a hash or nil for options" do
-> {
@io = IO.send(@method, @fd, 'w', false)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
-> {
@io = IO.send(@method, @fd, false, false)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
-> {
@io = IO.send(@method, @fd, nil, false)
- }.should raise_error(ArgumentError)
+ }.should.raise(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)
+ }.should.raise(ArgumentError)
end
end
diff --git a/spec/ruby/core/io/shared/pos.rb b/spec/ruby/core/io/shared/pos.rb
index 3fdd3eb2b3..450058e159 100644
--- a/spec/ruby/core/io/shared/pos.rb
+++ b/spec/ruby/core/io/shared/pos.rb
@@ -1,37 +1,3 @@
-describe :io_pos, shared: true do
- before :each do
- @fname = tmp('test.txt')
- File.open(@fname, 'w') { |f| f.write "123" }
- end
-
- after :each do
- rm_r @fname
- end
-
- it "gets the offset" do
- File.open @fname do |f|
- f.send(@method).should == 0
- f.read 1
- f.send(@method).should == 1
- f.read 2
- f.send(@method).should == 3
- end
- end
-
- it "raises IOError on closed stream" do
- -> { IOSpecs.closed_io.send(@method) }.should raise_error(IOError)
- end
-
- it "resets #eof?" do
- open @fname do |io|
- io.read 1
- io.read 1
- io.send(@method)
- io.should_not.eof?
- end
- end
-end
-
describe :io_set_pos, shared: true do
before :each do
@fname = tmp('test.txt')
@@ -62,17 +28,17 @@ describe :io_set_pos, shared: true do
it "raises TypeError when cannot convert implicitly argument to Integer" do
File.open @fname do |io|
- -> { io.send @method, Object.new }.should raise_error(TypeError, "no implicit conversion of Object into Integer")
+ -> { io.send @method, Object.new }.should.raise(TypeError, "no implicit conversion of Object into Integer")
end
end
it "does not accept Integers that don't fit in a C off_t" do
File.open @fname do |io|
- -> { io.send @method, 2**128 }.should raise_error(RangeError)
+ -> { io.send @method, 2**128 }.should.raise(RangeError)
end
end
it "raises IOError on closed stream" do
- -> { IOSpecs.closed_io.send @method, 0 }.should raise_error(IOError)
+ -> { IOSpecs.closed_io.send @method, 0 }.should.raise(IOError)
end
end
diff --git a/spec/ruby/core/io/shared/readlines.rb b/spec/ruby/core/io/shared/readlines.rb
index 6c1fa11a59..f54fccc2e3 100644
--- a/spec/ruby/core/io/shared/readlines.rb
+++ b/spec/ruby/core/io/shared/readlines.rb
@@ -1,11 +1,11 @@
describe :io_readlines, shared: true do
it "raises TypeError if the first parameter is nil" do
- -> { IO.send(@method, nil, &@object) }.should raise_error(TypeError)
+ -> { IO.send(@method, nil, &@object) }.should.raise(TypeError)
end
it "raises an Errno::ENOENT if the file does not exist" do
name = tmp("nonexistent.txt")
- -> { IO.send(@method, name, &@object) }.should raise_error(Errno::ENOENT)
+ -> { IO.send(@method, name, &@object) }.should.raise(Errno::ENOENT)
end
it "yields a single string with entire content when the separator is nil" do
@@ -80,14 +80,12 @@ describe :io_readlines_options_19, shared: true do
end
it "does not accept Integers that don't fit in a C off_t" do
- -> { IO.send(@method, @name, 2**128, &@object) }.should raise_error(RangeError)
+ -> { IO.send(@method, @name, 2**128, &@object) }.should.raise(RangeError)
end
- ruby_bug "#18767", ""..."3.3" do
- describe "when passed limit" do
- it "raises ArgumentError when passed 0 as a limit" do
- -> { IO.send(@method, @name, 0, &@object) }.should raise_error(ArgumentError)
- end
+ describe "when passed limit" do
+ it "raises ArgumentError when passed 0 as a limit" do
+ -> { IO.send(@method, @name, 0, &@object) }.should.raise(ArgumentError)
end
end
end
@@ -108,7 +106,7 @@ describe :io_readlines_options_19, shared: true do
it "raises TypeError exception" do
-> {
IO.send(@method, @name, { chomp: true }, &@object)
- }.should raise_error(TypeError)
+ }.should.raise(TypeError)
end
end
@@ -118,7 +116,7 @@ describe :io_readlines_options_19, shared: true do
-> {
IO.send(@method, @name, obj, &@object)
- }.should raise_error(TypeError)
+ }.should.raise(TypeError)
end
end
end
@@ -172,7 +170,7 @@ describe :io_readlines_options_19, shared: true do
-> {
IO.send(@method, @name, " ", obj, &@object)
- }.should raise_error(TypeError)
+ }.should.raise(TypeError)
end
end
@@ -180,7 +178,7 @@ describe :io_readlines_options_19, shared: true do
it "raises TypeError exception" do
-> {
IO.send(@method, @name, "", { chomp: true }, &@object)
- }.should raise_error(TypeError)
+ }.should.raise(TypeError)
end
end
end
@@ -190,7 +188,7 @@ describe :io_readlines_options_19, shared: true do
it "uses the keyword arguments as options" do
-> do
IO.send(@method, @filename, 10, mode: "w", &@object)
- end.should raise_error(IOError)
+ end.should.raise(IOError)
end
end
@@ -198,7 +196,7 @@ describe :io_readlines_options_19, shared: true do
it "uses the keyword arguments as options" do
-> do
IO.send(@method, @filename, " ", mode: "w", &@object)
- end.should raise_error(IOError)
+ end.should.raise(IOError)
end
end
@@ -209,7 +207,7 @@ describe :io_readlines_options_19, shared: true do
-> do
IO.send(@method, @filename, sep, mode: "w", &@object)
- end.should raise_error(IOError)
+ end.should.raise(IOError)
end
end
end
@@ -239,7 +237,7 @@ describe :io_readlines_options_19, shared: true do
it "uses the keyword arguments as options" do
-> do
IO.send(@method, @filename, " ", 10, mode: "w", &@object)
- end.should raise_error(IOError)
+ end.should.raise(IOError)
end
describe "when passed chomp, nil as a separator, and a limit" do
diff --git a/spec/ruby/core/io/shared/tty.rb b/spec/ruby/core/io/shared/tty.rb
deleted file mode 100644
index 89ac08ec86..0000000000
--- a/spec/ruby/core/io/shared/tty.rb
+++ /dev/null
@@ -1,24 +0,0 @@
-require_relative '../fixtures/classes'
-
-describe :io_tty, shared: true do
- platform_is_not :windows do
- it "returns true if this stream is a terminal device (TTY)" do
- begin
- # check to enabled tty
- File.open('/dev/tty') {}
- rescue Errno::ENXIO
- skip "workaround for not configured environment like OS X"
- else
- File.open('/dev/tty') { |f| f.send(@method) }.should == true
- end
- end
- end
-
- it "returns false if this stream is not a terminal device (TTY)" do
- File.open(__FILE__) { |f| f.send(@method) }.should == false
- end
-
- it "raises IOError on closed stream" do
- -> { IOSpecs.closed_io.send @method }.should raise_error(IOError)
- end
-end
diff --git a/spec/ruby/core/io/shared/write.rb b/spec/ruby/core/io/shared/write.rb
index 964064746a..5de9fe4335 100644
--- a/spec/ruby/core/io/shared/write.rb
+++ b/spec/ruby/core/io/shared/write.rb
@@ -23,7 +23,7 @@ describe :io_write, shared: true do
end
it "checks if the file is writable if writing more than zero bytes" do
- -> { @readonly_file.send(@method, "abcde") }.should raise_error(IOError)
+ -> { @readonly_file.send(@method, "abcde") }.should.raise(IOError)
end
it "returns the number of bytes written" do
@@ -66,7 +66,7 @@ describe :io_write, shared: true do
end
it "raises IOError on closed stream" do
- -> { IOSpecs.closed_io.send(@method, "hello") }.should raise_error(IOError)
+ -> { IOSpecs.closed_io.send(@method, "hello") }.should.raise(IOError)
end
describe "on a pipe" do
@@ -92,7 +92,7 @@ describe :io_write, shared: true do
guard_not -> { defined?(RubyVM::RJIT) && RubyVM::RJIT.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/)
+ -> { @w.send(@method, "foo") }.should.raise(Errno::EPIPE, /Broken pipe/)
end
end
end
@@ -126,7 +126,7 @@ describe :io_write_transcode, shared: true do
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)
+ -> { file.send(@method, str) }.should.raise(Encoding::UndefinedConversionError)
end
end
end
diff --git a/spec/ruby/core/io/stat_spec.rb b/spec/ruby/core/io/stat_spec.rb
index 717c45d0a3..f9fc232ee0 100644
--- a/spec/ruby/core/io/stat_spec.rb
+++ b/spec/ruby/core/io/stat_spec.rb
@@ -12,14 +12,14 @@ describe "IO#stat" do
end
it "raises IOError on closed stream" do
- -> { IOSpecs.closed_io.stat }.should raise_error(IOError)
+ -> { IOSpecs.closed_io.stat }.should.raise(IOError)
end
it "returns a File::Stat object for the stream" do
- STDOUT.stat.should be_an_instance_of(File::Stat)
+ STDOUT.stat.should.instance_of?(File::Stat)
end
it "can stat pipes" do
- @io.stat.should be_an_instance_of(File::Stat)
+ @io.stat.should.instance_of?(File::Stat)
end
end
diff --git a/spec/ruby/core/io/sync_spec.rb b/spec/ruby/core/io/sync_spec.rb
index 993b7ee244..b537db335b 100644
--- a/spec/ruby/core/io/sync_spec.rb
+++ b/spec/ruby/core/io/sync_spec.rb
@@ -27,7 +27,7 @@ describe "IO#sync=" do
end
it "raises an IOError on closed stream" do
- -> { IOSpecs.closed_io.sync = true }.should raise_error(IOError)
+ -> { IOSpecs.closed_io.sync = true }.should.raise(IOError)
end
end
@@ -45,7 +45,7 @@ describe "IO#sync" do
end
it "raises an IOError on closed stream" do
- -> { IOSpecs.closed_io.sync }.should raise_error(IOError)
+ -> { IOSpecs.closed_io.sync }.should.raise(IOError)
end
end
diff --git a/spec/ruby/core/io/sysopen_spec.rb b/spec/ruby/core/io/sysopen_spec.rb
index 7ad379df3a..325d51ed23 100644
--- a/spec/ruby/core/io/sysopen_spec.rb
+++ b/spec/ruby/core/io/sysopen_spec.rb
@@ -13,16 +13,16 @@ describe "IO.sysopen" do
it "returns the file descriptor for a given path" do
@fd = IO.sysopen(@filename, "w")
- @fd.should be_kind_of(Integer)
- @fd.should_not equal(0)
+ @fd.should.is_a?(Integer)
+ @fd.should_not.equal?(0)
end
# opening a directory is not supported on Windows
platform_is_not :windows do
it "works on directories" do
@fd = IO.sysopen(tmp("")) # /tmp
- @fd.should be_kind_of(Integer)
- @fd.should_not equal(0)
+ @fd.should.is_a?(Integer)
+ @fd.should_not.equal?(0)
end
end
@@ -33,18 +33,18 @@ describe "IO.sysopen" do
end
it "accepts a mode as second argument" do
- -> { @fd = IO.sysopen(@filename, "w") }.should_not raise_error
- @fd.should_not equal(0)
+ -> { @fd = IO.sysopen(@filename, "w") }.should_not.raise
+ @fd.should_not.equal?(0)
end
it "accepts permissions as third argument" do
@fd = IO.sysopen(@filename, "w", 777)
- @fd.should_not equal(0)
+ @fd.should_not.equal?(0)
end
it "accepts mode & permission that are nil" do
touch @filename # create the file
@fd = IO.sysopen(@filename, nil, nil)
- @fd.should_not equal(0)
+ @fd.should_not.equal?(0)
end
end
diff --git a/spec/ruby/core/io/sysread_spec.rb b/spec/ruby/core/io/sysread_spec.rb
index d56a27b3af..2d58db2250 100644
--- a/spec/ruby/core/io/sysread_spec.rb
+++ b/spec/ruby/core/io/sysread_spec.rb
@@ -52,7 +52,7 @@ describe "IO#sysread on a file" do
it "raises an error when called after buffered reads" do
@file.readline
- -> { @file.sysread(5) }.should raise_error(IOError)
+ -> { @file.sysread(5) }.should.raise(IOError)
end
it "reads normally even when called immediately after a buffered IO#read" do
@@ -63,13 +63,13 @@ describe "IO#sysread on a file" do
it "does not raise error if called after IO#read followed by IO#write" do
@file.read(5)
@file.write("abcde")
- -> { @file.sysread(5) }.should_not raise_error(IOError)
+ -> { @file.sysread(5) }.should_not.raise(IOError)
end
it "does not raise error if called after IO#read followed by IO#syswrite" do
@file.read(5)
@file.syswrite("abcde")
- -> { @file.sysread(5) }.should_not raise_error(IOError)
+ -> { @file.sysread(5) }.should_not.raise(IOError)
end
it "reads updated content after the flushed buffered IO#write" do
@@ -82,7 +82,7 @@ describe "IO#sysread on a file" do
end
it "raises IOError on closed stream" do
- -> { IOSpecs.closed_io.sysread(5) }.should raise_error(IOError)
+ -> { IOSpecs.closed_io.sysread(5) }.should.raise(IOError)
end
it "immediately returns an empty string if the length argument is 0" do
@@ -104,8 +104,8 @@ describe "IO#sysread on a file" do
it "discards the existing buffer content upon error" do
buffer = +"existing content"
@file.seek(0, :END)
- -> { @file.sysread(1, buffer) }.should raise_error(EOFError)
- buffer.should be_empty
+ -> { @file.sysread(1, buffer) }.should.raise(EOFError)
+ buffer.should.empty?
end
it "preserves the encoding of the given buffer" do
@@ -132,6 +132,6 @@ describe "IO#sysread" do
end
it "raises ArgumentError when length is less than 0" do
- -> { @read.sysread(-1) }.should raise_error(ArgumentError)
+ -> { @read.sysread(-1) }.should.raise(ArgumentError)
end
end
diff --git a/spec/ruby/core/io/sysseek_spec.rb b/spec/ruby/core/io/sysseek_spec.rb
index 002f2a14eb..2384895dc5 100644
--- a/spec/ruby/core/io/sysseek_spec.rb
+++ b/spec/ruby/core/io/sysseek_spec.rb
@@ -23,7 +23,7 @@ describe "IO#sysseek" do
it "raises an error when called after buffered reads" do
@io.readline
- -> { @io.sysseek(-5, IO::SEEK_CUR) }.should raise_error(IOError)
+ -> { @io.sysseek(-5, IO::SEEK_CUR) }.should.raise(IOError)
end
it "seeks normally even when called immediately after a buffered IO#read" do
@@ -41,7 +41,7 @@ describe "IO#sysseek" do
# this is the safest way of checking the EOF when
# sys-* methods are invoked
- -> { @io.sysread(1) }.should raise_error(EOFError)
+ -> { @io.sysread(1) }.should.raise(EOFError)
@io.sysseek(-25, IO::SEEK_END)
@io.sysread(7).should == "cinco.\n"
diff --git a/spec/ruby/core/io/tell_spec.rb b/spec/ruby/core/io/tell_spec.rb
index 0d6c6b02d3..a6b51adc17 100644
--- a/spec/ruby/core/io/tell_spec.rb
+++ b/spec/ruby/core/io/tell_spec.rb
@@ -1,7 +1,7 @@
require_relative '../../spec_helper'
-require_relative 'fixtures/classes'
-require_relative 'shared/pos'
describe "IO#tell" do
- it_behaves_like :io_pos, :tell
+ it "is an alias of IO#pos" do
+ IO.instance_method(:tell).should == IO.instance_method(:pos)
+ end
end
diff --git a/spec/ruby/core/io/to_i_spec.rb b/spec/ruby/core/io/to_i_spec.rb
index acf138c663..b271112a81 100644
--- a/spec/ruby/core/io/to_i_spec.rb
+++ b/spec/ruby/core/io/to_i_spec.rb
@@ -1,12 +1,7 @@
require_relative '../../spec_helper'
-require_relative 'fixtures/classes'
describe "IO#to_i" do
- it "returns the numeric file descriptor of the given IO object" do
- $stdout.to_i.should == 1
- end
-
- it "raises IOError on closed stream" do
- -> { IOSpecs.closed_io.to_i }.should raise_error(IOError)
+ it "is an alias of IO#fileno" do
+ IO.instance_method(:to_i).should == IO.instance_method(:fileno)
end
end
diff --git a/spec/ruby/core/io/to_io_spec.rb b/spec/ruby/core/io/to_io_spec.rb
index 55a0977740..0b1809dffa 100644
--- a/spec/ruby/core/io/to_io_spec.rb
+++ b/spec/ruby/core/io/to_io_spec.rb
@@ -11,11 +11,11 @@ describe "IO#to_io" do
end
it "returns self for open stream" do
- @io.to_io.should equal(@io)
+ @io.to_io.should.equal?(@io)
end
it "returns self for closed stream" do
io = IOSpecs.closed_io
- io.to_io.should equal(io)
+ io.to_io.should.equal?(io)
end
end
diff --git a/spec/ruby/core/io/to_path_spec.rb b/spec/ruby/core/io/to_path_spec.rb
new file mode 100644
index 0000000000..ec6dffc115
--- /dev/null
+++ b/spec/ruby/core/io/to_path_spec.rb
@@ -0,0 +1,7 @@
+require_relative '../../spec_helper'
+
+describe "IO#to_path" do
+ it "is an alias of IO#path" do
+ IO.instance_method(:to_path).should == IO.instance_method(:path)
+ end
+end
diff --git a/spec/ruby/core/io/try_convert_spec.rb b/spec/ruby/core/io/try_convert_spec.rb
index a9e99de7aa..7600b01b75 100644
--- a/spec/ruby/core/io/try_convert_spec.rb
+++ b/spec/ruby/core/io/try_convert_spec.rb
@@ -13,7 +13,7 @@ describe "IO.try_convert" do
end
it "returns the passed IO object" do
- IO.try_convert(@io).should equal(@io)
+ IO.try_convert(@io).should.equal?(@io)
end
it "does not call #to_io on an IO instance" do
@@ -24,26 +24,26 @@ describe "IO.try_convert" do
it "calls #to_io to coerce an object" do
obj = mock("io")
obj.should_receive(:to_io).and_return(@io)
- IO.try_convert(obj).should equal(@io)
+ IO.try_convert(obj).should.equal?(@io)
end
it "returns nil when the passed object does not respond to #to_io" do
- IO.try_convert(mock("io")).should be_nil
+ IO.try_convert(mock("io")).should == nil
end
it "return nil when BasicObject is passed" do
- IO.try_convert(BasicObject.new).should be_nil
+ IO.try_convert(BasicObject.new).should == nil
end
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_consistent_error(TypeError, "can't convert MockObject into IO (MockObject#to_io gives String)")
end
it "propagates an exception raised by #to_io" do
obj = mock("io")
obj.should_receive(:to_io).and_raise(TypeError.new)
- ->{ IO.try_convert(obj) }.should raise_error(TypeError)
+ ->{ IO.try_convert(obj) }.should.raise(TypeError)
end
end
diff --git a/spec/ruby/core/io/tty_spec.rb b/spec/ruby/core/io/tty_spec.rb
index 3b76c6d2b8..e1848a1760 100644
--- a/spec/ruby/core/io/tty_spec.rb
+++ b/spec/ruby/core/io/tty_spec.rb
@@ -1,6 +1,25 @@
require_relative '../../spec_helper'
-require_relative 'shared/tty'
+require_relative 'fixtures/classes'
describe "IO#tty?" do
- it_behaves_like :io_tty, :tty?
+ platform_is_not :windows do
+ it "returns true if this stream is a terminal device (TTY)" do
+ begin
+ # check to enabled tty
+ File.open('/dev/tty') {}
+ rescue Errno::ENXIO
+ skip "workaround for not configured environment like OS X"
+ else
+ File.open('/dev/tty') { |f| f.tty? }.should == true
+ end
+ end
+ end
+
+ it "returns false if this stream is not a terminal device (TTY)" do
+ File.open(__FILE__) { |f| f.tty? }.should == false
+ end
+
+ it "raises IOError on closed stream" do
+ -> { IOSpecs.closed_io.tty? }.should.raise(IOError)
+ end
end
diff --git a/spec/ruby/core/io/ungetbyte_spec.rb b/spec/ruby/core/io/ungetbyte_spec.rb
index 716743a6af..e0615cd76c 100644
--- a/spec/ruby/core/io/ungetbyte_spec.rb
+++ b/spec/ruby/core/io/ungetbyte_spec.rb
@@ -13,12 +13,12 @@ describe "IO#ungetbyte" do
end
it "does nothing when passed nil" do
- @io.ungetbyte(nil).should be_nil
+ @io.ungetbyte(nil).should == nil
@io.getbyte.should == 97
end
it "puts back each byte in a String argument" do
- @io.ungetbyte("cat").should be_nil
+ @io.ungetbyte("cat").should == nil
@io.getbyte.should == 99
@io.getbyte.should == 97
@io.getbyte.should == 116
@@ -29,7 +29,7 @@ describe "IO#ungetbyte" do
str = mock("io ungetbyte")
str.should_receive(:to_str).and_return("dog")
- @io.ungetbyte(str).should be_nil
+ @io.ungetbyte(str).should == nil
@io.getbyte.should == 100
@io.getbyte.should == 111
@io.getbyte.should == 103
@@ -38,17 +38,17 @@ describe "IO#ungetbyte" do
it "never raises RangeError" do
for i in [4095, 0x4f7574206f6620636861722072616e67ff] do
- @io.ungetbyte(i).should be_nil
+ @io.ungetbyte(i).should == nil
@io.getbyte.should == 255
end
end
it "raises IOError on stream not opened for reading" do
- -> { STDOUT.ungetbyte(42) }.should raise_error(IOError, "not opened for reading")
+ -> { STDOUT.ungetbyte(42) }.should.raise(IOError, "not opened for reading")
end
it "raises an IOError if the IO is closed" do
@io.close
- -> { @io.ungetbyte(42) }.should raise_error(IOError)
+ -> { @io.ungetbyte(42) }.should.raise(IOError)
end
end
diff --git a/spec/ruby/core/io/ungetc_spec.rb b/spec/ruby/core/io/ungetc_spec.rb
index 47a4e99ebf..4a9e67f126 100644
--- a/spec/ruby/core/io/ungetc_spec.rb
+++ b/spec/ruby/core/io/ungetc_spec.rb
@@ -100,17 +100,17 @@ describe "IO#ungetc" do
it "makes subsequent unbuffered operations to raise IOError" do
@io.getc
@io.ungetc(100)
- -> { @io.sysread(1) }.should raise_error(IOError)
+ -> { @io.sysread(1) }.should.raise(IOError)
end
it "raises TypeError if passed nil" do
@io.getc.should == ?V
- proc{@io.ungetc(nil)}.should raise_error(TypeError)
+ proc{@io.ungetc(nil)}.should.raise(TypeError)
end
it "puts one or more characters back in the stream" do
@io.gets
- @io.ungetc("Aquí ").should be_nil
+ @io.ungetc("Aquí ").should == nil
@io.gets.chomp.should == "Aquí Qui è la linea due."
end
@@ -118,21 +118,21 @@ describe "IO#ungetc" do
chars = mock("io ungetc")
chars.should_receive(:to_str).and_return("Aquí ")
- @io.ungetc(chars).should be_nil
+ @io.ungetc(chars).should == nil
@io.gets.chomp.should == "Aquí Voici la ligne une."
end
it "returns nil when invoked on stream that was not yet read" do
- @io.ungetc(100).should be_nil
+ @io.ungetc(100).should == nil
end
it "raises IOError on stream not opened for reading" do
- -> { STDOUT.ungetc(100) }.should raise_error(IOError, "not opened for reading")
+ -> { STDOUT.ungetc(100) }.should.raise(IOError, "not opened for reading")
end
it "raises IOError on closed stream" do
@io.getc
@io.close
- -> { @io.ungetc(100) }.should raise_error(IOError)
+ -> { @io.ungetc(100) }.should.raise(IOError)
end
end
diff --git a/spec/ruby/core/io/write_nonblock_spec.rb b/spec/ruby/core/io/write_nonblock_spec.rb
index 5bfc690f9b..a6bd43c058 100644
--- a/spec/ruby/core/io/write_nonblock_spec.rb
+++ b/spec/ruby/core/io/write_nonblock_spec.rb
@@ -44,7 +44,7 @@ platform_is_not :windows do
it "checks if the file is writable if writing zero bytes" do
-> {
@readonly_file.write_nonblock("")
- }.should raise_error(IOError)
+ }.should.raise(IOError)
end
end
@@ -67,12 +67,12 @@ describe 'IO#write_nonblock' do
it "raises an exception extending IO::WaitWritable when the write would block" do
-> {
loop { @write.write_nonblock('a' * 10_000) }
- }.should raise_error(IO::WaitWritable) { |e|
+ }.should.raise(IO::WaitWritable) { |e|
platform_is_not :windows do
- e.should be_kind_of(Errno::EAGAIN)
+ e.should.is_a?(Errno::EAGAIN)
end
platform_is :windows do
- e.should be_kind_of(Errno::EWOULDBLOCK)
+ e.should.is_a?(Errno::EWOULDBLOCK)
end
}
end
diff --git a/spec/ruby/core/io/write_spec.rb b/spec/ruby/core/io/write_spec.rb
index 4a26f8dbaf..1a745ba012 100644
--- a/spec/ruby/core/io/write_spec.rb
+++ b/spec/ruby/core/io/write_spec.rb
@@ -21,7 +21,7 @@ describe "IO#write on a file" do
end
it "does not check if the file is writable if writing zero bytes" do
- -> { @readonly_file.write("") }.should_not raise_error
+ -> { @readonly_file.write("") }.should_not.raise
end
before :each do
@@ -102,11 +102,18 @@ describe "IO#write on a file" do
File.binread(@filename).should == "h\u0000\u0000\u0000i\u0000\u0000\u0000"
end
+ it "ignores the 'bom|' prefix" do
+ File.open(@filename, "w", encoding: 'bom|utf-8') do |file|
+ file.write("hi")
+ end
+ File.binread(@filename).should == "hi"
+ end
+
it "raises a invalid byte sequence error if invalid bytes are being written" do
# pack "\xFEhi" to avoid utf-8 conflict
xFEhi = ([254].pack('C*') + 'hi').force_encoding('utf-8')
File.open(@filename, "w", encoding: Encoding::US_ASCII) do |file|
- -> { file.write(xFEhi) }.should raise_error(Encoding::InvalidByteSequenceError)
+ -> { file.write(xFEhi) }.should.raise(Encoding::InvalidByteSequenceError)
end
end
@@ -150,7 +157,7 @@ describe "IO.write" do
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")
+ }.should.raise(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
@@ -159,7 +166,7 @@ describe "IO.write" do
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")
+ }.should.raise(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
@@ -172,11 +179,11 @@ describe "IO.write" do
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")
+ }.should.raise(ArgumentError, "encoding specified twice")
-> {
IO.write(@filename, 'hi', mode: "w:UTF-16BE", encoding: Encoding::UTF_32LE)
- }.should raise_error(ArgumentError, "encoding specified twice")
+ }.should.raise(ArgumentError, "encoding specified twice")
end
it "writes the file with the permissions in the :perm parameter" do
@@ -220,7 +227,7 @@ describe "IO.write" do
end
end
- ruby_version_is "3.3" do
+ ruby_version_is ""..."4.0" do
# https://bugs.ruby-lang.org/issues/19630
it "warns about deprecation given a path with a pipe" do
-> {
diff --git a/spec/ruby/core/kernel/Array_spec.rb b/spec/ruby/core/kernel/Array_spec.rb
index b4a8bb7599..063faf7097 100644
--- a/spec/ruby/core/kernel/Array_spec.rb
+++ b/spec/ruby/core/kernel/Array_spec.rb
@@ -3,7 +3,7 @@ require_relative 'fixtures/classes'
describe "Kernel" do
it "has private instance method Array()" do
- Kernel.should have_private_instance_method(:Array)
+ Kernel.private_instance_methods(false).should.include?(:Array)
end
end
@@ -77,14 +77,14 @@ describe :kernel_Array, shared: true do
obj = mock("Array() string")
obj.should_receive(:to_ary).and_return("string")
- -> { @object.send(@method, obj) }.should raise_error(TypeError)
+ -> { @object.send(@method, obj) }.should.raise(TypeError)
end
it "raises a TypeError if #to_a does not return an Array" do
obj = mock("Array() string")
obj.should_receive(:to_a).and_return("string")
- -> { @object.send(@method, obj) }.should raise_error(TypeError)
+ -> { @object.send(@method, obj) }.should.raise(TypeError)
end
end
diff --git a/spec/ruby/core/kernel/Complex_spec.rb b/spec/ruby/core/kernel/Complex_spec.rb
index 346d50ab5e..92ce183cc8 100644
--- a/spec/ruby/core/kernel/Complex_spec.rb
+++ b/spec/ruby/core/kernel/Complex_spec.rb
@@ -19,19 +19,19 @@ describe "Kernel.Complex()" do
describe "when passed [Integer, Integer]" do
it "returns a new Complex number" do
- Complex(1, 2).should be_an_instance_of(Complex)
+ Complex(1, 2).should.instance_of?(Complex)
Complex(1, 2).real.should == 1
Complex(1, 2).imag.should == 2
- Complex(-3, -5).should be_an_instance_of(Complex)
+ Complex(-3, -5).should.instance_of?(Complex)
Complex(-3, -5).real.should == -3
Complex(-3, -5).imag.should == -5
- Complex(3.5, -4.5).should be_an_instance_of(Complex)
+ Complex(3.5, -4.5).should.instance_of?(Complex)
Complex(3.5, -4.5).real.should == 3.5
Complex(3.5, -4.5).imag.should == -4.5
- Complex(bignum_value, 30).should be_an_instance_of(Complex)
+ Complex(bignum_value, 30).should.instance_of?(Complex)
Complex(bignum_value, 30).real.should == bignum_value
Complex(bignum_value, 30).imag.should == 30
end
@@ -41,19 +41,19 @@ describe "Kernel.Complex()" do
it "returns a new Complex number with 0 as the imaginary component" do
# Guard against the Mathn library
guard -> { !defined?(Math.rsqrt) } do
- Complex(1).should be_an_instance_of(Complex)
+ Complex(1).should.instance_of?(Complex)
Complex(1).imag.should == 0
Complex(1).real.should == 1
- Complex(-3).should be_an_instance_of(Complex)
+ Complex(-3).should.instance_of?(Complex)
Complex(-3).imag.should == 0
Complex(-3).real.should == -3
- Complex(-4.5).should be_an_instance_of(Complex)
+ Complex(-4.5).should.instance_of?(Complex)
Complex(-4.5).imag.should == 0
Complex(-4.5).real.should == -4.5
- Complex(bignum_value).should be_an_instance_of(Complex)
+ Complex(bignum_value).should.instance_of?(Complex)
Complex(bignum_value).imag.should == 0
Complex(bignum_value).real.should == bignum_value
end
@@ -67,47 +67,47 @@ describe "Kernel.Complex()" do
it "raises Encoding::CompatibilityError if String is in not ASCII-compatible encoding" do
-> {
Complex("79+4i".encode("UTF-16"))
- }.should raise_error(Encoding::CompatibilityError, "ASCII incompatible encoding: UTF-16")
+ }.should.raise(Encoding::CompatibilityError, "ASCII incompatible encoding: UTF-16")
end
it "raises ArgumentError for unrecognised Strings" do
-> {
Complex("ruby")
- }.should raise_error(ArgumentError, 'invalid value for convert(): "ruby"')
+ }.should.raise(ArgumentError, 'invalid value for convert(): "ruby"')
end
it "raises ArgumentError for trailing garbage" do
-> {
Complex("79+4iruby")
- }.should raise_error(ArgumentError, 'invalid value for convert(): "79+4iruby"')
+ }.should.raise(ArgumentError, 'invalid value for convert(): "79+4iruby"')
end
it "does not understand Float::INFINITY" do
-> {
Complex("Infinity")
- }.should raise_error(ArgumentError, 'invalid value for convert(): "Infinity"')
+ }.should.raise(ArgumentError, 'invalid value for convert(): "Infinity"')
-> {
Complex("-Infinity")
- }.should raise_error(ArgumentError, 'invalid value for convert(): "-Infinity"')
+ }.should.raise(ArgumentError, 'invalid value for convert(): "-Infinity"')
end
it "does not understand Float::NAN" do
-> {
Complex("NaN")
- }.should raise_error(ArgumentError, 'invalid value for convert(): "NaN"')
+ }.should.raise(ArgumentError, 'invalid value for convert(): "NaN"')
end
it "does not understand a sequence of _" do
-> {
Complex("7__9+4__0i")
- }.should raise_error(ArgumentError, 'invalid value for convert(): "7__9+4__0i"')
+ }.should.raise(ArgumentError, 'invalid value for convert(): "7__9+4__0i"')
end
it "does not allow null-byte" do
-> {
Complex("1-2i\0")
- }.should raise_error(ArgumentError, "string contains null byte")
+ }.should.raise(ArgumentError, "string contains null byte")
end
end
@@ -115,7 +115,7 @@ describe "Kernel.Complex()" do
it "raises Encoding::CompatibilityError if String is in not ASCII-compatible encoding" do
-> {
Complex("79+4i".encode("UTF-16"), exception: false)
- }.should raise_error(Encoding::CompatibilityError, "ASCII incompatible encoding: UTF-16")
+ }.should.raise(Encoding::CompatibilityError, "ASCII incompatible encoding: UTF-16")
end
it "returns nil for unrecognised Strings" do
@@ -160,7 +160,7 @@ describe "Kernel.Complex()" do
it "returns the passed argument" do
n = mock_numeric("unreal")
n.should_receive(:real?).any_number_of_times.and_return(false)
- Complex(n).should equal(n)
+ Complex(n).should.equal?(n)
end
end
@@ -169,8 +169,8 @@ describe "Kernel.Complex()" do
n = mock_numeric("real")
n.should_receive(:real?).any_number_of_times.and_return(true)
result = Complex(n)
- result.real.should equal(n)
- result.imag.should equal(0)
+ result.real.should.equal?(n)
+ result.imag.should.equal?(0)
end
end
@@ -185,7 +185,7 @@ describe "Kernel.Complex()" do
n2.should_receive(:real?).any_number_of_times.and_return(r2)
n2.should_receive(:*).with(Complex(0, 1)).and_return(n3)
n1.should_receive(:+).with(n3).and_return(n4)
- Complex(n1, n2).should equal(n4)
+ Complex(n1, n2).should.equal?(n4)
end
end
end
@@ -197,8 +197,8 @@ describe "Kernel.Complex()" do
n1.should_receive(:real?).any_number_of_times.and_return(true)
n2.should_receive(:real?).any_number_of_times.and_return(true)
result = Complex(n1, n2)
- result.real.should equal(n1)
- result.imag.should equal(n2)
+ result.real.should.equal?(n1)
+ result.imag.should.equal?(n2)
end
end
@@ -207,22 +207,22 @@ describe "Kernel.Complex()" do
n = mock("n")
c = Complex(0, 0)
n.should_receive(:to_c).and_return(c)
- Complex(n).should equal(c)
+ Complex(n).should.equal?(c)
end
end
describe "when passed a non-Numeric second argument" do
it "raises TypeError" do
- -> { Complex(:sym, :sym) }.should raise_error(TypeError)
- -> { Complex(0, :sym) }.should raise_error(TypeError)
+ -> { Complex(:sym, :sym) }.should.raise(TypeError)
+ -> { Complex(0, :sym) }.should.raise(TypeError)
end
end
describe "when passed nil" do
it "raises TypeError" do
- -> { Complex(nil) }.should raise_error(TypeError, "can't convert nil into Complex")
- -> { Complex(0, nil) }.should raise_error(TypeError, "can't convert nil into Complex")
- -> { Complex(nil, 0) }.should raise_error(TypeError, "can't convert nil into Complex")
+ -> { Complex(nil) }.should.raise(TypeError, "can't convert nil into Complex")
+ -> { Complex(0, nil) }.should.raise(TypeError, "can't convert nil into Complex")
+ -> { Complex(nil, 0) }.should.raise(TypeError, "can't convert nil into Complex")
end
end
@@ -241,7 +241,7 @@ describe "Kernel.Complex()" do
describe "and [non-Numeric, Numeric] argument" do
it "throws a TypeError" do
- -> { Complex(:sym, 0, exception: false) }.should raise_error(TypeError, "not a real")
+ -> { Complex(:sym, 0, exception: false) }.should.raise(TypeError, "not a real")
end
end
diff --git a/spec/ruby/core/kernel/Float_spec.rb b/spec/ruby/core/kernel/Float_spec.rb
index 1705205996..f5566067ba 100644
--- a/spec/ruby/core/kernel/Float_spec.rb
+++ b/spec/ruby/core/kernel/Float_spec.rb
@@ -6,7 +6,7 @@ describe :kernel_float, shared: true do
float = 1.12
float2 = @object.send(:Float, float)
float2.should == float
- float2.should equal float
+ float2.should.equal? float
end
it "returns a Float for Fixnums" do
@@ -22,22 +22,22 @@ describe :kernel_float, shared: true do
end
it "raises an ArgumentError for nil" do
- -> { @object.send(:Float, nil) }.should raise_error(TypeError)
+ -> { @object.send(:Float, nil) }.should.raise(TypeError)
end
it "returns the identical NaN for NaN" do
nan = nan_value
- nan.nan?.should be_true
+ nan.nan?.should == true
nan2 = @object.send(:Float, nan)
- nan2.nan?.should be_true
- nan2.should equal(nan)
+ nan2.nan?.should == true
+ nan2.should.equal?(nan)
end
it "returns the same Infinity for Infinity" do
infinity = infinity_value
infinity2 = @object.send(:Float, infinity)
infinity2.should == infinity_value
- infinity.should equal(infinity2)
+ infinity.should.equal?(infinity2)
end
it "converts Strings to floats without calling #to_f" do
@@ -51,30 +51,30 @@ describe :kernel_float, shared: true do
end
it "raises an ArgumentError for a String of word characters" do
- -> { @object.send(:Float, "float") }.should raise_error(ArgumentError)
+ -> { @object.send(:Float, "float") }.should.raise(ArgumentError)
end
it "raises an ArgumentError for a String with string in error message" do
- -> { @object.send(:Float, "foo") }.should raise_error(ArgumentError) { |e|
+ -> { @object.send(:Float, "foo") }.should.raise(ArgumentError) { |e|
e.message.should == 'invalid value for Float(): "foo"'
}
end
it "raises an ArgumentError if there are two decimal points in the String" do
- -> { @object.send(:Float, "10.0.0") }.should raise_error(ArgumentError)
+ -> { @object.send(:Float, "10.0.0") }.should.raise(ArgumentError)
end
it "raises an ArgumentError for a String of numbers followed by word characters" do
- -> { @object.send(:Float, "10D") }.should raise_error(ArgumentError)
+ -> { @object.send(:Float, "10D") }.should.raise(ArgumentError)
end
it "raises an ArgumentError for a String of word characters followed by numbers" do
- -> { @object.send(:Float, "D10") }.should raise_error(ArgumentError)
+ -> { @object.send(:Float, "D10") }.should.raise(ArgumentError)
end
it "is strict about the string form even across newlines" do
- -> { @object.send(:Float, "not a number\n10") }.should raise_error(ArgumentError)
- -> { @object.send(:Float, "10\nnot a number") }.should raise_error(ArgumentError)
+ -> { @object.send(:Float, "not a number\n10") }.should.raise(ArgumentError)
+ -> { @object.send(:Float, "10\nnot a number") }.should.raise(ArgumentError)
end
it "converts String subclasses to floats without calling #to_f" do
@@ -96,17 +96,17 @@ describe :kernel_float, shared: true do
end
it "raises an ArgumentError if a + or - is embedded in a String" do
- -> { @object.send(:Float, "1+1") }.should raise_error(ArgumentError)
- -> { @object.send(:Float, "1-1") }.should raise_error(ArgumentError)
+ -> { @object.send(:Float, "1+1") }.should.raise(ArgumentError)
+ -> { @object.send(:Float, "1-1") }.should.raise(ArgumentError)
end
it "raises an ArgumentError if a String has a trailing + or -" do
- -> { @object.send(:Float, "11+") }.should raise_error(ArgumentError)
- -> { @object.send(:Float, "11-") }.should raise_error(ArgumentError)
+ -> { @object.send(:Float, "11+") }.should.raise(ArgumentError)
+ -> { @object.send(:Float, "11-") }.should.raise(ArgumentError)
end
it "raises an ArgumentError for a String with a leading _" do
- -> { @object.send(:Float, "_1") }.should raise_error(ArgumentError)
+ -> { @object.send(:Float, "_1") }.should.raise(ArgumentError)
end
it "returns a value for a String with an embedded _" do
@@ -114,31 +114,31 @@ describe :kernel_float, shared: true do
end
it "raises an ArgumentError for a String with a trailing _" do
- -> { @object.send(:Float, "10_") }.should raise_error(ArgumentError)
+ -> { @object.send(:Float, "10_") }.should.raise(ArgumentError)
end
it "raises an ArgumentError for a String of \\0" do
- -> { @object.send(:Float, "\0") }.should raise_error(ArgumentError)
+ -> { @object.send(:Float, "\0") }.should.raise(ArgumentError)
end
it "raises an ArgumentError for a String with a leading \\0" do
- -> { @object.send(:Float, "\01") }.should raise_error(ArgumentError)
+ -> { @object.send(:Float, "\01") }.should.raise(ArgumentError)
end
it "raises an ArgumentError for a String with an embedded \\0" do
- -> { @object.send(:Float, "1\01") }.should raise_error(ArgumentError)
+ -> { @object.send(:Float, "1\01") }.should.raise(ArgumentError)
end
it "raises an ArgumentError for a String with a trailing \\0" do
- -> { @object.send(:Float, "1\0") }.should raise_error(ArgumentError)
+ -> { @object.send(:Float, "1\0") }.should.raise(ArgumentError)
end
it "raises an ArgumentError for a String that is just an empty space" do
- -> { @object.send(:Float, " ") }.should raise_error(ArgumentError)
+ -> { @object.send(:Float, " ") }.should.raise(ArgumentError)
end
it "raises an ArgumentError for a String that with an embedded space" do
- -> { @object.send(:Float, "1 2") }.should raise_error(ArgumentError)
+ -> { @object.send(:Float, "1 2") }.should.raise(ArgumentError)
end
it "returns a value for a String with a leading space" do
@@ -159,10 +159,11 @@ describe :kernel_float, shared: true do
ruby_version_is ""..."3.4" do
it "raises ArgumentError if a fractional part is missing" do
- -> { @object.send(:Float, "1.") }.should raise_error(ArgumentError)
- -> { @object.send(:Float, "+1.") }.should raise_error(ArgumentError)
- -> { @object.send(:Float, "-1.") }.should raise_error(ArgumentError)
- -> { @object.send(:Float, "1.e+0") }.should raise_error(ArgumentError)
+ -> { @object.send(:Float, "1.") }.should.raise(ArgumentError)
+ -> { @object.send(:Float, "+1.") }.should.raise(ArgumentError)
+ -> { @object.send(:Float, "-1.") }.should.raise(ArgumentError)
+ -> { @object.send(:Float, "1.e+0") }.should.raise(ArgumentError)
+ -> { @object.send(:Float, "1.e-2") }.should.raise(ArgumentError)
end
end
@@ -172,16 +173,17 @@ describe :kernel_float, shared: true do
@object.send(:Float, "+1.").should == 1.0
@object.send(:Float, "-1.").should == -1.0
@object.send(:Float, "1.e+0").should == 1.0
+ @object.send(:Float, "1.e-2").should be_close(0.01, TOLERANCE)
end
end
%w(e E).each do |e|
it "raises an ArgumentError if #{e} is the trailing character" do
- -> { @object.send(:Float, "2#{e}") }.should raise_error(ArgumentError)
+ -> { @object.send(:Float, "2#{e}") }.should.raise(ArgumentError)
end
it "raises an ArgumentError if #{e} is the leading character" do
- -> { @object.send(:Float, "#{e}2") }.should raise_error(ArgumentError)
+ -> { @object.send(:Float, "#{e}2") }.should.raise(ArgumentError)
end
it "returns Infinity for '2#{e}1000'" do
@@ -199,18 +201,18 @@ describe :kernel_float, shared: true do
end
it "raises an exception if a space is embedded on either side of the '#{e}'" do
- -> { @object.send(:Float, "2 0#{e}100") }.should raise_error(ArgumentError)
- -> { @object.send(:Float, "20#{e}1 00") }.should raise_error(ArgumentError)
+ -> { @object.send(:Float, "2 0#{e}100") }.should.raise(ArgumentError)
+ -> { @object.send(:Float, "20#{e}1 00") }.should.raise(ArgumentError)
end
it "raises an exception if there's a leading _ on either side of the '#{e}'" do
- -> { @object.send(:Float, "_20#{e}100") }.should raise_error(ArgumentError)
- -> { @object.send(:Float, "20#{e}_100") }.should raise_error(ArgumentError)
+ -> { @object.send(:Float, "_20#{e}100") }.should.raise(ArgumentError)
+ -> { @object.send(:Float, "20#{e}_100") }.should.raise(ArgumentError)
end
it "raises an exception if there's a trailing _ on either side of the '#{e}'" do
- -> { @object.send(:Float, "20_#{e}100") }.should raise_error(ArgumentError)
- -> { @object.send(:Float, "20#{e}100_") }.should raise_error(ArgumentError)
+ -> { @object.send(:Float, "20_#{e}100") }.should.raise(ArgumentError)
+ -> { @object.send(:Float, "20#{e}100_") }.should.raise(ArgumentError)
end
it "allows decimal points on the left side of the '#{e}'" do
@@ -218,7 +220,7 @@ describe :kernel_float, shared: true do
end
it "raises an ArgumentError if there's a decimal point on the right side of the '#{e}'" do
- -> { @object.send(:Float, "20#{e}2.0") }.should raise_error(ArgumentError)
+ -> { @object.send(:Float, "20#{e}2.0") }.should.raise(ArgumentError)
end
end
@@ -229,14 +231,18 @@ describe :kernel_float, shared: true do
@object.send(:Float, "0x0f").should == 15.0
end
+ it "interprets negative hex value" do
+ @object.send(:Float, "-0x10").should == -16.0
+ end
+
it "accepts embedded _ if the number does not contain a-f" do
@object.send(:Float, "0x1_0").should == 16.0
end
ruby_version_is ""..."3.4.3" do
it "does not accept embedded _ if the number contains a-f" do
- -> { @object.send(:Float, "0x1_0a") }.should raise_error(ArgumentError)
- @object.send(:Float, "0x1_0a", exception: false).should be_nil
+ -> { @object.send(:Float, "0x1_0a") }.should.raise(ArgumentError)
+ @object.send(:Float, "0x1_0a", exception: false).should == nil
end
end
@@ -247,12 +253,16 @@ describe :kernel_float, shared: true do
end
it "does not accept _ before, after or inside the 0x prefix" do
- -> { @object.send(:Float, "_0x10") }.should raise_error(ArgumentError)
- -> { @object.send(:Float, "0_x10") }.should raise_error(ArgumentError)
- -> { @object.send(:Float, "0x_10") }.should raise_error(ArgumentError)
- @object.send(:Float, "_0x10", exception: false).should be_nil
- @object.send(:Float, "0_x10", exception: false).should be_nil
- @object.send(:Float, "0x_10", exception: false).should be_nil
+ -> { @object.send(:Float, "_0x10") }.should.raise(ArgumentError)
+ -> { @object.send(:Float, "0_x10") }.should.raise(ArgumentError)
+ -> { @object.send(:Float, "0x_10") }.should.raise(ArgumentError)
+ @object.send(:Float, "_0x10", exception: false).should == nil
+ @object.send(:Float, "0_x10", exception: false).should == nil
+ @object.send(:Float, "0x_10", exception: false).should == nil
+ end
+
+ it "parses negative hexadecimal string as negative float" do
+ @object.send(:Float, "-0x7b").should == -123.0
end
ruby_version_is "3.4" do
@@ -272,11 +282,11 @@ describe :kernel_float, shared: true do
end
it "raises an ArgumentError if #{p} is the trailing character" do
- -> { @object.send(:Float, "0x1#{p}") }.should raise_error(ArgumentError)
+ -> { @object.send(:Float, "0x1#{p}") }.should.raise(ArgumentError)
end
it "raises an ArgumentError if #{p} is the leading character" do
- -> { @object.send(:Float, "0x#{p}1") }.should raise_error(ArgumentError)
+ -> { @object.send(:Float, "0x#{p}1") }.should.raise(ArgumentError)
end
it "returns Infinity for '0x1#{p}10000'" do
@@ -294,18 +304,18 @@ describe :kernel_float, shared: true do
end
it "raises an exception if a space is embedded on either side of the '#{p}'" do
- -> { @object.send(:Float, "0x1 0#{p}10") }.should raise_error(ArgumentError)
- -> { @object.send(:Float, "0x10#{p}1 0") }.should raise_error(ArgumentError)
+ -> { @object.send(:Float, "0x1 0#{p}10") }.should.raise(ArgumentError)
+ -> { @object.send(:Float, "0x10#{p}1 0") }.should.raise(ArgumentError)
end
it "raises an exception if there's a leading _ on either side of the '#{p}'" do
- -> { @object.send(:Float, "0x_10#{p}10") }.should raise_error(ArgumentError)
- -> { @object.send(:Float, "0x10#{p}_10") }.should raise_error(ArgumentError)
+ -> { @object.send(:Float, "0x_10#{p}10") }.should.raise(ArgumentError)
+ -> { @object.send(:Float, "0x10#{p}_10") }.should.raise(ArgumentError)
end
it "raises an exception if there's a trailing _ on either side of the '#{p}'" do
- -> { @object.send(:Float, "0x10_#{p}10") }.should raise_error(ArgumentError)
- -> { @object.send(:Float, "0x10#{p}10_") }.should raise_error(ArgumentError)
+ -> { @object.send(:Float, "0x10_#{p}10") }.should.raise(ArgumentError)
+ -> { @object.send(:Float, "0x10#{p}10_") }.should.raise(ArgumentError)
end
it "allows hexadecimal points on the left side of the '#{p}'" do
@@ -313,7 +323,7 @@ describe :kernel_float, shared: true do
end
it "raises an ArgumentError if there's a decimal point on the right side of the '#{p}'" do
- -> { @object.send(:Float, "0x1#{p}1.0") }.should raise_error(ArgumentError)
+ -> { @object.send(:Float, "0x1#{p}1.0") }.should.raise(ArgumentError)
end
end
end
@@ -334,34 +344,34 @@ describe :kernel_float, shared: true do
nan = nan_value
(nan_to_f = mock('NaN')).should_receive(:to_f).once.and_return(nan)
nan2 = @object.send(:Float, nan_to_f)
- nan2.nan?.should be_true
- nan2.should equal(nan)
+ nan2.nan?.should == true
+ nan2.should.equal?(nan)
end
it "returns the identical Infinity if #to_f is called and it returns Infinity" do
infinity = infinity_value
(infinity_to_f = mock('Infinity')).should_receive(:to_f).once.and_return(infinity)
infinity2 = @object.send(:Float, infinity_to_f)
- infinity2.should equal(infinity)
+ infinity2.should.equal?(infinity)
end
it "raises a TypeError if #to_f is not provided" do
- -> { @object.send(:Float, mock('x')) }.should raise_error(TypeError)
+ -> { @object.send(:Float, mock('x')) }.should.raise(TypeError)
end
it "raises a TypeError if #to_f returns a String" do
(obj = mock('ha!')).should_receive(:to_f).once.and_return('ha!')
- -> { @object.send(:Float, obj) }.should raise_error(TypeError)
+ -> { @object.send(:Float, obj) }.should.raise(TypeError)
end
it "raises a TypeError if #to_f returns an Integer" do
(obj = mock('123')).should_receive(:to_f).once.and_return(123)
- -> { @object.send(:Float, obj) }.should raise_error(TypeError)
+ -> { @object.send(:Float, obj) }.should.raise(TypeError)
end
it "raises a RangeError when passed a Complex argument" do
c = Complex(2, 3)
- -> { @object.send(:Float, c) }.should raise_error(RangeError)
+ -> { @object.send(:Float, c) }.should.raise(RangeError)
end
describe "when passed exception: false" do
@@ -398,6 +408,6 @@ end
describe "Kernel#Float" do
it "is a private method" do
- Kernel.should have_private_instance_method(:Float)
+ Kernel.private_instance_methods(false).should.include?(:Float)
end
end
diff --git a/spec/ruby/core/kernel/Hash_spec.rb b/spec/ruby/core/kernel/Hash_spec.rb
index cbe098a8ac..ee16f56a90 100644
--- a/spec/ruby/core/kernel/Hash_spec.rb
+++ b/spec/ruby/core/kernel/Hash_spec.rb
@@ -13,7 +13,7 @@ end
describe "Kernel" do
it "has private instance method Hash()" do
- Kernel.should have_private_instance_method(:Hash)
+ Kernel.private_instance_methods(false).should.include?(:Hash)
end
end
@@ -43,14 +43,14 @@ describe :kernel_Hash, shared: true do
end
it "raises a TypeError if it doesn't respond to #to_hash" do
- -> { @object.send(@method, mock("")) }.should raise_error(TypeError)
+ -> { @object.send(@method, mock("")) }.should.raise(TypeError)
end
it "raises a TypeError if #to_hash does not return an Hash" do
obj = mock("Hash() string")
obj.should_receive(:to_hash).and_return("string")
- -> { @object.send(@method, obj) }.should raise_error(TypeError)
+ -> { @object.send(@method, obj) }.should.raise(TypeError)
end
end
diff --git a/spec/ruby/core/kernel/Integer_spec.rb b/spec/ruby/core/kernel/Integer_spec.rb
index 74dd3e0dd2..978fd8ef08 100644
--- a/spec/ruby/core/kernel/Integer_spec.rb
+++ b/spec/ruby/core/kernel/Integer_spec.rb
@@ -14,7 +14,9 @@ describe :kernel_integer, shared: true do
obj = mock("object")
obj.should_receive(:to_int).and_return("1")
obj.should_receive(:to_i).and_return(nil)
- -> { Integer(obj) }.should raise_error(TypeError)
+ -> {
+ Integer(obj)
+ }.should raise_consistent_error(TypeError, "can't convert MockObject into Integer (MockObject#to_i gives nil)")
end
it "return a result of to_i when to_int does not return an Integer" do
@@ -24,13 +26,36 @@ describe :kernel_integer, shared: true do
Integer(obj).should == 42
end
+ it "returns a result of to_str" do
+ obj = mock("obj")
+ obj.should_receive(:to_str).and_return("1")
+
+ Integer(obj).should == 1
+ end
+
+ it "returns a result of to_int when both to_int and to_str are defined" do
+ obj = mock("obj")
+ obj.should_receive(:to_int).and_return(1)
+ obj.should_not_receive(:to_str)
+
+ Integer(obj).should == 1
+ end
+
+ it "returns a result of to_str when both to_str and to_i are defined" do
+ obj = mock("obj")
+ obj.should_receive(:to_str).and_return("1")
+ obj.should_not_receive(:to_i)
+
+ Integer(obj).should == 1
+ end
+
it "raises a TypeError when passed nil" do
- -> { Integer(nil) }.should raise_error(TypeError)
+ -> { Integer(nil) }.should.raise(TypeError, "can't convert nil into Integer")
end
it "returns an Integer object" do
- Integer(2).should be_an_instance_of(Integer)
- Integer(9**99).should be_an_instance_of(Integer)
+ Integer(2).should.instance_of?(Integer)
+ Integer(9**99).should.instance_of?(Integer)
end
it "truncates Floats" do
@@ -67,26 +92,32 @@ describe :kernel_integer, shared: true do
it "raises a TypeError if to_i returns a value that is not an Integer" do
obj = mock("object")
obj.should_receive(:to_i).and_return("1")
- -> { Integer(obj) }.should raise_error(TypeError)
+ -> {
+ Integer(obj)
+ }.should raise_consistent_error(TypeError, "can't convert MockObject into Integer (MockObject#to_i gives String)")
end
it "raises a TypeError if no to_int or to_i methods exist" do
obj = mock("object")
- -> { Integer(obj) }.should raise_error(TypeError)
+ -> {
+ Integer(obj)
+ }.should.raise(TypeError, "can't convert MockObject into Integer")
end
it "raises a TypeError if to_int returns nil and no to_i exists" do
obj = mock("object")
obj.should_receive(:to_i).and_return(nil)
- -> { Integer(obj) }.should raise_error(TypeError)
+ -> {
+ Integer(obj)
+ }.should raise_consistent_error(TypeError, "can't convert MockObject into Integer (MockObject#to_i gives nil)")
end
it "raises a FloatDomainError when passed NaN" do
- -> { Integer(nan_value) }.should raise_error(FloatDomainError)
+ -> { Integer(nan_value) }.should.raise(FloatDomainError)
end
it "raises a FloatDomainError when passed Infinity" do
- -> { Integer(infinity_value) }.should raise_error(FloatDomainError)
+ -> { Integer(infinity_value) }.should.raise(FloatDomainError)
end
describe "when passed exception: false" do
@@ -147,19 +178,19 @@ end
describe :kernel_integer_string, shared: true do
it "raises an ArgumentError if the String is a null byte" do
- -> { Integer("\0") }.should raise_error(ArgumentError)
+ -> { Integer("\0") }.should.raise(ArgumentError)
end
it "raises an ArgumentError if the String starts with a null byte" do
- -> { Integer("\01") }.should raise_error(ArgumentError)
+ -> { Integer("\01") }.should.raise(ArgumentError)
end
it "raises an ArgumentError if the String ends with a null byte" do
- -> { Integer("1\0") }.should raise_error(ArgumentError)
+ -> { Integer("1\0") }.should.raise(ArgumentError)
end
it "raises an ArgumentError if the String contains a null byte" do
- -> { Integer("1\01") }.should raise_error(ArgumentError)
+ -> { Integer("1\01") }.should.raise(ArgumentError)
end
it "ignores leading whitespace" do
@@ -175,13 +206,13 @@ describe :kernel_integer_string, shared: true do
end
it "raises an ArgumentError if there are leading _s" do
- -> { Integer("_1") }.should raise_error(ArgumentError)
- -> { Integer("___1") }.should raise_error(ArgumentError)
+ -> { Integer("_1") }.should.raise(ArgumentError)
+ -> { Integer("___1") }.should.raise(ArgumentError)
end
it "raises an ArgumentError if there are trailing _s" do
- -> { Integer("1_") }.should raise_error(ArgumentError)
- -> { Integer("1___") }.should raise_error(ArgumentError)
+ -> { Integer("1_") }.should.raise(ArgumentError)
+ -> { Integer("1___") }.should.raise(ArgumentError)
end
it "ignores an embedded _" do
@@ -189,8 +220,8 @@ describe :kernel_integer_string, shared: true do
end
it "raises an ArgumentError if there are multiple embedded _s" do
- -> { Integer("1__1") }.should raise_error(ArgumentError)
- -> { Integer("1___1") }.should raise_error(ArgumentError)
+ -> { Integer("1__1") }.should.raise(ArgumentError)
+ -> { Integer("1___1") }.should.raise(ArgumentError)
end
it "ignores a single leading +" do
@@ -198,17 +229,17 @@ describe :kernel_integer_string, shared: true do
end
it "raises an ArgumentError if there is a space between the + and number" do
- -> { Integer("+ 1") }.should raise_error(ArgumentError)
+ -> { Integer("+ 1") }.should.raise(ArgumentError)
end
it "raises an ArgumentError if there are multiple leading +s" do
- -> { Integer("++1") }.should raise_error(ArgumentError)
- -> { Integer("+++1") }.should raise_error(ArgumentError)
+ -> { Integer("++1") }.should.raise(ArgumentError)
+ -> { Integer("+++1") }.should.raise(ArgumentError)
end
it "raises an ArgumentError if there are trailing +s" do
- -> { Integer("1+") }.should raise_error(ArgumentError)
- -> { Integer("1+++") }.should raise_error(ArgumentError)
+ -> { Integer("1+") }.should.raise(ArgumentError)
+ -> { Integer("1+++") }.should.raise(ArgumentError)
end
it "makes the number negative if there's a leading -" do
@@ -216,21 +247,21 @@ describe :kernel_integer_string, shared: true do
end
it "raises an ArgumentError if there are multiple leading -s" do
- -> { Integer("--1") }.should raise_error(ArgumentError)
- -> { Integer("---1") }.should raise_error(ArgumentError)
+ -> { Integer("--1") }.should.raise(ArgumentError)
+ -> { Integer("---1") }.should.raise(ArgumentError)
end
it "raises an ArgumentError if there are trailing -s" do
- -> { Integer("1-") }.should raise_error(ArgumentError)
- -> { Integer("1---") }.should raise_error(ArgumentError)
+ -> { Integer("1-") }.should.raise(ArgumentError)
+ -> { Integer("1---") }.should.raise(ArgumentError)
end
it "raises an ArgumentError if there is a period" do
- -> { Integer("0.0") }.should raise_error(ArgumentError)
+ -> { Integer("0.0") }.should.raise(ArgumentError)
end
it "raises an ArgumentError for an empty String" do
- -> { Integer("") }.should raise_error(ArgumentError)
+ -> { Integer("") }.should.raise(ArgumentError)
end
describe "when passed exception: false" do
@@ -280,7 +311,7 @@ describe :kernel_integer_string, shared: true do
end
it "raises an ArgumentError if the number cannot be parsed as hex" do
- -> { Integer("0#{x}g") }.should raise_error(ArgumentError)
+ -> { Integer("0#{x}g") }.should.raise(ArgumentError)
end
end
@@ -301,7 +332,7 @@ describe :kernel_integer_string, shared: true do
end
it "raises an ArgumentError if the number cannot be parsed as binary" do
- -> { Integer("0#{b}2") }.should raise_error(ArgumentError)
+ -> { Integer("0#{b}2") }.should.raise(ArgumentError)
end
end
@@ -322,7 +353,7 @@ describe :kernel_integer_string, shared: true do
end
it "raises an ArgumentError if the number cannot be parsed as octal" do
- -> { Integer("0#{o}9") }.should raise_error(ArgumentError)
+ -> { Integer("0#{o}9") }.should.raise(ArgumentError)
end
end
@@ -343,26 +374,26 @@ describe :kernel_integer_string, shared: true do
end
it "raises an ArgumentError if the number cannot be parsed as decimal" do
- -> { Integer("0#{d}a") }.should raise_error(ArgumentError)
+ -> { Integer("0#{d}a") }.should.raise(ArgumentError)
end
end
end
describe :kernel_integer_string_base, shared: true do
it "raises an ArgumentError if the String is a null byte" do
- -> { Integer("\0", 2) }.should raise_error(ArgumentError)
+ -> { Integer("\0", 2) }.should.raise(ArgumentError)
end
it "raises an ArgumentError if the String starts with a null byte" do
- -> { Integer("\01", 3) }.should raise_error(ArgumentError)
+ -> { Integer("\01", 3) }.should.raise(ArgumentError)
end
it "raises an ArgumentError if the String ends with a null byte" do
- -> { Integer("1\0", 4) }.should raise_error(ArgumentError)
+ -> { Integer("1\0", 4) }.should.raise(ArgumentError)
end
it "raises an ArgumentError if the String contains a null byte" do
- -> { Integer("1\01", 5) }.should raise_error(ArgumentError)
+ -> { Integer("1\01", 5) }.should.raise(ArgumentError)
end
it "ignores leading whitespace" do
@@ -378,13 +409,13 @@ describe :kernel_integer_string_base, shared: true do
end
it "raises an ArgumentError if there are leading _s" do
- -> { Integer("_1", 7) }.should raise_error(ArgumentError)
- -> { Integer("___1", 7) }.should raise_error(ArgumentError)
+ -> { Integer("_1", 7) }.should.raise(ArgumentError)
+ -> { Integer("___1", 7) }.should.raise(ArgumentError)
end
it "raises an ArgumentError if there are trailing _s" do
- -> { Integer("1_", 12) }.should raise_error(ArgumentError)
- -> { Integer("1___", 12) }.should raise_error(ArgumentError)
+ -> { Integer("1_", 12) }.should.raise(ArgumentError)
+ -> { Integer("1___", 12) }.should.raise(ArgumentError)
end
it "ignores an embedded _" do
@@ -392,8 +423,8 @@ describe :kernel_integer_string_base, shared: true do
end
it "raises an ArgumentError if there are multiple embedded _s" do
- -> { Integer("1__1", 4) }.should raise_error(ArgumentError)
- -> { Integer("1___1", 4) }.should raise_error(ArgumentError)
+ -> { Integer("1__1", 4) }.should.raise(ArgumentError)
+ -> { Integer("1___1", 4) }.should.raise(ArgumentError)
end
it "ignores a single leading +" do
@@ -401,17 +432,17 @@ describe :kernel_integer_string_base, shared: true do
end
it "raises an ArgumentError if there is a space between the + and number" do
- -> { Integer("+ 1", 3) }.should raise_error(ArgumentError)
+ -> { Integer("+ 1", 3) }.should.raise(ArgumentError)
end
it "raises an ArgumentError if there are multiple leading +s" do
- -> { Integer("++1", 3) }.should raise_error(ArgumentError)
- -> { Integer("+++1", 3) }.should raise_error(ArgumentError)
+ -> { Integer("++1", 3) }.should.raise(ArgumentError)
+ -> { Integer("+++1", 3) }.should.raise(ArgumentError)
end
it "raises an ArgumentError if there are trailing +s" do
- -> { Integer("1+", 3) }.should raise_error(ArgumentError)
- -> { Integer("1+++", 12) }.should raise_error(ArgumentError)
+ -> { Integer("1+", 3) }.should.raise(ArgumentError)
+ -> { Integer("1+++", 12) }.should.raise(ArgumentError)
end
it "makes the number negative if there's a leading -" do
@@ -419,29 +450,29 @@ describe :kernel_integer_string_base, shared: true do
end
it "raises an ArgumentError if there are multiple leading -s" do
- -> { Integer("--1", 9) }.should raise_error(ArgumentError)
- -> { Integer("---1", 9) }.should raise_error(ArgumentError)
+ -> { Integer("--1", 9) }.should.raise(ArgumentError)
+ -> { Integer("---1", 9) }.should.raise(ArgumentError)
end
it "raises an ArgumentError if there are trailing -s" do
- -> { Integer("1-", 12) }.should raise_error(ArgumentError)
- -> { Integer("1---", 12) }.should raise_error(ArgumentError)
+ -> { Integer("1-", 12) }.should.raise(ArgumentError)
+ -> { Integer("1---", 12) }.should.raise(ArgumentError)
end
it "raises an ArgumentError if there is a period" do
- -> { Integer("0.0", 3) }.should raise_error(ArgumentError)
+ -> { Integer("0.0", 3) }.should.raise(ArgumentError)
end
it "raises an ArgumentError for an empty String" do
- -> { Integer("", 12) }.should raise_error(ArgumentError)
+ -> { Integer("", 12) }.should.raise(ArgumentError)
end
it "raises an ArgumentError for a base of 1" do
- -> { Integer("1", 1) }.should raise_error(ArgumentError)
+ -> { Integer("1", 1) }.should.raise(ArgumentError)
end
it "raises an ArgumentError for a base of 37" do
- -> { Integer("1", 37) }.should raise_error(ArgumentError)
+ -> { Integer("1", 37) }.should.raise(ArgumentError)
end
it "accepts wholly lowercase alphabetic strings for bases > 10" do
@@ -469,8 +500,8 @@ describe :kernel_integer_string_base, shared: true do
end
it "raises an ArgumentError for letters invalid in the given base" do
- -> { Integer('z',19) }.should raise_error(ArgumentError)
- -> { Integer('c00o',2) }.should raise_error(ArgumentError)
+ -> { Integer('z',19) }.should.raise(ArgumentError)
+ -> { Integer('c00o',2) }.should.raise(ArgumentError)
end
%w(x X).each do |x|
@@ -491,12 +522,12 @@ describe :kernel_integer_string_base, shared: true do
2.upto(15) do |base|
it "raises an ArgumentError if the number begins with 0#{x} and the base is #{base}" do
- -> { Integer("0#{x}1", base) }.should raise_error(ArgumentError)
+ -> { Integer("0#{x}1", base) }.should.raise(ArgumentError)
end
end
it "raises an ArgumentError if the number cannot be parsed as hex and the base is 16" do
- -> { Integer("0#{x}g", 16) }.should raise_error(ArgumentError)
+ -> { Integer("0#{x}g", 16) }.should.raise(ArgumentError)
end
end
@@ -517,7 +548,7 @@ describe :kernel_integer_string_base, shared: true do
end
it "raises an ArgumentError if the number cannot be parsed as binary and the base is 2" do
- -> { Integer("0#{b}2", 2) }.should raise_error(ArgumentError)
+ -> { Integer("0#{b}2", 2) }.should.raise(ArgumentError)
end
end
@@ -538,12 +569,12 @@ describe :kernel_integer_string_base, shared: true do
end
it "raises an ArgumentError if the number cannot be parsed as octal and the base is 8" do
- -> { Integer("0#{o}9", 8) }.should raise_error(ArgumentError)
+ -> { Integer("0#{o}9", 8) }.should.raise(ArgumentError)
end
2.upto(7) do |base|
it "raises an ArgumentError if the number begins with 0#{o} and the base is #{base}" do
- -> { Integer("0#{o}1", base) }.should raise_error(ArgumentError)
+ -> { Integer("0#{o}1", base) }.should.raise(ArgumentError)
end
end
end
@@ -565,18 +596,18 @@ describe :kernel_integer_string_base, shared: true do
end
it "raises an ArgumentError if the number cannot be parsed as decimal and the base is 10" do
- -> { Integer("0#{d}a", 10) }.should raise_error(ArgumentError)
+ -> { Integer("0#{d}a", 10) }.should.raise(ArgumentError)
end
2.upto(9) do |base|
it "raises an ArgumentError if the number begins with 0#{d} and the base is #{base}" do
- -> { Integer("0#{d}1", base) }.should raise_error(ArgumentError)
+ -> { Integer("0#{d}1", base) }.should.raise(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)
+ -> { Integer(98, 15) }.should.raise(ArgumentError, "base specified for non string value")
end
it "tries to convert the base to an integer using to_int" do
@@ -586,19 +617,10 @@ describe :kernel_integer_string_base, shared: true do
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")
- end
+ it "raises a TypeError if it is not an integer and does not respond to #to_i" do
+ -> {
+ Integer("777", "8")
+ }.should.raise(TypeError, "no implicit conversion of String into Integer")
end
describe "when passed exception: false" do
@@ -621,176 +643,176 @@ end
describe :kernel_Integer, shared: true do
it "raises an ArgumentError when the String contains digits out of range of radix 2" do
str = "23456789abcdefghijklmnopqrstuvwxyz"
- -> { @object.send(@method, str, 2) }.should raise_error(ArgumentError)
+ -> { @object.send(@method, str, 2) }.should.raise(ArgumentError)
end
it "raises an ArgumentError when the String contains digits out of range of radix 3" do
str = "3456789abcdefghijklmnopqrstuvwxyz"
- -> { @object.send(@method, str, 3) }.should raise_error(ArgumentError)
+ -> { @object.send(@method, str, 3) }.should.raise(ArgumentError)
end
it "raises an ArgumentError when the String contains digits out of range of radix 4" do
str = "456789abcdefghijklmnopqrstuvwxyz"
- -> { @object.send(@method, str, 4) }.should raise_error(ArgumentError)
+ -> { @object.send(@method, str, 4) }.should.raise(ArgumentError)
end
it "raises an ArgumentError when the String contains digits out of range of radix 5" do
str = "56789abcdefghijklmnopqrstuvwxyz"
- -> { @object.send(@method, str, 5) }.should raise_error(ArgumentError)
+ -> { @object.send(@method, str, 5) }.should.raise(ArgumentError)
end
it "raises an ArgumentError when the String contains digits out of range of radix 6" do
str = "6789abcdefghijklmnopqrstuvwxyz"
- -> { @object.send(@method, str, 6) }.should raise_error(ArgumentError)
+ -> { @object.send(@method, str, 6) }.should.raise(ArgumentError)
end
it "raises an ArgumentError when the String contains digits out of range of radix 7" do
str = "789abcdefghijklmnopqrstuvwxyz"
- -> { @object.send(@method, str, 7) }.should raise_error(ArgumentError)
+ -> { @object.send(@method, str, 7) }.should.raise(ArgumentError)
end
it "raises an ArgumentError when the String contains digits out of range of radix 8" do
str = "89abcdefghijklmnopqrstuvwxyz"
- -> { @object.send(@method, str, 8) }.should raise_error(ArgumentError)
+ -> { @object.send(@method, str, 8) }.should.raise(ArgumentError)
end
it "raises an ArgumentError when the String contains digits out of range of radix 9" do
str = "9abcdefghijklmnopqrstuvwxyz"
- -> { @object.send(@method, str, 9) }.should raise_error(ArgumentError)
+ -> { @object.send(@method, str, 9) }.should.raise(ArgumentError)
end
it "raises an ArgumentError when the String contains digits out of range of radix 10" do
str = "abcdefghijklmnopqrstuvwxyz"
- -> { @object.send(@method, str, 10) }.should raise_error(ArgumentError)
+ -> { @object.send(@method, str, 10) }.should.raise(ArgumentError)
end
it "raises an ArgumentError when the String contains digits out of range of radix 11" do
str = "bcdefghijklmnopqrstuvwxyz"
- -> { @object.send(@method, str, 11) }.should raise_error(ArgumentError)
+ -> { @object.send(@method, str, 11) }.should.raise(ArgumentError)
end
it "raises an ArgumentError when the String contains digits out of range of radix 12" do
str = "cdefghijklmnopqrstuvwxyz"
- -> { @object.send(@method, str, 12) }.should raise_error(ArgumentError)
+ -> { @object.send(@method, str, 12) }.should.raise(ArgumentError)
end
it "raises an ArgumentError when the String contains digits out of range of radix 13" do
str = "defghijklmnopqrstuvwxyz"
- -> { @object.send(@method, str, 13) }.should raise_error(ArgumentError)
+ -> { @object.send(@method, str, 13) }.should.raise(ArgumentError)
end
it "raises an ArgumentError when the String contains digits out of range of radix 14" do
str = "efghijklmnopqrstuvwxyz"
- -> { @object.send(@method, str, 14) }.should raise_error(ArgumentError)
+ -> { @object.send(@method, str, 14) }.should.raise(ArgumentError)
end
it "raises an ArgumentError when the String contains digits out of range of radix 15" do
str = "fghijklmnopqrstuvwxyz"
- -> { @object.send(@method, str, 15) }.should raise_error(ArgumentError)
+ -> { @object.send(@method, str, 15) }.should.raise(ArgumentError)
end
it "raises an ArgumentError when the String contains digits out of range of radix 16" do
str = "ghijklmnopqrstuvwxyz"
- -> { @object.send(@method, str, 16) }.should raise_error(ArgumentError)
+ -> { @object.send(@method, str, 16) }.should.raise(ArgumentError)
end
it "raises an ArgumentError when the String contains digits out of range of radix 17" do
str = "hijklmnopqrstuvwxyz"
- -> { @object.send(@method, str, 17) }.should raise_error(ArgumentError)
+ -> { @object.send(@method, str, 17) }.should.raise(ArgumentError)
end
it "raises an ArgumentError when the String contains digits out of range of radix 18" do
str = "ijklmnopqrstuvwxyz"
- -> { @object.send(@method, str, 18) }.should raise_error(ArgumentError)
+ -> { @object.send(@method, str, 18) }.should.raise(ArgumentError)
end
it "raises an ArgumentError when the String contains digits out of range of radix 19" do
str = "jklmnopqrstuvwxyz"
- -> { @object.send(@method, str, 19) }.should raise_error(ArgumentError)
+ -> { @object.send(@method, str, 19) }.should.raise(ArgumentError)
end
it "raises an ArgumentError when the String contains digits out of range of radix 20" do
str = "klmnopqrstuvwxyz"
- -> { @object.send(@method, str, 20) }.should raise_error(ArgumentError)
+ -> { @object.send(@method, str, 20) }.should.raise(ArgumentError)
end
it "raises an ArgumentError when the String contains digits out of range of radix 21" do
str = "lmnopqrstuvwxyz"
- -> { @object.send(@method, str, 21) }.should raise_error(ArgumentError)
+ -> { @object.send(@method, str, 21) }.should.raise(ArgumentError)
end
it "raises an ArgumentError when the String contains digits out of range of radix 22" do
str = "mnopqrstuvwxyz"
- -> { @object.send(@method, str, 22) }.should raise_error(ArgumentError)
+ -> { @object.send(@method, str, 22) }.should.raise(ArgumentError)
end
it "raises an ArgumentError when the String contains digits out of range of radix 23" do
str = "nopqrstuvwxyz"
- -> { @object.send(@method, str, 23) }.should raise_error(ArgumentError)
+ -> { @object.send(@method, str, 23) }.should.raise(ArgumentError)
end
it "raises an ArgumentError when the String contains digits out of range of radix 24" do
str = "opqrstuvwxyz"
- -> { @object.send(@method, str, 24) }.should raise_error(ArgumentError)
+ -> { @object.send(@method, str, 24) }.should.raise(ArgumentError)
end
it "raises an ArgumentError when the String contains digits out of range of radix 25" do
str = "pqrstuvwxyz"
- -> { @object.send(@method, str, 25) }.should raise_error(ArgumentError)
+ -> { @object.send(@method, str, 25) }.should.raise(ArgumentError)
end
it "raises an ArgumentError when the String contains digits out of range of radix 26" do
str = "qrstuvwxyz"
- -> { @object.send(@method, str, 26) }.should raise_error(ArgumentError)
+ -> { @object.send(@method, str, 26) }.should.raise(ArgumentError)
end
it "raises an ArgumentError when the String contains digits out of range of radix 27" do
str = "rstuvwxyz"
- -> { @object.send(@method, str, 27) }.should raise_error(ArgumentError)
+ -> { @object.send(@method, str, 27) }.should.raise(ArgumentError)
end
it "raises an ArgumentError when the String contains digits out of range of radix 28" do
str = "stuvwxyz"
- -> { @object.send(@method, str, 28) }.should raise_error(ArgumentError)
+ -> { @object.send(@method, str, 28) }.should.raise(ArgumentError)
end
it "raises an ArgumentError when the String contains digits out of range of radix 29" do
str = "tuvwxyz"
- -> { @object.send(@method, str, 29) }.should raise_error(ArgumentError)
+ -> { @object.send(@method, str, 29) }.should.raise(ArgumentError)
end
it "raises an ArgumentError when the String contains digits out of range of radix 30" do
str = "uvwxyz"
- -> { @object.send(@method, str, 30) }.should raise_error(ArgumentError)
+ -> { @object.send(@method, str, 30) }.should.raise(ArgumentError)
end
it "raises an ArgumentError when the String contains digits out of range of radix 31" do
str = "vwxyz"
- -> { @object.send(@method, str, 31) }.should raise_error(ArgumentError)
+ -> { @object.send(@method, str, 31) }.should.raise(ArgumentError)
end
it "raises an ArgumentError when the String contains digits out of range of radix 32" do
str = "wxyz"
- -> { @object.send(@method, str, 32) }.should raise_error(ArgumentError)
+ -> { @object.send(@method, str, 32) }.should.raise(ArgumentError)
end
it "raises an ArgumentError when the String contains digits out of range of radix 33" do
str = "xyz"
- -> { @object.send(@method, str, 33) }.should raise_error(ArgumentError)
+ -> { @object.send(@method, str, 33) }.should.raise(ArgumentError)
end
it "raises an ArgumentError when the String contains digits out of range of radix 34" do
str = "yz"
- -> { @object.send(@method, str, 34) }.should raise_error(ArgumentError)
+ -> { @object.send(@method, str, 34) }.should.raise(ArgumentError)
end
it "raises an ArgumentError when the String contains digits out of range of radix 35" do
str = "z"
- -> { @object.send(@method, str, 35) }.should raise_error(ArgumentError)
+ -> { @object.send(@method, str, 35) }.should.raise(ArgumentError)
end
it "raises an ArgumentError when the String contains digits out of range of radix 36" do
- -> { @object.send(@method, "{", 36) }.should raise_error(ArgumentError)
+ -> { @object.send(@method, "{", 36) }.should.raise(ArgumentError)
end
end
@@ -818,6 +840,6 @@ describe "Kernel#Integer" do
it_behaves_like :kernel_integer_string_base, :Integer
it "is a private method" do
- Kernel.should have_private_instance_method(:Integer)
+ Kernel.private_instance_methods(false).should.include?(:Integer)
end
end
diff --git a/spec/ruby/core/kernel/Rational_spec.rb b/spec/ruby/core/kernel/Rational_spec.rb
index 841c8e8c64..b13ab4cf55 100644
--- a/spec/ruby/core/kernel/Rational_spec.rb
+++ b/spec/ruby/core/kernel/Rational_spec.rb
@@ -6,9 +6,9 @@ describe "Kernel.Rational" do
# Guard against the Mathn library
guard -> { !defined?(Math.rsqrt) } do
it "returns a new Rational number with 1 as the denominator" do
- Rational(1).should eql(Rational(1, 1))
- Rational(-3).should eql(Rational(-3, 1))
- Rational(bignum_value).should eql(Rational(bignum_value, 1))
+ Rational(1).should.eql?(Rational(1, 1))
+ Rational(-3).should.eql?(Rational(-3, 1))
+ Rational(bignum_value).should.eql?(Rational(bignum_value, 1))
end
end
end
@@ -18,17 +18,17 @@ describe "Kernel.Rational" do
rat = Rational(1, 2)
rat.numerator.should == 1
rat.denominator.should == 2
- rat.should be_an_instance_of(Rational)
+ rat.should.instance_of?(Rational)
rat = Rational(-3, -5)
rat.numerator.should == 3
rat.denominator.should == 5
- rat.should be_an_instance_of(Rational)
+ rat.should.instance_of?(Rational)
rat = Rational(bignum_value, 3)
rat.numerator.should == bignum_value
rat.denominator.should == 3
- rat.should be_an_instance_of(Rational)
+ rat.should.instance_of?(Rational)
end
it "reduces the Rational" do
@@ -76,34 +76,84 @@ describe "Kernel.Rational" do
end
describe "when passed a Complex" do
- it "returns a Rational from the real part if the imaginary part is 0" do
- Rational(Complex(1, 0)).should == Rational(1)
+ context "[Complex]" do
+ it "returns a Rational from the real part if the imaginary part is 0" do
+ Rational(Complex(1, 0)).should == Rational(1)
+ end
+
+ it "raises a RangeError if the imaginary part is not 0" do
+ -> { Rational(Complex(1, 2)) }.should.raise(RangeError, "can't convert 1+2i into Rational")
+ end
end
- it "raises a RangeError if the imaginary part is not 0" do
- -> { Rational(Complex(1, 2)) }.should raise_error(RangeError)
+ context "[Numeric, Complex]" do
+ it "uses the real part if the imaginary part is 0" do
+ Rational(1, Complex(2, 0)).should == Rational(1, 2)
+ end
+
+ it "divides a numerator by the Complex denominator if the imaginary part is not 0" do
+ Rational(1, Complex(2, 1)).should == Complex(2/5r, -1/5r)
+ end
+ end
+ end
+
+ context "when passed neither a Numeric nor a String" do
+ it "converts to Rational with #to_r method" do
+ obj = Object.new
+ def obj.to_r; 1/2r; end
+
+ Rational(obj).should == 1/2r
+ end
+
+ it "tries to convert to Integer with #to_int method if it does not respond to #to_r" do
+ obj = Object.new
+ def obj.to_int; 1; end
+
+ Rational(obj).should == 1r
+ end
+
+ it "raises TypeError if it neither responds to #to_r nor #to_int method" do
+ -> { Rational([]) }.should.raise(TypeError, "can't convert Array into Rational")
+ -> { Rational({}) }.should.raise(TypeError, "can't convert Hash into Rational")
+ -> { Rational(nil) }.should.raise(TypeError, "can't convert nil into Rational")
+ end
+
+ it "swallows exception raised in #to_int method" do
+ object = Object.new
+ def object.to_int() raise NoMethodError; end
+
+ -> { Rational(object) }.should.raise(TypeError)
+ -> { Rational(object, 1) }.should.raise(TypeError)
+ -> { Rational(1, object) }.should.raise(TypeError)
+ end
+
+ it "raises TypeError if #to_r does not return Rational" do
+ obj = Object.new
+ def obj.to_r; []; end
+
+ -> { Rational(obj) }.should raise_consistent_error(TypeError, "can't convert Object into Rational (Object#to_r gives Array)")
end
end
it "raises a ZeroDivisionError if the second argument is 0" do
- -> { Rational(1, 0) }.should raise_error(ZeroDivisionError, "divided by 0")
- -> { Rational(1, 0.0) }.should raise_error(ZeroDivisionError, "divided by 0")
+ -> { Rational(1, 0) }.should.raise(ZeroDivisionError, "divided by 0")
+ -> { Rational(1, 0.0) }.should.raise(ZeroDivisionError, "divided by 0")
end
it "raises a TypeError if the first argument is nil" do
- -> { Rational(nil) }.should raise_error(TypeError)
+ -> { Rational(nil) }.should.raise(TypeError, "can't convert nil into Rational")
end
it "raises a TypeError if the second argument is nil" do
- -> { Rational(1, nil) }.should raise_error(TypeError)
+ -> { Rational(1, nil) }.should.raise(TypeError, "can't convert nil into Rational")
end
it "raises a TypeError if the first argument is a Symbol" do
- -> { Rational(:sym) }.should raise_error(TypeError)
+ -> { Rational(:sym) }.should.raise(TypeError)
end
it "raises a TypeError if the second argument is a Symbol" do
- -> { Rational(1, :sym) }.should raise_error(TypeError)
+ -> { Rational(1, :sym) }.should.raise(TypeError)
end
describe "when passed exception: false" do
@@ -112,6 +162,18 @@ describe "Kernel.Rational" do
Rational(:sym, exception: false).should == nil
Rational("abc", exception: false).should == nil
end
+
+ it "swallows an exception raised in #to_r" do
+ obj = Object.new
+ def obj.to_r; raise; end
+ Rational(obj, exception: false).should == nil
+ end
+
+ it "swallows an exception raised in #to_int" do
+ obj = Object.new
+ def obj.to_int; raise; end
+ Rational(obj, exception: false).should == nil
+ end
end
describe "and [non-Numeric, Numeric]" do
@@ -119,6 +181,18 @@ describe "Kernel.Rational" do
Rational(:sym, 1, exception: false).should == nil
Rational("abc", 1, exception: false).should == nil
end
+
+ it "swallows an exception raised in #to_r" do
+ obj = Object.new
+ def obj.to_r; raise; end
+ Rational(obj, 1, exception: false).should == nil
+ end
+
+ it "swallows an exception raised in #to_int" do
+ obj = Object.new
+ def obj.to_int; raise; end
+ Rational(obj, 1, exception: false).should == nil
+ end
end
describe "and [anything, non-Numeric]" do
@@ -126,6 +200,18 @@ describe "Kernel.Rational" do
Rational(:sym, :sym, exception: false).should == nil
Rational("abc", :sym, exception: false).should == nil
end
+
+ it "swallows an exception raised in #to_r" do
+ obj = Object.new
+ def obj.to_r; raise; end
+ Rational(obj, obj, exception: false).should == nil
+ end
+
+ it "swallows an exception raised in #to_int" do
+ obj = Object.new
+ def obj.to_int; raise; end
+ Rational(obj, obj, exception: false).should == nil
+ end
end
describe "and non-Numeric String arguments" do
diff --git a/spec/ruby/core/kernel/String_spec.rb b/spec/ruby/core/kernel/String_spec.rb
index 7caec6eda5..a9b0758ad7 100644
--- a/spec/ruby/core/kernel/String_spec.rb
+++ b/spec/ruby/core/kernel/String_spec.rb
@@ -32,7 +32,7 @@ describe :kernel_String, shared: true do
undef_method :to_s
end
- -> { @object.send(@method, obj) }.should raise_error(TypeError)
+ -> { @object.send(@method, obj) }.should.raise(TypeError)
end
# #5158
@@ -44,7 +44,7 @@ describe :kernel_String, shared: true do
end
end
- -> { @object.send(@method, obj) }.should raise_error(TypeError)
+ -> { @object.send(@method, obj) }.should.raise(TypeError)
end
it "raises a TypeError if #to_s is not defined, even though #respond_to?(:to_s) returns true" do
@@ -57,7 +57,7 @@ describe :kernel_String, shared: true do
end
end
- -> { @object.send(@method, obj) }.should raise_error(TypeError)
+ -> { @object.send(@method, obj) }.should.raise(TypeError)
end
it "calls #to_s if #respond_to?(:to_s) returns true" do
@@ -74,14 +74,14 @@ describe :kernel_String, shared: true do
it "raises a TypeError if #to_s does not return a String" do
(obj = mock('123')).should_receive(:to_s).and_return(123)
- -> { @object.send(@method, obj) }.should raise_error(TypeError)
+ -> { @object.send(@method, obj) }.should.raise(TypeError)
end
it "returns the same object if it is already a String" do
string = +"Hello"
string.should_not_receive(:to_s)
string2 = @object.send(@method, string)
- string.should equal(string2)
+ string.should.equal?(string2)
end
it "returns the same object if it is an instance of a String subclass" do
@@ -89,7 +89,7 @@ describe :kernel_String, shared: true do
string = subklass.new("Hello")
string.should_not_receive(:to_s)
string2 = @object.send(@method, string)
- string.should equal(string2)
+ string.should.equal?(string2)
end
end
@@ -101,6 +101,6 @@ describe "Kernel#String" do
it_behaves_like :kernel_String, :String, Object.new
it "is a private method" do
- Kernel.should have_private_instance_method(:String)
+ Kernel.private_instance_methods(false).should.include?(:String)
end
end
diff --git a/spec/ruby/core/kernel/abort_spec.rb b/spec/ruby/core/kernel/abort_spec.rb
index f8152718c5..b75138182d 100644
--- a/spec/ruby/core/kernel/abort_spec.rb
+++ b/spec/ruby/core/kernel/abort_spec.rb
@@ -4,7 +4,7 @@ require_relative '../../shared/process/abort'
describe "Kernel#abort" do
it "is a private method" do
- Kernel.should have_private_instance_method(:abort)
+ Kernel.private_instance_methods(false).should.include?(:abort)
end
it_behaves_like :process_abort, :abort, KernelSpecs::Method.new
diff --git a/spec/ruby/core/kernel/at_exit_spec.rb b/spec/ruby/core/kernel/at_exit_spec.rb
index ebd9a71d15..fdb0eaf34c 100644
--- a/spec/ruby/core/kernel/at_exit_spec.rb
+++ b/spec/ruby/core/kernel/at_exit_spec.rb
@@ -6,11 +6,11 @@ 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)
+ Kernel.private_instance_methods(false).should.include?(:at_exit)
end
it "raises ArgumentError if called without a block" do
- -> { at_exit }.should raise_error(ArgumentError, "called without a block")
+ -> { at_exit }.should.raise(ArgumentError, "called without a block")
end
end
diff --git a/spec/ruby/core/kernel/autoload_relative_spec.rb b/spec/ruby/core/kernel/autoload_relative_spec.rb
new file mode 100644
index 0000000000..7d03da8a40
--- /dev/null
+++ b/spec/ruby/core/kernel/autoload_relative_spec.rb
@@ -0,0 +1,114 @@
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
+
+# Specs for Kernel#autoload_relative
+
+ruby_version_is "4.1" do
+ describe "Kernel#autoload_relative" do
+ before :each do
+ @loaded_features = $".dup
+ end
+
+ after :each do
+ $".replace @loaded_features
+ # Clean up constants defined by these tests
+ [:KSAutoloadRelativeA, :KSAutoloadRelativeB, :KSAutoloadRelativeC,
+ :KSAutoloadRelativeE, :KSAutoloadRelativeF, :KSAutoloadRelativeG,
+ :KSAutoloadRelativeH, :KSAutoloadRelativeI].each do |const|
+ KernelSpecs.send(:remove_const, const) if KernelSpecs.const_defined?(const, false)
+ end
+ [:KSAutoloadRelativeD, :NestedTest].each do |const|
+ Object.send(:remove_const, const) if Object.const_defined?(const, false)
+ end
+ end
+
+ it "is a private method" do
+ Kernel.private_instance_methods(false).should.include?(:autoload_relative)
+ end
+
+ it "registers a file to load relative to the current file" do
+ KernelSpecs.autoload_relative :KSAutoloadRelativeA, "fixtures/autoload_relative_b.rb"
+ path = KernelSpecs.autoload?(:KSAutoloadRelativeA)
+ path.should_not == nil
+ path.should.end_with?("autoload_relative_b.rb")
+ File.exist?(path).should == true
+ end
+
+ it "loads the file when the constant is accessed" do
+ KernelSpecs.autoload_relative :KSAutoloadRelativeB, "fixtures/autoload_relative_b.rb"
+ KernelSpecs::KSAutoloadRelativeB.loaded.should == :ksautoload_b
+ end
+
+ it "sets the autoload constant in the constant table" do
+ KernelSpecs.autoload_relative :KSAutoloadRelativeC, "fixtures/autoload_relative_b.rb"
+ KernelSpecs.should.const_defined?(:KSAutoloadRelativeC, false)
+ end
+
+ it "can autoload in instance_eval with a file context" do
+ result = Object.new.instance_eval(<<-CODE, __FILE__, __LINE__)
+ autoload_relative :KSAutoloadRelativeD, "fixtures/autoload_relative_d.rb"
+ KSAutoloadRelativeD.loaded
+ CODE
+ result.should == :ksautoload_d
+ end
+
+ it "raises LoadError if called from eval without file context" do
+ -> {
+ eval('autoload_relative :Foo, "foo.rb"')
+ }.should.raise(LoadError, /autoload_relative called without file context/)
+ end
+
+ it "accepts both string and symbol for constant name" do
+ KernelSpecs.autoload_relative :KSAutoloadRelativeE, "fixtures/autoload_relative_b.rb"
+ KernelSpecs.autoload_relative "KSAutoloadRelativeF", "fixtures/autoload_relative_b.rb"
+
+ KernelSpecs.should.const_defined?(:KSAutoloadRelativeE, false)
+ KernelSpecs.should.const_defined?(:KSAutoloadRelativeF, false)
+ end
+
+ it "returns nil" do
+ KernelSpecs.autoload_relative(:KSAutoloadRelativeG, "fixtures/autoload_relative_b.rb").should == nil
+ end
+
+ it "resolves nested directory paths correctly" do
+ -> {
+ autoload_relative :NestedTest, "../kernel/fixtures/autoload_relative_b.rb"
+ autoload?(:NestedTest)
+ }.should_not.raise
+ end
+
+ it "resolves paths starting with ./" do
+ KernelSpecs.autoload_relative :KSAutoloadRelativeH, "./fixtures/autoload_relative_b.rb"
+ path = KernelSpecs.autoload?(:KSAutoloadRelativeH)
+ path.should_not == nil
+ path.should.end_with?("autoload_relative_b.rb")
+ end
+
+ it "ignores $LOAD_PATH and uses only relative path resolution" do
+ original_load_path = $LOAD_PATH.dup
+ $LOAD_PATH.clear
+ begin
+ KernelSpecs.autoload_relative :KSAutoloadRelativeI, "fixtures/autoload_relative_b.rb"
+ path = KernelSpecs.autoload?(:KSAutoloadRelativeI)
+ path.should_not == nil
+ # Should still resolve even with empty $LOAD_PATH
+ File.exist?(path).should == true
+ ensure
+ $LOAD_PATH.replace(original_load_path)
+ end
+ end
+
+ describe "when Object is frozen" do
+ it "raises a FrozenError before defining the constant" do
+ ruby_exe(<<-RUBY).should.include?("FrozenError")
+ Object.freeze
+ begin
+ autoload_relative :Foo, "autoload_b.rb"
+ rescue => e
+ puts e.class
+ end
+ RUBY
+ end
+ end
+ end
+end
diff --git a/spec/ruby/core/kernel/autoload_spec.rb b/spec/ruby/core/kernel/autoload_spec.rb
index 0404caec6d..46783734c4 100644
--- a/spec/ruby/core/kernel/autoload_spec.rb
+++ b/spec/ruby/core/kernel/autoload_spec.rb
@@ -7,7 +7,9 @@ require_relative 'fixtures/classes'
autoload :KSAutoloadA, "autoload_a.rb"
autoload :KSAutoloadB, fixture(__FILE__, "autoload_b.rb")
-autoload :KSAutoloadCallsRequire, "main_autoload_not_exist.rb"
+define_autoload_KSAutoloadCallsRequire = -> {
+ autoload :KSAutoloadCallsRequire, "main_autoload_not_exist.rb"
+}
def check_autoload(const)
autoload? const
@@ -23,7 +25,7 @@ describe "Kernel#autoload" do
end
it "is a private method" do
- Kernel.should have_private_instance_method(:autoload)
+ Kernel.private_instance_methods(false).should.include?(:autoload)
end
it "registers a file to load the first time the named constant is accessed" do
@@ -35,7 +37,7 @@ describe "Kernel#autoload" do
end
it "sets the autoload constant in Object's constant table" do
- Object.should have_constant(:KSAutoloadA)
+ Object.should.const_defined?(:KSAutoloadA, false)
end
it "loads the file when the constant is accessed" do
@@ -43,10 +45,11 @@ describe "Kernel#autoload" do
end
it "calls main.require(path) to load the file" do
+ define_autoload_KSAutoloadCallsRequire.call
main = TOPLEVEL_BINDING.eval("self")
main.should_receive(:require).with("main_autoload_not_exist.rb")
# The constant won't be defined since require is mocked to do nothing
- -> { KSAutoloadCallsRequire }.should raise_error(NameError)
+ -> { KSAutoloadCallsRequire }.should.raise(NameError)
end
it "can autoload in instance_eval" do
@@ -99,7 +102,7 @@ end
describe "Kernel#autoload?" do
it "is a private method" do
- Kernel.should have_private_instance_method(:autoload?)
+ Kernel.private_instance_methods(false).should.include?(:autoload?)
end
it "returns the name of the file that will be autoloaded" do
@@ -107,7 +110,7 @@ describe "Kernel#autoload?" do
end
it "returns nil if no file has been registered for a constant" do
- check_autoload(:Manualload).should be_nil
+ check_autoload(:Manualload).should == nil
end
end
@@ -134,7 +137,7 @@ describe "Kernel.autoload" do
end
it "sets the autoload constant in Object's constant table" do
- Object.should have_constant(:KSAutoloadBB)
+ Object.should.const_defined?(:KSAutoloadBB, false)
end
it "calls #to_path on non-String filenames" do
@@ -170,6 +173,6 @@ describe "Kernel.autoload?" do
end
it "returns nil if no file has been registered for a constant" do
- Kernel.autoload?(:Manualload).should be_nil
+ Kernel.autoload?(:Manualload).should == nil
end
end
diff --git a/spec/ruby/core/kernel/backtick_spec.rb b/spec/ruby/core/kernel/backtick_spec.rb
index 834d5636c1..42e0f975f5 100644
--- a/spec/ruby/core/kernel/backtick_spec.rb
+++ b/spec/ruby/core/kernel/backtick_spec.rb
@@ -11,7 +11,7 @@ describe "Kernel#`" do
end
it "is a private method" do
- Kernel.should have_private_instance_method(:`)
+ Kernel.private_instance_methods(false).should.include?(:`)
end
it "returns the standard output of the executed sub-process" do
@@ -28,11 +28,11 @@ describe "Kernel#`" do
it "produces a String in the default external encoding" do
Encoding.default_external = Encoding::SHIFT_JIS
- `echo disc`.encoding.should equal(Encoding::SHIFT_JIS)
+ `echo disc`.encoding.should.equal?(Encoding::SHIFT_JIS)
end
it "raises an Errno::ENOENT if the command is not executable" do
- -> { `nonexistent_command` }.should raise_error(Errno::ENOENT)
+ -> { `nonexistent_command` }.should.raise(Errno::ENOENT)
end
platform_is_not :windows do
@@ -43,13 +43,13 @@ describe "Kernel#`" do
it "sets $? to the exit status of the executed sub-process" do
ip = 'world'
`echo disc #{ip}`
- $?.should be_kind_of(Process::Status)
+ $?.should.is_a?(Process::Status)
$?.should_not.stopped?
$?.should.exited?
$?.exitstatus.should == 0
$?.should.success?
`echo disc #{ip}; exit 99`
- $?.should be_kind_of(Process::Status)
+ $?.should.is_a?(Process::Status)
$?.should_not.stopped?
$?.should.exited?
$?.exitstatus.should == 99
@@ -61,13 +61,13 @@ describe "Kernel#`" do
it "sets $? to the exit status of the executed sub-process" do
ip = 'world'
`echo disc #{ip}`
- $?.should be_kind_of(Process::Status)
+ $?.should.is_a?(Process::Status)
$?.should_not.stopped?
$?.should.exited?
$?.exitstatus.should == 0
$?.should.success?
`echo disc #{ip}& exit 99`
- $?.should be_kind_of(Process::Status)
+ $?.should.is_a?(Process::Status)
$?.should_not.stopped?
$?.should.exited?
$?.exitstatus.should == 99
diff --git a/spec/ruby/core/kernel/binding_spec.rb b/spec/ruby/core/kernel/binding_spec.rb
index f1c9c6ec9f..6f27b26f37 100644
--- a/spec/ruby/core/kernel/binding_spec.rb
+++ b/spec/ruby/core/kernel/binding_spec.rb
@@ -9,7 +9,7 @@ end
describe "Kernel#binding" do
it "is a private method" do
- Kernel.should have_private_instance_method(:binding)
+ Kernel.private_instance_methods(false).should.include?(:binding)
end
before :each do
@@ -35,7 +35,7 @@ describe "Kernel#binding" do
end
it "raises a NameError on undefined variable" do
- -> { eval("a_fake_variable", @b1) }.should raise_error(NameError)
+ -> { eval("a_fake_variable", @b1) }.should.raise(NameError)
end
it "uses the closure's self as self in the binding" do
diff --git a/spec/ruby/core/kernel/block_given_spec.rb b/spec/ruby/core/kernel/block_given_spec.rb
index aece4c821d..20bb90ae96 100644
--- a/spec/ruby/core/kernel/block_given_spec.rb
+++ b/spec/ruby/core/kernel/block_given_spec.rb
@@ -30,7 +30,7 @@ describe "Kernel#block_given?" do
end
it "is a private method" do
- Kernel.should have_private_instance_method(:block_given?)
+ Kernel.private_instance_methods(false).should.include?(:block_given?)
end
end
diff --git a/spec/ruby/core/kernel/caller_locations_spec.rb b/spec/ruby/core/kernel/caller_locations_spec.rb
index 6074879d59..04cf806ef4 100644
--- a/spec/ruby/core/kernel/caller_locations_spec.rb
+++ b/spec/ruby/core/kernel/caller_locations_spec.rb
@@ -3,7 +3,7 @@ require_relative 'fixtures/caller_locations'
describe 'Kernel#caller_locations' do
it 'is a private method' do
- Kernel.should have_private_instance_method(:caller_locations)
+ Kernel.private_instance_methods(false).should.include?(:caller_locations)
end
it 'returns an Array of caller locations' do
@@ -83,7 +83,7 @@ describe 'Kernel#caller_locations' do
end
end
- ruby_version_is "3.4"..."3.5" do
+ ruby_version_is "3.4"..."4.0" do
it "includes core library methods defined in Ruby" do
file, line = Kernel.instance_method(:tap).source_location
file.should.start_with?('<internal:')
@@ -95,7 +95,7 @@ describe 'Kernel#caller_locations' do
end
end
- ruby_version_is "3.5" do
+ ruby_version_is "4.0" do
it "does not include core library methods defined in Ruby" do
file, line = Kernel.instance_method(:tap).source_location
file.should.start_with?('<internal:')
@@ -103,7 +103,10 @@ describe 'Kernel#caller_locations' do
loc = nil
tap { loc = caller_locations(1, 1)[0] }
loc.label.should == "Kernel#tap"
- loc.path.should == __FILE__
+ # CRuby hides the file which defines the method: https://bugs.ruby-lang.org/issues/20968
+ unless loc.path == __FILE__
+ loc.path.should.start_with? "<internal:"
+ end
end
end
end
diff --git a/spec/ruby/core/kernel/caller_spec.rb b/spec/ruby/core/kernel/caller_spec.rb
index 4bf9f7c2c2..225f6fc458 100644
--- a/spec/ruby/core/kernel/caller_spec.rb
+++ b/spec/ruby/core/kernel/caller_spec.rb
@@ -3,7 +3,7 @@ require_relative 'fixtures/caller'
describe 'Kernel#caller' do
it 'is a private method' do
- Kernel.should have_private_instance_method(:caller)
+ Kernel.private_instance_methods(false).should.include?(:caller)
end
it 'returns an Array of caller locations' do
@@ -32,7 +32,7 @@ describe 'Kernel#caller' do
locations = KernelSpecs::CallerTest.locations
line = __LINE__ - 1
- locations[0].should include("#{__FILE__}:#{line}:in")
+ locations[0].should.include?("#{__FILE__}:#{line}:in")
end
it "returns an Array with the block given to #at_exit at the base of the stack" do
@@ -84,25 +84,37 @@ describe 'Kernel#caller' do
end
guard -> { Kernel.instance_method(:tap).source_location } do
- ruby_version_is ""..."3.5" 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(1, 1)[0] }
- loc.should =~ /\A<internal:.*in [`'](?:Kernel#)?tap'\z/
+ loc.should =~ /\A<internal:.*in `tap'\z/
end
end
- ruby_version_is "3.5" do
+ ruby_version_is "3.4"..."4.0" 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(1, 1)[0] }
- loc.should =~ /\A#{ __FILE__ }:.*in [`'](?:Kernel#)?tap'\z/
+ loc.should =~ /\A<internal:.*in 'Kernel#tap'\z/
+ end
+ end
+
+ ruby_version_is "4.0" do
+ it "does not include 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(1, 1)[0] }
+ # CRuby hides the file which defines the method: https://bugs.ruby-lang.org/issues/20968
+ loc.should =~ /\A(<internal:|#{__FILE__}:).*in 'Kernel#tap'\z/
end
end
end
diff --git a/spec/ruby/core/kernel/case_compare_spec.rb b/spec/ruby/core/kernel/case_compare_spec.rb
index b8d30960e8..c74bbf63b9 100644
--- a/spec/ruby/core/kernel/case_compare_spec.rb
+++ b/spec/ruby/core/kernel/case_compare_spec.rb
@@ -58,18 +58,18 @@ describe "Kernel#=== for a class with #== overridden to consider other object's
end
it "returns true if #== returns true even if #equal? is false" do
- @o1.should_not equal(@o2)
+ @o1.should_not.equal?(@o2)
(@o1 == @o2).should == true
(@o1 === @o2).should == true
end
it "returns true if #equal? returns true" do
- @o1.should equal(@o1)
+ @o1.should.equal?(@o1)
(@o1 === @o1).should == true
end
it "returns false if neither #== nor #equal? returns true" do
- @o1.should_not equal(@o)
+ @o1.should_not.equal?(@o)
(@o1 == @o).should == false
(@o1 === @o).should == false
end
@@ -83,13 +83,13 @@ describe "Kernel#=== for a class with #equal? overridden to always be false" do
end
it "returns true if #== returns true even if #equal? is false" do
- @o1.should_not equal(@o1)
+ @o1.should_not.equal?(@o1)
(@o1 == @o1).should == true
(@o1 === @o1).should == true
end
it "returns false if neither #== nor #equal? returns true" do
- @o1.should_not equal(@o)
+ @o1.should_not.equal?(@o)
(@o1 == @o).should == false
(@o1 === @o).should == false
end
@@ -105,7 +105,7 @@ describe "Kernel#=== for a class with #== and #equal? overridden to always be fa
it "returns true if the object id is the same even if both #== and #equal? return false" do
@o1.object_id.should == @o1.object_id
- @o1.should_not equal(@o1)
+ @o1.should_not.equal?(@o1)
(@o1 == @o1).should == false
(@o1 === @o1).should == true
@@ -114,7 +114,7 @@ describe "Kernel#=== for a class with #== and #equal? overridden to always be fa
it "returns false if the object id is not the same and both #== and #equal? return false" do
@o1.object_id.should_not == @o2.object_id
- @o1.should_not equal(@o2)
+ @o1.should_not.equal?(@o2)
(@o1 == @o2).should == false
(@o1 === @o2).should == false
diff --git a/spec/ruby/core/kernel/catch_spec.rb b/spec/ruby/core/kernel/catch_spec.rb
index 9f59d3b384..9f02303678 100644
--- a/spec/ruby/core/kernel/catch_spec.rb
+++ b/spec/ruby/core/kernel/catch_spec.rb
@@ -31,11 +31,11 @@ describe "Kernel.catch" do
end
it "raises an ArgumentError if a Symbol is thrown for a String catch value" do
- -> { catch("exit") { throw :exit } }.should raise_error(ArgumentError)
+ -> { catch("exit") { throw :exit } }.should.raise(ArgumentError)
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".dup) { throw "exit".dup } }.should.raise(ArgumentError)
end
it "catches a Symbol when thrown a matching Symbol" do
@@ -60,7 +60,7 @@ describe "Kernel.catch" do
end
it "yields an object when called without arguments" do
- catch { |tag| tag }.should be_an_instance_of(Object)
+ catch { |tag| tag }.should.instance_of?(Object)
end
it "can be used even in a method different from where throw is called" do
@@ -116,12 +116,12 @@ describe "Kernel.catch" do
end
it "raises LocalJumpError if no block is given" do
- -> { catch :blah }.should raise_error(LocalJumpError)
+ -> { catch :blah }.should.raise(LocalJumpError)
end
end
describe "Kernel#catch" do
it "is a private method" do
- Kernel.should have_private_instance_method(:catch)
+ Kernel.private_instance_methods(false).should.include?(:catch)
end
end
diff --git a/spec/ruby/core/kernel/chomp_spec.rb b/spec/ruby/core/kernel/chomp_spec.rb
index d30e77c35a..434bf652f9 100644
--- a/spec/ruby/core/kernel/chomp_spec.rb
+++ b/spec/ruby/core/kernel/chomp_spec.rb
@@ -26,7 +26,7 @@ end
describe :kernel_chomp_private, shared: true do
it "is a private method" do
- KernelSpecs.has_private_method(@method).should be_true
+ KernelSpecs.has_private_method(@method).should == true
end
end
diff --git a/spec/ruby/core/kernel/chop_spec.rb b/spec/ruby/core/kernel/chop_spec.rb
index 9b91c011bc..bbf3c3f724 100644
--- a/spec/ruby/core/kernel/chop_spec.rb
+++ b/spec/ruby/core/kernel/chop_spec.rb
@@ -14,7 +14,7 @@ end
describe :kernel_chop_private, shared: true do
it "is a private method" do
- KernelSpecs.has_private_method(@method).should be_true
+ KernelSpecs.has_private_method(@method).should == true
end
end
diff --git a/spec/ruby/core/kernel/class_spec.rb b/spec/ruby/core/kernel/class_spec.rb
index b1d9df1671..0a7f774d14 100644
--- a/spec/ruby/core/kernel/class_spec.rb
+++ b/spec/ruby/core/kernel/class_spec.rb
@@ -3,24 +3,24 @@ require_relative 'fixtures/classes'
describe "Kernel#class" do
it "returns the class of the object" do
- Object.new.class.should equal(Object)
+ Object.new.class.should.equal?(Object)
- 1.class.should equal(Integer)
- 3.14.class.should equal(Float)
- :hello.class.should equal(Symbol)
- "hello".class.should equal(String)
- [1, 2].class.should equal(Array)
- { 1 => 2 }.class.should equal(Hash)
+ 1.class.should.equal?(Integer)
+ 3.14.class.should.equal?(Float)
+ :hello.class.should.equal?(Symbol)
+ "hello".class.should.equal?(String)
+ [1, 2].class.should.equal?(Array)
+ { 1 => 2 }.class.should.equal?(Hash)
end
it "returns Class for a class" do
- BasicObject.class.should equal(Class)
- String.class.should equal(Class)
+ BasicObject.class.should.equal?(Class)
+ String.class.should.equal?(Class)
end
it "returns the first non-singleton class" do
a = +"hello"
def a.my_singleton_method; end
- a.class.should equal(String)
+ a.class.should.equal?(String)
end
end
diff --git a/spec/ruby/core/kernel/clone_spec.rb b/spec/ruby/core/kernel/clone_spec.rb
index 5adcbbe603..80e7a78abb 100644
--- a/spec/ruby/core/kernel/clone_spec.rb
+++ b/spec/ruby/core/kernel/clone_spec.rb
@@ -10,12 +10,6 @@ describe "Kernel#clone" do
@obj = KernelSpecs::Duplicate.new 1, :a
end
- it "calls #initialize_copy on the new instance" do
- clone = @obj.clone
- ScratchPad.recorded.should_not == @obj.object_id
- ScratchPad.recorded.should == clone.object_id
- end
-
it "uses the internal allocator and does not call #allocate" do
klass = Class.new
instance = klass.new
@@ -25,7 +19,7 @@ describe "Kernel#clone" do
end
clone = instance.clone
- clone.class.should equal klass
+ clone.class.should.equal? klass
end
describe "with no arguments" do
@@ -40,7 +34,7 @@ describe "Kernel#clone" do
it 'copies frozen?' do
o = ''.freeze.clone
- o.frozen?.should be_true
+ o.frozen?.should == true
end
end
@@ -56,7 +50,7 @@ describe "Kernel#clone" do
it "copies frozen?" do
o = "".freeze.clone(freeze: nil)
- o.frozen?.should be_true
+ o.frozen?.should == true
end
end
@@ -78,7 +72,7 @@ describe "Kernel#clone" do
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)')
+ -> { obj.clone(freeze: true) }.should.raise(ArgumentError, 'wrong number of arguments (given 2, expected 1)')
end
end
@@ -100,15 +94,15 @@ describe "Kernel#clone" do
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)')
+ -> { obj.clone(freeze: false) }.should.raise(ArgumentError, 'wrong number of arguments (given 2, expected 1)')
end
end
describe "with freeze: anything else" do
it 'raises ArgumentError when passed not true/false/nil' do
- -> { @obj.clone(freeze: 1) }.should raise_error(ArgumentError, /unexpected value for freeze: Integer/)
- -> { @obj.clone(freeze: "") }.should raise_error(ArgumentError, /unexpected value for freeze: String/)
- -> { @obj.clone(freeze: Object.new) }.should raise_error(ArgumentError, /unexpected value for freeze: Object/)
+ -> { @obj.clone(freeze: 1) }.should.raise(ArgumentError, /unexpected value for freeze: Integer/)
+ -> { @obj.clone(freeze: "") }.should.raise(ArgumentError, /unexpected value for freeze: String/)
+ -> { @obj.clone(freeze: Object.new) }.should.raise(ArgumentError, /unexpected value for freeze: Object/)
end
end
diff --git a/spec/ruby/core/kernel/comparison_spec.rb b/spec/ruby/core/kernel/comparison_spec.rb
index affdc5c00d..48f17e1172 100644
--- a/spec/ruby/core/kernel/comparison_spec.rb
+++ b/spec/ruby/core/kernel/comparison_spec.rb
@@ -15,17 +15,17 @@ describe "Kernel#<=>" do
it "returns nil if self is eql? but not == to the argument" do
obj = mock('has eql?')
obj.should_not_receive(:eql?)
- obj.<=>(Object.new).should be_nil
+ obj.<=>(Object.new).should == nil
end
it "returns nil if self.==(arg) returns nil" do
obj = mock('wrong ==')
obj.should_receive(:==).and_return(nil)
- obj.<=>(Object.new).should be_nil
+ obj.<=>(Object.new).should == nil
end
it "returns nil if self is not == to the argument" do
obj = Object.new
- obj.<=>(3.14).should be_nil
+ obj.<=>(3.14).should == nil
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..ec48581db8 100644
--- a/spec/ruby/core/kernel/define_singleton_method_spec.rb
+++ b/spec/ruby/core/kernel/define_singleton_method_spec.rb
@@ -14,14 +14,14 @@ describe "Kernel#define_singleton_method" do
end
it "adds the new method to the methods list" do
- DefineSingletonMethodSpecClass.should have_method(:another_test_method)
+ DefineSingletonMethodSpecClass.should.respond_to?(:another_test_method)
end
it "defines any Child class method from any Parent's class methods" do
um = KernelSpecs::Parent.method(:parent_class_method).unbind
KernelSpecs::Child.send :define_singleton_method, :child_class_method, um
KernelSpecs::Child.child_class_method.should == :foo
- ->{KernelSpecs::Parent.child_class_method}.should raise_error(NoMethodError)
+ ->{KernelSpecs::Parent.child_class_method}.should.raise(NoMethodError)
end
it "will raise when attempting to define an object's singleton method from another object's singleton method" do
@@ -33,7 +33,7 @@ describe "Kernel#define_singleton_method" do
end
end
um = p.method(:singleton_method).unbind
- ->{ other.send :define_singleton_method, :other_singleton_method, um }.should raise_error(TypeError)
+ ->{ other.send :define_singleton_method, :other_singleton_method, um }.should.raise(TypeError)
end
end
@@ -52,11 +52,11 @@ describe "Kernel#define_singleton_method" do
it "raises a TypeError when the given method is no Method/Proc" do
-> {
Class.new { define_singleton_method(:test, "self") }
- }.should raise_error(TypeError)
+ }.should.raise(TypeError)
-> {
Class.new { define_singleton_method(:test, 1234) }
- }.should raise_error(TypeError)
+ }.should.raise(TypeError)
end
it "defines a new singleton method for objects" do
@@ -65,7 +65,7 @@ describe "Kernel#define_singleton_method" do
obj.test.should == "world!"
-> {
Object.new.test
- }.should raise_error(NoMethodError)
+ }.should.raise(NoMethodError)
end
it "maintains the Proc's scope" do
@@ -83,7 +83,7 @@ describe "Kernel#define_singleton_method" do
obj = Object.new
-> {
obj.define_singleton_method(:test)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
it "does not use the caller block when no block is given" do
@@ -94,7 +94,7 @@ describe "Kernel#define_singleton_method" do
-> {
o.define(:foo) { raise "not used" }
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
it "always defines the method with public visibility" do
@@ -109,12 +109,12 @@ describe "Kernel#define_singleton_method" do
cls.define(:foo) { :ok }
end
cls.foo.should == :ok
- }.should_not raise_error(NoMethodError)
+ }.should_not.raise(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)
+ -> { o.define_singleton_method(:foo) { 1 } }.should.raise(FrozenError)
end
end
diff --git a/spec/ruby/core/kernel/dup_spec.rb b/spec/ruby/core/kernel/dup_spec.rb
index 70198abdb7..fa4ca71476 100644
--- a/spec/ruby/core/kernel/dup_spec.rb
+++ b/spec/ruby/core/kernel/dup_spec.rb
@@ -10,12 +10,6 @@ describe "Kernel#dup" do
@obj = KernelSpecs::Duplicate.new 1, :a
end
- it "calls #initialize_copy on the new instance" do
- dup = @obj.dup
- ScratchPad.recorded.should_not == @obj.object_id
- ScratchPad.recorded.should == dup.object_id
- end
-
it "uses the internal allocator and does not call #allocate" do
klass = Class.new
instance = klass.new
@@ -25,7 +19,7 @@ describe "Kernel#dup" do
end
dup = instance.dup
- dup.class.should equal klass
+ dup.class.should.equal? klass
end
it "does not copy frozen state from the original" do
@@ -44,7 +38,7 @@ describe "Kernel#dup" do
it "does not copy singleton methods" do
def @obj.special() :the_one end
dup = @obj.dup
- -> { dup.special }.should raise_error(NameError)
+ -> { dup.special }.should.raise(NameError)
end
it "does not copy modules included in the singleton class" do
@@ -53,7 +47,7 @@ describe "Kernel#dup" do
end
dup = @obj.dup
- -> { dup.repr }.should raise_error(NameError)
+ -> { dup.repr }.should.raise(NameError)
end
it "does not copy constants defined in the singleton class" do
@@ -62,6 +56,6 @@ describe "Kernel#dup" do
end
dup = @obj.dup
- -> { class << dup; CLONE; end }.should raise_error(NameError)
+ -> { class << dup; CLONE; end }.should.raise(NameError)
end
end
diff --git a/spec/ruby/core/kernel/enum_for_spec.rb b/spec/ruby/core/kernel/enum_for_spec.rb
index 0092e20468..ef0fb64e63 100644
--- a/spec/ruby/core/kernel/enum_for_spec.rb
+++ b/spec/ruby/core/kernel/enum_for_spec.rb
@@ -1,5 +1,7 @@
require_relative '../../spec_helper'
describe "Kernel#enum_for" do
- it "needs to be reviewed for spec completeness"
+ it "is an alias of Kernel#to_enum" do
+ Kernel.instance_method(:enum_for).should == Kernel.instance_method(:to_enum)
+ end
end
diff --git a/spec/ruby/core/kernel/eql_spec.rb b/spec/ruby/core/kernel/eql_spec.rb
index e62a601a79..b3289090e5 100644
--- a/spec/ruby/core/kernel/eql_spec.rb
+++ b/spec/ruby/core/kernel/eql_spec.rb
@@ -3,7 +3,7 @@ require_relative '../../shared/kernel/equal'
describe "Kernel#eql?" do
it "is a public instance method" do
- Kernel.should have_public_instance_method(:eql?)
+ Kernel.public_instance_methods(false).should.include?(:eql?)
end
it_behaves_like :object_equal, :eql?
diff --git a/spec/ruby/core/kernel/eval_spec.rb b/spec/ruby/core/kernel/eval_spec.rb
index e027294347..f9ca47866e 100644
--- a/spec/ruby/core/kernel/eval_spec.rb
+++ b/spec/ruby/core/kernel/eval_spec.rb
@@ -5,7 +5,7 @@ EvalSpecs::A.new.c
describe "Kernel#eval" do
it "is a private method" do
- Kernel.should have_private_instance_method(:eval)
+ Kernel.private_instance_methods(false).should.include?(:eval)
end
it "is a module function" do
@@ -76,12 +76,12 @@ describe "Kernel#eval" do
x = 1
bind = proc {}
- -> { eval("x", bind) }.should raise_error(TypeError)
+ -> { eval("x", bind) }.should.raise(TypeError)
end
it "does not make Proc locals visible to evaluated code" do
bind = proc { inner = 4 }
- -> { eval("inner", bind.binding) }.should raise_error(NameError)
+ -> { eval("inner", bind.binding) }.should.raise(NameError)
end
# REWRITE ME: This obscures the real behavior of where locals are stored
@@ -119,7 +119,7 @@ describe "Kernel#eval" do
outer_binding = binding
eval("if false; a = 1; end", outer_binding)
- eval("a", outer_binding).should be_nil
+ eval("a", outer_binding).should == nil
end
it "allows creating a new class in a binding" do
@@ -136,7 +136,7 @@ describe "Kernel#eval" do
expected = 'speccing.rb'
-> {
eval('if true', TOPLEVEL_BINDING, expected)
- }.should raise_error(SyntaxError) { |e|
+ }.should.raise(SyntaxError) { |e|
e.message.should =~ /#{expected}:1:.+/
}
end
@@ -145,7 +145,7 @@ describe "Kernel#eval" do
expected_file = 'speccing.rb'
-> {
eval('if true', TOPLEVEL_BINDING, expected_file, -100)
- }.should raise_error(SyntaxError) { |e|
+ }.should.raise(SyntaxError) { |e|
e.message.should =~ /#{expected_file}:-100:.+/
}
end
@@ -159,22 +159,6 @@ describe "Kernel#eval" do
end
end
- ruby_version_is ""..."3.3" do
- it "uses (eval) filename if none is provided" do
- eval("__FILE__").should == "(eval)"
- eval("__FILE__", binding).should == "(eval)"
- eval("__FILE__", binding, "success").should == "success"
- eval("eval '__FILE__', binding").should == "(eval)"
- eval("eval '__FILE__', binding", binding).should == "(eval)"
- eval("eval '__FILE__', binding", binding, 'success').should == '(eval)'
- eval("eval '__FILE__', binding, 'success'", binding).should == 'success'
- end
-
- it 'uses (eval) for __FILE__ and 1 for __LINE__ with a binding argument' do
- eval("[__FILE__, __LINE__]", binding).should == ["(eval)", 1]
- end
- end
-
context "parameter forwarding" do
it "allows anonymous rest parameter forwarding" do
object = Object.new
@@ -244,20 +228,18 @@ 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__) 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
+ 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
# Found via Rubinius bug github:#149
it "does not alter the value of __FILE__ in the binding" do
@@ -281,14 +263,14 @@ describe "Kernel#eval" do
# See http://jira.codehaus.org/browse/JRUBY-5163
it "uses the receiver as self inside the eval" do
- eval("self").should equal(self)
- Kernel.eval("self").should equal(Kernel)
+ eval("self").should.equal?(self)
+ Kernel.eval("self").should.equal?(Kernel)
end
it "does not pass the block to the method being eval'ed" do
-> {
eval('KernelSpecs::EvalTest.call_yield') { "content" }
- }.should raise_error(LocalJumpError)
+ }.should.raise(LocalJumpError)
end
it "returns from the scope calling #eval when evaluating 'return'" do
@@ -326,7 +308,7 @@ describe "Kernel#eval" do
it "has the correct default definee when called through Method#call" do
class EvalSpecs
method(:eval).call("def eval_spec_method_call; end")
- EvalSpecs.should have_instance_method(:eval_spec_method_call)
+ EvalSpecs.should.method_defined?(:eval_spec_method_call, false)
end
end
@@ -380,7 +362,7 @@ end
CODE
code.encoding.should == Encoding::BINARY
eval(code)
- EvalSpecs.constants(false).should include(:"VÏ€")
+ EvalSpecs.constants(false).should.include?(:"VÏ€")
EvalSpecs::VÏ€.should == 3.14
ensure
EvalSpecs.send(:remove_const, :VÏ€)
@@ -395,7 +377,7 @@ end
CODE
code.encoding.should == Encoding::BINARY
eval(code)
- EvalSpecs.constants(false).should include(:"VÏ€emacs")
+ EvalSpecs.constants(false).should.include?(:"VÏ€emacs")
EvalSpecs::VÏ€emacs.should == 3.14
ensure
EvalSpecs.send(:remove_const, :VÏ€emacs)
@@ -410,7 +392,7 @@ end
CODE
code.encoding.should == Encoding::BINARY
eval(code)
- EvalSpecs.constants(false).should include(:"VÏ€spaces")
+ EvalSpecs.constants(false).should.include?(:"VÏ€spaces")
EvalSpecs::VÏ€spaces.should == 3.14
ensure
EvalSpecs.send(:remove_const, :VÏ€spaces)
@@ -426,7 +408,7 @@ end
CODE
code.encoding.should == Encoding::BINARY
eval(code)
- EvalSpecs.constants(false).should include(:"VÏ€shebang")
+ EvalSpecs.constants(false).should.include?(:"VÏ€shebang")
EvalSpecs::VÏ€shebang.should == 3.14
ensure
EvalSpecs.send(:remove_const, :VÏ€shebang)
@@ -442,7 +424,7 @@ end
CODE
code.encoding.should == Encoding::BINARY
eval(code)
- EvalSpecs.constants(false).should include(:"VÏ€shebang_spaces")
+ EvalSpecs.constants(false).should.include?(:"VÏ€shebang_spaces")
EvalSpecs::VÏ€shebang_spaces.should == 3.14
ensure
EvalSpecs.send(:remove_const, :VÏ€shebang_spaces)
@@ -460,7 +442,7 @@ end
CODE
code.encoding.should == Encoding::BINARY
eval(code)
- EvalSpecs.constants(false).should include(:"VÏ€string")
+ 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
@@ -477,10 +459,10 @@ end
CODE
code.encoding.should == Encoding::BINARY
eval(code)
- EvalSpecs.constants(false).should include(:"VÏ€same_line")
+ EvalSpecs.constants(false).should.include?(:"VÏ€same_line")
EvalSpecs::VÏ€same_line.should == "frozen"
EvalSpecs::VÏ€same_line.encoding.should == Encoding::UTF_8
- EvalSpecs::VÏ€same_line.frozen?.should be_true
+ EvalSpecs::VÏ€same_line.frozen?.should == true
ensure
EvalSpecs.send(:remove_const, :VÏ€same_line)
end
@@ -496,9 +478,9 @@ end
CODE
code.encoding.should == Encoding::BINARY
eval(code)
- EvalSpecs.constants(false).should_not include(:"VÏ€frozen_first")
+ EvalSpecs.constants(false).should_not.include?(:"VÏ€frozen_first")
binary_constant = "VÏ€frozen_first".b.to_sym
- EvalSpecs.constants(false).should include(binary_constant)
+ EvalSpecs.constants(false).should.include?(binary_constant)
value = EvalSpecs.const_get(binary_constant)
value.should == "frozen"
value.encoding.should == Encoding::BINARY
diff --git a/spec/ruby/core/kernel/exec_spec.rb b/spec/ruby/core/kernel/exec_spec.rb
index 3d9520ad67..fd8485791a 100644
--- a/spec/ruby/core/kernel/exec_spec.rb
+++ b/spec/ruby/core/kernel/exec_spec.rb
@@ -3,7 +3,7 @@ require_relative 'fixtures/classes'
describe "Kernel#exec" do
it "is a private method" do
- Kernel.should have_private_instance_method(:exec)
+ Kernel.private_instance_methods(false).should.include?(:exec)
end
it "runs the specified command, replacing current process" do
diff --git a/spec/ruby/core/kernel/exit_spec.rb b/spec/ruby/core/kernel/exit_spec.rb
index 93cec3fee5..864ff84449 100644
--- a/spec/ruby/core/kernel/exit_spec.rb
+++ b/spec/ruby/core/kernel/exit_spec.rb
@@ -4,7 +4,7 @@ require_relative '../../shared/process/exit'
describe "Kernel#exit" do
it "is a private method" do
- Kernel.should have_private_instance_method(:exit)
+ Kernel.private_instance_methods(false).should.include?(:exit)
end
it_behaves_like :process_exit, :exit, KernelSpecs::Method.new
@@ -16,7 +16,7 @@ end
describe "Kernel#exit!" do
it "is a private method" do
- Kernel.should have_private_instance_method(:exit!)
+ Kernel.private_instance_methods(false).should.include?(:exit!)
end
it_behaves_like :process_exit!, :exit!, "self"
diff --git a/spec/ruby/core/kernel/extend_spec.rb b/spec/ruby/core/kernel/extend_spec.rb
index 6342d8cae1..a344c7b5ca 100644
--- a/spec/ruby/core/kernel/extend_spec.rb
+++ b/spec/ruby/core/kernel/extend_spec.rb
@@ -53,13 +53,13 @@ describe "Kernel#extend" do
end
it "raises an ArgumentError when no arguments given" do
- -> { Object.new.extend }.should raise_error(ArgumentError)
+ -> { Object.new.extend }.should.raise(ArgumentError)
end
it "raises a TypeError when the argument is not a Module" do
o = mock('o')
klass = Class.new
- -> { o.extend(klass) }.should raise_error(TypeError)
+ -> { o.extend(klass) }.should.raise(TypeError)
end
describe "on frozen instance" do
@@ -69,11 +69,11 @@ describe "Kernel#extend" do
end
it "raises an ArgumentError when no arguments given" do
- -> { @frozen.extend }.should raise_error(ArgumentError)
+ -> { @frozen.extend }.should.raise(ArgumentError)
end
it "raises a FrozenError" do
- -> { @frozen.extend @module }.should raise_error(FrozenError)
+ -> { @frozen.extend @module }.should.raise(FrozenError)
end
end
diff --git a/spec/ruby/core/kernel/fail_spec.rb b/spec/ruby/core/kernel/fail_spec.rb
index fab622037e..2d117d26cd 100644
--- a/spec/ruby/core/kernel/fail_spec.rb
+++ b/spec/ruby/core/kernel/fail_spec.rb
@@ -1,42 +1,13 @@
require_relative '../../spec_helper'
-require_relative 'fixtures/classes'
describe "Kernel#fail" do
- it "is a private method" do
- Kernel.should have_private_instance_method(:fail)
- end
-
- it "raises a RuntimeError" do
- -> { fail }.should raise_error(RuntimeError)
- end
-
- it "accepts an Object with an exception method returning an Exception" do
- obj = Object.new
- def obj.exception(msg)
- StandardError.new msg
- end
- -> { fail obj, "..." }.should raise_error(StandardError, "...")
- end
-
- it "instantiates the specified exception class" do
- error_class = Class.new(RuntimeError)
- -> { fail error_class }.should raise_error(error_class)
- end
-
- it "uses the specified message" do
- -> {
- begin
- fail "the duck is not irish."
- rescue => e
- e.message.should == "the duck is not irish."
- raise
- else
- raise Exception
- end
- }.should raise_error(RuntimeError)
+ it "is an alias of Kernel#raise" do
+ Kernel.instance_method(:fail).should == Kernel.instance_method(:raise)
end
end
describe "Kernel.fail" do
- it "needs to be reviewed for spec completeness"
+ it "is an alias of Kernel.raise" do
+ Kernel.method(:fail).should == Kernel.method(:raise)
+ end
end
diff --git a/spec/ruby/core/kernel/fixtures/autoload_relative_b.rb b/spec/ruby/core/kernel/fixtures/autoload_relative_b.rb
new file mode 100644
index 0000000000..6de6f5091d
--- /dev/null
+++ b/spec/ruby/core/kernel/fixtures/autoload_relative_b.rb
@@ -0,0 +1,7 @@
+module KernelSpecs
+ module KSAutoloadRelativeB
+ def self.loaded
+ :ksautoload_b
+ end
+ end
+end
diff --git a/spec/ruby/core/kernel/fixtures/autoload_relative_d.rb b/spec/ruby/core/kernel/fixtures/autoload_relative_d.rb
new file mode 100644
index 0000000000..5b6b5e1fa2
--- /dev/null
+++ b/spec/ruby/core/kernel/fixtures/autoload_relative_d.rb
@@ -0,0 +1,5 @@
+module KSAutoloadRelativeD
+ def self.loaded
+ :ksautoload_d
+ end
+end
diff --git a/spec/ruby/core/kernel/fixtures/classes.rb b/spec/ruby/core/kernel/fixtures/classes.rb
index 0e2b81988f..ad82f3cef5 100644
--- a/spec/ruby/core/kernel/fixtures/classes.rb
+++ b/spec/ruby/core/kernel/fixtures/classes.rb
@@ -180,6 +180,25 @@ module KernelSpecs
alias aliased_pub_method pub_method
end
+ class BasicA < BasicObject
+ define_method(:respond_to?, ::Kernel.instance_method(:respond_to?))
+
+ def pub_method; :public_method; end
+
+ def undefed_method; :undefed_method; end
+ undef_method :undefed_method
+
+ protected
+ def protected_method; :protected_method; end
+
+ private
+ def private_method; :private_method; end
+ end
+
+ class MissingA < A
+ undef :respond_to_missing?
+ end
+
class VisibilityChange
class << self
private :new
diff --git a/spec/ruby/core/kernel/fork_spec.rb b/spec/ruby/core/kernel/fork_spec.rb
index b37f9980e0..4a2c848202 100644
--- a/spec/ruby/core/kernel/fork_spec.rb
+++ b/spec/ruby/core/kernel/fork_spec.rb
@@ -4,7 +4,7 @@ require_relative '../../shared/process/fork'
describe "Kernel#fork" do
it "is a private method" do
- Kernel.should have_private_instance_method(:fork)
+ Kernel.private_instance_methods(false).should.include?(:fork)
end
it_behaves_like :process_fork, :fork, KernelSpecs::Method.new
diff --git a/spec/ruby/core/kernel/format_spec.rb b/spec/ruby/core/kernel/format_spec.rb
index 1d0c000c15..a311f3c3d7 100644
--- a/spec/ruby/core/kernel/format_spec.rb
+++ b/spec/ruby/core/kernel/format_spec.rb
@@ -1,47 +1,13 @@
require_relative '../../spec_helper'
-require_relative 'fixtures/classes'
-# NOTE: most specs are in sprintf_spec.rb, this is just an alias
describe "Kernel#format" do
- it "is a private method" do
- Kernel.should have_private_instance_method(:format)
+ it "is an alias of Kernel#sprintf" do
+ Kernel.instance_method(:format).should == Kernel.instance_method(:sprintf)
end
end
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
+ it "is an alias of Kernel.sprintf" do
+ Kernel.method(:format).should == Kernel.method(:sprintf)
end
end
diff --git a/spec/ruby/core/kernel/freeze_spec.rb b/spec/ruby/core/kernel/freeze_spec.rb
index fa32d321cf..079617dce4 100644
--- a/spec/ruby/core/kernel/freeze_spec.rb
+++ b/spec/ruby/core/kernel/freeze_spec.rb
@@ -4,46 +4,46 @@ require_relative 'fixtures/classes'
describe "Kernel#freeze" do
it "prevents self from being further modified" do
o = mock('o')
- o.frozen?.should be_false
+ o.frozen?.should == false
o.freeze
- o.frozen?.should be_true
+ o.frozen?.should == true
end
it "returns self" do
o = Object.new
- o.freeze.should equal(o)
+ o.freeze.should.equal?(o)
end
describe "on integers" do
it "has no effect since they are already frozen" do
- 1.frozen?.should be_true
+ 1.frozen?.should == true
1.freeze
bignum = bignum_value
- bignum.frozen?.should be_true
+ bignum.frozen?.should == true
bignum.freeze
end
end
describe "on a Float" do
it "has no effect since it is already frozen" do
- 1.2.frozen?.should be_true
+ 1.2.frozen?.should == true
1.2.freeze
end
end
describe "on a Symbol" do
it "has no effect since it is already frozen" do
- :sym.frozen?.should be_true
+ :sym.frozen?.should == true
:sym.freeze
end
end
describe "on true, false and nil" do
it "has no effect since they are already frozen" do
- nil.frozen?.should be_true
- true.frozen?.should be_true
- false.frozen?.should be_true
+ nil.frozen?.should == true
+ true.frozen?.should == true
+ false.frozen?.should == true
nil.freeze
true.freeze
@@ -54,7 +54,7 @@ describe "Kernel#freeze" do
describe "on a Complex" do
it "has no effect since it is already frozen" do
c = Complex(1.3, 3.1)
- c.frozen?.should be_true
+ c.frozen?.should == true
c.freeze
end
end
@@ -62,7 +62,7 @@ describe "Kernel#freeze" do
describe "on a Rational" do
it "has no effect since it is already frozen" do
r = Rational(1, 3)
- r.frozen?.should be_true
+ r.frozen?.should == true
r.freeze
end
end
@@ -72,13 +72,13 @@ describe "Kernel#freeze" do
def mutate; @foo = 1; end
end.new
o.freeze
- -> {o.mutate}.should raise_error(RuntimeError)
+ -> {o.mutate}.should.raise(RuntimeError)
end
it "causes instance_variable_set to raise RuntimeError" do
o = Object.new
o.freeze
- -> {o.instance_variable_set(:@foo, 1)}.should raise_error(RuntimeError)
+ -> {o.instance_variable_set(:@foo, 1)}.should.raise(RuntimeError)
end
it "freezes an object's singleton class" do
diff --git a/spec/ruby/core/kernel/frozen_spec.rb b/spec/ruby/core/kernel/frozen_spec.rb
index a4cec4263d..8b8fad3de7 100644
--- a/spec/ruby/core/kernel/frozen_spec.rb
+++ b/spec/ruby/core/kernel/frozen_spec.rb
@@ -12,9 +12,9 @@ describe "Kernel#frozen?" do
describe "on true, false and nil" do
it "returns true" do
- true.frozen?.should be_true
- false.frozen?.should be_true
- nil.frozen?.should be_true
+ true.frozen?.should == true
+ false.frozen?.should == true
+ nil.frozen?.should == true
end
end
@@ -25,8 +25,8 @@ describe "Kernel#frozen?" do
end
it "returns true" do
- @fixnum.frozen?.should be_true
- @bignum.frozen?.should be_true
+ @fixnum.frozen?.should == true
+ @bignum.frozen?.should == true
end
end
@@ -36,7 +36,7 @@ describe "Kernel#frozen?" do
end
it "returns true" do
- @float.frozen?.should be_true
+ @float.frozen?.should == true
end
end
@@ -46,31 +46,31 @@ describe "Kernel#frozen?" do
end
it "returns true" do
- @symbol.frozen?.should be_true
+ @symbol.frozen?.should == true
end
end
describe "on a Complex" do
it "returns true" do
c = Complex(1.3, 3.1)
- c.frozen?.should be_true
+ c.frozen?.should == true
end
it "literal returns true" do
c = eval "1.3i"
- c.frozen?.should be_true
+ c.frozen?.should == true
end
end
describe "on a Rational" do
it "returns true" do
r = Rational(1, 3)
- r.frozen?.should be_true
+ r.frozen?.should == true
end
it "literal returns true" do
r = eval "1/3r"
- r.frozen?.should be_true
+ r.frozen?.should == true
end
end
end
diff --git a/spec/ruby/core/kernel/gets_spec.rb b/spec/ruby/core/kernel/gets_spec.rb
index 104613dbfa..1b2b36fbb9 100644
--- a/spec/ruby/core/kernel/gets_spec.rb
+++ b/spec/ruby/core/kernel/gets_spec.rb
@@ -3,7 +3,7 @@ require_relative 'fixtures/classes'
describe "Kernel#gets" do
it "is a private method" do
- Kernel.should have_private_instance_method(:gets)
+ Kernel.private_instance_methods(false).should.include?(:gets)
end
it "calls ARGF.gets" do
diff --git a/spec/ruby/core/kernel/global_variables_spec.rb b/spec/ruby/core/kernel/global_variables_spec.rb
index 8bce8e25b7..d41bdff49a 100644
--- a/spec/ruby/core/kernel/global_variables_spec.rb
+++ b/spec/ruby/core/kernel/global_variables_spec.rb
@@ -3,7 +3,7 @@ require_relative 'fixtures/classes'
describe "Kernel.global_variables" do
it "is a private method" do
- Kernel.should have_private_instance_method(:global_variables)
+ Kernel.private_instance_methods(false).should.include?(:global_variables)
end
before :all do
@@ -11,13 +11,13 @@ describe "Kernel.global_variables" do
end
it "finds subset starting with std" do
- global_variables.grep(/std/).should include(:$stderr, :$stdin, :$stdout)
+ global_variables.grep(/std/).to_set.should >= Set[:$stderr, :$stdin, :$stdout]
a = global_variables.size
gvar_name = "$foolish_global_var#{@i += 1}"
global_variables.include?(gvar_name.to_sym).should == false
eval("#{gvar_name} = 1")
global_variables.size.should == a+1
- global_variables.should include(gvar_name.to_sym)
+ global_variables.should.include?(gvar_name.to_sym)
end
end
diff --git a/spec/ruby/core/kernel/gsub_spec.rb b/spec/ruby/core/kernel/gsub_spec.rb
index a0cb9f2a70..e05349e2b5 100644
--- a/spec/ruby/core/kernel/gsub_spec.rb
+++ b/spec/ruby/core/kernel/gsub_spec.rb
@@ -6,20 +6,20 @@ require_relative 'fixtures/classes'
ruby_version_is ""..."1.9" do
describe "Kernel#gsub" do
it "is a private method" do
- Kernel.should have_private_instance_method(:gsub)
+ Kernel.private_instance_methods(false).should.include?(:gsub)
end
it "raises a TypeError if $_ is not a String" do
-> {
$_ = 123
gsub(/./, "!")
- }.should raise_error(TypeError)
+ }.should.raise(TypeError)
end
it "when matches sets $_ to a new string, leaving the former value unaltered" do
orig_value = $_ = "hello"
gsub("ello", "ola")
- $_.should_not equal(orig_value)
+ $_.should_not.equal?(orig_value)
$_.should == "hola"
orig_value.should == "hello"
end
@@ -86,7 +86,7 @@ ruby_version_is ""..."1.9" do
describe "Kernel#gsub!" do
it "is a private method" do
- Kernel.should have_private_instance_method(:gsub!)
+ Kernel.private_instance_methods(false).should.include?(:gsub!)
end
end
diff --git a/spec/ruby/core/kernel/initialize_clone_spec.rb b/spec/ruby/core/kernel/initialize_clone_spec.rb
index 21a90c19f0..0033eadffb 100644
--- a/spec/ruby/core/kernel/initialize_clone_spec.rb
+++ b/spec/ruby/core/kernel/initialize_clone_spec.rb
@@ -2,7 +2,7 @@ require_relative '../../spec_helper'
describe "Kernel#initialize_clone" do
it "is a private instance method" do
- Kernel.should have_private_instance_method(:initialize_clone)
+ Kernel.private_instance_methods(false).should.include?(:initialize_clone)
end
it "returns the receiver" do
diff --git a/spec/ruby/core/kernel/initialize_copy_spec.rb b/spec/ruby/core/kernel/initialize_copy_spec.rb
index d71ca9f60f..ebac0c14de 100644
--- a/spec/ruby/core/kernel/initialize_copy_spec.rb
+++ b/spec/ruby/core/kernel/initialize_copy_spec.rb
@@ -17,8 +17,8 @@ describe "Kernel#initialize_copy" do
end
it "raises FrozenError if the receiver is frozen" do
- -> { Object.new.freeze.send(:initialize_copy, Object.new) }.should raise_error(FrozenError)
- -> { 1.send(:initialize_copy, Object.new) }.should raise_error(FrozenError)
+ -> { Object.new.freeze.send(:initialize_copy, Object.new) }.should.raise(FrozenError)
+ -> { 1.send(:initialize_copy, Object.new) }.should.raise(FrozenError)
end
it "raises TypeError if the objects are of different class" do
@@ -27,10 +27,10 @@ describe "Kernel#initialize_copy" do
a = klass.new
b = sub.new
message = 'initialize_copy should take same class object'
- -> { a.send(:initialize_copy, b) }.should raise_error(TypeError, message)
- -> { b.send(:initialize_copy, a) }.should raise_error(TypeError, message)
+ -> { a.send(:initialize_copy, b) }.should.raise(TypeError, message)
+ -> { b.send(:initialize_copy, a) }.should.raise(TypeError, message)
- -> { a.send(:initialize_copy, 1) }.should raise_error(TypeError, message)
- -> { a.send(:initialize_copy, 1.0) }.should raise_error(TypeError, message)
+ -> { a.send(:initialize_copy, 1) }.should.raise(TypeError, message)
+ -> { a.send(:initialize_copy, 1.0) }.should.raise(TypeError, message)
end
end
diff --git a/spec/ruby/core/kernel/initialize_dup_spec.rb b/spec/ruby/core/kernel/initialize_dup_spec.rb
index 6dff34b7ad..f144647eb8 100644
--- a/spec/ruby/core/kernel/initialize_dup_spec.rb
+++ b/spec/ruby/core/kernel/initialize_dup_spec.rb
@@ -2,7 +2,7 @@ require_relative '../../spec_helper'
describe "Kernel#initialize_dup" do
it "is a private instance method" do
- Kernel.should have_private_instance_method(:initialize_dup)
+ Kernel.private_instance_methods(false).should.include?(:initialize_dup)
end
it "returns the receiver" do
diff --git a/spec/ruby/core/kernel/inspect_spec.rb b/spec/ruby/core/kernel/inspect_spec.rb
index e60f7576c5..8fc3ab51cd 100644
--- a/spec/ruby/core/kernel/inspect_spec.rb
+++ b/spec/ruby/core/kernel/inspect_spec.rb
@@ -3,7 +3,7 @@ require_relative 'fixtures/classes'
describe "Kernel#inspect" do
it "returns a String" do
- Object.new.inspect.should be_an_instance_of(String)
+ Object.new.inspect.should.instance_of?(String)
end
it "does not call #to_s if it is defined" do
@@ -26,10 +26,10 @@ describe "Kernel#inspect" do
class << obj
undef_method :class
end
- obj.inspect.should be_kind_of(String)
+ obj.inspect.should.is_a?(String)
end
- ruby_version_is "3.5" do
+ ruby_version_is "4.0" do
it "calls #instance_variables_to_inspect private method to know which variables to display" do
obj = Object.new
obj.instance_eval do
@@ -57,5 +57,47 @@ describe "Kernel#inspect" do
inspected = obj.inspect.sub(/^#<Object:0x[0-9a-f]+/, '#<Object:0x00')
inspected.should == "#<Object:0x00>"
end
+
+ it "displays all instance variables if #instance_variables_to_inspect returns nil" do
+ obj = Object.new
+ obj.instance_eval do
+ @host = "localhost"
+ @user = "root"
+ @password = "hunter2"
+ end
+ obj.singleton_class.class_eval do
+ private def instance_variables_to_inspect = nil
+ end
+
+ inspected = obj.inspect.sub(/^#<Object:0x[0-9a-f]+/, '#<Object:0x00')
+ inspected.should == %{#<Object:0x00 @host="localhost", @user="root", @password="hunter2">}
+ end
+
+ it "displays all instance variables if #instance_variables_to_inspect is not defined" do
+ obj = BasicObject.new
+ obj.instance_eval do
+ @host = "localhost"
+ @user = "root"
+ @password = "hunter2"
+ end
+ method_inspect = Kernel.instance_method(:inspect)
+
+ inspected = method_inspect.bind(obj).call.sub(/^#<BasicObject:0x[0-9a-f]+/, '#<BasicObject:0x00')
+ inspected.should == %{#<BasicObject:0x00 @host="localhost", @user="root", @password="hunter2">}
+ end
+
+ it "raises an error if #instance_variables_to_inspect returns an invalid value" do
+ obj = Object.new
+ obj.instance_eval do
+ @host = "localhost"
+ @user = "root"
+ @password = "hunter2"
+ end
+ obj.singleton_class.class_eval do
+ private def instance_variables_to_inspect = {}
+ end
+
+ ->{ obj.inspect }.should.raise(TypeError, "Expected #instance_variables_to_inspect to return an Array or nil, but it returned Hash")
+ end
end
end
diff --git a/spec/ruby/core/kernel/instance_of_spec.rb b/spec/ruby/core/kernel/instance_of_spec.rb
index d1170d5047..8d19974aa3 100644
--- a/spec/ruby/core/kernel/instance_of_spec.rb
+++ b/spec/ruby/core/kernel/instance_of_spec.rb
@@ -33,8 +33,8 @@ describe "Kernel#instance_of?" do
end
it "raises a TypeError if given an object that is not a Class nor a Module" do
- -> { @o.instance_of?(Object.new) }.should raise_error(TypeError)
- -> { @o.instance_of?('KernelSpecs::InstanceClass') }.should raise_error(TypeError)
- -> { @o.instance_of?(1) }.should raise_error(TypeError)
+ -> { @o.instance_of?(Object.new) }.should.raise(TypeError)
+ -> { @o.instance_of?('KernelSpecs::InstanceClass') }.should.raise(TypeError)
+ -> { @o.instance_of?(1) }.should.raise(TypeError)
end
end
diff --git a/spec/ruby/core/kernel/instance_variable_defined_spec.rb b/spec/ruby/core/kernel/instance_variable_defined_spec.rb
index 2ebb582b43..512f811393 100644
--- a/spec/ruby/core/kernel/instance_variable_defined_spec.rb
+++ b/spec/ruby/core/kernel/instance_variable_defined_spec.rb
@@ -8,21 +8,21 @@ describe "Kernel#instance_variable_defined?" do
describe "when passed a String" do
it "returns false if the instance variable is not defined" do
- @instance.instance_variable_defined?("@goodbye").should be_false
+ @instance.instance_variable_defined?("@goodbye").should == false
end
it "returns true if the instance variable is defined" do
- @instance.instance_variable_defined?("@greeting").should be_true
+ @instance.instance_variable_defined?("@greeting").should == true
end
end
describe "when passed a Symbol" do
it "returns false if the instance variable is not defined" do
- @instance.instance_variable_defined?(:@goodbye).should be_false
+ @instance.instance_variable_defined?(:@goodbye).should == false
end
it "returns true if the instance variable is defined" do
- @instance.instance_variable_defined?(:@greeting).should be_true
+ @instance.instance_variable_defined?(:@greeting).should == true
end
end
@@ -30,12 +30,12 @@ describe "Kernel#instance_variable_defined?" do
-> do
obj = mock("kernel instance_variable_defined?")
@instance.instance_variable_defined? obj
- end.should raise_error(TypeError)
+ end.should.raise(TypeError)
end
it "returns false if the instance variable is not defined for different types" do
[nil, false, true, 1, 2.0, :test, "test"].each do |obj|
- obj.instance_variable_defined?("@goodbye").should be_false
+ obj.instance_variable_defined?("@goodbye").should == false
end
end
end
diff --git a/spec/ruby/core/kernel/instance_variable_get_spec.rb b/spec/ruby/core/kernel/instance_variable_get_spec.rb
index f1d2a45df8..8404c94192 100644
--- a/spec/ruby/core/kernel/instance_variable_get_spec.rb
+++ b/spec/ruby/core/kernel/instance_variable_get_spec.rb
@@ -20,29 +20,29 @@ describe "Kernel#instance_variable_get" do
end
it "returns nil when the referred instance variable does not exist" do
- @obj.instance_variable_get(:@does_not_exist).should be_nil
+ @obj.instance_variable_get(:@does_not_exist).should == nil
end
it "raises a TypeError when the passed argument does not respond to #to_str" do
- -> { @obj.instance_variable_get(Object.new) }.should raise_error(TypeError)
+ -> { @obj.instance_variable_get(Object.new) }.should.raise(TypeError)
end
it "raises a TypeError when the passed argument can't be converted to a String" do
obj = mock("to_str")
obj.stub!(:to_str).and_return(123)
- -> { @obj.instance_variable_get(obj) }.should raise_error(TypeError)
+ -> { @obj.instance_variable_get(obj) }.should.raise(TypeError)
end
it "raises a NameError when the conversion result does not start with an '@'" do
obj = mock("to_str")
obj.stub!(:to_str).and_return("test")
- -> { @obj.instance_variable_get(obj) }.should raise_error(NameError)
+ -> { @obj.instance_variable_get(obj) }.should.raise(NameError)
end
it "raises a NameError when passed just '@'" do
obj = mock("to_str")
obj.stub!(:to_str).and_return('@')
- -> { @obj.instance_variable_get(obj) }.should raise_error(NameError)
+ -> { @obj.instance_variable_get(obj) }.should.raise(NameError)
end
end
@@ -57,20 +57,20 @@ describe "Kernel#instance_variable_get when passed Symbol" do
end
it "raises a NameError when passed :@ as an instance variable name" do
- -> { @obj.instance_variable_get(:"@") }.should raise_error(NameError)
+ -> { @obj.instance_variable_get(:"@") }.should.raise(NameError)
end
it "raises a NameError when the passed Symbol does not start with an '@'" do
- -> { @obj.instance_variable_get(:test) }.should raise_error(NameError)
+ -> { @obj.instance_variable_get(:test) }.should.raise(NameError)
end
it "raises a NameError when the passed Symbol is an invalid instance variable name" do
- -> { @obj.instance_variable_get(:"@0") }.should raise_error(NameError)
+ -> { @obj.instance_variable_get(:"@0") }.should.raise(NameError)
end
it "returns nil or raises for frozen objects" do
nil.instance_variable_get(:@foo).should == nil
- -> { nil.instance_variable_get(:foo) }.should raise_error(NameError)
+ -> { nil.instance_variable_get(:foo) }.should.raise(NameError)
:foo.instance_variable_get(:@foo).should == nil
end
end
@@ -86,15 +86,15 @@ describe "Kernel#instance_variable_get when passed String" do
end
it "raises a NameError when the passed String does not start with an '@'" do
- -> { @obj.instance_variable_get("test") }.should raise_error(NameError)
+ -> { @obj.instance_variable_get("test") }.should.raise(NameError)
end
it "raises a NameError when the passed String is an invalid instance variable name" do
- -> { @obj.instance_variable_get("@0") }.should raise_error(NameError)
+ -> { @obj.instance_variable_get("@0") }.should.raise(NameError)
end
it "raises a NameError when passed '@' as an instance variable name" do
- -> { @obj.instance_variable_get("@") }.should raise_error(NameError)
+ -> { @obj.instance_variable_get("@") }.should.raise(NameError)
end
end
@@ -105,7 +105,7 @@ describe "Kernel#instance_variable_get when passed Integer" do
end
it "raises a TypeError" do
- -> { @obj.instance_variable_get(10) }.should raise_error(TypeError)
- -> { @obj.instance_variable_get(-10) }.should raise_error(TypeError)
+ -> { @obj.instance_variable_get(10) }.should.raise(TypeError)
+ -> { @obj.instance_variable_get(-10) }.should.raise(TypeError)
end
end
diff --git a/spec/ruby/core/kernel/instance_variable_set_spec.rb b/spec/ruby/core/kernel/instance_variable_set_spec.rb
index 2c25f4366f..bf165a824e 100644
--- a/spec/ruby/core/kernel/instance_variable_set_spec.rb
+++ b/spec/ruby/core/kernel/instance_variable_set_spec.rb
@@ -18,26 +18,26 @@ describe "Kernel#instance_variable_set" do
it "raises a NameError exception if the argument is not of form '@x'" do
no_dog = Class.new
- -> { no_dog.new.instance_variable_set(:c, "cat") }.should raise_error(NameError)
+ -> { no_dog.new.instance_variable_set(:c, "cat") }.should.raise(NameError)
end
it "raises a NameError exception if the argument is an invalid instance variable name" do
digit_dog = Class.new
- -> { digit_dog.new.instance_variable_set(:"@0", "cat") }.should raise_error(NameError)
+ -> { digit_dog.new.instance_variable_set(:"@0", "cat") }.should.raise(NameError)
end
it "raises a NameError when the argument is '@'" do
dog_at = Class.new
- -> { dog_at.new.instance_variable_set(:"@", "cat") }.should raise_error(NameError)
+ -> { dog_at.new.instance_variable_set(:"@", "cat") }.should.raise(NameError)
end
it "raises a TypeError if the instance variable name is an Integer" do
- -> { "".instance_variable_set(1, 2) }.should raise_error(TypeError)
+ -> { "".instance_variable_set(1, 2) }.should.raise(TypeError)
end
it "raises a TypeError if the instance variable name is an object that does not respond to to_str" do
class KernelSpecs::A; end
- -> { "".instance_variable_set(KernelSpecs::A.new, 3) }.should raise_error(TypeError)
+ -> { "".instance_variable_set(KernelSpecs::A.new, 3) }.should.raise(TypeError)
end
it "raises a NameError if the passed object, when coerced with to_str, does not start with @" do
@@ -46,11 +46,11 @@ describe "Kernel#instance_variable_set" do
":c"
end
end
- -> { "".instance_variable_set(KernelSpecs::B.new, 4) }.should raise_error(NameError)
+ -> { "".instance_variable_set(KernelSpecs::B.new, 4) }.should.raise(NameError)
end
it "raises a NameError if pass an object that cannot be a symbol" do
- -> { "".instance_variable_set(:c, 1) }.should raise_error(NameError)
+ -> { "".instance_variable_set(:c, 1) }.should.raise(NameError)
end
it "accepts as instance variable name any instance of a class that responds to to_str" do
@@ -78,16 +78,16 @@ describe "Kernel#instance_variable_set" do
end
it "keeps stored object after any exceptions" do
- -> { @frozen.instance_variable_set(:@ivar, :replacement) }.should raise_error(Exception)
- @frozen.ivar.should equal(:origin)
+ -> { @frozen.instance_variable_set(:@ivar, :replacement) }.should.raise(Exception)
+ @frozen.ivar.should.equal?(:origin)
end
it "raises a FrozenError when passed replacement is identical to stored object" do
- -> { @frozen.instance_variable_set(:@ivar, :origin) }.should raise_error(FrozenError)
+ -> { @frozen.instance_variable_set(:@ivar, :origin) }.should.raise(FrozenError)
end
it "raises a FrozenError when passed replacement is different from stored object" do
- -> { @frozen.instance_variable_set(:@ivar, :replacement) }.should raise_error(FrozenError)
+ -> { @frozen.instance_variable_set(:@ivar, :replacement) }.should.raise(FrozenError)
end
it "accepts unicode instance variable names" do
@@ -97,9 +97,9 @@ describe "Kernel#instance_variable_set" do
end
it "raises for frozen objects" do
- -> { nil.instance_variable_set(:@foo, 42) }.should raise_error(FrozenError)
- -> { nil.instance_variable_set(:foo, 42) }.should raise_error(NameError)
- -> { :foo.instance_variable_set(:@foo, 42) }.should raise_error(FrozenError)
+ -> { nil.instance_variable_set(:@foo, 42) }.should.raise(FrozenError)
+ -> { nil.instance_variable_set(:foo, 42) }.should.raise(NameError)
+ -> { :foo.instance_variable_set(:@foo, 42) }.should.raise(FrozenError)
end
end
end
diff --git a/spec/ruby/core/kernel/instance_variables_spec.rb b/spec/ruby/core/kernel/instance_variables_spec.rb
index 677d8bb7b2..75c1d8f752 100644
--- a/spec/ruby/core/kernel/instance_variables_spec.rb
+++ b/spec/ruby/core/kernel/instance_variables_spec.rb
@@ -11,7 +11,7 @@ describe "Kernel#instance_variables" do
it "returns the correct array if an instance variable is added" do
a = 0
- ->{ a.instance_variable_set("@test", 1) }.should raise_error(RuntimeError)
+ ->{ a.instance_variable_set("@test", 1) }.should.raise(RuntimeError)
end
end
diff --git a/spec/ruby/core/kernel/is_a_spec.rb b/spec/ruby/core/kernel/is_a_spec.rb
index bd8c96529a..ff36a769c7 100644
--- a/spec/ruby/core/kernel/is_a_spec.rb
+++ b/spec/ruby/core/kernel/is_a_spec.rb
@@ -1,6 +1,56 @@
require_relative '../../spec_helper'
-require_relative 'shared/kind_of'
+require_relative 'fixtures/classes'
describe "Kernel#is_a?" do
- it_behaves_like :kernel_kind_of, :is_a?
+ before :each do
+ @o = KernelSpecs::KindaClass.new
+ end
+
+ it "returns true if given class is the object's class" do
+ @o.is_a?(KernelSpecs::KindaClass).should == true
+ end
+
+ it "returns true if given class is an ancestor of the object's class" do
+ @o.is_a?(KernelSpecs::AncestorClass).should == true
+ @o.is_a?(String).should == true
+ @o.is_a?(Object).should == true
+ end
+
+ it "returns false if the given class is not object's class nor an ancestor" do
+ @o.is_a?(Array).should == false
+ end
+
+ it "returns true if given a Module that is included in object's class" do
+ @o.is_a?(KernelSpecs::MyModule).should == true
+ end
+
+ it "returns true if given a Module that is included one of object's ancestors only" do
+ @o.is_a?(KernelSpecs::AncestorModule).should == true
+ end
+
+ it "returns true if given a Module that object has been extended with" do
+ @o.is_a?(KernelSpecs::MyExtensionModule).should == true
+ end
+
+ it "returns true if given a Module that object has been prepended with" do
+ @o.is_a?(KernelSpecs::MyPrependedModule).should == true
+ end
+
+ it "returns false if given a Module not included nor prepended in object's class nor ancestors" do
+ @o.is_a?(KernelSpecs::SomeOtherModule).should == false
+ end
+
+ it "raises a TypeError if given an object that is not a Class nor a Module" do
+ -> { @o.is_a?(1) }.should.raise(TypeError)
+ -> { @o.is_a?('KindaClass') }.should.raise(TypeError)
+ -> { @o.is_a?(:KindaClass) }.should.raise(TypeError)
+ -> { @o.is_a?(Object.new) }.should.raise(TypeError)
+ end
+
+ it "does not take into account `class` method overriding" do
+ def @o.class; Integer; end
+
+ @o.is_a?(Integer).should == false
+ @o.is_a?(KernelSpecs::KindaClass).should == true
+ end
end
diff --git a/spec/ruby/core/kernel/itself_spec.rb b/spec/ruby/core/kernel/itself_spec.rb
index c906d7c3e8..c1f01fdc5e 100644
--- a/spec/ruby/core/kernel/itself_spec.rb
+++ b/spec/ruby/core/kernel/itself_spec.rb
@@ -4,6 +4,6 @@ require_relative 'fixtures/classes'
describe "Kernel#itself" do
it "returns the receiver itself" do
foo = Object.new
- foo.itself.should equal foo
+ foo.itself.should.equal? foo
end
end
diff --git a/spec/ruby/core/kernel/kind_of_spec.rb b/spec/ruby/core/kernel/kind_of_spec.rb
index c988edccb5..7fcc72543d 100644
--- a/spec/ruby/core/kernel/kind_of_spec.rb
+++ b/spec/ruby/core/kernel/kind_of_spec.rb
@@ -1,6 +1,7 @@
require_relative '../../spec_helper'
-require_relative 'shared/kind_of'
describe "Kernel#kind_of?" do
- it_behaves_like :kernel_kind_of, :kind_of?
+ it "is an alias of Kernel#is_a?" do
+ Kernel.instance_method(:kind_of?).should == Kernel.instance_method(:is_a?)
+ end
end
diff --git a/spec/ruby/core/kernel/lambda_spec.rb b/spec/ruby/core/kernel/lambda_spec.rb
index 565536ac0d..6ab89c2bbb 100644
--- a/spec/ruby/core/kernel/lambda_spec.rb
+++ b/spec/ruby/core/kernel/lambda_spec.rb
@@ -8,92 +8,52 @@ describe "Kernel.lambda" do
it_behaves_like :kernel_lambda, :lambda
it "is a private method" do
- Kernel.should have_private_instance_method(:lambda)
+ Kernel.private_instance_methods(false).should.include?(:lambda)
end
it "creates a lambda-style Proc if given a literal block" do
l = lambda { 42 }
- l.lambda?.should be_true
+ l.lambda?.should == true
end
it "creates a lambda-style Proc if given a literal block via #send" do
l = send(:lambda) { 42 }
- l.lambda?.should be_true
+ l.lambda?.should == true
end
it "creates a lambda-style Proc if given a literal block via #__send__" do
l = __send__(:lambda) { 42 }
- 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
- 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
-
- 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 "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
+ l.lambda?.should == true
end
it "checks the arity of the call when no args are specified" do
l = lambda { :called }
l.call.should == :called
- lambda { l.call(1) }.should raise_error(ArgumentError)
- lambda { l.call(1, 2) }.should raise_error(ArgumentError)
+ lambda { l.call(1) }.should.raise(ArgumentError)
+ lambda { l.call(1, 2) }.should.raise(ArgumentError)
end
it "checks the arity when 1 arg is specified" do
l = lambda { |a| :called }
l.call(1).should == :called
- lambda { l.call }.should raise_error(ArgumentError)
- lambda { l.call(1, 2) }.should raise_error(ArgumentError)
+ lambda { l.call }.should.raise(ArgumentError)
+ lambda { l.call(1, 2) }.should.raise(ArgumentError)
end
it "does not check the arity when passing a Proc with &" do
l = lambda { || :called }
p = proc { || :called }
- lambda { l.call(1) }.should raise_error(ArgumentError)
+ lambda { l.call(1) }.should.raise(ArgumentError)
p.call(1).should == :called
end
it "accepts 0 arguments when used with ||" do
lambda {
lambda { || }.call(1)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
it "strictly checks the arity when 0 or 2..inf args are specified" do
@@ -101,15 +61,15 @@ describe "Kernel.lambda" do
lambda {
l.call
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
lambda {
l.call(1)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
lambda {
l.call(1,2)
- }.should_not raise_error(ArgumentError)
+ }.should_not.raise(ArgumentError)
end
it "returns from the lambda itself, not the creation site of the lambda" do
@@ -119,7 +79,7 @@ describe "Kernel.lambda" do
@reached_end_of_method = true
end
test
- @reached_end_of_method.should be_true
+ @reached_end_of_method.should == true
end
it "allows long returns to flow through it" do
@@ -134,21 +94,13 @@ describe "Kernel.lambda" do
2
end
end
- klass.new.lambda { 42 }.should be_an_instance_of Proc
+ klass.new.lambda { 42 }.should.instance_of? Proc
klass.new.ret.should == 1
end
context "when called without a literal block" do
- ruby_version_is ""..."3.3" 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/)
- end
+ it "raises when proc isn't a lambda" do
+ -> { lambda(&proc{}) }.should.raise(ArgumentError, /the lambda method requires a literal block/)
end
it "doesn't warn when proc is lambda" do
diff --git a/spec/ruby/core/kernel/load_spec.rb b/spec/ruby/core/kernel/load_spec.rb
index a165cc4acd..890aab8c27 100644
--- a/spec/ruby/core/kernel/load_spec.rb
+++ b/spec/ruby/core/kernel/load_spec.rb
@@ -13,7 +13,7 @@ describe "Kernel#load" do
end
it "is a private method" do
- Kernel.should have_private_instance_method(:load)
+ Kernel.private_instance_methods(false).should.include?(:load)
end
it_behaves_like :kernel_require_basic, :load, CodeLoadingSpecs::Method.new
diff --git a/spec/ruby/core/kernel/local_variables_spec.rb b/spec/ruby/core/kernel/local_variables_spec.rb
index f6f1e15f52..40c343f7e4 100644
--- a/spec/ruby/core/kernel/local_variables_spec.rb
+++ b/spec/ruby/core/kernel/local_variables_spec.rb
@@ -7,14 +7,13 @@ describe "Kernel#local_variables" do
end
it "is a private method" do
- Kernel.should have_private_instance_method(:local_variables)
+ Kernel.private_instance_methods(false).should.include?(:local_variables)
end
it "contains locals as they are added" do
a = 1
b = 2
- local_variables.should include(:a, :b)
- local_variables.length.should == 2
+ local_variables.sort.should == [:a, :b]
end
it "is accessible from bindings" do
@@ -25,14 +24,12 @@ describe "Kernel#local_variables" do
end
foo_binding = local_var_foo()
res = eval("local_variables",foo_binding)
- res.should include(:a, :b)
- res.length.should == 2
+ res.sort.should == [:a, :b]
end
it "is accessible in eval" do
eval "a=1; b=2; ScratchPad.record local_variables"
- ScratchPad.recorded.should include(:a, :b)
- ScratchPad.recorded.length.should == 2
+ ScratchPad.recorded.sort.should == [:a, :b]
end
it "includes only unique variable names" do
diff --git a/spec/ruby/core/kernel/loop_spec.rb b/spec/ruby/core/kernel/loop_spec.rb
index 7c76c7d28e..c2976e5cc5 100644
--- a/spec/ruby/core/kernel/loop_spec.rb
+++ b/spec/ruby/core/kernel/loop_spec.rb
@@ -3,7 +3,7 @@ require_relative 'fixtures/classes'
describe "Kernel.loop" do
it "is a private method" do
- Kernel.should have_private_instance_method(:loop)
+ Kernel.private_instance_methods(false).should.include?(:loop)
end
it "calls block until it is terminated by a break" do
@@ -30,7 +30,7 @@ describe "Kernel.loop" do
it "returns an enumerator if no block given" do
enum = loop
- enum.instance_of?(Enumerator).should be_true
+ enum.instance_of?(Enumerator).should == true
cnt = 0
enum.each do |*args|
raise "Args should be empty #{args.inspect}" unless args.empty?
@@ -55,7 +55,7 @@ describe "Kernel.loop" do
end
it "does not rescue other errors" do
- ->{ loop do raise StandardError end }.should raise_error( StandardError )
+ ->{ loop do raise StandardError end }.should.raise( StandardError )
end
it "returns StopIteration#result, the result value of a finished iterator" do
diff --git a/spec/ruby/core/kernel/method_spec.rb b/spec/ruby/core/kernel/method_spec.rb
index 3fc566d6a6..9187b8c7e7 100644
--- a/spec/ruby/core/kernel/method_spec.rb
+++ b/spec/ruby/core/kernel/method_spec.rb
@@ -11,12 +11,12 @@ describe "Kernel#method" do
it "can be called on a private method" do
@obj.send(:private_method).should == :private_method
- @obj.method(:private_method).should be_an_instance_of(Method)
+ @obj.method(:private_method).should.instance_of?(Method)
end
it "can be called on a protected method" do
@obj.send(:protected_method).should == :protected_method
- @obj.method(:protected_method).should be_an_instance_of(Method)
+ @obj.method(:protected_method).should.instance_of?(Method)
end
it "will see an alias of the original method as == when in a derived class" do
@@ -31,7 +31,7 @@ describe "Kernel#method" do
it "can be called even if we only respond_to_missing? method, true" do
m = KernelSpecs::RespondViaMissing.new.method(:handled_privately)
- m.should be_an_instance_of(Method)
+ m.should.instance_of?(Method)
m.call(1, 2, 3).should == "Done handled_privately([1, 2, 3])"
end
@@ -45,7 +45,7 @@ describe "Kernel#method" do
end
end
m = cls.new.method(:foo)
- -> { m.call }.should raise_error(ArgumentError)
+ -> { m.call }.should.raise(ArgumentError)
cls = Class.new do
def respond_to_missing?(name, *)
@@ -67,14 +67,22 @@ describe "Kernel#method" do
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)
+ -> { Object.method(nil) }.should.raise(TypeError)
+ -> { Object.method([]) }.should.raise(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)
+ -> { Object.method(name) }.should.raise(NoMethodError)
+
+ name = mock("method-name")
+ name.should_receive(:to_str).and_raise(NoMethodError)
+ begin
+ raise RuntimeError.new
+ rescue => cause
+ -> { Object.method(name) }.should.raise(NoMethodError, cause:)
+ end
end
end
end
diff --git a/spec/ruby/core/kernel/methods_spec.rb b/spec/ruby/core/kernel/methods_spec.rb
index fb7a7e8be9..cfa22aa05a 100644
--- a/spec/ruby/core/kernel/methods_spec.rb
+++ b/spec/ruby/core/kernel/methods_spec.rb
@@ -5,67 +5,67 @@ require_relative '../../fixtures/reflection'
# TODO: rewrite
describe "Kernel#methods" do
it "returns singleton methods defined by obj.meth" do
- KernelSpecs::Methods.methods(false).should include(:ichi)
+ KernelSpecs::Methods.methods(false).should.include?(:ichi)
end
it "returns singleton methods defined in 'class << self'" do
- KernelSpecs::Methods.methods(false).should include(:san)
+ KernelSpecs::Methods.methods(false).should.include?(:san)
end
it "returns private singleton methods defined by obj.meth" do
- KernelSpecs::Methods.methods(false).should include(:shi)
+ KernelSpecs::Methods.methods(false).should.include?(:shi)
end
it "returns singleton methods defined in 'class << self' when it follows 'private'" do
- KernelSpecs::Methods.methods(false).should include(:roku)
+ KernelSpecs::Methods.methods(false).should.include?(:roku)
end
it "does not return private singleton methods defined in 'class << self'" do
- KernelSpecs::Methods.methods(false).should_not include(:shichi)
+ KernelSpecs::Methods.methods(false).should_not.include?(:shichi)
end
it "returns the publicly accessible methods of the object" do
meths = KernelSpecs::Methods.methods(false)
- meths.should include(:hachi, :ichi, :juu, :juu_ichi,
- :juu_ni, :roku, :san, :shi)
+ meths.to_set.should >= Set[:hachi, :ichi, :juu, :juu_ichi,
+ :juu_ni, :roku, :san, :shi]
KernelSpecs::Methods.new.methods(false).should == []
end
it "returns the publicly accessible methods in the object, its ancestors and mixed-in modules" do
meths = KernelSpecs::Methods.methods(false) & KernelSpecs::Methods.methods
- meths.should include(:hachi, :ichi, :juu, :juu_ichi,
- :juu_ni, :roku, :san, :shi)
+ meths.to_set.should >= Set[:hachi, :ichi, :juu, :juu_ichi,
+ :juu_ni, :roku, :san, :shi]
- KernelSpecs::Methods.new.methods.should include(:ku, :ni, :juu_san)
+ KernelSpecs::Methods.new.methods.to_set.should >= Set[:ku, :ni, :juu_san]
end
it "returns methods added to the metaclass through extend" do
meth = KernelSpecs::Methods.new
- meth.methods.should_not include(:peekaboo)
+ meth.methods.should_not.include?(:peekaboo)
meth.extend(KernelSpecs::Methods::MetaclassMethods)
- meth.methods.should include(:peekaboo)
+ meth.methods.should.include?(:peekaboo)
end
it "does not return undefined singleton methods defined by obj.meth" do
o = KernelSpecs::Child.new
def o.single; end
- o.methods.should include(:single)
+ o.methods.should.include?(:single)
class << o; self; end.send :undef_method, :single
- o.methods.should_not include(:single)
+ o.methods.should_not.include?(:single)
end
it "does not return superclass methods undefined in the object's class" do
- KernelSpecs::Child.new.methods.should_not include(:parent_method)
+ KernelSpecs::Child.new.methods.should_not.include?(:parent_method)
end
it "does not return superclass methods undefined in a superclass" do
- KernelSpecs::Grandchild.new.methods.should_not include(:parent_method)
+ KernelSpecs::Grandchild.new.methods.should_not.include?(:parent_method)
end
it "does not return included module methods undefined in the object's class" do
- KernelSpecs::Grandchild.new.methods.should_not include(:parent_mixin_method)
+ KernelSpecs::Grandchild.new.methods.should_not.include?(:parent_mixin_method)
end
end
diff --git a/spec/ruby/core/kernel/not_match_spec.rb b/spec/ruby/core/kernel/not_match_spec.rb
index 082e56fed7..4ed7ea7b42 100644
--- a/spec/ruby/core/kernel/not_match_spec.rb
+++ b/spec/ruby/core/kernel/not_match_spec.rb
@@ -15,7 +15,7 @@ describe "Kernel#!~" do
end
it "raises NoMethodError if self does not respond to #=~" do
- -> { Object.new !~ :foo }.should raise_error(NoMethodError)
+ -> { Object.new !~ :foo }.should.raise(NoMethodError)
end
it 'can be overridden in subclasses' do
diff --git a/spec/ruby/core/kernel/open_spec.rb b/spec/ruby/core/kernel/open_spec.rb
index 6d00af395d..14a3c43cad 100644
--- a/spec/ruby/core/kernel/open_spec.rb
+++ b/spec/ruby/core/kernel/open_spec.rb
@@ -15,70 +15,70 @@ describe "Kernel#open" do
end
it "is a private method" do
- Kernel.should have_private_instance_method(:open)
+ Kernel.private_instance_methods(false).should.include?(:open)
end
it "opens a file when given a valid filename" do
@file = open(@name)
- @file.should be_kind_of(File)
+ @file.should.is_a?(File)
end
it "opens a file when called with a block" do
open(@name, "r") { |f| f.gets }.should == @content
end
- 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")
+ ruby_version_is ""..."4.0" 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
+ begin
+ @io.should.is_a?(IO)
+ @io.read
+ ensure
+ @io.close
+ end
end
- begin
- @io.should be_kind_of(IO)
- @io.read
- ensure
- @io.close
- end
- 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 }
+ 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.should_not == ''
end
- @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(".")
+ 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
end
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")
+ 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
+ begin
+ @io.should.is_a?(IO)
+ @io.read
+ ensure
+ @io.close
+ end
end
- begin
- @io.should be_kind_of(IO)
- @io.read
- ensure
- @io.close
- end
- 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 }
+ 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.should_not == ''
end
- @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"
@@ -89,16 +89,16 @@ describe "Kernel#open" do
end
it "raises an ArgumentError if not passed one argument" do
- -> { open }.should raise_error(ArgumentError)
+ -> { open }.should.raise(ArgumentError)
end
it "accepts options as keyword arguments" do
@file = open(@name, "r", 0666, flags: File::CREAT)
- @file.should be_kind_of(File)
+ @file.should.is_a?(File)
-> {
open(@name, "r", 0666, {flags: File::CREAT})
- }.should raise_error(ArgumentError, "wrong number of arguments (given 4, expected 1..3)")
+ }.should.raise(ArgumentError, "wrong number of arguments (given 4, expected 1..3)")
end
describe "when given an object that responds to to_open" do
@@ -126,7 +126,7 @@ describe "Kernel#open" do
@file = File.open(@name)
obj.should_receive(:to_open).and_return(@file)
@file = open(obj)
- @file.should be_kind_of(File)
+ @file.should.is_a?(File)
end
it "returns the value from #to_open" do
@@ -167,9 +167,9 @@ describe "Kernel#open" do
it "raises a TypeError if passed a non-String that does not respond to #to_open" do
obj = mock('non-fileish')
- -> { open(obj) }.should raise_error(TypeError)
- -> { open(nil) }.should raise_error(TypeError)
- -> { open(7) }.should raise_error(TypeError)
+ -> { open(obj) }.should.raise(TypeError)
+ -> { open(nil) }.should.raise(TypeError)
+ -> { open(7) }.should.raise(TypeError)
end
it "accepts nil for mode and permission" do
diff --git a/spec/ruby/core/kernel/p_spec.rb b/spec/ruby/core/kernel/p_spec.rb
index eae191aa54..f89716899a 100644
--- a/spec/ruby/core/kernel/p_spec.rb
+++ b/spec/ruby/core/kernel/p_spec.rb
@@ -13,7 +13,7 @@ describe "Kernel#p" do
end
it "is a private method" do
- Kernel.should have_private_instance_method(:p)
+ Kernel.private_instance_methods(false).should.include?(:p)
end
# TODO: fix
diff --git a/spec/ruby/core/kernel/print_spec.rb b/spec/ruby/core/kernel/print_spec.rb
index 7e7c9b822d..5473d22f71 100644
--- a/spec/ruby/core/kernel/print_spec.rb
+++ b/spec/ruby/core/kernel/print_spec.rb
@@ -3,7 +3,7 @@ require_relative 'fixtures/classes'
describe "Kernel#print" do
it "is a private method" do
- Kernel.should have_private_instance_method(:print)
+ Kernel.private_instance_methods(false).should.include?(:print)
end
it "delegates to $stdout" do
diff --git a/spec/ruby/core/kernel/printf_spec.rb b/spec/ruby/core/kernel/printf_spec.rb
index 61bf955c25..50939b3794 100644
--- a/spec/ruby/core/kernel/printf_spec.rb
+++ b/spec/ruby/core/kernel/printf_spec.rb
@@ -4,7 +4,7 @@ require_relative 'shared/sprintf'
describe "Kernel#printf" do
it "is a private method" do
- Kernel.should have_private_instance_method(:printf)
+ Kernel.private_instance_methods(false).should.include?(:printf)
end
end
diff --git a/spec/ruby/core/kernel/private_methods_spec.rb b/spec/ruby/core/kernel/private_methods_spec.rb
index 041634d1e5..b0e6d042a9 100644
--- a/spec/ruby/core/kernel/private_methods_spec.rb
+++ b/spec/ruby/core/kernel/private_methods_spec.rb
@@ -6,23 +6,23 @@ require_relative '../../fixtures/reflection'
describe "Kernel#private_methods" do
it "returns a list of the names of privately accessible methods in the object" do
m = KernelSpecs::Methods.private_methods(false)
- m.should include(:shichi)
+ m.should.include?(:shichi)
m = KernelSpecs::Methods.new.private_methods(false)
- m.should include(:juu_shi)
+ m.should.include?(:juu_shi)
end
it "returns a list of the names of privately accessible methods in the object and its ancestors and mixed-in modules" do
m = (KernelSpecs::Methods.private_methods(false) & KernelSpecs::Methods.private_methods)
- m.should include(:shichi)
+ m.should.include?(:shichi)
m = KernelSpecs::Methods.new.private_methods
- m.should include(:juu_shi)
+ m.should.include?(:juu_shi)
end
it "returns private methods mixed in to the metaclass" do
m = KernelSpecs::Methods.new
m.extend(KernelSpecs::Methods::MetaclassMethods)
- m.private_methods.should include(:shoo)
+ m.private_methods.should.include?(:shoo)
end
end
diff --git a/spec/ruby/core/kernel/proc_spec.rb b/spec/ruby/core/kernel/proc_spec.rb
index 6553b8fd04..1ba662177b 100644
--- a/spec/ruby/core/kernel/proc_spec.rb
+++ b/spec/ruby/core/kernel/proc_spec.rb
@@ -6,20 +6,20 @@ require_relative 'shared/lambda'
describe "Kernel.proc" do
it "is a private method" do
- Kernel.should have_private_instance_method(:proc)
+ Kernel.private_instance_methods(false).should.include?(:proc)
end
it "creates a proc-style Proc if given a literal block" do
l = proc { 42 }
- l.lambda?.should be_false
+ l.lambda?.should == false
end
it "returned the passed Proc if given an existing Proc" do
some_lambda = -> {}
- some_lambda.lambda?.should be_true
+ some_lambda.lambda?.should == true
l = proc(&some_lambda)
- l.should equal(some_lambda)
- l.lambda?.should be_true
+ l.should.equal?(some_lambda)
+ l.lambda?.should == true
end
it_behaves_like :kernel_lambda, :proc
@@ -31,7 +31,7 @@ describe "Kernel.proc" do
@reached_end_of_method = true
end
test
- @reached_end_of_method.should be_nil
+ @reached_end_of_method.should == nil
end
end
@@ -43,6 +43,6 @@ describe "Kernel#proc" 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')
+ }.should.raise(ArgumentError, 'tried to create Proc object without a block')
end
end
diff --git a/spec/ruby/core/kernel/protected_methods_spec.rb b/spec/ruby/core/kernel/protected_methods_spec.rb
index d3334e886b..aecb9f5ffb 100644
--- a/spec/ruby/core/kernel/protected_methods_spec.rb
+++ b/spec/ruby/core/kernel/protected_methods_spec.rb
@@ -8,21 +8,21 @@ require_relative '../../fixtures/reflection'
# You should use have_protected_method() with the exception of this spec.
describe "Kernel#protected_methods" do
it "returns a list of the names of protected methods accessible in the object" do
- KernelSpecs::Methods.protected_methods(false).sort.should include(:juu_ichi)
- KernelSpecs::Methods.new.protected_methods(false).should include(:ku)
+ KernelSpecs::Methods.protected_methods(false).sort.should.include?(:juu_ichi)
+ KernelSpecs::Methods.new.protected_methods(false).should.include?(:ku)
end
it "returns a list of the names of protected methods accessible in the object and from its ancestors and mixed-in modules" do
l1 = KernelSpecs::Methods.protected_methods(false)
l2 = KernelSpecs::Methods.protected_methods
- (l1 & l2).should include(:juu_ichi)
- KernelSpecs::Methods.new.protected_methods.should include(:ku)
+ (l1 & l2).should.include?(:juu_ichi)
+ KernelSpecs::Methods.new.protected_methods.should.include?(:ku)
end
it "returns methods mixed in to the metaclass" do
m = KernelSpecs::Methods.new
m.extend(KernelSpecs::Methods::MetaclassMethods)
- m.protected_methods.should include(:nopeeking)
+ m.protected_methods.should.include?(:nopeeking)
end
end
diff --git a/spec/ruby/core/kernel/public_method_spec.rb b/spec/ruby/core/kernel/public_method_spec.rb
index c5d54c777e..42b8f797d3 100644
--- a/spec/ruby/core/kernel/public_method_spec.rb
+++ b/spec/ruby/core/kernel/public_method_spec.rb
@@ -13,20 +13,20 @@ describe "Kernel#public_method" do
@obj.send(:private_method).should == :private_method
-> do
@obj.public_method(:private_method)
- end.should raise_error(NameError)
+ end.should.raise(NameError)
end
it "raises a NameError when called on a protected method" do
@obj.send(:protected_method).should == :protected_method
-> {
@obj.public_method(:protected_method)
- }.should raise_error(NameError)
+ }.should.raise(NameError)
end
it "raises a NameError if we only repond_to_missing? method, true" do
obj = KernelSpecs::RespondViaMissing.new
-> do
obj.public_method(:handled_privately)
- end.should raise_error(NameError)
+ end.should.raise(NameError)
end
end
diff --git a/spec/ruby/core/kernel/public_methods_spec.rb b/spec/ruby/core/kernel/public_methods_spec.rb
index a5512784fb..e334ac9a55 100644
--- a/spec/ruby/core/kernel/public_methods_spec.rb
+++ b/spec/ruby/core/kernel/public_methods_spec.rb
@@ -5,31 +5,30 @@ require_relative '../../fixtures/reflection'
# TODO: rewrite
describe "Kernel#public_methods" do
it "returns a list of the names of publicly accessible methods in the object" do
- KernelSpecs::Methods.public_methods(false).sort.should include(:hachi,
- :ichi, :juu, :juu_ni, :roku, :san, :shi)
- KernelSpecs::Methods.new.public_methods(false).sort.should include(:juu_san, :ni)
+ KernelSpecs::Methods.public_methods(false).to_set.should >= Set[:hachi, :ichi, :juu, :juu_ni, :roku, :san, :shi]
+ KernelSpecs::Methods.new.public_methods(false).to_set.should >= Set[:juu_san, :ni]
end
it "returns a list of names without protected accessible methods in the object" do
- KernelSpecs::Methods.public_methods(false).sort.should_not include(:juu_ichi)
- KernelSpecs::Methods.new.public_methods(false).sort.should_not include(:ku)
+ KernelSpecs::Methods.public_methods(false).sort.should_not.include?(:juu_ichi)
+ KernelSpecs::Methods.new.public_methods(false).sort.should_not.include?(:ku)
end
it "returns a list of the names of publicly accessible methods in the object and its ancestors and mixed-in modules" do
- (KernelSpecs::Methods.public_methods(false) & KernelSpecs::Methods.public_methods).sort.should include(
- :hachi, :ichi, :juu, :juu_ni, :roku, :san, :shi)
+ (KernelSpecs::Methods.public_methods(false) & KernelSpecs::Methods.public_methods).to_set.should >= Set[
+ :hachi, :ichi, :juu, :juu_ni, :roku, :san, :shi]
m = KernelSpecs::Methods.new.public_methods
- m.should include(:ni, :juu_san)
+ m.to_set.should >= Set[:ni, :juu_san]
end
it "returns methods mixed in to the metaclass" do
m = KernelSpecs::Methods.new
m.extend(KernelSpecs::Methods::MetaclassMethods)
- m.public_methods.should include(:peekaboo)
+ m.public_methods.should.include?(:peekaboo)
end
it "returns public methods for immediates" do
- 10.public_methods.should include(:divmod)
+ 10.public_methods.should.include?(:divmod)
end
end
diff --git a/spec/ruby/core/kernel/public_send_spec.rb b/spec/ruby/core/kernel/public_send_spec.rb
index b684b1729c..6a4a969c77 100644
--- a/spec/ruby/core/kernel/public_send_spec.rb
+++ b/spec/ruby/core/kernel/public_send_spec.rb
@@ -29,7 +29,7 @@ describe "Kernel#public_send" do
'done'
end
end
- -> { KernelSpecs::Foo.new.public_send(:bar)}.should raise_error(NoMethodError)
+ -> { KernelSpecs::Foo.new.public_send(:bar)}.should.raise(NoMethodError)
end
it "raises a NoMethodError if the named method is private" do
@@ -41,7 +41,7 @@ describe "Kernel#public_send" do
end
-> {
KernelSpecs::Foo.new.public_send(:bar)
- }.should raise_error(NoMethodError)
+ }.should.raise(NoMethodError)
end
context 'called from own public method' do
@@ -70,11 +70,11 @@ describe "Kernel#public_send" do
end
it "raises a NoMethodError if the method is protected" do
- -> { @receiver.call_protected_method }.should raise_error(NoMethodError)
+ -> { @receiver.call_protected_method }.should.raise(NoMethodError)
end
it "raises a NoMethodError if the method is private" do
- -> { @receiver.call_private_method }.should raise_error(NoMethodError)
+ -> { @receiver.call_private_method }.should.raise(NoMethodError)
end
end
@@ -88,7 +88,7 @@ describe "Kernel#public_send" do
end
-> {
KernelSpecs::Foo.new.public_send(:aka)
- }.should raise_error(NoMethodError)
+ }.should.raise(NoMethodError)
end
it "raises a NoMethodError if the named method is an alias of a protected method" do
@@ -101,15 +101,15 @@ describe "Kernel#public_send" do
end
-> {
KernelSpecs::Foo.new.public_send(:aka)
- }.should raise_error(NoMethodError)
+ }.should.raise(NoMethodError)
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(ArgumentError) { |e| e.backtrace[0].should =~ /[`'](?:Kernel#)?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(TypeError) { |e| e.backtrace[0].should =~ /[`'](?:Kernel#)?public_send'/ }
end
it_behaves_like :basicobject_send, :public_send
diff --git a/spec/ruby/core/kernel/putc_spec.rb b/spec/ruby/core/kernel/putc_spec.rb
index 74bd3765db..e6a20a9af1 100644
--- a/spec/ruby/core/kernel/putc_spec.rb
+++ b/spec/ruby/core/kernel/putc_spec.rb
@@ -4,7 +4,7 @@ require_relative '../../shared/io/putc'
describe "Kernel#putc" do
it "is a private instance method" do
- Kernel.should have_private_instance_method(:putc)
+ Kernel.private_instance_methods(false).should.include?(:putc)
end
end
diff --git a/spec/ruby/core/kernel/puts_spec.rb b/spec/ruby/core/kernel/puts_spec.rb
index 6eb38e8fcf..eed18fcd50 100644
--- a/spec/ruby/core/kernel/puts_spec.rb
+++ b/spec/ruby/core/kernel/puts_spec.rb
@@ -15,7 +15,7 @@ describe "Kernel#puts" do
end
it "is a private method" do
- Kernel.should have_private_instance_method(:puts)
+ Kernel.private_instance_methods(false).should.include?(:puts)
end
it "delegates to $stdout.puts" do
diff --git a/spec/ruby/core/kernel/raise_spec.rb b/spec/ruby/core/kernel/raise_spec.rb
index a4ab963fa3..6162677e17 100644
--- a/spec/ruby/core/kernel/raise_spec.rb
+++ b/spec/ruby/core/kernel/raise_spec.rb
@@ -4,9 +4,19 @@ require_relative '../../shared/kernel/raise'
describe "Kernel#raise" do
it "is a private method" do
- Kernel.should have_private_instance_method(:raise)
+ Kernel.private_instance_methods.should.include?(:raise)
end
+ # Shared specs expect a public #raise method.
+ public_raiser = Object.new
+ class << public_raiser
+ public :raise
+ end
+ it_behaves_like :kernel_raise, :raise, public_raiser
+ it_behaves_like :kernel_raise_with_cause, :raise, public_raiser
+end
+
+describe "Kernel#raise with previously rescued exception" do
it "re-raises the previously rescued exception if no exception is specified" do
ScratchPad.record nil
@@ -23,90 +33,9 @@ describe "Kernel#raise" do
raise
ScratchPad.record :no_reraise
end
- end.should raise_error(Exception, "outer")
-
- ScratchPad.recorded.should be_nil
- end
-
- it "accepts a cause keyword argument that sets the cause" do
- cause = StandardError.new
- -> { raise("error", cause: cause) }.should raise_error(RuntimeError) { |e| e.cause.should == cause }
- end
-
- it "accepts a cause keyword argument that overrides the last exception" do
- begin
- raise "first raise"
- rescue => ignored
- cause = StandardError.new
- -> { raise("error", cause: cause) }.should raise_error(RuntimeError) { |e| e.cause.should == cause }
- end
- end
-
- it "raises an ArgumentError when only cause is given" do
- cause = StandardError.new
- -> { raise(cause: cause) }.should raise_error(ArgumentError, "only cause is given with no arguments")
- end
-
- it "raises an ArgumentError when only cause is given even if it has nil value" do
- -> { raise(cause: nil) }.should raise_error(ArgumentError, "only cause is given with no arguments")
- end
-
- it "raises an ArgumentError when given cause is not an instance of Exception" do
- -> { raise "message", cause: Object.new }.should raise_error(TypeError, "exception object expected")
- end
-
- it "doesn't raise an ArgumentError when given cause is nil" do
- -> { raise "message", cause: nil }.should raise_error(RuntimeError, "message")
- end
-
- it "allows cause equal an exception" do
- e = RuntimeError.new("message")
- -> { raise e, cause: e }.should raise_error(e)
- end
+ end.should.raise(Exception, "outer")
- it "doesn't set given cause when it equals an exception" do
- e = RuntimeError.new("message")
-
- begin
- raise e, cause: e
- rescue
- end
-
- e.cause.should == nil
- end
-
- it "raises ArgumentError when exception is part of the cause chain" do
- -> {
- begin
- raise "Error 1"
- rescue => e1
- begin
- raise "Error 2"
- rescue => e2
- begin
- raise "Error 3"
- rescue => e3
- raise e1, cause: e3
- end
- end
- end
- }.should raise_error(ArgumentError, "circular causes")
- end
-
- it "re-raises a rescued exception" do
- -> do
- begin
- raise StandardError, "aaa"
- rescue Exception
- begin
- raise ArgumentError
- rescue ArgumentError
- end
-
- # should raise StandardError "aaa"
- raise
- end
- end.should raise_error(StandardError, "aaa")
+ ScratchPad.recorded.should == nil
end
it "re-raises a previously rescued exception without overwriting the cause" do
@@ -283,10 +212,11 @@ describe "Kernel#raise" do
end
end
-describe "Kernel#raise" do
- it_behaves_like :kernel_raise, :raise, Kernel
-end
-
describe "Kernel.raise" do
- it "needs to be reviewed for spec completeness"
+ it "is a public method" do
+ Kernel.singleton_class.should.public_method_defined?(:raise)
+ end
+
+ it_behaves_like :kernel_raise, :raise, Kernel
+ it_behaves_like :kernel_raise_with_cause, :raise, Kernel
end
diff --git a/spec/ruby/core/kernel/rand_spec.rb b/spec/ruby/core/kernel/rand_spec.rb
index 355e425792..1bf5e225d9 100644
--- a/spec/ruby/core/kernel/rand_spec.rb
+++ b/spec/ruby/core/kernel/rand_spec.rb
@@ -3,42 +3,42 @@ require_relative 'fixtures/classes'
describe "Kernel#rand" do
it "is a private method" do
- Kernel.should have_private_instance_method(:rand)
+ Kernel.private_instance_methods(false).should.include?(:rand)
end
it "returns a float if no argument is passed" do
- rand.should be_kind_of(Float)
+ rand.should.is_a?(Float)
end
it "returns an integer for an integer argument" do
- rand(77).should be_kind_of(Integer)
+ rand(77).should.is_a?(Integer)
end
it "returns an integer for a float argument greater than 1" do
- rand(1.3).should be_kind_of(Integer)
+ rand(1.3).should.is_a?(Integer)
end
it "returns a float for an argument between -1 and 1" do
- rand(-0.999).should be_kind_of(Float)
- rand(-0.01).should be_kind_of(Float)
- rand(0).should be_kind_of(Float)
- rand(0.01).should be_kind_of(Float)
- rand(0.999).should be_kind_of(Float)
+ rand(-0.999).should.is_a?(Float)
+ rand(-0.01).should.is_a?(Float)
+ rand(0).should.is_a?(Float)
+ rand(0.01).should.is_a?(Float)
+ rand(0.999).should.is_a?(Float)
end
it "ignores the sign of the argument" do
- [0, 1, 2, 3].should include(rand(-4))
+ [0, 1, 2, 3].should.include?(rand(-4))
end
it "never returns a value greater or equal to 1.0 with no arguments" do
1000.times do
- (0...1.0).should include(rand)
+ (0...1.0).should.include?(rand)
end
end
it "never returns a value greater or equal to any passed in max argument" do
1000.times do
- (0...100).to_a.should include(rand(100))
+ (0...100).to_a.should.include?(rand(100))
end
end
@@ -53,32 +53,32 @@ describe "Kernel#rand" do
it "returns an Integer between the two Integers" do
1000.times do
x = rand(4...6)
- x.should be_kind_of(Integer)
- (4...6).should include(x)
+ x.should.is_a?(Integer)
+ (4...6).should.include?(x)
end
end
it "returns a Float between the given Integer and Float" do
1000.times do
x = rand(4...6.5)
- x.should be_kind_of(Float)
- (4...6.5).should include(x)
+ x.should.is_a?(Float)
+ (4...6.5).should.include?(x)
end
end
it "returns a Float between the given Float and Integer" do
1000.times do
x = rand(3.5...6)
- x.should be_kind_of(Float)
- (3.5...6).should include(x)
+ x.should.is_a?(Float)
+ (3.5...6).should.include?(x)
end
end
it "returns a Float between the two given Floats" do
1000.times do
x = rand(3.5...6.5)
- x.should be_kind_of(Float)
- (3.5...6.5).should include(x)
+ x.should.is_a?(Float)
+ (3.5...6.5).should.include?(x)
end
end
end
@@ -87,32 +87,32 @@ describe "Kernel#rand" do
it "returns an Integer between the two Integers" do
1000.times do
x = rand(4..6)
- x.should be_kind_of(Integer)
- (4..6).should include(x)
+ x.should.is_a?(Integer)
+ (4..6).should.include?(x)
end
end
it "returns a Float between the given Integer and Float" do
1000.times do
x = rand(4..6.5)
- x.should be_kind_of(Float)
- (4..6.5).should include(x)
+ x.should.is_a?(Float)
+ (4..6.5).should.include?(x)
end
end
it "returns a Float between the given Float and Integer" do
1000.times do
x = rand(3.5..6)
- x.should be_kind_of(Float)
- (3.5..6).should include(x)
+ x.should.is_a?(Float)
+ (3.5..6).should.include?(x)
end
end
it "returns a Float between the two given Floats" do
1000.times do
x = rand(3.5..6.5)
- x.should be_kind_of(Float)
- (3.5..6.5).should include(x)
+ x.should.is_a?(Float)
+ (3.5..6.5).should.include?(x)
end
end
end
@@ -120,8 +120,8 @@ describe "Kernel#rand" do
context "given an inclusive range between 0 and 1" do
it "returns an Integer between the two Integers" do
x = rand(0..1)
- x.should be_kind_of(Integer)
- (0..1).should include(x)
+ x.should.is_a?(Integer)
+ (0..1).should.include?(x)
end
it "returns a Float if at least one side is Float" do
@@ -130,19 +130,19 @@ describe "Kernel#rand" do
x2 = Random.new(seed).rand(0.0..1.0)
x3 = Random.new(seed).rand(0.0..1)
- x3.should be_kind_of(Float)
- x1.should eql(x3)
- x2.should eql(x3)
+ x3.should.is_a?(Float)
+ x1.should.eql?(x3)
+ x2.should.eql?(x3)
- (0.0..1.0).should include(x3)
+ (0.0..1.0).should.include?(x3)
end
end
context "given an exclusive range between 0 and 1" do
it "returns zero as an Integer" do
x = rand(0...1)
- x.should be_kind_of(Integer)
- x.should eql(0)
+ x.should.is_a?(Integer)
+ x.should.eql?(0)
end
it "returns a Float if at least one side is Float" do
@@ -151,34 +151,34 @@ describe "Kernel#rand" do
x2 = Random.new(seed).rand(0.0...1.0)
x3 = Random.new(seed).rand(0.0...1)
- x3.should be_kind_of(Float)
- x1.should eql(x3)
- x2.should eql(x3)
+ x3.should.is_a?(Float)
+ x1.should.eql?(x3)
+ x2.should.eql?(x3)
- (0.0...1.0).should include(x3)
+ (0.0...1.0).should.include?(x3)
end
end
it "returns a numeric for an range argument where max is < 1" do
- rand(0.25..0.75).should be_kind_of(Numeric)
+ rand(0.25..0.75).should.is_a?(Numeric)
end
it "returns nil when range is backwards" do
- rand(1..0).should be_nil
+ rand(1..0).should == nil
end
it "returns the range start/end when Float range is 0" do
- rand(1.0..1.0).should eql(1.0)
+ rand(1.0..1.0).should.eql?(1.0)
end
it "returns the range start/end when Integer range is 0" do
- rand(42..42).should eql(42)
+ rand(42..42).should.eql?(42)
end
it "supports custom object types" do
- rand(KernelSpecs::CustomRangeInteger.new(1)..KernelSpecs::CustomRangeInteger.new(42)).should be_an_instance_of(KernelSpecs::CustomRangeInteger)
- rand(KernelSpecs::CustomRangeFloat.new(1.0)..KernelSpecs::CustomRangeFloat.new(42.0)).should be_an_instance_of(KernelSpecs::CustomRangeFloat)
- rand(Time.now..Time.now).should be_an_instance_of(Time)
+ rand(KernelSpecs::CustomRangeInteger.new(1)..KernelSpecs::CustomRangeInteger.new(42)).should.instance_of?(KernelSpecs::CustomRangeInteger)
+ rand(KernelSpecs::CustomRangeFloat.new(1.0)..KernelSpecs::CustomRangeFloat.new(42.0)).should.instance_of?(KernelSpecs::CustomRangeFloat)
+ rand(Time.now..Time.now).should.instance_of?(Time)
end
it "is random on boot" do
diff --git a/spec/ruby/core/kernel/readline_spec.rb b/spec/ruby/core/kernel/readline_spec.rb
index dce7b03dc8..86899d78d2 100644
--- a/spec/ruby/core/kernel/readline_spec.rb
+++ b/spec/ruby/core/kernel/readline_spec.rb
@@ -3,7 +3,7 @@ require_relative 'fixtures/classes'
describe "Kernel#readline" do
it "is a private method" do
- Kernel.should have_private_instance_method(:readline)
+ Kernel.private_instance_methods(false).should.include?(:readline)
end
end
diff --git a/spec/ruby/core/kernel/readlines_spec.rb b/spec/ruby/core/kernel/readlines_spec.rb
index 2b6d65fff2..c758014aab 100644
--- a/spec/ruby/core/kernel/readlines_spec.rb
+++ b/spec/ruby/core/kernel/readlines_spec.rb
@@ -3,7 +3,7 @@ require_relative 'fixtures/classes'
describe "Kernel#readlines" do
it "is a private method" do
- Kernel.should have_private_instance_method(:readlines)
+ Kernel.private_instance_methods(false).should.include?(:readlines)
end
end
diff --git a/spec/ruby/core/kernel/remove_instance_variable_spec.rb b/spec/ruby/core/kernel/remove_instance_variable_spec.rb
index 4e5ba5e018..114536064f 100644
--- a/spec/ruby/core/kernel/remove_instance_variable_spec.rb
+++ b/spec/ruby/core/kernel/remove_instance_variable_spec.rb
@@ -9,7 +9,7 @@ describe :kernel_remove_instance_variable, shared: true do
it "removes the instance variable" do
@instance.send :remove_instance_variable, @object
- @instance.instance_variable_defined?(@object).should be_false
+ @instance.instance_variable_defined?(@object).should == false
end
end
@@ -19,39 +19,39 @@ describe "Kernel#remove_instance_variable" do
end
it "is a public method" do
- Kernel.should have_public_instance_method(:remove_instance_variable, false)
+ Kernel.public_instance_methods(false).should.include?(:remove_instance_variable)
end
it "raises a NameError if the instance variable is not defined" do
-> do
@instance.send :remove_instance_variable, :@unknown
- end.should raise_error(NameError)
+ end.should.raise(NameError)
end
it "raises a NameError if the argument is not a valid instance variable name" do
-> do
@instance.send :remove_instance_variable, :"@0"
- end.should raise_error(NameError)
+ end.should.raise(NameError)
end
it "raises a TypeError if passed an Object not defining #to_str" do
-> do
obj = mock("kernel remove_instance_variable")
@instance.send :remove_instance_variable, obj
- end.should raise_error(TypeError)
+ end.should.raise(TypeError)
end
it "raises a FrozenError if self is frozen" do
o = Object.new
o.freeze
- -> { o.remove_instance_variable(:@foo) }.should raise_error(FrozenError)
- -> { o.remove_instance_variable(:foo) }.should raise_error(NameError)
+ -> { o.remove_instance_variable(:@foo) }.should.raise(FrozenError)
+ -> { o.remove_instance_variable(:foo) }.should.raise(NameError)
end
it "raises for frozen objects" do
- -> { nil.remove_instance_variable(:@foo) }.should raise_error(FrozenError)
- -> { nil.remove_instance_variable(:foo) }.should raise_error(NameError)
- -> { :foo.remove_instance_variable(:@foo) }.should raise_error(FrozenError)
+ -> { nil.remove_instance_variable(:@foo) }.should.raise(FrozenError)
+ -> { nil.remove_instance_variable(:foo) }.should.raise(NameError)
+ -> { :foo.remove_instance_variable(:@foo) }.should.raise(FrozenError)
end
describe "when passed a String" do
diff --git a/spec/ruby/core/kernel/require_relative_spec.rb b/spec/ruby/core/kernel/require_relative_spec.rb
index 6188d13a4e..b3ac1fc64c 100644
--- a/spec/ruby/core/kernel/require_relative_spec.rb
+++ b/spec/ruby/core/kernel/require_relative_spec.rb
@@ -27,14 +27,14 @@ describe "Kernel#require_relative with a relative path" do
end
it "loads a path relative to current file" do
- require_relative(@link).should be_true
+ require_relative(@link).should == true
ScratchPad.recorded.should == [:loaded]
end
end
end
it "loads a path relative to the current file" do
- require_relative(@path).should be_true
+ require_relative(@path).should == true
ScratchPad.recorded.should == [:loaded]
end
@@ -42,14 +42,14 @@ describe "Kernel#require_relative with a relative path" do
it "synthetic file base name loads a file base name relative to the working directory" do
Dir.chdir @abs_dir do
- Object.new.instance_eval("require_relative(#{File.basename(@path).inspect})", "foo.rb").should be_true
+ Object.new.instance_eval("require_relative(#{File.basename(@path).inspect})", "foo.rb").should == true
end
ScratchPad.recorded.should == [:loaded]
end
it "synthetic file path loads a relative path relative to the working directory plus the directory of the synthetic path" do
Dir.chdir @abs_dir do
- Object.new.instance_eval("require_relative(File.join('..', #{File.basename(@path).inspect}))", "bar/foo.rb").should be_true
+ Object.new.instance_eval("require_relative(File.join('..', #{File.basename(@path).inspect}))", "bar/foo.rb").should == true
end
ScratchPad.recorded.should == [:loaded]
end
@@ -57,14 +57,14 @@ describe "Kernel#require_relative with a relative path" do
platform_is_not :windows do
it "synthetic relative file path with a Windows path separator specified loads a relative path relative to the working directory" do
Dir.chdir @abs_dir do
- Object.new.instance_eval("require_relative(#{File.basename(@path).inspect})", "bar\\foo.rb").should be_true
+ Object.new.instance_eval("require_relative(#{File.basename(@path).inspect})", "bar\\foo.rb").should == true
end
ScratchPad.recorded.should == [:loaded]
end
end
it "absolute file path loads a path relative to the absolute path" do
- Object.new.instance_eval("require_relative(#{@path.inspect})", __FILE__).should be_true
+ Object.new.instance_eval("require_relative(#{@path.inspect})", __FILE__).should == true
ScratchPad.recorded.should == [:loaded]
end
@@ -74,34 +74,34 @@ describe "Kernel#require_relative with a relative path" do
root = File.dirname(root)
end
root_relative = @abs_path[root.size..-1]
- Object.new.instance_eval("require_relative(#{root_relative.inspect})", "/").should be_true
+ Object.new.instance_eval("require_relative(#{root_relative.inspect})", "/").should == true
ScratchPad.recorded.should == [:loaded]
end
end
it "loads a file defining many methods" do
- require_relative("#{@dir}/methods_fixture.rb").should be_true
+ require_relative("#{@dir}/methods_fixture.rb").should == true
ScratchPad.recorded.should == [:loaded]
end
it "raises a LoadError if the file does not exist" do
- -> { require_relative("#{@dir}/nonexistent.rb") }.should raise_error(LoadError)
+ -> { require_relative("#{@dir}/nonexistent.rb") }.should.raise(LoadError)
ScratchPad.recorded.should == []
end
it "raises a LoadError that includes the missing path" do
missing_path = "#{@dir}/nonexistent.rb"
expanded_missing_path = File.expand_path(missing_path, __dir__)
- -> { require_relative(missing_path) }.should raise_error(LoadError) { |e|
- e.message.should include(expanded_missing_path)
+ -> { require_relative(missing_path) }.should.raise(LoadError) { |e|
+ e.message.should.include?(expanded_missing_path)
e.path.should == expanded_missing_path
}
ScratchPad.recorded.should == []
end
it "raises a LoadError if basepath does not exist" do
- -> { eval("require_relative('#{@dir}/nonexistent.rb')") }.should raise_error(LoadError)
+ -> { eval("require_relative('#{@dir}/nonexistent.rb')") }.should.raise(LoadError)
end
it "stores the missing path in a LoadError object" do
@@ -109,42 +109,42 @@ describe "Kernel#require_relative with a relative path" do
-> {
require_relative(path)
- }.should(raise_error(LoadError) { |e|
+ }.should.raise(LoadError) { |e|
e.path.should == File.expand_path(path, @abs_dir)
- })
+ }
end
it "calls #to_str on non-String objects" do
name = mock("load_fixture.rb mock")
name.should_receive(:to_str).and_return(@path)
- require_relative(name).should be_true
+ require_relative(name).should == true
ScratchPad.recorded.should == [:loaded]
end
it "raises a TypeError if argument does not respond to #to_str" do
- -> { require_relative(nil) }.should raise_error(TypeError)
- -> { require_relative(42) }.should raise_error(TypeError)
+ -> { require_relative(nil) }.should.raise(TypeError)
+ -> { require_relative(42) }.should.raise(TypeError)
-> {
require_relative([@path,@path])
- }.should raise_error(TypeError)
+ }.should.raise(TypeError)
end
it "raises a TypeError if passed an object that has #to_s but not #to_str" do
name = mock("load_fixture.rb mock")
name.stub!(:to_s).and_return(@path)
- -> { require_relative(name) }.should raise_error(TypeError)
+ -> { require_relative(name) }.should.raise(TypeError)
end
it "raises a TypeError if #to_str does not return a String" do
name = mock("#to_str returns nil")
name.should_receive(:to_str).at_least(1).times.and_return(nil)
- -> { require_relative(name) }.should raise_error(TypeError)
+ -> { require_relative(name) }.should.raise(TypeError)
end
it "calls #to_path on non-String objects" do
name = mock("load_fixture.rb mock")
name.should_receive(:to_path).and_return(@path)
- require_relative(name).should be_true
+ require_relative(name).should == true
ScratchPad.recorded.should == [:loaded]
end
@@ -153,13 +153,13 @@ describe "Kernel#require_relative with a relative path" do
to_path = mock("load_fixture_rb #to_path mock")
name.should_receive(:to_path).and_return(to_path)
to_path.should_receive(:to_str).and_return(@path)
- require_relative(name).should be_true
+ require_relative(name).should == true
ScratchPad.recorded.should == [:loaded]
end
describe "(file extensions)" do
it "loads a .rb extensioned file when passed a non-extensioned path" do
- require_relative("#{@dir}/load_fixture").should be_true
+ require_relative("#{@dir}/load_fixture").should == true
ScratchPad.recorded.should == [:loaded]
end
@@ -168,20 +168,20 @@ describe "Kernel#require_relative with a relative path" do
$LOADED_FEATURES << "#{@abs_dir}/load_fixture.dylib"
$LOADED_FEATURES << "#{@abs_dir}/load_fixture.so"
$LOADED_FEATURES << "#{@abs_dir}/load_fixture.dll"
- require_relative(@path).should be_true
+ require_relative(@path).should == true
ScratchPad.recorded.should == [:loaded]
end
it "does not load a C-extension file if a .rb extensioned file is already loaded" do
$LOADED_FEATURES << "#{@abs_dir}/load_fixture.rb"
- require_relative("#{@dir}/load_fixture").should be_false
+ require_relative("#{@dir}/load_fixture").should == false
ScratchPad.recorded.should == []
end
it "loads a .rb extensioned file when passed a non-.rb extensioned path" do
- require_relative("#{@dir}/load_fixture.ext").should be_true
+ require_relative("#{@dir}/load_fixture.ext").should == true
ScratchPad.recorded.should == [:loaded]
- $LOADED_FEATURES.should include "#{@abs_dir}/load_fixture.ext.rb"
+ $LOADED_FEATURES.should.include? "#{@abs_dir}/load_fixture.ext.rb"
end
it "loads a .rb extensioned file when a complex-extensioned C-extension file of the same name is loaded" do
@@ -189,22 +189,22 @@ describe "Kernel#require_relative with a relative path" do
$LOADED_FEATURES << "#{@abs_dir}/load_fixture.ext.dylib"
$LOADED_FEATURES << "#{@abs_dir}/load_fixture.ext.so"
$LOADED_FEATURES << "#{@abs_dir}/load_fixture.ext.dll"
- require_relative("#{@dir}/load_fixture.ext").should be_true
+ require_relative("#{@dir}/load_fixture.ext").should == true
ScratchPad.recorded.should == [:loaded]
- $LOADED_FEATURES.should include "#{@abs_dir}/load_fixture.ext.rb"
+ $LOADED_FEATURES.should.include? "#{@abs_dir}/load_fixture.ext.rb"
end
it "does not load a C-extension file if a complex-extensioned .rb file is already loaded" do
$LOADED_FEATURES << "#{@abs_dir}/load_fixture.ext.rb"
- require_relative("#{@dir}/load_fixture.ext").should be_false
+ require_relative("#{@dir}/load_fixture.ext").should == false
ScratchPad.recorded.should == []
end
end
describe "($LOADED_FEATURES)" do
it "stores an absolute path" do
- require_relative(@path).should be_true
- $LOADED_FEATURES.should include(@abs_path)
+ require_relative(@path).should == true
+ $LOADED_FEATURES.should.include?(@abs_path)
end
platform_is_not :windows, :wasi do
@@ -231,8 +231,8 @@ describe "Kernel#require_relative with a relative path" do
ScratchPad.recorded.should == [:loaded]
features = $LOADED_FEATURES.select { |path| path.end_with?('load_fixture.rb') }
- features.should include(absolute_path)
- features.should_not include(canonical_path)
+ features.should.include?(absolute_path)
+ features.should_not.include?(canonical_path)
end
it "stores the same path that __FILE__ returns in the required file" do
@@ -249,26 +249,26 @@ describe "Kernel#require_relative with a relative path" do
it "does not store the path if the load fails" do
saved_loaded_features = $LOADED_FEATURES.dup
- -> { require_relative("#{@dir}/raise_fixture.rb") }.should raise_error(RuntimeError)
+ -> { require_relative("#{@dir}/raise_fixture.rb") }.should.raise(RuntimeError)
$LOADED_FEATURES.should == saved_loaded_features
end
it "does not load an absolute path that is already stored" do
$LOADED_FEATURES << @abs_path
- require_relative(@path).should be_false
+ require_relative(@path).should == false
ScratchPad.recorded.should == []
end
it "adds the suffix of the resolved filename" do
- require_relative("#{@dir}/load_fixture").should be_true
- $LOADED_FEATURES.should include("#{@abs_dir}/load_fixture.rb")
+ require_relative("#{@dir}/load_fixture").should == true
+ $LOADED_FEATURES.should.include?("#{@abs_dir}/load_fixture.rb")
end
it "loads a path for a file already loaded with a relative path" do
$LOAD_PATH << File.expand_path(@dir)
$LOADED_FEATURES << "load_fixture.rb" << "load_fixture"
- require_relative(@path).should be_true
- $LOADED_FEATURES.should include(@abs_path)
+ require_relative(@path).should == true
+ $LOADED_FEATURES.should.include?(@abs_path)
ScratchPad.recorded.should == [:loaded]
end
end
@@ -288,22 +288,22 @@ describe "Kernel#require_relative with an absolute path" do
end
it "loads a path relative to the current file" do
- require_relative(@path).should be_true
+ require_relative(@path).should == true
ScratchPad.recorded.should == [:loaded]
end
it "loads a file defining many methods" do
- require_relative("#{@dir}/methods_fixture.rb").should be_true
+ require_relative("#{@dir}/methods_fixture.rb").should == true
ScratchPad.recorded.should == [:loaded]
end
it "raises a LoadError if the file does not exist" do
- -> { require_relative("#{@dir}/nonexistent.rb") }.should raise_error(LoadError)
+ -> { require_relative("#{@dir}/nonexistent.rb") }.should.raise(LoadError)
ScratchPad.recorded.should == []
end
it "raises a LoadError if basepath does not exist" do
- -> { eval("require_relative('#{@dir}/nonexistent.rb')") }.should raise_error(LoadError)
+ -> { eval("require_relative('#{@dir}/nonexistent.rb')") }.should.raise(LoadError)
end
it "stores the missing path in a LoadError object" do
@@ -311,42 +311,42 @@ describe "Kernel#require_relative with an absolute path" do
-> {
require_relative(path)
- }.should(raise_error(LoadError) { |e|
+ }.should.raise(LoadError) { |e|
e.path.should == File.expand_path(path, @abs_dir)
- })
+ }
end
it "calls #to_str on non-String objects" do
name = mock("load_fixture.rb mock")
name.should_receive(:to_str).and_return(@path)
- require_relative(name).should be_true
+ require_relative(name).should == true
ScratchPad.recorded.should == [:loaded]
end
it "raises a TypeError if argument does not respond to #to_str" do
- -> { require_relative(nil) }.should raise_error(TypeError)
- -> { require_relative(42) }.should raise_error(TypeError)
+ -> { require_relative(nil) }.should.raise(TypeError)
+ -> { require_relative(42) }.should.raise(TypeError)
-> {
require_relative([@path,@path])
- }.should raise_error(TypeError)
+ }.should.raise(TypeError)
end
it "raises a TypeError if passed an object that has #to_s but not #to_str" do
name = mock("load_fixture.rb mock")
name.stub!(:to_s).and_return(@path)
- -> { require_relative(name) }.should raise_error(TypeError)
+ -> { require_relative(name) }.should.raise(TypeError)
end
it "raises a TypeError if #to_str does not return a String" do
name = mock("#to_str returns nil")
name.should_receive(:to_str).at_least(1).times.and_return(nil)
- -> { require_relative(name) }.should raise_error(TypeError)
+ -> { require_relative(name) }.should.raise(TypeError)
end
it "calls #to_path on non-String objects" do
name = mock("load_fixture.rb mock")
name.should_receive(:to_path).and_return(@path)
- require_relative(name).should be_true
+ require_relative(name).should == true
ScratchPad.recorded.should == [:loaded]
end
@@ -355,13 +355,13 @@ describe "Kernel#require_relative with an absolute path" do
to_path = mock("load_fixture_rb #to_path mock")
name.should_receive(:to_path).and_return(to_path)
to_path.should_receive(:to_str).and_return(@path)
- require_relative(name).should be_true
+ require_relative(name).should == true
ScratchPad.recorded.should == [:loaded]
end
describe "(file extensions)" do
it "loads a .rb extensioned file when passed a non-extensioned path" do
- require_relative("#{@dir}/load_fixture").should be_true
+ require_relative("#{@dir}/load_fixture").should == true
ScratchPad.recorded.should == [:loaded]
end
@@ -370,20 +370,20 @@ describe "Kernel#require_relative with an absolute path" do
$LOADED_FEATURES << "#{@abs_dir}/load_fixture.dylib"
$LOADED_FEATURES << "#{@abs_dir}/load_fixture.so"
$LOADED_FEATURES << "#{@abs_dir}/load_fixture.dll"
- require_relative(@path).should be_true
+ require_relative(@path).should == true
ScratchPad.recorded.should == [:loaded]
end
it "does not load a C-extension file if a .rb extensioned file is already loaded" do
$LOADED_FEATURES << "#{@abs_dir}/load_fixture.rb"
- require_relative("#{@dir}/load_fixture").should be_false
+ require_relative("#{@dir}/load_fixture").should == false
ScratchPad.recorded.should == []
end
it "loads a .rb extensioned file when passed a non-.rb extensioned path" do
- require_relative("#{@dir}/load_fixture.ext").should be_true
+ require_relative("#{@dir}/load_fixture.ext").should == true
ScratchPad.recorded.should == [:loaded]
- $LOADED_FEATURES.should include "#{@abs_dir}/load_fixture.ext.rb"
+ $LOADED_FEATURES.should.include? "#{@abs_dir}/load_fixture.ext.rb"
end
it "loads a .rb extensioned file when a complex-extensioned C-extension file of the same name is loaded" do
@@ -391,46 +391,46 @@ describe "Kernel#require_relative with an absolute path" do
$LOADED_FEATURES << "#{@abs_dir}/load_fixture.ext.dylib"
$LOADED_FEATURES << "#{@abs_dir}/load_fixture.ext.so"
$LOADED_FEATURES << "#{@abs_dir}/load_fixture.ext.dll"
- require_relative("#{@dir}/load_fixture.ext").should be_true
+ require_relative("#{@dir}/load_fixture.ext").should == true
ScratchPad.recorded.should == [:loaded]
- $LOADED_FEATURES.should include "#{@abs_dir}/load_fixture.ext.rb"
+ $LOADED_FEATURES.should.include? "#{@abs_dir}/load_fixture.ext.rb"
end
it "does not load a C-extension file if a complex-extensioned .rb file is already loaded" do
$LOADED_FEATURES << "#{@abs_dir}/load_fixture.ext.rb"
- require_relative("#{@dir}/load_fixture.ext").should be_false
+ require_relative("#{@dir}/load_fixture.ext").should == false
ScratchPad.recorded.should == []
end
end
describe "($LOAD_FEATURES)" do
it "stores an absolute path" do
- require_relative(@path).should be_true
- $LOADED_FEATURES.should include(@abs_path)
+ require_relative(@path).should == true
+ $LOADED_FEATURES.should.include?(@abs_path)
end
it "does not store the path if the load fails" do
saved_loaded_features = $LOADED_FEATURES.dup
- -> { require_relative("#{@dir}/raise_fixture.rb") }.should raise_error(RuntimeError)
+ -> { require_relative("#{@dir}/raise_fixture.rb") }.should.raise(RuntimeError)
$LOADED_FEATURES.should == saved_loaded_features
end
it "does not load an absolute path that is already stored" do
$LOADED_FEATURES << @abs_path
- require_relative(@path).should be_false
+ require_relative(@path).should == false
ScratchPad.recorded.should == []
end
it "adds the suffix of the resolved filename" do
- require_relative("#{@dir}/load_fixture").should be_true
- $LOADED_FEATURES.should include("#{@abs_dir}/load_fixture.rb")
+ require_relative("#{@dir}/load_fixture").should == true
+ $LOADED_FEATURES.should.include?("#{@abs_dir}/load_fixture.rb")
end
it "loads a path for a file already loaded with a relative path" do
$LOAD_PATH << File.expand_path(@dir)
$LOADED_FEATURES << "load_fixture.rb" << "load_fixture"
- require_relative(@path).should be_true
- $LOADED_FEATURES.should include(@abs_path)
+ require_relative(@path).should == true
+ $LOADED_FEATURES.should.include?(@abs_path)
ScratchPad.recorded.should == [:loaded]
end
end
diff --git a/spec/ruby/core/kernel/require_spec.rb b/spec/ruby/core/kernel/require_spec.rb
index 81777c5313..62d954c2bf 100644
--- a/spec/ruby/core/kernel/require_spec.rb
+++ b/spec/ruby/core/kernel/require_spec.rb
@@ -13,32 +13,40 @@ describe "Kernel#require" do
# if this fails, update your rubygems
it "is a private method" do
- Kernel.should have_private_instance_method(:require)
+ Kernel.private_instance_methods(false).should.include?(:require)
end
- provided = %w[complex enumerator fiber rational thread ruby2_keywords]
- ruby_version_is "3.5" do
- provided << "set"
- provided << "pathname"
- end
+ it "provided features are already required" do
+ provided = %w[complex enumerator fiber rational thread ruby2_keywords]
+ ruby_version_is "4.0" do
+ provided += %w[set pathname]
+ end
+ ruby_version_is "4.1" do
+ provided += %w[monitor]
+ 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, '.*') }
+ features = out.lines.map(&:chomp)
- # Ignore CRuby internals
- features -= %w[encdb transdb windows_1252 windows_31j]
- features.reject! { |feature| feature.end_with?('-fake') }
-
- features.sort.should == provided.sort
-
- ruby_version_is "3.5" do
- provided.map! { |f| f == "pathname" ? "pathname.so" : f }
+ # Ignore engine-specific internals
+ case RUBY_ENGINE
+ when "jruby"
+ features -= %w[java.rb jruby/util.rb]
+ when "ruby"
+ so = RbConfig::CONFIG['DLEXT']
+ features -= ["windows_1252.#{so}", "windows_31.#{so}"]
+ features.reject! { |feature| feature.end_with? "encdb.#{so}" }
+ features.reject! { |feature| feature.end_with? "transdb.#{so}" }
+ features.reject! { |feature| feature.include?('-fake') }
end
- code = provided.map { |f| "puts require #{f.inspect}\n" }.join
+ features_no_ext = features.map { |path| File.basename(path, '.*') }
+ features_no_ext.sort.should == provided.sort
+
+ requires = features
+ code = requires.map { |f| "puts require #{f.inspect}\n" }.join
required = ruby_exe(code, options: '--disable-gems')
- required.should == "false\n" * provided.size
+ required.should == "false\n" * requires.size
end
it_behaves_like :kernel_require_basic, :require, CodeLoadingSpecs::Method.new
diff --git a/spec/ruby/core/kernel/respond_to_missing_spec.rb b/spec/ruby/core/kernel/respond_to_missing_spec.rb
index cc82031e26..08c9184fb4 100644
--- a/spec/ruby/core/kernel/respond_to_missing_spec.rb
+++ b/spec/ruby/core/kernel/respond_to_missing_spec.rb
@@ -7,7 +7,7 @@ describe "Kernel#respond_to_missing?" do
end
it "is a private method" do
- Kernel.should have_private_instance_method(:respond_to_missing?, false)
+ Kernel.private_instance_methods(false).should.include?(:respond_to_missing?)
end
it "is only an instance method" do
@@ -18,7 +18,7 @@ describe "Kernel#respond_to_missing?" do
obj = mock('object')
obj.stub!(:glark)
obj.should_not_receive(:respond_to_missing?)
- obj.respond_to?(:glark).should be_true
+ obj.respond_to?(:glark).should == true
end
it "is called with a 2nd argument of false when #respond_to? is" do
@@ -48,39 +48,39 @@ describe "Kernel#respond_to_missing?" do
it "causes #respond_to? to return true if called and not returning false" do
obj = mock('object')
obj.should_receive(:respond_to_missing?).with(:undefined_method, false).and_return(:glark)
- obj.respond_to?(:undefined_method).should be_true
+ obj.respond_to?(:undefined_method).should == true
end
it "causes #respond_to? to return false if called and returning false" do
obj = mock('object')
obj.should_receive(:respond_to_missing?).with(:undefined_method, false).and_return(false)
- obj.respond_to?(:undefined_method).should be_false
+ obj.respond_to?(:undefined_method).should == false
end
it "causes #respond_to? to return false if called and returning nil" do
obj = mock('object')
obj.should_receive(:respond_to_missing?).with(:undefined_method, false).and_return(nil)
- obj.respond_to?(:undefined_method).should be_false
+ obj.respond_to?(:undefined_method).should == false
end
it "isn't called when obj responds to the given public method" do
@a.should_not_receive(:respond_to_missing?)
- @a.respond_to?(:pub_method).should be_true
+ @a.respond_to?(:pub_method).should == true
end
it "isn't called when obj responds to the given public method, include_private = true" do
@a.should_not_receive(:respond_to_missing?)
- @a.respond_to?(:pub_method, true).should be_true
+ @a.respond_to?(:pub_method, true).should == true
end
it "is called when obj responds to the given protected method, include_private = false" do
@a.should_receive(:respond_to_missing?)
- @a.respond_to?(:protected_method, false).should be_false
+ @a.respond_to?(:protected_method, false).should == false
end
it "isn't called when obj responds to the given protected method, include_private = true" do
@a.should_not_receive(:respond_to_missing?)
- @a.respond_to?(:protected_method, true).should be_true
+ @a.respond_to?(:protected_method, true).should == true
end
it "is called when obj responds to the given private method, include_private = false" do
@@ -90,7 +90,7 @@ describe "Kernel#respond_to_missing?" do
it "isn't called when obj responds to the given private method, include_private = true" do
@a.should_not_receive(:respond_to_missing?)
- @a.respond_to?(:private_method, true).should be_true
+ @a.respond_to?(:private_method, true).should == true
end
it "is called for missing class methods" do
diff --git a/spec/ruby/core/kernel/respond_to_spec.rb b/spec/ruby/core/kernel/respond_to_spec.rb
index 5b3ea3f651..72ab4eebe1 100644
--- a/spec/ruby/core/kernel/respond_to_spec.rb
+++ b/spec/ruby/core/kernel/respond_to_spec.rb
@@ -7,7 +7,7 @@ describe "Kernel#respond_to?" do
end
it "is a public method" do
- Kernel.should have_public_instance_method(:respond_to?, false)
+ Kernel.public_instance_methods(false).should.include?(:respond_to?)
end
it "is only an instance method" do
@@ -25,7 +25,7 @@ describe "Kernel#respond_to?" do
end
it "throws a type error if argument can't be coerced into a Symbol" do
- -> { @a.respond_to?(Object.new) }.should raise_error(TypeError, /is not a symbol nor a string/)
+ -> { @a.respond_to?(Object.new) }.should.raise(TypeError, /is not a symbol nor a string/)
end
it "returns false if obj responds to the given protected method" do
@@ -61,7 +61,7 @@ describe "Kernel#respond_to?" do
it "does not change method visibility when finding private method" do
KernelSpecs::VisibilityChange.respond_to?(:new, false).should == false
KernelSpecs::VisibilityChange.respond_to?(:new, true).should == true
- -> { KernelSpecs::VisibilityChange.new }.should raise_error(NoMethodError)
+ -> { KernelSpecs::VisibilityChange.new }.should.raise(NoMethodError)
end
it "indicates if an object responds to a particular message" do
@@ -69,4 +69,31 @@ describe "Kernel#respond_to?" do
KernelSpecs::Foo.new.respond_to?(:bar).should == true
KernelSpecs::Foo.new.respond_to?(:invalid_and_silly_method_name).should == false
end
+
+ context "if object does not have #respond_to_missing?" do
+ it "returns true if object responds to the given public method" do
+ KernelSpecs::BasicA.new.respond_to?(:pub_method).should == true
+ KernelSpecs::MissingA.new.respond_to?(:pub_method).should == true
+ end
+
+ it "returns false if object responds to the given protected method" do
+ KernelSpecs::BasicA.new.respond_to?(:protected_method).should == false
+ KernelSpecs::MissingA.new.respond_to?(:protected_method).should == false
+ end
+
+ it "returns false if object responds to the given private method" do
+ KernelSpecs::BasicA.new.respond_to?(:private_method).should == false
+ KernelSpecs::MissingA.new.respond_to?(:private_method).should == false
+ end
+
+ it "returns false if the given method was undefined" do
+ KernelSpecs::BasicA.new.respond_to?(:undefed_method).should == false
+ KernelSpecs::MissingA.new.respond_to?(:undefed_method).should == false
+ end
+
+ it "returns false if the given method never existed" do
+ KernelSpecs::BasicA.new.respond_to?(:invalid_and_silly_method_name).should == false
+ KernelSpecs::MissingA.new.respond_to?(:invalid_and_silly_method_name).should == false
+ end
+ end
end
diff --git a/spec/ruby/core/kernel/select_spec.rb b/spec/ruby/core/kernel/select_spec.rb
index df23414b28..58c963c1a4 100644
--- a/spec/ruby/core/kernel/select_spec.rb
+++ b/spec/ruby/core/kernel/select_spec.rb
@@ -3,7 +3,7 @@ require_relative 'fixtures/classes'
describe "Kernel#select" do
it "is a private method" do
- Kernel.should have_private_instance_method(:select)
+ Kernel.private_instance_methods(false).should.include?(:select)
end
end
diff --git a/spec/ruby/core/kernel/set_trace_func_spec.rb b/spec/ruby/core/kernel/set_trace_func_spec.rb
index 1f43e7a009..5201812f2f 100644
--- a/spec/ruby/core/kernel/set_trace_func_spec.rb
+++ b/spec/ruby/core/kernel/set_trace_func_spec.rb
@@ -3,7 +3,7 @@ require_relative 'fixtures/classes'
describe "Kernel#set_trace_func" do
it "is a private method" do
- Kernel.should have_private_instance_method(:set_trace_func)
+ Kernel.private_instance_methods(false).should.include?(:set_trace_func)
end
end
diff --git a/spec/ruby/core/kernel/shared/dup_clone.rb b/spec/ruby/core/kernel/shared/dup_clone.rb
index 4fac6006e1..3fbf918283 100644
--- a/spec/ruby/core/kernel/shared/dup_clone.rb
+++ b/spec/ruby/core/kernel/shared/dup_clone.rb
@@ -40,7 +40,7 @@ describe :kernel_dup_clone, shared: true do
o.obj = array
o2 = o.send(@method)
- o2.obj.should equal(o.obj)
+ o2.obj.should.equal?(o.obj)
end
it "calls #initialize_copy on the NEW object if available, passing in original object" do
@@ -49,7 +49,7 @@ describe :kernel_dup_clone, shared: true do
o.obj.should == :original
o2.obj.should == :init_copy
- o2.original.should equal(o)
+ o2.original.should.equal?(o)
end
it "does not preserve the object_id" do
@@ -81,11 +81,11 @@ describe :kernel_dup_clone, shared: true do
it "returns self for Complex" do
c = Complex(1.3, 3.1)
- c.send(@method).should equal c
+ c.send(@method).should.equal? c
end
it "returns self for Rational" do
r = Rational(1, 3)
- r.send(@method).should equal r
+ r.send(@method).should.equal? r
end
end
diff --git a/spec/ruby/core/kernel/shared/kind_of.rb b/spec/ruby/core/kernel/shared/kind_of.rb
deleted file mode 100644
index aef6f1c1d8..0000000000
--- a/spec/ruby/core/kernel/shared/kind_of.rb
+++ /dev/null
@@ -1,55 +0,0 @@
-require_relative '../fixtures/classes'
-
-describe :kernel_kind_of, shared: true do
- before :each do
- @o = KernelSpecs::KindaClass.new
- end
-
- it "returns true if given class is the object's class" do
- @o.send(@method, KernelSpecs::KindaClass).should == true
- end
-
- it "returns true if given class is an ancestor of the object's class" do
- @o.send(@method, KernelSpecs::AncestorClass).should == true
- @o.send(@method, String).should == true
- @o.send(@method, Object).should == true
- end
-
- it "returns false if the given class is not object's class nor an ancestor" do
- @o.send(@method, Array).should == false
- end
-
- it "returns true if given a Module that is included in object's class" do
- @o.send(@method, KernelSpecs::MyModule).should == true
- end
-
- it "returns true if given a Module that is included one of object's ancestors only" do
- @o.send(@method, KernelSpecs::AncestorModule).should == true
- end
-
- it "returns true if given a Module that object has been extended with" do
- @o.send(@method, KernelSpecs::MyExtensionModule).should == true
- end
-
- it "returns true if given a Module that object has been prepended with" do
- @o.send(@method, KernelSpecs::MyPrependedModule).should == true
- end
-
- it "returns false if given a Module not included nor prepended in object's class nor ancestors" do
- @o.send(@method, KernelSpecs::SomeOtherModule).should == false
- end
-
- it "raises a TypeError if given an object that is not a Class nor a Module" do
- -> { @o.send(@method, 1) }.should raise_error(TypeError)
- -> { @o.send(@method, 'KindaClass') }.should raise_error(TypeError)
- -> { @o.send(@method, :KindaClass) }.should raise_error(TypeError)
- -> { @o.send(@method, Object.new) }.should raise_error(TypeError)
- end
-
- it "does not take into account `class` method overriding" do
- def @o.class; Integer; end
-
- @o.send(@method, Integer).should == false
- @o.send(@method, KernelSpecs::KindaClass).should == true
- end
-end
diff --git a/spec/ruby/core/kernel/shared/lambda.rb b/spec/ruby/core/kernel/shared/lambda.rb
index c70640082a..83de06bb41 100644
--- a/spec/ruby/core/kernel/shared/lambda.rb
+++ b/spec/ruby/core/kernel/shared/lambda.rb
@@ -5,7 +5,7 @@ describe :kernel_lambda, shared: true do
it "raises an ArgumentError when no block is given" do
suppress_warning do
- -> { send(@method) }.should raise_error(ArgumentError)
+ -> { send(@method) }.should.raise(ArgumentError)
end
end
end
diff --git a/spec/ruby/core/kernel/shared/load.rb b/spec/ruby/core/kernel/shared/load.rb
index 62c5c7be9b..20d23a623e 100644
--- a/spec/ruby/core/kernel/shared/load.rb
+++ b/spec/ruby/core/kernel/shared/load.rb
@@ -15,19 +15,19 @@ describe :kernel_load, shared: true 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
+ @object.load(path).should == 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
+ @object.load(path).should == true
ScratchPad.recorded.should == [:no_rb_ext]
end
it "loads from the current working directory" do
Dir.chdir CODE_LOADING_DIR do
- @object.load("load_fixture.rb").should be_true
+ @object.load("load_fixture.rb").should == true
ScratchPad.recorded.should == [:loaded]
end
end
@@ -35,88 +35,88 @@ describe :kernel_load, shared: true do
# 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)
+ -> { @object.send(@method, path) }.should.raise(LoadError)
end
end
it "loads a file that recursively requires itself" do
path = File.expand_path "recursive_require_fixture.rb", CODE_LOADING_DIR
-> {
- @object.load(path).should be_true
+ @object.load(path).should == true
}.should complain(/circular require considered harmful/, verbose: true)
ScratchPad.recorded.should == [:loaded, :loaded]
end
it "loads a file that recursively loads itself" do
path = File.expand_path "recursive_load_fixture.rb", CODE_LOADING_DIR
- @object.load(path).should be_true
+ @object.load(path).should == true
ScratchPad.recorded.should == [:loaded, :loaded]
end
it "loads a file each time the method is called" do
- @object.load(@path).should be_true
- @object.load(@path).should be_true
+ @object.load(@path).should == true
+ @object.load(@path).should == true
ScratchPad.recorded.should == [:loaded, :loaded]
end
it "loads a file even when the name appears in $LOADED_FEATURES" do
$LOADED_FEATURES << @path
- @object.load(@path).should be_true
+ @object.load(@path).should == true
ScratchPad.recorded.should == [:loaded]
end
it "loads a file that has been loaded by #require" do
- @object.require(@path).should be_true
- @object.load(@path).should be_true
+ @object.require(@path).should == true
+ @object.load(@path).should == true
ScratchPad.recorded.should == [:loaded, :loaded]
end
it "loads file even after $LOAD_PATH change" do
$LOAD_PATH << CODE_LOADING_DIR
- @object.load("load_fixture.rb").should be_true
+ @object.load("load_fixture.rb").should == true
$LOAD_PATH.unshift CODE_LOADING_DIR + "/gem"
- @object.load("load_fixture.rb").should be_true
+ @object.load("load_fixture.rb").should == true
ScratchPad.recorded.should == [:loaded, :loaded_gem]
end
it "does not cause #require with the same path to fail" do
- @object.load(@path).should be_true
- @object.require(@path).should be_true
+ @object.load(@path).should == true
+ @object.require(@path).should == true
ScratchPad.recorded.should == [:loaded, :loaded]
end
it "does not add the loaded path to $LOADED_FEATURES" do
saved_loaded_features = $LOADED_FEATURES.dup
- @object.load(@path).should be_true
+ @object.load(@path).should == true
$LOADED_FEATURES.should == saved_loaded_features
end
it "raises a LoadError if passed a non-extensioned path that does not exist but a .rb extensioned path does exist" do
path = File.expand_path "load_ext_fixture", CODE_LOADING_DIR
- -> { @object.load(path) }.should raise_error(LoadError)
+ -> { @object.load(path) }.should.raise(LoadError)
end
describe "when passed true for 'wrap'" do
it "loads from an existing path" do
path = File.expand_path "load_wrap_fixture.rb", CODE_LOADING_DIR
- @object.load(path, true).should be_true
+ @object.load(path, true).should == true
end
it "sets the enclosing scope to an anonymous module" do
path = File.expand_path "load_wrap_fixture.rb", CODE_LOADING_DIR
@object.load(path, true)
- Object.const_defined?(:LoadSpecWrap).should be_false
+ Object.const_defined?(:LoadSpecWrap).should == false
wrap_module = ScratchPad.recorded[1]
- wrap_module.should be_an_instance_of(Module)
+ wrap_module.should.instance_of?(Module)
end
it "allows referencing outside namespaces" do
path = File.expand_path "load_wrap_fixture.rb", CODE_LOADING_DIR
@object.load(path, true)
- ScratchPad.recorded[0].should equal(String)
+ ScratchPad.recorded[0].should.equal?(String)
end
it "sets self as a copy of the top-level main" do
@@ -126,8 +126,8 @@ describe :kernel_load, shared: true do
top_level = ScratchPad.recorded[2]
top_level.to_s.should == "main"
top_level.method(:to_s).owner.should == top_level.singleton_class
- top_level.should_not equal(main)
- top_level.should be_an_instance_of(Object)
+ top_level.should_not.equal?(main)
+ top_level.should.instance_of?(Object)
end
it "includes modules included in main's singleton class in self's class" do
@@ -159,7 +159,7 @@ describe :kernel_load, shared: true do
end
it "does not pollute the receiver" do
- -> { @object.send(:top_level_method) }.should raise_error(NameError)
+ -> { @object.send(:top_level_method) }.should.raise(NameError)
end
end
end
@@ -170,8 +170,8 @@ describe :kernel_load, shared: true do
mod = Module.new
@object.load(path, mod)
- Object.const_defined?(:LoadSpecWrap).should be_false
- mod.const_defined?(:LoadSpecWrap).should be_true
+ Object.const_defined?(:LoadSpecWrap).should == false
+ mod.const_defined?(:LoadSpecWrap).should == true
wrap_module = ScratchPad.recorded[1]
wrap_module.should == mod
@@ -208,7 +208,7 @@ describe :kernel_load, shared: true do
end
it "expands a tilde to the HOME environment variable as the path to load" do
- @object.require("~/load_fixture.rb").should be_true
+ @object.require("~/load_fixture.rb").should == true
ScratchPad.recorded.should == [:loaded]
end
end
diff --git a/spec/ruby/core/kernel/shared/method.rb b/spec/ruby/core/kernel/shared/method.rb
index 8b6ab23fd3..82abc287d1 100644
--- a/spec/ruby/core/kernel/shared/method.rb
+++ b/spec/ruby/core/kernel/shared/method.rb
@@ -4,26 +4,26 @@ describe :kernel_method, shared: true do
it "returns a method object for a valid method" do
class KernelSpecs::Foo; def bar; 'done'; end; end
m = KernelSpecs::Foo.new.send(@method, :bar)
- m.should be_an_instance_of Method
+ m.should.instance_of? Method
m.call.should == 'done'
end
it "returns a method object for a valid singleton method" do
class KernelSpecs::Foo; def self.bar; 'class done'; end; end
m = KernelSpecs::Foo.send(@method, :bar)
- m.should be_an_instance_of Method
+ m.should.instance_of? Method
m.call.should == 'class done'
end
it "returns a method object if respond_to_missing?(method) is true" do
m = KernelSpecs::RespondViaMissing.new.send(@method, :handled_publicly)
- m.should be_an_instance_of Method
+ m.should.instance_of? Method
m.call(42).should == "Done handled_publicly([42])"
end
it "the returned method object if respond_to_missing?(method) calls #method_missing with a Symbol name" do
m = KernelSpecs::RespondViaMissing.new.send(@method, "handled_publicly")
- m.should be_an_instance_of Method
+ m.should.instance_of? Method
m.call(42).should == "Done handled_publicly([42])"
end
@@ -31,12 +31,12 @@ describe :kernel_method, shared: true do
class KernelSpecs::Foo; def bar; 'done'; end; end
-> {
KernelSpecs::Foo.new.send(@method, :invalid_and_silly_method_name)
- }.should raise_error(NameError)
+ }.should.raise(NameError)
end
it "raises a NameError for an invalid singleton method name" do
class KernelSpecs::Foo; def self.bar; 'done'; end; end
- -> { KernelSpecs::Foo.send(@method, :baz) }.should raise_error(NameError)
+ -> { KernelSpecs::Foo.send(@method, :baz) }.should.raise(NameError)
end
it "changes the method called for super on a target aliased method" do
diff --git a/spec/ruby/core/kernel/shared/require.rb b/spec/ruby/core/kernel/shared/require.rb
index 52f86f73e5..6272b00665 100644
--- a/spec/ruby/core/kernel/shared/require.rb
+++ b/spec/ruby/core/kernel/shared/require.rb
@@ -2,26 +2,26 @@ describe :kernel_require_basic, shared: true do
describe "(path resolution)" do
it "loads an absolute path" do
path = File.expand_path "load_fixture.rb", CODE_LOADING_DIR
- @object.send(@method, path).should be_true
+ @object.send(@method, path).should == true
ScratchPad.recorded.should == [:loaded]
end
it "loads a non-canonical absolute path" do
path = File.join CODE_LOADING_DIR, "..", "code", "load_fixture.rb"
- @object.send(@method, path).should be_true
+ @object.send(@method, path).should == true
ScratchPad.recorded.should == [:loaded]
end
it "loads a file defining many methods" do
path = File.expand_path "methods_fixture.rb", CODE_LOADING_DIR
- @object.send(@method, path).should be_true
+ @object.send(@method, path).should == true
ScratchPad.recorded.should == [:loaded]
end
it "raises a LoadError if the file does not exist" do
path = File.expand_path "nonexistent.rb", CODE_LOADING_DIR
File.should_not.exist?(path)
- -> { @object.send(@method, path) }.should raise_error(LoadError)
+ -> { @object.send(@method, path) }.should.raise(LoadError)
ScratchPad.recorded.should == []
end
@@ -42,7 +42,7 @@ describe :kernel_require_basic, shared: true do
it "raises a LoadError" do
File.should.exist?(@path)
- -> { @object.send(@method, @path) }.should raise_error(LoadError)
+ -> { @object.send(@method, @path) }.should.raise(LoadError)
end
end
end
@@ -52,24 +52,24 @@ describe :kernel_require_basic, shared: true do
path = File.expand_path "load_fixture.rb", CODE_LOADING_DIR
name = mock("load_fixture.rb mock")
name.should_receive(:to_str).and_return(path)
- @object.send(@method, name).should be_true
+ @object.send(@method, name).should == true
ScratchPad.recorded.should == [:loaded]
end
it "raises a TypeError if passed nil" do
- -> { @object.send(@method, nil) }.should raise_error(TypeError)
+ -> { @object.send(@method, nil) }.should.raise(TypeError)
end
it "raises a TypeError if passed an Integer" do
- -> { @object.send(@method, 42) }.should raise_error(TypeError)
+ -> { @object.send(@method, 42) }.should.raise(TypeError)
end
it "raises a TypeError if passed an Array" do
- -> { @object.send(@method, []) }.should raise_error(TypeError)
+ -> { @object.send(@method, []) }.should.raise(TypeError)
end
it "raises a TypeError if passed an object that does not provide #to_str" do
- -> { @object.send(@method, mock("not a filename")) }.should raise_error(TypeError)
+ -> { @object.send(@method, mock("not a filename")) }.should.raise(TypeError)
end
it "raises a TypeError if passed an object that has #to_s but not #to_str" do
@@ -77,14 +77,14 @@ describe :kernel_require_basic, shared: true do
name.stub!(:to_s).and_return("load_fixture.rb")
$LOAD_PATH << "."
Dir.chdir CODE_LOADING_DIR do
- -> { @object.send(@method, name) }.should raise_error(TypeError)
+ -> { @object.send(@method, name) }.should.raise(TypeError)
end
end
it "raises a TypeError if #to_str does not return a String" do
name = mock("#to_str returns nil")
name.should_receive(:to_str).at_least(1).times.and_return(nil)
- -> { @object.send(@method, name) }.should raise_error(TypeError)
+ -> { @object.send(@method, name) }.should.raise(TypeError)
end
it "calls #to_path on non-String objects" do
@@ -92,7 +92,7 @@ describe :kernel_require_basic, shared: true do
name.stub!(:to_path).and_return("load_fixture.rb")
$LOAD_PATH << "."
Dir.chdir CODE_LOADING_DIR do
- @object.send(@method, name).should be_true
+ @object.send(@method, name).should == true
end
ScratchPad.recorded.should == [:loaded]
end
@@ -101,7 +101,7 @@ describe :kernel_require_basic, shared: true do
path = File.expand_path "load_fixture.rb", CODE_LOADING_DIR
str = mock("load_fixture.rb mock")
str.should_receive(:to_path).and_return(path)
- @object.send(@method, str).should be_true
+ @object.send(@method, str).should == true
ScratchPad.recorded.should == [:loaded]
end
@@ -111,21 +111,21 @@ describe :kernel_require_basic, shared: true do
to_path = mock("load_fixture_rb #to_path mock")
name.should_receive(:to_path).and_return(to_path)
to_path.should_receive(:to_str).and_return(path)
- @object.send(@method, name).should be_true
+ @object.send(@method, name).should == true
ScratchPad.recorded.should == [:loaded]
end
# "http://redmine.ruby-lang.org/issues/show/2578"
it "loads a ./ relative path from the current working directory with empty $LOAD_PATH" do
Dir.chdir CODE_LOADING_DIR do
- @object.send(@method, "./load_fixture.rb").should be_true
+ @object.send(@method, "./load_fixture.rb").should == true
end
ScratchPad.recorded.should == [:loaded]
end
it "loads a ../ relative path from the current working directory with empty $LOAD_PATH" do
Dir.chdir CODE_LOADING_DIR do
- @object.send(@method, "../code/load_fixture.rb").should be_true
+ @object.send(@method, "../code/load_fixture.rb").should == true
end
ScratchPad.recorded.should == [:loaded]
end
@@ -133,7 +133,7 @@ describe :kernel_require_basic, shared: true do
it "loads a ./ relative path from the current working directory with non-empty $LOAD_PATH" do
$LOAD_PATH << "an_irrelevant_dir"
Dir.chdir CODE_LOADING_DIR do
- @object.send(@method, "./load_fixture.rb").should be_true
+ @object.send(@method, "./load_fixture.rb").should == true
end
ScratchPad.recorded.should == [:loaded]
end
@@ -141,7 +141,7 @@ describe :kernel_require_basic, shared: true do
it "loads a ../ relative path from the current working directory with non-empty $LOAD_PATH" do
$LOAD_PATH << "an_irrelevant_dir"
Dir.chdir CODE_LOADING_DIR do
- @object.send(@method, "../code/load_fixture.rb").should be_true
+ @object.send(@method, "../code/load_fixture.rb").should == true
end
ScratchPad.recorded.should == [:loaded]
end
@@ -149,14 +149,14 @@ describe :kernel_require_basic, shared: true do
it "loads a non-canonical path from the current working directory with non-empty $LOAD_PATH" do
$LOAD_PATH << "an_irrelevant_dir"
Dir.chdir CODE_LOADING_DIR do
- @object.send(@method, "../code/../code/load_fixture.rb").should be_true
+ @object.send(@method, "../code/../code/load_fixture.rb").should == true
end
ScratchPad.recorded.should == [:loaded]
end
it "resolves a filename against $LOAD_PATH entries" do
$LOAD_PATH << CODE_LOADING_DIR
- @object.send(@method, "load_fixture.rb").should be_true
+ @object.send(@method, "load_fixture.rb").should == true
ScratchPad.recorded.should == [:loaded]
end
@@ -164,15 +164,15 @@ describe :kernel_require_basic, shared: true do
obj = mock("to_path")
obj.should_receive(:to_path).at_least(:once).and_return(CODE_LOADING_DIR)
$LOAD_PATH << obj
- @object.send(@method, "load_fixture.rb").should be_true
+ @object.send(@method, "load_fixture.rb").should == true
ScratchPad.recorded.should == [:loaded]
end
it "does not require file twice after $LOAD_PATH change" do
$LOAD_PATH << CODE_LOADING_DIR
- @object.require("load_fixture.rb").should be_true
+ @object.require("load_fixture.rb").should == true
$LOAD_PATH.push CODE_LOADING_DIR + "/gem"
- @object.require("load_fixture.rb").should be_false
+ @object.require("load_fixture.rb").should == false
ScratchPad.recorded.should == [:loaded]
end
@@ -180,7 +180,7 @@ describe :kernel_require_basic, shared: true do
$LOAD_PATH << CODE_LOADING_DIR
-> do
@object.send(@method, "./load_fixture.rb")
- end.should raise_error(LoadError)
+ end.should.raise(LoadError)
ScratchPad.recorded.should == []
end
@@ -188,13 +188,13 @@ describe :kernel_require_basic, shared: true do
$LOAD_PATH << CODE_LOADING_DIR
-> do
@object.send(@method, "../code/load_fixture.rb")
- end.should raise_error(LoadError)
+ end.should.raise(LoadError)
ScratchPad.recorded.should == []
end
it "resolves a non-canonical path against $LOAD_PATH entries" do
$LOAD_PATH << File.dirname(CODE_LOADING_DIR)
- @object.send(@method, "code/../code/load_fixture.rb").should be_true
+ @object.send(@method, "code/../code/load_fixture.rb").should == true
ScratchPad.recorded.should == [:loaded]
end
@@ -203,7 +203,7 @@ describe :kernel_require_basic, shared: true do
sep = File::Separator + File::Separator
path = ["..", "code", "load_fixture.rb"].join(sep)
Dir.chdir CODE_LOADING_DIR do
- @object.send(@method, path).should be_true
+ @object.send(@method, path).should == true
end
ScratchPad.recorded.should == [:loaded]
end
@@ -214,7 +214,7 @@ 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
+ @object.send(@method, path).should == true
# This should _not_ be [:no_ext]
ScratchPad.recorded.should == [:loaded]
end
@@ -223,7 +223,7 @@ describe :kernel_require, shared: true 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(LoadError)
+ -> { @object.send(@method, path) }.should.raise(LoadError)
end
end
@@ -231,20 +231,20 @@ describe :kernel_require, shared: true 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(LoadError)
+ -> { @object.send(@method, path) }.should.raise(LoadError)
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)
+ -> { @object.send(@method, path) }.should.raise(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
Dir.chdir CODE_LOADING_DIR do
- -> { @object.require("load_fixture.rb") }.should raise_error(LoadError)
+ -> { @object.require("load_fixture.rb") }.should.raise(LoadError)
ScratchPad.recorded.should == []
end
end
@@ -253,7 +253,7 @@ describe :kernel_require, shared: true do
Dir.chdir File.dirname(CODE_LOADING_DIR) do
-> do
@object.require("code/load_fixture.rb")
- end.should raise_error(LoadError)
+ end.should.raise(LoadError)
ScratchPad.recorded.should == []
end
end
@@ -261,20 +261,18 @@ describe :kernel_require, shared: true do
it "loads a file that recursively requires itself" do
path = File.expand_path "recursive_require_fixture.rb", CODE_LOADING_DIR
-> {
- @object.require(path).should be_true
+ @object.require(path).should == true
}.should complain(/circular require considered harmful/, verbose: true)
ScratchPad.recorded.should == [:loaded]
end
- ruby_bug "#17340", ''...'3.3' do
- it "loads a file concurrently" do
- path = File.expand_path "concurrent_require_fixture.rb", CODE_LOADING_DIR
- ScratchPad.record(@object)
- -> {
- @object.require(path)
- }.should_not complain(/circular require considered harmful/, verbose: true)
- ScratchPad.recorded.join
- end
+ it "loads a file concurrently" do
+ path = File.expand_path "concurrent_require_fixture.rb", CODE_LOADING_DIR
+ ScratchPad.record(@object)
+ -> {
+ @object.require(path)
+ }.should_not complain(/circular require considered harmful/, verbose: true)
+ ScratchPad.recorded.join
end
end
@@ -286,15 +284,15 @@ describe :kernel_require, shared: true do
end
it "loads a .rb extensioned file when a C-extension file exists on an earlier load path" do
- @object.require("load_fixture").should be_true
+ @object.require("load_fixture").should == true
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
+ @object.require("load_fixture").should == true
$LOAD_PATH.replace [File.expand_path("b", CODE_LOADING_DIR), CODE_LOADING_DIR]
- @object.require("load_fixture").should be_false
+ @object.require("load_fixture").should == false
end
it "stores the missing path in a LoadError object" do
@@ -302,7 +300,7 @@ describe :kernel_require, shared: true do
-> {
@object.send(@method, path)
- }.should raise_error(LoadError) { |e|
+ }.should.raise(LoadError) { |e|
e.path.should == path
}
end
@@ -312,7 +310,7 @@ describe :kernel_require, shared: true do
it "loads a .rb extensioned file when passed a non-extensioned path" do
path = File.expand_path "load_fixture", CODE_LOADING_DIR
File.should.exist?(path)
- @object.require(path).should be_true
+ @object.require(path).should == true
ScratchPad.recorded.should == [:loaded]
end
@@ -322,21 +320,21 @@ describe :kernel_require, shared: true do
$LOADED_FEATURES << File.expand_path("load_fixture.so", CODE_LOADING_DIR)
$LOADED_FEATURES << File.expand_path("load_fixture.dll", CODE_LOADING_DIR)
path = File.expand_path "load_fixture", CODE_LOADING_DIR
- @object.require(path).should be_true
+ @object.require(path).should == true
ScratchPad.recorded.should == [:loaded]
end
it "does not load a C-extension file if a .rb extensioned file is already loaded" do
$LOADED_FEATURES << File.expand_path("load_fixture.rb", CODE_LOADING_DIR)
path = File.expand_path "load_fixture", CODE_LOADING_DIR
- @object.require(path).should be_false
+ @object.require(path).should == false
ScratchPad.recorded.should == []
end
it "loads a .rb extensioned file when passed a non-.rb extensioned path" do
path = File.expand_path "load_fixture.ext", CODE_LOADING_DIR
File.should.exist?(path)
- @object.require(path).should be_true
+ @object.require(path).should == true
ScratchPad.recorded.should == [:loaded]
end
@@ -346,14 +344,14 @@ describe :kernel_require, shared: true do
$LOADED_FEATURES << File.expand_path("load_fixture.ext.so", CODE_LOADING_DIR)
$LOADED_FEATURES << File.expand_path("load_fixture.ext.dll", CODE_LOADING_DIR)
path = File.expand_path "load_fixture.ext", CODE_LOADING_DIR
- @object.require(path).should be_true
+ @object.require(path).should == true
ScratchPad.recorded.should == [:loaded]
end
it "does not load a C-extension file if a complex-extensioned .rb file is already loaded" do
$LOADED_FEATURES << File.expand_path("load_fixture.ext.rb", CODE_LOADING_DIR)
path = File.expand_path "load_fixture.ext", CODE_LOADING_DIR
- @object.require(path).should be_false
+ @object.require(path).should == false
ScratchPad.recorded.should == []
end
end
@@ -364,8 +362,8 @@ describe :kernel_require, shared: true do
end
it "stores an absolute path" do
- @object.require(@path).should be_true
- $LOADED_FEATURES.should include(@path)
+ @object.require(@path).should == true
+ $LOADED_FEATURES.should.include?(@path)
end
platform_is_not :windows do
@@ -385,23 +383,23 @@ describe :kernel_require, shared: true do
it "does not canonicalize the path and stores a path with symlinks" do
symlink_path = "#{@symlink_to_code_dir}/load_fixture.rb"
canonical_path = "#{CODE_LOADING_DIR}/load_fixture.rb"
- @object.require(symlink_path).should be_true
+ @object.require(symlink_path).should == true
ScratchPad.recorded.should == [:loaded]
features = $LOADED_FEATURES.select { |path| path.end_with?('load_fixture.rb') }
- features.should include(symlink_path)
- features.should_not include(canonical_path)
+ features.should.include?(symlink_path)
+ features.should_not.include?(canonical_path)
end
it "stores the same path that __FILE__ returns in the required file" do
symlink_path = "#{@symlink_to_code_dir}/load_fixture_and__FILE__.rb"
- @object.require(symlink_path).should be_true
+ @object.require(symlink_path).should == true
loaded_feature = $LOADED_FEATURES.last
ScratchPad.recorded.should == [loaded_feature]
end
it "requires only once when a new matching file added to path" do
- @object.require('load_fixture').should be_true
+ @object.require('load_fixture').should == true
ScratchPad.recorded.should == [:loaded]
symlink_to_code_dir_two = tmp("codesymlinktwo")
@@ -409,7 +407,7 @@ describe :kernel_require, shared: true do
begin
$LOAD_PATH.unshift(symlink_to_code_dir_two)
- @object.require('load_fixture').should be_false
+ @object.require('load_fixture').should == false
ensure
rm_r symlink_to_code_dir_two
end
@@ -435,7 +433,7 @@ describe :kernel_require, shared: true do
it "canonicalizes the entry in $LOAD_PATH but not the filename passed to #require" do
$LOAD_PATH.unshift(@symlink_to_dir)
- @object.require("symfile").should be_true
+ @object.require("symfile").should == true
loaded_feature = "#{@dir}/symfile.rb"
ScratchPad.recorded.should == [loaded_feature]
$".last.should == loaded_feature
@@ -447,20 +445,20 @@ describe :kernel_require, shared: true do
it "does not store the path if the load fails" do
$LOAD_PATH << CODE_LOADING_DIR
saved_loaded_features = $LOADED_FEATURES.dup
- -> { @object.require("raise_fixture.rb") }.should raise_error(RuntimeError)
+ -> { @object.require("raise_fixture.rb") }.should.raise(RuntimeError)
$LOADED_FEATURES.should == saved_loaded_features
end
it "does not load an absolute path that is already stored" do
$LOADED_FEATURES << @path
- @object.require(@path).should be_false
+ @object.require(@path).should == false
ScratchPad.recorded.should == []
end
it "does not load a ./ relative path that is already stored" do
$LOADED_FEATURES << "./load_fixture.rb"
Dir.chdir CODE_LOADING_DIR do
- @object.require("./load_fixture.rb").should be_false
+ @object.require("./load_fixture.rb").should == false
end
ScratchPad.recorded.should == []
end
@@ -468,7 +466,7 @@ describe :kernel_require, shared: true do
it "does not load a ../ relative path that is already stored" do
$LOADED_FEATURES << "../load_fixture.rb"
Dir.chdir CODE_LOADING_DIR do
- @object.require("../load_fixture.rb").should be_false
+ @object.require("../load_fixture.rb").should == false
end
ScratchPad.recorded.should == []
end
@@ -476,27 +474,27 @@ describe :kernel_require, shared: true do
it "does not load a non-canonical path that is already stored" do
$LOADED_FEATURES << "code/../code/load_fixture.rb"
$LOAD_PATH << File.dirname(CODE_LOADING_DIR)
- @object.require("code/../code/load_fixture.rb").should be_false
+ @object.require("code/../code/load_fixture.rb").should == false
ScratchPad.recorded.should == []
end
it "respects being replaced with a new array" do
prev = $LOADED_FEATURES.dup
- @object.require(@path).should be_true
- $LOADED_FEATURES.should include(@path)
+ @object.require(@path).should == true
+ $LOADED_FEATURES.should.include?(@path)
$LOADED_FEATURES.replace(prev)
- $LOADED_FEATURES.should_not include(@path)
- @object.require(@path).should be_true
- $LOADED_FEATURES.should include(@path)
+ $LOADED_FEATURES.should_not.include?(@path)
+ @object.require(@path).should == true
+ $LOADED_FEATURES.should.include?(@path)
end
it "does not load twice the same file with and without extension" do
$LOAD_PATH << CODE_LOADING_DIR
- @object.require("load_fixture.rb").should be_true
- @object.require("load_fixture").should be_false
+ @object.require("load_fixture.rb").should == true
+ @object.require("load_fixture").should == false
end
describe "when a non-extensioned file is in $LOADED_FEATURES" do
@@ -506,19 +504,19 @@ describe :kernel_require, shared: true do
it "loads a .rb extensioned file when a non extensioned file is in $LOADED_FEATURES" do
$LOAD_PATH << CODE_LOADING_DIR
- @object.require("load_fixture").should be_true
+ @object.require("load_fixture").should == true
ScratchPad.recorded.should == [:loaded]
end
it "loads a .rb extensioned file from a subdirectory" do
$LOAD_PATH << File.dirname(CODE_LOADING_DIR)
- @object.require("code/load_fixture").should be_true
+ @object.require("code/load_fixture").should == true
ScratchPad.recorded.should == [:loaded]
end
it "returns false if the file is not found" do
Dir.chdir File.dirname(CODE_LOADING_DIR) do
- @object.require("load_fixture").should be_false
+ @object.require("load_fixture").should == false
ScratchPad.recorded.should == []
end
end
@@ -526,7 +524,7 @@ describe :kernel_require, shared: true do
it "returns false when passed a path and the file is not found" do
$LOADED_FEATURES << "code/load_fixture"
Dir.chdir CODE_LOADING_DIR do
- @object.require("code/load_fixture").should be_false
+ @object.require("code/load_fixture").should == false
ScratchPad.recorded.should == []
end
end
@@ -534,16 +532,16 @@ describe :kernel_require, shared: true do
it "stores ../ relative paths as absolute paths" do
Dir.chdir CODE_LOADING_DIR do
- @object.require("../code/load_fixture.rb").should be_true
+ @object.require("../code/load_fixture.rb").should == true
end
- $LOADED_FEATURES.should include(@path)
+ $LOADED_FEATURES.should.include?(@path)
end
it "stores ./ relative paths as absolute paths" do
Dir.chdir CODE_LOADING_DIR do
- @object.require("./load_fixture.rb").should be_true
+ @object.require("./load_fixture.rb").should == true
end
- $LOADED_FEATURES.should include(@path)
+ $LOADED_FEATURES.should.include?(@path)
end
it "collapses duplicate path separators" do
@@ -551,27 +549,27 @@ describe :kernel_require, shared: true do
sep = File::Separator + File::Separator
path = ["..", "code", "load_fixture.rb"].join(sep)
Dir.chdir CODE_LOADING_DIR do
- @object.require(path).should be_true
+ @object.require(path).should == true
end
- $LOADED_FEATURES.should include(@path)
+ $LOADED_FEATURES.should.include?(@path)
end
it "expands absolute paths containing .." do
path = File.join CODE_LOADING_DIR, "..", "code", "load_fixture.rb"
- @object.require(path).should be_true
- $LOADED_FEATURES.should include(@path)
+ @object.require(path).should == true
+ $LOADED_FEATURES.should.include?(@path)
end
it "adds the suffix of the resolved filename" do
$LOAD_PATH << CODE_LOADING_DIR
- @object.require("load_fixture").should be_true
- $LOADED_FEATURES.should include(@path)
+ @object.require("load_fixture").should == true
+ $LOADED_FEATURES.should.include?(@path)
end
it "does not load a non-canonical path for a file already loaded" do
$LOADED_FEATURES << @path
$LOAD_PATH << File.dirname(CODE_LOADING_DIR)
- @object.require("code/../code/load_fixture.rb").should be_false
+ @object.require("code/../code/load_fixture.rb").should == false
ScratchPad.recorded.should == []
end
@@ -579,7 +577,7 @@ describe :kernel_require, shared: true do
$LOADED_FEATURES << @path
$LOAD_PATH << "an_irrelevant_dir"
Dir.chdir CODE_LOADING_DIR do
- @object.require("./load_fixture.rb").should be_false
+ @object.require("./load_fixture.rb").should == false
end
ScratchPad.recorded.should == []
end
@@ -588,7 +586,7 @@ describe :kernel_require, shared: true do
$LOADED_FEATURES << @path
$LOAD_PATH << "an_irrelevant_dir"
Dir.chdir CODE_LOADING_DIR do
- @object.require("../code/load_fixture.rb").should be_false
+ @object.require("../code/load_fixture.rb").should == false
end
ScratchPad.recorded.should == []
end
@@ -596,26 +594,26 @@ describe :kernel_require, shared: true do
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|
- feature.should_not include("unicode_normalize")
+ feature.should_not.include?("unicode_normalize")
}
- -> { @object.require("unicode_normalize") }.should raise_error(LoadError)
+ -> { @object.require("unicode_normalize") }.should.raise(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
+ @object.send(@method, "../code/load_fixture").should == 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
+ @object.send(@method, "load_fixture").should == 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
+ @object.send(@method, "load_fixture").should == false
ScratchPad.recorded.should == [:loaded, :loaded]
end
end
@@ -633,13 +631,13 @@ describe :kernel_require, shared: true do
# "#3171"
it "performs tilde expansion on a .rb file before storing paths in $LOADED_FEATURES" do
- @object.require("~/load_fixture.rb").should be_true
- $LOADED_FEATURES.should include(@path)
+ @object.require("~/load_fixture.rb").should == true
+ $LOADED_FEATURES.should.include?(@path)
end
it "performs tilde expansion on a non-extensioned file before storing paths in $LOADED_FEATURES" do
- @object.require("~/load_fixture").should be_true
- $LOADED_FEATURES.should include(@path)
+ @object.require("~/load_fixture").should == true
+ $LOADED_FEATURES.should.include?(@path)
end
end
@@ -696,8 +694,8 @@ describe :kernel_require, shared: true do
t1.join
t2.join
- t1_res.should be_true
- t2_res.should be_false
+ t1_res.should == true
+ t2_res.should == false
ScratchPad.recorded.should == [:con_pre, :con_post, :t2_post, :t1_post]
end
@@ -721,8 +719,8 @@ describe :kernel_require, shared: true do
t1.join
t2.join
- t1_res.should be_true
- t2_res.should be_true
+ t1_res.should == true
+ t2_res.should == true
ScratchPad.recorded.should == [:con2_pre, :con3, :con2_post]
end
@@ -740,7 +738,7 @@ describe :kernel_require, shared: true do
-> {
@object.require(@path)
- }.should raise_error(RuntimeError)
+ }.should.raise(RuntimeError)
Thread.pass until fin
ScratchPad.recorded << :t1_post
@@ -761,7 +759,7 @@ describe :kernel_require, shared: true do
t1.join
t2.join
- t2_res.should be_true
+ t2_res.should == true
ScratchPad.recorded.should == [:con_pre, :con_pre, :con_post, :t2_post, :t1_post]
end
@@ -781,7 +779,7 @@ describe :kernel_require, shared: true do
-> {
@object.require(@path)
- }.should raise_error(RuntimeError)
+ }.should.raise(RuntimeError)
raised = true
@@ -809,8 +807,8 @@ describe :kernel_require, shared: true do
t1.join
t2.join
- t1_res.should be_false
- t2_res.should be_true
+ t1_res.should == false
+ t2_res.should == true
ScratchPad.recorded.should == [:con_pre, :con_pre, :con_post, :t2_post, :t1_post]
end
@@ -821,7 +819,7 @@ describe :kernel_require, shared: true do
-> {
@object.send(@method, path)
- }.should raise_error(LoadError) { |e|
+ }.should.raise(LoadError) { |e|
e.path.should == path
}
end
@@ -830,7 +828,7 @@ describe :kernel_require, shared: true do
it "does not store the missing path in a LoadError object when c-extension file exists but loading fails and passed absolute path without extension" 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(LoadError) { |e|
+ -> { @object.send(@method, path) }.should.raise(LoadError) { |e|
e.path.should == nil
}
end
@@ -840,7 +838,7 @@ describe :kernel_require, shared: true do
it "does not store the missing path in a LoadError object when c-extension file exists but loading fails and passed absolute path with extension" do
# the error message is specific to what dlerror() returns
path = File.join CODE_LOADING_DIR, "a", "load_fixture.bundle"
- -> { @object.send(@method, path) }.should raise_error(LoadError) { |e|
+ -> { @object.send(@method, path) }.should.raise(LoadError) { |e|
e.path.should == nil
}
end
diff --git a/spec/ruby/core/kernel/shared/sprintf.rb b/spec/ruby/core/kernel/shared/sprintf.rb
index a68389a7b4..e57334c5ab 100644
--- a/spec/ruby/core/kernel/shared/sprintf.rb
+++ b/spec/ruby/core/kernel/shared/sprintf.rb
@@ -28,7 +28,7 @@ describe :kernel_sprintf, shared: true do
it "raises TypeError exception if cannot convert to Integer" do
-> {
@method.call("%b", Object.new)
- }.should raise_error(TypeError)
+ }.should.raise(TypeError)
end
["b", "B"].each do |f|
@@ -58,11 +58,6 @@ describe :kernel_sprintf, shared: true do
it "works well with large numbers" do
@method.call("%#{f}", 1234567890987654321).should == "1234567890987654321"
end
-
- it "converts to the empty string if precision is 0 and value is 0" do
- @method.call("%.#{f}", 0).should == ""
- @method.call("%.0#{f}", 0).should == ""
- end
end
end
@@ -110,6 +105,20 @@ describe :kernel_sprintf, shared: true do
@method.call("%X", -1).should == "..F"
end
end
+
+ %w[b B d i u o x X].each do |f|
+ describe f do
+ it "converts to the empty string if precision is 0 and value is 0" do
+ @method.call("%.#{f}", 0).should == ""
+ @method.call("%.0#{f}", 0).should == ""
+ end
+
+ it "pads the empty string if precision is 0 and value is 0" do
+ @method.call("%2.#{f}", 0).should == " "
+ @method.call("%2.0#{f}", 0).should == " "
+ end
+ end
+ end
end
describe "float formats" do
@@ -122,7 +131,7 @@ describe :kernel_sprintf, shared: true do
it "raises TypeError exception if cannot convert to Float" do
-> {
@method.call("%f", Object.new)
- }.should raise_error(TypeError)
+ }.should.raise(TypeError)
end
{"e" => "e", "E" => "E"}.each_pair do |f, exp|
@@ -299,6 +308,10 @@ describe :kernel_sprintf, shared: true do
@method.call("%c", "abc").should == "a"
end
+ it "displays only the first character if argument is a string of several multibyte characters" do
+ @method.call("%c", "ã‚ã„ã†ãˆãŠ").should == "ã‚"
+ end
+
it "displays no characters if argument is an empty string" do
@method.call("%c", "").should == ""
end
@@ -306,13 +319,13 @@ describe :kernel_sprintf, shared: true do
it "raises TypeError if argument is not String or Integer and cannot be converted to them" do
-> {
@method.call("%c", [])
- }.should raise_error(TypeError, /no implicit conversion of Array into Integer/)
+ }.should raise_consistent_error(TypeError, /no implicit conversion of Array into Integer/)
end
it "raises TypeError if argument is nil" do
-> {
@method.call("%c", nil)
- }.should raise_error(TypeError, /no implicit conversion from nil to integer/)
+ }.should raise_consistent_error(TypeError, /no implicit conversion of nil into Integer/)
end
it "tries to convert argument to String with to_str" do
@@ -341,7 +354,7 @@ describe :kernel_sprintf, shared: true do
-> {
@method.call("%c", obj)
- }.should raise_error(TypeError, /can't convert BasicObject to String/)
+ }.should raise_consistent_error(TypeError, /can't convert BasicObject into String/)
end
it "raises TypeError if converting to Integer with to_int returns non-Integer" do
@@ -352,7 +365,7 @@ describe :kernel_sprintf, shared: true do
-> {
@method.call("%c", obj)
- }.should raise_error(TypeError, /can't convert BasicObject to Integer/)
+ }.should raise_consistent_error(TypeError, /can't convert BasicObject into Integer/)
end
end
@@ -391,7 +404,7 @@ describe :kernel_sprintf, shared: true do
-> {
@method.call("%s", obj)
- }.should raise_error(NoMethodError)
+ }.should.raise(NoMethodError)
end
it "formats a partial substring without including omitted characters" do
@@ -444,12 +457,12 @@ describe :kernel_sprintf, shared: true do
it "alone raises an ArgumentError" do
-> {
@method.call("%")
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
it "is escaped by %" do
@method.call("%%").should == "%"
- @method.call("%%d", 10).should == "%d"
+ @method.call("%%d").should == "%d"
end
end
end
@@ -551,7 +564,7 @@ describe :kernel_sprintf, shared: true do
it "raises exception if argument number is bigger than actual arguments list" do
-> {
@method.call("%4$d", 1, 2, 3)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
it "ignores '-' sign" do
@@ -562,7 +575,7 @@ describe :kernel_sprintf, shared: true do
it "raises ArgumentError exception when absolute and relative argument numbers are mixed" do
-> {
@method.call("%1$d %d", 1, 2)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
end
@@ -594,11 +607,28 @@ describe :kernel_sprintf, shared: true do
@method.call("%#b", 0).should == "0"
@method.call("%#B", 0).should == "0"
- @method.call("%#o", 0).should == "0"
-
@method.call("%#x", 0).should == "0"
@method.call("%#X", 0).should == "0"
end
+
+ it "does nothing for zero argument when combined with zero precision" do
+ @method.call("%#.0b", 0).should == ""
+ @method.call("%#.0B", 0).should == ""
+
+ @method.call("%#.0x", 0).should == ""
+ @method.call("%#.0X", 0).should == ""
+ end
+ end
+
+ context "applies to format o" do
+ it "does nothing for zero argument" do
+ @method.call("%#o", 0).should == "0"
+ @method.call("%#.1o", 0).should == "0"
+ end
+
+ it "increases the precision if precision zero is requested with zero argument" do
+ @method.call("%#.0o", 0).should == "0"
+ end
end
context "applies to formats aAeEfgG" do
@@ -812,7 +842,7 @@ describe :kernel_sprintf, shared: true do
it "raises ArgumentError when is mixed with width" do
-> {
@method.call("%*10d", 10, 112)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
end
end
@@ -911,7 +941,7 @@ describe :kernel_sprintf, shared: true do
it "cannot be mixed with unnamed style" do
-> {
@method.call("%d %<foo>d", 1, foo: "123")
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
end
@@ -931,13 +961,30 @@ describe :kernel_sprintf, shared: true do
it "cannot be mixed with unnamed style" do
-> {
@method.call("%d %{foo}", 1, foo: "123")
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
+ end
+
+ it "respects Hash#default when there is no set key" do
+ @method.call("%{foo}", Hash.new(123)).should == "123"
+ @method.call("%{foo}", Hash.new { 123 }).should == "123"
end
- it "raises KeyError when there is no matching key" do
+ it "raises KeyError when Hash#default returns nil" do
-> {
@method.call("%{foo}", {})
- }.should raise_error(KeyError)
+ }.should.raise(KeyError, 'key{foo} not found')
+
+ -> {
+ @method.call("%{foo}", Hash.new(nil))
+ }.should.raise(KeyError, 'key{foo} not found')
+
+ -> {
+ @method.call("%{foo}", Hash.new { nil })
+ }.should.raise(KeyError, 'key{foo} not found')
+ end
+
+ it "accepts a nil value for an existing key" do
+ @method.call("%{foo}", { foo: nil }).should == ""
end
it "converts value to String with to_s" do
@@ -961,21 +1008,21 @@ describe :kernel_sprintf, shared: true do
it "raises a KeyError" do
-> {
@method.call("%<foo>s", @object)
- }.should raise_error(KeyError)
+ }.should.raise(KeyError)
end
it "sets the Hash as the receiver of KeyError" do
-> {
@method.call("%<foo>s", @object)
- }.should raise_error(KeyError) { |err|
- err.receiver.should equal(@object)
+ }.should.raise(KeyError) { |err|
+ err.receiver.should.equal?(@object)
}
end
it "sets the unmatched key as the key of KeyError" do
-> {
@method.call("%<foo>s", @object)
- }.should raise_error(KeyError) { |err|
+ }.should.raise(KeyError) { |err|
err.key.to_s.should == 'foo'
}
end
@@ -984,4 +1031,27 @@ describe :kernel_sprintf, shared: true do
it "does not raise error when passed more arguments than needed" do
sprintf("%s %d %c", "string", 2, "c", []).should == "string 2 c"
end
+
+ describe "when $VERBOSE is true" do
+ it "warns if too many arguments are passed" do
+ -> {
+ format("test", 1)
+ }.should complain(/too many arguments for format string/, verbose: true)
+ end
+
+ it "does not warns if too many keyword arguments are passed" do
+ -> {
+ format("test %{test}", test: 1, unused: 2)
+ }.should_not complain(verbose: true)
+ end
+
+ ruby_bug "#20593", ""..."3.4" do
+ it "doesn't warns if keyword arguments are passed and none are used" do
+ -> {
+ format("test", test: 1)
+ format("test", {})
+ }.should_not complain(verbose: true)
+ end
+ end
+ end
end
diff --git a/spec/ruby/core/kernel/shared/sprintf_encoding.rb b/spec/ruby/core/kernel/shared/sprintf_encoding.rb
index 7ec0fe4c48..849c95cbb7 100644
--- a/spec/ruby/core/kernel/shared/sprintf_encoding.rb
+++ b/spec/ruby/core/kernel/shared/sprintf_encoding.rb
@@ -4,19 +4,19 @@ describe :kernel_sprintf_encoding, shared: true do
it "can produce a string with valid encoding" do
string = @method.call("good day %{valid}", valid: "e")
string.encoding.should == Encoding::UTF_8
- string.valid_encoding?.should be_true
+ string.valid_encoding?.should == true
end
it "can produce a string with invalid encoding" do
string = @method.call("good day %{invalid}", invalid: "\x80")
string.encoding.should == Encoding::UTF_8
- string.valid_encoding?.should be_false
+ string.valid_encoding?.should == false
end
it "returns a String in the same encoding as the format String if compatible" do
string = "%s".dup.force_encoding(Encoding::KOI8_U)
result = @method.call(string, "dogs")
- result.encoding.should equal(Encoding::KOI8_U)
+ result.encoding.should.equal?(Encoding::KOI8_U)
end
it "returns a String in the argument's encoding if format encoding is more restrictive" do
@@ -24,7 +24,7 @@ describe :kernel_sprintf_encoding, shared: true do
argument = "b\303\274r".dup.force_encoding(Encoding::UTF_8)
result = @method.call(string, argument)
- result.encoding.should equal(Encoding::UTF_8)
+ result.encoding.should.equal?(Encoding::UTF_8)
end
it "raises Encoding::CompatibilityError if both encodings are ASCII compatible and there are not ASCII characters" do
@@ -33,7 +33,7 @@ describe :kernel_sprintf_encoding, shared: true do
-> {
@method.call(string, argument)
- }.should raise_error(Encoding::CompatibilityError)
+ }.should.raise(Encoding::CompatibilityError)
end
describe "%c" do
@@ -52,7 +52,7 @@ describe :kernel_sprintf_encoding, shared: true do
-> {
@method.call(format, 1286)
- }.should raise_error(RangeError, /out of char range/)
+ }.should.raise(RangeError, /out of char range/)
end
it "uses the encoding of the format string to interpret codepoints" do
diff --git a/spec/ruby/core/kernel/shared/then.rb b/spec/ruby/core/kernel/shared/then.rb
index b52075371f..c71393bf50 100644
--- a/spec/ruby/core/kernel/shared/then.rb
+++ b/spec/ruby/core/kernel/shared/then.rb
@@ -1,20 +1,20 @@
describe :kernel_then, shared: true do
it "yields self" do
object = Object.new
- object.send(@method) { |o| o.should equal object }
+ object.send(@method) { |o| o.should.equal? object }
end
it "returns the block return value" do
object = Object.new
- object.send(@method) { 42 }.should equal 42
+ object.send(@method) { 42 }.should.equal? 42
end
it "returns a sized Enumerator when no block given" do
object = Object.new
enum = object.send(@method)
- enum.should be_an_instance_of Enumerator
- enum.size.should equal 1
- enum.peek.should equal object
- enum.first.should equal object
+ enum.should.instance_of? Enumerator
+ enum.size.should.equal? 1
+ enum.peek.should.equal? object
+ enum.first.should.equal? object
end
end
diff --git a/spec/ruby/core/kernel/singleton_class_spec.rb b/spec/ruby/core/kernel/singleton_class_spec.rb
index 23c400f9bd..7915272937 100644
--- a/spec/ruby/core/kernel/singleton_class_spec.rb
+++ b/spec/ruby/core/kernel/singleton_class_spec.rb
@@ -21,27 +21,27 @@ describe "Kernel#singleton_class" do
end
it "raises TypeError for Integer" do
- -> { 123.singleton_class }.should raise_error(TypeError, "can't define singleton")
+ -> { 123.singleton_class }.should.raise(TypeError, "can't define singleton")
end
it "raises TypeError for Float" do
- -> { 3.14.singleton_class }.should raise_error(TypeError, "can't define singleton")
+ -> { 3.14.singleton_class }.should.raise(TypeError, "can't define singleton")
end
it "raises TypeError for Symbol" do
- -> { :foo.singleton_class }.should raise_error(TypeError, "can't define singleton")
+ -> { :foo.singleton_class }.should.raise(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")
+ -> { (-"string").singleton_class }.should.raise(TypeError, "can't define singleton")
+ -> { a = -"string"; a.singleton_class }.should.raise(TypeError, "can't define singleton")
+ -> { a = "string"; (-a).singleton_class }.should.raise(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
+ obj.singleton_class.frozen?.should == true
end
context "for an IO object with a replaced singleton class" do
diff --git a/spec/ruby/core/kernel/singleton_method_spec.rb b/spec/ruby/core/kernel/singleton_method_spec.rb
index 0bdf125ad8..fe8e23eb02 100644
--- a/spec/ruby/core/kernel/singleton_method_spec.rb
+++ b/spec/ruby/core/kernel/singleton_method_spec.rb
@@ -1,10 +1,10 @@
require_relative '../../spec_helper'
describe "Kernel#singleton_method" do
- it "find a method defined on the singleton class" do
+ it "finds a method defined on the singleton class" do
obj = Object.new
def obj.foo; end
- obj.singleton_method(:foo).should be_an_instance_of(Method)
+ obj.singleton_method(:foo).should.instance_of?(Method)
end
it "returns a Method which can be called" do
@@ -23,7 +23,7 @@ describe "Kernel#singleton_method" do
obj.foo.should == 42
-> {
obj.singleton_method(:foo)
- }.should raise_error(NameError) { |e|
+ }.should.raise(NameError) { |e|
# a NameError and not a NoMethodError
e.class.should == NameError
}
@@ -33,9 +33,53 @@ describe "Kernel#singleton_method" do
obj = Object.new
-> {
obj.singleton_method(:not_existing)
- }.should raise_error(NameError) { |e|
+ }.should.raise(NameError) { |e|
# a NameError and not a NoMethodError
e.class.should == NameError
}
end
+
+ ruby_bug "#20620", ""..."3.4" do
+ it "finds a method defined in a module included in the singleton class" do
+ m = Module.new do
+ def foo
+ :foo
+ end
+ end
+
+ obj = Object.new
+ obj.singleton_class.include(m)
+
+ obj.singleton_method(:foo).should.instance_of?(Method)
+ obj.singleton_method(:foo).call.should == :foo
+ end
+
+ it "finds a method defined in a module prepended in the singleton class" do
+ m = Module.new do
+ def foo
+ :foo
+ end
+ end
+
+ obj = Object.new
+ obj.singleton_class.prepend(m)
+
+ obj.singleton_method(:foo).should.instance_of?(Method)
+ obj.singleton_method(:foo).call.should == :foo
+ end
+
+ it "finds a method defined in a module that an object is extended with" do
+ m = Module.new do
+ def foo
+ :foo
+ end
+ end
+
+ obj = Object.new
+ obj.extend(m)
+
+ obj.singleton_method(:foo).should.instance_of?(Method)
+ obj.singleton_method(:foo).call.should == :foo
+ end
+ end
end
diff --git a/spec/ruby/core/kernel/singleton_methods_spec.rb b/spec/ruby/core/kernel/singleton_methods_spec.rb
index a127a439de..a7f6969519 100644
--- a/spec/ruby/core/kernel/singleton_methods_spec.rb
+++ b/spec/ruby/core/kernel/singleton_methods_spec.rb
@@ -8,33 +8,33 @@ describe :kernel_singleton_methods, shared: true do
end
it "returns the names of module methods for a module" do
- ReflectSpecs::M.singleton_methods(*@object).should include(:ms_pro, :ms_pub)
+ ReflectSpecs::M.singleton_methods(*@object).to_set.should >= Set[:ms_pro, :ms_pub]
end
it "does not return private module methods for a module" do
- ReflectSpecs::M.singleton_methods(*@object).should_not include(:ms_pri)
+ ReflectSpecs::M.singleton_methods(*@object).should_not.include?(:ms_pri)
end
it "returns the names of class methods for a class" do
- ReflectSpecs::A.singleton_methods(*@object).should include(:as_pro, :as_pub)
+ ReflectSpecs::A.singleton_methods(*@object).to_set.should >= Set[:as_pro, :as_pub]
end
it "does not return private class methods for a class" do
- ReflectSpecs::A.singleton_methods(*@object).should_not include(:as_pri)
+ ReflectSpecs::A.singleton_methods(*@object).should_not.include?(:as_pri)
end
it "returns the names of singleton methods for an object" do
- ReflectSpecs.os.singleton_methods(*@object).should include(:os_pro, :os_pub)
+ ReflectSpecs.os.singleton_methods(*@object).to_set.should >= Set[:os_pro, :os_pub]
end
end
describe :kernel_singleton_methods_modules, shared: true do
it "does not return any included methods for a module including a module" do
- ReflectSpecs::N.singleton_methods(*@object).should include(:ns_pro, :ns_pub)
+ ReflectSpecs::N.singleton_methods(*@object).to_set.should >= Set[:ns_pro, :ns_pub]
end
it "does not return any included methods for a class including a module" do
- ReflectSpecs::D.singleton_methods(*@object).should include(:ds_pro, :ds_pub)
+ ReflectSpecs::D.singleton_methods(*@object).to_set.should >= Set[:ds_pro, :ds_pub]
end
it "for a module does not return methods in a module prepended to Module itself" do
@@ -44,7 +44,7 @@ describe :kernel_singleton_methods_modules, shared: true do
ancestors = mod.singleton_class.ancestors
ancestors[0...2].should == [ mod.singleton_class, mod ]
- ancestors.should include(SingletonMethodsSpecs::Prepended)
+ ancestors.should.include?(SingletonMethodsSpecs::Prepended)
# Do not search prepended modules of `Module`, as that's a non-singleton class
mod.singleton_methods.should == []
@@ -53,7 +53,7 @@ end
describe :kernel_singleton_methods_supers, shared: true do
it "returns the names of singleton methods for an object extended with a module" do
- ReflectSpecs.oe.singleton_methods(*@object).should include(:m_pro, :m_pub)
+ ReflectSpecs.oe.singleton_methods(*@object).to_set.should >= Set[:m_pro, :m_pub]
end
it "returns a unique list for an object extended with a module" do
@@ -63,15 +63,15 @@ describe :kernel_singleton_methods_supers, shared: true do
end
it "returns the names of singleton methods for an object extended with two modules" do
- ReflectSpecs.oee.singleton_methods(*@object).should include(:m_pro, :m_pub, :n_pro, :n_pub)
+ ReflectSpecs.oee.singleton_methods(*@object).to_set.should >= Set[:m_pro, :m_pub, :n_pro, :n_pub]
end
it "returns the names of singleton methods for an object extended with a module including a module" do
- ReflectSpecs.oei.singleton_methods(*@object).should include(:n_pro, :n_pub, :m_pro, :m_pub)
+ ReflectSpecs.oei.singleton_methods(*@object).to_set.should >= Set[:n_pro, :n_pub, :m_pro, :m_pub]
end
it "returns the names of inherited singleton methods for a subclass" do
- ReflectSpecs::B.singleton_methods(*@object).should include(:as_pro, :as_pub, :bs_pro, :bs_pub)
+ ReflectSpecs::B.singleton_methods(*@object).to_set.should >= Set[:as_pro, :as_pub, :bs_pro, :bs_pub]
end
it "returns a unique list for a subclass" do
@@ -81,7 +81,7 @@ describe :kernel_singleton_methods_supers, shared: true do
end
it "returns the names of inherited singleton methods for a subclass including a module" do
- ReflectSpecs::C.singleton_methods(*@object).should include(:as_pro, :as_pub, :cs_pro, :cs_pub)
+ ReflectSpecs::C.singleton_methods(*@object).to_set.should >= Set[:as_pro, :as_pub, :cs_pro, :cs_pub]
end
it "returns a unique list for a subclass including a module" do
@@ -91,57 +91,62 @@ describe :kernel_singleton_methods_supers, shared: true do
end
it "returns the names of inherited singleton methods for a subclass of a class including a module" do
- ReflectSpecs::E.singleton_methods(*@object).should include(:ds_pro, :ds_pub, :es_pro, :es_pub)
+ ReflectSpecs::E.singleton_methods(*@object).to_set.should >= Set[:ds_pro, :ds_pub, :es_pro, :es_pub]
end
it "returns the names of inherited singleton methods for a subclass of a class that includes a module, where the subclass also includes a module" do
- ReflectSpecs::F.singleton_methods(*@object).should include(:ds_pro, :ds_pub, :fs_pro, :fs_pub)
+ ReflectSpecs::F.singleton_methods(*@object).to_set.should >= Set[:ds_pro, :ds_pub, :fs_pro, :fs_pub]
end
it "returns the names of inherited singleton methods for a class extended with a module" do
- ReflectSpecs::P.singleton_methods(*@object).should include(:m_pro, :m_pub)
+ ReflectSpecs::P.singleton_methods(*@object).to_set.should >= Set[:m_pro, :m_pub]
end
end
describe :kernel_singleton_methods_private_supers, shared: true do
it "does not return private singleton methods for an object extended with a module" do
- ReflectSpecs.oe.singleton_methods(*@object).should_not include(:m_pri)
+ ReflectSpecs.oe.singleton_methods(*@object).should_not.include?(:m_pri)
end
it "does not return private singleton methods for an object extended with two modules" do
- ReflectSpecs.oee.singleton_methods(*@object).should_not include(:m_pri)
+ ReflectSpecs.oee.singleton_methods(*@object).should_not.include?(:m_pri)
end
it "does not return private singleton methods for an object extended with a module including a module" do
- ReflectSpecs.oei.singleton_methods(*@object).should_not include(:n_pri, :m_pri)
+ ReflectSpecs.oei.singleton_methods(*@object).should_not.include?(:n_pri)
+ ReflectSpecs.oei.singleton_methods(*@object).should_not.include?(:m_pri)
end
it "does not return private singleton methods for a class extended with a module" do
- ReflectSpecs::P.singleton_methods(*@object).should_not include(:m_pri)
+ ReflectSpecs::P.singleton_methods(*@object).should_not.include?(:m_pri)
end
it "does not return private inherited singleton methods for a module including a module" do
- ReflectSpecs::N.singleton_methods(*@object).should_not include(:ns_pri)
+ ReflectSpecs::N.singleton_methods(*@object).should_not.include?(:ns_pri)
end
it "does not return private inherited singleton methods for a class including a module" do
- ReflectSpecs::D.singleton_methods(*@object).should_not include(:ds_pri)
+ ReflectSpecs::D.singleton_methods(*@object).should_not.include?(:ds_pri)
end
it "does not return private inherited singleton methods for a subclass" do
- ReflectSpecs::B.singleton_methods(*@object).should_not include(:as_pri, :bs_pri)
+ ReflectSpecs::B.singleton_methods(*@object).should_not.include?(:as_pri)
+ ReflectSpecs::B.singleton_methods(*@object).should_not.include?(:bs_pri)
end
it "does not return private inherited singleton methods for a subclass including a module" do
- ReflectSpecs::C.singleton_methods(*@object).should_not include(:as_pri, :cs_pri)
+ ReflectSpecs::C.singleton_methods(*@object).should_not.include?(:as_pri)
+ ReflectSpecs::C.singleton_methods(*@object).should_not.include?(:cs_pri)
end
it "does not return private inherited singleton methods for a subclass of a class including a module" do
- ReflectSpecs::E.singleton_methods(*@object).should_not include(:ds_pri, :es_pri)
+ ReflectSpecs::E.singleton_methods(*@object).should_not.include?(:ds_pri)
+ ReflectSpecs::E.singleton_methods(*@object).should_not.include?(:es_pri)
end
it "does not return private inherited singleton methods for a subclass of a class that includes a module, where the subclass also includes a module" do
- ReflectSpecs::F.singleton_methods(*@object).should_not include(:ds_pri, :fs_pri)
+ ReflectSpecs::F.singleton_methods(*@object).should_not.include?(:ds_pri)
+ ReflectSpecs::F.singleton_methods(*@object).should_not.include?(:fs_pri)
end
end
@@ -178,15 +183,17 @@ describe "Kernel#singleton_methods" do
end
it "returns the names of singleton methods of the subclass" do
- ReflectSpecs::B.singleton_methods(false).should include(:bs_pro, :bs_pub)
+ ReflectSpecs::B.singleton_methods(false).to_set.should >= Set[:bs_pro, :bs_pub]
end
it "does not return names of inherited singleton methods for a subclass" do
- ReflectSpecs::B.singleton_methods(false).should_not include(:as_pro, :as_pub)
+ ReflectSpecs::B.singleton_methods(false).should_not.include?(:as_pro)
+ ReflectSpecs::B.singleton_methods(false).should_not.include?(:as_pub)
end
it "does not return the names of inherited singleton methods for a class extended with a module" do
- ReflectSpecs::P.singleton_methods(false).should_not include(:m_pro, :m_pub)
+ ReflectSpecs::P.singleton_methods(false).should_not.include?(:m_pro)
+ ReflectSpecs::P.singleton_methods(false).should_not.include?(:m_pub)
end
end
end
diff --git a/spec/ruby/core/kernel/sleep_spec.rb b/spec/ruby/core/kernel/sleep_spec.rb
index 4401e54256..61d8cc2380 100644
--- a/spec/ruby/core/kernel/sleep_spec.rb
+++ b/spec/ruby/core/kernel/sleep_spec.rb
@@ -1,12 +1,13 @@
require_relative '../../spec_helper'
+require_relative '../fiber/fixtures/scheduler'
describe "Kernel#sleep" do
it "is a private method" do
- Kernel.should have_private_instance_method(:sleep)
+ Kernel.private_instance_methods(false).should.include?(:sleep)
end
it "returns an Integer" do
- sleep(0.001).should be_kind_of(Integer)
+ sleep(0.001).should.is_a?(Integer)
end
it "accepts a Float" do
@@ -28,12 +29,12 @@ describe "Kernel#sleep" do
end
it "raises an ArgumentError when passed a negative duration" do
- -> { sleep(-0.1) }.should raise_error(ArgumentError)
- -> { sleep(-1) }.should raise_error(ArgumentError)
+ -> { sleep(-0.1) }.should.raise(ArgumentError)
+ -> { sleep(-1) }.should.raise(ArgumentError)
end
it "raises a TypeError when passed a String" do
- -> { sleep('2') }.should raise_error(TypeError)
+ -> { sleep('2') }.should.raise(TypeError)
end
it "pauses execution indefinitely if not given a duration" do
@@ -62,26 +63,52 @@ describe "Kernel#sleep" do
actual_duration.should > 0.01 # 100 * 0.0001 => 0.01
end
- ruby_version_is ""..."3.3" do
- it "raises a TypeError when passed nil" do
- -> { sleep(nil) }.should raise_error(TypeError)
+ 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
- ruby_version_is "3.3" do
- it "accepts a nil duration" do
- running = false
- t = Thread.new do
- running = true
- sleep(nil)
- 5
+ context "Kernel.sleep with Fiber scheduler" do
+ before :each do
+ Fiber.set_scheduler(FiberSpecs::LoggingScheduler.new)
+ end
+
+ after :each do
+ Fiber.set_scheduler(nil)
+ end
+
+ it "calls the scheduler without arguments when no duration is given" do
+ sleeper = Fiber.new(blocking: false) do
+ sleep
end
+ sleeper.resume
+ Fiber.scheduler.events.should == [{ event: :kernel_sleep, fiber: sleeper, args: [] }]
+ end
- Thread.pass until running
- Thread.pass while t.status and t.status != "sleep"
+ it "calls the scheduler with the given duration" do
+ sleeper = Fiber.new(blocking: false) do
+ sleep(0.01)
+ end
+ sleeper.resume
+ Fiber.scheduler.events.should == [{ event: :kernel_sleep, fiber: sleeper, args: [0.01] }]
+ end
- t.wakeup
- t.value.should == 5
+ it "does not call the scheduler if the fiber is blocking" do
+ sleeper = Fiber.new(blocking: true) do
+ sleep(0.01)
+ end
+ sleeper.resume
+ Fiber.scheduler.events.should == []
end
end
end
diff --git a/spec/ruby/core/kernel/spawn_spec.rb b/spec/ruby/core/kernel/spawn_spec.rb
index ba05b629d5..3432fc31da 100644
--- a/spec/ruby/core/kernel/spawn_spec.rb
+++ b/spec/ruby/core/kernel/spawn_spec.rb
@@ -6,7 +6,7 @@ require_relative 'fixtures/classes'
# run here as it is redundant and takes too long for little gain.
describe "Kernel#spawn" do
it "is a private method" do
- Kernel.should have_private_instance_method(:spawn)
+ Kernel.private_instance_methods(false).should.include?(:spawn)
end
it "executes the given command" do
diff --git a/spec/ruby/core/kernel/sprintf_spec.rb b/spec/ruby/core/kernel/sprintf_spec.rb
index 9ef7f86f16..5a4a90ff7a 100644
--- a/spec/ruby/core/kernel/sprintf_spec.rb
+++ b/spec/ruby/core/kernel/sprintf_spec.rb
@@ -13,28 +13,52 @@ end
describe "Kernel#sprintf" do
it_behaves_like :kernel_sprintf, -> format, *args {
- sprintf(format, *args)
+ r = nil
+ -> {
+ r = sprintf(format, *args)
+ }.should_not complain(verbose: true)
+ r
}
it_behaves_like :kernel_sprintf_encoding, -> format, *args {
- sprintf(format, *args)
+ r = nil
+ -> {
+ r = sprintf(format, *args)
+ }.should_not complain(verbose: true)
+ r
}
it_behaves_like :kernel_sprintf_to_str, -> format, *args {
- sprintf(format, *args)
+ r = nil
+ -> {
+ r = sprintf(format, *args)
+ }.should_not complain(verbose: true)
+ r
}
end
describe "Kernel.sprintf" do
it_behaves_like :kernel_sprintf, -> format, *args {
- Kernel.sprintf(format, *args)
+ r = nil
+ -> {
+ r = Kernel.sprintf(format, *args)
+ }.should_not complain(verbose: true)
+ r
}
it_behaves_like :kernel_sprintf_encoding, -> format, *args {
- Kernel.sprintf(format, *args)
+ r = nil
+ -> {
+ r = Kernel.sprintf(format, *args)
+ }.should_not complain(verbose: true)
+ r
}
it_behaves_like :kernel_sprintf_to_str, -> format, *args {
- Kernel.sprintf(format, *args)
+ r = nil
+ -> {
+ r = Kernel.sprintf(format, *args)
+ }.should_not complain(verbose: true)
+ r
}
end
diff --git a/spec/ruby/core/kernel/srand_spec.rb b/spec/ruby/core/kernel/srand_spec.rb
index 95bb406f46..cbc3a7f4b8 100644
--- a/spec/ruby/core/kernel/srand_spec.rb
+++ b/spec/ruby/core/kernel/srand_spec.rb
@@ -11,7 +11,7 @@ describe "Kernel#srand" do
end
it "is a private method" do
- Kernel.should have_private_instance_method(:srand)
+ Kernel.private_instance_methods(false).should.include?(:srand)
end
it "returns the previous seed value" do
@@ -31,7 +31,7 @@ describe "Kernel#srand" do
end
it "defaults number to a random value" do
- -> { srand }.should_not raise_error
+ -> { srand }.should_not.raise
srand.should_not == 0
end
@@ -60,11 +60,11 @@ describe "Kernel#srand" do
end
it "raises a TypeError when passed nil" do
- -> { srand(nil) }.should raise_error(TypeError)
+ -> { srand(nil) }.should.raise(TypeError)
end
it "raises a TypeError when passed a String" do
- -> { srand("7") }.should raise_error(TypeError)
+ -> { srand("7") }.should.raise(TypeError)
end
end
diff --git a/spec/ruby/core/kernel/sub_spec.rb b/spec/ruby/core/kernel/sub_spec.rb
index 9130bd159c..b175e371dc 100644
--- a/spec/ruby/core/kernel/sub_spec.rb
+++ b/spec/ruby/core/kernel/sub_spec.rb
@@ -6,13 +6,13 @@ require_relative 'fixtures/classes'
ruby_version_is ""..."1.9" do
describe "Kernel#sub" do
it "is a private method" do
- Kernel.should have_private_instance_method(:sub)
+ Kernel.private_instance_methods(false).should.include?(:sub)
end
end
describe "Kernel#sub!" do
it "is a private method" do
- Kernel.should have_private_instance_method(:sub!)
+ Kernel.private_instance_methods(false).should.include?(:sub!)
end
end
diff --git a/spec/ruby/core/kernel/syscall_spec.rb b/spec/ruby/core/kernel/syscall_spec.rb
index 32d07b3ae2..63943cdad5 100644
--- a/spec/ruby/core/kernel/syscall_spec.rb
+++ b/spec/ruby/core/kernel/syscall_spec.rb
@@ -3,7 +3,7 @@ require_relative 'fixtures/classes'
describe "Kernel#syscall" do
it "is a private method" do
- Kernel.should have_private_instance_method(:syscall)
+ Kernel.private_instance_methods(false).should.include?(:syscall)
end
end
diff --git a/spec/ruby/core/kernel/system_spec.rb b/spec/ruby/core/kernel/system_spec.rb
index 9bc03924dd..b24956104a 100644
--- a/spec/ruby/core/kernel/system_spec.rb
+++ b/spec/ruby/core/kernel/system_spec.rb
@@ -5,14 +5,14 @@ describe :kernel_system, shared: true do
it "executes the specified command in a subprocess" do
-> { @object.system("echo a") }.should output_to_fd("a\n")
- $?.should be_an_instance_of Process::Status
+ $?.should.instance_of? Process::Status
$?.should.success?
end
it "returns true when the command exits with a zero exit status" do
@object.system(ruby_cmd('exit 0')).should == true
- $?.should be_an_instance_of Process::Status
+ $?.should.instance_of? Process::Status
$?.should.success?
$?.exitstatus.should == 0
end
@@ -20,24 +20,24 @@ describe :kernel_system, shared: true do
it "returns false when the command exits with a non-zero exit status" do
@object.system(ruby_cmd('exit 1')).should == false
- $?.should be_an_instance_of Process::Status
+ $?.should.instance_of? Process::Status
$?.should_not.success?
$?.exitstatus.should == 1
end
it "raises RuntimeError when `exception: true` is given and the command exits with a non-zero exit status" do
- -> { @object.system(ruby_cmd('exit 1'), exception: true) }.should raise_error(RuntimeError)
+ -> { @object.system(ruby_cmd('exit 1'), exception: true) }.should.raise(RuntimeError)
end
it "raises Errno::ENOENT when `exception: true` is given and the specified command does not exist" do
- -> { @object.system('feature_14386', exception: true) }.should raise_error(Errno::ENOENT)
+ -> { @object.system('feature_14386', exception: true) }.should.raise(Errno::ENOENT)
end
it "returns nil when command execution fails" do
- @object.system("sad").should be_nil
+ @object.system("sad").should == nil
- $?.should be_an_instance_of Process::Status
- $?.pid.should be_kind_of(Integer)
+ $?.should.instance_of? Process::Status
+ $?.pid.should.is_a?(Integer)
$?.should_not.success?
end
@@ -121,7 +121,7 @@ end
describe "Kernel#system" do
it "is a private method" do
- Kernel.should have_private_instance_method(:system)
+ Kernel.private_instance_methods(false).should.include?(:system)
end
it_behaves_like :kernel_system, :system, KernelSpecs::Method.new
diff --git a/spec/ruby/core/kernel/tap_spec.rb b/spec/ruby/core/kernel/tap_spec.rb
index f7720a6dc7..453b9b84d5 100644
--- a/spec/ruby/core/kernel/tap_spec.rb
+++ b/spec/ruby/core/kernel/tap_spec.rb
@@ -4,10 +4,10 @@ require_relative 'fixtures/classes'
describe "Kernel#tap" do
it "always yields self and returns self" do
a = KernelSpecs::A.new
- a.tap{|o| o.should equal(a); 42}.should equal(a)
+ a.tap{|o| o.should.equal?(a); 42}.should.equal?(a)
end
it "raises a LocalJumpError when no block given" do
- -> { 3.tap }.should raise_error(LocalJumpError)
+ -> { 3.tap }.should.raise(LocalJumpError)
end
end
diff --git a/spec/ruby/core/kernel/test_spec.rb b/spec/ruby/core/kernel/test_spec.rb
index d26dc06361..30717dfd98 100644
--- a/spec/ruby/core/kernel/test_spec.rb
+++ b/spec/ruby/core/kernel/test_spec.rb
@@ -8,7 +8,7 @@ describe "Kernel#test" do
end
it "is a private method" do
- Kernel.should have_private_instance_method(:test)
+ Kernel.private_instance_methods(false).should.include?(:test)
end
it "returns true when passed ?f if the argument is a regular file" do
@@ -28,7 +28,7 @@ describe "Kernel#test" do
link = tmp("file_symlink.lnk")
File.symlink(@file, link)
begin
- Kernel.test(?l, link).should be_true
+ Kernel.test(?l, link).should == true
ensure
rm_r link
end
@@ -36,11 +36,11 @@ describe "Kernel#test" do
end
it "returns true when passed ?r if the argument is readable by the effective uid" do
- Kernel.test(?r, @file).should be_true
+ Kernel.test(?r, @file).should == true
end
it "returns true when passed ?R if the argument is readable by the real uid" do
- Kernel.test(?R, @file).should be_true
+ Kernel.test(?R, @file).should == true
end
context "writable test" do
@@ -54,11 +54,11 @@ describe "Kernel#test" do
end
it "returns true when passed ?w if the argument is readable by the effective uid" do
- Kernel.test(?w, @tmp_file).should be_true
+ Kernel.test(?w, @tmp_file).should == true
end
it "returns true when passed ?W if the argument is readable by the real uid" do
- Kernel.test(?W, @tmp_file).should be_true
+ Kernel.test(?W, @tmp_file).should == true
end
end
diff --git a/spec/ruby/core/kernel/then_spec.rb b/spec/ruby/core/kernel/then_spec.rb
index 8109a2960a..bda5a69662 100644
--- a/spec/ruby/core/kernel/then_spec.rb
+++ b/spec/ruby/core/kernel/then_spec.rb
@@ -2,5 +2,13 @@ require_relative '../../spec_helper'
require_relative 'shared/then'
describe "Kernel#then" do
- it_behaves_like :kernel_then, :then
+ ruby_version_is ""..."3.4" do
+ it_behaves_like :kernel_then, :then
+ end
+
+ ruby_version_is "3.4" do
+ it "is an alias of Kernel#yield_self" do
+ Kernel.instance_method(:then).should == Kernel.instance_method(:yield_self)
+ end
+ end
end
diff --git a/spec/ruby/core/kernel/throw_spec.rb b/spec/ruby/core/kernel/throw_spec.rb
index 64bfccb413..1086126176 100644
--- a/spec/ruby/core/kernel/throw_spec.rb
+++ b/spec/ruby/core/kernel/throw_spec.rb
@@ -7,7 +7,7 @@ describe "Kernel.throw" do
:value
throw :blah
fail("throw didn't transfer the control")
- end.should be_nil
+ end.should == nil
end
it "transfers control to the innermost catch block waiting for the same symbol" do
@@ -42,11 +42,11 @@ describe "Kernel.throw" do
end
it "raises an ArgumentError if there is no catch block for the symbol" do
- -> { throw :blah }.should raise_error(ArgumentError)
+ -> { throw :blah }.should.raise(ArgumentError)
end
it "raises an UncaughtThrowError if there is no catch block for the symbol" do
- -> { throw :blah }.should raise_error(UncaughtThrowError)
+ -> { throw :blah }.should.raise(UncaughtThrowError)
end
it "raises ArgumentError if 3 or more arguments provided" do
@@ -54,13 +54,13 @@ describe "Kernel.throw" do
catch :blah do
throw :blah, :return_value, 2
end
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
-> {
catch :blah do
throw :blah, :return_value, 2, 3, 4, 5
end
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
it "can throw an object" do
@@ -69,12 +69,12 @@ describe "Kernel.throw" do
catch obj do
throw obj
end
- }.should_not raise_error(NameError)
+ }.should_not.raise(NameError)
end
end
describe "Kernel#throw" do
it "is a private method" do
- Kernel.should have_private_instance_method(:throw)
+ Kernel.private_instance_methods(false).should.include?(:throw)
end
end
diff --git a/spec/ruby/core/kernel/to_enum_spec.rb b/spec/ruby/core/kernel/to_enum_spec.rb
index 9d9945450f..1cee26b694 100644
--- a/spec/ruby/core/kernel/to_enum_spec.rb
+++ b/spec/ruby/core/kernel/to_enum_spec.rb
@@ -1,5 +1,59 @@
require_relative '../../spec_helper'
describe "Kernel#to_enum" do
- it "needs to be reviewed for spec completeness"
+ it "is defined in Kernel" do
+ Kernel.method_defined?(:to_enum).should == true
+ end
+
+ it "returns a new enumerator" do
+ "abc".to_enum.should.instance_of?(Enumerator)
+ end
+
+ it "defaults the first argument to :each" do
+ enum = [1,2].to_enum
+ enum.map { |v| v }.should == [1,2].each { |v| v }
+ end
+
+ it "sets regexp matches in the caller" do
+ "wawa".to_enum(:scan, /./).map {|o| $& }.should == ["w", "a", "w", "a"]
+ a = []
+ "wawa".to_enum(:scan, /./).each {|o| a << $& }
+ a.should == ["w", "a", "w", "a"]
+ end
+
+ it "exposes multi-arg yields as an array" do
+ o = Object.new
+ def o.each
+ yield :a
+ yield :b1, :b2
+ yield [:c]
+ yield :d1, :d2
+ yield :e1, :e2, :e3
+ end
+
+ enum = o.to_enum
+ enum.next.should == :a
+ enum.next.should == [:b1, :b2]
+ enum.next.should == [:c]
+ enum.next.should == [:d1, :d2]
+ enum.next.should == [:e1, :e2, :e3]
+ end
+
+ it "uses the passed block's value to calculate the size of the enumerator" do
+ Object.new.to_enum { 100 }.size.should == 100
+ end
+
+ it "defers the evaluation of the passed block until #size is called" do
+ ScratchPad.record []
+
+ enum = Object.new.to_enum do
+ ScratchPad << :called
+ 100
+ end
+
+ ScratchPad.recorded.should.empty?
+
+ enum.size
+ ScratchPad.recorded.should == [:called]
+ end
end
diff --git a/spec/ruby/core/kernel/trace_var_spec.rb b/spec/ruby/core/kernel/trace_var_spec.rb
index 3c84aa5e60..150c3da266 100644
--- a/spec/ruby/core/kernel/trace_var_spec.rb
+++ b/spec/ruby/core/kernel/trace_var_spec.rb
@@ -14,7 +14,7 @@ describe "Kernel#trace_var" do
end
it "is a private method" do
- Kernel.should have_private_instance_method(:trace_var)
+ Kernel.private_instance_methods(false).should.include?(:trace_var)
end
it "hooks assignments to a global variable" do
@@ -49,6 +49,6 @@ describe "Kernel#trace_var" do
it "raises ArgumentError if no block or proc is provided" do
-> do
trace_var :$Kernel_trace_var_global
- end.should raise_error(ArgumentError)
+ end.should.raise(ArgumentError)
end
end
diff --git a/spec/ruby/core/kernel/trap_spec.rb b/spec/ruby/core/kernel/trap_spec.rb
index 4c801a7215..8f44f3af4b 100644
--- a/spec/ruby/core/kernel/trap_spec.rb
+++ b/spec/ruby/core/kernel/trap_spec.rb
@@ -2,7 +2,7 @@ require_relative '../../spec_helper'
describe "Kernel#trap" do
it "is a private method" do
- Kernel.should have_private_instance_method(:trap)
+ Kernel.private_instance_methods(false).should.include?(:trap)
end
# Behaviour is specified for Signal.trap
diff --git a/spec/ruby/core/kernel/untrace_var_spec.rb b/spec/ruby/core/kernel/untrace_var_spec.rb
index 1925a3a836..8b219801c8 100644
--- a/spec/ruby/core/kernel/untrace_var_spec.rb
+++ b/spec/ruby/core/kernel/untrace_var_spec.rb
@@ -3,7 +3,7 @@ require_relative 'fixtures/classes'
describe "Kernel#untrace_var" do
it "is a private method" do
- Kernel.should have_private_instance_method(:untrace_var)
+ Kernel.private_instance_methods(false).should.include?(:untrace_var)
end
end
diff --git a/spec/ruby/core/kernel/warn_spec.rb b/spec/ruby/core/kernel/warn_spec.rb
index 00164ad90b..189129dd31 100644
--- a/spec/ruby/core/kernel/warn_spec.rb
+++ b/spec/ruby/core/kernel/warn_spec.rb
@@ -14,7 +14,7 @@ describe "Kernel#warn" do
end
it "is a private method" do
- Kernel.should have_private_instance_method(:warn)
+ Kernel.private_instance_methods(false).should.include?(:warn)
end
it "accepts multiple arguments" do
@@ -112,6 +112,12 @@ describe "Kernel#warn" do
ruby_exe(file, options: "-rrubygems", args: "2>&1").should == "#{file}:2: warning: warn-require-warning\n"
end
+ it "doesn't show the caller when the uplevel is `nil`" do
+ w = KernelSpecs::WarnInNestedCall.new
+
+ -> { w.f4("foo", nil) }.should output(nil, "foo\n")
+ end
+
guard -> { Kernel.instance_method(:tap).source_location } do
it "skips <internal: core library methods defined in Ruby" do
file, line = Kernel.instance_method(:tap).source_location
@@ -155,7 +161,7 @@ describe "Kernel#warn" do
-> {
$VERBOSE = true
warn("message", category: Object.new)
- }.should raise_error(TypeError)
+ }.should.raise(TypeError)
end
it "converts first arg using to_s" do
@@ -188,19 +194,19 @@ describe "Kernel#warn" do
end
it "raises ArgumentError if passed negative value" do
- -> { warn "", uplevel: -2 }.should raise_error(ArgumentError)
- -> { warn "", uplevel: -100 }.should raise_error(ArgumentError)
+ -> { warn "", uplevel: -2 }.should.raise(ArgumentError)
+ -> { warn "", uplevel: -100 }.should.raise(ArgumentError)
end
it "raises ArgumentError if passed -1" do
- -> { warn "", uplevel: -1 }.should raise_error(ArgumentError)
+ -> { warn "", uplevel: -1 }.should.raise(ArgumentError)
end
it "raises TypeError if passed not Integer" do
- -> { warn "", uplevel: "" }.should raise_error(TypeError)
- -> { warn "", uplevel: [] }.should raise_error(TypeError)
- -> { warn "", uplevel: {} }.should raise_error(TypeError)
- -> { warn "", uplevel: Object.new }.should raise_error(TypeError)
+ -> { warn "", uplevel: "" }.should.raise(TypeError)
+ -> { warn "", uplevel: [] }.should.raise(TypeError)
+ -> { warn "", uplevel: {} }.should.raise(TypeError)
+ -> { warn "", uplevel: Object.new }.should.raise(TypeError)
end
end
diff --git a/spec/ruby/core/main/define_method_spec.rb b/spec/ruby/core/main/define_method_spec.rb
index d85c5e8119..5279d078c3 100644
--- a/spec/ruby/core/main/define_method_spec.rb
+++ b/spec/ruby/core/main/define_method_spec.rb
@@ -14,15 +14,15 @@ describe "main#define_method" do
it 'creates a public method in TOPLEVEL_BINDING' do
eval @code, TOPLEVEL_BINDING
- Object.should have_method :boom
+ Object.should.respond_to? :boom
end
it 'creates a public method in script binding' do
eval @code, script_binding
- Object.should have_method :boom
+ Object.should.respond_to? :boom
end
it 'returns the method name as symbol' do
- eval(@code, TOPLEVEL_BINDING).should equal :boom
+ eval(@code, TOPLEVEL_BINDING).should.equal? :boom
end
end
diff --git a/spec/ruby/core/main/include_spec.rb b/spec/ruby/core/main/include_spec.rb
index 9f5a5f54ea..09f8d4d3b5 100644
--- a/spec/ruby/core/main/include_spec.rb
+++ b/spec/ruby/core/main/include_spec.rb
@@ -4,13 +4,13 @@ require_relative 'fixtures/classes'
describe "main#include" do
it "includes the given Module in Object" do
eval "include MainSpecs::Module", TOPLEVEL_BINDING
- Object.ancestors.should include(MainSpecs::Module)
+ Object.ancestors.should.include?(MainSpecs::Module)
end
context "in a file loaded with wrapping" do
it "includes the given Module in the load wrapper" do
load(File.expand_path("../fixtures/wrapped_include.rb", __FILE__), true)
- Object.ancestors.should_not include(MainSpecs::WrapIncludeModule)
+ Object.ancestors.should_not.include?(MainSpecs::WrapIncludeModule)
end
end
end
diff --git a/spec/ruby/core/main/private_spec.rb b/spec/ruby/core/main/private_spec.rb
index 76895fd649..56a39ae3c1 100644
--- a/spec/ruby/core/main/private_spec.rb
+++ b/spec/ruby/core/main/private_spec.rb
@@ -10,33 +10,33 @@ describe "main#private" do
context "when single argument is passed and it is not an array" do
it "sets the visibility of the given methods to private" do
eval "private :main_public_method", TOPLEVEL_BINDING
- Object.should have_private_method(:main_public_method)
+ Object.private_methods(true).should.include?(:main_public_method)
end
end
context "when multiple arguments are passed" 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)
+ Object.private_methods(true).should.include?(:main_public_method)
+ Object.private_methods(true).should.include?(:main_public_method2)
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)
+ Object.private_methods(true).should.include?(:main_public_method)
+ Object.private_methods(true).should.include?(:main_public_method2)
end
end
it "returns argument" do
- eval("private :main_public_method", TOPLEVEL_BINDING).should equal(:main_public_method)
+ eval("private :main_public_method", TOPLEVEL_BINDING).should.equal?(:main_public_method)
end
it "raises a NameError when at least one of given method names is undefined" do
-> do
eval "private :main_public_method, :main_undefined_method", TOPLEVEL_BINDING
- end.should raise_error(NameError)
+ end.should.raise(NameError)
end
end
diff --git a/spec/ruby/core/main/public_spec.rb b/spec/ruby/core/main/public_spec.rb
index 3c77798fbc..89368ebb0d 100644
--- a/spec/ruby/core/main/public_spec.rb
+++ b/spec/ruby/core/main/public_spec.rb
@@ -10,34 +10,34 @@ describe "main#public" do
context "when single argument is passed and it is not an array" do
it "sets the visibility of the given methods to public" do
eval "public :main_private_method", TOPLEVEL_BINDING
- Object.should_not have_private_method(:main_private_method)
+ Object.private_methods(true).should_not.include?(:main_private_method)
end
end
context "when multiple arguments are passed" 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)
+ Object.private_methods(true).should_not.include?(:main_private_method)
+ Object.private_methods(true).should_not.include?(:main_private_method2)
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)
+ Object.private_methods(true).should_not.include?(:main_private_method)
+ Object.private_methods(true).should_not.include?(:main_private_method2)
end
end
it "returns argument" do
- eval("public :main_private_method", TOPLEVEL_BINDING).should equal(:main_private_method)
+ eval("public :main_private_method", TOPLEVEL_BINDING).should.equal?(:main_private_method)
end
it "raises a NameError when given an undefined name" do
-> do
eval "public :main_undefined_method", TOPLEVEL_BINDING
- end.should raise_error(NameError)
+ end.should.raise(NameError)
end
end
diff --git a/spec/ruby/core/main/ruby2_keywords_spec.rb b/spec/ruby/core/main/ruby2_keywords_spec.rb
index 27ceae3253..d12c0ed4e4 100644
--- a/spec/ruby/core/main/ruby2_keywords_spec.rb
+++ b/spec/ruby/core/main/ruby2_keywords_spec.rb
@@ -4,6 +4,6 @@ require_relative 'fixtures/classes'
describe "main.ruby2_keywords" do
it "is the same as Object.ruby2_keywords" do
main = TOPLEVEL_BINDING.receiver
- main.should have_private_method(:ruby2_keywords)
+ main.private_methods(false).should.include?(:ruby2_keywords)
end
end
diff --git a/spec/ruby/core/main/using_spec.rb b/spec/ruby/core/main/using_spec.rb
index 5b9a751595..314a6be416 100644
--- a/spec/ruby/core/main/using_spec.rb
+++ b/spec/ruby/core/main/using_spec.rb
@@ -5,11 +5,11 @@ describe "main.using" do
it "requires one Module argument" do
-> do
eval('using', TOPLEVEL_BINDING)
- end.should raise_error(ArgumentError)
+ end.should.raise(ArgumentError)
-> do
eval('using "foo"', TOPLEVEL_BINDING)
- end.should raise_error(TypeError)
+ end.should.raise(TypeError)
end
it "uses refinements from the given module only in the target file" do
@@ -19,7 +19,7 @@ describe "main.using" do
MainSpecs::DATA[:toplevel].should == 'foo'
-> do
'hello'.foo
- end.should raise_error(NoMethodError)
+ end.should.raise(NoMethodError)
end
it "uses refinements from the given module for method calls in the target file" do
@@ -27,7 +27,7 @@ describe "main.using" do
load File.expand_path('../fixtures/string_refinement_user.rb', __FILE__)
-> do
'hello'.foo
- end.should raise_error(NoMethodError)
+ end.should.raise(NoMethodError)
MainSpecs.call_foo('hello').should == 'foo'
end
@@ -133,18 +133,18 @@ describe "main.using" do
it "raises error when called from method in wrapped script" do
-> do
load File.expand_path('../fixtures/using_in_method.rb', __FILE__), true
- end.should raise_error(RuntimeError)
+ end.should.raise(RuntimeError)
end
it "raises error when called on toplevel from module" do
-> do
load File.expand_path('../fixtures/using_in_main.rb', __FILE__), true
- end.should raise_error(RuntimeError)
+ end.should.raise(RuntimeError)
end
it "does not raise error when wrapped with module" do
-> do
load File.expand_path('../fixtures/using.rb', __FILE__), true
- end.should_not raise_error
+ end.should_not.raise
end
end
diff --git a/spec/ruby/core/marshal/dump_spec.rb b/spec/ruby/core/marshal/dump_spec.rb
index 283016b8db..9bbb7809af 100644
--- a/spec/ruby/core/marshal/dump_spec.rb
+++ b/spec/ruby/core/marshal/dump_spec.rb
@@ -116,7 +116,7 @@ describe "Marshal.dump" do
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/)
+ -> { Marshal.dump(Class.new(UserMarshal).new) }.should.raise(TypeError, /can't dump anonymous class/)
end
it "uses object links for objects repeatedly dumped" do
@@ -157,11 +157,11 @@ describe "Marshal.dump" do
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)
+ -> { Marshal.dump(m) }.should.raise(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/)
+ -> { Marshal.dump(Class.new(UserDefined).new) }.should.raise(TypeError, /can't dump anonymous class/)
end
it "favors marshal_dump over _dump" do
@@ -231,7 +231,7 @@ describe "Marshal.dump" do
Marshal.dump(MarshalSpec::ClassWithOverriddenName).should == "\x04\bc)MarshalSpec::ClassWithOverriddenName"
end
- ruby_version_is "3.5" do
+ ruby_version_is "4.0" do
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\bIc,MarshalSpec::Multibyte\xE3\x81\x81\xE3\x81\x82\xE3\x81\x83\xE3\x81\x84Class\x06:\x06ET"
@@ -244,11 +244,11 @@ describe "Marshal.dump" do
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(TypeError, /can't dump anonymous class/)
end
it "raises TypeError with a singleton Class" do
- -> { Marshal.dump(class << self; self end) }.should raise_error(TypeError)
+ -> { Marshal.dump(class << self; self end) }.should.raise(TypeError)
end
end
@@ -261,7 +261,7 @@ describe "Marshal.dump" do
Marshal.dump(MarshalSpec::ModuleWithOverriddenName).should == "\x04\bc*MarshalSpec::ModuleWithOverriddenName"
end
- ruby_version_is "3.5" do
+ ruby_version_is "4.0" do
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\bIm-MarshalSpec::Multibyte\xE3\x81\x91\xE3\x81\x92\xE3\x81\x93\xE3\x81\x94Module\x06:\x06ET"
@@ -274,7 +274,7 @@ describe "Marshal.dump" do
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(TypeError, /can't dump anonymous module/)
end
end
@@ -388,7 +388,7 @@ describe "Marshal.dump" do
end
it "raises TypeError with an anonymous Struct" do
- -> { Marshal.dump(Data.define(:a).new(1)) }.should raise_error(TypeError, /can't dump anonymous class/)
+ -> { Marshal.dump(Data.define(:a).new(1)) }.should.raise(TypeError, /can't dump anonymous class/)
end
end
@@ -473,14 +473,26 @@ describe "Marshal.dump" do
Marshal.dump(//im).should == "\x04\bI/\x00\x05\x06:\x06EF"
end
- it "dumps a Regexp with instance variables" do
- o = Regexp.new("")
+ it "dumps a Regexp subclass with instance variables" do
+ o = UserRegexp.new("")
o.instance_variable_set(:@ivar, :ivar)
- Marshal.dump(o).should == "\x04\bI/\x00\x00\a:\x06EF:\n@ivar:\tivar"
+ Marshal.dump(o).should == "\x04\bIC:\x0FUserRegexp/\x00\x00\a:\x06EF:\n@ivar:\tivar"
end
- it "dumps an extended Regexp" do
- Marshal.dump(Regexp.new("").extend(Meths)).should == "\x04\bIe:\nMeths/\x00\x00\x06:\x06EF"
+ it "dumps an extended Regexp subclass" do
+ Marshal.dump(UserRegexp.new("").extend(Meths)).should == "\x04\bIe:\nMethsC:\x0FUserRegexp/\x00\x00\x06:\x06EF"
+ end
+
+ ruby_version_is ""..."4.1" do
+ it "dumps a Regexp with instance variables" do
+ o = Regexp.new("")
+ o.instance_variable_set(:@ivar, :ivar)
+ Marshal.dump(o).should == "\x04\bI/\x00\x00\a:\x06EF:\n@ivar:\tivar"
+ end
+
+ it "dumps an extended Regexp" do
+ Marshal.dump(Regexp.new("").extend(Meths)).should == "\x04\bIe:\nMeths/\x00\x00\x06:\x06EF"
+ end
end
it "dumps a Regexp subclass" do
@@ -618,7 +630,7 @@ describe "Marshal.dump" do
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(TypeError, "can't dump hash with default proc")
end
it "dumps a Hash with instance variables" do
@@ -694,7 +706,7 @@ describe "Marshal.dump" do
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/)
+ -> { Marshal.dump(Struct.new(:a).new(1)) }.should.raise(TypeError, /can't dump anonymous class/)
end
it "adds instance variables after the object itself into the objects table" do
@@ -753,7 +765,7 @@ describe "Marshal.dump" do
def obj.foo; end
-> {
Marshal.dump(obj)
- }.should raise_error(TypeError, "singleton can't be dumped")
+ }.should.raise(TypeError, "singleton can't be dumped")
end
it "raises TypeError if an Object has a singleton class and singleton instance variables" do
@@ -764,14 +776,14 @@ describe "Marshal.dump" do
-> {
Marshal.dump(obj)
- }.should raise_error(TypeError, "singleton can't be dumped")
+ }.should.raise(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/)
+ -> { Marshal.dump(obj) }.should.raise(TypeError, /can't dump anonymous class/)
end
it "raises TypeError if an Object extends an anonymous module" do
@@ -779,7 +791,7 @@ describe "Marshal.dump" do
obj = Object.new
obj.extend(anonymous_module)
- -> { Marshal.dump(obj) }.should raise_error(TypeError, /can't dump anonymous class/)
+ -> { Marshal.dump(obj) }.should.raise(TypeError, /can't dump anonymous class/)
end
it "dumps a BasicObject subclass if it defines respond_to?" do
@@ -835,7 +847,7 @@ describe "Marshal.dump" do
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/)
+ -> { Marshal.dump(Class.new(Range).new(1, 2)) }.should.raise(TypeError, /can't dump anonymous class/)
end
end
@@ -865,7 +877,7 @@ describe "Marshal.dump" do
base = "\x04\bIu:\tTime\r#{@t_dump}\a"
offset = ":\voffseti\x020*"
zone = ":\tzoneI\"\bAST\x06:\x06EF" # Last is 'F' (US-ASCII)
- [ "#{base}#{offset}#{zone}", "#{base}#{zone}#{offset}" ].should include(dump)
+ [ "#{base}#{offset}#{zone}", "#{base}#{zone}#{offset}" ].should.include?(dump)
end
end
@@ -877,10 +889,10 @@ describe "Marshal.dump" do
it "ignores overridden name method" do
obj = MarshalSpec::TimeWithOverriddenName.new
- Marshal.dump(obj).should include("MarshalSpec::TimeWithOverriddenName")
+ Marshal.dump(obj).should.include?("MarshalSpec::TimeWithOverriddenName")
end
- ruby_version_is "3.5" do
+ ruby_version_is "4.0" do
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\bIc+MarshalSpec::Multibyte\xE3\x81\x81\xE3\x81\x82\xE3\x81\x83\xE3\x81\x84Time\x06:\x06ET"
@@ -909,7 +921,7 @@ describe "Marshal.dump" do
end
it "raises TypeError with an anonymous Time subclass" do
- -> { Marshal.dump(Class.new(Time).now) }.should raise_error(TypeError)
+ -> { Marshal.dump(Class.new(Time).now) }.should.raise(TypeError)
end
end
@@ -942,13 +954,13 @@ describe "Marshal.dump" do
begin
raise RuntimeError, "the consequence"
rescue RuntimeError => e
- e.cause.should equal(cause)
+ e.cause.should.equal?(cause)
exc = e
end
end
reloaded = Marshal.load(Marshal.dump(exc))
- reloaded.cause.should be_an_instance_of(StandardError)
+ reloaded.cause.should.instance_of?(StandardError)
reloaded.cause.message.should == "the cause"
end
@@ -981,7 +993,7 @@ describe "Marshal.dump" do
anonymous_class = Class.new(Exception)
obj = anonymous_class.new
- -> { Marshal.dump(obj) }.should raise_error(TypeError, /can't dump anonymous class/)
+ -> { Marshal.dump(obj) }.should.raise(TypeError, /can't dump anonymous class/)
end
end
@@ -1002,10 +1014,10 @@ describe "Marshal.dump" do
it "raises an ArgumentError when the recursion limit is exceeded" do
h = {'one' => {'two' => {'three' => 0}}}
- -> { Marshal.dump(h, 3) }.should raise_error(ArgumentError)
- -> { Marshal.dump([h], 4) }.should raise_error(ArgumentError)
- -> { Marshal.dump([], 0) }.should raise_error(ArgumentError)
- -> { Marshal.dump([[[]]], 1) }.should raise_error(ArgumentError)
+ -> { Marshal.dump(h, 3) }.should.raise(ArgumentError)
+ -> { Marshal.dump([h], 4) }.should.raise(ArgumentError)
+ -> { Marshal.dump([], 0) }.should.raise(ArgumentError)
+ -> { Marshal.dump([[[]]], 1) }.should.raise(ArgumentError)
end
it "ignores the recursion limit if the limit is negative" do
@@ -1027,7 +1039,7 @@ describe "Marshal.dump" do
it "raises an Error when the IO-Object does not respond to #write" do
obj = mock('test')
- -> { Marshal.dump("test", obj) }.should raise_error(TypeError)
+ -> { Marshal.dump("test", obj) }.should.raise(TypeError)
end
@@ -1042,29 +1054,29 @@ describe "Marshal.dump" do
describe "when passed a StringIO" do
it "should raise an error" do
require "stringio"
- -> { Marshal.dump(StringIO.new) }.should raise_error(TypeError)
+ -> { Marshal.dump(StringIO.new) }.should.raise(TypeError)
end
end
it "raises a TypeError if marshalling a Method instance" do
- -> { Marshal.dump(Marshal.method(:dump)) }.should raise_error(TypeError)
+ -> { Marshal.dump(Marshal.method(:dump)) }.should.raise(TypeError)
end
it "raises a TypeError if marshalling a Proc" do
- -> { Marshal.dump(proc {}) }.should raise_error(TypeError)
+ -> { Marshal.dump(proc {}) }.should.raise(TypeError)
end
it "raises a TypeError if dumping a IO/File instance" do
- -> { Marshal.dump(STDIN) }.should raise_error(TypeError)
- -> { File.open(__FILE__) { |f| Marshal.dump(f) } }.should raise_error(TypeError)
+ -> { Marshal.dump(STDIN) }.should.raise(TypeError)
+ -> { File.open(__FILE__) { |f| Marshal.dump(f) } }.should.raise(TypeError)
end
it "raises a TypeError if dumping a MatchData instance" do
- -> { Marshal.dump(/(.)/.match("foo")) }.should raise_error(TypeError)
+ -> { Marshal.dump(/(.)/.match("foo")) }.should.raise(TypeError)
end
it "raises a TypeError if dumping a Mutex instance" do
m = Mutex.new
- -> { Marshal.dump(m) }.should raise_error(TypeError)
+ -> { Marshal.dump(m) }.should.raise(TypeError)
end
end
diff --git a/spec/ruby/core/marshal/float_spec.rb b/spec/ruby/core/marshal/float_spec.rb
index 5793bbd564..5b2d68d6e1 100644
--- a/spec/ruby/core/marshal/float_spec.rb
+++ b/spec/ruby/core/marshal/float_spec.rb
@@ -40,7 +40,7 @@ end
describe "Marshal.load with Float" do
it "loads NaN" do
- Marshal.load("\004\bf\bnan").should be_nan
+ Marshal.load("\004\bf\bnan").should.nan?
end
it "loads +Infinity" do
diff --git a/spec/ruby/core/marshal/load_spec.rb b/spec/ruby/core/marshal/load_spec.rb
index a5bdfbf520..f5a05f8e52 100644
--- a/spec/ruby/core/marshal/load_spec.rb
+++ b/spec/ruby/core/marshal/load_spec.rb
@@ -1,6 +1,1291 @@
+# encoding: binary
require_relative '../../spec_helper'
-require_relative 'shared/load'
+require_relative 'fixtures/marshal_data'
describe "Marshal.load" do
- it_behaves_like :marshal_load, :load
+ before :all do
+ @num_self_class = 1
+ end
+
+ it "raises an ArgumentError when the dumped data is truncated" do
+ obj = {first: 1, second: 2, third: 3}
+ -> { Marshal.load(Marshal.dump(obj)[0, 5]) }.should.raise(ArgumentError, "marshal data too short")
+ end
+
+ it "raises an ArgumentError when the argument is empty String" do
+ -> { Marshal.load("") }.should.raise(ArgumentError, "marshal data too short")
+ end
+
+ it "raises an ArgumentError when the dumped class is missing" do
+ Object.send(:const_set, :KaBoom, Class.new)
+ kaboom = Marshal.dump(KaBoom.new)
+ Object.send(:remove_const, :KaBoom)
+
+ -> { Marshal.load(kaboom) }.should.raise(ArgumentError)
+ end
+
+ describe "when called with freeze: true" do
+ it "returns frozen strings" do
+ string = Marshal.load(Marshal.dump("foo"), freeze: true)
+ string.should == "foo"
+ string.should.frozen?
+
+ utf8_string = "foo".encode(Encoding::UTF_8)
+ string = Marshal.load(Marshal.dump(utf8_string), freeze: true)
+ string.should == utf8_string
+ string.should.frozen?
+ end
+
+ it "returns frozen arrays" do
+ array = Marshal.load(Marshal.dump([1, 2, 3]), freeze: true)
+ array.should == [1, 2, 3]
+ array.should.frozen?
+ end
+
+ it "returns frozen hashes" do
+ hash = Marshal.load(Marshal.dump({foo: 42}), freeze: true)
+ hash.should == {foo: 42}
+ hash.should.frozen?
+ end
+
+ it "returns frozen regexps" do
+ regexp = Marshal.load(Marshal.dump(/foo/), freeze: true)
+ regexp.should == /foo/
+ regexp.should.frozen?
+ end
+
+ it "returns frozen structs" do
+ struct = Marshal.load(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
+
+ object = Marshal.load(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.load(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.load(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.load(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.load(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.load(Marshal.dump(source_object), freeze: true)
+
+ object[0].should.equal?(object[1])
+ end
+ end
+
+ it "does not freeze modules" do
+ object = Marshal.load(Marshal.dump(Kernel), freeze: true)
+ object.should_not.frozen?
+ Kernel.should_not.frozen?
+ end
+
+ it "does not freeze classes" do
+ object = Marshal.load(Marshal.dump(Object), freeze: true)
+ object.should_not.frozen?
+ Object.should_not.frozen?
+ end
+
+ 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
+
+ it "returns frozen object having #_dump method" do
+ object = Marshal.load(Marshal.dump(UserDefined.new), freeze: true)
+ object.should.frozen?
+ end
+
+ it "returns frozen object responding to #marshal_dump and #marshal_load" do
+ object = Marshal.load(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.load(Marshal.dump(object), freeze: true)
+ object.should.frozen?
+ end
+
+ it "does not call freeze method" do
+ object = MarshalSpec::ObjectWithFreezeRaisingException.new
+ object = Marshal.load(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.load(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.load(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.instance_variable_set(:@foo, 5)
+ st = Struct.new("Brittle", :a).new
+ st.instance_variable_set(:@clue, 'none')
+ st.a = 0.0
+ h = Hash.new('def')
+ h['nine'] = 9
+ a = [:a, :b, :c]
+ a.instance_variable_set(:@two, 2)
+ obj = [s, 10, s, s, st, a]
+ obj.instance_variable_set(:@zoo, 'ant')
+ proc = Proc.new { |o| arr << o; o}
+
+ Marshal.load(
+ "\x04\bI[\vI\"\ahi\a:\x06EF:\t@fooi\ni\x0F@\x06@\x06IS:\x14Struct::Brittle\x06:\x06af\x060\x06:\n@clueI\"\tnone\x06;\x00FI[\b;\b:\x06b:\x06c\x06:\t@twoi\a\x06:\t@zooI\"\bant\x06;\x00F",
+ proc,
+ freeze: true,
+ )
+
+ arr.should == [
+ false, 5, "hi", 10, "hi", "hi", 0.0, false, "none", st,
+ :b, :c, 2, a, false, "ant", ["hi", 10, "hi", "hi", st, [:a, :b, :c]],
+ ]
+
+ arr.each do |v|
+ v.should.frozen?
+ end
+
+ Struct.send(:remove_const, :Brittle)
+ end
+
+ it "does not freeze the object returned by the proc" do
+ string = Marshal.load(Marshal.dump("foo"), proc { |o| o.upcase }, freeze: true)
+ string.should == "FOO"
+ string.should_not.frozen?
+ end
+ end
+ end
+
+ describe "when called with a proc" do
+ it "call the proc with fully initialized strings" do
+ utf8_string = "foo".encode(Encoding::UTF_8)
+ Marshal.load(Marshal.dump(utf8_string), proc { |arg|
+ if arg.is_a?(String)
+ arg.should == utf8_string
+ arg.encoding.should == Encoding::UTF_8
+ end
+ arg
+ })
+ end
+
+ it "no longer mutate the object after it was passed to the proc" do
+ string = Marshal.load(Marshal.dump("foo"), :freeze.to_proc)
+ string.should.frozen?
+ end
+
+ 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
+
+ it "returns the value of the proc" do
+ Marshal.load(Marshal.dump([1,2]), proc { [3,4] }).should == [3,4]
+ end
+
+ it "calls the proc for recursively visited data" do
+ a = [1]
+ a << a
+ ret = []
+ Marshal.load(Marshal.dump(a), proc { |arg| ret << arg.inspect; arg })
+ ret[0].should == 1.inspect
+ ret[1].should == a.inspect
+ ret.size.should == 2
+ end
+
+ it "loads an Array with proc" do
+ arr = []
+ s = +'hi'
+ s.instance_variable_set(:@foo, 5)
+ st = Struct.new("Brittle", :a).new
+ st.instance_variable_set(:@clue, 'none')
+ st.a = 0.0
+ h = Hash.new('def')
+ h['nine'] = 9
+ a = [:a, :b, :c]
+ a.instance_variable_set(:@two, 2)
+ obj = [s, 10, s, s, st, a]
+ obj.instance_variable_set(:@zoo, 'ant')
+ proc = Proc.new { |o| arr << o.dup; o}
+
+ Marshal.load("\x04\bI[\vI\"\ahi\a:\x06EF:\t@fooi\ni\x0F@\x06@\x06IS:\x14Struct::Brittle\x06:\x06af\x060\x06:\n@clueI\"\tnone\x06;\x00FI[\b;\b:\x06b:\x06c\x06:\t@twoi\a\x06:\t@zooI\"\bant\x06;\x00F", proc)
+
+ arr.should == [
+ false, 5, "hi", 10, "hi", "hi", 0.0, false, "none", st,
+ :b, :c, 2, a, false, "ant", ["hi", 10, "hi", "hi", st, [:a, :b, :c]],
+ ]
+ Struct.send(:remove_const, :Brittle)
+ end
+ end
+
+ describe "when called with nil for the proc argument" do
+ it "behaves as if no proc argument was passed" do
+ a = [1]
+ a << a
+ b = Marshal.load(Marshal.dump(a), nil)
+ b.should == a
+ end
+ end
+
+ describe "when called on objects with custom _dump methods" do
+ it "does not set instance variables of an object with user-defined _dump/_load" do
+ # this string represents: <#UserPreviouslyDefinedWithInitializedIvar @field2=7 @field1=6>
+ dump_str = "\004\bu:-UserPreviouslyDefinedWithInitializedIvar\a:\f@field2i\f:\f@field1i\v"
+
+ UserPreviouslyDefinedWithInitializedIvar.should_receive(:_load).and_return(UserPreviouslyDefinedWithInitializedIvar.new)
+ marshaled_obj = Marshal.load(dump_str)
+
+ marshaled_obj.should.instance_of?(UserPreviouslyDefinedWithInitializedIvar)
+ marshaled_obj.field1.should == nil
+ marshaled_obj.field2.should == 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.load(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.load(Marshal.dump(source_object))
+ object.string.should == "a".encode("utf-32le")
+ end
+
+ describe "that returns an immediate value" do
+ it "loads an array containing an instance of the object, followed by multiple instances of another object" do
+ str = "string"
+
+ # this string represents: [<#UserDefinedImmediate A>, <#String "string">, <#String "string">]
+ marshaled_obj = Marshal.load("\004\b[\bu:\031UserDefinedImmediate\000\"\vstring@\a")
+
+ marshaled_obj.should == [nil, str, str]
+ end
+
+ it "loads any structure with multiple references to the same object, followed by multiple instances of another object" do
+ str = "string"
+
+ # this string represents: {a: <#UserDefinedImmediate A>, b: <#UserDefinedImmediate A>, c: <#String "string">, d: <#String "string">}
+ hash_dump = "\x04\b{\t:\x06aIu:\x19UserDefinedImmediate\x00\x06:\x06ET:\x06b@\x06:\x06cI\"\vstring\x06;\aT:\x06d@\a"
+
+ marshaled_obj = Marshal.load(hash_dump)
+ marshaled_obj.should == {a: nil, b: nil, c: str, d: str}
+
+ # this string represents: [<#UserDefinedImmediate A>, <#UserDefinedImmediate A>, <#String "string">, <#String "string">]
+ array_dump = "\x04\b[\tIu:\x19UserDefinedImmediate\x00\x06:\x06ET@\x06I\"\vstring\x06;\x06T@\a"
+
+ marshaled_obj = Marshal.load(array_dump)
+ marshaled_obj.should == [nil, nil, str, str]
+ end
+
+ it "loads an array containing references to multiple instances of the object, followed by multiple instances of another object" do
+ str = "string"
+
+ # this string represents: [<#UserDefinedImmediate A>, <#UserDefinedImmediate B>, <#String "string">, <#String "string">]
+ array_dump = "\x04\b[\tIu:\x19UserDefinedImmediate\x00\x06:\x06ETIu;\x00\x00\x06;\x06TI\"\vstring\x06;\x06T@\b"
+
+ marshaled_obj = Marshal.load(array_dump)
+ marshaled_obj.should == [nil, nil, str, str]
+ end
+ end
+ end
+
+ it "loads an array containing objects having _dump method, and with proc" do
+ arr = []
+ myproc = Proc.new { |o| arr << o.dup; o }
+ o1 = UserDefined.new;
+ o2 = UserDefinedWithIvar.new
+ obj = [o1, o2, o1, o2]
+
+ Marshal.load("\x04\b[\tu:\x10UserDefined\x18\x04\b[\aI\"\nstuff\x06:\x06EF@\x06u:\x18UserDefinedWithIvar>\x04\b[\bI\"\nstuff\a:\x06EF:\t@foo:\x18UserDefinedWithIvarI\"\tmore\x06;\x00F@\a@\x06@\a", myproc)
+
+ arr[0].should == o1
+ arr[1].should == o2
+ arr[2].should == obj
+ arr.size.should == 3
+ end
+
+ it "loads an array containing objects having marshal_dump method, and with proc" do
+ arr = []
+ proc = Proc.new { |o| arr << o.dup; o }
+ o1 = UserMarshal.new
+ o2 = UserMarshalWithIvar.new
+
+ Marshal.load("\004\b[\tU:\020UserMarshal\"\nstuffU:\030UserMarshalWithIvar[\006\"\fmy data@\006@\b", proc)
+
+ arr[0].should == 'stuff'
+ arr[1].should == o1
+ arr[2].should == 'my data'
+ arr[3].should == ['my data']
+ arr[4].should == o2
+ arr[5].should == [o1, o2, o1, o2]
+
+ arr.size.should == 6
+ end
+
+ it "assigns classes to nested subclasses of Array correctly" do
+ arr = ArraySub.new(ArraySub.new)
+ arr_dump = Marshal.dump(arr)
+ Marshal.load(arr_dump).class.should == ArraySub
+ end
+
+ it "loads subclasses of Array with overridden << and push correctly" do
+ arr = ArraySubPush.new
+ arr[0] = '1'
+ arr_dump = Marshal.dump(arr)
+ Marshal.load(arr_dump).should == arr
+ end
+
+ it "raises a TypeError with bad Marshal version" do
+ marshal_data = +'\xff\xff'
+ marshal_data[0] = (Marshal::MAJOR_VERSION).chr
+ marshal_data[1] = (Marshal::MINOR_VERSION + 1).chr
+
+ -> { Marshal.load(marshal_data) }.should.raise(TypeError)
+
+ marshal_data = +'\xff\xff'
+ marshal_data[0] = (Marshal::MAJOR_VERSION - 1).chr
+ marshal_data[1] = (Marshal::MINOR_VERSION).chr
+
+ -> { Marshal.load(marshal_data) }.should.raise(TypeError)
+ end
+
+ it "raises EOFError on loading an empty file" do
+ temp_file = tmp("marshal.rubyspec.tmp.#{Process.pid}")
+ file = File.new(temp_file, "w+")
+ begin
+ -> { Marshal.load(file) }.should.raise(EOFError)
+ ensure
+ file.close
+ rm_r temp_file
+ end
+ end
+
+ # Note: Ruby 1.9 should be compatible with older marshal format
+ MarshalSpec::DATA.each do |description, (object, marshal, attributes)|
+ it "loads a #{description}" do
+ Marshal.load(marshal).should == object
+ end
+ end
+
+ MarshalSpec::DATA_19.each do |description, (object, marshal, attributes)|
+ it "loads a #{description}" do
+ Marshal.load(marshal).should == object
+ end
+ end
+
+ describe "for an Array" do
+ it "loads an array containing the same objects" do
+ s = 'oh'
+ b = 'hi'
+ r = //
+ d = [b, :no, s, :go]
+ c = String
+ f = 1.0
+
+ o1 = UserMarshalWithIvar.new; o2 = UserMarshal.new
+
+ obj = [:so, 'hello', 100, :so, :so, d, :so, o2, :so, :no, o2,
+ :go, c, nil, Struct::Pyramid.new, f, :go, :no, s, b, r,
+ :so, 'huh', o1, true, b, b, 99, r, b, s, :so, f, c, :no, o1, d]
+
+ Marshal.load("\004\b[*:\aso\"\nhelloii;\000;\000[\t\"\ahi:\ano\"\aoh:\ago;\000U:\020UserMarshal\"\nstuff;\000;\006@\n;\ac\vString0S:\024Struct::Pyramid\000f\0061;\a;\006@\t@\b/\000\000;\000\"\bhuhU:\030UserMarshalWithIvar[\006\"\fmy dataT@\b@\bih@\017@\b@\t;\000@\016@\f;\006@\021@\a").should ==
+ obj
+ end
+
+ it "loads an array having ivar" do
+ s = +'well'
+ s.instance_variable_set(:@foo, 10)
+ obj = ['5', s, 'hi'].extend(Meths, MethsMore)
+ obj.instance_variable_set(:@mix, s)
+ new_obj = Marshal.load("\004\bI[\b\"\0065I\"\twell\006:\t@fooi\017\"\ahi\006:\t@mix@\a")
+ new_obj.should == obj
+ new_obj.instance_variable_get(:@mix).should.equal? new_obj[1]
+ new_obj[1].instance_variable_get(:@foo).should == 10
+ end
+
+ it "loads an extended Array object containing a user-marshaled object" do
+ obj = [UserMarshal.new, UserMarshal.new].extend(Meths)
+ dump = "\x04\be:\nMeths[\ao:\x10UserMarshal\x06:\n@dataI\"\nstuff\x06:\x06ETo;\x06\x06;\aI\"\nstuff\x06;\bT"
+ new_obj = Marshal.load(dump)
+
+ new_obj.should == obj
+ obj_ancestors = class << obj; ancestors[1..-1]; end
+ new_obj_ancestors = class << new_obj; ancestors[1..-1]; end
+ obj_ancestors.should == new_obj_ancestors
+ end
+ end
+
+ describe "for a Hash" do
+ it "loads an extended_user_hash with a parameter to initialize" do
+ obj = UserHashInitParams.new(:abc).extend(Meths)
+
+ new_obj = Marshal.load("\004\bIe:\nMethsC:\027UserHashInitParams{\000\006:\a@a:\babc")
+
+ new_obj.should == obj
+ new_obj_metaclass_ancestors = class << new_obj; ancestors; end
+ new_obj_metaclass_ancestors[@num_self_class].should == Meths
+ new_obj_metaclass_ancestors[@num_self_class+1].should == UserHashInitParams
+ end
+
+ it "loads an extended hash object containing a user-marshaled object" do
+ obj = {a: UserMarshal.new}.extend(Meths)
+
+ new_obj = Marshal.load("\004\be:\nMeths{\006:\006aU:\020UserMarshal\"\nstuff")
+
+ new_obj.should == obj
+ new_obj_metaclass_ancestors = class << new_obj; ancestors; end
+ new_obj_metaclass_ancestors[@num_self_class].should == Meths
+ new_obj_metaclass_ancestors[@num_self_class+1].should == Hash
+ end
+
+ it "preserves hash ivars when hash contains a string having ivar" do
+ s = +'string'
+ s.instance_variable_set :@string_ivar, 'string ivar'
+ h = { key: s }
+ h.instance_variable_set :@hash_ivar, 'hash ivar'
+
+ unmarshalled = Marshal.load(Marshal.dump(h))
+ unmarshalled.instance_variable_get(:@hash_ivar).should == 'hash ivar'
+ unmarshalled[:key].instance_variable_get(:@string_ivar).should == 'string ivar'
+ end
+
+ it "preserves compare_by_identity behaviour" do
+ h = { a: 1 }
+ h.compare_by_identity
+ unmarshalled = Marshal.load(Marshal.dump(h))
+ unmarshalled.should.compare_by_identity?
+
+ h = { a: 1 }
+ unmarshalled = Marshal.load(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.load(Marshal.dump(h))
+ unmarshalled.should.compare_by_identity?
+
+ h = UserHash.new({ a: 1 })
+ unmarshalled = Marshal.load(Marshal.dump(h))
+ unmarshalled.should_not.compare_by_identity?
+ 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.load(Marshal.dump(h))
+ unmarshalled.should.kind_of?(UserHash)
+ end
+ end
+
+ describe "for a Symbol" do
+ it "loads a Symbol" do
+ sym = Marshal.load("\004\b:\vsymbol")
+ sym.should == :symbol
+ sym.encoding.should == Encoding::US_ASCII
+ end
+
+ it "loads a big Symbol" do
+ sym = ('big' * 100).to_sym
+ Marshal.load("\004\b:\002,\001#{'big' * 100}").should == sym
+ end
+
+ it "loads an encoded Symbol" do
+ s = "\u2192"
+
+ sym = Marshal.load("\x04\bI:\b\xE2\x86\x92\x06:\x06ET")
+ sym.should == s.encode("utf-8").to_sym
+ sym.encoding.should == Encoding::UTF_8
+
+ sym = Marshal.load("\x04\bI:\t\xFE\xFF!\x92\x06:\rencoding\"\vUTF-16")
+ sym.should == s.encode("utf-16").to_sym
+ sym.encoding.should == Encoding::UTF_16
+
+ sym = Marshal.load("\x04\bI:\a\x92!\x06:\rencoding\"\rUTF-16LE")
+ sym.should == s.encode("utf-16le").to_sym
+ sym.encoding.should == Encoding::UTF_16LE
+
+ sym = Marshal.load("\x04\bI:\a!\x92\x06:\rencoding\"\rUTF-16BE")
+ sym.should == s.encode("utf-16be").to_sym
+ sym.encoding.should == Encoding::UTF_16BE
+
+ sym = Marshal.load("\x04\bI:\a\xA2\xAA\x06:\rencoding\"\vEUC-JP")
+ sym.should == s.encode("euc-jp").to_sym
+ sym.encoding.should == Encoding::EUC_JP
+
+ sym = Marshal.load("\x04\bI:\a\x81\xA8\x06:\rencoding\"\x10Windows-31J")
+ sym.should == s.encode("sjis").to_sym
+ sym.encoding.should == Encoding::SJIS
+ end
+
+ it "loads a binary encoded Symbol" do
+ s = "\u2192".dup.force_encoding("binary").to_sym
+ sym = Marshal.load("\x04\b:\b\xE2\x86\x92")
+ sym.should == s
+ sym.encoding.should == Encoding::BINARY
+ end
+
+ it "loads multiple Symbols sharing the same encoding" do
+ # Note that the encoding is a link for the second Symbol
+ symbol1 = "I:\t\xE2\x82\xACa\x06:\x06ET"
+ symbol2 = "I:\t\xE2\x82\xACb\x06;\x06T"
+ dump = "\x04\b[\a#{symbol1}#{symbol2}"
+ value = Marshal.load(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
+ ]
+ value.should == expected
+
+ value = Marshal.load("\x04\b[\b#{symbol1}#{symbol2};\x00")
+ 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.load("\x04\b:\nhel")
+ }.should.raise(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.instance_variable_set(:@self, obj)
+ Marshal.load("\004\bI\"\ahi\006:\n@self@\000").should == obj
+ end
+
+ it "loads a string through StringIO stream" do
+ require 'stringio'
+ obj = "This is a string which should be unmarshalled through StringIO stream!"
+ Marshal.load(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(RuntimeError, "binmode")
+ end
+
+ it "loads a string with an ivar" do
+ str = Marshal.load("\x04\bI\"\x00\x06:\t@fooI\"\bbar\x06:\x06EF")
+ str.instance_variable_get("@foo").should == "bar"
+ end
+
+ it "loads a String subclass with custom constructor" do
+ str = Marshal.load("\x04\bC: UserCustomConstructorString\"\x00")
+ str.should.instance_of?(UserCustomConstructorString)
+ end
+
+ it "loads a US-ASCII String" do
+ str = "abc".dup.force_encoding("us-ascii")
+ data = "\x04\bI\"\babc\x06:\x06EF"
+ result = Marshal.load(data)
+ result.should == str
+ result.encoding.should.equal?(Encoding::US_ASCII)
+ end
+
+ it "loads a UTF-8 String" do
+ str = "\x6d\xc3\xb6\x68\x72\x65".dup.force_encoding("utf-8")
+ data = "\x04\bI\"\vm\xC3\xB6hre\x06:\x06ET"
+ result = Marshal.load(data)
+ result.should == str
+ result.encoding.should.equal?(Encoding::UTF_8)
+ 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")
+ data = "\x04\bI\"\x0Fm\x00\xF6\x00h\x00r\x00e\x00\x06:\rencoding\"\rUTF-16LE"
+ result = Marshal.load(data)
+ result.should == str
+ result.encoding.should.equal?(Encoding::UTF_16LE)
+ 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")
+ result = Marshal.load(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.load("\x04\b\"\nhel")
+ }.should.raise(ArgumentError, "marshal data too short")
+ end
+ end
+
+ describe "for a Struct" do
+ it "loads a extended_struct having fields with same objects" do
+ s = 'hi'
+ obj = Struct.new("Extended", :a, :b).new.extend(Meths)
+ dump = "\004\be:\nMethsS:\025Struct::Extended\a:\006a0:\006b0"
+ Marshal.load(dump).should == obj
+
+ obj.a = [:a, s]
+ obj.b = [:Meths, s]
+ dump = "\004\be:\nMethsS:\025Struct::Extended\a:\006a[\a;\a\"\ahi:\006b[\a;\000@\a"
+ Marshal.load(dump).should == obj
+ Struct.send(:remove_const, :Extended)
+ end
+
+ it "loads a struct having ivar" do
+ obj = Struct.new("Thick").new
+ obj.instance_variable_set(:@foo, 5)
+ reloaded = Marshal.load("\004\bIS:\022Struct::Thick\000\006:\t@fooi\n")
+ reloaded.should == obj
+ reloaded.instance_variable_get(:@foo).should == 5
+ Struct.send(:remove_const, :Thick)
+ end
+
+ it "loads a struct having fields" do
+ obj = Struct.new("Ure1", :a, :b).new
+ Marshal.load("\004\bS:\021Struct::Ure1\a:\006a0:\006b0").should == obj
+ Struct.send(:remove_const, :Ure1)
+ end
+
+ it "does not call initialize on the unmarshaled struct" do
+ threadlocal_key = MarshalSpec::StructWithUserInitialize::THREADLOCAL_KEY
+
+ s = MarshalSpec::StructWithUserInitialize.new('foo')
+ Thread.current[threadlocal_key].should == ['foo']
+ s.a.should == 'foo'
+
+ Thread.current[threadlocal_key] = nil
+
+ dumped = Marshal.dump(s)
+ loaded = Marshal.load(dumped)
+
+ Thread.current[threadlocal_key].should == nil
+ loaded.a.should == 'foo'
+ end
+ end
+
+ describe "for a Data" do
+ it "loads a Data" do
+ obj = MarshalSpec::DataSpec::Measure.new(100, 'km')
+ dumped = "\x04\bS:#MarshalSpec::DataSpec::Measure\a:\vamountii:\tunit\"\akm"
+ Marshal.dump(obj).should == dumped
+
+ Marshal.load(dumped).should == obj
+ end
+
+ it "loads an extended Data" do
+ obj = MarshalSpec::DataSpec::MeasureExtended.new(100, "km")
+ dumped = "\x04\bS:+MarshalSpec::DataSpec::MeasureExtended\a:\vamountii:\tunit\"\akm"
+ Marshal.dump(obj).should == dumped
+
+ Marshal.load(dumped).should == obj
+ end
+
+ it "returns a frozen object" do
+ obj = MarshalSpec::DataSpec::Measure.new(100, 'km')
+ dumped = "\x04\bS:#MarshalSpec::DataSpec::Measure\a:\vamountii:\tunit\"\akm"
+ Marshal.dump(obj).should == dumped
+
+ Marshal.load(dumped).should.frozen?
+ end
+ end
+
+ describe "for an Exception" do
+ it "loads a marshalled exception with no message" do
+ obj = Exception.new
+ loaded = Marshal.load("\004\bo:\016Exception\a:\abt0:\tmesg0")
+ loaded.message.should == obj.message
+ loaded.backtrace.should == obj.backtrace
+ loaded = Marshal.load("\x04\bo:\x0EException\a:\tmesg0:\abt0")
+ loaded.message.should == obj.message
+ loaded.backtrace.should == obj.backtrace
+ end
+
+ it "loads a marshalled exception with a message" do
+ obj = Exception.new("foo")
+ loaded = Marshal.load("\004\bo:\016Exception\a:\abt0:\tmesg\"\bfoo")
+ loaded.message.should == obj.message
+ loaded.backtrace.should == obj.backtrace
+ loaded = Marshal.load("\x04\bo:\x0EException\a:\tmesgI\"\bfoo\x06:\x06EF:\abt0")
+ loaded.message.should == obj.message
+ loaded.backtrace.should == obj.backtrace
+ end
+
+ it "loads a marshalled exception with a backtrace" do
+ obj = Exception.new("foo")
+ obj.set_backtrace(["foo/bar.rb:10"])
+ loaded = Marshal.load("\004\bo:\016Exception\a:\abt[\006\"\022foo/bar.rb:10:\tmesg\"\bfoo")
+ loaded.message.should == obj.message
+ loaded.backtrace.should == obj.backtrace
+ loaded = Marshal.load("\x04\bo:\x0EException\a:\tmesgI\"\bfoo\x06:\x06EF:\abt[\x06I\"\x12foo/bar.rb:10\x06;\aF")
+ loaded.message.should == obj.message
+ loaded.backtrace.should == obj.backtrace
+ end
+
+ it "loads an marshalled exception with ivars" do
+ s = 'hi'
+ arr = [:so, :so, s, s]
+ obj = Exception.new("foo")
+ obj.instance_variable_set :@arr, arr
+
+ loaded = Marshal.load("\x04\bo:\x0EException\b:\tmesg\"\bfoo:\abt0:\t@arr[\t:\aso;\t\"\ahi@\b")
+ new_arr = loaded.instance_variable_get :@arr
+
+ loaded.message.should == obj.message
+ new_arr.should == arr
+ end
+ end
+
+ describe "for an Object" do
+ it "loads an object" do
+ Marshal.load("\004\bo:\vObject\000").should.is_a?(Object)
+ end
+
+ it "loads an extended Object" do
+ obj = Object.new.extend(Meths)
+
+ new_obj = Marshal.load("\004\be:\nMethso:\vObject\000")
+
+ new_obj.class.should == obj.class
+ new_obj_metaclass_ancestors = class << new_obj; ancestors; end
+ new_obj_metaclass_ancestors[@num_self_class, 2].should == [Meths, Object]
+ end
+
+ it "loads an object having ivar" do
+ s = 'hi'
+ arr = [:so, :so, s, s]
+ obj = Object.new
+ obj.instance_variable_set :@str, arr
+
+ new_obj = Marshal.load("\004\bo:\vObject\006:\t@str[\t:\aso;\a\"\ahi@\a")
+ new_str = new_obj.instance_variable_get :@str
+
+ new_str.should == arr
+ end
+
+ it "loads an Object with a non-US-ASCII instance variable" do
+ ivar = "@é".dup.force_encoding(Encoding::UTF_8).to_sym
+ obj = Marshal.load("\x04\bo:\vObject\x06I:\b@\xC3\xA9\x06:\x06ETi\x06")
+ obj.instance_variables.should == [ivar]
+ obj.instance_variables[0].encoding.should == Encoding::UTF_8
+ obj.instance_variable_get(ivar).should == 1
+ end
+
+ it "raises ArgumentError if the object from an 'o' stream is not dumpable as 'o' type user class" do
+ -> do
+ Marshal.load("\x04\bo:\tFile\001\001:\001\005@path\"\x10/etc/passwd")
+ end.should.raise(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.load("\x04\bo:\vObj")
+ }.should.raise(ArgumentError, "marshal data too short")
+ end
+ end
+
+ describe "for an object responding to #marshal_dump and #marshal_load" do
+ it "loads a user-marshaled object" do
+ obj = UserMarshal.new
+ obj.data = :data
+ value = [obj, :data]
+ dump = Marshal.dump(value)
+ dump.should == "\x04\b[\aU:\x10UserMarshal:\tdata;\x06"
+ reloaded = Marshal.load(dump)
+ reloaded.should == value
+ end
+ end
+
+ describe "for a user object" do
+ it "loads a user-marshaled extended object" do
+ obj = UserMarshal.new.extend(Meths)
+
+ new_obj = Marshal.load("\004\bU:\020UserMarshal\"\nstuff")
+
+ new_obj.should == obj
+ new_obj_metaclass_ancestors = class << new_obj; ancestors; end
+ new_obj_metaclass_ancestors[@num_self_class].should == UserMarshal
+ end
+
+ it "loads a UserObject" do
+ Marshal.load("\004\bo:\017UserObject\000").should.is_a?(UserObject)
+ end
+
+ describe "that extends a core type other than Object or BasicObject" do
+ after :each do
+ MarshalSpec.reset_swapped_class
+ end
+
+ it "raises ArgumentError if the resulting class does not extend the same type" do
+ MarshalSpec.set_swapped_class(Class.new(Hash))
+ data = Marshal.dump(MarshalSpec::SwappedClass.new)
+
+ MarshalSpec.set_swapped_class(Class.new(Array))
+ -> { Marshal.load(data) }.should.raise(ArgumentError)
+
+ MarshalSpec.set_swapped_class(Class.new)
+ -> { Marshal.load(data) }.should.raise(ArgumentError)
+ end
+ end
+ end
+
+ describe "for a Regexp" do
+ ruby_version_is "4.1" do
+ it "raises FrozenError for an extended Regexp" do
+ -> {
+ Marshal.load("\004\be:\nMethse:\016MethsMore/\n[a-z]\000")
+ }.should.raise(FrozenError)
+ end
+
+ it "raises FrozenError when regexp has instance variables" do
+ -> {
+ Marshal.load("\x04\bI/\nhello\x00\a:\x06EF:\x11@regexp_ivar[\x06i/")
+ }.should.raise(FrozenError)
+ end
+ end
+
+ ruby_version_is ""..."4.1" do
+ it "loads an extended Regexp" do
+ obj = /[a-z]/.dup.extend(Meths, MethsMore)
+ new_obj = Marshal.load("\004\be:\nMethse:\016MethsMore/\n[a-z]\000")
+
+ new_obj.should == obj
+ new_obj_metaclass_ancestors = class << new_obj; ancestors; end
+ new_obj_metaclass_ancestors[@num_self_class, 3].should ==
+ [Meths, MethsMore, Regexp]
+ end
+
+ it "restore the regexp instance variables" do
+ obj = Regexp.new("hello")
+ obj.instance_variable_set(:@regexp_ivar, [42])
+
+ new_obj = Marshal.load("\x04\bI/\nhello\x00\a:\x06EF:\x11@regexp_ivar[\x06i/")
+ new_obj.instance_variables.should == [:@regexp_ivar]
+ new_obj.instance_variable_get(:@regexp_ivar).should == [42]
+ end
+ end
+
+ it "loads a Regexp subclass instance variables" do
+ obj = UserRegexp.new('abc')
+ obj.instance_variable_set(:@noise, 'much')
+
+ new_obj = Marshal.load(Marshal.dump(obj))
+
+ new_obj.should == obj
+ new_obj.instance_variable_get(:@noise).should == 'much'
+ new_obj_metaclass_ancestors = class << new_obj; ancestors; end
+ new_obj_metaclass_ancestors[@num_self_class, 2].should ==
+ [UserRegexp, Regexp]
+ end
+
+ it "loads a Regexp subclass instance variables when it is extended with a module" do
+ obj = UserRegexp.new('').extend(Meths)
+ obj.instance_variable_set(:@noise, 'much')
+
+ new_obj = Marshal.load("\004\bIe:\nMethsC:\017UserRegexp/\000\000\006:\v@noise\"\tmuch")
+
+ new_obj.should == obj
+ new_obj.instance_variable_get(:@noise).should == 'much'
+ new_obj_metaclass_ancestors = class << new_obj; ancestors; end
+ new_obj_metaclass_ancestors[@num_self_class, 3].should ==
+ [Meths, UserRegexp, Regexp]
+ end
+
+ it "preserves Regexp encoding" do
+ source_object = Regexp.new("a".encode("utf-32le"))
+ regexp = Marshal.load(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.load("\x04\bI/\x10hel")
+ }.should.raise(ArgumentError, "marshal data too short")
+ end
+ end
+
+ describe "for a Float" do
+ it "loads a Float NaN" do
+ obj = 0.0 / 0.0
+ Marshal.load("\004\bf\bnan").to_s.should == obj.to_s
+ end
+
+ it "loads a Float 1.3" do
+ Marshal.load("\004\bf\v1.3\000\314\315").should == 1.3
+ end
+
+ it "loads a Float -5.1867345e-22" do
+ obj = -5.1867345e-22
+ Marshal.load("\004\bf\037-5.1867345000000008e-22\000\203_").should be_close(obj, 1e-30)
+ end
+
+ it "loads a Float 1.1867345e+22" do
+ obj = 1.1867345e+22
+ Marshal.load("\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.load("\004\bf\v1")
+ }.should.raise(ArgumentError, "marshal data too short")
+ end
+ end
+
+ describe "for an Integer" do
+ it "loads 0" do
+ Marshal.load("\004\bi\000").should == 0
+ Marshal.load("\004\bi\005").should == 0
+ end
+
+ it "loads an Integer 8" do
+ Marshal.load("\004\bi\r" ).should == 8
+ end
+
+ it "loads and Integer -8" do
+ Marshal.load("\004\bi\363" ).should == -8
+ end
+
+ it "loads an Integer 1234" do
+ Marshal.load("\004\bi\002\322\004").should == 1234
+ end
+
+ it "loads an Integer -1234" do
+ Marshal.load("\004\bi\376.\373").should == -1234
+ end
+
+ it "loads an Integer 4611686018427387903" do
+ Marshal.load("\004\bl+\t\377\377\377\377\377\377\377?").should == 4611686018427387903
+ end
+
+ it "loads an Integer -4611686018427387903" do
+ Marshal.load("\004\bl-\t\377\377\377\377\377\377\377?").should == -4611686018427387903
+ end
+
+ it "loads an Integer 2361183241434822606847" do
+ Marshal.load("\004\bl+\n\377\377\377\377\377\377\377\377\177\000").should == 2361183241434822606847
+ end
+
+ it "loads an Integer -2361183241434822606847" do
+ Marshal.load("\004\bl-\n\377\377\377\377\377\377\377\377\177\000").should == -2361183241434822606847
+ end
+
+ it "raises ArgumentError if the input is too short" do
+ ["\004\bi",
+ "\004\bi\001",
+ "\004\bi\002",
+ "\004\bi\002\0",
+ "\004\bi\003",
+ "\004\bi\003\0",
+ "\004\bi\003\0\0",
+ "\004\bi\004",
+ "\004\bi\004\0",
+ "\004\bi\004\0\0",
+ "\004\bi\004\0\0\0"].each do |invalid|
+ -> { Marshal.load(invalid) }.should.raise(ArgumentError)
+ end
+ end
+
+ if 0.size == 8 # for platforms like x86_64
+ it "roundtrips 4611686018427387903 from dump/load correctly" do
+ Marshal.load(Marshal.dump(4611686018427387903)).should == 4611686018427387903
+ end
+ end
+ end
+
+ describe "for a Rational" do
+ it "loads" do
+ r = Marshal.load(Marshal.dump(Rational(1, 3)))
+ r.should == Rational(1, 3)
+ r.should.frozen?
+ end
+ end
+
+ describe "for a Complex" do
+ it "loads" do
+ c = Marshal.load(Marshal.dump(Complex(4, 3)))
+ c.should == Complex(4, 3)
+ c.should.frozen?
+ end
+ end
+
+ describe "for a Bignum" do
+ platform_is c_long_size: 64 do
+ context "that is Bignum on 32-bit platforms but Fixnum on 64-bit" do
+ it "dumps a Fixnum" do
+ val = Marshal.load("\004\bl+\ab:wU")
+ val.should == 1433877090
+ val.class.should == Integer
+ end
+
+ it "dumps an array containing multiple references to the Bignum as an array of Fixnum" do
+ arr = Marshal.load("\004\b[\al+\a\223BwU@\006")
+ arr.should == [1433879187, 1433879187]
+ arr.each { |v| v.class.should == Integer }
+ end
+ end
+ end
+ end
+
+ describe "for a Time" do
+ it "loads" do
+ Marshal.load(Marshal.dump(Time.at(1))).should == Time.at(1)
+ end
+
+ it "loads serialized instance variables" do
+ t = Time.new
+ t.instance_variable_set(:@foo, 'bar')
+
+ Marshal.load(Marshal.dump(t)).instance_variable_get(:@foo).should == 'bar'
+ end
+
+ it "loads Time objects stored as links" do
+ t = Time.new
+
+ t1, t2 = Marshal.load(Marshal.dump([t, t]))
+ t1.should.equal? t2
+ end
+
+ it "keeps the local zone" do
+ with_timezone 'AST', 3 do
+ t = Time.local(2012, 1, 1)
+ Marshal.load(Marshal.dump(t)).zone.should == t.zone
+ end
+ end
+
+ it "keeps UTC zone" do
+ t = Time.now.utc
+ t2 = Marshal.load(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.load(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.load(Marshal.dump(t))
+ t2.utc_offset.should == 32400
+ end
+
+ it "keeps nanoseconds" do
+ t = Time.now
+ Marshal.load(Marshal.dump(t)).nsec.should == t.nsec
+ end
+
+ it "does not add any additional instance variable" do
+ t = Time.now
+ t2 = Marshal.load(Marshal.dump(t))
+ t2.instance_variables.should.empty?
+ end
+ end
+
+ describe "for nil" do
+ it "loads" do
+ Marshal.load("\x04\b0").should == nil
+ end
+ end
+
+ describe "for true" do
+ it "loads" do
+ Marshal.load("\x04\bT").should == true
+ end
+ end
+
+ describe "for false" do
+ it "loads" do
+ Marshal.load("\x04\bF").should == false
+ end
+ end
+
+ describe "for a Class" do
+ it "loads" do
+ Marshal.load("\x04\bc\vString").should == String
+ end
+
+ it "raises ArgumentError if given the name of a non-Module" do
+ -> { Marshal.load("\x04\bc\vKernel") }.should.raise(ArgumentError)
+ end
+
+ it "raises ArgumentError if given a nonexistent class" do
+ -> { Marshal.load("\x04\bc\vStrung") }.should.raise(ArgumentError)
+ end
+
+ it "raises ArgumentError when end of byte sequence reached before class name end" do
+ Marshal.dump(String).should == "\x04\bc\vString"
+
+ -> {
+ Marshal.load("\x04\bc\vStr")
+ }.should.raise(ArgumentError, "marshal data too short")
+ end
+ end
+
+ describe "for a Module" do
+ it "loads a module" do
+ Marshal.load("\x04\bm\vKernel").should == Kernel
+ end
+
+ it "raises ArgumentError if given the name of a non-Class" do
+ -> { Marshal.load("\x04\bm\vString") }.should.raise(ArgumentError)
+ end
+
+ it "loads an old module" do
+ Marshal.load("\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.load("\x04\bm\vKer")
+ }.should.raise(ArgumentError, "marshal data too short")
+ end
+ end
+
+ describe "for a wrapped C pointer" do
+ it "loads" do
+ class DumpableDir < Dir
+ def _dump_data
+ path
+ end
+ def _load_data path
+ initialize(path)
+ end
+ end
+
+ data = "\x04\bd:\x10DumpableDirI\"\x06.\x06:\x06ET"
+
+ dir = Marshal.load(data)
+ begin
+ dir.path.should == '.'
+ ensure
+ dir.close
+ end
+ end
+
+ it "raises TypeError when the local class is missing _load_data" do
+ class UnloadableDumpableDir < Dir
+ def _dump_data
+ path
+ end
+ # no _load_data
+ end
+
+ data = "\x04\bd:\x1AUnloadableDumpableDirI\"\x06.\x06:\x06ET"
+
+ -> { Marshal.load(data) }.should.raise(TypeError)
+ end
+
+ it "raises ArgumentError when the local class is a regular object" do
+ data = "\004\bd:\020UserDefined\0"
+
+ -> { Marshal.load(data) }.should.raise(ArgumentError)
+ end
+ end
+
+ describe "when a class does not exist in the namespace" do
+ before :each do
+ NamespaceTest.send(:const_set, :SameName, Class.new)
+ @data = Marshal.dump(NamespaceTest::SameName.new)
+ NamespaceTest.send(:remove_const, :SameName)
+ end
+
+ it "raises an ArgumentError" do
+ message = "undefined class/module NamespaceTest::SameName"
+ -> { Marshal.load(@data) }.should.raise(ArgumentError, message)
+ end
+ end
+
+ it "raises an ArgumentError with full constant name when the dumped constant is missing" do
+ NamespaceTest.send(:const_set, :KaBoom, Class.new)
+ @data = Marshal.dump(NamespaceTest::KaBoom.new)
+ NamespaceTest.send(:remove_const, :KaBoom)
+
+ -> { Marshal.load(@data) }.should.raise(ArgumentError, /NamespaceTest::KaBoom/)
+ end
end
diff --git a/spec/ruby/core/marshal/restore_spec.rb b/spec/ruby/core/marshal/restore_spec.rb
index 7e75d7dea6..3135f881d4 100644
--- a/spec/ruby/core/marshal/restore_spec.rb
+++ b/spec/ruby/core/marshal/restore_spec.rb
@@ -1,6 +1,7 @@
require_relative '../../spec_helper'
-require_relative 'shared/load'
describe "Marshal.restore" do
- it_behaves_like :marshal_load, :restore
+ it "is an alias of Marshal.load" do
+ Marshal.method(:restore).should == Marshal.method(:load)
+ end
end
diff --git a/spec/ruby/core/marshal/shared/load.rb b/spec/ruby/core/marshal/shared/load.rb
deleted file mode 100644
index 204a4d34e3..0000000000
--- a/spec/ruby/core/marshal/shared/load.rb
+++ /dev/null
@@ -1,1270 +0,0 @@
-# encoding: binary
-require_relative '../fixtures/marshal_data'
-
-describe :marshal_load, shared: true do
- before :all do
- @num_self_class = 1
- end
-
- 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")
- end
-
- it "raises an ArgumentError when the dumped class is missing" do
- Object.send(:const_set, :KaBoom, Class.new)
- kaboom = Marshal.dump(KaBoom.new)
- Object.send(:remove_const, :KaBoom)
-
- -> { Marshal.send(@method, kaboom) }.should raise_error(ArgumentError)
- end
-
- describe "when called with freeze: true" do
- it "returns frozen strings" do
- string = Marshal.send(@method, Marshal.dump("foo"), freeze: true)
- string.should == "foo"
- string.should.frozen?
-
- utf8_string = "foo".encode(Encoding::UTF_8)
- string = Marshal.send(@method, Marshal.dump(utf8_string), freeze: true)
- string.should == utf8_string
- string.should.frozen?
- end
-
- it "returns frozen arrays" do
- array = Marshal.send(@method, Marshal.dump([1, 2, 3]), freeze: true)
- array.should == [1, 2, 3]
- array.should.frozen?
- end
-
- it "returns frozen hashes" do
- hash = Marshal.send(@method, Marshal.dump({foo: 42}), freeze: true)
- hash.should == {foo: 42}
- hash.should.frozen?
- end
-
- it "returns frozen regexps" do
- regexp = Marshal.send(@method, Marshal.dump(/foo/), freeze: true)
- regexp.should == /foo/
- 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
-
- 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
- end
-
- it "does not freeze modules" do
- object = Marshal.send(@method, Marshal.dump(Kernel), freeze: true)
- object.should_not.frozen?
- Kernel.should_not.frozen?
- end
-
- it "does not freeze classes" do
- object = Marshal.send(@method, Marshal.dump(Object), freeze: true)
- object.should_not.frozen?
- 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.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.instance_variable_set(:@foo, 5)
- st = Struct.new("Brittle", :a).new
- st.instance_variable_set(:@clue, 'none')
- st.a = 0.0
- h = Hash.new('def')
- h['nine'] = 9
- a = [:a, :b, :c]
- a.instance_variable_set(:@two, 2)
- obj = [s, 10, s, s, st, a]
- obj.instance_variable_set(:@zoo, 'ant')
- proc = Proc.new { |o| arr << o; o}
-
- Marshal.send(
- @method,
- "\x04\bI[\vI\"\ahi\a:\x06EF:\t@fooi\ni\x0F@\x06@\x06IS:\x14Struct::Brittle\x06:\x06af\x060\x06:\n@clueI\"\tnone\x06;\x00FI[\b;\b:\x06b:\x06c\x06:\t@twoi\a\x06:\t@zooI\"\bant\x06;\x00F",
- proc,
- freeze: true,
- )
-
- arr.should == [
- false, 5, "hi", 10, "hi", "hi", 0.0, false, "none", st,
- :b, :c, 2, a, false, "ant", ["hi", 10, "hi", "hi", st, [:a, :b, :c]],
- ]
-
- arr.each do |v|
- v.should.frozen?
- end
-
- Struct.send(:remove_const, :Brittle)
- end
-
- it "does not freeze the object returned by the proc" do
- string = Marshal.send(@method, Marshal.dump("foo"), proc { |o| o.upcase }, freeze: true)
- string.should == "FOO"
- string.should_not.frozen?
- end
- end
- end
-
- describe "when called with a proc" do
- it "call the proc with fully initialized strings" do
- utf8_string = "foo".encode(Encoding::UTF_8)
- Marshal.send(@method, Marshal.dump(utf8_string), proc { |arg|
- if arg.is_a?(String)
- arg.should == utf8_string
- arg.encoding.should == Encoding::UTF_8
- end
- arg
- })
- end
-
- it "no longer mutate the object after it was passed to the proc" do
- string = Marshal.load(Marshal.dump("foo"), :freeze.to_proc)
- string.should.frozen?
- 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
-
- it "calls the proc for recursively visited data" do
- a = [1]
- a << a
- ret = []
- Marshal.send(@method, Marshal.dump(a), proc { |arg| ret << arg.inspect; arg })
- ret[0].should == 1.inspect
- ret[1].should == a.inspect
- ret.size.should == 2
- end
-
- it "loads an Array with proc" do
- arr = []
- s = +'hi'
- s.instance_variable_set(:@foo, 5)
- st = Struct.new("Brittle", :a).new
- st.instance_variable_set(:@clue, 'none')
- st.a = 0.0
- h = Hash.new('def')
- h['nine'] = 9
- a = [:a, :b, :c]
- a.instance_variable_set(:@two, 2)
- obj = [s, 10, s, s, st, a]
- obj.instance_variable_set(:@zoo, 'ant')
- proc = Proc.new { |o| arr << o.dup; o}
-
- Marshal.send(@method, "\x04\bI[\vI\"\ahi\a:\x06EF:\t@fooi\ni\x0F@\x06@\x06IS:\x14Struct::Brittle\x06:\x06af\x060\x06:\n@clueI\"\tnone\x06;\x00FI[\b;\b:\x06b:\x06c\x06:\t@twoi\a\x06:\t@zooI\"\bant\x06;\x00F", proc)
-
- arr.should == [
- false, 5, "hi", 10, "hi", "hi", 0.0, false, "none", st,
- :b, :c, 2, a, false, "ant", ["hi", 10, "hi", "hi", st, [:a, :b, :c]],
- ]
- Struct.send(:remove_const, :Brittle)
- end
- end
-
- describe "when called with nil for the proc argument" do
- it "behaves as if no proc argument was passed" do
- a = [1]
- a << a
- b = Marshal.send(@method, Marshal.dump(a), nil)
- b.should == a
- end
- end
-
- describe "when called on objects with custom _dump methods" do
- it "does not set instance variables of an object with user-defined _dump/_load" do
- # this string represents: <#UserPreviouslyDefinedWithInitializedIvar @field2=7 @field1=6>
- dump_str = "\004\bu:-UserPreviouslyDefinedWithInitializedIvar\a:\f@field2i\f:\f@field1i\v"
-
- UserPreviouslyDefinedWithInitializedIvar.should_receive(:_load).and_return(UserPreviouslyDefinedWithInitializedIvar.new)
- marshaled_obj = Marshal.send(@method, dump_str)
-
- marshaled_obj.should be_an_instance_of(UserPreviouslyDefinedWithInitializedIvar)
- marshaled_obj.field1.should be_nil
- 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
- it "loads an array containing an instance of the object, followed by multiple instances of another object" do
- str = "string"
-
- # this string represents: [<#UserDefinedImmediate A>, <#String "string">, <#String "string">]
- marshaled_obj = Marshal.send(@method, "\004\b[\bu:\031UserDefinedImmediate\000\"\vstring@\a")
-
- marshaled_obj.should == [nil, str, str]
- end
-
- it "loads any structure with multiple references to the same object, followed by multiple instances of another object" do
- str = "string"
-
- # this string represents: {a: <#UserDefinedImmediate A>, b: <#UserDefinedImmediate A>, c: <#String "string">, d: <#String "string">}
- hash_dump = "\x04\b{\t:\x06aIu:\x19UserDefinedImmediate\x00\x06:\x06ET:\x06b@\x06:\x06cI\"\vstring\x06;\aT:\x06d@\a"
-
- marshaled_obj = Marshal.send(@method, hash_dump)
- marshaled_obj.should == {a: nil, b: nil, c: str, d: str}
-
- # this string represents: [<#UserDefinedImmediate A>, <#UserDefinedImmediate A>, <#String "string">, <#String "string">]
- array_dump = "\x04\b[\tIu:\x19UserDefinedImmediate\x00\x06:\x06ET@\x06I\"\vstring\x06;\x06T@\a"
-
- marshaled_obj = Marshal.send(@method, array_dump)
- marshaled_obj.should == [nil, nil, str, str]
- end
-
- it "loads an array containing references to multiple instances of the object, followed by multiple instances of another object" do
- str = "string"
-
- # this string represents: [<#UserDefinedImmediate A>, <#UserDefinedImmediate B>, <#String "string">, <#String "string">]
- array_dump = "\x04\b[\tIu:\x19UserDefinedImmediate\x00\x06:\x06ETIu;\x00\x00\x06;\x06TI\"\vstring\x06;\x06T@\b"
-
- marshaled_obj = Marshal.send(@method, array_dump)
- marshaled_obj.should == [nil, nil, str, str]
- end
- end
- end
-
- it "loads an array containing objects having _dump method, and with proc" do
- arr = []
- myproc = Proc.new { |o| arr << o.dup; o }
- o1 = UserDefined.new;
- o2 = UserDefinedWithIvar.new
- obj = [o1, o2, o1, o2]
-
- Marshal.send(@method, "\x04\b[\tu:\x10UserDefined\x18\x04\b[\aI\"\nstuff\x06:\x06EF@\x06u:\x18UserDefinedWithIvar>\x04\b[\bI\"\nstuff\a:\x06EF:\t@foo:\x18UserDefinedWithIvarI\"\tmore\x06;\x00F@\a@\x06@\a", myproc)
-
- arr[0].should == o1
- arr[1].should == o2
- arr[2].should == obj
- arr.size.should == 3
- end
-
- it "loads an array containing objects having marshal_dump method, and with proc" do
- arr = []
- proc = Proc.new { |o| arr << o.dup; o }
- o1 = UserMarshal.new
- o2 = UserMarshalWithIvar.new
-
- Marshal.send(@method, "\004\b[\tU:\020UserMarshal\"\nstuffU:\030UserMarshalWithIvar[\006\"\fmy data@\006@\b", proc)
-
- arr[0].should == 'stuff'
- arr[1].should == o1
- arr[2].should == 'my data'
- arr[3].should == ['my data']
- arr[4].should == o2
- arr[5].should == [o1, o2, o1, o2]
-
- arr.size.should == 6
- end
-
- it "assigns classes to nested subclasses of Array correctly" do
- arr = ArraySub.new(ArraySub.new)
- arr_dump = Marshal.dump(arr)
- Marshal.send(@method, arr_dump).class.should == ArraySub
- end
-
- it "loads subclasses of Array with overridden << and push correctly" do
- arr = ArraySubPush.new
- arr[0] = '1'
- arr_dump = Marshal.dump(arr)
- Marshal.send(@method, arr_dump).should == arr
- end
-
- it "raises a TypeError with bad Marshal version" do
- 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[0] = (Marshal::MAJOR_VERSION - 1).chr
- marshal_data[1] = (Marshal::MINOR_VERSION).chr
-
- -> { Marshal.send(@method, marshal_data) }.should raise_error(TypeError)
- end
-
- it "raises EOFError on loading an empty file" do
- temp_file = tmp("marshal.rubyspec.tmp.#{Process.pid}")
- file = File.new(temp_file, "w+")
- begin
- -> { Marshal.send(@method, file) }.should raise_error(EOFError)
- ensure
- file.close
- rm_r temp_file
- end
- end
-
- # Note: Ruby 1.9 should be compatible with older marshal format
- MarshalSpec::DATA.each do |description, (object, marshal, attributes)|
- it "loads a #{description}" do
- Marshal.send(@method, marshal).should == object
- end
- end
-
- MarshalSpec::DATA_19.each do |description, (object, marshal, attributes)|
- it "loads a #{description}" do
- Marshal.send(@method, marshal).should == object
- end
- end
-
- describe "for an Array" do
- it "loads an array containing the same objects" do
- s = 'oh'
- b = 'hi'
- r = //
- d = [b, :no, s, :go]
- c = String
- f = 1.0
-
- o1 = UserMarshalWithIvar.new; o2 = UserMarshal.new
-
- obj = [:so, 'hello', 100, :so, :so, d, :so, o2, :so, :no, o2,
- :go, c, nil, Struct::Pyramid.new, f, :go, :no, s, b, r,
- :so, 'huh', o1, true, b, b, 99, r, b, s, :so, f, c, :no, o1, d]
-
- Marshal.send(@method, "\004\b[*:\aso\"\nhelloii;\000;\000[\t\"\ahi:\ano\"\aoh:\ago;\000U:\020UserMarshal\"\nstuff;\000;\006@\n;\ac\vString0S:\024Struct::Pyramid\000f\0061;\a;\006@\t@\b/\000\000;\000\"\bhuhU:\030UserMarshalWithIvar[\006\"\fmy dataT@\b@\bih@\017@\b@\t;\000@\016@\f;\006@\021@\a").should ==
- obj
- end
-
- it "loads an array having ivar" do
- s = +'well'
- s.instance_variable_set(:@foo, 10)
- obj = ['5', s, 'hi'].extend(Meths, MethsMore)
- obj.instance_variable_set(:@mix, s)
- new_obj = Marshal.send(@method, "\004\bI[\b\"\0065I\"\twell\006:\t@fooi\017\"\ahi\006:\t@mix@\a")
- new_obj.should == obj
- new_obj.instance_variable_get(:@mix).should equal new_obj[1]
- new_obj[1].instance_variable_get(:@foo).should == 10
- end
-
- it "loads an extended Array object containing a user-marshaled object" do
- obj = [UserMarshal.new, UserMarshal.new].extend(Meths)
- dump = "\x04\be:\nMeths[\ao:\x10UserMarshal\x06:\n@dataI\"\nstuff\x06:\x06ETo;\x06\x06;\aI\"\nstuff\x06;\bT"
- new_obj = Marshal.send(@method, dump)
-
- new_obj.should == obj
- obj_ancestors = class << obj; ancestors[1..-1]; end
- new_obj_ancestors = class << new_obj; ancestors[1..-1]; end
- obj_ancestors.should == new_obj_ancestors
- end
- end
-
- describe "for a Hash" do
- it "loads an extended_user_hash with a parameter to initialize" do
- obj = UserHashInitParams.new(:abc).extend(Meths)
-
- new_obj = Marshal.send(@method, "\004\bIe:\nMethsC:\027UserHashInitParams{\000\006:\a@a:\babc")
-
- new_obj.should == obj
- new_obj_metaclass_ancestors = class << new_obj; ancestors; end
- new_obj_metaclass_ancestors[@num_self_class].should == Meths
- new_obj_metaclass_ancestors[@num_self_class+1].should == UserHashInitParams
- end
-
- it "loads an extended hash object containing a user-marshaled object" do
- obj = {a: UserMarshal.new}.extend(Meths)
-
- new_obj = Marshal.send(@method, "\004\be:\nMeths{\006:\006aU:\020UserMarshal\"\nstuff")
-
- new_obj.should == obj
- new_obj_metaclass_ancestors = class << new_obj; ancestors; end
- new_obj_metaclass_ancestors[@num_self_class].should == Meths
- new_obj_metaclass_ancestors[@num_self_class+1].should == Hash
- end
-
- it "preserves hash ivars when hash contains a string having ivar" do
- s = +'string'
- s.instance_variable_set :@string_ivar, 'string ivar'
- h = { key: s }
- h.instance_variable_set :@hash_ivar, 'hash ivar'
-
- unmarshalled = Marshal.send(@method, Marshal.dump(h))
- unmarshalled.instance_variable_get(:@hash_ivar).should == 'hash ivar'
- unmarshalled[:key].instance_variable_get(:@string_ivar).should == 'string ivar'
- end
-
- 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
-
- 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
- it "loads a Symbol" do
- sym = Marshal.send(@method, "\004\b:\vsymbol")
- sym.should == :symbol
- sym.encoding.should == Encoding::US_ASCII
- end
-
- it "loads a big Symbol" do
- sym = ('big' * 100).to_sym
- Marshal.send(@method, "\004\b:\002,\001#{'big' * 100}").should == sym
- end
-
- it "loads an encoded Symbol" do
- s = "\u2192"
-
- sym = Marshal.send(@method, "\x04\bI:\b\xE2\x86\x92\x06:\x06ET")
- sym.should == s.encode("utf-8").to_sym
- sym.encoding.should == Encoding::UTF_8
-
- sym = Marshal.send(@method, "\x04\bI:\t\xFE\xFF!\x92\x06:\rencoding\"\vUTF-16")
- sym.should == s.encode("utf-16").to_sym
- sym.encoding.should == Encoding::UTF_16
-
- sym = Marshal.send(@method, "\x04\bI:\a\x92!\x06:\rencoding\"\rUTF-16LE")
- sym.should == s.encode("utf-16le").to_sym
- sym.encoding.should == Encoding::UTF_16LE
-
- sym = Marshal.send(@method, "\x04\bI:\a!\x92\x06:\rencoding\"\rUTF-16BE")
- sym.should == s.encode("utf-16be").to_sym
- sym.encoding.should == Encoding::UTF_16BE
-
- sym = Marshal.send(@method, "\x04\bI:\a\xA2\xAA\x06:\rencoding\"\vEUC-JP")
- sym.should == s.encode("euc-jp").to_sym
- sym.encoding.should == Encoding::EUC_JP
-
- sym = Marshal.send(@method, "\x04\bI:\a\x81\xA8\x06:\rencoding\"\x10Windows-31J")
- sym.should == s.encode("sjis").to_sym
- sym.encoding.should == Encoding::SJIS
- end
-
- it "loads a binary encoded Symbol" do
- s = "\u2192".dup.force_encoding("binary").to_sym
- sym = Marshal.send(@method, "\x04\b:\b\xE2\x86\x92")
- sym.should == s
- sym.encoding.should == Encoding::BINARY
- end
-
- it "loads multiple Symbols sharing the same encoding" do
- # Note that the encoding is a link for the second Symbol
- symbol1 = "I:\t\xE2\x82\xACa\x06:\x06ET"
- symbol2 = "I:\t\xE2\x82\xACb\x06;\x06T"
- dump = "\x04\b[\a#{symbol1}#{symbol2}"
- 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
- ]
- value.should == expected
-
- value = Marshal.send(@method, "\x04\b[\b#{symbol1}#{symbol2};\x00")
- 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.instance_variable_set(:@self, obj)
- Marshal.send(@method, "\004\bI\"\ahi\006:\n@self@\000").should == obj
- end
-
- it "loads a string through StringIO stream" do
- require 'stringio'
- obj = "This is a string which should be unmarshalled through StringIO stream!"
- 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"
- end
-
- it "loads a String subclass with custom constructor" do
- str = Marshal.send(@method, "\x04\bC: UserCustomConstructorString\"\x00")
- str.should be_an_instance_of(UserCustomConstructorString)
- end
-
- it "loads a US-ASCII String" do
- str = "abc".dup.force_encoding("us-ascii")
- data = "\x04\bI\"\babc\x06:\x06EF"
- result = Marshal.send(@method, data)
- result.should == str
- result.encoding.should equal(Encoding::US_ASCII)
- end
-
- it "loads a UTF-8 String" do
- str = "\x6d\xc3\xb6\x68\x72\x65".dup.force_encoding("utf-8")
- data = "\x04\bI\"\vm\xC3\xB6hre\x06:\x06ET"
- result = Marshal.send(@method, data)
- result.should == str
- result.encoding.should equal(Encoding::UTF_8)
- 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")
- data = "\x04\bI\"\x0Fm\x00\xF6\x00h\x00r\x00e\x00\x06:\rencoding\"\rUTF-16LE"
- result = Marshal.send(@method, data)
- result.should == str
- result.encoding.should equal(Encoding::UTF_16LE)
- 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")
- 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
- it "loads a extended_struct having fields with same objects" do
- s = 'hi'
- obj = Struct.new("Extended", :a, :b).new.extend(Meths)
- dump = "\004\be:\nMethsS:\025Struct::Extended\a:\006a0:\006b0"
- Marshal.send(@method, dump).should == obj
-
- obj.a = [:a, s]
- obj.b = [:Meths, s]
- dump = "\004\be:\nMethsS:\025Struct::Extended\a:\006a[\a;\a\"\ahi:\006b[\a;\000@\a"
- Marshal.send(@method, dump).should == obj
- Struct.send(:remove_const, :Extended)
- end
-
- it "loads a struct having ivar" do
- obj = Struct.new("Thick").new
- obj.instance_variable_set(:@foo, 5)
- reloaded = Marshal.send(@method, "\004\bIS:\022Struct::Thick\000\006:\t@fooi\n")
- reloaded.should == obj
- reloaded.instance_variable_get(:@foo).should == 5
- Struct.send(:remove_const, :Thick)
- end
-
- it "loads a struct having fields" do
- obj = Struct.new("Ure1", :a, :b).new
- Marshal.send(@method, "\004\bS:\021Struct::Ure1\a:\006a0:\006b0").should == obj
- Struct.send(:remove_const, :Ure1)
- end
-
- it "does not call initialize on the unmarshaled struct" do
- threadlocal_key = MarshalSpec::StructWithUserInitialize::THREADLOCAL_KEY
-
- s = MarshalSpec::StructWithUserInitialize.new('foo')
- Thread.current[threadlocal_key].should == ['foo']
- s.a.should == 'foo'
-
- Thread.current[threadlocal_key] = nil
-
- dumped = Marshal.dump(s)
- loaded = Marshal.send(@method, dumped)
-
- Thread.current[threadlocal_key].should == nil
- loaded.a.should == 'foo'
- end
- end
-
- describe "for a Data" do
- it "loads a Data" do
- obj = MarshalSpec::DataSpec::Measure.new(100, 'km')
- dumped = "\x04\bS:#MarshalSpec::DataSpec::Measure\a:\vamountii:\tunit\"\akm"
- Marshal.dump(obj).should == dumped
-
- Marshal.send(@method, dumped).should == obj
- end
-
- it "loads an extended Data" do
- obj = MarshalSpec::DataSpec::MeasureExtended.new(100, "km")
- dumped = "\x04\bS:+MarshalSpec::DataSpec::MeasureExtended\a:\vamountii:\tunit\"\akm"
- Marshal.dump(obj).should == dumped
-
- Marshal.send(@method, dumped).should == obj
- end
-
- it "returns a frozen object" do
- obj = MarshalSpec::DataSpec::Measure.new(100, 'km')
- dumped = "\x04\bS:#MarshalSpec::DataSpec::Measure\a:\vamountii:\tunit\"\akm"
- Marshal.dump(obj).should == dumped
-
- Marshal.send(@method, dumped).should.frozen?
- end
- end
-
- describe "for an Exception" do
- it "loads a marshalled exception with no message" do
- obj = Exception.new
- loaded = Marshal.send(@method, "\004\bo:\016Exception\a:\abt0:\tmesg0")
- loaded.message.should == obj.message
- loaded.backtrace.should == obj.backtrace
- loaded = Marshal.send(@method, "\x04\bo:\x0EException\a:\tmesg0:\abt0")
- loaded.message.should == obj.message
- loaded.backtrace.should == obj.backtrace
- end
-
- it "loads a marshalled exception with a message" do
- obj = Exception.new("foo")
- loaded = Marshal.send(@method, "\004\bo:\016Exception\a:\abt0:\tmesg\"\bfoo")
- loaded.message.should == obj.message
- loaded.backtrace.should == obj.backtrace
- loaded = Marshal.send(@method, "\x04\bo:\x0EException\a:\tmesgI\"\bfoo\x06:\x06EF:\abt0")
- loaded.message.should == obj.message
- loaded.backtrace.should == obj.backtrace
- end
-
- it "loads a marshalled exception with a backtrace" do
- obj = Exception.new("foo")
- obj.set_backtrace(["foo/bar.rb:10"])
- loaded = Marshal.send(@method, "\004\bo:\016Exception\a:\abt[\006\"\022foo/bar.rb:10:\tmesg\"\bfoo")
- loaded.message.should == obj.message
- loaded.backtrace.should == obj.backtrace
- loaded = Marshal.send(@method, "\x04\bo:\x0EException\a:\tmesgI\"\bfoo\x06:\x06EF:\abt[\x06I\"\x12foo/bar.rb:10\x06;\aF")
- loaded.message.should == obj.message
- loaded.backtrace.should == obj.backtrace
- end
-
- it "loads an marshalled exception with ivars" do
- s = 'hi'
- arr = [:so, :so, s, s]
- obj = Exception.new("foo")
- obj.instance_variable_set :@arr, arr
-
- loaded = Marshal.send(@method, "\x04\bo:\x0EException\b:\tmesg\"\bfoo:\abt0:\t@arr[\t:\aso;\t\"\ahi@\b")
- new_arr = loaded.instance_variable_get :@arr
-
- loaded.message.should == obj.message
- new_arr.should == arr
- end
- end
-
- describe "for an Object" do
- it "loads an object" do
- Marshal.send(@method, "\004\bo:\vObject\000").should be_kind_of(Object)
- end
-
- it "loads an extended Object" do
- obj = Object.new.extend(Meths)
-
- new_obj = Marshal.send(@method, "\004\be:\nMethso:\vObject\000")
-
- new_obj.class.should == obj.class
- new_obj_metaclass_ancestors = class << new_obj; ancestors; end
- new_obj_metaclass_ancestors[@num_self_class, 2].should == [Meths, Object]
- end
-
- it "loads an object having ivar" do
- s = 'hi'
- arr = [:so, :so, s, s]
- obj = Object.new
- obj.instance_variable_set :@str, arr
-
- new_obj = Marshal.send(@method, "\004\bo:\vObject\006:\t@str[\t:\aso;\a\"\ahi@\a")
- new_str = new_obj.instance_variable_get :@str
-
- new_str.should == arr
- end
-
- it "loads an Object with a non-US-ASCII instance variable" do
- ivar = "@é".dup.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
- obj.instance_variable_get(ivar).should == 1
- end
-
- it "raises ArgumentError if the object from an 'o' stream is not dumpable as 'o' type user class" do
- -> 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
- it "loads a user-marshaled object" do
- obj = UserMarshal.new
- obj.data = :data
- value = [obj, :data]
- dump = Marshal.dump(value)
- dump.should == "\x04\b[\aU:\x10UserMarshal:\tdata;\x06"
- reloaded = Marshal.load(dump)
- reloaded.should == value
- end
- end
-
- describe "for a user object" do
- it "loads a user-marshaled extended object" do
- obj = UserMarshal.new.extend(Meths)
-
- new_obj = Marshal.send(@method, "\004\bU:\020UserMarshal\"\nstuff")
-
- new_obj.should == obj
- new_obj_metaclass_ancestors = class << new_obj; ancestors; end
- new_obj_metaclass_ancestors[@num_self_class].should == UserMarshal
- end
-
- it "loads a UserObject" do
- Marshal.send(@method, "\004\bo:\017UserObject\000").should be_kind_of(UserObject)
- end
-
- describe "that extends a core type other than Object or BasicObject" do
- after :each do
- MarshalSpec.reset_swapped_class
- end
-
- it "raises ArgumentError if the resulting class does not extend the same type" do
- MarshalSpec.set_swapped_class(Class.new(Hash))
- data = Marshal.dump(MarshalSpec::SwappedClass.new)
-
- MarshalSpec.set_swapped_class(Class.new(Array))
- -> { Marshal.send(@method, data) }.should raise_error(ArgumentError)
-
- MarshalSpec.set_swapped_class(Class.new)
- -> { Marshal.send(@method, data) }.should raise_error(ArgumentError)
- end
- end
- end
-
- describe "for a Regexp" do
- it "loads an extended Regexp" do
- obj = /[a-z]/.dup.extend(Meths, MethsMore)
- new_obj = Marshal.send(@method, "\004\be:\nMethse:\016MethsMore/\n[a-z]\000")
-
- new_obj.should == obj
- new_obj_metaclass_ancestors = class << new_obj; ancestors; end
- new_obj_metaclass_ancestors[@num_self_class, 3].should ==
- [Meths, MethsMore, Regexp]
- end
-
- it "loads a Regexp subclass instance variables when it is extended with a module" do
- obj = UserRegexp.new('').extend(Meths)
- obj.instance_variable_set(:@noise, 'much')
-
- new_obj = Marshal.send(@method, "\004\bIe:\nMethsC:\017UserRegexp/\000\000\006:\v@noise\"\tmuch")
-
- new_obj.should == obj
- new_obj.instance_variable_get(:@noise).should == 'much'
- new_obj_metaclass_ancestors = class << new_obj; ancestors; end
- new_obj_metaclass_ancestors[@num_self_class, 3].should ==
- [Meths, UserRegexp, Regexp]
- end
-
- ruby_bug "#19439", ""..."3.3" do
- it "restore the regexp instance variables" do
- obj = Regexp.new("hello")
- obj.instance_variable_set(:@regexp_ivar, [42])
-
- new_obj = Marshal.send(@method, "\x04\bI/\nhello\x00\a:\x06EF:\x11@regexp_ivar[\x06i/")
- new_obj.instance_variables.should == [:@regexp_ivar]
- 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
- it "loads a Float NaN" do
- obj = 0.0 / 0.0
- Marshal.send(@method, "\004\bf\bnan").to_s.should == obj.to_s
- end
-
- it "loads a Float 1.3" do
- Marshal.send(@method, "\004\bf\v1.3\000\314\315").should == 1.3
- end
-
- it "loads a Float -5.1867345e-22" do
- obj = -5.1867345e-22
- Marshal.send(@method, "\004\bf\037-5.1867345000000008e-22\000\203_").should be_close(obj, 1e-30)
- end
-
- it "loads a Float 1.1867345e+22" 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
- it "loads 0" do
- Marshal.send(@method, "\004\bi\000").should == 0
- Marshal.send(@method, "\004\bi\005").should == 0
- end
-
- it "loads an Integer 8" do
- Marshal.send(@method, "\004\bi\r" ).should == 8
- end
-
- it "loads and Integer -8" do
- Marshal.send(@method, "\004\bi\363" ).should == -8
- end
-
- it "loads an Integer 1234" do
- Marshal.send(@method, "\004\bi\002\322\004").should == 1234
- end
-
- it "loads an Integer -1234" do
- Marshal.send(@method, "\004\bi\376.\373").should == -1234
- end
-
- it "loads an Integer 4611686018427387903" do
- Marshal.send(@method, "\004\bl+\t\377\377\377\377\377\377\377?").should == 4611686018427387903
- end
-
- it "loads an Integer -4611686018427387903" do
- Marshal.send(@method, "\004\bl-\t\377\377\377\377\377\377\377?").should == -4611686018427387903
- end
-
- it "loads an Integer 2361183241434822606847" do
- Marshal.send(@method, "\004\bl+\n\377\377\377\377\377\377\377\377\177\000").should == 2361183241434822606847
- end
-
- it "loads an Integer -2361183241434822606847" do
- Marshal.send(@method, "\004\bl-\n\377\377\377\377\377\377\377\377\177\000").should == -2361183241434822606847
- end
-
- it "raises ArgumentError if the input is too short" do
- ["\004\bi",
- "\004\bi\001",
- "\004\bi\002",
- "\004\bi\002\0",
- "\004\bi\003",
- "\004\bi\003\0",
- "\004\bi\003\0\0",
- "\004\bi\004",
- "\004\bi\004\0",
- "\004\bi\004\0\0",
- "\004\bi\004\0\0\0"].each do |invalid|
- -> { Marshal.send(@method, invalid) }.should raise_error(ArgumentError)
- end
- end
-
- if 0.size == 8 # for platforms like x86_64
- it "roundtrips 4611686018427387903 from dump/load correctly" do
- Marshal.send(@method, Marshal.dump(4611686018427387903)).should == 4611686018427387903
- end
- end
- end
-
- 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?
- 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?
- end
- end
-
- describe "for a Bignum" do
- platform_is c_long_size: 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")
- val.should == 1433877090
- val.class.should == Integer
- end
-
- it "dumps an array containing multiple references to the Bignum as an array of Fixnum" do
- arr = Marshal.send(@method, "\004\b[\al+\a\223BwU@\006")
- arr.should == [1433879187, 1433879187]
- arr.each { |v| v.class.should == Integer }
- end
- end
- end
- end
-
- describe "for a Time" do
- it "loads" do
- Marshal.send(@method, Marshal.dump(Time.at(1))).should == Time.at(1)
- end
-
- it "loads serialized instance variables" do
- t = Time.new
- t.instance_variable_set(:@foo, 'bar')
-
- Marshal.send(@method, Marshal.dump(t)).instance_variable_get(:@foo).should == 'bar'
- end
-
- it "loads Time objects stored as links" do
- t = Time.new
-
- t1, t2 = Marshal.send(@method, Marshal.dump([t, t]))
- t1.should equal t2
- end
-
- it "keeps the local 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
- 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
- it "loads" do
- Marshal.send(@method, "\x04\b0").should be_nil
- end
- end
-
- describe "for true" do
- it "loads" do
- Marshal.send(@method, "\x04\bT").should be_true
- end
- end
-
- describe "for false" do
- it "loads" do
- Marshal.send(@method, "\x04\bF").should be_false
- end
- end
-
- describe "for a Class" do
- it "loads" do
- Marshal.send(@method, "\x04\bc\vString").should == String
- end
-
- it "raises ArgumentError if given the name of a non-Module" do
- -> { Marshal.send(@method, "\x04\bc\vKernel") }.should raise_error(ArgumentError)
- end
-
- 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
- it "loads a module" do
- Marshal.send(@method, "\x04\bm\vKernel").should == Kernel
- end
-
- it "raises ArgumentError if given the name of a non-Class" do
- -> { Marshal.send(@method, "\x04\bm\vString") }.should raise_error(ArgumentError)
- end
-
- 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
- it "loads" do
- class DumpableDir < Dir
- def _dump_data
- path
- end
- def _load_data path
- initialize(path)
- end
- end
-
- data = "\x04\bd:\x10DumpableDirI\"\x06.\x06:\x06ET"
-
- dir = Marshal.send(@method, data)
- begin
- dir.path.should == '.'
- ensure
- dir.close
- end
- end
-
- it "raises TypeError when the local class is missing _load_data" do
- class UnloadableDumpableDir < Dir
- def _dump_data
- path
- end
- # no _load_data
- end
-
- data = "\x04\bd:\x1AUnloadableDumpableDirI\"\x06.\x06:\x06ET"
-
- -> { Marshal.send(@method, data) }.should raise_error(TypeError)
- end
-
- it "raises ArgumentError when the local class is a regular object" do
- data = "\004\bd:\020UserDefined\0"
-
- -> { Marshal.send(@method, data) }.should raise_error(ArgumentError)
- end
- end
-
- describe "when a class does not exist in the namespace" do
- before :each do
- NamespaceTest.send(:const_set, :SameName, Class.new)
- @data = Marshal.dump(NamespaceTest::SameName.new)
- NamespaceTest.send(:remove_const, :SameName)
- end
-
- it "raises an ArgumentError" do
- message = "undefined class/module NamespaceTest::SameName"
- -> { Marshal.send(@method, @data) }.should raise_error(ArgumentError, message)
- end
- end
-
- it "raises an ArgumentError with full constant name when the dumped constant is missing" do
- NamespaceTest.send(:const_set, :KaBoom, Class.new)
- @data = Marshal.dump(NamespaceTest::KaBoom.new)
- NamespaceTest.send(:remove_const, :KaBoom)
-
- -> { Marshal.send(@method, @data) }.should raise_error(ArgumentError, /NamespaceTest::KaBoom/)
- end
-end
diff --git a/spec/ruby/core/matchdata/allocate_spec.rb b/spec/ruby/core/matchdata/allocate_spec.rb
index 142ce639c2..f41e2d5481 100644
--- a/spec/ruby/core/matchdata/allocate_spec.rb
+++ b/spec/ruby/core/matchdata/allocate_spec.rb
@@ -3,6 +3,6 @@ require_relative '../../spec_helper'
describe "MatchData.allocate" do
it "is undefined" do
# https://bugs.ruby-lang.org/issues/16294
- -> { MatchData.allocate }.should raise_error(NoMethodError)
+ -> { MatchData.allocate }.should.raise(NoMethodError)
end
end
diff --git a/spec/ruby/core/matchdata/begin_spec.rb b/spec/ruby/core/matchdata/begin_spec.rb
index 54b4e0a33f..b4be077ae4 100644
--- a/spec/ruby/core/matchdata/begin_spec.rb
+++ b/spec/ruby/core/matchdata/begin_spec.rb
@@ -12,7 +12,7 @@ describe "MatchData#begin" do
it "returns nil when the nth match isn't found" do
match_data = /something is( not)? (right)/.match("something is right")
- match_data.begin(1).should be_nil
+ match_data.begin(1).should == nil
end
it "returns the character offset for multi-byte strings" do
@@ -42,11 +42,11 @@ describe "MatchData#begin" do
-> {
match_data.begin(-1)
- }.should raise_error(IndexError, "index -1 out of matches")
+ }.should.raise(IndexError, "index -1 out of matches")
-> {
match_data.begin(3)
- }.should raise_error(IndexError, "index 3 out of matches")
+ }.should.raise(IndexError, "index 3 out of matches")
end
end
@@ -86,7 +86,7 @@ describe "MatchData#begin" do
-> {
match_data.begin("y")
- }.should raise_error(IndexError, "undefined group name reference: y")
+ }.should.raise(IndexError, "undefined group name reference: y")
end
end
@@ -126,7 +126,7 @@ describe "MatchData#begin" do
-> {
match_data.begin(:y)
- }.should raise_error(IndexError, "undefined group name reference: y")
+ }.should.raise(IndexError, "undefined group name reference: y")
end
end
end
diff --git a/spec/ruby/core/matchdata/bytebegin_spec.rb b/spec/ruby/core/matchdata/bytebegin_spec.rb
new file mode 100644
index 0000000000..fa44ec3b41
--- /dev/null
+++ b/spec/ruby/core/matchdata/bytebegin_spec.rb
@@ -0,0 +1,132 @@
+require_relative '../../spec_helper'
+
+ruby_version_is "3.4" do
+ describe "MatchData#bytebegin" do
+ context "when passed an integer argument" do
+ it "returns the byte-based offset of the start of the nth element" do
+ match_data = /(.)(.)(\d+)(\d)/.match("THX1138.")
+ match_data.bytebegin(0).should == 1
+ match_data.bytebegin(2).should == 2
+ end
+
+ it "returns nil when the nth match isn't found" do
+ match_data = /something is( not)? (right)/.match("something is right")
+ match_data.bytebegin(1).should == nil
+ end
+
+ it "returns the byte-based offset for multi-byte strings" do
+ match_data = /(.)(.)(\d+)(\d)/.match("TñX1138.")
+ match_data.bytebegin(0).should == 1
+ match_data.bytebegin(2).should == 3
+ end
+
+ not_supported_on :opal do
+ it "returns the byte-based offset for multi-byte strings with unicode regexp" do
+ match_data = /(.)(.)(\d+)(\d)/u.match("TñX1138.")
+ match_data.bytebegin(0).should == 1
+ match_data.bytebegin(2).should == 3
+ 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)
+
+ match_data = /(.)(.)(\d+)(\d)/.match("THX1138.")
+ match_data.bytebegin(obj).should == 2
+ end
+
+ it "raises IndexError if index is out of bounds" do
+ match_data = /(?<f>foo)(?<b>bar)/.match("foobar")
+
+ -> {
+ match_data.bytebegin(-1)
+ }.should.raise(IndexError, "index -1 out of matches")
+
+ -> {
+ match_data.bytebegin(3)
+ }.should.raise(IndexError, "index 3 out of matches")
+ end
+ end
+
+ context "when passed a String argument" do
+ it "return the byte-based offset of the start of the named capture" do
+ match_data = /(?<a>.)(.)(?<b>\d+)(\d)/.match("THX1138.")
+ match_data.bytebegin("a").should == 1
+ match_data.bytebegin("b").should == 3
+ end
+
+ it "returns the byte-based offset for multi byte strings" do
+ match_data = /(?<a>.)(.)(?<b>\d+)(\d)/.match("TñX1138.")
+ match_data.bytebegin("a").should == 1
+ match_data.bytebegin("b").should == 4
+ end
+
+ not_supported_on :opal do
+ it "returns the byte-based offset for multi byte strings with unicode regexp" do
+ match_data = /(?<a>.)(.)(?<b>\d+)(\d)/u.match("TñX1138.")
+ match_data.bytebegin("a").should == 1
+ match_data.bytebegin("b").should == 4
+ end
+ end
+
+ it "returns the byte-based offset for the farthest match when multiple named captures use the same name" do
+ match_data = /(?<a>.)(.)(?<a>\d+)(\d)/.match("THX1138.")
+ match_data.bytebegin("a").should == 3
+ end
+
+ it "returns the byte-based offset for multi-byte names" do
+ match_data = /(?<æ>.)(.)(?<b>\d+)(\d)/.match("THX1138.")
+ match_data.bytebegin("æ").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.bytebegin("y")
+ }.should.raise(IndexError, "undefined group name reference: y")
+ end
+ end
+
+ context "when passed a Symbol argument" do
+ it "return the byte-based offset of the start of the named capture" do
+ match_data = /(?<a>.)(.)(?<b>\d+)(\d)/.match("THX1138.")
+ match_data.bytebegin(:a).should == 1
+ match_data.bytebegin(:b).should == 3
+ end
+
+ it "returns the byte-based offset for multi byte strings" do
+ match_data = /(?<a>.)(.)(?<b>\d+)(\d)/.match("TñX1138.")
+ match_data.bytebegin(:a).should == 1
+ match_data.bytebegin(:b).should == 4
+ end
+
+ not_supported_on :opal do
+ it "returns the byte-based offset for multi byte strings with unicode regexp" do
+ match_data = /(?<a>.)(.)(?<b>\d+)(\d)/u.match("TñX1138.")
+ match_data.bytebegin(:a).should == 1
+ match_data.bytebegin(:b).should == 4
+ end
+ end
+
+ it "returns the byte-based offset for the farthest match when multiple named captures use the same name" do
+ match_data = /(?<a>.)(.)(?<a>\d+)(\d)/.match("THX1138.")
+ match_data.bytebegin(:a).should == 3
+ end
+
+ it "returns the byte-based offset for multi-byte names" do
+ match_data = /(?<æ>.)(.)(?<b>\d+)(\d)/.match("THX1138.")
+ match_data.bytebegin(:æ).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.bytebegin(:y)
+ }.should.raise(IndexError, "undefined group name reference: y")
+ end
+ end
+ end
+end
diff --git a/spec/ruby/core/matchdata/byteend_spec.rb b/spec/ruby/core/matchdata/byteend_spec.rb
new file mode 100644
index 0000000000..e77cbf8b0d
--- /dev/null
+++ b/spec/ruby/core/matchdata/byteend_spec.rb
@@ -0,0 +1,104 @@
+require_relative '../../spec_helper'
+
+ruby_version_is "3.4" do
+ describe "MatchData#byteend" do
+ context "when passed an integer argument" do
+ it "returns the byte-based offset of the end of the nth element" do
+ match_data = /(.)(.)(\d+)(\d)/.match("THX1138.")
+ match_data.byteend(0).should == 7
+ match_data.byteend(2).should == 3
+ end
+
+ it "returns nil when the nth match isn't found" do
+ match_data = /something is( not)? (right)/.match("something is right")
+ match_data.byteend(1).should == nil
+ end
+
+ it "returns the byte-based offset for multi-byte strings" do
+ match_data = /(.)(.)(\d+)(\d)/.match("TñX1138.")
+ match_data.byteend(0).should == 8
+ match_data.byteend(2).should == 4
+ end
+
+ not_supported_on :opal do
+ it "returns the byte-based offset for multi-byte strings with unicode regexp" do
+ match_data = /(.)(.)(\d+)(\d)/u.match("TñX1138.")
+ match_data.byteend(0).should == 8
+ match_data.byteend(2).should == 4
+ 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)
+
+ match_data = /(.)(.)(\d+)(\d)/.match("THX1138.")
+ match_data.byteend(obj).should == 3
+ end
+ end
+
+ context "when passed a String argument" do
+ it "return the byte-based offset of the start of the named capture" do
+ match_data = /(?<a>.)(.)(?<b>\d+)(\d)/.match("THX1138.")
+ match_data.byteend("a").should == 2
+ match_data.byteend("b").should == 6
+ end
+
+ it "returns the byte-based offset for multi byte strings" do
+ match_data = /(?<a>.)(.)(?<b>\d+)(\d)/.match("TñX1138.")
+ match_data.byteend("a").should == 3
+ match_data.byteend("b").should == 7
+ end
+
+ not_supported_on :opal do
+ it "returns the byte-based offset for multi byte strings with unicode regexp" do
+ match_data = /(?<a>.)(.)(?<b>\d+)(\d)/u.match("TñX1138.")
+ match_data.byteend("a").should == 3
+ match_data.byteend("b").should == 7
+ end
+ end
+
+ it "returns the byte-based offset for the farthest match when multiple named captures use the same name" do
+ match_data = /(?<a>.)(.)(?<a>\d+)(\d)/.match("THX1138.")
+ match_data.byteend("a").should == 6
+ end
+
+ it "returns the byte-based offset for multi-byte names" do
+ match_data = /(?<æ>.)(.)(?<b>\d+)(\d)/.match("THX1138.")
+ match_data.byteend("æ").should == 2
+ end
+ end
+
+ context "when passed a Symbol argument" do
+ it "return the byte-based offset of the start of the named capture" do
+ match_data = /(?<a>.)(.)(?<b>\d+)(\d)/.match("THX1138.")
+ match_data.byteend(:a).should == 2
+ match_data.byteend(:b).should == 6
+ end
+
+ it "returns the byte-based offset for multi byte strings" do
+ match_data = /(?<a>.)(.)(?<b>\d+)(\d)/.match("TñX1138.")
+ match_data.byteend(:a).should == 3
+ match_data.byteend(:b).should == 7
+ end
+
+ not_supported_on :opal do
+ it "returns the byte-based offset for multi byte strings with unicode regexp" do
+ match_data = /(?<a>.)(.)(?<b>\d+)(\d)/u.match("TñX1138.")
+ match_data.byteend(:a).should == 3
+ match_data.byteend(:b).should == 7
+ end
+ end
+
+ it "returns the byte-based offset for the farthest match when multiple named captures use the same name" do
+ match_data = /(?<a>.)(.)(?<a>\d+)(\d)/.match("THX1138.")
+ match_data.byteend(:a).should == 6
+ end
+
+ it "returns the byte-based offset for multi-byte names" do
+ match_data = /(?<æ>.)(.)(?<b>\d+)(\d)/.match("THX1138.")
+ match_data.byteend(:æ).should == 2
+ end
+ end
+ end
+end
diff --git a/spec/ruby/core/matchdata/byteoffset_spec.rb b/spec/ruby/core/matchdata/byteoffset_spec.rb
index fb8f5fb67d..062e84027c 100644
--- a/spec/ruby/core/matchdata/byteoffset_spec.rb
+++ b/spec/ruby/core/matchdata/byteoffset_spec.rb
@@ -64,11 +64,11 @@ describe "MatchData#byteoffset" do
-> {
m.byteoffset("y")
- }.should raise_error(IndexError, "undefined group name reference: y")
+ }.should.raise(IndexError, "undefined group name reference: y")
-> {
m.byteoffset(:y)
- }.should raise_error(IndexError, "undefined group name reference: y")
+ }.should.raise(IndexError, "undefined group name reference: y")
end
it "raises IndexError if index is out of bounds" do
@@ -76,11 +76,11 @@ describe "MatchData#byteoffset" do
-> {
m.byteoffset(-1)
- }.should raise_error(IndexError, "index -1 out of matches")
+ }.should.raise(IndexError, "index -1 out of matches")
-> {
m.byteoffset(3)
- }.should raise_error(IndexError, "index 3 out of matches")
+ }.should.raise(IndexError, "index 3 out of matches")
end
it "raises TypeError if can't convert argument into Integer" do
@@ -88,6 +88,6 @@ describe "MatchData#byteoffset" do
-> {
m.byteoffset([])
- }.should raise_error(TypeError, "no implicit conversion of Array into Integer")
+ }.should.raise(TypeError, "no implicit conversion of Array into Integer")
end
end
diff --git a/spec/ruby/core/matchdata/captures_spec.rb b/spec/ruby/core/matchdata/captures_spec.rb
index f829a25481..fdbc1c4346 100644
--- a/spec/ruby/core/matchdata/captures_spec.rb
+++ b/spec/ruby/core/matchdata/captures_spec.rb
@@ -1,6 +1,13 @@
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
+
+ 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.instance_of?(String) }
+ end
end
diff --git a/spec/ruby/core/matchdata/deconstruct_keys_spec.rb b/spec/ruby/core/matchdata/deconstruct_keys_spec.rb
index bf22bc33ff..9126d20394 100644
--- a/spec/ruby/core/matchdata/deconstruct_keys_spec.rb
+++ b/spec/ruby/core/matchdata/deconstruct_keys_spec.rb
@@ -18,16 +18,16 @@ describe "MatchData#deconstruct_keys" do
-> {
m.deconstruct_keys
- }.should raise_error(ArgumentError, "wrong number of arguments (given 0, expected 1)")
+ }.should.raise(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)")
+ -> { m.deconstruct_keys(1) }.should.raise(TypeError, "wrong argument type Integer (expected Array)")
+ -> { m.deconstruct_keys("asd") }.should.raise(TypeError, "wrong argument type String (expected Array)")
+ -> { m.deconstruct_keys(:x) }.should.raise(TypeError, "wrong argument type Symbol (expected Array)")
+ -> { m.deconstruct_keys({}) }.should.raise(TypeError, "wrong argument type Hash (expected Array)")
end
it "returns {} when passed []" do
@@ -41,7 +41,7 @@ describe "MatchData#deconstruct_keys" do
-> {
m.deconstruct_keys(['year', :foo])
- }.should raise_error(TypeError, "wrong argument type String (expected Symbol)")
+ }.should.raise(TypeError, "wrong argument type String (expected Symbol)")
end
it "process keys till the first non-existing one" do
@@ -60,4 +60,19 @@ describe "MatchData#deconstruct_keys" do
m = /(?<f>foo)(?<b>bar)/.match("foobar")
m.deconstruct_keys([:f, :b, :c]).should == {}
end
+
+ it "includes non-participating captures as nil for nil argument" do
+ m = "hello".match(/(?<a>hello)(?<b>world)?/)
+ m.deconstruct_keys(nil).should == { a: "hello", b: nil }
+ end
+
+ it "includes non-participating captures as nil for explicit keys" do
+ m = "hello".match(/(?<a>hello)(?<b>world)?/)
+ m.deconstruct_keys([:a, :b]).should == { a: "hello", b: nil }
+ end
+
+ it "does not stop iterating at a non-participating capture" do
+ m = "hello!".match(/(?<a>hello)(?<b>world)?(?<c>!)/)
+ m.deconstruct_keys([:b, :c, :a]).should == { b: nil, c: "!", a: "hello" }
+ end
end
diff --git a/spec/ruby/core/matchdata/deconstruct_spec.rb b/spec/ruby/core/matchdata/deconstruct_spec.rb
index c55095665d..13ebd1848f 100644
--- a/spec/ruby/core/matchdata/deconstruct_spec.rb
+++ b/spec/ruby/core/matchdata/deconstruct_spec.rb
@@ -1,6 +1,7 @@
require_relative '../../spec_helper'
-require_relative 'shared/captures'
describe "MatchData#deconstruct" do
- it_behaves_like :matchdata_captures, :deconstruct
+ it "is an alias of MatchData#captures" do
+ MatchData.instance_method(:deconstruct).should == MatchData.instance_method(:captures)
+ end
end
diff --git a/spec/ruby/core/matchdata/element_reference_spec.rb b/spec/ruby/core/matchdata/element_reference_spec.rb
index 0924be0aae..5509371cd2 100644
--- a/spec/ruby/core/matchdata/element_reference_spec.rb
+++ b/spec/ruby/core/matchdata/element_reference_spec.rb
@@ -55,7 +55,7 @@ describe "MatchData#[]" 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) }
+ /(.)(.)(\d+)(\d)/.match(str)[0..-1].each { |m| m.should.instance_of?(String) }
end
end
@@ -108,12 +108,12 @@ describe "MatchData#[Symbol]" do
it "raises an IndexError if there is no named match corresponding to the Symbol" do
md = 'haystack'.match(/(?<t>t(?<a>ack))/)
- -> { md[:baz] }.should raise_error(IndexError, /baz/)
+ -> { md[:baz] }.should.raise(IndexError, /baz/)
end
it "raises an IndexError if there is no named match corresponding to the String" do
md = 'haystack'.match(/(?<t>t(?<a>ack))/)
- -> { md['baz'] }.should raise_error(IndexError, /baz/)
+ -> { md['baz'] }.should.raise(IndexError, /baz/)
end
it "returns matches in the String's encoding" do
diff --git a/spec/ruby/core/matchdata/end_spec.rb b/spec/ruby/core/matchdata/end_spec.rb
index d01b0a8b30..4fee24a763 100644
--- a/spec/ruby/core/matchdata/end_spec.rb
+++ b/spec/ruby/core/matchdata/end_spec.rb
@@ -12,7 +12,7 @@ describe "MatchData#end" do
it "returns nil when the nth match isn't found" do
match_data = /something is( not)? (right)/.match("something is right")
- match_data.end(1).should be_nil
+ match_data.end(1).should == nil
end
it "returns the character offset for multi-byte strings" do
diff --git a/spec/ruby/core/matchdata/eql_spec.rb b/spec/ruby/core/matchdata/eql_spec.rb
index 1d9666ebe1..937c4424aa 100644
--- a/spec/ruby/core/matchdata/eql_spec.rb
+++ b/spec/ruby/core/matchdata/eql_spec.rb
@@ -1,6 +1,7 @@
require_relative '../../spec_helper'
-require_relative 'shared/eql'
describe "MatchData#eql?" do
- it_behaves_like :matchdata_eql, :eql?
+ it "is an alias of MatchData#==" do
+ MatchData.instance_method(:eql?).should == MatchData.instance_method(:==)
+ end
end
diff --git a/spec/ruby/core/matchdata/equal_value_spec.rb b/spec/ruby/core/matchdata/equal_value_spec.rb
index a58f1277e4..74d3a5adcd 100644
--- a/spec/ruby/core/matchdata/equal_value_spec.rb
+++ b/spec/ruby/core/matchdata/equal_value_spec.rb
@@ -1,6 +1,26 @@
require_relative '../../spec_helper'
-require_relative 'shared/eql'
describe "MatchData#==" do
- it_behaves_like :matchdata_eql, :==
+ it "returns true if both operands have equal target strings, patterns, and match positions" do
+ a = 'haystack'.match(/hay/)
+ b = 'haystack'.match(/hay/)
+ a.==(b).should == true
+ end
+
+ it "returns false if the operands have different target strings" do
+ a = 'hay'.match(/hay/)
+ b = 'haystack'.match(/hay/)
+ a.==(b).should == false
+ end
+
+ it "returns false if the operands have different patterns" do
+ a = 'haystack'.match(/h.y/)
+ b = 'haystack'.match(/hay/)
+ a.==(b).should == false
+ end
+
+ it "returns false if the argument is not a MatchData object" do
+ a = 'haystack'.match(/hay/)
+ a.==(Object.new).should == false
+ end
end
diff --git a/spec/ruby/core/matchdata/inspect_spec.rb b/spec/ruby/core/matchdata/inspect_spec.rb
index 5315257677..cacbe10c5d 100644
--- a/spec/ruby/core/matchdata/inspect_spec.rb
+++ b/spec/ruby/core/matchdata/inspect_spec.rb
@@ -6,7 +6,7 @@ describe "MatchData#inspect" do
end
it "returns a String" do
- @match_data.inspect.should be_kind_of(String)
+ @match_data.inspect.should.is_a?(String)
end
it "returns a human readable representation that contains entire matched string and the captures" do
diff --git a/spec/ruby/core/matchdata/integer_at_spec.rb b/spec/ruby/core/matchdata/integer_at_spec.rb
new file mode 100644
index 0000000000..65f73a7bee
--- /dev/null
+++ b/spec/ruby/core/matchdata/integer_at_spec.rb
@@ -0,0 +1,38 @@
+# -*- encoding: utf-8 -*-
+
+require_relative '../../spec_helper'
+
+ruby_version_is "4.1" do
+ describe "MatchData#integer_at" do
+ it "converts the corresponding match to an Integer and returns it when given an Integer" do
+ md = /(\d{4})(\d{2})(\d{2})/.match("20260308")
+ md.integer_at(0).should == 20260308
+ md.integer_at(1).should == 2026
+ md.integer_at(2).should == 3
+ end
+
+ it "returns nil on non-matching index matches" do
+ md = /\b(\d)?\b/.match("THX1138.")
+ md.integer_at(1).should == nil
+ end
+
+ it "returns nil on non-integer matches" do
+ md = /(\w)?/.match("THX1138.")
+ md.integer_at(1).should == nil
+ end
+
+ it "converts the match to an Integer in the given base" do
+ md = /\w+/.match("0c")
+ md.integer_at(0).should == 0
+ md.integer_at(0, 16).should == 12
+ end
+
+ it "converts the match to an Integer in the prefix when given base is zero" do
+ /\w+/.match("010").integer_at(0, 0).should == 010
+ /\w+/.match("0x10").integer_at(0, 0).should == 0x10
+ /\w+/.match("0d10").integer_at(0, 0).should == 0d10
+ /\w+/.match("0o10").integer_at(0, 0).should == 0o10
+ /\w+/.match("0b10").integer_at(0, 0).should == 0b10
+ end
+ end
+end
diff --git a/spec/ruby/core/matchdata/length_spec.rb b/spec/ruby/core/matchdata/length_spec.rb
index 39df36df4b..72d4d80cec 100644
--- a/spec/ruby/core/matchdata/length_spec.rb
+++ b/spec/ruby/core/matchdata/length_spec.rb
@@ -1,6 +1,7 @@
require_relative '../../spec_helper'
-require_relative 'shared/length'
describe "MatchData#length" do
- it_behaves_like :matchdata_length, :length
+ it "is an alias of MatchData#size" do
+ MatchData.instance_method(:length).should == MatchData.instance_method(:size)
+ end
end
diff --git a/spec/ruby/core/matchdata/named_captures_spec.rb b/spec/ruby/core/matchdata/named_captures_spec.rb
index 5e4693d62d..10b1f884d6 100644
--- a/spec/ruby/core/matchdata/named_captures_spec.rb
+++ b/spec/ruby/core/matchdata/named_captures_spec.rb
@@ -13,15 +13,13 @@ describe 'MatchData#named_captures' 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 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
+ 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
diff --git a/spec/ruby/core/matchdata/names_spec.rb b/spec/ruby/core/matchdata/names_spec.rb
index 25ca06ced9..dca15985b0 100644
--- a/spec/ruby/core/matchdata/names_spec.rb
+++ b/spec/ruby/core/matchdata/names_spec.rb
@@ -3,12 +3,12 @@ require_relative '../../spec_helper'
describe "MatchData#names" do
it "returns an Array" do
md = 'haystack'.match(/(?<yellow>hay)/)
- md.names.should be_an_instance_of(Array)
+ md.names.should.instance_of?(Array)
end
it "sets each element to a String" do
'haystack'.match(/(?<yellow>hay)/).names.all? do |e|
- e.should be_an_instance_of(String)
+ e.should.instance_of?(String)
end
end
diff --git a/spec/ruby/core/matchdata/offset_spec.rb b/spec/ruby/core/matchdata/offset_spec.rb
index 1ccb54b7a7..5a923d6ce0 100644
--- a/spec/ruby/core/matchdata/offset_spec.rb
+++ b/spec/ruby/core/matchdata/offset_spec.rb
@@ -1,30 +1,102 @@
-# -*- encoding: utf-8 -*-
-
require_relative '../../spec_helper'
describe "MatchData#offset" do
- it "returns a two element array with the begin and end of the nth match" do
- match_data = /(.)(.)(\d+)(\d)/.match("THX1138.")
- match_data.offset(0).should == [1, 7]
- match_data.offset(4).should == [6, 7]
+ it "returns beginning and ending character offset of whole matched substring for 0 element" do
+ m = /(.)(.)(\d+)(\d)/.match("THX1138.")
+ m.offset(0).should == [1, 7]
+ end
+
+ it "returns beginning and ending character offset of n-th match, all the subsequent elements are capturing groups" do
+ m = /(.)(.)(\d+)(\d)/.match("THX1138.")
+
+ m.offset(2).should == [2, 3]
+ m.offset(3).should == [3, 6]
+ m.offset(4).should == [6, 7]
+ end
+
+ it "accepts String as a reference to a named capture" do
+ m = /(?<f>foo)(?<b>bar)/.match("foobar")
+
+ m.offset("f").should == [0, 3]
+ m.offset("b").should == [3, 6]
+ end
+
+ it "accepts Symbol as a reference to a named capture" do
+ m = /(?<f>foo)(?<b>bar)/.match("foobar")
+
+ m.offset(:f).should == [0, 3]
+ m.offset(:b).should == [3, 6]
end
- it "returns [nil, nil] when the nth match isn't found" do
- match_data = /something is( not)? (right)/.match("something is right")
- match_data.offset(1).should == [nil, nil]
+ it "returns [nil, nil] if a capturing group is optional and doesn't match" do
+ m = /(?<x>q..)?/.match("foobarbaz")
+
+ m.offset("x").should == [nil, nil]
+ m.offset(1).should == [nil, nil]
end
- it "returns the offset for multi byte strings" do
- match_data = /(.)(.)(\d+)(\d)/.match("TñX1138.")
- match_data.offset(0).should == [1, 7]
- match_data.offset(4).should == [6, 7]
+ it "returns correct beginning and ending character offset for multi-byte strings" do
+ m = /\A\u3042(.)(.)?(.)\z/.match("\u3042\u3043\u3044")
+
+ m.offset(1).should == [1, 2]
+ m.offset(3).should == [2, 3]
end
not_supported_on :opal do
- it "returns the offset for multi byte strings with unicode regexp" do
- match_data = /(.)(.)(\d+)(\d)/u.match("TñX1138.")
- match_data.offset(0).should == [1, 7]
- match_data.offset(4).should == [6, 7]
+ it "returns correct character offset for multi-byte strings with unicode regexp" do
+ m = /\A\u3042(.)(.)?(.)\z/u.match("\u3042\u3043\u3044")
+
+ m.offset(1).should == [1, 2]
+ m.offset(3).should == [2, 3]
end
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.offset(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.offset(1r).should == [0, 3]
+ m.offset(1.1).should == [0, 3]
+ m.offset(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.offset("y")
+ }.should.raise(IndexError, "undefined group name reference: y")
+
+ -> {
+ m.offset(:y)
+ }.should.raise(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.offset(-1)
+ }.should.raise(IndexError, "index -1 out of matches")
+
+ -> {
+ m.offset(3)
+ }.should.raise(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.offset([])
+ }.should.raise(TypeError, "no implicit conversion of Array into Integer")
+ end
end
diff --git a/spec/ruby/core/matchdata/post_match_spec.rb b/spec/ruby/core/matchdata/post_match_spec.rb
index 7bfe6df119..b50d637124 100644
--- a/spec/ruby/core/matchdata/post_match_spec.rb
+++ b/spec/ruby/core/matchdata/post_match_spec.rb
@@ -9,16 +9,16 @@ describe "MatchData#post_match" do
it "sets the encoding to the encoding of the source String" do
str = "abc".dup.force_encoding Encoding::EUC_JP
- str.match(/b/).post_match.encoding.should equal(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.match(/c/).post_match.encoding.should equal(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)
+ /(.)(.)(\d+)(\d)/.match(str).post_match.should.instance_of?(String)
end
end
diff --git a/spec/ruby/core/matchdata/pre_match_spec.rb b/spec/ruby/core/matchdata/pre_match_spec.rb
index 2f1ba9b8f6..106612a4f7 100644
--- a/spec/ruby/core/matchdata/pre_match_spec.rb
+++ b/spec/ruby/core/matchdata/pre_match_spec.rb
@@ -9,16 +9,16 @@ describe "MatchData#pre_match" do
it "sets the encoding to the encoding of the source String" do
str = "abc".dup.force_encoding Encoding::EUC_JP
- str.match(/b/).pre_match.encoding.should equal(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.match(/a/).pre_match.encoding.should equal(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)
+ /(.)(.)(\d+)(\d)/.match(str).pre_match.should.instance_of?(String)
end
end
diff --git a/spec/ruby/core/matchdata/regexp_spec.rb b/spec/ruby/core/matchdata/regexp_spec.rb
index 099b59c559..7dcb0e62db 100644
--- a/spec/ruby/core/matchdata/regexp_spec.rb
+++ b/spec/ruby/core/matchdata/regexp_spec.rb
@@ -3,7 +3,7 @@ require_relative '../../spec_helper'
describe "MatchData#regexp" do
it "returns a Regexp object" do
m = 'haystack'.match(/hay/)
- m.regexp.should be_an_instance_of(Regexp)
+ m.regexp.should.instance_of?(Regexp)
end
it "returns the pattern used in the match" do
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/shared/eql.rb b/spec/ruby/core/matchdata/shared/eql.rb
deleted file mode 100644
index e021baa178..0000000000
--- a/spec/ruby/core/matchdata/shared/eql.rb
+++ /dev/null
@@ -1,26 +0,0 @@
-require_relative '../../../spec_helper'
-
-describe :matchdata_eql, shared: true do
- it "returns true if both operands have equal target strings, patterns, and match positions" do
- a = 'haystack'.match(/hay/)
- b = 'haystack'.match(/hay/)
- a.send(@method, b).should be_true
- end
-
- it "returns false if the operands have different target strings" do
- a = 'hay'.match(/hay/)
- b = 'haystack'.match(/hay/)
- a.send(@method, b).should be_false
- end
-
- it "returns false if the operands have different patterns" do
- a = 'haystack'.match(/h.y/)
- b = 'haystack'.match(/hay/)
- a.send(@method, b).should be_false
- end
-
- it "returns false if the argument is not a MatchData object" do
- a = 'haystack'.match(/hay/)
- a.send(@method, Object.new).should be_false
- end
-end
diff --git a/spec/ruby/core/matchdata/shared/length.rb b/spec/ruby/core/matchdata/shared/length.rb
deleted file mode 100644
index 6312a7ed4c..0000000000
--- a/spec/ruby/core/matchdata/shared/length.rb
+++ /dev/null
@@ -1,5 +0,0 @@
-describe :matchdata_length, shared: true do
- it "length should return the number of elements in the match array" do
- /(.)(.)(\d+)(\d)/.match("THX1138.").send(@method).should == 5
- end
-end
diff --git a/spec/ruby/core/matchdata/size_spec.rb b/spec/ruby/core/matchdata/size_spec.rb
index b4965db3b8..f93ded72cb 100644
--- a/spec/ruby/core/matchdata/size_spec.rb
+++ b/spec/ruby/core/matchdata/size_spec.rb
@@ -1,6 +1,7 @@
require_relative '../../spec_helper'
-require_relative 'shared/length'
describe "MatchData#size" do
- it_behaves_like :matchdata_length, :size
+ it "should return the number of elements in the match array" do
+ /(.)(.)(\d+)(\d)/.match("THX1138.").size.should == 5
+ end
end
diff --git a/spec/ruby/core/matchdata/string_spec.rb b/spec/ruby/core/matchdata/string_spec.rb
index 952e953318..50bbb5a64f 100644
--- a/spec/ruby/core/matchdata/string_spec.rb
+++ b/spec/ruby/core/matchdata/string_spec.rb
@@ -14,7 +14,7 @@ describe "MatchData#string" do
it "returns the same frozen string for every call" do
md = /(.)(.)(\d+)(\d)/.match("THX1138.")
- md.string.should equal(md.string)
+ md.string.should.equal?(md.string)
end
it "returns a frozen copy of the matched string for gsub!(String)" do
diff --git a/spec/ruby/core/matchdata/to_a_spec.rb b/spec/ruby/core/matchdata/to_a_spec.rb
index 4fa11ff604..c77fc4ab37 100644
--- a/spec/ruby/core/matchdata/to_a_spec.rb
+++ b/spec/ruby/core/matchdata/to_a_spec.rb
@@ -8,6 +8,6 @@ describe "MatchData#to_a" 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) }
+ /(.)(.)(\d+)(\d)/.match(str)[0..-1].to_a.each { |m| m.should.instance_of?(String) }
end
end
diff --git a/spec/ruby/core/matchdata/to_s_spec.rb b/spec/ruby/core/matchdata/to_s_spec.rb
index cd1c4dbca2..cbcc5e8a21 100644
--- a/spec/ruby/core/matchdata/to_s_spec.rb
+++ b/spec/ruby/core/matchdata/to_s_spec.rb
@@ -8,6 +8,6 @@ describe "MatchData#to_s" 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)
+ /(.)(.)(\d+)(\d)/.match(str).to_s.should.instance_of?(String)
end
end
diff --git a/spec/ruby/core/matchdata/values_at_spec.rb b/spec/ruby/core/matchdata/values_at_spec.rb
index 535719a2ee..ba5b0e662c 100644
--- a/spec/ruby/core/matchdata/values_at_spec.rb
+++ b/spec/ruby/core/matchdata/values_at_spec.rb
@@ -26,7 +26,7 @@ describe "MatchData#values_at" do
end
it "raises RangeError if any element of the range is negative and out of range" do
- -> { /(.)(.)(\d+)(\d)/.match("THX1138: The Movie").values_at(-6..3) }.should raise_error(RangeError, "-6..3 out of range")
+ -> { /(.)(.)(\d+)(\d)/.match("THX1138: The Movie").values_at(-6..3) }.should.raise(RangeError, "-6..3 out of range")
end
it "supports endless Range" do
@@ -71,6 +71,6 @@ describe "MatchData#values_at" do
it "fails when passed arguments of unsupported types" do
-> {
/(.)(.)(\d+)(\d)/.match("THX1138: The Movie").values_at(Object.new)
- }.should raise_error(TypeError, "no implicit conversion of Object into Integer")
+ }.should.raise(TypeError, "no implicit conversion of Object into Integer")
end
end
diff --git a/spec/ruby/core/math/acos_spec.rb b/spec/ruby/core/math/acos_spec.rb
index 8b321ab29b..4649dc527c 100644
--- a/spec/ruby/core/math/acos_spec.rb
+++ b/spec/ruby/core/math/acos_spec.rb
@@ -8,7 +8,7 @@ describe "Math.acos" do
end
it "returns a float" do
- Math.acos(1).should be_kind_of(Float )
+ Math.acos(1).should.is_a?(Float )
end
it "returns the arccosine of the argument" do
@@ -21,27 +21,27 @@ describe "Math.acos" do
end
it "raises an Math::DomainError if the argument is greater than 1.0" do
- -> { Math.acos(1.0001) }.should raise_error(Math::DomainError)
+ -> { Math.acos(1.0001) }.should.raise(Math::DomainError)
end
it "raises an Math::DomainError if the argument is less than -1.0" do
- -> { Math.acos(-1.0001) }.should raise_error(Math::DomainError)
+ -> { Math.acos(-1.0001) }.should.raise(Math::DomainError)
end
it "raises a TypeError if the string argument cannot be coerced with Float()" do
- -> { Math.acos("test") }.should raise_error(TypeError)
+ -> { Math.acos("test") }.should.raise(TypeError)
end
it "returns NaN given NaN" do
- Math.acos(nan_value).nan?.should be_true
+ Math.acos(nan_value).nan?.should == true
end
it "raises a TypeError if the argument cannot be coerced with Float()" do
- -> { Math.acos(MathSpecs::UserClass.new) }.should raise_error(TypeError)
+ -> { Math.acos(MathSpecs::UserClass.new) }.should.raise(TypeError)
end
it "raises a TypeError if the argument is nil" do
- -> { Math.acos(nil) }.should raise_error(TypeError)
+ -> { Math.acos(nil) }.should.raise(TypeError)
end
it "accepts any argument that can be coerced with Float()" do
diff --git a/spec/ruby/core/math/acosh_spec.rb b/spec/ruby/core/math/acosh_spec.rb
index 6707de95d3..ccacda37e0 100644
--- a/spec/ruby/core/math/acosh_spec.rb
+++ b/spec/ruby/core/math/acosh_spec.rb
@@ -3,7 +3,7 @@ require_relative 'fixtures/classes'
describe "Math.acosh" do
it "returns a float" do
- Math.acosh(1.0).should be_kind_of(Float)
+ Math.acosh(1.0).should.is_a?(Float)
end
it "returns the principle value of the inverse hyperbolic cosine of the argument" do
@@ -12,21 +12,21 @@ describe "Math.acosh" do
end
it "raises Math::DomainError if the passed argument is less than -1.0 or greater than 1.0" do
- -> { Math.acosh(1.0 - TOLERANCE) }.should raise_error(Math::DomainError)
- -> { Math.acosh(0) }.should raise_error(Math::DomainError)
- -> { Math.acosh(-1.0) }.should raise_error(Math::DomainError)
+ -> { Math.acosh(1.0 - TOLERANCE) }.should.raise(Math::DomainError)
+ -> { Math.acosh(0) }.should.raise(Math::DomainError)
+ -> { Math.acosh(-1.0) }.should.raise(Math::DomainError)
end
it "raises a TypeError if the argument cannot be coerced with Float()" do
- -> { Math.acosh("test") }.should raise_error(TypeError)
+ -> { Math.acosh("test") }.should.raise(TypeError)
end
it "returns NaN given NaN" do
- Math.acosh(nan_value).nan?.should be_true
+ Math.acosh(nan_value).nan?.should == true
end
it "raises a TypeError if the argument is nil" do
- -> { Math.acosh(nil) }.should raise_error(TypeError)
+ -> { Math.acosh(nil) }.should.raise(TypeError)
end
it "accepts any argument that can be coerced with Float()" do
diff --git a/spec/ruby/core/math/asin_spec.rb b/spec/ruby/core/math/asin_spec.rb
index 3a674a1147..1386bccc06 100644
--- a/spec/ruby/core/math/asin_spec.rb
+++ b/spec/ruby/core/math/asin_spec.rb
@@ -4,7 +4,7 @@ require_relative 'fixtures/classes'
# arcsine : (-1.0, 1.0) --> (-PI/2, PI/2)
describe "Math.asin" do
it "returns a float" do
- Math.asin(1).should be_kind_of(Float)
+ Math.asin(1).should.is_a?(Float)
end
it "returns the arcsine of the argument" do
@@ -17,23 +17,23 @@ describe "Math.asin" do
end
it "raises an Math::DomainError if the argument is greater than 1.0" do
- -> { Math.asin(1.0001) }.should raise_error( Math::DomainError)
+ -> { Math.asin(1.0001) }.should.raise( Math::DomainError)
end
it "raises an Math::DomainError if the argument is less than -1.0" do
- -> { Math.asin(-1.0001) }.should raise_error( Math::DomainError)
+ -> { Math.asin(-1.0001) }.should.raise( Math::DomainError)
end
it "raises a TypeError if the argument cannot be coerced with Float()" do
- -> { Math.asin("test") }.should raise_error(TypeError)
+ -> { Math.asin("test") }.should.raise(TypeError)
end
it "returns NaN given NaN" do
- Math.asin(nan_value).nan?.should be_true
+ Math.asin(nan_value).nan?.should == true
end
it "raises a TypeError if the argument is nil" do
- -> { Math.asin(nil) }.should raise_error(TypeError)
+ -> { Math.asin(nil) }.should.raise(TypeError)
end
it "accepts any argument that can be coerced with Float()" do
diff --git a/spec/ruby/core/math/asinh_spec.rb b/spec/ruby/core/math/asinh_spec.rb
index ff8210df0a..8aa019f05f 100644
--- a/spec/ruby/core/math/asinh_spec.rb
+++ b/spec/ruby/core/math/asinh_spec.rb
@@ -3,7 +3,7 @@ require_relative 'fixtures/classes'
describe "Math.asinh" do
it "returns a float" do
- Math.asinh(1.5).should be_kind_of(Float)
+ Math.asinh(1.5).should.is_a?(Float)
end
it "returns the inverse hyperbolic sin of the argument" do
@@ -19,15 +19,15 @@ describe "Math.asinh" do
end
it "raises a TypeError if the argument cannot be coerced with Float()" do
- -> { Math.asinh("test") }.should raise_error(TypeError)
+ -> { Math.asinh("test") }.should.raise(TypeError)
end
it "returns NaN given NaN" do
- Math.asinh(nan_value).nan?.should be_true
+ Math.asinh(nan_value).nan?.should == true
end
it "raises a TypeError if the argument is nil" do
- -> { Math.asinh(nil) }.should raise_error(TypeError)
+ -> { Math.asinh(nil) }.should.raise(TypeError)
end
it "accepts any argument that can be coerced with Float()" do
diff --git a/spec/ruby/core/math/atan2_spec.rb b/spec/ruby/core/math/atan2_spec.rb
index d4ef369d2a..1f1de506c5 100644
--- a/spec/ruby/core/math/atan2_spec.rb
+++ b/spec/ruby/core/math/atan2_spec.rb
@@ -3,7 +3,7 @@ require_relative 'fixtures/classes'
describe "Math.atan2" do
it "returns a float" do
- Math.atan2(1.2, 0.5).should be_kind_of(Float)
+ Math.atan2(1.2, 0.5).should.is_a?(Float)
end
it "returns the arc tangent of y, x" do
@@ -14,15 +14,15 @@ describe "Math.atan2" do
end
it "raises a TypeError if the argument cannot be coerced with Float()" do
- -> { Math.atan2(1.0, "test") }.should raise_error(TypeError)
- -> { Math.atan2("test", 0.0) }.should raise_error(TypeError)
- -> { Math.atan2("test", "this") }.should raise_error(TypeError)
+ -> { Math.atan2(1.0, "test") }.should.raise(TypeError)
+ -> { Math.atan2("test", 0.0) }.should.raise(TypeError)
+ -> { Math.atan2("test", "this") }.should.raise(TypeError)
end
it "raises a TypeError if the argument is nil" do
- -> { Math.atan2(nil, 1.0) }.should raise_error(TypeError)
- -> { Math.atan2(-1.0, nil) }.should raise_error(TypeError)
- -> { Math.atan2(nil, nil) }.should raise_error(TypeError)
+ -> { Math.atan2(nil, 1.0) }.should.raise(TypeError)
+ -> { Math.atan2(-1.0, nil) }.should.raise(TypeError)
+ -> { Math.atan2(nil, nil) }.should.raise(TypeError)
end
it "accepts any argument that can be coerced with Float()" do
diff --git a/spec/ruby/core/math/atan_spec.rb b/spec/ruby/core/math/atan_spec.rb
index 15edf68c05..07d04cdf82 100644
--- a/spec/ruby/core/math/atan_spec.rb
+++ b/spec/ruby/core/math/atan_spec.rb
@@ -4,7 +4,7 @@ require_relative 'fixtures/classes'
# arctangent : (-Inf, Inf) --> (-PI/2, PI/2)
describe "Math.atan" do
it "returns a float" do
- Math.atan(1).should be_kind_of(Float)
+ Math.atan(1).should.is_a?(Float)
end
it "returns the arctangent of the argument" do
@@ -17,15 +17,15 @@ describe "Math.atan" do
end
it "raises a TypeError if the argument cannot be coerced with Float()" do
- -> { Math.atan("test") }.should raise_error(TypeError)
+ -> { Math.atan("test") }.should.raise(TypeError)
end
it "returns NaN given NaN" do
- Math.atan(nan_value).nan?.should be_true
+ Math.atan(nan_value).nan?.should == true
end
it "raises a TypeError if the argument is nil" do
- -> { Math.atan(nil) }.should raise_error(TypeError)
+ -> { Math.atan(nil) }.should.raise(TypeError)
end
it "accepts any argument that can be coerced with Float()" do
diff --git a/spec/ruby/core/math/cbrt_spec.rb b/spec/ruby/core/math/cbrt_spec.rb
index 01cf923c71..4e2383043b 100644
--- a/spec/ruby/core/math/cbrt_spec.rb
+++ b/spec/ruby/core/math/cbrt_spec.rb
@@ -3,7 +3,7 @@ require_relative 'fixtures/classes'
describe "Math.cbrt" do
it "returns a float" do
- Math.cbrt(1).should be_an_instance_of(Float)
+ Math.cbrt(1).should.instance_of?(Float)
end
it "returns the cubic root of the argument" do
@@ -14,11 +14,11 @@ describe "Math.cbrt" do
end
it "raises a TypeError if the argument cannot be coerced with Float()" do
- -> { Math.cbrt("foobar") }.should raise_error(TypeError)
+ -> { Math.cbrt("foobar") }.should.raise(TypeError)
end
it "raises a TypeError if the argument is nil" do
- -> { Math.cbrt(nil) }.should raise_error(TypeError)
+ -> { Math.cbrt(nil) }.should.raise(TypeError)
end
it "accepts any argument that can be coerced with Float()" do
diff --git a/spec/ruby/core/math/cos_spec.rb b/spec/ruby/core/math/cos_spec.rb
index 006afeb2cc..e8602cde3c 100644
--- a/spec/ruby/core/math/cos_spec.rb
+++ b/spec/ruby/core/math/cos_spec.rb
@@ -4,7 +4,7 @@ require_relative 'fixtures/classes'
# cosine : (-Inf, Inf) --> (-1.0, 1.0)
describe "Math.cos" do
it "returns a float" do
- Math.cos(Math::PI).should be_kind_of(Float)
+ Math.cos(Math::PI).should.is_a?(Float)
end
it "returns the cosine of the argument expressed in radians" do
@@ -16,11 +16,11 @@ describe "Math.cos" do
end
it "raises a TypeError unless the argument is Numeric and has #to_f" do
- -> { Math.cos("test") }.should raise_error(TypeError)
+ -> { Math.cos("test") }.should.raise(TypeError)
end
it "returns NaN given NaN" do
- Math.cos(nan_value).nan?.should be_true
+ Math.cos(nan_value).nan?.should == true
end
describe "coerces its argument with #to_f" do
@@ -31,14 +31,14 @@ describe "Math.cos" do
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)
+ -> { Math.cos(nil) }.should.raise(TypeError)
+ -> { Math.cos(:abc) }.should.raise(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)
+ -> { Math.cos(object) }.should.raise(NoMethodError)
end
end
end
diff --git a/spec/ruby/core/math/cosh_spec.rb b/spec/ruby/core/math/cosh_spec.rb
index 049e117e56..2093d8a74a 100644
--- a/spec/ruby/core/math/cosh_spec.rb
+++ b/spec/ruby/core/math/cosh_spec.rb
@@ -3,7 +3,7 @@ require_relative 'fixtures/classes'
describe "Math.cosh" do
it "returns a float" do
- Math.cosh(1.0).should be_kind_of(Float)
+ Math.cosh(1.0).should.is_a?(Float)
end
it "returns the hyperbolic cosine of the argument" do
@@ -14,15 +14,15 @@ describe "Math.cosh" do
end
it "raises a TypeError if the argument cannot be coerced with Float()" do
- -> { Math.cosh("test") }.should raise_error(TypeError)
+ -> { Math.cosh("test") }.should.raise(TypeError)
end
it "returns NaN given NaN" do
- Math.cosh(nan_value).nan?.should be_true
+ Math.cosh(nan_value).nan?.should == true
end
it "raises a TypeError if the argument is nil" do
- -> { Math.cosh(nil) }.should raise_error(TypeError)
+ -> { Math.cosh(nil) }.should.raise(TypeError)
end
it "accepts any argument that can be coerced with Float()" do
diff --git a/spec/ruby/core/math/erf_spec.rb b/spec/ruby/core/math/erf_spec.rb
index b4e6248e43..5384e73ae9 100644
--- a/spec/ruby/core/math/erf_spec.rb
+++ b/spec/ruby/core/math/erf_spec.rb
@@ -5,7 +5,7 @@ require_relative 'fixtures/classes'
# distribution (which is a normalized form of the Gaussian function).
describe "Math.erf" do
it "returns a float" do
- Math.erf(1).should be_kind_of(Float)
+ Math.erf(1).should.is_a?(Float)
end
it "returns the error function of the argument" do
@@ -21,15 +21,15 @@ describe "Math.erf" do
end
it "raises a TypeError if the argument cannot be coerced with Float()" do
- -> { Math.erf("test") }.should raise_error(TypeError)
+ -> { Math.erf("test") }.should.raise(TypeError)
end
it "returns NaN given NaN" do
- Math.erf(nan_value).nan?.should be_true
+ Math.erf(nan_value).nan?.should == true
end
it "raises a TypeError if the argument is nil" do
- -> { Math.erf(nil) }.should raise_error(TypeError)
+ -> { Math.erf(nil) }.should.raise(TypeError)
end
it "accepts any argument that can be coerced with Float()" do
diff --git a/spec/ruby/core/math/erfc_spec.rb b/spec/ruby/core/math/erfc_spec.rb
index e465f5cf58..4e09a68d1e 100644
--- a/spec/ruby/core/math/erfc_spec.rb
+++ b/spec/ruby/core/math/erfc_spec.rb
@@ -4,7 +4,7 @@ require_relative 'fixtures/classes'
# erfc is the complementary error function
describe "Math.erfc" do
it "returns a float" do
- Math.erf(1).should be_kind_of(Float)
+ Math.erf(1).should.is_a?(Float)
end
it "returns the complementary error function of the argument" do
@@ -20,15 +20,15 @@ describe "Math.erfc" do
end
it "raises a TypeError if the argument cannot be coerced with Float()" do
- -> { Math.erfc("test") }.should raise_error(TypeError)
+ -> { Math.erfc("test") }.should.raise(TypeError)
end
it "returns NaN given NaN" do
- Math.erfc(nan_value).nan?.should be_true
+ Math.erfc(nan_value).nan?.should == true
end
it "raises a TypeError if the argument is nil" do
- -> { Math.erfc(nil) }.should raise_error(TypeError)
+ -> { Math.erfc(nil) }.should.raise(TypeError)
end
it "accepts any argument that can be coerced with Float()" do
diff --git a/spec/ruby/core/math/exp_spec.rb b/spec/ruby/core/math/exp_spec.rb
index 36eb49a8c7..3688482457 100644
--- a/spec/ruby/core/math/exp_spec.rb
+++ b/spec/ruby/core/math/exp_spec.rb
@@ -3,7 +3,7 @@ require_relative 'fixtures/classes'
describe "Math.exp" do
it "returns a float" do
- Math.exp(1.0).should be_kind_of(Float)
+ Math.exp(1.0).should.is_a?(Float)
end
it "returns the base-e exponential of the argument" do
@@ -14,15 +14,15 @@ describe "Math.exp" do
end
it "raises a TypeError if the argument cannot be coerced with Float()" do
- -> { Math.exp("test") }.should raise_error(TypeError)
+ -> { Math.exp("test") }.should.raise(TypeError)
end
it "returns NaN given NaN" do
- Math.exp(nan_value).nan?.should be_true
+ Math.exp(nan_value).nan?.should == true
end
it "raises a TypeError if the argument is nil" do
- -> { Math.exp(nil) }.should raise_error(TypeError)
+ -> { Math.exp(nil) }.should.raise(TypeError)
end
it "accepts any argument that can be coerced with Float()" do
diff --git a/spec/ruby/core/math/expm1_spec.rb b/spec/ruby/core/math/expm1_spec.rb
new file mode 100644
index 0000000000..35f62b5dbd
--- /dev/null
+++ b/spec/ruby/core/math/expm1_spec.rb
@@ -0,0 +1,37 @@
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
+
+ruby_version_is "4.0" do
+ describe "Math.expm1" do
+ it "calculates Math.exp(arg) - 1" do
+ Math.expm1(3).should == Math.exp(3) - 1
+ end
+
+ it "preserves precision that can be lost otherwise" do
+ Math.expm1(1.0e-16).should be_close(1.0e-16, TOLERANCE)
+ Math.expm1(1.0e-16).should != 0.0
+ end
+
+ it "raises a TypeError if the argument cannot be coerced with Float()" do
+ -> { Math.expm1("test") }.should.raise(TypeError, "can't convert String into Float")
+ end
+
+ it "returns NaN given NaN" do
+ Math.expm1(nan_value).nan?.should == true
+ end
+
+ it "raises a TypeError if the argument is nil" do
+ -> { Math.expm1(nil) }.should.raise(TypeError, "can't convert nil into Float")
+ end
+
+ it "accepts any argument that can be coerced with Float()" do
+ Math.expm1(MathSpecs::Float.new).should be_close(Math::E - 1, TOLERANCE)
+ end
+ end
+
+ describe "Math#expm1" do
+ it "is accessible as a private instance method" do
+ IncludesMath.new.send(:expm1, 23.1415).should be_close(11226018483.0012, TOLERANCE)
+ end
+ end
+end
diff --git a/spec/ruby/core/math/frexp_spec.rb b/spec/ruby/core/math/frexp_spec.rb
index 7dfb493d20..6853e4672f 100644
--- a/spec/ruby/core/math/frexp_spec.rb
+++ b/spec/ruby/core/math/frexp_spec.rb
@@ -9,16 +9,16 @@ describe "Math.frexp" do
end
it "raises a TypeError if the argument cannot be coerced with Float()" do
- -> { Math.frexp("test") }.should raise_error(TypeError)
+ -> { Math.frexp("test") }.should.raise(TypeError)
end
it "returns NaN given NaN" do
frac, _exp = Math.frexp(nan_value)
- frac.nan?.should be_true
+ frac.nan?.should == true
end
it "raises a TypeError if the argument is nil" do
- -> { Math.frexp(nil) }.should raise_error(TypeError)
+ -> { Math.frexp(nil) }.should.raise(TypeError)
end
it "accepts any argument that can be coerced with Float()" do
diff --git a/spec/ruby/core/math/gamma_spec.rb b/spec/ruby/core/math/gamma_spec.rb
index 386162a087..9a0b14448a 100644
--- a/spec/ruby/core/math/gamma_spec.rb
+++ b/spec/ruby/core/math/gamma_spec.rb
@@ -51,7 +51,7 @@ describe "Math.gamma" do
end
it "raises Math::DomainError given -1" do
- -> { Math.gamma(-1) }.should raise_error(Math::DomainError)
+ -> { Math.gamma(-1) }.should.raise(Math::DomainError)
end
# See https://bugs.ruby-lang.org/issues/10642
@@ -60,10 +60,10 @@ describe "Math.gamma" do
end
it "raises Math::DomainError given negative infinity" do
- -> { Math.gamma(-Float::INFINITY) }.should raise_error(Math::DomainError)
+ -> { Math.gamma(-Float::INFINITY) }.should.raise(Math::DomainError)
end
it "returns NaN given NaN" do
- Math.gamma(nan_value).nan?.should be_true
+ Math.gamma(nan_value).nan?.should == true
end
end
diff --git a/spec/ruby/core/math/hypot_spec.rb b/spec/ruby/core/math/hypot_spec.rb
index 3e0ce74597..4ab5bd4e88 100644
--- a/spec/ruby/core/math/hypot_spec.rb
+++ b/spec/ruby/core/math/hypot_spec.rb
@@ -3,7 +3,7 @@ require_relative 'fixtures/classes'
describe "Math.hypot" do
it "returns a float" do
- Math.hypot(3, 4).should be_kind_of(Float)
+ Math.hypot(3, 4).should.is_a?(Float)
end
it "returns the length of the hypotenuse of a right triangle with legs given by the arguments" do
@@ -16,17 +16,17 @@ describe "Math.hypot" do
end
it "raises a TypeError if the argument cannot be coerced with Float()" do
- -> { Math.hypot("test", "this") }.should raise_error(TypeError)
+ -> { Math.hypot("test", "this") }.should.raise(TypeError)
end
it "returns NaN given NaN" do
- Math.hypot(nan_value, 0).nan?.should be_true
- Math.hypot(0, nan_value).nan?.should be_true
- Math.hypot(nan_value, nan_value).nan?.should be_true
+ Math.hypot(nan_value, 0).nan?.should == true
+ Math.hypot(0, nan_value).nan?.should == true
+ Math.hypot(nan_value, nan_value).nan?.should == true
end
it "raises a TypeError if the argument is nil" do
- -> { Math.hypot(nil, nil) }.should raise_error(TypeError)
+ -> { Math.hypot(nil, nil) }.should.raise(TypeError)
end
it "accepts any argument that can be coerced with Float()" do
diff --git a/spec/ruby/core/math/ldexp_spec.rb b/spec/ruby/core/math/ldexp_spec.rb
index 6dcf94a663..1864b7455a 100644
--- a/spec/ruby/core/math/ldexp_spec.rb
+++ b/spec/ruby/core/math/ldexp_spec.rb
@@ -3,7 +3,7 @@ require_relative 'fixtures/classes'
describe "Math.ldexp" do
it "returns a float" do
- Math.ldexp(1.0, 2).should be_kind_of(Float)
+ Math.ldexp(1.0, 2).should.is_a?(Float)
end
it "returns the argument multiplied by 2**n" do
@@ -15,27 +15,27 @@ describe "Math.ldexp" do
end
it "raises a TypeError if the first argument cannot be coerced with Float()" do
- -> { Math.ldexp("test", 2) }.should raise_error(TypeError)
+ -> { Math.ldexp("test", 2) }.should.raise(TypeError)
end
it "returns NaN given NaN" do
- Math.ldexp(nan_value, 0).nan?.should be_true
+ Math.ldexp(nan_value, 0).nan?.should == true
end
it "raises RangeError if NaN is given as the second arg" do
- -> { Math.ldexp(0, nan_value) }.should raise_error(RangeError)
+ -> { Math.ldexp(0, nan_value) }.should.raise(RangeError)
end
it "raises a TypeError if the second argument cannot be coerced with Integer()" do
- -> { Math.ldexp(3.2, "this") }.should raise_error(TypeError)
+ -> { Math.ldexp(3.2, "this") }.should.raise(TypeError)
end
it "raises a TypeError if the first argument is nil" do
- -> { Math.ldexp(nil, 2) }.should raise_error(TypeError)
+ -> { Math.ldexp(nil, 2) }.should.raise(TypeError)
end
it "raises a TypeError if the second argument is nil" do
- -> { Math.ldexp(3.1, nil) }.should raise_error(TypeError)
+ -> { Math.ldexp(3.1, nil) }.should.raise(TypeError)
end
it "accepts any first argument that can be coerced with Float()" do
diff --git a/spec/ruby/core/math/lgamma_spec.rb b/spec/ruby/core/math/lgamma_spec.rb
index 33e7836448..38f07d0bf8 100644
--- a/spec/ruby/core/math/lgamma_spec.rb
+++ b/spec/ruby/core/math/lgamma_spec.rb
@@ -5,10 +5,8 @@ describe "Math.lgamma" do
Math.lgamma(0).should == [infinity_value, 1]
end
- platform_is_not :windows do
- it "returns [Infinity, 1] when passed -1" do
- Math.lgamma(-1).should == [infinity_value, 1]
- end
+ it "returns [Infinity, ...] when passed -1" do
+ Math.lgamma(-1)[0].should == infinity_value
end
it "returns [Infinity, -1] when passed -0.0" do
@@ -40,15 +38,14 @@ describe "Math.lgamma" do
end
it "raises Math::DomainError when passed -Infinity" do
- -> { Math.lgamma(-infinity_value) }.should raise_error(Math::DomainError)
+ -> { Math.lgamma(-infinity_value) }.should.raise(Math::DomainError)
end
it "returns [Infinity, 1] when passed Infinity" do
Math.lgamma(infinity_value).should == [infinity_value, 1]
end
- it "returns [NaN, 1] when passed NaN" do
- Math.lgamma(nan_value)[0].nan?.should be_true
- Math.lgamma(nan_value)[1].should == 1
+ it "returns [NaN, ...] when passed NaN" do
+ Math.lgamma(nan_value)[0].should.nan?
end
end
diff --git a/spec/ruby/core/math/log10_spec.rb b/spec/ruby/core/math/log10_spec.rb
index c4daedcd5c..7576a67002 100644
--- a/spec/ruby/core/math/log10_spec.rb
+++ b/spec/ruby/core/math/log10_spec.rb
@@ -4,7 +4,7 @@ require_relative 'fixtures/classes'
# The common logarithm, having base 10
describe "Math.log10" do
it "returns a float" do
- Math.log10(1).should be_kind_of(Float)
+ Math.log10(1).should.is_a?(Float)
end
it "returns the base-10 logarithm of the argument" do
@@ -16,19 +16,23 @@ describe "Math.log10" do
end
it "raises an Math::DomainError if the argument is less than 0" do
- -> { Math.log10(-1e-15) }.should raise_error(Math::DomainError)
+ -> { Math.log10(-1e-15) }.should.raise(Math::DomainError)
end
it "raises a TypeError if the argument cannot be coerced with Float()" do
- -> { Math.log10("test") }.should raise_error(TypeError)
+ -> { Math.log10("test") }.should.raise(TypeError)
+ end
+
+ it "raises a TypeError if passed a numerical argument as a string" do
+ -> { Math.log10("1.0") }.should.raise(TypeError)
end
it "returns NaN given NaN" do
- Math.log10(nan_value).nan?.should be_true
+ Math.log10(nan_value).nan?.should == true
end
it "raises a TypeError if the argument is nil" do
- -> { Math.log10(nil) }.should raise_error(TypeError)
+ -> { Math.log10(nil) }.should.raise(TypeError)
end
it "accepts any argument that can be coerced with Float()" do
diff --git a/spec/ruby/core/math/log1p_spec.rb b/spec/ruby/core/math/log1p_spec.rb
new file mode 100644
index 0000000000..181b462ded
--- /dev/null
+++ b/spec/ruby/core/math/log1p_spec.rb
@@ -0,0 +1,49 @@
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
+
+ruby_version_is "4.0" do
+ describe "Math.log1p" do
+ it "calculates Math.log(1 + arg)" do
+ Math.log1p(3).should == Math.log(1 + 3)
+ end
+
+ it "preserves precision that can be lost otherwise" do
+ Math.log1p(1e-16).should be_close(1.0e-16, TOLERANCE)
+ Math.log1p(1e-16).should != 0.0
+ end
+
+ it "raises an Math::DomainError if the argument is less than 1" do
+ -> { Math.log1p(-1-1e-15) }.should.raise(Math::DomainError, "Numerical argument is out of domain - log1p")
+ end
+
+ it "raises a TypeError if the argument cannot be coerced with Float()" do
+ -> { Math.log1p("test") }.should.raise(TypeError, "can't convert String into Float")
+ end
+
+ it "raises a TypeError for numerical values passed as string" do
+ -> { Math.log1p("10") }.should.raise(TypeError, "can't convert String into Float")
+ end
+
+ it "does not accept a second argument for the base" do
+ -> { Math.log1p(9, 3) }.should.raise(ArgumentError, "wrong number of arguments (given 2, expected 1)")
+ end
+
+ it "returns NaN given NaN" do
+ Math.log1p(nan_value).nan?.should == true
+ end
+
+ it "raises a TypeError if the argument is nil" do
+ -> { Math.log1p(nil) }.should.raise(TypeError, "can't convert nil into Float")
+ end
+
+ it "accepts any argument that can be coerced with Float()" do
+ Math.log1p(MathSpecs::Float.new).should be_close(0.6931471805599453, TOLERANCE)
+ end
+ end
+
+ describe "Math#log1p" do
+ it "is accessible as a private instance method" do
+ IncludesMath.new.send(:log1p, 4.21).should be_close(1.65057985576528, TOLERANCE)
+ end
+ end
+end
diff --git a/spec/ruby/core/math/log2_spec.rb b/spec/ruby/core/math/log2_spec.rb
index 3d4d41d130..e38a8bb67f 100644
--- a/spec/ruby/core/math/log2_spec.rb
+++ b/spec/ruby/core/math/log2_spec.rb
@@ -16,23 +16,23 @@ describe "Math.log2" do
end
it "raises Math::DomainError if the argument is less than 0" do
- -> { Math.log2(-1e-15) }.should raise_error( Math::DomainError)
+ -> { Math.log2(-1e-15) }.should.raise( Math::DomainError)
end
it "raises a TypeError if the argument cannot be coerced with Float()" do
- -> { Math.log2("test") }.should raise_error(TypeError)
+ -> { Math.log2("test") }.should.raise(TypeError)
end
it "raises a TypeError if passed a numerical argument as a string" do
- -> { Math.log2("1.0") }.should raise_error(TypeError)
+ -> { Math.log2("1.0") }.should.raise(TypeError)
end
it "returns NaN given NaN" do
- Math.log2(nan_value).nan?.should be_true
+ Math.log2(nan_value).nan?.should == true
end
it "raises a TypeError if the argument is nil" do
- -> { Math.log2(nil) }.should raise_error(TypeError)
+ -> { Math.log2(nil) }.should.raise(TypeError)
end
it "accepts any argument that can be coerced with Float()" do
diff --git a/spec/ruby/core/math/log_spec.rb b/spec/ruby/core/math/log_spec.rb
index 6c5036ba81..7e0bc13bc6 100644
--- a/spec/ruby/core/math/log_spec.rb
+++ b/spec/ruby/core/math/log_spec.rb
@@ -4,7 +4,7 @@ require_relative 'fixtures/classes'
# The natural logarithm, having base Math::E
describe "Math.log" do
it "returns a float" do
- Math.log(1).should be_kind_of(Float)
+ Math.log(1).should.is_a?(Float)
end
it "returns the natural logarithm of the argument" do
@@ -16,15 +16,15 @@ describe "Math.log" do
end
it "raises an Math::DomainError if the argument is less than 0" do
- -> { Math.log(-1e-15) }.should raise_error(Math::DomainError)
+ -> { Math.log(-1e-15) }.should.raise(Math::DomainError)
end
it "raises a TypeError if the argument cannot be coerced with Float()" do
- -> { Math.log("test") }.should raise_error(TypeError)
+ -> { Math.log("test") }.should.raise(TypeError)
end
it "raises a TypeError for numerical values passed as string" do
- -> { Math.log("10") }.should raise_error(TypeError)
+ -> { Math.log("10") }.should.raise(TypeError)
end
it "accepts a second argument for the base" do
@@ -33,16 +33,16 @@ describe "Math.log" do
end
it "raises a TypeError when the numerical base cannot be coerced to a float" do
- -> { Math.log(10, "2") }.should raise_error(TypeError)
- -> { Math.log(10, nil) }.should raise_error(TypeError)
+ -> { Math.log(10, "2") }.should.raise(TypeError)
+ -> { Math.log(10, nil) }.should.raise(TypeError)
end
it "returns NaN given NaN" do
- Math.log(nan_value).nan?.should be_true
+ Math.log(nan_value).nan?.should == true
end
it "raises a TypeError if the argument is nil" do
- -> { Math.log(nil) }.should raise_error(TypeError)
+ -> { Math.log(nil) }.should.raise(TypeError)
end
it "accepts any argument that can be coerced with Float()" do
diff --git a/spec/ruby/core/math/shared/atanh.rb b/spec/ruby/core/math/shared/atanh.rb
index 3fb64153a0..48a6bf836e 100644
--- a/spec/ruby/core/math/shared/atanh.rb
+++ b/spec/ruby/core/math/shared/atanh.rb
@@ -1,6 +1,6 @@
describe :math_atanh_base, shared: true do
it "returns a float" do
- @object.send(@method, 0.5).should be_an_instance_of(Float)
+ @object.send(@method, 0.5).should.instance_of?(Float)
end
it "returns the inverse hyperbolic tangent of the argument" do
@@ -11,11 +11,11 @@ describe :math_atanh_base, shared: true do
end
it "raises a TypeError if the argument is nil" do
- -> { @object.send(@method, nil) }.should raise_error(TypeError)
+ -> { @object.send(@method, nil) }.should.raise(TypeError)
end
it "raises a TypeError if the argument is not a Numeric" do
- -> { @object.send(@method, "test") }.should raise_error(TypeError)
+ -> { @object.send(@method, "test") }.should.raise(TypeError)
end
it "returns Infinity if x == 1.0" do
@@ -29,16 +29,16 @@ end
describe :math_atanh_private, shared: true do
it "is a private instance method" do
- Math.should have_private_instance_method(@method)
+ Math.private_instance_methods(false).should.include?(@method)
end
end
describe :math_atanh_no_complex, shared: true do
it "raises a Math::DomainError for arguments greater than 1.0" do
- -> { @object.send(@method, 1.0 + Float::EPSILON) }.should raise_error(Math::DomainError)
+ -> { @object.send(@method, 1.0 + Float::EPSILON) }.should.raise(Math::DomainError)
end
it "raises a Math::DomainError for arguments less than -1.0" do
- -> { @object.send(@method, -1.0 - Float::EPSILON) }.should raise_error(Math::DomainError)
+ -> { @object.send(@method, -1.0 - Float::EPSILON) }.should.raise(Math::DomainError)
end
end
diff --git a/spec/ruby/core/math/sin_spec.rb b/spec/ruby/core/math/sin_spec.rb
index 8e944bc95f..a9479e3aec 100644
--- a/spec/ruby/core/math/sin_spec.rb
+++ b/spec/ruby/core/math/sin_spec.rb
@@ -4,7 +4,7 @@ require_relative 'fixtures/classes'
# sine : (-Inf, Inf) --> (-1.0, 1.0)
describe "Math.sin" do
it "returns a float" do
- Math.sin(Math::PI).should be_kind_of(Float)
+ Math.sin(Math::PI).should.is_a?(Float)
end
it "returns the sine of the argument expressed in radians" do
@@ -16,15 +16,15 @@ describe "Math.sin" do
end
it "raises a TypeError if the argument cannot be coerced with Float()" do
- -> { Math.sin("test") }.should raise_error(TypeError)
+ -> { Math.sin("test") }.should.raise(TypeError)
end
it "returns NaN given NaN" do
- Math.sin(nan_value).nan?.should be_true
+ Math.sin(nan_value).nan?.should == true
end
it "raises a TypeError if the argument is nil" do
- -> { Math.sin(nil) }.should raise_error(TypeError)
+ -> { Math.sin(nil) }.should.raise(TypeError)
end
it "accepts any argument that can be coerced with Float()" do
diff --git a/spec/ruby/core/math/sinh_spec.rb b/spec/ruby/core/math/sinh_spec.rb
index 027c2395a7..de0f06affa 100644
--- a/spec/ruby/core/math/sinh_spec.rb
+++ b/spec/ruby/core/math/sinh_spec.rb
@@ -3,7 +3,7 @@ require_relative 'fixtures/classes'
describe "Math.sinh" do
it "returns a float" do
- Math.sinh(1.2).should be_kind_of(Float)
+ Math.sinh(1.2).should.is_a?(Float)
end
it "returns the hyperbolic sin of the argument" do
@@ -14,15 +14,15 @@ describe "Math.sinh" do
end
it "raises a TypeError if the argument cannot be coerced with Float()" do
- -> { Math.sinh("test") }.should raise_error(TypeError)
+ -> { Math.sinh("test") }.should.raise(TypeError)
end
it "returns NaN given NaN" do
- Math.sinh(nan_value).nan?.should be_true
+ Math.sinh(nan_value).nan?.should == true
end
it "raises a TypeError if the argument is nil" do
- -> { Math.sinh(nil) }.should raise_error(TypeError)
+ -> { Math.sinh(nil) }.should.raise(TypeError)
end
it "accepts any argument that can be coerced with Float()" do
diff --git a/spec/ruby/core/math/sqrt_spec.rb b/spec/ruby/core/math/sqrt_spec.rb
index 918e7c3a17..545fa4d1c2 100644
--- a/spec/ruby/core/math/sqrt_spec.rb
+++ b/spec/ruby/core/math/sqrt_spec.rb
@@ -3,7 +3,7 @@ require_relative 'fixtures/classes'
describe "Math.sqrt" do
it "returns a float" do
- Math.sqrt(1).should be_kind_of(Float)
+ Math.sqrt(1).should.is_a?(Float)
end
it "returns the square root of the argument" do
@@ -13,15 +13,15 @@ describe "Math.sqrt" do
end
it "raises a TypeError if the argument cannot be coerced with Float()" do
- -> { Math.sqrt("test") }.should raise_error(TypeError)
+ -> { Math.sqrt("test") }.should.raise(TypeError)
end
it "returns NaN given NaN" do
- Math.sqrt(nan_value).nan?.should be_true
+ Math.sqrt(nan_value).nan?.should == true
end
it "raises a TypeError if the argument is nil" do
- -> { Math.sqrt(nil) }.should raise_error(TypeError)
+ -> { Math.sqrt(nil) }.should.raise(TypeError)
end
it "accepts any argument that can be coerced with Float()" do
@@ -29,7 +29,7 @@ describe "Math.sqrt" do
end
it "raises a Math::DomainError when given a negative number" do
- -> { Math.sqrt(-1) }.should raise_error(Math::DomainError)
+ -> { Math.sqrt(-1) }.should.raise(Math::DomainError)
end
end
diff --git a/spec/ruby/core/math/tan_spec.rb b/spec/ruby/core/math/tan_spec.rb
index 67307f1e6e..c3e773f318 100644
--- a/spec/ruby/core/math/tan_spec.rb
+++ b/spec/ruby/core/math/tan_spec.rb
@@ -3,7 +3,7 @@ require_relative 'fixtures/classes'
describe "Math.tan" do
it "returns a float" do
- Math.tan(1.35).should be_kind_of(Float)
+ Math.tan(1.35).should.is_a?(Float)
end
it "returns the tangent of the argument" do
@@ -19,15 +19,15 @@ describe "Math.tan" do
end
it "raises a TypeError if the argument cannot be coerced with Float()" do
- -> { Math.tan("test") }.should raise_error(TypeError)
+ -> { Math.tan("test") }.should.raise(TypeError)
end
it "returns NaN given NaN" do
- Math.tan(nan_value).nan?.should be_true
+ Math.tan(nan_value).nan?.should == true
end
it "raises a TypeError if the argument is nil" do
- -> { Math.tan(nil) }.should raise_error(TypeError)
+ -> { Math.tan(nil) }.should.raise(TypeError)
end
it "accepts any argument that can be coerced with Float()" do
diff --git a/spec/ruby/core/math/tanh_spec.rb b/spec/ruby/core/math/tanh_spec.rb
index 568f8dfa77..74a938ffd8 100644
--- a/spec/ruby/core/math/tanh_spec.rb
+++ b/spec/ruby/core/math/tanh_spec.rb
@@ -3,7 +3,7 @@ require_relative 'fixtures/classes'
describe "Math.tanh" do
it "returns a float" do
- Math.tanh(0.5).should be_kind_of(Float)
+ Math.tanh(0.5).should.is_a?(Float)
end
it "returns the hyperbolic tangent of the argument" do
@@ -16,15 +16,15 @@ describe "Math.tanh" do
end
it "raises a TypeError if the argument cannot be coerced with Float()" do
- -> { Math.tanh("test") }.should raise_error(TypeError)
+ -> { Math.tanh("test") }.should.raise(TypeError)
end
it "returns NaN given NaN" do
- Math.tanh(nan_value).nan?.should be_true
+ Math.tanh(nan_value).nan?.should == true
end
it "raises a TypeError if the argument is nil" do
- -> { Math.tanh(nil) }.should raise_error(TypeError)
+ -> { Math.tanh(nil) }.should.raise(TypeError)
end
it "accepts any argument that can be coerced with Float()" do
diff --git a/spec/ruby/core/method/call_spec.rb b/spec/ruby/core/method/call_spec.rb
index 6d997325fa..cb11545e91 100644
--- a/spec/ruby/core/method/call_spec.rb
+++ b/spec/ruby/core/method/call_spec.rb
@@ -1,7 +1,54 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
-require_relative 'shared/call'
describe "Method#call" do
- it_behaves_like :method_call, :call
+ it "invokes the method with the specified arguments, returning the method's return value" do
+ m = 12.method("+")
+ m.call(3).should == 15
+ m.call(20).should == 32
+
+ m = MethodSpecs::Methods.new.method(:attr=)
+ m.call(42).should == 42
+ end
+
+ it "raises an ArgumentError when given incorrect number of arguments" do
+ -> {
+ MethodSpecs::Methods.new.method(:two_req).call(1, 2, 3)
+ }.should.raise(ArgumentError)
+ -> {
+ MethodSpecs::Methods.new.method(:two_req).call(1)
+ }.should.raise(ArgumentError)
+ end
+
+ describe "for a Method generated by respond_to_missing?" do
+ it "invokes method_missing with the specified arguments and returns the result" do
+ @m = MethodSpecs::Methods.new
+ meth = @m.method(:handled_via_method_missing)
+ meth.call(:argument).should == [:argument]
+ end
+
+ it "invokes method_missing with the method name and the specified arguments" do
+ @m = MethodSpecs::Methods.new
+ meth = @m.method(:handled_via_method_missing)
+
+ @m.should_receive(:method_missing).with(:handled_via_method_missing, :argument)
+ meth.call(:argument)
+ end
+
+ it "invokes method_missing dynamically" do
+ @m = MethodSpecs::Methods.new
+ meth = @m.method(:handled_via_method_missing)
+
+ def @m.method_missing(*); :changed; end
+ meth.call(:argument).should == :changed
+ end
+
+ it "does not call the original method name even if it now exists" do
+ @m = MethodSpecs::Methods.new
+ meth = @m.method(:handled_via_method_missing)
+
+ def @m.handled_via_method_missing(*); :not_called; end
+ meth.call(:argument).should == [:argument]
+ end
+ end
end
diff --git a/spec/ruby/core/method/case_compare_spec.rb b/spec/ruby/core/method/case_compare_spec.rb
index a78953e8ad..771fea1ce5 100644
--- a/spec/ruby/core/method/case_compare_spec.rb
+++ b/spec/ruby/core/method/case_compare_spec.rb
@@ -1,7 +1,7 @@
require_relative '../../spec_helper'
-require_relative 'fixtures/classes'
-require_relative 'shared/call'
describe "Method#===" do
- it_behaves_like :method_call, :===
+ it "is an alias of Method#call" do
+ Method.instance_method(:===).should == Method.instance_method(:call)
+ end
end
diff --git a/spec/ruby/core/method/curry_spec.rb b/spec/ruby/core/method/curry_spec.rb
index 219de0f6b5..79c5d7c662 100644
--- a/spec/ruby/core/method/curry_spec.rb
+++ b/spec/ruby/core/method/curry_spec.rb
@@ -7,7 +7,7 @@ describe "Method#curry" do
def x.foo(a,b,c); [a,b,c]; end
c = x.method(:foo).curry
- c.should be_kind_of(Proc)
+ c.should.is_a?(Proc)
c.call(1).call(2, 3).should == [1,2,3]
end
@@ -17,20 +17,20 @@ describe "Method#curry" do
end
it "returns a curried proc when given correct arity" do
- @obj.method(:one_req).curry(1).should be_kind_of(Proc)
- @obj.method(:zero_with_splat).curry(100).should be_kind_of(Proc)
- @obj.method(:two_req_with_splat).curry(2).should be_kind_of(Proc)
+ @obj.method(:one_req).curry(1).should.is_a?(Proc)
+ @obj.method(:zero_with_splat).curry(100).should.is_a?(Proc)
+ @obj.method(:two_req_with_splat).curry(2).should.is_a?(Proc)
end
it "raises ArgumentError when the method requires less arguments than the given arity" do
- -> { @obj.method(:zero).curry(1) }.should raise_error(ArgumentError)
- -> { @obj.method(:one_req_one_opt).curry(3) }.should raise_error(ArgumentError)
- -> { @obj.method(:two_req_one_opt_with_block).curry(4) }.should raise_error(ArgumentError)
+ -> { @obj.method(:zero).curry(1) }.should.raise(ArgumentError)
+ -> { @obj.method(:one_req_one_opt).curry(3) }.should.raise(ArgumentError)
+ -> { @obj.method(:two_req_one_opt_with_block).curry(4) }.should.raise(ArgumentError)
end
it "raises ArgumentError when the method requires more arguments than the given arity" do
- -> { @obj.method(:two_req_with_splat).curry(1) }.should raise_error(ArgumentError)
- -> { @obj.method(:one_req).curry(0) }.should raise_error(ArgumentError)
+ -> { @obj.method(:two_req_with_splat).curry(1) }.should.raise(ArgumentError)
+ -> { @obj.method(:one_req).curry(0) }.should.raise(ArgumentError)
end
end
end
diff --git a/spec/ruby/core/method/element_reference_spec.rb b/spec/ruby/core/method/element_reference_spec.rb
index aa6c54d1cb..65c13cf32b 100644
--- a/spec/ruby/core/method/element_reference_spec.rb
+++ b/spec/ruby/core/method/element_reference_spec.rb
@@ -1,7 +1,7 @@
require_relative '../../spec_helper'
-require_relative 'fixtures/classes'
-require_relative 'shared/call'
describe "Method#[]" do
- it_behaves_like :method_call, :[]
+ it "is an alias of Method#call" do
+ Method.instance_method(:[]).should == Method.instance_method(:call)
+ end
end
diff --git a/spec/ruby/core/method/eql_spec.rb b/spec/ruby/core/method/eql_spec.rb
index b97c9e4db0..81fd086bd5 100644
--- a/spec/ruby/core/method/eql_spec.rb
+++ b/spec/ruby/core/method/eql_spec.rb
@@ -1,6 +1,7 @@
require_relative '../../spec_helper'
-require_relative 'shared/eql'
describe "Method#eql?" do
- it_behaves_like :method_equal, :eql?
+ it "is an alias of Method#==" do
+ Method.instance_method(:eql?).should == Method.instance_method(:==)
+ end
end
diff --git a/spec/ruby/core/method/equal_value_spec.rb b/spec/ruby/core/method/equal_value_spec.rb
index 0431d0c5f6..ca9ef9f108 100644
--- a/spec/ruby/core/method/equal_value_spec.rb
+++ b/spec/ruby/core/method/equal_value_spec.rb
@@ -1,6 +1,94 @@
require_relative '../../spec_helper'
-require_relative 'shared/eql'
+require_relative 'fixtures/classes'
describe "Method#==" do
- it_behaves_like :method_equal, :==
+ before :each do
+ @m = MethodSpecs::Methods.new
+ @m_foo = @m.method(:foo)
+ @m2 = MethodSpecs::Methods.new
+ @a = MethodSpecs::A.new
+ end
+
+ it "returns true if methods are the same" do
+ m2 = @m.method(:foo)
+
+ (@m_foo == @m_foo).should == true
+ (@m_foo == m2).should == true
+ end
+
+ it "returns true on aliased methods" do
+ m_bar = @m.method(:bar)
+
+ (m_bar == @m_foo).should == true
+ end
+
+ it "returns true if the two core methods are aliases" do
+ s = "hello"
+ a = s.method(:size)
+ b = s.method(:length)
+ (a == b).should == true
+ end
+
+ it "returns false on a method which is neither aliased nor the same method" do
+ m2 = @m.method(:zero)
+
+ (@m_foo == m2).should == false
+ end
+
+ it "returns false for a method which is not bound to the same object" do
+ m2_foo = @m2.method(:foo)
+ a_baz = @a.method(:baz)
+
+ (@m_foo == m2_foo).should == false
+ (@m_foo == a_baz).should == false
+ end
+
+ it "returns false if the two methods are bound to the same object but were defined independently" do
+ m2 = @m.method(:same_as_foo)
+ (@m_foo == m2).should == false
+ end
+
+ it "returns true if a method was defined using the other one" do
+ MethodSpecs::Methods.send :define_method, :defined_foo, MethodSpecs::Methods.instance_method(:foo)
+ m2 = @m.method(:defined_foo)
+ (@m_foo == m2).should == true
+ end
+
+ it "returns false if comparing a method defined via define_method and def" do
+ defn = @m.method(:zero)
+ defined = @m.method(:zero_defined_method)
+
+ (defn == defined).should == false
+ (defined == defn).should == false
+ end
+
+ describe 'missing methods' do
+ it "returns true for the same method missing" do
+ miss1 = @m.method(:handled_via_method_missing)
+ miss1bis = @m.method(:handled_via_method_missing)
+ miss2 = @m.method(:also_handled)
+
+ (miss1 == miss1bis).should == true
+ (miss1 == miss2).should == false
+ end
+
+ it 'calls respond_to_missing? with true to include private methods' do
+ @m.should_receive(:respond_to_missing?).with(:some_missing_method, true).and_return(true)
+ @m.method(:some_missing_method)
+ end
+ end
+
+ it "returns false if the two methods are bound to different objects, have the same names, and identical bodies" do
+ a = MethodSpecs::Eql.instance_method(:same_body)
+ b = MethodSpecs::Eql2.instance_method(:same_body)
+ (a == b).should == false
+ end
+
+ it "returns false if the argument is not a Method object" do
+ (String.instance_method(:size) == 7).should == false
+ end
+
+ it "returns false if the argument is an unbound version of self" do
+ (method(:load) == method(:load).unbind).should == false
+ end
end
diff --git a/spec/ruby/core/method/fixtures/classes.rb b/spec/ruby/core/method/fixtures/classes.rb
index 464a519aea..41904df1d1 100644
--- a/spec/ruby/core/method/fixtures/classes.rb
+++ b/spec/ruby/core/method/fixtures/classes.rb
@@ -27,6 +27,7 @@ module MethodSpecs
alias bar foo
alias baz bar
+ alias qux baz
def same_as_foo
true
diff --git a/spec/ruby/core/method/inspect_spec.rb b/spec/ruby/core/method/inspect_spec.rb
index e0fe1afdd0..5eb8850ff3 100644
--- a/spec/ruby/core/method/inspect_spec.rb
+++ b/spec/ruby/core/method/inspect_spec.rb
@@ -1,6 +1,7 @@
require_relative '../../spec_helper'
-require_relative 'shared/to_s'
describe "Method#inspect" do
- it_behaves_like :method_to_s, :inspect
+ it "is an alias of Method#to_s" do
+ Method.instance_method(:inspect).should == Method.instance_method(:to_s)
+ end
end
diff --git a/spec/ruby/core/method/original_name_spec.rb b/spec/ruby/core/method/original_name_spec.rb
index 676fdaedb4..b92cf35154 100644
--- a/spec/ruby/core/method/original_name_spec.rb
+++ b/spec/ruby/core/method/original_name_spec.rb
@@ -19,4 +19,41 @@ describe "Method#original_name" do
obj.method(:baz).original_name.should == :foo
obj.method(:baz).unbind.bind(obj).original_name.should == :foo
end
+
+ it "returns the original name even when aliased thrice" do
+ obj = MethodSpecs::Methods.new
+ obj.method(:qux).original_name.should == :foo
+ obj.method(:qux).unbind.bind(obj).original_name.should == :foo
+ end
+
+ it "returns the source UnboundMethod's name (not the name given to define_method)" do
+ klass = Class.new { define_method(:my_inspect, ::Kernel.instance_method(:inspect)) }
+ klass.new.method(:my_inspect).original_name.should == :inspect
+ end
+
+ it "preserves the source method's name through define_method and alias" do
+ source = Class.new { def my_method; end }
+ klass = Class.new(source) do
+ define_method(:renamed, source.instance_method(:my_method))
+ alias aliased renamed
+ end
+ klass.new.method(:renamed).original_name.should == :my_method
+ klass.new.method(:aliased).original_name.should == :my_method
+ end
+
+ it "returns the source UnboundMethod's name for Kernel#is_a? and Kernel#kind_of?" do
+ klass = Class.new { define_method(:my_is_a?, ::Kernel.instance_method(:is_a?)) }
+ klass.new.method(:my_is_a?).original_name.should == :is_a?
+
+ klass = Class.new { define_method(:my_kind_of?, ::Kernel.instance_method(:kind_of?)) }
+ klass.new.method(:my_kind_of?).original_name.should == :kind_of?
+ end
+
+ it "preserves the source name when aliasing a define_method'd Kernel method" do
+ klass = Class.new do
+ define_method(:my_is_a?, ::Kernel.instance_method(:is_a?))
+ alias_method :renamed_is_a?, :my_is_a?
+ end
+ klass.new.method(:renamed_is_a?).original_name.should == :is_a?
+ end
end
diff --git a/spec/ruby/core/method/parameters_spec.rb b/spec/ruby/core/method/parameters_spec.rb
index f1c2523cf0..fd88e8dcb8 100644
--- a/spec/ruby/core/method/parameters_spec.rb
+++ b/spec/ruby/core/method/parameters_spec.rb
@@ -22,6 +22,12 @@ describe "Method#parameters" do
local_is_not_parameter = {}
end
+ ruby_version_is "4.1" do
+ eval <<-RUBY
+ def one_noblock(&nil); end
+ RUBY
+ end
+
def forward_parameters(...) end
def underscore_parameters(_, _, _ = 1, *_, _:, _: 2, **_, &_); end
@@ -187,6 +193,13 @@ describe "Method#parameters" do
m.parameters.should == [[:nokey]]
end
+ ruby_version_is "4.1" do
+ it "returns [[:noblock]] for a method with a single &nil parameter" do
+ m = MethodSpecs::Methods.instance_method(:one_noblock)
+ m.parameters.should == [[:noblock]]
+ end
+ 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]]
@@ -295,7 +308,7 @@ describe "Method#parameters" do
[
[[:rest]],
[[:opt]]
- ].should include([].method(:pop).parameters)
+ ].should.include?([].method(:pop).parameters)
end
it "returns [[:req]] for each parameter for core methods with fixed-length argument lists" do
diff --git a/spec/ruby/core/method/receiver_spec.rb b/spec/ruby/core/method/receiver_spec.rb
index 2b2e11dd2e..315a08d288 100644
--- a/spec/ruby/core/method/receiver_spec.rb
+++ b/spec/ruby/core/method/receiver_spec.rb
@@ -4,19 +4,19 @@ require_relative 'fixtures/classes'
describe "Method#receiver" do
it "returns the receiver of the method" do
s = "abc"
- s.method(:upcase).receiver.should equal(s)
+ s.method(:upcase).receiver.should.equal?(s)
end
it "returns the right receiver even when aliased" do
obj = MethodSpecs::Methods.new
- obj.method(:foo).receiver.should equal(obj)
- obj.method(:bar).receiver.should equal(obj)
+ obj.method(:foo).receiver.should.equal?(obj)
+ obj.method(:bar).receiver.should.equal?(obj)
end
describe "for a Method generated by respond_to_missing?" do
it "returns the receiver of the method" do
m = MethodSpecs::Methods.new
- m.method(:handled_via_method_missing).receiver.should equal(m)
+ m.method(:handled_via_method_missing).receiver.should.equal?(m)
end
end
end
diff --git a/spec/ruby/core/method/shared/aliased_inspect.rb b/spec/ruby/core/method/shared/aliased_inspect.rb
new file mode 100644
index 0000000000..2a622c2f97
--- /dev/null
+++ b/spec/ruby/core/method/shared/aliased_inspect.rb
@@ -0,0 +1,31 @@
+describe :method_to_s_aliased, shared: true do
+ # @object converts a bound Method to either a Method (identity) or an
+ # UnboundMethod (-> meth { meth.unbind }), so these expectations cover both
+ # Method#to_s/#inspect and UnboundMethod#to_s/#inspect.
+
+ it "shows the original name in parentheses for an aliased method" do
+ klass = Class.new do
+ def original_method; end
+ alias_method :renamed_method, :original_method
+ end
+ @object.call(klass.new.method(:renamed_method)).send(@method).should.include? '#renamed_method(original_method)'
+ end
+
+ it "shows the source UnboundMethod's name in parentheses for a define_method'd method" do
+ klass = Class.new { define_method(:renamed_is_a?, ::Kernel.instance_method(:is_a?)) }
+ @object.call(klass.new.method(:renamed_is_a?)).send(@method).should.include? '#renamed_is_a?(is_a?)'
+ end
+
+ it "does not annotate a directly looked-up Kernel method with a shared internal name" do
+ @object.call(Object.new.method(:is_a?)).send(@method).should_not.include? '(kind_of?)'
+ @object.call(Object.new.method(:kind_of?)).send(@method).should_not.include? '(is_a?)'
+ end
+
+ it "shows the source name when aliasing a define_method'd Kernel method" do
+ klass = Class.new do
+ define_method(:my_is_a?, ::Kernel.instance_method(:is_a?))
+ alias_method :renamed_is_a?, :my_is_a?
+ end
+ @object.call(klass.new.method(:renamed_is_a?)).send(@method).should.include? '#renamed_is_a?(is_a?)'
+ end
+end
diff --git a/spec/ruby/core/method/shared/call.rb b/spec/ruby/core/method/shared/call.rb
deleted file mode 100644
index f26e373695..0000000000
--- a/spec/ruby/core/method/shared/call.rb
+++ /dev/null
@@ -1,51 +0,0 @@
-describe :method_call, shared: true do
- it "invokes the method with the specified arguments, returning the method's return value" do
- m = 12.method("+")
- m.send(@method, 3).should == 15
- m.send(@method, 20).should == 32
-
- m = MethodSpecs::Methods.new.method(:attr=)
- m.send(@method, 42).should == 42
- end
-
- it "raises an ArgumentError when given incorrect number of arguments" do
- -> {
- MethodSpecs::Methods.new.method(:two_req).send(@method, 1, 2, 3)
- }.should raise_error(ArgumentError)
- -> {
- MethodSpecs::Methods.new.method(:two_req).send(@method, 1)
- }.should raise_error(ArgumentError)
- end
-
- describe "for a Method generated by respond_to_missing?" do
- it "invokes method_missing with the specified arguments and returns the result" do
- @m = MethodSpecs::Methods.new
- meth = @m.method(:handled_via_method_missing)
- meth.send(@method, :argument).should == [:argument]
- end
-
- it "invokes method_missing with the method name and the specified arguments" do
- @m = MethodSpecs::Methods.new
- meth = @m.method(:handled_via_method_missing)
-
- @m.should_receive(:method_missing).with(:handled_via_method_missing, :argument)
- meth.send(@method, :argument)
- end
-
- it "invokes method_missing dynamically" do
- @m = MethodSpecs::Methods.new
- meth = @m.method(:handled_via_method_missing)
-
- def @m.method_missing(*); :changed; end
- meth.send(@method, :argument).should == :changed
- end
-
- it "does not call the original method name even if it now exists" do
- @m = MethodSpecs::Methods.new
- meth = @m.method(:handled_via_method_missing)
-
- def @m.handled_via_method_missing(*); :not_called; end
- meth.send(@method, :argument).should == [:argument]
- end
- end
-end
diff --git a/spec/ruby/core/method/shared/dup.rb b/spec/ruby/core/method/shared/dup.rb
index c74847083f..eee790890a 100644
--- a/spec/ruby/core/method/shared/dup.rb
+++ b/spec/ruby/core/method/shared/dup.rb
@@ -4,7 +4,7 @@ describe :method_dup, shared: true do
b = a.send(@method)
a.should == b
- a.should_not equal(b)
+ a.should_not.equal?(b)
end
ruby_version_is "3.4" do
diff --git a/spec/ruby/core/method/shared/eql.rb b/spec/ruby/core/method/shared/eql.rb
deleted file mode 100644
index 5c720cbac1..0000000000
--- a/spec/ruby/core/method/shared/eql.rb
+++ /dev/null
@@ -1,94 +0,0 @@
-require_relative '../../../spec_helper'
-require_relative '../fixtures/classes'
-
-describe :method_equal, shared: true do
- before :each do
- @m = MethodSpecs::Methods.new
- @m_foo = @m.method(:foo)
- @m2 = MethodSpecs::Methods.new
- @a = MethodSpecs::A.new
- end
-
- it "returns true if methods are the same" do
- m2 = @m.method(:foo)
-
- @m_foo.send(@method, @m_foo).should be_true
- @m_foo.send(@method, m2).should be_true
- end
-
- it "returns true on aliased methods" do
- m_bar = @m.method(:bar)
-
- m_bar.send(@method, @m_foo).should be_true
- end
-
- it "returns true if the two core methods are aliases" do
- s = "hello"
- a = s.method(:size)
- b = s.method(:length)
- a.send(@method, b).should be_true
- end
-
- it "returns false on a method which is neither aliased nor the same method" do
- m2 = @m.method(:zero)
-
- @m_foo.send(@method, m2).should be_false
- end
-
- it "returns false for a method which is not bound to the same object" do
- m2_foo = @m2.method(:foo)
- a_baz = @a.method(:baz)
-
- @m_foo.send(@method, m2_foo).should be_false
- @m_foo.send(@method, a_baz).should be_false
- end
-
- it "returns false if the two methods are bound to the same object but were defined independently" do
- m2 = @m.method(:same_as_foo)
- @m_foo.send(@method, m2).should be_false
- end
-
- it "returns true if a method was defined using the other one" do
- MethodSpecs::Methods.send :define_method, :defined_foo, MethodSpecs::Methods.instance_method(:foo)
- m2 = @m.method(:defined_foo)
- @m_foo.send(@method, m2).should be_true
- end
-
- it "returns false if comparing a method defined via define_method and def" do
- defn = @m.method(:zero)
- defined = @m.method(:zero_defined_method)
-
- defn.send(@method, defined).should be_false
- defined.send(@method, defn).should be_false
- end
-
- describe 'missing methods' do
- it "returns true for the same method missing" do
- miss1 = @m.method(:handled_via_method_missing)
- miss1bis = @m.method(:handled_via_method_missing)
- miss2 = @m.method(:also_handled)
-
- miss1.send(@method, miss1bis).should be_true
- miss1.send(@method, miss2).should be_false
- end
-
- it 'calls respond_to_missing? with true to include private methods' do
- @m.should_receive(:respond_to_missing?).with(:some_missing_method, true).and_return(true)
- @m.method(:some_missing_method)
- end
- end
-
- it "returns false if the two methods are bound to different objects, have the same names, and identical bodies" do
- a = MethodSpecs::Eql.instance_method(:same_body)
- b = MethodSpecs::Eql2.instance_method(:same_body)
- a.send(@method, b).should be_false
- end
-
- it "returns false if the argument is not a Method object" do
- String.instance_method(:size).send(@method, 7).should be_false
- end
-
- it "returns false if the argument is an unbound version of self" do
- method(:load).send(@method, method(:load).unbind).should be_false
- end
-end
diff --git a/spec/ruby/core/method/shared/to_s.rb b/spec/ruby/core/method/shared/to_s.rb
index b2d27d370f..bfb58e6896 100644
--- a/spec/ruby/core/method/shared/to_s.rb
+++ b/spec/ruby/core/method/shared/to_s.rb
@@ -8,12 +8,12 @@ describe :method_to_s, shared: true do
end
it "returns a String" do
- @m.send(@method).should be_kind_of(String)
+ @m.send(@method).should.is_a?(String)
end
it "returns a String for methods defined with attr_accessor" do
m = MethodSpecs::Methods.new.method :attr
- m.send(@method).should be_kind_of(String)
+ m.send(@method).should.is_a?(String)
end
it "returns a String containing 'Method'" do
diff --git a/spec/ruby/core/method/source_location_spec.rb b/spec/ruby/core/method/source_location_spec.rb
index 23d956ebec..22fcb98c74 100644
--- a/spec/ruby/core/method/source_location_spec.rb
+++ b/spec/ruby/core/method/source_location_spec.rb
@@ -7,27 +7,27 @@ describe "Method#source_location" do
end
it "returns an Array" do
- @method.source_location.should be_an_instance_of(Array)
+ @method.source_location.should.instance_of?(Array)
end
it "sets the first value to the path of the file in which the method was defined" do
- file = @method.source_location[0]
- file.should be_an_instance_of(String)
+ file = @method.source_location.first
+ file.should.instance_of?(String)
file.should == File.realpath('fixtures/classes.rb', __dir__)
end
it "sets the last value to an Integer representing the line on which the method was defined" do
- line = @method.source_location[1]
- line.should be_an_instance_of(Integer)
+ line = @method.source_location.last
+ line.should.instance_of?(Integer)
line.should == 5
end
it "returns the last place the method was defined" do
- MethodSpecs::SourceLocation.method(:redefined).source_location[1].should == 13
+ MethodSpecs::SourceLocation.method(:redefined).source_location.last.should == 13
end
it "returns the location of the original method even if it was aliased" do
- MethodSpecs::SourceLocation.new.method(:aka).source_location[1].should == 17
+ MethodSpecs::SourceLocation.new.method(:aka).source_location.last.should == 17
end
it "works for methods defined with a block" do
@@ -92,7 +92,7 @@ describe "Method#source_location" do
loc.should == nil
else
loc[0].should.start_with?('<internal:')
- loc[1].should be_kind_of(Integer)
+ loc[1].should.is_a?(Integer)
end
loc = method(:tap).source_location
@@ -100,7 +100,7 @@ describe "Method#source_location" do
loc.should == nil
else
loc[0].should.start_with?('<internal:')
- loc[1].should be_kind_of(Integer)
+ loc[1].should.is_a?(Integer)
end
end
@@ -108,19 +108,13 @@ describe "Method#source_location" do
c = Class.new do
eval('def self.m; end', nil, "foo", 100)
end
- location = c.method(:m).source_location
- ruby_version_is(""..."3.5") do
- location.should == ["foo", 100]
- end
- ruby_version_is("3.5") do
- location.should == ["foo", 100, 0, 100, 15]
- 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
- m.method(:handled_via_method_missing).source_location.should be_nil
+ m.method(:handled_via_method_missing).source_location.should == nil
end
end
end
diff --git a/spec/ruby/core/method/to_s_spec.rb b/spec/ruby/core/method/to_s_spec.rb
index 9f19011302..ba0b4fa3c6 100644
--- a/spec/ruby/core/method/to_s_spec.rb
+++ b/spec/ruby/core/method/to_s_spec.rb
@@ -1,6 +1,8 @@
require_relative '../../spec_helper'
require_relative 'shared/to_s'
+require_relative 'shared/aliased_inspect'
describe "Method#to_s" do
it_behaves_like :method_to_s, :to_s
+ it_behaves_like :method_to_s_aliased, :to_s, -> meth { meth }
end
diff --git a/spec/ruby/core/method/unbind_spec.rb b/spec/ruby/core/method/unbind_spec.rb
index 0b630e4d88..994c3a8879 100644
--- a/spec/ruby/core/method/unbind_spec.rb
+++ b/spec/ruby/core/method/unbind_spec.rb
@@ -11,7 +11,7 @@ describe "Method#unbind" do
end
it "returns an UnboundMethod" do
- @normal_um.should be_kind_of(UnboundMethod)
+ @normal_um.should.is_a?(UnboundMethod)
end
describe "#inspect" do
diff --git a/spec/ruby/core/module/alias_method_spec.rb b/spec/ruby/core/module/alias_method_spec.rb
index c36dedd2d8..852879cc8a 100644
--- a/spec/ruby/core/module/alias_method_spec.rb
+++ b/spec/ruby/core/module/alias_method_spec.rb
@@ -28,12 +28,12 @@ describe "Module#alias_method" do
it "retains method visibility" do
@class.make_alias :private_ichi, :private_one
- -> { @object.private_one }.should raise_error(NameError)
- -> { @object.private_ichi }.should raise_error(NameError)
+ -> { @object.private_one }.should.raise(NameError)
+ -> { @object.private_ichi }.should.raise(NameError)
@class.make_alias :public_ichi, :public_one
@object.public_ichi.should == @object.public_one
@class.make_alias :protected_ichi, :protected_one
- -> { @object.protected_ichi }.should raise_error(NameError)
+ -> { @object.protected_ichi }.should.raise(NameError)
end
it "handles aliasing a stub that changes visibility" do
@@ -55,7 +55,7 @@ describe "Module#alias_method" do
end
it "fails if origin method not found" do
- -> { @class.make_alias :ni, :san }.should raise_error(NameError) { |e|
+ -> { @class.make_alias :ni, :san }.should.raise(NameError) { |e|
# a NameError and not a NoMethodError
e.class.should == NameError
}
@@ -63,7 +63,7 @@ describe "Module#alias_method" do
it "raises FrozenError if frozen" do
@class.freeze
- -> { @class.make_alias :uno, :public_one }.should raise_error(FrozenError)
+ -> { @class.make_alias :uno, :public_one }.should.raise(FrozenError)
end
it "converts the names using #to_str" do
@@ -78,23 +78,23 @@ describe "Module#alias_method" do
end
it "raises a TypeError when the given name can't be converted using to_str" do
- -> { @class.make_alias mock('x'), :public_one }.should raise_error(TypeError)
+ -> { @class.make_alias mock('x'), :public_one }.should.raise(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)
+ -> { @class.make_alias obj, :public_one }.should.raise(NoMethodError)
end
it "is a public method" do
- Module.should have_public_instance_method(:alias_method, false)
+ Module.public_instance_methods(false).should.include?(:alias_method)
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)
+ @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
@@ -104,14 +104,14 @@ describe "Module#alias_method" do
it "works on private module methods in a module that has been reopened" do
ModuleSpecs::ReopeningModule.foo.should == true
- -> { ModuleSpecs::ReopeningModule.foo2 }.should_not raise_error(NoMethodError)
+ -> { ModuleSpecs::ReopeningModule.foo2 }.should_not.raise(NoMethodError)
end
it "accesses a method defined on Object from Kernel" do
- Kernel.should_not have_public_instance_method(:module_specs_public_method_on_object)
+ Kernel.public_instance_methods(true).should_not.include?(:module_specs_public_method_on_object)
- Kernel.should have_public_instance_method(:module_specs_alias_on_kernel)
- Object.should have_public_instance_method(:module_specs_alias_on_kernel)
+ Kernel.public_instance_methods(false).should.include?(:module_specs_alias_on_kernel)
+ Object.public_instance_methods(true).should.include?(:module_specs_alias_on_kernel)
end
it "can call a method with super aliased twice" do
@@ -130,42 +130,42 @@ describe "Module#alias_method" do
it "keeps initialize private when aliasing" do
@class.make_alias(:initialize, :public_one)
- @class.private_instance_methods.include?(:initialize).should be_true
+ @class.private_instance_methods.include?(:initialize).should == true
@subclass.make_alias(:initialize, :public_one)
- @subclass.private_instance_methods.include?(:initialize).should be_true
+ @subclass.private_instance_methods.include?(:initialize).should == true
end
it "keeps initialize_copy private when aliasing" do
@class.make_alias(:initialize_copy, :public_one)
- @class.private_instance_methods.include?(:initialize_copy).should be_true
+ @class.private_instance_methods.include?(:initialize_copy).should == true
@subclass.make_alias(:initialize_copy, :public_one)
- @subclass.private_instance_methods.include?(:initialize_copy).should be_true
+ @subclass.private_instance_methods.include?(:initialize_copy).should == true
end
it "keeps initialize_clone private when aliasing" do
@class.make_alias(:initialize_clone, :public_one)
- @class.private_instance_methods.include?(:initialize_clone).should be_true
+ @class.private_instance_methods.include?(:initialize_clone).should == true
@subclass.make_alias(:initialize_clone, :public_one)
- @subclass.private_instance_methods.include?(:initialize_clone).should be_true
+ @subclass.private_instance_methods.include?(:initialize_clone).should == true
end
it "keeps initialize_dup private when aliasing" do
@class.make_alias(:initialize_dup, :public_one)
- @class.private_instance_methods.include?(:initialize_dup).should be_true
+ @class.private_instance_methods.include?(:initialize_dup).should == true
@subclass.make_alias(:initialize_dup, :public_one)
- @subclass.private_instance_methods.include?(:initialize_dup).should be_true
+ @subclass.private_instance_methods.include?(:initialize_dup).should == true
end
it "keeps respond_to_missing? private when aliasing" do
@class.make_alias(:respond_to_missing?, :public_one)
- @class.private_instance_methods.include?(:respond_to_missing?).should be_true
+ @class.private_instance_methods.include?(:respond_to_missing?).should == true
@subclass.make_alias(:respond_to_missing?, :public_one)
- @subclass.private_instance_methods.include?(:respond_to_missing?).should be_true
+ @subclass.private_instance_methods.include?(:respond_to_missing?).should == true
end
end
end
diff --git a/spec/ruby/core/module/ancestors_spec.rb b/spec/ruby/core/module/ancestors_spec.rb
index 34679575b5..f85884a4f3 100644
--- a/spec/ruby/core/module/ancestors_spec.rb
+++ b/spec/ruby/core/module/ancestors_spec.rb
@@ -7,11 +7,11 @@ describe "Module#ancestors" do
ModuleSpecs.ancestors.should == [ModuleSpecs]
ModuleSpecs::Basic.ancestors.should == [ModuleSpecs::Basic]
ModuleSpecs::Super.ancestors.should == [ModuleSpecs::Super, ModuleSpecs::Basic]
- if defined?(Namespace) && Namespace.enabled?
+ if defined?(Ruby::Box) && Ruby::Box.enabled?
ModuleSpecs.without_test_modules(ModuleSpecs::Parent.ancestors).should ==
- [ModuleSpecs::Parent, Object, Namespace::Loader, Kernel, BasicObject]
+ [ModuleSpecs::Parent, Object, Ruby::Box::Loader, Kernel, BasicObject]
ModuleSpecs.without_test_modules(ModuleSpecs::Child.ancestors).should ==
- [ModuleSpecs::Child, ModuleSpecs::Super, ModuleSpecs::Basic, ModuleSpecs::Parent, Object, Namespace::Loader, Kernel, BasicObject]
+ [ModuleSpecs::Child, ModuleSpecs::Super, ModuleSpecs::Basic, ModuleSpecs::Parent, Object, Ruby::Box::Loader, Kernel, BasicObject]
else
ModuleSpecs.without_test_modules(ModuleSpecs::Parent.ancestors).should ==
[ModuleSpecs::Parent, Object, Kernel, BasicObject]
@@ -21,7 +21,7 @@ describe "Module#ancestors" do
end
it "returns only modules and classes" do
- class << ModuleSpecs::Child; self; end.ancestors.should include(ModuleSpecs::Internal, Class, Module, Object, Kernel)
+ class << ModuleSpecs::Child; self; end.ancestors.to_set.should >= Set[ModuleSpecs::Internal, Class, Module, Object, Kernel]
end
it "has 1 entry per module or class" do
@@ -45,7 +45,7 @@ describe "Module#ancestors" do
child = Class.new(parent)
schild = child.singleton_class
- schild.ancestors.should include(schild,
+ schild.ancestors.to_set.should >= Set[schild,
parent.singleton_class,
Object.singleton_class,
BasicObject.singleton_class,
@@ -53,14 +53,14 @@ describe "Module#ancestors" do
Module,
Object,
Kernel,
- BasicObject)
+ BasicObject]
end
describe 'for a standalone module' do
it 'does not include Class' do
s_mod = ModuleSpecs.singleton_class
- s_mod.ancestors.should_not include(Class)
+ s_mod.ancestors.should_not.include?(Class)
end
it 'does not include other singleton classes' do
@@ -69,19 +69,19 @@ describe "Module#ancestors" do
s_object = Object.singleton_class
s_basic_object = BasicObject.singleton_class
- s_standalone_mod.ancestors.should_not include(s_module, s_object, s_basic_object)
+ (s_standalone_mod.ancestors & [s_module, s_object, s_basic_object]).should.empty?
end
it 'includes its own singleton class' do
s_mod = ModuleSpecs.singleton_class
- s_mod.ancestors.should include(s_mod)
+ s_mod.ancestors.should.include?(s_mod)
end
it 'includes standard chain' do
s_mod = ModuleSpecs.singleton_class
- s_mod.ancestors.should include(Module, Object, Kernel, BasicObject)
+ s_mod.ancestors.to_set.should >= Set[Module, Object, Kernel, BasicObject]
end
end
end
diff --git a/spec/ruby/core/module/append_features_spec.rb b/spec/ruby/core/module/append_features_spec.rb
index 1724cde5d6..4d2207330d 100644
--- a/spec/ruby/core/module/append_features_spec.rb
+++ b/spec/ruby/core/module/append_features_spec.rb
@@ -3,18 +3,18 @@ require_relative 'fixtures/classes'
describe "Module#append_features" do
it "is a private method" do
- Module.should have_private_instance_method(:append_features)
+ Module.private_instance_methods(false).should.include?(:append_features)
end
describe "on Class" do
it "is undefined" do
- Class.should_not have_private_instance_method(:append_features, true)
+ Class.private_instance_methods(true).should_not.include?(:append_features)
end
it "raises a TypeError if calling after rebinded to Class" do
-> {
Module.instance_method(:append_features).bind(Class.new).call Module.new
- }.should raise_error(TypeError)
+ }.should.raise(TypeError)
end
end
@@ -39,11 +39,11 @@ describe "Module#append_features" do
it "raises an ArgumentError on a cyclic include" do
-> {
ModuleSpecs::CyclicAppendA.send(:append_features, ModuleSpecs::CyclicAppendA)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
-> {
ModuleSpecs::CyclicAppendB.send(:append_features, ModuleSpecs::CyclicAppendA)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
@@ -54,8 +54,8 @@ describe "Module#append_features" do
end
it "raises a FrozenError before appending self" do
- -> { @receiver.send(:append_features, @other) }.should raise_error(FrozenError)
- @other.ancestors.should_not include(@receiver)
+ -> { @receiver.send(:append_features, @other) }.should.raise(FrozenError)
+ @other.ancestors.should_not.include?(@receiver)
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..a608760cf2 100644
--- a/spec/ruby/core/module/attr_accessor_spec.rb
+++ b/spec/ruby/core/module/attr_accessor_spec.rb
@@ -34,7 +34,7 @@ describe "Module#attr_accessor" do
attr_accessor :spec_attr_accessor
end
- -> { true.spec_attr_accessor = "a" }.should raise_error(FrozenError)
+ -> { true.spec_attr_accessor = "a" }.should.raise(FrozenError)
end
it "raises FrozenError if the receiver if frozen" do
@@ -46,7 +46,7 @@ describe "Module#attr_accessor" do
obj.foo.should == 1
obj.freeze
- -> { obj.foo = 42 }.should raise_error(FrozenError)
+ -> { obj.foo = 42 }.should.raise(FrozenError)
obj.foo.should == 1
end
@@ -62,9 +62,9 @@ describe "Module#attr_accessor" do
it "raises a TypeError when the given names can't be converted to strings using to_str" do
o = mock('o')
- -> { Class.new { attr_accessor o } }.should raise_error(TypeError)
+ -> { Class.new { attr_accessor o } }.should.raise(TypeError)
(o = mock('123')).should_receive(:to_str).and_return(123)
- -> { Class.new { attr_accessor o } }.should raise_error(TypeError)
+ -> { Class.new { attr_accessor o } }.should.raise(TypeError)
end
it "applies current visibility to methods created" do
@@ -73,12 +73,12 @@ describe "Module#attr_accessor" do
attr_accessor :foo
end
- -> { c.new.foo }.should raise_error(NoMethodError)
- -> { c.new.foo=1 }.should raise_error(NoMethodError)
+ -> { c.new.foo }.should.raise(NoMethodError)
+ -> { c.new.foo=1 }.should.raise(NoMethodError)
end
it "is a public method" do
- Module.should have_public_instance_method(:attr_accessor, false)
+ Module.public_instance_methods(false).should.include?(:attr_accessor)
end
it "returns an array of defined method names as symbols" do
@@ -104,7 +104,7 @@ describe "Module#attr_accessor" do
end
it "can read through the accessor" do
- 1.foobar.should be_nil
+ 1.foobar.should == nil
end
end
diff --git a/spec/ruby/core/module/attr_reader_spec.rb b/spec/ruby/core/module/attr_reader_spec.rb
index 37fd537ff5..2b4ca2100e 100644
--- a/spec/ruby/core/module/attr_reader_spec.rb
+++ b/spec/ruby/core/module/attr_reader_spec.rb
@@ -30,7 +30,7 @@ describe "Module#attr_reader" do
attr_reader :spec_attr_reader
end
- -> { true.instance_variable_set("@spec_attr_reader", "a") }.should raise_error(RuntimeError)
+ -> { true.instance_variable_set("@spec_attr_reader", "a") }.should.raise(RuntimeError)
end
it "converts non string/symbol names to strings using to_str" do
@@ -45,9 +45,9 @@ describe "Module#attr_reader" do
it "raises a TypeError when the given names can't be converted to strings using to_str" do
o = mock('o')
- -> { Class.new { attr_reader o } }.should raise_error(TypeError)
+ -> { Class.new { attr_reader o } }.should.raise(TypeError)
(o = mock('123')).should_receive(:to_str).and_return(123)
- -> { Class.new { attr_reader o } }.should raise_error(TypeError)
+ -> { Class.new { attr_reader o } }.should.raise(TypeError)
end
it "applies current visibility to methods created" do
@@ -56,11 +56,11 @@ describe "Module#attr_reader" do
attr_reader :foo
end
- -> { c.new.foo }.should raise_error(NoMethodError)
+ -> { c.new.foo }.should.raise(NoMethodError)
end
it "is a public method" do
- Module.should have_public_instance_method(:attr_reader, false)
+ Module.public_instance_methods(false).should.include?(:attr_reader)
end
it "returns an array of defined method names as symbols" do
diff --git a/spec/ruby/core/module/attr_spec.rb b/spec/ruby/core/module/attr_spec.rb
index 2f9f4e26dc..d696864955 100644
--- a/spec/ruby/core/module/attr_spec.rb
+++ b/spec/ruby/core/module/attr_spec.rb
@@ -90,8 +90,8 @@ describe "Module#attr" do
attr :foo, true
end
- -> { c.new.foo }.should raise_error(NoMethodError)
- -> { c.new.foo=1 }.should raise_error(NoMethodError)
+ -> { c.new.foo }.should.raise(NoMethodError)
+ -> { c.new.foo=1 }.should.raise(NoMethodError)
end
it "creates a getter but no setter for all given attribute names" do
@@ -121,8 +121,8 @@ describe "Module#attr" do
attr :foo, :bar
end
- -> { c.new.foo }.should raise_error(NoMethodError)
- -> { c.new.bar }.should raise_error(NoMethodError)
+ -> { c.new.foo }.should.raise(NoMethodError)
+ -> { c.new.bar }.should.raise(NoMethodError)
end
it "converts non string/symbol names to strings using to_str" do
@@ -132,9 +132,9 @@ describe "Module#attr" do
it "raises a TypeError when the given names can't be converted to strings using to_str" do
o = mock('o')
- -> { Class.new { attr o } }.should raise_error(TypeError)
+ -> { Class.new { attr o } }.should.raise(TypeError)
(o = mock('123')).should_receive(:to_str).and_return(123)
- -> { Class.new { attr o } }.should raise_error(TypeError)
+ -> { Class.new { attr o } }.should.raise(TypeError)
end
it "with a boolean argument emits a warning when $VERBOSE is true" do
@@ -144,7 +144,7 @@ describe "Module#attr" do
end
it "is a public method" do
- Module.should have_public_instance_method(:attr, false)
+ Module.public_instance_methods(false).should.include?(:attr)
end
it "returns an array of defined method names as symbols" do
diff --git a/spec/ruby/core/module/attr_writer_spec.rb b/spec/ruby/core/module/attr_writer_spec.rb
index 5b863ef88c..6089b52495 100644
--- a/spec/ruby/core/module/attr_writer_spec.rb
+++ b/spec/ruby/core/module/attr_writer_spec.rb
@@ -30,7 +30,7 @@ describe "Module#attr_writer" do
attr_writer :spec_attr_writer
end
- -> { true.spec_attr_writer = "a" }.should raise_error(FrozenError)
+ -> { true.spec_attr_writer = "a" }.should.raise(FrozenError)
end
it "raises FrozenError if the receiver if frozen" do
@@ -40,7 +40,7 @@ describe "Module#attr_writer" do
obj = c.new
obj.freeze
- -> { obj.foo = 42 }.should raise_error(FrozenError)
+ -> { obj.foo = 42 }.should.raise(FrozenError)
end
it "converts non string/symbol names to strings using to_str" do
@@ -55,9 +55,9 @@ describe "Module#attr_writer" do
it "raises a TypeError when the given names can't be converted to strings using to_str" do
o = mock('test1')
- -> { Class.new { attr_writer o } }.should raise_error(TypeError)
+ -> { Class.new { attr_writer o } }.should.raise(TypeError)
(o = mock('123')).should_receive(:to_str).and_return(123)
- -> { Class.new { attr_writer o } }.should raise_error(TypeError)
+ -> { Class.new { attr_writer o } }.should.raise(TypeError)
end
it "applies current visibility to methods created" do
@@ -66,11 +66,11 @@ describe "Module#attr_writer" do
attr_writer :foo
end
- -> { c.new.foo=1 }.should raise_error(NoMethodError)
+ -> { c.new.foo=1 }.should.raise(NoMethodError)
end
it "is a public method" do
- Module.should have_public_instance_method(:attr_writer, false)
+ Module.public_instance_methods(false).should.include?(:attr_writer)
end
it "returns an array of defined method names as symbols" do
diff --git a/spec/ruby/core/module/autoload_relative_spec.rb b/spec/ruby/core/module/autoload_relative_spec.rb
new file mode 100644
index 0000000000..2e7d85496b
--- /dev/null
+++ b/spec/ruby/core/module/autoload_relative_spec.rb
@@ -0,0 +1,128 @@
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
+
+# Specs for Module#autoload_relative
+module ModuleSpecs
+ module AutoloadRelative
+ # Will be used for testing
+ end
+end
+
+ruby_version_is "4.1" do
+ describe "Module#autoload_relative" do
+ before :each do
+ @loaded_features = $".dup
+ end
+
+ after :each do
+ $".replace @loaded_features
+ end
+
+ it "is a public method" do
+ Module.public_instance_methods(false).should.include?(:autoload_relative)
+ end
+
+ it "registers a file to load relative to the current file the first time the named constant is accessed" do
+ ModuleSpecs::Autoload.autoload_relative :AutoloadRelativeA, "fixtures/autoload_relative_a.rb"
+ path = ModuleSpecs::Autoload.autoload?(:AutoloadRelativeA)
+ path.should_not == nil
+ path.should.end_with?("autoload_relative_a.rb")
+ File.exist?(path).should == true
+ end
+
+ it "loads the registered file when the constant is accessed" do
+ ModuleSpecs::Autoload.autoload_relative :AutoloadRelativeB, "fixtures/autoload_relative_a.rb"
+ ModuleSpecs::Autoload::AutoloadRelativeB.should.is_a?(Module)
+ end
+
+ it "returns nil" do
+ ModuleSpecs::Autoload.autoload_relative(:AutoloadRelativeC, "fixtures/autoload_relative_a.rb").should == nil
+ end
+
+ it "registers a file to load the first time the named constant is accessed" do
+ module ModuleSpecs::Autoload::AutoloadRelativeTest
+ autoload_relative :D, "fixtures/autoload_relative_a.rb"
+ end
+ path = ModuleSpecs::Autoload::AutoloadRelativeTest.autoload?(:D)
+ path.should_not == nil
+ path.should.end_with?("autoload_relative_a.rb")
+ end
+
+ it "sets the autoload constant in the constants table" do
+ ModuleSpecs::Autoload.autoload_relative :AutoloadRelativeTableTest, "fixtures/autoload_relative_a.rb"
+ ModuleSpecs::Autoload.should.const_defined?(:AutoloadRelativeTableTest, false)
+ end
+
+ it "calls #to_path on non-String filenames" do
+ name = mock("autoload_relative mock")
+ name.should_receive(:to_path).and_return("fixtures/autoload_relative_a.rb")
+ ModuleSpecs::Autoload.autoload_relative :AutoloadRelativeToPath, name
+ ModuleSpecs::Autoload.autoload?(:AutoloadRelativeToPath).should_not == nil
+ end
+
+ it "calls #to_str on non-String filenames" do
+ name = mock("autoload_relative mock")
+ name.should_receive(:to_str).and_return("fixtures/autoload_relative_a.rb")
+ ModuleSpecs::Autoload.autoload_relative :AutoloadRelativeToStr, name
+ ModuleSpecs::Autoload.autoload?(:AutoloadRelativeToStr).should_not == nil
+ end
+
+ it "raises a TypeError if the filename argument is not a String or pathname" do
+ -> {
+ ModuleSpecs::Autoload.autoload_relative :AutoloadRelativeTypError, nil
+ }.should.raise(TypeError)
+ end
+
+ it "raises a NameError if the constant name is not valid" do
+ -> {
+ ModuleSpecs::Autoload.autoload_relative :invalid_name, "fixtures/autoload_relative_a.rb"
+ }.should.raise(NameError)
+ end
+
+ it "raises an ArgumentError if the constant name starts with a lowercase letter" do
+ -> {
+ ModuleSpecs::Autoload.autoload_relative :autoload, "fixtures/autoload_relative_a.rb"
+ }.should.raise(NameError)
+ end
+
+ it "raises LoadError if called from eval without file context" do
+ -> {
+ ModuleSpecs::Autoload.module_eval('autoload_relative :EvalTest, "fixtures/autoload_relative_a.rb"')
+ }.should.raise(LoadError, /autoload_relative called without file context/)
+ end
+
+ it "can autoload in instance_eval with a file context" do
+ path = nil
+ ModuleSpecs::Autoload.instance_eval(<<-CODE, __FILE__, __LINE__)
+ autoload_relative :InstanceEvalTest, "fixtures/autoload_relative_a.rb"
+ path = autoload?(:InstanceEvalTest)
+ CODE
+ path.should_not == nil
+ path.should.end_with?("autoload_relative_a.rb")
+ end
+
+ it "resolves paths relative to the file where it's called" do
+ # Using fixtures/autoload_relative_a.rb which exists
+ ModuleSpecs::Autoload.autoload_relative :RelativePathTest, "fixtures/autoload_relative_a.rb"
+ path = ModuleSpecs::Autoload.autoload?(:RelativePathTest)
+ path.should.include?("fixtures")
+ path.should.end_with?("autoload_relative_a.rb")
+ end
+
+ it "can load nested directory paths" do
+ ModuleSpecs::Autoload.autoload_relative :NestedPath, "fixtures/autoload_relative_a.rb"
+ path = ModuleSpecs::Autoload.autoload?(:NestedPath)
+ path.should_not == nil
+ File.exist?(path).should == true
+ end
+
+ describe "interoperability with autoload?" do
+ it "returns the absolute path with autoload?" do
+ ModuleSpecs::Autoload.autoload_relative :QueryTest, "fixtures/autoload_relative_a.rb"
+ path = ModuleSpecs::Autoload.autoload?(:QueryTest)
+ # Should be an absolute path
+ Pathname.new(path).absolute?.should == true
+ end
+ end
+end
+end
diff --git a/spec/ruby/core/module/autoload_spec.rb b/spec/ruby/core/module/autoload_spec.rb
index bba911e752..057237a92f 100644
--- a/spec/ruby/core/module/autoload_spec.rb
+++ b/spec/ruby/core/module/autoload_spec.rb
@@ -9,7 +9,7 @@ describe "Module#autoload?" do
end
it "returns nil if no file has been registered for a constant" do
- ModuleSpecs::Autoload.autoload?(:Manualload).should be_nil
+ ModuleSpecs::Autoload.autoload?(:Manualload).should == nil
end
it "returns the name of the file that will be autoloaded if an ancestor defined that autoload" do
@@ -19,7 +19,7 @@ describe "Module#autoload?" do
it "returns nil if an ancestor defined that autoload but recursion is disabled" do
ModuleSpecs::Autoload::Parent.autoload :InheritedAutoload, "inherited_autoload.rb"
- ModuleSpecs::Autoload::Child.autoload?(:InheritedAutoload, false).should be_nil
+ ModuleSpecs::Autoload::Child.autoload?(:InheritedAutoload, false).should == nil
end
it "returns the name of the file that will be loaded if recursion is disabled but the autoload is defined on the class itself" do
@@ -55,7 +55,7 @@ describe "Module#autoload" do
it "sets the autoload constant in the constants table" do
ModuleSpecs::Autoload.autoload :B, @non_existent
- ModuleSpecs::Autoload.should have_constant(:B)
+ ModuleSpecs::Autoload.should.const_defined?(:B, false)
end
it "can be overridden with a second autoload on the same constant" do
@@ -71,7 +71,7 @@ describe "Module#autoload" do
end
it "loads the registered constant when it is accessed" do
- ModuleSpecs::Autoload.should_not have_constant(:X)
+ ModuleSpecs::Autoload.should_not.const_defined?(:X)
ModuleSpecs::Autoload.autoload :X, fixture(__FILE__, "autoload_x.rb")
@remove << :X
ModuleSpecs::Autoload::X.should == :x
@@ -82,7 +82,7 @@ describe "Module#autoload" do
ModuleSpecs::Autoload::DynClass = cls
@remove << :DynClass
- ScratchPad.recorded.should be_nil
+ ScratchPad.recorded.should == nil
ModuleSpecs::Autoload::DynClass::C.new.loaded.should == :dynclass_c
ScratchPad.recorded.should == :loaded
end
@@ -92,7 +92,7 @@ describe "Module#autoload" do
ModuleSpecs::Autoload::DynModule = mod
@remove << :DynModule
- ScratchPad.recorded.should be_nil
+ ScratchPad.recorded.should == nil
ModuleSpecs::Autoload::DynModule::D.new.loaded.should == :dynmodule_d
ScratchPad.recorded.should == :loaded
end
@@ -131,7 +131,7 @@ describe "Module#autoload" do
@remove << :I
ModuleSpecs::Autoload.const_set :I, 3
ModuleSpecs::Autoload::I.should == 3
- ScratchPad.recorded.should be_nil
+ ScratchPad.recorded.should == nil
end
it "loads a file with .rb extension when passed the name without the extension" do
@@ -144,7 +144,7 @@ describe "Module#autoload" do
main = TOPLEVEL_BINDING.eval("self")
main.should_receive(:require).with("module_autoload_not_exist.rb")
# The constant won't be defined since require is mocked to do nothing
- -> { ModuleSpecs::Autoload::ModuleAutoloadCallsRequire }.should raise_error(NameError)
+ -> { ModuleSpecs::Autoload::ModuleAutoloadCallsRequire }.should.raise(NameError)
end
it "does not load the file if the file is manually required" do
@@ -156,9 +156,9 @@ describe "Module#autoload" do
ScratchPad.recorded.should == :loaded
ScratchPad.clear
- ModuleSpecs::Autoload::KHash.should be_kind_of(Class)
+ ModuleSpecs::Autoload::KHash.should.is_a?(Class)
ModuleSpecs::Autoload::KHash::K.should == :autoload_k
- ScratchPad.recorded.should be_nil
+ ScratchPad.recorded.should == nil
end
it "ignores the autoload request if the file is already loaded" do
@@ -171,7 +171,7 @@ describe "Module#autoload" do
ModuleSpecs::Autoload.autoload :S, filename
@remove << :S
- ModuleSpecs::Autoload.autoload?(:S).should be_nil
+ ModuleSpecs::Autoload.autoload?(:S).should == nil
end
it "retains the autoload even if the request to require fails" do
@@ -182,7 +182,7 @@ describe "Module#autoload" do
-> {
require filename
- }.should raise_error(LoadError)
+ }.should.raise(LoadError)
ModuleSpecs::Autoload.autoload?(:NotThere).should == filename
end
@@ -205,7 +205,7 @@ describe "Module#autoload" do
filename = fixture(__FILE__, "autoload_during_require_current_file.rb")
require filename
- ScratchPad.recorded.should be_nil
+ ScratchPad.recorded.should == nil
end
describe "interacting with defined?" do
@@ -215,9 +215,9 @@ describe "Module#autoload" do
end
defined?(ModuleSpecs::Autoload::Dog::R).should == "constant"
- ScratchPad.recorded.should be_nil
+ ScratchPad.recorded.should == nil
- ModuleSpecs::Autoload::Dog.should have_constant(:R)
+ ModuleSpecs::Autoload::Dog.should.const_defined?(:R, false)
end
it "loads an autoloaded parent when referencing a nested constant" do
@@ -235,7 +235,7 @@ describe "Module#autoload" do
autoload :BadParent, fixture(__FILE__, "autoload_exception.rb")
end
- defined?(ModuleSpecs::Autoload::BadParent::Nested).should be_nil
+ defined?(ModuleSpecs::Autoload::BadParent::Nested).should == nil
ScratchPad.recorded.should == :exception
end
end
@@ -454,16 +454,16 @@ describe "Module#autoload" do
ModuleSpecs::Autoload.autoload :Fail, @non_existent
ModuleSpecs::Autoload.const_defined?(:Fail).should == true
- ModuleSpecs::Autoload.should have_constant(:Fail)
+ ModuleSpecs::Autoload.should.const_defined?(:Fail, false)
ModuleSpecs::Autoload.autoload?(:Fail).should == @non_existent
- -> { ModuleSpecs::Autoload::Fail }.should raise_error(LoadError)
+ -> { ModuleSpecs::Autoload::Fail }.should.raise(LoadError)
- ModuleSpecs::Autoload.should have_constant(:Fail)
+ ModuleSpecs::Autoload.should.const_defined?(:Fail, false)
ModuleSpecs::Autoload.const_defined?(:Fail).should == true
ModuleSpecs::Autoload.autoload?(:Fail).should == @non_existent
- -> { ModuleSpecs::Autoload::Fail }.should raise_error(LoadError)
+ -> { ModuleSpecs::Autoload::Fail }.should.raise(LoadError)
end
it "does not remove the constant from Module#constants if load raises a RuntimeError and keeps it as an autoload" do
@@ -472,17 +472,17 @@ describe "Module#autoload" do
ModuleSpecs::Autoload.autoload :Raise, path
ModuleSpecs::Autoload.const_defined?(:Raise).should == true
- ModuleSpecs::Autoload.should have_constant(:Raise)
+ ModuleSpecs::Autoload.should.const_defined?(:Raise, false)
ModuleSpecs::Autoload.autoload?(:Raise).should == path
- -> { ModuleSpecs::Autoload::Raise }.should raise_error(RuntimeError)
+ -> { ModuleSpecs::Autoload::Raise }.should.raise(RuntimeError)
ScratchPad.recorded.should == [:raise]
- ModuleSpecs::Autoload.should have_constant(:Raise)
+ ModuleSpecs::Autoload.should.const_defined?(:Raise, false)
ModuleSpecs::Autoload.const_defined?(:Raise).should == true
ModuleSpecs::Autoload.autoload?(:Raise).should == path
- -> { ModuleSpecs::Autoload::Raise }.should raise_error(RuntimeError)
+ -> { ModuleSpecs::Autoload::Raise }.should.raise(RuntimeError)
ScratchPad.recorded.should == [:raise, :raise]
end
@@ -492,15 +492,15 @@ describe "Module#autoload" do
ModuleSpecs::Autoload.autoload :O, path
ModuleSpecs::Autoload.const_defined?(:O).should == true
- ModuleSpecs::Autoload.should have_constant(:O)
+ ModuleSpecs::Autoload.should.const_defined?(:O, false)
ModuleSpecs::Autoload.autoload?(:O).should == path
- -> { ModuleSpecs::Autoload::O }.should raise_error(NameError)
+ -> { ModuleSpecs::Autoload::O }.should.raise(NameError)
ModuleSpecs::Autoload.const_defined?(:O).should == false
- ModuleSpecs::Autoload.should_not have_constant(:O)
+ ModuleSpecs::Autoload.should_not.const_defined?(:O)
ModuleSpecs::Autoload.autoload?(:O).should == nil
- -> { ModuleSpecs::Autoload.const_get(:O) }.should raise_error(NameError)
+ -> { ModuleSpecs::Autoload.const_get(:O) }.should.raise(NameError)
end
it "does not try to load the file again if the loaded file did not define the constant" do
@@ -508,13 +508,13 @@ describe "Module#autoload" do
ScratchPad.record []
ModuleSpecs::Autoload.autoload :NotDefinedByFile, path
- -> { ModuleSpecs::Autoload::NotDefinedByFile }.should raise_error(NameError)
+ -> { ModuleSpecs::Autoload::NotDefinedByFile }.should.raise(NameError)
ScratchPad.recorded.should == [:loaded]
- -> { ModuleSpecs::Autoload::NotDefinedByFile }.should raise_error(NameError)
+ -> { ModuleSpecs::Autoload::NotDefinedByFile }.should.raise(NameError)
ScratchPad.recorded.should == [:loaded]
Thread.new {
- -> { ModuleSpecs::Autoload::NotDefinedByFile }.should raise_error(NameError)
+ -> { ModuleSpecs::Autoload::NotDefinedByFile }.should.raise(NameError)
}.join
ScratchPad.recorded.should == [:loaded]
end
@@ -524,7 +524,7 @@ describe "Module#autoload" do
autoload :R, fixture(__FILE__, "autoload.rb")
defined?(R).should == 'constant'
end
- ModuleSpecs::Autoload::Q.should have_constant(:R)
+ ModuleSpecs::Autoload::Q.should.const_defined?(:R, false)
end
it "does not load the file when removing an autoload constant" do
@@ -532,13 +532,13 @@ describe "Module#autoload" do
autoload :R, fixture(__FILE__, "autoload.rb")
remove_const :R
end
- ModuleSpecs::Autoload::Q.should_not have_constant(:R)
+ ModuleSpecs::Autoload::Q.should_not.const_defined?(:R)
end
it "does not load the file when accessing the constants table of the module" do
ModuleSpecs::Autoload.autoload :P, @non_existent
- ModuleSpecs::Autoload.const_defined?(:P).should be_true
- ModuleSpecs::Autoload.const_defined?("P").should be_true
+ ModuleSpecs::Autoload.const_defined?(:P).should == true
+ ModuleSpecs::Autoload.const_defined?("P").should == true
end
it "loads the file when opening a module that is the autoloaded constant" do
@@ -573,8 +573,8 @@ describe "Module#autoload" do
DeclaredAndDefinedInParent.should == :declared_and_defined_in_parent
# The constant is really in Autoload, not Autoload::LexicalScope
- self.should_not have_constant(:DeclaredAndDefinedInParent)
- -> { const_get(:DeclaredAndDefinedInParent) }.should raise_error(NameError)
+ self.should_not.const_defined?(:DeclaredAndDefinedInParent)
+ -> { const_get(:DeclaredAndDefinedInParent) }.should.raise(NameError)
end
DeclaredAndDefinedInParent.should == :declared_and_defined_in_parent
end
@@ -597,7 +597,7 @@ describe "Module#autoload" do
# Basically, the parent autoload constant remains in a "undefined" state
self.autoload?(:DeclaredInParentDefinedInCurrent).should == nil
const_defined?(:DeclaredInParentDefinedInCurrent).should == false
- -> { DeclaredInParentDefinedInCurrent }.should raise_error(NameError)
+ -> { DeclaredInParentDefinedInCurrent }.should.raise(NameError)
ModuleSpecs::Autoload::LexicalScope.send(:remove_const, :DeclaredInParentDefinedInCurrent)
end
@@ -640,11 +640,11 @@ describe "Module#autoload" do
class LexicalScope
autoload :DeclaredInCurrentDefinedInParent, fixture(__FILE__, "autoload_callback.rb")
- -> { DeclaredInCurrentDefinedInParent }.should_not raise_error(NameError)
+ -> { DeclaredInCurrentDefinedInParent }.should_not.raise(NameError)
# Basically, the autoload constant remains in a "undefined" state
self.autoload?(:DeclaredInCurrentDefinedInParent).should == nil
const_defined?(:DeclaredInCurrentDefinedInParent).should == false
- -> { const_get(:DeclaredInCurrentDefinedInParent) }.should raise_error(NameError)
+ -> { const_get(:DeclaredInCurrentDefinedInParent) }.should.raise(NameError)
end
DeclaredInCurrentDefinedInParent.should == :declared_in_current_defined_in_parent
@@ -714,10 +714,25 @@ describe "Module#autoload" do
end
end
end
- ModuleSpecs::Autoload.r.should be_kind_of(ModuleSpecs::Autoload::MetaScope)
+ ModuleSpecs::Autoload.r.should.is_a?(ModuleSpecs::Autoload::MetaScope)
end
end
+ it "should trigger the autoload when using `private_constant`" do
+ @remove << :DynClass
+ module ModuleSpecs::Autoload
+ autoload :DynClass, fixture(__FILE__, "autoload_c.rb")
+ private_constant :DynClass
+
+ ScratchPad.recorded.should == nil
+
+ DynClass::C.new.loaded.should == :dynclass_c
+ ScratchPad.recorded.should == :loaded
+ end
+
+ -> { ModuleSpecs::Autoload::DynClass }.should.raise(NameError, /private constant/)
+ end
+
# [ruby-core:19127] [ruby-core:29941]
it "does NOT raise a NameError when the autoload file did not define the constant and a module is opened with the same name" do
module ModuleSpecs::Autoload
@@ -730,7 +745,7 @@ describe "Module#autoload" do
end
@remove << :W
- ModuleSpecs::Autoload::W::Y.should be_kind_of(Class)
+ ModuleSpecs::Autoload::W::Y.should.is_a?(Class)
ScratchPad.recorded.should == :loaded
end
@@ -745,7 +760,7 @@ describe "Module#autoload" do
-> {
Kernel.require fixture(__FILE__, "autoload_during_require.rb")
}.should_not complain(verbose: true)
- ModuleSpecs::Autoload::AutoloadDuringRequire.should be_kind_of(Class)
+ ModuleSpecs::Autoload::AutoloadDuringRequire.should.is_a?(Class)
end
it "does not call #require a second time and does not warn if feature sets and trigger autoload on itself" do
@@ -755,15 +770,15 @@ describe "Module#autoload" do
-> {
Kernel.require fixture(__FILE__, "autoload_self_during_require.rb")
}.should_not complain(verbose: true)
- ModuleSpecs::Autoload::AutoloadSelfDuringRequire.should be_kind_of(Class)
+ ModuleSpecs::Autoload::AutoloadSelfDuringRequire.should.is_a?(Class)
end
it "handles multiple autoloads in the same file" do
$LOAD_PATH.unshift(File.expand_path('../fixtures/multi', __FILE__))
begin
require 'foo/bar_baz'
- ModuleSpecs::Autoload::Foo::Bar.should be_kind_of(Class)
- ModuleSpecs::Autoload::Foo::Baz.should be_kind_of(Class)
+ ModuleSpecs::Autoload::Foo::Bar.should.is_a?(Class)
+ ModuleSpecs::Autoload::Foo::Baz.should.is_a?(Class)
ensure
$LOAD_PATH.shift
end
@@ -776,19 +791,19 @@ describe "Module#autoload" do
end
it "raises an ArgumentError when an empty filename is given" do
- -> { ModuleSpecs.autoload :A, "" }.should raise_error(ArgumentError)
+ -> { ModuleSpecs.autoload :A, "" }.should.raise(ArgumentError)
end
it "raises a NameError when the constant name starts with a lower case letter" do
- -> { ModuleSpecs.autoload "a", @non_existent }.should raise_error(NameError)
+ -> { ModuleSpecs.autoload "a", @non_existent }.should.raise(NameError)
end
it "raises a NameError when the constant name starts with a number" do
- -> { ModuleSpecs.autoload "1two", @non_existent }.should raise_error(NameError)
+ -> { ModuleSpecs.autoload "1two", @non_existent }.should.raise(NameError)
end
it "raises a NameError when the constant name has a space in it" do
- -> { ModuleSpecs.autoload "a name", @non_existent }.should raise_error(NameError)
+ -> { ModuleSpecs.autoload "a name", @non_existent }.should.raise(NameError)
end
it "shares the autoload request across dup'ed copies of modules" do
@@ -805,7 +820,7 @@ describe "Module#autoload" do
mod2.autoload?(:T).should == filename
mod1::T.should == :autoload_t
- -> { mod2::T }.should raise_error(NameError)
+ -> { mod2::T }.should.raise(NameError)
end
it "raises a TypeError if opening a class with a different superclass than the class defined in the autoload file" do
@@ -816,27 +831,27 @@ describe "Module#autoload" do
-> do
class ModuleSpecs::Autoload::Z < ModuleSpecs::Autoload::ZZ
end
- end.should raise_error(TypeError)
+ end.should.raise(TypeError)
end
it "raises a TypeError if not passed a String or object responding to #to_path for the filename" do
name = mock("autoload_name.rb")
- -> { ModuleSpecs::Autoload.autoload :Str, name }.should raise_error(TypeError)
+ -> { ModuleSpecs::Autoload.autoload :Str, name }.should.raise(TypeError)
end
it "calls #to_path on non-String filename arguments" do
name = mock("autoload_name.rb")
name.should_receive(:to_path).and_return("autoload_name.rb")
- -> { ModuleSpecs::Autoload.autoload :Str, name }.should_not raise_error
+ -> { ModuleSpecs::Autoload.autoload :Str, name }.should_not.raise
end
describe "on a frozen module" do
it "raises a FrozenError before setting the name" do
frozen_module = Module.new.freeze
- -> { frozen_module.autoload :Foo, @non_existent }.should raise_error(FrozenError)
- frozen_module.should_not have_constant(:Foo)
+ -> { frozen_module.autoload :Foo, @non_existent }.should.raise(FrozenError)
+ frozen_module.should_not.const_defined?(:Foo)
end
end
@@ -901,7 +916,7 @@ describe "Module#autoload" do
t1_val.should == 1
t2_val.should == t1_val
- t2_exc.should be_nil
+ t2_exc.should == nil
end
# https://bugs.ruby-lang.org/issues/10892
@@ -933,7 +948,7 @@ describe "Module#autoload" do
begin
Object.const_get(mod_name).foo
- rescue NoMethodError
+ rescue NameError, NoMethodError # rubocop:disable Lint/ShadowedException
barrier.disable!
break false
end
@@ -941,8 +956,8 @@ describe "Module#autoload" do
end
end
- # check that no thread got a NoMethodError because of partially loaded module
- threads.all? {|t| t.value}.should be_true
+ # check that no thread got a NameError or NoMethodError because of partially loaded module
+ threads.all? {|t| t.value}.should == true
# check that the autoloaded file was evaled exactly once
ScratchPad.recorded.get.should == mod_count
@@ -950,6 +965,8 @@ describe "Module#autoload" do
mod_names.each do |mod_name|
Object.send(:remove_const, mod_name)
end
+ ensure
+ threads.each(&:join) if threads
end
it "raises a NameError in each thread if the constant is not set" do
@@ -973,7 +990,7 @@ describe "Module#autoload" do
start = true
threads.each { |t|
- t.value.should be_an_instance_of(NameError)
+ t.value.should.instance_of?(NameError)
}
end
@@ -998,7 +1015,7 @@ describe "Module#autoload" do
start = true
threads.each { |t|
- t.value.should be_an_instance_of(LoadError)
+ t.value.should.instance_of?(LoadError)
}
end
end
diff --git a/spec/ruby/core/module/class_eval_spec.rb b/spec/ruby/core/module/class_eval_spec.rb
index c6665d5aff..0c190ceaff 100644
--- a/spec/ruby/core/module/class_eval_spec.rb
+++ b/spec/ruby/core/module/class_eval_spec.rb
@@ -1,7 +1,7 @@
require_relative '../../spec_helper'
-require_relative 'fixtures/classes'
-require_relative 'shared/class_eval'
describe "Module#class_eval" do
- it_behaves_like :module_class_eval, :class_eval
+ it "is an alias of Module#module_eval" do
+ Module.instance_method(:class_eval).should == Module.instance_method(:module_eval)
+ end
end
diff --git a/spec/ruby/core/module/class_exec_spec.rb b/spec/ruby/core/module/class_exec_spec.rb
index 4acd0169ad..d47a6ba982 100644
--- a/spec/ruby/core/module/class_exec_spec.rb
+++ b/spec/ruby/core/module/class_exec_spec.rb
@@ -1,7 +1,7 @@
require_relative '../../spec_helper'
-require_relative 'fixtures/classes'
-require_relative 'shared/class_exec'
describe "Module#class_exec" do
- it_behaves_like :module_class_exec, :class_exec
+ it "is an alias of Module#module_exec" do
+ Module.instance_method(:class_exec).should == Module.instance_method(:module_exec)
+ end
end
diff --git a/spec/ruby/core/module/class_variable_defined_spec.rb b/spec/ruby/core/module/class_variable_defined_spec.rb
index c0f2072a37..dedce9589a 100644
--- a/spec/ruby/core/module/class_variable_defined_spec.rb
+++ b/spec/ruby/core/module/class_variable_defined_spec.rb
@@ -19,13 +19,13 @@ describe "Module#class_variable_defined?" do
obj = mock("metaclass class variable")
meta = obj.singleton_class
meta.send :class_variable_set, :@@var, 1
- meta.send(:class_variable_defined?, :@@var).should be_true
+ meta.send(:class_variable_defined?, :@@var).should == true
end
it "returns false if the class variable is not defined in a metaclass" do
obj = mock("metaclass class variable")
meta = obj.singleton_class
- meta.class_variable_defined?(:@@var).should be_false
+ meta.class_variable_defined?(:@@var).should == false
end
it "returns true if a class variables with the given name is defined in an included module" do
@@ -44,11 +44,11 @@ describe "Module#class_variable_defined?" do
-> {
c.class_variable_defined?(:invalid_name)
- }.should raise_error(NameError)
+ }.should.raise(NameError)
-> {
c.class_variable_defined?("@invalid_name")
- }.should raise_error(NameError)
+ }.should.raise(NameError)
end
it "converts a non string/symbol name to string using to_str" do
@@ -62,11 +62,11 @@ describe "Module#class_variable_defined?" do
o = mock('123')
-> {
c.class_variable_defined?(o)
- }.should raise_error(TypeError)
+ }.should.raise(TypeError)
o.should_receive(:to_str).and_return(123)
-> {
c.class_variable_defined?(o)
- }.should raise_error(TypeError)
+ }.should.raise(TypeError)
end
end
diff --git a/spec/ruby/core/module/class_variable_get_spec.rb b/spec/ruby/core/module/class_variable_get_spec.rb
index e5d06731ec..13f06cb94a 100644
--- a/spec/ruby/core/module/class_variable_get_spec.rb
+++ b/spec/ruby/core/module/class_variable_get_spec.rb
@@ -15,8 +15,8 @@ describe "Module#class_variable_get" do
it "raises a NameError for a class variable named '@@'" do
c = Class.new
- -> { c.send(:class_variable_get, "@@") }.should raise_error(NameError)
- -> { c.send(:class_variable_get, :"@@") }.should raise_error(NameError)
+ -> { c.send(:class_variable_get, "@@") }.should.raise(NameError)
+ -> { c.send(:class_variable_get, :"@@") }.should.raise(NameError)
end
it "raises a NameError for a class variables with the given name defined in an extended module" do
@@ -24,7 +24,7 @@ describe "Module#class_variable_get" do
c.extend ModuleSpecs::MVars
-> {
c.send(:class_variable_get, "@@mvar")
- }.should raise_error(NameError)
+ }.should.raise(NameError)
end
it "returns class variables defined in the class body and accessed in the metaclass" do
@@ -49,15 +49,15 @@ describe "Module#class_variable_get" do
it "raises a NameError when an uninitialized class variable is accessed" do
c = Class.new
[:@@no_class_var, "@@no_class_var"].each do |cvar|
- -> { c.send(:class_variable_get, cvar) }.should raise_error(NameError)
+ -> { c.send(:class_variable_get, cvar) }.should.raise(NameError)
end
end
it "raises a NameError when the given name is not allowed" do
c = Class.new
- -> { c.send(:class_variable_get, :invalid_name) }.should raise_error(NameError)
- -> { c.send(:class_variable_get, "@invalid_name") }.should raise_error(NameError)
+ -> { c.send(:class_variable_get, :invalid_name) }.should.raise(NameError)
+ -> { c.send(:class_variable_get, "@invalid_name") }.should.raise(NameError)
end
it "converts a non string/symbol name to string using to_str" do
@@ -69,8 +69,8 @@ describe "Module#class_variable_get" do
it "raises a TypeError when the given names can't be converted to strings using to_str" do
c = Class.new { class_variable_set :@@class_var, "test" }
o = mock('123')
- -> { c.send(:class_variable_get, o) }.should raise_error(TypeError)
+ -> { c.send(:class_variable_get, o) }.should.raise(TypeError)
o.should_receive(:to_str).and_return(123)
- -> { c.send(:class_variable_get, o) }.should raise_error(TypeError)
+ -> { c.send(:class_variable_get, o) }.should.raise(TypeError)
end
end
diff --git a/spec/ruby/core/module/class_variable_set_spec.rb b/spec/ruby/core/module/class_variable_set_spec.rb
index 63f32f5389..a3d759767b 100644
--- a/spec/ruby/core/module/class_variable_set_spec.rb
+++ b/spec/ruby/core/module/class_variable_set_spec.rb
@@ -28,10 +28,10 @@ describe "Module#class_variable_set" do
it "raises a FrozenError when self is frozen" do
-> {
Class.new.freeze.send(:class_variable_set, :@@test, "test")
- }.should raise_error(FrozenError)
+ }.should.raise(FrozenError)
-> {
Module.new.freeze.send(:class_variable_set, :@@test, "test")
- }.should raise_error(FrozenError)
+ }.should.raise(FrozenError)
end
it "raises a NameError when the given name is not allowed" do
@@ -39,10 +39,10 @@ describe "Module#class_variable_set" do
-> {
c.send(:class_variable_set, :invalid_name, "test")
- }.should raise_error(NameError)
+ }.should.raise(NameError)
-> {
c.send(:class_variable_set, "@invalid_name", "test")
- }.should raise_error(NameError)
+ }.should.raise(NameError)
end
it "converts a non string/symbol name to string using to_str" do
@@ -55,8 +55,8 @@ describe "Module#class_variable_set" do
it "raises a TypeError when the given names can't be converted to strings using to_str" do
c = Class.new { class_variable_set :@@class_var, "test" }
o = mock('123')
- -> { c.send(:class_variable_set, o, "test") }.should raise_error(TypeError)
+ -> { c.send(:class_variable_set, o, "test") }.should.raise(TypeError)
o.should_receive(:to_str).and_return(123)
- -> { c.send(:class_variable_set, o, "test") }.should raise_error(TypeError)
+ -> { c.send(:class_variable_set, o, "test") }.should.raise(TypeError)
end
end
diff --git a/spec/ruby/core/module/class_variables_spec.rb b/spec/ruby/core/module/class_variables_spec.rb
index e155f1deac..9529df48ae 100644
--- a/spec/ruby/core/module/class_variables_spec.rb
+++ b/spec/ruby/core/module/class_variables_spec.rb
@@ -3,8 +3,8 @@ require_relative 'fixtures/classes'
describe "Module#class_variables" do
it "returns an Array with the names of class variables of self" do
- ModuleSpecs::ClassVars::A.class_variables.should include(:@@a_cvar)
- ModuleSpecs::ClassVars::M.class_variables.should include(:@@m_cvar)
+ ModuleSpecs::ClassVars::A.class_variables.should.include?(:@@a_cvar)
+ ModuleSpecs::ClassVars::M.class_variables.should.include?(:@@m_cvar)
end
it "returns an Array of Symbols of class variable names defined in a metaclass" do
@@ -15,13 +15,13 @@ describe "Module#class_variables" do
end
it "returns an Array with names of class variables defined in metaclasses" do
- ModuleSpecs::CVars.class_variables.should include(:@@cls, :@@meta)
+ ModuleSpecs::CVars.class_variables.to_set.should >= Set[:@@cls, :@@meta]
end
it "does not return class variables defined in extended modules" do
c = Class.new
c.extend ModuleSpecs::MVars
- c.class_variables.should_not include(:@@mvar)
+ c.class_variables.should_not.include?(:@@mvar)
end
it "returns the correct class variables when inherit is given" do
diff --git a/spec/ruby/core/module/const_added_spec.rb b/spec/ruby/core/module/const_added_spec.rb
index 739be3ead8..b60af7a2e8 100644
--- a/spec/ruby/core/module/const_added_spec.rb
+++ b/spec/ruby/core/module/const_added_spec.rb
@@ -4,7 +4,7 @@ require_relative 'fixtures/const_added'
describe "Module#const_added" do
it "is a private instance method" do
- Module.should have_private_instance_method(:const_added)
+ Module.private_instance_methods(false).should.include?(:const_added)
end
it "returns nil in the default implementation" do
@@ -117,6 +117,7 @@ describe "Module#const_added" do
end
ScratchPad.recorded.should == [:A, :B]
+ ModuleSpecs::ConstAddedSpecs.send :remove_const, :NamedModule
end
it "is called when a new class is defined under self" do
@@ -158,6 +159,7 @@ describe "Module#const_added" do
end
ScratchPad.recorded.should == [:A, :B]
+ ModuleSpecs::ConstAddedSpecs.send :remove_const, :NamedModuleB
end
it "is called when an autoload is defined" do
diff --git a/spec/ruby/core/module/const_defined_spec.rb b/spec/ruby/core/module/const_defined_spec.rb
index 8b137cd134..9d973c2b2b 100644
--- a/spec/ruby/core/module/const_defined_spec.rb
+++ b/spec/ruby/core/module/const_defined_spec.rb
@@ -14,40 +14,40 @@ describe "Module#const_defined?" do
it "returns true if the constant is defined in the receiver's superclass" do
# CS_CONST4 is defined in the superclass of ChildA
- ConstantSpecs::ContainerA::ChildA.const_defined?(:CS_CONST4).should be_true
+ ConstantSpecs::ContainerA::ChildA.const_defined?(:CS_CONST4).should == true
end
it "returns true if the constant is defined in a mixed-in module of the receiver's parent" do
# CS_CONST10 is defined in a module included by ChildA
- ConstantSpecs::ContainerA::ChildA.const_defined?(:CS_CONST10).should be_true
+ ConstantSpecs::ContainerA::ChildA.const_defined?(:CS_CONST10).should == true
end
it "returns true if the constant is defined in a mixed-in module (with prepends) of the receiver" do
# CS_CONST11 is defined in the module included by ContainerPrepend
- ConstantSpecs::ContainerPrepend.const_defined?(:CS_CONST11).should be_true
+ ConstantSpecs::ContainerPrepend.const_defined?(:CS_CONST11).should == true
end
it "returns true if the constant is defined in Object and the receiver is a module" do
# CS_CONST1 is defined in Object
- ConstantSpecs::ModuleA.const_defined?(:CS_CONST1).should be_true
+ ConstantSpecs::ModuleA.const_defined?(:CS_CONST1).should == true
end
it "returns true if the constant is defined in Object and the receiver is a class that has Object among its ancestors" do
# CS_CONST1 is defined in Object
- ConstantSpecs::ContainerA::ChildA.const_defined?(:CS_CONST1).should be_true
+ ConstantSpecs::ContainerA::ChildA.const_defined?(:CS_CONST1).should == true
end
it "returns false if the constant is defined in the receiver's superclass and the inherit flag is false" do
- ConstantSpecs::ContainerA::ChildA.const_defined?(:CS_CONST4, false).should be_false
+ ConstantSpecs::ContainerA::ChildA.const_defined?(:CS_CONST4, false).should == false
end
it "returns true if the constant is defined in the receiver's superclass and the inherit flag is true" do
- ConstantSpecs::ContainerA::ChildA.const_defined?(:CS_CONST4, true).should be_true
+ ConstantSpecs::ContainerA::ChildA.const_defined?(:CS_CONST4, true).should == true
end
it "coerces the inherit flag to a boolean" do
- ConstantSpecs::ContainerA::ChildA.const_defined?(:CS_CONST4, nil).should be_false
- ConstantSpecs::ContainerA::ChildA.const_defined?(:CS_CONST4, :true).should be_true
+ ConstantSpecs::ContainerA::ChildA.const_defined?(:CS_CONST4, nil).should == false
+ ConstantSpecs::ContainerA::ChildA.const_defined?(:CS_CONST4, :true).should == true
end
it "returns true if the given String names a constant defined in the receiver" do
@@ -58,23 +58,23 @@ describe "Module#const_defined?" do
end
it "returns true when passed a constant name with unicode characters" do
- ConstantUnicodeSpecs.const_defined?("CS_CONSTλ").should be_true
+ ConstantUnicodeSpecs.const_defined?("CS_CONSTλ").should == true
end
it "returns true when passed a constant name with EUC-JP characters" do
str = "CS_CONSTλ".encode("euc-jp")
ConstantSpecs.const_set str, 1
- ConstantSpecs.const_defined?(str).should be_true
+ ConstantSpecs.const_defined?(str).should == true
ensure
ConstantSpecs.send(:remove_const, str)
end
it "returns false if the constant is not defined in the receiver, its superclass, or any included modules" do
# The following constant isn't defined at all.
- ConstantSpecs::ContainerA::ChildA.const_defined?(:CS_CONST4726).should be_false
+ ConstantSpecs::ContainerA::ChildA.const_defined?(:CS_CONST4726).should == false
# DETACHED_CONSTANT is defined in ConstantSpecs::Detached, which isn't
# included by or inherited from ParentA
- ConstantSpecs::ParentA.const_defined?(:DETACHED_CONSTANT).should be_false
+ ConstantSpecs::ParentA.const_defined?(:DETACHED_CONSTANT).should == false
end
it "does not call #const_missing if the constant is not defined in the receiver" do
@@ -90,59 +90,59 @@ describe "Module#const_defined?" do
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)
+ -> { ConstantSpecs.const_defined?(nil) }.should.raise(TypeError)
+ -> { ConstantSpecs.const_defined?([]) }.should.raise(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)
+ -> { ConstantSpecs.const_defined?(name) }.should.raise(NoMethodError)
end
end
it "special cases Object and checks it's included Modules" do
- Object.const_defined?(:CS_CONST10).should be_true
+ Object.const_defined?(:CS_CONST10).should == true
end
it "returns true for toplevel constant when the name begins with '::'" do
- ConstantSpecs.const_defined?("::Array").should be_true
+ ConstantSpecs.const_defined?("::Array").should == true
end
it "returns true when passed a scoped constant name" do
- ConstantSpecs.const_defined?("ClassC::CS_CONST1").should be_true
+ ConstantSpecs.const_defined?("ClassC::CS_CONST1").should == true
end
it "returns true when passed a scoped constant name for a constant in the inheritance hierarchy and the inherited flag is default" do
- ConstantSpecs::ClassD.const_defined?("ClassE::CS_CONST2").should be_true
+ ConstantSpecs::ClassD.const_defined?("ClassE::CS_CONST2").should == true
end
it "returns true when passed a scoped constant name for a constant in the inheritance hierarchy and the inherited flag is true" do
- ConstantSpecs::ClassD.const_defined?("ClassE::CS_CONST2", true).should be_true
+ ConstantSpecs::ClassD.const_defined?("ClassE::CS_CONST2", true).should == true
end
it "returns false when passed a scoped constant name for a constant in the inheritance hierarchy and the inherited flag is false" do
- ConstantSpecs::ClassD.const_defined?("ClassE::CS_CONST2", false).should be_false
+ ConstantSpecs::ClassD.const_defined?("ClassE::CS_CONST2", false).should == false
end
it "returns false when the name begins with '::' and the toplevel constant does not exist" do
- ConstantSpecs.const_defined?("::Name").should be_false
+ ConstantSpecs.const_defined?("::Name").should == false
end
it "raises a NameError if the name does not start with a capital letter" do
- -> { ConstantSpecs.const_defined? "name" }.should raise_error(NameError)
+ -> { ConstantSpecs.const_defined? "name" }.should.raise(NameError)
end
it "raises a NameError if the name starts with '_'" do
- -> { ConstantSpecs.const_defined? "__CONSTX__" }.should raise_error(NameError)
+ -> { ConstantSpecs.const_defined? "__CONSTX__" }.should.raise(NameError)
end
it "raises a NameError if the name starts with '@'" do
- -> { ConstantSpecs.const_defined? "@Name" }.should raise_error(NameError)
+ -> { ConstantSpecs.const_defined? "@Name" }.should.raise(NameError)
end
it "raises a NameError if the name starts with '!'" do
- -> { ConstantSpecs.const_defined? "!Name" }.should raise_error(NameError)
+ -> { ConstantSpecs.const_defined? "!Name" }.should.raise(NameError)
end
it "returns true or false for the nested name" do
@@ -155,15 +155,15 @@ describe "Module#const_defined?" do
it "raises a NameError if the name contains non-alphabetic characters except '_'" do
ConstantSpecs.const_defined?("CS_CONSTX").should == false
- -> { ConstantSpecs.const_defined? "Name=" }.should raise_error(NameError)
- -> { ConstantSpecs.const_defined? "Name?" }.should raise_error(NameError)
+ -> { ConstantSpecs.const_defined? "Name=" }.should.raise(NameError)
+ -> { ConstantSpecs.const_defined? "Name?" }.should.raise(NameError)
end
it "raises a TypeError if conversion to a String by calling #to_str fails" do
name = mock('123')
- -> { ConstantSpecs.const_defined? name }.should raise_error(TypeError)
+ -> { ConstantSpecs.const_defined? name }.should.raise(TypeError)
name.should_receive(:to_str).and_return(123)
- -> { ConstantSpecs.const_defined? name }.should raise_error(TypeError)
+ -> { ConstantSpecs.const_defined? name }.should.raise(TypeError)
end
end
diff --git a/spec/ruby/core/module/const_get_spec.rb b/spec/ruby/core/module/const_get_spec.rb
index 4b53cbe7b3..68b5594faa 100644
--- a/spec/ruby/core/module/const_get_spec.rb
+++ b/spec/ruby/core/module/const_get_spec.rb
@@ -9,28 +9,28 @@ describe "Module#const_get" do
end
it "raises a NameError if no constant is defined in the search path" do
- -> { ConstantSpecs.const_get :CS_CONSTX }.should raise_error(NameError)
+ -> { ConstantSpecs.const_get :CS_CONSTX }.should.raise(NameError)
end
it "raises a NameError with the not found constant symbol" do
error_inspection = -> e { e.name.should == :CS_CONSTX }
- -> { ConstantSpecs.const_get :CS_CONSTX }.should raise_error(NameError, &error_inspection)
+ -> { ConstantSpecs.const_get :CS_CONSTX }.should.raise(NameError, &error_inspection)
end
it "raises a NameError if the name does not start with a capital letter" do
- -> { ConstantSpecs.const_get "name" }.should raise_error(NameError)
+ -> { ConstantSpecs.const_get "name" }.should.raise(NameError)
end
it "raises a NameError if the name starts with a non-alphabetic character" do
- -> { ConstantSpecs.const_get "__CONSTX__" }.should raise_error(NameError)
- -> { ConstantSpecs.const_get "@CS_CONST1" }.should raise_error(NameError)
- -> { ConstantSpecs.const_get "!CS_CONST1" }.should raise_error(NameError)
+ -> { ConstantSpecs.const_get "__CONSTX__" }.should.raise(NameError)
+ -> { ConstantSpecs.const_get "@CS_CONST1" }.should.raise(NameError)
+ -> { ConstantSpecs.const_get "!CS_CONST1" }.should.raise(NameError)
end
it "raises a NameError if the name contains non-alphabetic characters except '_'" do
Object.const_get("CS_CONST1").should == :const1
- -> { ConstantSpecs.const_get "CS_CONST1=" }.should raise_error(NameError)
- -> { ConstantSpecs.const_get "CS_CONST1?" }.should raise_error(NameError)
+ -> { ConstantSpecs.const_get "CS_CONST1=" }.should.raise(NameError)
+ -> { ConstantSpecs.const_get "CS_CONST1?" }.should.raise(NameError)
end
it "calls #to_str to convert the given name to a String" do
@@ -41,10 +41,10 @@ describe "Module#const_get" do
it "raises a TypeError if conversion to a String by calling #to_str fails" do
name = mock('123')
- -> { ConstantSpecs.const_get(name) }.should raise_error(TypeError)
+ -> { ConstantSpecs.const_get(name) }.should.raise(TypeError)
name.should_receive(:to_str).and_return(123)
- -> { ConstantSpecs.const_get(name) }.should raise_error(TypeError)
+ -> { ConstantSpecs.const_get(name) }.should.raise(TypeError)
end
it "calls #const_missing on the receiver if unable to locate the constant" do
@@ -55,21 +55,21 @@ describe "Module#const_get" do
it "does not search the singleton class of a Class or Module" do
-> do
ConstantSpecs::ContainerA::ChildA.const_get(:CS_CONST14)
- end.should raise_error(NameError)
- -> { ConstantSpecs.const_get(:CS_CONST14) }.should raise_error(NameError)
+ end.should.raise(NameError)
+ -> { ConstantSpecs.const_get(:CS_CONST14) }.should.raise(NameError)
end
it "does not search the containing scope" do
ConstantSpecs::ContainerA::ChildA.const_get(:CS_CONST20).should == :const20_2
-> do
ConstantSpecs::ContainerA::ChildA.const_get(:CS_CONST5)
- end.should raise_error(NameError)
+ end.should.raise(NameError)
end
it "raises a NameError if the constant is defined in the receiver's superclass and the inherit flag is false" do
-> do
ConstantSpecs::ContainerA::ChildA.const_get(:CS_CONST4, false)
- end.should raise_error(NameError)
+ end.should.raise(NameError)
end
it "searches into the receiver superclasses if the inherit flag is true" do
@@ -79,13 +79,13 @@ describe "Module#const_get" do
it "raises a NameError when the receiver is a Module, the constant is defined at toplevel and the inherit flag is false" do
-> do
ConstantSpecs::ModuleA.const_get(:CS_CONST1, false)
- end.should raise_error(NameError)
+ end.should.raise(NameError)
end
it "raises a NameError when the receiver is a Class, the constant is defined at toplevel and the inherit flag is false" do
-> do
ConstantSpecs::ContainerA::ChildA.const_get(:CS_CONST1, false)
- end.should raise_error(NameError)
+ end.should.raise(NameError)
end
it "coerces the inherit flag to a boolean" do
@@ -93,7 +93,7 @@ describe "Module#const_get" do
-> do
ConstantSpecs::ContainerA::ChildA.const_get(:CS_CONST1, nil)
- end.should raise_error(NameError)
+ end.should.raise(NameError)
end
it "accepts a toplevel scope qualifier" do
@@ -102,7 +102,7 @@ describe "Module#const_get" do
it "accepts a toplevel scope qualifier when inherit is false" do
ConstantSpecs.const_get("::CS_CONST1", false).should == :const1
- -> { ConstantSpecs.const_get("CS_CONST1", false) }.should raise_error(NameError)
+ -> { ConstantSpecs.const_get("CS_CONST1", false) }.should.raise(NameError)
end
it "returns a constant whose module is defined the toplevel" do
@@ -115,19 +115,19 @@ describe "Module#const_get" do
end
it "raises a NameError if the name includes two successive scope separators" do
- -> { ConstantSpecs.const_get("ClassA::::CS_CONST10") }.should raise_error(NameError)
+ -> { ConstantSpecs.const_get("ClassA::::CS_CONST10") }.should.raise(NameError)
end
it "raises a NameError if only '::' is passed" do
- -> { ConstantSpecs.const_get("::") }.should raise_error(NameError)
+ -> { ConstantSpecs.const_get("::") }.should.raise(NameError)
end
it "raises a NameError if a Symbol has a toplevel scope qualifier" do
- -> { ConstantSpecs.const_get(:'::CS_CONST1') }.should raise_error(NameError)
+ -> { ConstantSpecs.const_get(:'::CS_CONST1') }.should.raise(NameError)
end
it "raises a NameError if a Symbol is a scoped constant name" do
- -> { ConstantSpecs.const_get(:'ClassA::CS_CONST10') }.should raise_error(NameError)
+ -> { ConstantSpecs.const_get(:'ClassA::CS_CONST10') }.should.raise(NameError)
end
it "does read private constants" do
@@ -151,7 +151,7 @@ describe "Module#const_get" do
end
it "raises a NameError when the nested constant does not exist on the module but exists in Object" do
- -> { Object.const_get('ConstantSpecs::CS_CONST1') }.should raise_error(NameError)
+ -> { Object.const_get('ConstantSpecs::CS_CONST1') }.should.raise(NameError)
end
describe "with statically assigned constants" do
diff --git a/spec/ruby/core/module/const_missing_spec.rb b/spec/ruby/core/module/const_missing_spec.rb
index 742218281c..80a2caccab 100644
--- a/spec/ruby/core/module/const_missing_spec.rb
+++ b/spec/ruby/core/module/const_missing_spec.rb
@@ -13,7 +13,7 @@ describe "Module#const_missing" do
it "raises NameError and includes the name of the value that wasn't found" do
-> {
ConstantSpecs.const_missing("HelloMissing")
- }.should raise_error(NameError, /ConstantSpecs::HelloMissing/)
+ }.should.raise(NameError, /ConstantSpecs::HelloMissing/)
end
it "raises NameError and does not include toplevel Object" do
diff --git a/spec/ruby/core/module/const_set_spec.rb b/spec/ruby/core/module/const_set_spec.rb
index 823768b882..aa3c6bbcfc 100644
--- a/spec/ruby/core/module/const_set_spec.rb
+++ b/spec/ruby/core/module/const_set_spec.rb
@@ -50,20 +50,20 @@ describe "Module#const_set" do
end
it "raises a NameError if the name does not start with a capital letter" do
- -> { ConstantSpecs.const_set "name", 1 }.should raise_error(NameError)
+ -> { ConstantSpecs.const_set "name", 1 }.should.raise(NameError)
end
it "raises a NameError if the name starts with a non-alphabetic character" do
- -> { ConstantSpecs.const_set "__CONSTX__", 1 }.should raise_error(NameError)
- -> { ConstantSpecs.const_set "@Name", 1 }.should raise_error(NameError)
- -> { ConstantSpecs.const_set "!Name", 1 }.should raise_error(NameError)
- -> { ConstantSpecs.const_set "::Name", 1 }.should raise_error(NameError)
+ -> { ConstantSpecs.const_set "__CONSTX__", 1 }.should.raise(NameError)
+ -> { ConstantSpecs.const_set "@Name", 1 }.should.raise(NameError)
+ -> { ConstantSpecs.const_set "!Name", 1 }.should.raise(NameError)
+ -> { ConstantSpecs.const_set "::Name", 1 }.should.raise(NameError)
end
it "raises a NameError if the name contains non-alphabetic characters except '_'" do
ConstantSpecs.const_set("CS_CONST404", :const404).should == :const404
- -> { ConstantSpecs.const_set "Name=", 1 }.should raise_error(NameError)
- -> { ConstantSpecs.const_set "Name?", 1 }.should raise_error(NameError)
+ -> { ConstantSpecs.const_set "Name=", 1 }.should.raise(NameError)
+ -> { ConstantSpecs.const_set "Name?", 1 }.should.raise(NameError)
ensure
ConstantSpecs.send(:remove_const, :CS_CONST404)
end
@@ -79,10 +79,10 @@ describe "Module#const_set" do
it "raises a TypeError if conversion to a String by calling #to_str fails" do
name = mock('123')
- -> { ConstantSpecs.const_set name, 1 }.should raise_error(TypeError)
+ -> { ConstantSpecs.const_set name, 1 }.should.raise(TypeError)
name.should_receive(:to_str).and_return(123)
- -> { ConstantSpecs.const_set name, 1 }.should raise_error(TypeError)
+ -> { ConstantSpecs.const_set name, 1 }.should.raise(TypeError)
end
describe "when overwriting an existing constant" do
@@ -110,7 +110,7 @@ describe "Module#const_set" do
mod = Module.new
mod.autoload :Foo, path
- -> { mod::Foo }.should raise_error(NameError)
+ -> { mod::Foo }.should.raise(NameError)
mod.const_defined?(:Foo).should == false
mod.autoload?(:Foo).should == nil
@@ -138,8 +138,8 @@ describe "Module#const_set" do
end
it "raises a FrozenError before setting the name" do
- -> { @frozen.const_set @name, nil }.should raise_error(FrozenError)
- @frozen.should_not have_constant(@name)
+ -> { @frozen.const_set @name, nil }.should.raise(FrozenError)
+ @frozen.should_not.const_defined?(@name)
end
end
end
diff --git a/spec/ruby/core/module/const_source_location_spec.rb b/spec/ruby/core/module/const_source_location_spec.rb
index 06b3b215c2..e6cef727e2 100644
--- a/spec/ruby/core/module/const_source_location_spec.rb
+++ b/spec/ruby/core/module/const_source_location_spec.rb
@@ -142,19 +142,19 @@ describe "Module#const_source_location" do
end
it "raises a NameError if the name does not start with a capital letter" do
- -> { ConstantSpecs.const_source_location "name" }.should raise_error(NameError)
+ -> { ConstantSpecs.const_source_location "name" }.should.raise(NameError)
end
it "raises a NameError if the name starts with a non-alphabetic character" do
- -> { ConstantSpecs.const_source_location "__CONSTX__" }.should raise_error(NameError)
- -> { ConstantSpecs.const_source_location "@CS_CONST1" }.should raise_error(NameError)
- -> { ConstantSpecs.const_source_location "!CS_CONST1" }.should raise_error(NameError)
+ -> { ConstantSpecs.const_source_location "__CONSTX__" }.should.raise(NameError)
+ -> { ConstantSpecs.const_source_location "@CS_CONST1" }.should.raise(NameError)
+ -> { ConstantSpecs.const_source_location "!CS_CONST1" }.should.raise(NameError)
end
it "raises a NameError if the name contains non-alphabetic characters except '_'" do
Object.const_source_location("CS_CONST1").should == [@constants_fixture_path, CS_CONST1_LINE]
- -> { ConstantSpecs.const_source_location "CS_CONST1=" }.should raise_error(NameError)
- -> { ConstantSpecs.const_source_location "CS_CONST1?" }.should raise_error(NameError)
+ -> { ConstantSpecs.const_source_location "CS_CONST1=" }.should.raise(NameError)
+ -> { ConstantSpecs.const_source_location "CS_CONST1?" }.should.raise(NameError)
end
it "calls #to_str to convert the given name to a String" do
@@ -165,10 +165,10 @@ describe "Module#const_source_location" do
it "raises a TypeError if conversion to a String by calling #to_str fails" do
name = mock('123')
- -> { ConstantSpecs.const_source_location(name) }.should raise_error(TypeError)
+ -> { ConstantSpecs.const_source_location(name) }.should.raise(TypeError)
name.should_receive(:to_str).and_return(123)
- -> { ConstantSpecs.const_source_location(name) }.should raise_error(TypeError)
+ -> { ConstantSpecs.const_source_location(name) }.should.raise(TypeError)
end
it "does not search the singleton class of a Class or Module" do
@@ -213,19 +213,19 @@ describe "Module#const_source_location" do
end
it "raises a NameError if the name includes two successive scope separators" do
- -> { ConstantSpecs.const_source_location("ClassA::::CS_CONST10") }.should raise_error(NameError)
+ -> { ConstantSpecs.const_source_location("ClassA::::CS_CONST10") }.should.raise(NameError)
end
it "raises a NameError if only '::' is passed" do
- -> { ConstantSpecs.const_source_location("::") }.should raise_error(NameError)
+ -> { ConstantSpecs.const_source_location("::") }.should.raise(NameError)
end
it "raises a NameError if a Symbol has a toplevel scope qualifier" do
- -> { ConstantSpecs.const_source_location(:'::CS_CONST1') }.should raise_error(NameError)
+ -> { ConstantSpecs.const_source_location(:'::CS_CONST1') }.should.raise(NameError)
end
it "raises a NameError if a Symbol is a scoped constant name" do
- -> { ConstantSpecs.const_source_location(:'ClassA::CS_CONST10') }.should raise_error(NameError)
+ -> { ConstantSpecs.const_source_location(:'ClassA::CS_CONST10') }.should.raise(NameError)
end
it "does search private constants path" do
@@ -245,6 +245,14 @@ describe "Module#const_source_location" do
@line = __LINE__ - 1
end
+ before :each do
+ @loaded_features = $".dup
+ end
+
+ after :each do
+ $".replace @loaded_features
+ end
+
it 'returns the autoload location while not resolved' do
ConstantSpecs.const_source_location('CSL_CONST1').should == [__FILE__, @line]
end
@@ -265,6 +273,8 @@ describe "Module#const_source_location" do
ConstantSpecs.const_source_location(:ConstSource).should == autoload_location
ConstantSpecs::ConstSource::LOCATION.should == ConstantSpecs.const_source_location(:ConstSource)
ConstantSpecs::BEFORE_DEFINE_LOCATION.should == autoload_location
+ ConstantSpecs.send :remove_const, :ConstSource
+ ConstantSpecs.send :remove_const, :BEFORE_DEFINE_LOCATION
end
end
end
diff --git a/spec/ruby/core/module/constants_spec.rb b/spec/ruby/core/module/constants_spec.rb
index 330da1cc88..f2f12761e3 100644
--- a/spec/ruby/core/module/constants_spec.rb
+++ b/spec/ruby/core/module/constants_spec.rb
@@ -13,12 +13,13 @@ describe "Module.constants" do
it "returns an array of Symbol names" do
# This in NOT an exhaustive list
- Module.constants.should include(:Array, :Class, :Comparable, :Dir,
+ Module.constants.to_set.should >= Set[
+ :Array, :Class, :Comparable, :Dir,
:Enumerable, :ENV, :Exception, :FalseClass,
:File, :Float, :Hash, :Integer, :IO,
:Kernel, :Math, :Method, :Module, :NilClass,
:Numeric, :Object, :Range, :Regexp, :String,
- :Symbol, :Thread, :Time, :TrueClass)
+ :Symbol, :Thread, :Time, :TrueClass]
end
it "returns Module's constants when given a parameter" do
@@ -92,6 +93,6 @@ describe "Module#constants" do
end
it "includes names of constants defined after a module is included" do
- ConstantSpecs::ContainerA.constants.should include(:CS_CONST251)
+ ConstantSpecs::ContainerA.constants.should.include?(:CS_CONST251)
end
end
diff --git a/spec/ruby/core/module/define_method_spec.rb b/spec/ruby/core/module/define_method_spec.rb
index c5dfc53764..f838e2b85f 100644
--- a/spec/ruby/core/module/define_method_spec.rb
+++ b/spec/ruby/core/module/define_method_spec.rb
@@ -12,7 +12,7 @@ describe "passed { |a, b = 1| } creates a method that" do
end
it "raises an ArgumentError when passed zero arguments" do
- -> { @klass.new.m }.should raise_error(ArgumentError)
+ -> { @klass.new.m }.should.raise(ArgumentError)
end
it "has a default value for b when passed one argument" do
@@ -24,7 +24,7 @@ describe "passed { |a, b = 1| } creates a method that" do
end
it "raises an ArgumentError when passed three arguments" do
- -> { @klass.new.m(1, 2, 3) }.should raise_error(ArgumentError)
+ -> { @klass.new.m(1, 2, 3) }.should.raise(ArgumentError)
end
end
@@ -47,7 +47,7 @@ describe "Module#define_method when given an UnboundMethod" do
end
define_method(:another_test_method, instance_method(:test_method))
end
- klass.new.should have_method(:another_test_method)
+ klass.new.should.respond_to?(:another_test_method)
end
describe "defining a method on a singleton class" do
@@ -83,7 +83,7 @@ describe "Module#define_method when given an UnboundMethod" do
define_method :piggy, instance_method(:ziggy)
end
- -> { foo.new.ziggy }.should raise_error(NoMethodError)
+ -> { foo.new.ziggy }.should.raise(NoMethodError)
foo.new.piggy.should == 'piggy'
end
end
@@ -115,8 +115,8 @@ describe "Module#define_method when name is not a special private name" do
define_method(:baz, ModuleSpecs::EmptyFooMethod)
end
- klass.should have_public_instance_method(:bar)
- klass.should have_private_instance_method(:baz)
+ klass.public_instance_methods(false).should.include?(:bar)
+ klass.private_instance_methods(false).should.include?(:baz)
end
end
@@ -129,8 +129,8 @@ describe "Module#define_method when name is not a special private name" do
klass.send(:define_method, :baz, ModuleSpecs::EmptyFooMethod)
end
- klass.should have_public_instance_method(:bar)
- klass.should have_public_instance_method(:baz)
+ klass.public_instance_methods(false).should.include?(:bar)
+ klass.public_instance_methods(false).should.include?(:baz)
end
end
@@ -155,8 +155,8 @@ describe "Module#define_method when name is not a special private name" do
define_method(:baz) {}
end
- klass.should have_public_instance_method(:bar)
- klass.should have_private_instance_method(:baz)
+ klass.public_instance_methods(false).should.include?(:bar)
+ klass.private_instance_methods(false).should.include?(:baz)
end
end
@@ -169,8 +169,8 @@ describe "Module#define_method when name is not a special private name" do
klass.send(:define_method, :baz) {}
end
- klass.should have_public_instance_method(:bar)
- klass.should have_public_instance_method(:baz)
+ klass.public_instance_methods(false).should.include?(:bar)
+ klass.public_instance_methods(false).should.include?(:baz)
end
end
end
@@ -182,7 +182,7 @@ describe "Module#define_method when name is :initialize" do
klass = Class.new do
define_method(:initialize) { }
end
- klass.should have_private_instance_method(:initialize)
+ klass.private_instance_methods(false).should.include?(:initialize)
end
end
@@ -193,7 +193,7 @@ describe "Module#define_method when name is :initialize" do
end
define_method(:initialize, instance_method(:test_method))
end
- klass.should have_private_instance_method(:initialize)
+ klass.private_instance_methods(false).should.include?(:initialize)
end
end
end
@@ -233,11 +233,11 @@ describe "Module#define_method" do
it "raises TypeError if name cannot converted to String" do
-> {
Class.new { define_method(1001, -> {}) }
- }.should raise_error(TypeError, /is not a symbol nor a string/)
+ }.should.raise(TypeError, /is not a symbol nor a string/)
-> {
Class.new { define_method([], -> {}) }
- }.should raise_error(TypeError, /is not a symbol nor a string/)
+ }.should.raise(TypeError, /is not a symbol nor a string/)
end
it "converts non-String name to String with #to_str" do
@@ -254,21 +254,21 @@ describe "Module#define_method" do
-> {
Class.new { define_method(obj, -> {}) }
- }.should raise_error(TypeError, /can't convert Object to String/)
+ }.should raise_consistent_error(TypeError, /can't convert Object into String/)
end
it "raises a TypeError when the given method is no Method/Proc" do
-> {
Class.new { define_method(:test, "self") }
- }.should raise_error(TypeError, "wrong argument type String (expected Proc/Method/UnboundMethod)")
+ }.should.raise(TypeError, "wrong argument type String (expected Proc/Method/UnboundMethod)")
-> {
Class.new { define_method(:test, 1234) }
- }.should raise_error(TypeError, "wrong argument type Integer (expected Proc/Method/UnboundMethod)")
+ }.should.raise(TypeError, "wrong argument type Integer (expected Proc/Method/UnboundMethod)")
-> {
Class.new { define_method(:test, nil) }
- }.should raise_error(TypeError, "wrong argument type NilClass (expected Proc/Method/UnboundMethod)")
+ }.should.raise(TypeError, "wrong argument type NilClass (expected Proc/Method/UnboundMethod)")
end
it "uses provided Method/Proc even if block is specified" do
@@ -284,7 +284,7 @@ describe "Module#define_method" do
it "raises an ArgumentError when no block is given" do
-> {
Class.new { define_method(:test) }
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
it "does not use the caller block when no block is given" do
@@ -297,7 +297,7 @@ describe "Module#define_method" do
-> {
o.define(:foo) { raise "not used" }
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
it "does not change the arity check style of the original proc" do
@@ -307,13 +307,13 @@ describe "Module#define_method" do
end
obj = DefineMethodSpecClass.new
- -> { obj.proc_style_test :arg }.should raise_error(ArgumentError)
+ -> { obj.proc_style_test :arg }.should.raise(ArgumentError)
end
it "raises a FrozenError if frozen" do
-> {
Class.new { freeze; define_method(:foo) {} }
- }.should raise_error(FrozenError)
+ }.should.raise(FrozenError)
end
it "accepts a Method (still bound)" do
@@ -326,13 +326,13 @@ describe "Module#define_method" do
o = DefineMethodSpecClass.new
o.data = :foo
m = o.method(:inspect_data)
- m.should be_an_instance_of(Method)
+ m.should.instance_of?(Method)
klass = Class.new(DefineMethodSpecClass)
klass.send(:define_method,:other_inspect, m)
c = klass.new
c.data = :bar
c.other_inspect.should == "data is bar"
- ->{o.other_inspect}.should raise_error(NoMethodError)
+ ->{o.other_inspect}.should.raise(NoMethodError)
end
it "raises a TypeError when a Method from a singleton class is defined on another class" do
@@ -346,7 +346,7 @@ describe "Module#define_method" do
-> {
Class.new { define_method :bar, m }
- }.should raise_error(TypeError, /can't bind singleton method to a different class/)
+ }.should.raise(TypeError, /can't bind singleton method to a different class/)
end
it "raises a TypeError when a Method from one class is defined on an unrelated class" do
@@ -358,7 +358,7 @@ describe "Module#define_method" do
-> {
Class.new { define_method :bar, m }
- }.should raise_error(TypeError)
+ }.should.raise(TypeError)
end
it "accepts an UnboundMethod from an attr_accessor method" do
@@ -370,7 +370,7 @@ describe "Module#define_method" do
o = DefineMethodSpecClass.new
DefineMethodSpecClass.send(:undef_method, :accessor_method)
- -> { o.accessor_method }.should raise_error(NoMethodError)
+ -> { o.accessor_method }.should.raise(NoMethodError)
DefineMethodSpecClass.send(:define_method, :accessor_method, m)
@@ -415,7 +415,7 @@ describe "Module#define_method" do
end
o = DefineMethodByProcClass.new
- o.proc_test.should be_true
+ o.proc_test.should == true
end
it "accepts a String method name" do
@@ -429,7 +429,7 @@ describe "Module#define_method" do
end
it "is a public method" do
- Module.should have_public_instance_method(:define_method)
+ Module.public_instance_methods(false).should.include?(:define_method)
end
it "returns its symbol" do
@@ -443,7 +443,7 @@ describe "Module#define_method" do
klass = Class.new {
define_method :bar, ModuleSpecs::UnboundMethodTest.instance_method(:foo)
}
- klass.new.should respond_to(:bar)
+ klass.new.should.respond_to?(:bar)
end
it "allows an UnboundMethod from a parent class to be defined on a child class" do
@@ -451,7 +451,7 @@ describe "Module#define_method" do
child = Class.new(parent) {
define_method :baz, parent.instance_method(:foo)
}
- child.new.should respond_to(:baz)
+ child.new.should.respond_to?(:baz)
end
it "allows an UnboundMethod from a module to be defined on another unrelated module" do
@@ -459,7 +459,7 @@ describe "Module#define_method" do
define_method :bar, ModuleSpecs::UnboundMethodTest.instance_method(:foo)
}
klass = Class.new { include mod }
- klass.new.should respond_to(:bar)
+ klass.new.should.respond_to?(:bar)
end
@@ -475,7 +475,7 @@ describe "Module#define_method" do
ParentClass = Class.new { define_method(:foo) { :bar } }
ChildClass = Class.new(ParentClass) { define_method(:foo) { :baz } }
ParentClass.send :define_method, :foo, ChildClass.instance_method(:foo)
- }.should raise_error(TypeError, /bind argument must be a subclass of ChildClass/)
+ }.should.raise(TypeError, /bind argument must be a subclass of ChildClass/)
ensure
Object.send(:remove_const, :ParentClass)
Object.send(:remove_const, :ChildClass)
@@ -486,7 +486,7 @@ describe "Module#define_method" do
DestinationClass = Class.new {
define_method :bar, ModuleSpecs::InstanceMeth.instance_method(:foo)
}
- }.should raise_error(TypeError, /bind argument must be a subclass of ModuleSpecs::InstanceMeth/)
+ }.should.raise(TypeError, /bind argument must be a subclass of ModuleSpecs::InstanceMeth/)
end
it "raises a TypeError when an UnboundMethod from a singleton class is defined on another class" do
@@ -500,7 +500,7 @@ describe "Module#define_method" do
-> {
Class.new { define_method :bar, m }
- }.should raise_error(TypeError, /can't bind singleton method to a different class/)
+ }.should.raise(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
@@ -527,7 +527,7 @@ describe "Module#define_method" do
define_method(:bar, c.new.method(:foo))
end
- -> { object.bar }.should raise_error(NoMethodError)
+ -> { object.bar }.should.raise(NoMethodError)
end
end
@@ -544,11 +544,11 @@ describe "Module#define_method" do
end
it "raises an ArgumentError when passed one argument" do
- -> { @klass.new.m 1 }.should raise_error(ArgumentError)
+ -> { @klass.new.m 1 }.should.raise(ArgumentError)
end
it "raises an ArgumentError when passed two arguments" do
- -> { @klass.new.m 1, 2 }.should raise_error(ArgumentError)
+ -> { @klass.new.m 1, 2 }.should.raise(ArgumentError)
end
end
@@ -564,11 +564,11 @@ describe "Module#define_method" do
end
it "raises an ArgumentError when passed one argument" do
- -> { @klass.new.m 1 }.should raise_error(ArgumentError)
+ -> { @klass.new.m 1 }.should.raise(ArgumentError)
end
it "raises an ArgumentError when passed two arguments" do
- -> { @klass.new.m 1, 2 }.should raise_error(ArgumentError)
+ -> { @klass.new.m 1, 2 }.should.raise(ArgumentError)
end
end
@@ -580,15 +580,15 @@ describe "Module#define_method" do
end
it "raises an ArgumentError when passed zero arguments" do
- -> { @klass.new.m }.should raise_error(ArgumentError)
+ -> { @klass.new.m }.should.raise(ArgumentError)
end
it "raises an ArgumentError when passed zero arguments and a block" do
- -> { @klass.new.m { :computed } }.should raise_error(ArgumentError)
+ -> { @klass.new.m { :computed } }.should.raise(ArgumentError)
end
it "raises an ArgumentError when passed two arguments" do
- -> { @klass.new.m 1, 2 }.should raise_error(ArgumentError)
+ -> { @klass.new.m 1, 2 }.should.raise(ArgumentError)
end
it "receives the value passed as the argument when passed one argument" do
@@ -604,15 +604,15 @@ describe "Module#define_method" do
end
it "raises an ArgumentError when passed zero arguments" do
- -> { @klass.new.m }.should raise_error(ArgumentError)
+ -> { @klass.new.m }.should.raise(ArgumentError)
end
it "raises an ArgumentError when passed zero arguments and a block" do
- -> { @klass.new.m { :computed } }.should raise_error(ArgumentError)
+ -> { @klass.new.m { :computed } }.should.raise(ArgumentError)
end
it "raises an ArgumentError when passed two arguments" do
- -> { @klass.new.m 1, 2 }.should raise_error(ArgumentError)
+ -> { @klass.new.m 1, 2 }.should.raise(ArgumentError)
end
it "receives the value passed as the argument when passed one argument" do
@@ -654,7 +654,7 @@ describe "Module#define_method" do
end
it "raises an ArgumentError when passed zero arguments" do
- -> { @klass.new.m }.should raise_error(ArgumentError)
+ -> { @klass.new.m }.should.raise(ArgumentError)
end
it "returns the value computed by the block when passed one argument" do
@@ -682,19 +682,19 @@ describe "Module#define_method" do
end
it "raises an ArgumentError when passed zero arguments" do
- -> { @klass.new.m }.should raise_error(ArgumentError)
+ -> { @klass.new.m }.should.raise(ArgumentError)
end
it "raises an ArgumentError when passed one argument" do
- -> { @klass.new.m 1 }.should raise_error(ArgumentError)
+ -> { @klass.new.m 1 }.should.raise(ArgumentError)
end
it "raises an ArgumentError when passed one argument and a block" do
- -> { @klass.new.m(1) { } }.should raise_error(ArgumentError)
+ -> { @klass.new.m(1) { } }.should.raise(ArgumentError)
end
it "raises an ArgumentError when passed three arguments" do
- -> { @klass.new.m 1, 2, 3 }.should raise_error(ArgumentError)
+ -> { @klass.new.m 1, 2, 3 }.should.raise(ArgumentError)
end
end
@@ -706,15 +706,15 @@ describe "Module#define_method" do
end
it "raises an ArgumentError when passed zero arguments" do
- -> { @klass.new.m }.should raise_error(ArgumentError)
+ -> { @klass.new.m }.should.raise(ArgumentError)
end
it "raises an ArgumentError when passed one argument" do
- -> { @klass.new.m 1 }.should raise_error(ArgumentError)
+ -> { @klass.new.m 1 }.should.raise(ArgumentError)
end
it "raises an ArgumentError when passed one argument and a block" do
- -> { @klass.new.m(1) { } }.should raise_error(ArgumentError)
+ -> { @klass.new.m(1) { } }.should.raise(ArgumentError)
end
it "receives an empty array as the third argument when passed two arguments" do
@@ -795,7 +795,7 @@ describe "Module#define_method when passed a Proc object" do
o = c.new
o.test
- o.should_not have_method :nested_method_in_proc_for_define_method
+ o.should_not.respond_to? :nested_method_in_proc_for_define_method
t.new.nested_method_in_proc_for_define_method.should == 42
end
diff --git a/spec/ruby/core/module/deprecate_constant_spec.rb b/spec/ruby/core/module/deprecate_constant_spec.rb
index ec0de6782f..597379eb87 100644
--- a/spec/ruby/core/module/deprecate_constant_spec.rb
+++ b/spec/ruby/core/module/deprecate_constant_spec.rb
@@ -19,9 +19,9 @@ describe "Module#deprecate_constant" do
-> {
value = @module::PUBLIC1
}.should complain(/warning: constant .+::PUBLIC1 is deprecated/)
- value.should equal(@value)
+ value.should.equal?(@value)
- -> { @module::PRIVATE }.should raise_error(NameError)
+ -> { @module::PRIVATE }.should.raise(NameError)
end
it "warns with a message" do
@@ -61,10 +61,10 @@ describe "Module#deprecate_constant" do
end
it "returns self" do
- @module.deprecate_constant(:PUBLIC1).should equal(@module)
+ @module.deprecate_constant(:PUBLIC1).should.equal?(@module)
end
it "raises a NameError when given an undefined name" do
- -> { @module.deprecate_constant :UNDEFINED }.should raise_error(NameError)
+ -> { @module.deprecate_constant :UNDEFINED }.should.raise(NameError)
end
end
diff --git a/spec/ruby/core/module/extend_object_spec.rb b/spec/ruby/core/module/extend_object_spec.rb
index 1fd1abc0b5..b428eb7924 100644
--- a/spec/ruby/core/module/extend_object_spec.rb
+++ b/spec/ruby/core/module/extend_object_spec.rb
@@ -7,18 +7,18 @@ describe "Module#extend_object" do
end
it "is a private method" do
- Module.should have_private_instance_method(:extend_object)
+ Module.private_instance_methods(false).should.include?(:extend_object)
end
describe "on Class" do
it "is undefined" do
- Class.should_not have_private_instance_method(:extend_object, true)
+ Class.private_instance_methods(true).should_not.include?(:extend_object)
end
it "raises a TypeError if calling after rebinded to Class" do
-> {
Module.instance_method(:extend_object).bind(Class.new).call Object.new
- }.should raise_error(TypeError)
+ }.should.raise(TypeError)
end
end
@@ -49,8 +49,8 @@ describe "Module#extend_object" do
end
it "raises a RuntimeError before extending the object" do
- -> { @receiver.send(:extend_object, @object) }.should raise_error(RuntimeError)
- @object.should_not be_kind_of(@receiver)
+ -> { @receiver.send(:extend_object, @object) }.should.raise(RuntimeError)
+ @object.should_not.is_a?(@receiver)
end
end
end
diff --git a/spec/ruby/core/module/extended_spec.rb b/spec/ruby/core/module/extended_spec.rb
index c6300ffa0b..a4ec5a4ba7 100644
--- a/spec/ruby/core/module/extended_spec.rb
+++ b/spec/ruby/core/module/extended_spec.rb
@@ -39,6 +39,6 @@ describe "Module#extended" do
end
it "is private in its default implementation" do
- Module.new.private_methods.should include(:extended)
+ Module.new.private_methods.should.include?(:extended)
end
end
diff --git a/spec/ruby/core/module/fixtures/autoload_relative_a.rb b/spec/ruby/core/module/fixtures/autoload_relative_a.rb
new file mode 100644
index 0000000000..494181adc2
--- /dev/null
+++ b/spec/ruby/core/module/fixtures/autoload_relative_a.rb
@@ -0,0 +1,9 @@
+module ModuleSpecs
+ module Autoload
+ class AutoloadRelativeA
+ end
+
+ class AutoloadRelativeB
+ end
+ end
+end
diff --git a/spec/ruby/core/module/fixtures/classes.rb b/spec/ruby/core/module/fixtures/classes.rb
index a434e7b0b8..964f64c593 100644
--- a/spec/ruby/core/module/fixtures/classes.rb
+++ b/spec/ruby/core/module/fixtures/classes.rb
@@ -1,6 +1,6 @@
module ModuleSpecs
def self.without_test_modules(modules)
- ignore = %w[MSpecRSpecAdapter PP::ObjectMixin ModuleSpecs::IncludedInObject MainSpecs::Module ConstantSpecs::ModuleA]
+ ignore = %w[MSpecRSpecAdapter PP::ObjectMixin MainSpecs::Module ConstantSpecs::ModuleA]
modules.reject { |k| ignore.include?(k.name) }
end
diff --git a/spec/ruby/core/module/gt_spec.rb b/spec/ruby/core/module/gt_spec.rb
index b8a73c9ff9..04cdd90efb 100644
--- a/spec/ruby/core/module/gt_spec.rb
+++ b/spec/ruby/core/module/gt_spec.rb
@@ -3,10 +3,10 @@ require_relative 'fixtures/classes'
describe "Module#>" do
it "returns false if self is a subclass of or includes the given module" do
- (ModuleSpecs::Child > ModuleSpecs::Parent).should be_false
- (ModuleSpecs::Child > ModuleSpecs::Basic).should be_false
- (ModuleSpecs::Child > ModuleSpecs::Super).should be_false
- (ModuleSpecs::Super > ModuleSpecs::Basic).should be_false
+ (ModuleSpecs::Child > ModuleSpecs::Parent).should == false
+ (ModuleSpecs::Child > ModuleSpecs::Basic).should == false
+ (ModuleSpecs::Child > ModuleSpecs::Super).should == false
+ (ModuleSpecs::Super > ModuleSpecs::Basic).should == false
end
it "returns true if self is a superclass of or included by the given module" do
@@ -31,6 +31,6 @@ describe "Module#>" do
end
it "raises a TypeError if the argument is not a class/module" do
- -> { ModuleSpecs::Parent > mock('x') }.should raise_error(TypeError)
+ -> { ModuleSpecs::Parent > mock('x') }.should.raise(TypeError)
end
end
diff --git a/spec/ruby/core/module/gte_spec.rb b/spec/ruby/core/module/gte_spec.rb
index 18c60ba586..b19fc9fac3 100644
--- a/spec/ruby/core/module/gte_spec.rb
+++ b/spec/ruby/core/module/gte_spec.rb
@@ -28,6 +28,6 @@ describe "Module#>=" do
end
it "raises a TypeError if the argument is not a class/module" do
- -> { ModuleSpecs::Parent >= mock('x') }.should raise_error(TypeError)
+ -> { ModuleSpecs::Parent >= mock('x') }.should.raise(TypeError)
end
end
diff --git a/spec/ruby/core/module/include_spec.rb b/spec/ruby/core/module/include_spec.rb
index 210918b2e7..b6201550e4 100644
--- a/spec/ruby/core/module/include_spec.rb
+++ b/spec/ruby/core/module/include_spec.rb
@@ -3,7 +3,7 @@ require_relative 'fixtures/classes'
describe "Module#include" do
it "is a public method" do
- Module.should have_public_instance_method(:include, false)
+ Module.public_instance_methods(false).should.include?(:include)
end
it "calls #append_features(self) in reversed order on each module" do
@@ -33,20 +33,20 @@ describe "Module#include" do
end
it "adds all ancestor modules when a previously included module is included again" do
- ModuleSpecs::MultipleIncludes.ancestors.should include(ModuleSpecs::MA, ModuleSpecs::MB)
+ ModuleSpecs::MultipleIncludes.ancestors.to_set.should >= Set[ModuleSpecs::MA, ModuleSpecs::MB]
ModuleSpecs::MB.include(ModuleSpecs::MC)
ModuleSpecs::MultipleIncludes.include(ModuleSpecs::MB)
- ModuleSpecs::MultipleIncludes.ancestors.should include(ModuleSpecs::MA, ModuleSpecs::MB, ModuleSpecs::MC)
+ ModuleSpecs::MultipleIncludes.ancestors.to_set.should >= Set[ModuleSpecs::MA, ModuleSpecs::MB, ModuleSpecs::MC]
end
it "raises a TypeError when the argument is not a Module" do
- -> { ModuleSpecs::Basic.include(Class.new) }.should raise_error(TypeError)
+ -> { ModuleSpecs::Basic.include(Class.new) }.should.raise(TypeError)
end
it "does not raise a TypeError when the argument is an instance of a subclass of Module" do
class ModuleSpecs::SubclassSpec::AClass
end
- -> { ModuleSpecs::SubclassSpec::AClass.include(ModuleSpecs::Subclass.new) }.should_not raise_error(TypeError)
+ -> { ModuleSpecs::SubclassSpec::AClass.include(ModuleSpecs::Subclass.new) }.should_not.raise(TypeError)
ensure
ModuleSpecs::SubclassSpec.send(:remove_const, :AClass)
end
@@ -60,13 +60,13 @@ describe "Module#include" do
end
end
- -> { ModuleSpecs::Basic.include(refinement) }.should raise_error(TypeError, "Cannot include refinement")
+ -> { ModuleSpecs::Basic.include(refinement) }.should.raise(TypeError, "Cannot include refinement")
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)
- ModuleSpecs::C.constants.should include(:CONSTANT_A, :CONSTANT_B)
+ ModuleSpecs::A.constants.should.include?(:CONSTANT_A)
+ ModuleSpecs::B.constants.to_set.should >= Set[:CONSTANT_A, :CONSTANT_B]
+ ModuleSpecs::C.constants.to_set.should >= Set[:CONSTANT_A, :CONSTANT_B]
end
it "shadows constants from ancestors" do
@@ -84,9 +84,9 @@ describe "Module#include" do
end
it "imports instance methods to modules and classes" do
- ModuleSpecs::A.instance_methods.should include(:ma)
- ModuleSpecs::B.instance_methods.should include(:ma,:mb)
- ModuleSpecs::C.instance_methods.should include(:ma,:mb)
+ ModuleSpecs::A.instance_methods.should.include?(:ma)
+ ModuleSpecs::B.instance_methods.to_set.should >= Set[:ma,:mb]
+ ModuleSpecs::C.instance_methods.to_set.should >= Set[:ma,:mb]
end
it "does not import methods to modules and classes" do
@@ -146,7 +146,7 @@ describe "Module#include" do
anc = B.ancestors
[B, U, V, W, A, X].each do |i|
- anc.include?(i).should be_true
+ anc.include?(i).should == true
end
class B; include V; end
@@ -154,7 +154,7 @@ describe "Module#include" do
# the only new module is Y, it is added after U since it follows U in V mixin list:
anc = B.ancestors
[B, U, Y, V, W, A, X].each do |i|
- anc.include?(i).should be_true
+ anc.include?(i).should == true
end
end
end
@@ -178,7 +178,7 @@ describe "Module#include" do
module ModuleSpecs::M
include ModuleSpecs::M
end
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
it "doesn't accept no-arguments" do
@@ -186,7 +186,7 @@ describe "Module#include" do
Module.new do
include
end
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
it "returns the class it's included into" do
@@ -622,7 +622,7 @@ describe "Module#include?" do
end
it "raises a TypeError when no module was given" do
- -> { ModuleSpecs::Child.include?("Test") }.should raise_error(TypeError)
- -> { ModuleSpecs::Child.include?(ModuleSpecs::Parent) }.should raise_error(TypeError)
+ -> { ModuleSpecs::Child.include?("Test") }.should.raise(TypeError)
+ -> { ModuleSpecs::Child.include?(ModuleSpecs::Parent) }.should.raise(TypeError)
end
end
diff --git a/spec/ruby/core/module/included_modules_spec.rb b/spec/ruby/core/module/included_modules_spec.rb
index ce94ed1285..e22ee5e6cf 100644
--- a/spec/ruby/core/module/included_modules_spec.rb
+++ b/spec/ruby/core/module/included_modules_spec.rb
@@ -5,10 +5,10 @@ describe "Module#included_modules" do
it "returns a list of modules included in self" do
ModuleSpecs.included_modules.should == []
- ModuleSpecs::Child.included_modules.should include(ModuleSpecs::Super, ModuleSpecs::Basic, Kernel)
- ModuleSpecs::Parent.included_modules.should include(Kernel)
+ ModuleSpecs::Child.included_modules.to_set.should >= Set[ModuleSpecs::Super, ModuleSpecs::Basic, Kernel]
+ ModuleSpecs::Parent.included_modules.should.include?(Kernel)
ModuleSpecs::Basic.included_modules.should == []
- ModuleSpecs::Super.included_modules.should include(ModuleSpecs::Basic)
- ModuleSpecs::WithPrependedModule.included_modules.should include(ModuleSpecs::ModuleWithPrepend)
+ ModuleSpecs::Super.included_modules.should.include?(ModuleSpecs::Basic)
+ ModuleSpecs::WithPrependedModule.included_modules.should.include?(ModuleSpecs::ModuleWithPrepend)
end
end
diff --git a/spec/ruby/core/module/included_spec.rb b/spec/ruby/core/module/included_spec.rb
index 2fdd4325f2..d8a6c3f839 100644
--- a/spec/ruby/core/module/included_spec.rb
+++ b/spec/ruby/core/module/included_spec.rb
@@ -34,7 +34,7 @@ describe "Module#included" do
end
it "is private in its default implementation" do
- Module.should have_private_instance_method(:included)
+ Module.private_instance_methods(false).should.include?(:included)
end
it "works with super using a singleton class" do
diff --git a/spec/ruby/core/module/inspect_spec.rb b/spec/ruby/core/module/inspect_spec.rb
new file mode 100644
index 0000000000..68c8494c96
--- /dev/null
+++ b/spec/ruby/core/module/inspect_spec.rb
@@ -0,0 +1,7 @@
+require_relative '../../spec_helper'
+
+describe "Module#inspect" do
+ it "is an alias of Module#to_s" do
+ Module.instance_method(:inspect).should == Module.instance_method(:to_s)
+ end
+end
diff --git a/spec/ruby/core/module/instance_method_spec.rb b/spec/ruby/core/module/instance_method_spec.rb
index 182cdf5c54..8615e352f6 100644
--- a/spec/ruby/core/module/instance_method_spec.rb
+++ b/spec/ruby/core/module/instance_method_spec.rb
@@ -9,7 +9,7 @@ describe "Module#instance_method" do
end
it "is a public method" do
- Module.should have_public_instance_method(:instance_method, false)
+ Module.public_instance_methods(false).should.include?(:instance_method)
end
it "requires an argument" do
@@ -17,26 +17,26 @@ describe "Module#instance_method" do
end
it "returns an UnboundMethod corresponding to the given name" do
- @parent_um.should be_kind_of(UnboundMethod)
+ @parent_um.should.is_a?(UnboundMethod)
@parent_um.bind(ModuleSpecs::InstanceMeth.new).call.should == :foo
end
it "returns an UnboundMethod corresponding to the given name from a superclass" do
- @child_um.should be_kind_of(UnboundMethod)
+ @child_um.should.is_a?(UnboundMethod)
@child_um.bind(ModuleSpecs::InstanceMethChild.new).call.should == :foo
end
it "returns an UnboundMethod corresponding to the given name from an included Module" do
- @mod_um.should be_kind_of(UnboundMethod)
+ @mod_um.should.is_a?(UnboundMethod)
@mod_um.bind(ModuleSpecs::InstanceMethChild.new).call.should == :bar
end
it "returns an UnboundMethod when given a protected method name" do
- ModuleSpecs::Basic.instance_method(:protected_module).should be_an_instance_of(UnboundMethod)
+ ModuleSpecs::Basic.instance_method(:protected_module).should.instance_of?(UnboundMethod)
end
it "returns an UnboundMethod when given a private method name" do
- ModuleSpecs::Basic.instance_method(:private_module).should be_an_instance_of(UnboundMethod)
+ ModuleSpecs::Basic.instance_method(:private_module).should.instance_of?(UnboundMethod)
end
it "gives UnboundMethod method name, Module defined in and Module extracted from" do
@@ -51,20 +51,20 @@ describe "Module#instance_method" do
end
it "raises a TypeError if the given name is not a String/Symbol" do
- -> { Object.instance_method([]) }.should raise_error(TypeError, /is not a symbol nor a string/)
- -> { Object.instance_method(0) }.should raise_error(TypeError, /is not a symbol nor a string/)
- -> { Object.instance_method(nil) }.should raise_error(TypeError, /is not a symbol nor a string/)
- -> { Object.instance_method(mock('x')) }.should raise_error(TypeError, /is not a symbol nor a string/)
+ -> { Object.instance_method([]) }.should.raise(TypeError, /is not a symbol nor a string/)
+ -> { Object.instance_method(0) }.should.raise(TypeError, /is not a symbol nor a string/)
+ -> { Object.instance_method(nil) }.should.raise(TypeError, /is not a symbol nor a string/)
+ -> { Object.instance_method(mock('x')) }.should.raise(TypeError, /is not a symbol nor a string/)
end
it "accepts String name argument" do
method = ModuleSpecs::InstanceMeth.instance_method(:foo)
- method.should be_kind_of(UnboundMethod)
+ method.should.is_a?(UnboundMethod)
end
it "accepts Symbol name argument" do
method = ModuleSpecs::InstanceMeth.instance_method("foo")
- method.should be_kind_of(UnboundMethod)
+ method.should.is_a?(UnboundMethod)
end
it "converts non-String name by calling #to_str method" do
@@ -72,14 +72,14 @@ describe "Module#instance_method" do
def obj.to_str() "foo" end
method = ModuleSpecs::InstanceMeth.instance_method(obj)
- method.should be_kind_of(UnboundMethod)
+ method.should.is_a?(UnboundMethod)
end
it "raises TypeError when passed non-String name and #to_str returns non-String value" do
obj = Object.new
def obj.to_str() [] end
- -> { ModuleSpecs::InstanceMeth.instance_method(obj) }.should raise_error(TypeError, /can't convert Object to String/)
+ -> { ModuleSpecs::InstanceMeth.instance_method(obj) }.should raise_consistent_error(TypeError, /can't convert Object into String/)
end
it "raises a NameError if the method has been undefined" do
@@ -89,11 +89,11 @@ describe "Module#instance_method" do
um.should == @parent_um
-> do
child.instance_method(:foo)
- end.should raise_error(NameError)
+ end.should.raise(NameError)
end
it "raises a NameError if the method does not exist" do
- -> { Object.instance_method(:missing) }.should raise_error(NameError)
+ -> { Object.instance_method(:missing) }.should.raise(NameError)
end
it "sets the NameError#name attribute to the name of the missing method" do
diff --git a/spec/ruby/core/module/instance_methods_spec.rb b/spec/ruby/core/module/instance_methods_spec.rb
index d2d38cdda2..dbb6df8c34 100644
--- a/spec/ruby/core/module/instance_methods_spec.rb
+++ b/spec/ruby/core/module/instance_methods_spec.rb
@@ -4,21 +4,22 @@ require_relative 'fixtures/classes'
describe "Module#instance_methods" do
it "does not return methods undefined in a superclass" do
methods = ModuleSpecs::Parent.instance_methods(false)
- methods.should_not include(:undefed_method)
+ methods.should_not.include?(:undefed_method)
end
it "only includes module methods on an included module" do
methods = ModuleSpecs::Basic.instance_methods(false)
- methods.should include(:public_module)
+ methods.should.include?(:public_module)
# Child is an including class
methods = ModuleSpecs::Child.instance_methods(false)
- methods.should include(:public_child)
- methods.should_not include(:public_module)
+ methods.should.include?(:public_child)
+ methods.should_not.include?(:public_module)
end
it "does not return methods undefined in a subclass" do
methods = ModuleSpecs::Grandchild.instance_methods
- methods.should_not include(:parent_method, :another_parent_method)
+ methods.should_not.include?(:parent_method)
+ methods.should_not.include?(:another_parent_method)
end
it "does not return methods undefined in the current class" do
@@ -28,34 +29,35 @@ describe "Module#instance_methods" do
end
ModuleSpecs::Child.send(:undef_method, :undefed_child)
methods = ModuleSpecs::Child.instance_methods
- methods.should_not include(:undefed_method, :undefed_child)
+ methods.should_not.include?(:undefed_method)
+ methods.should_not.include?(:undefed_child)
end
it "does not return methods from an included module that are undefined in the class" do
- ModuleSpecs::Grandchild.instance_methods.should_not include(:super_included_method)
+ ModuleSpecs::Grandchild.instance_methods.should_not.include?(:super_included_method)
end
it "returns the public and protected methods of self if include_super is false" do
methods = ModuleSpecs::Parent.instance_methods(false)
- methods.should include(:protected_parent, :public_parent)
+ methods.to_set.should >= Set[:protected_parent, :public_parent]
methods = ModuleSpecs::Child.instance_methods(false)
- methods.should include(:protected_child, :public_child)
+ methods.to_set.should >= Set[:protected_child, :public_child]
end
it "returns the public and protected methods of self and it's ancestors" do
methods = ModuleSpecs::Basic.instance_methods
- methods.should include(:protected_module, :public_module)
+ methods.to_set.should >= Set[:protected_module, :public_module]
methods = ModuleSpecs::Super.instance_methods
- methods.should include(:protected_module, :protected_super_module,
- :public_module, :public_super_module)
+ methods.to_set.should >= Set[:protected_module, :protected_super_module,
+ :public_module, :public_super_module]
end
it "makes a private Object instance method public in Kernel" do
methods = Kernel.instance_methods
- methods.should include(:module_specs_private_method_on_object_for_kernel_public)
+ methods.should.include?(:module_specs_private_method_on_object_for_kernel_public)
methods = Object.instance_methods
- methods.should_not include(:module_specs_private_method_on_object_for_kernel_public)
+ methods.should_not.include?(:module_specs_private_method_on_object_for_kernel_public)
end
end
diff --git a/spec/ruby/core/module/lt_spec.rb b/spec/ruby/core/module/lt_spec.rb
index d7771e07a8..8567a24993 100644
--- a/spec/ruby/core/module/lt_spec.rb
+++ b/spec/ruby/core/module/lt_spec.rb
@@ -10,10 +10,10 @@ describe "Module#<" do
end
it "returns false if self is a superclass of or included by the given module" do
- (ModuleSpecs::Parent < ModuleSpecs::Child).should be_false
- (ModuleSpecs::Basic < ModuleSpecs::Child).should be_false
- (ModuleSpecs::Super < ModuleSpecs::Child).should be_false
- (ModuleSpecs::Basic < ModuleSpecs::Super).should be_false
+ (ModuleSpecs::Parent < ModuleSpecs::Child).should == false
+ (ModuleSpecs::Basic < ModuleSpecs::Child).should == false
+ (ModuleSpecs::Super < ModuleSpecs::Child).should == false
+ (ModuleSpecs::Basic < ModuleSpecs::Super).should == false
end
it "returns false if self is the same as the given module" do
@@ -31,6 +31,6 @@ describe "Module#<" do
end
it "raises a TypeError if the argument is not a class/module" do
- -> { ModuleSpecs::Parent < mock('x') }.should raise_error(TypeError)
+ -> { ModuleSpecs::Parent < mock('x') }.should.raise(TypeError)
end
end
diff --git a/spec/ruby/core/module/lte_spec.rb b/spec/ruby/core/module/lte_spec.rb
index 7a0e8496b8..c6aab94e9f 100644
--- a/spec/ruby/core/module/lte_spec.rb
+++ b/spec/ruby/core/module/lte_spec.rb
@@ -28,6 +28,6 @@ describe "Module#<=" do
end
it "raises a TypeError if the argument is not a class/module" do
- -> { ModuleSpecs::Parent <= mock('x') }.should raise_error(TypeError)
+ -> { ModuleSpecs::Parent <= mock('x') }.should.raise(TypeError)
end
end
diff --git a/spec/ruby/core/module/method_added_spec.rb b/spec/ruby/core/module/method_added_spec.rb
index ec92cddc1e..996a14eb86 100644
--- a/spec/ruby/core/module/method_added_spec.rb
+++ b/spec/ruby/core/module/method_added_spec.rb
@@ -7,7 +7,7 @@ describe "Module#method_added" do
end
it "is a private instance method" do
- Module.should have_private_instance_method(:method_added)
+ Module.private_instance_methods(false).should.include?(:method_added)
end
it "returns nil in the default implementation" do
@@ -57,7 +57,7 @@ describe "Module#method_added" do
undef_method :method_to_undef
end
- m.should_not have_method(:method_to_undef)
+ m.should_not.respond_to?(:method_to_undef)
end
it "is not called when a method changes visibility" do
diff --git a/spec/ruby/core/module/method_defined_spec.rb b/spec/ruby/core/module/method_defined_spec.rb
index bc5b420e11..e6b4c7b817 100644
--- a/spec/ruby/core/module/method_defined_spec.rb
+++ b/spec/ruby/core/module/method_defined_spec.rb
@@ -27,17 +27,17 @@ describe "Module#method_defined?" do
it "does not search Object or Kernel when called on a module" do
m = Module.new
- m.method_defined?(:module_specs_public_method_on_kernel).should be_false
+ m.method_defined?(:module_specs_public_method_on_kernel).should == false
end
it "raises a TypeError when the given object is not a string/symbol" do
c = Class.new
o = mock('123')
- -> { c.method_defined?(o) }.should raise_error(TypeError)
+ -> { c.method_defined?(o) }.should.raise(TypeError)
o.should_receive(:to_str).and_return(123)
- -> { c.method_defined?(o) }.should raise_error(TypeError)
+ -> { c.method_defined?(o) }.should.raise(TypeError)
end
it "converts the given name to a string using to_str" do
diff --git a/spec/ruby/core/module/method_removed_spec.rb b/spec/ruby/core/module/method_removed_spec.rb
index 9b39eb77a6..80e546406c 100644
--- a/spec/ruby/core/module/method_removed_spec.rb
+++ b/spec/ruby/core/module/method_removed_spec.rb
@@ -3,7 +3,7 @@ require_relative 'fixtures/classes'
describe "Module#method_removed" do
it "is a private instance method" do
- Module.should have_private_instance_method(:method_removed)
+ Module.private_instance_methods(false).should.include?(:method_removed)
end
it "returns nil in the default implementation" do
diff --git a/spec/ruby/core/module/method_undefined_spec.rb b/spec/ruby/core/module/method_undefined_spec.rb
index a94388fe0a..596c5c50e2 100644
--- a/spec/ruby/core/module/method_undefined_spec.rb
+++ b/spec/ruby/core/module/method_undefined_spec.rb
@@ -3,7 +3,7 @@ require_relative 'fixtures/classes'
describe "Module#method_undefined" do
it "is a private instance method" do
- Module.should have_private_instance_method(:method_undefined)
+ Module.private_instance_methods(false).should.include?(:method_undefined)
end
it "returns nil in the default implementation" do
diff --git a/spec/ruby/core/module/module_eval_spec.rb b/spec/ruby/core/module/module_eval_spec.rb
index e9e9fda28d..bcd51ca19d 100644
--- a/spec/ruby/core/module/module_eval_spec.rb
+++ b/spec/ruby/core/module/module_eval_spec.rb
@@ -1,7 +1,175 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
-require_relative 'shared/class_eval'
describe "Module#module_eval" do
- it_behaves_like :module_class_eval, :module_eval
+ # TODO: This should probably be replaced with a "should behave like" that uses
+ # the many scoping/binding specs from kernel/eval_spec, since most of those
+ # behaviors are the same for instance_eval. See also module_eval/class_eval.
+
+ it "evaluates a given string in the context of self" do
+ ModuleSpecs.module_eval("self").should == ModuleSpecs
+ ModuleSpecs.module_eval("1 + 1").should == 2
+ end
+
+ it "does not add defined methods to other classes" do
+ FalseClass.module_eval do
+ def foo
+ 'foo'
+ end
+ end
+ -> {42.foo}.should.raise(NoMethodError)
+ end
+
+ it "resolves constants in the caller scope" do
+ ModuleSpecs::ClassEvalTest.get_constant_from_scope.should == ModuleSpecs::Lookup
+ end
+
+ it "resolves constants in the caller scope ignoring send" do
+ ModuleSpecs::ClassEvalTest.get_constant_from_scope_with_send(:module_eval).should == ModuleSpecs::Lookup
+ end
+
+ it "resolves constants in the receiver's scope" do
+ ModuleSpecs.module_eval("Lookup").should == ModuleSpecs::Lookup
+ ModuleSpecs.module_eval("Lookup::LOOKIE").should == ModuleSpecs::Lookup::LOOKIE
+ end
+
+ it "defines constants in the receiver's scope" do
+ ModuleSpecs.module_eval("module NewEvaluatedModule;end")
+ ModuleSpecs.const_defined?(:NewEvaluatedModule, false).should == true
+ end
+
+ it "evaluates a given block in the context of self" do
+ ModuleSpecs.module_eval { self }.should == ModuleSpecs
+ ModuleSpecs.module_eval { 1 + 1 }.should == 2
+ end
+
+ it "passes the module as the first argument of the block" do
+ given = nil
+ ModuleSpecs.module_eval do |block_parameter|
+ given = block_parameter
+ end
+ given.should.equal? ModuleSpecs
+ end
+
+ it "uses the optional filename and lineno parameters for error messages" do
+ ModuleSpecs.module_eval("[__FILE__, __LINE__]", "test", 102).should == ["test", 102]
+ end
+
+ it "uses the caller location as default filename" do
+ ModuleSpecs.module_eval("[__FILE__, __LINE__]").should == ["(eval at #{__FILE__}:#{__LINE__})", 1]
+ 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.module_eval("1+1", file)
+
+ (file = mock(__FILE__)).should_receive(:to_str).and_return(__FILE__)
+ ModuleSpecs.module_eval("1+1", file, 15)
+ end
+
+ it "raises a TypeError when the given filename can't be converted to string using to_str" do
+ (file = mock('123')).should_receive(:to_str).and_return(123)
+ -> { ModuleSpecs.module_eval("1+1", file) }.should raise_consistent_error(TypeError, /can't convert MockObject into String/)
+ end
+
+ it "converts non string eval-string to string using to_str" do
+ (o = mock('1 + 1')).should_receive(:to_str).and_return("1 + 1")
+ ModuleSpecs.module_eval(o).should == 2
+
+ (o = mock('1 + 1')).should_receive(:to_str).and_return("1 + 1")
+ ModuleSpecs.module_eval(o, "file.rb").should == 2
+
+ (o = mock('1 + 1')).should_receive(:to_str).and_return("1 + 1")
+ ModuleSpecs.module_eval(o, "file.rb", 15).should == 2
+ end
+
+ it "raises a TypeError when the given eval-string can't be converted to string using to_str" do
+ o = mock('x')
+ -> { ModuleSpecs.module_eval(o) }.should.raise(TypeError, "no implicit conversion of MockObject into String")
+
+ (o = mock('123')).should_receive(:to_str).and_return(123)
+ -> { ModuleSpecs.module_eval(o) }.should raise_consistent_error(TypeError, /can't convert MockObject into String/)
+ end
+
+ it "raises an ArgumentError when no arguments and no block are given" do
+ -> { ModuleSpecs.module_eval }.should.raise(ArgumentError, "wrong number of arguments (given 0, expected 1..3)")
+ end
+
+ it "raises an ArgumentError when more than 3 arguments are given" do
+ -> {
+ ModuleSpecs.module_eval("1 + 1", "some file", 0, "bogus")
+ }.should.raise(ArgumentError, "wrong number of arguments (given 4, expected 1..3)")
+ end
+
+ it "raises an ArgumentError when a block and normal arguments are given" do
+ -> {
+ ModuleSpecs.module_eval("1 + 1") { 1 + 1 }
+ }.should.raise(ArgumentError, "wrong number of arguments (given 1, expected 0)")
+ end
+
+ # This case was found because Rubinius was caching the compiled
+ # version of the string and not duping the methods within the
+ # eval, causing the method addition to change the static scope
+ # of the shared CompiledCode.
+ it "adds methods respecting the lexical constant scope" do
+ code = "def self.attribute; C; end"
+
+ a = Class.new do
+ self::C = "A"
+ end
+
+ b = Class.new do
+ self::C = "B"
+ end
+
+ a.module_eval(code)
+ b.module_eval(code)
+
+ a.attribute.should == "A"
+ b.attribute.should == "B"
+ end
+
+ it "activates refinements from the eval scope" do
+ refinery = Module.new do
+ refine ModuleSpecs::NamedClass do
+ def foo
+ "bar"
+ end
+ end
+ end
+
+ mid = :module_eval
+ result = nil
+
+ Class.new do
+ using refinery
+
+ result = send(mid, "ModuleSpecs::NamedClass.new.foo")
+ end
+
+ result.should == "bar"
+ end
+
+ it "activates refinements from the eval scope with block" do
+ refinery = Module.new do
+ refine ModuleSpecs::NamedClass do
+ def foo
+ "bar"
+ end
+ end
+ end
+
+ mid = :module_eval
+ result = nil
+
+ Class.new do
+ using refinery
+
+ result = send(mid) do
+ ModuleSpecs::NamedClass.new.foo
+ end
+ end
+
+ result.should == "bar"
+ end
end
diff --git a/spec/ruby/core/module/module_exec_spec.rb b/spec/ruby/core/module/module_exec_spec.rb
index 47cdf7ef52..6b36e8a02f 100644
--- a/spec/ruby/core/module/module_exec_spec.rb
+++ b/spec/ruby/core/module/module_exec_spec.rb
@@ -1,7 +1,38 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
-require_relative 'shared/class_exec'
describe "Module#module_exec" do
- it_behaves_like :module_class_exec, :module_exec
+ it "does not add defined methods to other classes" do
+ FalseClass.module_exec do
+ def foo
+ 'foo'
+ end
+ end
+ -> {42.foo}.should.raise(NoMethodError)
+ end
+
+ it "defines method in the receiver's scope" do
+ ModuleSpecs::Subclass.module_exec { def foo; end }
+ ModuleSpecs::Subclass.new.respond_to?(:foo).should == true
+ end
+
+ it "evaluates a given block in the context of self" do
+ ModuleSpecs::Subclass.module_exec { self }.should == ModuleSpecs::Subclass
+ ModuleSpecs::Subclass.new.module_exec { 1 + 1 }.should == 2
+ end
+
+ it "raises a LocalJumpError when no block is given" do
+ -> { ModuleSpecs::Subclass.module_exec }.should.raise(LocalJumpError)
+ end
+
+ it "passes arguments to the block" do
+ a = ModuleSpecs::Subclass
+ a.module_exec(1) { |b| b }.should.equal?(1)
+ end
+
+ describe "with optional argument" do
+ it "does not destructure a single array argument" do
+ ModuleSpecs::Subclass.module_exec([1, 2, 3]) { |a = 99| a }.should == [1, 2, 3]
+ end
+ end
end
diff --git a/spec/ruby/core/module/module_function_spec.rb b/spec/ruby/core/module/module_function_spec.rb
index 51f647142e..41bd152608 100644
--- a/spec/ruby/core/module/module_function_spec.rb
+++ b/spec/ruby/core/module/module_function_spec.rb
@@ -3,22 +3,22 @@ require_relative 'fixtures/classes'
describe "Module#module_function" do
it "is a private method" do
- Module.should have_private_instance_method(:module_function)
+ Module.private_instance_methods(false).should.include?(:module_function)
end
describe "on Class" do
it "is undefined" do
- Class.should_not have_private_instance_method(:module_function, true)
+ Class.private_instance_methods(true).should_not.include?(:module_function)
end
it "raises a TypeError if calling after rebinded to Class" do
-> {
Module.instance_method(:module_function).bind(Class.new).call
- }.should raise_error(TypeError)
+ }.should.raise(TypeError)
-> {
Module.instance_method(:module_function).bind(Class.new).call :foo
- }.should raise_error(TypeError)
+ }.should.raise(TypeError)
end
end
end
@@ -41,7 +41,7 @@ describe "Module#module_function with specific method names" do
it "returns argument or arguments if given" do
Module.new do
def foo; end
- module_function(:foo).should equal(:foo)
+ module_function(:foo).should.equal?(:foo)
module_function(:foo, :foo).should == [:foo, :foo]
end
end
@@ -83,9 +83,9 @@ describe "Module#module_function with specific method names" do
(o = mock('x')).extend(m)
o.respond_to?(:test).should == false
- m.should have_private_instance_method(:test)
+ m.private_instance_methods(false).should.include?(:test)
o.send(:test).should == "hello"
- -> { o.test }.should raise_error(NoMethodError)
+ -> { o.test }.should.raise(NoMethodError)
end
it "makes the new Module methods public" do
@@ -114,17 +114,17 @@ describe "Module#module_function with specific method names" do
it "raises a TypeError when the given names can't be converted to string using to_str" do
o = mock('123')
- -> { Module.new { module_function(o) } }.should raise_error(TypeError)
+ -> { Module.new { module_function(o) } }.should.raise(TypeError)
o.should_receive(:to_str).and_return(123)
- -> { Module.new { module_function(o) } }.should raise_error(TypeError)
+ -> { Module.new { module_function(o) } }.should.raise(TypeError)
end
it "can make accessible private methods" do # JRUBY-4214
m = Module.new do
module_function :require
end
- m.respond_to?(:require).should be_true
+ m.respond_to?(:require).should == true
end
it "creates Module methods that super up the singleton class of the module" do
@@ -207,7 +207,7 @@ describe "Module#module_function as a toggle (no arguments) in a Module body" do
it "returns nil" do
Module.new do
- module_function.should equal(nil)
+ module_function.should.equal?(nil)
end
end
diff --git a/spec/ruby/core/module/name_spec.rb b/spec/ruby/core/module/name_spec.rb
index fd28ee0a33..332c08d782 100644
--- a/spec/ruby/core/module/name_spec.rb
+++ b/spec/ruby/core/module/name_spec.rb
@@ -3,7 +3,7 @@ require_relative 'fixtures/module'
describe "Module#name" do
it "is nil for an anonymous module" do
- Module.new.name.should be_nil
+ Module.new.name.should == nil
end
it "is not nil when assigned to a constant in an anonymous module" do
@@ -19,9 +19,9 @@ describe "Module#name" do
end
it "returns nil for a singleton class" do
- Module.new.singleton_class.name.should be_nil
- String.singleton_class.name.should be_nil
- Object.new.singleton_class.name.should be_nil
+ Module.new.singleton_class.name.should == nil
+ String.singleton_class.name.should == nil
+ Object.new.singleton_class.name.should == nil
end
it "changes when the module is reachable through a constant path" do
@@ -148,7 +148,7 @@ describe "Module#name" do
"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.
+ valid_names.should.include?(m::N.name) # You get one of the two, but you don't know which one.
ensure
ModuleSpecs::Anonymous.send(:remove_const, :StoredInMultiplePlaces)
end
@@ -190,6 +190,7 @@ describe "Module#name" do
ScratchPad.recorded.should.one?(/#<Module.+>::A$/)
ScratchPad.recorded.should.one?(/#<Module.+>::A::B$/)
+ ModuleSpecs::NameSpecs.send :remove_const, :NamedModule
end
it "returns a frozen String" do
@@ -199,6 +200,6 @@ describe "Module#name" do
it "always returns the same String for a given Module" do
s1 = ModuleSpecs.name
s2 = ModuleSpecs.name
- s1.should equal(s2)
+ s1.should.equal?(s2)
end
end
diff --git a/spec/ruby/core/module/new_spec.rb b/spec/ruby/core/module/new_spec.rb
index ec521360bd..ec7a0cfa77 100644
--- a/spec/ruby/core/module/new_spec.rb
+++ b/spec/ruby/core/module/new_spec.rb
@@ -7,7 +7,7 @@ describe "Module.new" do
end
it "creates a module without a name" do
- Module.new.name.should be_nil
+ Module.new.name.should == nil
end
it "creates a new Module and passes it to the provided block" do
diff --git a/spec/ruby/core/module/prepend_features_spec.rb b/spec/ruby/core/module/prepend_features_spec.rb
index 09c15c5c15..3a50f2c2a4 100644
--- a/spec/ruby/core/module/prepend_features_spec.rb
+++ b/spec/ruby/core/module/prepend_features_spec.rb
@@ -3,7 +3,7 @@ require_relative 'fixtures/classes'
describe "Module#prepend_features" do
it "is a private method" do
- Module.should have_private_instance_method(:prepend_features, true)
+ Module.private_instance_methods(false).should.include?(:prepend_features)
end
it "gets called when self is included in another module/class" do
@@ -25,7 +25,7 @@ describe "Module#prepend_features" do
it "raises an ArgumentError on a cyclic prepend" do
-> {
ModuleSpecs::CyclicPrepend.send(:prepend_features, ModuleSpecs::CyclicPrepend)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
it "clears caches of the given module" do
@@ -52,13 +52,13 @@ describe "Module#prepend_features" do
describe "on Class" do
it "is undefined" do
- Class.should_not have_private_instance_method(:prepend_features, true)
+ Class.private_instance_methods(true).should_not.include?(:prepend_features)
end
it "raises a TypeError if calling after rebinded to Class" do
-> {
Module.instance_method(:prepend_features).bind(Class.new).call Module.new
- }.should raise_error(TypeError)
+ }.should.raise(TypeError)
end
end
end
diff --git a/spec/ruby/core/module/prepend_spec.rb b/spec/ruby/core/module/prepend_spec.rb
index 71e82c513e..f7887e6d6a 100644
--- a/spec/ruby/core/module/prepend_spec.rb
+++ b/spec/ruby/core/module/prepend_spec.rb
@@ -3,7 +3,7 @@ require_relative 'fixtures/classes'
describe "Module#prepend" do
it "is a public method" do
- Module.should have_public_instance_method(:prepend, false)
+ Module.public_instance_methods(false).should.include?(:prepend)
end
it "does not affect the superclass" do
@@ -444,13 +444,13 @@ describe "Module#prepend" do
end
it "raises a TypeError when the argument is not a Module" do
- -> { ModuleSpecs::Basic.prepend(Class.new) }.should raise_error(TypeError)
+ -> { ModuleSpecs::Basic.prepend(Class.new) }.should.raise(TypeError)
end
it "does not raise a TypeError when the argument is an instance of a subclass of Module" do
class ModuleSpecs::SubclassSpec::AClass
end
- -> { ModuleSpecs::SubclassSpec::AClass.prepend(ModuleSpecs::Subclass.new) }.should_not raise_error(TypeError)
+ -> { ModuleSpecs::SubclassSpec::AClass.prepend(ModuleSpecs::Subclass.new) }.should_not.raise(TypeError)
ensure
ModuleSpecs::SubclassSpec.send(:remove_const, :AClass)
end
@@ -464,22 +464,22 @@ describe "Module#prepend" do
end
end
- -> { ModuleSpecs::Basic.prepend(refinement) }.should raise_error(TypeError, "Cannot prepend refinement")
+ -> { ModuleSpecs::Basic.prepend(refinement) }.should.raise(TypeError, "Cannot prepend refinement")
end
it "imports constants" do
m1 = Module.new
m1::MY_CONSTANT = 1
m2 = Module.new { prepend(m1) }
- m2.constants.should include(:MY_CONSTANT)
+ m2.constants.should.include?(:MY_CONSTANT)
end
it "imports instance methods" do
- Module.new { prepend ModuleSpecs::A }.instance_methods.should include(:ma)
+ Module.new { prepend ModuleSpecs::A }.instance_methods.should.include?(:ma)
end
it "does not import methods to modules and classes" do
- Module.new { prepend ModuleSpecs::A }.methods.should_not include(:ma)
+ Module.new { prepend ModuleSpecs::A }.methods.should_not.include?(:ma)
end
it "allows wrapping methods" do
@@ -505,7 +505,7 @@ describe "Module#prepend" do
it "includes prepended modules in ancestors" do
m = Module.new
- Class.new { prepend(m) }.ancestors.should include(m)
+ Class.new { prepend(m) }.ancestors.should.include?(m)
end
it "reports the prepended module as the method owner" do
@@ -542,13 +542,13 @@ describe "Module#prepend" do
it "sees an instance of a prepended class as kind of the prepended module" do
m = Module.new
c = Class.new { prepend(m) }
- c.new.should be_kind_of(m)
+ c.new.should.is_a?(m)
end
it "keeps the module in the chain when dupping the class" do
m = Module.new
c = Class.new { prepend(m) }
- c.dup.new.should be_kind_of(m)
+ c.dup.new.should.is_a?(m)
end
it "uses only new module when dupping the module" do
@@ -559,14 +559,14 @@ describe "Module#prepend" do
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)
+ c1.new.should.is_a?(m1)
c2.ancestors[0,3].should == [m1,m2dup,c2]
- c2.new.should be_kind_of(m1)
+ c2.new.should.is_a?(m1)
end
it "depends on prepend_features to add the module" do
m = Module.new { def self.prepend_features(mod) end }
- Class.new { prepend(m) }.ancestors.should_not include(m)
+ Class.new { prepend(m) }.ancestors.should_not.include?(m)
end
it "adds the module in the subclass chains" do
@@ -627,7 +627,7 @@ describe "Module#prepend" do
super << :class
end
end
- -> { c.new.chain }.should raise_error(NoMethodError)
+ -> { c.new.chain }.should.raise(NoMethodError)
end
it "calls prepended after prepend_features" do
@@ -663,7 +663,7 @@ describe "Module#prepend" do
module ModuleSpecs::P
prepend ModuleSpecs::P
end
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
it "doesn't accept no-arguments" do
@@ -671,7 +671,7 @@ describe "Module#prepend" do
Module.new do
prepend
end
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
it "returns the class it's included into" do
@@ -817,7 +817,7 @@ describe "Module#prepend" do
pre = Module.new
mod.prepend pre
- cls.instance_methods.should include(:foo)
+ cls.instance_methods.should.include?(:foo)
end
end
end
diff --git a/spec/ruby/core/module/prepended_spec.rb b/spec/ruby/core/module/prepended_spec.rb
index bd95d8fd05..ccd450d668 100644
--- a/spec/ruby/core/module/prepended_spec.rb
+++ b/spec/ruby/core/module/prepended_spec.rb
@@ -8,7 +8,7 @@ describe "Module#prepended" do
end
it "is a private method" do
- Module.should have_private_instance_method(:prepended, true)
+ Module.private_instance_methods(false).should.include?(:prepended)
end
it "is invoked when self is prepended to another module or class" 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..7ce07f1600 100644
--- a/spec/ruby/core/module/private_class_method_spec.rb
+++ b/spec/ruby/core/module/private_class_method_spec.rb
@@ -22,11 +22,11 @@ describe "Module#private_class_method" do
it "makes an existing class method private" do
ModuleSpecs::Parent.private_method_1.should == nil
ModuleSpecs::Parent.private_class_method :private_method_1
- -> { ModuleSpecs::Parent.private_method_1 }.should raise_error(NoMethodError)
+ -> { ModuleSpecs::Parent.private_method_1 }.should.raise(NoMethodError)
# Technically above we're testing the Singleton classes, class method(right?).
# Try a "real" class method set private.
- -> { ModuleSpecs::Parent.private_method }.should raise_error(NoMethodError)
+ -> { ModuleSpecs::Parent.private_method }.should.raise(NoMethodError)
end
it "makes an existing class method private up the inheritance tree" do
@@ -34,8 +34,8 @@ describe "Module#private_class_method" do
ModuleSpecs::Child.private_method_1.should == nil
ModuleSpecs::Child.private_class_method :private_method_1
- -> { ModuleSpecs::Child.private_method_1 }.should raise_error(NoMethodError)
- -> { ModuleSpecs::Child.private_method }.should raise_error(NoMethodError)
+ -> { ModuleSpecs::Child.private_method_1 }.should.raise(NoMethodError)
+ -> { ModuleSpecs::Child.private_method }.should.raise(NoMethodError)
end
it "accepts more than one method at a time" do
@@ -44,14 +44,14 @@ describe "Module#private_class_method" do
ModuleSpecs::Child.private_class_method :private_method_1, :private_method_2
- -> { ModuleSpecs::Child.private_method_1 }.should raise_error(NoMethodError)
- -> { ModuleSpecs::Child.private_method_2 }.should raise_error(NoMethodError)
+ -> { ModuleSpecs::Child.private_method_1 }.should.raise(NoMethodError)
+ -> { ModuleSpecs::Child.private_method_2 }.should.raise(NoMethodError)
end
it "raises a NameError if class method doesn't exist" do
-> do
ModuleSpecs.private_class_method :no_method_here
- end.should raise_error(NameError)
+ end.should.raise(NameError)
end
it "makes a class method private" do
@@ -59,7 +59,7 @@ describe "Module#private_class_method" do
def self.foo() "foo" end
private_class_method :foo
end
- -> { c.foo }.should raise_error(NoMethodError)
+ -> { c.foo }.should.raise(NoMethodError)
end
it "raises a NameError when the given name is not a method" do
@@ -67,7 +67,7 @@ describe "Module#private_class_method" do
Class.new do
private_class_method :foo
end
- end.should raise_error(NameError)
+ end.should.raise(NameError)
end
it "raises a NameError when the given name is an instance method" do
@@ -76,7 +76,7 @@ describe "Module#private_class_method" do
def foo() "foo" end
private_class_method :foo
end
- end.should raise_error(NameError)
+ end.should.raise(NameError)
end
context "when single argument is passed and is an array" do
@@ -85,7 +85,7 @@ describe "Module#private_class_method" do
def self.foo() "foo" end
private_class_method [:foo]
end
- -> { c.foo }.should raise_error(NoMethodError)
+ -> { c.foo }.should.raise(NoMethodError)
end
end
end
diff --git a/spec/ruby/core/module/private_constant_spec.rb b/spec/ruby/core/module/private_constant_spec.rb
index 3a91b3c3cd..ca0df48c0b 100644
--- a/spec/ruby/core/module/private_constant_spec.rb
+++ b/spec/ruby/core/module/private_constant_spec.rb
@@ -8,7 +8,7 @@ describe "Module#private_constant" do
-> do
cls2.send :private_constant, :Foo
- end.should raise_error(NameError)
+ end.should.raise(NameError)
end
it "accepts strings as constant names" do
@@ -16,7 +16,7 @@ describe "Module#private_constant" do
cls.const_set :Foo, true
cls.send :private_constant, "Foo"
- -> { cls::Foo }.should raise_error(NameError)
+ -> { cls::Foo }.should.raise(NameError)
end
it "accepts multiple names" do
@@ -26,7 +26,7 @@ describe "Module#private_constant" do
mod.send :private_constant, :Foo, :Bar
- -> {mod::Foo}.should raise_error(NameError)
- -> {mod::Bar}.should raise_error(NameError)
+ -> {mod::Foo}.should.raise(NameError)
+ -> {mod::Bar}.should.raise(NameError)
end
end
diff --git a/spec/ruby/core/module/private_instance_methods_spec.rb b/spec/ruby/core/module/private_instance_methods_spec.rb
index cce0f001bf..ae0f21d1dd 100644
--- a/spec/ruby/core/module/private_instance_methods_spec.rb
+++ b/spec/ruby/core/module/private_instance_methods_spec.rb
@@ -5,20 +5,20 @@ require_relative '../../fixtures/reflection'
# TODO: rewrite
describe "Module#private_instance_methods" do
it "returns a list of private methods in module and its ancestors" do
- ModuleSpecs::CountsMixin.should have_private_instance_method(:private_3)
+ ModuleSpecs::CountsMixin.private_instance_methods(false).should.include?(:private_3)
- ModuleSpecs::CountsParent.should have_private_instance_method(:private_2)
- ModuleSpecs::CountsParent.should have_private_instance_method(:private_3)
+ ModuleSpecs::CountsParent.private_instance_methods(false).should.include?(:private_2)
+ ModuleSpecs::CountsParent.private_instance_methods(true).should.include?(:private_3)
- ModuleSpecs::CountsChild.should have_private_instance_method(:private_1)
- ModuleSpecs::CountsChild.should have_private_instance_method(:private_2)
- ModuleSpecs::CountsChild.should have_private_instance_method(:private_3)
+ ModuleSpecs::CountsChild.private_instance_methods(false).should.include?(:private_1)
+ ModuleSpecs::CountsChild.private_instance_methods(true).should.include?(:private_2)
+ ModuleSpecs::CountsChild.private_instance_methods(true).should.include?(:private_3)
end
it "when passed false as a parameter, should return only methods defined in that module" do
- ModuleSpecs::CountsMixin.should have_private_instance_method(:private_3, false)
- ModuleSpecs::CountsParent.should have_private_instance_method(:private_2, false)
- ModuleSpecs::CountsChild.should have_private_instance_method(:private_1, false)
+ ModuleSpecs::CountsMixin.private_instance_methods(false).should.include?(:private_3)
+ ModuleSpecs::CountsParent.private_instance_methods(false).should.include?(:private_2)
+ ModuleSpecs::CountsChild.private_instance_methods(false).should.include?(:private_1)
end
it "default list should be the same as passing true as an argument" do
diff --git a/spec/ruby/core/module/private_method_defined_spec.rb b/spec/ruby/core/module/private_method_defined_spec.rb
index 01fc8f8fb9..f730decc0a 100644
--- a/spec/ruby/core/module/private_method_defined_spec.rb
+++ b/spec/ruby/core/module/private_method_defined_spec.rb
@@ -34,25 +34,25 @@ describe "Module#private_method_defined?" do
it "raises a TypeError if passed an Integer" do
-> do
ModuleSpecs::CountsMixin.private_method_defined?(1)
- end.should raise_error(TypeError)
+ end.should.raise(TypeError)
end
it "raises a TypeError if passed nil" do
-> do
ModuleSpecs::CountsMixin.private_method_defined?(nil)
- end.should raise_error(TypeError)
+ end.should.raise(TypeError)
end
it "raises a TypeError if passed false" do
-> do
ModuleSpecs::CountsMixin.private_method_defined?(false)
- end.should raise_error(TypeError)
+ end.should.raise(TypeError)
end
it "raises a TypeError if passed an object that does not defined #to_str" do
-> do
ModuleSpecs::CountsMixin.private_method_defined?(mock('x'))
- end.should raise_error(TypeError)
+ end.should.raise(TypeError)
end
it "raises a TypeError if passed an object that defines #to_sym" do
@@ -61,7 +61,7 @@ describe "Module#private_method_defined?" do
-> do
ModuleSpecs::CountsMixin.private_method_defined?(sym)
- end.should raise_error(TypeError)
+ end.should.raise(TypeError)
end
it "calls #to_str to convert an Object" do
diff --git a/spec/ruby/core/module/private_spec.rb b/spec/ruby/core/module/private_spec.rb
index 9e1a297eea..e60fdb24cc 100644
--- a/spec/ruby/core/module/private_spec.rb
+++ b/spec/ruby/core/module/private_spec.rb
@@ -17,7 +17,7 @@ describe "Module#private" do
private :foo
end
- -> { obj.foo }.should raise_error(NoMethodError)
+ -> { obj.foo }.should.raise(NoMethodError)
end
it "makes a public Object instance method private in a new module" do
@@ -25,33 +25,33 @@ describe "Module#private" do
private :module_specs_public_method_on_object
end
- m.should have_private_instance_method(:module_specs_public_method_on_object)
+ m.private_instance_methods(false).should.include?(:module_specs_public_method_on_object)
# Ensure we did not change Object's method
- Object.should_not have_private_instance_method(:module_specs_public_method_on_object)
+ Object.private_instance_methods(true).should_not.include?(:module_specs_public_method_on_object)
end
it "makes a public Object instance method private in Kernel" do
- Kernel.should have_private_instance_method(
+ Kernel.private_instance_methods(false).should.include?(
:module_specs_public_method_on_object_for_kernel_private)
- Object.should_not have_private_instance_method(
+ Object.private_instance_methods(true).should_not.include?(
:module_specs_public_method_on_object_for_kernel_private)
end
it "returns argument or arguments if given" do
(class << Object.new; self; end).class_eval do
def foo; end
- private(:foo).should equal(:foo)
+ private(:foo).should.equal?(:foo)
private([:foo, :foo]).should == [:foo, :foo]
private(:foo, :foo).should == [:foo, :foo]
- private.should equal(nil)
+ private.should.equal?(nil)
end
end
it "raises a NameError when given an undefined name" do
-> do
Module.new.send(:private, :undefined)
- end.should raise_error(NameError)
+ end.should.raise(NameError)
end
it "only makes the method private in the class it is called on" do
@@ -71,7 +71,7 @@ describe "Module#private" do
base.new.wrapped.should == 1
-> do
klass.new.wrapped
- end.should raise_error(NameError)
+ end.should.raise(NameError)
end
it "continues to allow a prepended module method to call super" do
diff --git a/spec/ruby/core/module/protected_instance_methods_spec.rb b/spec/ruby/core/module/protected_instance_methods_spec.rb
index 78ce7e788f..ea7ded030e 100644
--- a/spec/ruby/core/module/protected_instance_methods_spec.rb
+++ b/spec/ruby/core/module/protected_instance_methods_spec.rb
@@ -6,16 +6,16 @@ require_relative '../../fixtures/reflection'
describe "Module#protected_instance_methods" do
it "returns a list of protected methods in module and its ancestors" do
methods = ModuleSpecs::CountsMixin.protected_instance_methods
- methods.should include(:protected_3)
+ methods.should.include?(:protected_3)
methods = ModuleSpecs::CountsParent.protected_instance_methods
- methods.should include(:protected_3)
- methods.should include(:protected_2)
+ methods.should.include?(:protected_3)
+ methods.should.include?(:protected_2)
methods = ModuleSpecs::CountsChild.protected_instance_methods
- methods.should include(:protected_3)
- methods.should include(:protected_2)
- methods.should include(:protected_1)
+ methods.should.include?(:protected_3)
+ methods.should.include?(:protected_2)
+ methods.should.include?(:protected_1)
end
it "when passed false as a parameter, should return only methods defined in that module" do
diff --git a/spec/ruby/core/module/protected_method_defined_spec.rb b/spec/ruby/core/module/protected_method_defined_spec.rb
index 31e24a16c1..78ba120c2f 100644
--- a/spec/ruby/core/module/protected_method_defined_spec.rb
+++ b/spec/ruby/core/module/protected_method_defined_spec.rb
@@ -34,25 +34,25 @@ describe "Module#protected_method_defined?" do
it "raises a TypeError if passed an Integer" do
-> do
ModuleSpecs::CountsMixin.protected_method_defined?(1)
- end.should raise_error(TypeError)
+ end.should.raise(TypeError)
end
it "raises a TypeError if passed nil" do
-> do
ModuleSpecs::CountsMixin.protected_method_defined?(nil)
- end.should raise_error(TypeError)
+ end.should.raise(TypeError)
end
it "raises a TypeError if passed false" do
-> do
ModuleSpecs::CountsMixin.protected_method_defined?(false)
- end.should raise_error(TypeError)
+ end.should.raise(TypeError)
end
it "raises a TypeError if passed an object that does not defined #to_str" do
-> do
ModuleSpecs::CountsMixin.protected_method_defined?(mock('x'))
- end.should raise_error(TypeError)
+ end.should.raise(TypeError)
end
it "raises a TypeError if passed an object that defines #to_sym" do
@@ -61,7 +61,7 @@ describe "Module#protected_method_defined?" do
-> do
ModuleSpecs::CountsMixin.protected_method_defined?(sym)
- end.should raise_error(TypeError)
+ end.should.raise(TypeError)
end
it "calls #to_str to convert an Object" do
diff --git a/spec/ruby/core/module/protected_spec.rb b/spec/ruby/core/module/protected_spec.rb
index 9e37223e18..3ef6c76fae 100644
--- a/spec/ruby/core/module/protected_spec.rb
+++ b/spec/ruby/core/module/protected_spec.rb
@@ -18,7 +18,7 @@ describe "Module#protected" do
protected :protected_method_1
end
- -> { ModuleSpecs::Parent.protected_method_1 }.should raise_error(NoMethodError)
+ -> { ModuleSpecs::Parent.protected_method_1 }.should.raise(NoMethodError)
end
it "makes a public Object instance method protected in a new module" do
@@ -26,32 +26,32 @@ describe "Module#protected" do
protected :module_specs_public_method_on_object
end
- m.should have_protected_instance_method(:module_specs_public_method_on_object)
+ m.protected_instance_methods(false).should.include?(:module_specs_public_method_on_object)
# Ensure we did not change Object's method
- Object.should_not have_protected_instance_method(:module_specs_public_method_on_object)
+ Object.protected_instance_methods(true).should_not.include?(:module_specs_public_method_on_object)
end
it "makes a public Object instance method protected in Kernel" do
- Kernel.should have_protected_instance_method(
+ Kernel.protected_instance_methods(false).should.include?(
:module_specs_public_method_on_object_for_kernel_protected)
- Object.should_not have_protected_instance_method(
+ Object.protected_instance_methods(true).should_not.include?(
:module_specs_public_method_on_object_for_kernel_protected)
end
it "returns argument or arguments if given" do
(class << Object.new; self; end).class_eval do
def foo; end
- protected(:foo).should equal(:foo)
+ protected(:foo).should.equal?(:foo)
protected([:foo, :foo]).should == [:foo, :foo]
protected(:foo, :foo).should == [:foo, :foo]
- protected.should equal(nil)
+ protected.should.equal?(nil)
end
end
it "raises a NameError when given an undefined name" do
-> do
Module.new.send(:protected, :undefined)
- end.should raise_error(NameError)
+ end.should.raise(NameError)
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..4aca4d4311 100644
--- a/spec/ruby/core/module/public_class_method_spec.rb
+++ b/spec/ruby/core/module/public_class_method_spec.rb
@@ -18,7 +18,7 @@ describe "Module#public_class_method" do
end
it "makes an existing class method public" do
- -> { ModuleSpecs::Parent.public_method_1 }.should raise_error(NoMethodError)
+ -> { ModuleSpecs::Parent.public_method_1 }.should.raise(NoMethodError)
ModuleSpecs::Parent.public_class_method :public_method_1
ModuleSpecs::Parent.public_method_1.should == nil
@@ -29,7 +29,7 @@ describe "Module#public_class_method" do
it "makes an existing class method public up the inheritance tree" do
ModuleSpecs::Child.private_class_method :public_method_1
- -> { ModuleSpecs::Child.public_method_1 }.should raise_error(NoMethodError)
+ -> { ModuleSpecs::Child.public_method_1 }.should.raise(NoMethodError)
ModuleSpecs::Child.public_class_method :public_method_1
ModuleSpecs::Child.public_method_1.should == nil
@@ -37,8 +37,8 @@ describe "Module#public_class_method" do
end
it "accepts more than one method at a time" do
- -> { ModuleSpecs::Parent.public_method_1 }.should raise_error(NameError)
- -> { ModuleSpecs::Parent.public_method_2 }.should raise_error(NameError)
+ -> { ModuleSpecs::Parent.public_method_1 }.should.raise(NameError)
+ -> { ModuleSpecs::Parent.public_method_2 }.should.raise(NameError)
ModuleSpecs::Child.public_class_method :public_method_1, :public_method_2
@@ -49,7 +49,7 @@ describe "Module#public_class_method" do
it "raises a NameError if class method doesn't exist" do
-> do
ModuleSpecs.public_class_method :no_method_here
- end.should raise_error(NameError)
+ end.should.raise(NameError)
end
it "makes a class method public" do
@@ -66,7 +66,7 @@ describe "Module#public_class_method" do
Class.new do
public_class_method :foo
end
- end.should raise_error(NameError)
+ end.should.raise(NameError)
end
it "raises a NameError when the given name is an instance method" do
@@ -75,7 +75,7 @@ describe "Module#public_class_method" do
def foo() "foo" end
public_class_method :foo
end
- end.should raise_error(NameError)
+ end.should.raise(NameError)
end
context "when single argument is passed and is an array" do
diff --git a/spec/ruby/core/module/public_constant_spec.rb b/spec/ruby/core/module/public_constant_spec.rb
index e624d45fd2..87a051f125 100644
--- a/spec/ruby/core/module/public_constant_spec.rb
+++ b/spec/ruby/core/module/public_constant_spec.rb
@@ -8,7 +8,7 @@ describe "Module#public_constant" do
-> do
cls2.send :public_constant, :Foo
- end.should raise_error(NameError)
+ end.should.raise(NameError)
end
it "accepts strings as constant names" do
diff --git a/spec/ruby/core/module/public_instance_method_spec.rb b/spec/ruby/core/module/public_instance_method_spec.rb
index ba19ad0404..87c1bae599 100644
--- a/spec/ruby/core/module/public_instance_method_spec.rb
+++ b/spec/ruby/core/module/public_instance_method_spec.rb
@@ -3,7 +3,7 @@ require_relative 'fixtures/classes'
describe "Module#public_instance_method" do
it "is a public method" do
- Module.should have_public_instance_method(:public_instance_method, false)
+ Module.public_instance_methods(false).should.include?(:public_instance_method)
end
it "requires an argument" do
@@ -13,12 +13,12 @@ describe "Module#public_instance_method" do
describe "when given a public method name" do
it "returns an UnboundMethod corresponding to the defined Module" do
ret = ModuleSpecs::Super.public_instance_method(:public_module)
- ret.should be_an_instance_of(UnboundMethod)
- ret.owner.should equal(ModuleSpecs::Basic)
+ ret.should.instance_of?(UnboundMethod)
+ ret.owner.should.equal?(ModuleSpecs::Basic)
ret = ModuleSpecs::Super.public_instance_method(:public_super_module)
- ret.should be_an_instance_of(UnboundMethod)
- ret.owner.should equal(ModuleSpecs::Super)
+ ret.should.instance_of?(UnboundMethod)
+ ret.owner.should.equal?(ModuleSpecs::Super)
end
it "accepts if the name is a Symbol or String" do
@@ -28,31 +28,31 @@ describe "Module#public_instance_method" do
end
it "raises a TypeError when given a name is not Symbol or String" do
- -> { Module.new.public_instance_method(nil) }.should raise_error(TypeError)
+ -> { Module.new.public_instance_method(nil) }.should.raise(TypeError)
end
it "raises a NameError when given a protected method name" do
-> do
ModuleSpecs::Basic.public_instance_method(:protected_module)
- end.should raise_error(NameError)
+ end.should.raise(NameError)
end
it "raises a NameError if the method is private" do
-> do
ModuleSpecs::Basic.public_instance_method(:private_module)
- end.should raise_error(NameError)
+ end.should.raise(NameError)
end
it "raises a NameError if the method has been undefined" do
-> do
ModuleSpecs::Parent.public_instance_method(:undefed_method)
- end.should raise_error(NameError)
+ end.should.raise(NameError)
end
it "raises a NameError if the method does not exist" do
-> do
Module.new.public_instance_method(:missing)
- end.should raise_error(NameError)
+ end.should.raise(NameError)
end
it "sets the NameError#name attribute to the name of the missing method" do
diff --git a/spec/ruby/core/module/public_instance_methods_spec.rb b/spec/ruby/core/module/public_instance_methods_spec.rb
index ae7d9b5ffb..edea00d927 100644
--- a/spec/ruby/core/module/public_instance_methods_spec.rb
+++ b/spec/ruby/core/module/public_instance_methods_spec.rb
@@ -7,19 +7,19 @@ require_relative '../../fixtures/reflection'
describe "Module#public_instance_methods" do
it "returns a list of public methods in module and its ancestors" do
methods = ModuleSpecs::CountsMixin.public_instance_methods
- methods.should include(:public_3)
+ methods.should.include?(:public_3)
methods = ModuleSpecs::CountsParent.public_instance_methods
- methods.should include(:public_3)
- methods.should include(:public_2)
+ methods.should.include?(:public_3)
+ methods.should.include?(:public_2)
methods = ModuleSpecs::CountsChild.public_instance_methods
- methods.should include(:public_3)
- methods.should include(:public_2)
- methods.should include(:public_1)
+ methods.should.include?(:public_3)
+ methods.should.include?(:public_2)
+ methods.should.include?(:public_1)
methods = ModuleSpecs::Child2.public_instance_methods
- methods.should include(:foo)
+ methods.should.include?(:foo)
end
it "when passed false as a parameter, should return only methods defined in that module" do
diff --git a/spec/ruby/core/module/public_method_defined_spec.rb b/spec/ruby/core/module/public_method_defined_spec.rb
index 5c9bdf1ccc..70cd992358 100644
--- a/spec/ruby/core/module/public_method_defined_spec.rb
+++ b/spec/ruby/core/module/public_method_defined_spec.rb
@@ -34,25 +34,25 @@ describe "Module#public_method_defined?" do
it "raises a TypeError if passed an Integer" do
-> do
ModuleSpecs::CountsMixin.public_method_defined?(1)
- end.should raise_error(TypeError)
+ end.should.raise(TypeError)
end
it "raises a TypeError if passed nil" do
-> do
ModuleSpecs::CountsMixin.public_method_defined?(nil)
- end.should raise_error(TypeError)
+ end.should.raise(TypeError)
end
it "raises a TypeError if passed false" do
-> do
ModuleSpecs::CountsMixin.public_method_defined?(false)
- end.should raise_error(TypeError)
+ end.should.raise(TypeError)
end
it "raises a TypeError if passed an object that does not defined #to_str" do
-> do
ModuleSpecs::CountsMixin.public_method_defined?(mock('x'))
- end.should raise_error(TypeError)
+ end.should.raise(TypeError)
end
it "raises a TypeError if passed an object that defines #to_sym" do
@@ -61,7 +61,7 @@ describe "Module#public_method_defined?" do
-> do
ModuleSpecs::CountsMixin.public_method_defined?(sym)
- end.should raise_error(TypeError)
+ end.should.raise(TypeError)
end
it "calls #to_str to convert an Object" do
diff --git a/spec/ruby/core/module/public_spec.rb b/spec/ruby/core/module/public_spec.rb
index ce31eb5d0e..f35c64143b 100644
--- a/spec/ruby/core/module/public_spec.rb
+++ b/spec/ruby/core/module/public_spec.rb
@@ -14,32 +14,32 @@ describe "Module#public" do
public :module_specs_private_method_on_object
end
- m.should have_public_instance_method(:module_specs_private_method_on_object)
+ m.public_instance_methods(false).should.include?(:module_specs_private_method_on_object)
# Ensure we did not change Object's method
- Object.should_not have_public_instance_method(:module_specs_private_method_on_object)
+ Object.public_instance_methods(true).should_not.include?(:module_specs_private_method_on_object)
end
it "makes a private Object instance method public in Kernel" do
- Kernel.should have_public_instance_method(
+ Kernel.public_instance_methods(false).should.include?(
:module_specs_private_method_on_object_for_kernel_public)
- Object.should_not have_public_instance_method(
+ Object.public_instance_methods(true).should_not.include?(
:module_specs_private_method_on_object_for_kernel_public)
end
it "returns argument or arguments if given" do
(class << Object.new; self; end).class_eval do
def foo; end
- public(:foo).should equal(:foo)
+ public(:foo).should.equal?(:foo)
public([:foo, :foo]).should == [:foo, :foo]
public(:foo, :foo).should == [:foo, :foo]
- public.should equal(nil)
+ public.should.equal?(nil)
end
end
it "raises a NameError when given an undefined name" do
-> do
Module.new.send(:public, :undefined)
- end.should raise_error(NameError)
+ end.should.raise(NameError)
end
end
diff --git a/spec/ruby/core/module/refine_spec.rb b/spec/ruby/core/module/refine_spec.rb
index d219b98825..d0fc7015f8 100644
--- a/spec/ruby/core/module/refine_spec.rb
+++ b/spec/ruby/core/module/refine_spec.rb
@@ -11,7 +11,7 @@ describe "Module#refine" do
end
mod.should_not == inner_self
- inner_self.should be_kind_of(Module)
+ inner_self.should.is_a?(Module)
inner_self.name.should == nil
end
@@ -43,7 +43,7 @@ describe "Module#refine" do
end
end
- inner_self.public_instance_methods.should include(:blah)
+ inner_self.public_instance_methods.should.include?(:blah)
end
it "returns created anonymous module" do
@@ -63,7 +63,7 @@ describe "Module#refine" do
Module.new do
refine {}
end
- end.should raise_error(ArgumentError)
+ end.should.raise(ArgumentError)
end
it "raises TypeError if not passed a class" do
@@ -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(TypeError, "wrong argument type String (expected Class or Module)")
end
it "accepts a module as argument" do
@@ -84,7 +84,7 @@ describe "Module#refine" do
end
end
- inner_self.public_instance_methods.should include(:blah)
+ inner_self.public_instance_methods.should.include?(:blah)
end
it "applies refinements to the module" do
@@ -117,7 +117,7 @@ describe "Module#refine" do
Module.new do
refine String
end
- end.should raise_error(ArgumentError)
+ end.should.raise(ArgumentError)
end
it "applies refinements to calls in the refine block" do
@@ -136,7 +136,7 @@ describe "Module#refine" do
refine(String) {def foo; "foo"; end}
-> {
"hello".foo
- }.should raise_error(NoMethodError)
+ }.should.raise(NoMethodError)
end
end
@@ -145,7 +145,7 @@ describe "Module#refine" do
refine(String) {def foo; 'foo'; end}
end
- -> {"hello".foo}.should raise_error(NoMethodError)
+ -> {"hello".foo}.should.raise(NoMethodError)
end
# When defining multiple refinements in the same module,
@@ -209,7 +209,7 @@ describe "Module#refine" do
[1, 2].to_json_format
end
- }.should raise_error(NoMethodError)
+ }.should.raise(NoMethodError)
end
# method lookup:
@@ -596,7 +596,7 @@ describe "Module#refine" do
using refinement_with_super
-> {
refined_class.new.bar
- }.should raise_error(NoMethodError)
+ }.should.raise(NoMethodError)
end
end
end
@@ -610,7 +610,7 @@ describe "Module#refine" do
}
[1,2].orig_count.should == 2
end
- -> { [1,2].orig_count }.should raise_error(NoMethodError)
+ -> { [1,2].orig_count }.should.raise(NoMethodError)
end
it 'and alias_method aliases a method within a refinement module, but not outside it' do
@@ -622,7 +622,7 @@ describe "Module#refine" do
}
[1,2].orig_count.should == 2
end
- -> { [1,2].orig_count }.should raise_error(NoMethodError)
+ -> { [1,2].orig_count }.should.raise(NoMethodError)
end
it "and instance_methods returns a list of methods including those of the refined module" do
@@ -704,11 +704,10 @@ describe "Module#refine" do
end
end
end
- spec = self
- klass = Class.new { instance_methods.should_not spec.send(:include, :refinement_only_method) }
+ klass = Class.new { instance_methods.should_not.include?(:refinement_only_method) }
instance = klass.new
- instance.methods.should_not include :refinement_only_method
+ instance.methods.should_not.include? :refinement_only_method
instance.respond_to?(:refinement_only_method).should == false
- -> { instance.method :refinement_only_method }.should raise_error(NameError)
+ -> { instance.method :refinement_only_method }.should.raise(NameError)
end
end
diff --git a/spec/ruby/core/module/remove_class_variable_spec.rb b/spec/ruby/core/module/remove_class_variable_spec.rb
index ab9514adf6..fccb29f52d 100644
--- a/spec/ruby/core/module/remove_class_variable_spec.rb
+++ b/spec/ruby/core/module/remove_class_variable_spec.rb
@@ -18,27 +18,27 @@ describe "Module#remove_class_variable" do
meta = obj.singleton_class
meta.send :class_variable_set, :@@var, 1
meta.send(:remove_class_variable, :@@var).should == 1
- meta.class_variable_defined?(:@@var).should be_false
+ meta.class_variable_defined?(:@@var).should == false
end
it "raises a NameError when removing class variable declared in included module" do
c = ModuleSpecs::RemoveClassVariable.new { include ModuleSpecs::MVars.dup }
- -> { c.send(:remove_class_variable, :@@mvar) }.should raise_error(NameError)
+ -> { c.send(:remove_class_variable, :@@mvar) }.should.raise(NameError)
end
it "raises a NameError when passed a symbol with one leading @" do
- -> { ModuleSpecs::MVars.send(:remove_class_variable, :@mvar) }.should raise_error(NameError)
+ -> { ModuleSpecs::MVars.send(:remove_class_variable, :@mvar) }.should.raise(NameError)
end
it "raises a NameError when passed a symbol with no leading @" do
- -> { ModuleSpecs::MVars.send(:remove_class_variable, :mvar) }.should raise_error(NameError)
+ -> { ModuleSpecs::MVars.send(:remove_class_variable, :mvar) }.should.raise(NameError)
end
it "raises a NameError when an uninitialized class variable is given" do
- -> { ModuleSpecs::MVars.send(:remove_class_variable, :@@nonexisting_class_variable) }.should raise_error(NameError)
+ -> { ModuleSpecs::MVars.send(:remove_class_variable, :@@nonexisting_class_variable) }.should.raise(NameError)
end
it "is public" do
- Module.should_not have_private_instance_method(:remove_class_variable)
+ Module.private_instance_methods(true).should_not.include?(:remove_class_variable)
end
end
diff --git a/spec/ruby/core/module/remove_const_spec.rb b/spec/ruby/core/module/remove_const_spec.rb
index 35a9d65105..4e4b9fcb45 100644
--- a/spec/ruby/core/module/remove_const_spec.rb
+++ b/spec/ruby/core/module/remove_const_spec.rb
@@ -7,13 +7,13 @@ describe "Module#remove_const" do
ConstantSpecs::ModuleM::CS_CONST252.should == :const252
ConstantSpecs::ModuleM.send :remove_const, :CS_CONST252
- -> { ConstantSpecs::ModuleM::CS_CONST252 }.should raise_error(NameError)
+ -> { ConstantSpecs::ModuleM::CS_CONST252 }.should.raise(NameError)
ConstantSpecs::ModuleM::CS_CONST253 = :const253
ConstantSpecs::ModuleM::CS_CONST253.should == :const253
ConstantSpecs::ModuleM.send :remove_const, "CS_CONST253"
- -> { ConstantSpecs::ModuleM::CS_CONST253 }.should raise_error(NameError)
+ -> { ConstantSpecs::ModuleM::CS_CONST253 }.should.raise(NameError)
end
it "returns the value of the removed constant" do
@@ -23,7 +23,7 @@ describe "Module#remove_const" do
it "raises a NameError and does not call #const_missing if the constant is not defined" do
ConstantSpecs.should_not_receive(:const_missing)
- -> { ConstantSpecs.send(:remove_const, :Nonexistent) }.should raise_error(NameError)
+ -> { ConstantSpecs.send(:remove_const, :Nonexistent) }.should.raise(NameError)
end
it "raises a NameError and does not call #const_missing if the constant is not defined directly in the module" do
@@ -34,28 +34,28 @@ describe "Module#remove_const" do
-> do
ConstantSpecs::ContainerA.send :remove_const, :CS_CONST255
- end.should raise_error(NameError)
+ end.should.raise(NameError)
ensure
ConstantSpecs::ModuleM.send :remove_const, "CS_CONST255"
end
end
it "raises a NameError if the name does not start with a capital letter" do
- -> { ConstantSpecs.send :remove_const, "name" }.should raise_error(NameError)
+ -> { ConstantSpecs.send :remove_const, "name" }.should.raise(NameError)
end
it "raises a NameError if the name starts with a non-alphabetic character" do
- -> { ConstantSpecs.send :remove_const, "__CONSTX__" }.should raise_error(NameError)
- -> { ConstantSpecs.send :remove_const, "@Name" }.should raise_error(NameError)
- -> { ConstantSpecs.send :remove_const, "!Name" }.should raise_error(NameError)
- -> { ConstantSpecs.send :remove_const, "::Name" }.should raise_error(NameError)
+ -> { ConstantSpecs.send :remove_const, "__CONSTX__" }.should.raise(NameError)
+ -> { ConstantSpecs.send :remove_const, "@Name" }.should.raise(NameError)
+ -> { ConstantSpecs.send :remove_const, "!Name" }.should.raise(NameError)
+ -> { ConstantSpecs.send :remove_const, "::Name" }.should.raise(NameError)
end
it "raises a NameError if the name contains non-alphabetic characters except '_'" do
ConstantSpecs::ModuleM::CS_CONST256 = :const256
ConstantSpecs::ModuleM.send :remove_const, "CS_CONST256"
- -> { ConstantSpecs.send :remove_const, "Name=" }.should raise_error(NameError)
- -> { ConstantSpecs.send :remove_const, "Name?" }.should raise_error(NameError)
+ -> { ConstantSpecs.send :remove_const, "Name=" }.should.raise(NameError)
+ -> { ConstantSpecs.send :remove_const, "Name?" }.should.raise(NameError)
end
it "calls #to_str to convert the given name to a String" do
@@ -67,19 +67,19 @@ describe "Module#remove_const" do
it "raises a TypeError if conversion to a String by calling #to_str fails" do
name = mock('123')
- -> { ConstantSpecs.send :remove_const, name }.should raise_error(TypeError)
+ -> { ConstantSpecs.send :remove_const, name }.should.raise(TypeError)
name.should_receive(:to_str).and_return(123)
- -> { ConstantSpecs.send :remove_const, name }.should raise_error(TypeError)
+ -> { ConstantSpecs.send :remove_const, name }.should.raise(TypeError)
end
it "is a private method" do
- Module.private_methods.should include(:remove_const)
+ Module.private_methods.should.include?(:remove_const)
end
it "returns nil when removing autoloaded constant" do
ConstantSpecs.autoload :AutoloadedConstant, 'a_file'
- ConstantSpecs.send(:remove_const, :AutoloadedConstant).should be_nil
+ ConstantSpecs.send(:remove_const, :AutoloadedConstant).should == nil
end
it "updates the constant value" do
diff --git a/spec/ruby/core/module/remove_method_spec.rb b/spec/ruby/core/module/remove_method_spec.rb
index 94b255df62..39add01e36 100644
--- a/spec/ruby/core/module/remove_method_spec.rb
+++ b/spec/ruby/core/module/remove_method_spec.rb
@@ -21,7 +21,7 @@ describe "Module#remove_method" do
end
it "is a public method" do
- Module.should have_public_instance_method(:remove_method, false)
+ Module.public_instance_methods(false).should.include?(:remove_method)
end
it "removes the method from a class" do
@@ -88,14 +88,14 @@ describe "Module#remove_method" do
end
it "returns self" do
- @module.send(:remove_method, :method_to_remove).should equal(@module)
+ @module.send(:remove_method, :method_to_remove).should.equal?(@module)
end
it "raises a NameError when attempting to remove method further up the inheritance tree" do
Class.new(ModuleSpecs::Second) do
-> {
remove_method :method_to_remove
- }.should raise_error(NameError)
+ }.should.raise(NameError)
end
end
@@ -103,7 +103,7 @@ describe "Module#remove_method" do
Class.new(ModuleSpecs::Second) do
-> {
remove_method :blah
- }.should raise_error(NameError)
+ }.should.raise(NameError)
end
end
@@ -113,19 +113,19 @@ describe "Module#remove_method" do
end
it "raises a FrozenError when passed a name" do
- -> { @frozen.send :remove_method, :method_to_remove }.should raise_error(FrozenError)
+ -> { @frozen.send :remove_method, :method_to_remove }.should.raise(FrozenError)
end
it "raises a FrozenError when passed a missing name" do
- -> { @frozen.send :remove_method, :not_exist }.should raise_error(FrozenError)
+ -> { @frozen.send :remove_method, :not_exist }.should.raise(FrozenError)
end
it "raises a TypeError when passed a not name" do
- -> { @frozen.send :remove_method, Object.new }.should raise_error(TypeError)
+ -> { @frozen.send :remove_method, Object.new }.should.raise(TypeError)
end
it "does not raise exceptions when no arguments given" do
- @frozen.send(:remove_method).should equal(@frozen)
+ @frozen.send(:remove_method).should.equal?(@frozen)
end
end
end
diff --git a/spec/ruby/core/module/ruby2_keywords_spec.rb b/spec/ruby/core/module/ruby2_keywords_spec.rb
index 73b4ba62fa..e392642978 100644
--- a/spec/ruby/core/module/ruby2_keywords_spec.rb
+++ b/spec/ruby/core/module/ruby2_keywords_spec.rb
@@ -175,7 +175,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(NameError, /undefined method [`']not_existing'/)
end
it "accepts String as well" do
@@ -197,7 +197,7 @@ describe "Module#ruby2_keywords" do
obj.singleton_class.class_exec do
ruby2_keywords Object.new
end
- }.should raise_error(TypeError, /is not a symbol nor a string/)
+ }.should.raise(TypeError, /is not a symbol nor a string/)
end
it "prints warning when a method does not accept argument splat" do
@@ -233,7 +233,7 @@ describe "Module#ruby2_keywords" do
}.should complain(/Skipping set of ruby2_keywords flag for/)
end
- ruby_version_is "3.5" do
+ ruby_version_is "4.0" do
it "prints warning when a method accepts post arguments" do
obj = Object.new
def obj.foo(*a, b) end
diff --git a/spec/ruby/core/module/set_temporary_name_spec.rb b/spec/ruby/core/module/set_temporary_name_spec.rb
index 12c1c214dd..7c159121fa 100644
--- a/spec/ruby/core/module/set_temporary_name_spec.rb
+++ b/spec/ruby/core/module/set_temporary_name_spec.rb
@@ -1,146 +1,145 @@
require_relative '../../spec_helper'
require_relative 'fixtures/set_temporary_name'
-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
+describe "Module#set_temporary_name" do
+ it "can assign a temporary name" do
+ m = Module.new
+ m.name.should == nil
- m.set_temporary_name("fake_name")
- m.name.should == "fake_name"
+ m.set_temporary_name("fake_name")
+ m.name.should == "fake_name"
- m.set_temporary_name(nil)
- m.name.should be_nil
- end
+ m.set_temporary_name(nil)
+ m.name.should == nil
+ end
- it "returns self" do
- m = Module.new
- m.set_temporary_name("fake_name").should.equal? m
- end
+ it "returns self" do
+ m = Module.new
+ m.set_temporary_name("fake_name").should.equal? m
+ end
- it "can assign a temporary name which is not a valid constant path" do
- m = Module.new
+ it "can assign a temporary name which is not a valid constant path" do
+ m = Module.new
- m.set_temporary_name("name")
- m.name.should == "name"
+ m.set_temporary_name("name")
+ m.name.should == "name"
- m.set_temporary_name("Template['foo.rb']")
- m.name.should == "Template['foo.rb']"
+ m.set_temporary_name("Template['foo.rb']")
+ m.name.should == "Template['foo.rb']"
- m.set_temporary_name("a::B")
- m.name.should == "a::B"
+ m.set_temporary_name("a::B")
+ m.name.should == "a::B"
- m.set_temporary_name("A::b")
- m.name.should == "A::b"
+ m.set_temporary_name("A::b")
+ m.name.should == "A::b"
- m.set_temporary_name("A::B::")
- m.name.should == "A::B::"
+ m.set_temporary_name("A::B::")
+ m.name.should == "A::B::"
- m.set_temporary_name("A::::B")
- m.name.should == "A::::B"
+ m.set_temporary_name("A::::B")
+ m.name.should == "A::::B"
- m.set_temporary_name("A=")
- m.name.should == "A="
- end
+ m.set_temporary_name("A=")
+ m.name.should == "A="
+ 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 empty string as name" do
+ m = Module.new
+ -> { m.set_temporary_name("") }.should.raise(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 name as a temporary name" do
+ m = Module.new
+ -> { m.set_temporary_name("Object") }.should.raise(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 a constant path as a temporary name" do
+ m = Module.new
+ -> { m.set_temporary_name("A::B") }.should.raise(ArgumentError, "the temporary name must not be a constant path to avoid confusion")
+ -> { m.set_temporary_name("::A") }.should.raise(ArgumentError, "the temporary name must not be a constant path to avoid confusion")
+ -> { m.set_temporary_name("::A::B") }.should.raise(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't assign name to permanent module" do
+ -> { Object.set_temporary_name("fake_name") }.should.raise(RuntimeError, "can't change permanent name")
+ end
- it "can assign a temporary name to a module nested into an anonymous module" do
- m = Module.new
- module m::N; end
- m::N.name.should =~ /\A#<Module:0x\h+>::N\z/
+ it "can assign a temporary name to a module nested into an anonymous 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("fake_name")
+ m::N.name.should == "fake_name"
- m::N.set_temporary_name(nil)
- m::N.name.should be_nil
- end
+ m::N.set_temporary_name(nil)
+ m::N.name.should == nil
+ end
- it "discards a temporary name when an outer anonymous module gets a permanent name" do
- m = Module.new
- module m::N; end
+ it "discards a temporary name when an outer anonymous module gets a permanent name" do
+ m = Module.new
+ module m::N; end
- m::N.set_temporary_name("fake_name")
- m::N.name.should == "fake_name"
+ m::N.set_temporary_name("fake_name")
+ m::N.name.should == "fake_name"
- ModuleSpecs::SetTemporaryNameSpec::M = m
- m::N.name.should == "ModuleSpecs::SetTemporaryNameSpec::M::N"
- end
+ ModuleSpecs::SetTemporaryNameSpec::M = m
+ m::N.name.should == "ModuleSpecs::SetTemporaryNameSpec::M::N"
+ ModuleSpecs::SetTemporaryNameSpec.send :remove_const, :M
+ 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)
+ 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
+ m::M = m::N
+ m::M.name.should =~ /\A#<Module:0x\h+>::M\z/m
+ end
- it "can reassign a temporary name repeatedly" do
- m = Module.new
+ it "can reassign a temporary name repeatedly" do
+ m = Module.new
- m.set_temporary_name("fake_name")
- m.name.should == "fake_name"
+ m.set_temporary_name("fake_name")
+ m.name.should == "fake_name"
- m.set_temporary_name("fake_name_2")
- m.name.should == "fake_name_2"
- end
+ m.set_temporary_name("fake_name_2")
+ m.name.should == "fake_name_2"
+ end
- ruby_bug "#21094", ""..."3.5" do
- it "also updates a name of a nested module" do
- m = Module.new
- m::N = Module.new
- m::N.name.should =~ /\A#<Module:0x\h+>::N\z/
+ ruby_bug "#21094", ""..."4.0" do
+ it "also updates a name of a nested module" do
+ m = Module.new
+ m::N = Module.new
+ m::N.name.should =~ /\A#<Module:0x\h+>::N\z/
- m.set_temporary_name "m"
- m::N.name.should == "m::N"
+ m.set_temporary_name "m"
+ m::N.name.should == "m::N"
- m.set_temporary_name nil
- m::N.name.should == nil
- end
+ m.set_temporary_name nil
+ m::N.name.should == nil
end
+ end
- it "keeps temporary name when assigned in an anonymous module" do
- outer = Module.new
- m = Module.new
- m.set_temporary_name "m"
- m.name.should == "m"
- outer::M = m
- m.name.should == "m"
- m.inspect.should == "m"
- end
+ it "keeps temporary name when assigned in an anonymous module" do
+ outer = Module.new
+ m = Module.new
+ m.set_temporary_name "m"
+ m.name.should == "m"
+ outer::M = m
+ m.name.should == "m"
+ m.inspect.should == "m"
+ end
- it "keeps temporary name when assigned in an anonymous module and nested before" do
- outer = Module.new
- m = Module.new
- outer::A = m
- m.set_temporary_name "m"
- m.name.should == "m"
- outer::M = m
- m.name.should == "m"
- m.inspect.should == "m"
- end
+ it "keeps temporary name when assigned in an anonymous module and nested before" do
+ outer = Module.new
+ m = Module.new
+ outer::A = m
+ m.set_temporary_name "m"
+ m.name.should == "m"
+ outer::M = m
+ m.name.should == "m"
+ m.inspect.should == "m"
end
end
diff --git a/spec/ruby/core/module/shared/class_eval.rb b/spec/ruby/core/module/shared/class_eval.rb
deleted file mode 100644
index b1d5cb3814..0000000000
--- a/spec/ruby/core/module/shared/class_eval.rb
+++ /dev/null
@@ -1,174 +0,0 @@
-describe :module_class_eval, shared: true do
- # TODO: This should probably be replaced with a "should behave like" that uses
- # the many scoping/binding specs from kernel/eval_spec, since most of those
- # behaviors are the same for instance_eval. See also module_eval/class_eval.
-
- it "evaluates a given string in the context of self" do
- ModuleSpecs.send(@method, "self").should == ModuleSpecs
- ModuleSpecs.send(@method, "1 + 1").should == 2
- end
-
- it "does not add defined methods to other classes" do
- FalseClass.send(@method) do
- def foo
- 'foo'
- end
- end
- -> {42.foo}.should raise_error(NoMethodError)
- end
-
- it "resolves constants in the caller scope" do
- ModuleSpecs::ClassEvalTest.get_constant_from_scope.should == ModuleSpecs::Lookup
- end
-
- it "resolves constants in the caller scope ignoring send" do
- ModuleSpecs::ClassEvalTest.get_constant_from_scope_with_send(@method).should == ModuleSpecs::Lookup
- end
-
- it "resolves constants in the receiver's scope" do
- ModuleSpecs.send(@method, "Lookup").should == ModuleSpecs::Lookup
- ModuleSpecs.send(@method, "Lookup::LOOKIE").should == ModuleSpecs::Lookup::LOOKIE
- end
-
- it "defines constants in the receiver's scope" do
- ModuleSpecs.send(@method, "module NewEvaluatedModule;end")
- ModuleSpecs.const_defined?(:NewEvaluatedModule, false).should == true
- end
-
- it "evaluates a given block in the context of self" do
- ModuleSpecs.send(@method) { self }.should == ModuleSpecs
- ModuleSpecs.send(@method) { 1 + 1 }.should == 2
- end
-
- it "passes the module as the first argument of the block" do
- given = nil
- ModuleSpecs.send(@method) do |block_parameter|
- given = block_parameter
- end
- given.should equal ModuleSpecs
- end
-
- it "uses the optional filename and lineno parameters for error messages" 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)
-
- (file = mock(__FILE__)).should_receive(:to_str).and_return(__FILE__)
- ModuleSpecs.send(@method, "1+1", file, 15)
- end
-
- it "raises a TypeError when the given filename can't be converted to string using to_str" do
- (file = mock('123')).should_receive(:to_str).and_return(123)
- -> { ModuleSpecs.send(@method, "1+1", file) }.should raise_error(TypeError, /can't convert MockObject to String/)
- end
-
- it "converts non string eval-string to string using to_str" do
- (o = mock('1 + 1')).should_receive(:to_str).and_return("1 + 1")
- ModuleSpecs.send(@method, o).should == 2
-
- (o = mock('1 + 1')).should_receive(:to_str).and_return("1 + 1")
- ModuleSpecs.send(@method, o, "file.rb").should == 2
-
- (o = mock('1 + 1')).should_receive(:to_str).and_return("1 + 1")
- ModuleSpecs.send(@method, o, "file.rb", 15).should == 2
- end
-
- it "raises a TypeError when the given eval-string can't be converted to string using to_str" do
- o = mock('x')
- -> { ModuleSpecs.send(@method, o) }.should raise_error(TypeError, "no implicit conversion of MockObject into String")
-
- (o = mock('123')).should_receive(:to_str).and_return(123)
- -> { ModuleSpecs.send(@method, o) }.should raise_error(TypeError, /can't convert MockObject to String/)
- end
-
- it "raises an ArgumentError when no arguments and no block are given" do
- -> { ModuleSpecs.send(@method) }.should raise_error(ArgumentError, "wrong number of arguments (given 0, expected 1..3)")
- end
-
- it "raises an ArgumentError when more than 3 arguments are given" do
- -> {
- ModuleSpecs.send(@method, "1 + 1", "some file", 0, "bogus")
- }.should raise_error(ArgumentError, "wrong number of arguments (given 4, expected 1..3)")
- end
-
- it "raises an ArgumentError when a block and normal arguments are given" do
- -> {
- ModuleSpecs.send(@method, "1 + 1") { 1 + 1 }
- }.should raise_error(ArgumentError, "wrong number of arguments (given 1, expected 0)")
- end
-
- # This case was found because Rubinius was caching the compiled
- # version of the string and not duping the methods within the
- # eval, causing the method addition to change the static scope
- # of the shared CompiledCode.
- it "adds methods respecting the lexical constant scope" do
- code = "def self.attribute; C; end"
-
- a = Class.new do
- self::C = "A"
- end
-
- b = Class.new do
- self::C = "B"
- end
-
- a.send @method, code
- b.send @method, code
-
- a.attribute.should == "A"
- b.attribute.should == "B"
- end
-
- it "activates refinements from the eval scope" do
- refinery = Module.new do
- refine ModuleSpecs::NamedClass do
- def foo
- "bar"
- end
- end
- end
-
- mid = @method
- result = nil
-
- Class.new do
- using refinery
-
- result = send(mid, "ModuleSpecs::NamedClass.new.foo")
- end
-
- result.should == "bar"
- end
-
- it "activates refinements from the eval scope with block" do
- refinery = Module.new do
- refine ModuleSpecs::NamedClass do
- def foo
- "bar"
- end
- end
- end
-
- mid = @method
- result = nil
-
- Class.new do
- using refinery
-
- result = send(mid) do
- ModuleSpecs::NamedClass.new.foo
- end
- end
-
- result.should == "bar"
- end
-end
diff --git a/spec/ruby/core/module/shared/class_exec.rb b/spec/ruby/core/module/shared/class_exec.rb
deleted file mode 100644
index c7a9e5297f..0000000000
--- a/spec/ruby/core/module/shared/class_exec.rb
+++ /dev/null
@@ -1,29 +0,0 @@
-describe :module_class_exec, shared: true do
- it "does not add defined methods to other classes" do
- FalseClass.send(@method) do
- def foo
- 'foo'
- end
- end
- -> {42.foo}.should raise_error(NoMethodError)
- end
-
- it "defines method in the receiver's scope" do
- ModuleSpecs::Subclass.send(@method) { def foo; end }
- ModuleSpecs::Subclass.new.respond_to?(:foo).should == true
- end
-
- it "evaluates a given block in the context of self" do
- ModuleSpecs::Subclass.send(@method) { self }.should == ModuleSpecs::Subclass
- ModuleSpecs::Subclass.new.send(@method) { 1 + 1 }.should == 2
- end
-
- it "raises a LocalJumpError when no block is given" do
- -> { ModuleSpecs::Subclass.send(@method) }.should raise_error(LocalJumpError)
- end
-
- it "passes arguments to the block" do
- a = ModuleSpecs::Subclass
- a.send(@method, 1) { |b| b }.should equal(1)
- end
-end
diff --git a/spec/ruby/core/module/shared/set_visibility.rb b/spec/ruby/core/module/shared/set_visibility.rb
index a1586dd2bd..38cc2ad260 100644
--- a/spec/ruby/core/module/shared/set_visibility.rb
+++ b/spec/ruby/core/module/shared/set_visibility.rb
@@ -2,7 +2,7 @@
describe :set_visibility, shared: true do
it "is a private method" do
- Module.should have_private_instance_method(@method, false)
+ Module.private_instance_methods(false).should.include?(@method)
end
describe "with argument" do
@@ -17,8 +17,8 @@ describe :set_visibility, shared: true do
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)
+ mod.send(:"#{visibility}_instance_methods", false).should.include?(:test1)
+ mod.send(:"#{visibility}_instance_methods", false).should.include?(:test2)
end
end
@@ -33,8 +33,8 @@ describe :set_visibility, shared: true do
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)
+ mod.send(:"#{visibility}_instance_methods", false).should.include?(:test1)
+ mod.send(:"#{visibility}_instance_methods", false).should.include?(:test2)
end
end
@@ -50,7 +50,7 @@ describe :set_visibility, shared: true do
send(visibility, :test_method)
}
- child.should_not send(:"have_#{visibility}_instance_method", :test_method, false)
+ child.send(:"#{visibility}_instance_methods", false).should_not.include?(:test_method)
end
end
@@ -64,8 +64,8 @@ describe :set_visibility, shared: true do
def test2() end
}
- mod.should send(:"have_#{@method}_instance_method", :test1, false)
- mod.should send(:"have_#{@method}_instance_method", :test2, false)
+ mod.send(:"#{@method}_instance_methods", false).should.include?(:test1)
+ mod.send(:"#{@method}_instance_methods", false).should.include?(:test2)
end
it "stops setting visibility if the body encounters other visibility setters without arguments" do
@@ -78,7 +78,7 @@ describe :set_visibility, shared: true do
def test1() end
}
- mod.should send(:"have_#{new_visibility}_instance_method", :test1, false)
+ mod.send(:"#{new_visibility}_instance_methods", false).should.include?(:test1)
end
it "continues setting visibility if the body encounters other visibility setters with arguments" do
@@ -90,7 +90,7 @@ describe :set_visibility, shared: true do
def test2() end
}
- mod.should send(:"have_#{@method}_instance_method", :test2, false)
+ mod.send(:"#{@method}_instance_methods", false).should.include?(:test2)
end
it "does not affect module_evaled method definitions when itself is outside the eval" do
@@ -102,8 +102,8 @@ describe :set_visibility, shared: true do
module_eval " def test2() end "
}
- mod.should have_public_instance_method(:test1, false)
- mod.should have_public_instance_method(:test2, false)
+ mod.public_instance_methods(false).should.include?(:test1)
+ mod.public_instance_methods(false).should.include?(:test2)
end
it "does not affect outside method definitions when itself is inside a module_eval" do
@@ -114,7 +114,7 @@ describe :set_visibility, shared: true do
def test1() end
}
- mod.should have_public_instance_method(:test1, false)
+ mod.public_instance_methods(false).should.include?(:test1)
end
it "affects normally if itself and method definitions are inside a module_eval" do
@@ -127,7 +127,7 @@ describe :set_visibility, shared: true do
}
}
- mod.should send(:"have_#{@method}_instance_method", :test1, false)
+ mod.send(:"#{@method}_instance_methods", false).should.include?(:test1)
end
it "does not affect method definitions when itself is inside an eval and method definitions are outside" do
@@ -140,7 +140,7 @@ describe :set_visibility, shared: true do
def test1() end
}
- mod.should send(:"have_#{initialized_visibility}_instance_method", :test1, false)
+ mod.send(:"#{initialized_visibility}_instance_methods", false).should.include?(:test1)
end
it "affects evaled method definitions when itself is outside the eval" do
@@ -151,7 +151,7 @@ describe :set_visibility, shared: true do
eval "def test1() end"
}
- mod.should send(:"have_#{@method}_instance_method", :test1, false)
+ mod.send(:"#{@method}_instance_methods", false).should.include?(:test1)
end
it "affects normally if itself and following method definitions are inside a eval" do
@@ -164,7 +164,7 @@ describe :set_visibility, shared: true do
CODE
}
- mod.should send(:"have_#{@method}_instance_method", :test1, false)
+ mod.send(:"#{@method}_instance_methods", false).should.include?(:test1)
end
describe "within a closure" do
@@ -177,7 +177,7 @@ describe :set_visibility, shared: true do
def test1() end
}
- mod.should send(:"have_#{@method}_instance_method", :test1, false)
+ mod.send(:"#{@method}_instance_methods", false).should.include?(:test1)
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..d77640cb7e 100644
--- a/spec/ruby/core/module/undef_method_spec.rb
+++ b/spec/ruby/core/module/undef_method_spec.rb
@@ -19,7 +19,7 @@ describe "Module#undef_method" do
end
it "is a public method" do
- Module.should have_public_instance_method(:undef_method, false)
+ Module.public_instance_methods(false).should.include?(:undef_method)
end
it "requires multiple arguments" do
@@ -34,8 +34,8 @@ describe "Module#undef_method" do
x = klass.new
klass.send(:undef_method, :method_to_undef, :another_method_to_undef)
- -> { x.method_to_undef }.should raise_error(NoMethodError)
- -> { x.another_method_to_undef }.should raise_error(NoMethodError)
+ -> { x.method_to_undef }.should.raise(NoMethodError)
+ -> { x.another_method_to_undef }.should.raise(NoMethodError)
end
it "does not undef any instance methods when argument not given" do
@@ -46,11 +46,11 @@ describe "Module#undef_method" do
end
it "returns self" do
- @module.send(:undef_method, :method_to_undef).should equal(@module)
+ @module.send(:undef_method, :method_to_undef).should.equal?(@module)
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(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(NameError, /undefined method [`']not_exist' for class [`']#{klass}'/) { |e|
# a NameError and not a NoMethodError
e.class.should == NameError
}
@@ -69,7 +69,7 @@ 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|
+ -> { sclass.send :undef_method, :not_exist }.should.raise(NameError, /undefined method [`']not_exist' for class [`']#{sclass}'/) { |e|
e.message.should =~ /[`']#<Class:#<#<Class:/
# a NameError and not a NoMethodError
@@ -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(NameError, /undefined method [`']not_exist' for class [`']String'/) { |e|
# a NameError and not a NoMethodError
e.class.should == NameError
}
@@ -91,19 +91,19 @@ describe "Module#undef_method" do
end
it "raises a FrozenError when passed a name" do
- -> { @frozen.send :undef_method, :method_to_undef }.should raise_error(FrozenError)
+ -> { @frozen.send :undef_method, :method_to_undef }.should.raise(FrozenError)
end
it "raises a FrozenError when passed a missing name" do
- -> { @frozen.send :undef_method, :not_exist }.should raise_error(FrozenError)
+ -> { @frozen.send :undef_method, :not_exist }.should.raise(FrozenError)
end
it "raises a TypeError when passed a not name" do
- -> { @frozen.send :undef_method, Object.new }.should raise_error(TypeError)
+ -> { @frozen.send :undef_method, Object.new }.should.raise(TypeError)
end
it "does not raise exceptions when no arguments given" do
- @frozen.send(:undef_method).should equal(@frozen)
+ @frozen.send(:undef_method).should.equal?(@frozen)
end
end
end
@@ -120,7 +120,7 @@ describe "Module#undef_method with symbol" do
klass.send :undef_method, :method_to_undef
- -> { x.method_to_undef }.should raise_error(NoMethodError)
+ -> { x.method_to_undef }.should.raise(NoMethodError)
end
it "removes a method defined in a super class" do
@@ -130,7 +130,7 @@ describe "Module#undef_method with symbol" do
child_class.send :undef_method, :method_to_undef
- -> { child.method_to_undef }.should raise_error(NoMethodError)
+ -> { child.method_to_undef }.should.raise(NoMethodError)
end
it "does not remove a method defined in a super class when removed from a subclass" do
@@ -156,7 +156,7 @@ describe "Module#undef_method with string" do
klass.send :undef_method, 'another_method_to_undef'
- -> { x.another_method_to_undef }.should raise_error(NoMethodError)
+ -> { x.another_method_to_undef }.should.raise(NoMethodError)
end
it "removes a method defined in a super class" do
@@ -166,7 +166,7 @@ describe "Module#undef_method with string" do
child_class.send :undef_method, 'another_method_to_undef'
- -> { child.another_method_to_undef }.should raise_error(NoMethodError)
+ -> { child.another_method_to_undef }.should.raise(NoMethodError)
end
it "does not remove a method defined in a super class when removed from a subclass" do
diff --git a/spec/ruby/core/module/undefined_instance_methods_spec.rb b/spec/ruby/core/module/undefined_instance_methods_spec.rb
index d33ee93fc1..9f731c6adf 100644
--- a/spec/ruby/core/module/undefined_instance_methods_spec.rb
+++ b/spec/ruby/core/module/undefined_instance_methods_spec.rb
@@ -9,16 +9,17 @@ describe "Module#undefined_instance_methods" do
it "returns inherited methods undefined in the class" do
methods = ModuleSpecs::UndefinedInstanceMethods::Child.undefined_instance_methods
- methods.should include(:parent_method, :another_parent_method)
+ methods.to_set.should >= Set[: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)
+ 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)
+ methods.should_not.include?(:parent_method)
+ methods.should_not.include?(:another_parent_method)
end
end
diff --git a/spec/ruby/core/module/using_spec.rb b/spec/ruby/core/module/using_spec.rb
index a908363c96..cff0edef28 100644
--- a/spec/ruby/core/module/using_spec.rb
+++ b/spec/ruby/core/module/using_spec.rb
@@ -28,7 +28,7 @@ describe "Module#using" do
Module.new do
using refinement
end
- }.should_not raise_error
+ }.should_not.raise
end
it "accepts module without refinements" do
@@ -38,7 +38,7 @@ describe "Module#using" do
Module.new do
using mod
end
- }.should_not raise_error
+ }.should_not.raise
end
it "does not accept class" do
@@ -48,7 +48,7 @@ describe "Module#using" do
Module.new do
using klass
end
- }.should raise_error(TypeError)
+ }.should.raise(TypeError)
end
it "raises TypeError if passed something other than module" do
@@ -56,7 +56,7 @@ describe "Module#using" do
Module.new do
using "foo"
end
- }.should raise_error(TypeError)
+ }.should.raise(TypeError)
end
it "returns self" do
@@ -67,7 +67,7 @@ describe "Module#using" do
result = using refinement
end
- result.should equal(mod)
+ result.should.equal?(mod)
end
it "works in classes too" do
@@ -95,7 +95,7 @@ describe "Module#using" do
-> {
mod.foo
- }.should raise_error(RuntimeError, /Module#using is not permitted in methods/)
+ }.should.raise(RuntimeError, /Module#using is not permitted in methods/)
end
it "activates refinement even for existed objects" do
diff --git a/spec/ruby/core/mutex/lock_spec.rb b/spec/ruby/core/mutex/lock_spec.rb
index e9d33f5fd9..4fee29091a 100644
--- a/spec/ruby/core/mutex/lock_spec.rb
+++ b/spec/ruby/core/mutex/lock_spec.rb
@@ -20,11 +20,73 @@ describe "Mutex#lock" do
# Unable to find a specific ticket but behavior change may be
# related to this ML thread.
- it "raises a ThreadError when used recursively" do
+ it "raises a deadlock ThreadError when used recursively" do
m = Mutex.new
m.lock
-> {
m.lock
- }.should raise_error(ThreadError)
+ }.should.raise(ThreadError, /deadlock/)
+ end
+
+ it "raises a deadlock ThreadError when multiple fibers from the same thread try to lock" do
+ m = Mutex.new
+
+ m.lock
+ f0 = Fiber.new do
+ m.lock
+ end
+ -> { f0.resume }.should.raise(ThreadError, /deadlock/)
+
+ m.unlock
+ f1 = Fiber.new do
+ m.lock
+ Fiber.yield
+ end
+ f2 = Fiber.new do
+ m.lock
+ end
+ f1.resume
+ -> { f2.resume }.should.raise(ThreadError, /deadlock/)
+ end
+
+ it "does not raise deadlock if a fiber's attempt to lock was interrupted" do
+ lock = Mutex.new
+ main = Thread.current
+
+ t2 = nil
+ t1 = Thread.new do
+ loop do
+ # interrupt fiber below looping on synchronize
+ sleep 0.01
+ t2.raise if t2
+ end
+ end
+
+ # loop ten times to try to handle the interrupt during synchronize
+ t2 = Thread.new do
+ 10.times do
+ Fiber.new do
+ begin
+ loop { lock.synchronize {} }
+ rescue RuntimeError
+ end
+ end.resume
+
+ Fiber.new do
+ -> do
+ lock.synchronize {}
+ end.should_not.raise(ThreadError)
+ end.resume
+ rescue RuntimeError
+ retry
+ end
+ end
+ t2.join
+ ensure
+ t1.kill rescue nil
+ t2.kill rescue nil
+
+ t1.join
+ t2.join
end
end
diff --git a/spec/ruby/core/mutex/locked_spec.rb b/spec/ruby/core/mutex/locked_spec.rb
index 1bf3ed6394..1818cdb4f3 100644
--- a/spec/ruby/core/mutex/locked_spec.rb
+++ b/spec/ruby/core/mutex/locked_spec.rb
@@ -4,12 +4,12 @@ describe "Mutex#locked?" do
it "returns true if locked" do
m = Mutex.new
m.lock
- m.locked?.should be_true
+ m.locked?.should == true
end
it "returns false if unlocked" do
m = Mutex.new
- m.locked?.should be_false
+ m.locked?.should == false
end
it "returns the status of the lock" do
@@ -27,10 +27,10 @@ describe "Mutex#locked?" do
Thread.pass until m1_locked
- m1.locked?.should be_true
+ m1.locked?.should == true
m2.unlock # release th
th.join
# A Thread releases its locks upon termination
- m1.locked?.should be_false
+ m1.locked?.should == false
end
end
diff --git a/spec/ruby/core/mutex/owned_spec.rb b/spec/ruby/core/mutex/owned_spec.rb
index 7bfc7d8f83..ea7d5faf1c 100644
--- a/spec/ruby/core/mutex/owned_spec.rb
+++ b/spec/ruby/core/mutex/owned_spec.rb
@@ -4,7 +4,7 @@ describe "Mutex#owned?" do
describe "when unlocked" do
it "returns false" do
m = Mutex.new
- m.owned?.should be_false
+ m.owned?.should == false
end
end
@@ -12,7 +12,7 @@ describe "Mutex#owned?" do
it "returns true" do
m = Mutex.new
m.lock
- m.owned?.should be_true
+ m.owned?.should == true
end
end
@@ -37,7 +37,7 @@ describe "Mutex#owned?" do
end
Thread.pass until locked
- m.owned?.should be_false
+ m.owned?.should == false
end
end
diff --git a/spec/ruby/core/mutex/sleep_spec.rb b/spec/ruby/core/mutex/sleep_spec.rb
index 9832e3125e..71b089d251 100644
--- a/spec/ruby/core/mutex/sleep_spec.rb
+++ b/spec/ruby/core/mutex/sleep_spec.rb
@@ -4,21 +4,21 @@ describe "Mutex#sleep" do
describe "when not locked by the current thread" do
it "raises a ThreadError" do
m = Mutex.new
- -> { m.sleep }.should raise_error(ThreadError)
+ -> { m.sleep }.should.raise(ThreadError)
end
it "raises an ArgumentError if passed a negative duration" do
m = Mutex.new
- -> { m.sleep(-0.1) }.should raise_error(ArgumentError)
- -> { m.sleep(-1) }.should raise_error(ArgumentError)
+ -> { m.sleep(-0.1) }.should.raise(ArgumentError)
+ -> { m.sleep(-1) }.should.raise(ArgumentError)
end
end
it "raises an ArgumentError if passed a negative duration" do
m = Mutex.new
m.lock
- -> { m.sleep(-0.1) }.should raise_error(ArgumentError)
- -> { m.sleep(-1) }.should raise_error(ArgumentError)
+ -> { m.sleep(-0.1) }.should.raise(ArgumentError)
+ -> { m.sleep(-1) }.should.raise(ArgumentError)
end
it "pauses execution for approximately the duration requested" do
@@ -38,7 +38,7 @@ describe "Mutex#sleep" do
th = Thread.new { m.lock; locked = true; m.sleep }
Thread.pass until locked
Thread.pass until th.stop?
- m.locked?.should be_false
+ m.locked?.should == false
th.run
th.join
end
@@ -47,7 +47,7 @@ describe "Mutex#sleep" do
m = Mutex.new
m.lock
m.sleep(0.001)
- m.locked?.should be_true
+ m.locked?.should == true
end
it "relocks the mutex when woken by an exception being raised" do
@@ -65,7 +65,7 @@ describe "Mutex#sleep" do
Thread.pass until locked
Thread.pass until th.stop?
th.raise(Exception)
- th.value.should be_true
+ th.value.should == true
end
it "returns the rounded number of seconds asleep" do
@@ -79,7 +79,15 @@ describe "Mutex#sleep" do
Thread.pass until locked
Thread.pass until th.stop?
th.wakeup
- th.value.should be_kind_of(Integer)
+ th.value.should.is_a?(Integer)
+ end
+
+ it "accepts nil as a sleep duration" do
+ m = Mutex.new
+ -> {
+ m.lock
+ m.sleep(nil)
+ }.should block_caller
end
it "wakes up when requesting sleep times near or equal to zero" do
@@ -97,7 +105,7 @@ describe "Mutex#sleep" do
m.lock
times.each do |time|
# just testing that sleep completes
- -> {m.sleep(time)}.should_not raise_error
+ -> {m.sleep(time)}.should_not.raise
end
end
end
diff --git a/spec/ruby/core/mutex/synchronize_spec.rb b/spec/ruby/core/mutex/synchronize_spec.rb
index 7942885197..823f29a634 100644
--- a/spec/ruby/core/mutex/synchronize_spec.rb
+++ b/spec/ruby/core/mutex/synchronize_spec.rb
@@ -14,15 +14,15 @@ describe "Mutex#synchronize" do
m2.lock
raise Exception
end
- end.should raise_error(Exception)
+ end.should.raise(Exception)
end
Thread.pass until synchronized
- m1.locked?.should be_true
+ m1.locked?.should == true
m2.unlock
th.join
- m1.locked?.should be_false
+ m1.locked?.should == false
end
it "blocks the caller if already locked" do
@@ -60,7 +60,7 @@ describe "Mutex#synchronize" do
m = Mutex.new
m.synchronize do
- -> { m.synchronize { } }.should raise_error(ThreadError)
+ -> { m.synchronize { } }.should.raise(ThreadError)
end
end
end
diff --git a/spec/ruby/core/mutex/try_lock_spec.rb b/spec/ruby/core/mutex/try_lock_spec.rb
index 8d521f4c6b..1da0735d6a 100644
--- a/spec/ruby/core/mutex/try_lock_spec.rb
+++ b/spec/ruby/core/mutex/try_lock_spec.rb
@@ -4,13 +4,13 @@ describe "Mutex#try_lock" do
describe "when unlocked" do
it "returns true" do
m = Mutex.new
- m.try_lock.should be_true
+ m.try_lock.should == true
end
it "locks the mutex" do
m = Mutex.new
m.try_lock
- m.locked?.should be_true
+ m.locked?.should == true
end
end
@@ -18,7 +18,7 @@ describe "Mutex#try_lock" do
it "returns false" do
m = Mutex.new
m.lock
- m.try_lock.should be_false
+ m.try_lock.should == false
end
end
@@ -26,7 +26,7 @@ describe "Mutex#try_lock" do
it "returns false" do
m = Mutex.new
m.lock
- Thread.new { m.try_lock }.value.should be_false
+ Thread.new { m.try_lock }.value.should == false
end
end
end
diff --git a/spec/ruby/core/mutex/unlock_spec.rb b/spec/ruby/core/mutex/unlock_spec.rb
index d999e66842..ed493cf84a 100644
--- a/spec/ruby/core/mutex/unlock_spec.rb
+++ b/spec/ruby/core/mutex/unlock_spec.rb
@@ -3,7 +3,7 @@ require_relative '../../spec_helper'
describe "Mutex#unlock" do
it "raises ThreadError unless Mutex is locked" do
mutex = Mutex.new
- -> { mutex.unlock }.should raise_error(ThreadError)
+ -> { mutex.unlock }.should.raise(ThreadError)
end
it "raises ThreadError unless thread owns Mutex" do
@@ -19,7 +19,7 @@ describe "Mutex#unlock" do
Thread.pass until mutex.locked?
Thread.pass until th.stop?
- -> { mutex.unlock }.should raise_error(ThreadError)
+ -> { mutex.unlock }.should.raise(ThreadError)
wait.unlock
th.join
@@ -33,6 +33,6 @@ describe "Mutex#unlock" do
th.join
- -> { mutex.unlock }.should raise_error(ThreadError)
+ -> { mutex.unlock }.should.raise(ThreadError)
end
end
diff --git a/spec/ruby/core/nil/dup_spec.rb b/spec/ruby/core/nil/dup_spec.rb
index 0324b3f1f4..e0be9540a6 100644
--- a/spec/ruby/core/nil/dup_spec.rb
+++ b/spec/ruby/core/nil/dup_spec.rb
@@ -2,6 +2,6 @@ require_relative '../../spec_helper'
describe "NilClass#dup" do
it "returns self" do
- nil.dup.should equal(nil)
+ nil.dup.should.equal?(nil)
end
end
diff --git a/spec/ruby/core/nil/match_spec.rb b/spec/ruby/core/nil/match_spec.rb
index bc1c591793..27ebc53c3d 100644
--- a/spec/ruby/core/nil/match_spec.rb
+++ b/spec/ruby/core/nil/match_spec.rb
@@ -5,13 +5,13 @@ describe "NilClass#=~" do
o = nil
suppress_warning do
- (o =~ /Object/).should be_nil
- (o =~ 'Object').should be_nil
- (o =~ Object).should be_nil
- (o =~ Object.new).should be_nil
- (o =~ nil).should be_nil
- (o =~ false).should be_nil
- (o =~ true).should be_nil
+ (o =~ /Object/).should == nil
+ (o =~ 'Object').should == nil
+ (o =~ Object).should == nil
+ (o =~ Object.new).should == nil
+ (o =~ nil).should == nil
+ (o =~ false).should == nil
+ (o =~ true).should == nil
end
end
diff --git a/spec/ruby/core/nil/nilclass_spec.rb b/spec/ruby/core/nil/nilclass_spec.rb
index 7f6d8af25d..55c5d0eba7 100644
--- a/spec/ruby/core/nil/nilclass_spec.rb
+++ b/spec/ruby/core/nil/nilclass_spec.rb
@@ -4,12 +4,12 @@ describe "NilClass" do
it ".allocate raises a TypeError" do
-> do
NilClass.allocate
- end.should raise_error(TypeError)
+ end.should.raise(TypeError)
end
it ".new is undefined" do
-> do
NilClass.new
- end.should raise_error(NoMethodError)
+ end.should.raise(NoMethodError)
end
end
diff --git a/spec/ruby/core/nil/rationalize_spec.rb b/spec/ruby/core/nil/rationalize_spec.rb
index 84d6e6f056..69fb257a7f 100644
--- a/spec/ruby/core/nil/rationalize_spec.rb
+++ b/spec/ruby/core/nil/rationalize_spec.rb
@@ -10,7 +10,7 @@ describe "NilClass#rationalize" do
end
it "raises ArgumentError when passed more than one argument" do
- -> { nil.rationalize(0.1, 0.1) }.should raise_error(ArgumentError)
- -> { nil.rationalize(0.1, 0.1, 2) }.should raise_error(ArgumentError)
+ -> { nil.rationalize(0.1, 0.1) }.should.raise(ArgumentError)
+ -> { nil.rationalize(0.1, 0.1, 2) }.should.raise(ArgumentError)
end
end
diff --git a/spec/ruby/core/nil/singleton_method_spec.rb b/spec/ruby/core/nil/singleton_method_spec.rb
index 8d898b1cc9..f121b42f81 100644
--- a/spec/ruby/core/nil/singleton_method_spec.rb
+++ b/spec/ruby/core/nil/singleton_method_spec.rb
@@ -1,15 +1,13 @@
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
+ it "raises regardless of whether NilClass defines the method" do
+ -> { nil.singleton_method(:foo) }.should.raise(NameError)
+ begin
+ def (nil).foo; end
+ -> { nil.singleton_method(:foo) }.should.raise(NameError)
+ ensure
+ NilClass.send(:remove_method, :foo)
end
end
end
diff --git a/spec/ruby/core/nil/to_c_spec.rb b/spec/ruby/core/nil/to_c_spec.rb
index e0052be5bd..f449ddb6a3 100644
--- a/spec/ruby/core/nil/to_c_spec.rb
+++ b/spec/ruby/core/nil/to_c_spec.rb
@@ -2,6 +2,6 @@ require_relative '../../spec_helper'
describe "NilClass#to_c" do
it "returns Complex(0, 0)" do
- nil.to_c.should eql(Complex(0, 0))
+ nil.to_c.should.eql?(Complex(0, 0))
end
end
diff --git a/spec/ruby/core/nil/to_s_spec.rb b/spec/ruby/core/nil/to_s_spec.rb
index fa0b929677..016ba4165a 100644
--- a/spec/ruby/core/nil/to_s_spec.rb
+++ b/spec/ruby/core/nil/to_s_spec.rb
@@ -10,6 +10,6 @@ describe "NilClass#to_s" do
end
it "always returns the same string" do
- nil.to_s.should equal(nil.to_s)
+ nil.to_s.should.equal?(nil.to_s)
end
end
diff --git a/spec/ruby/core/nil/xor_spec.rb b/spec/ruby/core/nil/xor_spec.rb
index b45da9d443..31ce33e971 100644
--- a/spec/ruby/core/nil/xor_spec.rb
+++ b/spec/ruby/core/nil/xor_spec.rb
@@ -1,11 +1,7 @@
require_relative '../../spec_helper'
describe "NilClass#^" do
- it "returns false if other is nil or false, otherwise true" do
- (nil ^ nil).should == false
- (nil ^ true).should == true
- (nil ^ false).should == false
- (nil ^ "").should == true
- (nil ^ mock('x')).should == true
+ it "is an alias of NilClass#|" do
+ nil.method(:^).should == nil.method(:|)
end
end
diff --git a/spec/ruby/core/numeric/abs2_spec.rb b/spec/ruby/core/numeric/abs2_spec.rb
index 0e60cd0ae7..12866f9c47 100644
--- a/spec/ruby/core/numeric/abs2_spec.rb
+++ b/spec/ruby/core/numeric/abs2_spec.rb
@@ -18,7 +18,7 @@ describe "Numeric#abs2" do
it "returns the square of the absolute value of self" do
@numbers.each do |number|
- number.abs2.should eql(number.abs ** 2)
+ number.abs2.should.eql?(number.abs ** 2)
end
end
@@ -29,6 +29,6 @@ describe "Numeric#abs2" do
end
it "returns NaN when self is NaN" do
- nan_value.abs2.nan?.should be_true
+ nan_value.abs2.nan?.should == true
end
end
diff --git a/spec/ruby/core/numeric/abs_spec.rb b/spec/ruby/core/numeric/abs_spec.rb
index 8bec50e337..4b16e06c97 100644
--- a/spec/ruby/core/numeric/abs_spec.rb
+++ b/spec/ruby/core/numeric/abs_spec.rb
@@ -1,6 +1,19 @@
require_relative '../../spec_helper'
-require_relative 'shared/abs'
+require_relative 'fixtures/classes'
describe "Numeric#abs" do
- it_behaves_like :numeric_abs, :abs
+ before :each do
+ @obj = NumericSpecs::Subclass.new
+ end
+
+ it "returns self when self is greater than 0" do
+ @obj.should_receive(:<).with(0).and_return(false)
+ @obj.abs.should == @obj
+ end
+
+ it "returns self\#@- when self is less than 0" do
+ @obj.should_receive(:<).with(0).and_return(true)
+ @obj.should_receive(:-@).and_return(:absolute_value)
+ @obj.abs.should == :absolute_value
+ end
end
diff --git a/spec/ruby/core/numeric/angle_spec.rb b/spec/ruby/core/numeric/angle_spec.rb
index bb38165777..25d2834a52 100644
--- a/spec/ruby/core/numeric/angle_spec.rb
+++ b/spec/ruby/core/numeric/angle_spec.rb
@@ -1,6 +1,7 @@
require_relative '../../spec_helper'
-require_relative 'shared/arg'
describe "Numeric#angle" do
- it_behaves_like :numeric_arg, :angle
+ it "is an alias of Numeric#arg" do
+ Numeric.instance_method(:angle).should == Numeric.instance_method(:arg)
+ end
end
diff --git a/spec/ruby/core/numeric/arg_spec.rb b/spec/ruby/core/numeric/arg_spec.rb
index ba3b57c687..4fd059d7fc 100644
--- a/spec/ruby/core/numeric/arg_spec.rb
+++ b/spec/ruby/core/numeric/arg_spec.rb
@@ -1,6 +1,38 @@
require_relative '../../spec_helper'
-require_relative 'shared/arg'
describe "Numeric#arg" do
- it_behaves_like :numeric_arg, :arg
+ before :each do
+ @numbers = [
+ 20,
+ Rational(3, 4),
+ bignum_value,
+ infinity_value
+ ]
+ end
+
+ it "returns 0 if positive" do
+ @numbers.each do |number|
+ number.arg.should == 0
+ end
+ end
+
+ it "returns Pi if negative" do
+ @numbers.each do |number|
+ (0-number).arg.should == Math::PI
+ end
+ end
+
+ describe "with a Numeric subclass" do
+ it "returns 0 if self#<(0) returns false" do
+ numeric = mock_numeric('positive')
+ numeric.should_receive(:<).with(0).and_return(false)
+ numeric.arg.should == 0
+ end
+
+ it "returns Pi if self#<(0) returns true" do
+ numeric = mock_numeric('positive')
+ numeric.should_receive(:<).with(0).and_return(true)
+ numeric.arg.should == Math::PI
+ end
+ end
end
diff --git a/spec/ruby/core/numeric/clone_spec.rb b/spec/ruby/core/numeric/clone_spec.rb
index 423cec85dd..1d06fdb050 100644
--- a/spec/ruby/core/numeric/clone_spec.rb
+++ b/spec/ruby/core/numeric/clone_spec.rb
@@ -3,11 +3,11 @@ require_relative '../../spec_helper'
describe "Numeric#clone" do
it "returns self" do
value = 1
- value.clone.should equal(value)
+ value.clone.should.equal?(value)
subclass = Class.new(Numeric)
value = subclass.new
- value.clone.should equal(value)
+ value.clone.should.equal?(value)
end
it "does not change frozen status" do
@@ -16,15 +16,15 @@ describe "Numeric#clone" do
it "accepts optional keyword argument :freeze" do
value = 1
- value.clone(freeze: true).should equal(value)
+ value.clone(freeze: true).should.equal?(value)
end
it "raises ArgumentError if passed freeze: false" do
- -> { 1.clone(freeze: false) }.should raise_error(ArgumentError, /can't unfreeze/)
+ -> { 1.clone(freeze: false) }.should.raise(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)
+ value.clone(freeze: nil).should.equal?(value)
end
end
diff --git a/spec/ruby/core/numeric/coerce_spec.rb b/spec/ruby/core/numeric/coerce_spec.rb
index 4c4416d30b..9344d99ee6 100644
--- a/spec/ruby/core/numeric/coerce_spec.rb
+++ b/spec/ruby/core/numeric/coerce_spec.rb
@@ -25,7 +25,7 @@ describe "Numeric#coerce" do
class << a; true; end
# watch it explode
- -> { a.coerce(b) }.should raise_error(TypeError)
+ -> { a.coerce(b) }.should.raise(TypeError)
end
end
@@ -38,22 +38,22 @@ describe "Numeric#coerce" do
it "raise TypeError if they are instances of different classes and other does not respond to #to_f" do
other = mock("numeric")
- -> { @obj.coerce(other) }.should raise_error(TypeError)
+ -> { @obj.coerce(other) }.should.raise(TypeError)
end
it "raises a TypeError when passed nil" do
- -> { @obj.coerce(nil) }.should raise_error(TypeError)
+ -> { @obj.coerce(nil) }.should.raise(TypeError)
end
it "raises a TypeError when passed a boolean" do
- -> { @obj.coerce(false) }.should raise_error(TypeError)
+ -> { @obj.coerce(false) }.should.raise(TypeError)
end
it "raises a TypeError when passed a Symbol" do
- -> { @obj.coerce(:symbol) }.should raise_error(TypeError)
+ -> { @obj.coerce(:symbol) }.should.raise(TypeError)
end
it "raises an ArgumentError when passed a non-numeric String" do
- -> { @obj.coerce("test") }.should raise_error(ArgumentError)
+ -> { @obj.coerce("test") }.should.raise(ArgumentError)
end
end
diff --git a/spec/ruby/core/numeric/comparison_spec.rb b/spec/ruby/core/numeric/comparison_spec.rb
index 4b4d52501a..b0a9390cc0 100644
--- a/spec/ruby/core/numeric/comparison_spec.rb
+++ b/spec/ruby/core/numeric/comparison_spec.rb
@@ -26,22 +26,22 @@ describe "Numeric#<=>" do
end
it "is called when instances are compared with #<" do
- (@a < @b).should be_false
+ (@a < @b).should == false
ScratchPad.recorded.should == :numeric_comparison
end
it "is called when instances are compared with #<=" do
- (@a <= @b).should be_false
+ (@a <= @b).should == false
ScratchPad.recorded.should == :numeric_comparison
end
it "is called when instances are compared with #>" do
- (@a > @b).should be_true
+ (@a > @b).should == true
ScratchPad.recorded.should == :numeric_comparison
end
it "is called when instances are compared with #>=" do
- (@a >= @b).should be_true
+ (@a >= @b).should == true
ScratchPad.recorded.should == :numeric_comparison
end
end
diff --git a/spec/ruby/core/numeric/conj_spec.rb b/spec/ruby/core/numeric/conj_spec.rb
index 7d4777ca60..f376a0d4b1 100644
--- a/spec/ruby/core/numeric/conj_spec.rb
+++ b/spec/ruby/core/numeric/conj_spec.rb
@@ -1,6 +1,7 @@
require_relative '../../spec_helper'
-require_relative 'shared/conj'
describe "Numeric#conj" do
- it_behaves_like :numeric_conj, :conj
+ it "is an alias of Numeric#conjugate" do
+ Numeric.instance_method(:conj).should == Numeric.instance_method(:conjugate)
+ end
end
diff --git a/spec/ruby/core/numeric/conjugate_spec.rb b/spec/ruby/core/numeric/conjugate_spec.rb
index 99854766e7..ea4731991d 100644
--- a/spec/ruby/core/numeric/conjugate_spec.rb
+++ b/spec/ruby/core/numeric/conjugate_spec.rb
@@ -1,6 +1,20 @@
require_relative '../../spec_helper'
-require_relative 'shared/conj'
describe "Numeric#conjugate" do
- it_behaves_like :numeric_conj, :conjugate
+ before :each do
+ @numbers = [
+ 20, # Integer
+ 398.72, # Float
+ Rational(3, 4), # Rational
+ bignum_value,
+ infinity_value,
+ nan_value
+ ]
+ end
+
+ it "returns self" do
+ @numbers.each do |number|
+ number.conjugate.should.equal?(number)
+ end
+ end
end
diff --git a/spec/ruby/core/numeric/div_spec.rb b/spec/ruby/core/numeric/div_spec.rb
index 53917b84c9..a17961850c 100644
--- a/spec/ruby/core/numeric/div_spec.rb
+++ b/spec/ruby/core/numeric/div_spec.rb
@@ -15,8 +15,8 @@ describe "Numeric#div" do
end
it "raises ZeroDivisionError for 0" do
- -> { @obj.div(0) }.should raise_error(ZeroDivisionError)
- -> { @obj.div(0.0) }.should raise_error(ZeroDivisionError)
- -> { @obj.div(Complex(0,0)) }.should raise_error(ZeroDivisionError)
+ -> { @obj.div(0) }.should.raise(ZeroDivisionError)
+ -> { @obj.div(0.0) }.should.raise(ZeroDivisionError)
+ -> { @obj.div(Complex(0,0)) }.should.raise(ZeroDivisionError)
end
end
diff --git a/spec/ruby/core/numeric/dup_spec.rb b/spec/ruby/core/numeric/dup_spec.rb
index 189a7ef44d..c158c618de 100644
--- a/spec/ruby/core/numeric/dup_spec.rb
+++ b/spec/ruby/core/numeric/dup_spec.rb
@@ -3,11 +3,11 @@ require_relative '../../spec_helper'
describe "Numeric#dup" do
it "returns self" do
value = 1
- value.dup.should equal(value)
+ value.dup.should.equal?(value)
subclass = Class.new(Numeric)
value = subclass.new
- value.dup.should equal(value)
+ value.dup.should.equal?(value)
end
it "does not change frozen status" do
diff --git a/spec/ruby/core/numeric/eql_spec.rb b/spec/ruby/core/numeric/eql_spec.rb
index b33e00e51f..80c58caef4 100644
--- a/spec/ruby/core/numeric/eql_spec.rb
+++ b/spec/ruby/core/numeric/eql_spec.rb
@@ -7,16 +7,16 @@ describe "Numeric#eql?" do
end
it "returns false if self's and other's types don't match" do
- @obj.should_not eql(1)
- @obj.should_not eql(-1.5)
- @obj.should_not eql(bignum_value)
- @obj.should_not eql(:sym)
+ @obj.should_not.eql?(1)
+ @obj.should_not.eql?(-1.5)
+ @obj.should_not.eql?(bignum_value)
+ @obj.should_not.eql?(:sym)
end
it "returns the result of calling self#== with other when self's and other's types match" do
other = NumericSpecs::Subclass.new
@obj.should_receive(:==).with(other).and_return("result", nil)
- @obj.should eql(other)
- @obj.should_not eql(other)
+ @obj.should.eql?(other)
+ @obj.should_not.eql?(other)
end
end
diff --git a/spec/ruby/core/numeric/fdiv_spec.rb b/spec/ruby/core/numeric/fdiv_spec.rb
index e97fa77f79..2c22c6a86a 100644
--- a/spec/ruby/core/numeric/fdiv_spec.rb
+++ b/spec/ruby/core/numeric/fdiv_spec.rb
@@ -18,7 +18,7 @@ describe "Numeric#fdiv" do
end
it "returns a Float" do
- bignum_value.fdiv(Float::MAX).should be_an_instance_of(Float)
+ bignum_value.fdiv(Float::MAX).should.instance_of?(Float)
end
it "returns Infinity if other is 0" do
@@ -26,6 +26,6 @@ describe "Numeric#fdiv" do
end
it "returns NaN if other is NaN" do
- 3334.fdiv(nan_value).nan?.should be_true
+ 3334.fdiv(nan_value).nan?.should == true
end
end
diff --git a/spec/ruby/core/numeric/finite_spec.rb b/spec/ruby/core/numeric/finite_spec.rb
index 05b5eebbd6..2c18c89466 100644
--- a/spec/ruby/core/numeric/finite_spec.rb
+++ b/spec/ruby/core/numeric/finite_spec.rb
@@ -3,6 +3,6 @@ require_relative '../../spec_helper'
describe "Numeric#finite?" do
it "returns true by default" do
o = mock_numeric("finite")
- o.finite?.should be_true
+ o.finite?.should == true
end
end
diff --git a/spec/ruby/core/numeric/i_spec.rb b/spec/ruby/core/numeric/i_spec.rb
index 621ecc09ec..f5fb99dfd3 100644
--- a/spec/ruby/core/numeric/i_spec.rb
+++ b/spec/ruby/core/numeric/i_spec.rb
@@ -2,7 +2,7 @@ require_relative '../../spec_helper'
describe "Numeric#i" do
it "returns a Complex object" do
- 34.i.should be_an_instance_of(Complex)
+ 34.i.should.instance_of?(Complex)
end
it "sets the real part to 0" do
diff --git a/spec/ruby/core/numeric/imag_spec.rb b/spec/ruby/core/numeric/imag_spec.rb
index b9e343cee9..761d6b0dbe 100644
--- a/spec/ruby/core/numeric/imag_spec.rb
+++ b/spec/ruby/core/numeric/imag_spec.rb
@@ -1,6 +1,7 @@
require_relative '../../spec_helper'
-require_relative 'shared/imag'
describe "Numeric#imag" do
- it_behaves_like :numeric_imag, :imag
+ it "is an alias of Numeric#imaginary" do
+ Numeric.instance_method(:imag).should == Numeric.instance_method(:imaginary)
+ end
end
diff --git a/spec/ruby/core/numeric/imaginary_spec.rb b/spec/ruby/core/numeric/imaginary_spec.rb
index ec708cb505..7b5d94cc75 100644
--- a/spec/ruby/core/numeric/imaginary_spec.rb
+++ b/spec/ruby/core/numeric/imaginary_spec.rb
@@ -1,6 +1,26 @@
require_relative '../../spec_helper'
-require_relative 'shared/imag'
describe "Numeric#imaginary" do
- it_behaves_like :numeric_imag, :imaginary
+ before :each do
+ @numbers = [
+ 20, # Integer
+ 398.72, # Float
+ Rational(3, 4), # Rational
+ bignum_value, # Bignum
+ infinity_value,
+ nan_value
+ ].map{|n| [n,-n]}.flatten
+ end
+
+ it "returns 0" do
+ @numbers.each do |number|
+ number.imaginary.should == 0
+ end
+ end
+
+ it "raises an ArgumentError if given any arguments" do
+ @numbers.each do |number|
+ -> { number.imaginary(number) }.should.raise(ArgumentError)
+ end
+ end
end
diff --git a/spec/ruby/core/numeric/magnitude_spec.rb b/spec/ruby/core/numeric/magnitude_spec.rb
index 1371dff21f..ea4dbd166f 100644
--- a/spec/ruby/core/numeric/magnitude_spec.rb
+++ b/spec/ruby/core/numeric/magnitude_spec.rb
@@ -1,6 +1,7 @@
require_relative "../../spec_helper"
-require_relative 'shared/abs'
describe "Numeric#magnitude" do
- it_behaves_like :numeric_abs, :magnitude
+ it "is an alias of Numeric#abs" do
+ Numeric.instance_method(:magnitude).should == Numeric.instance_method(:abs)
+ end
end
diff --git a/spec/ruby/core/numeric/modulo_spec.rb b/spec/ruby/core/numeric/modulo_spec.rb
index e3dc7e56f3..0baf96dc18 100644
--- a/spec/ruby/core/numeric/modulo_spec.rb
+++ b/spec/ruby/core/numeric/modulo_spec.rb
@@ -1,7 +1,12 @@
require_relative '../../spec_helper'
-require_relative 'fixtures/classes'
-describe :numeric_modulo_19, shared: true do
+describe "Numeric#modulo" do
+ it "is an alias of Numeric#%" do
+ Numeric.instance_method(:modulo).should == Numeric.instance_method(:%)
+ end
+end
+
+describe "Numeric#%" do
it "returns self - other * self.div(other)" do
s = mock_numeric('self')
o = mock_numeric('other')
@@ -11,14 +16,6 @@ describe :numeric_modulo_19, shared: true do
s.should_receive(:div).with(o).and_return(n3)
o.should_receive(:*).with(n3).and_return(n4)
s.should_receive(:-).with(n4).and_return(n5)
- s.send(@method, o).should == n5
+ (s % o).should == n5
end
end
-
-describe "Numeric#modulo" do
- it_behaves_like :numeric_modulo_19, :modulo
-end
-
-describe "Numeric#%" do
- it_behaves_like :numeric_modulo_19, :%
-end
diff --git a/spec/ruby/core/numeric/negative_spec.rb b/spec/ruby/core/numeric/negative_spec.rb
index 9c6f95fd87..f2d8a847da 100644
--- a/spec/ruby/core/numeric/negative_spec.rb
+++ b/spec/ruby/core/numeric/negative_spec.rb
@@ -4,22 +4,22 @@ require_relative 'fixtures/classes'
describe "Numeric#negative?" do
describe "on positive numbers" do
it "returns false" do
- 1.negative?.should be_false
- 0.1.negative?.should be_false
+ 1.negative?.should == false
+ 0.1.negative?.should == false
end
end
describe "on zero" do
it "returns false" do
- 0.negative?.should be_false
- 0.0.negative?.should be_false
+ 0.negative?.should == false
+ 0.0.negative?.should == false
end
end
describe "on negative numbers" do
it "returns true" do
- -1.negative?.should be_true
- -0.1.negative?.should be_true
+ -1.negative?.should == true
+ -0.1.negative?.should == true
end
end
end
diff --git a/spec/ruby/core/numeric/phase_spec.rb b/spec/ruby/core/numeric/phase_spec.rb
index bc1995303f..3abe8f2e02 100644
--- a/spec/ruby/core/numeric/phase_spec.rb
+++ b/spec/ruby/core/numeric/phase_spec.rb
@@ -1,6 +1,7 @@
require_relative '../../spec_helper'
-require_relative 'shared/arg'
describe "Numeric#phase" do
- it_behaves_like :numeric_arg, :phase
+ it "is an alias of Numeric#arg" do
+ Numeric.instance_method(:phase).should == Numeric.instance_method(:arg)
+ end
end
diff --git a/spec/ruby/core/numeric/polar_spec.rb b/spec/ruby/core/numeric/polar_spec.rb
index b594e408b2..0695d7afb2 100644
--- a/spec/ruby/core/numeric/polar_spec.rb
+++ b/spec/ruby/core/numeric/polar_spec.rb
@@ -17,7 +17,7 @@ describe "Numeric#polar" do
it "returns a two-element Array" do
@numbers.each do |number|
- number.polar.should be_an_instance_of(Array)
+ number.polar.should.instance_of?(Array)
number.polar.size.should == 2
end
end
@@ -44,7 +44,7 @@ describe "Numeric#polar" do
it "returns [NaN, NaN] if self is NaN" do
nan_value.polar.size.should == 2
- nan_value.polar.first.nan?.should be_true
- nan_value.polar.last.nan?.should be_true
+ nan_value.polar.first.nan?.should == true
+ nan_value.polar.last.nan?.should == true
end
end
diff --git a/spec/ruby/core/numeric/positive_spec.rb b/spec/ruby/core/numeric/positive_spec.rb
index 3b831b4d34..7c8d15cd9f 100644
--- a/spec/ruby/core/numeric/positive_spec.rb
+++ b/spec/ruby/core/numeric/positive_spec.rb
@@ -4,22 +4,22 @@ require_relative 'fixtures/classes'
describe "Numeric#positive?" do
describe "on positive numbers" do
it "returns true" do
- 1.positive?.should be_true
- 0.1.positive?.should be_true
+ 1.positive?.should == true
+ 0.1.positive?.should == true
end
end
describe "on zero" do
it "returns false" do
- 0.positive?.should be_false
- 0.0.positive?.should be_false
+ 0.positive?.should == false
+ 0.0.positive?.should == false
end
end
describe "on negative numbers" do
it "returns false" do
- -1.positive?.should be_false
- -0.1.positive?.should be_false
+ -1.positive?.should == false
+ -0.1.positive?.should == false
end
end
end
diff --git a/spec/ruby/core/numeric/quo_spec.rb b/spec/ruby/core/numeric/quo_spec.rb
index 6e3ce7a374..66ff019231 100644
--- a/spec/ruby/core/numeric/quo_spec.rb
+++ b/spec/ruby/core/numeric/quo_spec.rb
@@ -3,11 +3,11 @@ require_relative 'fixtures/classes'
describe "Numeric#quo" do
it "returns the result of self divided by the given Integer as a Rational" do
- 5.quo(2).should eql(Rational(5,2))
+ 5.quo(2).should.eql?(Rational(5,2))
end
it "returns the result of self divided by the given Float as a Float" do
- 2.quo(2.5).should eql(0.8)
+ 2.quo(2.5).should.eql?(0.8)
end
it "returns the result of self divided by the given Bignum as a Float" do
@@ -15,11 +15,11 @@ describe "Numeric#quo" do
end
it "raises a ZeroDivisionError when the given Integer is 0" do
- -> { 0.quo(0) }.should raise_error(ZeroDivisionError)
- -> { 10.quo(0) }.should raise_error(ZeroDivisionError)
- -> { -10.quo(0) }.should raise_error(ZeroDivisionError)
- -> { bignum_value.quo(0) }.should raise_error(ZeroDivisionError)
- -> { (-bignum_value).quo(0) }.should raise_error(ZeroDivisionError)
+ -> { 0.quo(0) }.should.raise(ZeroDivisionError)
+ -> { 10.quo(0) }.should.raise(ZeroDivisionError)
+ -> { -10.quo(0) }.should.raise(ZeroDivisionError)
+ -> { bignum_value.quo(0) }.should.raise(ZeroDivisionError)
+ -> { (-bignum_value).quo(0) }.should.raise(ZeroDivisionError)
end
it "calls #to_r to convert the object to a Rational" do
@@ -33,16 +33,16 @@ describe "Numeric#quo" do
obj = NumericSpecs::Subclass.new
obj.should_receive(:to_r).and_return(1)
- -> { obj.quo(19) }.should raise_error(TypeError)
+ -> { obj.quo(19) }.should.raise(TypeError)
end
it "raises a TypeError when given a non-Integer" do
-> {
(obj = mock('x')).should_not_receive(:to_int)
13.quo(obj)
- }.should raise_error(TypeError)
- -> { 13.quo("10") }.should raise_error(TypeError)
- -> { 13.quo(:symbol) }.should raise_error(TypeError)
+ }.should.raise(TypeError)
+ -> { 13.quo("10") }.should.raise(TypeError)
+ -> { 13.quo(:symbol) }.should.raise(TypeError)
end
it "returns the result of calling self#/ with other" do
@@ -53,7 +53,7 @@ describe "Numeric#quo" do
end
it "raises a ZeroDivisionError if the given argument is zero and not a Float" do
- -> { 1.quo(0) }.should raise_error(ZeroDivisionError)
+ -> { 1.quo(0) }.should.raise(ZeroDivisionError)
end
it "returns infinity if the given argument is zero and is a Float" do
diff --git a/spec/ruby/core/numeric/real_spec.rb b/spec/ruby/core/numeric/real_spec.rb
index 2d2499bcce..09d482a691 100644
--- a/spec/ruby/core/numeric/real_spec.rb
+++ b/spec/ruby/core/numeric/real_spec.rb
@@ -16,7 +16,7 @@ describe "Numeric#real" do
it "returns self" do
@numbers.each do |number|
if number.to_f.nan?
- number.real.nan?.should be_true
+ number.real.nan?.should == true
else
number.real.should == number
end
@@ -25,7 +25,7 @@ describe "Numeric#real" do
it "raises an ArgumentError if given any arguments" do
@numbers.each do |number|
- -> { number.real(number) }.should raise_error(ArgumentError)
+ -> { number.real(number) }.should.raise(ArgumentError)
end
end
end
diff --git a/spec/ruby/core/numeric/rect_spec.rb b/spec/ruby/core/numeric/rect_spec.rb
index 79a144c5a4..65cdcc5229 100644
--- a/spec/ruby/core/numeric/rect_spec.rb
+++ b/spec/ruby/core/numeric/rect_spec.rb
@@ -1,6 +1,7 @@
require_relative '../../spec_helper'
-require_relative 'shared/rect'
describe "Numeric#rect" do
- it_behaves_like :numeric_rect, :rect
+ it "is an alias of Numeric#rectangular" do
+ Numeric.instance_method(:rect).should == Numeric.instance_method(:rectangular)
+ end
end
diff --git a/spec/ruby/core/numeric/rectangular_spec.rb b/spec/ruby/core/numeric/rectangular_spec.rb
index 2c68985a16..81afccc12d 100644
--- a/spec/ruby/core/numeric/rectangular_spec.rb
+++ b/spec/ruby/core/numeric/rectangular_spec.rb
@@ -1,6 +1,48 @@
require_relative '../../spec_helper'
-require_relative 'shared/rect'
describe "Numeric#rectangular" do
- it_behaves_like :numeric_rect, :rectangular
+ before :each do
+ @numbers = [
+ 20, # Integer
+ 398.72, # Float
+ Rational(3, 4), # Rational
+ 99999999**99, # Bignum
+ infinity_value,
+ nan_value
+ ]
+ end
+
+ it "returns an Array" do
+ @numbers.each do |number|
+ number.rectangular.should.instance_of?(Array)
+ end
+ end
+
+ it "returns a two-element Array" do
+ @numbers.each do |number|
+ number.rectangular.size.should == 2
+ end
+ end
+
+ it "returns self as the first element" do
+ @numbers.each do |number|
+ if Float === number and number.nan?
+ number.rectangular.first.nan?.should == true
+ else
+ number.rectangular.first.should == number
+ end
+ end
+ end
+
+ it "returns 0 as the last element" do
+ @numbers.each do |number|
+ number.rectangular.last.should == 0
+ end
+ end
+
+ it "raises an ArgumentError if given any arguments" do
+ @numbers.each do |number|
+ -> { number.rectangular(number) }.should.raise(ArgumentError)
+ end
+ end
end
diff --git a/spec/ruby/core/numeric/remainder_spec.rb b/spec/ruby/core/numeric/remainder_spec.rb
index 674fa22d8e..bdf7358b21 100644
--- a/spec/ruby/core/numeric/remainder_spec.rb
+++ b/spec/ruby/core/numeric/remainder_spec.rb
@@ -6,16 +6,14 @@ 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
+ @other.should_receive(:coerce).with(@obj).and_return([@obj, @other])
end
it "returns the result of calling self#% with other if self is 0" do
@obj.should_receive(:%).with(@other).and_return(@result)
@result.should_receive(:==).with(0).and_return(true)
- @obj.remainder(@other).should equal(@result)
+ @obj.remainder(@other).should.equal?(@result)
end
it "returns the result of calling self#% with other if self and other are greater than 0" do
@@ -27,7 +25,7 @@ describe "Numeric#remainder" do
@obj.should_receive(:>).with(0).and_return(true)
@other.should_receive(:<).with(0).and_return(false)
- @obj.remainder(@other).should equal(@result)
+ @obj.remainder(@other).should.equal?(@result)
end
it "returns the result of calling self#% with other if self and other are less than 0" do
@@ -39,7 +37,7 @@ describe "Numeric#remainder" do
@obj.should_receive(:>).with(0).and_return(false)
- @obj.remainder(@other).should equal(@result)
+ @obj.remainder(@other).should.equal?(@result)
end
it "returns the result of calling self#% with other - other if self is greater than 0 and other is less than 0" do
diff --git a/spec/ruby/core/numeric/shared/abs.rb b/spec/ruby/core/numeric/shared/abs.rb
deleted file mode 100644
index c3dadccfd6..0000000000
--- a/spec/ruby/core/numeric/shared/abs.rb
+++ /dev/null
@@ -1,19 +0,0 @@
-require_relative '../../../spec_helper'
-require_relative '../fixtures/classes'
-
-describe :numeric_abs, shared: true do
- before :each do
- @obj = NumericSpecs::Subclass.new
- end
-
- it "returns self when self is greater than 0" do
- @obj.should_receive(:<).with(0).and_return(false)
- @obj.send(@method).should == @obj
- end
-
- it "returns self\#@- when self is less than 0" do
- @obj.should_receive(:<).with(0).and_return(true)
- @obj.should_receive(:-@).and_return(:absolute_value)
- @obj.send(@method).should == :absolute_value
- end
-end
diff --git a/spec/ruby/core/numeric/shared/arg.rb b/spec/ruby/core/numeric/shared/arg.rb
deleted file mode 100644
index c8e7ad8333..0000000000
--- a/spec/ruby/core/numeric/shared/arg.rb
+++ /dev/null
@@ -1,38 +0,0 @@
-require_relative '../../../spec_helper'
-
-describe :numeric_arg, shared: true do
- before :each do
- @numbers = [
- 20,
- Rational(3, 4),
- bignum_value,
- infinity_value
- ]
- end
-
- it "returns 0 if positive" do
- @numbers.each do |number|
- number.send(@method).should == 0
- end
- end
-
- it "returns Pi if negative" do
- @numbers.each do |number|
- (0-number).send(@method).should == Math::PI
- end
- end
-
- describe "with a Numeric subclass" do
- it "returns 0 if self#<(0) returns false" do
- numeric = mock_numeric('positive')
- numeric.should_receive(:<).with(0).and_return(false)
- numeric.send(@method).should == 0
- end
-
- it "returns Pi if self#<(0) returns true" do
- numeric = mock_numeric('positive')
- numeric.should_receive(:<).with(0).and_return(true)
- numeric.send(@method).should == Math::PI
- end
- end
-end
diff --git a/spec/ruby/core/numeric/shared/conj.rb b/spec/ruby/core/numeric/shared/conj.rb
deleted file mode 100644
index 6d5197ecab..0000000000
--- a/spec/ruby/core/numeric/shared/conj.rb
+++ /dev/null
@@ -1,20 +0,0 @@
-require_relative '../../../spec_helper'
-
-describe :numeric_conj, shared: true do
- before :each do
- @numbers = [
- 20, # Integer
- 398.72, # Float
- Rational(3, 4), # Rational
- bignum_value,
- infinity_value,
- nan_value
- ]
- end
-
- it "returns self" do
- @numbers.each do |number|
- number.send(@method).should equal(number)
- end
- end
-end
diff --git a/spec/ruby/core/numeric/shared/imag.rb b/spec/ruby/core/numeric/shared/imag.rb
deleted file mode 100644
index 4f117e243a..0000000000
--- a/spec/ruby/core/numeric/shared/imag.rb
+++ /dev/null
@@ -1,26 +0,0 @@
-require_relative '../../../spec_helper'
-
-describe :numeric_imag, shared: true do
- before :each do
- @numbers = [
- 20, # Integer
- 398.72, # Float
- Rational(3, 4), # Rational
- bignum_value, # Bignum
- infinity_value,
- nan_value
- ].map{|n| [n,-n]}.flatten
- end
-
- it "returns 0" do
- @numbers.each do |number|
- number.send(@method).should == 0
- end
- end
-
- it "raises an ArgumentError if given any arguments" do
- @numbers.each do |number|
- -> { number.send(@method, number) }.should raise_error(ArgumentError)
- end
- end
-end
diff --git a/spec/ruby/core/numeric/shared/rect.rb b/spec/ruby/core/numeric/shared/rect.rb
deleted file mode 100644
index 120a69b1c4..0000000000
--- a/spec/ruby/core/numeric/shared/rect.rb
+++ /dev/null
@@ -1,48 +0,0 @@
-require_relative '../../../spec_helper'
-
-describe :numeric_rect, shared: true do
- before :each do
- @numbers = [
- 20, # Integer
- 398.72, # Float
- Rational(3, 4), # Rational
- 99999999**99, # Bignum
- infinity_value,
- nan_value
- ]
- end
-
- it "returns an Array" do
- @numbers.each do |number|
- number.send(@method).should be_an_instance_of(Array)
- end
- end
-
- it "returns a two-element Array" do
- @numbers.each do |number|
- number.send(@method).size.should == 2
- end
- end
-
- it "returns self as the first element" do
- @numbers.each do |number|
- if Float === number and number.nan?
- number.send(@method).first.nan?.should be_true
- else
- number.send(@method).first.should == number
- end
- end
- end
-
- it "returns 0 as the last element" do
- @numbers.each do |number|
- number.send(@method).last.should == 0
- end
- end
-
- it "raises an ArgumentError if given any arguments" do
- @numbers.each do |number|
- -> { number.send(@method, number) }.should raise_error(ArgumentError)
- end
- end
-end
diff --git a/spec/ruby/core/numeric/shared/step.rb b/spec/ruby/core/numeric/shared/step.rb
index 977ec6de02..66b8c1af0d 100644
--- a/spec/ruby/core/numeric/shared/step.rb
+++ b/spec/ruby/core/numeric/shared/step.rb
@@ -13,7 +13,7 @@ describe :numeric_step, shared: true do
it "defaults to step = 1" do
@step.call(1, 5, &@prc)
- ScratchPad.recorded.should eql [1, 2, 3, 4, 5]
+ ScratchPad.recorded.should.eql? [1, 2, 3, 4, 5]
end
it "defaults to an infinite limit with a step size of 1 for Integers" do
@@ -26,35 +26,35 @@ describe :numeric_step, shared: true do
describe "when self, stop and step are Integers" do
it "yields only Integers" do
- @step.call(1, 5, 1) { |x| x.should be_an_instance_of(Integer) }
+ @step.call(1, 5, 1) { |x| x.should.instance_of?(Integer) }
end
describe "with a positive step" do
it "yields while increasing self by step until stop is reached" do
@step.call(1, 5, 1, &@prc)
- ScratchPad.recorded.should eql [1, 2, 3, 4, 5]
+ ScratchPad.recorded.should.eql? [1, 2, 3, 4, 5]
end
it "yields once when self equals stop" do
@step.call(1, 1, 1, &@prc)
- ScratchPad.recorded.should eql [1]
+ ScratchPad.recorded.should.eql? [1]
end
it "does not yield when self is greater than stop" do
@step.call(2, 1, 1, &@prc)
- ScratchPad.recorded.should eql []
+ ScratchPad.recorded.should.eql? []
end
end
describe "with a negative step" do
it "yields while decreasing self by step until stop is reached" do
@step.call(5, 1, -1, &@prc)
- ScratchPad.recorded.should eql [5, 4, 3, 2, 1]
+ ScratchPad.recorded.should.eql? [5, 4, 3, 2, 1]
end
it "yields once when self equals stop" do
@step.call(5, 5, -1, &@prc)
- ScratchPad.recorded.should eql [5]
+ ScratchPad.recorded.should.eql? [5]
end
it "does not yield when self is less than stop" do
@@ -66,26 +66,26 @@ describe :numeric_step, shared: true do
describe "when at least one of self, stop or step is a Float" do
it "yields Floats even if only self is a Float" do
- @step.call(1.5, 5, 1) { |x| x.should be_an_instance_of(Float) }
+ @step.call(1.5, 5, 1) { |x| x.should.instance_of?(Float) }
end
it "yields Floats even if only stop is a Float" do
- @step.call(1, 5.0, 1) { |x| x.should be_an_instance_of(Float) }
+ @step.call(1, 5.0, 1) { |x| x.should.instance_of?(Float) }
end
it "yields Floats even if only step is a Float" do
- @step.call(1, 5, 1.0) { |x| x.should be_an_instance_of(Float) }
+ @step.call(1, 5, 1.0) { |x| x.should.instance_of?(Float) }
end
describe "with a positive step" do
it "yields while increasing self by step while < stop" do
@step.call(1.5, 5, 1, &@prc)
- ScratchPad.recorded.should eql [1.5, 2.5, 3.5, 4.5]
+ ScratchPad.recorded.should.eql? [1.5, 2.5, 3.5, 4.5]
end
it "yields once when self equals stop" do
@step.call(1.5, 1.5, 1, &@prc)
- ScratchPad.recorded.should eql [1.5]
+ ScratchPad.recorded.should.eql? [1.5]
end
it "does not yield when self is greater than stop" do
@@ -96,19 +96,19 @@ describe :numeric_step, shared: true do
it "is careful about not yielding a value greater than limit" do
# As 9*1.3+1.0 == 12.700000000000001 > 12.7, we test:
@step.call(1.0, 12.7, 1.3, &@prc)
- ScratchPad.recorded.should eql [1.0, 2.3, 3.6, 4.9, 6.2, 7.5, 8.8, 10.1, 11.4, 12.7]
+ ScratchPad.recorded.should.eql? [1.0, 2.3, 3.6, 4.9, 6.2, 7.5, 8.8, 10.1, 11.4, 12.7]
end
end
describe "with a negative step" do
it "yields while decreasing self by step while self > stop" do
@step.call(5, 1.5, -1, &@prc)
- ScratchPad.recorded.should eql [5.0, 4.0, 3.0, 2.0]
+ ScratchPad.recorded.should.eql? [5.0, 4.0, 3.0, 2.0]
end
it "yields once when self equals stop" do
@step.call(1.5, 1.5, -1, &@prc)
- ScratchPad.recorded.should eql [1.5]
+ ScratchPad.recorded.should.eql? [1.5]
end
it "does not yield when self is less than stop" do
@@ -119,24 +119,24 @@ describe :numeric_step, shared: true do
it "is careful about not yielding a value smaller than limit" do
# As -9*1.3-1.0 == -12.700000000000001 < -12.7, we test:
@step.call(-1.0, -12.7, -1.3, &@prc)
- ScratchPad.recorded.should eql [-1.0, -2.3, -3.6, -4.9, -6.2, -7.5, -8.8, -10.1, -11.4, -12.7]
+ ScratchPad.recorded.should.eql? [-1.0, -2.3, -3.6, -4.9, -6.2, -7.5, -8.8, -10.1, -11.4, -12.7]
end
end
describe "with a positive Infinity step" do
it "yields once if self < stop" do
@step.call(42, 100, infinity_value, &@prc)
- ScratchPad.recorded.should eql [42.0]
+ ScratchPad.recorded.should.eql? [42.0]
end
it "yields once when stop is Infinity" do
@step.call(42, infinity_value, infinity_value, &@prc)
- ScratchPad.recorded.should eql [42.0]
+ ScratchPad.recorded.should.eql? [42.0]
end
it "yields once when self equals stop" do
@step.call(42, 42, infinity_value, &@prc)
- ScratchPad.recorded.should eql [42.0]
+ ScratchPad.recorded.should.eql? [42.0]
end
it "yields once when self and stop are Infinity" do
@@ -159,17 +159,17 @@ describe :numeric_step, shared: true do
describe "with a negative Infinity step" do
it "yields once if self > stop" do
@step.call(42, 6, -infinity_value, &@prc)
- ScratchPad.recorded.should eql [42.0]
+ ScratchPad.recorded.should.eql? [42.0]
end
it "yields once if stop is -Infinity" do
@step.call(42, -infinity_value, -infinity_value, &@prc)
- ScratchPad.recorded.should eql [42.0]
+ ScratchPad.recorded.should.eql? [42.0]
end
it "yields once when self equals stop" do
@step.call(42, 42, -infinity_value, &@prc)
- ScratchPad.recorded.should eql [42.0]
+ ScratchPad.recorded.should.eql? [42.0]
end
it "yields once when self and stop are Infinity" do
@@ -226,60 +226,60 @@ describe :numeric_step, shared: true do
describe "when step is a String" do
describe "with self and stop as Integers" do
it "raises an ArgumentError when step is a numeric representation" do
- -> { @step.call(1, 5, "1") {} }.should raise_error(ArgumentError)
- -> { @step.call(1, 5, "0.1") {} }.should raise_error(ArgumentError)
- -> { @step.call(1, 5, "1/3") {} }.should raise_error(ArgumentError)
+ -> { @step.call(1, 5, "1") {} }.should.raise(ArgumentError)
+ -> { @step.call(1, 5, "0.1") {} }.should.raise(ArgumentError)
+ -> { @step.call(1, 5, "1/3") {} }.should.raise(ArgumentError)
end
it "raises an ArgumentError with step as an alphanumeric string" do
- -> { @step.call(1, 5, "foo") {} }.should raise_error(ArgumentError)
+ -> { @step.call(1, 5, "foo") {} }.should.raise(ArgumentError)
end
end
describe "with self and stop as Floats" do
it "raises an ArgumentError when step is a numeric representation" do
- -> { @step.call(1.1, 5.1, "1") {} }.should raise_error(ArgumentError)
- -> { @step.call(1.1, 5.1, "0.1") {} }.should raise_error(ArgumentError)
- -> { @step.call(1.1, 5.1, "1/3") {} }.should raise_error(ArgumentError)
+ -> { @step.call(1.1, 5.1, "1") {} }.should.raise(ArgumentError)
+ -> { @step.call(1.1, 5.1, "0.1") {} }.should.raise(ArgumentError)
+ -> { @step.call(1.1, 5.1, "1/3") {} }.should.raise(ArgumentError)
end
it "raises an ArgumentError with step as an alphanumeric string" do
- -> { @step.call(1.1, 5.1, "foo") {} }.should raise_error(ArgumentError)
+ -> { @step.call(1.1, 5.1, "foo") {} }.should.raise(ArgumentError)
end
end
end
it "does not rescue ArgumentError exceptions" do
- -> { @step.call(1, 2) { raise ArgumentError, "" }}.should raise_error(ArgumentError)
+ -> { @step.call(1, 2) { raise ArgumentError, "" }}.should.raise(ArgumentError)
end
it "does not rescue TypeError exceptions" do
- -> { @step.call(1, 2) { raise TypeError, "" } }.should raise_error(TypeError)
+ -> { @step.call(1, 2) { raise TypeError, "" } }.should.raise(TypeError)
end
describe "when no block is given" do
step_enum_class = Enumerator::ArithmeticSequence
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)
+ @step.call(1, 0, 2).should.instance_of?(step_enum_class)
end
it "returns an #{step_enum_class} when not passed a block and self < stop" do
- @step.call(1, 2, 3).should be_an_instance_of(step_enum_class)
+ @step.call(1, 2, 3).should.instance_of?(step_enum_class)
end
it "returns an #{step_enum_class} that uses the given step" do
- @step.call(0, 5, 2).to_a.should eql [0, 2, 4]
+ @step.call(0, 5, 2).to_a.should.eql? [0, 2, 4]
end
describe "when step is a String" do
describe "with self and stop as Integers" do
it "returns an Enumerator" do
- @step.call(1, 5, "foo").should be_an_instance_of(Enumerator)
+ @step.call(1, 5, "foo").should.instance_of?(Enumerator)
end
end
describe "with self and stop as Floats" do
it "returns an Enumerator" do
- @step.call(1.1, 5.1, "foo").should be_an_instance_of(Enumerator)
+ @step.call(1.1, 5.1, "foo").should.instance_of?(Enumerator)
end
end
end
@@ -289,23 +289,23 @@ describe :numeric_step, shared: true do
describe "when step is a String" do
describe "with self and stop as Integers" do
it "raises an ArgumentError when step is a numeric representation" do
- -> { @step.call(1, 5, "1").size }.should raise_error(ArgumentError)
- -> { @step.call(1, 5, "0.1").size }.should raise_error(ArgumentError)
- -> { @step.call(1, 5, "1/3").size }.should raise_error(ArgumentError)
+ -> { @step.call(1, 5, "1").size }.should.raise(ArgumentError)
+ -> { @step.call(1, 5, "0.1").size }.should.raise(ArgumentError)
+ -> { @step.call(1, 5, "1/3").size }.should.raise(ArgumentError)
end
it "raises an ArgumentError with step as an alphanumeric string" do
- -> { @step.call(1, 5, "foo").size }.should raise_error(ArgumentError)
+ -> { @step.call(1, 5, "foo").size }.should.raise(ArgumentError)
end
end
describe "with self and stop as Floats" do
it "raises an ArgumentError when step is a numeric representation" do
- -> { @step.call(1.1, 5.1, "1").size }.should raise_error(ArgumentError)
- -> { @step.call(1.1, 5.1, "0.1").size }.should raise_error(ArgumentError)
- -> { @step.call(1.1, 5.1, "1/3").size }.should raise_error(ArgumentError)
+ -> { @step.call(1.1, 5.1, "1").size }.should.raise(ArgumentError)
+ -> { @step.call(1.1, 5.1, "0.1").size }.should.raise(ArgumentError)
+ -> { @step.call(1.1, 5.1, "1/3").size }.should.raise(ArgumentError)
end
it "raises an ArgumentError with step as an alphanumeric string" do
- -> { @step.call(1.1, 5.1, "foo").size }.should raise_error(ArgumentError)
+ -> { @step.call(1.1, 5.1, "foo").size }.should.raise(ArgumentError)
end
end
end
diff --git a/spec/ruby/core/numeric/singleton_method_added_spec.rb b/spec/ruby/core/numeric/singleton_method_added_spec.rb
index 2091398e5d..327bb5662a 100644
--- a/spec/ruby/core/numeric/singleton_method_added_spec.rb
+++ b/spec/ruby/core/numeric/singleton_method_added_spec.rb
@@ -21,21 +21,21 @@ describe "Numeric#singleton_method_added" do
-> do
a = NumericSpecs::Subclass.new
def a.test; end
- end.should raise_error(TypeError)
+ end.should.raise(TypeError)
-> do
a = 1
def a.test; end
- end.should raise_error(TypeError)
+ end.should.raise(TypeError)
-> do
a = 1.5
def a.test; end
- end.should raise_error(TypeError)
+ end.should.raise(TypeError)
-> do
a = bignum_value
def a.test; end
- end.should raise_error(TypeError)
+ end.should.raise(TypeError)
end
end
diff --git a/spec/ruby/core/numeric/step_spec.rb b/spec/ruby/core/numeric/step_spec.rb
index 1705fb1b4e..6896009eb6 100644
--- a/spec/ruby/core/numeric/step_spec.rb
+++ b/spec/ruby/core/numeric/step_spec.rb
@@ -6,11 +6,11 @@ describe "Numeric#step" do
describe 'with positional args' do
it "raises an ArgumentError when step is 0" do
- -> { 1.step(5, 0) {} }.should raise_error(ArgumentError)
+ -> { 1.step(5, 0) {} }.should.raise(ArgumentError)
end
it "raises an ArgumentError when step is 0.0" do
- -> { 1.step(2, 0.0) {} }.should raise_error(ArgumentError)
+ -> { 1.step(2, 0.0) {} }.should.raise(ArgumentError)
end
before :all do
@@ -81,19 +81,19 @@ describe "Numeric#step" do
describe 'with mixed arguments' do
it " raises an ArgumentError when step is 0" do
- -> { 1.step(5, by: 0) { break } }.should raise_error(ArgumentError)
+ -> { 1.step(5, by: 0) { break } }.should.raise(ArgumentError)
end
it "raises an ArgumentError when step is 0.0" do
- -> { 1.step(2, by: 0.0) { break } }.should raise_error(ArgumentError)
+ -> { 1.step(2, by: 0.0) { break } }.should.raise(ArgumentError)
end
it "raises a ArgumentError when limit and to are defined" do
- -> { 1.step(5, 1, to: 5) { break } }.should raise_error(ArgumentError)
+ -> { 1.step(5, 1, to: 5) { break } }.should.raise(ArgumentError)
end
it "raises a ArgumentError when step and by are defined" do
- -> { 1.step(5, 1, by: 5) { break } }.should raise_error(ArgumentError)
+ -> { 1.step(5, 1, by: 5) { break } }.should.raise(ArgumentError)
end
describe "when no block is given" do
diff --git a/spec/ruby/core/numeric/to_c_spec.rb b/spec/ruby/core/numeric/to_c_spec.rb
index 75245a612e..70b7a9dd0c 100644
--- a/spec/ruby/core/numeric/to_c_spec.rb
+++ b/spec/ruby/core/numeric/to_c_spec.rb
@@ -22,7 +22,7 @@ describe "Numeric#to_c" do
it "returns a Complex object" do
@numbers.each do |number|
- number.to_c.should be_an_instance_of(Complex)
+ number.to_c.should.instance_of?(Complex)
end
end
@@ -30,7 +30,7 @@ describe "Numeric#to_c" do
@numbers.each do |number|
real = number.to_c.real
if Float === number and number.nan?
- real.nan?.should be_true
+ real.nan?.should == true
else
real.should == number
end
diff --git a/spec/ruby/core/objectspace/_id2ref_spec.rb b/spec/ruby/core/objectspace/_id2ref_spec.rb
index 7c0e0e7a71..a9fd526b7d 100644
--- a/spec/ruby/core/objectspace/_id2ref_spec.rb
+++ b/spec/ruby/core/objectspace/_id2ref_spec.rb
@@ -1,6 +1,6 @@
require_relative '../../spec_helper'
-ruby_version_is "3.5" do
+ruby_version_is "4.0" do
describe "ObjectSpace._id2ref" do
it "is deprecated" do
id = nil.object_id
@@ -11,7 +11,7 @@ ruby_version_is "3.5" do
end
end
-ruby_version_is ""..."3.5" do
+ruby_version_is ""..."4.0" do
describe "ObjectSpace._id2ref" do
it "converts an object id to a reference to the object" do
s = "I am a string"
@@ -59,7 +59,7 @@ ruby_version_is ""..."3.5" do
end
it 'raises RangeError when an object could not be found' do
- proc { ObjectSpace._id2ref(1 << 60) }.should raise_error(RangeError)
+ proc { ObjectSpace._id2ref(1 << 60) }.should.raise(RangeError)
end
end
end
diff --git a/spec/ruby/core/objectspace/define_finalizer_spec.rb b/spec/ruby/core/objectspace/define_finalizer_spec.rb
index 0f4b54c345..5441cb4a21 100644
--- a/spec/ruby/core/objectspace/define_finalizer_spec.rb
+++ b/spec/ruby/core/objectspace/define_finalizer_spec.rb
@@ -13,7 +13,7 @@ describe "ObjectSpace.define_finalizer" do
it "raises an ArgumentError if the action does not respond to call" do
-> {
ObjectSpace.define_finalizer(Object.new, mock("ObjectSpace.define_finalizer no #call"))
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
it "accepts an object and a proc" do
@@ -42,7 +42,7 @@ describe "ObjectSpace.define_finalizer" do
it "raises ArgumentError trying to define a finalizer on a non-reference" do
-> {
ObjectSpace.define_finalizer(:blah) { 1 }
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
# see [ruby-core:24095]
@@ -57,7 +57,7 @@ describe "ObjectSpace.define_finalizer" do
exit 0
RUBY
- ruby_exe(code, :args => "2>&1").should include("finalizer run\n")
+ ruby_exe(code, :args => "2>&1").should.include?("finalizer run\n")
end
it "warns if the finalizer has the object as the receiver" do
@@ -73,7 +73,7 @@ describe "ObjectSpace.define_finalizer" do
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
it "warns if the finalizer is a method bound to the receiver" do
@@ -90,7 +90,7 @@ describe "ObjectSpace.define_finalizer" do
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
it "warns if the finalizer was a block in the receiver" do
@@ -106,7 +106,7 @@ describe "ObjectSpace.define_finalizer" do
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
it "calls a finalizer at exit even if it is self-referencing" do
@@ -117,7 +117,7 @@ describe "ObjectSpace.define_finalizer" do
exit 0
RUBY
- ruby_exe(code).should include("finalizer run\n")
+ ruby_exe(code).should.include?("finalizer run\n")
end
it "calls a finalizer at exit even if it is indirectly self-referencing" do
@@ -136,7 +136,7 @@ describe "ObjectSpace.define_finalizer" do
exit 0
RUBY
- ruby_exe(code, :args => "2>&1").should include("finalizer run\n")
+ ruby_exe(code, :args => "2>&1").should.include?("finalizer run\n")
end
it "calls a finalizer defined in a finalizer running at exit" do
@@ -152,7 +152,7 @@ describe "ObjectSpace.define_finalizer" do
exit 0
RUBY
- ruby_exe(code, :args => "2>&1").should include("finalizer 2 run\n")
+ ruby_exe(code, :args => "2>&1").should.include?("finalizer 2 run\n")
end
it "allows multiple finalizers with different 'callables' to be defined" do
@@ -199,7 +199,9 @@ describe "ObjectSpace.define_finalizer" do
ObjectSpace.define_finalizer(Object.new) { raise "finalizing" }
RUBY
- ruby_exe(code, args: "2>&1").should include("warning: Exception in finalizer", "finalizing")
+ out = ruby_exe(code, args: "2>&1")
+ out.should.include?("warning: Exception in finalizer")
+ out.should.include?("finalizing")
end
end
diff --git a/spec/ruby/core/objectspace/each_object_spec.rb b/spec/ruby/core/objectspace/each_object_spec.rb
index 09a582afaf..aee0fd629c 100644
--- a/spec/ruby/core/objectspace/each_object_spec.rb
+++ b/spec/ruby/core/objectspace/each_object_spec.rb
@@ -39,7 +39,7 @@ describe "ObjectSpace.each_object" do
new_obj = klass.new
counter = ObjectSpace.each_object(klass)
- counter.should be_an_instance_of(Enumerator)
+ counter.should.instance_of?(Enumerator)
counter.each{}.should == 1
# this is needed to prevent the new_obj from being GC'd too early
new_obj.should_not == nil
@@ -47,20 +47,20 @@ describe "ObjectSpace.each_object" do
it "finds an object stored in a global variable" do
$object_space_global_variable = ObjectSpaceFixtures::ObjectToBeFound.new(:global)
- ObjectSpaceFixtures.to_be_found_symbols.should include(:global)
+ ObjectSpaceFixtures.to_be_found_symbols.should.include?(:global)
end
it "finds an object stored in a top-level constant" do
- ObjectSpaceFixtures.to_be_found_symbols.should include(:top_level_constant)
+ ObjectSpaceFixtures.to_be_found_symbols.should.include?(:top_level_constant)
end
it "finds an object stored in a second-level constant" do
- ObjectSpaceFixtures.to_be_found_symbols.should include(:second_level_constant)
+ ObjectSpaceFixtures.to_be_found_symbols.should.include?(:second_level_constant)
end
it "finds an object stored in a local variable" do
local = ObjectSpaceFixtures::ObjectToBeFound.new(:local)
- ObjectSpaceFixtures.to_be_found_symbols.should include(:local)
+ ObjectSpaceFixtures.to_be_found_symbols.should.include?(:local)
end
it "finds an object stored in a local variable captured in a block explicitly" do
@@ -69,7 +69,7 @@ describe "ObjectSpace.each_object" do
Proc.new { local_in_block }
}.call
- ObjectSpaceFixtures.to_be_found_symbols.should include(:local_in_block_explicit)
+ ObjectSpaceFixtures.to_be_found_symbols.should.include?(:local_in_block_explicit)
end
it "finds an object stored in a local variable captured in a block implicitly" do
@@ -78,11 +78,11 @@ describe "ObjectSpace.each_object" do
Proc.new { }
}.call
- ObjectSpaceFixtures.to_be_found_symbols.should include(:local_in_block_implicit)
+ ObjectSpaceFixtures.to_be_found_symbols.should.include?(:local_in_block_implicit)
end
it "finds an object stored in a local variable captured in by a method defined with a block" do
- ObjectSpaceFixtures.to_be_found_symbols.should include(:captured_by_define_method)
+ ObjectSpaceFixtures.to_be_found_symbols.should.include?(:captured_by_define_method)
end
it "finds an object stored in a local variable captured in a Proc#binding" do
@@ -91,7 +91,7 @@ describe "ObjectSpace.each_object" do
Proc.new { }.binding
}.call
- ObjectSpaceFixtures.to_be_found_symbols.should include(:local_in_proc_binding)
+ ObjectSpaceFixtures.to_be_found_symbols.should.include?(:local_in_proc_binding)
end
it "finds an object stored in a local variable captured in a Kernel#binding" do
@@ -100,45 +100,45 @@ describe "ObjectSpace.each_object" do
binding
}.call
- ObjectSpaceFixtures.to_be_found_symbols.should include(:local_in_kernel_binding)
+ ObjectSpaceFixtures.to_be_found_symbols.should.include?(:local_in_kernel_binding)
end
it "finds an object stored in a local variable set in a binding manually" do
b = binding
b.eval("local = ObjectSpaceFixtures::ObjectToBeFound.new(:local_in_manual_binding)")
- ObjectSpaceFixtures.to_be_found_symbols.should include(:local_in_manual_binding)
+ ObjectSpaceFixtures.to_be_found_symbols.should.include?(:local_in_manual_binding)
end
it "finds an object stored in an array" do
array = [ObjectSpaceFixtures::ObjectToBeFound.new(:array)]
- ObjectSpaceFixtures.to_be_found_symbols.should include(:array)
+ ObjectSpaceFixtures.to_be_found_symbols.should.include?(:array)
end
it "finds an object stored in a hash key" do
hash = {ObjectSpaceFixtures::ObjectToBeFound.new(:hash_key) => :value}
- ObjectSpaceFixtures.to_be_found_symbols.should include(:hash_key)
+ ObjectSpaceFixtures.to_be_found_symbols.should.include?(:hash_key)
end
it "finds an object stored in a hash value" do
hash = {a: ObjectSpaceFixtures::ObjectToBeFound.new(:hash_value)}
- ObjectSpaceFixtures.to_be_found_symbols.should include(:hash_value)
+ ObjectSpaceFixtures.to_be_found_symbols.should.include?(:hash_value)
end
it "finds an object stored in an instance variable" do
local = ObjectSpaceFixtures::ObjectWithInstanceVariable.new
- ObjectSpaceFixtures.to_be_found_symbols.should include(:instance_variable)
+ ObjectSpaceFixtures.to_be_found_symbols.should.include?(:instance_variable)
end
it "finds an object stored in a thread local" do
thread = Thread.new {}
thread.thread_variable_set(:object_space_thread_local, ObjectSpaceFixtures::ObjectToBeFound.new(:thread_local))
- ObjectSpaceFixtures.to_be_found_symbols.should include(:thread_local)
+ ObjectSpaceFixtures.to_be_found_symbols.should.include?(:thread_local)
thread.join
end
it "finds an object stored in a fiber local" do
Thread.current[:object_space_fiber_local] = ObjectSpaceFixtures::ObjectToBeFound.new(:fiber_local)
- ObjectSpaceFixtures.to_be_found_symbols.should include(:fiber_local)
+ ObjectSpaceFixtures.to_be_found_symbols.should.include?(:fiber_local)
end
it "finds an object captured in an at_exit handler" do
@@ -150,7 +150,7 @@ describe "ObjectSpace.each_object" do
end
}.call
- ObjectSpaceFixtures.to_be_found_symbols.should include(:at_exit)
+ ObjectSpaceFixtures.to_be_found_symbols.should.include?(:at_exit)
end
it "finds an object captured in finalizer" do
@@ -164,9 +164,9 @@ describe "ObjectSpace.each_object" do
})
}.call
- ObjectSpaceFixtures.to_be_found_symbols.should include(:finalizer)
+ ObjectSpaceFixtures.to_be_found_symbols.should.include?(:finalizer)
- alive.should_not be_nil
+ alive.should_not == nil
end
describe "on singleton classes" do
@@ -185,8 +185,8 @@ describe "ObjectSpace.each_object" do
end
it "walks singleton classes" do
- @sclass.should be_kind_of(@meta)
- ObjectSpace.each_object(@meta).to_a.should include(@sclass)
+ @sclass.should.is_a?(@meta)
+ ObjectSpace.each_object(@meta).to_a.should.include?(@sclass)
end
end
@@ -202,7 +202,7 @@ describe "ObjectSpace.each_object" do
expected = [ a, b, c, d ]
expected << c_sclass
- c_sclass.should be_kind_of(a.singleton_class)
+ c_sclass.should.is_a?(a.singleton_class)
b.extend Enumerable # included modules should not be walked
diff --git a/spec/ruby/core/objectspace/garbage_collect_spec.rb b/spec/ruby/core/objectspace/garbage_collect_spec.rb
index 521eaa8785..d2db22e0aa 100644
--- a/spec/ruby/core/objectspace/garbage_collect_spec.rb
+++ b/spec/ruby/core/objectspace/garbage_collect_spec.rb
@@ -3,7 +3,7 @@ require_relative '../../spec_helper'
describe "ObjectSpace.garbage_collect" do
it "can be invoked without any exceptions" do
- -> { ObjectSpace.garbage_collect }.should_not raise_error
+ -> { ObjectSpace.garbage_collect }.should_not.raise
end
it "accepts keyword arguments" do
@@ -11,7 +11,7 @@ describe "ObjectSpace.garbage_collect" do
end
it "ignores the supplied block" do
- -> { ObjectSpace.garbage_collect {} }.should_not raise_error
+ -> { ObjectSpace.garbage_collect {} }.should_not.raise
end
it "always returns nil" do
diff --git a/spec/ruby/core/objectspace/undefine_finalizer_spec.rb b/spec/ruby/core/objectspace/undefine_finalizer_spec.rb
index f57d5a7845..98ffc6a986 100644
--- a/spec/ruby/core/objectspace/undefine_finalizer_spec.rb
+++ b/spec/ruby/core/objectspace/undefine_finalizer_spec.rb
@@ -28,6 +28,6 @@ describe "ObjectSpace.undefine_finalizer" do
it "should raise when removing finalizers for a frozen object" do
obj = Object.new
obj.freeze
- -> { ObjectSpace.undefine_finalizer(obj) }.should raise_error(FrozenError)
+ -> { ObjectSpace.undefine_finalizer(obj) }.should.raise(FrozenError)
end
end
diff --git a/spec/ruby/core/objectspace/weakkeymap/clear_spec.rb b/spec/ruby/core/objectspace/weakkeymap/clear_spec.rb
index 8050e2c307..b1804ec9b0 100644
--- a/spec/ruby/core/objectspace/weakkeymap/clear_spec.rb
+++ b/spec/ruby/core/objectspace/weakkeymap/clear_spec.rb
@@ -1,27 +1,25 @@
require_relative '../../../spec_helper'
-ruby_version_is '3.3' do
- describe "ObjectSpace::WeakKeyMap#clear" do
- it "removes all the entries" do
- m = ObjectSpace::WeakKeyMap.new
+describe "ObjectSpace::WeakKeyMap#clear" do
+ it "removes all the entries" do
+ m = ObjectSpace::WeakKeyMap.new
- key = Object.new
- value = Object.new
- m[key] = value
+ key = Object.new
+ value = Object.new
+ m[key] = value
- key2 = Object.new
- value2 = Object.new
- m[key2] = value2
+ key2 = Object.new
+ value2 = Object.new
+ m[key2] = value2
- m.clear
+ m.clear
- m.key?(key).should == false
- m.key?(key2).should == false
- end
+ m.key?(key).should == false
+ m.key?(key2).should == false
+ end
- it "returns self" do
- m = ObjectSpace::WeakKeyMap.new
- m.clear.should.equal?(m)
- end
+ it "returns self" do
+ m = ObjectSpace::WeakKeyMap.new
+ m.clear.should.equal?(m)
end
end
diff --git a/spec/ruby/core/objectspace/weakkeymap/delete_spec.rb b/spec/ruby/core/objectspace/weakkeymap/delete_spec.rb
index 3cd61355d6..ad32c2c75e 100644
--- a/spec/ruby/core/objectspace/weakkeymap/delete_spec.rb
+++ b/spec/ruby/core/objectspace/weakkeymap/delete_spec.rb
@@ -1,51 +1,49 @@
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
+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
+ 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
+ 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
+ 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::WeakKeyMap.new
- m.delete(Object.new).should == nil
- end
+ it "returns nil if the key is not found when no block is given" do
+ m = ObjectSpace::WeakKeyMap.new
+ m.delete(Object.new).should == nil
+ end
- it "returns nil when a key cannot be garbage collected" do
- map = ObjectSpace::WeakKeyMap.new
+ it "returns nil when a key cannot be garbage collected" do
+ map = ObjectSpace::WeakKeyMap.new
- map.delete(1).should == nil
- map.delete(1.0).should == nil
- map.delete(:a).should == nil
- map.delete(true).should == nil
- map.delete(false).should == nil
- map.delete(nil).should == nil
- end
+ map.delete(1).should == nil
+ map.delete(1.0).should == nil
+ map.delete(:a).should == nil
+ map.delete(true).should == nil
+ map.delete(false).should == nil
+ map.delete(nil).should == nil
end
end
diff --git a/spec/ruby/core/objectspace/weakkeymap/element_reference_spec.rb b/spec/ruby/core/objectspace/weakkeymap/element_reference_spec.rb
index 51368e8d3b..53eff79c40 100644
--- a/spec/ruby/core/objectspace/weakkeymap/element_reference_spec.rb
+++ b/spec/ruby/core/objectspace/weakkeymap/element_reference_spec.rb
@@ -1,107 +1,105 @@
require_relative '../../../spec_helper'
require_relative 'fixtures/classes'
-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 "compares keys with #eql? semantics" do
- map = ObjectSpace::WeakKeyMap.new
- key = [1.0]
- map[key] = "x"
- map[[1]].should == nil
- map[[1.0]].should == "x"
- key.should == [1.0] # keep the key alive until here to keep the map entry
-
- map = ObjectSpace::WeakKeyMap.new
- key = [1]
- map[key] = "x"
- map[[1.0]].should == nil
- map[[1]].should == "x"
- key.should == [1] # keep the key alive until here to keep the map entry
-
- map = ObjectSpace::WeakKeyMap.new
- key1, key2 = %w[a a].map(&:upcase)
- ref = "x"
- map[key1] = ref
- map[key2].should == ref
- end
-
- it "compares key via #hash first" do
- x = mock('0')
- x.should_receive(:hash).and_return(0)
-
- map = ObjectSpace::WeakKeyMap.new
- key = 'foo'
- map[key] = :bar
- map[x].should == nil
- end
-
- it "does not compare keys with different #hash values via #eql?" do
- x = mock('x')
- x.should_not_receive(:eql?)
- x.stub!(:hash).and_return(0)
-
- y = mock('y')
- y.should_not_receive(:eql?)
- y.stub!(:hash).and_return(1)
-
- map = ObjectSpace::WeakKeyMap.new
- map[y] = 1
- map[x].should == nil
- end
-
- it "compares keys with the same #hash value via #eql?" do
- x = mock('x')
- x.should_receive(:eql?).and_return(true)
- x.stub!(:hash).and_return(42)
-
- y = mock('y')
- y.should_not_receive(:eql?)
- y.stub!(:hash).and_return(42)
-
- map = ObjectSpace::WeakKeyMap.new
- map[y] = 1
- map[x].should == 1
- end
-
- it "finds a value via an identical key even when its #eql? isn't reflexive" do
- x = mock('x')
- x.should_receive(:hash).at_least(1).and_return(42)
- x.stub!(:eql?).and_return(false) # Stubbed for clarity and latitude in implementation; not actually sent by MRI.
-
- map = ObjectSpace::WeakKeyMap.new
- map[x] = :x
- map[x].should == :x
- end
-
- it "supports keys with private #hash method" do
- key = WeakKeyMapSpecs::KeyWithPrivateHash.new
- map = ObjectSpace::WeakKeyMap.new
- map[key] = 42
- map[key].should == 42
- end
-
- it "returns nil and does not raise error when a key cannot be garbage collected" do
- map = ObjectSpace::WeakKeyMap.new
-
- map[1].should == nil
- map[1.0].should == nil
- map[:a].should == nil
- map[true].should == nil
- map[false].should == nil
- map[nil].should == nil
- end
+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 "compares keys with #eql? semantics" do
+ map = ObjectSpace::WeakKeyMap.new
+ key = [1.0]
+ map[key] = "x"
+ map[[1]].should == nil
+ map[[1.0]].should == "x"
+ key.should == [1.0] # keep the key alive until here to keep the map entry
+
+ map = ObjectSpace::WeakKeyMap.new
+ key = [1]
+ map[key] = "x"
+ map[[1.0]].should == nil
+ map[[1]].should == "x"
+ key.should == [1] # keep the key alive until here to keep the map entry
+
+ map = ObjectSpace::WeakKeyMap.new
+ key1, key2 = %w[a a].map(&:upcase)
+ ref = "x"
+ map[key1] = ref
+ map[key2].should == ref
+ end
+
+ it "compares key via #hash first" do
+ x = mock('0')
+ x.should_receive(:hash).and_return(0)
+
+ map = ObjectSpace::WeakKeyMap.new
+ key = 'foo'
+ map[key] = :bar
+ map[x].should == nil
+ end
+
+ it "does not compare keys with different #hash values via #eql?" do
+ x = mock('x')
+ x.should_not_receive(:eql?)
+ x.stub!(:hash).and_return(0)
+
+ y = mock('y')
+ y.should_not_receive(:eql?)
+ y.stub!(:hash).and_return(1)
+
+ map = ObjectSpace::WeakKeyMap.new
+ map[y] = 1
+ map[x].should == nil
+ end
+
+ it "compares keys with the same #hash value via #eql?" do
+ x = mock('x')
+ x.should_receive(:eql?).and_return(true)
+ x.stub!(:hash).and_return(42)
+
+ y = mock('y')
+ y.should_not_receive(:eql?)
+ y.stub!(:hash).and_return(42)
+
+ map = ObjectSpace::WeakKeyMap.new
+ map[y] = 1
+ map[x].should == 1
+ end
+
+ it "finds a value via an identical key even when its #eql? isn't reflexive" do
+ x = mock('x')
+ x.should_receive(:hash).at_least(1).and_return(42)
+ x.stub!(:eql?).and_return(false) # Stubbed for clarity and latitude in implementation; not actually sent by MRI.
+
+ map = ObjectSpace::WeakKeyMap.new
+ map[x] = :x
+ map[x].should == :x
+ end
+
+ it "supports keys with private #hash method" do
+ key = WeakKeyMapSpecs::KeyWithPrivateHash.new
+ map = ObjectSpace::WeakKeyMap.new
+ map[key] = 42
+ map[key].should == 42
+ end
+
+ it "returns nil and does not raise error when a key cannot be garbage collected" do
+ map = ObjectSpace::WeakKeyMap.new
+
+ map[1].should == nil
+ map[1.0].should == nil
+ map[:a].should == nil
+ map[true].should == nil
+ map[false].should == nil
+ map[nil].should == nil
end
end
diff --git a/spec/ruby/core/objectspace/weakkeymap/element_set_spec.rb b/spec/ruby/core/objectspace/weakkeymap/element_set_spec.rb
index 8db8d780c7..cf59aebc6f 100644
--- a/spec/ruby/core/objectspace/weakkeymap/element_set_spec.rb
+++ b/spec/ruby/core/objectspace/weakkeymap/element_set_spec.rb
@@ -1,82 +1,80 @@
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
+describe "ObjectSpace::WeakKeyMap#[]=" do
+ def should_accept(map, key, value)
+ (map[key] = value).should == value
+ map.should.key?(key)
+ map[key].should == value
+ 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(NoMethodError, /undefined method [`']hash' for an instance of BasicObject/)
+ end
- it "is correct" do
+ 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 "does not duplicate and freeze String keys (like Hash#[]= does)" do
+ map = ObjectSpace::WeakKeyMap.new
+ key = +"a"
+ map[key] = 1
+
+ map.getkey("a").should.equal? key
+ map.getkey("a").should_not.frozen?
+
+ key.should == "a" # keep the key alive until here to keep the map entry
+ end
+
+ context "a key cannot be garbage collected" do
+ it "raises ArgumentError when Integer is used as a key" 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
+ -> { map[1] = "x" }.should.raise(ArgumentError, /WeakKeyMap (keys )?must be garbage collectable/)
end
- it "requires the keys to implement #hash" do
+ it "raises ArgumentError when Float is used as a key" do
map = ObjectSpace::WeakKeyMap.new
- -> { map[BasicObject.new] = 1 }.should raise_error(NoMethodError, /undefined method [`']hash' for an instance of BasicObject/)
+ -> { map[1.0] = "x" }.should.raise(ArgumentError, /WeakKeyMap (keys )?must be garbage collectable/)
end
- it "accepts frozen keys or values" do
+ it "raises ArgumentError when Symbol is used as a key" 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)
+ -> { map[:a] = "x" }.should.raise(ArgumentError, /WeakKeyMap (keys )?must be garbage collectable/)
end
- it "does not duplicate and freeze String keys (like Hash#[]= does)" do
+ it "raises ArgumentError when true is used as a key" do
map = ObjectSpace::WeakKeyMap.new
- key = +"a"
- map[key] = 1
-
- map.getkey("a").should.equal? key
- map.getkey("a").should_not.frozen?
-
- key.should == "a" # keep the key alive until here to keep the map entry
+ -> { map[true] = "x" }.should.raise(ArgumentError, /WeakKeyMap (keys )?must be garbage collectable/)
end
- context "a key cannot be garbage collected" do
- it "raises ArgumentError when Integer is used as a key" do
- map = ObjectSpace::WeakKeyMap.new
- -> { map[1] = "x" }.should raise_error(ArgumentError, /WeakKeyMap (keys )?must be garbage collectable/)
- end
-
- it "raises ArgumentError when Float is used as a key" do
- map = ObjectSpace::WeakKeyMap.new
- -> { map[1.0] = "x" }.should raise_error(ArgumentError, /WeakKeyMap (keys )?must be garbage collectable/)
- end
-
- it "raises ArgumentError when Symbol is used as a key" do
- map = ObjectSpace::WeakKeyMap.new
- -> { map[:a] = "x" }.should raise_error(ArgumentError, /WeakKeyMap (keys )?must be garbage collectable/)
- end
-
- it "raises ArgumentError when true is used as a key" do
- map = ObjectSpace::WeakKeyMap.new
- -> { map[true] = "x" }.should raise_error(ArgumentError, /WeakKeyMap (keys )?must be garbage collectable/)
- end
-
- it "raises ArgumentError when false is used as a key" do
- map = ObjectSpace::WeakKeyMap.new
- -> { map[false] = "x" }.should raise_error(ArgumentError, /WeakKeyMap (keys )?must be garbage collectable/)
- end
+ it "raises ArgumentError when false is used as a key" do
+ map = ObjectSpace::WeakKeyMap.new
+ -> { map[false] = "x" }.should.raise(ArgumentError, /WeakKeyMap (keys )?must be garbage collectable/)
+ end
- it "raises ArgumentError when nil is used as a key" do
- map = ObjectSpace::WeakKeyMap.new
- -> { map[nil] = "x" }.should raise_error(ArgumentError, /WeakKeyMap (keys )?must be garbage collectable/)
- end
+ it "raises ArgumentError when nil is used as a key" do
+ map = ObjectSpace::WeakKeyMap.new
+ -> { map[nil] = "x" }.should.raise(ArgumentError, /WeakKeyMap (keys )?must be garbage collectable/)
end
end
end
diff --git a/spec/ruby/core/objectspace/weakkeymap/getkey_spec.rb b/spec/ruby/core/objectspace/weakkeymap/getkey_spec.rb
index 8a2dbf809d..798a2e2cda 100644
--- a/spec/ruby/core/objectspace/weakkeymap/getkey_spec.rb
+++ b/spec/ruby/core/objectspace/weakkeymap/getkey_spec.rb
@@ -1,28 +1,26 @@
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)
+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
+ map[key1] = true
+ map.getkey(key2).should.equal?(key1)
+ map.getkey("X").should == nil
- key1.should == "A" # keep the key alive until here to keep the map entry
- key2.should == "A" # keep the key alive until here to keep the map entry
- end
+ key1.should == "A" # keep the key alive until here to keep the map entry
+ key2.should == "A" # keep the key alive until here to keep the map entry
+ end
- it "returns nil when a key cannot be garbage collected" do
- map = ObjectSpace::WeakKeyMap.new
+ it "returns nil when a key cannot be garbage collected" do
+ map = ObjectSpace::WeakKeyMap.new
- map.getkey(1).should == nil
- map.getkey(1.0).should == nil
- map.getkey(:a).should == nil
- map.getkey(true).should == nil
- map.getkey(false).should == nil
- map.getkey(nil).should == nil
- end
+ map.getkey(1).should == nil
+ map.getkey(1.0).should == nil
+ map.getkey(:a).should == nil
+ map.getkey(true).should == nil
+ map.getkey(false).should == nil
+ map.getkey(nil).should == nil
end
end
diff --git a/spec/ruby/core/objectspace/weakkeymap/inspect_spec.rb b/spec/ruby/core/objectspace/weakkeymap/inspect_spec.rb
index 319f050970..b6bb469158 100644
--- a/spec/ruby/core/objectspace/weakkeymap/inspect_spec.rb
+++ b/spec/ruby/core/objectspace/weakkeymap/inspect_spec.rb
@@ -1,21 +1,19 @@
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/
+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/
- key1.should == "foo" # keep the key alive until here to keep the map entry
- key2.should == "bar" # keep the key alive until here to keep the map entry
- key3.should == "bar" # keep the key alive until here to keep the map entry
- end
+ key1.should == "foo" # keep the key alive until here to keep the map entry
+ key2.should == "bar" # keep the key alive until here to keep the map entry
+ key3.should == "bar" # keep the key alive until here to keep the map entry
end
end
diff --git a/spec/ruby/core/objectspace/weakkeymap/key_spec.rb b/spec/ruby/core/objectspace/weakkeymap/key_spec.rb
index a9a2e12432..e0b6866671 100644
--- a/spec/ruby/core/objectspace/weakkeymap/key_spec.rb
+++ b/spec/ruby/core/objectspace/weakkeymap/key_spec.rb
@@ -1,44 +1,42 @@
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]
+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
+ 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 "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
+ 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
- it "returns false when a key cannot be garbage collected" do
- map = ObjectSpace::WeakKeyMap.new
+ it "returns false when a key cannot be garbage collected" do
+ map = ObjectSpace::WeakKeyMap.new
- map.key?(1).should == false
- map.key?(1.0).should == false
- map.key?(:a).should == false
- map.key?(true).should == false
- map.key?(false).should == false
- map.key?(nil).should == false
- end
+ map.key?(1).should == false
+ map.key?(1.0).should == false
+ map.key?(:a).should == false
+ map.key?(true).should == false
+ map.key?(false).should == false
+ map.key?(nil).should == false
end
end
diff --git a/spec/ruby/core/objectspace/weakmap/delete_spec.rb b/spec/ruby/core/objectspace/weakmap/delete_spec.rb
index 302de264fb..03beebbb83 100644
--- a/spec/ruby/core/objectspace/weakmap/delete_spec.rb
+++ b/spec/ruby/core/objectspace/weakmap/delete_spec.rb
@@ -1,30 +1,28 @@
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
+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
+ 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
+ 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
+ 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
diff --git a/spec/ruby/core/objectspace/weakmap/each_pair_spec.rb b/spec/ruby/core/objectspace/weakmap/each_pair_spec.rb
index ea29edbd2f..272669ad0a 100644
--- a/spec/ruby/core/objectspace/weakmap/each_pair_spec.rb
+++ b/spec/ruby/core/objectspace/weakmap/each_pair_spec.rb
@@ -1,11 +1,8 @@
require_relative '../../../spec_helper'
-require_relative 'shared/members'
-require_relative 'shared/each'
describe "ObjectSpace::WeakMap#each_pair" do
- it_behaves_like :weakmap_members, -> map { a = []; map.each_pair{ |k,v| a << "#{k}#{v}" }; a }, %w[Ax By]
-end
-
-describe "ObjectSpace::WeakMap#each_key" do
- it_behaves_like :weakmap_each, :each_pair
+ it "is an alias of ObjectSpace::WeakMap#each" do
+ ObjectSpace::WeakMap.instance_method(:each_pair).should ==
+ ObjectSpace::WeakMap.instance_method(:each)
+ end
end
diff --git a/spec/ruby/core/objectspace/weakmap/each_spec.rb b/spec/ruby/core/objectspace/weakmap/each_spec.rb
index 46fcb66a6f..8493a36158 100644
--- a/spec/ruby/core/objectspace/weakmap/each_spec.rb
+++ b/spec/ruby/core/objectspace/weakmap/each_spec.rb
@@ -6,6 +6,6 @@ describe "ObjectSpace::WeakMap#each" do
it_behaves_like :weakmap_members, -> map { a = []; map.each{ |k,v| a << "#{k}#{v}" }; a }, %w[Ax By]
end
-describe "ObjectSpace::WeakMap#each_key" do
+describe "ObjectSpace::WeakMap#each" do
it_behaves_like :weakmap_each, :each
end
diff --git a/spec/ruby/core/objectspace/weakmap/each_value_spec.rb b/spec/ruby/core/objectspace/weakmap/each_value_spec.rb
index 65a1a7f6fe..89f2f6ae98 100644
--- a/spec/ruby/core/objectspace/weakmap/each_value_spec.rb
+++ b/spec/ruby/core/objectspace/weakmap/each_value_spec.rb
@@ -6,6 +6,6 @@ describe "ObjectSpace::WeakMap#each_value" do
it_behaves_like :weakmap_members, -> map { a = []; map.each_value{ |k| a << k }; a }, %w[x y]
end
-describe "ObjectSpace::WeakMap#each_key" do
+describe "ObjectSpace::WeakMap#each_value" do
it_behaves_like :weakmap_each, :each_value
end
diff --git a/spec/ruby/core/objectspace/weakmap/include_spec.rb b/spec/ruby/core/objectspace/weakmap/include_spec.rb
index 54ca6b3030..1affaef907 100644
--- a/spec/ruby/core/objectspace/weakmap/include_spec.rb
+++ b/spec/ruby/core/objectspace/weakmap/include_spec.rb
@@ -1,6 +1,32 @@
require_relative '../../../spec_helper'
-require_relative 'shared/include'
describe "ObjectSpace::WeakMap#include?" do
- it_behaves_like :weakmap_include?, :include?
+ it "recognizes keys in use" do
+ map = ObjectSpace::WeakMap.new
+ key1, key2 = %w[a b].map(&:upcase)
+ ref1, ref2 = %w[x y]
+
+ map[key1] = ref1
+ map.include?(key1).should == true
+ map[key1] = ref1
+ map.include?(key1).should == true
+ map[key2] = ref2
+ map.include?(key2).should == true
+ end
+
+ it "matches using identity semantics" do
+ map = ObjectSpace::WeakMap.new
+ key1, key2 = %w[a a].map(&:upcase)
+ ref = "x"
+ map[key1] = ref
+ map.include?(key2).should == false
+ end
+
+ it "reports true if the pair exists and the value is nil" do
+ map = ObjectSpace::WeakMap.new
+ key = Object.new
+ map[key] = nil
+ map.size.should == 1
+ map.include?(key).should == true
+ end
end
diff --git a/spec/ruby/core/objectspace/weakmap/key_spec.rb b/spec/ruby/core/objectspace/weakmap/key_spec.rb
index 999685ff95..5d38f1fa5f 100644
--- a/spec/ruby/core/objectspace/weakmap/key_spec.rb
+++ b/spec/ruby/core/objectspace/weakmap/key_spec.rb
@@ -1,6 +1,8 @@
require_relative '../../../spec_helper'
-require_relative 'shared/include'
describe "ObjectSpace::WeakMap#key?" do
- it_behaves_like :weakmap_include?, :key?
+ it "is an alias of ObjectSpace::WeakMap#include?" do
+ ObjectSpace::WeakMap.instance_method(:key?).should ==
+ ObjectSpace::WeakMap.instance_method(:include?)
+ end
end
diff --git a/spec/ruby/core/objectspace/weakmap/length_spec.rb b/spec/ruby/core/objectspace/weakmap/length_spec.rb
index 3a935648b1..8ad47aa9d6 100644
--- a/spec/ruby/core/objectspace/weakmap/length_spec.rb
+++ b/spec/ruby/core/objectspace/weakmap/length_spec.rb
@@ -1,6 +1,8 @@
require_relative '../../../spec_helper'
-require_relative 'shared/size'
describe "ObjectSpace::WeakMap#length" do
- it_behaves_like :weakmap_size, :length
+ it "is an alias of ObjectSpace::WeakMap#size" do
+ ObjectSpace::WeakMap.instance_method(:length).should ==
+ ObjectSpace::WeakMap.instance_method(:size)
+ end
end
diff --git a/spec/ruby/core/objectspace/weakmap/member_spec.rb b/spec/ruby/core/objectspace/weakmap/member_spec.rb
index cefb190ce7..eaf9a76285 100644
--- a/spec/ruby/core/objectspace/weakmap/member_spec.rb
+++ b/spec/ruby/core/objectspace/weakmap/member_spec.rb
@@ -1,6 +1,8 @@
require_relative '../../../spec_helper'
-require_relative 'shared/include'
describe "ObjectSpace::WeakMap#member?" do
- it_behaves_like :weakmap_include?, :member?
+ it "is an alias of ObjectSpace::WeakMap#include?" do
+ ObjectSpace::WeakMap.instance_method(:member?).should ==
+ ObjectSpace::WeakMap.instance_method(:include?)
+ end
end
diff --git a/spec/ruby/core/objectspace/weakmap/shared/each.rb b/spec/ruby/core/objectspace/weakmap/shared/each.rb
index 3d43a19347..771c416dde 100644
--- a/spec/ruby/core/objectspace/weakmap/shared/each.rb
+++ b/spec/ruby/core/objectspace/weakmap/shared/each.rb
@@ -5,6 +5,6 @@ describe :weakmap_each, shared: true do
ref = "x"
map.send(@method).should == map
map[key] = ref
- -> { map.send(@method) }.should raise_error(LocalJumpError)
+ -> { map.send(@method) }.should.raise(LocalJumpError)
end
end
diff --git a/spec/ruby/core/objectspace/weakmap/shared/include.rb b/spec/ruby/core/objectspace/weakmap/shared/include.rb
deleted file mode 100644
index 1770eeac8b..0000000000
--- a/spec/ruby/core/objectspace/weakmap/shared/include.rb
+++ /dev/null
@@ -1,30 +0,0 @@
-describe :weakmap_include?, shared: true do
- it "recognizes keys in use" do
- map = ObjectSpace::WeakMap.new
- key1, key2 = %w[a b].map(&:upcase)
- ref1, ref2 = %w[x y]
-
- map[key1] = ref1
- map.send(@method, key1).should == true
- map[key1] = ref1
- map.send(@method, key1).should == true
- map[key2] = ref2
- map.send(@method, key2).should == true
- end
-
- it "matches using identity semantics" do
- map = ObjectSpace::WeakMap.new
- key1, key2 = %w[a a].map(&:upcase)
- ref = "x"
- map[key1] = ref
- map.send(@method, key2).should == false
- end
-
- it "reports true if the pair exists and the value is nil" do
- map = ObjectSpace::WeakMap.new
- key = Object.new
- map[key] = nil
- map.size.should == 1
- map.send(@method, key).should == true
- end
-end
diff --git a/spec/ruby/core/objectspace/weakmap/shared/size.rb b/spec/ruby/core/objectspace/weakmap/shared/size.rb
deleted file mode 100644
index 1064f99d1b..0000000000
--- a/spec/ruby/core/objectspace/weakmap/shared/size.rb
+++ /dev/null
@@ -1,14 +0,0 @@
-describe :weakmap_size, shared: true do
- it "is correct" do
- map = ObjectSpace::WeakMap.new
- key1, key2 = %w[a b].map(&:upcase)
- ref1, ref2 = %w[x y]
- map.send(@method).should == 0
- map[key1] = ref1
- map.send(@method).should == 1
- map[key1] = ref1
- map.send(@method).should == 1
- map[key2] = ref2
- map.send(@method).should == 2
- end
-end
diff --git a/spec/ruby/core/objectspace/weakmap/size_spec.rb b/spec/ruby/core/objectspace/weakmap/size_spec.rb
index 1446abaa24..d301750c62 100644
--- a/spec/ruby/core/objectspace/weakmap/size_spec.rb
+++ b/spec/ruby/core/objectspace/weakmap/size_spec.rb
@@ -1,6 +1,16 @@
require_relative '../../../spec_helper'
-require_relative 'shared/size'
describe "ObjectSpace::WeakMap#size" do
- it_behaves_like :weakmap_size, :size
+ it "is correct" do
+ map = ObjectSpace::WeakMap.new
+ key1, key2 = %w[a b].map(&:upcase)
+ ref1, ref2 = %w[x y]
+ map.size.should == 0
+ map[key1] = ref1
+ map.size.should == 1
+ map[key1] = ref1
+ map.size.should == 1
+ map[key2] = ref2
+ map.size.should == 2
+ end
end
diff --git a/spec/ruby/core/proc/allocate_spec.rb b/spec/ruby/core/proc/allocate_spec.rb
index 54e1b69df9..96c4eb9fa8 100644
--- a/spec/ruby/core/proc/allocate_spec.rb
+++ b/spec/ruby/core/proc/allocate_spec.rb
@@ -4,6 +4,6 @@ describe "Proc.allocate" do
it "raises a TypeError" do
-> {
Proc.allocate
- }.should raise_error(TypeError)
+ }.should.raise(TypeError)
end
end
diff --git a/spec/ruby/core/proc/binding_spec.rb b/spec/ruby/core/proc/binding_spec.rb
index 86ab6bd400..d643cbf89c 100644
--- a/spec/ruby/core/proc/binding_spec.rb
+++ b/spec/ruby/core/proc/binding_spec.rb
@@ -3,7 +3,7 @@ require_relative '../../spec_helper'
describe "Proc#binding" do
it "returns a Binding instance" do
[Proc.new{}, -> {}, proc {}].each { |p|
- p.binding.should be_kind_of(Binding)
+ p.binding.should.is_a?(Binding)
}
end
diff --git a/spec/ruby/core/proc/block_pass_spec.rb b/spec/ruby/core/proc/block_pass_spec.rb
index 411c0bf3db..82c08db8a7 100644
--- a/spec/ruby/core/proc/block_pass_spec.rb
+++ b/spec/ruby/core/proc/block_pass_spec.rb
@@ -8,14 +8,14 @@ describe "Proc as a block pass argument" do
it "remains the same object if re-vivified by the target method" do
p = Proc.new {}
p2 = revivify(&p)
- p.should equal p2
+ p.should.equal? p2
p.should == p2
end
it "remains the same object if reconstructed with Proc.new" do
p = Proc.new {}
p2 = Proc.new(&p)
- p.should equal p2
+ p.should.equal? p2
p.should == p2
end
end
diff --git a/spec/ruby/core/proc/call_spec.rb b/spec/ruby/core/proc/call_spec.rb
index 6ec2fc8682..8b65be97c9 100644
--- a/spec/ruby/core/proc/call_spec.rb
+++ b/spec/ruby/core/proc/call_spec.rb
@@ -1,16 +1,138 @@
require_relative '../../spec_helper'
-require_relative 'shared/call'
-require_relative 'shared/call_arguments'
+require_relative 'fixtures/common'
+require_relative 'fixtures/proc_call'
+require_relative 'fixtures/proc_call_frozen'
describe "Proc#call" do
- it_behaves_like :proc_call, :call
- it_behaves_like :proc_call_block_args, :call
-end
+ it "invokes self" do
+ Proc.new { "test!" }.call.should == "test!"
+ -> { "test!" }.call.should == "test!"
+ proc { "test!" }.call.should == "test!"
+ end
-describe "Proc#call on a Proc created with Proc.new" do
- it_behaves_like :proc_call_on_proc_new, :call
-end
+ it "sets self's parameters to the given values" do
+ Proc.new { |a, b| a + b }.call(1, 2).should == 3
+ Proc.new { |*args| args }.call(1, 2, 3, 4).should == [1, 2, 3, 4]
+ Proc.new { |_, *args| args }.call(1, 2, 3).should == [2, 3]
+
+ -> a, b { a + b }.call(1, 2).should == 3
+ -> *args { args }.call(1, 2, 3, 4).should == [1, 2, 3, 4]
+ -> _, *args { args }.call(1, 2, 3).should == [2, 3]
+
+ proc { |a, b| a + b }.call(1, 2).should == 3
+ proc { |*args| args }.call(1, 2, 3, 4).should == [1, 2, 3, 4]
+ proc { |_, *args| args }.call(1, 2, 3).should == [2, 3]
+ end
+
+ it "can receive block arguments" do
+ Proc.new {|&b| b.call}.call {1 + 1}.should == 2
+ -> &b { b.call}.call {1 + 1}.should == 2
+ proc {|&b| b.call}.call {1 + 1}.should == 2
+ end
+
+ it "yields to the block given at declaration and not to the block argument" do
+ proc_creator = Object.new
+ def proc_creator.create
+ Proc.new do |&b|
+ yield
+ end
+ end
+ a_proc = proc_creator.create { 7 }
+ a_proc.call { 3 }.should == 7
+ end
+
+ it "can call its block argument declared with a block argument" do
+ proc_creator = Object.new
+ def proc_creator.create(method_name)
+ Proc.new do |&b|
+ yield + b.send(method_name)
+ end
+ end
+ a_proc = proc_creator.create(:call) { 7 }
+ a_proc.call { 3 }.should == 10
+ end
+
+ describe "on a Proc created with frozen_string_literal: true/false" do
+ it "doesn't duplicate frozen strings" do
+ ProcCallSpecs.call.frozen?.should == false
+ ProcCallSpecs.call_freeze.frozen?.should == true
+ ProcCallFrozenSpecs.call.frozen?.should == true
+ ProcCallFrozenSpecs.call_freeze.frozen?.should == true
+ end
+ end
+
+ context "on a Proc created with Proc.new" do
+ it "replaces missing arguments with nil" do
+ Proc.new { |a, b| [a, b] }.call.should == [nil, nil]
+ Proc.new { |a, b| [a, b] }.call(1).should == [1, nil]
+ end
+
+ it "silently ignores extra arguments" do
+ Proc.new { |a, b| a + b }.call(1, 2, 5).should == 3
+ end
+
+ it "auto-explodes a single Array argument" do
+ p = Proc.new { |a, b| [a, b] }
+ p.call(1, 2).should == [1, 2]
+ p.call([1, 2]).should == [1, 2]
+ p.call([1, 2, 3]).should == [1, 2]
+ p.call([1, 2, 3], 4).should == [[1, 2, 3], 4]
+ end
+ end
+
+ context "on a Proc created with Kernel#lambda or Kernel#proc" do
+ it "ignores excess arguments when self is a proc" do
+ a = proc {|x| x}.call(1, 2)
+ a.should == 1
+
+ a = proc {|x| x}.call(1, 2, 3)
+ a.should == 1
+
+ a = proc {|x:| x}.call(2, x: 1)
+ a.should == 1
+ end
+
+ it "will call #to_ary on argument and return self if return is nil" do
+ argument = ProcSpecs::ToAryAsNil.new
+ result = proc { |x, _| x }.call(argument)
+ result.should == argument
+ end
+
+ it "substitutes nil for missing arguments when self is a proc" do
+ proc {|x,y| [x,y]}.call.should == [nil,nil]
+
+ a = proc {|x,y| [x, y]}.call(1)
+ a.should == [1,nil]
+ end
+
+ it "raises an ArgumentError on excess arguments when self is a lambda" do
+ -> {
+ -> x { x }.call(1, 2)
+ }.should.raise(ArgumentError)
+
+ -> {
+ -> x { x }.call(1, 2, 3)
+ }.should.raise(ArgumentError)
+ end
+
+ it "raises an ArgumentError on missing arguments when self is a lambda" do
+ -> {
+ -> x { x }.call
+ }.should.raise(ArgumentError)
+
+ -> {
+ -> x, y { [x,y] }.call(1)
+ }.should.raise(ArgumentError)
+ end
+
+ it "treats a single Array argument as a single argument when self is a lambda" do
+ -> a { a }.call([1, 2]).should == [1, 2]
+ -> a, b { [a, b] }.call([1, 2], 3).should == [[1,2], 3]
+ end
-describe "Proc#call on a Proc created with Kernel#lambda or Kernel#proc" do
- it_behaves_like :proc_call_on_proc_or_lambda, :call
+ it "treats a single Array argument as a single argument when self is a proc" do
+ proc { |a| a }.call([1, 2]).should == [1, 2]
+ proc { |a, b| [a, b] }.call([1, 2], 3).should == [[1,2], 3]
+ end
+ end
end
diff --git a/spec/ruby/core/proc/case_compare_spec.rb b/spec/ruby/core/proc/case_compare_spec.rb
index f11513cdb9..421afb24f0 100644
--- a/spec/ruby/core/proc/case_compare_spec.rb
+++ b/spec/ruby/core/proc/case_compare_spec.rb
@@ -1,16 +1,7 @@
require_relative '../../spec_helper'
-require_relative 'shared/call'
-require_relative 'shared/call_arguments'
describe "Proc#===" do
- it_behaves_like :proc_call, :===
- it_behaves_like :proc_call_block_args, :===
-end
-
-describe "Proc#=== on a Proc created with Proc.new" do
- it_behaves_like :proc_call_on_proc_new, :===
-end
-
-describe "Proc#=== on a Proc created with Kernel#lambda or Kernel#proc" do
- it_behaves_like :proc_call_on_proc_or_lambda, :===
+ it "is an alias of Proc#call" do
+ Proc.instance_method(:===).should == Proc.instance_method(:call)
+ end
end
diff --git a/spec/ruby/core/proc/clone_spec.rb b/spec/ruby/core/proc/clone_spec.rb
index 730dc421a8..aee4873e09 100644
--- a/spec/ruby/core/proc/clone_spec.rb
+++ b/spec/ruby/core/proc/clone_spec.rb
@@ -5,7 +5,7 @@ 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
+ ruby_bug "cloning a frozen proc is broken on Ruby 3.3", ""..."3.4" do
it "preserves frozen status" do
proc = Proc.new { }
proc.freeze
@@ -14,17 +14,15 @@ describe "Proc#clone" do
end
end
- ruby_version_is "3.3" do
- it "calls #initialize_clone on subclass" do
- obj = ProcSpecs::MyProc2.new(:a, 2) { }
- dup = obj.clone
+ it "calls #initialize_clone on subclass" do
+ obj = ProcSpecs::MyProc2.new(:a, 2) { }
+ dup = obj.clone
- dup.should_not equal(obj)
- dup.class.should == ProcSpecs::MyProc2
+ dup.should_not.equal?(obj)
+ dup.class.should == ProcSpecs::MyProc2
- dup.first.should == :a
- dup.second.should == 2
- dup.initializer.should == :clone
- end
+ dup.first.should == :a
+ dup.second.should == 2
+ dup.initializer.should == :clone
end
end
diff --git a/spec/ruby/core/proc/curry_spec.rb b/spec/ruby/core/proc/curry_spec.rb
index 6daabe0ee1..de13983ca6 100644
--- a/spec/ruby/core/proc/curry_spec.rb
+++ b/spec/ruby/core/proc/curry_spec.rb
@@ -8,12 +8,12 @@ describe "Proc#curry" do
it "returns a Proc when called on a proc" do
p = proc { true }
- p.curry.should be_an_instance_of(Proc)
+ p.curry.should.instance_of?(Proc)
end
it "returns a Proc when called on a lambda" do
p = -> { true }
- p.curry.should be_an_instance_of(Proc)
+ p.curry.should.instance_of?(Proc)
end
it "calls the curried proc with the arguments if sufficient arguments have been given" do
@@ -23,11 +23,11 @@ describe "Proc#curry" do
it "returns a Proc that consumes the remainder of the arguments unless sufficient arguments have been given" do
proc2 = @proc_add.curry[1][2]
- proc2.should be_an_instance_of(Proc)
+ proc2.should.instance_of?(Proc)
proc2.call(3).should == 6
lambda2 = @lambda_add.curry[1][2]
- lambda2.should be_an_instance_of(Proc)
+ lambda2.should.instance_of?(Proc)
lambda2.call(3).should == 6
@proc_add.curry.call(1,2,3).should == 6
@@ -36,10 +36,10 @@ describe "Proc#curry" do
it "can be called multiple times on the same Proc" do
@proc_add.curry
- -> { @proc_add.curry }.should_not raise_error
+ -> { @proc_add.curry }.should_not.raise
@lambda_add.curry
- -> { @lambda_add.curry }.should_not raise_error
+ -> { @lambda_add.curry }.should_not.raise
end
it "can be passed superfluous arguments if created from a proc" do
@@ -49,8 +49,8 @@ describe "Proc#curry" do
end
it "raises an ArgumentError if passed superfluous arguments when created from a lambda" do
- -> { @lambda_add.curry[1,2,3,4] }.should raise_error(ArgumentError)
- -> { @lambda_add.curry[1,2].curry[3,4,5,6] }.should raise_error(ArgumentError)
+ -> { @lambda_add.curry[1,2,3,4] }.should.raise(ArgumentError)
+ -> { @lambda_add.curry[1,2].curry[3,4,5,6] }.should.raise(ArgumentError)
end
it "returns Procs with arities of -1" do
@@ -63,7 +63,7 @@ describe "Proc#curry" do
it "produces Procs that raise ArgumentError for #binding" do
-> do
@proc_add.curry.binding
- end.should raise_error(ArgumentError)
+ end.should.raise(ArgumentError)
end
it "produces Procs that return [[:rest]] for #parameters" do
@@ -98,41 +98,41 @@ describe "Proc#curry with arity argument" do
end
it "accepts an optional Integer argument for the arity" do
- -> { @proc_add.curry(3) }.should_not raise_error
- -> { @lambda_add.curry(3) }.should_not raise_error
+ -> { @proc_add.curry(3) }.should_not.raise
+ -> { @lambda_add.curry(3) }.should_not.raise
end
it "returns a Proc when called on a proc" do
- @proc_add.curry(3).should be_an_instance_of(Proc)
+ @proc_add.curry(3).should.instance_of?(Proc)
end
it "returns a Proc when called on a lambda" do
- @lambda_add.curry(3).should be_an_instance_of(Proc)
+ @lambda_add.curry(3).should.instance_of?(Proc)
end
# [ruby-core:24127]
it "retains the lambda-ness of the Proc on which its called" do
- @lambda_add.curry(3).lambda?.should be_true
- @proc_add.curry(3).lambda?.should be_false
+ @lambda_add.curry(3).lambda?.should == true
+ @proc_add.curry(3).lambda?.should == false
end
it "raises an ArgumentError if called on a lambda that requires more than _arity_ arguments" do
- -> { @lambda_add.curry(2) }.should raise_error(ArgumentError)
- -> { -> x, y, z, *more{}.curry(2) }.should raise_error(ArgumentError)
+ -> { @lambda_add.curry(2) }.should.raise(ArgumentError)
+ -> { -> x, y, z, *more{}.curry(2) }.should.raise(ArgumentError)
end
it 'returns a Proc if called on a lambda that requires fewer than _arity_ arguments but may take more' do
- -> a, b, c, d=nil, e=nil {}.curry(4).should be_an_instance_of(Proc)
- -> a, b, c, d=nil, *e {}.curry(4).should be_an_instance_of(Proc)
- -> a, b, c, *d {}.curry(4).should be_an_instance_of(Proc)
+ -> a, b, c, d=nil, e=nil {}.curry(4).should.instance_of?(Proc)
+ -> a, b, c, d=nil, *e {}.curry(4).should.instance_of?(Proc)
+ -> a, b, c, *d {}.curry(4).should.instance_of?(Proc)
end
it "raises an ArgumentError if called on a lambda that requires fewer than _arity_ arguments" do
- -> { @lambda_add.curry(4) }.should raise_error(ArgumentError)
- -> { -> { true }.curry(1) }.should raise_error(ArgumentError)
- -> { -> a, b=nil {}.curry(5) }.should raise_error(ArgumentError)
- -> { -> a, &b {}.curry(2) }.should raise_error(ArgumentError)
- -> { -> a, b=nil, &c {}.curry(3) }.should raise_error(ArgumentError)
+ -> { @lambda_add.curry(4) }.should.raise(ArgumentError)
+ -> { -> { true }.curry(1) }.should.raise(ArgumentError)
+ -> { -> a, b=nil {}.curry(5) }.should.raise(ArgumentError)
+ -> { -> a, &b {}.curry(2) }.should.raise(ArgumentError)
+ -> { -> a, b=nil, &c {}.curry(3) }.should.raise(ArgumentError)
end
it "calls the curried proc with the arguments if _arity_ arguments have been given" do
@@ -142,20 +142,20 @@ describe "Proc#curry with arity argument" do
it "returns a Proc that consumes the remainder of the arguments when fewer than _arity_ arguments are given" do
proc2 = @proc_add.curry(3)[1][2]
- proc2.should be_an_instance_of(Proc)
+ proc2.should.instance_of?(Proc)
proc2.call(3).should == 6
lambda2 = @lambda_add.curry(3)[1][2]
- lambda2.should be_an_instance_of(Proc)
+ lambda2.should.instance_of?(Proc)
lambda2.call(3).should == 6
end
it "can be specified multiple times on the same Proc" do
@proc_add.curry(2)
- -> { @proc_add.curry(1) }.should_not raise_error
+ -> { @proc_add.curry(1) }.should_not.raise
@lambda_add.curry(3)
- -> { @lambda_add.curry(3) }.should_not raise_error
+ -> { @lambda_add.curry(3) }.should_not.raise
end
it "can be passed more than _arity_ arguments if created from a proc" do
@@ -165,8 +165,8 @@ describe "Proc#curry with arity argument" do
end
it "raises an ArgumentError if passed more than _arity_ arguments when created from a lambda" do
- -> { @lambda_add.curry(3)[1,2,3,4] }.should raise_error(ArgumentError)
- -> { @lambda_add.curry(3)[1,2].curry(3)[3,4,5,6] }.should raise_error(ArgumentError)
+ -> { @lambda_add.curry(3)[1,2,3,4] }.should.raise(ArgumentError)
+ -> { @lambda_add.curry(3)[1,2].curry(3)[3,4,5,6] }.should.raise(ArgumentError)
end
it "returns Procs with arities of -1 regardless of the value of _arity_" do
diff --git a/spec/ruby/core/proc/dup_spec.rb b/spec/ruby/core/proc/dup_spec.rb
index 716357d1f0..8604389422 100644
--- a/spec/ruby/core/proc/dup_spec.rb
+++ b/spec/ruby/core/proc/dup_spec.rb
@@ -12,17 +12,15 @@ describe "Proc#dup" do
proc.dup.frozen?.should == false
end
- ruby_version_is "3.3" do
- it "calls #initialize_dup on subclass" do
- obj = ProcSpecs::MyProc2.new(:a, 2) { }
- dup = obj.dup
+ it "calls #initialize_dup on subclass" do
+ obj = ProcSpecs::MyProc2.new(:a, 2) { }
+ dup = obj.dup
- dup.should_not equal(obj)
- dup.class.should == ProcSpecs::MyProc2
+ dup.should_not.equal?(obj)
+ dup.class.should == ProcSpecs::MyProc2
- dup.first.should == :a
- dup.second.should == 2
- dup.initializer.should == :dup
- end
+ dup.first.should == :a
+ dup.second.should == 2
+ dup.initializer.should == :dup
end
end
diff --git a/spec/ruby/core/proc/element_reference_spec.rb b/spec/ruby/core/proc/element_reference_spec.rb
index 9077e44c34..ac14292464 100644
--- a/spec/ruby/core/proc/element_reference_spec.rb
+++ b/spec/ruby/core/proc/element_reference_spec.rb
@@ -1,27 +1,7 @@
require_relative '../../spec_helper'
-require_relative 'shared/call'
-require_relative 'shared/call_arguments'
-require_relative 'fixtures/proc_aref'
-require_relative 'fixtures/proc_aref_frozen'
describe "Proc#[]" do
- it_behaves_like :proc_call, :[]
- it_behaves_like :proc_call_block_args, :[]
-end
-
-describe "Proc#call on a Proc created with Proc.new" do
- it_behaves_like :proc_call_on_proc_new, :call
-end
-
-describe "Proc#call on a Proc created with Kernel#lambda or Kernel#proc" do
- it_behaves_like :proc_call_on_proc_or_lambda, :call
-end
-
-describe "Proc#[] with frozen_string_literals" do
- it "doesn't duplicate frozen strings" do
- ProcArefSpecs.aref.frozen?.should be_false
- ProcArefSpecs.aref_freeze.frozen?.should be_true
- ProcArefFrozenSpecs.aref.frozen?.should be_true
- ProcArefFrozenSpecs.aref_freeze.frozen?.should be_true
+ it "is an alias of Proc#call" do
+ Proc.instance_method(:[]).should == Proc.instance_method(:call)
end
end
diff --git a/spec/ruby/core/proc/eql_spec.rb b/spec/ruby/core/proc/eql_spec.rb
index ad8f6749fc..1a5fb42a0e 100644
--- a/spec/ruby/core/proc/eql_spec.rb
+++ b/spec/ruby/core/proc/eql_spec.rb
@@ -1,6 +1,7 @@
require_relative '../../spec_helper'
-require_relative 'shared/equal'
describe "Proc#eql?" do
- it_behaves_like :proc_equal, :eql?
+ it "is an alias of Proc#==" do
+ Proc.instance_method(:eql?).should == Proc.instance_method(:==)
+ end
end
diff --git a/spec/ruby/core/proc/equal_value_spec.rb b/spec/ruby/core/proc/equal_value_spec.rb
index ec7f274732..92e462152e 100644
--- a/spec/ruby/core/proc/equal_value_spec.rb
+++ b/spec/ruby/core/proc/equal_value_spec.rb
@@ -1,6 +1,83 @@
require_relative '../../spec_helper'
-require_relative 'shared/equal'
+require_relative 'fixtures/common'
describe "Proc#==" do
- it_behaves_like :proc_equal, :==
+ it "is a public method" do
+ Proc.public_instance_methods(false).should.include?(:==)
+ end
+
+ it "returns true if self and other are the same object" do
+ p = proc { :foo }
+ (p == p).should == true
+
+ p = Proc.new { :foo }
+ (p == p).should == true
+
+ p = -> { :foo }
+ (p == p).should == true
+ end
+
+ it "returns true if other is a dup of the original" do
+ p = proc { :foo }
+ (p == p.dup).should == true
+
+ p = Proc.new { :foo }
+ (p == p.dup).should == true
+
+ p = -> { :foo }
+ (p == p.dup).should == true
+ end
+
+ # identical here means the same method invocation.
+ it "returns false when bodies are the same but capture env is not identical" do
+ a = ProcSpecs.proc_for_1
+ b = ProcSpecs.proc_for_1
+
+ (a == b).should == false
+ end
+
+ it "returns false if procs are distinct but have the same body and environment" do
+ p = proc { :foo }
+ p2 = proc { :foo }
+ (p == p2).should == false
+ end
+
+ it "returns false if lambdas are distinct but have same body and environment" do
+ x = -> { :foo }
+ x2 = -> { :foo }
+ (x == x2).should == false
+ end
+
+ it "returns false if using comparing lambda to proc, even with the same body and env" do
+ p = -> { :foo }
+ p2 = proc { :foo }
+ (p == p2).should == false
+
+ x = proc { :bar }
+ x2 = -> { :bar }
+ (x == x2).should == false
+ end
+
+ it "returns false if other is not a Proc" do
+ p = proc { :foo }
+ (p == []).should == false
+
+ p = Proc.new { :foo }
+ (p == Object.new).should == false
+
+ p = -> { :foo }
+ (p == :foo).should == false
+ end
+
+ it "returns false if self and other are both procs but have different bodies" do
+ p = proc { :bar }
+ p2 = proc { :foo }
+ (p == p2).should == false
+ end
+
+ it "returns false if self and other are both lambdas but have different bodies" do
+ p = -> { :foo }
+ p2 = -> { :bar }
+ (p == p2).should == false
+ end
end
diff --git a/spec/ruby/core/proc/fixtures/proc_aref.rb b/spec/ruby/core/proc/fixtures/proc_aref.rb
deleted file mode 100644
index 8ee355b14c..0000000000
--- a/spec/ruby/core/proc/fixtures/proc_aref.rb
+++ /dev/null
@@ -1,10 +0,0 @@
-# frozen_string_literal: false
-module ProcArefSpecs
- def self.aref
- proc {|a| a }["sometext"]
- end
-
- def self.aref_freeze
- proc {|a| a }["sometext".freeze]
- end
-end
diff --git a/spec/ruby/core/proc/fixtures/proc_aref_frozen.rb b/spec/ruby/core/proc/fixtures/proc_aref_frozen.rb
deleted file mode 100644
index 50a330ba4f..0000000000
--- a/spec/ruby/core/proc/fixtures/proc_aref_frozen.rb
+++ /dev/null
@@ -1,10 +0,0 @@
-# frozen_string_literal: true
-module ProcArefFrozenSpecs
- def self.aref
- proc {|a| a }["sometext"]
- end
-
- def self.aref_freeze
- proc {|a| a }["sometext".freeze]
- end
-end
diff --git a/spec/ruby/core/proc/fixtures/proc_call.rb b/spec/ruby/core/proc/fixtures/proc_call.rb
new file mode 100644
index 0000000000..32048f5319
--- /dev/null
+++ b/spec/ruby/core/proc/fixtures/proc_call.rb
@@ -0,0 +1,10 @@
+# frozen_string_literal: false
+module ProcCallSpecs
+ def self.call
+ proc {|a| a }.call("sometext")
+ end
+
+ def self.call_freeze
+ proc {|a| a }.call("sometext".freeze)
+ end
+end
diff --git a/spec/ruby/core/proc/fixtures/proc_call_frozen.rb b/spec/ruby/core/proc/fixtures/proc_call_frozen.rb
new file mode 100644
index 0000000000..29ffc3c4c9
--- /dev/null
+++ b/spec/ruby/core/proc/fixtures/proc_call_frozen.rb
@@ -0,0 +1,10 @@
+# frozen_string_literal: true
+module ProcCallFrozenSpecs
+ def self.call
+ proc {|a| a }.call("sometext")
+ end
+
+ def self.call_freeze
+ proc {|a| a }.call("sometext".freeze)
+ end
+end
diff --git a/spec/ruby/core/proc/hash_spec.rb b/spec/ruby/core/proc/hash_spec.rb
index ebe0fde1a0..adcb1ccb78 100644
--- a/spec/ruby/core/proc/hash_spec.rb
+++ b/spec/ruby/core/proc/hash_spec.rb
@@ -2,12 +2,12 @@ require_relative '../../spec_helper'
describe "Proc#hash" do
it "is provided" do
- proc {}.respond_to?(:hash).should be_true
- -> {}.respond_to?(:hash).should be_true
+ proc {}.respond_to?(:hash).should == true
+ -> {}.respond_to?(:hash).should == true
end
it "returns an Integer" do
- proc { 1 + 489 }.hash.should be_kind_of(Integer)
+ proc { 1 + 489 }.hash.should.is_a?(Integer)
end
it "is stable" do
diff --git a/spec/ruby/core/proc/inspect_spec.rb b/spec/ruby/core/proc/inspect_spec.rb
index f53d34116f..96995ec410 100644
--- a/spec/ruby/core/proc/inspect_spec.rb
+++ b/spec/ruby/core/proc/inspect_spec.rb
@@ -1,6 +1,7 @@
require_relative '../../spec_helper'
-require_relative 'shared/to_s'
describe "Proc#inspect" do
- it_behaves_like :proc_to_s, :inspect
+ it "is an alias of Proc#to_s" do
+ Proc.instance_method(:inspect).should == Proc.instance_method(:to_s)
+ end
end
diff --git a/spec/ruby/core/proc/lambda_spec.rb b/spec/ruby/core/proc/lambda_spec.rb
index 5c3c38fc2a..1ff6147319 100644
--- a/spec/ruby/core/proc/lambda_spec.rb
+++ b/spec/ruby/core/proc/lambda_spec.rb
@@ -3,60 +3,53 @@ require_relative 'fixtures/common'
describe "Proc#lambda?" do
it "returns true if the Proc was created from a block with the lambda keyword" do
- -> {}.lambda?.should be_true
+ -> {}.lambda?.should == true
end
it "returns false if the Proc was created from a block with the proc keyword" do
- proc {}.lambda?.should be_false
+ proc {}.lambda?.should == false
end
it "returns false if the Proc was created from a block with Proc.new" 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
+ Proc.new {}.lambda?.should == false
end
it "is preserved when passing a Proc with & to the proc keyword" do
- proc(&->{}).lambda?.should be_true
- proc(&proc{}).lambda?.should be_false
+ proc(&->{}).lambda?.should == true
+ proc(&proc{}).lambda?.should == false
end
it "is preserved when passing a Proc with & to Proc.new" do
- Proc.new(&->{}).lambda?.should be_true
- Proc.new(&proc{}).lambda?.should be_false
+ Proc.new(&->{}).lambda?.should == true
+ Proc.new(&proc{}).lambda?.should == false
end
it "returns false if the Proc was created from a block with &" do
- ProcSpecs.new_proc_from_amp{}.lambda?.should be_false
+ ProcSpecs.new_proc_from_amp{}.lambda?.should == false
end
it "is preserved when the Proc was passed using &" do
- ProcSpecs.new_proc_from_amp(&->{}).lambda?.should be_true
- ProcSpecs.new_proc_from_amp(&proc{}).lambda?.should be_false
- ProcSpecs.new_proc_from_amp(&Proc.new{}).lambda?.should be_false
+ ProcSpecs.new_proc_from_amp(&->{}).lambda?.should == true
+ ProcSpecs.new_proc_from_amp(&proc{}).lambda?.should == false
+ ProcSpecs.new_proc_from_amp(&Proc.new{}).lambda?.should == false
end
it "returns true for a Method converted to a Proc" do
m = :foo.method(:to_s)
- m.to_proc.lambda?.should be_true
- ProcSpecs.new_proc_from_amp(&m).lambda?.should be_true
+ m.to_proc.lambda?.should == true
+ ProcSpecs.new_proc_from_amp(&m).lambda?.should == true
end
# [ruby-core:24127]
it "is preserved when a Proc is curried" do
- ->{}.curry.lambda?.should be_true
- proc{}.curry.lambda?.should be_false
- Proc.new{}.curry.lambda?.should be_false
+ ->{}.curry.lambda?.should == true
+ proc{}.curry.lambda?.should == false
+ Proc.new{}.curry.lambda?.should == false
end
it "is preserved when a curried Proc is called without enough arguments" do
- -> x, y{}.curry.call(42).lambda?.should be_true
- proc{|x,y|}.curry.call(42).lambda?.should be_false
- Proc.new{|x,y|}.curry.call(42).lambda?.should be_false
+ -> x, y{}.curry.call(42).lambda?.should == true
+ proc{|x,y|}.curry.call(42).lambda?.should == false
+ Proc.new{|x,y|}.curry.call(42).lambda?.should == false
end
end
diff --git a/spec/ruby/core/proc/new_spec.rb b/spec/ruby/core/proc/new_spec.rb
index b2b7387756..f0b817f0cb 100644
--- a/spec/ruby/core/proc/new_spec.rb
+++ b/spec/ruby/core/proc/new_spec.rb
@@ -71,7 +71,7 @@ describe "Proc.new with an associated block" do
end
res = some_method()
- -> { res.call }.should raise_error(LocalJumpError)
+ -> { res.call }.should.raise(LocalJumpError)
end
it "returns from within enclosing method when 'return' is used in the block" do
@@ -86,7 +86,7 @@ describe "Proc.new with an associated block" do
it "returns a subclass of Proc" do
obj = ProcSpecs::MyProc.new { }
- obj.should be_kind_of(ProcSpecs::MyProc)
+ obj.should.is_a?(ProcSpecs::MyProc)
end
it "calls initialize on the Proc object" do
@@ -101,7 +101,7 @@ describe "Proc.new with a block argument" do
passed_prc = Proc.new { "hello".size }
prc = Proc.new(&passed_prc)
- prc.should equal(passed_prc)
+ prc.should.equal?(passed_prc)
prc.call.should == 5
end
@@ -110,7 +110,7 @@ describe "Proc.new with a block argument" do
passed_prc = Proc.new(&method)
prc = Proc.new(&passed_prc)
- prc.should equal(passed_prc)
+ prc.should.equal?(passed_prc)
prc.call.should == 5
end
@@ -118,7 +118,7 @@ describe "Proc.new with a block argument" do
passed_prc = Proc.new(&:size)
prc = Proc.new(&passed_prc)
- prc.should equal(passed_prc)
+ prc.should.equal?(passed_prc)
prc.call("hello").should == 5
end
end
@@ -129,7 +129,7 @@ describe "Proc.new with a block argument called indirectly from a subclass" do
passed_prc.class.should == ProcSpecs::MyProc
prc = ProcSpecs::MyProc.new(&passed_prc)
- prc.should equal(passed_prc)
+ prc.should.equal?(passed_prc)
prc.call.should == 5
end
@@ -139,7 +139,7 @@ describe "Proc.new with a block argument called indirectly from a subclass" do
passed_prc.class.should == ProcSpecs::MyProc
prc = ProcSpecs::MyProc.new(&passed_prc)
- prc.should equal(passed_prc)
+ prc.should.equal?(passed_prc)
prc.call.should == 5
end
@@ -148,22 +148,22 @@ describe "Proc.new with a block argument called indirectly from a subclass" do
passed_prc.class.should == ProcSpecs::MyProc
prc = ProcSpecs::MyProc.new(&passed_prc)
- prc.should equal(passed_prc)
+ prc.should.equal?(passed_prc)
prc.call("hello").should == 5
end
end
describe "Proc.new without a block" do
it "raises an ArgumentError" do
- -> { Proc.new }.should raise_error(ArgumentError)
+ -> { Proc.new }.should.raise(ArgumentError)
end
it "raises an ArgumentError if invoked from within a method with no block" do
- -> { ProcSpecs.new_proc_in_method }.should raise_error(ArgumentError)
+ -> { ProcSpecs.new_proc_in_method }.should.raise(ArgumentError)
end
it "raises an ArgumentError if invoked on a subclass from within a method with no block" do
- -> { ProcSpecs.new_proc_subclass_in_method }.should raise_error(ArgumentError)
+ -> { ProcSpecs.new_proc_subclass_in_method }.should.raise(ArgumentError)
end
it "raises an ArgumentError when passed no block" do
@@ -171,8 +171,8 @@ describe "Proc.new without a block" do
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')
+ -> { ProcSpecs.new_proc_in_method { "hello" } }.should.raise(ArgumentError, 'tried to create Proc object without a block')
+ -> { ProcSpecs.new_proc_subclass_in_method { "hello" } }.should.raise(ArgumentError, 'tried to create Proc object without a block')
+ -> { some_method { "hello" } }.should.raise(ArgumentError, 'tried to create Proc object without a block')
end
end
diff --git a/spec/ruby/core/proc/parameters_spec.rb b/spec/ruby/core/proc/parameters_spec.rb
index e9bc9a1c57..ac8c6e3560 100644
--- a/spec/ruby/core/proc/parameters_spec.rb
+++ b/spec/ruby/core/proc/parameters_spec.rb
@@ -7,8 +7,8 @@ describe "Proc#parameters" do
it "returns an Array of Arrays for a proc expecting parameters" do
p = proc {|x| }
- p.parameters.should be_an_instance_of(Array)
- p.parameters.first.should be_an_instance_of(Array)
+ p.parameters.should.instance_of?(Array)
+ p.parameters.first.should.instance_of?(Array)
end
it "sets the first element of each sub-Array to :opt for optional arguments" do
@@ -158,4 +158,26 @@ describe "Proc#parameters" do
it "returns :nokey for **nil parameter" do
proc { |**nil| }.parameters.should == [[:nokey]]
end
+
+ ruby_version_is "3.4"..."4.0" do
+ it "handles the usage of `it` as a parameter" do
+ eval("proc { it }").parameters.should == [[:opt, nil]]
+ eval("lambda { it }").parameters.should == [[:req]]
+ end
+ end
+
+ ruby_version_is "4.0" do
+ it "handles the usage of `it` as a parameter" do
+ eval("proc { it }").parameters.should == [[:opt]]
+ eval("lambda { it }").parameters.should == [[:req]]
+ end
+ end
+
+ ruby_version_is "4.1" do
+ it "returns :noblock for &nil parameter" do
+ eval <<~RUBY
+ proc { |&nil| }.parameters.should == [[:noblock]]
+ RUBY
+ end
+ end
end
diff --git a/spec/ruby/core/proc/ruby2_keywords_spec.rb b/spec/ruby/core/proc/ruby2_keywords_spec.rb
index 030eeeeb68..e06fad8693 100644
--- a/spec/ruby/core/proc/ruby2_keywords_spec.rb
+++ b/spec/ruby/core/proc/ruby2_keywords_spec.rb
@@ -27,7 +27,7 @@ describe "Proc#ruby2_keywords" do
it "returns self" do
f = -> *a { }
- f.ruby2_keywords.should equal f
+ f.ruby2_keywords.should.equal? f
end
it "prints warning when a proc does not accept argument splat" do
@@ -54,7 +54,7 @@ describe "Proc#ruby2_keywords" do
}.should complain(/Skipping set of ruby2_keywords flag for/)
end
- ruby_version_is "3.5" do
+ ruby_version_is "4.0" do
it "prints warning when a proc accepts post arguments" do
f = -> *a, b { }
diff --git a/spec/ruby/core/proc/shared/call.rb b/spec/ruby/core/proc/shared/call.rb
deleted file mode 100644
index dbec34df4b..0000000000
--- a/spec/ruby/core/proc/shared/call.rb
+++ /dev/null
@@ -1,99 +0,0 @@
-require_relative '../fixtures/common'
-
-describe :proc_call, shared: true do
- it "invokes self" do
- Proc.new { "test!" }.send(@method).should == "test!"
- -> { "test!" }.send(@method).should == "test!"
- proc { "test!" }.send(@method).should == "test!"
- end
-
- it "sets self's parameters to the given values" do
- Proc.new { |a, b| a + b }.send(@method, 1, 2).should == 3
- Proc.new { |*args| args }.send(@method, 1, 2, 3, 4).should == [1, 2, 3, 4]
- Proc.new { |_, *args| args }.send(@method, 1, 2, 3).should == [2, 3]
-
- -> a, b { a + b }.send(@method, 1, 2).should == 3
- -> *args { args }.send(@method, 1, 2, 3, 4).should == [1, 2, 3, 4]
- -> _, *args { args }.send(@method, 1, 2, 3).should == [2, 3]
-
- proc { |a, b| a + b }.send(@method, 1, 2).should == 3
- proc { |*args| args }.send(@method, 1, 2, 3, 4).should == [1, 2, 3, 4]
- proc { |_, *args| args }.send(@method, 1, 2, 3).should == [2, 3]
- end
-end
-
-
-describe :proc_call_on_proc_new, shared: true do
- it "replaces missing arguments with nil" do
- Proc.new { |a, b| [a, b] }.send(@method).should == [nil, nil]
- Proc.new { |a, b| [a, b] }.send(@method, 1).should == [1, nil]
- end
-
- it "silently ignores extra arguments" do
- Proc.new { |a, b| a + b }.send(@method, 1, 2, 5).should == 3
- end
-
- it "auto-explodes a single Array argument" do
- p = Proc.new { |a, b| [a, b] }
- p.send(@method, 1, 2).should == [1, 2]
- p.send(@method, [1, 2]).should == [1, 2]
- p.send(@method, [1, 2, 3]).should == [1, 2]
- p.send(@method, [1, 2, 3], 4).should == [[1, 2, 3], 4]
- end
-end
-
-describe :proc_call_on_proc_or_lambda, shared: true do
- it "ignores excess arguments when self is a proc" do
- a = proc {|x| x}.send(@method, 1, 2)
- a.should == 1
-
- a = proc {|x| x}.send(@method, 1, 2, 3)
- a.should == 1
-
- a = proc {|x:| x}.send(@method, 2, x: 1)
- a.should == 1
- end
-
- it "will call #to_ary on argument and return self if return is nil" do
- argument = ProcSpecs::ToAryAsNil.new
- result = proc { |x, _| x }.send(@method, argument)
- result.should == argument
- end
-
- it "substitutes nil for missing arguments when self is a proc" do
- proc {|x,y| [x,y]}.send(@method).should == [nil,nil]
-
- a = proc {|x,y| [x, y]}.send(@method, 1)
- a.should == [1,nil]
- end
-
- it "raises an ArgumentError on excess arguments when self is a lambda" do
- -> {
- -> x { x }.send(@method, 1, 2)
- }.should raise_error(ArgumentError)
-
- -> {
- -> x { x }.send(@method, 1, 2, 3)
- }.should raise_error(ArgumentError)
- end
-
- it "raises an ArgumentError on missing arguments when self is a lambda" do
- -> {
- -> x { x }.send(@method)
- }.should raise_error(ArgumentError)
-
- -> {
- -> x, y { [x,y] }.send(@method, 1)
- }.should raise_error(ArgumentError)
- end
-
- it "treats a single Array argument as a single argument when self is a lambda" do
- -> a { a }.send(@method, [1, 2]).should == [1, 2]
- -> a, b { [a, b] }.send(@method, [1, 2], 3).should == [[1,2], 3]
- end
-
- it "treats a single Array argument as a single argument when self is a proc" do
- proc { |a| a }.send(@method, [1, 2]).should == [1, 2]
- proc { |a, b| [a, b] }.send(@method, [1, 2], 3).should == [[1,2], 3]
- end
-end
diff --git a/spec/ruby/core/proc/shared/call_arguments.rb b/spec/ruby/core/proc/shared/call_arguments.rb
deleted file mode 100644
index 91ada3439e..0000000000
--- a/spec/ruby/core/proc/shared/call_arguments.rb
+++ /dev/null
@@ -1,29 +0,0 @@
-describe :proc_call_block_args, shared: true do
- it "can receive block arguments" do
- Proc.new {|&b| b.send(@method)}.send(@method) {1 + 1}.should == 2
- -> &b { b.send(@method)}.send(@method) {1 + 1}.should == 2
- proc {|&b| b.send(@method)}.send(@method) {1 + 1}.should == 2
- end
-
- it "yields to the block given at declaration and not to the block argument" do
- proc_creator = Object.new
- def proc_creator.create
- Proc.new do |&b|
- yield
- end
- end
- a_proc = proc_creator.create { 7 }
- a_proc.send(@method) { 3 }.should == 7
- end
-
- it "can call its block argument declared with a block argument" do
- proc_creator = Object.new
- def proc_creator.create(method_name)
- Proc.new do |&b|
- yield + b.send(method_name)
- end
- end
- a_proc = proc_creator.create(@method) { 7 }
- a_proc.call { 3 }.should == 10
- end
-end
diff --git a/spec/ruby/core/proc/shared/compose.rb b/spec/ruby/core/proc/shared/compose.rb
index 3d3f3b310d..c004cec7c9 100644
--- a/spec/ruby/core/proc/shared/compose.rb
+++ b/spec/ruby/core/proc/shared/compose.rb
@@ -5,7 +5,7 @@ describe :proc_compose, shared: true do
-> {
lhs.send(@method, not_callable)
- }.should raise_error(TypeError, "callable object is expected")
+ }.should.raise(TypeError, "callable object is expected")
end
@@ -17,6 +17,6 @@ describe :proc_compose, shared: true do
-> {
lhs.send(@method, succ)
- }.should raise_error(TypeError, "callable object is expected")
+ }.should.raise(TypeError, "callable object is expected")
end
end
diff --git a/spec/ruby/core/proc/shared/dup.rb b/spec/ruby/core/proc/shared/dup.rb
index 1266337f94..2821d2e00f 100644
--- a/spec/ruby/core/proc/shared/dup.rb
+++ b/spec/ruby/core/proc/shared/dup.rb
@@ -3,7 +3,7 @@ describe :proc_dup, shared: true do
a = -> { "hello" }
b = a.send(@method)
- a.should_not equal(b)
+ a.should_not.equal?(b)
a.call.should == b.call
end
diff --git a/spec/ruby/core/proc/shared/equal.rb b/spec/ruby/core/proc/shared/equal.rb
deleted file mode 100644
index d0503fb064..0000000000
--- a/spec/ruby/core/proc/shared/equal.rb
+++ /dev/null
@@ -1,83 +0,0 @@
-require_relative '../../../spec_helper'
-require_relative '../fixtures/common'
-
-describe :proc_equal, shared: true do
- it "is a public method" do
- Proc.should have_public_instance_method(@method, false)
- end
-
- it "returns true if self and other are the same object" do
- p = proc { :foo }
- p.send(@method, p).should be_true
-
- p = Proc.new { :foo }
- p.send(@method, p).should be_true
-
- p = -> { :foo }
- p.send(@method, p).should be_true
- end
-
- it "returns true if other is a dup of the original" do
- p = proc { :foo }
- p.send(@method, p.dup).should be_true
-
- p = Proc.new { :foo }
- p.send(@method, p.dup).should be_true
-
- p = -> { :foo }
- p.send(@method, p.dup).should be_true
- end
-
- # identical here means the same method invocation.
- it "returns false when bodies are the same but capture env is not identical" do
- a = ProcSpecs.proc_for_1
- b = ProcSpecs.proc_for_1
-
- a.send(@method, b).should be_false
- end
-
- it "returns false if procs are distinct but have the same body and environment" do
- p = proc { :foo }
- p2 = proc { :foo }
- p.send(@method, p2).should be_false
- end
-
- it "returns false if lambdas are distinct but have same body and environment" do
- x = -> { :foo }
- x2 = -> { :foo }
- x.send(@method, x2).should be_false
- end
-
- it "returns false if using comparing lambda to proc, even with the same body and env" do
- p = -> { :foo }
- p2 = proc { :foo }
- p.send(@method, p2).should be_false
-
- x = proc { :bar }
- x2 = -> { :bar }
- x.send(@method, x2).should be_false
- end
-
- it "returns false if other is not a Proc" do
- p = proc { :foo }
- p.send(@method, []).should be_false
-
- p = Proc.new { :foo }
- p.send(@method, Object.new).should be_false
-
- p = -> { :foo }
- p.send(@method, :foo).should be_false
- end
-
- it "returns false if self and other are both procs but have different bodies" do
- p = proc { :bar }
- p2 = proc { :foo }
- p.send(@method, p2).should be_false
- end
-
- it "returns false if self and other are both lambdas but have different bodies" do
- p = -> { :foo }
- p2 = -> { :bar }
- p.send(@method, p2).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
deleted file mode 100644
index a52688a89f..0000000000
--- a/spec/ruby/core/proc/shared/to_s.rb
+++ /dev/null
@@ -1,60 +0,0 @@
-describe :proc_to_s, shared: true do
- describe "for a proc created with Proc.new" do
- it "returns a description including file and line number" do
- Proc.new { "hello" }.send(@method).should =~ /^#<Proc:([^ ]*?) #{Regexp.escape __FILE__}:#{__LINE__ }>$/
- end
-
- it "has a binary encoding" do
- Proc.new { "hello" }.send(@method).encoding.should == Encoding::BINARY
- end
- end
-
- describe "for a proc created with lambda" do
- it "returns a description including '(lambda)' and including file and line number" do
- -> { "hello" }.send(@method).should =~ /^#<Proc:([^ ]*?) #{Regexp.escape __FILE__}:#{__LINE__ } \(lambda\)>$/
- end
-
- it "has a binary encoding" do
- -> { "hello" }.send(@method).encoding.should == Encoding::BINARY
- end
- end
-
- describe "for a proc created with proc" do
- it "returns a description including file and line number" do
- proc { "hello" }.send(@method).should =~ /^#<Proc:([^ ]*?) #{Regexp.escape __FILE__}:#{__LINE__ }>$/
- end
-
- it "has a binary encoding" do
- proc { "hello" }.send(@method).encoding.should == Encoding::BINARY
- end
- end
-
- 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
- end
-
- it "has a binary encoding" do
- def hello; end
- method("hello").to_proc.send(@method).encoding.should == Encoding::BINARY
- end
- end
-
- describe "for a proc created with Symbol#to_proc" do
- it "returns a description including '(&:symbol)'" do
- proc = :foobar.to_proc
- proc.send(@method).should.include?('(&:foobar)')
- end
-
- it "has a binary encoding" do
- proc = :foobar.to_proc
- proc.send(@method).encoding.should == Encoding::BINARY
- end
- end
-end
diff --git a/spec/ruby/core/proc/source_location_spec.rb b/spec/ruby/core/proc/source_location_spec.rb
index 484466f577..d27ad0559e 100644
--- a/spec/ruby/core/proc/source_location_spec.rb
+++ b/spec/ruby/core/proc/source_location_spec.rb
@@ -10,71 +10,64 @@ describe "Proc#source_location" do
end
it "returns an Array" do
- @proc.source_location.should be_an_instance_of(Array)
- @proc_new.source_location.should be_an_instance_of(Array)
- @lambda.source_location.should be_an_instance_of(Array)
- @method.source_location.should be_an_instance_of(Array)
+ @proc.source_location.should.instance_of?(Array)
+ @proc_new.source_location.should.instance_of?(Array)
+ @lambda.source_location.should.instance_of?(Array)
+ @method.source_location.should.instance_of?(Array)
end
it "sets the first value to the path of the file in which the proc was defined" do
- file = @proc.source_location[0]
- file.should be_an_instance_of(String)
+ file = @proc.source_location.first
+ file.should.instance_of?(String)
file.should == File.realpath('fixtures/source_location.rb', __dir__)
- file = @proc_new.source_location[0]
- file.should be_an_instance_of(String)
+ file = @proc_new.source_location.first
+ file.should.instance_of?(String)
file.should == File.realpath('fixtures/source_location.rb', __dir__)
- file = @lambda.source_location[0]
- file.should be_an_instance_of(String)
+ file = @lambda.source_location.first
+ file.should.instance_of?(String)
file.should == File.realpath('fixtures/source_location.rb', __dir__)
- file = @method.source_location[0]
- file.should be_an_instance_of(String)
+ file = @method.source_location.first
+ file.should.instance_of?(String)
file.should == File.realpath('fixtures/source_location.rb', __dir__)
end
- it "sets the second value to an Integer representing the line on which the proc was defined" do
- line = @proc.source_location[1]
- line.should be_an_instance_of(Integer)
+ it "sets the last value to an Integer representing the line on which the proc was defined" do
+ line = @proc.source_location.last
+ line.should.instance_of?(Integer)
line.should == 4
- line = @proc_new.source_location[1]
- line.should be_an_instance_of(Integer)
+ line = @proc_new.source_location.last
+ line.should.instance_of?(Integer)
line.should == 12
- line = @lambda.source_location[1]
- line.should be_an_instance_of(Integer)
+ line = @lambda.source_location.last
+ line.should.instance_of?(Integer)
line.should == 8
- line = @method.source_location[1]
- line.should be_an_instance_of(Integer)
+ line = @method.source_location.last
+ line.should.instance_of?(Integer)
line.should == 15
end
it "works even if the proc was created on the same line" do
- ruby_version_is(""..."3.5") do
- proc { true }.source_location.should == [__FILE__, __LINE__]
- Proc.new { true }.source_location.should == [__FILE__, __LINE__]
- -> { true }.source_location.should == [__FILE__, __LINE__]
- end
- ruby_version_is("3.5") do
- proc { true }.source_location.should == [__FILE__, __LINE__, 11, __LINE__, 19]
- Proc.new { true }.source_location.should == [__FILE__, __LINE__, 15, __LINE__, 23]
- -> { true }.source_location.should == [__FILE__, __LINE__, 8, __LINE__, 17]
- end
+ proc { true }.source_location.should == [__FILE__, __LINE__]
+ Proc.new { true }.source_location.should == [__FILE__, __LINE__]
+ -> { true }.source_location.should == [__FILE__, __LINE__]
end
it "returns the first line of a multi-line proc (i.e. the line containing 'proc do')" do
- ProcSpecs::SourceLocation.my_multiline_proc.source_location[1].should == 20
- ProcSpecs::SourceLocation.my_multiline_proc_new.source_location[1].should == 34
- ProcSpecs::SourceLocation.my_multiline_lambda.source_location[1].should == 27
+ ProcSpecs::SourceLocation.my_multiline_proc.source_location.last.should == 20
+ ProcSpecs::SourceLocation.my_multiline_proc_new.source_location.last.should == 34
+ ProcSpecs::SourceLocation.my_multiline_lambda.source_location.last.should == 27
end
it "returns the location of the proc's body; not necessarily the proc itself" do
- ProcSpecs::SourceLocation.my_detached_proc.source_location[1].should == 41
- ProcSpecs::SourceLocation.my_detached_proc_new.source_location[1].should == 51
- ProcSpecs::SourceLocation.my_detached_lambda.source_location[1].should == 46
+ ProcSpecs::SourceLocation.my_detached_proc.source_location.last.should == 41
+ ProcSpecs::SourceLocation.my_detached_proc_new.source_location.last.should == 51
+ ProcSpecs::SourceLocation.my_detached_lambda.source_location.last.should == 46
end
it "returns the same value for a proc-ified method as the method reports" do
@@ -93,12 +86,6 @@ describe "Proc#source_location" do
it "works for eval with a given line" do
proc = eval('-> {}', nil, "foo", 100)
- location = proc.source_location
- ruby_version_is(""..."3.5") do
- location.should == ["foo", 100]
- end
- ruby_version_is("3.5") do
- location.should == ["foo", 100, 2, 100, 5]
- end
+ proc.source_location.should == ["foo", 100]
end
end
diff --git a/spec/ruby/core/proc/to_proc_spec.rb b/spec/ruby/core/proc/to_proc_spec.rb
index ffaa34929b..7f35a4f19b 100644
--- a/spec/ruby/core/proc/to_proc_spec.rb
+++ b/spec/ruby/core/proc/to_proc_spec.rb
@@ -3,7 +3,7 @@ require_relative '../../spec_helper'
describe "Proc#to_proc" do
it "returns self" do
[Proc.new {}, -> {}, proc {}].each { |p|
- p.to_proc.should equal(p)
+ p.to_proc.should.equal?(p)
}
end
end
diff --git a/spec/ruby/core/proc/to_s_spec.rb b/spec/ruby/core/proc/to_s_spec.rb
index 5e9c46b6b8..58a9aa76fb 100644
--- a/spec/ruby/core/proc/to_s_spec.rb
+++ b/spec/ruby/core/proc/to_s_spec.rb
@@ -1,6 +1,62 @@
require_relative '../../spec_helper'
-require_relative 'shared/to_s'
describe "Proc#to_s" do
- it_behaves_like :proc_to_s, :to_s
+ describe "for a proc created with Proc.new" do
+ it "returns a description including file and line number" do
+ Proc.new { "hello" }.to_s.should =~ /^#<Proc:([^ ]*?) #{Regexp.escape __FILE__}:#{__LINE__ }>$/
+ end
+
+ it "has a binary encoding" do
+ Proc.new { "hello" }.to_s.encoding.should == Encoding::BINARY
+ end
+ end
+
+ describe "for a proc created with lambda" do
+ it "returns a description including '(lambda)' and including file and line number" do
+ -> { "hello" }.to_s.should =~ /^#<Proc:([^ ]*?) #{Regexp.escape __FILE__}:#{__LINE__ } \(lambda\)>$/
+ end
+
+ it "has a binary encoding" do
+ -> { "hello" }.to_s.encoding.should == Encoding::BINARY
+ end
+ end
+
+ describe "for a proc created with proc" do
+ it "returns a description including file and line number" do
+ proc { "hello" }.to_s.should =~ /^#<Proc:([^ ]*?) #{Regexp.escape __FILE__}:#{__LINE__ }>$/
+ end
+
+ it "has a binary encoding" do
+ proc { "hello" }.to_s.encoding.should == Encoding::BINARY
+ end
+ end
+
+ 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.to_s
+ 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
+ def hello; end
+ method("hello").to_proc.to_s.encoding.should == Encoding::BINARY
+ end
+ end
+
+ describe "for a proc created with Symbol#to_proc" do
+ it "returns a description including '(&:symbol)'" do
+ proc = :foobar.to_proc
+ proc.to_s.should.include?('(&:foobar)')
+ end
+
+ it "has a binary encoding" do
+ proc = :foobar.to_proc
+ proc.to_s.encoding.should == Encoding::BINARY
+ end
+ end
end
diff --git a/spec/ruby/core/proc/yield_spec.rb b/spec/ruby/core/proc/yield_spec.rb
index 365d5b04bd..e6ee2d5eff 100644
--- a/spec/ruby/core/proc/yield_spec.rb
+++ b/spec/ruby/core/proc/yield_spec.rb
@@ -1,16 +1,7 @@
require_relative '../../spec_helper'
-require_relative 'shared/call'
-require_relative 'shared/call_arguments'
describe "Proc#yield" do
- it_behaves_like :proc_call, :yield
- it_behaves_like :proc_call_block_args, :yield
-end
-
-describe "Proc#yield on a Proc created with Proc.new" do
- it_behaves_like :proc_call_on_proc_new, :yield
-end
-
-describe "Proc#yield on a Proc created with Kernel#lambda or Kernel#proc" do
- it_behaves_like :proc_call_on_proc_or_lambda, :yield
+ it "is an alias of Proc#call" do
+ Proc.instance_method(:yield).should == Proc.instance_method(:call)
+ end
end
diff --git a/spec/ruby/core/process/_fork_spec.rb b/spec/ruby/core/process/_fork_spec.rb
index e1f45e2656..620f243ce5 100644
--- a/spec/ruby/core/process/_fork_spec.rb
+++ b/spec/ruby/core/process/_fork_spec.rb
@@ -9,7 +9,7 @@ describe "Process._fork" do
# are that _fork is implemented if and only if fork is (see above).
guard_not -> { Process.respond_to?(:fork) } do
it "raises a NotImplementedError when called" do
- -> { Process._fork }.should raise_error(NotImplementedError)
+ -> { Process._fork }.should.raise(NotImplementedError)
end
end
@@ -18,7 +18,7 @@ describe "Process._fork" do
Process.should_receive(:_fork).once.and_return(42)
pid = Process.fork {}
- pid.should equal(42)
+ pid.should.equal?(42)
end
end
end
diff --git a/spec/ruby/core/process/argv0_spec.rb b/spec/ruby/core/process/argv0_spec.rb
index f5aba719e9..4c7a2c9ecb 100644
--- a/spec/ruby/core/process/argv0_spec.rb
+++ b/spec/ruby/core/process/argv0_spec.rb
@@ -2,7 +2,7 @@ require_relative '../../spec_helper'
describe "Process.argv0" do
it "returns a String" do
- Process.argv0.should be_kind_of(String)
+ Process.argv0.should.is_a?(String)
end
it "is the path given as the main script and the same as __FILE__" do
@@ -13,10 +13,8 @@ describe "Process.argv0" do
end
end
- ruby_bug "#19597", ""..."3.3" do
- it "returns a frozen object" do
- Process.argv0.should.frozen?
- end
+ it "returns a frozen object" do
+ Process.argv0.should.frozen?
end
it "returns every time the same object" do
diff --git a/spec/ruby/core/process/clock_gettime_spec.rb b/spec/ruby/core/process/clock_gettime_spec.rb
index 6c1a52f21e..88158904e1 100644
--- a/spec/ruby/core/process/clock_gettime_spec.rb
+++ b/spec/ruby/core/process/clock_gettime_spec.rb
@@ -4,31 +4,31 @@ require_relative 'fixtures/clocks'
describe "Process.clock_gettime" do
ProcessSpecs.clock_constants.each do |name, value|
it "can be called with Process::#{name}" do
- Process.clock_gettime(value).should be_an_instance_of(Float)
+ Process.clock_gettime(value).should.instance_of?(Float)
end
end
describe 'time units' do
it 'handles a fixed set of time units' do
[:nanosecond, :microsecond, :millisecond, :second].each do |unit|
- Process.clock_gettime(Process::CLOCK_MONOTONIC, unit).should be_kind_of(Integer)
+ Process.clock_gettime(Process::CLOCK_MONOTONIC, unit).should.is_a?(Integer)
end
[:float_microsecond, :float_millisecond, :float_second].each do |unit|
- Process.clock_gettime(Process::CLOCK_MONOTONIC, unit).should be_an_instance_of(Float)
+ Process.clock_gettime(Process::CLOCK_MONOTONIC, unit).should.instance_of?(Float)
end
end
it 'raises an ArgumentError for an invalid time unit' do
- -> { Process.clock_gettime(Process::CLOCK_MONOTONIC, :bad) }.should raise_error(ArgumentError)
+ -> { Process.clock_gettime(Process::CLOCK_MONOTONIC, :bad) }.should.raise(ArgumentError)
end
it 'defaults to :float_second' do
t1 = Process.clock_gettime(Process::CLOCK_MONOTONIC)
t2 = Process.clock_gettime(Process::CLOCK_MONOTONIC, :float_second)
- t1.should be_an_instance_of(Float)
- t2.should be_an_instance_of(Float)
+ t1.should.instance_of?(Float)
+ t2.should.instance_of?(Float)
t2.should be_close(t1, TIME_TOLERANCE)
end
@@ -36,116 +36,116 @@ describe "Process.clock_gettime" do
t1 = Process.clock_gettime(Process::CLOCK_MONOTONIC, nil)
t2 = Process.clock_gettime(Process::CLOCK_MONOTONIC, :float_second)
- t1.should be_an_instance_of(Float)
- t2.should be_an_instance_of(Float)
+ t1.should.instance_of?(Float)
+ t2.should.instance_of?(Float)
t2.should be_close(t1, TIME_TOLERANCE)
end
end
describe "supports the platform clocks mentioned in the documentation" do
it "CLOCK_REALTIME" do
- Process.clock_gettime(Process::CLOCK_REALTIME).should be_an_instance_of(Float)
+ Process.clock_gettime(Process::CLOCK_REALTIME).should.instance_of?(Float)
end
it "CLOCK_MONOTONIC" do
- Process.clock_gettime(Process::CLOCK_MONOTONIC).should be_an_instance_of(Float)
+ Process.clock_gettime(Process::CLOCK_MONOTONIC).should.instance_of?(Float)
end
# These specs need macOS 10.12+ / darwin 16+
guard -> { platform_is_not(:darwin) or kernel_version_is '16' } do
platform_is :linux, :openbsd, :darwin do
it "CLOCK_PROCESS_CPUTIME_ID" do
- Process.clock_gettime(Process::CLOCK_PROCESS_CPUTIME_ID).should be_an_instance_of(Float)
+ Process.clock_gettime(Process::CLOCK_PROCESS_CPUTIME_ID).should.instance_of?(Float)
end
end
platform_is :linux, :freebsd, :openbsd, :darwin do
it "CLOCK_THREAD_CPUTIME_ID" do
- Process.clock_gettime(Process::CLOCK_THREAD_CPUTIME_ID).should be_an_instance_of(Float)
+ Process.clock_gettime(Process::CLOCK_THREAD_CPUTIME_ID).should.instance_of?(Float)
end
end
platform_is :linux, :darwin do
it "CLOCK_MONOTONIC_RAW" do
- Process.clock_gettime(Process::CLOCK_MONOTONIC_RAW).should be_an_instance_of(Float)
+ Process.clock_gettime(Process::CLOCK_MONOTONIC_RAW).should.instance_of?(Float)
end
end
platform_is :darwin do
it "CLOCK_MONOTONIC_RAW_APPROX" do
- Process.clock_gettime(Process::CLOCK_MONOTONIC_RAW_APPROX).should be_an_instance_of(Float)
+ Process.clock_gettime(Process::CLOCK_MONOTONIC_RAW_APPROX).should.instance_of?(Float)
end
it "CLOCK_UPTIME_RAW and CLOCK_UPTIME_RAW_APPROX" do
- Process.clock_gettime(Process::CLOCK_UPTIME_RAW).should be_an_instance_of(Float)
- Process.clock_gettime(Process::CLOCK_UPTIME_RAW_APPROX).should be_an_instance_of(Float)
+ Process.clock_gettime(Process::CLOCK_UPTIME_RAW).should.instance_of?(Float)
+ Process.clock_gettime(Process::CLOCK_UPTIME_RAW_APPROX).should.instance_of?(Float)
end
end
end
platform_is :freebsd do
it "CLOCK_VIRTUAL" do
- Process.clock_gettime(Process::CLOCK_VIRTUAL).should be_an_instance_of(Float)
+ Process.clock_gettime(Process::CLOCK_VIRTUAL).should.instance_of?(Float)
end
it "CLOCK_PROF" do
- Process.clock_gettime(Process::CLOCK_PROF).should be_an_instance_of(Float)
+ Process.clock_gettime(Process::CLOCK_PROF).should.instance_of?(Float)
end
end
platform_is :freebsd, :openbsd do
it "CLOCK_UPTIME" do
- Process.clock_gettime(Process::CLOCK_UPTIME).should be_an_instance_of(Float)
+ Process.clock_gettime(Process::CLOCK_UPTIME).should.instance_of?(Float)
end
end
platform_is :freebsd do
it "CLOCK_REALTIME_FAST and CLOCK_REALTIME_PRECISE" do
- Process.clock_gettime(Process::CLOCK_REALTIME_FAST).should be_an_instance_of(Float)
- Process.clock_gettime(Process::CLOCK_REALTIME_PRECISE).should be_an_instance_of(Float)
+ Process.clock_gettime(Process::CLOCK_REALTIME_FAST).should.instance_of?(Float)
+ Process.clock_gettime(Process::CLOCK_REALTIME_PRECISE).should.instance_of?(Float)
end
it "CLOCK_MONOTONIC_FAST and CLOCK_MONOTONIC_PRECISE" do
- Process.clock_gettime(Process::CLOCK_MONOTONIC_FAST).should be_an_instance_of(Float)
- Process.clock_gettime(Process::CLOCK_MONOTONIC_PRECISE).should be_an_instance_of(Float)
+ Process.clock_gettime(Process::CLOCK_MONOTONIC_FAST).should.instance_of?(Float)
+ Process.clock_gettime(Process::CLOCK_MONOTONIC_PRECISE).should.instance_of?(Float)
end
it "CLOCK_UPTIME_FAST and CLOCK_UPTIME_PRECISE" do
- Process.clock_gettime(Process::CLOCK_UPTIME_FAST).should be_an_instance_of(Float)
- Process.clock_gettime(Process::CLOCK_UPTIME_PRECISE).should be_an_instance_of(Float)
+ Process.clock_gettime(Process::CLOCK_UPTIME_FAST).should.instance_of?(Float)
+ Process.clock_gettime(Process::CLOCK_UPTIME_PRECISE).should.instance_of?(Float)
end
it "CLOCK_SECOND" do
- Process.clock_gettime(Process::CLOCK_SECOND).should be_an_instance_of(Float)
+ Process.clock_gettime(Process::CLOCK_SECOND).should.instance_of?(Float)
end
end
guard -> { platform_is :linux and kernel_version_is '2.6.32' } do
it "CLOCK_REALTIME_COARSE" do
- Process.clock_gettime(Process::CLOCK_REALTIME_COARSE).should be_an_instance_of(Float)
+ Process.clock_gettime(Process::CLOCK_REALTIME_COARSE).should.instance_of?(Float)
end
it "CLOCK_MONOTONIC_COARSE" do
- Process.clock_gettime(Process::CLOCK_MONOTONIC_COARSE).should be_an_instance_of(Float)
+ Process.clock_gettime(Process::CLOCK_MONOTONIC_COARSE).should.instance_of?(Float)
end
end
guard -> { platform_is :linux and kernel_version_is '2.6.39' } do
it "CLOCK_BOOTTIME" do
skip "No Process::CLOCK_BOOTTIME" unless defined?(Process::CLOCK_BOOTTIME)
- Process.clock_gettime(Process::CLOCK_BOOTTIME).should be_an_instance_of(Float)
+ Process.clock_gettime(Process::CLOCK_BOOTTIME).should.instance_of?(Float)
end
end
guard -> { platform_is "x86_64-linux" and kernel_version_is '3.0' } do
it "CLOCK_REALTIME_ALARM" do
skip "No Process::CLOCK_REALTIME_ALARM" unless defined?(Process::CLOCK_REALTIME_ALARM)
- Process.clock_gettime(Process::CLOCK_REALTIME_ALARM).should be_an_instance_of(Float)
+ Process.clock_gettime(Process::CLOCK_REALTIME_ALARM).should.instance_of?(Float)
end
it "CLOCK_BOOTTIME_ALARM" do
skip "No Process::CLOCK_BOOTTIME_ALARM" unless defined?(Process::CLOCK_BOOTTIME_ALARM)
- Process.clock_gettime(Process::CLOCK_BOOTTIME_ALARM).should be_an_instance_of(Float)
+ Process.clock_gettime(Process::CLOCK_BOOTTIME_ALARM).should.instance_of?(Float)
end
end
end
diff --git a/spec/ruby/core/process/constants_spec.rb b/spec/ruby/core/process/constants_spec.rb
index 57cacadef2..5a4c478e74 100644
--- a/spec/ruby/core/process/constants_spec.rb
+++ b/spec/ruby/core/process/constants_spec.rb
@@ -2,7 +2,7 @@ require_relative '../../spec_helper'
describe "Process::Constants" do
platform_is :darwin, :netbsd, :freebsd do
- it "are all present on BSD-like systems" do
+ describe "on BSD-like systems" do
%i[
WNOHANG
WUNTRACED
@@ -20,27 +20,31 @@ describe "Process::Constants" do
RLIMIT_NPROC
RLIMIT_NOFILE
].each do |const|
- Process.const_defined?(const).should be_true
- Process.const_get(const).should be_an_instance_of(Integer)
+ it "defines #{const}" do
+ Process.const_defined?(const).should == true
+ Process.const_get(const).should.instance_of?(Integer)
+ end
end
end
end
platform_is :darwin do
- it "are all present on Darwin" do
+ describe "on Darwin" do
%i[
RLIM_SAVED_MAX
RLIM_SAVED_CUR
RLIMIT_AS
].each do |const|
- Process.const_defined?(const).should be_true
- Process.const_get(const).should be_an_instance_of(Integer)
+ it "defines #{const}" do
+ Process.const_defined?(const).should == true
+ Process.const_get(const).should.instance_of?(Integer)
+ end
end
end
end
platform_is :linux do
- it "are all present on Linux" do
+ describe "on Linux" do
%i[
WNOHANG
WUNTRACED
@@ -61,37 +65,43 @@ describe "Process::Constants" do
RLIM_SAVED_MAX
RLIM_SAVED_CUR
].each do |const|
- Process.const_defined?(const).should be_true
- Process.const_get(const).should be_an_instance_of(Integer)
+ it "defines #{const}" do
+ Process.const_defined?(const).should == true
+ Process.const_get(const).should.instance_of?(Integer)
+ end
end
end
end
platform_is :netbsd, :freebsd do
- it "are all present on NetBSD and FreeBSD" do
+ describe "on NetBSD and FreeBSD" do
%i[
RLIMIT_SBSIZE
RLIMIT_AS
].each do |const|
- Process.const_defined?(const).should be_true
- Process.const_get(const).should be_an_instance_of(Integer)
+ it "defines #{const}" do
+ Process.const_defined?(const).should == true
+ Process.const_get(const).should.instance_of?(Integer)
+ end
end
end
end
platform_is :freebsd do
- it "are all present on FreeBSD" do
+ describe "on FreeBSD" do
%i[
RLIMIT_NPTS
].each do |const|
- Process.const_defined?(const).should be_true
- Process.const_get(const).should be_an_instance_of(Integer)
+ it "defines #{const}" do
+ Process.const_defined?(const).should == true
+ Process.const_get(const).should.instance_of?(Integer)
+ end
end
end
end
platform_is :windows do
- it "does not define RLIMIT constants" do
+ describe "on Windows" do
%i[
RLIMIT_CPU
RLIMIT_FSIZE
@@ -107,7 +117,9 @@ describe "Process::Constants" do
RLIM_SAVED_MAX
RLIM_SAVED_CUR
].each do |const|
- Process.const_defined?(const).should be_false
+ it "does not define #{const}" do
+ Process.const_defined?(const).should == false
+ end
end
end
end
diff --git a/spec/ruby/core/process/daemon_spec.rb b/spec/ruby/core/process/daemon_spec.rb
index 20b0d743b9..7198dfa6ee 100644
--- a/spec/ruby/core/process/daemon_spec.rb
+++ b/spec/ruby/core/process/daemon_spec.rb
@@ -1,10 +1,11 @@
require_relative '../../spec_helper'
require_relative 'fixtures/common'
-platform_is_not :windows do
- # macOS 15 is not working this examples
- return if /darwin/ =~ RUBY_PLATFORM && /15/ =~ `sw_vers -productVersion`
-
+guard -> {
+ Process.respond_to?(:fork) and
+ # macOS 15 is not working for these examples
+ !(/darwin/ =~ RUBY_PLATFORM && /15/ =~ `sw_vers -productVersion`)
+} do
describe :process_daemon_keep_stdio_open_false, shared: true do
it "redirects stdout to /dev/null" do
@daemon.invoke("keep_stdio_open_false_stdout", @object).should == ""
@@ -107,12 +108,16 @@ platform_is_not :windows do
end
end
-platform_is :windows do
+guard_not -> { Process.respond_to?(:fork) } do
describe "Process.daemon" do
+ it "returns false from #respond_to?" do
+ Process.respond_to?(:daemon).should == false
+ end
+
it "raises a NotImplementedError" do
-> {
Process.daemon
- }.should raise_error(NotImplementedError)
+ }.should.raise(NotImplementedError)
end
end
end
diff --git a/spec/ruby/core/process/detach_spec.rb b/spec/ruby/core/process/detach_spec.rb
index f13bda1f5d..862768a909 100644
--- a/spec/ruby/core/process/detach_spec.rb
+++ b/spec/ruby/core/process/detach_spec.rb
@@ -1,81 +1,82 @@
require_relative '../../spec_helper'
+require_relative 'fixtures/common'
describe "Process.detach" do
- platform_is_not :windows do
- it "returns a thread" do
- pid = Process.fork { Process.exit! }
- thr = Process.detach(pid)
- thr.should be_kind_of(Thread)
- thr.join
- end
+ ProcessSpecs.use_system_ruby(self)
- it "produces the exit Process::Status as the thread value" do
- pid = Process.fork { Process.exit! }
- thr = Process.detach(pid)
- thr.join
+ it "returns a thread" do
+ pid = Process.spawn(*ruby_exe, "-e", "exit")
+ thr = Process.detach(pid)
+ thr.should.is_a?(Thread)
+ thr.join
+ end
- status = thr.value
- status.should be_kind_of(Process::Status)
- status.pid.should == pid
- end
+ it "produces the exit Process::Status as the thread value" do
+ pid = Process.spawn(*ruby_exe, "-e", "exit")
+ thr = Process.detach(pid)
+ thr.join
+
+ status = thr.value
+ status.should.is_a?(Process::Status)
+ status.pid.should == pid
+ end
- platform_is_not :openbsd do
- it "reaps the child process's status automatically" do
- pid = Process.fork { Process.exit! }
- Process.detach(pid).join
- -> { Process.waitpid(pid) }.should raise_error(Errno::ECHILD)
- end
+ platform_is_not :openbsd do
+ it "reaps the child process's status automatically" do
+ pid = Process.spawn(*ruby_exe, "-e", "exit")
+ Process.detach(pid).join
+ -> { Process.waitpid(pid) }.should.raise(Errno::ECHILD)
end
+ end
- it "sets the :pid thread-local to the PID" do
- pid = Process.fork { Process.exit! }
- thr = Process.detach(pid)
- thr.join
+ it "sets the :pid thread-local to the PID" do
+ pid = Process.spawn(*ruby_exe, "-e", "exit")
+ thr = Process.detach(pid)
+ thr.join
- thr[:pid].should == pid
- end
+ thr[:pid].should == pid
+ end
- it "provides a #pid method on the returned thread which returns the PID" do
- pid = Process.fork { Process.exit! }
- thr = Process.detach(pid)
- thr.join
+ it "provides a #pid method on the returned thread which returns the PID" do
+ pid = Process.spawn(*ruby_exe, "-e", "exit")
+ thr = Process.detach(pid)
+ thr.join
- thr.pid.should == pid
- end
+ thr.pid.should == pid
+ 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)
+ 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)
- # 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)
+ # 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(Errno::ESRCH)
- thr = Process.detach(pid_not_existing)
- thr.join
+ thr = Process.detach(pid_not_existing)
+ thr.join
- thr.should be_kind_of(Thread)
- end
+ thr.should.is_a?(Thread)
+ end
- it "calls #to_int to implicitly convert non-Integer pid to Integer" do
- pid = MockObject.new('mock-enumerable')
- pid.should_receive(:to_int).and_return(100500)
+ it "calls #to_int to implicitly convert non-Integer pid to Integer" do
+ pid = MockObject.new('mock-enumerable')
+ pid.should_receive(:to_int).and_return(100500)
- Process.detach(pid).join
- end
+ Process.detach(pid).join
+ end
- it "raises TypeError when pid argument does not have #to_int method" do
- -> { Process.detach(Object.new) }.should raise_error(TypeError, "no implicit conversion of Object into Integer")
- end
+ it "raises TypeError when pid argument does not have #to_int method" do
+ -> { Process.detach(Object.new) }.should.raise(TypeError, "no implicit conversion of Object into Integer")
+ end
- it "raises TypeError when #to_int returns non-Integer value" do
- pid = MockObject.new('mock-enumerable')
- pid.should_receive(:to_int).and_return(:symbol)
+ it "raises TypeError when #to_int returns non-Integer value" do
+ pid = MockObject.new('mock-enumerable')
+ pid.should_receive(:to_int).and_return(:symbol)
- -> { Process.detach(pid) }.should raise_error(TypeError, "can't convert MockObject to Integer (MockObject#to_int gives Symbol)")
- end
+ -> { Process.detach(pid) }.should raise_consistent_error(TypeError, "can't convert MockObject into Integer (MockObject#to_int gives Symbol)")
end
end
diff --git a/spec/ruby/core/process/egid_spec.rb b/spec/ruby/core/process/egid_spec.rb
index a67b623d5c..69c86bebe2 100644
--- a/spec/ruby/core/process/egid_spec.rb
+++ b/spec/ruby/core/process/egid_spec.rb
@@ -2,7 +2,7 @@ require_relative '../../spec_helper'
describe "Process.egid" do
it "returns the effective group ID for this process" do
- Process.egid.should be_kind_of(Integer)
+ Process.egid.should.is_a?(Integer)
end
it "also goes by Process::GID.eid" do
@@ -18,7 +18,7 @@ describe "Process.egid=" do
platform_is_not :windows do
it "raises TypeError if not passed an Integer or String" do
- -> { Process.egid = Object.new }.should raise_error(TypeError)
+ -> { Process.egid = Object.new }.should.raise(TypeError)
end
it "sets the effective group id to its own gid if given the username corresponding to its own gid" do
@@ -33,12 +33,12 @@ describe "Process.egid=" do
as_user do
it "raises Errno::ERPERM if run by a non superuser trying to set the root group id" do
- -> { Process.egid = 0 }.should raise_error(Errno::EPERM)
+ -> { Process.egid = 0 }.should.raise(Errno::EPERM)
end
platform_is :linux do
it "raises Errno::ERPERM if run by a non superuser trying to set the group id from group name" do
- -> { Process.egid = "root" }.should raise_error(Errno::EPERM)
+ -> { Process.egid = "root" }.should.raise(Errno::EPERM)
end
end
end
diff --git a/spec/ruby/core/process/euid_spec.rb b/spec/ruby/core/process/euid_spec.rb
index c1ec4171d0..da76f06e59 100644
--- a/spec/ruby/core/process/euid_spec.rb
+++ b/spec/ruby/core/process/euid_spec.rb
@@ -2,7 +2,7 @@ require_relative '../../spec_helper'
describe "Process.euid" do
it "returns the effective user ID for this process" do
- Process.euid.should be_kind_of(Integer)
+ Process.euid.should.is_a?(Integer)
end
it "also goes by Process::UID.eid" do
@@ -18,7 +18,7 @@ describe "Process.euid=" do
platform_is_not :windows do
it "raises TypeError if not passed an Integer" do
- -> { Process.euid = Object.new }.should raise_error(TypeError)
+ -> { Process.euid = Object.new }.should.raise(TypeError)
end
it "sets the effective user id to its own uid if given the username corresponding to its own uid" do
@@ -33,11 +33,11 @@ describe "Process.euid=" do
as_user do
it "raises Errno::ERPERM if run by a non superuser trying to set the superuser id" do
- -> { Process.euid = 0 }.should raise_error(Errno::EPERM)
+ -> { Process.euid = 0 }.should.raise(Errno::EPERM)
end
it "raises Errno::ERPERM if run by a non superuser trying to set the superuser id from username" do
- -> { Process.euid = "root" }.should raise_error(Errno::EPERM)
+ -> { Process.euid = "root" }.should.raise(Errno::EPERM)
end
end
diff --git a/spec/ruby/core/process/exec_spec.rb b/spec/ruby/core/process/exec_spec.rb
index 0f371b39c8..a48d461b02 100644
--- a/spec/ruby/core/process/exec_spec.rb
+++ b/spec/ruby/core/process/exec_spec.rb
@@ -2,35 +2,35 @@ require_relative '../../spec_helper'
describe "Process.exec" do
it "raises Errno::ENOENT for an empty string" do
- -> { Process.exec "" }.should raise_error(Errno::ENOENT)
+ -> { Process.exec "" }.should.raise(Errno::ENOENT)
end
it "raises Errno::ENOENT for a command which does not exist" do
- -> { Process.exec "bogus-noent-script.sh" }.should raise_error(Errno::ENOENT)
+ -> { Process.exec "bogus-noent-script.sh" }.should.raise(Errno::ENOENT)
end
it "raises an ArgumentError if the command includes a null byte" do
- -> { Process.exec "\000" }.should raise_error(ArgumentError)
+ -> { Process.exec "\000" }.should.raise(ArgumentError)
end
unless File.executable?(__FILE__) # Some FS (e.g. vboxfs) locate all files executable
platform_is_not :windows do
it "raises Errno::EACCES when the file does not have execute permissions" do
- -> { Process.exec __FILE__ }.should raise_error(Errno::EACCES)
+ -> { Process.exec __FILE__ }.should.raise(Errno::EACCES)
end
end
platform_is :windows do
it "raises Errno::EACCES or Errno::ENOEXEC when the file is not an executable file" do
- -> { Process.exec __FILE__ }.should raise_error(SystemCallError) { |e|
- [Errno::EACCES, Errno::ENOEXEC].should include(e.class)
+ -> { Process.exec __FILE__ }.should.raise(SystemCallError) { |e|
+ [Errno::EACCES, Errno::ENOEXEC].should.include?(e.class)
}
end
end
end
it "raises Errno::EACCES when passed a directory" do
- -> { Process.exec __dir__ }.should raise_error(Errno::EACCES)
+ -> { Process.exec __dir__ }.should.raise(Errno::EACCES)
end
it "runs the specified command, replacing current process" do
@@ -171,9 +171,9 @@ describe "Process.exec" do
end
it "raises an ArgumentError if the Array does not have exactly two elements" do
- -> { Process.exec([]) }.should raise_error(ArgumentError)
- -> { Process.exec([:a]) }.should raise_error(ArgumentError)
- -> { Process.exec([:a, :b, :c]) }.should raise_error(ArgumentError)
+ -> { Process.exec([]) }.should.raise(ArgumentError)
+ -> { Process.exec([:a]) }.should.raise(ArgumentError)
+ -> { Process.exec([:a, :b, :c]) }.should.raise(ArgumentError)
end
end
diff --git a/spec/ruby/core/process/getpriority_spec.rb b/spec/ruby/core/process/getpriority_spec.rb
index a35e5956a5..53fe7bfe20 100644
--- a/spec/ruby/core/process/getpriority_spec.rb
+++ b/spec/ruby/core/process/getpriority_spec.rb
@@ -5,19 +5,19 @@ describe "Process.getpriority" do
it "coerces arguments to Integers" do
ret = Process.getpriority mock_int(Process::PRIO_PROCESS), mock_int(0)
- ret.should be_kind_of(Integer)
+ ret.should.is_a?(Integer)
end
it "gets the scheduling priority for a specified process" do
- Process.getpriority(Process::PRIO_PROCESS, 0).should be_kind_of(Integer)
+ Process.getpriority(Process::PRIO_PROCESS, 0).should.is_a?(Integer)
end
it "gets the scheduling priority for a specified process group" do
- Process.getpriority(Process::PRIO_PGRP, 0).should be_kind_of(Integer)
+ Process.getpriority(Process::PRIO_PGRP, 0).should.is_a?(Integer)
end
it "gets the scheduling priority for a specified user" do
- Process.getpriority(Process::PRIO_USER, 0).should be_kind_of(Integer)
+ Process.getpriority(Process::PRIO_USER, 0).should.is_a?(Integer)
end
end
end
diff --git a/spec/ruby/core/process/getrlimit_spec.rb b/spec/ruby/core/process/getrlimit_spec.rb
index 883b8fac48..d36d8c3335 100644
--- a/spec/ruby/core/process/getrlimit_spec.rb
+++ b/spec/ruby/core/process/getrlimit_spec.rb
@@ -16,8 +16,8 @@ describe "Process.getrlimit" do
it "returns a two-element Array of Integers" do
result = Process.getrlimit Process::RLIMIT_CORE
result.size.should == 2
- result.first.should be_kind_of(Integer)
- result.last.should be_kind_of(Integer)
+ result.first.should.is_a?(Integer)
+ result.last.should.is_a?(Integer)
end
context "when passed an Object" do
@@ -36,7 +36,7 @@ describe "Process.getrlimit" do
obj = mock("process getrlimit integer")
obj.should_receive(:to_int).and_return(nil)
- -> { Process.getrlimit(obj) }.should raise_error(TypeError)
+ -> { Process.getrlimit(obj) }.should.raise(TypeError)
end
end
@@ -49,7 +49,7 @@ describe "Process.getrlimit" do
end
it "raises ArgumentError when passed an unknown resource" do
- -> { Process.getrlimit(:FOO) }.should raise_error(ArgumentError)
+ -> { Process.getrlimit(:FOO) }.should.raise(ArgumentError)
end
end
@@ -62,7 +62,7 @@ describe "Process.getrlimit" do
end
it "raises ArgumentError when passed an unknown resource" do
- -> { Process.getrlimit("FOO") }.should raise_error(ArgumentError)
+ -> { Process.getrlimit("FOO") }.should.raise(ArgumentError)
end
end
@@ -91,10 +91,10 @@ describe "Process.getrlimit" do
platform_is :windows do
it "is not implemented" do
- Process.respond_to?(:getrlimit).should be_false
+ Process.respond_to?(:getrlimit).should == false
-> do
Process.getrlimit(nil)
- end.should raise_error NotImplementedError
+ end.should.raise NotImplementedError
end
end
end
diff --git a/spec/ruby/core/process/groups_spec.rb b/spec/ruby/core/process/groups_spec.rb
index 33e0f9d7b3..fa916671a4 100644
--- a/spec/ruby/core/process/groups_spec.rb
+++ b/spec/ruby/core/process/groups_spec.rb
@@ -50,7 +50,7 @@ describe "Process.groups=" do
Process.groups.should == [ Process.gid ]
supplementary = groups - [ Process.gid ]
if supplementary.length > 0
- -> { Process.groups = supplementary }.should raise_error(Errno::EPERM)
+ -> { Process.groups = supplementary }.should.raise(Errno::EPERM)
end
end
end
@@ -59,7 +59,7 @@ describe "Process.groups=" do
it "raises Errno::EPERM" do
-> {
Process.groups = [0]
- }.should raise_error(Errno::EPERM)
+ }.should.raise(Errno::EPERM)
end
end
end
diff --git a/spec/ruby/core/process/initgroups_spec.rb b/spec/ruby/core/process/initgroups_spec.rb
index ffc7f282b6..d9f31936cb 100644
--- a/spec/ruby/core/process/initgroups_spec.rb
+++ b/spec/ruby/core/process/initgroups_spec.rb
@@ -14,7 +14,7 @@ describe "Process.initgroups" do
Process.groups.sort.should == augmented_groups.sort
Process.groups = groups
else
- -> { Process.initgroups(name, gid) }.should raise_error(Errno::EPERM)
+ -> { Process.initgroups(name, gid) }.should.raise(Errno::EPERM)
end
end
end
diff --git a/spec/ruby/core/process/kill_spec.rb b/spec/ruby/core/process/kill_spec.rb
index af9c9e6deb..885c2bf2b7 100644
--- a/spec/ruby/core/process/kill_spec.rb
+++ b/spec/ruby/core/process/kill_spec.rb
@@ -9,18 +9,18 @@ describe "Process.kill" do
end
it "raises an ArgumentError for unknown signals" do
- -> { Process.kill("FOO", @pid) }.should raise_error(ArgumentError)
+ -> { Process.kill("FOO", @pid) }.should.raise(ArgumentError)
end
it "raises an ArgumentError if passed a lowercase signal name" do
- -> { Process.kill("term", @pid) }.should raise_error(ArgumentError)
+ -> { Process.kill("term", @pid) }.should.raise(ArgumentError)
end
it "raises an ArgumentError if signal is not an Integer or String" do
signal = mock("process kill signal")
signal.should_not_receive(:to_int)
- -> { Process.kill(signal, @pid) }.should raise_error(ArgumentError)
+ -> { Process.kill(signal, @pid) }.should.raise(ArgumentError)
end
it "raises Errno::ESRCH if the process does not exist" do
@@ -29,7 +29,7 @@ describe "Process.kill" do
Process.wait(pid)
-> {
Process.kill("SIGKILL", pid)
- }.should raise_error(Errno::ESRCH)
+ }.should.raise(Errno::ESRCH)
end
it "checks for existence and permissions to signal a process, but does not actually signal it, when using signal 0" do
diff --git a/spec/ruby/core/process/last_status_spec.rb b/spec/ruby/core/process/last_status_spec.rb
index 2372f2aae3..1bd8adf798 100644
--- a/spec/ruby/core/process/last_status_spec.rb
+++ b/spec/ruby/core/process/last_status_spec.rb
@@ -13,6 +13,6 @@ describe 'Process#last_status' do
end
it 'raises an ArgumentError if any arguments are provided' do
- -> { Process.last_status(1) }.should raise_error(ArgumentError)
+ -> { Process.last_status(1) }.should.raise(ArgumentError)
end
end
diff --git a/spec/ruby/core/process/maxgroups_spec.rb b/spec/ruby/core/process/maxgroups_spec.rb
index 2549a7a971..895b384bd0 100644
--- a/spec/ruby/core/process/maxgroups_spec.rb
+++ b/spec/ruby/core/process/maxgroups_spec.rb
@@ -3,7 +3,7 @@ require_relative '../../spec_helper'
platform_is_not :windows do
describe "Process.maxgroups" do
it "returns the maximum number of gids allowed in the supplemental group access list" do
- Process.maxgroups.should be_kind_of(Integer)
+ Process.maxgroups.should.is_a?(Integer)
end
it "sets the maximum number of gids allowed in the supplemental group access list" do
diff --git a/spec/ruby/core/process/pid_spec.rb b/spec/ruby/core/process/pid_spec.rb
index 2d008bc4b7..42b0b918b9 100644
--- a/spec/ruby/core/process/pid_spec.rb
+++ b/spec/ruby/core/process/pid_spec.rb
@@ -3,7 +3,7 @@ require_relative '../../spec_helper'
describe "Process.pid" do
it "returns the process id of this process" do
pid = Process.pid
- pid.should be_kind_of(Integer)
+ pid.should.is_a?(Integer)
Process.pid.should == pid
end
end
diff --git a/spec/ruby/core/process/set_proctitle_spec.rb b/spec/ruby/core/process/set_proctitle_spec.rb
index d022f2021c..28a0fa6cee 100644
--- a/spec/ruby/core/process/set_proctitle_spec.rb
+++ b/spec/ruby/core/process/set_proctitle_spec.rb
@@ -17,7 +17,7 @@ describe 'Process.setproctitle' do
title = 'rubyspec-proctitle-test'
Process.setproctitle(title).should == title
- `ps -ocommand= -p#{$$}`.should include(title)
+ `ps -ocommand= -p#{$$}`.should.include?(title)
end
end
end
diff --git a/spec/ruby/core/process/setpgid_spec.rb b/spec/ruby/core/process/setpgid_spec.rb
index be724e9007..1442d7f99c 100644
--- a/spec/ruby/core/process/setpgid_spec.rb
+++ b/spec/ruby/core/process/setpgid_spec.rb
@@ -1,7 +1,7 @@
require_relative '../../spec_helper'
describe "Process.setpgid" do
- platform_is_not :windows do
+ guard -> { Process.respond_to?(:fork) } do
# Must use fork as setpgid(2) gives EACCESS after execve()
it "sets the process group id of the specified process" do
rd, wr = IO.pipe
diff --git a/spec/ruby/core/process/setpgrp_spec.rb b/spec/ruby/core/process/setpgrp_spec.rb
index 800668008d..7c4344f115 100644
--- a/spec/ruby/core/process/setpgrp_spec.rb
+++ b/spec/ruby/core/process/setpgrp_spec.rb
@@ -2,7 +2,7 @@ require_relative '../../spec_helper'
# TODO: put these in the right files.
describe "Process.setpgrp and Process.getpgrp" do
- platform_is_not :windows do
+ guard -> { Process.respond_to?(:fork) } do
it "sets and gets the process group ID of the calling process" do
# there are two synchronization points here:
# One for the child to let the parent know that it has finished
diff --git a/spec/ruby/core/process/setrlimit_spec.rb b/spec/ruby/core/process/setrlimit_spec.rb
index ba8d1e04ca..f02ab46fca 100644
--- a/spec/ruby/core/process/setrlimit_spec.rb
+++ b/spec/ruby/core/process/setrlimit_spec.rb
@@ -9,196 +9,196 @@ describe "Process.setrlimit" do
end
it "calls #to_int to convert resource to an Integer" do
- Process.setrlimit(mock_int(@resource), @limit, @max).should be_nil
+ Process.setrlimit(mock_int(@resource), @limit, @max).should == nil
end
it "raises a TypeError if #to_int for resource does not return an Integer" do
obj = mock("process getrlimit integer")
obj.should_receive(:to_int).and_return(nil)
- -> { Process.setrlimit(obj, @limit, @max) }.should raise_error(TypeError)
+ -> { Process.setrlimit(obj, @limit, @max) }.should.raise(TypeError)
end
it "calls #to_int to convert the soft limit to an Integer" do
- Process.setrlimit(@resource, mock_int(@limit), @max).should be_nil
+ Process.setrlimit(@resource, mock_int(@limit), @max).should == nil
end
it "raises a TypeError if #to_int for resource does not return an Integer" do
obj = mock("process getrlimit integer")
obj.should_receive(:to_int).and_return(nil)
- -> { Process.setrlimit(@resource, obj, @max) }.should raise_error(TypeError)
+ -> { Process.setrlimit(@resource, obj, @max) }.should.raise(TypeError)
end
it "calls #to_int to convert the hard limit to an Integer" do
- Process.setrlimit(@resource, @limit, mock_int(@max)).should be_nil
+ Process.setrlimit(@resource, @limit, mock_int(@max)).should == nil
end
it "raises a TypeError if #to_int for resource does not return an Integer" do
obj = mock("process getrlimit integer")
obj.should_receive(:to_int).and_return(nil)
- -> { Process.setrlimit(@resource, @limit, obj) }.should raise_error(TypeError)
+ -> { Process.setrlimit(@resource, @limit, obj) }.should.raise(TypeError)
end
end
context "when passed a Symbol" do
platform_is_not :openbsd do
it "coerces :AS into RLIMIT_AS" do
- Process.setrlimit(:AS, *Process.getrlimit(Process::RLIMIT_AS)).should be_nil
+ Process.setrlimit(:AS, *Process.getrlimit(Process::RLIMIT_AS)).should == nil
end
end
it "coerces :CORE into RLIMIT_CORE" do
- Process.setrlimit(:CORE, *Process.getrlimit(Process::RLIMIT_CORE)).should be_nil
+ Process.setrlimit(:CORE, *Process.getrlimit(Process::RLIMIT_CORE)).should == nil
end
it "coerces :CPU into RLIMIT_CPU" do
- Process.setrlimit(:CPU, *Process.getrlimit(Process::RLIMIT_CPU)).should be_nil
+ Process.setrlimit(:CPU, *Process.getrlimit(Process::RLIMIT_CPU)).should == nil
end
it "coerces :DATA into RLIMIT_DATA" do
- Process.setrlimit(:DATA, *Process.getrlimit(Process::RLIMIT_DATA)).should be_nil
+ Process.setrlimit(:DATA, *Process.getrlimit(Process::RLIMIT_DATA)).should == nil
end
it "coerces :FSIZE into RLIMIT_FSIZE" do
- Process.setrlimit(:FSIZE, *Process.getrlimit(Process::RLIMIT_FSIZE)).should be_nil
+ Process.setrlimit(:FSIZE, *Process.getrlimit(Process::RLIMIT_FSIZE)).should == nil
end
it "coerces :NOFILE into RLIMIT_NOFILE" do
- Process.setrlimit(:NOFILE, *Process.getrlimit(Process::RLIMIT_NOFILE)).should be_nil
+ Process.setrlimit(:NOFILE, *Process.getrlimit(Process::RLIMIT_NOFILE)).should == nil
end
it "coerces :STACK into RLIMIT_STACK" do
- Process.setrlimit(:STACK, *Process.getrlimit(Process::RLIMIT_STACK)).should be_nil
+ Process.setrlimit(:STACK, *Process.getrlimit(Process::RLIMIT_STACK)).should == nil
end
platform_is_not :aix do
it "coerces :MEMLOCK into RLIMIT_MEMLOCK" do
- Process.setrlimit(:MEMLOCK, *Process.getrlimit(Process::RLIMIT_MEMLOCK)).should be_nil
+ Process.setrlimit(:MEMLOCK, *Process.getrlimit(Process::RLIMIT_MEMLOCK)).should == nil
end
end
it "coerces :NPROC into RLIMIT_NPROC" do
- Process.setrlimit(:NPROC, *Process.getrlimit(Process::RLIMIT_NPROC)).should be_nil
+ Process.setrlimit(:NPROC, *Process.getrlimit(Process::RLIMIT_NPROC)).should == nil
end
it "coerces :RSS into RLIMIT_RSS" do
- Process.setrlimit(:RSS, *Process.getrlimit(Process::RLIMIT_RSS)).should be_nil
+ Process.setrlimit(:RSS, *Process.getrlimit(Process::RLIMIT_RSS)).should == nil
end
platform_is :netbsd, :freebsd do
it "coerces :SBSIZE into RLIMIT_SBSIZE" do
- Process.setrlimit(:SBSIZE, *Process.getrlimit(Process::RLIMIT_SBSIZE)).should be_nil
+ Process.setrlimit(:SBSIZE, *Process.getrlimit(Process::RLIMIT_SBSIZE)).should == nil
end
end
platform_is :linux do
it "coerces :RTPRIO into RLIMIT_RTPRIO" do
- Process.setrlimit(:RTPRIO, *Process.getrlimit(Process::RLIMIT_RTPRIO)).should be_nil
+ Process.setrlimit(:RTPRIO, *Process.getrlimit(Process::RLIMIT_RTPRIO)).should == nil
end
guard -> { defined?(Process::RLIMIT_RTTIME) } do
it "coerces :RTTIME into RLIMIT_RTTIME" do
- Process.setrlimit(:RTTIME, *Process.getrlimit(Process::RLIMIT_RTTIME)).should be_nil
+ Process.setrlimit(:RTTIME, *Process.getrlimit(Process::RLIMIT_RTTIME)).should == nil
end
end
it "coerces :SIGPENDING into RLIMIT_SIGPENDING" do
- Process.setrlimit(:SIGPENDING, *Process.getrlimit(Process::RLIMIT_SIGPENDING)).should be_nil
+ Process.setrlimit(:SIGPENDING, *Process.getrlimit(Process::RLIMIT_SIGPENDING)).should == nil
end
it "coerces :MSGQUEUE into RLIMIT_MSGQUEUE" do
- Process.setrlimit(:MSGQUEUE, *Process.getrlimit(Process::RLIMIT_MSGQUEUE)).should be_nil
+ Process.setrlimit(:MSGQUEUE, *Process.getrlimit(Process::RLIMIT_MSGQUEUE)).should == nil
end
it "coerces :NICE into RLIMIT_NICE" do
- Process.setrlimit(:NICE, *Process.getrlimit(Process::RLIMIT_NICE)).should be_nil
+ Process.setrlimit(:NICE, *Process.getrlimit(Process::RLIMIT_NICE)).should == nil
end
end
it "raises ArgumentError when passed an unknown resource" do
- -> { Process.setrlimit(:FOO, 1, 1) }.should raise_error(ArgumentError)
+ -> { Process.setrlimit(:FOO, 1, 1) }.should.raise(ArgumentError)
end
end
context "when passed a String" do
platform_is_not :openbsd do
it "coerces 'AS' into RLIMIT_AS" do
- Process.setrlimit("AS", *Process.getrlimit(Process::RLIMIT_AS)).should be_nil
+ Process.setrlimit("AS", *Process.getrlimit(Process::RLIMIT_AS)).should == nil
end
end
it "coerces 'CORE' into RLIMIT_CORE" do
- Process.setrlimit("CORE", *Process.getrlimit(Process::RLIMIT_CORE)).should be_nil
+ Process.setrlimit("CORE", *Process.getrlimit(Process::RLIMIT_CORE)).should == nil
end
it "coerces 'CPU' into RLIMIT_CPU" do
- Process.setrlimit("CPU", *Process.getrlimit(Process::RLIMIT_CPU)).should be_nil
+ Process.setrlimit("CPU", *Process.getrlimit(Process::RLIMIT_CPU)).should == nil
end
it "coerces 'DATA' into RLIMIT_DATA" do
- Process.setrlimit("DATA", *Process.getrlimit(Process::RLIMIT_DATA)).should be_nil
+ Process.setrlimit("DATA", *Process.getrlimit(Process::RLIMIT_DATA)).should == nil
end
it "coerces 'FSIZE' into RLIMIT_FSIZE" do
- Process.setrlimit("FSIZE", *Process.getrlimit(Process::RLIMIT_FSIZE)).should be_nil
+ Process.setrlimit("FSIZE", *Process.getrlimit(Process::RLIMIT_FSIZE)).should == nil
end
it "coerces 'NOFILE' into RLIMIT_NOFILE" do
- Process.setrlimit("NOFILE", *Process.getrlimit(Process::RLIMIT_NOFILE)).should be_nil
+ Process.setrlimit("NOFILE", *Process.getrlimit(Process::RLIMIT_NOFILE)).should == nil
end
it "coerces 'STACK' into RLIMIT_STACK" do
- Process.setrlimit("STACK", *Process.getrlimit(Process::RLIMIT_STACK)).should be_nil
+ Process.setrlimit("STACK", *Process.getrlimit(Process::RLIMIT_STACK)).should == nil
end
platform_is_not :aix do
it "coerces 'MEMLOCK' into RLIMIT_MEMLOCK" do
- Process.setrlimit("MEMLOCK", *Process.getrlimit(Process::RLIMIT_MEMLOCK)).should be_nil
+ Process.setrlimit("MEMLOCK", *Process.getrlimit(Process::RLIMIT_MEMLOCK)).should == nil
end
end
it "coerces 'NPROC' into RLIMIT_NPROC" do
- Process.setrlimit("NPROC", *Process.getrlimit(Process::RLIMIT_NPROC)).should be_nil
+ Process.setrlimit("NPROC", *Process.getrlimit(Process::RLIMIT_NPROC)).should == nil
end
it "coerces 'RSS' into RLIMIT_RSS" do
- Process.setrlimit("RSS", *Process.getrlimit(Process::RLIMIT_RSS)).should be_nil
+ Process.setrlimit("RSS", *Process.getrlimit(Process::RLIMIT_RSS)).should == nil
end
platform_is :netbsd, :freebsd do
it "coerces 'SBSIZE' into RLIMIT_SBSIZE" do
- Process.setrlimit("SBSIZE", *Process.getrlimit(Process::RLIMIT_SBSIZE)).should be_nil
+ Process.setrlimit("SBSIZE", *Process.getrlimit(Process::RLIMIT_SBSIZE)).should == nil
end
end
platform_is :linux do
it "coerces 'RTPRIO' into RLIMIT_RTPRIO" do
- Process.setrlimit("RTPRIO", *Process.getrlimit(Process::RLIMIT_RTPRIO)).should be_nil
+ Process.setrlimit("RTPRIO", *Process.getrlimit(Process::RLIMIT_RTPRIO)).should == nil
end
guard -> { defined?(Process::RLIMIT_RTTIME) } do
it "coerces 'RTTIME' into RLIMIT_RTTIME" do
- Process.setrlimit("RTTIME", *Process.getrlimit(Process::RLIMIT_RTTIME)).should be_nil
+ Process.setrlimit("RTTIME", *Process.getrlimit(Process::RLIMIT_RTTIME)).should == nil
end
end
it "coerces 'SIGPENDING' into RLIMIT_SIGPENDING" do
- Process.setrlimit("SIGPENDING", *Process.getrlimit(Process::RLIMIT_SIGPENDING)).should be_nil
+ Process.setrlimit("SIGPENDING", *Process.getrlimit(Process::RLIMIT_SIGPENDING)).should == nil
end
it "coerces 'MSGQUEUE' into RLIMIT_MSGQUEUE" do
- Process.setrlimit("MSGQUEUE", *Process.getrlimit(Process::RLIMIT_MSGQUEUE)).should be_nil
+ Process.setrlimit("MSGQUEUE", *Process.getrlimit(Process::RLIMIT_MSGQUEUE)).should == nil
end
it "coerces 'NICE' into RLIMIT_NICE" do
- Process.setrlimit("NICE", *Process.getrlimit(Process::RLIMIT_NICE)).should be_nil
+ Process.setrlimit("NICE", *Process.getrlimit(Process::RLIMIT_NICE)).should == nil
end
end
it "raises ArgumentError when passed an unknown resource" do
- -> { Process.setrlimit("FOO", 1, 1) }.should raise_error(ArgumentError)
+ -> { Process.setrlimit("FOO", 1, 1) }.should.raise(ArgumentError)
end
end
@@ -213,7 +213,7 @@ describe "Process.setrlimit" do
obj.should_receive(:to_str).and_return("CORE")
obj.should_not_receive(:to_int)
- Process.setrlimit(obj, @limit, @max).should be_nil
+ Process.setrlimit(obj, @limit, @max).should == nil
end
it "calls #to_int if #to_str does not return a String" do
@@ -221,17 +221,17 @@ describe "Process.setrlimit" do
obj.should_receive(:to_str).and_return(nil)
obj.should_receive(:to_int).and_return(@resource)
- Process.setrlimit(obj, @limit, @max).should be_nil
+ Process.setrlimit(obj, @limit, @max).should == nil
end
end
end
platform_is :windows do
it "is not implemented" do
- Process.respond_to?(:setrlimit).should be_false
+ Process.respond_to?(:setrlimit).should == false
-> do
Process.setrlimit(nil, nil)
- end.should raise_error NotImplementedError
+ end.should.raise NotImplementedError
end
end
end
diff --git a/spec/ruby/core/process/spawn_spec.rb b/spec/ruby/core/process/spawn_spec.rb
index 283a7f033d..fb619dce42 100644
--- a/spec/ruby/core/process/spawn_spec.rb
+++ b/spec/ruby/core/process/spawn_spec.rb
@@ -51,7 +51,7 @@ describe "Process.spawn" do
it "returns the process ID of the new process as an Integer" do
pid = Process.spawn(*ruby_exe, "-e", "exit")
Process.wait pid
- pid.should be_an_instance_of(Integer)
+ pid.should.instance_of?(Integer)
end
it "returns immediately" do
@@ -93,11 +93,11 @@ describe "Process.spawn" do
end
it "raises an ArgumentError if the command includes a null byte" do
- -> { Process.spawn "\000" }.should raise_error(ArgumentError)
+ -> { Process.spawn "\000" }.should.raise(ArgumentError)
end
it "raises a TypeError if the argument does not respond to #to_str" do
- -> { Process.spawn :echo }.should raise_error(TypeError)
+ -> { Process.spawn :echo }.should.raise(TypeError)
end
end
@@ -122,11 +122,11 @@ describe "Process.spawn" do
end
it "raises an ArgumentError if an argument includes a null byte" do
- -> { Process.spawn "echo", "\000" }.should raise_error(ArgumentError)
+ -> { Process.spawn "echo", "\000" }.should.raise(ArgumentError)
end
it "raises a TypeError if an argument does not respond to #to_str" do
- -> { Process.spawn "echo", :foo }.should raise_error(TypeError)
+ -> { Process.spawn "echo", :foo }.should.raise(TypeError)
end
end
@@ -178,19 +178,19 @@ describe "Process.spawn" do
end
it "raises an ArgumentError if the Array does not have exactly two elements" do
- -> { Process.spawn([]) }.should raise_error(ArgumentError)
- -> { Process.spawn([:a]) }.should raise_error(ArgumentError)
- -> { Process.spawn([:a, :b, :c]) }.should raise_error(ArgumentError)
+ -> { Process.spawn([]) }.should.raise(ArgumentError)
+ -> { Process.spawn([:a]) }.should.raise(ArgumentError)
+ -> { Process.spawn([:a, :b, :c]) }.should.raise(ArgumentError)
end
it "raises an ArgumentError if the Strings in the Array include a null byte" do
- -> { Process.spawn ["\000", "echo"] }.should raise_error(ArgumentError)
- -> { Process.spawn ["echo", "\000"] }.should raise_error(ArgumentError)
+ -> { Process.spawn ["\000", "echo"] }.should.raise(ArgumentError)
+ -> { Process.spawn ["echo", "\000"] }.should.raise(ArgumentError)
end
it "raises a TypeError if an element in the Array does not respond to #to_str" do
- -> { Process.spawn ["echo", :echo] }.should raise_error(TypeError)
- -> { Process.spawn [:echo, "echo"] }.should raise_error(TypeError)
+ -> { Process.spawn ["echo", :echo] }.should.raise(TypeError)
+ -> { Process.spawn [:echo, "echo"] }.should.raise(TypeError)
end
end
@@ -256,19 +256,19 @@ describe "Process.spawn" do
it "raises an ArgumentError if an environment key includes an equals sign" do
-> do
Process.spawn({"FOO=" => "BAR"}, "echo #{@var}>#{@name}")
- end.should raise_error(ArgumentError)
+ end.should.raise(ArgumentError)
end
it "raises an ArgumentError if an environment key includes a null byte" do
-> do
Process.spawn({"\000" => "BAR"}, "echo #{@var}>#{@name}")
- end.should raise_error(ArgumentError)
+ end.should.raise(ArgumentError)
end
it "raises an ArgumentError if an environment value includes a null byte" do
-> do
Process.spawn({"FOO" => "\000"}, "echo #{@var}>#{@name}")
- end.should raise_error(ArgumentError)
+ end.should.raise(ArgumentError)
end
# :unsetenv_others
@@ -285,7 +285,7 @@ describe "Process.spawn" do
it "unsets other environment variables when given a true :unsetenv_others option" do
ENV["FOO"] = "BAR"
Process.wait Process.spawn(*@common_env_spawn_args, unsetenv_others: true)
- $?.success?.should be_true
+ $?.success?.should == true
File.read(@name).should == "\n"
end
end
@@ -293,7 +293,7 @@ describe "Process.spawn" do
it "does not unset other environment variables when given a false :unsetenv_others option" do
ENV["FOO"] = "BAR"
Process.wait Process.spawn(*@common_env_spawn_args, unsetenv_others: false)
- $?.success?.should be_true
+ $?.success?.should == true
File.read(@name).should == "BAR\n"
end
@@ -301,7 +301,7 @@ describe "Process.spawn" do
it "does not unset environment variables included in the environment hash" do
env = @minimal_env.merge({"FOO" => "BAR"})
Process.wait Process.spawn(env, "echo #{@var}>#{@name}", unsetenv_others: true)
- $?.success?.should be_true
+ $?.success?.should == true
File.read(@name).should == "BAR\n"
end
end
@@ -363,17 +363,17 @@ describe "Process.spawn" do
end
it "raises an ArgumentError if given a negative :pgroup option" do
- -> { Process.spawn("echo", pgroup: -1) }.should raise_error(ArgumentError)
+ -> { Process.spawn("echo", pgroup: -1) }.should.raise(ArgumentError)
end
it "raises a TypeError if given a symbol as :pgroup option" do
- -> { Process.spawn("echo", pgroup: :true) }.should raise_error(TypeError)
+ -> { Process.spawn("echo", pgroup: :true) }.should.raise(TypeError)
end
end
platform_is :windows do
it "raises an ArgumentError if given :pgroup option" do
- -> { Process.spawn("echo", pgroup: false) }.should raise_error(ArgumentError)
+ -> { Process.spawn("echo", pgroup: false) }.should.raise(ArgumentError)
end
end
@@ -452,7 +452,7 @@ describe "Process.spawn" do
children.each do |child|
-> do
Process.kill("TERM", child)
- end.should raise_error(Errno::ESRCH)
+ end.should.raise(Errno::ESRCH)
end
end
end
@@ -678,53 +678,93 @@ describe "Process.spawn" do
# error handling
it "raises an ArgumentError if passed no command arguments" do
- -> { Process.spawn }.should raise_error(ArgumentError)
+ -> { Process.spawn }.should.raise(ArgumentError)
end
it "raises an ArgumentError if passed env or options but no command arguments" do
- -> { Process.spawn({}) }.should raise_error(ArgumentError)
+ -> { Process.spawn({}) }.should.raise(ArgumentError)
end
it "raises an ArgumentError if passed env and options but no command arguments" do
- -> { Process.spawn({}, {}) }.should raise_error(ArgumentError)
+ -> { Process.spawn({}, {}) }.should.raise(ArgumentError)
end
it "raises an Errno::ENOENT for an empty string" do
- -> { Process.spawn "" }.should raise_error(Errno::ENOENT)
+ -> { Process.spawn "" }.should.raise(Errno::ENOENT)
end
it "raises an Errno::ENOENT if the command does not exist" do
- -> { Process.spawn "nonesuch" }.should raise_error(Errno::ENOENT)
+ -> { Process.spawn "nonesuch" }.should.raise(Errno::ENOENT, "No such file or directory - nonesuch")
+ end
+
+ it "sets $? to exit status 127 when the command does not exist" do
+ Process.spawn("nonesuch") rescue nil
+ $?.exitstatus.should == 127
+ end
+
+ it "raises an Errno::ENOENT if the file does not exist" do
+ -> { Process.spawn "./nonesuch" }.should.raise(Errno::ENOENT, "No such file or directory - ./nonesuch")
+ end
+
+ it "sets $? to exit status 127 when the file does not exist" do
+ Process.spawn("./nonesuch") rescue nil
+ $?.exitstatus.should == 127
+ end
+
+ platform_is_not :windows do
+ it "raises an Errno::EACCES when the path is a directory" do
+ -> { Process.spawn "./" }.should.raise(Errno::EACCES, "Permission denied - ./")
+ end
end
unless File.executable?(__FILE__) # Some FS (e.g. vboxfs) locate all files executable
platform_is_not :windows do
it "raises an Errno::EACCES when the file does not have execute permissions" do
- -> { Process.spawn __FILE__ }.should raise_error(Errno::EACCES)
+ -> { Process.spawn __FILE__ }.should.raise(Errno::EACCES, "Permission denied - #{__FILE__}")
+ end
+
+ it "sets $? to exit status 127 when the file does not have execute permissions" do
+ Process.spawn(__FILE__) rescue nil
+ $?.exitstatus.should == 127
+ end
+
+ it "raises an Errno::ENOENT when a non-executable file is found in PATH" do
+ dir = tmp("spawn_path_non_executable_dir")
+ mkdir_p dir
+ begin
+ exe = 'process-spawn-non-executable-in-path'
+ File.write("#{dir}/#{exe}", "#!/bin/sh\necho hi")
+ File.chmod(0644, "#{dir}/#{exe}")
+ env = { "PATH" => "#{dir}#{File::PATH_SEPARATOR}#{ENV['PATH']}" }
+ -> { Process.spawn(env, exe) }.should.raise(Errno::ENOENT, "No such file or directory - #{exe}")
+ $?.exitstatus.should == 127
+ ensure
+ rm_r dir
+ end
end
end
platform_is :windows do
it "raises Errno::EACCES or Errno::ENOEXEC when the file is not an executable file" do
- -> { Process.spawn __FILE__ }.should raise_error(SystemCallError) { |e|
- [Errno::EACCES, Errno::ENOEXEC].should include(e.class)
+ -> { Process.spawn __FILE__ }.should.raise(SystemCallError) { |e|
+ [Errno::EACCES, Errno::ENOEXEC].should.include?(e.class)
}
end
end
end
it "raises an Errno::EACCES or Errno::EISDIR when passed a directory" do
- -> { Process.spawn __dir__ }.should raise_error(SystemCallError) { |e|
- [Errno::EACCES, Errno::EISDIR].should include(e.class)
+ -> { Process.spawn __dir__ }.should.raise(SystemCallError) { |e|
+ [Errno::EACCES, Errno::EISDIR].should.include?(e.class)
}
end
it "raises an ArgumentError when passed a string key in options" do
- -> { Process.spawn("echo", "chdir" => Dir.pwd) }.should raise_error(ArgumentError)
+ -> { Process.spawn("echo", "chdir" => Dir.pwd) }.should.raise(ArgumentError)
end
it "raises an ArgumentError when passed an unknown option key" do
- -> { Process.spawn("echo", nonesuch: :foo) }.should raise_error(ArgumentError)
+ -> { Process.spawn("echo", nonesuch: :foo) }.should.raise(ArgumentError)
end
platform_is_not :windows, :aix do
diff --git a/spec/ruby/core/process/status/bit_and_spec.rb b/spec/ruby/core/process/status/bit_and_spec.rb
index 0e0edb0afa..a5b1123e90 100644
--- a/spec/ruby/core/process/status/bit_and_spec.rb
+++ b/spec/ruby/core/process/status/bit_and_spec.rb
@@ -1,6 +1,6 @@
require_relative '../../../spec_helper'
-ruby_version_is ""..."3.5" do
+ruby_version_is ""..."4.0" do
describe "Process::Status#&" do
it "returns a bitwise and of the integer status of an exited child" do
@@ -17,13 +17,13 @@ ruby_version_is ""..."3.5" do
end
end
- ruby_version_is "3.3"..."3.5" do
+ ruby_version_is ""..."4.0" do
it "raises an ArgumentError if mask is negative" do
suppress_warning do
ruby_exe("exit(0)")
-> {
$? & -1
- }.should raise_error(ArgumentError, 'negative mask value: -1')
+ }.should.raise(ArgumentError, 'negative mask value: -1')
end
end
diff --git a/spec/ruby/core/process/status/exited_spec.rb b/spec/ruby/core/process/status/exited_spec.rb
index a61292b146..ad14b35000 100644
--- a/spec/ruby/core/process/status/exited_spec.rb
+++ b/spec/ruby/core/process/status/exited_spec.rb
@@ -7,7 +7,7 @@ describe "Process::Status#exited?" do
end
it "returns true" do
- $?.exited?.should be_true
+ $?.exited?.should == true
end
end
@@ -19,13 +19,13 @@ describe "Process::Status#exited?" do
platform_is_not :windows do
it "returns false" do
- $?.exited?.should be_false
+ $?.exited?.should == false
end
end
platform_is :windows do
it "always returns true" do
- $?.exited?.should be_true
+ $?.exited?.should == true
end
end
end
diff --git a/spec/ruby/core/process/status/right_shift_spec.rb b/spec/ruby/core/process/status/right_shift_spec.rb
index a1ab75141a..5689526f54 100644
--- a/spec/ruby/core/process/status/right_shift_spec.rb
+++ b/spec/ruby/core/process/status/right_shift_spec.rb
@@ -1,6 +1,6 @@
require_relative '../../../spec_helper'
-ruby_version_is ""..."3.5" do
+ruby_version_is ""..."4.0" do
describe "Process::Status#>>" do
it "returns a right shift of the integer status of an exited child" do
@@ -16,13 +16,13 @@ ruby_version_is ""..."3.5" do
end
end
- ruby_version_is "3.3"..."3.5" do
+ ruby_version_is ""..."4.0" do
it "raises an ArgumentError if shift value is negative" do
suppress_warning do
ruby_exe("exit(0)")
-> {
$? >> -1
- }.should raise_error(ArgumentError, 'negative shift value: -1')
+ }.should.raise(ArgumentError, 'negative shift value: -1')
end
end
diff --git a/spec/ruby/core/process/status/signaled_spec.rb b/spec/ruby/core/process/status/signaled_spec.rb
index c0de7b8006..8cf409bb42 100644
--- a/spec/ruby/core/process/status/signaled_spec.rb
+++ b/spec/ruby/core/process/status/signaled_spec.rb
@@ -7,7 +7,7 @@ describe "Process::Status#signaled?" do
end
it "returns false" do
- $?.signaled?.should be_false
+ $?.signaled?.should == false
end
end
@@ -18,13 +18,13 @@ describe "Process::Status#signaled?" do
platform_is_not :windows do
it "returns true" do
- $?.signaled?.should be_true
+ $?.signaled?.should == true
end
end
platform_is :windows do
it "always returns false" do
- $?.signaled?.should be_false
+ $?.signaled?.should == false
end
end
end
diff --git a/spec/ruby/core/process/status/success_spec.rb b/spec/ruby/core/process/status/success_spec.rb
index 3589cc611f..f61243c667 100644
--- a/spec/ruby/core/process/status/success_spec.rb
+++ b/spec/ruby/core/process/status/success_spec.rb
@@ -7,7 +7,7 @@ describe "Process::Status#success?" do
end
it "returns true" do
- $?.success?.should be_true
+ $?.success?.should == true
end
end
@@ -17,7 +17,7 @@ describe "Process::Status#success?" do
end
it "returns false" do
- $?.success?.should be_false
+ $?.success?.should == false
end
end
@@ -28,13 +28,13 @@ describe "Process::Status#success?" do
platform_is_not :windows do
it "returns nil" do
- $?.success?.should be_nil
+ $?.success?.should == nil
end
end
platform_is :windows do
it "always returns true" do
- $?.success?.should be_true
+ $?.success?.should == true
end
end
end
diff --git a/spec/ruby/core/process/status/termsig_spec.rb b/spec/ruby/core/process/status/termsig_spec.rb
index 9a22dbea71..1d57724d12 100644
--- a/spec/ruby/core/process/status/termsig_spec.rb
+++ b/spec/ruby/core/process/status/termsig_spec.rb
@@ -7,7 +7,7 @@ describe "Process::Status#termsig" do
end
it "returns nil" do
- $?.termsig.should be_nil
+ $?.termsig.should == nil
end
end
@@ -36,7 +36,7 @@ describe "Process::Status#termsig" do
platform_is :windows do
it "always returns nil" do
- $?.termsig.should be_nil
+ $?.termsig.should == nil
end
end
end
diff --git a/spec/ruby/core/process/status/to_i_spec.rb b/spec/ruby/core/process/status/to_i_spec.rb
index 39f8e2d84c..0bfb883d23 100644
--- a/spec/ruby/core/process/status/to_i_spec.rb
+++ b/spec/ruby/core/process/status/to_i_spec.rb
@@ -3,11 +3,11 @@ require_relative '../../../spec_helper'
describe "Process::Status#to_i" do
it "returns an integer when the child exits" do
ruby_exe('exit 48', exit_status: 48)
- $?.to_i.should be_an_instance_of(Integer)
+ $?.to_i.should.instance_of?(Integer)
end
it "returns an integer when the child is signaled" do
ruby_exe('raise SignalException, "TERM"', exit_status: platform_is(:windows) ? 3 : :SIGTERM)
- $?.to_i.should be_an_instance_of(Integer)
+ $?.to_i.should.instance_of?(Integer)
end
end
diff --git a/spec/ruby/core/process/status/wait_spec.rb b/spec/ruby/core/process/status/wait_spec.rb
index 57d56209a9..8bd7fc6b43 100644
--- a/spec/ruby/core/process/status/wait_spec.rb
+++ b/spec/ruby/core/process/status/wait_spec.rb
@@ -21,14 +21,14 @@ describe "Process::Status.wait" 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.should.instance_of?(Process::Status)
status.pid.should == pid
end
it "should not set $? to the Process::Status" do
pid = Process.spawn(ruby_cmd('exit'))
status = Process::Status.wait
- $?.should_not equal(status)
+ $?.should_not.equal?(status)
end
it "should not change the value of $?" do
@@ -36,13 +36,13 @@ describe "Process::Status.wait" do
Process.wait
status = $?
Process::Status.wait
- status.should equal($?)
+ status.should.equal?($?)
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)
+ -> { Process.kill(0, pid) }.should.raise(Errno::ESRCH)
end
it "waits for a specific child if a pid is given" do
@@ -50,14 +50,14 @@ describe "Process::Status.wait" do
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)
+ -> { Process.kill(0, pid1) }.should.raise(Errno::ESRCH)
+ -> { Process.kill(0, pid2) }.should.raise(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)
+ -> { Process.kill(0, pid1) }.should.raise(Errno::ESRCH)
end
# This spec is probably system-dependent.
@@ -70,31 +70,33 @@ describe "Process::Status.wait" do
end
# 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
+ guard -> { Process.respond_to?(:fork) } do
+ 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
+
+ Process::Status.wait(pid, Process::WNOHANG).should == nil
+
+ # wait for the child to setup its TERM handler
write.close
- sleep
- end
-
- Process::Status.wait(pid, Process::WNOHANG).should be_nil
-
- # wait for the child to setup its TERM handler
- write.close
- read.read(1)
- read.close
+ read.read(1)
+ read.close
- Process.kill("TERM", pid)
- Process::Status.wait.pid.should == pid
+ Process.kill("TERM", pid)
+ Process::Status.wait.pid.should == pid
+ end
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)
+ -> { Process.kill(0, pid) }.should.raise(Errno::ESRCH)
end
end
end
diff --git a/spec/ruby/core/process/times_spec.rb b/spec/ruby/core/process/times_spec.rb
index d3bff2cda9..a7ffbb79e5 100644
--- a/spec/ruby/core/process/times_spec.rb
+++ b/spec/ruby/core/process/times_spec.rb
@@ -2,7 +2,7 @@ require_relative '../../spec_helper'
describe "Process.times" do
it "returns a Process::Tms" do
- Process.times.should be_kind_of(Process::Tms)
+ Process.times.should.is_a?(Process::Tms)
end
# TODO: Intel C Compiler does not work this example
diff --git a/spec/ruby/core/process/uid_spec.rb b/spec/ruby/core/process/uid_spec.rb
index a068b1a2c1..1e218ef4fe 100644
--- a/spec/ruby/core/process/uid_spec.rb
+++ b/spec/ruby/core/process/uid_spec.rb
@@ -20,16 +20,16 @@ end
describe "Process.uid=" do
platform_is_not :windows do
it "raises TypeError if not passed an Integer" do
- -> { Process.uid = Object.new }.should raise_error(TypeError)
+ -> { Process.uid = Object.new }.should.raise(TypeError)
end
as_user do
it "raises Errno::ERPERM if run by a non privileged user trying to set the superuser id" do
- -> { (Process.uid = 0)}.should raise_error(Errno::EPERM)
+ -> { (Process.uid = 0)}.should.raise(Errno::EPERM)
end
it "raises Errno::ERPERM if run by a non privileged user trying to set the superuser id from username" do
- -> { Process.uid = "root" }.should raise_error(Errno::EPERM)
+ -> { Process.uid = "root" }.should.raise(Errno::EPERM)
end
end
diff --git a/spec/ruby/core/process/wait2_spec.rb b/spec/ruby/core/process/wait2_spec.rb
index 8ba429dc96..1fa6f76151 100644
--- a/spec/ruby/core/process/wait2_spec.rb
+++ b/spec/ruby/core/process/wait2_spec.rb
@@ -1,6 +1,9 @@
require_relative '../../spec_helper'
+require_relative 'fixtures/common'
describe "Process.wait2" do
+ ProcessSpecs.use_system_ruby(self)
+
before :all do
# HACK: this kludge is temporarily necessary because some
# misbehaving spec somewhere else does not clear processes
@@ -12,33 +15,31 @@ describe "Process.wait2" do
leaked = Process.waitall
$stderr.puts "leaked before wait2 specs: #{leaked}" unless leaked.empty?
# Ruby-space should not see PIDs used by rjit
- leaked.should be_empty
+ leaked.should.empty?
rescue Errno::ECHILD # No child processes
rescue NotImplementedError
end
end
- platform_is_not :windows do
- it "returns the pid and status of child process" do
- pidf = Process.fork { Process.exit! 99 }
- results = Process.wait2
- results.size.should == 2
- pidw, status = results
- pidf.should == pidw
- status.exitstatus.should == 99
- end
+ it "returns the pid and status of child process" do
+ pidf = Process.spawn(*ruby_exe, "-e", "exit 99")
+ results = Process.wait2
+ results.size.should == 2
+ pidw, status = results
+ pidf.should == pidw
+ status.exitstatus.should == 99
end
it "raises a StandardError if no child processes exist" do
- -> { Process.wait2 }.should raise_error(Errno::ECHILD)
- -> { Process.wait2 }.should raise_error(StandardError)
+ -> { Process.wait2 }.should.raise(Errno::ECHILD)
+ -> { Process.wait2 }.should.raise(StandardError)
end
it "returns nil if the child process is still running when given the WNOHANG flag" do
IO.popen(ruby_cmd('STDIN.getbyte'), "w") do |io|
pid, status = Process.wait2(io.pid, Process::WNOHANG)
- pid.should be_nil
- status.should be_nil
+ pid.should == nil
+ status.should == nil
io.write('a')
end
end
diff --git a/spec/ruby/core/process/wait_spec.rb b/spec/ruby/core/process/wait_spec.rb
index 385acc9928..5a1889487c 100644
--- a/spec/ruby/core/process/wait_spec.rb
+++ b/spec/ruby/core/process/wait_spec.rb
@@ -14,26 +14,37 @@ describe "Process.wait" do
end
it "raises an Errno::ECHILD if there are no child processes" do
- -> { Process.wait }.should raise_error(Errno::ECHILD)
+ -> { Process.wait }.should.raise(Errno::ECHILD)
end
- platform_is_not :windows do
- it "returns its child pid" do
- pid = Process.spawn(ruby_cmd('exit'))
- Process.wait.should == pid
- end
+ it "returns its child pid" do
+ pid = Process.spawn(ruby_cmd('exit'))
+ Process.wait.should == pid
+ end
- it "sets $? to a Process::Status" do
- pid = Process.spawn(ruby_cmd('exit'))
- Process.wait
- $?.should be_kind_of(Process::Status)
- $?.pid.should == pid
+ 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")
+ begin
+ Process.wait(pid, Process::WNOHANG).should == nil
+ Process.kill("KILL", pid)
+ ensure
+ Process.wait(pid)
end
+ end
+ it "sets $? to a Process::Status" do
+ pid = Process.spawn(ruby_cmd('exit'))
+ Process.wait
+ $?.should.is_a?(Process::Status)
+ $?.pid.should == pid
+ end
+
+ platform_is_not :windows do
it "waits for any child process if no pid is given" do
pid = Process.spawn(ruby_cmd('exit'))
Process.wait.should == pid
- -> { Process.kill(0, pid) }.should raise_error(Errno::ESRCH)
+ -> { Process.kill(0, pid) }.should.raise(Errno::ESRCH)
end
it "waits for a specific child if a pid is given" do
@@ -41,14 +52,14 @@ describe "Process.wait" do
pid2 = Process.spawn(ruby_cmd('exit'))
Process.wait(pid2).should == pid2
Process.wait(pid1).should == pid1
- -> { Process.kill(0, pid1) }.should raise_error(Errno::ESRCH)
- -> { Process.kill(0, pid2) }.should raise_error(Errno::ESRCH)
+ -> { Process.kill(0, pid1) }.should.raise(Errno::ESRCH)
+ -> { Process.kill(0, pid2) }.should.raise(Errno::ESRCH)
end
it "coerces the pid to an Integer" do
pid1 = Process.spawn(ruby_cmd('exit'))
Process.wait(mock_int(pid1)).should == pid1
- -> { Process.kill(0, pid1) }.should raise_error(Errno::ESRCH)
+ -> { Process.kill(0, pid1) }.should.raise(Errno::ESRCH)
end
# This spec is probably system-dependent.
@@ -59,8 +70,10 @@ describe "Process.wait" do
Process.wait(0).should == pid2
Process.wait.should == pid1
end
+ end
- # This spec is probably system-dependent.
+ # This spec is probably system-dependent.
+ guard -> { Process.respond_to?(:fork) } do
it "doesn't block if no child is available when WNOHANG is used" do
read, write = IO.pipe
pid = Process.fork do
@@ -71,7 +84,7 @@ describe "Process.wait" do
sleep
end
- Process.wait(pid, Process::WNOHANG).should be_nil
+ Process.wait(pid, Process::WNOHANG).should == nil
# wait for the child to setup its TERM handler
write.close
@@ -81,11 +94,13 @@ describe "Process.wait" do
Process.kill("TERM", pid)
Process.wait.should == pid
end
+ end
+ platform_is_not :windows do
it "always accepts flags=0" do
pid = Process.spawn(ruby_cmd('exit'))
Process.wait(-1, 0).should == pid
- -> { Process.kill(0, pid) }.should raise_error(Errno::ESRCH)
+ -> { Process.kill(0, pid) }.should.raise(Errno::ESRCH)
end
end
end
diff --git a/spec/ruby/core/process/waitall_spec.rb b/spec/ruby/core/process/waitall_spec.rb
index 6cf4e32bc9..f5fbce71c1 100644
--- a/spec/ruby/core/process/waitall_spec.rb
+++ b/spec/ruby/core/process/waitall_spec.rb
@@ -1,6 +1,9 @@
require_relative '../../spec_helper'
+require_relative 'fixtures/common'
describe "Process.waitall" do
+ ProcessSpecs.use_system_ruby(self)
+
before :all do
begin
Process.waitall
@@ -13,35 +16,28 @@ describe "Process.waitall" do
end
it "takes no arguments" do
- -> { Process.waitall(0) }.should raise_error(ArgumentError)
+ -> { Process.waitall(0) }.should.raise(ArgumentError)
end
platform_is_not :windows do
- it "waits for all children" do
+ it "waits for all children and returns an array of pid/status pairs" do
pids = []
- pids << Process.fork { Process.exit! 2 }
- pids << Process.fork { Process.exit! 1 }
- pids << Process.fork { Process.exit! 0 }
- Process.waitall
+ pids << Process.spawn(ruby_cmd('exit 2'))
+ pids << Process.spawn(ruby_cmd('exit 1'))
+ pids << Process.spawn(ruby_cmd('exit 0'))
+ a = Process.waitall
pids.each { |pid|
- -> { Process.kill(0, pid) }.should raise_error(Errno::ESRCH)
+ -> { Process.kill(0, pid) }.should.raise(Errno::ESRCH)
}
- end
- it "returns an array of pid/status pairs" do
- pids = []
- pids << Process.fork { Process.exit! 2 }
- pids << Process.fork { Process.exit! 1 }
- pids << Process.fork { Process.exit! 0 }
- a = Process.waitall
- a.should be_kind_of(Array)
+ a.should.is_a?(Array)
a.size.should == 3
pids.each { |pid|
pid_status = a.assoc(pid)
- pid_status.should be_kind_of(Array)
+ pid_status.should.is_a?(Array)
pid_status.size.should == 2
pid_status.first.should == pid
- pid_status.last.should be_kind_of(Process::Status)
+ pid_status.last.should.is_a?(Process::Status)
}
end
end
diff --git a/spec/ruby/core/process/waitpid2_spec.rb b/spec/ruby/core/process/waitpid2_spec.rb
index 45513af667..70fe0fbeee 100644
--- a/spec/ruby/core/process/waitpid2_spec.rb
+++ b/spec/ruby/core/process/waitpid2_spec.rb
@@ -1,5 +1,7 @@
require_relative '../../spec_helper'
describe "Process.waitpid2" do
- it "needs to be reviewed for spec completeness"
+ it "is an alias of Process.wait2" do
+ Process.method(:waitpid2).should == Process.method(:wait2)
+ end
end
diff --git a/spec/ruby/core/process/waitpid_spec.rb b/spec/ruby/core/process/waitpid_spec.rb
index a02147b663..9b2f49e7cf 100644
--- a/spec/ruby/core/process/waitpid_spec.rb
+++ b/spec/ruby/core/process/waitpid_spec.rb
@@ -1,14 +1,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")
- begin
- Process.waitpid(pid, Process::WNOHANG).should == nil
- Process.kill("KILL", pid)
- ensure
- Process.wait(pid)
- end
+ it "is an alias of Process.wait" do
+ Process.method(:waitpid).should == Process.method(:wait)
end
end
diff --git a/spec/ruby/core/process/warmup_spec.rb b/spec/ruby/core/process/warmup_spec.rb
index b562d52d22..4530ae222c 100644
--- a/spec/ruby/core/process/warmup_spec.rb
+++ b/spec/ruby/core/process/warmup_spec.rb
@@ -1,11 +1,9 @@
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
+ # 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
diff --git a/spec/ruby/core/queue/deq_spec.rb b/spec/ruby/core/queue/deq_spec.rb
index a2784e6a63..374611366e 100644
--- a/spec/ruby/core/queue/deq_spec.rb
+++ b/spec/ruby/core/queue/deq_spec.rb
@@ -1,11 +1,7 @@
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
- it_behaves_like :rb_num2dbl_fails, nil, -> v { q = Queue.new; q.push(1); q.deq(timeout: v) }
+ it "is an alias of Queue#pop" do
+ Queue.instance_method(:deq).should == Queue.instance_method(:pop)
+ end
end
diff --git a/spec/ruby/core/queue/enq_spec.rb b/spec/ruby/core/queue/enq_spec.rb
index c69c496fbc..76ecf0ca5f 100644
--- a/spec/ruby/core/queue/enq_spec.rb
+++ b/spec/ruby/core/queue/enq_spec.rb
@@ -1,6 +1,7 @@
require_relative '../../spec_helper'
-require_relative '../../shared/queue/enque'
describe "Queue#enq" do
- it_behaves_like :queue_enq, :enq, -> { Queue.new }
+ it "is an alias of Queue#<<" do
+ Queue.instance_method(:enq).should == Queue.instance_method(:<<)
+ end
end
diff --git a/spec/ruby/core/queue/initialize_spec.rb b/spec/ruby/core/queue/initialize_spec.rb
index 592fbe2487..080e4d0abd 100644
--- a/spec/ruby/core/queue/initialize_spec.rb
+++ b/spec/ruby/core/queue/initialize_spec.rb
@@ -35,26 +35,26 @@ describe "Queue#initialize" do
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)
+ -> { Queue.new(42) }.should.raise(TypeError)
+ -> { Queue.new(:abc) }.should.raise(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)
+ -> { Queue.new(enumerable) }.should.raise(NoMethodError)
end
end
it "raises TypeError if the provided Enumerable does not respond to #to_a" do
enumerable = MockObject.new('mock-enumerable')
- -> { Queue.new(enumerable) }.should raise_error(TypeError, "can't convert MockObject into Array")
+ -> { Queue.new(enumerable) }.should.raise(TypeError, "can't convert MockObject into Array")
end
it "raises TypeError if #to_a does not return Array" do
enumerable = MockObject.new('mock-enumerable')
enumerable.should_receive(:to_a).and_return("string")
- -> { Queue.new(enumerable) }.should raise_error(TypeError, "can't convert MockObject to Array (MockObject#to_a gives String)")
+ -> { Queue.new(enumerable) }.should raise_consistent_error(TypeError, "can't convert MockObject into Array (MockObject#to_a gives String)")
end
end
diff --git a/spec/ruby/core/queue/length_spec.rb b/spec/ruby/core/queue/length_spec.rb
index 25399b2b76..0566b1d547 100644
--- a/spec/ruby/core/queue/length_spec.rb
+++ b/spec/ruby/core/queue/length_spec.rb
@@ -1,6 +1,7 @@
require_relative '../../spec_helper'
-require_relative '../../shared/queue/length'
describe "Queue#length" do
- it_behaves_like :queue_length, :length, -> { Queue.new }
+ it "is an alias of Queue#size" do
+ Queue.instance_method(:length).should == Queue.instance_method(:size)
+ end
end
diff --git a/spec/ruby/core/queue/push_spec.rb b/spec/ruby/core/queue/push_spec.rb
index e936f9d282..ef622ac89d 100644
--- a/spec/ruby/core/queue/push_spec.rb
+++ b/spec/ruby/core/queue/push_spec.rb
@@ -1,6 +1,7 @@
require_relative '../../spec_helper'
-require_relative '../../shared/queue/enque'
describe "Queue#push" do
- it_behaves_like :queue_enq, :push, -> { Queue.new }
+ it "is an alias of Queue#<<" do
+ Queue.instance_method(:push).should == Queue.instance_method(:<<)
+ end
end
diff --git a/spec/ruby/core/queue/shift_spec.rb b/spec/ruby/core/queue/shift_spec.rb
index c105da74b2..074332359c 100644
--- a/spec/ruby/core/queue/shift_spec.rb
+++ b/spec/ruby/core/queue/shift_spec.rb
@@ -1,11 +1,7 @@
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
- it_behaves_like :rb_num2dbl_fails, nil, -> v { q = Queue.new; q.push(1); q.shift(timeout: v) }
+ it "is an alias of Queue#pop" do
+ Queue.instance_method(:shift).should == Queue.instance_method(:pop)
+ end
end
diff --git a/spec/ruby/core/random/new_seed_spec.rb b/spec/ruby/core/random/new_seed_spec.rb
index 7a93da99aa..b2741aaa31 100644
--- a/spec/ruby/core/random/new_seed_spec.rb
+++ b/spec/ruby/core/random/new_seed_spec.rb
@@ -2,7 +2,7 @@ require_relative '../../spec_helper'
describe "Random.new_seed" do
it "returns an Integer" do
- Random.new_seed.should be_an_instance_of(Integer)
+ Random.new_seed.should.instance_of?(Integer)
end
it "returns an arbitrary seed value each time" do
diff --git a/spec/ruby/core/random/new_spec.rb b/spec/ruby/core/random/new_spec.rb
index 90e2a9d6f2..e20d487137 100644
--- a/spec/ruby/core/random/new_spec.rb
+++ b/spec/ruby/core/random/new_spec.rb
@@ -1,17 +1,17 @@
require_relative "../../spec_helper"
describe "Random.new" do
it "returns a new instance of Random" do
- Random.new.should be_an_instance_of(Random)
+ Random.new.should.instance_of?(Random)
end
it "uses a random seed value if none is supplied" do
- Random.new.seed.should be_an_instance_of(Integer)
+ Random.new.seed.should.instance_of?(Integer)
end
it "returns Random instances initialized with different seeds" do
first = Random.new
second = Random.new
- (0..20).map { first.rand } .should_not == (0..20).map { second.rand }
+ (0..20).map { first.rand }.should_not == (0..20).map { second.rand }
end
it "accepts an Integer seed value as an argument" do
@@ -33,6 +33,6 @@ describe "Random.new" do
it "raises a RangeError if passed a Complex (with imaginary part) seed value as an argument" do
-> do
Random.new(Complex(20,2))
- end.should raise_error(RangeError)
+ end.should.raise(RangeError)
end
end
diff --git a/spec/ruby/core/random/rand_spec.rb b/spec/ruby/core/random/rand_spec.rb
index 9244177ab5..c882db6381 100644
--- a/spec/ruby/core/random/rand_spec.rb
+++ b/spec/ruby/core/random/rand_spec.rb
@@ -45,13 +45,13 @@ describe "Random.rand" do
it "coerces arguments to Integers with #to_int" do
obj = mock_numeric('int')
obj.should_receive(:to_int).and_return(99)
- Random.rand(obj).should be_kind_of(Integer)
+ Random.rand(obj).should.is_a?(Integer)
end
end
describe "Random#rand with Fixnum" do
it "returns an Integer" do
- Random.new.rand(20).should be_an_instance_of(Integer)
+ Random.new.rand(20).should.instance_of?(Integer)
end
it "returns a Fixnum greater than or equal to 0" do
@@ -82,20 +82,20 @@ describe "Random#rand with Fixnum" do
it "raises an ArgumentError when the argument is 0" do
-> do
Random.new.rand(0)
- end.should raise_error(ArgumentError)
+ end.should.raise(ArgumentError)
end
it "raises an ArgumentError when the argument is negative" do
-> do
Random.new.rand(-12)
- end.should raise_error(ArgumentError)
+ end.should.raise(ArgumentError)
end
end
describe "Random#rand with Bignum" do
it "typically returns a Bignum" do
rnd = Random.new(1)
- 10.times.map{ rnd.rand(bignum_value*2) }.max.should be_an_instance_of(Integer)
+ 10.times.map{ rnd.rand(bignum_value*2) }.max.should.instance_of?(Integer)
end
it "returns a Bignum greater than or equal to 0" do
@@ -121,13 +121,13 @@ describe "Random#rand with Bignum" do
it "raises an ArgumentError when the argument is negative" do
-> do
Random.new.rand(-bignum_value)
- end.should raise_error(ArgumentError)
+ end.should.raise(ArgumentError)
end
end
describe "Random#rand with Float" do
it "returns a Float" do
- Random.new.rand(20.43).should be_an_instance_of(Float)
+ Random.new.rand(20.43).should.instance_of?(Float)
end
it "returns a Float greater than or equal to 0.0" do
@@ -153,25 +153,25 @@ describe "Random#rand with Float" do
it "raises an ArgumentError when the argument is negative" do
-> do
Random.new.rand(-1.234567)
- end.should raise_error(ArgumentError)
+ end.should.raise(ArgumentError)
end
end
describe "Random#rand with Range" do
it "returns an element from the Range" do
- Random.new.rand(20..43).should be_an_instance_of(Integer)
+ Random.new.rand(20..43).should.instance_of?(Integer)
end
it "supports custom object types" do
- rand(RandomSpecs::CustomRangeInteger.new(1)..RandomSpecs::CustomRangeInteger.new(42)).should be_an_instance_of(RandomSpecs::CustomRangeInteger)
- rand(RandomSpecs::CustomRangeFloat.new(1.0)..RandomSpecs::CustomRangeFloat.new(42.0)).should be_an_instance_of(RandomSpecs::CustomRangeFloat)
- rand(Time.now..Time.now).should be_an_instance_of(Time)
+ rand(RandomSpecs::CustomRangeInteger.new(1)..RandomSpecs::CustomRangeInteger.new(42)).should.instance_of?(RandomSpecs::CustomRangeInteger)
+ rand(RandomSpecs::CustomRangeFloat.new(1.0)..RandomSpecs::CustomRangeFloat.new(42.0)).should.instance_of?(RandomSpecs::CustomRangeFloat)
+ rand(Time.now..Time.now).should.instance_of?(Time)
end
it "returns an object that is a member of the Range" do
prng = Random.new
r = 20..30
- 20.times { r.member?(prng.rand(r)).should be_true }
+ 20.times { r.member?(prng.rand(r)).should == true }
end
it "works with inclusive ranges" do
@@ -201,8 +201,8 @@ describe "Random#rand with Range" do
end
it "considers Integers as Floats if one end point is a float" do
- Random.new(42).rand(0.0..1).should be_kind_of(Float)
- Random.new(42).rand(0..1.0).should be_kind_of(Float)
+ Random.new(42).rand(0.0..1).should.is_a?(Float)
+ Random.new(42).rand(0..1.0).should.is_a?(Float)
end
it "returns a float within a given float range" do
@@ -213,12 +213,12 @@ describe "Random#rand with Range" do
it "raises an ArgumentError when the startpoint lacks #+ and #- methods" do
-> do
Random.new.rand(Object.new..67)
- end.should raise_error(ArgumentError)
+ end.should.raise(ArgumentError)
end
it "raises an ArgumentError when the endpoint lacks #+ and #- methods" do
-> do
Random.new.rand(68..Object.new)
- end.should raise_error(ArgumentError)
+ end.should.raise(ArgumentError)
end
end
diff --git a/spec/ruby/core/random/seed_spec.rb b/spec/ruby/core/random/seed_spec.rb
index bf4524fdd9..6529b2c873 100644
--- a/spec/ruby/core/random/seed_spec.rb
+++ b/spec/ruby/core/random/seed_spec.rb
@@ -2,7 +2,7 @@ require_relative '../../spec_helper'
describe "Random#seed" do
it "returns an Integer" do
- Random.new.seed.should be_kind_of(Integer)
+ Random.new.seed.should.is_a?(Integer)
end
it "returns an arbitrary seed if the constructor was called without arguments" do
diff --git a/spec/ruby/core/random/shared/bytes.rb b/spec/ruby/core/random/shared/bytes.rb
index 9afad3b7f8..86c64d5696 100644
--- a/spec/ruby/core/random/shared/bytes.rb
+++ b/spec/ruby/core/random/shared/bytes.rb
@@ -1,6 +1,6 @@
describe :random_bytes, shared: true do
it "returns a String" do
- @object.send(@method, 1).should be_an_instance_of(String)
+ @object.send(@method, 1).should.instance_of?(String)
end
it "returns a String of the length given as argument" do
diff --git a/spec/ruby/core/random/shared/rand.rb b/spec/ruby/core/random/shared/rand.rb
index d3b24b8851..655c75c9f1 100644
--- a/spec/ruby/core/random/shared/rand.rb
+++ b/spec/ruby/core/random/shared/rand.rb
@@ -1,9 +1,9 @@
describe :random_number, shared: true do
it "returns a Float if no max argument is passed" do
- @object.send(@method).should be_kind_of(Float)
+ @object.send(@method).should.is_a?(Float)
end
it "returns an Integer if an Integer argument is passed" do
- @object.send(@method, 20).should be_kind_of(Integer)
+ @object.send(@method, 20).should.is_a?(Integer)
end
end
diff --git a/spec/ruby/core/random/urandom_spec.rb b/spec/ruby/core/random/urandom_spec.rb
index 6f180e54ac..94e9423a06 100644
--- a/spec/ruby/core/random/urandom_spec.rb
+++ b/spec/ruby/core/random/urandom_spec.rb
@@ -2,7 +2,7 @@ require_relative '../../spec_helper'
describe "Random.urandom" do
it "returns a String" do
- Random.urandom(1).should be_an_instance_of(String)
+ Random.urandom(1).should.instance_of?(String)
end
it "returns a String of the length given as argument" do
@@ -12,7 +12,7 @@ describe "Random.urandom" do
it "raises an ArgumentError on a negative size" do
-> {
Random.urandom(-1)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
it "returns a binary String" do
diff --git a/spec/ruby/core/range/bsearch_spec.rb b/spec/ruby/core/range/bsearch_spec.rb
index 5254ab756c..151a1798cf 100644
--- a/spec/ruby/core/range/bsearch_spec.rb
+++ b/spec/ruby/core/range/bsearch_spec.rb
@@ -3,46 +3,46 @@ require_relative '../enumerable/shared/enumeratorized'
describe "Range#bsearch" do
it "returns an Enumerator when not passed a block" do
- (0..1).bsearch.should be_an_instance_of(Enumerator)
+ (0..1).bsearch.should.instance_of?(Enumerator)
end
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(TypeError, "wrong argument type Object (must be numeric, true, false or nil)")
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)")
+ -> { (0..1).bsearch { "1" } }.should.raise(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)")
+ -> { (0.0..1.0).bsearch { "1" } }.should.raise(TypeError, "wrong argument type String (must be numeric, true, false or nil)")
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(TypeError, "can't do binary search for MockObject")
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")
+ -> { ("a".."e").bsearch { true } }.should.raise(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 }.should.raise(TypeError, "can't do binary search for String")
end
context "with Integer values" do
context "with a block returning true or false" do
it "returns nil if the block returns false for every element" do
- (0...3).bsearch { |x| x > 3 }.should be_nil
+ (0...3).bsearch { |x| x > 3 }.should == nil
end
it "returns nil if the block returns nil for every element" do
- (0..3).bsearch { |x| nil }.should be_nil
+ (0..3).bsearch { |x| nil }.should == nil
end
it "returns minimum element if the block returns true for every element" do
@@ -62,21 +62,21 @@ describe "Range#bsearch" do
context "with a block returning negative, zero, positive numbers" do
it "returns nil if the block returns less than zero for every element" do
- (0..3).bsearch { |x| x <=> 5 }.should be_nil
+ (0..3).bsearch { |x| x <=> 5 }.should == nil
end
it "returns nil if the block returns greater than zero for every element" do
- (0..3).bsearch { |x| x <=> -1 }.should be_nil
+ (0..3).bsearch { |x| x <=> -1 }.should == nil
end
it "returns nil if the block never returns zero" do
- (0..3).bsearch { |x| x < 2 ? 1 : -1 }.should be_nil
+ (0..3).bsearch { |x| x < 2 ? 1 : -1 }.should == nil
end
it "accepts (+/-)Float::INFINITY from the block" do
- (0..4).bsearch { |x| Float::INFINITY }.should be_nil
- (0..4).bsearch { |x| -Float::INFINITY }.should be_nil
+ (0..4).bsearch { |x| Float::INFINITY }.should == nil
+ (0..4).bsearch { |x| -Float::INFINITY }.should == nil
end
it "returns an element at an index for which block returns 0.0" do
@@ -86,7 +86,7 @@ describe "Range#bsearch" do
it "returns an element at an index for which block returns 0" do
result = (0..4).bsearch { |x| x < 1 ? 1 : x > 3 ? -1 : 0 }
- [1, 2].should include(result)
+ [1, 2].should.include?(result)
end
end
@@ -111,11 +111,11 @@ describe "Range#bsearch" do
context "with Float values" do
context "with a block returning true or false" do
it "returns nil if the block returns false for every element" do
- (0.1...2.3).bsearch { |x| x > 3 }.should be_nil
+ (0.1...2.3).bsearch { |x| x > 3 }.should == nil
end
it "returns nil if the block returns nil for every element" do
- (-0.0..2.3).bsearch { |x| nil }.should be_nil
+ (-0.0..2.3).bsearch { |x| nil }.should == nil
end
it "returns minimum element if the block returns true for every element" do
@@ -163,20 +163,20 @@ describe "Range#bsearch" do
context "with a block returning negative, zero, positive numbers" do
it "returns nil if the block returns less than zero for every element" do
- (-2.0..3.2).bsearch { |x| x <=> 5 }.should be_nil
+ (-2.0..3.2).bsearch { |x| x <=> 5 }.should == nil
end
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
+ (0.3..3.0).bsearch { |x| x <=> -1 }.should == nil
end
it "returns nil if the block never returns zero" do
- (0.2..2.3).bsearch { |x| x < 2 ? 1 : -1 }.should be_nil
+ (0.2..2.3).bsearch { |x| x < 2 ? 1 : -1 }.should == nil
end
it "accepts (+/-)Float::INFINITY from the block" do
- (0.1..4.5).bsearch { |x| Float::INFINITY }.should be_nil
- (-5.0..4.0).bsearch { |x| -Float::INFINITY }.should be_nil
+ (0.1..4.5).bsearch { |x| Float::INFINITY }.should == nil
+ (-5.0..4.0).bsearch { |x| -Float::INFINITY }.should == nil
end
it "returns an element at an index for which block returns 0.0" do
@@ -244,15 +244,15 @@ describe "Range#bsearch" do
context "with a block returning negative, zero, positive numbers" do
it "returns nil if the block returns less than zero for every element" do
- eval("(0..)").bsearch { |x| -1 }.should be_nil
+ eval("(0..)").bsearch { |x| -1 }.should == nil
end
it "returns nil if the block never returns zero" do
- eval("(0..)").bsearch { |x| x > 5 ? -1 : 1 }.should be_nil
+ eval("(0..)").bsearch { |x| x > 5 ? -1 : 1 }.should == nil
end
it "accepts -Float::INFINITY from the block" do
- eval("(0..)").bsearch { |x| -Float::INFINITY }.should be_nil
+ eval("(0..)").bsearch { |x| -Float::INFINITY }.should == nil
end
it "returns an element at an index for which block returns 0.0" do
@@ -262,7 +262,7 @@ describe "Range#bsearch" do
it "returns an element at an index for which block returns 0" do
result = eval("(0..)").bsearch { |x| x < 1 ? 1 : x > 3 ? -1 : 0 }
- [1, 2, 3].should include(result)
+ [1, 2, 3].should.include?(result)
end
end
@@ -274,13 +274,13 @@ describe "Range#bsearch" do
context "with endless ranges and Float values" do
context "with a block returning true or false" do
it "returns nil if the block returns false for every element" do
- eval("(0.1..)").bsearch { |x| x < 0.0 }.should be_nil
- eval("(0.1...)").bsearch { |x| x < 0.0 }.should be_nil
+ eval("(0.1..)").bsearch { |x| x < 0.0 }.should == nil
+ eval("(0.1...)").bsearch { |x| x < 0.0 }.should == nil
end
it "returns nil if the block returns nil for every element" do
- eval("(-0.0..)").bsearch { |x| nil }.should be_nil
- eval("(-0.0...)").bsearch { |x| nil }.should be_nil
+ eval("(-0.0..)").bsearch { |x| nil }.should == nil
+ eval("(-0.0...)").bsearch { |x| nil }.should == nil
end
it "returns minimum element if the block returns true for every element" do
@@ -304,22 +304,22 @@ describe "Range#bsearch" do
context "with a block returning negative, zero, positive numbers" do
it "returns nil if the block returns less than zero for every element" do
- eval("(-2.0..)").bsearch { |x| -1 }.should be_nil
- eval("(-2.0...)").bsearch { |x| -1 }.should be_nil
+ eval("(-2.0..)").bsearch { |x| -1 }.should == nil
+ eval("(-2.0...)").bsearch { |x| -1 }.should == nil
end
it "returns nil if the block returns greater than zero for every element" do
- eval("(0.3..)").bsearch { |x| 1 }.should be_nil
- eval("(0.3...)").bsearch { |x| 1 }.should be_nil
+ eval("(0.3..)").bsearch { |x| 1 }.should == nil
+ eval("(0.3...)").bsearch { |x| 1 }.should == nil
end
it "returns nil if the block never returns zero" do
- eval("(0.2..)").bsearch { |x| x < 2 ? 1 : -1 }.should be_nil
+ eval("(0.2..)").bsearch { |x| x < 2 ? 1 : -1 }.should == nil
end
it "accepts (+/-)Float::INFINITY from the block" do
- eval("(0.1..)").bsearch { |x| Float::INFINITY }.should be_nil
- eval("(-5.0..)").bsearch { |x| -Float::INFINITY }.should be_nil
+ eval("(0.1..)").bsearch { |x| Float::INFINITY }.should == nil
+ eval("(-5.0..)").bsearch { |x| -Float::INFINITY }.should == nil
end
it "returns an element at an index for which block returns 0.0" do
@@ -362,15 +362,15 @@ describe "Range#bsearch" do
context "with a block returning negative, zero, positive numbers" do
it "returns nil if the block returns greater than zero for every element" do
- (..0).bsearch { |x| 1 }.should be_nil
+ (..0).bsearch { |x| 1 }.should == nil
end
it "returns nil if the block never returns zero" do
- (..0).bsearch { |x| x > 5 ? -1 : 1 }.should be_nil
+ (..0).bsearch { |x| x > 5 ? -1 : 1 }.should == nil
end
it "accepts Float::INFINITY from the block" do
- (..0).bsearch { |x| Float::INFINITY }.should be_nil
+ (..0).bsearch { |x| Float::INFINITY }.should == nil
end
it "returns an element at an index for which block returns 0.0" do
@@ -380,7 +380,7 @@ describe "Range#bsearch" do
it "returns an element at an index for which block returns 0" do
result = (...10).bsearch { |x| x < 1 ? 1 : x > 3 ? -1 : 0 }
- [1, 2, 3].should include(result)
+ [1, 2, 3].should.include?(result)
end
end
@@ -392,13 +392,13 @@ describe "Range#bsearch" do
context "with beginless ranges and Float values" do
context "with a block returning true or false" do
it "returns nil if the block returns true for every element" do
- (..-0.1).bsearch { |x| x > 0.0 }.should be_nil
- (...-0.1).bsearch { |x| x > 0.0 }.should be_nil
+ (..-0.1).bsearch { |x| x > 0.0 }.should == nil
+ (...-0.1).bsearch { |x| x > 0.0 }.should == nil
end
it "returns nil if the block returns nil for every element" do
- (..-0.1).bsearch { |x| nil }.should be_nil
- (...-0.1).bsearch { |x| nil }.should be_nil
+ (..-0.1).bsearch { |x| nil }.should == nil
+ (...-0.1).bsearch { |x| nil }.should == nil
end
it "returns the smallest element for which block returns true" do
@@ -417,22 +417,22 @@ describe "Range#bsearch" do
context "with a block returning negative, zero, positive numbers" do
it "returns nil if the block returns less than zero for every element" do
- (..5.0).bsearch { |x| -1 }.should be_nil
- (...5.0).bsearch { |x| -1 }.should be_nil
+ (..5.0).bsearch { |x| -1 }.should == nil
+ (...5.0).bsearch { |x| -1 }.should == nil
end
it "returns nil if the block returns greater than zero for every element" do
- (..1.1).bsearch { |x| 1 }.should be_nil
- (...1.1).bsearch { |x| 1 }.should be_nil
+ (..1.1).bsearch { |x| 1 }.should == nil
+ (...1.1).bsearch { |x| 1 }.should == nil
end
it "returns nil if the block never returns zero" do
- (..6.3).bsearch { |x| x < 2 ? 1 : -1 }.should be_nil
+ (..6.3).bsearch { |x| x < 2 ? 1 : -1 }.should == nil
end
it "accepts (+/-)Float::INFINITY from the block" do
- (..5.0).bsearch { |x| Float::INFINITY }.should be_nil
- (..7.0).bsearch { |x| -Float::INFINITY }.should be_nil
+ (..5.0).bsearch { |x| Float::INFINITY }.should == nil
+ (..7.0).bsearch { |x| -Float::INFINITY }.should == nil
end
it "returns an element at an index for which block returns 0.0" do
diff --git a/spec/ruby/core/range/case_compare_spec.rb b/spec/ruby/core/range/case_compare_spec.rb
index c9b253f0a5..7a76487d68 100644
--- a/spec/ruby/core/range/case_compare_spec.rb
+++ b/spec/ruby/core/range/case_compare_spec.rb
@@ -11,9 +11,7 @@ describe "Range#===" do
it_behaves_like :range_cover_and_include, :===
it_behaves_like :range_cover, :===
- ruby_bug "#19533", ""..."3.3" do
- it "returns true on any value if begin and end are both nil" do
- (nil..nil).should === 1
- end
+ it "returns true on any value if begin and end are both nil" do
+ (nil..nil).should === 1
end
end
diff --git a/spec/ruby/core/range/cover_spec.rb b/spec/ruby/core/range/cover_spec.rb
index c05bb50614..eb8d5453bf 100644
--- a/spec/ruby/core/range/cover_spec.rb
+++ b/spec/ruby/core/range/cover_spec.rb
@@ -9,6 +9,6 @@ describe "Range#cover?" do
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
+ ("\u{999}".."\u{9999}").cover?("\u{9995}").should == true
end
end
diff --git a/spec/ruby/core/range/each_spec.rb b/spec/ruby/core/range/each_spec.rb
index f10330d61d..b4389f864d 100644
--- a/spec/ruby/core/range/each_spec.rb
+++ b/spec/ruby/core/range/each_spec.rb
@@ -59,26 +59,26 @@ describe "Range#each" do
end
it "raises a TypeError beginless ranges" do
- -> { (..2).each { |x| x } }.should raise_error(TypeError)
+ -> { (..2).each { |x| x } }.should.raise(TypeError)
end
it "raises a TypeError if the first element does not respond to #succ" do
- -> { (0.5..2.4).each { |i| i } }.should raise_error(TypeError)
+ -> { (0.5..2.4).each { |i| i } }.should.raise(TypeError)
b = mock('x')
(a = mock('1')).should_receive(:<=>).with(b).and_return(1)
- -> { (a..b).each { |i| i } }.should raise_error(TypeError)
+ -> { (a..b).each { |i| i } }.should.raise(TypeError)
end
it "returns self" do
range = 1..10
- range.each{}.should equal(range)
+ range.each{}.should.equal?(range)
end
it "returns an enumerator when no block given" do
enum = (1..3).each
- enum.should be_an_instance_of(Enumerator)
+ enum.should.instance_of?(Enumerator)
enum.to_a.should == [1, 2, 3]
end
diff --git a/spec/ruby/core/range/entries_spec.rb b/spec/ruby/core/range/entries_spec.rb
new file mode 100644
index 0000000000..29296711dc
--- /dev/null
+++ b/spec/ruby/core/range/entries_spec.rb
@@ -0,0 +1,7 @@
+require_relative '../../spec_helper'
+
+describe "Range#entries" do
+ it "is an alias of Range#to_a" do
+ Range.instance_method(:entries).should == Range.instance_method(:to_a)
+ end
+end
diff --git a/spec/ruby/core/range/eql_spec.rb b/spec/ruby/core/range/eql_spec.rb
index fa6c71840e..cdc19c9331 100644
--- a/spec/ruby/core/range/eql_spec.rb
+++ b/spec/ruby/core/range/eql_spec.rb
@@ -5,6 +5,6 @@ describe "Range#eql?" do
it_behaves_like :range_eql, :eql?
it "returns false if the endpoints are not eql?" do
- (0..1).should_not eql(0..1.0)
+ (0..1).should_not.eql?(0..1.0)
end
end
diff --git a/spec/ruby/core/range/first_spec.rb b/spec/ruby/core/range/first_spec.rb
index 2af935f439..54bd73a4e8 100644
--- a/spec/ruby/core/range/first_spec.rb
+++ b/spec/ruby/core/range/first_spec.rb
@@ -21,7 +21,7 @@ describe "Range#first" do
end
it "raises an ArgumentError when count is negative" do
- -> { (0..2).first(-1) }.should raise_error(ArgumentError)
+ -> { (0..2).first(-1) }.should.raise(ArgumentError)
end
it "calls #to_int to convert the argument" do
@@ -32,7 +32,7 @@ describe "Range#first" do
it "raises a TypeError if #to_int does not return an Integer" do
obj = mock("to_int")
obj.should_receive(:to_int).and_return("1")
- -> { (2..3).first(obj) }.should raise_error(TypeError)
+ -> { (2..3).first(obj) }.should.raise(TypeError)
end
it "truncates the value when passed a Float" do
@@ -40,14 +40,14 @@ describe "Range#first" do
end
it "raises a TypeError when passed nil" do
- -> { (2..3).first(nil) }.should raise_error(TypeError)
+ -> { (2..3).first(nil) }.should.raise(TypeError)
end
it "raises a TypeError when passed a String" do
- -> { (2..3).first("1") }.should raise_error(TypeError)
+ -> { (2..3).first("1") }.should.raise(TypeError)
end
it "raises a RangeError when called on an beginless range" do
- -> { (..1).first }.should raise_error(RangeError)
+ -> { (..1).first }.should.raise(RangeError)
end
end
diff --git a/spec/ruby/core/range/hash_spec.rb b/spec/ruby/core/range/hash_spec.rb
index 4f2681e86e..087f5d6de8 100644
--- a/spec/ruby/core/range/hash_spec.rb
+++ b/spec/ruby/core/range/hash_spec.rb
@@ -15,10 +15,10 @@ describe "Range#hash" do
end
it "generates an Integer for the hash value" do
- (0..0).hash.should be_an_instance_of(Integer)
- (0..1).hash.should be_an_instance_of(Integer)
- (0...10).hash.should be_an_instance_of(Integer)
- (0..10).hash.should be_an_instance_of(Integer)
+ (0..0).hash.should.instance_of?(Integer)
+ (0..1).hash.should.instance_of?(Integer)
+ (0...10).hash.should.instance_of?(Integer)
+ (0..10).hash.should.instance_of?(Integer)
end
end
diff --git a/spec/ruby/core/range/include_spec.rb b/spec/ruby/core/range/include_spec.rb
index 449e18985b..e5cc0dc234 100644
--- a/spec/ruby/core/range/include_spec.rb
+++ b/spec/ruby/core/range/include_spec.rb
@@ -1,14 +1,98 @@
# encoding: binary
require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
require_relative 'shared/cover_and_include'
-require_relative 'shared/include'
-require_relative 'shared/cover'
describe "Range#include?" do
it_behaves_like :range_cover_and_include, :include?
- it_behaves_like :range_include, :include?
+
+ describe "on string elements" do
+ it "returns true if other is matched by element.succ" do
+ ('a'..'c').include?('b').should == true
+ ('a'...'c').include?('b').should == true
+ end
+
+ it "returns false if other is not matched by element.succ" do
+ ('a'..'c').include?('bc').should == false
+ ('a'...'c').include?('bc').should == false
+ end
+ end
+
+ describe "with weird succ" do
+ describe "when included end value" do
+ before :each do
+ @range = RangeSpecs::TenfoldSucc.new(1)..RangeSpecs::TenfoldSucc.new(99)
+ end
+
+ it "returns false if other is less than first element" do
+ @range.include?(RangeSpecs::TenfoldSucc.new(0)).should == false
+ end
+
+ it "returns true if other is equal as first element" do
+ @range.include?(RangeSpecs::TenfoldSucc.new(1)).should == true
+ end
+
+ it "returns true if other is matched by element.succ" do
+ @range.include?(RangeSpecs::TenfoldSucc.new(10)).should == true
+ end
+
+ it "returns false if other is not matched by element.succ" do
+ @range.include?(RangeSpecs::TenfoldSucc.new(2)).should == false
+ end
+
+ it "returns false if other is equal as last element but not matched by element.succ" do
+ @range.include?(RangeSpecs::TenfoldSucc.new(99)).should == false
+ end
+
+ it "returns false if other is greater than last element but matched by element.succ" do
+ @range.include?(RangeSpecs::TenfoldSucc.new(100)).should == false
+ end
+ end
+
+ describe "when excluded end value" do
+ before :each do
+ @range = RangeSpecs::TenfoldSucc.new(1)...RangeSpecs::TenfoldSucc.new(99)
+ end
+
+ it "returns false if other is less than first element" do
+ @range.include?(RangeSpecs::TenfoldSucc.new(0)).should == false
+ end
+
+ it "returns true if other is equal as first element" do
+ @range.include?(RangeSpecs::TenfoldSucc.new(1)).should == true
+ end
+
+ it "returns true if other is matched by element.succ" do
+ @range.include?(RangeSpecs::TenfoldSucc.new(10)).should == true
+ end
+
+ it "returns false if other is not matched by element.succ" do
+ @range.include?(RangeSpecs::TenfoldSucc.new(2)).should == false
+ end
+
+ it "returns false if other is equal as last element but not matched by element.succ" do
+ @range.include?(RangeSpecs::TenfoldSucc.new(99)).should == false
+ end
+
+ it "returns false if other is greater than last element but matched by element.succ" do
+ @range.include?(RangeSpecs::TenfoldSucc.new(100)).should == false
+ end
+ end
+ end
+
+ describe "with Time endpoints" do
+ it "uses cover? logic" do
+ now = Time.now
+ range = (now..(now + 60))
+
+ range.include?(now).should == true
+ range.include?(now - 1).should == false
+ range.include?(now + 60).should == true
+ range.include?(now + 61).should == false
+ end
+ end
it "does not include U+9995 in the range U+0999..U+9999" do
- ("\u{999}".."\u{9999}").include?("\u{9995}").should be_false
+ ("\u{999}".."\u{9999}").include?("\u{9995}").should == false
end
end
diff --git a/spec/ruby/core/range/initialize_spec.rb b/spec/ruby/core/range/initialize_spec.rb
index c653caf0c6..b1a0565ab2 100644
--- a/spec/ruby/core/range/initialize_spec.rb
+++ b/spec/ruby/core/range/initialize_spec.rb
@@ -6,36 +6,36 @@ describe "Range#initialize" do
end
it "is private" do
- Range.should have_private_instance_method("initialize")
+ Range.private_instance_methods(false).should.include?(:initialize)
end
it "initializes correctly the Range object when given 2 arguments" do
- -> { @range.send(:initialize, 0, 1) }.should_not raise_error
+ -> { @range.send(:initialize, 0, 1) }.should_not.raise
end
it "initializes correctly the Range object when given 3 arguments" do
- -> { @range.send(:initialize, 0, 1, true) }.should_not raise_error
+ -> { @range.send(:initialize, 0, 1, true) }.should_not.raise
end
it "raises an ArgumentError if passed without or with only one argument" do
- -> { @range.send(:initialize) }.should raise_error(ArgumentError)
- -> { @range.send(:initialize, 1) }.should raise_error(ArgumentError)
+ -> { @range.send(:initialize) }.should.raise(ArgumentError)
+ -> { @range.send(:initialize, 1) }.should.raise(ArgumentError)
end
it "raises an ArgumentError if passed with four or more arguments" do
- -> { @range.send(:initialize, 1, 3, 5, 7) }.should raise_error(ArgumentError)
- -> { @range.send(:initialize, 1, 3, 5, 7, 9) }.should raise_error(ArgumentError)
+ -> { @range.send(:initialize, 1, 3, 5, 7) }.should.raise(ArgumentError)
+ -> { @range.send(:initialize, 1, 3, 5, 7, 9) }.should.raise(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)
+ -> { (0..1).send(:initialize, 1, 3) }.should.raise(FrozenError)
+ -> { (0..1).send(:initialize, 1, 3, true) }.should.raise(FrozenError)
end
it "raises an ArgumentError if arguments don't respond to <=>" do
o1 = Object.new
o2 = Object.new
- -> { @range.send(:initialize, o1, o2) }.should raise_error(ArgumentError)
+ -> { @range.send(:initialize, o1, o2) }.should.raise(ArgumentError)
end
end
diff --git a/spec/ruby/core/range/last_spec.rb b/spec/ruby/core/range/last_spec.rb
index 82b3e2ff53..a7db7f85a7 100644
--- a/spec/ruby/core/range/last_spec.rb
+++ b/spec/ruby/core/range/last_spec.rb
@@ -25,7 +25,7 @@ describe "Range#last" do
end
it "raises an ArgumentError when count is negative" do
- -> { (0..2).last(-1) }.should raise_error(ArgumentError)
+ -> { (0..2).last(-1) }.should.raise(ArgumentError)
end
it "calls #to_int to convert the argument" do
@@ -36,7 +36,7 @@ describe "Range#last" do
it "raises a TypeError if #to_int does not return an Integer" do
obj = mock("to_int")
obj.should_receive(:to_int).and_return("1")
- -> { (2..3).last(obj) }.should raise_error(TypeError)
+ -> { (2..3).last(obj) }.should.raise(TypeError)
end
it "truncates the value when passed a Float" do
@@ -44,14 +44,14 @@ describe "Range#last" do
end
it "raises a TypeError when passed nil" do
- -> { (2..3).last(nil) }.should raise_error(TypeError)
+ -> { (2..3).last(nil) }.should.raise(TypeError)
end
it "raises a TypeError when passed a String" do
- -> { (2..3).last("1") }.should raise_error(TypeError)
+ -> { (2..3).last("1") }.should.raise(TypeError)
end
it "raises a RangeError when called on an endless range" do
- -> { eval("(1..)").last }.should raise_error(RangeError)
+ -> { eval("(1..)").last }.should.raise(RangeError)
end
end
diff --git a/spec/ruby/core/range/max_spec.rb b/spec/ruby/core/range/max_spec.rb
index 8b83f69a5a..57714967ce 100644
--- a/spec/ruby/core/range/max_spec.rb
+++ b/spec/ruby/core/range/max_spec.rb
@@ -14,40 +14,40 @@ describe "Range#max" do
end
it "raises TypeError when called on an exclusive range and a non Integer value" do
- -> { (303.20...908.1111).max }.should raise_error(TypeError)
+ -> { (303.20...908.1111).max }.should.raise(TypeError)
end
it "returns nil when the endpoint is less than the start point" do
- (100..10).max.should be_nil
- ('z'..'l').max.should be_nil
+ (100..10).max.should == nil
+ ('z'..'l').max.should == nil
end
it "returns nil when the endpoint equals the start point and the range is exclusive" do
- (5...5).max.should be_nil
+ (5...5).max.should == nil
end
it "returns the endpoint when the endpoint equals the start point and the range is inclusive" do
- (5..5).max.should equal(5)
+ (5..5).max.should.equal?(5)
end
it "returns nil when the endpoint is less than the start point in a Float range" do
- (3003.20..908.1111).max.should be_nil
+ (3003.20..908.1111).max.should == nil
end
it "returns end point when the range is Time..Time(included end point)" do
time_start = Time.now
time_end = Time.now + 1.0
- (time_start..time_end).max.should equal(time_end)
+ (time_start..time_end).max.should.equal?(time_end)
end
it "raises TypeError when called on a Time...Time(excluded end point)" do
time_start = Time.now
time_end = Time.now + 1.0
- -> { (time_start...time_end).max }.should raise_error(TypeError)
+ -> { (time_start...time_end).max }.should.raise(TypeError)
end
it "raises RangeError when called on an endless range" do
- -> { eval("(1..)").max }.should raise_error(RangeError)
+ -> { eval("(1..)").max }.should.raise(RangeError)
end
it "returns the end point for beginless ranges" do
@@ -55,15 +55,15 @@ describe "Range#max" do
(..1.0).max.should == 1.0
end
- ruby_version_is ""..."3.5" do
+ ruby_version_is ""..."4.0" do
it "raises for an exclusive beginless Integer range" do
-> {
(...1).max
- }.should raise_error(TypeError, 'cannot exclude end value with non Integer begin value')
+ }.should.raise(TypeError, 'cannot exclude end value with non Integer begin value')
end
end
- ruby_version_is "3.5" do
+ ruby_version_is "4.0" do
it "returns the end point for exclusive beginless Integer ranges" do
(...1).max.should == 0
end
@@ -72,7 +72,7 @@ describe "Range#max" do
it "raises for an exclusive beginless non Integer range" do
-> {
(...1.0).max
- }.should raise_error(TypeError, 'cannot exclude non Integer end value')
+ }.should.raise(TypeError, 'cannot exclude non Integer end value')
end
end
@@ -82,7 +82,7 @@ describe "Range#max given a block" do
(1..10).max {|a,b| acc << [a,b]; a }
acc.flatten!
(1..10).each do |value|
- acc.include?(value).should be_true
+ acc.include?(value).should == true
end
end
@@ -104,12 +104,12 @@ describe "Range#max given a block" do
end
it "returns nil when the endpoint is less than the start point" do
- (100..10).max {|x,y| x <=> y}.should be_nil
- ('z'..'l').max {|x,y| x <=> y}.should be_nil
- (5...5).max {|x,y| x <=> y}.should be_nil
+ (100..10).max {|x,y| x <=> y}.should == nil
+ ('z'..'l').max {|x,y| x <=> y}.should == nil
+ (5...5).max {|x,y| x <=> y}.should == nil
end
it "raises RangeError when called with custom comparison method on an beginless range" do
- -> { (..1).max {|a, b| a} }.should raise_error(RangeError)
+ -> { (..1).max {|a, b| a} }.should.raise(RangeError)
end
end
diff --git a/spec/ruby/core/range/member_spec.rb b/spec/ruby/core/range/member_spec.rb
index 78299ae9e5..98835e4cf3 100644
--- a/spec/ruby/core/range/member_spec.rb
+++ b/spec/ruby/core/range/member_spec.rb
@@ -1,10 +1,7 @@
-# encoding: binary
require_relative '../../spec_helper'
-require_relative 'shared/cover_and_include'
-require_relative 'shared/include'
-require_relative 'shared/cover'
describe "Range#member?" do
- it_behaves_like :range_cover_and_include, :member?
- it_behaves_like :range_include, :member?
+ it "is an alias of Range#include?" do
+ Range.instance_method(:member?).should == Range.instance_method(:include?)
+ end
end
diff --git a/spec/ruby/core/range/min_spec.rb b/spec/ruby/core/range/min_spec.rb
index 89310ee589..9c83d3deca 100644
--- a/spec/ruby/core/range/min_spec.rb
+++ b/spec/ruby/core/range/min_spec.rb
@@ -11,32 +11,32 @@ describe "Range#min" do
end
it "returns nil when the start point is greater than the endpoint" do
- (100..10).min.should be_nil
- ('z'..'l').min.should be_nil
+ (100..10).min.should == nil
+ ('z'..'l').min.should == nil
end
it "returns nil when the endpoint equals the start point and the range is exclusive" do
- (7...7).min.should be_nil
+ (7...7).min.should == nil
end
it "returns the start point when the endpoint equals the start point and the range is inclusive" do
- (7..7).min.should equal(7)
+ (7..7).min.should.equal?(7)
end
it "returns nil when the start point is greater than the endpoint in a Float range" do
- (3003.20..908.1111).min.should be_nil
+ (3003.20..908.1111).min.should == nil
end
it "returns start point when the range is Time..Time(included end point)" do
time_start = Time.now
time_end = Time.now + 1.0
- (time_start..time_end).min.should equal(time_start)
+ (time_start..time_end).min.should.equal?(time_start)
end
it "returns start point when the range is Time...Time(excluded end point)" do
time_start = Time.now
time_end = Time.now + 1.0
- (time_start...time_end).min.should equal(time_start)
+ (time_start...time_end).min.should.equal?(time_start)
end
it "returns the start point for endless ranges" do
@@ -45,7 +45,7 @@ describe "Range#min" do
end
it "raises RangeError when called on an beginless range" do
- -> { (..1).min }.should raise_error(RangeError)
+ -> { (..1).min }.should.raise(RangeError)
end
end
@@ -55,7 +55,7 @@ describe "Range#min given a block" do
(1..10).min {|a,b| acc << [a,b]; a }
acc.flatten!
(1..10).each do |value|
- acc.include?(value).should be_true
+ acc.include?(value).should == true
end
end
@@ -77,12 +77,12 @@ describe "Range#min given a block" do
end
it "returns nil when the start point is greater than the endpoint" do
- (100..10).min {|x,y| x <=> y}.should be_nil
- ('z'..'l').min {|x,y| x <=> y}.should be_nil
- (7...7).min {|x,y| x <=> y}.should be_nil
+ (100..10).min {|x,y| x <=> y}.should == nil
+ ('z'..'l').min {|x,y| x <=> y}.should == nil
+ (7...7).min {|x,y| x <=> y}.should == nil
end
it "raises RangeError when called with custom comparison method on an endless range" do
- -> { eval("(1..)").min {|a, b| a} }.should raise_error(RangeError)
+ -> { eval("(1..)").min {|a, b| a} }.should.raise(RangeError)
end
end
diff --git a/spec/ruby/core/range/minmax_spec.rb b/spec/ruby/core/range/minmax_spec.rb
index 6651ae3726..16c7626ea3 100644
--- a/spec/ruby/core/range/minmax_spec.rb
+++ b/spec/ruby/core/range/minmax_spec.rb
@@ -17,19 +17,19 @@ describe 'Range#minmax' do
range = (@x..)
- -> { range.minmax }.should raise_error(RangeError, 'cannot get the maximum of endless range')
+ -> { range.minmax }.should.raise(RangeError, 'cannot get the maximum of endless range')
end
it 'raises RangeError or ArgumentError on a beginless range' do
range = (..@x)
- -> { range.minmax }.should raise_error(StandardError) { |e|
+ -> { range.minmax }.should.raise(StandardError) { |e|
if RangeError === e
# error from #min
- -> { raise e }.should raise_error(RangeError, 'cannot get the minimum of beginless range')
+ -> { raise e }.should.raise(RangeError, 'cannot get the minimum of beginless range')
else
# error from #max
- -> { raise e }.should raise_error(ArgumentError, 'comparison of NilClass with MockObject failed')
+ -> { raise e }.should.raise(ArgumentError, 'comparison of NilClass with MockObject failed')
end
}
end
@@ -76,13 +76,13 @@ describe 'Range#minmax' do
@x.should_not_receive(:succ)
range = (@x...)
- -> { range.minmax }.should raise_error(RangeError, 'cannot get the maximum of endless range')
+ -> { range.minmax }.should.raise(RangeError, 'cannot get the maximum of endless range')
end
it 'should raise RangeError on a beginless range' do
range = (...@x)
- -> { range.minmax }.should raise_error(RangeError,
+ -> { range.minmax }.should.raise(RangeError,
/cannot get the maximum of beginless range with custom comparison method|cannot get the minimum of beginless range/)
end
@@ -118,7 +118,7 @@ describe 'Range#minmax' do
it 'raises TypeError if the end value is not an integer' do
range = (0...Float::INFINITY)
- -> { range.minmax }.should raise_error(TypeError, 'cannot exclude non Integer end value')
+ -> { range.minmax }.should.raise(TypeError, 'cannot exclude non Integer end value')
end
it 'should return the minimum and maximum values according to the provided block by iterating the range' do
diff --git a/spec/ruby/core/range/new_spec.rb b/spec/ruby/core/range/new_spec.rb
index 3cab887799..9a35f28c7e 100644
--- a/spec/ruby/core/range/new_spec.rb
+++ b/spec/ruby/core/range/new_spec.rb
@@ -25,12 +25,12 @@ describe "Range.new" do
end
it "raises an ArgumentError when the given start and end can't be compared by using #<=>" do
- -> { Range.new(1, mock('x')) }.should raise_error(ArgumentError)
- -> { Range.new(mock('x'), mock('y')) }.should raise_error(ArgumentError)
+ -> { Range.new(1, mock('x')) }.should.raise(ArgumentError)
+ -> { Range.new(mock('x'), mock('y')) }.should.raise(ArgumentError)
b = mock('x')
(a = mock('nil')).should_receive(:<=>).with(b).and_return(nil)
- -> { Range.new(a, b) }.should raise_error(ArgumentError)
+ -> { Range.new(a, b) }.should.raise(ArgumentError)
end
it "does not rescue exception raised in #<=> when compares the given start and end" do
@@ -38,7 +38,7 @@ describe "Range.new" do
a = mock('b')
a.should_receive(:<=>).with(b).and_raise(RangeSpecs::ComparisonError)
- -> { Range.new(a, b) }.should raise_error(RangeSpecs::ComparisonError)
+ -> { Range.new(a, b) }.should.raise(RangeSpecs::ComparisonError)
end
describe "beginless/endless range" do
diff --git a/spec/ruby/core/range/overlap_spec.rb b/spec/ruby/core/range/overlap_spec.rb
index 9b6fc13493..201cd2b1ff 100644
--- a/spec/ruby/core/range/overlap_spec.rb
+++ b/spec/ruby/core/range/overlap_spec.rb
@@ -1,89 +1,87 @@
require_relative '../../spec_helper'
-ruby_version_is '3.3' do
- describe "Range#overlap?" do
- it "returns true if other Range overlaps self" do
- (0..2).overlap?(1..3).should == true
- (1..3).overlap?(0..2).should == true
- (0..2).overlap?(0..2).should == true
- (0..3).overlap?(1..2).should == true
- (1..2).overlap?(0..3).should == true
-
- ('a'..'c').overlap?('b'..'d').should == true
- end
-
- it "returns false if other Range does not overlap self" do
- (0..2).overlap?(3..4).should == false
- (0..2).overlap?(-4..-1).should == false
-
- ('a'..'c').overlap?('d'..'f').should == false
- end
-
- it "raises TypeError when called with non-Range argument" do
- -> {
- (0..2).overlap?(1)
- }.should raise_error(TypeError, "wrong argument type Integer (expected Range)")
- end
-
- it "returns true when beginningless and endless Ranges overlap" do
- (0..2).overlap?(..3).should == true
- (0..2).overlap?(..1).should == true
- (0..2).overlap?(..0).should == true
-
- (..3).overlap?(0..2).should == true
- (..1).overlap?(0..2).should == true
- (..0).overlap?(0..2).should == true
-
- (0..2).overlap?(-1..).should == true
- (0..2).overlap?(1..).should == true
- (0..2).overlap?(2..).should == true
-
- (-1..).overlap?(0..2).should == true
- (1..).overlap?(0..2).should == true
- (2..).overlap?(0..2).should == true
-
- (0..).overlap?(2..).should == true
- (..0).overlap?(..2).should == true
- end
-
- it "returns false when beginningless and endless Ranges do not overlap" do
- (0..2).overlap?(..-1).should == false
- (0..2).overlap?(3..).should == false
-
- (..-1).overlap?(0..2).should == false
- (3..).overlap?(0..2).should == false
- end
-
- it "returns false when Ranges are not compatible" do
- (0..2).overlap?('a'..'d').should == false
- end
-
- it "return false when self is empty" do
- (2..0).overlap?(1..3).should == false
- (2...2).overlap?(1..3).should == false
- (1...1).overlap?(1...1).should == false
- (2..0).overlap?(2..0).should == false
-
- ('c'..'a').overlap?('b'..'d').should == false
- ('a'...'a').overlap?('b'..'d').should == false
- ('b'...'b').overlap?('b'...'b').should == false
- ('c'...'a').overlap?('c'...'a').should == false
- end
-
- it "return false when other Range is empty" do
- (1..3).overlap?(2..0).should == false
- (1..3).overlap?(2...2).should == false
-
- ('b'..'d').overlap?('c'..'a').should == false
- ('b'..'d').overlap?('c'...'c').should == false
- end
-
- it "takes into account exclusive end" do
- (0...2).overlap?(2..4).should == false
- (2..4).overlap?(0...2).should == false
-
- ('a'...'c').overlap?('c'..'e').should == false
- ('c'..'e').overlap?('a'...'c').should == false
- end
+describe "Range#overlap?" do
+ it "returns true if other Range overlaps self" do
+ (0..2).overlap?(1..3).should == true
+ (1..3).overlap?(0..2).should == true
+ (0..2).overlap?(0..2).should == true
+ (0..3).overlap?(1..2).should == true
+ (1..2).overlap?(0..3).should == true
+
+ ('a'..'c').overlap?('b'..'d').should == true
+ end
+
+ it "returns false if other Range does not overlap self" do
+ (0..2).overlap?(3..4).should == false
+ (0..2).overlap?(-4..-1).should == false
+
+ ('a'..'c').overlap?('d'..'f').should == false
+ end
+
+ it "raises TypeError when called with non-Range argument" do
+ -> {
+ (0..2).overlap?(1)
+ }.should.raise(TypeError, "wrong argument type Integer (expected Range)")
+ end
+
+ it "returns true when beginningless and endless Ranges overlap" do
+ (0..2).overlap?(..3).should == true
+ (0..2).overlap?(..1).should == true
+ (0..2).overlap?(..0).should == true
+
+ (..3).overlap?(0..2).should == true
+ (..1).overlap?(0..2).should == true
+ (..0).overlap?(0..2).should == true
+
+ (0..2).overlap?(-1..).should == true
+ (0..2).overlap?(1..).should == true
+ (0..2).overlap?(2..).should == true
+
+ (-1..).overlap?(0..2).should == true
+ (1..).overlap?(0..2).should == true
+ (2..).overlap?(0..2).should == true
+
+ (0..).overlap?(2..).should == true
+ (..0).overlap?(..2).should == true
+ end
+
+ it "returns false when beginningless and endless Ranges do not overlap" do
+ (0..2).overlap?(..-1).should == false
+ (0..2).overlap?(3..).should == false
+
+ (..-1).overlap?(0..2).should == false
+ (3..).overlap?(0..2).should == false
+ end
+
+ it "returns false when Ranges are not compatible" do
+ (0..2).overlap?('a'..'d').should == false
+ end
+
+ it "return false when self is empty" do
+ (2..0).overlap?(1..3).should == false
+ (2...2).overlap?(1..3).should == false
+ (1...1).overlap?(1...1).should == false
+ (2..0).overlap?(2..0).should == false
+
+ ('c'..'a').overlap?('b'..'d').should == false
+ ('a'...'a').overlap?('b'..'d').should == false
+ ('b'...'b').overlap?('b'...'b').should == false
+ ('c'...'a').overlap?('c'...'a').should == false
+ end
+
+ it "return false when other Range is empty" do
+ (1..3).overlap?(2..0).should == false
+ (1..3).overlap?(2...2).should == false
+
+ ('b'..'d').overlap?('c'..'a').should == false
+ ('b'..'d').overlap?('c'...'c').should == false
+ end
+
+ it "takes into account exclusive end" do
+ (0...2).overlap?(2..4).should == false
+ (2..4).overlap?(0...2).should == false
+
+ ('a'...'c').overlap?('c'..'e').should == false
+ ('c'..'e').overlap?('a'...'c').should == false
end
end
diff --git a/spec/ruby/core/range/reverse_each_spec.rb b/spec/ruby/core/range/reverse_each_spec.rb
index b51e04c3ff..49790e8b0a 100644
--- a/spec/ruby/core/range/reverse_each_spec.rb
+++ b/spec/ruby/core/range/reverse_each_spec.rb
@@ -1,102 +1,124 @@
require_relative '../../spec_helper'
-ruby_version_is "3.3" do
- describe "Range#reverse_each" do
- it "traverses the Range in reverse order and passes each element to block" do
- a = []
- (1..3).reverse_each { |i| a << i }
- a.should == [3, 2, 1]
+describe "Range#reverse_each" do
+ it "traverses the Range in reverse order and passes each element to block" do
+ a = []
+ (1..3).reverse_each { |i| a << i }
+ a.should == [3, 2, 1]
+
+ a = []
+ (1...3).reverse_each { |i| a << i }
+ a.should == [2, 1]
+ end
- a = []
- (1...3).reverse_each { |i| a << i }
- a.should == [2, 1]
- end
+ it "returns self" do
+ r = (1..3)
+ r.reverse_each { |x| }.should.equal?(r)
+ end
- it "returns self" do
- r = (1..3)
- r.reverse_each { |x| }.should equal(r)
- end
+ it "returns an Enumerator if no block given" do
+ enum = (1..3).reverse_each
+ enum.should.instance_of?(Enumerator)
+ enum.to_a.should == [3, 2, 1]
+ end
- it "returns an Enumerator if no block given" do
- enum = (1..3).reverse_each
- enum.should be_an_instance_of(Enumerator)
- enum.to_a.should == [3, 2, 1]
- end
+ it "raises a TypeError for endless Ranges of Integers" do
+ -> {
+ (1..).reverse_each.take(3)
+ }.should.raise(TypeError, "can't iterate from NilClass")
+ end
- it "raises a TypeError for endless Ranges of Integers" do
- -> {
- (1..).reverse_each.take(3)
- }.should raise_error(TypeError, "can't iterate from NilClass")
- end
+ it "raises a TypeError for endless Ranges of non-Integers" do
+ -> {
+ ("a"..).reverse_each.take(3)
+ }.should.raise(TypeError, "can't iterate from NilClass")
+ end
- it "raises a TypeError for endless Ranges of non-Integers" do
- -> {
- ("a"..).reverse_each.take(3)
- }.should raise_error(TypeError, "can't iterate from NilClass")
+ context "Integer boundaries" do
+ it "supports beginningless Ranges" do
+ (..5).reverse_each.take(3).should == [5, 4, 3]
end
+ end
- context "Integer boundaries" do
- it "supports beginningless Ranges" do
- (..5).reverse_each.take(3).should == [5, 4, 3]
- end
+ context "non-Integer boundaries" do
+ it "uses #succ to iterate a Range of non-Integer elements" do
+ y = mock('y')
+ x = mock('x')
+
+ x.should_receive(:succ).any_number_of_times.and_return(y)
+ x.should_receive(:<=>).with(y).any_number_of_times.and_return(-1)
+ x.should_receive(:<=>).with(x).any_number_of_times.and_return(0)
+ y.should_receive(:<=>).with(x).any_number_of_times.and_return(1)
+ y.should_receive(:<=>).with(y).any_number_of_times.and_return(0)
+
+ a = []
+ (x..y).each { |i| a << i }
+ a.should == [x, y]
end
- context "non-Integer boundaries" do
- it "uses #succ to iterate a Range of non-Integer elements" do
- y = mock('y')
- x = mock('x')
+ it "uses #succ to iterate a Range of Strings" do
+ a = []
+ ('A'..'D').reverse_each { |i| a << i }
+ a.should == ['D','C','B','A']
+ end
- x.should_receive(:succ).any_number_of_times.and_return(y)
- x.should_receive(:<=>).with(y).any_number_of_times.and_return(-1)
- x.should_receive(:<=>).with(x).any_number_of_times.and_return(0)
- y.should_receive(:<=>).with(x).any_number_of_times.and_return(1)
- y.should_receive(:<=>).with(y).any_number_of_times.and_return(0)
+ it "uses #succ to iterate a Range of Symbols" do
+ a = []
+ (:A..:D).reverse_each { |i| a << i }
+ a.should == [:D, :C, :B, :A]
+ end
- a = []
- (x..y).each { |i| a << i }
- a.should == [x, y]
- end
+ it "raises a TypeError when `begin` value does not respond to #succ" do
+ -> { (Time.now..Time.now).reverse_each { |x| x } }.should.raise(TypeError, /can't iterate from Time/)
+ -> { (//..//).reverse_each { |x| x } }.should.raise(TypeError, /can't iterate from Regexp/)
+ -> { ([]..[]).reverse_each { |x| x } }.should.raise(TypeError, /can't iterate from Array/)
+ end
- it "uses #succ to iterate a Range of Strings" do
- a = []
- ('A'..'D').reverse_each { |i| a << i }
- a.should == ['D','C','B','A']
- end
+ it "does not support beginningless Ranges" do
+ -> {
+ (..'a').reverse_each { |x| x }
+ }.should.raise(TypeError, /can't iterate from NilClass/)
+ end
+ end
- it "uses #succ to iterate a Range of Symbols" do
- a = []
- (:A..:D).reverse_each { |i| a << i }
- a.should == [:D, :C, :B, :A]
- end
+ context "when no block is given" do
+ describe "returned Enumerator size" do
+ it "returns the Range size when Range size is finite" do
+ (1..3).reverse_each.size.should == 3
+ (1...3).reverse_each.size.should == 2
- it "raises a TypeError when `begin` value does not respond to #succ" do
- -> { (Time.now..Time.now).reverse_each { |x| x } }.should raise_error(TypeError, /can't iterate from Time/)
- -> { (//..//).reverse_each { |x| x } }.should raise_error(TypeError, /can't iterate from Regexp/)
- -> { ([]..[]).reverse_each { |x| x } }.should raise_error(TypeError, /can't iterate from Array/)
+ (1..3.3).reverse_each.size.should == 3
+ (1...3.3).reverse_each.size.should == 3
end
- it "does not support beginningless Ranges" do
- -> {
- (..'a').reverse_each { |x| x }
- }.should raise_error(TypeError, /can't iterate from NilClass/)
+ ruby_version_is ""..."3.4" do
+ it "returns a size when it is not iterable" do
+ (1.1..3).reverse_each.size.should == 2
+ (1.1..3.3).reverse_each.size.should == 3
+ (1.1..nil).reverse_each.size.should == Float::INFINITY
+ (nil..3.3).reverse_each.size.should == Float::INFINITY
+ (nil..nil).reverse_each.size.should == nil
+ end
end
- end
- context "when no block is given" do
- describe "returned Enumerator size" do
- it "returns the Range size when Range size is finite" do
- (1..3).reverse_each.size.should == 3
+ ruby_version_is "3.4" do
+ it "raises TypeError when the range is not iterable" do
+ -> { (1.1..3).reverse_each.size }.should.raise(TypeError, /can't iterate from Integer/)
+ -> { (1.1..3.3).reverse_each.size }.should.raise(TypeError, /can't iterate from Float/)
+ -> { (1.1..nil).reverse_each.size }.should.raise(TypeError, /can't iterate from NilClass/)
+ -> { (nil..3.3).reverse_each.size }.should.raise(TypeError, /can't iterate from Float/)
+ -> { (nil..nil).reverse_each.size }.should.raise(TypeError, /can't iterate from NilClass/)
end
+ end
- ruby_bug "#20936", "3.4"..."3.5" do
- it "returns Infinity when Range size is infinite" do
- (..3).reverse_each.size.should == Float::INFINITY
- end
+ ruby_bug "#20936", "3.4"..."4.0" do
+ it "returns Infinity when Range size is infinite" do
+ (..3).reverse_each.size.should == Float::INFINITY
end
+ end
- it "returns nil when Range size is unknown" do
- ('a'..'z').reverse_each.size.should == nil
- end
+ it "returns nil when Range size is unknown" do
+ ('a'..'z').reverse_each.size.should == nil
end
end
end
diff --git a/spec/ruby/core/range/shared/cover.rb b/spec/ruby/core/range/shared/cover.rb
index eaefb45942..189f3da4bf 100644
--- a/spec/ruby/core/range/shared/cover.rb
+++ b/spec/ruby/core/range/shared/cover.rb
@@ -6,26 +6,26 @@ describe :range_cover, shared: true do
it "uses the range element's <=> to make the comparison" do
a = mock('a')
a.should_receive(:<=>).twice.and_return(-1,-1)
- (a..'z').send(@method, 'b').should be_true
+ (a..'z').send(@method, 'b').should == true
end
it "uses a continuous inclusion test" do
- ('a'..'f').send(@method, 'aa').should be_true
- ('a'..'f').send(@method, 'babe').should be_true
- ('a'..'f').send(@method, 'baby').should be_true
- ('a'..'f').send(@method, 'ga').should be_false
- (-10..-2).send(@method, -2.5).should be_true
+ ('a'..'f').send(@method, 'aa').should == true
+ ('a'..'f').send(@method, 'babe').should == true
+ ('a'..'f').send(@method, 'baby').should == true
+ ('a'..'f').send(@method, 'ga').should == false
+ (-10..-2).send(@method, -2.5).should == true
end
describe "on string elements" do
it "returns true if other is matched by element.succ" do
- ('a'..'c').send(@method, 'b').should be_true
- ('a'...'c').send(@method, 'b').should be_true
+ ('a'..'c').send(@method, 'b').should == true
+ ('a'...'c').send(@method, 'b').should == true
end
it "returns true if other is not matched by element.succ" do
- ('a'..'c').send(@method, 'bc').should be_true
- ('a'...'c').send(@method, 'bc').should be_true
+ ('a'..'c').send(@method, 'bc').should == true
+ ('a'...'c').send(@method, 'bc').should == true
end
end
@@ -36,27 +36,27 @@ describe :range_cover, shared: true do
end
it "returns false if other is less than first element" do
- @range.send(@method, RangeSpecs::TenfoldSucc.new(0)).should be_false
+ @range.send(@method, RangeSpecs::TenfoldSucc.new(0)).should == false
end
it "returns true if other is equal as first element" do
- @range.send(@method, RangeSpecs::TenfoldSucc.new(1)).should be_true
+ @range.send(@method, RangeSpecs::TenfoldSucc.new(1)).should == true
end
it "returns true if other is matched by element.succ" do
- @range.send(@method, RangeSpecs::TenfoldSucc.new(10)).should be_true
+ @range.send(@method, RangeSpecs::TenfoldSucc.new(10)).should == true
end
it "returns true if other is not matched by element.succ" do
- @range.send(@method, RangeSpecs::TenfoldSucc.new(2)).should be_true
+ @range.send(@method, RangeSpecs::TenfoldSucc.new(2)).should == true
end
it "returns true if other is equal as last element but not matched by element.succ" do
- @range.send(@method, RangeSpecs::TenfoldSucc.new(99)).should be_true
+ @range.send(@method, RangeSpecs::TenfoldSucc.new(99)).should == true
end
it "returns false if other is greater than last element but matched by element.succ" do
- @range.send(@method, RangeSpecs::TenfoldSucc.new(100)).should be_false
+ @range.send(@method, RangeSpecs::TenfoldSucc.new(100)).should == false
end
end
@@ -66,27 +66,27 @@ describe :range_cover, shared: true do
end
it "returns false if other is less than first element" do
- @range.send(@method, RangeSpecs::TenfoldSucc.new(0)).should be_false
+ @range.send(@method, RangeSpecs::TenfoldSucc.new(0)).should == false
end
it "returns true if other is equal as first element" do
- @range.send(@method, RangeSpecs::TenfoldSucc.new(1)).should be_true
+ @range.send(@method, RangeSpecs::TenfoldSucc.new(1)).should == true
end
it "returns true if other is matched by element.succ" do
- @range.send(@method, RangeSpecs::TenfoldSucc.new(10)).should be_true
+ @range.send(@method, RangeSpecs::TenfoldSucc.new(10)).should == true
end
it "returns true if other is not matched by element.succ" do
- @range.send(@method, RangeSpecs::TenfoldSucc.new(2)).should be_true
+ @range.send(@method, RangeSpecs::TenfoldSucc.new(2)).should == true
end
it "returns false if other is equal as last element but not matched by element.succ" do
- @range.send(@method, RangeSpecs::TenfoldSucc.new(99)).should be_false
+ @range.send(@method, RangeSpecs::TenfoldSucc.new(99)).should == false
end
it "returns false if other is greater than last element but matched by element.succ" do
- @range.send(@method, RangeSpecs::TenfoldSucc.new(100)).should be_false
+ @range.send(@method, RangeSpecs::TenfoldSucc.new(100)).should == false
end
end
end
@@ -95,99 +95,99 @@ end
describe :range_cover_subrange, shared: true do
context "range argument" do
it "accepts range argument" do
- (0..10).send(@method, (3..7)).should be_true
- (0..10).send(@method, (3..15)).should be_false
- (0..10).send(@method, (-2..7)).should be_false
+ (0..10).send(@method, (3..7)).should == true
+ (0..10).send(@method, (3..15)).should == false
+ (0..10).send(@method, (-2..7)).should == false
- (1.1..7.9).send(@method, (2.5..6.5)).should be_true
- (1.1..7.9).send(@method, (2.5..8.5)).should be_false
- (1.1..7.9).send(@method, (0.5..6.5)).should be_false
+ (1.1..7.9).send(@method, (2.5..6.5)).should == true
+ (1.1..7.9).send(@method, (2.5..8.5)).should == false
+ (1.1..7.9).send(@method, (0.5..6.5)).should == false
- ('c'..'i').send(@method, ('d'..'f')).should be_true
- ('c'..'i').send(@method, ('d'..'z')).should be_false
- ('c'..'i').send(@method, ('a'..'f')).should be_false
+ ('c'..'i').send(@method, ('d'..'f')).should == true
+ ('c'..'i').send(@method, ('d'..'z')).should == false
+ ('c'..'i').send(@method, ('a'..'f')).should == false
range_10_100 = RangeSpecs::TenfoldSucc.new(10)..RangeSpecs::TenfoldSucc.new(100)
range_20_90 = RangeSpecs::TenfoldSucc.new(20)..RangeSpecs::TenfoldSucc.new(90)
range_20_110 = RangeSpecs::TenfoldSucc.new(20)..RangeSpecs::TenfoldSucc.new(110)
range_0_90 = RangeSpecs::TenfoldSucc.new(0)..RangeSpecs::TenfoldSucc.new(90)
- range_10_100.send(@method, range_20_90).should be_true
- range_10_100.send(@method, range_20_110).should be_false
- range_10_100.send(@method, range_0_90).should be_false
+ range_10_100.send(@method, range_20_90).should == true
+ range_10_100.send(@method, range_20_110).should == false
+ range_10_100.send(@method, range_0_90).should == false
end
it "supports boundaries of different comparable types" do
- (0..10).send(@method, (3.1..7.9)).should be_true
- (0..10).send(@method, (3.1..15.9)).should be_false
- (0..10).send(@method, (-2.1..7.9)).should be_false
+ (0..10).send(@method, (3.1..7.9)).should == true
+ (0..10).send(@method, (3.1..15.9)).should == false
+ (0..10).send(@method, (-2.1..7.9)).should == false
end
it "returns false if types are not comparable" do
- (0..10).send(@method, ('a'..'z')).should be_false
- (0..10).send(@method, (RangeSpecs::TenfoldSucc.new(0)..RangeSpecs::TenfoldSucc.new(100))).should be_false
+ (0..10).send(@method, ('a'..'z')).should == false
+ (0..10).send(@method, (RangeSpecs::TenfoldSucc.new(0)..RangeSpecs::TenfoldSucc.new(100))).should == false
end
it "honors exclusion of right boundary (:exclude_end option)" do
# Integer
- (0..10).send(@method, (0..10)).should be_true
- (0...10).send(@method, (0...10)).should be_true
+ (0..10).send(@method, (0..10)).should == true
+ (0...10).send(@method, (0...10)).should == true
- (0..10).send(@method, (0...10)).should be_true
- (0...10).send(@method, (0..10)).should be_false
+ (0..10).send(@method, (0...10)).should == true
+ (0...10).send(@method, (0..10)).should == false
- (0...11).send(@method, (0..10)).should be_true
- (0..10).send(@method, (0...11)).should be_true
+ (0...11).send(@method, (0..10)).should == true
+ (0..10).send(@method, (0...11)).should == true
# Float
- (0..10.1).send(@method, (0..10.1)).should be_true
- (0...10.1).send(@method, (0...10.1)).should be_true
+ (0..10.1).send(@method, (0..10.1)).should == true
+ (0...10.1).send(@method, (0...10.1)).should == true
- (0..10.1).send(@method, (0...10.1)).should be_true
- (0...10.1).send(@method, (0..10.1)).should be_false
+ (0..10.1).send(@method, (0...10.1)).should == true
+ (0...10.1).send(@method, (0..10.1)).should == false
- (0...11.1).send(@method, (0..10.1)).should be_true
- (0..10.1).send(@method, (0...11.1)).should be_false
+ (0...11.1).send(@method, (0..10.1)).should == true
+ (0..10.1).send(@method, (0...11.1)).should == false
end
end
it "allows self to be a beginless range" do
- (...10).send(@method, (3..7)).should be_true
- (...10).send(@method, (3..15)).should be_false
+ (...10).send(@method, (3..7)).should == true
+ (...10).send(@method, (3..15)).should == false
- (..7.9).send(@method, (2.5..6.5)).should be_true
- (..7.9).send(@method, (2.5..8.5)).should be_false
+ (..7.9).send(@method, (2.5..6.5)).should == true
+ (..7.9).send(@method, (2.5..8.5)).should == false
- (..'i').send(@method, ('d'..'f')).should be_true
- (..'i').send(@method, ('d'..'z')).should be_false
+ (..'i').send(@method, ('d'..'f')).should == true
+ (..'i').send(@method, ('d'..'z')).should == false
end
it "allows self to be a endless range" do
- eval("(0...)").send(@method, (3..7)).should be_true
- eval("(5...)").send(@method, (3..15)).should be_false
+ eval("(0...)").send(@method, (3..7)).should == true
+ eval("(5...)").send(@method, (3..15)).should == false
- eval("(1.1..)").send(@method, (2.5..6.5)).should be_true
- eval("(3.3..)").send(@method, (2.5..8.5)).should be_false
+ eval("(1.1..)").send(@method, (2.5..6.5)).should == true
+ eval("(3.3..)").send(@method, (2.5..8.5)).should == false
- eval("('a'..)").send(@method, ('d'..'f')).should be_true
- eval("('p'..)").send(@method, ('d'..'z')).should be_false
+ eval("('a'..)").send(@method, ('d'..'f')).should == true
+ eval("('p'..)").send(@method, ('d'..'z')).should == false
end
it "accepts beginless range argument" do
- (..10).send(@method, (...10)).should be_true
- (0..10).send(@method, (...10)).should be_false
+ (..10).send(@method, (...10)).should == true
+ (0..10).send(@method, (...10)).should == false
- (1.1..7.9).send(@method, (...10.5)).should be_false
+ (1.1..7.9).send(@method, (...10.5)).should == false
- ('c'..'i').send(@method, (..'i')).should be_false
+ ('c'..'i').send(@method, (..'i')).should == false
end
it "accepts endless range argument" do
- eval("(0..)").send(@method, eval("(0...)")).should be_true
- (0..10).send(@method, eval("(0...)")).should be_false
+ eval("(0..)").send(@method, eval("(0...)")).should == true
+ (0..10).send(@method, eval("(0...)")).should == false
- (1.1..7.9).send(@method, eval("(0.8...)")).should be_false
+ (1.1..7.9).send(@method, eval("(0.8...)")).should == false
- ('c'..'i').send(@method, eval("('a'..)")).should be_false
+ ('c'..'i').send(@method, eval("('a'..)")).should == false
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 13fc5e1790..97721a7307 100644
--- a/spec/ruby/core/range/shared/cover_and_include.rb
+++ b/spec/ruby/core/range/shared/cover_and_include.rb
@@ -46,41 +46,41 @@ describe :range_cover_and_include, shared: true do
m.should_receive(:coerce).and_return([1, 2])
m.should_receive(:<=>).and_return(1)
- rng.send(@method, m).should be_false
+ rng.send(@method, m).should == false
end
it "raises an ArgumentError without exactly one argument" do
- ->{ (1..2).send(@method) }.should raise_error(ArgumentError)
- ->{ (1..2).send(@method, 1, 2) }.should raise_error(ArgumentError)
+ ->{ (1..2).send(@method) }.should.raise(ArgumentError)
+ ->{ (1..2).send(@method, 1, 2) }.should.raise(ArgumentError)
end
it "returns true if argument is equal to the first value of the range" do
- (0..5).send(@method, 0).should be_true
- ('f'..'s').send(@method, 'f').should be_true
+ (0..5).send(@method, 0).should == true
+ ('f'..'s').send(@method, 'f').should == true
end
it "returns true if argument is equal to the last value of the range" do
- (0..5).send(@method, 5).should be_true
- (0...5).send(@method, 4).should be_true
- ('f'..'s').send(@method, 's').should be_true
+ (0..5).send(@method, 5).should == true
+ (0...5).send(@method, 4).should == true
+ ('f'..'s').send(@method, 's').should == true
end
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
+ (20..30).send(@method, 28).should == true
+ ('e'..'h').send(@method, 'g').should == true
end
it "returns true if argument is sole element in the range" do
- (30..30).send(@method, 30).should be_true
+ (30..30).send(@method, 30).should == true
end
it "returns false if range is empty" do
- (30...30).send(@method, 30).should be_false
- (30...30).send(@method, nil).should be_false
+ (30...30).send(@method, 30).should == false
+ (30...30).send(@method, nil).should == false
end
it "returns false if the range does not contain the argument" do
- ('A'..'C').send(@method, 20.9).should be_false
- ('A'...'C').send(@method, 'C').should be_false
+ ('A'..'C').send(@method, 20.9).should == false
+ ('A'...'C').send(@method, 'C').should == false
end
end
diff --git a/spec/ruby/core/range/shared/include.rb b/spec/ruby/core/range/shared/include.rb
deleted file mode 100644
index 15a0e5fb9f..0000000000
--- a/spec/ruby/core/range/shared/include.rb
+++ /dev/null
@@ -1,91 +0,0 @@
-# encoding: binary
-require_relative '../../../spec_helper'
-require_relative '../fixtures/classes'
-
-describe :range_include, shared: true do
- describe "on string elements" do
- it "returns true if other is matched by element.succ" do
- ('a'..'c').send(@method, 'b').should be_true
- ('a'...'c').send(@method, 'b').should be_true
- end
-
- it "returns false if other is not matched by element.succ" do
- ('a'..'c').send(@method, 'bc').should be_false
- ('a'...'c').send(@method, 'bc').should be_false
- end
- end
-
- describe "with weird succ" do
- describe "when included end value" do
- before :each do
- @range = RangeSpecs::TenfoldSucc.new(1)..RangeSpecs::TenfoldSucc.new(99)
- end
-
- it "returns false if other is less than first element" do
- @range.send(@method, RangeSpecs::TenfoldSucc.new(0)).should be_false
- end
-
- it "returns true if other is equal as first element" do
- @range.send(@method, RangeSpecs::TenfoldSucc.new(1)).should be_true
- end
-
- it "returns true if other is matched by element.succ" do
- @range.send(@method, RangeSpecs::TenfoldSucc.new(10)).should be_true
- end
-
- it "returns false if other is not matched by element.succ" do
- @range.send(@method, RangeSpecs::TenfoldSucc.new(2)).should be_false
- end
-
- it "returns false if other is equal as last element but not matched by element.succ" do
- @range.send(@method, RangeSpecs::TenfoldSucc.new(99)).should be_false
- end
-
- it "returns false if other is greater than last element but matched by element.succ" do
- @range.send(@method, RangeSpecs::TenfoldSucc.new(100)).should be_false
- end
- end
-
- describe "when excluded end value" do
- before :each do
- @range = RangeSpecs::TenfoldSucc.new(1)...RangeSpecs::TenfoldSucc.new(99)
- end
-
- it "returns false if other is less than first element" do
- @range.send(@method, RangeSpecs::TenfoldSucc.new(0)).should be_false
- end
-
- it "returns true if other is equal as first element" do
- @range.send(@method, RangeSpecs::TenfoldSucc.new(1)).should be_true
- end
-
- it "returns true if other is matched by element.succ" do
- @range.send(@method, RangeSpecs::TenfoldSucc.new(10)).should be_true
- end
-
- it "returns false if other is not matched by element.succ" do
- @range.send(@method, RangeSpecs::TenfoldSucc.new(2)).should be_false
- end
-
- it "returns false if other is equal as last element but not matched by element.succ" do
- @range.send(@method, RangeSpecs::TenfoldSucc.new(99)).should be_false
- end
-
- it "returns false if other is greater than last element but matched by element.succ" do
- @range.send(@method, RangeSpecs::TenfoldSucc.new(100)).should be_false
- end
- end
- end
-
- describe "with Time endpoints" do
- it "uses cover? logic" do
- now = Time.now
- range = (now..(now + 60))
-
- range.include?(now).should == true
- range.include?(now - 1).should == false
- range.include?(now + 60).should == true
- range.include?(now + 61).should == false
- end
- end
-end
diff --git a/spec/ruby/core/range/size_spec.rb b/spec/ruby/core/range/size_spec.rb
index 1a3ddd197e..3a8843b99d 100644
--- a/spec/ruby/core/range/size_spec.rb
+++ b/spec/ruby/core/range/size_spec.rb
@@ -67,26 +67,26 @@ describe "Range#size" do
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/)
+ -> { (1.0..16.0).size }.should.raise(TypeError, /can't iterate from/)
+ -> { (1.0...16.0).size }.should.raise(TypeError, /can't iterate from/)
+ -> { (1.0..15.9).size }.should.raise(TypeError, /can't iterate from/)
+ -> { (1.1..16.0).size }.should.raise(TypeError, /can't iterate from/)
+ -> { (1.1..15.9).size }.should.raise(TypeError, /can't iterate from/)
+ -> { (16.0..0.0).size }.should.raise(TypeError, /can't iterate from/)
+ -> { (Float::INFINITY..0).size }.should.raise(TypeError, /can't iterate from/)
+ -> { (-Float::INFINITY..0).size }.should.raise(TypeError, /can't iterate from/)
+ -> { (-Float::INFINITY..Float::INFINITY).size }.should.raise(TypeError, /can't iterate from/)
+ -> { (..1).size }.should.raise(TypeError, /can't iterate from/)
+ -> { (...0.5).size }.should.raise(TypeError, /can't iterate from/)
+ -> { (..nil).size }.should.raise(TypeError, /can't iterate from/)
+ -> { (...'o').size }.should.raise(TypeError, /can't iterate from/)
+ -> { eval("(0.5...)").size }.should.raise(TypeError, /can't iterate from/)
+ -> { eval("([]...)").size }.should.raise(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
+ (:a..:z).size.should == nil
+ ('a'..'z').size.should == nil
end
end
diff --git a/spec/ruby/core/range/step_spec.rb b/spec/ruby/core/range/step_spec.rb
index 0d0caf746d..faab95d88d 100644
--- a/spec/ruby/core/range/step_spec.rb
+++ b/spec/ruby/core/range/step_spec.rb
@@ -7,7 +7,7 @@ describe "Range#step" do
it "returns self" do
r = 1..2
- r.step { }.should equal(r)
+ r.step { }.should.equal?(r)
end
ruby_version_is ""..."3.4" do
@@ -16,27 +16,27 @@ describe "Range#step" do
obj.should_receive(:to_int).and_return(1)
(1..2).step(obj) { |x| ScratchPad << x }
- ScratchPad.recorded.should eql([1, 2])
+ ScratchPad.recorded.should.eql?([1, 2])
end
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)
+ -> { (1..2).step(obj) { } }.should.raise(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")
- -> { (1..2).step(obj) { } }.should raise_error(TypeError)
+ -> { (1..2).step(obj) { } }.should.raise(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)
- -> { (obj..obj).step { |x| x } }.should raise_error(TypeError)
+ -> { (obj..obj).step { |x| x } }.should.raise(TypeError)
end
end
@@ -46,34 +46,40 @@ describe "Range#step" do
obj.should_receive(:coerce).at_least(:once).and_return([1, 2])
(1..3).step(obj) { |x| ScratchPad << x }
- ScratchPad.recorded.should eql([1, 3])
+ ScratchPad.recorded.should.eql?([1, 3])
end
it "raises a TypeError if step does not respond to #coerce" do
obj = mock("Range#step non-coercible")
- -> { (1..2).step(obj) { } }.should raise_error(TypeError)
+ -> { (1..2).step(obj) { } }.should.raise(TypeError)
end
end
it "raises an ArgumentError if step is 0" do
- -> { (-1..1).step(0) { |x| x } }.should raise_error(ArgumentError)
+ -> { (-1..1).step(0) { |x| x } }.should.raise(ArgumentError)
end
it "raises an ArgumentError if step is 0.0" do
- -> { (-1..1).step(0.0) { |x| x } }.should raise_error(ArgumentError)
+ -> { (-1..1).step(0.0) { |x| x } }.should.raise(ArgumentError)
end
ruby_version_is "3.4" do
- it "does not raise an ArgumentError if step is 0 for non-numeric ranges" do
+ it "does not iterate if step is 0 for bounded non-numeric ranges" do
t = Time.utc(2023, 2, 24)
- -> { (t..t+1).step(0) { break } }.should_not raise_error(ArgumentError)
+ (t..t + 1).step(0) { |x| ScratchPad << x }
+ ScratchPad.recorded.should == []
+ end
+
+ it "raises an ArgumentError when iterating a beginless range" do
+ -> { (..10).step(1) { break } }.should.raise(ArgumentError,
+ "#step iteration for beginless ranges is meaningless")
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)
+ -> { (-1..1).step(-2) { |x| x } }.should.raise(ArgumentError)
end
end
@@ -81,28 +87,28 @@ describe "Range#step" do
describe "and Integer values" do
it "yields Integer values incremented by 1 and less than or equal to end when not passed a step" do
(-2..2).step { |x| ScratchPad << x }
- ScratchPad.recorded.should eql([-2, -1, 0, 1, 2])
+ ScratchPad.recorded.should.eql?([-2, -1, 0, 1, 2])
end
it "yields Integer values incremented by an Integer step" do
(-5..5).step(2) { |x| ScratchPad << x }
- ScratchPad.recorded.should eql([-5, -3, -1, 1, 3, 5])
+ ScratchPad.recorded.should.eql?([-5, -3, -1, 1, 3, 5])
end
it "yields Float values incremented by a Float step" do
(-2..2).step(1.5) { |x| ScratchPad << x }
- ScratchPad.recorded.should eql([-2.0, -0.5, 1.0])
+ 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([])
+ 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])
+ ScratchPad.recorded.should.eql?([1, 0, -1])
end
end
end
@@ -110,67 +116,79 @@ describe "Range#step" do
describe "and Float values" do
it "yields Float values incremented by 1 and less than or equal to end when not passed a step" do
(-2.0..2.0).step { |x| ScratchPad << x }
- ScratchPad.recorded.should eql([-2.0, -1.0, 0.0, 1.0, 2.0])
+ ScratchPad.recorded.should.eql?([-2.0, -1.0, 0.0, 1.0, 2.0])
end
it "yields Float values incremented by an Integer step" do
(-5.0..5.0).step(2) { |x| ScratchPad << x }
- ScratchPad.recorded.should eql([-5.0, -3.0, -1.0, 1.0, 3.0, 5.0])
+ ScratchPad.recorded.should.eql?([-5.0, -3.0, -1.0, 1.0, 3.0, 5.0])
end
it "yields Float values incremented by a Float step" do
(-1.0..1.0).step(0.5) { |x| ScratchPad << x }
- ScratchPad.recorded.should eql([-1.0, -0.5, 0.0, 0.5, 1.0])
+ ScratchPad.recorded.should.eql?([-1.0, -0.5, 0.0, 0.5, 1.0])
end
it "returns Float values of 'step * n + begin <= end'" do
(1.0..6.4).step(1.8) { |x| ScratchPad << x }
(1.0..12.7).step(1.3) { |x| ScratchPad << x }
- ScratchPad.recorded.should eql([1.0, 2.8, 4.6, 6.4, 1.0, 2.3, 3.6,
+ ScratchPad.recorded.should.eql?([1.0, 2.8, 4.6, 6.4, 1.0, 2.3, 3.6,
4.9, 6.2, 7.5, 8.8, 10.1, 11.4, 12.7])
end
it "handles infinite values at either end" do
(-Float::INFINITY..0.0).step(2) { |x| ScratchPad << x; break if ScratchPad.recorded.size == 3 }
- ScratchPad.recorded.should eql([-Float::INFINITY, -Float::INFINITY, -Float::INFINITY])
+ ScratchPad.recorded.should.eql?([-Float::INFINITY, -Float::INFINITY, -Float::INFINITY])
ScratchPad.record []
(0.0..Float::INFINITY).step(2) { |x| ScratchPad << x; break if ScratchPad.recorded.size == 3 }
- ScratchPad.recorded.should eql([0.0, 2.0, 4.0])
+ ScratchPad.recorded.should.eql?([0.0, 2.0, 4.0])
+ end
+
+ ruby_version_is "3.4" do
+ it "does not iterate if step is negative for forward range" do
+ (-1.0..1.0).step(-0.5) { |x| ScratchPad << x }
+ ScratchPad.recorded.should.eql?([])
+ end
+
+ it "iterates backward if step is negative for backward range" do
+ (1.0..-1.0).step(-0.5) { |x| ScratchPad << x }
+ ScratchPad.recorded.should.eql?([1.0, 0.5, 0.0, -0.5, -1.0])
+ end
end
end
describe "and Integer, Float values" do
it "yields Float values incremented by 1 and less than or equal to end when not passed a step" do
(-2..2.0).step { |x| ScratchPad << x }
- ScratchPad.recorded.should eql([-2.0, -1.0, 0.0, 1.0, 2.0])
+ ScratchPad.recorded.should.eql?([-2.0, -1.0, 0.0, 1.0, 2.0])
end
it "yields Float values incremented by an Integer step" do
(-5..5.0).step(2) { |x| ScratchPad << x }
- ScratchPad.recorded.should eql([-5.0, -3.0, -1.0, 1.0, 3.0, 5.0])
+ ScratchPad.recorded.should.eql?([-5.0, -3.0, -1.0, 1.0, 3.0, 5.0])
end
it "yields Float values incremented by a Float step" do
(-1..1.0).step(0.5) { |x| ScratchPad << x }
- ScratchPad.recorded.should eql([-1.0, -0.5, 0.0, 0.5, 1.0])
+ ScratchPad.recorded.should.eql?([-1.0, -0.5, 0.0, 0.5, 1.0])
end
end
describe "and Float, Integer values" do
it "yields Float values incremented by 1 and less than or equal to end when not passed a step" do
(-2.0..2).step { |x| ScratchPad << x }
- ScratchPad.recorded.should eql([-2.0, -1.0, 0.0, 1.0, 2.0])
+ ScratchPad.recorded.should.eql?([-2.0, -1.0, 0.0, 1.0, 2.0])
end
it "yields Float values incremented by an Integer step" do
(-5.0..5).step(2) { |x| ScratchPad << x }
- ScratchPad.recorded.should eql([-5.0, -3.0, -1.0, 1.0, 3.0, 5.0])
+ ScratchPad.recorded.should.eql?([-5.0, -3.0, -1.0, 1.0, 3.0, 5.0])
end
it "yields Float values incremented by a Float step" do
(-1.0..1).step(0.5) { |x| ScratchPad << x }
- ScratchPad.recorded.should eql([-1.0, -0.5, 0.0, 0.5, 1.0])
+ ScratchPad.recorded.should.eql?([-1.0, -0.5, 0.0, 0.5, 1.0])
end
end
@@ -186,7 +204,7 @@ describe "Range#step" do
end
it "raises a TypeError when passed a Float step" do
- -> { ("A".."G").step(2.0) { } }.should raise_error(TypeError)
+ -> { ("A".."G").step(2.0) { } }.should.raise(TypeError)
end
ruby_version_is ""..."3.4" do
@@ -207,7 +225,7 @@ describe "Range#step" do
end
it "raises a TypeError when passed an incompatible type step" do
- -> { ("A".."G").step([]) { } }.should raise_error(TypeError)
+ -> { ("A".."G").step([]) { } }.should.raise(TypeError)
end
it "calls #+ on begin and each element returned by #+" do
@@ -287,89 +305,96 @@ describe "Range#step" do
describe "and Integer values" do
it "yields Integer values incremented by 1 and less than end when not passed a step" do
(-2...2).step { |x| ScratchPad << x }
- ScratchPad.recorded.should eql([-2, -1, 0, 1])
+ ScratchPad.recorded.should.eql?([-2, -1, 0, 1])
end
it "yields Integer values incremented by an Integer step" do
(-5...5).step(2) { |x| ScratchPad << x }
- ScratchPad.recorded.should eql([-5, -3, -1, 1, 3])
+ ScratchPad.recorded.should.eql?([-5, -3, -1, 1, 3])
end
it "yields Float values incremented by a Float step" do
(-2...2).step(1.5) { |x| ScratchPad << x }
- ScratchPad.recorded.should eql([-2.0, -0.5, 1.0])
+ ScratchPad.recorded.should.eql?([-2.0, -0.5, 1.0])
end
end
describe "and Float values" do
it "yields Float values incremented by 1 and less than end when not passed a step" do
(-2.0...2.0).step { |x| ScratchPad << x }
- ScratchPad.recorded.should eql([-2.0, -1.0, 0.0, 1.0])
+ ScratchPad.recorded.should.eql?([-2.0, -1.0, 0.0, 1.0])
end
it "yields Float values incremented by an Integer step" do
(-5.0...5.0).step(2) { |x| ScratchPad << x }
- ScratchPad.recorded.should eql([-5.0, -3.0, -1.0, 1.0, 3.0])
+ ScratchPad.recorded.should.eql?([-5.0, -3.0, -1.0, 1.0, 3.0])
end
it "yields Float values incremented by a Float step" do
(-1.0...1.0).step(0.5) { |x| ScratchPad << x }
- ScratchPad.recorded.should eql([-1.0, -0.5, 0.0, 0.5])
+ ScratchPad.recorded.should.eql?([-1.0, -0.5, 0.0, 0.5])
end
it "returns Float values of 'step * n + begin < end'" do
(1.0...6.4).step(1.8) { |x| ScratchPad << x }
- ScratchPad.recorded.should eql([1.0, 2.8, 4.6])
+ ScratchPad.recorded.should.eql?([1.0, 2.8, 4.6])
end
it "correctly handles values near the upper limit" do # https://bugs.ruby-lang.org/issues/16612
(1.0...55.6).step(18.2) { |x| ScratchPad << x }
- ScratchPad.recorded.should eql([1.0, 19.2, 37.4, 55.599999999999994])
+ ScratchPad.recorded.should.eql?([1.0, 19.2, 37.4, 55.599999999999994])
(1.0...55.6).step(18.2).size.should == 4
end
it "handles infinite values at either end" do
(-Float::INFINITY...0.0).step(2) { |x| ScratchPad << x; break if ScratchPad.recorded.size == 3 }
- ScratchPad.recorded.should eql([-Float::INFINITY, -Float::INFINITY, -Float::INFINITY])
+ ScratchPad.recorded.should.eql?([-Float::INFINITY, -Float::INFINITY, -Float::INFINITY])
ScratchPad.record []
(0.0...Float::INFINITY).step(2) { |x| ScratchPad << x; break if ScratchPad.recorded.size == 3 }
- ScratchPad.recorded.should eql([0.0, 2.0, 4.0])
+ ScratchPad.recorded.should.eql?([0.0, 2.0, 4.0])
+ end
+
+ ruby_version_is "3.4" do
+ it "iterates backward with exclusive end if step is negative" do
+ (1.0...-1.0).step(-0.5) { |x| ScratchPad << x }
+ ScratchPad.recorded.should.eql?([1.0, 0.5, 0.0, -0.5])
+ end
end
end
describe "and Integer, Float values" do
it "yields Float values incremented by 1 and less than end when not passed a step" do
(-2...2.0).step { |x| ScratchPad << x }
- ScratchPad.recorded.should eql([-2.0, -1.0, 0.0, 1.0])
+ ScratchPad.recorded.should.eql?([-2.0, -1.0, 0.0, 1.0])
end
it "yields Float values incremented by an Integer step" do
(-5...5.0).step(2) { |x| ScratchPad << x }
- ScratchPad.recorded.should eql([-5.0, -3.0, -1.0, 1.0, 3.0])
+ ScratchPad.recorded.should.eql?([-5.0, -3.0, -1.0, 1.0, 3.0])
end
it "yields an Float and then Float values incremented by a Float step" do
(-1...1.0).step(0.5) { |x| ScratchPad << x }
- ScratchPad.recorded.should eql([-1.0, -0.5, 0.0, 0.5])
+ ScratchPad.recorded.should.eql?([-1.0, -0.5, 0.0, 0.5])
end
end
describe "and Float, Integer values" do
it "yields Float values incremented by 1 and less than end when not passed a step" do
(-2.0...2).step { |x| ScratchPad << x }
- ScratchPad.recorded.should eql([-2.0, -1.0, 0.0, 1.0])
+ ScratchPad.recorded.should.eql?([-2.0, -1.0, 0.0, 1.0])
end
it "yields Float values incremented by an Integer step" do
(-5.0...5).step(2) { |x| ScratchPad << x }
- ScratchPad.recorded.should eql([-5.0, -3.0, -1.0, 1.0, 3.0])
+ ScratchPad.recorded.should.eql?([-5.0, -3.0, -1.0, 1.0, 3.0])
end
it "yields Float values incremented by a Float step" do
(-1.0...1).step(0.5) { |x| ScratchPad << x }
- ScratchPad.recorded.should eql([-1.0, -0.5, 0.0, 0.5])
+ ScratchPad.recorded.should.eql?([-1.0, -0.5, 0.0, 0.5])
end
end
@@ -386,7 +411,7 @@ describe "Range#step" do
end
it "raises a TypeError when passed a Float step" do
- -> { ("A"..."G").step(2.0) { } }.should raise_error(TypeError)
+ -> { ("A"..."G").step(2.0) { } }.should.raise(TypeError)
end
end
@@ -397,7 +422,7 @@ describe "Range#step" do
end
it "raises a TypeError when passed an incompatible type step" do
- -> { ("A".."G").step([]) { } }.should raise_error(TypeError)
+ -> { ("A".."G").step([]) { } }.should.raise(TypeError)
end
end
end
@@ -407,67 +432,74 @@ describe "Range#step" do
describe "and Integer values" do
it "yield Integer values incremented by 1 when not passed a step" do
(-2..).step { |x| break if x > 2; ScratchPad << x }
- ScratchPad.recorded.should eql([-2, -1, 0, 1, 2])
+ ScratchPad.recorded.should.eql?([-2, -1, 0, 1, 2])
ScratchPad.record []
(-2...).step { |x| break if x > 2; ScratchPad << x }
- ScratchPad.recorded.should eql([-2, -1, 0, 1, 2])
+ ScratchPad.recorded.should.eql?([-2, -1, 0, 1, 2])
end
it "yields Integer values incremented by an Integer step" do
(-5..).step(2) { |x| break if x > 3; ScratchPad << x }
- ScratchPad.recorded.should eql([-5, -3, -1, 1, 3])
+ ScratchPad.recorded.should.eql?([-5, -3, -1, 1, 3])
ScratchPad.record []
(-5...).step(2) { |x| break if x > 3; ScratchPad << x }
- ScratchPad.recorded.should eql([-5, -3, -1, 1, 3])
+ ScratchPad.recorded.should.eql?([-5, -3, -1, 1, 3])
end
it "yields Float values incremented by a Float step" do
(-2..).step(1.5) { |x| break if x > 1.0; ScratchPad << x }
- ScratchPad.recorded.should eql([-2.0, -0.5, 1.0])
+ ScratchPad.recorded.should.eql?([-2.0, -0.5, 1.0])
ScratchPad.record []
(-2..).step(1.5) { |x| break if x > 1.0; ScratchPad << x }
- ScratchPad.recorded.should eql([-2.0, -0.5, 1.0])
+ ScratchPad.recorded.should.eql?([-2.0, -0.5, 1.0])
end
end
describe "and Float values" do
it "yields Float values incremented by 1 and less than end when not passed a step" do
(-2.0..).step { |x| break if x > 1.5; ScratchPad << x }
- ScratchPad.recorded.should eql([-2.0, -1.0, 0.0, 1.0])
+ ScratchPad.recorded.should.eql?([-2.0, -1.0, 0.0, 1.0])
ScratchPad.record []
(-2.0...).step { |x| break if x > 1.5; ScratchPad << x }
- ScratchPad.recorded.should eql([-2.0, -1.0, 0.0, 1.0])
+ ScratchPad.recorded.should.eql?([-2.0, -1.0, 0.0, 1.0])
end
it "yields Float values incremented by an Integer step" do
(-5.0..).step(2) { |x| break if x > 3.5; ScratchPad << x }
- ScratchPad.recorded.should eql([-5.0, -3.0, -1.0, 1.0, 3.0])
+ ScratchPad.recorded.should.eql?([-5.0, -3.0, -1.0, 1.0, 3.0])
ScratchPad.record []
(-5.0...).step(2) { |x| break if x > 3.5; ScratchPad << x }
- ScratchPad.recorded.should eql([-5.0, -3.0, -1.0, 1.0, 3.0])
+ ScratchPad.recorded.should.eql?([-5.0, -3.0, -1.0, 1.0, 3.0])
end
it "yields Float values incremented by a Float step" do
(-1.0..).step(0.5) { |x| break if x > 0.6; ScratchPad << x }
- ScratchPad.recorded.should eql([-1.0, -0.5, 0.0, 0.5])
+ ScratchPad.recorded.should.eql?([-1.0, -0.5, 0.0, 0.5])
ScratchPad.record []
(-1.0...).step(0.5) { |x| break if x > 0.6; ScratchPad << x }
- ScratchPad.recorded.should eql([-1.0, -0.5, 0.0, 0.5])
+ ScratchPad.recorded.should.eql?([-1.0, -0.5, 0.0, 0.5])
+ end
+
+ it "computes each value independently to avoid accumulating floating-point errors" do
+ result = []
+ (0.0..).step(0.1) { |x| result << x; break if result.size == 20 }
+ expected = 20.times.map { |i| i * 0.1 + 0.0 }
+ result.should.eql?(expected)
end
it "handles infinite values at the start" do
(-Float::INFINITY..).step(2) { |x| ScratchPad << x; break if ScratchPad.recorded.size == 3 }
- ScratchPad.recorded.should eql([-Float::INFINITY, -Float::INFINITY, -Float::INFINITY])
+ ScratchPad.recorded.should.eql?([-Float::INFINITY, -Float::INFINITY, -Float::INFINITY])
ScratchPad.record []
(-Float::INFINITY...).step(2) { |x| ScratchPad << x; break if ScratchPad.recorded.size == 3 }
- ScratchPad.recorded.should eql([-Float::INFINITY, -Float::INFINITY, -Float::INFINITY])
+ ScratchPad.recorded.should.eql?([-Float::INFINITY, -Float::INFINITY, -Float::INFINITY])
end
end
@@ -491,8 +523,8 @@ describe "Range#step" do
end
it "raises a TypeError when passed a Float step" do
- -> { ('A'..).step(2.0) { } }.should raise_error(TypeError)
- -> { ('A'...).step(2.0) { } }.should raise_error(TypeError)
+ -> { ('A'..).step(2.0) { } }.should.raise(TypeError)
+ -> { ('A'...).step(2.0) { } }.should.raise(TypeError)
end
ruby_version_is "3.4" do
@@ -506,8 +538,8 @@ describe "Range#step" do
end
it "raises a TypeError when passed an incompatible type step" do
- -> { ('A'..).step([]) { } }.should raise_error(TypeError)
- -> { ('A'...).step([]) { } }.should raise_error(TypeError)
+ -> { ('A'..).step([]) { } }.should.raise(TypeError)
+ -> { ('A'...).step([]) { } }.should.raise(TypeError)
end
end
end
@@ -515,7 +547,7 @@ describe "Range#step" do
describe "when no block is given" do
it "raises an ArgumentError if step is 0" do
- -> { (-1..1).step(0) }.should raise_error(ArgumentError)
+ -> { (-1..1).step(0) }.should.raise(ArgumentError)
end
describe "returned Enumerator" do
@@ -523,20 +555,20 @@ describe "Range#step" do
ruby_version_is ""..."3.4" 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)
+ -> { (1..2).step(obj) }.should.raise(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")
- -> { (1..2).step(obj) }.should raise_error(TypeError)
+ -> { (1..2).step(obj) }.should.raise(TypeError)
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
+ -> { (1..2).step(obj) }.should_not.raise
end
end
@@ -589,7 +621,7 @@ describe "Range#step" 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_not.raise
enum.size.should == nil
end
end
@@ -604,7 +636,7 @@ describe "Range#step" 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_not.raise
enum.size.should == nil
end
end
@@ -657,7 +689,17 @@ describe "Range#step" do
ruby_version_is "3.4" do
it "raises an ArgumentError" do
- -> { Range.new(nil, nil).step(1) }.should raise_error(ArgumentError)
+ -> { Range.new(nil, nil).step(1) }.should.raise(ArgumentError,
+ "#step for non-numeric beginless ranges is meaningless")
+ end
+ end
+ end
+
+ context "when range is beginless and finite" do
+ ruby_version_is "3.4" do
+ it "raises an ArgumentError if step is non-numeric" do
+ -> { (..10).step("a") }.should.raise(ArgumentError,
+ "#step for non-numeric beginless ranges is meaningless")
end
end
end
diff --git a/spec/ruby/core/range/to_a_spec.rb b/spec/ruby/core/range/to_a_spec.rb
index b1d3de32db..6221ae5f71 100644
--- a/spec/ruby/core/range/to_a_spec.rb
+++ b/spec/ruby/core/range/to_a_spec.rb
@@ -6,7 +6,7 @@ describe "Range#to_a" do
('A'..'D').to_a.should == ['A','B','C','D']
('A'...'D').to_a.should == ['A','B','C']
(0xfffd...0xffff).to_a.should == [0xfffd,0xfffe]
- -> { (0.5..2.4).to_a }.should raise_error(TypeError)
+ -> { (0.5..2.4).to_a }.should.raise(TypeError)
end
it "returns empty array for descending-ordered" do
@@ -30,10 +30,10 @@ describe "Range#to_a" do
end
it "throws an exception for endless ranges" do
- -> { eval("(1..)").to_a }.should raise_error(RangeError)
+ -> { eval("(1..)").to_a }.should.raise(RangeError)
end
it "throws an exception for beginless ranges" do
- -> { (..1).to_a }.should raise_error(TypeError)
+ -> { (..1).to_a }.should.raise(TypeError)
end
end
diff --git a/spec/ruby/core/range/to_set_spec.rb b/spec/ruby/core/range/to_set_spec.rb
new file mode 100644
index 0000000000..ac81d2cc4b
--- /dev/null
+++ b/spec/ruby/core/range/to_set_spec.rb
@@ -0,0 +1,54 @@
+require_relative '../../spec_helper'
+require_relative '../enumerable/fixtures/classes'
+
+describe "Range#to_set" do
+ it "returns a new Set created from self" do
+ (1..4).to_set.should == Set[1, 2, 3, 4]
+ (1...4).to_set.should == Set[1, 2, 3]
+ end
+
+ it "passes down passed blocks" do
+ (1..3).to_set { |x| x * x }.should == Set[1, 4, 9]
+ end
+
+ it "raises a TypeError for a beginningless range" do
+ -> {
+ (..0).to_set
+ }.should.raise(TypeError, "can't iterate from NilClass")
+ end
+
+ ruby_version_is "4.0" do
+ it "raises a RangeError if the range is endless" do
+ -> { (1..).to_set }.should.raise(RangeError, "cannot convert endless range to a set")
+ -> { (1...).to_set }.should.raise(RangeError, "cannot convert endless range to a set")
+ end
+ end
+
+ context "given positional arguments" do
+ ruby_version_is ""..."4.0" do
+ it "instantiates an object of provided as the first argument set class" do
+ set = (1..3).to_set(EnumerableSpecs::SetSubclass)
+ set.should.is_a?(EnumerableSpecs::SetSubclass)
+ set.to_a.sort.should == [1, 2, 3]
+ end
+ end
+
+ ruby_version_is "4.0"..."4.1" do
+ it "instantiates an object of provided as the first argument set class and warns" do
+ -> {
+ set = (1..3).to_set(EnumerableSpecs::SetSubclass)
+ set.should.is_a?(EnumerableSpecs::SetSubclass)
+ set.to_a.sort.should == [1, 2, 3]
+ }.should complain(/warning: passing arguments to Enumerable#to_set is deprecated/)
+ end
+ end
+
+ ruby_version_is "4.1" do
+ it "does not accept any positional argument" do
+ -> {
+ (1..3).to_set(EnumerableSpecs::SetSubclass)
+ }.should.raise(ArgumentError, "wrong number of arguments (given 1, expected 0)")
+ end
+ end
+ end
+end
diff --git a/spec/ruby/core/rational/abs_spec.rb b/spec/ruby/core/rational/abs_spec.rb
index 54099aa14d..6bb4a0fbef 100644
--- a/spec/ruby/core/rational/abs_spec.rb
+++ b/spec/ruby/core/rational/abs_spec.rb
@@ -1,6 +1,11 @@
require_relative "../../spec_helper"
-require_relative 'shared/abs'
describe "Rational#abs" do
- it_behaves_like :rational_abs, :abs
+ it "returns self's absolute value" do
+ Rational(3, 4).abs.should == Rational(3, 4)
+ Rational(-3, 4).abs.should == Rational(3, 4)
+ Rational(3, -4).abs.should == Rational(3, 4)
+
+ Rational(bignum_value, -bignum_value).abs.should == Rational(bignum_value, bignum_value)
+ end
end
diff --git a/spec/ruby/core/rational/ceil_spec.rb b/spec/ruby/core/rational/ceil_spec.rb
index d5bdadf3b6..0464eab101 100644
--- a/spec/ruby/core/rational/ceil_spec.rb
+++ b/spec/ruby/core/rational/ceil_spec.rb
@@ -1,45 +1,48 @@
require_relative "../../spec_helper"
+require_relative "../integer/shared/integer_ceil_precision"
describe "Rational#ceil" do
+ context "with values equal to integers" do
+ it_behaves_like :integer_ceil_precision, :Rational
+ end
+
before do
@rational = Rational(2200, 7)
end
describe "with no arguments (precision = 0)" do
- it "returns an Integer" do
- @rational.ceil.should be_kind_of(Integer)
- end
+ it "returns the Integer value rounded toward positive infinity" do
+ @rational.ceil.should.eql? 315
- it "returns the truncated value toward positive infinity" do
- @rational.ceil.should == 315
- Rational(1, 2).ceil.should == 1
- Rational(-1, 2).ceil.should == 0
+ Rational(1, 2).ceil.should.eql? 1
+ Rational(-1, 2).ceil.should.eql? 0
+ Rational(1, 1).ceil.should.eql? 1
end
end
describe "with a precision < 0" do
- it "returns an Integer" do
- @rational.ceil(-2).should be_kind_of(Integer)
- @rational.ceil(-1).should be_kind_of(Integer)
- end
+ it "moves the rounding point n decimal places left, returning an Integer" do
+ @rational.ceil(-3).should.eql? 1000
+ @rational.ceil(-2).should.eql? 400
+ @rational.ceil(-1).should.eql? 320
- it "moves the truncation point n decimal places left" do
- @rational.ceil(-3).should == 1000
- @rational.ceil(-2).should == 400
- @rational.ceil(-1).should == 320
+ Rational(100, 2).ceil(-1).should.eql? 50
+ Rational(100, 2).ceil(-2).should.eql? 100
+ Rational(-100, 2).ceil(-1).should.eql?(-50)
+ Rational(-100, 2).ceil(-2).should.eql?(0)
end
end
describe "with precision > 0" do
- it "returns a Rational" do
- @rational.ceil(1).should be_kind_of(Rational)
- @rational.ceil(2).should be_kind_of(Rational)
- end
+ it "moves the rounding point n decimal places right, returning a Rational" do
+ @rational.ceil(1).should.eql? Rational(3143, 10)
+ @rational.ceil(2).should.eql? Rational(31429, 100)
+ @rational.ceil(3).should.eql? Rational(157143, 500)
- it "moves the truncation point n decimal places right" do
- @rational.ceil(1).should == Rational(3143, 10)
- @rational.ceil(2).should == Rational(31429, 100)
- @rational.ceil(3).should == Rational(157143, 500)
+ Rational(100, 2).ceil(1).should.eql? Rational(50, 1)
+ Rational(100, 2).ceil(2).should.eql? Rational(50, 1)
+ Rational(-100, 2).ceil(1).should.eql? Rational(-50, 1)
+ Rational(-100, 2).ceil(2).should.eql? Rational(-50, 1)
end
end
end
diff --git a/spec/ruby/core/rational/comparison_spec.rb b/spec/ruby/core/rational/comparison_spec.rb
index c9db60d5c7..482e904989 100644
--- a/spec/ruby/core/rational/comparison_spec.rb
+++ b/spec/ruby/core/rational/comparison_spec.rb
@@ -3,54 +3,54 @@ require_relative 'fixtures/rational'
describe "Rational#<=> when passed a Rational object" do
it "returns 1 when self is greater than the passed argument" do
- (Rational(4, 4) <=> Rational(3, 4)).should equal(1)
- (Rational(-3, 4) <=> Rational(-4, 4)).should equal(1)
+ (Rational(4, 4) <=> Rational(3, 4)).should.equal?(1)
+ (Rational(-3, 4) <=> Rational(-4, 4)).should.equal?(1)
end
it "returns 0 when self is equal to the passed argument" do
- (Rational(4, 4) <=> Rational(4, 4)).should equal(0)
- (Rational(-3, 4) <=> Rational(-3, 4)).should equal(0)
+ (Rational(4, 4) <=> Rational(4, 4)).should.equal?(0)
+ (Rational(-3, 4) <=> Rational(-3, 4)).should.equal?(0)
end
it "returns -1 when self is less than the passed argument" do
- (Rational(3, 4) <=> Rational(4, 4)).should equal(-1)
- (Rational(-4, 4) <=> Rational(-3, 4)).should equal(-1)
+ (Rational(3, 4) <=> Rational(4, 4)).should.equal?(-1)
+ (Rational(-4, 4) <=> Rational(-3, 4)).should.equal?(-1)
end
end
describe "Rational#<=> when passed an Integer object" do
it "returns 1 when self is greater than the passed argument" do
- (Rational(4, 4) <=> 0).should equal(1)
- (Rational(4, 4) <=> -10).should equal(1)
- (Rational(-3, 4) <=> -1).should equal(1)
+ (Rational(4, 4) <=> 0).should.equal?(1)
+ (Rational(4, 4) <=> -10).should.equal?(1)
+ (Rational(-3, 4) <=> -1).should.equal?(1)
end
it "returns 0 when self is equal to the passed argument" do
- (Rational(4, 4) <=> 1).should equal(0)
- (Rational(-8, 4) <=> -2).should equal(0)
+ (Rational(4, 4) <=> 1).should.equal?(0)
+ (Rational(-8, 4) <=> -2).should.equal?(0)
end
it "returns -1 when self is less than the passed argument" do
- (Rational(3, 4) <=> 1).should equal(-1)
- (Rational(-4, 4) <=> 0).should equal(-1)
+ (Rational(3, 4) <=> 1).should.equal?(-1)
+ (Rational(-4, 4) <=> 0).should.equal?(-1)
end
end
describe "Rational#<=> when passed a Float object" do
it "returns 1 when self is greater than the passed argument" do
- (Rational(4, 4) <=> 0.5).should equal(1)
- (Rational(4, 4) <=> -1.5).should equal(1)
- (Rational(-3, 4) <=> -0.8).should equal(1)
+ (Rational(4, 4) <=> 0.5).should.equal?(1)
+ (Rational(4, 4) <=> -1.5).should.equal?(1)
+ (Rational(-3, 4) <=> -0.8).should.equal?(1)
end
it "returns 0 when self is equal to the passed argument" do
- (Rational(4, 4) <=> 1.0).should equal(0)
- (Rational(-6, 4) <=> -1.5).should equal(0)
+ (Rational(4, 4) <=> 1.0).should.equal?(0)
+ (Rational(-6, 4) <=> -1.5).should.equal?(0)
end
it "returns -1 when self is less than the passed argument" do
- (Rational(3, 4) <=> 1.2).should equal(-1)
- (Rational(-4, 4) <=> 0.5).should equal(-1)
+ (Rational(3, 4) <=> 1.2).should.equal?(-1)
+ (Rational(-4, 4) <=> 0.5).should.equal?(-1)
end
end
@@ -82,12 +82,12 @@ describe "Rational#<=> when passed an Object that responds to #coerce" do
b = mock("numeric with failed #coerce")
b.should_receive(:coerce).and_raise(RationalSpecs::CoerceError)
- -> { Rational(3, 4) <=> b }.should raise_error(RationalSpecs::CoerceError)
+ -> { Rational(3, 4) <=> b }.should.raise(RationalSpecs::CoerceError)
end
end
describe "Rational#<=> when passed a non-Numeric Object that doesn't respond to #coerce" do
it "returns nil" do
- (Rational <=> mock("Object")).should be_nil
+ (Rational <=> mock("Object")).should == nil
end
end
diff --git a/spec/ruby/core/rational/denominator_spec.rb b/spec/ruby/core/rational/denominator_spec.rb
index 4687244893..ba6e936d60 100644
--- a/spec/ruby/core/rational/denominator_spec.rb
+++ b/spec/ruby/core/rational/denominator_spec.rb
@@ -2,8 +2,8 @@ require_relative "../../spec_helper"
describe "Rational#denominator" do
it "returns the denominator" do
- Rational(3, 4).denominator.should equal(4)
- Rational(3, -4).denominator.should equal(4)
+ Rational(3, 4).denominator.should.equal?(4)
+ Rational(3, -4).denominator.should.equal?(4)
Rational(1, bignum_value).denominator.should == bignum_value
end
diff --git a/spec/ruby/core/rational/div_spec.rb b/spec/ruby/core/rational/div_spec.rb
index d3adb9b536..a679663543 100644
--- a/spec/ruby/core/rational/div_spec.rb
+++ b/spec/ruby/core/rational/div_spec.rb
@@ -2,16 +2,16 @@ require_relative "../../spec_helper"
describe "Rational#div" do
it "returns an Integer" do
- Rational(229, 21).div(82).should be_kind_of(Integer)
+ Rational(229, 21).div(82).should.is_a?(Integer)
end
it "raises an ArgumentError if passed more than one argument" do
- -> { Rational(3, 4).div(2,3) }.should raise_error(ArgumentError)
+ -> { Rational(3, 4).div(2,3) }.should.raise(ArgumentError)
end
# See http://redmine.ruby-lang.org/issues/show/1648
it "raises a TypeError if passed a non-numeric argument" do
- -> { Rational(3, 4).div([]) }.should raise_error(TypeError)
+ -> { Rational(3, 4).div([]) }.should.raise(TypeError)
end
end
@@ -22,11 +22,11 @@ describe "Rational#div passed a Rational" do
end
it "raises a ZeroDivisionError when the argument has a numerator of 0" do
- -> { Rational(3, 4).div(Rational(0, 3)) }.should raise_error(ZeroDivisionError)
+ -> { Rational(3, 4).div(Rational(0, 3)) }.should.raise(ZeroDivisionError)
end
it "raises a ZeroDivisionError when the argument has a numerator of 0.0" do
- -> { Rational(3, 4).div(Rational(0.0, 3)) }.should raise_error(ZeroDivisionError)
+ -> { Rational(3, 4).div(Rational(0.0, 3)) }.should.raise(ZeroDivisionError)
end
end
@@ -37,7 +37,7 @@ describe "Rational#div passed an Integer" do
end
it "raises a ZeroDivisionError when the argument is 0" do
- -> { Rational(3, 4).div(0) }.should raise_error(ZeroDivisionError)
+ -> { Rational(3, 4).div(0) }.should.raise(ZeroDivisionError)
end
end
@@ -49,6 +49,6 @@ describe "Rational#div passed a Float" do
end
it "raises a ZeroDivisionError when the argument is 0.0" do
- -> { Rational(3, 4).div(0.0) }.should raise_error(ZeroDivisionError)
+ -> { Rational(3, 4).div(0.0) }.should.raise(ZeroDivisionError)
end
end
diff --git a/spec/ruby/core/rational/divide_spec.rb b/spec/ruby/core/rational/divide_spec.rb
index 8f5ca1fdec..c45d1fca2f 100644
--- a/spec/ruby/core/rational/divide_spec.rb
+++ b/spec/ruby/core/rational/divide_spec.rb
@@ -29,46 +29,46 @@ end
describe "Rational#/ when passed an Integer" do
it "returns self divided by other as a Rational" do
- (Rational(3, 4) / 2).should eql(Rational(3, 8))
- (Rational(2, 4) / 2).should eql(Rational(1, 4))
- (Rational(6, 7) / -2).should eql(Rational(-3, 7))
+ (Rational(3, 4) / 2).should.eql?(Rational(3, 8))
+ (Rational(2, 4) / 2).should.eql?(Rational(1, 4))
+ (Rational(6, 7) / -2).should.eql?(Rational(-3, 7))
end
it "raises a ZeroDivisionError when passed 0" do
- -> { Rational(3, 4) / 0 }.should raise_error(ZeroDivisionError)
+ -> { Rational(3, 4) / 0 }.should.raise(ZeroDivisionError)
end
end
describe "Rational#/ when passed a Rational" do
it "returns self divided by other as a Rational" do
- (Rational(3, 4) / Rational(3, 4)).should eql(Rational(1, 1))
- (Rational(2, 4) / Rational(1, 4)).should eql(Rational(2, 1))
+ (Rational(3, 4) / Rational(3, 4)).should.eql?(Rational(1, 1))
+ (Rational(2, 4) / Rational(1, 4)).should.eql?(Rational(2, 1))
(Rational(2, 4) / 2).should == Rational(1, 4)
(Rational(6, 7) / -2).should == Rational(-3, 7)
end
it "raises a ZeroDivisionError when passed a Rational with a numerator of 0" do
- -> { Rational(3, 4) / Rational(0, 1) }.should raise_error(ZeroDivisionError)
+ -> { Rational(3, 4) / Rational(0, 1) }.should.raise(ZeroDivisionError)
end
end
describe "Rational#/ when passed a Float" do
it "returns self divided by other as a Float" do
- (Rational(3, 4) / 0.75).should eql(1.0)
- (Rational(3, 4) / 0.25).should eql(3.0)
- (Rational(3, 4) / 0.3).should eql(2.5)
+ (Rational(3, 4) / 0.75).should.eql?(1.0)
+ (Rational(3, 4) / 0.25).should.eql?(3.0)
+ (Rational(3, 4) / 0.3).should.eql?(2.5)
- (Rational(-3, 4) / 0.3).should eql(-2.5)
- (Rational(3, -4) / 0.3).should eql(-2.5)
- (Rational(3, 4) / -0.3).should eql(-2.5)
+ (Rational(-3, 4) / 0.3).should.eql?(-2.5)
+ (Rational(3, -4) / 0.3).should.eql?(-2.5)
+ (Rational(3, 4) / -0.3).should.eql?(-2.5)
end
it "returns infinity when passed 0" do
- (Rational(3, 4) / 0.0).infinite?.should eql(1)
- (Rational(-3, -4) / 0.0).infinite?.should eql(1)
+ (Rational(3, 4) / 0.0).infinite?.should.eql?(1)
+ (Rational(-3, -4) / 0.0).infinite?.should.eql?(1)
- (Rational(-3, 4) / 0.0).infinite?.should eql(-1)
- (Rational(3, -4) / 0.0).infinite?.should eql(-1)
+ (Rational(-3, 4) / 0.0).infinite?.should.eql?(-1)
+ (Rational(3, -4) / 0.0).infinite?.should.eql?(-1)
end
end
diff --git a/spec/ruby/core/rational/divmod_spec.rb b/spec/ruby/core/rational/divmod_spec.rb
index f0555294a3..68f8ecfd2d 100644
--- a/spec/ruby/core/rational/divmod_spec.rb
+++ b/spec/ruby/core/rational/divmod_spec.rb
@@ -2,41 +2,41 @@ require_relative "../../spec_helper"
describe "Rational#divmod when passed a Rational" do
it "returns the quotient as Integer and the remainder as Rational" do
- Rational(7, 4).divmod(Rational(1, 2)).should eql([3, Rational(1, 4)])
- Rational(7, 4).divmod(Rational(-1, 2)).should eql([-4, Rational(-1, 4)])
- Rational(0, 4).divmod(Rational(4, 3)).should eql([0, Rational(0, 1)])
+ Rational(7, 4).divmod(Rational(1, 2)).should.eql?([3, Rational(1, 4)])
+ Rational(7, 4).divmod(Rational(-1, 2)).should.eql?([-4, Rational(-1, 4)])
+ Rational(0, 4).divmod(Rational(4, 3)).should.eql?([0, Rational(0, 1)])
- Rational(bignum_value, 4).divmod(Rational(4, 3)).should eql([3458764513820540928, Rational(0, 1)])
+ Rational(bignum_value, 4).divmod(Rational(4, 3)).should.eql?([3458764513820540928, Rational(0, 1)])
end
it "raises a ZeroDivisionError when passed a Rational with a numerator of 0" do
- -> { Rational(7, 4).divmod(Rational(0, 3)) }.should raise_error(ZeroDivisionError)
+ -> { Rational(7, 4).divmod(Rational(0, 3)) }.should.raise(ZeroDivisionError)
end
end
describe "Rational#divmod when passed an Integer" do
it "returns the quotient as Integer and the remainder as Rational" do
- Rational(7, 4).divmod(2).should eql([0, Rational(7, 4)])
- Rational(7, 4).divmod(-2).should eql([-1, Rational(-1, 4)])
+ Rational(7, 4).divmod(2).should.eql?([0, Rational(7, 4)])
+ Rational(7, 4).divmod(-2).should.eql?([-1, Rational(-1, 4)])
- Rational(bignum_value, 4).divmod(3).should eql([1537228672809129301, Rational(1, 1)])
+ Rational(bignum_value, 4).divmod(3).should.eql?([1537228672809129301, Rational(1, 1)])
end
it "raises a ZeroDivisionError when passed 0" do
- -> { Rational(7, 4).divmod(0) }.should raise_error(ZeroDivisionError)
+ -> { Rational(7, 4).divmod(0) }.should.raise(ZeroDivisionError)
end
end
describe "Rational#divmod when passed a Float" do
it "returns the quotient as Integer and the remainder as Float" do
- Rational(7, 4).divmod(0.5).should eql([3, 0.25])
+ Rational(7, 4).divmod(0.5).should.eql?([3, 0.25])
end
it "returns the quotient as Integer and the remainder as Float" do
- Rational(7, 4).divmod(-0.5).should eql([-4, -0.25])
+ Rational(7, 4).divmod(-0.5).should.eql?([-4, -0.25])
end
it "raises a ZeroDivisionError when passed 0" do
- -> { Rational(7, 4).divmod(0.0) }.should raise_error(ZeroDivisionError)
+ -> { Rational(7, 4).divmod(0.0) }.should.raise(ZeroDivisionError)
end
end
diff --git a/spec/ruby/core/rational/equal_value_spec.rb b/spec/ruby/core/rational/equal_value_spec.rb
index ba40d29c3b..1dd077ea41 100644
--- a/spec/ruby/core/rational/equal_value_spec.rb
+++ b/spec/ruby/core/rational/equal_value_spec.rb
@@ -5,35 +5,35 @@ describe "Rational#==" do
obj = mock("Object")
obj.should_receive(:==).and_return(:result)
- (Rational(3, 4) == obj).should_not be_false
+ (Rational(3, 4) == obj).should_not == false
end
end
describe "Rational#== when passed a Rational" do
it "returns true if self has the same numerator and denominator as the passed argument" do
- (Rational(3, 4) == Rational(3, 4)).should be_true
- (Rational(-3, -4) == Rational(3, 4)).should be_true
- (Rational(-4, 5) == Rational(4, -5)).should be_true
+ (Rational(3, 4) == Rational(3, 4)).should == true
+ (Rational(-3, -4) == Rational(3, 4)).should == true
+ (Rational(-4, 5) == Rational(4, -5)).should == true
- (Rational(bignum_value, 3) == Rational(bignum_value, 3)).should be_true
- (Rational(-bignum_value, 3) == Rational(bignum_value, -3)).should be_true
+ (Rational(bignum_value, 3) == Rational(bignum_value, 3)).should == true
+ (Rational(-bignum_value, 3) == Rational(bignum_value, -3)).should == true
end
end
describe "Rational#== when passed a Float" do
it "converts self to a Float and compares it with the passed argument" do
- (Rational(3, 4) == 0.75).should be_true
- (Rational(4, 2) == 2.0).should be_true
- (Rational(-4, 2) == -2.0).should be_true
- (Rational(4, -2) == -2.0).should be_true
+ (Rational(3, 4) == 0.75).should == true
+ (Rational(4, 2) == 2.0).should == true
+ (Rational(-4, 2) == -2.0).should == true
+ (Rational(4, -2) == -2.0).should == true
end
end
describe "Rational#== when passed an Integer" do
it "returns true if self has the passed argument as numerator and a denominator of 1" do
# Rational(x, y) reduces x and y automatically
- (Rational(4, 2) == 2).should be_true
- (Rational(-4, 2) == -2).should be_true
- (Rational(4, -2) == -2).should be_true
+ (Rational(4, 2) == 2).should == true
+ (Rational(-4, 2) == -2).should == true
+ (Rational(4, -2) == -2).should == true
end
end
diff --git a/spec/ruby/core/rational/exponent_spec.rb b/spec/ruby/core/rational/exponent_spec.rb
index 65fbf2ed1c..88b4a43796 100644
--- a/spec/ruby/core/rational/exponent_spec.rb
+++ b/spec/ruby/core/rational/exponent_spec.rb
@@ -5,20 +5,20 @@ describe "Rational#**" do
# Guard against the Mathn library
guard -> { !defined?(Math.rsqrt) } do
it "returns Rational(1) if the exponent is Rational(0)" do
- (Rational(0) ** Rational(0)).should eql(Rational(1))
- (Rational(1) ** Rational(0)).should eql(Rational(1))
- (Rational(3, 4) ** Rational(0)).should eql(Rational(1))
- (Rational(-1) ** Rational(0)).should eql(Rational(1))
- (Rational(-3, 4) ** Rational(0)).should eql(Rational(1))
- (Rational(bignum_value) ** Rational(0)).should eql(Rational(1))
- (Rational(-bignum_value) ** Rational(0)).should eql(Rational(1))
+ (Rational(0) ** Rational(0)).should.eql?(Rational(1))
+ (Rational(1) ** Rational(0)).should.eql?(Rational(1))
+ (Rational(3, 4) ** Rational(0)).should.eql?(Rational(1))
+ (Rational(-1) ** Rational(0)).should.eql?(Rational(1))
+ (Rational(-3, 4) ** Rational(0)).should.eql?(Rational(1))
+ (Rational(bignum_value) ** Rational(0)).should.eql?(Rational(1))
+ (Rational(-bignum_value) ** Rational(0)).should.eql?(Rational(1))
end
it "returns self raised to the argument as a Rational if the exponent's denominator is 1" do
- (Rational(3, 4) ** Rational(1, 1)).should eql(Rational(3, 4))
- (Rational(3, 4) ** Rational(2, 1)).should eql(Rational(9, 16))
- (Rational(3, 4) ** Rational(-1, 1)).should eql(Rational(4, 3))
- (Rational(3, 4) ** Rational(-2, 1)).should eql(Rational(16, 9))
+ (Rational(3, 4) ** Rational(1, 1)).should.eql?(Rational(3, 4))
+ (Rational(3, 4) ** Rational(2, 1)).should.eql?(Rational(9, 16))
+ (Rational(3, 4) ** Rational(-1, 1)).should.eql?(Rational(4, 3))
+ (Rational(3, 4) ** Rational(-2, 1)).should.eql?(Rational(16, 9))
end
it "returns self raised to the argument as a Float if the exponent's denominator is not 1" do
@@ -49,12 +49,12 @@ describe "Rational#**" do
# Guard against the Mathn library
guard -> { !defined?(Math.rsqrt) } do
it "returns Rational(1, 1) when the passed argument is 0" do
- (Rational(3, 4) ** 0).should eql(Rational(1, 1))
- (Rational(-3, 4) ** 0).should eql(Rational(1, 1))
- (Rational(3, -4) ** 0).should eql(Rational(1, 1))
+ (Rational(3, 4) ** 0).should.eql?(Rational(1, 1))
+ (Rational(-3, 4) ** 0).should.eql?(Rational(1, 1))
+ (Rational(3, -4) ** 0).should.eql?(Rational(1, 1))
- (Rational(bignum_value, 4) ** 0).should eql(Rational(1, 1))
- (Rational(3, -bignum_value) ** 0).should eql(Rational(1, 1))
+ (Rational(bignum_value, 4) ** 0).should.eql?(Rational(1, 1))
+ (Rational(3, -bignum_value) ** 0).should.eql?(Rational(1, 1))
end
end
end
@@ -62,26 +62,26 @@ describe "Rational#**" do
describe "when passed Bignum" do
# #5713
it "returns Rational(0) when self is Rational(0) and the exponent is positive" do
- (Rational(0) ** bignum_value).should eql(Rational(0))
+ (Rational(0) ** bignum_value).should.eql?(Rational(0))
end
it "raises ZeroDivisionError when self is Rational(0) and the exponent is negative" do
- -> { Rational(0) ** -bignum_value }.should raise_error(ZeroDivisionError)
+ -> { Rational(0) ** -bignum_value }.should.raise(ZeroDivisionError)
end
it "returns Rational(1) when self is Rational(1)" do
- (Rational(1) ** bignum_value).should eql(Rational(1))
- (Rational(1) ** -bignum_value).should eql(Rational(1))
+ (Rational(1) ** bignum_value).should.eql?(Rational(1))
+ (Rational(1) ** -bignum_value).should.eql?(Rational(1))
end
it "returns Rational(1) when self is Rational(-1) and the exponent is positive and even" do
- (Rational(-1) ** bignum_value(0)).should eql(Rational(1))
- (Rational(-1) ** bignum_value(2)).should eql(Rational(1))
+ (Rational(-1) ** bignum_value(0)).should.eql?(Rational(1))
+ (Rational(-1) ** bignum_value(2)).should.eql?(Rational(1))
end
it "returns Rational(-1) when self is Rational(-1) and the exponent is positive and odd" do
- (Rational(-1) ** bignum_value(1)).should eql(Rational(-1))
- (Rational(-1) ** bignum_value(3)).should eql(Rational(-1))
+ (Rational(-1) ** bignum_value(1)).should.eql?(Rational(-1))
+ (Rational(-1) ** bignum_value(3)).should.eql?(Rational(-1))
end
ruby_version_is ""..."3.4" do
@@ -96,10 +96,10 @@ describe "Rational#**" do
it "returns 0.0 when self is > 1 and the exponent is negative" do
-> {
- (Rational(2) ** -bignum_value).should eql(0.0)
+ (Rational(2) ** -bignum_value).should.eql?(0.0)
}.should complain(/warning: in a\*\*b, b may be too big/)
-> {
- (Rational(fixnum_max) ** -bignum_value).should eql(0.0)
+ (Rational(fixnum_max) ** -bignum_value).should.eql?(0.0)
}.should complain(/warning: in a\*\*b, b may be too big/)
end
end
@@ -108,37 +108,37 @@ describe "Rational#**" do
it "raises an ArgumentError when self is > 1" do
-> {
(Rational(2) ** bignum_value)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError, "exponent is too large")
-> {
(Rational(fixnum_max) ** bignum_value)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError, "exponent is too large")
end
it "raises an ArgumentError when self is > 1 and the exponent is negative" do
-> {
(Rational(2) ** -bignum_value)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError, "exponent is too large")
-> {
(Rational(fixnum_max) ** -bignum_value)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError, "exponent is too large")
end
it "raises an ArgumentError when self is < -1" do
-> {
(Rational(-2) ** bignum_value)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError, "exponent is too large")
-> {
(Rational(fixnum_min) ** bignum_value)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError, "exponent is too large")
end
it "raises an ArgumentError when self is < -1 and the exponent is negative" do
-> {
(Rational(-2) ** -bignum_value)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError, "exponent is too large")
-> {
(Rational(fixnum_min) ** -bignum_value)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError, "exponent is too large")
end
end
@@ -159,10 +159,10 @@ describe "Rational#**" do
it "returns 0.0 when self is < -1 and the exponent is negative" do
-> {
- (Rational(-2) ** -bignum_value).should eql(0.0)
+ (Rational(-2) ** -bignum_value).should.eql?(0.0)
}.should complain(/warning: in a\*\*b, b may be too big/)
-> {
- (Rational(fixnum_min) ** -bignum_value).should eql(0.0)
+ (Rational(fixnum_min) ** -bignum_value).should.eql?(0.0)
}.should complain(/warning: in a\*\*b, b may be too big/)
end
end
@@ -171,7 +171,7 @@ describe "Rational#**" do
describe "when passed Float" do
it "returns self converted to Float and raised to the passed argument" do
- (Rational(3, 1) ** 3.0).should eql(27.0)
+ (Rational(3, 1) ** 3.0).should.eql?(27.0)
(Rational(3, 1) ** 1.5).should be_close(5.19615242270663, TOLERANCE)
(Rational(3, 1) ** -1.5).should be_close(0.192450089729875, TOLERANCE)
end
@@ -213,19 +213,19 @@ describe "Rational#**" do
it "raises ZeroDivisionError for Rational(0, 1) passed a negative Integer" do
[-1, -4, -9999].each do |exponent|
- -> { Rational(0, 1) ** exponent }.should raise_error(ZeroDivisionError, "divided by 0")
+ -> { Rational(0, 1) ** exponent }.should.raise(ZeroDivisionError, "divided by 0")
end
end
it "raises ZeroDivisionError for Rational(0, 1) passed a negative Rational with denominator 1" do
[Rational(-1, 1), Rational(-3, 1)].each do |exponent|
- -> { Rational(0, 1) ** exponent }.should raise_error(ZeroDivisionError, "divided by 0")
+ -> { Rational(0, 1) ** exponent }.should.raise(ZeroDivisionError, "divided by 0")
end
end
# #7513
it "raises ZeroDivisionError for Rational(0, 1) passed a negative Rational" do
- -> { Rational(0, 1) ** Rational(-3, 2) }.should raise_error(ZeroDivisionError, "divided by 0")
+ -> { Rational(0, 1) ** Rational(-3, 2) }.should.raise(ZeroDivisionError, "divided by 0")
end
it "returns Infinity for Rational(0, 1) passed a negative Float" do
diff --git a/spec/ruby/core/rational/floor_spec.rb b/spec/ruby/core/rational/floor_spec.rb
index 8068aaf119..6d4cee79a9 100644
--- a/spec/ruby/core/rational/floor_spec.rb
+++ b/spec/ruby/core/rational/floor_spec.rb
@@ -1,45 +1,49 @@
require_relative "../../spec_helper"
+require_relative "../integer/shared/integer_floor_precision"
describe "Rational#floor" do
+ context "with values equal to integers" do
+ it_behaves_like :integer_floor_precision, :Rational
+ end
+
before do
@rational = Rational(2200, 7)
end
describe "with no arguments (precision = 0)" do
- it "returns an integer" do
- @rational.floor.should be_kind_of(Integer)
- end
- it "returns the truncated value toward negative infinity" do
- @rational.floor.should == 314
- Rational(1, 2).floor.should == 0
- Rational(-1, 2).floor.should == -1
+ it "returns the Integer value rounded toward negative infinity" do
+ @rational.floor.should.eql? 314
+
+ Rational(1, 2).floor.should.eql? 0
+ Rational(-1, 2).floor.should.eql?(-1)
+ Rational(1, 1).floor.should.eql? 1
end
end
describe "with a precision < 0" do
- it "returns an integer" do
- @rational.floor(-2).should be_kind_of(Integer)
- @rational.floor(-1).should be_kind_of(Integer)
- end
+ it "moves the rounding point n decimal places left, returning an Integer" do
+ @rational.floor(-3).should.eql? 0
+ @rational.floor(-2).should.eql? 300
+ @rational.floor(-1).should.eql? 310
- it "moves the truncation point n decimal places left" do
- @rational.floor(-3).should == 0
- @rational.floor(-2).should == 300
- @rational.floor(-1).should == 310
+ Rational(100, 2).floor(-1).should.eql? 50
+ Rational(100, 2).floor(-2).should.eql? 0
+ Rational(-100, 2).floor(-1).should.eql?(-50)
+ Rational(-100, 2).floor(-2).should.eql?(-100)
end
end
describe "with a precision > 0" do
- it "returns a Rational" do
- @rational.floor(1).should be_kind_of(Rational)
- @rational.floor(2).should be_kind_of(Rational)
- end
+ it "moves the rounding point n decimal places right, returning a Rational" do
+ @rational.floor(1).should.eql? Rational(1571, 5)
+ @rational.floor(2).should.eql? Rational(7857, 25)
+ @rational.floor(3).should.eql? Rational(62857, 200)
- it "moves the truncation point n decimal places right" do
- @rational.floor(1).should == Rational(1571, 5)
- @rational.floor(2).should == Rational(7857, 25)
- @rational.floor(3).should == Rational(62857, 200)
+ Rational(100, 2).floor(1).should.eql? Rational(50, 1)
+ Rational(100, 2).floor(2).should.eql? Rational(50, 1)
+ Rational(-100, 2).floor(1).should.eql? Rational(-50, 1)
+ Rational(-100, 2).floor(2).should.eql? Rational(-50, 1)
end
end
end
diff --git a/spec/ruby/core/rational/integer_spec.rb b/spec/ruby/core/rational/integer_spec.rb
index be7476a9dd..cd7fa97fcf 100644
--- a/spec/ruby/core/rational/integer_spec.rb
+++ b/spec/ruby/core/rational/integer_spec.rb
@@ -3,11 +3,11 @@ describe "Rational#integer?" do
# Guard against the Mathn library
guard -> { !defined?(Math.rsqrt) } do
it "returns false for a rational with a numerator and no denominator" do
- Rational(20).integer?.should be_false
+ Rational(20).integer?.should == false
end
end
it "returns false for a rational with a numerator and a denominator" do
- Rational(20,3).integer?.should be_false
+ Rational(20,3).integer?.should == false
end
end
diff --git a/spec/ruby/core/rational/magnitude_spec.rb b/spec/ruby/core/rational/magnitude_spec.rb
index f5f667edb1..0df637df7a 100644
--- a/spec/ruby/core/rational/magnitude_spec.rb
+++ b/spec/ruby/core/rational/magnitude_spec.rb
@@ -1,6 +1,7 @@
require_relative "../../spec_helper"
-require_relative 'shared/abs'
-describe "Rational#abs" do
- it_behaves_like :rational_abs, :magnitude
+describe "Rational#magnitude" do
+ it "is an alias of Rational#abs" do
+ Rational.instance_method(:magnitude).should == Rational.instance_method(:abs)
+ end
end
diff --git a/spec/ruby/core/rational/marshal_dump_spec.rb b/spec/ruby/core/rational/marshal_dump_spec.rb
index 17a6107cd5..06bf36f166 100644
--- a/spec/ruby/core/rational/marshal_dump_spec.rb
+++ b/spec/ruby/core/rational/marshal_dump_spec.rb
@@ -2,7 +2,7 @@ require_relative '../../spec_helper'
describe "Rational#marshal_dump" do
it "is a private method" do
- Rational.should have_private_instance_method(:marshal_dump, false)
+ Rational.private_instance_methods(false).should.include?(:marshal_dump)
end
it "dumps numerator and denominator" do
diff --git a/spec/ruby/core/rational/minus_spec.rb b/spec/ruby/core/rational/minus_spec.rb
index 8aee85f9dd..4e10e118b9 100644
--- a/spec/ruby/core/rational/minus_spec.rb
+++ b/spec/ruby/core/rational/minus_spec.rb
@@ -29,23 +29,23 @@ end
describe "Rational#- passed a Rational" do
it "returns the result of subtracting other from self as a Rational" do
- (Rational(3, 4) - Rational(0, 1)).should eql(Rational(3, 4))
- (Rational(3, 4) - Rational(1, 4)).should eql(Rational(1, 2))
+ (Rational(3, 4) - Rational(0, 1)).should.eql?(Rational(3, 4))
+ (Rational(3, 4) - Rational(1, 4)).should.eql?(Rational(1, 2))
- (Rational(3, 4) - Rational(2, 1)).should eql(Rational(-5, 4))
+ (Rational(3, 4) - Rational(2, 1)).should.eql?(Rational(-5, 4))
end
end
describe "Rational#- passed a Float" do
it "returns the result of subtracting other from self as a Float" do
- (Rational(3, 4) - 0.2).should eql(0.55)
- (Rational(3, 4) - 2.5).should eql(-1.75)
+ (Rational(3, 4) - 0.2).should.eql?(0.55)
+ (Rational(3, 4) - 2.5).should.eql?(-1.75)
end
end
describe "Rational#- passed an Integer" do
it "returns the result of subtracting other from self as a Rational" do
- (Rational(3, 4) - 1).should eql(Rational(-1, 4))
- (Rational(3, 4) - 2).should eql(Rational(-5, 4))
+ (Rational(3, 4) - 1).should.eql?(Rational(-1, 4))
+ (Rational(3, 4) - 2).should.eql?(Rational(-5, 4))
end
end
diff --git a/spec/ruby/core/rational/modulo_spec.rb b/spec/ruby/core/rational/modulo_spec.rb
index 23ed93e118..6241077f68 100644
--- a/spec/ruby/core/rational/modulo_spec.rb
+++ b/spec/ruby/core/rational/modulo_spec.rb
@@ -16,7 +16,7 @@ describe "Rational#%" do
end
it "returns a Float value when the argument is Float" do
- (Rational(7, 4) % 1.0).should be_kind_of(Float)
+ (Rational(7, 4) % 1.0).should.is_a?(Float)
(Rational(7, 4) % 1.0).should == 0.75
(Rational(7, 4) % 0.26).should be_close(0.19, 0.0001)
end
@@ -24,20 +24,20 @@ describe "Rational#%" do
it "raises ZeroDivisionError on zero denominator" do
-> {
Rational(3, 5) % Rational(0, 1)
- }.should raise_error(ZeroDivisionError)
+ }.should.raise(ZeroDivisionError)
-> {
Rational(0, 1) % Rational(0, 1)
- }.should raise_error(ZeroDivisionError)
+ }.should.raise(ZeroDivisionError)
-> {
Rational(3, 5) % 0
- }.should raise_error(ZeroDivisionError)
+ }.should.raise(ZeroDivisionError)
end
it "raises a ZeroDivisionError when the argument is 0.0" do
-> {
Rational(3, 5) % 0.0
- }.should raise_error(ZeroDivisionError)
+ }.should.raise(ZeroDivisionError)
end
end
diff --git a/spec/ruby/core/rational/multiply_spec.rb b/spec/ruby/core/rational/multiply_spec.rb
index 87fb4de2b4..3e059cbc1c 100644
--- a/spec/ruby/core/rational/multiply_spec.rb
+++ b/spec/ruby/core/rational/multiply_spec.rb
@@ -29,37 +29,37 @@ end
describe "Rational#* passed a Rational" do
it "returns self divided by other as a Rational" do
- (Rational(3, 4) * Rational(3, 4)).should eql(Rational(9, 16))
- (Rational(2, 4) * Rational(1, 4)).should eql(Rational(1, 8))
+ (Rational(3, 4) * Rational(3, 4)).should.eql?(Rational(9, 16))
+ (Rational(2, 4) * Rational(1, 4)).should.eql?(Rational(1, 8))
- (Rational(3, 4) * Rational(0, 1)).should eql(Rational(0, 4))
+ (Rational(3, 4) * Rational(0, 1)).should.eql?(Rational(0, 4))
end
end
describe "Rational#* passed a Float" do
it "returns self divided by other as a Float" do
- (Rational(3, 4) * 0.75).should eql(0.5625)
- (Rational(3, 4) * 0.25).should eql(0.1875)
+ (Rational(3, 4) * 0.75).should.eql?(0.5625)
+ (Rational(3, 4) * 0.25).should.eql?(0.1875)
(Rational(3, 4) * 0.3).should be_close(0.225, TOLERANCE)
(Rational(-3, 4) * 0.3).should be_close(-0.225, TOLERANCE)
(Rational(3, -4) * 0.3).should be_close(-0.225, TOLERANCE)
(Rational(3, 4) * -0.3).should be_close(-0.225, TOLERANCE)
- (Rational(3, 4) * 0.0).should eql(0.0)
- (Rational(-3, -4) * 0.0).should eql(0.0)
+ (Rational(3, 4) * 0.0).should.eql?(0.0)
+ (Rational(-3, -4) * 0.0).should.eql?(0.0)
- (Rational(-3, 4) * 0.0).should eql(0.0)
- (Rational(3, -4) * 0.0).should eql(0.0)
+ (Rational(-3, 4) * 0.0).should.eql?(0.0)
+ (Rational(3, -4) * 0.0).should.eql?(0.0)
end
end
describe "Rational#* passed an Integer" do
it "returns self divided by other as a Rational" do
- (Rational(3, 4) * 2).should eql(Rational(3, 2))
- (Rational(2, 4) * 2).should eql(Rational(1, 1))
- (Rational(6, 7) * -2).should eql(Rational(-12, 7))
+ (Rational(3, 4) * 2).should.eql?(Rational(3, 2))
+ (Rational(2, 4) * 2).should.eql?(Rational(1, 1))
+ (Rational(6, 7) * -2).should.eql?(Rational(-12, 7))
- (Rational(3, 4) * 0).should eql(Rational(0, 4))
+ (Rational(3, 4) * 0).should.eql?(Rational(0, 4))
end
end
diff --git a/spec/ruby/core/rational/numerator_spec.rb b/spec/ruby/core/rational/numerator_spec.rb
index 2b9fe2ff5c..631bb4703c 100644
--- a/spec/ruby/core/rational/numerator_spec.rb
+++ b/spec/ruby/core/rational/numerator_spec.rb
@@ -2,8 +2,8 @@ require_relative "../../spec_helper"
describe "Rational#numerator" do
it "returns the numerator" do
- Rational(3, 4).numerator.should equal(3)
- Rational(3, -4).numerator.should equal(-3)
+ Rational(3, 4).numerator.should.equal?(3)
+ Rational(3, -4).numerator.should.equal?(-3)
Rational(bignum_value, 1).numerator.should == bignum_value
end
diff --git a/spec/ruby/core/rational/plus_spec.rb b/spec/ruby/core/rational/plus_spec.rb
index 01df5f6719..92f830a105 100644
--- a/spec/ruby/core/rational/plus_spec.rb
+++ b/spec/ruby/core/rational/plus_spec.rb
@@ -29,22 +29,22 @@ end
describe "Rational#+ with a Rational" do
it "returns the result of subtracting other from self as a Rational" do
- (Rational(3, 4) + Rational(0, 1)).should eql(Rational(3, 4))
- (Rational(3, 4) + Rational(1, 4)).should eql(Rational(1, 1))
+ (Rational(3, 4) + Rational(0, 1)).should.eql?(Rational(3, 4))
+ (Rational(3, 4) + Rational(1, 4)).should.eql?(Rational(1, 1))
- (Rational(3, 4) + Rational(2, 1)).should eql(Rational(11, 4))
+ (Rational(3, 4) + Rational(2, 1)).should.eql?(Rational(11, 4))
end
end
describe "Rational#+ with a Float" do
it "returns the result of subtracting other from self as a Float" do
- (Rational(3, 4) + 0.2).should eql(0.95)
- (Rational(3, 4) + 2.5).should eql(3.25)
+ (Rational(3, 4) + 0.2).should.eql?(0.95)
+ (Rational(3, 4) + 2.5).should.eql?(3.25)
end
end
describe "Rational#+ with an Integer" do
it "returns the result of subtracting other from self as a Rational" do
- (Rational(3, 4) + 1).should eql(Rational(7, 4))
- (Rational(3, 4) + 2).should eql(Rational(11, 4))
+ (Rational(3, 4) + 1).should.eql?(Rational(7, 4))
+ (Rational(3, 4) + 2).should.eql?(Rational(11, 4))
end
end
diff --git a/spec/ruby/core/rational/quo_spec.rb b/spec/ruby/core/rational/quo_spec.rb
index 907898ad34..62178f403b 100644
--- a/spec/ruby/core/rational/quo_spec.rb
+++ b/spec/ruby/core/rational/quo_spec.rb
@@ -1,25 +1,7 @@
require_relative "../../spec_helper"
describe "Rational#quo" do
- it "calls #coerce on the passed argument with self" do
- rational = Rational(3, 4)
- obj = mock("Object")
- obj.should_receive(:coerce).with(rational).and_return([1, 2])
-
- rational.quo(obj)
- end
-
- it "calls #/ on the coerced Rational with the coerced Object" do
- rational = Rational(3, 4)
-
- coerced_rational = mock("Coerced Rational")
- coerced_rational.should_receive(:/).and_return(:result)
-
- coerced_obj = mock("Coerced Object")
-
- obj = mock("Object")
- obj.should_receive(:coerce).and_return([coerced_rational, coerced_obj])
-
- rational.quo(obj).should == :result
+ it "is an alias of Rational#/" do
+ Rational.instance_method(:quo).should == Rational.instance_method(:/)
end
end
diff --git a/spec/ruby/core/rational/rational_spec.rb b/spec/ruby/core/rational/rational_spec.rb
index 482deab38d..278c4116a4 100644
--- a/spec/ruby/core/rational/rational_spec.rb
+++ b/spec/ruby/core/rational/rational_spec.rb
@@ -6,6 +6,6 @@ describe "Rational" do
end
it "does not respond to new" do
- -> { Rational.new(1) }.should raise_error(NoMethodError)
+ -> { Rational.new(1) }.should.raise(NoMethodError)
end
end
diff --git a/spec/ruby/core/rational/rationalize_spec.rb b/spec/ruby/core/rational/rationalize_spec.rb
index 3db027d446..9c86824ddd 100644
--- a/spec/ruby/core/rational/rationalize_spec.rb
+++ b/spec/ruby/core/rational/rationalize_spec.rb
@@ -30,7 +30,7 @@ describe "Rational#rationalize" do
end
it "raises ArgumentError when passed more than one argument" do
- -> { Rational(1,1).rationalize(0.1, 0.1) }.should raise_error(ArgumentError)
- -> { Rational(1,1).rationalize(0.1, 0.1, 2) }.should raise_error(ArgumentError)
+ -> { Rational(1,1).rationalize(0.1, 0.1) }.should.raise(ArgumentError)
+ -> { Rational(1,1).rationalize(0.1, 0.1, 2) }.should.raise(ArgumentError)
end
end
diff --git a/spec/ruby/core/rational/round_spec.rb b/spec/ruby/core/rational/round_spec.rb
index ac3dcafe7b..dd6f66f408 100644
--- a/spec/ruby/core/rational/round_spec.rb
+++ b/spec/ruby/core/rational/round_spec.rb
@@ -7,9 +7,9 @@ describe "Rational#round" do
describe "with no arguments (precision = 0)" do
it "returns an integer" do
- @rational.round.should be_kind_of(Integer)
- Rational(0, 1).round(0).should be_kind_of(Integer)
- Rational(124, 1).round(0).should be_kind_of(Integer)
+ @rational.round.should.is_a?(Integer)
+ Rational(0, 1).round(0).should.is_a?(Integer)
+ Rational(124, 1).round(0).should.is_a?(Integer)
end
it "returns the truncated value toward the nearest integer" do
@@ -30,10 +30,10 @@ describe "Rational#round" do
describe "with a precision < 0" do
it "returns an integer" do
- @rational.round(-2).should be_kind_of(Integer)
- @rational.round(-1).should be_kind_of(Integer)
- Rational(0, 1).round(-1).should be_kind_of(Integer)
- Rational(2, 1).round(-1).should be_kind_of(Integer)
+ @rational.round(-2).should.is_a?(Integer)
+ @rational.round(-1).should.is_a?(Integer)
+ Rational(0, 1).round(-1).should.is_a?(Integer)
+ Rational(2, 1).round(-1).should.is_a?(Integer)
end
it "moves the truncation point n decimal places left" do
@@ -45,12 +45,12 @@ describe "Rational#round" do
describe "with a precision > 0" do
it "returns a Rational" do
- @rational.round(1).should be_kind_of(Rational)
- @rational.round(2).should be_kind_of(Rational)
+ @rational.round(1).should.is_a?(Rational)
+ @rational.round(2).should.is_a?(Rational)
# Guard against the Mathn library
guard -> { !defined?(Math.rsqrt) } do
- Rational(0, 1).round(1).should be_kind_of(Rational)
- Rational(2, 1).round(1).should be_kind_of(Rational)
+ Rational(0, 1).round(1).should.is_a?(Rational)
+ Rational(2, 1).round(1).should.is_a?(Rational)
end
end
@@ -100,7 +100,7 @@ describe "Rational#round" do
end
it "raise for a non-existent round mode" do
- -> { Rational(10, 4).round(half: :nonsense) }.should raise_error(ArgumentError, "invalid rounding mode: nonsense")
+ -> { Rational(10, 4).round(half: :nonsense) }.should.raise(ArgumentError, "invalid rounding mode: nonsense")
end
end
end
diff --git a/spec/ruby/core/rational/shared/abs.rb b/spec/ruby/core/rational/shared/abs.rb
deleted file mode 100644
index 3d64bcc1a0..0000000000
--- a/spec/ruby/core/rational/shared/abs.rb
+++ /dev/null
@@ -1,11 +0,0 @@
-require_relative '../../../spec_helper'
-
-describe :rational_abs, shared: true do
- it "returns self's absolute value" do
- Rational(3, 4).send(@method).should == Rational(3, 4)
- Rational(-3, 4).send(@method).should == Rational(3, 4)
- Rational(3, -4).send(@method).should == Rational(3, 4)
-
- Rational(bignum_value, -bignum_value).send(@method).should == Rational(bignum_value, bignum_value)
- end
-end
diff --git a/spec/ruby/core/rational/shared/arithmetic_exception_in_coerce.rb b/spec/ruby/core/rational/shared/arithmetic_exception_in_coerce.rb
index f4cf70d147..e15169c912 100644
--- a/spec/ruby/core/rational/shared/arithmetic_exception_in_coerce.rb
+++ b/spec/ruby/core/rational/shared/arithmetic_exception_in_coerce.rb
@@ -6,6 +6,6 @@ describe :rational_arithmetic_exception_in_coerce, shared: true do
b.should_receive(:coerce).and_raise(RationalSpecs::CoerceError)
# e.g. Rational(3, 4) + b
- -> { Rational(3, 4).send(@method, b) }.should raise_error(RationalSpecs::CoerceError)
+ -> { Rational(3, 4).send(@method, b) }.should.raise(RationalSpecs::CoerceError)
end
end
diff --git a/spec/ruby/core/rational/to_f_spec.rb b/spec/ruby/core/rational/to_f_spec.rb
index d0da49d377..40e3f11c0c 100644
--- a/spec/ruby/core/rational/to_f_spec.rb
+++ b/spec/ruby/core/rational/to_f_spec.rb
@@ -2,10 +2,10 @@ require_relative "../../spec_helper"
describe "Rational#to_f" do
it "returns self converted to a Float" do
- Rational(3, 4).to_f.should eql(0.75)
- Rational(3, -4).to_f.should eql(-0.75)
- Rational(-1, 4).to_f.should eql(-0.25)
- Rational(-1, -4).to_f.should eql(0.25)
+ Rational(3, 4).to_f.should.eql?(0.75)
+ Rational(3, -4).to_f.should.eql?(-0.75)
+ Rational(-1, 4).to_f.should.eql?(-0.25)
+ Rational(-1, -4).to_f.should.eql?(0.25)
end
it "converts to a Float for large numerator and denominator" do
diff --git a/spec/ruby/core/rational/to_i_spec.rb b/spec/ruby/core/rational/to_i_spec.rb
index 520a380b2a..e61b1b6c3b 100644
--- a/spec/ruby/core/rational/to_i_spec.rb
+++ b/spec/ruby/core/rational/to_i_spec.rb
@@ -2,11 +2,11 @@ require_relative "../../spec_helper"
describe "Rational#to_i" do
it "converts self to an Integer by truncation" do
- Rational(7, 4).to_i.should eql(1)
- Rational(11, 4).to_i.should eql(2)
+ Rational(7, 4).to_i.should.eql?(1)
+ Rational(11, 4).to_i.should.eql?(2)
end
it "converts self to an Integer by truncation" do
- Rational(-7, 4).to_i.should eql(-1)
+ Rational(-7, 4).to_i.should.eql?(-1)
end
end
diff --git a/spec/ruby/core/rational/to_r_spec.rb b/spec/ruby/core/rational/to_r_spec.rb
index 34f16d7890..eb6097f595 100644
--- a/spec/ruby/core/rational/to_r_spec.rb
+++ b/spec/ruby/core/rational/to_r_spec.rb
@@ -3,15 +3,15 @@ require_relative "../../spec_helper"
describe "Rational#to_r" do
it "returns self" do
a = Rational(3, 4)
- a.to_r.should equal(a)
+ a.to_r.should.equal?(a)
a = Rational(bignum_value, 4)
- a.to_r.should equal(a)
+ a.to_r.should.equal?(a)
end
it "raises TypeError trying to convert BasicObject" do
obj = BasicObject.new
- -> { Rational(obj) }.should raise_error(TypeError)
+ -> { Rational(obj) }.should.raise(TypeError)
end
it "works when a BasicObject has to_r" do
@@ -21,6 +21,6 @@ describe "Rational#to_r" do
it "fails when a BasicObject's to_r does not return a Rational" do
obj = BasicObject.new; def obj.to_r; 1 end
- -> { Rational(obj) }.should raise_error(TypeError)
+ -> { Rational(obj) }.should.raise(TypeError)
end
end
diff --git a/spec/ruby/core/rational/truncate_spec.rb b/spec/ruby/core/rational/truncate_spec.rb
index 728fca34ea..3614431a7f 100644
--- a/spec/ruby/core/rational/truncate_spec.rb
+++ b/spec/ruby/core/rational/truncate_spec.rb
@@ -7,7 +7,7 @@ describe "Rational#truncate" do
describe "with no arguments (precision = 0)" do
it "returns an integer" do
- @rational.truncate.should be_kind_of(Integer)
+ @rational.truncate.should.is_a?(Integer)
end
it "returns the truncated value toward 0" do
@@ -19,7 +19,7 @@ describe "Rational#truncate" do
describe "with an explicit precision = 0" do
it "returns an integer" do
- @rational.truncate(0).should be_kind_of(Integer)
+ @rational.truncate(0).should.is_a?(Integer)
end
it "returns the truncated value toward 0" do
@@ -31,8 +31,8 @@ describe "Rational#truncate" do
describe "with a precision < 0" do
it "returns an integer" do
- @rational.truncate(-2).should be_kind_of(Integer)
- @rational.truncate(-1).should be_kind_of(Integer)
+ @rational.truncate(-2).should.is_a?(Integer)
+ @rational.truncate(-1).should.is_a?(Integer)
end
it "moves the truncation point n decimal places left" do
@@ -44,8 +44,8 @@ describe "Rational#truncate" do
describe "with a precision > 0" do
it "returns a Rational" do
- @rational.truncate(1).should be_kind_of(Rational)
- @rational.truncate(2).should be_kind_of(Rational)
+ @rational.truncate(1).should.is_a?(Rational)
+ @rational.truncate(2).should.is_a?(Rational)
end
it "moves the truncation point n decimal places right" do
@@ -57,15 +57,15 @@ describe "Rational#truncate" do
describe "with an invalid value for precision" do
it "raises a TypeError" do
- -> { @rational.truncate(nil) }.should raise_error(TypeError, "not an integer")
- -> { @rational.truncate(1.0) }.should raise_error(TypeError, "not an integer")
- -> { @rational.truncate('') }.should raise_error(TypeError, "not an integer")
+ -> { @rational.truncate(nil) }.should.raise(TypeError, "not an integer")
+ -> { @rational.truncate(1.0) }.should.raise(TypeError, "not an integer")
+ -> { @rational.truncate('') }.should.raise(TypeError, "not an integer")
end
it "does not call to_int on the argument" do
object = Object.new
object.should_not_receive(:to_int)
- -> { @rational.truncate(object) }.should raise_error(TypeError, "not an integer")
+ -> { @rational.truncate(object) }.should.raise(TypeError, "not an integer")
end
end
end
diff --git a/spec/ruby/core/rational/zero_spec.rb b/spec/ruby/core/rational/zero_spec.rb
index af7fb391ac..2e4f783d5c 100644
--- a/spec/ruby/core/rational/zero_spec.rb
+++ b/spec/ruby/core/rational/zero_spec.rb
@@ -1,14 +1,14 @@
require_relative "../../spec_helper"
describe "Rational#zero?" do
it "returns true if the numerator is 0" do
- Rational(0,26).zero?.should be_true
+ Rational(0,26).zero?.should == true
end
it "returns true if the numerator is 0.0" do
- Rational(0.0,26).zero?.should be_true
+ Rational(0.0,26).zero?.should == true
end
it "returns false if the numerator isn't 0" do
- Rational(26).zero?.should be_false
+ Rational(26).zero?.should == false
end
end
diff --git a/spec/ruby/core/refinement/append_features_spec.rb b/spec/ruby/core/refinement/append_features_spec.rb
index f7e5f32bc1..cffc9ed308 100644
--- a/spec/ruby/core/refinement/append_features_spec.rb
+++ b/spec/ruby/core/refinement/append_features_spec.rb
@@ -2,7 +2,7 @@ require_relative '../../spec_helper'
describe "Refinement#append_features" do
it "is not defined" do
- Refinement.should_not have_private_instance_method(:append_features)
+ Refinement.private_instance_methods(true).should_not.include?(:append_features)
end
it "is not called by Module#include" do
@@ -11,7 +11,7 @@ describe "Refinement#append_features" do
refine c do
called = false
define_method(:append_features){called = true}
- proc{c.include(self)}.should raise_error(TypeError)
+ proc{c.include(self)}.should.raise(TypeError)
called.should == false
end
end
diff --git a/spec/ruby/core/refinement/extend_object_spec.rb b/spec/ruby/core/refinement/extend_object_spec.rb
index 4da8b359cc..f6fe2a60ea 100644
--- a/spec/ruby/core/refinement/extend_object_spec.rb
+++ b/spec/ruby/core/refinement/extend_object_spec.rb
@@ -2,7 +2,7 @@ require_relative '../../spec_helper'
describe "Refinement#extend_object" do
it "is not defined" do
- Refinement.should_not have_private_instance_method(:extend_object)
+ Refinement.private_instance_methods(true).should_not.include?(:extend_object)
end
it "is not called by Object#extend" do
@@ -13,7 +13,7 @@ describe "Refinement#extend_object" do
define_method(:extend_object) { called = true }
-> {
c.extend(self)
- }.should raise_error(TypeError)
+ }.should.raise(TypeError)
called.should == false
end
end
diff --git a/spec/ruby/core/refinement/import_methods_spec.rb b/spec/ruby/core/refinement/import_methods_spec.rb
index 13c0b1004c..bcb5e9b066 100644
--- a/spec/ruby/core/refinement/import_methods_spec.rb
+++ b/spec/ruby/core/refinement/import_methods_spec.rb
@@ -23,7 +23,7 @@ describe "Refinement#import_methods" do
refine String do
-> {
import_methods Integer
- }.should raise_error(TypeError, "wrong argument type Class (expected Module)")
+ }.should.raise(TypeError, "wrong argument type Class (expected Module)")
end
end
end
@@ -82,7 +82,7 @@ describe "Refinement#import_methods" do
refine String do
-> {
import_methods str_utils, Kernel
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
end
@@ -127,7 +127,7 @@ describe "Refinement#import_methods" do
using self
-> {
"foo".indent(3)
- }.should raise_error(NoMethodError, /undefined method [`']indent' for ("foo":String|an instance of String)/)
+ }.should.raise(NoMethodError, /undefined method [`']indent' for ("foo":String|an instance of String)/)
end
end
@@ -142,7 +142,7 @@ describe "Refinement#import_methods" do
refine String do
-> {
import_methods str_utils, Integer
- }.should raise_error(TypeError)
+ }.should.raise(TypeError)
end
end
@@ -150,7 +150,7 @@ describe "Refinement#import_methods" do
using string_refined
-> {
"foo".indent(3)
- }.should raise_error(NoMethodError)
+ }.should.raise(NoMethodError)
end
end
@@ -213,7 +213,7 @@ describe "Refinement#import_methods" do
using self
-> {
String.indent(3)
- }.should raise_error(NoMethodError, /undefined method [`']indent' for (String:Class|class String)/)
+ }.should.raise(NoMethodError, /undefined method [`']indent' for (String:Class|class String)/)
end
end
@@ -242,13 +242,33 @@ describe "Refinement#import_methods" do
end
end
+ it "correctly sets owner as the refinement module" do
+ str_utils = Module.new do
+ def indent(level)
+ " " * level + self
+ end
+ end
+
+ refinement = Module.new do
+ refine String do
+ import_methods str_utils
+ end
+ end
+
+ Module.new do
+ using refinement
+
+ String.instance_method(:indent).owner.should == refinement.refinements.first
+ end
+ end
+
context "when methods are not defined in Ruby code" do
it "raises ArgumentError" do
Module.new do
refine String do
-> {
import_methods Kernel
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
end
end
@@ -259,7 +279,7 @@ describe "Refinement#import_methods" do
refine String do
-> {
import_methods Zlib
- }.should raise_error(ArgumentError, /Can't import method which is not defined with Ruby code: Zlib#*/)
+ }.should.raise(ArgumentError, /Can't import method which is not defined with Ruby code: Zlib#*/)
end
end
end
diff --git a/spec/ruby/core/refinement/include_spec.rb b/spec/ruby/core/refinement/include_spec.rb
index 57451bd9bc..55ac89ffb5 100644
--- a/spec/ruby/core/refinement/include_spec.rb
+++ b/spec/ruby/core/refinement/include_spec.rb
@@ -6,7 +6,7 @@ describe "Refinement#include" do
refine String do
-> {
include Module.new
- }.should raise_error(TypeError, "Refinement#include has been removed")
+ }.should.raise(TypeError, "Refinement#include has been removed")
end
end
end
diff --git a/spec/ruby/core/refinement/prepend_features_spec.rb b/spec/ruby/core/refinement/prepend_features_spec.rb
index fbc431bbd2..9dc5838f1f 100644
--- a/spec/ruby/core/refinement/prepend_features_spec.rb
+++ b/spec/ruby/core/refinement/prepend_features_spec.rb
@@ -2,7 +2,7 @@ require_relative '../../spec_helper'
describe "Refinement#prepend_features" do
it "is not defined" do
- Refinement.should_not have_private_instance_method(:prepend_features)
+ Refinement.private_instance_methods(true).should_not.include?(:prepend_features)
end
it "is not called by Module#prepend" do
@@ -11,7 +11,7 @@ describe "Refinement#prepend_features" do
refine c do
called = false
define_method(:prepend_features){called = true}
- proc{c.prepend(self)}.should raise_error(TypeError)
+ proc{c.prepend(self)}.should.raise(TypeError)
called.should == false
end
end
diff --git a/spec/ruby/core/refinement/prepend_spec.rb b/spec/ruby/core/refinement/prepend_spec.rb
index 64cf7cd17f..fd70dd6f97 100644
--- a/spec/ruby/core/refinement/prepend_spec.rb
+++ b/spec/ruby/core/refinement/prepend_spec.rb
@@ -6,7 +6,7 @@ describe "Refinement#prepend" do
refine String do
-> {
prepend Module.new
- }.should raise_error(TypeError, "Refinement#prepend has been removed")
+ }.should.raise(TypeError, "Refinement#prepend has been removed")
end
end
end
diff --git a/spec/ruby/core/refinement/refined_class_spec.rb b/spec/ruby/core/refinement/refined_class_spec.rb
index 60a58380cc..90f8d963d8 100644
--- a/spec/ruby/core/refinement/refined_class_spec.rb
+++ b/spec/ruby/core/refinement/refined_class_spec.rb
@@ -1,12 +1,7 @@
require_relative "../../spec_helper"
-require_relative 'shared/target'
describe "Refinement#refined_class" do
- ruby_version_is ""..."3.3" do
- it_behaves_like :refinement_target, :refined_class
- end
-
- ruby_version_is "3.3"..."3.4" do
+ ruby_version_is ""..."3.4" do
it "has been deprecated in favour of Refinement#target" do
refinement_int = nil
diff --git a/spec/ruby/core/refinement/shared/target.rb b/spec/ruby/core/refinement/shared/target.rb
deleted file mode 100644
index 79557bea0b..0000000000
--- a/spec/ruby/core/refinement/shared/target.rb
+++ /dev/null
@@ -1,13 +0,0 @@
-describe :refinement_target, shared: true 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.send(@method).should == Integer
- end
-end
diff --git a/spec/ruby/core/refinement/target_spec.rb b/spec/ruby/core/refinement/target_spec.rb
index fee9588a96..eaee71e8c6 100644
--- a/spec/ruby/core/refinement/target_spec.rb
+++ b/spec/ruby/core/refinement/target_spec.rb
@@ -1,8 +1,15 @@
require_relative "../../spec_helper"
-require_relative 'shared/target'
describe "Refinement#target" do
- ruby_version_is "3.3" do
- it_behaves_like :refinement_target, :target
+ 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.target.should == Integer
end
end
diff --git a/spec/ruby/core/regexp/case_compare_spec.rb b/spec/ruby/core/regexp/case_compare_spec.rb
index 5ae8b56c6a..29aada70bc 100644
--- a/spec/ruby/core/regexp/case_compare_spec.rb
+++ b/spec/ruby/core/regexp/case_compare_spec.rb
@@ -2,25 +2,25 @@ require_relative '../../spec_helper'
describe "Regexp#===" do
it "is true if there is a match" do
- (/abc/ === "aabcc").should be_true
+ (/abc/ === "aabcc").should == true
end
it "is false if there is no match" do
- (/abc/ === "xyz").should be_false
+ (/abc/ === "xyz").should == false
end
it "returns true if it matches a Symbol" do
- (/a/ === :a).should be_true
+ (/a/ === :a).should == true
end
it "returns false if it does not match a Symbol" do
- (/a/ === :b).should be_false
+ (/a/ === :b).should == false
end
# mirroring https://github.com/ruby/ruby/blob/master/test/ruby/test_regexp.rb
it "returns false if the other value cannot be coerced to a string" do
- (/abc/ === nil).should be_false
- (/abc/ === /abc/).should be_false
+ (/abc/ === nil).should == false
+ (/abc/ === /abc/).should == false
end
it "uses #to_str on string-like objects" do
@@ -30,6 +30,6 @@ describe "Regexp#===" do
end
end.new
- (/abc/ === stringlike).should be_true
+ (/abc/ === stringlike).should == true
end
end
diff --git a/spec/ruby/core/regexp/compile_spec.rb b/spec/ruby/core/regexp/compile_spec.rb
index c41399cfbb..887c8d77dc 100644
--- a/spec/ruby/core/regexp/compile_spec.rb
+++ b/spec/ruby/core/regexp/compile_spec.rb
@@ -14,6 +14,6 @@ describe "Regexp.compile given a Regexp" do
it_behaves_like :regexp_new_regexp, :compile
end
-describe "Regexp.new given a non-String/Regexp" do
+describe "Regexp.compile given a non-String/Regexp" do
it_behaves_like :regexp_new_non_string_or_regexp, :compile
end
diff --git a/spec/ruby/core/regexp/encoding_spec.rb b/spec/ruby/core/regexp/encoding_spec.rb
index dfc835b4e4..fb4fdba064 100644
--- a/spec/ruby/core/regexp/encoding_spec.rb
+++ b/spec/ruby/core/regexp/encoding_spec.rb
@@ -3,7 +3,7 @@ require_relative '../../spec_helper'
describe "Regexp#encoding" do
it "returns an Encoding object" do
- /glar/.encoding.should be_an_instance_of(Encoding)
+ /glar/.encoding.should.instance_of?(Encoding)
end
it "defaults to US-ASCII if the Regexp contains only US-ASCII character" do
diff --git a/spec/ruby/core/regexp/eql_spec.rb b/spec/ruby/core/regexp/eql_spec.rb
index bd5ae43eb2..5924333fbd 100644
--- a/spec/ruby/core/regexp/eql_spec.rb
+++ b/spec/ruby/core/regexp/eql_spec.rb
@@ -1,6 +1,7 @@
require_relative '../../spec_helper'
-require_relative 'shared/equal_value'
describe "Regexp#eql?" do
- it_behaves_like :regexp_eql, :eql?
+ it "is an alias of Regexp#==" do
+ Regexp.instance_method(:eql?).should == Regexp.instance_method(:==)
+ end
end
diff --git a/spec/ruby/core/regexp/equal_value_spec.rb b/spec/ruby/core/regexp/equal_value_spec.rb
index 5455a30598..ad8dc33222 100644
--- a/spec/ruby/core/regexp/equal_value_spec.rb
+++ b/spec/ruby/core/regexp/equal_value_spec.rb
@@ -1,6 +1,33 @@
require_relative '../../spec_helper'
-require_relative 'shared/equal_value'
describe "Regexp#==" do
- it_behaves_like :regexp_eql, :==
+ it "is true if self and other have the same pattern" do
+ (/abc/ == /abc/).should == true
+ (/abc/ == /abd/).should == false
+ end
+
+ not_supported_on :opal do
+ it "is true if self and other have the same character set code" do
+ (/abc/ == /abc/x).should == false
+ (/abc/x == /abc/x).should == true
+ (/abc/u == /abc/n).should == false
+ (/abc/u == /abc/u).should == true
+ (/abc/n == /abc/n).should == true
+ end
+ end
+
+ it "is true if other has the same #casefold? values" do
+ (/abc/ == /abc/i).should == false
+ (/abc/i == /abc/i).should == true
+ end
+
+ not_supported_on :opal do
+ it "is true if self does not specify /n option and other does" do
+ (// == //n).should == true
+ end
+
+ it "is true if self specifies /n option and other does not" do
+ (//n == //).should == true
+ end
+ end
end
diff --git a/spec/ruby/core/regexp/escape_spec.rb b/spec/ruby/core/regexp/escape_spec.rb
index 6b06ab1cbc..99e5eb71d6 100644
--- a/spec/ruby/core/regexp/escape_spec.rb
+++ b/spec/ruby/core/regexp/escape_spec.rb
@@ -1,6 +1,7 @@
require_relative '../../spec_helper'
-require_relative 'shared/quote'
describe "Regexp.escape" do
- it_behaves_like :regexp_quote, :escape
+ it "is an alias of Regexp.quote" do
+ Regexp.method(:escape).should == Regexp.method(:quote)
+ end
end
diff --git a/spec/ruby/core/regexp/fixed_encoding_spec.rb b/spec/ruby/core/regexp/fixed_encoding_spec.rb
index 29d0a22c53..5d8b1c2860 100644
--- a/spec/ruby/core/regexp/fixed_encoding_spec.rb
+++ b/spec/ruby/core/regexp/fixed_encoding_spec.rb
@@ -3,34 +3,34 @@ require_relative '../../spec_helper'
describe "Regexp#fixed_encoding?" do
it "returns false by default" do
- /needle/.fixed_encoding?.should be_false
+ /needle/.fixed_encoding?.should == false
end
it "returns false if the 'n' modifier was supplied to the Regexp" do
- /needle/n.fixed_encoding?.should be_false
+ /needle/n.fixed_encoding?.should == false
end
it "returns true if the 'u' modifier was supplied to the Regexp" do
- /needle/u.fixed_encoding?.should be_true
+ /needle/u.fixed_encoding?.should == true
end
it "returns true if the 's' modifier was supplied to the Regexp" do
- /needle/s.fixed_encoding?.should be_true
+ /needle/s.fixed_encoding?.should == true
end
it "returns true if the 'e' modifier was supplied to the Regexp" do
- /needle/e.fixed_encoding?.should be_true
+ /needle/e.fixed_encoding?.should == true
end
it "returns true if the Regexp contains a \\u escape" do
- /needle \u{8768}/.fixed_encoding?.should be_true
+ /needle \u{8768}/.fixed_encoding?.should == true
end
it "returns true if the Regexp contains a UTF-8 literal" do
- /文字化ã‘/.fixed_encoding?.should be_true
+ /文字化ã‘/.fixed_encoding?.should == true
end
it "returns true if the Regexp was created with the Regexp::FIXEDENCODING option" do
- Regexp.new("", Regexp::FIXEDENCODING).fixed_encoding?.should be_true
+ Regexp.new("", Regexp::FIXEDENCODING).fixed_encoding?.should == true
end
end
diff --git a/spec/ruby/core/regexp/initialize_spec.rb b/spec/ruby/core/regexp/initialize_spec.rb
index dd57292242..1c0133acae 100644
--- a/spec/ruby/core/regexp/initialize_spec.rb
+++ b/spec/ruby/core/regexp/initialize_spec.rb
@@ -2,14 +2,28 @@ require_relative '../../spec_helper'
describe "Regexp#initialize" do
it "is a private method" do
- Regexp.should have_private_instance_method(:initialize)
+ Regexp.private_instance_methods(false).should.include?(:initialize)
end
it "raises a FrozenError on a Regexp literal" do
- -> { //.send(:initialize, "") }.should raise_error(FrozenError)
+ -> { //.send(:initialize, "") }.should.raise(FrozenError)
end
- it "raises a TypeError on an initialized non-literal Regexp" do
- -> { Regexp.new("").send(:initialize, "") }.should raise_error(TypeError)
+ ruby_version_is "4.1" do
+ it "raises a FrozenError on an initialized non-literal Regexp" do
+ regexp = Regexp.new("")
+ -> { regexp.send(:initialize, "") }.should.raise(FrozenError)
+ end
+ end
+
+ ruby_version_is ""..."4.1" do
+ it "raises a TypeError on an initialized non-literal Regexp" do
+ -> { Regexp.new("").send(:initialize, "") }.should.raise(TypeError)
+ end
+ end
+
+ it "raises a TypeError on an initialized non-literal Regexp subclass" do
+ r = Class.new(Regexp).new("")
+ -> { r.send(:initialize, "") }.should.raise(TypeError)
end
end
diff --git a/spec/ruby/core/regexp/last_match_spec.rb b/spec/ruby/core/regexp/last_match_spec.rb
index 0bfed32051..6c256cc1cf 100644
--- a/spec/ruby/core/regexp/last_match_spec.rb
+++ b/spec/ruby/core/regexp/last_match_spec.rb
@@ -4,7 +4,7 @@ describe "Regexp.last_match" do
it "returns MatchData instance when not passed arguments" do
/c(.)t/ =~ 'cat'
- Regexp.last_match.should be_kind_of(MatchData)
+ Regexp.last_match.should.is_a?(MatchData)
end
it "returns the nth field in this MatchData when passed an Integer" do
@@ -28,7 +28,7 @@ describe "Regexp.last_match" do
it "raises an IndexError when given a missing name" do
/(?<test>[A-Z]+.*)/ =~ "TEST123"
- -> { Regexp.last_match(:missing) }.should raise_error(IndexError)
+ -> { Regexp.last_match(:missing) }.should.raise(IndexError)
end
end
@@ -50,7 +50,7 @@ describe "Regexp.last_match" do
it "raises a TypeError when unable to coerce" do
obj = Object.new
/(?<test>[A-Z]+.*)/ =~ "TEST123"
- -> { Regexp.last_match(obj) }.should raise_error(TypeError)
+ -> { Regexp.last_match(obj) }.should.raise(TypeError)
end
end
end
diff --git a/spec/ruby/core/regexp/linear_time_spec.rb b/spec/ruby/core/regexp/linear_time_spec.rb
index c3b3500549..f70021dfed 100644
--- a/spec/ruby/core/regexp/linear_time_spec.rb
+++ b/spec/ruby/core/regexp/linear_time_spec.rb
@@ -24,4 +24,57 @@ describe "Regexp.linear_time?" do
Regexp.linear_time?(/a/, Regexp::IGNORECASE)
}.should complain(/warning: flags ignored/)
end
+
+ it "returns true for positive lookahead" do
+ Regexp.linear_time?(/a*(?:(?=a*)a)*b/).should == true
+ end
+
+ it "returns true for positive lookbehind" do
+ Regexp.linear_time?(/a*(?:(?<=a)a*)*b/).should == true
+ end
+
+ it "returns true for negative lookbehind" do
+ Regexp.linear_time?(/a*(?:(?<!a)a*)*b/).should == true
+ end
+
+ # There are two known ways to make Regexp linear:
+ # * Using a DFA (deterministic finite-state automaton) Regexp engine, which always matches in linear time (e.g. TruffleRuby with TRegex)
+ # * Caching position and state to avoid catastrophic backtracking (e.g. CRuby: https://bugs.ruby-lang.org/issues/19104)
+ #
+ # Both approach should be allowed and given that DFA Regexp engines
+ # are much faster there should be no specs preventing using them.
+ uses_regexp_caching = RUBY_ENGINE == 'ruby'
+ uses_dfa_regexp_engine = !uses_regexp_caching
+
+ # The following specs should not be relied upon,
+ # they are here only to illustrate differences between Regexp engines.
+ guard -> { uses_regexp_caching } do
+ it "returns true for negative lookahead" do
+ Regexp.linear_time?(/a*(?:(?!a*)a*)*b/).should == true
+ end
+
+ it "returns true for atomic groups" do
+ Regexp.linear_time?(/a*(?:(?>a)a*)*b/).should == true
+ end
+
+ it "returns true for possessive quantifiers" do
+ Regexp.linear_time?(/a*(?:(?:a)?+a*)*b/).should == true
+ end
+
+ it "returns true for positive lookbehind with capture group" do
+ Regexp.linear_time?(/.(?<=(a))/).should == true
+ end
+ end
+
+ # The following specs should not be relied upon,
+ # they are here only to illustrate differences between Regexp engines.
+ guard -> { uses_dfa_regexp_engine } do
+ it "returns true for non-recursive subexpression call" do
+ Regexp.linear_time?(/(?<a>a){0}\g<a>/).should == true
+ end
+
+ it "returns true for positive lookahead with capture group" do
+ Regexp.linear_time?(/x+(?=(a))/).should == true
+ end
+ end
end
diff --git a/spec/ruby/core/regexp/match_spec.rb b/spec/ruby/core/regexp/match_spec.rb
index 80dbfb4c10..276cecc8e4 100644
--- a/spec/ruby/core/regexp/match_spec.rb
+++ b/spec/ruby/core/regexp/match_spec.rb
@@ -3,11 +3,11 @@ require_relative '../../spec_helper'
describe :regexp_match, shared: true do
it "returns nil if there is no match" do
- /xyz/.send(@method,"abxyc").should be_nil
+ /xyz/.send(@method,"abxyc").should == nil
end
it "returns nil if the object is nil" do
- /\w+/.send(@method, nil).should be_nil
+ /\w+/.send(@method, nil).should == nil
end
end
@@ -27,19 +27,19 @@ describe "Regexp#match" do
it_behaves_like :regexp_match, :match
it "returns a MatchData object" do
- /(.)(.)(.)/.match("abc").should be_kind_of(MatchData)
+ /(.)(.)(.)/.match("abc").should.is_a?(MatchData)
end
it "returns a MatchData object, when argument is a Symbol" do
- /(.)(.)(.)/.match(:abc).should be_kind_of(MatchData)
+ /(.)(.)(.)/.match(:abc).should.is_a?(MatchData)
end
it "raises a TypeError on an uninitialized Regexp" do
- -> { Regexp.allocate.match('foo') }.should raise_error(TypeError)
+ -> { Regexp.allocate.match('foo') }.should.raise(TypeError)
end
it "raises TypeError on an uninitialized Regexp" do
- -> { Regexp.allocate.match('foo'.encode("UTF-16LE")) }.should raise_error(TypeError)
+ -> { Regexp.allocate.match('foo'.encode("UTF-16LE")) }.should.raise(TypeError)
end
describe "with [string, position]" do
@@ -54,7 +54,7 @@ describe "Regexp#match" do
it "raises an ArgumentError for an invalid encoding" do
x96 = ([150].pack('C')).force_encoding('utf-8')
- -> { /(.).(.)/.match("Hello, #{x96} world!", 1) }.should raise_error(ArgumentError)
+ -> { /(.).(.)/.match("Hello, #{x96} world!", 1) }.should.raise(ArgumentError)
end
end
@@ -69,14 +69,14 @@ describe "Regexp#match" do
it "raises an ArgumentError for an invalid encoding" do
x96 = ([150].pack('C')).force_encoding('utf-8')
- -> { /(.).(.)/.match("Hello, #{x96} world!", -1) }.should raise_error(ArgumentError)
+ -> { /(.).(.)/.match("Hello, #{x96} world!", -1) }.should.raise(ArgumentError)
end
end
describe "when passed a block" do
it "yields the MatchData" do
/./.match("abc") {|m| ScratchPad.record m }
- ScratchPad.recorded.should be_kind_of(MatchData)
+ ScratchPad.recorded.should.is_a?(MatchData)
end
it "returns the block result" do
@@ -94,20 +94,20 @@ describe "Regexp#match" do
it "resets $~ if passed nil" do
# set $~
/./.match("a")
- $~.should be_kind_of(MatchData)
+ $~.should.is_a?(MatchData)
/1/.match(nil)
- $~.should be_nil
+ $~.should == nil
end
it "raises TypeError when the given argument cannot be coerced to String" do
f = 1
- -> { /foo/.match(f)[0] }.should raise_error(TypeError)
+ -> { /foo/.match(f)[0] }.should.raise(TypeError)
end
it "raises TypeError when the given argument is an Exception" do
f = Exception.new("foo")
- -> { /foo/.match(f)[0] }.should raise_error(TypeError)
+ -> { /foo/.match(f)[0] }.should.raise(TypeError)
end
end
@@ -119,22 +119,22 @@ describe "Regexp#match?" do
context "when matches the given value" do
it "returns true but does not set Regexp.last_match" do
- /string/i.match?('string').should be_true
- Regexp.last_match.should be_nil
+ /string/i.match?('string').should == true
+ Regexp.last_match.should == nil
end
end
it "returns false when does not match the given value" do
- /STRING/.match?('string').should be_false
+ /STRING/.match?('string').should == false
end
it "takes matching position as the 2nd argument" do
- /str/i.match?('string', 0).should be_true
- /str/i.match?('string', 1).should be_false
+ /str/i.match?('string', 0).should == true
+ /str/i.match?('string', 1).should == false
end
it "returns false when given nil" do
- /./.match?(nil).should be_false
+ /./.match?(nil).should == false
end
end
diff --git a/spec/ruby/core/regexp/named_captures_spec.rb b/spec/ruby/core/regexp/named_captures_spec.rb
index 1a68d7877b..4d3fdd23ab 100644
--- a/spec/ruby/core/regexp/named_captures_spec.rb
+++ b/spec/ruby/core/regexp/named_captures_spec.rb
@@ -2,7 +2,7 @@ require_relative '../../spec_helper'
describe "Regexp#named_captures" do
it "returns a Hash" do
- /foo/.named_captures.should be_an_instance_of(Hash)
+ /foo/.named_captures.should.instance_of?(Hash)
end
it "returns an empty Hash when there are no capture groups" do
@@ -17,7 +17,7 @@ describe "Regexp#named_captures" do
it "sets the values of the Hash to Arrays" do
rex = /this (?<is>is) [aA] (?<pat>pate?rn)/
rex.named_captures.values.each do |value|
- value.should be_an_instance_of(Array)
+ value.should.instance_of?(Array)
end
end
diff --git a/spec/ruby/core/regexp/names_spec.rb b/spec/ruby/core/regexp/names_spec.rb
index 099768fd26..9013f41e20 100644
--- a/spec/ruby/core/regexp/names_spec.rb
+++ b/spec/ruby/core/regexp/names_spec.rb
@@ -2,7 +2,7 @@ require_relative '../../spec_helper'
describe "Regexp#names" do
it "returns an Array" do
- /foo/.names.should be_an_instance_of(Array)
+ /foo/.names.should.instance_of?(Array)
end
it "returns an empty Array if there are no named captures" do
@@ -11,7 +11,7 @@ describe "Regexp#names" do
it "returns each named capture as a String" do
/n(?<cap>ee)d(?<ture>le)/.names.each do |name|
- name.should be_an_instance_of(String)
+ name.should.instance_of?(String)
end
end
diff --git a/spec/ruby/core/regexp/new_spec.rb b/spec/ruby/core/regexp/new_spec.rb
index 65f612df55..79210e9a23 100644
--- a/spec/ruby/core/regexp/new_spec.rb
+++ b/spec/ruby/core/regexp/new_spec.rb
@@ -7,11 +7,11 @@ end
describe "Regexp.new given a String" do
it_behaves_like :regexp_new_string, :new
+ it_behaves_like :regexp_new_string_binary, :new
end
describe "Regexp.new given a Regexp" do
it_behaves_like :regexp_new_regexp, :new
- it_behaves_like :regexp_new_string_binary, :new
end
describe "Regexp.new given a non-String/Regexp" do
diff --git a/spec/ruby/core/regexp/options_spec.rb b/spec/ruby/core/regexp/options_spec.rb
index 527b51a3b2..c3401cee6e 100644
--- a/spec/ruby/core/regexp/options_spec.rb
+++ b/spec/ruby/core/regexp/options_spec.rb
@@ -2,9 +2,9 @@ require_relative '../../spec_helper'
describe "Regexp#options" do
it "returns an Integer bitvector of regexp options for the Regexp object" do
- /cat/.options.should be_kind_of(Integer)
+ /cat/.options.should.is_a?(Integer)
not_supported_on :opal do
- /cat/ix.options.should be_kind_of(Integer)
+ /cat/ix.options.should.is_a?(Integer)
end
end
@@ -29,7 +29,7 @@ describe "Regexp#options" do
end
it "raises a TypeError on an uninitialized Regexp" do
- -> { Regexp.allocate.options }.should raise_error(TypeError)
+ -> { Regexp.allocate.options }.should.raise(TypeError)
end
it "includes Regexp::FIXEDENCODING for a Regexp literal with the 'u' option" do
diff --git a/spec/ruby/core/regexp/quote_spec.rb b/spec/ruby/core/regexp/quote_spec.rb
index 370ab13e30..27fa0c0669 100644
--- a/spec/ruby/core/regexp/quote_spec.rb
+++ b/spec/ruby/core/regexp/quote_spec.rb
@@ -1,6 +1,43 @@
+# encoding: binary
+
require_relative '../../spec_helper'
-require_relative 'shared/quote'
describe "Regexp.quote" do
- it_behaves_like :regexp_quote, :quote
+ it "escapes any characters with special meaning in a regular expression" do
+ Regexp.quote('\*?{}.+^$[]()- ').should == '\\\\\*\?\{\}\.\+\^\$\[\]\(\)\-\\ '
+ Regexp.quote("\*?{}.+^$[]()- ").should == '\\*\\?\\{\\}\\.\\+\\^\\$\\[\\]\\(\\)\\-\\ '
+ Regexp.quote('\n\r\f\t').should == '\\\\n\\\\r\\\\f\\\\t'
+ Regexp.quote("\n\r\f\t").should == '\\n\\r\\f\\t'
+ end
+
+ it "works with symbols" do
+ Regexp.quote(:symbol).should == 'symbol'
+ end
+
+ it "works with substrings" do
+ str = ".+[]()"[1...-1]
+ Regexp.quote(str).should == '\+\[\]\('
+ end
+
+ it "works for broken strings" do
+ Regexp.quote("a.\x85b.".dup.force_encoding("US-ASCII")).should =="a\\.\x85b\\.".dup.force_encoding("US-ASCII")
+ Regexp.quote("a.\x80".dup.force_encoding("UTF-8")).should == "a\\.\x80".dup.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")
+ Regexp.quote(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.valid_encoding?.should == true
+ Regexp.quote(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.valid_encoding?.should == false
+ Regexp.quote("\xff").encoding.should == Encoding::BINARY
+ end
end
diff --git a/spec/ruby/core/regexp/shared/equal_value.rb b/spec/ruby/core/regexp/shared/equal_value.rb
deleted file mode 100644
index 803988de9e..0000000000
--- a/spec/ruby/core/regexp/shared/equal_value.rb
+++ /dev/null
@@ -1,31 +0,0 @@
-describe :regexp_eql, shared: true do
- it "is true if self and other have the same pattern" do
- /abc/.send(@method, /abc/).should == true
- /abc/.send(@method, /abd/).should == false
- end
-
- not_supported_on :opal do
- it "is true if self and other have the same character set code" do
- /abc/.send(@method, /abc/x).should == false
- /abc/x.send(@method, /abc/x).should == true
- /abc/u.send(@method, /abc/n).should == false
- /abc/u.send(@method, /abc/u).should == true
- /abc/n.send(@method, /abc/n).should == true
- end
- end
-
- it "is true if other has the same #casefold? values" do
- /abc/.send(@method, /abc/i).should == false
- /abc/i.send(@method, /abc/i).should == true
- end
-
- not_supported_on :opal do
- it "is true if self does not specify /n option and other does" do
- //.send(@method, //n).should == true
- end
-
- it "is true if self specifies /n option and other does not" do
- //n.send(@method, //).should == true
- end
- end
-end
diff --git a/spec/ruby/core/regexp/shared/new.rb b/spec/ruby/core/regexp/shared/new.rb
index 921736d299..affdaf855c 100644
--- a/spec/ruby/core/regexp/shared/new.rb
+++ b/spec/ruby/core/regexp/shared/new.rb
@@ -5,6 +5,12 @@ describe :regexp_new, shared: true do
Regexp.send(@method, '').is_a?(Regexp).should == true
end
+ ruby_version_is "4.1" do
+ it "is frozen" do
+ Regexp.send(@method, '').should.frozen?
+ end
+ end
+
it "works by default for subclasses with overridden #initialize" do
class RegexpSpecsSubclass < Regexp
def initialize(*args)
@@ -17,10 +23,10 @@ describe :regexp_new, shared: true do
class RegexpSpecsSubclassTwo < Regexp; end
- RegexpSpecsSubclass.send(@method, "hi").should be_kind_of(RegexpSpecsSubclass)
+ RegexpSpecsSubclass.send(@method, "hi").should.is_a?(RegexpSpecsSubclass)
RegexpSpecsSubclass.send(@method, "hi").args.first.should == "hi"
- RegexpSpecsSubclassTwo.send(@method, "hi").should be_kind_of(RegexpSpecsSubclassTwo)
+ RegexpSpecsSubclassTwo.send(@method, "hi").should.is_a?(RegexpSpecsSubclassTwo)
end
end
@@ -34,19 +40,19 @@ describe :regexp_new_non_string_or_regexp, shared: true do
it "raises TypeError if there is no #to_str method for non-String/Regexp argument" do
obj = Object.new
- -> { Regexp.send(@method, obj) }.should raise_error(TypeError, "no implicit conversion of Object into String")
+ -> { Regexp.send(@method, obj) }.should.raise(TypeError, "no implicit conversion of Object into String")
- -> { Regexp.send(@method, 1) }.should raise_error(TypeError, "no implicit conversion of Integer into String")
- -> { Regexp.send(@method, 1.0) }.should raise_error(TypeError, "no implicit conversion of Float into String")
- -> { Regexp.send(@method, :symbol) }.should raise_error(TypeError, "no implicit conversion of Symbol into String")
- -> { Regexp.send(@method, []) }.should raise_error(TypeError, "no implicit conversion of Array into String")
+ -> { Regexp.send(@method, 1) }.should.raise(TypeError, "no implicit conversion of Integer into String")
+ -> { Regexp.send(@method, 1.0) }.should.raise(TypeError, "no implicit conversion of Float into String")
+ -> { Regexp.send(@method, :symbol) }.should.raise(TypeError, "no implicit conversion of Symbol into String")
+ -> { Regexp.send(@method, []) }.should.raise(TypeError, "no implicit conversion of Array into String")
end
it "raises TypeError if #to_str returns non-String value" do
obj = Object.new
def obj.to_str() [] end
- -> { Regexp.send(@method, obj) }.should raise_error(TypeError, /can't convert Object to String/)
+ -> { Regexp.send(@method, obj) }.should raise_consistent_error(TypeError, /can't convert Object into String/)
end
end
@@ -56,7 +62,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(RegexpError, Regexp.new(Regexp.escape("premature end of char-class: /^[$/")))
end
it "does not set Regexp options if only given one argument" do
@@ -178,221 +184,45 @@ 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(ArgumentError, "unknown regexp option: e")
+ -> { Regexp.send(@method, 'Hi', 'n') }.should.raise(ArgumentError, "unknown regexp option: n")
+ -> { Regexp.send(@method, 'Hi', 's') }.should.raise(ArgumentError, "unknown regexp option: s")
+ -> { Regexp.send(@method, 'Hi', 'u') }.should.raise(ArgumentError, "unknown regexp option: u")
+ -> { Regexp.send(@method, 'Hi', 'j') }.should.raise(ArgumentError, "unknown regexp option: j")
+ -> { Regexp.send(@method, 'Hi', 'mjx') }.should.raise(ArgumentError, /unknown regexp option: mjx\b/)
end
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(RegexpError, Regexp.new(Regexp.escape("too short escape sequence: /\\/")))
end
it "does not raise a Regexp error if there is an escaped trailing backslash" do
- -> { Regexp.send(@method, "\\\\") }.should_not raise_error(RegexpError)
+ -> { Regexp.send(@method, "\\\\") }.should_not.raise(RegexpError)
end
- it "accepts a backspace followed by a character" do
+ it "accepts a backspace followed by a non-special character" do
Regexp.send(@method, "\\N").should == /#{"\x5c"+"N"}/
end
- it "accepts a one-digit octal value" do
- Regexp.send(@method, "\0").should == /#{"\x00"}/
- end
-
- it "accepts a two-digit octal value" do
- Regexp.send(@method, "\11").should == /#{"\x09"}/
- end
-
- it "accepts a one-digit hexadecimal value" do
- Regexp.send(@method, "\x9n").should == /#{"\x09n"}/
- end
-
- it "accepts a two-digit hexadecimal value" do
- Regexp.send(@method, "\x23").should == /#{"\x23"}/
- end
-
- it "interprets a digit following a two-digit hexadecimal value as a character" do
- Regexp.send(@method, "\x420").should == /#{"\x420"}/
- 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/")))
- end
-
- it "accepts an escaped string interpolation" do
- Regexp.send(@method, "\#{abc}").should == /#{"\#{abc}"}/
- end
-
- it "accepts '\\n'" do
- Regexp.send(@method, "\n").should == /#{"\x0a"}/
- end
-
- it "accepts '\\t'" do
- Regexp.send(@method, "\t").should == /#{"\x09"}/
- end
-
- it "accepts '\\r'" do
- Regexp.send(@method, "\r").should == /#{"\x0d"}/
- end
-
- it "accepts '\\f'" do
- Regexp.send(@method, "\f").should == /#{"\x0c"}/
- end
-
- it "accepts '\\v'" do
- Regexp.send(@method, "\v").should == /#{"\x0b"}/
- end
-
- it "accepts '\\a'" do
- Regexp.send(@method, "\a").should == /#{"\x07"}/
- end
-
- it "accepts '\\e'" do
- Regexp.send(@method, "\e").should == /#{"\x1b"}/
- end
-
- it "accepts '\\C-\\n'" do
- Regexp.send(@method, "\C-\n").should == /#{"\x0a"}/
- end
-
- it "accepts '\\C-\\t'" do
- Regexp.send(@method, "\C-\t").should == /#{"\x09"}/
- end
-
- it "accepts '\\C-\\r'" do
- Regexp.send(@method, "\C-\r").should == /#{"\x0d"}/
- end
-
- it "accepts '\\C-\\f'" do
- Regexp.send(@method, "\C-\f").should == /#{"\x0c"}/
- end
-
- it "accepts '\\C-\\v'" do
- Regexp.send(@method, "\C-\v").should == /#{"\x0b"}/
- end
-
- it "accepts '\\C-\\a'" do
- Regexp.send(@method, "\C-\a").should == /#{"\x07"}/
- end
-
- it "accepts '\\C-\\e'" do
- Regexp.send(@method, "\C-\e").should == /#{"\x1b"}/
- end
-
- it "accepts multiple consecutive '\\' characters" do
- Regexp.send(@method, "\\\\\\N").should == /#{"\\\\\\"+"N"}/
- end
-
- it "accepts characters and escaped octal digits" do
- Regexp.send(@method, "abc\076").should == /#{"abc\x3e"}/
- end
-
- it "accepts escaped octal digits and characters" do
- Regexp.send(@method, "\076abc").should == /#{"\x3eabc"}/
- end
-
- it "accepts characters and escaped hexadecimal digits" do
- Regexp.send(@method, "abc\x42").should == /#{"abc\x42"}/
- end
-
- it "accepts escaped hexadecimal digits and characters" do
- Regexp.send(@method, "\x3eabc").should == /#{"\x3eabc"}/
- end
-
- it "accepts escaped hexadecimal and octal digits" do
- Regexp.send(@method, "\061\x42").should == /#{"\x31\x42"}/
- end
-
- it "accepts \\u{H} for a single Unicode codepoint" do
- Regexp.send(@method, "\u{f}").should == /#{"\x0f"}/
- end
-
- it "accepts \\u{HH} for a single Unicode codepoint" do
- Regexp.send(@method, "\u{7f}").should == /#{"\x7f"}/
- end
-
- it "accepts \\u{HHH} for a single Unicode codepoint" do
- Regexp.send(@method, "\u{07f}").should == /#{"\x7f"}/
- end
-
- it "accepts \\u{HHHH} for a single Unicode codepoint" do
- Regexp.send(@method, "\u{0000}").should == /#{"\x00"}/
- end
-
- it "accepts \\u{HHHHH} for a single Unicode codepoint" do
- Regexp.send(@method, "\u{00001}").should == /#{"\x01"}/
- end
-
- it "accepts \\u{HHHHHH} for a single Unicode codepoint" do
- Regexp.send(@method, "\u{000000}").should == /#{"\x00"}/
- end
-
- it "accepts characters followed by \\u{HHHH}" do
- Regexp.send(@method, "abc\u{3042}").should == /#{"abc\u3042"}/
- end
-
- it "accepts \\u{HHHH} followed by characters" do
- Regexp.send(@method, "\u{3042}abc").should == /#{"\u3042abc"}/
- end
-
- it "accepts escaped hexadecimal digits followed by \\u{HHHH}" do
- Regexp.send(@method, "\x42\u{3042}").should == /#{"\x42\u3042"}/
- end
-
- it "accepts escaped octal digits followed by \\u{HHHH}" do
- Regexp.send(@method, "\056\u{3042}").should == /#{"\x2e\u3042"}/
- end
-
- it "accepts a combination of escaped octal and hexadecimal digits and \\u{HHHH}" do
- Regexp.send(@method, "\056\x42\u{3042}\x52\076").should == /#{"\x2e\x42\u3042\x52\x3e"}/
- end
-
- it "accepts \\uHHHH for a single Unicode codepoint" do
- Regexp.send(@method, "\u3042").should == /#{"\u3042"}/
- end
-
- it "accepts characters followed by \\uHHHH" do
- Regexp.send(@method, "abc\u3042").should == /#{"abc\u3042"}/
- end
-
- it "accepts \\uHHHH followed by characters" do
- Regexp.send(@method, "\u3042abc").should == /#{"\u3042abc"}/
- end
-
- it "accepts escaped hexadecimal digits followed by \\uHHHH" do
- Regexp.send(@method, "\x42\u3042").should == /#{"\x42\u3042"}/
- end
-
- it "accepts escaped octal digits followed by \\uHHHH" do
- Regexp.send(@method, "\056\u3042").should == /#{"\x2e\u3042"}/
- end
-
- it "accepts a combination of escaped octal and hexadecimal digits and \\uHHHH" 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 == /#{"§"}/
+ -> { Regexp.send(@method, "\\" + "xn") }.should.raise(RegexpError, Regexp.new(Regexp.escape("invalid hex escape: /\\xn/")))
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(RegexpError, Regexp.new(Regexp.escape("invalid Unicode escape: /\\u304/")))
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(RegexpError, Regexp.new(Regexp.escape("invalid Unicode list: /\\u{}/")))
end
it "raises a RegexpError if the \\u{} escape contains non hexadecimal digits" do
- -> { Regexp.send(@method, "\\" + "u{abcX}") }.should raise_error(RegexpError, Regexp.new(Regexp.escape("invalid Unicode list: /\\u{abcX}/")))
+ -> { Regexp.send(@method, "\\" + "u{abcX}") }.should.raise(RegexpError, Regexp.new(Regexp.escape("invalid Unicode list: /\\u{abcX}/")))
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(RegexpError, Regexp.new(Regexp.escape("invalid Unicode range: /\\u{0ffffff}/")))
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
@@ -433,69 +263,6 @@ end
describe :regexp_new_string_binary, shared: true do
describe "with escaped characters" do
- it "accepts a three-digit octal value" do
- Regexp.send(@method, "\315").should == /#{"\xcd"}/
- end
-
- it "interprets a digit following a three-digit octal value as a character" do
- Regexp.send(@method, "\3762").should == /#{"\xfe2"}/
- end
-
- it "accepts '\\M-\\n'" do
- Regexp.send(@method, "\M-\n").should == /#{"\x8a"}/
- end
-
- it "accepts '\\M-\\t'" do
- Regexp.send(@method, "\M-\t").should == /#{"\x89"}/
- end
-
- it "accepts '\\M-\\r'" do
- Regexp.send(@method, "\M-\r").should == /#{"\x8d"}/
- end
-
- it "accepts '\\M-\\f'" do
- Regexp.send(@method, "\M-\f").should == /#{"\x8c"}/
- end
-
- it "accepts '\\M-\\v'" do
- Regexp.send(@method, "\M-\v").should == /#{"\x8b"}/
- end
-
- it "accepts '\\M-\\a'" do
- Regexp.send(@method, "\M-\a").should == /#{"\x87"}/
- end
-
- it "accepts '\\M-\\e'" do
- Regexp.send(@method, "\M-\e").should == /#{"\x9b"}/
- end
-
- it "accepts '\\M-\\C-\\n'" do
- Regexp.send(@method, "\M-\C-\n").should == /#{"\x8a"}/
- end
-
- it "accepts '\\M-\\C-\\t'" do
- Regexp.send(@method, "\M-\C-\t").should == /#{"\x89"}/
- end
-
- it "accepts '\\M-\\C-\\r'" do
- Regexp.send(@method, "\M-\C-\r").should == /#{"\x8d"}/
- end
-
- it "accepts '\\M-\\C-\\f'" do
- Regexp.send(@method, "\M-\C-\f").should == /#{"\x8c"}/
- end
-
- it "accepts '\\M-\\C-\\v'" do
- Regexp.send(@method, "\M-\C-\v").should == /#{"\x8b"}/
- end
-
- it "accepts '\\M-\\C-\\a'" do
- Regexp.send(@method, "\M-\C-\a").should == /#{"\x87"}/
- end
-
- it "accepts '\\M-\\C-\\e'" do
- Regexp.send(@method, "\M-\C-\e").should == /#{"\x9b"}/
- end
end
end
diff --git a/spec/ruby/core/regexp/shared/quote.rb b/spec/ruby/core/regexp/shared/quote.rb
deleted file mode 100644
index 3f46a18b5b..0000000000
--- a/spec/ruby/core/regexp/shared/quote.rb
+++ /dev/null
@@ -1,41 +0,0 @@
-# encoding: binary
-
-describe :regexp_quote, shared: true do
- it "escapes any characters with special meaning in a regular expression" do
- Regexp.send(@method, '\*?{}.+^$[]()- ').should == '\\\\\*\?\{\}\.\+\^\$\[\]\(\)\-\\ '
- Regexp.send(@method, "\*?{}.+^$[]()- ").should == '\\*\\?\\{\\}\\.\\+\\^\\$\\[\\]\\(\\)\\-\\ '
- Regexp.send(@method, '\n\r\f\t').should == '\\\\n\\\\r\\\\f\\\\t'
- Regexp.send(@method, "\n\r\f\t").should == '\\n\\r\\f\\t'
- end
-
- it "works with symbols" do
- Regexp.send(@method, :symbol).should == 'symbol'
- end
-
- it "works with substrings" do
- str = ".+[]()"[1...-1]
- Regexp.send(@method, str).should == '\+\[\]\('
- 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")
- 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")
- 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.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.valid_encoding?.should be_false
- Regexp.send(@method, "\xff").encoding.should == Encoding::BINARY
- end
-end
diff --git a/spec/ruby/core/regexp/source_spec.rb b/spec/ruby/core/regexp/source_spec.rb
index 5f253da9ea..4eebf280f0 100644
--- a/spec/ruby/core/regexp/source_spec.rb
+++ b/spec/ruby/core/regexp/source_spec.rb
@@ -34,14 +34,14 @@ describe "Regexp#source" do
not_supported_on :opal do
it "has US-ASCII encoding when created from an ASCII-only \\u{} literal" do
re = /[\u{20}-\u{7E}]/
- re.source.encoding.should equal(Encoding::US_ASCII)
+ re.source.encoding.should.equal?(Encoding::US_ASCII)
end
end
not_supported_on :opal do
it "has UTF-8 encoding when created from a non-ASCII-only \\u{} literal" do
re = /[\u{20}-\u{7EE}]/
- re.source.encoding.should equal(Encoding::UTF_8)
+ re.source.encoding.should.equal?(Encoding::UTF_8)
end
end
end
diff --git a/spec/ruby/core/regexp/timeout_spec.rb b/spec/ruby/core/regexp/timeout_spec.rb
index c64103c82c..a1ec475ef3 100644
--- a/spec/ruby/core/regexp/timeout_spec.rb
+++ b/spec/ruby/core/regexp/timeout_spec.rb
@@ -17,7 +17,7 @@ describe "Regexp.timeout" do
-> {
# A typical ReDoS case
/^(a*)*$/ =~ "a" * 1000000 + "x"
- }.should raise_error(Regexp::TimeoutError, "regexp match timeout")
+ }.should.raise(Regexp::TimeoutError, "regexp match timeout")
end
it "raises Regexp::TimeoutError after timeout keyword value elapsed" do
@@ -28,6 +28,6 @@ describe "Regexp.timeout" do
-> {
re =~ "a" * 1000000 + "x"
- }.should raise_error(Regexp::TimeoutError, "regexp match timeout")
+ }.should.raise(Regexp::TimeoutError, "regexp match timeout")
end
end
diff --git a/spec/ruby/core/regexp/try_convert_spec.rb b/spec/ruby/core/regexp/try_convert_spec.rb
index e775dbe971..da5e10adce 100644
--- a/spec/ruby/core/regexp/try_convert_spec.rb
+++ b/spec/ruby/core/regexp/try_convert_spec.rb
@@ -9,7 +9,7 @@ describe "Regexp.try_convert" do
it "returns nil if given an argument that can't be converted to a Regexp" do
['', 'glark', [], Object.new, :pat].each do |arg|
- Regexp.try_convert(arg).should be_nil
+ Regexp.try_convert(arg).should == nil
end
end
@@ -22,6 +22,6 @@ describe "Regexp.try_convert" do
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)")
+ -> { Regexp.try_convert(obj) }.should raise_consistent_error(TypeError, "can't convert MockObject into 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..c0a9d12fed 100644
--- a/spec/ruby/core/regexp/union_spec.rb
+++ b/spec/ruby/core/regexp/union_spec.rb
@@ -75,83 +75,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(ArgumentError, 'incompatible encodings: UTF-16LE and UTF-16BE')
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(ArgumentError, 'incompatible encodings: UTF-16LE and UTF-16BE')
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(ArgumentError, 'incompatible encodings: UTF-8 and US-ASCII')
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(ArgumentError, 'incompatible encodings: UTF-8 and ISO-8859-1')
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(ArgumentError, 'incompatible encodings: ISO-8859-1 and UTF-8')
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(ArgumentError, /ASCII incompatible encoding: UTF-16LE|incompatible encodings: UTF-16LE and US-ASCII/)
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(ArgumentError, /ASCII incompatible encoding: UTF-16LE|incompatible encodings: UTF-16LE and US-ASCII/)
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(ArgumentError, /ASCII incompatible encoding: UTF-16LE|incompatible encodings: UTF-16LE and US-ASCII/)
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(ArgumentError, /ASCII incompatible encoding: UTF-16LE|incompatible encodings: UTF-16LE and US-ASCII/)
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(ArgumentError, 'incompatible encodings: UTF-16LE and ISO-8859-1')
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(ArgumentError, 'incompatible encodings: UTF-16LE and ISO-8859-1')
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(ArgumentError, 'incompatible encodings: UTF-16LE and ISO-8859-1')
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(ArgumentError, 'incompatible encodings: UTF-16LE and ISO-8859-1')
end
it "uses to_str to convert arguments (if not Regexp)" do
@@ -177,6 +177,6 @@ describe "Regexp.union" do
end
-> {
Regexp.union(["skiing", "sledding"], [/dogs/, /cats/i])
- }.should raise_error(TypeError, 'no implicit conversion of Array into String')
+ }.should.raise(TypeError, 'no implicit conversion of Array into String')
end
end
diff --git a/spec/ruby/core/set/add_spec.rb b/spec/ruby/core/set/add_spec.rb
index 0fe1a0926c..1a018b186a 100644
--- a/spec/ruby/core/set/add_spec.rb
+++ b/spec/ruby/core/set/add_spec.rb
@@ -1,8 +1,18 @@
require_relative '../../spec_helper'
-require_relative 'shared/add'
describe "Set#add" do
- it_behaves_like :set_add, :add
+ before :each do
+ @set = Set.new
+ end
+
+ it "adds the passed Object to self" do
+ @set.add("dog")
+ @set.should.include?("dog")
+ end
+
+ it "returns self" do
+ @set.add("dog").should.equal?(@set)
+ end
end
describe "Set#add?" do
@@ -12,22 +22,22 @@ describe "Set#add?" do
it "adds the passed Object to self" do
@set.add?("cat")
- @set.should include("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)
+ @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
+ @set.add?("cat").should == nil
end
it "raises RuntimeError when called during iteration" do
set = Set[:a, :b, :c, :d, :e, :f]
set.each do |_m|
- -> { set << 1 }.should raise_error(RuntimeError, /iteration/)
+ -> { set << 1 }.should.raise(RuntimeError, /iteration/)
end
set.should == Set[:a, :b, :c, :d, :e, :f]
end
diff --git a/spec/ruby/core/set/append_spec.rb b/spec/ruby/core/set/append_spec.rb
index 82d34d9130..4f4e2351e2 100644
--- a/spec/ruby/core/set/append_spec.rb
+++ b/spec/ruby/core/set/append_spec.rb
@@ -1,6 +1,7 @@
require_relative '../../spec_helper'
-require_relative 'shared/add'
describe "Set#<<" do
- it_behaves_like :set_add, :<<
+ it "is an alias of Set#add" do
+ Set.instance_method(:<<).should == Set.instance_method(:add)
+ end
end
diff --git a/spec/ruby/core/set/case_compare_spec.rb b/spec/ruby/core/set/case_compare_spec.rb
index 3781b1b963..6fe749c79b 100644
--- a/spec/ruby/core/set/case_compare_spec.rb
+++ b/spec/ruby/core/set/case_compare_spec.rb
@@ -1,11 +1,7 @@
require_relative '../../spec_helper'
-require_relative 'shared/include'
describe "Set#===" do
- it_behaves_like :set_include, :===
-
- it "is an alias for include?" do
- set = Set.new
- set.method(:===).should == set.method(:include?)
+ it "is an alias of Set#include?" do
+ Set.instance_method(:===).should == Set.instance_method(:include?)
end
end
diff --git a/spec/ruby/core/set/case_equality_spec.rb b/spec/ruby/core/set/case_equality_spec.rb
deleted file mode 100644
index 19c1fb6b9c..0000000000
--- a/spec/ruby/core/set/case_equality_spec.rb
+++ /dev/null
@@ -1,6 +0,0 @@
-require_relative '../../spec_helper'
-require_relative 'shared/include'
-
-describe "Set#===" do
- it_behaves_like :set_include, :===
-end
diff --git a/spec/ruby/core/set/classify_spec.rb b/spec/ruby/core/set/classify_spec.rb
index d86ea2722d..a225ab7cbb 100644
--- a/spec/ruby/core/set/classify_spec.rb
+++ b/spec/ruby/core/set/classify_spec.rb
@@ -13,7 +13,7 @@ describe "Set#classify" do
it "returns an Enumerator when passed no block" do
enum = @set.classify
- enum.should be_an_instance_of(Enumerator)
+ enum.should.instance_of?(Enumerator)
classified = enum.each { |x| x.length }
classified.should == { 3 => Set["one", "two"], 4 => Set["four"], 5 => Set["three"] }
diff --git a/spec/ruby/core/set/clear_spec.rb b/spec/ruby/core/set/clear_spec.rb
index ebeac211d3..c61a0d78f2 100644
--- a/spec/ruby/core/set/clear_spec.rb
+++ b/spec/ruby/core/set/clear_spec.rb
@@ -7,10 +7,10 @@ describe "Set#clear" do
it "removes all elements from self" do
@set.clear
- @set.should be_empty
+ @set.should.empty?
end
it "returns self" do
- @set.clear.should equal(@set)
+ @set.clear.should.equal?(@set)
end
end
diff --git a/spec/ruby/core/set/collect_spec.rb b/spec/ruby/core/set/collect_spec.rb
index d186f1a0d9..b78ee493d4 100644
--- a/spec/ruby/core/set/collect_spec.rb
+++ b/spec/ruby/core/set/collect_spec.rb
@@ -1,6 +1,7 @@
require_relative '../../spec_helper'
-require_relative 'shared/collect'
describe "Set#collect!" do
- it_behaves_like :set_collect_bang, :collect!
+ it "is an alias of Set#map!" do
+ Set.instance_method(:collect!).should == Set.instance_method(:map!)
+ end
end
diff --git a/spec/ruby/core/set/compare_by_identity_spec.rb b/spec/ruby/core/set/compare_by_identity_spec.rb
index 0dda6d79f0..458e760da0 100644
--- a/spec/ruby/core/set/compare_by_identity_spec.rb
+++ b/spec/ruby/core/set/compare_by_identity_spec.rb
@@ -16,9 +16,9 @@ describe "Set#compare_by_identity" do
elt = [1]
set = Set.new
set << elt
- set.member?(elt.dup).should be_true
+ set.member?(elt.dup).should == true
set.compare_by_identity
- set.member?(elt.dup).should be_false
+ set.member?(elt.dup).should == false
end
it "rehashes internally so that old members can be looked up" do
@@ -28,19 +28,19 @@ describe "Set#compare_by_identity" do
def o.hash; 123; end
set << o
set.compare_by_identity
- set.member?(o).should be_true
+ set.member?(o).should == true
end
it "returns self" do
set = Set.new
result = set.compare_by_identity
- result.should equal(set)
+ result.should.equal?(set)
end
it "is idempotent and has no effect on an already compare_by_identity set" do
set = Set.new.compare_by_identity
set << :foo
- set.compare_by_identity.should equal(set)
+ set.compare_by_identity.should.equal?(set)
set.should.compare_by_identity?
set.to_a.should == [:foo]
end
@@ -69,7 +69,7 @@ describe "Set#compare_by_identity" do
elt.should_not_receive(:hash)
set = Set.new.compare_by_identity
set << elt
- set.member?(elt).should be_true
+ set.member?(elt).should == true
end
it "regards #dup'd objects as having different identities" do
@@ -90,21 +90,21 @@ describe "Set#compare_by_identity" do
set.to_a.sort.should == [a1, a2].sort
end
- ruby_version_is "3.5" do
+ ruby_version_is "4.0" do
it "raises a FrozenError on frozen sets" do
set = Set.new.freeze
-> {
set.compare_by_identity
- }.should raise_error(FrozenError, /can't modify frozen Set: (#<)?Set(\[|: {)[\]}]>?/)
+ }.should.raise(FrozenError, /can't modify frozen Set: (#<)?Set(\[|: {)[\]}]>?/)
end
end
- ruby_version_is ""..."3.5" do
+ ruby_version_is ""..."4.0" do
it "raises a FrozenError on frozen sets" do
set = Set.new.freeze
-> {
set.compare_by_identity
- }.should raise_error(FrozenError, /frozen Hash/)
+ }.should.raise(FrozenError, /frozen Hash/)
end
end
diff --git a/spec/ruby/core/set/comparison_spec.rb b/spec/ruby/core/set/comparison_spec.rb
index 62059b70b3..eb18a198e5 100644
--- a/spec/ruby/core/set/comparison_spec.rb
+++ b/spec/ruby/core/set/comparison_spec.rb
@@ -17,10 +17,10 @@ describe "Set#<=>" do
end
it "returns nil if the set has unique elements" do
- (Set[1, 2, 3] <=> Set[:a, :b, :c]).should be_nil
+ (Set[1, 2, 3] <=> Set[:a, :b, :c]).should == nil
end
it "returns nil when the argument is not set-like" do
- (Set[] <=> false).should be_nil
+ (Set[] <=> false).should == nil
end
end
diff --git a/spec/ruby/core/set/constructor_spec.rb b/spec/ruby/core/set/constructor_spec.rb
index 365081ad39..11138f3a5b 100644
--- a/spec/ruby/core/set/constructor_spec.rb
+++ b/spec/ruby/core/set/constructor_spec.rb
@@ -4,11 +4,11 @@ describe "Set[]" do
it "returns a new Set populated with the passed Objects" do
set = Set[1, 2, 3]
- set.instance_of?(Set).should be_true
- set.size.should eql(3)
+ set.instance_of?(Set).should == true
+ set.size.should.eql?(3)
- set.should include(1)
- set.should include(2)
- set.should include(3)
+ set.should.include?(1)
+ set.should.include?(2)
+ set.should.include?(3)
end
end
diff --git a/spec/ruby/core/set/delete_if_spec.rb b/spec/ruby/core/set/delete_if_spec.rb
index beda73a5e5..b231dff50d 100644
--- a/spec/ruby/core/set/delete_if_spec.rb
+++ b/spec/ruby/core/set/delete_if_spec.rb
@@ -13,25 +13,25 @@ describe "Set#delete_if" do
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.size.should.eql?(1)
- @set.should_not include("one")
- @set.should_not include("two")
- @set.should include("three")
+ @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)
+ @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.should.instance_of?(Enumerator)
enum.each { |x| x.size == 3 }
- @set.should_not include("one")
- @set.should_not include("two")
- @set.should include("three")
+ @set.should_not.include?("one")
+ @set.should_not.include?("two")
+ @set.should.include?("three")
end
end
diff --git a/spec/ruby/core/set/delete_spec.rb b/spec/ruby/core/set/delete_spec.rb
index a2543ecbee..cdc6dd7b36 100644
--- a/spec/ruby/core/set/delete_spec.rb
+++ b/spec/ruby/core/set/delete_spec.rb
@@ -7,12 +7,12 @@ describe "Set#delete" do
it "deletes the passed Object from self" do
@set.delete("a")
- @set.should_not include("a")
+ @set.should_not.include?("a")
end
it "returns self" do
- @set.delete("a").should equal(@set)
- @set.delete("x").should equal(@set)
+ @set.delete("a").should.equal?(@set)
+ @set.delete("x").should.equal?(@set)
end
end
@@ -23,14 +23,14 @@ describe "Set#delete?" do
it "deletes the passed Object from self" do
@set.delete?("a")
- @set.should_not include("a")
+ @set.should_not.include?("a")
end
it "returns self when the passed Object is in self" do
- @set.delete?("a").should equal(@set)
+ @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
+ @set.delete?("x").should == nil
end
end
diff --git a/spec/ruby/core/set/difference_spec.rb b/spec/ruby/core/set/difference_spec.rb
index 149f946592..22d89973a8 100644
--- a/spec/ruby/core/set/difference_spec.rb
+++ b/spec/ruby/core/set/difference_spec.rb
@@ -1,6 +1,7 @@
require_relative '../../spec_helper'
-require_relative 'shared/difference'
describe "Set#difference" do
- it_behaves_like :set_difference, :difference
+ it "is an alias of Set#-" do
+ Set.instance_method(:difference).should == Set.instance_method(:-)
+ end
end
diff --git a/spec/ruby/core/set/disjoint_spec.rb b/spec/ruby/core/set/disjoint_spec.rb
index 89a3c4b157..d415c21045 100644
--- a/spec/ruby/core/set/disjoint_spec.rb
+++ b/spec/ruby/core/set/disjoint_spec.rb
@@ -12,11 +12,11 @@ describe "Set#disjoint?" do
context "when comparing to a Set-like object" do
it "returns false when a Set has at least one element in common with a Set-like object" do
- Set[1, 2].disjoint?(SetSpecs::SetLike.new([2, 3])).should be_false
+ Set[1, 2].disjoint?(SetSpecs::SetLike.new([2, 3])).should == false
end
it "returns true when a Set has no element in common with a Set-like object" do
- Set[1, 2].disjoint?(SetSpecs::SetLike.new([3, 4])).should be_true
+ Set[1, 2].disjoint?(SetSpecs::SetLike.new([3, 4])).should == true
end
end
end
diff --git a/spec/ruby/core/set/divide_spec.rb b/spec/ruby/core/set/divide_spec.rb
index cbe0042f16..409a22df75 100644
--- a/spec/ruby/core/set/divide_spec.rb
+++ b/spec/ruby/core/set/divide_spec.rb
@@ -14,7 +14,7 @@ describe "Set#divide" do
it "returns an enumerator when not passed a block" do
ret = Set[1, 2, 3, 4].divide
- ret.should be_kind_of(Enumerator)
+ ret.should.is_a?(Enumerator)
ret.each(&:even?).should == Set[Set[1, 3], Set[2, 4]]
end
end
@@ -25,7 +25,7 @@ describe "Set#divide when passed a block with an arity of 2" do
set.map{ |x| x.to_a.sort }.sort.should == [[1], [3, 4], [6], [9, 10, 11]]
end
- ruby_version_is "3.5" do
+ ruby_version_is "4.0" do
it "yields each two Object to the block" do
ret = []
Set[1, 2].divide { |x, y| ret << [x, y] }
@@ -33,7 +33,7 @@ describe "Set#divide when passed a block with an arity of 2" do
end
end
- ruby_version_is ""..."3.5" do
+ ruby_version_is ""..."4.0" do
it "yields each two Object to the block" do
ret = []
Set[1, 2].divide { |x, y| ret << [x, y] }
@@ -43,7 +43,7 @@ describe "Set#divide when passed a block with an arity of 2" do
it "returns an enumerator when not passed a block" do
ret = Set[1, 2, 3, 4].divide
- ret.should be_kind_of(Enumerator)
+ ret.should.is_a?(Enumerator)
ret.each { |a, b| (a + b).even? }.should == Set[Set[1, 3], Set[2, 4]]
end
end
@@ -51,8 +51,8 @@ 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
+ y.should == nil
+ z.should == nil
x.length
end
set.map { |x| x.to_a.sort }.sort.should == [["five", "four"], ["one", "two"], ["three"]]
diff --git a/spec/ruby/core/set/each_spec.rb b/spec/ruby/core/set/each_spec.rb
index 3d9cdc2d46..bdafc99571 100644
--- a/spec/ruby/core/set/each_spec.rb
+++ b/spec/ruby/core/set/each_spec.rb
@@ -12,12 +12,12 @@ describe "Set#each" do
end
it "returns self" do
- @set.each { |x| x }.should equal(@set)
+ @set.each { |x| x }.should.equal?(@set)
end
it "returns an Enumerator when not passed a block" do
enum = @set.each
- enum.should be_an_instance_of(Enumerator)
+ enum.should.instance_of?(Enumerator)
ret = []
enum.each { |x| ret << x }
diff --git a/spec/ruby/core/set/empty_spec.rb b/spec/ruby/core/set/empty_spec.rb
index 4b55658e20..c71f2ce18d 100644
--- a/spec/ruby/core/set/empty_spec.rb
+++ b/spec/ruby/core/set/empty_spec.rb
@@ -2,8 +2,8 @@ require_relative '../../spec_helper'
describe "Set#empty?" do
it "returns true if self is empty" do
- Set[].empty?.should be_true
- Set[1].empty?.should be_false
- Set[1,2,3].empty?.should be_false
+ Set[].empty?.should == true
+ Set[1].empty?.should == false
+ Set[1,2,3].empty?.should == false
end
end
diff --git a/spec/ruby/core/set/eql_spec.rb b/spec/ruby/core/set/eql_spec.rb
index 4ad5c3aa5a..e7eacf2999 100644
--- a/spec/ruby/core/set/eql_spec.rb
+++ b/spec/ruby/core/set/eql_spec.rb
@@ -1,14 +1,22 @@
require_relative '../../spec_helper'
describe "Set#eql?" do
- it "returns true when the passed argument is a Set and contains the same elements" do
- Set[].should eql(Set[])
- Set[1, 2, 3].should eql(Set[1, 2, 3])
- Set[1, 2, 3].should eql(Set[3, 2, 1])
- Set["a", :b, ?c].should eql(Set[?c, :b, "a"])
+ ruby_version_is ""..."4.0" do
+ it "returns true when the passed argument is a Set and contains the same elements" do
+ Set[].should.eql?(Set[])
+ Set[1, 2, 3].should.eql?(Set[1, 2, 3])
+ Set[1, 2, 3].should.eql?(Set[3, 2, 1])
+ Set["a", :b, ?c].should.eql?(Set[?c, :b, "a"])
- Set[1, 2, 3].should_not eql(Set[1.0, 2, 3])
- Set[1, 2, 3].should_not eql(Set[2, 3])
- Set[1, 2, 3].should_not eql(Set[])
+ Set[1, 2, 3].should_not.eql?(Set[1.0, 2, 3])
+ Set[1, 2, 3].should_not.eql?(Set[2, 3])
+ Set[1, 2, 3].should_not.eql?(Set[])
+ end
+ end
+
+ ruby_version_is "4.0" do
+ it "is an alias of Set#==" do
+ Set.instance_method(:eql?).should == Set.instance_method(:==)
+ end
end
end
diff --git a/spec/ruby/core/set/equal_value_spec.rb b/spec/ruby/core/set/equal_value_spec.rb
index e3514928c8..721a79a3f1 100644
--- a/spec/ruby/core/set/equal_value_spec.rb
+++ b/spec/ruby/core/set/equal_value_spec.rb
@@ -24,7 +24,7 @@ describe "Set#==" do
set1.should == set2
end
- ruby_version_is ""..."3.5" do
+ ruby_version_is ""..."4.0" do
context "when comparing to a Set-like object" do
it "returns true when a Set and a Set-like object contain the same elements" do
Set[1, 2, 3].should == SetSpecs::SetLike.new([1, 2, 3])
diff --git a/spec/ruby/core/set/exclusion_spec.rb b/spec/ruby/core/set/exclusion_spec.rb
index bbc29afa95..52ee34fe78 100644
--- a/spec/ruby/core/set/exclusion_spec.rb
+++ b/spec/ruby/core/set/exclusion_spec.rb
@@ -11,7 +11,7 @@ describe "Set#^" do
end
it "raises an ArgumentError when passed a non-Enumerable" do
- -> { @set ^ 3 }.should raise_error(ArgumentError)
- -> { @set ^ Object.new }.should raise_error(ArgumentError)
+ -> { @set ^ 3 }.should.raise(ArgumentError)
+ -> { @set ^ Object.new }.should.raise(ArgumentError)
end
end
diff --git a/spec/ruby/core/set/filter_spec.rb b/spec/ruby/core/set/filter_spec.rb
index 779254ad68..d0c294c27f 100644
--- a/spec/ruby/core/set/filter_spec.rb
+++ b/spec/ruby/core/set/filter_spec.rb
@@ -1,6 +1,7 @@
require_relative '../../spec_helper'
-require_relative 'shared/select'
describe "Set#filter!" do
- it_behaves_like :set_select_bang, :filter!
+ it "is an alias of Set#select!" do
+ Set.instance_method(:filter!).should == Set.instance_method(:select!)
+ end
end
diff --git a/spec/ruby/core/set/flatten_merge_spec.rb b/spec/ruby/core/set/flatten_merge_spec.rb
index d7c2b30657..3904d969ae 100644
--- a/spec/ruby/core/set/flatten_merge_spec.rb
+++ b/spec/ruby/core/set/flatten_merge_spec.rb
@@ -1,9 +1,9 @@
require_relative '../../spec_helper'
describe "Set#flatten_merge" do
- ruby_version_is ""..."3.5" do
+ ruby_version_is ""..."4.0" do
it "is protected" do
- Set.should have_protected_instance_method("flatten_merge")
+ Set.protected_instance_methods(false).should.include?(:flatten_merge)
end
it "flattens the passed Set and merges it into self" do
@@ -18,7 +18,7 @@ describe "Set#flatten_merge" do
set2 = Set[5, 6, 7]
set2 << set2
- -> { set1.send(:flatten_merge, set2) }.should raise_error(ArgumentError)
+ -> { set1.send(:flatten_merge, set2) }.should.raise(ArgumentError)
end
end
end
diff --git a/spec/ruby/core/set/flatten_spec.rb b/spec/ruby/core/set/flatten_spec.rb
index 870eccc2f1..ca6323fac8 100644
--- a/spec/ruby/core/set/flatten_spec.rb
+++ b/spec/ruby/core/set/flatten_spec.rb
@@ -7,16 +7,16 @@ describe "Set#flatten" do
set = Set[1, 2, Set[3, 4, Set[5, 6, Set[7, 8]]], 9, 10]
flattened_set = set.flatten
- flattened_set.should_not equal(set)
+ flattened_set.should_not.equal?(set)
flattened_set.should == Set[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
end
it "raises an ArgumentError when self is recursive" do
(set = Set[]) << set
- -> { set.flatten }.should raise_error(ArgumentError)
+ -> { set.flatten }.should.raise(ArgumentError)
end
- ruby_version_is ""..."3.5" do
+ ruby_version_is ""..."4.0" do
context "when Set contains a Set-like object" do
it "returns a copy of self with each included Set-like object flattened" do
Set[SetSpecs::SetLike.new([1])].flatten.should == Set[1]
@@ -34,26 +34,16 @@ describe "Set#flatten!" do
it "returns self when self was modified" do
set = Set[1, 2, Set[3, 4]]
- set.flatten!.should equal(set)
+ set.flatten!.should.equal?(set)
end
it "returns nil when self was not modified" do
set = Set[1, 2, 3, 4]
- set.flatten!.should be_nil
+ set.flatten!.should == nil
end
it "raises an ArgumentError when self is recursive" do
(set = Set[]) << set
- -> { set.flatten! }.should raise_error(ArgumentError)
- end
-
- version_is(set_version, ""..."1.1.0") do #ruby_version_is ""..."3.3" do
- ruby_version_is ""..."3.5" 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
- end
- end
+ -> { set.flatten! }.should.raise(ArgumentError)
end
end
diff --git a/spec/ruby/core/set/gt_spec.rb b/spec/ruby/core/set/gt_spec.rb
new file mode 100644
index 0000000000..8a7e421e40
--- /dev/null
+++ b/spec/ruby/core/set/gt_spec.rb
@@ -0,0 +1,7 @@
+require_relative '../../spec_helper'
+
+describe "Set#>" do
+ it "is an alias of Set#proper_superset?" do
+ Set.instance_method(:>).should == Set.instance_method(:proper_superset?)
+ end
+end
diff --git a/spec/ruby/core/set/gte_spec.rb b/spec/ruby/core/set/gte_spec.rb
new file mode 100644
index 0000000000..e98c3cb1e2
--- /dev/null
+++ b/spec/ruby/core/set/gte_spec.rb
@@ -0,0 +1,7 @@
+require_relative '../../spec_helper'
+
+describe "Set#>=" do
+ it "is an alias of Set#superset?" do
+ Set.instance_method(:>=).should == Set.instance_method(:superset?)
+ end
+end
diff --git a/spec/ruby/core/set/hash_spec.rb b/spec/ruby/core/set/hash_spec.rb
index 4b4696e34c..63a0aa66a5 100644
--- a/spec/ruby/core/set/hash_spec.rb
+++ b/spec/ruby/core/set/hash_spec.rb
@@ -10,7 +10,7 @@ describe "Set#hash" do
Set[1, 2, 3].hash.should_not == Set[:a, "b", ?c].hash
end
- ruby_version_is ""..."3.5" do
+ ruby_version_is ""..."4.0" do
# see https://github.com/jruby/jruby/issues/8393
it "is equal to nil.hash for an uninitialized Set" do
Set.allocate.hash.should == nil.hash
diff --git a/spec/ruby/core/set/include_spec.rb b/spec/ruby/core/set/include_spec.rb
index dd33bbc3bd..92a6ca04e6 100644
--- a/spec/ruby/core/set/include_spec.rb
+++ b/spec/ruby/core/set/include_spec.rb
@@ -1,6 +1,31 @@
require_relative '../../spec_helper'
-require_relative 'shared/include'
describe "Set#include?" do
- it_behaves_like :set_include, :include?
+ it "returns true when self contains the passed Object" do
+ set = Set[:a, :b, :c]
+ set.include?(:a).should == true
+ set.include?(:e).should == false
+ end
+
+ describe "member equality" do
+ it "is checked using both #hash and #eql?" do
+ obj = Object.new
+ obj_another = Object.new
+
+ def obj.hash; 42 end
+ def obj_another.hash; 42 end
+ def obj_another.eql?(o) hash == o.hash end
+
+ set = Set["a", "b", "c", obj]
+ set.include?(obj_another).should == true
+ end
+
+ it "is not checked using #==" do
+ obj = Object.new
+ set = Set["a", "b", "c"]
+
+ obj.should_not_receive(:==)
+ set.include?(obj)
+ end
+ end
end
diff --git a/spec/ruby/core/set/initialize_spec.rb b/spec/ruby/core/set/initialize_spec.rb
index ad9e1bd8c9..45538b38fb 100644
--- a/spec/ruby/core/set/initialize_spec.rb
+++ b/spec/ruby/core/set/initialize_spec.rb
@@ -2,71 +2,87 @@ require_relative '../../spec_helper'
describe "Set#initialize" do
it "is private" do
- Set.should have_private_instance_method(:initialize)
+ Set.private_instance_methods(false).should.include?(:initialize)
end
it "adds all elements of the passed Enumerable to self" do
s = Set.new([1, 2, 3])
- s.size.should eql(3)
- s.should include(1)
- s.should include(2)
- s.should include(3)
+ s.size.should.eql?(3)
+ s.should.include?(1)
+ s.should.include?(2)
+ s.should.include?(3)
end
it "uses #each_entry on the provided Enumerable" do
enumerable = MockObject.new('mock-enumerable')
enumerable.should_receive(:each_entry).and_yield(1).and_yield(2).and_yield(3)
s = Set.new(enumerable)
- s.size.should eql(3)
- s.should include(1)
- s.should include(2)
- s.should include(3)
+ s.size.should.eql?(3)
+ s.should.include?(1)
+ s.should.include?(2)
+ s.should.include?(3)
end
it "uses #each on the provided Enumerable if it does not respond to #each_entry" do
enumerable = MockObject.new('mock-enumerable')
enumerable.should_receive(:each).and_yield(1).and_yield(2).and_yield(3)
s = Set.new(enumerable)
- s.size.should eql(3)
- s.should include(1)
- s.should include(2)
- s.should include(3)
+ s.size.should.eql?(3)
+ s.should.include?(1)
+ s.should.include?(2)
+ s.should.include?(3)
end
it "raises if the provided Enumerable does not respond to #each_entry or #each" do
enumerable = MockObject.new('mock-enumerable')
- -> { Set.new(enumerable) }.should raise_error(ArgumentError, "value must be enumerable")
+ -> { Set.new(enumerable) }.should.raise(ArgumentError, "value must be enumerable")
end
it "should initialize with empty array and set" do
s = Set.new([])
- s.size.should eql(0)
+ s.size.should.eql?(0)
s = Set.new({})
- s.size.should eql(0)
+ s.size.should.eql?(0)
end
it "preprocesses all elements by a passed block before adding to self" do
s = Set.new([1, 2, 3]) { |x| x * x }
- s.size.should eql(3)
- s.should include(1)
- s.should include(4)
- s.should include(9)
+ s.size.should.eql?(3)
+ s.should.include?(1)
+ s.should.include?(4)
+ s.should.include?(9)
end
it "should initialize with empty array and block" do
s = Set.new([]) { |x| x * x }
- s.size.should eql(0)
+ s.size.should.eql?(0)
end
it "should initialize with empty set and block" do
s = Set.new(Set.new) { |x| x * x }
- s.size.should eql(0)
+ s.size.should.eql?(0)
+ end
+
+ it "should initialize with set" do
+ o = Set.new([1, 2])
+ s = Set.new(o)
+ s.size.should.eql?(2)
+ s.should.include?(1)
+ s.should.include?(2)
+ end
+
+ it "should initialize with set and block" do
+ o = Set.new([1, 2])
+ s = Set.new(o) { |e| e + 2 }
+ s.size.should.eql?(2)
+ s.should.include?(3)
+ s.should.include?(4)
end
it "should initialize with just block" do
s = Set.new { |x| x * x }
- s.size.should eql(0)
- s.should eql(Set.new)
+ s.size.should.eql?(0)
+ s.should.eql?(Set.new)
end
end
diff --git a/spec/ruby/core/set/inspect_spec.rb b/spec/ruby/core/set/inspect_spec.rb
index 0dcce83eb6..45aeed280e 100644
--- a/spec/ruby/core/set/inspect_spec.rb
+++ b/spec/ruby/core/set/inspect_spec.rb
@@ -1,6 +1,7 @@
require_relative '../../spec_helper'
-require_relative 'shared/inspect'
describe "Set#inspect" do
- it_behaves_like :set_inspect, :inspect
+ it "is an alias of Set#to_s" do
+ Set.instance_method(:inspect).should == Set.instance_method(:to_s)
+ end
end
diff --git a/spec/ruby/core/set/intersect_spec.rb b/spec/ruby/core/set/intersect_spec.rb
index 0736dea5fd..d04a1af441 100644
--- a/spec/ruby/core/set/intersect_spec.rb
+++ b/spec/ruby/core/set/intersect_spec.rb
@@ -12,11 +12,11 @@ describe "Set#intersect?" do
context "when comparing to a Set-like object" do
it "returns true when a Set has at least one element in common with a Set-like object" do
- Set[1, 2].intersect?(SetSpecs::SetLike.new([2, 3])).should be_true
+ Set[1, 2].intersect?(SetSpecs::SetLike.new([2, 3])).should == true
end
it "returns false when a Set has no element in common with a Set-like object" do
- Set[1, 2].intersect?(SetSpecs::SetLike.new([3, 4])).should be_false
+ Set[1, 2].intersect?(SetSpecs::SetLike.new([3, 4])).should == false
end
end
end
diff --git a/spec/ruby/core/set/intersection_spec.rb b/spec/ruby/core/set/intersection_spec.rb
index 136b886775..c14e1f62ad 100644
--- a/spec/ruby/core/set/intersection_spec.rb
+++ b/spec/ruby/core/set/intersection_spec.rb
@@ -1,10 +1,23 @@
require_relative '../../spec_helper'
-require_relative 'shared/intersection'
describe "Set#intersection" do
- it_behaves_like :set_intersection, :intersection
+ it "is an alias of Set#&" do
+ Set.instance_method(:intersection).should == Set.instance_method(:&)
+ end
end
describe "Set#&" do
- it_behaves_like :set_intersection, :&
+ before :each do
+ @set = Set[:a, :b, :c]
+ end
+
+ it "returns a new Set containing only elements shared by self and the passed Enumerable" do
+ (@set & Set[:b, :c, :d, :e]).should == Set[:b, :c]
+ (@set & [:b, :c, :d]).should == Set[:b, :c]
+ end
+
+ it "raises an ArgumentError when passed a non-Enumerable" do
+ -> { @set & 1 }.should.raise(ArgumentError)
+ -> { @set & Object.new }.should.raise(ArgumentError)
+ end
end
diff --git a/spec/ruby/core/set/join_spec.rb b/spec/ruby/core/set/join_spec.rb
index cdb593597d..1c1e8a8af8 100644
--- a/spec/ruby/core/set/join_spec.rb
+++ b/spec/ruby/core/set/join_spec.rb
@@ -20,7 +20,7 @@ describe "Set#join" do
set.join(' | ').should == "a | b | c"
end
- ruby_version_is ""..."3.5" do
+ ruby_version_is ""..."4.0" do
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])
diff --git a/spec/ruby/core/set/keep_if_spec.rb b/spec/ruby/core/set/keep_if_spec.rb
index d6abdd6adc..7ca5d0cd43 100644
--- a/spec/ruby/core/set/keep_if_spec.rb
+++ b/spec/ruby/core/set/keep_if_spec.rb
@@ -13,25 +13,25 @@ describe "Set#keep_if" do
it "keeps every element from self for which the passed block returns true" do
@set.keep_if { |x| x.size != 3 }
- @set.size.should eql(1)
+ @set.size.should.eql?(1)
- @set.should_not include("one")
- @set.should_not include("two")
- @set.should include("three")
+ @set.should_not.include?("one")
+ @set.should_not.include?("two")
+ @set.should.include?("three")
end
it "returns self" do
- @set.keep_if {}.should equal(@set)
+ @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.should.instance_of?(Enumerator)
enum.each { |x| x.size != 3 }
- @set.should_not include("one")
- @set.should_not include("two")
- @set.should include("three")
+ @set.should_not.include?("one")
+ @set.should_not.include?("two")
+ @set.should.include?("three")
end
end
diff --git a/spec/ruby/core/set/length_spec.rb b/spec/ruby/core/set/length_spec.rb
index 6bb697b4ca..9b0d3622b8 100644
--- a/spec/ruby/core/set/length_spec.rb
+++ b/spec/ruby/core/set/length_spec.rb
@@ -1,6 +1,7 @@
require_relative '../../spec_helper'
-require_relative 'shared/length'
describe "Set#length" do
- it_behaves_like :set_length, :length
+ it "is an alias of Set#size" do
+ Set.instance_method(:length).should == Set.instance_method(:size)
+ end
end
diff --git a/spec/ruby/core/set/lt_spec.rb b/spec/ruby/core/set/lt_spec.rb
new file mode 100644
index 0000000000..0f5bc9c642
--- /dev/null
+++ b/spec/ruby/core/set/lt_spec.rb
@@ -0,0 +1,7 @@
+require_relative '../../spec_helper'
+
+describe "Set#<" do
+ it "is an alias of Set#proper_subset?" do
+ Set.instance_method(:<).should == Set.instance_method(:proper_subset?)
+ end
+end
diff --git a/spec/ruby/core/set/lte_spec.rb b/spec/ruby/core/set/lte_spec.rb
new file mode 100644
index 0000000000..291d582240
--- /dev/null
+++ b/spec/ruby/core/set/lte_spec.rb
@@ -0,0 +1,7 @@
+require_relative '../../spec_helper'
+
+describe "Set#<=" do
+ it "is an alias of Set#subset?" do
+ Set.instance_method(:<=).should == Set.instance_method(:subset?)
+ end
+end
diff --git a/spec/ruby/core/set/map_spec.rb b/spec/ruby/core/set/map_spec.rb
index 996191b0a8..fd04a8bde1 100644
--- a/spec/ruby/core/set/map_spec.rb
+++ b/spec/ruby/core/set/map_spec.rb
@@ -1,6 +1,22 @@
require_relative '../../spec_helper'
-require_relative 'shared/collect'
describe "Set#map!" do
- it_behaves_like :set_collect_bang, :map!
+ before :each do
+ @set = Set[1, 2, 3, 4, 5]
+ end
+
+ it "yields each Object in self" do
+ res = []
+ @set.map! { |x| res << x }
+ res.sort.should == [1, 2, 3, 4, 5].sort
+ end
+
+ it "returns self" do
+ @set.map! { |x| x }.should.equal?(@set)
+ end
+
+ it "replaces self with the return values of the block" do
+ @set.map! { |x| x * 2 }
+ @set.should == Set[2, 4, 6, 8, 10]
+ end
end
diff --git a/spec/ruby/core/set/member_spec.rb b/spec/ruby/core/set/member_spec.rb
index 5c82e8f826..a36308eec7 100644
--- a/spec/ruby/core/set/member_spec.rb
+++ b/spec/ruby/core/set/member_spec.rb
@@ -1,6 +1,7 @@
require_relative '../../spec_helper'
-require_relative 'shared/include'
describe "Set#member?" do
- it_behaves_like :set_include, :member?
+ it "is an alias of Set#include?" do
+ Set.instance_method(:member?).should == Set.instance_method(:include?)
+ end
end
diff --git a/spec/ruby/core/set/merge_spec.rb b/spec/ruby/core/set/merge_spec.rb
index 0c6ed27670..a2c1a7e706 100644
--- a/spec/ruby/core/set/merge_spec.rb
+++ b/spec/ruby/core/set/merge_spec.rb
@@ -8,30 +8,22 @@ describe "Set#merge" do
it "returns self" do
set = Set[1, 2]
- set.merge([3, 4]).should equal(set)
+ set.merge([3, 4]).should.equal?(set)
end
it "raises an ArgumentError when passed a non-Enumerable" do
- -> { Set[1, 2].merge(1) }.should raise_error(ArgumentError)
- -> { Set[1, 2].merge(Object.new) }.should raise_error(ArgumentError)
+ -> { Set[1, 2].merge(1) }.should.raise(ArgumentError)
+ -> { Set[1, 2].merge(Object.new) }.should.raise(ArgumentError)
end
it "raises RuntimeError when called during iteration" do
set = Set[:a, :b]
set.each do |_m|
- -> { set.merge([1, 2]) }.should raise_error(RuntimeError, /iteration/)
+ -> { set.merge([1, 2]) }.should.raise(RuntimeError, /iteration/)
end
end
- ruby_version_is ""..."3.3" do
- it "accepts only a single argument" do
- -> { Set[].merge([], []) }.should raise_error(ArgumentError, "wrong number of arguments (given 2, expected 1)")
- end
- end
-
- ruby_version_is "3.3" do
- it "accepts multiple arguments" do
- Set[:a, :b].merge(Set[:b, :c], [:d]).should == Set[:a, :b, :c, :d]
- end
+ it "accepts multiple arguments" do
+ Set[:a, :b].merge(Set[:b, :c], [:d]).should == Set[:a, :b, :c, :d]
end
end
diff --git a/spec/ruby/core/set/minus_spec.rb b/spec/ruby/core/set/minus_spec.rb
index 72f98f985e..8574708559 100644
--- a/spec/ruby/core/set/minus_spec.rb
+++ b/spec/ruby/core/set/minus_spec.rb
@@ -1,6 +1,17 @@
require_relative '../../spec_helper'
-require_relative 'shared/difference'
describe "Set#-" do
- it_behaves_like :set_difference, :-
+ before :each do
+ @set = Set[:a, :b, :c]
+ end
+
+ it "returns a new Set containing self's elements excluding the elements in the passed Enumerable" do
+ (@set - Set[:a, :b]).should == Set[:c]
+ (@set - [:b, :c]).should == Set[:a]
+ end
+
+ it "raises an ArgumentError when passed a non-Enumerable" do
+ -> { @set - 1 }.should.raise(ArgumentError)
+ -> { @set - Object.new }.should.raise(ArgumentError)
+ end
end
diff --git a/spec/ruby/core/set/plus_spec.rb b/spec/ruby/core/set/plus_spec.rb
index 7e44ff0b7e..839f77fc39 100644
--- a/spec/ruby/core/set/plus_spec.rb
+++ b/spec/ruby/core/set/plus_spec.rb
@@ -1,6 +1,7 @@
require_relative '../../spec_helper'
-require_relative 'shared/union'
describe "Set#+" do
- it_behaves_like :set_union, :+
+ it "is an alias of Set#|" do
+ Set.instance_method(:+).should == Set.instance_method(:|)
+ end
end
diff --git a/spec/ruby/core/set/pretty_print_cycle_spec.rb b/spec/ruby/core/set/pretty_print_cycle_spec.rb
index c3b383fe80..7e6017c112 100644
--- a/spec/ruby/core/set/pretty_print_cycle_spec.rb
+++ b/spec/ruby/core/set/pretty_print_cycle_spec.rb
@@ -3,7 +3,12 @@ require_relative '../../spec_helper'
describe "Set#pretty_print_cycle" do
it "passes the 'pretty print' representation of a self-referencing Set to the pretty print writer" do
pp = mock("PrettyPrint")
- pp.should_receive(:text).with("#<Set: {...}>")
+ ruby_version_is(""..."4.0") do
+ pp.should_receive(:text).with("#<Set: {...}>")
+ end
+ ruby_version_is("4.0") do
+ pp.should_receive(:text).with("Set[...]")
+ end
Set[1, 2, 3].pretty_print_cycle(pp)
end
end
diff --git a/spec/ruby/core/set/proper_subset_spec.rb b/spec/ruby/core/set/proper_subset_spec.rb
index a84c4197c2..3fd27da131 100644
--- a/spec/ruby/core/set/proper_subset_spec.rb
+++ b/spec/ruby/core/set/proper_subset_spec.rb
@@ -8,38 +8,28 @@ describe "Set#proper_subset?" do
end
it "returns true if passed a Set that self is a proper subset of" do
- Set[].proper_subset?(@set).should be_true
- Set[].proper_subset?(Set[1, 2, 3]).should be_true
- Set[].proper_subset?(Set["a", :b, ?c]).should be_true
+ Set[].proper_subset?(@set).should == true
+ Set[].proper_subset?(Set[1, 2, 3]).should == true
+ Set[].proper_subset?(Set["a", :b, ?c]).should == true
- Set[1, 2, 3].proper_subset?(@set).should be_true
- Set[1, 3].proper_subset?(@set).should be_true
- Set[1, 2].proper_subset?(@set).should be_true
- Set[1].proper_subset?(@set).should be_true
+ Set[1, 2, 3].proper_subset?(@set).should == true
+ Set[1, 3].proper_subset?(@set).should == true
+ Set[1, 2].proper_subset?(@set).should == true
+ Set[1].proper_subset?(@set).should == true
- Set[5].proper_subset?(@set).should be_false
- Set[1, 5].proper_subset?(@set).should be_false
- Set[nil].proper_subset?(@set).should be_false
- Set["test"].proper_subset?(@set).should be_false
+ Set[5].proper_subset?(@set).should == false
+ Set[1, 5].proper_subset?(@set).should == false
+ Set[nil].proper_subset?(@set).should == false
+ Set["test"].proper_subset?(@set).should == false
- @set.proper_subset?(@set).should be_false
- Set[].proper_subset?(Set[]).should be_false
+ @set.proper_subset?(@set).should == false
+ Set[].proper_subset?(Set[]).should == false
end
it "raises an ArgumentError when passed a non-Set" do
- -> { Set[].proper_subset?([]) }.should raise_error(ArgumentError)
- -> { Set[].proper_subset?(1) }.should raise_error(ArgumentError)
- -> { Set[].proper_subset?("test") }.should raise_error(ArgumentError)
- -> { Set[].proper_subset?(Object.new) }.should raise_error(ArgumentError)
- end
-
- version_is(set_version, ""..."1.1.0") do #ruby_version_is ""..."3.3" do
- ruby_version_is ""..."3.5" 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
- end
- end
+ -> { Set[].proper_subset?([]) }.should.raise(ArgumentError)
+ -> { Set[].proper_subset?(1) }.should.raise(ArgumentError)
+ -> { Set[].proper_subset?("test") }.should.raise(ArgumentError)
+ -> { Set[].proper_subset?(Object.new) }.should.raise(ArgumentError)
end
end
diff --git a/spec/ruby/core/set/proper_superset_spec.rb b/spec/ruby/core/set/proper_superset_spec.rb
index 653411f6b2..e95c67ef0e 100644
--- a/spec/ruby/core/set/proper_superset_spec.rb
+++ b/spec/ruby/core/set/proper_superset_spec.rb
@@ -7,35 +7,35 @@ describe "Set#proper_superset?" do
end
it "returns true if passed a Set that self is a proper superset of" do
- @set.proper_superset?(Set[]).should be_true
- Set[1, 2, 3].proper_superset?(Set[]).should be_true
- Set["a", :b, ?c].proper_superset?(Set[]).should be_true
+ @set.proper_superset?(Set[]).should == true
+ Set[1, 2, 3].proper_superset?(Set[]).should == true
+ Set["a", :b, ?c].proper_superset?(Set[]).should == true
- @set.proper_superset?(Set[1, 2, 3]).should be_true
- @set.proper_superset?(Set[1, 3]).should be_true
- @set.proper_superset?(Set[1, 2]).should be_true
- @set.proper_superset?(Set[1]).should be_true
+ @set.proper_superset?(Set[1, 2, 3]).should == true
+ @set.proper_superset?(Set[1, 3]).should == true
+ @set.proper_superset?(Set[1, 2]).should == true
+ @set.proper_superset?(Set[1]).should == true
- @set.proper_superset?(Set[5]).should be_false
- @set.proper_superset?(Set[1, 5]).should be_false
- @set.proper_superset?(Set[nil]).should be_false
- @set.proper_superset?(Set["test"]).should be_false
+ @set.proper_superset?(Set[5]).should == false
+ @set.proper_superset?(Set[1, 5]).should == false
+ @set.proper_superset?(Set[nil]).should == false
+ @set.proper_superset?(Set["test"]).should == false
- @set.proper_superset?(@set).should be_false
- Set[].proper_superset?(Set[]).should be_false
+ @set.proper_superset?(@set).should == false
+ Set[].proper_superset?(Set[]).should == false
end
it "raises an ArgumentError when passed a non-Set" do
- -> { Set[].proper_superset?([]) }.should raise_error(ArgumentError)
- -> { Set[].proper_superset?(1) }.should raise_error(ArgumentError)
- -> { Set[].proper_superset?("test") }.should raise_error(ArgumentError)
- -> { Set[].proper_superset?(Object.new) }.should raise_error(ArgumentError)
+ -> { Set[].proper_superset?([]) }.should.raise(ArgumentError)
+ -> { Set[].proper_superset?(1) }.should.raise(ArgumentError)
+ -> { Set[].proper_superset?("test") }.should.raise(ArgumentError)
+ -> { Set[].proper_superset?(Object.new) }.should.raise(ArgumentError)
end
- ruby_version_is ""..."3.5" do
+ ruby_version_is ""..."4.0" do
context "when comparing to a Set-like object" do
it "returns true if passed a Set-like object that self is a proper superset of" do
- Set[1, 2, 3, 4].proper_superset?(SetSpecs::SetLike.new([1, 2, 3])).should be_true
+ Set[1, 2, 3, 4].proper_superset?(SetSpecs::SetLike.new([1, 2, 3])).should == true
end
end
end
diff --git a/spec/ruby/core/set/reject_spec.rb b/spec/ruby/core/set/reject_spec.rb
index 91d0293415..b00a36812b 100644
--- a/spec/ruby/core/set/reject_spec.rb
+++ b/spec/ruby/core/set/reject_spec.rb
@@ -13,29 +13,29 @@ describe "Set#reject!" do
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.size.should.eql?(1)
- @set.should_not include("one")
- @set.should_not include("two")
- @set.should include("three")
+ @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)
+ @set.reject! { |x| true }.should.equal?(@set)
end
it "returns nil when self was not modified" do
- @set.reject! { |x| false }.should be_nil
+ @set.reject! { |x| false }.should == nil
end
it "returns an Enumerator when passed no block" do
enum = @set.reject!
- enum.should be_an_instance_of(Enumerator)
+ enum.should.instance_of?(Enumerator)
enum.each { |x| x.size == 3 }
- @set.should_not include("one")
- @set.should_not include("two")
- @set.should include("three")
+ @set.should_not.include?("one")
+ @set.should_not.include?("two")
+ @set.should.include?("three")
end
end
diff --git a/spec/ruby/core/set/replace_spec.rb b/spec/ruby/core/set/replace_spec.rb
index c66a2d0ec3..2a51a024dc 100644
--- a/spec/ruby/core/set/replace_spec.rb
+++ b/spec/ruby/core/set/replace_spec.rb
@@ -13,7 +13,7 @@ describe "Set#replace" do
it "raises RuntimeError when called during iteration" do
set = Set[:a, :b, :c, :d, :e, :f]
set.each do |_m|
- -> { set.replace(Set[1, 2, 3]) }.should raise_error(RuntimeError, /iteration/)
+ -> { set.replace(Set[1, 2, 3]) }.should.raise(RuntimeError, /iteration/)
end
set.should == Set[:a, :b, :c, :d, :e, :f]
end
diff --git a/spec/ruby/core/set/select_spec.rb b/spec/ruby/core/set/select_spec.rb
index b458ffacaa..619194605b 100644
--- a/spec/ruby/core/set/select_spec.rb
+++ b/spec/ruby/core/set/select_spec.rb
@@ -1,6 +1,41 @@
require_relative '../../spec_helper'
-require_relative 'shared/select'
describe "Set#select!" do
- it_behaves_like :set_select_bang, :select!
+ before :each do
+ @set = Set["one", "two", "three"]
+ end
+
+ it "yields every element of self" do
+ ret = []
+ @set.select! { |x| ret << x }
+ ret.sort.should == ["one", "two", "three"].sort
+ end
+
+ it "keeps every element from self for which the passed block returns true" do
+ @set.select! { |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.select! { false }.should.equal?(@set)
+ end
+
+ it "returns nil when self was not modified" do
+ @set.select! { true }.should == nil
+ end
+
+ it "returns an Enumerator when passed no block" do
+ enum = @set.select!
+ enum.should.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
diff --git a/spec/ruby/core/set/shared/add.rb b/spec/ruby/core/set/shared/add.rb
deleted file mode 100644
index 9e797f5df9..0000000000
--- a/spec/ruby/core/set/shared/add.rb
+++ /dev/null
@@ -1,14 +0,0 @@
-describe :set_add, shared: true do
- before :each do
- @set = Set.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/core/set/shared/collect.rb b/spec/ruby/core/set/shared/collect.rb
deleted file mode 100644
index bc58c231be..0000000000
--- a/spec/ruby/core/set/shared/collect.rb
+++ /dev/null
@@ -1,20 +0,0 @@
-describe :set_collect_bang, shared: true do
- before :each do
- @set = Set[1, 2, 3, 4, 5]
- end
-
- it "yields each Object in self" do
- res = []
- @set.send(@method) { |x| res << x }
- res.sort.should == [1, 2, 3, 4, 5].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 == Set[2, 4, 6, 8, 10]
- end
-end
diff --git a/spec/ruby/core/set/shared/difference.rb b/spec/ruby/core/set/shared/difference.rb
deleted file mode 100644
index f88987ed2a..0000000000
--- a/spec/ruby/core/set/shared/difference.rb
+++ /dev/null
@@ -1,15 +0,0 @@
-describe :set_difference, shared: true do
- before :each do
- @set = Set[:a, :b, :c]
- end
-
- it "returns a new Set containing self's elements excluding the elements in the passed Enumerable" do
- @set.send(@method, Set[:a, :b]).should == Set[:c]
- @set.send(@method, [:b, :c]).should == Set[: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/core/set/shared/include.rb b/spec/ruby/core/set/shared/include.rb
deleted file mode 100644
index b4d95cde24..0000000000
--- a/spec/ruby/core/set/shared/include.rb
+++ /dev/null
@@ -1,29 +0,0 @@
-describe :set_include, shared: true do
- it "returns true when self contains the passed Object" do
- set = Set[:a, :b, :c]
- set.send(@method, :a).should be_true
- set.send(@method, :e).should be_false
- end
-
- describe "member equality" do
- it "is checked using both #hash and #eql?" do
- obj = Object.new
- obj_another = Object.new
-
- def obj.hash; 42 end
- def obj_another.hash; 42 end
- def obj_another.eql?(o) hash == o.hash end
-
- set = Set["a", "b", "c", obj]
- set.send(@method, obj_another).should == true
- end
-
- it "is not checked using #==" do
- obj = Object.new
- set = Set["a", "b", "c"]
-
- obj.should_not_receive(:==)
- set.send(@method, obj)
- end
- end
-end
diff --git a/spec/ruby/core/set/shared/inspect.rb b/spec/ruby/core/set/shared/inspect.rb
deleted file mode 100644
index fbc7486acd..0000000000
--- a/spec/ruby/core/set/shared/inspect.rb
+++ /dev/null
@@ -1,45 +0,0 @@
-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)
- Set[1, 2, 3].send(@method).should be_kind_of(String)
- Set["1", "2", "3"].send(@method).should be_kind_of(String)
- Set[:a, "b", Set[?c]].send(@method).should be_kind_of(String)
- end
-
- ruby_version_is "3.5" do
- it "does include the elements of the set" do
- Set["1"].send(@method).should == 'Set["1"]'
- end
- end
-
- ruby_version_is ""..."3.5" do
- it "does include the elements of the set" do
- Set["1"].send(@method).should == '#<Set: {"1"}>'
- end
- end
-
- it "puts spaces between the elements" do
- Set["1", "2"].send(@method).should include('", "')
- end
-
- ruby_version_is "3.5" do
- 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[...]")
- end
- end
-
- ruby_version_is ""..."3.5" do
- 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: {...}>")
- end
- end
-end
diff --git a/spec/ruby/core/set/shared/intersection.rb b/spec/ruby/core/set/shared/intersection.rb
deleted file mode 100644
index 5ae4199c94..0000000000
--- a/spec/ruby/core/set/shared/intersection.rb
+++ /dev/null
@@ -1,15 +0,0 @@
-describe :set_intersection, shared: true do
- before :each do
- @set = Set[:a, :b, :c]
- end
-
- it "returns a new Set containing only elements shared by self and the passed Enumerable" do
- @set.send(@method, Set[:b, :c, :d, :e]).should == Set[:b, :c]
- @set.send(@method, [:b, :c, :d]).should == Set[: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/core/set/shared/length.rb b/spec/ruby/core/set/shared/length.rb
deleted file mode 100644
index a8fcee9f39..0000000000
--- a/spec/ruby/core/set/shared/length.rb
+++ /dev/null
@@ -1,6 +0,0 @@
-describe :set_length, shared: true do
- it "returns the number of elements in the set" do
- set = Set[:a, :b, :c]
- set.send(@method).should == 3
- end
-end
diff --git a/spec/ruby/core/set/shared/select.rb b/spec/ruby/core/set/shared/select.rb
deleted file mode 100644
index 467b236ed3..0000000000
--- a/spec/ruby/core/set/shared/select.rb
+++ /dev/null
@@ -1,41 +0,0 @@
-require_relative '../../../spec_helper'
-
-describe :set_select_bang, shared: true do
- before :each do
- @set = Set["one", "two", "three"]
- end
-
- it "yields every element of self" do
- ret = []
- @set.send(@method) { |x| ret << x }
- ret.sort.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.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.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.should_not include("one")
- @set.should_not include("two")
- @set.should include("three")
- end
-end
diff --git a/spec/ruby/core/set/shared/union.rb b/spec/ruby/core/set/shared/union.rb
deleted file mode 100644
index 314f0e852d..0000000000
--- a/spec/ruby/core/set/shared/union.rb
+++ /dev/null
@@ -1,15 +0,0 @@
-describe :set_union, shared: true do
- before :each do
- @set = Set[:a, :b, :c]
- end
-
- it "returns a new Set containing all elements of self and the passed Enumerable" do
- @set.send(@method, Set[:b, :d, :e]).should == Set[:a, :b, :c, :d, :e]
- @set.send(@method, [:b, :e]).should == Set[: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/core/set/size_spec.rb b/spec/ruby/core/set/size_spec.rb
index 4ae22c5f0a..c57272a235 100644
--- a/spec/ruby/core/set/size_spec.rb
+++ b/spec/ruby/core/set/size_spec.rb
@@ -1,6 +1,8 @@
require_relative '../../spec_helper'
-require_relative 'shared/length'
describe "Set#size" do
- it_behaves_like :set_length, :size
+ it "returns the number of elements in the set" do
+ set = Set[:a, :b, :c]
+ set.size.should == 3
+ end
end
diff --git a/spec/ruby/core/set/sortedset/sortedset_spec.rb b/spec/ruby/core/set/sortedset/sortedset_spec.rb
index 41f010e011..c8f65f0851 100644
--- a/spec/ruby/core/set/sortedset/sortedset_spec.rb
+++ b/spec/ruby/core/set/sortedset/sortedset_spec.rb
@@ -1,11 +1,11 @@
require_relative '../../../spec_helper'
describe "SortedSet" do
- ruby_version_is ""..."3.5" do
+ ruby_version_is ""..."4.0" do
it "raises error including message that it has been extracted from the set stdlib" do
-> {
SortedSet
- }.should raise_error(RuntimeError) { |e|
+ }.should.raise(RuntimeError) { |e|
e.message.should.include?("The `SortedSet` class has been extracted from the `set` library")
}
end
diff --git a/spec/ruby/core/set/subset_spec.rb b/spec/ruby/core/set/subset_spec.rb
index cde61d7cd7..81869d4993 100644
--- a/spec/ruby/core/set/subset_spec.rb
+++ b/spec/ruby/core/set/subset_spec.rb
@@ -8,38 +8,28 @@ describe "Set#subset?" do
end
it "returns true if passed a Set that is equal to self or self is a subset of" do
- @set.subset?(@set).should be_true
- Set[].subset?(Set[]).should be_true
+ @set.subset?(@set).should == true
+ Set[].subset?(Set[]).should == true
- Set[].subset?(@set).should be_true
- Set[].subset?(Set[1, 2, 3]).should be_true
- Set[].subset?(Set["a", :b, ?c]).should be_true
+ Set[].subset?(@set).should == true
+ Set[].subset?(Set[1, 2, 3]).should == true
+ Set[].subset?(Set["a", :b, ?c]).should == true
- Set[1, 2, 3].subset?(@set).should be_true
- Set[1, 3].subset?(@set).should be_true
- Set[1, 2].subset?(@set).should be_true
- Set[1].subset?(@set).should be_true
+ Set[1, 2, 3].subset?(@set).should == true
+ Set[1, 3].subset?(@set).should == true
+ Set[1, 2].subset?(@set).should == true
+ Set[1].subset?(@set).should == true
- Set[5].subset?(@set).should be_false
- Set[1, 5].subset?(@set).should be_false
- Set[nil].subset?(@set).should be_false
- Set["test"].subset?(@set).should be_false
+ Set[5].subset?(@set).should == false
+ Set[1, 5].subset?(@set).should == false
+ Set[nil].subset?(@set).should == false
+ Set["test"].subset?(@set).should == false
end
it "raises an ArgumentError when passed a non-Set" do
- -> { Set[].subset?([]) }.should raise_error(ArgumentError)
- -> { Set[].subset?(1) }.should raise_error(ArgumentError)
- -> { Set[].subset?("test") }.should raise_error(ArgumentError)
- -> { Set[].subset?(Object.new) }.should raise_error(ArgumentError)
- end
-
- version_is(set_version, ""..."1.1.0") do #ruby_version_is ""..."3.3" do
- ruby_version_is ""..."3.5" 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
- end
- end
+ -> { Set[].subset?([]) }.should.raise(ArgumentError)
+ -> { Set[].subset?(1) }.should.raise(ArgumentError)
+ -> { Set[].subset?("test") }.should.raise(ArgumentError)
+ -> { Set[].subset?(Object.new) }.should.raise(ArgumentError)
end
end
diff --git a/spec/ruby/core/set/superset_spec.rb b/spec/ruby/core/set/superset_spec.rb
index 9d7bab964a..7e7db2b179 100644
--- a/spec/ruby/core/set/superset_spec.rb
+++ b/spec/ruby/core/set/superset_spec.rb
@@ -7,35 +7,35 @@ describe "Set#superset?" do
end
it "returns true if passed a Set that equals self or self is a proper superset of" do
- @set.superset?(@set).should be_true
- Set[].superset?(Set[]).should be_true
+ @set.superset?(@set).should == true
+ Set[].superset?(Set[]).should == true
- @set.superset?(Set[]).should be_true
- Set[1, 2, 3].superset?(Set[]).should be_true
- Set["a", :b, ?c].superset?(Set[]).should be_true
+ @set.superset?(Set[]).should == true
+ Set[1, 2, 3].superset?(Set[]).should == true
+ Set["a", :b, ?c].superset?(Set[]).should == true
- @set.superset?(Set[1, 2, 3]).should be_true
- @set.superset?(Set[1, 3]).should be_true
- @set.superset?(Set[1, 2]).should be_true
- @set.superset?(Set[1]).should be_true
+ @set.superset?(Set[1, 2, 3]).should == true
+ @set.superset?(Set[1, 3]).should == true
+ @set.superset?(Set[1, 2]).should == true
+ @set.superset?(Set[1]).should == true
- @set.superset?(Set[5]).should be_false
- @set.superset?(Set[1, 5]).should be_false
- @set.superset?(Set[nil]).should be_false
- @set.superset?(Set["test"]).should be_false
+ @set.superset?(Set[5]).should == false
+ @set.superset?(Set[1, 5]).should == false
+ @set.superset?(Set[nil]).should == false
+ @set.superset?(Set["test"]).should == false
end
it "raises an ArgumentError when passed a non-Set" do
- -> { Set[].superset?([]) }.should raise_error(ArgumentError)
- -> { Set[].superset?(1) }.should raise_error(ArgumentError)
- -> { Set[].superset?("test") }.should raise_error(ArgumentError)
- -> { Set[].superset?(Object.new) }.should raise_error(ArgumentError)
+ -> { Set[].superset?([]) }.should.raise(ArgumentError)
+ -> { Set[].superset?(1) }.should.raise(ArgumentError)
+ -> { Set[].superset?("test") }.should.raise(ArgumentError)
+ -> { Set[].superset?(Object.new) }.should.raise(ArgumentError)
end
- ruby_version_is ""..."3.5" do
+ ruby_version_is ""..."4.0" do
context "when comparing to a Set-like object" do
it "returns true if passed a Set-like object that self is a superset of" do
- Set[1, 2, 3, 4].superset?(SetSpecs::SetLike.new([1, 2, 3])).should be_true
+ Set[1, 2, 3, 4].superset?(SetSpecs::SetLike.new([1, 2, 3])).should == true
end
end
end
diff --git a/spec/ruby/core/set/to_s_spec.rb b/spec/ruby/core/set/to_s_spec.rb
index 55b8bfd9b2..7f768bdcbf 100644
--- a/spec/ruby/core/set/to_s_spec.rb
+++ b/spec/ruby/core/set/to_s_spec.rb
@@ -1,11 +1,47 @@
require_relative "../../spec_helper"
-require_relative 'shared/inspect'
describe "Set#to_s" do
- it_behaves_like :set_inspect, :to_s
+ it "returns a String representation of self" do
+ Set[].to_s.should.is_a?(String)
+ Set[nil, false, true].to_s.should.is_a?(String)
+ Set[1, 2, 3].to_s.should.is_a?(String)
+ Set["1", "2", "3"].to_s.should.is_a?(String)
+ Set[:a, "b", Set[?c]].to_s.should.is_a?(String)
+ end
+
+ ruby_version_is "4.0" do
+ it "does include the elements of the set" do
+ Set["1"].to_s.should == 'Set["1"]'
+ end
+ end
+
+ ruby_version_is ""..."4.0" do
+ it "does include the elements of the set" do
+ Set["1"].to_s.should == '#<Set: {"1"}>'
+ end
+ end
+
+ it "puts spaces between the elements" do
+ Set["1", "2"].to_s.should.include?('", "')
+ end
+
+ ruby_version_is "4.0" do
+ it "correctly handles cyclic-references" do
+ set1 = Set[]
+ set2 = Set[set1]
+ set1 << set2
+ set1.to_s.should.is_a?(String)
+ set1.to_s.should.include?("Set[...]")
+ end
+ end
- it "is an alias of inspect" do
- set = Set.new
- set.method(:to_s).should == set.method(:inspect)
+ ruby_version_is ""..."4.0" do
+ it "correctly handles cyclic-references" do
+ set1 = Set[]
+ set2 = Set[set1]
+ set1 << set2
+ set1.to_s.should.is_a?(String)
+ set1.to_s.should.include?("#<Set: {...}>")
+ end
end
end
diff --git a/spec/ruby/core/set/union_spec.rb b/spec/ruby/core/set/union_spec.rb
index 3e77022d4b..206535aae2 100644
--- a/spec/ruby/core/set/union_spec.rb
+++ b/spec/ruby/core/set/union_spec.rb
@@ -1,10 +1,23 @@
require_relative '../../spec_helper'
-require_relative 'shared/union'
describe "Set#union" do
- it_behaves_like :set_union, :union
+ it "is an alias of Set#|" do
+ Set.instance_method(:union).should == Set.instance_method(:|)
+ end
end
describe "Set#|" do
- it_behaves_like :set_union, :|
+ before :each do
+ @set = Set[:a, :b, :c]
+ end
+
+ it "returns a new Set containing all elements of self and the passed Enumerable" do
+ (@set | Set[:b, :d, :e]).should == Set[:a, :b, :c, :d, :e]
+ (@set | [:b, :e]).should == Set[:a, :b, :c, :e]
+ end
+
+ it "raises an ArgumentError when passed a non-Enumerable" do
+ -> { @set | 1 }.should.raise(ArgumentError)
+ -> { @set | Object.new }.should.raise(ArgumentError)
+ end
end
diff --git a/spec/ruby/core/signal/signame_spec.rb b/spec/ruby/core/signal/signame_spec.rb
index adfe895d97..82f040a6f9 100644
--- a/spec/ruby/core/signal/signame_spec.rb
+++ b/spec/ruby/core/signal/signame_spec.rb
@@ -16,13 +16,13 @@ describe "Signal.signame" do
end
it "raises a TypeError when the passed argument can't be coerced to Integer" do
- -> { Signal.signame("hello") }.should raise_error(TypeError)
+ -> { Signal.signame("hello") }.should.raise(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)
+ -> { Signal.signame(obj) }.should.raise(TypeError)
end
platform_is_not :windows do
diff --git a/spec/ruby/core/signal/trap_spec.rb b/spec/ruby/core/signal/trap_spec.rb
index 6d654a99be..5d3105fee8 100644
--- a/spec/ruby/core/signal/trap_spec.rb
+++ b/spec/ruby/core/signal/trap_spec.rb
@@ -14,7 +14,7 @@ describe "Signal.trap" do
end
it "returns the previous handler" do
- Signal.trap(:HUP, @saved_trap).should equal(@proc)
+ Signal.trap(:HUP, @saved_trap).should.equal?(@proc)
end
it "accepts a block" do
@@ -97,7 +97,7 @@ describe "Signal.trap" do
-> {
Process.kill :HUP, Process.pid
loop { Thread.pass }
- }.should raise_error(NoMethodError)
+ }.should.raise(NoMethodError)
end
it "accepts a non-callable that becomes callable when used" do
@@ -134,7 +134,7 @@ describe "Signal.trap" do
Process.kill :HUP, Process.pid
Thread.pass until done
- ScratchPad.recorded.should be_true
+ ScratchPad.recorded.should == true
end
it "registers an handler doing nothing with :IGNORE" do
@@ -158,7 +158,7 @@ describe "Signal.trap" do
it "ignores the signal when passed nil" do
Signal.trap :HUP, nil
- Signal.trap(:HUP, @saved_trap).should be_nil
+ Signal.trap(:HUP, @saved_trap).should == nil
end
it "accepts :DEFAULT in place of a proc" do
@@ -203,53 +203,53 @@ describe "Signal.trap" do
it "accepts long names as Strings" do
Signal.trap "SIGHUP", @proc
- Signal.trap("SIGHUP", @saved_trap).should equal(@proc)
+ Signal.trap("SIGHUP", @saved_trap).should.equal?(@proc)
end
it "accepts short names as Strings" do
Signal.trap "HUP", @proc
- Signal.trap("HUP", @saved_trap).should equal(@proc)
+ Signal.trap("HUP", @saved_trap).should.equal?(@proc)
end
it "accepts long names as Symbols" do
Signal.trap :SIGHUP, @proc
- Signal.trap(:SIGHUP, @saved_trap).should equal(@proc)
+ Signal.trap(:SIGHUP, @saved_trap).should.equal?(@proc)
end
it "accepts short names as Symbols" do
Signal.trap :HUP, @proc
- Signal.trap(:HUP, @saved_trap).should equal(@proc)
+ 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)
+ 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)
+ 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/)
+ -> { Signal.trap obj, @proc }.should.raise(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(300) { } }.should.raise(ArgumentError, "invalid signal number (300)")
+ -> { Signal.trap("USR10") { } }.should.raise(ArgumentError, /\Aunsupported signal [`']SIGUSR10'\z/)
+ -> { Signal.trap("SIGUSR10") { } }.should.raise(ArgumentError, /\Aunsupported signal [`']SIGUSR10'\z/)
end
it "raises ArgumentError when passed signal is not Integer, String or Symbol" do
- -> { Signal.trap(nil) { } }.should raise_error(ArgumentError, "bad signal type NilClass")
- -> { Signal.trap(100.0) { } }.should raise_error(ArgumentError, "bad signal type Float")
- -> { Signal.trap(Rational(100)) { } }.should raise_error(ArgumentError, "bad signal type Rational")
+ -> { Signal.trap(nil) { } }.should.raise(ArgumentError, "bad signal type NilClass")
+ -> { Signal.trap(100.0) { } }.should.raise(ArgumentError, "bad signal type Float")
+ -> { Signal.trap(Rational(100)) { } }.should.raise(ArgumentError, "bad signal type Rational")
end
# See man 2 signal
@@ -257,8 +257,8 @@ describe "Signal.trap" do
it "raises ArgumentError or Errno::EINVAL for SIG#{signal}" do
-> {
Signal.trap(signal, -> {})
- }.should raise_error(StandardError) { |e|
- [ArgumentError, Errno::EINVAL].should include(e.class)
+ }.should.raise(StandardError) { |e|
+ [ArgumentError, Errno::EINVAL].should.include?(e.class)
e.message.should =~ /Invalid argument|Signal already used by VM or OS/
}
end
@@ -268,7 +268,7 @@ describe "Signal.trap" do
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}")
+ }.should.raise(ArgumentError, "can't trap reserved signal: SIG#{signal}")
end
end
diff --git a/spec/ruby/core/sizedqueue/deq_spec.rb b/spec/ruby/core/sizedqueue/deq_spec.rb
index 2aeb52f8a6..51ff706557 100644
--- a/spec/ruby/core/sizedqueue/deq_spec.rb
+++ b/spec/ruby/core/sizedqueue/deq_spec.rb
@@ -1,11 +1,7 @@
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
- it_behaves_like :rb_num2dbl_fails, nil, -> v { q = SizedQueue.new(10); q.push(1); q.deq(timeout: v) }
+ it "is an alias of SizedQueue#pop" do
+ SizedQueue.instance_method(:deq).should == SizedQueue.instance_method(:pop)
+ end
end
diff --git a/spec/ruby/core/sizedqueue/enq_spec.rb b/spec/ruby/core/sizedqueue/enq_spec.rb
index b955909475..94697cd247 100644
--- a/spec/ruby/core/sizedqueue/enq_spec.rb
+++ b/spec/ruby/core/sizedqueue/enq_spec.rb
@@ -1,16 +1,7 @@
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) }
-end
-
-describe "SizedQueue#enq" do
- it_behaves_like :sizedqueue_enq, :enq, -> n { SizedQueue.new(n) }
-end
-
-describe "SizedQueue operations with timeout" do
- it_behaves_like :rb_num2dbl_fails, nil, -> v { q = SizedQueue.new(1); q.enq(1, timeout: v) }
+ it "is an alias of SizedQueue#<<" do
+ SizedQueue.instance_method(:enq).should == SizedQueue.instance_method(:<<)
+ end
end
diff --git a/spec/ruby/core/sizedqueue/length_spec.rb b/spec/ruby/core/sizedqueue/length_spec.rb
index b93e7f8997..b9d16d8932 100644
--- a/spec/ruby/core/sizedqueue/length_spec.rb
+++ b/spec/ruby/core/sizedqueue/length_spec.rb
@@ -1,6 +1,7 @@
require_relative '../../spec_helper'
-require_relative '../../shared/queue/length'
describe "SizedQueue#length" do
- it_behaves_like :queue_length, :length, -> { SizedQueue.new(10) }
+ it "is an alias of SizedQueue#size" do
+ SizedQueue.instance_method(:length).should == SizedQueue.instance_method(:size)
+ end
end
diff --git a/spec/ruby/core/sizedqueue/push_spec.rb b/spec/ruby/core/sizedqueue/push_spec.rb
index 9eaa6beca0..943d0fcfb4 100644
--- a/spec/ruby/core/sizedqueue/push_spec.rb
+++ b/spec/ruby/core/sizedqueue/push_spec.rb
@@ -1,16 +1,7 @@
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) }
-end
-
-describe "SizedQueue#push" do
- it_behaves_like :sizedqueue_enq, :push, -> n { SizedQueue.new(n) }
-end
-
-describe "SizedQueue operations with timeout" do
- it_behaves_like :rb_num2dbl_fails, nil, -> v { q = SizedQueue.new(1); q.push(1, timeout: v) }
+ it "is an alias of SizedQueue#<<" do
+ SizedQueue.instance_method(:push).should == SizedQueue.instance_method(:<<)
+ end
end
diff --git a/spec/ruby/core/sizedqueue/shift_spec.rb b/spec/ruby/core/sizedqueue/shift_spec.rb
index 52974c1d99..f410f3f80d 100644
--- a/spec/ruby/core/sizedqueue/shift_spec.rb
+++ b/spec/ruby/core/sizedqueue/shift_spec.rb
@@ -1,11 +1,7 @@
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
- it_behaves_like :rb_num2dbl_fails, nil, -> v { q = SizedQueue.new(10); q.push(1); q.shift(timeout: v) }
+ it "is an alias of SizedQueue#pop" do
+ SizedQueue.instance_method(:shift).should == SizedQueue.instance_method(:pop)
+ end
end
diff --git a/spec/ruby/core/string/allocate_spec.rb b/spec/ruby/core/string/allocate_spec.rb
index 30d5f60594..00dadaf076 100644
--- a/spec/ruby/core/string/allocate_spec.rb
+++ b/spec/ruby/core/string/allocate_spec.rb
@@ -3,7 +3,7 @@ require_relative '../../spec_helper'
describe "String.allocate" do
it "returns an instance of String" do
str = String.allocate
- str.should be_an_instance_of(String)
+ str.should.instance_of?(String)
end
it "returns a fully-formed String" do
diff --git a/spec/ruby/core/string/append_as_bytes_spec.rb b/spec/ruby/core/string/append_as_bytes_spec.rb
index b1703e5f89..feead64615 100644
--- a/spec/ruby/core/string/append_as_bytes_spec.rb
+++ b/spec/ruby/core/string/append_as_bytes_spec.rb
@@ -4,17 +4,19 @@ 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)
+ -> { str.append_as_bytes("\xE2\x82") }.should.raise(FrozenError)
end
- it "allows creating broken strings" do
+ it "allows creating broken strings in UTF8" do
str = +"hello"
str.append_as_bytes("\xE2\x82")
str.valid_encoding?.should == false
str.append_as_bytes("\xAC")
str.valid_encoding?.should == true
+ end
+ it "allows creating broken strings in UTF_32" do
str = "abc".encode(Encoding::UTF_32LE)
str.append_as_bytes("def")
str.encoding.should == Encoding::UTF_32LE
@@ -52,7 +54,7 @@ describe "String#append_bytes" do
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)")
+ -> { str.append_as_bytes(to_str) }.should.raise(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..e0f71b7c97 100644
--- a/spec/ruby/core/string/append_spec.rb
+++ b/spec/ruby/core/string/append_spec.rb
@@ -8,7 +8,7 @@ describe "String#<<" do
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)
- -> { "hello".send(:<<, "one", "two") }.should raise_error(ArgumentError)
+ -> { "hello".send(:<<) }.should.raise(ArgumentError)
+ -> { "hello".send(:<<, "one", "two") }.should.raise(ArgumentError)
end
end
diff --git a/spec/ruby/core/string/ascii_only_spec.rb b/spec/ruby/core/string/ascii_only_spec.rb
index 88a0559cfd..9af663beb8 100644
--- a/spec/ruby/core/string/ascii_only_spec.rb
+++ b/spec/ruby/core/string/ascii_only_spec.rb
@@ -12,13 +12,13 @@ describe "String#ascii_only?" do
end
it "returns true if the encoding is US-ASCII" do
- "hello".dup.force_encoding(Encoding::US_ASCII).ascii_only?.should be_true
- "hello".encode(Encoding::US_ASCII).ascii_only?.should be_true
+ "hello".dup.force_encoding(Encoding::US_ASCII).ascii_only?.should == true
+ "hello".encode(Encoding::US_ASCII).ascii_only?.should == true
end
it "returns true for all single-character UTF-8 Strings" do
0.upto(127) do |n|
- n.chr.ascii_only?.should be_true
+ n.chr.ascii_only?.should == true
end
end
end
@@ -27,7 +27,7 @@ describe "String#ascii_only?" do
it "returns false if the encoding is BINARY" do
chr = 128.chr
chr.encoding.should == Encoding::BINARY
- chr.ascii_only?.should be_false
+ chr.ascii_only?.should == false
end
it "returns false if the String contains any non-ASCII characters" do
@@ -46,37 +46,37 @@ describe "String#ascii_only?" do
end
it "returns true for the empty String with an ASCII-compatible encoding" do
- "".ascii_only?.should be_true
- "".encode('UTF-8').ascii_only?.should be_true
+ "".ascii_only?.should == true
+ "".encode('UTF-8').ascii_only?.should == true
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
- "".encode('UTF-16BE').ascii_only?.should be_false
+ "".dup.force_encoding('UTF-16LE').ascii_only?.should == false
+ "".encode('UTF-16BE').ascii_only?.should == 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".dup.force_encoding("UTF-16LE").ascii_only?.should == false
end
it "returns false when interpolating non ascii strings" do
base = "EU currency is".dup.force_encoding(Encoding::US_ASCII)
euro = "\u20AC"
interp = "#{base} #{euro}"
- euro.ascii_only?.should be_false
- base.ascii_only?.should be_true
- interp.ascii_only?.should be_false
+ euro.ascii_only?.should == false
+ base.ascii_only?.should == true
+ interp.ascii_only?.should == false
end
it "returns false after appending non ASCII characters to an empty String" do
- ("".dup << "λ").ascii_only?.should be_false
+ ("".dup << "λ").ascii_only?.should == false
end
it "returns false when concatenating an ASCII and non-ASCII String" do
- "".dup.concat("λ").ascii_only?.should be_false
+ "".dup.concat("λ").ascii_only?.should == false
end
it "returns false when replacing an ASCII String with a non-ASCII String" do
- "".dup.replace("λ").ascii_only?.should be_false
+ "".dup.replace("λ").ascii_only?.should == false
end
end
diff --git a/spec/ruby/core/string/b_spec.rb b/spec/ruby/core/string/b_spec.rb
index 4b1fafff11..d181447709 100644
--- a/spec/ruby/core/string/b_spec.rb
+++ b/spec/ruby/core/string/b_spec.rb
@@ -10,7 +10,7 @@ describe "String#b" do
it "returns new string without modifying self" do
str = "ã“ã‚“ã¡ã«ã¯"
- str.b.should_not equal(str)
+ str.b.should_not.equal?(str)
str.should == "ã“ã‚“ã¡ã«ã¯"
end
end
diff --git a/spec/ruby/core/string/byteindex_spec.rb b/spec/ruby/core/string/byteindex_spec.rb
index d420f3f683..f4c6408790 100644
--- a/spec/ruby/core/string/byteindex_spec.rb
+++ b/spec/ruby/core/string/byteindex_spec.rb
@@ -149,7 +149,7 @@ describe "String#byteindex with String" do
char = "れ".encode Encoding::EUC_JP
-> do
"ã‚れ".byteindex(char)
- end.should raise_error(Encoding::CompatibilityError)
+ end.should.raise(Encoding::CompatibilityError)
end
it "handles a substring in a superset encoding" do
@@ -255,7 +255,7 @@ describe "String#byteindex with Regexp" do
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
+ "ruby".byteindex(//, 12).should == nil
end
it "supports \\G which matches at the given start offset" do
diff --git a/spec/ruby/core/string/byterindex_spec.rb b/spec/ruby/core/string/byterindex_spec.rb
index 983222e35d..569820463d 100644
--- a/spec/ruby/core/string/byterindex_spec.rb
+++ b/spec/ruby/core/string/byterindex_spec.rb
@@ -184,7 +184,7 @@ describe "String#byterindex with String" do
end
it "raises a TypeError when given offset is nil" do
- -> { "str".byterindex("st", nil) }.should raise_error(TypeError)
+ -> { "str".byterindex("st", nil) }.should.raise(TypeError)
end
it "handles a substring in a superset encoding" do
@@ -338,7 +338,7 @@ describe "String#byterindex with Regexp" do
end
it "raises a TypeError when given offset is nil" do
- -> { "str".byterindex(/../, nil) }.should raise_error(TypeError)
+ -> { "str".byterindex(/../, nil) }.should.raise(TypeError)
end
it "returns the reverse byte index of a multibyte character" do
diff --git a/spec/ruby/core/string/bytes_spec.rb b/spec/ruby/core/string/bytes_spec.rb
index 02151eebbc..e6019fb987 100644
--- a/spec/ruby/core/string/bytes_spec.rb
+++ b/spec/ruby/core/string/bytes_spec.rb
@@ -9,7 +9,7 @@ describe "String#bytes" do
end
it "returns an Array when no block is given" do
- @utf8.bytes.should be_an_instance_of(Array)
+ @utf8.bytes.should.instance_of?(Array)
end
it "yields each byte to a block if one is given, returning self" do
@@ -23,8 +23,8 @@ describe "String#bytes" do
end
it "returns bytes as Integers" do
- @ascii.bytes.to_a.each {|b| b.should be_an_instance_of(Integer)}
- @utf8_ascii.bytes { |b| b.should be_an_instance_of(Integer) }
+ @ascii.bytes.to_a.each {|b| b.should.instance_of?(Integer)}
+ @utf8_ascii.bytes { |b| b.should.instance_of?(Integer) }
end
it "agrees with #unpack('C*')" do
diff --git a/spec/ruby/core/string/bytesplice_spec.rb b/spec/ruby/core/string/bytesplice_spec.rb
index 2c770e340a..3e5e6fe1ee 100644
--- a/spec/ruby/core/string/bytesplice_spec.rb
+++ b/spec/ruby/core/string/bytesplice_spec.rb
@@ -4,15 +4,15 @@ require_relative '../../spec_helper'
describe "String#bytesplice" 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")
+ -> { "hello".bytesplice(-6, 0, "xxx") }.should.raise(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")
+ -> { "hello".bytesplice(6, 0, "xxx") }.should.raise(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")
+ -> { "abc".bytesplice(0, -2, "") }.should.raise(IndexError, "negative length -2")
end
it "replaces with integer indices" do
@@ -24,7 +24,7 @@ describe "String#bytesplice" do
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")
+ -> { "hello".bytesplice(-6...-6, "xxx") }.should.raise(RangeError, "-6...-6 out of range")
end
it "replaces with ranges" do
@@ -39,7 +39,7 @@ describe "String#bytesplice" do
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)")
+ -> { "hello".bytesplice(0, "xxx") }.should.raise(TypeError, "wrong argument type Integer (expected Range)")
end
it "replaces on an empty string" do
@@ -54,95 +54,93 @@ describe "String#bytesplice" do
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
-
- ruby_version_is "3.3" do
- it "raises IndexError when str_index is less than -bytesize" do
- -> { "hello".bytesplice(2, 1, "HELLO", -6, 0) }.should raise_error(IndexError, "index -6 out of string")
- end
-
- it "raises IndexError when str_index is greater than bytesize" do
- -> { "hello".bytesplice(2, 1, "HELLO", 6, 0) }.should raise_error(IndexError, "index 6 out of string")
- end
-
- it "raises IndexError for negative str length" do
- -> { "abc".bytesplice(0, 1, "", 0, -2) }.should raise_error(IndexError, "negative length -2")
- end
-
- it "replaces with integer str indices" do
- "hello".bytesplice(1, 2, "HELLO", -5, 0).should == "hlo"
- "hello".bytesplice(1, 2, "HELLO", 0, 0).should == "hlo"
- "hello".bytesplice(1, 2, "HELLO", 0, 1).should == "hHlo"
- "hello".bytesplice(1, 2, "HELLO", 0, 5).should == "hHELLOlo"
- "hello".bytesplice(1, 2, "HELLO", 0, 6).should == "hHELLOlo"
- end
-
- it "raises RangeError when str range left boundary is less than -bytesize" do
- -> { "hello".bytesplice(0..1, "HELLO", -6...-6) }.should raise_error(RangeError, "-6...-6 out of range")
- end
-
- it "replaces with str ranges" do
- "hello".bytesplice(1..2, "HELLO", -5...-5).should == "hlo"
- "hello".bytesplice(1..2, "HELLO", 0...0).should == "hlo"
- "hello".bytesplice(1..2, "HELLO", 0..0).should == "hHlo"
- "hello".bytesplice(1..2, "HELLO", 0...1).should == "hHlo"
- "hello".bytesplice(1..2, "HELLO", 0..1).should == "hHElo"
- "hello".bytesplice(1..2, "HELLO", 0..-1).should == "hHELLOlo"
- "hello".bytesplice(1..2, "HELLO", 0...5).should == "hHELLOlo"
- "hello".bytesplice(1..2, "HELLO", 0...6).should == "hHELLOlo"
- end
-
- it "raises ArgumentError when integer str index is provided without str length argument" do
- -> { "hello".bytesplice(0, 1, "xxx", 0) }.should raise_error(ArgumentError, "wrong number of arguments (given 4, expected 2, 3, or 5)")
- end
-
- it "replaces on an empty string with str index/length" do
- "".bytesplice(0, 0, "", 0, 0).should == ""
- "".bytesplice(0, 0, "xxx", 0, 1).should == "x"
- end
-
- it "mutates self with substring and str index/length" do
- s = "hello"
- s.bytesplice(2, 1, "xxx", 1, 2).should.equal?(s)
- s.should.eql?("hexxlo")
- end
-
- it "raises when string is frozen and str index/length" do
- s = "hello".freeze
- -> { s.bytesplice(2, 1, "xxx", 0, 1) }.should raise_error(FrozenError, "can't modify frozen String: \"hello\"")
- end
-
- it "replaces on an empty string with str range" do
- "".bytesplice(0..0, "", 0..0).should == ""
- "".bytesplice(0..0, "xyz", 0..1).should == "xy"
- end
-
- it "mutates self with substring and str range" do
- s = "hello"
- s.bytesplice(2..2, "xyz", 1..2).should.equal?(s)
- s.should.eql?("heyzlo")
- end
-
- it "raises when string is frozen and str range" do
- s = "hello".freeze
- -> { s.bytesplice(2..2, "yzx", 0..1) }.should raise_error(FrozenError, "can't modify frozen String: \"hello\"")
- end
+ -> { s.bytesplice(2, 1, "xxx") }.should.raise(FrozenError, "can't modify frozen String: \"hello\"")
+ end
+
+ it "raises IndexError when str_index is less than -bytesize" do
+ -> { "hello".bytesplice(2, 1, "HELLO", -6, 0) }.should.raise(IndexError, "index -6 out of string")
+ end
+
+ it "raises IndexError when str_index is greater than bytesize" do
+ -> { "hello".bytesplice(2, 1, "HELLO", 6, 0) }.should.raise(IndexError, "index 6 out of string")
+ end
+
+ it "raises IndexError for negative str length" do
+ -> { "abc".bytesplice(0, 1, "", 0, -2) }.should.raise(IndexError, "negative length -2")
+ end
+
+ it "replaces with integer str indices" do
+ "hello".bytesplice(1, 2, "HELLO", -5, 0).should == "hlo"
+ "hello".bytesplice(1, 2, "HELLO", 0, 0).should == "hlo"
+ "hello".bytesplice(1, 2, "HELLO", 0, 1).should == "hHlo"
+ "hello".bytesplice(1, 2, "HELLO", 0, 5).should == "hHELLOlo"
+ "hello".bytesplice(1, 2, "HELLO", 0, 6).should == "hHELLOlo"
+ end
+
+ it "raises RangeError when str range left boundary is less than -bytesize" do
+ -> { "hello".bytesplice(0..1, "HELLO", -6...-6) }.should.raise(RangeError, "-6...-6 out of range")
+ end
+
+ it "replaces with str ranges" do
+ "hello".bytesplice(1..2, "HELLO", -5...-5).should == "hlo"
+ "hello".bytesplice(1..2, "HELLO", 0...0).should == "hlo"
+ "hello".bytesplice(1..2, "HELLO", 0..0).should == "hHlo"
+ "hello".bytesplice(1..2, "HELLO", 0...1).should == "hHlo"
+ "hello".bytesplice(1..2, "HELLO", 0..1).should == "hHElo"
+ "hello".bytesplice(1..2, "HELLO", 0..-1).should == "hHELLOlo"
+ "hello".bytesplice(1..2, "HELLO", 0...5).should == "hHELLOlo"
+ "hello".bytesplice(1..2, "HELLO", 0...6).should == "hHELLOlo"
+ end
+
+ it "raises ArgumentError when integer str index is provided without str length argument" do
+ -> { "hello".bytesplice(0, 1, "xxx", 0) }.should.raise(ArgumentError, "wrong number of arguments (given 4, expected 2, 3, or 5)")
+ end
+
+ it "replaces on an empty string with str index/length" do
+ "".bytesplice(0, 0, "", 0, 0).should == ""
+ "".bytesplice(0, 0, "xxx", 0, 1).should == "x"
+ end
+
+ it "mutates self with substring and str index/length" do
+ s = "hello"
+ s.bytesplice(2, 1, "xxx", 1, 2).should.equal?(s)
+ s.should.eql?("hexxlo")
+ end
+
+ it "raises when string is frozen and str index/length" do
+ s = "hello".freeze
+ -> { s.bytesplice(2, 1, "xxx", 0, 1) }.should.raise(FrozenError, "can't modify frozen String: \"hello\"")
+ end
+
+ it "replaces on an empty string with str range" do
+ "".bytesplice(0..0, "", 0..0).should == ""
+ "".bytesplice(0..0, "xyz", 0..1).should == "xy"
+ end
+
+ it "mutates self with substring and str range" do
+ s = "hello"
+ s.bytesplice(2..2, "xyz", 1..2).should.equal?(s)
+ s.should.eql?("heyzlo")
+ end
+
+ it "raises when string is frozen and str range" do
+ s = "hello".freeze
+ -> { s.bytesplice(2..2, "yzx", 0..1) }.should.raise(FrozenError, "can't modify frozen String: \"hello\"")
end
end
describe "String#bytesplice with multibyte characters" 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")
+ -> { "ã“ã‚“ã«ã¡ã¯".bytesplice(-16, 0, "xxx") }.should.raise(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")
+ -> { "ã“ã‚“ã«ã¡ã¯".bytesplice(1, 0, "xxx") }.should.raise(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")
+ -> { "ã“ã‚“ã«ã¡ã¯".bytesplice(0, 1, "xxx") }.should.raise(IndexError, "offset 1 does not land on character boundary")
+ -> { "ã“ã‚“ã«ã¡ã¯".bytesplice(0, 2, "xxx") }.should.raise(IndexError, "offset 2 does not land on character boundary")
end
it "replaces with integer indices" do
@@ -171,14 +169,14 @@ describe "String#bytesplice with multibyte characters" do
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")
+ -> { "ã“ã‚“ã«ã¡ã¯".bytesplice(0..0, "x") }.should.raise(IndexError, "offset 1 does not land on character boundary")
+ -> { "ã“ã‚“ã«ã¡ã¯".bytesplice(0..1, "x") }.should.raise(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")
+ -> { "ã“ã‚“ã«ã¡ã¯".bytesplice(-4..-1, "x") }.should.raise(IndexError, "offset 11 does not land on character boundary")
+ -> { "ã“ã‚“ã«ã¡ã¯".bytesplice(-5..-1, "x") }.should.raise(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")
+ -> { "ã“ã‚“ã«ã¡ã¯".bytesplice(-3..-2, "x") }.should.raise(IndexError, "offset 14 does not land on character boundary")
+ -> { "ã“ã‚“ã«ã¡ã¯".bytesplice(-3..-3, "x") }.should.raise(IndexError, "offset 13 does not land on character boundary")
end
it "deals with a different encoded argument" do
@@ -201,94 +199,92 @@ describe "String#bytesplice with multibyte characters" do
result.encoding.should == Encoding::UTF_8
end
- ruby_version_is "3.3" do
- it "raises IndexError when str_index is out of byte size boundary" do
- -> { "ã“ã‚“ã«ã¡ã¯".bytesplice(3, 3, "ã“ã‚“ã«ã¡ã¯", -16, 0) }.should raise_error(IndexError, "index -16 out of string")
- end
-
- it "raises IndexError when str_index is not on a codepoint boundary" do
- -> { "ã“ã‚“ã«ã¡ã¯".bytesplice(3, 3, "ã“ã‚“ã«ã¡ã¯", 1, 0) }.should raise_error(IndexError, "offset 1 does not land on character boundary")
- end
-
- it "raises IndexError when str_length is not matching the codepoint boundary" do
- -> { "ã“ã‚“ã«ã¡ã¯".bytesplice(3, 3, "ã“ã‚“ã«ã¡ã¯", 0, 1) }.should raise_error(IndexError, "offset 1 does not land on character boundary")
- -> { "ã“ã‚“ã«ã¡ã¯".bytesplice(3, 3, "ã“ã‚“ã«ã¡ã¯", 0, 2) }.should raise_error(IndexError, "offset 2 does not land on character boundary")
- end
-
- it "replaces with integer str indices" do
- "ã“ã‚“ã«ã¡ã¯".bytesplice(3, 3, "ã“ã‚“ã«ã¡ã¯", -15, 0).should == "ã“ã«ã¡ã¯"
- "ã“ã‚“ã«ã¡ã¯".bytesplice(3, 3, "ã“ã‚“ã«ã¡ã¯", 0, 0).should == "ã“ã«ã¡ã¯"
- "ã“ã‚“ã«ã¡ã¯".bytesplice(3, 3, "ã“ã‚“ã«ã¡ã¯", 0, 3).should == "ã“ã“ã«ã¡ã¯"
- "ã“ã‚“ã«ã¡ã¯".bytesplice(3, 3, "ã¯ã¯", 3, 3).should == "ã“ã¯ã«ã¡ã¯"
- "ã“ã‚“ã«ã¡ã¯".bytesplice(3, 3, "ã“ã‚“ã«ã¡ã¯", 15, 0).should == "ã“ã«ã¡ã¯"
- end
-
- it "replaces with str range" do
- "ã“ã‚“ã«ã¡ã¯".bytesplice(0..2, "ã“ã‚“ã«ã¡ã¯", -15...-16).should == "ã‚“ã«ã¡ã¯"
- "ã“ã‚“ã«ã¡ã¯".bytesplice(0..2, "ã“ã‚“ã«ã¡ã¯", 0...0).should == "ã‚“ã«ã¡ã¯"
- "ã“ã‚“ã«ã¡ã¯".bytesplice(0..2, "ã“ã‚“ã«ã¡ã¯", 3..5).should == "ã‚“ã‚“ã«ã¡ã¯"
- "ã“ã‚“ã«ã¡ã¯".bytesplice(0..2, "ã“ã‚“ã«ã¡ã¯", 3...6).should == "ã‚“ã‚“ã«ã¡ã¯"
- "ã“ã‚“ã«ã¡ã¯".bytesplice(0..2, "ã“ã‚“ã«ã¡ã¯", 3..8).should == "ã‚“ã«ã‚“ã«ã¡ã¯"
- "ã“ã‚“ã«ã¡ã¯".bytesplice(0..2, "ã“ã‚“ã«ã¡ã¯", 0..-1).should == "ã“ã‚“ã«ã¡ã¯ã‚“ã«ã¡ã¯"
- "ã“ã‚“ã«ã¡ã¯".bytesplice(0..2, "ã“ã‚“ã«ã¡ã¯", 0...15).should == "ã“ã‚“ã«ã¡ã¯ã‚“ã«ã¡ã¯"
- "ã“ã‚“ã«ã¡ã¯".bytesplice(0..2, "ã“ã‚“ã«ã¡ã¯", 0...18).should == "ã“ã‚“ã«ã¡ã¯ã‚“ã«ã¡ã¯"
- end
-
- it "treats negative length for str range as 0" do
- "ã“ã‚“ã«ã¡ã¯".bytesplice(0..2, "ã“ã‚“ã«ã¡ã¯", 0...-100).should == "ã‚“ã«ã¡ã¯"
- "ã“ã‚“ã«ã¡ã¯".bytesplice(0..2, "ã“ã‚“ã«ã¡ã¯", 3...-100).should == "ã‚“ã«ã¡ã¯"
- "ã“ã‚“ã«ã¡ã¯".bytesplice(0..2, "ã“ã‚“ã«ã¡ã¯", -15...-100).should == "ã‚“ã«ã¡ã¯"
- end
-
- it "raises when ranges not match codepoint boundaries in str" do
- -> { "ã“ã‚“ã«ã¡ã¯".bytesplice(3...3, "ã“", 0..0) }.should raise_error(IndexError, "offset 1 does not land on character boundary")
- -> { "ã“ã‚“ã«ã¡ã¯".bytesplice(3...3, "ã“", 0..1) }.should raise_error(IndexError, "offset 2 does not land on character boundary")
- # Begin is incorrect
- -> { "ã“ã‚“ã«ã¡ã¯".bytesplice(3...3, "ã“ã‚“ã«ã¡ã¯", -4..-1) }.should raise_error(IndexError, "offset 11 does not land on character boundary")
- -> { "ã“ã‚“ã«ã¡ã¯".bytesplice(3...3, "ã“ã‚“ã«ã¡ã¯", -5..-1) }.should raise_error(IndexError, "offset 10 does not land on character boundary")
- # End is incorrect
- -> { "ã“ã‚“ã«ã¡ã¯".bytesplice(3...3, "ã“ã‚“ã«ã¡ã¯", -3..-2) }.should raise_error(IndexError, "offset 14 does not land on character boundary")
- -> { "ã“ã‚“ã«ã¡ã¯".bytesplice(3...3, "ã“ã‚“ã«ã¡ã¯", -3..-3) }.should raise_error(IndexError, "offset 13 does not land on character boundary")
- end
-
- it "deals with a different encoded argument with str index/length" do
- s = "ã“ã‚“ã«ã¡ã¯"
- s.encoding.should == Encoding::UTF_8
- sub = "goodbye"
- sub.force_encoding(Encoding::US_ASCII)
-
- result = s.bytesplice(3, 3, sub, 0, 3)
- result.should == "ã“gooã«ã¡ã¯"
- result.encoding.should == Encoding::UTF_8
-
- s = "hello"
- s.force_encoding(Encoding::US_ASCII)
- sub = "ã“ã‚“ã«ã¡ã¯"
- sub.encoding.should == Encoding::UTF_8
-
- result = s.bytesplice(1, 2, sub, 3, 3)
- result.should == "hã‚“lo"
- result.encoding.should == Encoding::UTF_8
- end
-
- it "deals with a different encoded argument with str range" do
- s = "ã“ã‚“ã«ã¡ã¯"
- s.encoding.should == Encoding::UTF_8
- sub = "goodbye"
- sub.force_encoding(Encoding::US_ASCII)
-
- result = s.bytesplice(3..5, sub, 0..2)
- result.should == "ã“gooã«ã¡ã¯"
- result.encoding.should == Encoding::UTF_8
-
- s = "hello"
- s.force_encoding(Encoding::US_ASCII)
- sub = "ã“ã‚“ã«ã¡ã¯"
- sub.encoding.should == Encoding::UTF_8
-
- result = s.bytesplice(1..2, sub, 3..5)
- result.should == "hã‚“lo"
- result.encoding.should == Encoding::UTF_8
- end
+ it "raises IndexError when str_index is out of byte size boundary" do
+ -> { "ã“ã‚“ã«ã¡ã¯".bytesplice(3, 3, "ã“ã‚“ã«ã¡ã¯", -16, 0) }.should.raise(IndexError, "index -16 out of string")
+ end
+
+ it "raises IndexError when str_index is not on a codepoint boundary" do
+ -> { "ã“ã‚“ã«ã¡ã¯".bytesplice(3, 3, "ã“ã‚“ã«ã¡ã¯", 1, 0) }.should.raise(IndexError, "offset 1 does not land on character boundary")
+ end
+
+ it "raises IndexError when str_length is not matching the codepoint boundary" do
+ -> { "ã“ã‚“ã«ã¡ã¯".bytesplice(3, 3, "ã“ã‚“ã«ã¡ã¯", 0, 1) }.should.raise(IndexError, "offset 1 does not land on character boundary")
+ -> { "ã“ã‚“ã«ã¡ã¯".bytesplice(3, 3, "ã“ã‚“ã«ã¡ã¯", 0, 2) }.should.raise(IndexError, "offset 2 does not land on character boundary")
+ end
+
+ it "replaces with integer str indices" do
+ "ã“ã‚“ã«ã¡ã¯".bytesplice(3, 3, "ã“ã‚“ã«ã¡ã¯", -15, 0).should == "ã“ã«ã¡ã¯"
+ "ã“ã‚“ã«ã¡ã¯".bytesplice(3, 3, "ã“ã‚“ã«ã¡ã¯", 0, 0).should == "ã“ã«ã¡ã¯"
+ "ã“ã‚“ã«ã¡ã¯".bytesplice(3, 3, "ã“ã‚“ã«ã¡ã¯", 0, 3).should == "ã“ã“ã«ã¡ã¯"
+ "ã“ã‚“ã«ã¡ã¯".bytesplice(3, 3, "ã¯ã¯", 3, 3).should == "ã“ã¯ã«ã¡ã¯"
+ "ã“ã‚“ã«ã¡ã¯".bytesplice(3, 3, "ã“ã‚“ã«ã¡ã¯", 15, 0).should == "ã“ã«ã¡ã¯"
+ end
+
+ it "replaces with str range" do
+ "ã“ã‚“ã«ã¡ã¯".bytesplice(0..2, "ã“ã‚“ã«ã¡ã¯", -15...-16).should == "ã‚“ã«ã¡ã¯"
+ "ã“ã‚“ã«ã¡ã¯".bytesplice(0..2, "ã“ã‚“ã«ã¡ã¯", 0...0).should == "ã‚“ã«ã¡ã¯"
+ "ã“ã‚“ã«ã¡ã¯".bytesplice(0..2, "ã“ã‚“ã«ã¡ã¯", 3..5).should == "ã‚“ã‚“ã«ã¡ã¯"
+ "ã“ã‚“ã«ã¡ã¯".bytesplice(0..2, "ã“ã‚“ã«ã¡ã¯", 3...6).should == "ã‚“ã‚“ã«ã¡ã¯"
+ "ã“ã‚“ã«ã¡ã¯".bytesplice(0..2, "ã“ã‚“ã«ã¡ã¯", 3..8).should == "ã‚“ã«ã‚“ã«ã¡ã¯"
+ "ã“ã‚“ã«ã¡ã¯".bytesplice(0..2, "ã“ã‚“ã«ã¡ã¯", 0..-1).should == "ã“ã‚“ã«ã¡ã¯ã‚“ã«ã¡ã¯"
+ "ã“ã‚“ã«ã¡ã¯".bytesplice(0..2, "ã“ã‚“ã«ã¡ã¯", 0...15).should == "ã“ã‚“ã«ã¡ã¯ã‚“ã«ã¡ã¯"
+ "ã“ã‚“ã«ã¡ã¯".bytesplice(0..2, "ã“ã‚“ã«ã¡ã¯", 0...18).should == "ã“ã‚“ã«ã¡ã¯ã‚“ã«ã¡ã¯"
+ end
+
+ it "treats negative length for str range as 0" do
+ "ã“ã‚“ã«ã¡ã¯".bytesplice(0..2, "ã“ã‚“ã«ã¡ã¯", 0...-100).should == "ã‚“ã«ã¡ã¯"
+ "ã“ã‚“ã«ã¡ã¯".bytesplice(0..2, "ã“ã‚“ã«ã¡ã¯", 3...-100).should == "ã‚“ã«ã¡ã¯"
+ "ã“ã‚“ã«ã¡ã¯".bytesplice(0..2, "ã“ã‚“ã«ã¡ã¯", -15...-100).should == "ã‚“ã«ã¡ã¯"
+ end
+
+ it "raises when ranges not match codepoint boundaries in str" do
+ -> { "ã“ã‚“ã«ã¡ã¯".bytesplice(3...3, "ã“", 0..0) }.should.raise(IndexError, "offset 1 does not land on character boundary")
+ -> { "ã“ã‚“ã«ã¡ã¯".bytesplice(3...3, "ã“", 0..1) }.should.raise(IndexError, "offset 2 does not land on character boundary")
+ # Begin is incorrect
+ -> { "ã“ã‚“ã«ã¡ã¯".bytesplice(3...3, "ã“ã‚“ã«ã¡ã¯", -4..-1) }.should.raise(IndexError, "offset 11 does not land on character boundary")
+ -> { "ã“ã‚“ã«ã¡ã¯".bytesplice(3...3, "ã“ã‚“ã«ã¡ã¯", -5..-1) }.should.raise(IndexError, "offset 10 does not land on character boundary")
+ # End is incorrect
+ -> { "ã“ã‚“ã«ã¡ã¯".bytesplice(3...3, "ã“ã‚“ã«ã¡ã¯", -3..-2) }.should.raise(IndexError, "offset 14 does not land on character boundary")
+ -> { "ã“ã‚“ã«ã¡ã¯".bytesplice(3...3, "ã“ã‚“ã«ã¡ã¯", -3..-3) }.should.raise(IndexError, "offset 13 does not land on character boundary")
+ end
+
+ it "deals with a different encoded argument with str index/length" do
+ s = "ã“ã‚“ã«ã¡ã¯"
+ s.encoding.should == Encoding::UTF_8
+ sub = "goodbye"
+ sub.force_encoding(Encoding::US_ASCII)
+
+ result = s.bytesplice(3, 3, sub, 0, 3)
+ result.should == "ã“gooã«ã¡ã¯"
+ result.encoding.should == Encoding::UTF_8
+
+ s = "hello"
+ s.force_encoding(Encoding::US_ASCII)
+ sub = "ã“ã‚“ã«ã¡ã¯"
+ sub.encoding.should == Encoding::UTF_8
+
+ result = s.bytesplice(1, 2, sub, 3, 3)
+ result.should == "hã‚“lo"
+ result.encoding.should == Encoding::UTF_8
+ end
+
+ it "deals with a different encoded argument with str range" do
+ s = "ã“ã‚“ã«ã¡ã¯"
+ s.encoding.should == Encoding::UTF_8
+ sub = "goodbye"
+ sub.force_encoding(Encoding::US_ASCII)
+
+ result = s.bytesplice(3..5, sub, 0..2)
+ result.should == "ã“gooã«ã¡ã¯"
+ result.encoding.should == Encoding::UTF_8
+
+ s = "hello"
+ s.force_encoding(Encoding::US_ASCII)
+ sub = "ã“ã‚“ã«ã¡ã¯"
+ sub.encoding.should == Encoding::UTF_8
+
+ result = s.bytesplice(1..2, sub, 3..5)
+ result.should == "hã‚“lo"
+ result.encoding.should == Encoding::UTF_8
end
end
diff --git a/spec/ruby/core/string/capitalize_spec.rb b/spec/ruby/core/string/capitalize_spec.rb
index 5e59b656c5..12b1675c2e 100644
--- a/spec/ruby/core/string/capitalize_spec.rb
+++ b/spec/ruby/core/string/capitalize_spec.rb
@@ -28,7 +28,7 @@ describe "String#capitalize" do
capitalized.should == "Sset"
capitalized.size.should == 4
capitalized.bytesize.should == 4
- capitalized.ascii_only?.should be_true
+ capitalized.ascii_only?.should == true
end
end
@@ -52,7 +52,7 @@ describe "String#capitalize" do
end
it "does not allow any other additional option" do
- -> { "iSa".capitalize(:turkic, :ascii) }.should raise_error(ArgumentError)
+ -> { "iSa".capitalize(:turkic, :ascii) }.should.raise(ArgumentError)
end
end
@@ -66,21 +66,21 @@ describe "String#capitalize" do
end
it "does not allow any other additional option" do
- -> { "iß".capitalize(:lithuanian, :ascii) }.should raise_error(ArgumentError)
+ -> { "iß".capitalize(:lithuanian, :ascii) }.should.raise(ArgumentError)
end
end
it "does not allow the :fold option for upcasing" do
- -> { "abc".capitalize(:fold) }.should raise_error(ArgumentError)
+ -> { "abc".capitalize(:fold) }.should.raise(ArgumentError)
end
it "does not allow invalid options" do
- -> { "abc".capitalize(:invalid_option) }.should raise_error(ArgumentError)
+ -> { "abc".capitalize(:invalid_option) }.should.raise(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)
+ StringSpecs::MyString.new("hello").capitalize.should.instance_of?(String)
+ StringSpecs::MyString.new("Hello").capitalize.should.instance_of?(String)
end
it "returns a String in the same encoding as self" do
@@ -91,7 +91,7 @@ end
describe "String#capitalize!" do
it "capitalizes self in place" do
a = +"hello"
- a.capitalize!.should equal(a)
+ a.capitalize!.should.equal?(a)
a.should == "Hello"
end
@@ -127,7 +127,7 @@ describe "String#capitalize!" do
capitalized.should == "Sset"
capitalized.size.should == 4
capitalized.bytesize.should == 4
- capitalized.ascii_only?.should be_true
+ capitalized.ascii_only?.should == true
end
end
@@ -159,7 +159,7 @@ describe "String#capitalize!" do
end
it "does not allow any other additional option" do
- -> { a = "iSa"; a.capitalize!(:turkic, :ascii) }.should raise_error(ArgumentError)
+ -> { a = "iSa"; a.capitalize!(:turkic, :ascii) }.should.raise(ArgumentError)
end
end
@@ -177,16 +177,16 @@ describe "String#capitalize!" do
end
it "does not allow any other additional option" do
- -> { a = "iß"; a.capitalize!(:lithuanian, :ascii) }.should raise_error(ArgumentError)
+ -> { a = "iß"; a.capitalize!(:lithuanian, :ascii) }.should.raise(ArgumentError)
end
end
it "does not allow the :fold option for upcasing" do
- -> { a = "abc"; a.capitalize!(:fold) }.should raise_error(ArgumentError)
+ -> { a = "abc"; a.capitalize!(:fold) }.should.raise(ArgumentError)
end
it "does not allow invalid options" do
- -> { a = "abc"; a.capitalize!(:invalid_option) }.should raise_error(ArgumentError)
+ -> { a = "abc"; a.capitalize!(:invalid_option) }.should.raise(ArgumentError)
end
it "returns nil when no changes are made" do
@@ -201,7 +201,7 @@ describe "String#capitalize!" do
it "raises a FrozenError when self is frozen" do
["", "Hello", "hello"].each do |a|
a.freeze
- -> { a.capitalize! }.should raise_error(FrozenError)
+ -> { a.capitalize! }.should.raise(FrozenError)
end
end
end
diff --git a/spec/ruby/core/string/case_compare_spec.rb b/spec/ruby/core/string/case_compare_spec.rb
index b83d1adb91..f98ec003be 100644
--- a/spec/ruby/core/string/case_compare_spec.rb
+++ b/spec/ruby/core/string/case_compare_spec.rb
@@ -1,8 +1,7 @@
require_relative '../../spec_helper'
-require_relative 'shared/eql'
-require_relative 'shared/equal_value'
describe "String#===" do
- it_behaves_like :string_eql_value, :===
- it_behaves_like :string_equal_value, :===
+ it "is an alias of String#==" do
+ String.instance_method(:===).should == String.instance_method(:==)
+ end
end
diff --git a/spec/ruby/core/string/casecmp_spec.rb b/spec/ruby/core/string/casecmp_spec.rb
index 81ebea557c..90577aaac0 100644
--- a/spec/ruby/core/string/casecmp_spec.rb
+++ b/spec/ruby/core/string/casecmp_spec.rb
@@ -26,11 +26,11 @@ describe "String#casecmp independent of case" do
end
it "returns nil if other can't be converted to a string" do
- "abc".casecmp(mock('abc')).should be_nil
+ "abc".casecmp(mock('abc')).should == nil
end
it "returns nil if incompatible encodings" do
- "ã‚れ".casecmp("れ".encode(Encoding::EUC_JP)).should be_nil
+ "ã‚れ".casecmp("れ".encode(Encoding::EUC_JP)).should == nil
end
describe "in UTF-8 mode" do
@@ -143,7 +143,7 @@ describe 'String#casecmp? independent of case' do
end
it "returns nil if incompatible encodings" do
- "ã‚れ".casecmp?("れ".encode(Encoding::EUC_JP)).should be_nil
+ "ã‚れ".casecmp?("れ".encode(Encoding::EUC_JP)).should == nil
end
describe 'for UNICODE characters' do
@@ -190,11 +190,11 @@ describe 'String#casecmp? independent of case' do
end
it "case folds" do
- "ß".casecmp?("ss").should be_true
+ "ß".casecmp?("ss").should == true
end
it "returns nil if other can't be converted to a string" do
- "abc".casecmp?(mock('abc')).should be_nil
+ "abc".casecmp?(mock('abc')).should == nil
end
it "returns true for empty strings in different encodings" do
diff --git a/spec/ruby/core/string/center_spec.rb b/spec/ruby/core/string/center_spec.rb
index 1667b59327..ac5b8a2ff3 100644
--- a/spec/ruby/core/string/center_spec.rb
+++ b/spec/ruby/core/string/center_spec.rb
@@ -57,10 +57,10 @@ describe "String#center with length, padding" do
end
it "raises a TypeError when length can't be converted to an integer" do
- -> { "hello".center("x") }.should raise_error(TypeError)
- -> { "hello".center("x", "y") }.should raise_error(TypeError)
- -> { "hello".center([]) }.should raise_error(TypeError)
- -> { "hello".center(mock('x')) }.should raise_error(TypeError)
+ -> { "hello".center("x") }.should.raise(TypeError)
+ -> { "hello".center("x", "y") }.should.raise(TypeError)
+ -> { "hello".center([]) }.should.raise(TypeError)
+ -> { "hello".center(mock('x')) }.should.raise(TypeError)
end
it "calls #to_str to convert padstr to a String" do
@@ -71,23 +71,23 @@ describe "String#center with length, padding" do
end
it "raises a TypeError when padstr can't be converted to a string" do
- -> { "hello".center(20, 100) }.should raise_error(TypeError)
- -> { "hello".center(20, []) }.should raise_error(TypeError)
- -> { "hello".center(20, mock('x')) }.should raise_error(TypeError)
+ -> { "hello".center(20, 100) }.should.raise(TypeError)
+ -> { "hello".center(20, []) }.should.raise(TypeError)
+ -> { "hello".center(20, mock('x')) }.should.raise(TypeError)
end
it "raises an ArgumentError if padstr is empty" do
- -> { "hello".center(10, "") }.should raise_error(ArgumentError)
- -> { "hello".center(0, "") }.should raise_error(ArgumentError)
+ -> { "hello".center(10, "") }.should.raise(ArgumentError)
+ -> { "hello".center(0, "") }.should.raise(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)
+ StringSpecs::MyString.new("").center(10).should.instance_of?(String)
+ StringSpecs::MyString.new("foo").center(10).should.instance_of?(String)
+ StringSpecs::MyString.new("foo").center(10, StringSpecs::MyString.new("x")).should.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)
+ "".center(10, StringSpecs::MyString.new("x")).should.instance_of?(String)
+ "foo".center(10, StringSpecs::MyString.new("x")).should.instance_of?(String)
end
describe "with width" do
@@ -95,7 +95,7 @@ describe "String#center with length, padding" do
str = "abc".dup.force_encoding Encoding::IBM437
result = str.center 6
result.should == " abc "
- result.encoding.should equal(Encoding::IBM437)
+ result.encoding.should.equal?(Encoding::IBM437)
end
end
@@ -104,14 +104,14 @@ describe "String#center with length, padding" do
str = "abc".dup.force_encoding Encoding::IBM437
result = str.center 6, "ã‚"
result.should == "ã‚abcã‚ã‚"
- result.encoding.should equal(Encoding::UTF_8)
+ result.encoding.should.equal?(Encoding::UTF_8)
end
it "raises an Encoding::CompatibilityError if the encodings are incompatible" do
pat = "ã‚¢".encode Encoding::EUC_JP
-> do
"ã‚れ".center 5, pat
- end.should raise_error(Encoding::CompatibilityError)
+ end.should.raise(Encoding::CompatibilityError)
end
end
end
diff --git a/spec/ruby/core/string/chilled_string_spec.rb b/spec/ruby/core/string/chilled_string_spec.rb
index 968e4ec1f0..6a5e846db2 100644
--- a/spec/ruby/core/string/chilled_string_spec.rb
+++ b/spec/ruby/core/string/chilled_string_spec.rb
@@ -47,6 +47,14 @@ describe "chilled String" do
input.should == "chilled-mutated"
end
+ it "emits a warning for concatenated strings" do
+ input = "still" "+chilled"
+ -> {
+ input << "-mutated"
+ }.should complain(/literal string will be frozen in the future/)
+ input.should == "still+chilled-mutated"
+ end
+
it "emits a warning on singleton_class creation" do
-> {
"chilled".singleton_class
@@ -65,7 +73,7 @@ describe "chilled String" do
-> {
-> {
input << "mutated"
- }.should raise_error(FrozenError)
+ }.should.raise(FrozenError)
}.should_not complain(/literal string will be frozen in the future/)
end
end
@@ -134,7 +142,7 @@ describe "chilled String" do
-> {
-> {
input << "mutated"
- }.should raise_error(FrozenError)
+ }.should.raise(FrozenError)
}.should_not complain(/string returned by :chilled\.to_s will be frozen in the future/)
end
end
diff --git a/spec/ruby/core/string/chomp_spec.rb b/spec/ruby/core/string/chomp_spec.rb
index d27c84c6f6..3a8550892f 100644
--- a/spec/ruby/core/string/chomp_spec.rb
+++ b/spec/ruby/core/string/chomp_spec.rb
@@ -22,7 +22,7 @@ describe "String#chomp" do
it "returns a copy of the String when it is not modified" do
str = "abc"
- str.chomp.should_not equal(str)
+ str.chomp.should_not.equal?(str)
end
it "removes one trailing newline" do
@@ -47,7 +47,7 @@ describe "String#chomp" 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)
+ str.should.instance_of?(String)
end
it "removes trailing characters that match $/ when it has been assigned a value" do
@@ -67,7 +67,7 @@ describe "String#chomp" do
it "returns a copy of the String" do
str = "abc"
- str.chomp(nil).should_not equal(str)
+ str.chomp(nil).should_not.equal?(str)
end
it "returns an empty String when self is empty" do
@@ -133,7 +133,7 @@ describe "String#chomp" do
it "raises a TypeError if #to_str does not return a String" do
arg = mock("string chomp")
arg.should_receive(:to_str).and_return(1)
- -> { "abc".chomp(arg) }.should raise_error(TypeError)
+ -> { "abc".chomp(arg) }.should.raise(TypeError)
end
end
@@ -171,11 +171,11 @@ describe "String#chomp!" do
it "modifies self" do
str = "abc\n"
- str.chomp!.should equal(str)
+ str.chomp!.should.equal?(str)
end
it "returns nil if self is not modified" do
- "abc".chomp!.should be_nil
+ "abc".chomp!.should == nil
end
it "removes one trailing newline" do
@@ -191,12 +191,12 @@ describe "String#chomp!" do
end
it "returns nil when self is empty" do
- "".chomp!.should be_nil
+ "".chomp!.should == nil
end
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)
+ str.should.instance_of?(StringSpecs::MyString)
end
it "removes trailing characters that match $/ when it has been assigned a value" do
@@ -207,11 +207,11 @@ describe "String#chomp!" do
describe "when passed nil" do
it "returns nil" do
- "abc\r\n".chomp!(nil).should be_nil
+ "abc\r\n".chomp!(nil).should == nil
end
it "returns nil when self is empty" do
- "".chomp!(nil).should be_nil
+ "".chomp!(nil).should == nil
end
end
@@ -225,7 +225,7 @@ describe "String#chomp!" do
end
it "does not remove a final carriage return" do
- "abc\r".chomp!("").should be_nil
+ "abc\r".chomp!("").should == nil
end
it "removes more than one trailing newlines" do
@@ -237,7 +237,7 @@ describe "String#chomp!" do
end
it "returns nil when self is empty" do
- "".chomp!("").should be_nil
+ "".chomp!("").should == nil
end
end
@@ -255,7 +255,7 @@ describe "String#chomp!" do
end
it "returns nil when self is empty" do
- "".chomp!("\n").should be_nil
+ "".chomp!("\n").should == nil
end
end
@@ -269,7 +269,7 @@ describe "String#chomp!" do
it "raises a TypeError if #to_str does not return a String" do
arg = mock("string chomp")
arg.should_receive(:to_str).and_return(1)
- -> { "abc".chomp!(arg) }.should raise_error(TypeError)
+ -> { "abc".chomp!(arg) }.should.raise(TypeError)
end
end
@@ -279,11 +279,11 @@ describe "String#chomp!" do
end
it "returns nil if the argument does not match the trailing characters" do
- "abc".chomp!("def").should be_nil
+ "abc".chomp!("def").should == nil
end
it "returns nil when self is empty" do
- "".chomp!("abc").should be_nil
+ "".chomp!("abc").should == nil
end
end
@@ -291,15 +291,15 @@ describe "String#chomp!" do
a = "string\n\r"
a.freeze
- -> { a.chomp! }.should raise_error(FrozenError)
+ -> { a.chomp! }.should.raise(FrozenError)
end
# see [ruby-core:23666]
it "raises a FrozenError on a frozen instance when it would not be modified" do
a = "string\n\r"
a.freeze
- -> { a.chomp!(nil) }.should raise_error(FrozenError)
- -> { a.chomp!("x") }.should raise_error(FrozenError)
+ -> { a.chomp!(nil) }.should.raise(FrozenError)
+ -> { a.chomp!("x") }.should.raise(FrozenError)
end
end
@@ -346,7 +346,7 @@ describe "String#chomp!" do
end
it "returns nil when the String is not modified" do
- "ã‚れ".chomp!.should be_nil
+ "ã‚れ".chomp!.should == nil
end
it "removes the final carriage return, newline from a multibyte String" do
diff --git a/spec/ruby/core/string/chop_spec.rb b/spec/ruby/core/string/chop_spec.rb
index 99c2c82190..2113da543b 100644
--- a/spec/ruby/core/string/chop_spec.rb
+++ b/spec/ruby/core/string/chop_spec.rb
@@ -47,11 +47,11 @@ describe "String#chop" do
it "returns a new string when applied to an empty string" do
s = ""
- s.chop.should_not equal(s)
+ 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)
+ StringSpecs::MyString.new("hello\n").chop.should.instance_of?(String)
end
it "returns a String in the same encoding as self" do
@@ -99,21 +99,21 @@ describe "String#chop!" do
it "returns self if modifications were made" do
str = "hello"
- str.chop!.should equal(str)
+ str.chop!.should.equal?(str)
end
it "returns nil when called on an empty string" do
- "".chop!.should be_nil
+ "".chop!.should == nil
end
it "raises a FrozenError on a frozen instance that is modified" do
- -> { "string\n\r".freeze.chop! }.should raise_error(FrozenError)
+ -> { "string\n\r".freeze.chop! }.should.raise(FrozenError)
end
# see [ruby-core:23666]
it "raises a FrozenError on a frozen instance that would not be modified" do
a = ""
a.freeze
- -> { a.chop! }.should raise_error(FrozenError)
+ -> { a.chop! }.should.raise(FrozenError)
end
end
diff --git a/spec/ruby/core/string/chr_spec.rb b/spec/ruby/core/string/chr_spec.rb
index 9ed29542e6..26c7d51202 100644
--- a/spec/ruby/core/string/chr_spec.rb
+++ b/spec/ruby/core/string/chr_spec.rb
@@ -3,11 +3,11 @@ require_relative '../../spec_helper'
describe "String#chr" do
it "returns a copy of self" do
s = 'e'
- s.should_not equal s.chr
+ s.should_not.equal? s.chr
end
it "returns a String" do
- 'glark'.chr.should be_an_instance_of(String)
+ 'glark'.chr.should.instance_of?(String)
end
it "returns an empty String if self is an empty String" do
diff --git a/spec/ruby/core/string/clear_spec.rb b/spec/ruby/core/string/clear_spec.rb
index 152986fd0f..d4688d3689 100644
--- a/spec/ruby/core/string/clear_spec.rb
+++ b/spec/ruby/core/string/clear_spec.rb
@@ -14,7 +14,7 @@ describe "String#clear" do
it "returns self after emptying it" do
cleared = @s.clear
cleared.should == ""
- cleared.should equal @s
+ cleared.should.equal? @s
end
it "preserves its encoding" do
@@ -32,7 +32,7 @@ describe "String#clear" do
it "raises a FrozenError if self is frozen" do
@s.freeze
- -> { @s.clear }.should raise_error(FrozenError)
- -> { "".freeze.clear }.should raise_error(FrozenError)
+ -> { @s.clear }.should.raise(FrozenError)
+ -> { "".freeze.clear }.should.raise(FrozenError)
end
end
diff --git a/spec/ruby/core/string/clone_spec.rb b/spec/ruby/core/string/clone_spec.rb
index a2ba2f9877..2cb289d2c1 100644
--- a/spec/ruby/core/string/clone_spec.rb
+++ b/spec/ruby/core/string/clone_spec.rb
@@ -43,8 +43,8 @@ describe "String#clone" do
end
it "copies frozen state" do
- @obj.freeze.clone.frozen?.should be_true
- "".freeze.clone.frozen?.should be_true
+ @obj.freeze.clone.frozen?.should == true
+ "".freeze.clone.frozen?.should == true
end
it "does not modify the original string when changing cloned string" do
diff --git a/spec/ruby/core/string/codepoints_spec.rb b/spec/ruby/core/string/codepoints_spec.rb
index 12a5bf5892..4434eb66a5 100644
--- a/spec/ruby/core/string/codepoints_spec.rb
+++ b/spec/ruby/core/string/codepoints_spec.rb
@@ -1,7 +1,6 @@
# encoding: binary
require_relative '../../spec_helper'
require_relative 'shared/codepoints'
-require_relative 'shared/each_codepoint_without_block'
describe "String#codepoints" do
it_behaves_like :string_codepoints, :codepoints
@@ -12,7 +11,7 @@ describe "String#codepoints" do
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.valid_encoding?.should be_false
- -> { s.codepoints }.should raise_error(ArgumentError)
+ s.valid_encoding?.should == false
+ -> { s.codepoints }.should.raise(ArgumentError)
end
end
diff --git a/spec/ruby/core/string/comparison_spec.rb b/spec/ruby/core/string/comparison_spec.rb
index 9db0cff5ee..0737c131bb 100644
--- a/spec/ruby/core/string/comparison_spec.rb
+++ b/spec/ruby/core/string/comparison_spec.rb
@@ -85,7 +85,7 @@ end
# just using it as an indicator.
describe "String#<=>" do
it "returns nil if its argument provides neither #to_str nor #<=>" do
- ("abc" <=> mock('x')).should be_nil
+ ("abc" <=> mock('x')).should == nil
end
it "uses the result of calling #to_str for comparison when #to_str is defined" do
@@ -107,6 +107,6 @@ describe "String#<=>" do
def obj.<=>(other); other <=> self; end
obj.should_receive(:<=>).once
- ("abc" <=> obj).should be_nil
+ ("abc" <=> obj).should == nil
end
end
diff --git a/spec/ruby/core/string/concat_spec.rb b/spec/ruby/core/string/concat_spec.rb
index cbd7df54e2..0194a357a0 100644
--- a/spec/ruby/core/string/concat_spec.rb
+++ b/spec/ruby/core/string/concat_spec.rb
@@ -21,7 +21,7 @@ describe "String#concat" do
it "returns self when given no arguments" do
str = +"hello"
- str.concat.should equal(str)
+ str.concat.should.equal?(str)
str.should == "hello"
end
end
diff --git a/spec/ruby/core/string/count_spec.rb b/spec/ruby/core/string/count_spec.rb
index e614e901dd..fd127c6ff2 100644
--- a/spec/ruby/core/string/count_spec.rb
+++ b/spec/ruby/core/string/count_spec.rb
@@ -23,7 +23,7 @@ describe "String#count" do
end
it "raises an ArgumentError when given no arguments" do
- -> { "hell yeah".count }.should raise_error(ArgumentError)
+ -> { "hell yeah".count }.should.raise(ArgumentError)
end
it "negates sets starting with ^" do
@@ -76,8 +76,8 @@ describe "String#count" do
it "raises if the given sequences are invalid" do
s = "hel-[()]-lo012^"
- -> { s.count("h-e") }.should raise_error(ArgumentError)
- -> { s.count("^h-e") }.should raise_error(ArgumentError)
+ -> { s.count("h-e") }.should.raise(ArgumentError)
+ -> { s.count("^h-e") }.should.raise(ArgumentError)
end
it 'returns the number of occurrences of a multi-byte character' do
@@ -98,8 +98,8 @@ describe "String#count" do
end
it "raises a TypeError when a set arg can't be converted to a string" do
- -> { "hello world".count(100) }.should raise_error(TypeError)
- -> { "hello world".count([]) }.should raise_error(TypeError)
- -> { "hello world".count(mock('x')) }.should raise_error(TypeError)
+ -> { "hello world".count(100) }.should.raise(TypeError)
+ -> { "hello world".count([]) }.should.raise(TypeError)
+ -> { "hello world".count(mock('x')) }.should.raise(TypeError)
end
end
diff --git a/spec/ruby/core/string/crypt_spec.rb b/spec/ruby/core/string/crypt_spec.rb
index 06f84c70a4..924b4d48cf 100644
--- a/spec/ruby/core/string/crypt_spec.rb
+++ b/spec/ruby/core/string/crypt_spec.rb
@@ -15,7 +15,7 @@ describe "String#crypt" do
end
it "raises Errno::EINVAL when the salt is shorter than 29 characters" do
- -> { "mypassword".crypt("$2a$04$0WVaz0pV3jzfZ5G5tpmHW") }.should raise_error(Errno::EINVAL)
+ -> { "mypassword".crypt("$2a$04$0WVaz0pV3jzfZ5G5tpmHW") }.should.raise(Errno::EINVAL)
end
it "calls #to_str to converts the salt arg to a String" do
@@ -26,9 +26,9 @@ describe "String#crypt" do
end
it "doesn't return subclass instances" do
- StringSpecs::MyString.new("mypassword").crypt("$2a$04$0WVaz0pV3jzfZ5G5tpmHWu").should be_an_instance_of(String)
- "mypassword".crypt(StringSpecs::MyString.new("$2a$04$0WVaz0pV3jzfZ5G5tpmHWu")).should be_an_instance_of(String)
- StringSpecs::MyString.new("mypassword").crypt(StringSpecs::MyString.new("$2a$04$0WVaz0pV3jzfZ5G5tpmHWu")).should be_an_instance_of(String)
+ StringSpecs::MyString.new("mypassword").crypt("$2a$04$0WVaz0pV3jzfZ5G5tpmHWu").should.instance_of?(String)
+ "mypassword".crypt(StringSpecs::MyString.new("$2a$04$0WVaz0pV3jzfZ5G5tpmHWu")).should.instance_of?(String)
+ StringSpecs::MyString.new("mypassword").crypt(StringSpecs::MyString.new("$2a$04$0WVaz0pV3jzfZ5G5tpmHWu")).should.instance_of?(String)
end
end
@@ -60,7 +60,7 @@ describe "String#crypt" do
end
it "raises an ArgumentError when the string contains NUL character" do
- -> { "poison\0null".crypt("aa") }.should raise_error(ArgumentError)
+ -> { "poison\0null".crypt("aa") }.should.raise(ArgumentError)
end
it "calls #to_str to converts the salt arg to a String" do
@@ -71,22 +71,22 @@ describe "String#crypt" do
end
it "doesn't return subclass instances" do
- StringSpecs::MyString.new("hello").crypt("aa").should be_an_instance_of(String)
- "hello".crypt(StringSpecs::MyString.new("aa")).should be_an_instance_of(String)
- StringSpecs::MyString.new("hello").crypt(StringSpecs::MyString.new("aa")).should be_an_instance_of(String)
+ StringSpecs::MyString.new("hello").crypt("aa").should.instance_of?(String)
+ "hello".crypt(StringSpecs::MyString.new("aa")).should.instance_of?(String)
+ StringSpecs::MyString.new("hello").crypt(StringSpecs::MyString.new("aa")).should.instance_of?(String)
end
it "raises an ArgumentError when the salt is shorter than two characters" do
- -> { "hello".crypt("") }.should raise_error(ArgumentError)
- -> { "hello".crypt("f") }.should raise_error(ArgumentError)
- -> { "hello".crypt("\x00\x00") }.should raise_error(ArgumentError)
- -> { "hello".crypt("\x00a") }.should raise_error(ArgumentError)
- -> { "hello".crypt("a\x00") }.should raise_error(ArgumentError)
+ -> { "hello".crypt("") }.should.raise(ArgumentError)
+ -> { "hello".crypt("f") }.should.raise(ArgumentError)
+ -> { "hello".crypt("\x00\x00") }.should.raise(ArgumentError)
+ -> { "hello".crypt("\x00a") }.should.raise(ArgumentError)
+ -> { "hello".crypt("a\x00") }.should.raise(ArgumentError)
end
end
it "raises a type error when the salt arg can't be converted to a string" do
- -> { "".crypt(5) }.should raise_error(TypeError)
- -> { "".crypt(mock('x')) }.should raise_error(TypeError)
+ -> { "".crypt(5) }.should.raise(TypeError)
+ -> { "".crypt(mock('x')) }.should.raise(TypeError)
end
end
diff --git a/spec/ruby/core/string/dedup_spec.rb b/spec/ruby/core/string/dedup_spec.rb
index 2b31d80708..940f07668e 100644
--- a/spec/ruby/core/string/dedup_spec.rb
+++ b/spec/ruby/core/string/dedup_spec.rb
@@ -1,6 +1,7 @@
require_relative '../../spec_helper'
-require_relative 'shared/dedup'
describe 'String#dedup' do
- it_behaves_like :string_dedup, :dedup
+ it "is an alias of String#-@" do
+ String.instance_method(:dedup).should == String.instance_method(:-@)
+ end
end
diff --git a/spec/ruby/core/string/delete_prefix_spec.rb b/spec/ruby/core/string/delete_prefix_spec.rb
index ee7f044905..fc69adcbad 100644
--- a/spec/ruby/core/string/delete_prefix_spec.rb
+++ b/spec/ruby/core/string/delete_prefix_spec.rb
@@ -12,13 +12,13 @@ describe "String#delete_prefix" do
it "returns a copy of the string, when the prefix isn't found" do
s = 'hello'
r = s.delete_prefix('hello!')
- r.should_not equal s
+ r.should_not.equal? s
r.should == s
r = s.delete_prefix('ell')
- r.should_not equal s
+ r.should_not.equal? s
r.should == s
r = s.delete_prefix('')
- r.should_not equal s
+ r.should_not.equal? s
r.should == s
end
@@ -41,7 +41,7 @@ describe "String#delete_prefix" 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)
+ s.delete_prefix('hell').should.instance_of?(String)
end
it "returns a String in the same encoding as self" do
@@ -52,7 +52,7 @@ end
describe "String#delete_prefix!" do
it "removes the found prefix" do
s = 'hello'
- s.delete_prefix!('hell').should equal(s)
+ s.delete_prefix!('hell').should.equal?(s)
s.should == 'o'
end
@@ -76,8 +76,8 @@ describe "String#delete_prefix!" do
end
it "raises a FrozenError when self is frozen" do
- -> { 'hello'.freeze.delete_prefix!('hell') }.should raise_error(FrozenError)
- -> { 'hello'.freeze.delete_prefix!('') }.should raise_error(FrozenError)
- -> { ''.freeze.delete_prefix!('') }.should raise_error(FrozenError)
+ -> { 'hello'.freeze.delete_prefix!('hell') }.should.raise(FrozenError)
+ -> { 'hello'.freeze.delete_prefix!('') }.should.raise(FrozenError)
+ -> { ''.freeze.delete_prefix!('') }.should.raise(FrozenError)
end
end
diff --git a/spec/ruby/core/string/delete_spec.rb b/spec/ruby/core/string/delete_spec.rb
index 6d359776e4..adb5150cff 100644
--- a/spec/ruby/core/string/delete_spec.rb
+++ b/spec/ruby/core/string/delete_spec.rb
@@ -15,7 +15,7 @@ describe "String#delete" do
end
it "raises an ArgumentError when given no arguments" do
- -> { "hell yeah".delete }.should raise_error(ArgumentError)
+ -> { "hell yeah".delete }.should.raise(ArgumentError)
end
it "negates sets starting with ^" do
@@ -63,10 +63,10 @@ describe "String#delete" do
not_supported_on :opal do
xFF = [0xFF].pack('C')
range = "\x00 - #{xFF}".force_encoding('utf-8')
- -> { "hello".delete(range).should == "" }.should raise_error(ArgumentError)
+ -> { "hello".delete(range).should == "" }.should.raise(ArgumentError)
end
- -> { "hello".delete("h-e") }.should raise_error(ArgumentError)
- -> { "hello".delete("^h-e") }.should raise_error(ArgumentError)
+ -> { "hello".delete("h-e") }.should.raise(ArgumentError)
+ -> { "hello".delete("^h-e") }.should.raise(ArgumentError)
end
it "tries to convert each set arg to a string using to_str" do
@@ -80,13 +80,13 @@ describe "String#delete" do
end
it "raises a TypeError when one set arg can't be converted to a string" do
- -> { "hello world".delete(100) }.should raise_error(TypeError)
- -> { "hello world".delete([]) }.should raise_error(TypeError)
- -> { "hello world".delete(mock('x')) }.should raise_error(TypeError)
+ -> { "hello world".delete(100) }.should.raise(TypeError)
+ -> { "hello world".delete([]) }.should.raise(TypeError)
+ -> { "hello world".delete(mock('x')) }.should.raise(TypeError)
end
it "returns String instances when called on a subclass" do
- StringSpecs::MyString.new("oh no!!!").delete("!").should be_an_instance_of(String)
+ StringSpecs::MyString.new("oh no!!!").delete("!").should.instance_of?(String)
end
it "returns a String in the same encoding as self" do
@@ -97,7 +97,7 @@ end
describe "String#delete!" do
it "modifies self in place and returns self" do
a = "hello"
- a.delete!("aeiou", "^e").should equal(a)
+ a.delete!("aeiou", "^e").should.equal?(a)
a.should == "hell"
end
@@ -111,7 +111,7 @@ describe "String#delete!" do
a = "hello"
a.freeze
- -> { a.delete!("") }.should raise_error(FrozenError)
- -> { a.delete!("aeiou", "^e") }.should raise_error(FrozenError)
+ -> { a.delete!("") }.should.raise(FrozenError)
+ -> { a.delete!("aeiou", "^e") }.should.raise(FrozenError)
end
end
diff --git a/spec/ruby/core/string/delete_suffix_spec.rb b/spec/ruby/core/string/delete_suffix_spec.rb
index 1842d75aa5..11d8fbbac1 100644
--- a/spec/ruby/core/string/delete_suffix_spec.rb
+++ b/spec/ruby/core/string/delete_suffix_spec.rb
@@ -12,13 +12,13 @@ describe "String#delete_suffix" do
it "returns a copy of the string, when the suffix isn't found" do
s = 'hello'
r = s.delete_suffix('!hello')
- r.should_not equal s
+ r.should_not.equal? s
r.should == s
r = s.delete_suffix('ell')
- r.should_not equal s
+ r.should_not.equal? s
r.should == s
r = s.delete_suffix('')
- r.should_not equal s
+ r.should_not.equal? s
r.should == s
end
@@ -41,7 +41,7 @@ describe "String#delete_suffix" 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)
+ s.delete_suffix('ello').should.instance_of?(String)
end
it "returns a String in the same encoding as self" do
@@ -52,7 +52,7 @@ end
describe "String#delete_suffix!" do
it "removes the found prefix" do
s = 'hello'
- s.delete_suffix!('ello').should equal(s)
+ s.delete_suffix!('ello').should.equal?(s)
s.should == 'h'
end
@@ -76,8 +76,8 @@ describe "String#delete_suffix!" do
end
it "raises a FrozenError when self is frozen" do
- -> { 'hello'.freeze.delete_suffix!('ello') }.should raise_error(FrozenError)
- -> { 'hello'.freeze.delete_suffix!('') }.should raise_error(FrozenError)
- -> { ''.freeze.delete_suffix!('') }.should raise_error(FrozenError)
+ -> { 'hello'.freeze.delete_suffix!('ello') }.should.raise(FrozenError)
+ -> { 'hello'.freeze.delete_suffix!('') }.should.raise(FrozenError)
+ -> { ''.freeze.delete_suffix!('') }.should.raise(FrozenError)
end
end
diff --git a/spec/ruby/core/string/downcase_spec.rb b/spec/ruby/core/string/downcase_spec.rb
index 2d260f23f1..4f7f44e5d4 100644
--- a/spec/ruby/core/string/downcase_spec.rb
+++ b/spec/ruby/core/string/downcase_spec.rb
@@ -24,7 +24,7 @@ describe "String#downcase" do
downcased.should == "king"
downcased.size.should == 4
downcased.bytesize.should == 4
- downcased.ascii_only?.should be_true
+ downcased.ascii_only?.should == true
end
end
@@ -48,7 +48,7 @@ describe "String#downcase" do
end
it "does not allow any other additional option" do
- -> { "İ".downcase(:turkic, :ascii) }.should raise_error(ArgumentError)
+ -> { "İ".downcase(:turkic, :ascii) }.should.raise(ArgumentError)
end
end
@@ -62,7 +62,7 @@ describe "String#downcase" do
end
it "does not allow any other additional option" do
- -> { "İS".downcase(:lithuanian, :ascii) }.should raise_error(ArgumentError)
+ -> { "İS".downcase(:lithuanian, :ascii) }.should.raise(ArgumentError)
end
end
@@ -74,18 +74,18 @@ describe "String#downcase" do
end
it "does not allow invalid options" do
- -> { "ABC".downcase(:invalid_option) }.should raise_error(ArgumentError)
+ -> { "ABC".downcase(:invalid_option) }.should.raise(ArgumentError)
end
it "returns a String instance for subclasses" do
- StringSpecs::MyString.new("FOObar").downcase.should be_an_instance_of(String)
+ StringSpecs::MyString.new("FOObar").downcase.should.instance_of?(String)
end
end
describe "String#downcase!" do
it "modifies self in place" do
a = "HeLlO"
- a.downcase!.should equal(a)
+ a.downcase!.should.equal?(a)
a.should == "hello"
end
@@ -109,7 +109,7 @@ describe "String#downcase!" do
downcased.should == "king"
downcased.size.should == 4
downcased.bytesize.should == 4
- downcased.ascii_only?.should be_true
+ downcased.ascii_only?.should == true
end
end
@@ -141,7 +141,7 @@ describe "String#downcase!" do
end
it "does not allow any other additional option" do
- -> { a = "İ"; a.downcase!(:turkic, :ascii) }.should raise_error(ArgumentError)
+ -> { a = "İ"; a.downcase!(:turkic, :ascii) }.should.raise(ArgumentError)
end
end
@@ -159,7 +159,7 @@ describe "String#downcase!" do
end
it "does not allow any other additional option" do
- -> { a = "İS"; a.downcase!(:lithuanian, :ascii) }.should raise_error(ArgumentError)
+ -> { a = "İS"; a.downcase!(:lithuanian, :ascii) }.should.raise(ArgumentError)
end
end
@@ -175,7 +175,7 @@ describe "String#downcase!" do
end
it "does not allow invalid options" do
- -> { a = "ABC"; a.downcase!(:invalid_option) }.should raise_error(ArgumentError)
+ -> { a = "ABC"; a.downcase!(:invalid_option) }.should.raise(ArgumentError)
end
it "returns nil if no modifications were made" do
@@ -185,11 +185,11 @@ describe "String#downcase!" do
end
it "raises a FrozenError when self is frozen" do
- -> { "HeLlo".freeze.downcase! }.should raise_error(FrozenError)
- -> { "hello".freeze.downcase! }.should raise_error(FrozenError)
+ -> { "HeLlo".freeze.downcase! }.should.raise(FrozenError)
+ -> { "hello".freeze.downcase! }.should.raise(FrozenError)
end
it "sets the result String encoding to the source String encoding" do
- "ABC".downcase.encoding.should equal(Encoding::UTF_8)
+ "ABC".downcase.encoding.should.equal?(Encoding::UTF_8)
end
end
diff --git a/spec/ruby/core/string/dump_spec.rb b/spec/ruby/core/string/dump_spec.rb
index cab8beff5a..176be79db2 100644
--- a/spec/ruby/core/string/dump_spec.rb
+++ b/spec/ruby/core/string/dump_spec.rb
@@ -8,7 +8,7 @@ describe "String#dump" do
end
it "returns a String instance" do
- StringSpecs::MyString.new.dump.should be_an_instance_of(String)
+ StringSpecs::MyString.new.dump.should.instance_of?(String)
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..e367f7a311 100644
--- a/spec/ruby/core/string/dup_spec.rb
+++ b/spec/ruby/core/string/dup_spec.rb
@@ -21,7 +21,7 @@ describe "String#dup" do
it "does not copy singleton methods" do
def @obj.special() :the_one end
dup = @obj.dup
- -> { dup.special }.should raise_error(NameError)
+ -> { dup.special }.should.raise(NameError)
end
it "does not copy modules included in the singleton class" do
@@ -30,7 +30,7 @@ describe "String#dup" do
end
dup = @obj.dup
- -> { dup.repr }.should raise_error(NameError)
+ -> { dup.repr }.should.raise(NameError)
end
it "does not copy constants defined in the singleton class" do
@@ -39,7 +39,7 @@ describe "String#dup" do
end
dup = @obj.dup
- -> { class << dup; CLONE; end }.should raise_error(NameError)
+ -> { class << dup; CLONE; end }.should.raise(NameError)
end
it "does not modify the original string when changing dupped string" do
diff --git a/spec/ruby/core/string/each_byte_spec.rb b/spec/ruby/core/string/each_byte_spec.rb
index 7b3db265ac..1884df416b 100644
--- a/spec/ruby/core/string/each_byte_spec.rb
+++ b/spec/ruby/core/string/each_byte_spec.rb
@@ -35,13 +35,13 @@ describe "String#each_byte" do
it "returns self" do
s = "hello"
- (s.each_byte {}).should equal(s)
+ (s.each_byte {}).should.equal?(s)
end
describe "when no block is given" do
it "returns an enumerator" do
enum = "hello".each_byte
- enum.should be_an_instance_of(Enumerator)
+ enum.should.instance_of?(Enumerator)
enum.to_a.should == [104, 101, 108, 108, 111]
end
diff --git a/spec/ruby/core/string/each_codepoint_spec.rb b/spec/ruby/core/string/each_codepoint_spec.rb
index c11cb1beae..08d4292371 100644
--- a/spec/ruby/core/string/each_codepoint_spec.rb
+++ b/spec/ruby/core/string/each_codepoint_spec.rb
@@ -1,8 +1,38 @@
+# encoding: binary
require_relative '../../spec_helper'
require_relative 'shared/codepoints'
-require_relative 'shared/each_codepoint_without_block'
describe "String#each_codepoint" do
it_behaves_like :string_codepoints, :each_codepoint
- it_behaves_like :string_each_codepoint_without_block, :each_codepoint
+
+ describe "when no block is given" do
+ it "returns an Enumerator" do
+ "".each_codepoint.should.instance_of?(Enumerator)
+ end
+
+ it "returns an Enumerator even when self has an invalid encoding" do
+ s = "\xDF".dup.force_encoding(Encoding::UTF_8)
+ s.valid_encoding?.should == false
+ s.each_codepoint.should.instance_of?(Enumerator)
+ end
+
+ describe "returned Enumerator" do
+ describe "size" do
+ it "should return the size of the string" do
+ str = "hello"
+ str.each_codepoint.size.should == str.size
+ str = "ola"
+ str.each_codepoint.size.should == str.size
+ str = "\303\207\342\210\202\303\251\306\222g"
+ str.each_codepoint.size.should == str.size
+ 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.valid_encoding?.should == false
+ s.each_codepoint.size.should == 1
+ end
+ end
+ 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..2abc5117aa 100644
--- a/spec/ruby/core/string/element_set_spec.rb
+++ b/spec/ruby/core/string/element_set_spec.rb
@@ -18,13 +18,13 @@ describe "String#[]= with Integer index" do
it "raises an IndexError without changing self if idx is outside of self" do
str = "hello"
- -> { str[20] = "bam" }.should raise_error(IndexError)
+ -> { str[20] = "bam" }.should.raise(IndexError)
str.should == "hello"
- -> { str[-20] = "bam" }.should raise_error(IndexError)
+ -> { str[-20] = "bam" }.should.raise(IndexError)
str.should == "hello"
- -> { ""[-1] = "bam" }.should raise_error(IndexError)
+ -> { ""[-1] = "bam" }.should.raise(IndexError)
end
# Behaviour is verified by matz in
@@ -37,7 +37,7 @@ describe "String#[]= with Integer index" do
it "raises IndexError if the string index doesn't match a position in the string" do
str = "hello"
- -> { str['y'] = "bam" }.should raise_error(IndexError)
+ -> { str['y'] = "bam" }.should.raise(IndexError)
str.should == "hello"
end
@@ -45,7 +45,7 @@ describe "String#[]= with Integer index" do
a = "hello"
a.freeze
- -> { a[0] = "bam" }.should raise_error(FrozenError)
+ -> { a[0] = "bam" }.should.raise(FrozenError)
end
it "calls to_int on index" do
@@ -69,17 +69,17 @@ describe "String#[]= with Integer index" do
end
it "raises a TypeError if other_str can't be converted to a String" do
- -> { "test"[1] = [] }.should raise_error(TypeError)
- -> { "test"[1] = mock('x') }.should raise_error(TypeError)
- -> { "test"[1] = nil }.should raise_error(TypeError)
+ -> { "test"[1] = [] }.should.raise(TypeError)
+ -> { "test"[1] = mock('x') }.should.raise(TypeError)
+ -> { "test"[1] = nil }.should.raise(TypeError)
end
it "raises a TypeError if passed an Integer replacement" do
- -> { "abc"[1] = 65 }.should raise_error(TypeError)
+ -> { "abc"[1] = 65 }.should.raise(TypeError)
end
it "raises an IndexError if the index is greater than character size" do
- -> { "ã‚れ"[4] = "a" }.should raise_error(IndexError)
+ -> { "ã‚れ"[4] = "a" }.should.raise(IndexError)
end
it "calls #to_int to convert the index" do
@@ -95,14 +95,14 @@ describe "String#[]= with Integer index" do
index = mock("string element set")
index.should_receive(:to_int).and_return('1')
- -> { "abc"[index] = "d" }.should raise_error(TypeError)
+ -> { "abc"[index] = "d" }.should.raise(TypeError)
end
it "raises an IndexError if #to_int returns a value out of range" do
index = mock("string element set")
index.should_receive(:to_int).and_return(4)
- -> { "ab"[index] = "c" }.should raise_error(IndexError)
+ -> { "ab"[index] = "c" }.should.raise(IndexError)
end
it "replaces a character with a multibyte character" do
@@ -127,7 +127,7 @@ describe "String#[]= with Integer index" do
str = " ".force_encoding Encoding::US_ASCII
rep = [160].pack('C').force_encoding Encoding::BINARY
str[0] = rep
- str.encoding.should equal(Encoding::BINARY)
+ str.encoding.should.equal?(Encoding::BINARY)
end
it "updates the string to a compatible encoding" do
@@ -139,7 +139,7 @@ describe "String#[]= with Integer index" do
it "raises an Encoding::CompatibilityError if the replacement encoding is incompatible" do
str = "ã‚れ"
rep = "ãŒ".encode Encoding::EUC_JP
- -> { str[0] = rep }.should raise_error(Encoding::CompatibilityError)
+ -> { str[0] = rep }.should.raise(Encoding::CompatibilityError)
end
end
@@ -164,7 +164,7 @@ describe "String#[]= with String index" do
it "raises an IndexError if the search String is not found" do
str = "abcde"
- -> { str["g"] = "h" }.should raise_error(IndexError)
+ -> { str["g"] = "h" }.should.raise(IndexError)
end
it "replaces characters with a multibyte character" do
@@ -189,13 +189,13 @@ describe "String#[]= with String index" do
str = " ".force_encoding Encoding::US_ASCII
rep = [160].pack('C').force_encoding Encoding::BINARY
str[" "] = rep
- str.encoding.should equal(Encoding::BINARY)
+ str.encoding.should.equal?(Encoding::BINARY)
end
it "raises an Encoding::CompatibilityError if the replacement encoding is incompatible" do
str = "ã‚れ"
rep = "ãŒ".encode Encoding::EUC_JP
- -> { str["れ"] = rep }.should raise_error(Encoding::CompatibilityError)
+ -> { str["れ"] = rep }.should.raise(Encoding::CompatibilityError)
end
end
@@ -208,7 +208,7 @@ describe "String#[]= with a Regexp index" do
it "raises IndexError if the regexp index doesn't match a position in the string" do
str = "hello"
- -> { str[/y/] = "bam" }.should raise_error(IndexError)
+ -> { str[/y/] = "bam" }.should.raise(IndexError)
str.should == "hello"
end
@@ -225,7 +225,7 @@ describe "String#[]= with a Regexp index" do
rep = mock("string element set regexp")
rep.should_not_receive(:to_str)
- -> { "abc"[/def/] = rep }.should raise_error(IndexError)
+ -> { "abc"[/def/] = rep }.should.raise(IndexError)
end
describe "with 3 arguments" do
@@ -242,7 +242,7 @@ describe "String#[]= with a Regexp index" do
ref = mock("string element set regexp ref")
ref.should_receive(:to_int).and_return(nil)
- -> { "abc"[/a(b)/, ref] = "x" }.should raise_error(TypeError)
+ -> { "abc"[/a(b)/, ref] = "x" }.should.raise(TypeError)
end
it "uses the 2nd of 3 arguments as which capture should be replaced" do
@@ -261,20 +261,20 @@ describe "String#[]= with a Regexp index" do
rep = mock("string element set regexp")
rep.should_not_receive(:to_str)
- -> { "abc"[/a(b)/, 2] = rep }.should raise_error(IndexError)
+ -> { "abc"[/a(b)/, 2] = rep }.should.raise(IndexError)
end
it "raises IndexError if the specified capture isn't available" do
str = "aaa bbb ccc"
- -> { str[/a (bbb) c/, 2] = "ddd" }.should raise_error(IndexError)
- -> { str[/a (bbb) c/, -2] = "ddd" }.should raise_error(IndexError)
+ -> { str[/a (bbb) c/, 2] = "ddd" }.should.raise(IndexError)
+ -> { str[/a (bbb) c/, -2] = "ddd" }.should.raise(IndexError)
end
describe "when the optional capture does not match" do
it "raises an IndexError before setting the replacement" do
str1 = "a b c"
str2 = str1.dup
- -> { str2[/a (b) (Z)?/, 2] = "d" }.should raise_error(IndexError)
+ -> { str2[/a (b) (Z)?/, 2] = "d" }.should.raise(IndexError)
str2.should == str1
end
end
@@ -302,13 +302,13 @@ describe "String#[]= with a Regexp index" do
str = " ".force_encoding Encoding::US_ASCII
rep = [160].pack('C').force_encoding Encoding::BINARY
str[/ /] = rep
- str.encoding.should equal(Encoding::BINARY)
+ str.encoding.should.equal?(Encoding::BINARY)
end
it "raises an Encoding::CompatibilityError if the replacement encoding is incompatible" do
str = "ã‚れ"
rep = "ãŒ".encode Encoding::EUC_JP
- -> { str[/れ/] = rep }.should raise_error(Encoding::CompatibilityError)
+ -> { str[/れ/] = rep }.should.raise(Encoding::CompatibilityError)
end
end
@@ -358,11 +358,11 @@ describe "String#[]= with a Range index" do
end
it "raises a RangeError if negative Range begin is out of range" do
- -> { "abc"[-4..-2] = "x" }.should raise_error(RangeError, "-4..-2 out of range")
+ -> { "abc"[-4..-2] = "x" }.should.raise(RangeError, "-4..-2 out of range")
end
it "raises a RangeError if positive Range begin is greater than String size" do
- -> { "abc"[4..2] = "x" }.should raise_error(RangeError, "4..2 out of range")
+ -> { "abc"[4..2] = "x" }.should.raise(RangeError, "4..2 out of range")
end
it "uses the Range end as an index rather than a count" do
@@ -423,13 +423,13 @@ describe "String#[]= with a Range index" do
str = " ".force_encoding Encoding::US_ASCII
rep = [160].pack('C').force_encoding Encoding::BINARY
str[0..1] = rep
- str.encoding.should equal(Encoding::BINARY)
+ str.encoding.should.equal?(Encoding::BINARY)
end
it "raises an Encoding::CompatibilityError if the replacement encoding is incompatible" do
str = "ã‚れ"
rep = "ãŒ".encode Encoding::EUC_JP
- -> { str[0..1] = rep }.should raise_error(Encoding::CompatibilityError)
+ -> { str[0..1] = rep }.should.raise(Encoding::CompatibilityError)
end
end
@@ -498,14 +498,14 @@ describe "String#[]= with Integer index, count" do
index = mock("string element set index")
index.should_receive(:to_int).and_return("1")
- -> { "abc"[index, 2] = "xyz" }.should raise_error(TypeError)
+ -> { "abc"[index, 2] = "xyz" }.should.raise(TypeError)
end
it "raises a TypeError if #to_int for count does not return an Integer" do
count = mock("string element set count")
count.should_receive(:to_int).and_return("1")
- -> { "abc"[1, count] = "xyz" }.should raise_error(TypeError)
+ -> { "abc"[1, count] = "xyz" }.should.raise(TypeError)
end
it "calls #to_str to convert the replacement object" do
@@ -521,23 +521,23 @@ describe "String#[]= with Integer index, count" do
r = mock("string element set replacement")
r.should_receive(:to_str).and_return(nil)
- -> { "abc"[1, 1] = r }.should raise_error(TypeError)
+ -> { "abc"[1, 1] = r }.should.raise(TypeError)
end
it "raises an IndexError if |idx| is greater than the length of the string" do
- -> { "hello"[6, 0] = "bob" }.should raise_error(IndexError)
- -> { "hello"[-6, 0] = "bob" }.should raise_error(IndexError)
+ -> { "hello"[6, 0] = "bob" }.should.raise(IndexError)
+ -> { "hello"[-6, 0] = "bob" }.should.raise(IndexError)
end
it "raises an IndexError if count < 0" do
- -> { "hello"[0, -1] = "bob" }.should raise_error(IndexError)
- -> { "hello"[1, -1] = "bob" }.should raise_error(IndexError)
+ -> { "hello"[0, -1] = "bob" }.should.raise(IndexError)
+ -> { "hello"[1, -1] = "bob" }.should.raise(IndexError)
end
it "raises a TypeError if other_str is a type other than String" do
- -> { "hello"[0, 2] = nil }.should raise_error(TypeError)
- -> { "hello"[0, 2] = [] }.should raise_error(TypeError)
- -> { "hello"[0, 2] = 33 }.should raise_error(TypeError)
+ -> { "hello"[0, 2] = nil }.should.raise(TypeError)
+ -> { "hello"[0, 2] = [] }.should.raise(TypeError)
+ -> { "hello"[0, 2] = 33 }.should.raise(TypeError)
end
it "replaces characters with a multibyte character" do
@@ -571,19 +571,19 @@ describe "String#[]= with Integer index, count" do
end
it "raises an IndexError if the character index is out of range of a multibyte String" do
- -> { "ã‚れ"[3, 0] = "り" }.should raise_error(IndexError)
+ -> { "ã‚れ"[3, 0] = "り" }.should.raise(IndexError)
end
it "encodes the String in an encoding compatible with the replacement" do
str = " ".force_encoding Encoding::US_ASCII
rep = [160].pack('C').force_encoding Encoding::BINARY
str[0, 1] = rep
- str.encoding.should equal(Encoding::BINARY)
+ str.encoding.should.equal?(Encoding::BINARY)
end
it "raises an Encoding::CompatibilityError if the replacement encoding is incompatible" do
str = "ã‚れ"
rep = "ãŒ".encode Encoding::EUC_JP
- -> { str[0, 1] = rep }.should raise_error(Encoding::CompatibilityError)
+ -> { str[0, 1] = rep }.should.raise(Encoding::CompatibilityError)
end
end
diff --git a/spec/ruby/core/string/encode_spec.rb b/spec/ruby/core/string/encode_spec.rb
index cd449498a3..ab096f4041 100644
--- a/spec/ruby/core/string/encode_spec.rb
+++ b/spec/ruby/core/string/encode_spec.rb
@@ -20,7 +20,7 @@ describe "String#encode" do
Encoding.default_internal = nil
str = "ã‚"
encoded = str.encode
- encoded.should_not equal(str)
+ encoded.should_not.equal?(str)
encoded.should == str
end
@@ -28,7 +28,7 @@ describe "String#encode" do
Encoding.default_internal = nil
str = "abc"
encoded = str.encode
- encoded.should_not equal(str)
+ encoded.should_not.equal?(str)
encoded.should == str
end
@@ -36,7 +36,7 @@ describe "String#encode" 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.encoding.should equal(Encoding::UTF_8)
+ str.encoding.should.equal?(Encoding::UTF_8)
end
end
@@ -44,7 +44,7 @@ describe "String#encode" do
it "returns a copy when passed the same encoding as the String" do
str = "ã‚"
encoded = str.encode(Encoding::UTF_8)
- encoded.should_not equal(str)
+ encoded.should_not.equal?(str)
encoded.should == str
end
@@ -58,7 +58,7 @@ describe "String#encode" do
it "returns a copy when Encoding.default_internal is nil" do
Encoding.default_internal = nil
str = "ã‚"
- str.encode(invalid: :replace).should_not equal(str)
+ str.encode(invalid: :replace).should_not.equal?(str)
end
it "normalizes newlines with cr_newline option" do
@@ -137,7 +137,7 @@ describe "String#encode" do
str = "ã‚".dup.force_encoding("binary")
encoded = str.encode("utf-8", "utf-8")
- encoded.should_not equal(str)
+ encoded.should_not.equal?(str)
encoded.should == str.force_encoding("utf-8")
encoded.encoding.should == Encoding::UTF_8
end
@@ -152,7 +152,7 @@ describe "String#encode" do
it "returns a copy when the destination encoding is the same as the String encoding" do
str = "ã‚"
encoded = str.encode(Encoding::UTF_8, undef: :replace)
- encoded.should_not equal(str)
+ encoded.should_not.equal?(str)
encoded.should == str
end
end
@@ -161,7 +161,7 @@ describe "String#encode" do
it "returns a copy when both encodings are the same" do
str = "ã‚"
encoded = str.encode("utf-8", "utf-8", invalid: :replace)
- encoded.should_not equal(str)
+ encoded.should_not.equal?(str)
encoded.should == str
end
@@ -169,7 +169,7 @@ describe "String#encode" do
str = "ã‚".dup.force_encoding("binary")
encoded = str.encode("utf-8", "utf-8", invalid: :replace)
- encoded.should_not equal(str)
+ encoded.should_not.equal?(str)
encoded.should == str.force_encoding("utf-8")
encoded.encoding.should == Encoding::UTF_8
end
@@ -190,25 +190,25 @@ describe "String#encode!" do
it_behaves_like :string_encode, :encode!
it "raises a FrozenError when called on a frozen String" do
- -> { "foo".freeze.encode!("euc-jp") }.should raise_error(FrozenError)
+ -> { "foo".freeze.encode!("euc-jp") }.should.raise(FrozenError)
end
# http://redmine.ruby-lang.org/issues/show/1836
it "raises a FrozenError when called on a frozen String when it's a no-op" do
- -> { "foo".freeze.encode!("utf-8") }.should raise_error(FrozenError)
+ -> { "foo".freeze.encode!("utf-8") }.should.raise(FrozenError)
end
describe "when passed no options" do
it "returns self when Encoding.default_internal is nil" do
Encoding.default_internal = nil
str = +"ã‚"
- str.encode!.should equal(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.encode!.should equal(str)
+ str.encode!.should.equal?(str)
end
end
@@ -216,7 +216,7 @@ describe "String#encode!" do
it "returns self for ASCII-only String when Encoding.default_internal is nil" do
Encoding.default_internal = nil
str = +"abc"
- str.encode!(invalid: :replace).should equal(str)
+ str.encode!(invalid: :replace).should.equal?(str)
end
end
@@ -224,8 +224,8 @@ describe "String#encode!" do
it "returns self" do
str = +"abc"
result = str.encode!(Encoding::BINARY)
- result.encoding.should equal(Encoding::BINARY)
- result.should equal(str)
+ result.encoding.should.equal?(Encoding::BINARY)
+ result.should.equal?(str)
end
end
@@ -233,8 +233,8 @@ describe "String#encode!" do
it "returns self" do
str = +"ã‚ã‚"
result = str.encode!("euc-jp", "utf-8")
- result.encoding.should equal(Encoding::EUC_JP)
- result.should equal(str)
+ result.encoding.should.equal?(Encoding::EUC_JP)
+ result.should.equal?(str)
end
end
end
diff --git a/spec/ruby/core/string/encoding_spec.rb b/spec/ruby/core/string/encoding_spec.rb
index f6e8fd3470..aa0e4765ed 100644
--- a/spec/ruby/core/string/encoding_spec.rb
+++ b/spec/ruby/core/string/encoding_spec.rb
@@ -4,7 +4,7 @@ require_relative 'fixtures/iso-8859-9-encoding'
describe "String#encoding" do
it "returns an Encoding object" do
- String.new.encoding.should be_an_instance_of(Encoding)
+ String.new.encoding.should.instance_of?(Encoding)
end
it "is equal to the source encoding by default" do
@@ -70,13 +70,13 @@ describe "String#encoding for Strings with \\u escapes" do
it "returns US-ASCII if self is US-ASCII only" do
s = "\u{40}"
- s.ascii_only?.should be_true
+ s.ascii_only?.should == true
s.encoding.should == Encoding::US_ASCII
end
it "returns UTF-8 if self isn't US-ASCII only" do
s = "\u{4076}\u{619}"
- s.ascii_only?.should be_false
+ s.ascii_only?.should == false
s.encoding.should == Encoding::UTF_8
end
@@ -122,7 +122,7 @@ describe "String#encoding for Strings with \\x escapes" do
it "returns US-ASCII if self is US-ASCII only" do
s = "\x61"
- s.ascii_only?.should be_true
+ s.ascii_only?.should == true
s.encoding.should == Encoding::US_ASCII
end
@@ -131,7 +131,7 @@ describe "String#encoding for Strings with \\x escapes" do
str = " "
str.encoding.should == Encoding::US_ASCII
str += [0xDF].pack('C')
- str.ascii_only?.should be_false
+ str.ascii_only?.should == false
str.encoding.should == Encoding::BINARY
end
@@ -140,7 +140,7 @@ describe "String#encoding for Strings with \\x escapes" do
it "returns the source encoding when an escape creates a byte with the 8th bit set if the source encoding isn't US-ASCII" do
fixture = StringSpecs::ISO88599Encoding.new
fixture.source_encoding.should == Encoding::ISO8859_9
- fixture.x_escape.ascii_only?.should be_false
+ fixture.x_escape.ascii_only?.should == false
fixture.x_escape.encoding.should == Encoding::ISO8859_9
end
diff --git a/spec/ruby/core/string/eql_spec.rb b/spec/ruby/core/string/eql_spec.rb
index 397974d9fb..46ebeda509 100644
--- a/spec/ruby/core/string/eql_spec.rb
+++ b/spec/ruby/core/string/eql_spec.rb
@@ -6,16 +6,16 @@ describe "String#eql?" do
describe "when given a non-String" do
it "returns false" do
- 'hello'.should_not eql(5)
+ 'hello'.should_not.eql?(5)
not_supported_on :opal do
- 'hello'.should_not eql(:hello)
+ 'hello'.should_not.eql?(:hello)
end
- 'hello'.should_not eql(mock('x'))
+ 'hello'.should_not.eql?(mock('x'))
end
it "does not try to call #to_str on the given argument" do
(obj = mock('x')).should_not_receive(:to_str)
- 'hello'.should_not eql(obj)
+ 'hello'.should_not.eql?(obj)
end
end
end
diff --git a/spec/ruby/core/string/equal_value_spec.rb b/spec/ruby/core/string/equal_value_spec.rb
index b9c9c372f8..e8b706c524 100644
--- a/spec/ruby/core/string/equal_value_spec.rb
+++ b/spec/ruby/core/string/equal_value_spec.rb
@@ -1,8 +1,30 @@
require_relative '../../spec_helper'
require_relative 'shared/eql'
-require_relative 'shared/equal_value'
describe "String#==" do
it_behaves_like :string_eql_value, :==
- it_behaves_like :string_equal_value, :==
+
+ it "returns false if obj does not respond to to_str" do
+ ('hello' == 5).should == false
+ not_supported_on :opal do
+ ('hello' == :hello).should == false
+ end
+ ('hello' == mock('x')).should == false
+ end
+
+ it "returns obj == self if obj responds to to_str" do
+ obj = Object.new
+
+ # String#== merely checks if #to_str is defined. It does
+ # not call it.
+ obj.stub!(:to_str)
+
+ obj.should_receive(:==).and_return(true)
+
+ ('hello' == obj).should == true
+ end
+
+ it "is not fooled by NUL characters" do
+ ("abc\0def" == "abc\0xyz").should == false
+ end
end
diff --git a/spec/ruby/core/string/force_encoding_spec.rb b/spec/ruby/core/string/force_encoding_spec.rb
index 2259dcf3cf..fc6914213f 100644
--- a/spec/ruby/core/string/force_encoding_spec.rb
+++ b/spec/ruby/core/string/force_encoding_spec.rb
@@ -41,23 +41,23 @@ describe "String#force_encoding" do
obj = mock("force_encoding")
obj.should_receive(:to_str).and_return(1)
- -> { "abc".force_encoding(obj) }.should raise_error(TypeError)
+ -> { "abc".force_encoding(obj) }.should.raise(TypeError)
end
it "raises a TypeError if passed nil" do
- -> { "abc".force_encoding(nil) }.should raise_error(TypeError)
+ -> { "abc".force_encoding(nil) }.should.raise(TypeError)
end
it "returns self" do
str = "abc"
- str.force_encoding('utf-8').should equal(str)
+ str.force_encoding('utf-8').should.equal?(str)
end
it "sets the encoding even if the String contents are invalid in that encoding" do
str = "\u{9765}"
str.force_encoding('euc-jp')
str.encoding.should == Encoding::EUC_JP
- str.valid_encoding?.should be_false
+ str.valid_encoding?.should == false
end
it "does not transcode self" do
@@ -67,6 +67,6 @@ describe "String#force_encoding" do
it "raises a FrozenError if self is frozen" do
str = "abcd".freeze
- -> { str.force_encoding(str.encoding) }.should raise_error(FrozenError)
+ -> { str.force_encoding(str.encoding) }.should.raise(FrozenError)
end
end
diff --git a/spec/ruby/core/string/freeze_spec.rb b/spec/ruby/core/string/freeze_spec.rb
index 2e8e70386d..8485e8de21 100644
--- a/spec/ruby/core/string/freeze_spec.rb
+++ b/spec/ruby/core/string/freeze_spec.rb
@@ -4,11 +4,11 @@ require_relative '../../spec_helper'
describe "String#freeze" do
it "produces the same object whenever called on an instance of a literal in the source" do
- "abc".freeze.should equal "abc".freeze
+ "abc".freeze.should.equal? "abc".freeze
end
it "doesn't produce the same object for different instances of literals in the source" do
- "abc".should_not equal "abc"
+ "abc".should_not.equal? "abc"
end
it "being a special form doesn't change the value of defined?" do
diff --git a/spec/ruby/core/string/getbyte_spec.rb b/spec/ruby/core/string/getbyte_spec.rb
index 27b7d826ea..d4619dca61 100644
--- a/spec/ruby/core/string/getbyte_spec.rb
+++ b/spec/ruby/core/string/getbyte_spec.rb
@@ -3,7 +3,7 @@ require_relative '../../spec_helper'
describe "String#getbyte" do
it "returns an Integer if given a valid index" do
- "a".getbyte(0).should be_kind_of(Integer)
+ "a".getbyte(0).should.is_a?(Integer)
end
it "starts indexing at 0" do
@@ -51,19 +51,19 @@ describe "String#getbyte" do
end
it "returns nil for out-of-bound indexes" do
- "g".getbyte(1).should be_nil
+ "g".getbyte(1).should == nil
end
it "regards the empty String as containing no bytes" do
- "".getbyte(0).should be_nil
+ "".getbyte(0).should == nil
end
it "raises an ArgumentError unless given one argument" do
- -> { "glark".getbyte }.should raise_error(ArgumentError)
- -> { "food".getbyte(0,0) }.should raise_error(ArgumentError)
+ -> { "glark".getbyte }.should.raise(ArgumentError)
+ -> { "food".getbyte(0,0) }.should.raise(ArgumentError)
end
it "raises a TypeError unless its argument can be coerced into an Integer" do
- -> { "a".getbyte('a') }.should raise_error(TypeError)
+ -> { "a".getbyte('a') }.should.raise(TypeError)
end
end
diff --git a/spec/ruby/core/string/gsub_spec.rb b/spec/ruby/core/string/gsub_spec.rb
index 0d9f32eca2..d0e1c30bd2 100644
--- a/spec/ruby/core/string/gsub_spec.rb
+++ b/spec/ruby/core/string/gsub_spec.rb
@@ -175,9 +175,9 @@ describe "String#gsub with pattern and replacement" do
end
it "raises a TypeError when pattern can't be converted to a string" do
- -> { "hello".gsub([], "x") }.should raise_error(TypeError)
- -> { "hello".gsub(Object.new, "x") }.should raise_error(TypeError)
- -> { "hello".gsub(nil, "x") }.should raise_error(TypeError)
+ -> { "hello".gsub([], "x") }.should.raise(TypeError)
+ -> { "hello".gsub(Object.new, "x") }.should.raise(TypeError)
+ -> { "hello".gsub(nil, "x") }.should.raise(TypeError)
end
it "tries to convert replacement to a string using to_str" do
@@ -188,16 +188,16 @@ describe "String#gsub with pattern and replacement" do
end
it "raises a TypeError when replacement can't be converted to a string" do
- -> { "hello".gsub(/[aeiou]/, []) }.should raise_error(TypeError)
- -> { "hello".gsub(/[aeiou]/, Object.new) }.should raise_error(TypeError)
- -> { "hello".gsub(/[aeiou]/, nil) }.should raise_error(TypeError)
+ -> { "hello".gsub(/[aeiou]/, []) }.should.raise(TypeError)
+ -> { "hello".gsub(/[aeiou]/, Object.new) }.should.raise(TypeError)
+ -> { "hello".gsub(/[aeiou]/, nil) }.should.raise(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)
+ StringSpecs::MyString.new("").gsub(//, "").should.instance_of?(String)
+ StringSpecs::MyString.new("").gsub(/foo/, "").should.instance_of?(String)
+ StringSpecs::MyString.new("foo").gsub(/foo/, "").should.instance_of?(String)
+ StringSpecs::MyString.new("foo").gsub("foo", "").should.instance_of?(String)
end
it "sets $~ to MatchData of last match and nil when there's none" do
@@ -450,8 +450,8 @@ describe "String#gsub with pattern and block" do
s = "hllëllo"
s2 = "hellö"
- -> { s.gsub(/l/) { |bar| "РуÑÑкий".force_encoding("iso-8859-5") } }.should raise_error(Encoding::CompatibilityError)
- -> { s2.gsub(/l/) { |bar| "РуÑÑкий".force_encoding("iso-8859-5") } }.should raise_error(Encoding::CompatibilityError)
+ -> { s.gsub(/l/) { |bar| "РуÑÑкий".force_encoding("iso-8859-5") } }.should.raise(Encoding::CompatibilityError)
+ -> { s2.gsub(/l/) { |bar| "РуÑÑкий".force_encoding("iso-8859-5") } }.should.raise(Encoding::CompatibilityError)
end
it "replaces the incompatible part properly even if the encodings are not compatible" do
@@ -463,7 +463,7 @@ describe "String#gsub with pattern and block" do
not_supported_on :opal do
it "raises an ArgumentError if encoding is not valid" do
x92 = [0x92].pack('C').force_encoding('utf-8')
- -> { "a#{x92}b".gsub(/[^\x00-\x7f]/u, '') }.should raise_error(ArgumentError)
+ -> { "a#{x92}b".gsub(/[^\x00-\x7f]/u, '') }.should.raise(ArgumentError)
end
end
end
@@ -471,7 +471,7 @@ end
describe "String#gsub with pattern and without replacement and block" do
it "returns an enumerator" do
enum = "abca".gsub(/a/)
- enum.should be_an_instance_of(Enumerator)
+ enum.should.instance_of?(Enumerator)
enum.to_a.should == ["a", "a"]
end
@@ -495,13 +495,13 @@ end
describe "String#gsub! with pattern and replacement" do
it "modifies self in place and returns self" do
a = "hello"
- a.gsub!(/[aeiou]/, '*').should equal(a)
+ a.gsub!(/[aeiou]/, '*').should.equal?(a)
a.should == "h*ll*"
end
it "modifies self in place with multi-byte characters and returns self" do
a = "¿por qué?"
- a.gsub!(/([a-z\d]*)/, "*").should equal(a)
+ a.gsub!(/([a-z\d]*)/, "*").should.equal?(a)
a.should == "*¿** **é*?*"
end
@@ -517,9 +517,9 @@ describe "String#gsub! with pattern and replacement" do
s = "hello"
s.freeze
- -> { s.gsub!(/ROAR/, "x") }.should raise_error(FrozenError)
- -> { s.gsub!(/e/, "e") }.should raise_error(FrozenError)
- -> { s.gsub!(/[aeiou]/, '*') }.should raise_error(FrozenError)
+ -> { s.gsub!(/ROAR/, "x") }.should.raise(FrozenError)
+ -> { s.gsub!(/e/, "e") }.should.raise(FrozenError)
+ -> { s.gsub!(/[aeiou]/, '*') }.should.raise(FrozenError)
end
it "handles a pattern in a superset encoding" do
@@ -547,7 +547,7 @@ end
describe "String#gsub! with pattern and block" do
it "modifies self in place and returns self" do
a = "hello"
- a.gsub!(/[aeiou]/) { '*' }.should equal(a)
+ a.gsub!(/[aeiou]/) { '*' }.should.equal?(a)
a.should == "h*ll*"
end
@@ -563,9 +563,9 @@ describe "String#gsub! with pattern and block" do
s = "hello"
s.freeze
- -> { s.gsub!(/ROAR/) { "x" } }.should raise_error(FrozenError)
- -> { s.gsub!(/e/) { "e" } }.should raise_error(FrozenError)
- -> { s.gsub!(/[aeiou]/) { '*' } }.should raise_error(FrozenError)
+ -> { s.gsub!(/ROAR/) { "x" } }.should.raise(FrozenError)
+ -> { s.gsub!(/e/) { "e" } }.should.raise(FrozenError)
+ -> { s.gsub!(/[aeiou]/) { '*' } }.should.raise(FrozenError)
end
it "uses the compatible encoding if they are compatible" do
@@ -580,8 +580,8 @@ describe "String#gsub! with pattern and block" do
s = "hllëllo"
s2 = "hellö"
- -> { s.gsub!(/l/) { |bar| "РуÑÑкий".force_encoding("iso-8859-5") } }.should raise_error(Encoding::CompatibilityError)
- -> { s2.gsub!(/l/) { |bar| "РуÑÑкий".force_encoding("iso-8859-5") } }.should raise_error(Encoding::CompatibilityError)
+ -> { s.gsub!(/l/) { |bar| "РуÑÑкий".force_encoding("iso-8859-5") } }.should.raise(Encoding::CompatibilityError)
+ -> { s2.gsub!(/l/) { |bar| "РуÑÑкий".force_encoding("iso-8859-5") } }.should.raise(Encoding::CompatibilityError)
end
it "replaces the incompatible part properly even if the encodings are not compatible" do
@@ -593,7 +593,7 @@ describe "String#gsub! with pattern and block" do
not_supported_on :opal do
it "raises an ArgumentError if encoding is not valid" do
x92 = [0x92].pack('C').force_encoding('utf-8')
- -> { "a#{x92}b".gsub!(/[^\x00-\x7f]/u, '') }.should raise_error(ArgumentError)
+ -> { "a#{x92}b".gsub!(/[^\x00-\x7f]/u, '') }.should.raise(ArgumentError)
end
end
end
@@ -601,7 +601,7 @@ end
describe "String#gsub! with pattern and without replacement and block" do
it "returns an enumerator" do
enum = "abca".gsub!(/a/)
- enum.should be_an_instance_of(Enumerator)
+ enum.should.instance_of?(Enumerator)
enum.to_a.should == ["a", "a"]
end
diff --git a/spec/ruby/core/string/include_spec.rb b/spec/ruby/core/string/include_spec.rb
index 9781140a55..d943430335 100644
--- a/spec/ruby/core/string/include_spec.rb
+++ b/spec/ruby/core/string/include_spec.rb
@@ -35,15 +35,15 @@ describe "String#include? with String" do
end
it "raises a TypeError if other can't be converted to string" do
- -> { "hello".include?([]) }.should raise_error(TypeError)
- -> { "hello".include?('h'.ord) }.should raise_error(TypeError)
- -> { "hello".include?(mock('x')) }.should raise_error(TypeError)
+ -> { "hello".include?([]) }.should.raise(TypeError)
+ -> { "hello".include?('h'.ord) }.should.raise(TypeError)
+ -> { "hello".include?(mock('x')) }.should.raise(TypeError)
end
it "raises an Encoding::CompatibilityError if the encodings are incompatible" do
pat = "ã‚¢".encode Encoding::EUC_JP
-> do
"ã‚れ".include?(pat)
- end.should raise_error(Encoding::CompatibilityError)
+ end.should.raise(Encoding::CompatibilityError)
end
end
diff --git a/spec/ruby/core/string/index_spec.rb b/spec/ruby/core/string/index_spec.rb
index 835263a2cd..3f82181b98 100644
--- a/spec/ruby/core/string/index_spec.rb
+++ b/spec/ruby/core/string/index_spec.rb
@@ -4,15 +4,15 @@ require_relative 'fixtures/classes'
describe "String#index" do
it "raises a TypeError if passed nil" do
- -> { "abc".index nil }.should raise_error(TypeError)
+ -> { "abc".index nil }.should.raise(TypeError)
end
it "raises a TypeError if passed a boolean" do
- -> { "abc".index true }.should raise_error(TypeError)
+ -> { "abc".index true }.should.raise(TypeError)
end
it "raises a TypeError if passed a Symbol" do
- -> { "abc".index :a }.should raise_error(TypeError)
+ -> { "abc".index :a }.should.raise(TypeError)
end
it "calls #to_str to convert the first argument" do
@@ -28,7 +28,7 @@ describe "String#index" do
end
it "raises a TypeError if passed an Integer" do
- -> { "abc".index 97 }.should raise_error(TypeError)
+ -> { "abc".index 97 }.should.raise(TypeError)
end
end
@@ -157,7 +157,7 @@ describe "String#index with String" do
char = "れ".encode Encoding::EUC_JP
-> do
"ã‚れ".index char
- end.should raise_error(Encoding::CompatibilityError)
+ end.should.raise(Encoding::CompatibilityError)
end
it "handles a substring in a superset encoding" do
@@ -172,7 +172,7 @@ describe "String#index with String" 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")
+ -> { str.index(pattern) }.should.raise(Encoding::CompatibilityError, "incompatible character encodings: ISO-2022-JP and EUC-JP")
end
end
@@ -231,15 +231,13 @@ 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
+ it "always clear $~" do
+ "a".index(/a/)
+ $~.should_not == nil
- string = "blablabla"
- string.index(/bla/, string.length + 1)
- $~.should == nil
- end
+ string = "blablabla"
+ string.index(/bla/, string.length + 1)
+ $~.should == nil
end
it "starts the search at the given offset" do
@@ -289,7 +287,7 @@ describe "String#index with Regexp" do
end
it "returns nil if the Regexp matches the empty string and the offset is out of range" do
- "ruby".index(//,12).should be_nil
+ "ruby".index(//,12).should == nil
end
it "supports \\G which matches at the given start offset" do
@@ -330,21 +328,10 @@ 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
"ã‚れ".index re
- end.should raise_error(Encoding::CompatibilityError)
+ end.should.raise(Encoding::CompatibilityError, "incompatible encoding regexp match (EUC-JP regexp with UTF-8 string)")
end
end
diff --git a/spec/ruby/core/string/initialize_spec.rb b/spec/ruby/core/string/initialize_spec.rb
index 08734cc916..b0c1e2e573 100644
--- a/spec/ruby/core/string/initialize_spec.rb
+++ b/spec/ruby/core/string/initialize_spec.rb
@@ -4,7 +4,7 @@ require_relative 'shared/replace'
describe "String#initialize" do
it "is a private method" do
- String.should have_private_instance_method(:initialize)
+ String.private_instance_methods(false).should.include?(:initialize)
end
describe "with no arguments" do
@@ -16,7 +16,7 @@ describe "String#initialize" do
it "does not raise an exception when frozen" do
a = "hello".freeze
- a.send(:initialize).should equal(a)
+ a.send(:initialize).should.equal?(a)
end
end
diff --git a/spec/ruby/core/string/insert_spec.rb b/spec/ruby/core/string/insert_spec.rb
index 483f3c9367..c89793a8ca 100644
--- a/spec/ruby/core/string/insert_spec.rb
+++ b/spec/ruby/core/string/insert_spec.rb
@@ -23,8 +23,8 @@ describe "String#insert with index, other" do
end
it "raises an IndexError if the index is beyond string" do
- -> { "abcd".insert(5, 'X') }.should raise_error(IndexError)
- -> { "abcd".insert(-6, 'X') }.should raise_error(IndexError)
+ -> { "abcd".insert(5, 'X') }.should.raise(IndexError)
+ -> { "abcd".insert(-6, 'X') }.should.raise(IndexError)
end
it "converts index to an integer using to_int" do
@@ -42,15 +42,15 @@ describe "String#insert with index, other" do
end
it "raises a TypeError if other can't be converted to string" do
- -> { "abcd".insert(-6, Object.new)}.should raise_error(TypeError)
- -> { "abcd".insert(-6, []) }.should raise_error(TypeError)
- -> { "abcd".insert(-6, mock('x')) }.should raise_error(TypeError)
+ -> { "abcd".insert(-6, Object.new)}.should.raise(TypeError)
+ -> { "abcd".insert(-6, []) }.should.raise(TypeError)
+ -> { "abcd".insert(-6, mock('x')) }.should.raise(TypeError)
end
it "raises a FrozenError if self is frozen" do
str = "abcd".freeze
- -> { str.insert(4, '') }.should raise_error(FrozenError)
- -> { str.insert(4, 'X') }.should raise_error(FrozenError)
+ -> { str.insert(4, '') }.should.raise(FrozenError)
+ -> { str.insert(4, 'X') }.should.raise(FrozenError)
end
it "inserts a character into a multibyte encoded string" do
@@ -67,7 +67,7 @@ describe "String#insert with index, other" do
pat = "ã‚¢".encode Encoding::EUC_JP
-> do
"ã‚れ".insert 0, pat
- end.should raise_error(Encoding::CompatibilityError)
+ end.should.raise(Encoding::CompatibilityError)
end
it "should not call subclassed string methods" do
diff --git a/spec/ruby/core/string/inspect_spec.rb b/spec/ruby/core/string/inspect_spec.rb
index 15db06c7f5..8b91ce2f84 100644
--- a/spec/ruby/core/string/inspect_spec.rb
+++ b/spec/ruby/core/string/inspect_spec.rb
@@ -4,7 +4,7 @@ require_relative 'fixtures/classes'
describe "String#inspect" do
it "does not return a subclass instance" do
- StringSpecs::MyString.new.inspect.should be_an_instance_of(String)
+ StringSpecs::MyString.new.inspect.should.instance_of?(String)
end
it "returns a string with special characters replaced with \\<char> notation" do
diff --git a/spec/ruby/core/string/intern_spec.rb b/spec/ruby/core/string/intern_spec.rb
index cd7dad4359..af85e56dba 100644
--- a/spec/ruby/core/string/intern_spec.rb
+++ b/spec/ruby/core/string/intern_spec.rb
@@ -1,7 +1,7 @@
require_relative '../../spec_helper'
-require_relative 'fixtures/classes'
-require_relative 'shared/to_sym'
describe "String#intern" do
- it_behaves_like :string_to_sym, :intern
+ it "is an alias of String#to_sym" do
+ String.instance_method(:intern).should == String.instance_method(:to_sym)
+ end
end
diff --git a/spec/ruby/core/string/length_spec.rb b/spec/ruby/core/string/length_spec.rb
index 98cee1f03d..a723babdbc 100644
--- a/spec/ruby/core/string/length_spec.rb
+++ b/spec/ruby/core/string/length_spec.rb
@@ -1,7 +1,56 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
-require_relative 'shared/length'
describe "String#length" do
- it_behaves_like :string_length, :length
+ it "returns the length of self" do
+ "".length.should == 0
+ "\x00".length.should == 1
+ "one".length.should == 3
+ "two".length.should == 3
+ "three".length.should == 5
+ "four".length.should == 4
+ end
+
+ it "returns the length of a string in different encodings" do
+ utf8_str = 'ã“ã«ã¡ã‚' * 100
+ utf8_str.length.should == 400
+ utf8_str.encode(Encoding::UTF_32BE).length.should == 400
+ utf8_str.encode(Encoding::SHIFT_JIS).length.should == 400
+ end
+
+ it "returns the length of the new self after encoding is changed" do
+ str = +'ã“ã«ã¡ã‚'
+ str.length
+
+ str.force_encoding('BINARY').length.should == 12
+ end
+
+ it "returns the correct length after force_encoding(BINARY)" do
+ utf8 = "ã‚"
+ ascii = "a"
+ concat = utf8 + ascii
+
+ concat.encoding.should == Encoding::UTF_8
+ concat.bytesize.should == 4
+
+ concat.length.should == 2
+ concat.force_encoding(Encoding::ASCII_8BIT)
+ concat.length.should == 4
+ end
+
+ it "adds 1 for every invalid byte in UTF-8" do
+ "\xF4\x90\x80\x80".length.should == 4
+ "a\xF4\x90\x80\x80b".length.should == 6
+ "é\xF4\x90\x80\x80è".length.should == 6
+ end
+
+ it "adds 1 (and not 2) for a incomplete surrogate in UTF-16" do
+ "\x00\xd8".dup.force_encoding("UTF-16LE").length.should == 1
+ "\xd8\x00".dup.force_encoding("UTF-16BE").length.should == 1
+ end
+
+ it "adds 1 for a broken sequence in UTF-32" do
+ "\x04\x03\x02\x01".dup.force_encoding("UTF-32LE").length.should == 1
+ "\x01\x02\x03\x04".dup.force_encoding("UTF-32BE").length.should == 1
+ end
end
diff --git a/spec/ruby/core/string/ljust_spec.rb b/spec/ruby/core/string/ljust_spec.rb
index 47324c59d2..0b2aab2638 100644
--- a/spec/ruby/core/string/ljust_spec.rb
+++ b/spec/ruby/core/string/ljust_spec.rb
@@ -41,10 +41,10 @@ describe "String#ljust with length, padding" do
end
it "raises a TypeError when length can't be converted to an integer" do
- -> { "hello".ljust("x") }.should raise_error(TypeError)
- -> { "hello".ljust("x", "y") }.should raise_error(TypeError)
- -> { "hello".ljust([]) }.should raise_error(TypeError)
- -> { "hello".ljust(mock('x')) }.should raise_error(TypeError)
+ -> { "hello".ljust("x") }.should.raise(TypeError)
+ -> { "hello".ljust("x", "y") }.should.raise(TypeError)
+ -> { "hello".ljust([]) }.should.raise(TypeError)
+ -> { "hello".ljust(mock('x')) }.should.raise(TypeError)
end
it "tries to convert padstr to a string using to_str" do
@@ -55,22 +55,22 @@ describe "String#ljust with length, padding" do
end
it "raises a TypeError when padstr can't be converted" do
- -> { "hello".ljust(20, []) }.should raise_error(TypeError)
- -> { "hello".ljust(20, Object.new)}.should raise_error(TypeError)
- -> { "hello".ljust(20, mock('x')) }.should raise_error(TypeError)
+ -> { "hello".ljust(20, []) }.should.raise(TypeError)
+ -> { "hello".ljust(20, Object.new)}.should.raise(TypeError)
+ -> { "hello".ljust(20, mock('x')) }.should.raise(TypeError)
end
it "raises an ArgumentError when padstr is empty" do
- -> { "hello".ljust(10, '') }.should raise_error(ArgumentError)
+ -> { "hello".ljust(10, '') }.should.raise(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)
+ StringSpecs::MyString.new("").ljust(10).should.instance_of?(String)
+ StringSpecs::MyString.new("foo").ljust(10).should.instance_of?(String)
+ StringSpecs::MyString.new("foo").ljust(10, StringSpecs::MyString.new("x")).should.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)
+ "".ljust(10, StringSpecs::MyString.new("x")).should.instance_of?(String)
+ "foo".ljust(10, StringSpecs::MyString.new("x")).should.instance_of?(String)
end
describe "with width" do
@@ -78,7 +78,7 @@ describe "String#ljust with length, padding" do
str = "abc".dup.force_encoding Encoding::IBM437
result = str.ljust 5
result.should == "abc "
- result.encoding.should equal(Encoding::IBM437)
+ result.encoding.should.equal?(Encoding::IBM437)
end
end
@@ -87,14 +87,14 @@ describe "String#ljust with length, padding" do
str = "abc".dup.force_encoding Encoding::IBM437
result = str.ljust 5, "ã‚"
result.should == "abcã‚ã‚"
- result.encoding.should equal(Encoding::UTF_8)
+ result.encoding.should.equal?(Encoding::UTF_8)
end
it "raises an Encoding::CompatibilityError if the encodings are incompatible" do
pat = "ã‚¢".encode Encoding::EUC_JP
-> do
"ã‚れ".ljust 5, pat
- end.should raise_error(Encoding::CompatibilityError)
+ end.should.raise(Encoding::CompatibilityError)
end
end
end
diff --git a/spec/ruby/core/string/lstrip_spec.rb b/spec/ruby/core/string/lstrip_spec.rb
index c83650207e..5896f8d7da 100644
--- a/spec/ruby/core/string/lstrip_spec.rb
+++ b/spec/ruby/core/string/lstrip_spec.rb
@@ -30,7 +30,7 @@ end
describe "String#lstrip!" do
it "modifies self in place and returns self" do
a = " hello "
- a.lstrip!.should equal(a)
+ a.lstrip!.should.equal?(a)
a.should == "hello "
end
@@ -53,22 +53,22 @@ describe "String#lstrip!" do
end
it "raises a FrozenError on a frozen instance that is modified" do
- -> { " hello ".freeze.lstrip! }.should raise_error(FrozenError)
+ -> { " hello ".freeze.lstrip! }.should.raise(FrozenError)
end
# see [ruby-core:23657]
it "raises a FrozenError on a frozen instance that would not be modified" do
- -> { "hello".freeze.lstrip! }.should raise_error(FrozenError)
- -> { "".freeze.lstrip! }.should raise_error(FrozenError)
+ -> { "hello".freeze.lstrip! }.should.raise(FrozenError)
+ -> { "".freeze.lstrip! }.should.raise(FrozenError)
end
it "raises an ArgumentError if the first non-space codepoint is invalid" do
s = "\xDFabc".force_encoding(Encoding::UTF_8)
- s.valid_encoding?.should be_false
- -> { s.lstrip! }.should raise_error(ArgumentError)
+ s.valid_encoding?.should == false
+ -> { s.lstrip! }.should.raise(ArgumentError)
s = " \xDFabc".force_encoding(Encoding::UTF_8)
- s.valid_encoding?.should be_false
- -> { s.lstrip! }.should raise_error(ArgumentError)
+ s.valid_encoding?.should == false
+ -> { s.lstrip! }.should.raise(ArgumentError)
end
end
diff --git a/spec/ruby/core/string/match_spec.rb b/spec/ruby/core/string/match_spec.rb
index 5e988f34ca..3ea8d90aa8 100644
--- a/spec/ruby/core/string/match_spec.rb
+++ b/spec/ruby/core/string/match_spec.rb
@@ -19,8 +19,8 @@ describe "String#=~" do
end
it "raises a TypeError if a obj is a string" do
- -> { "some string" =~ "another string" }.should raise_error(TypeError)
- -> { "a" =~ StringSpecs::MyString.new("b") }.should raise_error(TypeError)
+ -> { "some string" =~ "another string" }.should.raise(TypeError)
+ -> { "a" =~ StringSpecs::MyString.new("b") }.should.raise(TypeError)
end
it "invokes obj.=~ with self if obj is neither a string nor regexp" do
@@ -81,7 +81,7 @@ describe "String#match" do
describe "when passed a block" do
it "yields the MatchData" do
"abc".match(/./) {|m| ScratchPad.record m }
- ScratchPad.recorded.should be_kind_of(MatchData)
+ ScratchPad.recorded.should.is_a?(MatchData)
end
it "returns the block result" do
@@ -107,9 +107,9 @@ describe "String#match" do
end
it "raises a TypeError if pattern is not a regexp or a string" do
- -> { 'hello'.match(10) }.should raise_error(TypeError)
+ -> { 'hello'.match(10) }.should.raise(TypeError)
not_supported_on :opal do
- -> { 'hello'.match(:ell) }.should raise_error(TypeError)
+ -> { 'hello'.match(:ell) }.should.raise(TypeError)
end
end
@@ -137,9 +137,17 @@ describe "String#match" do
end
it "calls match on the regular expression" do
- regexp = /./.dup
- regexp.should_receive(:match).and_return(:foo)
- 'hello'.match(regexp).should == :foo
+ # Can't use regexp.should_receive(:match).and_return(:foo) since regexps are frozen
+ ScratchPad.clear
+ regexp = Class.new(Regexp) {
+ def match(*args)
+ ScratchPad.record [:match, *args]
+ super(*args)
+ end
+ }.new('.')
+
+ 'hello'.match(regexp)
+ ScratchPad.recorded.should == [:match, 'hello']
end
end
@@ -151,17 +159,17 @@ describe "String#match?" do
context "when matches the given regex" do
it "returns true but does not set Regexp.last_match" do
- 'string'.match?(/string/i).should be_true
- Regexp.last_match.should be_nil
+ 'string'.match?(/string/i).should == true
+ Regexp.last_match.should == nil
end
end
it "returns false when does not match the given regex" do
- 'string'.match?(/STRING/).should be_false
+ 'string'.match?(/STRING/).should == false
end
it "takes matching position as the 2nd argument" do
- 'string'.match?(/str/i, 0).should be_true
- 'string'.match?(/str/i, 1).should be_false
+ 'string'.match?(/str/i, 0).should == true
+ 'string'.match?(/str/i, 1).should == false
end
end
diff --git a/spec/ruby/core/string/modulo_spec.rb b/spec/ruby/core/string/modulo_spec.rb
index 46e0aa0f36..f93ec4bcf8 100644
--- a/spec/ruby/core/string/modulo_spec.rb
+++ b/spec/ruby/core/string/modulo_spec.rb
@@ -46,13 +46,13 @@ describe "String#%" do
end
it "raises if a compatible encoding can't be found" do
- -> { "hello %s".encode("utf-8") % "world".encode("UTF-16LE") }.should raise_error(Encoding::CompatibilityError)
+ -> { "hello %s".encode("utf-8") % "world".encode("UTF-16LE") }.should.raise(Encoding::CompatibilityError)
end
end
it "raises an error if single % appears at the end" do
- -> { ("%" % []) }.should raise_error(ArgumentError)
- -> { ("foo%" % [])}.should raise_error(ArgumentError)
+ -> { ("%" % []) }.should.raise(ArgumentError)
+ -> { ("foo%" % [])}.should.raise(ArgumentError)
end
ruby_version_is ""..."3.4" do
@@ -69,18 +69,18 @@ describe "String#%" do
end
it "raises an error if single % appears anywhere else" do
- -> { (" % " % []) }.should raise_error(ArgumentError)
- -> { ("foo%quux" % []) }.should raise_error(ArgumentError)
+ -> { (" % " % []) }.should.raise(ArgumentError)
+ -> { ("foo%quux" % []) }.should.raise(ArgumentError)
end
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)
+ -> { "%.\n3f" % 1.2 }.should.raise(ArgumentError)
+ -> { "%.3\nf" % 1.2 }.should.raise(ArgumentError)
+ -> { "%.\03f" % 1.2 }.should.raise(ArgumentError)
+ -> { "%.3\0f" % 1.2 }.should.raise(ArgumentError)
ensure
$DEBUG = old_debug
end
@@ -89,14 +89,14 @@ describe "String#%" do
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)
- -> { "%.\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)
+ -> { "%" % [] }.should.raise(ArgumentError)
+ -> { "%\n" % [] }.should.raise(ArgumentError)
+ -> { "%\0" % [] }.should.raise(ArgumentError)
+ -> { " % " % [] }.should.raise(ArgumentError)
+ -> { "%.\n3f" % 1.2 }.should.raise(ArgumentError)
+ -> { "%.3\nf" % 1.2 }.should.raise(ArgumentError)
+ -> { "%.\03f" % 1.2 }.should.raise(ArgumentError)
+ -> { "%.3\0f" % 1.2 }.should.raise(ArgumentError)
end
end
@@ -119,8 +119,8 @@ describe "String#%" do
s = $stderr
$stderr = IOStub.new
- -> { "" % [1, 2, 3] }.should raise_error(ArgumentError)
- -> { "%s" % [1, 2, 3] }.should raise_error(ArgumentError)
+ -> { "" % [1, 2, 3] }.should.raise(ArgumentError)
+ -> { "%s" % [1, 2, 3] }.should.raise(ArgumentError)
ensure
$DEBUG = old_debug
$stderr = s
@@ -148,26 +148,26 @@ describe "String#%" do
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)
+ -> { "hello %1$" % "foo" }.should.raise(ArgumentError)
end
end
it "raises an ArgumentError when given invalid argument specifiers" do
- -> { "%1" % [] }.should raise_error(ArgumentError)
- -> { "%+" % [] }.should raise_error(ArgumentError)
- -> { "%-" % [] }.should raise_error(ArgumentError)
- -> { "%#" % [] }.should raise_error(ArgumentError)
- -> { "%0" % [] }.should raise_error(ArgumentError)
- -> { "%*" % [] }.should raise_error(ArgumentError)
- -> { "%." % [] }.should raise_error(ArgumentError)
- -> { "%_" % [] }.should raise_error(ArgumentError)
- -> { "%0$s" % "x" }.should raise_error(ArgumentError)
- -> { "%*0$s" % [5, "x"] }.should raise_error(ArgumentError)
- -> { "%*1$.*0$1$s" % [1, 2, 3] }.should raise_error(ArgumentError)
+ -> { "%1" % [] }.should.raise(ArgumentError)
+ -> { "%+" % [] }.should.raise(ArgumentError)
+ -> { "%-" % [] }.should.raise(ArgumentError)
+ -> { "%#" % [] }.should.raise(ArgumentError)
+ -> { "%0" % [] }.should.raise(ArgumentError)
+ -> { "%*" % [] }.should.raise(ArgumentError)
+ -> { "%." % [] }.should.raise(ArgumentError)
+ -> { "%_" % [] }.should.raise(ArgumentError)
+ -> { "%0$s" % "x" }.should.raise(ArgumentError)
+ -> { "%*0$s" % [5, "x"] }.should.raise(ArgumentError)
+ -> { "%*1$.*0$1$s" % [1, 2, 3] }.should.raise(ArgumentError)
end
it "raises an ArgumentError when multiple positional argument tokens are given for one format specifier" do
- -> { "%1$1$s" % "foo" }.should raise_error(ArgumentError)
+ -> { "%1$1$s" % "foo" }.should.raise(ArgumentError)
end
it "respects positional arguments and precision tokens given for one format specifier" do
@@ -183,36 +183,36 @@ describe "String#%" do
end
it "raises an ArgumentError when multiple width star tokens are given for one format specifier" do
- -> { "%**s" % [5, 5, 5] }.should raise_error(ArgumentError)
+ -> { "%**s" % [5, 5, 5] }.should.raise(ArgumentError)
end
it "raises an ArgumentError when a width star token is seen after a width token" do
- -> { "%5*s" % [5, 5] }.should raise_error(ArgumentError)
+ -> { "%5*s" % [5, 5] }.should.raise(ArgumentError)
end
it "raises an ArgumentError when multiple precision tokens are given" do
- -> { "%.5.5s" % 5 }.should raise_error(ArgumentError)
- -> { "%.5.*s" % [5, 5] }.should raise_error(ArgumentError)
- -> { "%.*.5s" % [5, 5] }.should raise_error(ArgumentError)
+ -> { "%.5.5s" % 5 }.should.raise(ArgumentError)
+ -> { "%.5.*s" % [5, 5] }.should.raise(ArgumentError)
+ -> { "%.*.5s" % [5, 5] }.should.raise(ArgumentError)
end
it "raises an ArgumentError when there are less arguments than format specifiers" do
("foo" % []).should == "foo"
- -> { "%s" % [] }.should raise_error(ArgumentError)
- -> { "%s %s" % [1] }.should raise_error(ArgumentError)
+ -> { "%s" % [] }.should.raise(ArgumentError)
+ -> { "%s %s" % [1] }.should.raise(ArgumentError)
end
it "raises an ArgumentError when absolute and relative argument numbers are mixed" do
- -> { "%s %1$s" % "foo" }.should raise_error(ArgumentError)
- -> { "%1$s %s" % "foo" }.should raise_error(ArgumentError)
+ -> { "%s %1$s" % "foo" }.should.raise(ArgumentError)
+ -> { "%1$s %s" % "foo" }.should.raise(ArgumentError)
- -> { "%s %2$s" % ["foo", "bar"] }.should raise_error(ArgumentError)
- -> { "%2$s %s" % ["foo", "bar"] }.should raise_error(ArgumentError)
+ -> { "%s %2$s" % ["foo", "bar"] }.should.raise(ArgumentError)
+ -> { "%2$s %s" % ["foo", "bar"] }.should.raise(ArgumentError)
- -> { "%*2$s" % [5, 5, 5] }.should raise_error(ArgumentError)
- -> { "%*.*2$s" % [5, 5, 5] }.should raise_error(ArgumentError)
- -> { "%*2$.*2$s" % [5, 5, 5] }.should raise_error(ArgumentError)
- -> { "%*.*2$s" % [5, 5, 5] }.should raise_error(ArgumentError)
+ -> { "%*2$s" % [5, 5, 5] }.should.raise(ArgumentError)
+ -> { "%*.*2$s" % [5, 5, 5] }.should.raise(ArgumentError)
+ -> { "%*2$.*2$s" % [5, 5, 5] }.should.raise(ArgumentError)
+ -> { "%*.*2$s" % [5, 5, 5] }.should.raise(ArgumentError)
end
it "allows reuse of the one argument multiple via absolute argument numbers" do
@@ -221,13 +221,13 @@ describe "String#%" do
end
it "always interprets an array argument as a list of argument parameters" do
- -> { "%p" % [] }.should raise_error(ArgumentError)
+ -> { "%p" % [] }.should.raise(ArgumentError)
("%p" % [1]).should == "1"
("%p %p" % [1, 2]).should == "1 2"
end
it "always interprets an array subclass argument as a list of argument parameters" do
- -> { "%p" % StringSpecs::MyArray[] }.should raise_error(ArgumentError)
+ -> { "%p" % StringSpecs::MyArray[] }.should.raise(ArgumentError)
("%p" % StringSpecs::MyArray[1]).should == "1"
("%p %p" % StringSpecs::MyArray[1, 2]).should == "1 2"
end
@@ -298,7 +298,7 @@ describe "String#%" do
x = mock("string modulo to_ary")
x.should_receive(:to_ary).and_return("x")
- -> { "%s" % x }.should raise_error(TypeError)
+ -> { "%s" % x }.should.raise(TypeError)
end
it "tries to convert the argument to Array by calling #to_ary" do
@@ -321,7 +321,7 @@ describe "String#%" do
"%f", "%g", "%G", "%i", "%o", "%p",
"%s", "%u", "%x", "%X"
].each do |format|
- (StringSpecs::MyString.new(format) % universal).should be_an_instance_of(String)
+ (StringSpecs::MyString.new(format) % universal).should.instance_of?(String)
end
end
@@ -384,7 +384,7 @@ describe "String#%" do
("%*c" % [10, 3]).should == " \003"
("%c" % 42).should == "*"
- -> { "%c" % Object }.should raise_error(TypeError)
+ -> { "%c" % Object }.should.raise(TypeError)
end
it "supports single character strings as argument for %c" do
@@ -610,7 +610,7 @@ describe "String#%" do
# See http://groups.google.com/group/ruby-core-google/t/c285c18cd94c216d
it "raises an ArgumentError for huge precisions for %s" do
block = -> { "%.25555555555555555555555555555555555555s" % "hello world" }
- block.should raise_error(ArgumentError)
+ block.should.raise(ArgumentError)
end
# Note: %u has been changed to an alias for %d in 1.9.
@@ -705,16 +705,16 @@ describe "String#%" do
-> {
# see [ruby-core:14139] for more details
(format % "0777").should == (format % Kernel.Integer("0777"))
- }.should_not raise_error(ArgumentError)
+ }.should_not.raise(ArgumentError)
- -> { format % "0__7_7_7" }.should raise_error(ArgumentError)
+ -> { format % "0__7_7_7" }.should.raise(ArgumentError)
- -> { format % "" }.should raise_error(ArgumentError)
- -> { format % "x" }.should raise_error(ArgumentError)
- -> { format % "5x" }.should raise_error(ArgumentError)
- -> { format % "08" }.should raise_error(ArgumentError)
- -> { format % "0b2" }.should raise_error(ArgumentError)
- -> { format % "123__456" }.should raise_error(ArgumentError)
+ -> { format % "" }.should.raise(ArgumentError)
+ -> { format % "x" }.should.raise(ArgumentError)
+ -> { format % "5x" }.should.raise(ArgumentError)
+ -> { format % "08" }.should.raise(ArgumentError)
+ -> { format % "0b2" }.should.raise(ArgumentError)
+ -> { format % "123__456" }.should.raise(ArgumentError)
obj = mock('5')
obj.should_receive(:to_i).and_return(5)
@@ -752,14 +752,14 @@ describe "String#%" do
(format % "0777").should == (format % 777)
- -> { format % "" }.should raise_error(ArgumentError)
- -> { format % "x" }.should raise_error(ArgumentError)
- -> { format % "." }.should raise_error(ArgumentError)
- -> { format % "5x" }.should raise_error(ArgumentError)
- -> { format % "0b1" }.should raise_error(ArgumentError)
- -> { format % "10e10.5" }.should raise_error(ArgumentError)
- -> { format % "10__10" }.should raise_error(ArgumentError)
- -> { format % "10.10__10" }.should raise_error(ArgumentError)
+ -> { format % "" }.should.raise(ArgumentError)
+ -> { format % "x" }.should.raise(ArgumentError)
+ -> { format % "." }.should.raise(ArgumentError)
+ -> { format % "5x" }.should.raise(ArgumentError)
+ -> { format % "0b1" }.should.raise(ArgumentError)
+ -> { format % "10e10.5" }.should.raise(ArgumentError)
+ -> { format % "10__10" }.should.raise(ArgumentError)
+ -> { format % "10.10__10" }.should.raise(ArgumentError)
obj = mock('5.0')
obj.should_receive(:to_f).and_return(5.0)
@@ -777,7 +777,7 @@ describe "String#%" do
end
it "should raise ArgumentError if no hash given" do
- -> {"%{foo}" % []}.should raise_error(ArgumentError)
+ -> {"%{foo}" % []}.should.raise(ArgumentError)
end
end
@@ -787,11 +787,11 @@ describe "String#%" do
end
it "raises KeyError if key is missing from passed-in hash" do
- -> {"%<foo>d" % {}}.should raise_error(KeyError)
+ -> {"%<foo>d" % {}}.should.raise(KeyError)
end
it "should raise ArgumentError if no hash given" do
- -> {"%<foo>" % []}.should raise_error(ArgumentError)
+ -> {"%<foo>" % []}.should.raise(ArgumentError)
end
end
end
diff --git a/spec/ruby/core/string/new_spec.rb b/spec/ruby/core/string/new_spec.rb
index ca678f5323..aadf1e0e46 100644
--- a/spec/ruby/core/string/new_spec.rb
+++ b/spec/ruby/core/string/new_spec.rb
@@ -4,7 +4,7 @@ require_relative 'fixtures/classes'
describe "String.new" do
it "returns an instance of String" do
str = String.new
- str.should be_an_instance_of(String)
+ str.should.instance_of?(String)
end
it "accepts an encoding argument" do
@@ -28,7 +28,7 @@ describe "String.new" do
it "returns a new string given a string argument" do
str1 = "test"
str = String.new(str1)
- str.should be_an_instance_of(String)
+ str.should.instance_of?(String)
str.should == str1
str << "more"
str.should == "testmore"
@@ -36,7 +36,7 @@ describe "String.new" do
it "returns an instance of a subclass" do
a = StringSpecs::MyString.new("blah")
- a.should be_an_instance_of(StringSpecs::MyString)
+ a.should.instance_of?(StringSpecs::MyString)
a.should == "blah"
end
@@ -51,8 +51,8 @@ describe "String.new" do
end
it "raises TypeError on inconvertible object" do
- -> { String.new 5 }.should raise_error(TypeError)
- -> { String.new nil }.should raise_error(TypeError)
+ -> { String.new 5 }.should.raise(TypeError)
+ -> { String.new nil }.should.raise(TypeError)
end
it "returns a binary String" do
diff --git a/spec/ruby/core/string/next_spec.rb b/spec/ruby/core/string/next_spec.rb
index fcd3e5ef90..2ab121a909 100644
--- a/spec/ruby/core/string/next_spec.rb
+++ b/spec/ruby/core/string/next_spec.rb
@@ -1,11 +1,13 @@
require_relative '../../spec_helper'
-require_relative 'fixtures/classes'
-require_relative 'shared/succ'
describe "String#next" do
- it_behaves_like :string_succ, :next
+ it "is an alias of String#succ" do
+ String.instance_method(:next).should == String.instance_method(:succ)
+ end
end
describe "String#next!" do
- it_behaves_like :string_succ_bang, :"next!"
+ it "is an alias of String#succ!" do
+ String.instance_method(:next!).should == String.instance_method(:succ!)
+ end
end
diff --git a/spec/ruby/core/string/ord_spec.rb b/spec/ruby/core/string/ord_spec.rb
index 35af3b5458..5a17fc1d87 100644
--- a/spec/ruby/core/string/ord_spec.rb
+++ b/spec/ruby/core/string/ord_spec.rb
@@ -2,7 +2,7 @@ require_relative '../../spec_helper'
describe "String#ord" do
it "returns an Integer" do
- 'a'.ord.should be_an_instance_of(Integer)
+ 'a'.ord.should.instance_of?(Integer)
end
it "returns the codepoint of the first character in the String" do
@@ -23,11 +23,11 @@ describe "String#ord" do
end
it "raises an ArgumentError if called on an empty String" do
- -> { ''.ord }.should raise_error(ArgumentError)
+ -> { ''.ord }.should.raise(ArgumentError)
end
it "raises ArgumentError if the character is broken" do
s = "©".dup.force_encoding("US-ASCII")
- -> { s.ord }.should raise_error(ArgumentError, "invalid byte sequence in US-ASCII")
+ -> { s.ord }.should.raise(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..29fe910b39 100644
--- a/spec/ruby/core/string/partition_spec.rb
+++ b/spec/ruby/core/string/partition_spec.rb
@@ -31,8 +31,8 @@ describe "String#partition with String" do
end
it "raises an error if not convertible to string" do
- ->{ "hello".partition(5) }.should raise_error(TypeError)
- ->{ "hello".partition(nil) }.should raise_error(TypeError)
+ ->{ "hello".partition(5) }.should.raise(TypeError)
+ ->{ "hello".partition(nil) }.should.raise(TypeError)
end
it "takes precedence over a given block" do
diff --git a/spec/ruby/core/string/plus_spec.rb b/spec/ruby/core/string/plus_spec.rb
index 9da17451c6..0464141c37 100644
--- a/spec/ruby/core/string/plus_spec.rb
+++ b/spec/ruby/core/string/plus_spec.rb
@@ -21,17 +21,17 @@ describe "String#+" do
end
it "raises a TypeError when given any object that fails #to_str" do
- -> { "" + Object.new }.should raise_error(TypeError)
- -> { "" + 65 }.should raise_error(TypeError)
+ -> { "" + Object.new }.should.raise(TypeError)
+ -> { "" + 65 }.should.raise(TypeError)
end
it "doesn't return subclass instances" do
- (StringSpecs::MyString.new("hello") + "").should be_an_instance_of(String)
- (StringSpecs::MyString.new("hello") + "foo").should be_an_instance_of(String)
- (StringSpecs::MyString.new("hello") + StringSpecs::MyString.new("foo")).should be_an_instance_of(String)
- (StringSpecs::MyString.new("hello") + StringSpecs::MyString.new("")).should be_an_instance_of(String)
- (StringSpecs::MyString.new("") + StringSpecs::MyString.new("")).should be_an_instance_of(String)
- ("hello" + StringSpecs::MyString.new("foo")).should be_an_instance_of(String)
- ("hello" + StringSpecs::MyString.new("")).should be_an_instance_of(String)
+ (StringSpecs::MyString.new("hello") + "").should.instance_of?(String)
+ (StringSpecs::MyString.new("hello") + "foo").should.instance_of?(String)
+ (StringSpecs::MyString.new("hello") + StringSpecs::MyString.new("foo")).should.instance_of?(String)
+ (StringSpecs::MyString.new("hello") + StringSpecs::MyString.new("")).should.instance_of?(String)
+ (StringSpecs::MyString.new("") + StringSpecs::MyString.new("")).should.instance_of?(String)
+ ("hello" + StringSpecs::MyString.new("foo")).should.instance_of?(String)
+ ("hello" + StringSpecs::MyString.new("")).should.instance_of?(String)
end
end
diff --git a/spec/ruby/core/string/prepend_spec.rb b/spec/ruby/core/string/prepend_spec.rb
index 5248ea8056..a8da4e62cb 100644
--- a/spec/ruby/core/string/prepend_spec.rb
+++ b/spec/ruby/core/string/prepend_spec.rb
@@ -5,7 +5,7 @@ require_relative 'fixtures/classes'
describe "String#prepend" do
it "prepends the given argument to self and returns self" do
str = "world"
- str.prepend("hello ").should equal(str)
+ str.prepend("hello ").should.equal?(str)
str.should == "hello world"
end
@@ -17,16 +17,16 @@ describe "String#prepend" do
end
it "raises a TypeError if the given argument can't be converted to a String" do
- -> { "hello ".prepend [] }.should raise_error(TypeError)
- -> { 'hello '.prepend mock('x') }.should raise_error(TypeError)
+ -> { "hello ".prepend [] }.should.raise(TypeError)
+ -> { 'hello '.prepend mock('x') }.should.raise(TypeError)
end
it "raises a FrozenError when self is frozen" do
a = "hello"
a.freeze
- -> { a.prepend "" }.should raise_error(FrozenError)
- -> { a.prepend "test" }.should raise_error(FrozenError)
+ -> { a.prepend "" }.should.raise(FrozenError)
+ -> { a.prepend "test" }.should.raise(FrozenError)
end
it "works when given a subclass instance" do
@@ -49,7 +49,7 @@ describe "String#prepend" do
it "returns self when given no arguments" do
str = "hello"
- str.prepend.should equal(str)
+ str.prepend.should.equal?(str)
str.should == "hello"
end
end
diff --git a/spec/ruby/core/string/reverse_spec.rb b/spec/ruby/core/string/reverse_spec.rb
index aa6abe6036..e37c1125db 100644
--- a/spec/ruby/core/string/reverse_spec.rb
+++ b/spec/ruby/core/string/reverse_spec.rb
@@ -12,9 +12,9 @@ describe "String#reverse" do
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)
+ StringSpecs::MyString.new("stressed").reverse.should.instance_of?(String)
+ StringSpecs::MyString.new("m").reverse.should.instance_of?(String)
+ StringSpecs::MyString.new("").reverse.should.instance_of?(String)
end
it "reverses a string with multi byte characters" do
@@ -24,7 +24,7 @@ describe "String#reverse" do
it "works with a broken string" do
str = "微軟\xDF\xDE正黑體".force_encoding(Encoding::UTF_8)
- str.valid_encoding?.should be_false
+ str.valid_encoding?.should == false
str.reverse.should == "體黑正\xDE\xDF軟微"
end
@@ -37,20 +37,20 @@ end
describe "String#reverse!" do
it "reverses self in place and always returns self" do
a = "stressed"
- a.reverse!.should equal(a)
+ a.reverse!.should.equal?(a)
a.should == "desserts"
"".reverse!.should == ""
end
it "raises a FrozenError on a frozen instance that is modified" do
- -> { "anna".freeze.reverse! }.should raise_error(FrozenError)
- -> { "hello".freeze.reverse! }.should raise_error(FrozenError)
+ -> { "anna".freeze.reverse! }.should.raise(FrozenError)
+ -> { "hello".freeze.reverse! }.should.raise(FrozenError)
end
# see [ruby-core:23666]
it "raises a FrozenError on a frozen instance that would not be modified" do
- -> { "".freeze.reverse! }.should raise_error(FrozenError)
+ -> { "".freeze.reverse! }.should.raise(FrozenError)
end
it "reverses a string with multi byte characters" do
@@ -62,7 +62,7 @@ describe "String#reverse!" do
it "works with a broken string" do
str = "微軟\xDF\xDE正黑體".force_encoding(Encoding::UTF_8)
- str.valid_encoding?.should be_false
+ str.valid_encoding?.should == false
str.reverse!
str.should == "體黑正\xDE\xDF軟微"
diff --git a/spec/ruby/core/string/rindex_spec.rb b/spec/ruby/core/string/rindex_spec.rb
index 0863a9c3be..acecec224f 100644
--- a/spec/ruby/core/string/rindex_spec.rb
+++ b/spec/ruby/core/string/rindex_spec.rb
@@ -5,19 +5,19 @@ require_relative 'fixtures/classes'
describe "String#rindex with object" do
it "raises a TypeError if obj isn't a String or Regexp" do
not_supported_on :opal do
- -> { "hello".rindex(:sym) }.should raise_error(TypeError)
+ -> { "hello".rindex(:sym) }.should.raise(TypeError)
end
- -> { "hello".rindex(mock('x')) }.should raise_error(TypeError)
+ -> { "hello".rindex(mock('x')) }.should.raise(TypeError)
end
it "raises a TypeError if obj is an Integer" do
- -> { "hello".rindex(42) }.should raise_error(TypeError)
+ -> { "hello".rindex(42) }.should.raise(TypeError)
end
it "doesn't try to convert obj to an integer via to_int" do
obj = mock('x')
obj.should_not_receive(:to_int)
- -> { "hello".rindex(obj) }.should raise_error(TypeError)
+ -> { "hello".rindex(obj) }.should.raise(TypeError)
end
it "tries to convert obj to a string via to_str" do
@@ -193,7 +193,7 @@ describe "String#rindex with String" do
end
it "raises a TypeError when given offset is nil" do
- -> { "str".rindex("st", nil) }.should raise_error(TypeError)
+ -> { "str".rindex("st", nil) }.should.raise(TypeError)
end
it "handles a substring in a superset encoding" do
@@ -208,7 +208,7 @@ describe "String#rindex with String" 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")
+ -> { str.rindex(pattern) }.should.raise(Encoding::CompatibilityError, "incompatible character encodings: ISO-2022-JP and EUC-JP")
end
end
@@ -362,7 +362,7 @@ describe "String#rindex with Regexp" do
end
it "raises a TypeError when given offset is nil" do
- -> { "str".rindex(/../, nil) }.should raise_error(TypeError)
+ -> { "str".rindex(/../, nil) }.should.raise(TypeError)
end
it "returns the reverse character index of a multibyte character" do
@@ -379,6 +379,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(Encoding::CompatibilityError, "incompatible encoding regexp match (EUC-JP regexp with UTF-8 string)")
end
end
diff --git a/spec/ruby/core/string/rjust_spec.rb b/spec/ruby/core/string/rjust_spec.rb
index 4ad3e54aea..9f9c369745 100644
--- a/spec/ruby/core/string/rjust_spec.rb
+++ b/spec/ruby/core/string/rjust_spec.rb
@@ -41,10 +41,10 @@ describe "String#rjust with length, padding" do
end
it "raises a TypeError when length can't be converted to an integer" do
- -> { "hello".rjust("x") }.should raise_error(TypeError)
- -> { "hello".rjust("x", "y") }.should raise_error(TypeError)
- -> { "hello".rjust([]) }.should raise_error(TypeError)
- -> { "hello".rjust(mock('x')) }.should raise_error(TypeError)
+ -> { "hello".rjust("x") }.should.raise(TypeError)
+ -> { "hello".rjust("x", "y") }.should.raise(TypeError)
+ -> { "hello".rjust([]) }.should.raise(TypeError)
+ -> { "hello".rjust(mock('x')) }.should.raise(TypeError)
end
it "tries to convert padstr to a string using to_str" do
@@ -55,22 +55,22 @@ describe "String#rjust with length, padding" do
end
it "raises a TypeError when padstr can't be converted" do
- -> { "hello".rjust(20, []) }.should raise_error(TypeError)
- -> { "hello".rjust(20, Object.new)}.should raise_error(TypeError)
- -> { "hello".rjust(20, mock('x')) }.should raise_error(TypeError)
+ -> { "hello".rjust(20, []) }.should.raise(TypeError)
+ -> { "hello".rjust(20, Object.new)}.should.raise(TypeError)
+ -> { "hello".rjust(20, mock('x')) }.should.raise(TypeError)
end
it "raises an ArgumentError when padstr is empty" do
- -> { "hello".rjust(10, '') }.should raise_error(ArgumentError)
+ -> { "hello".rjust(10, '') }.should.raise(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)
+ StringSpecs::MyString.new("").rjust(10).should.instance_of?(String)
+ StringSpecs::MyString.new("foo").rjust(10).should.instance_of?(String)
+ StringSpecs::MyString.new("foo").rjust(10, StringSpecs::MyString.new("x")).should.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)
+ "".rjust(10, StringSpecs::MyString.new("x")).should.instance_of?(String)
+ "foo".rjust(10, StringSpecs::MyString.new("x")).should.instance_of?(String)
end
describe "with width" do
@@ -78,7 +78,7 @@ describe "String#rjust with length, padding" do
str = "abc".dup.force_encoding Encoding::IBM437
result = str.rjust 5
result.should == " abc"
- result.encoding.should equal(Encoding::IBM437)
+ result.encoding.should.equal?(Encoding::IBM437)
end
end
@@ -87,14 +87,14 @@ describe "String#rjust with length, padding" do
str = "abc".dup.force_encoding Encoding::IBM437
result = str.rjust 5, "ã‚"
result.should == "ã‚ã‚abc"
- result.encoding.should equal(Encoding::UTF_8)
+ result.encoding.should.equal?(Encoding::UTF_8)
end
it "raises an Encoding::CompatibilityError if the encodings are incompatible" do
pat = "ã‚¢".encode Encoding::EUC_JP
-> do
"ã‚れ".rjust 5, pat
- end.should raise_error(Encoding::CompatibilityError)
+ end.should.raise(Encoding::CompatibilityError)
end
end
end
diff --git a/spec/ruby/core/string/rpartition_spec.rb b/spec/ruby/core/string/rpartition_spec.rb
index cef0384c73..a7dd7430b7 100644
--- a/spec/ruby/core/string/rpartition_spec.rb
+++ b/spec/ruby/core/string/rpartition_spec.rb
@@ -43,8 +43,8 @@ describe "String#rpartition with String" do
end
it "raises an error if not convertible to string" do
- ->{ "hello".rpartition(5) }.should raise_error(TypeError)
- ->{ "hello".rpartition(nil) }.should raise_error(TypeError)
+ ->{ "hello".rpartition(5) }.should.raise(TypeError)
+ ->{ "hello".rpartition(nil) }.should.raise(TypeError)
end
it "handles a pattern in a superset encoding" do
diff --git a/spec/ruby/core/string/rstrip_spec.rb b/spec/ruby/core/string/rstrip_spec.rb
index 55773f5238..1638ea375d 100644
--- a/spec/ruby/core/string/rstrip_spec.rb
+++ b/spec/ruby/core/string/rstrip_spec.rb
@@ -30,7 +30,7 @@ end
describe "String#rstrip!" do
it "modifies self in place and returns self" do
a = " hello "
- a.rstrip!.should equal(a)
+ a.rstrip!.should.equal?(a)
a.should == " hello"
end
@@ -59,22 +59,22 @@ describe "String#rstrip!" do
end
it "raises a FrozenError on a frozen instance that is modified" do
- -> { " hello ".freeze.rstrip! }.should raise_error(FrozenError)
+ -> { " hello ".freeze.rstrip! }.should.raise(FrozenError)
end
# see [ruby-core:23666]
it "raises a FrozenError on a frozen instance that would not be modified" do
- -> { "hello".freeze.rstrip! }.should raise_error(FrozenError)
- -> { "".freeze.rstrip! }.should raise_error(FrozenError)
+ -> { "hello".freeze.rstrip! }.should.raise(FrozenError)
+ -> { "".freeze.rstrip! }.should.raise(FrozenError)
end
it "raises an Encoding::CompatibilityError if the last non-space codepoint is invalid" do
s = "abc\xDF".force_encoding(Encoding::UTF_8)
- s.valid_encoding?.should be_false
- -> { s.rstrip! }.should raise_error(Encoding::CompatibilityError)
+ s.valid_encoding?.should == false
+ -> { s.rstrip! }.should.raise(Encoding::CompatibilityError)
s = "abc\xDF ".force_encoding(Encoding::UTF_8)
- s.valid_encoding?.should be_false
- -> { s.rstrip! }.should raise_error(Encoding::CompatibilityError)
+ s.valid_encoding?.should == false
+ -> { s.rstrip! }.should.raise(Encoding::CompatibilityError)
end
end
diff --git a/spec/ruby/core/string/scan_spec.rb b/spec/ruby/core/string/scan_spec.rb
index bbe843b591..47fa7214c2 100644
--- a/spec/ruby/core/string/scan_spec.rb
+++ b/spec/ruby/core/string/scan_spec.rb
@@ -58,11 +58,11 @@ describe "String#scan" do
end
it "raises a TypeError if pattern isn't a Regexp and can't be converted to a String" do
- -> { "cruel world".scan(5) }.should raise_error(TypeError)
+ -> { "cruel world".scan(5) }.should.raise(TypeError)
not_supported_on :opal do
- -> { "cruel world".scan(:test) }.should raise_error(TypeError)
+ -> { "cruel world".scan(:test) }.should.raise(TypeError)
end
- -> { "cruel world".scan(mock('x')) }.should raise_error(TypeError)
+ -> { "cruel world".scan(mock('x')) }.should.raise(TypeError)
end
# jruby/jruby#5513
@@ -80,8 +80,8 @@ end
describe "String#scan with pattern and block" do
it "returns self" do
s = "foo"
- s.scan(/./) {}.should equal(s)
- s.scan(/roar/) {}.should equal(s)
+ s.scan(/./) {}.should.equal?(s)
+ s.scan(/roar/) {}.should.equal?(s)
end
it "passes each match to the block as one argument: an array" do
diff --git a/spec/ruby/core/string/scrub_spec.rb b/spec/ruby/core/string/scrub_spec.rb
index b9ef0f1a16..9dc55dbef7 100644
--- a/spec/ruby/core/string/scrub_spec.rb
+++ b/spec/ruby/core/string/scrub_spec.rb
@@ -38,9 +38,9 @@ describe "String#scrub with a default replacement" do
end
it "returns String instances when called on a subclass" do
- StringSpecs::MyString.new("foo").scrub.should be_an_instance_of(String)
+ StringSpecs::MyString.new("foo").scrub.should.instance_of?(String)
input = [0x81].pack('C').force_encoding('utf-8')
- StringSpecs::MyString.new(input).scrub.should be_an_instance_of(String)
+ StringSpecs::MyString.new(input).scrub.should.instance_of?(String)
end
end
@@ -75,7 +75,7 @@ describe "String#scrub with a custom replacement" do
xE4 = [0xE4].pack('C').force_encoding('utf-8')
block = -> { "foo#{x81}".scrub(xE4) }
- block.should raise_error(ArgumentError)
+ block.should.raise(ArgumentError)
end
it "returns a String in the same encoding as self" do
@@ -87,13 +87,13 @@ describe "String#scrub with a custom replacement" do
x81 = [0x81].pack('C').force_encoding('utf-8')
block = -> { "foo#{x81}".scrub(1) }
- block.should raise_error(TypeError)
+ block.should.raise(TypeError)
end
it "returns String instances when called on a subclass" do
- StringSpecs::MyString.new("foo").scrub("*").should be_an_instance_of(String)
+ StringSpecs::MyString.new("foo").scrub("*").should.instance_of?(String)
input = [0x81].pack('C').force_encoding('utf-8')
- StringSpecs::MyString.new(input).scrub("*").should be_an_instance_of(String)
+ StringSpecs::MyString.new(input).scrub("*").should.instance_of?(String)
end
end
@@ -121,9 +121,9 @@ describe "String#scrub with a block" do
end
it "returns String instances when called on a subclass" do
- StringSpecs::MyString.new("foo").scrub { |b| "*" }.should be_an_instance_of(String)
+ StringSpecs::MyString.new("foo").scrub { |b| "*" }.should.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)
+ StringSpecs::MyString.new(input).scrub { |b| "<#{b.unpack("H*")[0]}>" }.should.instance_of?(String)
end
end
@@ -146,7 +146,7 @@ describe "String#scrub!" do
input = "a"
input.freeze
input.scrub!
- input.frozen?.should be_true
+ input.frozen?.should == true
end
it "preserves the instance variables of already valid strings" do
diff --git a/spec/ruby/core/string/setbyte_spec.rb b/spec/ruby/core/string/setbyte_spec.rb
index 85403ca62c..d9fcc279c0 100644
--- a/spec/ruby/core/string/setbyte_spec.rb
+++ b/spec/ruby/core/string/setbyte_spec.rb
@@ -4,7 +4,7 @@ require_relative '../../spec_helper'
describe "String#setbyte" do
it "returns an Integer" do
- "a".setbyte(0,1).should be_kind_of(Integer)
+ "a".setbyte(0,1).should.is_a?(Integer)
end
it "modifies the receiver" do
@@ -34,9 +34,9 @@ describe "String#setbyte" do
it "can invalidate a String's encoding" do
str = "glark"
- str.valid_encoding?.should be_true
+ str.valid_encoding?.should == true
str.setbyte(2,253)
- str.valid_encoding?.should be_false
+ str.valid_encoding?.should == false
str = "ABC"
str.setbyte(0, 0x20) # ' '
@@ -58,11 +58,11 @@ describe "String#setbyte" do
end
it "raises an IndexError if the index is greater than the String bytesize" do
- -> { "?".setbyte(1, 97) }.should raise_error(IndexError)
+ -> { "?".setbyte(1, 97) }.should.raise(IndexError)
end
it "raises an IndexError if the negative index is greater magnitude than the String bytesize" do
- -> { "???".setbyte(-5, 97) }.should raise_error(IndexError)
+ -> { "???".setbyte(-5, 97) }.should.raise(IndexError)
end
it "sets a byte at an index greater than String size" do
@@ -84,12 +84,12 @@ describe "String#setbyte" do
it "raises a FrozenError if self is frozen" do
str = "cold".freeze
- str.frozen?.should be_true
- -> { str.setbyte(3,96) }.should raise_error(FrozenError)
+ str.frozen?.should == true
+ -> { str.setbyte(3,96) }.should.raise(FrozenError)
end
it "raises a TypeError unless the second argument is an Integer" do
- -> { "a".setbyte(0,'a') }.should raise_error(TypeError)
+ -> { "a".setbyte(0,'a') }.should.raise(TypeError)
end
it "calls #to_int to convert the index" do
diff --git a/spec/ruby/core/string/shared/byte_index_common.rb b/spec/ruby/core/string/shared/byte_index_common.rb
index 3de1453f4f..bae6cff49f 100644
--- a/spec/ruby/core/string/shared/byte_index_common.rb
+++ b/spec/ruby/core/string/shared/byte_index_common.rb
@@ -4,43 +4,43 @@ 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")
+ -> { "abc".send(@method, nil) }.should.raise(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")
+ -> { "abc".send(@method, true) }.should.raise(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")
+ -> { "abc".send(@method, :a) }.should.raise(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")
+ -> { "hello".send(@method, obj) }.should.raise(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")
+ -> { "abc".send(@method, 97) }.should.raise(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")
+ -> { "ã‚".send(@method, "", 1) }.should.raise(IndexError, "offset 1 does not land on character boundary")
+ -> { "ã‚".send(@method, "", 2) }.should.raise(IndexError, "offset 2 does not land on character boundary")
+ -> { "ã‚".send(@method, "", -1) }.should.raise(IndexError, "offset 2 does not land on character boundary")
+ -> { "ã‚".send(@method, "", -2) }.should.raise(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.should.raise(Encoding::CompatibilityError, "incompatible encoding regexp match (EUC-JP regexp with UTF-8 string)")
end
end
diff --git a/spec/ruby/core/string/shared/chars.rb b/spec/ruby/core/string/shared/chars.rb
index c730643cf4..826d403589 100644
--- a/spec/ruby/core/string/shared/chars.rb
+++ b/spec/ruby/core/string/shared/chars.rb
@@ -11,10 +11,9 @@ describe :string_chars, shared: true do
it "returns self" do
s = StringSpecs::MyString.new "hello"
- s.send(@method){}.should equal(s)
+ s.send(@method){}.should.equal?(s)
end
-
it "is unicode aware" do
"\303\207\342\210\202\303\251\306\222g".send(@method).to_a.should ==
["\303\207", "\342\210\202", "\303\251", "\306\222", "g"]
@@ -34,7 +33,7 @@ describe :string_chars, shared: true do
it "works if the String's contents is invalid for its encoding" do
xA4 = [0xA4].pack('C')
xA4.force_encoding('UTF-8')
- xA4.valid_encoding?.should be_false
+ xA4.valid_encoding?.should == false
xA4.send(@method).to_a.should == [xA4.force_encoding("UTF-8")]
end
@@ -63,4 +62,25 @@ describe :string_chars, shared: true do
[0xA2].pack('C').force_encoding('SJIS')
]
end
+
+ it "returns individual chars for dummy encodings" do
+ "ab".dup.force_encoding(Encoding::UTF_7).send(@method).to_a.should == [
+ "\x61".dup.force_encoding(Encoding::UTF_7),
+ "\x62".dup.force_encoding(Encoding::UTF_7)
+ ]
+
+ "abcd".dup.force_encoding(Encoding::UTF_16).send(@method).to_a.should == [
+ "\x61".dup.force_encoding(Encoding::UTF_16),
+ "\x62".dup.force_encoding(Encoding::UTF_16),
+ "\x63".dup.force_encoding(Encoding::UTF_16),
+ "\x64".dup.force_encoding(Encoding::UTF_16)
+ ]
+
+ "abcd".dup.force_encoding(Encoding::UTF_32).send(@method).to_a.should == [
+ "\x61".dup.force_encoding(Encoding::UTF_32),
+ "\x62".dup.force_encoding(Encoding::UTF_32),
+ "\x63".dup.force_encoding(Encoding::UTF_32),
+ "\x64".dup.force_encoding(Encoding::UTF_32)
+ ]
+ end
end
diff --git a/spec/ruby/core/string/shared/codepoints.rb b/spec/ruby/core/string/shared/codepoints.rb
index 1c28ba3d5e..b6abf6a3ff 100644
--- a/spec/ruby/core/string/shared/codepoints.rb
+++ b/spec/ruby/core/string/shared/codepoints.rb
@@ -3,13 +3,13 @@ describe :string_codepoints, shared: true do
it "returns self" do
s = "foo"
result = s.send(@method) {}
- result.should equal s
+ result.should.equal? s
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.valid_encoding?.should be_false
- -> { s.send(@method).to_a }.should raise_error(ArgumentError)
+ s.valid_encoding?.should == false
+ -> { s.send(@method).to_a }.should.raise(ArgumentError)
end
it "yields each codepoint to the block if one is given" do
@@ -22,13 +22,13 @@ describe :string_codepoints, shared: true do
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.valid_encoding?.should be_false
- -> { s.send(@method) { } }.should raise_error(ArgumentError)
+ s.valid_encoding?.should == false
+ -> { s.send(@method) { } }.should.raise(ArgumentError)
end
it "yields codepoints as Integers" do
"glark\u{20}".send(@method).to_a.each do |codepoint|
- codepoint.should be_an_instance_of(Integer)
+ codepoint.should.instance_of?(Integer)
end
end
@@ -56,7 +56,12 @@ describe :string_codepoints, shared: true do
it "is synonymous with #bytes for Strings which are single-byte optimizable" do
s = "(){}".encode('ascii')
- s.ascii_only?.should be_true
+ s.ascii_only?.should == true
s.send(@method).to_a.should == s.bytes.to_a
end
+
+ it "returns individual bytes for dummy encodings UTF-16 and UTF-32" do
+ "abcd".dup.force_encoding(Encoding::UTF_16).send(@method).to_a.should == [97, 98, 99, 100]
+ "abcd".dup.force_encoding(Encoding::UTF_32).send(@method).to_a.should == [97, 98, 99, 100]
+ end
end
diff --git a/spec/ruby/core/string/shared/concat.rb b/spec/ruby/core/string/shared/concat.rb
index dded9a69e7..60cd0e12d4 100644
--- a/spec/ruby/core/string/shared/concat.rb
+++ b/spec/ruby/core/string/shared/concat.rb
@@ -2,7 +2,7 @@
describe :string_concat, shared: true do
it "concatenates the given argument to self and returns self" do
str = 'hello '
- str.send(@method, 'world').should equal(str)
+ str.send(@method, 'world').should.equal?(str)
str.should == "hello world"
end
@@ -10,22 +10,22 @@ describe :string_concat, shared: true do
a = "hello"
a.freeze
- -> { a.send(@method, "") }.should raise_error(FrozenError)
- -> { a.send(@method, "test") }.should raise_error(FrozenError)
+ -> { a.send(@method, "") }.should.raise(FrozenError)
+ -> { a.send(@method, "test") }.should.raise(FrozenError)
end
it "returns a String when given a subclass instance" do
a = "hello"
a.send(@method, StringSpecs::MyString.new(" world"))
a.should == "hello world"
- a.should be_an_instance_of(String)
+ a.should.instance_of?(String)
end
it "returns an instance of same class when called on a subclass" do
str = StringSpecs::MyString.new("hello")
str.send(@method, " world")
str.should == "hello world"
- str.should be_an_instance_of(StringSpecs::MyString)
+ str.should.instance_of?(StringSpecs::MyString)
end
describe "with Integer" do
@@ -50,28 +50,28 @@ describe :string_concat, shared: true do
end
it "raises RangeError if the argument is an invalid codepoint for self's encoding" do
- -> { "".encode(Encoding::US_ASCII).send(@method, 256) }.should raise_error(RangeError)
- -> { "".encode(Encoding::EUC_JP).send(@method, 0x81) }.should raise_error(RangeError)
+ -> { "".encode(Encoding::US_ASCII).send(@method, 256) }.should.raise(RangeError)
+ -> { "".encode(Encoding::EUC_JP).send(@method, 0x81) }.should.raise(RangeError)
end
it "raises RangeError if the argument is negative" do
- -> { "".send(@method, -200) }.should raise_error(RangeError)
- -> { "".send(@method, -bignum_value) }.should raise_error(RangeError)
+ -> { "".send(@method, -200) }.should.raise(RangeError)
+ -> { "".send(@method, -bignum_value) }.should.raise(RangeError)
end
it "doesn't call to_int on its argument" do
x = mock('x')
x.should_not_receive(:to_int)
- -> { "".send(@method, x) }.should raise_error(TypeError)
+ -> { "".send(@method, x) }.should.raise(TypeError)
end
it "raises a FrozenError when self is frozen" do
a = "hello"
a.freeze
- -> { a.send(@method, 0) }.should raise_error(FrozenError)
- -> { a.send(@method, 33) }.should raise_error(FrozenError)
+ -> { a.send(@method, 0) }.should.raise(FrozenError)
+ -> { a.send(@method, 33) }.should.raise(FrozenError)
end
end
end
@@ -91,7 +91,7 @@ describe :string_concat_encoding, shared: true do
end
it "raises Encoding::CompatibilityError if neither are empty" do
- -> { "x".encode("UTF-16LE").send(@method, "y".encode("UTF-8")) }.should raise_error(Encoding::CompatibilityError)
+ -> { "x".encode("UTF-16LE").send(@method, "y".encode("UTF-8")) }.should.raise(Encoding::CompatibilityError)
end
end
@@ -109,7 +109,7 @@ describe :string_concat_encoding, shared: true do
end
it "raises Encoding::CompatibilityError if neither are empty" do
- -> { "x".encode("UTF-8").send(@method, "y".encode("UTF-16LE")) }.should raise_error(Encoding::CompatibilityError)
+ -> { "x".encode("UTF-8").send(@method, "y".encode("UTF-16LE")) }.should.raise(Encoding::CompatibilityError)
end
end
@@ -127,7 +127,7 @@ describe :string_concat_encoding, shared: true do
end
it "raises Encoding::CompatibilityError if neither are ASCII-only" do
- -> { "\u00E9".encode("UTF-8").send(@method, "\u00E9".encode("ISO-8859-1")) }.should raise_error(Encoding::CompatibilityError)
+ -> { "\u00E9".encode("UTF-8").send(@method, "\u00E9".encode("ISO-8859-1")) }.should.raise(Encoding::CompatibilityError)
end
end
@@ -147,13 +147,13 @@ describe :string_concat_type_coercion, shared: true do
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)
+ -> { 'hello '.send(@method, []) }.should.raise(TypeError)
+ -> { 'hello '.send(@method, mock('x')) }.should.raise(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)
+ -> { 'hello '.send(@method, obj) }.should.raise(NoMethodError)
end
end
diff --git a/spec/ruby/core/string/shared/dedup.rb b/spec/ruby/core/string/shared/dedup.rb
deleted file mode 100644
index 1ffd6aa0fd..0000000000
--- a/spec/ruby/core/string/shared/dedup.rb
+++ /dev/null
@@ -1,51 +0,0 @@
-# frozen_string_literal: false
-describe :string_dedup, shared: true do
- it 'returns self if the String is frozen' do
- input = 'foo'.freeze
- output = input.send(@method)
-
- output.should equal(input)
- output.should.frozen?
- end
-
- it 'returns a frozen copy if the String is not frozen' do
- input = 'foo'
- output = input.send(@method)
-
- output.should.frozen?
- output.should_not equal(input)
- output.should == 'foo'
- end
-
- it "returns the same object for equal unfrozen strings" do
- origin = "this is a string"
- dynamic = %w(this is a string).join(' ')
-
- origin.should_not equal(dynamic)
- origin.send(@method).should equal(dynamic.send(@method))
- end
-
- it "returns the same object when it's called on the same String literal" do
- "unfrozen string".send(@method).should equal("unfrozen string".send(@method))
- "unfrozen string".send(@method).should_not equal("another unfrozen string".send(@method))
- end
-
- it "deduplicates frozen strings" do
- dynamic = %w(this string is frozen).join(' ').freeze
-
- dynamic.should_not equal("this string is frozen".freeze)
-
- dynamic.send(@method).should equal("this string is frozen".freeze)
- dynamic.send(@method).should equal("this string is frozen".send(@method).freeze)
- end
-
- it "does not deduplicate a frozen string when it has instance variables" do
- dynamic = %w(this string is frozen).join(' ')
- dynamic.instance_variable_set(:@a, 1)
- dynamic.freeze
-
- dynamic.send(@method).should_not equal("this string is frozen".freeze)
- dynamic.send(@method).should_not equal("this string is frozen".send(@method).freeze)
- dynamic.send(@method).should equal(dynamic)
- end
-end
diff --git a/spec/ruby/core/string/shared/each_char_without_block.rb b/spec/ruby/core/string/shared/each_char_without_block.rb
index 397100ce0e..3c32bae42b 100644
--- a/spec/ruby/core/string/shared/each_char_without_block.rb
+++ b/spec/ruby/core/string/shared/each_char_without_block.rb
@@ -6,7 +6,7 @@ describe :string_each_char_without_block, shared: true do
describe "when no block is given" do
it "returns an enumerator" do
enum = "hello".send(@method)
- enum.should be_an_instance_of(Enumerator)
+ enum.should.instance_of?(Enumerator)
enum.to_a.should == ['h', 'e', 'l', 'l', 'o']
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
deleted file mode 100644
index c88e5c54c7..0000000000
--- a/spec/ruby/core/string/shared/each_codepoint_without_block.rb
+++ /dev/null
@@ -1,33 +0,0 @@
-# encoding: binary
-describe :string_each_codepoint_without_block, shared: true do
- describe "when no block is given" do
- it "returns an Enumerator" do
- "".send(@method).should be_an_instance_of(Enumerator)
- end
-
- it "returns an Enumerator even when self has an invalid encoding" do
- s = "\xDF".dup.force_encoding(Encoding::UTF_8)
- s.valid_encoding?.should be_false
- s.send(@method).should be_an_instance_of(Enumerator)
- end
-
- describe "returned Enumerator" do
- describe "size" do
- it "should return the size of the string" do
- str = "hello"
- str.send(@method).size.should == str.size
- str = "ola"
- str.send(@method).size.should == str.size
- str = "\303\207\342\210\202\303\251\306\222g"
- str.send(@method).size.should == str.size
- 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.valid_encoding?.should be_false
- s.send(@method).size.should == 1
- end
- end
- end
- end
-end
diff --git a/spec/ruby/core/string/shared/each_line.rb b/spec/ruby/core/string/shared/each_line.rb
index 231a6d9d4f..127db876ad 100644
--- a/spec/ruby/core/string/shared/each_line.rb
+++ b/spec/ruby/core/string/shared/each_line.rb
@@ -46,14 +46,36 @@ describe :string_each_line, shared: true do
a.should == ["one\ntwo\r\nthree"]
end
- it "yields paragraphs (broken by 2 or more successive newlines) when passed '' and replaces multiple newlines with only two ones" do
- a = []
- "hello\nworld\n\n\nand\nuniverse\n\n\n\n\n".send(@method, '') { |s| a << s }
- a.should == ["hello\nworld\n\n", "and\nuniverse\n\n"]
+ context "when passed '' (paragraph mode, broken by 2 or more successive newlines)" do
+ it "replaces multiple newlines with only two ones" do
+ a = []
+ "hello\nworld\n\n\nand\nuniverse\n\n\n\n\n".send(@method, '') { |s| a << s }
+ a.should == ["hello\nworld\n\n", "and\nuniverse\n\n"]
- a = []
- "hello\nworld\n\n\nand\nuniverse\n\n\n\n\ndog".send(@method, '') { |s| a << s }
- a.should == ["hello\nworld\n\n", "and\nuniverse\n\n", "dog"]
+ a = []
+ "hello\nworld\n\n\nand\nuniverse\n\n\n\n\ndog".send(@method, '') { |s| a << s }
+ a.should == ["hello\nworld\n\n", "and\nuniverse\n\n", "dog"]
+ end
+
+ it 'handles \r\n-style newlines' do
+ a = []
+ "hello\nworld\r\n\r\n\nand\nuniverse\n\r\n\n\n\n".send(@method, '') { |s| a << s }
+ a.should == ["hello\nworld\r\n\r\n", "and\nuniverse\n\r\n"]
+
+ a = []
+ "hello\r\nworld\n\n\nand\nuniverse\n\n\n\r\n\r\ndog".send(@method, '') { |s| a << s }
+ a.should == ["hello\r\nworld\n\n", "and\nuniverse\n\n", "dog"]
+ end
+
+ it "removes trailing newlines with `chomp: true`" do
+ a = []
+ "hello\nworld\n\n\nand\nuniverse\n\n\n\n\n".send(@method, '', chomp: true) { |s| a << s }
+ a.should == ["hello\nworld", "and\nuniverse"]
+
+ a = []
+ "hello\nworld\n\n\nand\nuniverse\n\n\n\n\ndog".send(@method, '', chomp: true) { |s| a << s }
+ a.should == ["hello\nworld", "and\nuniverse", "dog"]
+ end
end
describe "uses $/" do
@@ -93,7 +115,7 @@ describe :string_each_line, shared: true do
it "returns self" do
s = "hello\nworld"
- (s.send(@method) {}).should equal(s)
+ (s.send(@method) {}).should.equal?(s)
end
it "tries to convert the separator to a string using to_str" do
@@ -119,8 +141,8 @@ describe :string_each_line, shared: true do
end
it "raises a TypeError when the separator can't be converted to a string" do
- -> { "hello world".send(@method, false) {} }.should raise_error(TypeError)
- -> { "hello world".send(@method, mock('x')) {} }.should raise_error(TypeError)
+ -> { "hello world".send(@method, false) {} }.should.raise(TypeError)
+ -> { "hello world".send(@method, mock('x')) {} }.should.raise(TypeError)
end
it "accepts a string separator" do
@@ -128,7 +150,7 @@ describe :string_each_line, shared: true do
end
it "raises a TypeError when the separator is a symbol" do
- -> { "hello world".send(@method, :o).to_a }.should raise_error(TypeError)
+ -> { "hello world".send(@method, :o).to_a }.should.raise(TypeError)
end
context "when `chomp` keyword argument is passed" do
@@ -159,4 +181,18 @@ describe :string_each_line, shared: true do
a.should == ["hello\r\n", "world\r\n"]
end
end
+
+ it "does not split lines for dummy UTF-16" do
+ "a\nb".encode(Encoding::UTF_16).lines.should == [
+ "\xFE\xFF\x00\x61\x00\n\x00\x62".dup.force_encoding(Encoding::UTF_16)
+ ]
+
+ str = "\x00\n\n\x00".dup.force_encoding(Encoding::UTF_16)
+ str.lines.should == [str]
+ end
+
+ it "raises Encoding::ConverterNotFoundError for dummy UTF-7" do
+ str = "a\nb".dup.force_encoding(Encoding::UTF_7)
+ -> { str.lines }.should.raise(Encoding::ConverterNotFoundError)
+ end
end
diff --git a/spec/ruby/core/string/shared/each_line_without_block.rb b/spec/ruby/core/string/shared/each_line_without_block.rb
index 8e08b0390c..af0ab69c00 100644
--- a/spec/ruby/core/string/shared/each_line_without_block.rb
+++ b/spec/ruby/core/string/shared/each_line_without_block.rb
@@ -2,7 +2,7 @@ describe :string_each_line_without_block, shared: true do
describe "when no block is given" do
it "returns an enumerator" do
enum = "hello world".send(@method, ' ')
- enum.should be_an_instance_of(Enumerator)
+ enum.should.instance_of?(Enumerator)
enum.to_a.should == ["hello ", "world"]
end
diff --git a/spec/ruby/core/string/shared/encode.rb b/spec/ruby/core/string/shared/encode.rb
index 9466308886..7f644c26d9 100644
--- a/spec/ruby/core/string/shared/encode.rb
+++ b/spec/ruby/core/string/shared/encode.rb
@@ -11,7 +11,7 @@ describe :string_encode, shared: true do
it "transcodes a 7-bit String despite no generic converting being available" do
-> do
Encoding::Converter.new Encoding::Emacs_Mule, Encoding::BINARY
- end.should raise_error(Encoding::ConverterNotFoundError)
+ end.should.raise(Encoding::ConverterNotFoundError)
Encoding.default_internal = Encoding::Emacs_Mule
str = "\x79".force_encoding Encoding::BINARY
@@ -22,7 +22,7 @@ describe :string_encode, shared: true do
it "raises an Encoding::ConverterNotFoundError when no conversion is possible" do
Encoding.default_internal = Encoding::Emacs_Mule
str = [0x80].pack('C').force_encoding Encoding::BINARY
- -> { str.send(@method) }.should raise_error(Encoding::ConverterNotFoundError)
+ -> { str.send(@method) }.should.raise(Encoding::ConverterNotFoundError)
end
end
@@ -54,7 +54,7 @@ describe :string_encode, shared: true do
it "transcodes a 7-bit String despite no generic converting being available" do
-> do
Encoding::Converter.new Encoding::Emacs_Mule, Encoding::BINARY
- end.should raise_error(Encoding::ConverterNotFoundError)
+ end.should.raise(Encoding::ConverterNotFoundError)
str = "\x79".force_encoding Encoding::BINARY
str.send(@method, Encoding::Emacs_Mule).should == "y".force_encoding(Encoding::BINARY)
@@ -64,13 +64,21 @@ describe :string_encode, shared: true do
str = [0x80].pack('C').force_encoding Encoding::BINARY
-> do
str.send(@method, Encoding::Emacs_Mule)
- end.should raise_error(Encoding::ConverterNotFoundError)
+ end.should.raise(Encoding::ConverterNotFoundError)
end
it "raises an Encoding::ConverterNotFoundError for an invalid encoding" do
-> do
"abc".send(@method, "xyz")
- end.should raise_error(Encoding::ConverterNotFoundError)
+ end.should.raise(Encoding::ConverterNotFoundError)
+ end
+
+ it "raises an Encoding::UndefinedConversionError when a character cannot be represented in the destination encoding" do
+ # U+0100 (Ä€) is valid UTF-8 but not representable in windows-1252
+ str = "test\u0100".force_encoding('utf-8')
+ -> {
+ str.send(@method, Encoding::Windows_1252)
+ }.should.raise(Encoding::UndefinedConversionError)
end
end
@@ -99,7 +107,7 @@ describe :string_encode, shared: true do
str = [0x80].pack('C').force_encoding Encoding::BINARY
-> do
str.send(@method, invalid: :replace, undef: :replace)
- end.should raise_error(Encoding::ConverterNotFoundError)
+ end.should.raise(Encoding::ConverterNotFoundError)
end
it "replaces invalid characters when replacing Emacs-Mule encoded strings" do
@@ -142,6 +150,14 @@ describe :string_encode, shared: true do
"ab#{xFF}c".send(@method, Encoding::ISO_8859_1, invalid: :replace).should == "ab?c"
end
+ it "raises UndefinedConversionError for characters not representable in destination encoding with only invalid: :replace" do
+ # U+0100 (Ä€) is valid UTF-8 but not representable in windows-1252
+ str = "test\u0100".force_encoding('utf-8')
+ -> {
+ str.send(@method, Encoding::Windows_1252, invalid: :replace, replace: "")
+ }.should.raise(Encoding::UndefinedConversionError)
+ end
+
it "calls #to_hash to convert the options object" do
options = mock("string encode options")
options.should_receive(:to_hash).and_return({ undef: :replace })
@@ -213,19 +229,19 @@ describe :string_encode, shared: true do
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")
+ }.should.raise(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")
+ }.should.raise(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")
+ }.should.raise(ArgumentError, "too big fallback string")
end
it "uses the hash's default value if set" do
@@ -278,7 +294,7 @@ describe :string_encode, shared: true do
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")
+ }.should.raise(Encoding::UndefinedConversionError, "U+FFFD from UTF-8 to US-ASCII")
end
end
@@ -300,13 +316,13 @@ describe :string_encode, shared: true do
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")
+ }.should.raise(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")
+ }.should.raise(ArgumentError, "too big fallback string")
end
end
@@ -328,13 +344,13 @@ describe :string_encode, shared: true do
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")
+ }.should.raise(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")
+ }.should.raise(ArgumentError, "too big fallback string")
end
end
@@ -367,13 +383,13 @@ describe :string_encode, shared: true do
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")
+ }.should.raise(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")
+ }.should.raise(ArgumentError, "too big fallback string")
end
end
end
@@ -427,6 +443,6 @@ describe :string_encode, shared: true do
end
it "raises ArgumentError if the value of the :xml option is not :text or :attr" do
- -> { ''.send(@method, "UTF-8", xml: :other) }.should raise_error(ArgumentError)
+ -> { ''.send(@method, "UTF-8", xml: :other) }.should.raise(ArgumentError)
end
end
diff --git a/spec/ruby/core/string/shared/eql.rb b/spec/ruby/core/string/shared/eql.rb
index d5af337d53..0e356c69e8 100644
--- a/spec/ruby/core/string/shared/eql.rb
+++ b/spec/ruby/core/string/shared/eql.rb
@@ -4,32 +4,32 @@ require_relative '../fixtures/classes'
describe :string_eql_value, shared: true do
it "returns true if self <=> string returns 0" do
- 'hello'.send(@method, 'hello').should be_true
+ 'hello'.send(@method, 'hello').should == true
end
it "returns false if self <=> string does not return 0" do
- "more".send(@method, "MORE").should be_false
- "less".send(@method, "greater").should be_false
+ "more".send(@method, "MORE").should == false
+ "less".send(@method, "greater").should == false
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".dup.force_encoding("utf-8").send(@method, "hello".dup.force_encoding("iso-8859-1")).should == 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".dup.force_encoding("utf-8").send(@method, "\xff".dup.force_encoding("iso-8859-1")).should == 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".dup.force_encoding("utf-8").send(@method, "abcd".dup.force_encoding("utf-32le")).should == false
end
it "ignores subclass differences" do
a = "hello"
b = StringSpecs::MyString.new("hello")
- a.send(@method, b).should be_true
- b.send(@method, a).should be_true
+ a.send(@method, b).should == true
+ b.send(@method, a).should == true
end
it "returns true when comparing 2 empty strings but one is not ASCII-compatible" do
diff --git a/spec/ruby/core/string/shared/equal_value.rb b/spec/ruby/core/string/shared/equal_value.rb
deleted file mode 100644
index fccafb5821..0000000000
--- a/spec/ruby/core/string/shared/equal_value.rb
+++ /dev/null
@@ -1,29 +0,0 @@
-require_relative '../../../spec_helper'
-require_relative '../fixtures/classes'
-
-describe :string_equal_value, shared: true do
- it "returns false if obj does not respond to to_str" do
- 'hello'.send(@method, 5).should be_false
- not_supported_on :opal do
- 'hello'.send(@method, :hello).should be_false
- end
- 'hello'.send(@method, mock('x')).should be_false
- end
-
- it "returns obj == self if obj responds to to_str" do
- obj = Object.new
-
- # String#== merely checks if #to_str is defined. It does
- # not call it.
- obj.stub!(:to_str)
-
- # Don't use @method for :== in `obj.should_receive(:==)`
- obj.should_receive(:==).and_return(true)
-
- 'hello'.send(@method, obj).should be_true
- end
-
- it "is not fooled by NUL characters" do
- "abc\0def".send(@method, "abc\0xyz").should be_false
- end
-end
diff --git a/spec/ruby/core/string/shared/grapheme_clusters.rb b/spec/ruby/core/string/shared/grapheme_clusters.rb
index 8b666868b1..dd8c7ed5fe 100644
--- a/spec/ruby/core/string/shared/grapheme_clusters.rb
+++ b/spec/ruby/core/string/shared/grapheme_clusters.rb
@@ -9,8 +9,17 @@ describe :string_grapheme_clusters, shared: true do
a.should == ['a', 'b', "\u{1f3f3}\u{fe0f}\u{200d}\u{1f308}", "\u{1F43E}"]
end
+ it "returns grapheme clusters for various UTF encodings" do
+ [Encoding::UTF_16LE, Encoding::UTF_16BE, Encoding::UTF_32LE, Encoding::UTF_32BE].each do |enc|
+ a = []
+ # test string: abc[rainbow flag emoji][paw prints]
+ "ab\u{1f3f3}\u{fe0f}\u{200d}\u{1f308}\u{1F43E}".encode(enc).send(@method) { |c| a << c }
+ a.should == ['a', 'b', "\u{1f3f3}\u{fe0f}\u{200d}\u{1f308}", "\u{1F43E}"].map { |s| s.encode(enc) }
+ end
+ end
+
it "returns self" do
s = StringSpecs::MyString.new "ab\u{1f3f3}\u{fe0f}\u{200d}\u{1f308}\u{1F43E}"
- s.send(@method) {}.should equal(s)
+ s.send(@method) {}.should.equal?(s)
end
end
diff --git a/spec/ruby/core/string/shared/length.rb b/spec/ruby/core/string/shared/length.rb
deleted file mode 100644
index ae572ba755..0000000000
--- a/spec/ruby/core/string/shared/length.rb
+++ /dev/null
@@ -1,55 +0,0 @@
-# encoding: utf-8
-
-describe :string_length, shared: true do
- it "returns the length of self" do
- "".send(@method).should == 0
- "\x00".send(@method).should == 1
- "one".send(@method).should == 3
- "two".send(@method).should == 3
- "three".send(@method).should == 5
- "four".send(@method).should == 4
- end
-
- it "returns the length of a string in different encodings" do
- utf8_str = 'ã“ã«ã¡ã‚' * 100
- utf8_str.send(@method).should == 400
- utf8_str.encode(Encoding::UTF_32BE).send(@method).should == 400
- utf8_str.encode(Encoding::SHIFT_JIS).send(@method).should == 400
- end
-
- it "returns the length of the new self after encoding is changed" do
- str = +'ã“ã«ã¡ã‚'
- str.send(@method)
-
- str.force_encoding('BINARY').send(@method).should == 12
- end
-
- it "returns the correct length after force_encoding(BINARY)" do
- utf8 = "ã‚"
- ascii = "a"
- concat = utf8 + ascii
-
- concat.encoding.should == Encoding::UTF_8
- concat.bytesize.should == 4
-
- concat.send(@method).should == 2
- concat.force_encoding(Encoding::ASCII_8BIT)
- concat.send(@method).should == 4
- end
-
- it "adds 1 for every invalid byte in UTF-8" do
- "\xF4\x90\x80\x80".send(@method).should == 4
- "a\xF4\x90\x80\x80b".send(@method).should == 6
- "é\xF4\x90\x80\x80è".send(@method).should == 6
- 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
- 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
- end
-end
diff --git a/spec/ruby/core/string/shared/partition.rb b/spec/ruby/core/string/shared/partition.rb
index 4cac149ce5..3f7e606eb3 100644
--- a/spec/ruby/core/string/shared/partition.rb
+++ b/spec/ruby/core/string/shared/partition.rb
@@ -4,15 +4,15 @@ 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)
+ item.should.instance_of?(String)
end
StringSpecs::MyString.new("hello").send(@method, "x").each do |item|
- item.should be_an_instance_of(String)
+ item.should.instance_of?(String)
end
StringSpecs::MyString.new("hello").send(@method, /l./).each do |item|
- item.should be_an_instance_of(String)
+ item.should.instance_of?(String)
end
end
diff --git a/spec/ruby/core/string/shared/replace.rb b/spec/ruby/core/string/shared/replace.rb
index 24dac0eb27..73b26351f1 100644
--- a/spec/ruby/core/string/shared/replace.rb
+++ b/spec/ruby/core/string/shared/replace.rb
@@ -2,7 +2,7 @@
describe :string_replace, shared: true do
it "returns self" do
a = "a"
- a.send(@method, "b").should equal(a)
+ a.send(@method, "b").should.equal?(a)
end
it "replaces the content of self with other" do
@@ -20,7 +20,7 @@ describe :string_replace, shared: true do
it "carries over the encoding invalidity" do
a = "\u{8765}".force_encoding('ascii')
- "".send(@method, a).valid_encoding?.should be_false
+ "".send(@method, a).valid_encoding?.should == false
end
it "tries to convert other to string using to_str" do
@@ -30,19 +30,19 @@ describe :string_replace, shared: true do
end
it "raises a TypeError if other can't be converted to string" do
- -> { "hello".send(@method, 123) }.should raise_error(TypeError)
- -> { "hello".send(@method, []) }.should raise_error(TypeError)
- -> { "hello".send(@method, mock('x')) }.should raise_error(TypeError)
+ -> { "hello".send(@method, 123) }.should.raise(TypeError)
+ -> { "hello".send(@method, []) }.should.raise(TypeError)
+ -> { "hello".send(@method, mock('x')) }.should.raise(TypeError)
end
it "raises a FrozenError on a frozen instance that is modified" do
a = "hello".freeze
- -> { a.send(@method, "world") }.should raise_error(FrozenError)
+ -> { a.send(@method, "world") }.should.raise(FrozenError)
end
# see [ruby-core:23666]
it "raises a FrozenError on a frozen instance when self-replacing" do
a = "hello".freeze
- -> { a.send(@method, a) }.should raise_error(FrozenError)
+ -> { a.send(@method, a) }.should.raise(FrozenError)
end
end
diff --git a/spec/ruby/core/string/shared/slice.rb b/spec/ruby/core/string/shared/slice.rb
index 7b9b9f6a14..d296ab6680 100644
--- a/spec/ruby/core/string/shared/slice.rb
+++ b/spec/ruby/core/string/shared/slice.rb
@@ -21,17 +21,17 @@ describe :string_slice, shared: true do
end
it "raises a TypeError if the given index is nil" do
- -> { "hello".send(@method, nil) }.should raise_error(TypeError)
+ -> { "hello".send(@method, nil) }.should.raise(TypeError)
end
it "raises a TypeError if the given index can't be converted to an Integer" do
- -> { "hello".send(@method, mock('x')) }.should raise_error(TypeError)
- -> { "hello".send(@method, {}) }.should raise_error(TypeError)
- -> { "hello".send(@method, []) }.should raise_error(TypeError)
+ -> { "hello".send(@method, mock('x')) }.should.raise(TypeError)
+ -> { "hello".send(@method, {}) }.should.raise(TypeError)
+ -> { "hello".send(@method, []) }.should.raise(TypeError)
end
it "raises a RangeError if the index is too big" do
- -> { "hello".send(@method, bignum_value) }.should raise_error(RangeError)
+ -> { "hello".send(@method, bignum_value) }.should.raise(RangeError)
end
end
@@ -145,35 +145,35 @@ describe :string_slice_index_length, shared: true do
end
it "raises a TypeError when idx or length can't be converted to an integer" do
- -> { "hello".send(@method, mock('x'), 0) }.should raise_error(TypeError)
- -> { "hello".send(@method, 0, mock('x')) }.should raise_error(TypeError)
+ -> { "hello".send(@method, mock('x'), 0) }.should.raise(TypeError)
+ -> { "hello".send(@method, 0, mock('x')) }.should.raise(TypeError)
# I'm deliberately including this here.
# It means that str.send(@method, other, idx) isn't supported.
- -> { "hello".send(@method, "", 0) }.should raise_error(TypeError)
+ -> { "hello".send(@method, "", 0) }.should.raise(TypeError)
end
it "raises a TypeError when the given index or the given length is nil" do
- -> { "hello".send(@method, 1, nil) }.should raise_error(TypeError)
- -> { "hello".send(@method, nil, 1) }.should raise_error(TypeError)
- -> { "hello".send(@method, nil, nil) }.should raise_error(TypeError)
+ -> { "hello".send(@method, 1, nil) }.should.raise(TypeError)
+ -> { "hello".send(@method, nil, 1) }.should.raise(TypeError)
+ -> { "hello".send(@method, nil, nil) }.should.raise(TypeError)
end
it "raises a RangeError if the index or length is too big" do
- -> { "hello".send(@method, bignum_value, 1) }.should raise_error(RangeError)
- -> { "hello".send(@method, 0, bignum_value) }.should raise_error(RangeError)
+ -> { "hello".send(@method, bignum_value, 1) }.should.raise(RangeError)
+ -> { "hello".send(@method, 0, bignum_value) }.should.raise(RangeError)
end
it "raises a RangeError if the index or length is too small" do
- -> { "hello".send(@method, -bignum_value, 1) }.should raise_error(RangeError)
- -> { "hello".send(@method, 0, -bignum_value) }.should raise_error(RangeError)
+ -> { "hello".send(@method, -bignum_value, 1) }.should.raise(RangeError)
+ -> { "hello".send(@method, 0, -bignum_value) }.should.raise(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)
+ s.send(@method, 0,0).should.instance_of?(String)
+ s.send(@method, 0,4).should.instance_of?(String)
+ s.send(@method, 1,4).should.instance_of?(String)
end
it "handles repeated application" do
@@ -250,9 +250,9 @@ describe :string_slice_range, shared: true 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)
+ s.send(@method, 0...0).should.instance_of?(String)
+ s.send(@method, 0..4).should.instance_of?(String)
+ s.send(@method, 1..4).should.instance_of?(String)
end
it "calls to_int on range arguments" do
@@ -293,12 +293,12 @@ describe :string_slice_range, shared: true do
end
it "raises a type error if a range is passed with a length" do
- ->{ "hello".send(@method, 1..2, 1) }.should raise_error(TypeError)
+ ->{ "hello".send(@method, 1..2, 1) }.should.raise(TypeError)
end
it "raises a RangeError if one of the bound is too big" do
- -> { "hello".send(@method, bignum_value..(bignum_value + 1)) }.should raise_error(RangeError)
- -> { "hello".send(@method, 0..bignum_value) }.should raise_error(RangeError)
+ -> { "hello".send(@method, bignum_value..(bignum_value + 1)) }.should.raise(RangeError)
+ -> { "hello".send(@method, 0..bignum_value) }.should.raise(RangeError)
end
it "works with endless ranges" do
@@ -333,8 +333,8 @@ describe :string_slice_regexp, shared: true 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)
+ s.send(@method, //).should.instance_of?(String)
+ s.send(@method, /../).should.instance_of?(String)
end
it "sets $~ to MatchData when there is a match and nil when there's none" do
@@ -394,19 +394,19 @@ describe :string_slice_regexp_index, shared: true do
end
it "raises a TypeError when the given index can't be converted to Integer" do
- -> { "hello".send(@method, /(.)(.)(.)/, mock('x')) }.should raise_error(TypeError)
- -> { "hello".send(@method, /(.)(.)(.)/, {}) }.should raise_error(TypeError)
- -> { "hello".send(@method, /(.)(.)(.)/, []) }.should raise_error(TypeError)
+ -> { "hello".send(@method, /(.)(.)(.)/, mock('x')) }.should.raise(TypeError)
+ -> { "hello".send(@method, /(.)(.)(.)/, {}) }.should.raise(TypeError)
+ -> { "hello".send(@method, /(.)(.)(.)/, []) }.should.raise(TypeError)
end
it "raises a TypeError when the given index is nil" do
- -> { "hello".send(@method, /(.)(.)(.)/, nil) }.should raise_error(TypeError)
+ -> { "hello".send(@method, /(.)(.)(.)/, nil) }.should.raise(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)
+ s.send(@method, /(.)(.)/, 0).should.instance_of?(String)
+ s.send(@method, /(.)(.)/, 1).should.instance_of?(String)
end
it "sets $~ to MatchData when there is a match and nil when there's none" do
@@ -442,14 +442,14 @@ describe :string_slice_string, shared: true do
o = mock('x')
o.should_not_receive(:to_str)
- -> { "hello".send(@method, o) }.should raise_error(TypeError)
+ -> { "hello".send(@method, o) }.should.raise(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)
+ r.should.instance_of?(String)
end
end
@@ -476,28 +476,28 @@ describe :string_slice_regexp_group, shared: true do
end
it "returns nil if there is no match" do
- "hello there".send(@method, /(?<whut>what?)/, 'whut').should be_nil
+ "hello there".send(@method, /(?<whut>what?)/, 'whut').should == nil
end
it "raises an IndexError if there is no capture for the given name" do
-> do
"hello there".send(@method, /[aeiou](.)\1/, 'non')
- end.should raise_error(IndexError)
+ end.should.raise(IndexError)
end
it "raises a TypeError when the given name is not a String" do
- -> { "hello".send(@method, /(?<q>.)/, mock('x')) }.should raise_error(TypeError)
- -> { "hello".send(@method, /(?<q>.)/, {}) }.should raise_error(TypeError)
- -> { "hello".send(@method, /(?<q>.)/, []) }.should raise_error(TypeError)
+ -> { "hello".send(@method, /(?<q>.)/, mock('x')) }.should.raise(TypeError)
+ -> { "hello".send(@method, /(?<q>.)/, {}) }.should.raise(TypeError)
+ -> { "hello".send(@method, /(?<q>.)/, []) }.should.raise(TypeError)
end
it "raises an IndexError when given the empty String as a group name" do
- -> { "hello".send(@method, /(?<q>)/, '') }.should raise_error(IndexError)
+ -> { "hello".send(@method, /(?<q>)/, '') }.should.raise(IndexError)
end
it "returns String instances" do
s = StringSpecs::MyString.new("hello")
- s.send(@method, /(?<q>.)/, 'q').should be_an_instance_of(String)
+ s.send(@method, /(?<q>.)/, 'q').should.instance_of?(String)
end
it "sets $~ to MatchData when there is a match and nil when there's none" do
@@ -505,13 +505,13 @@ describe :string_slice_regexp_group, shared: true do
$~[0].should == 'he'
'hello'.send(@method, /(?<non>not)/, 'non')
- $~.should be_nil
+ $~.should == nil
end
end
end
describe :string_slice_symbol, shared: true do
it "raises TypeError" do
- -> { 'hello'.send(@method, :hello) }.should raise_error(TypeError)
+ -> { 'hello'.send(@method, :hello) }.should.raise(TypeError)
end
end
diff --git a/spec/ruby/core/string/shared/strip.rb b/spec/ruby/core/string/shared/strip.rb
index 3af77b50fe..39c7232ff9 100644
--- a/spec/ruby/core/string/shared/strip.rb
+++ b/spec/ruby/core/string/shared/strip.rb
@@ -7,8 +7,8 @@ describe :string_strip, shared: true do
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)
+ StringSpecs::MyString.new(" hello ").send(@method).should.instance_of?(String)
+ StringSpecs::MyString.new(" ").send(@method).should.instance_of?(String)
+ StringSpecs::MyString.new("").send(@method).should.instance_of?(String)
end
end
diff --git a/spec/ruby/core/string/shared/succ.rb b/spec/ruby/core/string/shared/succ.rb
deleted file mode 100644
index 7c68345f10..0000000000
--- a/spec/ruby/core/string/shared/succ.rb
+++ /dev/null
@@ -1,87 +0,0 @@
-# encoding: binary
-describe :string_succ, shared: true do
- it "returns an empty string for empty strings" do
- "".send(@method).should == ""
- end
-
- it "returns the successor by increasing the rightmost alphanumeric (digit => digit, letter => letter with same case)" do
- "abcd".send(@method).should == "abce"
- "THX1138".send(@method).should == "THX1139"
-
- "<<koala>>".send(@method).should == "<<koalb>>"
- "==A??".send(@method).should == "==B??"
- end
-
- it "increases non-alphanumerics (via ascii rules) if there are no alphanumerics" do
- "***".send(@method).should == "**+"
- "**`".send(@method).should == "**a"
- end
-
- it "increases the next best alphanumeric (jumping over non-alphanumerics) if there is a carry" do
- "dz".send(@method).should == "ea"
- "HZ".send(@method).should == "IA"
- "49".send(@method).should == "50"
-
- "izz".send(@method).should == "jaa"
- "IZZ".send(@method).should == "JAA"
- "699".send(@method).should == "700"
-
- "6Z99z99Z".send(@method).should == "7A00a00A"
-
- "1999zzz".send(@method).should == "2000aaa"
- "NZ/[]ZZZ9999".send(@method).should == "OA/[]AAA0000"
- end
-
- it "increases the next best character if there is a carry for non-alphanumerics" do
- "(\xFF".send(@method).should == ")\x00"
- "`\xFF".send(@method).should == "a\x00"
- "<\xFF\xFF".send(@method).should == "=\x00\x00"
- end
-
- it "adds an additional character (just left to the last increased one) if there is a carry and no character left to increase" do
- "z".send(@method).should == "aa"
- "Z".send(@method).should == "AA"
- "9".send(@method).should == "10"
-
- "zz".send(@method).should == "aaa"
- "ZZ".send(@method).should == "AAA"
- "99".send(@method).should == "100"
-
- "9Z99z99Z".send(@method).should == "10A00a00A"
-
- "ZZZ9999".send(@method).should == "AAAA0000"
- "/[]9999".send(@method).should == "/[]10000"
- "/[]ZZZ9999".send(@method).should == "/[]AAAA0000"
- "Z/[]ZZZ9999".send(@method).should == "AA/[]AAA0000"
-
- # non-alphanumeric cases
- "\xFF".send(@method).should == "\x01\x00"
- "\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)
- end
-
- it "returns a String in the same encoding as self" do
- "z".encode("US-ASCII").send(@method).encoding.should == Encoding::US_ASCII
- end
-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
- end
- end
-
- it "raises a FrozenError if self is frozen" do
- -> { "".freeze.send(@method) }.should raise_error(FrozenError)
- -> { "abcd".freeze.send(@method) }.should raise_error(FrozenError)
- end
-end
diff --git a/spec/ruby/core/string/shared/to_s.rb b/spec/ruby/core/string/shared/to_s.rb
deleted file mode 100644
index 4b87a6cbe1..0000000000
--- a/spec/ruby/core/string/shared/to_s.rb
+++ /dev/null
@@ -1,13 +0,0 @@
-describe :string_to_s, shared: true do
- it "returns self when self.class == String" do
- a = "a string"
- a.should equal(a.send(@method))
- end
-
- it "returns a new instance of String when called on a subclass" do
- a = StringSpecs::MyString.new("a string")
- s = a.send(@method)
- s.should == "a string"
- s.should be_an_instance_of(String)
- end
-end
diff --git a/spec/ruby/core/string/shared/to_sym.rb b/spec/ruby/core/string/shared/to_sym.rb
deleted file mode 100644
index 833eae100e..0000000000
--- a/spec/ruby/core/string/shared/to_sym.rb
+++ /dev/null
@@ -1,72 +0,0 @@
-describe :string_to_sym, shared: true do
- it "returns the symbol corresponding to self" do
- "Koala".send(@method).should equal :Koala
- 'cat'.send(@method).should equal :cat
- '@cat'.send(@method).should equal :@cat
- 'cat and dog'.send(@method).should equal :"cat and dog"
- "abc=".send(@method).should equal :abc=
- end
-
- it "does not special case +(binary) and -(binary)" do
- "+(binary)".send(@method).should equal :"+(binary)"
- "-(binary)".send(@method).should equal :"-(binary)"
- end
-
- it "does not special case certain operators" do
- "!@".send(@method).should equal :"!@"
- "~@".send(@method).should equal :"~@"
- "!(unary)".send(@method).should equal :"!(unary)"
- "~(unary)".send(@method).should equal :"~(unary)"
- "+(unary)".send(@method).should equal :"+(unary)"
- "-(unary)".send(@method).should equal :"-(unary)"
- end
-
- it "returns a US-ASCII Symbol for a UTF-8 String containing only US-ASCII characters" do
- sym = "foobar".send(@method)
- sym.encoding.should == Encoding::US_ASCII
- sym.should equal :"foobar"
- end
-
- it "returns a US-ASCII Symbol for a binary String containing only US-ASCII characters" do
- sym = "foobar".b.send(@method)
- sym.encoding.should == Encoding::US_ASCII
- sym.should equal :"foobar"
- end
-
- it "returns a UTF-8 Symbol for a UTF-8 String containing non US-ASCII characters" do
- sym = "il était une fois".send(@method)
- sym.encoding.should == Encoding::UTF_8
- sym.should equal :"il était une #{'fois'}"
- end
-
- it "returns a UTF-16LE Symbol for a UTF-16LE String containing non US-ASCII characters" do
- utf16_str = "UtéF16".encode(Encoding::UTF_16LE)
- sym = utf16_str.send(@method)
- sym.encoding.should == Encoding::UTF_16LE
- sym.to_s.should == utf16_str
- end
-
- it "returns a binary Symbol for a binary String containing non US-ASCII characters" do
- binary_string = "binarí".b
- sym = binary_string.send(@method)
- sym.encoding.should == Encoding::BINARY
- sym.to_s.should == binary_string
- end
-
- 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.encoding.should == Encoding::ISO_8859_1
- binary_symbol = source.dup.force_encoding(Encoding::BINARY).send(@method)
- binary_symbol.encoding.should == Encoding::BINARY
- end
-
- it "raises an EncodingError for UTF-8 String containing invalid bytes" do
- invalid_utf8 = "\xC3"
- invalid_utf8.should_not.valid_encoding?
- -> {
- invalid_utf8.send(@method)
- }.should raise_error(EncodingError, 'invalid symbol in encoding UTF-8 :"\xC3"')
- end
-end
diff --git a/spec/ruby/core/string/size_spec.rb b/spec/ruby/core/string/size_spec.rb
index 9e1f40c5ae..6fc81480c4 100644
--- a/spec/ruby/core/string/size_spec.rb
+++ b/spec/ruby/core/string/size_spec.rb
@@ -1,7 +1,7 @@
require_relative '../../spec_helper'
-require_relative 'fixtures/classes'
-require_relative 'shared/length'
describe "String#size" do
- it_behaves_like :string_length, :size
+ it "is an alias of String#length" do
+ String.instance_method(:size).should == String.instance_method(:length)
+ end
end
diff --git a/spec/ruby/core/string/slice_spec.rb b/spec/ruby/core/string/slice_spec.rb
index 5aba2d3be0..16d7665bbf 100644
--- a/spec/ruby/core/string/slice_spec.rb
+++ b/spec/ruby/core/string/slice_spec.rb
@@ -1,39 +1,12 @@
-# -*- encoding: utf-8 -*-
# frozen_string_literal: false
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
require_relative 'shared/slice'
describe "String#slice" do
- it_behaves_like :string_slice, :slice
-end
-
-describe "String#slice with index, length" do
- it_behaves_like :string_slice_index_length, :slice
-end
-
-describe "String#slice with Range" do
- it_behaves_like :string_slice_range, :slice
-end
-
-describe "String#slice with Regexp" do
- it_behaves_like :string_slice_regexp, :slice
-end
-
-describe "String#slice with Regexp, index" do
- it_behaves_like :string_slice_regexp_index, :slice
-end
-
-describe "String#slice with Regexp, group" do
- it_behaves_like :string_slice_regexp_group, :slice
-end
-
-describe "String#slice with String" do
- it_behaves_like :string_slice_string, :slice
-end
-
-describe "String#slice with Symbol" do
- it_behaves_like :string_slice_symbol, :slice
+ it "is an alias of String#[]" do
+ String.instance_method(:slice).should == String.instance_method(:[])
+ end
end
describe "String#slice! with index" do
@@ -54,9 +27,9 @@ describe "String#slice! with index" do
end
it "raises a FrozenError if self is frozen" do
- -> { "hello".freeze.slice!(1) }.should raise_error(FrozenError)
- -> { "hello".freeze.slice!(10) }.should raise_error(FrozenError)
- -> { "".freeze.slice!(0) }.should raise_error(FrozenError)
+ -> { "hello".freeze.slice!(1) }.should.raise(FrozenError)
+ -> { "hello".freeze.slice!(10) }.should.raise(FrozenError)
+ -> { "".freeze.slice!(0) }.should.raise(FrozenError)
end
it "calls to_int on index" do
@@ -110,13 +83,13 @@ describe "String#slice! with index, length" do
end
it "raises a FrozenError if self is frozen" do
- -> { "hello".freeze.slice!(1, 2) }.should raise_error(FrozenError)
- -> { "hello".freeze.slice!(10, 3) }.should raise_error(FrozenError)
- -> { "hello".freeze.slice!(-10, 3)}.should raise_error(FrozenError)
- -> { "hello".freeze.slice!(4, -3) }.should raise_error(FrozenError)
- -> { "hello".freeze.slice!(10, 3) }.should raise_error(FrozenError)
- -> { "hello".freeze.slice!(-10, 3)}.should raise_error(FrozenError)
- -> { "hello".freeze.slice!(4, -3) }.should raise_error(FrozenError)
+ -> { "hello".freeze.slice!(1, 2) }.should.raise(FrozenError)
+ -> { "hello".freeze.slice!(10, 3) }.should.raise(FrozenError)
+ -> { "hello".freeze.slice!(-10, 3)}.should.raise(FrozenError)
+ -> { "hello".freeze.slice!(4, -3) }.should.raise(FrozenError)
+ -> { "hello".freeze.slice!(10, 3) }.should.raise(FrozenError)
+ -> { "hello".freeze.slice!(-10, 3)}.should.raise(FrozenError)
+ -> { "hello".freeze.slice!(4, -3) }.should.raise(FrozenError)
end
it "calls to_int on idx and length" do
@@ -134,8 +107,8 @@ describe "String#slice! with index, length" 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)
+ s.slice!(0, 0).should.instance_of?(String)
+ s.slice!(0, 4).should.instance_of?(String)
end
it "returns the substring given by the character offsets" do
@@ -177,8 +150,8 @@ describe "String#slice! Range" 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)
+ s.slice!(0...0).should.instance_of?(String)
+ s.slice!(0..4).should.instance_of?(String)
end
it "calls to_int on range arguments" do
@@ -228,12 +201,12 @@ describe "String#slice! Range" do
it "raises a FrozenError on a frozen instance that is modified" do
- -> { "hello".freeze.slice!(1..3) }.should raise_error(FrozenError)
+ -> { "hello".freeze.slice!(1..3) }.should.raise(FrozenError)
end
# see redmine #1551
it "raises a FrozenError on a frozen instance that would not be modified" do
- -> { "hello".freeze.slice!(10..20)}.should raise_error(FrozenError)
+ -> { "hello".freeze.slice!(10..20)}.should.raise(FrozenError)
end
end
@@ -256,8 +229,8 @@ describe "String#slice! with Regexp" 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)
+ s.slice!(//).should.instance_of?(String)
+ s.slice!(/../).should.instance_of?(String)
end
it "returns the matching portion of self with a multi byte character" do
@@ -274,11 +247,11 @@ describe "String#slice! with Regexp" do
end
it "raises a FrozenError on a frozen instance that is modified" do
- -> { "this is a string".freeze.slice!(/s.*t/) }.should raise_error(FrozenError)
+ -> { "this is a string".freeze.slice!(/s.*t/) }.should.raise(FrozenError)
end
it "raises a FrozenError on a frozen instance that would not be modified" do
- -> { "this is a string".freeze.slice!(/zzz/) }.should raise_error(FrozenError)
+ -> { "this is a string".freeze.slice!(/zzz/) }.should.raise(FrozenError)
end
end
@@ -316,8 +289,8 @@ describe "String#slice! with Regexp, index" 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)
+ s.slice!(/(.)(.)/, 0).should.instance_of?(String)
+ s.slice!(/(.)(.)/, 1).should.instance_of?(String)
end
it "returns the encoding aware capture for the given index" do
@@ -342,9 +315,9 @@ describe "String#slice! with Regexp, index" do
end
it "raises a FrozenError if self is frozen" do
- -> { "this is a string".freeze.slice!(/s.*t/) }.should raise_error(FrozenError)
- -> { "this is a string".freeze.slice!(/zzz/, 0)}.should raise_error(FrozenError)
- -> { "this is a string".freeze.slice!(/(.)/, 2)}.should raise_error(FrozenError)
+ -> { "this is a string".freeze.slice!(/s.*t/) }.should.raise(FrozenError)
+ -> { "this is a string".freeze.slice!(/zzz/, 0)}.should.raise(FrozenError)
+ -> { "this is a string".freeze.slice!(/(.)/, 2)}.should.raise(FrozenError)
end
end
@@ -372,19 +345,19 @@ describe "String#slice! with String" do
o = mock('x')
o.should_not_receive(:to_str)
- -> { "hello".slice!(o) }.should raise_error(TypeError)
+ -> { "hello".slice!(o) }.should.raise(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)
+ r.should.instance_of?(String)
end
it "raises a FrozenError if self is frozen" do
- -> { "hello hello".freeze.slice!('llo') }.should raise_error(FrozenError)
- -> { "this is a string".freeze.slice!('zzz')}.should raise_error(FrozenError)
- -> { "this is a string".freeze.slice!('zzz')}.should raise_error(FrozenError)
+ -> { "hello hello".freeze.slice!('llo') }.should.raise(FrozenError)
+ -> { "this is a string".freeze.slice!('zzz')}.should.raise(FrozenError)
+ -> { "this is a string".freeze.slice!('zzz')}.should.raise(FrozenError)
end
end
diff --git a/spec/ruby/core/string/split_spec.rb b/spec/ruby/core/string/split_spec.rb
index 3c6d1864d1..6e8c1c6219 100644
--- a/spec/ruby/core/string/split_spec.rb
+++ b/spec/ruby/core/string/split_spec.rb
@@ -6,15 +6,15 @@ 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.split }.should raise_error(ArgumentError)
- -> { s.split(':') }.should raise_error(ArgumentError)
+ -> { s.split }.should.raise(ArgumentError)
+ -> { s.split(':') }.should.raise(ArgumentError)
end
it "throws an ArgumentError if the pattern is not a valid string" do
str = 'проверка'
broken_str = "\xDF".dup.force_encoding(Encoding::UTF_8)
- -> { str.split(broken_str) }.should raise_error(ArgumentError)
+ -> { str.split(broken_str) }.should.raise(ArgumentError)
end
it "splits on multibyte characters" do
@@ -94,7 +94,7 @@ describe "String#split with String" do
end
it "raises a RangeError when the limit is larger than int" do
- -> { "a,b".split(" ", 2147483649) }.should raise_error(RangeError)
+ -> { "a,b".split(" ", 2147483649) }.should.raise(RangeError)
end
it "defaults to $; when string isn't given or nil" do
@@ -119,21 +119,21 @@ describe "String#split with String" do
$; = old_fs
end
end
+ end
- context "when $; is not nil" do
- before do
- suppress_warning do
- @old_value, $; = $;, 'foobar'
- end
+ context "when $; is not nil" do
+ before do
+ suppress_warning do
+ @old_value, $; = $;, 'foobar'
end
+ end
- after do
- $; = @old_value
- end
+ after do
+ $; = @old_value
+ end
- it "warns" do
- -> { "".split }.should complain(/warning: \$; is set to non-nil value/)
- end
+ it "warns" do
+ -> { "".split }.should complain(/warning: \$; is set to non-nil value/)
end
end
@@ -197,11 +197,11 @@ describe "String#split with String" do
["", ".", " "].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)
+ x.should.instance_of?(String)
end
str.split(StringSpecs::MyString.new(pat), limit).each do |x|
- x.should be_an_instance_of(String)
+ x.should.instance_of?(String)
end
end
end
@@ -231,7 +231,7 @@ 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.split(/./) }.should raise_error(ArgumentError)
+ -> { s.split(/./) }.should.raise(ArgumentError)
end
it "divides self on regexp matches" do
@@ -367,8 +367,8 @@ describe "String#split with Regexp" do
end
it "returns a type error if limit can't be converted to an integer" do
- -> {"1.2.3.4".split(".", "three")}.should raise_error(TypeError)
- -> {"1.2.3.4".split(".", nil) }.should raise_error(TypeError)
+ -> {"1.2.3.4".split(".", "three")}.should.raise(TypeError)
+ -> {"1.2.3.4".split(".", nil) }.should.raise(TypeError)
end
it "doesn't set $~" do
@@ -391,7 +391,7 @@ describe "String#split with Regexp" do
[//, /:/, /\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)
+ x.should.instance_of?(String)
end
end
end
@@ -413,7 +413,7 @@ describe "String#split with Regexp" do
broken_str.force_encoding('binary')
broken_str.chop!
broken_str.force_encoding('utf-8')
- ->{ broken_str.split(/\r\n|\r|\n/) }.should raise_error(ArgumentError)
+ ->{ broken_str.split(/\r\n|\r|\n/) }.should.raise(ArgumentError)
end
# See https://bugs.ruby-lang.org/issues/12689 and https://github.com/jruby/jruby/issues/4868
@@ -522,19 +522,19 @@ describe "String#split with Regexp" do
StringSpecs::MyString.new("a|b").split("|") { |str| a << str }
first, last = a
- first.should be_an_instance_of(String)
+ first.should.instance_of?(String)
first.should == "a"
- last.should be_an_instance_of(String)
+ last.should.instance_of?(String)
last.should == "b"
end
end
it "raises a TypeError when not called with nil, String, or Regexp" do
- -> { "hello".split(42) }.should raise_error(TypeError)
- -> { "hello".split(:ll) }.should raise_error(TypeError)
- -> { "hello".split(false) }.should raise_error(TypeError)
- -> { "hello".split(Object.new) }.should raise_error(TypeError)
+ -> { "hello".split(42) }.should.raise(TypeError)
+ -> { "hello".split(:ll) }.should.raise(TypeError)
+ -> { "hello".split(false) }.should.raise(TypeError)
+ -> { "hello".split(Object.new) }.should.raise(TypeError)
end
it "returns Strings in the same encoding as self" do
diff --git a/spec/ruby/core/string/squeeze_spec.rb b/spec/ruby/core/string/squeeze_spec.rb
index 981d480684..52b6e1eed4 100644
--- a/spec/ruby/core/string/squeeze_spec.rb
+++ b/spec/ruby/core/string/squeeze_spec.rb
@@ -51,8 +51,8 @@ describe "String#squeeze" do
it "raises an ArgumentError when the parameter is out of sequence" do
s = "--subbookkeeper--"
- -> { s.squeeze("e-b") }.should raise_error(ArgumentError)
- -> { s.squeeze("^e-b") }.should raise_error(ArgumentError)
+ -> { s.squeeze("e-b") }.should.raise(ArgumentError)
+ -> { s.squeeze("^e-b") }.should.raise(ArgumentError)
end
it "tries to convert each set arg to a string using to_str" do
@@ -71,20 +71,20 @@ describe "String#squeeze" do
end
it "raises a TypeError when one set arg can't be converted to a string" do
- -> { "hello world".squeeze([]) }.should raise_error(TypeError)
- -> { "hello world".squeeze(Object.new)}.should raise_error(TypeError)
- -> { "hello world".squeeze(mock('x')) }.should raise_error(TypeError)
+ -> { "hello world".squeeze([]) }.should.raise(TypeError)
+ -> { "hello world".squeeze(Object.new)}.should.raise(TypeError)
+ -> { "hello world".squeeze(mock('x')) }.should.raise(TypeError)
end
it "returns String instances when called on a subclass" do
- StringSpecs::MyString.new("oh no!!!").squeeze("!").should be_an_instance_of(String)
+ StringSpecs::MyString.new("oh no!!!").squeeze("!").should.instance_of?(String)
end
end
describe "String#squeeze!" do
it "modifies self in place and returns self" do
a = "yellow moon"
- a.squeeze!.should equal(a)
+ a.squeeze!.should.equal?(a)
a.should == "yelow mon"
end
@@ -97,15 +97,15 @@ describe "String#squeeze!" do
it "raises an ArgumentError when the parameter is out of sequence" do
s = "--subbookkeeper--"
- -> { s.squeeze!("e-b") }.should raise_error(ArgumentError)
- -> { s.squeeze!("^e-b") }.should raise_error(ArgumentError)
+ -> { s.squeeze!("e-b") }.should.raise(ArgumentError)
+ -> { s.squeeze!("^e-b") }.should.raise(ArgumentError)
end
it "raises a FrozenError when self is frozen" do
a = "yellow moon"
a.freeze
- -> { a.squeeze!("") }.should raise_error(FrozenError)
- -> { a.squeeze! }.should raise_error(FrozenError)
+ -> { a.squeeze!("") }.should.raise(FrozenError)
+ -> { a.squeeze! }.should.raise(FrozenError)
end
end
diff --git a/spec/ruby/core/string/start_with_spec.rb b/spec/ruby/core/string/start_with_spec.rb
index 35e33b46a6..8b0ba6b5a7 100644
--- a/spec/ruby/core/string/start_with_spec.rb
+++ b/spec/ruby/core/string/start_with_spec.rb
@@ -11,17 +11,8 @@ describe "String#start_with?" 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 "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
end
diff --git a/spec/ruby/core/string/strip_spec.rb b/spec/ruby/core/string/strip_spec.rb
index edb6ea3b44..81994a7f2e 100644
--- a/spec/ruby/core/string/strip_spec.rb
+++ b/spec/ruby/core/string/strip_spec.rb
@@ -20,7 +20,7 @@ end
describe "String#strip!" do
it "modifies self in place and returns self" do
a = " hello "
- a.strip!.should equal(a)
+ a.strip!.should.equal?(a)
a.should == "hello"
a = "\tgoodbye\r\v\n"
@@ -47,12 +47,12 @@ describe "String#strip!" do
end
it "raises a FrozenError on a frozen instance that is modified" do
- -> { " hello ".freeze.strip! }.should raise_error(FrozenError)
+ -> { " hello ".freeze.strip! }.should.raise(FrozenError)
end
# see #1552
it "raises a FrozenError on a frozen instance that would not be modified" do
- -> {"hello".freeze.strip! }.should raise_error(FrozenError)
- -> {"".freeze.strip! }.should raise_error(FrozenError)
+ -> {"hello".freeze.strip! }.should.raise(FrozenError)
+ -> {"".freeze.strip! }.should.raise(FrozenError)
end
end
diff --git a/spec/ruby/core/string/sub_spec.rb b/spec/ruby/core/string/sub_spec.rb
index 6ff28ec851..f0082fba59 100644
--- a/spec/ruby/core/string/sub_spec.rb
+++ b/spec/ruby/core/string/sub_spec.rb
@@ -7,7 +7,7 @@ describe "String#sub with pattern, replacement" do
a = "hello"
b = a.sub(/w.*$/, "*")
- b.should_not equal(a)
+ b.should_not.equal?(a)
b.should == "hello"
end
@@ -147,16 +147,16 @@ describe "String#sub with pattern, replacement" do
not_supported_on :opal do
it "raises a TypeError when pattern is a Symbol" do
- -> { "hello".sub(:woot, "x") }.should raise_error(TypeError)
+ -> { "hello".sub(:woot, "x") }.should.raise(TypeError)
end
end
it "raises a TypeError when pattern is an Array" do
- -> { "hello".sub([], "x") }.should raise_error(TypeError)
+ -> { "hello".sub([], "x") }.should.raise(TypeError)
end
it "raises a TypeError when pattern can't be converted to a string" do
- -> { "hello".sub(Object.new, nil) }.should raise_error(TypeError)
+ -> { "hello".sub(Object.new, nil) }.should.raise(TypeError)
end
it "tries to convert replacement to a string using to_str" do
@@ -167,15 +167,15 @@ describe "String#sub with pattern, replacement" do
end
it "raises a TypeError when replacement can't be converted to a string" do
- -> { "hello".sub(/[aeiou]/, []) }.should raise_error(TypeError)
- -> { "hello".sub(/[aeiou]/, 99) }.should raise_error(TypeError)
+ -> { "hello".sub(/[aeiou]/, []) }.should.raise(TypeError)
+ -> { "hello".sub(/[aeiou]/, 99) }.should.raise(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)
+ StringSpecs::MyString.new("").sub(//, "").should.instance_of?(String)
+ StringSpecs::MyString.new("").sub(/foo/, "").should.instance_of?(String)
+ StringSpecs::MyString.new("foo").sub(/foo/, "").should.instance_of?(String)
+ StringSpecs::MyString.new("foo").sub("foo", "").should.instance_of?(String)
end
it "sets $~ to MatchData of match and nil when there's none" do
@@ -281,7 +281,7 @@ end
describe "String#sub! with pattern, replacement" do
it "modifies self in place and returns self" do
a = "hello"
- a.sub!(/[aeiou]/, '*').should equal(a)
+ a.sub!(/[aeiou]/, '*').should.equal?(a)
a.should == "h*llo"
end
@@ -296,9 +296,9 @@ describe "String#sub! with pattern, replacement" do
s = "hello"
s.freeze
- -> { s.sub!(/ROAR/, "x") }.should raise_error(FrozenError)
- -> { s.sub!(/e/, "e") }.should raise_error(FrozenError)
- -> { s.sub!(/[aeiou]/, '*') }.should raise_error(FrozenError)
+ -> { s.sub!(/ROAR/, "x") }.should.raise(FrozenError)
+ -> { s.sub!(/e/, "e") }.should.raise(FrozenError)
+ -> { s.sub!(/[aeiou]/, '*') }.should.raise(FrozenError)
end
it "handles a pattern in a superset encoding" do
@@ -326,7 +326,7 @@ end
describe "String#sub! with pattern and block" do
it "modifies self in place and returns self" do
a = "hello"
- a.sub!(/[aeiou]/) { '*' }.should equal(a)
+ a.sub!(/[aeiou]/) { '*' }.should.equal?(a)
a.should == "h*llo"
end
@@ -357,16 +357,16 @@ describe "String#sub! with pattern and block" do
it "raises a RuntimeError if the string is modified while substituting" do
str = "hello"
- -> { str.sub!(//) { str << 'x' } }.should raise_error(RuntimeError)
+ -> { str.sub!(//) { str << 'x' } }.should.raise(RuntimeError)
end
it "raises a FrozenError when self is frozen" do
s = "hello"
s.freeze
- -> { s.sub!(/ROAR/) { "x" } }.should raise_error(FrozenError)
- -> { s.sub!(/e/) { "e" } }.should raise_error(FrozenError)
- -> { s.sub!(/[aeiou]/) { '*' } }.should raise_error(FrozenError)
+ -> { s.sub!(/ROAR/) { "x" } }.should.raise(FrozenError)
+ -> { s.sub!(/e/) { "e" } }.should.raise(FrozenError)
+ -> { s.sub!(/[aeiou]/) { '*' } }.should.raise(FrozenError)
end
end
@@ -501,12 +501,12 @@ end
describe "String#sub with pattern and without replacement and block" do
it "raises a ArgumentError" do
- -> { "abca".sub(/a/) }.should raise_error(ArgumentError)
+ -> { "abca".sub(/a/) }.should.raise(ArgumentError)
end
end
describe "String#sub! with pattern and without replacement and block" do
it "raises a ArgumentError" do
- -> { "abca".sub!(/a/) }.should raise_error(ArgumentError)
+ -> { "abca".sub!(/a/) }.should.raise(ArgumentError)
end
end
diff --git a/spec/ruby/core/string/succ_spec.rb b/spec/ruby/core/string/succ_spec.rb
index 65047e0aa2..87beca8b09 100644
--- a/spec/ruby/core/string/succ_spec.rb
+++ b/spec/ruby/core/string/succ_spec.rb
@@ -1,11 +1,90 @@
+# encoding: binary
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
-require_relative 'shared/succ'
describe "String#succ" do
- it_behaves_like :string_succ, :succ
+ it "returns an empty string for empty strings" do
+ "".succ.should == ""
+ end
+
+ it "returns the successor by increasing the rightmost alphanumeric (digit => digit, letter => letter with same case)" do
+ "abcd".succ.should == "abce"
+ "THX1138".succ.should == "THX1139"
+
+ "<<koala>>".succ.should == "<<koalb>>"
+ "==A??".succ.should == "==B??"
+ end
+
+ it "increases non-alphanumerics (via ascii rules) if there are no alphanumerics" do
+ "***".succ.should == "**+"
+ "**`".succ.should == "**a"
+ end
+
+ it "increases the next best alphanumeric (jumping over non-alphanumerics) if there is a carry" do
+ "dz".succ.should == "ea"
+ "HZ".succ.should == "IA"
+ "49".succ.should == "50"
+
+ "izz".succ.should == "jaa"
+ "IZZ".succ.should == "JAA"
+ "699".succ.should == "700"
+
+ "6Z99z99Z".succ.should == "7A00a00A"
+
+ "1999zzz".succ.should == "2000aaa"
+ "NZ/[]ZZZ9999".succ.should == "OA/[]AAA0000"
+ end
+
+ it "increases the next best character if there is a carry for non-alphanumerics" do
+ "(\xFF".succ.should == ")\x00"
+ "`\xFF".succ.should == "a\x00"
+ "<\xFF\xFF".succ.should == "=\x00\x00"
+ end
+
+ it "adds an additional character (just left to the last increased one) if there is a carry and no character left to increase" do
+ "z".succ.should == "aa"
+ "Z".succ.should == "AA"
+ "9".succ.should == "10"
+
+ "zz".succ.should == "aaa"
+ "ZZ".succ.should == "AAA"
+ "99".succ.should == "100"
+
+ "9Z99z99Z".succ.should == "10A00a00A"
+
+ "ZZZ9999".succ.should == "AAAA0000"
+ "/[]9999".succ.should == "/[]10000"
+ "/[]ZZZ9999".succ.should == "/[]AAAA0000"
+ "Z/[]ZZZ9999".succ.should == "AA/[]AAA0000"
+
+ # non-alphanumeric cases
+ "\xFF".succ.should == "\x01\x00"
+ "\xFF\xFF".succ.should == "\x01\x00\x00"
+ end
+
+ it "returns String instances when called on a subclass" do
+ StringSpecs::MyString.new("").succ.should.instance_of?(String)
+ StringSpecs::MyString.new("a").succ.should.instance_of?(String)
+ StringSpecs::MyString.new("z").succ.should.instance_of?(String)
+ end
+
+ it "returns a String in the same encoding as self" do
+ "z".encode("US-ASCII").succ.encoding.should == Encoding::US_ASCII
+ end
end
describe "String#succ!" do
- it_behaves_like :string_succ_bang, :"succ!"
+ it "is equivalent to succ, but modifies self in place (still returns self)" do
+ ["", "abcd", "THX1138"].each do |s|
+ s = +s
+ r = s.dup.succ!
+ s.succ!.should.equal?(s)
+ s.should == r
+ end
+ end
+
+ it "raises a FrozenError if self is frozen" do
+ -> { "".freeze.succ! }.should.raise(FrozenError)
+ -> { "abcd".freeze.succ! }.should.raise(FrozenError)
+ end
end
diff --git a/spec/ruby/core/string/swapcase_spec.rb b/spec/ruby/core/string/swapcase_spec.rb
index 011a213501..f0e6e0182c 100644
--- a/spec/ruby/core/string/swapcase_spec.rb
+++ b/spec/ruby/core/string/swapcase_spec.rb
@@ -25,7 +25,7 @@ describe "String#swapcase" do
swapcased.should == "aSSET"
swapcased.size.should == 5
swapcased.bytesize.should == 5
- swapcased.ascii_only?.should be_true
+ swapcased.ascii_only?.should == true
end
end
@@ -49,7 +49,7 @@ describe "String#swapcase" do
end
it "does not allow any other additional option" do
- -> { "aiS".swapcase(:turkic, :ascii) }.should raise_error(ArgumentError)
+ -> { "aiS".swapcase(:turkic, :ascii) }.should.raise(ArgumentError)
end
end
@@ -63,28 +63,28 @@ describe "String#swapcase" do
end
it "does not allow any other additional option" do
- -> { "aiS".swapcase(:lithuanian, :ascii) }.should raise_error(ArgumentError)
+ -> { "aiS".swapcase(:lithuanian, :ascii) }.should.raise(ArgumentError)
end
end
it "does not allow the :fold option for upcasing" do
- -> { "abc".swapcase(:fold) }.should raise_error(ArgumentError)
+ -> { "abc".swapcase(:fold) }.should.raise(ArgumentError)
end
it "does not allow invalid options" do
- -> { "abc".swapcase(:invalid_option) }.should raise_error(ArgumentError)
+ -> { "abc".swapcase(:invalid_option) }.should.raise(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)
+ StringSpecs::MyString.new("").swapcase.should.instance_of?(String)
+ StringSpecs::MyString.new("hello").swapcase.should.instance_of?(String)
end
end
describe "String#swapcase!" do
it "modifies self in place" do
a = "cYbEr_PuNk11"
- a.swapcase!.should equal(a)
+ a.swapcase!.should.equal?(a)
a.should == "CyBeR_pUnK11"
end
@@ -114,7 +114,7 @@ describe "String#swapcase!" do
swapcased.should == "aSSET"
swapcased.size.should == 5
swapcased.bytesize.should == 5
- swapcased.ascii_only?.should be_true
+ swapcased.ascii_only?.should == true
end
end
@@ -146,7 +146,7 @@ describe "String#swapcase!" do
end
it "does not allow any other additional option" do
- -> { a = "aiS"; a.swapcase!(:turkic, :ascii) }.should raise_error(ArgumentError)
+ -> { a = "aiS"; a.swapcase!(:turkic, :ascii) }.should.raise(ArgumentError)
end
end
@@ -164,16 +164,16 @@ describe "String#swapcase!" do
end
it "does not allow any other additional option" do
- -> { a = "aiS"; a.swapcase!(:lithuanian, :ascii) }.should raise_error(ArgumentError)
+ -> { a = "aiS"; a.swapcase!(:lithuanian, :ascii) }.should.raise(ArgumentError)
end
end
it "does not allow the :fold option for upcasing" do
- -> { a = "abc"; a.swapcase!(:fold) }.should raise_error(ArgumentError)
+ -> { a = "abc"; a.swapcase!(:fold) }.should.raise(ArgumentError)
end
it "does not allow invalid options" do
- -> { a = "abc"; a.swapcase!(:invalid_option) }.should raise_error(ArgumentError)
+ -> { a = "abc"; a.swapcase!(:invalid_option) }.should.raise(ArgumentError)
end
it "returns nil if no modifications were made" do
@@ -187,7 +187,7 @@ describe "String#swapcase!" do
it "raises a FrozenError when self is frozen" do
["", "hello"].each do |a|
a.freeze
- -> { a.swapcase! }.should raise_error(FrozenError)
+ -> { a.swapcase! }.should.raise(FrozenError)
end
end
end
diff --git a/spec/ruby/core/string/to_c_spec.rb b/spec/ruby/core/string/to_c_spec.rb
index 1813890e72..9cd0ed4401 100644
--- a/spec/ruby/core/string/to_c_spec.rb
+++ b/spec/ruby/core/string/to_c_spec.rb
@@ -38,7 +38,7 @@ describe "String#to_c" do
it "raises Encoding::CompatibilityError if String is in not ASCII-compatible encoding" do
-> {
'79+4i'.encode("UTF-16").to_c
- }.should raise_error(Encoding::CompatibilityError, "ASCII incompatible encoding: UTF-16")
+ }.should.raise(Encoding::CompatibilityError, "ASCII incompatible encoding: UTF-16")
end
it "treats a sequence of underscores as an end of Complex string" do
diff --git a/spec/ruby/core/string/to_f_spec.rb b/spec/ruby/core/string/to_f_spec.rb
index a91ccc168e..bb09e4f2f3 100644
--- a/spec/ruby/core/string/to_f_spec.rb
+++ b/spec/ruby/core/string/to_f_spec.rb
@@ -120,11 +120,21 @@ describe "String#to_f" do
"\3771.2".b.to_f.should == 0
end
- ruby_version_is "3.2.3" do
- it "raises Encoding::CompatibilityError if String is in not ASCII-compatible encoding" do
- -> {
- '1.2'.encode("UTF-16").to_f
- }.should raise_error(Encoding::CompatibilityError, "ASCII incompatible encoding: UTF-16")
+ it "raises Encoding::CompatibilityError if String is in not ASCII-compatible encoding" do
+ -> {
+ '1.2'.encode("UTF-16").to_f
+ }.should.raise(Encoding::CompatibilityError, "ASCII incompatible encoding: UTF-16")
+ end
+
+ it "allows String representation without a fractional part" do
+ "1.".to_f.should == 1.0
+ "+1.".to_f.should == 1.0
+ "-1.".to_f.should == -1.0
+ "1.e+0".to_f.should == 1.0
+ "1.e+0".to_f.should == 1.0
+
+ ruby_bug "#20705", ""..."3.4" do
+ "1.e-2".to_f.should be_close(0.01, TOLERANCE)
end
end
end
diff --git a/spec/ruby/core/string/to_i_spec.rb b/spec/ruby/core/string/to_i_spec.rb
index 39f69acda3..629750bd73 100644
--- a/spec/ruby/core/string/to_i_spec.rb
+++ b/spec/ruby/core/string/to_i_spec.rb
@@ -138,31 +138,31 @@ describe "String#to_i" do
end
it "raises an ArgumentError for illegal bases (1, < 0 or > 36)" do
- -> { "".to_i(1) }.should raise_error(ArgumentError)
- -> { "".to_i(-1) }.should raise_error(ArgumentError)
- -> { "".to_i(37) }.should raise_error(ArgumentError)
+ -> { "".to_i(1) }.should.raise(ArgumentError)
+ -> { "".to_i(-1) }.should.raise(ArgumentError)
+ -> { "".to_i(37) }.should.raise(ArgumentError)
end
it "returns an Integer for long strings with trailing spaces" do
"0 ".to_i.should == 0
- "0 ".to_i.should be_an_instance_of(Integer)
+ "0 ".to_i.should.instance_of?(Integer)
"10 ".to_i.should == 10
- "10 ".to_i.should be_an_instance_of(Integer)
+ "10 ".to_i.should.instance_of?(Integer)
"-10 ".to_i.should == -10
- "-10 ".to_i.should be_an_instance_of(Integer)
+ "-10 ".to_i.should.instance_of?(Integer)
end
it "returns an Integer for long strings with leading spaces" do
" 0".to_i.should == 0
- " 0".to_i.should be_an_instance_of(Integer)
+ " 0".to_i.should.instance_of?(Integer)
" 10".to_i.should == 10
- " 10".to_i.should be_an_instance_of(Integer)
+ " 10".to_i.should.instance_of?(Integer)
" -10".to_i.should == -10
- " -10".to_i.should be_an_instance_of(Integer)
+ " -10".to_i.should.instance_of?(Integer)
end
it "returns the correct Integer for long strings" do
diff --git a/spec/ruby/core/string/to_r_spec.rb b/spec/ruby/core/string/to_r_spec.rb
index 4ffbb10d98..fb7c9d108e 100644
--- a/spec/ruby/core/string/to_r_spec.rb
+++ b/spec/ruby/core/string/to_r_spec.rb
@@ -2,7 +2,7 @@ require_relative '../../spec_helper'
describe "String#to_r" do
it "returns a Rational object" do
- String.new.to_r.should be_an_instance_of(Rational)
+ String.new.to_r.should.instance_of?(Rational)
end
it "returns (0/1) for the empty String" do
diff --git a/spec/ruby/core/string/to_s_spec.rb b/spec/ruby/core/string/to_s_spec.rb
index e5872745a8..c48c7f89ac 100644
--- a/spec/ruby/core/string/to_s_spec.rb
+++ b/spec/ruby/core/string/to_s_spec.rb
@@ -1,7 +1,16 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
-require_relative 'shared/to_s'
describe "String#to_s" do
- it_behaves_like :string_to_s, :to_s
+ it "returns self when self.class == String" do
+ a = "a string"
+ a.should.equal?(a.to_s)
+ end
+
+ it "returns a new instance of String when called on a subclass" do
+ a = StringSpecs::MyString.new("a string")
+ s = a.to_s
+ s.should == "a string"
+ s.should.instance_of?(String)
+ end
end
diff --git a/spec/ruby/core/string/to_str_spec.rb b/spec/ruby/core/string/to_str_spec.rb
index e24262a7ae..8253b3d8a3 100644
--- a/spec/ruby/core/string/to_str_spec.rb
+++ b/spec/ruby/core/string/to_str_spec.rb
@@ -1,7 +1,7 @@
require_relative '../../spec_helper'
-require_relative 'fixtures/classes'
-require_relative 'shared/to_s'
describe "String#to_str" do
- it_behaves_like :string_to_s, :to_str
+ it "is an alias of String#to_s" do
+ String.instance_method(:to_str).should == String.instance_method(:to_s)
+ end
end
diff --git a/spec/ruby/core/string/to_sym_spec.rb b/spec/ruby/core/string/to_sym_spec.rb
index f9135211ce..f0ffe58674 100644
--- a/spec/ruby/core/string/to_sym_spec.rb
+++ b/spec/ruby/core/string/to_sym_spec.rb
@@ -1,7 +1,74 @@
require_relative '../../spec_helper'
-require_relative 'fixtures/classes'
-require_relative 'shared/to_sym'
describe "String#to_sym" do
- it_behaves_like :string_to_sym, :to_sym
+ it "returns the symbol corresponding to self" do
+ "Koala".to_sym.should.equal? :Koala
+ 'cat'.to_sym.should.equal? :cat
+ '@cat'.to_sym.should.equal? :@cat
+ 'cat and dog'.to_sym.should.equal? :"cat and dog"
+ "abc=".to_sym.should.equal? :abc=
+ end
+
+ it "does not special case +(binary) and -(binary)" do
+ "+(binary)".to_sym.should.equal? :"+(binary)"
+ "-(binary)".to_sym.should.equal? :"-(binary)"
+ end
+
+ it "does not special case certain operators" do
+ "!@".to_sym.should.equal? :"!@"
+ "~@".to_sym.should.equal? :"~@"
+ "!(unary)".to_sym.should.equal? :"!(unary)"
+ "~(unary)".to_sym.should.equal? :"~(unary)"
+ "+(unary)".to_sym.should.equal? :"+(unary)"
+ "-(unary)".to_sym.should.equal? :"-(unary)"
+ end
+
+ it "returns a US-ASCII Symbol for a UTF-8 String containing only US-ASCII characters" do
+ sym = "foobar".to_sym
+ sym.encoding.should == Encoding::US_ASCII
+ sym.should.equal? :"foobar"
+ end
+
+ it "returns a US-ASCII Symbol for a binary String containing only US-ASCII characters" do
+ sym = "foobar".b.to_sym
+ sym.encoding.should == Encoding::US_ASCII
+ sym.should.equal? :"foobar"
+ end
+
+ it "returns a UTF-8 Symbol for a UTF-8 String containing non US-ASCII characters" do
+ sym = "il était une fois".to_sym
+ sym.encoding.should == Encoding::UTF_8
+ sym.should.equal? :"il était une fois"
+ end
+
+ it "returns a UTF-16LE Symbol for a UTF-16LE String containing non US-ASCII characters" do
+ utf16_str = "UtéF16".encode(Encoding::UTF_16LE)
+ sym = utf16_str.to_sym
+ sym.encoding.should == Encoding::UTF_16LE
+ sym.to_s.should == utf16_str
+ end
+
+ it "returns a binary Symbol for a binary String containing non US-ASCII characters" do
+ binary_string = "binarí".b
+ sym = binary_string.to_sym
+ sym.encoding.should == Encoding::BINARY
+ sym.to_s.should == binary_string
+ end
+
+ it "ignores existing symbols with different encoding" do
+ source = "fée"
+
+ iso_symbol = source.dup.force_encoding(Encoding::ISO_8859_1).to_sym
+ iso_symbol.encoding.should == Encoding::ISO_8859_1
+ binary_symbol = source.dup.force_encoding(Encoding::BINARY).to_sym
+ binary_symbol.encoding.should == Encoding::BINARY
+ end
+
+ it "raises an EncodingError for UTF-8 String containing invalid bytes" do
+ invalid_utf8 = "\xC3"
+ invalid_utf8.should_not.valid_encoding?
+ -> {
+ invalid_utf8.to_sym
+ }.should.raise(EncodingError, 'invalid symbol in encoding UTF-8 :"\xC3"')
+ end
end
diff --git a/spec/ruby/core/string/tr_s_spec.rb b/spec/ruby/core/string/tr_s_spec.rb
index dd72da440c..22a193ec4b 100644
--- a/spec/ruby/core/string/tr_s_spec.rb
+++ b/spec/ruby/core/string/tr_s_spec.rb
@@ -18,13 +18,11 @@ 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
+ 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
it "pads to_str with its last char if it is shorter than from_string" do
@@ -56,7 +54,7 @@ describe "String#tr_s" do
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)
+ StringSpecs::MyString.new("hello").tr_s("e", "a").should.instance_of?(String)
end
# http://redmine.ruby-lang.org/issues/show/1839
@@ -126,8 +124,8 @@ describe "String#tr_s!" do
it "raises a FrozenError if self is frozen" do
s = "hello".freeze
- -> { s.tr_s!("el", "ar") }.should raise_error(FrozenError)
- -> { s.tr_s!("l", "r") }.should raise_error(FrozenError)
- -> { s.tr_s!("", "") }.should raise_error(FrozenError)
+ -> { s.tr_s!("el", "ar") }.should.raise(FrozenError)
+ -> { s.tr_s!("l", "r") }.should.raise(FrozenError)
+ -> { s.tr_s!("", "") }.should.raise(FrozenError)
end
end
diff --git a/spec/ruby/core/string/tr_spec.rb b/spec/ruby/core/string/tr_spec.rb
index 75841a974f..cb57c3851e 100644
--- a/spec/ruby/core/string/tr_spec.rb
+++ b/spec/ruby/core/string/tr_spec.rb
@@ -17,13 +17,11 @@ 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
+ 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
it "pads to_str with its last char if it is shorter than from_string" do
@@ -32,11 +30,11 @@ describe "String#tr" do
end
it "raises an ArgumentError a descending range in the replacement as containing just the start character" do
- -> { "hello".tr("a-y", "z-b") }.should raise_error(ArgumentError)
+ -> { "hello".tr("a-y", "z-b") }.should.raise(ArgumentError)
end
it "raises an ArgumentError a descending range in the source as empty" do
- -> { "hello".tr("l-a", "z") }.should raise_error(ArgumentError)
+ -> { "hello".tr("l-a", "z") }.should.raise(ArgumentError)
end
it "translates chars not in from_string when it starts with a ^" do
@@ -68,7 +66,7 @@ describe "String#tr" do
end
it "returns Stringinstances when called on a subclass" do
- StringSpecs::MyString.new("hello").tr("e", "a").should be_an_instance_of(String)
+ StringSpecs::MyString.new("hello").tr("e", "a").should.instance_of?(String)
end
# http://redmine.ruby-lang.org/issues/show/1839
@@ -121,8 +119,8 @@ describe "String#tr!" do
it "raises a FrozenError if self is frozen" do
s = "abcdefghijklmnopqR".freeze
- -> { s.tr!("cdefg", "12") }.should raise_error(FrozenError)
- -> { s.tr!("R", "S") }.should raise_error(FrozenError)
- -> { s.tr!("", "") }.should raise_error(FrozenError)
+ -> { s.tr!("cdefg", "12") }.should.raise(FrozenError)
+ -> { s.tr!("R", "S") }.should.raise(FrozenError)
+ -> { s.tr!("", "") }.should.raise(FrozenError)
end
end
diff --git a/spec/ruby/core/string/try_convert_spec.rb b/spec/ruby/core/string/try_convert_spec.rb
index 72ce5dd8b2..0c0219cd2e 100644
--- a/spec/ruby/core/string/try_convert_spec.rb
+++ b/spec/ruby/core/string/try_convert_spec.rb
@@ -4,47 +4,47 @@ require_relative 'fixtures/classes'
describe "String.try_convert" do
it "returns the argument if it's a String" do
x = String.new
- String.try_convert(x).should equal(x)
+ String.try_convert(x).should.equal?(x)
end
it "returns the argument if it's a kind of String" do
x = StringSpecs::MyString.new
- String.try_convert(x).should equal(x)
+ String.try_convert(x).should.equal?(x)
end
it "returns nil when the argument does not respond to #to_str" do
- String.try_convert(Object.new).should be_nil
+ String.try_convert(Object.new).should == nil
end
it "sends #to_str to the argument and returns the result if it's nil" do
obj = mock("to_str")
obj.should_receive(:to_str).and_return(nil)
- String.try_convert(obj).should be_nil
+ String.try_convert(obj).should == nil
end
it "sends #to_str to the argument and returns the result if it's a String" do
x = String.new
obj = mock("to_str")
obj.should_receive(:to_str).and_return(x)
- String.try_convert(obj).should equal(x)
+ String.try_convert(obj).should.equal?(x)
end
it "sends #to_str to the argument and returns the result if it's a kind of String" do
x = StringSpecs::MyString.new
obj = mock("to_str")
obj.should_receive(:to_str).and_return(x)
- String.try_convert(obj).should equal(x)
+ String.try_convert(obj).should.equal?(x)
end
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_consistent_error(TypeError, "can't convert MockObject into String (MockObject#to_str gives Object)")
end
it "does not rescue exceptions raised by #to_str" do
obj = mock("to_str")
obj.should_receive(:to_str).and_raise(RuntimeError)
- -> { String.try_convert obj }.should raise_error(RuntimeError)
+ -> { String.try_convert obj }.should.raise(RuntimeError)
end
end
diff --git a/spec/ruby/core/string/uminus_spec.rb b/spec/ruby/core/string/uminus_spec.rb
index 46d88f6704..43abf71d50 100644
--- a/spec/ruby/core/string/uminus_spec.rb
+++ b/spec/ruby/core/string/uminus_spec.rb
@@ -1,6 +1,53 @@
+# frozen_string_literal: false
require_relative '../../spec_helper'
-require_relative 'shared/dedup'
describe 'String#-@' do
- it_behaves_like :string_dedup, :-@
+ it 'returns self if the String is frozen' do
+ input = 'foo'.freeze
+ output = -input
+
+ output.should.equal?(input)
+ output.should.frozen?
+ end
+
+ it 'returns a frozen copy if the String is not frozen' do
+ input = 'foo'
+ output = -input
+
+ output.should.frozen?
+ output.should_not.equal?(input)
+ output.should == 'foo'
+ end
+
+ it "returns the same object for equal unfrozen strings" do
+ origin = "this is a string"
+ dynamic = %w(this is a string).join(' ')
+
+ origin.should_not.equal?(dynamic)
+ (-origin).should.equal?(-dynamic)
+ end
+
+ it "returns the same object when it's called on the same String literal" do
+ (-"unfrozen string").should.equal?(-"unfrozen string")
+ (-"unfrozen string").should_not.equal?(-"another unfrozen string")
+ end
+
+ it "deduplicates frozen strings" do
+ dynamic = %w(this string is frozen).join(' ').freeze
+
+ dynamic.should_not.equal?("this string is frozen".freeze)
+
+ (-dynamic).should.equal?("this string is frozen".freeze)
+ (-dynamic).should.equal?((-"this string is frozen").freeze)
+ end
+
+ it "does not deduplicate a frozen string when it has instance variables" do
+ dynamic = %w(this string is frozen).join(' ')
+ dynamic.instance_variable_set(:@a, 1)
+ dynamic.freeze
+
+ (-dynamic).should_not.equal?("this string is frozen".freeze)
+ (-dynamic).should_not.equal?((-"this string is frozen").freeze)
+ (-dynamic).should.equal?(-dynamic)
+ end
end
diff --git a/spec/ruby/core/string/undump_spec.rb b/spec/ruby/core/string/undump_spec.rb
index 6ff220161c..8516e24b3b 100644
--- a/spec/ruby/core/string/undump_spec.rb
+++ b/spec/ruby/core/string/undump_spec.rb
@@ -8,7 +8,7 @@ describe "String#undump" do
end
it "always returns String instance" do
- StringSpecs::MyString.new('"foo"').undump.should be_an_instance_of(String)
+ StringSpecs::MyString.new('"foo"').undump.should.instance_of?(String)
end
it "strips outer \"" do
@@ -396,46 +396,46 @@ describe "String#undump" do
describe "Limitations" do
it "cannot undump non ASCII-compatible string" do
- -> { '"foo"'.encode('utf-16le').undump }.should raise_error(Encoding::CompatibilityError)
+ -> { '"foo"'.encode('utf-16le').undump }.should.raise(Encoding::CompatibilityError)
end
end
describe "invalid dump" do
it "raises RuntimeError exception if wrapping \" are missing" do
- -> { 'foo'.undump }.should raise_error(RuntimeError, /invalid dumped string/)
- -> { '"foo'.undump }.should raise_error(RuntimeError, /unterminated dumped string/)
- -> { 'foo"'.undump }.should raise_error(RuntimeError, /invalid dumped string/)
- -> { "'foo'".undump }.should raise_error(RuntimeError, /invalid dumped string/)
+ -> { 'foo'.undump }.should.raise(RuntimeError, /invalid dumped string/)
+ -> { '"foo'.undump }.should.raise(RuntimeError, /unterminated dumped string/)
+ -> { 'foo"'.undump }.should.raise(RuntimeError, /invalid dumped string/)
+ -> { "'foo'".undump }.should.raise(RuntimeError, /invalid dumped string/)
end
it "raises RuntimeError if there is incorrect \\x sequence" do
- -> { '"\x"'.undump }.should raise_error(RuntimeError, /invalid hex escape/)
- -> { '"\\x3y"'.undump }.should raise_error(RuntimeError, /invalid hex escape/)
+ -> { '"\x"'.undump }.should.raise(RuntimeError, /invalid hex escape/)
+ -> { '"\\x3y"'.undump }.should.raise(RuntimeError, /invalid hex escape/)
end
it "raises RuntimeError in there is incorrect \\u sequence" do
- -> { '"\\u"'.undump }.should raise_error(RuntimeError, /invalid Unicode escape/)
- -> { '"\\u{"'.undump }.should raise_error(RuntimeError, /invalid Unicode escape/)
- -> { '"\\u{3042"'.undump }.should raise_error(RuntimeError, /invalid Unicode escape/)
- -> { '"\\u"'.undump }.should raise_error(RuntimeError, /invalid Unicode escape/)
+ -> { '"\\u"'.undump }.should.raise(RuntimeError, /invalid Unicode escape/)
+ -> { '"\\u{"'.undump }.should.raise(RuntimeError, /invalid Unicode escape/)
+ -> { '"\\u{3042"'.undump }.should.raise(RuntimeError, /invalid Unicode escape/)
+ -> { '"\\u"'.undump }.should.raise(RuntimeError, /invalid Unicode escape/)
end
it "raises RuntimeError if there is malformed dump of non ASCII-compatible string" do
- -> { '"".force_encoding("BINARY"'.undump }.should raise_error(RuntimeError, /invalid dumped string/)
- -> { '"".force_encoding("Unknown")'.undump }.should raise_error(RuntimeError, /dumped string has unknown encoding name/)
- -> { '"".force_encoding()'.undump }.should raise_error(RuntimeError, /invalid dumped string/)
+ -> { '"".force_encoding("BINARY"'.undump }.should.raise(RuntimeError, /invalid dumped string/)
+ -> { '"".force_encoding("Unknown")'.undump }.should.raise(RuntimeError, /dumped string has unknown encoding name/)
+ -> { '"".force_encoding()'.undump }.should.raise(RuntimeError, /invalid dumped string/)
end
it "raises RuntimeError if string contains \0 character" do
- -> { "\"foo\0\"".undump }.should raise_error(RuntimeError, /string contains null byte/)
+ -> { "\"foo\0\"".undump }.should.raise(RuntimeError, /string contains null byte/)
end
it "raises RuntimeError if string contains non ASCII character" do
- -> { "\"\u3042\"".undump }.should raise_error(RuntimeError, /non-ASCII character detected/)
+ -> { "\"\u3042\"".undump }.should.raise(RuntimeError, /non-ASCII character detected/)
end
it "raises RuntimeError if there are some excessive \"" do
- -> { '" "" "'.undump }.should raise_error(RuntimeError, /invalid dumped string/)
+ -> { '" "" "'.undump }.should.raise(RuntimeError, /invalid dumped string/)
end
end
end
diff --git a/spec/ruby/core/string/unicode_normalize_spec.rb b/spec/ruby/core/string/unicode_normalize_spec.rb
index 2e7d22394a..92b3a46b43 100644
--- a/spec/ruby/core/string/unicode_normalize_spec.rb
+++ b/spec/ruby/core/string/unicode_normalize_spec.rb
@@ -51,13 +51,13 @@ describe "String#unicode_normalize" do
it "raises an Encoding::CompatibilityError if string is not in an unicode encoding" do
-> do
[0xE0].pack('C').force_encoding("ISO-8859-1").unicode_normalize(:nfd)
- end.should raise_error(Encoding::CompatibilityError)
+ end.should.raise(Encoding::CompatibilityError)
end
it "raises an ArgumentError if the specified form is invalid" do
-> {
@angstrom.unicode_normalize(:invalid_form)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
end
@@ -104,13 +104,13 @@ describe "String#unicode_normalize!" do
it "raises an Encoding::CompatibilityError if the string is not in an unicode encoding" do
-> {
[0xE0].pack('C').force_encoding("ISO-8859-1").unicode_normalize!
- }.should raise_error(Encoding::CompatibilityError)
+ }.should.raise(Encoding::CompatibilityError)
end
it "raises an ArgumentError if the specified form is invalid" do
ohm = "\u2126"
-> {
ohm.unicode_normalize!(:invalid_form)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
end
diff --git a/spec/ruby/core/string/unicode_normalized_spec.rb b/spec/ruby/core/string/unicode_normalized_spec.rb
index 91cf2086b2..3ca27d35dd 100644
--- a/spec/ruby/core/string/unicode_normalized_spec.rb
+++ b/spec/ruby/core/string/unicode_normalized_spec.rb
@@ -38,38 +38,38 @@ describe "String#unicode_normalized?" do
end
it "raises an Encoding::CompatibilityError if the string is not in an unicode encoding" do
- -> { @nfc_normalized_str.force_encoding("ISO-8859-1").unicode_normalized? }.should raise_error(Encoding::CompatibilityError)
+ -> { @nfc_normalized_str.force_encoding("ISO-8859-1").unicode_normalized? }.should.raise(Encoding::CompatibilityError)
end
it "raises an ArgumentError if the specified form is invalid" do
- -> { @nfc_normalized_str.unicode_normalized?(:invalid_form) }.should raise_error(ArgumentError)
+ -> { @nfc_normalized_str.unicode_normalized?(:invalid_form) }.should.raise(ArgumentError)
end
it "returns true if str is in Unicode normalization form (nfc)" do
str = "a\u0300"
- str.unicode_normalized?(:nfc).should be_false
+ str.unicode_normalized?(:nfc).should == false
str.unicode_normalize!(:nfc)
- str.unicode_normalized?(:nfc).should be_true
+ str.unicode_normalized?(:nfc).should == true
end
it "returns true if str is in Unicode normalization form (nfd)" do
str = "a\u00E0"
- str.unicode_normalized?(:nfd).should be_false
+ str.unicode_normalized?(:nfd).should == false
str.unicode_normalize!(:nfd)
- str.unicode_normalized?(:nfd).should be_true
+ str.unicode_normalized?(:nfd).should == true
end
it "returns true if str is in Unicode normalization form (nfkc)" do
str = "a\u0300"
- str.unicode_normalized?(:nfkc).should be_false
+ str.unicode_normalized?(:nfkc).should == false
str.unicode_normalize!(:nfkc)
- str.unicode_normalized?(:nfkc).should be_true
+ str.unicode_normalized?(:nfkc).should == true
end
it "returns true if str is in Unicode normalization form (nfkd)" do
str = "a\u00E0"
- str.unicode_normalized?(:nfkd).should be_false
+ str.unicode_normalized?(:nfkd).should == false
str.unicode_normalize!(:nfkd)
- str.unicode_normalized?(:nfkd).should be_true
+ str.unicode_normalized?(:nfkd).should == true
end
end
diff --git a/spec/ruby/core/string/unpack/at_spec.rb b/spec/ruby/core/string/unpack/at_spec.rb
index d4133c23ee..f4999f5922 100644
--- a/spec/ruby/core/string/unpack/at_spec.rb
+++ b/spec/ruby/core/string/unpack/at_spec.rb
@@ -24,6 +24,6 @@ describe "String#unpack with format '@'" do
end
it "raises an ArgumentError if the count exceeds the size of the String" do
- -> { "\x01\x02\x03\x04".unpack("C2@5C") }.should raise_error(ArgumentError)
+ -> { "\x01\x02\x03\x04".unpack("C2@5C") }.should.raise(ArgumentError)
end
end
diff --git a/spec/ruby/core/string/unpack/b_spec.rb b/spec/ruby/core/string/unpack/b_spec.rb
index b088f901fc..fac6ef5151 100644
--- a/spec/ruby/core/string/unpack/b_spec.rb
+++ b/spec/ruby/core/string/unpack/b_spec.rb
@@ -86,20 +86,10 @@ describe "String#unpack with format 'B'" do
].should be_computed_by(:unpack, "BBB")
end
- 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
- end
- end
-
- ruby_version_is "3.3" do
- it "raise ArgumentError for NULL bytes between directives" do
- -> {
- "\x80\x00".unpack("B\x00B")
- }.should raise_error(ArgumentError, /unknown unpack directive/)
- end
+ it "raise ArgumentError for NULL bytes between directives" do
+ -> {
+ "\x80\x00".unpack("B\x00B")
+ }.should.raise(ArgumentError, /unknown unpack directive/)
end
it "ignores spaces between directives" do
@@ -194,20 +184,10 @@ describe "String#unpack with format 'b'" do
].should be_computed_by(:unpack, "bbb")
end
- 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
- end
- end
-
- ruby_version_is "3.3" do
- it "raise ArgumentError for NULL bytes between directives" do
- -> {
- "\x01\x00".unpack("b\x00b")
- }.should raise_error(ArgumentError, /unknown unpack directive/)
- end
+ it "raise ArgumentError for NULL bytes between directives" do
+ -> {
+ "\x01\x00".unpack("b\x00b")
+ }.should.raise(ArgumentError, /unknown unpack directive/)
end
it "ignores spaces between directives" do
diff --git a/spec/ruby/core/string/unpack/c_spec.rb b/spec/ruby/core/string/unpack/c_spec.rb
index 1e9548fb82..d881015b5e 100644
--- a/spec/ruby/core/string/unpack/c_spec.rb
+++ b/spec/ruby/core/string/unpack/c_spec.rb
@@ -35,20 +35,10 @@ describe :string_unpack_8bit, shared: true do
].should be_computed_by(:unpack, unpack_format(3))
end
- 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
- end
- end
-
- ruby_version_is "3.3" do
- it "raise ArgumentError for NULL bytes between directives" do
- -> {
- "abc".unpack(unpack_format("\000", 2))
- }.should raise_error(ArgumentError, /unknown unpack directive/)
- end
+ it "raise ArgumentError for NULL bytes between directives" do
+ -> {
+ "abc".unpack(unpack_format("\000", 2))
+ }.should.raise(ArgumentError, /unknown unpack directive/)
end
it "ignores spaces between directives" do
diff --git a/spec/ruby/core/string/unpack/carret_spec.rb b/spec/ruby/core/string/unpack/carret_spec.rb
new file mode 100644
index 0000000000..815df0c718
--- /dev/null
+++ b/spec/ruby/core/string/unpack/carret_spec.rb
@@ -0,0 +1,43 @@
+# encoding: binary
+ruby_version_is "4.1" do
+ require_relative '../../../spec_helper'
+ require_relative '../fixtures/classes'
+ require_relative 'shared/basic'
+
+ describe "String#unpack with format '^'" do
+ it_behaves_like :string_unpack_basic, '^'
+ it_behaves_like :string_unpack_no_platform, '^'
+
+ it "returns the current offset that start from 0" do
+ "".unpack("^").should == [0]
+ end
+
+ it "returns the current offset after the last decode ended" do
+ "a".unpack("CC^").should == [97, nil, 1]
+ end
+
+ it "returns the current offset that start from the given offset" do
+ "abc".unpack("^", offset: 1).should == [1]
+ end
+
+ it "returns the offset moved by 'X'" do
+ "\x01\x02\x03\x04".unpack("C3X2^").should == [1, 2, 3, 1]
+ end
+
+ it "returns the offset moved by 'x'" do
+ "\x01\x02\x03\x04".unpack("Cx2^").should == [1, 3]
+ end
+
+ it "returns the offset to the position the previous decode ended" do
+ "foo".unpack("A4^").should == ["foo", 3]
+ "foo".unpack("a4^").should == ["foo", 3]
+ "foo".unpack("Z5^").should == ["foo", 3]
+ end
+
+ it "returns the offset including truncated part" do
+ "foo ".unpack("A*^").should == ["foo", 6]
+ "foo\0".unpack("Z*^").should == ["foo", 4]
+ "foo\0\0\0".unpack("Z5^").should == ["foo", 5]
+ end
+ end
+end
diff --git a/spec/ruby/core/string/unpack/h_spec.rb b/spec/ruby/core/string/unpack/h_spec.rb
index 535836087d..0cf8d943a7 100644
--- a/spec/ruby/core/string/unpack/h_spec.rb
+++ b/spec/ruby/core/string/unpack/h_spec.rb
@@ -56,20 +56,10 @@ describe "String#unpack with format 'H'" do
].should be_computed_by(:unpack, "HHH")
end
- 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
- end
- end
-
- ruby_version_is "3.3" do
- it "raise ArgumentError for NULL bytes between directives" do
- -> {
- "\x01\x10".unpack("H\x00H")
- }.should raise_error(ArgumentError, /unknown unpack directive/)
- end
+ it "raise ArgumentError for NULL bytes between directives" do
+ -> {
+ "\x01\x10".unpack("H\x00H")
+ }.should.raise(ArgumentError, /unknown unpack directive/)
end
it "ignores spaces between directives" do
@@ -133,20 +123,10 @@ describe "String#unpack with format 'h'" do
].should be_computed_by(:unpack, "hhh")
end
- 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
- end
- end
-
- ruby_version_is "3.3" do
- it "raise ArgumentError for NULL bytes between directives" do
- -> {
- "\x01\x10".unpack("h\x00h")
- }.should raise_error(ArgumentError, /unknown unpack directive/)
- end
+ it "raise ArgumentError for NULL bytes between directives" do
+ -> {
+ "\x01\x10".unpack("h\x00h")
+ }.should.raise(ArgumentError, /unknown unpack directive/)
end
it "ignores spaces between directives" do
diff --git a/spec/ruby/core/string/unpack/m_spec.rb b/spec/ruby/core/string/unpack/m_spec.rb
index 357987a053..c1c1eea629 100644
--- a/spec/ruby/core/string/unpack/m_spec.rb
+++ b/spec/ruby/core/string/unpack/m_spec.rb
@@ -186,7 +186,7 @@ describe "String#unpack with format 'm'" do
end
it "raises an ArgumentError for an invalid base64 character" do
- -> { "dGV%zdA==".unpack("m0") }.should raise_error(ArgumentError)
+ -> { "dGV%zdA==".unpack("m0") }.should.raise(ArgumentError)
end
end
end
diff --git a/spec/ruby/core/string/unpack/p_spec.rb b/spec/ruby/core/string/unpack/p_spec.rb
index cd48c0523d..4103730269 100644
--- a/spec/ruby/core/string/unpack/p_spec.rb
+++ b/spec/ruby/core/string/unpack/p_spec.rb
@@ -15,7 +15,7 @@ describe "String#unpack with format 'P'" do
packed = ["hello"].pack("P")
packed.unpack("P5").should == ["hello"]
packed.dup.unpack("P5").should == ["hello"]
- -> { packed.to_sym.to_s.unpack("P5") }.should raise_error(ArgumentError, /no associated pointer/)
+ -> { packed.to_sym.to_s.unpack("P5") }.should.raise(ArgumentError, /no associated pointer/)
end
it "reads as many characters as specified" do
@@ -39,6 +39,6 @@ describe "String#unpack with format 'p'" do
packed = ["hello"].pack("p")
packed.unpack("p").should == ["hello"]
packed.dup.unpack("p").should == ["hello"]
- -> { packed.to_sym.to_s.unpack("p") }.should raise_error(ArgumentError, /no associated pointer/)
+ -> { packed.to_sym.to_s.unpack("p") }.should.raise(ArgumentError, /no associated pointer/)
end
end
diff --git a/spec/ruby/core/string/unpack/percent_spec.rb b/spec/ruby/core/string/unpack/percent_spec.rb
index 0e27663195..7142bbf241 100644
--- a/spec/ruby/core/string/unpack/percent_spec.rb
+++ b/spec/ruby/core/string/unpack/percent_spec.rb
@@ -2,6 +2,6 @@ require_relative '../../../spec_helper'
describe "String#unpack with format '%'" do
it "raises an Argument Error" do
- -> { "abc".unpack("%") }.should raise_error(ArgumentError)
+ -> { "abc".unpack("%") }.should.raise(ArgumentError)
end
end
diff --git a/spec/ruby/core/string/unpack/r_spec.rb b/spec/ruby/core/string/unpack/r_spec.rb
new file mode 100644
index 0000000000..a385951aa8
--- /dev/null
+++ b/spec/ruby/core/string/unpack/r_spec.rb
@@ -0,0 +1,85 @@
+# encoding: binary
+require_relative '../../../spec_helper'
+require_relative '../fixtures/classes'
+require_relative 'shared/basic'
+
+ruby_version_is "4.1" do
+ describe "String#unpack with format 'R'" do
+ it_behaves_like :string_unpack_basic, 'R'
+ it_behaves_like :string_unpack_no_platform, 'R'
+
+ it "decodes a ULEB128 integer" do
+ [ ["\x00", [0]],
+ ["\x01", [1]],
+ ["\x7f", [127]],
+ ["\x80\x01", [128]],
+ ["\xff\x7f", [0x3fff]],
+ ["\x80\x80\x01", [0x4000]],
+ ["\xff\xff\xff\xff\x0f", [0xffffffff]],
+ ["\x80\x80\x80\x80\x10", [0x100000000]],
+ ["\xff\xff\xff\xff\xff\xff\xff\xff\xff\x01", [0xffff_ffff_ffff_ffff]],
+ ].should be_computed_by(:unpack, "R")
+ end
+
+ it "decodes multiple values with '*' modifier" do
+ "\x01\x02".unpack("R*").should == [1, 2]
+ "\x7f\x80\x01".unpack("R*").should == [127, 128]
+ end
+
+ it "returns nil for incomplete data" do
+ "\xFF".unpack("R").should == [nil]
+ "\xFF".unpack1("R").should == nil
+ end
+
+ it "returns nil for remaining incomplete values after a valid one" do
+ bytes = [256].pack("R")
+ (bytes + "\xFF").unpack("RRRR").should == [256, nil, nil, nil]
+ end
+
+ it "skips incomplete values with '*' modifier" do
+ "\xFF".unpack("R*").should == []
+ end
+ end
+
+ describe "String#unpack with format 'r'" do
+ it_behaves_like :string_unpack_basic, 'r'
+ it_behaves_like :string_unpack_no_platform, 'r'
+
+ it "decodes a SLEB128 integer" do
+ [ ["\x00", [0]],
+ ["\x01", [1]],
+ ["\x7f", [-1]],
+ ["\x7e", [-2]],
+ ["\xff\x00", [127]],
+ ["\x80\x01", [128]],
+ ["\x81\x7f", [-127]],
+ ["\x80\x7f", [-128]],
+ ].should be_computed_by(:unpack, "r")
+ end
+
+ it "decodes larger numbers" do
+ "\xff\xff\x00".unpack("r").should == [0x3fff]
+ "\x80\x80\x01".unpack("r").should == [0x4000]
+ "\x81\x80\x7f".unpack("r").should == [-0x3fff]
+ "\x80\x80\x7f".unpack("r").should == [-0x4000]
+ end
+
+ it "decodes multiple values with '*' modifier" do
+ "\x00\x01\x7f".unpack("r*").should == [0, 1, -1]
+ end
+
+ it "returns nil for incomplete data" do
+ "\xFF".unpack("r").should == [nil]
+ "\xFF".unpack1("r").should == nil
+ end
+
+ it "returns nil for remaining incomplete values after a valid one" do
+ bytes = [256].pack("r")
+ (bytes + "\xFF").unpack("rrrr").should == [256, nil, nil, nil]
+ end
+
+ it "skips incomplete values with '*' modifier" do
+ "\xFF".unpack("r*").should == []
+ end
+ end
+end
diff --git a/spec/ruby/core/string/unpack/shared/basic.rb b/spec/ruby/core/string/unpack/shared/basic.rb
index b37a447683..2ee2d6899a 100644
--- a/spec/ruby/core/string/unpack/shared/basic.rb
+++ b/spec/ruby/core/string/unpack/shared/basic.rb
@@ -1,30 +1,27 @@
describe :string_unpack_basic, shared: true do
it "ignores whitespace in the format string" do
- "abc".unpack("a \t\n\v\f\r"+unpack_format).should be_an_instance_of(Array)
+ "abc".unpack("a \t\n\v\f\r"+unpack_format).should.instance_of?(Array)
end
it "calls #to_str to coerce the directives string" do
d = mock("unpack directive")
d.should_receive(:to_str).and_return("a"+unpack_format)
- "abc".unpack(d).should be_an_instance_of(Array)
+ "abc".unpack(d).should.instance_of?(Array)
end
- ruby_version_is "3.3" do
- # https://bugs.ruby-lang.org/issues/19150
- it 'raise ArgumentError when a directive is unknown' do
- -> { "abcdefgh".unpack("a R" + unpack_format) }.should raise_error(ArgumentError, /unknown unpack directive 'R'/)
- -> { "abcdefgh".unpack("a 0" + unpack_format) }.should raise_error(ArgumentError, /unknown unpack directive '0'/)
- -> { "abcdefgh".unpack("a :" + unpack_format) }.should raise_error(ArgumentError, /unknown unpack directive ':'/)
- end
+ it "raises ArgumentError when a directive is unknown" do
+ -> { "abcdefgh".unpack("a K" + unpack_format) }.should.raise(ArgumentError, "unknown unpack directive 'K' in 'a K#{unpack_format}'")
+ -> { "abcdefgh".unpack("a 0" + unpack_format) }.should.raise(ArgumentError, "unknown unpack directive '0' in 'a 0#{unpack_format}'")
+ -> { "abcdefgh".unpack("a :" + unpack_format) }.should.raise(ArgumentError, "unknown unpack directive ':' in 'a :#{unpack_format}'")
end
end
describe :string_unpack_no_platform, shared: true do
it "raises an ArgumentError when the format modifier is '_'" do
- -> { "abcdefgh".unpack(unpack_format("_")) }.should raise_error(ArgumentError)
+ -> { "abcdefgh".unpack(unpack_format("_")) }.should.raise(ArgumentError)
end
it "raises an ArgumentError when the format modifier is '!'" do
- -> { "abcdefgh".unpack(unpack_format("!")) }.should raise_error(ArgumentError)
+ -> { "abcdefgh".unpack(unpack_format("!")) }.should.raise(ArgumentError)
end
end
diff --git a/spec/ruby/core/string/unpack/shared/float.rb b/spec/ruby/core/string/unpack/shared/float.rb
index b31c2c8bdc..5525c3fe73 100644
--- a/spec/ruby/core/string/unpack/shared/float.rb
+++ b/spec/ruby/core/string/unpack/shared/float.rb
@@ -53,24 +53,13 @@ describe :string_unpack_float_le, shared: true do
it "decodes NaN" do
# mumble mumble NaN mumble https://bugs.ruby-lang.org/issues/5884
- [nan_value].pack(unpack_format).unpack(unpack_format).first.nan?.should be_true
+ [nan_value].pack(unpack_format).unpack(unpack_format).first.nan?.should == true
end
- 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
- end
- end
-
- ruby_version_is "3.3" do
- it "raise ArgumentError for NULL bytes between directives" do
- -> {
- "\x9a\x999@33\xb3?".unpack(unpack_format("\000", 2))
- }.should raise_error(ArgumentError, /unknown unpack directive/)
- end
+ it "raise ArgumentError for NULL bytes between directives" do
+ -> {
+ "\x9a\x999@33\xb3?".unpack(unpack_format("\000", 2))
+ }.should.raise(ArgumentError, /unknown unpack directive/)
end
it "ignores spaces between directives" do
@@ -132,24 +121,13 @@ describe :string_unpack_float_be, shared: true do
it "decodes NaN" do
# mumble mumble NaN mumble https://bugs.ruby-lang.org/issues/5884
- [nan_value].pack(unpack_format).unpack(unpack_format).first.nan?.should be_true
- end
-
- 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
- end
+ [nan_value].pack(unpack_format).unpack(unpack_format).first.nan?.should == true
end
- ruby_version_is "3.3" do
- it "raise ArgumentError for NULL bytes between directives" do
- -> {
- "@9\x99\x9a?\xb333".unpack(unpack_format("\000", 2))
- }.should raise_error(ArgumentError, /unknown unpack directive/)
- end
+ it "raise ArgumentError for NULL bytes between directives" do
+ -> {
+ "@9\x99\x9a?\xb333".unpack(unpack_format("\000", 2))
+ }.should.raise(ArgumentError, /unknown unpack directive/)
end
it "ignores spaces between directives" do
@@ -214,23 +192,13 @@ describe :string_unpack_double_le, shared: true do
it "decodes NaN" do
# mumble mumble NaN mumble https://bugs.ruby-lang.org/issues/5884
- [nan_value].pack(unpack_format).unpack(unpack_format).first.nan?.should be_true
+ [nan_value].pack(unpack_format).unpack(unpack_format).first.nan?.should == true
end
- 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
- end
- end
-
- ruby_version_is "3.3" do
- it "raise ArgumentError for NULL bytes between directives" do
- -> {
- "333333\x07@ffffff\xf6?".unpack(unpack_format("\000", 2))
- }.should raise_error(ArgumentError, /unknown unpack directive/)
- end
+ it "raise ArgumentError for NULL bytes between directives" do
+ -> {
+ "333333\x07@ffffff\xf6?".unpack(unpack_format("\000", 2))
+ }.should.raise(ArgumentError, /unknown unpack directive/)
end
it "ignores spaces between directives" do
@@ -294,23 +262,13 @@ describe :string_unpack_double_be, shared: true do
it "decodes NaN" do
# mumble mumble NaN mumble https://bugs.ruby-lang.org/issues/5884
- [nan_value].pack(unpack_format).unpack(unpack_format).first.nan?.should be_true
- end
-
- 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
- end
+ [nan_value].pack(unpack_format).unpack(unpack_format).first.nan?.should == true
end
- ruby_version_is "3.3" do
- it "raise ArgumentError for NULL bytes between directives" do
- -> {
- "@\x07333333?\xf6ffffff".unpack(unpack_format("\000", 2))
- }.should raise_error(ArgumentError, /unknown unpack directive/)
- end
+ it "raise ArgumentError for NULL bytes between directives" do
+ -> {
+ "@\x07333333?\xf6ffffff".unpack(unpack_format("\000", 2))
+ }.should.raise(ArgumentError, /unknown unpack directive/)
end
it "ignores spaces between directives" do
diff --git a/spec/ruby/core/string/unpack/shared/integer.rb b/spec/ruby/core/string/unpack/shared/integer.rb
index d3934753ba..c66156536b 100644
--- a/spec/ruby/core/string/unpack/shared/integer.rb
+++ b/spec/ruby/core/string/unpack/shared/integer.rb
@@ -32,20 +32,10 @@ describe :string_unpack_16bit_le, shared: true do
].should be_computed_by(:unpack, unpack_format(3))
end
- 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
- end
- end
-
- ruby_version_is "3.3" do
- it "raise ArgumentError for NULL bytes between directives" do
- -> {
- "abcd".unpack(unpack_format("\000", 2))
- }.should raise_error(ArgumentError, /unknown unpack directive/)
- end
+ it "raise ArgumentError for NULL bytes between directives" do
+ -> {
+ "abcd".unpack(unpack_format("\000", 2))
+ }.should.raise(ArgumentError, /unknown unpack directive/)
end
it "ignores spaces between directives" do
@@ -97,20 +87,10 @@ describe :string_unpack_16bit_be, shared: true do
].should be_computed_by(:unpack, unpack_format(3))
end
- 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
- end
- end
-
- ruby_version_is "3.3" do
- it "raise ArgumentError for NULL bytes between directives" do
- -> {
- "badc".unpack(unpack_format("\000", 2))
- }.should raise_error(ArgumentError, /unknown unpack directive/)
- end
+ it "raise ArgumentError for NULL bytes between directives" do
+ -> {
+ "badc".unpack(unpack_format("\000", 2))
+ }.should.raise(ArgumentError, /unknown unpack directive/)
end
it "ignores spaces between directives" do
@@ -163,20 +143,10 @@ describe :string_unpack_32bit_le, shared: true do
].should be_computed_by(:unpack, unpack_format(3))
end
- 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
- end
- end
-
- ruby_version_is "3.3" do
- it "raise ArgumentError for NULL bytes between directives" do
- -> {
- "abcdefgh".unpack(unpack_format("\000", 2))
- }.should raise_error(ArgumentError, /unknown unpack directive/)
- end
+ it "raise ArgumentError for NULL bytes between directives" do
+ -> {
+ "abcdefgh".unpack(unpack_format("\000", 2))
+ }.should.raise(ArgumentError, /unknown unpack directive/)
end
it "ignores spaces between directives" do
@@ -229,20 +199,10 @@ describe :string_unpack_32bit_be, shared: true do
].should be_computed_by(:unpack, unpack_format(3))
end
- 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
- end
- end
-
- ruby_version_is "3.3" do
- it "raise ArgumentError for NULL bytes between directives" do
- -> {
- "dcbahgfe".unpack(unpack_format("\000", 2))
- }.should raise_error(ArgumentError, /unknown unpack directive/)
- end
+ it "raise ArgumentError for NULL bytes between directives" do
+ -> {
+ "dcbahgfe".unpack(unpack_format("\000", 2))
+ }.should.raise(ArgumentError, /unknown unpack directive/)
end
it "ignores spaces between directives" do
@@ -291,21 +251,10 @@ describe :string_unpack_64bit_le, shared: true do
"abc".unpack(unpack_format('*')).should == []
end
- 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
- end
- end
-
- ruby_version_is "3.3" do
- it "raise ArgumentError for NULL bytes between directives" do
- -> {
- "badc".unpack(unpack_format("\000", 2))
- }.should raise_error(ArgumentError, /unknown unpack directive/)
- end
+ it "raise ArgumentError for NULL bytes between directives" do
+ -> {
+ "badc".unpack(unpack_format("\000", 2))
+ }.should.raise(ArgumentError, /unknown unpack directive/)
end
it "ignores spaces between directives" do
@@ -365,21 +314,10 @@ describe :string_unpack_64bit_be, shared: true do
"abc".unpack(unpack_format('*')).should == []
end
- 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
- end
- end
-
- ruby_version_is "3.3" do
- it "raise ArgumentError for NULL bytes between directives" do
- -> {
- "hgfedcbadcfehgba".unpack(unpack_format("\000", 2))
- }.should raise_error(ArgumentError, /unknown unpack directive/)
- end
+ it "raise ArgumentError for NULL bytes between directives" do
+ -> {
+ "hgfedcbadcfehgba".unpack(unpack_format("\000", 2))
+ }.should.raise(ArgumentError, /unknown unpack directive/)
end
it "ignores spaces between directives" do
diff --git a/spec/ruby/core/string/unpack/shared/unicode.rb b/spec/ruby/core/string/unpack/shared/unicode.rb
index 9fe07f53ae..9b4e0c09de 100644
--- a/spec/ruby/core/string/unpack/shared/unicode.rb
+++ b/spec/ruby/core/string/unpack/shared/unicode.rb
@@ -50,20 +50,10 @@ describe :string_unpack_unicode, shared: true do
"\xc2\x80".unpack("UUUU").should == [0x80]
end
- 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
- end
- end
-
- ruby_version_is "3.3" do
- it "raise ArgumentError for NULL bytes between directives" do
- -> {
- "\x01\x02".unpack("U\x00U")
- }.should raise_error(ArgumentError, /unknown unpack directive/)
- end
+ it "raise ArgumentError for NULL bytes between directives" do
+ -> {
+ "\x01\x02".unpack("U\x00U")
+ }.should.raise(ArgumentError, /unknown unpack directive/)
end
it "ignores spaces between directives" do
diff --git a/spec/ruby/core/string/unpack/u_spec.rb b/spec/ruby/core/string/unpack/u_spec.rb
index 68c8f6f11c..720c1b8583 100644
--- a/spec/ruby/core/string/unpack/u_spec.rb
+++ b/spec/ruby/core/string/unpack/u_spec.rb
@@ -12,11 +12,11 @@ describe "String#unpack with format 'U'" do
it_behaves_like :string_unpack_taint, 'U'
it "raises ArgumentError on a malformed byte sequence" do
- -> { "\xE3".unpack('U') }.should raise_error(ArgumentError)
+ -> { "\xE3".unpack('U') }.should.raise(ArgumentError)
end
it "raises ArgumentError on a malformed byte sequence and doesn't continue when used with the * modifier" do
- -> { "\xE3".unpack('U*') }.should raise_error(ArgumentError)
+ -> { "\xE3".unpack('U*') }.should.raise(ArgumentError)
end
end
diff --git a/spec/ruby/core/string/unpack/w_spec.rb b/spec/ruby/core/string/unpack/w_spec.rb
index 7d3533ccae..cc9aecac9c 100644
--- a/spec/ruby/core/string/unpack/w_spec.rb
+++ b/spec/ruby/core/string/unpack/w_spec.rb
@@ -15,20 +15,10 @@ describe "String#unpack with directive 'w'" do
].should be_computed_by(:unpack, "w")
end
- 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
- end
- end
-
- ruby_version_is "3.3" do
- it "raise ArgumentError for NULL bytes between directives" do
- -> {
- "\x01\x02\x03".unpack("w\x00w")
- }.should raise_error(ArgumentError, /unknown unpack directive/)
- end
+ it "raise ArgumentError for NULL bytes between directives" do
+ -> {
+ "\x01\x02\x03".unpack("w\x00w")
+ }.should.raise(ArgumentError, /unknown unpack directive/)
end
it "ignores spaces between directives" do
diff --git a/spec/ruby/core/string/unpack/x_spec.rb b/spec/ruby/core/string/unpack/x_spec.rb
index 2926ebbe0f..fb2e79fc1f 100644
--- a/spec/ruby/core/string/unpack/x_spec.rb
+++ b/spec/ruby/core/string/unpack/x_spec.rb
@@ -24,11 +24,11 @@ describe "String#unpack with format 'X'" do
end
it "raises an ArgumentError when passed the '*' modifier if the remaining bytes exceed the bytes from the index to the start of the String" do
- -> { "abcd".unpack("CX*C") }.should raise_error(ArgumentError)
+ -> { "abcd".unpack("CX*C") }.should.raise(ArgumentError)
end
it "raises an ArgumentError if the count exceeds the bytes from current index to the start of the String" do
- -> { "\x01\x02\x03\x04".unpack("C3X4C") }.should raise_error(ArgumentError)
+ -> { "\x01\x02\x03\x04".unpack("C3X4C") }.should.raise(ArgumentError)
end
end
@@ -57,6 +57,6 @@ describe "String#unpack with format 'x'" do
end
it "raises an ArgumentError if the count exceeds the size of the String" do
- -> { "\x01\x02\x03\x04".unpack("C2x3C") }.should raise_error(ArgumentError)
+ -> { "\x01\x02\x03\x04".unpack("C2x3C") }.should.raise(ArgumentError)
end
end
diff --git a/spec/ruby/core/string/unpack1_spec.rb b/spec/ruby/core/string/unpack1_spec.rb
index 3b3b879f75..ee10042eb8 100644
--- a/spec/ruby/core/string/unpack1_spec.rb
+++ b/spec/ruby/core/string/unpack1_spec.rb
@@ -20,8 +20,22 @@ describe "String#unpack1" do
"؈".unpack1("C", offset: 1).should == 136
end
- it "raises an ArgumentError when the offset is negative" do
- -> { "a".unpack1("C", offset: -1) }.should raise_error(ArgumentError, "offset can't be negative")
+ describe "when the offset is negative" do
+ ruby_version_is "4.1" do
+ it "starts unpacking from the end" do
+ "abc".unpack1("C", offset: -2).should == 98
+ end
+
+ it "raises an ArgumentError if it is less than -length" do
+ -> { "a".unpack1("C", offset: -2) }.should.raise(ArgumentError, "offset outside of string")
+ end
+ end
+
+ ruby_version_is ""..."4.1" do
+ it "raises an ArgumentError" do
+ -> { "a".unpack1("C", offset: -1) }.should.raise(ArgumentError, "offset can't be negative")
+ end
+ end
end
it "returns nil if the offset is at the end of the string" do
@@ -29,6 +43,19 @@ describe "String#unpack1" do
end
it "raises an ArgumentError when the offset is larger than the string bytesize" do
- -> { "a".unpack1("C", offset: 2) }.should raise_error(ArgumentError, "offset outside of string")
+ -> { "a".unpack1("C", offset: 2) }.should.raise(ArgumentError, "offset outside of string")
+ end
+
+ context "with format 'm0'" do
+ # unpack1("m0") takes a special code path that calls Pack.unpackBase46Strict instead of Pack.unpack_m,
+ # which is why we repeat the tests for unpack("m0") here.
+
+ it "decodes base64" do
+ "dGVzdA==".unpack1("m0").should == "test"
+ end
+
+ it "raises an ArgumentError for an invalid base64 character" do
+ -> { "dGV%zdA==".unpack1("m0") }.should.raise(ArgumentError)
+ end
end
end
diff --git a/spec/ruby/core/string/unpack_spec.rb b/spec/ruby/core/string/unpack_spec.rb
index a0abf8fa99..eb4710ce14 100644
--- a/spec/ruby/core/string/unpack_spec.rb
+++ b/spec/ruby/core/string/unpack_spec.rb
@@ -2,11 +2,11 @@ require_relative '../../spec_helper'
describe "String#unpack" do
it "raises a TypeError when passed nil" do
- -> { "abc".unpack(nil) }.should raise_error(TypeError)
+ -> { "abc".unpack(nil) }.should.raise(TypeError)
end
it "raises a TypeError when passed an Integer" do
- -> { "abc".unpack(1) }.should raise_error(TypeError)
+ -> { "abc".unpack(1) }.should.raise(TypeError)
end
it "starts unpacking from the given offset" do
@@ -18,8 +18,22 @@ describe "String#unpack" do
"؈".unpack("CC", offset: 1).should == [136, nil]
end
- it "raises an ArgumentError when the offset is negative" do
- -> { "a".unpack("C", offset: -1) }.should raise_error(ArgumentError, "offset can't be negative")
+ describe "when the offset is negative" do
+ ruby_version_is "4.1" do
+ it "starts unpacking from the end" do
+ "abc".unpack("CC", offset: -2).should == [98, 99]
+ end
+
+ it "raises an ArgumentError if it is less than -length" do
+ -> { "a".unpack("C", offset: -2) }.should.raise(ArgumentError, "offset outside of string")
+ end
+ end
+
+ ruby_version_is ""..."4.1" do
+ it "raises an ArgumentError" do
+ -> { "a".unpack("C", offset: -1) }.should.raise(ArgumentError, "offset can't be negative")
+ end
+ end
end
it "returns nil if the offset is at the end of the string" do
@@ -27,6 +41,6 @@ describe "String#unpack" do
end
it "raises an ArgumentError when the offset is larger than the string" do
- -> { "a".unpack("C", offset: 2) }.should raise_error(ArgumentError, "offset outside of string")
+ -> { "a".unpack("C", offset: 2) }.should.raise(ArgumentError, "offset outside of string")
end
end
diff --git a/spec/ruby/core/string/upcase_spec.rb b/spec/ruby/core/string/upcase_spec.rb
index 652de5c2ef..a6e1869267 100644
--- a/spec/ruby/core/string/upcase_spec.rb
+++ b/spec/ruby/core/string/upcase_spec.rb
@@ -24,7 +24,7 @@ describe "String#upcase" do
upcased.should == "ASSET"
upcased.size.should == 5
upcased.bytesize.should == 5
- upcased.ascii_only?.should be_true
+ upcased.ascii_only?.should == true
end
end
@@ -48,7 +48,7 @@ describe "String#upcase" do
end
it "does not allow any other additional option" do
- -> { "i".upcase(:turkic, :ascii) }.should raise_error(ArgumentError)
+ -> { "i".upcase(:turkic, :ascii) }.should.raise(ArgumentError)
end
end
@@ -62,27 +62,27 @@ describe "String#upcase" do
end
it "does not allow any other additional option" do
- -> { "iß".upcase(:lithuanian, :ascii) }.should raise_error(ArgumentError)
+ -> { "iß".upcase(:lithuanian, :ascii) }.should.raise(ArgumentError)
end
end
it "does not allow the :fold option for upcasing" do
- -> { "abc".upcase(:fold) }.should raise_error(ArgumentError)
+ -> { "abc".upcase(:fold) }.should.raise(ArgumentError)
end
it "does not allow invalid options" do
- -> { "abc".upcase(:invalid_option) }.should raise_error(ArgumentError)
+ -> { "abc".upcase(:invalid_option) }.should.raise(ArgumentError)
end
it "returns a String instance for subclasses" do
- StringSpecs::MyString.new("fooBAR").upcase.should be_an_instance_of(String)
+ StringSpecs::MyString.new("fooBAR").upcase.should.instance_of?(String)
end
end
describe "String#upcase!" do
it "modifies self in place" do
a = "HeLlO"
- a.upcase!.should equal(a)
+ a.upcase!.should.equal?(a)
a.should == "HELLO"
end
@@ -112,7 +112,7 @@ describe "String#upcase!" do
upcased.should == "ASSET"
upcased.size.should == 5
upcased.bytesize.should == 5
- upcased.ascii_only?.should be_true
+ upcased.ascii_only?.should == true
end
end
@@ -144,7 +144,7 @@ describe "String#upcase!" do
end
it "does not allow any other additional option" do
- -> { a = "i"; a.upcase!(:turkic, :ascii) }.should raise_error(ArgumentError)
+ -> { a = "i"; a.upcase!(:turkic, :ascii) }.should.raise(ArgumentError)
end
end
@@ -162,16 +162,16 @@ describe "String#upcase!" do
end
it "does not allow any other additional option" do
- -> { a = "iß"; a.upcase!(:lithuanian, :ascii) }.should raise_error(ArgumentError)
+ -> { a = "iß"; a.upcase!(:lithuanian, :ascii) }.should.raise(ArgumentError)
end
end
it "does not allow the :fold option for upcasing" do
- -> { a = "abc"; a.upcase!(:fold) }.should raise_error(ArgumentError)
+ -> { a = "abc"; a.upcase!(:fold) }.should.raise(ArgumentError)
end
it "does not allow invalid options" do
- -> { a = "abc"; a.upcase!(:invalid_option) }.should raise_error(ArgumentError)
+ -> { a = "abc"; a.upcase!(:invalid_option) }.should.raise(ArgumentError)
end
it "returns nil if no modifications were made" do
@@ -181,7 +181,7 @@ describe "String#upcase!" do
end
it "raises a FrozenError when self is frozen" do
- -> { "HeLlo".freeze.upcase! }.should raise_error(FrozenError)
- -> { "HELLO".freeze.upcase! }.should raise_error(FrozenError)
+ -> { "HeLlo".freeze.upcase! }.should.raise(FrozenError)
+ -> { "HELLO".freeze.upcase! }.should.raise(FrozenError)
end
end
diff --git a/spec/ruby/core/string/uplus_spec.rb b/spec/ruby/core/string/uplus_spec.rb
index c0b0c49ede..20767bcc01 100644
--- a/spec/ruby/core/string/uplus_spec.rb
+++ b/spec/ruby/core/string/uplus_spec.rb
@@ -13,14 +13,48 @@ describe 'String#+@' do
output.should == 'foobar'
end
- it 'returns self if the String is not frozen' do
- input = 'foo'
+ it 'returns a mutable String itself' do
+ input = String.new("foo")
output = +input
- output.equal?(input).should == true
+ output.should.equal?(input)
+
+ input << "bar"
+ output.should == "foobar"
+ end
+
+ context 'if file has "frozen_string_literal: true" magic comment' do
+ it 'returns mutable copy of a literal' do
+ ruby_exe(fixture(__FILE__, "freeze_magic_comment.rb")).should == 'mutable'
+ end
end
- it 'returns mutable copy despite freeze-magic-comment in file' do
- ruby_exe(fixture(__FILE__, "freeze_magic_comment.rb")).should == 'mutable'
+ context 'if file has "frozen_string_literal: false" magic comment' do
+ it 'returns literal string itself' do
+ input = 'foo'
+ output = +input
+
+ output.equal?(input).should == true
+ end
+ end
+
+ context 'if file has no frozen_string_literal magic comment' do
+ ruby_version_is ''...'3.4' do
+ it 'returns literal string itself' do
+ eval(<<~RUBY).should == true
+ s = "foo"
+ s.equal?(+s)
+ RUBY
+ end
+ end
+
+ ruby_version_is '3.4' do
+ it 'returns mutable copy of a literal' do
+ eval(<<~RUBY).should == false
+ s = "foo"
+ s.equal?(+s)
+ RUBY
+ end
+ end
end
end
diff --git a/spec/ruby/core/string/upto_spec.rb b/spec/ruby/core/string/upto_spec.rb
index 8bc847d5ac..2eea06fd01 100644
--- a/spec/ruby/core/string/upto_spec.rb
+++ b/spec/ruby/core/string/upto_spec.rb
@@ -53,13 +53,13 @@ describe "String#upto" do
end
it "raises a TypeError if other can't be converted to a string" do
- -> { "abc".upto(123) { } }.should raise_error(TypeError)
- -> { "abc".upto(mock('x')){ } }.should raise_error(TypeError)
+ -> { "abc".upto(123) { } }.should.raise(TypeError)
+ -> { "abc".upto(mock('x')){ } }.should.raise(TypeError)
end
it "does not work with symbols" do
- -> { "a".upto(:c).to_a }.should raise_error(TypeError)
+ -> { "a".upto(:c).to_a }.should.raise(TypeError)
end
it "returns non-alphabetic characters in the ASCII range for single letters" do
@@ -83,7 +83,7 @@ describe "String#upto" do
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")
+ -> { char1.upto(char2) {} }.should.raise(Encoding::CompatibilityError, "incompatible character encodings: EUC-JP and ISO-2022-JP")
end
describe "on sequence of numbers" do
@@ -95,7 +95,7 @@ describe "String#upto" do
describe "when no block is given" do
it "returns an enumerator" do
enum = "aaa".upto("baa", true)
- enum.should be_an_instance_of(Enumerator)
+ enum.should.instance_of?(Enumerator)
enum.count.should == 26**2
end
diff --git a/spec/ruby/core/string/valid_encoding_spec.rb b/spec/ruby/core/string/valid_encoding_spec.rb
index 375035cd94..f29220fc99 100644
--- a/spec/ruby/core/string/valid_encoding_spec.rb
+++ b/spec/ruby/core/string/valid_encoding_spec.rb
@@ -2,132 +2,132 @@ require_relative '../../spec_helper'
describe "String#valid_encoding?" do
it "returns true if the String's encoding is valid" do
- "a".valid_encoding?.should be_true
- "\u{8365}\u{221}".valid_encoding?.should be_true
+ "a".valid_encoding?.should == true
+ "\u{8365}\u{221}".valid_encoding?.should == true
end
it "returns true if self is valid in the current encoding and other encodings" do
str = +"\x77"
- str.force_encoding('utf-8').valid_encoding?.should be_true
- str.force_encoding('binary').valid_encoding?.should be_true
+ str.force_encoding('utf-8').valid_encoding?.should == true
+ str.force_encoding('binary').valid_encoding?.should == true
end
it "returns true for all encodings self is valid in" do
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
- str.force_encoding('Big5').valid_encoding?.should be_false
- str.force_encoding('CP949').valid_encoding?.should be_false
- str.force_encoding('Emacs-Mule').valid_encoding?.should be_false
- str.force_encoding('EUC-JP').valid_encoding?.should be_false
- str.force_encoding('EUC-KR').valid_encoding?.should be_false
- str.force_encoding('EUC-TW').valid_encoding?.should be_false
- str.force_encoding('GB18030').valid_encoding?.should be_false
- str.force_encoding('GBK').valid_encoding?.should be_false
- str.force_encoding('ISO-8859-1').valid_encoding?.should be_true
- str.force_encoding('ISO-8859-2').valid_encoding?.should be_true
- str.force_encoding('ISO-8859-3').valid_encoding?.should be_true
- str.force_encoding('ISO-8859-4').valid_encoding?.should be_true
- str.force_encoding('ISO-8859-5').valid_encoding?.should be_true
- str.force_encoding('ISO-8859-6').valid_encoding?.should be_true
- str.force_encoding('ISO-8859-7').valid_encoding?.should be_true
- str.force_encoding('ISO-8859-8').valid_encoding?.should be_true
- str.force_encoding('ISO-8859-9').valid_encoding?.should be_true
- str.force_encoding('ISO-8859-10').valid_encoding?.should be_true
- str.force_encoding('ISO-8859-11').valid_encoding?.should be_true
- str.force_encoding('ISO-8859-13').valid_encoding?.should be_true
- str.force_encoding('ISO-8859-14').valid_encoding?.should be_true
- str.force_encoding('ISO-8859-15').valid_encoding?.should be_true
- str.force_encoding('ISO-8859-16').valid_encoding?.should be_true
- 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
- 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
- str.force_encoding('IBM775').valid_encoding?.should be_true
- str.force_encoding('CP850').valid_encoding?.should be_true
- str.force_encoding('IBM852').valid_encoding?.should be_true
- str.force_encoding('CP852').valid_encoding?.should be_true
- str.force_encoding('IBM855').valid_encoding?.should be_true
- str.force_encoding('CP855').valid_encoding?.should be_true
- str.force_encoding('IBM857').valid_encoding?.should be_true
- str.force_encoding('IBM860').valid_encoding?.should be_true
- str.force_encoding('IBM861').valid_encoding?.should be_true
- str.force_encoding('IBM862').valid_encoding?.should be_true
- str.force_encoding('IBM863').valid_encoding?.should be_true
- str.force_encoding('IBM864').valid_encoding?.should be_true
- str.force_encoding('IBM865').valid_encoding?.should be_true
- str.force_encoding('IBM866').valid_encoding?.should be_true
- str.force_encoding('IBM869').valid_encoding?.should be_true
- str.force_encoding('Windows-1258').valid_encoding?.should be_true
- str.force_encoding('GB1988').valid_encoding?.should be_true
- str.force_encoding('macCentEuro').valid_encoding?.should be_true
- str.force_encoding('macCroatian').valid_encoding?.should be_true
- str.force_encoding('macCyrillic').valid_encoding?.should be_true
- str.force_encoding('macGreek').valid_encoding?.should be_true
- str.force_encoding('macIceland').valid_encoding?.should be_true
- str.force_encoding('macRoman').valid_encoding?.should be_true
- str.force_encoding('macRomania').valid_encoding?.should be_true
- str.force_encoding('macThai').valid_encoding?.should be_true
- str.force_encoding('macTurkish').valid_encoding?.should be_true
- str.force_encoding('macUkraine').valid_encoding?.should be_true
- str.force_encoding('stateless-ISO-2022-JP').valid_encoding?.should be_false
- str.force_encoding('eucJP-ms').valid_encoding?.should be_false
- str.force_encoding('CP51932').valid_encoding?.should be_false
- str.force_encoding('GB2312').valid_encoding?.should be_false
- str.force_encoding('GB12345').valid_encoding?.should be_false
- str.force_encoding('ISO-2022-JP').valid_encoding?.should be_true
- str.force_encoding('ISO-2022-JP-2').valid_encoding?.should be_true
- str.force_encoding('CP50221').valid_encoding?.should be_true
- str.force_encoding('Windows-1252').valid_encoding?.should be_true
- str.force_encoding('Windows-1250').valid_encoding?.should be_true
- str.force_encoding('Windows-1256').valid_encoding?.should be_true
- str.force_encoding('Windows-1253').valid_encoding?.should be_true
- str.force_encoding('Windows-1255').valid_encoding?.should be_true
- str.force_encoding('Windows-1254').valid_encoding?.should be_true
- str.force_encoding('TIS-620').valid_encoding?.should be_true
- str.force_encoding('Windows-874').valid_encoding?.should be_true
- str.force_encoding('Windows-1257').valid_encoding?.should be_true
- str.force_encoding('Windows-31J').valid_encoding?.should be_false
- str.force_encoding('MacJapanese').valid_encoding?.should be_false
- str.force_encoding('UTF-7').valid_encoding?.should be_true
- str.force_encoding('UTF8-MAC').valid_encoding?.should be_true
+ str.force_encoding('BINARY').valid_encoding?.should == true
+ str.force_encoding('UTF-8').valid_encoding?.should == true
+ str.force_encoding('US-ASCII').valid_encoding?.should == false
+ str.force_encoding('Big5').valid_encoding?.should == false
+ str.force_encoding('CP949').valid_encoding?.should == false
+ str.force_encoding('Emacs-Mule').valid_encoding?.should == false
+ str.force_encoding('EUC-JP').valid_encoding?.should == false
+ str.force_encoding('EUC-KR').valid_encoding?.should == false
+ str.force_encoding('EUC-TW').valid_encoding?.should == false
+ str.force_encoding('GB18030').valid_encoding?.should == false
+ str.force_encoding('GBK').valid_encoding?.should == false
+ str.force_encoding('ISO-8859-1').valid_encoding?.should == true
+ str.force_encoding('ISO-8859-2').valid_encoding?.should == true
+ str.force_encoding('ISO-8859-3').valid_encoding?.should == true
+ str.force_encoding('ISO-8859-4').valid_encoding?.should == true
+ str.force_encoding('ISO-8859-5').valid_encoding?.should == true
+ str.force_encoding('ISO-8859-6').valid_encoding?.should == true
+ str.force_encoding('ISO-8859-7').valid_encoding?.should == true
+ str.force_encoding('ISO-8859-8').valid_encoding?.should == true
+ str.force_encoding('ISO-8859-9').valid_encoding?.should == true
+ str.force_encoding('ISO-8859-10').valid_encoding?.should == true
+ str.force_encoding('ISO-8859-11').valid_encoding?.should == true
+ str.force_encoding('ISO-8859-13').valid_encoding?.should == true
+ str.force_encoding('ISO-8859-14').valid_encoding?.should == true
+ str.force_encoding('ISO-8859-15').valid_encoding?.should == true
+ str.force_encoding('ISO-8859-16').valid_encoding?.should == true
+ str.force_encoding('KOI8-R').valid_encoding?.should == true
+ str.force_encoding('KOI8-U').valid_encoding?.should == true
+ str.force_encoding('Shift_JIS').valid_encoding?.should == false
+ "\xD8\x00".dup.force_encoding('UTF-16BE').valid_encoding?.should == false
+ "\x00\xD8".dup.force_encoding('UTF-16LE').valid_encoding?.should == false
+ "\x04\x03\x02\x01".dup.force_encoding('UTF-32BE').valid_encoding?.should == false
+ "\x01\x02\x03\x04".dup.force_encoding('UTF-32LE').valid_encoding?.should == false
+ str.force_encoding('Windows-1251').valid_encoding?.should == true
+ str.force_encoding('IBM437').valid_encoding?.should == true
+ str.force_encoding('IBM737').valid_encoding?.should == true
+ str.force_encoding('IBM775').valid_encoding?.should == true
+ str.force_encoding('CP850').valid_encoding?.should == true
+ str.force_encoding('IBM852').valid_encoding?.should == true
+ str.force_encoding('CP852').valid_encoding?.should == true
+ str.force_encoding('IBM855').valid_encoding?.should == true
+ str.force_encoding('CP855').valid_encoding?.should == true
+ str.force_encoding('IBM857').valid_encoding?.should == true
+ str.force_encoding('IBM860').valid_encoding?.should == true
+ str.force_encoding('IBM861').valid_encoding?.should == true
+ str.force_encoding('IBM862').valid_encoding?.should == true
+ str.force_encoding('IBM863').valid_encoding?.should == true
+ str.force_encoding('IBM864').valid_encoding?.should == true
+ str.force_encoding('IBM865').valid_encoding?.should == true
+ str.force_encoding('IBM866').valid_encoding?.should == true
+ str.force_encoding('IBM869').valid_encoding?.should == true
+ str.force_encoding('Windows-1258').valid_encoding?.should == true
+ str.force_encoding('GB1988').valid_encoding?.should == true
+ str.force_encoding('macCentEuro').valid_encoding?.should == true
+ str.force_encoding('macCroatian').valid_encoding?.should == true
+ str.force_encoding('macCyrillic').valid_encoding?.should == true
+ str.force_encoding('macGreek').valid_encoding?.should == true
+ str.force_encoding('macIceland').valid_encoding?.should == true
+ str.force_encoding('macRoman').valid_encoding?.should == true
+ str.force_encoding('macRomania').valid_encoding?.should == true
+ str.force_encoding('macThai').valid_encoding?.should == true
+ str.force_encoding('macTurkish').valid_encoding?.should == true
+ str.force_encoding('macUkraine').valid_encoding?.should == true
+ str.force_encoding('stateless-ISO-2022-JP').valid_encoding?.should == false
+ str.force_encoding('eucJP-ms').valid_encoding?.should == false
+ str.force_encoding('CP51932').valid_encoding?.should == false
+ str.force_encoding('GB2312').valid_encoding?.should == false
+ str.force_encoding('GB12345').valid_encoding?.should == false
+ str.force_encoding('ISO-2022-JP').valid_encoding?.should == true
+ str.force_encoding('ISO-2022-JP-2').valid_encoding?.should == true
+ str.force_encoding('CP50221').valid_encoding?.should == true
+ str.force_encoding('Windows-1252').valid_encoding?.should == true
+ str.force_encoding('Windows-1250').valid_encoding?.should == true
+ str.force_encoding('Windows-1256').valid_encoding?.should == true
+ str.force_encoding('Windows-1253').valid_encoding?.should == true
+ str.force_encoding('Windows-1255').valid_encoding?.should == true
+ str.force_encoding('Windows-1254').valid_encoding?.should == true
+ str.force_encoding('TIS-620').valid_encoding?.should == true
+ str.force_encoding('Windows-874').valid_encoding?.should == true
+ str.force_encoding('Windows-1257').valid_encoding?.should == true
+ str.force_encoding('Windows-31J').valid_encoding?.should == false
+ str.force_encoding('MacJapanese').valid_encoding?.should == false
+ str.force_encoding('UTF-7').valid_encoding?.should == true
+ str.force_encoding('UTF8-MAC').valid_encoding?.should == 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
+ str.force_encoding('IBM720').valid_encoding?.should == true
+ str.force_encoding('CP720').valid_encoding?.should == true
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.valid_encoding?.should be_true
+ str.valid_encoding?.should == true
str.force_encoding('ascii')
- str.valid_encoding?.should be_false
+ str.valid_encoding?.should == 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')}".dup.force_encoding('ascii').valid_encoding?.should == false
end
it "returns false if a valid String had an invalid character appended to it" do
str = +"a"
- str.valid_encoding?.should be_true
+ str.valid_encoding?.should == true
str << [0xDD].pack('C').force_encoding('utf-8')
- str.valid_encoding?.should be_false
+ str.valid_encoding?.should == false
end
it "returns true if an invalid string is appended another invalid one but both make a valid string" do
str = [0xD0].pack('C').force_encoding('utf-8')
- str.valid_encoding?.should be_false
+ str.valid_encoding?.should == false
str << [0xBF].pack('C').force_encoding('utf-8')
- str.valid_encoding?.should be_true
+ str.valid_encoding?.should == true
end
end
diff --git a/spec/ruby/core/struct/deconstruct_keys_spec.rb b/spec/ruby/core/struct/deconstruct_keys_spec.rb
index e16b50f930..590e1ab40b 100644
--- a/spec/ruby/core/struct/deconstruct_keys_spec.rb
+++ b/spec/ruby/core/struct/deconstruct_keys_spec.rb
@@ -14,7 +14,7 @@ describe "Struct#deconstruct_keys" do
-> {
obj.deconstruct_keys
- }.should raise_error(ArgumentError, /wrong number of arguments \(given 0, expected 1\)/)
+ }.should.raise(ArgumentError, /wrong number of arguments \(given 0, expected 1\)/)
end
it "returns only specified keys" do
@@ -106,7 +106,7 @@ describe "Struct#deconstruct_keys" do
-> {
s.deconstruct_keys([key])
- }.should raise_error(TypeError, /can't convert MockObject to Integer/)
+ }.should raise_consistent_error(TypeError, /can't convert MockObject into Integer/)
end
it "raises TypeError if index is not a String, a Symbol and not convertible to Integer" do
@@ -115,16 +115,16 @@ describe "Struct#deconstruct_keys" do
-> {
s.deconstruct_keys([0, []])
- }.should raise_error(TypeError, "no implicit conversion of Array into Integer")
+ }.should.raise(TypeError, "no implicit conversion of Array into Integer")
end
it "raise TypeError if passed anything except nil or array" do
struct = Struct.new(:x, :y)
s = struct.new(1, 2)
- -> { s.deconstruct_keys('x') }.should raise_error(TypeError, /expected Array or nil/)
- -> { s.deconstruct_keys(1) }.should raise_error(TypeError, /expected Array or nil/)
- -> { s.deconstruct_keys(:x) }.should raise_error(TypeError, /expected Array or nil/)
- -> { s.deconstruct_keys({}) }.should raise_error(TypeError, /expected Array or nil/)
+ -> { s.deconstruct_keys('x') }.should.raise(TypeError, /expected Array or nil/)
+ -> { s.deconstruct_keys(1) }.should.raise(TypeError, /expected Array or nil/)
+ -> { s.deconstruct_keys(:x) }.should.raise(TypeError, /expected Array or nil/)
+ -> { s.deconstruct_keys({}) }.should.raise(TypeError, /expected Array or nil/)
end
end
diff --git a/spec/ruby/core/struct/deconstruct_spec.rb b/spec/ruby/core/struct/deconstruct_spec.rb
index 32d4f6bac4..aad82ac2ba 100644
--- a/spec/ruby/core/struct/deconstruct_spec.rb
+++ b/spec/ruby/core/struct/deconstruct_spec.rb
@@ -1,10 +1,7 @@
require_relative '../../spec_helper'
describe "Struct#deconstruct" do
- it "returns an array of attribute values" do
- struct = Struct.new(:x, :y)
- s = struct.new(1, 2)
-
- s.deconstruct.should == [1, 2]
+ it "is an alias of Struct#to_a" do
+ Struct.instance_method(:deconstruct).should == Struct.instance_method(:to_a)
end
end
diff --git a/spec/ruby/core/struct/dig_spec.rb b/spec/ruby/core/struct/dig_spec.rb
index 93a52dbbe1..52e4d1dd9a 100644
--- a/spec/ruby/core/struct/dig_spec.rb
+++ b/spec/ruby/core/struct/dig_spec.rb
@@ -32,11 +32,11 @@ describe "Struct#dig" do
instance = @klass.new(1)
-> {
instance.dig(:a, 3)
- }.should raise_error(TypeError)
+ }.should.raise(TypeError)
end
it "raises an ArgumentError if no arguments provided" do
- -> { @instance.dig }.should raise_error(ArgumentError)
+ -> { @instance.dig }.should.raise(ArgumentError)
end
it "calls #dig on any intermediate step with the rest of the sequence as arguments" do
diff --git a/spec/ruby/core/struct/each_pair_spec.rb b/spec/ruby/core/struct/each_pair_spec.rb
index 1230ca9026..db146c81e9 100644
--- a/spec/ruby/core/struct/each_pair_spec.rb
+++ b/spec/ruby/core/struct/each_pair_spec.rb
@@ -21,11 +21,11 @@ describe "Struct#each_pair" do
end
it "returns self if passed a block" do
- @car.each_pair {}.should equal(@car)
+ @car.each_pair {}.should.equal?(@car)
end
it "returns an Enumerator if not passed a block" do
- @car.each_pair.should be_an_instance_of(Enumerator)
+ @car.each_pair.should.instance_of?(Enumerator)
end
it_behaves_like :struct_accessor, :each_pair
diff --git a/spec/ruby/core/struct/each_spec.rb b/spec/ruby/core/struct/each_spec.rb
index 41c0fbd4d0..4fbdfee02a 100644
--- a/spec/ruby/core/struct/each_spec.rb
+++ b/spec/ruby/core/struct/each_spec.rb
@@ -19,7 +19,7 @@ describe "Struct#each" do
it "returns an Enumerator if not passed a block" do
car = StructClasses::Car.new('Ford', 'Ranger')
- car.each.should be_an_instance_of(Enumerator)
+ car.each.should.instance_of?(Enumerator)
end
it_behaves_like :struct_accessor, :each
diff --git a/spec/ruby/core/struct/element_reference_spec.rb b/spec/ruby/core/struct/element_reference_spec.rb
index 0f6d547f66..b94f3aae8c 100644
--- a/spec/ruby/core/struct/element_reference_spec.rb
+++ b/spec/ruby/core/struct/element_reference_spec.rb
@@ -3,7 +3,7 @@ require_relative 'fixtures/classes'
describe "Struct[]" do
it "is a synonym for new" do
- StructClasses::Ruby['2.0', 'i686'].should be_kind_of(StructClasses::Ruby)
+ StructClasses::Ruby['2.0', 'i686'].should.is_a?(StructClasses::Ruby)
end
end
@@ -26,20 +26,20 @@ describe "Struct#[]" do
it "fails when it does not know about the requested attribute" do
car = StructClasses::Car.new('Ford', 'Ranger')
- -> { car[3] }.should raise_error(IndexError)
- -> { car[-4] }.should raise_error(IndexError)
- -> { car[:body] }.should raise_error(NameError)
- -> { car['wheels'] }.should raise_error(NameError)
+ -> { car[3] }.should.raise(IndexError)
+ -> { car[-4] }.should.raise(IndexError)
+ -> { car[:body] }.should.raise(NameError)
+ -> { car['wheels'] }.should.raise(NameError)
end
it "fails if passed too many arguments" do
car = StructClasses::Car.new('Ford', 'Ranger')
- -> { car[:make, :model] }.should raise_error(ArgumentError)
+ -> { car[:make, :model] }.should.raise(ArgumentError)
end
it "fails if not passed a string, symbol, or integer" do
car = StructClasses::Car.new('Ford', 'Ranger')
- -> { car[Object.new] }.should raise_error(TypeError)
+ -> { car[Object.new] }.should.raise(TypeError)
end
it "returns attribute names that contain hyphens" do
diff --git a/spec/ruby/core/struct/element_set_spec.rb b/spec/ruby/core/struct/element_set_spec.rb
index 0a0e34a5ee..e5438ca09a 100644
--- a/spec/ruby/core/struct/element_set_spec.rb
+++ b/spec/ruby/core/struct/element_set_spec.rb
@@ -21,16 +21,16 @@ describe "Struct#[]=" do
it "fails when trying to assign attributes which don't exist" do
car = StructClasses::Car.new('Ford', 'Ranger')
- -> { car[:something] = true }.should raise_error(NameError)
- -> { car[3] = true }.should raise_error(IndexError)
- -> { car[-4] = true }.should raise_error(IndexError)
- -> { car[Object.new] = true }.should raise_error(TypeError)
+ -> { car[:something] = true }.should.raise(NameError)
+ -> { car[3] = true }.should.raise(IndexError)
+ -> { car[-4] = true }.should.raise(IndexError)
+ -> { car[Object.new] = true }.should.raise(TypeError)
end
it "raises a FrozenError on a frozen struct" do
car = StructClasses::Car.new('Ford', 'Ranger')
car.freeze
- -> { car[:model] = 'Escape' }.should raise_error(FrozenError)
+ -> { car[:model] = 'Escape' }.should.raise(FrozenError)
end
end
diff --git a/spec/ruby/core/struct/eql_spec.rb b/spec/ruby/core/struct/eql_spec.rb
index c864b2b943..327c927278 100644
--- a/spec/ruby/core/struct/eql_spec.rb
+++ b/spec/ruby/core/struct/eql_spec.rb
@@ -8,6 +8,6 @@ describe "Struct#eql?" do
it "returns false if any corresponding elements are not #eql?" do
car = StructClasses::Car.new("Honda", "Accord", 1998)
similar_car = StructClasses::Car.new("Honda", "Accord", 1998.0)
- car.should_not eql(similar_car)
+ car.should_not.eql?(similar_car)
end
end
diff --git a/spec/ruby/core/struct/filter_spec.rb b/spec/ruby/core/struct/filter_spec.rb
index 0ccd8ad6b2..5d11f47e6b 100644
--- a/spec/ruby/core/struct/filter_spec.rb
+++ b/spec/ruby/core/struct/filter_spec.rb
@@ -1,10 +1,8 @@
require_relative '../../spec_helper'
-require_relative 'shared/select'
-require_relative 'shared/accessor'
-require_relative '../enumerable/shared/enumeratorized'
+require_relative 'fixtures/classes'
describe "Struct#filter" do
- it_behaves_like :struct_select, :filter
- it_behaves_like :struct_accessor, :filter
- it_behaves_like :enumeratorized_with_origin_size, :filter, Struct.new(:foo).new
+ it "is an alias of Struct#select" do
+ StructClasses::Car.instance_method(:filter).should == StructClasses::Car.instance_method(:select)
+ end
end
diff --git a/spec/ruby/core/struct/fixtures/classes.rb b/spec/ruby/core/struct/fixtures/classes.rb
index 7b80b814ef..675d403abd 100644
--- a/spec/ruby/core/struct/fixtures/classes.rb
+++ b/spec/ruby/core/struct/fixtures/classes.rb
@@ -3,6 +3,7 @@ module StructClasses
class Apple < Struct; end
Ruby = Struct.new(:version, :platform)
+ Single = Struct.new(:value)
Car = Struct.new(:make, :model, :year)
diff --git a/spec/ruby/core/struct/hash_spec.rb b/spec/ruby/core/struct/hash_spec.rb
index 53361eb7a9..750387b326 100644
--- a/spec/ruby/core/struct/hash_spec.rb
+++ b/spec/ruby/core/struct/hash_spec.rb
@@ -8,14 +8,14 @@ describe "Struct#hash" do
[StructClasses::Ruby.new("1.8.6", "PPC"),
StructClasses::Car.new("Hugo", "Foo", "1972")].each do |stc|
stc.hash.should == stc.dup.hash
- stc.hash.should be_kind_of(Integer)
+ stc.hash.should.is_a?(Integer)
end
end
it "returns the same value if structs are #eql?" do
car = StructClasses::Car.new("Honda", "Accord", "1998")
similar_car = StructClasses::Car.new("Honda", "Accord", "1998")
- car.should eql(similar_car)
+ car.should.eql?(similar_car)
car.hash.should == similar_car.hash
end
diff --git a/spec/ruby/core/struct/initialize_spec.rb b/spec/ruby/core/struct/initialize_spec.rb
index 06055594d5..c824f52e13 100644
--- a/spec/ruby/core/struct/initialize_spec.rb
+++ b/spec/ruby/core/struct/initialize_spec.rb
@@ -4,7 +4,7 @@ require_relative 'fixtures/classes'
describe "Struct#initialize" do
it "is private" do
- StructClasses::Car.should have_private_instance_method(:initialize)
+ StructClasses::Car.private_instance_methods(true).should.include?(:initialize)
end
it 'allows valid Ruby method names for members' do
@@ -48,4 +48,27 @@ describe "Struct#initialize" do
positional_args.version.should == keyword_args.version
positional_args.platform.should == keyword_args.platform
end
+
+ it "accepts positional arguments with empty keyword arguments" do
+ data = StructClasses::Single.new(42, **{})
+
+ data.value.should == 42
+
+ data = StructClasses::Ruby.new("3.2", "OS", **{})
+
+ data.version.should == "3.2"
+ data.platform.should == "OS"
+ end
+
+ it "can be called via delegated ... from a prepended module" do
+ wrapper = Module.new do
+ def initialize(...)
+ super(...)
+ end
+ end
+
+ klass = Class.new(Struct.new(:a)) { prepend wrapper }
+ s = klass.new("x")
+ s.a.should == "x"
+ end
end
diff --git a/spec/ruby/core/struct/inspect_spec.rb b/spec/ruby/core/struct/inspect_spec.rb
index 657b06abc1..13fd0bef41 100644
--- a/spec/ruby/core/struct/inspect_spec.rb
+++ b/spec/ruby/core/struct/inspect_spec.rb
@@ -1,7 +1,8 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
-require_relative 'shared/inspect'
describe "Struct#inspect" do
- it_behaves_like :struct_inspect, :inspect
+ it "is an alias of Struct#to_s" do
+ StructClasses::Car.instance_method(:inspect).should == StructClasses::Car.instance_method(:to_s)
+ end
end
diff --git a/spec/ruby/core/struct/instance_variable_get_spec.rb b/spec/ruby/core/struct/instance_variable_get_spec.rb
index e4a3ea87dc..e3555cd246 100644
--- a/spec/ruby/core/struct/instance_variable_get_spec.rb
+++ b/spec/ruby/core/struct/instance_variable_get_spec.rb
@@ -4,7 +4,7 @@ require_relative 'fixtures/classes'
describe "Struct#instance_variable_get" do
it "returns nil for attributes" do
car = StructClasses::Car.new("Hugo", "Foo", "1972")
- car.instance_variable_get(:@make).should be_nil
+ car.instance_variable_get(:@make).should == nil
end
it "returns a user value for variables with the same name as attributes" do
diff --git a/spec/ruby/core/struct/keyword_init_spec.rb b/spec/ruby/core/struct/keyword_init_spec.rb
index 536b82041a..42fcd3cc29 100644
--- a/spec/ruby/core/struct/keyword_init_spec.rb
+++ b/spec/ruby/core/struct/keyword_init_spec.rb
@@ -5,36 +5,36 @@ require_relative 'fixtures/classes'
describe "StructClass#keyword_init?" do
it "returns true for a struct that accepts keyword arguments to initialize" do
struct = Struct.new(:arg, keyword_init: true)
- struct.keyword_init?.should be_true
+ struct.keyword_init?.should == true
end
it "returns false for a struct that does not accept keyword arguments to initialize" do
struct = Struct.new(:arg, keyword_init: false)
- struct.keyword_init?.should be_false
+ struct.keyword_init?.should == false
end
it "returns nil for a struct that did not explicitly specify keyword_init" do
struct = Struct.new(:arg)
- struct.keyword_init?.should be_nil
+ struct.keyword_init?.should == 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
+ struct.keyword_init?.should == 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.keyword_init?.should == true
struct = Struct.new(:arg, keyword_init: "")
- struct.keyword_init?.should be_true
+ struct.keyword_init?.should == true
struct = Struct.new(:arg, keyword_init: [])
- struct.keyword_init?.should be_true
+ struct.keyword_init?.should == true
struct = Struct.new(:arg, keyword_init: {})
- struct.keyword_init?.should be_true
+ struct.keyword_init?.should == true
end
context "class inheriting Struct" do
diff --git a/spec/ruby/core/struct/length_spec.rb b/spec/ruby/core/struct/length_spec.rb
index 1143676122..8d48f4118d 100644
--- a/spec/ruby/core/struct/length_spec.rb
+++ b/spec/ruby/core/struct/length_spec.rb
@@ -1,12 +1,8 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
-require_relative 'shared/accessor'
describe "Struct#length" do
- it "returns the number of attributes" do
- StructClasses::Car.new('Cadillac', 'DeVille').length.should == 3
- StructClasses::Car.new.length.should == 3
+ it "is an alias of Struct#size" do
+ StructClasses::Car.instance_method(:length).should == StructClasses::Car.instance_method(:size)
end
-
- it_behaves_like :struct_accessor, :length
end
diff --git a/spec/ruby/core/struct/new_spec.rb b/spec/ruby/core/struct/new_spec.rb
index 1d35de7b87..b3ece2efed 100644
--- a/spec/ruby/core/struct/new_spec.rb
+++ b/spec/ruby/core/struct/new_spec.rb
@@ -38,19 +38,19 @@ describe "Struct.new" do
it "creates a new anonymous class with nil first argument" do
struct = Struct.new(nil, :foo)
struct.new("bar").foo.should == "bar"
- struct.should be_kind_of(Class)
- struct.name.should be_nil
+ struct.should.is_a?(Class)
+ struct.name.should == nil
end
it "creates a new anonymous class with symbol arguments" do
struct = Struct.new(:make, :model)
- struct.should be_kind_of(Class)
+ struct.should.is_a?(Class)
struct.name.should == nil
end
it "does not create a constant with symbol as first argument" do
Struct.new(:Animal2, :name, :legs, :eyeballs)
- Struct.const_defined?("Animal2").should be_false
+ Struct.const_defined?("Animal2").should == false
end
it "allows non-ASCII member name" do
@@ -60,50 +60,42 @@ describe "Struct.new" do
end
it "fails with invalid constant name as first argument" do
- -> { Struct.new('animal', :name, :legs, :eyeballs) }.should raise_error(NameError)
+ -> { Struct.new('animal', :name, :legs, :eyeballs) }.should.raise(NameError)
end
it "raises a TypeError if object doesn't respond to to_sym" do
- -> { Struct.new(:animal, mock('giraffe')) }.should raise_error(TypeError)
- -> { Struct.new(:animal, 1.0) }.should raise_error(TypeError)
- -> { Struct.new(:animal, Time.now) }.should raise_error(TypeError)
- -> { Struct.new(:animal, Class) }.should raise_error(TypeError)
- -> { Struct.new(:animal, nil) }.should raise_error(TypeError)
- -> { Struct.new(:animal, true) }.should raise_error(TypeError)
- -> { Struct.new(:animal, ['chris', 'evan']) }.should raise_error(TypeError)
+ -> { Struct.new(:animal, mock('giraffe')) }.should.raise(TypeError)
+ -> { Struct.new(:animal, 1.0) }.should.raise(TypeError)
+ -> { Struct.new(:animal, Time.now) }.should.raise(TypeError)
+ -> { Struct.new(:animal, Class) }.should.raise(TypeError)
+ -> { Struct.new(:animal, nil) }.should.raise(TypeError)
+ -> { Struct.new(:animal, true) }.should.raise(TypeError)
+ -> { Struct.new(:animal, ['chris', 'evan']) }.should.raise(TypeError)
end
it "raises a TypeError if passed a Hash with an unknown key" do
- -> { Struct.new(:animal, { name: 'chris' }) }.should raise_error(TypeError)
+ -> { Struct.new(:animal, { name: 'chris' }) }.should.raise(TypeError)
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
+ it "works when not provided any arguments" do
+ c = Struct.new
+ c.should.is_a?(Class)
+ c.superclass.should == Struct
end
it "raises ArgumentError when there is a duplicate member" do
- -> { Struct.new(:foo, :foo) }.should raise_error(ArgumentError, "duplicate member: foo")
+ -> { Struct.new(:foo, :foo) }.should.raise(ArgumentError, "duplicate member: foo")
end
it "raises a TypeError if object is not a Symbol" do
obj = mock(':ruby')
def obj.to_sym() :ruby end
- -> { Struct.new(:animal, obj) }.should raise_error(TypeError)
+ -> { Struct.new(:animal, obj) }.should.raise(TypeError)
end
it "processes passed block with instance_eval" do
klass = Struct.new(:something) { @something_else = 'something else entirely!' }
- klass.instance_variables.should include(:@something_else)
+ klass.instance_variables.should.include?(:@something_else)
end
context "with a block" do
@@ -124,7 +116,7 @@ describe "Struct.new" do
klass = Struct.new(:attr) do |block_parameter|
given = block_parameter
end
- klass.should equal(given)
+ klass.should.equal?(given)
end
end
@@ -141,17 +133,17 @@ describe "Struct.new" do
end
it "creates reader methods" do
- StructClasses::Ruby.new.should have_method(:version)
- StructClasses::Ruby.new.should have_method(:platform)
+ StructClasses::Ruby.new.should.respond_to?(:version)
+ StructClasses::Ruby.new.should.respond_to?(:platform)
end
it "creates writer methods" do
- StructClasses::Ruby.new.should have_method(:version=)
- StructClasses::Ruby.new.should have_method(:platform=)
+ StructClasses::Ruby.new.should.respond_to?(:version=)
+ StructClasses::Ruby.new.should.respond_to?(:platform=)
end
it "fails with too many arguments" do
- -> { StructClasses::Ruby.new('2.0', 'i686', true) }.should raise_error(ArgumentError)
+ -> { StructClasses::Ruby.new('2.0', 'i686', true) }.should.raise(ArgumentError)
end
it "accepts keyword arguments to initialize" do
@@ -190,7 +182,7 @@ describe "Struct.new" do
it "raises ArgumentError when all struct attribute values are specified" do
type = Struct.new(:a, :b)
- -> { type.new("a", "b", c: "c") }.should raise_error(ArgumentError, "struct size differs")
+ -> { type.new("a", "b", c: "c") }.should.raise(ArgumentError, "struct size differs")
end
end
end
@@ -207,7 +199,7 @@ describe "Struct.new" do
end
it "raises when there is a duplicate member" do
- -> { Struct.new(:foo, :foo, keyword_init: true) }.should raise_error(ArgumentError, "duplicate member: foo")
+ -> { Struct.new(:foo, :foo, keyword_init: true) }.should.raise(ArgumentError, "duplicate member: foo")
end
describe "new class instantiation" do
@@ -220,31 +212,31 @@ describe "Struct.new" do
it "allows missing arguments" do
obj = @struct_with_kwa.new(name: "elefant")
obj.name.should == "elefant"
- obj.legs.should be_nil
+ obj.legs.should == nil
end
it "allows no arguments" do
obj = @struct_with_kwa.new
- obj.name.should be_nil
- obj.legs.should be_nil
+ obj.name.should == nil
+ obj.legs.should == nil
end
it "raises ArgumentError when passed not declared keyword argument" do
-> {
@struct_with_kwa.new(name: "elefant", legs: 4, foo: "bar")
- }.should raise_error(ArgumentError, /unknown keywords: foo/)
+ }.should.raise(ArgumentError, /unknown keywords: foo/)
end
it "raises ArgumentError when passed a list of arguments" do
-> {
@struct_with_kwa.new("elefant", 4)
- }.should raise_error(ArgumentError, /wrong number of arguments/)
+ }.should.raise(ArgumentError, /wrong number of arguments/)
end
it "raises ArgumentError when passed a single non-hash argument" do
-> {
@struct_with_kwa.new("elefant")
- }.should raise_error(ArgumentError, /wrong number of arguments/)
+ }.should.raise(ArgumentError, /wrong number of arguments/)
end
end
end
diff --git a/spec/ruby/core/struct/select_spec.rb b/spec/ruby/core/struct/select_spec.rb
index ee846ec45f..5f26a177eb 100644
--- a/spec/ruby/core/struct/select_spec.rb
+++ b/spec/ruby/core/struct/select_spec.rb
@@ -1,10 +1,31 @@
require_relative '../../spec_helper'
-require_relative 'shared/select'
+require_relative 'fixtures/classes'
require_relative 'shared/accessor'
require_relative '../enumerable/shared/enumeratorized'
describe "Struct#select" do
- it_behaves_like :struct_select, :select
it_behaves_like :struct_accessor, :select
it_behaves_like :enumeratorized_with_origin_size, :select, Struct.new(:foo).new
+
+ it "raises an ArgumentError if given any non-block arguments" do
+ struct = StructClasses::Car.new
+ -> { struct.select(1) { } }.should.raise(ArgumentError)
+ end
+
+ it "returns a new array of elements for which block is true" do
+ struct = StructClasses::Car.new("Toyota", "Tercel", "2000")
+ struct.select { |i| i == "2000" }.should == [ "2000" ]
+ end
+
+ it "returns an instance of Array" do
+ struct = StructClasses::Car.new("Ford", "Escort", "1995")
+ struct.select { true }.should.instance_of?(Array)
+ end
+
+ describe "without block" do
+ it "returns an instance of Enumerator" do
+ struct = Struct.new(:foo).new
+ struct.select.should.instance_of?(Enumerator)
+ end
+ end
end
diff --git a/spec/ruby/core/struct/shared/inspect.rb b/spec/ruby/core/struct/shared/inspect.rb
deleted file mode 100644
index 1a0fb6a6b2..0000000000
--- a/spec/ruby/core/struct/shared/inspect.rb
+++ /dev/null
@@ -1,40 +0,0 @@
-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/shared/select.rb b/spec/ruby/core/struct/shared/select.rb
deleted file mode 100644
index 35abee461b..0000000000
--- a/spec/ruby/core/struct/shared/select.rb
+++ /dev/null
@@ -1,26 +0,0 @@
-require_relative '../../../spec_helper'
-require_relative '../fixtures/classes'
-
-describe :struct_select, shared: true do
- it "raises an ArgumentError if given any non-block arguments" do
- struct = StructClasses::Car.new
- -> { struct.send(@method, 1) { } }.should raise_error(ArgumentError)
- end
-
- it "returns a new array of elements for which block is true" do
- struct = StructClasses::Car.new("Toyota", "Tercel", "2000")
- struct.send(@method) { |i| i == "2000" }.should == [ "2000" ]
- end
-
- it "returns an instance of Array" do
- struct = StructClasses::Car.new("Ford", "Escort", "1995")
- struct.send(@method) { true }.should be_an_instance_of(Array)
- end
-
- describe "without block" do
- it "returns an instance of Enumerator" do
- struct = Struct.new(:foo).new
- struct.send(@method).should be_an_instance_of(Enumerator)
- end
- end
-end
diff --git a/spec/ruby/core/struct/size_spec.rb b/spec/ruby/core/struct/size_spec.rb
index 09f260cf20..5f07320bb9 100644
--- a/spec/ruby/core/struct/size_spec.rb
+++ b/spec/ruby/core/struct/size_spec.rb
@@ -3,8 +3,9 @@ require_relative 'fixtures/classes'
require_relative 'shared/accessor'
describe "Struct#size" do
- it "is a synonym for length" do
- StructClasses::Car.new.size.should == StructClasses::Car.new.length
+ it "returns the number of attributes" do
+ StructClasses::Car.new('Cadillac', 'DeVille').length.should == 3
+ StructClasses::Car.new.length.should == 3
end
it_behaves_like :struct_accessor, :size
diff --git a/spec/ruby/core/struct/struct_spec.rb b/spec/ruby/core/struct/struct_spec.rb
index 1b6a4488ce..9fab9c0629 100644
--- a/spec/ruby/core/struct/struct_spec.rb
+++ b/spec/ruby/core/struct/struct_spec.rb
@@ -21,7 +21,7 @@ describe "Struct anonymous class instance methods" do
it "reader method should not interfere with undefined methods" do
car = StructClasses::Car.new('Ford', 'Ranger')
- -> { car.something_weird }.should raise_error(NoMethodError)
+ -> { car.something_weird }.should.raise(NoMethodError)
end
it "writer method be a synonym for []=" do
@@ -38,7 +38,7 @@ describe "Struct anonymous class instance methods" do
car = StructClasses::Car.new('Ford', 'Ranger')
car.freeze
- -> { car.model = 'Escape' }.should raise_error(FrozenError)
+ -> { car.model = 'Escape' }.should.raise(FrozenError)
end
end
diff --git a/spec/ruby/core/struct/to_h_spec.rb b/spec/ruby/core/struct/to_h_spec.rb
index 861ce3f49d..e0846ef268 100644
--- a/spec/ruby/core/struct/to_h_spec.rb
+++ b/spec/ruby/core/struct/to_h_spec.rb
@@ -36,17 +36,17 @@ describe "Struct#to_h" do
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] }
- end.should raise_error(ArgumentError, /element has wrong array length/)
+ end.should.raise(ArgumentError, /element has wrong array length/)
-> do
StructClasses::Car.new.to_h { |k, v| [k] }
- end.should raise_error(ArgumentError, /element has wrong array length/)
+ end.should.raise(ArgumentError, /element has wrong array length/)
end
it "raises TypeError if block returns something other than Array" do
-> do
StructClasses::Car.new.to_h { |k, v| "not-array" }
- end.should raise_error(TypeError, /wrong element type String/)
+ end.should.raise(TypeError, /wrong element type String/)
end
it "coerces returned pair to Array with #to_ary" do
@@ -62,7 +62,7 @@ describe "Struct#to_h" do
-> do
StructClasses::Car.new.to_h { |k| x }
- end.should raise_error(TypeError, /wrong element type MockObject/)
+ end.should.raise(TypeError, /wrong element type MockObject/)
end
end
end
diff --git a/spec/ruby/core/struct/to_s_spec.rb b/spec/ruby/core/struct/to_s_spec.rb
index 94c672d3d5..9648b8af9b 100644
--- a/spec/ruby/core/struct/to_s_spec.rb
+++ b/spec/ruby/core/struct/to_s_spec.rb
@@ -1,12 +1,43 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
-require_relative 'shared/inspect'
describe "Struct#to_s" do
- it "is a synonym for inspect" do
+ it "returns a string representation showing members and values" do
car = StructClasses::Car.new('Ford', 'Ranger')
- car.inspect.should == car.to_s
+ car.to_s.should == '#<struct StructClasses::Car make="Ford", model="Ranger", year=nil>'
end
- it_behaves_like :struct_inspect, :to_s
+ it "returns a string representation without the class name for anonymous structs" do
+ Struct.new(:a).new("").to_s.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("").to_s.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("").to_s.should == '#<struct a="">'
+ end
+
+ it "does not call #name method" do
+ struct = StructClasses::StructWithOverriddenName.new("")
+ struct.to_s.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("").to_s.should == '#<struct a="">'
+ end
end
diff --git a/spec/ruby/core/struct/values_at_spec.rb b/spec/ruby/core/struct/values_at_spec.rb
index 5e5a496600..6aac5d96b3 100644
--- a/spec/ruby/core/struct/values_at_spec.rb
+++ b/spec/ruby/core/struct/values_at_spec.rb
@@ -14,8 +14,8 @@ describe "Struct#values_at" do
end
it "raises IndexError if any of integers is out of range" do
- -> { @movie.values_at(3) }.should raise_error(IndexError, "offset 3 too large for struct(size:3)")
- -> { @movie.values_at(-4) }.should raise_error(IndexError, "offset -4 too small for struct(size:3)")
+ -> { @movie.values_at(3) }.should.raise(IndexError, "offset 3 too large for struct(size:3)")
+ -> { @movie.values_at(-4) }.should.raise(IndexError, "offset -4 too small for struct(size:3)")
end
end
@@ -29,7 +29,7 @@ describe "Struct#values_at" do
end
it "raises RangeError if any element of the range is negative and out of range" do
- -> { @movie.values_at(-4..3) }.should raise_error(RangeError, "-4..3 out of range")
+ -> { @movie.values_at(-4..3) }.should.raise(RangeError, "-4..3 out of range")
end
it "supports endless Range" do
@@ -54,6 +54,6 @@ describe "Struct#values_at" do
end
it "fails when passed unsupported types" do
- -> { @movie.values_at('make') }.should raise_error(TypeError, "no implicit conversion of String into Integer")
+ -> { @movie.values_at('make') }.should.raise(TypeError, "no implicit conversion of String into Integer")
end
end
diff --git a/spec/ruby/core/struct/values_spec.rb b/spec/ruby/core/struct/values_spec.rb
index b2d11725b9..16583253d7 100644
--- a/spec/ruby/core/struct/values_spec.rb
+++ b/spec/ruby/core/struct/values_spec.rb
@@ -2,10 +2,7 @@ require_relative '../../spec_helper'
require_relative 'fixtures/classes'
describe "Struct#values" do
- it "is a synonym for to_a" do
- car = StructClasses::Car.new('Nissan', 'Maxima')
- car.values.should == car.to_a
-
- StructClasses::Car.new.values.should == StructClasses::Car.new.to_a
+ it "is an alias of Struct#to_a" do
+ StructClasses::Car.instance_method(:values).should == StructClasses::Car.instance_method(:to_a)
end
end
diff --git a/spec/ruby/core/symbol/all_symbols_spec.rb b/spec/ruby/core/symbol/all_symbols_spec.rb
index 1e21809093..689f6211de 100644
--- a/spec/ruby/core/symbol/all_symbols_spec.rb
+++ b/spec/ruby/core/symbol/all_symbols_spec.rb
@@ -3,17 +3,17 @@ require_relative '../../spec_helper'
describe "Symbol.all_symbols" do
it "returns an array of Symbols" do
all_symbols = Symbol.all_symbols
- all_symbols.should be_an_instance_of(Array)
- all_symbols.each { |s| s.should be_an_instance_of(Symbol) }
+ all_symbols.should.instance_of?(Array)
+ all_symbols.each { |s| s.should.instance_of?(Symbol) }
end
it "includes symbols that are strongly referenced" do
symbol = "symbol_specs_#{rand(5_000_000)}".to_sym
- Symbol.all_symbols.should include(symbol)
+ Symbol.all_symbols.should.include?(symbol)
end
it "includes symbols that are referenced in source code but not yet executed" do
- Symbol.all_symbols.any? { |s| s.to_s == 'symbol_specs_referenced_in_source_code' }.should be_true
+ Symbol.all_symbols.any? { |s| s.to_s == 'symbol_specs_referenced_in_source_code' }.should == true
:symbol_specs_referenced_in_source_code
end
end
diff --git a/spec/ruby/core/symbol/capitalize_spec.rb b/spec/ruby/core/symbol/capitalize_spec.rb
index a84bcf280a..a93d951e6a 100644
--- a/spec/ruby/core/symbol/capitalize_spec.rb
+++ b/spec/ruby/core/symbol/capitalize_spec.rb
@@ -3,7 +3,7 @@ require_relative '../../spec_helper'
describe "Symbol#capitalize" do
it "returns a Symbol" do
- :glark.capitalize.should be_an_instance_of(Symbol)
+ :glark.capitalize.should.instance_of?(Symbol)
end
it "converts the first character to uppercase if it is ASCII" do
diff --git a/spec/ruby/core/symbol/case_compare_spec.rb b/spec/ruby/core/symbol/case_compare_spec.rb
index 0c6bc1eda5..a296132c04 100644
--- a/spec/ruby/core/symbol/case_compare_spec.rb
+++ b/spec/ruby/core/symbol/case_compare_spec.rb
@@ -1,11 +1,7 @@
require_relative '../../spec_helper'
describe "Symbol#===" do
- it "returns true when the argument is a Symbol" do
- (Symbol === :ruby).should == true
- end
-
- it "returns false when the argument is a String" do
- (Symbol === 'ruby').should == false
+ it "is an alias of Symbol#==" do
+ Symbol.instance_method(:===).should == Symbol.instance_method(:==)
end
end
diff --git a/spec/ruby/core/symbol/casecmp_spec.rb b/spec/ruby/core/symbol/casecmp_spec.rb
index 662a29a284..dcb77a8350 100644
--- a/spec/ruby/core/symbol/casecmp_spec.rb
+++ b/spec/ruby/core/symbol/casecmp_spec.rb
@@ -64,16 +64,16 @@ end
describe "Symbol#casecmp" do
it "returns nil if other is a String" do
- :abc.casecmp("abc").should be_nil
+ :abc.casecmp("abc").should == nil
end
it "returns nil if other is an Integer" do
- :abc.casecmp(1).should be_nil
+ :abc.casecmp(1).should == nil
end
it "returns nil if other is an object" do
obj = mock("string <=>")
- :abc.casecmp(obj).should be_nil
+ :abc.casecmp(obj).should == nil
end
end
diff --git a/spec/ruby/core/symbol/comparison_spec.rb b/spec/ruby/core/symbol/comparison_spec.rb
index 613177be05..6d56176e97 100644
--- a/spec/ruby/core/symbol/comparison_spec.rb
+++ b/spec/ruby/core/symbol/comparison_spec.rb
@@ -37,15 +37,15 @@ end
describe "Symbol#<=>" do
it "returns nil if other is a String" do
- (:abc <=> "abc").should be_nil
+ (:abc <=> "abc").should == nil
end
it "returns nil if other is an Integer" do
- (:abc <=> 1).should be_nil
+ (:abc <=> 1).should == nil
end
it "returns nil if other is an object" do
obj = mock("string <=>")
- (:abc <=> obj).should be_nil
+ (:abc <=> obj).should == nil
end
end
diff --git a/spec/ruby/core/symbol/downcase_spec.rb b/spec/ruby/core/symbol/downcase_spec.rb
index 7e94c669cc..76418aa9da 100644
--- a/spec/ruby/core/symbol/downcase_spec.rb
+++ b/spec/ruby/core/symbol/downcase_spec.rb
@@ -3,7 +3,7 @@ require_relative '../../spec_helper'
describe "Symbol#downcase" do
it "returns a Symbol" do
- :glark.downcase.should be_an_instance_of(Symbol)
+ :glark.downcase.should.instance_of?(Symbol)
end
it "converts uppercase ASCII characters to their lowercase equivalents" do
diff --git a/spec/ruby/core/symbol/dup_spec.rb b/spec/ruby/core/symbol/dup_spec.rb
index 8b35917c27..eef3078030 100644
--- a/spec/ruby/core/symbol/dup_spec.rb
+++ b/spec/ruby/core/symbol/dup_spec.rb
@@ -2,6 +2,6 @@ require_relative '../../spec_helper'
describe "Symbol#dup" do
it "returns self" do
- :a_symbol.dup.should equal(:a_symbol)
+ :a_symbol.dup.should.equal?(:a_symbol)
end
end
diff --git a/spec/ruby/core/symbol/element_reference_spec.rb b/spec/ruby/core/symbol/element_reference_spec.rb
index df6bc15ddb..360a661891 100644
--- a/spec/ruby/core/symbol/element_reference_spec.rb
+++ b/spec/ruby/core/symbol/element_reference_spec.rb
@@ -1,6 +1,263 @@
require_relative '../../spec_helper'
-require_relative 'shared/slice'
+require_relative 'fixtures/classes'
describe "Symbol#[]" do
- it_behaves_like :symbol_slice, :[]
+ describe "with an Integer index" do
+ it "returns the character code of the element at the index" do
+ :symbol[1].should == ?y
+ end
+
+ it "returns nil if the index starts from the end and is greater than the length" do
+ :symbol[-10].should == nil
+ end
+
+ it "returns nil if the index is greater than the length" do
+ :symbol[42].should == nil
+ end
+ end
+
+ describe "with an Integer index and length" do
+ describe "and a positive index and length" do
+ it "returns a slice" do
+ :symbol[1, 3].should == "ymb"
+ end
+
+ it "returns a blank slice if the length is 0" do
+ :symbol[0, 0].should == ""
+ :symbol[1, 0].should == ""
+ end
+
+ it "returns a slice of all remaining characters if the given length is greater than the actual length" do
+ :symbol[1, 100].should == "ymbol"
+ end
+
+ it "returns nil if the index is greater than the length" do
+ :symbol[10, 1].should == nil
+ end
+ end
+
+ describe "and a positive index and negative length" do
+ it "returns nil" do
+ :symbol[0, -1].should == nil
+ :symbol[1, -1].should == nil
+ end
+ end
+
+ describe "and a negative index and positive length" do
+ it "returns a slice starting from the end upto the length" do
+ :symbol[-3, 2].should == "bo"
+ end
+
+ it "returns a blank slice if the length is 0" do
+ :symbol[-1, 0].should == ""
+ end
+
+ it "returns a slice of all remaining characters if the given length is larger than the actual length" do
+ :symbol[-4, 100].should == "mbol"
+ end
+
+ it "returns nil if the index is past the start" do
+ :symbol[-10, 1].should == nil
+ end
+ end
+
+ describe "and a negative index and negative length" do
+ it "returns nil" do
+ :symbol[-1, -1].should == nil
+ end
+ end
+
+ describe "and a Float length" do
+ it "converts the length to an Integer" do
+ :symbol[2, 2.5].should == "mb"
+ end
+ end
+
+ describe "and a nil length" do
+ it "raises a TypeError" do
+ -> { :symbol[1, nil] }.should.raise(TypeError)
+ end
+ end
+
+ describe "and a length that cannot be converted into an Integer" do
+ it "raises a TypeError when given an Array" do
+ -> { :symbol[1, Array.new] }.should.raise(TypeError)
+ end
+
+ it "raises a TypeError when given an Hash" do
+ -> { :symbol[1, Hash.new] }.should.raise(TypeError)
+ end
+
+ it "raises a TypeError when given an Object" do
+ -> { :symbol[1, Object.new] }.should.raise(TypeError)
+ end
+ end
+ end
+
+ describe "with a Float index" do
+ it "converts the index to an Integer" do
+ :symbol[1.5].should == ?y
+ end
+ end
+
+ describe "with a nil index" do
+ it "raises a TypeError" do
+ -> { :symbol[nil] }.should.raise(TypeError)
+ end
+ end
+
+ describe "with an index that cannot be converted into an Integer" do
+ it "raises a TypeError when given an Array" do
+ -> { :symbol[Array.new] }.should.raise(TypeError)
+ end
+
+ it "raises a TypeError when given an Hash" do
+ -> { :symbol[Hash.new] }.should.raise(TypeError)
+ end
+
+ it "raises a TypeError when given an Object" do
+ -> { :symbol[Object.new] }.should.raise(TypeError)
+ end
+ end
+
+ describe "with a Range slice" do
+ describe "that is within bounds" do
+ it "returns a slice if both range values begin at the start and are within bounds" do
+ :symbol[1..4].should == "ymbo"
+ end
+
+ it "returns a slice if the first range value begins at the start and the last begins at the end" do
+ :symbol[1..-1].should == "ymbol"
+ end
+
+ it "returns a slice if the first range value begins at the end and the last begins at the end" do
+ :symbol[-4..-1].should == "mbol"
+ end
+ end
+
+ describe "that is out of bounds" do
+ it "returns nil if the first range value begins past the end" do
+ :symbol[10..12].should == nil
+ end
+
+ it "returns a blank string if the first range value is within bounds and the last range value is not" do
+ :symbol[-2..-10].should == ""
+ :symbol[2..-10].should == ""
+ end
+
+ it "returns nil if the first range value starts from the end and is within bounds and the last value starts from the end and is greater than the length" do
+ :symbol[-10..-12].should == nil
+ end
+
+ it "returns nil if the first range value starts from the end and is out of bounds and the last value starts from the end and is less than the length" do
+ :symbol[-10..-2].should == nil
+ end
+ end
+
+ describe "with Float values" do
+ it "converts the first value to an Integer" do
+ :symbol[0.5..2].should == "sym"
+ end
+
+ it "converts the last value to an Integer" do
+ :symbol[0..2.5].should == "sym"
+ end
+ end
+ end
+
+ describe "with a Range subclass slice" do
+ it "returns a slice" do
+ range = SymbolSpecs::MyRange.new(1, 4)
+ :symbol[range].should == "ymbo"
+ end
+ end
+
+ describe "with a Regex slice" do
+ describe "without a capture index" do
+ it "returns a string of the match" do
+ :symbol[/[^bol]+/].should == "sym"
+ end
+
+ it "returns nil if the expression does not match" do
+ :symbol[/0-9/].should == nil
+ end
+
+ it "sets $~ to the MatchData if there is a match" do
+ :symbol[/[^bol]+/]
+ $~[0].should == "sym"
+ end
+
+ it "does not set $~ if there if there is not a match" do
+ :symbol[/[0-9]+/]
+ $~.should == nil
+ end
+ end
+
+ describe "with a capture index" do
+ it "returns a string of the complete match if the capture index is 0" do
+ :symbol[/(sy)(mb)(ol)/, 0].should == "symbol"
+ end
+
+ it "returns a string for the matched capture at the given index" do
+ :symbol[/(sy)(mb)(ol)/, 1].should == "sy"
+ :symbol[/(sy)(mb)(ol)/, -1].should == "ol"
+ end
+
+ it "returns nil if there is no capture for the index" do
+ :symbol[/(sy)(mb)(ol)/, 4].should == nil
+ :symbol[/(sy)(mb)(ol)/, -4].should == nil
+ end
+
+ it "converts the index to an Integer" do
+ :symbol[/(sy)(mb)(ol)/, 1.5].should == "sy"
+ end
+
+ describe "and an index that cannot be converted to an Integer" do
+ it "raises a TypeError when given an Hash" do
+ -> { :symbol[/(sy)(mb)(ol)/, Hash.new] }.should.raise(TypeError)
+ end
+
+ it "raises a TypeError when given an Array" do
+ -> { :symbol[/(sy)(mb)(ol)/, Array.new] }.should.raise(TypeError)
+ end
+
+ it "raises a TypeError when given an Object" do
+ -> { :symbol[/(sy)(mb)(ol)/, Object.new] }.should.raise(TypeError)
+ end
+ end
+
+ it "raises a TypeError if the index is nil" do
+ -> { :symbol[/(sy)(mb)(ol)/, nil] }.should.raise(TypeError)
+ end
+
+ it "sets $~ to the MatchData if there is a match" do
+ :symbol[/(sy)(mb)(ol)/, 0]
+ $~[0].should == "symbol"
+ $~[1].should == "sy"
+ $~[2].should == "mb"
+ $~[3].should == "ol"
+ end
+
+ it "does not set $~ to the MatchData if there is not a match" do
+ :symbol[/0-9/, 0]
+ $~.should == nil
+ end
+ end
+ end
+
+ describe "with a String slice" do
+ it "does not set $~" do
+ $~ = nil
+ :symbol["sym"]
+ $~.should == nil
+ end
+
+ it "returns a string if there is match" do
+ :symbol["ymb"].should == "ymb"
+ end
+
+ it "returns nil if there is not a match" do
+ :symbol["foo"].should == nil
+ end
+ end
end
diff --git a/spec/ruby/core/symbol/empty_spec.rb b/spec/ruby/core/symbol/empty_spec.rb
index 19c23cfe5f..1d90a59a5b 100644
--- a/spec/ruby/core/symbol/empty_spec.rb
+++ b/spec/ruby/core/symbol/empty_spec.rb
@@ -2,10 +2,10 @@ require_relative '../../spec_helper'
describe "Symbol#empty?" do
it "returns true if self is empty" do
- :"".empty?.should be_true
+ :"".empty?.should == true
end
it "returns false if self is non-empty" do
- :"a".empty?.should be_false
+ :"a".empty?.should == false
end
end
diff --git a/spec/ruby/core/symbol/id2name_spec.rb b/spec/ruby/core/symbol/id2name_spec.rb
index 2caa89fc37..abcbff65f4 100644
--- a/spec/ruby/core/symbol/id2name_spec.rb
+++ b/spec/ruby/core/symbol/id2name_spec.rb
@@ -1,6 +1,7 @@
require_relative '../../spec_helper'
-require_relative 'shared/id2name'
describe "Symbol#id2name" do
- it_behaves_like :symbol_id2name, :id2name
+ it "is an alias of Symbol#to_s" do
+ Symbol.instance_method(:id2name).should == Symbol.instance_method(:to_s)
+ end
end
diff --git a/spec/ruby/core/symbol/inspect_spec.rb b/spec/ruby/core/symbol/inspect_spec.rb
index 6dbb36c2ad..f2269996af 100644
--- a/spec/ruby/core/symbol/inspect_spec.rb
+++ b/spec/ruby/core/symbol/inspect_spec.rb
@@ -6,7 +6,7 @@ describe "Symbol#inspect" do
:fred? => ":fred?",
:fred! => ":fred!",
:BAD! => ":BAD!",
- :_BAD! => ":_BAD!",
+ :_BAD! => ":_BAD!",
:$ruby => ":$ruby",
:@ruby => ":@ruby",
:@@ruby => ":@@ruby",
@@ -66,9 +66,9 @@ describe "Symbol#inspect" do
:~ => ":~",
:| => ":|",
- :"!" => [":\"!\"", ":!" ],
- :"!=" => [":\"!=\"", ":!="],
- :"!~" => [":\"!~\"", ":!~"],
+ :"!" => ":!",
+ :"!=" => ":!=",
+ :"!~" => ":!~",
:"\$" => ":\"$\"", # for justice!
:"&&" => ":\"&&\"",
:"'" => ":\"\'\"",
@@ -96,12 +96,36 @@ describe "Symbol#inspect" do
:"foo " => ":\"foo \"",
:" foo" => ":\" foo\"",
:" " => ":\" \"",
+
+ :"ê" => [":ê", ":\"\\u00EA\""],
+ :"测" => [":测", ":\"\\u6D4B\""],
+ :"🦊" => [":🦊", ":\"\\u{1F98A}\""],
}
+ expected_by_encoding = Encoding::default_external == Encoding::UTF_8 ? 0 : 1
symbols.each do |input, expected|
- expected = expected[1] if expected.is_a?(Array)
+ expected = expected[expected_by_encoding] if expected.is_a?(Array)
it "returns self as a symbol literal for #{expected}" do
input.inspect.should == expected
end
end
+
+ it "quotes BINARY symbols" do
+ sym = "foo\xA4".b.to_sym
+ sym.inspect.should == ':"foo\xA4"'
+ end
+
+ it "quotes symbols in non-ASCII-compatible encodings" do
+ Encoding.list.reject(&:ascii_compatible?).reject(&:dummy?).each do |encoding|
+ sym = "foo".encode(encoding).to_sym
+ sym.inspect.should == ':"foo"'
+ end
+ end
+
+ it "quotes and escapes symbols in dummy encodings" do
+ Encoding.list.select(&:dummy?).each do |encoding|
+ sym = "abcd".dup.force_encoding(encoding).to_sym
+ sym.inspect.should == ':"\x61\x62\x63\x64"'
+ end
+ end
end
diff --git a/spec/ruby/core/symbol/intern_spec.rb b/spec/ruby/core/symbol/intern_spec.rb
index ea04b87e8a..746d313d40 100644
--- a/spec/ruby/core/symbol/intern_spec.rb
+++ b/spec/ruby/core/symbol/intern_spec.rb
@@ -1,11 +1,7 @@
require_relative '../../spec_helper'
describe "Symbol#intern" do
- it "returns self" do
- :foo.intern.should == :foo
- end
-
- it "returns a Symbol" do
- :foo.intern.should be_kind_of(Symbol)
+ it "is an alias of Symbol#to_sym" do
+ Symbol.instance_method(:intern).should == Symbol.instance_method(:to_sym)
end
end
diff --git a/spec/ruby/core/symbol/length_spec.rb b/spec/ruby/core/symbol/length_spec.rb
index 27bee575ef..29dd4ad46b 100644
--- a/spec/ruby/core/symbol/length_spec.rb
+++ b/spec/ruby/core/symbol/length_spec.rb
@@ -1,6 +1,23 @@
require_relative '../../spec_helper'
-require_relative 'shared/length'
describe "Symbol#length" do
- it_behaves_like :symbol_length, :length
+ it "returns 0 for empty name" do
+ :''.length.should == 0
+ end
+
+ it "returns 1 for name formed by a NUL character" do
+ :"\x00".length.should == 1
+ end
+
+ it "returns 3 for name formed by 3 ASCII characters" do
+ :one.length.should == 3
+ end
+
+ it "returns 4 for name formed by 4 ASCII characters" do
+ :four.length.should == 4
+ end
+
+ it "returns 4 for name formed by 1 multibyte and 3 ASCII characters" do
+ :"\xC3\x9Cber".length.should == 4
+ end
end
diff --git a/spec/ruby/core/symbol/match_spec.rb b/spec/ruby/core/symbol/match_spec.rb
index 41e058f977..7b165218c6 100644
--- a/spec/ruby/core/symbol/match_spec.rb
+++ b/spec/ruby/core/symbol/match_spec.rb
@@ -6,7 +6,7 @@ describe :symbol_match, shared: true do
end
it "returns nil if there is no match" do
- :a.send(@method, /b/).should be_nil
+ :a.send(@method, /b/).should == nil
end
it "sets the last match pseudo-variables" do
@@ -22,12 +22,12 @@ end
describe "Symbol#match" do
it "returns the MatchData" do
result = :abc.match(/b/)
- result.should be_kind_of(MatchData)
+ result.should.is_a?(MatchData)
result[0].should == 'b'
end
it "returns nil if there is no match" do
- :a.match(/b/).should be_nil
+ :a.match(/b/).should == nil
end
it "sets the last match pseudo-variables" do
@@ -38,7 +38,7 @@ describe "Symbol#match" do
describe "when passed a block" do
it "yields the MatchData" do
:abc.match(/./) {|m| ScratchPad.record m }
- ScratchPad.recorded.should be_kind_of(MatchData)
+ ScratchPad.recorded.should.is_a?(MatchData)
end
it "returns the block result" do
@@ -61,17 +61,17 @@ describe "Symbol#match?" do
context "when matches the given regex" do
it "returns true but does not set Regexp.last_match" do
- :string.match?(/string/i).should be_true
- Regexp.last_match.should be_nil
+ :string.match?(/string/i).should == true
+ Regexp.last_match.should == nil
end
end
it "returns false when does not match the given regex" do
- :string.match?(/STRING/).should be_false
+ :string.match?(/STRING/).should == false
end
it "takes matching position as the 2nd argument" do
- :string.match?(/str/i, 0).should be_true
- :string.match?(/str/i, 1).should be_false
+ :string.match?(/str/i, 0).should == true
+ :string.match?(/str/i, 1).should == false
end
end
diff --git a/spec/ruby/core/symbol/next_spec.rb b/spec/ruby/core/symbol/next_spec.rb
index 97fe913739..e80bbaa508 100644
--- a/spec/ruby/core/symbol/next_spec.rb
+++ b/spec/ruby/core/symbol/next_spec.rb
@@ -1,6 +1,7 @@
require_relative '../../spec_helper'
-require_relative 'shared/succ'
describe "Symbol#next" do
- it_behaves_like :symbol_succ, :next
+ it "is an alias of Symbol#succ" do
+ Symbol.instance_method(:next).should == Symbol.instance_method(:succ)
+ end
end
diff --git a/spec/ruby/core/symbol/shared/id2name.rb b/spec/ruby/core/symbol/shared/id2name.rb
deleted file mode 100644
index d012b7634e..0000000000
--- a/spec/ruby/core/symbol/shared/id2name.rb
+++ /dev/null
@@ -1,16 +0,0 @@
-describe :symbol_id2name, shared: true do
- it "returns the string corresponding to self" do
- :rubinius.send(@method).should == "rubinius"
- :squash.send(@method).should == "squash"
- :[].send(@method).should == "[]"
- :@ruby.send(@method).should == "@ruby"
- :@@ruby.send(@method).should == "@@ruby"
- end
-
- it "returns a String in the same encoding as self" do
- string = "ruby".encode("US-ASCII")
- symbol = string.to_sym
-
- symbol.send(@method).encoding.should == Encoding::US_ASCII
- end
-end
diff --git a/spec/ruby/core/symbol/shared/length.rb b/spec/ruby/core/symbol/shared/length.rb
deleted file mode 100644
index 692e8c57e3..0000000000
--- a/spec/ruby/core/symbol/shared/length.rb
+++ /dev/null
@@ -1,23 +0,0 @@
-# -*- encoding: utf-8 -*-
-
-describe :symbol_length, shared: true do
- it "returns 0 for empty name" do
- :''.send(@method).should == 0
- end
-
- it "returns 1 for name formed by a NUL character" do
- :"\x00".send(@method).should == 1
- end
-
- it "returns 3 for name formed by 3 ASCII characters" do
- :one.send(@method).should == 3
- end
-
- it "returns 4 for name formed by 4 ASCII characters" do
- :four.send(@method).should == 4
- end
-
- it "returns 4 for name formed by 1 multibyte and 3 ASCII characters" do
- :"\xC3\x9Cber".send(@method).should == 4
- end
-end
diff --git a/spec/ruby/core/symbol/shared/slice.rb b/spec/ruby/core/symbol/shared/slice.rb
deleted file mode 100644
index d3d4aad617..0000000000
--- a/spec/ruby/core/symbol/shared/slice.rb
+++ /dev/null
@@ -1,262 +0,0 @@
-require_relative '../fixtures/classes'
-
-describe :symbol_slice, shared: true do
- describe "with an Integer index" do
- it "returns the character code of the element at the index" do
- :symbol.send(@method, 1).should == ?y
- end
-
- it "returns nil if the index starts from the end and is greater than the length" do
- :symbol.send(@method, -10).should be_nil
- end
-
- it "returns nil if the index is greater than the length" do
- :symbol.send(@method, 42).should be_nil
- end
- end
-
- describe "with an Integer index and length" do
- describe "and a positive index and length" do
- it "returns a slice" do
- :symbol.send(@method, 1,3).should == "ymb"
- end
-
- it "returns a blank slice if the length is 0" do
- :symbol.send(@method, 0,0).should == ""
- :symbol.send(@method, 1,0).should == ""
- end
-
- it "returns a slice of all remaining characters if the given length is greater than the actual length" do
- :symbol.send(@method, 1,100).should == "ymbol"
- end
-
- it "returns nil if the index is greater than the length" do
- :symbol.send(@method, 10,1).should be_nil
- end
- end
-
- describe "and a positive index and negative length" do
- it "returns nil" do
- :symbol.send(@method, 0,-1).should be_nil
- :symbol.send(@method, 1,-1).should be_nil
- end
- end
-
- describe "and a negative index and positive length" do
- it "returns a slice starting from the end upto the length" do
- :symbol.send(@method, -3,2).should == "bo"
- end
-
- it "returns a blank slice if the length is 0" do
- :symbol.send(@method, -1,0).should == ""
- end
-
- it "returns a slice of all remaining characters if the given length is larger than the actual length" do
- :symbol.send(@method, -4,100).should == "mbol"
- end
-
- it "returns nil if the index is past the start" do
- :symbol.send(@method, -10,1).should be_nil
- end
- end
-
- describe "and a negative index and negative length" do
- it "returns nil" do
- :symbol.send(@method, -1,-1).should be_nil
- end
- end
-
- describe "and a Float length" do
- it "converts the length to an Integer" do
- :symbol.send(@method, 2,2.5).should == "mb"
- end
- end
-
- describe "and a nil length" do
- it "raises a TypeError" do
- -> { :symbol.send(@method, 1,nil) }.should raise_error(TypeError)
- end
- end
-
- describe "and a length that cannot be converted into an Integer" do
- it "raises a TypeError when given an Array" do
- -> { :symbol.send(@method, 1,Array.new) }.should raise_error(TypeError)
- end
-
- it "raises a TypeError when given an Hash" do
- -> { :symbol.send(@method, 1,Hash.new) }.should raise_error(TypeError)
- end
-
- it "raises a TypeError when given an Object" do
- -> { :symbol.send(@method, 1,Object.new) }.should raise_error(TypeError)
- end
- end
- end
-
- describe "with a Float index" do
- it "converts the index to an Integer" do
- :symbol.send(@method, 1.5).should == ?y
- end
- end
-
- describe "with a nil index" do
- it "raises a TypeError" do
- -> { :symbol.send(@method, nil) }.should raise_error(TypeError)
- end
- end
-
- describe "with an index that cannot be converted into an Integer" do
- it "raises a TypeError when given an Array" do
- -> { :symbol.send(@method, Array.new) }.should raise_error(TypeError)
- end
-
- it "raises a TypeError when given an Hash" do
- -> { :symbol.send(@method, Hash.new) }.should raise_error(TypeError)
- end
-
- it "raises a TypeError when given an Object" do
- -> { :symbol.send(@method, Object.new) }.should raise_error(TypeError)
- end
- end
-
- describe "with a Range slice" do
- describe "that is within bounds" do
- it "returns a slice if both range values begin at the start and are within bounds" do
- :symbol.send(@method, 1..4).should == "ymbo"
- end
-
- it "returns a slice if the first range value begins at the start and the last begins at the end" do
- :symbol.send(@method, 1..-1).should == "ymbol"
- end
-
- it "returns a slice if the first range value begins at the end and the last begins at the end" do
- :symbol.send(@method, -4..-1).should == "mbol"
- end
- end
-
- describe "that is out of bounds" do
- it "returns nil if the first range value begins past the end" do
- :symbol.send(@method, 10..12).should be_nil
- end
-
- it "returns a blank string if the first range value is within bounds and the last range value is not" do
- :symbol.send(@method, -2..-10).should == ""
- :symbol.send(@method, 2..-10).should == ""
- end
-
- it "returns nil if the first range value starts from the end and is within bounds and the last value starts from the end and is greater than the length" do
- :symbol.send(@method, -10..-12).should be_nil
- end
-
- it "returns nil if the first range value starts from the end and is out of bounds and the last value starts from the end and is less than the length" do
- :symbol.send(@method, -10..-2).should be_nil
- end
- end
-
- describe "with Float values" do
- it "converts the first value to an Integer" do
- :symbol.send(@method, 0.5..2).should == "sym"
- end
-
- it "converts the last value to an Integer" do
- :symbol.send(@method, 0..2.5).should == "sym"
- end
- end
- end
-
- describe "with a Range subclass slice" do
- it "returns a slice" do
- range = SymbolSpecs::MyRange.new(1, 4)
- :symbol.send(@method, range).should == "ymbo"
- end
- end
-
- describe "with a Regex slice" do
- describe "without a capture index" do
- it "returns a string of the match" do
- :symbol.send(@method, /[^bol]+/).should == "sym"
- end
-
- it "returns nil if the expression does not match" do
- :symbol.send(@method, /0-9/).should be_nil
- end
-
- it "sets $~ to the MatchData if there is a match" do
- :symbol.send(@method, /[^bol]+/)
- $~[0].should == "sym"
- end
-
- it "does not set $~ if there if there is not a match" do
- :symbol.send(@method, /[0-9]+/)
- $~.should be_nil
- end
- end
-
- describe "with a capture index" do
- it "returns a string of the complete match if the capture index is 0" do
- :symbol.send(@method, /(sy)(mb)(ol)/, 0).should == "symbol"
- end
-
- it "returns a string for the matched capture at the given index" do
- :symbol.send(@method, /(sy)(mb)(ol)/, 1).should == "sy"
- :symbol.send(@method, /(sy)(mb)(ol)/, -1).should == "ol"
- end
-
- it "returns nil if there is no capture for the index" do
- :symbol.send(@method, /(sy)(mb)(ol)/, 4).should be_nil
- :symbol.send(@method, /(sy)(mb)(ol)/, -4).should be_nil
- end
-
- it "converts the index to an Integer" do
- :symbol.send(@method, /(sy)(mb)(ol)/, 1.5).should == "sy"
- end
-
- describe "and an index that cannot be converted to an Integer" do
- it "raises a TypeError when given an Hash" do
- -> { :symbol.send(@method, /(sy)(mb)(ol)/, Hash.new) }.should raise_error(TypeError)
- end
-
- it "raises a TypeError when given an Array" do
- -> { :symbol.send(@method, /(sy)(mb)(ol)/, Array.new) }.should raise_error(TypeError)
- end
-
- it "raises a TypeError when given an Object" do
- -> { :symbol.send(@method, /(sy)(mb)(ol)/, Object.new) }.should raise_error(TypeError)
- end
- end
-
- it "raises a TypeError if the index is nil" do
- -> { :symbol.send(@method, /(sy)(mb)(ol)/, nil) }.should raise_error(TypeError)
- end
-
- it "sets $~ to the MatchData if there is a match" do
- :symbol.send(@method, /(sy)(mb)(ol)/, 0)
- $~[0].should == "symbol"
- $~[1].should == "sy"
- $~[2].should == "mb"
- $~[3].should == "ol"
- end
-
- it "does not set $~ to the MatchData if there is not a match" do
- :symbol.send(@method, /0-9/, 0)
- $~.should be_nil
- end
- end
- end
-
- describe "with a String slice" do
- it "does not set $~" do
- $~ = nil
- :symbol.send(@method, "sym")
- $~.should be_nil
- end
-
- it "returns a string if there is match" do
- :symbol.send(@method, "ymb").should == "ymb"
- end
-
- it "returns nil if there is not a match" do
- :symbol.send(@method, "foo").should be_nil
- end
- end
-end
diff --git a/spec/ruby/core/symbol/shared/succ.rb b/spec/ruby/core/symbol/shared/succ.rb
deleted file mode 100644
index dde298207e..0000000000
--- a/spec/ruby/core/symbol/shared/succ.rb
+++ /dev/null
@@ -1,18 +0,0 @@
-require_relative '../../../spec_helper'
-
-describe :symbol_succ, shared: true do
- it "returns a successor" do
- :abcd.send(@method).should == :abce
- :THX1138.send(@method).should == :THX1139
- end
-
- it "propagates a 'carry'" do
- :"1999zzz".send(@method).should == :"2000aaa"
- :ZZZ9999.send(@method).should == :AAAA0000
- end
-
- it "increments non-alphanumeric characters when no alphanumeric characters are present" do
- :"<<koala>>".send(@method).should == :"<<koalb>>"
- :"***".send(@method).should == :"**+"
- end
-end
diff --git a/spec/ruby/core/symbol/size_spec.rb b/spec/ruby/core/symbol/size_spec.rb
index 5e2aa8d4d2..b5d375b3aa 100644
--- a/spec/ruby/core/symbol/size_spec.rb
+++ b/spec/ruby/core/symbol/size_spec.rb
@@ -1,6 +1,7 @@
require_relative '../../spec_helper'
-require_relative 'shared/length'
describe "Symbol#size" do
- it_behaves_like :symbol_length, :size
+ it "is an alias of Symbol#length" do
+ Symbol.instance_method(:size).should == Symbol.instance_method(:length)
+ end
end
diff --git a/spec/ruby/core/symbol/slice_spec.rb b/spec/ruby/core/symbol/slice_spec.rb
index d2421c474c..050a2cf38c 100644
--- a/spec/ruby/core/symbol/slice_spec.rb
+++ b/spec/ruby/core/symbol/slice_spec.rb
@@ -1,6 +1,7 @@
require_relative '../../spec_helper'
-require_relative 'shared/slice'
describe "Symbol#slice" do
- it_behaves_like :symbol_slice, :slice
+ it "is an alias of Symbol#[]" do
+ Symbol.instance_method(:slice).should == Symbol.instance_method(:[])
+ end
end
diff --git a/spec/ruby/core/symbol/succ_spec.rb b/spec/ruby/core/symbol/succ_spec.rb
index 694bfff862..893164a2a6 100644
--- a/spec/ruby/core/symbol/succ_spec.rb
+++ b/spec/ruby/core/symbol/succ_spec.rb
@@ -1,6 +1,18 @@
require_relative '../../spec_helper'
-require_relative 'shared/succ'
describe "Symbol#succ" do
- it_behaves_like :symbol_succ, :succ
+ it "returns a successor" do
+ :abcd.succ.should == :abce
+ :THX1138.succ.should == :THX1139
+ end
+
+ it "propagates a 'carry'" do
+ :"1999zzz".succ.should == :"2000aaa"
+ :ZZZ9999.succ.should == :AAAA0000
+ end
+
+ it "increments non-alphanumeric characters when no alphanumeric characters are present" do
+ :"<<koala>>".succ.should == :"<<koalb>>"
+ :"***".succ.should == :"**+"
+ end
end
diff --git a/spec/ruby/core/symbol/swapcase_spec.rb b/spec/ruby/core/symbol/swapcase_spec.rb
index 24709cac30..95fc29e32b 100644
--- a/spec/ruby/core/symbol/swapcase_spec.rb
+++ b/spec/ruby/core/symbol/swapcase_spec.rb
@@ -3,7 +3,7 @@ require_relative '../../spec_helper'
describe "Symbol#swapcase" do
it "returns a Symbol" do
- :glark.swapcase.should be_an_instance_of(Symbol)
+ :glark.swapcase.should.instance_of?(Symbol)
end
it "converts lowercase ASCII characters to their uppercase equivalents" do
diff --git a/spec/ruby/core/symbol/symbol_spec.rb b/spec/ruby/core/symbol/symbol_spec.rb
index cefe70bc99..3534686a08 100644
--- a/spec/ruby/core/symbol/symbol_spec.rb
+++ b/spec/ruby/core/symbol/symbol_spec.rb
@@ -8,12 +8,12 @@ describe "Symbol" do
it ".allocate raises a TypeError" do
-> do
Symbol.allocate
- end.should raise_error(TypeError)
+ end.should.raise(TypeError)
end
it ".new is undefined" do
-> do
Symbol.new
- end.should raise_error(NoMethodError)
+ end.should.raise(NoMethodError)
end
end
diff --git a/spec/ruby/core/symbol/to_proc_spec.rb b/spec/ruby/core/symbol/to_proc_spec.rb
index def5d6d344..93ed1e9e9b 100644
--- a/spec/ruby/core/symbol/to_proc_spec.rb
+++ b/spec/ruby/core/symbol/to_proc_spec.rb
@@ -3,7 +3,7 @@ require_relative '../../spec_helper'
describe "Symbol#to_proc" do
it "returns a new Proc" do
proc = :to_s.to_proc
- proc.should be_kind_of(Proc)
+ proc.should.is_a?(Proc)
end
it "sends self to arguments passed when calling #call on the Proc" do
@@ -38,8 +38,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(NoMethodError, /protected method [`']pro' called/)
+ proc{tap(&:pri)}.should.raise(NoMethodError, /private method [`']pri' called/)
@a.should == [:pub]
@a = []
@@ -47,15 +47,15 @@ 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(NoMethodError, /protected method [`']pro' called/)
+ proc{o.tap(&:pri)}.should.raise(NoMethodError, /private method [`']pri' called/)
o.a.should == [:pub]
end
it "raises an ArgumentError when calling #call on the Proc without receiver" do
-> {
:object_id.to_proc.call
- }.should raise_error(ArgumentError, /no receiver given|wrong number of arguments \(given 0, expected 1\+\)/)
+ }.should.raise(ArgumentError, /no receiver given|wrong number of arguments \(given 0, expected 1\+\)/)
end
it "passes along the block passed to Proc#call" do
diff --git a/spec/ruby/core/symbol/to_s_spec.rb b/spec/ruby/core/symbol/to_s_spec.rb
index cd963faa28..2cb57c4cbc 100644
--- a/spec/ruby/core/symbol/to_s_spec.rb
+++ b/spec/ruby/core/symbol/to_s_spec.rb
@@ -1,6 +1,32 @@
require_relative '../../spec_helper'
-require_relative 'shared/id2name'
describe "Symbol#to_s" do
- it_behaves_like :symbol_id2name, :to_s
+ it "returns the string corresponding to self" do
+ :rubinius.to_s.should == "rubinius"
+ :squash.to_s.should == "squash"
+ :[].to_s.should == "[]"
+ :@ruby.to_s.should == "@ruby"
+ :@@ruby.to_s.should == "@@ruby"
+ end
+
+ it "returns a String in the same encoding as self" do
+ string = "ruby".encode("US-ASCII")
+ symbol = string.to_sym
+
+ symbol.to_s.encoding.should == Encoding::US_ASCII
+ end
+
+ ruby_version_is "3.4" do
+ it "warns about mutating returned string" do
+ -> { :bad!.to_s.upcase! }.should complain(/warning: string returned by :bad!.to_s will be frozen in the future/)
+ end
+
+ it "does not warn about mutation when Warning[:deprecated] is false" do
+ deprecated = Warning[:deprecated]
+ Warning[:deprecated] = false
+ -> { :bad!.to_s.upcase! }.should_not complain
+ ensure
+ Warning[:deprecated] = deprecated
+ end
+ end
end
diff --git a/spec/ruby/core/symbol/to_sym_spec.rb b/spec/ruby/core/symbol/to_sym_spec.rb
index e75f3d48a8..062daa3fc7 100644
--- a/spec/ruby/core/symbol/to_sym_spec.rb
+++ b/spec/ruby/core/symbol/to_sym_spec.rb
@@ -3,7 +3,7 @@ require_relative '../../spec_helper'
describe "Symbol#to_sym" do
it "returns self" do
[:rubinius, :squash, :[], :@ruby, :@@ruby].each do |sym|
- sym.to_sym.should == sym
+ sym.to_sym.should.equal?(sym)
end
end
end
diff --git a/spec/ruby/core/symbol/upcase_spec.rb b/spec/ruby/core/symbol/upcase_spec.rb
index f704bdcbf3..3895d95efb 100644
--- a/spec/ruby/core/symbol/upcase_spec.rb
+++ b/spec/ruby/core/symbol/upcase_spec.rb
@@ -3,7 +3,7 @@ require_relative '../../spec_helper'
describe "Symbol#upcase" do
it "returns a Symbol" do
- :glark.upcase.should be_an_instance_of(Symbol)
+ :glark.upcase.should.instance_of?(Symbol)
end
it "converts lowercase ASCII characters to their uppercase equivalents" do
diff --git a/spec/ruby/core/thread/abort_on_exception_spec.rb b/spec/ruby/core/thread/abort_on_exception_spec.rb
index 49be84ea9f..aeca50e5c1 100644
--- a/spec/ruby/core/thread/abort_on_exception_spec.rb
+++ b/spec/ruby/core/thread/abort_on_exception_spec.rb
@@ -13,12 +13,12 @@ describe "Thread#abort_on_exception" do
end
it "is false by default" do
- @thread.abort_on_exception.should be_false
+ @thread.abort_on_exception.should == false
end
it "returns true when #abort_on_exception= is passed true" do
@thread.abort_on_exception = true
- @thread.abort_on_exception.should be_true
+ @thread.abort_on_exception.should == true
end
end
@@ -39,7 +39,7 @@ describe :thread_abort_on_exception, shared: true do
ThreadSpecs.state = :run
# Wait for the main thread to be interrupted
sleep
- end.should raise_error(RuntimeError, "Thread#abort_on_exception= specs")
+ end.should.raise(RuntimeError, "Thread#abort_on_exception= specs")
ScratchPad << :after
rescue Exception => e
@@ -81,7 +81,7 @@ describe "Thread.abort_on_exception" do
it "returns true when .abort_on_exception= is passed true" do
Thread.abort_on_exception = true
- Thread.abort_on_exception.should be_true
+ Thread.abort_on_exception.should == true
end
end
diff --git a/spec/ruby/core/thread/allocate_spec.rb b/spec/ruby/core/thread/allocate_spec.rb
index cfd556812f..0b4e4f1b1f 100644
--- a/spec/ruby/core/thread/allocate_spec.rb
+++ b/spec/ruby/core/thread/allocate_spec.rb
@@ -4,6 +4,6 @@ describe "Thread.allocate" do
it "raises a TypeError" do
-> {
Thread.allocate
- }.should raise_error(TypeError)
+ }.should.raise(TypeError)
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 68a69049d9..6d9482f2ae 100644
--- a/spec/ruby/core/thread/backtrace/location/absolute_path_spec.rb
+++ b/spec/ruby/core/thread/backtrace/location/absolute_path_spec.rb
@@ -42,7 +42,7 @@ describe 'Thread::Backtrace::Location#absolute_path' do
locations = ScratchPad.recorded
locations[0].absolute_path.should == path
# Make sure it's from the class body, not from the file top-level
- locations[0].label.should include 'MethodAddedAbsolutePath'
+ locations[0].label.should.include? 'MethodAddedAbsolutePath'
end
end
diff --git a/spec/ruby/core/thread/backtrace/location/fixtures/classes.rb b/spec/ruby/core/thread/backtrace/location/fixtures/classes.rb
index e903c3e450..103c36b3a0 100644
--- a/spec/ruby/core/thread/backtrace/location/fixtures/classes.rb
+++ b/spec/ruby/core/thread/backtrace/location/fixtures/classes.rb
@@ -1,10 +1,26 @@
+# These are top-level def on purpose to test those cases
+
+def label_top_method = ThreadBacktraceLocationSpecs::LABEL.call
+
+def self.label_sdef_method_of_main = ThreadBacktraceLocationSpecs::LABEL.call
+
+class << self
+ def label_sclass_method_of_main = ThreadBacktraceLocationSpecs::LABEL.call
+end
+
module ThreadBacktraceLocationSpecs
MODULE_LOCATION = caller_locations(0) rescue nil
+ INSTANCE = Object.new.extend(self)
+ LABEL = -> { caller_locations(1, 1)[0].label }
def self.locations
caller_locations
end
+ def instance_method_location
+ caller_locations(0)
+ end
+
def self.method_location
caller_locations(0)
end
@@ -15,6 +31,12 @@ module ThreadBacktraceLocationSpecs
end
end
+ def instance_block_location
+ 1.times do
+ return caller_locations(0)
+ end
+ end
+
def self.locations_inside_nested_blocks
first_level_location = nil
second_level_location = nil
@@ -32,4 +54,86 @@ module ThreadBacktraceLocationSpecs
[first_level_location, second_level_location, third_level_location]
end
+
+ def instance_locations_inside_nested_block
+ loc = nil
+ 1.times do
+ 1.times do
+ loc = caller_locations(0)
+ end
+ end
+ loc
+ end
+
+ def original_method = LABEL.call
+ alias_method :aliased_method, :original_method
+
+ module M
+ class C
+ def regular_instance_method = LABEL.call
+
+ def self.sdef_class_method = LABEL.call
+
+ class << self
+ def sclass_method = LABEL.call
+
+ def block_in_sclass_method
+ -> {
+ -> { LABEL.call }.call
+ }.call
+ end
+ end
+ block_in_sclass_method
+ end
+ end
+
+ class M::D
+ def scoped_method = LABEL.call
+
+ def self.sdef_scoped_method = LABEL.call
+
+ class << self
+ def sclass_scoped_method = LABEL.call
+ end
+
+ module ::ThreadBacktraceLocationSpecs
+ def top = LABEL.call
+ end
+
+ class ::ThreadBacktraceLocationSpecs::Nested
+ def top_nested = LABEL.call
+
+ class C
+ def top_nested_c = LABEL.call
+ end
+ end
+ end
+
+ SOME_OBJECT = Object.new
+ SOME_OBJECT.instance_exec do
+ def unknown_def_singleton_method = LABEL.call
+
+ def self.unknown_sdef_singleton_method = LABEL.call
+ end
+
+ M.module_eval do
+ def module_eval_method = LABEL.call
+
+ def self.sdef_module_eval_method = LABEL.call
+ end
+
+ def ThreadBacktraceLocationSpecs.string_class_method = LABEL.call
+
+ module M
+ def ThreadBacktraceLocationSpecs.nested_class_method = LABEL.call
+ end
+
+ module M
+ module_function def mod_function = LABEL.call
+ end
+
+ expr = self
+ def expr.sdef_expression = LABEL.call
+
+ def expr.block_in_sdef_expression = -> { LABEL.call }.call
end
diff --git a/spec/ruby/core/thread/backtrace/location/inspect_spec.rb b/spec/ruby/core/thread/backtrace/location/inspect_spec.rb
index 20e477a5a6..4df88a2f33 100644
--- a/spec/ruby/core/thread/backtrace/location/inspect_spec.rb
+++ b/spec/ruby/core/thread/backtrace/location/inspect_spec.rb
@@ -8,6 +8,6 @@ describe 'Thread::Backtrace::Location#inspect' do
end
it 'converts the call frame to a String' do
- @frame.inspect.should include("#{__FILE__}:#{@line}:in ")
+ @frame.inspect.should.include?("#{__FILE__}:#{@line}:in ")
end
end
diff --git a/spec/ruby/core/thread/backtrace/location/label_spec.rb b/spec/ruby/core/thread/backtrace/location/label_spec.rb
index 85ddccc8e3..5f6a7b73df 100644
--- a/spec/ruby/core/thread/backtrace/location/label_spec.rb
+++ b/spec/ruby/core/thread/backtrace/location/label_spec.rb
@@ -3,7 +3,7 @@ require_relative 'fixtures/classes'
describe 'Thread::Backtrace::Location#label' do
it 'returns the base label of the call frame' do
- ThreadBacktraceLocationSpecs.locations[0].label.should include('<top (required)>')
+ ThreadBacktraceLocationSpecs.locations[0].label.should.include?('<top (required)>')
end
it 'returns the method name for a method location' do
@@ -15,7 +15,7 @@ describe 'Thread::Backtrace::Location#label' do
end
it 'returns the module name for a module location' do
- ThreadBacktraceLocationSpecs::MODULE_LOCATION[0].label.should include "ThreadBacktraceLocationSpecs"
+ ThreadBacktraceLocationSpecs::MODULE_LOCATION[0].label.should == "<module:ThreadBacktraceLocationSpecs>"
end
it 'includes the nesting level of a block as part of the location label' do
@@ -34,4 +34,194 @@ describe 'Thread::Backtrace::Location#label' do
main_label.should == "block in <main>\n"
required_label.should == "block in <top (required)>\n"
end
+
+ it "return the same name as the caller for eval" do
+ this = caller_locations(0)[0].label
+ eval("caller_locations(0)[0]").label.should == this
+
+ b = binding
+ b.eval("caller_locations(0)[0]").label.should == this
+
+ b.local_variable_set(:binding_var1, 1)
+ b.eval("caller_locations(0)[0]").label.should == this
+
+ b.local_variable_set(:binding_var2, 2)
+ b.eval("caller_locations(0)[0]").label.should == this
+
+ b.local_variable_set(:binding_var2, 2)
+ eval("caller_locations(0)[0]", b).label.should == this
+ end
+
+ ruby_version_is "3.4" do
+ describe "is Module#method for" do
+ it "a core method defined natively" do
+ BasicObject.instance_method(:instance_exec).should_not.source_location
+ loc = nil
+ loc = instance_exec { caller_locations(1, 1)[0] }
+ loc.label.should == "BasicObject#instance_exec"
+ end
+
+ it "a core method defined in Ruby" do
+ Kernel.instance_method(:tap).should.source_location
+ loc = nil
+ tap { loc = caller_locations(1, 1)[0] }
+ loc.label.should == "Kernel#tap"
+ end
+
+ it "an instance method defined in Ruby" do
+ ThreadBacktraceLocationSpecs::INSTANCE.instance_method_location[0].label.should == "ThreadBacktraceLocationSpecs#instance_method_location"
+ end
+
+ it "a block in an instance method defined in Ruby" do
+ ThreadBacktraceLocationSpecs::INSTANCE.instance_block_location[0].label.should == "block in ThreadBacktraceLocationSpecs#instance_block_location"
+ end
+
+ it "a nested block in an instance method defined in Ruby" do
+ ThreadBacktraceLocationSpecs::INSTANCE.instance_locations_inside_nested_block[0].label.should == "block (2 levels) in ThreadBacktraceLocationSpecs#instance_locations_inside_nested_block"
+ end
+
+ it "a method defined via module_exec" do
+ ThreadBacktraceLocationSpecs.module_exec do
+ def in_module_exec
+ caller_locations(0)
+ end
+ end
+ ThreadBacktraceLocationSpecs::INSTANCE.in_module_exec[0].label.should == "ThreadBacktraceLocationSpecs#in_module_exec"
+ end
+
+ it "a method defined via module_eval" do
+ ThreadBacktraceLocationSpecs.module_eval <<~RUBY
+ def in_module_eval
+ caller_locations(0)
+ end
+ RUBY
+ ThreadBacktraceLocationSpecs::INSTANCE.in_module_eval[0].label.should == "ThreadBacktraceLocationSpecs#in_module_eval"
+ end
+ end
+
+ describe "is Module.method for" do
+ it "a singleton method defined in Ruby" do
+ ThreadBacktraceLocationSpecs.method_location[0].label.should == "ThreadBacktraceLocationSpecs.method_location"
+ end
+
+ it "a block in a singleton method defined in Ruby" do
+ ThreadBacktraceLocationSpecs.block_location[0].label.should == "block in ThreadBacktraceLocationSpecs.block_location"
+ end
+
+ it "a nested block in a singleton method defined in Ruby" do
+ ThreadBacktraceLocationSpecs.locations_inside_nested_blocks[2].label.should == "block (3 levels) in ThreadBacktraceLocationSpecs.locations_inside_nested_blocks"
+ end
+
+ it "a singleton method defined via def Const.method" do
+ def ThreadBacktraceLocationSpecs.def_singleton
+ caller_locations(0)
+ end
+ ThreadBacktraceLocationSpecs.def_singleton[0].label.should == "ThreadBacktraceLocationSpecs.def_singleton"
+ end
+ end
+
+ it "shows the original method name for an aliased method" do
+ ThreadBacktraceLocationSpecs::INSTANCE.aliased_method.should == "ThreadBacktraceLocationSpecs#original_method"
+ end
+
+ # A wide variety of cases.
+ # These show interesting cases when trying to determine the name statically/at parse time
+ describe "is correct for" do
+ base = ThreadBacktraceLocationSpecs
+
+ it "M::C#regular_instance_method" do
+ base::M::C.new.regular_instance_method.should == "#{base}::M::C#regular_instance_method"
+ end
+
+ it "M::C.sdef_class_method" do
+ base::M::C.sdef_class_method.should == "#{base}::M::C.sdef_class_method"
+ end
+
+ it "M::C.sclass_method" do
+ base::M::C.sclass_method.should == "#{base}::M::C.sclass_method"
+ end
+
+ it "M::C.block_in_sclass_method" do
+ base::M::C.block_in_sclass_method.should == "block (2 levels) in #{base}::M::C.block_in_sclass_method"
+ end
+
+ it "M::D#scoped_method" do
+ base::M::D.new.scoped_method.should == "#{base}::M::D#scoped_method"
+ end
+
+ it "M::D.sdef_scoped_method" do
+ base::M::D.sdef_scoped_method.should == "#{base}::M::D.sdef_scoped_method"
+ end
+
+ it "M::D.sclass_scoped_method" do
+ base::M::D.sclass_scoped_method.should == "#{base}::M::D.sclass_scoped_method"
+ end
+
+ it "ThreadBacktraceLocationSpecs#top" do
+ ThreadBacktraceLocationSpecs::INSTANCE.top.should == "ThreadBacktraceLocationSpecs#top"
+ end
+
+ it "ThreadBacktraceLocationSpecs::Nested#top_nested" do
+ ThreadBacktraceLocationSpecs::Nested.new.top_nested.should == "ThreadBacktraceLocationSpecs::Nested#top_nested"
+ end
+
+ it "ThreadBacktraceLocationSpecs::Nested::C#top_nested_c" do
+ ThreadBacktraceLocationSpecs::Nested::C.new.top_nested_c.should == "ThreadBacktraceLocationSpecs::Nested::C#top_nested_c"
+ end
+
+ it "Object#label_top_method" do
+ label_top_method.should == "Object#label_top_method"
+ end
+
+ it "main.label_sdef_method_of_main" do
+ main = TOPLEVEL_BINDING.receiver
+ main.label_sdef_method_of_main.should == "label_sdef_method_of_main"
+ end
+
+ it "main.label_sclass_method_of_main" do
+ main = TOPLEVEL_BINDING.receiver
+ main.label_sclass_method_of_main.should == "label_sclass_method_of_main"
+ end
+
+ it "unknown_def_singleton_method" do
+ base::SOME_OBJECT.unknown_def_singleton_method.should == "unknown_def_singleton_method"
+ end
+
+ it "unknown_sdef_singleton_method" do
+ base::SOME_OBJECT.unknown_sdef_singleton_method.should == "unknown_sdef_singleton_method"
+ end
+
+ it "M#module_eval_method" do
+ Object.new.extend(base::M).module_eval_method.should == "#{base}::M#module_eval_method"
+ end
+
+ it "M.sdef_module_eval_method" do
+ base::M.sdef_module_eval_method.should == "#{base}::M.sdef_module_eval_method"
+ end
+
+ it "ThreadBacktraceLocationSpecs.string_class_method" do
+ ThreadBacktraceLocationSpecs.string_class_method.should == "ThreadBacktraceLocationSpecs.string_class_method"
+ end
+
+ it "ThreadBacktraceLocationSpecs.nested_class_method" do
+ ThreadBacktraceLocationSpecs.nested_class_method.should == "ThreadBacktraceLocationSpecs.nested_class_method"
+ end
+
+ it "M#mod_function" do
+ Object.new.extend(base::M).send(:mod_function).should == "#{base}::M#mod_function"
+ end
+
+ it "M.mod_function" do
+ base::M.mod_function.should == "#{base}::M.mod_function"
+ end
+
+ it "sdef_expression" do
+ base.sdef_expression.should == "#{base}.sdef_expression"
+ end
+
+ it "block_in_sdef_expression" do
+ base.block_in_sdef_expression.should == "block in #{base}.block_in_sdef_expression"
+ end
+ end
+ end
end
diff --git a/spec/ruby/core/thread/backtrace/location/to_s_spec.rb b/spec/ruby/core/thread/backtrace/location/to_s_spec.rb
index 5911cdced0..983ce4c3f8 100644
--- a/spec/ruby/core/thread/backtrace/location/to_s_spec.rb
+++ b/spec/ruby/core/thread/backtrace/location/to_s_spec.rb
@@ -8,6 +8,6 @@ describe 'Thread::Backtrace::Location#to_s' do
end
it 'converts the call frame to a String' do
- @frame.to_s.should include("#{__FILE__}:#{@line}:in ")
+ @frame.to_s.should.include?("#{__FILE__}:#{@line}:in ")
end
end
diff --git a/spec/ruby/core/thread/backtrace_locations_spec.rb b/spec/ruby/core/thread/backtrace_locations_spec.rb
index 09fe622e0d..28a488f311 100644
--- a/spec/ruby/core/thread/backtrace_locations_spec.rb
+++ b/spec/ruby/core/thread/backtrace_locations_spec.rb
@@ -3,20 +3,20 @@ require_relative '../../spec_helper'
describe "Thread#backtrace_locations" do
it "returns an Array" do
locations = Thread.current.backtrace_locations
- locations.should be_an_instance_of(Array)
- locations.should_not be_empty
+ locations.should.instance_of?(Array)
+ locations.should_not.empty?
end
it "sets each element to a Thread::Backtrace::Location" do
locations = Thread.current.backtrace_locations
- locations.each { |loc| loc.should be_an_instance_of(Thread::Backtrace::Location) }
+ locations.each { |loc| loc.should.instance_of?(Thread::Backtrace::Location) }
end
it "can be called on any Thread" do
locations = Thread.new { Thread.current.backtrace_locations }.value
- locations.should be_an_instance_of(Array)
- locations.should_not be_empty
- locations.each { |loc| loc.should be_an_instance_of(Thread::Backtrace::Location) }
+ locations.should.instance_of?(Array)
+ locations.should_not.empty?
+ locations.each { |loc| loc.should.instance_of?(Thread::Backtrace::Location) }
end
it "can be called with a number of locations to omit" do
diff --git a/spec/ruby/core/thread/backtrace_spec.rb b/spec/ruby/core/thread/backtrace_spec.rb
index 15bb29a349..770c300f06 100644
--- a/spec/ruby/core/thread/backtrace_spec.rb
+++ b/spec/ruby/core/thread/backtrace_spec.rb
@@ -12,7 +12,7 @@ describe "Thread#backtrace" do
Thread.pass while t.status && t.status != 'sleep'
backtrace = t.backtrace
- backtrace.should be_kind_of(Array)
+ backtrace.should.is_a?(Array)
backtrace.first.should =~ /[`'](?:Kernel#)?sleep'/
t.raise 'finish the thread'
@@ -30,7 +30,7 @@ describe "Thread#backtrace" do
backtrace = t.backtrace
t.kill
t.join
- backtrace.should be_kind_of(Array)
+ backtrace.should.is_a?(Array)
end
it "can be called with a number of locations to omit" do
diff --git a/spec/ruby/core/thread/current_spec.rb b/spec/ruby/core/thread/current_spec.rb
index f5ed1d95cd..f893f078ba 100644
--- a/spec/ruby/core/thread/current_spec.rb
+++ b/spec/ruby/core/thread/current_spec.rb
@@ -4,13 +4,13 @@ require_relative 'fixtures/classes'
describe "Thread.current" do
it "returns a thread" do
current = Thread.current
- current.should be_kind_of(Thread)
+ current.should.is_a?(Thread)
end
it "returns the current thread" do
t = Thread.new { Thread.current }
- t.value.should equal(t)
- Thread.current.should_not equal(t.value)
+ t.value.should.equal?(t)
+ Thread.current.should_not.equal?(t.value)
end
it "returns the correct thread in a Fiber" do
@@ -22,10 +22,10 @@ describe "Thread.current" do
cur = Thread.current
Fiber.new {
Thread.current
- }.resume.should equal cur
+ }.resume.should.equal? cur
cur
}
- t.value.should equal t
+ t.value.should.equal? t
end
end
end
diff --git a/spec/ruby/core/thread/each_caller_location_spec.rb b/spec/ruby/core/thread/each_caller_location_spec.rb
index aa7423675b..15fda1a37b 100644
--- a/spec/ruby/core/thread/each_caller_location_spec.rb
+++ b/spec/ruby/core/thread/each_caller_location_spec.rb
@@ -6,7 +6,7 @@ describe "Thread.each_caller_location" do
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)
+ ScratchPad.recorded[0].should.is_a?(Thread::Backtrace::Location)
end
it "returns subset of 'Thread.to_enum(:each_caller_location)' locations" do
@@ -26,7 +26,7 @@ describe "Thread.each_caller_location" do
end
ar.map(&:to_s).should == caller_locations(1, 2).map(&:to_s)
- ecl.should be_kind_of(Thread::Backtrace::Location)
+ ecl.should.is_a?(Thread::Backtrace::Location)
end
it "returns nil" do
@@ -36,12 +36,12 @@ describe "Thread.each_caller_location" do
it "raises LocalJumpError when called without a block" do
-> {
Thread.each_caller_location
- }.should raise_error(LocalJumpError, "no block given")
+ }.should.raise(LocalJumpError, "no block given")
end
it "doesn't accept keyword arguments" do
-> {
Thread.each_caller_location(12, foo: 10) {}
- }.should raise_error(ArgumentError);
+ }.should.raise(ArgumentError);
end
end
diff --git a/spec/ruby/core/thread/element_reference_spec.rb b/spec/ruby/core/thread/element_reference_spec.rb
index fde9d1f440..72892f6c50 100644
--- a/spec/ruby/core/thread/element_reference_spec.rb
+++ b/spec/ruby/core/thread/element_reference_spec.rb
@@ -49,7 +49,7 @@ describe "Thread#[]" do
end
it "raises exceptions on the wrong type of keys" do
- -> { Thread.current[nil] }.should raise_error(TypeError)
- -> { Thread.current[5] }.should raise_error(TypeError)
+ -> { Thread.current[nil] }.should.raise(TypeError)
+ -> { Thread.current[5] }.should.raise(TypeError)
end
end
diff --git a/spec/ruby/core/thread/element_set_spec.rb b/spec/ruby/core/thread/element_set_spec.rb
index f205177304..97d6c23980 100644
--- a/spec/ruby/core/thread/element_set_spec.rb
+++ b/spec/ruby/core/thread/element_set_spec.rb
@@ -12,7 +12,7 @@ describe "Thread#[]=" do
th.freeze
-> {
th[:foo] = "bar"
- }.should raise_error(FrozenError, "can't modify frozen thread locals")
+ }.should.raise(FrozenError, "can't modify frozen thread locals")
end.join
end
@@ -40,8 +40,8 @@ describe "Thread#[]=" do
end
it "raises exceptions on the wrong type of keys" do
- -> { Thread.current[nil] = true }.should raise_error(TypeError)
- -> { Thread.current[5] = true }.should raise_error(TypeError)
+ -> { Thread.current[nil] = true }.should.raise(TypeError)
+ -> { Thread.current[5] = true }.should.raise(TypeError)
end
it "is not shared across fibers" do
@@ -51,7 +51,7 @@ describe "Thread#[]=" do
Thread.current[:value].should == 1
end
fib.resume
- Thread.current[:value].should be_nil
+ Thread.current[:value].should == nil
Thread.current[:value] = 2
fib.resume
Thread.current[:value] = 2
diff --git a/spec/ruby/core/thread/exit_spec.rb b/spec/ruby/core/thread/exit_spec.rb
index c3f710920e..dbcd889898 100644
--- a/spec/ruby/core/thread/exit_spec.rb
+++ b/spec/ruby/core/thread/exit_spec.rb
@@ -1,6 +1,11 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
-require_relative 'shared/exit'
+
+describe "Thread#exit" do
+ it "is an alias of Thread#kill" do
+ Thread.instance_method(:exit).should == Thread.instance_method(:kill)
+ end
+end
describe "Thread#exit!" do
it "needs to be reviewed for spec completeness"
@@ -10,6 +15,6 @@ describe "Thread.exit" do
it "causes the current thread to exit" do
thread = Thread.new { Thread.exit; sleep }
thread.join
- thread.status.should be_false
+ thread.status.should == false
end
end
diff --git a/spec/ruby/core/thread/fetch_spec.rb b/spec/ruby/core/thread/fetch_spec.rb
index 85ffb71874..fe27dec4a2 100644
--- a/spec/ruby/core/thread/fetch_spec.rb
+++ b/spec/ruby/core/thread/fetch_spec.rb
@@ -19,7 +19,7 @@ describe 'Thread#fetch' do
it 'raises a KeyError when the Thread does not have a fiber-local variable of the same name' do
th = Thread.new {}
th.join
- -> { th.fetch(:cat) }.should raise_error(KeyError)
+ -> { th.fetch(:cat) }.should.raise(KeyError)
end
it 'returns the value of the fiber-local variable if value has been assigned' do
@@ -60,7 +60,7 @@ describe 'Thread#fetch' do
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)
+ -> { Thread.current.fetch() }.should.raise(ArgumentError)
+ -> { Thread.current.fetch(1, 2, 3) }.should.raise(ArgumentError)
end
end
diff --git a/spec/ruby/core/thread/fixtures/classes.rb b/spec/ruby/core/thread/fixtures/classes.rb
index 54bd85fae3..14d5d2f7bf 100644
--- a/spec/ruby/core/thread/fixtures/classes.rb
+++ b/spec/ruby/core/thread/fixtures/classes.rb
@@ -27,6 +27,7 @@ module ThreadSpecs
thread.join
ensure
thread.kill if thread.alive?
+ Thread.pass while thread.alive? # Thread#kill may not terminate a thread immediately so it may be detected as a leaked one
end
end
@@ -206,7 +207,7 @@ module ThreadSpecs
def self.join_dying_thread_with_outer_ensure(kill_method_name=:kill)
t = dying_thread_with_outer_ensure(kill_method_name) { yield }
- -> { t.join }.should raise_error(RuntimeError, "In dying thread")
+ -> { t.join }.should.raise(RuntimeError, "In dying thread")
return t
end
diff --git a/spec/ruby/core/thread/fork_spec.rb b/spec/ruby/core/thread/fork_spec.rb
index a2f4181298..60d574a185 100644
--- a/spec/ruby/core/thread/fork_spec.rb
+++ b/spec/ruby/core/thread/fork_spec.rb
@@ -1,9 +1,7 @@
require_relative '../../spec_helper'
-require_relative 'fixtures/classes'
-require_relative 'shared/start'
describe "Thread.fork" do
- describe "Thread.start" do
- it_behaves_like :thread_start, :fork
+ it "is an alias of Thread.start" do
+ Thread.method(:fork).should == Thread.method(:start)
end
end
diff --git a/spec/ruby/core/thread/handle_interrupt_spec.rb b/spec/ruby/core/thread/handle_interrupt_spec.rb
index ea7e81cb98..aa03d4c66d 100644
--- a/spec/ruby/core/thread/handle_interrupt_spec.rb
+++ b/spec/ruby/core/thread/handle_interrupt_spec.rb
@@ -75,7 +75,7 @@ describe "Thread.handle_interrupt" do
Thread.handle_interrupt(RuntimeError => :immediate) {
flunk "not reached"
}
- }.should raise_error(RuntimeError, "interrupt immediate")
+ }.should.raise(RuntimeError, "interrupt immediate")
Thread.pending_interrupt?.should == false
end
end
@@ -95,7 +95,7 @@ describe "Thread.handle_interrupt" do
Thread.handle_interrupt(RuntimeError => :immediate) {
flunk "not reached"
}
- }.should raise_error(RuntimeError, "interrupt with fibers")
+ }.should.raise(RuntimeError, "interrupt with fibers")
Thread.pending_interrupt?.should == false
end
@@ -115,7 +115,7 @@ describe "Thread.handle_interrupt" do
executed = true
raise "regular exception"
end
- }.should raise_error(RuntimeError, "interrupt exception")
+ }.should.raise(RuntimeError, "interrupt exception")
executed.should == true
end
diff --git a/spec/ruby/core/thread/initialize_spec.rb b/spec/ruby/core/thread/initialize_spec.rb
index 4fca900cd8..b9a94560ee 100644
--- a/spec/ruby/core/thread/initialize_spec.rb
+++ b/spec/ruby/core/thread/initialize_spec.rb
@@ -19,7 +19,7 @@ describe "Thread#initialize" do
@t.instance_eval do
initialize {}
end
- }.should raise_error(ThreadError)
+ }.should.raise(ThreadError)
end
end
diff --git a/spec/ruby/core/thread/inspect_spec.rb b/spec/ruby/core/thread/inspect_spec.rb
index bd6e0c31fc..fee401830a 100644
--- a/spec/ruby/core/thread/inspect_spec.rb
+++ b/spec/ruby/core/thread/inspect_spec.rb
@@ -1,6 +1,7 @@
require_relative '../../spec_helper'
-require_relative 'shared/to_s'
describe "Thread#inspect" do
- it_behaves_like :thread_to_s, :inspect
+ it "is an alias of Thread#to_s" do
+ Thread.instance_method(:inspect).should == Thread.instance_method(:to_s)
+ end
end
diff --git a/spec/ruby/core/thread/join_spec.rb b/spec/ruby/core/thread/join_spec.rb
index 213fe2e505..f4332167f1 100644
--- a/spec/ruby/core/thread/join_spec.rb
+++ b/spec/ruby/core/thread/join_spec.rb
@@ -4,28 +4,28 @@ require_relative 'fixtures/classes'
describe "Thread#join" do
it "returns the thread when it is finished" do
t = Thread.new {}
- t.join.should equal(t)
+ t.join.should.equal?(t)
end
it "returns the thread when it is finished when given a timeout" do
t = Thread.new {}
t.join
- t.join(0).should equal(t)
+ t.join(0).should.equal?(t)
end
it "coerces timeout to a Float if it is not nil" do
t = Thread.new {}
t.join
- t.join(0).should equal(t)
- t.join(0.0).should equal(t)
- t.join(nil).should equal(t)
+ t.join(0).should.equal?(t)
+ t.join(0.0).should.equal?(t)
+ t.join(nil).should.equal?(t)
end
it "raises TypeError if the argument is not a valid timeout" do
t = Thread.new { }
t.join
- -> { t.join(:foo) }.should raise_error TypeError
- -> { t.join("bar") }.should raise_error TypeError
+ -> { t.join(:foo) }.should.raise TypeError
+ -> { t.join("bar") }.should.raise TypeError
end
it "returns nil if it is not finished when given a timeout" do
@@ -55,16 +55,16 @@ describe "Thread#join" do
Thread.current.report_on_exception = false
raise NotImplementedError.new("Just kidding")
}
- -> { t.join }.should raise_error(NotImplementedError)
+ -> { t.join }.should.raise(NotImplementedError)
end
it "returns the dead thread" do
t = Thread.new { Thread.current.kill }
- t.join.should equal(t)
+ t.join.should.equal?(t)
end
it "raises any uncaught exception encountered in ensure block" do
t = ThreadSpecs.dying_thread_ensures { raise NotImplementedError.new("Just kidding") }
- -> { t.join }.should raise_error(NotImplementedError)
+ -> { t.join }.should.raise(NotImplementedError)
end
end
diff --git a/spec/ruby/core/thread/key_spec.rb b/spec/ruby/core/thread/key_spec.rb
index 339fa98f53..a14aeb8d31 100644
--- a/spec/ruby/core/thread/key_spec.rb
+++ b/spec/ruby/core/thread/key_spec.rb
@@ -24,30 +24,30 @@ describe "Thread#key?" do
end
it "raises exceptions on the wrong type of keys" do
- -> { Thread.current.key? nil }.should raise_error(TypeError)
- -> { Thread.current.key? 5 }.should raise_error(TypeError)
+ -> { Thread.current.key? nil }.should.raise(TypeError)
+ -> { Thread.current.key? 5 }.should.raise(TypeError)
end
it "is not shared across fibers" do
fib = Fiber.new do
Thread.current[:val1] = 1
Fiber.yield
- Thread.current.key?(:val1).should be_true
- Thread.current.key?(:val2).should be_false
+ Thread.current.key?(:val1).should == true
+ Thread.current.key?(:val2).should == false
end
- Thread.current.key?(:val1).should_not be_true
+ Thread.current.key?(:val1).should_not == true
fib.resume
Thread.current[:val2] = 2
fib.resume
- Thread.current.key?(:val1).should be_false
- Thread.current.key?(:val2).should be_true
+ Thread.current.key?(:val1).should == false
+ Thread.current.key?(:val2).should == true
end
it "stores a local in another thread when in a fiber" do
fib = Fiber.new do
t = Thread.new do
sleep
- Thread.current.key?(:value).should be_true
+ Thread.current.key?(:value).should == true
end
Thread.pass while t.status and t.status != "sleep"
diff --git a/spec/ruby/core/thread/keys_spec.rb b/spec/ruby/core/thread/keys_spec.rb
index 15efda51d6..3a2edd2456 100644
--- a/spec/ruby/core/thread/keys_spec.rb
+++ b/spec/ruby/core/thread/keys_spec.rb
@@ -16,22 +16,22 @@ describe "Thread#keys" do
fib = Fiber.new do
Thread.current[:val1] = 1
Fiber.yield
- Thread.current.keys.should include(:val1)
- Thread.current.keys.should_not include(:val2)
+ Thread.current.keys.should.include?(:val1)
+ Thread.current.keys.should_not.include?(:val2)
end
- Thread.current.keys.should_not include(:val1)
+ Thread.current.keys.should_not.include?(:val1)
fib.resume
Thread.current[:val2] = 2
fib.resume
- Thread.current.keys.should include(:val2)
- Thread.current.keys.should_not include(:val1)
+ Thread.current.keys.should.include?(:val2)
+ Thread.current.keys.should_not.include?(:val1)
end
it "stores a local in another thread when in a fiber" do
fib = Fiber.new do
t = Thread.new do
sleep
- Thread.current.keys.should include(:value)
+ Thread.current.keys.should.include?(:value)
end
Thread.pass while t.status and t.status != "sleep"
diff --git a/spec/ruby/core/thread/kill_spec.rb b/spec/ruby/core/thread/kill_spec.rb
index 4b62c686c7..907cc5c4d8 100644
--- a/spec/ruby/core/thread/kill_spec.rb
+++ b/spec/ruby/core/thread/kill_spec.rb
@@ -1,12 +1,221 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
-require_relative 'shared/exit'
# This spec randomly kills mspec worker like: https://ci.appveyor.com/project/ruby/ruby/builds/19473223/job/f69derxnlo09xhuj
# TODO: Investigate the cause or at least print helpful logs, and remove this `platform_is_not` guard.
platform_is_not :mingw do
describe "Thread#kill" do
- it_behaves_like :thread_exit, :kill
+ before :each do
+ ScratchPad.clear
+ end
+
+ it "kills sleeping thread" do
+ sleeping_thread = Thread.new do
+ sleep
+ ScratchPad.record :after_sleep
+ end
+ Thread.pass while sleeping_thread.status and sleeping_thread.status != "sleep"
+ sleeping_thread.kill
+ sleeping_thread.join
+ ScratchPad.recorded.should == nil
+ end
+
+ it "kills current thread" do
+ thread = Thread.new do
+ Thread.current.kill
+ ScratchPad.record :after_sleep
+ end
+ thread.join
+ ScratchPad.recorded.should == nil
+ end
+
+ it "runs ensure clause" do
+ thread = ThreadSpecs.dying_thread_ensures(:kill) { ScratchPad.record :in_ensure_clause }
+ thread.join
+ ScratchPad.recorded.should == :in_ensure_clause
+ end
+
+ it "runs nested ensure clauses" do
+ ScratchPad.record []
+ @outer = Thread.new do
+ begin
+ @inner = Thread.new do
+ begin
+ sleep
+ ensure
+ ScratchPad << :inner_ensure_clause
+ end
+ end
+ sleep
+ ensure
+ ScratchPad << :outer_ensure_clause
+ @inner.kill
+ @inner.join
+ end
+ end
+ Thread.pass while @outer.status and @outer.status != "sleep"
+ Thread.pass until @inner
+ Thread.pass while @inner.status and @inner.status != "sleep"
+ @outer.kill
+ @outer.join
+ ScratchPad.recorded.should.include?(:inner_ensure_clause)
+ ScratchPad.recorded.should.include?(:outer_ensure_clause)
+ end
+
+ it "does not set $!" do
+ thread = ThreadSpecs.dying_thread_ensures(:kill) { ScratchPad.record $! }
+ thread.join
+ ScratchPad.recorded.should == nil
+ end
+
+ it "does not reset $!" do
+ ScratchPad.record []
+
+ exc = RuntimeError.new("foo")
+ thread = Thread.new do
+ begin
+ raise exc
+ ensure
+ ScratchPad << $!
+ begin
+ Thread.current.kill
+ ensure
+ ScratchPad << $!
+ end
+ end
+ end
+ thread.join
+ ScratchPad.recorded.should == [exc, exc]
+ end
+
+ it "cannot be rescued" do
+ thread = Thread.new do
+ begin
+ Thread.current.kill
+ rescue Exception
+ ScratchPad.record :in_rescue
+ end
+ ScratchPad.record :end_of_thread_block
+ end
+
+ thread.join
+ ScratchPad.recorded.should == nil
+ end
+
+ it "kills the entire thread when a fiber is active" do
+ t = Thread.new do
+ Fiber.new do
+ sleep
+ end.resume
+ ScratchPad.record :fiber_resumed
+ end
+ Thread.pass while t.status and t.status != "sleep"
+ t.kill
+ t.join
+ 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.kill
+ 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
+ in_ensure_clause = false
+ exit_loop = true
+ t = ThreadSpecs.dying_thread_ensures do
+ in_ensure_clause = true
+ loop { if exit_loop then break end }
+ ScratchPad.record :after_stop
+ end
+
+ Thread.pass until in_ensure_clause == true
+ 10.times { t.kill; Thread.pass }
+ exit_loop = true
+ t.join
+ ScratchPad.recorded.should == :after_stop
+ end
+ end
+
+ quarantine! do
+
+ it "propagates inner exception to Thread.join if there is an outer ensure clause" do
+ thread = ThreadSpecs.dying_thread_with_outer_ensure(:kill) { }
+ -> { thread.join }.should.raise(RuntimeError, "In dying thread")
+ end
+
+ it "runs all outer ensure clauses even if inner ensure clause raises exception" do
+ ThreadSpecs.join_dying_thread_with_outer_ensure(:kill) { ScratchPad.record :in_outer_ensure_clause }
+ ScratchPad.recorded.should == :in_outer_ensure_clause
+ end
+
+ it "sets $! in outer ensure clause if inner ensure clause raises exception" do
+ ThreadSpecs.join_dying_thread_with_outer_ensure(:kill) { ScratchPad.record $! }
+ ScratchPad.recorded.to_s.should == "In dying thread"
+ end
+ end
+
+ it "can be rescued by outer rescue clause when inner ensure clause raises exception" do
+ thread = Thread.new do
+ begin
+ begin
+ Thread.current.kill
+ ensure
+ raise "In dying thread"
+ end
+ rescue Exception
+ ScratchPad.record $!
+ end
+ :end_of_thread_block
+ end
+
+ thread.value.should == :end_of_thread_block
+ ScratchPad.recorded.to_s.should == "In dying thread"
+ end
+
+ it "is deferred if ensure clause does Thread.stop" do
+ ThreadSpecs.wakeup_dying_sleeping_thread(:kill) { Thread.stop; ScratchPad.record :after_sleep }
+ ScratchPad.recorded.should == :after_sleep
+ end
+
+ # Hangs on 1.8.6.114 OS X, possibly also on Linux
+ quarantine! do
+ it "is deferred if ensure clause sleeps" do
+ ThreadSpecs.wakeup_dying_sleeping_thread(:kill) { sleep; ScratchPad.record :after_sleep }
+ ScratchPad.recorded.should == :after_sleep
+ end
+ end
+
+ # This case occurred in JRuby where native threads are used to provide
+ # the same behavior as MRI green threads. Key to this issue was the fact
+ # that the thread which called #exit in its block was also being explicitly
+ # sent #join from outside the thread. The 100.times provides a certain
+ # probability that the deadlock will occur. It was sufficient to reliably
+ # reproduce the deadlock in JRuby.
+ it "does not deadlock when called from within the thread while being joined from without" do
+ 100.times do
+ t = Thread.new { Thread.stop; Thread.current.kill }
+ Thread.pass while t.status and t.status != "sleep"
+ t.wakeup.should == t
+ t.join.should == t
+ end
+ end
end
describe "Thread.kill" do
@@ -15,7 +224,7 @@ platform_is_not :mingw do
Thread.pass while thread.status and thread.status != "sleep"
Thread.kill(thread).should == thread
thread.join
- thread.status.should be_false
+ thread.status.should == false
end
end
end
diff --git a/spec/ruby/core/thread/list_spec.rb b/spec/ruby/core/thread/list_spec.rb
index 3c6f70c13e..5036841d58 100644
--- a/spec/ruby/core/thread/list_spec.rb
+++ b/spec/ruby/core/thread/list_spec.rb
@@ -3,15 +3,15 @@ require_relative 'fixtures/classes'
describe "Thread.list" do
it "includes the current and main thread" do
- Thread.list.should include(Thread.current)
- Thread.list.should include(Thread.main)
+ Thread.list.should.include?(Thread.current)
+ Thread.list.should.include?(Thread.main)
end
it "includes threads of non-default thread groups" do
t = Thread.new { sleep }
begin
ThreadGroup.new.add(t)
- Thread.list.should include(t)
+ Thread.list.should.include?(t)
ensure
t.kill
t.join
@@ -21,7 +21,7 @@ describe "Thread.list" do
it "does not include deceased threads" do
t = Thread.new { 1; }
t.join
- Thread.list.should_not include(t)
+ Thread.list.should_not.include?(t)
end
it "includes waiting threads" do
@@ -29,7 +29,7 @@ describe "Thread.list" do
t = Thread.new { q.pop }
begin
Thread.pass while t.status and t.status != 'sleep'
- Thread.list.should include(t)
+ Thread.list.should.include?(t)
ensure
q << nil
t.join
@@ -45,7 +45,7 @@ describe "Thread.list" do
begin
Thread.list.each { |th|
- th.should be_kind_of(Thread)
+ th.should.is_a?(Thread)
}
end while spawner.alive?
diff --git a/spec/ruby/core/thread/name_spec.rb b/spec/ruby/core/thread/name_spec.rb
index 9b3d2f4b09..47d807be4d 100644
--- a/spec/ruby/core/thread/name_spec.rb
+++ b/spec/ruby/core/thread/name_spec.rb
@@ -36,7 +36,7 @@ describe "Thread#name=" do
it "raises an ArgumentError if the name includes a null byte" do
-> {
@thread.name = "new thread\0name"
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
it "can be reset to nil" do
diff --git a/spec/ruby/core/thread/native_thread_id_spec.rb b/spec/ruby/core/thread/native_thread_id_spec.rb
index 374cc59279..cc72e0b853 100644
--- a/spec/ruby/core/thread/native_thread_id_spec.rb
+++ b/spec/ruby/core/thread/native_thread_id_spec.rb
@@ -3,7 +3,7 @@ require_relative '../../spec_helper'
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)
+ Thread.current.native_thread_id.should.is_a?(Integer)
end
it "returns nil when the thread is not running" do
@@ -18,12 +18,8 @@ platform_is :linux, :darwin, :windows, :freebsd do
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
+ # native_thread_id can be nil on a M:N scheduler
+ t_thread_id.should.is_a?(Integer) if t_thread_id != nil
main_thread_id.should_not == t_thread_id
diff --git a/spec/ruby/core/thread/new_spec.rb b/spec/ruby/core/thread/new_spec.rb
index 47a836201c..acb6cd4e30 100644
--- a/spec/ruby/core/thread/new_spec.rb
+++ b/spec/ruby/core/thread/new_spec.rb
@@ -18,7 +18,7 @@ describe "Thread.new" do
end
it "raises an exception when not given a block" do
- -> { Thread.new }.should raise_error(ThreadError)
+ -> { Thread.new }.should.raise(ThreadError)
end
it "creates a subclass of thread calls super with a block in initialize" do
@@ -36,7 +36,7 @@ describe "Thread.new" do
-> {
c.new
- }.should raise_error(ThreadError)
+ }.should.raise(ThreadError)
end
it "calls and respects #initialize for the block to use" do
diff --git a/spec/ruby/core/thread/pending_interrupt_spec.rb b/spec/ruby/core/thread/pending_interrupt_spec.rb
index cd565d92a4..5fbe7422a9 100644
--- a/spec/ruby/core/thread/pending_interrupt_spec.rb
+++ b/spec/ruby/core/thread/pending_interrupt_spec.rb
@@ -19,7 +19,7 @@ describe "Thread.pending_interrupt?" do
Thread.pending_interrupt?.should == true
executed = true
end
- }.should raise_error(RuntimeError, "interrupt")
+ }.should.raise(RuntimeError, "interrupt")
executed.should == true
Thread.pending_interrupt?.should == false
end
diff --git a/spec/ruby/core/thread/priority_spec.rb b/spec/ruby/core/thread/priority_spec.rb
index e13ad478b5..970f7f9971 100644
--- a/spec/ruby/core/thread/priority_spec.rb
+++ b/spec/ruby/core/thread/priority_spec.rb
@@ -15,19 +15,19 @@ describe "Thread#priority" do
end
it "inherits the priority of the current thread while running" do
- @thread.alive?.should be_true
+ @thread.alive?.should == true
@thread.priority.should == @current_priority
end
it "maintain the priority of the current thread after death" do
ThreadSpecs.state = :exit
@thread.join
- @thread.alive?.should be_false
+ @thread.alive?.should == false
@thread.priority.should == @current_priority
end
it "returns an integer" do
- @thread.priority.should be_kind_of(Integer)
+ @thread.priority.should.is_a?(Integer)
end
end
@@ -59,7 +59,7 @@ describe "Thread#priority=" do
describe "when set with a non-integer" do
it "raises a type error" do
- ->{ @thread.priority = Object.new }.should raise_error(TypeError)
+ ->{ @thread.priority = Object.new }.should.raise(TypeError)
end
end
diff --git a/spec/ruby/core/thread/raise_spec.rb b/spec/ruby/core/thread/raise_spec.rb
index b473eabd42..efc09d4a35 100644
--- a/spec/ruby/core/thread/raise_spec.rb
+++ b/spec/ruby/core/thread/raise_spec.rb
@@ -3,8 +3,15 @@ require_relative 'fixtures/classes'
require_relative '../../shared/kernel/raise'
describe "Thread#raise" do
+ it "is a public method" do
+ Thread.public_instance_methods.should.include?(:raise)
+ end
+
it_behaves_like :kernel_raise, :raise, ThreadSpecs::NewThreadToRaise
it_behaves_like :kernel_raise_across_contexts, :raise, ThreadSpecs::NewThreadToRaise
+ ruby_version_is "4.0" do
+ it_behaves_like :kernel_raise_with_cause, :raise, ThreadSpecs::NewThreadToRaise
+ end
it "ignores dead threads and returns nil" do
t = Thread.new { :dead }
@@ -29,27 +36,27 @@ describe "Thread#raise on a sleeping thread" do
it "raises a RuntimeError if no exception class is given" do
@thr.raise
Thread.pass while @thr.status
- ScratchPad.recorded.should be_kind_of(RuntimeError)
+ ScratchPad.recorded.should.is_a?(RuntimeError)
end
it "raises the given exception" do
@thr.raise Exception
Thread.pass while @thr.status
- ScratchPad.recorded.should be_kind_of(Exception)
+ ScratchPad.recorded.should.is_a?(Exception)
end
it "raises the given exception with the given message" do
@thr.raise Exception, "get to work"
Thread.pass while @thr.status
- ScratchPad.recorded.should be_kind_of(Exception)
+ ScratchPad.recorded.should.is_a?(Exception)
ScratchPad.recorded.message.should == "get to work"
end
it "raises the given exception and the backtrace is the one of the interrupted thread" do
@thr.raise Exception
Thread.pass while @thr.status
- ScratchPad.recorded.should be_kind_of(Exception)
- ScratchPad.recorded.backtrace[0].should include("sleep")
+ ScratchPad.recorded.should.is_a?(Exception)
+ ScratchPad.recorded.backtrace[0].should.include?("sleep")
end
it "is captured and raised by Thread#value" do
@@ -61,7 +68,7 @@ describe "Thread#raise on a sleeping thread" do
ThreadSpecs.spin_until_sleeping(t)
t.raise
- -> { t.value }.should raise_error(RuntimeError)
+ -> { t.value }.should.raise(RuntimeError)
end
it "raises a RuntimeError when called with no arguments inside rescue" do
@@ -79,7 +86,7 @@ describe "Thread#raise on a sleeping thread" do
ThreadSpecs.spin_until_sleeping(t)
t.raise
end
- -> { t.value }.should raise_error(RuntimeError)
+ -> { t.value }.should.raise(RuntimeError)
end
it "re-raises a previously rescued exception without overwriting the backtrace" do
@@ -101,8 +108,8 @@ describe "Thread#raise on a sleeping thread" do
raise_again_line = __LINE__; t.raise raised
raised_again = t.value
- raised_again.backtrace.first.should include("#{__FILE__}:#{initial_raise_line}:")
- raised_again.backtrace.first.should_not include("#{__FILE__}:#{raise_again_line}:")
+ raised_again.backtrace.first.should.include?("#{__FILE__}:#{initial_raise_line}:")
+ raised_again.backtrace.first.should_not.include?("#{__FILE__}:#{raise_again_line}:")
end
end
@@ -129,6 +136,31 @@ describe "Thread#raise on a sleeping thread" do
[ScratchPad.recorded, @thr, []]
]
end
+
+ it "calls #set_backtrace only in the caller thread" do
+ cls = Class.new(Exception) do
+ attr_accessor :log
+ def initialize(*args)
+ @log = [] # This is shared because the super #exception uses a shallow clone
+ super
+ end
+
+ def set_backtrace(backtrace)
+ @log << [Thread.current, backtrace]
+ super
+ end
+ end
+ exc = cls.new
+
+ backtrace = ["a.rb:1"]
+
+ @thr.raise exc, "Thread#raise #set_backtrace spec", backtrace
+ @thr.join
+ ScratchPad.recorded.should.is_a?(cls)
+ exc.log.should == [
+ [Thread.current, backtrace]
+ ]
+ end
end
describe "Thread#raise on a running thread" do
@@ -148,19 +180,19 @@ describe "Thread#raise on a running thread" do
it "raises a RuntimeError if no exception class is given" do
@thr.raise
Thread.pass while @thr.status
- ScratchPad.recorded.should be_kind_of(RuntimeError)
+ ScratchPad.recorded.should.is_a?(RuntimeError)
end
it "raises the given exception" do
@thr.raise Exception
Thread.pass while @thr.status
- ScratchPad.recorded.should be_kind_of(Exception)
+ ScratchPad.recorded.should.is_a?(Exception)
end
it "raises the given exception with the given message" do
@thr.raise Exception, "get to work"
Thread.pass while @thr.status
- ScratchPad.recorded.should be_kind_of(Exception)
+ ScratchPad.recorded.should.is_a?(Exception)
ScratchPad.recorded.message.should == "get to work"
end
@@ -174,7 +206,7 @@ describe "Thread#raise on a running thread" do
q.pop # wait for `report_on_exception = false`.
t.raise
- -> { t.value }.should raise_error(RuntimeError)
+ -> { t.value }.should.raise(RuntimeError)
end
it "raises the given argument even when there is an active exception" do
@@ -193,7 +225,7 @@ describe "Thread#raise on a running thread" do
rescue
Thread.pass until raised
t.raise RangeError
- -> { t.value }.should raise_error(RangeError)
+ -> { t.value }.should.raise(RangeError)
end
end
@@ -214,7 +246,7 @@ describe "Thread#raise on a running thread" do
Thread.pass until raised
t.raise
end
- -> { t.value }.should raise_error(RuntimeError)
+ -> { t.value }.should.raise(RuntimeError)
end
end
@@ -230,6 +262,6 @@ describe "Thread#raise on same thread" do
Thread.current.raise
end
end
- -> { t.value }.should raise_error(RuntimeError, '')
+ -> { t.value }.should.raise(RuntimeError, '')
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..9cf5260808 100644
--- a/spec/ruby/core/thread/report_on_exception_spec.rb
+++ b/spec/ruby/core/thread/report_on_exception_spec.rb
@@ -58,7 +58,7 @@ describe "Thread#report_on_exception=" do
-> {
t.join
- }.should raise_error(RuntimeError, "Thread#report_on_exception specs")
+ }.should.raise(RuntimeError, "Thread#report_on_exception specs")
end
it "prints a backtrace on $stderr in the regular backtrace order" do
@@ -86,7 +86,7 @@ describe "Thread#report_on_exception=" do
-> {
t.join
- }.should raise_error(RuntimeError, "Thread#report_on_exception specs backtrace order")
+ }.should.raise(RuntimeError, "Thread#report_on_exception specs backtrace order")
end
it "prints the backtrace even if the thread was killed just after Thread#raise" do
@@ -107,7 +107,7 @@ describe "Thread#report_on_exception=" do
-> {
t.join
- }.should raise_error(RuntimeError, "Thread#report_on_exception before kill spec")
+ }.should.raise(RuntimeError, "Thread#report_on_exception before kill spec")
end
end
@@ -124,7 +124,7 @@ describe "Thread#report_on_exception=" do
-> {
t.join
- }.should raise_error(RuntimeError, "Thread#report_on_exception specs")
+ }.should.raise(RuntimeError, "Thread#report_on_exception specs")
end
end
@@ -144,12 +144,12 @@ describe "Thread#report_on_exception=" do
-> {
mutex.sleep(5)
- }.should raise_error(RuntimeError, "Thread#report_on_exception specs")
+ }.should.raise(RuntimeError, "Thread#report_on_exception specs")
}.should output("", /Thread.+terminated with exception.+Thread#report_on_exception specs/m)
-> {
t.join
- }.should raise_error(RuntimeError, "Thread#report_on_exception specs")
+ }.should.raise(RuntimeError, "Thread#report_on_exception specs")
end
end
end
diff --git a/spec/ruby/core/thread/shared/exit.rb b/spec/ruby/core/thread/shared/exit.rb
deleted file mode 100644
index 13e8832684..0000000000
--- a/spec/ruby/core/thread/shared/exit.rb
+++ /dev/null
@@ -1,219 +0,0 @@
-describe :thread_exit, shared: true do
- before :each do
- ScratchPad.clear
- end
-
- # This spec randomly kills mspec worker like: https://ci.appveyor.com/project/ruby/ruby/builds/19390874/job/wv1bsm8skd4e1pxl
- # TODO: Investigate the cause or at least print helpful logs, and remove this `platform_is_not` guard.
- platform_is_not :mingw do
-
- it "kills sleeping thread" do
- sleeping_thread = Thread.new do
- sleep
- ScratchPad.record :after_sleep
- end
- Thread.pass while sleeping_thread.status and sleeping_thread.status != "sleep"
- sleeping_thread.send(@method)
- sleeping_thread.join
- ScratchPad.recorded.should == nil
- end
-
- it "kills current thread" do
- thread = Thread.new do
- Thread.current.send(@method)
- ScratchPad.record :after_sleep
- end
- thread.join
- ScratchPad.recorded.should == nil
- end
-
- it "runs ensure clause" do
- thread = ThreadSpecs.dying_thread_ensures(@method) { ScratchPad.record :in_ensure_clause }
- thread.join
- ScratchPad.recorded.should == :in_ensure_clause
- end
-
- it "runs nested ensure clauses" do
- ScratchPad.record []
- @outer = Thread.new do
- begin
- @inner = Thread.new do
- begin
- sleep
- ensure
- ScratchPad << :inner_ensure_clause
- end
- end
- sleep
- ensure
- ScratchPad << :outer_ensure_clause
- @inner.send(@method)
- @inner.join
- end
- end
- Thread.pass while @outer.status and @outer.status != "sleep"
- Thread.pass until @inner
- Thread.pass while @inner.status and @inner.status != "sleep"
- @outer.send(@method)
- @outer.join
- ScratchPad.recorded.should include(:inner_ensure_clause)
- ScratchPad.recorded.should include(:outer_ensure_clause)
- end
-
- it "does not set $!" do
- thread = ThreadSpecs.dying_thread_ensures(@method) { ScratchPad.record $! }
- thread.join
- ScratchPad.recorded.should == nil
- end
-
- it "does not reset $!" do
- ScratchPad.record []
-
- exc = RuntimeError.new("foo")
- thread = Thread.new do
- begin
- raise exc
- ensure
- ScratchPad << $!
- begin
- Thread.current.send(@method)
- ensure
- ScratchPad << $!
- end
- end
- end
- thread.join
- ScratchPad.recorded.should == [exc, exc]
- end
-
- it "cannot be rescued" do
- thread = Thread.new do
- begin
- Thread.current.send(@method)
- rescue Exception
- ScratchPad.record :in_rescue
- end
- ScratchPad.record :end_of_thread_block
- end
-
- thread.join
- ScratchPad.recorded.should == nil
- end
-
- it "kills the entire thread when a fiber is active" do
- t = Thread.new do
- Fiber.new do
- sleep
- end.resume
- ScratchPad.record :fiber_resumed
- end
- Thread.pass while t.status and t.status != "sleep"
- t.send(@method)
- t.join
- 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
- in_ensure_clause = false
- exit_loop = true
- t = ThreadSpecs.dying_thread_ensures do
- in_ensure_clause = true
- loop { if exit_loop then break end }
- ScratchPad.record :after_stop
- end
-
- Thread.pass until in_ensure_clause == true
- 10.times { t.send(@method); Thread.pass }
- exit_loop = true
- t.join
- ScratchPad.recorded.should == :after_stop
- end
- end
-
- quarantine! do
-
- it "propagates inner exception to Thread.join if there is an outer ensure clause" do
- thread = ThreadSpecs.dying_thread_with_outer_ensure(@method) { }
- -> { thread.join }.should raise_error(RuntimeError, "In dying thread")
- end
-
- it "runs all outer ensure clauses even if inner ensure clause raises exception" do
- ThreadSpecs.join_dying_thread_with_outer_ensure(@method) { ScratchPad.record :in_outer_ensure_clause }
- ScratchPad.recorded.should == :in_outer_ensure_clause
- end
-
- it "sets $! in outer ensure clause if inner ensure clause raises exception" do
- ThreadSpecs.join_dying_thread_with_outer_ensure(@method) { ScratchPad.record $! }
- ScratchPad.recorded.to_s.should == "In dying thread"
- end
- end
-
- it "can be rescued by outer rescue clause when inner ensure clause raises exception" do
- thread = Thread.new do
- begin
- begin
- Thread.current.send(@method)
- ensure
- raise "In dying thread"
- end
- rescue Exception
- ScratchPad.record $!
- end
- :end_of_thread_block
- end
-
- thread.value.should == :end_of_thread_block
- ScratchPad.recorded.to_s.should == "In dying thread"
- end
-
- it "is deferred if ensure clause does Thread.stop" do
- ThreadSpecs.wakeup_dying_sleeping_thread(@method) { Thread.stop; ScratchPad.record :after_sleep }
- ScratchPad.recorded.should == :after_sleep
- end
-
- # Hangs on 1.8.6.114 OS X, possibly also on Linux
- quarantine! do
- it "is deferred if ensure clause sleeps" do
- ThreadSpecs.wakeup_dying_sleeping_thread(@method) { sleep; ScratchPad.record :after_sleep }
- ScratchPad.recorded.should == :after_sleep
- end
- end
-
- # This case occurred in JRuby where native threads are used to provide
- # the same behavior as MRI green threads. Key to this issue was the fact
- # that the thread which called #exit in its block was also being explicitly
- # sent #join from outside the thread. The 100.times provides a certain
- # probability that the deadlock will occur. It was sufficient to reliably
- # reproduce the deadlock in JRuby.
- it "does not deadlock when called from within the thread while being joined from without" do
- 100.times do
- t = Thread.new { Thread.stop; Thread.current.send(@method) }
- Thread.pass while t.status and t.status != "sleep"
- t.wakeup.should == t
- t.join.should == t
- end
- end
-
- end # platform_is_not :mingw
-end
diff --git a/spec/ruby/core/thread/shared/start.rb b/spec/ruby/core/thread/shared/start.rb
deleted file mode 100644
index 2ba926bf00..0000000000
--- a/spec/ruby/core/thread/shared/start.rb
+++ /dev/null
@@ -1,41 +0,0 @@
-describe :thread_start, shared: true do
- before :each do
- ScratchPad.clear
- end
-
- it "raises an ArgumentError if not passed a block" do
- -> {
- Thread.send(@method)
- }.should raise_error(ArgumentError)
- end
-
- it "spawns a new Thread running the block" do
- run = false
- t = Thread.send(@method) { run = true }
- t.should be_kind_of(Thread)
- t.join
-
- run.should be_true
- end
-
- it "respects Thread subclasses" do
- c = Class.new(Thread)
- t = c.send(@method) { }
- t.should be_kind_of(c)
-
- t.join
- end
-
- it "does not call #initialize" do
- c = Class.new(Thread) do
- def initialize
- ScratchPad.record :bad
- end
- end
-
- t = c.send(@method) { }
- t.join
-
- ScratchPad.recorded.should == nil
- end
-end
diff --git a/spec/ruby/core/thread/shared/to_s.rb b/spec/ruby/core/thread/shared/to_s.rb
deleted file mode 100644
index 43640deb33..0000000000
--- a/spec/ruby/core/thread/shared/to_s.rb
+++ /dev/null
@@ -1,53 +0,0 @@
-require_relative '../fixtures/classes'
-
-describe :thread_to_s, shared: true do
- it "returns a description including file and line number" do
- thread, line = Thread.new { "hello" }, __LINE__
- thread.join
- thread.send(@method).should =~ /^#<Thread:([^ ]*?) #{Regexp.escape __FILE__}:#{line} \w+>$/
- end
-
- it "has a binary encoding" do
- ThreadSpecs.status_of_current_thread.send(@method).encoding.should == Encoding::BINARY
- end
-
- it "can check it's own status" do
- ThreadSpecs.status_of_current_thread.send(@method).should include('run')
- end
-
- it "describes a running thread" do
- ThreadSpecs.status_of_running_thread.send(@method).should include('run')
- end
-
- it "describes a sleeping thread" do
- ThreadSpecs.status_of_sleeping_thread.send(@method).should include('sleep')
- end
-
- it "describes a blocked thread" do
- ThreadSpecs.status_of_blocked_thread.send(@method).should include('sleep')
- end
-
- it "describes a completed thread" do
- ThreadSpecs.status_of_completed_thread.send(@method).should include('dead')
- end
-
- it "describes a killed thread" do
- ThreadSpecs.status_of_killed_thread.send(@method).should include('dead')
- end
-
- it "describes a thread with an uncaught exception" do
- ThreadSpecs.status_of_thread_with_uncaught_exception.send(@method).should include('dead')
- end
-
- it "describes a dying sleeping thread" do
- ThreadSpecs.status_of_dying_sleeping_thread.send(@method).should include('sleep')
- end
-
- it "reports aborting on a killed thread" do
- ThreadSpecs.status_of_dying_running_thread.send(@method).should include('aborting')
- end
-
- it "reports aborting on a killed thread after sleep" do
- ThreadSpecs.status_of_dying_thread_after_sleep.send(@method).should include('aborting')
- end
-end
diff --git a/spec/ruby/core/thread/shared/wakeup.rb b/spec/ruby/core/thread/shared/wakeup.rb
index 6f010fea25..c89235ba60 100644
--- a/spec/ruby/core/thread/shared/wakeup.rb
+++ b/spec/ruby/core/thread/shared/wakeup.rb
@@ -57,6 +57,6 @@ describe :thread_wakeup, shared: true do
it "raises a ThreadError when trying to wake up a dead thread" do
t = Thread.new { 1 }
t.join
- -> { t.send @method }.should raise_error(ThreadError)
+ -> { t.send @method }.should.raise(ThreadError)
end
end
diff --git a/spec/ruby/core/thread/start_spec.rb b/spec/ruby/core/thread/start_spec.rb
index 3dd040f98b..a2ee52180b 100644
--- a/spec/ruby/core/thread/start_spec.rb
+++ b/spec/ruby/core/thread/start_spec.rb
@@ -1,9 +1,43 @@
require_relative '../../spec_helper'
-require_relative 'fixtures/classes'
-require_relative 'shared/start'
describe "Thread.start" do
- describe "Thread.start" do
- it_behaves_like :thread_start, :start
+ before :each do
+ ScratchPad.clear
+ end
+
+ it "raises an ArgumentError if not passed a block" do
+ -> {
+ Thread.start
+ }.should.raise(ArgumentError)
+ end
+
+ it "spawns a new Thread running the block" do
+ run = false
+ t = Thread.start { run = true }
+ t.should.is_a?(Thread)
+ t.join
+
+ run.should == true
+ end
+
+ it "respects Thread subclasses" do
+ c = Class.new(Thread)
+ t = c.start { }
+ t.should.is_a?(c)
+
+ t.join
+ end
+
+ it "does not call #initialize" do
+ c = Class.new(Thread) do
+ def initialize
+ ScratchPad.record :bad
+ end
+ end
+
+ t = c.start { }
+ t.join
+
+ ScratchPad.recorded.should == nil
end
end
diff --git a/spec/ruby/core/thread/terminate_spec.rb b/spec/ruby/core/thread/terminate_spec.rb
index cf6cab472b..68c431a0c0 100644
--- a/spec/ruby/core/thread/terminate_spec.rb
+++ b/spec/ruby/core/thread/terminate_spec.rb
@@ -1,7 +1,7 @@
require_relative '../../spec_helper'
-require_relative 'fixtures/classes'
-require_relative 'shared/exit'
describe "Thread#terminate" do
- it_behaves_like :thread_exit, :terminate
+ it "is an alias of Thread#kill" do
+ Thread.instance_method(:terminate).should == Thread.instance_method(:kill)
+ end
end
diff --git a/spec/ruby/core/thread/thread_variable_get_spec.rb b/spec/ruby/core/thread/thread_variable_get_spec.rb
index 1ea34cf2b3..3d92cd5479 100644
--- a/spec/ruby/core/thread/thread_variable_get_spec.rb
+++ b/spec/ruby/core/thread/thread_variable_get_spec.rb
@@ -10,7 +10,7 @@ describe "Thread#thread_variable_get" do
end
it "returns nil if the variable is not set" do
- @t.thread_variable_get(:a).should be_nil
+ @t.thread_variable_get(:a).should == nil
end
it "returns the value previously set by #thread_variable_set" do
@@ -20,7 +20,7 @@ describe "Thread#thread_variable_get" do
it "returns a value private to self" do
@t.thread_variable_set(:thread_variable_get_spec, 82)
- Thread.current.thread_variable_get(:thread_variable_get_spec).should be_nil
+ Thread.current.thread_variable_get(:thread_variable_get_spec).should == nil
end
it "accepts String and Symbol keys interchangeably" do
@@ -38,23 +38,23 @@ describe "Thread#thread_variable_get" do
it "does not raise FrozenError if the thread is frozen" do
@t.freeze
- @t.thread_variable_get(:a).should be_nil
+ @t.thread_variable_get(:a).should == 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/)
+ -> { @t.thread_variable_get(123) }.should.raise(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/)
+ -> { @t.thread_variable_get(123) }.should.raise(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/)
+ -> { @t.thread_variable_get(key) }.should.raise(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..f8d25364ae 100644
--- a/spec/ruby/core/thread/thread_variable_set_spec.rb
+++ b/spec/ruby/core/thread/thread_variable_set_spec.rb
@@ -21,7 +21,7 @@ describe "Thread#thread_variable_set" do
it "sets a value private to self" do
@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
+ Thread.current.thread_variable_get(:thread_variable_get_spec).should == nil
end
it "accepts String and Symbol keys interchangeably" do
@@ -42,21 +42,21 @@ describe "Thread#thread_variable_set" do
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
+ @t.thread_variable?(:a).should == 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")
+ -> { @t.thread_variable_set(:a, 1) }.should.raise(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/)
+ -> { @t.thread_variable_set(123, 1) }.should.raise(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/)
+ -> { @t.thread_variable_set(key, 42) }.should.raise(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..ebafd4f3eb 100644
--- a/spec/ruby/core/thread/thread_variable_spec.rb
+++ b/spec/ruby/core/thread/thread_variable_spec.rb
@@ -11,50 +11,50 @@ describe "Thread#thread_variable?" do
it "returns false if the thread variables do not contain 'key'" do
@t.thread_variable_set(:a, 2)
- @t.thread_variable?(:b).should be_false
+ @t.thread_variable?(:b).should == false
end
it "returns true if the thread variables contain 'key'" do
@t.thread_variable_set(:a, 2)
- @t.thread_variable?(:a).should be_true
+ @t.thread_variable?(:a).should == 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?('a').should == false
+ @t.thread_variable?(:a).should == false
@t.thread_variable_set(:a, 49)
- @t.thread_variable?('a').should be_true
- @t.thread_variable?(:a).should be_true
+ @t.thread_variable?('a').should == true
+ @t.thread_variable?(:a).should == 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
+ @t.thread_variable?(key).should == true
end
it "does not raise FrozenError if the thread is frozen" do
@t.freeze
- @t.thread_variable?(:a).should be_false
+ @t.thread_variable?(:a).should == 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/)
+ -> { @t.thread_variable?(123) }.should.raise(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/)
+ -> { @t.thread_variable?(123) }.should.raise(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/)
+ -> { @t.thread_variable?(key) }.should.raise(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..f15c681a8f 100644
--- a/spec/ruby/core/thread/thread_variables_spec.rb
+++ b/spec/ruby/core/thread/thread_variables_spec.rb
@@ -19,7 +19,8 @@ describe "Thread#thread_variables" do
it "returns the keys 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)
+ Thread.current.thread_variables.should_not.include?(:a)
+ Thread.current.thread_variables.should_not.include?(:b)
end
it "only contains user thread variables and is empty initially" do
diff --git a/spec/ruby/core/thread/to_s_spec.rb b/spec/ruby/core/thread/to_s_spec.rb
index cb182a017f..2aef426de8 100644
--- a/spec/ruby/core/thread/to_s_spec.rb
+++ b/spec/ruby/core/thread/to_s_spec.rb
@@ -1,6 +1,54 @@
require_relative '../../spec_helper'
-require_relative 'shared/to_s'
+require_relative 'fixtures/classes'
describe "Thread#to_s" do
- it_behaves_like :thread_to_s, :to_s
+ it "returns a description including file and line number" do
+ thread, line = Thread.new { "hello" }, __LINE__
+ thread.join
+ thread.to_s.should =~ /^#<Thread:([^ ]*?) #{Regexp.escape __FILE__}:#{line} \w+>$/
+ end
+
+ it "has a binary encoding" do
+ ThreadSpecs.status_of_current_thread.to_s.encoding.should == Encoding::BINARY
+ end
+
+ it "can check it's own status" do
+ ThreadSpecs.status_of_current_thread.to_s.should.include?('run')
+ end
+
+ it "describes a running thread" do
+ ThreadSpecs.status_of_running_thread.to_s.should.include?('run')
+ end
+
+ it "describes a sleeping thread" do
+ ThreadSpecs.status_of_sleeping_thread.to_s.should.include?('sleep')
+ end
+
+ it "describes a blocked thread" do
+ ThreadSpecs.status_of_blocked_thread.to_s.should.include?('sleep')
+ end
+
+ it "describes a completed thread" do
+ ThreadSpecs.status_of_completed_thread.to_s.should.include?('dead')
+ end
+
+ it "describes a killed thread" do
+ ThreadSpecs.status_of_killed_thread.to_s.should.include?('dead')
+ end
+
+ it "describes a thread with an uncaught exception" do
+ ThreadSpecs.status_of_thread_with_uncaught_exception.to_s.should.include?('dead')
+ end
+
+ it "describes a dying sleeping thread" do
+ ThreadSpecs.status_of_dying_sleeping_thread.to_s.should.include?('sleep')
+ end
+
+ it "reports aborting on a killed thread" do
+ ThreadSpecs.status_of_dying_running_thread.to_s.should.include?('aborting')
+ end
+
+ it "reports aborting on a killed thread after sleep" do
+ ThreadSpecs.status_of_dying_thread_after_sleep.to_s.should.include?('aborting')
+ end
end
diff --git a/spec/ruby/core/thread/value_spec.rb b/spec/ruby/core/thread/value_spec.rb
index 30e43abd1a..50c823171d 100644
--- a/spec/ruby/core/thread/value_spec.rb
+++ b/spec/ruby/core/thread/value_spec.rb
@@ -11,7 +11,7 @@ describe "Thread#value" do
Thread.current.report_on_exception = false
raise "Hello"
}
- -> { t.value }.should raise_error(RuntimeError, "Hello")
+ -> { t.value }.should.raise(RuntimeError, "Hello")
end
it "is nil for a killed thread" do
diff --git a/spec/ruby/core/threadgroup/default_spec.rb b/spec/ruby/core/threadgroup/default_spec.rb
index d7d4726cc2..4f57508abf 100644
--- a/spec/ruby/core/threadgroup/default_spec.rb
+++ b/spec/ruby/core/threadgroup/default_spec.rb
@@ -2,7 +2,7 @@ require_relative '../../spec_helper'
describe "ThreadGroup::Default" do
it "is a ThreadGroup instance" do
- ThreadGroup::Default.should be_kind_of(ThreadGroup)
+ ThreadGroup::Default.should.is_a?(ThreadGroup)
end
it "is the ThreadGroup of the main thread" do
diff --git a/spec/ruby/core/threadgroup/enclose_spec.rb b/spec/ruby/core/threadgroup/enclose_spec.rb
index dd9a7a362d..6f703d4ce2 100644
--- a/spec/ruby/core/threadgroup/enclose_spec.rb
+++ b/spec/ruby/core/threadgroup/enclose_spec.rb
@@ -19,6 +19,6 @@ describe "ThreadGroup#enclose" do
thread_group.enclose
-> do
default_group.add(@thread)
- end.should raise_error(ThreadError)
+ end.should.raise(ThreadError)
end
end
diff --git a/spec/ruby/core/threadgroup/enclosed_spec.rb b/spec/ruby/core/threadgroup/enclosed_spec.rb
index a734256a64..cf8a5bb4c6 100644
--- a/spec/ruby/core/threadgroup/enclosed_spec.rb
+++ b/spec/ruby/core/threadgroup/enclosed_spec.rb
@@ -3,12 +3,12 @@ require_relative '../../spec_helper'
describe "ThreadGroup#enclosed?" do
it "returns false when a ThreadGroup has not been enclosed (default state)" do
thread_group = ThreadGroup.new
- thread_group.enclosed?.should be_false
+ thread_group.enclosed?.should == false
end
it "returns true when a ThreadGroup is enclosed" do
thread_group = ThreadGroup.new
thread_group.enclose
- thread_group.enclosed?.should be_true
+ thread_group.enclosed?.should == true
end
end
diff --git a/spec/ruby/core/threadgroup/list_spec.rb b/spec/ruby/core/threadgroup/list_spec.rb
index b2ac64324a..ef601d75ea 100644
--- a/spec/ruby/core/threadgroup/list_spec.rb
+++ b/spec/ruby/core/threadgroup/list_spec.rb
@@ -7,13 +7,13 @@ describe "ThreadGroup#list" do
q.pop.should == :go
tg = ThreadGroup.new
tg.add(th1)
- tg.list.should include(th1)
+ tg.list.should.include?(th1)
th2 = Thread.new { q << :go; sleep }
q.pop.should == :go
tg.add(th2)
- (tg.list & [th1, th2]).should include(th1, th2)
+ (tg.list & [th1, th2]).to_set.should == Set[th1, th2]
Thread.pass while th1.status and th1.status != 'sleep'
Thread.pass while th2.status and th2.status != 'sleep'
diff --git a/spec/ruby/core/time/_dump_spec.rb b/spec/ruby/core/time/_dump_spec.rb
index 852f9a07ab..21f0806327 100644
--- a/spec/ruby/core/time/_dump_spec.rb
+++ b/spec/ruby/core/time/_dump_spec.rb
@@ -10,7 +10,7 @@ describe "Time#_dump" do
end
it "is a private method" do
- Time.should have_private_instance_method(:_dump, false)
+ Time.private_instance_methods(false).should.include?(:_dump)
end
# http://redmine.ruby-lang.org/issues/show/627
@@ -25,7 +25,7 @@ describe "Time#_dump" do
end
it "dumps a Time object to a bytestring" do
- @s.should be_an_instance_of(String)
+ @s.should.instance_of?(String)
@s.should == [3222863947, 2235564032].pack("VV")
end
diff --git a/spec/ruby/core/time/_load_spec.rb b/spec/ruby/core/time/_load_spec.rb
index 30899de262..a74e3dc129 100644
--- a/spec/ruby/core/time/_load_spec.rb
+++ b/spec/ruby/core/time/_load_spec.rb
@@ -3,7 +3,7 @@ require_relative '../../spec_helper'
describe "Time._load" do
it "is a private method" do
- Time.should have_private_method(:_load, false)
+ Time.private_methods(false).should.include?(:_load)
end
# http://redmine.ruby-lang.org/issues/show/627
diff --git a/spec/ruby/core/time/asctime_spec.rb b/spec/ruby/core/time/asctime_spec.rb
index a41ee531e4..17e155787a 100644
--- a/spec/ruby/core/time/asctime_spec.rb
+++ b/spec/ruby/core/time/asctime_spec.rb
@@ -1,6 +1,8 @@
require_relative '../../spec_helper'
-require_relative 'shared/asctime'
describe "Time#asctime" do
- it_behaves_like :time_asctime, :asctime
+ it "returns a canonical string representation of time" do
+ t = Time.now
+ t.asctime.should == t.strftime("%a %b %e %H:%M:%S %Y")
+ end
end
diff --git a/spec/ruby/core/time/at_spec.rb b/spec/ruby/core/time/at_spec.rb
index 97906b8c8c..10d4d36a68 100644
--- a/spec/ruby/core/time/at_spec.rb
+++ b/spec/ruby/core/time/at_spec.rb
@@ -20,7 +20,7 @@ describe "Time.at" do
it "returns a subclass instance on a Time subclass" do
c = Class.new(Time)
t = c.at(0)
- t.should be_an_instance_of(c)
+ t.should.instance_of?(c)
end
it "roundtrips a Rational produced by #to_r" do
@@ -56,7 +56,7 @@ describe "Time.at" do
it "creates a dup time object with the value given by time" do
t1 = Time.new
t2 = Time.at(t1)
- t1.should_not equal t2
+ t1.should_not.equal? t2
end
it "returns a UTC time if the argument is UTC" do
@@ -72,17 +72,17 @@ describe "Time.at" do
it "returns a subclass instance" do
c = Class.new(Time)
t = c.at(Time.now)
- t.should be_an_instance_of(c)
+ t.should.instance_of?(c)
end
end
describe "passed non-Time, non-Numeric" do
it "raises a TypeError with a String argument" do
- -> { Time.at("0") }.should raise_error(TypeError)
+ -> { Time.at("0") }.should.raise(TypeError)
end
it "raises a TypeError with a nil argument" do
- -> { Time.at(nil) }.should raise_error(TypeError)
+ -> { Time.at(nil) }.should.raise(TypeError)
end
describe "with an argument that responds to #to_int" do
@@ -103,7 +103,7 @@ describe "Time.at" do
it "needs for the argument to respond to #to_int too" do
o = mock('rational-but-no-to_int')
def o.to_r; Rational(5, 2) end
- -> { Time.at(o) }.should raise_error(TypeError, "can't convert MockObject into an exact number")
+ -> { Time.at(o) }.should.raise(TypeError, "can't convert MockObject into an exact number")
end
end
end
@@ -140,20 +140,20 @@ describe "Time.at" do
describe "passed [Integer, nil]" do
it "raises a TypeError" do
- -> { Time.at(0, nil) }.should raise_error(TypeError)
+ -> { Time.at(0, nil) }.should.raise(TypeError)
end
end
describe "passed [Integer, String]" do
it "raises a TypeError" do
- -> { Time.at(0, "0") }.should raise_error(TypeError)
+ -> { Time.at(0, "0") }.should.raise(TypeError)
end
end
describe "passed [Time, Integer]" do
# #8173
it "raises a TypeError" do
- -> { Time.at(Time.now, 500000) }.should raise_error(TypeError)
+ -> { Time.at(Time.now, 500000) }.should.raise(TypeError)
end
end
@@ -190,15 +190,15 @@ describe "Time.at" do
context "not supported format" do
it "raises ArgumentError" do
- -> { Time.at(0, 123456, 2) }.should raise_error(ArgumentError)
- -> { Time.at(0, 123456, nil) }.should raise_error(ArgumentError)
- -> { Time.at(0, 123456, :invalid) }.should raise_error(ArgumentError)
+ -> { Time.at(0, 123456, 2) }.should.raise(ArgumentError)
+ -> { Time.at(0, 123456, nil) }.should.raise(ArgumentError)
+ -> { Time.at(0, 123456, :invalid) }.should.raise(ArgumentError)
end
it "does not try to convert format to Symbol with #to_sym" do
format = +"usec"
format.should_not_receive(:to_sym)
- -> { Time.at(0, 123456, format) }.should raise_error(ArgumentError)
+ -> { Time.at(0, 123456, format) }.should.raise(ArgumentError)
end
end
@@ -283,33 +283,33 @@ describe "Time.at" do
end
it "raises ArgumentError if format is invalid" do
- -> { Time.at(@epoch_time, in: "+09:99") }.should raise_error(ArgumentError)
- -> { Time.at(@epoch_time, in: "ABC") }.should raise_error(ArgumentError)
+ -> { Time.at(@epoch_time, in: "+09:99") }.should.raise(ArgumentError)
+ -> { Time.at(@epoch_time, in: "ABC") }.should.raise(ArgumentError)
end
it "raises ArgumentError if hours greater than 23" do # TODO
- -> { Time.at(@epoch_time, in: "+24:00") }.should raise_error(ArgumentError, "utc_offset out of range")
- -> { Time.at(@epoch_time, in: "+2400") }.should raise_error(ArgumentError, "utc_offset out of range")
+ -> { Time.at(@epoch_time, in: "+24:00") }.should.raise(ArgumentError, "utc_offset out of range")
+ -> { Time.at(@epoch_time, in: "+2400") }.should.raise(ArgumentError, "utc_offset out of range")
- -> { Time.at(@epoch_time, in: "+99:00") }.should raise_error(ArgumentError, "utc_offset out of range")
- -> { Time.at(@epoch_time, in: "+9900") }.should raise_error(ArgumentError, "utc_offset out of range")
+ -> { Time.at(@epoch_time, in: "+99:00") }.should.raise(ArgumentError, "utc_offset out of range")
+ -> { Time.at(@epoch_time, in: "+9900") }.should.raise(ArgumentError, "utc_offset out of range")
end
it "raises ArgumentError if minutes greater than 59" do # TODO
- -> { Time.at(@epoch_time, in: "+00:60") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +00:60')
- -> { Time.at(@epoch_time, in: "+0060") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +0060')
+ -> { Time.at(@epoch_time, in: "+00:60") }.should.raise(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +00:60')
+ -> { Time.at(@epoch_time, in: "+0060") }.should.raise(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +0060')
- -> { Time.at(@epoch_time, in: "+00:99") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +00:99')
- -> { Time.at(@epoch_time, in: "+0099") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +0099')
+ -> { Time.at(@epoch_time, in: "+00:99") }.should.raise(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +00:99')
+ -> { Time.at(@epoch_time, in: "+0099") }.should.raise(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +0099')
end
ruby_bug '#20797', ''...'3.4' do
it "raises ArgumentError if seconds greater than 59" do
- -> { Time.at(@epoch_time, in: "+00:00:60") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +00:00:60')
- -> { Time.at(@epoch_time, in: "+000060") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +000060')
+ -> { Time.at(@epoch_time, in: "+00:00:60") }.should.raise(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +00:00:60')
+ -> { Time.at(@epoch_time, in: "+000060") }.should.raise(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +000060')
- -> { Time.at(@epoch_time, in: "+00:00:99") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +00:00:99')
- -> { Time.at(@epoch_time, in: "+000099") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +000099')
+ -> { Time.at(@epoch_time, in: "+00:00:99") }.should.raise(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +00:00:99')
+ -> { Time.at(@epoch_time, in: "+000099") }.should.raise(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +000099')
end
end
end
diff --git a/spec/ruby/core/time/ceil_spec.rb b/spec/ruby/core/time/ceil_spec.rb
index 9d624a1ed0..18e26f9994 100644
--- a/spec/ruby/core/time/ceil_spec.rb
+++ b/spec/ruby/core/time/ceil_spec.rb
@@ -28,8 +28,8 @@ describe "Time#ceil" do
it "returns an instance of Time, even if #ceil is called on a subclass" do
subclass = Class.new(Time)
instance = subclass.at(0)
- instance.class.should equal subclass
- instance.ceil.should be_an_instance_of(Time)
+ instance.class.should.equal? subclass
+ instance.ceil.should.instance_of?(Time)
end
it "copies own timezone to the returning value" do
diff --git a/spec/ruby/core/time/comparison_spec.rb b/spec/ruby/core/time/comparison_spec.rb
index 866fbea72e..0790088f9e 100644
--- a/spec/ruby/core/time/comparison_spec.rb
+++ b/spec/ruby/core/time/comparison_spec.rb
@@ -124,7 +124,7 @@ describe "Time#<=>" do
def r.<=>(other); other <=> self; end
r.should_receive(:<=>).once
- (t <=> r).should be_nil
+ (t <=> r).should == nil
end
end
end
diff --git a/spec/ruby/core/time/ctime_spec.rb b/spec/ruby/core/time/ctime_spec.rb
index 57e7cfd9ce..b609b03974 100644
--- a/spec/ruby/core/time/ctime_spec.rb
+++ b/spec/ruby/core/time/ctime_spec.rb
@@ -1,6 +1,7 @@
require_relative '../../spec_helper'
-require_relative 'shared/asctime'
describe "Time#ctime" do
- it_behaves_like :time_asctime, :ctime
+ it "is an alias of Time#asctime" do
+ Time.instance_method(:ctime).should == Time.instance_method(:asctime)
+ end
end
diff --git a/spec/ruby/core/time/day_spec.rb b/spec/ruby/core/time/day_spec.rb
index 895bcd7a86..3dec17644c 100644
--- a/spec/ruby/core/time/day_spec.rb
+++ b/spec/ruby/core/time/day_spec.rb
@@ -1,6 +1,17 @@
require_relative '../../spec_helper'
-require_relative 'shared/day'
describe "Time#day" do
- it_behaves_like :time_day, :day
+ it "returns the day of the month (1..n) for a local Time" do
+ with_timezone("CET", 1) do
+ Time.local(1970, 1, 1).day.should == 1
+ end
+ end
+
+ it "returns the day of the month for a UTC Time" do
+ Time.utc(1970, 1, 1).day.should == 1
+ end
+
+ it "returns the day of the month for a Time with a fixed offset" do
+ Time.new(2012, 1, 1, 0, 0, 0, -3600).day.should == 1
+ end
end
diff --git a/spec/ruby/core/time/deconstruct_keys_spec.rb b/spec/ruby/core/time/deconstruct_keys_spec.rb
index b5cfdaa93f..9918728c1d 100644
--- a/spec/ruby/core/time/deconstruct_keys_spec.rb
+++ b/spec/ruby/core/time/deconstruct_keys_spec.rb
@@ -16,16 +16,16 @@ describe "Time#deconstruct_keys" do
it "requires one argument" do
-> {
Time.new(2022, 10, 5, 13, 30).deconstruct_keys
- }.should raise_error(ArgumentError)
+ }.should.raise(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)")
+ -> { d.deconstruct_keys(1) }.should.raise(TypeError, "wrong argument type Integer (expected Array or nil)")
+ -> { d.deconstruct_keys("asd") }.should.raise(TypeError, "wrong argument type String (expected Array or nil)")
+ -> { d.deconstruct_keys(:x) }.should.raise(TypeError, "wrong argument type Symbol (expected Array or nil)")
+ -> { d.deconstruct_keys({}) }.should.raise(TypeError, "wrong argument type Hash (expected Array or nil)")
end
it "returns {} when passed []" do
diff --git a/spec/ruby/core/time/dst_spec.rb b/spec/ruby/core/time/dst_spec.rb
index 436240aae5..42daf86875 100644
--- a/spec/ruby/core/time/dst_spec.rb
+++ b/spec/ruby/core/time/dst_spec.rb
@@ -1,6 +1,10 @@
require_relative '../../spec_helper'
-require_relative 'shared/isdst'
describe "Time#dst?" do
- it_behaves_like :time_isdst, :dst?
+ it "returns whether time is during daylight saving time" do
+ with_timezone("America/Los_Angeles") do
+ Time.local(2007, 9, 9, 0, 0, 0).dst?.should == true
+ Time.local(2007, 1, 9, 0, 0, 0).dst?.should == false
+ end
+ end
end
diff --git a/spec/ruby/core/time/dup_spec.rb b/spec/ruby/core/time/dup_spec.rb
index 5d6621beaa..33aa1304ef 100644
--- a/spec/ruby/core/time/dup_spec.rb
+++ b/spec/ruby/core/time/dup_spec.rb
@@ -22,25 +22,25 @@ describe "Time#dup" do
c = Class.new(Time)
t = c.now
- t.should be_an_instance_of(c)
- t.dup.should be_an_instance_of(c)
+ t.should.instance_of?(c)
+ t.dup.should.instance_of?(c)
end
it "returns a clone of Time instance" do
c = Time.dup
t = c.now
- t.should be_an_instance_of(c)
- t.should_not be_an_instance_of(Time)
+ t.should.instance_of?(c)
+ t.should_not.instance_of?(Time)
- t.dup.should be_an_instance_of(c)
- t.dup.should_not be_an_instance_of(Time)
+ t.dup.should.instance_of?(c)
+ t.dup.should_not.instance_of?(Time)
end
it "does not copy frozen status from the original" do
t = Time.now
t.freeze
t2 = t.dup
- t2.frozen?.should be_false
+ t2.frozen?.should == false
end
end
diff --git a/spec/ruby/core/time/eql_spec.rb b/spec/ruby/core/time/eql_spec.rb
index 2ffb4eec96..b7505969dd 100644
--- a/spec/ruby/core/time/eql_spec.rb
+++ b/spec/ruby/core/time/eql_spec.rb
@@ -2,28 +2,28 @@ require_relative '../../spec_helper'
describe "Time#eql?" do
it "returns true if self and other have the same whole number of seconds" do
- Time.at(100).should eql(Time.at(100))
+ Time.at(100).should.eql?(Time.at(100))
end
it "returns false if self and other have differing whole numbers of seconds" do
- Time.at(100).should_not eql(Time.at(99))
+ Time.at(100).should_not.eql?(Time.at(99))
end
it "returns true if self and other have the same number of microseconds" do
- Time.at(100, 100).should eql(Time.at(100, 100))
+ Time.at(100, 100).should.eql?(Time.at(100, 100))
end
it "returns false if self and other have differing numbers of microseconds" do
- Time.at(100, 100).should_not eql(Time.at(100, 99))
+ Time.at(100, 100).should_not.eql?(Time.at(100, 99))
end
it "returns false if self and other have differing fractional microseconds" do
- Time.at(100, Rational(100,1000)).should_not eql(Time.at(100, Rational(99,1000)))
+ Time.at(100, Rational(100,1000)).should_not.eql?(Time.at(100, Rational(99,1000)))
end
it "returns false when given a non-time value" do
- Time.at(100, 100).should_not eql("100")
- Time.at(100, 100).should_not eql(100)
- Time.at(100, 100).should_not eql(100.1)
+ Time.at(100, 100).should_not.eql?("100")
+ Time.at(100, 100).should_not.eql?(100)
+ Time.at(100, 100).should_not.eql?(100.1)
end
end
diff --git a/spec/ruby/core/time/floor_spec.rb b/spec/ruby/core/time/floor_spec.rb
index b0003469c9..41e5142b19 100644
--- a/spec/ruby/core/time/floor_spec.rb
+++ b/spec/ruby/core/time/floor_spec.rb
@@ -20,8 +20,8 @@ describe "Time#floor" do
it "returns an instance of Time, even if #floor is called on a subclass" do
subclass = Class.new(Time)
instance = subclass.at(0)
- instance.class.should equal subclass
- instance.floor.should be_an_instance_of(Time)
+ instance.class.should.equal? subclass
+ instance.floor.should.instance_of?(Time)
end
it "copies own timezone to the returning value" do
diff --git a/spec/ruby/core/time/getgm_spec.rb b/spec/ruby/core/time/getgm_spec.rb
index b5d45b1d9f..7698156c8c 100644
--- a/spec/ruby/core/time/getgm_spec.rb
+++ b/spec/ruby/core/time/getgm_spec.rb
@@ -1,6 +1,7 @@
require_relative '../../spec_helper'
-require_relative 'shared/getgm'
describe "Time#getgm" do
- it_behaves_like :time_getgm, :getgm
+ it "is an alias of Time#getutc" do
+ Time.instance_method(:getgm).should == Time.instance_method(:getutc)
+ end
end
diff --git a/spec/ruby/core/time/getlocal_spec.rb b/spec/ruby/core/time/getlocal_spec.rb
index 398596f400..7e5334c303 100644
--- a/spec/ruby/core/time/getlocal_spec.rb
+++ b/spec/ruby/core/time/getlocal_spec.rb
@@ -14,7 +14,7 @@ describe "Time#getlocal" do
t = Time.gm(2007, 1, 9, 12, 0, 0).getlocal(3630)
t.should == Time.new(2007, 1, 9, 13, 0, 30, 3630)
t.utc_offset.should == 3630
- t.zone.should be_nil
+ t.zone.should == nil
end
platform_is_not :windows do
@@ -41,7 +41,7 @@ describe "Time#getlocal" do
it "returns a Time with a UTC offset of the specified number of Rational seconds" do
t = Time.gm(2007, 1, 9, 12, 0, 0).getlocal(Rational(7201, 2))
t.should == Time.new(2007, 1, 9, 13, 0, Rational(1, 2), Rational(7201, 2))
- t.utc_offset.should eql(Rational(7201, 2))
+ t.utc_offset.should.eql?(Rational(7201, 2))
end
describe "with an argument that responds to #to_r" do
@@ -50,7 +50,7 @@ describe "Time#getlocal" do
o.should_receive(:to_r).and_return(Rational(7201, 2))
t = Time.gm(2007, 1, 9, 12, 0, 0).getlocal(o)
t.should == Time.new(2007, 1, 9, 13, 0, Rational(1, 2), Rational(7201, 2))
- t.utc_offset.should eql(Rational(7201, 2))
+ t.utc_offset.should.eql?(Rational(7201, 2))
end
end
@@ -90,49 +90,49 @@ describe "Time#getlocal" do
it "raises ArgumentError if the String argument is not of the form (+|-)HH:MM" do
t = Time.now
- -> { t.getlocal("3600") }.should raise_error(ArgumentError)
+ -> { t.getlocal("3600") }.should.raise(ArgumentError)
end
it "raises ArgumentError if the String argument is not in an ASCII-compatible encoding" do
t = Time.now
- -> { t.getlocal("-01:00".encode("UTF-16LE")) }.should raise_error(ArgumentError)
+ -> { t.getlocal("-01:00".encode("UTF-16LE")) }.should.raise(ArgumentError)
end
it "raises ArgumentError if the argument represents a value less than or equal to -86400 seconds" do
t = Time.new
t.getlocal(-86400 + 1).utc_offset.should == (-86400 + 1)
- -> { t.getlocal(-86400) }.should raise_error(ArgumentError)
+ -> { t.getlocal(-86400) }.should.raise(ArgumentError)
end
it "raises ArgumentError if the argument represents a value greater than or equal to 86400 seconds" do
t = Time.new
t.getlocal(86400 - 1).utc_offset.should == (86400 - 1)
- -> { t.getlocal(86400) }.should raise_error(ArgumentError)
+ -> { t.getlocal(86400) }.should.raise(ArgumentError)
end
it "raises ArgumentError if String argument and hours greater than 23" do
- -> { Time.now.getlocal("+24:00") }.should raise_error(ArgumentError, "utc_offset out of range")
- -> { Time.now.getlocal("+2400") }.should raise_error(ArgumentError, "utc_offset out of range")
+ -> { Time.now.getlocal("+24:00") }.should.raise(ArgumentError, "utc_offset out of range")
+ -> { Time.now.getlocal("+2400") }.should.raise(ArgumentError, "utc_offset out of range")
- -> { Time.now.getlocal("+99:00") }.should raise_error(ArgumentError, "utc_offset out of range")
- -> { Time.now.getlocal("+9900") }.should raise_error(ArgumentError, "utc_offset out of range")
+ -> { Time.now.getlocal("+99:00") }.should.raise(ArgumentError, "utc_offset out of range")
+ -> { Time.now.getlocal("+9900") }.should.raise(ArgumentError, "utc_offset out of range")
end
it "raises ArgumentError if String argument and minutes greater than 59" do
- -> { Time.now.getlocal("+00:60") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +00:60')
- -> { Time.now.getlocal("+0060") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +0060')
+ -> { Time.now.getlocal("+00:60") }.should.raise(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +00:60')
+ -> { Time.now.getlocal("+0060") }.should.raise(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +0060')
- -> { Time.now.getlocal("+00:99") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +00:99')
- -> { Time.now.getlocal("+0099") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +0099')
+ -> { Time.now.getlocal("+00:99") }.should.raise(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +00:99')
+ -> { Time.now.getlocal("+0099") }.should.raise(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +0099')
end
ruby_bug '#20797', ''...'3.4' do
it "raises ArgumentError if String argument and seconds greater than 59" do
- -> { Time.now.getlocal("+00:00:60") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +00:00:60')
- -> { Time.now.getlocal("+000060") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +000060')
+ -> { Time.now.getlocal("+00:00:60") }.should.raise(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +00:00:60')
+ -> { Time.now.getlocal("+000060") }.should.raise(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +000060')
- -> { Time.now.getlocal("+00:00:99") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +00:00:99')
- -> { Time.now.getlocal("+000099") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +000099')
+ -> { Time.now.getlocal("+00:00:99") }.should.raise(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +00:00:99')
+ -> { Time.now.getlocal("+000099") }.should.raise(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +000099')
end
end
@@ -155,8 +155,8 @@ describe "Time#getlocal" do
end
-> {
- Time.utc(2000, 1, 1, 12, 0, 0).getlocal(zone).should be_kind_of(Time)
- }.should_not raise_error
+ Time.utc(2000, 1, 1, 12, 0, 0).getlocal(zone).should.is_a?(Time)
+ }.should_not.raise
end
it "raises TypeError if timezone does not implement #utc_to_local method" do
@@ -167,7 +167,7 @@ describe "Time#getlocal" do
-> {
Time.utc(2000, 1, 1, 12, 0, 0).getlocal(zone)
- }.should raise_error(TypeError, /can't convert \w+ into an exact number/)
+ }.should.raise(TypeError, /can't convert \w+ into an exact number/)
end
it "does not raise exception if timezone does not implement #local_to_utc method" do
@@ -177,18 +177,18 @@ describe "Time#getlocal" do
end
-> {
- Time.utc(2000, 1, 1, 12, 0, 0).getlocal(zone).should be_kind_of(Time)
- }.should_not raise_error
+ Time.utc(2000, 1, 1, 12, 0, 0).getlocal(zone).should.is_a?(Time)
+ }.should_not.raise
end
context "subject's class implements .find_timezone method" do
it "calls .find_timezone to build a time object if passed zone name as a timezone argument" do
time = TimeSpecs::TimeWithFindTimezone.utc(2000, 1, 1, 12, 0, 0).getlocal("Asia/Colombo")
- time.zone.should be_kind_of TimeSpecs::TimezoneWithName
+ time.zone.should.is_a? TimeSpecs::TimezoneWithName
time.zone.name.should == "Asia/Colombo"
time = TimeSpecs::TimeWithFindTimezone.utc(2000, 1, 1, 12, 0, 0).getlocal("some invalid zone name")
- time.zone.should be_kind_of TimeSpecs::TimezoneWithName
+ time.zone.should.is_a? TimeSpecs::TimezoneWithName
time.zone.name.should == "some invalid zone name"
end
@@ -198,7 +198,7 @@ describe "Time#getlocal" do
-> {
time.getlocal(zone)
- }.should raise_error(TypeError, /can't convert \w+ into an exact number/)
+ }.should.raise(TypeError, /can't convert \w+ into an exact number/)
end
end
end
diff --git a/spec/ruby/core/time/getutc_spec.rb b/spec/ruby/core/time/getutc_spec.rb
index 0cd9c17b00..1d49059a71 100644
--- a/spec/ruby/core/time/getutc_spec.rb
+++ b/spec/ruby/core/time/getutc_spec.rb
@@ -1,6 +1,11 @@
require_relative '../../spec_helper'
-require_relative 'shared/getgm'
describe "Time#getutc" do
- it_behaves_like :time_getgm, :getutc
+ it "returns a new time which is the utc representation of time" do
+ # Testing with America/Regina here because it doesn't have DST.
+ with_timezone("CST", -6) do
+ t = Time.local(2007, 1, 9, 6, 0, 0)
+ t.getutc.should == Time.gm(2007, 1, 9, 12, 0, 0)
+ end
+ end
end
diff --git a/spec/ruby/core/time/gm_spec.rb b/spec/ruby/core/time/gm_spec.rb
index 26dffbcedc..fbabede6ba 100644
--- a/spec/ruby/core/time/gm_spec.rb
+++ b/spec/ruby/core/time/gm_spec.rb
@@ -1,10 +1,7 @@
require_relative '../../spec_helper'
-require_relative 'shared/gm'
-require_relative 'shared/time_params'
describe "Time.gm" do
- it_behaves_like :time_gm, :gm
- it_behaves_like :time_params, :gm
- it_behaves_like :time_params_10_arg, :gm
- it_behaves_like :time_params_microseconds, :gm
+ it "is an alias of Time.utc" do
+ Time.method(:gm).should == Time.method(:utc)
+ end
end
diff --git a/spec/ruby/core/time/gmt_offset_spec.rb b/spec/ruby/core/time/gmt_offset_spec.rb
index df417e6e4e..1769981753 100644
--- a/spec/ruby/core/time/gmt_offset_spec.rb
+++ b/spec/ruby/core/time/gmt_offset_spec.rb
@@ -1,6 +1,7 @@
require_relative '../../spec_helper'
-require_relative 'shared/gmt_offset'
describe "Time#gmt_offset" do
- it_behaves_like :time_gmt_offset, :gmt_offset
+ it "is an alias of Time#utc_offset" do
+ Time.instance_method(:gmt_offset).should == Time.instance_method(:utc_offset)
+ end
end
diff --git a/spec/ruby/core/time/gmt_spec.rb b/spec/ruby/core/time/gmt_spec.rb
index 840f59e0e8..38e98cc43c 100644
--- a/spec/ruby/core/time/gmt_spec.rb
+++ b/spec/ruby/core/time/gmt_spec.rb
@@ -1,8 +1,7 @@
require_relative '../../spec_helper'
describe "Time#gmt?" do
- it "returns true if time represents a time in UTC (GMT)" do
- Time.now.should_not.gmt?
- Time.now.gmtime.should.gmt?
+ it "is an alias of Time#utc?" do
+ Time.instance_method(:gmt?).should == Time.instance_method(:utc?)
end
end
diff --git a/spec/ruby/core/time/gmtime_spec.rb b/spec/ruby/core/time/gmtime_spec.rb
index d965cd541d..e7e1d4ffb2 100644
--- a/spec/ruby/core/time/gmtime_spec.rb
+++ b/spec/ruby/core/time/gmtime_spec.rb
@@ -1,6 +1,7 @@
require_relative '../../spec_helper'
-require_relative 'shared/gmtime'
describe "Time#gmtime" do
- it_behaves_like :time_gmtime, :gmtime
+ it "is an alias of Time#utc" do
+ Time.instance_method(:gmtime).should == Time.instance_method(:utc)
+ end
end
diff --git a/spec/ruby/core/time/gmtoff_spec.rb b/spec/ruby/core/time/gmtoff_spec.rb
index fa28520e9e..c7d801a681 100644
--- a/spec/ruby/core/time/gmtoff_spec.rb
+++ b/spec/ruby/core/time/gmtoff_spec.rb
@@ -1,6 +1,7 @@
require_relative '../../spec_helper'
-require_relative 'shared/gmt_offset'
describe "Time#gmtoff" do
- it_behaves_like :time_gmt_offset, :gmtoff
+ it "is an alias of Time#utc_offset" do
+ Time.instance_method(:gmtoff).should == Time.instance_method(:utc_offset)
+ end
end
diff --git a/spec/ruby/core/time/hash_spec.rb b/spec/ruby/core/time/hash_spec.rb
index 4f4d11a2cd..1cfc56eab0 100644
--- a/spec/ruby/core/time/hash_spec.rb
+++ b/spec/ruby/core/time/hash_spec.rb
@@ -2,7 +2,7 @@ require_relative '../../spec_helper'
describe "Time#hash" do
it "returns an Integer" do
- Time.at(100).hash.should be_an_instance_of(Integer)
+ Time.at(100).hash.should.instance_of?(Integer)
end
it "is stable" do
diff --git a/spec/ruby/core/time/isdst_spec.rb b/spec/ruby/core/time/isdst_spec.rb
index 173230ca07..759953cca7 100644
--- a/spec/ruby/core/time/isdst_spec.rb
+++ b/spec/ruby/core/time/isdst_spec.rb
@@ -1,6 +1,7 @@
require_relative '../../spec_helper'
-require_relative 'shared/isdst'
describe "Time#isdst" do
- it_behaves_like :time_isdst, :isdst
+ it "is an alias of Time#dst?" do
+ Time.instance_method(:isdst).should == Time.instance_method(:dst?)
+ end
end
diff --git a/spec/ruby/core/time/iso8601_spec.rb b/spec/ruby/core/time/iso8601_spec.rb
index ad60c3bb32..a6efc57b28 100644
--- a/spec/ruby/core/time/iso8601_spec.rb
+++ b/spec/ruby/core/time/iso8601_spec.rb
@@ -1,6 +1,33 @@
require_relative '../../spec_helper'
-require_relative 'shared/xmlschema'
describe "Time#iso8601" do
- it_behaves_like :time_xmlschema, :iso8601
+ 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.iso8601.should == "1985-04-12T23:20:50Z"
+ t.iso8601(2).should == "1985-04-12T23:20:50.52Z"
+ t.iso8601(9).should == "1985-04-12T23:20:50.521245000Z"
+ end
+
+ it "generates ISO-8601 string with timezone offset for non-UTC times" do
+ t = Time.new(1985, 4, 12, 23, 20, 50, "+02:00")
+ t.iso8601.should == "1985-04-12T23:20:50+02:00"
+ t.iso8601(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.iso8601.should == "0012-04-12T00:00:00Z"
+ end
+
+ it "year can be more than 4 digits" do
+ t = Time.utc(40_000, 4, 12)
+ t.iso8601.should == "40000-04-12T00:00:00Z"
+ end
+
+ it "year can be negative" do
+ t = Time.utc(-2000, 4, 12)
+ t.iso8601.should == "-2000-04-12T00:00:00Z"
+ end
+ end
end
diff --git a/spec/ruby/core/time/localtime_spec.rb b/spec/ruby/core/time/localtime_spec.rb
index 71c0dfebde..1c0b11b7a6 100644
--- a/spec/ruby/core/time/localtime_spec.rb
+++ b/spec/ruby/core/time/localtime_spec.rb
@@ -12,7 +12,7 @@ describe "Time#localtime" do
it "returns self" do
t = Time.gm(2007, 1, 9, 12, 0, 0)
- t.localtime.should equal(t)
+ t.localtime.should.equal?(t)
end
it "converts time to the UTC offset specified as an Integer number of seconds" do
@@ -26,13 +26,13 @@ describe "Time#localtime" do
it "does not raise an error if already in the right time zone" do
time = Time.now
time.freeze
- time.localtime.should equal(time)
+ time.localtime.should.equal?(time)
end
it "raises a FrozenError if the time has a different time zone" do
time = Time.gm(2007, 1, 9, 12, 0, 0)
time.freeze
- -> { time.localtime }.should raise_error(FrozenError)
+ -> { time.localtime }.should.raise(FrozenError)
end
end
@@ -51,7 +51,7 @@ describe "Time#localtime" do
t = Time.gm(2007, 1, 9, 12, 0, 0)
t.localtime(Rational(7201, 2))
t.should == Time.new(2007, 1, 9, 13, 0, Rational(1, 2), Rational(7201, 2))
- t.utc_offset.should eql(Rational(7201, 2))
+ t.utc_offset.should.eql?(Rational(7201, 2))
end
describe "with an argument that responds to #to_r" do
@@ -61,7 +61,7 @@ describe "Time#localtime" do
t = Time.gm(2007, 1, 9, 12, 0, 0)
t.localtime(o)
t.should == Time.new(2007, 1, 9, 13, 0, Rational(1, 2), Rational(7201, 2))
- t.utc_offset.should eql(Rational(7201, 2))
+ t.utc_offset.should.eql?(Rational(7201, 2))
end
end
@@ -106,28 +106,28 @@ describe "Time#localtime" do
end
it "raises ArgumentError if String argument and hours greater than 23" do
- -> { Time.now.localtime("+24:00") }.should raise_error(ArgumentError, "utc_offset out of range")
- -> { Time.now.localtime("+2400") }.should raise_error(ArgumentError, "utc_offset out of range")
+ -> { Time.now.localtime("+24:00") }.should.raise(ArgumentError, "utc_offset out of range")
+ -> { Time.now.localtime("+2400") }.should.raise(ArgumentError, "utc_offset out of range")
- -> { Time.now.localtime("+99:00") }.should raise_error(ArgumentError, "utc_offset out of range")
- -> { Time.now.localtime("+9900") }.should raise_error(ArgumentError, "utc_offset out of range")
+ -> { Time.now.localtime("+99:00") }.should.raise(ArgumentError, "utc_offset out of range")
+ -> { Time.now.localtime("+9900") }.should.raise(ArgumentError, "utc_offset out of range")
end
it "raises ArgumentError if String argument and minutes greater than 59" do
- -> { Time.now.localtime("+00:60") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +00:60')
- -> { Time.now.localtime("+0060") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +0060')
+ -> { Time.now.localtime("+00:60") }.should.raise(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +00:60')
+ -> { Time.now.localtime("+0060") }.should.raise(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +0060')
- -> { Time.now.localtime("+00:99") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +00:99')
- -> { Time.now.localtime("+0099") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +0099')
+ -> { Time.now.localtime("+00:99") }.should.raise(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +00:99')
+ -> { Time.now.localtime("+0099") }.should.raise(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +0099')
end
ruby_bug '#20797', ''...'3.4' do
it "raises ArgumentError if String argument and seconds greater than 59" do
- -> { Time.now.localtime("+00:00:60") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +00:00:60')
- -> { Time.now.localtime("+000060") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +000060')
+ -> { Time.now.localtime("+00:00:60") }.should.raise(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +00:00:60')
+ -> { Time.now.localtime("+000060") }.should.raise(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +000060')
- -> { Time.now.localtime("+00:00:99") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +00:00:99')
- -> { Time.now.localtime("+000099") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +000099')
+ -> { Time.now.localtime("+00:00:99") }.should.raise(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +00:00:99')
+ -> { Time.now.localtime("+000099") }.should.raise(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +000099')
end
end
@@ -181,23 +181,23 @@ describe "Time#localtime" do
it "raises ArgumentError if the String argument is not of the form (+|-)HH:MM" do
t = Time.now
- -> { t.localtime("3600") }.should raise_error(ArgumentError)
+ -> { t.localtime("3600") }.should.raise(ArgumentError)
end
it "raises ArgumentError if the String argument is not in an ASCII-compatible encoding" do
t = Time.now
- -> { t.localtime("-01:00".encode("UTF-16LE")) }.should raise_error(ArgumentError)
+ -> { t.localtime("-01:00".encode("UTF-16LE")) }.should.raise(ArgumentError)
end
it "raises ArgumentError if the argument represents a value less than or equal to -86400 seconds" do
t = Time.new
t.localtime(-86400 + 1).utc_offset.should == (-86400 + 1)
- -> { t.localtime(-86400) }.should raise_error(ArgumentError)
+ -> { t.localtime(-86400) }.should.raise(ArgumentError)
end
it "raises ArgumentError if the argument represents a value greater than or equal to 86400 seconds" do
t = Time.new
t.localtime(86400 - 1).utc_offset.should == (86400 - 1)
- -> { t.localtime(86400) }.should raise_error(ArgumentError)
+ -> { t.localtime(86400) }.should.raise(ArgumentError)
end
end
diff --git a/spec/ruby/core/time/mday_spec.rb b/spec/ruby/core/time/mday_spec.rb
index 3c21939890..78021785f9 100644
--- a/spec/ruby/core/time/mday_spec.rb
+++ b/spec/ruby/core/time/mday_spec.rb
@@ -1,6 +1,7 @@
require_relative '../../spec_helper'
-require_relative 'shared/day'
describe "Time#mday" do
- it_behaves_like :time_day, :mday
+ it "is an alias of Time#day" do
+ Time.instance_method(:mday).should == Time.instance_method(:day)
+ end
end
diff --git a/spec/ruby/core/time/minus_spec.rb b/spec/ruby/core/time/minus_spec.rb
index 9182d99652..ee3d8acda8 100644
--- a/spec/ruby/core/time/minus_spec.rb
+++ b/spec/ruby/core/time/minus_spec.rb
@@ -20,18 +20,18 @@ describe "Time#-" do
end
it "raises a TypeError if given argument is a coercible String" do
- -> { Time.now - "1" }.should raise_error(TypeError)
- -> { Time.now - "0.1" }.should raise_error(TypeError)
- -> { Time.now - "1/3" }.should raise_error(TypeError)
+ -> { Time.now - "1" }.should.raise(TypeError)
+ -> { Time.now - "0.1" }.should.raise(TypeError)
+ -> { Time.now - "1/3" }.should.raise(TypeError)
end
it "raises TypeError on argument that can't be coerced" do
- -> { Time.now - Object.new }.should raise_error(TypeError)
- -> { Time.now - "stuff" }.should raise_error(TypeError)
+ -> { Time.now - Object.new }.should.raise(TypeError)
+ -> { Time.now - "stuff" }.should.raise(TypeError)
end
it "raises TypeError on nil argument" do
- -> { Time.now - nil }.should raise_error(TypeError)
+ -> { Time.now - nil }.should.raise(TypeError)
end
it "tracks microseconds" do
@@ -110,7 +110,7 @@ describe "Time#-" do
it "does not return a subclass instance" do
c = Class.new(Time)
x = c.now - 1
- x.should be_an_instance_of(Time)
+ x.should.instance_of?(Time)
end
it "returns a time with nanoseconds precision between two time objects" do
diff --git a/spec/ruby/core/time/mktime_spec.rb b/spec/ruby/core/time/mktime_spec.rb
index 78a6a6e772..83bf12293a 100644
--- a/spec/ruby/core/time/mktime_spec.rb
+++ b/spec/ruby/core/time/mktime_spec.rb
@@ -1,11 +1,7 @@
require_relative '../../spec_helper'
-require_relative 'shared/local'
-require_relative 'shared/time_params'
describe "Time.mktime" do
- it_behaves_like :time_local, :mktime
- it_behaves_like :time_local_10_arg, :mktime
- it_behaves_like :time_params, :mktime
- it_behaves_like :time_params_10_arg, :mktime
- it_behaves_like :time_params_microseconds, :mktime
+ it "is an alias of Time.local" do
+ Time.method(:mktime).should == Time.method(:local)
+ end
end
diff --git a/spec/ruby/core/time/mon_spec.rb b/spec/ruby/core/time/mon_spec.rb
index f41b39648b..d57549dadd 100644
--- a/spec/ruby/core/time/mon_spec.rb
+++ b/spec/ruby/core/time/mon_spec.rb
@@ -1,6 +1,7 @@
require_relative '../../spec_helper'
-require_relative 'shared/month'
describe "Time#mon" do
- it_behaves_like :time_month, :mon
+ it "is an alias of Time#month" do
+ Time.instance_method(:mon).should == Time.instance_method(:month)
+ end
end
diff --git a/spec/ruby/core/time/month_spec.rb b/spec/ruby/core/time/month_spec.rb
index 81e20384ab..eae0e85acd 100644
--- a/spec/ruby/core/time/month_spec.rb
+++ b/spec/ruby/core/time/month_spec.rb
@@ -1,6 +1,17 @@
require_relative '../../spec_helper'
-require_relative 'shared/month'
describe "Time#month" do
- it_behaves_like :time_month, :month
+ it "returns the month of the year for a local Time" do
+ with_timezone("CET", 1) do
+ Time.local(1970, 1).month.should == 1
+ end
+ end
+
+ it "returns the month of the year for a UTC Time" do
+ Time.utc(1970, 1).month.should == 1
+ end
+
+ it "returns the four digit year for a Time with a fixed offset" do
+ Time.new(2012, 1, 1, 0, 0, 0, -3600).month.should == 1
+ end
end
diff --git a/spec/ruby/core/time/new_spec.rb b/spec/ruby/core/time/new_spec.rb
index dc3ccbdc00..91ce4b2e3a 100644
--- a/spec/ruby/core/time/new_spec.rb
+++ b/spec/ruby/core/time/new_spec.rb
@@ -31,14 +31,14 @@ describe "Time.new with a utc_offset argument" do
end
it "returns a Time with a UTC offset of the specified number of Rational seconds" do
- Time.new(2000, 1, 1, 0, 0, 0, Rational(5, 2)).utc_offset.should eql(Rational(5, 2))
+ Time.new(2000, 1, 1, 0, 0, 0, Rational(5, 2)).utc_offset.should.eql?(Rational(5, 2))
end
describe "with an argument that responds to #to_r" do
it "coerces using #to_r" do
o = mock_numeric('rational')
o.should_receive(:to_r).and_return(Rational(5, 2))
- Time.new(2000, 1, 1, 0, 0, 0, o).utc_offset.should eql(Rational(5, 2))
+ Time.new(2000, 1, 1, 0, 0, 0, o).utc_offset.should.eql?(Rational(5, 2))
end
end
@@ -129,7 +129,7 @@ describe "Time.new with a utc_offset argument" do
it "raises ArgumentError if the string argument is J" do
message = '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: J'
- -> { Time.new(2000, 1, 1, 0, 0, 0, "J") }.should raise_error(ArgumentError, message)
+ -> { Time.new(2000, 1, 1, 0, 0, 0, "J") }.should.raise(ArgumentError, message)
end
it "returns a local Time if the argument is nil" do
@@ -144,18 +144,18 @@ describe "Time.new with a utc_offset argument" do
it "disallows a value for minutes greater than 59" do
-> {
Time.new(2000, 1, 1, 0, 0, 0, "+01:60")
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
-> {
Time.new(2000, 1, 1, 0, 0, 0, "+01:99")
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
it "raises ArgumentError if the String argument is not of the form (+|-)HH:MM" do
- -> { Time.new(2000, 1, 1, 0, 0, 0, "3600") }.should raise_error(ArgumentError)
+ -> { Time.new(2000, 1, 1, 0, 0, 0, "3600") }.should.raise(ArgumentError)
end
it "raises ArgumentError if the hour value is greater than 23" do
- -> { Time.new(2000, 1, 1, 0, 0, 0, "+24:00") }.should raise_error(ArgumentError)
+ -> { Time.new(2000, 1, 1, 0, 0, 0, "+24:00") }.should.raise(ArgumentError)
end
it "raises ArgumentError if the String argument is not in an ASCII-compatible encoding" do
@@ -164,21 +164,21 @@ describe "Time.new with a utc_offset argument" do
# - '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset'
-> {
Time.new(2000, 1, 1, 0, 0, 0, "-04:10".encode("UTF-16LE"))
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
it "raises ArgumentError if the argument represents a value less than or equal to -86400 seconds" do
Time.new(2000, 1, 1, 0, 0, 0, -86400 + 1).utc_offset.should == (-86400 + 1)
- -> { Time.new(2000, 1, 1, 0, 0, 0, -86400) }.should raise_error(ArgumentError)
+ -> { Time.new(2000, 1, 1, 0, 0, 0, -86400) }.should.raise(ArgumentError)
end
it "raises ArgumentError if the argument represents a value greater than or equal to 86400 seconds" do
Time.new(2000, 1, 1, 0, 0, 0, 86400 - 1).utc_offset.should == (86400 - 1)
- -> { Time.new(2000, 1, 1, 0, 0, 0, 86400) }.should raise_error(ArgumentError)
+ -> { Time.new(2000, 1, 1, 0, 0, 0, 86400) }.should.raise(ArgumentError)
end
it "raises ArgumentError if the utc_offset argument is greater than or equal to 10e9" do
- -> { Time.new(2000, 1, 1, 0, 0, 0, 1000000000) }.should raise_error(ArgumentError)
+ -> { Time.new(2000, 1, 1, 0, 0, 0, 1000000000) }.should.raise(ArgumentError)
end
end
@@ -203,7 +203,7 @@ describe "Time.new with a timezone argument" do
time
end
- Time.new(2000, 1, 1, 12, 0, 0, zone).should be_kind_of(Time)
+ Time.new(2000, 1, 1, 12, 0, 0, zone).should.is_a?(Time)
end
it "raises TypeError if timezone does not implement #local_to_utc method" do
@@ -214,7 +214,7 @@ describe "Time.new with a timezone argument" do
-> {
Time.new(2000, 1, 1, 12, 0, 0, zone)
- }.should raise_error(TypeError, /can't convert Object into an exact number/)
+ }.should.raise(TypeError, /can't convert Object into an exact number/)
end
it "does not raise exception if timezone does not implement #utc_to_local method" do
@@ -223,7 +223,7 @@ describe "Time.new with a timezone argument" do
time
end
- Time.new(2000, 1, 1, 12, 0, 0, zone).should be_kind_of(Time)
+ Time.new(2000, 1, 1, 12, 0, 0, zone).should.is_a?(Time)
end
# The result also should be a Time or Time-like object (not necessary to be the same class)
@@ -236,7 +236,7 @@ describe "Time.new with a timezone argument" do
time - 60 * 60 # - 1 hour
end
- Time.new(2000, 1, 1, 12, 0, 0, zone).should be_kind_of(Time)
+ Time.new(2000, 1, 1, 12, 0, 0, zone).should.is_a?(Time)
Time.new(2000, 1, 1, 12, 0, 0, zone).utc_offset.should == 60*60
end
@@ -248,7 +248,7 @@ describe "Time.new with a timezone argument" do
Class.new(Time).utc(time.year, time.mon, time.day, time.hour, t.min, t.sec)
end
- Time.new(2000, 1, 1, 12, 0, 0, zone).should be_kind_of(Time)
+ Time.new(2000, 1, 1, 12, 0, 0, zone).should.is_a?(Time)
Time.new(2000, 1, 1, 12, 0, 0, zone).utc_offset.should == 60*60
end
@@ -260,7 +260,7 @@ describe "Time.new with a timezone argument" do
obj
end
- Time.new(2000, 1, 1, 12, 0, 0, zone).should be_kind_of(Time)
+ Time.new(2000, 1, 1, 12, 0, 0, zone).should.is_a?(Time)
Time.new(2000, 1, 1, 12, 0, 0, zone).utc_offset.should == 60*60
end
@@ -294,7 +294,7 @@ describe "Time.new with a timezone argument" do
-> {
Time.new(2000, 1, 1, 12, 0, 0, zone)
- }.should raise_error(ArgumentError, "utc_offset out of range")
+ }.should.raise(ArgumentError, "utc_offset out of range")
end
end
@@ -348,7 +348,7 @@ describe "Time.new with a timezone argument" do
-> {
Marshal.dump(time)
- }.should raise_error(NoMethodError, /undefined method [`']name' for/)
+ }.should.raise(NoMethodError, /undefined method [`']name' for/)
end
end
@@ -369,18 +369,18 @@ describe "Time.new with a timezone argument" do
time = TimeSpecs::TimeWithFindTimezone.new(2000, 1, 1, 12, 0, 0, zone)
time_loaded = Marshal.load(Marshal.dump(time))
- time_loaded.zone.should be_kind_of TimeSpecs::TimezoneWithName
+ time_loaded.zone.should.is_a? TimeSpecs::TimezoneWithName
time_loaded.zone.name.should == "Asia/Colombo"
time_loaded.utc_offset.should == 5*3600+30*60
end
it "calls .find_timezone to build a time object if passed zone name as a timezone argument" do
time = TimeSpecs::TimeWithFindTimezone.new(2000, 1, 1, 12, 0, 0, "Asia/Colombo")
- time.zone.should be_kind_of TimeSpecs::TimezoneWithName
+ time.zone.should.is_a? TimeSpecs::TimezoneWithName
time.zone.name.should == "Asia/Colombo"
time = TimeSpecs::TimeWithFindTimezone.new(2000, 1, 1, 12, 0, 0, "some invalid zone name")
- time.zone.should be_kind_of TimeSpecs::TimezoneWithName
+ time.zone.should.is_a? TimeSpecs::TimezoneWithName
time.zone.name.should == "some invalid zone name"
end
@@ -388,7 +388,7 @@ describe "Time.new with a timezone argument" do
[Object.new, [], {}, :"some zone"].each do |zone|
-> {
TimeSpecs::TimeWithFindTimezone.new(2000, 1, 1, 12, 0, 0, zone)
- }.should raise_error(TypeError, /can't convert \w+ into an exact number/)
+ }.should.raise(TypeError, /can't convert \w+ into an exact number/)
end
end
end
@@ -456,14 +456,14 @@ describe "Time.new with a timezone argument" do
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)
+ -> { Time.new(2000, 1, 1, 12, 0, 0, in: "+09:99") }.should.raise(ArgumentError)
+ -> { Time.new(2000, 1, 1, 12, 0, 0, in: "ABC") }.should.raise(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")
+ }.should.raise(ArgumentError, "timezone argument given as positional and keyword arguments")
end
end
@@ -554,200 +554,186 @@ describe "Time.new with a timezone argument" do
Time.new("2020-12-25T00:56:17.123456789876 +09:00").subsec.should == 0.123456789
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
+ 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(TypeError, "no implicit conversion of String into Integer")
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 |can't parse:/)
+ }.should.raise(ArgumentError, /missing sec part: 00:56 |can't parse:/)
-> {
Time.new("2020-12-25 00 +09:00")
- }.should raise_error(ArgumentError, /missing min part: 00 |can't parse:/)
+ }.should.raise(ArgumentError, /missing min part: 00 |can't parse:/)
end
- ruby_version_is "3.2.3" do
- it "raises ArgumentError if the time part is missing" do
- -> {
- Time.new("2020-12-25")
- }.should raise_error(ArgumentError, /no time information|can't parse:/)
- end
+ it "raises ArgumentError if the time part is missing" do
+ -> {
+ Time.new("2020-12-25")
+ }.should.raise(ArgumentError, /no time information|can't parse:/)
+ end
- it "raises ArgumentError if day is missing" do
- -> {
- Time.new("2020-12")
- }.should raise_error(ArgumentError, /no time information|can't parse:/)
- end
+ it "raises ArgumentError if day is missing" do
+ -> {
+ Time.new("2020-12")
+ }.should.raise(ArgumentError, /no time information|can't parse:/)
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. |can't parse:/)
+ }.should.raise(ArgumentError, /subsecond expected after dot: 00:56:17. |can't parse:/)
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|can't parse:/)
+ }.should.raise(ArgumentError, /year must be 4 or more digits: 021|can't parse:/)
-> {
Time.new("2020-012-25 00:56:17 +0900")
- }.should raise_error(ArgumentError, /\Atwo digits mon is expected after [`']-': -012-25 00:\z|can't parse:/)
+ }.should.raise(ArgumentError, /\Atwo digits mon is expected after [`']-': -012-25 00:\z|can't parse:/)
-> {
Time.new("2020-2-25 00:56:17 +0900")
- }.should raise_error(ArgumentError, /\Atwo digits mon is expected after [`']-': -2-25 00:56\z|can't parse:/)
+ }.should.raise(ArgumentError, /\Atwo digits mon is expected after [`']-': -2-25 00:56\z|can't parse:/)
-> {
Time.new("2020-12-215 00:56:17 +0900")
- }.should raise_error(ArgumentError, /\Atwo digits mday is expected after [`']-': -215 00:56:\z|can't parse:/)
+ }.should.raise(ArgumentError, /\Atwo digits mday is expected after [`']-': -215 00:56:\z|can't parse:/)
-> {
Time.new("2020-12-25 000:56:17 +0900")
- }.should raise_error(ArgumentError, /two digits hour is expected: 000:56:17 |can't parse:/)
+ }.should.raise(ArgumentError, /two digits hour is expected: 000:56:17 |can't parse:/)
-> {
Time.new("2020-12-25 0:56:17 +0900")
- }.should raise_error(ArgumentError, /two digits hour is expected: 0:56:17 \+0|can't parse:/)
+ }.should.raise(ArgumentError, /two digits hour is expected: 0:56:17 \+0|can't parse:/)
-> {
Time.new("2020-12-25 00:516:17 +0900")
- }.should raise_error(ArgumentError, /\Atwo digits min is expected after [`']:': :516:17 \+09\z|can't parse:/)
+ }.should.raise(ArgumentError, /\Atwo digits min is expected after [`']:': :516:17 \+09\z|can't parse:/)
-> {
Time.new("2020-12-25 00:6:17 +0900")
- }.should raise_error(ArgumentError, /\Atwo digits min is expected after [`']:': :6:17 \+0900\z|can't parse:/)
+ }.should.raise(ArgumentError, /\Atwo digits min is expected after [`']:': :6:17 \+0900\z|can't parse:/)
-> {
Time.new("2020-12-25 00:56:137 +0900")
- }.should raise_error(ArgumentError, /\Atwo digits sec is expected after [`']:': :137 \+0900\z|can't parse:/)
+ }.should.raise(ArgumentError, /\Atwo digits sec is expected after [`']:': :137 \+0900\z|can't parse:/)
-> {
Time.new("2020-12-25 00:56:7 +0900")
- }.should raise_error(ArgumentError, /\Atwo digits sec is expected after [`']:': :7 \+0900\z|can't parse:/)
+ }.should.raise(ArgumentError, /\Atwo digits sec is expected after [`']:': :7 \+0900\z|can't parse:/)
-> {
Time.new("2020-12-25 00:56. +0900")
- }.should raise_error(ArgumentError, /fraction min is not supported: 00:56\.|can't parse:/)
+ }.should.raise(ArgumentError, /fraction min is not supported: 00:56\.|can't parse:/)
-> {
Time.new("2020-12-25 00. +0900")
- }.should raise_error(ArgumentError, /fraction hour is not supported: 00\.|can't parse:/)
+ }.should.raise(ArgumentError, /fraction hour is not supported: 00\.|can't parse:/)
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|argument) out of range/)
+ }.should.raise(ArgumentError, /(mon|argument) out of range/)
-> {
Time.new("2020-12-32 00:56:17 +09:00")
- }.should raise_error(ArgumentError, /(mday|argument) out of range/)
+ }.should.raise(ArgumentError, /(mday|argument) out of range/)
-> {
Time.new("2020-12-25 25:56:17 +09:00")
- }.should raise_error(ArgumentError, /(hour|argument) out of range/)
+ }.should.raise(ArgumentError, /(hour|argument) out of range/)
-> {
Time.new("2020-12-25 00:61:17 +09:00")
- }.should raise_error(ArgumentError, /(min|argument) out of range/)
+ }.should.raise(ArgumentError, /(min|argument) out of range/)
-> {
Time.new("2020-12-25 00:56:61 +09:00")
- }.should raise_error(ArgumentError, /(sec|argument) out of range/)
+ }.should.raise(ArgumentError, /(sec|argument) out of range/)
-> {
Time.new("2020-12-25 00:56:17 +23:59:60")
- }.should raise_error(ArgumentError, /utc_offset|argument out of range/)
+ }.should.raise(ArgumentError, /utc_offset|argument out of range/)
-> {
Time.new("2020-12-25 00:56:17 +24:00")
- }.should raise_error(ArgumentError, /(utc_offset|argument) out of range/)
+ }.should.raise(ArgumentError, /(utc_offset|argument) out of range/)
-> {
Time.new("2020-12-25 00:56:17 +23:61")
- }.should raise_error(ArgumentError, /utc_offset/)
+ }.should.raise(ArgumentError, /utc_offset/)
ruby_bug '#20797', ''...'3.4' do
-> {
Time.new("2020-12-25 00:56:17 +00:23:61")
- }.should raise_error(ArgumentError, /utc_offset/)
+ }.should.raise(ArgumentError, /utc_offset/)
end
end
it "raises ArgumentError if utc offset parts are not valid" do
- -> { 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 +2400") }.should raise_error(ArgumentError, "utc_offset out of range")
+ -> { Time.new("2020-12-25 00:56:17 +24:00") }.should.raise(ArgumentError, "utc_offset out of range")
+ -> { Time.new("2020-12-25 00:56:17 +2400") }.should.raise(ArgumentError, "utc_offset out of range")
- -> { Time.new("2020-12-25 00:56:17 +99:00") }.should raise_error(ArgumentError, "utc_offset out of range")
- -> { Time.new("2020-12-25 00:56:17 +9900") }.should raise_error(ArgumentError, "utc_offset out of range")
+ -> { Time.new("2020-12-25 00:56:17 +99:00") }.should.raise(ArgumentError, "utc_offset out of range")
+ -> { Time.new("2020-12-25 00:56:17 +9900") }.should.raise(ArgumentError, "utc_offset out of range")
- -> { Time.new("2020-12-25 00:56:17 +00:60") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +00:60')
- -> { Time.new("2020-12-25 00:56:17 +0060") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +0060')
+ -> { Time.new("2020-12-25 00:56:17 +00:60") }.should.raise(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +00:60')
+ -> { Time.new("2020-12-25 00:56:17 +0060") }.should.raise(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +0060')
- -> { Time.new("2020-12-25 00:56:17 +00:99") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +00:99')
- -> { Time.new("2020-12-25 00:56:17 +0099") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +0099')
+ -> { Time.new("2020-12-25 00:56:17 +00:99") }.should.raise(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +00:99')
+ -> { Time.new("2020-12-25 00:56:17 +0099") }.should.raise(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +0099')
ruby_bug '#20797', ''...'3.4' do
- -> { Time.new("2020-12-25 00:56:17 +00:00:60") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +00:00:60')
- -> { Time.new("2020-12-25 00:56:17 +000060") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +000060')
+ -> { Time.new("2020-12-25 00:56:17 +00:00:60") }.should.raise(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +00:00:60')
+ -> { Time.new("2020-12-25 00:56:17 +000060") }.should.raise(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +000060')
- -> { Time.new("2020-12-25 00:56:17 +00:00:99") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +00:00:99')
- -> { Time.new("2020-12-25 00:56:17 +000099") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +000099')
+ -> { Time.new("2020-12-25 00:56:17 +00:00:99") }.should.raise(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +00:00:99')
+ -> { Time.new("2020-12-25 00:56:17 +000099") }.should.raise(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +000099')
end
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")
+ }.should.raise(ArgumentError, "time string should have ASCII compatible encoding")
end
it "raises ArgumentError if string doesn't start with year" do
-> {
Time.new("a\nb")
- }.should raise_error(ArgumentError, "can't parse: \"a\\nb\"")
+ }.should.raise(ArgumentError, "can't parse: \"a\\nb\"")
end
it "raises ArgumentError if string has extra characters after offset" do
-> {
Time.new("2021-11-31 00:00:59 +09:00 abc")
- }.should raise_error(ArgumentError, /can't parse.+ abc/)
+ }.should.raise(ArgumentError, /can't parse.+ abc/)
end
- ruby_version_is "3.2.3" do
- it "raises ArgumentError when there are leading space characters" do
- -> { Time.new(" 2020-12-02 00:00:00") }.should raise_error(ArgumentError, /can't parse/)
- -> { Time.new("\t2020-12-02 00:00:00") }.should raise_error(ArgumentError, /can't parse/)
- -> { Time.new("\n2020-12-02 00:00:00") }.should raise_error(ArgumentError, /can't parse/)
- -> { Time.new("\v2020-12-02 00:00:00") }.should raise_error(ArgumentError, /can't parse/)
- -> { Time.new("\f2020-12-02 00:00:00") }.should raise_error(ArgumentError, /can't parse/)
- -> { Time.new("\r2020-12-02 00:00:00") }.should raise_error(ArgumentError, /can't parse/)
- end
+ it "raises ArgumentError when there are leading space characters" do
+ -> { Time.new(" 2020-12-02 00:00:00") }.should.raise(ArgumentError, /can't parse/)
+ -> { Time.new("\t2020-12-02 00:00:00") }.should.raise(ArgumentError, /can't parse/)
+ -> { Time.new("\n2020-12-02 00:00:00") }.should.raise(ArgumentError, /can't parse/)
+ -> { Time.new("\v2020-12-02 00:00:00") }.should.raise(ArgumentError, /can't parse/)
+ -> { Time.new("\f2020-12-02 00:00:00") }.should.raise(ArgumentError, /can't parse/)
+ -> { Time.new("\r2020-12-02 00:00:00") }.should.raise(ArgumentError, /can't parse/)
+ end
- it "raises ArgumentError when there are trailing whitespaces" do
- -> { Time.new("2020-12-02 00:00:00 ") }.should raise_error(ArgumentError, /can't parse/)
- -> { Time.new("2020-12-02 00:00:00\t") }.should raise_error(ArgumentError, /can't parse/)
- -> { Time.new("2020-12-02 00:00:00\n") }.should raise_error(ArgumentError, /can't parse/)
- -> { Time.new("2020-12-02 00:00:00\v") }.should raise_error(ArgumentError, /can't parse/)
- -> { Time.new("2020-12-02 00:00:00\f") }.should raise_error(ArgumentError, /can't parse/)
- -> { Time.new("2020-12-02 00:00:00\r") }.should raise_error(ArgumentError, /can't parse/)
- end
+ it "raises ArgumentError when there are trailing whitespaces" do
+ -> { Time.new("2020-12-02 00:00:00 ") }.should.raise(ArgumentError, /can't parse/)
+ -> { Time.new("2020-12-02 00:00:00\t") }.should.raise(ArgumentError, /can't parse/)
+ -> { Time.new("2020-12-02 00:00:00\n") }.should.raise(ArgumentError, /can't parse/)
+ -> { Time.new("2020-12-02 00:00:00\v") }.should.raise(ArgumentError, /can't parse/)
+ -> { Time.new("2020-12-02 00:00:00\f") }.should.raise(ArgumentError, /can't parse/)
+ -> { Time.new("2020-12-02 00:00:00\r") }.should.raise(ArgumentError, /can't parse/)
end
end
end
diff --git a/spec/ruby/core/time/now_spec.rb b/spec/ruby/core/time/now_spec.rb
index e3fe6edad6..533cf68380 100644
--- a/spec/ruby/core/time/now_spec.rb
+++ b/spec/ruby/core/time/now_spec.rb
@@ -53,33 +53,33 @@ describe "Time.now" do
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)
+ -> { Time.now(in: "+09:99") }.should.raise(ArgumentError)
+ -> { Time.now(in: "ABC") }.should.raise(ArgumentError)
end
it "raises ArgumentError if String argument and hours greater than 23" do
- -> { Time.now(in: "+24:00") }.should raise_error(ArgumentError, "utc_offset out of range")
- -> { Time.now(in: "+2400") }.should raise_error(ArgumentError, "utc_offset out of range")
+ -> { Time.now(in: "+24:00") }.should.raise(ArgumentError, "utc_offset out of range")
+ -> { Time.now(in: "+2400") }.should.raise(ArgumentError, "utc_offset out of range")
- -> { Time.now(in: "+99:00") }.should raise_error(ArgumentError, "utc_offset out of range")
- -> { Time.now(in: "+9900") }.should raise_error(ArgumentError, "utc_offset out of range")
+ -> { Time.now(in: "+99:00") }.should.raise(ArgumentError, "utc_offset out of range")
+ -> { Time.now(in: "+9900") }.should.raise(ArgumentError, "utc_offset out of range")
end
it "raises ArgumentError if String argument and minutes greater than 59" do
- -> { Time.now(in: "+00:60") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +00:60')
- -> { Time.now(in: "+0060") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +0060')
+ -> { Time.now(in: "+00:60") }.should.raise(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +00:60')
+ -> { Time.now(in: "+0060") }.should.raise(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +0060')
- -> { Time.now(in: "+00:99") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +00:99')
- -> { Time.now(in: "+0099") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +0099')
+ -> { Time.now(in: "+00:99") }.should.raise(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +00:99')
+ -> { Time.now(in: "+0099") }.should.raise(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +0099')
end
ruby_bug '#20797', ''...'3.4' do
it "raises ArgumentError if String argument and seconds greater than 59" do
- -> { Time.now(in: "+00:00:60") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +00:00:60')
- -> { Time.now(in: "+000060") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +000060')
+ -> { Time.now(in: "+00:00:60") }.should.raise(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +00:00:60')
+ -> { Time.now(in: "+000060") }.should.raise(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +000060')
- -> { Time.now(in: "+00:00:99") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +00:00:99')
- -> { Time.now(in: "+000099") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +000099')
+ -> { Time.now(in: "+00:00:99") }.should.raise(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +00:00:99')
+ -> { Time.now(in: "+000099") }.should.raise(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +000099')
end
end
end
@@ -93,7 +93,7 @@ describe "Time.now" do
-> {
Time.now(in: zone)
- }.should raise_error(TypeError, /can't convert Object into an exact number/)
+ }.should.raise(TypeError, /can't convert Object into an exact number/)
end
it "does not raise exception if timezone does not implement #local_to_utc method" do
@@ -102,7 +102,7 @@ describe "Time.now" do
time
end
- Time.now(in: zone).should be_kind_of(Time)
+ Time.now(in: zone).should.is_a?(Time)
end
# The result also should be a Time or Time-like object (not necessary to be the same class)
@@ -115,7 +115,7 @@ describe "Time.now" do
time + 60 * 60 # + 1 hour
end
- Time.now(in: zone).should be_kind_of(Time)
+ Time.now(in: zone).should.is_a?(Time)
Time.now(in: zone).utc_offset.should == 3600
end
@@ -128,7 +128,7 @@ describe "Time.now" do
Class.new(Time).new(time.year, time.mon, time.day, time.hour, time.min, time.sec, time.utc_offset)
end
- Time.now(in: zone).should be_kind_of(Time)
+ Time.now(in: zone).should.is_a?(Time)
Time.now(in: zone).utc_offset.should == 3600
end
@@ -138,7 +138,7 @@ describe "Time.now" do
time.to_i + 60*60
end
- Time.now(in: zone).should be_kind_of(Time)
+ Time.now(in: zone).should.is_a?(Time)
Time.now(in: zone).utc_offset.should == 60*60
end
@@ -174,7 +174,7 @@ describe "Time.now" do
-> {
Time.now(in: zone)
- }.should raise_error(ArgumentError, "utc_offset out of range")
+ }.should.raise(ArgumentError, "utc_offset out of range")
end
end
end
diff --git a/spec/ruby/core/time/plus_spec.rb b/spec/ruby/core/time/plus_spec.rb
index 642393b615..6bd01bcdf3 100644
--- a/spec/ruby/core/time/plus_spec.rb
+++ b/spec/ruby/core/time/plus_spec.rb
@@ -17,9 +17,9 @@ describe "Time#+" do
end
it "raises a TypeError if given argument is a coercible String" do
- -> { Time.now + "1" }.should raise_error(TypeError)
- -> { Time.now + "0.1" }.should raise_error(TypeError)
- -> { Time.now + "1/3" }.should raise_error(TypeError)
+ -> { Time.now + "1" }.should.raise(TypeError)
+ -> { Time.now + "0.1" }.should.raise(TypeError)
+ -> { Time.now + "1/3" }.should.raise(TypeError)
end
it "increments the time by the specified amount as rational numbers" do
@@ -32,8 +32,8 @@ describe "Time#+" do
end
it "raises TypeError on argument that can't be coerced into Rational" do
- -> { Time.now + Object.new }.should raise_error(TypeError)
- -> { Time.now + "stuff" }.should raise_error(TypeError)
+ -> { Time.now + Object.new }.should.raise(TypeError)
+ -> { Time.now + "stuff" }.should.raise(TypeError)
end
it "returns a UTC time if self is UTC" do
@@ -68,15 +68,15 @@ describe "Time#+" do
it "does not return a subclass instance" do
c = Class.new(Time)
x = c.now + 1
- x.should be_an_instance_of(Time)
+ x.should.instance_of?(Time)
end
it "raises TypeError on Time argument" do
- -> { Time.now + Time.now }.should raise_error(TypeError)
+ -> { Time.now + Time.now }.should.raise(TypeError)
end
it "raises TypeError on nil argument" do
- -> { Time.now + nil }.should raise_error(TypeError)
+ -> { Time.now + nil }.should.raise(TypeError)
end
#see [ruby-dev:38446]
diff --git a/spec/ruby/core/time/round_spec.rb b/spec/ruby/core/time/round_spec.rb
index 0cbed04ade..a739cabfdf 100644
--- a/spec/ruby/core/time/round_spec.rb
+++ b/spec/ruby/core/time/round_spec.rb
@@ -20,8 +20,8 @@ describe "Time#round" do
it "returns an instance of Time, even if #round is called on a subclass" do
subclass = Class.new(Time)
instance = subclass.at(0)
- instance.class.should equal subclass
- instance.round.should be_an_instance_of(Time)
+ instance.class.should.equal? subclass
+ instance.round.should.instance_of?(Time)
end
it "copies own timezone to the returning value" do
diff --git a/spec/ruby/core/time/shared/asctime.rb b/spec/ruby/core/time/shared/asctime.rb
deleted file mode 100644
index d096666863..0000000000
--- a/spec/ruby/core/time/shared/asctime.rb
+++ /dev/null
@@ -1,6 +0,0 @@
-describe :time_asctime, shared: true do
- it "returns a canonical string representation of time" do
- t = Time.now
- t.send(@method).should == t.strftime("%a %b %e %H:%M:%S %Y")
- end
-end
diff --git a/spec/ruby/core/time/shared/day.rb b/spec/ruby/core/time/shared/day.rb
deleted file mode 100644
index 472dc959c1..0000000000
--- a/spec/ruby/core/time/shared/day.rb
+++ /dev/null
@@ -1,15 +0,0 @@
-describe :time_day, shared: true do
- it "returns the day of the month (1..n) for a local Time" do
- with_timezone("CET", 1) do
- Time.local(1970, 1, 1).send(@method).should == 1
- end
- end
-
- it "returns the day of the month for a UTC Time" do
- Time.utc(1970, 1, 1).send(@method).should == 1
- end
-
- it "returns the day of the month for a Time with a fixed offset" do
- Time.new(2012, 1, 1, 0, 0, 0, -3600).send(@method).should == 1
- end
-end
diff --git a/spec/ruby/core/time/shared/getgm.rb b/spec/ruby/core/time/shared/getgm.rb
deleted file mode 100644
index 3576365772..0000000000
--- a/spec/ruby/core/time/shared/getgm.rb
+++ /dev/null
@@ -1,9 +0,0 @@
-describe :time_getgm, shared: true do
- it "returns a new time which is the utc representation of time" do
- # Testing with America/Regina here because it doesn't have DST.
- with_timezone("CST", -6) do
- t = Time.local(2007, 1, 9, 6, 0, 0)
- t.send(@method).should == Time.gm(2007, 1, 9, 12, 0, 0)
- end
- end
-end
diff --git a/spec/ruby/core/time/shared/gm.rb b/spec/ruby/core/time/shared/gm.rb
deleted file mode 100644
index 0ee602c837..0000000000
--- a/spec/ruby/core/time/shared/gm.rb
+++ /dev/null
@@ -1,70 +0,0 @@
-describe :time_gm, shared: true do
- it "creates a time based on given values, interpreted as UTC (GMT)" do
- Time.send(@method, 2000,"jan",1,20,15,1).inspect.should == "2000-01-01 20:15:01 UTC"
- end
-
- it "creates a time based on given C-style gmtime arguments, interpreted as UTC (GMT)" do
- time = Time.send(@method, 1, 15, 20, 1, 1, 2000, :ignored, :ignored, :ignored, :ignored)
- time.inspect.should == "2000-01-01 20:15:01 UTC"
- end
-
- it "interprets pre-Gregorian reform dates using Gregorian proleptic calendar" do
- Time.send(@method, 1582, 10, 4, 12).to_i.should == -12220200000 # 2299150j
- end
-
- it "interprets Julian-Gregorian gap dates using Gregorian proleptic calendar" do
- Time.send(@method, 1582, 10, 14, 12).to_i.should == -12219336000 # 2299160j
- end
-
- it "interprets post-Gregorian reform dates using Gregorian calendar" do
- Time.send(@method, 1582, 10, 15, 12).to_i.should == -12219249600 # 2299161j
- end
-
- it "handles fractional usec close to rounding limit" do
- time = Time.send(@method, 2000, 1, 1, 12, 30, 0, 9999r/10000)
-
- time.usec.should == 0
- time.nsec.should == 999
- end
-
- guard -> {
- with_timezone 'right/UTC' do
- (Time.gm(1972, 6, 30, 23, 59, 59) + 1).sec == 60
- end
- } do
- it "handles real leap seconds in zone 'right/UTC'" do
- with_timezone 'right/UTC' do
- time = Time.send(@method, 1972, 6, 30, 23, 59, 60)
-
- time.sec.should == 60
- time.min.should == 59
- time.hour.should == 23
- time.day.should == 30
- time.month.should == 6
- end
- end
- end
-
- it "handles bad leap seconds by carrying values forward" do
- with_timezone 'UTC' do
- time = Time.send(@method, 2017, 7, 5, 23, 59, 60)
- time.sec.should == 0
- time.min.should == 0
- time.hour.should == 0
- time.day.should == 6
- time.month.should == 7
- end
- end
-
- it "handles a value of 60 for seconds by carrying values forward in zone 'UTC'" do
- with_timezone 'UTC' do
- time = Time.send(@method, 1972, 6, 30, 23, 59, 60)
-
- time.sec.should == 0
- time.min.should == 0
- time.hour.should == 0
- time.day.should == 1
- time.month.should == 7
- end
- end
-end
diff --git a/spec/ruby/core/time/shared/gmt_offset.rb b/spec/ruby/core/time/shared/gmt_offset.rb
deleted file mode 100644
index 839566c249..0000000000
--- a/spec/ruby/core/time/shared/gmt_offset.rb
+++ /dev/null
@@ -1,59 +0,0 @@
-describe :time_gmt_offset, shared: true do
- it "returns the offset in seconds between the timezone of time and UTC" do
- with_timezone("AST", 3) do
- Time.new.send(@method).should == 10800
- end
- end
-
- it "returns 0 when the date is UTC" do
- with_timezone("AST", 3) do
- Time.new.utc.send(@method).should == 0
- end
- end
-
- platform_is_not :windows do
- it "returns the correct offset for US Eastern time zone around daylight savings time change" do
- # "2010-03-14 01:59:59 -0500" + 1 ==> "2010-03-14 03:00:00 -0400"
- with_timezone("EST5EDT") do
- t = Time.local(2010,3,14,1,59,59)
- t.send(@method).should == -5*60*60
- (t + 1).send(@method).should == -4*60*60
- end
- end
-
- it "returns the correct offset for Hawaii around daylight savings time change" do
- # "2010-03-14 01:59:59 -1000" + 1 ==> "2010-03-14 02:00:00 -1000"
- with_timezone("Pacific/Honolulu") do
- t = Time.local(2010,3,14,1,59,59)
- t.send(@method).should == -10*60*60
- (t + 1).send(@method).should == -10*60*60
- end
- end
-
- it "returns the correct offset for New Zealand around daylight savings time change" do
- # "2010-04-04 02:59:59 +1300" + 1 ==> "2010-04-04 02:00:00 +1200"
- with_timezone("Pacific/Auckland") do
- t = Time.local(2010,4,4,1,59,59) + (60 * 60)
- t.send(@method).should == 13*60*60
- (t + 1).send(@method).should == 12*60*60
- end
- end
- end
-
- it "returns offset as Rational" do
- Time.new(2010,4,4,1,59,59,7245).send(@method).should == 7245
- Time.new(2010,4,4,1,59,59,7245.5).send(@method).should == Rational(14491,2)
- end
-
- context 'given positive offset' do
- it 'returns a positive offset' do
- Time.new(2013,3,17,nil,nil,nil,"+03:00").send(@method).should == 10800
- end
- end
-
- context 'given negative offset' do
- it 'returns a negative offset' do
- Time.new(2013,3,17,nil,nil,nil,"-03:00").send(@method).should == -10800
- end
- end
-end
diff --git a/spec/ruby/core/time/shared/gmtime.rb b/spec/ruby/core/time/shared/gmtime.rb
deleted file mode 100644
index 7b4f65f0b7..0000000000
--- a/spec/ruby/core/time/shared/gmtime.rb
+++ /dev/null
@@ -1,40 +0,0 @@
-describe :time_gmtime, shared: true do
- it "converts self to UTC, modifying the receiver" do
- # Testing with America/Regina here because it doesn't have DST.
- with_timezone("CST", -6) do
- t = Time.local(2007, 1, 9, 6, 0, 0)
- t.send(@method)
- # Time#== compensates for time zones, so check all parts separately
- t.year.should == 2007
- t.month.should == 1
- t.mday.should == 9
- t.hour.should == 12
- t.min.should == 0
- t.sec.should == 0
- t.zone.should == "UTC"
- end
- end
-
- it "returns self" do
- with_timezone("CST", -6) do
- t = Time.local(2007, 1, 9, 12, 0, 0)
- t.send(@method).should equal(t)
- end
- end
-
- describe "on a frozen time" do
- it "does not raise an error if already in UTC" do
- time = Time.gm(2007, 1, 9, 12, 0, 0)
- time.freeze
- time.send(@method).should equal(time)
- end
-
- it "raises a FrozenError if the time is not UTC" do
- with_timezone("CST", -6) do
- time = Time.now
- time.freeze
- -> { time.send(@method) }.should raise_error(FrozenError)
- end
- end
- end
-end
diff --git a/spec/ruby/core/time/shared/inspect.rb b/spec/ruby/core/time/shared/inspect.rb
index 4133671924..82f7f3c686 100644
--- a/spec/ruby/core/time/shared/inspect.rb
+++ b/spec/ruby/core/time/shared/inspect.rb
@@ -16,6 +16,6 @@ describe :inspect, shared: true do
end
it "returns a US-ASCII encoded string" do
- Time.now.send(@method).encoding.should equal(Encoding::US_ASCII)
+ Time.now.send(@method).encoding.should.equal?(Encoding::US_ASCII)
end
end
diff --git a/spec/ruby/core/time/shared/isdst.rb b/spec/ruby/core/time/shared/isdst.rb
deleted file mode 100644
index bc6d139230..0000000000
--- a/spec/ruby/core/time/shared/isdst.rb
+++ /dev/null
@@ -1,8 +0,0 @@
-describe :time_isdst, shared: true do
- it "dst? returns whether time is during daylight saving time" do
- with_timezone("America/Los_Angeles") do
- Time.local(2007, 9, 9, 0, 0, 0).send(@method).should == true
- Time.local(2007, 1, 9, 0, 0, 0).send(@method).should == false
- end
- end
-end
diff --git a/spec/ruby/core/time/shared/month.rb b/spec/ruby/core/time/shared/month.rb
deleted file mode 100644
index 31ca679557..0000000000
--- a/spec/ruby/core/time/shared/month.rb
+++ /dev/null
@@ -1,15 +0,0 @@
-describe :time_month, shared: true do
- it "returns the month of the year for a local Time" do
- with_timezone("CET", 1) do
- Time.local(1970, 1).send(@method).should == 1
- end
- end
-
- it "returns the month of the year for a UTC Time" do
- Time.utc(1970, 1).send(@method).should == 1
- end
-
- it "returns the four digit year for a Time with a fixed offset" do
- Time.new(2012, 1, 1, 0, 0, 0, -3600).send(@method).should == 1
- end
-end
diff --git a/spec/ruby/core/time/shared/now.rb b/spec/ruby/core/time/shared/now.rb
index f4018d72f4..839cfdcd2a 100644
--- a/spec/ruby/core/time/shared/now.rb
+++ b/spec/ruby/core/time/shared/now.rb
@@ -2,8 +2,8 @@ require_relative '../fixtures/classes'
describe :time_now, shared: true do
it "creates a subclass instance if called on a subclass" do
- TimeSpecs::SubTime.send(@method).should be_an_instance_of(TimeSpecs::SubTime)
- TimeSpecs::MethodHolder.send(@method).should be_an_instance_of(Time)
+ TimeSpecs::SubTime.send(@method).should.instance_of?(TimeSpecs::SubTime)
+ TimeSpecs::MethodHolder.send(@method).should.instance_of?(Time)
end
it "sets the current time" do
diff --git a/spec/ruby/core/time/shared/time_params.rb b/spec/ruby/core/time/shared/time_params.rb
index 9832fd17fe..f0de986b8e 100644
--- a/spec/ruby/core/time/shared/time_params.rb
+++ b/spec/ruby/core/time/shared/time_params.rb
@@ -30,7 +30,7 @@ describe :time_params, shared: true do
end
it "raises a TypeError if the year is nil" do
- -> { Time.send(@method, nil) }.should raise_error(TypeError)
+ -> { Time.send(@method, nil) }.should.raise(TypeError)
end
it "accepts nil month, day, hour, minute, and second" do
@@ -148,52 +148,52 @@ describe :time_params, shared: true do
# For some reason MRI uses a different message for month in 13-15 and month>=16
-> {
Time.send(@method, 2008, 16, 31, 23, 59, 59)
- }.should raise_error(ArgumentError, /(mon|argument) out of range/)
+ }.should.raise(ArgumentError, /(mon|argument) out of range/)
end
it "raises an ArgumentError for out of range day" do
-> {
Time.send(@method, 2008, 12, 32, 23, 59, 59)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
it "raises an ArgumentError for out of range hour" do
-> {
Time.send(@method, 2008, 12, 31, 25, 59, 59)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
it "raises an ArgumentError for out of range minute" do
-> {
Time.send(@method, 2008, 12, 31, 23, 61, 59)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
it "raises an ArgumentError for out of range second" do
# For some reason MRI uses different messages for seconds 61-63 and seconds >= 64
-> {
Time.send(@method, 2008, 12, 31, 23, 59, 61)
- }.should raise_error(ArgumentError, /(sec|argument) out of range/)
+ }.should.raise(ArgumentError, /(sec|argument) out of range/)
-> {
Time.send(@method, 2008, 12, 31, 23, 59, -1)
- }.should raise_error(ArgumentError, "argument out of range")
+ }.should.raise(ArgumentError, "argument out of range")
end
it "raises ArgumentError when given 8 arguments" do
- -> { Time.send(@method, *[0]*8) }.should raise_error(ArgumentError)
+ -> { Time.send(@method, *[0]*8) }.should.raise(ArgumentError)
end
it "raises ArgumentError when given 9 arguments" do
- -> { Time.send(@method, *[0]*9) }.should raise_error(ArgumentError)
+ -> { Time.send(@method, *[0]*9) }.should.raise(ArgumentError)
end
it "raises ArgumentError when given 11 arguments" do
- -> { Time.send(@method, *[0]*11) }.should raise_error(ArgumentError)
+ -> { Time.send(@method, *[0]*11) }.should.raise(ArgumentError)
end
it "returns subclass instances" do
c = Class.new(Time)
- c.send(@method, 2008, "12").should be_an_instance_of(c)
+ c.send(@method, 2008, "12").should.instance_of?(c)
end
end
@@ -213,23 +213,23 @@ describe :time_params_10_arg, shared: true do
it "raises an ArgumentError for out of range values" do
-> {
Time.send(@method, 61, 59, 23, 31, 12, 2008, :ignored, :ignored, :ignored, :ignored)
- }.should raise_error(ArgumentError) # sec
+ }.should.raise(ArgumentError) # sec
-> {
Time.send(@method, 59, 61, 23, 31, 12, 2008, :ignored, :ignored, :ignored, :ignored)
- }.should raise_error(ArgumentError) # min
+ }.should.raise(ArgumentError) # min
-> {
Time.send(@method, 59, 59, 25, 31, 12, 2008, :ignored, :ignored, :ignored, :ignored)
- }.should raise_error(ArgumentError) # hour
+ }.should.raise(ArgumentError) # hour
-> {
Time.send(@method, 59, 59, 23, 32, 12, 2008, :ignored, :ignored, :ignored, :ignored)
- }.should raise_error(ArgumentError) # day
+ }.should.raise(ArgumentError) # day
-> {
Time.send(@method, 59, 59, 23, 31, 13, 2008, :ignored, :ignored, :ignored, :ignored)
- }.should raise_error(ArgumentError) # month
+ }.should.raise(ArgumentError) # month
end
end
@@ -240,7 +240,7 @@ describe :time_params_microseconds, shared: true do
end
it "raises an ArgumentError for out of range microsecond" do
- -> { Time.send(@method, 2000, 1, 1, 20, 15, 1, 1000000) }.should raise_error(ArgumentError)
+ -> { Time.send(@method, 2000, 1, 1, 20, 15, 1, 1000000) }.should.raise(ArgumentError)
end
it "handles fractional microseconds as a Float" do
diff --git a/spec/ruby/core/time/shared/to_i.rb b/spec/ruby/core/time/shared/to_i.rb
deleted file mode 100644
index 06c966b708..0000000000
--- a/spec/ruby/core/time/shared/to_i.rb
+++ /dev/null
@@ -1,16 +0,0 @@
-describe :time_to_i, shared: true do
- it "returns the value of time as an integer number of seconds since epoch" do
- Time.at(0).send(@method).should == 0
- end
-
- it "doesn't return an actual number of seconds in time" do
- Time.at(65.5).send(@method).should == 65
- end
-
- it "rounds fractional seconds toward zero" do
- t = Time.utc(1960, 1, 1, 0, 0, 0, 999_999)
-
- t.to_f.to_i.should == -315619199
- t.to_i.should == -315619200
- 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/strftime_spec.rb b/spec/ruby/core/time/strftime_spec.rb
index fd233f3577..1528a668a1 100644
--- a/spec/ruby/core/time/strftime_spec.rb
+++ b/spec/ruby/core/time/strftime_spec.rb
@@ -25,7 +25,7 @@ describe "Time#strftime" do
# Differences with date
it "requires an argument" do
- -> { @time.strftime }.should raise_error(ArgumentError)
+ -> { @time.strftime }.should.raise(ArgumentError)
end
# %Z is zone name or empty for Time
diff --git a/spec/ruby/core/time/subsec_spec.rb b/spec/ruby/core/time/subsec_spec.rb
index 0f2c4eb856..3ed1bf5dd1 100644
--- a/spec/ruby/core/time/subsec_spec.rb
+++ b/spec/ruby/core/time/subsec_spec.rb
@@ -2,26 +2,26 @@ require_relative '../../spec_helper'
describe "Time#subsec" do
it "returns 0 as an Integer for a Time with a whole number of seconds" do
- Time.at(100).subsec.should eql(0)
+ Time.at(100).subsec.should.eql?(0)
end
it "returns the fractional seconds as a Rational for a Time constructed with a Rational number of seconds" do
- Time.at(Rational(3, 2)).subsec.should eql(Rational(1, 2))
+ Time.at(Rational(3, 2)).subsec.should.eql?(Rational(1, 2))
end
it "returns the fractional seconds as a Rational for a Time constructed with a Float number of seconds" do
- Time.at(10.75).subsec.should eql(Rational(3, 4))
+ Time.at(10.75).subsec.should.eql?(Rational(3, 4))
end
it "returns the fractional seconds as a Rational for a Time constructed with an Integer number of microseconds" do
- Time.at(0, 999999).subsec.should eql(Rational(999999, 1000000))
+ Time.at(0, 999999).subsec.should.eql?(Rational(999999, 1000000))
end
it "returns the fractional seconds as a Rational for a Time constructed with an Rational number of microseconds" do
- Time.at(0, Rational(9, 10)).subsec.should eql(Rational(9, 10000000))
+ Time.at(0, Rational(9, 10)).subsec.should.eql?(Rational(9, 10000000))
end
it "returns the fractional seconds as a Rational for a Time constructed with an Float number of microseconds" do
- Time.at(0, 0.75).subsec.should eql(Rational(3, 4000000))
+ Time.at(0, 0.75).subsec.should.eql?(Rational(3, 4000000))
end
end
diff --git a/spec/ruby/core/time/to_i_spec.rb b/spec/ruby/core/time/to_i_spec.rb
index 54929d1e18..00c4215d31 100644
--- a/spec/ruby/core/time/to_i_spec.rb
+++ b/spec/ruby/core/time/to_i_spec.rb
@@ -1,6 +1,18 @@
require_relative '../../spec_helper'
-require_relative 'shared/to_i'
describe "Time#to_i" do
- it_behaves_like :time_to_i, :to_i
+ it "returns the value of time as an integer number of seconds since epoch" do
+ Time.at(0).to_i.should == 0
+ end
+
+ it "doesn't return an actual number of seconds in time" do
+ Time.at(65.5).to_i.should == 65
+ end
+
+ it "rounds fractional seconds toward zero" do
+ t = Time.utc(1960, 1, 1, 0, 0, 0, 999_999)
+
+ t.to_f.to_i.should == -315619199
+ t.to_i.should == -315619200
+ end
end
diff --git a/spec/ruby/core/time/to_r_spec.rb b/spec/ruby/core/time/to_r_spec.rb
index 6af2d9b7ea..e30f5d8f94 100644
--- a/spec/ruby/core/time/to_r_spec.rb
+++ b/spec/ruby/core/time/to_r_spec.rb
@@ -2,10 +2,10 @@ require_relative '../../spec_helper'
describe "Time#to_r" do
it "returns the a Rational representing seconds and subseconds since the epoch" do
- Time.at(Rational(11, 10)).to_r.should eql(Rational(11, 10))
+ Time.at(Rational(11, 10)).to_r.should.eql?(Rational(11, 10))
end
it "returns a Rational even for a whole number of seconds" do
- Time.at(2).to_r.should eql(Rational(2))
+ Time.at(2).to_r.should.eql?(Rational(2))
end
end
diff --git a/spec/ruby/core/time/tv_nsec_spec.rb b/spec/ruby/core/time/tv_nsec_spec.rb
index feb7998b16..802138bf3a 100644
--- a/spec/ruby/core/time/tv_nsec_spec.rb
+++ b/spec/ruby/core/time/tv_nsec_spec.rb
@@ -1,5 +1,7 @@
require_relative '../../spec_helper'
describe "Time#tv_nsec" do
- it "needs to be reviewed for spec completeness"
+ it "is an alias of Time#nsec" do
+ Time.instance_method(:tv_nsec).should == Time.instance_method(:nsec)
+ end
end
diff --git a/spec/ruby/core/time/tv_sec_spec.rb b/spec/ruby/core/time/tv_sec_spec.rb
index f83e1fbfdd..21bdb53ee6 100644
--- a/spec/ruby/core/time/tv_sec_spec.rb
+++ b/spec/ruby/core/time/tv_sec_spec.rb
@@ -1,6 +1,7 @@
require_relative '../../spec_helper'
-require_relative 'shared/to_i'
describe "Time#tv_sec" do
- it_behaves_like :time_to_i, :tv_sec
+ it "is an alias of Time#to_i" do
+ Time.instance_method(:tv_sec).should == Time.instance_method(:to_i)
+ end
end
diff --git a/spec/ruby/core/time/tv_usec_spec.rb b/spec/ruby/core/time/tv_usec_spec.rb
index f0de4f4a9c..e922ee5625 100644
--- a/spec/ruby/core/time/tv_usec_spec.rb
+++ b/spec/ruby/core/time/tv_usec_spec.rb
@@ -1,5 +1,7 @@
require_relative '../../spec_helper'
describe "Time#tv_usec" do
- it "needs to be reviewed for spec completeness"
+ it "is an alias of Time#usec" do
+ Time.instance_method(:tv_usec).should == Time.instance_method(:usec)
+ end
end
diff --git a/spec/ruby/core/time/utc_offset_spec.rb b/spec/ruby/core/time/utc_offset_spec.rb
index 17c031b8c6..8d2fff2012 100644
--- a/spec/ruby/core/time/utc_offset_spec.rb
+++ b/spec/ruby/core/time/utc_offset_spec.rb
@@ -1,6 +1,61 @@
require_relative '../../spec_helper'
-require_relative 'shared/gmt_offset'
describe "Time#utc_offset" do
- it_behaves_like :time_gmt_offset, :utc_offset
+ it "returns the offset in seconds between the timezone of time and UTC" do
+ with_timezone("AST", 3) do
+ Time.new.utc_offset.should == 10800
+ end
+ end
+
+ it "returns 0 when the date is UTC" do
+ with_timezone("AST", 3) do
+ Time.new.utc.utc_offset.should == 0
+ end
+ end
+
+ platform_is_not :windows do
+ it "returns the correct offset for US Eastern time zone around daylight savings time change" do
+ # "2010-03-14 01:59:59 -0500" + 1 ==> "2010-03-14 03:00:00 -0400"
+ with_timezone("EST5EDT") do
+ t = Time.local(2010,3,14,1,59,59)
+ t.utc_offset.should == -5*60*60
+ (t + 1).utc_offset.should == -4*60*60
+ end
+ end
+
+ it "returns the correct offset for Hawaii around daylight savings time change" do
+ # "2010-03-14 01:59:59 -1000" + 1 ==> "2010-03-14 02:00:00 -1000"
+ with_timezone("Pacific/Honolulu") do
+ t = Time.local(2010,3,14,1,59,59)
+ t.utc_offset.should == -10*60*60
+ (t + 1).utc_offset.should == -10*60*60
+ end
+ end
+
+ it "returns the correct offset for New Zealand around daylight savings time change" do
+ # "2010-04-04 02:59:59 +1300" + 1 ==> "2010-04-04 02:00:00 +1200"
+ with_timezone("Pacific/Auckland") do
+ t = Time.local(2010,4,4,1,59,59) + (60 * 60)
+ t.utc_offset.should == 13*60*60
+ (t + 1).utc_offset.should == 12*60*60
+ end
+ end
+ end
+
+ it "returns offset as Rational" do
+ Time.new(2010,4,4,1,59,59,7245).utc_offset.should == 7245
+ Time.new(2010,4,4,1,59,59,7245.5).utc_offset.should == Rational(14491,2)
+ end
+
+ context 'given positive offset' do
+ it 'returns a positive offset' do
+ Time.new(2013,3,17,nil,nil,nil,"+03:00").utc_offset.should == 10800
+ end
+ end
+
+ context 'given negative offset' do
+ it 'returns a negative offset' do
+ Time.new(2013,3,17,nil,nil,nil,"-03:00").utc_offset.should == -10800
+ end
+ end
end
diff --git a/spec/ruby/core/time/utc_spec.rb b/spec/ruby/core/time/utc_spec.rb
index 3d36e13ccf..35c1daa9e5 100644
--- a/spec/ruby/core/time/utc_spec.rb
+++ b/spec/ruby/core/time/utc_spec.rb
@@ -1,6 +1,4 @@
require_relative '../../spec_helper'
-require_relative 'shared/gm'
-require_relative 'shared/gmtime'
require_relative 'shared/time_params'
describe "Time#utc?" do
@@ -11,7 +9,7 @@ describe "Time#utc?" do
it "treats time as UTC what was created in different ways" do
Time.now.utc.utc?.should == true
- Time.now.gmtime.utc?.should == true
+ Time.now.utc.utc?.should == true
Time.now.getgm.utc?.should == true
Time.now.getutc.utc?.should == true
Time.utc(2022).utc?.should == true
@@ -43,20 +41,129 @@ describe "Time#utc?" do
it "does not treat time with +00:00 offset as UTC" do
Time.new(2022, 1, 1, 0, 0, 0, "+00:00").utc?.should == false
+ Time.now.localtime("+00:00").utc?.should == false
+ Time.at(Time.now, in: "+00:00").utc?.should == false
end
it "does not treat time with 0 offset as UTC" do
Time.new(2022, 1, 1, 0, 0, 0, 0).utc?.should == false
+ Time.now.localtime(0).utc?.should == false
+ Time.at(Time.now, in: 0).utc?.should == false
end
end
describe "Time.utc" do
- it_behaves_like :time_gm, :utc
it_behaves_like :time_params, :utc
it_behaves_like :time_params_10_arg, :utc
it_behaves_like :time_params_microseconds, :utc
+
+ it "creates a time based on given values, interpreted as UTC (GMT)" do
+ Time.utc(2000,"jan",1,20,15,1).inspect.should == "2000-01-01 20:15:01 UTC"
+ end
+
+ it "creates a time based on given C-style gmtime arguments, interpreted as UTC (GMT)" do
+ time = Time.utc(1, 15, 20, 1, 1, 2000, :ignored, :ignored, :ignored, :ignored)
+ time.inspect.should == "2000-01-01 20:15:01 UTC"
+ end
+
+ it "interprets pre-Gregorian reform dates using Gregorian proleptic calendar" do
+ Time.utc(1582, 10, 4, 12).to_i.should == -12220200000 # 2299150j
+ end
+
+ it "interprets Julian-Gregorian gap dates using Gregorian proleptic calendar" do
+ Time.utc(1582, 10, 14, 12).to_i.should == -12219336000 # 2299160j
+ end
+
+ it "interprets post-Gregorian reform dates using Gregorian calendar" do
+ Time.utc(1582, 10, 15, 12).to_i.should == -12219249600 # 2299161j
+ end
+
+ it "handles fractional usec close to rounding limit" do
+ time = Time.utc(2000, 1, 1, 12, 30, 0, 9999r/10000)
+
+ time.usec.should == 0
+ time.nsec.should == 999
+ end
+
+ guard -> {
+ with_timezone 'right/UTC' do
+ (Time.utc(1972, 6, 30, 23, 59, 59) + 1).sec == 60
+ end
+ } do
+ it "handles real leap seconds in zone 'right/UTC'" do
+ with_timezone 'right/UTC' do
+ time = Time.utc(1972, 6, 30, 23, 59, 60)
+
+ time.sec.should == 60
+ time.min.should == 59
+ time.hour.should == 23
+ time.day.should == 30
+ time.month.should == 6
+ end
+ end
+ end
+
+ it "handles bad leap seconds by carrying values forward" do
+ with_timezone 'UTC' do
+ time = Time.utc(2017, 7, 5, 23, 59, 60)
+ time.sec.should == 0
+ time.min.should == 0
+ time.hour.should == 0
+ time.day.should == 6
+ time.month.should == 7
+ end
+ end
+
+ it "handles a value of 60 for seconds by carrying values forward in zone 'UTC'" do
+ with_timezone 'UTC' do
+ time = Time.utc(1972, 6, 30, 23, 59, 60)
+
+ time.sec.should == 0
+ time.min.should == 0
+ time.hour.should == 0
+ time.day.should == 1
+ time.month.should == 7
+ end
+ end
end
describe "Time#utc" do
- it_behaves_like :time_gmtime, :utc
+ it "converts self to UTC, modifying the receiver" do
+ # Testing with America/Regina here because it doesn't have DST.
+ with_timezone("CST", -6) do
+ t = Time.local(2007, 1, 9, 6, 0, 0)
+ t.utc
+ # Time#== compensates for time zones, so check all parts separately
+ t.year.should == 2007
+ t.month.should == 1
+ t.mday.should == 9
+ t.hour.should == 12
+ t.min.should == 0
+ t.sec.should == 0
+ t.zone.should == "UTC"
+ end
+ end
+
+ it "returns self" do
+ with_timezone("CST", -6) do
+ t = Time.local(2007, 1, 9, 12, 0, 0)
+ t.utc.should.equal?(t)
+ end
+ end
+
+ describe "on a frozen time" do
+ it "does not raise an error if already in UTC" do
+ time = Time.gm(2007, 1, 9, 12, 0, 0)
+ time.freeze
+ time.utc.should.equal?(time)
+ end
+
+ it "raises a FrozenError if the time is not UTC" do
+ with_timezone("CST", -6) do
+ time = Time.now
+ time.freeze
+ -> { time.utc }.should.raise(FrozenError)
+ end
+ end
+ end
end
diff --git a/spec/ruby/core/time/xmlschema_spec.rb b/spec/ruby/core/time/xmlschema_spec.rb
index bdf1dc7923..6a26861a45 100644
--- a/spec/ruby/core/time/xmlschema_spec.rb
+++ b/spec/ruby/core/time/xmlschema_spec.rb
@@ -1,6 +1,9 @@
require_relative '../../spec_helper'
-require_relative 'shared/xmlschema'
describe "Time#xmlschema" do
- it_behaves_like :time_xmlschema, :xmlschema
+ ruby_version_is "3.4" do
+ it "is an alias of Time#iso8601" do
+ Time.instance_method(:xmlschema).should == Time.instance_method(:iso8601)
+ end
+ end
end
diff --git a/spec/ruby/core/time/zone_spec.rb b/spec/ruby/core/time/zone_spec.rb
index 9a15bd569b..2cb3c5e7bb 100644
--- a/spec/ruby/core/time/zone_spec.rb
+++ b/spec/ruby/core/time/zone_spec.rb
@@ -6,7 +6,7 @@ describe "Time#zone" do
with_timezone("America/New_York") do
Time.new(2001, 1, 1, 0, 0, 0).zone.should == "EST"
Time.new(2001, 7, 1, 0, 0, 0).zone.should == "EDT"
- %w[EST EDT].should include Time.now.zone
+ %w[EST EDT].should.include? Time.now.zone
end
end
end
@@ -29,7 +29,7 @@ describe "Time#zone" do
t = Time.new(2005, 2, 27, 22, 50, 0, -3600)
with_timezone("America/New_York") do
- t.getlocal("+05:00").zone.should be_nil
+ t.getlocal("+05:00").zone.should == nil
end
end
diff --git a/spec/ruby/core/tracepoint/allow_reentry_spec.rb b/spec/ruby/core/tracepoint/allow_reentry_spec.rb
index 75e9e859a9..475cca29a9 100644
--- a/spec/ruby/core/tracepoint/allow_reentry_spec.rb
+++ b/spec/ruby/core/tracepoint/allow_reentry_spec.rb
@@ -25,6 +25,6 @@ describe 'TracePoint.allow_reentry' do
it 'raises RuntimeError when not called inside a TracePoint' do
-> {
TracePoint.allow_reentry{}
- }.should raise_error(RuntimeError)
+ }.should.raise(RuntimeError)
end
end
diff --git a/spec/ruby/core/tracepoint/binding_spec.rb b/spec/ruby/core/tracepoint/binding_spec.rb
index 6a7ef5f85a..6de6e47d7d 100644
--- a/spec/ruby/core/tracepoint/binding_spec.rb
+++ b/spec/ruby/core/tracepoint/binding_spec.rb
@@ -15,7 +15,7 @@ describe 'TracePoint#binding' do
test
}
bindings.size.should == 1
- bindings[0].should be_kind_of(Binding)
+ bindings[0].should.is_a?(Binding)
bindings[0].local_variables.should == [:secret]
end
end
diff --git a/spec/ruby/core/tracepoint/defined_class_spec.rb b/spec/ruby/core/tracepoint/defined_class_spec.rb
index 4593db6d1f..53c86a8210 100644
--- a/spec/ruby/core/tracepoint/defined_class_spec.rb
+++ b/spec/ruby/core/tracepoint/defined_class_spec.rb
@@ -9,19 +9,19 @@ describe 'TracePoint#defined_class' do
last_class_name = tp.defined_class
end.enable do
TracePointSpec::B.new.foo
- last_class_name.should equal(TracePointSpec::B)
+ last_class_name.should.equal?(TracePointSpec::B)
TracePointSpec::B.new.bar
- last_class_name.should equal(TracePointSpec::A)
+ last_class_name.should.equal?(TracePointSpec::A)
c = TracePointSpec::C.new
- last_class_name.should equal(TracePointSpec::C)
+ last_class_name.should.equal?(TracePointSpec::C)
c.foo
- last_class_name.should equal(TracePointSpec::B)
+ last_class_name.should.equal?(TracePointSpec::B)
c.bar
- last_class_name.should equal(TracePointSpec::A)
+ last_class_name.should.equal?(TracePointSpec::A)
end
end
end
diff --git a/spec/ruby/core/tracepoint/enable_spec.rb b/spec/ruby/core/tracepoint/enable_spec.rb
index 93a6b281e3..bf61c35154 100644
--- a/spec/ruby/core/tracepoint/enable_spec.rb
+++ b/spec/ruby/core/tracepoint/enable_spec.rb
@@ -54,7 +54,7 @@ describe 'TracePoint#enable' do
TracePoint.new(:line) do |tp|
next unless TracePointSpec.target_thread?
event_name = tp.event
- end.enable { event_name.should equal(:line) }
+ end.enable { event_name.should.equal?(:line) }
end
it 'enables the trace object only for the current thread' do
@@ -85,7 +85,7 @@ describe 'TracePoint#enable' do
event_name = tp.event
end
trace.enable do |*args|
- event_name.should equal(:line)
+ event_name.should.equal?(:line)
args.should == []
end
trace.should_not.enabled?
@@ -301,7 +301,7 @@ describe 'TracePoint#enable' do
end
ScratchPad.recorded.should == [lineno]
- lineno.should be_kind_of(Integer)
+ lineno.should.is_a?(Integer)
end
end
@@ -317,7 +317,7 @@ describe 'TracePoint#enable' do
trace.enable(target: block) do
block.call # triggers :b_call and :b_return events
end
- }.should raise_error(ArgumentError, /can not enable any hooks/)
+ }.should.raise(ArgumentError, /can not enable any hooks/)
end
it "raises ArgumentError if passed not Method/UnboundMethod/Proc" do
@@ -326,7 +326,7 @@ describe 'TracePoint#enable' do
-> {
trace.enable(target: Object.new) do
end
- }.should raise_error(ArgumentError, /specified target is not supported/)
+ }.should.raise(ArgumentError, /specified target is not supported/)
end
context "nested enabling and disabling" do
@@ -338,7 +338,7 @@ describe 'TracePoint#enable' do
trace.enable(target: -> {}) do
end
end
- }.should raise_error(ArgumentError, /can't nest-enable a targett?ing TracePoint/)
+ }.should.raise(ArgumentError, /can't nest-enable a targett?ing TracePoint/)
end
it "raises ArgumentError if trace point already enabled without target is re-enabled with target" do
@@ -349,7 +349,7 @@ describe 'TracePoint#enable' do
trace.enable(target: -> {}) do
end
end
- }.should raise_error(ArgumentError, /can't nest-enable a targett?ing TracePoint/)
+ }.should.raise(ArgumentError, /can't nest-enable a targett?ing TracePoint/)
end
it "raises ArgumentError if trace point already enabled with target is re-enabled without target" do
@@ -360,7 +360,7 @@ describe 'TracePoint#enable' do
trace.enable do
end
end
- }.should raise_error(ArgumentError, /can't nest-enable a targett?ing TracePoint/)
+ }.should.raise(ArgumentError, /can't nest-enable a targett?ing TracePoint/)
end
it "raises ArgumentError if trace point already enabled with target is disabled with block" do
@@ -371,7 +371,7 @@ describe 'TracePoint#enable' do
trace.disable do
end
end
- }.should raise_error(ArgumentError, /can't disable a targett?ing TracePoint in a block/)
+ }.should.raise(ArgumentError, /can't disable a targett?ing TracePoint in a block/)
end
it "traces events when trace point with target is enabled in another trace point enabled without target" do
@@ -474,7 +474,7 @@ describe 'TracePoint#enable' do
-> {
trace.enable(target_line: 67) do
end
- }.should raise_error(ArgumentError, /only target_line is specified/)
+ }.should.raise(ArgumentError, /only target_line is specified/)
end
it "raises ArgumentError if :line event isn't registered" do
@@ -491,7 +491,7 @@ describe 'TracePoint#enable' do
-> {
trace.enable(target_line: target_line, target: target) do
end
- }.should raise_error(ArgumentError, /target_line is specified, but line event is not specified/)
+ }.should.raise(ArgumentError, /target_line is specified, but line event is not specified/)
end
it "raises ArgumentError if :target_line value is out of target code lines range" do
@@ -500,7 +500,7 @@ describe 'TracePoint#enable' do
-> {
trace.enable(target_line: 1, target: -> { }) do
end
- }.should raise_error(ArgumentError, /can not enable any hooks/)
+ }.should.raise(ArgumentError, /can not enable any hooks/)
end
it "raises TypeError if :target_line value couldn't be coerced to Integer" do
@@ -509,7 +509,7 @@ describe 'TracePoint#enable' do
-> {
trace.enable(target_line: Object.new, target: -> { }) do
end
- }.should raise_error(TypeError, /no implicit conversion of \w+? into Integer/)
+ }.should.raise(TypeError, /no implicit conversion of \w+? into Integer/)
end
it "raises ArgumentError if :target_line value is negative" do
@@ -518,7 +518,7 @@ describe 'TracePoint#enable' do
-> {
trace.enable(target_line: -2, target: -> { }) do
end
- }.should raise_error(ArgumentError, /can not enable any hooks/)
+ }.should.raise(ArgumentError, /can not enable any hooks/)
end
it "accepts value that could be coerced to Integer" do
diff --git a/spec/ruby/core/tracepoint/event_spec.rb b/spec/ruby/core/tracepoint/event_spec.rb
index 9dea24d125..58017dc98d 100644
--- a/spec/ruby/core/tracepoint/event_spec.rb
+++ b/spec/ruby/core/tracepoint/event_spec.rb
@@ -9,13 +9,13 @@ describe 'TracePoint#event' do
event_name = tp.event
end.enable do
TracePointSpec.test
- event_name.should equal(:call)
+ event_name.should.equal?(:call)
TracePointSpec::B.new.foo
- event_name.should equal(:call)
+ event_name.should.equal?(:call)
class TracePointSpec::B; end
- event_name.should equal(:end)
+ event_name.should.equal?(:end)
end
end
diff --git a/spec/ruby/core/tracepoint/lineno_spec.rb b/spec/ruby/core/tracepoint/lineno_spec.rb
index 77b3ac8b54..7c46d5222b 100644
--- a/spec/ruby/core/tracepoint/lineno_spec.rb
+++ b/spec/ruby/core/tracepoint/lineno_spec.rb
@@ -15,6 +15,6 @@ describe 'TracePoint#lineno' do
it 'raises RuntimeError if accessed from outside' do
tp = TracePoint.new(:line) {}
- -> { tp.lineno }.should raise_error(RuntimeError, 'access from outside')
+ -> { tp.lineno }.should.raise(RuntimeError, 'access from outside')
end
end
diff --git a/spec/ruby/core/tracepoint/method_id_spec.rb b/spec/ruby/core/tracepoint/method_id_spec.rb
index 43e23248b7..67740f2d7d 100644
--- a/spec/ruby/core/tracepoint/method_id_spec.rb
+++ b/spec/ruby/core/tracepoint/method_id_spec.rb
@@ -9,7 +9,7 @@ describe 'TracePoint#method_id' do
method_name = tp.method_id
}.enable do
TracePointSpec.test
- method_name.should equal(:test)
+ method_name.should.equal?(:test)
end
end
end
diff --git a/spec/ruby/core/tracepoint/new_spec.rb b/spec/ruby/core/tracepoint/new_spec.rb
index e53c2b04a2..763b35292b 100644
--- a/spec/ruby/core/tracepoint/new_spec.rb
+++ b/spec/ruby/core/tracepoint/new_spec.rb
@@ -3,7 +3,7 @@ require_relative 'fixtures/classes'
describe 'TracePoint.new' do
it 'returns a new TracePoint object, not enabled by default' do
- TracePoint.new(:line) {}.enabled?.should be_false
+ TracePoint.new(:line) {}.enabled?.should == false
end
it 'includes :line event when event is not specified' do
@@ -12,15 +12,15 @@ describe 'TracePoint.new' do
next unless TracePointSpec.target_thread?
event_name = tp.event
}.enable do
- event_name.should equal(:line)
+ event_name.should.equal?(:line)
event_name = nil
TracePointSpec.test
- event_name.should equal(:line)
+ event_name.should.equal?(:line)
event_name = nil
TracePointSpec::B.new.foo
- event_name.should equal(:line)
+ event_name.should.equal?(:line)
end
end
@@ -44,29 +44,29 @@ describe 'TracePoint.new' do
event_name = tp.event
end.enable do
TracePointSpec.test
- event_name.should equal(:call)
+ event_name.should.equal?(:call)
TracePointSpec::B.new.foo
- event_name.should equal(:call)
+ event_name.should.equal?(:call)
class TracePointSpec::B; end
- event_name.should equal(:end)
+ event_name.should.equal?(:end)
end
end
it 'raises a TypeError when the given object is not a string/symbol' do
o = mock('123')
- -> { TracePoint.new(o) {} }.should raise_error(TypeError)
+ -> { TracePoint.new(o) {} }.should.raise(TypeError)
o.should_receive(:to_sym).and_return(123)
- -> { TracePoint.new(o) {} }.should raise_error(TypeError)
+ -> { TracePoint.new(o) {} }.should.raise(TypeError)
end
it 'expects to be called with a block' do
- -> { TracePoint.new(:line) }.should raise_error(ArgumentError, "must be called with a block")
+ -> { TracePoint.new(:line) }.should.raise(ArgumentError, "must be called with a block")
end
it "raises a Argument error when the given argument doesn't match an event name" do
- -> { TracePoint.new(:test) }.should raise_error(ArgumentError, "unknown event: test")
+ -> { TracePoint.new(:test) }.should.raise(ArgumentError, "unknown event: test")
end
end
diff --git a/spec/ruby/core/tracepoint/path_spec.rb b/spec/ruby/core/tracepoint/path_spec.rb
index dc2ca840b8..aa6868ead2 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 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})"
end
end
diff --git a/spec/ruby/core/tracepoint/raised_exception_spec.rb b/spec/ruby/core/tracepoint/raised_exception_spec.rb
index 5ac8531840..b1199902f2 100644
--- a/spec/ruby/core/tracepoint/raised_exception_spec.rb
+++ b/spec/ruby/core/tracepoint/raised_exception_spec.rb
@@ -14,25 +14,23 @@ describe 'TracePoint#raised_exception' do
rescue => e
error_result = e
end
- raised_exception.should equal(error_result)
+ raised_exception.should.equal?(error_result)
end
end
- ruby_version_is "3.3" do
- it 'returns value from exception rescued on the :rescue event' do
- raised_exception, error_result = nil
- trace = TracePoint.new(:rescue) { |tp|
- next unless TracePointSpec.target_thread?
- raised_exception = tp.raised_exception
- }
- trace.enable do
- begin
- raise StandardError
- rescue => e
- error_result = e
- end
- raised_exception.should equal(error_result)
+ it 'returns value from exception rescued on the :rescue event' do
+ raised_exception, error_result = nil
+ trace = TracePoint.new(:rescue) { |tp|
+ next unless TracePointSpec.target_thread?
+ raised_exception = tp.raised_exception
+ }
+ trace.enable do
+ begin
+ raise StandardError
+ rescue => e
+ error_result = e
end
+ raised_exception.should.equal?(error_result)
end
end
end
diff --git a/spec/ruby/core/tracepoint/self_spec.rb b/spec/ruby/core/tracepoint/self_spec.rb
index 2098860e59..bf9a2b6a45 100644
--- a/spec/ruby/core/tracepoint/self_spec.rb
+++ b/spec/ruby/core/tracepoint/self_spec.rb
@@ -8,7 +8,7 @@ describe 'TracePoint#self' do
next unless TracePointSpec.target_thread?
trace = tp.self
}.enable do
- trace.equal?(self).should be_true
+ trace.equal?(self).should == true
end
end
@@ -21,6 +21,6 @@ describe 'TracePoint#self' do
class TracePointSpec::C
end
end
- trace.should equal TracePointSpec::C
+ trace.should.equal? TracePointSpec::C
end
end
diff --git a/spec/ruby/core/true/dup_spec.rb b/spec/ruby/core/true/dup_spec.rb
index 351457ed22..2628f6d374 100644
--- a/spec/ruby/core/true/dup_spec.rb
+++ b/spec/ruby/core/true/dup_spec.rb
@@ -2,6 +2,6 @@ require_relative '../../spec_helper'
describe "TrueClass#dup" do
it "returns self" do
- true.dup.should equal(true)
+ true.dup.should.equal?(true)
end
end
diff --git a/spec/ruby/core/true/inspect_spec.rb b/spec/ruby/core/true/inspect_spec.rb
index 09d1914856..b9f5390b5c 100644
--- a/spec/ruby/core/true/inspect_spec.rb
+++ b/spec/ruby/core/true/inspect_spec.rb
@@ -1,7 +1,7 @@
require_relative '../../spec_helper'
describe "TrueClass#inspect" do
- it "returns the string 'true'" do
- true.inspect.should == "true"
+ it "is an alias of TrueClass#to_s" do
+ true.method(:inspect).should == true.method(:to_s)
end
end
diff --git a/spec/ruby/core/true/singleton_method_spec.rb b/spec/ruby/core/true/singleton_method_spec.rb
index c06793850f..58689fb6e5 100644
--- a/spec/ruby/core/true/singleton_method_spec.rb
+++ b/spec/ruby/core/true/singleton_method_spec.rb
@@ -1,15 +1,13 @@
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
+ it "raises regardless of whether TrueClass defines the method" do
+ -> { true.singleton_method(:foo) }.should.raise(NameError)
+ begin
+ def (true).foo; end
+ -> { true.singleton_method(:foo) }.should.raise(NameError)
+ ensure
+ TrueClass.send(:remove_method, :foo)
end
end
end
diff --git a/spec/ruby/core/true/to_s_spec.rb b/spec/ruby/core/true/to_s_spec.rb
index fa1b53a580..2c6f3889e9 100644
--- a/spec/ruby/core/true/to_s_spec.rb
+++ b/spec/ruby/core/true/to_s_spec.rb
@@ -10,6 +10,6 @@ describe "TrueClass#to_s" do
end
it "always returns the same string" do
- true.to_s.should equal(true.to_s)
+ true.to_s.should.equal?(true.to_s)
end
end
diff --git a/spec/ruby/core/true/trueclass_spec.rb b/spec/ruby/core/true/trueclass_spec.rb
index 02af649d09..1c1a0ddbe2 100644
--- a/spec/ruby/core/true/trueclass_spec.rb
+++ b/spec/ruby/core/true/trueclass_spec.rb
@@ -4,12 +4,12 @@ describe "TrueClass" do
it ".allocate raises a TypeError" do
-> do
TrueClass.allocate
- end.should raise_error(TypeError)
+ end.should.raise(TypeError)
end
it ".new is undefined" do
-> do
TrueClass.new
- end.should raise_error(NoMethodError)
+ end.should.raise(NoMethodError)
end
end
diff --git a/spec/ruby/core/unboundmethod/bind_call_spec.rb b/spec/ruby/core/unboundmethod/bind_call_spec.rb
index 80b2095d86..ee1dad9c9e 100644
--- a/spec/ruby/core/unboundmethod/bind_call_spec.rb
+++ b/spec/ruby/core/unboundmethod/bind_call_spec.rb
@@ -12,7 +12,7 @@ describe "UnboundMethod#bind_call" do
end
it "raises TypeError if object is not kind_of? the Module the method defined in" do
- -> { @normal_um.bind_call(UnboundMethodSpecs::B.new) }.should raise_error(TypeError)
+ -> { @normal_um.bind_call(UnboundMethodSpecs::B.new) }.should.raise(TypeError)
end
it "binds and calls the method if object is kind_of the Module the method defined in" do
@@ -47,7 +47,7 @@ describe "UnboundMethod#bind_call" do
end
end
um = p.method(:singleton_method).unbind
- ->{ um.bind_call(other) }.should raise_error(TypeError)
+ ->{ um.bind_call(other) }.should.raise(TypeError)
end
it "allows calling super for module methods bound to hierarchies that do not already have that module" do
diff --git a/spec/ruby/core/unboundmethod/bind_spec.rb b/spec/ruby/core/unboundmethod/bind_spec.rb
index 7658b664e5..087994ff57 100644
--- a/spec/ruby/core/unboundmethod/bind_spec.rb
+++ b/spec/ruby/core/unboundmethod/bind_spec.rb
@@ -12,15 +12,15 @@ describe "UnboundMethod#bind" do
end
it "raises TypeError if object is not kind_of? the Module the method defined in" do
- -> { @normal_um.bind(UnboundMethodSpecs::B.new) }.should raise_error(TypeError)
+ -> { @normal_um.bind(UnboundMethodSpecs::B.new) }.should.raise(TypeError)
end
it "returns Method for any object that is kind_of? the Module method was extracted from" do
- @normal_um.bind(UnboundMethodSpecs::Methods.new).should be_kind_of(Method)
+ @normal_um.bind(UnboundMethodSpecs::Methods.new).should.is_a?(Method)
end
it "returns Method on any object when UnboundMethod is unbound from a module" do
- UnboundMethodSpecs::Mod.instance_method(:from_mod).bind(Object.new).should be_kind_of(Method)
+ UnboundMethodSpecs::Mod.instance_method(:from_mod).bind(Object.new).should.is_a?(Method)
end
it "the returned Method is equal to the one directly returned by obj.method" do
@@ -29,9 +29,9 @@ describe "UnboundMethod#bind" do
end
it "returns Method for any object kind_of? the Module the method is defined in" do
- @parent_um.bind(UnboundMethodSpecs::Child1.new).should be_kind_of(Method)
- @child1_um.bind(UnboundMethodSpecs::Parent.new).should be_kind_of(Method)
- @child2_um.bind(UnboundMethodSpecs::Child1.new).should be_kind_of(Method)
+ @parent_um.bind(UnboundMethodSpecs::Child1.new).should.is_a?(Method)
+ @child1_um.bind(UnboundMethodSpecs::Parent.new).should.is_a?(Method)
+ @child2_um.bind(UnboundMethodSpecs::Child1.new).should.is_a?(Method)
end
it "allows binding a Kernel method retrieved from Object on BasicObject" do
@@ -45,7 +45,7 @@ describe "UnboundMethod#bind" do
it "binds a Parent's class method to any Child's class methods" do
m = UnboundMethodSpecs::Parent.method(:class_method).unbind.bind(UnboundMethodSpecs::Child1)
- m.should be_an_instance_of(Method)
+ m.should.instance_of?(Method)
m.call.should == "I am UnboundMethodSpecs::Child1"
end
@@ -58,7 +58,7 @@ describe "UnboundMethod#bind" do
end
end
um = p.method(:singleton_method).unbind
- ->{ um.bind(other) }.should raise_error(TypeError)
+ ->{ um.bind(other) }.should.raise(TypeError)
end
it "allows calling super for module methods bound to hierarchies that do not already have that module" do
diff --git a/spec/ruby/core/unboundmethod/eql_spec.rb b/spec/ruby/core/unboundmethod/eql_spec.rb
index cf2c6b5aae..3b299d047a 100644
--- a/spec/ruby/core/unboundmethod/eql_spec.rb
+++ b/spec/ruby/core/unboundmethod/eql_spec.rb
@@ -1,5 +1,7 @@
require_relative '../../spec_helper'
describe "UnboundMethod#eql?" do
- it "needs to be reviewed for spec completeness"
+ it "is an alias of UnboundMethod#==" do
+ UnboundMethod.instance_method(:eql?).should == UnboundMethod.instance_method(:==)
+ end
end
diff --git a/spec/ruby/core/unboundmethod/equal_value_spec.rb b/spec/ruby/core/unboundmethod/equal_value_spec.rb
index 4d4fc66504..24d5233299 100644
--- a/spec/ruby/core/unboundmethod/equal_value_spec.rb
+++ b/spec/ruby/core/unboundmethod/equal_value_spec.rb
@@ -3,8 +3,8 @@ require_relative 'fixtures/classes'
context "Creating UnboundMethods" do
specify "there is no difference between Method#unbind and Module#instance_method" do
- UnboundMethodSpecs::Methods.instance_method(:foo).should be_kind_of(UnboundMethod)
- UnboundMethodSpecs::Methods.new.method(:foo).unbind.should be_kind_of(UnboundMethod)
+ UnboundMethodSpecs::Methods.instance_method(:foo).should.is_a?(UnboundMethod)
+ UnboundMethodSpecs::Methods.new.method(:foo).unbind.should.is_a?(UnboundMethod)
end
end
@@ -35,6 +35,12 @@ describe "UnboundMethod#==" do
@method_one = UnboundMethodSpecs::Methods.instance_method(:one)
@method_two = UnboundMethodSpecs::Methods.instance_method(:two)
+
+ @mixin = UnboundMethodSpecs::Mixin.instance_method(:mixin_method)
+ @includer_base = UnboundMethodSpecs::IncluderBase.new.method(:mixin_method).unbind
+ @includer_child = UnboundMethodSpecs::IncluderChild.new.method(:mixin_method).unbind
+ @extender_base = UnboundMethodSpecs::ExtenderBase.method(:mixin_method).unbind
+ @extender_child = UnboundMethodSpecs::ExtenderChild.method(:mixin_method).unbind
end
it "returns true if objects refer to the same method" do
@@ -81,7 +87,7 @@ describe "UnboundMethod#==" do
(@child1 == @parent).should == true
end
- it "returns false if same method but extracted from two different subclasses" do
+ it "returns true if same method but extracted from two different subclasses" do
(@child2 == @child1).should == true
(@child1 == @child2).should == true
end
@@ -91,6 +97,30 @@ describe "UnboundMethod#==" do
(@includer == @includee).should == true
end
+ ruby_bug "#21873", ""..."4.1" do
+ it "returns true if same method is present in an object through module inclusion" do
+ (@mixin == @includer_base).should == true
+ (@includer_base == @mixin).should == true
+
+ (@mixin == @includer_child).should == true
+ (@includer_child == @mixin).should == true
+
+ (@includer_base == @includer_child).should == true
+ (@includer_child == @includer_base).should == true
+ end
+
+ it "returns true if same method is present in an object through module extension" do
+ (@mixin == @extender_base).should == true
+ (@extender_base == @mixin).should == true
+
+ (@mixin == @extender_child).should == true
+ (@extender_child == @mixin).should == true
+
+ (@extender_base == @extender_child).should == true
+ (@extender_child == @extender_base).should == true
+ end
+ end
+
it "returns false if both have same Module, same name, identical body but not the same" do
class UnboundMethodSpecs::Methods
def discard_1; :discard; end
@@ -110,9 +140,6 @@ describe "UnboundMethod#==" do
c.method(:n).should == Class.instance_method(:new).bind(c)
end
- # On CRuby < 3.2, the 2 specs below pass due to method/instance_method skipping zsuper methods.
- # We are interested in the general pattern working, i.e. the combination of method/instance_method
- # and #== exposes the wanted behavior.
it "considers methods through visibility change equal" do
c = Class.new do
class << self
diff --git a/spec/ruby/core/unboundmethod/fixtures/classes.rb b/spec/ruby/core/unboundmethod/fixtures/classes.rb
index 28d8e0a965..58120c2f88 100644
--- a/spec/ruby/core/unboundmethod/fixtures/classes.rb
+++ b/spec/ruby/core/unboundmethod/fixtures/classes.rb
@@ -36,6 +36,7 @@ module UnboundMethodSpecs
alias bar foo
alias baz bar
+ alias qux baz
alias alias_1 foo
alias alias_2 foo
@@ -80,6 +81,22 @@ module UnboundMethodSpecs
end
end
+ module Mixin
+ def mixin_method; end
+ end
+
+ class IncluderBase
+ include Mixin
+ end
+
+ class IncluderChild < IncluderBase; end
+
+ class ExtenderBase
+ extend Mixin
+ end
+
+ class ExtenderChild < ExtenderBase; end
+
class A
def baz(a, b)
return [__FILE__, self.class]
diff --git a/spec/ruby/core/unboundmethod/inspect_spec.rb b/spec/ruby/core/unboundmethod/inspect_spec.rb
index cecf542fcd..b0fcfd00ea 100644
--- a/spec/ruby/core/unboundmethod/inspect_spec.rb
+++ b/spec/ruby/core/unboundmethod/inspect_spec.rb
@@ -1,7 +1,7 @@
require_relative '../../spec_helper'
-require_relative 'fixtures/classes'
-require_relative 'shared/to_s'
describe "UnboundMethod#inspect" do
- it_behaves_like :unboundmethod_to_s, :inspect
+ it "is an alias of UnboundMethod#to_s" do
+ UnboundMethod.instance_method(:inspect).should == UnboundMethod.instance_method(:to_s)
+ end
end
diff --git a/spec/ruby/core/unboundmethod/original_name_spec.rb b/spec/ruby/core/unboundmethod/original_name_spec.rb
index 7280dcb2b4..cd5f55805d 100644
--- a/spec/ruby/core/unboundmethod/original_name_spec.rb
+++ b/spec/ruby/core/unboundmethod/original_name_spec.rb
@@ -19,4 +19,41 @@ describe "UnboundMethod#original_name" do
obj.method(:baz).unbind.original_name.should == :foo
UnboundMethodSpecs::Methods.instance_method(:baz).original_name.should == :foo
end
+
+ it "returns the original name even when aliased thrice" do
+ obj = UnboundMethodSpecs::Methods.new
+ obj.method(:qux).unbind.original_name.should == :foo
+ UnboundMethodSpecs::Methods.instance_method(:qux).original_name.should == :foo
+ end
+
+ it "returns the source UnboundMethod's name (not the name given to define_method)" do
+ klass = Class.new { define_method(:my_inspect, ::Kernel.instance_method(:inspect)) }
+ klass.instance_method(:my_inspect).original_name.should == :inspect
+ end
+
+ it "preserves the source method's name through define_method and alias" do
+ source = Class.new { def my_method; end }
+ klass = Class.new(source) do
+ define_method(:renamed, source.instance_method(:my_method))
+ alias aliased renamed
+ end
+ klass.instance_method(:renamed).original_name.should == :my_method
+ klass.instance_method(:aliased).original_name.should == :my_method
+ end
+
+ it "returns the source UnboundMethod's name for Kernel#is_a? and Kernel#kind_of?" do
+ klass = Class.new { define_method(:my_is_a?, ::Kernel.instance_method(:is_a?)) }
+ klass.instance_method(:my_is_a?).original_name.should == :is_a?
+
+ klass = Class.new { define_method(:my_kind_of?, ::Kernel.instance_method(:kind_of?)) }
+ klass.instance_method(:my_kind_of?).original_name.should == :kind_of?
+ end
+
+ it "preserves the source name when aliasing a define_method'd Kernel method" do
+ klass = Class.new do
+ define_method(:my_is_a?, ::Kernel.instance_method(:is_a?))
+ alias_method :renamed_is_a?, :my_is_a?
+ end
+ klass.instance_method(:renamed_is_a?).original_name.should == :is_a?
+ end
end
diff --git a/spec/ruby/core/unboundmethod/shared/dup.rb b/spec/ruby/core/unboundmethod/shared/dup.rb
index 194e2cc1a1..fd30f75c5b 100644
--- a/spec/ruby/core/unboundmethod/shared/dup.rb
+++ b/spec/ruby/core/unboundmethod/shared/dup.rb
@@ -4,7 +4,7 @@ describe :unboundmethod_dup, shared: true do
b = a.send(@method)
a.should == b
- a.should_not equal(b)
+ a.should_not.equal?(b)
end
ruby_version_is "3.4" do
diff --git a/spec/ruby/core/unboundmethod/shared/to_s.rb b/spec/ruby/core/unboundmethod/shared/to_s.rb
deleted file mode 100644
index 6b2c9c3e79..0000000000
--- a/spec/ruby/core/unboundmethod/shared/to_s.rb
+++ /dev/null
@@ -1,33 +0,0 @@
-require_relative '../../../spec_helper'
-require_relative '../fixtures/classes'
-
-describe :unboundmethod_to_s, shared: true do
- before :each do
- @from_module = UnboundMethodSpecs::Methods.instance_method(:from_mod)
- @from_method = UnboundMethodSpecs::Methods.new.method(:from_mod).unbind
- end
-
- it "returns a String" do
- @from_module.send(@method).should be_kind_of(String)
- @from_method.send(@method).should be_kind_of(String)
- end
-
- it "the String reflects that this is an UnboundMethod object" do
- @from_module.send(@method).should =~ /\bUnboundMethod\b/
- @from_method.send(@method).should =~ /\bUnboundMethod\b/
- end
-
- it "the String shows the method name, Module defined in and Module extracted from" do
- @from_module.send(@method).should =~ /\bfrom_mod\b/
- @from_module.send(@method).should =~ /\bUnboundMethodSpecs::Mod\b/
- end
-
- it "returns a String including all details" do
- @from_module.send(@method).should.start_with? "#<UnboundMethod: UnboundMethodSpecs::Mod#from_mod"
- @from_method.send(@method).should.start_with? "#<UnboundMethod: UnboundMethodSpecs::Mod#from_mod"
- end
-
- it "does not show the defining module if it is the same as the origin" do
- UnboundMethodSpecs::A.instance_method(:baz).send(@method).should.start_with? "#<UnboundMethod: UnboundMethodSpecs::A#baz"
- end
-end
diff --git a/spec/ruby/core/unboundmethod/source_location_spec.rb b/spec/ruby/core/unboundmethod/source_location_spec.rb
index 2391d07d99..927600bfcb 100644
--- a/spec/ruby/core/unboundmethod/source_location_spec.rb
+++ b/spec/ruby/core/unboundmethod/source_location_spec.rb
@@ -7,23 +7,23 @@ describe "UnboundMethod#source_location" do
end
it "sets the first value to the path of the file in which the method was defined" do
- file = @method.source_location[0]
- file.should be_an_instance_of(String)
+ file = @method.source_location.first
+ file.should.instance_of?(String)
file.should == File.realpath('fixtures/classes.rb', __dir__)
end
- it "sets the second value to an Integer representing the line on which the method was defined" do
- line = @method.source_location[1]
- line.should be_an_instance_of(Integer)
+ it "sets the last value to an Integer representing the line on which the method was defined" do
+ line = @method.source_location.last
+ line.should.instance_of?(Integer)
line.should == 5
end
it "returns the last place the method was defined" do
- UnboundMethodSpecs::SourceLocation.method(:redefined).unbind.source_location[1].should == 13
+ UnboundMethodSpecs::SourceLocation.method(:redefined).unbind.source_location.last.should == 13
end
it "returns the location of the original method even if it was aliased" do
- UnboundMethodSpecs::SourceLocation.instance_method(:aka).source_location[1].should == 17
+ UnboundMethodSpecs::SourceLocation.instance_method(:aka).source_location.last.should == 17
end
it "works for define_method methods" do
@@ -54,12 +54,6 @@ describe "UnboundMethod#source_location" do
c = Class.new do
eval('def m; end', nil, "foo", 100)
end
- location = c.instance_method(:m).source_location
- ruby_version_is(""..."3.5") do
- location.should == ["foo", 100]
- end
- ruby_version_is("3.5") do
- location.should == ["foo", 100, 0, 100, 10]
- end
+ c.instance_method(:m).source_location.should == ["foo", 100]
end
end
diff --git a/spec/ruby/core/unboundmethod/to_s_spec.rb b/spec/ruby/core/unboundmethod/to_s_spec.rb
index a508229b49..b90f315c3a 100644
--- a/spec/ruby/core/unboundmethod/to_s_spec.rb
+++ b/spec/ruby/core/unboundmethod/to_s_spec.rb
@@ -1,7 +1,36 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
-require_relative 'shared/to_s'
+require_relative '../method/shared/aliased_inspect'
describe "UnboundMethod#to_s" do
- it_behaves_like :unboundmethod_to_s, :to_s
+ it_behaves_like :method_to_s_aliased, :to_s, -> meth { meth.unbind }
+
+ before :each do
+ @from_module = UnboundMethodSpecs::Methods.instance_method(:from_mod)
+ @from_method = UnboundMethodSpecs::Methods.new.method(:from_mod).unbind
+ end
+
+ it "returns a String" do
+ @from_module.to_s.should.is_a?(String)
+ @from_method.to_s.should.is_a?(String)
+ end
+
+ it "the String reflects that this is an UnboundMethod object" do
+ @from_module.to_s.should =~ /\bUnboundMethod\b/
+ @from_method.to_s.should =~ /\bUnboundMethod\b/
+ end
+
+ it "the String shows the method name, Module defined in and Module extracted from" do
+ @from_module.to_s.should =~ /\bfrom_mod\b/
+ @from_module.to_s.should =~ /\bUnboundMethodSpecs::Mod\b/
+ end
+
+ it "returns a String including all details" do
+ @from_module.to_s.should.start_with? "#<UnboundMethod: UnboundMethodSpecs::Mod#from_mod"
+ @from_method.to_s.should.start_with? "#<UnboundMethod: UnboundMethodSpecs::Mod#from_mod"
+ end
+
+ it "does not show the defining module if it is the same as the origin" do
+ UnboundMethodSpecs::A.instance_method(:baz).to_s.should.start_with? "#<UnboundMethod: UnboundMethodSpecs::A#baz"
+ end
end
diff --git a/spec/ruby/core/warning/categories_spec.rb b/spec/ruby/core/warning/categories_spec.rb
new file mode 100644
index 0000000000..1e310ef38b
--- /dev/null
+++ b/spec/ruby/core/warning/categories_spec.rb
@@ -0,0 +1,12 @@
+require_relative '../../spec_helper'
+
+ruby_version_is "3.4" do
+ describe "Warning.categories" do
+ # There might be more, but these are standard across Ruby implementations
+ it "returns the list of possible warning categories" do
+ Warning.categories.should.include? :deprecated
+ Warning.categories.should.include? :experimental
+ Warning.categories.should.include? :performance
+ 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..5f977759ec 100644
--- a/spec/ruby/core/warning/element_reference_spec.rb
+++ b/spec/ruby/core/warning/element_reference_spec.rb
@@ -10,20 +10,18 @@ describe "Warning.[]" do
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"
- end
+ 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"
end
it "raises for unknown category" do
- -> { Warning[:noop] }.should raise_error(ArgumentError, /unknown category: noop/)
+ -> { Warning[:noop] }.should.raise(ArgumentError, /unknown category: noop/)
end
it "raises for non-Symbol category" do
- -> { Warning[42] }.should raise_error(TypeError)
- -> { Warning[false] }.should raise_error(TypeError)
- -> { Warning["noop"] }.should raise_error(TypeError)
+ -> { Warning[42] }.should.raise(TypeError)
+ -> { Warning[false] }.should.raise(TypeError)
+ -> { Warning["noop"] }.should.raise(TypeError)
end
end
diff --git a/spec/ruby/core/warning/element_set_spec.rb b/spec/ruby/core/warning/element_set_spec.rb
index d59a7d4c9e..3c8ceb721e 100644
--- a/spec/ruby/core/warning/element_set_spec.rb
+++ b/spec/ruby/core/warning/element_set_spec.rb
@@ -17,25 +17,23 @@ 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
+ it "enables or disables performance warnings" do
+ original = Warning[:performance]
+ begin
+ Warning[:performance] = !original
+ Warning[:performance].should == !original
+ ensure
+ Warning[:performance] = original
end
end
it "raises for unknown category" do
- -> { Warning[:noop] = false }.should raise_error(ArgumentError, /unknown category: noop/)
+ -> { Warning[:noop] = false }.should.raise(ArgumentError, /unknown category: noop/)
end
it "raises for non-Symbol category" do
- -> { Warning[42] = false }.should raise_error(TypeError)
- -> { Warning[false] = false }.should raise_error(TypeError)
- -> { Warning["noop"] = false }.should raise_error(TypeError)
+ -> { Warning[42] = false }.should.raise(TypeError)
+ -> { Warning[false] = false }.should.raise(TypeError)
+ -> { Warning["noop"] = false }.should.raise(TypeError)
end
end
diff --git a/spec/ruby/core/warning/warn_spec.rb b/spec/ruby/core/warning/warn_spec.rb
index 572885c2b4..62f36e3454 100644
--- a/spec/ruby/core/warning/warn_spec.rb
+++ b/spec/ruby/core/warning/warn_spec.rb
@@ -16,7 +16,7 @@ describe "Warning.warn" do
end
it "extends itself" do
- Warning.singleton_class.ancestors.should include(Warning)
+ Warning.singleton_class.ancestors.should.include?(Warning)
end
it "has Warning as the method owner" do
@@ -97,6 +97,20 @@ describe "Warning.warn" do
end
end
+ ruby_version_is "3.4" do
+ it "warns when category is :strict_unused_block but Warning[:strict_unused_block] is false" do
+ warn_strict_unused_block = Warning[:strict_unused_block]
+ Warning[:strict_unused_block] = true
+ begin
+ -> {
+ Warning.warn("foo", category: :strict_unused_block)
+ }.should complain("foo")
+ ensure
+ Warning[:strict_unused_block] = warn_strict_unused_block
+ end
+ end
+ end
+
it "doesn't print message when category is :deprecated but Warning[:deprecated] is false" do
warn_deprecated = Warning[:deprecated]
Warning[:deprecated] = false
@@ -121,6 +135,20 @@ describe "Warning.warn" do
end
end
+ ruby_version_is "3.4" do
+ it "doesn't print message when category is :strict_unused_block but Warning[:strict_unused_block] is false" do
+ warn_strict_unused_block = Warning[:strict_unused_block]
+ Warning[:strict_unused_block] = false
+ begin
+ -> {
+ Warning.warn("foo", category: :strict_unused_block)
+ }.should_not complain
+ ensure
+ Warning[:strict_unused_block] = warn_strict_unused_block
+ end
+ end
+ end
+
ruby_bug '#20573', ''...'3.4' do
it "isn't called by Kernel.warn when category is :deprecated but Warning[:deprecated] is false" do
warn_deprecated = Warning[:deprecated]
diff --git a/spec/ruby/default.mspec b/spec/ruby/default.mspec
index 1e8f8893aa..c8b1215f56 100644
--- a/spec/ruby/default.mspec
+++ b/spec/ruby/default.mspec
@@ -20,8 +20,11 @@ class MSpecScript
# C extension API specs
set :capi, [ 'optional/capi' ]
+ # Thread safety specs
+ set :thread_safety, [ 'optional/thread_safety' ]
+
# A list of _all_ optional specs
- set :optional, get(:capi)
+ set :optional, get(:capi) + get(:thread_safety)
# An ordered list of the directories containing specs to run
set :files, get(:command_line) + get(:language) + get(:core) + get(:library) + get(:security) + get(:optional)
diff --git a/spec/ruby/language/BEGIN_spec.rb b/spec/ruby/language/BEGIN_spec.rb
index 5aef5a1d7c..25db32b96a 100644
--- a/spec/ruby/language/BEGIN_spec.rb
+++ b/spec/ruby/language/BEGIN_spec.rb
@@ -15,7 +15,7 @@ describe "The BEGIN keyword" do
end
it "must appear in a top-level context" do
- -> { eval "1.times { BEGIN { 1 } }" }.should raise_error(SyntaxError)
+ -> { eval "1.times { BEGIN { 1 } }" }.should.raise(SyntaxError)
end
it "uses top-level for self" do
diff --git a/spec/ruby/language/alias_spec.rb b/spec/ruby/language/alias_spec.rb
index 61fddb0184..4b3d36d308 100644
--- a/spec/ruby/language/alias_spec.rb
+++ b/spec/ruby/language/alias_spec.rb
@@ -140,7 +140,7 @@ describe "The alias keyword" do
end
@obj.__value.should == 5
- -> { AliasObject.new.__value }.should raise_error(NoMethodError)
+ -> { AliasObject.new.__value }.should.raise(NoMethodError)
end
it "operates on the class/module metaclass when used in instance_eval" do
@@ -149,7 +149,7 @@ describe "The alias keyword" do
end
AliasObject.__klass_method.should == 7
- -> { Object.__klass_method }.should raise_error(NoMethodError)
+ -> { Object.__klass_method }.should.raise(NoMethodError)
end
it "operates on the class/module metaclass when used in instance_exec" do
@@ -158,7 +158,7 @@ describe "The alias keyword" do
end
AliasObject.__klass_method2.should == 7
- -> { Object.__klass_method2 }.should raise_error(NoMethodError)
+ -> { Object.__klass_method2 }.should.raise(NoMethodError)
end
it "operates on methods defined via attr, attr_reader, and attr_accessor" do
@@ -241,13 +241,13 @@ describe "The alias keyword" do
1.instance_eval do
alias :foo :to_s
end
- end.should raise_error(TypeError)
+ end.should.raise(TypeError)
-> do
:blah.instance_eval do
alias :foo :to_s
end
- end.should raise_error(TypeError)
+ end.should.raise(TypeError)
end
it "on top level defines the alias on Object" do
@@ -256,7 +256,7 @@ describe "The alias keyword" do
end
it "raises a NameError when passed a missing name" do
- -> { @meta.class_eval { alias undef_method not_exist } }.should raise_error(NameError) { |e|
+ -> { @meta.class_eval { alias undef_method not_exist } }.should.raise(NameError) { |e|
# a NameError and not a NoMethodError
e.class.should == NameError
}
@@ -272,7 +272,7 @@ describe "The alias keyword" do
end
child.instance_method(:parent_method_alias).owner.should == child
- child.instance_methods(false).should include(:parent_method_alias)
+ child.instance_methods(false).should.include?(:parent_method_alias)
end
end
diff --git a/spec/ruby/language/and_spec.rb b/spec/ruby/language/and_spec.rb
index 55a2a3103a..c5c255989b 100644
--- a/spec/ruby/language/and_spec.rb
+++ b/spec/ruby/language/and_spec.rb
@@ -5,7 +5,7 @@ describe "The '&&' statement" do
it "short-circuits evaluation at the first condition to be false" do
x = nil
true && false && x = 1
- x.should be_nil
+ x.should == nil
end
it "evaluates to the first condition not to be true" do
@@ -33,9 +33,9 @@ describe "The '&&' statement" do
end
it "treats empty expressions as nil" do
- (() && true).should be_nil
- (true && ()).should be_nil
- (() && ()).should be_nil
+ (() && true).should == nil
+ (true && ()).should == nil
+ (() && ()).should == nil
end
end
@@ -44,7 +44,7 @@ describe "The 'and' statement" do
it "short-circuits evaluation at the first condition to be false" do
x = nil
true and false and x = 1
- x.should be_nil
+ x.should == nil
end
it "evaluates to the first condition not to be true" do
@@ -72,9 +72,9 @@ describe "The 'and' statement" do
end
it "treats empty expressions as nil" do
- (() and true).should be_nil
- (true and ()).should be_nil
- (() and ()).should be_nil
+ (() and true).should == nil
+ (true and ()).should == nil
+ (() and ()).should == nil
end
end
diff --git a/spec/ruby/language/array_spec.rb b/spec/ruby/language/array_spec.rb
index 2583cffbf7..78cf36c201 100644
--- a/spec/ruby/language/array_spec.rb
+++ b/spec/ruby/language/array_spec.rb
@@ -4,7 +4,7 @@ require_relative 'fixtures/array'
describe "Array literals" do
it "[] should return a new array populated with the given elements" do
array = [1, 'a', nil]
- array.should be_kind_of(Array)
+ array.should.is_a?(Array)
array[0].should == 1
array[1].should == 'a'
array[2].should == nil
@@ -12,7 +12,7 @@ describe "Array literals" do
it "[] treats empty expressions as nil elements" do
array = [0, (), 2, (), 4]
- array.should be_kind_of(Array)
+ array.should.is_a?(Array)
array[0].should == 0
array[1].should == nil
array[2].should == 2
@@ -89,7 +89,7 @@ describe "The unpacking splat operator (*)" do
it "returns a new array containing the same values when applied to an array inside an empty array" do
splatted_array = [3, 4, 5]
[*splatted_array].should == splatted_array
- [*splatted_array].should_not equal(splatted_array)
+ [*splatted_array].should_not.equal?(splatted_array)
end
it "unpacks the start and count arguments in an array slice assignment" do
@@ -135,7 +135,7 @@ describe "The unpacking splat operator (*)" do
it "when applied to a non-Array value uses it unchanged if it does not respond_to?(:to_a)" do
obj = Object.new
- obj.should_not respond_to(:to_a)
+ obj.should_not.respond_to?(:to_a)
[1, *obj].should == [1, obj]
end
@@ -155,8 +155,12 @@ describe "The unpacking splat operator (*)" do
b = [1, 0]
[*a, 3, *a, *b].should == [1, 2, 3, 1, 2, 1, 0]
end
-end
-
-describe "The packing splat operator (*)" do
+ ruby_version_is "4.0" do
+ it "does not call #to_a on nil" do
+ e = nil
+ e.should_not_receive(:to_a)
+ [*e].should == []
+ end
+ end
end
diff --git a/spec/ruby/language/assignments_spec.rb b/spec/ruby/language/assignments_spec.rb
index 4ad9f4167b..d621c9f0c6 100644
--- a/spec/ruby/language/assignments_spec.rb
+++ b/spec/ruby/language/assignments_spec.rb
@@ -36,7 +36,7 @@ describe 'Assignments' do
-> {
(:not_a_module)::A = (ScratchPad << :rhs; :value)
- }.should raise_error(TypeError)
+ }.should.raise(TypeError)
ScratchPad.recorded.should == [:rhs]
end
@@ -68,7 +68,35 @@ describe 'Assignments' do
-> {
eval "obj[:a, &block] = 2"
- }.should raise_error(SyntaxError, /unexpected block arg given in index assignment|block arg given in index assignment/)
+ }.should.raise(SyntaxError, /unexpected block arg given in index assignment|block arg given in index assignment/)
+ end
+ end
+ end
+
+ context "given keyword arguments" do
+ before do
+ @klass = Class.new do
+ attr_reader :x
+
+ def []=(*args, **kw)
+ @x = [args, kw]
+ end
+ end
+ end
+
+ ruby_version_is ""..."3.4" do
+ it "supports keyword arguments in index assignments" do
+ a = @klass.new
+ eval "a[1, 2, 3, b: 4] = 5"
+ a.x.should == [[1, 2, 3, {b: 4}, 5], {}]
+ end
+ end
+
+ ruby_version_is "3.4" do
+ it "raises SyntaxError when given keyword arguments in index assignments" do
+ a = @klass.new
+ -> { eval "a[1, 2, 3, b: 4] = 5" }.should.raise(SyntaxError,
+ /keywords are not allowed in index assignment expressions|keyword arg given in index assignment/) # prism|parse.y
end
end
end
@@ -171,7 +199,39 @@ describe 'Assignments' do
-> {
eval "obj[:a, &block] += 2"
- }.should raise_error(SyntaxError, /unexpected block arg given in index assignment|block arg given in index assignment/)
+ }.should.raise(SyntaxError, /unexpected block arg given in index assignment|block arg given in index assignment/)
+ end
+ end
+ end
+
+ context "given keyword arguments" do
+ before do
+ @klass = Class.new do
+ attr_reader :x
+
+ def [](*args)
+ 100
+ end
+
+ def []=(*args, **kw)
+ @x = [args, kw]
+ end
+ end
+ end
+
+ ruby_version_is ""..."3.4" do
+ it "supports keyword arguments in index assignments" do
+ a = @klass.new
+ eval "a[1, 2, 3, b: 4] += 5"
+ a.x.should == [[1, 2, 3, 105], {b: 4}]
+ end
+ end
+
+ ruby_version_is "3.4" do
+ it "raises SyntaxError when given keyword arguments in index assignments" do
+ a = @klass.new
+ -> { eval "a[1, 2, 3, b: 4] += 5" }.should.raise(SyntaxError,
+ /keywords are not allowed in index assignment expressions|keyword arg given in index assignment/) # prism|parse.y
end
end
end
diff --git a/spec/ruby/language/block_spec.rb b/spec/ruby/language/block_spec.rb
index e1e4a363c8..5bdb993aea 100644
--- a/spec/ruby/language/block_spec.rb
+++ b/spec/ruby/language/block_spec.rb
@@ -13,7 +13,7 @@ describe "A block yielded a single" do
it "receives the identical Array object" do
ary = [1, 2]
- m(ary) { |a| a }.should equal(ary)
+ m(ary) { |a| a }.should.equal?(ary)
end
it "assigns the Array to a single rest argument" do
@@ -73,7 +73,7 @@ describe "A block yielded a single" do
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")
+ }.should.raise(ArgumentError, "missing keywords: :b, :c")
end
it "assigns elements to mixed argument types" do
@@ -192,6 +192,22 @@ describe "A block yielded a single" do
m(obj) { |a, b, c| [a, b, c] }.should == [1, 2, nil]
end
+ it "calls #respond_to? on a BasicObject to check if object has method #to_ary" do
+ ScratchPad.record []
+ obj = BasicObject.new
+ def obj.respond_to?(name, *)
+ ScratchPad << [:respond_to?, name]
+ name == :to_ary ? true : super
+ end
+ def obj.to_ary
+ ScratchPad << :to_ary
+ [1, 2]
+ end
+
+ m(obj) { |a, b, c| [a, b, c] }.should == [1, 2, nil]
+ ScratchPad.recorded.should == [[:respond_to?, :to_ary], :to_ary]
+ end
+
it "receives the object if it does not respond to #respond_to?" do
obj = BasicObject.new
@@ -218,14 +234,14 @@ describe "A block yielded a single" do
obj = mock("destructure block arguments")
obj.should_receive(:to_ary).and_return(1)
- -> { m(obj) { |a, b| } }.should raise_error(TypeError)
+ -> { m(obj) { |a, b| } }.should.raise(TypeError)
end
it "raises error transparently if #to_ary raises error on its own" do
obj = Object.new
def obj.to_ary; raise "Exception raised in #to_ary" end
- -> { m(obj) { |a, b| } }.should raise_error(RuntimeError, "Exception raised in #to_ary")
+ -> { m(obj) { |a, b| } }.should.raise(RuntimeError, "Exception raised in #to_ary")
end
end
end
@@ -295,7 +311,7 @@ describe "A block" do
describe "taking |a| arguments" do
it "assigns nil to the argument when no values are yielded" do
- @y.z { |a| a }.should be_nil
+ @y.z { |a| a }.should == nil
end
it "assigns the value yielded to the argument" do
@@ -306,7 +322,7 @@ describe "A block" do
obj = mock("block yield to_ary")
obj.should_not_receive(:to_ary)
- @y.s(obj) { |a| a }.should equal(obj)
+ @y.s(obj) { |a| a }.should.equal?(obj)
end
it "assigns the first value yielded to the argument" do
@@ -382,14 +398,14 @@ describe "A block" do
obj = mock("block yield to_ary invalid")
obj.should_receive(:to_ary).and_return(1)
- -> { @y.s(obj) { |a, b| } }.should raise_error(TypeError)
+ -> { @y.s(obj) { |a, b| } }.should.raise(TypeError)
end
it "raises the original exception if #to_ary raises an exception" do
obj = mock("block yield to_ary raising an exception")
obj.should_receive(:to_ary).and_raise(ZeroDivisionError)
- -> { @y.s(obj) { |a, b| } }.should raise_error(ZeroDivisionError)
+ -> { @y.s(obj) { |a, b| } }.should.raise(ZeroDivisionError)
end
end
@@ -445,7 +461,7 @@ describe "A block" do
obj = mock("block yield to_ary invalid")
obj.should_receive(:to_ary).and_return(1)
- -> { @y.s(obj) { |a, *b| } }.should raise_error(TypeError)
+ -> { @y.s(obj) { |a, *b| } }.should.raise(TypeError)
end
end
@@ -523,7 +539,7 @@ describe "A block" do
describe "taking |a, | arguments" do
it "assigns nil to the argument when no values are yielded" do
- @y.z { |a, | a }.should be_nil
+ @y.z { |a, | a }.should == nil
end
it "assigns the argument a single value yielded" do
@@ -539,7 +555,7 @@ describe "A block" do
end
it "assigns nil to the argument when passed an empty Array" do
- @y.s([]) { |a, | a }.should be_nil
+ @y.s([]) { |a, | a }.should == nil
end
it "assigns the argument the first element of the Array when passed a single Array" do
@@ -570,7 +586,7 @@ describe "A block" do
obj = mock("block yield to_ary invalid")
obj.should_receive(:to_ary).and_return(1)
- -> { @y.s(obj) { |a, | } }.should raise_error(TypeError)
+ -> { @y.s(obj) { |a, | } }.should.raise(TypeError)
end
end
@@ -612,7 +628,7 @@ describe "A block" do
obj = mock("block yield to_ary invalid")
obj.should_receive(:to_ary).and_return(1)
- -> { @y.s(obj) { |(a, b)| } }.should raise_error(TypeError)
+ -> { @y.s(obj) { |(a, b)| } }.should.raise(TypeError)
end
end
@@ -653,7 +669,7 @@ describe "A block" do
obj = mock("block yield to_ary invalid")
obj.should_receive(:to_ary).and_return(1)
- -> { @y.s(obj) { |(a, b), c| } }.should raise_error(TypeError)
+ -> { @y.s(obj) { |(a, b), c| } }.should.raise(TypeError)
end
end
@@ -712,15 +728,15 @@ describe "A block" do
describe "taking identically-named arguments" do
it "raises a SyntaxError for standard arguments" do
- -> { eval "lambda { |x,x| }" }.should raise_error(SyntaxError)
- -> { eval "->(x,x) {}" }.should raise_error(SyntaxError)
- -> { eval "Proc.new { |x,x| }" }.should raise_error(SyntaxError)
+ -> { eval "lambda { |x,x| }" }.should.raise(SyntaxError)
+ -> { eval "->(x,x) {}" }.should.raise(SyntaxError)
+ -> { eval "Proc.new { |x,x| }" }.should.raise(SyntaxError)
end
it "accepts unnamed arguments" do
- lambda { |_,_| }.should be_an_instance_of(Proc) # rubocop:disable Style/Lambda
- -> _,_ {}.should be_an_instance_of(Proc)
- Proc.new { |_,_| }.should be_an_instance_of(Proc)
+ lambda { |_,_| }.should.instance_of?(Proc) # rubocop:disable Style/Lambda
+ -> _,_ {}.should.instance_of?(Proc)
+ Proc.new { |_,_| }.should.instance_of?(Proc)
end
end
@@ -771,29 +787,29 @@ describe "Block-local variables" do
end
it "can not have the same name as one of the standard parameters" do
- -> { eval "[1].each {|foo; foo| }" }.should raise_error(SyntaxError)
- -> { eval "[1].each {|foo, bar; glark, bar| }" }.should raise_error(SyntaxError)
+ -> { eval "[1].each {|foo; foo| }" }.should.raise(SyntaxError)
+ -> { eval "[1].each {|foo, bar; glark, bar| }" }.should.raise(SyntaxError)
end
it "can not be prefixed with an asterisk" do
- -> { eval "[1].each {|foo; *bar| }" }.should raise_error(SyntaxError)
+ -> { eval "[1].each {|foo; *bar| }" }.should.raise(SyntaxError)
-> do
eval "[1].each {|foo, bar; glark, *fnord| }"
- end.should raise_error(SyntaxError)
+ end.should.raise(SyntaxError)
end
it "can not be prefixed with an ampersand" do
- -> { eval "[1].each {|foo; &bar| }" }.should raise_error(SyntaxError)
+ -> { eval "[1].each {|foo; &bar| }" }.should.raise(SyntaxError)
-> do
eval "[1].each {|foo, bar; glark, &fnord| }"
- end.should raise_error(SyntaxError)
+ end.should.raise(SyntaxError)
end
it "can not be assigned default values" do
- -> { eval "[1].each {|foo; bar=1| }" }.should raise_error(SyntaxError)
+ -> { eval "[1].each {|foo; bar=1| }" }.should.raise(SyntaxError)
-> do
eval "[1].each {|foo, bar; glark, fnord=:fnord| }"
- end.should raise_error(SyntaxError)
+ end.should.raise(SyntaxError)
end
it "need not be preceded by standard parameters" do
@@ -802,8 +818,8 @@ describe "Block-local variables" do
end
it "only allow a single semi-colon in the parameter list" do
- -> { eval "[1].each {|foo; bar; glark| }" }.should raise_error(SyntaxError)
- -> { eval "[1].each {|; bar; glark| }" }.should raise_error(SyntaxError)
+ -> { eval "[1].each {|foo; bar; glark| }" }.should.raise(SyntaxError)
+ -> { eval "[1].each {|; bar; glark| }" }.should.raise(SyntaxError)
end
it "override shadowed variables from the outer scope" do
@@ -828,21 +844,21 @@ describe "Block-local variables" do
end
it "are not automatically instantiated in the outer scope" do
- defined?(glark).should be_nil
+ defined?(glark).should == nil
[1].each {|;glark| 1}
- defined?(glark).should be_nil
+ defined?(glark).should == nil
end
it "are automatically instantiated in the block" do
[1].each do |;glark|
- glark.should be_nil
+ glark.should == nil
end
end
it "are visible in deeper scopes before initialization" do
[1].each {|;glark|
[1].each {
- defined?(glark).should_not be_nil
+ defined?(glark).should_not == nil
glark = 1
}
glark.should == 1
@@ -870,7 +886,7 @@ describe "Post-args" do
-> *a, b do
[a, b]
end.call
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
it "are assigned to nil when not enough arguments are given to a proc" do
@@ -946,7 +962,7 @@ describe "Post-args" do
a = 1
-> {
eval "proc { |a=a| a }"
- }.should raise_error(SyntaxError)
+ }.should.raise(SyntaxError)
end
end
@@ -990,7 +1006,7 @@ describe "Anonymous block forwarding" do
end
it "requires the anonymous block parameter to be declared if directly passing a block" do
- -> { eval "def a; b(&); end; def b; end" }.should raise_error(SyntaxError)
+ -> { eval "def a; b(&); end; def b; end" }.should.raise(SyntaxError)
end
it "works when it's the only declared parameter" do
@@ -1041,14 +1057,20 @@ describe "Anonymous block forwarding" do
end
end
-describe "`it` calls without arguments in a block with no ordinary parameters" do
- ruby_version_is "3.3"..."3.4" do
+describe "`it` calls without arguments in a block" do
+ ruby_version_is ""..."3.4" do
it "emits a deprecation warning" do
-> {
eval "proc { it }"
}.should complain(/warning: `it` calls without arguments will refer to the first block param in Ruby 3.4; use it\(\) or self.it/)
end
+ it "emits a deprecation warning if numbered parameters are used" do
+ -> {
+ eval "proc { it; _1 }"
+ }.should complain(/warning: `it` calls without arguments will refer to the first block param in Ruby 3.4; use it\(\) or self.it/)
+ end
+
it "does not emit a deprecation warning when a block has parameters" do
-> { eval "proc { |a, b| it }" }.should_not complain
-> { eval "proc { |*rest| it }" }.should_not complain
@@ -1058,21 +1080,69 @@ describe "`it` calls without arguments in a block with no ordinary parameters" d
-> { eval "proc { |**| it }" }.should_not complain
-> { eval "proc { |&block| it }" }.should_not complain
-> { eval "proc { |&| it }" }.should_not complain
+ -> { eval "proc { || it }" }.should_not complain
end
it "does not emit a deprecation warning when `it` calls with arguments" do
-> { eval "proc { it(42) }" }.should_not complain
+ -> { eval "proc { it 42 }" }.should_not complain
+ end
+
+ it "does not emit a deprecation warning when `it` calls with a block" do
+ -> { eval "proc { it {} }" }.should_not complain
+ end
+
+ it "does not emit a deprecation warning when a local variable inside the block named `it` exists" do
+ -> { eval "proc { it = 42; it }" }.should_not complain
end
it "does not emit a deprecation warning when `it` calls with explicit empty arguments list" do
-> { eval "proc { it() }" }.should_not complain
end
+
+ it "calls the method `it` if defined" do
+ o = Object.new
+ def o.it
+ 21
+ end
+ suppress_warning do
+ o.instance_eval("proc { it * 2 }").call(1).should == 42
+ end
+ end
+ end
+
+ ruby_version_is "4.1" do
+ it "works alongside disallowed block argument" do
+ no_block = eval <<-EOF
+ proc {|arg1, &nil| arg1}
+ EOF
+
+ no_block.call(:a).should == :a
+ -> { no_block.call(:a) {} }.should.raise(ArgumentError, 'no block accepted')
+ end
end
end
-describe "if `it` is defined outside of a block" do
- it "treats `it` as a captured variable" do
+# Duplicates specs in language/it_parameter_spec.rb
+# Need them here to run on Ruby versions prior 3.4
+# TODO: remove when the minimal supported Ruby version is 3.4
+describe "if `it` is defined as a variable" do
+ it "treats `it` as a captured variable if defined outside of a block" do
it = 5
proc { it }.call(0).should == 5
end
+
+ it "treats `it` as a local variable if defined inside of a block" do
+ proc { it = 5; it }.call(0).should == 5
+ end
+end
+
+describe "Block-parameter destructuring" do
+ it "does not warn about unused inner names in verbose mode" do
+ -> {
+ eval <<~RUBY, binding, __FILE__, __LINE__ + 1
+ proc { |key, (val1, val2)| [key, val2] }
+ RUBY
+ }.should_not complain(verbose: true)
+ end
end
diff --git a/spec/ruby/language/break_spec.rb b/spec/ruby/language/break_spec.rb
index 7e5b6fb328..5c9b8060c3 100644
--- a/spec/ruby/language/break_spec.rb
+++ b/spec/ruby/language/break_spec.rb
@@ -52,29 +52,29 @@ describe "The break statement in a captured block" do
describe "when the invocation of the scope creating the block is still active" do
it "raises a LocalJumpError when invoking the block from the scope creating the block" do
- -> { @program.break_in_method }.should raise_error(LocalJumpError)
+ -> { @program.break_in_method }.should.raise(LocalJumpError)
ScratchPad.recorded.should == [:a, :xa, :d, :b]
end
it "raises a LocalJumpError when invoking the block from a method" do
- -> { @program.break_in_nested_method }.should raise_error(LocalJumpError)
+ -> { @program.break_in_nested_method }.should.raise(LocalJumpError)
ScratchPad.recorded.should == [:a, :xa, :cc, :aa, :b]
end
it "raises a LocalJumpError when yielding to the block" do
- -> { @program.break_in_yielding_method }.should raise_error(LocalJumpError)
+ -> { @program.break_in_yielding_method }.should.raise(LocalJumpError)
ScratchPad.recorded.should == [:a, :xa, :cc, :aa, :b]
end
end
describe "from a scope that has returned" do
it "raises a LocalJumpError when calling the block from a method" do
- -> { @program.break_in_method_captured }.should raise_error(LocalJumpError)
+ -> { @program.break_in_method_captured }.should.raise(LocalJumpError)
ScratchPad.recorded.should == [:a, :za, :xa, :zd, :zb]
end
it "raises a LocalJumpError when yielding to the block" do
- -> { @program.break_in_yield_captured }.should raise_error(LocalJumpError)
+ -> { @program.break_in_yield_captured }.should.raise(LocalJumpError)
ScratchPad.recorded.should == [:a, :za, :xa, :zd, :aa, :zb]
end
end
@@ -88,7 +88,7 @@ describe "The break statement in a captured block" do
e
end
end
- thread_with_break.value.should be_an_instance_of(LocalJumpError)
+ thread_with_break.value.should.instance_of?(LocalJumpError)
end
end
end
@@ -256,7 +256,7 @@ 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)
+ }.should.raise(SyntaxError)
end
end
@@ -268,7 +268,7 @@ describe "The break statement in a module literal" do
end
RUBY
- -> { eval(code) }.should raise_error(SyntaxError)
+ -> { eval(code) }.should.raise(SyntaxError)
end
end
@@ -388,7 +388,7 @@ describe "Executing break from within a block" do
-> do
cls2.new.foo.should == 1
- end.should_not raise_error
+ end.should_not.raise
end
it "raises LocalJumpError when converted into a proc during a super call" do
@@ -397,6 +397,6 @@ describe "Executing break from within a block" do
-> do
cls2.new.foo
- end.should raise_error(LocalJumpError)
+ end.should.raise(LocalJumpError)
end
end
diff --git a/spec/ruby/language/case_spec.rb b/spec/ruby/language/case_spec.rb
index 464d06e46a..41881bf20a 100644
--- a/spec/ruby/language/case_spec.rb
+++ b/spec/ruby/language/case_spec.rb
@@ -27,6 +27,41 @@ describe "The 'case'-construct" do
@calls.should == [:foo, :bar]
end
+ it "matches an Integer literal whose value does not fit in a 32-bit int" do
+ big = 10_000_000_000
+ case big
+ when 10_000_000_000; true
+ else false
+ end.should == true
+
+ case -3_000_000_000
+ when -3_000_000_000; true
+ else false
+ end.should == true
+ end
+
+ it "matches an arbitrary-precision Integer literal" do
+ huge = 1267650600228229401496703205376
+ case huge
+ when 1267650600228229401496703205376; true
+ else false
+ end.should == true
+ end
+
+ it "dispatches correctly with mixed small and large Integer literals" do
+ pick = -> x {
+ case x
+ when 1267650600228229401496703205376 then :beyond_long
+ when 10_000_000_000 then :beyond_int
+ when 1 then :fits_int
+ else :other
+ end
+ }
+
+ [1267650600228229401496703205376, 10_000_000_000, 1, :nope].map(&pick).should ==
+ [:beyond_long, :beyond_int, :fits_int, :other]
+ end
+
it "evaluates the body of the when clause whose range expression includes the case target expression" do
case 5
when 21..30; false
@@ -94,12 +129,12 @@ describe "The 'case'-construct" do
it "tests with matching regexps and sets $~ and captures" do
case "foo42"
when /oo(\d+)/
- $~.should be_kind_of(MatchData)
+ $~.should.is_a?(MatchData)
$1.should == "42"
else
flunk
end
- $~.should be_kind_of(MatchData)
+ $~.should.is_a?(MatchData)
$1.should == "42"
end
@@ -107,12 +142,12 @@ describe "The 'case'-construct" do
digits = '\d+'
case "foo44"
when /oo(#{digits})/
- $~.should be_kind_of(MatchData)
+ $~.should.is_a?(MatchData)
$1.should == "44"
else
flunk
end
- $~.should be_kind_of(MatchData)
+ $~.should.is_a?(MatchData)
$1.should == "44"
end
@@ -120,12 +155,12 @@ describe "The 'case'-construct" do
digits_regexp = /\d+/
case "foo43"
when /oo(#{digits_regexp})/
- $~.should be_kind_of(MatchData)
+ $~.should.is_a?(MatchData)
$1.should == "43"
else
flunk
end
- $~.should be_kind_of(MatchData)
+ $~.should.is_a?(MatchData)
$1.should == "43"
end
@@ -268,7 +303,7 @@ describe "The 'case'-construct" do
true
end
CODE
- }.should raise_error(SyntaxError)
+ }.should.raise(SyntaxError)
end
it "raises a SyntaxError when 'else' is used before a 'when' was given" do
@@ -280,7 +315,7 @@ describe "The 'case'-construct" do
when 4; false
end
CODE
- }.should raise_error(SyntaxError)
+ }.should.raise(SyntaxError)
end
it "supports nested case statements" do
diff --git a/spec/ruby/language/class_spec.rb b/spec/ruby/language/class_spec.rb
index 0b770d69b5..7ea4857514 100644
--- a/spec/ruby/language/class_spec.rb
+++ b/spec/ruby/language/class_spec.rb
@@ -10,23 +10,23 @@ end
describe "The class keyword" do
it "creates a new class with semicolon" do
class ClassSpecsKeywordWithSemicolon; end
- ClassSpecsKeywordWithSemicolon.should be_an_instance_of(Class)
+ ClassSpecsKeywordWithSemicolon.should.instance_of?(Class)
end
it "does not raise a SyntaxError when opening a class without a semicolon" do
eval "class ClassSpecsKeywordWithoutSemicolon end"
- ClassSpecsKeywordWithoutSemicolon.should be_an_instance_of(Class)
+ ClassSpecsKeywordWithoutSemicolon.should.instance_of?(Class)
end
it "can redefine a class when called from a block" do
ClassSpecs::DEFINE_CLASS.call
- A.should be_an_instance_of(Class)
+ A.should.instance_of?(Class)
Object.send(:remove_const, :A)
- defined?(A).should be_nil
+ defined?(A).should == nil
ClassSpecs::DEFINE_CLASS.call
- A.should be_an_instance_of(Class)
+ A.should.instance_of?(Class)
ensure
Object.send(:remove_const, :A) if defined?(::A)
end
@@ -34,8 +34,8 @@ end
describe "A class definition" do
it "creates a new class" do
- ClassSpecs::A.should be_kind_of(Class)
- ClassSpecs::A.new.should be_kind_of(ClassSpecs::A)
+ ClassSpecs::A.should.is_a?(Class)
+ ClassSpecs::A.new.should.is_a?(ClassSpecs::A)
end
it "has no class variables" do
@@ -46,7 +46,14 @@ describe "A class definition" do
-> {
class ClassSpecsNumber
end
- }.should raise_error(TypeError)
+ }.should.raise(TypeError, /\AClassSpecsNumber is not a class/)
+ end
+
+ it "raises TypeError if constant given as class name exists and is a Module but not a Class" do
+ -> {
+ class ClassSpecs
+ end
+ }.should.raise(TypeError, /\AClassSpecs is not a class/)
end
# test case known to be detecting bugs (JRuby, MRI)
@@ -54,19 +61,19 @@ describe "A class definition" do
-> {
class nil::Foo
end
- }.should raise_error(TypeError)
+ }.should.raise(TypeError)
end
it "raises TypeError if any constant qualifying the class is not a Module" do
-> {
class ClassSpecs::Number::MyClass
end
- }.should raise_error(TypeError)
+ }.should.raise(TypeError)
-> {
class ClassSpecsNumber::MyClass
end
- }.should raise_error(TypeError)
+ }.should.raise(TypeError)
end
it "inherits from Object by default" do
@@ -80,7 +87,7 @@ describe "A class definition" do
-> {
class SuperclassResetToSubclass < M
end
- }.should raise_error(TypeError, /superclass mismatch/)
+ }.should.raise(TypeError, /superclass mismatch/)
end
end
@@ -93,7 +100,7 @@ describe "A class definition" do
-> {
class SuperclassReopenedBasicObject < BasicObject
end
- }.should raise_error(TypeError, /superclass mismatch/)
+ }.should.raise(TypeError, /superclass mismatch/)
SuperclassReopenedBasicObject.superclass.should == A
end
end
@@ -108,7 +115,7 @@ describe "A class definition" do
-> {
class SuperclassReopenedObject < Object
end
- }.should raise_error(TypeError, /superclass mismatch/)
+ }.should.raise(TypeError, /superclass mismatch/)
SuperclassReopenedObject.superclass.should == A
end
end
@@ -133,7 +140,7 @@ describe "A class definition" do
-> {
class NoSuperclassSet < String
end
- }.should raise_error(TypeError, /superclass mismatch/)
+ }.should.raise(TypeError, /superclass mismatch/)
end
end
@@ -142,7 +149,7 @@ describe "A class definition" do
-> {
class ShouldNotWork < self; end
- }.should raise_error(TypeError)
+ }.should.raise(TypeError)
end
it "first evaluates the superclass before checking if the class already exists" do
@@ -161,7 +168,7 @@ describe "A class definition" do
it "raises a TypeError if inheriting from a metaclass" do
obj = mock("metaclass super")
meta = obj.singleton_class
- -> { class ClassSpecs::MetaclassSuper < meta; end }.should raise_error(TypeError)
+ -> { class ClassSpecs::MetaclassSuper < meta; end }.should.raise(TypeError)
end
it "allows the declaration of class variables in the body" do
@@ -170,7 +177,7 @@ describe "A class definition" do
end
it "stores instance variables defined in the class body in the class object" do
- ClassSpecs.string_instance_variables(ClassSpecs::B).should include("@ivar")
+ ClassSpecs.string_instance_variables(ClassSpecs::B).should.include?("@ivar")
ClassSpecs::B.instance_variable_get(:@ivar).should == :ivar
end
@@ -182,9 +189,9 @@ describe "A class definition" do
end
it "allows the definition of class-level instance variables in a class method" do
- ClassSpecs.string_instance_variables(ClassSpecs::C).should_not include("@civ")
+ ClassSpecs.string_instance_variables(ClassSpecs::C).should_not.include?("@civ")
ClassSpecs::C.make_class_instance_variable
- ClassSpecs.string_instance_variables(ClassSpecs::C).should include("@civ")
+ ClassSpecs.string_instance_variables(ClassSpecs::C).should.include?("@civ")
ClassSpecs::C.remove_instance_variable :@civ
end
@@ -279,7 +286,8 @@ end
describe "An outer class definition" do
it "contains the inner classes" do
- ClassSpecs::Container.constants.should include(:A, :B)
+ ClassSpecs::Container.constants.should.include?(:A)
+ ClassSpecs::Container.constants.should.include?(:B)
end
end
@@ -297,23 +305,23 @@ describe "A class definition extending an object (sclass)" do
end
end
CODE
- }.should raise_error(TypeError)
+ }.should.raise(TypeError)
end
it "raises a TypeError when trying to extend non-Class" do
error_msg = /superclass must be a.* Class/
- -> { class TestClass < ""; end }.should raise_error(TypeError, error_msg)
- -> { class TestClass < 1; end }.should raise_error(TypeError, error_msg)
- -> { class TestClass < :symbol; end }.should raise_error(TypeError, error_msg)
- -> { class TestClass < mock('o'); end }.should raise_error(TypeError, error_msg)
- -> { class TestClass < Module.new; end }.should raise_error(TypeError, error_msg)
- -> { class TestClass < BasicObject.new; end }.should raise_error(TypeError, error_msg)
+ -> { class TestClass < ""; end }.should.raise(TypeError, error_msg)
+ -> { class TestClass < 1; end }.should.raise(TypeError, error_msg)
+ -> { class TestClass < :symbol; end }.should.raise(TypeError, error_msg)
+ -> { class TestClass < mock('o'); end }.should.raise(TypeError, error_msg)
+ -> { class TestClass < Module.new; end }.should.raise(TypeError, error_msg)
+ -> { class TestClass < BasicObject.new; end }.should.raise(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)
+ }.should.raise(SyntaxError)
end
it "can use return to cause the enclosing method to return" do
@@ -333,11 +341,11 @@ describe "Reopening a class" do
end
it "raises a TypeError when superclasses mismatch" do
- -> { class ClassSpecs::A < Array; end }.should raise_error(TypeError)
+ -> { class ClassSpecs::A < Array; end }.should.raise(TypeError)
end
it "adds new methods to subclasses" do
- -> { ClassSpecs::M.m }.should raise_error(NoMethodError)
+ -> { ClassSpecs::M.m }.should.raise(NoMethodError)
class ClassSpecs::L
def self.m
1
@@ -346,6 +354,39 @@ describe "Reopening a class" do
ClassSpecs::M.m.should == 1
ClassSpecs::L.singleton_class.send(:remove_method, :m)
end
+
+ it "does not reopen a class included in Object" do
+ ruby_exe(<<~RUBY).should == "false"
+ module IncludedInObject
+ class IncludedClass
+ end
+ end
+ class Object
+ include IncludedInObject
+ end
+ class IncludedClass
+ end
+ print IncludedInObject::IncludedClass == Object::IncludedClass
+ RUBY
+ end
+
+ it "does not reopen a class included in non-Object modules" do
+ ruby_exe(<<~RUBY).should == "false/false"
+ module Included
+ module IncludedClass; end
+ end
+ module M
+ include Included
+ module IncludedClass; end
+ end
+ class C
+ include Included
+ module IncludedClass; end
+ end
+ print Included::IncludedClass == M::IncludedClass, "/",
+ Included::IncludedClass == C::IncludedClass
+ RUBY
+ end
end
describe "class provides hooks" do
diff --git a/spec/ruby/language/class_variable_spec.rb b/spec/ruby/language/class_variable_spec.rb
index a26a3fb8de..84a7684c6d 100644
--- a/spec/ruby/language/class_variable_spec.rb
+++ b/spec/ruby/language/class_variable_spec.rb
@@ -30,19 +30,19 @@ describe "A class variable defined in a module" do
end
it "is not defined in these classes" do
- ClassVariablesSpec::ClassC.cvar_defined?.should be_false
+ ClassVariablesSpec::ClassC.cvar_defined?.should == false
end
it "is only updated in the module a method defined in the module is used" do
ClassVariablesSpec::ClassC.cvar_m = "new value"
ClassVariablesSpec::ClassC.cvar_m.should == "new value"
- ClassVariablesSpec::ClassC.cvar_defined?.should be_false
+ ClassVariablesSpec::ClassC.cvar_defined?.should == false
end
it "is updated in the class when a Method defined in the class is used" do
ClassVariablesSpec::ClassC.cvar_c = "new value"
- ClassVariablesSpec::ClassC.cvar_defined?.should be_true
+ ClassVariablesSpec::ClassC.cvar_defined?.should == true
end
it "can be accessed inside the class using the module methods" do
@@ -55,11 +55,11 @@ describe "A class variable defined in a module" do
end
it "is defined in the extended module" do
- ClassVariablesSpec::ModuleN.class_variable_defined?(:@@cvar_n).should be_true
+ ClassVariablesSpec::ModuleN.class_variable_defined?(:@@cvar_n).should == true
end
it "is not defined in the extending module" do
- ClassVariablesSpec::ModuleO.class_variable_defined?(:@@cvar_n).should be_false
+ ClassVariablesSpec::ModuleO.class_variable_defined?(:@@cvar_n).should == false
end
end
@@ -70,14 +70,14 @@ describe 'A class variable definition' do
c = Class.new(b)
b.class_variable_set(:@@cv, :value)
- -> { a.class_variable_get(:@@cv) }.should raise_error(NameError)
+ -> { a.class_variable_get(:@@cv) }.should.raise(NameError)
b.class_variable_get(:@@cv).should == :value
c.class_variable_get(:@@cv).should == :value
# updates the same variable
c.class_variable_set(:@@cv, :next)
- -> { a.class_variable_get(:@@cv) }.should raise_error(NameError)
+ -> { a.class_variable_get(:@@cv) }.should.raise(NameError)
b.class_variable_get(:@@cv).should == :next
c.class_variable_get(:@@cv).should == :next
end
@@ -87,16 +87,16 @@ 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')
+ }.should.raise(RuntimeError, 'class variable access from toplevel')
-> {
eval "@@cvar_toplevel2 = 2"
- }.should raise_error(RuntimeError, 'class variable access from toplevel')
+ }.should.raise(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
+ }.should_not.raise
end
it "raises a RuntimeError when a class variable is overtaken in an ancestor class" do
@@ -107,7 +107,7 @@ describe 'Accessing a class variable' do
-> {
subclass.class_variable_get(:@@cvar_overtaken)
- }.should raise_error(RuntimeError, /class variable @@cvar_overtaken of .+ is overtaken by .+/)
+ }.should.raise(RuntimeError, /class variable @@cvar_overtaken of .+ is overtaken by .+/)
parent.class_variable_get(:@@cvar_overtaken).should == :parent
end
diff --git a/spec/ruby/language/constants_spec.rb b/spec/ruby/language/constants_spec.rb
index 063c52c422..0880230a36 100644
--- a/spec/ruby/language/constants_spec.rb
+++ b/spec/ruby/language/constants_spec.rb
@@ -51,8 +51,8 @@ describe "Literal (A::X) constant resolution" do
it "does not search the singleton class of the class or module" do
-> do
ConstantSpecs::ContainerA::ChildA::CS_CONST14
- end.should raise_error(NameError)
- -> { ConstantSpecs::CS_CONST14 }.should raise_error(NameError)
+ end.should.raise(NameError)
+ -> { ConstantSpecs::CS_CONST14 }.should.raise(NameError)
end
end
@@ -135,7 +135,7 @@ describe "Literal (A::X) constant resolution" do
-> do
ConstantSpecs::ContainerB::ChildB::CS_CONST108
- end.should raise_error(NameError)
+ end.should.raise(NameError)
module ConstantSpecs
class << self
@@ -143,7 +143,7 @@ describe "Literal (A::X) constant resolution" do
end
end
- -> { ConstantSpecs::CS_CONST108 }.should raise_error(NameError)
+ -> { ConstantSpecs::CS_CONST108 }.should.raise(NameError)
ensure
ConstantSpecs::ContainerB::ChildB.singleton_class.send(:remove_const, :CS_CONST108)
ConstantSpecs.singleton_class.send(:remove_const, :CS_CONST108)
@@ -175,7 +175,7 @@ describe "Literal (A::X) constant resolution" do
end
it "raises a NameError if no constant is defined in the search path" do
- -> { ConstantSpecs::ParentA::CS_CONSTX }.should raise_error(NameError)
+ -> { ConstantSpecs::ParentA::CS_CONSTX }.should.raise(NameError)
end
it "uses the module or class #name to craft the error message" do
@@ -189,7 +189,7 @@ describe "Literal (A::X) constant resolution" do
end
end
- -> { mod::DOES_NOT_EXIST }.should raise_error(NameError, /uninitialized constant ModuleName::DOES_NOT_EXIST/)
+ -> { mod::DOES_NOT_EXIST }.should.raise(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
@@ -203,7 +203,7 @@ describe "Literal (A::X) constant resolution" do
end
end
- -> { mod::DOES_NOT_EXIST }.should raise_error(NameError, /uninitialized constant <unusable info>::DOES_NOT_EXIST/)
+ -> { mod::DOES_NOT_EXIST }.should.raise(NameError, /uninitialized constant <unusable info>::DOES_NOT_EXIST/)
end
it "sends #const_missing to the original class or module scope" do
@@ -215,10 +215,10 @@ describe "Literal (A::X) constant resolution" do
end
it "raises a TypeError if a non-class or non-module qualifier is given" do
- -> { CS_CONST1::CS_CONST }.should raise_error(TypeError)
- -> { 1::CS_CONST }.should raise_error(TypeError)
- -> { "mod"::CS_CONST }.should raise_error(TypeError)
- -> { false::CS_CONST }.should raise_error(TypeError)
+ -> { CS_CONST1::CS_CONST }.should.raise(TypeError)
+ -> { 1::CS_CONST }.should.raise(TypeError)
+ -> { "mod"::CS_CONST }.should.raise(TypeError)
+ -> { false::CS_CONST }.should.raise(TypeError)
end
end
@@ -264,7 +264,7 @@ describe "Constant resolution within methods" do
end
it "does not search the lexical scope of the caller" do
- -> { ConstantSpecs::ClassA.const16 }.should raise_error(NameError)
+ -> { ConstantSpecs::ClassA.const16 }.should.raise(NameError)
end
it "searches the lexical scope of a block" do
@@ -279,7 +279,7 @@ describe "Constant resolution within methods" do
it "does not search the lexical scope of qualifying modules" do
-> do
ConstantSpecs::ContainerA::ChildA.const23
- end.should raise_error(NameError)
+ end.should.raise(NameError)
end
end
@@ -377,7 +377,7 @@ describe "Constant resolution within methods" do
it "does not search the lexical scope of the caller" do
ConstantSpecs::ClassB::CS_CONST209 = :const209
- -> { ConstantSpecs::ClassB.const209 }.should raise_error(NameError)
+ -> { ConstantSpecs::ClassB.const209 }.should.raise(NameError)
ensure
ConstantSpecs::ClassB.send(:remove_const, :CS_CONST209)
end
@@ -426,14 +426,14 @@ describe "Constant resolution within methods" do
-> do
ConstantSpecs::ContainerB::ChildB.const214
- end.should raise_error(NameError)
+ end.should.raise(NameError)
ensure
ConstantSpecs::ContainerB.send(:remove_const, :CS_CONST214)
end
end
it "raises a NameError if no constant is defined in the search path" do
- -> { ConstantSpecs::ParentA.constx }.should raise_error(NameError)
+ -> { ConstantSpecs::ParentA.constx }.should.raise(NameError)
end
it "sends #const_missing to the original class or module scope" do
@@ -456,7 +456,7 @@ describe "Constant resolution within a singleton class (class << obj)" do
it "uses its own namespace for nested modules" do
a = ConstantSpecs::CS_SINGLETON3[0].x
b = ConstantSpecs::CS_SINGLETON3[1].x
- a.should_not equal(b)
+ a.should_not.equal?(b)
end
it "allows nested modules to have proper resolution" do
@@ -469,12 +469,12 @@ end
describe "top-level constant lookup" do
context "on a class" do
it "does not search Object after searching other scopes" do
- -> { String::Hash }.should raise_error(NameError)
+ -> { String::Hash }.should.raise(NameError)
end
end
it "searches Object unsuccessfully when searches on a module" do
- -> { Enumerable::Hash }.should raise_error(NameError)
+ -> { Enumerable::Hash }.should.raise(NameError)
end
end
@@ -488,7 +488,7 @@ describe "Module#private_constant marked constants" do
mod.const_set :Foo, false
}.should complain(/already initialized constant/)
- -> {mod::Foo}.should raise_error(NameError)
+ -> {mod::Foo}.should.raise(NameError)
end
it "sends #const_missing to the original class or module" do
@@ -506,19 +506,19 @@ describe "Module#private_constant marked constants" do
it "cannot be accessed from outside the module" do
-> do
ConstantVisibility::PrivConstModule::PRIVATE_CONSTANT_MODULE
- end.should raise_error(NameError)
+ end.should.raise(NameError)
end
it "cannot be reopened as a module from scope where constant would be private" do
-> do
module ConstantVisibility::ModuleContainer::PrivateModule; end
- end.should raise_error(NameError)
+ end.should.raise(NameError)
end
it "cannot be reopened as a class from scope where constant would be private" do
-> do
class ConstantVisibility::ModuleContainer::PrivateClass; end
- end.should raise_error(NameError)
+ end.should.raise(NameError)
end
it "can be reopened as a module where constant is not private" do
@@ -554,7 +554,7 @@ describe "Module#private_constant marked constants" do
end
it "can be accessed from the module itself" do
- ConstantVisibility::PrivConstModule.private_constant_from_self.should be_true
+ ConstantVisibility::PrivConstModule.private_constant_from_self.should == true
end
it "is defined? from the module itself" do
@@ -562,7 +562,7 @@ describe "Module#private_constant marked constants" do
end
it "can be accessed from lexical scope" do
- ConstantVisibility::PrivConstModule::Nested.private_constant_from_scope.should be_true
+ ConstantVisibility::PrivConstModule::Nested.private_constant_from_scope.should == true
end
it "is defined? from lexical scope" do
@@ -570,20 +570,20 @@ describe "Module#private_constant marked constants" do
end
it "can be accessed from classes that include the module" do
- ConstantVisibility::ClassIncludingPrivConstModule.new.private_constant_from_include.should be_true
+ ConstantVisibility::ClassIncludingPrivConstModule.new.private_constant_from_include.should == true
end
it "can be accessed from modules that include the module" do
- ConstantVisibility::ModuleIncludingPrivConstModule.private_constant_from_include.should be_true
+ ConstantVisibility::ModuleIncludingPrivConstModule.private_constant_from_include.should == true
end
it "raises a NameError when accessed directly from modules that include the module" do
-> do
ConstantVisibility::ModuleIncludingPrivConstModule.private_constant_self_from_include
- end.should raise_error(NameError)
+ end.should.raise(NameError)
-> do
ConstantVisibility::ModuleIncludingPrivConstModule.private_constant_named_from_include
- end.should raise_error(NameError)
+ end.should.raise(NameError)
end
it "is defined? from classes that include the module" do
@@ -595,19 +595,19 @@ describe "Module#private_constant marked constants" do
it "cannot be accessed from outside the class" do
-> do
ConstantVisibility::PrivConstClass::PRIVATE_CONSTANT_CLASS
- end.should raise_error(NameError)
+ end.should.raise(NameError)
end
it "cannot be reopened as a module" do
-> do
module ConstantVisibility::ClassContainer::PrivateModule; end
- end.should raise_error(NameError)
+ end.should.raise(NameError)
end
it "cannot be reopened as a class" do
-> do
class ConstantVisibility::ClassContainer::PrivateClass; end
- end.should raise_error(NameError)
+ end.should.raise(NameError)
end
it "can be reopened as a module where constant is not private" do
@@ -643,7 +643,7 @@ describe "Module#private_constant marked constants" do
end
it "can be accessed from the class itself" do
- ConstantVisibility::PrivConstClass.private_constant_from_self.should be_true
+ ConstantVisibility::PrivConstClass.private_constant_from_self.should == true
end
it "is defined? from the class itself" do
@@ -651,7 +651,7 @@ describe "Module#private_constant marked constants" do
end
it "can be accessed from lexical scope" do
- ConstantVisibility::PrivConstClass::Nested.private_constant_from_scope.should be_true
+ ConstantVisibility::PrivConstClass::Nested.private_constant_from_scope.should == true
end
it "is defined? from lexical scope" do
@@ -659,7 +659,7 @@ describe "Module#private_constant marked constants" do
end
it "can be accessed from subclasses" do
- ConstantVisibility::PrivConstClassChild.new.private_constant_from_subclass.should be_true
+ ConstantVisibility::PrivConstClassChild.new.private_constant_from_subclass.should == true
end
it "is defined? from subclasses" do
@@ -671,7 +671,7 @@ describe "Module#private_constant marked constants" do
it "cannot be accessed using ::Const form" do
-> do
::PRIVATE_CONSTANT_IN_OBJECT
- end.should raise_error(NameError)
+ end.should.raise(NameError)
end
it "is not defined? using ::Const form" do
@@ -691,14 +691,14 @@ describe "Module#private_constant marked constants" do
it "has :receiver and :name attributes" do
-> do
ConstantVisibility::PrivConstClass::PRIVATE_CONSTANT_CLASS
- end.should raise_error(NameError) {|e|
+ end.should.raise(NameError) {|e|
e.receiver.should == ConstantVisibility::PrivConstClass
e.name.should == :PRIVATE_CONSTANT_CLASS
}
-> do
ConstantVisibility::PrivConstModule::PRIVATE_CONSTANT_MODULE
- end.should raise_error(NameError) {|e|
+ end.should.raise(NameError) {|e|
e.receiver.should == ConstantVisibility::PrivConstModule
e.name.should == :PRIVATE_CONSTANT_MODULE
}
@@ -707,14 +707,14 @@ describe "Module#private_constant marked constants" do
it "has the defined class as the :name attribute" do
-> do
ConstantVisibility::PrivConstClassChild::PRIVATE_CONSTANT_CLASS
- end.should raise_error(NameError) {|e|
+ end.should.raise(NameError) {|e|
e.receiver.should == ConstantVisibility::PrivConstClass
e.name.should == :PRIVATE_CONSTANT_CLASS
}
-> do
ConstantVisibility::ClassIncludingPrivConstModule::PRIVATE_CONSTANT_MODULE
- end.should raise_error(NameError) {|e|
+ end.should.raise(NameError) {|e|
e.receiver.should == ConstantVisibility::PrivConstModule
e.name.should == :PRIVATE_CONSTANT_MODULE
}
@@ -783,7 +783,7 @@ describe 'Allowed characters' do
it 'does not allow not ASCII characters that cannot be upcased or lowercased at the beginning' do
-> do
Module.new.const_set("થBB", 1)
- end.should raise_error(NameError, /wrong constant name/)
+ end.should.raise(NameError, /wrong constant name/)
end
it 'allows not ASCII upcased characters at the beginning' do
@@ -803,7 +803,7 @@ describe 'Assignment' do
B = 1
end
CODE
- end.should raise_error(SyntaxError, /dynamic constant assignment/)
+ end.should.raise(SyntaxError, /dynamic constant assignment/)
end
end
end
diff --git a/spec/ruby/language/def_spec.rb b/spec/ruby/language/def_spec.rb
index 296d4787d0..a589b4750b 100644
--- a/spec/ruby/language/def_spec.rb
+++ b/spec/ruby/language/def_spec.rb
@@ -14,11 +14,11 @@ end
describe "Defining a method at the top-level" do
it "defines it on Object with private visibility by default" do
- Object.should have_private_instance_method(:some_toplevel_method, false)
+ Object.private_instance_methods(false).should.include?(:some_toplevel_method)
end
it "defines it on Object with public visibility after calling public" do
- Object.should have_public_instance_method(:public_toplevel_method, false)
+ Object.public_instance_methods(false).should.include?(:public_toplevel_method)
end
end
@@ -28,7 +28,7 @@ describe "Defining an 'initialize' method" do
def initialize
end
end
- DefInitializeSpec.should have_private_instance_method(:initialize, false)
+ DefInitializeSpec.private_instance_methods(false).should.include?(:initialize)
end
end
@@ -38,7 +38,7 @@ describe "Defining an 'initialize_copy' method" do
def initialize_copy
end
end
- DefInitializeCopySpec.should have_private_instance_method(:initialize_copy, false)
+ DefInitializeCopySpec.private_instance_methods(false).should.include?(:initialize_copy)
end
end
@@ -48,7 +48,7 @@ describe "Defining an 'initialize_dup' method" do
def initialize_dup
end
end
- DefInitializeDupSpec.should have_private_instance_method(:initialize_dup, false)
+ DefInitializeDupSpec.private_instance_methods(false).should.include?(:initialize_dup)
end
end
@@ -58,7 +58,7 @@ describe "Defining an 'initialize_clone' method" do
def initialize_clone
end
end
- DefInitializeCloneSpec.should have_private_instance_method(:initialize_clone, false)
+ DefInitializeCloneSpec.private_instance_methods(false).should.include?(:initialize_clone)
end
end
@@ -68,7 +68,7 @@ describe "Defining a 'respond_to_missing?' method" do
def respond_to_missing?
end
end
- DefRespondToMissingPSpec.should have_private_instance_method(:respond_to_missing?, false)
+ DefRespondToMissingPSpec.private_instance_methods(false).should.include?(:respond_to_missing?)
end
end
@@ -82,12 +82,12 @@ end
describe "An instance method" do
it "raises an error with too few arguments" do
def foo(a, b); end
- -> { foo 1 }.should raise_error(ArgumentError, 'wrong number of arguments (given 1, expected 2)')
+ -> { foo 1 }.should.raise(ArgumentError, 'wrong number of arguments (given 1, expected 2)')
end
it "raises an error with too many arguments" do
def foo(a); end
- -> { foo 1, 2 }.should raise_error(ArgumentError, 'wrong number of arguments (given 2, expected 1)')
+ -> { foo 1, 2 }.should.raise(ArgumentError, 'wrong number of arguments (given 2, expected 1)')
end
it "raises FrozenError with the correct class name" do
@@ -96,8 +96,9 @@ describe "An instance method" do
self.freeze
def foo; end
end
- }.should raise_error(FrozenError) { |e|
- e.message.should == "can't modify frozen module: #{e.receiver}"
+ }.should.raise(FrozenError) { |e|
+ msg_class = ruby_version_is("4.0") ? "Module" : "module"
+ e.message.should == "can't modify frozen #{msg_class}: #{e.receiver}"
}
-> {
@@ -105,8 +106,9 @@ describe "An instance method" do
self.freeze
def foo; end
end
- }.should raise_error(FrozenError){ |e|
- e.message.should == "can't modify frozen class: #{e.receiver}"
+ }.should.raise(FrozenError){ |e|
+ msg_class = ruby_version_is("4.0") ? "Class" : "class"
+ e.message.should == "can't modify frozen #{msg_class}: #{e.receiver}"
}
end
end
@@ -133,12 +135,12 @@ describe "An instance method definition with a splat" do
end
it "allows only a single * argument" do
- -> { eval 'def foo(a, *b, *c); end' }.should raise_error(SyntaxError)
+ -> { eval 'def foo(a, *b, *c); end' }.should.raise(SyntaxError)
end
it "requires the presence of any arguments that precede the *" do
def foo(a, b, *c); end
- -> { foo 1 }.should raise_error(ArgumentError, 'wrong number of arguments (given 1, expected 2+)')
+ -> { foo 1 }.should.raise(ArgumentError, 'wrong number of arguments (given 1, expected 2+)')
end
end
@@ -171,7 +173,7 @@ describe "An instance method with a default argument" do
def foo(a, b = 2)
[a,b]
end
- -> { foo }.should raise_error(ArgumentError, 'wrong number of arguments (given 0, expected 1..2)')
+ -> { foo }.should.raise(ArgumentError, 'wrong number of arguments (given 0, expected 1..2)')
foo(1).should == [1, 2]
end
@@ -179,7 +181,7 @@ describe "An instance method with a default argument" do
def foo(a, b = 2, *c)
[a,b,c]
end
- -> { foo }.should raise_error(ArgumentError, 'wrong number of arguments (given 0, expected 1+)')
+ -> { foo }.should.raise(ArgumentError, 'wrong number of arguments (given 0, expected 1+)')
foo(1).should == [1,2,[]]
end
@@ -203,7 +205,7 @@ describe "An instance method with a default argument" do
eval "def foo(bar = bar)
bar
end"
- }.should raise_error(SyntaxError)
+ }.should.raise(SyntaxError)
end
end
@@ -277,58 +279,48 @@ describe "A singleton method definition" do
it "raises FrozenError if frozen" do
obj = Object.new
obj.freeze
- -> { def obj.foo; end }.should raise_error(FrozenError)
+ -> { def obj.foo; end }.should.raise(FrozenError)
end
it "raises FrozenError with the correct class name" do
obj = Object.new
obj.freeze
- -> { def obj.foo; end }.should raise_error(FrozenError, "can't modify frozen object: #{obj}")
+ msg_class = ruby_version_is("4.0") ? "Object" : "object"
+ -> { def obj.foo; end }.should.raise(FrozenError, "can't modify frozen #{msg_class}: #{obj}")
obj = Object.new
c = obj.singleton_class
c.singleton_class.freeze
- -> { def c.foo; end }.should raise_error(FrozenError, "can't modify frozen Class: #{c}")
+ -> { def c.foo; end }.should.raise(FrozenError, "can't modify frozen Class: #{c}")
c = Class.new
c.freeze
- -> { def c.foo; end }.should raise_error(FrozenError, "can't modify frozen Class: #{c}")
+ -> { def c.foo; end }.should.raise(FrozenError, "can't modify frozen Class: #{c}")
m = Module.new
m.freeze
- -> { def m.foo; end }.should raise_error(FrozenError, "can't modify frozen Module: #{m}")
+ -> { def m.foo; end }.should.raise(FrozenError, "can't modify frozen Module: #{m}")
end
end
describe "Redefining a singleton method" do
it "does not inherit a previously set visibility" do
o = Object.new
+ sc = o.singleton_class
- class << o; private; def foo; end; end;
-
- class << o; should have_private_instance_method(:foo); end
-
- class << o; def foo; end; end;
-
- class << o; should_not have_private_instance_method(:foo); end
- class << o; should have_instance_method(:foo); end
-
- end
-end
-
-describe "Redefining a singleton method" do
- it "does not inherit a previously set visibility" do
- o = Object.new
-
- class << o; private; def foo; end; end;
-
- class << o; should have_private_instance_method(:foo); end
+ class << o
+ private
+ def foo; end
+ end
- class << o; def foo; end; end;
+ sc.private_instance_methods(false).should.include?(:foo)
- class << o; should_not have_private_instance_method(:foo); end
- class << o; should have_instance_method(:foo); end
+ class << o
+ def foo; end
+ end
+ sc.private_instance_methods(false).should_not.include?(:foo)
+ sc.should.method_defined?(:foo)
end
end
@@ -431,7 +423,7 @@ describe "A method definition inside a metaclass scope" do
end
DefSpecSingleton.a_class_method.should == DefSpecSingleton
- -> { Object.a_class_method }.should raise_error(NoMethodError)
+ -> { Object.a_class_method }.should.raise(NoMethodError)
end
it "can create a singleton method" do
@@ -441,7 +433,7 @@ describe "A method definition inside a metaclass scope" do
end
obj.a_singleton_method.should == obj
- -> { Object.new.a_singleton_method }.should raise_error(NoMethodError)
+ -> { Object.new.a_singleton_method }.should.raise(NoMethodError)
end
it "raises FrozenError if frozen" do
@@ -449,7 +441,7 @@ describe "A method definition inside a metaclass scope" do
obj.freeze
class << obj
- -> { def foo; end }.should raise_error(FrozenError)
+ -> { def foo; end }.should.raise(FrozenError)
end
end
end
@@ -470,7 +462,7 @@ describe "A nested method definition" do
other = DefSpecNested.new
other.an_instance_method.should == other
- DefSpecNested.should have_instance_method(:an_instance_method)
+ DefSpecNested.should.method_defined?(:an_instance_method, false)
end
it "creates a class method when evaluated in a class method" do
@@ -485,11 +477,11 @@ describe "A nested method definition" do
end
end
- -> { DefSpecNested.a_class_method }.should raise_error(NoMethodError)
+ -> { DefSpecNested.a_class_method }.should.raise(NoMethodError)
DefSpecNested.create_class_method.should == DefSpecNested
DefSpecNested.a_class_method.should == DefSpecNested
- -> { Object.a_class_method }.should raise_error(NoMethodError)
- -> { DefSpecNested.new.a_class_method }.should raise_error(NoMethodError)
+ -> { Object.a_class_method }.should.raise(NoMethodError)
+ -> { DefSpecNested.new.a_class_method }.should.raise(NoMethodError)
end
it "creates a singleton method when evaluated in the metaclass of an instance" do
@@ -507,7 +499,7 @@ describe "A nested method definition" do
obj.a_singleton_method.should == obj
other = DefSpecNested.new
- -> { other.a_singleton_method }.should raise_error(NoMethodError)
+ -> { other.a_singleton_method }.should.raise(NoMethodError)
end
it "creates a method in the surrounding context when evaluated in a def expr.method" do
@@ -519,8 +511,8 @@ describe "A nested method definition" do
end
DefSpecNested::TARGET.defs_method
- DefSpecNested.should have_instance_method :inherited_method
- DefSpecNested::TARGET.should_not have_method :inherited_method
+ DefSpecNested.should.method_defined?(:inherited_method, false)
+ DefSpecNested::TARGET.should_not.respond_to? :inherited_method
obj = DefSpecNested.new
obj.inherited_method.should == obj
@@ -542,11 +534,11 @@ describe "A nested method definition" do
obj = DefSpecNested::OBJ
obj.create_method_in_instance_eval
- obj.should have_method :arg_method
- obj.should have_method :body_method
+ obj.should.respond_to? :arg_method
+ obj.should.respond_to? :body_method
- DefSpecNested.should_not have_instance_method :arg_method
- DefSpecNested.should_not have_instance_method :body_method
+ DefSpecNested.should_not.method_defined? :arg_method
+ DefSpecNested.should_not.method_defined? :body_method
ensure
DefSpecNested.send(:remove_const, :OBJ)
end
@@ -566,7 +558,7 @@ describe "A nested method definition" do
cls.new.new_def.should == 1
- -> { Object.new.new_def }.should raise_error(NoMethodError)
+ -> { Object.new.new_def }.should.raise(NoMethodError)
end
end
@@ -582,18 +574,18 @@ describe "A method definition always resets the visibility to public for nested
end
obj = cls.new
- -> { obj.do_def }.should raise_error(NoMethodError, /private/)
+ -> { obj.do_def }.should.raise(NoMethodError, /private/)
obj.send :do_def
obj.new_def.should == 1
cls.new.new_def.should == 1
- -> { Object.new.new_def }.should raise_error(NoMethodError)
+ -> { Object.new.new_def }.should.raise(NoMethodError)
end
it "at the toplevel" do
obj = Object.new
- -> { obj.toplevel_define_other_method }.should raise_error(NoMethodError, /private/)
+ -> { obj.toplevel_define_other_method }.should.raise(NoMethodError, /private/)
toplevel_define_other_method
nested_method_in_toplevel_method.should == 42
@@ -610,7 +602,7 @@ describe "A method definition inside an instance_eval" do
obj.an_instance_eval_method.should == obj
other = Object.new
- -> { other.an_instance_eval_method }.should raise_error(NoMethodError)
+ -> { other.an_instance_eval_method }.should.raise(NoMethodError)
end
it "creates a singleton method when evaluated inside a metaclass" do
@@ -623,7 +615,7 @@ describe "A method definition inside an instance_eval" do
obj.a_metaclass_eval_method.should == obj
other = Object.new
- -> { other.a_metaclass_eval_method }.should raise_error(NoMethodError)
+ -> { other.a_metaclass_eval_method }.should.raise(NoMethodError)
end
it "creates a class method when the receiver is a class" do
@@ -632,7 +624,7 @@ describe "A method definition inside an instance_eval" do
end
DefSpecNested.an_instance_eval_class_method.should == DefSpecNested
- -> { Object.an_instance_eval_class_method }.should raise_error(NoMethodError)
+ -> { Object.an_instance_eval_class_method }.should.raise(NoMethodError)
end
it "creates a class method when the receiver is an anonymous class" do
@@ -644,7 +636,7 @@ describe "A method definition inside an instance_eval" do
end
m.klass_method.should == :test
- -> { Object.klass_method }.should raise_error(NoMethodError)
+ -> { Object.klass_method }.should.raise(NoMethodError)
end
it "creates a class method when instance_eval is within class" do
@@ -657,7 +649,7 @@ describe "A method definition inside an instance_eval" do
end
m.klass_method.should == :test
- -> { Object.klass_method }.should raise_error(NoMethodError)
+ -> { Object.klass_method }.should.raise(NoMethodError)
end
end
@@ -670,7 +662,7 @@ describe "A method definition inside an instance_exec" do
end
DefSpecNested.an_instance_exec_class_method.should == 1
- -> { Object.an_instance_exec_class_method }.should raise_error(NoMethodError)
+ -> { Object.an_instance_exec_class_method }.should.raise(NoMethodError)
end
it "creates a class method when the receiver is an anonymous class" do
@@ -684,7 +676,7 @@ describe "A method definition inside an instance_exec" do
end
m.klass_method.should == 1
- -> { Object.klass_method }.should raise_error(NoMethodError)
+ -> { Object.klass_method }.should.raise(NoMethodError)
end
it "creates a class method when instance_exec is within class" do
@@ -699,7 +691,7 @@ describe "A method definition inside an instance_exec" do
end
m.klass_method.should == 2
- -> { Object.klass_method }.should raise_error(NoMethodError)
+ -> { Object.klass_method }.should.raise(NoMethodError)
end
end
@@ -719,7 +711,7 @@ describe "A method definition in an eval" do
other = DefSpecNested.new
other.an_eval_instance_method.should == other
- -> { Object.new.an_eval_instance_method }.should raise_error(NoMethodError)
+ -> { Object.new.an_eval_instance_method }.should.raise(NoMethodError)
end
it "creates a class method" do
@@ -735,8 +727,8 @@ describe "A method definition in an eval" do
DefSpecNestedB.eval_class_method.should == DefSpecNestedB
DefSpecNestedB.an_eval_class_method.should == DefSpecNestedB
- -> { Object.an_eval_class_method }.should raise_error(NoMethodError)
- -> { DefSpecNestedB.new.an_eval_class_method}.should raise_error(NoMethodError)
+ -> { Object.an_eval_class_method }.should.raise(NoMethodError)
+ -> { DefSpecNestedB.new.an_eval_class_method}.should.raise(NoMethodError)
end
it "creates a singleton method" do
@@ -754,7 +746,7 @@ describe "A method definition in an eval" do
obj.an_eval_singleton_method.should == obj
other = DefSpecNested.new
- -> { other.an_eval_singleton_method }.should raise_error(NoMethodError)
+ -> { other.an_eval_singleton_method }.should.raise(NoMethodError)
end
end
@@ -765,8 +757,8 @@ describe "a method definition that sets more than one default parameter all to t
it "assigns them all the same object by default" do
foo.should == [{},{},{}]
a, b, c = foo
- a.should eql(b)
- a.should eql(c)
+ a.should.eql?(b)
+ a.should.eql?(c)
end
it "allows the first argument to be given, and sets the rest to null" do
@@ -776,11 +768,11 @@ describe "a method definition that sets more than one default parameter all to t
it "assigns the parameters different objects across different default calls" do
a, _b, _c = foo
d, _e, _f = foo
- a.should_not equal(d)
+ a.should_not.equal?(d)
end
it "only allows overriding the default value of the first such parameter in each set" do
- -> { foo(1,2) }.should raise_error(ArgumentError, 'wrong number of arguments (given 2, expected 0..1)')
+ -> { foo(1,2) }.should.raise(ArgumentError, 'wrong number of arguments (given 2, expected 0..1)')
end
def bar(a=b=c=1,d=2)
@@ -791,7 +783,7 @@ describe "a method definition that sets more than one default parameter all to t
bar.should == [1,1,1,2]
bar(3).should == [3,nil,nil,2]
bar(3,4).should == [3,nil,nil,4]
- -> { bar(3,4,5) }.should raise_error(ArgumentError, 'wrong number of arguments (given 3, expected 0..2)')
+ -> { bar(3,4,5) }.should.raise(ArgumentError, 'wrong number of arguments (given 3, expected 0..2)')
end
end
@@ -806,7 +798,7 @@ describe "The def keyword" do
}.call
end
- DefSpecsLambdaVisibility.should have_private_instance_method("some_method")
+ DefSpecsLambdaVisibility.private_instance_methods(false).should.include?(:some_method)
end
end
end
diff --git a/spec/ruby/language/defined_spec.rb b/spec/ruby/language/defined_spec.rb
index 80ad1818b1..6846179a7c 100644
--- a/spec/ruby/language/defined_spec.rb
+++ b/spec/ruby/language/defined_spec.rb
@@ -70,7 +70,7 @@ describe "The defined? keyword when called with a method name" do
end
it "returns nil if the method is not defined" do
- defined?(defined_specs_undefined_method).should be_nil
+ defined?(defined_specs_undefined_method).should == nil
end
it "returns 'method' if the method is defined and private" do
@@ -90,23 +90,23 @@ describe "The defined? keyword when called with a method name" do
end
it "returns nil if the method is private" do
- defined?(Object.print).should be_nil
+ defined?(Object.print).should == nil
end
it "returns nil if the method is protected" do
- defined?(DefinedSpecs::Basic.new.protected_method).should be_nil
+ defined?(DefinedSpecs::Basic.new.protected_method).should == nil
end
it "returns nil if the method is not defined" do
- defined?(Kernel.defined_specs_undefined_method).should be_nil
+ defined?(Kernel.defined_specs_undefined_method).should == nil
end
it "returns nil if the class is not defined" do
- defined?(DefinedSpecsUndefined.puts).should be_nil
+ defined?(DefinedSpecsUndefined.puts).should == nil
end
it "returns nil if the subclass is not defined" do
- defined?(DefinedSpecs::Undefined.puts).should be_nil
+ defined?(DefinedSpecs::Undefined.puts).should == nil
end
end
@@ -123,11 +123,11 @@ describe "The defined? keyword when called with a method name" do
it "returns nil if the method is not defined" do
obj = DefinedSpecs::Basic.new
- defined?(obj.an_undefined_method).should be_nil
+ defined?(obj.an_undefined_method).should == nil
end
it "returns nil if the variable does not exist" do
- defined?(nonexistent_local_variable.some_method).should be_nil
+ defined?(nonexistent_local_variable.some_method).should == nil
end
it "calls #respond_to_missing?" do
@@ -145,11 +145,11 @@ describe "The defined? keyword when called with a method name" do
it "returns nil if the method is not defined" do
@defined_specs_obj = DefinedSpecs::Basic.new
- defined?(@defined_specs_obj.an_undefined_method).should be_nil
+ defined?(@defined_specs_obj.an_undefined_method).should == nil
end
it "returns nil if the variable does not exist" do
- defined?(@nonexistent_instance_variable.some_method).should be_nil
+ defined?(@nonexistent_instance_variable.some_method).should == nil
end
end
@@ -161,22 +161,22 @@ describe "The defined? keyword when called with a method name" do
it "returns nil if the method is not defined" do
$defined_specs_obj = DefinedSpecs::Basic.new
- defined?($defined_specs_obj.an_undefined_method).should be_nil
+ defined?($defined_specs_obj.an_undefined_method).should == nil
end
it "returns nil if the variable does not exist" do
- defined?($nonexistent_global_variable.some_method).should be_nil
+ defined?($nonexistent_global_variable.some_method).should == nil
end
end
describe "having a method call as a receiver" do
it "returns nil if evaluating the receiver raises an exception" do
- defined?(DefinedSpecs.exception_method / 2).should be_nil
+ defined?(DefinedSpecs.exception_method / 2).should == nil
ScratchPad.recorded.should == :defined_specs_exception
end
it "returns nil if the method is not defined on the object the receiver returns" do
- defined?(DefinedSpecs.side_effects / 2).should be_nil
+ defined?(DefinedSpecs.side_effects / 2).should == nil
ScratchPad.recorded.should == :defined_specs_side_effects
end
@@ -211,6 +211,22 @@ describe "The defined? keyword when called with a method name" do
}.should complain(/warning: possibly useless use of defined\? in void context/, verbose: true)
end
end
+
+ describe "for a protected method" do
+ it "returns 'method' when the receiver is a subclass instance" do
+ DefinedSpecs::ProtectedBase.new.defined_on(DefinedSpecs::ProtectedSubclass.new).should == "method"
+ end
+
+ it "returns 'method' when the receiver is the base class instance" do
+ DefinedSpecs::ProtectedSubclass.new.defined_on(DefinedSpecs::ProtectedBase.new).should == "method"
+ end
+
+ ruby_bug "#22076", ""..."4.1" do
+ it "returns 'method' when the receiver is a sibling class instance via a shared included module" do
+ DefinedSpecs::ProtectedIncluderA.new.defined_on(DefinedSpecs::ProtectedIncluderB.new).should == "method"
+ end
+ end
+ end
end
describe "The defined? keyword for an expression" do
@@ -403,15 +419,15 @@ describe "The defined? keyword for an expression" do
end
it "returns nil for an expression with == and an undefined method" do
- defined?(defined_specs_undefined_method == 2).should be_nil
+ defined?(defined_specs_undefined_method == 2).should == nil
end
it "returns nil for an expression with != and an undefined method" do
- defined?(defined_specs_undefined_method != 2).should be_nil
+ defined?(defined_specs_undefined_method != 2).should == nil
end
it "returns nil for an expression with !~ and an undefined method" do
- defined?(defined_specs_undefined_method !~ 2).should be_nil
+ defined?(defined_specs_undefined_method !~ 2).should == nil
end
it "returns 'method' for an expression with '=='" do
@@ -431,25 +447,25 @@ describe "The defined? keyword for an expression" do
describe "with logical connectives" do
it "returns nil for an expression with '!' and an undefined method" do
- defined?(!defined_specs_undefined_method).should be_nil
+ defined?(!defined_specs_undefined_method).should == nil
end
it "returns nil for an expression with '!' and an unset class variable" do
@result = eval("class singleton_class::A; defined?(!@@doesnt_exist) end", binding, __FILE__, __LINE__)
- @result.should be_nil
+ @result.should == nil
end
it "returns nil for an expression with 'not' and an undefined method" do
- defined?(not defined_specs_undefined_method).should be_nil
+ defined?(not defined_specs_undefined_method).should == nil
end
it "returns nil for an expression with 'not' and an unset class variable" do
@result = eval("class singleton_class::A; defined?(not @@doesnt_exist) end", binding, __FILE__, __LINE__)
- @result.should be_nil
+ @result.should == nil
end
it "does not propagate an exception raised by a method in a 'not' expression" do
- defined?(not DefinedSpecs.exception_method).should be_nil
+ defined?(not DefinedSpecs.exception_method).should == nil
ScratchPad.recorded.should == :defined_specs_exception
end
@@ -488,11 +504,11 @@ describe "The defined? keyword for an expression" do
end
it "returns nil for an expression with '!' and an unset global variable" do
- defined?(!$defined_specs_undefined_global_variable).should be_nil
+ defined?(!$defined_specs_undefined_global_variable).should == nil
end
it "returns nil for an expression with '!' and an unset instance variable" do
- defined?(!@defined_specs_undefined_instance_variable).should be_nil
+ defined?(!@defined_specs_undefined_instance_variable).should == nil
end
it "returns 'method' for a 'not' expression with a method" do
@@ -505,11 +521,11 @@ describe "The defined? keyword for an expression" do
end
it "returns nil for an expression with 'not' and an unset global variable" do
- defined?(not $defined_specs_undefined_global_variable).should be_nil
+ defined?(not $defined_specs_undefined_global_variable).should == nil
end
it "returns nil for an expression with 'not' and an unset instance variable" do
- defined?(not @defined_specs_undefined_instance_variable).should be_nil
+ defined?(not @defined_specs_undefined_instance_variable).should == nil
end
it "returns 'expression' for an expression with '&&/and' and an undefined method" do
@@ -524,12 +540,12 @@ describe "The defined? keyword for an expression" do
it "does not call a method in an '&&' expression and returns 'expression'" do
defined?(DefinedSpecs.side_effects && true).should == "expression"
- ScratchPad.recorded.should be_nil
+ ScratchPad.recorded.should == nil
end
it "does not call a method in an 'and' expression and returns 'expression'" do
defined?(DefinedSpecs.side_effects and true).should == "expression"
- ScratchPad.recorded.should be_nil
+ ScratchPad.recorded.should == nil
end
it "returns 'expression' for an expression with '||/or' and an undefined method" do
@@ -544,12 +560,12 @@ describe "The defined? keyword for an expression" do
it "does not call a method in an '||' expression and returns 'expression'" do
defined?(DefinedSpecs.side_effects || true).should == "expression"
- ScratchPad.recorded.should be_nil
+ ScratchPad.recorded.should == nil
end
it "does not call a method in an 'or' expression and returns 'expression'" do
defined?(DefinedSpecs.side_effects or true).should == "expression"
- ScratchPad.recorded.should be_nil
+ ScratchPad.recorded.should == nil
end
end
@@ -572,7 +588,7 @@ describe "The defined? keyword for an expression" do
it "does not call the method in the String" do
defined?("garble #{DefinedSpecs.dynamic_string}").should == "expression"
- ScratchPad.recorded.should be_nil
+ ScratchPad.recorded.should == nil
end
end
@@ -591,7 +607,7 @@ describe "The defined? keyword for an expression" do
it "does not call the method in the Regexp" do
defined?(/garble #{DefinedSpecs.dynamic_string}/).should == "expression"
- ScratchPad.recorded.should be_nil
+ ScratchPad.recorded.should == nil
end
end
@@ -640,11 +656,11 @@ describe "The defined? keyword for variables" do
end
it "returns nil for an instance variable that has not been read" do
- DefinedSpecs::Basic.new.instance_variable_undefined.should be_nil
+ DefinedSpecs::Basic.new.instance_variable_undefined.should == nil
end
it "returns nil for an instance variable that has been read but not assigned to" do
- DefinedSpecs::Basic.new.instance_variable_read.should be_nil
+ DefinedSpecs::Basic.new.instance_variable_read.should == nil
end
it "returns 'instance-variable' for an instance variable that has been assigned" do
@@ -658,11 +674,11 @@ describe "The defined? keyword for variables" do
end
it "returns nil for a global variable that has not been read" do
- DefinedSpecs::Basic.new.global_variable_undefined.should be_nil
+ DefinedSpecs::Basic.new.global_variable_undefined.should == nil
end
it "returns nil for a global variable that has been read but not assigned to" do
- DefinedSpecs::Basic.new.global_variable_read.should be_nil
+ DefinedSpecs::Basic.new.global_variable_read.should == nil
end
it "returns 'global-variable' for a global variable that has been assigned nil" do
@@ -694,27 +710,27 @@ describe "The defined? keyword for variables" do
end
it "returns nil for $&" do
- defined?($&).should be_nil
+ defined?($&).should == nil
end
it "returns nil for $`" do
- defined?($`).should be_nil
+ defined?($`).should == nil
end
it "returns nil for $'" do
- defined?($').should be_nil
+ defined?($').should == nil
end
it "returns nil for $+" do
- defined?($+).should be_nil
+ defined?($+).should == nil
end
it "returns nil for any last match global" do
- defined?($1).should be_nil
- defined?($4).should be_nil
- defined?($7).should be_nil
- defined?($10).should be_nil
- defined?($200).should be_nil
+ defined?($1).should == nil
+ defined?($4).should == nil
+ defined?($7).should == nil
+ defined?($10).should == nil
+ defined?($200).should == nil
end
end
@@ -749,10 +765,10 @@ describe "The defined? keyword for variables" do
end
it "returns nil for non-captures" do
- defined?($4).should be_nil
- defined?($7).should be_nil
- defined?($10).should be_nil
- defined?($200).should be_nil
+ defined?($4).should == nil
+ defined?($7).should == nil
+ defined?($10).should == nil
+ defined?($200).should == nil
end
end
@@ -766,27 +782,27 @@ describe "The defined? keyword for variables" do
end
it "returns nil for $&" do
- defined?($&).should be_nil
+ defined?($&).should == nil
end
it "returns nil for $`" do
- defined?($`).should be_nil
+ defined?($`).should == nil
end
it "returns nil for $'" do
- defined?($').should be_nil
+ defined?($').should == nil
end
it "returns nil for $+" do
- defined?($+).should be_nil
+ defined?($+).should == nil
end
it "returns nil for any last match global" do
- defined?($1).should be_nil
- defined?($4).should be_nil
- defined?($7).should be_nil
- defined?($10).should be_nil
- defined?($200).should be_nil
+ defined?($1).should == nil
+ defined?($4).should == nil
+ defined?($7).should == nil
+ defined?($10).should == nil
+ defined?($200).should == nil
end
end
@@ -821,10 +837,10 @@ describe "The defined? keyword for variables" do
end
it "returns nil for non-captures" do
- defined?($4).should be_nil
- defined?($7).should be_nil
- defined?($10).should be_nil
- defined?($200).should be_nil
+ defined?($4).should == nil
+ defined?($7).should == nil
+ defined?($10).should == nil
+ defined?($200).should == nil
end
end
it "returns 'global-variable' for a global variable that has been assigned" do
@@ -832,7 +848,7 @@ describe "The defined? keyword for variables" do
end
it "returns nil for a class variable that has not been read" do
- DefinedSpecs::Basic.new.class_variable_undefined.should be_nil
+ DefinedSpecs::Basic.new.class_variable_undefined.should == nil
end
# There is no spec for a class variable that is read before being assigned
@@ -859,12 +875,12 @@ describe "The defined? keyword for a simple constant" do
end
it "returns nil when the constant is not defined" do
- defined?(DefinedSpecsUndefined).should be_nil
+ defined?(DefinedSpecsUndefined).should == nil
end
it "does not call Object.const_missing if the constant is not defined" do
Object.should_not_receive(:const_missing)
- defined?(DefinedSpecsUndefined).should be_nil
+ defined?(DefinedSpecsUndefined).should == nil
end
it "returns 'constant' for an included module" do
@@ -882,12 +898,12 @@ describe "The defined? keyword for a top-level constant" do
end
it "returns nil if the constant is not defined" do
- defined?(::DefinedSpecsUndefined).should be_nil
+ defined?(::DefinedSpecsUndefined).should == nil
end
it "does not call Object.const_missing if the constant is not defined" do
Object.should_not_receive(:const_missing)
- defined?(::DefinedSpecsUndefined).should be_nil
+ defined?(::DefinedSpecsUndefined).should == nil
end
end
@@ -897,37 +913,37 @@ describe "The defined? keyword for a scoped constant" do
end
it "returns nil when the scoped constant is not defined" do
- defined?(DefinedSpecs::Undefined).should be_nil
+ defined?(DefinedSpecs::Undefined).should == nil
end
it "returns nil when the constant is not defined and the outer module implements .const_missing" do
- defined?(DefinedSpecs::ModuleWithConstMissing::Undefined).should be_nil
+ defined?(DefinedSpecs::ModuleWithConstMissing::Undefined).should == nil
end
it "does not call .const_missing if the constant is not defined" do
DefinedSpecs.should_not_receive(:const_missing)
- defined?(DefinedSpecs::UnknownChild).should be_nil
+ defined?(DefinedSpecs::UnknownChild).should == nil
end
it "returns nil when an undefined constant is scoped to a defined constant" do
- defined?(DefinedSpecs::Child::Undefined).should be_nil
+ defined?(DefinedSpecs::Child::Undefined).should == nil
end
it "returns nil when a constant is scoped to an undefined constant" do
Object.should_not_receive(:const_missing)
- defined?(Undefined::Object).should be_nil
+ defined?(Undefined::Object).should == nil
end
it "returns nil when the undefined constant is scoped to an undefined constant" do
- defined?(DefinedSpecs::Undefined::Undefined).should be_nil
+ defined?(DefinedSpecs::Undefined::Undefined).should == nil
end
it "returns nil when a constant is defined on top-level but not on the module" do
- defined?(DefinedSpecs::String).should be_nil
+ defined?(DefinedSpecs::String).should == nil
end
it "returns nil when a constant is defined on top-level but not on the class" do
- defined?(DefinedSpecs::Basic::String).should be_nil
+ defined?(DefinedSpecs::Basic::String).should == nil
end
it "returns 'constant' if the scoped-scoped constant is defined" do
@@ -941,15 +957,15 @@ describe "The defined? keyword for a top-level scoped constant" do
end
it "returns nil when the scoped constant is not defined" do
- defined?(::DefinedSpecs::Undefined).should be_nil
+ defined?(::DefinedSpecs::Undefined).should == nil
end
it "returns nil when an undefined constant is scoped to a defined constant" do
- defined?(::DefinedSpecs::Child::Undefined).should be_nil
+ defined?(::DefinedSpecs::Child::Undefined).should == nil
end
it "returns nil when the undefined constant is scoped to an undefined constant" do
- defined?(::DefinedSpecs::Undefined::Undefined).should be_nil
+ defined?(::DefinedSpecs::Undefined::Undefined).should == nil
end
it "returns 'constant' if the scoped-scoped constant is defined" do
@@ -959,7 +975,7 @@ end
describe "The defined? keyword for a self-send method call scoped constant" do
it "returns nil if the constant is not defined in the scope of the method's value" do
- defined?(defined_specs_method::Undefined).should be_nil
+ defined?(defined_specs_method::Undefined).should == nil
end
it "returns 'constant' if the constant is defined in the scope of the method's value" do
@@ -967,11 +983,11 @@ describe "The defined? keyword for a self-send method call scoped constant" do
end
it "returns nil if the last constant is not defined in the scope chain" do
- defined?(defined_specs_method::Basic::Undefined).should be_nil
+ defined?(defined_specs_method::Basic::Undefined).should == nil
end
it "returns nil if the middle constant is not defined in the scope chain" do
- defined?(defined_specs_method::Undefined::Undefined).should be_nil
+ defined?(defined_specs_method::Undefined::Undefined).should == nil
end
it "returns 'constant' if all the constants in the scope chain are defined" do
@@ -981,7 +997,7 @@ end
describe "The defined? keyword for a receiver method call scoped constant" do
it "returns nil if the constant is not defined in the scope of the method's value" do
- defined?(defined_specs_receiver.defined_method::Undefined).should be_nil
+ defined?(defined_specs_receiver.defined_method::Undefined).should == nil
end
it "returns 'constant' if the constant is defined in the scope of the method's value" do
@@ -989,11 +1005,11 @@ describe "The defined? keyword for a receiver method call scoped constant" do
end
it "returns nil if the last constant is not defined in the scope chain" do
- defined?(defined_specs_receiver.defined_method::Basic::Undefined).should be_nil
+ defined?(defined_specs_receiver.defined_method::Basic::Undefined).should == nil
end
it "returns nil if the middle constant is not defined in the scope chain" do
- defined?(defined_specs_receiver.defined_method::Undefined::Undefined).should be_nil
+ defined?(defined_specs_receiver.defined_method::Undefined::Undefined).should == nil
end
it "returns 'constant' if all the constants in the scope chain are defined" do
@@ -1003,7 +1019,7 @@ end
describe "The defined? keyword for a module method call scoped constant" do
it "returns nil if the constant is not defined in the scope of the method's value" do
- defined?(DefinedSpecs.defined_method::Undefined).should be_nil
+ defined?(DefinedSpecs.defined_method::Undefined).should == nil
end
it "returns 'constant' if the constant scoped by the method's value is defined" do
@@ -1011,11 +1027,11 @@ describe "The defined? keyword for a module method call scoped constant" do
end
it "returns nil if the last constant in the scope chain is not defined" do
- defined?(DefinedSpecs.defined_method::Basic::Undefined).should be_nil
+ defined?(DefinedSpecs.defined_method::Basic::Undefined).should == nil
end
it "returns nil if the middle constant in the scope chain is not defined" do
- defined?(DefinedSpecs.defined_method::Undefined::Undefined).should be_nil
+ defined?(DefinedSpecs.defined_method::Undefined::Undefined).should == nil
end
it "returns 'constant' if all the constants in the scope chain are defined" do
@@ -1023,11 +1039,11 @@ describe "The defined? keyword for a module method call scoped constant" do
end
it "returns nil if the outer scope constant in the receiver is not defined" do
- defined?(Undefined::DefinedSpecs.defined_method::Basic).should be_nil
+ defined?(Undefined::DefinedSpecs.defined_method::Basic).should == nil
end
it "returns nil if the scoped constant in the receiver is not defined" do
- defined?(DefinedSpecs::Undefined.defined_method::Basic).should be_nil
+ defined?(DefinedSpecs::Undefined.defined_method::Basic).should == nil
end
it "returns 'constant' if all the constants in the receiver are defined" do
@@ -1048,7 +1064,7 @@ describe "The defined? keyword for a variable scoped constant" do
it "returns nil if the instance scoped constant is not defined" do
@defined_specs_obj = DefinedSpecs::Basic
- defined?(@defined_specs_obj::Undefined).should be_nil
+ defined?(@defined_specs_obj::Undefined).should == nil
end
it "returns 'constant' if the constant is defined in the scope of the instance variable" do
@@ -1058,7 +1074,7 @@ describe "The defined? keyword for a variable scoped constant" do
it "returns nil if the global scoped constant is not defined" do
$defined_specs_obj = DefinedSpecs::Basic
- defined?($defined_specs_obj::Undefined).should be_nil
+ defined?($defined_specs_obj::Undefined).should == nil
end
it "returns 'constant' if the constant is defined in the scope of the global variable" do
@@ -1070,7 +1086,7 @@ describe "The defined? keyword for a variable scoped constant" do
eval(<<-END, binding, __FILE__, __LINE__)
class singleton_class::A
@@defined_specs_obj = DefinedSpecs::Basic
- defined?(@@defined_specs_obj::Undefined).should be_nil
+ defined?(@@defined_specs_obj::Undefined).should == nil
end
END
end
@@ -1086,7 +1102,7 @@ describe "The defined? keyword for a variable scoped constant" do
it "returns nil if the local scoped constant is not defined" do
defined_specs_obj = DefinedSpecs::Basic
- defined?(defined_specs_obj::Undefined).should be_nil
+ defined?(defined_specs_obj::Undefined).should == nil
end
it "returns 'constant' if the constant is defined in the scope of the local variable" do
@@ -1107,11 +1123,11 @@ end
describe "The defined? keyword for yield" do
it "returns nil if no block is passed to a method not taking a block parameter" do
- DefinedSpecs::Basic.new.no_yield_block.should be_nil
+ DefinedSpecs::Basic.new.no_yield_block.should == nil
end
it "returns nil if no block is passed to a method taking a block parameter" do
- DefinedSpecs::Basic.new.no_yield_block_parameter.should be_nil
+ DefinedSpecs::Basic.new.no_yield_block_parameter.should == nil
end
it "returns 'yield' if a block is passed to a method not taking a block parameter" do
@@ -1139,24 +1155,24 @@ end
describe "The defined? keyword for super" do
it "returns nil when a superclass undef's the method" do
- DefinedSpecs::ClassWithoutMethod.new.test.should be_nil
+ DefinedSpecs::ClassWithoutMethod.new.test.should == nil
end
describe "for a method taking no arguments" do
it "returns nil when no superclass method exists" do
- DefinedSpecs::Super.new.no_super_method_no_args.should be_nil
+ DefinedSpecs::Super.new.no_super_method_no_args.should == nil
end
it "returns nil from a block when no superclass method exists" do
- DefinedSpecs::Super.new.no_super_method_block_no_args.should be_nil
+ DefinedSpecs::Super.new.no_super_method_block_no_args.should == nil
end
it "returns nil from a #define_method when no superclass method exists" do
- DefinedSpecs::Super.new.no_super_define_method_no_args.should be_nil
+ DefinedSpecs::Super.new.no_super_define_method_no_args.should == nil
end
it "returns nil from a block in a #define_method when no superclass method exists" do
- DefinedSpecs::Super.new.no_super_define_method_block_no_args.should be_nil
+ DefinedSpecs::Super.new.no_super_define_method_block_no_args.should == nil
end
it "returns 'super' when a superclass method exists" do
@@ -1184,19 +1200,19 @@ describe "The defined? keyword for super" do
describe "for a method taking arguments" do
it "returns nil when no superclass method exists" do
- DefinedSpecs::Super.new.no_super_method_args.should be_nil
+ DefinedSpecs::Super.new.no_super_method_args.should == nil
end
it "returns nil from a block when no superclass method exists" do
- DefinedSpecs::Super.new.no_super_method_block_args.should be_nil
+ DefinedSpecs::Super.new.no_super_method_block_args.should == nil
end
it "returns nil from a #define_method when no superclass method exists" do
- DefinedSpecs::Super.new.no_super_define_method_args.should be_nil
+ DefinedSpecs::Super.new.no_super_define_method_args.should == nil
end
it "returns nil from a block in a #define_method when no superclass method exists" do
- DefinedSpecs::Super.new.no_super_define_method_block_args.should be_nil
+ DefinedSpecs::Super.new.no_super_define_method_block_args.should == nil
end
it "returns 'super' when a superclass method exists" do
@@ -1231,7 +1247,7 @@ describe "The defined? keyword for instance variables" do
end
it "returns nil if not assigned" do
- defined?(@unassigned_ivar).should be_nil
+ defined?(@unassigned_ivar).should == nil
end
end
diff --git a/spec/ruby/language/delegation_spec.rb b/spec/ruby/language/delegation_spec.rb
index c711a536c2..efcf37aabc 100644
--- a/spec/ruby/language/delegation_spec.rb
+++ b/spec/ruby/language/delegation_spec.rb
@@ -37,6 +37,16 @@ describe "delegation with def(...)" do
a.new.delegate(1, b: 2, &block).should == [[1], {b: 2}, block]
end
+ it "delegates with additional arguments" do
+ a = Class.new(DelegationSpecs::Target)
+ a.class_eval(<<-RUBY)
+ def delegate(...)
+ target(:first, :second, ...)
+ end
+ RUBY
+ a.new.delegate(1, b: 2).should == [[:first, :second, 1], {b: 2}, nil]
+ end
+
it "parses as open endless Range when brackets are omitted" do
a = Class.new(DelegationSpecs::Target)
suppress_warning do
@@ -49,6 +59,20 @@ describe "delegation with def(...)" do
a.new.delegate(1, b: 2).should == Range.new([[], {}, nil], nil, true)
end
+
+ it "passes non-keyword trailing hash through without modification" do
+ a = Class.new(DelegationSpecs::Target)
+ a.class_eval(<<-RUBY)
+ def delegate(...)
+ target_single(...)
+ end
+ RUBY
+
+ h = {a:1}
+ h.freeze
+ h2 = a.new.delegate(h)
+ h2.should.equal?(h)
+ end
end
describe "delegation with def(x, ...)" do
@@ -99,13 +123,11 @@ describe "delegation with def(*)" do
a.new.delegate(0, 1).should == [[0, 1], {}, nil]
end
- ruby_version_is "3.3" do
- context "within a block that accepts anonymous rest within a method that accepts anonymous rest" do
- it "does not allow delegating rest" do
- -> {
- eval "def m(*); proc { |*| n(*) } end"
- }.should raise_error(SyntaxError, /anonymous rest parameter is also used within block/)
- end
+ context "within a block that accepts anonymous rest within a method that accepts anonymous rest" do
+ it "does not allow delegating rest" do
+ -> {
+ eval "def m(*); proc { |*| n(*) } end"
+ }.should.raise(SyntaxError, /anonymous rest parameter is also used within block/)
end
end
end
@@ -122,13 +144,11 @@ describe "delegation with def(**)" do
a.new.delegate(a: 1) { |x| x }.should == [[], {a: 1}, nil]
end
- ruby_version_is "3.3" do
- context "within a block that accepts anonymous kwargs within a method that accepts anonymous kwargs" do
- it "does not allow delegating kwargs" do
- -> {
- eval "def m(**); proc { |**| n(**) } end"
- }.should raise_error(SyntaxError, /anonymous keyword rest parameter is also used within block/)
- end
+ context "within a block that accepts anonymous kwargs within a method that accepts anonymous kwargs" do
+ it "does not allow delegating kwargs" do
+ -> {
+ eval "def m(**); proc { |**| n(**) } end"
+ }.should.raise(SyntaxError, /anonymous keyword rest parameter is also used within block/)
end
end
end
@@ -146,13 +166,11 @@ describe "delegation with def(&)" do
a.new.delegate(&block).should == [[], {}, block]
end
- ruby_version_is "3.3" do
- context "within a block that accepts anonymous block within a method that accepts anonymous block" do
- it "does not allow delegating a block" do
- -> {
- eval "def m(&); proc { |&| n(&) } end"
- }.should raise_error(SyntaxError, /anonymous block parameter is also used within block/)
- end
+ context "within a block that accepts anonymous block within a method that accepts anonymous block" do
+ it "does not allow delegating a block" do
+ -> {
+ eval "def m(&); proc { |&| n(&) } end"
+ }.should.raise(SyntaxError, /anonymous block parameter is also used within block/)
end
end
end
diff --git a/spec/ruby/language/encoding_spec.rb b/spec/ruby/language/encoding_spec.rb
index e761a53cb6..116f53a77d 100644
--- a/spec/ruby/language/encoding_spec.rb
+++ b/spec/ruby/language/encoding_spec.rb
@@ -5,7 +5,7 @@ require_relative 'fixtures/coding_utf_8'
describe "The __ENCODING__ pseudo-variable" do
it "is an instance of Encoding" do
- __ENCODING__.should be_kind_of(Encoding)
+ __ENCODING__.should.is_a?(Encoding)
end
it "is US-ASCII by default" do
@@ -31,6 +31,6 @@ describe "The __ENCODING__ pseudo-variable" do
end
it "raises a SyntaxError if assigned to" do
- -> { eval("__ENCODING__ = 1") }.should raise_error(SyntaxError)
+ -> { eval("__ENCODING__ = 1") }.should.raise(SyntaxError)
end
end
diff --git a/spec/ruby/language/ensure_spec.rb b/spec/ruby/language/ensure_spec.rb
index b76292c007..04ff0305ab 100644
--- a/spec/ruby/language/ensure_spec.rb
+++ b/spec/ruby/language/ensure_spec.rb
@@ -6,7 +6,7 @@ describe "An ensure block inside a begin block" do
ScratchPad.record []
end
- it "is executed when an exception is raised in it's corresponding begin block" do
+ it "is executed when an exception is raised in its corresponding begin block" do
-> {
begin
ScratchPad << :begin
@@ -14,12 +14,12 @@ describe "An ensure block inside a begin block" do
ensure
ScratchPad << :ensure
end
- }.should raise_error(EnsureSpec::Error)
+ }.should.raise(EnsureSpec::Error)
ScratchPad.recorded.should == [:begin, :ensure]
end
- it "is executed when an exception is raised and rescued in it's corresponding begin block" do
+ it "is executed when an exception is raised and rescued in its corresponding begin block" do
begin
ScratchPad << :begin
raise "An exception occurred!"
@@ -32,7 +32,7 @@ describe "An ensure block inside a begin block" do
ScratchPad.recorded.should == [:begin, :rescue, :ensure]
end
- it "is executed even when a symbol is thrown in it's corresponding begin block" do
+ it "is executed even when a symbol is thrown in its corresponding begin block" do
catch(:symbol) do
begin
ScratchPad << :begin
@@ -47,7 +47,7 @@ describe "An ensure block inside a begin block" do
ScratchPad.recorded.should == [:begin, :ensure]
end
- it "is executed when nothing is raised or thrown in it's corresponding begin block" do
+ it "is executed when nothing is raised or thrown in its corresponding begin block" do
begin
ScratchPad << :begin
rescue
@@ -74,7 +74,7 @@ describe "An ensure block inside a begin block" do
ensure
raise "from ensure"
end
- }.should raise_error(RuntimeError, "from ensure") { |e|
+ }.should.raise(RuntimeError, "from ensure") { |e|
e.cause.message.should == "from block"
}
end
@@ -108,7 +108,7 @@ describe "An ensure block inside a method" do
end
it "is executed when an exception is raised in the method" do
- -> { @obj.raise_in_method_with_ensure }.should raise_error(EnsureSpec::Error)
+ -> { @obj.raise_in_method_with_ensure }.should.raise(EnsureSpec::Error)
@obj.executed.should == [:method, :ensure]
end
@@ -149,13 +149,13 @@ describe "An ensure block inside a method" do
it "overrides exception raised in rescue if raises exception itself" do
-> {
@obj.raise_in_rescue_and_raise_in_ensure
- }.should raise_error(RuntimeError, "raised in ensure")
+ }.should.raise(RuntimeError, "raised in ensure")
end
it "suppresses exception raised in method if raises exception itself" do
-> {
@obj.raise_in_method_and_raise_in_ensure
- }.should raise_error(RuntimeError, "raised in ensure")
+ }.should.raise(RuntimeError, "raised in ensure")
end
end
@@ -174,7 +174,7 @@ describe "An ensure block inside a class" do
ScratchPad << :ensure
end
ruby
- }.should raise_error(EnsureSpec::Error)
+ }.should.raise(EnsureSpec::Error)
ScratchPad.recorded.should == [:class, :ensure]
end
@@ -247,7 +247,7 @@ describe "An ensure block inside {} block" do
ensure
}
ruby
- }.should raise_error(SyntaxError)
+ }.should.raise(SyntaxError)
end
end
@@ -256,7 +256,7 @@ describe "An ensure block inside 'do end' block" do
ScratchPad.record []
end
- it "is executed when an exception is raised in it's corresponding begin block" do
+ it "is executed when an exception is raised in its corresponding begin block" do
-> {
eval(<<-ruby).call
lambda do
@@ -266,12 +266,12 @@ describe "An ensure block inside 'do end' block" do
ScratchPad << :ensure
end
ruby
- }.should raise_error(EnsureSpec::Error)
+ }.should.raise(EnsureSpec::Error)
ScratchPad.recorded.should == [:begin, :ensure]
end
- it "is executed when an exception is raised and rescued in it's corresponding begin block" do
+ it "is executed when an exception is raised and rescued in its corresponding begin block" do
eval(<<-ruby).call
lambda do
ScratchPad << :begin
@@ -286,7 +286,7 @@ describe "An ensure block inside 'do end' block" do
ScratchPad.recorded.should == [:begin, :rescue, :ensure]
end
- it "is executed even when a symbol is thrown in it's corresponding begin block" do
+ it "is executed even when a symbol is thrown in its corresponding begin block" do
catch(:symbol) do
eval(<<-ruby).call
lambda do
@@ -303,7 +303,7 @@ describe "An ensure block inside 'do end' block" do
ScratchPad.recorded.should == [:begin, :ensure]
end
- it "is executed when nothing is raised or thrown in it's corresponding begin block" do
+ it "is executed when nothing is raised or thrown in its corresponding begin block" do
eval(<<-ruby).call
lambda do
ScratchPad << :begin
diff --git a/spec/ruby/language/file_spec.rb b/spec/ruby/language/file_spec.rb
index 59563d9642..dd89ce2385 100644
--- a/spec/ruby/language/file_spec.rb
+++ b/spec/ruby/language/file_spec.rb
@@ -4,19 +4,11 @@ require_relative 'shared/__FILE__'
describe "The __FILE__ pseudo-variable" do
it "raises a SyntaxError if assigned to" do
- -> { eval("__FILE__ = 1") }.should raise_error(SyntaxError)
+ -> { eval("__FILE__ = 1") }.should.raise(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 at __FILE__:__LINE__) inside an eval" do
+ eval("__FILE__").should == "(eval at #{__FILE__}:#{__LINE__})"
end
end
diff --git a/spec/ruby/language/fixtures/defined.rb b/spec/ruby/language/fixtures/defined.rb
index 3761cfa5bd..15bd7c50cf 100644
--- a/spec/ruby/language/fixtures/defined.rb
+++ b/spec/ruby/language/fixtures/defined.rb
@@ -299,6 +299,33 @@ module DefinedSpecs
super
end
end
+
+ class ProtectedBase
+ def m; end
+ protected :m
+ def defined_on(o)
+ defined?(o.m)
+ end
+ end
+
+ class ProtectedSubclass < ProtectedBase
+ end
+
+ module ProtectedInModule
+ def m; end
+ protected :m
+ def defined_on(o)
+ defined?(o.m)
+ end
+ end
+
+ class ProtectedIncluderA
+ include ProtectedInModule
+ end
+
+ class ProtectedIncluderB
+ include ProtectedInModule
+ end
end
class Object
diff --git a/spec/ruby/language/fixtures/delegation.rb b/spec/ruby/language/fixtures/delegation.rb
index da2b024791..049a923e66 100644
--- a/spec/ruby/language/fixtures/delegation.rb
+++ b/spec/ruby/language/fixtures/delegation.rb
@@ -7,5 +7,9 @@ module DelegationSpecs
def target_block(*args, **kwargs)
yield [kwargs, args]
end
+
+ def target_single(arg)
+ arg
+ end
end
end
diff --git a/spec/ruby/language/fixtures/freeze_magic_comment_across_files.rb b/spec/ruby/language/fixtures/freeze_magic_comment_across_files.rb
index 3aed2f29b6..f3ef666a3c 100644
--- a/spec/ruby/language/fixtures/freeze_magic_comment_across_files.rb
+++ b/spec/ruby/language/fixtures/freeze_magic_comment_across_files.rb
@@ -2,4 +2,5 @@
require_relative 'freeze_magic_comment_required'
-p "abc".object_id == $second_literal_id
+p "abc".equal?($second_literal)
+$second_literal = nil
diff --git a/spec/ruby/language/fixtures/freeze_magic_comment_across_files_diff_enc.rb b/spec/ruby/language/fixtures/freeze_magic_comment_across_files_diff_enc.rb
index 53ef959970..e9ca35e7c8 100644
--- a/spec/ruby/language/fixtures/freeze_magic_comment_across_files_diff_enc.rb
+++ b/spec/ruby/language/fixtures/freeze_magic_comment_across_files_diff_enc.rb
@@ -2,4 +2,5 @@
require_relative 'freeze_magic_comment_required_diff_enc'
-p "abc".object_id != $second_literal_id
+p !"abc".equal?($second_literal)
+$second_literal = nil
diff --git a/spec/ruby/language/fixtures/freeze_magic_comment_across_files_no_comment.rb b/spec/ruby/language/fixtures/freeze_magic_comment_across_files_no_comment.rb
index fc6cd5bf82..c9eaab46a2 100644
--- a/spec/ruby/language/fixtures/freeze_magic_comment_across_files_no_comment.rb
+++ b/spec/ruby/language/fixtures/freeze_magic_comment_across_files_no_comment.rb
@@ -2,4 +2,5 @@
require_relative 'freeze_magic_comment_required_no_comment'
-p "abc".object_id != $second_literal_id
+p !"abc".equal?($second_literal)
+$second_literal = nil
diff --git a/spec/ruby/language/fixtures/freeze_magic_comment_one_literal.rb b/spec/ruby/language/fixtures/freeze_magic_comment_one_literal.rb
index d35905b332..c175b2b7a2 100644
--- a/spec/ruby/language/fixtures/freeze_magic_comment_one_literal.rb
+++ b/spec/ruby/language/fixtures/freeze_magic_comment_one_literal.rb
@@ -1,4 +1,4 @@
# frozen_string_literal: true
-ids = Array.new(2) { "abc".object_id }
-p ids.first == ids.last
+objs = Array.new(2) { "abc" }
+p objs.first.equal?(objs.last)
diff --git a/spec/ruby/language/fixtures/freeze_magic_comment_required.rb b/spec/ruby/language/fixtures/freeze_magic_comment_required.rb
index a4ff4459b1..f75acb2ce3 100644
--- a/spec/ruby/language/fixtures/freeze_magic_comment_required.rb
+++ b/spec/ruby/language/fixtures/freeze_magic_comment_required.rb
@@ -1,3 +1,3 @@
# frozen_string_literal: true
-$second_literal_id = "abc".object_id
+$second_literal = "abc"
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..739e96e99a 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
@@ -1,4 +1,4 @@
# encoding: euc-jp # built-in for old regexp option
# frozen_string_literal: true
-$second_literal_id = "abc".object_id
+$second_literal = "abc"
diff --git a/spec/ruby/language/fixtures/freeze_magic_comment_required_no_comment.rb b/spec/ruby/language/fixtures/freeze_magic_comment_required_no_comment.rb
index e09232a5f4..6fbe175b42 100644
--- a/spec/ruby/language/fixtures/freeze_magic_comment_required_no_comment.rb
+++ b/spec/ruby/language/fixtures/freeze_magic_comment_required_no_comment.rb
@@ -1 +1 @@
-$second_literal_id = "abc".object_id
+$second_literal = "abc"
diff --git a/spec/ruby/language/fixtures/module.rb b/spec/ruby/language/fixtures/module.rb
index 33d323846e..75eee77791 100644
--- a/spec/ruby/language/fixtures/module.rb
+++ b/spec/ruby/language/fixtures/module.rb
@@ -12,13 +12,4 @@ module ModuleSpecs
module Anonymous
end
-
- module IncludedInObject
- module IncludedModuleSpecs
- end
- end
-end
-
-class Object
- include ModuleSpecs::IncludedInObject
end
diff --git a/spec/ruby/language/fixtures/send.rb b/spec/ruby/language/fixtures/send.rb
index 5d1d9da214..4787abee5c 100644
--- a/spec/ruby/language/fixtures/send.rb
+++ b/spec/ruby/language/fixtures/send.rb
@@ -81,6 +81,16 @@ module LangSendSpecs
end
end
+ class RawToProc
+ def initialize(to_proc)
+ @to_proc = to_proc
+ end
+
+ def to_proc
+ @to_proc
+ end
+ end
+
class ToAry
def initialize(obj)
@obj = obj
diff --git a/spec/ruby/language/fixtures/super.rb b/spec/ruby/language/fixtures/super.rb
index c5bdcf0e40..b6d4218b03 100644
--- a/spec/ruby/language/fixtures/super.rb
+++ b/spec/ruby/language/fixtures/super.rb
@@ -266,7 +266,7 @@ module SuperSpecs
# Use this so that we can see collect all supers that we see.
# One bug that arises is that we call Alias2#name from Alias2#name
- # as it's superclass. In that case, either we get a runaway recursion
+ # as its superclass. In that case, either we get a runaway recursion
# super OR we get the return value being [:alias2, :alias2, :alias1]
# rather than [:alias2, :alias1].
#
diff --git a/spec/ruby/language/for_spec.rb b/spec/ruby/language/for_spec.rb
index b8ddfe5f0d..b0f3aef405 100644
--- a/spec/ruby/language/for_spec.rb
+++ b/spec/ruby/language/for_spec.rb
@@ -129,37 +129,34 @@ describe "The for expression" do
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
+ it "allows an attribute with safe navigation as an iterator name" do
+ class OFor
+ attr_accessor :target
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
+ 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 == nil
+ n.should == 3
end
it "allows an array index writer as an iterator name" do
@@ -218,7 +215,15 @@ describe "The for expression" do
j.should == 6
end
- it "executes code in containing variable scope" do
+ it "declares iteration variables in the surrounding variable scope" do
+ for a, b in [[1,2]]
+ end
+
+ a.should == 1
+ b.should == 2
+ end
+
+ it "declares variables in the body in the surrounding variable scope" do
for i in 1..2
a = 123
end
@@ -226,7 +231,7 @@ describe "The for expression" do
a.should == 123
end
- it "executes code in containing variable scope with 'do'" do
+ it "declares variables in the body in the surrounding variable scope with 'do'" do
for i in 1..2 do
a = 123
end
@@ -234,6 +239,96 @@ describe "The for expression" do
a.should == 123
end
+ it "declares variables inside a block as normal" do
+ for i in 1..2 do
+ proc {
+ inside_proc = 42
+ }.call
+ end
+ local_variables.should == [:i]
+ end
+
+ it "declares variables inside a lambda as normal" do
+ for i in 1..2 do
+ -> {
+ inside_proc = 42
+ }.call
+ end
+ local_variables.should == [:i]
+ end
+
+ it "can be nested" do
+ for a in [6]
+ for b in [7]
+ c = a * b
+ end
+ end
+ local_variables.sort.should == [:a, :b, :c]
+ c.should == 42
+ end
+
+ it "can be nested with blocks in between" do
+ # This is an edge case spec for Ruby implementations which have
+ # their own runtime scope per for loop body (like YARV and TruffleRuby)
+ for a in [1]
+ a1 = a
+ a1.should == a
+ for b in [2]
+ b1 = b
+ a1.should == a
+ b1.should == b
+ proc {
+ inside_proc = 42
+
+ a1.should == a
+ b1.should == b
+ inside_proc.should == 42
+
+ for c in [3].map { |enum_var|
+ a1.should == a
+ b1.should == b
+ inside_proc.should == 42
+ enum_var
+ }
+ c1 = c
+
+ a1.should == a
+ b1.should == b
+ c1.should == c
+ inside_proc.should == 42
+
+ for d in [4]
+ d1 = d
+
+ a1.should == a
+ b1.should == b
+ c1.should == c
+ d1.should == d
+ inside_proc.should == 42
+ end
+ end
+ local_variables.sort.should == [:a, :a1, :b, :b1, :c, :c1, :d, :d1, :inside_proc]
+ }.call
+ end
+ end
+ local_variables.sort.should == [:a, :a1, :b, :b1]
+ end
+
+ it "can be nested with forward arguments" do
+ def bar(*args)
+ args
+ end
+
+ def foo(...)
+ for a in [1]
+ r = bar(...)
+ end
+ r
+ end
+
+ foo(2, 3).should == [2, 3]
+ end
+
it "does not try to access variables outside the method" do
ForSpecs::ForInClassMethod.foo.should == [:bar, :baz]
ForSpecs::ForInClassMethod::READER.call.should == :same_variable_set_outside
diff --git a/spec/ruby/language/hash_spec.rb b/spec/ruby/language/hash_spec.rb
index 668716e2e3..7a4a2e37c9 100644
--- a/spec/ruby/language/hash_spec.rb
+++ b/spec/ruby/language/hash_spec.rb
@@ -81,7 +81,7 @@ describe "Hash literal" do
end
it "with '==>' in the middle raises SyntaxError" do
- -> { eval("{:a ==> 1}") }.should raise_error(SyntaxError)
+ -> { eval("{:a ==> 1}") }.should.raise(SyntaxError)
end
it "recognizes '!' at the end of the key" do
@@ -93,7 +93,7 @@ describe "Hash literal" do
end
it "raises a SyntaxError if there is no space between `!` and `=>`" do
- -> { eval("{:a!=> 1}") }.should raise_error(SyntaxError)
+ -> { eval("{:a!=> 1}") }.should.raise(SyntaxError)
end
it "recognizes '?' at the end of the key" do
@@ -105,7 +105,7 @@ describe "Hash literal" do
end
it "raises a SyntaxError if there is no space between `?` and `=>`" do
- -> { eval("{:a?=> 1}") }.should raise_error(SyntaxError)
+ -> { eval("{:a?=> 1}") }.should.raise(SyntaxError)
end
it "constructs a new hash with the given elements" do
@@ -152,9 +152,9 @@ describe "Hash literal" do
ruby_version_is ""..."3.4" do
it "does not expand nil using ** into {} and raises TypeError" do
h = nil
- -> { {a: 1, **h} }.should raise_error(TypeError, "no implicit conversion of nil into Hash")
+ -> { {a: 1, **h} }.should.raise(TypeError, "no implicit conversion of nil into Hash")
- -> { {a: 1, **nil} }.should raise_error(TypeError, "no implicit conversion of nil into Hash")
+ -> { {a: 1, **nil} }.should.raise(TypeError, "no implicit conversion of nil into Hash")
end
end
@@ -167,6 +167,17 @@ describe "Hash literal" do
{**nil}.should == {}
{a: 1, **nil}.should == {a: 1}
end
+
+ it "expands nil using ** into {} and provides a copy to the callable" do
+ ScratchPad.record []
+ insert = -> key, **kw do
+ kw[key] = 1
+ ScratchPad << kw
+ end
+ insert.call(:foo, **nil)
+ insert.call(:bar, **nil)
+ ScratchPad.recorded.should == [{ foo: 1 }, { bar: 1 }]
+ end
end
it "expands an '**{}' or '**obj' element with the last key/value pair taking precedence" do
@@ -212,13 +223,13 @@ describe "Hash literal" do
obj = mock("hash splat")
obj.should_receive(:to_hash).and_return(obj)
- -> { {**obj} }.should raise_error(TypeError)
+ -> { {**obj} }.should.raise(TypeError)
end
it "raises a TypeError if the object does not respond to #to_hash" do
obj = 42
- -> { {**obj} }.should raise_error(TypeError)
- -> { {a: 1, **obj} }.should raise_error(TypeError)
+ -> { {**obj} }.should.raise(TypeError)
+ -> { {a: 1, **obj} }.should.raise(TypeError)
end
it "does not change encoding of literal string keys during creation" do
@@ -238,7 +249,7 @@ describe "Hash literal" do
ScratchPad.record []
-> {
eval 'ScratchPad << 1; {:"\xC3" => 1}'
- }.should raise_error(SyntaxError, /invalid symbol/)
+ }.should.raise(SyntaxError, /invalid symbol/)
ScratchPad.recorded.should == []
end
@@ -246,7 +257,7 @@ describe "Hash literal" do
ScratchPad.record []
-> {
eval 'ScratchPad << 1; {"\xC3": 1}'
- }.should raise_error(SyntaxError, /invalid symbol/)
+ }.should.raise(SyntaxError, /invalid symbol/)
ScratchPad.recorded.should == []
end
end
@@ -264,17 +275,15 @@ 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
- def m(h)
- h.delete(:one); h
- end
-
- h = { one: 1, two: 2 }
- m(**h).should == { two: 2 }
- m(**h).should_not.equal?(h)
- h.should == { one: 1, two: 2 }
+ it "makes a 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_not.equal?(h)
+ h.should == { one: 1, two: 2 }
end
describe "hash with omitted value" do
@@ -314,11 +323,11 @@ describe "The ** operator" do
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/)
+ -> { eval("{a!:}") }.should.raise(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/)
+ -> { eval("{a?:}") }.should.raise(SyntaxError, /identifier a\? is not valid to get/)
end
end
end
diff --git a/spec/ruby/language/heredoc_spec.rb b/spec/ruby/language/heredoc_spec.rb
index 47ee9c2c51..535f18cba8 100644
--- a/spec/ruby/language/heredoc_spec.rb
+++ b/spec/ruby/language/heredoc_spec.rb
@@ -62,7 +62,7 @@ HERE
it 'raises SyntaxError if quoted HEREDOC identifier is ending not on same line' do
-> {
eval %{<<"HERE\n"\nraises syntax error\nHERE}
- }.should raise_error(SyntaxError)
+ }.should.raise(SyntaxError)
end
it "allows HEREDOC with <<~'identifier', allowing to indent identifier and content" do
@@ -114,6 +114,6 @@ HERE
b
#{c}
HERE
- }.should raise_error(NameError) { |e| e.backtrace[0].should.start_with?("#{__FILE__}:#{__LINE__ - 2}") }
+ }.should.raise(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..53fcb853d5 100644
--- a/spec/ruby/language/if_spec.rb
+++ b/spec/ruby/language/if_spec.rb
@@ -330,7 +330,7 @@ describe "The if expression" do
a
end
RUBY
- }.should raise_error(SyntaxError, /void value expression/)
+ }.should.raise(SyntaxError, /void value expression/)
end
it "does not raise SyntaxError if one branch returns a value" do
diff --git a/spec/ruby/language/it_parameter_spec.rb b/spec/ruby/language/it_parameter_spec.rb
new file mode 100644
index 0000000000..6ba67cbb4f
--- /dev/null
+++ b/spec/ruby/language/it_parameter_spec.rb
@@ -0,0 +1,108 @@
+require_relative '../spec_helper'
+
+ruby_version_is "3.4" do
+ eval <<-RUBY # use eval to avoid warnings on Ruby 3.3
+ describe "The `it` parameter" do
+ it "provides it in a block" do
+ -> { it }.call("a").should == "a"
+ proc { it }.call("a").should == "a"
+ lambda { it }.call("a").should == "a"
+ ["a"].map { it }.should == ["a"]
+ end
+
+ it "assigns nil to not passed parameters" do
+ proc { it }.call().should == nil
+ end
+
+ it "can be used in both outer and nested blocks at the same time" do
+ -> { it + -> { it * it }.call(2) }.call(3).should == 7
+ end
+
+ it "can be reassigned to act as a local variable" do
+ proc { tmp = it; it = tmp * 2; it }.call(21).should == 42
+ end
+
+ it "is a regular local variable if there is already a 'it' local variable" do
+ it = 0
+ proc { it }.call("a").should == 0
+ end
+
+ it "is a regular local variable if there is a method `it` defined" do
+ o = Object.new
+ def o.it
+ 21
+ end
+
+ o.instance_eval("proc { it * 2 }").call(1).should == 2
+ end
+
+ it "is not shadowed by an reassignment in a block" do
+ a = nil
+ proc { a = it; it = 42 }.call(0)
+ a.should == 0 # if `it` were shadowed its value would be nil
+ end
+
+ it "raises SyntaxError when block parameters are specified explicitly" do
+ -> { eval("-> () { it }") }.should.raise(SyntaxError, /ordinary parameter is defined/)
+ -> { eval("-> (x) { it }") }.should.raise(SyntaxError, /ordinary parameter is defined/)
+
+ -> { eval("proc { || it }") }.should.raise(SyntaxError, /ordinary parameter is defined/)
+ -> { eval("proc { |x| it }") }.should.raise(SyntaxError, /ordinary parameter is defined/)
+
+ -> { eval("lambda { || it }") }.should.raise(SyntaxError, /ordinary parameter is defined/)
+ -> { eval("lambda { |x| it }") }.should.raise(SyntaxError, /ordinary parameter is defined/)
+
+ -> { eval("['a'].map { || it }") }.should.raise(SyntaxError, /ordinary parameter is defined/)
+ -> { eval("['a'].map { |x| it }") }.should.raise(SyntaxError, /ordinary parameter is defined/)
+ end
+
+ it "cannot be mixed with numbered parameters" do
+ -> {
+ eval("proc { it + _1 }")
+ }.should.raise(SyntaxError, /numbered parameters are not allowed when 'it' is already used|'it' is already used in/)
+
+ -> {
+ eval("proc { _1 + it }")
+ }.should.raise(SyntaxError, /numbered parameter is already used in|'it' is not allowed when a numbered parameter is already used/)
+ end
+
+ it "affects block arity" do
+ -> {}.arity.should == 0
+ -> { it }.arity.should == 1
+ end
+
+ it "affects block parameters" do
+ -> { it }.parameters.should == [[:req]]
+
+ ruby_version_is ""..."4.0" do
+ proc { it }.parameters.should == [[:opt, nil]]
+ end
+ ruby_version_is "4.0" do
+ proc { it }.parameters.should == [[:opt]]
+ end
+ end
+
+ it "does not affect binding local variables" do
+ -> { it; binding.local_variables }.call("a").should == []
+ end
+
+ it "does not work in methods" do
+ obj = Object.new
+ def obj.foo; it; end
+
+ -> { obj.foo("a") }.should.raise(ArgumentError, /wrong number of arguments/)
+ end
+
+ context "given multiple arguments" do
+ it "provides it in a block and assigns the first argument for a block" do
+ proc { it }.call("a", "b").should == "a"
+ end
+
+ it "raises ArgumentError for a proc" do
+ -> { -> { it }.call("a", "b") }.should.raise(ArgumentError, "wrong number of arguments (given 2, expected 1)")
+ -> { lambda { it }.call("a", "b") }.should.raise(ArgumentError, "wrong number of arguments (given 2, expected 1)")
+ end
+ end
+ end
+ RUBY
+end
diff --git a/spec/ruby/language/keyword_arguments_spec.rb b/spec/ruby/language/keyword_arguments_spec.rb
index 4f6370d419..38edc24414 100644
--- a/spec/ruby/language/keyword_arguments_spec.rb
+++ b/spec/ruby/language/keyword_arguments_spec.rb
@@ -55,9 +55,9 @@ describe "Keyword arguments" do
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')
+ -> { m(kw: 1, kw2: 2) }.should.raise(ArgumentError, 'unknown keyword: :kw2')
+ -> { m(kw: 1, true => false) }.should.raise(ArgumentError, 'unknown keyword: true')
+ -> { m(kw: 1, a: 1, b: 2, c: 3) }.should.raise(ArgumentError, 'unknown keywords: :a, :b, :c')
end
it "raises ArgumentError exception when required keyword argument is not passed" do
@@ -65,8 +65,8 @@ describe "Keyword arguments" do
[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/)
+ -> { m(a: 1, b: 2) }.should.raise(ArgumentError, /missing keyword: :c/)
+ -> { m() }.should.raise(ArgumentError, /missing keywords: :a, :b, :c/)
end
it "raises ArgumentError for missing keyword arguments even if there are extra ones" do
@@ -74,7 +74,7 @@ describe "Keyword arguments" do
a
end
- -> { m(b: 1) }.should raise_error(ArgumentError, /missing keyword: :a/)
+ -> { m(b: 1) }.should.raise(ArgumentError, /missing keyword: :a/)
end
it "handle * and ** at the same call site" do
@@ -86,17 +86,29 @@ describe "Keyword arguments" do
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]
- end
+ context "marked as ruby2_keywords_hash" do
+ it "is not copied when passed as a positional argument" do
+ h = Hash.ruby2_keywords_hash(a:1)
- h = {a: 1}
- m(**h).should_not.equal?(h)
- h.should == {a: 1}
+ def bar(a)
+ a
end
+
+ h2 = bar(h)
+ h2.should.equal?(h)
+ Hash.ruby2_keywords_hash?(h).should == true
+ end
+ end
+
+ context "**" do
+ it "copies a non-empty Hash for a method taking (*args)" do
+ def m(*args)
+ args[0]
+ end
+
+ h = {a: 1}
+ m(**h).should_not.equal?(h)
+ h.should == {a: 1}
end
it "copies the given Hash for a method taking (**kwargs)" do
diff --git a/spec/ruby/language/lambda_spec.rb b/spec/ruby/language/lambda_spec.rb
index ed5a1c69e8..c6239e32bb 100644
--- a/spec/ruby/language/lambda_spec.rb
+++ b/spec/ruby/language/lambda_spec.rb
@@ -11,23 +11,29 @@ describe "A lambda literal -> () { }" do
end
end
- klass.new.create_lambda.should be_an_instance_of(Proc)
+ klass.new.create_lambda.should.instance_of?(Proc)
+ end
+
+ it "is not just syntactic sugar for Kernel#lambda" do
+ should_not_receive(:lambda)
+
+ -> {}
end
it "does not execute the block" do
- -> { fail }.should be_an_instance_of(Proc)
+ -> { fail }.should.instance_of?(Proc)
end
it "returns a lambda" do
- -> { }.lambda?.should be_true
+ -> { }.lambda?.should == true
end
it "may include a rescue clause" do
- eval('-> do raise ArgumentError; rescue ArgumentError; 7; end').should be_an_instance_of(Proc)
+ eval('-> do raise ArgumentError; rescue ArgumentError; 7; end').should.instance_of?(Proc)
end
it "may include a ensure clause" do
- eval('-> do 1; ensure; 2; end').should be_an_instance_of(Proc)
+ eval('-> do 1; ensure; 2; end').should.instance_of?(Proc)
end
it "has its own scope for local variables" do
@@ -48,10 +54,10 @@ describe "A lambda literal -> () { }" do
@d = -> do end
ruby
- @a.().should be_nil
- @b.().should be_nil
- @c.().should be_nil
- @d.().should be_nil
+ @a.().should == nil
+ @b.().should == nil
+ @c.().should == nil
+ @d.().should == nil
end
end
@@ -91,9 +97,9 @@ describe "A lambda literal -> () { }" do
@a = -> (*) { }
ruby
- @a.().should be_nil
- @a.(1).should be_nil
- @a.(1, 2, 3).should be_nil
+ @a.().should == nil
+ @a.(1).should == nil
+ @a.(1, 2, 3).should == nil
end
evaluate <<-ruby do
@@ -109,7 +115,7 @@ describe "A lambda literal -> () { }" do
@a = -> (a:) { a }
ruby
- -> { @a.() }.should raise_error(ArgumentError)
+ -> { @a.() }.should.raise(ArgumentError)
@a.(a: 1).should == 1
end
@@ -125,9 +131,9 @@ describe "A lambda literal -> () { }" do
@a = -> (**) { }
ruby
- @a.().should be_nil
- @a.(a: 1, b: 2).should be_nil
- -> { @a.(1) }.should raise_error(ArgumentError)
+ @a.().should == nil
+ @a.(a: 1, b: 2).should == nil
+ -> { @a.(1) }.should.raise(ArgumentError)
end
evaluate <<-ruby do
@@ -142,8 +148,8 @@ describe "A lambda literal -> () { }" do
@a = -> (&b) { b }
ruby
- @a.().should be_nil
- @a.() { }.should be_an_instance_of(Proc)
+ @a.().should == nil
+ @a.() { }.should.instance_of?(Proc)
end
evaluate <<-ruby do
@@ -151,8 +157,8 @@ describe "A lambda literal -> () { }" do
ruby
@a.(1, 2).should == [1, 2]
- -> { @a.() }.should raise_error(ArgumentError)
- -> { @a.(1) }.should raise_error(ArgumentError)
+ -> { @a.() }.should.raise(ArgumentError)
+ -> { @a.(1) }.should.raise(ArgumentError)
end
evaluate <<-ruby do
@@ -193,9 +199,9 @@ describe "A lambda literal -> () { }" do
@a = -> (*, &b) { b }
ruby
- @a.().should be_nil
- @a.(1, 2, 3, 4).should be_nil
- @a.(&(l = ->{})).should equal(l)
+ @a.().should == nil
+ @a.(1, 2, 3, 4).should == nil
+ @a.(&(l = ->{})).should.equal?(l)
end
evaluate <<-ruby do
@@ -268,7 +274,7 @@ describe "A lambda literal -> () { }" do
a = 1
-> {
eval "-> (a=a) { a }"
- }.should raise_error(SyntaxError)
+ }.should.raise(SyntaxError)
end
end
@@ -286,6 +292,24 @@ describe "A lambda literal -> () { }" do
end
end
end
+
+ evaluate <<-ruby do
+ @a = -> (**nil) { :ok }
+ ruby
+
+ @a.call().should == :ok
+ -> { @a.call(a: 1) }.should.raise(ArgumentError, 'no keywords accepted')
+ -> { @a.call(**{a: 1}) }.should.raise(ArgumentError, 'no keywords accepted')
+ -> { @a.call("a" => 1) }.should.raise(ArgumentError, 'no keywords accepted')
+ end
+
+ evaluate <<-ruby do
+ @a = -> (a, **nil) { a }
+ ruby
+
+ @a.call({a: 1}).should == {a: 1}
+ -> { @a.call(a: 1) }.should.raise(ArgumentError, 'no keywords accepted')
+ end
end
describe "A lambda expression 'lambda { ... }'" do
@@ -299,25 +323,25 @@ describe "A lambda expression 'lambda { ... }'" do
lambda { }
end
- obj.define.should equal(obj)
+ obj.define.should.equal?(obj)
end
it "does not execute the block" do
- lambda { fail }.should be_an_instance_of(Proc)
+ lambda { fail }.should.instance_of?(Proc)
end
it "returns a lambda" do
- lambda { }.lambda?.should be_true
+ lambda { }.lambda?.should == true
end
it "requires a block" do
suppress_warning do
- lambda { lambda }.should raise_error(ArgumentError)
+ lambda { lambda }.should.raise(ArgumentError)
end
end
it "may include a rescue clause" do
- eval('lambda do raise ArgumentError; rescue ArgumentError; 7; end').should be_an_instance_of(Proc)
+ eval('lambda do raise ArgumentError; rescue ArgumentError; 7; end').should.instance_of?(Proc)
end
context "with an implicit block" do
@@ -330,7 +354,7 @@ describe "A lambda expression 'lambda { ... }'" do
suppress_warning do
-> {
meth { 1 }
- }.should raise_error(ArgumentError, /tried to create Proc object without a block/)
+ }.should.raise(ArgumentError, /tried to create Proc object without a block/)
end
end
end
@@ -341,8 +365,8 @@ describe "A lambda expression 'lambda { ... }'" do
@b = lambda { || }
ruby
- @a.().should be_nil
- @b.().should be_nil
+ @a.().should == nil
+ @b.().should == nil
end
end
@@ -359,8 +383,8 @@ describe "A lambda expression 'lambda { ... }'" do
@a = lambda { |a| a }
ruby
- lambda { m(&@a) }.should raise_error(ArgumentError)
- lambda { m(1, 2, &@a) }.should raise_error(ArgumentError)
+ lambda { m(&@a) }.should.raise(ArgumentError)
+ lambda { m(1, 2, &@a) }.should.raise(ArgumentError)
end
evaluate <<-ruby do
@@ -370,8 +394,8 @@ describe "A lambda expression 'lambda { ... }'" do
@a.(1).should == 1
@a.([1, 2]).should == [1, 2]
- lambda { @a.() }.should raise_error(ArgumentError)
- lambda { @a.(1, 2) }.should raise_error(ArgumentError)
+ lambda { @a.() }.should.raise(ArgumentError)
+ lambda { @a.(1, 2) }.should.raise(ArgumentError)
end
evaluate <<-ruby do
@@ -384,7 +408,7 @@ describe "A lambda expression 'lambda { ... }'" do
m(1, &@a).should == 1
m([1, 2], &@a).should == [1, 2]
- lambda { m2(&@a) }.should raise_error(ArgumentError)
+ lambda { m2(&@a) }.should.raise(ArgumentError)
end
evaluate <<-ruby do
@@ -415,9 +439,9 @@ describe "A lambda expression 'lambda { ... }'" do
@a = lambda { |*| }
ruby
- @a.().should be_nil
- @a.(1).should be_nil
- @a.(1, 2, 3).should be_nil
+ @a.().should == nil
+ @a.(1).should == nil
+ @a.(1, 2, 3).should == nil
end
evaluate <<-ruby do
@@ -433,7 +457,7 @@ describe "A lambda expression 'lambda { ... }'" do
@a = lambda { |a:| a }
ruby
- lambda { @a.() }.should raise_error(ArgumentError)
+ lambda { @a.() }.should.raise(ArgumentError)
@a.(a: 1).should == 1
end
@@ -449,9 +473,9 @@ describe "A lambda expression 'lambda { ... }'" do
@a = lambda { |**| }
ruby
- @a.().should be_nil
- @a.(a: 1, b: 2).should be_nil
- lambda { @a.(1) }.should raise_error(ArgumentError)
+ @a.().should == nil
+ @a.(a: 1, b: 2).should == nil
+ lambda { @a.(1) }.should.raise(ArgumentError)
end
evaluate <<-ruby do
@@ -466,8 +490,8 @@ describe "A lambda expression 'lambda { ... }'" do
@a = lambda { |&b| b }
ruby
- @a.().should be_nil
- @a.() { }.should be_an_instance_of(Proc)
+ @a.().should == nil
+ @a.() { }.should.instance_of?(Proc)
end
evaluate <<-ruby do
@@ -515,9 +539,9 @@ describe "A lambda expression 'lambda { ... }'" do
@a = lambda { |*, &b| b }
ruby
- @a.().should be_nil
- @a.(1, 2, 3, 4).should be_nil
- @a.(&(l = ->{})).should equal(l)
+ @a.().should == nil
+ @a.(1, 2, 3, 4).should == nil
+ @a.(&(l = ->{})).should.equal?(l)
end
evaluate <<-ruby do
@@ -583,5 +607,23 @@ describe "A lambda expression 'lambda { ... }'" do
result = @a.(1, 2, e: 3, g: 4, h: 5, i: 6, &(l = ->{}))
result.should == [1, 1, [], 2, 3, 2, 4, { h: 5, i: 6 }, l]
end
+
+ evaluate <<-ruby do
+ @a = lambda { |**nil| :ok }
+ ruby
+
+ @a.call().should == :ok
+ -> { @a.call(a: 1) }.should.raise(ArgumentError, 'no keywords accepted')
+ -> { @a.call(**{a: 1}) }.should.raise(ArgumentError, 'no keywords accepted')
+ -> { @a.call("a" => 1) }.should.raise(ArgumentError, 'no keywords accepted')
+ end
+
+ evaluate <<-ruby do
+ @a = lambda { |a, **nil| a }
+ ruby
+
+ @a.call({a: 1}).should == {a: 1}
+ -> { @a.call(a: 1) }.should.raise(ArgumentError, 'no keywords accepted')
+ end
end
end
diff --git a/spec/ruby/language/line_spec.rb b/spec/ruby/language/line_spec.rb
index fcadaa71d7..2864798079 100644
--- a/spec/ruby/language/line_spec.rb
+++ b/spec/ruby/language/line_spec.rb
@@ -4,7 +4,7 @@ require_relative 'shared/__LINE__'
describe "The __LINE__ pseudo-variable" do
it "raises a SyntaxError if assigned to" do
- -> { eval("__LINE__ = 1") }.should raise_error(SyntaxError)
+ -> { eval("__LINE__ = 1") }.should.raise(SyntaxError)
end
before :each do
diff --git a/spec/ruby/language/loop_spec.rb b/spec/ruby/language/loop_spec.rb
index fd17b53910..9b12765a5f 100644
--- a/spec/ruby/language/loop_spec.rb
+++ b/spec/ruby/language/loop_spec.rb
@@ -15,7 +15,7 @@ describe "The loop expression" do
inner_loop = 123
break
end
- -> { inner_loop }.should raise_error(NameError)
+ -> { inner_loop }.should.raise(NameError)
end
it "returns the value passed to break if interrupted by break" do
diff --git a/spec/ruby/language/magic_comment_spec.rb b/spec/ruby/language/magic_comment_spec.rb
index f2bf3a08e5..af9c9dbfd0 100644
--- a/spec/ruby/language/magic_comment_spec.rb
+++ b/spec/ruby/language/magic_comment_spec.rb
@@ -45,7 +45,8 @@ end
describe "Magic comments" do
describe "in stdin" do
- it_behaves_like :magic_comments, :locale, -> file {
+ default = (platform_is :windows and ruby_version_is "4.0") ? :UTF8 : :locale
+ it_behaves_like :magic_comments, default, -> file {
print_at_exit = fixture(__FILE__, "print_magic_comment_result_at_exit.rb")
ruby_exe(nil, args: "< #{fixture(__FILE__, file)}", options: "-r#{print_at_exit}")
}
diff --git a/spec/ruby/language/match_spec.rb b/spec/ruby/language/match_spec.rb
index ebf677cabc..096ebee022 100644
--- a/spec/ruby/language/match_spec.rb
+++ b/spec/ruby/language/match_spec.rb
@@ -46,6 +46,14 @@ describe "The =~ operator with named captures" do
matched.should == "foo"
unmatched.should == nil
end
+
+ it "sets existing local variables if declared in a higher scope" do
+ a = 42
+ 1.times do
+ /(?<a>foo)/ =~ @string
+ end
+ a.should == "foo"
+ end
end
describe "on syntax of 'string_literal' =~ /regexp/" do
diff --git a/spec/ruby/language/metaclass_spec.rb b/spec/ruby/language/metaclass_spec.rb
index fc83067977..3bee823a75 100644
--- a/spec/ruby/language/metaclass_spec.rb
+++ b/spec/ruby/language/metaclass_spec.rb
@@ -16,17 +16,17 @@ describe "self in a metaclass body (class << obj)" do
end
it "raises a TypeError for numbers" do
- -> { class << 1; self; end }.should raise_error(TypeError)
+ -> { class << 1; self; end }.should.raise(TypeError)
end
it "raises a TypeError for symbols" do
- -> { class << :symbol; self; end }.should raise_error(TypeError)
+ -> { class << :symbol; self; end }.should.raise(TypeError)
end
it "is a singleton Class instance" do
cls = class << mock('x'); self; end
cls.is_a?(Class).should == true
- cls.should_not equal(Object)
+ cls.should_not.equal?(Object)
end
end
@@ -57,20 +57,20 @@ describe "A constant on a metaclass" do
end
it "is not defined on the object's class" do
- @object.class.const_defined?(:CONST).should be_false
+ @object.class.const_defined?(:CONST).should == false
end
it "is not defined in the metaclass opener's scope" do
class << @object
CONST
end
- -> { CONST }.should raise_error(NameError)
+ -> { CONST }.should.raise(NameError)
end
it "cannot be accessed via object::CONST" do
-> do
@object::CONST
- end.should raise_error(TypeError)
+ end.should.raise(TypeError)
end
it "raises a NameError for anonymous_module::CONST" do
@@ -81,16 +81,16 @@ describe "A constant on a metaclass" do
-> do
@object::CONST
- end.should raise_error(NameError)
+ end.should.raise(NameError)
end
it "appears in the metaclass constant list" do
constants = class << @object; constants; end
- constants.should include(:CONST)
+ constants.should.include?(:CONST)
end
it "does not appear in the object's class constant list" do
- @object.class.constants.should_not include(:CONST)
+ @object.class.constants.should_not.include?(:CONST)
end
it "is not preserved when the object is duped" do
@@ -98,14 +98,14 @@ describe "A constant on a metaclass" do
-> do
class << @object; CONST; end
- end.should raise_error(NameError)
+ end.should.raise(NameError)
end
it "is preserved when the object is cloned" do
@object = @object.clone
class << @object
- CONST.should_not be_nil
+ CONST.should_not == nil
end
end
end
diff --git a/spec/ruby/language/method_spec.rb b/spec/ruby/language/method_spec.rb
index 1d412a133e..324bd6cea5 100644
--- a/spec/ruby/language/method_spec.rb
+++ b/spec/ruby/language/method_spec.rb
@@ -19,7 +19,7 @@ describe "A method send" do
x = mock("splat argument")
x.should_not_receive(:to_ary)
- m(*x).should equal(x)
+ m(*x).should.equal?(x)
end
it "calls #to_a" do
@@ -40,7 +40,7 @@ describe "A method send" do
x = mock("splat argument")
x.should_receive(:to_a).and_return(1)
- -> { m(*x) }.should raise_error(TypeError)
+ -> { m(*x) }.should.raise(TypeError)
end
end
@@ -74,7 +74,7 @@ describe "A method send" do
x = mock("splat argument")
x.should_receive(:to_a).and_return(1)
- -> { m(*x, 2, 3) }.should raise_error(TypeError)
+ -> { m(*x, 2, 3) }.should.raise(TypeError)
end
end
@@ -108,13 +108,13 @@ describe "A method send" do
x = mock("splat argument")
x.should_receive(:to_a).and_return(1)
- -> { m(1, *x, 2, 3) }.should raise_error(TypeError)
+ -> { m(1, *x, 2, 3) }.should.raise(TypeError)
end
it "copies the splatted array" do
args = [3, 4]
m(1, 2, *args, 4, 5).should == [1, 2, [3, 4], 4, 5]
- m(1, 2, *args, 4, 5)[2].should_not equal(args)
+ m(1, 2, *args, 4, 5)[2].should_not.equal?(args)
end
it "allows an array being splatted to be modified by another argument" do
@@ -153,7 +153,7 @@ describe "A method send" do
x = mock("splat argument")
x.should_receive(:to_a).and_return(1)
- -> { m(1, 2, *x) }.should raise_error(TypeError)
+ -> { m(1, 2, *x) }.should.raise(TypeError)
end
end
@@ -217,7 +217,7 @@ describe "An element assignment method send" do
x = mock("splat argument")
x.should_receive(:to_a).and_return(1)
- -> { @o[*x] = 1 }.should raise_error(TypeError)
+ -> { @o[*x] = 1 }.should.raise(TypeError)
end
end
@@ -255,7 +255,7 @@ describe "An element assignment method send" do
x = mock("splat argument")
x.should_receive(:to_a).and_return(1)
- -> { @o[*x, 2, 3] = 4 }.should raise_error(TypeError)
+ -> { @o[*x, 2, 3] = 4 }.should.raise(TypeError)
end
end
@@ -293,7 +293,7 @@ describe "An element assignment method send" do
x = mock("splat argument")
x.should_receive(:to_a).and_return(1)
- -> { @o[1, 2, *x, 3] = 4 }.should raise_error(TypeError)
+ -> { @o[1, 2, *x, 3] = 4 }.should.raise(TypeError)
end
end
@@ -331,7 +331,7 @@ describe "An element assignment method send" do
x = mock("splat argument")
x.should_receive(:to_a).and_return(1)
- -> { @o[1, 2, 3, *x] = 4 }.should raise_error(TypeError)
+ -> { @o[1, 2, 3, *x] = 4 }.should.raise(TypeError)
end
end
end
@@ -368,7 +368,7 @@ describe "An attribute assignment method send" do
x = mock("splat argument")
x.should_receive(:to_a).and_return(1)
- -> { @o.send :m=, *x, 1 }.should raise_error(TypeError)
+ -> { @o.send :m=, *x, 1 }.should.raise(TypeError)
end
end
@@ -403,7 +403,7 @@ describe "An attribute assignment method send" do
x = mock("splat argument")
x.should_receive(:to_a).and_return(1)
- -> { @o.send :m=, *x, 2, 3, 4 }.should raise_error(TypeError)
+ -> { @o.send :m=, *x, 2, 3, 4 }.should.raise(TypeError)
end
end
@@ -438,7 +438,7 @@ describe "An attribute assignment method send" do
x = mock("splat argument")
x.should_receive(:to_a).and_return(1)
- -> { @o.send :m=, 1, 2, *x, 3, 4 }.should raise_error(TypeError)
+ -> { @o.send :m=, 1, 2, *x, 3, 4 }.should.raise(TypeError)
end
end
@@ -473,7 +473,7 @@ describe "An attribute assignment method send" do
x = mock("splat argument")
x.should_receive(:to_a).and_return(1)
- -> { @o.send :m=, 1, 2, 3, *x, 4 }.should raise_error(TypeError)
+ -> { @o.send :m=, 1, 2, 3, *x, 4 }.should.raise(TypeError)
end
end
end
@@ -487,7 +487,7 @@ describe "A method" do
end
ruby
- m.should be_nil
+ m.should == nil
end
evaluate <<-ruby do
@@ -495,7 +495,7 @@ describe "A method" do
end
ruby
- m.should be_nil
+ m.should == nil
end
end
@@ -504,7 +504,7 @@ describe "A method" do
def m(a) a end
ruby
- m((args = 1, 2, 3)).should equal(args)
+ m((args = 1, 2, 3)).should.equal?(args)
end
evaluate <<-ruby do
@@ -535,18 +535,18 @@ describe "A method" do
def m() end
ruby
- m().should be_nil
- m(*[]).should be_nil
- m(**{}).should be_nil
+ m().should == nil
+ m(*[]).should == nil
+ m(**{}).should == nil
end
evaluate <<-ruby do
def m(*) end
ruby
- m().should be_nil
- m(1).should be_nil
- m(1, 2, 3).should be_nil
+ m().should == nil
+ m(1).should == nil
+ m(1, 2, 3).should == nil
end
evaluate <<-ruby do
@@ -564,10 +564,10 @@ describe "A method" do
def m(a:) a end
ruby
- -> { m() }.should raise_error(ArgumentError)
+ -> { m() }.should.raise(ArgumentError)
m(a: 1).should == 1
suppress_keyword_warning do
- -> { m("a" => 1, a: 1) }.should raise_error(ArgumentError)
+ -> { m("a" => 1, a: 1) }.should.raise(ArgumentError)
end
end
@@ -575,7 +575,7 @@ describe "A method" do
def m(a:, **kw) [a, kw] end
ruby
- -> { m(b: 1) }.should raise_error(ArgumentError)
+ -> { m(b: 1) }.should.raise(ArgumentError)
end
evaluate <<-ruby do
@@ -590,9 +590,9 @@ describe "A method" do
def m(**) end
ruby
- m().should be_nil
- m(a: 1, b: 2).should be_nil
- -> { m(1) }.should raise_error(ArgumentError)
+ m().should == nil
+ m(a: 1, b: 2).should == nil
+ -> { m(1) }.should.raise(ArgumentError)
end
evaluate <<-ruby do
@@ -606,7 +606,7 @@ describe "A method" do
suppress_warning {
eval "m(**{a: 1, b: 2}, **{a: 4, c: 7})"
}.should == { a: 4, b: 2, c: 7 }
- -> { m(2) }.should raise_error(ArgumentError)
+ -> { m(2) }.should.raise(ArgumentError)
end
evaluate <<-ruby do
@@ -620,7 +620,7 @@ describe "A method" do
def m(&b) b end
ruby
- m { }.should be_an_instance_of(Proc)
+ m { }.should.instance_of?(Proc)
end
evaluate <<-ruby do
@@ -650,9 +650,9 @@ describe "A method" do
def m((*), (*)) end
ruby
- m(2, 3).should be_nil
- m([2, 3, 4], [5, 6]).should be_nil
- -> { m a: 1 }.should raise_error(ArgumentError)
+ m(2, 3).should == nil
+ m([2, 3, 4], [5, 6]).should == nil
+ -> { m a: 1 }.should.raise(ArgumentError)
end
evaluate <<-ruby do
@@ -745,7 +745,7 @@ describe "A method" do
m(1, b: 2).should == [1, 2]
suppress_keyword_warning do
- -> { m("a" => 1, b: 2) }.should raise_error(ArgumentError)
+ -> { m("a" => 1, b: 2) }.should.raise(ArgumentError)
end
end
@@ -755,7 +755,7 @@ describe "A method" do
m(2).should == [2, 1]
m(1, b: 2).should == [1, 2]
- -> { m("a" => 1, b: 2) }.should raise_error(ArgumentError)
+ -> { m("a" => 1, b: 2) }.should.raise(ArgumentError)
end
evaluate <<-ruby do
@@ -764,7 +764,7 @@ describe "A method" do
m(1).should == 1
m(1, a: 2, b: 3).should == 1
- -> { m("a" => 1, b: 2) }.should raise_error(ArgumentError)
+ -> { m("a" => 1, b: 2) }.should.raise(ArgumentError)
end
evaluate <<-ruby do
@@ -773,7 +773,7 @@ describe "A method" do
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)
+ -> { m("a" => 1, b: 2) }.should.raise(ArgumentError)
end
evaluate <<-ruby do
@@ -848,8 +848,8 @@ describe "A method" do
def m(a=1, (*b), (*c)) [a, b, c] end
ruby
- -> { m() }.should raise_error(ArgumentError)
- -> { m(2) }.should raise_error(ArgumentError)
+ -> { m() }.should.raise(ArgumentError)
+ -> { m(2) }.should.raise(ArgumentError)
m(2, 3).should == [1, [2], [3]]
m(2, [3, 4], [5, 6]).should == [2, [3, 4], [5, 6]]
end
@@ -890,7 +890,7 @@ describe "A method" do
m(b: 2).should == [1, 2]
m(2, b: 1).should == [2, 1]
- -> { m("a" => 1, b: 2) }.should raise_error(ArgumentError)
+ -> { m("a" => 1, b: 2) }.should.raise(ArgumentError)
end
evaluate <<-ruby do
@@ -900,7 +900,7 @@ describe "A method" do
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("a" => 1, b: 2) }.should.raise(ArgumentError)
end
evaluate <<-ruby do
@@ -953,9 +953,9 @@ describe "A method" do
def m(*, &b) b end
ruby
- m().should be_nil
- m(1, 2, 3, 4).should be_nil
- m(&(l = ->{})).should equal(l)
+ m().should == nil
+ m(1, 2, 3, 4).should == nil
+ m(&(l = ->{})).should.equal?(l)
end
evaluate <<-ruby do
@@ -973,7 +973,7 @@ describe "A method" do
m(a: 1, b: 2).should == [1, 2]
suppress_keyword_warning do
- -> { m("a" => 1, a: 1, b: 2) }.should raise_error(ArgumentError)
+ -> { m("a" => 1, a: 1, b: 2) }.should.raise(ArgumentError)
end
end
@@ -984,7 +984,7 @@ describe "A method" do
m(a: 1).should == [1, 1]
m(a: 1, b: 2).should == [1, 2]
suppress_keyword_warning do
- -> { m("a" => 1, a: 1, b: 2) }.should raise_error(ArgumentError)
+ -> { m("a" => 1, a: 1, b: 2) }.should.raise(ArgumentError)
end
end
@@ -1101,15 +1101,25 @@ describe "A method" do
end
evaluate <<-ruby do
+ def m(**nil); :ok; end;
+ ruby
+
+ m().should == :ok
+ -> { m(a: 1) }.should.raise(ArgumentError, 'no keywords accepted')
+ -> { m(**{a: 1}) }.should.raise(ArgumentError, 'no keywords accepted')
+ -> { m("a" => 1) }.should.raise(ArgumentError, 'no keywords accepted')
+ end
+
+ evaluate <<-ruby do
def m(a, **nil); a end;
ruby
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(ArgumentError, 'no keywords accepted')
+ -> { m(**{a: 1}) }.should.raise(ArgumentError, 'no keywords accepted')
+ -> { m("a" => 1) }.should.raise(ArgumentError, 'no keywords accepted')
end
evaluate <<-ruby do
@@ -1127,6 +1137,18 @@ describe "A method" do
result = m(1, {foo: :bar})
result.should == [1, nil, nil, {foo: :bar}, nil, {}]
end
+
+ ruby_version_is "4.1" do
+ evaluate <<-ruby do
+ def m(a, &nil); a end;
+ ruby
+
+ m(1).should == 1
+
+ -> { m(1) {} }.should.raise(ArgumentError, 'no block accepted')
+ -> { m(1, &proc {}) }.should.raise(ArgumentError, 'no block accepted')
+ end
+ end
end
context 'when passing an empty keyword splat to a method that does not accept keywords' do
@@ -1147,7 +1169,7 @@ describe "A method" do
-> do
m(**h).should == {}
- end.should raise_error(ArgumentError)
+ end.should.raise(ArgumentError)
end
end
@@ -1159,7 +1181,7 @@ describe "A method" do
options = {a: 1}.freeze
-> do
m(options)
- end.should raise_error(ArgumentError)
+ end.should.raise(ArgumentError)
end
end
@@ -1181,8 +1203,8 @@ context "when passing **nil into a method that accepts keyword arguments" do
def m(**kw) kw; end
h = nil
- -> { m(a: 1, **h) }.should raise_error(TypeError, "no implicit conversion of nil into Hash")
- -> { m(a: 1, **nil) }.should raise_error(TypeError, "no implicit conversion of nil into Hash")
+ -> { m(a: 1, **h) }.should.raise(TypeError, "no implicit conversion of nil into Hash")
+ -> { m(a: 1, **nil) }.should.raise(TypeError, "no implicit conversion of nil into Hash")
end
end
@@ -1234,10 +1256,8 @@ describe "A method call with a space between method name and parentheses" do
args.should == [true]
end
- ruby_version_is "3.3" do
- it "supports multiple statements" do
- eval("m (1; 2)").should == [2]
- end
+ it "supports multiple statements" do
+ eval("m (1; 2)").should == [2]
end
end
@@ -1257,11 +1277,11 @@ describe "A method call with a space between method name and parentheses" do
it "raises a syntax error" do
-> {
eval("m (1, 2)")
- }.should raise_error(SyntaxError)
+ }.should.raise(SyntaxError)
-> {
eval("m (1, 2, 3)")
- }.should raise_error(SyntaxError)
+ }.should.raise(SyntaxError)
end
end
@@ -1411,7 +1431,7 @@ describe "Keyword arguments are now separated from positional arguments" do
-> {
foo(1, 2, 3, { key: 42 })
- }.should raise_error(ArgumentError, 'wrong number of arguments (given 4, expected 3)')
+ }.should.raise(ArgumentError, 'wrong number of arguments (given 4, expected 3)')
end
end
@@ -1424,7 +1444,7 @@ describe "Keyword arguments are now separated from positional arguments" do
-> {
foo(1, 2, 3, { key: 42 })
- }.should raise_error(ArgumentError, 'wrong number of arguments (given 4, expected 3)')
+ }.should.raise(ArgumentError, 'wrong number of arguments (given 4, expected 3)')
end
end
@@ -1487,3 +1507,163 @@ describe "Inside 'endless' method definitions" do
greet("Homer").should == "Hi, Homer"
end
end
+
+describe "warning about not used block argument" do
+ ruby_version_is "3.4" do
+ it "warns when passing a block argument to a method that never uses it" do
+ def m_that_does_not_use_block
+ 42
+ end
+
+ -> {
+ m_that_does_not_use_block { }
+ }.should complain(
+ /#{__FILE__}:#{__LINE__ - 2}: warning: the block passed to 'm_that_does_not_use_block' defined at #{__FILE__}:#{__LINE__ - 7} may be ignored/,
+ verbose: true)
+ end
+
+ it "does not warn when passing a block argument to a method that declares a block parameter" do
+ def m_with_block_parameter(&block)
+ 42
+ end
+
+ -> { m_with_block_parameter { } }.should_not complain(verbose: true)
+ end
+
+ it "does not warn when passing a block argument to a method that declares an anonymous block parameter" do
+ def m_with_anonymous_block_parameter(&)
+ 42
+ end
+
+ -> { m_with_anonymous_block_parameter { } }.should_not complain(verbose: true)
+ end
+
+ it "does not warn when passing a block argument to a method that yields an implicit block parameter" do
+ def m_with_yield
+ yield 42
+ end
+
+ -> { m_with_yield { } }.should_not complain(verbose: true)
+ end
+
+ it "warns when passing a block argument to a method that calls #block_given?" do
+ def m_with_block_given
+ block_given?
+ end
+
+ -> {
+ m_with_block_given { }
+ }.should complain(
+ /#{__FILE__}:#{__LINE__ - 2}: warning: the block passed to 'm_with_block_given' defined at #{__FILE__}:#{__LINE__ - 7} may be ignored/,
+ verbose: true)
+ end
+
+ it "does not warn when passing a block argument to a method that calls super" do
+ parent = Class.new do
+ def m
+ end
+ end
+
+ child = Class.new(parent) do
+ def m
+ super
+ end
+ end
+
+ obj = child.new
+ -> { obj.m { } }.should_not complain(verbose: true)
+ end
+
+ it "does not warn when passing a block argument to a method that calls super(...)" do
+ parent = Class.new do
+ def m(a)
+ end
+ end
+
+ child = Class.new(parent) do
+ def m(...)
+ super(...)
+ end
+ end
+
+ obj = child.new
+ -> { obj.m(42) { } }.should_not complain(verbose: true)
+ end
+
+ it "does not warn when called #initialize()" do
+ klass = Class.new do
+ def initialize
+ end
+ end
+
+ -> { klass.new {} }.should_not complain(verbose: true)
+ end
+
+ it "does not warn when passing a block argument to a method that calls super()" do
+ parent = Class.new do
+ def m
+ end
+ end
+
+ child = Class.new(parent) do
+ def m
+ super()
+ end
+ end
+
+ obj = child.new
+ -> { obj.m { } }.should_not complain(verbose: true)
+ end
+
+ it "warns only once per call site" do
+ def m_that_does_not_use_block
+ 42
+ end
+
+ def call_m_that_does_not_use_block
+ m_that_does_not_use_block {}
+ end
+
+ -> {
+ m_that_does_not_use_block { }
+ }.should complain(/the block passed to 'm_that_does_not_use_block' defined at .+ may be ignored/, verbose: true)
+
+ -> {
+ m_that_does_not_use_block { }
+ }.should_not complain(verbose: true)
+ end
+
+ it "can be disabled with :strict_unused_block warning category" do
+ def m_that_does_not_use_block
+ 42
+ end
+
+ # ensure that warning is emitted
+ -> { m_that_does_not_use_block { } }.should complain(verbose: true)
+
+ warn_strict_unused_block = Warning[:strict_unused_block]
+ Warning[:strict_unused_block] = false
+ begin
+ -> { m_that_does_not_use_block { } }.should_not complain(verbose: true)
+ ensure
+ Warning[:strict_unused_block] = warn_strict_unused_block
+ end
+ end
+
+ it "can be enabled with :strict_unused_block = true warning category in not verbose mode" do
+ def m_that_does_not_use_block
+ 42
+ end
+
+ warn_strict_unused_block = Warning[:strict_unused_block]
+ Warning[:strict_unused_block] = true
+ begin
+ -> {
+ m_that_does_not_use_block { }
+ }.should complain(/the block passed to 'm_that_does_not_use_block' defined at .+ may be ignored/)
+ ensure
+ Warning[:strict_unused_block] = warn_strict_unused_block
+ end
+ end
+ end
+end
diff --git a/spec/ruby/language/module_spec.rb b/spec/ruby/language/module_spec.rb
index 4db00bd7fb..2f22e383d5 100644
--- a/spec/ruby/language/module_spec.rb
+++ b/spec/ruby/language/module_spec.rb
@@ -4,70 +4,94 @@ require_relative 'fixtures/module'
describe "The module keyword" do
it "creates a new module without semicolon" do
module ModuleSpecsKeywordWithoutSemicolon end
- ModuleSpecsKeywordWithoutSemicolon.should be_an_instance_of(Module)
+ ModuleSpecsKeywordWithoutSemicolon.should.instance_of?(Module)
end
it "creates a new module with a non-qualified constant name" do
module ModuleSpecsToplevel; end
- ModuleSpecsToplevel.should be_an_instance_of(Module)
+ ModuleSpecsToplevel.should.instance_of?(Module)
end
it "creates a new module with a qualified constant name" do
module ModuleSpecs::Nested; end
- ModuleSpecs::Nested.should be_an_instance_of(Module)
+ ModuleSpecs::Nested.should.instance_of?(Module)
end
it "creates a new module with a variable qualified constant name" do
m = Module.new
module m::N; end
- m::N.should be_an_instance_of(Module)
+ m::N.should.instance_of?(Module)
end
it "reopens an existing module" do
module ModuleSpecs; Reopened = true; end
- ModuleSpecs::Reopened.should be_true
+ ModuleSpecs::Reopened.should == true
ensure
ModuleSpecs.send(:remove_const, :Reopened)
end
it "does not reopen a module included in Object" do
- module IncludedModuleSpecs; Reopened = true; end
- ModuleSpecs::IncludedInObject::IncludedModuleSpecs.should_not == Object::IncludedModuleSpecs
- ensure
- IncludedModuleSpecs.send(:remove_const, :Reopened)
+ ruby_exe(<<~RUBY).should == "false"
+ module IncludedInObject
+ module IncludedModule; end
+ end
+ class Object
+ include IncludedInObject
+ end
+ module IncludedModule; end
+ print IncludedInObject::IncludedModule == Object::IncludedModule
+ RUBY
+ end
+
+ it "does not reopen a module included in non-Object modules" do
+ ruby_exe(<<~RUBY).should == "false/false"
+ module Included
+ module IncludedModule; end
+ end
+ module M
+ include Included
+ module IncludedModule; end
+ end
+ class C
+ include Included
+ module IncludedModule; end
+ end
+ print Included::IncludedModule == M::IncludedModule, "/",
+ Included::IncludedModule == C::IncludedModule
+ RUBY
end
it "raises a TypeError if the constant is a Class" do
-> do
module ModuleSpecs::Modules::Klass; end
- end.should raise_error(TypeError)
+ end.should.raise(TypeError)
end
it "raises a TypeError if the constant is a String" do
- -> { module ModuleSpecs::Modules::A; end }.should raise_error(TypeError)
+ -> { module ModuleSpecs::Modules::A; end }.should.raise(TypeError)
end
it "raises a TypeError if the constant is an Integer" do
- -> { module ModuleSpecs::Modules::B; end }.should raise_error(TypeError)
+ -> { module ModuleSpecs::Modules::B; end }.should.raise(TypeError)
end
it "raises a TypeError if the constant is nil" do
- -> { module ModuleSpecs::Modules::C; end }.should raise_error(TypeError)
+ -> { module ModuleSpecs::Modules::C; end }.should.raise(TypeError)
end
it "raises a TypeError if the constant is true" do
- -> { module ModuleSpecs::Modules::D; end }.should raise_error(TypeError)
+ -> { module ModuleSpecs::Modules::D; end }.should.raise(TypeError)
end
it "raises a TypeError if the constant is false" do
- -> { module ModuleSpecs::Modules::D; end }.should raise_error(TypeError)
+ -> { module ModuleSpecs::Modules::D; end }.should.raise(TypeError)
end
end
describe "Assigning an anonymous module to a constant" do
it "sets the name of the module" do
mod = Module.new
- mod.name.should be_nil
+ mod.name.should == nil
::ModuleSpecs_CS1 = mod
mod.name.should == "ModuleSpecs_CS1"
diff --git a/spec/ruby/language/next_spec.rb b/spec/ruby/language/next_spec.rb
index 6fbfc4a54d..eac151eeb3 100644
--- a/spec/ruby/language/next_spec.rb
+++ b/spec/ruby/language/next_spec.rb
@@ -21,7 +21,7 @@ describe "The next statement from within the block" do
end
it "causes block to return nil if invoked with an empty expression" do
- -> { next (); 456 }.call.should be_nil
+ -> { next (); 456 }.call.should == nil
end
it "returns the argument passed" do
@@ -111,7 +111,7 @@ describe "The next statement" do
it "is invalid and raises a SyntaxError" do
-> {
eval("def m; next; end")
- }.should raise_error(SyntaxError)
+ }.should.raise(SyntaxError)
end
end
end
diff --git a/spec/ruby/language/not_spec.rb b/spec/ruby/language/not_spec.rb
index 052af9b256..23411a8e1d 100644
--- a/spec/ruby/language/not_spec.rb
+++ b/spec/ruby/language/not_spec.rb
@@ -2,50 +2,50 @@ require_relative '../spec_helper'
describe "The not keyword" do
it "negates a `true' value" do
- (not true).should be_false
- (not 'true').should be_false
+ (not true).should == false
+ (not 'true').should == false
end
it "negates a `false' value" do
- (not false).should be_true
- (not nil).should be_true
+ (not false).should == true
+ (not nil).should == true
end
it "accepts an argument" do
- not(true).should be_false
+ not(true).should == false
end
it "returns false if the argument is true" do
- (not(true)).should be_false
+ (not(true)).should == false
end
it "returns true if the argument is false" do
- (not(false)).should be_true
+ (not(false)).should == true
end
it "returns true if the argument is nil" do
- (not(nil)).should be_true
+ (not(nil)).should == true
end
end
describe "The `!' keyword" do
it "negates a `true' value" do
- (!true).should be_false
- (!'true').should be_false
+ (!true).should == false
+ (!'true').should == false
end
it "negates a `false' value" do
- (!false).should be_true
- (!nil).should be_true
+ (!false).should == true
+ (!nil).should == true
end
it "doubled turns a truthful object into `true'" do
- (!!true).should be_true
- (!!'true').should be_true
+ (!!true).should == true
+ (!!'true').should == true
end
it "doubled turns a not truthful object into `false'" do
- (!!false).should be_false
- (!!nil).should be_false
+ (!!false).should == false
+ (!!nil).should == false
end
end
diff --git a/spec/ruby/language/numbered_parameters_spec.rb b/spec/ruby/language/numbered_parameters_spec.rb
index 39ddd6fee8..23e89a14be 100644
--- a/spec/ruby/language/numbered_parameters_spec.rb
+++ b/spec/ruby/language/numbered_parameters_spec.rb
@@ -22,13 +22,13 @@ 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(NameError, /undefined local variable or method [`']_10'/)
end
it "can not be used in both outer and nested blocks at the same time" do
-> {
eval("-> { _1; -> { _2 } }")
- }.should raise_error(SyntaxError, /numbered parameter is already used in/m)
+ }.should.raise(SyntaxError, /numbered parameter is already used in/m)
end
it "cannot be overwritten with local variable" do
@@ -37,32 +37,32 @@ describe "Numbered parameters" do
_1 = 0
proc { _1 }.call("a").should == 0
CODE
- }.should raise_error(SyntaxError, /_1 is reserved for numbered parameter/)
+ }.should.raise(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/)
+ }.should.raise(SyntaxError, /_1 is reserved for numbered parameter/)
end
it "raises SyntaxError when block parameters are specified explicitly" do
- -> { eval("-> () { _1 }") }.should raise_error(SyntaxError, /ordinary parameter is defined/)
- -> { eval("-> (x) { _1 }") }.should raise_error(SyntaxError, /ordinary parameter is defined/)
+ -> { eval("-> () { _1 }") }.should.raise(SyntaxError, /ordinary parameter is defined/)
+ -> { eval("-> (x) { _1 }") }.should.raise(SyntaxError, /ordinary parameter is defined/)
- -> { eval("proc { || _1 }") }.should raise_error(SyntaxError, /ordinary parameter is defined/)
- -> { eval("proc { |x| _1 }") }.should raise_error(SyntaxError, /ordinary parameter is defined/)
+ -> { eval("proc { || _1 }") }.should.raise(SyntaxError, /ordinary parameter is defined/)
+ -> { eval("proc { |x| _1 }") }.should.raise(SyntaxError, /ordinary parameter is defined/)
- -> { eval("lambda { || _1 }") }.should raise_error(SyntaxError, /ordinary parameter is defined/)
- -> { eval("lambda { |x| _1 }") }.should raise_error(SyntaxError, /ordinary parameter is defined/)
+ -> { eval("lambda { || _1 }") }.should.raise(SyntaxError, /ordinary parameter is defined/)
+ -> { eval("lambda { |x| _1 }") }.should.raise(SyntaxError, /ordinary parameter is defined/)
- -> { eval("['a'].map { || _1 }") }.should raise_error(SyntaxError, /ordinary parameter is defined/)
- -> { eval("['a'].map { |x| _1 }") }.should raise_error(SyntaxError, /ordinary parameter is defined/)
+ -> { eval("['a'].map { || _1 }") }.should.raise(SyntaxError, /ordinary parameter is defined/)
+ -> { eval("['a'].map { |x| _1 }") }.should.raise(SyntaxError, /ordinary parameter is defined/)
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/)
+ -> { eval("proc { _1 = 0 }") }.should.raise(SyntaxError, /_1 is reserved for numbered parameter/)
end
end
@@ -90,14 +90,14 @@ describe "Numbered parameters" do
proc { _2 }.parameters.should == [[:opt, :_1], [:opt, :_2]]
end
- ruby_version_is ""..."3.5" do
+ ruby_version_is ""..."4.0" do
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
end
- ruby_version_is "3.5" do
+ ruby_version_is "4.0" do
it "does not affect binding local variables" do
-> { _1; binding.local_variables }.call("a").should == []
-> { _2; binding.local_variables }.call("a", "b").should == []
@@ -108,6 +108,6 @@ describe "Numbered parameters" do
obj = Object.new
def obj.foo; _1 end
- -> { obj.foo("a") }.should raise_error(ArgumentError, /wrong number of arguments/)
+ -> { obj.foo("a") }.should.raise(ArgumentError, /wrong number of arguments/)
end
end
diff --git a/spec/ruby/language/numbers_spec.rb b/spec/ruby/language/numbers_spec.rb
index a8e023efb6..ed0e49c048 100644
--- a/spec/ruby/language/numbers_spec.rb
+++ b/spec/ruby/language/numbers_spec.rb
@@ -11,7 +11,7 @@ describe "A number literal" do
end
it "cannot have a leading underscore" do
- -> { eval("_4_2") }.should raise_error(NameError)
+ -> { eval("_4_2") }.should.raise(NameError)
end
it "can have a decimal point" do
@@ -20,8 +20,8 @@ describe "A number literal" do
it "must have a digit before the decimal point" do
0.75.should == 0.75
- -> { eval(".75") }.should raise_error(SyntaxError)
- -> { eval("-.75") }.should raise_error(SyntaxError)
+ -> { eval(".75") }.should.raise(SyntaxError)
+ -> { eval("-.75") }.should.raise(SyntaxError)
end
it "can have an exponent" do
diff --git a/spec/ruby/language/optional_assignments_spec.rb b/spec/ruby/language/optional_assignments_spec.rb
index 5fe3e3671b..ebb5d36351 100644
--- a/spec/ruby/language/optional_assignments_spec.rb
+++ b/spec/ruby/language/optional_assignments_spec.rb
@@ -603,7 +603,7 @@ describe 'Optional variable assignments' do
end
it 'with &&= assignments will fail with non-existent constants' do
- -> { Object::A &&= 10 }.should raise_error(NameError)
+ -> { Object::A &&= 10 }.should.raise(NameError)
end
it 'with operator assignments' do
@@ -615,7 +615,7 @@ describe 'Optional variable assignments' do
end
it 'with operator assignments will fail with non-existent constants' do
- -> { Object::A += 10 }.should raise_error(NameError)
+ -> { Object::A += 10 }.should.raise(NameError)
end
end
end
@@ -623,7 +623,7 @@ end
describe 'Optional constant assignment' do
describe 'with ||=' do
it "assigns a scoped constant if previously undefined" do
- ConstantSpecs.should_not have_constant(:OpAssignUndefined)
+ ConstantSpecs.should_not.const_defined?(:OpAssignUndefined)
module ConstantSpecs
OpAssignUndefined ||= 42
end
@@ -679,7 +679,7 @@ describe 'Optional constant assignment' do
-> {
(x += 1; raise Exception; ConstantSpecs::ClassA)::OR_ASSIGNED_CONSTANT3 ||= (y += 1; :assigned)
- }.should raise_error(Exception)
+ }.should.raise(Exception)
x.should == 1
y.should == 0
@@ -693,7 +693,7 @@ describe 'Optional constant assignment' do
-> {
(x += 1; raise Exception; ConstantSpecs::ClassA)::NIL_OR_ASSIGNED_CONSTANT3 ||= (y += 1; :assigned)
- }.should raise_error(Exception)
+ }.should.raise(Exception)
x.should == 1
y.should == 0
diff --git a/spec/ruby/language/or_spec.rb b/spec/ruby/language/or_spec.rb
index fb75e788f1..8ae577a142 100644
--- a/spec/ruby/language/or_spec.rb
+++ b/spec/ruby/language/or_spec.rb
@@ -26,24 +26,24 @@ describe "The || operator" do
end
it "treats empty expressions as nil" do
- (() || true).should be_true
- (() || false).should be_false
- (true || ()).should be_true
- (false || ()).should be_nil
- (() || ()).should be_nil
+ (() || true).should == true
+ (() || false).should == false
+ (true || ()).should == true
+ (false || ()).should == nil
+ (() || ()).should == nil
end
it "has a higher precedence than 'break' in 'break true || false'" do
# see also 'break true or false' below
- -> { break false || true }.call.should be_true
+ -> { break false || true }.call.should == true
end
it "has a higher precedence than 'next' in 'next true || false'" do
- -> { next false || true }.call.should be_true
+ -> { next false || true }.call.should == true
end
it "has a higher precedence than 'return' in 'return true || false'" do
- -> { return false || true }.call.should be_true
+ -> { return false || true }.call.should == true
end
end
@@ -68,23 +68,23 @@ describe "The or operator" do
end
it "treats empty expressions as nil" do
- (() or true).should be_true
- (() or false).should be_false
- (true or ()).should be_true
- (false or ()).should be_nil
- (() or ()).should be_nil
+ (() or true).should == true
+ (() or false).should == false
+ (true or ()).should == true
+ (false or ()).should == nil
+ (() or ()).should == nil
end
it "has a lower precedence than 'break' in 'break true or false'" do
# see also 'break true || false' above
- -> { eval "break true or false" }.should raise_error(SyntaxError, /void value expression/)
+ -> { eval "break true or false" }.should.raise(SyntaxError, /void value expression/)
end
it "has a lower precedence than 'next' in 'next true or false'" do
- -> { eval "next true or false" }.should raise_error(SyntaxError, /void value expression/)
+ -> { eval "next true or false" }.should.raise(SyntaxError, /void value expression/)
end
it "has a lower precedence than 'return' in 'return true or false'" do
- -> { eval "return true or false" }.should raise_error(SyntaxError, /void value expression/)
+ -> { eval "return true or false" }.should.raise(SyntaxError, /void value expression/)
end
end
diff --git a/spec/ruby/language/pattern_matching_spec.rb b/spec/ruby/language/pattern_matching_spec.rb
index cb4f5864d7..a24500c9fd 100644
--- a/spec/ruby/language/pattern_matching_spec.rb
+++ b/spec/ruby/language/pattern_matching_spec.rb
@@ -185,7 +185,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(SyntaxError, /syntax error, unexpected `in'|\(eval\):3: syntax error, unexpected keyword_in|unexpected 'in'/)
-> {
eval <<~RUBY
@@ -194,7 +194,7 @@ 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(SyntaxError, /syntax error, unexpected `when'|\(eval\):3: syntax error, unexpected keyword_when|unexpected 'when'/)
end
it "checks patterns until the first matching" do
@@ -222,14 +222,14 @@ describe "Pattern matching" do
case [0, 1]
in [0]
end
- }.should raise_error(NoMatchingPatternError, /\[0, 1\]/)
+ }.should.raise(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)
+ }.should.raise(NoMatchingPatternError, error_pattern)
end
it "raises NoMatchingPatternError if no pattern matches and evaluates the expression only once" do
@@ -238,7 +238,7 @@ describe "Pattern matching" do
case (evals += 1; [0, 1])
in [0]
end
- }.should raise_error(NoMatchingPatternError, /\[0, 1\]/)
+ }.should.raise(NoMatchingPatternError, /\[0, 1\]/)
evals.should == 1
end
@@ -250,7 +250,7 @@ describe "Pattern matching" do
true
end
RUBY
- }.should raise_error(SyntaxError, /unexpected|expected a delimiter after the patterns of an `in` clause/)
+ }.should.raise(SyntaxError, /unexpected|expected a delimiter after the patterns of an `in` clause/)
end
it "evaluates the case expression once for multiple patterns, caching the result" do
@@ -336,7 +336,7 @@ describe "Pattern matching" do
case [0, 1]
in [0, 1] if false
end
- }.should raise_error(NoMatchingPatternError, /\[0, 1\]/)
+ }.should.raise(NoMatchingPatternError, /\[0, 1\]/)
end
end
@@ -438,7 +438,7 @@ describe "Pattern matching" do
in [a, a]
end
RUBY
- }.should raise_error(SyntaxError, /duplicated variable name/)
+ }.should.raise(SyntaxError, /duplicated variable name/)
end
it "supports existing variables in a pattern specified with ^ operator" do
@@ -474,7 +474,7 @@ describe "Pattern matching" do
false
end
RUBY
- }.should raise_error(SyntaxError, /n: no such local variable/)
+ }.should.raise(SyntaxError, /n: no such local variable/)
end
end
@@ -493,7 +493,7 @@ describe "Pattern matching" do
in [0, 0] | [0, a]
end
RUBY
- }.should raise_error(SyntaxError, /illegal variable in alternative pattern/)
+ }.should.raise(SyntaxError)
end
it "support underscore prefixed variables in alternation" do
@@ -674,7 +674,7 @@ describe "Pattern matching" do
in Object[]
else
end
- }.should raise_error(TypeError, /deconstruct must return Array/)
+ }.should.raise(TypeError, /deconstruct must return Array/)
end
it "accepts a subclass of Array from #deconstruct" do
@@ -870,7 +870,7 @@ 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(SyntaxError, /unexpected|expected a label as the key in the hash pattern/)
end
it "does not support string interpolation in keys" do
@@ -880,7 +880,7 @@ describe "Pattern matching" do
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(SyntaxError, /symbol literal with interpolation is not allowed|expected a label as the key in the hash pattern/)
end
it "raise SyntaxError when keys duplicate in pattern" do
@@ -890,7 +890,7 @@ describe "Pattern matching" do
in {a: 1, b: 2, a: 3}
end
RUBY
- }.should raise_error(SyntaxError, /duplicated key name/)
+ }.should.raise(SyntaxError, /duplicated key name/)
end
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
@@ -969,7 +969,7 @@ describe "Pattern matching" do
case obj
in Object[a: 1]
end
- }.should raise_error(TypeError, /deconstruct_keys must return Hash/)
+ }.should.raise(TypeError, /deconstruct_keys must return Hash/)
end
it "does not match object if #deconstruct_keys method returns Hash with non-symbol keys" do
diff --git a/spec/ruby/language/precedence_spec.rb b/spec/ruby/language/precedence_spec.rb
index 5e606c16d8..edb990525e 100644
--- a/spec/ruby/language/precedence_spec.rb
+++ b/spec/ruby/language/precedence_spec.rb
@@ -251,12 +251,12 @@ describe "Operators" do
end
it "<=> == === != =~ !~ are non-associative" do
- -> { eval("1 <=> 2 <=> 3") }.should raise_error(SyntaxError)
- -> { eval("1 == 2 == 3") }.should raise_error(SyntaxError)
- -> { eval("1 === 2 === 3") }.should raise_error(SyntaxError)
- -> { eval("1 != 2 != 3") }.should raise_error(SyntaxError)
- -> { eval("1 =~ 2 =~ 3") }.should raise_error(SyntaxError)
- -> { eval("1 !~ 2 !~ 3") }.should raise_error(SyntaxError)
+ -> { eval("1 <=> 2 <=> 3") }.should.raise(SyntaxError)
+ -> { eval("1 == 2 == 3") }.should.raise(SyntaxError)
+ -> { eval("1 === 2 === 3") }.should.raise(SyntaxError)
+ -> { eval("1 != 2 != 3") }.should.raise(SyntaxError)
+ -> { eval("1 =~ 2 =~ 3") }.should.raise(SyntaxError)
+ -> { eval("1 !~ 2 !~ 3") }.should.raise(SyntaxError)
end
it "<=> == === != =~ !~ have higher precedence than &&" do
@@ -290,8 +290,8 @@ describe "Operators" do
end
it ".. ... are non-associative" do
- -> { eval("1..2..3") }.should raise_error(SyntaxError)
- -> { eval("1...2...3") }.should raise_error(SyntaxError)
+ -> { eval("1..2..3") }.should.raise(SyntaxError)
+ -> { eval("1...2...3") }.should.raise(SyntaxError)
end
it ".. ... have higher precedence than ? :" do
diff --git a/spec/ruby/language/predefined_spec.rb b/spec/ruby/language/predefined_spec.rb
index d90e19858a..f14f8ba93e 100644
--- a/spec/ruby/language/predefined_spec.rb
+++ b/spec/ruby/language/predefined_spec.rb
@@ -40,12 +40,12 @@ require 'stringio'
describe "Predefined global $~" do
it "is set to contain the MatchData object of the last match if successful" do
md = /foo/.match 'foo'
- $~.should be_kind_of(MatchData)
- $~.should equal md
+ $~.should.is_a?(MatchData)
+ $~.should.equal? md
/bar/ =~ 'bar'
- $~.should be_kind_of(MatchData)
- $~.should_not equal md
+ $~.should.is_a?(MatchData)
+ $~.should_not.equal? md
end
it "is set to nil if the last match was unsuccessful" do
@@ -87,10 +87,10 @@ describe "Predefined global $~" do
$~ = nil
$~.should == nil
$~ = /foo/.match("foo")
- $~.should be_an_instance_of(MatchData)
+ $~.should.instance_of?(MatchData)
- -> { $~ = Object.new }.should raise_error(TypeError, 'wrong argument type Object (expected MatchData)')
- -> { $~ = 1 }.should raise_error(TypeError, 'wrong argument type Integer (expected MatchData)')
+ -> { $~ = Object.new }.should.raise(TypeError, 'wrong argument type Object (expected MatchData)')
+ -> { $~ = 1 }.should.raise(TypeError, 'wrong argument type Integer (expected MatchData)')
end
it "changes the value of derived capture globals when assigned" do
@@ -135,20 +135,20 @@ describe "Predefined global $&" do
it "sets the encoding to the encoding of the source String" do
"abc".dup.force_encoding(Encoding::EUC_JP) =~ /b/
- $&.encoding.should equal(Encoding::EUC_JP)
+ $&.encoding.should.equal?(Encoding::EUC_JP)
end
it "is read-only" do
-> {
eval %q{$& = ""}
- }.should raise_error(SyntaxError, /Can't set variable \$&/)
+ }.should.raise(SyntaxError, /Can't set variable \$&/)
end
it "is read-only when aliased" do
alias $predefined_spec_ampersand $&
-> {
$predefined_spec_ampersand = ""
- }.should raise_error(NameError, '$predefined_spec_ampersand is a read-only variable')
+ }.should.raise(NameError, '$predefined_spec_ampersand is a read-only variable')
end
end
@@ -161,25 +161,25 @@ describe "Predefined global $`" do
it "sets the encoding to the encoding of the source String" do
"abc".dup.force_encoding(Encoding::EUC_JP) =~ /b/
- $`.encoding.should equal(Encoding::EUC_JP)
+ $`.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/
- $`.encoding.should equal(Encoding::ISO_8859_1)
+ $`.encoding.should.equal?(Encoding::ISO_8859_1)
end
it "is read-only" do
-> {
eval %q{$` = ""}
- }.should raise_error(SyntaxError, /Can't set variable \$`/)
+ }.should.raise(SyntaxError, /Can't set variable \$`/)
end
it "is read-only when aliased" do
alias $predefined_spec_backquote $`
-> {
$predefined_spec_backquote = ""
- }.should raise_error(NameError, '$predefined_spec_backquote is a read-only variable')
+ }.should.raise(NameError, '$predefined_spec_backquote is a read-only variable')
end
end
@@ -192,25 +192,25 @@ describe "Predefined global $'" do
it "sets the encoding to the encoding of the source String" do
"abc".dup.force_encoding(Encoding::EUC_JP) =~ /b/
- $'.encoding.should equal(Encoding::EUC_JP)
+ $'.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/
- $'.encoding.should equal(Encoding::ISO_8859_1)
+ $'.encoding.should.equal?(Encoding::ISO_8859_1)
end
it "is read-only" do
-> {
eval %q{$' = ""}
- }.should raise_error(SyntaxError, /Can't set variable \$'/)
+ }.should.raise(SyntaxError, /Can't set variable \$'/)
end
it "is read-only when aliased" do
alias $predefined_spec_single_quote $'
-> {
$predefined_spec_single_quote = ""
- }.should raise_error(NameError, '$predefined_spec_single_quote is a read-only variable')
+ }.should.raise(NameError, '$predefined_spec_single_quote is a read-only variable')
end
end
@@ -228,20 +228,20 @@ describe "Predefined global $+" do
it "sets the encoding to the encoding of the source String" do
"abc".dup.force_encoding(Encoding::EUC_JP) =~ /(b)/
- $+.encoding.should equal(Encoding::EUC_JP)
+ $+.encoding.should.equal?(Encoding::EUC_JP)
end
it "is read-only" do
-> {
eval %q{$+ = ""}
- }.should raise_error(SyntaxError, /Can't set variable \$\+/)
+ }.should.raise(SyntaxError, /Can't set variable \$\+/)
end
it "is read-only when aliased" do
alias $predefined_spec_plus $+
-> {
$predefined_spec_plus = ""
- }.should raise_error(NameError, '$predefined_spec_plus is a read-only variable')
+ }.should.raise(NameError, '$predefined_spec_plus is a read-only variable')
end
end
@@ -268,7 +268,7 @@ describe "Predefined globals $1..N" do
it "sets the encoding to the encoding of the source String" do
"abc".dup.force_encoding(Encoding::EUC_JP) =~ /(b)/
- $1.encoding.should equal(Encoding::EUC_JP)
+ $1.encoding.should.equal?(Encoding::EUC_JP)
end
end
@@ -282,16 +282,16 @@ describe "Predefined global $stdout" do
end
it "raises TypeError error if assigned to nil" do
- -> { $stdout = nil }.should raise_error(TypeError, '$stdout must have write method, NilClass given')
+ -> { $stdout = nil }.should.raise(TypeError, '$stdout must have write method, NilClass given')
end
it "raises TypeError error if assigned to object that doesn't respond to #write" do
obj = mock('object')
- -> { $stdout = obj }.should raise_error(TypeError)
+ -> { $stdout = obj }.should.raise(TypeError)
obj.stub!(:write)
$stdout = obj
- $stdout.should equal(obj)
+ $stdout.should.equal?(obj)
end
end
@@ -309,7 +309,7 @@ describe "Predefined global $!" do
it "is read-only" do
-> {
$! = []
- }.should raise_error(NameError, '$! is a read-only variable')
+ }.should.raise(NameError, '$! is a read-only variable')
end
# See http://jira.codehaus.org/browse/JRUBY-5550
@@ -586,7 +586,7 @@ describe "Predefined global $@" do
begin
raise
rescue
- $@.should be_an_instance_of(Array)
+ $@.should.instance_of?(Array)
$@.should == $!.backtrace
end
end
@@ -608,7 +608,7 @@ describe "Predefined global $@" do
begin
raise
rescue
- $@.should be_an_instance_of(Array)
+ $@.should.instance_of?(Array)
$@.should == $!.backtrace
end
end
@@ -636,7 +636,7 @@ describe "Predefined global $@" do
it "cannot be assigned when there is no a rescued exception" do
-> {
$@ = []
- }.should raise_error(ArgumentError, '$! not set')
+ }.should.raise(ArgumentError, '$! not set')
end
end
@@ -687,22 +687,22 @@ describe "Predefined global $/" do
$VERBOSE = @verbose
end
- ruby_version_is ""..."3.5" do
+ ruby_version_is ""..."4.0" do
it "can be assigned a String" do
str = +"abc"
$/ = str
- $/.should equal(str)
+ $/.should.equal?(str)
end
end
- ruby_version_is "3.5" do
+ ruby_version_is "4.0" do
it "makes a new frozen String from the assigned String" do
string_subclass = Class.new(String)
str = string_subclass.new("abc")
str.instance_variable_set(:@ivar, 1)
$/ = str
$/.should.frozen?
- $/.should be_an_instance_of(String)
+ $/.should.instance_of?(String)
$/.should_not.instance_variable_defined?(:@ivar)
$/.should == str
end
@@ -717,12 +717,13 @@ describe "Predefined global $/" do
it "assigns the given String if it's frozen and has no instance variables" do
str = "abc".freeze
$/ = str
- $/.should equal(str)
+ $/.should.equal?(str)
end
end
+
it "can be assigned nil" do
$/ = nil
- $/.should be_nil
+ $/.should == nil
end
it "returns the value assigned" do
@@ -731,22 +732,26 @@ describe "Predefined global $/" do
it "changes $-0" do
$/ = "xyz"
- $-0.should equal($/)
+ $-0.should.equal?($/)
end
it "does not call #to_str to convert the object to a String" do
obj = mock("$/ value")
obj.should_not_receive(:to_str)
- -> { $/ = obj }.should raise_error(TypeError, 'value of $/ must be String')
+ -> { $/ = obj }.should.raise(TypeError, 'value of $/ must be String')
end
it "raises a TypeError if assigned an Integer" do
- -> { $/ = 1 }.should raise_error(TypeError, 'value of $/ must be String')
+ -> { $/ = 1 }.should.raise(TypeError, 'value of $/ must be String')
end
it "raises a TypeError if assigned a boolean" do
- -> { $/ = true }.should raise_error(TypeError, 'value of $/ must be String')
+ -> { $/ = true }.should.raise(TypeError, 'value of $/ must be String')
+ end
+
+ it "warns if assigned non-nil" do
+ -> { $/ = "_" }.should complain(/warning: (?:non-nil )?[`']\$\/' is deprecated/)
end
end
@@ -763,22 +768,22 @@ describe "Predefined global $-0" do
$VERBOSE = @verbose
end
- ruby_version_is ""..."3.5" do
+ ruby_version_is ""..."4.0" do
it "can be assigned a String" do
str = +"abc"
$-0 = str
- $-0.should equal(str)
+ $-0.should.equal?(str)
end
end
- ruby_version_is "3.5" do
+ ruby_version_is "4.0" do
it "makes a new frozen String from the assigned String" do
string_subclass = Class.new(String)
str = string_subclass.new("abc")
str.instance_variable_set(:@ivar, 1)
$-0 = str
$-0.should.frozen?
- $-0.should be_an_instance_of(String)
+ $-0.should.instance_of?(String)
$-0.should_not.instance_variable_defined?(:@ivar)
$-0.should == str
end
@@ -793,13 +798,13 @@ describe "Predefined global $-0" do
it "assigns the given String if it's frozen and has no instance variables" do
str = "abc".freeze
$-0 = str
- $-0.should equal(str)
+ $-0.should.equal?(str)
end
end
it "can be assigned nil" do
$-0 = nil
- $-0.should be_nil
+ $-0.should == nil
end
it "returns the value assigned" do
@@ -808,22 +813,26 @@ describe "Predefined global $-0" do
it "changes $/" do
$-0 = "xyz"
- $/.should equal($-0)
+ $/.should.equal?($-0)
end
it "does not call #to_str to convert the object to a String" do
obj = mock("$-0 value")
obj.should_not_receive(:to_str)
- -> { $-0 = obj }.should raise_error(TypeError, 'value of $-0 must be String')
+ -> { $-0 = obj }.should.raise(TypeError, 'value of $-0 must be String')
end
it "raises a TypeError if assigned an Integer" do
- -> { $-0 = 1 }.should raise_error(TypeError, 'value of $-0 must be String')
+ -> { $-0 = 1 }.should.raise(TypeError, 'value of $-0 must be String')
end
it "raises a TypeError if assigned a boolean" do
- -> { $-0 = true }.should raise_error(TypeError, 'value of $-0 must be String')
+ -> { $-0 = true }.should.raise(TypeError, 'value of $-0 must be String')
+ end
+
+ it "warns if assigned non-nil" do
+ -> { $-0 = "_" }.should complain(/warning: (?:non-nil )?[`']\$-0' is deprecated/)
end
end
@@ -841,12 +850,12 @@ describe "Predefined global $\\" do
it "can be assigned a String" do
str = "abc"
$\ = str
- $\.should equal(str)
+ $\.should.equal?(str)
end
it "can be assigned nil" do
$\ = nil
- $\.should be_nil
+ $\.should == nil
end
it "returns the value assigned" do
@@ -857,12 +866,16 @@ describe "Predefined global $\\" do
obj = mock("$\\ value")
obj.should_not_receive(:to_str)
- -> { $\ = obj }.should raise_error(TypeError, 'value of $\ must be String')
+ -> { $\ = obj }.should.raise(TypeError, 'value of $\ must be String')
end
it "raises a TypeError if assigned not String" do
- -> { $\ = 1 }.should raise_error(TypeError, 'value of $\ must be String')
- -> { $\ = true }.should raise_error(TypeError, 'value of $\ must be String')
+ -> { $\ = 1 }.should.raise(TypeError, 'value of $\ must be String')
+ -> { $\ = true }.should.raise(TypeError, 'value of $\ must be String')
+ end
+
+ it "warns if assigned non-nil" do
+ -> { $\ = "_" }.should complain(/warning: (?:non-nil )?[`']\$\\' is deprecated/)
end
end
@@ -872,15 +885,15 @@ describe "Predefined global $," do
end
it "defaults to nil" do
- $,.should be_nil
+ $,.should == nil
end
it "raises TypeError if assigned a non-String" do
- -> { $, = Object.new }.should raise_error(TypeError, 'value of $, must be String')
+ -> { $, = Object.new }.should.raise(TypeError, 'value of $, must be String')
end
it "warns if assigned non-nil" do
- -> { $, = "_" }.should complain(/warning: [`']\$,' is deprecated/)
+ -> { $, = "_" }.should complain(/warning: (?:non-nil )?[`']\$,' is deprecated/)
end
end
@@ -907,7 +920,7 @@ describe "Predefined global $." do
obj = mock("bad-value")
obj.should_receive(:to_int).and_return('abc')
- -> { $. = obj }.should raise_error(TypeError)
+ -> { $. = obj }.should.raise(TypeError)
end
end
@@ -917,7 +930,7 @@ describe "Predefined global $;" do
end
it "warns if assigned non-nil" do
- -> { $; = "_" }.should complain(/warning: [`']\$;' is deprecated/)
+ -> { $; = "_" }.should complain(/warning: (?:non-nil )?[`']\$;' is deprecated/)
end
end
@@ -972,7 +985,7 @@ describe "Predefined global $_" do
end
Thread.pass until running
- $_.should be_nil
+ $_.should == nil
thr.join
end
@@ -1043,7 +1056,7 @@ describe "Execution variable $:" do
end
it "does not include the current directory" do
- $:.should_not include(".")
+ $:.should_not.include?(".")
end
it "is the same object as $LOAD_PATH and $-I" do
@@ -1053,7 +1066,7 @@ describe "Execution variable $:" do
it "can be changed via <<" do
$: << "foo"
- $:.should include("foo")
+ $:.should.include?("foo")
ensure
$:.delete("foo")
end
@@ -1061,15 +1074,15 @@ describe "Execution variable $:" do
it "is read-only" do
-> {
$: = []
- }.should raise_error(NameError, '$: is a read-only variable')
+ }.should.raise(NameError, '$: is a read-only variable')
-> {
$LOAD_PATH = []
- }.should raise_error(NameError, '$LOAD_PATH is a read-only variable')
+ }.should.raise(NameError, '$LOAD_PATH is a read-only variable')
-> {
$-I = []
- }.should raise_error(NameError, '$-I is a read-only variable')
+ }.should.raise(NameError, '$-I is a read-only variable')
end
it "default $LOAD_PATH entries until sitelibdir included have @gem_prelude_index set" do
@@ -1084,24 +1097,24 @@ describe "Execution variable $:" do
idx = $:.index(RbConfig::CONFIG['sitelibdir'])
end
- $:[idx..-1].all? { |p| p.instance_variable_defined?(:@gem_prelude_index) }.should be_true
- $:[0...idx].all? { |p| !p.instance_variable_defined?(:@gem_prelude_index) }.should be_true
+ $:[idx..-1].all? { |p| p.instance_variable_defined?(:@gem_prelude_index) }.should == true
+ $:[0...idx].all? { |p| !p.instance_variable_defined?(:@gem_prelude_index) }.should == true
end
end
describe "Global variable $\"" do
- it "is an alias for $LOADED_FEATURES" do
- $".should equal $LOADED_FEATURES
+ it "is an alias of $LOADED_FEATURES" do
+ $".should.equal? $LOADED_FEATURES
end
it "is read-only" do
-> {
$" = []
- }.should raise_error(NameError, '$" is a read-only variable')
+ }.should.raise(NameError, '$" is a read-only variable')
-> {
$LOADED_FEATURES = []
- }.should raise_error(NameError, '$LOADED_FEATURES is a read-only variable')
+ }.should.raise(NameError, '$LOADED_FEATURES is a read-only variable')
end
end
@@ -1109,7 +1122,7 @@ describe "Global variable $<" do
it "is read-only" do
-> {
$< = nil
- }.should raise_error(NameError, '$< is a read-only variable')
+ }.should.raise(NameError, '$< is a read-only variable')
end
end
@@ -1117,7 +1130,7 @@ describe "Global variable $FILENAME" do
it "is read-only" do
-> {
$FILENAME = "-"
- }.should raise_error(NameError, '$FILENAME is a read-only variable')
+ }.should.raise(NameError, '$FILENAME is a read-only variable')
end
end
@@ -1125,30 +1138,30 @@ describe "Global variable $?" do
it "is read-only" do
-> {
$? = nil
- }.should raise_error(NameError, '$? is a read-only variable')
+ }.should.raise(NameError, '$? is a read-only variable')
end
it "is thread-local" do
system(ruby_cmd('exit 0'))
- Thread.new { $?.should be_nil }.join
+ Thread.new { $?.should == nil }.join
end
end
describe "Global variable $-a" do
it "is read-only" do
- -> { $-a = true }.should raise_error(NameError, '$-a is a read-only variable')
+ -> { $-a = true }.should.raise(NameError, '$-a is a read-only variable')
end
end
describe "Global variable $-l" do
it "is read-only" do
- -> { $-l = true }.should raise_error(NameError, '$-l is a read-only variable')
+ -> { $-l = true }.should.raise(NameError, '$-l is a read-only variable')
end
end
describe "Global variable $-p" do
it "is read-only" do
- -> { $-p = true }.should raise_error(NameError, '$-p is a read-only variable')
+ -> { $-p = true }.should.raise(NameError, '$-p is a read-only variable')
end
end
@@ -1163,9 +1176,9 @@ describe "Global variable $-d" do
it "is an alias of $DEBUG" do
$DEBUG = true
- $-d.should be_true
+ $-d.should == true
$-d = false
- $DEBUG.should be_false
+ $DEBUG.should == false
end
end
@@ -1179,24 +1192,24 @@ describe "Global variable $VERBOSE" do
end
it "is false by default" do
- $VERBOSE.should be_false
+ $VERBOSE.should == false
end
it "converts truthy values to true" do
[true, 1, 0, [], ""].each do |true_value|
$VERBOSE = true_value
- $VERBOSE.should be_true
+ $VERBOSE.should == true
end
end
it "allows false" do
$VERBOSE = false
- $VERBOSE.should be_false
+ $VERBOSE.should == false
end
it "allows nil without coercing to false" do
$VERBOSE = nil
- $VERBOSE.should be_nil
+ $VERBOSE.should == nil
end
end
@@ -1211,9 +1224,9 @@ describe :verbose_global_alias, shared: true do
it "is an alias of $VERBOSE" do
$VERBOSE = true
- eval(@method).should be_true
+ eval(@method).should == true
eval("#{@method} = false")
- $VERBOSE.should be_false
+ $VERBOSE.should == false
end
end
@@ -1250,7 +1263,7 @@ describe "Global variable $0" do
it "actually sets the program name" do
title = "rubyspec-dollar0-test"
$0 = title
- `ps -ocommand= -p#{$$}`.should include(title)
+ `ps -ocommand= -p#{$$}`.should.include?(title)
end
end
@@ -1259,7 +1272,7 @@ describe "Global variable $0" do
end
it "raises a TypeError when not given an object that can be coerced to a String" do
- -> { $0 = nil }.should raise_error(TypeError)
+ -> { $0 = nil }.should.raise(TypeError)
end
end
@@ -1295,37 +1308,37 @@ end
describe "The predefined standard object nil" do
it "is an instance of NilClass" do
- nil.should be_kind_of(NilClass)
+ nil.should.is_a?(NilClass)
end
it "raises a SyntaxError if assigned to" do
- -> { eval("nil = true") }.should raise_error(SyntaxError, /Can't assign to nil/)
+ -> { eval("nil = true") }.should.raise(SyntaxError, /Can't assign to nil/)
end
end
describe "The predefined standard object true" do
it "is an instance of TrueClass" do
- true.should be_kind_of(TrueClass)
+ true.should.is_a?(TrueClass)
end
it "raises a SyntaxError if assigned to" do
- -> { eval("true = false") }.should raise_error(SyntaxError, /Can't assign to true/)
+ -> { eval("true = false") }.should.raise(SyntaxError, /Can't assign to true/)
end
end
describe "The predefined standard object false" do
it "is an instance of FalseClass" do
- false.should be_kind_of(FalseClass)
+ false.should.is_a?(FalseClass)
end
it "raises a SyntaxError if assigned to" do
- -> { eval("false = nil") }.should raise_error(SyntaxError, /Can't assign to false/)
+ -> { eval("false = nil") }.should.raise(SyntaxError, /Can't assign to false/)
end
end
describe "The self pseudo-variable" do
it "raises a SyntaxError if assigned to" do
- -> { eval("self = 1") }.should raise_error(SyntaxError, /Can't change the value of self/)
+ -> { eval("self = 1") }.should.raise(SyntaxError, /Can't change the value of self/)
end
end
@@ -1420,21 +1433,21 @@ describe "The predefined global constant" do
describe "STDIN" do
platform_is_not :windows do
it "has the same external encoding as Encoding.default_external" do
- STDIN.external_encoding.should equal(Encoding.default_external)
+ STDIN.external_encoding.should.equal?(Encoding.default_external)
end
it "has the same external encoding as Encoding.default_external when that encoding is changed" do
Encoding.default_external = Encoding::ISO_8859_16
- STDIN.external_encoding.should equal(Encoding::ISO_8859_16)
+ STDIN.external_encoding.should.equal?(Encoding::ISO_8859_16)
end
it "has nil for the internal encoding" do
- STDIN.internal_encoding.should be_nil
+ STDIN.internal_encoding.should == nil
end
it "has nil for the internal encoding despite Encoding.default_internal being changed" do
Encoding.default_internal = Encoding::IBM437
- STDIN.internal_encoding.should be_nil
+ STDIN.internal_encoding.should == nil
end
end
@@ -1454,12 +1467,12 @@ describe "The predefined global constant" do
describe "STDOUT" do
it "has nil for the external encoding" do
- STDOUT.external_encoding.should be_nil
+ STDOUT.external_encoding.should == nil
end
it "has nil for the external encoding despite Encoding.default_external being changed" do
Encoding.default_external = Encoding::ISO_8859_1
- STDOUT.external_encoding.should be_nil
+ STDOUT.external_encoding.should == nil
end
it "has the encodings set by #set_encoding" do
@@ -1469,23 +1482,23 @@ describe "The predefined global constant" do
end
it "has nil for the internal encoding" do
- STDOUT.internal_encoding.should be_nil
+ STDOUT.internal_encoding.should == nil
end
it "has nil for the internal encoding despite Encoding.default_internal being changed" do
Encoding.default_internal = Encoding::IBM437
- STDOUT.internal_encoding.should be_nil
+ STDOUT.internal_encoding.should == nil
end
end
describe "STDERR" do
it "has nil for the external encoding" do
- STDERR.external_encoding.should be_nil
+ STDERR.external_encoding.should == nil
end
it "has nil for the external encoding despite Encoding.default_external being changed" do
Encoding.default_external = Encoding::ISO_8859_1
- STDERR.external_encoding.should be_nil
+ STDERR.external_encoding.should == nil
end
it "has the encodings set by #set_encoding" do
@@ -1495,12 +1508,12 @@ describe "The predefined global constant" do
end
it "has nil for the internal encoding" do
- STDERR.internal_encoding.should be_nil
+ STDERR.internal_encoding.should == nil
end
it "has nil for the internal encoding despite Encoding.default_internal being changed" do
Encoding.default_internal = Encoding::IBM437
- STDERR.internal_encoding.should be_nil
+ STDERR.internal_encoding.should == nil
end
end
@@ -1531,7 +1544,7 @@ describe "$LOAD_PATH.resolve_feature_path" do
end
it "return nil if feature cannot be found" do
- $LOAD_PATH.resolve_feature_path('noop').should be_nil
+ $LOAD_PATH.resolve_feature_path('noop').should == nil
end
end
diff --git a/spec/ruby/language/private_spec.rb b/spec/ruby/language/private_spec.rb
index b04aa25c9e..94b56fee5b 100644
--- a/spec/ruby/language/private_spec.rb
+++ b/spec/ruby/language/private_spec.rb
@@ -4,12 +4,12 @@ require_relative 'fixtures/private'
describe "The private keyword" do
it "marks following methods as being private" do
a = Private::A.new
- a.methods.should_not include(:bar)
- -> { a.bar }.should raise_error(NoMethodError)
+ a.methods.should_not.include?(:bar)
+ -> { a.bar }.should.raise(NoMethodError)
b = Private::B.new
- b.methods.should_not include(:bar)
- -> { b.bar }.should raise_error(NoMethodError)
+ b.methods.should_not.include?(:bar)
+ -> { b.bar }.should.raise(NoMethodError)
end
# def expr.meth() methods are always public
@@ -19,15 +19,15 @@ describe "The private keyword" do
it "is overridden when a new class is opened" do
c = Private::B::C.new
- c.methods.should include(:baz)
+ c.methods.should.include?(:baz)
c.baz
Private::B.public_class_method1.should == 1
- -> { Private::B.private_class_method1 }.should raise_error(NoMethodError)
+ -> { Private::B.private_class_method1 }.should.raise(NoMethodError)
end
it "is no longer in effect when the class is closed" do
b = Private::B.new
- b.methods.should include(:foo)
+ b.methods.should.include?(:foo)
b.foo
end
@@ -42,7 +42,7 @@ describe "The private keyword" do
klass.class_eval do
private :foo
end
- -> { f.foo }.should raise_error(NoMethodError)
+ -> { f.foo }.should.raise(NoMethodError)
end
it "changes visibility of previously called methods with same send/call site" do
@@ -56,12 +56,12 @@ describe "The private keyword" do
end
end
end
- }.should raise_error(NoMethodError)
+ }.should.raise(NoMethodError)
end
it "changes the visibility of the existing method in the subclass" do
::Private::A.new.foo.should == 'foo'
- -> { ::Private::H.new.foo }.should raise_error(NoMethodError)
+ -> { ::Private::H.new.foo }.should.raise(NoMethodError)
::Private::H.new.send(:foo).should == 'foo'
end
end
diff --git a/spec/ruby/language/proc_spec.rb b/spec/ruby/language/proc_spec.rb
index ca9a13aa61..53a21d6b85 100644
--- a/spec/ruby/language/proc_spec.rb
+++ b/spec/ruby/language/proc_spec.rb
@@ -22,7 +22,7 @@ describe "A Proc" do
end
it "raises an ArgumentError if a value is passed" do
- lambda { @l.call(0) }.should raise_error(ArgumentError)
+ lambda { @l.call(0) }.should.raise(ArgumentError)
end
end
@@ -36,7 +36,7 @@ describe "A Proc" do
end
it "raises an ArgumentError if a value is passed" do
- lambda { @l.call(0) }.should raise_error(ArgumentError)
+ lambda { @l.call(0) }.should.raise(ArgumentError)
end
end
@@ -57,11 +57,11 @@ describe "A Proc" do
obj = mock("block yield to_ary")
obj.should_not_receive(:to_ary)
- @l.call(obj).should equal(obj)
+ @l.call(obj).should.equal?(obj)
end
it "raises an ArgumentError if no value is passed" do
- lambda { @l.call }.should raise_error(ArgumentError)
+ lambda { @l.call }.should.raise(ArgumentError)
end
end
@@ -71,11 +71,11 @@ describe "A Proc" do
end
it "raises an ArgumentError if passed no values" do
- lambda { @l.call }.should raise_error(ArgumentError)
+ lambda { @l.call }.should.raise(ArgumentError)
end
it "raises an ArgumentError if passed one value" do
- lambda { @l.call(0) }.should raise_error(ArgumentError)
+ lambda { @l.call(0) }.should.raise(ArgumentError)
end
it "assigns the values passed to the arguments" do
@@ -86,7 +86,7 @@ describe "A Proc" do
obj = mock("proc call to_ary")
obj.should_not_receive(:to_ary)
- lambda { @l.call(obj) }.should raise_error(ArgumentError)
+ lambda { @l.call(obj) }.should.raise(ArgumentError)
end
end
@@ -96,7 +96,7 @@ describe "A Proc" do
end
it "raises an ArgumentError if passed no values" do
- lambda { @l.call }.should raise_error(ArgumentError)
+ lambda { @l.call }.should.raise(ArgumentError)
end
it "does not destructure a single Array value yielded" do
@@ -179,11 +179,11 @@ describe "A Proc" do
end
it "raises an ArgumentError when passed no values" do
- lambda { @l.call }.should raise_error(ArgumentError)
+ lambda { @l.call }.should.raise(ArgumentError)
end
it "raises an ArgumentError when passed more than one value" do
- lambda { @l.call(1, 2) }.should raise_error(ArgumentError)
+ lambda { @l.call(1, 2) }.should.raise(ArgumentError)
end
it "assigns the argument the value passed" do
@@ -208,7 +208,7 @@ describe "A Proc" do
end
it "raises an ArgumentError when passed no values" do
- lambda { @l.call }.should raise_error(ArgumentError)
+ lambda { @l.call }.should.raise(ArgumentError)
end
it "destructures a single Array value yielded" do
@@ -226,7 +226,7 @@ describe "A Proc" do
obj = mock("block yield to_ary invalid")
obj.should_receive(:to_ary).and_return(1)
- lambda { @l.call(obj) }.should raise_error(TypeError)
+ lambda { @l.call(obj) }.should.raise(TypeError)
end
end
@@ -243,7 +243,25 @@ describe "A Proc" do
describe "taking |required keyword arguments, **kw| arguments" do
it "raises ArgumentError for missing required argument" do
p = proc { |a:, **kw| [a, kw] }
- -> { p.call() }.should raise_error(ArgumentError)
+ -> { p.call() }.should.raise(ArgumentError)
end
end
+
+ evaluate <<-ruby do
+ @p = proc { |**nil| :ok }
+ ruby
+
+ @p.call().should == :ok
+ -> { @p.call(a: 1) }.should.raise(ArgumentError, 'no keywords accepted')
+ -> { @p.call(**{a: 1}) }.should.raise(ArgumentError, 'no keywords accepted')
+ -> { @p.call("a" => 1) }.should.raise(ArgumentError, 'no keywords accepted')
+ end
+
+ evaluate <<-ruby do
+ @p = proc { |a, **nil| a }
+ ruby
+
+ @p.call({a: 1}).should == {a: 1}
+ -> { @p.call(a: 1) }.should.raise(ArgumentError, 'no keywords accepted')
+ end
end
diff --git a/spec/ruby/language/redo_spec.rb b/spec/ruby/language/redo_spec.rb
index 57532553b3..9b14c5add1 100644
--- a/spec/ruby/language/redo_spec.rb
+++ b/spec/ruby/language/redo_spec.rb
@@ -60,7 +60,7 @@ describe "The redo statement" do
it "is invalid and raises a SyntaxError" do
-> {
eval("def m; redo; end")
- }.should raise_error(SyntaxError)
+ }.should.raise(SyntaxError)
end
end
end
diff --git a/spec/ruby/language/regexp/anchors_spec.rb b/spec/ruby/language/regexp/anchors_spec.rb
index cdc06c0b4d..8e597b65e8 100644
--- a/spec/ruby/language/regexp/anchors_spec.rb
+++ b/spec/ruby/language/regexp/anchors_spec.rb
@@ -7,8 +7,8 @@ describe "Regexps with anchors" do
/^foo/.match("foo").to_a.should == ["foo"]
/^bar/.match("foo\nbar").to_a.should == ["bar"]
# Basic non-matching
- /^foo/.match(" foo").should be_nil
- /foo^/.match("foo\n\n\n").should be_nil
+ /^foo/.match(" foo").should == nil
+ /foo^/.match("foo\n\n\n").should == nil
# A bit advanced
/^^^foo/.match("foo").to_a.should == ["foo"]
@@ -16,8 +16,8 @@ describe "Regexps with anchors" do
(/($^)($^)/ =~ "foo\n\n").should == "foo\n".size and $~.to_a.should == ["", "", ""]
# Different start of line chars
- /^bar/.match("foo\rbar").should be_nil
- /^bar/.match("foo\0bar").should be_nil
+ /^bar/.match("foo\rbar").should == nil
+ /^bar/.match("foo\0bar").should == nil
# Trivial
/^/.match("foo").to_a.should == [""]
@@ -29,7 +29,7 @@ describe "Regexps with anchors" do
end
it "does not match ^ after trailing \\n" do
- /^(?!\A)/.match("foo\n").should be_nil # There is no (empty) line after a trailing \n
+ /^(?!\A)/.match("foo\n").should == nil # There is no (empty) line after a trailing \n
end
it "supports $ (line end anchor)" do
@@ -37,16 +37,16 @@ describe "Regexps with anchors" do
/foo$/.match("foo").to_a.should == ["foo"]
/foo$/.match("foo\nbar").to_a.should == ["foo"]
# Basic non-matching
- /foo$/.match("foo ").should be_nil
- /$foo/.match("\n\n\nfoo").should be_nil
+ /foo$/.match("foo ").should == nil
+ /$foo/.match("\n\n\nfoo").should == nil
# A bit advanced
/foo$$$/.match("foo").to_a.should == ["foo"]
(/[^o]$/ =~ "foo\n\n").should == ("foo\n".size - 1) and $~.to_a.should == ["\n"]
# Different end of line chars
- /foo$/.match("foo\r\nbar").should be_nil
- /foo$/.match("foo\0bar").should be_nil
+ /foo$/.match("foo\r\nbar").should == nil
+ /foo$/.match("foo\0bar").should == nil
# Trivial
(/$/ =~ "foo").should == "foo".size and $~.to_a.should == [""]
@@ -61,15 +61,15 @@ describe "Regexps with anchors" do
# Basic matching
/\Afoo/.match("foo").to_a.should == ["foo"]
# Basic non-matching
- /\Abar/.match("foo\nbar").should be_nil
- /\Afoo/.match(" foo").should be_nil
+ /\Abar/.match("foo\nbar").should == nil
+ /\Afoo/.match(" foo").should == nil
# A bit advanced
/\A\A\Afoo/.match("foo").to_a.should == ["foo"]
/(\A\Z)(\A\Z)/.match("").to_a.should == ["", "", ""]
# Different start of line chars
- /\Abar/.match("foo\0bar").should be_nil
+ /\Abar/.match("foo\0bar").should == nil
# Grouping
/(\Afoo)/.match("foo").to_a.should == ["foo", "foo"]
@@ -81,8 +81,8 @@ describe "Regexps with anchors" do
/foo\Z/.match("foo").to_a.should == ["foo"]
/foo\Z/.match("foo\n").to_a.should == ["foo"]
# Basic non-matching
- /foo\Z/.match("foo\nbar").should be_nil
- /foo\Z/.match("foo ").should be_nil
+ /foo\Z/.match("foo\nbar").should == nil
+ /foo\Z/.match("foo ").should == nil
# A bit advanced
/foo\Z\Z\Z/.match("foo\n").to_a.should == ["foo"]
@@ -90,8 +90,8 @@ describe "Regexps with anchors" do
(/(\z\Z)(\z\Z)/ =~ "foo\n").should == "foo\n".size and $~.to_a.should == ["", "", ""]
# Different end of line chars
- /foo\Z/.match("foo\0bar").should be_nil
- /foo\Z/.match("foo\r\n").should be_nil
+ /foo\Z/.match("foo\0bar").should == nil
+ /foo\Z/.match("foo\r\n").should == nil
# Grouping
/(foo\Z)/.match("foo").to_a.should == ["foo", "foo"]
@@ -102,17 +102,17 @@ describe "Regexps with anchors" do
# Basic matching
/foo\z/.match("foo").to_a.should == ["foo"]
# Basic non-matching
- /foo\z/.match("foo\nbar").should be_nil
- /foo\z/.match("foo\n").should be_nil
- /foo\z/.match("foo ").should be_nil
+ /foo\z/.match("foo\nbar").should == nil
+ /foo\z/.match("foo\n").should == nil
+ /foo\z/.match("foo ").should == nil
# A bit advanced
/foo\z\z\z/.match("foo").to_a.should == ["foo"]
(/($\z)($\z)/ =~ "foo").should == "foo".size and $~.to_a.should == ["", "", ""]
# Different end of line chars
- /foo\z/.match("foo\0bar").should be_nil
- /foo\z/.match("foo\r\nbar").should be_nil
+ /foo\z/.match("foo\0bar").should == nil
+ /foo\z/.match("foo\r\nbar").should == nil
# Grouping
/(foo\z)/.match("foo").to_a.should == ["foo", "foo"]
@@ -131,9 +131,9 @@ describe "Regexps with anchors" do
end
/foo\b/.match("foo\0").to_a.should == ["foo"]
# Basic non-matching
- /foo\b/.match("foobar").should be_nil
- /foo\b/.match("foo123").should be_nil
- /foo\b/.match("foo_").should be_nil
+ /foo\b/.match("foobar").should == nil
+ /foo\b/.match("foo123").should == nil
+ /foo\b/.match("foo_").should == nil
end
it "supports \\B (non-word-boundary)" do
@@ -142,15 +142,15 @@ describe "Regexps with anchors" do
/foo\B/.match("foo123").to_a.should == ["foo"]
/foo\B/.match("foo_").to_a.should == ["foo"]
# Basic non-matching
- /foo\B/.match("foo").should be_nil
- /foo\B/.match("foo\n").should be_nil
+ /foo\B/.match("foo").should == nil
+ /foo\B/.match("foo\n").should == nil
LanguageSpecs.white_spaces.scan(/./).each do |c|
- /foo\B/.match("foo" + c).should be_nil
+ /foo\B/.match("foo" + c).should == nil
end
LanguageSpecs.non_alphanum_non_space.scan(/./).each do |c|
- /foo\B/.match("foo" + c).should be_nil
+ /foo\B/.match("foo" + c).should == nil
end
- /foo\B/.match("foo\0").should be_nil
+ /foo\B/.match("foo\0").should == nil
end
it "supports (?= ) (positive lookahead)" do
diff --git a/spec/ruby/language/regexp/back-references_spec.rb b/spec/ruby/language/regexp/back-references_spec.rb
index 627c8daace..3b4c5656a2 100644
--- a/spec/ruby/language/regexp/back-references_spec.rb
+++ b/spec/ruby/language/regexp/back-references_spec.rb
@@ -49,7 +49,7 @@ describe "Regexps with back-references" do
it "supports \<n> (backreference to previous group match)" do
/(foo.)\1/.match("foo1foo1").to_a.should == ["foo1foo1", "foo1"]
- /(foo.)\1/.match("foo1foo2").should be_nil
+ /(foo.)\1/.match("foo1foo2").should == nil
end
it "resets nested \<n> backreference before match of outer subexpression" do
@@ -82,7 +82,7 @@ describe "Regexps with back-references" do
end
it "0 is not a valid backreference" do
- -> { Regexp.new("\\k<0>") }.should raise_error(RegexpError)
+ -> { Regexp.new("\\k<0>") }.should.raise(RegexpError)
end
it "allows numeric conditional backreferences" do
@@ -92,7 +92,7 @@ describe "Regexps with back-references" do
end
it "allows either <> or '' in named conditional backreferences" do
- -> { Regexp.new("(?<a>a)(?(a)a|b)") }.should raise_error(RegexpError)
+ -> { Regexp.new("(?<a>a)(?(a)a|b)") }.should.raise(RegexpError)
/(?<a>a)(?(<a>)a|b)/.match("aa").to_a.should == [ "aa", "a" ]
/(?<a>a)(?('a')a|b)/.match("aa").to_a.should == [ "aa", "a" ]
end
@@ -118,32 +118,32 @@ describe "Regexps with back-references" do
end
it "named capture groups invalidate numeric backreferences" do
- -> { Regexp.new("(?<a>a)\\1") }.should raise_error(RegexpError)
- -> { Regexp.new("(?<a>a)\\k<1>") }.should raise_error(RegexpError)
- -> { Regexp.new("(a)(?<a>a)\\1") }.should raise_error(RegexpError)
- -> { Regexp.new("(a)(?<a>a)\\k<1>") }.should raise_error(RegexpError)
+ -> { Regexp.new("(?<a>a)\\1") }.should.raise(RegexpError)
+ -> { Regexp.new("(?<a>a)\\k<1>") }.should.raise(RegexpError)
+ -> { Regexp.new("(a)(?<a>a)\\1") }.should.raise(RegexpError)
+ -> { Regexp.new("(a)(?<a>a)\\k<1>") }.should.raise(RegexpError)
end
it "treats + or - as the beginning of a level specifier in \\k<> backreferences and (?(...)...|...) conditional backreferences" do
- -> { Regexp.new("(?<a+>a)\\k<a+>") }.should raise_error(RegexpError)
- -> { Regexp.new("(?<a+b>a)\\k<a+b>") }.should raise_error(RegexpError)
- -> { Regexp.new("(?<a+1>a)\\k<a+1>") }.should raise_error(RegexpError)
- -> { Regexp.new("(?<a->a)\\k<a->") }.should raise_error(RegexpError)
- -> { Regexp.new("(?<a-b>a)\\k<a-b>") }.should raise_error(RegexpError)
- -> { Regexp.new("(?<a-1>a)\\k<a-1>") }.should raise_error(RegexpError)
-
- -> { Regexp.new("(?<a+>a)(?(<a+>)a|b)") }.should raise_error(RegexpError)
- -> { Regexp.new("(?<a+b>a)(?(<a+b>)a|b)") }.should raise_error(RegexpError)
- -> { Regexp.new("(?<a+1>a)(?(<a+1>)a|b)") }.should raise_error(RegexpError)
- -> { Regexp.new("(?<a->a)(?(<a->)a|b)") }.should raise_error(RegexpError)
- -> { Regexp.new("(?<a-b>a)(?(<a-b>)a|b)") }.should raise_error(RegexpError)
- -> { Regexp.new("(?<a-1>a)(?(<a-1>)a|b)") }.should raise_error(RegexpError)
-
- -> { Regexp.new("(?<a+>a)(?('a+')a|b)") }.should raise_error(RegexpError)
- -> { Regexp.new("(?<a+b>a)(?('a+b')a|b)") }.should raise_error(RegexpError)
- -> { Regexp.new("(?<a+1>a)(?('a+1')a|b)") }.should raise_error(RegexpError)
- -> { Regexp.new("(?<a->a)(?('a-')a|b)") }.should raise_error(RegexpError)
- -> { Regexp.new("(?<a-b>a)(?('a-b')a|b)") }.should raise_error(RegexpError)
- -> { Regexp.new("(?<a-1>a)(?('a-1')a|b)") }.should raise_error(RegexpError)
+ -> { Regexp.new("(?<a+>a)\\k<a+>") }.should.raise(RegexpError)
+ -> { Regexp.new("(?<a+b>a)\\k<a+b>") }.should.raise(RegexpError)
+ -> { Regexp.new("(?<a+1>a)\\k<a+1>") }.should.raise(RegexpError)
+ -> { Regexp.new("(?<a->a)\\k<a->") }.should.raise(RegexpError)
+ -> { Regexp.new("(?<a-b>a)\\k<a-b>") }.should.raise(RegexpError)
+ -> { Regexp.new("(?<a-1>a)\\k<a-1>") }.should.raise(RegexpError)
+
+ -> { Regexp.new("(?<a+>a)(?(<a+>)a|b)") }.should.raise(RegexpError)
+ -> { Regexp.new("(?<a+b>a)(?(<a+b>)a|b)") }.should.raise(RegexpError)
+ -> { Regexp.new("(?<a+1>a)(?(<a+1>)a|b)") }.should.raise(RegexpError)
+ -> { Regexp.new("(?<a->a)(?(<a->)a|b)") }.should.raise(RegexpError)
+ -> { Regexp.new("(?<a-b>a)(?(<a-b>)a|b)") }.should.raise(RegexpError)
+ -> { Regexp.new("(?<a-1>a)(?(<a-1>)a|b)") }.should.raise(RegexpError)
+
+ -> { Regexp.new("(?<a+>a)(?('a+')a|b)") }.should.raise(RegexpError)
+ -> { Regexp.new("(?<a+b>a)(?('a+b')a|b)") }.should.raise(RegexpError)
+ -> { Regexp.new("(?<a+1>a)(?('a+1')a|b)") }.should.raise(RegexpError)
+ -> { Regexp.new("(?<a->a)(?('a-')a|b)") }.should.raise(RegexpError)
+ -> { Regexp.new("(?<a-b>a)(?('a-b')a|b)") }.should.raise(RegexpError)
+ -> { Regexp.new("(?<a-1>a)(?('a-1')a|b)") }.should.raise(RegexpError)
end
end
diff --git a/spec/ruby/language/regexp/character_classes_spec.rb b/spec/ruby/language/regexp/character_classes_spec.rb
index 80cf88c7bd..c6ed92b78e 100644
--- a/spec/ruby/language/regexp/character_classes_spec.rb
+++ b/spec/ruby/language/regexp/character_classes_spec.rb
@@ -9,9 +9,9 @@ describe "Regexp with character classes" do
/\w/.match("_").to_a.should == ["_"]
# Non-matches
- /\w/.match(LanguageSpecs.white_spaces).should be_nil
- /\w/.match(LanguageSpecs.non_alphanum_non_space).should be_nil
- /\w/.match("\0").should be_nil
+ /\w/.match(LanguageSpecs.white_spaces).should == nil
+ /\w/.match(LanguageSpecs.non_alphanum_non_space).should == nil
+ /\w/.match("\0").should == nil
end
it "supports \\W (non-word character)" do
@@ -20,19 +20,19 @@ describe "Regexp with character classes" do
/\W/.match("\0").to_a.should == ["\0"]
# Non-matches
- /\W/.match("a").should be_nil
- /\W/.match("1").should be_nil
- /\W/.match("_").should be_nil
+ /\W/.match("a").should == nil
+ /\W/.match("1").should == nil
+ /\W/.match("_").should == nil
end
it "supports \\s (space character)" do
/\s+/.match(LanguageSpecs.white_spaces).to_a.should == [LanguageSpecs.white_spaces]
# Non-matches
- /\s/.match("a").should be_nil
- /\s/.match("1").should be_nil
- /\s/.match(LanguageSpecs.non_alphanum_non_space).should be_nil
- /\s/.match("\0").should be_nil
+ /\s/.match("a").should == nil
+ /\s/.match("1").should == nil
+ /\s/.match(LanguageSpecs.non_alphanum_non_space).should == nil
+ /\s/.match("\0").should == nil
end
it "supports \\S (non-space character)" do
@@ -42,17 +42,17 @@ describe "Regexp with character classes" do
/\S/.match("\0").to_a.should == ["\0"]
# Non-matches
- /\S/.match(LanguageSpecs.white_spaces).should be_nil
+ /\S/.match(LanguageSpecs.white_spaces).should == nil
end
it "supports \\d (numeric digit)" do
/\d/.match("1").to_a.should == ["1"]
# Non-matches
- /\d/.match("a").should be_nil
- /\d/.match(LanguageSpecs.white_spaces).should be_nil
- /\d/.match(LanguageSpecs.non_alphanum_non_space).should be_nil
- /\d/.match("\0").should be_nil
+ /\d/.match("a").should == nil
+ /\d/.match(LanguageSpecs.white_spaces).should == nil
+ /\d/.match(LanguageSpecs.non_alphanum_non_space).should == nil
+ /\d/.match("\0").should == nil
end
it "supports \\D (non-digit)" do
@@ -62,7 +62,7 @@ describe "Regexp with character classes" do
/\D/.match("\0").to_a.should == ["\0"]
# Non-matches
- /\D/.match("1").should be_nil
+ /\D/.match("1").should == nil
end
it "supports [] (character class)" do
@@ -89,7 +89,7 @@ describe "Regexp with character classes" do
/[^[:lower:]A-C]+/.match("abcABCDEF123def").to_a.should == ["DEF123"] # negated character class
/[:alnum:]+/.match("a:l:n:u:m").to_a.should == ["a:l:n:u:m"] # should behave like regular character class composed of the individual letters
/[\[:alnum:]+/.match("[:a:l:n:u:m").to_a.should == ["[:a:l:n:u:m"] # should behave like regular character class composed of the individual letters
- -> { eval('/[[:alpha:]-[:digit:]]/') }.should raise_error(SyntaxError) # can't use character class as a start value of range
+ -> { eval('/[[:alpha:]-[:digit:]]/') }.should.raise(SyntaxError) # can't use character class as a start value of range
end
it "matches ASCII characters with [[:ascii:]]" do
@@ -99,8 +99,8 @@ describe "Regexp with character classes" do
not_supported_on :opal do
it "doesn't match non-ASCII characters with [[:ascii:]]" do
- /[[:ascii:]]/.match("\u{80}").should be_nil
- /[[:ascii:]]/.match("\u{9898}").should be_nil
+ /[[:ascii:]]/.match("\u{80}").should == nil
+ /[[:ascii:]]/.match("\u{9898}").should == nil
end
end
@@ -113,7 +113,7 @@ describe "Regexp with character classes" do
end
it "doesn't matches Unicode marks with [[:alnum:]]" do
- "\u{3099}".match(/[[:alnum:]]/).should be_nil
+ "\u{3099}".match(/[[:alnum:]]/).should == nil
end
it "doesn't match Unicode control characters with [[:alnum:]]" do
@@ -133,7 +133,7 @@ describe "Regexp with character classes" do
end
it "doesn't matches Unicode marks with [[:alpha:]]" do
- "\u{3099}".match(/[[:alpha:]]/).should be_nil
+ "\u{3099}".match(/[[:alpha:]]/).should == nil
end
it "doesn't match Unicode control characters with [[:alpha:]]" do
@@ -149,39 +149,39 @@ describe "Regexp with character classes" do
end
it "doesn't match Unicode control characters with [[:blank:]]" do
- "\u{16}".match(/[[:blank:]]/).should be_nil
+ "\u{16}".match(/[[:blank:]]/).should == nil
end
it "doesn't match Unicode punctuation characters with [[:blank:]]" do
- "\u{3F}".match(/[[:blank:]]/).should be_nil
+ "\u{3F}".match(/[[:blank:]]/).should == nil
end
it "doesn't match Unicode letter characters with [[:blank:]]" do
- "à".match(/[[:blank:]]/).should be_nil
+ "à".match(/[[:blank:]]/).should == nil
end
it "doesn't match Unicode digits with [[:blank:]]" do
- "\u{0660}".match(/[[:blank:]]/).should be_nil
+ "\u{0660}".match(/[[:blank:]]/).should == nil
end
it "doesn't match Unicode marks with [[:blank:]]" do
- "\u{36F}".match(/[[:blank:]]/).should be_nil
+ "\u{36F}".match(/[[:blank:]]/).should == nil
end
it "doesn't Unicode letter characters with [[:cntrl:]]" do
- "à".match(/[[:cntrl:]]/).should be_nil
+ "à".match(/[[:cntrl:]]/).should == nil
end
it "doesn't match Unicode digits with [[:cntrl:]]" do
- "\u{0660}".match(/[[:cntrl:]]/).should be_nil
+ "\u{0660}".match(/[[:cntrl:]]/).should == nil
end
it "doesn't match Unicode marks with [[:cntrl:]]" do
- "\u{36F}".match(/[[:cntrl:]]/).should be_nil
+ "\u{36F}".match(/[[:cntrl:]]/).should == nil
end
it "doesn't match Unicode punctuation characters with [[:cntrl:]]" do
- "\u{3F}".match(/[[:cntrl:]]/).should be_nil
+ "\u{3F}".match(/[[:cntrl:]]/).should == nil
end
it "matches Unicode control characters with [[:cntrl:]]" do
@@ -189,15 +189,15 @@ describe "Regexp with character classes" do
end
it "doesn't match Unicode format characters with [[:cntrl:]]" do
- "\u{2060}".match(/[[:cntrl:]]/).should be_nil
+ "\u{2060}".match(/[[:cntrl:]]/).should == nil
end
it "doesn't match Unicode private-use characters with [[:cntrl:]]" do
- "\u{E001}".match(/[[:cntrl:]]/).should be_nil
+ "\u{E001}".match(/[[:cntrl:]]/).should == nil
end
it "doesn't match Unicode letter characters with [[:digit:]]" do
- "à".match(/[[:digit:]]/).should be_nil
+ "à".match(/[[:digit:]]/).should == nil
end
it "matches Unicode digits with [[:digit:]]" do
@@ -206,23 +206,23 @@ describe "Regexp with character classes" do
end
it "doesn't match Unicode marks with [[:digit:]]" do
- "\u{36F}".match(/[[:digit:]]/).should be_nil
+ "\u{36F}".match(/[[:digit:]]/).should == nil
end
it "doesn't match Unicode punctuation characters with [[:digit:]]" do
- "\u{3F}".match(/[[:digit:]]/).should be_nil
+ "\u{3F}".match(/[[:digit:]]/).should == nil
end
it "doesn't match Unicode control characters with [[:digit:]]" do
- "\u{16}".match(/[[:digit:]]/).should be_nil
+ "\u{16}".match(/[[:digit:]]/).should == nil
end
it "doesn't match Unicode format characters with [[:digit:]]" do
- "\u{2060}".match(/[[:digit:]]/).should be_nil
+ "\u{2060}".match(/[[:digit:]]/).should == nil
end
it "doesn't match Unicode private-use characters with [[:digit:]]" do
- "\u{E001}".match(/[[:digit:]]/).should be_nil
+ "\u{E001}".match(/[[:digit:]]/).should == nil
end
it "matches Unicode letter characters with [[:graph:]]" do
@@ -243,7 +243,7 @@ describe "Regexp with character classes" do
end
it "doesn't match Unicode control characters with [[:graph:]]" do
- "\u{16}".match(/[[:graph:]]/).should be_nil
+ "\u{16}".match(/[[:graph:]]/).should == nil
end
it "match Unicode format characters with [[:graph:]]" do
@@ -261,40 +261,40 @@ describe "Regexp with character classes" do
end
it "doesn't match Unicode uppercase letter characters with [[:lower:]]" do
- "\u{100}".match(/[[:lower:]]/).should be_nil
- "\u{130}".match(/[[:lower:]]/).should be_nil
- "\u{405}".match(/[[:lower:]]/).should be_nil
+ "\u{100}".match(/[[:lower:]]/).should == nil
+ "\u{130}".match(/[[:lower:]]/).should == nil
+ "\u{405}".match(/[[:lower:]]/).should == nil
end
it "doesn't match Unicode title-case characters with [[:lower:]]" do
- "\u{1F88}".match(/[[:lower:]]/).should be_nil
- "\u{1FAD}".match(/[[:lower:]]/).should be_nil
- "\u{01C5}".match(/[[:lower:]]/).should be_nil
+ "\u{1F88}".match(/[[:lower:]]/).should == nil
+ "\u{1FAD}".match(/[[:lower:]]/).should == nil
+ "\u{01C5}".match(/[[:lower:]]/).should == nil
end
it "doesn't match Unicode digits with [[:lower:]]" do
- "\u{0660}".match(/[[:lower:]]/).should be_nil
- "\u{FF12}".match(/[[:lower:]]/).should be_nil
+ "\u{0660}".match(/[[:lower:]]/).should == nil
+ "\u{FF12}".match(/[[:lower:]]/).should == nil
end
it "doesn't match Unicode marks with [[:lower:]]" do
- "\u{36F}".match(/[[:lower:]]/).should be_nil
+ "\u{36F}".match(/[[:lower:]]/).should == nil
end
it "doesn't match Unicode punctuation characters with [[:lower:]]" do
- "\u{3F}".match(/[[:lower:]]/).should be_nil
+ "\u{3F}".match(/[[:lower:]]/).should == nil
end
it "doesn't match Unicode control characters with [[:lower:]]" do
- "\u{16}".match(/[[:lower:]]/).should be_nil
+ "\u{16}".match(/[[:lower:]]/).should == nil
end
it "doesn't match Unicode format characters with [[:lower:]]" do
- "\u{2060}".match(/[[:lower:]]/).should be_nil
+ "\u{2060}".match(/[[:lower:]]/).should == nil
end
it "doesn't match Unicode private-use characters with [[:lower:]]" do
- "\u{E001}".match(/[[:lower:]]/).should be_nil
+ "\u{E001}".match(/[[:lower:]]/).should == nil
end
it "matches Unicode lowercase letter characters with [[:print:]]" do
@@ -329,7 +329,7 @@ describe "Regexp with character classes" do
end
it "doesn't match Unicode control characters with [[:print:]]" do
- "\u{16}".match(/[[:print:]]/).should be_nil
+ "\u{16}".match(/[[:print:]]/).should == nil
end
it "match Unicode format characters with [[:print:]]" do
@@ -342,30 +342,30 @@ describe "Regexp with character classes" do
it "doesn't match Unicode lowercase letter characters with [[:punct:]]" do
- "\u{FF41}".match(/[[:punct:]]/).should be_nil
- "\u{1D484}".match(/[[:punct:]]/).should be_nil
- "\u{E8}".match(/[[:punct:]]/).should be_nil
+ "\u{FF41}".match(/[[:punct:]]/).should == nil
+ "\u{1D484}".match(/[[:punct:]]/).should == nil
+ "\u{E8}".match(/[[:punct:]]/).should == nil
end
it "doesn't match Unicode uppercase letter characters with [[:punct:]]" do
- "\u{100}".match(/[[:punct:]]/).should be_nil
- "\u{130}".match(/[[:punct:]]/).should be_nil
- "\u{405}".match(/[[:punct:]]/).should be_nil
+ "\u{100}".match(/[[:punct:]]/).should == nil
+ "\u{130}".match(/[[:punct:]]/).should == nil
+ "\u{405}".match(/[[:punct:]]/).should == nil
end
it "doesn't match Unicode title-case characters with [[:punct:]]" do
- "\u{1F88}".match(/[[:punct:]]/).should be_nil
- "\u{1FAD}".match(/[[:punct:]]/).should be_nil
- "\u{01C5}".match(/[[:punct:]]/).should be_nil
+ "\u{1F88}".match(/[[:punct:]]/).should == nil
+ "\u{1FAD}".match(/[[:punct:]]/).should == nil
+ "\u{01C5}".match(/[[:punct:]]/).should == nil
end
it "doesn't match Unicode digits with [[:punct:]]" do
- "\u{0660}".match(/[[:punct:]]/).should be_nil
- "\u{FF12}".match(/[[:punct:]]/).should be_nil
+ "\u{0660}".match(/[[:punct:]]/).should == nil
+ "\u{FF12}".match(/[[:punct:]]/).should == nil
end
it "doesn't match Unicode marks with [[:punct:]]" do
- "\u{36F}".match(/[[:punct:]]/).should be_nil
+ "\u{36F}".match(/[[:punct:]]/).should == nil
end
it "matches Unicode Pc characters with [[:punct:]]" do
@@ -398,38 +398,38 @@ describe "Regexp with character classes" do
end
it "doesn't match Unicode format characters with [[:punct:]]" do
- "\u{2060}".match(/[[:punct:]]/).should be_nil
+ "\u{2060}".match(/[[:punct:]]/).should == nil
end
it "doesn't match Unicode private-use characters with [[:punct:]]" do
- "\u{E001}".match(/[[:punct:]]/).should be_nil
+ "\u{E001}".match(/[[:punct:]]/).should == nil
end
it "doesn't match Unicode lowercase letter characters with [[:space:]]" do
- "\u{FF41}".match(/[[:space:]]/).should be_nil
- "\u{1D484}".match(/[[:space:]]/).should be_nil
- "\u{E8}".match(/[[:space:]]/).should be_nil
+ "\u{FF41}".match(/[[:space:]]/).should == nil
+ "\u{1D484}".match(/[[:space:]]/).should == nil
+ "\u{E8}".match(/[[:space:]]/).should == nil
end
it "doesn't match Unicode uppercase letter characters with [[:space:]]" do
- "\u{100}".match(/[[:space:]]/).should be_nil
- "\u{130}".match(/[[:space:]]/).should be_nil
- "\u{405}".match(/[[:space:]]/).should be_nil
+ "\u{100}".match(/[[:space:]]/).should == nil
+ "\u{130}".match(/[[:space:]]/).should == nil
+ "\u{405}".match(/[[:space:]]/).should == nil
end
it "doesn't match Unicode title-case characters with [[:space:]]" do
- "\u{1F88}".match(/[[:space:]]/).should be_nil
- "\u{1FAD}".match(/[[:space:]]/).should be_nil
- "\u{01C5}".match(/[[:space:]]/).should be_nil
+ "\u{1F88}".match(/[[:space:]]/).should == nil
+ "\u{1FAD}".match(/[[:space:]]/).should == nil
+ "\u{01C5}".match(/[[:space:]]/).should == nil
end
it "doesn't match Unicode digits with [[:space:]]" do
- "\u{0660}".match(/[[:space:]]/).should be_nil
- "\u{FF12}".match(/[[:space:]]/).should be_nil
+ "\u{0660}".match(/[[:space:]]/).should == nil
+ "\u{FF12}".match(/[[:space:]]/).should == nil
end
it "doesn't match Unicode marks with [[:space:]]" do
- "\u{36F}".match(/[[:space:]]/).should be_nil
+ "\u{36F}".match(/[[:space:]]/).should == nil
end
it "matches Unicode Zs characters with [[:space:]]" do
@@ -445,17 +445,17 @@ describe "Regexp with character classes" do
end
it "doesn't match Unicode format characters with [[:space:]]" do
- "\u{2060}".match(/[[:space:]]/).should be_nil
+ "\u{2060}".match(/[[:space:]]/).should == nil
end
it "doesn't match Unicode private-use characters with [[:space:]]" do
- "\u{E001}".match(/[[:space:]]/).should be_nil
+ "\u{E001}".match(/[[:space:]]/).should == nil
end
it "doesn't match Unicode lowercase characters with [[:upper:]]" do
- "\u{FF41}".match(/[[:upper:]]/).should be_nil
- "\u{1D484}".match(/[[:upper:]]/).should be_nil
- "\u{E8}".match(/[[:upper:]]/).should be_nil
+ "\u{FF41}".match(/[[:upper:]]/).should == nil
+ "\u{1D484}".match(/[[:upper:]]/).should == nil
+ "\u{E8}".match(/[[:upper:]]/).should == nil
end
it "matches Unicode uppercase characters with [[:upper:]]" do
@@ -465,40 +465,40 @@ describe "Regexp with character classes" do
end
it "doesn't match Unicode title-case characters with [[:upper:]]" do
- "\u{1F88}".match(/[[:upper:]]/).should be_nil
- "\u{1FAD}".match(/[[:upper:]]/).should be_nil
- "\u{01C5}".match(/[[:upper:]]/).should be_nil
+ "\u{1F88}".match(/[[:upper:]]/).should == nil
+ "\u{1FAD}".match(/[[:upper:]]/).should == nil
+ "\u{01C5}".match(/[[:upper:]]/).should == nil
end
it "doesn't match Unicode digits with [[:upper:]]" do
- "\u{0660}".match(/[[:upper:]]/).should be_nil
- "\u{FF12}".match(/[[:upper:]]/).should be_nil
+ "\u{0660}".match(/[[:upper:]]/).should == nil
+ "\u{FF12}".match(/[[:upper:]]/).should == nil
end
it "doesn't match Unicode marks with [[:upper:]]" do
- "\u{36F}".match(/[[:upper:]]/).should be_nil
+ "\u{36F}".match(/[[:upper:]]/).should == nil
end
it "doesn't match Unicode punctuation characters with [[:upper:]]" do
- "\u{3F}".match(/[[:upper:]]/).should be_nil
+ "\u{3F}".match(/[[:upper:]]/).should == nil
end
it "doesn't match Unicode control characters with [[:upper:]]" do
- "\u{16}".match(/[[:upper:]]/).should be_nil
+ "\u{16}".match(/[[:upper:]]/).should == nil
end
it "doesn't match Unicode format characters with [[:upper:]]" do
- "\u{2060}".match(/[[:upper:]]/).should be_nil
+ "\u{2060}".match(/[[:upper:]]/).should == nil
end
it "doesn't match Unicode private-use characters with [[:upper:]]" do
- "\u{E001}".match(/[[:upper:]]/).should be_nil
+ "\u{E001}".match(/[[:upper:]]/).should == nil
end
it "doesn't match Unicode letter characters [^a-fA-F] with [[:xdigit:]]" do
- "à".match(/[[:xdigit:]]/).should be_nil
- "g".match(/[[:xdigit:]]/).should be_nil
- "X".match(/[[:xdigit:]]/).should be_nil
+ "à".match(/[[:xdigit:]]/).should == nil
+ "g".match(/[[:xdigit:]]/).should == nil
+ "X".match(/[[:xdigit:]]/).should == nil
end
it "matches Unicode letter characters [a-fA-F] with [[:xdigit:]]" do
@@ -507,28 +507,28 @@ describe "Regexp with character classes" do
end
it "doesn't match Unicode digits [^0-9] with [[:xdigit:]]" do
- "\u{0660}".match(/[[:xdigit:]]/).should be_nil
- "\u{FF12}".match(/[[:xdigit:]]/).should be_nil
+ "\u{0660}".match(/[[:xdigit:]]/).should == nil
+ "\u{FF12}".match(/[[:xdigit:]]/).should == nil
end
it "doesn't match Unicode marks with [[:xdigit:]]" do
- "\u{36F}".match(/[[:xdigit:]]/).should be_nil
+ "\u{36F}".match(/[[:xdigit:]]/).should == nil
end
it "doesn't match Unicode punctuation characters with [[:xdigit:]]" do
- "\u{3F}".match(/[[:xdigit:]]/).should be_nil
+ "\u{3F}".match(/[[:xdigit:]]/).should == nil
end
it "doesn't match Unicode control characters with [[:xdigit:]]" do
- "\u{16}".match(/[[:xdigit:]]/).should be_nil
+ "\u{16}".match(/[[:xdigit:]]/).should == nil
end
it "doesn't match Unicode format characters with [[:xdigit:]]" do
- "\u{2060}".match(/[[:xdigit:]]/).should be_nil
+ "\u{2060}".match(/[[:xdigit:]]/).should == nil
end
it "doesn't match Unicode private-use characters with [[:xdigit:]]" do
- "\u{E001}".match(/[[:xdigit:]]/).should be_nil
+ "\u{E001}".match(/[[:xdigit:]]/).should == nil
end
it "matches Unicode lowercase characters with [[:word:]]" do
@@ -562,7 +562,7 @@ describe "Regexp with character classes" do
"\u{16EE}".match(/[[:word:]]/).to_a.should == ["\u{16EE}"]
end
- ruby_bug "#19417", ""..."3.5" do
+ ruby_bug "#19417", ""..."3.4.6" do
it "matches Unicode join control characters with [[:word:]]" do
"\u{200C}".match(/[[:word:]]/).to_a.should == ["\u{200C}"]
"\u{200D}".match(/[[:word:]]/).to_a.should == ["\u{200D}"]
@@ -570,22 +570,22 @@ describe "Regexp with character classes" do
end
it "doesn't match Unicode No characters with [[:word:]]" do
- "\u{17F0}".match(/[[:word:]]/).should be_nil
+ "\u{17F0}".match(/[[:word:]]/).should == nil
end
it "doesn't match Unicode punctuation characters with [[:word:]]" do
- "\u{3F}".match(/[[:word:]]/).should be_nil
+ "\u{3F}".match(/[[:word:]]/).should == nil
end
it "doesn't match Unicode control characters with [[:word:]]" do
- "\u{16}".match(/[[:word:]]/).should be_nil
+ "\u{16}".match(/[[:word:]]/).should == nil
end
it "doesn't match Unicode format characters with [[:word:]]" do
- "\u{2060}".match(/[[:word:]]/).should be_nil
+ "\u{2060}".match(/[[:word:]]/).should == nil
end
it "doesn't match Unicode private-use characters with [[:word:]]" do
- "\u{E001}".match(/[[:word:]]/).should be_nil
+ "\u{E001}".match(/[[:word:]]/).should == nil
end
it "matches unicode named character properties" do
@@ -617,12 +617,12 @@ 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(eval("/\P{L}/")).should == nil
+ "1".match(eval("/\P{N}/")).should == nil
end
it "raises a RegexpError for an unterminated unicode property" do
- -> { Regexp.new('\p{') }.should raise_error(RegexpError)
+ -> { Regexp.new('\p{') }.should.raise(RegexpError)
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 898b6d4ff7..81e845af0c 100644
--- a/spec/ruby/language/regexp/encoding_spec.rb
+++ b/spec/ruby/language/regexp/encoding_spec.rb
@@ -39,7 +39,11 @@ 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})
+ -> {
+ eval <<~RUBY
+ /./n.match("\303\251".dup.force_encoding('utf-8'))
+ RUBY
+ }.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
@@ -110,28 +114,28 @@ describe "Regexps with encoding modifiers" do
end
it "raises Encoding::CompatibilityError when trying match against different encodings" do
- -> { /\A[[:space:]]*\z/.match(" ".encode("UTF-16LE")) }.should raise_error(Encoding::CompatibilityError)
+ -> { /\A[[:space:]]*\z/.match(" ".encode("UTF-16LE")) }.should.raise(Encoding::CompatibilityError)
end
it "raises Encoding::CompatibilityError when trying match? against different encodings" do
- -> { /\A[[:space:]]*\z/.match?(" ".encode("UTF-16LE")) }.should raise_error(Encoding::CompatibilityError)
+ -> { /\A[[:space:]]*\z/.match?(" ".encode("UTF-16LE")) }.should.raise(Encoding::CompatibilityError)
end
it "raises Encoding::CompatibilityError when trying =~ against different encodings" do
- -> { /\A[[:space:]]*\z/ =~ " ".encode("UTF-16LE") }.should raise_error(Encoding::CompatibilityError)
+ -> { /\A[[:space:]]*\z/ =~ " ".encode("UTF-16LE") }.should.raise(Encoding::CompatibilityError)
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("".dup.force_encoding("UTF-16LE"), Regexp::FIXEDENCODING) =~ " ".encode("UTF-8") }.should.raise(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("".dup.force_encoding("US-ASCII"), Regexp::FIXEDENCODING) =~ "\303\251".dup.force_encoding('UTF-8') }.should.raise(Encoding::CompatibilityError)
end
it "raises ArgumentError when trying to match a broken String" do
s = "\x80".dup.force_encoding('UTF-8')
- -> { s =~ /./ }.should raise_error(ArgumentError, "invalid byte sequence in UTF-8")
+ -> { s =~ /./ }.should.raise(ArgumentError, "invalid byte sequence in UTF-8")
end
it "computes the Regexp Encoding for each interpolated Regexp instance" do
diff --git a/spec/ruby/language/regexp/escapes_spec.rb b/spec/ruby/language/regexp/escapes_spec.rb
index 541998b937..4a0e611540 100644
--- a/spec/ruby/language/regexp/escapes_spec.rb
+++ b/spec/ruby/language/regexp/escapes_spec.rb
@@ -116,11 +116,11 @@ describe "Regexps with escape characters" do
it "supports \\x (hex characters)" do
/\xA/.match("\nxyz").to_a.should == ["\n"]
/\x0A/.match("\n").to_a.should == ["\n"]
- /\xAA/.match("\nA").should be_nil
+ /\xAA/.match("\nA").should == nil
/\x0AA/.match("\nA").to_a.should == ["\nA"]
/\xAG/.match("\nG").to_a.should == ["\nG"]
# Non-matches
- -> { eval('/\xG/') }.should raise_error(SyntaxError)
+ -> { eval('/\xG/') }.should.raise(SyntaxError)
# \x{7HHHHHHH} wide hexadecimal char (character code point value)
end
@@ -136,14 +136,14 @@ describe "Regexps with escape characters" do
/\c,\cL\cl/.match("\f\f\f").to_a.should == ["\f\f\f"]
/\c-\cM\cm/.match("\r\r\r").to_a.should == ["\r\r\r"]
- /\cJ/.match("\r").should be_nil
+ /\cJ/.match("\r").should == nil
# Parsing precedence
/\cJ+/.match("\n\n").to_a.should == ["\n\n"] # Quantifiers apply to entire escape sequence
/\\cJ/.match("\\cJ").to_a.should == ["\\cJ"]
- -> { eval('/[abc\x]/') }.should raise_error(SyntaxError) # \x is treated as a escape sequence even inside a character class
+ -> { eval('/[abc\x]/') }.should.raise(SyntaxError) # \x is treated as a escape sequence even inside a character class
# Syntax error
- -> { eval('/\c/') }.should raise_error(SyntaxError)
+ -> { eval('/\c/') }.should.raise(SyntaxError)
# \cx control char (character code point value)
# \C-x control char (character code point value)
diff --git a/spec/ruby/language/regexp/grouping_spec.rb b/spec/ruby/language/regexp/grouping_spec.rb
index 313858f714..80ad7460da 100644
--- a/spec/ruby/language/regexp/grouping_spec.rb
+++ b/spec/ruby/language/regexp/grouping_spec.rb
@@ -12,7 +12,7 @@ describe "Regexps with grouping" do
end
it "raises a SyntaxError when parentheses aren't balanced" do
- -> { eval "/(hay(st)ack/" }.should raise_error(SyntaxError)
+ -> { eval "/(hay(st)ack/" }.should.raise(SyntaxError)
end
it "supports (?: ) (non-capturing group)" do
@@ -22,8 +22,8 @@ describe "Regexps with grouping" do
end
it "group names cannot start with digits or minus" do
- -> { Regexp.new("(?<1a>a)") }.should raise_error(RegexpError)
- -> { Regexp.new("(?<-a>a)") }.should raise_error(RegexpError)
+ -> { Regexp.new("(?<1a>a)") }.should.raise(RegexpError)
+ -> { Regexp.new("(?<-a>a)") }.should.raise(RegexpError)
end
it "ignore capture groups in line comments" do
diff --git a/spec/ruby/language/regexp/interpolation_spec.rb b/spec/ruby/language/regexp/interpolation_spec.rb
index 6951fd38ca..f771d0a395 100644
--- a/spec/ruby/language/regexp/interpolation_spec.rb
+++ b/spec/ruby/language/regexp/interpolation_spec.rb
@@ -36,14 +36,14 @@ describe "Regexps with interpolation" do
it "gives precedence to escape sequences over substitution" do
str = "J"
- /\c#{str}/.to_s.should include('{str}')
+ /\c#{str}/.to_s.should.include?('{str}')
end
it "throws RegexpError for malformed interpolation" do
s = ""
- -> { /(#{s}/ }.should raise_error(RegexpError)
+ -> { /(#{s}/ }.should.raise(RegexpError)
s = "("
- -> { /#{s}/ }.should raise_error(RegexpError)
+ -> { /#{s}/ }.should.raise(RegexpError)
end
it "allows interpolation in extended mode" do
diff --git a/spec/ruby/language/regexp/modifiers_spec.rb b/spec/ruby/language/regexp/modifiers_spec.rb
index 2f5522bc8a..c96fbfa983 100644
--- a/spec/ruby/language/regexp/modifiers_spec.rb
+++ b/spec/ruby/language/regexp/modifiers_spec.rb
@@ -8,7 +8,7 @@ describe "Regexps with modifiers" do
it "supports /m (multiline)" do
/foo.bar/m.match("foo\nbar").to_a.should == ["foo\nbar"]
- /foo.bar/.match("foo\nbar").should be_nil
+ /foo.bar/.match("foo\nbar").should == nil
end
it "supports /x (extended syntax)" do
@@ -36,7 +36,7 @@ describe "Regexps with modifiers" do
/foo/imox.match("foo").to_a.should == ["foo"]
/foo/imoximox.match("foo").to_a.should == ["foo"]
- -> { eval('/foo/a') }.should raise_error(SyntaxError)
+ -> { eval('/foo/a') }.should.raise(SyntaxError)
end
it "supports (?~) (absent operator)" do
@@ -46,57 +46,57 @@ describe "Regexps with modifiers" do
it "supports (?imx-imx) (inline modifiers)" do
/(?i)foo/.match("FOO").to_a.should == ["FOO"]
- /foo(?i)/.match("FOO").should be_nil
+ /foo(?i)/.match("FOO").should == nil
# Interaction with /i
- /(?-i)foo/i.match("FOO").should be_nil
+ /(?-i)foo/i.match("FOO").should == nil
/foo(?-i)/i.match("FOO").to_a.should == ["FOO"]
# Multiple uses
/foo (?i)bar (?-i)baz/.match("foo BAR baz").to_a.should == ["foo BAR baz"]
- /foo (?i)bar (?-i)baz/.match("foo BAR BAZ").should be_nil
+ /foo (?i)bar (?-i)baz/.match("foo BAR BAZ").should == nil
/(?m)./.match("\n").to_a.should == ["\n"]
- /.(?m)/.match("\n").should be_nil
+ /.(?m)/.match("\n").should == nil
# Interaction with /m
- /(?-m)./m.match("\n").should be_nil
+ /(?-m)./m.match("\n").should == nil
/.(?-m)/m.match("\n").to_a.should == ["\n"]
# Multiple uses
/. (?m). (?-m)./.match(". \n .").to_a.should == [". \n ."]
- /. (?m). (?-m)./.match(". \n \n").should be_nil
+ /. (?m). (?-m)./.match(". \n \n").should == nil
/(?x) foo /.match("foo").to_a.should == ["foo"]
- / foo (?x)/.match("foo").should be_nil
+ / foo (?x)/.match("foo").should == nil
# Interaction with /x
- /(?-x) foo /x.match("foo").should be_nil
+ /(?-x) foo /x.match("foo").should == nil
/ foo (?-x)/x.match("foo").to_a.should == ["foo"]
# Multiple uses
/( foo )(?x)( bar )(?-x)( baz )/.match(" foo bar baz ").to_a.should == [" foo bar baz ", " foo ", "bar", " baz "]
- /( foo )(?x)( bar )(?-x)( baz )/.match(" foo barbaz").should be_nil
+ /( foo )(?x)( bar )(?-x)( baz )/.match(" foo barbaz").should == nil
# Parsing
- /(?i-i)foo/.match("FOO").should be_nil
+ /(?i-i)foo/.match("FOO").should == nil
/(?ii)foo/.match("FOO").to_a.should == ["FOO"]
/(?-)foo/.match("foo").to_a.should == ["foo"]
- -> { eval('/(?o)/') }.should raise_error(SyntaxError)
+ -> { eval('/(?o)/') }.should.raise(SyntaxError)
end
it "supports (?imx-imx:expr) (scoped inline modifiers)" do
/foo (?i:bar) baz/.match("foo BAR baz").to_a.should == ["foo BAR baz"]
- /foo (?i:bar) baz/.match("foo BAR BAZ").should be_nil
- /foo (?-i:bar) baz/i.match("foo BAR BAZ").should be_nil
+ /foo (?i:bar) baz/.match("foo BAR BAZ").should == nil
+ /foo (?-i:bar) baz/i.match("foo BAR BAZ").should == nil
/. (?m:.) ./.match(". \n .").to_a.should == [". \n ."]
- /. (?m:.) ./.match(". \n \n").should be_nil
- /. (?-m:.) ./m.match("\n \n \n").should be_nil
+ /. (?m:.) ./.match(". \n \n").should == nil
+ /. (?-m:.) ./m.match("\n \n \n").should == nil
/( foo )(?x: bar )( baz )/.match(" foo bar baz ").to_a.should == [" foo bar baz ", " foo ", " baz "]
- /( foo )(?x: bar )( baz )/.match(" foo barbaz").should be_nil
+ /( foo )(?x: bar )( baz )/.match(" foo barbaz").should == nil
/( foo )(?-x: bar )( baz )/x.match("foo bar baz").to_a.should == ["foo bar baz", "foo", "baz"]
# Parsing
- /(?i-i:foo)/.match("FOO").should be_nil
+ /(?i-i:foo)/.match("FOO").should == nil
/(?ii:foo)/.match("FOO").to_a.should == ["FOO"]
/(?-:)foo/.match("foo").to_a.should == ["foo"]
- -> { eval('/(?o:)/') }.should raise_error(SyntaxError)
+ -> { eval('/(?o:)/') }.should.raise(SyntaxError)
end
it "supports . with /m" do
diff --git a/spec/ruby/language/regexp/repetition_spec.rb b/spec/ruby/language/regexp/repetition_spec.rb
index d76619688f..f24323de5c 100644
--- a/spec/ruby/language/regexp/repetition_spec.rb
+++ b/spec/ruby/language/regexp/repetition_spec.rb
@@ -15,7 +15,7 @@ describe "Regexps with repetition" do
it "supports + (1 or more of previous subexpression)" do
/a+/.match("aaa").to_a.should == ["aaa"]
- /a+/.match("bbb").should be_nil
+ /a+/.match("bbb").should == nil
/<.+>/.match("<a>foo</a>").to_a.should == ["<a>foo</a>"] # it is greedy
end
diff --git a/spec/ruby/language/regexp_spec.rb b/spec/ruby/language/regexp_spec.rb
index 0cd9584549..1452b01935 100644
--- a/spec/ruby/language/regexp_spec.rb
+++ b/spec/ruby/language/regexp_spec.rb
@@ -15,7 +15,7 @@ describe "Literal Regexps" do
end
it "yields a Regexp" do
- /Hello/.should be_kind_of(Regexp)
+ /Hello/.should.is_a?(Regexp)
end
it "is frozen" do
@@ -27,11 +27,11 @@ describe "Literal Regexps" do
2.times do |i|
rs << /foo/
end
- rs[0].should equal(rs[1])
+ rs[0].should.equal?(rs[1])
end
it "throws SyntaxError for malformed literals" do
- -> { eval('/(/') }.should raise_error(SyntaxError)
+ -> { eval('/(/') }.should.raise(SyntaxError)
end
#############################################################################
@@ -58,7 +58,7 @@ describe "Literal Regexps" do
it "disallows first part of paired delimiters to be used as non-paired delimiters" do
LanguageSpecs.paired_delimiters.each do |p0, p1|
- -> { eval("%r#{p0} foo #{p0}") }.should raise_error(SyntaxError)
+ -> { eval("%r#{p0} foo #{p0}") }.should.raise(SyntaxError)
end
end
@@ -69,11 +69,11 @@ describe "Literal Regexps" do
end
it "disallows alphabets as non-paired delimiter with %r" do
- -> { eval('%ra foo a') }.should raise_error(SyntaxError)
+ -> { eval('%ra foo a') }.should.raise(SyntaxError)
end
it "disallows spaces after %r and delimiter" do
- -> { eval('%r !foo!') }.should raise_error(SyntaxError)
+ -> { eval('%r !foo!') }.should.raise(SyntaxError)
end
it "allows unescaped / to be used with %r" do
@@ -89,8 +89,8 @@ describe "Literal Regexps" do
# Basic matching
/./.match("foo").to_a.should == ["f"]
# Basic non-matching
- /./.match("").should be_nil
- /./.match("\n").should be_nil
+ /./.match("").should == nil
+ /./.match("\n").should == nil
/./.match("\0").to_a.should == ["\0"]
end
@@ -100,7 +100,7 @@ describe "Literal Regexps" do
it "supports (?> ) (embedded subexpression)" do
/(?>foo)(?>bar)/.match("foobar").to_a.should == ["foobar"]
- /(?>foo*)obar/.match("foooooooobar").should be_nil # it is possessive
+ /(?>foo*)obar/.match("foooooooobar").should == nil # it is possessive
end
it "supports (?# )" do
@@ -112,7 +112,7 @@ describe "Literal Regexps" do
/foo.(?<=\d)/.match("fooA foo1").to_a.should == ["foo1"]
end
- ruby_bug "#13671", ""..."3.6" do # https://bugs.ruby-lang.org/issues/13671
+ ruby_bug "#13671", ""..."4.0" do # https://bugs.ruby-lang.org/issues/13671
it "handles a lookbehind with ss characters" do
r = Regexp.new("(?<!dss)", Regexp::IGNORECASE)
r.should =~ "✨"
@@ -135,9 +135,9 @@ describe "Literal Regexps" do
it "supports possessive quantifiers" do
/fooA++bar/.match("fooAAAbar").to_a.should == ["fooAAAbar"]
- /fooA++Abar/.match("fooAAAbar").should be_nil
- /fooA?+Abar/.match("fooAAAbar").should be_nil
- /fooA*+Abar/.match("fooAAAbar").should be_nil
+ /fooA++Abar/.match("fooAAAbar").should == nil
+ /fooA?+Abar/.match("fooAAAbar").should == nil
+ /fooA*+Abar/.match("fooAAAbar").should == nil
end
it "supports conditional regular expressions with positional capture groups" do
diff --git a/spec/ruby/language/rescue_spec.rb b/spec/ruby/language/rescue_spec.rb
index 79571d689f..cf16d8f6f8 100644
--- a/spec/ruby/language/rescue_spec.rb
+++ b/spec/ruby/language/rescue_spec.rb
@@ -59,7 +59,7 @@ describe "The rescue keyword" do
rescue SpecificExampleException => target&.captured_error
:caught
end.should == :caught
- target.should be_nil
+ target.should == nil
end
it 'using a setter method' do
@@ -136,10 +136,14 @@ describe "The rescue keyword" do
it 'captures successfully at the top-level' do
ScratchPad.record []
+ loaded_features = $".dup
+ begin
+ require_relative 'fixtures/rescue/top_level'
- require_relative 'fixtures/rescue/top_level'
-
- ScratchPad.recorded.should == ["message"]
+ ScratchPad.recorded.should == ["message"]
+ ensure
+ $".replace loaded_features
+ end
end
end
@@ -182,7 +186,7 @@ describe "The rescue keyword" do
rescue *exception_list
caught_it = true
end
- caught_it.should be_true
+ caught_it.should == true
caught = []
[->{raise ArbitraryException}, ->{raise SpecificExampleException}].each do |block|
begin
@@ -193,7 +197,7 @@ describe "The rescue keyword" do
end
caught.size.should == 2
exception_list.each do |exception_class|
- caught.map{|e| e.class}.should include(exception_class)
+ caught.map{|e| e.class}.should.include?(exception_class)
end
end
@@ -206,7 +210,7 @@ describe "The rescue keyword" do
rescue *exceptions
caught_it = true
end
- caught_it.should be_true
+ caught_it.should == true
end
it "can combine a splatted list of exceptions with a literal list of exceptions" do
@@ -216,7 +220,7 @@ describe "The rescue keyword" do
rescue ArbitraryException, *exception_list
caught_it = true
end
- caught_it.should be_true
+ caught_it.should == true
caught = []
[->{raise ArbitraryException}, ->{raise SpecificExampleException}].each do |block|
begin
@@ -227,7 +231,7 @@ describe "The rescue keyword" do
end
caught.size.should == 2
exception_list.each do |exception_class|
- caught.map{|e| e.class}.should include(exception_class)
+ caught.map{|e| e.class}.should.include?(exception_class)
end
end
@@ -237,7 +241,7 @@ describe "The rescue keyword" do
raise OtherCustomException, "not rescued!"
rescue *exception_list
end
- end.should raise_error(OtherCustomException)
+ end.should.raise(OtherCustomException)
end
it "can rescue different types of exceptions in different ways" do
@@ -341,7 +345,7 @@ describe "The rescue keyword" do
ScratchPad << :else
end
ruby
- }.should raise_error(SyntaxError, /else without rescue is useless/)
+ }.should.raise(SyntaxError, /else without rescue is useless/)
end
it "will not execute an else block if an exception was raised" do
@@ -409,7 +413,7 @@ describe "The rescue keyword" do
ScratchPad << :two
raise SpecificExampleException, "an error from else"
end
- end.should raise_error(SpecificExampleException)
+ end.should.raise(SpecificExampleException)
ScratchPad.recorded.should == [:one, :two]
end
@@ -441,7 +445,7 @@ describe "The rescue keyword" do
rescue
ScratchPad << :caught
end
- }.should raise_error(exception.class)
+ }.should.raise(exception.class)
end
ScratchPad.recorded.should == []
end
@@ -472,7 +476,7 @@ describe "The rescue keyword" do
raise "error"
rescue rescuer
end
- }.should raise_error(TypeError) { |e|
+ }.should.raise(TypeError) { |e|
e.message.should =~ /class or module required for rescue clause/
}
end
@@ -484,7 +488,7 @@ describe "The rescue keyword" do
raise "error"
rescue *rescuer
end
- }.should raise_error(TypeError) { |e|
+ }.should.raise(TypeError) { |e|
e.message.should =~ /class or module required for rescue clause/
}
end
@@ -504,7 +508,7 @@ describe "The rescue keyword" do
raise "from block"
rescue (raise "from rescue expression")
end
- }.should raise_error(RuntimeError, "from rescue expression") { |e|
+ }.should.raise(RuntimeError, "from rescue expression") { |e|
e.cause.message.should == "from block"
}
end
@@ -538,7 +542,7 @@ describe "The rescue keyword" do
:caught
}
ruby
- }.should raise_error(SyntaxError)
+ }.should.raise(SyntaxError)
end
it "allows rescue in 'do end' block" do
@@ -559,7 +563,7 @@ describe "The rescue keyword" do
end
it "requires the 'rescue' in method arguments to be wrapped in parens" do
- -> { eval '1.+(1 rescue 1)' }.should raise_error(SyntaxError)
+ -> { eval '1.+(1 rescue 1)' }.should.raise(SyntaxError)
eval('1.+((1 rescue 1))').should == 2
end
@@ -589,7 +593,7 @@ describe "The rescue keyword" do
eval <<-ruby
a = 1 rescue RuntimeError 2
ruby
- }.should raise_error(SyntaxError)
+ }.should.raise(SyntaxError)
end
it "rescues only StandardError and its subclasses" do
@@ -598,7 +602,7 @@ describe "The rescue keyword" do
-> {
a = raise(Exception) rescue 1
- }.should raise_error(Exception)
+ }.should.raise(Exception)
end
it "rescues with multiple assignment" do
diff --git a/spec/ruby/language/reserved_keywords.rb b/spec/ruby/language/reserved_keywords.rb
new file mode 100644
index 0000000000..bd1a55feec
--- /dev/null
+++ b/spec/ruby/language/reserved_keywords.rb
@@ -0,0 +1,149 @@
+require_relative '../spec_helper'
+
+describe "Ruby's reserved keywords" do
+ # Copied from https://github.com/ruby/ruby/blob/master/defs/keywords
+ keywords = %w[
+ 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__
+ ]
+
+ keywords.each do |name|
+ describe "keyword '#{name}'" do
+ it "can't be used as local variable name" do
+ -> { eval(<<~RUBY) }.should.raise(SyntaxError)
+ #{name} = :local_variable
+ RUBY
+ end
+
+ if name == "defined?"
+ it "can't be used as an instance variable name" do
+ -> { eval(<<~RUBY) }.should.raise(SyntaxError)
+ @#{name} = :instance_variable
+ RUBY
+ end
+
+ it "can't be used as a class variable name" do
+ -> { eval(<<~RUBY) }.should.raise(SyntaxError)
+ class C
+ @@#{name} = :class_variable
+ end
+ RUBY
+ end
+
+ it "can't be used as a global variable name" do
+ -> { eval(<<~RUBY) }.should.raise(SyntaxError)
+ $#{name} = :global_variable
+ RUBY
+ end
+ else
+ it "can be used as an instance variable name" do
+ result = eval <<~RUBY
+ @#{name} = :instance_variable
+ @#{name}
+ RUBY
+
+ result.should == :instance_variable
+ end
+
+ it "can be used as a class variable name" do
+ result = eval <<~RUBY
+ class C
+ @@#{name} = :class_variable
+ @@#{name}
+ end
+ RUBY
+
+ result.should == :class_variable
+ end
+
+ it "can be used as a global variable name" do
+ result = eval <<~RUBY
+ $#{name} = :global_variable
+ $#{name}
+ RUBY
+
+ result.should == :global_variable
+ end
+ end
+
+ it "can't be used as a positional parameter name" do
+ -> { eval(<<~RUBY) }.should.raise(SyntaxError)
+ def x(#{name}); end
+ RUBY
+ end
+
+ invalid_kw_param_names = ["BEGIN","END","defined?"]
+
+ if invalid_kw_param_names.include?(name)
+ it "can't be used a keyword parameter name" do
+ -> { eval(<<~RUBY) }.should.raise(SyntaxError)
+ def m(#{name}:); end
+ RUBY
+ end
+ else
+ it "can be used a keyword parameter name" do
+ result = instance_eval <<~RUBY
+ def m(#{name}:)
+ binding.local_variable_get(:#{name})
+ end
+
+ m(#{name}: :argument)
+ RUBY
+
+ result.should == :argument
+ end
+ end
+
+ it "can be used as a method name" do
+ result = instance_eval <<~RUBY
+ def #{name}
+ :method_return_value
+ end
+
+ send(:#{name})
+ RUBY
+
+ result.should == :method_return_value
+ end
+ end
+ end
+end
diff --git a/spec/ruby/language/retry_spec.rb b/spec/ruby/language/retry_spec.rb
index 669d5f0ff5..39e58b7b5d 100644
--- a/spec/ruby/language/retry_spec.rb
+++ b/spec/ruby/language/retry_spec.rb
@@ -32,10 +32,10 @@ describe "The retry statement" do
end
it "raises a SyntaxError when used outside of a rescue 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)
+ -> { eval 'retry' }.should.raise(SyntaxError)
+ -> { eval 'begin; retry; end' }.should.raise(SyntaxError)
+ -> { eval 'def m; retry; end' }.should.raise(SyntaxError)
+ -> { eval 'module RetrySpecs; retry; end' }.should.raise(SyntaxError)
end
end
diff --git a/spec/ruby/language/return_spec.rb b/spec/ruby/language/return_spec.rb
index a62ed1242d..36a3cba4d7 100644
--- a/spec/ruby/language/return_spec.rb
+++ b/spec/ruby/language/return_spec.rb
@@ -19,7 +19,7 @@ describe "The return keyword" do
it "returns nil by default" do
def r; return; end
- r().should be_nil
+ r().should == nil
end
describe "in a Thread" do
@@ -31,7 +31,7 @@ describe "The return keyword" do
e
end
}
- t.value.should be_an_instance_of(LocalJumpError)
+ t.value.should.instance_of?(LocalJumpError)
end
end
@@ -176,11 +176,11 @@ describe "The return keyword" do
end
it "causes lambda to return nil if invoked without any arguments" do
- -> { return; 456 }.call.should be_nil
+ -> { return; 456 }.call.should == nil
end
it "causes lambda to return nil if invoked with an empty expression" do
- -> { return (); 456 }.call.should be_nil
+ -> { return (); 456 }.call.should == nil
end
it "causes lambda to return the value passed to return" do
@@ -229,7 +229,7 @@ describe "The return keyword" do
def f
1.times { 1.times {return true}; false}; false
end
- f.should be_true
+ f.should == true
end
end
@@ -417,7 +417,7 @@ describe "The return keyword" do
end
END_OF_CODE
- -> { load @filename }.should raise_error(SyntaxError)
+ -> { load @filename }.should.raise(SyntaxError)
end
end
@@ -431,7 +431,7 @@ describe "The return keyword" do
end
END_OF_CODE
- -> { load @filename }.should raise_error(LocalJumpError)
+ -> { load @filename }.should.raise(LocalJumpError)
end
end
diff --git a/spec/ruby/language/safe_navigator_spec.rb b/spec/ruby/language/safe_navigator_spec.rb
index b1e28c3963..e8b429631d 100644
--- a/spec/ruby/language/safe_navigator_spec.rb
+++ b/spec/ruby/language/safe_navigator_spec.rb
@@ -2,7 +2,7 @@ require_relative '../spec_helper'
describe "Safe navigator" do
it "requires a method name to be provided" do
- -> { eval("obj&. {}") }.should raise_error(SyntaxError)
+ -> { eval("obj&. {}") }.should.raise(SyntaxError)
end
context "when context is nil" do
@@ -26,7 +26,7 @@ describe "Safe navigator" do
it "calls the method" do
false&.to_s.should == "false"
- -> { false&.unknown }.should raise_error(NoMethodError)
+ -> { false&.unknown }.should.raise(NoMethodError)
end
end
@@ -34,7 +34,7 @@ describe "Safe navigator" do
it "calls the method" do
1&.to_s.should == "1"
- -> { 1&.unknown }.should raise_error(NoMethodError)
+ -> { 1&.unknown }.should.raise(NoMethodError)
end
end
@@ -140,7 +140,7 @@ describe "Safe navigator" do
-> {
obj&.foo += 3
- }.should raise_error(NoMethodError) { |e|
+ }.should.raise(NoMethodError) { |e|
e.name.should == :+
}
end
diff --git a/spec/ruby/language/send_spec.rb b/spec/ruby/language/send_spec.rb
index aaccdf0998..f56a77d529 100644
--- a/spec/ruby/language/send_spec.rb
+++ b/spec/ruby/language/send_spec.rb
@@ -22,7 +22,7 @@ describe "Invoking a method" do
it "raises ArgumentError if the method has a positive arity" do
-> {
specs.fooM1
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
end
@@ -38,7 +38,7 @@ describe "Invoking a method" do
it "raises ArgumentError if the methods arity doesn't match" do
-> {
specs.fooM1(1,2)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
end
@@ -54,7 +54,7 @@ describe "Invoking a method" do
it "raises ArgumentError if extra arguments are passed" do
-> {
specs.fooM0O1(2,3)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
end
@@ -66,13 +66,13 @@ describe "Invoking a method" do
it "raises an ArgumentError if there are no values for the mandatory args" do
-> {
specs.fooM1O1
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
it "raises an ArgumentError if too many values are passed" do
-> {
specs.fooM1O1(1,2,3)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
end
@@ -94,7 +94,7 @@ describe "Invoking a method" do
it "with a block converts the block to a Proc" do
prc = specs.makeproc { "hello" }
- prc.should be_kind_of(Proc)
+ prc.should.is_a?(Proc)
prc.call.should == "hello"
end
@@ -106,10 +106,28 @@ describe "Invoking a method" do
specs.yield_now(&o).should == :from_to_proc
end
+ ruby_version_is "4.0" do
+ it "raises TypeError if 'to_proc' doesn't return a Proc" do
+ o = LangSendSpecs::RawToProc.new(42)
+
+ -> {
+ specs.makeproc(&o)
+ }.should raise_consistent_error(TypeError, "can't convert LangSendSpecs::RawToProc into Proc (LangSendSpecs::RawToProc#to_proc gives Integer)")
+ end
+
+ it "raises TypeError if block object isn't a Proc and doesn't respond to `to_proc`" do
+ o = Object.new
+
+ -> {
+ specs.makeproc(&o)
+ }.should.raise(TypeError, "no implicit conversion of Object into Proc")
+ end
+ end
+
it "raises a SyntaxError with both a literal block and an object as block" do
-> {
eval "specs.oneb(10, &l){ 42 }"
- }.should raise_error(SyntaxError)
+ }.should.raise(SyntaxError)
end
it "with same names as existing variables is ok" do
@@ -194,21 +212,42 @@ describe "Invoking a method" do
o.args.should == [1,2]
end
- it "raises NameError if invoked as a vcall" do
- -> { no_such_method }.should raise_error NameError
+ describe "if invoked as a vcall" do
+ it "raises NameError" do
+ -> { no_such_method }.should.raise NameError
+ end
+
+ it "raises NameError with $! as a cause" do
+ begin
+ raise RuntimeError.new
+ rescue => cause
+ -> { no_such_method }.should.raise(NameError, cause:)
+ end
+ end
end
it "should omit the method_missing call from the backtrace for NameError" do
- -> { no_such_method }.should raise_error { |e| e.backtrace.first.should_not include("method_missing") }
+ -> { no_such_method }.should.raise { |e| e.backtrace.first.should_not.include?("method_missing") }
end
- it "raises NoMethodError if invoked as an unambiguous method call" do
- -> { no_such_method() }.should raise_error NoMethodError
- -> { no_such_method(1,2,3) }.should raise_error NoMethodError
+ describe "if invoked as an unambiguous method call" do
+ it "raises NoMethodError" do
+ -> { no_such_method() }.should.raise NoMethodError
+ -> { no_such_method(1,2,3) }.should.raise NoMethodError
+ end
+
+ it "raises NoMethodError with $! as a cause" do
+ begin
+ raise
+ rescue => cause
+ -> { no_such_method() }.should.raise(NoMethodError, cause:)
+ -> { no_such_method(1,2,3) }.should.raise(NoMethodError, cause:)
+ end
+ end
end
it "should omit the method_missing call from the backtrace for NoMethodError" do
- -> { no_such_method() }.should raise_error { |e| e.backtrace.first.should_not include("method_missing") }
+ -> { no_such_method() }.should.raise { |e| e.backtrace.first.should_not.include?("method_missing") }
end
end
@@ -337,7 +376,7 @@ describe "Invoking a method" do
it "with splat operator * and non-Array value uses value unchanged if it does not respond_to?(:to_ary)" do
obj = Object.new
- obj.should_not respond_to(:to_a)
+ obj.should_not.respond_to?(:to_a)
specs.fooM0R(*obj).should == [obj]
specs.fooM1R(1,*obj).should == [1, [obj]]
diff --git a/spec/ruby/language/shared/__FILE__.rb b/spec/ruby/language/shared/__FILE__.rb
index 3e4f5c958d..7e2e871932 100644
--- a/spec/ruby/language/shared/__FILE__.rb
+++ b/spec/ruby/language/shared/__FILE__.rb
@@ -9,14 +9,14 @@ describe :language___FILE__, shared: true do
end
it "equals the absolute path of a file loaded by an absolute path" do
- @object.send(@method, @path).should be_true
+ @object.send(@method, @path).should == true
ScratchPad.recorded.should == [@path]
end
it "equals the absolute path of a file loaded by a relative path" do
$LOAD_PATH << "."
Dir.chdir CODE_LOADING_DIR do
- @object.send(@method, "file_fixture.rb").should be_true
+ @object.send(@method, "file_fixture.rb").should == true
end
ScratchPad.recorded.should == [@path]
end
diff --git a/spec/ruby/language/shared/__LINE__.rb b/spec/ruby/language/shared/__LINE__.rb
index 076b74b3ba..6bfc8c1c17 100644
--- a/spec/ruby/language/shared/__LINE__.rb
+++ b/spec/ruby/language/shared/__LINE__.rb
@@ -9,7 +9,7 @@ describe :language___LINE__, shared: true do
end
it "equals the line number of the text in a loaded file" do
- @object.send(@method, @path).should be_true
+ @object.send(@method, @path).should == true
ScratchPad.recorded.should == [1, 5]
end
end
diff --git a/spec/ruby/language/singleton_class_spec.rb b/spec/ruby/language/singleton_class_spec.rb
index 45e1f7f3ad..20256a323c 100644
--- a/spec/ruby/language/singleton_class_spec.rb
+++ b/spec/ruby/language/singleton_class_spec.rb
@@ -15,39 +15,39 @@ describe "A singleton class" do
end
it "raises a TypeError for Integer's" do
- -> { 1.singleton_class }.should raise_error(TypeError)
+ -> { 1.singleton_class }.should.raise(TypeError)
end
it "raises a TypeError for symbols" do
- -> { :symbol.singleton_class }.should raise_error(TypeError)
+ -> { :symbol.singleton_class }.should.raise(TypeError)
end
it "is a singleton Class instance" do
o = mock('x')
- o.singleton_class.should be_kind_of(Class)
- o.singleton_class.should_not equal(Object)
- o.should be_kind_of(o.singleton_class)
+ o.singleton_class.should.is_a?(Class)
+ o.singleton_class.should_not.equal?(Object)
+ o.should.is_a?(o.singleton_class)
end
it "is a Class for classes" do
- ClassSpecs::A.singleton_class.should be_kind_of(Class)
+ ClassSpecs::A.singleton_class.should.is_a?(Class)
end
it "inherits from Class for classes" do
- Class.should be_ancestor_of(Object.singleton_class)
+ Object.singleton_class.ancestors.should.include?(Class)
end
it "is a subclass of Class's singleton class" do
ec = ClassSpecs::A.singleton_class
- ec.should be_kind_of(Class.singleton_class)
+ ec.should.is_a?(Class.singleton_class)
end
it "is a subclass of the same level of Class's singleton class" do
ecec = ClassSpecs::A.singleton_class.singleton_class
class_ec = Class.singleton_class
- ecec.should be_kind_of(class_ec.singleton_class)
- ecec.should be_kind_of(class_ec)
+ ecec.should.is_a?(class_ec.singleton_class)
+ ecec.should.is_a?(class_ec)
end
it "is a subclass of a superclass's singleton class" do
@@ -60,7 +60,7 @@ describe "A singleton class" do
ClassSpecs::H.singleton_class.singleton_class
end
- it "for BasicObject has Class as it's superclass" do
+ it "for BasicObject has Class as its superclass" do
BasicObject.singleton_class.superclass.should == Class
end
@@ -74,7 +74,7 @@ describe "A singleton class" do
end
it "doesn't have singleton class" do
- -> { bignum_value.singleton_class }.should raise_error(TypeError)
+ -> { bignum_value.singleton_class }.should.raise(TypeError)
end
end
@@ -105,20 +105,20 @@ describe "A constant on a singleton class" do
end
it "is not defined on the object's class" do
- @object.class.const_defined?(:CONST).should be_false
+ @object.class.const_defined?(:CONST).should == false
end
it "is not defined in the singleton class opener's scope" do
class << @object
CONST
end
- -> { CONST }.should raise_error(NameError)
+ -> { CONST }.should.raise(NameError)
end
it "cannot be accessed via object::CONST" do
-> do
@object::CONST
- end.should raise_error(TypeError)
+ end.should.raise(TypeError)
end
it "raises a NameError for anonymous_module::CONST" do
@@ -129,15 +129,15 @@ describe "A constant on a singleton class" do
-> do
@object::CONST
- end.should raise_error(NameError)
+ end.should.raise(NameError)
end
it "appears in the singleton class constant list" do
- @object.singleton_class.should have_constant(:CONST)
+ @object.singleton_class.should.const_defined?(:CONST, false)
end
it "does not appear in the object's class constant list" do
- @object.class.should_not have_constant(:CONST)
+ @object.class.should_not.const_defined?(:CONST)
end
it "is not preserved when the object is duped" do
@@ -145,14 +145,14 @@ describe "A constant on a singleton class" do
-> do
class << @object; CONST; end
- end.should raise_error(NameError)
+ end.should.raise(NameError)
end
it "is preserved when the object is cloned" do
@object = @object.clone
class << @object
- CONST.should_not be_nil
+ CONST.should_not == nil
end
end
end
@@ -168,7 +168,7 @@ describe "Defining instance methods on a singleton class" do
end
it "defines public methods" do
- @k_sc.should have_public_instance_method(:singleton_method)
+ @k_sc.public_instance_methods(false).should.include?(:singleton_method)
end
end
@@ -181,46 +181,46 @@ describe "Instance methods of a singleton class" do
end
it "include ones of the object's class" do
- @k_sc.should have_instance_method(:example_instance_method)
+ @k_sc.should.method_defined?(:example_instance_method, true)
end
it "does not include class methods of the object's class" do
- @k_sc.should_not have_instance_method(:example_class_method)
+ @k_sc.should_not.method_defined?(:example_class_method)
end
it "include instance methods of Object" do
- @a_sc.should have_instance_method(:example_instance_method_of_object)
+ @a_sc.should.method_defined?(:example_instance_method_of_object, true)
end
it "does not include class methods of Object" do
- @a_sc.should_not have_instance_method(:example_class_method_of_object)
+ @a_sc.should_not.method_defined?(:example_class_method_of_object)
end
describe "for a class" do
it "include instance methods of Class" do
- @a_c_sc.should have_instance_method(:example_instance_method_of_class)
+ @a_c_sc.should.method_defined?(:example_instance_method_of_class, true)
end
it "does not include class methods of Class" do
- @a_c_sc.should_not have_instance_method(:example_class_method_of_class)
+ @a_c_sc.should_not.method_defined?(:example_class_method_of_class)
end
it "does not include instance methods of the singleton class of Class" do
- @a_c_sc.should_not have_instance_method(:example_instance_method_of_singleton_class)
+ @a_c_sc.should_not.method_defined?(:example_instance_method_of_singleton_class)
end
it "does not include class methods of the singleton class of Class" do
- @a_c_sc.should_not have_instance_method(:example_class_method_of_singleton_class)
+ @a_c_sc.should_not.method_defined?(:example_class_method_of_singleton_class)
end
end
describe "for a singleton class" do
it "includes instance methods of the singleton class of Class" do
- @a_c_sc.singleton_class.should have_instance_method(:example_instance_method_of_singleton_class)
+ @a_c_sc.singleton_class.should.method_defined?(:example_instance_method_of_singleton_class, true)
end
it "does not include class methods of the singleton class of Class" do
- @a_c_sc.singleton_class.should_not have_instance_method(:example_class_method_of_singleton_class)
+ @a_c_sc.singleton_class.should_not.method_defined?(:example_class_method_of_singleton_class)
end
end
end
@@ -234,46 +234,46 @@ describe "Class methods of a singleton class" do
end
it "include ones of the object's class" do
- @k_sc.should have_method(:example_class_method)
+ @k_sc.should.respond_to?(:example_class_method)
end
it "does not include instance methods of the object's class" do
- @k_sc.should_not have_method(:example_instance_method)
+ @k_sc.should_not.respond_to?(:example_instance_method)
end
it "include instance methods of Class" do
- @a_sc.should have_method(:example_instance_method_of_class)
+ @a_sc.should.respond_to?(:example_instance_method_of_class)
end
it "does not include class methods of Class" do
- @a_sc.should_not have_method(:example_class_method_of_class)
+ @a_sc.should_not.respond_to?(:example_class_method_of_class)
end
describe "for a class" do
it "include instance methods of Class" do
- @a_c_sc.should have_method(:example_instance_method_of_class)
+ @a_c_sc.should.respond_to?(:example_instance_method_of_class)
end
it "include class methods of Class" do
- @a_c_sc.should have_method(:example_class_method_of_class)
+ @a_c_sc.should.respond_to?(:example_class_method_of_class)
end
it "include instance methods of the singleton class of Class" do
- @a_c_sc.should have_method(:example_instance_method_of_singleton_class)
+ @a_c_sc.should.respond_to?(:example_instance_method_of_singleton_class)
end
it "does not include class methods of the singleton class of Class" do
- @a_c_sc.should_not have_method(:example_class_method_of_singleton_class)
+ @a_c_sc.should_not.respond_to?(:example_class_method_of_singleton_class)
end
end
describe "for a singleton class" do
it "include instance methods of the singleton class of Class" do
- @a_c_sc.singleton_class.should have_method(:example_instance_method_of_singleton_class)
+ @a_c_sc.singleton_class.should.respond_to?(:example_instance_method_of_singleton_class)
end
it "include class methods of the singleton class of Class" do
- @a_c_sc.singleton_class.should have_method(:example_class_method_of_singleton_class)
+ @a_c_sc.singleton_class.should.respond_to?(:example_class_method_of_singleton_class)
end
end
end
@@ -282,13 +282,13 @@ describe "Instantiating a singleton class" do
it "raises a TypeError when new is called" do
-> {
Object.new.singleton_class.new
- }.should raise_error(TypeError)
+ }.should.raise(TypeError)
end
it "raises a TypeError when allocate is called" do
-> {
Object.new.singleton_class.allocate
- }.should raise_error(TypeError)
+ }.should.raise(TypeError)
end
end
diff --git a/spec/ruby/language/source_encoding_spec.rb b/spec/ruby/language/source_encoding_spec.rb
index 7135bc0a70..5a243fa2c3 100644
--- a/spec/ruby/language/source_encoding_spec.rb
+++ b/spec/ruby/language/source_encoding_spec.rb
@@ -29,7 +29,7 @@ describe "Source files" do
touch(path, "wb") { |f| f.write source }
begin
- ruby_exe(path, args: "2>&1", exit_status: 1).should =~ /invalid multibyte char/
+ ruby_exe(path, args: "2>&1", exit_status: 1).b.should =~ /invalid multibyte char/
ensure
rm_r path
end
@@ -51,7 +51,7 @@ describe "Source files" do
touch(path, "wb") { |f| f.write source }
begin
- ruby_exe(path, args: "2>&1", exit_status: 1).should =~ /invalid multibyte char/
+ ruby_exe(path, args: "2>&1", exit_status: 1).b.should =~ /invalid multibyte char/
ensure
rm_r path
end
diff --git a/spec/ruby/language/string_spec.rb b/spec/ruby/language/string_spec.rb
index f287731bed..163063032f 100644
--- a/spec/ruby/language/string_spec.rb
+++ b/spec/ruby/language/string_spec.rb
@@ -133,6 +133,12 @@ describe "Ruby character strings" do
"#{obj}".should == '42'
end
+ it "raise NoMethodError when #to_s is not defined for the object" do
+ obj = BasicObject.new
+
+ -> { "#{obj}" }.should.raise(NoMethodError)
+ end
+
it "uses an internal representation when #to_s doesn't return a String" do
obj = mock('to_s')
obj.stub!(:to_s).and_return(42)
@@ -143,7 +149,7 @@ describe "Ruby character strings" do
# is that if you interpolate an object that fails to return
# a String, you will still get a String and not raise an
# exception.
- "#{obj}".should be_an_instance_of(String)
+ "#{obj}".should.instance_of?(String)
end
it "allows a dynamic string to parse a nested do...end block as an argument to a call without parens, interpolated" do
@@ -281,7 +287,7 @@ describe "Ruby String interpolation" do
a = "\u3042"
b = "\xff".dup.force_encoding "binary"
- -> { "#{a} #{b}" }.should raise_error(Encoding::CompatibilityError)
+ -> { "#{a} #{b}" }.should.raise(Encoding::CompatibilityError)
end
it "creates a non-frozen String" do
diff --git a/spec/ruby/language/super_spec.rb b/spec/ruby/language/super_spec.rb
index 7d9e896d8b..f595d49395 100644
--- a/spec/ruby/language/super_spec.rb
+++ b/spec/ruby/language/super_spec.rb
@@ -83,8 +83,8 @@ describe "The super keyword" do
end
end
- -> {sub_normal.new.foo}.should raise_error(NoMethodError, /super/)
- -> {sub_zsuper.new.foo}.should raise_error(NoMethodError, /super/)
+ -> {sub_normal.new.foo}.should.raise(NoMethodError, /super/)
+ -> {sub_zsuper.new.foo}.should.raise(NoMethodError, /super/)
end
it "uses given block even if arguments are passed explicitly" do
@@ -130,7 +130,7 @@ describe "The super keyword" do
end
end
- c2.new.m('a') { raise }.should be_false
+ c2.new.m('a') { raise }.should == false
end
it "uses block argument given to method when used in a block" do
@@ -200,7 +200,7 @@ describe "The super keyword" do
end
end
- -> { klass.new.a(:a_called) }.should raise_error(RuntimeError)
+ -> { klass.new.a(:a_called) }.should.raise(RuntimeError)
end
it "is able to navigate to super, when a method is defined dynamically on the singleton class" do
@@ -461,4 +461,18 @@ describe "The super keyword" do
@all.foo('a', b: 'b').should == [['a'], {b: 'b'}]
end
end
+
+ it "works in method definitions using **nil" do
+ parent = Class.new do
+ def m(*args, **kwargs)
+ [args, kwargs]
+ end
+ end
+ child = Class.new(parent) do
+ def m(*args, **nil)
+ super
+ end
+ end
+ child.new.m(1, 2).should == [[1, 2], {}]
+ end
end
diff --git a/spec/ruby/language/symbol_spec.rb b/spec/ruby/language/symbol_spec.rb
index 0801d3223e..81fe06b50b 100644
--- a/spec/ruby/language/symbol_spec.rb
+++ b/spec/ruby/language/symbol_spec.rb
@@ -3,7 +3,7 @@ require_relative '../spec_helper'
describe "A Symbol literal" do
it "is a ':' followed by any number of valid characters" do
a = :foo
- a.should be_kind_of(Symbol)
+ a.should.is_a?(Symbol)
a.inspect.should == ':foo'
end
@@ -21,7 +21,7 @@ describe "A Symbol literal" do
:_Foo,
:&,
:_9
- ].each { |s| s.should be_kind_of(Symbol) }
+ ].each { |s| s.should.is_a?(Symbol) }
end
it "is a ':' followed by a single- or double-quoted string that may contain otherwise invalid characters" do
@@ -31,7 +31,7 @@ describe "A Symbol literal" do
[:"foo #{1 + 1}", ':"foo 2"'],
[:"foo\nbar", ':"foo\nbar"'],
].each { |sym, str|
- sym.should be_kind_of(Symbol)
+ sym.should.is_a?(Symbol)
sym.inspect.should == str
}
end
@@ -42,22 +42,22 @@ describe "A Symbol literal" do
end
it "may contain '::' in the string" do
- :'Some::Class'.should be_kind_of(Symbol)
+ :'Some::Class'.should.is_a?(Symbol)
end
it "is converted to a literal, unquoted representation if the symbol contains only valid characters" do
a, b, c = :'foo', :'+', :'Foo__9'
- a.should be_kind_of(Symbol)
+ a.should.is_a?(Symbol)
a.inspect.should == ':foo'
- b.should be_kind_of(Symbol)
+ b.should.is_a?(Symbol)
b.inspect.should == ':+'
- c.should be_kind_of(Symbol)
+ c.should.is_a?(Symbol)
c.inspect.should == ':Foo__9'
end
it "can be created by the %s-delimited expression" do
a, b = :'foo bar', %s{foo bar}
- b.should be_kind_of(Symbol)
+ b.should.is_a?(Symbol)
b.inspect.should == ':"foo bar"'
b.should == a
end
@@ -68,7 +68,7 @@ describe "A Symbol literal" do
[:'a string', :'a string'],
[:"#{var}", :"#{var}"]
].each { |a, b|
- a.should equal(b)
+ a.should.equal?(b)
}
end
@@ -78,7 +78,7 @@ describe "A Symbol literal" do
it "can be an empty string" do
c = :''
- c.should be_kind_of(Symbol)
+ c.should.is_a?(Symbol)
c.inspect.should == ':""'
end
@@ -101,7 +101,7 @@ describe "A Symbol literal" do
ScratchPad.record []
-> {
eval 'ScratchPad << 1; :"\xC3"'
- }.should raise_error(SyntaxError, /invalid symbol/)
+ }.should.raise(SyntaxError, /invalid symbol/)
ScratchPad.recorded.should == []
end
end
diff --git a/spec/ruby/language/throw_spec.rb b/spec/ruby/language/throw_spec.rb
index d723843688..73f64de17d 100644
--- a/spec/ruby/language/throw_spec.rb
+++ b/spec/ruby/language/throw_spec.rb
@@ -35,7 +35,7 @@ describe "The throw keyword" do
throw :exit
end
end
- $!.should be_nil
+ $!.should == nil
end
it "allows any object as its argument" do
@@ -45,7 +45,7 @@ describe "The throw keyword" do
end
it "does not convert strings to a symbol" do
- -> { catch(:exit) { throw "exit" } }.should raise_error(ArgumentError)
+ -> { catch(:exit) { throw "exit" } }.should.raise(ArgumentError)
end
it "unwinds stack from within a method" do
@@ -64,8 +64,8 @@ describe "The throw keyword" do
end
it "raises an ArgumentError if outside of scope of a matching catch" do
- -> { throw :test, 5 }.should raise_error(ArgumentError)
- -> { catch(:different) { throw :test, 5 } }.should raise_error(ArgumentError)
+ -> { throw :test, 5 }.should.raise(ArgumentError)
+ -> { catch(:different) { throw :test, 5 } }.should.raise(ArgumentError)
end
it "raises an UncaughtThrowError if used to exit a thread" do
@@ -73,7 +73,7 @@ describe "The throw keyword" do
t = Thread.new {
-> {
throw :what
- }.should raise_error(UncaughtThrowError)
+ }.should.raise(UncaughtThrowError)
}
t.join
end
diff --git a/spec/ruby/language/undef_spec.rb b/spec/ruby/language/undef_spec.rb
index 268c0b84c3..98ecd99c21 100644
--- a/spec/ruby/language/undef_spec.rb
+++ b/spec/ruby/language/undef_spec.rb
@@ -14,42 +14,42 @@ describe "The undef keyword" do
@undef_class.class_eval do
undef meth
end
- -> { @obj.meth(5) }.should raise_error(NoMethodError)
+ -> { @obj.meth(5) }.should.raise(NoMethodError)
end
it "with a simple symbol" do
@undef_class.class_eval do
undef :meth
end
- -> { @obj.meth(5) }.should raise_error(NoMethodError)
+ -> { @obj.meth(5) }.should.raise(NoMethodError)
end
it "with a single quoted symbol" do
@undef_class.class_eval do
undef :'meth'
end
- -> { @obj.meth(5) }.should raise_error(NoMethodError)
+ -> { @obj.meth(5) }.should.raise(NoMethodError)
end
it "with a double quoted symbol" do
@undef_class.class_eval do
undef :"meth"
end
- -> { @obj.meth(5) }.should raise_error(NoMethodError)
+ -> { @obj.meth(5) }.should.raise(NoMethodError)
end
it "with an interpolated symbol" do
@undef_class.class_eval do
undef :"#{'meth'}"
end
- -> { @obj.meth(5) }.should raise_error(NoMethodError)
+ -> { @obj.meth(5) }.should.raise(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)
+ -> { @obj.meth(5) }.should.raise(NoMethodError)
end
end
@@ -70,7 +70,7 @@ describe "The undef keyword" do
Class.new do
-> {
undef not_exist
- }.should raise_error(NameError) { |e|
+ }.should.raise(NameError) { |e|
# a NameError and not a NoMethodError
e.class.should == NameError
}
diff --git a/spec/ruby/language/variables_spec.rb b/spec/ruby/language/variables_spec.rb
index eb080eea55..e01e03f01e 100644
--- a/spec/ruby/language/variables_spec.rb
+++ b/spec/ruby/language/variables_spec.rb
@@ -91,7 +91,7 @@ describe "Multiple assignment" do
x = mock("multi-assign single RHS")
x.should_receive(:to_ary).and_return(1)
- -> { a, b, c = x }.should raise_error(TypeError)
+ -> { a, b, c = x }.should.raise(TypeError)
end
it "does not call #to_a to convert an Object RHS when assigning a simple MLHS" do
@@ -122,7 +122,7 @@ describe "Multiple assignment" do
ary = [1, 2]
x = (a, b = ary)
- x.should equal(ary)
+ x.should.equal?(ary)
end
it "returns the RHS when it is an Array subclass" do
@@ -130,7 +130,7 @@ describe "Multiple assignment" do
ary = cls.new [1, 2]
x = (a, b = ary)
- x.should equal(ary)
+ x.should.equal?(ary)
end
it "does not call #to_ary on an Array subclass instance" do
@@ -172,7 +172,7 @@ describe "Multiple assignment" do
x = mock("multi-assign splat")
x.should_receive(:to_ary).and_return(1)
- -> { *a = x }.should raise_error(TypeError)
+ -> { *a = x }.should.raise(TypeError)
end
it "does not call #to_ary on an Array subclass" do
@@ -189,8 +189,8 @@ describe "Multiple assignment" do
ary = cls.new [1, 2]
x = (*a = ary)
- x.should equal(ary)
- a.should be_an_instance_of(Array)
+ x.should.equal?(ary)
+ a.should.instance_of?(Array)
end
it "calls #to_ary to convert an Object RHS with MLHS" do
@@ -205,7 +205,7 @@ describe "Multiple assignment" do
x = mock("multi-assign splat")
x.should_receive(:to_ary).and_return(1)
- -> { a, *b, c = x }.should raise_error(TypeError)
+ -> { a, *b, c = x }.should.raise(TypeError)
end
it "does not call #to_a to convert an Object RHS with a MLHS" do
@@ -301,7 +301,7 @@ describe "Multiple assignment" do
x = mock("multi-assign attributes")
x.should_receive(:m).and_return(y)
- -> { a, b = x.m }.should raise_error(TypeError)
+ -> { a, b = x.m }.should.raise(TypeError)
end
it "assigns values from a RHS method call with receiver and arguments" do
@@ -363,7 +363,7 @@ describe "Multiple assignment" do
a.should == []
end
- ruby_version_is "3.5" do
+ ruby_version_is "4.0" do
it "converts nil to empty array without calling a method" do
nil.should_not_receive(:to_a)
@@ -372,7 +372,7 @@ describe "Multiple assignment" do
end
end
- ruby_version_is ""..."3.5" do
+ ruby_version_is ""..."4.0" do
it "calls #to_a to convert nil to an empty Array" do
nil.should_receive(:to_a).and_return([])
@@ -393,7 +393,7 @@ describe "Multiple assignment" do
ary = [1, 2]
(a = *ary).should == [1, 2]
- a.should_not equal(ary)
+ a.should_not.equal?(ary)
end
it "does not call #to_a on an Array subclass" do
@@ -412,10 +412,10 @@ describe "Multiple assignment" do
x = (a = *ary)
x.should == [1, 2]
- x.should be_an_instance_of(Array)
+ x.should.instance_of?(Array)
a.should == [1, 2]
- a.should be_an_instance_of(Array)
+ a.should.instance_of?(Array)
end
it "unfreezes the array returned from calling 'to_a' on the splatted value" do
@@ -481,7 +481,7 @@ describe "Multiple assignment" do
x = mock("multi-assign RHS splat")
x.should_receive(:to_a).and_return(1)
- -> { *a = *x }.should raise_error(TypeError)
+ -> { *a = *x }.should.raise(TypeError)
end
it "does not call #to_ary to convert an Object RHS with a single splat LHS" do
@@ -527,7 +527,7 @@ describe "Multiple assignment" do
x = mock("multi-assign splat")
x.should_receive(:to_a).and_return(1)
- -> { a = *x }.should raise_error(TypeError)
+ -> { a = *x }.should.raise(TypeError)
end
it "calls #to_a to convert an Object splat RHS when assigned to a simple MLHS" do
@@ -542,7 +542,7 @@ describe "Multiple assignment" do
x = mock("multi-assign splat")
x.should_receive(:to_a).and_return(1)
- -> { a, b, c = *x }.should raise_error(TypeError)
+ -> { a, b, c = *x }.should.raise(TypeError)
end
it "does not call #to_ary to convert an Object splat RHS when assigned to a simple MLHS" do
@@ -565,7 +565,7 @@ describe "Multiple assignment" do
x = mock("multi-assign splat")
x.should_receive(:to_a).and_return(1)
- -> { a, *b, c = *x }.should raise_error(TypeError)
+ -> { a, *b, c = *x }.should.raise(TypeError)
end
it "does not call #to_ary to convert an Object RHS with a MLHS" do
@@ -645,7 +645,7 @@ describe "Multiple assignment" do
x = mock("multi-assign splat MRHS")
x.should_receive(:to_a).and_return(1)
- -> { a, *b = 1, *x }.should raise_error(TypeError)
+ -> { a, *b = 1, *x }.should.raise(TypeError)
end
it "does not call #to_ary to convert a splatted Object as part of a MRHS with a splat MRHS" do
@@ -668,7 +668,7 @@ describe "Multiple assignment" do
x = mock("multi-assign splat MRHS")
x.should_receive(:to_a).and_return(1)
- -> { a, *b = *x, 1 }.should raise_error(TypeError)
+ -> { a, *b = *x, 1 }.should.raise(TypeError)
end
it "does not call #to_ary to convert a splatted Object with a splat MRHS" do
@@ -717,7 +717,7 @@ describe "Multiple assignment" do
x = mock("multi-assign mixed RHS")
x.should_receive(:to_ary).and_return(x)
- -> { a, (b, c), d = 1, x, 3, 4 }.should raise_error(TypeError)
+ -> { a, (b, c), d = 1, x, 3, 4 }.should.raise(TypeError)
end
it "calls #to_a to convert a splatted Object value in a MRHS" do
@@ -741,7 +741,7 @@ describe "Multiple assignment" do
x = mock("multi-assign mixed splatted RHS")
x.should_receive(:to_ary).and_return(x)
- -> { a, *b, (c, d) = 1, 2, 3, *x }.should raise_error(TypeError)
+ -> { a, *b, (c, d) = 1, 2, 3, *x }.should.raise(TypeError)
end
it "does not call #to_ary to convert an Object when the position receiving the value is a simple variable" do
@@ -889,7 +889,7 @@ describe 'Allowed characters' do
á¼BB = 1
end
CODE
- end.should raise_error(SyntaxError, /dynamic constant assignment/)
+ end.should.raise(SyntaxError, /dynamic constant assignment/)
end
end
diff --git a/spec/ruby/language/while_spec.rb b/spec/ruby/language/while_spec.rb
index e172453ca6..b9bf32047d 100644
--- a/spec/ruby/language/while_spec.rb
+++ b/spec/ruby/language/while_spec.rb
@@ -88,7 +88,7 @@ describe "The while expression" do
break if c
c = false
)
- end.should be_nil
+ end.should == nil
end
it "stops running body if interrupted by break in a begin ... end element op-assign-or value" do
@@ -99,7 +99,7 @@ describe "The while expression" do
break if c
c = false
end
- end.should be_nil
+ end.should == nil
end
it "stops running body if interrupted by break in a parenthesized element op-assign value" do
@@ -111,7 +111,7 @@ describe "The while expression" do
break if c
c = false
)
- end.should be_nil
+ end.should == nil
a.should == [1, 2]
end
@@ -123,7 +123,7 @@ describe "The while expression" do
break if c
c = false
end
- end.should be_nil
+ end.should == nil
a.should == [1, 2]
end
@@ -139,7 +139,7 @@ describe "The while expression" do
break unless d
d = false
)
- end.should be_nil
+ end.should == nil
end
it "stops running body if interrupted by break with unless in a begin ... end attribute op-assign-or value" do
@@ -153,7 +153,7 @@ describe "The while expression" do
break unless d
d = false
end
- end.should be_nil
+ end.should == nil
end
it "stops running body if interrupted by break in a parenthesized attribute op-assign-or value" do
@@ -168,7 +168,7 @@ describe "The while expression" do
break if c
c = false
)
- end.should be_nil
+ end.should == nil
end
it "stops running body if interrupted by break in a begin ... end attribute op-assign-or value" do
@@ -182,7 +182,7 @@ describe "The while expression" do
break if c
c = false
end
- end.should be_nil
+ end.should == nil
end
it "returns value passed to break if interrupted by break" do
diff --git a/spec/ruby/language/yield_spec.rb b/spec/ruby/language/yield_spec.rb
index e125cf8e73..3173f41b0c 100644
--- a/spec/ruby/language/yield_spec.rb
+++ b/spec/ruby/language/yield_spec.rb
@@ -13,7 +13,7 @@ describe "The yield call" do
describe "taking no arguments" do
it "raises a LocalJumpError when the method is not passed a block" do
- -> { @y.z }.should raise_error(LocalJumpError)
+ -> { @y.z }.should.raise(LocalJumpError)
end
it "ignores assignment to the explicit block argument and calls the passed block" do
@@ -28,7 +28,7 @@ describe "The yield call" do
describe "taking a single argument" do
describe "when no block is given" do
it "raises a LocalJumpError" do
- -> { @y.s(1) }.should raise_error(LocalJumpError)
+ -> { @y.s(1) }.should.raise(LocalJumpError)
end
end
@@ -48,6 +48,12 @@ describe "The yield call" do
it "passes a single, multi-value Array" do
@y.s([1, 2, 3]) { |*a| a }.should == [[1, 2, 3]]
end
+
+ describe "with optional argument" do
+ it "does not destructure a single array argument" do
+ @y.s([1, 2, 3]) { |a = 99| a }.should == [1, 2, 3]
+ end
+ end
end
describe "yielding to a lambda" do
@@ -70,20 +76,20 @@ describe "The yield call" do
it "raises an ArgumentError if too few arguments are passed" do
-> {
@y.s(1, &-> a, b { [a,b] })
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
it "should not destructure an Array into multiple arguments" do
-> {
@y.s([1, 2], &-> a, b { [a,b] })
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
end
end
describe "taking multiple arguments" do
it "raises a LocalJumpError when the method is not passed a block" do
- -> { @y.m(1, 2, 3) }.should raise_error(LocalJumpError)
+ -> { @y.m(1, 2, 3) }.should.raise(LocalJumpError)
end
it "passes the arguments to the block" do
@@ -97,19 +103,19 @@ describe "The yield call" do
it "raises an ArgumentError if too many arguments are passed to a lambda" do
-> {
@y.m(1, 2, 3, &-> a { })
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
it "raises an ArgumentError if too few arguments are passed to a lambda" do
-> {
@y.m(1, 2, 3, &-> a, b, c, d { })
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
end
describe "taking a single splatted argument" do
it "raises a LocalJumpError when the method is not passed a block" do
- -> { @y.r(0) }.should raise_error(LocalJumpError)
+ -> { @y.r(0) }.should.raise(LocalJumpError)
end
it "passes a single value" do
@@ -141,7 +147,7 @@ describe "The yield call" do
describe "taking multiple arguments with a splat" do
it "raises a LocalJumpError when the method is not passed a block" do
- -> { @y.rs(1, 2, [3, 4]) }.should raise_error(LocalJumpError)
+ -> { @y.rs(1, 2, [3, 4]) }.should.raise(LocalJumpError)
end
it "passes the arguments to the block" do
@@ -166,7 +172,7 @@ describe "The yield call" do
describe "taking matching arguments with splats and post args" do
it "raises a LocalJumpError when the method is not passed a block" do
- -> { @y.rs(1, 2, [3, 4]) }.should raise_error(LocalJumpError)
+ -> { @y.rs(1, 2, [3, 4]) }.should.raise(LocalJumpError)
end
it "passes the arguments to the block" do
@@ -193,7 +199,7 @@ describe "Using yield in a singleton class literal" do
end
RUBY
- -> { eval(code) }.should raise_error(SyntaxError, /Invalid yield/)
+ -> { eval(code) }.should.raise(SyntaxError, /Invalid yield/)
end
end
@@ -203,7 +209,7 @@ describe "Using yield in non-lambda block" do
1.times { yield }
RUBY
- -> { eval(code) }.should raise_error(SyntaxError, /Invalid yield/)
+ -> { eval(code) }.should.raise(SyntaxError, /Invalid yield/)
end
end
@@ -215,6 +221,6 @@ describe "Using yield in a module literal" do
end
RUBY
- -> { eval(code) }.should raise_error(SyntaxError, /Invalid yield/)
+ -> { eval(code) }.should.raise(SyntaxError, /Invalid yield/)
end
end
diff --git a/spec/ruby/library/English/English_spec.rb b/spec/ruby/library/English/English_spec.rb
index 4d615d1e25..bdc3774608 100644
--- a/spec/ruby/library/English/English_spec.rb
+++ b/spec/ruby/library/English/English_spec.rb
@@ -7,26 +7,26 @@ describe "English" do
begin
raise "error"
rescue
- $ERROR_INFO.should_not be_nil
+ $ERROR_INFO.should_not == nil
$ERROR_INFO.should == $!
end
- $ERROR_INFO.should be_nil
+ $ERROR_INFO.should == nil
end
it "aliases $ERROR_POSITION to $@" do
begin
raise "error"
rescue
- $ERROR_POSITION.should_not be_nil
+ $ERROR_POSITION.should_not == nil
$ERROR_POSITION.should == $@
end
- $ERROR_POSITION.should be_nil
+ $ERROR_POSITION.should == nil
end
it "aliases $FS to $;" do
original = $;
suppress_warning {$; = ","}
- $FS.should_not be_nil
+ $FS.should_not == nil
$FS.should == $;
suppress_warning {$; = original}
end
@@ -34,7 +34,7 @@ describe "English" do
it "aliases $FIELD_SEPARATOR to $;" do
original = $;
suppress_warning {$; = ","}
- $FIELD_SEPARATOR.should_not be_nil
+ $FIELD_SEPARATOR.should_not == nil
$FIELD_SEPARATOR.should == $;
suppress_warning {$; = original}
end
@@ -42,7 +42,7 @@ describe "English" do
it "aliases $OFS to $," do
original = $,
suppress_warning {$, = "|"}
- $OFS.should_not be_nil
+ $OFS.should_not == nil
$OFS.should == $,
suppress_warning {$, = original}
end
@@ -50,25 +50,25 @@ describe "English" do
it "aliases $OUTPUT_FIELD_SEPARATOR to $," do
original = $,
suppress_warning {$, = "|"}
- $OUTPUT_FIELD_SEPARATOR.should_not be_nil
+ $OUTPUT_FIELD_SEPARATOR.should_not == nil
$OUTPUT_FIELD_SEPARATOR.should == $,
suppress_warning {$, = original}
end
it "aliases $RS to $/" do
- $RS.should_not be_nil
+ $RS.should_not == nil
$RS.should == $/
end
it "aliases $INPUT_RECORD_SEPARATOR to $/" do
- $INPUT_RECORD_SEPARATOR.should_not be_nil
+ $INPUT_RECORD_SEPARATOR.should_not == nil
$INPUT_RECORD_SEPARATOR.should == $/
end
it "aliases $ORS to $\\" do
original = $\
suppress_warning {$\ = "\t"}
- $ORS.should_not be_nil
+ $ORS.should_not == nil
$ORS.should == $\
suppress_warning {$\ = original}
end
@@ -76,98 +76,86 @@ describe "English" do
it "aliases $OUTPUT_RECORD_SEPARATOR to $\\" do
original = $\
suppress_warning {$\ = "\t"}
- $OUTPUT_RECORD_SEPARATOR.should_not be_nil
+ $OUTPUT_RECORD_SEPARATOR.should_not == nil
$OUTPUT_RECORD_SEPARATOR.should == $\
suppress_warning {$\ = original}
end
it "aliases $INPUT_LINE_NUMBER to $." do
- $INPUT_LINE_NUMBER.should_not be_nil
+ $INPUT_LINE_NUMBER.should_not == nil
$INPUT_LINE_NUMBER.should == $.
end
it "aliases $NR to $." do
- $NR.should_not be_nil
+ $NR.should_not == nil
$NR.should == $.
end
it "aliases $LAST_READ_LINE to $_ needs to be reviewed for spec completeness"
it "aliases $DEFAULT_OUTPUT to $>" do
- $DEFAULT_OUTPUT.should_not be_nil
+ $DEFAULT_OUTPUT.should_not == nil
$DEFAULT_OUTPUT.should == $>
end
it "aliases $DEFAULT_INPUT to $<" do
- $DEFAULT_INPUT.should_not be_nil
+ $DEFAULT_INPUT.should_not == nil
$DEFAULT_INPUT.should == $<
end
it "aliases $PID to $$" do
- $PID.should_not be_nil
+ $PID.should_not == nil
$PID.should == $$
end
it "aliases $PID to $$" do
- $PID.should_not be_nil
+ $PID.should_not == nil
$PID.should == $$
end
it "aliases $PROCESS_ID to $$" do
- $PROCESS_ID.should_not be_nil
+ $PROCESS_ID.should_not == nil
$PROCESS_ID.should == $$
end
it "aliases $CHILD_STATUS to $?" do
ruby_exe('exit 0')
- $CHILD_STATUS.should_not be_nil
+ $CHILD_STATUS.should_not == nil
$CHILD_STATUS.should == $?
end
it "aliases $LAST_MATCH_INFO to $~" do
/c(a)t/ =~ "cat"
- $LAST_MATCH_INFO.should_not be_nil
+ $LAST_MATCH_INFO.should_not == nil
$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
- end
- end
-
it "aliases $ARGV to $*" do
- $ARGV.should_not be_nil
+ $ARGV.should_not == nil
$ARGV.should == $*
end
it "aliases $MATCH to $&" do
/c(a)t/ =~ "cat"
- $MATCH.should_not be_nil
+ $MATCH.should_not == nil
$MATCH.should == $&
end
it "aliases $PREMATCH to $`" do
/c(a)t/ =~ "cat"
- $PREMATCH.should_not be_nil
+ $PREMATCH.should_not == nil
$PREMATCH.should == $`
end
it "aliases $POSTMATCH to $'" do
/c(a)t/ =~ "cat"
- $POSTMATCH.should_not be_nil
+ $POSTMATCH.should_not == nil
$POSTMATCH.should == $'
end
it "aliases $LAST_PAREN_MATCH to $+" do
/c(a)t/ =~ "cat"
- $LAST_PAREN_MATCH.should_not be_nil
+ $LAST_PAREN_MATCH.should_not == nil
$LAST_PAREN_MATCH.should == $+
end
end
diff --git a/spec/ruby/library/English/alias_spec.rb b/spec/ruby/library/English/alias_spec.rb
index 78ccfb4398..3ff92f964d 100644
--- a/spec/ruby/library/English/alias_spec.rb
+++ b/spec/ruby/library/English/alias_spec.rb
@@ -4,11 +4,11 @@ require 'English'
describe "English" do
it "aliases $! to $ERROR_INFO and $ERROR_INFO still returns an Exception with a backtrace" do
exception = (1 / 0 rescue $ERROR_INFO)
- exception.should be_kind_of(Exception)
- exception.backtrace.should be_kind_of(Array)
+ exception.should.is_a?(Exception)
+ exception.backtrace.should.is_a?(Array)
end
it "aliases $@ to $ERROR_POSITION and $ERROR_POSITION still returns a backtrace" do
- (1 / 0 rescue $ERROR_POSITION).should be_kind_of(Array)
+ (1 / 0 rescue $ERROR_POSITION).should.is_a?(Array)
end
end
diff --git a/spec/ruby/library/base64/strict_decode64_spec.rb b/spec/ruby/library/base64/strict_decode64_spec.rb
index d258223c82..7b52f0c922 100644
--- a/spec/ruby/library/base64/strict_decode64_spec.rb
+++ b/spec/ruby/library/base64/strict_decode64_spec.rb
@@ -14,25 +14,25 @@ describe "Base64#strict_decode64" do
it "raises ArgumentError when the given string contains CR" do
-> do
Base64.strict_decode64("U2VuZCByZWluZm9yY2VtZW50cw==\r")
- end.should raise_error(ArgumentError)
+ end.should.raise(ArgumentError)
end
it "raises ArgumentError when the given string contains LF" do
-> do
Base64.strict_decode64("U2VuZCByZWluZm9yY2VtZW50cw==\n")
- end.should raise_error(ArgumentError)
+ end.should.raise(ArgumentError)
end
it "raises ArgumentError when the given string has wrong padding" do
-> do
Base64.strict_decode64("=U2VuZCByZWluZm9yY2VtZW50cw==")
- end.should raise_error(ArgumentError)
+ end.should.raise(ArgumentError)
end
it "raises ArgumentError when the given string contains an invalid character" do
-> do
Base64.strict_decode64("%3D")
- end.should raise_error(ArgumentError)
+ end.should.raise(ArgumentError)
end
it "returns a binary encoded string" do
diff --git a/spec/ruby/library/bigdecimal/BigDecimal_spec.rb b/spec/ruby/library/bigdecimal/BigDecimal_spec.rb
index 45f5ebffc7..6adebabe84 100644
--- a/spec/ruby/library/bigdecimal/BigDecimal_spec.rb
+++ b/spec/ruby/library/bigdecimal/BigDecimal_spec.rb
@@ -10,7 +10,7 @@ end
describe "Kernel#BigDecimal" do
it "creates a new object of class BigDecimal" do
- BigDecimal("3.14159").should be_kind_of(BigDecimal)
+ BigDecimal("3.14159").should.is_a?(BigDecimal)
(0..9).each {|i|
BigDecimal("1#{i}").should == 10 + i
BigDecimal("-1#{i}").should == -10 - i
@@ -31,16 +31,12 @@ describe "Kernel#BigDecimal" do
end
it "accepts significant digits >= given precision" do
- suppress_warning do
- BigDecimal("3.1415923", 10).precs[1].should >= 10
- end
+ BigDecimal("3.1415923", 10).should == BigDecimal("3.1415923")
end
it "determines precision from initial value" do
pi_string = "3.14159265358979323846264338327950288419716939937510582097494459230781640628620899862803482534211706798214808651328230664709384460955058223172535940812848111745028410270193852110555964462294895493038196442881097566593014782083152134043"
- suppress_warning {
- BigDecimal(pi_string).precs[1]
- }.should >= pi_string.size-1
+ BigDecimal(pi_string).precision.should == pi_string.size-1
end
it "ignores leading and trailing whitespace" do
@@ -57,15 +53,15 @@ describe "Kernel#BigDecimal" do
end
it "does not ignores trailing garbage" do
- -> { BigDecimal("123E45ruby") }.should raise_error(ArgumentError)
- -> { BigDecimal("123x45") }.should raise_error(ArgumentError)
- -> { BigDecimal("123.4%E5") }.should raise_error(ArgumentError)
- -> { BigDecimal("1E2E3E4E5E") }.should raise_error(ArgumentError)
+ -> { BigDecimal("123E45ruby") }.should.raise(ArgumentError)
+ -> { BigDecimal("123x45") }.should.raise(ArgumentError)
+ -> { BigDecimal("123.4%E5") }.should.raise(ArgumentError)
+ -> { BigDecimal("1E2E3E4E5E") }.should.raise(ArgumentError)
end
it "raises ArgumentError for invalid strings" do
- -> { BigDecimal("ruby") }.should raise_error(ArgumentError)
- -> { BigDecimal(" \t\n \r-\t\t\tInfinity \n") }.should raise_error(ArgumentError)
+ -> { BigDecimal("ruby") }.should.raise(ArgumentError)
+ -> { BigDecimal(" \t\n \r-\t\t\tInfinity \n") }.should.raise(ArgumentError)
end
it "allows omitting the integer part" do
@@ -76,8 +72,8 @@ describe "Kernel#BigDecimal" do
reference = BigDecimal("12345.67E89")
BigDecimal("12_345.67E89").should == reference
- -> { BigDecimal("1_2_3_4_5_._6____7_E89") }.should raise_error(ArgumentError)
- -> { BigDecimal("12345_.67E_8__9_") }.should raise_error(ArgumentError)
+ -> { BigDecimal("1_2_3_4_5_._6____7_E89") }.should.raise(ArgumentError)
+ -> { BigDecimal("12345_.67E_8__9_") }.should.raise(ArgumentError)
end
it "accepts NaN and [+-]Infinity" do
@@ -95,13 +91,13 @@ describe "Kernel#BigDecimal" do
describe "with exception: false" do
it "returns nil for invalid strings" do
- BigDecimal("invalid", exception: false).should be_nil
- BigDecimal("0invalid", exception: false).should be_nil
- BigDecimal("invalid0", exception: false).should be_nil
+ BigDecimal("invalid", exception: false).should == nil
+ BigDecimal("0invalid", exception: false).should == nil
+ BigDecimal("invalid0", exception: false).should == nil
if BigDecimal::VERSION >= "3.1.9"
BigDecimal("0.", exception: false).to_i.should == 0
else
- BigDecimal("0.", exception: false).should be_nil
+ BigDecimal("0.", exception: false).should == nil
end
end
end
@@ -156,8 +152,10 @@ describe "Kernel#BigDecimal" do
BigDecimal("-12345.6E-1").should == -reference
end
- it "raises ArgumentError when Float is used without precision" do
- -> { BigDecimal(1.0) }.should raise_error(ArgumentError)
+ version_is BigDecimal::VERSION, "3.3.0" do
+ it "allows Float without precision" do
+ BigDecimal(1.2).should == BigDecimal("1.2")
+ end
end
it "returns appropriate BigDecimal zero for signed zero" do
@@ -206,14 +204,6 @@ describe "Kernel#BigDecimal" do
Float(@b).to_s.should == "166.66666666666666"
end
- it "has the expected precision on the LHS" do
- suppress_warning { @a.precs[0] }.should == 18
- end
-
- it "has the expected maximum precision on the LHS" do
- suppress_warning { @a.precs[1] }.should == 27
- end
-
it "produces the expected result when done via Float" do
(Float(@a) - Float(@b)).to_s.should == "-6.666596163995564e-10"
end
@@ -224,34 +214,10 @@ describe "Kernel#BigDecimal" do
# Check underlying methods work as we understand
- it "BigDecimal precision is the number of digits rounded up to a multiple of nine" do
- 1.upto(100) do |n|
- b = BigDecimal('4' * n)
- precs, _ = suppress_warning { b.precs }
- (precs >= 9).should be_true
- (precs >= n).should be_true
- (precs % 9).should == 0
- end
- suppress_warning { BigDecimal('NaN').precs[0] }.should == 9
- end
-
- it "BigDecimal maximum precision is nine more than precision except for abnormals" do
- 1.upto(100) do |n|
- b = BigDecimal('4' * n)
- precs, max = suppress_warning { b.precs }
- max.should == precs + 9
- end
- suppress_warning { BigDecimal('NaN').precs[1] }.should == 9
- end
-
it "BigDecimal(Rational, 18) produces the result we expect" do
BigDecimal(@b, 18).to_s.should == "0.166666666666666667e3"
end
- it "BigDecimal(Rational, BigDecimal.precs[0]) produces the result we expect" do
- BigDecimal(@b, suppress_warning { @a.precs[0] }).to_s.should == "0.166666666666666667e3"
- end
-
# Check the top-level expression works as we expect
it "produces a BigDecimal" do
@@ -259,8 +225,8 @@ describe "Kernel#BigDecimal" do
end
it "produces the expected result" do
- @c.should == BigDecimal("-0.666667e-9")
- @c.to_s.should == "-0.666667e-9"
+ @c.round(15).should == BigDecimal("-0.666667e-9")
+ @c.round(15).to_s.should == "-0.666667e-9"
end
it "produces the correct class for other arithmetic operators" do
diff --git a/spec/ruby/library/bigdecimal/add_spec.rb b/spec/ruby/library/bigdecimal/add_spec.rb
index 542713011d..a4237298f4 100644
--- a/spec/ruby/library/bigdecimal/add_spec.rb
+++ b/spec/ruby/library/bigdecimal/add_spec.rb
@@ -73,14 +73,6 @@ describe "BigDecimal#add" do
# BigDecimal("0.88").add(0.0, 1).should == BigDecimal("0.9")
# end
- describe "with Object" do
- it "tries to coerce the other operand to self" do
- object = mock("Object")
- object.should_receive(:coerce).with(@frac_3).and_return([@frac_3, @frac_4])
- @frac_3.add(object, 1).should == BigDecimal("0.1E16")
- end
- end
-
describe "with Rational" do
it "produces a BigDecimal" do
(@three + Rational(500, 2)).should == BigDecimal("0.253e3")
@@ -173,21 +165,21 @@ describe "BigDecimal#add" do
it "raises TypeError when adds nil" do
-> {
@one.add(nil, 10)
- }.should raise_error(TypeError)
+ }.should.raise(TypeError)
-> {
@one.add(nil, 0)
- }.should raise_error(TypeError)
+ }.should.raise(TypeError)
end
it "raises TypeError when precision parameter is nil" do
-> {
@one.add(@one, nil)
- }.should raise_error(TypeError)
+ }.should.raise(TypeError)
end
it "raises ArgumentError when precision parameter is negative" do
-> {
@one.add(@one, -10)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
end
diff --git a/spec/ruby/library/bigdecimal/case_compare_spec.rb b/spec/ruby/library/bigdecimal/case_compare_spec.rb
index fac6714356..1f1d223d6a 100644
--- a/spec/ruby/library/bigdecimal/case_compare_spec.rb
+++ b/spec/ruby/library/bigdecimal/case_compare_spec.rb
@@ -1,7 +1,9 @@
require_relative '../../spec_helper'
-require_relative 'shared/eql'
+require 'bigdecimal'
describe "BigDecimal#===" do
- it_behaves_like :bigdecimal_eql, :===
+ it "is an alias of BigDecimal#==" do
+ BigDecimal.instance_method(:===).should == BigDecimal.instance_method(:==)
+ end
end
diff --git a/spec/ruby/library/bigdecimal/ceil_spec.rb b/spec/ruby/library/bigdecimal/ceil_spec.rb
index 60e71b12fb..3d94b8e578 100644
--- a/spec/ruby/library/bigdecimal/ceil_spec.rb
+++ b/spec/ruby/library/bigdecimal/ceil_spec.rb
@@ -48,9 +48,9 @@ describe "BigDecimal#ceil" do
end
it "raise exception, if self is special value" do
- -> { @infinity.ceil }.should raise_error(FloatDomainError)
- -> { @infinity_neg.ceil }.should raise_error(FloatDomainError)
- -> { @nan.ceil }.should raise_error(FloatDomainError)
+ -> { @infinity.ceil }.should.raise(FloatDomainError)
+ -> { @infinity_neg.ceil }.should.raise(FloatDomainError)
+ -> { @nan.ceil }.should.raise(FloatDomainError)
end
it "returns n digits right of the decimal point if given n > 0" do
diff --git a/spec/ruby/library/bigdecimal/clone_spec.rb b/spec/ruby/library/bigdecimal/clone_spec.rb
index b3a1c61d6a..979cc4c8e9 100644
--- a/spec/ruby/library/bigdecimal/clone_spec.rb
+++ b/spec/ruby/library/bigdecimal/clone_spec.rb
@@ -1,6 +1,8 @@
require_relative '../../spec_helper'
-require_relative 'shared/clone'
+require 'bigdecimal'
-describe "BigDecimal#dup" do
- it_behaves_like :bigdecimal_clone, :clone
+describe "BigDecimal#clone" do
+ it "is an alias of BigDecimal#dup" do
+ BigDecimal.instance_method(:clone).should == BigDecimal.instance_method(:dup)
+ end
end
diff --git a/spec/ruby/library/bigdecimal/constants_spec.rb b/spec/ruby/library/bigdecimal/constants_spec.rb
index 8d879c036a..f2cc42dfc9 100644
--- a/spec/ruby/library/bigdecimal/constants_spec.rb
+++ b/spec/ruby/library/bigdecimal/constants_spec.rb
@@ -3,17 +3,17 @@ require 'bigdecimal'
describe "BigDecimal constants" do
it "defines a VERSION value" do
- BigDecimal.const_defined?(:VERSION).should be_true
+ BigDecimal.const_defined?(:VERSION).should == true
end
it "has a BASE value" do
# The actual one is decided based on HAVE_INT64_T in MRI,
# which is hard to check here.
- [10000, 1000000000].should include(BigDecimal::BASE)
+ [10000, 1000000000].should.include?(BigDecimal::BASE)
end
it "has a NaN value" do
- BigDecimal::NAN.nan?.should be_true
+ BigDecimal::NAN.nan?.should == true
end
it "has an INFINITY value" do
diff --git a/spec/ruby/library/bigdecimal/core_spec.rb b/spec/ruby/library/bigdecimal/core_spec.rb
index acee4dcf56..8f64fdf388 100644
--- a/spec/ruby/library/bigdecimal/core_spec.rb
+++ b/spec/ruby/library/bigdecimal/core_spec.rb
@@ -20,9 +20,12 @@ describe "Core extension by bigdecimal" do
describe "BigDecimal#log" do
it "handles high-precision Rational arguments" do
- result = BigDecimal('0.22314354220170971436137296411949880462556361100856391620766259404746040597133837784E0')
+ # log(BigDecimal(r, 50), 50)
+ result1 = BigDecimal('0.22314354220170971436137296411949880462556361100856e0')
+ # log(BigDecimal(r, 1000), 50)
+ result2 = BigDecimal('0.22314354220170971436137296411949880462556361100853e0')
r = Rational(1_234_567_890, 987_654_321)
- BigMath.log(r, 50).should == result
+ [result1, result2].should.include?(BigMath.log(r, 50).mult(1, 50))
end
end
@@ -30,15 +33,15 @@ describe "Core extension by bigdecimal" 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
+ result.first.is_a?(Float).should == true
+ result.last.is_a?(Float).should == 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
+ result.first.is_a?(Rational).should == true
+ result.last.is_a?(Rational).should == true
end
it "coerces to Rational, when given a Complex" do
@@ -53,7 +56,7 @@ describe "Core extension by bigdecimal" do
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/)
+ }.should.raise(TypeError, /BigDecimal can't be coerced into Rational/)
end
end
end
diff --git a/spec/ruby/library/bigdecimal/div_spec.rb b/spec/ruby/library/bigdecimal/div_spec.rb
index 53ad6d0418..967d8b5221 100644
--- a/spec/ruby/library/bigdecimal/div_spec.rb
+++ b/spec/ruby/library/bigdecimal/div_spec.rb
@@ -51,9 +51,9 @@ describe "BigDecimal#div" do
end
it "raises FloatDomainError if NaN is involved" do
- -> { @one.div(@nan) }.should raise_error(FloatDomainError)
- -> { @nan.div(@one) }.should raise_error(FloatDomainError)
- -> { @nan.div(@nan) }.should raise_error(FloatDomainError)
+ -> { @one.div(@nan) }.should.raise(FloatDomainError)
+ -> { @nan.div(@one) }.should.raise(FloatDomainError)
+ -> { @nan.div(@nan) }.should.raise(FloatDomainError)
end
it "returns 0 if divided by Infinity and no precision given" do
@@ -69,14 +69,14 @@ describe "BigDecimal#div" do
end
it "raises ZeroDivisionError if divided by zero and no precision given" do
- -> { @one.div(@zero) }.should raise_error(ZeroDivisionError)
- -> { @one.div(@zero_plus) }.should raise_error(ZeroDivisionError)
- -> { @one.div(@zero_minus) }.should raise_error(ZeroDivisionError)
-
- -> { @zero.div(@zero) }.should raise_error(ZeroDivisionError)
- -> { @zero_minus.div(@zero_plus) }.should raise_error(ZeroDivisionError)
- -> { @zero_minus.div(@zero_minus) }.should raise_error(ZeroDivisionError)
- -> { @zero_plus.div(@zero_minus) }.should raise_error(ZeroDivisionError)
+ -> { @one.div(@zero) }.should.raise(ZeroDivisionError)
+ -> { @one.div(@zero_plus) }.should.raise(ZeroDivisionError)
+ -> { @one.div(@zero_minus) }.should.raise(ZeroDivisionError)
+
+ -> { @zero.div(@zero) }.should.raise(ZeroDivisionError)
+ -> { @zero_minus.div(@zero_plus) }.should.raise(ZeroDivisionError)
+ -> { @zero_minus.div(@zero_minus) }.should.raise(ZeroDivisionError)
+ -> { @zero_plus.div(@zero_minus) }.should.raise(ZeroDivisionError)
end
it "returns NaN if zero is divided by zero" do
@@ -90,9 +90,9 @@ describe "BigDecimal#div" do
end
it "raises FloatDomainError if (+|-) Infinity divided by 1 and no precision given" do
- -> { @infinity_minus.div(@one) }.should raise_error(FloatDomainError)
- -> { @infinity.div(@one) }.should raise_error(FloatDomainError)
- -> { @infinity_minus.div(@one_minus) }.should raise_error(FloatDomainError)
+ -> { @infinity_minus.div(@one) }.should.raise(FloatDomainError)
+ -> { @infinity.div(@one) }.should.raise(FloatDomainError)
+ -> { @infinity_minus.div(@one_minus) }.should.raise(FloatDomainError)
end
it "returns (+|-)Infinity if (+|-)Infinity by 1 and precision given" do
diff --git a/spec/ruby/library/bigdecimal/divmod_spec.rb b/spec/ruby/library/bigdecimal/divmod_spec.rb
index 294f01cba0..d170c6f845 100644
--- a/spec/ruby/library/bigdecimal/divmod_spec.rb
+++ b/spec/ruby/library/bigdecimal/divmod_spec.rb
@@ -33,14 +33,16 @@ describe "BigDecimal#mod_part_of_divmod" do
end
end
- it_behaves_like :bigdecimal_modulo, :mod_part_of_divmod
+ version_is BigDecimal::VERSION, ""..."4.0.0" do
+ it_behaves_like :bigdecimal_modulo, :mod_part_of_divmod
+ end
it "raises ZeroDivisionError if other is zero" do
bd5667 = BigDecimal("5667.19")
-
- -> { bd5667.mod_part_of_divmod(0) }.should raise_error(ZeroDivisionError)
- -> { bd5667.mod_part_of_divmod(BigDecimal("0")) }.should raise_error(ZeroDivisionError)
- -> { @zero.mod_part_of_divmod(@zero) }.should raise_error(ZeroDivisionError)
+ zero = BigDecimal("0")
+ -> { bd5667.mod_part_of_divmod(0) }.should.raise(ZeroDivisionError)
+ -> { bd5667.mod_part_of_divmod(BigDecimal("0")) }.should.raise(ZeroDivisionError)
+ -> { zero.mod_part_of_divmod(zero) }.should.raise(ZeroDivisionError)
end
end
@@ -73,14 +75,25 @@ describe "BigDecimal#divmod" do
@zeroes = [@zero, @zero_pos, @zero_neg]
end
- it "divides value, returns an array" do
- res = @a.divmod(5)
- res.kind_of?(Array).should == true
+ version_is BigDecimal::VERSION, ""..."4.0.0" do
+ it "divides value, returns [BigDecimal, BigDecimal]" do
+ res = @a.divmod(5)
+ res.kind_of?(Array).should == true
+ DivmodSpecs.check_both_bigdecimal(res)
+ end
+ end
+
+ version_is BigDecimal::VERSION, "4.0.0" do
+ it "divides value, returns [Integer, BigDecimal]" do
+ res = @a.divmod(5)
+ res.kind_of?(Array).should == true
+ res[0].kind_of?(Integer).should == true
+ res[1].kind_of?(BigDecimal).should == true
+ end
end
it "array contains quotient and modulus as BigDecimal" do
res = @a.divmod(5)
- DivmodSpecs.check_both_bigdecimal(res)
res[0].should == BigDecimal('0.8E1')
res[1].should == BigDecimal('2.00000000000000000001')
@@ -123,43 +136,62 @@ describe "BigDecimal#divmod" do
values_and_zeroes.each do |val1|
values.each do |val2|
res = val1.divmod(val2)
- DivmodSpecs.check_both_bigdecimal(res)
res[0].should == ((val1/val2).floor)
res[1].should == (val1 - res[0] * val2)
end
end
end
- it "returns an array of two NaNs if NaN is involved" do
- (@special_vals + @regular_vals + @zeroes).each do |val|
- DivmodSpecs.check_both_nan(val.divmod(@nan))
- DivmodSpecs.check_both_nan(@nan.divmod(val))
+ version_is BigDecimal::VERSION, "4.0.0" do
+ it "raise FloatDomainError error if NaN is involved" do
+ (@special_vals + @regular_vals + @zeroes).each do |val|
+ -> { val.divmod(@nan) }.should.raise(FloatDomainError)
+ -> { @nan.divmod(val) }.should.raise(FloatDomainError)
+ end
+ end
+ end
+
+ version_is BigDecimal::VERSION, ""..."4.0.0" do
+ it "returns an array of two NaNs if NaN is involved" do
+ (@special_vals + @regular_vals + @zeroes).each do |val|
+ DivmodSpecs.check_both_nan(val.divmod(@nan))
+ DivmodSpecs.check_both_nan(@nan.divmod(val))
+ end
end
end
it "raises ZeroDivisionError if the divisor is zero" do
(@special_vals + @regular_vals + @zeroes - [@nan]).each do |val|
@zeroes.each do |zero|
- -> { val.divmod(zero) }.should raise_error(ZeroDivisionError)
+ -> { val.divmod(zero) }.should.raise(ZeroDivisionError)
end
end
end
- it "returns an array of Infinity and NaN if the dividend is Infinity" do
- @regular_vals.each do |val|
- array = @infinity.divmod(val)
- array.length.should == 2
- array[0].infinite?.should == (val > 0 ? 1 : -1)
- array[1].should.nan?
+ version_is BigDecimal::VERSION, ""..."4.0.0" do
+ it "returns an array of Infinity and NaN if the dividend is Infinity" do
+ @regular_vals.each do |val|
+ array = @infinity.divmod(val)
+ array.length.should == 2
+ array[0].infinite?.should == (val > 0 ? 1 : -1)
+ array[1].should.nan?
+ end
end
end
- it "returns an array of zero and the dividend if the divisor is Infinity" do
- @regular_vals.each do |val|
- array = val.divmod(@infinity)
- array.length.should == 2
- array[0].should == @zero
- array[1].should == val
+ version_is BigDecimal::VERSION, "3.3.0" do
+ it "returns an array of zero and the dividend or minus one and Infinity if the divisor is Infinity" do
+ @regular_vals.each do |val|
+ array = val.divmod(@infinity)
+ array.length.should == 2
+ if val >= 0
+ array[0].should == @zero
+ array[1].should == val
+ else
+ array[0].should == @one_minus
+ array[1].should == @infinity
+ end
+ end
end
end
@@ -174,7 +206,7 @@ describe "BigDecimal#divmod" do
it "raises TypeError if the argument cannot be coerced to BigDecimal" do
-> {
@one.divmod('1')
- }.should raise_error(TypeError)
+ }.should.raise(TypeError)
end
end
diff --git a/spec/ruby/library/bigdecimal/dup_spec.rb b/spec/ruby/library/bigdecimal/dup_spec.rb
index bfabaf6e8b..dbf79ce5a6 100644
--- a/spec/ruby/library/bigdecimal/dup_spec.rb
+++ b/spec/ruby/library/bigdecimal/dup_spec.rb
@@ -1,6 +1,14 @@
require_relative '../../spec_helper'
-require_relative 'shared/clone'
+require 'bigdecimal'
describe "BigDecimal#dup" do
- it_behaves_like :bigdecimal_clone, :dup
+ before :each do
+ @obj = BigDecimal("1.2345")
+ end
+
+ it "returns self" do
+ copy = @obj.dup
+
+ copy.should.equal?(@obj)
+ end
end
diff --git a/spec/ruby/library/bigdecimal/eql_spec.rb b/spec/ruby/library/bigdecimal/eql_spec.rb
index 1be5862751..0346175e1e 100644
--- a/spec/ruby/library/bigdecimal/eql_spec.rb
+++ b/spec/ruby/library/bigdecimal/eql_spec.rb
@@ -1,6 +1,8 @@
require_relative '../../spec_helper'
-require_relative 'shared/eql'
+require 'bigdecimal'
describe "BigDecimal#eql?" do
- it_behaves_like :bigdecimal_eql, :eql?
+ it "is an alias of BigDecimal#==" do
+ BigDecimal.instance_method(:eql?).should == BigDecimal.instance_method(:==)
+ end
end
diff --git a/spec/ruby/library/bigdecimal/equal_value_spec.rb b/spec/ruby/library/bigdecimal/equal_value_spec.rb
index 933060eada..d1133765b1 100644
--- a/spec/ruby/library/bigdecimal/equal_value_spec.rb
+++ b/spec/ruby/library/bigdecimal/equal_value_spec.rb
@@ -1,7 +1,63 @@
require_relative '../../spec_helper'
-require_relative 'shared/eql'
+require 'bigdecimal'
describe "BigDecimal#==" do
- it_behaves_like :bigdecimal_eql, :==
+ before :each do
+ @bg6543_21 = BigDecimal("6543.21")
+ @bg5667_19 = BigDecimal("5667.19")
+ @a = BigDecimal("1.0000000000000000000000000000000000000000005")
+ @b = BigDecimal("1.00000000000000000000000000000000000000000005")
+ @bigint = BigDecimal("1000.0")
+ @nan = BigDecimal("NaN")
+ @infinity = BigDecimal("Infinity")
+ @infinity_minus = BigDecimal("-Infinity")
+ end
+
+ it "tests for equality" do
+ (@bg6543_21 == @bg6543_21).should == true
+ (@a == @a).should == true
+ (@a == @b).should == false
+ (@bg6543_21 == @a).should == false
+ (@bigint == 1000).should == true
+ end
+
+ it "returns false for NaN as it is never equal to any number" do
+ (@nan == @nan).should == false
+ (@a == @nan).should == false
+ (@nan == @a).should == false
+ (@nan == @infinity).should == false
+ (@nan == @infinity_minus).should == false
+ (@infinity == @nan).should == false
+ (@infinity_minus == @nan).should == false
+ end
+
+ it "returns true for infinity values with the same sign" do
+ (@infinity == @infinity).should == true
+ (@infinity == BigDecimal("Infinity")).should == true
+ (BigDecimal("Infinity") == @infinity).should == true
+
+ (@infinity_minus == @infinity_minus).should == true
+ (@infinity_minus == BigDecimal("-Infinity")).should == true
+ (BigDecimal("-Infinity") == @infinity_minus).should == true
+ end
+
+ it "returns false for infinity values with different signs" do
+ (@infinity == @infinity_minus).should == false
+ (@infinity_minus == @infinity).should == false
+ end
+
+ it "returns false when infinite value compared to finite one" do
+ (@infinity == @a).should == false
+ (@infinity_minus == @a).should == false
+
+ (@a == @infinity).should == false
+ (@a == @infinity_minus).should == false
+ end
+
+ it "returns false when compared objects that can not be coerced into BigDecimal" do
+ (@infinity == nil).should == false
+ (@bigint == nil).should == false
+ (@nan == nil).should == false
+ end
end
diff --git a/spec/ruby/library/bigdecimal/fix_spec.rb b/spec/ruby/library/bigdecimal/fix_spec.rb
index 2c6276899e..dceb2ce867 100644
--- a/spec/ruby/library/bigdecimal/fix_spec.rb
+++ b/spec/ruby/library/bigdecimal/fix_spec.rb
@@ -51,7 +51,7 @@ describe "BigDecimal#fix" do
it "does not allow any arguments" do
-> {
@mixed.fix(10)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
end
diff --git a/spec/ruby/library/bigdecimal/floor_spec.rb b/spec/ruby/library/bigdecimal/floor_spec.rb
index a7dfec2c9a..c0666c668c 100644
--- a/spec/ruby/library/bigdecimal/floor_spec.rb
+++ b/spec/ruby/library/bigdecimal/floor_spec.rb
@@ -41,9 +41,9 @@ describe "BigDecimal#floor" do
end
it "raise exception, if self is special value" do
- -> { @infinity.floor }.should raise_error(FloatDomainError)
- -> { @infinity_neg.floor }.should raise_error(FloatDomainError)
- -> { @nan.floor }.should raise_error(FloatDomainError)
+ -> { @infinity.floor }.should.raise(FloatDomainError)
+ -> { @infinity_neg.floor }.should.raise(FloatDomainError)
+ -> { @nan.floor }.should.raise(FloatDomainError)
end
it "returns n digits right of the decimal point if given n > 0" do
diff --git a/spec/ruby/library/bigdecimal/gt_spec.rb b/spec/ruby/library/bigdecimal/gt_spec.rb
index 78547fb85f..e9c9a60e75 100644
--- a/spec/ruby/library/bigdecimal/gt_spec.rb
+++ b/spec/ruby/library/bigdecimal/gt_spec.rb
@@ -86,11 +86,11 @@ describe "BigDecimal#>" do
end
it "raises an ArgumentError if the argument can't be coerced into a BigDecimal" do
- -> {@zero > nil }.should raise_error(ArgumentError)
- -> {@infinity > nil }.should raise_error(ArgumentError)
- -> {@infinity_neg > nil }.should raise_error(ArgumentError)
- -> {@mixed > nil }.should raise_error(ArgumentError)
- -> {@pos_int > nil }.should raise_error(ArgumentError)
- -> {@neg_frac > nil }.should raise_error(ArgumentError)
+ -> {@zero > nil }.should.raise(ArgumentError)
+ -> {@infinity > nil }.should.raise(ArgumentError)
+ -> {@infinity_neg > nil }.should.raise(ArgumentError)
+ -> {@mixed > nil }.should.raise(ArgumentError)
+ -> {@pos_int > nil }.should.raise(ArgumentError)
+ -> {@neg_frac > nil }.should.raise(ArgumentError)
end
end
diff --git a/spec/ruby/library/bigdecimal/gte_spec.rb b/spec/ruby/library/bigdecimal/gte_spec.rb
index 2a5cc025ba..548f3efe4c 100644
--- a/spec/ruby/library/bigdecimal/gte_spec.rb
+++ b/spec/ruby/library/bigdecimal/gte_spec.rb
@@ -90,11 +90,11 @@ describe "BigDecimal#>=" do
end
it "returns nil if the argument is nil" do
- -> {@zero >= nil }.should raise_error(ArgumentError)
- -> {@infinity >= nil }.should raise_error(ArgumentError)
- -> {@infinity_neg >= nil }.should raise_error(ArgumentError)
- -> {@mixed >= nil }.should raise_error(ArgumentError)
- -> {@pos_int >= nil }.should raise_error(ArgumentError)
- -> {@neg_frac >= nil }.should raise_error(ArgumentError)
+ -> {@zero >= nil }.should.raise(ArgumentError)
+ -> {@infinity >= nil }.should.raise(ArgumentError)
+ -> {@infinity_neg >= nil }.should.raise(ArgumentError)
+ -> {@mixed >= nil }.should.raise(ArgumentError)
+ -> {@pos_int >= nil }.should.raise(ArgumentError)
+ -> {@neg_frac >= nil }.should.raise(ArgumentError)
end
end
diff --git a/spec/ruby/library/bigdecimal/lt_spec.rb b/spec/ruby/library/bigdecimal/lt_spec.rb
index 02390e76e3..c3f3573247 100644
--- a/spec/ruby/library/bigdecimal/lt_spec.rb
+++ b/spec/ruby/library/bigdecimal/lt_spec.rb
@@ -84,11 +84,11 @@ describe "BigDecimal#<" do
end
it "raises an ArgumentError if the argument can't be coerced into a BigDecimal" do
- -> {@zero < nil }.should raise_error(ArgumentError)
- -> {@infinity < nil }.should raise_error(ArgumentError)
- -> {@infinity_neg < nil }.should raise_error(ArgumentError)
- -> {@mixed < nil }.should raise_error(ArgumentError)
- -> {@pos_int < nil }.should raise_error(ArgumentError)
- -> {@neg_frac < nil }.should raise_error(ArgumentError)
+ -> {@zero < nil }.should.raise(ArgumentError)
+ -> {@infinity < nil }.should.raise(ArgumentError)
+ -> {@infinity_neg < nil }.should.raise(ArgumentError)
+ -> {@mixed < nil }.should.raise(ArgumentError)
+ -> {@pos_int < nil }.should.raise(ArgumentError)
+ -> {@neg_frac < nil }.should.raise(ArgumentError)
end
end
diff --git a/spec/ruby/library/bigdecimal/lte_spec.rb b/spec/ruby/library/bigdecimal/lte_spec.rb
index b92be04123..7918bde88b 100644
--- a/spec/ruby/library/bigdecimal/lte_spec.rb
+++ b/spec/ruby/library/bigdecimal/lte_spec.rb
@@ -90,11 +90,11 @@ describe "BigDecimal#<=" do
end
it "raises an ArgumentError if the argument can't be coerced into a BigDecimal" do
- -> {@zero <= nil }.should raise_error(ArgumentError)
- -> {@infinity <= nil }.should raise_error(ArgumentError)
- -> {@infinity_neg <= nil }.should raise_error(ArgumentError)
- -> {@mixed <= nil }.should raise_error(ArgumentError)
- -> {@pos_int <= nil }.should raise_error(ArgumentError)
- -> {@neg_frac <= nil }.should raise_error(ArgumentError)
+ -> {@zero <= nil }.should.raise(ArgumentError)
+ -> {@infinity <= nil }.should.raise(ArgumentError)
+ -> {@infinity_neg <= nil }.should.raise(ArgumentError)
+ -> {@mixed <= nil }.should.raise(ArgumentError)
+ -> {@pos_int <= nil }.should.raise(ArgumentError)
+ -> {@neg_frac <= nil }.should.raise(ArgumentError)
end
end
diff --git a/spec/ruby/library/bigdecimal/mode_spec.rb b/spec/ruby/library/bigdecimal/mode_spec.rb
index 73fa1a118e..26e6d0ea75 100644
--- a/spec/ruby/library/bigdecimal/mode_spec.rb
+++ b/spec/ruby/library/bigdecimal/mode_spec.rb
@@ -24,13 +24,13 @@ describe "BigDecimal.mode" do
it "raise an exception if the flag is true" do
BigDecimal.mode(BigDecimal::EXCEPTION_NaN, true)
- -> { BigDecimal("NaN").add(BigDecimal("1"),0) }.should raise_error(FloatDomainError)
+ -> { BigDecimal("NaN").add(BigDecimal("1"),0) }.should.raise(FloatDomainError)
BigDecimal.mode(BigDecimal::EXCEPTION_INFINITY, true)
- -> { BigDecimal("0").add(BigDecimal("Infinity"),0) }.should raise_error(FloatDomainError)
+ -> { BigDecimal("0").add(BigDecimal("Infinity"),0) }.should.raise(FloatDomainError)
BigDecimal.mode(BigDecimal::EXCEPTION_ZERODIVIDE, true)
- -> { BigDecimal("1").quo(BigDecimal("0")) }.should raise_error(FloatDomainError)
+ -> { BigDecimal("1").quo(BigDecimal("0")) }.should.raise(FloatDomainError)
BigDecimal.mode(BigDecimal::EXCEPTION_OVERFLOW, true)
- -> { BigDecimal("1E11111111111111111111") }.should raise_error(FloatDomainError)
- -> { (BigDecimal("1E1000000000000000000")**10) }.should raise_error(FloatDomainError)
+ -> { BigDecimal("1E11111111111111111111") }.should.raise(FloatDomainError)
+ -> { (BigDecimal("1E1000000000000000000")**10) }.should.raise(FloatDomainError)
end
end
diff --git a/spec/ruby/library/bigdecimal/modulo_spec.rb b/spec/ruby/library/bigdecimal/modulo_spec.rb
index 035d31bd98..d6b4f91b6d 100644
--- a/spec/ruby/library/bigdecimal/modulo_spec.rb
+++ b/spec/ruby/library/bigdecimal/modulo_spec.rb
@@ -1,12 +1,21 @@
require_relative '../../spec_helper'
require_relative 'shared/modulo'
+require 'bigdecimal'
describe "BigDecimal#%" do
it_behaves_like :bigdecimal_modulo, :%
- it_behaves_like :bigdecimal_modulo_zerodivisionerror, :%
+
+ it "raises ZeroDivisionError if other is zero" do
+ bd5667 = BigDecimal("5667.19")
+
+ -> { bd5667 % 0 }.should.raise(ZeroDivisionError)
+ -> { bd5667 % BigDecimal("0") }.should.raise(ZeroDivisionError)
+ -> { @zero % @zero }.should.raise(ZeroDivisionError)
+ end
end
describe "BigDecimal#modulo" do
- it_behaves_like :bigdecimal_modulo, :modulo
- it_behaves_like :bigdecimal_modulo_zerodivisionerror, :modulo
+ it "is an alias of BigDecimal#%" do
+ BigDecimal.instance_method(:modulo).should == BigDecimal.instance_method(:%)
+ end
end
diff --git a/spec/ruby/library/bigdecimal/mult_spec.rb b/spec/ruby/library/bigdecimal/mult_spec.rb
index b7f8044b0b..2353df9cb8 100644
--- a/spec/ruby/library/bigdecimal/mult_spec.rb
+++ b/spec/ruby/library/bigdecimal/mult_spec.rb
@@ -21,12 +21,4 @@ describe "BigDecimal#mult" do
@e.mult(@one, 1).should be_close(@one, @tolerance)
@e3_minus.mult(@one, 1).should be_close(0, @tolerance2)
end
-
- describe "with Object" do
- it "tries to coerce the other operand to self" do
- object = mock("Object")
- object.should_receive(:coerce).with(@e3_minus).and_return([@e3_minus, @e3_plus])
- @e3_minus.mult(object, 1).should == BigDecimal("9")
- end
- end
end
diff --git a/spec/ruby/library/bigdecimal/nonzero_spec.rb b/spec/ruby/library/bigdecimal/nonzero_spec.rb
index f43c4393cd..31421ebdf4 100644
--- a/spec/ruby/library/bigdecimal/nonzero_spec.rb
+++ b/spec/ruby/library/bigdecimal/nonzero_spec.rb
@@ -10,11 +10,11 @@ describe "BigDecimal#nonzero?" do
infinity = BigDecimal("Infinity")
infinity_minus = BigDecimal("-Infinity")
nan = BigDecimal("NaN")
- infinity.nonzero?.should equal(infinity)
- infinity_minus.nonzero?.should equal(infinity_minus)
- nan.nonzero?.should equal(nan)
- e3_minus.nonzero?.should equal(e3_minus)
- e2_plus.nonzero?.should equal(e2_plus)
+ infinity.nonzero?.should.equal?(infinity)
+ infinity_minus.nonzero?.should.equal?(infinity_minus)
+ nan.nonzero?.should.equal?(nan)
+ e3_minus.nonzero?.should.equal?(e3_minus)
+ e2_plus.nonzero?.should.equal?(e2_plus)
end
it "returns nil otherwise" do
diff --git a/spec/ruby/library/bigdecimal/precs_spec.rb b/spec/ruby/library/bigdecimal/precs_spec.rb
deleted file mode 100644
index 5fda8d3087..0000000000
--- a/spec/ruby/library/bigdecimal/precs_spec.rb
+++ /dev/null
@@ -1,55 +0,0 @@
-require_relative '../../spec_helper'
-require 'bigdecimal'
-
-describe "BigDecimal#precs" do
- before :each do
- @infinity = BigDecimal("Infinity")
- @infinity_neg = BigDecimal("-Infinity")
- @nan = BigDecimal("NaN")
- @zero = BigDecimal("0")
- @zero_neg = BigDecimal("-0")
-
- @arr = [BigDecimal("2E40001"), BigDecimal("3E-20001"),\
- @infinity, @infinity_neg, @nan, @zero, @zero_neg]
- @precision = BigDecimal::BASE.to_s.length - 1
- end
-
- it "returns array of two values" do
- suppress_warning do
- @arr.each do |x|
- x.precs.kind_of?(Array).should == true
- x.precs.size.should == 2
- end
- end
- end
-
- it "returns Integers as array values" do
- suppress_warning do
- @arr.each do |x|
- x.precs[0].kind_of?(Integer).should == true
- x.precs[1].kind_of?(Integer).should == true
- end
- end
- end
-
- it "returns the current value of significant digits as the first value" do
- suppress_warning do
- BigDecimal("3.14159").precs[0].should >= 6
- BigDecimal('1').precs[0].should == BigDecimal('1' + '0' * 100).precs[0]
- [@infinity, @infinity_neg, @nan, @zero, @zero_neg].each do |value|
- value.precs[0].should <= @precision
- end
- end
- end
-
- it "returns the maximum number of significant digits as the second value" do
- suppress_warning do
- BigDecimal("3.14159").precs[1].should >= 6
- BigDecimal('1').precs[1].should >= 1
- BigDecimal('1' + '0' * 100).precs[1].should >= 101
- [@infinity, @infinity_neg, @nan, @zero, @zero_neg].each do |value|
- value.precs[1].should >= 1
- end
- end
- end
-end
diff --git a/spec/ruby/library/bigdecimal/remainder_spec.rb b/spec/ruby/library/bigdecimal/remainder_spec.rb
index bac5f37ba9..27a2986570 100644
--- a/spec/ruby/library/bigdecimal/remainder_spec.rb
+++ b/spec/ruby/library/bigdecimal/remainder_spec.rb
@@ -37,9 +37,11 @@ describe "BigDecimal#remainder" do
@neg_int.remainder(@pos_frac).should == @neg_int - @pos_frac * (@neg_int / @pos_frac).truncate
end
- it "returns NaN used with zero" do
- @mixed.remainder(@zero).should.nan?
- @zero.remainder(@zero).should.nan?
+ version_is BigDecimal::VERSION, "3.3.0" do
+ it "raises ZeroDivisionError used with zero" do
+ -> { @mixed.remainder(@zero) }.should.raise(ZeroDivisionError)
+ -> { @zero.remainder(@zero) }.should.raise(ZeroDivisionError)
+ end
end
it "returns zero if used on zero" do
@@ -54,25 +56,6 @@ 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?
-
- @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
- end
-
it "coerces arguments to BigDecimal if possible" do
@three.remainder(2).should == @one
end
@@ -88,7 +71,7 @@ describe "BigDecimal#remainder" do
it "raises TypeError if the argument cannot be coerced to BigDecimal" do
-> {
@one.remainder('2')
- }.should raise_error(TypeError)
+ }.should.raise(TypeError)
end
end
diff --git a/spec/ruby/library/bigdecimal/round_spec.rb b/spec/ruby/library/bigdecimal/round_spec.rb
index 6a4d220417..622e129d93 100644
--- a/spec/ruby/library/bigdecimal/round_spec.rb
+++ b/spec/ruby/library/bigdecimal/round_spec.rb
@@ -217,18 +217,18 @@ describe "BigDecimal#round" do
end
it 'raise exception, if self is special value' do
- -> { BigDecimal('NaN').round }.should raise_error(FloatDomainError)
- -> { BigDecimal('Infinity').round }.should raise_error(FloatDomainError)
- -> { BigDecimal('-Infinity').round }.should raise_error(FloatDomainError)
+ -> { BigDecimal('NaN').round }.should.raise(FloatDomainError)
+ -> { BigDecimal('Infinity').round }.should.raise(FloatDomainError)
+ -> { BigDecimal('-Infinity').round }.should.raise(FloatDomainError)
end
it 'do not raise exception, if self is special value and precision is given' do
- -> { BigDecimal('NaN').round(2) }.should_not raise_error(FloatDomainError)
- -> { BigDecimal('Infinity').round(2) }.should_not raise_error(FloatDomainError)
- -> { BigDecimal('-Infinity').round(2) }.should_not raise_error(FloatDomainError)
+ -> { BigDecimal('NaN').round(2) }.should_not.raise(FloatDomainError)
+ -> { BigDecimal('Infinity').round(2) }.should_not.raise(FloatDomainError)
+ -> { BigDecimal('-Infinity').round(2) }.should_not.raise(FloatDomainError)
end
it 'raise for a non-existent round mode' do
- -> { @p1_50.round(0, :nonsense) }.should raise_error(ArgumentError, "invalid rounding mode (nonsense)")
+ -> { @p1_50.round(0, :nonsense) }.should.raise(ArgumentError, "invalid rounding mode (nonsense)")
end
end
diff --git a/spec/ruby/library/bigdecimal/shared/clone.rb b/spec/ruby/library/bigdecimal/shared/clone.rb
deleted file mode 100644
index 935ef76e7e..0000000000
--- a/spec/ruby/library/bigdecimal/shared/clone.rb
+++ /dev/null
@@ -1,13 +0,0 @@
-require 'bigdecimal'
-
-describe :bigdecimal_clone, shared: true do
- before :each do
- @obj = BigDecimal("1.2345")
- end
-
- it "returns self" do
- copy = @obj.public_send(@method)
-
- copy.should equal(@obj)
- end
-end
diff --git a/spec/ruby/library/bigdecimal/shared/eql.rb b/spec/ruby/library/bigdecimal/shared/eql.rb
deleted file mode 100644
index 8e3e388bab..0000000000
--- a/spec/ruby/library/bigdecimal/shared/eql.rb
+++ /dev/null
@@ -1,61 +0,0 @@
-require 'bigdecimal'
-
-describe :bigdecimal_eql, shared: true do
- before :each do
- @bg6543_21 = BigDecimal("6543.21")
- @bg5667_19 = BigDecimal("5667.19")
- @a = BigDecimal("1.0000000000000000000000000000000000000000005")
- @b = BigDecimal("1.00000000000000000000000000000000000000000005")
- @bigint = BigDecimal("1000.0")
- @nan = BigDecimal("NaN")
- @infinity = BigDecimal("Infinity")
- @infinity_minus = BigDecimal("-Infinity")
- end
-
- it "tests for equality" do
- @bg6543_21.send(@method, @bg6543_21).should == true
- @a.send(@method, @a).should == true
- @a.send(@method, @b).should == false
- @bg6543_21.send(@method, @a).should == false
- @bigint.send(@method, 1000).should == true
- end
-
- it "returns false for NaN as it is never equal to any number" do
- @nan.send(@method, @nan).should == false
- @a.send(@method, @nan).should == false
- @nan.send(@method, @a).should == false
- @nan.send(@method, @infinity).should == false
- @nan.send(@method, @infinity_minus).should == false
- @infinity.send(@method, @nan).should == false
- @infinity_minus.send(@method, @nan).should == false
- end
-
- it "returns true for infinity values with the same sign" do
- @infinity.send(@method, @infinity).should == true
- @infinity.send(@method, BigDecimal("Infinity")).should == true
- BigDecimal("Infinity").send(@method, @infinity).should == true
-
- @infinity_minus.send(@method, @infinity_minus).should == true
- @infinity_minus.send(@method, BigDecimal("-Infinity")).should == true
- BigDecimal("-Infinity").send(@method, @infinity_minus).should == true
- end
-
- it "returns false for infinity values with different signs" do
- @infinity.send(@method, @infinity_minus).should == false
- @infinity_minus.send(@method, @infinity).should == false
- end
-
- it "returns false when infinite value compared to finite one" do
- @infinity.send(@method, @a).should == false
- @infinity_minus.send(@method, @a).should == false
-
- @a.send(@method, @infinity).should == false
- @a.send(@method, @infinity_minus).should == false
- end
-
- it "returns false when compared objects that can not be coerced into BigDecimal" do
- @infinity.send(@method, nil).should == false
- @bigint.send(@method, nil).should == false
- @nan.send(@method, nil).should == false
- end
-end
diff --git a/spec/ruby/library/bigdecimal/shared/modulo.rb b/spec/ruby/library/bigdecimal/shared/modulo.rb
index aa5c5a640b..5b5e3503c4 100644
--- a/spec/ruby/library/bigdecimal/shared/modulo.rb
+++ b/spec/ruby/library/bigdecimal/shared/modulo.rb
@@ -101,25 +101,21 @@ describe :bigdecimal_modulo, shared: true do
@infinity_minus.send(@method, @infinity).should.nan?
end
- it "returns the dividend if the divisor is Infinity" do
- @one.send(@method, @infinity).should == @one
- @one.send(@method, @infinity_minus).should == @one
- @frac_2.send(@method, @infinity_minus).should == @frac_2
+ version_is BigDecimal::VERSION, "3.3.0" do
+ it "returns the dividend if the divisor is Infinity and signs are same" do
+ @one.send(@method, @infinity).should == @one
+ (-@frac_2).send(@method, @infinity_minus).should == -@frac_2
+ end
+
+ it "returns the divisor if the divisor is Infinity and signs are different" do
+ (-@one).send(@method, @infinity).should == @infinity
+ @frac_2.send(@method, @infinity_minus).should == @infinity_minus
+ end
end
it "raises TypeError if the argument cannot be coerced to BigDecimal" do
-> {
@one.send(@method, '2')
- }.should raise_error(TypeError)
- end
-end
-
-describe :bigdecimal_modulo_zerodivisionerror, shared: true do
- it "raises ZeroDivisionError if other is zero" do
- bd5667 = BigDecimal("5667.19")
-
- -> { bd5667.send(@method, 0) }.should raise_error(ZeroDivisionError)
- -> { bd5667.send(@method, BigDecimal("0")) }.should raise_error(ZeroDivisionError)
- -> { @zero.send(@method, @zero) }.should raise_error(ZeroDivisionError)
+ }.should.raise(TypeError)
end
end
diff --git a/spec/ruby/library/bigdecimal/shared/power.rb b/spec/ruby/library/bigdecimal/shared/power.rb
index 568a08589b..6dafb638e2 100644
--- a/spec/ruby/library/bigdecimal/shared/power.rb
+++ b/spec/ruby/library/bigdecimal/shared/power.rb
@@ -10,8 +10,8 @@ describe :bigdecimal_power, shared: true do
e = BigDecimal("1.00000000000000000000123456789")
one = BigDecimal("1")
ten = BigDecimal("10")
- # The tolerance is dependent upon the size of BASE_FIG
- tolerance = BigDecimal("1E-70")
+ # Accuracy is at least ndigits(== 30) + DOUBLE_FIG(== 16)
+ tolerance = BigDecimal("1E-46")
ten_powers = BigDecimal("1E10000")
pi = BigDecimal("3.14159265358979")
e3_minus.send(@method, 2).should == e3_minus_power_2
diff --git a/spec/ruby/library/bigdecimal/shared/to_int.rb b/spec/ruby/library/bigdecimal/shared/to_int.rb
deleted file mode 100644
index 44b6a3c7b2..0000000000
--- a/spec/ruby/library/bigdecimal/shared/to_int.rb
+++ /dev/null
@@ -1,16 +0,0 @@
-require 'bigdecimal'
-
-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)
- end
-
- it "returns Integer otherwise" do
- BigDecimal("3E-20001").send(@method).should == 0
- BigDecimal("2E4000").send(@method).should == 2 * 10 ** 4000
- BigDecimal("2").send(@method).should == 2
- BigDecimal("2E10").send(@method).should == 20000000000
- BigDecimal("3.14159").send(@method).should == 3
- end
-end
diff --git a/spec/ruby/library/bigdecimal/sqrt_spec.rb b/spec/ruby/library/bigdecimal/sqrt_spec.rb
index 42cf4545cb..1f3ef9a8c3 100644
--- a/spec/ruby/library/bigdecimal/sqrt_spec.rb
+++ b/spec/ruby/library/bigdecimal/sqrt_spec.rb
@@ -45,37 +45,37 @@ describe "BigDecimal#sqrt" do
it "raises ArgumentError when no argument is given" do
-> {
@one.sqrt
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
it "raises ArgumentError if a negative number is given" do
-> {
@one.sqrt(-1)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
it "raises ArgumentError if 2 arguments are given" do
-> {
@one.sqrt(1, 1)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
it "raises TypeError if nil is given" do
-> {
@one.sqrt(nil)
- }.should raise_error(TypeError)
+ }.should.raise(TypeError)
end
it "raises TypeError if a string is given" do
-> {
@one.sqrt("stuff")
- }.should raise_error(TypeError)
+ }.should.raise(TypeError)
end
it "raises TypeError if a plain Object is given" do
-> {
@one.sqrt(Object.new)
- }.should raise_error(TypeError)
+ }.should.raise(TypeError)
end
it "returns 1 if precision is 0 or 1" do
@@ -86,7 +86,7 @@ describe "BigDecimal#sqrt" do
it "raises FloatDomainError on negative values" do
-> {
BigDecimal('-1').sqrt(10)
- }.should raise_error(FloatDomainError)
+ }.should.raise(FloatDomainError)
end
it "returns positive infinity for infinity" do
@@ -96,13 +96,13 @@ describe "BigDecimal#sqrt" do
it "raises FloatDomainError for negative infinity" do
-> {
@infinity_minus.sqrt(1)
- }.should raise_error(FloatDomainError)
+ }.should.raise(FloatDomainError)
end
it "raises FloatDomainError for NaN" do
-> {
@nan.sqrt(1)
- }.should raise_error(FloatDomainError)
+ }.should.raise(FloatDomainError)
end
it "returns 0 for 0, +0.0 and -0.0" do
diff --git a/spec/ruby/library/bigdecimal/sub_spec.rb b/spec/ruby/library/bigdecimal/sub_spec.rb
index bddfec2186..3b62a0c794 100644
--- a/spec/ruby/library/bigdecimal/sub_spec.rb
+++ b/spec/ruby/library/bigdecimal/sub_spec.rb
@@ -35,14 +35,6 @@ describe "BigDecimal#sub" do
@frac_1.sub(@frac_1, 1000000).should == @zero
end
- describe "with Object" do
- it "tries to coerce the other operand to self" do
- object = mock("Object")
- object.should_receive(:coerce).with(@frac_3).and_return([@frac_3, @frac_4])
- @frac_3.sub(object, 1).should == BigDecimal("-0.9E15")
- end
- end
-
describe "with Rational" do
it "produces a BigDecimal" do
(@three - Rational(500, 2)).should == BigDecimal('-0.247e3')
diff --git a/spec/ruby/library/bigdecimal/to_f_spec.rb b/spec/ruby/library/bigdecimal/to_f_spec.rb
index 84d4d49de2..f5220d995a 100644
--- a/spec/ruby/library/bigdecimal/to_f_spec.rb
+++ b/spec/ruby/library/bigdecimal/to_f_spec.rb
@@ -20,9 +20,9 @@ describe "BigDecimal#to_f" do
end
it "returns number of type float" do
- BigDecimal("3.14159").to_f.should be_kind_of(Float)
- @vals.each { |val| val.to_f.should be_kind_of(Float) }
- @spec_vals.each { |val| val.to_f.should be_kind_of(Float) }
+ BigDecimal("3.14159").to_f.should.is_a?(Float)
+ @vals.each { |val| val.to_f.should.is_a?(Float) }
+ @spec_vals.each { |val| val.to_f.should.is_a?(Float) }
end
it "rounds correctly to Float precision" do
diff --git a/spec/ruby/library/bigdecimal/to_i_spec.rb b/spec/ruby/library/bigdecimal/to_i_spec.rb
index e5e65c562e..b6d9e43e57 100644
--- a/spec/ruby/library/bigdecimal/to_i_spec.rb
+++ b/spec/ruby/library/bigdecimal/to_i_spec.rb
@@ -1,7 +1,17 @@
require_relative '../../spec_helper'
-require_relative 'shared/to_int'
require 'bigdecimal'
describe "BigDecimal#to_i" do
- it_behaves_like :bigdecimal_to_int, :to_i
+ it "raises FloatDomainError if BigDecimal is infinity or NaN" do
+ -> { BigDecimal("Infinity").to_i }.should.raise(FloatDomainError)
+ -> { BigDecimal("NaN").to_i }.should.raise(FloatDomainError)
+ end
+
+ it "returns Integer otherwise" do
+ BigDecimal("3E-20001").to_i.should == 0
+ BigDecimal("2E4000").to_i.should == 2 * 10 ** 4000
+ BigDecimal("2").to_i.should == 2
+ BigDecimal("2E10").to_i.should == 20000000000
+ BigDecimal("3.14159").to_i.should == 3
+ end
end
diff --git a/spec/ruby/library/bigdecimal/to_int_spec.rb b/spec/ruby/library/bigdecimal/to_int_spec.rb
index 4df6749845..18f3620f5e 100644
--- a/spec/ruby/library/bigdecimal/to_int_spec.rb
+++ b/spec/ruby/library/bigdecimal/to_int_spec.rb
@@ -1,8 +1,8 @@
require_relative '../../spec_helper'
-require_relative 'shared/to_int'
require 'bigdecimal'
-
describe "BigDecimal#to_int" do
- it_behaves_like :bigdecimal_to_int, :to_int
+ it "is an alias of BigDecimal#to_i" do
+ BigDecimal.instance_method(:to_int).should == BigDecimal.instance_method(:to_i)
+ end
end
diff --git a/spec/ruby/library/bigdecimal/to_r_spec.rb b/spec/ruby/library/bigdecimal/to_r_spec.rb
index c350beff08..a112c002ef 100644
--- a/spec/ruby/library/bigdecimal/to_r_spec.rb
+++ b/spec/ruby/library/bigdecimal/to_r_spec.rb
@@ -4,25 +4,25 @@ require 'bigdecimal'
describe "BigDecimal#to_r" do
it "returns a Rational" do
- BigDecimal("3.14159").to_r.should be_kind_of(Rational)
+ BigDecimal("3.14159").to_r.should.is_a?(Rational)
end
it "returns a Rational with bignum values" do
r = BigDecimal("3.141592653589793238462643").to_r
- r.numerator.should eql(3141592653589793238462643)
- r.denominator.should eql(1000000000000000000000000)
+ r.numerator.should.eql?(3141592653589793238462643)
+ r.denominator.should.eql?(1000000000000000000000000)
end
it "returns a Rational from a BigDecimal with an exponent" do
r = BigDecimal("1E2").to_r
- r.numerator.should eql(100)
- r.denominator.should eql(1)
+ r.numerator.should.eql?(100)
+ r.denominator.should.eql?(1)
end
it "returns a Rational from a negative BigDecimal with an exponent" do
r = BigDecimal("-1E2").to_r
- r.numerator.should eql(-100)
- r.denominator.should eql(1)
+ r.numerator.should.eql?(-100)
+ r.denominator.should.eql?(1)
end
end
diff --git a/spec/ruby/library/bigdecimal/to_s_spec.rb b/spec/ruby/library/bigdecimal/to_s_spec.rb
index ba9f960eb3..5ec54765b5 100644
--- a/spec/ruby/library/bigdecimal/to_s_spec.rb
+++ b/spec/ruby/library/bigdecimal/to_s_spec.rb
@@ -31,7 +31,7 @@ describe "BigDecimal#to_s" do
end
it "takes an optional argument" do
- -> {@bigdec.to_s("F")}.should_not raise_error()
+ -> {@bigdec.to_s("F")}.should_not.raise()
end
it "starts with + if + is supplied and value is positive" do
@@ -52,10 +52,8 @@ describe "BigDecimal#to_s" do
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
+ 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
it "can return a leading space for values > 0" do
@@ -90,11 +88,11 @@ describe "BigDecimal#to_s" 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)
+ 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)
+ BigDecimal('1.23').to_s.encoding.should.equal?(Encoding::US_ASCII)
end
end
diff --git a/spec/ruby/library/bigdecimal/truncate_spec.rb b/spec/ruby/library/bigdecimal/truncate_spec.rb
index 0ae0421b30..cedc662aeb 100644
--- a/spec/ruby/library/bigdecimal/truncate_spec.rb
+++ b/spec/ruby/library/bigdecimal/truncate_spec.rb
@@ -74,8 +74,8 @@ describe "BigDecimal#truncate" do
end
it "returns the same value if self is special value" do
- -> { @nan.truncate }.should raise_error(FloatDomainError)
- -> { @infinity.truncate }.should raise_error(FloatDomainError)
- -> { @infinity_negative.truncate }.should raise_error(FloatDomainError)
+ -> { @nan.truncate }.should.raise(FloatDomainError)
+ -> { @infinity.truncate }.should.raise(FloatDomainError)
+ -> { @infinity_negative.truncate }.should.raise(FloatDomainError)
end
end
diff --git a/spec/ruby/library/bigdecimal/util_spec.rb b/spec/ruby/library/bigdecimal/util_spec.rb
index fc67fcf200..69663d4bd2 100644
--- a/spec/ruby/library/bigdecimal/util_spec.rb
+++ b/spec/ruby/library/bigdecimal/util_spec.rb
@@ -20,7 +20,7 @@ describe "BigDecimal's util method definitions" do
it "should define #to_d on BigDecimal" do
bd = BigDecimal("3.14")
- bd.to_d.should equal(bd)
+ bd.to_d.should.equal?(bd)
end
it "should define #to_d on Rational" do
diff --git a/spec/ruby/library/cgi/cookie/domain_spec.rb b/spec/ruby/library/cgi/cookie/domain_spec.rb
index 622549039f..c118ef6383 100644
--- a/spec/ruby/library/cgi/cookie/domain_spec.rb
+++ b/spec/ruby/library/cgi/cookie/domain_spec.rb
@@ -1,12 +1,12 @@
require_relative '../../../spec_helper'
-ruby_version_is ""..."3.5" do
+ruby_version_is ""..."4.0" do
require 'cgi'
describe "CGI::Cookie#domain" do
it "returns self's domain" do
cookie = CGI::Cookie.new("test-cookie")
- cookie.domain.should be_nil
+ cookie.domain.should == nil
cookie = CGI::Cookie.new("name" => "test-cookie", "domain" => "example.com")
cookie.domain.should == "example.com"
diff --git a/spec/ruby/library/cgi/cookie/expires_spec.rb b/spec/ruby/library/cgi/cookie/expires_spec.rb
index df52a6f41e..b9cc7d5b65 100644
--- a/spec/ruby/library/cgi/cookie/expires_spec.rb
+++ b/spec/ruby/library/cgi/cookie/expires_spec.rb
@@ -1,12 +1,12 @@
require_relative '../../../spec_helper'
-ruby_version_is ""..."3.5" do
+ruby_version_is ""..."4.0" do
require 'cgi'
describe "CGI::Cookie#expires" do
it "returns self's expiration date" do
cookie = CGI::Cookie.new("test-cookie")
- cookie.expires.should be_nil
+ cookie.expires.should == nil
cookie = CGI::Cookie.new("name" => "test-cookie", "expires" => Time.at(1196524602))
cookie.expires.should == Time.at(1196524602)
diff --git a/spec/ruby/library/cgi/cookie/initialize_spec.rb b/spec/ruby/library/cgi/cookie/initialize_spec.rb
index ac99d5e4fd..80bc2c2196 100644
--- a/spec/ruby/library/cgi/cookie/initialize_spec.rb
+++ b/spec/ruby/library/cgi/cookie/initialize_spec.rb
@@ -1,6 +1,6 @@
require_relative '../../../spec_helper'
-ruby_version_is ""..."3.5" do
+ruby_version_is ""..."4.0" do
require 'cgi'
describe "CGI::Cookie#initialize when passed String" do
@@ -20,7 +20,7 @@ ruby_version_is ""..."3.5" do
it "sets self to a non-secure cookie" do
@cookie.send(:initialize, "test")
- @cookie.secure.should be_false
+ @cookie.secure.should == false
end
it "does set self's path to an empty String when ENV[\"SCRIPT_NAME\"] is not set" do
@@ -49,11 +49,11 @@ ruby_version_is ""..."3.5" do
end
it "does not set self's expiration date" do
- @cookie.expires.should be_nil
+ @cookie.expires.should == nil
end
it "does not set self's domain" do
- @cookie.domain.should be_nil
+ @cookie.domain.should == nil
end
end
@@ -76,7 +76,7 @@ ruby_version_is ""..."3.5" do
@cookie.path.should == "some/path/"
@cookie.domain.should == "example.com"
@cookie.expires.should == Time.at(1196524602)
- @cookie.secure.should be_true
+ @cookie.secure.should == true
end
it "does set self's path based on ENV[\"SCRIPT_NAME\"] when the Hash has no 'path' entry" do
@@ -122,8 +122,8 @@ ruby_version_is ""..."3.5" do
end
it "raises a ArgumentError when the passed Hash has no 'name' entry" do
- -> { @cookie.send(:initialize, {}) }.should raise_error(ArgumentError)
- -> { @cookie.send(:initialize, "value" => "test") }.should raise_error(ArgumentError)
+ -> { @cookie.send(:initialize, {}) }.should.raise(ArgumentError)
+ -> { @cookie.send(:initialize, "value" => "test") }.should.raise(ArgumentError)
end
end
@@ -144,7 +144,7 @@ ruby_version_is ""..."3.5" do
it "sets self to a non-secure cookie" do
@cookie.send(:initialize, "test", "one", "two", "three")
- @cookie.secure.should be_false
+ @cookie.secure.should == false
end
end
end
diff --git a/spec/ruby/library/cgi/cookie/name_spec.rb b/spec/ruby/library/cgi/cookie/name_spec.rb
index 712628180b..4908204e8a 100644
--- a/spec/ruby/library/cgi/cookie/name_spec.rb
+++ b/spec/ruby/library/cgi/cookie/name_spec.rb
@@ -1,6 +1,6 @@
require_relative '../../../spec_helper'
-ruby_version_is ""..."3.5" do
+ruby_version_is ""..."4.0" do
require 'cgi'
describe "CGI::Cookie#name" do
diff --git a/spec/ruby/library/cgi/cookie/parse_spec.rb b/spec/ruby/library/cgi/cookie/parse_spec.rb
index ecc78d77dc..bc505c37ba 100644
--- a/spec/ruby/library/cgi/cookie/parse_spec.rb
+++ b/spec/ruby/library/cgi/cookie/parse_spec.rb
@@ -1,6 +1,6 @@
require_relative '../../../spec_helper'
-ruby_version_is ""..."3.5" do
+ruby_version_is ""..."4.0" do
require 'cgi'
describe "CGI::Cookie.parse" do
diff --git a/spec/ruby/library/cgi/cookie/path_spec.rb b/spec/ruby/library/cgi/cookie/path_spec.rb
index 010e87a6b8..13ee5d726b 100644
--- a/spec/ruby/library/cgi/cookie/path_spec.rb
+++ b/spec/ruby/library/cgi/cookie/path_spec.rb
@@ -1,6 +1,6 @@
require_relative '../../../spec_helper'
-ruby_version_is ""..."3.5" do
+ruby_version_is ""..."4.0" do
require 'cgi'
describe "CGI::Cookie#path" do
diff --git a/spec/ruby/library/cgi/cookie/secure_spec.rb b/spec/ruby/library/cgi/cookie/secure_spec.rb
index b526897250..233881b173 100644
--- a/spec/ruby/library/cgi/cookie/secure_spec.rb
+++ b/spec/ruby/library/cgi/cookie/secure_spec.rb
@@ -1,6 +1,6 @@
require_relative '../../../spec_helper'
-ruby_version_is ""..."3.5" do
+ruby_version_is ""..."4.0" do
require 'cgi'
describe "CGI::Cookie#secure" do
@@ -10,10 +10,10 @@ ruby_version_is ""..."3.5" do
it "returns whether self is a secure cookie or not" do
@cookie.secure = true
- @cookie.secure.should be_true
+ @cookie.secure.should == true
@cookie.secure = false
- @cookie.secure.should be_false
+ @cookie.secure.should == false
end
end
@@ -23,12 +23,12 @@ ruby_version_is ""..."3.5" do
end
it "returns true" do
- (@cookie.secure = true).should be_true
+ (@cookie.secure = true).should == true
end
it "sets self to a secure cookie" do
@cookie.secure = true
- @cookie.secure.should be_true
+ @cookie.secure.should == true
end
end
@@ -38,12 +38,12 @@ ruby_version_is ""..."3.5" do
end
it "returns false" do
- (@cookie.secure = false).should be_false
+ (@cookie.secure = false).should == false
end
it "sets self to a non-secure cookie" do
@cookie.secure = false
- @cookie.secure.should be_false
+ @cookie.secure.should == false
end
end
@@ -56,18 +56,18 @@ ruby_version_is ""..."3.5" do
@cookie.secure = false
@cookie.secure = Object.new
- @cookie.secure.should be_false
+ @cookie.secure.should == false
@cookie.secure = "Test"
- @cookie.secure.should be_false
+ @cookie.secure.should == false
@cookie.secure = true
@cookie.secure = Object.new
- @cookie.secure.should be_true
+ @cookie.secure.should == true
@cookie.secure = "Test"
- @cookie.secure.should be_true
+ @cookie.secure.should == true
end
end
end
diff --git a/spec/ruby/library/cgi/cookie/to_s_spec.rb b/spec/ruby/library/cgi/cookie/to_s_spec.rb
index 34326f672b..20d2579f8d 100644
--- a/spec/ruby/library/cgi/cookie/to_s_spec.rb
+++ b/spec/ruby/library/cgi/cookie/to_s_spec.rb
@@ -1,6 +1,6 @@
require_relative '../../../spec_helper'
-ruby_version_is ""..."3.5" do
+ruby_version_is ""..."4.0" do
require 'cgi'
describe "CGI::Cookie#to_s" do
diff --git a/spec/ruby/library/cgi/cookie/value_spec.rb b/spec/ruby/library/cgi/cookie/value_spec.rb
index e7c91b55b9..45032edcbf 100644
--- a/spec/ruby/library/cgi/cookie/value_spec.rb
+++ b/spec/ruby/library/cgi/cookie/value_spec.rb
@@ -1,6 +1,6 @@
require_relative '../../../spec_helper'
-ruby_version_is ""..."3.5" do
+ruby_version_is ""..."4.0" do
require 'cgi'
describe "CGI::Cookie#value" do
@@ -37,7 +37,7 @@ ruby_version_is ""..."3.5" do
cookie2.value.send(method, *args)
fail << method unless cookie1.value == cookie2.value
end
- fail.should be_empty
+ fail.should.empty?
end
end
diff --git a/spec/ruby/library/cgi/escapeElement_spec.rb b/spec/ruby/library/cgi/escapeElement_spec.rb
index 7bfa3f4feb..72c38d6028 100644
--- a/spec/ruby/library/cgi/escapeElement_spec.rb
+++ b/spec/ruby/library/cgi/escapeElement_spec.rb
@@ -1,9 +1,9 @@
require_relative '../../spec_helper'
-ruby_version_is ""..."3.5" do
+ruby_version_is ""..."4.0" do
require 'cgi'
end
-ruby_version_is "3.5" do
+ruby_version_is "4.0" do
require 'cgi/escape'
end
diff --git a/spec/ruby/library/cgi/escapeURIComponent_spec.rb b/spec/ruby/library/cgi/escapeURIComponent_spec.rb
index 02921ab8bf..98efa2e67e 100644
--- a/spec/ruby/library/cgi/escapeURIComponent_spec.rb
+++ b/spec/ruby/library/cgi/escapeURIComponent_spec.rb
@@ -6,48 +6,67 @@ rescue LoadError
end
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'
+ it "percent-encodes characters reserved according to RFC 3986" do
+ # https://www.rfc-editor.org/rfc/rfc3986#section-2.2
+ string = ":/?#[]@!$&'()*+,;="
+ CGI.escapeURIComponent(string).should == "%3A%2F%3F%23%5B%5D%40%21%24%26%27%28%29%2A%2B%2C%3B%3D"
end
- it "does not escape with unreserved characters" do
+ it "does not percent-encode unreserved characters according to RFC 3986" 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"
+ it "encodes % character as %25" do
+ CGI.escapeURIComponent("%").should == "%25"
end
- it "processes String bytes one by one, not characters" do
- CGI.escapeURIComponent("β").should == "%CE%B2" # "β" bytes representation is CE B2
+ # Compare to .escape which uses "+".
+ it "percent-encodes single whitespace" do
+ CGI.escapeURIComponent(" ").should == "%20"
end
- it "raises a TypeError with nil" do
- -> {
- CGI.escapeURIComponent(nil)
- }.should raise_error(TypeError, 'no implicit conversion of nil into String')
+ it "percent-encodes all non-reserved and non-unreserved ASCII characters" do
+ special_set = ":/?#[]@!$&'()*+,;=ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~"
+ all_other = (0x00..0x7F).filter_map { |i| i.chr unless special_set.include?(i.chr) }.join
+ encoded = CGI.escapeURIComponent(all_other)
+ encoded.should.match?(/\A(?:%[0-9A-F]{2}){#{all_other.length}}\z/)
end
- it "encodes empty string" do
- CGI.escapeURIComponent("").should == ""
+ it "percent-encodes non-ASCII bytes" do
+ bytes = (0x80..0xFF).map(&:chr).join
+ encoded = CGI.escapeURIComponent(bytes)
+ encoded.should.match?(/\A(?:%[0-9A-F]{2}){#{bytes.length}}\z/)
end
- it "encodes single whitespace" do
- CGI.escapeURIComponent(" ").should == "%20"
+ it "processes multi-byte characters as separate bytes, percent-encoding each one" do
+ CGI.escapeURIComponent("β").should == "%CE%B2" # "β" bytes representation is CE B2
end
- it "encodes double whitespace" do
- CGI.escapeURIComponent(" ").should == "%20%20"
+ it "produces a copy of an empty string" do
+ string = "".encode(Encoding::BINARY)
+ encoded = CGI.escapeURIComponent(string)
+ encoded.should == ""
+ encoded.encoding.should == Encoding::BINARY
+ string.should_not.equal?(encoded)
end
- it "preserves encoding" do
+ it "preserves string's encoding" do
string = "whatever".encode("ASCII-8BIT")
CGI.escapeURIComponent(string).encoding.should == Encoding::ASCII_8BIT
end
+ it "processes even strings with invalid encoding, percent-encoding octets as-is" do
+ string = "\xC0<<".dup.force_encoding("UTF-8")
+ CGI.escapeURIComponent(string).should == "%C0%3C%3C"
+ end
+
+ it "raises a TypeError with nil" do
+ -> {
+ CGI.escapeURIComponent(nil)
+ }.should.raise(TypeError, "no implicit conversion of nil into String")
+ end
+
it "uses implicit type conversion to String" do
object = Object.new
def object.to_str
diff --git a/spec/ruby/library/cgi/htmlextension/a_spec.rb b/spec/ruby/library/cgi/htmlextension/a_spec.rb
index 16a0552bac..78d3dec8fa 100644
--- a/spec/ruby/library/cgi/htmlextension/a_spec.rb
+++ b/spec/ruby/library/cgi/htmlextension/a_spec.rb
@@ -1,6 +1,6 @@
require_relative '../../../spec_helper'
-ruby_version_is ""..."3.5" do
+ruby_version_is ""..."4.0" do
require 'cgi'
require_relative 'fixtures/common'
diff --git a/spec/ruby/library/cgi/htmlextension/base_spec.rb b/spec/ruby/library/cgi/htmlextension/base_spec.rb
index a4c4a61614..1eedfdea54 100644
--- a/spec/ruby/library/cgi/htmlextension/base_spec.rb
+++ b/spec/ruby/library/cgi/htmlextension/base_spec.rb
@@ -1,6 +1,6 @@
require_relative '../../../spec_helper'
-ruby_version_is ""..."3.5" do
+ruby_version_is ""..."4.0" do
require 'cgi'
require_relative 'fixtures/common'
diff --git a/spec/ruby/library/cgi/htmlextension/blockquote_spec.rb b/spec/ruby/library/cgi/htmlextension/blockquote_spec.rb
index f8d4ca310e..883e36f78b 100644
--- a/spec/ruby/library/cgi/htmlextension/blockquote_spec.rb
+++ b/spec/ruby/library/cgi/htmlextension/blockquote_spec.rb
@@ -1,6 +1,6 @@
require_relative '../../../spec_helper'
-ruby_version_is ""..."3.5" do
+ruby_version_is ""..."4.0" do
require 'cgi'
require_relative 'fixtures/common'
diff --git a/spec/ruby/library/cgi/htmlextension/br_spec.rb b/spec/ruby/library/cgi/htmlextension/br_spec.rb
index 45909a2db7..23c2cb4a48 100644
--- a/spec/ruby/library/cgi/htmlextension/br_spec.rb
+++ b/spec/ruby/library/cgi/htmlextension/br_spec.rb
@@ -1,6 +1,6 @@
require_relative '../../../spec_helper'
-ruby_version_is ""..."3.5" do
+ruby_version_is ""..."4.0" do
require 'cgi'
require_relative 'fixtures/common'
diff --git a/spec/ruby/library/cgi/htmlextension/caption_spec.rb b/spec/ruby/library/cgi/htmlextension/caption_spec.rb
index 74f0a098f4..3d3e21ecaa 100644
--- a/spec/ruby/library/cgi/htmlextension/caption_spec.rb
+++ b/spec/ruby/library/cgi/htmlextension/caption_spec.rb
@@ -1,6 +1,6 @@
require_relative '../../../spec_helper'
-ruby_version_is ""..."3.5" do
+ruby_version_is ""..."4.0" do
require 'cgi'
require_relative 'fixtures/common'
diff --git a/spec/ruby/library/cgi/htmlextension/checkbox_group_spec.rb b/spec/ruby/library/cgi/htmlextension/checkbox_group_spec.rb
index 1acfe62fda..07163c010e 100644
--- a/spec/ruby/library/cgi/htmlextension/checkbox_group_spec.rb
+++ b/spec/ruby/library/cgi/htmlextension/checkbox_group_spec.rb
@@ -1,6 +1,6 @@
require_relative '../../../spec_helper'
-ruby_version_is ""..."3.5" do
+ruby_version_is ""..."4.0" do
require 'cgi'
require_relative 'fixtures/common'
diff --git a/spec/ruby/library/cgi/htmlextension/checkbox_spec.rb b/spec/ruby/library/cgi/htmlextension/checkbox_spec.rb
index ba410f31de..ad87b78061 100644
--- a/spec/ruby/library/cgi/htmlextension/checkbox_spec.rb
+++ b/spec/ruby/library/cgi/htmlextension/checkbox_spec.rb
@@ -1,6 +1,6 @@
require_relative '../../../spec_helper'
-ruby_version_is ""..."3.5" do
+ruby_version_is ""..."4.0" do
require 'cgi'
require_relative 'fixtures/common'
diff --git a/spec/ruby/library/cgi/htmlextension/doctype_spec.rb b/spec/ruby/library/cgi/htmlextension/doctype_spec.rb
index 49501ac8f7..02af831855 100644
--- a/spec/ruby/library/cgi/htmlextension/doctype_spec.rb
+++ b/spec/ruby/library/cgi/htmlextension/doctype_spec.rb
@@ -1,6 +1,6 @@
require_relative '../../../spec_helper'
-ruby_version_is ""..."3.5" do
+ruby_version_is ""..."4.0" do
require 'cgi'
require_relative 'fixtures/common'
diff --git a/spec/ruby/library/cgi/htmlextension/file_field_spec.rb b/spec/ruby/library/cgi/htmlextension/file_field_spec.rb
index b8ef0b2045..eff077b9a2 100644
--- a/spec/ruby/library/cgi/htmlextension/file_field_spec.rb
+++ b/spec/ruby/library/cgi/htmlextension/file_field_spec.rb
@@ -1,6 +1,6 @@
require_relative '../../../spec_helper'
-ruby_version_is ""..."3.5" do
+ruby_version_is ""..."4.0" do
require 'cgi'
require_relative 'fixtures/common'
diff --git a/spec/ruby/library/cgi/htmlextension/form_spec.rb b/spec/ruby/library/cgi/htmlextension/form_spec.rb
index 510ce27b77..55ac63152b 100644
--- a/spec/ruby/library/cgi/htmlextension/form_spec.rb
+++ b/spec/ruby/library/cgi/htmlextension/form_spec.rb
@@ -1,6 +1,6 @@
require_relative '../../../spec_helper'
-ruby_version_is ""..."3.5" do
+ruby_version_is ""..."4.0" do
require 'cgi'
require_relative 'fixtures/common'
diff --git a/spec/ruby/library/cgi/htmlextension/frame_spec.rb b/spec/ruby/library/cgi/htmlextension/frame_spec.rb
index 0dc30e94f7..fef40849eb 100644
--- a/spec/ruby/library/cgi/htmlextension/frame_spec.rb
+++ b/spec/ruby/library/cgi/htmlextension/frame_spec.rb
@@ -1,6 +1,6 @@
require_relative '../../../spec_helper'
-ruby_version_is ""..."3.5" do
+ruby_version_is ""..."4.0" do
require_relative 'fixtures/common'
require 'cgi'
diff --git a/spec/ruby/library/cgi/htmlextension/frameset_spec.rb b/spec/ruby/library/cgi/htmlextension/frameset_spec.rb
index a37b5f537d..3ad0a9c4d2 100644
--- a/spec/ruby/library/cgi/htmlextension/frameset_spec.rb
+++ b/spec/ruby/library/cgi/htmlextension/frameset_spec.rb
@@ -1,6 +1,6 @@
require_relative '../../../spec_helper'
-ruby_version_is ""..."3.5" do
+ruby_version_is ""..."4.0" do
require_relative 'fixtures/common'
require 'cgi'
diff --git a/spec/ruby/library/cgi/htmlextension/hidden_spec.rb b/spec/ruby/library/cgi/htmlextension/hidden_spec.rb
index 5771058fa3..b2323775f6 100644
--- a/spec/ruby/library/cgi/htmlextension/hidden_spec.rb
+++ b/spec/ruby/library/cgi/htmlextension/hidden_spec.rb
@@ -1,6 +1,6 @@
require_relative '../../../spec_helper'
-ruby_version_is ""..."3.5" do
+ruby_version_is ""..."4.0" do
require 'cgi'
require_relative 'fixtures/common'
diff --git a/spec/ruby/library/cgi/htmlextension/html_spec.rb b/spec/ruby/library/cgi/htmlextension/html_spec.rb
index 0e4052dcc4..60a10fb6b4 100644
--- a/spec/ruby/library/cgi/htmlextension/html_spec.rb
+++ b/spec/ruby/library/cgi/htmlextension/html_spec.rb
@@ -1,6 +1,6 @@
require_relative '../../../spec_helper'
-ruby_version_is ""..."3.5" do
+ruby_version_is ""..."4.0" do
require 'cgi'
require_relative 'fixtures/common'
diff --git a/spec/ruby/library/cgi/htmlextension/image_button_spec.rb b/spec/ruby/library/cgi/htmlextension/image_button_spec.rb
index cd7f1ae4f7..f8770119d4 100644
--- a/spec/ruby/library/cgi/htmlextension/image_button_spec.rb
+++ b/spec/ruby/library/cgi/htmlextension/image_button_spec.rb
@@ -1,6 +1,6 @@
require_relative '../../../spec_helper'
-ruby_version_is ""..."3.5" do
+ruby_version_is ""..."4.0" do
require 'cgi'
require_relative 'fixtures/common'
diff --git a/spec/ruby/library/cgi/htmlextension/img_spec.rb b/spec/ruby/library/cgi/htmlextension/img_spec.rb
index 193d3dca26..a05cfdea48 100644
--- a/spec/ruby/library/cgi/htmlextension/img_spec.rb
+++ b/spec/ruby/library/cgi/htmlextension/img_spec.rb
@@ -1,6 +1,6 @@
require_relative '../../../spec_helper'
-ruby_version_is ""..."3.5" do
+ruby_version_is ""..."4.0" do
require 'cgi'
require_relative 'fixtures/common'
diff --git a/spec/ruby/library/cgi/htmlextension/multipart_form_spec.rb b/spec/ruby/library/cgi/htmlextension/multipart_form_spec.rb
index e5c16f2475..4b56a7abfe 100644
--- a/spec/ruby/library/cgi/htmlextension/multipart_form_spec.rb
+++ b/spec/ruby/library/cgi/htmlextension/multipart_form_spec.rb
@@ -1,6 +1,6 @@
require_relative '../../../spec_helper'
-ruby_version_is ""..."3.5" do
+ruby_version_is ""..."4.0" do
require 'cgi'
require_relative 'fixtures/common'
@@ -11,7 +11,7 @@ ruby_version_is ""..."3.5" do
end
describe "when passed no arguments" do
- it "returns a 'form'-element with it's enctype set to multipart" do
+ it "returns a 'form'-element with its enctype set to multipart" do
output = @html.multipart_form
output.should equal_element("FORM", { "ENCTYPE" => "multipart/form-data", "METHOD" => "post" }, "")
end
diff --git a/spec/ruby/library/cgi/htmlextension/password_field_spec.rb b/spec/ruby/library/cgi/htmlextension/password_field_spec.rb
index a462bea015..0fefdd5c45 100644
--- a/spec/ruby/library/cgi/htmlextension/password_field_spec.rb
+++ b/spec/ruby/library/cgi/htmlextension/password_field_spec.rb
@@ -1,6 +1,6 @@
require_relative '../../../spec_helper'
-ruby_version_is ""..."3.5" do
+ruby_version_is ""..."4.0" do
require 'cgi'
require_relative 'fixtures/common'
diff --git a/spec/ruby/library/cgi/htmlextension/popup_menu_spec.rb b/spec/ruby/library/cgi/htmlextension/popup_menu_spec.rb
index 0ec85e96df..7452d15317 100644
--- a/spec/ruby/library/cgi/htmlextension/popup_menu_spec.rb
+++ b/spec/ruby/library/cgi/htmlextension/popup_menu_spec.rb
@@ -1,6 +1,6 @@
require_relative '../../../spec_helper'
-ruby_version_is ""..."3.5" do
+ruby_version_is ""..."4.0" do
require 'cgi'
require_relative 'fixtures/common'
require_relative 'shared/popup_menu'
diff --git a/spec/ruby/library/cgi/htmlextension/radio_button_spec.rb b/spec/ruby/library/cgi/htmlextension/radio_button_spec.rb
index 865c16d232..8458685cdc 100644
--- a/spec/ruby/library/cgi/htmlextension/radio_button_spec.rb
+++ b/spec/ruby/library/cgi/htmlextension/radio_button_spec.rb
@@ -1,6 +1,6 @@
require_relative '../../../spec_helper'
-ruby_version_is ""..."3.5" do
+ruby_version_is ""..."4.0" do
require 'cgi'
require_relative 'fixtures/common'
diff --git a/spec/ruby/library/cgi/htmlextension/radio_group_spec.rb b/spec/ruby/library/cgi/htmlextension/radio_group_spec.rb
index 7381e7183b..fd925a5165 100644
--- a/spec/ruby/library/cgi/htmlextension/radio_group_spec.rb
+++ b/spec/ruby/library/cgi/htmlextension/radio_group_spec.rb
@@ -1,6 +1,6 @@
require_relative '../../../spec_helper'
-ruby_version_is ""..."3.5" do
+ruby_version_is ""..."4.0" do
require 'cgi'
require_relative 'fixtures/common'
diff --git a/spec/ruby/library/cgi/htmlextension/reset_spec.rb b/spec/ruby/library/cgi/htmlextension/reset_spec.rb
index d3a5c801fa..80e4441b16 100644
--- a/spec/ruby/library/cgi/htmlextension/reset_spec.rb
+++ b/spec/ruby/library/cgi/htmlextension/reset_spec.rb
@@ -1,6 +1,6 @@
require_relative '../../../spec_helper'
-ruby_version_is ""..."3.5" do
+ruby_version_is ""..."4.0" do
require 'cgi'
require_relative 'fixtures/common'
diff --git a/spec/ruby/library/cgi/htmlextension/scrolling_list_spec.rb b/spec/ruby/library/cgi/htmlextension/scrolling_list_spec.rb
index aab52d7409..b565444679 100644
--- a/spec/ruby/library/cgi/htmlextension/scrolling_list_spec.rb
+++ b/spec/ruby/library/cgi/htmlextension/scrolling_list_spec.rb
@@ -1,6 +1,6 @@
require_relative '../../../spec_helper'
-ruby_version_is ""..."3.5" do
+ruby_version_is ""..."4.0" do
require_relative 'fixtures/common'
require 'cgi'
require_relative 'shared/popup_menu'
diff --git a/spec/ruby/library/cgi/htmlextension/submit_spec.rb b/spec/ruby/library/cgi/htmlextension/submit_spec.rb
index 3401b10356..bb6e079c4e 100644
--- a/spec/ruby/library/cgi/htmlextension/submit_spec.rb
+++ b/spec/ruby/library/cgi/htmlextension/submit_spec.rb
@@ -1,6 +1,6 @@
require_relative '../../../spec_helper'
-ruby_version_is ""..."3.5" do
+ruby_version_is ""..."4.0" do
require 'cgi'
require_relative 'fixtures/common'
diff --git a/spec/ruby/library/cgi/htmlextension/text_field_spec.rb b/spec/ruby/library/cgi/htmlextension/text_field_spec.rb
index 4f63dbce59..37e13e3746 100644
--- a/spec/ruby/library/cgi/htmlextension/text_field_spec.rb
+++ b/spec/ruby/library/cgi/htmlextension/text_field_spec.rb
@@ -1,6 +1,6 @@
require_relative '../../../spec_helper'
-ruby_version_is ""..."3.5" do
+ruby_version_is ""..."4.0" do
require 'cgi'
require_relative 'fixtures/common'
diff --git a/spec/ruby/library/cgi/htmlextension/textarea_spec.rb b/spec/ruby/library/cgi/htmlextension/textarea_spec.rb
index a3881796fd..99c6d3dd2d 100644
--- a/spec/ruby/library/cgi/htmlextension/textarea_spec.rb
+++ b/spec/ruby/library/cgi/htmlextension/textarea_spec.rb
@@ -1,6 +1,6 @@
require_relative '../../../spec_helper'
-ruby_version_is ""..."3.5" do
+ruby_version_is ""..."4.0" do
require 'cgi'
require_relative 'fixtures/common'
diff --git a/spec/ruby/library/cgi/http_header_spec.rb b/spec/ruby/library/cgi/http_header_spec.rb
index 173055718b..8d9f3fe9b8 100644
--- a/spec/ruby/library/cgi/http_header_spec.rb
+++ b/spec/ruby/library/cgi/http_header_spec.rb
@@ -1,6 +1,6 @@
require_relative '../../spec_helper'
-ruby_version_is ""..."3.5" do
+ruby_version_is ""..."4.0" do
require 'cgi'
require_relative 'shared/http_header'
diff --git a/spec/ruby/library/cgi/initialize_spec.rb b/spec/ruby/library/cgi/initialize_spec.rb
index d46b5a3564..6135522c54 100644
--- a/spec/ruby/library/cgi/initialize_spec.rb
+++ b/spec/ruby/library/cgi/initialize_spec.rb
@@ -1,11 +1,11 @@
require_relative '../../spec_helper'
-ruby_version_is ""..."3.5" do
+ruby_version_is ""..."4.0" do
require 'cgi'
describe "CGI#initialize" do
it "is private" do
- CGI.should have_private_instance_method(:initialize)
+ CGI.private_instance_methods(false).should.include?(:initialize)
end
end
@@ -21,21 +21,21 @@ ruby_version_is ""..."3.5" do
it "extends self with CGI::QueryExtension" do
@cgi.send(:initialize)
- @cgi.should be_kind_of(CGI::QueryExtension)
+ @cgi.should.is_a?(CGI::QueryExtension)
end
it "does not extend self with CGI::HtmlExtension" do
@cgi.send(:initialize)
- @cgi.should_not be_kind_of(CGI::HtmlExtension)
+ @cgi.should_not.is_a?(CGI::HtmlExtension)
end
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::Html4)
- @cgi.should_not be_kind_of(CGI::Html4Tr)
- @cgi.should_not be_kind_of(CGI::Html4Fr)
+ @cgi.should_not.is_a?(CGI::HtmlExtension)
+ @cgi.should_not.is_a?(CGI::Html3)
+ @cgi.should_not.is_a?(CGI::Html4)
+ @cgi.should_not.is_a?(CGI::Html4Tr)
+ @cgi.should_not.is_a?(CGI::Html4Fr)
end
it "sets #cookies based on ENV['HTTP_COOKIE']" do
@@ -86,51 +86,51 @@ ruby_version_is ""..."3.5" do
it "extends self with CGI::QueryExtension" do
@cgi.send(:initialize, "test")
- @cgi.should be_kind_of(CGI::QueryExtension)
+ @cgi.should.is_a?(CGI::QueryExtension)
end
it "extends self with CGI::QueryExtension, CGI::Html3 and CGI::HtmlExtension when the passed type is 'html3'" do
@cgi.send(:initialize, "html3")
- @cgi.should be_kind_of(CGI::Html3)
- @cgi.should be_kind_of(CGI::HtmlExtension)
- @cgi.should be_kind_of(CGI::QueryExtension)
+ @cgi.should.is_a?(CGI::Html3)
+ @cgi.should.is_a?(CGI::HtmlExtension)
+ @cgi.should.is_a?(CGI::QueryExtension)
- @cgi.should_not be_kind_of(CGI::Html4)
- @cgi.should_not be_kind_of(CGI::Html4Tr)
- @cgi.should_not be_kind_of(CGI::Html4Fr)
+ @cgi.should_not.is_a?(CGI::Html4)
+ @cgi.should_not.is_a?(CGI::Html4Tr)
+ @cgi.should_not.is_a?(CGI::Html4Fr)
end
it "extends self with CGI::QueryExtension, CGI::Html4 and CGI::HtmlExtension when the passed type is 'html4'" do
@cgi.send(:initialize, "html4")
- @cgi.should be_kind_of(CGI::Html4)
- @cgi.should be_kind_of(CGI::HtmlExtension)
- @cgi.should be_kind_of(CGI::QueryExtension)
+ @cgi.should.is_a?(CGI::Html4)
+ @cgi.should.is_a?(CGI::HtmlExtension)
+ @cgi.should.is_a?(CGI::QueryExtension)
- @cgi.should_not be_kind_of(CGI::Html3)
- @cgi.should_not be_kind_of(CGI::Html4Tr)
- @cgi.should_not be_kind_of(CGI::Html4Fr)
+ @cgi.should_not.is_a?(CGI::Html3)
+ @cgi.should_not.is_a?(CGI::Html4Tr)
+ @cgi.should_not.is_a?(CGI::Html4Fr)
end
it "extends self with CGI::QueryExtension, CGI::Html4Tr and CGI::HtmlExtension when the passed type is 'html4Tr'" do
@cgi.send(:initialize, "html4Tr")
- @cgi.should be_kind_of(CGI::Html4Tr)
- @cgi.should be_kind_of(CGI::HtmlExtension)
- @cgi.should be_kind_of(CGI::QueryExtension)
+ @cgi.should.is_a?(CGI::Html4Tr)
+ @cgi.should.is_a?(CGI::HtmlExtension)
+ @cgi.should.is_a?(CGI::QueryExtension)
- @cgi.should_not be_kind_of(CGI::Html3)
- @cgi.should_not be_kind_of(CGI::Html4)
- @cgi.should_not be_kind_of(CGI::Html4Fr)
+ @cgi.should_not.is_a?(CGI::Html3)
+ @cgi.should_not.is_a?(CGI::Html4)
+ @cgi.should_not.is_a?(CGI::Html4Fr)
end
it "extends self with CGI::QueryExtension, CGI::Html4Tr, CGI::Html4Fr and CGI::HtmlExtension when the passed type is 'html4Fr'" do
@cgi.send(:initialize, "html4Fr")
- @cgi.should be_kind_of(CGI::Html4Tr)
- @cgi.should be_kind_of(CGI::Html4Fr)
- @cgi.should be_kind_of(CGI::HtmlExtension)
- @cgi.should be_kind_of(CGI::QueryExtension)
+ @cgi.should.is_a?(CGI::Html4Tr)
+ @cgi.should.is_a?(CGI::Html4Fr)
+ @cgi.should.is_a?(CGI::HtmlExtension)
+ @cgi.should.is_a?(CGI::QueryExtension)
- @cgi.should_not be_kind_of(CGI::Html3)
- @cgi.should_not be_kind_of(CGI::Html4)
+ @cgi.should_not.is_a?(CGI::Html3)
+ @cgi.should_not.is_a?(CGI::Html4)
end
end
end
diff --git a/spec/ruby/library/cgi/out_spec.rb b/spec/ruby/library/cgi/out_spec.rb
index c79d000284..e9eaf5e151 100644
--- a/spec/ruby/library/cgi/out_spec.rb
+++ b/spec/ruby/library/cgi/out_spec.rb
@@ -1,6 +1,6 @@
require_relative '../../spec_helper'
-ruby_version_is ""..."3.5" do
+ruby_version_is ""..."4.0" do
require 'cgi'
describe "CGI#out" do
@@ -48,7 +48,7 @@ ruby_version_is ""..."3.5" do
end
it "raises a LocalJumpError" do
- -> { @cgi.out }.should raise_error(LocalJumpError)
+ -> { @cgi.out }.should.raise(LocalJumpError)
end
end
end
diff --git a/spec/ruby/library/cgi/parse_spec.rb b/spec/ruby/library/cgi/parse_spec.rb
index d35d0d3365..f09270c195 100644
--- a/spec/ruby/library/cgi/parse_spec.rb
+++ b/spec/ruby/library/cgi/parse_spec.rb
@@ -1,6 +1,6 @@
require_relative '../../spec_helper'
-ruby_version_is ""..."3.5" do
+ruby_version_is ""..."4.0" do
require 'cgi'
describe "CGI.parse when passed String" do
diff --git a/spec/ruby/library/cgi/pretty_spec.rb b/spec/ruby/library/cgi/pretty_spec.rb
index 1fed3bbd2e..9df1611037 100644
--- a/spec/ruby/library/cgi/pretty_spec.rb
+++ b/spec/ruby/library/cgi/pretty_spec.rb
@@ -1,6 +1,6 @@
require_relative '../../spec_helper'
-ruby_version_is ""..."3.5" do
+ruby_version_is ""..."4.0" do
require 'cgi'
describe "CGI.pretty when passed html" do
diff --git a/spec/ruby/library/cgi/print_spec.rb b/spec/ruby/library/cgi/print_spec.rb
index 5057c280a0..f4f461c5c0 100644
--- a/spec/ruby/library/cgi/print_spec.rb
+++ b/spec/ruby/library/cgi/print_spec.rb
@@ -1,6 +1,6 @@
require_relative '../../spec_helper'
-ruby_version_is ""..."3.5" do
+ruby_version_is ""..."4.0" do
require 'cgi'
describe "CGI#print" do
diff --git a/spec/ruby/library/cgi/queryextension/accept_charset_spec.rb b/spec/ruby/library/cgi/queryextension/accept_charset_spec.rb
index 9bfc833a3b..be05f0c175 100644
--- a/spec/ruby/library/cgi/queryextension/accept_charset_spec.rb
+++ b/spec/ruby/library/cgi/queryextension/accept_charset_spec.rb
@@ -1,6 +1,6 @@
require_relative '../../../spec_helper'
-ruby_version_is ""..."3.5" do
+ruby_version_is ""..."4.0" do
require 'cgi'
describe "CGI::QueryExtension#accept_charset" do
diff --git a/spec/ruby/library/cgi/queryextension/accept_encoding_spec.rb b/spec/ruby/library/cgi/queryextension/accept_encoding_spec.rb
index f0d7f2058a..42eb4a49b5 100644
--- a/spec/ruby/library/cgi/queryextension/accept_encoding_spec.rb
+++ b/spec/ruby/library/cgi/queryextension/accept_encoding_spec.rb
@@ -1,6 +1,6 @@
require_relative '../../../spec_helper'
-ruby_version_is ""..."3.5" do
+ruby_version_is ""..."4.0" do
require 'cgi'
describe "CGI::QueryExtension#accept_encoding" do
diff --git a/spec/ruby/library/cgi/queryextension/accept_language_spec.rb b/spec/ruby/library/cgi/queryextension/accept_language_spec.rb
index e3dfcd0324..19f29c6345 100644
--- a/spec/ruby/library/cgi/queryextension/accept_language_spec.rb
+++ b/spec/ruby/library/cgi/queryextension/accept_language_spec.rb
@@ -1,6 +1,6 @@
require_relative '../../../spec_helper'
-ruby_version_is ""..."3.5" do
+ruby_version_is ""..."4.0" do
require 'cgi'
describe "CGI::QueryExtension#accept_language" do
diff --git a/spec/ruby/library/cgi/queryextension/accept_spec.rb b/spec/ruby/library/cgi/queryextension/accept_spec.rb
index 9370a885a4..dcae39a736 100644
--- a/spec/ruby/library/cgi/queryextension/accept_spec.rb
+++ b/spec/ruby/library/cgi/queryextension/accept_spec.rb
@@ -1,6 +1,6 @@
require_relative '../../../spec_helper'
-ruby_version_is ""..."3.5" do
+ruby_version_is ""..."4.0" do
require 'cgi'
describe "CGI::QueryExtension#accept" do
diff --git a/spec/ruby/library/cgi/queryextension/auth_type_spec.rb b/spec/ruby/library/cgi/queryextension/auth_type_spec.rb
index c858436037..75e9cdb27a 100644
--- a/spec/ruby/library/cgi/queryextension/auth_type_spec.rb
+++ b/spec/ruby/library/cgi/queryextension/auth_type_spec.rb
@@ -1,6 +1,6 @@
require_relative '../../../spec_helper'
-ruby_version_is ""..."3.5" do
+ruby_version_is ""..."4.0" do
require 'cgi'
describe "CGI::QueryExtension#auth_type" do
diff --git a/spec/ruby/library/cgi/queryextension/cache_control_spec.rb b/spec/ruby/library/cgi/queryextension/cache_control_spec.rb
index d42421126c..c4b727e671 100644
--- a/spec/ruby/library/cgi/queryextension/cache_control_spec.rb
+++ b/spec/ruby/library/cgi/queryextension/cache_control_spec.rb
@@ -1,6 +1,6 @@
require_relative '../../../spec_helper'
-ruby_version_is ""..."3.5" do
+ruby_version_is ""..."4.0" do
require 'cgi'
describe "CGI::QueryExtension#cache_control" do
diff --git a/spec/ruby/library/cgi/queryextension/content_length_spec.rb b/spec/ruby/library/cgi/queryextension/content_length_spec.rb
index 2e3dca6f58..bd02f3d8da 100644
--- a/spec/ruby/library/cgi/queryextension/content_length_spec.rb
+++ b/spec/ruby/library/cgi/queryextension/content_length_spec.rb
@@ -1,6 +1,6 @@
require_relative '../../../spec_helper'
-ruby_version_is ""..."3.5" do
+ruby_version_is ""..."4.0" do
require 'cgi'
describe "CGI::QueryExtension#content_length" do
@@ -17,10 +17,10 @@ ruby_version_is ""..."3.5" do
old_value = ENV['CONTENT_LENGTH']
begin
ENV['CONTENT_LENGTH'] = nil
- @cgi.content_length.should be_nil
+ @cgi.content_length.should == nil
ENV['CONTENT_LENGTH'] = "100"
- @cgi.content_length.should eql(100)
+ @cgi.content_length.should.eql?(100)
ensure
ENV['CONTENT_LENGTH'] = old_value
end
diff --git a/spec/ruby/library/cgi/queryextension/content_type_spec.rb b/spec/ruby/library/cgi/queryextension/content_type_spec.rb
index ce1be28571..d3cbdf0b14 100644
--- a/spec/ruby/library/cgi/queryextension/content_type_spec.rb
+++ b/spec/ruby/library/cgi/queryextension/content_type_spec.rb
@@ -1,6 +1,6 @@
require_relative '../../../spec_helper'
-ruby_version_is ""..."3.5" do
+ruby_version_is ""..."4.0" do
require 'cgi'
describe "CGI::QueryExtension#content_type" do
diff --git a/spec/ruby/library/cgi/queryextension/cookies_spec.rb b/spec/ruby/library/cgi/queryextension/cookies_spec.rb
index 029ad5991a..266fe0c721 100644
--- a/spec/ruby/library/cgi/queryextension/cookies_spec.rb
+++ b/spec/ruby/library/cgi/queryextension/cookies_spec.rb
@@ -1,6 +1,6 @@
require_relative '../../../spec_helper'
-ruby_version_is ""..."3.5" do
+ruby_version_is ""..."4.0" do
require 'cgi'
describe "CGI::QueryExtension#cookies" do
diff --git a/spec/ruby/library/cgi/queryextension/element_reference_spec.rb b/spec/ruby/library/cgi/queryextension/element_reference_spec.rb
index df1c372ab7..c835f385f0 100644
--- a/spec/ruby/library/cgi/queryextension/element_reference_spec.rb
+++ b/spec/ruby/library/cgi/queryextension/element_reference_spec.rb
@@ -1,6 +1,6 @@
require_relative '../../../spec_helper'
-ruby_version_is ""..."3.5" do
+ruby_version_is ""..."4.0" do
require 'cgi'
describe "CGI::QueryExtension#[]" do
@@ -24,7 +24,7 @@ ruby_version_is ""..."3.5" do
end
it "returns a String" do
- @cgi["one"].should be_kind_of(String)
+ @cgi["one"].should.is_a?(String)
end
end
end
diff --git a/spec/ruby/library/cgi/queryextension/from_spec.rb b/spec/ruby/library/cgi/queryextension/from_spec.rb
index 8d278f5318..b341e0be10 100644
--- a/spec/ruby/library/cgi/queryextension/from_spec.rb
+++ b/spec/ruby/library/cgi/queryextension/from_spec.rb
@@ -1,6 +1,6 @@
require_relative '../../../spec_helper'
-ruby_version_is ""..."3.5" do
+ruby_version_is ""..."4.0" do
require 'cgi'
describe "CGI::QueryExtension#from" do
diff --git a/spec/ruby/library/cgi/queryextension/gateway_interface_spec.rb b/spec/ruby/library/cgi/queryextension/gateway_interface_spec.rb
index d519b80e32..c82522326b 100644
--- a/spec/ruby/library/cgi/queryextension/gateway_interface_spec.rb
+++ b/spec/ruby/library/cgi/queryextension/gateway_interface_spec.rb
@@ -1,6 +1,6 @@
require_relative '../../../spec_helper'
-ruby_version_is ""..."3.5" do
+ruby_version_is ""..."4.0" do
require 'cgi'
describe "CGI::QueryExtension#gateway_interface" do
diff --git a/spec/ruby/library/cgi/queryextension/has_key_spec.rb b/spec/ruby/library/cgi/queryextension/has_key_spec.rb
index 5892ecaf77..43f7aae1b2 100644
--- a/spec/ruby/library/cgi/queryextension/has_key_spec.rb
+++ b/spec/ruby/library/cgi/queryextension/has_key_spec.rb
@@ -1,6 +1,6 @@
require_relative '../../../spec_helper'
-ruby_version_is ""..."3.5" do
+ruby_version_is ""..."4.0" do
require 'cgi'
require_relative 'shared/has_key'
diff --git a/spec/ruby/library/cgi/queryextension/host_spec.rb b/spec/ruby/library/cgi/queryextension/host_spec.rb
index 2eaf1330c0..e1047c942b 100644
--- a/spec/ruby/library/cgi/queryextension/host_spec.rb
+++ b/spec/ruby/library/cgi/queryextension/host_spec.rb
@@ -1,6 +1,6 @@
require_relative '../../../spec_helper'
-ruby_version_is ""..."3.5" do
+ruby_version_is ""..."4.0" do
require 'cgi'
describe "CGI::QueryExtension#host" do
diff --git a/spec/ruby/library/cgi/queryextension/include_spec.rb b/spec/ruby/library/cgi/queryextension/include_spec.rb
index 18520c4aaf..7275c309f9 100644
--- a/spec/ruby/library/cgi/queryextension/include_spec.rb
+++ b/spec/ruby/library/cgi/queryextension/include_spec.rb
@@ -1,6 +1,6 @@
require_relative '../../../spec_helper'
-ruby_version_is ""..."3.5" do
+ruby_version_is ""..."4.0" do
require 'cgi'
require_relative 'shared/has_key'
diff --git a/spec/ruby/library/cgi/queryextension/key_spec.rb b/spec/ruby/library/cgi/queryextension/key_spec.rb
index c8c5870eba..dc2f52fbe0 100644
--- a/spec/ruby/library/cgi/queryextension/key_spec.rb
+++ b/spec/ruby/library/cgi/queryextension/key_spec.rb
@@ -1,6 +1,6 @@
require_relative '../../../spec_helper'
-ruby_version_is ""..."3.5" do
+ruby_version_is ""..."4.0" do
require 'cgi'
require_relative 'shared/has_key'
diff --git a/spec/ruby/library/cgi/queryextension/keys_spec.rb b/spec/ruby/library/cgi/queryextension/keys_spec.rb
index 0c35404103..bb16914065 100644
--- a/spec/ruby/library/cgi/queryextension/keys_spec.rb
+++ b/spec/ruby/library/cgi/queryextension/keys_spec.rb
@@ -1,6 +1,6 @@
require_relative '../../../spec_helper'
-ruby_version_is ""..."3.5" do
+ruby_version_is ""..."4.0" do
require 'cgi'
describe "CGI::QueryExtension#keys" do
diff --git a/spec/ruby/library/cgi/queryextension/multipart_spec.rb b/spec/ruby/library/cgi/queryextension/multipart_spec.rb
index 72c8073a5a..1fa771ca1c 100644
--- a/spec/ruby/library/cgi/queryextension/multipart_spec.rb
+++ b/spec/ruby/library/cgi/queryextension/multipart_spec.rb
@@ -1,6 +1,6 @@
require_relative '../../../spec_helper'
-ruby_version_is ""..."3.5" do
+ruby_version_is ""..."4.0" do
require 'cgi'
require "stringio"
@@ -37,7 +37,7 @@ EOS
end
it "returns true if the current Request is a multipart request" do
- @cgi.multipart?.should be_true
+ @cgi.multipart?.should == true
end
end
end
diff --git a/spec/ruby/library/cgi/queryextension/negotiate_spec.rb b/spec/ruby/library/cgi/queryextension/negotiate_spec.rb
index c159c6cfe2..4083e6a8cd 100644
--- a/spec/ruby/library/cgi/queryextension/negotiate_spec.rb
+++ b/spec/ruby/library/cgi/queryextension/negotiate_spec.rb
@@ -1,6 +1,6 @@
require_relative '../../../spec_helper'
-ruby_version_is ""..."3.5" do
+ruby_version_is ""..."4.0" do
require 'cgi'
describe "CGI::QueryExtension#negotiate" do
diff --git a/spec/ruby/library/cgi/queryextension/params_spec.rb b/spec/ruby/library/cgi/queryextension/params_spec.rb
index e8b447f227..938028ea14 100644
--- a/spec/ruby/library/cgi/queryextension/params_spec.rb
+++ b/spec/ruby/library/cgi/queryextension/params_spec.rb
@@ -1,6 +1,6 @@
require_relative '../../../spec_helper'
-ruby_version_is ""..."3.5" do
+ruby_version_is ""..."4.0" do
require 'cgi'
describe "CGI::QueryExtension#params" do
diff --git a/spec/ruby/library/cgi/queryextension/path_info_spec.rb b/spec/ruby/library/cgi/queryextension/path_info_spec.rb
index 9054f1cfd3..9b7834c514 100644
--- a/spec/ruby/library/cgi/queryextension/path_info_spec.rb
+++ b/spec/ruby/library/cgi/queryextension/path_info_spec.rb
@@ -1,6 +1,6 @@
require_relative '../../../spec_helper'
-ruby_version_is ""..."3.5" do
+ruby_version_is ""..."4.0" do
require 'cgi'
describe "CGI::QueryExtension#path_info" do
diff --git a/spec/ruby/library/cgi/queryextension/path_translated_spec.rb b/spec/ruby/library/cgi/queryextension/path_translated_spec.rb
index 4b17f6c01b..a773aaafdb 100644
--- a/spec/ruby/library/cgi/queryextension/path_translated_spec.rb
+++ b/spec/ruby/library/cgi/queryextension/path_translated_spec.rb
@@ -1,6 +1,6 @@
require_relative '../../../spec_helper'
-ruby_version_is ""..."3.5" do
+ruby_version_is ""..."4.0" do
require 'cgi'
describe "CGI::QueryExtension#path_translated" do
diff --git a/spec/ruby/library/cgi/queryextension/pragma_spec.rb b/spec/ruby/library/cgi/queryextension/pragma_spec.rb
index c6a9c5b973..be384182a5 100644
--- a/spec/ruby/library/cgi/queryextension/pragma_spec.rb
+++ b/spec/ruby/library/cgi/queryextension/pragma_spec.rb
@@ -1,6 +1,6 @@
require_relative '../../../spec_helper'
-ruby_version_is ""..."3.5" do
+ruby_version_is ""..."4.0" do
require 'cgi'
describe "CGI::QueryExtension#pragma" do
diff --git a/spec/ruby/library/cgi/queryextension/query_string_spec.rb b/spec/ruby/library/cgi/queryextension/query_string_spec.rb
index ef3cb9c8fb..64fbeaea10 100644
--- a/spec/ruby/library/cgi/queryextension/query_string_spec.rb
+++ b/spec/ruby/library/cgi/queryextension/query_string_spec.rb
@@ -1,6 +1,6 @@
require_relative '../../../spec_helper'
-ruby_version_is ""..."3.5" do
+ruby_version_is ""..."4.0" do
require 'cgi'
describe "CGI::QueryExtension#query_string" do
diff --git a/spec/ruby/library/cgi/queryextension/raw_cookie2_spec.rb b/spec/ruby/library/cgi/queryextension/raw_cookie2_spec.rb
index 07ef00e8c5..30d314aca1 100644
--- a/spec/ruby/library/cgi/queryextension/raw_cookie2_spec.rb
+++ b/spec/ruby/library/cgi/queryextension/raw_cookie2_spec.rb
@@ -1,6 +1,6 @@
require_relative '../../../spec_helper'
-ruby_version_is ""..."3.5" do
+ruby_version_is ""..."4.0" do
require 'cgi'
describe "CGI::QueryExtension#raw_cookie2" do
diff --git a/spec/ruby/library/cgi/queryextension/raw_cookie_spec.rb b/spec/ruby/library/cgi/queryextension/raw_cookie_spec.rb
index f1ebb8ad82..affa504b39 100644
--- a/spec/ruby/library/cgi/queryextension/raw_cookie_spec.rb
+++ b/spec/ruby/library/cgi/queryextension/raw_cookie_spec.rb
@@ -1,6 +1,6 @@
require_relative '../../../spec_helper'
-ruby_version_is ""..."3.5" do
+ruby_version_is ""..."4.0" do
require 'cgi'
describe "CGI::QueryExtension#raw_cookie" do
diff --git a/spec/ruby/library/cgi/queryextension/referer_spec.rb b/spec/ruby/library/cgi/queryextension/referer_spec.rb
index 737253eac9..53fc19ddd0 100644
--- a/spec/ruby/library/cgi/queryextension/referer_spec.rb
+++ b/spec/ruby/library/cgi/queryextension/referer_spec.rb
@@ -1,6 +1,6 @@
require_relative '../../../spec_helper'
-ruby_version_is ""..."3.5" do
+ruby_version_is ""..."4.0" do
require 'cgi'
describe "CGI::QueryExtension#referer" do
diff --git a/spec/ruby/library/cgi/queryextension/remote_addr_spec.rb b/spec/ruby/library/cgi/queryextension/remote_addr_spec.rb
index e2cc696ae2..7b5addc2d5 100644
--- a/spec/ruby/library/cgi/queryextension/remote_addr_spec.rb
+++ b/spec/ruby/library/cgi/queryextension/remote_addr_spec.rb
@@ -1,6 +1,6 @@
require_relative '../../../spec_helper'
-ruby_version_is ""..."3.5" do
+ruby_version_is ""..."4.0" do
require 'cgi'
describe "CGI::QueryExtension#remote_addr" do
diff --git a/spec/ruby/library/cgi/queryextension/remote_host_spec.rb b/spec/ruby/library/cgi/queryextension/remote_host_spec.rb
index c4db9e4ffe..2dfe59ca38 100644
--- a/spec/ruby/library/cgi/queryextension/remote_host_spec.rb
+++ b/spec/ruby/library/cgi/queryextension/remote_host_spec.rb
@@ -1,6 +1,6 @@
require_relative '../../../spec_helper'
-ruby_version_is ""..."3.5" do
+ruby_version_is ""..."4.0" do
require 'cgi'
describe "CGI::QueryExtension#remote_host" do
diff --git a/spec/ruby/library/cgi/queryextension/remote_ident_spec.rb b/spec/ruby/library/cgi/queryextension/remote_ident_spec.rb
index d507b7d7be..bb05fc7942 100644
--- a/spec/ruby/library/cgi/queryextension/remote_ident_spec.rb
+++ b/spec/ruby/library/cgi/queryextension/remote_ident_spec.rb
@@ -1,6 +1,6 @@
require_relative '../../../spec_helper'
-ruby_version_is ""..."3.5" do
+ruby_version_is ""..."4.0" do
require 'cgi'
describe "CGI::QueryExtension#remote_ident" do
diff --git a/spec/ruby/library/cgi/queryextension/remote_user_spec.rb b/spec/ruby/library/cgi/queryextension/remote_user_spec.rb
index ceee410797..29856302ab 100644
--- a/spec/ruby/library/cgi/queryextension/remote_user_spec.rb
+++ b/spec/ruby/library/cgi/queryextension/remote_user_spec.rb
@@ -1,6 +1,6 @@
require_relative '../../../spec_helper'
-ruby_version_is ""..."3.5" do
+ruby_version_is ""..."4.0" do
require 'cgi'
describe "CGI::QueryExtension#remote_user" do
diff --git a/spec/ruby/library/cgi/queryextension/request_method_spec.rb b/spec/ruby/library/cgi/queryextension/request_method_spec.rb
index b540280261..7331b134d2 100644
--- a/spec/ruby/library/cgi/queryextension/request_method_spec.rb
+++ b/spec/ruby/library/cgi/queryextension/request_method_spec.rb
@@ -1,6 +1,6 @@
require_relative '../../../spec_helper'
-ruby_version_is ""..."3.5" do
+ruby_version_is ""..."4.0" do
require 'cgi'
describe "CGI::QueryExtension#request_method" do
diff --git a/spec/ruby/library/cgi/queryextension/script_name_spec.rb b/spec/ruby/library/cgi/queryextension/script_name_spec.rb
index 49a7847eff..4b359a545f 100644
--- a/spec/ruby/library/cgi/queryextension/script_name_spec.rb
+++ b/spec/ruby/library/cgi/queryextension/script_name_spec.rb
@@ -1,6 +1,6 @@
require_relative '../../../spec_helper'
-ruby_version_is ""..."3.5" do
+ruby_version_is ""..."4.0" do
require 'cgi'
describe "CGI::QueryExtension#script_name" do
diff --git a/spec/ruby/library/cgi/queryextension/server_name_spec.rb b/spec/ruby/library/cgi/queryextension/server_name_spec.rb
index ee5d754ad3..c1f7fb4c54 100644
--- a/spec/ruby/library/cgi/queryextension/server_name_spec.rb
+++ b/spec/ruby/library/cgi/queryextension/server_name_spec.rb
@@ -1,6 +1,6 @@
require_relative '../../../spec_helper'
-ruby_version_is ""..."3.5" do
+ruby_version_is ""..."4.0" do
require 'cgi'
describe "CGI::QueryExtension#server_name" do
diff --git a/spec/ruby/library/cgi/queryextension/server_port_spec.rb b/spec/ruby/library/cgi/queryextension/server_port_spec.rb
index c4f8df78cf..1c88d3225d 100644
--- a/spec/ruby/library/cgi/queryextension/server_port_spec.rb
+++ b/spec/ruby/library/cgi/queryextension/server_port_spec.rb
@@ -1,6 +1,6 @@
require_relative '../../../spec_helper'
-ruby_version_is ""..."3.5" do
+ruby_version_is ""..."4.0" do
require 'cgi'
describe "CGI::QueryExtension#server_port" do
@@ -17,10 +17,10 @@ ruby_version_is ""..."3.5" do
old_value = ENV['SERVER_PORT']
begin
ENV['SERVER_PORT'] = nil
- @cgi.server_port.should be_nil
+ @cgi.server_port.should == nil
ENV['SERVER_PORT'] = "3000"
- @cgi.server_port.should eql(3000)
+ @cgi.server_port.should.eql?(3000)
ensure
ENV['SERVER_PORT'] = old_value
end
diff --git a/spec/ruby/library/cgi/queryextension/server_protocol_spec.rb b/spec/ruby/library/cgi/queryextension/server_protocol_spec.rb
index 35d3b8add1..fdbcc2108f 100644
--- a/spec/ruby/library/cgi/queryextension/server_protocol_spec.rb
+++ b/spec/ruby/library/cgi/queryextension/server_protocol_spec.rb
@@ -1,6 +1,6 @@
require_relative '../../../spec_helper'
-ruby_version_is ""..."3.5" do
+ruby_version_is ""..."4.0" do
require 'cgi'
describe "CGI::QueryExtension#server_protocol" do
diff --git a/spec/ruby/library/cgi/queryextension/server_software_spec.rb b/spec/ruby/library/cgi/queryextension/server_software_spec.rb
index d4fcceb379..c5811a2268 100644
--- a/spec/ruby/library/cgi/queryextension/server_software_spec.rb
+++ b/spec/ruby/library/cgi/queryextension/server_software_spec.rb
@@ -1,6 +1,6 @@
require_relative '../../../spec_helper'
-ruby_version_is ""..."3.5" do
+ruby_version_is ""..."4.0" do
require 'cgi'
describe "CGI::QueryExtension#server_software" do
diff --git a/spec/ruby/library/cgi/queryextension/shared/has_key.rb b/spec/ruby/library/cgi/queryextension/shared/has_key.rb
index cfac5865fa..6231cb548e 100644
--- a/spec/ruby/library/cgi/queryextension/shared/has_key.rb
+++ b/spec/ruby/library/cgi/queryextension/shared/has_key.rb
@@ -12,8 +12,8 @@ describe :cgi_query_extension_has_key_p, shared: true do
end
it "returns true when the passed key exists in the HTTP Query" do
- @cgi.send(@method, "one").should be_true
- @cgi.send(@method, "two").should be_true
- @cgi.send(@method, "three").should be_false
+ @cgi.send(@method, "one").should == true
+ @cgi.send(@method, "two").should == true
+ @cgi.send(@method, "three").should == false
end
end
diff --git a/spec/ruby/library/cgi/queryextension/user_agent_spec.rb b/spec/ruby/library/cgi/queryextension/user_agent_spec.rb
index 070a779123..3240352ef6 100644
--- a/spec/ruby/library/cgi/queryextension/user_agent_spec.rb
+++ b/spec/ruby/library/cgi/queryextension/user_agent_spec.rb
@@ -1,6 +1,6 @@
require_relative '../../../spec_helper'
-ruby_version_is ""..."3.5" do
+ruby_version_is ""..."4.0" do
require 'cgi'
describe "CGI::QueryExtension#user_agent" do
diff --git a/spec/ruby/library/cgi/rfc1123_date_spec.rb b/spec/ruby/library/cgi/rfc1123_date_spec.rb
index 2641b40e94..636185f22c 100644
--- a/spec/ruby/library/cgi/rfc1123_date_spec.rb
+++ b/spec/ruby/library/cgi/rfc1123_date_spec.rb
@@ -1,6 +1,6 @@
require_relative '../../spec_helper'
-ruby_version_is ""..."3.5" do
+ruby_version_is ""..."4.0" do
require 'cgi'
describe "CGI.rfc1123_date when passed Time" do
diff --git a/spec/ruby/library/cgi/shared/http_header.rb b/spec/ruby/library/cgi/shared/http_header.rb
index b225b5925e..e739fed538 100644
--- a/spec/ruby/library/cgi/shared/http_header.rb
+++ b/spec/ruby/library/cgi/shared/http_header.rb
@@ -63,11 +63,11 @@ describe :cgi_http_header, shared: true do
header.should == "Content-Type: text/plain; charset=UTF-8\r\n\r\n"
header = @cgi.send(@method, "nph" => true)
- header.should include("HTTP/1.0 200 OK\r\n")
- header.should include("Date: ")
- header.should include("Server: ")
- header.should include("Connection: close\r\n")
- header.should include("Content-Type: text/html\r\n")
+ header.should.include?("HTTP/1.0 200 OK\r\n")
+ header.should.include?("Date: ")
+ header.should.include?("Server: ")
+ header.should.include?("Connection: close\r\n")
+ header.should.include?("Content-Type: text/html\r\n")
header = @cgi.send(@method, "status" => "OK")
header.should == "Status: 200 OK\r\nContent-Type: text/html\r\n\r\n"
diff --git a/spec/ruby/library/cgi/unescapeElement_spec.rb b/spec/ruby/library/cgi/unescapeElement_spec.rb
index af2fa8a47d..db83f0d2fb 100644
--- a/spec/ruby/library/cgi/unescapeElement_spec.rb
+++ b/spec/ruby/library/cgi/unescapeElement_spec.rb
@@ -1,9 +1,9 @@
require_relative '../../spec_helper'
-ruby_version_is ""..."3.5" do
+ruby_version_is ""..."4.0" do
require 'cgi'
end
-ruby_version_is "3.5" do
+ruby_version_is "4.0" do
require 'cgi/escape'
end
diff --git a/spec/ruby/library/cgi/unescapeURIComponent_spec.rb b/spec/ruby/library/cgi/unescapeURIComponent_spec.rb
new file mode 100644
index 0000000000..e0bf4b70e0
--- /dev/null
+++ b/spec/ruby/library/cgi/unescapeURIComponent_spec.rb
@@ -0,0 +1,128 @@
+require_relative '../../spec_helper'
+
+ruby_version_is ""..."4.0" do
+ require 'cgi'
+end
+ruby_version_is "4.0" do
+ require 'cgi/escape'
+end
+
+describe "CGI.unescapeURIComponent" do
+ it "decodes any percent-encoded octets to their corresponding bytes according to RFC 3986" do
+ string = (0x00..0xff).map { |i| "%%%02x" % i }.join
+ expected = (0x00..0xff).map { |i| i.chr }.join.force_encoding(Encoding::UTF_8)
+ CGI.unescapeURIComponent(string).should == expected
+ end
+
+ it "disregards case of characters in a percent-encoding triplet" do
+ CGI.unescapeURIComponent("%CE%B2abc").should == "βabc"
+ CGI.unescapeURIComponent("%ce%b2ABC").should == "βABC"
+ end
+
+ it "leaves any non-percent-encoded characters as-is" do
+ string = "ABCDEFGHIJKLMNOPQRSTUVWXYZ:/?#[]@!$&'()*+,;=\t\x0D\xFFβᛉ▒90%"
+ decoded = CGI.unescapeURIComponent(string)
+ decoded.should == string
+ string.should_not.equal?(decoded)
+ end
+
+ it "leaves sequences which can't be a percent-encoded octet as-is" do
+ string = "%AZ%B"
+ decoded = CGI.unescapeURIComponent(string)
+ decoded.should == string
+ string.should_not.equal?(decoded)
+ end
+
+ it "creates a String with the specified target Encoding" do
+ string = CGI.unescapeURIComponent("%D2%3C%3CABC", Encoding::ISO_8859_1)
+ string.encoding.should == Encoding::ISO_8859_1
+ string.should == "Ã’<<ABC".encode("ISO-8859-1")
+ end
+
+ it "accepts a string name of an Encoding" do
+ CGI.unescapeURIComponent("%D2%3C%3CABC", "ISO-8859-1").should == "Ã’<<ABC".encode("ISO-8859-1")
+ end
+
+ it "raises ArgumentError if specified encoding is unknown" do
+ -> { CGI.unescapeURIComponent("ABC", "ISO-JOKE-1") }.should.raise(ArgumentError, "unknown encoding name - ISO-JOKE-1")
+ end
+
+ ruby_version_is ""..."4.0" do
+ it "uses CGI.accept_charset as the default target encoding" do
+ original_charset = CGI.accept_charset
+ CGI.accept_charset = "ISO-8859-1"
+ decoded = CGI.unescapeURIComponent("%D2%3C%3CABC")
+ decoded.should == "Ã’<<ABC".encode("ISO-8859-1")
+ decoded.encoding.should == Encoding::ISO_8859_1
+ ensure
+ CGI.accept_charset = original_charset
+ end
+
+ it "has CGI.accept_charset as UTF-8 by default" do
+ decoded = CGI.unescapeURIComponent("%CE%B2ABC")
+ decoded.should == "βABC"
+ decoded.encoding.should == Encoding::UTF_8
+ end
+ end
+
+ ruby_version_is "4.0" do
+ # "cgi/escape" does not have methods to access @@accept_charset.
+ # Full "cgi" gem provides them, allowing to possibly change it.
+ it "uses CGI's @@accept_charset as the default target encoding" do
+ original_charset = CGI.class_variable_get(:@@accept_charset)
+ CGI.class_variable_set(:@@accept_charset, "ISO-8859-1")
+ decoded = CGI.unescapeURIComponent("%D2%3C%3CABC")
+ decoded.should == "Ã’<<ABC".encode("ISO-8859-1")
+ decoded.encoding.should == Encoding::ISO_8859_1
+ ensure
+ CGI.class_variable_set(:@@accept_charset, original_charset)
+ end
+
+ it "has CGI's @@accept_charset as UTF-8 by default" do
+ decoded = CGI.unescapeURIComponent("%CE%B2ABC")
+ decoded.should == "βABC"
+ decoded.encoding.should == Encoding::UTF_8
+ end
+ end
+
+ context "when source string specifies octets invalid in target encoding" do
+ it "uses source string's encoding" do
+ string = "%A2%A6%A3".encode(Encoding::SHIFT_JIS)
+ decoded = CGI.unescapeURIComponent(string, Encoding::US_ASCII)
+ decoded.encoding.should == Encoding::SHIFT_JIS
+ decoded.should == "「ヲ」".encode(Encoding::SHIFT_JIS)
+ decoded.valid_encoding?.should == true
+ end
+
+ it "uses source string's encoding even if it's also invalid" do
+ string = "%FF".encode(Encoding::US_ASCII)
+ decoded = CGI.unescapeURIComponent(string, Encoding::SHIFT_JIS)
+ decoded.encoding.should == Encoding::US_ASCII
+ decoded.should == "\xFF".dup.force_encoding(Encoding::US_ASCII)
+ decoded.valid_encoding?.should == false
+ end
+ end
+
+ it "decodes an empty string as an empty string with target encoding" do
+ string = "".encode(Encoding::BINARY)
+ decoded = CGI.unescapeURIComponent(string, "UTF-8")
+ decoded.should == ""
+ decoded.encoding.should == Encoding::UTF_8
+ string.should_not.equal?(decoded)
+ end
+
+ it "raises a TypeError with nil" do
+ -> {
+ CGI.unescapeURIComponent(nil)
+ }.should.raise(TypeError, "no implicit conversion of nil into String")
+ end
+
+ it "uses implicit type conversion to String" do
+ object = Object.new
+ def object.to_str
+ "a%20b"
+ end
+
+ CGI.unescapeURIComponent(object).should == "a b"
+ end
+end
diff --git a/spec/ruby/library/cgi/unescape_spec.rb b/spec/ruby/library/cgi/unescape_spec.rb
index e750c72921..aa731b9367 100644
--- a/spec/ruby/library/cgi/unescape_spec.rb
+++ b/spec/ruby/library/cgi/unescape_spec.rb
@@ -1,10 +1,10 @@
# -*- encoding: utf-8 -*-
require_relative '../../spec_helper'
-ruby_version_is ""..."3.5" do
+ruby_version_is ""..."4.0" do
require 'cgi'
end
-ruby_version_is "3.5" do
+ruby_version_is "4.0" do
require 'cgi/escape'
end
diff --git a/spec/ruby/library/coverage/result_spec.rb b/spec/ruby/library/coverage/result_spec.rb
index 0101eb6a64..2e7d598bb8 100644
--- a/spec/ruby/library/coverage/result_spec.rb
+++ b/spec/ruby/library/coverage/result_spec.rb
@@ -80,7 +80,7 @@ describe 'Coverage.result' do
Coverage.result
-> {
Coverage.result
- }.should raise_error(RuntimeError, 'coverage measurement is not enabled')
+ }.should.raise(RuntimeError, 'coverage measurement is not enabled')
end
it 'second run should give same result' do
@@ -108,7 +108,7 @@ describe 'Coverage.result' do
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)
+ Coverage.result.should_not.include?(@config_file)
end
it 'returns the correct results when eval coverage is enabled' do
diff --git a/spec/ruby/library/coverage/start_spec.rb b/spec/ruby/library/coverage/start_spec.rb
index c921b85401..11777347a2 100644
--- a/spec/ruby/library/coverage/start_spec.rb
+++ b/spec/ruby/library/coverage/start_spec.rb
@@ -24,7 +24,7 @@ describe 'Coverage.start' do
-> {
Coverage.start
- }.should raise_error(RuntimeError, 'coverage measurement is already setup')
+ }.should.raise(RuntimeError, 'coverage measurement is already setup')
end
it "accepts :all optional argument" do
@@ -65,13 +65,13 @@ describe 'Coverage.start' do
it "expects a Hash if not passed :all" do
-> {
Coverage.start(42)
- }.should raise_error(TypeError, "no implicit conversion of Integer into Hash")
+ }.should.raise(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")
+ }.should.raise(RuntimeError, "cannot enable lines and oneshot_lines simultaneously")
end
it "enables the coverage measurement if passed options with `false` value" do
diff --git a/spec/ruby/library/coverage/supported_spec.rb b/spec/ruby/library/coverage/supported_spec.rb
index 9226548c1f..fcf8a76d79 100644
--- a/spec/ruby/library/coverage/supported_spec.rb
+++ b/spec/ruby/library/coverage/supported_spec.rb
@@ -17,14 +17,14 @@ describe "Coverage.supported?" do
it "raise TypeError if argument is not Symbol" do
-> {
Coverage.supported?("lines")
- }.should raise_error(TypeError, "wrong argument type String (expected Symbol)")
+ }.should.raise(TypeError, "wrong argument type String (expected Symbol)")
-> {
Coverage.supported?([])
- }.should raise_error(TypeError, "wrong argument type Array (expected Symbol)")
+ }.should.raise(TypeError, "wrong argument type Array (expected Symbol)")
-> {
Coverage.supported?(1)
- }.should raise_error(TypeError, "wrong argument type Integer (expected Symbol)")
+ }.should.raise(TypeError, "wrong argument type Integer (expected Symbol)")
end
end
diff --git a/spec/ruby/library/csv/generate_spec.rb b/spec/ruby/library/csv/generate_spec.rb
index b45e2eb95b..62e19aa6e4 100644
--- a/spec/ruby/library/csv/generate_spec.rb
+++ b/spec/ruby/library/csv/generate_spec.rb
@@ -26,7 +26,7 @@ describe "CSV.generate" do
csv.add_row [1, 2, 3]
csv << [4, 5, 6]
end
- csv_str.should equal str
+ csv_str.should.equal? str
str.should == "1,2,3\n4,5,6\n"
end
end
diff --git a/spec/ruby/library/csv/parse_spec.rb b/spec/ruby/library/csv/parse_spec.rb
index ef5d4ea3ca..7000f03cda 100644
--- a/spec/ruby/library/csv/parse_spec.rb
+++ b/spec/ruby/library/csv/parse_spec.rb
@@ -5,7 +5,7 @@ describe "CSV.parse" do
it "parses '' into []" do
result = CSV.parse ''
- result.should be_kind_of(Array)
+ result.should.is_a?(Array)
result.should == []
end
@@ -82,7 +82,7 @@ describe "CSV.parse" do
it "raises CSV::MalformedCSVError exception if input is illegal" do
-> {
CSV.parse('"quoted" field')
- }.should raise_error(CSV::MalformedCSVError)
+ }.should.raise(CSV::MalformedCSVError)
end
it "handles illegal input with the liberal_parsing option" do
diff --git a/spec/ruby/library/csv/readlines_spec.rb b/spec/ruby/library/csv/readlines_spec.rb
index 14dea34381..624f906489 100644
--- a/spec/ruby/library/csv/readlines_spec.rb
+++ b/spec/ruby/library/csv/readlines_spec.rb
@@ -23,7 +23,7 @@ describe "CSV#readlines" do
it "raises CSV::MalformedCSVError exception if input is illegal" do
csv = CSV.new('"quoted" field')
- -> { csv.readlines }.should raise_error(CSV::MalformedCSVError)
+ -> { csv.readlines }.should.raise(CSV::MalformedCSVError)
end
it "handles illegal input with the liberal_parsing option" do
diff --git a/spec/ruby/library/date/add_month_spec.rb b/spec/ruby/library/date/add_month_spec.rb
index 40833f6487..ab802ea97a 100644
--- a/spec/ruby/library/date/add_month_spec.rb
+++ b/spec/ruby/library/date/add_month_spec.rb
@@ -21,18 +21,18 @@ describe "Date#>>" do
end
it "raise a TypeError when passed a Symbol" do
- -> { Date.civil(2007,2,27) >> :hello }.should raise_error(TypeError)
+ -> { Date.civil(2007,2,27) >> :hello }.should.raise(TypeError)
end
it "raise a TypeError when passed a String" do
- -> { Date.civil(2007,2,27) >> "hello" }.should raise_error(TypeError)
+ -> { Date.civil(2007,2,27) >> "hello" }.should.raise(TypeError)
end
it "raise a TypeError when passed a Date" do
- -> { Date.civil(2007,2,27) >> Date.new }.should raise_error(TypeError)
+ -> { Date.civil(2007,2,27) >> Date.new }.should.raise(TypeError)
end
it "raise a TypeError when passed an Object" do
- -> { Date.civil(2007,2,27) >> Object.new }.should raise_error(TypeError)
+ -> { Date.civil(2007,2,27) >> Object.new }.should.raise(TypeError)
end
end
diff --git a/spec/ruby/library/date/add_spec.rb b/spec/ruby/library/date/add_spec.rb
index 2b9cc62023..5e368decdc 100644
--- a/spec/ruby/library/date/add_spec.rb
+++ b/spec/ruby/library/date/add_spec.rb
@@ -13,18 +13,18 @@ describe "Date#+" do
end
it "raises a TypeError when passed a Symbol" do
- -> { Date.civil(2007,2,27) + :hello }.should raise_error(TypeError)
+ -> { Date.civil(2007,2,27) + :hello }.should.raise(TypeError)
end
it "raises a TypeError when passed a String" do
- -> { Date.civil(2007,2,27) + "hello" }.should raise_error(TypeError)
+ -> { Date.civil(2007,2,27) + "hello" }.should.raise(TypeError)
end
it "raises a TypeError when passed a Date" do
- -> { Date.civil(2007,2,27) + Date.new }.should raise_error(TypeError)
+ -> { Date.civil(2007,2,27) + Date.new }.should.raise(TypeError)
end
it "raises a TypeError when passed an Object" do
- -> { Date.civil(2007,2,27) + Object.new }.should raise_error(TypeError)
+ -> { Date.civil(2007,2,27) + Object.new }.should.raise(TypeError)
end
end
diff --git a/spec/ruby/library/date/asctime_spec.rb b/spec/ruby/library/date/asctime_spec.rb
index 67d158cc01..e268ffe098 100644
--- a/spec/ruby/library/date/asctime_spec.rb
+++ b/spec/ruby/library/date/asctime_spec.rb
@@ -2,5 +2,8 @@ require_relative '../../spec_helper'
require 'date'
describe "Date#asctime" do
- it "needs to be reviewed for spec completeness"
+ it "returns a canonical string representation of date" do
+ d = Date.today
+ d.asctime.should == d.strftime("%a %b %e %H:%M:%S %Y")
+ end
end
diff --git a/spec/ruby/library/date/commercial_spec.rb b/spec/ruby/library/date/commercial_spec.rb
index d7fc34d74a..8e2df79b90 100644
--- a/spec/ruby/library/date/commercial_spec.rb
+++ b/spec/ruby/library/date/commercial_spec.rb
@@ -1,12 +1,5 @@
require 'date'
require_relative '../../spec_helper'
-require_relative 'shared/commercial'
-
-describe "Date#commercial" do
-
- it_behaves_like :date_commercial, :commercial
-
-end
# reference:
# October 1582 (the Gregorian calendar, Civil Date)
@@ -15,3 +8,42 @@ end
# 17 18 19 20 21 22 23
# 24 25 26 27 28 29 30
# 31
+describe "Date.commercial" do
+ it "creates a Date for Julian Day Number day 0 by default" do
+ d = Date.commercial
+ d.year.should == -4712
+ d.month.should == 1
+ d.day.should == 1
+ end
+
+ it "creates a Date for the monday in the year and week given" do
+ d = Date.commercial(2000, 1)
+ d.year.should == 2000
+ d.month.should == 1
+ d.day.should == 3
+ d.cwday.should == 1
+ end
+
+ it "creates a Date for the correct day given the year, week and day number" do
+ d = Date.commercial(2004, 1, 1)
+ d.year.should == 2003
+ d.month.should == 12
+ d.day.should == 29
+ d.cwday.should == 1
+ d.cweek.should == 1
+ d.cwyear.should == 2004
+ end
+
+ it "creates only Date objects for valid weeks" do
+ -> { Date.commercial(2004, 53, 1) }.should_not.raise(ArgumentError)
+ -> { Date.commercial(2004, 53, 0) }.should.raise(ArgumentError)
+ -> { Date.commercial(2004, 53, 8) }.should.raise(ArgumentError)
+ -> { Date.commercial(2004, 54, 1) }.should.raise(ArgumentError)
+ -> { Date.commercial(2004, 0, 1) }.should.raise(ArgumentError)
+
+ -> { Date.commercial(2003, 52, 1) }.should_not.raise(ArgumentError)
+ -> { Date.commercial(2003, 53, 1) }.should.raise(ArgumentError)
+ -> { Date.commercial(2003, 52, 0) }.should.raise(ArgumentError)
+ -> { Date.commercial(2003, 52, 8) }.should.raise(ArgumentError)
+ end
+end
diff --git a/spec/ruby/library/date/constants_spec.rb b/spec/ruby/library/date/constants_spec.rb
index 1d18dd1b0c..3494b0c296 100644
--- a/spec/ruby/library/date/constants_spec.rb
+++ b/spec/ruby/library/date/constants_spec.rb
@@ -36,11 +36,11 @@ describe "Date constants" do
[Date::MONTHNAMES, Date::DAYNAMES, Date::ABBR_MONTHNAMES, Date::ABBR_DAYNAMES].each do |ary|
-> {
ary << "Unknown"
- }.should raise_error(FrozenError, /frozen/)
+ }.should.raise(FrozenError, /frozen/)
ary.compact.each do |name|
-> {
name << "modified"
- }.should raise_error(FrozenError, /frozen/)
+ }.should.raise(FrozenError, /frozen/)
end
end
end
diff --git a/spec/ruby/library/date/ctime_spec.rb b/spec/ruby/library/date/ctime_spec.rb
index 3faa7c6380..330076a735 100644
--- a/spec/ruby/library/date/ctime_spec.rb
+++ b/spec/ruby/library/date/ctime_spec.rb
@@ -2,5 +2,7 @@ require_relative '../../spec_helper'
require 'date'
describe "Date#ctime" do
- it "needs to be reviewed for spec completeness"
+ it "is an alias of Date#asctime" do
+ Date.instance_method(:ctime).should == Date.instance_method(:asctime)
+ end
end
diff --git a/spec/ruby/library/date/deconstruct_keys_spec.rb b/spec/ruby/library/date/deconstruct_keys_spec.rb
index b9dd6b8816..1fa1e70250 100644
--- a/spec/ruby/library/date/deconstruct_keys_spec.rb
+++ b/spec/ruby/library/date/deconstruct_keys_spec.rb
@@ -16,16 +16,16 @@ describe "Date#deconstruct_keys" do
it "requires one argument" do
-> {
Date.new(2022, 10, 5).deconstruct_keys
- }.should raise_error(ArgumentError)
+ }.should.raise(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)")
+ -> { d.deconstruct_keys(1) }.should.raise(TypeError, "wrong argument type Integer (expected Array or nil)")
+ -> { d.deconstruct_keys("asd") }.should.raise(TypeError, "wrong argument type String (expected Array or nil)")
+ -> { d.deconstruct_keys(:x) }.should.raise(TypeError, "wrong argument type Symbol (expected Array or nil)")
+ -> { d.deconstruct_keys({}) }.should.raise(TypeError, "wrong argument type Hash (expected Array or nil)")
end
it "returns {} when passed []" do
diff --git a/spec/ruby/library/date/eql_spec.rb b/spec/ruby/library/date/eql_spec.rb
index a1819cae3a..79fabc47f4 100644
--- a/spec/ruby/library/date/eql_spec.rb
+++ b/spec/ruby/library/date/eql_spec.rb
@@ -3,10 +3,10 @@ require 'date'
describe "Date#eql?" do
it "returns true if self is equal to another date" do
- Date.civil(2007, 10, 11).eql?(Date.civil(2007, 10, 11)).should be_true
+ Date.civil(2007, 10, 11).eql?(Date.civil(2007, 10, 11)).should == true
end
it "returns false if self is not equal to another date" do
- Date.civil(2007, 10, 11).eql?(Date.civil(2007, 10, 12)).should be_false
+ Date.civil(2007, 10, 11).eql?(Date.civil(2007, 10, 12)).should == false
end
end
diff --git a/spec/ruby/library/date/friday_spec.rb b/spec/ruby/library/date/friday_spec.rb
index 3dc040fabe..62f050346e 100644
--- a/spec/ruby/library/date/friday_spec.rb
+++ b/spec/ruby/library/date/friday_spec.rb
@@ -3,10 +3,10 @@ require 'date'
describe "Date#friday?" do
it "should be friday" do
- Date.new(2000, 1, 7).friday?.should be_true
+ Date.new(2000, 1, 7).friday?.should == true
end
it "should not be friday" do
- Date.new(2000, 1, 8).friday?.should be_false
+ Date.new(2000, 1, 8).friday?.should == false
end
end
diff --git a/spec/ruby/library/date/gregorian_leap_spec.rb b/spec/ruby/library/date/gregorian_leap_spec.rb
index c3d25cf90f..c27890faf4 100644
--- a/spec/ruby/library/date/gregorian_leap_spec.rb
+++ b/spec/ruby/library/date/gregorian_leap_spec.rb
@@ -3,13 +3,13 @@ require 'date'
describe "Date#gregorian_leap?" do
it "returns true if a year is a leap year in the Gregorian calendar" do
- Date.gregorian_leap?(2000).should be_true
- Date.gregorian_leap?(2004).should be_true
+ Date.gregorian_leap?(2000).should == true
+ Date.gregorian_leap?(2004).should == true
end
it "returns false if a year is not a leap year in the Gregorian calendar" do
- Date.gregorian_leap?(1900).should be_false
- Date.gregorian_leap?(1999).should be_false
- Date.gregorian_leap?(2002).should be_false
+ Date.gregorian_leap?(1900).should == false
+ Date.gregorian_leap?(1999).should == false
+ Date.gregorian_leap?(2002).should == false
end
end
diff --git a/spec/ruby/library/date/gregorian_spec.rb b/spec/ruby/library/date/gregorian_spec.rb
index ea7ece2ade..bbda13af08 100644
--- a/spec/ruby/library/date/gregorian_spec.rb
+++ b/spec/ruby/library/date/gregorian_spec.rb
@@ -4,13 +4,13 @@ require 'date'
describe "Date#gregorian?" do
it "marks a day before the calendar reform as Julian" do
- Date.civil(1007, 2, 27).gregorian?.should be_false
- Date.civil(1907, 2, 27, Date.civil(1930, 1, 1).jd).gregorian?.should be_false
+ Date.civil(1007, 2, 27).gregorian?.should == false
+ Date.civil(1907, 2, 27, Date.civil(1930, 1, 1).jd).gregorian?.should == false
end
it "marks a day after the calendar reform as Julian" do
Date.civil(2007, 2, 27).should.gregorian?
- Date.civil(1607, 2, 27, Date.civil(1582, 1, 1).jd).gregorian?.should be_true
+ Date.civil(1607, 2, 27, Date.civil(1582, 1, 1).jd).gregorian?.should == true
end
end
diff --git a/spec/ruby/library/date/iso8601_spec.rb b/spec/ruby/library/date/iso8601_spec.rb
index af66845a6b..26815bd76c 100644
--- a/spec/ruby/library/date/iso8601_spec.rb
+++ b/spec/ruby/library/date/iso8601_spec.rb
@@ -25,17 +25,17 @@ describe "Date.iso8601" do
it "raises a Date::Error if the argument is a invalid Date" do
-> {
Date.iso8601('invalid')
- }.should raise_error(Date::Error, "invalid date")
+ }.should.raise(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")
+ }.should.raise(Date::Error, "invalid date")
end
it "raises a TypeError when passed an Object" do
- -> { Date.iso8601(Object.new) }.should raise_error(TypeError)
+ -> { Date.iso8601(Object.new) }.should.raise(TypeError)
end
end
@@ -51,6 +51,6 @@ describe "Date._iso8601" do
end
it "raises a TypeError when passed an Object" do
- -> { Date._iso8601(Object.new) }.should raise_error(TypeError)
+ -> { Date._iso8601(Object.new) }.should.raise(TypeError)
end
end
diff --git a/spec/ruby/library/date/jd_spec.rb b/spec/ruby/library/date/jd_spec.rb
index 336b783e8d..e5cfe10eff 100644
--- a/spec/ruby/library/date/jd_spec.rb
+++ b/spec/ruby/library/date/jd_spec.rb
@@ -1,15 +1,22 @@
require_relative '../../spec_helper'
-require_relative 'shared/jd'
require 'date'
describe "Date#jd" do
-
it "determines the Julian day for a Date object" do
Date.civil(2008, 1, 16).jd.should == 2454482
end
-
end
describe "Date.jd" do
- it_behaves_like :date_jd, :jd
+ it "constructs a Date object if passed a Julian day" do
+ Date.jd(2454482).should == Date.civil(2008, 1, 16)
+ end
+
+ it "returns a Date object representing Julian day 0 (-4712-01-01) if no arguments passed" do
+ Date.jd.should == Date.civil(-4712, 1, 1)
+ end
+
+ it "constructs a Date object if passed a negative number" do
+ Date.jd(-1).should == Date.civil(-4713, 12, 31)
+ end
end
diff --git a/spec/ruby/library/date/julian_leap_spec.rb b/spec/ruby/library/date/julian_leap_spec.rb
index 2ef2d65d81..42231e012f 100644
--- a/spec/ruby/library/date/julian_leap_spec.rb
+++ b/spec/ruby/library/date/julian_leap_spec.rb
@@ -3,13 +3,13 @@ require 'date'
describe "Date.julian_leap?" do
it "determines whether a year is a leap year in the Julian calendar" do
- Date.julian_leap?(1900).should be_true
- Date.julian_leap?(2000).should be_true
- Date.julian_leap?(2004).should be_true
+ Date.julian_leap?(1900).should == true
+ Date.julian_leap?(2000).should == true
+ Date.julian_leap?(2004).should == true
end
it "determines whether a year is not a leap year in the Julian calendar" do
- Date.julian_leap?(1999).should be_false
- Date.julian_leap?(2002).should be_false
+ Date.julian_leap?(1999).should == false
+ Date.julian_leap?(2002).should == false
end
end
diff --git a/spec/ruby/library/date/julian_spec.rb b/spec/ruby/library/date/julian_spec.rb
index db2629d1e7..9f8a670899 100644
--- a/spec/ruby/library/date/julian_spec.rb
+++ b/spec/ruby/library/date/julian_spec.rb
@@ -5,12 +5,12 @@ describe "Date#julian?" do
it "marks a day before the calendar reform as Julian" do
Date.civil(1007, 2, 27).should.julian?
- Date.civil(1907, 2, 27, Date.civil(1930, 1, 1).jd).julian?.should be_true
+ Date.civil(1907, 2, 27, Date.civil(1930, 1, 1).jd).julian?.should == true
end
it "marks a day after the calendar reform as Julian" do
Date.civil(2007, 2, 27).should_not.julian?
- Date.civil(1607, 2, 27, Date.civil(1582, 1, 1).jd).julian?.should be_false
+ Date.civil(1607, 2, 27, Date.civil(1582, 1, 1).jd).julian?.should == false
end
end
diff --git a/spec/ruby/library/date/mday_spec.rb b/spec/ruby/library/date/mday_spec.rb
index 53f6f98169..32fd8fc7f1 100644
--- a/spec/ruby/library/date/mday_spec.rb
+++ b/spec/ruby/library/date/mday_spec.rb
@@ -2,5 +2,7 @@ require_relative '../../spec_helper'
require 'date'
describe "Date#mday" do
- it "needs to be reviewed for spec completeness"
+ it "is an alias of Date#day" do
+ Date.instance_method(:mday).should == Date.instance_method(:day)
+ end
end
diff --git a/spec/ruby/library/date/minus_month_spec.rb b/spec/ruby/library/date/minus_month_spec.rb
index 470c4d8a76..d56e19dc31 100644
--- a/spec/ruby/library/date/minus_month_spec.rb
+++ b/spec/ruby/library/date/minus_month_spec.rb
@@ -14,10 +14,10 @@ describe "Date#<<" do
end
it "raises an error on non numeric parameters" do
- -> { Date.civil(2007,2,27) << :hello }.should raise_error(TypeError)
- -> { Date.civil(2007,2,27) << "hello" }.should raise_error(TypeError)
- -> { Date.civil(2007,2,27) << Date.new }.should raise_error(TypeError)
- -> { Date.civil(2007,2,27) << Object.new }.should raise_error(TypeError)
+ -> { Date.civil(2007,2,27) << :hello }.should.raise(TypeError)
+ -> { Date.civil(2007,2,27) << "hello" }.should.raise(TypeError)
+ -> { Date.civil(2007,2,27) << Date.new }.should.raise(TypeError)
+ -> { Date.civil(2007,2,27) << Object.new }.should.raise(TypeError)
end
end
diff --git a/spec/ruby/library/date/minus_spec.rb b/spec/ruby/library/date/minus_spec.rb
index 5a2a29e04a..c2a08fa5b0 100644
--- a/spec/ruby/library/date/minus_spec.rb
+++ b/spec/ruby/library/date/minus_spec.rb
@@ -22,9 +22,9 @@ describe "Date#-" do
end
it "raises an error for non Numeric arguments" do
- -> { Date.civil(2007,2,27) - :hello }.should raise_error(TypeError)
- -> { Date.civil(2007,2,27) - "hello" }.should raise_error(TypeError)
- -> { Date.civil(2007,2,27) - Object.new }.should raise_error(TypeError)
+ -> { Date.civil(2007,2,27) - :hello }.should.raise(TypeError)
+ -> { Date.civil(2007,2,27) - "hello" }.should.raise(TypeError)
+ -> { Date.civil(2007,2,27) - Object.new }.should.raise(TypeError)
end
end
diff --git a/spec/ruby/library/date/mon_spec.rb b/spec/ruby/library/date/mon_spec.rb
index 616d72cf88..15754ffb1f 100644
--- a/spec/ruby/library/date/mon_spec.rb
+++ b/spec/ruby/library/date/mon_spec.rb
@@ -1,7 +1,8 @@
require_relative '../../spec_helper'
-require_relative 'shared/month'
require 'date'
describe "Date#mon" do
- it_behaves_like :date_month, :mon
+ it "is an alias of Date#month" do
+ Date.instance_method(:mon).should == Date.instance_method(:month)
+ end
end
diff --git a/spec/ruby/library/date/monday_spec.rb b/spec/ruby/library/date/monday_spec.rb
index 14a117b73c..61d728f3c5 100644
--- a/spec/ruby/library/date/monday_spec.rb
+++ b/spec/ruby/library/date/monday_spec.rb
@@ -3,6 +3,6 @@ require 'date'
describe "Date#monday?" do
it "should be monday" do
- Date.new(2000, 1, 3).monday?.should be_true
+ Date.new(2000, 1, 3).monday?.should == true
end
end
diff --git a/spec/ruby/library/date/month_spec.rb b/spec/ruby/library/date/month_spec.rb
index f493ec8119..e040f9a94c 100644
--- a/spec/ruby/library/date/month_spec.rb
+++ b/spec/ruby/library/date/month_spec.rb
@@ -1,7 +1,9 @@
require_relative '../../spec_helper'
-require_relative 'shared/month'
require 'date'
describe "Date#month" do
- it_behaves_like :date_month, :month
+ it "returns the month" do
+ m = Date.new(2000, 7, 1).month
+ m.should == 7
+ end
end
diff --git a/spec/ruby/library/date/ordinal_spec.rb b/spec/ruby/library/date/ordinal_spec.rb
index ec490fd49c..c8bf715163 100644
--- a/spec/ruby/library/date/ordinal_spec.rb
+++ b/spec/ruby/library/date/ordinal_spec.rb
@@ -1,7 +1,17 @@
require 'date'
require_relative '../../spec_helper'
-require_relative 'shared/ordinal'
describe "Date.ordinal" do
- it_behaves_like :date_ordinal, :ordinal
+ it "constructs a Date object from an ordinal date" do
+ # October 1582 (the Gregorian calendar, Ordinal Date)
+ # S M Tu W Th F S
+ # 274 275 276 277 278 279
+ # 280 281 282 283 284 285 286
+ # 287 288 289 290 291 292 293
+ # 294
+ Date.ordinal(1582, 274).should == Date.civil(1582, 10, 1)
+ Date.ordinal(1582, 277).should == Date.civil(1582, 10, 4)
+ Date.ordinal(1582, 278).should == Date.civil(1582, 10, 15)
+ Date.ordinal(1582, 287, Date::ENGLAND).should == Date.civil(1582, 10, 14, Date::ENGLAND)
+ end
end
diff --git a/spec/ruby/library/date/parse_spec.rb b/spec/ruby/library/date/parse_spec.rb
index 5ef4f6e9b5..4d655f516e 100644
--- a/spec/ruby/library/date/parse_spec.rb
+++ b/spec/ruby/library/date/parse_spec.rb
@@ -23,7 +23,7 @@ describe "Date#parse" do
# Specs using numbers
it "throws an argument error for a single digit" do
- ->{ Date.parse("1") }.should raise_error(ArgumentError)
+ ->{ Date.parse("1") }.should.raise(ArgumentError)
end
it "parses DD as month day number" do
@@ -66,8 +66,8 @@ describe "Date#parse" do
end
it "raises a TypeError trying to parse non-String-like object" do
- -> { Date.parse(1) }.should raise_error(TypeError)
- -> { Date.parse([]) }.should raise_error(TypeError)
+ -> { Date.parse(1) }.should.raise(TypeError)
+ -> { Date.parse([]) }.should.raise(TypeError)
end
it "coerces using to_str" do
diff --git a/spec/ruby/library/date/plus_spec.rb b/spec/ruby/library/date/plus_spec.rb
index 0cb99fd4ca..6179370fca 100644
--- a/spec/ruby/library/date/plus_spec.rb
+++ b/spec/ruby/library/date/plus_spec.rb
@@ -15,6 +15,6 @@ describe "Date#+" do
end
it "raises TypeError if argument is not Numeric" do
- -> { Date.today + Date.today }.should raise_error(TypeError)
+ -> { Date.today + Date.today }.should.raise(TypeError)
end
end
diff --git a/spec/ruby/library/date/saturday_spec.rb b/spec/ruby/library/date/saturday_spec.rb
index 1527b71d00..29f8267a2b 100644
--- a/spec/ruby/library/date/saturday_spec.rb
+++ b/spec/ruby/library/date/saturday_spec.rb
@@ -3,6 +3,6 @@ require 'date'
describe "Date#saturday?" do
it "should be saturday" do
- Date.new(2000, 1, 1).saturday?.should be_true
+ Date.new(2000, 1, 1).saturday?.should == true
end
end
diff --git a/spec/ruby/library/date/shared/civil.rb b/spec/ruby/library/date/shared/civil.rb
index bbed4a8866..4499cdf8e9 100644
--- a/spec/ruby/library/date/shared/civil.rb
+++ b/spec/ruby/library/date/shared/civil.rb
@@ -36,14 +36,14 @@ describe :date_civil, shared: true do
end
it "doesn't create dates for invalid arguments" do
- -> { Date.send(@method, 2000, 13, 31) }.should raise_error(ArgumentError)
- -> { Date.send(@method, 2000, 12, 32) }.should raise_error(ArgumentError)
- -> { Date.send(@method, 2000, 2, 30) }.should raise_error(ArgumentError)
- -> { Date.send(@method, 1900, 2, 29) }.should raise_error(ArgumentError)
- -> { Date.send(@method, 2000, 2, 29) }.should_not raise_error(ArgumentError)
-
- -> { Date.send(@method, 1582, 10, 14) }.should raise_error(ArgumentError)
- -> { Date.send(@method, 1582, 10, 15) }.should_not raise_error(ArgumentError)
+ -> { Date.send(@method, 2000, 13, 31) }.should.raise(ArgumentError)
+ -> { Date.send(@method, 2000, 12, 32) }.should.raise(ArgumentError)
+ -> { Date.send(@method, 2000, 2, 30) }.should.raise(ArgumentError)
+ -> { Date.send(@method, 1900, 2, 29) }.should.raise(ArgumentError)
+ -> { Date.send(@method, 2000, 2, 29) }.should_not.raise(ArgumentError)
+
+ -> { Date.send(@method, 1582, 10, 14) }.should.raise(ArgumentError)
+ -> { Date.send(@method, 1582, 10, 15) }.should_not.raise(ArgumentError)
end
diff --git a/spec/ruby/library/date/shared/commercial.rb b/spec/ruby/library/date/shared/commercial.rb
deleted file mode 100644
index 39c9af47b6..0000000000
--- a/spec/ruby/library/date/shared/commercial.rb
+++ /dev/null
@@ -1,39 +0,0 @@
-describe :date_commercial, shared: true do
- it "creates a Date for Julian Day Number day 0 by default" do
- d = Date.send(@method)
- d.year.should == -4712
- d.month.should == 1
- d.day.should == 1
- end
-
- it "creates a Date for the monday in the year and week given" do
- d = Date.send(@method, 2000, 1)
- d.year.should == 2000
- d.month.should == 1
- d.day.should == 3
- d.cwday.should == 1
- end
-
- it "creates a Date for the correct day given the year, week and day number" do
- d = Date.send(@method, 2004, 1, 1)
- d.year.should == 2003
- d.month.should == 12
- d.day.should == 29
- d.cwday.should == 1
- d.cweek.should == 1
- d.cwyear.should == 2004
- end
-
- it "creates only Date objects for valid weeks" do
- -> { Date.send(@method, 2004, 53, 1) }.should_not raise_error(ArgumentError)
- -> { Date.send(@method, 2004, 53, 0) }.should raise_error(ArgumentError)
- -> { Date.send(@method, 2004, 53, 8) }.should raise_error(ArgumentError)
- -> { Date.send(@method, 2004, 54, 1) }.should raise_error(ArgumentError)
- -> { Date.send(@method, 2004, 0, 1) }.should raise_error(ArgumentError)
-
- -> { Date.send(@method, 2003, 52, 1) }.should_not raise_error(ArgumentError)
- -> { Date.send(@method, 2003, 53, 1) }.should raise_error(ArgumentError)
- -> { Date.send(@method, 2003, 52, 0) }.should raise_error(ArgumentError)
- -> { Date.send(@method, 2003, 52, 8) }.should raise_error(ArgumentError)
- end
-end
diff --git a/spec/ruby/library/date/shared/jd.rb b/spec/ruby/library/date/shared/jd.rb
deleted file mode 100644
index 511557b4f7..0000000000
--- a/spec/ruby/library/date/shared/jd.rb
+++ /dev/null
@@ -1,14 +0,0 @@
-describe :date_jd, shared: true do
- it "constructs a Date object if passed a Julian day" do
- Date.send(@method, 2454482).should == Date.civil(2008, 1, 16)
- end
-
- it "returns a Date object representing Julian day 0 (-4712-01-01) if no arguments passed" do
- Date.send(@method).should == Date.civil(-4712, 1, 1)
- end
-
- it "constructs a Date object if passed a negative number" do
- Date.send(@method, -1).should == Date.civil(-4713, 12, 31)
- end
-
-end
diff --git a/spec/ruby/library/date/shared/month.rb b/spec/ruby/library/date/shared/month.rb
deleted file mode 100644
index 5fcb2cbeb0..0000000000
--- a/spec/ruby/library/date/shared/month.rb
+++ /dev/null
@@ -1,6 +0,0 @@
-describe :date_month, shared: true do
- it "returns the month" do
- m = Date.new(2000, 7, 1).send(@method)
- m.should == 7
- end
-end
diff --git a/spec/ruby/library/date/shared/ordinal.rb b/spec/ruby/library/date/shared/ordinal.rb
deleted file mode 100644
index 4b182d5a25..0000000000
--- a/spec/ruby/library/date/shared/ordinal.rb
+++ /dev/null
@@ -1,22 +0,0 @@
-# reference:
-# October 1582 (the Gregorian calendar, Civil Date)
-# S M Tu W Th F S
-# 1 2 3 4 15 16
-# 17 18 19 20 21 22 23
-# 24 25 26 27 28 29 30
-# 31
-
-describe :date_ordinal, shared: true do
- it "constructs a Date object from an ordinal date" do
- # October 1582 (the Gregorian calendar, Ordinal Date)
- # S M Tu W Th F S
- # 274 275 276 277 278 279
- # 280 281 282 283 284 285 286
- # 287 288 289 290 291 292 293
- # 294
- Date.send(@method, 1582, 274).should == Date.civil(1582, 10, 1)
- Date.send(@method, 1582, 277).should == Date.civil(1582, 10, 4)
- Date.send(@method, 1582, 278).should == Date.civil(1582, 10, 15)
- Date.send(@method, 1582, 287, Date::ENGLAND).should == Date.civil(1582, 10, 14, Date::ENGLAND)
- end
-end
diff --git a/spec/ruby/library/date/shared/valid_civil.rb b/spec/ruby/library/date/shared/valid_civil.rb
deleted file mode 100644
index 545c207bbe..0000000000
--- a/spec/ruby/library/date/shared/valid_civil.rb
+++ /dev/null
@@ -1,36 +0,0 @@
-describe :date_valid_civil?, shared: true do
-
- # reference:
- # October 1582 (the Gregorian calendar, Civil Date)
- # S M Tu W Th F S
- # 1 2 3 4 15 16
- # 17 18 19 20 21 22 23
- # 24 25 26 27 28 29 30
- # 31
-
- it "returns true if it is a valid civil date" do
- Date.send(@method, 1582, 10, 15).should be_true
- Date.send(@method, 1582, 10, 14, Date::ENGLAND).should be_true
- end
-
- it "returns false if it is not a valid civil date" do
- Date.send(@method, 1582, 10, 14).should == false
- end
-
- it "handles negative months and days" do
- # October 1582 (the Gregorian calendar, Civil Date)
- # S M Tu W Th F S
- # -21 -20 -19 -18 -17 -16
- # -15 -14 -13 -12 -11 -10 -9
- # -8 -7 -6 -5 -4 -3 -2
- # -1
- Date.send(@method, 1582, -3, -22).should be_false
- Date.send(@method, 1582, -3, -21).should be_true
- Date.send(@method, 1582, -3, -18).should be_true
- Date.send(@method, 1582, -3, -17).should be_true
-
- Date.send(@method, 2007, -11, -10).should be_true
- Date.send(@method, 2008, -11, -10).should be_true
- end
-
-end
diff --git a/spec/ruby/library/date/shared/valid_commercial.rb b/spec/ruby/library/date/shared/valid_commercial.rb
deleted file mode 100644
index 117dfe1d3d..0000000000
--- a/spec/ruby/library/date/shared/valid_commercial.rb
+++ /dev/null
@@ -1,34 +0,0 @@
-describe :date_valid_commercial?, shared: true do
-
- it "returns true if it is a valid commercial date" do
- # October 1582 (the Gregorian calendar, Commercial Date)
- # M Tu W Th F Sa Su
- # 39: 1 2 3 4 5 6 7
- # 40: 1 2 3 4 5 6 7
- # 41: 1 2 3 4 5 6 7
- Date.send(@method, 1582, 39, 4).should be_true
- Date.send(@method, 1582, 39, 5).should be_true
- Date.send(@method, 1582, 41, 4).should be_true
- Date.send(@method, 1582, 41, 5).should be_true
- Date.send(@method, 1582, 41, 4, Date::ENGLAND).should be_true
- Date.send(@method, 1752, 37, 4, Date::ENGLAND).should be_true
- end
-
- it "returns false it is not a valid commercial date" do
- Date.send(@method, 1999, 53, 1).should be_false
- end
-
- it "handles negative week and day numbers" do
- # October 1582 (the Gregorian calendar, Commercial Date)
- # M Tu W Th F Sa Su
- # -12: -7 -6 -5 -4 -3 -2 -1
- # -11: -7 -6 -5 -4 -3 -2 -1
- # -10: -7 -6 -5 -4 -3 -2 -1
- Date.send(@method, 1582, -12, -4).should be_true
- Date.send(@method, 1582, -12, -3).should be_true
- Date.send(@method, 2007, -44, -2).should be_true
- Date.send(@method, 2008, -44, -2).should be_true
- Date.send(@method, 1999, -53, -1).should be_false
- end
-
-end
diff --git a/spec/ruby/library/date/shared/valid_jd.rb b/spec/ruby/library/date/shared/valid_jd.rb
deleted file mode 100644
index e474dfb450..0000000000
--- a/spec/ruby/library/date/shared/valid_jd.rb
+++ /dev/null
@@ -1,20 +0,0 @@
-describe :date_valid_jd?, shared: true do
- it "returns true if passed a number value" do
- Date.send(@method, -100).should be_true
- Date.send(@method, 100.0).should be_true
- Date.send(@method, 2**100).should be_true
- Date.send(@method, Rational(1,2)).should be_true
- end
-
- it "returns false if passed nil" do
- Date.send(@method, nil).should be_false
- end
-
- it "returns false if passed symbol" do
- Date.send(@method, :number).should be_false
- end
-
- it "returns false if passed false" do
- Date.send(@method, false).should be_false
- end
-end
diff --git a/spec/ruby/library/date/shared/valid_ordinal.rb b/spec/ruby/library/date/shared/valid_ordinal.rb
deleted file mode 100644
index 1ed961be23..0000000000
--- a/spec/ruby/library/date/shared/valid_ordinal.rb
+++ /dev/null
@@ -1,26 +0,0 @@
-describe :date_valid_ordinal?, shared: true do
- it "determines if the date is a valid ordinal date" do
- # October 1582 (the Gregorian calendar, Ordinal Date)
- # S M Tu W Th F S
- # 274 275 276 277 278 279
- # 280 281 282 283 284 285 286
- # 287 288 289 290 291 292 293
- # 294
- Date.send(@method, 1582, 277).should == true
- Date.send(@method, 1582, 278).should == true
- Date.send(@method, 1582, 287).should == true
- Date.send(@method, 1582, 288).should == true
- end
-
- it "handles negative day numbers" do
- # October 1582 (the Gregorian calendar, Ordinal Date)
- # S M Tu W Th F S
- # -82 -81 -80 -79 -78 -77
- # -76 -75 -74 -73 -72 -71 -70
- # -69 -68 -67 -66 -65 -64 -63
- # -62
- Date.send(@method, 1582, -79).should == true
- Date.send(@method, 1582, -78).should == true
- Date.send(@method, 2007, -100).should == true
- end
-end
diff --git a/spec/ruby/library/date/succ_spec.rb b/spec/ruby/library/date/succ_spec.rb
index c4a902aa63..0b14d3bb73 100644
--- a/spec/ruby/library/date/succ_spec.rb
+++ b/spec/ruby/library/date/succ_spec.rb
@@ -2,5 +2,7 @@ require_relative '../../spec_helper'
require 'date'
describe "Date#succ" do
- it "needs to be reviewed for spec completeness"
+ it "is an alias of Date#next" do
+ Date.instance_method(:succ).should == Date.instance_method(:next)
+ end
end
diff --git a/spec/ruby/library/date/sunday_spec.rb b/spec/ruby/library/date/sunday_spec.rb
index c3a817fa86..548f36a4f0 100644
--- a/spec/ruby/library/date/sunday_spec.rb
+++ b/spec/ruby/library/date/sunday_spec.rb
@@ -3,6 +3,6 @@ require 'date'
describe "Date#sunday?" do
it "should be sunday" do
- Date.new(2000, 1, 2).sunday?.should be_true
+ Date.new(2000, 1, 2).sunday?.should == true
end
end
diff --git a/spec/ruby/library/date/thursday_spec.rb b/spec/ruby/library/date/thursday_spec.rb
index 74b5f40365..4df3b9103a 100644
--- a/spec/ruby/library/date/thursday_spec.rb
+++ b/spec/ruby/library/date/thursday_spec.rb
@@ -3,6 +3,6 @@ require 'date'
describe "Date#thursday?" do
it "should be thursday" do
- Date.new(2000, 1, 6).thursday?.should be_true
+ Date.new(2000, 1, 6).thursday?.should == true
end
end
diff --git a/spec/ruby/library/date/today_spec.rb b/spec/ruby/library/date/today_spec.rb
index 7c6ebc9cb4..4be8d8e931 100644
--- a/spec/ruby/library/date/today_spec.rb
+++ b/spec/ruby/library/date/today_spec.rb
@@ -3,7 +3,7 @@ require 'date'
describe "Date.today" do
it "returns a Date object" do
- Date.today.should be_kind_of Date
+ Date.today.should.is_a? Date
end
it "sets Date object to the current date" do
diff --git a/spec/ruby/library/date/tuesday_spec.rb b/spec/ruby/library/date/tuesday_spec.rb
index 052837b54e..db31387aed 100644
--- a/spec/ruby/library/date/tuesday_spec.rb
+++ b/spec/ruby/library/date/tuesday_spec.rb
@@ -3,6 +3,6 @@ require 'date'
describe "Date#tuesday?" do
it "should be tuesday" do
- Date.new(2000, 1, 4).tuesday?.should be_true
+ Date.new(2000, 1, 4).tuesday?.should == true
end
end
diff --git a/spec/ruby/library/date/valid_civil_spec.rb b/spec/ruby/library/date/valid_civil_spec.rb
index 00f2c57205..8cffc80310 100644
--- a/spec/ruby/library/date/valid_civil_spec.rb
+++ b/spec/ruby/library/date/valid_civil_spec.rb
@@ -1,9 +1,8 @@
require_relative '../../spec_helper'
-require_relative 'shared/valid_civil'
require 'date'
-describe "Date#valid_civil?" do
-
- it_behaves_like :date_valid_civil?, :valid_civil?
-
+describe "Date.valid_civil?" do
+ it "is an alias of Date.valid_date?" do
+ Date.method(:valid_civil?).should == Date.method(:valid_date?)
+ end
end
diff --git a/spec/ruby/library/date/valid_commercial_spec.rb b/spec/ruby/library/date/valid_commercial_spec.rb
index 7e96782b6b..21a91ad867 100644
--- a/spec/ruby/library/date/valid_commercial_spec.rb
+++ b/spec/ruby/library/date/valid_commercial_spec.rb
@@ -1,8 +1,35 @@
require_relative '../../spec_helper'
-require_relative 'shared/valid_commercial'
require 'date'
-describe "Date#valid_commercial?" do
+describe "Date.valid_commercial?" do
+ it "returns true if it is a valid commercial date" do
+ # October 1582 (the Gregorian calendar, Commercial Date)
+ # M Tu W Th F Sa Su
+ # 39: 1 2 3 4 5 6 7
+ # 40: 1 2 3 4 5 6 7
+ # 41: 1 2 3 4 5 6 7
+ Date.valid_commercial?(1582, 39, 4).should == true
+ Date.valid_commercial?(1582, 39, 5).should == true
+ Date.valid_commercial?(1582, 41, 4).should == true
+ Date.valid_commercial?(1582, 41, 5).should == true
+ Date.valid_commercial?(1582, 41, 4, Date::ENGLAND).should == true
+ Date.valid_commercial?(1752, 37, 4, Date::ENGLAND).should == true
+ end
- it_behaves_like :date_valid_commercial?, :valid_commercial?
+ it "returns false it is not a valid commercial date" do
+ Date.valid_commercial?(1999, 53, 1).should == false
+ end
+
+ it "handles negative week and day numbers" do
+ # October 1582 (the Gregorian calendar, Commercial Date)
+ # M Tu W Th F Sa Su
+ # -12: -7 -6 -5 -4 -3 -2 -1
+ # -11: -7 -6 -5 -4 -3 -2 -1
+ # -10: -7 -6 -5 -4 -3 -2 -1
+ Date.valid_commercial?(1582, -12, -4).should == true
+ Date.valid_commercial?(1582, -12, -3).should == true
+ Date.valid_commercial?(2007, -44, -2).should == true
+ Date.valid_commercial?(2008, -44, -2).should == true
+ Date.valid_commercial?(1999, -53, -1).should == false
+ end
end
diff --git a/spec/ruby/library/date/valid_date_spec.rb b/spec/ruby/library/date/valid_date_spec.rb
index f12a71d966..f0d5ec7b4d 100644
--- a/spec/ruby/library/date/valid_date_spec.rb
+++ b/spec/ruby/library/date/valid_date_spec.rb
@@ -1,7 +1,36 @@
require_relative '../../spec_helper'
-require_relative 'shared/valid_civil'
require 'date'
-describe "Date#valid_date?" do
- it_behaves_like :date_valid_civil?, :valid_date?
+describe "Date.valid_date?" do
+ # reference:
+ # October 1582 (the Gregorian calendar, Civil Date)
+ # S M Tu W Th F S
+ # 1 2 3 4 15 16
+ # 17 18 19 20 21 22 23
+ # 24 25 26 27 28 29 30
+ # 31
+ it "returns true if it is a valid civil date" do
+ Date.valid_date?(1582, 10, 15).should == true
+ Date.valid_date?(1582, 10, 14, Date::ENGLAND).should == true
+ end
+
+ it "returns false if it is not a valid civil date" do
+ Date.valid_date?(1582, 10, 14).should == false
+ end
+
+ it "handles negative months and days" do
+ # October 1582 (the Gregorian calendar, Civil Date)
+ # S M Tu W Th F S
+ # -21 -20 -19 -18 -17 -16
+ # -15 -14 -13 -12 -11 -10 -9
+ # -8 -7 -6 -5 -4 -3 -2
+ # -1
+ Date.valid_date?(1582, -3, -22).should == false
+ Date.valid_date?(1582, -3, -21).should == true
+ Date.valid_date?(1582, -3, -18).should == true
+ Date.valid_date?(1582, -3, -17).should == true
+
+ Date.valid_date?(2007, -11, -10).should == true
+ Date.valid_date?(2008, -11, -10).should == true
+ end
end
diff --git a/spec/ruby/library/date/valid_jd_spec.rb b/spec/ruby/library/date/valid_jd_spec.rb
index aecaaabcf4..46f22de497 100644
--- a/spec/ruby/library/date/valid_jd_spec.rb
+++ b/spec/ruby/library/date/valid_jd_spec.rb
@@ -1,9 +1,23 @@
require_relative '../../spec_helper'
-require_relative 'shared/valid_jd'
require 'date'
describe "Date.valid_jd?" do
+ it "returns true if passed a number value" do
+ Date.valid_jd?(-100).should == true
+ Date.valid_jd?(100.0).should == true
+ Date.valid_jd?(2**100).should == true
+ Date.valid_jd?(Rational(1,2)).should == true
+ end
- it_behaves_like :date_valid_jd?, :valid_jd?
+ it "returns false if passed nil" do
+ Date.valid_jd?(nil).should == false
+ end
+ it "returns false if passed symbol" do
+ Date.valid_jd?(:number).should == false
+ end
+
+ it "returns false if passed false" do
+ Date.valid_jd?(false).should == false
+ end
end
diff --git a/spec/ruby/library/date/valid_ordinal_spec.rb b/spec/ruby/library/date/valid_ordinal_spec.rb
index 58d548c704..bb5c259606 100644
--- a/spec/ruby/library/date/valid_ordinal_spec.rb
+++ b/spec/ruby/library/date/valid_ordinal_spec.rb
@@ -1,9 +1,29 @@
require_relative '../../spec_helper'
-require_relative 'shared/valid_ordinal'
require 'date'
describe "Date.valid_ordinal?" do
+ it "determines if the date is a valid ordinal date" do
+ # October 1582 (the Gregorian calendar, Ordinal Date)
+ # S M Tu W Th F S
+ # 274 275 276 277 278 279
+ # 280 281 282 283 284 285 286
+ # 287 288 289 290 291 292 293
+ # 294
+ Date.valid_ordinal?(1582, 277).should == true
+ Date.valid_ordinal?(1582, 278).should == true
+ Date.valid_ordinal?(1582, 287).should == true
+ Date.valid_ordinal?(1582, 288).should == true
+ end
- it_behaves_like :date_valid_ordinal?, :valid_ordinal?
-
+ it "handles negative day numbers" do
+ # October 1582 (the Gregorian calendar, Ordinal Date)
+ # S M Tu W Th F S
+ # -82 -81 -80 -79 -78 -77
+ # -76 -75 -74 -73 -72 -71 -70
+ # -69 -68 -67 -66 -65 -64 -63
+ # -62
+ Date.valid_ordinal?(1582, -79).should == true
+ Date.valid_ordinal?(1582, -78).should == true
+ Date.valid_ordinal?(2007, -100).should == true
+ end
end
diff --git a/spec/ruby/library/date/wednesday_spec.rb b/spec/ruby/library/date/wednesday_spec.rb
index e80ec23dd2..4bbeead5b8 100644
--- a/spec/ruby/library/date/wednesday_spec.rb
+++ b/spec/ruby/library/date/wednesday_spec.rb
@@ -3,6 +3,6 @@ require 'date'
describe "Date#wednesday?" do
it "should be wednesday" do
- Date.new(2000, 1, 5).wednesday?.should be_true
+ Date.new(2000, 1, 5).wednesday?.should == true
end
end
diff --git a/spec/ruby/library/datetime/deconstruct_keys_spec.rb b/spec/ruby/library/datetime/deconstruct_keys_spec.rb
index 154c024a23..07a7bda881 100644
--- a/spec/ruby/library/datetime/deconstruct_keys_spec.rb
+++ b/spec/ruby/library/datetime/deconstruct_keys_spec.rb
@@ -18,16 +18,16 @@ describe "DateTime#deconstruct_keys" do
it "requires one argument" do
-> {
DateTime.new(2022, 10, 5, 13, 30).deconstruct_keys
- }.should raise_error(ArgumentError)
+ }.should.raise(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)")
+ -> { d.deconstruct_keys(1) }.should.raise(TypeError, "wrong argument type Integer (expected Array or nil)")
+ -> { d.deconstruct_keys("asd") }.should.raise(TypeError, "wrong argument type String (expected Array or nil)")
+ -> { d.deconstruct_keys(:x) }.should.raise(TypeError, "wrong argument type Symbol (expected Array or nil)")
+ -> { d.deconstruct_keys({}) }.should.raise(TypeError, "wrong argument type Hash (expected Array or nil)")
end
it "returns {} when passed []" do
diff --git a/spec/ruby/library/datetime/hour_spec.rb b/spec/ruby/library/datetime/hour_spec.rb
index 8efd5f92f0..5d8e75edcb 100644
--- a/spec/ruby/library/datetime/hour_spec.rb
+++ b/spec/ruby/library/datetime/hour_spec.rb
@@ -15,28 +15,27 @@ describe "DateTime#hour" do
end
it "raises an error for Rational" do
- -> { new_datetime(hour: 1 + Rational(1,2)) }.should raise_error(ArgumentError)
+ -> { new_datetime(hour: 1 + Rational(1,2)) }.should.raise(ArgumentError)
end
it "raises an error for Float" do
- -> { new_datetime(hour: 1.5).hour }.should raise_error(ArgumentError)
+ -> { new_datetime(hour: 1.5).hour }.should.raise(ArgumentError)
end
it "raises an error for Rational" do
- -> { new_datetime(day: 1 + Rational(1,2)) }.should raise_error(ArgumentError)
+ -> { new_datetime(day: 1 + Rational(1,2)) }.should.raise(ArgumentError)
end
it "raises an error, when the hour is smaller than -24" do
- -> { new_datetime(hour: -25) }.should raise_error(ArgumentError)
+ -> { new_datetime(hour: -25) }.should.raise(ArgumentError)
end
it "raises an error, when the hour is larger than 24" do
- -> { new_datetime(hour: 25) }.should raise_error(ArgumentError)
+ -> { new_datetime(hour: 25) }.should.raise(ArgumentError)
end
it "raises an error for hour fractions smaller than -24" do
- -> { new_datetime(hour: -24 - Rational(1,2)) }.should(
- raise_error(ArgumentError))
+ -> { new_datetime(hour: -24 - Rational(1,2)) }.should.raise(ArgumentError)
end
it "adds 1 to day, when 24 hours given" do
diff --git a/spec/ruby/library/datetime/iso8601_spec.rb b/spec/ruby/library/datetime/iso8601_spec.rb
index 457881277a..4368300fd5 100644
--- a/spec/ruby/library/datetime/iso8601_spec.rb
+++ b/spec/ruby/library/datetime/iso8601_spec.rb
@@ -6,5 +6,7 @@ describe "DateTime.iso8601" do
end
describe "DateTime#iso8601" do
- it "needs to be reviewed for spec completeness"
+ it "is an alias of DateTime#isoxmlschema8601" do
+ DateTime.instance_method(:iso8601).should == DateTime.instance_method(:xmlschema)
+ end
end
diff --git a/spec/ruby/library/datetime/min_spec.rb b/spec/ruby/library/datetime/min_spec.rb
index a1eaa214cb..ca995a7eed 100644
--- a/spec/ruby/library/datetime/min_spec.rb
+++ b/spec/ruby/library/datetime/min_spec.rb
@@ -1,6 +1,8 @@
require_relative '../../spec_helper'
-require_relative 'shared/min'
+require 'date'
-describe "DateTime.min" do
- it_behaves_like :datetime_min, :min
+describe "DateTime#min" do
+ it "is an alias of DateTime#minute" do
+ DateTime.instance_method(:min).should == DateTime.instance_method(:minute)
+ end
end
diff --git a/spec/ruby/library/datetime/minute_spec.rb b/spec/ruby/library/datetime/minute_spec.rb
index acdfeda345..6e99752de7 100644
--- a/spec/ruby/library/datetime/minute_spec.rb
+++ b/spec/ruby/library/datetime/minute_spec.rb
@@ -1,6 +1,40 @@
require_relative '../../spec_helper'
-require_relative 'shared/min'
+require 'date'
-describe "DateTime.minute" do
- it_behaves_like :datetime_min, :minute
+describe "DateTime#minute" do
+ it "returns 0 if no argument is passed" do
+ DateTime.new.minute.should == 0
+ end
+
+ it "returns the minute passed as argument" do
+ new_datetime(minute: 5).minute.should == 5
+ end
+
+ it "adds 60 to negative minutes" do
+ new_datetime(minute: -20).minute.should == 40
+ end
+
+ it "raises an error for Rational" do
+ -> { new_datetime minute: 5 + Rational(1,2) }.should.raise(ArgumentError)
+ end
+
+ it "raises an error for Float" do
+ -> { new_datetime minute: 5.5 }.should.raise(ArgumentError)
+ end
+
+ it "raises an error for Rational" do
+ -> { new_datetime(hour: 2 + Rational(1,2)) }.should.raise(ArgumentError)
+ end
+
+ it "raises an error, when the minute is smaller than -60" do
+ -> { new_datetime(minute: -61) }.should.raise(ArgumentError)
+ end
+
+ it "raises an error, when the minute is greater or equal than 60" do
+ -> { new_datetime(minute: 60) }.should.raise(ArgumentError)
+ end
+
+ it "raises an error for minute fractions smaller than -60" do
+ -> { new_datetime(minute: -60 - Rational(1,2))}.should.raise(ArgumentError)
+ end
end
diff --git a/spec/ruby/library/datetime/new_spec.rb b/spec/ruby/library/datetime/new_spec.rb
index 6a4dced384..2b3c3f156c 100644
--- a/spec/ruby/library/datetime/new_spec.rb
+++ b/spec/ruby/library/datetime/new_spec.rb
@@ -47,6 +47,6 @@ describe "DateTime.new" do
end
it "raises an error on invalid arguments" do
- -> { new_datetime(minute: 999) }.should raise_error(ArgumentError)
+ -> { new_datetime(minute: 999) }.should.raise(ArgumentError)
end
end
diff --git a/spec/ruby/library/datetime/now_spec.rb b/spec/ruby/library/datetime/now_spec.rb
index 9f22153c15..5c0411c2be 100644
--- a/spec/ruby/library/datetime/now_spec.rb
+++ b/spec/ruby/library/datetime/now_spec.rb
@@ -3,7 +3,7 @@ require 'date'
describe "DateTime.now" do
it "creates an instance of DateTime" do
- DateTime.now.should be_an_instance_of(DateTime)
+ DateTime.now.should.instance_of?(DateTime)
end
it "sets the current date" do
diff --git a/spec/ruby/library/datetime/parse_spec.rb b/spec/ruby/library/datetime/parse_spec.rb
index e9bf4e2ed1..0a965273a0 100644
--- a/spec/ruby/library/datetime/parse_spec.rb
+++ b/spec/ruby/library/datetime/parse_spec.rb
@@ -20,7 +20,7 @@ describe "DateTime.parse" do
# Specs using numbers
it "throws an argument error for a single digit" do
- ->{ DateTime.parse("1") }.should raise_error(ArgumentError)
+ ->{ DateTime.parse("1") }.should.raise(ArgumentError)
end
it "parses DD as month day number" do
@@ -54,23 +54,23 @@ describe "DateTime.parse" do
end
it "throws an argument error for invalid month values" do
- ->{DateTime.parse("2012-13-08T15:43:59")}.should raise_error(ArgumentError)
+ ->{DateTime.parse("2012-13-08T15:43:59")}.should.raise(ArgumentError)
end
it "throws an argument error for invalid day values" do
- ->{DateTime.parse("2012-12-32T15:43:59")}.should raise_error(ArgumentError)
+ ->{DateTime.parse("2012-12-32T15:43:59")}.should.raise(ArgumentError)
end
it "throws an argument error for invalid hour values" do
- ->{DateTime.parse("2012-12-31T25:43:59")}.should raise_error(ArgumentError)
+ ->{DateTime.parse("2012-12-31T25:43:59")}.should.raise(ArgumentError)
end
it "throws an argument error for invalid minute values" do
- ->{DateTime.parse("2012-12-31T25:43:59")}.should raise_error(ArgumentError)
+ ->{DateTime.parse("2012-12-31T25:43:59")}.should.raise(ArgumentError)
end
it "throws an argument error for invalid second values" do
- ->{DateTime.parse("2012-11-08T15:43:61")}.should raise_error(ArgumentError)
+ ->{DateTime.parse("2012-11-08T15:43:61")}.should.raise(ArgumentError)
end
end
diff --git a/spec/ruby/library/datetime/rfc2822_spec.rb b/spec/ruby/library/datetime/rfc2822_spec.rb
index 83f7fa8d5b..11b79a1e84 100644
--- a/spec/ruby/library/datetime/rfc2822_spec.rb
+++ b/spec/ruby/library/datetime/rfc2822_spec.rb
@@ -5,6 +5,6 @@ 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")
+ -> { DateTime.rfc2822(nil) }.should.raise(Date::Error, "invalid date")
end
end
diff --git a/spec/ruby/library/datetime/sec_spec.rb b/spec/ruby/library/datetime/sec_spec.rb
index f681283c8e..f8a8b4646e 100644
--- a/spec/ruby/library/datetime/sec_spec.rb
+++ b/spec/ruby/library/datetime/sec_spec.rb
@@ -1,6 +1,8 @@
require_relative '../../spec_helper'
-require_relative 'shared/sec'
+require 'date'
-describe "DateTime.sec" do
- it_behaves_like :datetime_sec, :sec
+describe "DateTime#sec" do
+ it "is an alias of DateTime#second" do
+ DateTime.instance_method(:sec).should == DateTime.instance_method(:second)
+ end
end
diff --git a/spec/ruby/library/datetime/second_fraction_spec.rb b/spec/ruby/library/datetime/second_fraction_spec.rb
index d5393149ba..70f5abf560 100644
--- a/spec/ruby/library/datetime/second_fraction_spec.rb
+++ b/spec/ruby/library/datetime/second_fraction_spec.rb
@@ -2,5 +2,7 @@ require_relative '../../spec_helper'
require 'date'
describe "DateTime#second_fraction" do
- it "needs to be reviewed for spec completeness"
+ it "is an alias of DateTime#sec_fraction" do
+ DateTime.instance_method(:second_fraction).should == DateTime.instance_method(:sec_fraction)
+ end
end
diff --git a/spec/ruby/library/datetime/second_spec.rb b/spec/ruby/library/datetime/second_spec.rb
index 545c3f9109..9fb1965b73 100644
--- a/spec/ruby/library/datetime/second_spec.rb
+++ b/spec/ruby/library/datetime/second_spec.rb
@@ -1,6 +1,45 @@
require_relative '../../spec_helper'
-require_relative 'shared/sec'
+require 'date'
describe "DateTime#second" do
- it_behaves_like :datetime_sec, :second
+ it "returns 0 seconds if passed no arguments" do
+ d = DateTime.new
+ d.second.should == 0
+ end
+
+ it "returns the seconds passed in the arguments" do
+ new_datetime(second: 5).second.should == 5
+ end
+
+ it "adds 60 to negative values" do
+ new_datetime(second: -20).second.should == 40
+ end
+
+ it "returns the absolute value of a Rational" do
+ new_datetime(second: 5 + Rational(1,2)).second.should == 5
+ end
+
+ it "returns the absolute value of a float" do
+ new_datetime(second: 5.5).second.should == 5
+ end
+
+ it "raises an error when minute is given as a rational" do
+ -> { new_datetime(minute: 5 + Rational(1,2)) }.should.raise(ArgumentError)
+ end
+
+ it "raises an error, when the second is smaller than -60" do
+ -> { new_datetime(second: -61) }.should.raise(ArgumentError)
+ end
+
+ it "raises an error, when the second is greater or equal than 60" do
+ -> { new_datetime(second: 60) }.should.raise(ArgumentError)
+ end
+
+ it "raises an error for second fractions smaller than -60" do
+ -> { new_datetime(second: -60 - Rational(1,2))}.should.raise(ArgumentError)
+ end
+
+ it "takes a second fraction near 60" do
+ new_datetime(second: 59 + Rational(1,2)).second.should == 59
+ end
end
diff --git a/spec/ruby/library/datetime/shared/min.rb b/spec/ruby/library/datetime/shared/min.rb
deleted file mode 100644
index a35b839281..0000000000
--- a/spec/ruby/library/datetime/shared/min.rb
+++ /dev/null
@@ -1,40 +0,0 @@
-require 'date'
-
-describe :datetime_min, shared: true do
- it "returns 0 if no argument is passed" do
- DateTime.new.send(@method).should == 0
- end
-
- it "returns the minute passed as argument" do
- new_datetime(minute: 5).send(@method).should == 5
- end
-
- it "adds 60 to negative minutes" do
- new_datetime(minute: -20).send(@method).should == 40
- end
-
- it "raises an error for Rational" do
- -> { new_datetime minute: 5 + Rational(1,2) }.should raise_error(ArgumentError)
- end
-
- it "raises an error for Float" do
- -> { new_datetime minute: 5.5 }.should raise_error(ArgumentError)
- end
-
- it "raises an error for Rational" do
- -> { new_datetime(hour: 2 + Rational(1,2)) }.should raise_error(ArgumentError)
- end
-
- it "raises an error, when the minute is smaller than -60" do
- -> { new_datetime(minute: -61) }.should raise_error(ArgumentError)
- end
-
- it "raises an error, when the minute is greater or equal than 60" do
- -> { new_datetime(minute: 60) }.should raise_error(ArgumentError)
- end
-
- it "raises an error for minute fractions smaller than -60" do
- -> { new_datetime(minute: -60 - Rational(1,2))}.should(
- raise_error(ArgumentError))
- end
-end
diff --git a/spec/ruby/library/datetime/shared/sec.rb b/spec/ruby/library/datetime/shared/sec.rb
deleted file mode 100644
index 60009213aa..0000000000
--- a/spec/ruby/library/datetime/shared/sec.rb
+++ /dev/null
@@ -1,45 +0,0 @@
-require 'date'
-
-describe :datetime_sec, shared: true do
- it "returns 0 seconds if passed no arguments" do
- d = DateTime.new
- d.send(@method).should == 0
- end
-
- it "returns the seconds passed in the arguments" do
- new_datetime(second: 5).send(@method).should == 5
- end
-
- it "adds 60 to negative values" do
- new_datetime(second: -20).send(@method).should == 40
- end
-
- it "returns the absolute value of a Rational" do
- new_datetime(second: 5 + Rational(1,2)).send(@method).should == 5
- end
-
- it "returns the absolute value of a float" do
- new_datetime(second: 5.5).send(@method).should == 5
- end
-
- it "raises an error when minute is given as a rational" do
- -> { new_datetime(minute: 5 + Rational(1,2)) }.should raise_error(ArgumentError)
- end
-
- it "raises an error, when the second is smaller than -60" do
- -> { new_datetime(second: -61) }.should raise_error(ArgumentError)
- end
-
- it "raises an error, when the second is greater or equal than 60" do
- -> { new_datetime(second: 60) }.should raise_error(ArgumentError)
- end
-
- it "raises an error for second fractions smaller than -60" do
- -> { new_datetime(second: -60 - Rational(1,2))}.should(
- raise_error(ArgumentError))
- end
-
- it "takes a second fraction near 60" do
- new_datetime(second: 59 + Rational(1,2)).send(@method).should == 59
- end
-end
diff --git a/spec/ruby/library/datetime/to_date_spec.rb b/spec/ruby/library/datetime/to_date_spec.rb
index 48c05e7fed..31ccf5ae98 100644
--- a/spec/ruby/library/datetime/to_date_spec.rb
+++ b/spec/ruby/library/datetime/to_date_spec.rb
@@ -4,7 +4,7 @@ require 'date'
describe "DateTime#to_date" do
it "returns an instance of Date" do
dt = DateTime.new(2012, 12, 24, 12, 23, 00, '+05:00')
- dt.to_date.should be_kind_of(Date)
+ dt.to_date.should.is_a?(Date)
end
it "maintains the same year" do
diff --git a/spec/ruby/library/datetime/to_s_spec.rb b/spec/ruby/library/datetime/to_s_spec.rb
index 175fb807f4..ed0746f42b 100644
--- a/spec/ruby/library/datetime/to_s_spec.rb
+++ b/spec/ruby/library/datetime/to_s_spec.rb
@@ -4,7 +4,7 @@ require 'date'
describe "DateTime#to_s" do
it "returns a new String object" do
dt = DateTime.new(2012, 12, 24, 1, 2, 3, "+03:00")
- dt.to_s.should be_kind_of(String)
+ dt.to_s.should.is_a?(String)
end
it "maintains timezone regardless of local time" do
diff --git a/spec/ruby/library/datetime/to_time_spec.rb b/spec/ruby/library/datetime/to_time_spec.rb
index 58bb363653..a3ffc019fb 100644
--- a/spec/ruby/library/datetime/to_time_spec.rb
+++ b/spec/ruby/library/datetime/to_time_spec.rb
@@ -4,7 +4,7 @@ date_version = defined?(Date::VERSION) ? Date::VERSION : '3.1.0'
describe "DateTime#to_time" do
it "yields a new Time object" do
- DateTime.now.to_time.should be_kind_of(Time)
+ DateTime.now.to_time.should.is_a?(Time)
end
it "returns a Time representing the same instant" do
diff --git a/spec/ruby/library/delegate/delegate_class/instance_method_spec.rb b/spec/ruby/library/delegate/delegate_class/instance_method_spec.rb
index 16bf8d734c..19ffc4cf85 100644
--- a/spec/ruby/library/delegate/delegate_class/instance_method_spec.rb
+++ b/spec/ruby/library/delegate/delegate_class/instance_method_spec.rb
@@ -9,44 +9,44 @@ describe "DelegateClass.instance_method" do
it "returns a method object for public instance methods of the delegated class" do
m = @klass.instance_method(:pub)
- m.should be_an_instance_of(UnboundMethod)
+ m.should.instance_of?(UnboundMethod)
m.bind(@obj).call.should == :foo
end
it "returns a method object for protected instance methods of the delegated class" do
m = @klass.instance_method(:prot)
- m.should be_an_instance_of(UnboundMethod)
+ m.should.instance_of?(UnboundMethod)
m.bind(@obj).call.should == :protected
end
it "raises a NameError for a private instance methods of the delegated class" do
-> {
@klass.instance_method(:priv)
- }.should raise_error(NameError)
+ }.should.raise(NameError)
end
it "returns a method object for public instance methods of the DelegateClass class" do
m = @klass.instance_method(:extra)
- m.should be_an_instance_of(UnboundMethod)
+ m.should.instance_of?(UnboundMethod)
m.bind(@obj).call.should == :cheese
end
it "returns a method object for protected instance methods of the DelegateClass class" do
m = @klass.instance_method(:extra_protected)
- m.should be_an_instance_of(UnboundMethod)
+ m.should.instance_of?(UnboundMethod)
m.bind(@obj).call.should == :baz
end
it "returns a method object for private instance methods of the DelegateClass class" do
m = @klass.instance_method(:extra_private)
- m.should be_an_instance_of(UnboundMethod)
+ m.should.instance_of?(UnboundMethod)
m.bind(@obj).call.should == :bar
end
it "raises a NameError for an invalid method name" do
-> {
@klass.instance_method(:invalid_and_silly_method_name)
- }.should raise_error(NameError)
+ }.should.raise(NameError)
end
end
diff --git a/spec/ruby/library/delegate/delegate_class/instance_methods_spec.rb b/spec/ruby/library/delegate/delegate_class/instance_methods_spec.rb
index 6012ff72de..586be56cae 100644
--- a/spec/ruby/library/delegate/delegate_class/instance_methods_spec.rb
+++ b/spec/ruby/library/delegate/delegate_class/instance_methods_spec.rb
@@ -7,20 +7,20 @@ describe "DelegateClass.instance_methods" do
end
it "includes all public methods of the delegated class" do
- @methods.should include :pub
+ @methods.should.include? :pub
end
it "includes all protected methods of the delegated class" do
- @methods.should include :prot
+ @methods.should.include? :prot
end
it "includes instance methods of the DelegateClass class" do
- @methods.should include :extra
- @methods.should include :extra_protected
+ @methods.should.include? :extra
+ @methods.should.include? :extra_protected
end
it "does not include private methods" do
- @methods.should_not include :priv
- @methods.should_not include :extra_private
+ @methods.should_not.include? :priv
+ @methods.should_not.include? :extra_private
end
end
diff --git a/spec/ruby/library/delegate/delegate_class/private_instance_methods_spec.rb b/spec/ruby/library/delegate/delegate_class/private_instance_methods_spec.rb
index 06b2115cc5..18ca2a4c88 100644
--- a/spec/ruby/library/delegate/delegate_class/private_instance_methods_spec.rb
+++ b/spec/ruby/library/delegate/delegate_class/private_instance_methods_spec.rb
@@ -7,17 +7,17 @@ describe "DelegateClass.private_instance_methods" do
end
it "does not include any instance methods of the delegated class" do
- @methods.should_not include :pub
- @methods.should_not include :prot
- @methods.should_not include :priv # since these are not forwarded...
+ @methods.should_not.include? :pub
+ @methods.should_not.include? :prot
+ @methods.should_not.include? :priv # since these are not forwarded...
end
it "includes private instance methods of the DelegateClass class" do
- @methods.should include :extra_private
+ @methods.should.include? :extra_private
end
it "does not include public or protected instance methods of the DelegateClass class" do
- @methods.should_not include :extra
- @methods.should_not include :extra_protected
+ @methods.should_not.include? :extra
+ @methods.should_not.include? :extra_protected
end
end
diff --git a/spec/ruby/library/delegate/delegate_class/protected_instance_methods_spec.rb b/spec/ruby/library/delegate/delegate_class/protected_instance_methods_spec.rb
index ac6659ec1e..d540b45065 100644
--- a/spec/ruby/library/delegate/delegate_class/protected_instance_methods_spec.rb
+++ b/spec/ruby/library/delegate/delegate_class/protected_instance_methods_spec.rb
@@ -7,23 +7,23 @@ describe "DelegateClass.protected_instance_methods" do
end
it "does not include public methods of the delegated class" do
- @methods.should_not include :pub
+ @methods.should_not.include? :pub
end
it "includes the protected methods of the delegated class" do
- @methods.should include :prot
+ @methods.should.include? :prot
end
it "includes protected instance methods of the DelegateClass class" do
- @methods.should include :extra_protected
+ @methods.should.include? :extra_protected
end
it "does not include public instance methods of the DelegateClass class" do
- @methods.should_not include :extra
+ @methods.should_not.include? :extra
end
it "does not include private methods" do
- @methods.should_not include :priv
- @methods.should_not include :extra_private
+ @methods.should_not.include? :priv
+ @methods.should_not.include? :extra_private
end
end
diff --git a/spec/ruby/library/delegate/delegate_class/public_instance_methods_spec.rb b/spec/ruby/library/delegate/delegate_class/public_instance_methods_spec.rb
index 6c0d9bcab1..124b92de82 100644
--- a/spec/ruby/library/delegate/delegate_class/public_instance_methods_spec.rb
+++ b/spec/ruby/library/delegate/delegate_class/public_instance_methods_spec.rb
@@ -7,19 +7,19 @@ describe "DelegateClass.public_instance_methods" do
end
it "includes all public methods of the delegated class" do
- @methods.should include :pub
+ @methods.should.include? :pub
end
it "does not include the protected methods of the delegated class" do
- @methods.should_not include :prot
+ @methods.should_not.include? :prot
end
it "includes public instance methods of the DelegateClass class" do
- @methods.should include :extra
+ @methods.should.include? :extra
end
it "does not include private methods" do
- @methods.should_not include :priv
- @methods.should_not include :extra_private
+ @methods.should_not.include? :priv
+ @methods.should_not.include? :extra_private
end
end
diff --git a/spec/ruby/library/delegate/delegator/eql_spec.rb b/spec/ruby/library/delegate/delegator/eql_spec.rb
index 34f56f44c9..b302bb7016 100644
--- a/spec/ruby/library/delegate/delegator/eql_spec.rb
+++ b/spec/ruby/library/delegate/delegator/eql_spec.rb
@@ -6,14 +6,14 @@ describe "Delegator#eql?" do
base = mock('base')
delegator = DelegateSpecs::Delegator.new(base)
- delegator.eql?(delegator).should be_true
+ delegator.eql?(delegator).should == true
end
it "returns true when compared with the inner object" do
base = mock('base')
delegator = DelegateSpecs::Delegator.new(base)
- delegator.eql?(base).should be_true
+ delegator.eql?(base).should == true
end
it "returns false when compared with the delegator with other object" do
@@ -22,7 +22,7 @@ describe "Delegator#eql?" do
delegator0 = DelegateSpecs::Delegator.new(base)
delegator1 = DelegateSpecs::Delegator.new(other)
- delegator0.eql?(delegator1).should be_false
+ delegator0.eql?(delegator1).should == false
end
it "returns false when compared with the other object" do
@@ -30,6 +30,6 @@ describe "Delegator#eql?" do
other = mock('other')
delegator = DelegateSpecs::Delegator.new(base)
- delegator.eql?(other).should be_false
+ delegator.eql?(other).should == false
end
end
diff --git a/spec/ruby/library/delegate/delegator/equal_spec.rb b/spec/ruby/library/delegate/delegator/equal_spec.rb
index c8711c74b5..97aabebabe 100644
--- a/spec/ruby/library/delegate/delegator/equal_spec.rb
+++ b/spec/ruby/library/delegate/delegator/equal_spec.rb
@@ -6,8 +6,8 @@ describe "Delegator#equal?" do
obj = mock('base')
delegator = DelegateSpecs::Delegator.new(obj)
obj.should_not_receive(:equal?)
- delegator.equal?(obj).should be_false
- delegator.equal?(nil).should be_false
- delegator.equal?(delegator).should be_true
+ delegator.equal?(obj).should == false
+ delegator.equal?(nil).should == false
+ delegator.equal?(delegator).should == true
end
end
diff --git a/spec/ruby/library/delegate/delegator/equal_value_spec.rb b/spec/ruby/library/delegate/delegator/equal_value_spec.rb
index 0c967d5f94..d70aad1e03 100644
--- a/spec/ruby/library/delegate/delegator/equal_value_spec.rb
+++ b/spec/ruby/library/delegate/delegator/equal_value_spec.rb
@@ -9,16 +9,16 @@ describe "Delegator#==" do
it "is not delegated when passed self" do
@base.should_not_receive(:==)
- (@delegator == @delegator).should be_true
+ (@delegator == @delegator).should == true
end
it "is delegated when passed the delegated object" do
@base.should_receive(:==).and_return(false)
- (@delegator == @base).should be_false
+ (@delegator == @base).should == false
end
it "is delegated in general" do
@base.should_receive(:==).and_return(true)
- (@delegator == 42).should be_true
+ (@delegator == 42).should == true
end
end
diff --git a/spec/ruby/library/delegate/delegator/frozen_spec.rb b/spec/ruby/library/delegate/delegator/frozen_spec.rb
index b3145c54b1..ad87dc8bdf 100644
--- a/spec/ruby/library/delegate/delegator/frozen_spec.rb
+++ b/spec/ruby/library/delegate/delegator/frozen_spec.rb
@@ -10,30 +10,30 @@ describe "Delegator when frozen" do
it "is still readable" do
@delegate.should == [42, :hello]
- @delegate.include?("bar").should be_false
+ @delegate.include?("bar").should == false
end
it "is frozen" do
- @delegate.frozen?.should be_true
+ @delegate.frozen?.should == true
end
it "is not writable" do
- ->{ @delegate[0] += 2 }.should raise_error( RuntimeError )
+ ->{ @delegate[0] += 2 }.should.raise( RuntimeError )
end
it "creates a frozen clone" do
- @delegate.clone.frozen?.should be_true
+ @delegate.clone.frozen?.should == true
end
it "creates an unfrozen dup" do
- @delegate.dup.frozen?.should be_false
+ @delegate.dup.frozen?.should == false
end
it "causes mutative calls to raise RuntimeError" do
- ->{ @delegate.__setobj__("hola!") }.should raise_error( RuntimeError )
+ ->{ @delegate.__setobj__("hola!") }.should.raise( RuntimeError )
end
it "returns false if only the delegated object is frozen" do
- DelegateSpecs::Delegator.new([1,2,3].freeze).frozen?.should be_false
+ DelegateSpecs::Delegator.new([1,2,3].freeze).frozen?.should == false
end
end
diff --git a/spec/ruby/library/delegate/delegator/marshal_spec.rb b/spec/ruby/library/delegate/delegator/marshal_spec.rb
index 6c75c8f573..2817ac7e0b 100644
--- a/spec/ruby/library/delegate/delegator/marshal_spec.rb
+++ b/spec/ruby/library/delegate/delegator/marshal_spec.rb
@@ -10,7 +10,7 @@ describe "SimpleDelegator" do
it "can be marshalled" do
m = Marshal.load(Marshal.dump(@delegate))
m.class.should == SimpleDelegator
- (m == @obj).should be_true
+ (m == @obj).should == true
end
it "can be marshalled with its instance variables intact" do
diff --git a/spec/ruby/library/delegate/delegator/method_spec.rb b/spec/ruby/library/delegate/delegator/method_spec.rb
index 81c8eea710..e41d3b4a53 100644
--- a/spec/ruby/library/delegate/delegator/method_spec.rb
+++ b/spec/ruby/library/delegate/delegator/method_spec.rb
@@ -9,7 +9,7 @@ describe "Delegator#method" do
it "returns a method object for public methods of the delegate object" do
m = @delegate.method(:pub)
- m.should be_an_instance_of(Method)
+ m.should.instance_of?(Method)
m.call.should == :foo
end
@@ -18,7 +18,7 @@ describe "Delegator#method" do
-> {
@delegate.method(:prot)
}.should complain(/delegator does not forward private method #prot/)
- }.should raise_error(NameError)
+ }.should.raise(NameError)
end
it "raises a NameError for a private methods of the delegate object" do
@@ -26,36 +26,36 @@ describe "Delegator#method" do
-> {
@delegate.method(:priv)
}.should complain(/delegator does not forward private method #priv/)
- }.should raise_error(NameError)
+ }.should.raise(NameError)
end
it "returns a method object for public methods of the Delegator class" do
m = @delegate.method(:extra)
- m.should be_an_instance_of(Method)
+ m.should.instance_of?(Method)
m.call.should == :cheese
end
it "returns a method object for protected methods of the Delegator class" do
m = @delegate.method(:extra_protected)
- m.should be_an_instance_of(Method)
+ m.should.instance_of?(Method)
m.call.should == :baz
end
it "returns a method object for private methods of the Delegator class" do
m = @delegate.method(:extra_private)
- m.should be_an_instance_of(Method)
+ m.should.instance_of?(Method)
m.call.should == :bar
end
it "raises a NameError for an invalid method name" do
-> {
@delegate.method(:invalid_and_silly_method_name)
- }.should raise_error(NameError)
+ }.should.raise(NameError)
end
it "returns a method that respond_to_missing?" do
m = @delegate.method(:pub_too)
- m.should be_an_instance_of(Method)
+ m.should.instance_of?(Method)
m.call.should == :pub_too
end
@@ -64,6 +64,6 @@ describe "Delegator#method" do
@delegate.__setobj__([1,2,3])
-> {
m.call
- }.should raise_error(NameError)
+ }.should.raise(NameError)
end
end
diff --git a/spec/ruby/library/delegate/delegator/methods_spec.rb b/spec/ruby/library/delegate/delegator/methods_spec.rb
index b9942bd230..928f63f21d 100644
--- a/spec/ruby/library/delegate/delegator/methods_spec.rb
+++ b/spec/ruby/library/delegate/delegator/methods_spec.rb
@@ -14,24 +14,24 @@ describe "Delegator#methods" do
end
it "returns singleton methods when passed false" do
- @delegate.methods(false).should include(:singleton_method)
+ @delegate.methods(false).should.include?(:singleton_method)
end
it "includes all public methods of the delegate object" do
- @methods.should include :pub
+ @methods.should.include? :pub
end
it "includes all protected methods of the delegate object" do
- @methods.should include :prot
+ @methods.should.include? :prot
end
it "includes instance methods of the Delegator class" do
- @methods.should include :extra
- @methods.should include :extra_protected
+ @methods.should.include? :extra
+ @methods.should.include? :extra_protected
end
it "does not include private methods" do
- @methods.should_not include :priv
- @methods.should_not include :extra_private
+ @methods.should_not.include? :priv
+ @methods.should_not.include? :extra_private
end
end
diff --git a/spec/ruby/library/delegate/delegator/not_equal_spec.rb b/spec/ruby/library/delegate/delegator/not_equal_spec.rb
index 6f2df21715..7fd234a671 100644
--- a/spec/ruby/library/delegate/delegator/not_equal_spec.rb
+++ b/spec/ruby/library/delegate/delegator/not_equal_spec.rb
@@ -9,16 +9,16 @@ describe "Delegator#!=" do
it "is not delegated when passed self" do
@base.should_not_receive(:"!=")
- (@delegator != @delegator).should be_false
+ (@delegator != @delegator).should == false
end
it "is delegated when passed the delegated object" do
@base.should_receive(:"!=").and_return(true)
- (@delegator != @base).should be_true
+ (@delegator != @base).should == true
end
it "is delegated in general" do
@base.should_receive(:"!=").and_return(false)
- (@delegator != 42).should be_false
+ (@delegator != 42).should == false
end
end
diff --git a/spec/ruby/library/delegate/delegator/private_methods_spec.rb b/spec/ruby/library/delegate/delegator/private_methods_spec.rb
index 7724b8d413..5615ed0668 100644
--- a/spec/ruby/library/delegate/delegator/private_methods_spec.rb
+++ b/spec/ruby/library/delegate/delegator/private_methods_spec.rb
@@ -9,12 +9,12 @@ describe "Delegator#private_methods" do
end
it "does not include any method of the delegate object" do # since delegates does not forward private calls
- @methods.should_not include :priv
- @methods.should_not include :prot
- @methods.should_not include :pub
+ @methods.should_not.include? :priv
+ @methods.should_not.include? :prot
+ @methods.should_not.include? :pub
end
it "includes all private instance methods of the Delegate class" do
- @methods.should include :extra_private
+ @methods.should.include? :extra_private
end
end
diff --git a/spec/ruby/library/delegate/delegator/protected_methods_spec.rb b/spec/ruby/library/delegate/delegator/protected_methods_spec.rb
index fd7874fb21..3ee999fdac 100644
--- a/spec/ruby/library/delegate/delegator/protected_methods_spec.rb
+++ b/spec/ruby/library/delegate/delegator/protected_methods_spec.rb
@@ -9,10 +9,10 @@ describe "Delegator#protected_methods" do
end
it "includes protected methods of the delegate object" do
- @methods.should include :prot
+ @methods.should.include? :prot
end
it "includes protected instance methods of the Delegator class" do
- @methods.should include :extra_protected
+ @methods.should.include? :extra_protected
end
end
diff --git a/spec/ruby/library/delegate/delegator/public_methods_spec.rb b/spec/ruby/library/delegate/delegator/public_methods_spec.rb
index 18da16a613..8cf6621e2d 100644
--- a/spec/ruby/library/delegate/delegator/public_methods_spec.rb
+++ b/spec/ruby/library/delegate/delegator/public_methods_spec.rb
@@ -9,10 +9,10 @@ describe "Delegator#public_methods" do
end
it "includes public methods of the delegate object" do
- @methods.should include :pub
+ @methods.should.include? :pub
end
it "includes public instance methods of the Delegator class" do
- @methods.should include :extra
+ @methods.should.include? :extra
end
end
diff --git a/spec/ruby/library/delegate/delegator/send_spec.rb b/spec/ruby/library/delegate/delegator/send_spec.rb
index 3022c2ce91..cc18a2794b 100644
--- a/spec/ruby/library/delegate/delegator/send_spec.rb
+++ b/spec/ruby/library/delegate/delegator/send_spec.rb
@@ -12,15 +12,15 @@ describe "SimpleDelegator.new" do
end
it "forwards protected method calls" do
- ->{ @delegate.prot }.should raise_error( NoMethodError )
+ ->{ @delegate.prot }.should.raise( NoMethodError )
end
it "doesn't forward private method calls" do
- ->{ @delegate.priv }.should raise_error( NoMethodError )
+ ->{ @delegate.priv }.should.raise( NoMethodError )
end
it "doesn't forward private method calls even via send or __send__" do
- ->{ @delegate.send(:priv, 42) }.should raise_error( NoMethodError )
- ->{ @delegate.__send__(:priv, 42) }.should raise_error( NoMethodError )
+ ->{ @delegate.send(:priv, 42) }.should.raise( NoMethodError )
+ ->{ @delegate.__send__(:priv, 42) }.should.raise( NoMethodError )
end
end
diff --git a/spec/ruby/library/delegate/delegator/tap_spec.rb b/spec/ruby/library/delegate/delegator/tap_spec.rb
index 34a88fa1d5..916e4a37fe 100644
--- a/spec/ruby/library/delegate/delegator/tap_spec.rb
+++ b/spec/ruby/library/delegate/delegator/tap_spec.rb
@@ -11,6 +11,6 @@ describe "Delegator#tap" do
yielded << x
end
yielded.size.should == 1
- yielded[0].equal?(delegator).should be_true
+ yielded[0].equal?(delegator).should == true
end
end
diff --git a/spec/ruby/library/digest/bubblebabble_spec.rb b/spec/ruby/library/digest/bubblebabble_spec.rb
index bbc11ceec5..44a9bf0e26 100644
--- a/spec/ruby/library/digest/bubblebabble_spec.rb
+++ b/spec/ruby/library/digest/bubblebabble_spec.rb
@@ -3,7 +3,7 @@ require 'digest/bubblebabble'
describe "Digest.bubblebabble" do
it "returns a String" do
- Digest.bubblebabble('').should be_an_instance_of(String)
+ Digest.bubblebabble('').should.instance_of?(String)
end
it "returns a String in the Bubble Babble Binary Data Encoding format" do
@@ -20,10 +20,10 @@ describe "Digest.bubblebabble" do
end
it "raises a TypeError when passed nil" do
- -> { Digest.bubblebabble(nil) }.should raise_error(TypeError)
+ -> { Digest.bubblebabble(nil) }.should.raise(TypeError)
end
it "raises a TypeError when passed an Integer" do
- -> { Digest.bubblebabble(9001) }.should raise_error(TypeError)
+ -> { Digest.bubblebabble(9001) }.should.raise(TypeError)
end
end
diff --git a/spec/ruby/library/digest/hexencode_spec.rb b/spec/ruby/library/digest/hexencode_spec.rb
index 4b6db6eaff..3359303d15 100644
--- a/spec/ruby/library/digest/hexencode_spec.rb
+++ b/spec/ruby/library/digest/hexencode_spec.rb
@@ -22,10 +22,10 @@ describe "Digest.hexencode" do
end
it "raises a TypeError when passed nil" do
- -> { Digest.hexencode(nil) }.should raise_error(TypeError)
+ -> { Digest.hexencode(nil) }.should.raise(TypeError)
end
it "raises a TypeError when passed an Integer" do
- -> { Digest.hexencode(9001) }.should raise_error(TypeError)
+ -> { Digest.hexencode(9001) }.should.raise(TypeError)
end
end
diff --git a/spec/ruby/library/digest/instance/append_spec.rb b/spec/ruby/library/digest/instance/append_spec.rb
index 2499579298..7f4ce3d121 100644
--- a/spec/ruby/library/digest/instance/append_spec.rb
+++ b/spec/ruby/library/digest/instance/append_spec.rb
@@ -1,7 +1,11 @@
require_relative '../../../spec_helper'
require 'digest'
-require_relative 'shared/update'
describe "Digest::Instance#<<" do
- it_behaves_like :digest_instance_update, :<<
+ it "raises a RuntimeError if called" do
+ c = Class.new do
+ include Digest::Instance
+ end
+ -> { c.new << "test" }.should.raise(RuntimeError)
+ end
end
diff --git a/spec/ruby/library/digest/instance/shared/update.rb b/spec/ruby/library/digest/instance/shared/update.rb
deleted file mode 100644
index 17779e54a4..0000000000
--- a/spec/ruby/library/digest/instance/shared/update.rb
+++ /dev/null
@@ -1,8 +0,0 @@
-describe :digest_instance_update, shared: true do
- it "raises a RuntimeError if called" do
- c = Class.new do
- include Digest::Instance
- end
- -> { c.new.send(@method, "test") }.should raise_error(RuntimeError)
- end
-end
diff --git a/spec/ruby/library/digest/instance/update_spec.rb b/spec/ruby/library/digest/instance/update_spec.rb
index 3bb4dd7f1b..d15b976213 100644
--- a/spec/ruby/library/digest/instance/update_spec.rb
+++ b/spec/ruby/library/digest/instance/update_spec.rb
@@ -1,7 +1,8 @@
require_relative '../../../spec_helper'
require 'digest'
-require_relative 'shared/update'
describe "Digest::Instance#update" do
- it_behaves_like :digest_instance_update, :update
+ it "is an alias of Digest::Instance#<<" do
+ Digest::Instance.instance_method(:update).should == Digest::Instance.instance_method(:<<)
+ end
end
diff --git a/spec/ruby/library/digest/md5/append_spec.rb b/spec/ruby/library/digest/md5/append_spec.rb
index 0abdc074a1..6f42e4f286 100644
--- a/spec/ruby/library/digest/md5/append_spec.rb
+++ b/spec/ruby/library/digest/md5/append_spec.rb
@@ -1,7 +1,10 @@
require_relative '../../../spec_helper'
require_relative 'shared/constants'
-require_relative 'shared/update'
describe "Digest::MD5#<<" do
- it_behaves_like :md5_update, :<<
+ it "can update" do
+ cur_digest = Digest::MD5.new
+ cur_digest << MD5Constants::Contents
+ cur_digest.digest.should == MD5Constants::Digest
+ end
end
diff --git a/spec/ruby/library/digest/md5/file_spec.rb b/spec/ruby/library/digest/md5/file_spec.rb
index 0c8d12cbc9..9a78a8c055 100644
--- a/spec/ruby/library/digest/md5/file_spec.rb
+++ b/spec/ruby/library/digest/md5/file_spec.rb
@@ -15,7 +15,7 @@ describe "Digest::MD5.file" do
end
it "returns a Digest::MD5 object" do
- Digest::MD5.file(@file).should be_kind_of(Digest::MD5)
+ Digest::MD5.file(@file).should.is_a?(Digest::MD5)
end
it "returns a Digest::MD5 object with the correct digest" do
@@ -26,7 +26,7 @@ describe "Digest::MD5.file" do
obj = mock("to_str")
obj.should_receive(:to_str).and_return(@file)
result = Digest::MD5.file(obj)
- result.should be_kind_of(Digest::MD5)
+ result.should.is_a?(Digest::MD5)
result.digest.should == MD5Constants::Digest
end
end
@@ -34,10 +34,10 @@ describe "Digest::MD5.file" do
it_behaves_like :file_read_directory, :file, Digest::MD5
it "raises a Errno::ENOENT when passed a path that does not exist" do
- -> { Digest::MD5.file("") }.should raise_error(Errno::ENOENT)
+ -> { Digest::MD5.file("") }.should.raise(Errno::ENOENT)
end
it "raises a TypeError when passed nil" do
- -> { Digest::MD5.file(nil) }.should raise_error(TypeError)
+ -> { Digest::MD5.file(nil) }.should.raise(TypeError)
end
end
diff --git a/spec/ruby/library/digest/md5/length_spec.rb b/spec/ruby/library/digest/md5/length_spec.rb
index b05b2a20fd..18bda51129 100644
--- a/spec/ruby/library/digest/md5/length_spec.rb
+++ b/spec/ruby/library/digest/md5/length_spec.rb
@@ -1,7 +1,11 @@
require_relative '../../../spec_helper'
require_relative 'shared/constants'
-require_relative 'shared/length'
describe "Digest::MD5#length" do
- it_behaves_like :md5_length, :length
+ it "returns the length of the digest" do
+ cur_digest = Digest::MD5.new
+ cur_digest.length.should == MD5Constants::BlankDigest.size
+ cur_digest << MD5Constants::Contents
+ cur_digest.length.should == MD5Constants::Digest.size
+ end
end
diff --git a/spec/ruby/library/digest/md5/shared/length.rb b/spec/ruby/library/digest/md5/shared/length.rb
deleted file mode 100644
index c5b2b97b58..0000000000
--- a/spec/ruby/library/digest/md5/shared/length.rb
+++ /dev/null
@@ -1,8 +0,0 @@
-describe :md5_length, shared: true do
- it "returns the length of the digest" do
- cur_digest = Digest::MD5.new
- cur_digest.send(@method).should == MD5Constants::BlankDigest.size
- cur_digest << MD5Constants::Contents
- cur_digest.send(@method).should == MD5Constants::Digest.size
- end
-end
diff --git a/spec/ruby/library/digest/md5/shared/update.rb b/spec/ruby/library/digest/md5/shared/update.rb
deleted file mode 100644
index be8622aed5..0000000000
--- a/spec/ruby/library/digest/md5/shared/update.rb
+++ /dev/null
@@ -1,7 +0,0 @@
-describe :md5_update, shared: true do
- it "can update" do
- cur_digest = Digest::MD5.new
- cur_digest.send @method, MD5Constants::Contents
- cur_digest.digest.should == MD5Constants::Digest
- end
-end
diff --git a/spec/ruby/library/digest/md5/size_spec.rb b/spec/ruby/library/digest/md5/size_spec.rb
index 22e3272d36..54709234de 100644
--- a/spec/ruby/library/digest/md5/size_spec.rb
+++ b/spec/ruby/library/digest/md5/size_spec.rb
@@ -1,7 +1,8 @@
require_relative '../../../spec_helper'
require_relative 'shared/constants'
-require_relative 'shared/length'
describe "Digest::MD5#size" do
- it_behaves_like :md5_length, :size
+ it "is an alias of Digest::MD5#length" do
+ Digest::MD5.instance_method(:size).should == Digest::MD5.instance_method(:length)
+ end
end
diff --git a/spec/ruby/library/digest/md5/update_spec.rb b/spec/ruby/library/digest/md5/update_spec.rb
index 4773db308c..830ccfead6 100644
--- a/spec/ruby/library/digest/md5/update_spec.rb
+++ b/spec/ruby/library/digest/md5/update_spec.rb
@@ -1,7 +1,8 @@
require_relative '../../../spec_helper'
-require_relative 'shared/constants'
-require_relative 'shared/update'
+require 'digest'
describe "Digest::MD5#update" do
- it_behaves_like :md5_update, :update
+ it "is an alias of Digest::MD5#<<" do
+ Digest::MD5.instance_method(:update).should == Digest::MD5.instance_method(:<<)
+ end
end
diff --git a/spec/ruby/library/digest/sha1/file_spec.rb b/spec/ruby/library/digest/sha1/file_spec.rb
index 9c15f5b02f..d36e560e21 100644
--- a/spec/ruby/library/digest/sha1/file_spec.rb
+++ b/spec/ruby/library/digest/sha1/file_spec.rb
@@ -15,7 +15,7 @@ describe "Digest::SHA1.file" do
end
it "returns a Digest::SHA1 object" do
- Digest::SHA1.file(@file).should be_kind_of(Digest::SHA1)
+ Digest::SHA1.file(@file).should.is_a?(Digest::SHA1)
end
it "returns a Digest::SHA1 object with the correct digest" do
@@ -26,7 +26,7 @@ describe "Digest::SHA1.file" do
obj = mock("to_str")
obj.should_receive(:to_str).and_return(@file)
result = Digest::SHA1.file(obj)
- result.should be_kind_of(Digest::SHA1)
+ result.should.is_a?(Digest::SHA1)
result.digest.should == SHA1Constants::Digest
end
end
@@ -34,10 +34,10 @@ describe "Digest::SHA1.file" do
it_behaves_like :file_read_directory, :file, Digest::SHA1
it "raises a Errno::ENOENT when passed a path that does not exist" do
- -> { Digest::SHA1.file("") }.should raise_error(Errno::ENOENT)
+ -> { Digest::SHA1.file("") }.should.raise(Errno::ENOENT)
end
it "raises a TypeError when passed nil" do
- -> { Digest::SHA1.file(nil) }.should raise_error(TypeError)
+ -> { Digest::SHA1.file(nil) }.should.raise(TypeError)
end
end
diff --git a/spec/ruby/library/digest/sha256/append_spec.rb b/spec/ruby/library/digest/sha256/append_spec.rb
index ab594c105f..f18b06c2a1 100644
--- a/spec/ruby/library/digest/sha256/append_spec.rb
+++ b/spec/ruby/library/digest/sha256/append_spec.rb
@@ -1,7 +1,10 @@
require_relative '../../../spec_helper'
require_relative 'shared/constants'
-require_relative 'shared/update'
describe "Digest::SHA256#<<" do
- it_behaves_like :sha256_update, :<<
+ it "can update" do
+ cur_digest = Digest::SHA256.new
+ cur_digest << SHA256Constants::Contents
+ cur_digest.digest.should == SHA256Constants::Digest
+ end
end
diff --git a/spec/ruby/library/digest/sha256/file_spec.rb b/spec/ruby/library/digest/sha256/file_spec.rb
index 8cbc5a2755..d67a9ebcd6 100644
--- a/spec/ruby/library/digest/sha256/file_spec.rb
+++ b/spec/ruby/library/digest/sha256/file_spec.rb
@@ -15,7 +15,7 @@ describe "Digest::SHA256.file" do
end
it "returns a Digest::SHA256 object" do
- Digest::SHA256.file(@file).should be_kind_of(Digest::SHA256)
+ Digest::SHA256.file(@file).should.is_a?(Digest::SHA256)
end
it "returns a Digest::SHA256 object with the correct digest" do
@@ -30,7 +30,7 @@ describe "Digest::SHA256.file" do
obj = mock("to_str")
obj.should_receive(:to_str).and_return(@file)
result = Digest::SHA256.file(obj)
- result.should be_kind_of(Digest::SHA256)
+ result.should.is_a?(Digest::SHA256)
result.digest.should == SHA256Constants::Digest
end
end
@@ -38,10 +38,10 @@ describe "Digest::SHA256.file" do
it_behaves_like :file_read_directory, :file, Digest::SHA256
it "raises a Errno::ENOENT when passed a path that does not exist" do
- -> { Digest::SHA256.file("") }.should raise_error(Errno::ENOENT)
+ -> { Digest::SHA256.file("") }.should.raise(Errno::ENOENT)
end
it "raises a TypeError when passed nil" do
- -> { Digest::SHA256.file(nil) }.should raise_error(TypeError)
+ -> { Digest::SHA256.file(nil) }.should.raise(TypeError)
end
end
diff --git a/spec/ruby/library/digest/sha256/length_spec.rb b/spec/ruby/library/digest/sha256/length_spec.rb
index 181ac564ad..fc3db6548e 100644
--- a/spec/ruby/library/digest/sha256/length_spec.rb
+++ b/spec/ruby/library/digest/sha256/length_spec.rb
@@ -1,7 +1,11 @@
require_relative '../../../spec_helper'
require_relative 'shared/constants'
-require_relative 'shared/length'
describe "Digest::SHA256#length" do
- it_behaves_like :sha256_length, :length
+ it "returns the length of the digest" do
+ cur_digest = Digest::SHA256.new
+ cur_digest.length.should == SHA256Constants::BlankDigest.size
+ cur_digest << SHA256Constants::Contents
+ cur_digest.length.should == SHA256Constants::Digest.size
+ end
end
diff --git a/spec/ruby/library/digest/sha256/shared/length.rb b/spec/ruby/library/digest/sha256/shared/length.rb
deleted file mode 100644
index 996673a5bd..0000000000
--- a/spec/ruby/library/digest/sha256/shared/length.rb
+++ /dev/null
@@ -1,8 +0,0 @@
-describe :sha256_length, shared: true do
- it "returns the length of the digest" do
- cur_digest = Digest::SHA256.new
- cur_digest.send(@method).should == SHA256Constants::BlankDigest.size
- cur_digest << SHA256Constants::Contents
- cur_digest.send(@method).should == SHA256Constants::Digest.size
- end
-end
diff --git a/spec/ruby/library/digest/sha256/shared/update.rb b/spec/ruby/library/digest/sha256/shared/update.rb
deleted file mode 100644
index 0edc07935b..0000000000
--- a/spec/ruby/library/digest/sha256/shared/update.rb
+++ /dev/null
@@ -1,7 +0,0 @@
-describe :sha256_update, shared: true do
- it "can update" do
- cur_digest = Digest::SHA256.new
- cur_digest.send @method, SHA256Constants::Contents
- cur_digest.digest.should == SHA256Constants::Digest
- end
-end
diff --git a/spec/ruby/library/digest/sha256/size_spec.rb b/spec/ruby/library/digest/sha256/size_spec.rb
index 1028263342..6102e1c8aa 100644
--- a/spec/ruby/library/digest/sha256/size_spec.rb
+++ b/spec/ruby/library/digest/sha256/size_spec.rb
@@ -1,7 +1,8 @@
require_relative '../../../spec_helper'
require_relative 'shared/constants'
-require_relative 'shared/length'
describe "Digest::SHA256#size" do
- it_behaves_like :sha256_length, :size
+ it "is an alias of Digest::SHA256#length" do
+ Digest::SHA256.instance_method(:size).should == Digest::SHA256.instance_method(:length)
+ end
end
diff --git a/spec/ruby/library/digest/sha256/update_spec.rb b/spec/ruby/library/digest/sha256/update_spec.rb
index 92316eb752..d6724936f1 100644
--- a/spec/ruby/library/digest/sha256/update_spec.rb
+++ b/spec/ruby/library/digest/sha256/update_spec.rb
@@ -1,7 +1,8 @@
require_relative '../../../spec_helper'
-require_relative 'shared/constants'
-require_relative 'shared/update'
+require 'digest'
describe "Digest::SHA256#update" do
- it_behaves_like :sha256_update, :update
+ it "is an alias of Digest::SHA256#<<" do
+ Digest::SHA256.instance_method(:update).should == Digest::SHA256.instance_method(:<<)
+ end
end
diff --git a/spec/ruby/library/digest/sha384/append_spec.rb b/spec/ruby/library/digest/sha384/append_spec.rb
index 94c036cc3f..b9a862f1c2 100644
--- a/spec/ruby/library/digest/sha384/append_spec.rb
+++ b/spec/ruby/library/digest/sha384/append_spec.rb
@@ -1,7 +1,10 @@
require_relative '../../../spec_helper'
require_relative 'shared/constants'
-require_relative 'shared/update'
describe "Digest::SHA384#<<" do
- it_behaves_like :sha384_update, :<<
+ it "can update" do
+ cur_digest = Digest::SHA384.new
+ cur_digest << SHA384Constants::Contents
+ cur_digest.digest.should == SHA384Constants::Digest
+ end
end
diff --git a/spec/ruby/library/digest/sha384/file_spec.rb b/spec/ruby/library/digest/sha384/file_spec.rb
index 8556f10175..3726ad4423 100644
--- a/spec/ruby/library/digest/sha384/file_spec.rb
+++ b/spec/ruby/library/digest/sha384/file_spec.rb
@@ -15,7 +15,7 @@ describe "Digest::SHA384.file" do
end
it "returns a Digest::SHA384 object" do
- Digest::SHA384.file(@file).should be_kind_of(Digest::SHA384)
+ Digest::SHA384.file(@file).should.is_a?(Digest::SHA384)
end
it "returns a Digest::SHA384 object with the correct digest" do
@@ -26,7 +26,7 @@ describe "Digest::SHA384.file" do
obj = mock("to_str")
obj.should_receive(:to_str).and_return(@file)
result = Digest::SHA384.file(obj)
- result.should be_kind_of(Digest::SHA384)
+ result.should.is_a?(Digest::SHA384)
result.digest.should == SHA384Constants::Digest
end
end
@@ -34,10 +34,10 @@ describe "Digest::SHA384.file" do
it_behaves_like :file_read_directory, :file, Digest::SHA384
it "raises a Errno::ENOENT when passed a path that does not exist" do
- -> { Digest::SHA384.file("") }.should raise_error(Errno::ENOENT)
+ -> { Digest::SHA384.file("") }.should.raise(Errno::ENOENT)
end
it "raises a TypeError when passed nil" do
- -> { Digest::SHA384.file(nil) }.should raise_error(TypeError)
+ -> { Digest::SHA384.file(nil) }.should.raise(TypeError)
end
end
diff --git a/spec/ruby/library/digest/sha384/length_spec.rb b/spec/ruby/library/digest/sha384/length_spec.rb
index 33fed492ef..e5cd6131fd 100644
--- a/spec/ruby/library/digest/sha384/length_spec.rb
+++ b/spec/ruby/library/digest/sha384/length_spec.rb
@@ -1,7 +1,11 @@
require_relative '../../../spec_helper'
require_relative 'shared/constants'
-require_relative 'shared/length'
describe "Digest::SHA384#length" do
- it_behaves_like :sha384_length, :length
+ it "returns the length of the digest" do
+ cur_digest = Digest::SHA384.new
+ cur_digest.length.should == SHA384Constants::BlankDigest.size
+ cur_digest << SHA384Constants::Contents
+ cur_digest.length.should == SHA384Constants::Digest.size
+ end
end
diff --git a/spec/ruby/library/digest/sha384/shared/length.rb b/spec/ruby/library/digest/sha384/shared/length.rb
deleted file mode 100644
index 0c88288bcf..0000000000
--- a/spec/ruby/library/digest/sha384/shared/length.rb
+++ /dev/null
@@ -1,8 +0,0 @@
-describe :sha384_length, shared: true do
- it "returns the length of the digest" do
- cur_digest = Digest::SHA384.new
- cur_digest.send(@method).should == SHA384Constants::BlankDigest.size
- cur_digest << SHA384Constants::Contents
- cur_digest.send(@method).should == SHA384Constants::Digest.size
- end
-end
diff --git a/spec/ruby/library/digest/sha384/shared/update.rb b/spec/ruby/library/digest/sha384/shared/update.rb
deleted file mode 100644
index 1c6e31cf6a..0000000000
--- a/spec/ruby/library/digest/sha384/shared/update.rb
+++ /dev/null
@@ -1,7 +0,0 @@
-describe :sha384_update, shared: true do
- it "can update" do
- cur_digest = Digest::SHA384.new
- cur_digest.send @method, SHA384Constants::Contents
- cur_digest.digest.should == SHA384Constants::Digest
- end
-end
diff --git a/spec/ruby/library/digest/sha384/size_spec.rb b/spec/ruby/library/digest/sha384/size_spec.rb
index 4c3b14f7a0..40c291c623 100644
--- a/spec/ruby/library/digest/sha384/size_spec.rb
+++ b/spec/ruby/library/digest/sha384/size_spec.rb
@@ -1,7 +1,8 @@
require_relative '../../../spec_helper'
-require_relative 'shared/constants'
-require_relative 'shared/length'
+require 'digest'
describe "Digest::SHA384#size" do
- it_behaves_like :sha384_length, :size
+ it "is an alias of Digest::SHA384#length" do
+ Digest::SHA384.instance_method(:size).should == Digest::SHA384.instance_method(:length)
+ end
end
diff --git a/spec/ruby/library/digest/sha384/update_spec.rb b/spec/ruby/library/digest/sha384/update_spec.rb
index a1d0dd6068..561dcad3ec 100644
--- a/spec/ruby/library/digest/sha384/update_spec.rb
+++ b/spec/ruby/library/digest/sha384/update_spec.rb
@@ -1,7 +1,8 @@
require_relative '../../../spec_helper'
-require_relative 'shared/constants'
-require_relative 'shared/update'
+require 'digest'
describe "Digest::SHA384#update" do
- it_behaves_like :sha384_update, :update
+ it "is an alias of Digest::SHA384#<<" do
+ Digest::SHA384.instance_method(:update).should == Digest::SHA384.instance_method(:<<)
+ end
end
diff --git a/spec/ruby/library/digest/sha512/append_spec.rb b/spec/ruby/library/digest/sha512/append_spec.rb
index 9106e9685d..f297005403 100644
--- a/spec/ruby/library/digest/sha512/append_spec.rb
+++ b/spec/ruby/library/digest/sha512/append_spec.rb
@@ -1,7 +1,10 @@
require_relative '../../../spec_helper'
require_relative 'shared/constants'
-require_relative 'shared/update'
describe "Digest::SHA512#<<" do
- it_behaves_like :sha512_update, :<<
+ it "can update" do
+ cur_digest = Digest::SHA512.new
+ cur_digest << SHA512Constants::Contents
+ cur_digest.digest.should == SHA512Constants::Digest
+ end
end
diff --git a/spec/ruby/library/digest/sha512/file_spec.rb b/spec/ruby/library/digest/sha512/file_spec.rb
index 781ec781e5..78d6d3d4f3 100644
--- a/spec/ruby/library/digest/sha512/file_spec.rb
+++ b/spec/ruby/library/digest/sha512/file_spec.rb
@@ -15,7 +15,7 @@ describe "Digest::SHA512.file" do
end
it "returns a Digest::SHA512 object" do
- Digest::SHA512.file(@file).should be_kind_of(Digest::SHA512)
+ Digest::SHA512.file(@file).should.is_a?(Digest::SHA512)
end
it "returns a Digest::SHA512 object with the correct digest" do
@@ -26,7 +26,7 @@ describe "Digest::SHA512.file" do
obj = mock("to_str")
obj.should_receive(:to_str).and_return(@file)
result = Digest::SHA512.file(obj)
- result.should be_kind_of(Digest::SHA512)
+ result.should.is_a?(Digest::SHA512)
result.digest.should == SHA512Constants::Digest
end
end
@@ -34,10 +34,10 @@ describe "Digest::SHA512.file" do
it_behaves_like :file_read_directory, :file, Digest::SHA512
it "raises a Errno::ENOENT when passed a path that does not exist" do
- -> { Digest::SHA512.file("") }.should raise_error(Errno::ENOENT)
+ -> { Digest::SHA512.file("") }.should.raise(Errno::ENOENT)
end
it "raises a TypeError when passed nil" do
- -> { Digest::SHA512.file(nil) }.should raise_error(TypeError)
+ -> { Digest::SHA512.file(nil) }.should.raise(TypeError)
end
end
diff --git a/spec/ruby/library/digest/sha512/length_spec.rb b/spec/ruby/library/digest/sha512/length_spec.rb
index e9fde90577..8e909482c5 100644
--- a/spec/ruby/library/digest/sha512/length_spec.rb
+++ b/spec/ruby/library/digest/sha512/length_spec.rb
@@ -1,7 +1,11 @@
require_relative '../../../spec_helper'
require_relative 'shared/constants'
-require_relative 'shared/length'
describe "Digest::SHA512#length" do
- it_behaves_like :sha512_length, :length
+ it "returns the length of the digest" do
+ cur_digest = Digest::SHA512.new
+ cur_digest.length.should == SHA512Constants::BlankDigest.size
+ cur_digest << SHA512Constants::Contents
+ cur_digest.length.should == SHA512Constants::Digest.size
+ end
end
diff --git a/spec/ruby/library/digest/sha512/shared/length.rb b/spec/ruby/library/digest/sha512/shared/length.rb
deleted file mode 100644
index c0609d5386..0000000000
--- a/spec/ruby/library/digest/sha512/shared/length.rb
+++ /dev/null
@@ -1,8 +0,0 @@
-describe :sha512_length, shared: true do
- it "returns the length of the digest" do
- cur_digest = Digest::SHA512.new
- cur_digest.send(@method).should == SHA512Constants::BlankDigest.size
- cur_digest << SHA512Constants::Contents
- cur_digest.send(@method).should == SHA512Constants::Digest.size
- end
-end
diff --git a/spec/ruby/library/digest/sha512/shared/update.rb b/spec/ruby/library/digest/sha512/shared/update.rb
deleted file mode 100644
index ca74dbf4df..0000000000
--- a/spec/ruby/library/digest/sha512/shared/update.rb
+++ /dev/null
@@ -1,7 +0,0 @@
-describe :sha512_update, shared: true do
- it "can update" do
- cur_digest = Digest::SHA512.new
- cur_digest.send @method, SHA512Constants::Contents
- cur_digest.digest.should == SHA512Constants::Digest
- end
-end
diff --git a/spec/ruby/library/digest/sha512/size_spec.rb b/spec/ruby/library/digest/sha512/size_spec.rb
index 6d0acdabdb..498d686802 100644
--- a/spec/ruby/library/digest/sha512/size_spec.rb
+++ b/spec/ruby/library/digest/sha512/size_spec.rb
@@ -1,7 +1,8 @@
require_relative '../../../spec_helper'
-require_relative 'shared/constants'
-require_relative 'shared/length'
+require 'digest'
describe "Digest::SHA512#size" do
- it_behaves_like :sha512_length, :size
+ it "is an alias of Digest::SHA512#length" do
+ Digest::SHA512.instance_method(:size).should == Digest::SHA512.instance_method(:length)
+ end
end
diff --git a/spec/ruby/library/digest/sha512/update_spec.rb b/spec/ruby/library/digest/sha512/update_spec.rb
index 682d3a19bb..33edf216ac 100644
--- a/spec/ruby/library/digest/sha512/update_spec.rb
+++ b/spec/ruby/library/digest/sha512/update_spec.rb
@@ -1,7 +1,8 @@
require_relative '../../../spec_helper'
-require_relative 'shared/constants'
-require_relative 'shared/update'
+require 'digest'
describe "Digest::SHA512#update" do
- it_behaves_like :sha512_update, :update
+ it "is an alias of Digest::SHA512#<<" do
+ Digest::SHA512.instance_method(:update).should == Digest::SHA512.instance_method(:<<)
+ end
end
diff --git a/spec/ruby/library/erb/filename_spec.rb b/spec/ruby/library/erb/filename_spec.rb
index 8ecaed7343..bbd2233bb3 100644
--- a/spec/ruby/library/erb/filename_spec.rb
+++ b/spec/ruby/library/erb/filename_spec.rb
@@ -13,7 +13,7 @@ describe "ERB#filename" do
@ex = e
raise e
end
- }.should raise_error(SyntaxError)
+ }.should.raise(SyntaxError)
expected = filename
@ex.message =~ /^(.*?):(\d+): /
@@ -30,7 +30,7 @@ describe "ERB#filename" do
@ex = e
raise e
end
- }.should raise_error(SyntaxError)
+ }.should.raise(SyntaxError)
expected = '(erb)'
@ex.message =~ /^(.*?):(\d+): /
diff --git a/spec/ruby/library/erb/new_spec.rb b/spec/ruby/library/erb/new_spec.rb
index ec1be5c234..35ac0dfdfe 100644
--- a/spec/ruby/library/erb/new_spec.rb
+++ b/spec/ruby/library/erb/new_spec.rb
@@ -83,7 +83,7 @@ END
-> {
ERBSpecs.new_erb(input, trim_mode: '-').result
- }.should raise_error(SyntaxError)
+ }.should.raise(SyntaxError)
end
it "regards lines starting with '%' as '<% ... %>' when trim_mode is '%'" do
@@ -136,20 +136,22 @@ END
it "forget local variables defined previous one" do
ERB.new(@eruby_str).result
- ->{ ERB.new("<%= list %>").result }.should raise_error(NameError)
+ ->{ ERB.new("<%= list %>").result }.should.raise(NameError)
end
- describe "warning about arguments" do
- it "warns when passed safe_level and later arguments" do
- -> {
- ERB.new(@eruby_str, nil, '%')
- }.should complain(/warning: Passing safe_level with the 2nd argument of ERB.new is deprecated. Do not use it, and specify other arguments as keyword arguments./)
- end
-
- it "does not warn when passed arguments as keyword argument" do
- -> {
- ERB.new(@eruby_str, trim_mode: '%')
- }.should_not complain(/warning: Passing safe_level with the 2nd argument of ERB.new is deprecated. Do not use it, and specify other arguments as keyword arguments./)
+ version_is ERB.const_get(:VERSION, false), ""..."6.0.0" do
+ describe "warning about arguments" do
+ it "warns when passed safe_level and later arguments" do
+ -> {
+ ERB.new(@eruby_str, nil, '%')
+ }.should complain(/warning: Passing safe_level with the 2nd argument of ERB.new is deprecated. Do not use it, and specify other arguments as keyword arguments./)
+ end
+
+ it "does not warn when passed arguments as keyword argument" do
+ -> {
+ ERB.new(@eruby_str, trim_mode: '%')
+ }.should_not complain(/warning: Passing safe_level with the 2nd argument of ERB.new is deprecated. Do not use it, and specify other arguments as keyword arguments./)
+ end
end
end
end
diff --git a/spec/ruby/library/erb/result_spec.rb b/spec/ruby/library/erb/result_spec.rb
index a29c1ccedb..84333031ec 100644
--- a/spec/ruby/library/erb/result_spec.rb
+++ b/spec/ruby/library/erb/result_spec.rb
@@ -43,7 +43,7 @@ END
input = "<%=h '<>' %>"
-> {
ERB.new(input).result()
- }.should raise_error(NameError)
+ }.should.raise(NameError)
end
@@ -81,6 +81,6 @@ END
-> {
myerb2.new.main2()
- }.should raise_error(NameError)
+ }.should.raise(NameError)
end
end
diff --git a/spec/ruby/library/erb/run_spec.rb b/spec/ruby/library/erb/run_spec.rb
index 602e53ab38..d81d534087 100644
--- a/spec/ruby/library/erb/run_spec.rb
+++ b/spec/ruby/library/erb/run_spec.rb
@@ -54,7 +54,7 @@ END
input = "<%=h '<>' %>"
-> {
_steal_stdout { ERB.new(input).run() }
- }.should raise_error(NameError)
+ }.should.raise(NameError)
end
it "is able to h() or u() if ERB::Util is included" do
@@ -91,6 +91,6 @@ END
-> {
_steal_stdout { myerb2.new.main2() }
- }.should raise_error(NameError)
+ }.should.raise(NameError)
end
end
diff --git a/spec/ruby/library/etc/confstr_spec.rb b/spec/ruby/library/etc/confstr_spec.rb
index 5b43461150..786cb16407 100644
--- a/spec/ruby/library/etc/confstr_spec.rb
+++ b/spec/ruby/library/etc/confstr_spec.rb
@@ -4,11 +4,11 @@ require 'etc'
platform_is_not :windows, :android do
describe "Etc.confstr" do
it "returns a String for Etc::CS_PATH" do
- Etc.confstr(Etc::CS_PATH).should be_an_instance_of(String)
+ Etc.confstr(Etc::CS_PATH).should.instance_of?(String)
end
it "raises Errno::EINVAL for unknown configuration variables" do
- -> { Etc.confstr(-1) }.should raise_error(Errno::EINVAL)
+ -> { Etc.confstr(-1) }.should.raise(Errno::EINVAL)
end
end
end
diff --git a/spec/ruby/library/etc/getgrgid_spec.rb b/spec/ruby/library/etc/getgrgid_spec.rb
index 14da5e041d..472d4c82c8 100644
--- a/spec/ruby/library/etc/getgrgid_spec.rb
+++ b/spec/ruby/library/etc/getgrgid_spec.rb
@@ -34,7 +34,7 @@ platform_is_not :windows do
it "returns the Etc::Group for a given gid if it exists" do
grp = Etc.getgrgid(@gid)
- grp.should be_kind_of(Etc::Group)
+ grp.should.is_a?(Etc::Group)
grp.gid.should == @gid
grp.name.should == @name
end
@@ -47,12 +47,12 @@ platform_is_not :windows do
end
it "raises if the group does not exist" do
- -> { Etc.getgrgid(9876)}.should raise_error(ArgumentError)
+ -> { Etc.getgrgid(9876)}.should.raise(ArgumentError)
end
it "raises a TypeError if not passed an Integer" do
- -> { Etc.getgrgid("foo") }.should raise_error(TypeError)
- -> { Etc.getgrgid(nil) }.should raise_error(TypeError)
+ -> { Etc.getgrgid("foo") }.should.raise(TypeError)
+ -> { Etc.getgrgid(nil) }.should.raise(TypeError)
end
it "can be called safely by multiple threads" do
diff --git a/spec/ruby/library/etc/getgrnam_spec.rb b/spec/ruby/library/etc/getgrnam_spec.rb
index fa49f15349..325ea7b297 100644
--- a/spec/ruby/library/etc/getgrnam_spec.rb
+++ b/spec/ruby/library/etc/getgrnam_spec.rb
@@ -24,7 +24,7 @@ platform_is_not :windows, :android do
-> {
Etc.getgrnam(123)
Etc.getgrnam(nil)
- }.should raise_error(TypeError)
+ }.should.raise(TypeError)
end
end
end
diff --git a/spec/ruby/library/etc/getlogin_spec.rb b/spec/ruby/library/etc/getlogin_spec.rb
index 7a4fd79ae2..2bc598c0af 100644
--- a/spec/ruby/library/etc/getlogin_spec.rb
+++ b/spec/ruby/library/etc/getlogin_spec.rb
@@ -14,7 +14,7 @@ describe "Etc.getlogin" do
if ENV['TRAVIS'] and platform_is(:darwin)
# See https://travis-ci.org/ruby/spec/jobs/285967744
# and https://travis-ci.org/ruby/spec/jobs/285999602
- Etc.getlogin.should be_an_instance_of(String)
+ Etc.getlogin.should.instance_of?(String)
else
# Etc.getlogin returns the same result of logname(2)
# if it returns non NULL
@@ -28,7 +28,7 @@ describe "Etc.getlogin" do
else
# Etc.getlogin may return nil if the login name is not set
# because of chroot or sudo or something.
- Etc.getlogin.should be_nil
+ Etc.getlogin.should == nil
getlogin_null = true
end
ensure
diff --git a/spec/ruby/library/etc/getpwnam_spec.rb b/spec/ruby/library/etc/getpwnam_spec.rb
index 3f4416aa9d..a0b3c9e1fe 100644
--- a/spec/ruby/library/etc/getpwnam_spec.rb
+++ b/spec/ruby/library/etc/getpwnam_spec.rb
@@ -22,7 +22,7 @@ platform_is_not :windows do
-> {
Etc.getpwnam(123)
Etc.getpwnam(nil)
- }.should raise_error(TypeError)
+ }.should.raise(TypeError)
end
end
end
diff --git a/spec/ruby/library/etc/getpwuid_spec.rb b/spec/ruby/library/etc/getpwuid_spec.rb
index 5b98f0f8d9..3e35dfe6d5 100644
--- a/spec/ruby/library/etc/getpwuid_spec.rb
+++ b/spec/ruby/library/etc/getpwuid_spec.rb
@@ -30,7 +30,7 @@ platform_is_not :windows do
-> {
Etc.getpwuid("foo")
Etc.getpwuid(nil)
- }.should raise_error(TypeError)
+ }.should.raise(TypeError)
end
end
end
diff --git a/spec/ruby/library/etc/group_spec.rb b/spec/ruby/library/etc/group_spec.rb
index fda808eec9..d7addbbec1 100644
--- a/spec/ruby/library/etc/group_spec.rb
+++ b/spec/ruby/library/etc/group_spec.rb
@@ -9,7 +9,7 @@ describe "Etc.group" do
it "returns a Etc::Group struct" do
group = Etc.group
begin
- group.should be_an_instance_of(Etc::Group)
+ group.should.instance_of?(Etc::Group)
ensure
Etc.endgrent
end
@@ -21,7 +21,7 @@ describe "Etc.group" do
Etc.group do | group2 |
end
end
- }.should raise_error(RuntimeError)
+ }.should.raise(RuntimeError)
end
end
end
diff --git a/spec/ruby/library/etc/nprocessors_spec.rb b/spec/ruby/library/etc/nprocessors_spec.rb
index ec7ffc81da..482719dde0 100644
--- a/spec/ruby/library/etc/nprocessors_spec.rb
+++ b/spec/ruby/library/etc/nprocessors_spec.rb
@@ -3,7 +3,7 @@ require 'etc'
describe "Etc.nprocessors" do
it "returns the number of online processors" do
- Etc.nprocessors.should be_kind_of(Integer)
+ Etc.nprocessors.should.is_a?(Integer)
Etc.nprocessors.should >= 1
end
end
diff --git a/spec/ruby/library/etc/passwd_spec.rb b/spec/ruby/library/etc/passwd_spec.rb
index 7157fd3f2e..0602b7e10b 100644
--- a/spec/ruby/library/etc/passwd_spec.rb
+++ b/spec/ruby/library/etc/passwd_spec.rb
@@ -6,7 +6,7 @@ platform_is_not :windows do
it "returns a Etc::Passwd struct" do
passwd = Etc.passwd
begin
- passwd.should be_an_instance_of(Etc::Passwd)
+ passwd.should.instance_of?(Etc::Passwd)
ensure
Etc.endpwent
end
diff --git a/spec/ruby/library/etc/sysconf_spec.rb b/spec/ruby/library/etc/sysconf_spec.rb
index 1f2c7a770f..81ce1ca258 100644
--- a/spec/ruby/library/etc/sysconf_spec.rb
+++ b/spec/ruby/library/etc/sysconf_spec.rb
@@ -14,7 +14,7 @@ platform_is_not :windows do
if value.nil?
value.should == nil
else
- value.should be_kind_of(Integer)
+ value.should.is_a?(Integer)
end
end
end
diff --git a/spec/ruby/library/etc/sysconfdir_spec.rb b/spec/ruby/library/etc/sysconfdir_spec.rb
index 8538faa65b..eb2d6b649a 100644
--- a/spec/ruby/library/etc/sysconfdir_spec.rb
+++ b/spec/ruby/library/etc/sysconfdir_spec.rb
@@ -3,6 +3,6 @@ require 'etc'
describe "Etc.sysconfdir" do
it "returns a String" do
- Etc.sysconfdir.should be_an_instance_of(String)
+ Etc.sysconfdir.should.instance_of?(String)
end
end
diff --git a/spec/ruby/library/etc/systmpdir_spec.rb b/spec/ruby/library/etc/systmpdir_spec.rb
index 5b007aa9f9..ed34cb43fc 100644
--- a/spec/ruby/library/etc/systmpdir_spec.rb
+++ b/spec/ruby/library/etc/systmpdir_spec.rb
@@ -3,6 +3,6 @@ require 'etc'
describe "Etc.systmpdir" do
it "returns a String" do
- Etc.systmpdir.should be_an_instance_of(String)
+ Etc.systmpdir.should.instance_of?(String)
end
end
diff --git a/spec/ruby/library/etc/uname_spec.rb b/spec/ruby/library/etc/uname_spec.rb
index a42558f593..1c5fe2a741 100644
--- a/spec/ruby/library/etc/uname_spec.rb
+++ b/spec/ruby/library/etc/uname_spec.rb
@@ -4,7 +4,7 @@ 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.is_a?(Hash)
uname.should.key?(:sysname)
uname.should.key?(:nodename)
uname.should.key?(:release)
diff --git a/spec/ruby/library/expect/expect_spec.rb b/spec/ruby/library/expect/expect_spec.rb
index 76ea3d5451..ba705c5535 100644
--- a/spec/ruby/library/expect/expect_spec.rb
+++ b/spec/ruby/library/expect/expect_spec.rb
@@ -40,14 +40,14 @@ platform_is_not :windows do
-> {
@read.expect("hello")
- }.should raise_error(IOError)
+ }.should.raise(IOError)
end
it "returns nil if eof is hit" do
@write << "pro"
@write.close
- @read.expect("prompt").should be_nil
+ @read.expect("prompt").should == nil
end
it "yields the result if a block is given" do
diff --git a/spec/ruby/library/fiddle/handle/initialize_spec.rb b/spec/ruby/library/fiddle/handle/initialize_spec.rb
index 51c2470efd..84c809a727 100644
--- a/spec/ruby/library/fiddle/handle/initialize_spec.rb
+++ b/spec/ruby/library/fiddle/handle/initialize_spec.rb
@@ -5,6 +5,6 @@ describe "Fiddle::Handle#initialize" do
it "raises Fiddle::DLError if the library cannot be found" do
-> {
Fiddle::Handle.new("doesnotexist.doesnotexist")
- }.should raise_error(Fiddle::DLError)
+ }.should.raise(Fiddle::DLError)
end
end
diff --git a/spec/ruby/library/find/find_spec.rb b/spec/ruby/library/find/find_spec.rb
index 7cd76fa01b..c4ccfa76fd 100644
--- a/spec/ruby/library/find/find_spec.rb
+++ b/spec/ruby/library/find/find_spec.rb
@@ -13,7 +13,7 @@ describe "Find.find" do
describe "when called without a block" do
it "returns an Enumerator" do
- Find.find(FindDirSpecs.mock_dir).should be_an_instance_of(Enumerator)
+ Find.find(FindDirSpecs.mock_dir).should.instance_of?(Enumerator)
Find.find(FindDirSpecs.mock_dir).to_a.sort.should == FindDirSpecs.expected_paths
end
end
diff --git a/spec/ruby/library/getoptlong/each_option_spec.rb b/spec/ruby/library/getoptlong/each_option_spec.rb
index c6d82af86d..3349554aaa 100644
--- a/spec/ruby/library/getoptlong/each_option_spec.rb
+++ b/spec/ruby/library/getoptlong/each_option_spec.rb
@@ -1,7 +1,21 @@
require_relative '../../spec_helper'
require 'getoptlong'
-require_relative 'shared/each'
describe "GetoptLong#each_option" do
- it_behaves_like :getoptlong_each, :each_option
+ before :each do
+ @opts = GetoptLong.new(
+ [ '--size', '-s', GetoptLong::REQUIRED_ARGUMENT ],
+ [ '--verbose', '-v', GetoptLong::NO_ARGUMENT ],
+ [ '--query', '-q', GetoptLong::NO_ARGUMENT ],
+ [ '--check', '--valid', '-c', GetoptLong::NO_ARGUMENT ]
+ )
+ end
+
+ it "passes each_option argument/value pair to the block" do
+ argv [ "--size", "10k", "-v", "-q", "a.txt", "b.txt" ] do
+ pairs = []
+ @opts.each_option { |arg, val| pairs << [ arg, val ] }
+ pairs.should == [ [ "--size", "10k" ], [ "--verbose", "" ], [ "--query", ""] ]
+ end
+ end
end
diff --git a/spec/ruby/library/getoptlong/each_spec.rb b/spec/ruby/library/getoptlong/each_spec.rb
index d9022f02af..646c3297b5 100644
--- a/spec/ruby/library/getoptlong/each_spec.rb
+++ b/spec/ruby/library/getoptlong/each_spec.rb
@@ -1,7 +1,8 @@
require_relative '../../spec_helper'
require 'getoptlong'
-require_relative 'shared/each'
describe "GetoptLong#each" do
- it_behaves_like :getoptlong_each, :each
+ it "is an alias of GetoptLong#each_option" do
+ GetoptLong.instance_method(:each).should == GetoptLong.instance_method(:each_option)
+ end
end
diff --git a/spec/ruby/library/getoptlong/error_message_spec.rb b/spec/ruby/library/getoptlong/error_message_spec.rb
index 1ed9419f6c..10435b1350 100644
--- a/spec/ruby/library/getoptlong/error_message_spec.rb
+++ b/spec/ruby/library/getoptlong/error_message_spec.rb
@@ -14,7 +14,7 @@ describe "GetoptLong#error_message" do
opts.get
-> {
opts.ordering = GetoptLong::PERMUTE
- }.should raise_error(ArgumentError) { |e|
+ }.should.raise(ArgumentError) { |e|
e.message.should == "argument error"
opts.error_message.should == "argument error"
}
diff --git a/spec/ruby/library/getoptlong/get_option_spec.rb b/spec/ruby/library/getoptlong/get_option_spec.rb
index 3cb2044379..1d80e3622e 100644
--- a/spec/ruby/library/getoptlong/get_option_spec.rb
+++ b/spec/ruby/library/getoptlong/get_option_spec.rb
@@ -1,7 +1,8 @@
require_relative '../../spec_helper'
require 'getoptlong'
-require_relative 'shared/get'
describe "GetoptLong#get_option" do
- it_behaves_like :getoptlong_get, :get_option
+ it "is an alias of GetoptLong#get" do
+ GetoptLong.instance_method(:get_option).should == GetoptLong.instance_method(:get)
+ end
end
diff --git a/spec/ruby/library/getoptlong/get_spec.rb b/spec/ruby/library/getoptlong/get_spec.rb
index a8ec586fc9..bfc6697a5a 100644
--- a/spec/ruby/library/getoptlong/get_spec.rb
+++ b/spec/ruby/library/getoptlong/get_spec.rb
@@ -1,7 +1,65 @@
require_relative '../../spec_helper'
require 'getoptlong'
-require_relative 'shared/get'
describe "GetoptLong#get" do
- it_behaves_like :getoptlong_get, :get
+ before :each do
+ @opts = GetoptLong.new(
+ [ '--size', '-s', GetoptLong::REQUIRED_ARGUMENT ],
+ [ '--verbose', '-v', GetoptLong::NO_ARGUMENT ],
+ [ '--query', '-q', GetoptLong::NO_ARGUMENT ],
+ [ '--check', '--valid', '-c', GetoptLong::NO_ARGUMENT ]
+ )
+ @opts.quiet = true # silence using $deferr
+ end
+
+ it "returns the next option name and its argument as an Array" do
+ argv [ "--size", "10k", "-v", "-q", "a.txt", "b.txt" ] do
+ @opts.get.should == [ "--size", "10k" ]
+ @opts.get.should == [ "--verbose", "" ]
+ @opts.get.should == [ "--query", ""]
+ @opts.get.should == nil
+ end
+ end
+
+ it "shifts ARGV on each call" do
+ argv [ "--size", "10k", "-v", "-q", "a.txt", "b.txt" ] do
+ @opts.get
+ ARGV.should == [ "-v", "-q", "a.txt", "b.txt" ]
+
+ @opts.get
+ ARGV.should == [ "-q", "a.txt", "b.txt" ]
+
+ @opts.get
+ ARGV.should == [ "a.txt", "b.txt" ]
+
+ @opts.get
+ ARGV.should == [ "a.txt", "b.txt" ]
+ end
+ end
+
+ it "terminates processing when encountering '--'" do
+ argv [ "--size", "10k", "--", "-v", "-q", "a.txt", "b.txt" ] do
+ @opts.get
+ ARGV.should == ["--", "-v", "-q", "a.txt", "b.txt"]
+
+ @opts.get
+ ARGV.should == ["-v", "-q", "a.txt", "b.txt"]
+
+ @opts.get
+ ARGV.should == ["-v", "-q", "a.txt", "b.txt"]
+ end
+ end
+
+ it "raises a if an argument was required, but none given" do
+ argv [ "--size" ] do
+ -> { @opts.get }.should.raise(GetoptLong::MissingArgument)
+ end
+ end
+
+ # https://bugs.ruby-lang.org/issues/13858
+ it "returns multiline argument" do
+ argv [ "--size=\n10k\n" ] do
+ @opts.get.should == [ "--size", "\n10k\n" ]
+ end
+ end
end
diff --git a/spec/ruby/library/getoptlong/ordering_spec.rb b/spec/ruby/library/getoptlong/ordering_spec.rb
index 695d1cafa7..60ce73afaa 100644
--- a/spec/ruby/library/getoptlong/ordering_spec.rb
+++ b/spec/ruby/library/getoptlong/ordering_spec.rb
@@ -11,7 +11,7 @@ describe "GetoptLong#ordering=" do
-> {
opts.ordering = GetoptLong::PERMUTE
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
end
@@ -20,7 +20,7 @@ describe "GetoptLong#ordering=" do
-> {
opts.ordering = 12345
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
it "does not allow changing ordering to PERMUTE if ENV['POSIXLY_CORRECT'] is set" do
diff --git a/spec/ruby/library/getoptlong/set_options_spec.rb b/spec/ruby/library/getoptlong/set_options_spec.rb
index 36b9c579c4..f60dcc87a3 100644
--- a/spec/ruby/library/getoptlong/set_options_spec.rb
+++ b/spec/ruby/library/getoptlong/set_options_spec.rb
@@ -41,7 +41,7 @@ describe "GetoptLong#set_options" do
argv [] do
-> {
@opts.set_options(["--size", GetoptLong::NO_ARGUMENT, GetoptLong::REQUIRED_ARGUMENT])
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
end
@@ -50,7 +50,7 @@ describe "GetoptLong#set_options" do
@opts.get
-> {
@opts.set_options()
- }.should raise_error(RuntimeError)
+ }.should.raise(RuntimeError)
end
end
@@ -58,7 +58,7 @@ describe "GetoptLong#set_options" do
argv [] do
-> {
@opts.set_options(["--size"])
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
end
@@ -68,7 +68,7 @@ describe "GetoptLong#set_options" do
@opts.set_options(
["--size", GetoptLong::REQUIRED_ARGUMENT],
"test")
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
end
@@ -78,13 +78,13 @@ describe "GetoptLong#set_options" do
@opts.set_options(
["--size", GetoptLong::NO_ARGUMENT],
["--size", GetoptLong::OPTIONAL_ARGUMENT])
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
-> {
@opts.set_options(
["--size", GetoptLong::NO_ARGUMENT],
["-s", "--size", GetoptLong::OPTIONAL_ARGUMENT])
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
end
@@ -92,7 +92,7 @@ describe "GetoptLong#set_options" do
argv [] do
-> {
@opts.set_options(["-size", GetoptLong::NO_ARGUMENT])
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
end
end
diff --git a/spec/ruby/library/getoptlong/shared/each.rb b/spec/ruby/library/getoptlong/shared/each.rb
deleted file mode 100644
index b534e24c0f..0000000000
--- a/spec/ruby/library/getoptlong/shared/each.rb
+++ /dev/null
@@ -1,18 +0,0 @@
-describe :getoptlong_each, shared: true do
- before :each do
- @opts = GetoptLong.new(
- [ '--size', '-s', GetoptLong::REQUIRED_ARGUMENT ],
- [ '--verbose', '-v', GetoptLong::NO_ARGUMENT ],
- [ '--query', '-q', GetoptLong::NO_ARGUMENT ],
- [ '--check', '--valid', '-c', GetoptLong::NO_ARGUMENT ]
- )
- end
-
- it "passes each argument/value pair to the block" do
- argv [ "--size", "10k", "-v", "-q", "a.txt", "b.txt" ] do
- pairs = []
- @opts.send(@method) { |arg, val| pairs << [ arg, val ] }
- pairs.should == [ [ "--size", "10k" ], [ "--verbose", "" ], [ "--query", ""] ]
- end
- end
-end
diff --git a/spec/ruby/library/getoptlong/shared/get.rb b/spec/ruby/library/getoptlong/shared/get.rb
deleted file mode 100644
index f44cf583d2..0000000000
--- a/spec/ruby/library/getoptlong/shared/get.rb
+++ /dev/null
@@ -1,62 +0,0 @@
-describe :getoptlong_get, shared: true do
- before :each do
- @opts = GetoptLong.new(
- [ '--size', '-s', GetoptLong::REQUIRED_ARGUMENT ],
- [ '--verbose', '-v', GetoptLong::NO_ARGUMENT ],
- [ '--query', '-q', GetoptLong::NO_ARGUMENT ],
- [ '--check', '--valid', '-c', GetoptLong::NO_ARGUMENT ]
- )
- @opts.quiet = true # silence using $deferr
- end
-
- it "returns the next option name and its argument as an Array" do
- argv [ "--size", "10k", "-v", "-q", "a.txt", "b.txt" ] do
- @opts.send(@method).should == [ "--size", "10k" ]
- @opts.send(@method).should == [ "--verbose", "" ]
- @opts.send(@method).should == [ "--query", ""]
- @opts.send(@method).should == nil
- end
- end
-
- it "shifts ARGV on each call" do
- argv [ "--size", "10k", "-v", "-q", "a.txt", "b.txt" ] do
- @opts.send(@method)
- ARGV.should == [ "-v", "-q", "a.txt", "b.txt" ]
-
- @opts.send(@method)
- ARGV.should == [ "-q", "a.txt", "b.txt" ]
-
- @opts.send(@method)
- ARGV.should == [ "a.txt", "b.txt" ]
-
- @opts.send(@method)
- ARGV.should == [ "a.txt", "b.txt" ]
- end
- end
-
- it "terminates processing when encountering '--'" do
- argv [ "--size", "10k", "--", "-v", "-q", "a.txt", "b.txt" ] do
- @opts.send(@method)
- ARGV.should == ["--", "-v", "-q", "a.txt", "b.txt"]
-
- @opts.send(@method)
- ARGV.should == ["-v", "-q", "a.txt", "b.txt"]
-
- @opts.send(@method)
- ARGV.should == ["-v", "-q", "a.txt", "b.txt"]
- end
- end
-
- it "raises a if an argument was required, but none given" do
- argv [ "--size" ] do
- -> { @opts.send(@method) }.should raise_error(GetoptLong::MissingArgument)
- end
- end
-
- # https://bugs.ruby-lang.org/issues/13858
- it "returns multiline argument" do
- argv [ "--size=\n10k\n" ] do
- @opts.send(@method).should == [ "--size", "\n10k\n" ]
- end
- end
-end
diff --git a/spec/ruby/library/io-wait/wait_spec.rb b/spec/ruby/library/io-wait/wait_spec.rb
index 6a3890a401..1d784e7aa4 100644
--- a/spec/ruby/library/io-wait/wait_spec.rb
+++ b/spec/ruby/library/io-wait/wait_spec.rb
@@ -56,12 +56,12 @@ describe "IO#wait" do
it "raises IOError when io is closed (closed stream (IOError))" do
@io.close
- -> { @io.wait(IO::READABLE, 0) }.should raise_error(IOError, "closed stream")
+ -> { @io.wait(IO::READABLE, 0) }.should.raise(IOError, "closed stream")
end
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!")
+ -> { @w.wait(0, 0) }.should.raise(ArgumentError, "Events must be positive integer!")
+ -> { @w.wait(-1, 0) }.should.raise(ArgumentError, "Events must be positive integer!")
end
it "changes thread status to 'sleep' when waits for READABLE event" do
@@ -147,16 +147,16 @@ describe "IO#wait" do
end
it "raises ArgumentError when passed wrong Symbol value as mode argument" do
- -> { @io.wait(0, :wrong) }.should raise_error(ArgumentError, "unsupported mode: wrong")
+ -> { @io.wait(0, :wrong) }.should.raise(ArgumentError, "unsupported mode: wrong")
end
it "raises ArgumentError when several Integer arguments passed" do
- -> { @w.wait(0, 10, :r) }.should raise_error(ArgumentError, "timeout given more than once")
+ -> { @w.wait(0, 10, :r) }.should.raise(ArgumentError, "timeout given more than once")
end
it "raises IOError when io is closed (closed stream (IOError))" do
@io.close
- -> { @io.wait(0, :r) }.should raise_error(IOError, "closed stream")
+ -> { @io.wait(0, :r) }.should.raise(IOError, "closed stream")
end
end
end
diff --git a/spec/ruby/library/ipaddr/new_spec.rb b/spec/ruby/library/ipaddr/new_spec.rb
index 2c0f44acf2..7fba2b372e 100644
--- a/spec/ruby/library/ipaddr/new_spec.rb
+++ b/spec/ruby/library/ipaddr/new_spec.rb
@@ -3,9 +3,9 @@ require 'ipaddr'
describe "IPAddr#new" do
it "initializes IPAddr" do
- ->{ IPAddr.new("3FFE:505:ffff::/48") }.should_not raise_error
- ->{ IPAddr.new("0:0:0:1::") }.should_not raise_error
- ->{ IPAddr.new("2001:200:300::/48") }.should_not raise_error
+ ->{ IPAddr.new("3FFE:505:ffff::/48") }.should_not.raise
+ ->{ IPAddr.new("0:0:0:1::") }.should_not.raise
+ ->{ IPAddr.new("2001:200:300::/48") }.should_not.raise
end
it "initializes IPAddr ipv6 address with short notation" do
@@ -86,7 +86,7 @@ describe "IPAddr#new" do
].each { |args|
->{
IPAddr.new(*args)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
}
end
end
diff --git a/spec/ruby/library/ipaddr/operator_spec.rb b/spec/ruby/library/ipaddr/operator_spec.rb
index f90c56009c..3337d22300 100644
--- a/spec/ruby/library/ipaddr/operator_spec.rb
+++ b/spec/ruby/library/ipaddr/operator_spec.rb
@@ -66,17 +66,17 @@ describe "IPAddr Operator" do
end
it "checks whether an address is included in a range" do
- @a.should include(IPAddr.new("3ffe:505:2::"))
- @a.should include(IPAddr.new("3ffe:505:2::1"))
- @a.should_not include(IPAddr.new("3ffe:505:3::"))
+ @a.should.include?(IPAddr.new("3ffe:505:2::"))
+ @a.should.include?(IPAddr.new("3ffe:505:2::1"))
+ @a.should_not.include?(IPAddr.new("3ffe:505:3::"))
net1 = IPAddr.new("192.168.2.0/24")
- net1.should include(IPAddr.new("192.168.2.0"))
- net1.should include(IPAddr.new("192.168.2.255"))
- net1.should_not include(IPAddr.new("192.168.3.0"))
+ net1.should.include?(IPAddr.new("192.168.2.0"))
+ net1.should.include?(IPAddr.new("192.168.2.255"))
+ net1.should_not.include?(IPAddr.new("192.168.3.0"))
# test with integer parameter
int = (192 << 24) + (168 << 16) + (2 << 8) + 13
- net1.should include(int)
- net1.should_not include(int+255)
+ net1.should.include?(int)
+ net1.should_not.include?(int+255)
end
end
diff --git a/spec/ruby/library/ipaddr/reverse_spec.rb b/spec/ruby/library/ipaddr/reverse_spec.rb
index 6ebb343269..9bda60ca70 100644
--- a/spec/ruby/library/ipaddr/reverse_spec.rb
+++ b/spec/ruby/library/ipaddr/reverse_spec.rb
@@ -13,7 +13,7 @@ describe "IPAddr#ip6_arpa" do
IPAddr.new("3ffe:505:2::f").ip6_arpa.should == "f.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.2.0.0.0.5.0.5.0.e.f.f.3.ip6.arpa"
->{
IPAddr.new("192.168.2.1").ip6_arpa
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
end
@@ -22,6 +22,6 @@ describe "IPAddr#ip6_int" do
IPAddr.new("3ffe:505:2::f").ip6_int.should == "f.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.2.0.0.0.5.0.5.0.e.f.f.3.ip6.int"
->{
IPAddr.new("192.168.2.1").ip6_int
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
end
diff --git a/spec/ruby/library/logger/device/new_spec.rb b/spec/ruby/library/logger/device/new_spec.rb
index 26a38c2b8c..c943e7fbe2 100644
--- a/spec/ruby/library/logger/device/new_spec.rb
+++ b/spec/ruby/library/logger/device/new_spec.rb
@@ -14,11 +14,11 @@ describe "Logger::LogDevice#new" do
it "creates a new log device" do
l = Logger::LogDevice.new(@log_file)
- l.dev.should be_kind_of(File)
+ l.dev.should.is_a?(File)
end
it "receives an IO object to log there as first argument" do
- @log_file.should be_kind_of(IO)
+ @log_file.should.is_a?(IO)
l = Logger::LogDevice.new(@log_file)
l.write("foo")
@log_file.rewind
@@ -33,7 +33,7 @@ describe "Logger::LogDevice#new" do
File.should.exist?(path)
File.open(path) do |f|
- f.readlines.should_not be_empty
+ f.readlines.should_not.empty?
end
rm_r path
@@ -42,6 +42,6 @@ describe "Logger::LogDevice#new" do
it "receives options via a hash as second argument" do
-> {
Logger::LogDevice.new(STDERR, shift_age: 8, shift_size: 10)
- }.should_not raise_error
+ }.should_not.raise
end
end
diff --git a/spec/ruby/library/logger/logger/add_spec.rb b/spec/ruby/library/logger/logger/add_spec.rb
index 3f709e18ba..98ac88f64f 100644
--- a/spec/ruby/library/logger/logger/add_spec.rb
+++ b/spec/ruby/library/logger/logger/add_spec.rb
@@ -56,7 +56,7 @@ describe "Logger#add" do
@logger.log(nil, "test", "TestApp") do
1+1
end
- }.should_not raise_error
+ }.should_not.raise
end
it "calls the block if message is nil" do
@@ -65,7 +65,7 @@ describe "Logger#add" do
@logger.log(nil, nil, "TestApp") do
temp = 1+1
end
- }.should_not raise_error
+ }.should_not.raise
temp.should == 2
end
@@ -75,7 +75,7 @@ describe "Logger#add" do
@logger.log(nil, "not nil", "TestApp") do
temp = 1+1
end
- }.should_not raise_error
+ }.should_not.raise
temp.should == 0
end
end
diff --git a/spec/ruby/library/logger/logger/datetime_format_spec.rb b/spec/ruby/library/logger/logger/datetime_format_spec.rb
index 582b34bfda..75a7f6cc03 100644
--- a/spec/ruby/library/logger/logger/datetime_format_spec.rb
+++ b/spec/ruby/library/logger/logger/datetime_format_spec.rb
@@ -49,7 +49,7 @@ describe "Logger#datetime_format=" do
end
it "follows the Time#strftime format" do
- -> { @logger.datetime_format = "%Y-%m" }.should_not raise_error
+ -> { @logger.datetime_format = "%Y-%m" }.should_not.raise
regex = /\d{4}-\d{2}-\d{2}oo-\w+ar/
@logger.datetime_format = "%Foo-%Bar"
diff --git a/spec/ruby/library/logger/logger/new_spec.rb b/spec/ruby/library/logger/logger/new_spec.rb
index 3db20e7432..b311c96132 100644
--- a/spec/ruby/library/logger/logger/new_spec.rb
+++ b/spec/ruby/library/logger/logger/new_spec.rb
@@ -28,13 +28,13 @@ describe "Logger#new" do
end
it "receives a frequency rotation as second argument" do
- -> { Logger.new(@log_file, "daily") }.should_not raise_error
- -> { Logger.new(@log_file, "weekly") }.should_not raise_error
- -> { Logger.new(@log_file, "monthly") }.should_not raise_error
+ -> { Logger.new(@log_file, "daily") }.should_not.raise
+ -> { Logger.new(@log_file, "weekly") }.should_not.raise
+ -> { Logger.new(@log_file, "monthly") }.should_not.raise
end
it "also receives a number of log files to keep as second argument" do
- -> { Logger.new(@log_file, 1).close }.should_not raise_error
+ -> { Logger.new(@log_file, 1).close }.should_not.raise
end
it "receives a maximum logfile size as third argument" do
@@ -94,7 +94,7 @@ describe "Logger#new" do
logger.formatter.should == formatter
end
- it "receives shift_period_suffix " do
+ it "receives shift_period_suffix" do
shift_period_suffix = "%Y-%m-%d"
path = tmp("shift_period_suffix_test.log")
now = Time.now
diff --git a/spec/ruby/library/logger/logger/unknown_spec.rb b/spec/ruby/library/logger/logger/unknown_spec.rb
index b174b8b2c9..4d37c9797e 100644
--- a/spec/ruby/library/logger/logger/unknown_spec.rb
+++ b/spec/ruby/library/logger/logger/unknown_spec.rb
@@ -29,7 +29,7 @@ describe "Logger#unknown" do
end
it "receives empty messages" do
- -> { @logger.unknown("") }.should_not raise_error
+ -> { @logger.unknown("") }.should_not.raise
@log_file.rewind
LoggerSpecs.strip_date(@log_file.readlines.first).should == "ANY -- : \n"
end
diff --git a/spec/ruby/library/matrix/I_spec.rb b/spec/ruby/library/matrix/I_spec.rb
index 6eeffe8e98..ca5e79279a 100644
--- a/spec/ruby/library/matrix/I_spec.rb
+++ b/spec/ruby/library/matrix/I_spec.rb
@@ -1,6 +1,8 @@
require_relative '../../spec_helper'
-require_relative 'shared/identity'
+require 'matrix'
describe "Matrix.I" do
- it_behaves_like :matrix_identity, :I
+ it "is an alias of Matrix.identity" do
+ Matrix.method(:I).should == Matrix.method(:identity)
+ end
end
diff --git a/spec/ruby/library/matrix/antisymmetric_spec.rb b/spec/ruby/library/matrix/antisymmetric_spec.rb
index 200df703cb..b4b8858f32 100644
--- a/spec/ruby/library/matrix/antisymmetric_spec.rb
+++ b/spec/ruby/library/matrix/antisymmetric_spec.rb
@@ -4,11 +4,11 @@ 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
+ Matrix[[0, -2, Complex(1, 3)], [2, 0, 5], [-Complex(1, 3), -5, 0]].antisymmetric?.should == true
end
it "returns true for a 0x0 empty matrix" do
- Matrix.empty.antisymmetric?.should be_true
+ Matrix.empty.antisymmetric?.should == true
end
it "returns false for non-antisymmetric matrices" do
@@ -17,7 +17,7 @@ describe "Matrix#antisymmetric?" do
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
+ matrix.antisymmetric?.should == false
end
end
@@ -30,7 +30,7 @@ describe "Matrix#antisymmetric?" do
].each do |rectangular_matrix|
-> {
rectangular_matrix.antisymmetric?
- }.should raise_error(Matrix::ErrDimensionMismatch)
+ }.should.raise(Matrix::ErrDimensionMismatch)
end
end
end
diff --git a/spec/ruby/library/matrix/build_spec.rb b/spec/ruby/library/matrix/build_spec.rb
index 6d8017a3df..49eb2e69a5 100644
--- a/spec/ruby/library/matrix/build_spec.rb
+++ b/spec/ruby/library/matrix/build_spec.rb
@@ -6,7 +6,7 @@ describe "Matrix.build" do
it "returns a Matrix object of the given size" do
m = Matrix.build(3, 4){1}
- m.should be_an_instance_of(Matrix)
+ m.should.instance_of?(Matrix)
m.row_size.should == 3
m.column_size.should == 4
end
@@ -24,32 +24,32 @@ describe "Matrix.build" do
it "returns an Enumerator is no block is given" do
enum = Matrix.build(2, 1)
- enum.should be_an_instance_of(Enumerator)
+ enum.should.instance_of?(Enumerator)
enum.each{1}.should == Matrix[[1], [1]]
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)
+ -> { Matrix.build("1", "2"){1} }.should.raise(TypeError)
+ -> { Matrix.build(nil, nil){1} }.should.raise(TypeError)
+ -> { Matrix.build(1..2){1} }.should.raise(TypeError)
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)
+ -> { Matrix.build(-1, 1){1} }.should.raise(ArgumentError)
+ -> { Matrix.build(+1,-1){1} }.should.raise(ArgumentError)
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.should.empty?
m.column_size.should == 3
m = Matrix.build(3, 0){
raise "Should not yield"
}
- m.should be_empty
+ m.should.empty?
m.row_size.should == 3
end
@@ -68,6 +68,6 @@ 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)
+ MatrixSub.build(3){1}.should.instance_of?(MatrixSub)
end
end
diff --git a/spec/ruby/library/matrix/clone_spec.rb b/spec/ruby/library/matrix/clone_spec.rb
index 74e5bf157e..51aefc6010 100644
--- a/spec/ruby/library/matrix/clone_spec.rb
+++ b/spec/ruby/library/matrix/clone_spec.rb
@@ -9,17 +9,17 @@ describe "Matrix#clone" do
it "returns a shallow copy of the matrix" do
b = @a.clone
- @a.should_not equal(b)
- b.should be_kind_of(Matrix)
+ @a.should_not.equal?(b)
+ b.should.is_a?(Matrix)
b.should == @a
0.upto(@a.row_size - 1) do |i|
- @a.row(i).should_not equal(b.row(i))
+ @a.row(i).should_not.equal?(b.row(i))
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)
+ MatrixSub.ins.clone.should.instance_of?(MatrixSub)
end
end
end
diff --git a/spec/ruby/library/matrix/coerce_spec.rb b/spec/ruby/library/matrix/coerce_spec.rb
index 4022f00236..6032dd2f62 100644
--- a/spec/ruby/library/matrix/coerce_spec.rb
+++ b/spec/ruby/library/matrix/coerce_spec.rb
@@ -2,7 +2,7 @@ require_relative '../../spec_helper'
require 'matrix'
describe "Matrix#coerce" do
- it "allows the division of integer by a Matrix " 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
diff --git a/spec/ruby/library/matrix/collect_spec.rb b/spec/ruby/library/matrix/collect_spec.rb
index bba640213b..664c3f3038 100644
--- a/spec/ruby/library/matrix/collect_spec.rb
+++ b/spec/ruby/library/matrix/collect_spec.rb
@@ -1,6 +1,8 @@
require_relative '../../spec_helper'
-require_relative 'shared/collect'
+require 'matrix'
describe "Matrix#collect" do
- it_behaves_like :collect, :collect
+ it "is an alias of Matrix#map" do
+ Matrix.instance_method(:collect).should == Matrix.instance_method(:map)
+ end
end
diff --git a/spec/ruby/library/matrix/column_spec.rb b/spec/ruby/library/matrix/column_spec.rb
index 1f3c80964a..d5d8c80c1a 100644
--- a/spec/ruby/library/matrix/column_spec.rb
+++ b/spec/ruby/library/matrix/column_spec.rb
@@ -21,7 +21,7 @@ describe "Matrix#column" do
end
it "returns self when called with a block" do
- @m.column(0) { |x| x }.should equal(@m)
+ @m.column(0) { |x| x }.should.equal?(@m)
end
it "returns nil when out of bounds" do
@@ -29,7 +29,7 @@ describe "Matrix#column" do
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
+ -> { @m.column(3){ raise } }.should_not.raise
+ -> { @m.column(-4){ raise } }.should_not.raise
end
end
diff --git a/spec/ruby/library/matrix/column_vector_spec.rb b/spec/ruby/library/matrix/column_vector_spec.rb
index 47e866a8d5..d86c3f9e42 100644
--- a/spec/ruby/library/matrix/column_vector_spec.rb
+++ b/spec/ruby/library/matrix/column_vector_spec.rb
@@ -6,20 +6,20 @@ describe "Matrix.column_vector" do
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.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.should.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)
+ MatrixSub.column_vector([4,5,6]).should.instance_of?(MatrixSub)
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..7ac6871e7f 100644
--- a/spec/ruby/library/matrix/column_vectors_spec.rb
+++ b/spec/ruby/library/matrix/column_vectors_spec.rb
@@ -8,11 +8,11 @@ describe "Matrix#column_vectors" do
end
it "returns an Array" do
- Matrix[ [1,2], [3,4] ].column_vectors.should be_an_instance_of(Array)
+ Matrix[ [1,2], [3,4] ].column_vectors.should.instance_of?(Array)
end
it "returns an Array of Vectors" do
- @vectors.all? {|v| v.should be_an_instance_of(Vector)}
+ @vectors.all? {|v| v.should.instance_of?(Vector)}
end
it "returns each column as a Vector" do
diff --git a/spec/ruby/library/matrix/columns_spec.rb b/spec/ruby/library/matrix/columns_spec.rb
index 3095fdd7af..ac9587899d 100644
--- a/spec/ruby/library/matrix/columns_spec.rb
+++ b/spec/ruby/library/matrix/columns_spec.rb
@@ -10,7 +10,7 @@ describe "Matrix.columns" do
end
it "creates a Matrix from argument columns" do
- @m.should be_an_instance_of(Matrix)
+ @m.should.instance_of?(Matrix)
@m.column(0).to_a.should == @a
@m.column(1).to_a.should == @b
end
@@ -36,7 +36,7 @@ describe "Matrix.columns" do
describe "for a subclass of Matrix" do
it "returns an instance of that subclass" do
- MatrixSub.columns([[1]]).should be_an_instance_of(MatrixSub)
+ MatrixSub.columns([[1]]).should.instance_of?(MatrixSub)
end
end
end
diff --git a/spec/ruby/library/matrix/conj_spec.rb b/spec/ruby/library/matrix/conj_spec.rb
index ecee95c255..eff5986fc4 100644
--- a/spec/ruby/library/matrix/conj_spec.rb
+++ b/spec/ruby/library/matrix/conj_spec.rb
@@ -1,6 +1,8 @@
require_relative '../../spec_helper'
-require_relative 'shared/conjugate'
+require 'matrix'
describe "Matrix#conj" do
- it_behaves_like :matrix_conjugate, :conj
+ it "is an alias of Matrix#conjugate" do
+ Matrix.instance_method(:conj).should == Matrix.instance_method(:conjugate)
+ end
end
diff --git a/spec/ruby/library/matrix/conjugate_spec.rb b/spec/ruby/library/matrix/conjugate_spec.rb
index 682bd41d94..46077d4fa9 100644
--- a/spec/ruby/library/matrix/conjugate_spec.rb
+++ b/spec/ruby/library/matrix/conjugate_spec.rb
@@ -1,6 +1,20 @@
require_relative '../../spec_helper'
-require_relative 'shared/conjugate'
+require_relative 'fixtures/classes'
describe "Matrix#conjugate" do
- it_behaves_like :matrix_conjugate, :conjugate
+ it "returns a matrix with all entries 'conjugated'" do
+ Matrix[ [1, 2], [3, 4] ].conjugate.should == Matrix[ [1, 2], [3, 4] ]
+ Matrix[ [1.9, Complex(1,1)], [3, 4] ].conjugate.should == Matrix[ [1.9, Complex(1,-1)], [3, 4] ]
+ end
+
+ it "returns empty matrices on the same size if empty" do
+ Matrix.empty(0, 3).conjugate.should == Matrix.empty(0, 3)
+ Matrix.empty(3, 0).conjugate.should == Matrix.empty(3, 0)
+ end
+
+ describe "for a subclass of Matrix" do
+ it "returns an instance of that subclass" do
+ MatrixSub.ins.conjugate.should.instance_of?(MatrixSub)
+ end
+ end
end
diff --git a/spec/ruby/library/matrix/constructor_spec.rb b/spec/ruby/library/matrix/constructor_spec.rb
index 70d77babbb..026525f36d 100644
--- a/spec/ruby/library/matrix/constructor_spec.rb
+++ b/spec/ruby/library/matrix/constructor_spec.rb
@@ -5,10 +5,10 @@ require 'matrix'
describe "Matrix.[]" do
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)
+ -> { Matrix[5] }.should.raise(TypeError)
+ -> { Matrix[nil] }.should.raise(TypeError)
+ -> { Matrix[1..2] }.should.raise(TypeError)
+ -> { Matrix[[1, 2], 3] }.should.raise(TypeError)
end
it "creates an empty Matrix with no arguments" do
@@ -18,15 +18,13 @@ describe "Matrix.[]" do
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)
+ ->{ Matrix[ [0], [0,1] ] }.should.raise(Matrix::ErrDimensionMismatch)
+ ->{ Matrix[ [0,1], [0,1,2], [0,1] ]}.should.raise(Matrix::ErrDimensionMismatch)
end
it "accepts vector arguments" do
a = Matrix[Vector[1, 2], Vector[3, 4]]
- a.should be_an_instance_of(Matrix)
+ a.should.instance_of?(Matrix)
a.should == Matrix[ [1, 2], [3, 4] ]
end
@@ -38,7 +36,7 @@ describe "Matrix.[]" do
it "returns a Matrix object" do
- Matrix[ [1] ].should be_an_instance_of(Matrix)
+ Matrix[ [1] ].should.instance_of?(Matrix)
end
it "can create an nxn Matrix" do
@@ -59,7 +57,7 @@ describe "Matrix.[]" do
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)
+ MatrixSub[ [20,30], [40.5, 9] ].should.instance_of?(MatrixSub)
end
end
end
diff --git a/spec/ruby/library/matrix/det_spec.rb b/spec/ruby/library/matrix/det_spec.rb
index aa7086cacf..fc4b1c252a 100644
--- a/spec/ruby/library/matrix/det_spec.rb
+++ b/spec/ruby/library/matrix/det_spec.rb
@@ -1,7 +1,8 @@
require_relative '../../spec_helper'
-require_relative 'shared/determinant'
require 'matrix'
describe "Matrix#det" do
- it_behaves_like :determinant, :det
+ it "is an alias of Matrix#determinant" do
+ Matrix.instance_method(:det).should == Matrix.instance_method(:determinant)
+ end
end
diff --git a/spec/ruby/library/matrix/determinant_spec.rb b/spec/ruby/library/matrix/determinant_spec.rb
index 825c9907b1..603e13ba28 100644
--- a/spec/ruby/library/matrix/determinant_spec.rb
+++ b/spec/ruby/library/matrix/determinant_spec.rb
@@ -1,7 +1,39 @@
require_relative '../../spec_helper'
-require_relative 'shared/determinant'
require 'matrix'
describe "Matrix#determinant" do
- it_behaves_like :determinant, :determinant
+ it "returns the determinant of a square Matrix" do
+ m = Matrix[ [7,6], [3,9] ]
+ m.determinant.should == 45
+
+ m = Matrix[ [9, 8], [6,5] ]
+ m.determinant.should == -3
+
+ m = Matrix[ [9,8,3], [4,20,5], [1,1,1] ]
+ m.determinant.should == 95
+ end
+
+ it "returns the determinant of a single-element Matrix" do
+ m = Matrix[ [2] ]
+ m.determinant.should == 2
+ end
+
+ it "returns 1 for an empty Matrix" do
+ m = Matrix[ ]
+ m.determinant.should == 1
+ end
+
+ it "returns the determinant even for Matrices containing 0 as first entry" do
+ Matrix[[0,1],[1,0]].determinant.should == -1
+ end
+
+ it "raises an error for rectangular matrices" do
+ -> {
+ Matrix[[1], [2], [3]].determinant
+ }.should.raise(Matrix::ErrDimensionMismatch)
+
+ -> {
+ Matrix.empty(3,0).determinant
+ }.should.raise(Matrix::ErrDimensionMismatch)
+ end
end
diff --git a/spec/ruby/library/matrix/diagonal_spec.rb b/spec/ruby/library/matrix/diagonal_spec.rb
index ef9738e73e..ee84ac8c28 100644
--- a/spec/ruby/library/matrix/diagonal_spec.rb
+++ b/spec/ruby/library/matrix/diagonal_spec.rb
@@ -8,7 +8,7 @@ describe "Matrix.diagonal" do
end
it "returns an object of type Matrix" do
- @m.should be_kind_of(Matrix)
+ @m.should.is_a?(Matrix)
end
it "returns a square Matrix of the right size" do
@@ -34,27 +34,27 @@ describe "Matrix.diagonal" do
describe "for a subclass of Matrix" do
it "returns an instance of that subclass" do
- MatrixSub.diagonal(1).should be_an_instance_of(MatrixSub)
+ MatrixSub.diagonal(1).should.instance_of?(MatrixSub)
end
end
end
describe "Matrix.diagonal?" do
it "returns true for a diagonal Matrix" do
- Matrix.diagonal([1, 2, 3]).diagonal?.should be_true
+ Matrix.diagonal([1, 2, 3]).diagonal?.should == true
end
it "returns true for a zero square Matrix" do
- Matrix.zero(3).diagonal?.should be_true
+ Matrix.zero(3).diagonal?.should == 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
+ Matrix[[0, 1], [0, 0]].diagonal?.should == false
+ Matrix[[1, 2, 3], [1, 2, 3], [1, 2, 3]].diagonal?.should == false
end
it "returns true for an empty 0x0 matrix" do
- Matrix.empty(0,0).diagonal?.should be_true
+ Matrix.empty(0,0).diagonal?.should == true
end
it "raises an error for rectangular matrices" do
@@ -66,7 +66,7 @@ describe "Matrix.diagonal?" do
].each do |rectangular_matrix|
-> {
rectangular_matrix.diagonal?
- }.should raise_error(Matrix::ErrDimensionMismatch)
+ }.should.raise(Matrix::ErrDimensionMismatch)
end
end
end
diff --git a/spec/ruby/library/matrix/divide_spec.rb b/spec/ruby/library/matrix/divide_spec.rb
index 2e3bb85bf6..711a5189e4 100644
--- a/spec/ruby/library/matrix/divide_spec.rb
+++ b/spec/ruby/library/matrix/divide_spec.rb
@@ -30,25 +30,25 @@ describe "Matrix#/" do
end
it "raises a Matrix::ErrDimensionMismatch if the matrices are different sizes" do
- -> { @a / Matrix[ [1] ] }.should raise_error(Matrix::ErrDimensionMismatch)
+ -> { @a / Matrix[ [1] ] }.should.raise(Matrix::ErrDimensionMismatch)
end
it "returns an instance of Matrix" do
- (@a / @b).should be_kind_of(Matrix)
+ (@a / @b).should.is_a?(Matrix)
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)
+ (m/m).should.instance_of?(MatrixSub)
+ (m/1).should.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)
+ -> { @a / nil }.should.raise(TypeError)
+ -> { @a / "a" }.should.raise(TypeError)
+ -> { @a / [ [1, 2] ] }.should.raise(TypeError)
+ -> { @a / Object.new }.should.raise(TypeError)
end
end
diff --git a/spec/ruby/library/matrix/each_spec.rb b/spec/ruby/library/matrix/each_spec.rb
index f3b0f01867..b4bfd3c76f 100644
--- a/spec/ruby/library/matrix/each_spec.rb
+++ b/spec/ruby/library/matrix/each_spec.rb
@@ -9,12 +9,12 @@ describe "Matrix#each" do
it "returns an Enumerator when called without a block" do
enum = @m.each
- enum.should be_an_instance_of(Enumerator)
+ enum.should.instance_of?(Enumerator)
enum.to_a.should == @result
end
it "returns self" do
- @m.each{}.should equal(@m)
+ @m.each{}.should.equal?(@m)
end
it "yields the elements starting with the those of the first row" do
@@ -33,13 +33,13 @@ describe "Matrix#each with an argument" do
it "raises an ArgumentError for unrecognized argument" do
-> {
@m.each("all"){}
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
-> {
@m.each(nil){}
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
-> {
@m.each(:left){}
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
it "yields the rights elements when passed :diagonal" do
diff --git a/spec/ruby/library/matrix/each_with_index_spec.rb b/spec/ruby/library/matrix/each_with_index_spec.rb
index a005b88621..17e3f3f44c 100644
--- a/spec/ruby/library/matrix/each_with_index_spec.rb
+++ b/spec/ruby/library/matrix/each_with_index_spec.rb
@@ -16,12 +16,12 @@ describe "Matrix#each_with_index" do
it "returns an Enumerator when called without a block" do
enum = @m.each_with_index
- enum.should be_an_instance_of(Enumerator)
+ enum.should.instance_of?(Enumerator)
enum.to_a.should == @result
end
it "returns self" do
- @m.each_with_index{}.should equal(@m)
+ @m.each_with_index{}.should.equal?(@m)
end
it "yields the elements starting with the those of the first row" do
@@ -40,13 +40,13 @@ describe "Matrix#each_with_index with an argument" do
it "raises an ArgumentError for unrecognized argument" do
-> {
@m.each_with_index("all"){}
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
-> {
@m.each_with_index(nil){}
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
-> {
@m.each_with_index(:left){}
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
it "yields the rights elements when passed :diagonal" do
diff --git a/spec/ruby/library/matrix/eigenvalue_decomposition/initialize_spec.rb b/spec/ruby/library/matrix/eigenvalue_decomposition/initialize_spec.rb
index 8438f63133..cbda82a16a 100644
--- a/spec/ruby/library/matrix/eigenvalue_decomposition/initialize_spec.rb
+++ b/spec/ruby/library/matrix/eigenvalue_decomposition/initialize_spec.rb
@@ -5,16 +5,16 @@ describe "Matrix::EigenvalueDecomposition#initialize" do
it "raises an error if argument is not a matrix" do
-> {
Matrix::EigenvalueDecomposition.new([[]])
- }.should raise_error(TypeError)
+ }.should.raise(TypeError)
-> {
Matrix::EigenvalueDecomposition.new(42)
- }.should raise_error(TypeError)
+ }.should.raise(TypeError)
end
it "raises an error if matrix is not square" do
-> {
Matrix::EigenvalueDecomposition.new(Matrix[[1, 2]])
- }.should raise_error(Matrix::ErrDimensionMismatch)
+ }.should.raise(Matrix::ErrDimensionMismatch)
end
it "never hangs" do
diff --git a/spec/ruby/library/matrix/element_reference_spec.rb b/spec/ruby/library/matrix/element_reference_spec.rb
index b950d1c391..c6804b3846 100644
--- a/spec/ruby/library/matrix/element_reference_spec.rb
+++ b/spec/ruby/library/matrix/element_reference_spec.rb
@@ -16,8 +16,8 @@ describe "Matrix#[]" do
end
it "returns nil for an invalid index pair" do
- @m[8,1].should be_nil
- @m[1,8].should be_nil
+ @m[8,1].should == nil
+ @m[1,8].should == nil
end
end
diff --git a/spec/ruby/library/matrix/empty_spec.rb b/spec/ruby/library/matrix/empty_spec.rb
index 5f294711db..7b0f0af9eb 100644
--- a/spec/ruby/library/matrix/empty_spec.rb
+++ b/spec/ruby/library/matrix/empty_spec.rb
@@ -4,20 +4,20 @@ 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
+ Matrix[ ].empty?.should == true
+ Matrix[ [], [], [] ].empty?.should == true
+ Matrix[ [], [], [] ].transpose.empty?.should == 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
+ Matrix[ [1, 2] ].empty?.should == false
+ Matrix[ [1], [2] ].empty?.should == false
end
it "doesn't accept any parameter" do
->{
Matrix[ [1, 2] ].empty?(42)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
end
@@ -40,29 +40,29 @@ describe "Matrix.empty" do
it "does not accept more than two parameters" do
->{
Matrix.empty(1, 2, 3)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
it "raises an error if both dimensions are > 0" do
->{
Matrix.empty(1, 2)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
it "raises an error if any dimension is < 0" do
->{
Matrix.empty(-2, 0)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
->{
Matrix.empty(0, -2)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
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)
+ MatrixSub.empty(0, 1).should.instance_of?(MatrixSub)
end
end
diff --git a/spec/ruby/library/matrix/eql_spec.rb b/spec/ruby/library/matrix/eql_spec.rb
index ea26c3320d..cda122f4d8 100644
--- a/spec/ruby/library/matrix/eql_spec.rb
+++ b/spec/ruby/library/matrix/eql_spec.rb
@@ -6,6 +6,6 @@ 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
+ Matrix[[1, 2],[3, 4]].eql?(Matrix[[1, 2],[3, 4.0]]).should == false
end
end
diff --git a/spec/ruby/library/matrix/exponent_spec.rb b/spec/ruby/library/matrix/exponent_spec.rb
index 38cdfa9276..4cbe63587d 100644
--- a/spec/ruby/library/matrix/exponent_spec.rb
+++ b/spec/ruby/library/matrix/exponent_spec.rb
@@ -17,8 +17,8 @@ describe "Matrix#**" do
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)
+ -> { m ** 3 }.should.raise(Matrix::ErrDimensionMismatch)
+ -> { m ** 0 }.should.raise(Matrix::ErrDimensionMismatch)
end
describe "that is < 0" do
@@ -30,7 +30,7 @@ describe "Matrix#**" do
it "raises a ErrNotRegular for irregular matrices" do
m = Matrix[ [1, 1], [1, 1] ]
- -> { m ** -2 }.should raise_error(Matrix::ErrNotRegular)
+ -> { m ** -2 }.should.raise(Matrix::ErrNotRegular)
end
end
@@ -42,7 +42,7 @@ describe "Matrix#**" do
it "raises an ErrDimensionMismatch for non-square matrices" do
m = Matrix[ [1, 1] ]
- -> { m ** 0 }.should raise_error(Matrix::ErrDimensionMismatch)
+ -> { m ** 0 }.should.raise(Matrix::ErrDimensionMismatch)
end
end
end
@@ -56,7 +56,7 @@ describe "Matrix#**" do
describe "for a subclass of Matrix" do
it "returns an instance of that subclass" do
- (MatrixSub.ins ** 1).should be_an_instance_of(MatrixSub)
+ (MatrixSub.ins ** 1).should.instance_of?(MatrixSub)
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..c7278fd449 100644
--- a/spec/ruby/library/matrix/find_index_spec.rb
+++ b/spec/ruby/library/matrix/find_index_spec.rb
@@ -8,12 +8,12 @@ describe "Matrix#find_index without any argument" do
it "returns an Enumerator when called without a block" do
enum = @m.find_index
- enum.should be_an_instance_of(Enumerator)
+ enum.should.instance_of?(Enumerator)
enum.to_a.should == [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
+ @m.find_index{false}.should == nil
end
it "returns the first index for which the block is true" do
@@ -48,7 +48,7 @@ describe "Matrix#find_index with a subselection 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)
+ matrix.find_index(selector).should.instance_of?(Enumerator)
end
end
end
@@ -116,7 +116,7 @@ describe "Matrix#find_index with only a generic argument" do
end
it "returns nil if the value is not found" do
- @m.find_index(42).should be_nil
+ @m.find_index(42).should == nil
end
it "returns the first index for of the requested value" do
@@ -132,15 +132,15 @@ 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)
+ }.should.raise(ArgumentError)
-> {
@m.find_index(1, nil){}
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
-> {
@m.find_index(1, :left){}
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
-> {
@m.find_index(:diagonal, 1){}
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
end
diff --git a/spec/ruby/library/matrix/hash_spec.rb b/spec/ruby/library/matrix/hash_spec.rb
index 7dabcd3737..27bf7b9751 100644
--- a/spec/ruby/library/matrix/hash_spec.rb
+++ b/spec/ruby/library/matrix/hash_spec.rb
@@ -4,7 +4,7 @@ require 'matrix'
describe "Matrix#hash" do
it "returns an Integer" do
- Matrix[ [1,2] ].hash.should be_an_instance_of(Integer)
+ Matrix[ [1,2] ].hash.should.instance_of?(Integer)
end
it "returns the same value for the same matrix" do
diff --git a/spec/ruby/library/matrix/hermitian_spec.rb b/spec/ruby/library/matrix/hermitian_spec.rb
index 177ca64d83..94d0dbe6b6 100644
--- a/spec/ruby/library/matrix/hermitian_spec.rb
+++ b/spec/ruby/library/matrix/hermitian_spec.rb
@@ -3,15 +3,15 @@ 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
+ Matrix[[1, 2, Complex(0, 3)], [2, 4, 5], [Complex(0, -3), 5, 6]].hermitian?.should == true
end
it "returns true for a 0x0 empty matrix" do
- Matrix.empty.hermitian?.should be_true
+ Matrix.empty.hermitian?.should == true
end
it "returns false for an asymmetric Matrix" do
- Matrix[[1, 2],[-2, 1]].hermitian?.should be_false
+ Matrix[[1, 2],[-2, 1]].hermitian?.should == false
end
it "raises an error for rectangular matrices" do
@@ -23,12 +23,12 @@ describe "Matrix.hermitian?" do
].each do |rectangular_matrix|
-> {
rectangular_matrix.hermitian?
- }.should raise_error(Matrix::ErrDimensionMismatch)
+ }.should.raise(Matrix::ErrDimensionMismatch)
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
+ Matrix[[Complex(1,1)]].hermitian?.should == false
+ Matrix[[Complex(1,0)]].hermitian?.should == true
end
end
diff --git a/spec/ruby/library/matrix/identity_spec.rb b/spec/ruby/library/matrix/identity_spec.rb
index 646462bc47..afefd27565 100644
--- a/spec/ruby/library/matrix/identity_spec.rb
+++ b/spec/ruby/library/matrix/identity_spec.rb
@@ -1,6 +1,20 @@
require_relative '../../spec_helper'
-require_relative 'shared/identity'
+require_relative 'fixtures/classes'
+require 'matrix'
describe "Matrix.identity" do
- it_behaves_like :matrix_identity, :identity
+ it "returns a Matrix" do
+ Matrix.identity(2).should.is_a?(Matrix)
+ end
+
+ it "returns a n x n identity matrix" do
+ Matrix.identity(3).should == Matrix.scalar(3, 1)
+ Matrix.identity(100).should == Matrix.scalar(100, 1)
+ end
+
+ describe "for a subclass of Matrix" do
+ it "returns an instance of that subclass" do
+ MatrixSub.identity(2).should.instance_of?(MatrixSub)
+ end
+ end
end
diff --git a/spec/ruby/library/matrix/imag_spec.rb b/spec/ruby/library/matrix/imag_spec.rb
index 1c988753d8..9d6cc2e953 100644
--- a/spec/ruby/library/matrix/imag_spec.rb
+++ b/spec/ruby/library/matrix/imag_spec.rb
@@ -1,6 +1,8 @@
require_relative '../../spec_helper'
-require_relative 'shared/imaginary'
+require 'matrix'
describe "Matrix#imag" do
- it_behaves_like :matrix_imaginary, :imag
+ it "is an alias of Matrix#imaginary" do
+ Matrix.instance_method(:imag).should == Matrix.instance_method(:imaginary)
+ end
end
diff --git a/spec/ruby/library/matrix/imaginary_spec.rb b/spec/ruby/library/matrix/imaginary_spec.rb
index ceae4bbe8d..bbd06677b7 100644
--- a/spec/ruby/library/matrix/imaginary_spec.rb
+++ b/spec/ruby/library/matrix/imaginary_spec.rb
@@ -1,6 +1,21 @@
require_relative '../../spec_helper'
-require_relative 'shared/imaginary'
+require_relative 'fixtures/classes'
+require 'matrix'
describe "Matrix#imaginary" do
- it_behaves_like :matrix_imaginary, :imaginary
+ it "returns a matrix with the imaginary part of the elements of the receiver" do
+ Matrix[ [1, 2], [3, 4] ].imaginary.should == Matrix[ [0, 0], [0, 0] ]
+ Matrix[ [1.9, Complex(1,1)], [Complex(-2,0.42), 4] ].imaginary.should == Matrix[ [0, 1], [0.42, 0] ]
+ end
+
+ it "returns empty matrices on the same size if empty" do
+ Matrix.empty(0, 3).imaginary.should == Matrix.empty(0, 3)
+ Matrix.empty(3, 0).imaginary.should == Matrix.empty(3, 0)
+ end
+
+ describe "for a subclass of Matrix" do
+ it "returns an instance of that subclass" do
+ MatrixSub.ins.imaginary.should.instance_of?(MatrixSub)
+ end
+ end
end
diff --git a/spec/ruby/library/matrix/inv_spec.rb b/spec/ruby/library/matrix/inv_spec.rb
index 82879a6d82..02684030d2 100644
--- a/spec/ruby/library/matrix/inv_spec.rb
+++ b/spec/ruby/library/matrix/inv_spec.rb
@@ -1,7 +1,8 @@
require_relative '../../spec_helper'
-require_relative 'spec_helper'
-require_relative 'shared/inverse'
+require 'matrix'
describe "Matrix#inv" do
- it_behaves_like :inverse, :inv
+ it "is an alias of Matrix#inverse" do
+ Matrix.instance_method(:inv).should == Matrix.instance_method(:inverse)
+ end
end
diff --git a/spec/ruby/library/matrix/inverse_spec.rb b/spec/ruby/library/matrix/inverse_spec.rb
index fa3fa7de8a..38b01b28fb 100644
--- a/spec/ruby/library/matrix/inverse_spec.rb
+++ b/spec/ruby/library/matrix/inverse_spec.rb
@@ -1,7 +1,39 @@
require_relative '../../spec_helper'
require_relative 'spec_helper'
-require_relative 'shared/inverse'
+require_relative 'fixtures/classes'
+require 'matrix'
describe "Matrix#inverse" do
- it_behaves_like :inverse, :inverse
+ it "returns a Matrix" do
+ Matrix[ [1,2], [2,1] ].inverse.should.instance_of?(Matrix)
+ end
+
+ it "returns the inverse of the Matrix" do
+ Matrix[
+ [1, 3, 3], [1, 4, 3], [1, 3, 4]
+ ].inverse.should ==
+ Matrix[
+ [7, -3, -3], [-1, 1, 0], [-1, 0, 1]
+ ]
+ end
+
+ it "returns the inverse of the Matrix (other case)" do
+ Matrix[
+ [1, 2, 3], [0, 1, 4], [5, 6, 0]
+ ].inverse.should be_close_to_matrix([
+ [-24, 18, 5], [20, -15, -4], [-5, 4, 1]
+ ])
+ end
+
+ it "raises a ErrDimensionMismatch if the Matrix is not square" do
+ ->{
+ Matrix[ [1,2,3], [1,2,3] ].inverse
+ }.should.raise(Matrix::ErrDimensionMismatch)
+ end
+
+ describe "for a subclass of Matrix" do
+ it "returns an instance of that subclass" do
+ MatrixSub.ins.inverse.should.instance_of?(MatrixSub)
+ end
+ end
end
diff --git a/spec/ruby/library/matrix/lower_triangular_spec.rb b/spec/ruby/library/matrix/lower_triangular_spec.rb
index f3aa4501f4..7e8688fd9b 100644
--- a/spec/ruby/library/matrix/lower_triangular_spec.rb
+++ b/spec/ruby/library/matrix/lower_triangular_spec.rb
@@ -3,22 +3,22 @@ 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
+ Matrix[[1, 0, 0], [1, 2, 0], [1, 2, 3]].lower_triangular?.should == true
+ Matrix.diagonal([1, 2, 3]).lower_triangular?.should == true
+ Matrix[[1, 0], [1, 2], [1, 2], [1, 2]].lower_triangular?.should == true
+ Matrix[[1, 0, 0, 0], [1, 2, 0, 0]].lower_triangular?.should == 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
+ Matrix.empty(3, 0).lower_triangular?.should == true
+ Matrix.empty(0, 3).lower_triangular?.should == true
+ Matrix.empty(0, 0).lower_triangular?.should == 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
+ Matrix[[0, 1], [0, 0]].lower_triangular?.should == false
+ Matrix[[1, 2, 3], [1, 2, 3], [1, 2, 3]].lower_triangular?.should == false
+ Matrix[[0, 1], [0, 0], [0, 0], [0, 0]].lower_triangular?.should == false
+ Matrix[[0, 0, 0, 1], [0, 0, 0, 0]].lower_triangular?.should == false
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..98ac5c71a3 100644
--- a/spec/ruby/library/matrix/lup_decomposition/determinant_spec.rb
+++ b/spec/ruby/library/matrix/lup_decomposition/determinant_spec.rb
@@ -15,7 +15,7 @@ describe "Matrix::LUPDecomposition#determinant" do
lup = m.lup
-> {
lup.determinant
- }.should raise_error(Matrix::ErrDimensionMismatch)
+ }.should.raise(Matrix::ErrDimensionMismatch)
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..b813757525 100644
--- a/spec/ruby/library/matrix/lup_decomposition/initialize_spec.rb
+++ b/spec/ruby/library/matrix/lup_decomposition/initialize_spec.rb
@@ -5,9 +5,9 @@ describe "Matrix::LUPDecomposition#initialize" do
it "raises an error if argument is not a matrix" do
-> {
Matrix::LUPDecomposition.new([[]])
- }.should raise_error(TypeError)
+ }.should.raise(TypeError)
-> {
Matrix::LUPDecomposition.new(42)
- }.should raise_error(TypeError)
+ }.should.raise(TypeError)
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..0a6797cc85 100644
--- a/spec/ruby/library/matrix/lup_decomposition/l_spec.rb
+++ b/spec/ruby/library/matrix/lup_decomposition/l_spec.rb
@@ -13,6 +13,6 @@ describe "Matrix::LUPDecomposition#l" do
end
it "returns a lower triangular matrix" do
- @l.lower_triangular?.should be_true
+ @l.lower_triangular?.should == true
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..2c44399b79 100644
--- a/spec/ruby/library/matrix/lup_decomposition/p_spec.rb
+++ b/spec/ruby/library/matrix/lup_decomposition/p_spec.rb
@@ -13,6 +13,6 @@ describe "Matrix::LUPDecomposition#p" do
end
it "returns a permutation matrix" do
- @p.permutation?.should be_true
+ @p.permutation?.should == true
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..9927e96727 100644
--- a/spec/ruby/library/matrix/lup_decomposition/solve_spec.rb
+++ b/spec/ruby/library/matrix/lup_decomposition/solve_spec.rb
@@ -8,7 +8,7 @@ describe "Matrix::LUPDecomposition#solve" do
lu = Matrix::LUPDecomposition.new(a)
-> {
lu.solve(a)
- }.should raise_error(Matrix::ErrNotRegular)
+ }.should.raise(Matrix::ErrNotRegular)
end
describe "for non singular matrices" do
@@ -33,7 +33,7 @@ describe "Matrix::LUPDecomposition#solve" do
values = Matrix[[1, 2, 3, 4], [0, 1, 2, 3]]
-> {
@lu.solve(values)
- }.should raise_error(Matrix::ErrDimensionMismatch)
+ }.should.raise(Matrix::ErrDimensionMismatch)
end
it "returns the right vector when given a vector of the appropriate size" do
@@ -46,7 +46,7 @@ describe "Matrix::LUPDecomposition#solve" do
values = Vector[14, 55]
-> {
@lu.solve(values)
- }.should raise_error(Matrix::ErrDimensionMismatch)
+ }.should.raise(Matrix::ErrDimensionMismatch)
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..ab59677dd9 100644
--- a/spec/ruby/library/matrix/lup_decomposition/to_a_spec.rb
+++ b/spec/ruby/library/matrix/lup_decomposition/to_a_spec.rb
@@ -10,9 +10,9 @@ describe "Matrix::LUPDecomposition#to_a" do
end
it "returns an array of three matrices" do
- @to_a.should be_kind_of(Array)
+ @to_a.should.is_a?(Array)
@to_a.length.should == 3
- @to_a.each{|m| m.should be_kind_of(Matrix)}
+ @to_a.each{|m| m.should.is_a?(Matrix)}
end
it "returns [l, u, p] such that l*u == a*p" do
diff --git a/spec/ruby/library/matrix/lup_decomposition/u_spec.rb b/spec/ruby/library/matrix/lup_decomposition/u_spec.rb
index ca3dfc1f00..967bc669dc 100644
--- a/spec/ruby/library/matrix/lup_decomposition/u_spec.rb
+++ b/spec/ruby/library/matrix/lup_decomposition/u_spec.rb
@@ -13,6 +13,6 @@ describe "Matrix::LUPDecomposition#u" do
end
it "returns an upper triangular matrix" do
- @u.upper_triangular?.should be_true
+ @u.upper_triangular?.should == true
end
end
diff --git a/spec/ruby/library/matrix/map_spec.rb b/spec/ruby/library/matrix/map_spec.rb
index bc07c48cda..bae96db381 100644
--- a/spec/ruby/library/matrix/map_spec.rb
+++ b/spec/ruby/library/matrix/map_spec.rb
@@ -1,6 +1,26 @@
require_relative '../../spec_helper'
-require_relative 'shared/collect'
+require_relative 'fixtures/classes'
describe "Matrix#map" do
- it_behaves_like :collect, :map
+ before :all do
+ @m = Matrix[ [1, 2], [1, 2] ]
+ end
+
+ it "returns an instance of Matrix" do
+ @m.map{|n| n * 2 }.should.is_a?(Matrix)
+ end
+
+ it "returns a Matrix where each element is the result of the block" do
+ @m.map { |n| n * 2 }.should == Matrix[ [2, 4], [2, 4] ]
+ end
+
+ it "returns an enumerator if no block is given" do
+ @m.map.should.instance_of?(Enumerator)
+ end
+
+ describe "for a subclass of Matrix" do
+ it "returns an instance of that subclass" do
+ MatrixSub.ins.map{1}.should.instance_of?(MatrixSub)
+ end
+ end
end
diff --git a/spec/ruby/library/matrix/minor_spec.rb b/spec/ruby/library/matrix/minor_spec.rb
index 009826c3d6..6b29db568b 100644
--- a/spec/ruby/library/matrix/minor_spec.rb
+++ b/spec/ruby/library/matrix/minor_spec.rb
@@ -79,7 +79,7 @@ describe "Matrix#minor" do
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)
+ MatrixSub.ins.minor(0, 1, 0, 1).should.instance_of?(MatrixSub)
end
end
end
diff --git a/spec/ruby/library/matrix/minus_spec.rb b/spec/ruby/library/matrix/minus_spec.rb
index 95cf4a6072..7426aa2d2c 100644
--- a/spec/ruby/library/matrix/minus_spec.rb
+++ b/spec/ruby/library/matrix/minus_spec.rb
@@ -13,30 +13,30 @@ describe "Matrix#-" do
end
it "returns an instance of Matrix" do
- (@a - @b).should be_kind_of(Matrix)
+ (@a - @b).should.is_a?(Matrix)
end
it "raises a Matrix::ErrDimensionMismatch if the matrices are different sizes" do
- -> { @a - Matrix[ [1] ] }.should raise_error(Matrix::ErrDimensionMismatch)
+ -> { @a - Matrix[ [1] ] }.should.raise(Matrix::ErrDimensionMismatch)
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)
+ -> { @a - 2 }.should.raise(Matrix::ErrOperationNotDefined)
+ -> { @a - 1.2 }.should.raise(Matrix::ErrOperationNotDefined)
+ -> { @a - bignum_value }.should.raise(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)
+ -> { @a - nil }.should.raise(TypeError)
+ -> { @a - "a" }.should.raise(TypeError)
+ -> { @a - [ [1, 2] ] }.should.raise(TypeError)
+ -> { @a - Object.new }.should.raise(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-m).should.instance_of?(MatrixSub)
end
end
end
diff --git a/spec/ruby/library/matrix/multiply_spec.rb b/spec/ruby/library/matrix/multiply_spec.rb
index 206868af92..6c495c5521 100644
--- a/spec/ruby/library/matrix/multiply_spec.rb
+++ b/spec/ruby/library/matrix/multiply_spec.rb
@@ -33,7 +33,7 @@ describe "Matrix#*" do
end
it "raises a Matrix::ErrDimensionMismatch if the matrices are different sizes" do
- -> { @a * Matrix[ [1] ] }.should raise_error(Matrix::ErrDimensionMismatch)
+ -> { @a * Matrix[ [1] ] }.should.raise(Matrix::ErrDimensionMismatch)
end
it "returns a zero matrix if (nx0) * (0xn)" do
@@ -53,17 +53,17 @@ describe "Matrix#*" do
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)
+ -> { @a * nil }.should.raise(TypeError)
+ -> { @a * "a" }.should.raise(TypeError)
+ -> { @a * [ [1, 2] ] }.should.raise(TypeError)
+ -> { @a * Object.new }.should.raise(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)
+ (m*m).should.instance_of?(MatrixSub)
+ (m*1).should.instance_of?(MatrixSub)
end
end
end
diff --git a/spec/ruby/library/matrix/new_spec.rb b/spec/ruby/library/matrix/new_spec.rb
index 3005066846..bde9d9f4c8 100644
--- a/spec/ruby/library/matrix/new_spec.rb
+++ b/spec/ruby/library/matrix/new_spec.rb
@@ -3,6 +3,6 @@ require 'matrix'
describe "Matrix.new" do
it "is private" do
- Matrix.should have_private_method(:new)
+ Matrix.private_methods(false).should.include?(:new)
end
end
diff --git a/spec/ruby/library/matrix/normal_spec.rb b/spec/ruby/library/matrix/normal_spec.rb
index a9e6c645fa..420d4b011f 100644
--- a/spec/ruby/library/matrix/normal_spec.rb
+++ b/spec/ruby/library/matrix/normal_spec.rb
@@ -20,7 +20,7 @@ describe "Matrix.normal?" do
].each do |rectangular_matrix|
-> {
rectangular_matrix.normal?
- }.should raise_error(Matrix::ErrDimensionMismatch)
+ }.should.raise(Matrix::ErrDimensionMismatch)
end
end
end
diff --git a/spec/ruby/library/matrix/orthogonal_spec.rb b/spec/ruby/library/matrix/orthogonal_spec.rb
index 26afe89ff0..71ac831fe8 100644
--- a/spec/ruby/library/matrix/orthogonal_spec.rb
+++ b/spec/ruby/library/matrix/orthogonal_spec.rb
@@ -20,7 +20,7 @@ describe "Matrix.orthogonal?" do
].each do |rectangular_matrix|
-> {
rectangular_matrix.orthogonal?
- }.should raise_error(Matrix::ErrDimensionMismatch)
+ }.should.raise(Matrix::ErrDimensionMismatch)
end
end
end
diff --git a/spec/ruby/library/matrix/permutation_spec.rb b/spec/ruby/library/matrix/permutation_spec.rb
index 825a9d982c..43727edea1 100644
--- a/spec/ruby/library/matrix/permutation_spec.rb
+++ b/spec/ruby/library/matrix/permutation_spec.rb
@@ -3,18 +3,18 @@ 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
+ Matrix[[0, 1, 0], [0, 0, 1], [1, 0, 0]].permutation?.should == 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
+ Matrix[[0, 1], [0, 0]].permutation?.should == false
+ Matrix[[-1, 0], [0, -1]].permutation?.should == false
+ Matrix[[1, 0], [1, 0]].permutation?.should == false
+ Matrix[[1, 0], [1, 1]].permutation?.should == false
end
it "returns true for an empty 0x0 matrix" do
- Matrix.empty(0,0).permutation?.should be_true
+ Matrix.empty(0,0).permutation?.should == true
end
it "raises an error for rectangular matrices" do
@@ -26,7 +26,7 @@ describe "Matrix#permutation?" do
].each do |rectangular_matrix|
-> {
rectangular_matrix.permutation?
- }.should raise_error(Matrix::ErrDimensionMismatch)
+ }.should.raise(Matrix::ErrDimensionMismatch)
end
end
end
diff --git a/spec/ruby/library/matrix/plus_spec.rb b/spec/ruby/library/matrix/plus_spec.rb
index 2706bad060..72a9ba8f8f 100644
--- a/spec/ruby/library/matrix/plus_spec.rb
+++ b/spec/ruby/library/matrix/plus_spec.rb
@@ -13,30 +13,30 @@ describe "Matrix#+" do
end
it "returns an instance of Matrix" do
- (@a + @b).should be_kind_of(Matrix)
+ (@a + @b).should.is_a?(Matrix)
end
it "raises a Matrix::ErrDimensionMismatch if the matrices are different sizes" do
- -> { @a + Matrix[ [1] ] }.should raise_error(Matrix::ErrDimensionMismatch)
+ -> { @a + Matrix[ [1] ] }.should.raise(Matrix::ErrDimensionMismatch)
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)
+ -> { @a + 2 }.should.raise(ExceptionForMatrix::ErrOperationNotDefined)
+ -> { @a + 1.2 }.should.raise(ExceptionForMatrix::ErrOperationNotDefined)
+ -> { @a + bignum_value }.should.raise(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)
+ -> { @a + nil }.should.raise(TypeError)
+ -> { @a + "a" }.should.raise(TypeError)
+ -> { @a + [ [1, 2] ] }.should.raise(TypeError)
+ -> { @a + Object.new }.should.raise(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+m).should.instance_of?(MatrixSub)
end
end
end
diff --git a/spec/ruby/library/matrix/real_spec.rb b/spec/ruby/library/matrix/real_spec.rb
index 38033c63c8..4589dc22a5 100644
--- a/spec/ruby/library/matrix/real_spec.rb
+++ b/spec/ruby/library/matrix/real_spec.rb
@@ -4,22 +4,22 @@ 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
+ Matrix[ [1, 2], [3, 4] ].real?.should == true
+ Matrix[ [1.9, 2], [3, 4] ].real?.should == true
end
it "returns true for empty matrices" do
- Matrix.empty.real?.should be_true
+ Matrix.empty.real?.should == true
end
it "returns false if one element is a Complex" do
- Matrix[ [Complex(1,1), 2], [3, 4] ].real?.should be_false
+ Matrix[ [Complex(1,1), 2], [3, 4] ].real?.should == false
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
+ Matrix[ [Complex(1,0), 2], [3, 4] ].real?.should == false
end
end
end
@@ -37,7 +37,7 @@ describe "Matrix#real" do
describe "for a subclass of Matrix" do
it "returns an instance of that subclass" do
- MatrixSub.ins.real.should be_an_instance_of(MatrixSub)
+ MatrixSub.ins.real.should.instance_of?(MatrixSub)
end
end
end
diff --git a/spec/ruby/library/matrix/rect_spec.rb b/spec/ruby/library/matrix/rect_spec.rb
index 83a0404e47..b0ca3f0421 100644
--- a/spec/ruby/library/matrix/rect_spec.rb
+++ b/spec/ruby/library/matrix/rect_spec.rb
@@ -1,6 +1,8 @@
require_relative '../../spec_helper'
-require_relative 'shared/rectangular'
+require 'matrix'
describe "Matrix#rect" do
- it_behaves_like :matrix_rectangular, :rect
+ it "is an alias of Matrix#rectangular" do
+ Matrix.instance_method(:rect).should == Matrix.instance_method(:rectangular)
+ end
end
diff --git a/spec/ruby/library/matrix/rectangular_spec.rb b/spec/ruby/library/matrix/rectangular_spec.rb
index a235fac640..c0732f96bc 100644
--- a/spec/ruby/library/matrix/rectangular_spec.rb
+++ b/spec/ruby/library/matrix/rectangular_spec.rb
@@ -1,6 +1,19 @@
require_relative '../../spec_helper'
-require_relative 'shared/rectangular'
+require_relative 'fixtures/classes'
+require 'matrix'
describe "Matrix#rectangular" do
- it_behaves_like :matrix_rectangular, :rectangular
+ it "returns [receiver.real, receiver.imag]" do
+ m = Matrix[ [1.2, Complex(1,2)], [Complex(-2,0.42), 4] ]
+ m.rectangular.should == [m.real, m.imag]
+
+ m = Matrix.empty(3, 0)
+ m.rectangular.should == [m.real, m.imag]
+ end
+
+ describe "for a subclass of Matrix" do
+ it "returns instances of that subclass" do
+ MatrixSub.ins.rectangular.each{|m| m.should.instance_of?(MatrixSub) }
+ end
+ end
end
diff --git a/spec/ruby/library/matrix/regular_spec.rb b/spec/ruby/library/matrix/regular_spec.rb
index 3699d0ef8b..4cb00819ac 100644
--- a/spec/ruby/library/matrix/regular_spec.rb
+++ b/spec/ruby/library/matrix/regular_spec.rb
@@ -5,27 +5,27 @@ describe "Matrix#regular?" do
it "returns false for singular matrices" do
m = Matrix[ [1,2,3], [3,4,3], [0,0,0] ]
- m.regular?.should be_false
+ m.regular?.should == false
m = Matrix[ [1,2,9], [3,4,9], [1,2,9] ]
- m.regular?.should be_false
+ m.regular?.should == false
end
it "returns true if the Matrix is regular" do
- Matrix[ [0,1], [1,0] ].regular?.should be_true
+ Matrix[ [0,1], [1,0] ].regular?.should == true
end
it "returns true for an empty 0x0 matrix" do
- Matrix.empty(0,0).regular?.should be_true
+ Matrix.empty(0,0).regular?.should == true
end
it "raises an error for rectangular matrices" do
-> {
Matrix[[1], [2], [3]].regular?
- }.should raise_error(Matrix::ErrDimensionMismatch)
+ }.should.raise(Matrix::ErrDimensionMismatch)
-> {
Matrix.empty(3,0).regular?
- }.should raise_error(Matrix::ErrDimensionMismatch)
+ }.should.raise(Matrix::ErrDimensionMismatch)
end
end
diff --git a/spec/ruby/library/matrix/round_spec.rb b/spec/ruby/library/matrix/round_spec.rb
index 1dc29df890..cdec646fa1 100644
--- a/spec/ruby/library/matrix/round_spec.rb
+++ b/spec/ruby/library/matrix/round_spec.rb
@@ -15,7 +15,7 @@ describe "Matrix#round" do
describe "for a subclass of Matrix" do
it "returns an instance of that subclass" do
- MatrixSub.ins.round.should be_an_instance_of(MatrixSub)
+ MatrixSub.ins.round.should.instance_of?(MatrixSub)
end
end
end
diff --git a/spec/ruby/library/matrix/row_spec.rb b/spec/ruby/library/matrix/row_spec.rb
index 00b1f02a8e..8a7662fdf2 100644
--- a/spec/ruby/library/matrix/row_spec.rb
+++ b/spec/ruby/library/matrix/row_spec.rb
@@ -21,7 +21,7 @@ describe "Matrix#row" do
end
it "returns self when called with a block" do
- @m.row(0) { |x| x }.should equal(@m)
+ @m.row(0) { |x| x }.should.equal?(@m)
end
it "returns nil when out of bounds" do
@@ -30,7 +30,7 @@ describe "Matrix#row" do
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
+ -> { @m.row(3){ raise } }.should_not.raise
+ -> { @m.row(-4){ raise } }.should_not.raise
end
end
diff --git a/spec/ruby/library/matrix/row_vector_spec.rb b/spec/ruby/library/matrix/row_vector_spec.rb
index 341437ee05..f3919fb7d8 100644
--- a/spec/ruby/library/matrix/row_vector_spec.rb
+++ b/spec/ruby/library/matrix/row_vector_spec.rb
@@ -5,7 +5,7 @@ require 'matrix'
describe "Matrix.row_vector" do
it "returns a Matrix" do
- Matrix.row_vector([]).should be_an_instance_of(Matrix)
+ Matrix.row_vector([]).should.instance_of?(Matrix)
end
it "returns a single-row Matrix with the specified values" do
@@ -18,7 +18,7 @@ describe "Matrix.row_vector" do
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)
+ MatrixSub.row_vector([1]).should.instance_of?(MatrixSub)
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..4a0db67527 100644
--- a/spec/ruby/library/matrix/row_vectors_spec.rb
+++ b/spec/ruby/library/matrix/row_vectors_spec.rb
@@ -8,11 +8,11 @@ describe "Matrix#row_vectors" do
end
it "returns an Array" do
- Matrix[ [1,2], [3,4] ].row_vectors.should be_an_instance_of(Array)
+ Matrix[ [1,2], [3,4] ].row_vectors.should.instance_of?(Array)
end
it "returns an Array of Vectors" do
- @vectors.all? {|v| v.should be_an_instance_of(Vector)}
+ @vectors.all? {|v| v.should.instance_of?(Vector)}
end
it "returns each row as a Vector" do
diff --git a/spec/ruby/library/matrix/rows_spec.rb b/spec/ruby/library/matrix/rows_spec.rb
index 41ba635775..9c248cd8a4 100644
--- a/spec/ruby/library/matrix/rows_spec.rb
+++ b/spec/ruby/library/matrix/rows_spec.rb
@@ -10,7 +10,7 @@ describe "Matrix.rows" do
end
it "returns a Matrix" do
- @m.should be_kind_of(Matrix)
+ @m.should.is_a?(Matrix)
end
it "creates a matrix from argument rows" do
@@ -21,8 +21,8 @@ describe "Matrix.rows" do
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)
+ @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
@@ -35,7 +35,7 @@ describe "Matrix.rows" do
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)
+ MatrixSub.rows([[0, 1], [0, 1]]).should.instance_of?(MatrixSub)
end
end
end
diff --git a/spec/ruby/library/matrix/scalar_spec.rb b/spec/ruby/library/matrix/scalar_spec.rb
index 7fdd64c9d9..5b93b60533 100644
--- a/spec/ruby/library/matrix/scalar_spec.rb
+++ b/spec/ruby/library/matrix/scalar_spec.rb
@@ -10,7 +10,7 @@ describe "Matrix.scalar" do
end
it "returns a Matrix" do
- @a.should be_kind_of(Matrix)
+ @a.should.is_a?(Matrix)
end
it "returns a n x n matrix" do
@@ -41,7 +41,7 @@ describe "Matrix.scalar" do
end
it "returns a Matrix" do
- @a.should be_kind_of(Matrix)
+ @a.should.is_a?(Matrix)
end
it "returns a square matrix, where the first argument specifies the side of the square" do
diff --git a/spec/ruby/library/matrix/shared/collect.rb b/spec/ruby/library/matrix/shared/collect.rb
deleted file mode 100644
index 852f7fd6cf..0000000000
--- a/spec/ruby/library/matrix/shared/collect.rb
+++ /dev/null
@@ -1,26 +0,0 @@
-require_relative '../fixtures/classes'
-require 'matrix'
-
-describe :collect, shared: true do
- before :all do
- @m = Matrix[ [1, 2], [1, 2] ]
- end
-
- it "returns an instance of Matrix" do
- @m.send(@method){|n| n * 2 }.should be_kind_of(Matrix)
- end
-
- it "returns a Matrix where each element is the result of the block" do
- @m.send(@method) { |n| n * 2 }.should == Matrix[ [2, 4], [2, 4] ]
- end
-
- it "returns an enumerator if no block is given" do
- @m.send(@method).should be_an_instance_of(Enumerator)
- end
-
- describe "for a subclass of Matrix" do
- it "returns an instance of that subclass" do
- MatrixSub.ins.send(@method){1}.should be_an_instance_of(MatrixSub)
- end
- end
-end
diff --git a/spec/ruby/library/matrix/shared/conjugate.rb b/spec/ruby/library/matrix/shared/conjugate.rb
deleted file mode 100644
index d87658f855..0000000000
--- a/spec/ruby/library/matrix/shared/conjugate.rb
+++ /dev/null
@@ -1,20 +0,0 @@
-require_relative '../fixtures/classes'
-require 'matrix'
-
-describe :matrix_conjugate, shared: true do
- it "returns a matrix with all entries 'conjugated'" do
- Matrix[ [1, 2], [3, 4] ].send(@method).should == Matrix[ [1, 2], [3, 4] ]
- Matrix[ [1.9, Complex(1,1)], [3, 4] ].send(@method).should == Matrix[ [1.9, Complex(1,-1)], [3, 4] ]
- end
-
- it "returns empty matrices on the same size if empty" do
- Matrix.empty(0, 3).send(@method).should == Matrix.empty(0, 3)
- Matrix.empty(3, 0).send(@method).should == Matrix.empty(3, 0)
- end
-
- describe "for a subclass of Matrix" do
- it "returns an instance of that subclass" do
- MatrixSub.ins.send(@method).should be_an_instance_of(MatrixSub)
- end
- end
-end
diff --git a/spec/ruby/library/matrix/shared/determinant.rb b/spec/ruby/library/matrix/shared/determinant.rb
deleted file mode 100644
index 9e0528c24b..0000000000
--- a/spec/ruby/library/matrix/shared/determinant.rb
+++ /dev/null
@@ -1,38 +0,0 @@
-require 'matrix'
-
-describe :determinant, shared: true do
- it "returns the determinant of a square Matrix" do
- m = Matrix[ [7,6], [3,9] ]
- m.send(@method).should == 45
-
- m = Matrix[ [9, 8], [6,5] ]
- m.send(@method).should == -3
-
- m = Matrix[ [9,8,3], [4,20,5], [1,1,1] ]
- m.send(@method).should == 95
- end
-
- it "returns the determinant of a single-element Matrix" do
- m = Matrix[ [2] ]
- m.send(@method).should == 2
- end
-
- it "returns 1 for an empty Matrix" do
- m = Matrix[ ]
- m.send(@method).should == 1
- end
-
- it "returns the determinant even for Matrices containing 0 as first entry" do
- Matrix[[0,1],[1,0]].send(@method).should == -1
- end
-
- it "raises an error for rectangular matrices" do
- -> {
- Matrix[[1], [2], [3]].send(@method)
- }.should raise_error(Matrix::ErrDimensionMismatch)
-
- -> {
- Matrix.empty(3,0).send(@method)
- }.should raise_error(Matrix::ErrDimensionMismatch)
- end
-end
diff --git a/spec/ruby/library/matrix/shared/equal_value.rb b/spec/ruby/library/matrix/shared/equal_value.rb
index 2b2311d49e..9bc6ed908b 100644
--- a/spec/ruby/library/matrix/shared/equal_value.rb
+++ b/spec/ruby/library/matrix/shared/equal_value.rb
@@ -7,27 +7,27 @@ describe :equal, shared: true do
end
it "returns true for self" do
- @matrix.send(@method, @matrix).should be_true
+ @matrix.send(@method, @matrix).should == true
end
it "returns true for equal matrices" do
- @matrix.send(@method, Matrix[ [1, 2, 3, 4, 5], [2, 3, 4, 5, 6] ]).should be_true
+ @matrix.send(@method, Matrix[ [1, 2, 3, 4, 5], [2, 3, 4, 5, 6] ]).should == true
end
it "returns false for different matrices" do
- @matrix.send(@method, Matrix[ [42, 2, 3, 4, 5], [2, 3, 4, 5, 6] ]).should be_false
- @matrix.send(@method, Matrix[ [1, 2, 3, 4, 5, 6], [2, 3, 4, 5, 6, 7] ]).should be_false
- @matrix.send(@method, Matrix[ [1, 2, 3], [2, 3, 4] ]).should be_false
+ @matrix.send(@method, Matrix[ [42, 2, 3, 4, 5], [2, 3, 4, 5, 6] ]).should == false
+ @matrix.send(@method, Matrix[ [1, 2, 3, 4, 5, 6], [2, 3, 4, 5, 6, 7] ]).should == false
+ @matrix.send(@method, Matrix[ [1, 2, 3], [2, 3, 4] ]).should == false
end
it "returns false for different empty matrices" do
- Matrix.empty(42, 0).send(@method, Matrix.empty(6, 0)).should be_false
- Matrix.empty(0, 42).send(@method, Matrix.empty(0, 6)).should be_false
- Matrix.empty(0, 0).send(@method, Matrix.empty(6, 0)).should be_false
- Matrix.empty(0, 0).send(@method, Matrix.empty(0, 6)).should be_false
+ Matrix.empty(42, 0).send(@method, Matrix.empty(6, 0)).should == false
+ Matrix.empty(0, 42).send(@method, Matrix.empty(0, 6)).should == false
+ Matrix.empty(0, 0).send(@method, Matrix.empty(6, 0)).should == false
+ Matrix.empty(0, 0).send(@method, Matrix.empty(0, 6)).should == false
end
it "doesn't distinguish on subclasses" do
- MatrixSub.ins.send(@method, Matrix.I(2)).should be_true
+ MatrixSub.ins.send(@method, Matrix.I(2)).should == true
end
end
diff --git a/spec/ruby/library/matrix/shared/identity.rb b/spec/ruby/library/matrix/shared/identity.rb
deleted file mode 100644
index 114f86e7b0..0000000000
--- a/spec/ruby/library/matrix/shared/identity.rb
+++ /dev/null
@@ -1,19 +0,0 @@
-require_relative '../fixtures/classes'
-require 'matrix'
-
-describe :matrix_identity, shared: true do
- it "returns a Matrix" do
- Matrix.send(@method, 2).should be_kind_of(Matrix)
- end
-
- it "returns a n x n identity matrix" do
- Matrix.send(@method, 3).should == Matrix.scalar(3, 1)
- Matrix.send(@method, 100).should == Matrix.scalar(100, 1)
- end
-
- describe "for a subclass of Matrix" do
- it "returns an instance of that subclass" do
- MatrixSub.send(@method, 2).should be_an_instance_of(MatrixSub)
- end
- end
-end
diff --git a/spec/ruby/library/matrix/shared/imaginary.rb b/spec/ruby/library/matrix/shared/imaginary.rb
deleted file mode 100644
index d28ecc69f1..0000000000
--- a/spec/ruby/library/matrix/shared/imaginary.rb
+++ /dev/null
@@ -1,20 +0,0 @@
-require_relative '../fixtures/classes'
-require 'matrix'
-
-describe :matrix_imaginary, shared: true do
- it "returns a matrix with the imaginary part of the elements of the receiver" do
- Matrix[ [1, 2], [3, 4] ].send(@method).should == Matrix[ [0, 0], [0, 0] ]
- Matrix[ [1.9, Complex(1,1)], [Complex(-2,0.42), 4] ].send(@method).should == Matrix[ [0, 1], [0.42, 0] ]
- end
-
- it "returns empty matrices on the same size if empty" do
- Matrix.empty(0, 3).send(@method).should == Matrix.empty(0, 3)
- Matrix.empty(3, 0).send(@method).should == Matrix.empty(3, 0)
- end
-
- describe "for a subclass of Matrix" do
- it "returns an instance of that subclass" do
- MatrixSub.ins.send(@method).should be_an_instance_of(MatrixSub)
- end
- end
-end
diff --git a/spec/ruby/library/matrix/shared/inverse.rb b/spec/ruby/library/matrix/shared/inverse.rb
deleted file mode 100644
index c8a6b90da5..0000000000
--- a/spec/ruby/library/matrix/shared/inverse.rb
+++ /dev/null
@@ -1,38 +0,0 @@
-require_relative '../fixtures/classes'
-require 'matrix'
-
-describe :inverse, shared: true do
-
- it "returns a Matrix" do
- Matrix[ [1,2], [2,1] ].send(@method).should be_an_instance_of(Matrix)
- end
-
- it "returns the inverse of the Matrix" do
- Matrix[
- [1, 3, 3], [1, 4, 3], [1, 3, 4]
- ].send(@method).should ==
- Matrix[
- [7, -3, -3], [-1, 1, 0], [-1, 0, 1]
- ]
- end
-
- it "returns the inverse of the Matrix (other case)" do
- Matrix[
- [1, 2, 3], [0, 1, 4], [5, 6, 0]
- ].send(@method).should be_close_to_matrix([
- [-24, 18, 5], [20, -15, -4], [-5, 4, 1]
- ])
- end
-
- it "raises a ErrDimensionMismatch if the Matrix is not square" do
- ->{
- Matrix[ [1,2,3], [1,2,3] ].send(@method)
- }.should raise_error(Matrix::ErrDimensionMismatch)
- end
-
- describe "for a subclass of Matrix" do
- it "returns an instance of that subclass" do
- MatrixSub.ins.send(@method).should be_an_instance_of(MatrixSub)
- end
- end
-end
diff --git a/spec/ruby/library/matrix/shared/rectangular.rb b/spec/ruby/library/matrix/shared/rectangular.rb
deleted file mode 100644
index 3d9a0dfe8a..0000000000
--- a/spec/ruby/library/matrix/shared/rectangular.rb
+++ /dev/null
@@ -1,18 +0,0 @@
-require_relative '../fixtures/classes'
-require 'matrix'
-
-describe :matrix_rectangular, shared: true do
- it "returns [receiver.real, receiver.imag]" do
- m = Matrix[ [1.2, Complex(1,2)], [Complex(-2,0.42), 4] ]
- m.send(@method).should == [m.real, m.imag]
-
- m = Matrix.empty(3, 0)
- m.send(@method).should == [m.real, m.imag]
- end
-
- describe "for a subclass of Matrix" do
- it "returns instances of that subclass" do
- MatrixSub.ins.send(@method).each{|m| m.should be_an_instance_of(MatrixSub) }
- end
- end
-end
diff --git a/spec/ruby/library/matrix/shared/trace.rb b/spec/ruby/library/matrix/shared/trace.rb
deleted file mode 100644
index 57b89863f8..0000000000
--- a/spec/ruby/library/matrix/shared/trace.rb
+++ /dev/null
@@ -1,12 +0,0 @@
-require 'matrix'
-
-describe :trace, shared: true do
- it "returns the sum of diagonal elements in a square Matrix" do
- Matrix[[7,6], [3,9]].trace.should == 16
- end
-
- it "returns the sum of diagonal elements in a rectangular Matrix" do
- ->{ Matrix[[1,2,3], [4,5,6]].trace}.should raise_error(Matrix::ErrDimensionMismatch)
- end
-
-end
diff --git a/spec/ruby/library/matrix/shared/transpose.rb b/spec/ruby/library/matrix/shared/transpose.rb
deleted file mode 100644
index 89b1d025be..0000000000
--- a/spec/ruby/library/matrix/shared/transpose.rb
+++ /dev/null
@@ -1,19 +0,0 @@
-require_relative '../fixtures/classes'
-require 'matrix'
-
-describe :matrix_transpose, shared: true do
- it "returns a transposed matrix" do
- Matrix[[1, 2], [3, 4], [5, 6]].send(@method).should == Matrix[[1, 3, 5], [2, 4, 6]]
- end
-
- it "can transpose empty matrices" do
- m = Matrix[[], [], []]
- m.send(@method).send(@method).should == m
- end
-
- describe "for a subclass of Matrix" do
- it "returns an instance of that subclass" do
- MatrixSub.ins.send(@method).should be_an_instance_of(MatrixSub)
- end
- end
-end
diff --git a/spec/ruby/library/matrix/singular_spec.rb b/spec/ruby/library/matrix/singular_spec.rb
index 7bba36a54a..00b93af495 100644
--- a/spec/ruby/library/matrix/singular_spec.rb
+++ b/spec/ruby/library/matrix/singular_spec.rb
@@ -4,28 +4,28 @@ 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
+ m.singular?.should == true
m = Matrix[ [1,2,9], [3,4,9], [1,2,9] ]
- m.singular?.should be_true
+ m.singular?.should == true
end
it "returns false if the Matrix is regular" do
- Matrix[ [0,1], [1,0] ].singular?.should be_false
+ Matrix[ [0,1], [1,0] ].singular?.should == false
end
it "returns false for an empty 0x0 matrix" do
- Matrix.empty(0,0).singular?.should be_false
+ Matrix.empty(0,0).singular?.should == false
end
it "raises an error for rectangular matrices" do
-> {
Matrix[[1], [2], [3]].singular?
- }.should raise_error(Matrix::ErrDimensionMismatch)
+ }.should.raise(Matrix::ErrDimensionMismatch)
-> {
Matrix.empty(3,0).singular?
- }.should raise_error(Matrix::ErrDimensionMismatch)
+ }.should.raise(Matrix::ErrDimensionMismatch)
end
end
diff --git a/spec/ruby/library/matrix/square_spec.rb b/spec/ruby/library/matrix/square_spec.rb
index 25d2d1ad9c..b8cf4acf44 100644
--- a/spec/ruby/library/matrix/square_spec.rb
+++ b/spec/ruby/library/matrix/square_spec.rb
@@ -4,25 +4,25 @@ require 'matrix'
describe "Matrix#square?" do
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
+ Matrix[ [1,2], [2,4] ].square?.should == true
+ Matrix[ [100,3,5], [9.5, 4.9, 8], [2,0,77] ].square?.should == true
end
it "returns true when the Matrix has only one element" do
- Matrix[ [9] ].square?.should be_true
+ Matrix[ [9] ].square?.should == true
end
it "returns false when the Matrix is rectangular" do
- Matrix[ [1, 2] ].square?.should be_false
+ Matrix[ [1, 2] ].square?.should == false
end
it "returns false when the Matrix is rectangular" do
- Matrix[ [1], [2] ].square?.should be_false
+ Matrix[ [1], [2] ].square?.should == false
end
it "returns handles empty matrices" do
- Matrix[].square?.should be_true
- Matrix[[]].square?.should be_false
- Matrix.columns([[]]).square?.should be_false
+ Matrix[].square?.should == true
+ Matrix[[]].square?.should == false
+ Matrix.columns([[]]).square?.should == false
end
end
diff --git a/spec/ruby/library/matrix/symmetric_spec.rb b/spec/ruby/library/matrix/symmetric_spec.rb
index 6f2a99276a..4b86c19503 100644
--- a/spec/ruby/library/matrix/symmetric_spec.rb
+++ b/spec/ruby/library/matrix/symmetric_spec.rb
@@ -3,15 +3,15 @@ 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
+ Matrix[[1, 2, Complex(0, 3)], [2, 4, 5], [Complex(0, 3), 5, 6]].symmetric?.should == true
end
it "returns true for a 0x0 empty matrix" do
- Matrix.empty.symmetric?.should be_true
+ Matrix.empty.symmetric?.should == true
end
it "returns false for an asymmetric Matrix" do
- Matrix[[1, 2],[-2, 1]].symmetric?.should be_false
+ Matrix[[1, 2],[-2, 1]].symmetric?.should == false
end
it "raises an error for rectangular matrices" do
@@ -23,7 +23,7 @@ describe "Matrix.symmetric?" do
].each do |rectangular_matrix|
-> {
rectangular_matrix.symmetric?
- }.should raise_error(Matrix::ErrDimensionMismatch)
+ }.should.raise(Matrix::ErrDimensionMismatch)
end
end
end
diff --git a/spec/ruby/library/matrix/t_spec.rb b/spec/ruby/library/matrix/t_spec.rb
index 6f1a5178e0..9411597e7c 100644
--- a/spec/ruby/library/matrix/t_spec.rb
+++ b/spec/ruby/library/matrix/t_spec.rb
@@ -1,6 +1,8 @@
require_relative '../../spec_helper'
-require_relative 'shared/transpose'
+require 'matrix'
-describe "Matrix#transpose" do
- it_behaves_like :matrix_transpose, :t
+describe "Matrix#t" do
+ it "is an alias of Matrix#transpose" do
+ Matrix.instance_method(:t).should == Matrix.instance_method(:transpose)
+ end
end
diff --git a/spec/ruby/library/matrix/tr_spec.rb b/spec/ruby/library/matrix/tr_spec.rb
index e17bd790d7..04d237d483 100644
--- a/spec/ruby/library/matrix/tr_spec.rb
+++ b/spec/ruby/library/matrix/tr_spec.rb
@@ -1,7 +1,8 @@
require_relative '../../spec_helper'
-require_relative 'shared/trace'
require 'matrix'
describe "Matrix#tr" do
- it_behaves_like :trace, :tr
+ it "is an alias of Matrix#trace" do
+ Matrix.instance_method(:tr).should == Matrix.instance_method(:trace)
+ end
end
diff --git a/spec/ruby/library/matrix/trace_spec.rb b/spec/ruby/library/matrix/trace_spec.rb
index 290e7cb1f7..831278c838 100644
--- a/spec/ruby/library/matrix/trace_spec.rb
+++ b/spec/ruby/library/matrix/trace_spec.rb
@@ -1,7 +1,12 @@
require_relative '../../spec_helper'
-require_relative 'shared/trace'
require 'matrix'
describe "Matrix#trace" do
- it_behaves_like :trace, :trace
+ it "returns the sum of diagonal elements in a square Matrix" do
+ Matrix[[7,6], [3,9]].trace.should == 16
+ end
+
+ it "returns the sum of diagonal elements in a rectangular Matrix" do
+ ->{ Matrix[[1,2,3], [4,5,6]].trace}.should.raise(Matrix::ErrDimensionMismatch)
+ end
end
diff --git a/spec/ruby/library/matrix/transpose_spec.rb b/spec/ruby/library/matrix/transpose_spec.rb
index 79600dd439..0b24ab32a7 100644
--- a/spec/ruby/library/matrix/transpose_spec.rb
+++ b/spec/ruby/library/matrix/transpose_spec.rb
@@ -1,6 +1,19 @@
require_relative '../../spec_helper'
-require_relative 'shared/transpose'
+require_relative 'fixtures/classes'
describe "Matrix#transpose" do
- it_behaves_like :matrix_transpose, :transpose
+ it "returns a transposed matrix" do
+ Matrix[[1, 2], [3, 4], [5, 6]].transpose.should == Matrix[[1, 3, 5], [2, 4, 6]]
+ end
+
+ it "can transpose empty matrices" do
+ m = Matrix[[], [], []]
+ m.transpose.transpose.should == m
+ end
+
+ describe "for a subclass of Matrix" do
+ it "returns an instance of that subclass" do
+ MatrixSub.ins.transpose.should.instance_of?(MatrixSub)
+ end
+ end
end
diff --git a/spec/ruby/library/matrix/unit_spec.rb b/spec/ruby/library/matrix/unit_spec.rb
index 6a41d729c7..1121996122 100644
--- a/spec/ruby/library/matrix/unit_spec.rb
+++ b/spec/ruby/library/matrix/unit_spec.rb
@@ -1,6 +1,8 @@
require_relative '../../spec_helper'
-require_relative 'shared/identity'
+require 'matrix'
describe "Matrix.unit" do
- it_behaves_like :matrix_identity, :unit
+ it "is an alias of Matrix.identity" do
+ Matrix.method(:unit).should == Matrix.method(:identity)
+ end
end
diff --git a/spec/ruby/library/matrix/unitary_spec.rb b/spec/ruby/library/matrix/unitary_spec.rb
index c214ee9b2f..4490e8f8d4 100644
--- a/spec/ruby/library/matrix/unitary_spec.rb
+++ b/spec/ruby/library/matrix/unitary_spec.rb
@@ -26,7 +26,7 @@ describe "Matrix.unitary?" do
].each do |rectangular_matrix|
-> {
rectangular_matrix.unitary?
- }.should raise_error(Matrix::ErrDimensionMismatch)
+ }.should.raise(Matrix::ErrDimensionMismatch)
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..0e2bf611e2 100644
--- a/spec/ruby/library/matrix/upper_triangular_spec.rb
+++ b/spec/ruby/library/matrix/upper_triangular_spec.rb
@@ -3,22 +3,22 @@ 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
+ Matrix[[1, 2, 3], [0, 2, 3], [0, 0, 3]].upper_triangular?.should == true
+ Matrix.diagonal([1, 2, 3]).upper_triangular?.should == true
+ Matrix[[1, 2], [0, 2], [0, 0], [0, 0]].upper_triangular?.should == true
+ Matrix[[1, 2, 3, 4], [0, 2, 3, 4]].upper_triangular?.should == 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
+ Matrix[[0, 0], [1, 0]].upper_triangular?.should == false
+ Matrix[[1, 2, 3], [1, 2, 3], [1, 2, 3]].upper_triangular?.should == false
+ Matrix[[0, 0], [0, 0], [0, 0], [0, 1]].upper_triangular?.should == false
+ Matrix[[0, 0, 0, 0], [1, 0, 0, 0]].upper_triangular?.should == 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
+ Matrix.empty(3,0).upper_triangular?.should == true
+ Matrix.empty(0,3).upper_triangular?.should == true
+ Matrix.empty(0,0).upper_triangular?.should == true
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..96a462c067 100644
--- a/spec/ruby/library/matrix/vector/cross_product_spec.rb
+++ b/spec/ruby/library/matrix/vector/cross_product_spec.rb
@@ -9,6 +9,6 @@ describe "Vector#cross_product" do
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)
+ }.should.raise(Vector::ErrDimensionMismatch)
end
end
diff --git a/spec/ruby/library/matrix/vector/each2_spec.rb b/spec/ruby/library/matrix/vector/each2_spec.rb
index 10d2fc404d..86e7ed75aa 100644
--- a/spec/ruby/library/matrix/vector/each2_spec.rb
+++ b/spec/ruby/library/matrix/vector/each2_spec.rb
@@ -8,8 +8,8 @@ describe "Vector.each2" do
end
it "requires one argument" do
- -> { @v.each2(@v2, @v2){} }.should raise_error(ArgumentError)
- -> { @v.each2(){} }.should raise_error(ArgumentError)
+ -> { @v.each2(@v2, @v2){} }.should.raise(ArgumentError)
+ -> { @v.each2(){} }.should.raise(ArgumentError)
end
describe "given one argument" do
@@ -20,8 +20,8 @@ describe "Vector.each2" do
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)
+ -> { @v.each2(Vector[1,2]){} }.should.raise(Vector::ErrDimensionMismatch)
+ -> { @v.each2(Vector[1,2,3,4]){} }.should.raise(Vector::ErrDimensionMismatch)
end
it "yields arguments in sequence" do
@@ -37,12 +37,12 @@ describe "Vector.each2" do
end
it "returns self when given a block" do
- @v.each2(@v2){}.should equal(@v)
+ @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.should.instance_of?(Enumerator)
enum.to_a.should == [[1, 4], [2, 5], [3, 6]]
end
end
diff --git a/spec/ruby/library/matrix/vector/eql_spec.rb b/spec/ruby/library/matrix/vector/eql_spec.rb
index eb2451b550..6e2cd47b8e 100644
--- a/spec/ruby/library/matrix/vector/eql_spec.rb
+++ b/spec/ruby/library/matrix/vector/eql_spec.rb
@@ -7,10 +7,10 @@ describe "Vector#eql?" do
end
it "returns true for self" do
- @vector.eql?(@vector).should be_true
+ @vector.eql?(@vector).should == 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
+ @vector.eql?(Vector[1, 2, 3, 4, 5.0]).should == false
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..79dee10833 100644
--- a/spec/ruby/library/matrix/vector/inner_product_spec.rb
+++ b/spec/ruby/library/matrix/vector/inner_product_spec.rb
@@ -13,7 +13,7 @@ describe "Vector#inner_product" do
it "raises an error for mismatched vectors" do
-> {
Vector[1, 2, 3].inner_product(Vector[0, -4])
- }.should raise_error(Vector::ErrDimensionMismatch)
+ }.should.raise(Vector::ErrDimensionMismatch)
end
it "uses the conjugate of its argument" do
diff --git a/spec/ruby/library/matrix/vector/normalize_spec.rb b/spec/ruby/library/matrix/vector/normalize_spec.rb
index 527c9260de..bb1f046786 100644
--- a/spec/ruby/library/matrix/vector/normalize_spec.rb
+++ b/spec/ruby/library/matrix/vector/normalize_spec.rb
@@ -10,9 +10,9 @@ describe "Vector#normalize" do
it "raises an error for zero vectors" do
-> {
Vector[].normalize
- }.should raise_error(Vector::ZeroVectorError)
+ }.should.raise(Vector::ZeroVectorError)
-> {
Vector[0, 0, 0].normalize
- }.should raise_error(Vector::ZeroVectorError)
+ }.should.raise(Vector::ZeroVectorError)
end
end
diff --git a/spec/ruby/library/matrix/zero_spec.rb b/spec/ruby/library/matrix/zero_spec.rb
index 68e8567c26..406bcad6ed 100644
--- a/spec/ruby/library/matrix/zero_spec.rb
+++ b/spec/ruby/library/matrix/zero_spec.rb
@@ -4,7 +4,7 @@ require 'matrix'
describe "Matrix.zero" do
it "returns an object of type Matrix" do
- Matrix.zero(3).should be_kind_of(Matrix)
+ Matrix.zero(3).should.is_a?(Matrix)
end
it "creates a n x n matrix" do
@@ -30,7 +30,7 @@ describe "Matrix.zero" do
describe "for a subclass of Matrix" do
it "returns an instance of that subclass" do
- MatrixSub.zero(3).should be_an_instance_of(MatrixSub)
+ MatrixSub.zero(3).should.instance_of?(MatrixSub)
end
end
end
diff --git a/spec/ruby/library/monitor/exit_spec.rb b/spec/ruby/library/monitor/exit_spec.rb
index 952ad9525d..0748a523ac 100644
--- a/spec/ruby/library/monitor/exit_spec.rb
+++ b/spec/ruby/library/monitor/exit_spec.rb
@@ -5,6 +5,6 @@ describe "Monitor#exit" do
it "raises ThreadError when monitor is not entered" do
m = Monitor.new
- -> { m.exit }.should raise_error(ThreadError)
+ -> { m.exit }.should.raise(ThreadError)
end
end
diff --git a/spec/ruby/library/monitor/mon_initialize_spec.rb b/spec/ruby/library/monitor/mon_initialize_spec.rb
index e0fe6c2d97..092aee929c 100644
--- a/spec/ruby/library/monitor/mon_initialize_spec.rb
+++ b/spec/ruby/library/monitor/mon_initialize_spec.rb
@@ -26,6 +26,6 @@ describe "MonitorMixin#mon_initialize" do
instance = cls.new(1, 2, 3)
copy = instance.dup
- copy.should_not equal(instance)
+ copy.should_not.equal?(instance)
end
end
diff --git a/spec/ruby/library/monitor/synchronize_spec.rb b/spec/ruby/library/monitor/synchronize_spec.rb
index d78393eb3a..27cc1258b4 100644
--- a/spec/ruby/library/monitor/synchronize_spec.rb
+++ b/spec/ruby/library/monitor/synchronize_spec.rb
@@ -31,11 +31,11 @@ describe "Monitor#synchronize" do
end
it "raises a LocalJumpError if not passed a block" do
- -> { Monitor.new.synchronize }.should raise_error(LocalJumpError)
+ -> { Monitor.new.synchronize }.should.raise(LocalJumpError)
end
it "raises a thread error if the monitor is not owned on exiting the block" do
monitor = Monitor.new
- -> { monitor.synchronize { monitor.exit } }.should raise_error(ThreadError)
+ -> { monitor.synchronize { monitor.exit } }.should.raise(ThreadError)
end
end
diff --git a/spec/ruby/library/net-ftp/FTPError_spec.rb b/spec/ruby/library/net-ftp/FTPError_spec.rb
index 0c31b65dcc..b447e50546 100644
--- a/spec/ruby/library/net-ftp/FTPError_spec.rb
+++ b/spec/ruby/library/net-ftp/FTPError_spec.rb
@@ -1,8 +1,11 @@
require_relative '../../spec_helper'
-require 'net/ftp'
-describe "Net::FTPError" do
- it "is an Exception" do
- Net::FTPError.should < Exception
+ruby_version_is ""..."4.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-ftp/FTPPermError_spec.rb b/spec/ruby/library/net-ftp/FTPPermError_spec.rb
index b43e12c503..b9a2d93aef 100644
--- a/spec/ruby/library/net-ftp/FTPPermError_spec.rb
+++ b/spec/ruby/library/net-ftp/FTPPermError_spec.rb
@@ -1,12 +1,15 @@
require_relative '../../spec_helper'
-require 'net/ftp'
-describe "Net::FTPPermError" do
- it "is an Exception" do
- Net::FTPPermError.should < Exception
- end
+ruby_version_is ""..."4.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
+ it "is a subclass of Net::FTPError" do
+ Net::FTPPermError.should < Net::FTPError
+ end
end
end
diff --git a/spec/ruby/library/net-ftp/FTPProtoError_spec.rb b/spec/ruby/library/net-ftp/FTPProtoError_spec.rb
index e7abbc0dd8..a1d9e44d63 100644
--- a/spec/ruby/library/net-ftp/FTPProtoError_spec.rb
+++ b/spec/ruby/library/net-ftp/FTPProtoError_spec.rb
@@ -1,12 +1,15 @@
require_relative '../../spec_helper'
-require 'net/ftp'
-describe "Net::FTPProtoError" do
- it "is an Exception" do
- Net::FTPProtoError.should < Exception
- end
+ruby_version_is ""..."4.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
+ it "is a subclass of Net::FTPError" do
+ Net::FTPPermError.should < Net::FTPError
+ end
end
end
diff --git a/spec/ruby/library/net-ftp/FTPReplyError_spec.rb b/spec/ruby/library/net-ftp/FTPReplyError_spec.rb
index fcc7501fc1..c9e6468323 100644
--- a/spec/ruby/library/net-ftp/FTPReplyError_spec.rb
+++ b/spec/ruby/library/net-ftp/FTPReplyError_spec.rb
@@ -1,12 +1,15 @@
require_relative '../../spec_helper'
-require 'net/ftp'
-describe "Net::FTPReplyError" do
- it "is an Exception" do
- Net::FTPReplyError.should < Exception
- end
+ruby_version_is ""..."4.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
+ it "is a subclass of Net::FTPError" do
+ Net::FTPPermError.should < Net::FTPError
+ end
end
end
diff --git a/spec/ruby/library/net-ftp/FTPTempError_spec.rb b/spec/ruby/library/net-ftp/FTPTempError_spec.rb
index f4b045dfb5..c0953cb0f2 100644
--- a/spec/ruby/library/net-ftp/FTPTempError_spec.rb
+++ b/spec/ruby/library/net-ftp/FTPTempError_spec.rb
@@ -1,12 +1,15 @@
require_relative '../../spec_helper'
-require 'net/ftp'
-describe "Net::FTPTempError" do
- it "is an Exception" do
- Net::FTPTempError.should < Exception
- end
+ruby_version_is ""..."4.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
+ 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
index 335d056512..9e8be53c68 100644
--- a/spec/ruby/library/net-ftp/abort_spec.rb
+++ b/spec/ruby/library/net-ftp/abort_spec.rb
@@ -1,62 +1,65 @@
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
+ruby_version_is ""..."4.1" do
+ require_relative 'spec_helper'
+ require_relative 'fixtures/server'
- @ftp = Net::FTP.new
- @ftp.connect(@server.hostname, @server.server_port)
- end
+ describe "Net::FTP#abort" do
+ before :each do
+ @server = NetFTPSpecs::DummyFTP.new
+ @server.serve_once
- after :each do
- @ftp.quit rescue nil
- @ftp.close
- @server.stop
- end
+ @ftp = Net::FTP.new
+ @ftp.connect(@server.hostname, @server.server_port)
+ end
- it "sends the ABOR command to the server" do
- -> { @ftp.abort }.should_not raise_error
- end
+ after :each do
+ @ftp.quit rescue nil
+ @ftp.close
+ @server.stop
+ end
- it "ignores the response" do
- @ftp.abort
- @ftp.last_response.should == "220 Dummy FTP Server ready!\n"
- end
+ it "sends the ABOR command to the server" do
+ -> { @ftp.abort }.should_not.raise
+ end
- it "returns the full response" do
- @ftp.abort.should == "226 Closing data connection. (ABOR)\n"
- end
+ it "ignores the response" do
+ @ftp.abort
+ @ftp.last_response.should == "220 Dummy FTP Server ready!\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 "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 226" do
- @server.should_receive(:abor).and_respond("226 Closing data connection.")
- -> { @ftp.abort }.should_not raise_error
- 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
+ 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 "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
+ 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 500" do
+ @server.should_receive(:abor).and_respond("500 Syntax error, command unrecognized.")
+ -> { @ftp.abort }.should.raise(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 501" do
+ @server.should_receive(:abor).and_respond("501 Syntax error in parameters or arguments.")
+ -> { @ftp.abort }.should.raise(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(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)
+ 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(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
index ab093448a2..a64a0f48a8 100644
--- a/spec/ruby/library/net-ftp/acct_spec.rb
+++ b/spec/ruby/library/net-ftp/acct_spec.rb
@@ -1,58 +1,61 @@
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)
+ruby_version_is ""..."4.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
+ 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(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(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(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(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(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
index 1e0585b795..de8d0ac103 100644
--- a/spec/ruby/library/net-ftp/binary_spec.rb
+++ b/spec/ruby/library/net-ftp/binary_spec.rb
@@ -1,24 +1,27 @@
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
+ruby_version_is ""..."4.1" do
+ require_relative 'spec_helper'
- ftp.binary = false
- ftp.binary.should be_false
+ describe "Net::FTP#binary" do
+ it "returns true when self is in binary mode" do
+ ftp = Net::FTP.new
+ ftp.binary.should == true
+
+ ftp.binary = false
+ ftp.binary.should == false
+ end
end
-end
-describe "Net::FTP#binary=" do
- it "sets self to binary mode when passed true" do
- ftp = Net::FTP.new
+ 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 = true
+ ftp.binary.should == true
- ftp.binary = false
- ftp.binary.should be_false
+ ftp.binary = false
+ ftp.binary.should == false
+ end
end
end
diff --git a/spec/ruby/library/net-ftp/chdir_spec.rb b/spec/ruby/library/net-ftp/chdir_spec.rb
index cc129b5e42..f8f352158c 100644
--- a/spec/ruby/library/net-ftp/chdir_spec.rb
+++ b/spec/ruby/library/net-ftp/chdir_spec.rb
@@ -1,99 +1,102 @@
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
+ruby_version_is ""..."4.1" do
+ require_relative 'spec_helper'
+ require_relative 'fixtures/server'
- @ftp = Net::FTP.new
- @ftp.connect(@server.hostname, @server.server_port)
- end
+ describe "Net::FTP#chdir" do
+ before :each do
+ @server = NetFTPSpecs::DummyFTP.new
+ @server.serve_once
- after :each do
- @ftp.quit rescue nil
- @ftp.close
- @server.stop
- end
+ @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 == 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(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(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(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(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(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(Net::FTPPermError)
+ end
+ 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"
+ 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("..").should be_nil
+ @ftp.chdir("test").should == 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)
+ 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(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)
+ @server.should_receive(:cwd).and_respond("501 Syntax error in parameters or arguments.")
+ -> { @ftp.chdir("test") }.should.raise(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)
+ @server.should_receive(:cwd).and_respond("502 Command not implemented.")
+ -> { @ftp.chdir("test") }.should.raise(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)
+ @server.should_receive(:cwd).and_respond("421 Service not available, closing control connection.")
+ -> { @ftp.chdir("test") }.should.raise(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)
+ @server.should_receive(:cwd).and_respond("530 Not logged in.")
+ -> { @ftp.chdir("test") }.should.raise(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)
+ @server.should_receive(:cwd).and_respond("550 Requested action not taken.")
+ -> { @ftp.chdir("test") }.should.raise(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
index 183f14a84b..9d5d4c638a 100644
--- a/spec/ruby/library/net-ftp/close_spec.rb
+++ b/spec/ruby/library/net-ftp/close_spec.rb
@@ -1,30 +1,33 @@
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)
+ruby_version_is ""..."4.1" do
+ require_relative 'spec_helper'
- @ftp = Net::FTP.new
- @ftp.instance_variable_set(:@sock, @socket)
- end
+ 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)
- it "closes the socket" do
- @socket.should_receive(:close)
- @ftp.close.should be_nil
- end
+ @ftp = Net::FTP.new
+ @ftp.instance_variable_set(:@sock, @socket)
+ 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 "closes the socket" do
+ @socket.should_receive(:close)
+ @ftp.close.should == 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 == 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
+ it "does not try to close the socket if it is nil" do
+ @ftp.instance_variable_set(:@sock, nil)
+ @ftp.close.should == nil
+ end
end
end
diff --git a/spec/ruby/library/net-ftp/closed_spec.rb b/spec/ruby/library/net-ftp/closed_spec.rb
index 84001cdc0f..1c8693932e 100644
--- a/spec/ruby/library/net-ftp/closed_spec.rb
+++ b/spec/ruby/library/net-ftp/closed_spec.rb
@@ -1,21 +1,24 @@
require_relative '../../spec_helper'
-require_relative 'spec_helper'
-describe "Net::FTP#closed?" do
- before :each do
- @socket = mock("Socket")
+ruby_version_is ""..."4.1" do
+ require_relative 'spec_helper'
- @ftp = Net::FTP.new
- @ftp.instance_variable_set(:@sock, @socket)
- end
+ describe "Net::FTP#closed?" do
+ before :each do
+ @socket = mock("Socket")
- it "returns true when the socket is closed" do
- @socket.should_receive(:closed?).and_return(true)
- @ftp.closed?.should be_true
- end
+ @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 == true
+ end
- it "returns true when the socket is nil" do
- @ftp.instance_variable_set(:@sock, nil)
- @ftp.closed?.should be_true
+ it "returns true when the socket is nil" do
+ @ftp.instance_variable_set(:@sock, nil)
+ @ftp.closed?.should == true
+ end
end
end
diff --git a/spec/ruby/library/net-ftp/connect_spec.rb b/spec/ruby/library/net-ftp/connect_spec.rb
index e606b11e2a..597381f67c 100644
--- a/spec/ruby/library/net-ftp/connect_spec.rb
+++ b/spec/ruby/library/net-ftp/connect_spec.rb
@@ -1,43 +1,46 @@
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
-
- 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)
+ruby_version_is ""..."4.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
+ end
+
+ it "returns nil" do
+ @ftp.connect(@server.hostname, @server.server_port).should == nil
+ 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
+ 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(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(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
index f2ef53c089..28765b9d1c 100644
--- a/spec/ruby/library/net-ftp/debug_mode_spec.rb
+++ b/spec/ruby/library/net-ftp/debug_mode_spec.rb
@@ -1,23 +1,26 @@
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
+ruby_version_is ""..."4.1" do
+ require_relative 'spec_helper'
- ftp.debug_mode = true
- ftp.debug_mode.should be_true
+ describe "Net::FTP#debug_mode" do
+ it "returns true when self is in debug mode" do
+ ftp = Net::FTP.new
+ ftp.debug_mode.should == false
+
+ ftp.debug_mode = true
+ ftp.debug_mode.should == true
+ end
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
+ 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 == true
- ftp.debug_mode = false
- ftp.debug_mode.should be_false
+ ftp.debug_mode = false
+ ftp.debug_mode.should == 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
index 3f14f6187e..b47b4e9782 100644
--- a/spec/ruby/library/net-ftp/default_passive_spec.rb
+++ b/spec/ruby/library/net-ftp/default_passive_spec.rb
@@ -1,8 +1,11 @@
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"
+ruby_version_is ""..."4.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
index bfb7da1ffe..40cd8f1d99 100644
--- a/spec/ruby/library/net-ftp/delete_spec.rb
+++ b/spec/ruby/library/net-ftp/delete_spec.rb
@@ -1,59 +1,62 @@
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)
+ruby_version_is ""..."4.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(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(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(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(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(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(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(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
index 894f03dd7b..af38724fad 100644
--- a/spec/ruby/library/net-ftp/dir_spec.rb
+++ b/spec/ruby/library/net-ftp/dir_spec.rb
@@ -1,8 +1,11 @@
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
+ruby_version_is ""..."4.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/server.rb b/spec/ruby/library/net-ftp/fixtures/server.rb
index 8b34d3f8bd..9fc2beb57b 100644
--- a/spec/ruby/library/net-ftp/fixtures/server.rb
+++ b/spec/ruby/library/net-ftp/fixtures/server.rb
@@ -1,277 +1,279 @@
-module NetFTPSpecs
- class DummyFTP
- attr_accessor :connect_message
- attr_reader :login_user, :login_pass, :login_acct
-
- # hostname or IP address
- attr_reader :hostname
- # port number
- attr_reader :server_port
-
- def initialize
- @hostname = "127.0.0.1"
- @server = TCPServer.new(@hostname, 0)
- @server_port = @server.addr[1]
-
- @handlers = {}
- @commands = []
- @connect_message = nil
- end
+ruby_version_is ""..."4.1" do
+ module NetFTPSpecs
+ class DummyFTP
+ attr_accessor :connect_message
+ attr_reader :login_user, :login_pass, :login_acct
+
+ # hostname or IP address
+ attr_reader :hostname
+ # port number
+ attr_reader :server_port
+
+ def initialize
+ @hostname = "127.0.0.1"
+ @server = TCPServer.new(@hostname, 0)
+ @server_port = @server.addr[1]
+
+ @handlers = {}
+ @commands = []
+ @connect_message = nil
+ end
- def serve_once
- @thread = Thread.new do
- @socket = @server.accept
- @socket.setsockopt(Socket::SOL_SOCKET, Socket::SO_OOBINLINE, 1)
- begin
- handle_request
- ensure
- @socket.close
+ def serve_once
+ @thread = Thread.new do
+ @socket = @server.accept
+ @socket.setsockopt(Socket::SOL_SOCKET, Socket::SO_OOBINLINE, 1)
+ begin
+ handle_request
+ ensure
+ @socket.close
+ end
end
end
- end
-
- def handle_request
- # Send out the welcome message.
- response @connect_message || "220 Dummy FTP Server ready!"
- begin
- while command = @socket.gets
- command, argument = command.chomp.split(" ", 2)
+ def handle_request
+ # Send out the welcome message.
+ response @connect_message || "220 Dummy FTP Server ready!"
- if command == "QUIT"
- self.response("221 OK, bye")
- break
- elsif proc_handler = @handlers[command.downcase.to_sym]
- if argument.nil?
- proc_handler.call(self)
- else
- proc_handler.call(self, argument)
- end
- else
- if argument.nil?
- self.send(command.downcase.to_sym)
+ begin
+ while command = @socket.gets
+ command, argument = command.chomp.split(" ", 2)
+
+ if command == "QUIT"
+ self.response("221 OK, bye")
+ break
+ elsif proc_handler = @handlers[command.downcase.to_sym]
+ if argument.nil?
+ proc_handler.call(self)
+ else
+ proc_handler.call(self, argument)
+ end
else
- self.send(command.downcase.to_sym, argument)
+ if argument.nil?
+ self.send(command.downcase.to_sym)
+ else
+ self.send(command.downcase.to_sym, argument)
+ end
end
end
+ rescue => e
+ self.error_response("Exception: #{e} #{e.backtrace.inspect}")
end
- rescue => e
- self.error_response("Exception: #{e} #{e.backtrace.inspect}")
end
- end
- def error_response(text)
- self.response("451 #{text}")
- end
+ def error_response(text)
+ self.response("451 #{text}")
+ end
- def response(text)
- @socket.puts(text) unless @socket.closed?
- end
+ def response(text)
+ @socket.puts(text) unless @socket.closed?
+ end
- def stop
- @datasocket.close unless @datasocket.nil? || @datasocket.closed?
- @server.close
- @thread.join
- end
+ def stop
+ @datasocket.close unless @datasocket.nil? || @datasocket.closed?
+ @server.close
+ @thread.join
+ end
- ##
- def handle(sym, &block)
- @handlers[sym] = block
- end
+ ##
+ def handle(sym, &block)
+ @handlers[sym] = block
+ end
- def should_receive(method)
- @handler_for = method
- self
- end
+ def should_receive(method)
+ @handler_for = method
+ self
+ end
- def and_respond(text)
- @handlers[@handler_for] = -> s, *args { s.response(text) }
- end
+ def and_respond(text)
+ @handlers[@handler_for] = -> s, *args { s.response(text) }
+ end
- ##
- # FTP methods
- ##
+ ##
+ # FTP methods
+ ##
- def abor
- self.response("226 Closing data connection. (ABOR)")
- end
+ def abor
+ self.response("226 Closing data connection. (ABOR)")
+ end
- def acct(account)
- @login_acct = account
- self.response("230 User '#{account}' logged in, proceed. (ACCT)")
- end
+ def acct(account)
+ @login_acct = account
+ self.response("230 User '#{account}' logged in, proceed. (ACCT)")
+ end
- def cdup
- self.response("200 Command okay. (CDUP)")
- end
+ def cdup
+ self.response("200 Command okay. (CDUP)")
+ end
- def cwd(dir)
- self.response("200 Command okay. (CWD #{dir})")
- end
+ def cwd(dir)
+ self.response("200 Command okay. (CWD #{dir})")
+ end
- def dele(file)
- self.response("250 Requested file action okay, completed. (DELE #{file})")
- end
+ def dele(file)
+ self.response("250 Requested file action okay, completed. (DELE #{file})")
+ end
- def eprt(arg)
- _, _, host, port = arg.split("|")
+ def eprt(arg)
+ _, _, host, port = arg.split("|")
- @datasocket = TCPSocket.new(host, port)
- self.response("200 port opened")
- end
+ @datasocket = TCPSocket.new(host, port)
+ self.response("200 port opened")
+ end
- def help(param = :default)
- if param == :default
- self.response("211 System status, or system help reply. (HELP)")
- else
- self.response("211 System status, or system help reply. (HELP #{param})")
+ def help(param = :default)
+ if param == :default
+ self.response("211 System status, or system help reply. (HELP)")
+ else
+ self.response("211 System status, or system help reply. (HELP #{param})")
+ end
end
- end
- def list(folder)
- self.response("150 opening ASCII connection for file list")
- @datasocket.puts("-rw-r--r-- 1 spec staff 507 17 Jul 18:41 last_response_code.rb")
- @datasocket.puts("-rw-r--r-- 1 spec staff 50 17 Jul 18:41 list.rb")
- @datasocket.puts("-rw-r--r-- 1 spec staff 48 17 Jul 18:41 pwd.rb")
- @datasocket.close()
- self.response("226 transfer complete (LIST #{folder})")
- end
+ def list(folder)
+ self.response("150 opening ASCII connection for file list")
+ @datasocket.puts("-rw-r--r-- 1 spec staff 507 17 Jul 18:41 last_response_code.rb")
+ @datasocket.puts("-rw-r--r-- 1 spec staff 50 17 Jul 18:41 list.rb")
+ @datasocket.puts("-rw-r--r-- 1 spec staff 48 17 Jul 18:41 pwd.rb")
+ @datasocket.close()
+ self.response("226 transfer complete (LIST #{folder})")
+ end
- def mdtm(filename)
- self.response("213 19980705132316")
- end
+ def mdtm(filename)
+ self.response("213 19980705132316")
+ end
- def mkd(foldername)
- self.response(%Q{257 "#{foldername.gsub('"', '""')}" created.})
- end
+ def mkd(foldername)
+ self.response(%Q{257 "#{foldername.gsub('"', '""')}" created.})
+ end
- def nlst(folder = nil)
- self.response("150 opening ASCII connection for file list")
- @datasocket.puts("last_response_code.rb")
- @datasocket.puts("list.rb")
- @datasocket.puts("pwd.rb")
- @datasocket.close()
- self.response("226 transfer complete (NLST#{folder ? " #{folder}" : ""})")
- end
+ def nlst(folder = nil)
+ self.response("150 opening ASCII connection for file list")
+ @datasocket.puts("last_response_code.rb")
+ @datasocket.puts("list.rb")
+ @datasocket.puts("pwd.rb")
+ @datasocket.close()
+ self.response("226 transfer complete (NLST#{folder ? " #{folder}" : ""})")
+ end
- def noop
- self.response("200 Command okay. (NOOP)")
- end
+ def noop
+ self.response("200 Command okay. (NOOP)")
+ end
- def pass(password)
- @login_pass = password
- self.response("230 User logged in, proceed. (PASS #{password})")
- end
+ def pass(password)
+ @login_pass = password
+ self.response("230 User logged in, proceed. (PASS #{password})")
+ end
- def port(arg)
- nums = arg.split(",")
+ def port(arg)
+ nums = arg.split(",")
+
+ if nums[0] == "::1"
+ # IPv6
+ port = nums[1].to_i * 256 + nums[2].to_i
+ host = nums[0]
+ else
+ # IPv4
+ port = nums[4].to_i * 256 + nums[5].to_i
+ host = nums[0..3].join(".")
+ end
- if nums[0] == "::1"
- # IPv6
- port = nums[1].to_i * 256 + nums[2].to_i
- host = nums[0]
- else
- # IPv4
- port = nums[4].to_i * 256 + nums[5].to_i
- host = nums[0..3].join(".")
+ @datasocket = TCPSocket.new(host, port)
+ self.response("200 port opened")
end
- @datasocket = TCPSocket.new(host, port)
- self.response("200 port opened")
- end
-
- def pwd
- self.response('257 "/some/dir/" - current directory')
- end
+ def pwd
+ self.response('257 "/some/dir/" - current directory')
+ end
- def retr(file)
- self.response("125 Data transfer starting")
- if @restart_at && @restart_at == 20
- @datasocket.puts("of the file named '#{file}'.")
- @restart_at = nil
- else
- @datasocket.puts("This is the content")
- @datasocket.puts("of the file named '#{file}'.")
- end
- @datasocket.close()
- self.response("226 Closing data connection. (RETR #{file})")
- end
+ def retr(file)
+ self.response("125 Data transfer starting")
+ if @restart_at && @restart_at == 20
+ @datasocket.puts("of the file named '#{file}'.")
+ @restart_at = nil
+ else
+ @datasocket.puts("This is the content")
+ @datasocket.puts("of the file named '#{file}'.")
+ end
+ @datasocket.close()
+ self.response("226 Closing data connection. (RETR #{file})")
+ end
- def rest(at_bytes)
- @restart_at = at_bytes.to_i
- self.response("350 Requested file action pending further information. (REST)")
- end
+ def rest(at_bytes)
+ @restart_at = at_bytes.to_i
+ self.response("350 Requested file action pending further information. (REST)")
+ end
- def rmd(folder)
- self.response("250 Requested file action okay, completed. (RMD #{folder})")
- end
+ def rmd(folder)
+ self.response("250 Requested file action okay, completed. (RMD #{folder})")
+ end
- def rnfr(from)
- @rename_from = from
- self.response("350 Requested file action pending further information.")
- end
+ def rnfr(from)
+ @rename_from = from
+ self.response("350 Requested file action pending further information.")
+ end
- def rnto(to)
- self.response("250 Requested file action okay, completed. (Renamed #{@rename_from} to #{to})")
- @rename_from = nil
- end
+ def rnto(to)
+ self.response("250 Requested file action okay, completed. (Renamed #{@rename_from} to #{to})")
+ @rename_from = nil
+ end
- def site(param)
- self.response("200 Command okay. (SITE #{param})")
- end
+ def site(param)
+ self.response("200 Command okay. (SITE #{param})")
+ end
- def size(filename)
- if filename == "binary"
- self.response("213 24")
- else
- self.response("213 1024")
+ def size(filename)
+ if filename == "binary"
+ self.response("213 24")
+ else
+ self.response("213 1024")
+ end
end
- end
- def stat(param = :default)
- if param == :default
- self.response("211 System status, or system help reply. (STAT)")
- else
- self.response("211 System status, or system help reply. (STAT #{param})")
+ def stat(param = :default)
+ if param == :default
+ self.response("211 System status, or system help reply. (STAT)")
+ else
+ self.response("211 System status, or system help reply. (STAT #{param})")
+ end
end
- end
- def stor(file)
- tmp_file = tmp("#{file}file", false)
+ def stor(file)
+ tmp_file = tmp("#{file}file", false)
- self.response("125 Data transfer starting.")
+ self.response("125 Data transfer starting.")
- mode = @restart_at ? "a" : "w"
+ mode = @restart_at ? "a" : "w"
- File.open(tmp_file, mode + "b") do |f|
- loop do
- data = @datasocket.recv(1024)
- break if !data || data.empty?
- f << data
+ File.open(tmp_file, mode + "b") do |f|
+ loop do
+ data = @datasocket.recv(1024)
+ break if !data || data.empty?
+ f << data
+ end
end
- end
- @datasocket.close()
- self.response("200 OK, Data received. (STOR #{file})")
- end
+ @datasocket.close()
+ self.response("200 OK, Data received. (STOR #{file})")
+ end
- def appe(file)
- @restart_at = true
- stor(file)
- end
+ def appe(file)
+ @restart_at = true
+ stor(file)
+ end
- def syst
- self.response("215 FTP Dummy Server (SYST)")
- end
+ def syst
+ self.response("215 FTP Dummy Server (SYST)")
+ end
- def type(type)
- self.response("200 TYPE switched to #{type}")
- end
+ def type(type)
+ self.response("200 TYPE switched to #{type}")
+ end
- def user(name)
- @login_user = name
- self.response("230 User logged in, proceed. (USER #{name})")
+ def user(name)
+ @login_user = name
+ self.response("230 User logged in, proceed. (USER #{name})")
+ end
end
end
end
diff --git a/spec/ruby/library/net-ftp/get_spec.rb b/spec/ruby/library/net-ftp/get_spec.rb
index 1bc1bd744b..6a8aa3e206 100644
--- a/spec/ruby/library/net-ftp/get_spec.rb
+++ b/spec/ruby/library/net-ftp/get_spec.rb
@@ -1,21 +1,24 @@
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
+ruby_version_is ""..."4.1" do
+ require_relative 'spec_helper'
+ require_relative 'fixtures/server'
+ require_relative 'shared/gettextfile'
+ require_relative 'shared/getbinaryfile'
- it_behaves_like :net_ftp_getbinaryfile, :get
-end
+ describe "Net::FTP#get (binary mode)" do
+ before :each do
+ @binary_mode = true
+ end
-describe "Net::FTP#get (text mode)" do
- before :each do
- @binary_mode = false
+ it_behaves_like :net_ftp_getbinaryfile, :get
end
- it_behaves_like :net_ftp_gettextfile, :get
+ 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
index e9898fccc7..6b2d38edf5 100644
--- a/spec/ruby/library/net-ftp/getbinaryfile_spec.rb
+++ b/spec/ruby/library/net-ftp/getbinaryfile_spec.rb
@@ -1,8 +1,11 @@
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
+ruby_version_is ""..."4.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
index 756d6a23af..2ff62d399d 100644
--- a/spec/ruby/library/net-ftp/getdir_spec.rb
+++ b/spec/ruby/library/net-ftp/getdir_spec.rb
@@ -1,7 +1,10 @@
require_relative '../../spec_helper'
-require_relative 'spec_helper'
-require_relative 'shared/pwd'
-describe "Net::FTP#getdir" do
- it_behaves_like :net_ftp_pwd, :getdir
+ruby_version_is ""..."4.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
index cdd1b4c797..3bb037663b 100644
--- a/spec/ruby/library/net-ftp/gettextfile_spec.rb
+++ b/spec/ruby/library/net-ftp/gettextfile_spec.rb
@@ -1,8 +1,11 @@
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
+ruby_version_is ""..."4.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
index c562be50b2..bb52fb9e69 100644
--- a/spec/ruby/library/net-ftp/help_spec.rb
+++ b/spec/ruby/library/net-ftp/help_spec.rb
@@ -1,66 +1,69 @@
require_relative '../../spec_helper'
-require_relative 'spec_helper'
-require_relative 'fixtures/server'
-describe "Net::FTP#help" do
- def with_connection
- yield
- end
+ruby_version_is ""..."4.1" do
+ require_relative 'spec_helper'
+ require_relative 'fixtures/server'
- before :each do
- @server = NetFTPSpecs::DummyFTP.new
- @server.serve_once
+ describe "Net::FTP#help" do
+ def with_connection
+ yield
+ end
- @ftp = Net::FTP.new
- @ftp.connect(@server.hostname, @server.server_port)
- end
+ before :each do
+ @server = NetFTPSpecs::DummyFTP.new
+ @server.serve_once
- after :each do
- @ftp.quit rescue nil
- @ftp.close
- @server.stop
- end
+ @ftp = Net::FTP.new
+ @ftp.connect(@server.hostname, @server.server_port)
+ 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
+ after :each do
+ @ftp.quit rescue nil
+ @ftp.close
+ @server.stop
+ 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 to the server" do
+ @ftp.help
+ @ftp.last_response.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 "returns the server's response" do
+ @ftp.help.should == "211 System status, or system help reply. (HELP)\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 "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 214" do
- @server.should_receive(:help).and_respond("214 Help message.")
- -> { @ftp.help }.should_not raise_error
- 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
+ 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 "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
+ 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 500" do
+ @server.should_receive(:help).and_respond("500 Syntax error, command unrecognized.")
+ -> { @ftp.help }.should.raise(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::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(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(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)
+ 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(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
index 4d775e8dc1..9079ad6b79 100644
--- a/spec/ruby/library/net-ftp/initialize_spec.rb
+++ b/spec/ruby/library/net-ftp/initialize_spec.rb
@@ -1,402 +1,405 @@
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
+ruby_version_is ""..."4.1" do
+ require_relative 'spec_helper'
- 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
+ describe "Net::FTP#initialize" do
+ before :each do
+ @ftp = Net::FTP.allocate
+ @ftp.stub!(:connect)
+ @port_args = []
+ @port_args << 21
+ 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 "is private" do
+ Net::FTP.private_instance_methods(false).should.include?(:initialize)
+ 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
+ it "sets self into binary mode" do
+ @ftp.binary.should == nil
+ @ftp.send(:initialize)
+ @ftp.binary.should == true
+ end
- describe "when passed no arguments" do
- it "does not try to connect" do
- @ftp.should_not_receive(:connect)
+ it "sets self into active mode" do
+ @ftp.passive.should == nil
@ftp.send(:initialize)
+ @ftp.passive.should == false
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")
+ it "sets self into non-debug mode" do
+ @ftp.debug_mode.should == nil
+ @ftp.send(:initialize)
+ @ftp.debug_mode.should == false
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")
+ it "sets self to not resume file uploads/downloads" do
+ @ftp.resume.should == nil
+ @ftp.send(:initialize)
+ @ftp.resume.should == false
end
- it "tries to login with the passed username" do
- @ftp.should_receive(:login).with("rubyspec", nil, nil)
- @ftp.send(:initialize, "localhost", "rubyspec")
+ describe "when passed no arguments" do
+ it "does not try to connect" do
+ @ftp.should_not_receive(:connect)
+ @ftp.send(:initialize)
+ end
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")
+ 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
- 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")
+ 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
- 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")
+ 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
- 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")
+ 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
- end
- before :each do
- @ftp.stub!(:login)
- 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)
+ 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)
+ @ftp.send(:initialize, 'localhost', options)
+ end
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)
+ 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')
+ @ftp.send(:initialize, 'localhost')
+ end
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)
+ 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
- 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)
+ 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)
+ @ftp.send(:initialize, 'localhost', options)
+ end
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')
+ 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)
+ @ftp.send(:initialize, 'localhost', options)
+ end
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)
+ 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)
+ @ftp.send(:initialize, 'localhost', options)
+ end
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)
+ 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)
+ @ftp.send(:initialize, 'localhost', options)
+ end
end
end
end
- end
- describe 'is unset' do
- it 'does not try to connect' do
- @ftp.should_not_receive(:connect)
+ describe 'is unset' do
+ it 'does not try to connect' do
+ @ftp.should_not_receive(:connect)
- @ftp.send(:initialize)
- end
+ @ftp.send(:initialize)
+ end
- it 'does not try to log in' do
- @ftp.should_not_receive(:login)
+ it 'does not try to log in' do
+ @ftp.should_not_receive(:login)
- @ftp.send(:initialize)
+ @ftp.send(:initialize)
+ end
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 })
+ 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
+ @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 'to false' do
+ describe 'is unset' 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.send(:initialize)
@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 })
- 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
- @ftp.send(:initialize, nil, options)
- @ftp.debug_mode.should == true
+ 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 'to false' do
+ describe 'is unset' 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.send(:initialize)
@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 })
+ 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
+ @ftp.send(:initialize, nil, options)
+ @ftp.open_timeout.should == 42
+ end
end
- end
- describe 'is not set' do
- it 'sets open_timeout to nil' do
- @ftp.send(:initialize)
- @ftp.open_timeout.should == nil
+ describe 'is not set' do
+ it 'sets open_timeout to nil' do
+ @ftp.send(:initialize)
+ @ftp.open_timeout.should == nil
+ end
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 })
+ 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
+ @ftp.send(:initialize, nil, options)
+ @ftp.read_timeout.should == 100
+ end
end
- end
- describe 'is not set' do
- it 'sets read_timeout to the default value' do
- @ftp.send(:initialize)
- @ftp.read_timeout.should == 60
+ 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
- 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 })
+ 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
+ @ftp.send(:initialize, nil, options)
+ @ftp.ssl_handshake_timeout.should == 23
+ end
end
- end
- describe 'is not set' do
- it 'sets ssl_handshake_timeout to nil' do
- @ftp.send(:initialize)
- @ftp.ssl_handshake_timeout.should == nil
+ 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
- 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 })
+ 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)
+ 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({})
+ 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
+ @ftp.send(:initialize, nil, options)
+ @ftp.instance_variable_get(:@ssl_context).should == ssl_context
+ end
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'} })
+ 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)
+ 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'})
+ 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
+ @ftp.send(:initialize, nil, options)
+ @ftp.instance_variable_get(:@ssl_context).should == ssl_context
+ end
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' })
+ 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'
+ @ftp.send(:initialize, nil, options)
+ @ftp.instance_variable_get(:@private_data_connection).should == 'true'
+ end
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 })
+ 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
+ @ftp.send(:initialize, nil, options)
+ @ftp.instance_variable_get(:@private_data_connection).should == true
+ end
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({})
+ 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
+ @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 })
+ 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/)
+ -> {
+ @ftp.send(:initialize, nil, options)
+ }.should.raise(ArgumentError, /private_data_connection can be set to true only when ssl is enabled/)
+ end
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({})
+ 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
+ @ftp.send(:initialize, nil, options)
+ @ftp.instance_variable_get(:@private_data_connection).should == false
+ 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
index c17c28f0f8..03329758b5 100644
--- a/spec/ruby/library/net-ftp/last_response_code_spec.rb
+++ b/spec/ruby/library/net-ftp/last_response_code_spec.rb
@@ -1,8 +1,11 @@
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
+ruby_version_is ""..."4.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
index c9d9d70f35..7cda9fa7a4 100644
--- a/spec/ruby/library/net-ftp/last_response_spec.rb
+++ b/spec/ruby/library/net-ftp/last_response_spec.rb
@@ -1,25 +1,28 @@
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
+ruby_version_is ""..."4.1" do
+ require_relative 'spec_helper'
+ require_relative 'fixtures/server'
- @ftp = Net::FTP.new
- @ftp.connect(@server.hostname, @server.server_port)
- end
+ describe "Net::FTP#last_response" do
+ before :each do
+ @server = NetFTPSpecs::DummyFTP.new
+ @server.serve_once
- after :each do
- @ftp.quit rescue nil
- @ftp.close
- @server.stop
- end
+ @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"
+ 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
index e0c1b862a0..c373670ec4 100644
--- a/spec/ruby/library/net-ftp/lastresp_spec.rb
+++ b/spec/ruby/library/net-ftp/lastresp_spec.rb
@@ -1,8 +1,11 @@
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
+ruby_version_is ""..."4.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
index 6cb1bbc4b8..297d100dd9 100644
--- a/spec/ruby/library/net-ftp/list_spec.rb
+++ b/spec/ruby/library/net-ftp/list_spec.rb
@@ -1,8 +1,11 @@
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
+ruby_version_is ""..."4.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
index 0de2f5cc63..05bb6b7f81 100644
--- a/spec/ruby/library/net-ftp/login_spec.rb
+++ b/spec/ruby/library/net-ftp/login_spec.rb
@@ -1,195 +1,198 @@
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
+ruby_version_is ""..."4.1" do
+ require_relative 'spec_helper'
+ require_relative 'fixtures/server'
- @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
+ describe "Net::FTP#login" 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)
+ @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(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(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(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(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(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(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(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(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(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
+ 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(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(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(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(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(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
+ 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(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(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(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(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(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
index acd7e9e523..f8fdb10e8f 100644
--- a/spec/ruby/library/net-ftp/ls_spec.rb
+++ b/spec/ruby/library/net-ftp/ls_spec.rb
@@ -1,8 +1,11 @@
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
+ruby_version_is ""..."4.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
index a504507c84..effd22a6e4 100644
--- a/spec/ruby/library/net-ftp/mdtm_spec.rb
+++ b/spec/ruby/library/net-ftp/mdtm_spec.rb
@@ -1,38 +1,41 @@
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
+ruby_version_is ""..."4.1" do
+ require_relative 'spec_helper'
+ require_relative 'fixtures/server'
- @ftp = Net::FTP.new
- @ftp.connect(@server.hostname, @server.server_port)
- end
+ describe "Net::FTP#mdtm" do
+ before :each do
+ @server = NetFTPSpecs::DummyFTP.new
+ @server.serve_once
- after :each do
- @ftp.quit rescue nil
- @ftp.close
- @server.stop
- end
+ @ftp = Net::FTP.new
+ @ftp.connect(@server.hostname, @server.server_port)
+ 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
+ after :each do
+ @ftp.quit rescue nil
+ @ftp.close
+ @server.stop
+ end
- it "returns the last modification time of the passed file" do
- @ftp.mdtm("test.file").should == "19980705132316"
- 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 "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 "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(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)
+ 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(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
index 8cc6ae785e..6daeb7c022 100644
--- a/spec/ruby/library/net-ftp/mkdir_spec.rb
+++ b/spec/ruby/library/net-ftp/mkdir_spec.rb
@@ -1,61 +1,64 @@
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
+ruby_version_is ""..."4.1" do
+ require_relative 'spec_helper'
+ require_relative 'fixtures/server'
- @ftp = Net::FTP.new
- @ftp.connect(@server.hostname, @server.server_port)
- end
+ describe "Net::FTP#mkdir" do
+ before :each do
+ @server = NetFTPSpecs::DummyFTP.new
+ @server.serve_once
- after :each do
- @ftp.quit rescue nil
- @ftp.close
- @server.stop
- end
+ @ftp = Net::FTP.new
+ @ftp.connect(@server.hostname, @server.server_port)
+ 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
+ after :each do
+ @ftp.quit rescue nil
+ @ftp.close
+ @server.stop
+ 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 "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 "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 "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 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 500" do
+ @server.should_receive(:mkd).and_respond("500 Syntax error, command unrecognized.")
+ -> { @ftp.mkdir("test.folder") }.should.raise(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::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(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 502" do
+ @server.should_receive(:mkd).and_respond("502 Command not implemented.")
+ -> { @ftp.mkdir("test.folder") }.should.raise(Net::FTPPermError)
+ 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::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(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(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)
+ 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(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
index 9dde1278a8..694036a296 100644
--- a/spec/ruby/library/net-ftp/mtime_spec.rb
+++ b/spec/ruby/library/net-ftp/mtime_spec.rb
@@ -1,50 +1,53 @@
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
+ruby_version_is ""..."4.1" do
+ require_relative 'spec_helper'
+ require_relative 'fixtures/server'
- @ftp = Net::FTP.new
- @ftp.connect(@server.hostname, @server.server_port)
- end
+ describe "Net::FTP#mtime" do
+ before :each do
+ @server = NetFTPSpecs::DummyFTP.new
+ @server.serve_once
- after :each do
- @ftp.quit rescue nil
- @ftp.close
- @server.stop
- end
+ @ftp = Net::FTP.new
+ @ftp.connect(@server.hostname, @server.server_port)
+ 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
+ after :each do
+ @ftp.quit rescue nil
+ @ftp.close
+ @server.stop
+ 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")
+ 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
- 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")
+ 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
- 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")
+ 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
- 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::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(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)
+ 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(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
index 2f22543af6..87b80b43fd 100644
--- a/spec/ruby/library/net-ftp/nlst_spec.rb
+++ b/spec/ruby/library/net-ftp/nlst_spec.rb
@@ -1,92 +1,95 @@
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
+ruby_version_is ""..."4.1" do
+ require_relative 'spec_helper'
+ require_relative 'fixtures/server'
- @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 "Net::FTP#nlst" do
+ before :each do
+ @server = NetFTPSpecs::DummyFTP.new
+ @server.serve_once
- 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"
+ @ftp = Net::FTP.new
+ @ftp.passive = false
+ @ftp.connect(@server.hostname, @server.server_port)
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"
+ after :each do
+ @ftp.quit rescue nil
+ @ftp.close
+ @server.stop
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)
+ 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
- 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)
+ 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
- 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
+ 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(Net::FTPTempError)
+ 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::FTPPermError when the response code is 500" do
+ @server.should_receive(:nlst).and_respond("500 Syntax error, command unrecognized.")
+ -> { @ftp.nlst }.should.raise(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 501" do
+ @server.should_receive(:nlst).and_respond("501 Syntax error, command unrecognized.")
+ -> { @ftp.nlst }.should.raise(Net::FTPPermError)
+ 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
+ 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(Net::FTPPermError)
+ 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::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(Net::FTPTempError)
+ 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)
+ 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(Net::FTPPermError)
+ end
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
+ 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(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(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(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)
+ 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(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
index 4743a39ef6..43c48e355a 100644
--- a/spec/ruby/library/net-ftp/noop_spec.rb
+++ b/spec/ruby/library/net-ftp/noop_spec.rb
@@ -1,38 +1,41 @@
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
+ruby_version_is ""..."4.1" do
+ require_relative 'spec_helper'
+ require_relative 'fixtures/server'
- @ftp = Net::FTP.new
- @ftp.connect(@server.hostname, @server.server_port)
- end
+ describe "Net::FTP#noop" do
+ before :each do
+ @server = NetFTPSpecs::DummyFTP.new
+ @server.serve_once
- after :each do
- @ftp.quit rescue nil
- @ftp.close
- @server.stop
- end
+ @ftp = Net::FTP.new
+ @ftp.connect(@server.hostname, @server.server_port)
+ end
- it "sends the NOOP command to the server" do
- @ftp.noop
- @ftp.last_response.should == "200 Command okay. (NOOP)\n"
- end
+ after :each do
+ @ftp.quit rescue nil
+ @ftp.close
+ @server.stop
+ end
- it "returns nil" do
- @ftp.noop.should be_nil
- end
+ it "sends the NOOP command to the server" do
+ @ftp.noop
+ @ftp.last_response.should == "200 Command okay. (NOOP)\n"
+ 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 "returns nil" do
+ @ftp.noop.should == 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(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)
+ 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(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
index e59496dc3c..2d6477ec4d 100644
--- a/spec/ruby/library/net-ftp/open_spec.rb
+++ b/spec/ruby/library/net-ftp/open_spec.rb
@@ -1,55 +1,58 @@
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
+ruby_version_is ""..."4.1" do
+ require_relative 'spec_helper'
- describe "when passed no block" do
- it "returns a new Net::FTP instance" do
- Net::FTP.open("localhost").should equal(@ftp)
+ describe "Net::FTP.open" do
+ before :each do
+ @ftp = mock("Net::FTP instance")
+ Net::FTP.stub!(:new).and_return(@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 no block" do
+ it "returns a new Net::FTP instance" do
+ Net::FTP.open("localhost").should.equal?(@ftp)
+ end
- describe "when passed a block" do
- before :each do
- @ftp.stub!(:close)
+ 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
- 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)
+ describe "when passed a block" do
+ before :each do
+ @ftp.stub!(:close)
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)
+ 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 == true
end
- end
- it "closes the Net::FTP instance even if an exception is raised while yielding" do
- begin
+ it "closes the Net::FTP instance after yielding" do
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
+ 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
index 97659f1b68..6acabd3f98 100644
--- a/spec/ruby/library/net-ftp/passive_spec.rb
+++ b/spec/ruby/library/net-ftp/passive_spec.rb
@@ -1,28 +1,31 @@
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
+ruby_version_is ""..."4.1" do
+ require_relative 'spec_helper'
- ftp.passive = true
- ftp.passive.should be_true
- end
+ describe "Net::FTP#passive" do
+ it "returns true when self is in passive mode" do
+ ftp = Net::FTP.new
+ ftp.passive.should == false
+
+ ftp.passive = true
+ ftp.passive.should == true
+ end
- it "is the value of Net::FTP.default_value by default" do
- ruby_exe(fixture(__FILE__, "passive.rb")).should == "true"
+ it "is the value of Net::FTP.default_value by default" do
+ ruby_exe(fixture(__FILE__, "passive.rb")).should == "true"
+ end
end
-end
-describe "Net::FTP#passive=" do
- it "sets self to passive mode when passed true" do
- ftp = Net::FTP.new
+ 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 = true
+ ftp.passive.should == true
- ftp.passive = false
- ftp.passive.should be_false
+ ftp.passive = false
+ ftp.passive.should == false
+ end
end
end
diff --git a/spec/ruby/library/net-ftp/put_spec.rb b/spec/ruby/library/net-ftp/put_spec.rb
index 6d40d3d5b9..603409e283 100644
--- a/spec/ruby/library/net-ftp/put_spec.rb
+++ b/spec/ruby/library/net-ftp/put_spec.rb
@@ -1,21 +1,24 @@
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
+ruby_version_is ""..."4.1" do
+ require_relative 'spec_helper'
+ require_relative 'fixtures/server'
+ require_relative 'shared/puttextfile'
+ require_relative 'shared/putbinaryfile'
- it_behaves_like :net_ftp_putbinaryfile, :put
-end
+ describe "Net::FTP#put (binary mode)" do
+ before :each do
+ @binary_mode = true
+ end
-describe "Net::FTP#put (text mode)" do
- before :each do
- @binary_mode = false
+ it_behaves_like :net_ftp_putbinaryfile, :put
end
- it_behaves_like :net_ftp_puttextfile, :put
+ 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
index d0398229e5..ce8a6f0473 100644
--- a/spec/ruby/library/net-ftp/putbinaryfile_spec.rb
+++ b/spec/ruby/library/net-ftp/putbinaryfile_spec.rb
@@ -1,8 +1,11 @@
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
+ruby_version_is ""..."4.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
index b8bcac33df..b4ab86aab1 100644
--- a/spec/ruby/library/net-ftp/puttextfile_spec.rb
+++ b/spec/ruby/library/net-ftp/puttextfile_spec.rb
@@ -1,8 +1,11 @@
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
+ruby_version_is ""..."4.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
index 992e2c4ed2..53692b553f 100644
--- a/spec/ruby/library/net-ftp/pwd_spec.rb
+++ b/spec/ruby/library/net-ftp/pwd_spec.rb
@@ -1,53 +1,56 @@
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)
+ruby_version_is ""..."4.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(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(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(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(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(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
index c5352ceada..1af0107d34 100644
--- a/spec/ruby/library/net-ftp/quit_spec.rb
+++ b/spec/ruby/library/net-ftp/quit_spec.rb
@@ -1,33 +1,36 @@
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
+ruby_version_is ""..."4.1" do
+ require_relative 'spec_helper'
+ require_relative 'fixtures/server'
- @ftp = Net::FTP.new
- @ftp.connect(@server.hostname, @server.server_port)
- end
+ describe "Net::FTP#quit" do
+ before :each do
+ @server = NetFTPSpecs::DummyFTP.new
+ @server.serve_once
- after :each do
- @ftp.quit rescue nil
- @ftp.close
- @server.stop
- end
+ @ftp = Net::FTP.new
+ @ftp.connect(@server.hostname, @server.server_port)
+ end
- it "sends the QUIT command to the server" do
- @ftp.quit
- @ftp.last_response.should == "221 OK, bye\n"
- end
+ after :each do
+ @ftp.quit rescue nil
+ @ftp.close
+ @server.stop
+ end
- it "does not close the socket automatically" do
- @ftp.quit
- @ftp.closed?.should be_false
- 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 == false
+ end
- it "returns nil" do
- @ftp.quit.should be_nil
+ it "returns nil" do
+ @ftp.quit.should == nil
+ end
end
end
diff --git a/spec/ruby/library/net-ftp/rename_spec.rb b/spec/ruby/library/net-ftp/rename_spec.rb
index 48f81b7deb..6541fe5301 100644
--- a/spec/ruby/library/net-ftp/rename_spec.rb
+++ b/spec/ruby/library/net-ftp/rename_spec.rb
@@ -1,94 +1,97 @@
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
+ruby_version_is ""..."4.1" do
+ require_relative 'spec_helper'
+ require_relative 'fixtures/server'
- @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
+ describe "Net::FTP#rename" do
+ before :each do
+ @server = NetFTPSpecs::DummyFTP.new
+ @server.serve_once
- 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)
+ @ftp = Net::FTP.new
+ @ftp.connect(@server.hostname, @server.server_port)
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)
+ after :each do
+ @ftp.quit rescue nil
+ @ftp.close
+ @server.stop
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
+ 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 "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)
+ it "returns something" do
+ @ftp.rename("from.file", "to.file").should == nil
+ end
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)
+ 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(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(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(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(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(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(Net::FTPPermError)
+ end
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)
+ 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(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(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(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(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(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(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
index 6592fc5bb0..5ec565d155 100644
--- a/spec/ruby/library/net-ftp/resume_spec.rb
+++ b/spec/ruby/library/net-ftp/resume_spec.rb
@@ -1,23 +1,26 @@
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
+ruby_version_is ""..."4.1" do
+ require_relative 'spec_helper'
- ftp.resume = true
- ftp.resume.should be_true
+ describe "Net::FTP#resume" do
+ it "returns true when self is set to resume uploads/downloads" do
+ ftp = Net::FTP.new
+ ftp.resume.should == false
+
+ ftp.resume = true
+ ftp.resume.should == true
+ end
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
+ 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 == true
- ftp.resume = false
- ftp.resume.should be_false
+ ftp.resume = false
+ ftp.resume.should == false
+ end
end
end
diff --git a/spec/ruby/library/net-ftp/retrbinary_spec.rb b/spec/ruby/library/net-ftp/retrbinary_spec.rb
index de024208aa..ff8c8098a4 100644
--- a/spec/ruby/library/net-ftp/retrbinary_spec.rb
+++ b/spec/ruby/library/net-ftp/retrbinary_spec.rb
@@ -1,30 +1,33 @@
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
+ruby_version_is ""..."4.1" do
+ require_relative 'spec_helper'
+ require_relative 'fixtures/server'
- @ftp = Net::FTP.new
- @ftp.connect(@server.hostname, @server.server_port)
- end
+ describe "Net::FTP#retrbinary" do
+ before :each do
+ @server = NetFTPSpecs::DummyFTP.new
+ @server.serve_once
- after :each do
- @ftp.quit rescue nil
- @ftp.close
- @server.stop
- end
+ @ftp = Net::FTP.new
+ @ftp.connect(@server.hostname, @server.server_port)
+ 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
+ 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" ]
+ 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
index 866ecb5f40..2963da14f7 100644
--- a/spec/ruby/library/net-ftp/retrlines_spec.rb
+++ b/spec/ruby/library/net-ftp/retrlines_spec.rb
@@ -1,34 +1,37 @@
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
+ruby_version_is ""..."4.1" do
+ require_relative 'spec_helper'
+ require_relative 'fixtures/server'
- @ftp = Net::FTP.new
- @ftp.connect(@server.hostname, @server.server_port)
- end
+ describe "Net::FTP#retrlines" do
+ before :each do
+ @server = NetFTPSpecs::DummyFTP.new
+ @server.serve_once
- after :each do
- @ftp.quit rescue nil
- @ftp.close
- @server.stop
- end
+ @ftp = Net::FTP.new
+ @ftp.connect(@server.hostname, @server.server_port)
+ 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
+ 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"
- ]
+ 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
index 35a6232f7e..fcf5a32aa7 100644
--- a/spec/ruby/library/net-ftp/return_code_spec.rb
+++ b/spec/ruby/library/net-ftp/return_code_spec.rb
@@ -1,24 +1,27 @@
require_relative '../../spec_helper'
-require_relative 'spec_helper'
-describe "Net::FTP#return_code" do
- before :each do
- @ftp = Net::FTP.new
- end
+ruby_version_is ""..."4.1" do
+ require_relative 'spec_helper'
- 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
-describe "Net::FTP#return_code=" do
- before :each do
- @ftp = Net::FTP.new
+ 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
- it "outputs a warning" do
- -> { @ftp.return_code = 123 }.should complain(/warning: Net::FTP#return_code= is obsolete and do nothing/)
+ 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
index 400874d60d..23650ebcc8 100644
--- a/spec/ruby/library/net-ftp/rmdir_spec.rb
+++ b/spec/ruby/library/net-ftp/rmdir_spec.rb
@@ -1,58 +1,61 @@
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)
+ruby_version_is ""..."4.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 == 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(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(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(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(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(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(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
index c50b373869..67dbd3bdb8 100644
--- a/spec/ruby/library/net-ftp/sendcmd_spec.rb
+++ b/spec/ruby/library/net-ftp/sendcmd_spec.rb
@@ -1,54 +1,57 @@
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)
+ruby_version_is ""..."4.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
+
+ @server.should_receive(:help).and_respond("200 Command okay.")
+ -> { @ftp.sendcmd("HELP") }.should_not.raise
+
+ @server.should_receive(:help).and_respond("350 Requested file action pending further information.")
+ -> { @ftp.sendcmd("HELP") }.should_not.raise
+ 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(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(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(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
index 8182dd8b33..ad83dfcc4f 100644
--- a/spec/ruby/library/net-ftp/set_socket_spec.rb
+++ b/spec/ruby/library/net-ftp/set_socket_spec.rb
@@ -1,8 +1,11 @@
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"
+ruby_version_is ""..."4.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
index ceec8e7cd5..4fc4731c45 100644
--- a/spec/ruby/library/net-ftp/shared/getbinaryfile.rb
+++ b/spec/ruby/library/net-ftp/shared/getbinaryfile.rb
@@ -1,150 +1,152 @@
-describe :net_ftp_getbinaryfile, shared: true do
- before :each do
- @fixture_file = __dir__ + "/../fixtures/getbinaryfile"
- @tmp_file = tmp("getbinaryfile")
+ruby_version_is ""..."4.1" do
+ 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
+ @server = NetFTPSpecs::DummyFTP.new
+ @server.serve_once
- @ftp = Net::FTP.new
- @ftp.connect(@server.hostname, @server.server_port)
- @ftp.binary = @binary_mode
- end
+ @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
+ after :each do
+ @ftp.quit rescue nil
+ @ftp.close
+ @server.stop
- rm_r @tmp_file
- end
+ 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 "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 "returns nil" do
+ @ftp.send(@method, "test", @tmp_file).should == 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
+ 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" ]
+ 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
- end
- describe "when resuming an existing file" do
- before :each do
- @tmp_file = tmp("getbinaryfile_resume")
+ 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"
+ File.open(@tmp_file, "wb") do |f|
+ f << "This is the content\n"
+ end
+
+ @ftp.resume = true
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
- 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"
+ 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(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(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(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(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(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(Net::FTPPermError)
+ end
+ end
end
- describe "and the REST command fails" do
+ 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(Net::FTPTempError)
+ end
+
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)
+ @server.should_receive(:retr).and_respond("Requested action not taken.")
+ -> { @ftp.send(@method, "test", @tmp_file) }.should.raise(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)
+ @server.should_receive(:retr).and_respond("500 Syntax error, command unrecognized.")
+ -> { @ftp.send(@method, "test", @tmp_file) }.should.raise(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)
+ @server.should_receive(:retr).and_respond("501 Syntax error, command unrecognized.")
+ -> { @ftp.send(@method, "test", @tmp_file) }.should.raise(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)
+ @server.should_receive(:retr).and_respond("421 Service not available, closing control connection.")
+ -> { @ftp.send(@method, "test", @tmp_file) }.should.raise(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)
+ @server.should_receive(:retr).and_respond("530 Not logged in.")
+ -> { @ftp.send(@method, "test", @tmp_file) }.should.raise(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
+ 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(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::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(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::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(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)
+ 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(Net::FTPPermError)
+ end
end
end
end
diff --git a/spec/ruby/library/net-ftp/shared/gettextfile.rb b/spec/ruby/library/net-ftp/shared/gettextfile.rb
index 7fe14f7dfb..562c7a3047 100644
--- a/spec/ruby/library/net-ftp/shared/gettextfile.rb
+++ b/spec/ruby/library/net-ftp/shared/gettextfile.rb
@@ -1,100 +1,102 @@
-describe :net_ftp_gettextfile, shared: true do
- before :each do
- @tmp_file = tmp("gettextfile")
+ruby_version_is ""..."4.1" do
+ describe :net_ftp_gettextfile, shared: true do
+ before :each do
+ @tmp_file = tmp("gettextfile")
- @server = NetFTPSpecs::DummyFTP.new
- @server.serve_once
+ @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'."]
+ @ftp = Net::FTP.new
+ @ftp.connect(@server.hostname, @server.server_port)
+ @ftp.binary = @binary_mode
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
+ after :each do
+ @ftp.quit rescue nil
+ @ftp.close
+ @server.stop
- 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)
+ rm_r @tmp_file
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)
+ 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 "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)
+ it "returns nil" do
+ @ftp.send(@method, "test", @tmp_file).should == nil
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)
+ 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
- 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)
+ 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
- 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)
+ 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(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(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(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(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(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(Net::FTPPermError)
+ end
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)
+ 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(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(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(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(Net::FTPPermError)
+ end
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..9d36e37f0c 100644
--- a/spec/ruby/library/net-ftp/shared/last_response_code.rb
+++ b/spec/ruby/library/net-ftp/shared/last_response_code.rb
@@ -1,25 +1,27 @@
-describe :net_ftp_last_response_code, shared: true do
- before :each do
- @server = NetFTPSpecs::DummyFTP.new
- @server.serve_once
+ruby_version_is ""..."4.1" do
+ describe :net_ftp_last_response_code, shared: true do
+ before :each do
+ @server = NetFTPSpecs::DummyFTP.new
+ @server.serve_once
- @ftp = Net::FTP.new
- @ftp.connect(@server.hostname, @server.server_port)
- end
+ @ftp = Net::FTP.new
+ @ftp.connect(@server.hostname, @server.server_port)
+ end
- after :each do
- @ftp.quit rescue nil
- @ftp.close
- @server.stop
- end
+ after :each do
+ @ftp.quit rescue nil
+ @ftp.close
+ @server.stop
+ end
- it "returns the response code for the last response" do
- @server.should_receive(:help).and_respond("200 Command okay.")
- @ftp.help
- @ftp.send(@method).should == "200"
+ it "returns the response code for the last response" do
+ @server.should_receive(:help).and_respond("200 Command okay.")
+ @ftp.help
+ @ftp.send(@method).should == "200"
- @server.should_receive(:help).and_respond("212 Directory status.")
- @ftp.help
- @ftp.send(@method).should == "212"
+ @server.should_receive(:help).and_respond("212 Directory status.")
+ @ftp.help
+ @ftp.send(@method).should == "212"
+ end
end
end
diff --git a/spec/ruby/library/net-ftp/shared/list.rb b/spec/ruby/library/net-ftp/shared/list.rb
index adc3fa59c1..ec372447e8 100644
--- a/spec/ruby/library/net-ftp/shared/list.rb
+++ b/spec/ruby/library/net-ftp/shared/list.rb
@@ -1,104 +1,106 @@
-describe :net_ftp_list, shared: true 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 a block" do
- it "yields each file in the list of files in the passed dir" do
- expected = [
- "-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"
- ]
-
- res = []
- @ftp.send(@method, "test.folder") { |line| res << line}
- res.should == expected
-
- @ftp.last_response.should == "226 transfer complete (LIST test.folder)\n"
+ruby_version_is ""..."4.1" do
+ describe :net_ftp_list, shared: true 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
- end
-
- describe "when passed no block" do
- it "returns an Array containing a list of files in the passed dir" do
- expected = [
- "-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"
- ]
- @ftp.send(@method, "test.folder").should == expected
-
- @ftp.last_response.should == "226 transfer complete (LIST test.folder)\n"
+ after :each do
+ @ftp.quit rescue nil
+ @ftp.close
+ @server.stop
end
- end
- describe "when the LIST command fails" do
- it "raises a Net::FTPTempError when the response code is 450" do
- @server.should_receive(:list).and_respond("450 Requested file action not taken..")
- -> { @ftp.send(@method) }.should raise_error(Net::FTPTempError)
- end
+ describe "when passed a block" do
+ it "yields each file in the list of files in the passed dir" do
+ expected = [
+ "-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"
+ ]
- it "raises a Net::FTPPermError when the response code is 500" do
- @server.should_receive(:list).and_respond("500 Syntax error, command unrecognized.")
- -> { @ftp.send(@method) }.should raise_error(Net::FTPPermError)
- end
+ res = []
+ @ftp.send(@method, "test.folder") { |line| res << line}
+ res.should == expected
- it "raises a Net::FTPPermError when the response code is 501" do
- @server.should_receive(:list).and_respond("501 Syntax error, command unrecognized.")
- -> { @ftp.send(@method) }.should raise_error(Net::FTPPermError)
+ @ftp.last_response.should == "226 transfer complete (LIST test.folder)\n"
+ end
end
- it "raises a Net::FTPPermError when the response code is 502" do
- @server.should_receive(:list).and_respond("502 Command not implemented.")
- -> { @ftp.send(@method) }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPTempError when the response code is 421" do
- @server.should_receive(:list).and_respond("421 Service not available, closing control connection.")
- -> { @ftp.send(@method) }.should raise_error(Net::FTPTempError)
- end
+ describe "when passed no block" do
+ it "returns an Array containing a list of files in the passed dir" do
+ expected = [
+ "-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"
+ ]
- it "raises a Net::FTPPermError when the response code is 530" do
- @server.should_receive(:list).and_respond("530 Not logged in.")
- -> { @ftp.send(@method) }.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) }.should raise_error(Net::FTPPermError)
- end
+ @ftp.send(@method, "test.folder").should == expected
- 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) }.should raise_error(Net::FTPPermError)
+ @ftp.last_response.should == "226 transfer complete (LIST test.folder)\n"
+ end
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) }.should raise_error(Net::FTPTempError)
+ describe "when the LIST command fails" do
+ it "raises a Net::FTPTempError when the response code is 450" do
+ @server.should_receive(:list).and_respond("450 Requested file action not taken..")
+ -> { @ftp.send(@method) }.should.raise(Net::FTPTempError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 500" do
+ @server.should_receive(:list).and_respond("500 Syntax error, command unrecognized.")
+ -> { @ftp.send(@method) }.should.raise(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 501" do
+ @server.should_receive(:list).and_respond("501 Syntax error, command unrecognized.")
+ -> { @ftp.send(@method) }.should.raise(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 502" do
+ @server.should_receive(:list).and_respond("502 Command not implemented.")
+ -> { @ftp.send(@method) }.should.raise(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPTempError when the response code is 421" do
+ @server.should_receive(:list).and_respond("421 Service not available, closing control connection.")
+ -> { @ftp.send(@method) }.should.raise(Net::FTPTempError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 530" do
+ @server.should_receive(:list).and_respond("530 Not logged in.")
+ -> { @ftp.send(@method) }.should.raise(Net::FTPPermError)
+ end
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) }.should raise_error(Net::FTPPermError)
+ 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) }.should.raise(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) }.should.raise(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) }.should.raise(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) }.should.raise(Net::FTPPermError)
+ end
end
end
end
diff --git a/spec/ruby/library/net-ftp/shared/putbinaryfile.rb b/spec/ruby/library/net-ftp/shared/putbinaryfile.rb
index 45f53adc2a..afbe3c61f8 100644
--- a/spec/ruby/library/net-ftp/shared/putbinaryfile.rb
+++ b/spec/ruby/library/net-ftp/shared/putbinaryfile.rb
@@ -1,167 +1,169 @@
-describe :net_ftp_putbinaryfile, shared: true do
- before :each do
- @server = NetFTPSpecs::DummyFTP.new
- @server.serve_once
+ruby_version_is ""..."4.1" do
+ 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)
+ @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
+ @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
+ 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
+ rm_r @remote_tmp_file
+ end
- it "sends the contents of the passed local_file, without modifications" do
- @ftp.send(@method, @local_fixture_file, "binary")
+ 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
- remote_lines = File.readlines(@remote_tmp_file)
- local_lines = File.readlines(@local_fixture_file)
+ it "sends the contents of the passed local_file, without modifications" do
+ @ftp.send(@method, @local_fixture_file, "binary")
- remote_lines.should == local_lines
- end
+ remote_lines = File.readlines(@remote_tmp_file)
+ local_lines = File.readlines(@local_fixture_file)
- it "returns nil" do
- @ftp.send(@method, @local_fixture_file, "binary").should be_nil
- end
+ remote_lines.should == local_lines
+ 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"
- ]
+ it "returns nil" do
+ @ftp.send(@method, @local_fixture_file, "binary").should == nil
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"
+ 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
-
- @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 "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
- 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)
+ @ftp.resume = true
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)
+ 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
- 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)
+ 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(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(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(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(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(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(Net::FTPPermError)
+ end
end
+ 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)
+ 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(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)
+ 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(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)
+ 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(Net::FTPTempError)
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 553" do
+ @server.should_receive(:stor).and_respond("553 Requested action not taken.")
+ -> { @ftp.send(@method, @local_fixture_file, "binary") }.should.raise(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 500" do
+ @server.should_receive(:stor).and_respond("500 Syntax error, command unrecognized.")
+ -> { @ftp.send(@method, @local_fixture_file, "binary") }.should.raise(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::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(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::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(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)
+ 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(Net::FTPPermError)
+ end
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
+ 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(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::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(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::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(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)
+ 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(Net::FTPPermError)
+ end
end
end
end
diff --git a/spec/ruby/library/net-ftp/shared/puttextfile.rb b/spec/ruby/library/net-ftp/shared/puttextfile.rb
index e2c0453352..3650cad230 100644
--- a/spec/ruby/library/net-ftp/shared/puttextfile.rb
+++ b/spec/ruby/library/net-ftp/shared/puttextfile.rb
@@ -1,128 +1,130 @@
-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
+ruby_version_is ""..."4.1" do
+ 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
- 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
+ after :each do
+ @ftp.quit rescue nil
+ @ftp.close
+ @server.stop
- 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"
- ]
+ rm_r @remote_tmp_file
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)
+ 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 "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 "sends the contents of the passed local_file, using \\r\\n as the newline separator" do
+ @ftp.send(@method, @local_fixture_file, "text")
- 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
+ remote_lines = File.binread(@remote_tmp_file)
+ local_lines = File.binread(@local_fixture_file)
- 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)
+ remote_lines.should_not == local_lines
+ remote_lines.should == local_lines.gsub("\n", "\r\n")
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)
+ guard -> { Net::FTP::VERSION < '0.3.6' } do
+ it "returns nil" do
+ @ftp.send(@method, @local_fixture_file, "text").should == nil
+ end
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)
+ 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
- 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)
+ 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
- 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)
+ 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(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(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(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(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(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(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(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(Net::FTPPermError)
+ end
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)
+ 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(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(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(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(Net::FTPPermError)
+ end
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..db3e587464 100644
--- a/spec/ruby/library/net-ftp/shared/pwd.rb
+++ b/spec/ruby/library/net-ftp/shared/pwd.rb
@@ -1,3 +1,5 @@
-describe :net_ftp_pwd, shared: true do
+ruby_version_is ""..."4.1" do
+ describe :net_ftp_pwd, shared: true do
+ end
end
diff --git a/spec/ruby/library/net-ftp/site_spec.rb b/spec/ruby/library/net-ftp/site_spec.rb
index c3e589a920..adc7dfafdf 100644
--- a/spec/ruby/library/net-ftp/site_spec.rb
+++ b/spec/ruby/library/net-ftp/site_spec.rb
@@ -1,53 +1,56 @@
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)
+ruby_version_is ""..."4.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 == 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
+ 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(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(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(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(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
index 0cf2e24477..dd84e5a449 100644
--- a/spec/ruby/library/net-ftp/size_spec.rb
+++ b/spec/ruby/library/net-ftp/size_spec.rb
@@ -1,48 +1,51 @@
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)
+ruby_version_is ""..."4.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(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(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(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(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..7689b4fb0c 100644
--- a/spec/ruby/library/net-ftp/spec_helper.rb
+++ b/spec/ruby/library/net-ftp/spec_helper.rb
@@ -1,5 +1,7 @@
-require "net/ftp"
+ruby_version_is ""..."4.1" do
+ require "net/ftp"
-if defined?(Net::FTP.default_passive)
- Net::FTP.default_passive = false
+ if defined?(Net::FTP.default_passive)
+ Net::FTP.default_passive = false
+ end
end
diff --git a/spec/ruby/library/net-ftp/status_spec.rb b/spec/ruby/library/net-ftp/status_spec.rb
index 9d9f86c381..ce29e215d4 100644
--- a/spec/ruby/library/net-ftp/status_spec.rb
+++ b/spec/ruby/library/net-ftp/status_spec.rb
@@ -1,67 +1,70 @@
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
+ruby_version_is ""..."4.1" do
+ require_relative 'spec_helper'
+ require_relative 'fixtures/server'
- @ftp = Net::FTP.new
- @ftp.connect(@server.hostname, @server.server_port)
- end
+ describe "Net::FTP#status" do
+ before :each do
+ @server = NetFTPSpecs::DummyFTP.new
+ @server.serve_once
- after :each do
- @ftp.quit rescue nil
- @ftp.close
- @server.stop
- end
+ @ftp = Net::FTP.new
+ @ftp.connect(@server.hostname, @server.server_port)
+ 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
+ after :each do
+ @ftp.quit rescue nil
+ @ftp.close
+ @server.stop
+ 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 "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 "returns the received information" do
- @ftp.status.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 "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 "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 213" do
- @server.should_receive(:stat).and_respond("213 File status.")
- -> { @ftp.status }.should_not raise_error
- 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
+ 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 "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
+ 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 500" do
+ @server.should_receive(:stat).and_respond("500 Syntax error, command unrecognized.")
+ -> { @ftp.status }.should.raise(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::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(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 502" do
+ @server.should_receive(:stat).and_respond("502 Command not implemented.")
+ -> { @ftp.status }.should.raise(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(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)
+ 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(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
index aa4c51f2e8..a2f81fc669 100644
--- a/spec/ruby/library/net-ftp/storbinary_spec.rb
+++ b/spec/ruby/library/net-ftp/storbinary_spec.rb
@@ -1,49 +1,52 @@
require_relative '../../spec_helper'
-require_relative 'spec_helper'
-require_relative 'fixtures/server'
+ruby_version_is ""..."4.1" do
-describe "Net::FTP#storbinary" do
- before :each do
- @server = NetFTPSpecs::DummyFTP.new
- @server.serve_once
+ require_relative 'spec_helper'
+ require_relative 'fixtures/server'
- @local_fixture_file = __dir__ + "/fixtures/putbinaryfile"
- @tmp_file = tmp("binaryfile", false)
+ describe "Net::FTP#storbinary" do
+ before :each do
+ @server = NetFTPSpecs::DummyFTP.new
+ @server.serve_once
- @ftp = Net::FTP.new
- @ftp.connect(@server.hostname, @server.server_port)
- end
+ @local_fixture_file = __dir__ + "/fixtures/putbinaryfile"
+ @tmp_file = tmp("binaryfile", false)
- after :each do
- @ftp.quit rescue nil
- @ftp.close
- @server.stop
+ @ftp = Net::FTP.new
+ @ftp.connect(@server.hostname, @server.server_port)
+ end
- rm_r @tmp_file
- end
+ after :each do
+ @ftp.quit rescue nil
+ @ftp.close
+ @server.stop
- 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
+ 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"
+ @ftp.storbinary("STOR binary", f, 4096) {}
+ @ftp.last_response.should == "200 OK, Data received. (STOR binary)\n"
+ end
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"
- ]
+ 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
index dc6830da7b..09340bafe9 100644
--- a/spec/ruby/library/net-ftp/storlines_spec.rb
+++ b/spec/ruby/library/net-ftp/storlines_spec.rb
@@ -1,44 +1,47 @@
require_relative '../../spec_helper'
-require_relative 'spec_helper'
-require_relative 'fixtures/server'
+ruby_version_is ""..."4.1" do
-describe "Net::FTP#storlines" do
- before :each do
- @server = NetFTPSpecs::DummyFTP.new
- @server.serve_once
+ require_relative 'spec_helper'
+ require_relative 'fixtures/server'
- @local_fixture_file = __dir__ + "/fixtures/puttextfile"
- @tmp_file = tmp("textfile", false)
+ describe "Net::FTP#storlines" do
+ before :each do
+ @server = NetFTPSpecs::DummyFTP.new
+ @server.serve_once
- @ftp = Net::FTP.new
- @ftp.connect(@server.hostname, @server.server_port)
- end
+ @local_fixture_file = __dir__ + "/fixtures/puttextfile"
+ @tmp_file = tmp("textfile", false)
- after :each do
- @ftp.quit rescue nil
- @ftp.close
- @server.stop
+ @ftp = Net::FTP.new
+ @ftp.connect(@server.hostname, @server.server_port)
+ end
- rm_r @tmp_file
- end
+ after :each do
+ @ftp.quit rescue nil
+ @ftp.close
+ @server.stop
- 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"
+ 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
- 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"
- ]
+ 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
index 2b7f0d2560..fa61776282 100644
--- a/spec/ruby/library/net-ftp/system_spec.rb
+++ b/spec/ruby/library/net-ftp/system_spec.rb
@@ -1,48 +1,51 @@
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)
+ruby_version_is ""..."4.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(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(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(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(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
index f2536fe697..4f74da7a70 100644
--- a/spec/ruby/library/net-ftp/voidcmd_spec.rb
+++ b/spec/ruby/library/net-ftp/voidcmd_spec.rb
@@ -1,54 +1,57 @@
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)
+ruby_version_is ""..."4.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
+ end
+
+ it "returns nil" do
+ @server.should_receive(:help).and_respond("2xx Does not raise.")
+ @ftp.voidcmd("HELP").should == 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(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(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(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(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(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
index 4279127ce3..761a0f9a3e 100644
--- a/spec/ruby/library/net-ftp/welcome_spec.rb
+++ b/spec/ruby/library/net-ftp/welcome_spec.rb
@@ -1,25 +1,28 @@
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
+ruby_version_is ""..."4.1" do
+ require_relative 'spec_helper'
+ require_relative 'fixtures/server'
- @ftp = Net::FTP.new
- @ftp.connect(@server.hostname, @server.server_port)
- end
+ describe "Net::FTP#welcome" do
+ before :each do
+ @server = NetFTPSpecs::DummyFTP.new
+ @server.serve_once
- after :each do
- @ftp.quit rescue nil
- @ftp.close
- @server.stop
- end
+ @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"
+ it "returns the server's welcome message" do
+ @ftp.welcome.should == 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/HTTPServerException_spec.rb b/spec/ruby/library/net-http/HTTPServerException_spec.rb
index 5e0a833fee..020d3cce85 100644
--- a/spec/ruby/library/net-http/HTTPServerException_spec.rb
+++ b/spec/ruby/library/net-http/HTTPServerException_spec.rb
@@ -3,10 +3,10 @@ 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/)
+ -> { eval("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/)
+ -> { eval("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
index a1a04fa00b..7753ce5e30 100644
--- a/spec/ruby/library/net-http/http/Proxy_spec.rb
+++ b/spec/ruby/library/net-http/http/Proxy_spec.rb
@@ -13,7 +13,7 @@ describe "Net::HTTP.Proxy" do
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_port.should.eql?(1234)
http_with_proxy.proxy_user.should == "rspec"
http_with_proxy.proxy_pass.should == "rocks"
end
@@ -22,14 +22,14 @@ 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
+ Net::HTTP.new("localhost", 3333).proxy?.should == 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
+ http_with_proxy.new("localhost", 3333).proxy?.should == 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
index c260274594..ba870b39d2 100644
--- a/spec/ruby/library/net-http/http/active_spec.rb
+++ b/spec/ruby/library/net-http/http/active_spec.rb
@@ -1,8 +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?
+ it "is an alias of Net::HTTP#started?" do
+ Net::HTTP.instance_method(:active?).should == Net::HTTP.instance_method(:started?)
+ end
end
diff --git a/spec/ruby/library/net-http/http/copy_spec.rb b/spec/ruby/library/net-http/http/copy_spec.rb
index fba96c0f11..1f3e25009f 100644
--- a/spec/ruby/library/net-http/http/copy_spec.rb
+++ b/spec/ruby/library/net-http/http/copy_spec.rb
@@ -15,7 +15,7 @@ describe "Net::HTTP#copy" do
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.should.is_a?(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
index 95b7316a0c..20407d0b12 100644
--- a/spec/ruby/library/net-http/http/default_port_spec.rb
+++ b/spec/ruby/library/net-http/http/default_port_spec.rb
@@ -3,6 +3,6 @@ require 'net/http'
describe "Net::HTTP.default_port" do
it "returns 80" do
- Net::HTTP.http_default_port.should eql(80)
+ 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
index d73aa5b375..09ddd74000 100644
--- a/spec/ruby/library/net-http/http/delete_spec.rb
+++ b/spec/ruby/library/net-http/http/delete_spec.rb
@@ -15,7 +15,7 @@ describe "Net::HTTP#delete" do
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.should.is_a?(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
index d4aa00dffe..0d466675f3 100644
--- a/spec/ruby/library/net-http/http/finish_spec.rb
+++ b/spec/ruby/library/net-http/http/finish_spec.rb
@@ -17,13 +17,13 @@ describe "Net::HTTP#finish" do
it "closes the tcp connection" do
@http.start
@http.finish
- @http.started?.should be_false
+ @http.started?.should == false
end
end
describe "when self has not been started yet" do
it "raises an IOError" do
- -> { @http.finish }.should raise_error(IOError)
+ -> { @http.finish }.should.raise(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
index 57c05ec64b..046443d73e 100644
--- a/spec/ruby/library/net-http/http/get2_spec.rb
+++ b/spec/ruby/library/net-http/http/get2_spec.rb
@@ -1,8 +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
+ it "is an alias of Net::HTTP#request_get" do
+ Net::HTTP.instance_method(:get2).should == Net::HTTP.instance_method(:request_get)
+ end
end
diff --git a/spec/ruby/library/net-http/http/get_spec.rb b/spec/ruby/library/net-http/http/get_spec.rb
index e64a61c52c..9be726dc3b 100644
--- a/spec/ruby/library/net-http/http/get_spec.rb
+++ b/spec/ruby/library/net-http/http/get_spec.rb
@@ -74,7 +74,7 @@ describe "Net::HTTP.get" do
socket, client_thread = start_threads
begin
client_thread.raise my_exception, "my exception"
- -> { client_thread.value }.should raise_error(my_exception)
+ -> { client_thread.value }.should.raise(my_exception)
ensure
socket.close
end
diff --git a/spec/ruby/library/net-http/http/head2_spec.rb b/spec/ruby/library/net-http/http/head2_spec.rb
index 84cfff33d7..19c0cede9f 100644
--- a/spec/ruby/library/net-http/http/head2_spec.rb
+++ b/spec/ruby/library/net-http/http/head2_spec.rb
@@ -1,8 +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
+ it "is an alias of Net::HTTP#request_head" do
+ Net::HTTP.instance_method(:head2).should == Net::HTTP.instance_method(:request_head)
+ end
end
diff --git a/spec/ruby/library/net-http/http/head_spec.rb b/spec/ruby/library/net-http/http/head_spec.rb
index 64621fa87b..4824d22534 100644
--- a/spec/ruby/library/net-http/http/head_spec.rb
+++ b/spec/ruby/library/net-http/http/head_spec.rb
@@ -16,10 +16,10 @@ describe "Net::HTTP#head" do
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
+ response.body.should == nil
end
it "returns a Net::HTTPResponse" do
- @http.head("/request").should be_kind_of(Net::HTTPResponse)
+ @http.head("/request").should.is_a?(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
index 3b17bcd0a5..82c88e58a8 100644
--- a/spec/ruby/library/net-http/http/http_default_port_spec.rb
+++ b/spec/ruby/library/net-http/http/http_default_port_spec.rb
@@ -3,6 +3,6 @@ require 'net/http'
describe "Net::HTTP.http_default_port" do
it "returns 80" do
- Net::HTTP.http_default_port.should eql(80)
+ 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
index 8c24e1d97c..24b9c3b462 100644
--- a/spec/ruby/library/net-http/http/https_default_port_spec.rb
+++ b/spec/ruby/library/net-http/http/https_default_port_spec.rb
@@ -3,6 +3,6 @@ require 'net/http'
describe "Net::HTTP.https_default_port" do
it "returns 443" do
- Net::HTTP.https_default_port.should eql(443)
+ 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
index 78aa01e1aa..907314cb25 100644
--- a/spec/ruby/library/net-http/http/initialize_spec.rb
+++ b/spec/ruby/library/net-http/http/initialize_spec.rb
@@ -3,7 +3,7 @@ require 'net/http'
describe "Net::HTTP#initialize" do
it "is private" do
- Net::HTTP.should have_private_instance_method(:initialize)
+ Net::HTTP.private_instance_methods(false).should.include?(:initialize)
end
describe "when passed address" do
@@ -17,11 +17,11 @@ describe "Net::HTTP#initialize" do
end
it "sets the new Net::HTTP instance's port to the default HTTP port" do
- @net.port.should eql(Net::HTTP.default_port)
+ @net.port.should.eql?(Net::HTTP.default_port)
end
it "does not start the new Net::HTTP instance" do
- @net.started?.should be_false
+ @net.started?.should == false
end
end
@@ -36,11 +36,11 @@ describe "Net::HTTP#initialize" do
end
it "sets the new Net::HTTP instance's port to the passed port" do
- @net.port.should eql(3333)
+ @net.port.should.eql?(3333)
end
it "does not start the new Net::HTTP instance" do
- @net.started?.should be_false
+ @net.started?.should == 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
index b8f650809e..fd4e6116c7 100644
--- a/spec/ruby/library/net-http/http/inspect_spec.rb
+++ b/spec/ruby/library/net-http/http/inspect_spec.rb
@@ -15,7 +15,7 @@ describe "Net::HTTP#inspect" do
end
it "returns a String representation of self" do
- @http.inspect.should be_kind_of(String)
+ @http.inspect.should.is_a?(String)
@http.inspect.should == "#<Net::HTTP localhost:#{@port} open=false>"
@http.start
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
index bdb343f9e0..f4910ef1e4 100644
--- 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
@@ -1,7 +1,8 @@
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?
+ it "is an alias of Net::HTTP.version_1_1?" do
+ Net::HTTP.method(:is_version_1_1?).should == Net::HTTP.method(:version_1_1?)
+ end
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
index 555bb205dd..555724babe 100644
--- 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
@@ -1,7 +1,8 @@
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?
+ it "is an alias of Net::HTTP.version_1_2?" do
+ Net::HTTP.method(:is_version_1_2?).should == Net::HTTP.method(:version_1_2?)
+ end
end
diff --git a/spec/ruby/library/net-http/http/lock_spec.rb b/spec/ruby/library/net-http/http/lock_spec.rb
index aa1f944196..12df138ad0 100644
--- a/spec/ruby/library/net-http/http/lock_spec.rb
+++ b/spec/ruby/library/net-http/http/lock_spec.rb
@@ -15,7 +15,7 @@ describe "Net::HTTP#lock" do
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.should.is_a?(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
index f8009f9059..b1a5055982 100644
--- a/spec/ruby/library/net-http/http/mkcol_spec.rb
+++ b/spec/ruby/library/net-http/http/mkcol_spec.rb
@@ -15,7 +15,7 @@ describe "Net::HTTP#mkcol" do
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.should.is_a?(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
index ae43016a2c..a57c2a0f49 100644
--- a/spec/ruby/library/net-http/http/move_spec.rb
+++ b/spec/ruby/library/net-http/http/move_spec.rb
@@ -20,6 +20,6 @@ describe "Net::HTTP#head" do
end
it "returns a Net::HTTPResponse" do
- @http.move("/request").should be_kind_of(Net::HTTPResponse)
+ @http.move("/request").should.is_a?(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
index 1ec6bbd0c0..8feb3d1351 100644
--- a/spec/ruby/library/net-http/http/new_spec.rb
+++ b/spec/ruby/library/net-http/http/new_spec.rb
@@ -8,8 +8,8 @@ describe "Net::HTTP.new" do
end
it "returns a Net::HTTP instance" do
- @http.proxy?.should be_false
- @http.instance_of?(Net::HTTP).should be_true
+ @http.proxy?.should == false
+ @http.instance_of?(Net::HTTP).should == true
end
it "sets the new Net::HTTP instance's address to the passed address" do
@@ -17,11 +17,11 @@ describe "Net::HTTP.new" do
end
it "sets the new Net::HTTP instance's port to the default HTTP port" do
- @http.port.should eql(Net::HTTP.default_port)
+ @http.port.should.eql?(Net::HTTP.default_port)
end
it "does not start the new Net::HTTP instance" do
- @http.started?.should be_false
+ @http.started?.should == false
end
end
@@ -31,8 +31,8 @@ describe "Net::HTTP.new" do
end
it "returns a Net::HTTP instance" do
- @http.proxy?.should be_false
- @http.instance_of?(Net::HTTP).should be_true
+ @http.proxy?.should == false
+ @http.instance_of?(Net::HTTP).should == true
end
it "sets the new Net::HTTP instance's address to the passed address" do
@@ -40,44 +40,44 @@ describe "Net::HTTP.new" do
end
it "sets the new Net::HTTP instance's port to the passed port" do
- @http.port.should eql(3333)
+ @http.port.should.eql?(3333)
end
it "does not start the new Net::HTTP instance" do
- @http.started?.should be_false
+ @http.started?.should == 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)
+ http.proxy?.should == true
+ http.instance_of?(Net::HTTP).should == true
+ http.should.is_a?(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.proxy_port.should.eql?(80)
+ http.proxy_user.should == nil
+ http.proxy_pass.should == 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.proxy_port.should.eql?(1234)
+ http.proxy_user.should == nil
+ http.proxy_pass.should == nil
http = Net::HTTP.new("localhost", 3333, "localhost", 1234, "rubyspec")
http.proxy_address.should == "localhost"
- http.proxy_port.should eql(1234)
+ http.proxy_port.should.eql?(1234)
http.proxy_user.should == "rubyspec"
- http.proxy_pass.should be_nil
+ http.proxy_pass.should == nil
http = Net::HTTP.new("localhost", 3333, "localhost", 1234, "rubyspec", "rocks")
http.proxy_address.should == "localhost"
- http.proxy_port.should eql(1234)
+ http.proxy_port.should.eql?(1234)
http.proxy_user.should == "rubyspec"
http.proxy_pass.should == "rocks"
end
diff --git a/spec/ruby/library/net-http/http/newobj_spec.rb b/spec/ruby/library/net-http/http/newobj_spec.rb
index e19b30fca9..d398fb7d9a 100644
--- a/spec/ruby/library/net-http/http/newobj_spec.rb
+++ b/spec/ruby/library/net-http/http/newobj_spec.rb
@@ -8,7 +8,7 @@ describe "Net::HTTP.newobj" do
describe "when passed address" do
it "returns a new Net::HTTP instance" do
- @net.should be_kind_of(Net::HTTP)
+ @net.should.is_a?(Net::HTTP)
end
it "sets the new Net::HTTP instance's address to the passed address" do
@@ -16,11 +16,11 @@ describe "Net::HTTP.newobj" do
end
it "sets the new Net::HTTP instance's port to the default HTTP port" do
- @net.port.should eql(Net::HTTP.default_port)
+ @net.port.should.eql?(Net::HTTP.default_port)
end
it "does not start the new Net::HTTP instance" do
- @net.started?.should be_false
+ @net.started?.should == false
end
end
@@ -30,7 +30,7 @@ describe "Net::HTTP.newobj" do
end
it "returns a new Net::HTTP instance" do
- @net.should be_kind_of(Net::HTTP)
+ @net.should.is_a?(Net::HTTP)
end
it "sets the new Net::HTTP instance's address to the passed address" do
@@ -38,11 +38,11 @@ describe "Net::HTTP.newobj" do
end
it "sets the new Net::HTTP instance's port to the passed port" do
- @net.port.should eql(3333)
+ @net.port.should.eql?(3333)
end
it "does not start the new Net::HTTP instance" do
- @net.started?.should be_false
+ @net.started?.should == 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
index 0d93752271..d00f844b38 100644
--- a/spec/ruby/library/net-http/http/open_timeout_spec.rb
+++ b/spec/ruby/library/net-http/http/open_timeout_spec.rb
@@ -4,9 +4,9 @@ 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.should.eql?(60)
net.open_timeout = 10
- net.open_timeout.should eql(10)
+ net.open_timeout.should.eql?(10)
end
end
@@ -14,11 +14,11 @@ 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)
+ 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)
+ (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
index 3d9887a557..3b90573cfa 100644
--- a/spec/ruby/library/net-http/http/options_spec.rb
+++ b/spec/ruby/library/net-http/http/options_spec.rb
@@ -20,6 +20,6 @@ describe "Net::HTTP#options" do
end
it "returns a Net::HTTPResponse" do
- @http.options("/request").should be_kind_of(Net::HTTPResponse)
+ @http.options("/request").should.is_a?(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
index 0984d5e6ce..edb689f9ca 100644
--- a/spec/ruby/library/net-http/http/port_spec.rb
+++ b/spec/ruby/library/net-http/http/port_spec.rb
@@ -4,6 +4,6 @@ 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)
+ 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
index abc998709f..68c2a9ea06 100644
--- a/spec/ruby/library/net-http/http/post2_spec.rb
+++ b/spec/ruby/library/net-http/http/post2_spec.rb
@@ -1,8 +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
+ it "is an alias of Net::HTTP#request_post" do
+ Net::HTTP.instance_method(:post2).should == Net::HTTP.instance_method(:request_post)
+ end
end
diff --git a/spec/ruby/library/net-http/http/post_spec.rb b/spec/ruby/library/net-http/http/post_spec.rb
index cebbee4ff3..f294411197 100644
--- a/spec/ruby/library/net-http/http/post_spec.rb
+++ b/spec/ruby/library/net-http/http/post_spec.rb
@@ -22,13 +22,13 @@ describe "Net::HTTP.post" do
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)
+ response.should.is_a?(Net::HTTPResponse)
end
- ruby_version_is ""..."3.5" do
+ ruby_version_is ""..."4.0" do
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("{}"))
+ response.body.should.include?({ "Content-Type" => "application/x-www-form-urlencoded" }.inspect.delete("{}"))
end
end
@@ -57,7 +57,7 @@ describe "Net::HTTP#post" do
end
it "returns a Net::HTTPResponse" do
- @http.post("/request", "test=test").should be_kind_of(Net::HTTPResponse)
+ @http.post("/request", "test=test").should.is_a?(Net::HTTPResponse)
end
describe "when passed a block" do
@@ -70,7 +70,7 @@ describe "Net::HTTP#post" do
end
it "returns a Net::HTTPResponse" do
- @http.post("/request", "test=test") {}.should be_kind_of(Net::HTTPResponse)
+ @http.post("/request", "test=test") {}.should.is_a?(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
index f3742d1b1a..6a1be0392a 100644
--- a/spec/ruby/library/net-http/http/propfind_spec.rb
+++ b/spec/ruby/library/net-http/http/propfind_spec.rb
@@ -19,6 +19,6 @@ describe "Net::HTTP#propfind" do
end
it "returns a Net::HTTPResponse" do
- @http.propfind("/request", "test=test").should be_kind_of(Net::HTTPResponse)
+ @http.propfind("/request", "test=test").should.is_a?(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
index 0163d24d46..074dfafaef 100644
--- a/spec/ruby/library/net-http/http/proppatch_spec.rb
+++ b/spec/ruby/library/net-http/http/proppatch_spec.rb
@@ -19,6 +19,6 @@ describe "Net::HTTP#proppatch" do
end
it "returns a Net::HTTPResponse" do
- @http.proppatch("/request", "test=test").should be_kind_of(Net::HTTPResponse)
+ @http.proppatch("/request", "test=test").should.is_a?(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
index 5b5efb7ac0..ba040336ad 100644
--- a/spec/ruby/library/net-http/http/proxy_address_spec.rb
+++ b/spec/ruby/library/net-http/http/proxy_address_spec.rb
@@ -4,7 +4,7 @@ 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
+ Net::HTTP.proxy_address.should == nil
end
end
@@ -18,7 +18,7 @@ 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
+ Net::HTTP.new("localhost", 3333).proxy_address.should == nil
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
index 00975aef4e..eda027c893 100644
--- a/spec/ruby/library/net-http/http/proxy_class_spec.rb
+++ b/spec/ruby/library/net-http/http/proxy_class_spec.rb
@@ -3,7 +3,7 @@ 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
+ Net::HTTP.proxy_class?.should == false
+ Net::HTTP.Proxy("localhost").proxy_class?.should == 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
index 4e393a53ff..ad02d896c0 100644
--- a/spec/ruby/library/net-http/http/proxy_pass_spec.rb
+++ b/spec/ruby/library/net-http/http/proxy_pass_spec.rb
@@ -4,13 +4,13 @@ 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
+ Net::HTTP.proxy_pass.should == 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
+ Net::HTTP.Proxy("localhost").proxy_pass.should == nil
end
it "returns the password for self's proxy connection" do
@@ -22,13 +22,13 @@ 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
+ Net::HTTP.new("localhost", 3333).proxy_pass.should == 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
+ Net::HTTP.Proxy("localhost").new("localhost", 3333).proxy_pass.should == nil
end
it "returns the password for self's proxy connection" do
diff --git a/spec/ruby/library/net-http/http/proxy_port_spec.rb b/spec/ruby/library/net-http/http/proxy_port_spec.rb
index d7d37f3927..21c1e4180e 100644
--- a/spec/ruby/library/net-http/http/proxy_port_spec.rb
+++ b/spec/ruby/library/net-http/http/proxy_port_spec.rb
@@ -4,17 +4,17 @@ 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
+ Net::HTTP.proxy_port.should == 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)
+ 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)
+ Net::HTTP.Proxy("localhost", 1234, "rspec", "rocks").proxy_port.should.eql?(1234)
end
end
end
@@ -22,18 +22,18 @@ 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
+ Net::HTTP.new("localhost", 3333).proxy_port.should == 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)
+ 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)
+ 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
index ef7654425d..492ea2e8ee 100644
--- a/spec/ruby/library/net-http/http/proxy_user_spec.rb
+++ b/spec/ruby/library/net-http/http/proxy_user_spec.rb
@@ -4,13 +4,13 @@ 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
+ Net::HTTP.proxy_user.should == 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
+ Net::HTTP.Proxy("localhost").proxy_user.should == nil
end
it "returns the username for self's proxy connection" do
@@ -22,13 +22,13 @@ 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
+ Net::HTTP.new("localhost", 3333).proxy_user.should == 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
+ Net::HTTP.Proxy("localhost").new("localhost", 3333).proxy_user.should == nil
end
it "returns the username for self's proxy connection" do
diff --git a/spec/ruby/library/net-http/http/put2_spec.rb b/spec/ruby/library/net-http/http/put2_spec.rb
index 7b03a39d0b..237df67e82 100644
--- a/spec/ruby/library/net-http/http/put2_spec.rb
+++ b/spec/ruby/library/net-http/http/put2_spec.rb
@@ -1,8 +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
+ it "is an alias of Net::HTTP#request_put" do
+ Net::HTTP.instance_method(:put2).should == Net::HTTP.instance_method(:request_put)
+ end
end
diff --git a/spec/ruby/library/net-http/http/put_spec.rb b/spec/ruby/library/net-http/http/put_spec.rb
index 75f3c243d4..7ef9219f63 100644
--- a/spec/ruby/library/net-http/http/put_spec.rb
+++ b/spec/ruby/library/net-http/http/put_spec.rb
@@ -19,6 +19,6 @@ describe "Net::HTTP#put" do
end
it "returns a Net::HTTPResponse" do
- @http.put("/request", "test=test").should be_kind_of(Net::HTTPResponse)
+ @http.put("/request", "test=test").should.is_a?(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
index 7a0d2f1d72..81e71337bb 100644
--- a/spec/ruby/library/net-http/http/read_timeout_spec.rb
+++ b/spec/ruby/library/net-http/http/read_timeout_spec.rb
@@ -4,9 +4,9 @@ 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.should.eql?(60)
net.read_timeout = 10
- net.read_timeout.should eql(10)
+ net.read_timeout.should.eql?(10)
end
end
@@ -14,11 +14,11 @@ 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)
+ 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)
+ (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
index 98025a14a1..1737e62439 100644
--- a/spec/ruby/library/net-http/http/request_get_spec.rb
+++ b/spec/ruby/library/net-http/http/request_get_spec.rb
@@ -1,8 +1,45 @@
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
+ 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 no block" do
+ it "sends a GET request to the passed path and returns the response" do
+ response = @http.request_get("/request")
+ response.body.should == "Request type: GET"
+ end
+
+ it "returns a Net::HTTPResponse object" do
+ response = @http.request_get("/request")
+ response.should.is_a?(Net::HTTPResponse)
+ end
+ end
+
+ describe "when passed a block" do
+ it "sends a GET request to the passed path and returns the response" do
+ response = @http.request_get("/request") {}
+ response.body.should == "Request type: GET"
+ end
+
+ it "yields the response to the passed block" do
+ @http.request_get("/request") do |response|
+ response.body.should == "Request type: GET"
+ end
+ end
+
+ it "returns a Net::HTTPResponse object" do
+ response = @http.request_get("/request") {}
+ response.should.is_a?(Net::HTTPResponse)
+ end
+ end
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
index 8f514d4eee..7c46ebfc53 100644
--- a/spec/ruby/library/net-http/http/request_head_spec.rb
+++ b/spec/ruby/library/net-http/http/request_head_spec.rb
@@ -1,8 +1,45 @@
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
+ 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 no block" do
+ it "sends a head request to the passed path and returns the response" do
+ response = @http.request_head("/request")
+ response.body.should == nil
+ end
+
+ it "returns a Net::HTTPResponse object" do
+ response = @http.request_head("/request")
+ response.should.is_a?(Net::HTTPResponse)
+ end
+ end
+
+ describe "when passed a block" do
+ it "sends a head request to the passed path and returns the response" do
+ response = @http.request_head("/request") {}
+ response.body.should == nil
+ end
+
+ it "yields the response to the passed block" do
+ @http.request_head("/request") do |response|
+ response.body.should == nil
+ end
+ end
+
+ it "returns a Net::HTTPResponse object" do
+ response = @http.request_head("/request") {}
+ response.should.is_a?(Net::HTTPResponse)
+ end
+ end
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
index 719bd5a7ee..8cfdd3469e 100644
--- a/spec/ruby/library/net-http/http/request_post_spec.rb
+++ b/spec/ruby/library/net-http/http/request_post_spec.rb
@@ -1,8 +1,45 @@
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
+ 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 no block" do
+ it "sends a post request to the passed path and returns the response" do
+ response = @http.request_post("/request", "test=test")
+ response.body.should == "Request type: POST"
+ end
+
+ it "returns a Net::HTTPResponse object" do
+ response = @http.request_post("/request", "test=test")
+ response.should.is_a?(Net::HTTPResponse)
+ end
+ end
+
+ describe "when passed a block" do
+ it "sends a post request to the passed path and returns the response" do
+ response = @http.request_post("/request", "test=test") {}
+ response.body.should == "Request type: POST"
+ end
+
+ it "yields the response to the passed block" do
+ @http.request_post("/request", "test=test") do |response|
+ response.body.should == "Request type: POST"
+ end
+ end
+
+ it "returns a Net::HTTPResponse object" do
+ response = @http.request_post("/request", "test=test") {}
+ response.should.is_a?(Net::HTTPResponse)
+ end
+ end
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
index 9fcf3a98d6..b7388a21c8 100644
--- a/spec/ruby/library/net-http/http/request_put_spec.rb
+++ b/spec/ruby/library/net-http/http/request_put_spec.rb
@@ -1,8 +1,45 @@
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
+ 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 no block" do
+ it "sends a put request to the passed path and returns the response" do
+ response = @http.request_put("/request", "test=test")
+ response.body.should == "Request type: PUT"
+ end
+
+ it "returns a Net::HTTPResponse object" do
+ response = @http.request_put("/request", "test=test")
+ response.should.is_a?(Net::HTTPResponse)
+ end
+ end
+
+ describe "when passed a block" do
+ it "sends a put request to the passed path and returns the response" do
+ response = @http.request_put("/request", "test=test") {}
+ response.body.should == "Request type: PUT"
+ end
+
+ it "yields the response to the passed block" do
+ @http.request_put("/request", "test=test") do |response|
+ response.body.should == "Request type: PUT"
+ end
+ end
+
+ it "returns a Net::HTTPResponse object" do
+ response = @http.request_put("/request", "test=test") {}
+ response.should.is_a?(Net::HTTPResponse)
+ end
+ end
end
diff --git a/spec/ruby/library/net-http/http/request_spec.rb b/spec/ruby/library/net-http/http/request_spec.rb
index 356e605b3b..e05ee96b55 100644
--- a/spec/ruby/library/net-http/http/request_spec.rb
+++ b/spec/ruby/library/net-http/http/request_spec.rb
@@ -19,7 +19,7 @@ describe "Net::HTTP#request" do
response.body.should == "Request type: GET"
response = @http.request(Net::HTTP::Head.new("/request"), "test=test")
- response.body.should be_nil
+ response.body.should == nil
response = @http.request(Net::HTTP::Post.new("/request"), "test=test")
response.body.should == "Request type: POST"
@@ -38,7 +38,7 @@ describe "Net::HTTP#request" do
# TODO: Does not work?
#response = @http.request(Net::HTTP::Options.new("/request"), "test=test")
- #response.body.should be_nil
+ #response.body.should == nil
response = @http.request(Net::HTTP::Propfind.new("/request"), "test=test")
response.body.should == "Request type: PROPFIND"
@@ -66,7 +66,7 @@ describe "Net::HTTP#request" do
response.body.should == "test=test"
response = @http.request(Net::HTTP::Head.new("/request/body"), "test=test")
- response.body.should be_nil
+ response.body.should == nil
response = @http.request(Net::HTTP::Post.new("/request/body"), "test=test")
response.body.should == "test=test"
@@ -85,7 +85,7 @@ describe "Net::HTTP#request" do
# TODO: Does not work?
#response = @http.request(Net::HTTP::Options.new("/request/body"), "test=test")
- #response.body.should be_nil
+ #response.body.should == nil
response = @http.request(Net::HTTP::Propfind.new("/request/body"), "test=test")
response.body.should == "test=test"
diff --git a/spec/ruby/library/net-http/http/request_types_spec.rb b/spec/ruby/library/net-http/http/request_types_spec.rb
index 53aef1ee58..0adc625979 100644
--- a/spec/ruby/library/net-http/http/request_types_spec.rb
+++ b/spec/ruby/library/net-http/http/request_types_spec.rb
@@ -11,11 +11,11 @@ describe "Net::HTTP::Get" do
end
it "has no Request Body" do
- Net::HTTP::Get::REQUEST_HAS_BODY.should be_false
+ Net::HTTP::Get::REQUEST_HAS_BODY.should == false
end
it "has a Response Body" do
- Net::HTTP::Get::RESPONSE_HAS_BODY.should be_true
+ Net::HTTP::Get::RESPONSE_HAS_BODY.should == true
end
end
@@ -29,11 +29,11 @@ describe "Net::HTTP::Head" do
end
it "has no Request Body" do
- Net::HTTP::Head::REQUEST_HAS_BODY.should be_false
+ Net::HTTP::Head::REQUEST_HAS_BODY.should == false
end
it "has no Response Body" do
- Net::HTTP::Head::RESPONSE_HAS_BODY.should be_false
+ Net::HTTP::Head::RESPONSE_HAS_BODY.should == false
end
end
@@ -47,11 +47,11 @@ describe "Net::HTTP::Post" do
end
it "has a Request Body" do
- Net::HTTP::Post::REQUEST_HAS_BODY.should be_true
+ Net::HTTP::Post::REQUEST_HAS_BODY.should == true
end
it "has a Response Body" do
- Net::HTTP::Post::RESPONSE_HAS_BODY.should be_true
+ Net::HTTP::Post::RESPONSE_HAS_BODY.should == true
end
end
@@ -65,11 +65,11 @@ describe "Net::HTTP::Put" do
end
it "has a Request Body" do
- Net::HTTP::Put::REQUEST_HAS_BODY.should be_true
+ Net::HTTP::Put::REQUEST_HAS_BODY.should == true
end
it "has a Response Body" do
- Net::HTTP::Put::RESPONSE_HAS_BODY.should be_true
+ Net::HTTP::Put::RESPONSE_HAS_BODY.should == true
end
end
@@ -83,11 +83,11 @@ describe "Net::HTTP::Delete" do
end
it "has no Request Body" do
- Net::HTTP::Delete::REQUEST_HAS_BODY.should be_false
+ Net::HTTP::Delete::REQUEST_HAS_BODY.should == false
end
it "has a Response Body" do
- Net::HTTP::Delete::RESPONSE_HAS_BODY.should be_true
+ Net::HTTP::Delete::RESPONSE_HAS_BODY.should == true
end
end
@@ -101,11 +101,11 @@ describe "Net::HTTP::Options" do
end
it "has no Request Body" do
- Net::HTTP::Options::REQUEST_HAS_BODY.should be_false
+ Net::HTTP::Options::REQUEST_HAS_BODY.should == false
end
it "has no Response Body" do
- Net::HTTP::Options::RESPONSE_HAS_BODY.should be_true
+ Net::HTTP::Options::RESPONSE_HAS_BODY.should == true
end
end
@@ -119,11 +119,11 @@ describe "Net::HTTP::Trace" do
end
it "has no Request Body" do
- Net::HTTP::Trace::REQUEST_HAS_BODY.should be_false
+ Net::HTTP::Trace::REQUEST_HAS_BODY.should == false
end
it "has a Response Body" do
- Net::HTTP::Trace::RESPONSE_HAS_BODY.should be_true
+ Net::HTTP::Trace::RESPONSE_HAS_BODY.should == true
end
end
@@ -137,11 +137,11 @@ describe "Net::HTTP::Propfind" do
end
it "has a Request Body" do
- Net::HTTP::Propfind::REQUEST_HAS_BODY.should be_true
+ Net::HTTP::Propfind::REQUEST_HAS_BODY.should == true
end
it "has a Response Body" do
- Net::HTTP::Propfind::RESPONSE_HAS_BODY.should be_true
+ Net::HTTP::Propfind::RESPONSE_HAS_BODY.should == true
end
end
@@ -155,11 +155,11 @@ describe "Net::HTTP::Proppatch" do
end
it "has a Request Body" do
- Net::HTTP::Proppatch::REQUEST_HAS_BODY.should be_true
+ Net::HTTP::Proppatch::REQUEST_HAS_BODY.should == true
end
it "has a Response Body" do
- Net::HTTP::Proppatch::RESPONSE_HAS_BODY.should be_true
+ Net::HTTP::Proppatch::RESPONSE_HAS_BODY.should == true
end
end
@@ -173,11 +173,11 @@ describe "Net::HTTP::Mkcol" do
end
it "has a Request Body" do
- Net::HTTP::Mkcol::REQUEST_HAS_BODY.should be_true
+ Net::HTTP::Mkcol::REQUEST_HAS_BODY.should == true
end
it "has a Response Body" do
- Net::HTTP::Mkcol::RESPONSE_HAS_BODY.should be_true
+ Net::HTTP::Mkcol::RESPONSE_HAS_BODY.should == true
end
end
@@ -191,11 +191,11 @@ describe "Net::HTTP::Copy" do
end
it "has no Request Body" do
- Net::HTTP::Copy::REQUEST_HAS_BODY.should be_false
+ Net::HTTP::Copy::REQUEST_HAS_BODY.should == false
end
it "has a Response Body" do
- Net::HTTP::Copy::RESPONSE_HAS_BODY.should be_true
+ Net::HTTP::Copy::RESPONSE_HAS_BODY.should == true
end
end
@@ -209,11 +209,11 @@ describe "Net::HTTP::Move" do
end
it "has no Request Body" do
- Net::HTTP::Move::REQUEST_HAS_BODY.should be_false
+ Net::HTTP::Move::REQUEST_HAS_BODY.should == false
end
it "has a Response Body" do
- Net::HTTP::Move::RESPONSE_HAS_BODY.should be_true
+ Net::HTTP::Move::RESPONSE_HAS_BODY.should == true
end
end
@@ -227,11 +227,11 @@ describe "Net::HTTP::Lock" do
end
it "has a Request Body" do
- Net::HTTP::Lock::REQUEST_HAS_BODY.should be_true
+ Net::HTTP::Lock::REQUEST_HAS_BODY.should == true
end
it "has a Response Body" do
- Net::HTTP::Lock::RESPONSE_HAS_BODY.should be_true
+ Net::HTTP::Lock::RESPONSE_HAS_BODY.should == true
end
end
@@ -245,10 +245,10 @@ describe "Net::HTTP::Unlock" do
end
it "has a Request Body" do
- Net::HTTP::Unlock::REQUEST_HAS_BODY.should be_true
+ Net::HTTP::Unlock::REQUEST_HAS_BODY.should == true
end
it "has a Response Body" do
- Net::HTTP::Unlock::RESPONSE_HAS_BODY.should be_true
+ Net::HTTP::Unlock::RESPONSE_HAS_BODY.should == 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
index af35c068ce..e2dfc505b6 100644
--- a/spec/ruby/library/net-http/http/send_request_spec.rb
+++ b/spec/ruby/library/net-http/http/send_request_spec.rb
@@ -24,7 +24,7 @@ describe "Net::HTTP#send_request" do
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
+ response.body.should == nil
(@methods - %w[POST PUT]).each do |method|
response = @http.send_request(method, "/request")
@@ -36,7 +36,7 @@ describe "Net::HTTP#send_request" do
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
+ response.body.should == nil
@methods.each do |method|
response = @http.send_request(method, "/request/body", "test=test")
@@ -50,11 +50,11 @@ describe "Net::HTTP#send_request" do
referer = 'https://www.ruby-lang.org/'.freeze
response = @http.send_request("HEAD", "/request/header", "test=test", "referer" => referer)
- response.body.should be_nil
+ response.body.should == nil
@methods.each do |method|
response = @http.send_request(method, "/request/header", "test=test", "referer" => referer)
- response.body.should include({ "Referer" => referer }.inspect.delete("{}"))
+ response.body.should.include?({ "Referer" => referer }.inspect.delete("{}"))
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
index 5ceecb39fb..491ac38b5d 100644
--- a/spec/ruby/library/net-http/http/set_debug_output_spec.rb
+++ b/spec/ruby/library/net-http/http/set_debug_output_spec.rb
@@ -19,7 +19,7 @@ describe "Net::HTTP#set_debug_output when passed io" do
@http.set_debug_output(io)
@http.start
- io.string.should_not be_empty
+ io.string.should_not.empty?
size = io.string.size
@http.get("/")
diff --git a/spec/ruby/library/net-http/http/shared/request_get.rb b/spec/ruby/library/net-http/http/shared/request_get.rb
deleted file mode 100644
index d25f32049b..0000000000
--- a/spec/ruby/library/net-http/http/shared/request_get.rb
+++ /dev/null
@@ -1,41 +0,0 @@
-describe :net_http_request_get, shared: true 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 no block" do
- it "sends a GET request to the passed path and returns the response" do
- response = @http.send(@method, "/request")
- response.body.should == "Request type: GET"
- end
-
- it "returns a Net::HTTPResponse object" do
- response = @http.send(@method, "/request")
- response.should be_kind_of(Net::HTTPResponse)
- end
- end
-
- describe "when passed a block" do
- it "sends a GET request to the passed path and returns the response" do
- response = @http.send(@method, "/request") {}
- response.body.should == "Request type: GET"
- end
-
- it "yields the response to the passed block" do
- @http.send(@method, "/request") do |response|
- response.body.should == "Request type: GET"
- end
- end
-
- it "returns a Net::HTTPResponse object" do
- response = @http.send(@method, "/request") {}
- response.should be_kind_of(Net::HTTPResponse)
- end
- end
-end
diff --git a/spec/ruby/library/net-http/http/shared/request_head.rb b/spec/ruby/library/net-http/http/shared/request_head.rb
deleted file mode 100644
index 78b555884b..0000000000
--- a/spec/ruby/library/net-http/http/shared/request_head.rb
+++ /dev/null
@@ -1,41 +0,0 @@
-describe :net_http_request_head, shared: true 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 no block" do
- it "sends a head request to the passed path and returns the response" do
- response = @http.send(@method, "/request")
- response.body.should be_nil
- end
-
- it "returns a Net::HTTPResponse object" do
- response = @http.send(@method, "/request")
- response.should be_kind_of(Net::HTTPResponse)
- end
- end
-
- describe "when passed a block" do
- it "sends a head request to the passed path and returns the response" do
- response = @http.send(@method, "/request") {}
- response.body.should be_nil
- end
-
- it "yields the response to the passed block" do
- @http.send(@method, "/request") do |response|
- response.body.should be_nil
- end
- end
-
- it "returns a Net::HTTPResponse object" do
- response = @http.send(@method, "/request") {}
- response.should be_kind_of(Net::HTTPResponse)
- end
- end
-end
diff --git a/spec/ruby/library/net-http/http/shared/request_post.rb b/spec/ruby/library/net-http/http/shared/request_post.rb
deleted file mode 100644
index e832411c48..0000000000
--- a/spec/ruby/library/net-http/http/shared/request_post.rb
+++ /dev/null
@@ -1,41 +0,0 @@
-describe :net_http_request_post, shared: true 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 no block" do
- it "sends a post request to the passed path and returns the response" do
- response = @http.send(@method, "/request", "test=test")
- response.body.should == "Request type: POST"
- end
-
- it "returns a Net::HTTPResponse object" do
- response = @http.send(@method, "/request", "test=test")
- response.should be_kind_of(Net::HTTPResponse)
- end
- end
-
- describe "when passed a block" do
- it "sends a post request to the passed path and returns the response" do
- response = @http.send(@method, "/request", "test=test") {}
- response.body.should == "Request type: POST"
- end
-
- it "yields the response to the passed block" do
- @http.send(@method, "/request", "test=test") do |response|
- response.body.should == "Request type: POST"
- end
- end
-
- it "returns a Net::HTTPResponse object" do
- response = @http.send(@method, "/request", "test=test") {}
- response.should be_kind_of(Net::HTTPResponse)
- end
- end
-end
diff --git a/spec/ruby/library/net-http/http/shared/request_put.rb b/spec/ruby/library/net-http/http/shared/request_put.rb
deleted file mode 100644
index 3b902f4957..0000000000
--- a/spec/ruby/library/net-http/http/shared/request_put.rb
+++ /dev/null
@@ -1,41 +0,0 @@
-describe :net_http_request_put, shared: true 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 no block" do
- it "sends a put request to the passed path and returns the response" do
- response = @http.send(@method, "/request", "test=test")
- response.body.should == "Request type: PUT"
- end
-
- it "returns a Net::HTTPResponse object" do
- response = @http.send(@method, "/request", "test=test")
- response.should be_kind_of(Net::HTTPResponse)
- end
- end
-
- describe "when passed a block" do
- it "sends a put request to the passed path and returns the response" do
- response = @http.send(@method, "/request", "test=test") {}
- response.body.should == "Request type: PUT"
- end
-
- it "yields the response to the passed block" do
- @http.send(@method, "/request", "test=test") do |response|
- response.body.should == "Request type: PUT"
- end
- end
-
- it "returns a Net::HTTPResponse object" do
- response = @http.send(@method, "/request", "test=test") {}
- response.should be_kind_of(Net::HTTPResponse)
- end
- end
-end
diff --git a/spec/ruby/library/net-http/http/shared/started.rb b/spec/ruby/library/net-http/http/shared/started.rb
deleted file mode 100644
index 9ff6272c31..0000000000
--- a/spec/ruby/library/net-http/http/shared/started.rb
+++ /dev/null
@@ -1,26 +0,0 @@
-describe :net_http_started_p, shared: true 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 true when self has been started" do
- @http.start
- @http.send(@method).should be_true
- end
-
- it "returns false when self has not been started yet" do
- @http.send(@method).should be_false
- end
-
- it "returns false when self has been stopped again" do
- @http.start
- @http.finish
- @http.send(@method).should be_false
- end
-end
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
deleted file mode 100644
index db3d6a986d..0000000000
--- a/spec/ruby/library/net-http/http/shared/version_1_1.rb
+++ /dev/null
@@ -1,6 +0,0 @@
-describe :net_http_version_1_1_p, shared: true do
- it "returns the state of net/http 1.1 features" do
- Net::HTTP.version_1_2
- Net::HTTP.send(@method).should be_false
- end
-end
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
deleted file mode 100644
index b044182c60..0000000000
--- a/spec/ruby/library/net-http/http/shared/version_1_2.rb
+++ /dev/null
@@ -1,6 +0,0 @@
-describe :net_http_version_1_2_p, shared: true do
- it "returns the state of net/http 1.2 features" do
- Net::HTTP.version_1_2
- Net::HTTP.send(@method).should be_true
- end
-end
diff --git a/spec/ruby/library/net-http/http/start_spec.rb b/spec/ruby/library/net-http/http/start_spec.rb
index 0ce3e79269..1aebc16f4d 100644
--- a/spec/ruby/library/net-http/http/start_spec.rb
+++ b/spec/ruby/library/net-http/http/start_spec.rb
@@ -22,13 +22,13 @@ describe "Net::HTTP.start" do
end
it "returns a new Net::HTTP object for the passed address and port" do
- @http.should be_kind_of(Net::HTTP)
+ @http.should.is_a?(Net::HTTP)
@http.address.should == "localhost"
@http.port.should == @port
end
it "opens the tcp connection" do
- @http.started?.should be_true
+ @http.started?.should == true
end
end
@@ -41,19 +41,19 @@ describe "Net::HTTP.start" do
yielded = false
Net::HTTP.start("localhost", @port) do |net|
yielded = true
- net.should be_kind_of(Net::HTTP)
+ net.should.is_a?(Net::HTTP)
end
- yielded.should be_true
+ yielded.should == true
end
it "opens the tcp connection before yielding" do
- Net::HTTP.start("localhost", @port) { |http| http.started?.should be_true }
+ Net::HTTP.start("localhost", @port) { |http| http.started?.should == 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
+ net.started?.should == false
end
end
end
@@ -70,18 +70,18 @@ describe "Net::HTTP#start" do
end
it "returns self" do
- @http.start.should equal(@http)
+ @http.start.should.equal?(@http)
end
it "opens the tcp connection" do
@http.start
- @http.started?.should be_true
+ @http.started?.should == true
end
describe "when self has already been started" do
it "raises an IOError" do
@http.start
- -> { @http.start }.should raise_error(IOError)
+ -> { @http.start }.should.raise(IOError)
end
end
@@ -94,18 +94,18 @@ describe "Net::HTTP#start" do
yielded = false
@http.start do |http|
yielded = true
- http.should equal(@http)
+ http.should.equal?(@http)
end
- yielded.should be_true
+ yielded.should == true
end
it "opens the tcp connection before yielding" do
- @http.start { |http| http.started?.should be_true }
+ @http.start { |http| http.started?.should == true }
end
it "closes the tcp connection after yielding" do
@http.start { }
- @http.started?.should be_false
+ @http.started?.should == 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
index cbb82ceefa..a0b46fcbd2 100644
--- a/spec/ruby/library/net-http/http/started_spec.rb
+++ b/spec/ruby/library/net-http/http/started_spec.rb
@@ -1,8 +1,30 @@
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?
+ 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 true when self has been started" do
+ @http.start
+ @http.started?.should == true
+ end
+
+ it "returns false when self has not been started yet" do
+ @http.started?.should == false
+ end
+
+ it "returns false when self has been stopped again" do
+ @http.start
+ @http.finish
+ @http.started?.should == false
+ end
end
diff --git a/spec/ruby/library/net-http/http/trace_spec.rb b/spec/ruby/library/net-http/http/trace_spec.rb
index 9809d537c5..e0ff741b04 100644
--- a/spec/ruby/library/net-http/http/trace_spec.rb
+++ b/spec/ruby/library/net-http/http/trace_spec.rb
@@ -19,6 +19,6 @@ describe "Net::HTTP#trace" do
end
it "returns a Net::HTTPResponse" do
- @http.trace("/request").should be_kind_of(Net::HTTPResponse)
+ @http.trace("/request").should.is_a?(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
index adf0b49f65..cbfc803f09 100644
--- a/spec/ruby/library/net-http/http/unlock_spec.rb
+++ b/spec/ruby/library/net-http/http/unlock_spec.rb
@@ -19,6 +19,6 @@ describe "Net::HTTP#unlock" do
end
it "returns a Net::HTTPResponse" do
- @http.unlock("/request", "test=test").should be_kind_of(Net::HTTPResponse)
+ @http.unlock("/request", "test=test").should.is_a?(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
index 912a62a8ba..b283655359 100644
--- a/spec/ruby/library/net-http/http/use_ssl_spec.rb
+++ b/spec/ruby/library/net-http/http/use_ssl_spec.rb
@@ -4,6 +4,6 @@ require 'net/http'
describe "Net::HTTP#use_ssl?" do
it "returns false" do
http = Net::HTTP.new("localhost")
- http.use_ssl?.should be_false
+ http.use_ssl?.should == 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
index 34a4ac8a6b..7f87bf30f9 100644
--- a/spec/ruby/library/net-http/http/version_1_1_spec.rb
+++ b/spec/ruby/library/net-http/http/version_1_1_spec.rb
@@ -1,7 +1,9 @@
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?
+ it "returns the state of net/http 1.1 features" do
+ Net::HTTP.version_1_2
+ Net::HTTP.version_1_1?.should == false
+ end
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
index e994511aea..73ca70ac7b 100644
--- a/spec/ruby/library/net-http/http/version_1_2_spec.rb
+++ b/spec/ruby/library/net-http/http/version_1_2_spec.rb
@@ -1,20 +1,22 @@
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
+ Net::HTTP.version_1_2?.should == true
+ Net::HTTP.version_1_1?.should == false
end
it "returns true" do
- Net::HTTP.version_1_2.should be_true
+ Net::HTTP.version_1_2.should == true
end
end
describe "Net::HTTP.version_1_2?" do
- it_behaves_like :net_http_version_1_2_p, :version_1_2?
+ it "returns the state of net/http 1.2 features" do
+ Net::HTTP.version_1_2
+ Net::HTTP.version_1_2?.should == true
+ 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
index 6c886499ca..96a761929e 100644
--- a/spec/ruby/library/net-http/httpgenericrequest/body_exist_spec.rb
+++ b/spec/ruby/library/net-http/httpgenericrequest/body_exist_spec.rb
@@ -4,10 +4,10 @@ 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.body_exist?.should == true
request = Net::HTTPGenericRequest.new("POST", true, false, "/some/path")
- request.body_exist?.should be_false
+ request.body_exist?.should == false
end
describe "when $VERBOSE is true" do
diff --git a/spec/ruby/library/net-http/httpgenericrequest/body_spec.rb b/spec/ruby/library/net-http/httpgenericrequest/body_spec.rb
index 5f7315f303..63cda994e5 100644
--- a/spec/ruby/library/net-http/httpgenericrequest/body_spec.rb
+++ b/spec/ruby/library/net-http/httpgenericrequest/body_spec.rb
@@ -5,7 +5,7 @@ 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.should == nil
request.body = "Some Content"
request.body.should == "Some Content"
@@ -25,6 +25,6 @@ describe "Net::HTTPGenericRequest#body=" do
it "sets self's body stream to nil" do
@request.body_stream = StringIO.new("")
@request.body = "Some Content"
- @request.body_stream.should be_nil
+ @request.body_stream.should == 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
index dea1c8c883..3237dbb861 100644
--- a/spec/ruby/library/net-http/httpgenericrequest/body_stream_spec.rb
+++ b/spec/ruby/library/net-http/httpgenericrequest/body_stream_spec.rb
@@ -5,11 +5,11 @@ 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
+ request.body_stream.should == nil
stream = StringIO.new("test")
request.body_stream = stream
- request.body_stream.should equal(stream)
+ request.body_stream.should.equal?(stream)
end
end
@@ -21,12 +21,12 @@ describe "Net::HTTPGenericRequest#body_stream=" do
it "sets self's body stream to the passed Object" do
@request.body_stream = @stream
- @request.body_stream.should equal(@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
+ @request.body.should == 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
index 0912e5a71f..0ccf80e3b6 100644
--- a/spec/ruby/library/net-http/httpgenericrequest/exec_spec.rb
+++ b/spec/ruby/library/net-http/httpgenericrequest/exec_spec.rb
@@ -31,7 +31,7 @@ describe "Net::HTTPGenericRequest#exec when passed socket, version, path" do
end
describe "when a request body is set" do
- ruby_version_is ""..."3.5" do
+ ruby_version_is ""..."4.0" 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"
@@ -64,7 +64,7 @@ describe "Net::HTTPGenericRequest#exec when passed socket, version, path" do
end
describe "when a body stream is set" do
- ruby_version_is ""..."3.5" do
+ ruby_version_is ""..."4.0" 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")
@@ -129,7 +129,7 @@ describe "Net::HTTPGenericRequest#exec when passed socket, version, path" do
"Content-Type" => "text/html")
request.body_stream = StringIO.new("Some Content")
- -> { request.exec(@buffered_socket, "1.1", "/some/other/path") }.should raise_error(ArgumentError)
+ -> { request.exec(@buffered_socket, "1.1", "/some/other/path") }.should.raise(ArgumentError)
end
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
index 1713b59baf..ba836e8130 100644
--- a/spec/ruby/library/net-http/httpgenericrequest/request_body_permitted_spec.rb
+++ b/spec/ruby/library/net-http/httpgenericrequest/request_body_permitted_spec.rb
@@ -4,9 +4,9 @@ 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.request_body_permitted?.should == true
request = Net::HTTPGenericRequest.new("POST", false, true, "/some/path")
- request.request_body_permitted?.should be_false
+ request.request_body_permitted?.should == 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
index 2f0751c344..067500f60d 100644
--- a/spec/ruby/library/net-http/httpgenericrequest/response_body_permitted_spec.rb
+++ b/spec/ruby/library/net-http/httpgenericrequest/response_body_permitted_spec.rb
@@ -4,9 +4,9 @@ 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.response_body_permitted?.should == true
request = Net::HTTPGenericRequest.new("POST", true, false, "/some/path")
- request.response_body_permitted?.should be_false
+ request.response_body_permitted?.should == 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
index 358aa6cde3..f241d8d698 100644
--- a/spec/ruby/library/net-http/httpgenericrequest/set_body_internal_spec.rb
+++ b/spec/ruby/library/net-http/httpgenericrequest/set_body_internal_spec.rb
@@ -13,9 +13,9 @@ describe "Net::HTTPGenericRequest#set_body_internal when passed string" do
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.set_body_internal("Some other Content") }.should.raise(ArgumentError)
@request.body_stream = "Some Content"
- -> { @request.set_body_internal("Some other Content") }.should raise_error(ArgumentError)
+ -> { @request.set_body_internal("Some other Content") }.should.raise(ArgumentError)
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
index 64a5cae89e..c009e9f7ea 100644
--- a/spec/ruby/library/net-http/httpheader/canonical_each_spec.rb
+++ b/spec/ruby/library/net-http/httpheader/canonical_each_spec.rb
@@ -1,8 +1,9 @@
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
+ it "is an alias of Net::HTTPHeader#each_capitalized" do
+ Net::HTTPHeader.instance_method(:canonical_each).should ==
+ Net::HTTPHeader.instance_method(:each_capitalized)
+ end
end
diff --git a/spec/ruby/library/net-http/httpheader/chunked_spec.rb b/spec/ruby/library/net-http/httpheader/chunked_spec.rb
index b32a0aab38..4da218ae25 100644
--- a/spec/ruby/library/net-http/httpheader/chunked_spec.rb
+++ b/spec/ruby/library/net-http/httpheader/chunked_spec.rb
@@ -8,15 +8,15 @@ describe "Net::HTTPHeader#chunked?" do
end
it "returns true if the 'Transfer-Encoding' header entry is set to chunked" do
- @headers.chunked?.should be_false
+ @headers.chunked?.should == false
@headers["Transfer-Encoding"] = "bla"
- @headers.chunked?.should be_false
+ @headers.chunked?.should == false
@headers["Transfer-Encoding"] = "blachunkedbla"
- @headers.chunked?.should be_false
+ @headers.chunked?.should == false
@headers["Transfer-Encoding"] = "chunked"
- @headers.chunked?.should be_true
+ @headers.chunked?.should == 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
index f05c5f8d8b..c66d5673c1 100644
--- a/spec/ruby/library/net-http/httpheader/content_length_spec.rb
+++ b/spec/ruby/library/net-http/httpheader/content_length_spec.rb
@@ -8,23 +8,23 @@ describe "Net::HTTPHeader#content_length" do
end
it "returns nil if no 'Content-Length' header entry is set" do
- @headers.content_length.should be_nil
+ @headers.content_length.should == 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)
+ -> { @headers.content_length }.should.raise(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.should.eql?(123)
@headers["Content-Length"] = "123valid"
- @headers.content_length.should eql(123)
+ @headers.content_length.should.eql?(123)
@headers["Content-Length"] = "valid123"
- @headers.content_length.should eql(123)
+ @headers.content_length.should.eql?(123)
end
end
@@ -36,7 +36,7 @@ describe "Net::HTTPHeader#content_length=" do
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
+ @headers["Content-Length"].should == nil
end
it "sets the 'Content-Length' entry to the passed value" do
diff --git a/spec/ruby/library/net-http/httpheader/content_range_spec.rb b/spec/ruby/library/net-http/httpheader/content_range_spec.rb
index 09737141a5..3635fb3f1b 100644
--- a/spec/ruby/library/net-http/httpheader/content_range_spec.rb
+++ b/spec/ruby/library/net-http/httpheader/content_range_spec.rb
@@ -16,17 +16,17 @@ describe "Net::HTTPHeader#content_range" do
end
it "returns nil when there is no 'Content-Range' header entry" do
- @headers.content_range.should be_nil
+ @headers.content_range.should == 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 }.should.raise(Net::HTTPHeaderSyntaxError)
@headers["Content-Range"] = "bytes 123-abc"
- -> { @headers.content_range }.should raise_error(Net::HTTPHeaderSyntaxError)
+ -> { @headers.content_range }.should.raise(Net::HTTPHeaderSyntaxError)
@headers["Content-Range"] = "bytes abc-123"
- -> { @headers.content_range }.should raise_error(Net::HTTPHeaderSyntaxError)
+ -> { @headers.content_range }.should.raise(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
index a6e1ae1093..0ee43a6942 100644
--- a/spec/ruby/library/net-http/httpheader/content_type_spec.rb
+++ b/spec/ruby/library/net-http/httpheader/content_type_spec.rb
@@ -1,7 +1,6 @@
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
@@ -17,10 +16,13 @@ describe "Net::HTTPHeader#content_type" do
end
it "returns nil if the 'Content-Type' header entry does not exist" do
- @headers.content_type.should be_nil
+ @headers.content_type.should == nil
end
end
describe "Net::HTTPHeader#content_type=" do
- it_behaves_like :net_httpheader_set_content_type, :content_type=
+ it "is an alias of Net::HTTPHeader#set_content_type" do
+ Net::HTTPHeader.instance_method(:content_type=).should ==
+ Net::HTTPHeader.instance_method(:set_content_type)
+ end
end
diff --git a/spec/ruby/library/net-http/httpheader/delete_spec.rb b/spec/ruby/library/net-http/httpheader/delete_spec.rb
index 8d929dbd86..09bae65a13 100644
--- a/spec/ruby/library/net-http/httpheader/delete_spec.rb
+++ b/spec/ruby/library/net-http/httpheader/delete_spec.rb
@@ -11,8 +11,8 @@ describe "Net::HTTPHeader#delete when passed key" do
@headers["My-Header"] = "test"
@headers.delete("My-Header")
- @headers["My-Header"].should be_nil
- @headers.size.should eql(0)
+ @headers["My-Header"].should == nil
+ @headers.size.should.eql?(0)
end
it "returns the removed values" do
@@ -24,7 +24,7 @@ describe "Net::HTTPHeader#delete when passed key" do
@headers["My-Header"] = "test"
@headers.delete("my-header")
- @headers["My-Header"].should be_nil
- @headers.size.should eql(0)
+ @headers["My-Header"].should == 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
index 27713577f9..54874c0535 100644
--- a/spec/ruby/library/net-http/httpheader/each_capitalized_name_spec.rb
+++ b/spec/ruby/library/net-http/httpheader/each_capitalized_name_spec.rb
@@ -23,7 +23,7 @@ describe "Net::HTTPHeader#each_capitalized_name" do
describe "when passed no block" do
it "returns an Enumerator" do
enumerator = @headers.each_capitalized_name
- enumerator.should be_an_instance_of(Enumerator)
+ enumerator.should.instance_of?(Enumerator)
res = []
enumerator.each do |key|
diff --git a/spec/ruby/library/net-http/httpheader/each_capitalized_spec.rb b/spec/ruby/library/net-http/httpheader/each_capitalized_spec.rb
index 1e853995ea..e24e778238 100644
--- a/spec/ruby/library/net-http/httpheader/each_capitalized_spec.rb
+++ b/spec/ruby/library/net-http/httpheader/each_capitalized_spec.rb
@@ -1,8 +1,35 @@
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
+ 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 to the passed block (capitalized keys, values joined)" do
+ res = []
+ @headers.each_capitalized do |key, value|
+ res << [key, value]
+ end
+ res.sort.should == [["My-Header", "test"], ["My-Other-Header", "a, b"]]
+ end
+ end
+
+ describe "when passed no block" do
+ it "returns an Enumerator" do
+ enumerator = @headers.each_capitalized
+ enumerator.should.instance_of?(Enumerator)
+
+ res = []
+ enumerator.each do |*key|
+ res << key
+ end
+ res.sort.should == [["My-Header", "test"], ["My-Other-Header", "a, b"]]
+ end
+ end
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
index 869feebacf..63c1106d18 100644
--- a/spec/ruby/library/net-http/httpheader/each_header_spec.rb
+++ b/spec/ruby/library/net-http/httpheader/each_header_spec.rb
@@ -1,8 +1,35 @@
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
+ 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 to the passed block (keys in lower case, values joined)" do
+ res = []
+ @headers.each_header do |key, value|
+ res << [key, value]
+ end
+ res.sort.should == [["my-header", "test"], ["my-other-header", "a, b"]]
+ end
+ end
+
+ describe "when passed no block" do
+ it "returns an Enumerator" do
+ enumerator = @headers.each_header
+ enumerator.should.instance_of?(Enumerator)
+
+ res = []
+ enumerator.each do |*key|
+ res << key
+ end
+ res.sort.should == [["my-header", "test"], ["my-other-header", "a, b"]]
+ end
+ end
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
index 1ad145629f..a5635da5db 100644
--- a/spec/ruby/library/net-http/httpheader/each_key_spec.rb
+++ b/spec/ruby/library/net-http/httpheader/each_key_spec.rb
@@ -1,8 +1,35 @@
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
+ 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 in lower case)" do
+ res = []
+ @headers.each_key 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_key
+ enumerator.should.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_name_spec.rb b/spec/ruby/library/net-http/httpheader/each_name_spec.rb
index f819bd989d..02f9761f80 100644
--- a/spec/ruby/library/net-http/httpheader/each_name_spec.rb
+++ b/spec/ruby/library/net-http/httpheader/each_name_spec.rb
@@ -1,8 +1,10 @@
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
+ it "is an alias of Net::HTTPHeader#each_key" do
+ Net::HTTPHeader.instance_method(:each_name).should ==
+ Net::HTTPHeader.instance_method(:each_key)
+ end
end
diff --git a/spec/ruby/library/net-http/httpheader/each_spec.rb b/spec/ruby/library/net-http/httpheader/each_spec.rb
index ff37249d0a..e219609b67 100644
--- a/spec/ruby/library/net-http/httpheader/each_spec.rb
+++ b/spec/ruby/library/net-http/httpheader/each_spec.rb
@@ -1,8 +1,9 @@
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
+ it "is an alias of Net::HTTPHeader#each_header" do
+ Net::HTTPHeader.instance_method(:each).should ==
+ Net::HTTPHeader.instance_method(:each_header)
+ end
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
index b71df58c65..55ba4c1ef8 100644
--- a/spec/ruby/library/net-http/httpheader/each_value_spec.rb
+++ b/spec/ruby/library/net-http/httpheader/each_value_spec.rb
@@ -23,7 +23,7 @@ describe "Net::HTTPHeader#each_value" do
describe "when passed no block" do
it "returns an Enumerator" do
enumerator = @headers.each_value
- enumerator.should be_an_instance_of(Enumerator)
+ enumerator.should.instance_of?(Enumerator)
res = []
enumerator.each do |key|
diff --git a/spec/ruby/library/net-http/httpheader/element_reference_spec.rb b/spec/ruby/library/net-http/httpheader/element_reference_spec.rb
index 1003c41af9..f12f8494db 100644
--- a/spec/ruby/library/net-http/httpheader/element_reference_spec.rb
+++ b/spec/ruby/library/net-http/httpheader/element_reference_spec.rb
@@ -33,7 +33,7 @@ describe "Net::HTTPHeader#[] when passed key" do
end
it "returns nil for non-existing entries" do
- @headers["My-Header"].should be_nil
- @headers["My-Other-Header"].should be_nil
+ @headers["My-Header"].should == nil
+ @headers["My-Other-Header"].should == 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
index 376df2f977..633fe18b2e 100644
--- a/spec/ruby/library/net-http/httpheader/element_set_spec.rb
+++ b/spec/ruby/library/net-http/httpheader/element_set_spec.rb
@@ -26,16 +26,16 @@ describe "Net::HTTPHeader#[]= when passed key, value" do
@headers['MY-HEADER'] = "last one"
@headers["My-Header"].should == "last one"
- @headers.size.should eql(1)
+ @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'].should == nil
@headers['My-Header'] = "test"
@headers['My-Header'] = false
- @headers['My-Header'].should be_nil
+ @headers['My-Header'].should == 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
index 58c69c0377..d1c273dada 100644
--- a/spec/ruby/library/net-http/httpheader/fetch_spec.rb
+++ b/spec/ruby/library/net-http/httpheader/fetch_spec.rb
@@ -25,7 +25,7 @@ describe "Net::HTTPHeader#fetch" do
end
it "returns nil when there is no entry for the passed key" do
- -> { @headers.fetch("my-header") }.should raise_error(IndexError)
+ -> { @headers.fetch("my-header") }.should.raise(IndexError)
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
index acd913f53a..8d4974cde3 100644
--- a/spec/ruby/library/net-http/httpheader/form_data_spec.rb
+++ b/spec/ruby/library/net-http/httpheader/form_data_spec.rb
@@ -1,8 +1,10 @@
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=
+ it "is an alias of Net::HTTPHeader#set_form_data" do
+ Net::HTTPHeader.instance_method(:form_data=).should ==
+ Net::HTTPHeader.instance_method(:set_form_data)
+ end
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
index 0278bcede2..76da63bc31 100644
--- a/spec/ruby/library/net-http/httpheader/get_fields_spec.rb
+++ b/spec/ruby/library/net-http/httpheader/get_fields_spec.rb
@@ -26,8 +26,8 @@ describe "Net::HTTPHeader#get_fields when passed key" do
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
+ @headers.get_fields("My-Header").should == nil
+ @headers.get_fields("My-Other-header").should == nil
end
it "is case-insensitive" do
diff --git a/spec/ruby/library/net-http/httpheader/key_spec.rb b/spec/ruby/library/net-http/httpheader/key_spec.rb
index 2b7aeb9c2a..65662591eb 100644
--- a/spec/ruby/library/net-http/httpheader/key_spec.rb
+++ b/spec/ruby/library/net-http/httpheader/key_spec.rb
@@ -8,14 +8,14 @@ describe "Net::HTTPHeader#key? when passed key" do
end
it "returns true if the header entry with the passed key exists" do
- @headers.key?("My-Header").should be_false
+ @headers.key?("My-Header").should == false
@headers["My-Header"] = "test"
- @headers.key?("My-Header").should be_true
+ @headers.key?("My-Header").should == 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
+ @headers.key?("my-header").should == true
+ @headers.key?("MY-HEADER").should == 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
index 57e32742e4..1f059719e9 100644
--- a/spec/ruby/library/net-http/httpheader/length_spec.rb
+++ b/spec/ruby/library/net-http/httpheader/length_spec.rb
@@ -1,8 +1,9 @@
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
+ it "is an alias of Net::HTTPHeader#size" do
+ Net::HTTPHeader.instance_method(:length).should ==
+ Net::HTTPHeader.instance_method(:size)
+ end
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
index 4dd551d8f4..af7d3e05a3 100644
--- a/spec/ruby/library/net-http/httpheader/main_type_spec.rb
+++ b/spec/ruby/library/net-http/httpheader/main_type_spec.rb
@@ -19,6 +19,6 @@ describe "Net::HTTPHeader#main_type" do
end
it "returns nil if the 'Content-Type' header entry does not exist" do
- @headers.main_type.should be_nil
+ @headers.main_type.should == nil
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
index 77323ac872..34db7e6126 100644
--- a/spec/ruby/library/net-http/httpheader/range_length_spec.rb
+++ b/spec/ruby/library/net-http/httpheader/range_length_spec.rb
@@ -9,24 +9,24 @@ describe "Net::HTTPHeader#range_length" do
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.range_length.should.eql?(500)
@headers["Content-Range"] = "bytes 500-1233/1234"
- @headers.range_length.should eql(734)
+ @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
+ @headers.range_length.should == 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.range_length }.should.raise(Net::HTTPHeaderSyntaxError)
@headers["Content-Range"] = "bytes 123-abc"
- -> { @headers.range_length }.should raise_error(Net::HTTPHeaderSyntaxError)
+ -> { @headers.range_length }.should.raise(Net::HTTPHeaderSyntaxError)
@headers["Content-Range"] = "bytes abc-123"
- -> { @headers.range_length }.should raise_error(Net::HTTPHeaderSyntaxError)
+ -> { @headers.range_length }.should.raise(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
index 2de80a825e..8944e2d5f2 100644
--- a/spec/ruby/library/net-http/httpheader/range_spec.rb
+++ b/spec/ruby/library/net-http/httpheader/range_spec.rb
@@ -1,7 +1,6 @@
require_relative '../../../spec_helper'
require 'net/http'
require_relative 'fixtures/classes'
-require_relative 'shared/set_range'
describe "Net::HTTPHeader#range" do
before :each do
@@ -23,26 +22,29 @@ describe "Net::HTTPHeader#range" do
end
it "returns nil when there is no 'Range' header entry" do
- @headers.range.should be_nil
+ @headers.range.should == 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 }.should.raise(Net::HTTPHeaderSyntaxError)
@headers["Range"] = "bytes 123-abc"
- -> { @headers.range }.should raise_error(Net::HTTPHeaderSyntaxError)
+ -> { @headers.range }.should.raise(Net::HTTPHeaderSyntaxError)
@headers["Range"] = "bytes abc-123"
- -> { @headers.range }.should raise_error(Net::HTTPHeaderSyntaxError)
+ -> { @headers.range }.should.raise(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)
+ -> { @headers.range }.should.raise(Net::HTTPHeaderSyntaxError)
end
end
describe "Net::HTTPHeader#range=" do
- it_behaves_like :net_httpheader_set_range, :range=
+ it "is an alias of Net::HTTPHeader#set_range" do
+ Net::HTTPHeader.instance_method(:range=).should ==
+ Net::HTTPHeader.instance_method(:set_range)
+ end
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
index 7ec4f90b8e..3674061626 100644
--- a/spec/ruby/library/net-http/httpheader/set_content_type_spec.rb
+++ b/spec/ruby/library/net-http/httpheader/set_content_type_spec.rb
@@ -1,8 +1,22 @@
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
+ describe "when passed type, params" do
+ before :each do
+ @headers = NetHTTPHeaderSpecs::Example.new
+ end
+
+ it "sets the 'Content-Type' header entry based on the passed type and params" do
+ @headers.set_content_type("text/html")
+ @headers["Content-Type"].should == "text/html"
+
+ @headers.set_content_type("text/html", "charset" => "utf-8")
+ @headers["Content-Type"].should == "text/html; charset=utf-8"
+
+ @headers.set_content_type("text/html", "charset" => "utf-8", "rubyspec" => "rocks")
+ @headers["Content-Type"].split(/; /).sort.should == %w[charset=utf-8 rubyspec=rocks text/html]
+ end
+ end
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
index 7aac19f045..093dc100d5 100644
--- a/spec/ruby/library/net-http/httpheader/set_form_data_spec.rb
+++ b/spec/ruby/library/net-http/httpheader/set_form_data_spec.rb
@@ -1,8 +1,31 @@
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
+ before :each do
+ @headers = NetHTTPHeaderSpecs::Example.new
+ end
+
+ describe "when passed params" do
+ it "automatically set the 'Content-Type' to 'application/x-www-form-urlencoded'" do
+ @headers.set_form_data("cmd" => "search", "q" => "ruby", "max" => "50")
+ @headers["Content-Type"].should == "application/x-www-form-urlencoded"
+ end
+
+ it "sets self's body based on the passed form parameters" do
+ @headers.set_form_data("cmd" => "search", "q" => "ruby", "max" => "50")
+ @headers.body.split("&").sort.should == ["cmd=search", "max=50", "q=ruby"]
+ end
+ end
+
+ describe "when passed params, separator" do
+ it "sets self's body based on the passed form parameters and the passed separator" do
+ @headers.set_form_data({"cmd" => "search", "q" => "ruby", "max" => "50"}, "&")
+ @headers.body.split("&").sort.should == ["cmd=search", "max=50", "q=ruby"]
+
+ @headers.set_form_data({"cmd" => "search", "q" => "ruby", "max" => "50"}, ";")
+ @headers.body.split(";").sort.should == ["cmd=search", "max=50", "q=ruby"]
+ end
+ end
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
index 0f98de55e6..d48ed1897a 100644
--- a/spec/ruby/library/net-http/httpheader/set_range_spec.rb
+++ b/spec/ruby/library/net-http/httpheader/set_range_spec.rb
@@ -1,8 +1,93 @@
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
+ before :each do
+ @headers = NetHTTPHeaderSpecs::Example.new
+ end
+
+ describe "when passed nil" do
+ it "returns nil" do
+ @headers.set_range(nil).should == nil
+ end
+
+ it "deletes the 'Range' header entry" do
+ @headers["Range"] = "bytes 0-499/1234"
+ @headers.set_range(nil)
+ @headers["Range"].should == nil
+ end
+ end
+
+ describe "when passed Numeric" do
+ it "sets the 'Range' header entry based on the passed Numeric" do
+ @headers.set_range(10)
+ @headers["Range"].should == "bytes=0-9"
+
+ @headers.set_range(-10)
+ @headers["Range"].should == "bytes=-10"
+
+ @headers.set_range(10.9)
+ @headers["Range"].should == "bytes=0-9"
+ end
+ end
+
+ describe "when passed Range" do
+ it "sets the 'Range' header entry based on the passed Range" do
+ @headers.set_range(10..200)
+ @headers["Range"].should == "bytes=10-200"
+
+ @headers.set_range(1..5)
+ @headers["Range"].should == "bytes=1-5"
+
+ @headers.set_range(1...5)
+ @headers["Range"].should == "bytes=1-4"
+
+ @headers.set_range(234..567)
+ @headers["Range"].should == "bytes=234-567"
+
+ @headers.set_range(-5..-1)
+ @headers["Range"].should == "bytes=-5"
+
+ @headers.set_range(1..-1)
+ @headers["Range"].should == "bytes=1-"
+ end
+
+ it "raises a Net::HTTPHeaderSyntaxError when the first Range element is negative" do
+ -> { @headers.set_range(-10..5) }.should.raise(Net::HTTPHeaderSyntaxError)
+ end
+
+ it "raises a Net::HTTPHeaderSyntaxError when the last Range element is negative" do
+ -> { @headers.set_range(10..-5) }.should.raise(Net::HTTPHeaderSyntaxError)
+ end
+
+ it "raises a Net::HTTPHeaderSyntaxError when the last Range element is smaller than the first" do
+ -> { @headers.set_range(10..5) }.should.raise(Net::HTTPHeaderSyntaxError)
+ end
+ end
+
+ describe "when passed start, end" do
+ it "sets the 'Range' header entry based on the passed start and length values" do
+ @headers.set_range(10, 200)
+ @headers["Range"].should == "bytes=10-209"
+
+ @headers.set_range(1, 5)
+ @headers["Range"].should == "bytes=1-5"
+
+ @headers.set_range(234, 567)
+ @headers["Range"].should == "bytes=234-800"
+ end
+
+ it "raises a Net::HTTPHeaderSyntaxError when start is negative" do
+ -> { @headers.set_range(-10, 5) }.should.raise(Net::HTTPHeaderSyntaxError)
+ end
+
+ it "raises a Net::HTTPHeaderSyntaxError when start + length is negative" do
+ -> { @headers.set_range(10, -15) }.should.raise(Net::HTTPHeaderSyntaxError)
+ end
+
+ it "raises a Net::HTTPHeaderSyntaxError when length is negative" do
+ -> { @headers.set_range(10, -4) }.should.raise(Net::HTTPHeaderSyntaxError)
+ end
+ end
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
deleted file mode 100644
index 3bac409876..0000000000
--- a/spec/ruby/library/net-http/httpheader/shared/each_capitalized.rb
+++ /dev/null
@@ -1,31 +0,0 @@
-describe :net_httpheader_each_capitalized, shared: true 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 to the passed block (capitalized keys, values joined)" do
- res = []
- @headers.send(@method) do |key, value|
- res << [key, value]
- end
- res.sort.should == [["My-Header", "test"], ["My-Other-Header", "a, b"]]
- end
- end
-
- describe "when passed no block" do
- it "returns an Enumerator" do
- enumerator = @headers.send(@method)
- enumerator.should be_an_instance_of(Enumerator)
-
- res = []
- enumerator.each do |*key|
- res << key
- end
- res.sort.should == [["My-Header", "test"], ["My-Other-Header", "a, b"]]
- end
- end
-end
diff --git a/spec/ruby/library/net-http/httpheader/shared/each_header.rb b/spec/ruby/library/net-http/httpheader/shared/each_header.rb
deleted file mode 100644
index 6bf3a6ddfe..0000000000
--- a/spec/ruby/library/net-http/httpheader/shared/each_header.rb
+++ /dev/null
@@ -1,31 +0,0 @@
-describe :net_httpheader_each_header, shared: true 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 to the passed block (keys in lower case, values joined)" do
- res = []
- @headers.send(@method) do |key, value|
- res << [key, value]
- end
- res.sort.should == [["my-header", "test"], ["my-other-header", "a, b"]]
- end
- end
-
- describe "when passed no block" do
- it "returns an Enumerator" do
- enumerator = @headers.send(@method)
- enumerator.should be_an_instance_of(Enumerator)
-
- res = []
- enumerator.each do |*key|
- res << key
- end
- res.sort.should == [["my-header", "test"], ["my-other-header", "a, b"]]
- end
- end
-end
diff --git a/spec/ruby/library/net-http/httpheader/shared/each_name.rb b/spec/ruby/library/net-http/httpheader/shared/each_name.rb
deleted file mode 100644
index efc6a09dfd..0000000000
--- a/spec/ruby/library/net-http/httpheader/shared/each_name.rb
+++ /dev/null
@@ -1,31 +0,0 @@
-describe :net_httpheader_each_name, shared: true 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 in lower case)" do
- res = []
- @headers.send(@method) 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.send(@method)
- 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/shared/set_content_type.rb b/spec/ruby/library/net-http/httpheader/shared/set_content_type.rb
deleted file mode 100644
index b7359bdca6..0000000000
--- a/spec/ruby/library/net-http/httpheader/shared/set_content_type.rb
+++ /dev/null
@@ -1,18 +0,0 @@
-describe :net_httpheader_set_content_type, shared: true do
- describe "when passed type, params" do
- before :each do
- @headers = NetHTTPHeaderSpecs::Example.new
- end
-
- it "sets the 'Content-Type' header entry based on the passed type and params" do
- @headers.send(@method, "text/html")
- @headers["Content-Type"].should == "text/html"
-
- @headers.send(@method, "text/html", "charset" => "utf-8")
- @headers["Content-Type"].should == "text/html; charset=utf-8"
-
- @headers.send(@method, "text/html", "charset" => "utf-8", "rubyspec" => "rocks")
- @headers["Content-Type"].split(/; /).sort.should == %w[charset=utf-8 rubyspec=rocks text/html]
- end
- end
-end
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
deleted file mode 100644
index db20b18803..0000000000
--- a/spec/ruby/library/net-http/httpheader/shared/set_form_data.rb
+++ /dev/null
@@ -1,27 +0,0 @@
-describe :net_httpheader_set_form_data, shared: true do
- before :each do
- @headers = NetHTTPHeaderSpecs::Example.new
- end
-
- describe "when passed params" do
- it "automatically set the 'Content-Type' to 'application/x-www-form-urlencoded'" do
- @headers.send(@method, "cmd" => "search", "q" => "ruby", "max" => "50")
- @headers["Content-Type"].should == "application/x-www-form-urlencoded"
- end
-
- it "sets self's body based on the passed form parameters" do
- @headers.send(@method, "cmd" => "search", "q" => "ruby", "max" => "50")
- @headers.body.split("&").sort.should == ["cmd=search", "max=50", "q=ruby"]
- end
- end
-
- describe "when passed params, separator" do
- it "sets self's body based on the passed form parameters and the passed separator" do
- @headers.send(@method, {"cmd" => "search", "q" => "ruby", "max" => "50"}, "&")
- @headers.body.split("&").sort.should == ["cmd=search", "max=50", "q=ruby"]
-
- @headers.send(@method, {"cmd" => "search", "q" => "ruby", "max" => "50"}, ";")
- @headers.body.split(";").sort.should == ["cmd=search", "max=50", "q=ruby"]
- end
- end
-end
diff --git a/spec/ruby/library/net-http/httpheader/shared/set_range.rb b/spec/ruby/library/net-http/httpheader/shared/set_range.rb
deleted file mode 100644
index 87f51d46f3..0000000000
--- a/spec/ruby/library/net-http/httpheader/shared/set_range.rb
+++ /dev/null
@@ -1,89 +0,0 @@
-describe :net_httpheader_set_range, shared: true do
- before :each do
- @headers = NetHTTPHeaderSpecs::Example.new
- end
-
- describe "when passed nil" do
- it "returns nil" do
- @headers.send(@method, nil).should be_nil
- end
-
- it "deletes the 'Range' header entry" do
- @headers["Range"] = "bytes 0-499/1234"
- @headers.send(@method, nil)
- @headers["Range"].should be_nil
- end
- end
-
- describe "when passed Numeric" do
- it "sets the 'Range' header entry based on the passed Numeric" do
- @headers.send(@method, 10)
- @headers["Range"].should == "bytes=0-9"
-
- @headers.send(@method, -10)
- @headers["Range"].should == "bytes=-10"
-
- @headers.send(@method, 10.9)
- @headers["Range"].should == "bytes=0-9"
- end
- end
-
- describe "when passed Range" do
- it "sets the 'Range' header entry based on the passed Range" do
- @headers.send(@method, 10..200)
- @headers["Range"].should == "bytes=10-200"
-
- @headers.send(@method, 1..5)
- @headers["Range"].should == "bytes=1-5"
-
- @headers.send(@method, 1...5)
- @headers["Range"].should == "bytes=1-4"
-
- @headers.send(@method, 234..567)
- @headers["Range"].should == "bytes=234-567"
-
- @headers.send(@method, -5..-1)
- @headers["Range"].should == "bytes=-5"
-
- @headers.send(@method, 1..-1)
- @headers["Range"].should == "bytes=1-"
- end
-
- it "raises a Net::HTTPHeaderSyntaxError when the first Range element is negative" do
- -> { @headers.send(@method, -10..5) }.should raise_error(Net::HTTPHeaderSyntaxError)
- end
-
- it "raises a Net::HTTPHeaderSyntaxError when the last Range element is negative" do
- -> { @headers.send(@method, 10..-5) }.should raise_error(Net::HTTPHeaderSyntaxError)
- end
-
- it "raises a Net::HTTPHeaderSyntaxError when the last Range element is smaller than the first" do
- -> { @headers.send(@method, 10..5) }.should raise_error(Net::HTTPHeaderSyntaxError)
- end
- end
-
- describe "when passed start, end" do
- it "sets the 'Range' header entry based on the passed start and length values" do
- @headers.send(@method, 10, 200)
- @headers["Range"].should == "bytes=10-209"
-
- @headers.send(@method, 1, 5)
- @headers["Range"].should == "bytes=1-5"
-
- @headers.send(@method, 234, 567)
- @headers["Range"].should == "bytes=234-800"
- end
-
- it "raises a Net::HTTPHeaderSyntaxError when start is negative" do
- -> { @headers.send(@method, -10, 5) }.should raise_error(Net::HTTPHeaderSyntaxError)
- end
-
- it "raises a Net::HTTPHeaderSyntaxError when start + length is negative" do
- -> { @headers.send(@method, 10, -15) }.should raise_error(Net::HTTPHeaderSyntaxError)
- end
-
- it "raises a Net::HTTPHeaderSyntaxError when length is negative" do
- -> { @headers.send(@method, 10, -4) }.should raise_error(Net::HTTPHeaderSyntaxError)
- end
- end
-end
diff --git a/spec/ruby/library/net-http/httpheader/shared/size.rb b/spec/ruby/library/net-http/httpheader/shared/size.rb
deleted file mode 100644
index e2b1e4c22b..0000000000
--- a/spec/ruby/library/net-http/httpheader/shared/size.rb
+++ /dev/null
@@ -1,18 +0,0 @@
-describe :net_httpheader_size, shared: true do
- before :each do
- @headers = NetHTTPHeaderSpecs::Example.new
- end
-
- it "returns the number of header entries in self" do
- @headers.send(@method).should eql(0)
-
- @headers["a"] = "b"
- @headers.send(@method).should eql(1)
-
- @headers["b"] = "b"
- @headers.send(@method).should eql(2)
-
- @headers["c"] = "c"
- @headers.send(@method).should eql(3)
- end
-end
diff --git a/spec/ruby/library/net-http/httpheader/size_spec.rb b/spec/ruby/library/net-http/httpheader/size_spec.rb
index 210060ce21..f84a0fb5ab 100644
--- a/spec/ruby/library/net-http/httpheader/size_spec.rb
+++ b/spec/ruby/library/net-http/httpheader/size_spec.rb
@@ -1,8 +1,22 @@
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
+ before :each do
+ @headers = NetHTTPHeaderSpecs::Example.new
+ end
+
+ it "returns the number of header entries in self" do
+ @headers.size.should.eql?(0)
+
+ @headers["a"] = "b"
+ @headers.size.should.eql?(1)
+
+ @headers["b"] = "b"
+ @headers.size.should.eql?(2)
+
+ @headers["c"] = "c"
+ @headers.size.should.eql?(3)
+ end
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
index b39b57fe8d..9e7d2a5368 100644
--- a/spec/ruby/library/net-http/httpheader/sub_type_spec.rb
+++ b/spec/ruby/library/net-http/httpheader/sub_type_spec.rb
@@ -20,13 +20,13 @@ describe "Net::HTTPHeader#sub_type" do
it "returns nil if no 'sub-content-type' is set" do
@headers["Content-Type"] = "text"
- @headers.sub_type.should be_nil
+ @headers.sub_type.should == nil
@headers["Content-Type"] = "text;charset=utf-8"
- @headers.sub_type.should be_nil
+ @headers.sub_type.should == nil
end
it "returns nil if the 'Content-Type' header entry does not exist" do
- @headers.sub_type.should be_nil
+ @headers.sub_type.should == 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
index 3cebc519a6..e245c20d4c 100644
--- a/spec/ruby/library/net-http/httpheader/to_hash_spec.rb
+++ b/spec/ruby/library/net-http/httpheader/to_hash_spec.rb
@@ -20,6 +20,6 @@ describe "Net::HTTPHeader#to_hash" do
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
+ @headers.key?("my-header").should == false
end
end
diff --git a/spec/ruby/library/net-http/httprequest/initialize_spec.rb b/spec/ruby/library/net-http/httprequest/initialize_spec.rb
index d009a00ed2..1229986bef 100644
--- a/spec/ruby/library/net-http/httprequest/initialize_spec.rb
+++ b/spec/ruby/library/net-http/httprequest/initialize_spec.rb
@@ -21,12 +21,12 @@ describe "Net::HTTPRequest#initialize" do
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
+ @req.request_body_permitted?.should == 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
+ @req.response_body_permitted?.should == true
end
describe "when passed path" do
diff --git a/spec/ruby/library/net-http/httpresponse/body_spec.rb b/spec/ruby/library/net-http/httpresponse/body_spec.rb
index ddfcd834c4..5b00913687 100644
--- a/spec/ruby/library/net-http/httpresponse/body_spec.rb
+++ b/spec/ruby/library/net-http/httpresponse/body_spec.rb
@@ -1,7 +1,22 @@
require_relative '../../../spec_helper'
require 'net/http'
-require_relative 'shared/body'
+require 'stringio'
describe "Net::HTTPResponse#body" do
- it_behaves_like :net_httpresponse_body, :body
+ before :each do
+ @res = Net::HTTPUnknownResponse.new("1.0", "???", "test response")
+ @socket = Net::BufferedIO.new(StringIO.new("test body"))
+ end
+
+ it "returns the read body" do
+ @res.reading_body(@socket, true) do
+ @res.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.body.should.equal?(@res.body)
+ end
+ end
end
diff --git a/spec/ruby/library/net-http/httpresponse/entity_spec.rb b/spec/ruby/library/net-http/httpresponse/entity_spec.rb
index ca8c4b29c0..d2201db37b 100644
--- a/spec/ruby/library/net-http/httpresponse/entity_spec.rb
+++ b/spec/ruby/library/net-http/httpresponse/entity_spec.rb
@@ -1,7 +1,9 @@
require_relative '../../../spec_helper'
require 'net/http'
-require_relative 'shared/body'
describe "Net::HTTPResponse#entity" do
- it_behaves_like :net_httpresponse_body, :entity
+ it "is an alias of Net::HTTPResponse#body" do
+ Net::HTTPResponse.instance_method(:entity).should ==
+ Net::HTTPResponse.instance_method(:body)
+ end
end
diff --git a/spec/ruby/library/net-http/httpresponse/error_spec.rb b/spec/ruby/library/net-http/httpresponse/error_spec.rb
index 6ced90fa23..e194df95af 100644
--- a/spec/ruby/library/net-http/httpresponse/error_spec.rb
+++ b/spec/ruby/library/net-http/httpresponse/error_spec.rb
@@ -4,21 +4,21 @@ 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.error! }.should.raise(Net::HTTPError)
res = Net::HTTPInformation.new("1.0", "1xx", "test response")
- -> { res.error! }.should raise_error(Net::HTTPError)
+ -> { res.error! }.should.raise(Net::HTTPError)
res = Net::HTTPSuccess.new("1.0", "2xx", "test response")
- -> { res.error! }.should raise_error(Net::HTTPError)
+ -> { res.error! }.should.raise(Net::HTTPError)
res = Net::HTTPRedirection.new("1.0", "3xx", "test response")
- -> { res.error! }.should raise_error(Net::HTTPRetriableError)
+ -> { res.error! }.should.raise(Net::HTTPRetriableError)
res = Net::HTTPClientError.new("1.0", "4xx", "test response")
- -> { res.error! }.should raise_error(Net::HTTPClientException)
+ -> { res.error! }.should.raise(Net::HTTPClientException)
res = Net::HTTPServerError.new("1.0", "5xx", "test response")
- -> { res.error! }.should raise_error(Net::HTTPFatalError)
+ -> { res.error! }.should.raise(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
index a403dbd2c3..3ddadfb8e4 100644
--- a/spec/ruby/library/net-http/httpresponse/header_spec.rb
+++ b/spec/ruby/library/net-http/httpresponse/header_spec.rb
@@ -4,6 +4,6 @@ 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)
+ res.response.should.equal?(res)
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
index 4530a26bfc..d8b2418624 100644
--- a/spec/ruby/library/net-http/httpresponse/read_body_spec.rb
+++ b/spec/ruby/library/net-http/httpresponse/read_body_spec.rb
@@ -17,7 +17,7 @@ describe "Net::HTTPResponse#read_body" do
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)
+ @res.read_body.should.equal?(@res.read_body)
end
end
end
@@ -34,14 +34,14 @@ describe "Net::HTTPResponse#read_body" do
it "returns the passed buffer" do
@res.reading_body(@socket, true) do
buffer = +""
- @res.read_body(buffer).should equal(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)
+ -> { @res.read_body(+"") }.should.raise(IOError)
end
end
end
@@ -57,21 +57,21 @@ describe "Net::HTTPResponse#read_body" do
buffer << body
end
- yielded.should be_true
+ yielded.should == 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)
+ @res.read_body { nil }.should.is_a?(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)
+ -> { @res.read_body {} }.should.raise(IOError)
end
end
end
@@ -79,7 +79,7 @@ describe "Net::HTTPResponse#read_body" do
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)
+ -> { @res.read_body(+"") {} }.should.raise(ArgumentError)
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
index 3ea4ee834b..70ce988502 100644
--- a/spec/ruby/library/net-http/httpresponse/read_header_spec.rb
+++ b/spec/ruby/library/net-http/httpresponse/read_header_spec.rb
@@ -4,6 +4,6 @@ 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)
+ 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
index 82f7a47ce8..3795e29d83 100644
--- a/spec/ruby/library/net-http/httpresponse/read_new_spec.rb
+++ b/spec/ruby/library/net-http/httpresponse/read_new_spec.rb
@@ -12,7 +12,7 @@ test-body
EOS
response = Net::HTTPResponse.read_new(socket)
- response.should be_kind_of(Net::HTTPOK)
+ response.should.is_a?(Net::HTTPOK)
response.code.should == "200"
response["Content-Type"].should == "text/html; charset=utf-8"
diff --git a/spec/ruby/library/net-http/httpresponse/reading_body_spec.rb b/spec/ruby/library/net-http/httpresponse/reading_body_spec.rb
index 637a2806f8..a3671d6eb5 100644
--- a/spec/ruby/library/net-http/httpresponse/reading_body_spec.rb
+++ b/spec/ruby/library/net-http/httpresponse/reading_body_spec.rb
@@ -22,7 +22,7 @@ describe "Net::HTTPResponse#reading_body" do
yielded = true
end
- yielded.should be_true
+ yielded.should == true
end
describe "but the response type is not allowed to have a body" do
@@ -31,28 +31,28 @@ describe "Net::HTTPResponse#reading_body" do
end
it "returns nil" do
- @res.reading_body(@socket, false) {}.should be_nil
- @res.body.should be_nil
+ @res.reading_body(@socket, false) {}.should == nil
+ @res.body.should == nil
end
it "yields the passed block" do
yielded = false
@res.reading_body(@socket, true) { yielded = true }
- yielded.should be_true
+ yielded.should == 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
+ @res.reading_body(@socket, false) {}.should == nil
+ @res.body.should == nil
end
it "yields the passed block" do
yielded = false
@res.reading_body(@socket, true) { yielded = true }
- yielded.should be_true
+ yielded.should == 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
index caa0ca2d19..440c33c168 100644
--- a/spec/ruby/library/net-http/httpresponse/response_spec.rb
+++ b/spec/ruby/library/net-http/httpresponse/response_spec.rb
@@ -4,6 +4,6 @@ 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)
+ 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
deleted file mode 100644
index 618e3936fb..0000000000
--- a/spec/ruby/library/net-http/httpresponse/shared/body.rb
+++ /dev/null
@@ -1,20 +0,0 @@
-require 'stringio'
-
-describe :net_httpresponse_body, shared: true do
- before :each do
- @res = Net::HTTPUnknownResponse.new("1.0", "???", "test response")
- @socket = Net::BufferedIO.new(StringIO.new("test body"))
- end
-
- it "returns the read body" do
- @res.reading_body(@socket, true) do
- @res.send(@method).should == "test body"
- end
- end
-
- it "returns the previously read body if called a second time" do
- @res.reading_body(@socket, true) do
- @res.send(@method).should equal(@res.send(@method))
- end
- end
-end
diff --git a/spec/ruby/library/net-http/httpresponse/value_spec.rb b/spec/ruby/library/net-http/httpresponse/value_spec.rb
index 2df8beaa10..e32d37500a 100644
--- a/spec/ruby/library/net-http/httpresponse/value_spec.rb
+++ b/spec/ruby/library/net-http/httpresponse/value_spec.rb
@@ -4,21 +4,21 @@ 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.value }.should.raise(Net::HTTPError)
res = Net::HTTPInformation.new("1.0", "1xx", "test response")
- -> { res.value }.should raise_error(Net::HTTPError)
+ -> { res.value }.should.raise(Net::HTTPError)
res = Net::HTTPSuccess.new("1.0", "2xx", "test response")
- -> { res.value }.should_not raise_error(Net::HTTPError)
+ -> { res.value }.should_not.raise(Net::HTTPError)
res = Net::HTTPRedirection.new("1.0", "3xx", "test response")
- -> { res.value }.should raise_error(Net::HTTPRetriableError)
+ -> { res.value }.should.raise(Net::HTTPRetriableError)
res = Net::HTTPClientError.new("1.0", "4xx", "test response")
- -> { res.value }.should raise_error(Net::HTTPClientException)
+ -> { res.value }.should.raise(Net::HTTPClientException)
res = Net::HTTPServerError.new("1.0", "5xx", "test response")
- -> { res.value }.should raise_error(Net::HTTPFatalError)
+ -> { res.value }.should.raise(Net::HTTPFatalError)
end
end
diff --git a/spec/ruby/library/objectspace/dump_all_spec.rb b/spec/ruby/library/objectspace/dump_all_spec.rb
index e9b449a905..c92812ebd5 100644
--- a/spec/ruby/library/objectspace/dump_all_spec.rb
+++ b/spec/ruby/library/objectspace/dump_all_spec.rb
@@ -82,7 +82,7 @@ describe "ObjectSpace.dump_all" do
ObjectSpace.dump_all(output: :stdout)
RUBY
- stdout.should include('"value":"abc"')
+ stdout.should.include?('"value":"abc"')
end
it "dumps Ruby heap to provided IO when passed output: IO" do
@@ -107,6 +107,6 @@ describe "ObjectSpace.dump_all" do
end
it "raises ArgumentError when passed not supported :output value" do
- -> { ObjectSpace.dump_all(output: Object.new) }.should raise_error(ArgumentError, /wrong output option/)
+ -> { ObjectSpace.dump_all(output: Object.new) }.should.raise(ArgumentError, /wrong output option/)
end
end
diff --git a/spec/ruby/library/objectspace/dump_spec.rb b/spec/ruby/library/objectspace/dump_spec.rb
index e22ee3df1e..4b5e0da198 100644
--- a/spec/ruby/library/objectspace/dump_spec.rb
+++ b/spec/ruby/library/objectspace/dump_spec.rb
@@ -13,23 +13,23 @@ describe "ObjectSpace.dump" do
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"')
+ string.should.is_a?(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"')
+ string.should.is_a?(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.should.is_a?(File)
file.rewind
content = file.read
- content.should include('"value":"abc"')
+ content.should.include?('"value":"abc"')
ensure
file.close
File.unlink file.path
@@ -37,10 +37,10 @@ describe "ObjectSpace.dump" do
it "dumps to a temporary file when passed output: :nil" do
file = ObjectSpace.dump("abc", output: nil)
- file.should be_kind_of(File)
+ file.should.is_a?(File)
file.rewind
- file.read.should include('"value":"abc"')
+ file.read.should.include?('"value":"abc"')
ensure
file.close
File.unlink file.path
@@ -48,7 +48,7 @@ describe "ObjectSpace.dump" do
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"')
+ stdout.should.include?('"value":"abc"')
end
it "dumps to provided IO when passed output: IO" do
@@ -58,13 +58,13 @@ describe "ObjectSpace.dump" do
result.should.equal? io
io.rewind
- io.read.should include('"value":"abc"')
+ 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/)
+ -> { ObjectSpace.dump("abc", output: Object.new) }.should.raise(ArgumentError, /wrong output option/)
end
end
diff --git a/spec/ruby/library/objectspace/memsize_of_all_spec.rb b/spec/ruby/library/objectspace/memsize_of_all_spec.rb
index c5a48165ce..9fc6e8be9d 100644
--- a/spec/ruby/library/objectspace/memsize_of_all_spec.rb
+++ b/spec/ruby/library/objectspace/memsize_of_all_spec.rb
@@ -3,12 +3,12 @@ require 'objspace'
describe "ObjectSpace.memsize_of_all" do
it "returns a non-zero Integer for all objects" do
- ObjectSpace.memsize_of_all.should be_kind_of(Integer)
+ ObjectSpace.memsize_of_all.should.is_a?(Integer)
ObjectSpace.memsize_of_all.should > 0
end
it "returns a non-zero Integer for Class" do
- ObjectSpace.memsize_of_all(Class).should be_kind_of(Integer)
+ ObjectSpace.memsize_of_all(Class).should.is_a?(Integer)
ObjectSpace.memsize_of_all(Class).should > 0
end
diff --git a/spec/ruby/library/objectspace/memsize_of_spec.rb b/spec/ruby/library/objectspace/memsize_of_spec.rb
index cbb5a07d54..9c8aea4e84 100644
--- a/spec/ruby/library/objectspace/memsize_of_spec.rb
+++ b/spec/ruby/library/objectspace/memsize_of_spec.rb
@@ -18,7 +18,7 @@ describe "ObjectSpace.memsize_of" do
it "returns a positive Integer for an Object" do
obj = Object.new
- ObjectSpace.memsize_of(obj).should be_kind_of(Integer)
+ ObjectSpace.memsize_of(obj).should.is_a?(Integer)
ObjectSpace.memsize_of(obj).should > 0
end
diff --git a/spec/ruby/library/objectspace/reachable_objects_from_spec.rb b/spec/ruby/library/objectspace/reachable_objects_from_spec.rb
index dee5961663..4620bdec31 100644
--- a/spec/ruby/library/objectspace/reachable_objects_from_spec.rb
+++ b/spec/ruby/library/objectspace/reachable_objects_from_spec.rb
@@ -16,7 +16,7 @@ describe "ObjectSpace.reachable_objects_from" do
end
it "enumerates objects directly reachable from a given object" do
- ObjectSpace.reachable_objects_from(['a', 'b', 'c']).should include(Array, 'a', 'b', 'c')
+ ObjectSpace.reachable_objects_from(['a', 'b', 'c']).to_set.should >= Set[Array, 'a', 'b', 'c']
ObjectSpace.reachable_objects_from(Object.new).should == [Object]
end
@@ -24,7 +24,7 @@ describe "ObjectSpace.reachable_objects_from" do
obj = Object.new
ary = [obj]
reachable = ObjectSpace.reachable_objects_from(ary)
- reachable.should include(obj)
+ reachable.should.include?(obj)
end
it "finds an object stored in a copy-on-write Array" do
@@ -33,8 +33,8 @@ describe "ObjectSpace.reachable_objects_from" do
ary = [removed, obj]
ary.shift
reachable = ObjectSpace.reachable_objects_from(ary)
- reachable.should include(obj)
- reachable.should_not include(removed)
+ reachable.should.include?(obj)
+ reachable.should_not.include?(removed)
end
it "finds an object stored in a Queue" do
@@ -44,7 +44,7 @@ describe "ObjectSpace.reachable_objects_from" do
reachable = ObjectSpace.reachable_objects_from(q)
reachable = reachable + reachable.flat_map { |r| ObjectSpace.reachable_objects_from(r) }
- reachable.should include(o)
+ reachable.should.include?(o)
end
it "finds an object stored in a SizedQueue" do
@@ -54,6 +54,6 @@ describe "ObjectSpace.reachable_objects_from" do
reachable = ObjectSpace.reachable_objects_from(q)
reachable = reachable + reachable.flat_map { |r| ObjectSpace.reachable_objects_from(r) }
- reachable.should include(o)
+ reachable.should.include?(o)
end
end
diff --git a/spec/ruby/library/objectspace/trace_object_allocations_spec.rb b/spec/ruby/library/objectspace/trace_object_allocations_spec.rb
index 0f1e2aa8b9..0bb6efbfa5 100644
--- a/spec/ruby/library/objectspace/trace_object_allocations_spec.rb
+++ b/spec/ruby/library/objectspace/trace_object_allocations_spec.rb
@@ -74,7 +74,7 @@ describe "ObjectSpace.trace_object_allocations" do
o = Object.new
ObjectSpace.allocation_class_path(o).should == obj_class_path
ObjectSpace.trace_object_allocations_clear
- ObjectSpace.allocation_class_path(o).should be_nil
+ ObjectSpace.allocation_class_path(o).should == nil
end
end
diff --git a/spec/ruby/library/observer/notify_observers_spec.rb b/spec/ruby/library/observer/notify_observers_spec.rb
index 31f82e9266..6f3f984637 100644
--- a/spec/ruby/library/observer/notify_observers_spec.rb
+++ b/spec/ruby/library/observer/notify_observers_spec.rb
@@ -18,7 +18,7 @@ describe "Observer#notify_observers" do
it "verifies observer responds to update" do
-> {
@observable.add_observer(@observable)
- }.should raise_error(NoMethodError)
+ }.should.raise(NoMethodError)
end
it "receives the callback" do
diff --git a/spec/ruby/library/open3/popen3_spec.rb b/spec/ruby/library/open3/popen3_spec.rb
index d3103ad3cb..3651bd516c 100644
--- a/spec/ruby/library/open3/popen3_spec.rb
+++ b/spec/ruby/library/open3/popen3_spec.rb
@@ -5,10 +5,10 @@ describe "Open3.popen3" do
it "returns in, out, err and a thread waiting the process" do
stdin, out, err, waiter = Open3.popen3(ruby_cmd("print :foo"))
begin
- stdin.should be_kind_of IO
- out.should be_kind_of IO
- err.should be_kind_of IO
- waiter.should be_kind_of Thread
+ stdin.should.is_a? IO
+ out.should.is_a? IO
+ err.should.is_a? IO
+ waiter.should.is_a? Thread
out.read.should == "foo"
ensure
diff --git a/spec/ruby/library/openssl/cipher_spec.rb b/spec/ruby/library/openssl/cipher_spec.rb
index f66f25f9c6..91da1c592c 100644
--- a/spec/ruby/library/openssl/cipher_spec.rb
+++ b/spec/ruby/library/openssl/cipher_spec.rb
@@ -4,6 +4,6 @@ require 'openssl'
describe "OpenSSL::Cipher's CipherError" do
it "exists under OpenSSL::Cipher namespace" do
- OpenSSL::Cipher.should have_constant :CipherError
+ OpenSSL::Cipher.should.const_defined?(:CipherError, false)
end
end
diff --git a/spec/ruby/library/openssl/digest/initialize_spec.rb b/spec/ruby/library/openssl/digest/initialize_spec.rb
index 1cd0409c4d..e24ab51d14 100644
--- a/spec/ruby/library/openssl/digest/initialize_spec.rb
+++ b/spec/ruby/library/openssl/digest/initialize_spec.rb
@@ -23,18 +23,14 @@ describe "OpenSSL::Digest#initialize" 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\)/)
+ version_is OpenSSL::VERSION, "4.0.0" do
+ it "throws an error when called with an unknown digest" do
+ -> { OpenSSL::Digest.new("wd40") }.should.raise(OpenSSL::Digest::DigestError, /wd40/)
+ end
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/)
+ -> { OpenSSL::Digest.new(:SHA1) }.should.raise(TypeError)
end
end
@@ -62,7 +58,7 @@ describe "OpenSSL::Digest#initialize" do
end
it "cannot be called with a digest class" do
- -> { OpenSSL::Digest.new(OpenSSL::Digest::SHA1) }.should raise_error(TypeError, /wrong argument type Class/)
+ -> { OpenSSL::Digest.new(OpenSSL::Digest::SHA1) }.should.raise(TypeError)
end
context "when called without an initial String argument" do
diff --git a/spec/ruby/library/openssl/digest/shared/update.rb b/spec/ruby/library/openssl/digest/shared/update.rb
index e5ff9dcb16..37277c945d 100644
--- a/spec/ruby/library/openssl/digest/shared/update.rb
+++ b/spec/ruby/library/openssl/digest/shared/update.rb
@@ -96,28 +96,28 @@ describe :openssl_digest_update, shared: true do
digest = OpenSSL::Digest.new('sha1')
-> {
digest.send(@method, Object.new)
- }.should raise_error(TypeError, 'no implicit conversion of Object into String')
+ }.should.raise(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')
+ }.should.raise(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')
+ }.should.raise(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')
+ }.should.raise(TypeError, 'no implicit conversion of Object into String')
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
index 5a2ca168b5..cc638e1f0d 100644
--- a/spec/ruby/library/openssl/fixed_length_secure_compare_spec.rb
+++ b/spec/ruby/library/openssl/fixed_length_secure_compare_spec.rb
@@ -5,13 +5,13 @@ 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
+ OpenSSL.fixed_length_secure_compare(input1, input2).should == 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
+ OpenSSL.fixed_length_secure_compare(input1, input2).should == false
end
it "converts both arguments to strings using #to_str" do
@@ -19,17 +19,17 @@ describe "OpenSSL.fixed_length_secure_compare" do
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
+ OpenSSL.fixed_length_secure_compare(input1, input2).should == 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')
+ }.should.raise(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')
+ }.should.raise(TypeError, 'no implicit conversion of Object into String')
end
it "raises an ArgumentError for two strings of different size" do
@@ -37,6 +37,6 @@ describe "OpenSSL.fixed_length_secure_compare" do
input2 = "the quick brown fox"
-> {
OpenSSL.fixed_length_secure_compare(input1, input2)
- }.should raise_error(ArgumentError, 'inputs must be of equal length')
+ }.should.raise(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
index 40f8597275..2558dbb9ec 100644
--- a/spec/ruby/library/openssl/kdf/pbkdf2_hmac_spec.rb
+++ b/spec/ruby/library/openssl/kdf/pbkdf2_hmac_spec.rb
@@ -83,86 +83,80 @@ describe "OpenSSL::KDF.pbkdf2_hmac" do
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")
+ }.should.raise(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")
+ }.should.raise(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")
+ }.should.raise(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")
+ }.should.raise(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)")
+ }.should.raise(TypeError)
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\)/)
+ version_is OpenSSL::VERSION, "4.0.0" do
+ it "raises a OpenSSL::Digest::DigestError for unknown digest algorithms" do
+ -> {
+ OpenSSL::KDF.pbkdf2_hmac("secret", **@defaults, hash: "wd40")
+ }.should.raise(OpenSSL::Digest::DigestError, /wd40/)
+ end
end
it "treats salt as a required keyword" do
-> {
OpenSSL::KDF.pbkdf2_hmac("secret", **@defaults.except(:salt))
- }.should raise_error(ArgumentError, 'missing keyword: :salt')
+ }.should.raise(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')
+ }.should.raise(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')
+ }.should.raise(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')
+ }.should.raise(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')
+ }.should.raise(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")
+ }.should.raise(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/)
+ }.should.raise(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
index e01b8bca8a..c00f91bb5b 100644
--- a/spec/ruby/library/openssl/kdf/scrypt_spec.rb
+++ b/spec/ruby/library/openssl/kdf/scrypt_spec.rb
@@ -89,79 +89,79 @@ guard -> { OpenSSL::OPENSSL_VERSION.start_with?('OpenSSL') and OpenSSL::OPENSSL_
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")
+ }.should.raise(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")
+ }.should.raise(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")
+ }.should.raise(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")
+ }.should.raise(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")
+ }.should.raise(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")
+ }.should.raise(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')
+ }.should.raise(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')
+ }.should.raise(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')
+ }.should.raise(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')
+ }.should.raise(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')
+ }.should.raise(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')
+ }.should.raise(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/)
+ }.should.raise(OpenSSL::KDF::KDFError, /EVP_PBE_scrypt/)
end
it "requires N to be at least 2" do
@@ -170,41 +170,41 @@ guard -> { OpenSSL::OPENSSL_VERSION.start_with?('OpenSSL') and OpenSSL::OPENSSL_
-> {
OpenSSL::KDF.scrypt("secret", **@defaults, N: 1)
- }.should raise_error(OpenSSL::KDF::KDFError, /EVP_PBE_scrypt/)
+ }.should.raise(OpenSSL::KDF::KDFError, /EVP_PBE_scrypt/)
-> {
OpenSSL::KDF.scrypt("secret", **@defaults, N: 0)
- }.should raise_error(OpenSSL::KDF::KDFError, /EVP_PBE_scrypt/)
+ }.should.raise(OpenSSL::KDF::KDFError, /EVP_PBE_scrypt/)
-> {
OpenSSL::KDF.scrypt("secret", **@defaults, N: -1)
- }.should raise_error(OpenSSL::KDF::KDFError, /EVP_PBE_scrypt/)
+ }.should.raise(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/)
+ }.should.raise(OpenSSL::KDF::KDFError, /EVP_PBE_scrypt/)
-> {
OpenSSL::KDF.scrypt("secret", **@defaults, r: -1)
- }.should raise_error(OpenSSL::KDF::KDFError, /EVP_PBE_scrypt/)
+ }.should.raise(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/)
+ }.should.raise(OpenSSL::KDF::KDFError, /EVP_PBE_scrypt/)
-> {
OpenSSL::KDF.scrypt("secret", **@defaults, p: -1)
- }.should raise_error(OpenSSL::KDF::KDFError, /EVP_PBE_scrypt/)
+ }.should.raise(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)")
+ }.should.raise(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..4d1751e57e 100644
--- a/spec/ruby/library/openssl/random/shared/random_bytes.rb
+++ b/spec/ruby/library/openssl/random/shared/random_bytes.rb
@@ -5,7 +5,7 @@ describe :openssl_random_bytes, shared: true do
it "generates a random binary string of specified length" do
(1..64).each do |idx|
bytes = OpenSSL::Random.send(@method, idx)
- bytes.should be_kind_of(String)
+ bytes.should.is_a?(String)
bytes.length.should == idx
end
end
@@ -24,6 +24,6 @@ describe :openssl_random_bytes, shared: true do
it "raises ArgumentError on negative arguments" do
-> {
OpenSSL::Random.send(@method, -1)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
end
diff --git a/spec/ruby/library/openssl/secure_compare_spec.rb b/spec/ruby/library/openssl/secure_compare_spec.rb
index cec48e01e7..ce2a4a0d43 100644
--- a/spec/ruby/library/openssl/secure_compare_spec.rb
+++ b/spec/ruby/library/openssl/secure_compare_spec.rb
@@ -5,13 +5,13 @@ 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
+ OpenSSL.secure_compare(input1, input2).should == 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
+ OpenSSL.secure_compare(input1, input2).should == false
end
it "converts both arguments to strings using #to_str, but adds equality check for the original objects" do
@@ -19,20 +19,20 @@ describe "OpenSSL.secure_compare" do
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
+ OpenSSL.secure_compare(input1, input2).should == 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
+ OpenSSL.secure_compare(input, input).should == 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')
+ }.should.raise(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')
+ }.should.raise(TypeError, 'no implicit conversion of Object into String')
end
end
diff --git a/spec/ruby/library/openssl/x509/name/parse_spec.rb b/spec/ruby/library/openssl/x509/name/parse_spec.rb
index 6624161d83..84e3d442f6 100644
--- a/spec/ruby/library/openssl/x509/name/parse_spec.rb
+++ b/spec/ruby/library/openssl/x509/name/parse_spec.rb
@@ -37,12 +37,12 @@ describe "OpenSSL::X509::Name.parse" do
it "raises TypeError if the given string contains no key/value pairs" do
-> do
OpenSSL::X509::Name.parse("hello")
- end.should raise_error(TypeError)
+ end.should.raise(TypeError)
end
it "raises OpenSSL::X509::NameError if the given string contains invalid keys" do
-> do
OpenSSL::X509::Name.parse("hello=goodbye")
- end.should raise_error(OpenSSL::X509::NameError)
+ end.should.raise(OpenSSL::X509::NameError)
end
end
diff --git a/spec/ruby/library/openstruct/delete_field_spec.rb b/spec/ruby/library/openstruct/delete_field_spec.rb
index 9ac80196cc..12fed6c90d 100644
--- a/spec/ruby/library/openstruct/delete_field_spec.rb
+++ b/spec/ruby/library/openstruct/delete_field_spec.rb
@@ -8,12 +8,12 @@ describe "OpenStruct#delete_field" do
it "removes the named field from self's method/value table" do
@os.delete_field(:name)
- @os[:name].should be_nil
+ @os[:name].should == nil
end
it "does remove the accessor methods" do
@os.delete_field(:name)
- @os.respond_to?(:name).should be_false
- @os.respond_to?(:name=).should be_false
+ @os.respond_to?(:name).should == false
+ @os.respond_to?(:name=).should == false
end
end
diff --git a/spec/ruby/library/openstruct/equal_value_spec.rb b/spec/ruby/library/openstruct/equal_value_spec.rb
index 103ac13588..ec30214fd3 100644
--- a/spec/ruby/library/openstruct/equal_value_spec.rb
+++ b/spec/ruby/library/openstruct/equal_value_spec.rb
@@ -1,5 +1,5 @@
require_relative '../../spec_helper'
-require "ostruct"
+require 'ostruct'
require_relative 'fixtures/classes'
describe "OpenStruct#==" do
@@ -8,21 +8,21 @@ describe "OpenStruct#==" do
end
it "returns false when the passed argument is no OpenStruct" do
- (@os == Object.new).should be_false
- (@os == "Test").should be_false
- (@os == 10).should be_false
- (@os == :sym).should be_false
+ (@os == Object.new).should == false
+ (@os == "Test").should == false
+ (@os == 10).should == false
+ (@os == :sym).should == false
end
it "returns true when self and other are equal method/value wise" do
- (@os == @os).should be_true
- (@os == OpenStruct.new(name: "John")).should be_true
- (@os == OpenStructSpecs::OpenStructSub.new(name: "John")).should be_true
+ (@os == @os).should == true
+ (@os == OpenStruct.new(name: "John")).should == true
+ (@os == OpenStructSpecs::OpenStructSub.new(name: "John")).should == true
- (@os == OpenStruct.new(name: "Jonny")).should be_false
- (@os == OpenStructSpecs::OpenStructSub.new(name: "Jonny")).should be_false
+ (@os == OpenStruct.new(name: "Jonny")).should == false
+ (@os == OpenStructSpecs::OpenStructSub.new(name: "Jonny")).should == false
- (@os == OpenStruct.new(name: "John", age: 20)).should be_false
- (@os == OpenStructSpecs::OpenStructSub.new(name: "John", age: 20)).should be_false
+ (@os == OpenStruct.new(name: "John", age: 20)).should == false
+ (@os == OpenStructSpecs::OpenStructSub.new(name: "John", age: 20)).should == false
end
end
diff --git a/spec/ruby/library/openstruct/frozen_spec.rb b/spec/ruby/library/openstruct/frozen_spec.rb
index c14a4bac55..c37fd18c8c 100644
--- a/spec/ruby/library/openstruct/frozen_spec.rb
+++ b/spec/ruby/library/openstruct/frozen_spec.rb
@@ -9,25 +9,25 @@ describe "OpenStruct.new when frozen" do
# method_missing case handled in method_missing_spec.rb
#
it "is still readable" do
- @os.age.should eql(70)
- @os.pension.should eql(300)
+ @os.age.should.eql?(70)
+ @os.pension.should.eql?(300)
@os.name.should == "John Smith"
end
it "is not writable" do
- ->{ @os.age = 42 }.should raise_error( RuntimeError )
+ ->{ @os.age = 42 }.should.raise( RuntimeError )
end
it "cannot create new fields" do
- ->{ @os.state = :new }.should raise_error( RuntimeError )
+ ->{ @os.state = :new }.should.raise( RuntimeError )
end
it "creates a frozen clone" do
f = @os.clone
f.frozen?.should == true
f.age.should == 70
- ->{ f.age = 0 }.should raise_error( RuntimeError )
- ->{ f.state = :newer }.should raise_error( RuntimeError )
+ ->{ f.age = 0 }.should.raise( RuntimeError )
+ ->{ f.state = :newer }.should.raise( RuntimeError )
end
it "creates an unfrozen dup" do
diff --git a/spec/ruby/library/openstruct/initialize_spec.rb b/spec/ruby/library/openstruct/initialize_spec.rb
index dee5de48c6..52304cf780 100644
--- a/spec/ruby/library/openstruct/initialize_spec.rb
+++ b/spec/ruby/library/openstruct/initialize_spec.rb
@@ -3,6 +3,6 @@ require 'ostruct'
describe "OpenStruct#initialize" do
it "is private" do
- OpenStruct.should have_private_instance_method(:initialize)
+ OpenStruct.private_instance_methods(false).should.include?(:initialize)
end
end
diff --git a/spec/ruby/library/openstruct/inspect_spec.rb b/spec/ruby/library/openstruct/inspect_spec.rb
index e2fed41528..81da96d6bf 100644
--- a/spec/ruby/library/openstruct/inspect_spec.rb
+++ b/spec/ruby/library/openstruct/inspect_spec.rb
@@ -1,8 +1,8 @@
require_relative '../../spec_helper'
require 'ostruct'
-require_relative 'fixtures/classes'
-require_relative 'shared/inspect'
describe "OpenStruct#inspect" do
- it_behaves_like :ostruct_inspect, :inspect
+ it "is an alias of OpenStruct#to_s" do
+ OpenStruct.instance_method(:inspect).should == OpenStruct.instance_method(:to_s)
+ end
end
diff --git a/spec/ruby/library/openstruct/marshal_load_spec.rb b/spec/ruby/library/openstruct/marshal_load_spec.rb
index 342e5e68cd..a8cdda3b43 100644
--- a/spec/ruby/library/openstruct/marshal_load_spec.rb
+++ b/spec/ruby/library/openstruct/marshal_load_spec.rb
@@ -6,7 +6,7 @@ describe "OpenStruct#marshal_load when passed [Hash]" do
os = OpenStruct.new
os.send :marshal_load, age: 20, name: "John"
- os.age.should eql(20)
+ os.age.should.eql?(20)
os.name.should == "John"
end
end
diff --git a/spec/ruby/library/openstruct/method_missing_spec.rb b/spec/ruby/library/openstruct/method_missing_spec.rb
index 89f83d07b3..cf6734d629 100644
--- a/spec/ruby/library/openstruct/method_missing_spec.rb
+++ b/spec/ruby/library/openstruct/method_missing_spec.rb
@@ -7,18 +7,18 @@ describe "OpenStruct#method_missing when called with a method name ending in '='
end
it "raises an ArgumentError when not passed any additional arguments" do
- -> { @os.send(:test=) }.should raise_error(ArgumentError)
+ -> { @os.send(:test=) }.should.raise(ArgumentError)
end
end
describe "OpenStruct#method_missing when passed additional arguments" do
it "raises a NoMethodError when the key does not exist" do
os = OpenStruct.new
- -> { os.test(1, 2, 3) }.should raise_error(NoMethodError)
+ -> { os.test(1, 2, 3) }.should.raise(NoMethodError)
end
it "raises an ArgumentError when the key exists" do
os = OpenStruct.new(test: 20)
- -> { os.test(1, 2, 3) }.should raise_error(ArgumentError)
+ -> { os.test(1, 2, 3) }.should.raise(ArgumentError)
end
end
diff --git a/spec/ruby/library/openstruct/new_spec.rb b/spec/ruby/library/openstruct/new_spec.rb
index 5d2cacea40..9e53948c82 100644
--- a/spec/ruby/library/openstruct/new_spec.rb
+++ b/spec/ruby/library/openstruct/new_spec.rb
@@ -7,8 +7,8 @@ describe "OpenStruct.new when passed [Hash]" do
end
it "creates an attribute for each key of the passed Hash" do
- @os.age.should eql(70)
- @os.pension.should eql(300)
+ @os.age.should.eql?(70)
+ @os.pension.should.eql?(300)
@os.name.should == "John Smith"
end
end
diff --git a/spec/ruby/library/openstruct/shared/inspect.rb b/spec/ruby/library/openstruct/shared/inspect.rb
deleted file mode 100644
index ffcd690e1f..0000000000
--- a/spec/ruby/library/openstruct/shared/inspect.rb
+++ /dev/null
@@ -1,20 +0,0 @@
-describe :ostruct_inspect, shared: true do
- it "returns a String representation of self" do
- os = OpenStruct.new(name: "John Smith")
- os.send(@method).should == "#<OpenStruct name=\"John Smith\">"
-
- os = OpenStruct.new(age: 20, name: "John Smith")
- os.send(@method).should be_kind_of(String)
- end
-
- it "correctly handles self-referential OpenStructs" do
- os = OpenStruct.new
- os.self = os
- os.send(@method).should == "#<OpenStruct self=#<OpenStruct ...>>"
- end
-
- it "correctly handles OpenStruct subclasses" do
- os = OpenStructSpecs::OpenStructSub.new(name: "John Smith")
- os.send(@method).should == "#<OpenStructSpecs::OpenStructSub name=\"John Smith\">"
- end
-end
diff --git a/spec/ruby/library/openstruct/to_h_spec.rb b/spec/ruby/library/openstruct/to_h_spec.rb
index 6c272bcc71..7d9c7db5dc 100644
--- a/spec/ruby/library/openstruct/to_h_spec.rb
+++ b/spec/ruby/library/openstruct/to_h_spec.rb
@@ -19,7 +19,7 @@ describe "OpenStruct#to_h" do
end
it "does not return the hash used as initializer" do
- @to_h.should_not equal(@h)
+ @to_h.should_not.equal?(@h)
end
it "returns a Hash that is independent from the struct" do
@@ -36,17 +36,17 @@ describe "OpenStruct#to_h" do
it "raises ArgumentError if block returns longer or shorter array" do
-> do
@os.to_h { |k, v| [k.to_s, v*2, 1] }
- end.should raise_error(ArgumentError, /element has wrong array length/)
+ end.should.raise(ArgumentError, /element has wrong array length/)
-> do
@os.to_h { |k, v| [k] }
- end.should raise_error(ArgumentError, /element has wrong array length/)
+ end.should.raise(ArgumentError, /element has wrong array length/)
end
it "raises TypeError if block returns something other than Array" do
-> do
@os.to_h { |k, v| "not-array" }
- end.should raise_error(TypeError, /wrong element type String/)
+ end.should.raise(TypeError, /wrong element type String/)
end
it "coerces returned pair to Array with #to_ary" do
@@ -62,7 +62,7 @@ describe "OpenStruct#to_h" do
-> do
@os.to_h { |k| x }
- end.should raise_error(TypeError, /wrong element type MockObject/)
+ end.should.raise(TypeError, /wrong element type MockObject/)
end
end
end
diff --git a/spec/ruby/library/openstruct/to_s_spec.rb b/spec/ruby/library/openstruct/to_s_spec.rb
index 73d91bf981..9131cd4897 100644
--- a/spec/ruby/library/openstruct/to_s_spec.rb
+++ b/spec/ruby/library/openstruct/to_s_spec.rb
@@ -1,8 +1,24 @@
require_relative '../../spec_helper'
require 'ostruct'
require_relative 'fixtures/classes'
-require_relative 'shared/inspect'
describe "OpenStruct#to_s" do
- it_behaves_like :ostruct_inspect, :to_s
+ it "returns a String representation of self" do
+ os = OpenStruct.new(name: "John Smith")
+ os.to_s.should == "#<OpenStruct name=\"John Smith\">"
+
+ os = OpenStruct.new(age: 20, name: "John Smith")
+ os.to_s.should.is_a?(String)
+ end
+
+ it "correctly handles self-referential OpenStructs" do
+ os = OpenStruct.new
+ os.self = os
+ os.to_s.should == "#<OpenStruct self=#<OpenStruct ...>>"
+ end
+
+ it "correctly handles OpenStruct subclasses" do
+ os = OpenStructSpecs::OpenStructSub.new(name: "John Smith")
+ os.to_s.should == "#<OpenStructSpecs::OpenStructSub name=\"John Smith\">"
+ end
end
diff --git a/spec/ruby/library/pathname/birthtime_spec.rb b/spec/ruby/library/pathname/birthtime_spec.rb
index 109c112303..387f0aa54d 100644
--- a/spec/ruby/library/pathname/birthtime_spec.rb
+++ b/spec/ruby/library/pathname/birthtime_spec.rb
@@ -4,13 +4,13 @@ require 'pathname'
describe "Pathname#birthtime" do
platform_is :windows, :darwin, :freebsd, :netbsd do
it "returns the birth time for self" do
- Pathname.new(__FILE__).birthtime.should be_kind_of(Time)
+ Pathname.new(__FILE__).birthtime.should.is_a?(Time)
end
end
platform_is :openbsd do
it "raises an NotImplementedError" do
- -> { Pathname.new(__FILE__).birthtime }.should raise_error(NotImplementedError)
+ -> { Pathname.new(__FILE__).birthtime }.should.raise(NotImplementedError)
end
end
end
diff --git a/spec/ruby/library/pathname/case_compare_spec.rb b/spec/ruby/library/pathname/case_compare_spec.rb
new file mode 100644
index 0000000000..0cf799dd23
--- /dev/null
+++ b/spec/ruby/library/pathname/case_compare_spec.rb
@@ -0,0 +1,8 @@
+require_relative '../../spec_helper'
+require 'pathname'
+
+describe "Pathname#===" do
+ it "is an alias of Pathname#==" do
+ Pathname.instance_method(:===).should == Pathname.instance_method(:==)
+ end
+end
diff --git a/spec/ruby/library/pathname/divide_spec.rb b/spec/ruby/library/pathname/divide_spec.rb
index 8af79d0c8f..e5afc9f864 100644
--- a/spec/ruby/library/pathname/divide_spec.rb
+++ b/spec/ruby/library/pathname/divide_spec.rb
@@ -1,6 +1,8 @@
require_relative '../../spec_helper'
-require_relative 'shared/plus'
+require 'pathname'
describe "Pathname#/" do
- it_behaves_like :pathname_plus, :/
+ it "is an alias of Pathname#+" do
+ Pathname.instance_method(:/).should == Pathname.instance_method(:+)
+ end
end
diff --git a/spec/ruby/library/pathname/empty_spec.rb b/spec/ruby/library/pathname/empty_spec.rb
index 4deade5b64..9f0305a0f0 100644
--- a/spec/ruby/library/pathname/empty_spec.rb
+++ b/spec/ruby/library/pathname/empty_spec.rb
@@ -15,18 +15,18 @@ describe 'Pathname#empty?' do
end
it 'returns true when file is not empty' do
- Pathname.new(__FILE__).empty?.should be_false
+ Pathname.new(__FILE__).empty?.should == false
end
it 'returns false when the directory is not empty' do
- Pathname.new(__dir__).empty?.should be_false
+ Pathname.new(__dir__).empty?.should == false
end
it 'return true when file is empty' do
- Pathname.new(@file).empty?.should be_true
+ Pathname.new(@file).empty?.should == true
end
it 'returns true when directory is empty' do
- Pathname.new(@dir).empty?.should be_true
+ Pathname.new(@dir).empty?.should == true
end
end
diff --git a/spec/ruby/library/pathname/glob_spec.rb b/spec/ruby/library/pathname/glob_spec.rb
index de322bab47..e20e6f8f85 100644
--- a/spec/ruby/library/pathname/glob_spec.rb
+++ b/spec/ruby/library/pathname/glob_spec.rb
@@ -41,7 +41,7 @@ describe 'Pathname.glob' do
it "raises an ArgumentError when supplied a keyword argument other than :base" do
-> {
Pathname.glob('*i*.rb', foo: @dir + 'lib')
- }.should raise_error(ArgumentError, /unknown keyword: :?foo/)
+ }.should.raise(ArgumentError, "unknown keyword: :foo")
end
it "does not raise an ArgumentError when supplied a flag and :base keyword argument" do
@@ -81,7 +81,7 @@ describe 'Pathname#glob' do
it 'yields matching file paths to block' do
ary = []
- Pathname.new(@dir).glob('lib/*i*.rb') { |p| ary << p }.should be_nil
+ Pathname.new(@dir).glob('lib/*i*.rb') { |p| ary << p }.should == nil
ary.sort.should == [Pathname.new(@file_1), Pathname.new(@file_2)].sort
end
diff --git a/spec/ruby/library/pathname/inspect_spec.rb b/spec/ruby/library/pathname/inspect_spec.rb
index 304746fbe5..3abba6cbb5 100644
--- a/spec/ruby/library/pathname/inspect_spec.rb
+++ b/spec/ruby/library/pathname/inspect_spec.rb
@@ -4,7 +4,7 @@ require 'pathname'
describe "Pathname#inspect" do
it "returns a consistent String" do
result = Pathname.new('/tmp').inspect
- result.should be_an_instance_of(String)
+ result.should.instance_of?(String)
result.should == "#<Pathname:/tmp>"
end
end
diff --git a/spec/ruby/library/pathname/new_spec.rb b/spec/ruby/library/pathname/new_spec.rb
index 36226ed515..3ef9d9b76d 100644
--- a/spec/ruby/library/pathname/new_spec.rb
+++ b/spec/ruby/library/pathname/new_spec.rb
@@ -3,18 +3,18 @@ require 'pathname'
describe "Pathname.new" do
it "returns a new Pathname Object with 1 argument" do
- Pathname.new('').should be_kind_of(Pathname)
+ Pathname.new('').should.is_a?(Pathname)
end
it "raises an ArgumentError when called with \0" do
- -> { Pathname.new("\0")}.should raise_error(ArgumentError)
+ -> { Pathname.new("\0")}.should.raise(ArgumentError)
end
it "raises a TypeError if not passed a String type" do
- -> { Pathname.new(nil) }.should raise_error(TypeError)
- -> { Pathname.new(0) }.should raise_error(TypeError)
- -> { Pathname.new(true) }.should raise_error(TypeError)
- -> { Pathname.new(false) }.should raise_error(TypeError)
+ -> { Pathname.new(nil) }.should.raise(TypeError)
+ -> { Pathname.new(0) }.should.raise(TypeError)
+ -> { Pathname.new(true) }.should.raise(TypeError)
+ -> { Pathname.new(false) }.should.raise(TypeError)
end
it "initializes with an object with to_path" do
diff --git a/spec/ruby/library/pathname/pathname_spec.rb b/spec/ruby/library/pathname/pathname_spec.rb
index 0fb2881468..6fa6fd2bcb 100644
--- a/spec/ruby/library/pathname/pathname_spec.rb
+++ b/spec/ruby/library/pathname/pathname_spec.rb
@@ -3,11 +3,11 @@ require 'pathname'
describe "Kernel#Pathname" do
it "is a private instance method" do
- Kernel.should have_private_instance_method(:Pathname)
+ Kernel.private_instance_methods(false).should.include?(:Pathname)
end
it "is also a public method" do
- Kernel.should have_method(:Pathname)
+ Kernel.should.respond_to?(:Pathname)
end
it "returns same argument when called with a pathname argument" do
diff --git a/spec/ruby/library/pathname/plus_spec.rb b/spec/ruby/library/pathname/plus_spec.rb
index 57e472c266..76316df9d2 100644
--- a/spec/ruby/library/pathname/plus_spec.rb
+++ b/spec/ruby/library/pathname/plus_spec.rb
@@ -1,6 +1,9 @@
require_relative '../../spec_helper'
-require_relative 'shared/plus'
+require 'pathname'
describe "Pathname#+" do
- it_behaves_like :pathname_plus, :+
+ it "appends a pathname to self" do
+ p = Pathname.new("/usr")
+ (p + "bin/ruby").should == Pathname.new("/usr/bin/ruby")
+ end
end
diff --git a/spec/ruby/library/pathname/realdirpath_spec.rb b/spec/ruby/library/pathname/realdirpath_spec.rb
index a9e44e354e..e50741a737 100644
--- a/spec/ruby/library/pathname/realdirpath_spec.rb
+++ b/spec/ruby/library/pathname/realdirpath_spec.rb
@@ -4,7 +4,7 @@ require 'pathname'
describe "Pathname#realdirpath" do
it "returns a Pathname" do
- Pathname.pwd.realdirpath.should be_an_instance_of(Pathname)
+ Pathname.pwd.realdirpath.should.instance_of?(Pathname)
end
end
diff --git a/spec/ruby/library/pathname/realpath_spec.rb b/spec/ruby/library/pathname/realpath_spec.rb
index f2c654308e..d8b87f57d0 100644
--- a/spec/ruby/library/pathname/realpath_spec.rb
+++ b/spec/ruby/library/pathname/realpath_spec.rb
@@ -4,7 +4,7 @@ require 'pathname'
describe "Pathname#realpath" do
it "returns a Pathname" do
- Pathname.pwd.realpath.should be_an_instance_of(Pathname)
+ Pathname.pwd.realpath.should.instance_of?(Pathname)
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..7cbd22c3d6 100644
--- a/spec/ruby/library/pathname/relative_path_from_spec.rb
+++ b/spec/ruby/library/pathname/relative_path_from_spec.rb
@@ -7,11 +7,11 @@ describe "Pathname#relative_path_from" do
end
it "raises an error when the two paths do not share a common prefix" do
- -> { relative_path_str('/usr', 'foo') }.should raise_error(ArgumentError)
+ -> { relative_path_str('/usr', 'foo') }.should.raise(ArgumentError)
end
it "raises an error when the base directory has .." do
- -> { relative_path_str('a', '..') }.should raise_error(ArgumentError)
+ -> { relative_path_str('a', '..') }.should.raise(ArgumentError)
end
it "returns a path relative from root" do
diff --git a/spec/ruby/library/pathname/shared/plus.rb b/spec/ruby/library/pathname/shared/plus.rb
deleted file mode 100644
index b3b896ea43..0000000000
--- a/spec/ruby/library/pathname/shared/plus.rb
+++ /dev/null
@@ -1,8 +0,0 @@
-require 'pathname'
-
-describe :pathname_plus, shared: true do
- it "appends a pathname to self" do
- p = Pathname.new("/usr")
- p.send(@method, "bin/ruby").should == Pathname.new("/usr/bin/ruby")
- end
-end
diff --git a/spec/ruby/library/prime/each_spec.rb b/spec/ruby/library/prime/each_spec.rb
index b99cf7cf0e..d81e952a88 100644
--- a/spec/ruby/library/prime/each_spec.rb
+++ b/spec/ruby/library/prime/each_spec.rb
@@ -32,11 +32,11 @@ describe :prime_each, shared: true do
all_prime &&= (2..Math.sqrt(prime)).all? { |d| prime % d != 0 }
end
- all_prime.should be_true
+ all_prime.should == true
end
it "returns the last evaluated expression in the passed block" do
- @object.each { break :value }.should equal(:value)
+ @object.each { break :value }.should.equal?(:value)
end
describe "when not passed a block" do
@@ -45,23 +45,23 @@ describe :prime_each, shared: true do
end
it "returns an object that is Enumerable" do
- @prime_enum.each.should be_kind_of(Enumerable)
+ @prime_enum.each.should.is_a?(Enumerable)
end
it "returns an object that responds to #with_index" do
- @prime_enum.should respond_to(:with_index)
+ @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)
+ @prime_enum.should.respond_to?(:with_object)
end
it "returns an object that responds to #next" do
- @prime_enum.should respond_to(:next)
+ @prime_enum.should.respond_to?(:next)
end
it "returns an object that responds to #rewind" do
- @prime_enum.should respond_to(:rewind)
+ @prime_enum.should.respond_to?(:rewind)
end
it "yields primes starting at 2 independent of prior enumerators" do
@@ -106,13 +106,13 @@ describe :prime_each_with_arguments, shared: true do
ScratchPad.recorded.all? do |prime|
(2..Math.sqrt(prime)).all? { |d| prime % d != 0 }
- end.should be_true
+ end.should == true
- ScratchPad.recorded.all? { |prime| prime <= bound }.should be_true
+ ScratchPad.recorded.all? { |prime| prime <= bound }.should == true
end
it "returns nil when no prime is generated" do
- @object.each(1) { :value }.should be_nil
+ @object.each(1) { :value }.should == nil
end
it "yields primes starting at 2 independent of prior enumeration" do
@@ -132,7 +132,7 @@ describe :prime_each_with_arguments, shared: true do
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
+ @object.each(bound).all? { |prime| prime <= bound }.should == true
end
end
end
diff --git a/spec/ruby/library/prime/instance_spec.rb b/spec/ruby/library/prime/instance_spec.rb
index 5183f36901..680895eb64 100644
--- a/spec/ruby/library/prime/instance_spec.rb
+++ b/spec/ruby/library/prime/instance_spec.rb
@@ -3,12 +3,12 @@ require 'prime'
describe "Prime.instance" do
it "returns a object representing the set of prime numbers" do
- Prime.instance.should be_kind_of(Prime)
+ Prime.instance.should.is_a?(Prime)
end
it "returns a object with no obsolete features" do
- Prime.instance.should_not respond_to(:succ)
- Prime.instance.should_not respond_to(:next)
+ Prime.instance.should_not.respond_to?(:succ)
+ Prime.instance.should_not.respond_to?(:next)
end
it "does not complain anything" do
@@ -16,6 +16,6 @@ describe "Prime.instance" do
end
it "raises a ArgumentError when is called with some arguments" do
- -> { Prime.instance(1) }.should raise_error(ArgumentError)
+ -> { Prime.instance(1) }.should.raise(ArgumentError)
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..5631b22d0a 100644
--- a/spec/ruby/library/prime/integer/prime_division_spec.rb
+++ b/spec/ruby/library/prime/integer/prime_division_spec.rb
@@ -14,6 +14,6 @@ describe "Integer#prime_division" do
-1.prime_division.should == [[-1, 1]]
end
it "raises ZeroDivisionError for 0" do
- -> { 0.prime_division }.should raise_error(ZeroDivisionError)
+ -> { 0.prime_division }.should.raise(ZeroDivisionError)
end
end
diff --git a/spec/ruby/library/prime/integer/prime_spec.rb b/spec/ruby/library/prime/integer/prime_spec.rb
index 53de76d5ab..d24f883b19 100644
--- a/spec/ruby/library/prime/integer/prime_spec.rb
+++ b/spec/ruby/library/prime/integer/prime_spec.rb
@@ -3,15 +3,15 @@ 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)
+ 2.prime?.should == true
+ 3.prime?.should == true
+ (2**31-1).prime?.should == 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
+ 4.prime?.should == false
+ 15.prime?.should == false
+ (2**32-1).prime?.should == false
+ ( (2**17-1)*(2**19-1) ).prime?.should == false # M6*M7
end
end
diff --git a/spec/ruby/library/prime/next_spec.rb b/spec/ruby/library/prime/next_spec.rb
index 39c4ae16ae..07e80ab3a5 100644
--- a/spec/ruby/library/prime/next_spec.rb
+++ b/spec/ruby/library/prime/next_spec.rb
@@ -1,7 +1,11 @@
require_relative '../../spec_helper'
-require_relative 'shared/next'
require 'prime'
describe "Prime#next" do
- it_behaves_like :prime_next, :next
+ it "returns the element at the current position and moves forward" do
+ p = Prime.instance.each
+ p.next.should == 2
+ p.next.should == 3
+ p.next.next.should == 6
+ end
end
diff --git a/spec/ruby/library/prime/prime_division_spec.rb b/spec/ruby/library/prime/prime_division_spec.rb
index 6293478f59..cc39969a56 100644
--- a/spec/ruby/library/prime/prime_division_spec.rb
+++ b/spec/ruby/library/prime/prime_division_spec.rb
@@ -16,10 +16,10 @@ describe "Prime.prime_division" do
end
it "includes [[-1, 1]] in the divisors of a negative number" do
- Prime.prime_division(-10).should include([-1, 1])
+ Prime.prime_division(-10).should.include?([-1, 1])
end
it "raises ZeroDivisionError for 0" do
- -> { Prime.prime_division(0) }.should raise_error(ZeroDivisionError)
+ -> { Prime.prime_division(0) }.should.raise(ZeroDivisionError)
end
end
diff --git a/spec/ruby/library/prime/prime_spec.rb b/spec/ruby/library/prime/prime_spec.rb
index 0896c7f0f3..207c763aed 100644
--- a/spec/ruby/library/prime/prime_spec.rb
+++ b/spec/ruby/library/prime/prime_spec.rb
@@ -3,15 +3,15 @@ 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)
+ Prime.prime?(2).should == true
+ Prime.prime?(3).should == true
+ Prime.prime?(2**31-1).should == 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
+ Prime.prime?(4).should == false
+ Prime.prime?(15).should == false
+ Prime.prime?(2**32-1).should == false
+ Prime.prime?( (2**17-1)*(2**19-1) ).should == false # M6*M7
end
end
diff --git a/spec/ruby/library/prime/shared/next.rb b/spec/ruby/library/prime/shared/next.rb
deleted file mode 100644
index f79b2c051e..0000000000
--- a/spec/ruby/library/prime/shared/next.rb
+++ /dev/null
@@ -1,8 +0,0 @@
-describe :prime_next, shared: true do
- it "returns the element at the current position and moves forward" do
- p = Prime.instance.each
- p.next.should == 2
- p.next.should == 3
- p.next.next.should == 6
- end
-end
diff --git a/spec/ruby/library/prime/succ_spec.rb b/spec/ruby/library/prime/succ_spec.rb
index 34c18d2ba0..86f76c2513 100644
--- a/spec/ruby/library/prime/succ_spec.rb
+++ b/spec/ruby/library/prime/succ_spec.rb
@@ -1,7 +1,9 @@
require_relative '../../spec_helper'
-require_relative 'shared/next'
require 'prime'
describe "Prime#succ" do
- it_behaves_like :prime_next, :succ
+ it "is an alias of Prime#next" do
+ p = Prime.instance.each
+ p.method(:succ).should == p.method(:next)
+ end
end
diff --git a/spec/ruby/library/random/formatter/alphanumeric_spec.rb b/spec/ruby/library/random/formatter/alphanumeric_spec.rb
index 9bd325e1d0..62a4698d0d 100644
--- a/spec/ruby/library/random/formatter/alphanumeric_spec.rb
+++ b/spec/ruby/library/random/formatter/alphanumeric_spec.rb
@@ -30,7 +30,7 @@ describe "Random::Formatter#alphanumeric" do
it "raises an ArgumentError if the size is not numeric" do
-> {
@object.alphanumeric("10")
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
it "does not coerce the size argument with #to_int" do
@@ -38,19 +38,17 @@ describe "Random::Formatter#alphanumeric" do
size.should_not_receive(:to_int)
-> {
@object.alphanumeric(size)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
- ruby_version_is "3.3" do
- it "accepts a 'chars' argument with the output alphabet" do
- @object.alphanumeric(chars: ['a', 'b']).should =~ /\A[ab]+\z/
- end
+ it "accepts a 'chars' argument with the output alphabet" do
+ @object.alphanumeric(chars: ['a', 'b']).should =~ /\A[ab]+\z/
+ end
- it "converts the elements of chars using #to_s" do
- to_s = mock("to_s")
- to_s.should_receive(:to_s).and_return("[mock to_s]")
- # Using 1 value in chars results in an infinite loop
- @object.alphanumeric(1, chars: [to_s, to_s]).should == "[mock to_s]"
- end
+ it "converts the elements of chars using #to_s" do
+ to_s = mock("to_s")
+ to_s.should_receive(:to_s).and_return("[mock to_s]")
+ # Using 1 value in chars results in an infinite loop
+ @object.alphanumeric(1, chars: [to_s, to_s]).should == "[mock to_s]"
end
end
diff --git a/spec/ruby/library/rbconfig/rbconfig_spec.rb b/spec/ruby/library/rbconfig/rbconfig_spec.rb
index b9a4588bf0..4195128a05 100644
--- a/spec/ruby/library/rbconfig/rbconfig_spec.rb
+++ b/spec/ruby/library/rbconfig/rbconfig_spec.rb
@@ -4,8 +4,8 @@ require 'rbconfig'
describe 'RbConfig::CONFIG' do
it 'values are all strings' do
RbConfig::CONFIG.each do |k, v|
- k.should be_kind_of String
- v.should be_kind_of String
+ k.should.is_a? String
+ v.should.is_a? String
end
end
@@ -32,7 +32,7 @@ describe 'RbConfig::CONFIG' do
it "['sitelibdir'] is set and is part of $LOAD_PATH" do
sitelibdir = RbConfig::CONFIG['sitelibdir']
- sitelibdir.should be_kind_of String
+ sitelibdir.should.is_a? String
$LOAD_PATH.map{|path| File.realpath(path) rescue path }.should.include? sitelibdir
end
end
@@ -80,7 +80,7 @@ describe 'RbConfig::CONFIG' do
ar = RbConfig::CONFIG.fetch('AR')
out = `#{ar} --version`
$?.should.success?
- out.should_not be_empty
+ out.should_not.empty?
end
it "['STRIP'] exists and can be executed" do
diff --git a/spec/ruby/library/rbconfig/sizeof/limits_spec.rb b/spec/ruby/library/rbconfig/sizeof/limits_spec.rb
index 776099da27..08b1185965 100644
--- a/spec/ruby/library/rbconfig/sizeof/limits_spec.rb
+++ b/spec/ruby/library/rbconfig/sizeof/limits_spec.rb
@@ -3,13 +3,13 @@ require 'rbconfig/sizeof'
describe "RbConfig::LIMITS" do
it "is a Hash" do
- RbConfig::LIMITS.should be_kind_of(Hash)
+ RbConfig::LIMITS.should.is_a?(Hash)
end
it "has string keys and numeric values" do
RbConfig::LIMITS.each do |key, value|
- key.should be_kind_of String
- value.should be_kind_of Numeric
+ key.should.is_a? String
+ value.should.is_a? Numeric
end
end
diff --git a/spec/ruby/library/rbconfig/sizeof/sizeof_spec.rb b/spec/ruby/library/rbconfig/sizeof/sizeof_spec.rb
index f2582dc4fd..b74dae5166 100644
--- a/spec/ruby/library/rbconfig/sizeof/sizeof_spec.rb
+++ b/spec/ruby/library/rbconfig/sizeof/sizeof_spec.rb
@@ -3,13 +3,13 @@ require 'rbconfig/sizeof'
describe "RbConfig::SIZEOF" do
it "is a Hash" do
- RbConfig::SIZEOF.should be_kind_of(Hash)
+ RbConfig::SIZEOF.should.is_a?(Hash)
end
it "has string keys and integer values" do
RbConfig::SIZEOF.each do |key, value|
- key.should be_kind_of String
- value.should be_kind_of Integer
+ key.should.is_a? String
+ value.should.is_a? Integer
end
end
diff --git a/spec/ruby/library/rbconfig/unicode_emoji_version_spec.rb b/spec/ruby/library/rbconfig/unicode_emoji_version_spec.rb
index 2c6d1f4e93..521a750bf7 100644
--- a/spec/ruby/library/rbconfig/unicode_emoji_version_spec.rb
+++ b/spec/ruby/library/rbconfig/unicode_emoji_version_spec.rb
@@ -9,9 +9,9 @@ describe "RbConfig::CONFIG['UNICODE_EMOJI_VERSION']" do
end
# Caution: ruby_version_is means is_or_later
- ruby_version_is "3.5" do
- it "is 16.0" do
- RbConfig::CONFIG['UNICODE_EMOJI_VERSION'].should == "16.0"
+ ruby_version_is "4.0" do
+ it "is 17.0" do
+ RbConfig::CONFIG['UNICODE_EMOJI_VERSION'].should == "17.0"
end
end
end
diff --git a/spec/ruby/library/rbconfig/unicode_version_spec.rb b/spec/ruby/library/rbconfig/unicode_version_spec.rb
index 961bb989a5..5cdde74f79 100644
--- a/spec/ruby/library/rbconfig/unicode_version_spec.rb
+++ b/spec/ruby/library/rbconfig/unicode_version_spec.rb
@@ -9,9 +9,9 @@ describe "RbConfig::CONFIG['UNICODE_VERSION']" do
end
# Caution: ruby_version_is means is_or_later
- ruby_version_is "3.5" do
- it "is 16.0.0" do
- RbConfig::CONFIG['UNICODE_VERSION'].should == "16.0.0"
+ ruby_version_is "4.0" do
+ it "is 17.0.0" do
+ RbConfig::CONFIG['UNICODE_VERSION'].should == "17.0.0"
end
end
end
diff --git a/spec/ruby/library/readline/basic_quote_characters_spec.rb b/spec/ruby/library/readline/basic_quote_characters_spec.rb
index 216899d875..f6467c8be4 100644
--- a/spec/ruby/library/readline/basic_quote_characters_spec.rb
+++ b/spec/ruby/library/readline/basic_quote_characters_spec.rb
@@ -4,7 +4,7 @@ platform_is_not :darwin do
with_feature :readline do
describe "Readline.basic_quote_characters" do
it "returns not nil" do
- Readline.basic_quote_characters.should_not be_nil
+ Readline.basic_quote_characters.should_not == nil
end
end
diff --git a/spec/ruby/library/readline/basic_word_break_characters_spec.rb b/spec/ruby/library/readline/basic_word_break_characters_spec.rb
index daa0e1cb76..ef05d6560b 100644
--- a/spec/ruby/library/readline/basic_word_break_characters_spec.rb
+++ b/spec/ruby/library/readline/basic_word_break_characters_spec.rb
@@ -3,7 +3,7 @@ require_relative 'spec_helper'
with_feature :readline do
describe "Readline.basic_word_break_characters" do
it "returns not nil" do
- Readline.basic_word_break_characters.should_not be_nil
+ Readline.basic_word_break_characters.should_not == nil
end
end
diff --git a/spec/ruby/library/readline/completer_quote_characters_spec.rb b/spec/ruby/library/readline/completer_quote_characters_spec.rb
index 86c58f3cf6..1109ea1f03 100644
--- a/spec/ruby/library/readline/completer_quote_characters_spec.rb
+++ b/spec/ruby/library/readline/completer_quote_characters_spec.rb
@@ -3,7 +3,7 @@ require_relative 'spec_helper'
with_feature :readline do
describe "Readline.completer_quote_characters" do
it "returns nil" do
- Readline.completer_quote_characters.should be_nil
+ Readline.completer_quote_characters.should == nil
end
end
diff --git a/spec/ruby/library/readline/completer_word_break_characters_spec.rb b/spec/ruby/library/readline/completer_word_break_characters_spec.rb
index c72f1135c4..91a002b9de 100644
--- a/spec/ruby/library/readline/completer_word_break_characters_spec.rb
+++ b/spec/ruby/library/readline/completer_word_break_characters_spec.rb
@@ -3,7 +3,7 @@ require_relative 'spec_helper'
with_feature :readline do
describe "Readline.completer_word_break_characters" do
it "returns nil" do
- Readline.completer_word_break_characters.should be_nil
+ Readline.completer_word_break_characters.should == nil
end
end
diff --git a/spec/ruby/library/readline/completion_append_character_spec.rb b/spec/ruby/library/readline/completion_append_character_spec.rb
index 615b523f4e..2a14d5d30e 100644
--- a/spec/ruby/library/readline/completion_append_character_spec.rb
+++ b/spec/ruby/library/readline/completion_append_character_spec.rb
@@ -3,7 +3,7 @@ require_relative 'spec_helper'
with_feature :readline do
describe "Readline.completion_append_character" do
it "returns not nil" do
- Readline.completion_append_character.should_not be_nil
+ Readline.completion_append_character.should_not == nil
end
end
diff --git a/spec/ruby/library/readline/completion_case_fold_spec.rb b/spec/ruby/library/readline/completion_case_fold_spec.rb
index 966f5d6c79..b6a4aab101 100644
--- a/spec/ruby/library/readline/completion_case_fold_spec.rb
+++ b/spec/ruby/library/readline/completion_case_fold_spec.rb
@@ -3,7 +3,7 @@ require_relative 'spec_helper'
with_feature :readline do
describe "Readline.completion_case_fold" do
it "returns nil" do
- Readline.completion_case_fold.should be_nil
+ Readline.completion_case_fold.should == nil
end
end
diff --git a/spec/ruby/library/readline/completion_proc_spec.rb b/spec/ruby/library/readline/completion_proc_spec.rb
index 2d7a353ec5..037fc6de21 100644
--- a/spec/ruby/library/readline/completion_proc_spec.rb
+++ b/spec/ruby/library/readline/completion_proc_spec.rb
@@ -3,7 +3,7 @@ require_relative 'spec_helper'
with_feature :readline do
describe "Readline.completion_proc" do
it "returns nil" do
- Readline.completion_proc.should be_nil
+ Readline.completion_proc.should == nil
end
end
@@ -16,7 +16,7 @@ with_feature :readline do
end
it "returns an ArgumentError if not given an Proc or #call" do
- -> { Readline.completion_proc = "test" }.should raise_error(ArgumentError)
+ -> { Readline.completion_proc = "test" }.should.raise(ArgumentError)
end
end
end
diff --git a/spec/ruby/library/readline/constants_spec.rb b/spec/ruby/library/readline/constants_spec.rb
index 8fee274866..91536ce1cc 100644
--- a/spec/ruby/library/readline/constants_spec.rb
+++ b/spec/ruby/library/readline/constants_spec.rb
@@ -11,8 +11,8 @@ with_feature :readline do
describe "Readline::VERSION" do
it "is defined and is a non-empty String" do
Readline.const_defined?(:VERSION).should == true
- Readline::VERSION.should be_kind_of(String)
- Readline::VERSION.should_not be_empty
+ Readline::VERSION.should.is_a?(String)
+ Readline::VERSION.should_not.empty?
end
end
end
diff --git a/spec/ruby/library/readline/emacs_editing_mode_spec.rb b/spec/ruby/library/readline/emacs_editing_mode_spec.rb
index f7e8eda982..93ded3d023 100644
--- a/spec/ruby/library/readline/emacs_editing_mode_spec.rb
+++ b/spec/ruby/library/readline/emacs_editing_mode_spec.rb
@@ -4,7 +4,7 @@ platform_is_not :darwin do
with_feature :readline do
describe "Readline.emacs_editing_mode" do
it "returns nil" do
- Readline.emacs_editing_mode.should be_nil
+ Readline.emacs_editing_mode.should == nil
end
end
end
diff --git a/spec/ruby/library/readline/filename_quote_characters_spec.rb b/spec/ruby/library/readline/filename_quote_characters_spec.rb
index de8ce700a8..6bcb04fc79 100644
--- a/spec/ruby/library/readline/filename_quote_characters_spec.rb
+++ b/spec/ruby/library/readline/filename_quote_characters_spec.rb
@@ -4,7 +4,7 @@ platform_is_not :darwin do
with_feature :readline do
describe "Readline.filename_quote_characters" do
it "returns nil" do
- Readline.filename_quote_characters.should be_nil
+ Readline.filename_quote_characters.should == nil
end
end
diff --git a/spec/ruby/library/readline/history/append_spec.rb b/spec/ruby/library/readline/history/append_spec.rb
index 5383271374..be0e515b84 100644
--- a/spec/ruby/library/readline/history/append_spec.rb
+++ b/spec/ruby/library/readline/history/append_spec.rb
@@ -22,7 +22,7 @@ with_feature :readline do
end
it "raises a TypeError when the passed Object can't be converted to a String" do
- -> { Readline::HISTORY << mock("Object") }.should raise_error(TypeError)
+ -> { Readline::HISTORY << mock("Object") }.should.raise(TypeError)
end
end
end
diff --git a/spec/ruby/library/readline/history/delete_at_spec.rb b/spec/ruby/library/readline/history/delete_at_spec.rb
index 3bd577e75c..4383ff7e83 100644
--- a/spec/ruby/library/readline/history/delete_at_spec.rb
+++ b/spec/ruby/library/readline/history/delete_at_spec.rb
@@ -31,8 +31,8 @@ with_feature :readline do
end
it "raises an IndexError when the given index is greater than the history size" do
- -> { Readline::HISTORY.delete_at(10) }.should raise_error(IndexError)
- -> { Readline::HISTORY.delete_at(-10) }.should raise_error(IndexError)
+ -> { Readline::HISTORY.delete_at(10) }.should.raise(IndexError)
+ -> { Readline::HISTORY.delete_at(-10) }.should.raise(IndexError)
end
end
end
diff --git a/spec/ruby/library/readline/history/element_reference_spec.rb b/spec/ruby/library/readline/history/element_reference_spec.rb
index 0a74f3d62d..1f1642626f 100644
--- a/spec/ruby/library/readline/history/element_reference_spec.rb
+++ b/spec/ruby/library/readline/history/element_reference_spec.rb
@@ -23,13 +23,13 @@ with_feature :readline do
end
it "raises an IndexError when there is no item at the passed index" do
- -> { Readline::HISTORY[-10] }.should raise_error(IndexError)
- -> { Readline::HISTORY[-9] }.should raise_error(IndexError)
- -> { Readline::HISTORY[-8] }.should raise_error(IndexError)
+ -> { Readline::HISTORY[-10] }.should.raise(IndexError)
+ -> { Readline::HISTORY[-9] }.should.raise(IndexError)
+ -> { Readline::HISTORY[-8] }.should.raise(IndexError)
- -> { Readline::HISTORY[8] }.should raise_error(IndexError)
- -> { Readline::HISTORY[9] }.should raise_error(IndexError)
- -> { Readline::HISTORY[10] }.should raise_error(IndexError)
+ -> { Readline::HISTORY[8] }.should.raise(IndexError)
+ -> { Readline::HISTORY[9] }.should.raise(IndexError)
+ -> { Readline::HISTORY[10] }.should.raise(IndexError)
end
end
end
diff --git a/spec/ruby/library/readline/history/element_set_spec.rb b/spec/ruby/library/readline/history/element_set_spec.rb
index 776adaacd1..0787b6343d 100644
--- a/spec/ruby/library/readline/history/element_set_spec.rb
+++ b/spec/ruby/library/readline/history/element_set_spec.rb
@@ -17,7 +17,7 @@ with_feature :readline do
end
it "raises an IndexError when there is no item at the passed positive index" do
- -> { Readline::HISTORY[10] = "test" }.should raise_error(IndexError)
+ -> { Readline::HISTORY[10] = "test" }.should.raise(IndexError)
end
it "sets the item at the given index" do
@@ -29,7 +29,7 @@ with_feature :readline do
end
it "raises an IndexError when there is no item at the passed negative index" do
- -> { Readline::HISTORY[10] = "test" }.should raise_error(IndexError)
+ -> { Readline::HISTORY[10] = "test" }.should.raise(IndexError)
end
end
end
diff --git a/spec/ruby/library/readline/history/empty_spec.rb b/spec/ruby/library/readline/history/empty_spec.rb
index 31d01d9601..5b722dccd3 100644
--- a/spec/ruby/library/readline/history/empty_spec.rb
+++ b/spec/ruby/library/readline/history/empty_spec.rb
@@ -3,11 +3,11 @@ require_relative '../spec_helper'
with_feature :readline do
describe "Readline::HISTORY.empty?" do
it "returns true when the history is empty" do
- Readline::HISTORY.should be_empty
+ Readline::HISTORY.should.empty?
Readline::HISTORY.push("test")
- Readline::HISTORY.should_not be_empty
+ Readline::HISTORY.should_not.empty?
Readline::HISTORY.pop
- Readline::HISTORY.should be_empty
+ Readline::HISTORY.should.empty?
end
end
end
diff --git a/spec/ruby/library/readline/history/history_spec.rb b/spec/ruby/library/readline/history/history_spec.rb
index 927dd52ebf..3233071033 100644
--- a/spec/ruby/library/readline/history/history_spec.rb
+++ b/spec/ruby/library/readline/history/history_spec.rb
@@ -3,7 +3,7 @@ require_relative '../spec_helper'
with_feature :readline do
describe "Readline::HISTORY" do
it "is extended with the Enumerable module" do
- Readline::HISTORY.should be_kind_of(Enumerable)
+ Readline::HISTORY.should.is_a?(Enumerable)
end
end
end
diff --git a/spec/ruby/library/readline/history/pop_spec.rb b/spec/ruby/library/readline/history/pop_spec.rb
index 156a8a06f8..0b780a38cc 100644
--- a/spec/ruby/library/readline/history/pop_spec.rb
+++ b/spec/ruby/library/readline/history/pop_spec.rb
@@ -3,7 +3,7 @@ require_relative '../spec_helper'
with_feature :readline do
describe "Readline::HISTORY.pop" do
it "returns nil when the history is empty" do
- Readline::HISTORY.pop.should be_nil
+ Readline::HISTORY.pop.should == nil
end
it "returns and removes the last item from the history" do
diff --git a/spec/ruby/library/readline/history/push_spec.rb b/spec/ruby/library/readline/history/push_spec.rb
index 53505ccba6..4bbf1763a1 100644
--- a/spec/ruby/library/readline/history/push_spec.rb
+++ b/spec/ruby/library/readline/history/push_spec.rb
@@ -20,7 +20,7 @@ with_feature :readline do
end
it "raises a TypeError when the passed Object can't be converted to a String" do
- -> { Readline::HISTORY.push(mock("Object")) }.should raise_error(TypeError)
+ -> { Readline::HISTORY.push(mock("Object")) }.should.raise(TypeError)
end
end
end
diff --git a/spec/ruby/library/readline/history/shift_spec.rb b/spec/ruby/library/readline/history/shift_spec.rb
index 9aad7d5399..d852480a2a 100644
--- a/spec/ruby/library/readline/history/shift_spec.rb
+++ b/spec/ruby/library/readline/history/shift_spec.rb
@@ -3,7 +3,7 @@ require_relative '../spec_helper'
with_feature :readline do
describe "Readline::HISTORY.shift" do
it "returns nil when the history is empty" do
- Readline::HISTORY.shift.should be_nil
+ Readline::HISTORY.shift.should == nil
end
it "returns and removes the first item from the history" do
diff --git a/spec/ruby/library/readline/vi_editing_mode_spec.rb b/spec/ruby/library/readline/vi_editing_mode_spec.rb
index 6622962ceb..3ce4f5a7e6 100644
--- a/spec/ruby/library/readline/vi_editing_mode_spec.rb
+++ b/spec/ruby/library/readline/vi_editing_mode_spec.rb
@@ -4,7 +4,7 @@ platform_is_not :darwin do
with_feature :readline do
describe "Readline.vi_editing_mode" do
it "returns nil" do
- Readline.vi_editing_mode.should be_nil
+ Readline.vi_editing_mode.should == nil
end
end
end
diff --git a/spec/ruby/library/resolv/get_address_spec.rb b/spec/ruby/library/resolv/get_address_spec.rb
index ecc2cdf7de..9caa94643a 100644
--- a/spec/ruby/library/resolv/get_address_spec.rb
+++ b/spec/ruby/library/resolv/get_address_spec.rb
@@ -14,6 +14,6 @@ describe "Resolv#getaddress" do
res = Resolv.new([])
-> {
res.getaddress("should.raise.error.")
- }.should raise_error(Resolv::ResolvError)
+ }.should.raise(Resolv::ResolvError)
end
end
diff --git a/spec/ruby/library/resolv/get_name_spec.rb b/spec/ruby/library/resolv/get_name_spec.rb
index 3ef97a2cea..81e0cda28d 100644
--- a/spec/ruby/library/resolv/get_name_spec.rb
+++ b/spec/ruby/library/resolv/get_name_spec.rb
@@ -13,6 +13,6 @@ describe "Resolv#getname" do
res = Resolv.new([])
-> {
res.getname("should.raise.error")
- }.should raise_error(Resolv::ResolvError)
+ }.should.raise(Resolv::ResolvError)
end
end
diff --git a/spec/ruby/library/ripper/lex_spec.rb b/spec/ruby/library/ripper/lex_spec.rb
index 97cfb06904..0255480579 100644
--- a/spec/ruby/library/ripper/lex_spec.rb
+++ b/spec/ruby/library/ripper/lex_spec.rb
@@ -10,14 +10,14 @@ describe "Ripper.lex" do
[[1, 5], :on_lparen, "(", 'BEG|LABEL'],
[[1, 6], :on_ident, "a", 'ARG'],
[[1, 7], :on_rparen, ")", 'ENDFN'],
- [[1, 8], :on_sp, " ", 'BEG'],
+ [[1, 8], :on_semicolon, ";", 'BEG'],
[[1, 9], :on_kw, "nil", 'END'],
[[1, 12], :on_sp, " ", 'END'],
[[1, 13], :on_kw, "end", 'END']
]
- lexed = Ripper.lex("def m(a) nil end")
+ lexed = Ripper.lex("def m(a);nil end")
lexed.map { |e|
- e[0...-1] + [e[-1].to_s.split('|').map { |s| s.sub(/^EXPR_/, '') }.join('|')]
+ e[0...-1] + [e[-1].to_s]
}.should == expected
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..693c72a29e 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
@@ -4,7 +4,7 @@ require 'rubygems'
describe "Gem.load_path_insert_index" do
guard -> { RbConfig::TOPDIR } do
it "is set for an installed Ruby" do
- Gem.load_path_insert_index.should be_kind_of Integer
+ Gem.load_path_insert_index.should.is_a? Integer
end
end
end
diff --git a/spec/ruby/library/securerandom/base64_spec.rb b/spec/ruby/library/securerandom/base64_spec.rb
index 34cd419ce2..49d4b8a029 100644
--- a/spec/ruby/library/securerandom/base64_spec.rb
+++ b/spec/ruby/library/securerandom/base64_spec.rb
@@ -6,13 +6,13 @@ describe "SecureRandom.base64" do
it "generates a random base64 string out of specified number of random bytes" do
(16..128).each do |idx|
base64 = SecureRandom.base64(idx)
- base64.should be_kind_of(String)
+ base64.should.is_a?(String)
base64.length.should < 2 * idx
base64.should =~ /^[A-Za-z0-9\+\/]+={0,2}$/
end
base64 = SecureRandom.base64(16.5)
- base64.should be_kind_of(String)
+ base64.should.is_a?(String)
base64.length.should < 2 * 16
end
@@ -32,19 +32,19 @@ describe "SecureRandom.base64" do
end
it "generates a random base64 string out of 32 random bytes" do
- SecureRandom.base64.should be_kind_of(String)
+ SecureRandom.base64.should.is_a?(String)
SecureRandom.base64.length.should < 32 * 2
end
it "treats nil argument as default one and generates a random base64 string" do
- SecureRandom.base64(nil).should be_kind_of(String)
+ SecureRandom.base64(nil).should.is_a?(String)
SecureRandom.base64(nil).length.should < 32 * 2
end
it "raises ArgumentError on negative arguments" do
-> {
SecureRandom.base64(-1)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
it "tries to convert the passed argument to an Integer using #to_int" do
diff --git a/spec/ruby/library/securerandom/hex_spec.rb b/spec/ruby/library/securerandom/hex_spec.rb
index bdb920b217..ec33aca1ee 100644
--- a/spec/ruby/library/securerandom/hex_spec.rb
+++ b/spec/ruby/library/securerandom/hex_spec.rb
@@ -6,13 +6,13 @@ describe "SecureRandom.hex" do
it "generates a random hex string of length twice the specified argument" do
(1..64).each do |idx|
hex = SecureRandom.hex(idx)
- hex.should be_kind_of(String)
+ hex.should.is_a?(String)
hex.length.should == 2 * idx
end
base64 = SecureRandom.hex(5.5)
- base64.should be_kind_of(String)
- base64.length.should eql(10)
+ base64.should.is_a?(String)
+ base64.length.should.eql?(10)
end
it "returns an empty string when argument is 0" do
@@ -31,24 +31,24 @@ describe "SecureRandom.hex" do
end
it "generates a random hex string of length 32 if no argument is provided" do
- SecureRandom.hex.should be_kind_of(String)
+ SecureRandom.hex.should.is_a?(String)
SecureRandom.hex.length.should == 32
end
it "treats nil argument as default one and generates a random hex string of length 32" do
- SecureRandom.hex(nil).should be_kind_of(String)
+ SecureRandom.hex(nil).should.is_a?(String)
SecureRandom.hex(nil).length.should == 32
end
it "raises ArgumentError on negative arguments" do
-> {
SecureRandom.hex(-1)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
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(5)
- SecureRandom.hex(obj).size.should eql(10)
+ SecureRandom.hex(obj).size.should.eql?(10)
end
end
diff --git a/spec/ruby/library/securerandom/random_bytes_spec.rb b/spec/ruby/library/securerandom/random_bytes_spec.rb
index ed3a02255c..4e30a53163 100644
--- a/spec/ruby/library/securerandom/random_bytes_spec.rb
+++ b/spec/ruby/library/securerandom/random_bytes_spec.rb
@@ -8,24 +8,24 @@ describe "SecureRandom.random_bytes" do
it "generates a random binary string of length 16 if no argument is provided" do
bytes = SecureRandom.random_bytes
- bytes.should be_kind_of(String)
+ bytes.should.is_a?(String)
bytes.length.should == 16
end
it "generates a random binary string of length 16 if argument is nil" do
bytes = SecureRandom.random_bytes(nil)
- bytes.should be_kind_of(String)
+ bytes.should.is_a?(String)
bytes.length.should == 16
end
it "generates a random binary string of specified length" do
(1..64).each do |idx|
bytes = SecureRandom.random_bytes(idx)
- bytes.should be_kind_of(String)
+ bytes.should.is_a?(String)
bytes.length.should == idx
end
- SecureRandom.random_bytes(2.2).length.should eql(2)
+ SecureRandom.random_bytes(2.2).length.should.eql?(2)
end
it "generates different binary strings with subsequent invocations" do
@@ -42,12 +42,12 @@ describe "SecureRandom.random_bytes" do
it "raises ArgumentError on negative arguments" do
-> {
SecureRandom.random_bytes(-1)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
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(5)
- SecureRandom.random_bytes(obj).size.should eql(5)
+ SecureRandom.random_bytes(obj).size.should.eql?(5)
end
end
diff --git a/spec/ruby/library/securerandom/random_number_spec.rb b/spec/ruby/library/securerandom/random_number_spec.rb
index bb25bc496e..97cd66f7bc 100644
--- a/spec/ruby/library/securerandom/random_number_spec.rb
+++ b/spec/ruby/library/securerandom/random_number_spec.rb
@@ -10,7 +10,7 @@ describe "SecureRandom.random_number" do
it "generates a random positive number smaller then the positive integer argument" do
(1..64).each do |idx|
num = SecureRandom.random_number(idx)
- num.should be_kind_of(Integer)
+ num.should.is_a?(Integer)
0.should <= num
num.should < idx
end
@@ -20,7 +20,7 @@ describe "SecureRandom.random_number" do
max = 12345678901234567890
11.times do
num = SecureRandom.random_number max
- num.should be_kind_of(Integer)
+ num.should.is_a?(Integer)
0.should <= num
num.should < max
end
@@ -29,7 +29,7 @@ describe "SecureRandom.random_number" do
it "generates a random float number between 0.0 and 1.0 if no argument provided" do
64.times do
num = SecureRandom.random_number
- num.should be_kind_of(Float)
+ num.should.is_a?(Float)
0.0.should <= num
num.should < 1.0
end
@@ -38,7 +38,7 @@ describe "SecureRandom.random_number" do
it "generates a random value in given (integer) range limits" do
64.times do
num = SecureRandom.random_number 11...13
- num.should be_kind_of(Integer)
+ num.should.is_a?(Integer)
11.should <= num
num.should < 13
end
@@ -49,7 +49,7 @@ describe "SecureRandom.random_number" do
upper = 12345678901234567890 + 5
32.times do
num = SecureRandom.random_number lower..upper
- num.should be_kind_of(Integer)
+ num.should.is_a?(Integer)
lower.should <= num
num.should <= upper
end
@@ -58,7 +58,7 @@ describe "SecureRandom.random_number" do
it "generates a random value in given (float) range limits" do
64.times do
num = SecureRandom.random_number 0.6..0.9
- num.should be_kind_of(Float)
+ num.should.is_a?(Float)
0.6.should <= num
num.should <= 0.9
end
@@ -66,14 +66,14 @@ describe "SecureRandom.random_number" do
it "generates a random float number between 0.0 and 1.0 if argument is negative" do
num = SecureRandom.random_number(-10)
- num.should be_kind_of(Float)
+ num.should.is_a?(Float)
0.0.should <= num
num.should < 1.0
end
it "generates a random float number between 0.0 and 1.0 if argument is negative float" do
num = SecureRandom.random_number(-11.1)
- num.should be_kind_of(Float)
+ num.should.is_a?(Float)
0.0.should <= num
num.should < 1.0
end
@@ -84,7 +84,7 @@ describe "SecureRandom.random_number" do
256.times do
val = SecureRandom.random_number
# make sure the random values are not repeating
- values.should_not include(val)
+ values.should_not.include?(val)
values << val
end
end
@@ -92,6 +92,6 @@ describe "SecureRandom.random_number" do
it "raises ArgumentError if the argument is non-numeric" do
-> {
SecureRandom.random_number(Object.new)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
end
diff --git a/spec/ruby/library/shellwords/shellwords_spec.rb b/spec/ruby/library/shellwords/shellwords_spec.rb
index fe86b6faab..d1b61e0a6e 100644
--- a/spec/ruby/library/shellwords/shellwords_spec.rb
+++ b/spec/ruby/library/shellwords/shellwords_spec.rb
@@ -19,11 +19,11 @@ describe "Shellwords#shellwords" do
end
it "raises ArgumentError when double quoted strings are misquoted" do
- -> { Shellwords.shellwords('a "b c d e') }.should raise_error(ArgumentError)
+ -> { Shellwords.shellwords('a "b c d e') }.should.raise(ArgumentError)
end
it "raises ArgumentError when single quoted strings are misquoted" do
- -> { Shellwords.shellwords("a 'b c d e") }.should raise_error(ArgumentError)
+ -> { Shellwords.shellwords("a 'b c d e") }.should.raise(ArgumentError)
end
# https://bugs.ruby-lang.org/issues/10055
diff --git a/spec/ruby/library/singleton/allocate_spec.rb b/spec/ruby/library/singleton/allocate_spec.rb
index 6a1512d53b..a0094fb32a 100644
--- a/spec/ruby/library/singleton/allocate_spec.rb
+++ b/spec/ruby/library/singleton/allocate_spec.rb
@@ -3,6 +3,6 @@ require_relative 'fixtures/classes'
describe "Singleton.allocate" do
it "is a private method" do
- -> { SingletonSpecs::MyClass.allocate }.should raise_error(NoMethodError)
+ -> { SingletonSpecs::MyClass.allocate }.should.raise(NoMethodError)
end
end
diff --git a/spec/ruby/library/singleton/clone_spec.rb b/spec/ruby/library/singleton/clone_spec.rb
index 3635bcd594..a7b7b731f5 100644
--- a/spec/ruby/library/singleton/clone_spec.rb
+++ b/spec/ruby/library/singleton/clone_spec.rb
@@ -3,6 +3,6 @@ require_relative 'fixtures/classes'
describe "Singleton#clone" do
it "is prevented" do
- -> { SingletonSpecs::MyClass.instance.clone }.should raise_error(TypeError)
+ -> { SingletonSpecs::MyClass.instance.clone }.should.raise(TypeError)
end
end
diff --git a/spec/ruby/library/singleton/dup_spec.rb b/spec/ruby/library/singleton/dup_spec.rb
index 13d5a213e9..a0455f37b7 100644
--- a/spec/ruby/library/singleton/dup_spec.rb
+++ b/spec/ruby/library/singleton/dup_spec.rb
@@ -3,6 +3,6 @@ require_relative 'fixtures/classes'
describe "Singleton#dup" do
it "is prevented" do
- -> { SingletonSpecs::MyClass.instance.dup }.should raise_error(TypeError)
+ -> { SingletonSpecs::MyClass.instance.dup }.should.raise(TypeError)
end
end
diff --git a/spec/ruby/library/singleton/instance_spec.rb b/spec/ruby/library/singleton/instance_spec.rb
index 1679728d4c..20cac602b5 100644
--- a/spec/ruby/library/singleton/instance_spec.rb
+++ b/spec/ruby/library/singleton/instance_spec.rb
@@ -3,28 +3,28 @@ require_relative 'fixtures/classes'
describe "Singleton.instance" do
it "returns an instance of the singleton class" do
- SingletonSpecs::MyClass.instance.should be_kind_of(SingletonSpecs::MyClass)
+ SingletonSpecs::MyClass.instance.should.is_a?(SingletonSpecs::MyClass)
end
it "returns the same instance for multiple calls to instance" do
- SingletonSpecs::MyClass.instance.should equal(SingletonSpecs::MyClass.instance)
+ SingletonSpecs::MyClass.instance.should.equal?(SingletonSpecs::MyClass.instance)
end
it "returns an instance of the singleton's subclasses" do
- SingletonSpecs::MyClassChild.instance.should be_kind_of(SingletonSpecs::MyClassChild)
+ SingletonSpecs::MyClassChild.instance.should.is_a?(SingletonSpecs::MyClassChild)
end
it "returns the same instance for multiple class to instance on subclasses" do
- SingletonSpecs::MyClassChild.instance.should equal(SingletonSpecs::MyClassChild.instance)
+ SingletonSpecs::MyClassChild.instance.should.equal?(SingletonSpecs::MyClassChild.instance)
end
it "returns an instance of the singleton's clone" do
klone = SingletonSpecs::MyClassChild.clone
- klone.instance.should be_kind_of(klone)
+ klone.instance.should.is_a?(klone)
end
it "returns the same instance for multiple class to instance on clones" do
klone = SingletonSpecs::MyClassChild.clone
- klone.instance.should equal(klone.instance)
+ klone.instance.should.equal?(klone.instance)
end
end
diff --git a/spec/ruby/library/singleton/load_spec.rb b/spec/ruby/library/singleton/load_spec.rb
index 4c753f9e7a..ab95d14640 100644
--- a/spec/ruby/library/singleton/load_spec.rb
+++ b/spec/ruby/library/singleton/load_spec.rb
@@ -1,21 +1,20 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
-# TODO: change to a.should be_equal(b)
# TODO: write spec for cloning classes and calling private methods
# TODO: write spec for private_methods not showing up via extended
describe "Singleton._load" do
it "returns the singleton instance for anything passed in" do
klass = SingletonSpecs::MyClass
- klass._load("").should equal(klass.instance)
- klass._load("42").should equal(klass.instance)
- klass._load(42).should equal(klass.instance)
+ klass._load("").should.equal?(klass.instance)
+ klass._load("42").should.equal?(klass.instance)
+ klass._load(42).should.equal?(klass.instance)
end
it "returns the singleton instance for anything passed in to subclass" do
subklass = SingletonSpecs::MyClassChild
- subklass._load("").should equal(subklass.instance)
- subklass._load("42").should equal(subklass.instance)
- subklass._load(42).should equal(subklass.instance)
+ subklass._load("").should.equal?(subklass.instance)
+ subklass._load("42").should.equal?(subklass.instance)
+ subklass._load(42).should.equal?(subklass.instance)
end
end
diff --git a/spec/ruby/library/singleton/new_spec.rb b/spec/ruby/library/singleton/new_spec.rb
index 2f45db819c..6167231a29 100644
--- a/spec/ruby/library/singleton/new_spec.rb
+++ b/spec/ruby/library/singleton/new_spec.rb
@@ -3,6 +3,6 @@ require_relative 'fixtures/classes'
describe "Singleton.new" do
it "is a private method" do
- -> { SingletonSpecs::NewSpec.new }.should raise_error(NoMethodError)
+ -> { SingletonSpecs::NewSpec.new }.should.raise(NoMethodError)
end
end
diff --git a/spec/ruby/library/socket/addrinfo/afamily_spec.rb b/spec/ruby/library/socket/addrinfo/afamily_spec.rb
index 7229dab9de..5d075be057 100644
--- a/spec/ruby/library/socket/addrinfo/afamily_spec.rb
+++ b/spec/ruby/library/socket/addrinfo/afamily_spec.rb
@@ -23,15 +23,13 @@ describe "Addrinfo#afamily" do
end
end
- with_feature :unix_socket do
- describe "for a unix socket" do
- before :each do
- @addrinfo = Addrinfo.unix("/tmp/sock")
- end
-
- it "returns Socket::AF_UNIX" do
- @addrinfo.afamily.should == Socket::AF_UNIX
- end
+ describe "for a unix socket" do
+ before :each do
+ @addrinfo = Addrinfo.unix("/tmp/sock")
+ end
+
+ it "returns Socket::AF_UNIX" do
+ @addrinfo.afamily.should == Socket::AF_UNIX
end
end
end
diff --git a/spec/ruby/library/socket/addrinfo/bind_spec.rb b/spec/ruby/library/socket/addrinfo/bind_spec.rb
index 6f78890a4d..cdd187771f 100644
--- a/spec/ruby/library/socket/addrinfo/bind_spec.rb
+++ b/spec/ruby/library/socket/addrinfo/bind_spec.rb
@@ -13,16 +13,16 @@ describe "Addrinfo#bind" do
it "returns a bound socket when no block is given" do
@socket = @addrinfo.bind
- @socket.should be_kind_of(Socket)
- @socket.closed?.should be_false
+ @socket.should.is_a?(Socket)
+ @socket.closed?.should == false
end
it "yields the socket if a block is given" do
@addrinfo.bind do |sock|
@socket = sock
- sock.should be_kind_of(Socket)
+ sock.should.is_a?(Socket)
end
- @socket.closed?.should be_true
+ @socket.closed?.should == true
end
end
diff --git a/spec/ruby/library/socket/addrinfo/canonname_spec.rb b/spec/ruby/library/socket/addrinfo/canonname_spec.rb
index a1cc8b3980..efd3147125 100644
--- a/spec/ruby/library/socket/addrinfo/canonname_spec.rb
+++ b/spec/ruby/library/socket/addrinfo/canonname_spec.rb
@@ -10,7 +10,7 @@ describe "Addrinfo#canonname" do
it "returns the canonical name for a host" do
canonname = @addrinfos.map { |a| a.canonname }.find { |name| name and name.include?("localhost") }
if canonname
- canonname.should include("localhost")
+ canonname.should.include?("localhost")
else
canonname.should == nil
end
@@ -20,7 +20,7 @@ describe "Addrinfo#canonname" do
it 'returns nil' do
addr = Addrinfo.new(Socket.sockaddr_in(0, '127.0.0.1'))
- addr.canonname.should be_nil
+ addr.canonname.should == nil
end
end
diff --git a/spec/ruby/library/socket/addrinfo/connect_from_spec.rb b/spec/ruby/library/socket/addrinfo/connect_from_spec.rb
index 55fce2e159..b1f6caa174 100644
--- a/spec/ruby/library/socket/addrinfo/connect_from_spec.rb
+++ b/spec/ruby/library/socket/addrinfo/connect_from_spec.rb
@@ -17,18 +17,18 @@ describe 'Addrinfo#connect_from' do
describe 'using separate arguments' do
it 'returns a Socket when no block is given' do
@socket = @addr.connect_from(ip_address, 0)
- @socket.should be_an_instance_of(Socket)
+ @socket.should.instance_of?(Socket)
end
it 'yields the Socket when a block is given' do
@addr.connect_from(ip_address, 0) do |socket|
- socket.should be_an_instance_of(Socket)
+ socket.should.instance_of?(Socket)
end
end
it 'treats the last argument as a set of options if it is a Hash' do
@socket = @addr.connect_from(ip_address, 0, timeout: 2)
- @socket.should be_an_instance_of(Socket)
+ @socket.should.instance_of?(Socket)
end
it 'binds the socket to the local address' do
@@ -48,18 +48,18 @@ describe 'Addrinfo#connect_from' do
it 'returns a Socket when no block is given' do
@socket = @addr.connect_from(@from_addr)
- @socket.should be_an_instance_of(Socket)
+ @socket.should.instance_of?(Socket)
end
it 'yields the Socket when a block is given' do
@addr.connect_from(@from_addr) do |socket|
- socket.should be_an_instance_of(Socket)
+ socket.should.instance_of?(Socket)
end
end
it 'treats the last argument as a set of options if it is a Hash' do
@socket = @addr.connect_from(@from_addr, timeout: 2)
- @socket.should be_an_instance_of(Socket)
+ @socket.should.instance_of?(Socket)
end
it 'binds the socket to the local address' do
diff --git a/spec/ruby/library/socket/addrinfo/connect_spec.rb b/spec/ruby/library/socket/addrinfo/connect_spec.rb
index 1c2dc609ca..a8494b5501 100644
--- a/spec/ruby/library/socket/addrinfo/connect_spec.rb
+++ b/spec/ruby/library/socket/addrinfo/connect_spec.rb
@@ -16,20 +16,20 @@ describe 'Addrinfo#connect' do
it 'returns a Socket when no block is given' do
addr = Addrinfo.tcp(ip_address, @port)
@socket = addr.connect
- @socket.should be_an_instance_of(Socket)
+ @socket.should.instance_of?(Socket)
end
it 'yields a Socket when a block is given' do
addr = Addrinfo.tcp(ip_address, @port)
addr.connect do |socket|
- socket.should be_an_instance_of(Socket)
+ socket.should.instance_of?(Socket)
end
end
it 'accepts a Hash of options' do
addr = Addrinfo.tcp(ip_address, @port)
@socket = addr.connect(timeout: 2)
- @socket.should be_an_instance_of(Socket)
+ @socket.should.instance_of?(Socket)
end
end
end
diff --git a/spec/ruby/library/socket/addrinfo/connect_to_spec.rb b/spec/ruby/library/socket/addrinfo/connect_to_spec.rb
index 69666da19b..2bf49a38e8 100644
--- a/spec/ruby/library/socket/addrinfo/connect_to_spec.rb
+++ b/spec/ruby/library/socket/addrinfo/connect_to_spec.rb
@@ -17,18 +17,18 @@ describe 'Addrinfo#connect_to' do
describe 'using separate arguments' do
it 'returns a Socket when no block is given' do
@socket = @addr.connect_to(ip_address, @port)
- @socket.should be_an_instance_of(Socket)
+ @socket.should.instance_of?(Socket)
end
it 'yields the Socket when a block is given' do
@addr.connect_to(ip_address, @port) do |socket|
- socket.should be_an_instance_of(Socket)
+ socket.should.instance_of?(Socket)
end
end
it 'treats the last argument as a set of options if it is a Hash' do
@socket = @addr.connect_to(ip_address, @port, timeout: 2)
- @socket.should be_an_instance_of(Socket)
+ @socket.should.instance_of?(Socket)
end
it 'binds the Addrinfo to the local address' do
@@ -48,18 +48,18 @@ describe 'Addrinfo#connect_to' do
it 'returns a Socket when no block is given' do
@socket = @addr.connect_to(@to_addr)
- @socket.should be_an_instance_of(Socket)
+ @socket.should.instance_of?(Socket)
end
it 'yields the Socket when a block is given' do
@addr.connect_to(@to_addr) do |socket|
- socket.should be_an_instance_of(Socket)
+ socket.should.instance_of?(Socket)
end
end
it 'treats the last argument as a set of options if it is a Hash' do
@socket = @addr.connect_to(@to_addr, timeout: 2)
- @socket.should be_an_instance_of(Socket)
+ @socket.should.instance_of?(Socket)
end
it 'binds the socket to the local address' do
diff --git a/spec/ruby/library/socket/addrinfo/family_addrinfo_spec.rb b/spec/ruby/library/socket/addrinfo/family_addrinfo_spec.rb
index 2bc3b6a2e3..38834ade91 100644
--- a/spec/ruby/library/socket/addrinfo/family_addrinfo_spec.rb
+++ b/spec/ruby/library/socket/addrinfo/family_addrinfo_spec.rb
@@ -4,7 +4,7 @@ describe 'Addrinfo#family_addrinfo' do
it 'raises ArgumentError if no arguments are given' do
addr = Addrinfo.tcp('127.0.0.1', 0)
- -> { addr.family_addrinfo }.should raise_error(ArgumentError)
+ -> { addr.family_addrinfo }.should.raise(ArgumentError)
end
describe 'using multiple arguments' do
@@ -14,17 +14,17 @@ describe 'Addrinfo#family_addrinfo' do
end
it 'raises ArgumentError if only 1 argument is given' do
- -> { @source.family_addrinfo('127.0.0.1') }.should raise_error(ArgumentError)
+ -> { @source.family_addrinfo('127.0.0.1') }.should.raise(ArgumentError)
end
it 'raises ArgumentError if more than 2 arguments are given' do
- -> { @source.family_addrinfo('127.0.0.1', 0, 666) }.should raise_error(ArgumentError)
+ -> { @source.family_addrinfo('127.0.0.1', 0, 666) }.should.raise(ArgumentError)
end
it 'returns an Addrinfo when a host and port are given' do
addr = @source.family_addrinfo('127.0.0.1', 0)
- addr.should be_an_instance_of(Addrinfo)
+ addr.should.instance_of?(Addrinfo)
end
describe 'the returned Addrinfo' do
@@ -50,38 +50,36 @@ describe 'Addrinfo#family_addrinfo' do
end
end
- with_feature :unix_socket do
- describe 'with a UNIX Addrinfo' do
- before do
- @source = Addrinfo.unix('cats')
- end
+ describe 'with a UNIX Addrinfo' do
+ before do
+ @source = Addrinfo.unix('cats')
+ end
- it 'raises ArgumentError if more than 1 argument is given' do
- -> { @source.family_addrinfo('foo', 'bar') }.should raise_error(ArgumentError)
- end
+ it 'raises ArgumentError if more than 1 argument is given' do
+ -> { @source.family_addrinfo('foo', 'bar') }.should.raise(ArgumentError)
+ end
- it 'returns an Addrinfo when a UNIX socket path is given' do
- addr = @source.family_addrinfo('dogs')
+ it 'returns an Addrinfo when a UNIX socket path is given' do
+ addr = @source.family_addrinfo('dogs')
- addr.should be_an_instance_of(Addrinfo)
- end
+ addr.should.instance_of?(Addrinfo)
+ end
- describe 'the returned Addrinfo' do
- before do
- @addr = @source.family_addrinfo('dogs')
- end
+ describe 'the returned Addrinfo' do
+ before do
+ @addr = @source.family_addrinfo('dogs')
+ end
- it 'uses AF_UNIX as the address family' do
- @addr.afamily.should == Socket::AF_UNIX
- end
+ it 'uses AF_UNIX as the address family' do
+ @addr.afamily.should == Socket::AF_UNIX
+ end
- it 'uses PF_UNIX as the protocol family' do
- @addr.pfamily.should == Socket::PF_UNIX
- end
+ it 'uses PF_UNIX as the protocol family' do
+ @addr.pfamily.should == Socket::PF_UNIX
+ end
- it 'uses the given socket path' do
- @addr.unix_path.should == 'dogs'
- end
+ it 'uses the given socket path' do
+ @addr.unix_path.should == 'dogs'
end
end
end
@@ -99,17 +97,17 @@ describe 'Addrinfo#family_addrinfo' do
it 'raises ArgumentError if more than 1 argument is given' do
input = Addrinfo.tcp('127.0.0.2', 0)
- -> { @source.family_addrinfo(input, 666) }.should raise_error(ArgumentError)
+ -> { @source.family_addrinfo(input, 666) }.should.raise(ArgumentError)
end
it "raises ArgumentError if the protocol families don't match" do
input = Addrinfo.tcp('::1', 0)
- -> { @source.family_addrinfo(input) }.should raise_error(ArgumentError)
+ -> { @source.family_addrinfo(input) }.should.raise(ArgumentError)
end
it "raises ArgumentError if the socket types don't match" do
input = Addrinfo.udp('127.0.0.1', 0)
- -> { @source.family_addrinfo(input) }.should raise_error(ArgumentError)
+ -> { @source.family_addrinfo(input) }.should.raise(ArgumentError)
end
end
end
diff --git a/spec/ruby/library/socket/addrinfo/foreach_spec.rb b/spec/ruby/library/socket/addrinfo/foreach_spec.rb
index 6ec8fab905..8cbbddb8f0 100644
--- a/spec/ruby/library/socket/addrinfo/foreach_spec.rb
+++ b/spec/ruby/library/socket/addrinfo/foreach_spec.rb
@@ -3,7 +3,7 @@ require_relative '../spec_helper'
describe 'Addrinfo.foreach' do
it 'yields Addrinfo instances to the supplied block' do
Addrinfo.foreach('127.0.0.1', 80) do |addr|
- addr.should be_an_instance_of(Addrinfo)
+ addr.should.instance_of?(Addrinfo)
end
end
end
diff --git a/spec/ruby/library/socket/addrinfo/getaddrinfo_spec.rb b/spec/ruby/library/socket/addrinfo/getaddrinfo_spec.rb
index e05fe9967a..47393ee167 100644
--- a/spec/ruby/library/socket/addrinfo/getaddrinfo_spec.rb
+++ b/spec/ruby/library/socket/addrinfo/getaddrinfo_spec.rb
@@ -5,8 +5,8 @@ describe 'Addrinfo.getaddrinfo' do
it 'returns an Array of Addrinfo instances' do
array = Addrinfo.getaddrinfo('127.0.0.1', 80)
- array.should be_an_instance_of(Array)
- array[0].should be_an_instance_of(Addrinfo)
+ array.should.instance_of?(Array)
+ array[0].should.instance_of?(Addrinfo)
end
SocketSpecs.each_ip_protocol do |family, ip_address|
@@ -54,7 +54,7 @@ describe 'Addrinfo.getaddrinfo' do
array = Addrinfo.getaddrinfo('127.0.0.1', 80)
possible = [Socket::SOCK_STREAM, Socket::SOCK_DGRAM]
- possible.should include(array[0].socktype)
+ possible.should.include?(array[0].socktype)
end
end
@@ -69,7 +69,7 @@ describe 'Addrinfo.getaddrinfo' do
array = Addrinfo.getaddrinfo('127.0.0.1', 80)
possible = [Socket::IPPROTO_TCP, Socket::IPPROTO_UDP]
- possible.should include(array[0].protocol)
+ possible.should.include?(array[0].protocol)
end
end
@@ -82,6 +82,6 @@ describe 'Addrinfo.getaddrinfo' do
it 'sets the canonical name when AI_CANONNAME is given as a flag' do
array = Addrinfo.getaddrinfo('localhost', 80, nil, nil, nil, Socket::AI_CANONNAME)
- array[0].canonname.should be_an_instance_of(String)
+ array[0].canonname.should.instance_of?(String)
end
end
diff --git a/spec/ruby/library/socket/addrinfo/getnameinfo_spec.rb b/spec/ruby/library/socket/addrinfo/getnameinfo_spec.rb
index 76579de74c..43b5a2000a 100644
--- a/spec/ruby/library/socket/addrinfo/getnameinfo_spec.rb
+++ b/spec/ruby/library/socket/addrinfo/getnameinfo_spec.rb
@@ -22,19 +22,17 @@ describe 'Addrinfo#getnameinfo' do
platform_is :linux do
platform_is_not :android do
- with_feature :unix_socket do
- describe 'using a UNIX Addrinfo' do
- before do
- @addr = Addrinfo.unix('cats')
- @host = Socket.gethostname
- end
+ describe 'using a UNIX Addrinfo' do
+ before do
+ @addr = Addrinfo.unix('cats')
+ @host = Socket.gethostname
+ end
- it 'returns the hostname and UNIX socket path' do
- host, path = @addr.getnameinfo
+ it 'returns the hostname and UNIX socket path' do
+ host, path = @addr.getnameinfo
- host.should == @host
- path.should == 'cats'
- end
+ host.should == @host
+ path.should == 'cats'
end
end
end
diff --git a/spec/ruby/library/socket/addrinfo/initialize_spec.rb b/spec/ruby/library/socket/addrinfo/initialize_spec.rb
index b7477efc79..f33255e38b 100644
--- a/spec/ruby/library/socket/addrinfo/initialize_spec.rb
+++ b/spec/ruby/library/socket/addrinfo/initialize_spec.rb
@@ -17,7 +17,7 @@ describe "Addrinfo#initialize" do
@addrinfo.ip_port.should == 25
end
- it "returns the Socket::UNSPEC pfamily" do
+ it "returns the UNSPEC pfamily" do
@addrinfo.pfamily.should == Socket::PF_UNSPEC
end
@@ -53,11 +53,11 @@ describe "Addrinfo#initialize" do
@addrinfo.ip_port.should == 25
end
- it "returns the Socket::UNSPEC pfamily" do
+ it "returns the specified pfamily" do
@addrinfo.pfamily.should == Socket::PF_INET6
end
- it "returns the INET6 afamily" do
+ it "returns the specified afamily" do
@addrinfo.afamily.should == Socket::AF_INET6
end
@@ -83,11 +83,11 @@ describe "Addrinfo#initialize" do
@addrinfo.ip_port.should == 25
end
- it "returns the Socket::UNSPEC pfamily" do
+ it "returns the specified pfamily" do
@addrinfo.pfamily.should == Socket::PF_INET6
end
- it "returns the INET6 afamily" do
+ it "returns the specified afamily" do
@addrinfo.afamily.should == Socket::AF_INET6
end
@@ -113,11 +113,11 @@ describe "Addrinfo#initialize" do
@addrinfo.ip_port.should == 25
end
- it "returns the Socket::UNSPEC pfamily" do
+ it "returns the specified pfamily" do
@addrinfo.pfamily.should == Socket::PF_INET6
end
- it "returns the INET6 afamily" do
+ it "returns the specified afamily" do
@addrinfo.afamily.should == Socket::AF_INET6
end
@@ -147,11 +147,11 @@ describe "Addrinfo#initialize" do
@addrinfo.ip_port.should == 46102
end
- it "returns the Socket::PF_INET pfamily" do
+ it "returns the specified pfamily" do
@addrinfo.pfamily.should == Socket::PF_INET
end
- it "returns the INET6 afamily" do
+ it "returns the specified afamily" do
@addrinfo.afamily.should == Socket::AF_INET
end
@@ -200,7 +200,7 @@ describe "Addrinfo#initialize" do
it 'raises SocketError' do
block = -> { Addrinfo.new(['AF_INET6', 80, 'hostname', '127.0.0.1']) }
- block.should raise_error(SocketError)
+ block.should.raise(SocketError)
end
end
@@ -217,11 +217,11 @@ describe "Addrinfo#initialize" do
@addrinfo.ip_port.should == 46102
end
- it "returns the Socket::UNSPEC pfamily" do
+ it "returns the specified pfamily" do
@addrinfo.pfamily.should == Socket::PF_INET
end
- it "returns the INET6 afamily" do
+ it "returns the specified afamily" do
@addrinfo.afamily.should == Socket::AF_INET
end
@@ -247,11 +247,11 @@ describe "Addrinfo#initialize" do
@addrinfo.ip_port.should == 46102
end
- it "returns the Socket::UNSPEC pfamily" do
+ it "returns the specified pfamily" do
@addrinfo.pfamily.should == Socket::PF_INET
end
- it "returns the INET6 afamily" do
+ it "returns the specified afamily" do
@addrinfo.afamily.should == Socket::AF_INET
end
@@ -294,7 +294,7 @@ describe "Addrinfo#initialize" do
value = Socket::SOCK_RDM
block = -> { Addrinfo.new(sockaddr, nil, value) }
- block.should raise_error(SocketError)
+ block.should.raise(SocketError)
end
end
@@ -311,11 +311,11 @@ describe "Addrinfo#initialize" do
@addrinfo.ip_port.should == 46102
end
- it "returns the Socket::UNSPEC pfamily" do
+ it "returns the specified pfamily" do
@addrinfo.pfamily.should == Socket::PF_INET
end
- it "returns the INET6 afamily" do
+ it "returns the specified afamily" do
@addrinfo.afamily.should == Socket::AF_INET
end
@@ -340,7 +340,7 @@ describe "Addrinfo#initialize" do
value = Socket.const_get(constant)
-> {
Addrinfo.new(@sockaddr, value)
- }.should raise_error(SocketError)
+ }.should.raise(SocketError)
end
end
end
@@ -368,7 +368,7 @@ describe "Addrinfo#initialize" do
value = Socket.const_get(type)
block = -> { Addrinfo.new(@sockaddr, nil, nil, value) }
- block.should raise_error(SocketError)
+ block.should.raise(SocketError)
end
end
end
@@ -396,7 +396,7 @@ describe "Addrinfo#initialize" do
value = Socket.const_get(type)
block = -> { Addrinfo.new(@sockaddr, nil, @socktype, value) }
- block.should raise_error(SocketError)
+ block.should.raise(SocketError)
end
end
end
@@ -413,7 +413,7 @@ describe "Addrinfo#initialize" do
value = Socket.const_get(type)
block = -> { Addrinfo.new(@sockaddr, nil, @socktype, value) }
- block.should raise_error(SocketError)
+ block.should.raise(SocketError)
end
end
end
@@ -444,7 +444,7 @@ describe "Addrinfo#initialize" do
value = Socket.const_get(type)
block = -> { Addrinfo.new(@sockaddr, nil, @socktype, value) }
- block.should raise_error(SocketError)
+ block.should.raise(SocketError)
end
end
end
@@ -472,7 +472,7 @@ describe "Addrinfo#initialize" do
value = Socket.const_get(type)
block = -> { Addrinfo.new(@sockaddr, nil, @socktype, value) }
- block.should raise_error(SocketError)
+ block.should.raise(SocketError)
end
end
end
@@ -501,7 +501,7 @@ describe "Addrinfo#initialize" do
value = Socket.const_get(type)
block = -> { Addrinfo.new(@sockaddr, nil, @socktype, value) }
- block.should raise_error(SocketError)
+ block.should.raise(SocketError)
end
end
end
@@ -514,13 +514,13 @@ describe "Addrinfo#initialize" do
@sockaddr = Socket.sockaddr_in(80, '127.0.0.1')
end
- it 'returns an Addrinfo with :PF_INET family' do
+ it 'returns an Addrinfo with the specified pfamily for :PF_INET' do
addr = Addrinfo.new(@sockaddr, :PF_INET)
addr.pfamily.should == Socket::PF_INET
end
- it 'returns an Addrinfo with :INET family' do
+ it 'returns an Addrinfo with the specified pfamily for :INET' do
addr = Addrinfo.new(@sockaddr, :INET)
addr.pfamily.should == Socket::PF_INET
@@ -544,13 +544,13 @@ describe "Addrinfo#initialize" do
@sockaddr = Socket.sockaddr_in(80, '127.0.0.1')
end
- it 'returns an Addrinfo with "PF_INET" family' do
+ it 'returns an Addrinfo with the specified pfamily for PF_INET' do
addr = Addrinfo.new(@sockaddr, 'PF_INET')
addr.pfamily.should == Socket::PF_INET
end
- it 'returns an Addrinfo with "INET" family' do
+ it 'returns an Addrinfo with the specified pfamily for INET' do
addr = Addrinfo.new(@sockaddr, 'INET')
addr.pfamily.should == Socket::PF_INET
@@ -569,23 +569,21 @@ describe "Addrinfo#initialize" do
end
end
- with_feature :unix_socket do
- describe 'using separate arguments for a Unix socket' do
- before do
- @sockaddr = Socket.pack_sockaddr_un('socket')
- end
+ describe 'using separate arguments for a Unix socket' do
+ before do
+ @sockaddr = Socket.pack_sockaddr_un('socket')
+ end
- it 'returns an Addrinfo with the correct unix path' do
- Addrinfo.new(@sockaddr).unix_path.should == 'socket'
- end
+ it 'returns an Addrinfo with the correct unix path' do
+ Addrinfo.new(@sockaddr).unix_path.should == 'socket'
+ end
- it 'returns an Addrinfo with the correct protocol family' do
- Addrinfo.new(@sockaddr).pfamily.should == Socket::PF_UNSPEC
- end
+ it 'returns an Addrinfo with the correct protocol family' do
+ Addrinfo.new(@sockaddr).pfamily.should == Socket::PF_UNSPEC
+ end
- it 'returns an Addrinfo with the correct address family' do
- Addrinfo.new(@sockaddr).afamily.should == Socket::AF_UNIX
- end
+ it 'returns an Addrinfo with the correct address family' do
+ Addrinfo.new(@sockaddr).afamily.should == Socket::AF_UNIX
end
end
end
diff --git a/spec/ruby/library/socket/addrinfo/inspect_sockaddr_spec.rb b/spec/ruby/library/socket/addrinfo/inspect_sockaddr_spec.rb
index 70ca4dd4d7..6b18c79469 100644
--- a/spec/ruby/library/socket/addrinfo/inspect_sockaddr_spec.rb
+++ b/spec/ruby/library/socket/addrinfo/inspect_sockaddr_spec.rb
@@ -32,19 +32,17 @@ describe 'Addrinfo#inspect_sockaddr' do
end
end
- with_feature :unix_socket do
- describe 'using a UNIX path' do
- it 'returns a String containing the UNIX path' do
- addr = Addrinfo.unix('/foo/bar')
+ describe 'using a UNIX path' do
+ it 'returns a String containing the UNIX path' do
+ addr = Addrinfo.unix('/foo/bar')
- addr.inspect_sockaddr.should == '/foo/bar'
- end
+ addr.inspect_sockaddr.should == '/foo/bar'
+ end
- it 'returns a String containing the UNIX path when using a relative path' do
- addr = Addrinfo.unix('foo')
+ it 'returns a String containing the UNIX path when using a relative path' do
+ addr = Addrinfo.unix('foo')
- addr.inspect_sockaddr.should == 'UNIX foo'
- end
+ addr.inspect_sockaddr.should == 'UNIX foo'
end
end
end
diff --git a/spec/ruby/library/socket/addrinfo/inspect_spec.rb b/spec/ruby/library/socket/addrinfo/inspect_spec.rb
index 98e1e83ffa..1442af6162 100644
--- a/spec/ruby/library/socket/addrinfo/inspect_spec.rb
+++ b/spec/ruby/library/socket/addrinfo/inspect_spec.rb
@@ -41,25 +41,23 @@ describe 'Addrinfo#inspect' do
end
end
- with_feature :unix_socket do
- describe 'using a UNIX Addrinfo' do
- it 'returns a String' do
- addr = Addrinfo.unix('/foo')
+ describe 'using a UNIX Addrinfo' do
+ it 'returns a String' do
+ addr = Addrinfo.unix('/foo')
- addr.inspect.should == '#<Addrinfo: /foo SOCK_STREAM>'
- end
+ addr.inspect.should == '#<Addrinfo: /foo SOCK_STREAM>'
+ end
- it 'returns a String when using a relative UNIX path' do
- addr = Addrinfo.unix('foo')
+ it 'returns a String when using a relative UNIX path' do
+ addr = Addrinfo.unix('foo')
- addr.inspect.should == '#<Addrinfo: UNIX foo SOCK_STREAM>'
- end
+ addr.inspect.should == '#<Addrinfo: UNIX foo SOCK_STREAM>'
+ end
- it 'returns a String when using a DGRAM socket' do
- addr = Addrinfo.unix('/foo', Socket::SOCK_DGRAM)
+ it 'returns a String when using a DGRAM socket' do
+ addr = Addrinfo.unix('/foo', Socket::SOCK_DGRAM)
- addr.inspect.should == '#<Addrinfo: /foo SOCK_DGRAM>'
- end
+ addr.inspect.should == '#<Addrinfo: /foo SOCK_DGRAM>'
end
end
end
diff --git a/spec/ruby/library/socket/addrinfo/ip_address_spec.rb b/spec/ruby/library/socket/addrinfo/ip_address_spec.rb
index 4522cf5cfd..9a0ede4eeb 100644
--- a/spec/ruby/library/socket/addrinfo/ip_address_spec.rb
+++ b/spec/ruby/library/socket/addrinfo/ip_address_spec.rb
@@ -21,15 +21,13 @@ describe "Addrinfo#ip_address" do
end
end
- with_feature :unix_socket do
- describe "for a unix socket" do
- before :each do
- @addrinfo = Addrinfo.unix("/tmp/sock")
- end
+ describe "for a unix socket" do
+ before :each do
+ @addrinfo = Addrinfo.unix("/tmp/sock")
+ end
- it "raises an exception" do
- -> { @addrinfo.ip_address }.should raise_error(SocketError)
- end
+ it "raises an exception" do
+ -> { @addrinfo.ip_address }.should.raise(SocketError)
end
end
diff --git a/spec/ruby/library/socket/addrinfo/ip_port_spec.rb b/spec/ruby/library/socket/addrinfo/ip_port_spec.rb
index 4118607db0..00f74cdd46 100644
--- a/spec/ruby/library/socket/addrinfo/ip_port_spec.rb
+++ b/spec/ruby/library/socket/addrinfo/ip_port_spec.rb
@@ -21,15 +21,13 @@ describe "Addrinfo#ip_port" do
end
end
- with_feature :unix_socket do
- describe "for a unix socket" do
- before :each do
- @addrinfo = Addrinfo.unix("/tmp/sock")
- end
+ describe "for a unix socket" do
+ before :each do
+ @addrinfo = Addrinfo.unix("/tmp/sock")
+ end
- it "raises an exception" do
- -> { @addrinfo.ip_port }.should raise_error(SocketError)
- end
+ it "raises an exception" do
+ -> { @addrinfo.ip_port }.should.raise(SocketError)
end
end
end
diff --git a/spec/ruby/library/socket/addrinfo/ip_spec.rb b/spec/ruby/library/socket/addrinfo/ip_spec.rb
index 80e7a62df7..2237eca263 100644
--- a/spec/ruby/library/socket/addrinfo/ip_spec.rb
+++ b/spec/ruby/library/socket/addrinfo/ip_spec.rb
@@ -8,7 +8,7 @@ describe "Addrinfo#ip?" do
end
it "returns true" do
- @addrinfo.ip?.should be_true
+ @addrinfo.ip?.should == true
end
end
@@ -18,19 +18,17 @@ describe "Addrinfo#ip?" do
end
it "returns true" do
- @addrinfo.ip?.should be_true
+ @addrinfo.ip?.should == true
end
end
- with_feature :unix_socket do
- describe "for a unix socket" do
- before :each do
- @addrinfo = Addrinfo.unix("/tmp/sock")
- end
+ describe "for a unix socket" do
+ before :each do
+ @addrinfo = Addrinfo.unix("/tmp/sock")
+ end
- it "returns false" do
- @addrinfo.ip?.should be_false
- end
+ it "returns false" do
+ @addrinfo.ip?.should == false
end
end
end
@@ -38,7 +36,7 @@ end
describe 'Addrinfo.ip' do
SocketSpecs.each_ip_protocol do |family, ip_address|
it 'returns an Addrinfo instance' do
- Addrinfo.ip(ip_address).should be_an_instance_of(Addrinfo)
+ Addrinfo.ip(ip_address).should.instance_of?(Addrinfo)
end
it 'sets the IP address' do
diff --git a/spec/ruby/library/socket/addrinfo/ip_unpack_spec.rb b/spec/ruby/library/socket/addrinfo/ip_unpack_spec.rb
index 6c81c48d1c..b48ca062ee 100644
--- a/spec/ruby/library/socket/addrinfo/ip_unpack_spec.rb
+++ b/spec/ruby/library/socket/addrinfo/ip_unpack_spec.rb
@@ -21,15 +21,13 @@ describe "Addrinfo#ip_unpack" do
end
end
- with_feature :unix_socket do
- describe "for a unix socket" do
- before :each do
- @addrinfo = Addrinfo.unix("/tmp/sock")
- end
+ describe "for a unix socket" do
+ before :each do
+ @addrinfo = Addrinfo.unix("/tmp/sock")
+ end
- it "raises an exception" do
- -> { @addrinfo.ip_unpack }.should raise_error(SocketError)
- end
+ it "raises an exception" do
+ -> { @addrinfo.ip_unpack }.should.raise(SocketError)
end
end
end
diff --git a/spec/ruby/library/socket/addrinfo/ipv4_loopback_spec.rb b/spec/ruby/library/socket/addrinfo/ipv4_loopback_spec.rb
index 10ad084fc9..266281ce7a 100644
--- a/spec/ruby/library/socket/addrinfo/ipv4_loopback_spec.rb
+++ b/spec/ruby/library/socket/addrinfo/ipv4_loopback_spec.rb
@@ -10,7 +10,7 @@ describe "Addrinfo#ipv4_loopback?" do
end
it "returns false for another address" do
- Addrinfo.ip('255.255.255.0').ipv4_loopback?.should be_false
+ Addrinfo.ip('255.255.255.0').ipv4_loopback?.should == false
end
end
@@ -21,23 +21,21 @@ describe "Addrinfo#ipv4_loopback?" do
end
it "returns false for the loopback address" do
- @loopback.ipv4_loopback?.should be_false
+ @loopback.ipv4_loopback?.should == false
end
it "returns false for another address" do
- @other.ipv4_loopback?.should be_false
+ @other.ipv4_loopback?.should == false
end
end
- with_feature :unix_socket do
- describe "for a unix socket" do
- before :each do
- @addrinfo = Addrinfo.unix("/tmp/sock")
- end
+ describe "for a unix socket" do
+ before :each do
+ @addrinfo = Addrinfo.unix("/tmp/sock")
+ end
- it "returns false" do
- @addrinfo.ipv4_loopback?.should be_false
- end
+ it "returns false" do
+ @addrinfo.ipv4_loopback?.should == false
end
end
end
diff --git a/spec/ruby/library/socket/addrinfo/ipv4_multicast_spec.rb b/spec/ruby/library/socket/addrinfo/ipv4_multicast_spec.rb
index f7fead8640..bc8a31dfa8 100644
--- a/spec/ruby/library/socket/addrinfo/ipv4_multicast_spec.rb
+++ b/spec/ruby/library/socket/addrinfo/ipv4_multicast_spec.rb
@@ -15,15 +15,13 @@ describe "Addrinfo#ipv4_multicast?" do
Addrinfo.ip('::1').should_not.ipv4_multicast?
end
- with_feature :unix_socket do
- describe "for a unix socket" do
- before :each do
- @addrinfo = Addrinfo.unix("/tmp/sock")
- end
+ describe "for a unix socket" do
+ before :each do
+ @addrinfo = Addrinfo.unix("/tmp/sock")
+ end
- it "returns false" do
- @addrinfo.ipv4_multicast?.should be_false
- end
+ it "returns false" do
+ @addrinfo.ipv4_multicast?.should == false
end
end
end
diff --git a/spec/ruby/library/socket/addrinfo/ipv4_private_spec.rb b/spec/ruby/library/socket/addrinfo/ipv4_private_spec.rb
index e5a33b4953..8cfbf0a25e 100644
--- a/spec/ruby/library/socket/addrinfo/ipv4_private_spec.rb
+++ b/spec/ruby/library/socket/addrinfo/ipv4_private_spec.rb
@@ -19,7 +19,7 @@ describe "Addrinfo#ipv4_private?" do
end
it "returns false for a public address" do
- @other.ipv4_private?.should be_false
+ @other.ipv4_private?.should == false
end
end
@@ -29,19 +29,17 @@ describe "Addrinfo#ipv4_private?" do
end
it "returns false" do
- @other.ipv4_private?.should be_false
+ @other.ipv4_private?.should == false
end
end
- with_feature :unix_socket do
- describe "for a unix socket" do
- before :each do
- @addrinfo = Addrinfo.unix("/tmp/sock")
- end
+ describe "for a unix socket" do
+ before :each do
+ @addrinfo = Addrinfo.unix("/tmp/sock")
+ end
- it "returns false" do
- @addrinfo.ipv4_private?.should be_false
- end
+ it "returns false" do
+ @addrinfo.ipv4_private?.should == false
end
end
end
diff --git a/spec/ruby/library/socket/addrinfo/ipv4_spec.rb b/spec/ruby/library/socket/addrinfo/ipv4_spec.rb
index 7cba8209b6..8fef94a8e8 100644
--- a/spec/ruby/library/socket/addrinfo/ipv4_spec.rb
+++ b/spec/ruby/library/socket/addrinfo/ipv4_spec.rb
@@ -7,7 +7,7 @@ describe "Addrinfo#ipv4?" do
end
it "returns true" do
- @addrinfo.ipv4?.should be_true
+ @addrinfo.ipv4?.should == true
end
end
@@ -17,19 +17,17 @@ describe "Addrinfo#ipv4?" do
end
it "returns false" do
- @addrinfo.ipv4?.should be_false
+ @addrinfo.ipv4?.should == false
end
end
- with_feature :unix_socket do
- describe "for a unix socket" do
- before :each do
- @addrinfo = Addrinfo.unix("/tmp/sock")
- end
+ describe "for a unix socket" do
+ before :each do
+ @addrinfo = Addrinfo.unix("/tmp/sock")
+ end
- it "returns false" do
- @addrinfo.ipv4?.should be_false
- end
+ it "returns false" do
+ @addrinfo.ipv4?.should == false
end
end
end
diff --git a/spec/ruby/library/socket/addrinfo/ipv6_loopback_spec.rb b/spec/ruby/library/socket/addrinfo/ipv6_loopback_spec.rb
index 9ff8f107bf..2e8241e336 100644
--- a/spec/ruby/library/socket/addrinfo/ipv6_loopback_spec.rb
+++ b/spec/ruby/library/socket/addrinfo/ipv6_loopback_spec.rb
@@ -8,11 +8,11 @@ describe "Addrinfo#ipv6_loopback?" do
end
it "returns false for the loopback address" do
- @loopback.ipv6_loopback?.should be_false
+ @loopback.ipv6_loopback?.should == false
end
it "returns false for another address" do
- @other.ipv6_loopback?.should be_false
+ @other.ipv6_loopback?.should == false
end
end
@@ -23,23 +23,21 @@ describe "Addrinfo#ipv6_loopback?" do
end
it "returns true for the loopback address" do
- @loopback.ipv6_loopback?.should be_true
+ @loopback.ipv6_loopback?.should == true
end
it "returns false for another address" do
- @other.ipv6_loopback?.should be_false
+ @other.ipv6_loopback?.should == false
end
end
- with_feature :unix_socket do
- describe "for a unix socket" do
- before :each do
- @addrinfo = Addrinfo.unix("/tmp/sock")
- end
+ describe "for a unix socket" do
+ before :each do
+ @addrinfo = Addrinfo.unix("/tmp/sock")
+ end
- it "returns false" do
- @addrinfo.ipv6_loopback?.should be_false
- end
+ it "returns false" do
+ @addrinfo.ipv6_loopback?.should == false
end
end
end
diff --git a/spec/ruby/library/socket/addrinfo/ipv6_multicast_spec.rb b/spec/ruby/library/socket/addrinfo/ipv6_multicast_spec.rb
index 2c987b5921..52787e5e53 100644
--- a/spec/ruby/library/socket/addrinfo/ipv6_multicast_spec.rb
+++ b/spec/ruby/library/socket/addrinfo/ipv6_multicast_spec.rb
@@ -8,11 +8,11 @@ describe "Addrinfo#ipv6_multicast?" do
end
it "returns true for a multicast address" do
- @multicast.ipv6_multicast?.should be_false
+ @multicast.ipv6_multicast?.should == false
end
it "returns false for another address" do
- @other.ipv6_multicast?.should be_false
+ @other.ipv6_multicast?.should == false
end
end
@@ -34,15 +34,13 @@ describe "Addrinfo#ipv6_multicast?" do
end
end
- with_feature :unix_socket do
- describe "for a unix socket" do
- before :each do
- @addrinfo = Addrinfo.unix("/tmp/sock")
- end
+ describe "for a unix socket" do
+ before :each do
+ @addrinfo = Addrinfo.unix("/tmp/sock")
+ end
- it "returns false" do
- @addrinfo.ipv6_multicast?.should be_false
- end
+ it "returns false" do
+ @addrinfo.ipv6_multicast?.should == false
end
end
end
diff --git a/spec/ruby/library/socket/addrinfo/ipv6_spec.rb b/spec/ruby/library/socket/addrinfo/ipv6_spec.rb
index 131e38849c..9fa8e9bd0c 100644
--- a/spec/ruby/library/socket/addrinfo/ipv6_spec.rb
+++ b/spec/ruby/library/socket/addrinfo/ipv6_spec.rb
@@ -7,7 +7,7 @@ describe "Addrinfo#ipv6?" do
end
it "returns true" do
- @addrinfo.ipv6?.should be_false
+ @addrinfo.ipv6?.should == false
end
end
@@ -17,19 +17,17 @@ describe "Addrinfo#ipv6?" do
end
it "returns false" do
- @addrinfo.ipv6?.should be_true
+ @addrinfo.ipv6?.should == true
end
end
- with_feature :unix_socket do
- describe "for a unix socket" do
- before :each do
- @addrinfo = Addrinfo.unix("/tmp/sock")
- end
+ describe "for a unix socket" do
+ before :each do
+ @addrinfo = Addrinfo.unix("/tmp/sock")
+ end
- it "returns false" do
- @addrinfo.ipv6?.should be_false
- end
+ it "returns false" do
+ @addrinfo.ipv6?.should == false
end
end
end
diff --git a/spec/ruby/library/socket/addrinfo/ipv6_to_ipv4_spec.rb b/spec/ruby/library/socket/addrinfo/ipv6_to_ipv4_spec.rb
index 6dfaf531ae..d1436d4527 100644
--- a/spec/ruby/library/socket/addrinfo/ipv6_to_ipv4_spec.rb
+++ b/spec/ruby/library/socket/addrinfo/ipv6_to_ipv4_spec.rb
@@ -6,7 +6,7 @@ guard -> { SocketSpecs.ipv6_available? } do
it 'returns an Addrinfo for ::192.168.1.1' do
addr = Addrinfo.ip('::192.168.1.1').ipv6_to_ipv4
- addr.should be_an_instance_of(Addrinfo)
+ addr.should.instance_of?(Addrinfo)
addr.afamily.should == Socket::AF_INET
addr.ip_address.should == '192.168.1.1'
@@ -16,7 +16,7 @@ guard -> { SocketSpecs.ipv6_available? } do
it 'returns an Addrinfo for ::0.0.1.1' do
addr = Addrinfo.ip('::0.0.1.1').ipv6_to_ipv4
- addr.should be_an_instance_of(Addrinfo)
+ addr.should.instance_of?(Addrinfo)
addr.afamily.should == Socket::AF_INET
addr.ip_address.should == '0.0.1.1'
@@ -25,7 +25,7 @@ guard -> { SocketSpecs.ipv6_available? } do
it 'returns an Addrinfo for ::0.0.1.0' do
addr = Addrinfo.ip('::0.0.1.0').ipv6_to_ipv4
- addr.should be_an_instance_of(Addrinfo)
+ addr.should.instance_of?(Addrinfo)
addr.afamily.should == Socket::AF_INET
addr.ip_address.should == '0.0.1.0'
@@ -34,7 +34,7 @@ guard -> { SocketSpecs.ipv6_available? } do
it 'returns an Addrinfo for ::0.1.0.0' do
addr = Addrinfo.ip('::0.1.0.0').ipv6_to_ipv4
- addr.should be_an_instance_of(Addrinfo)
+ addr.should.instance_of?(Addrinfo)
addr.afamily.should == Socket::AF_INET
addr.ip_address.should == '0.1.0.0'
@@ -44,27 +44,27 @@ guard -> { SocketSpecs.ipv6_available? } do
it 'returns an Addrinfo for ::ffff:192.168.1.1' do
addr = Addrinfo.ip('::ffff:192.168.1.1').ipv6_to_ipv4
- addr.should be_an_instance_of(Addrinfo)
+ addr.should.instance_of?(Addrinfo)
addr.afamily.should == Socket::AF_INET
addr.ip_address.should == '192.168.1.1'
end
it 'returns nil for ::0.0.0.1' do
- Addrinfo.ip('::0.0.0.1').ipv6_to_ipv4.should be_nil
+ Addrinfo.ip('::0.0.0.1').ipv6_to_ipv4.should == nil
end
it 'returns nil for a pure IPv6 Addrinfo' do
- Addrinfo.ip('::1').ipv6_to_ipv4.should be_nil
+ Addrinfo.ip('::1').ipv6_to_ipv4.should == nil
end
it 'returns nil for an IPv4 Addrinfo' do
- Addrinfo.ip('192.168.1.1').ipv6_to_ipv4.should be_nil
+ Addrinfo.ip('192.168.1.1').ipv6_to_ipv4.should == nil
end
- with_feature :unix_socket do
+ describe 'for a unix socket' do
it 'returns nil for a UNIX Addrinfo' do
- Addrinfo.unix('foo').ipv6_to_ipv4.should be_nil
+ Addrinfo.unix('foo').ipv6_to_ipv4.should == nil
end
end
end
diff --git a/spec/ruby/library/socket/addrinfo/listen_spec.rb b/spec/ruby/library/socket/addrinfo/listen_spec.rb
index 931093f732..80bcdc7f83 100644
--- a/spec/ruby/library/socket/addrinfo/listen_spec.rb
+++ b/spec/ruby/library/socket/addrinfo/listen_spec.rb
@@ -13,12 +13,12 @@ describe 'Addrinfo#listen' do
it 'returns a Socket when no block is given' do
@socket = @addr.listen
- @socket.should be_an_instance_of(Socket)
+ @socket.should.instance_of?(Socket)
end
it 'yields the Socket if a block is given' do
@addr.listen do |socket|
- socket.should be_an_instance_of(Socket)
+ socket.should.instance_of?(Socket)
end
end
diff --git a/spec/ruby/library/socket/addrinfo/marshal_dump_spec.rb b/spec/ruby/library/socket/addrinfo/marshal_dump_spec.rb
index 2d69a33b53..438b04a99c 100644
--- a/spec/ruby/library/socket/addrinfo/marshal_dump_spec.rb
+++ b/spec/ruby/library/socket/addrinfo/marshal_dump_spec.rb
@@ -8,7 +8,7 @@ describe 'Addrinfo#marshal_dump' do
end
it 'returns an Array' do
- @addr.marshal_dump.should be_an_instance_of(Array)
+ @addr.marshal_dump.should.instance_of?(Array)
end
describe 'the returned Array' do
@@ -42,40 +42,38 @@ describe 'Addrinfo#marshal_dump' do
end
end
- with_feature :unix_socket do
- describe 'using a UNIX Addrinfo' do
+ describe 'using a UNIX Addrinfo' do
+ before do
+ @addr = Addrinfo.unix('foo')
+ end
+
+ it 'returns an Array' do
+ @addr.marshal_dump.should.instance_of?(Array)
+ end
+
+ describe 'the returned Array' do
before do
- @addr = Addrinfo.unix('foo')
+ @array = @addr.marshal_dump
end
- it 'returns an Array' do
- @addr.marshal_dump.should be_an_instance_of(Array)
+ it 'includes the address family as the 1st value' do
+ @array[0].should == 'AF_UNIX'
end
- describe 'the returned Array' do
- before do
- @array = @addr.marshal_dump
- end
-
- it 'includes the address family as the 1st value' do
- @array[0].should == 'AF_UNIX'
- end
-
- it 'includes the UNIX path as the 2nd value' do
- @array[1].should == @addr.unix_path
- end
+ it 'includes the UNIX path as the 2nd value' do
+ @array[1].should == @addr.unix_path
+ end
- it 'includes the protocol family as the 3rd value' do
- @array[2].should == 'PF_UNIX'
- end
+ it 'includes the protocol family as the 3rd value' do
+ @array[2].should == 'PF_UNIX'
+ end
- it 'includes the socket type as the 4th value' do
- @array[3].should == 'SOCK_STREAM'
- end
+ it 'includes the socket type as the 4th value' do
+ @array[3].should == 'SOCK_STREAM'
+ end
- it 'includes the protocol as the 5th value' do
- @array[4].should == 0
- end
+ it 'includes the protocol as the 5th value' do
+ @array[4].should == 0
end
end
end
diff --git a/spec/ruby/library/socket/addrinfo/marshal_load_spec.rb b/spec/ruby/library/socket/addrinfo/marshal_load_spec.rb
index aa20865224..02cef90115 100644
--- a/spec/ruby/library/socket/addrinfo/marshal_load_spec.rb
+++ b/spec/ruby/library/socket/addrinfo/marshal_load_spec.rb
@@ -18,18 +18,16 @@ describe 'Addrinfo#marshal_load' do
end
end
- with_feature :unix_socket do
- describe 'using a UNIX socket' do
- it 'returns a new Addrinfo' do
- source = Addrinfo.unix('foo')
- addr = Marshal.load(Marshal.dump(source))
+ describe 'using a UNIX socket' do
+ it 'returns a new Addrinfo' do
+ source = Addrinfo.unix('foo')
+ addr = Marshal.load(Marshal.dump(source))
- addr.afamily.should == source.afamily
- addr.pfamily.should == source.pfamily
- addr.socktype.should == source.socktype
- addr.protocol.should == source.protocol
- addr.unix_path.should == source.unix_path
- end
+ addr.afamily.should == source.afamily
+ addr.pfamily.should == source.pfamily
+ addr.socktype.should == source.socktype
+ addr.protocol.should == source.protocol
+ addr.unix_path.should == source.unix_path
end
end
end
diff --git a/spec/ruby/library/socket/addrinfo/pfamily_spec.rb b/spec/ruby/library/socket/addrinfo/pfamily_spec.rb
index 984744a964..da530b7fdc 100644
--- a/spec/ruby/library/socket/addrinfo/pfamily_spec.rb
+++ b/spec/ruby/library/socket/addrinfo/pfamily_spec.rb
@@ -29,15 +29,13 @@ describe "Addrinfo#pfamily" do
end
end
- with_feature :unix_socket do
- describe "for a unix socket" do
- before :each do
- @addrinfo = Addrinfo.unix("/tmp/sock")
- end
-
- it "returns Socket::PF_UNIX" do
- @addrinfo.pfamily.should == Socket::PF_UNIX
- end
+ describe "for a unix socket" do
+ before :each do
+ @addrinfo = Addrinfo.unix("/tmp/sock")
+ end
+
+ it "returns Socket::PF_UNIX" do
+ @addrinfo.pfamily.should == Socket::PF_UNIX
end
end
end
diff --git a/spec/ruby/library/socket/addrinfo/protocol_spec.rb b/spec/ruby/library/socket/addrinfo/protocol_spec.rb
index ea143fc4a8..f6ffc9acf9 100644
--- a/spec/ruby/library/socket/addrinfo/protocol_spec.rb
+++ b/spec/ruby/library/socket/addrinfo/protocol_spec.rb
@@ -10,15 +10,13 @@ describe "Addrinfo#protocol" do
Addrinfo.tcp('::1', 80).protocol.should == Socket::IPPROTO_TCP
end
- with_feature :unix_socket do
- describe "for a unix socket" do
- before :each do
- @addrinfo = Addrinfo.unix("/tmp/sock")
- end
+ describe "for a unix socket" do
+ before :each do
+ @addrinfo = Addrinfo.unix("/tmp/sock")
+ end
- it "returns 0" do
- @addrinfo.protocol.should == 0
- end
+ it "returns 0" do
+ @addrinfo.protocol.should == 0
end
end
end
diff --git a/spec/ruby/library/socket/addrinfo/shared/to_sockaddr.rb b/spec/ruby/library/socket/addrinfo/shared/to_sockaddr.rb
deleted file mode 100644
index 4f7cf439a0..0000000000
--- a/spec/ruby/library/socket/addrinfo/shared/to_sockaddr.rb
+++ /dev/null
@@ -1,49 +0,0 @@
-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)
- end
-
- it "returns a sockaddr packed structure" do
- @addrinfo.send(@method).should == Socket.sockaddr_in(80, '127.0.0.1')
- end
- end
-
- describe "for an ipv6 socket" do
- before :each do
- @addrinfo = Addrinfo.tcp("::1", 80)
- end
-
- it "returns a sockaddr packed structure" do
- @addrinfo.send(@method).should == Socket.sockaddr_in(80, '::1')
- end
- end
-
- with_feature :unix_socket do
- describe "for a unix socket" do
- before :each do
- @addrinfo = Addrinfo.unix("/tmp/sock")
- end
-
- it "returns a sockaddr packed structure" do
- @addrinfo.send(@method).should == Socket.sockaddr_un('/tmp/sock')
- end
- end
- end
-
- describe 'using a Addrinfo with just an IP address' do
- it 'returns a String' do
- addr = Addrinfo.ip('127.0.0.1')
-
- addr.send(@method).should == Socket.sockaddr_in(0, '127.0.0.1')
- end
- end
-
- describe 'using a Addrinfo without an IP and port' do
- it 'returns a String' do
- addr = Addrinfo.new(['AF_INET', 0, '', ''])
-
- addr.send(@method).should == Socket.sockaddr_in(0, '')
- end
- end
-end
diff --git a/spec/ruby/library/socket/addrinfo/socktype_spec.rb b/spec/ruby/library/socket/addrinfo/socktype_spec.rb
index b994bea140..e5f02cd759 100644
--- a/spec/ruby/library/socket/addrinfo/socktype_spec.rb
+++ b/spec/ruby/library/socket/addrinfo/socktype_spec.rb
@@ -9,15 +9,13 @@ describe "Addrinfo#socktype" do
Addrinfo.tcp('127.0.0.1', 80).socktype.should == Socket::SOCK_STREAM
end
- with_feature :unix_socket do
- describe "for a unix socket" do
- before :each do
- @addrinfo = Addrinfo.unix("/tmp/sock")
- end
+ describe "for a unix socket" do
+ before :each do
+ @addrinfo = Addrinfo.unix("/tmp/sock")
+ end
- it "returns Socket::SOCK_STREAM" do
- @addrinfo.socktype.should == Socket::SOCK_STREAM
- end
+ it "returns Socket::SOCK_STREAM" do
+ @addrinfo.socktype.should == Socket::SOCK_STREAM
end
end
end
diff --git a/spec/ruby/library/socket/addrinfo/tcp_spec.rb b/spec/ruby/library/socket/addrinfo/tcp_spec.rb
index c74c9c21c2..0669de16a6 100644
--- a/spec/ruby/library/socket/addrinfo/tcp_spec.rb
+++ b/spec/ruby/library/socket/addrinfo/tcp_spec.rb
@@ -4,7 +4,7 @@ require_relative '../fixtures/classes'
describe 'Addrinfo.tcp' do
SocketSpecs.each_ip_protocol do |family, ip_address|
it 'returns an Addrinfo instance' do
- Addrinfo.tcp(ip_address, 80).should be_an_instance_of(Addrinfo)
+ Addrinfo.tcp(ip_address, 80).should.instance_of?(Addrinfo)
end
it 'sets the IP address' do
diff --git a/spec/ruby/library/socket/addrinfo/to_s_spec.rb b/spec/ruby/library/socket/addrinfo/to_s_spec.rb
index ddf994e051..5c1c82793c 100644
--- a/spec/ruby/library/socket/addrinfo/to_s_spec.rb
+++ b/spec/ruby/library/socket/addrinfo/to_s_spec.rb
@@ -1,6 +1,7 @@
require_relative '../spec_helper'
-require_relative 'shared/to_sockaddr'
describe "Addrinfo#to_s" do
- it_behaves_like :socket_addrinfo_to_sockaddr, :to_s
+ it "is an alias of Addrinfo#to_sockaddr" do
+ Addrinfo.instance_method(:to_s).should == Addrinfo.instance_method(:to_sockaddr)
+ end
end
diff --git a/spec/ruby/library/socket/addrinfo/to_sockaddr_spec.rb b/spec/ruby/library/socket/addrinfo/to_sockaddr_spec.rb
index b9f75454bd..c703c7b28f 100644
--- a/spec/ruby/library/socket/addrinfo/to_sockaddr_spec.rb
+++ b/spec/ruby/library/socket/addrinfo/to_sockaddr_spec.rb
@@ -1,6 +1,49 @@
require_relative '../spec_helper'
-require_relative 'shared/to_sockaddr'
describe "Addrinfo#to_sockaddr" do
- it_behaves_like :socket_addrinfo_to_sockaddr, :to_sockaddr
+ describe "for an ipv4 socket" do
+ before :each do
+ @addrinfo = Addrinfo.tcp("127.0.0.1", 80)
+ end
+
+ it "returns a sockaddr packed structure" do
+ @addrinfo.to_sockaddr.should == Socket.sockaddr_in(80, '127.0.0.1')
+ end
+ end
+
+ describe "for an ipv6 socket" do
+ before :each do
+ @addrinfo = Addrinfo.tcp("::1", 80)
+ end
+
+ it "returns a sockaddr packed structure" do
+ @addrinfo.to_sockaddr.should == Socket.sockaddr_in(80, '::1')
+ end
+ end
+
+ describe "for a unix socket" do
+ before :each do
+ @addrinfo = Addrinfo.unix("/tmp/sock")
+ end
+
+ it "returns a sockaddr packed structure" do
+ @addrinfo.to_sockaddr.should == Socket.sockaddr_un('/tmp/sock')
+ end
+ end
+
+ describe 'using a Addrinfo with just an IP address' do
+ it 'returns a String' do
+ addr = Addrinfo.ip('127.0.0.1')
+
+ addr.to_sockaddr.should == Socket.sockaddr_in(0, '127.0.0.1')
+ end
+ end
+
+ describe 'using a Addrinfo without an IP and port' do
+ it 'returns a String' do
+ addr = Addrinfo.new(['AF_INET', 0, '', ''])
+
+ addr.to_sockaddr.should == Socket.sockaddr_in(0, '')
+ end
+ end
end
diff --git a/spec/ruby/library/socket/addrinfo/udp_spec.rb b/spec/ruby/library/socket/addrinfo/udp_spec.rb
index ac02e76ef5..51d7f5588e 100644
--- a/spec/ruby/library/socket/addrinfo/udp_spec.rb
+++ b/spec/ruby/library/socket/addrinfo/udp_spec.rb
@@ -4,7 +4,7 @@ require_relative '../fixtures/classes'
describe 'Addrinfo.udp' do
SocketSpecs.each_ip_protocol do |family, ip_address|
it 'returns an Addrinfo instance' do
- Addrinfo.udp(ip_address, 80).should be_an_instance_of(Addrinfo)
+ Addrinfo.udp(ip_address, 80).should.instance_of?(Addrinfo)
end
it 'sets the IP address' do
diff --git a/spec/ruby/library/socket/addrinfo/unix_path_spec.rb b/spec/ruby/library/socket/addrinfo/unix_path_spec.rb
index 6bfb56a4ac..c15075bce3 100644
--- a/spec/ruby/library/socket/addrinfo/unix_path_spec.rb
+++ b/spec/ruby/library/socket/addrinfo/unix_path_spec.rb
@@ -1,37 +1,35 @@
require_relative '../spec_helper'
-with_feature :unix_socket do
- describe "Addrinfo#unix_path" do
- describe "for an ipv4 socket" do
+describe "Addrinfo#unix_path" do
+ describe "for an ipv4 socket" do
- before :each do
- @addrinfo = Addrinfo.tcp("127.0.0.1", 80)
- end
-
- it "raises an exception" do
- -> { @addrinfo.unix_path }.should raise_error(SocketError)
- end
+ before :each do
+ @addrinfo = Addrinfo.tcp("127.0.0.1", 80)
+ end
+ it "raises an exception" do
+ -> { @addrinfo.unix_path }.should.raise(SocketError)
end
- describe "for an ipv6 socket" do
- before :each do
- @addrinfo = Addrinfo.tcp("::1", 80)
- end
+ end
- it "raises an exception" do
- -> { @addrinfo.unix_path }.should raise_error(SocketError)
- end
+ describe "for an ipv6 socket" do
+ before :each do
+ @addrinfo = Addrinfo.tcp("::1", 80)
end
- describe "for a unix socket" do
- before :each do
- @addrinfo = Addrinfo.unix("/tmp/sock")
- end
+ it "raises an exception" do
+ -> { @addrinfo.unix_path }.should.raise(SocketError)
+ end
+ end
+
+ describe "for a unix socket" do
+ before :each do
+ @addrinfo = Addrinfo.unix("/tmp/sock")
+ end
- it "returns the socket path" do
- @addrinfo.unix_path.should == "/tmp/sock"
- end
+ it "returns the socket path" do
+ @addrinfo.unix_path.should == "/tmp/sock"
end
end
end
diff --git a/spec/ruby/library/socket/addrinfo/unix_spec.rb b/spec/ruby/library/socket/addrinfo/unix_spec.rb
index 4596ece17e..da65e13efb 100644
--- a/spec/ruby/library/socket/addrinfo/unix_spec.rb
+++ b/spec/ruby/library/socket/addrinfo/unix_spec.rb
@@ -1,36 +1,34 @@
require_relative '../spec_helper'
-with_feature :unix_socket do
- describe 'Addrinfo.unix' do
- it 'returns an Addrinfo instance' do
- Addrinfo.unix('socket').should be_an_instance_of(Addrinfo)
- end
+describe 'Addrinfo.unix' do
+ it 'returns an Addrinfo instance' do
+ Addrinfo.unix('socket').should.instance_of?(Addrinfo)
+ end
- it 'sets the IP address' do
- Addrinfo.unix('socket').unix_path.should == 'socket'
- end
+ it 'sets the IP address' do
+ Addrinfo.unix('socket').unix_path.should == 'socket'
+ end
- it 'sets the address family' do
- Addrinfo.unix('socket').afamily.should == Socket::AF_UNIX
- end
+ it 'sets the address family' do
+ Addrinfo.unix('socket').afamily.should == Socket::AF_UNIX
+ end
- it 'sets the protocol family' do
- Addrinfo.unix('socket').pfamily.should == Socket::PF_UNIX
- end
+ it 'sets the protocol family' do
+ Addrinfo.unix('socket').pfamily.should == Socket::PF_UNIX
+ end
- it 'sets the socket type' do
- Addrinfo.unix('socket').socktype.should == Socket::SOCK_STREAM
- end
+ it 'sets the socket type' do
+ Addrinfo.unix('socket').socktype.should == Socket::SOCK_STREAM
+ end
- it 'sets a custom socket type' do
- addr = Addrinfo.unix('socket', Socket::SOCK_DGRAM)
+ it 'sets a custom socket type' do
+ addr = Addrinfo.unix('socket', Socket::SOCK_DGRAM)
- addr.socktype.should == Socket::SOCK_DGRAM
- end
+ addr.socktype.should == Socket::SOCK_DGRAM
+ end
- it 'sets the socket protocol to 0' do
- Addrinfo.unix('socket').protocol.should == 0
- end
+ it 'sets the socket protocol to 0' do
+ Addrinfo.unix('socket').protocol.should == 0
end
end
@@ -42,7 +40,7 @@ describe "Addrinfo#unix?" do
end
it "returns false" do
- @addrinfo.unix?.should be_false
+ @addrinfo.unix?.should == false
end
end
@@ -53,7 +51,7 @@ describe "Addrinfo#unix?" do
end
it "returns false" do
- @addrinfo.unix?.should be_false
+ @addrinfo.unix?.should == false
end
end
@@ -64,7 +62,7 @@ describe "Addrinfo#unix?" do
end
it "returns true" do
- @addrinfo.unix?.should be_true
+ @addrinfo.unix?.should == true
end
end
end
diff --git a/spec/ruby/library/socket/ancillarydata/cmsg_is_spec.rb b/spec/ruby/library/socket/ancillarydata/cmsg_is_spec.rb
index c54ee29825..c77f3bdbae 100644
--- a/spec/ruby/library/socket/ancillarydata/cmsg_is_spec.rb
+++ b/spec/ruby/library/socket/ancillarydata/cmsg_is_spec.rb
@@ -26,7 +26,7 @@ with_feature :ancillary_data do
end
it 'raises SocketError when comparing with :IPV6 and :RIGHTS' do
- -> { @data.cmsg_is?(:IPV6, :RIGHTS) }.should raise_error(SocketError)
+ -> { @data.cmsg_is?(:IPV6, :RIGHTS) }.should.raise(SocketError)
end
end
end
diff --git a/spec/ruby/library/socket/ancillarydata/initialize_spec.rb b/spec/ruby/library/socket/ancillarydata/initialize_spec.rb
index eca45599d7..60f5ac7a90 100644
--- a/spec/ruby/library/socket/ancillarydata/initialize_spec.rb
+++ b/spec/ruby/library/socket/ancillarydata/initialize_spec.rb
@@ -115,25 +115,25 @@ with_feature :ancillary_data do
it 'raises TypeError when using a numeric string as the type argument' do
-> {
Socket::AncillaryData.new(:INET, :IGMP, Socket::SCM_RIGHTS.to_s, '')
- }.should raise_error(TypeError)
+ }.should.raise(TypeError)
end
it 'raises SocketError when using :RECVTTL as the type argument' do
-> {
Socket::AncillaryData.new(:INET, :SOCKET, :RECVTTL, '')
- }.should raise_error(SocketError)
+ }.should.raise(SocketError)
end
it 'raises SocketError when using :MOO as the type argument' do
-> {
Socket::AncillaryData.new(:INET, :SOCKET, :MOO, '')
- }.should raise_error(SocketError)
+ }.should.raise(SocketError)
end
it 'raises SocketError when using :IP_RECVTTL as the type argument' do
-> {
Socket::AncillaryData.new(:INET, :SOCKET, :IP_RECVTTL, '')
- }.should raise_error(SocketError)
+ }.should.raise(SocketError)
end
end
@@ -157,13 +157,13 @@ with_feature :ancillary_data do
it 'raises SocketError when using :RIGHTS as the type argument' do
-> {
Socket::AncillaryData.new(:INET, :IP, :RIGHTS, '')
- }.should raise_error(SocketError)
+ }.should.raise(SocketError)
end
it 'raises SocketError when using :MOO as the type argument' do
-> {
Socket::AncillaryData.new(:INET, :IP, :MOO, '')
- }.should raise_error(SocketError)
+ }.should.raise(SocketError)
end
end
@@ -181,13 +181,13 @@ with_feature :ancillary_data do
it 'raises SocketError when using :RIGHTS as the type argument' do
-> {
Socket::AncillaryData.new(:INET, :IPV6, :RIGHTS, '')
- }.should raise_error(SocketError)
+ }.should.raise(SocketError)
end
it 'raises SocketError when using :MOO as the type argument' do
-> {
Socket::AncillaryData.new(:INET, :IPV6, :MOO, '')
- }.should raise_error(SocketError)
+ }.should.raise(SocketError)
end
end
@@ -207,13 +207,13 @@ with_feature :ancillary_data do
it 'raises SocketError when using :RIGHTS as the type argument' do
-> {
Socket::AncillaryData.new(:INET, :TCP, :RIGHTS, '')
- }.should raise_error(SocketError)
+ }.should.raise(SocketError)
end
it 'raises SocketError when using :MOO as the type argument' do
-> {
Socket::AncillaryData.new(:INET, :TCP, :MOO, '')
- }.should raise_error(SocketError)
+ }.should.raise(SocketError)
end
end
@@ -227,13 +227,13 @@ with_feature :ancillary_data do
it 'raises SocketError when using :RIGHTS as the type argument' do
-> {
Socket::AncillaryData.new(:INET, :UDP, :RIGHTS, '')
- }.should raise_error(SocketError)
+ }.should.raise(SocketError)
end
it 'raises SocketError when using :MOO as the type argument' do
-> {
Socket::AncillaryData.new(:INET, :UDP, :MOO, '')
- }.should raise_error(SocketError)
+ }.should.raise(SocketError)
end
end
@@ -245,7 +245,7 @@ with_feature :ancillary_data do
it 'raises SocketError when using :CORK sa the type argument' do
-> {
Socket::AncillaryData.new(:UNIX, :SOCKET, :CORK, '')
- }.should raise_error(SocketError)
+ }.should.raise(SocketError)
end
end
@@ -253,7 +253,7 @@ with_feature :ancillary_data do
it 'raises SocketError' do
-> {
Socket::AncillaryData.new(:UNIX, :IP, :RECVTTL, '')
- }.should raise_error(SocketError)
+ }.should.raise(SocketError)
end
end
@@ -261,7 +261,7 @@ with_feature :ancillary_data do
it 'raises SocketError' do
-> {
Socket::AncillaryData.new(:UNIX, :IPV6, :NEXTHOP, '')
- }.should raise_error(SocketError)
+ }.should.raise(SocketError)
end
end
@@ -269,7 +269,7 @@ with_feature :ancillary_data do
it 'raises SocketError' do
-> {
Socket::AncillaryData.new(:UNIX, :TCP, :CORK, '')
- }.should raise_error(SocketError)
+ }.should.raise(SocketError)
end
end
@@ -277,7 +277,7 @@ with_feature :ancillary_data do
it 'raises SocketError' do
-> {
Socket::AncillaryData.new(:UNIX, :UDP, :CORK, '')
- }.should raise_error(SocketError)
+ }.should.raise(SocketError)
end
end
end
diff --git a/spec/ruby/library/socket/ancillarydata/int_spec.rb b/spec/ruby/library/socket/ancillarydata/int_spec.rb
index fe41a30a1a..10c5dea436 100644
--- a/spec/ruby/library/socket/ancillarydata/int_spec.rb
+++ b/spec/ruby/library/socket/ancillarydata/int_spec.rb
@@ -7,7 +7,7 @@ with_feature :ancillary_data do
end
it 'returns a Socket::AncillaryData' do
- @data.should be_an_instance_of(Socket::AncillaryData)
+ @data.should.instance_of?(Socket::AncillaryData)
end
it 'sets the family to AF_INET' do
@@ -37,7 +37,7 @@ with_feature :ancillary_data do
it 'raises when the data is not an Integer' do
data = Socket::AncillaryData.new(:UNIX, :SOCKET, :RIGHTS, 'ugh')
- -> { data.int }.should raise_error(TypeError)
+ -> { data.int }.should.raise(TypeError)
end
end
end
diff --git a/spec/ruby/library/socket/ancillarydata/ip_pktinfo_spec.rb b/spec/ruby/library/socket/ancillarydata/ip_pktinfo_spec.rb
index 84910a038a..065bcf1f39 100644
--- a/spec/ruby/library/socket/ancillarydata/ip_pktinfo_spec.rb
+++ b/spec/ruby/library/socket/ancillarydata/ip_pktinfo_spec.rb
@@ -8,7 +8,7 @@ with_feature :ancillary_data, :pktinfo do
end
it 'returns a Socket::AncillaryData' do
- @data.should be_an_instance_of(Socket::AncillaryData)
+ @data.should.instance_of?(Socket::AncillaryData)
end
it 'sets the family to AF_INET' do
@@ -32,7 +32,7 @@ with_feature :ancillary_data, :pktinfo do
end
it 'returns a Socket::AncillaryData' do
- @data.should be_an_instance_of(Socket::AncillaryData)
+ @data.should.instance_of?(Socket::AncillaryData)
end
it 'sets the family to AF_INET' do
@@ -58,7 +58,7 @@ with_feature :ancillary_data, :pktinfo do
end
it 'returns an Array' do
- @data.ip_pktinfo.should be_an_instance_of(Array)
+ @data.ip_pktinfo.should.instance_of?(Array)
end
describe 'the returned Array' do
@@ -67,15 +67,15 @@ with_feature :ancillary_data, :pktinfo do
end
it 'stores an Addrinfo at index 0' do
- @info[0].should be_an_instance_of(Addrinfo)
+ @info[0].should.instance_of?(Addrinfo)
end
it 'stores the ifindex at index 1' do
- @info[1].should be_kind_of(Integer)
+ @info[1].should.is_a?(Integer)
end
it 'stores an Addrinfo at index 2' do
- @info[2].should be_an_instance_of(Addrinfo)
+ @info[2].should.instance_of?(Addrinfo)
end
end
@@ -89,7 +89,7 @@ with_feature :ancillary_data, :pktinfo do
end
it 'is not the same object as the input Addrinfo' do
- @addr.should_not equal @source
+ @addr.should_not.equal? @source
end
end
@@ -109,7 +109,7 @@ with_feature :ancillary_data, :pktinfo do
end
it 'is not the same object as the input Addrinfo' do
- @addr.should_not equal @dest
+ @addr.should_not.equal? @dest
end
end
end
diff --git a/spec/ruby/library/socket/ancillarydata/ipv6_pktinfo_addr_spec.rb b/spec/ruby/library/socket/ancillarydata/ipv6_pktinfo_addr_spec.rb
index f70fe27d6a..7c630218d1 100644
--- a/spec/ruby/library/socket/ancillarydata/ipv6_pktinfo_addr_spec.rb
+++ b/spec/ruby/library/socket/ancillarydata/ipv6_pktinfo_addr_spec.rb
@@ -5,7 +5,7 @@ with_feature :ancillary_data, :ipv6_pktinfo do
it 'returns an Addrinfo' do
data = Socket::AncillaryData.ipv6_pktinfo(Addrinfo.ip('::1'), 4)
- data.ipv6_pktinfo_addr.should be_an_instance_of(Addrinfo)
+ data.ipv6_pktinfo_addr.should.instance_of?(Addrinfo)
end
end
end
diff --git a/spec/ruby/library/socket/ancillarydata/ipv6_pktinfo_spec.rb b/spec/ruby/library/socket/ancillarydata/ipv6_pktinfo_spec.rb
index 0fffc720dc..b5b779c36e 100644
--- a/spec/ruby/library/socket/ancillarydata/ipv6_pktinfo_spec.rb
+++ b/spec/ruby/library/socket/ancillarydata/ipv6_pktinfo_spec.rb
@@ -7,7 +7,7 @@ with_feature :ancillary_data, :ipv6_pktinfo do
end
it 'returns a Socket::AncillaryData' do
- @data.should be_an_instance_of(Socket::AncillaryData)
+ @data.should.instance_of?(Socket::AncillaryData)
end
it 'sets the family to AF_INET' do
@@ -31,7 +31,7 @@ with_feature :ancillary_data, :ipv6_pktinfo do
end
it 'returns an Array' do
- @data.ipv6_pktinfo.should be_an_instance_of(Array)
+ @data.ipv6_pktinfo.should.instance_of?(Array)
end
describe 'the returned Array' do
@@ -40,11 +40,11 @@ with_feature :ancillary_data, :ipv6_pktinfo do
end
it 'stores an Addrinfo at index 0' do
- @info[0].should be_an_instance_of(Addrinfo)
+ @info[0].should.instance_of?(Addrinfo)
end
it 'stores the ifindex at index 1' do
- @info[1].should be_kind_of(Integer)
+ @info[1].should.is_a?(Integer)
end
end
@@ -58,7 +58,7 @@ with_feature :ancillary_data, :ipv6_pktinfo do
end
it 'is not the same object as the input Addrinfo' do
- @addr.should_not equal @source
+ @addr.should_not.equal? @source
end
end
diff --git a/spec/ruby/library/socket/ancillarydata/unix_rights_spec.rb b/spec/ruby/library/socket/ancillarydata/unix_rights_spec.rb
index 95052fd91c..6dd144ba5a 100644
--- a/spec/ruby/library/socket/ancillarydata/unix_rights_spec.rb
+++ b/spec/ruby/library/socket/ancillarydata/unix_rights_spec.rb
@@ -26,7 +26,7 @@ with_feature :ancillary_data do
describe 'using non IO objects' do
it 'raises TypeError' do
- -> { Socket::AncillaryData.unix_rights(10) }.should raise_error(TypeError)
+ -> { Socket::AncillaryData.unix_rights(10) }.should.raise(TypeError)
end
end
end
@@ -41,20 +41,20 @@ with_feature :ancillary_data do
it 'returns nil when the data is not a list of file descriptors' do
data = Socket::AncillaryData.new(:UNIX, :SOCKET, :RIGHTS, '')
- data.unix_rights.should be_nil
+ data.unix_rights.should == nil
end
it 'raises TypeError when the level is not SOL_SOCKET' do
data = Socket::AncillaryData.new(:INET, :IP, :RECVTTL, '')
- -> { data.unix_rights }.should raise_error(TypeError)
+ -> { data.unix_rights }.should.raise(TypeError)
end
platform_is_not :aix do
it 'raises TypeError when the type is not SCM_RIGHTS' do
data = Socket::AncillaryData.new(:INET, :SOCKET, :TIMESTAMP, '')
- -> { data.unix_rights }.should raise_error(TypeError)
+ -> { data.unix_rights }.should.raise(TypeError)
end
end
end
diff --git a/spec/ruby/library/socket/basicsocket/close_read_spec.rb b/spec/ruby/library/socket/basicsocket/close_read_spec.rb
index f317b34955..35bec203d7 100644
--- a/spec/ruby/library/socket/basicsocket/close_read_spec.rb
+++ b/spec/ruby/library/socket/basicsocket/close_read_spec.rb
@@ -12,32 +12,32 @@ describe "Socket::BasicSocket#close_read" do
it "closes the reading end of the socket" do
@server.close_read
- -> { @server.read }.should raise_error(IOError)
+ -> { @server.read }.should.raise(IOError)
end
it 'does not raise when called on a socket already closed for reading' do
@server.close_read
@server.close_read
- -> { @server.read }.should raise_error(IOError)
+ -> { @server.read }.should.raise(IOError)
end
it 'does not fully close the socket' do
@server.close_read
- @server.closed?.should be_false
+ @server.closed?.should == false
end
it "fully closes the socket if it was already closed for writing" do
@server.close_write
@server.close_read
- @server.closed?.should be_true
+ @server.closed?.should == true
end
it 'raises IOError when called on a fully closed socket' do
@server.close
- -> { @server.close_read }.should raise_error(IOError)
+ -> { @server.close_read }.should.raise(IOError)
end
it "returns nil" do
- @server.close_read.should be_nil
+ @server.close_read.should == nil
end
end
diff --git a/spec/ruby/library/socket/basicsocket/close_write_spec.rb b/spec/ruby/library/socket/basicsocket/close_write_spec.rb
index 232cfbb7c6..c1b6d9e9ef 100644
--- a/spec/ruby/library/socket/basicsocket/close_write_spec.rb
+++ b/spec/ruby/library/socket/basicsocket/close_write_spec.rb
@@ -12,18 +12,18 @@ describe "Socket::BasicSocket#close_write" do
it "closes the writing end of the socket" do
@server.close_write
- -> { @server.write("foo") }.should raise_error(IOError)
+ -> { @server.write("foo") }.should.raise(IOError)
end
it 'does not raise when called on a socket already closed for writing' do
@server.close_write
@server.close_write
- -> { @server.write("foo") }.should raise_error(IOError)
+ -> { @server.write("foo") }.should.raise(IOError)
end
it 'does not fully close the socket' do
@server.close_write
- @server.closed?.should be_false
+ @server.closed?.should == false
end
it "does not prevent reading" do
@@ -34,15 +34,15 @@ describe "Socket::BasicSocket#close_write" do
it "fully closes the socket if it was already closed for reading" do
@server.close_read
@server.close_write
- @server.closed?.should be_true
+ @server.closed?.should == true
end
it 'raises IOError when called on a fully closed socket' do
@server.close
- -> { @server.close_write }.should raise_error(IOError)
+ -> { @server.close_write }.should.raise(IOError)
end
it "returns nil" do
- @server.close_write.should be_nil
+ @server.close_write.should == nil
end
end
diff --git a/spec/ruby/library/socket/basicsocket/connect_address_spec.rb b/spec/ruby/library/socket/basicsocket/connect_address_spec.rb
index 1a1c9982d9..e330b6e1be 100644
--- a/spec/ruby/library/socket/basicsocket/connect_address_spec.rb
+++ b/spec/ruby/library/socket/basicsocket/connect_address_spec.rb
@@ -10,7 +10,7 @@ describe 'Socket#connect_address' do
it 'raises SocketError' do
@sock = Socket.new(:INET, :STREAM)
- -> { @sock.connect_address }.should raise_error(SocketError)
+ -> { @sock.connect_address }.should.raise(SocketError)
end
end
@@ -25,7 +25,7 @@ describe 'Socket#connect_address' do
end
it 'returns an Addrinfo' do
- @sock.connect_address.should be_an_instance_of(Addrinfo)
+ @sock.connect_address.should.instance_of?(Addrinfo)
end
it 'uses 127.0.0.1 as the IP address' do
@@ -65,7 +65,7 @@ describe 'Socket#connect_address' do
end
it 'returns an Addrinfo' do
- @sock.connect_address.should be_an_instance_of(Addrinfo)
+ @sock.connect_address.should.instance_of?(Addrinfo)
end
it 'uses ::1 as the IP address' do
@@ -94,61 +94,59 @@ describe 'Socket#connect_address' do
end
end
- with_feature :unix_socket do
- platform_is_not :aix do
- describe 'using an unbound UNIX socket' do
- before do
- @path = SocketSpecs.socket_path
- @server = UNIXServer.new(@path)
- @client = UNIXSocket.new(@path)
- end
-
- after do
- @client.close
- @server.close
- rm_r(@path)
- end
-
- it 'raises SocketError' do
- -> { @client.connect_address }.should raise_error(SocketError)
- end
- end
- end
-
- describe 'using a bound UNIX socket' do
+ platform_is_not :aix do
+ describe 'using an unbound UNIX socket' do
before do
@path = SocketSpecs.socket_path
- @sock = UNIXServer.new(@path)
+ @server = UNIXServer.new(@path)
+ @client = UNIXSocket.new(@path)
end
after do
- @sock.close
+ @client.close
+ @server.close
rm_r(@path)
end
- it 'returns an Addrinfo' do
- @sock.connect_address.should be_an_instance_of(Addrinfo)
+ it 'raises SocketError' do
+ -> { @client.connect_address }.should.raise(SocketError)
end
+ end
+ end
- it 'uses the correct socket path' do
- @sock.connect_address.unix_path.should == @path
- end
+ describe 'using a bound UNIX socket' do
+ before do
+ @path = SocketSpecs.socket_path
+ @sock = UNIXServer.new(@path)
+ end
- it 'uses AF_UNIX as the address family' do
- @sock.connect_address.afamily.should == Socket::AF_UNIX
- end
+ after do
+ @sock.close
+ rm_r(@path)
+ end
- it 'uses PF_UNIX as the protocol family' do
- @sock.connect_address.pfamily.should == Socket::PF_UNIX
- end
+ it 'returns an Addrinfo' do
+ @sock.connect_address.should.instance_of?(Addrinfo)
+ end
- it 'uses SOCK_STREAM as the socket type' do
- @sock.connect_address.socktype.should == Socket::SOCK_STREAM
- end
+ it 'uses the correct socket path' do
+ @sock.connect_address.unix_path.should == @path
+ end
- it 'uses 0 as the protocol' do
- @sock.connect_address.protocol.should == 0
- end
+ it 'uses AF_UNIX as the address family' do
+ @sock.connect_address.afamily.should == Socket::AF_UNIX
+ end
+
+ it 'uses PF_UNIX as the protocol family' do
+ @sock.connect_address.pfamily.should == Socket::PF_UNIX
+ end
+
+ it 'uses SOCK_STREAM as the socket type' do
+ @sock.connect_address.socktype.should == Socket::SOCK_STREAM
+ end
+
+ it 'uses 0 as the protocol' do
+ @sock.connect_address.protocol.should == 0
end
end
end
diff --git a/spec/ruby/library/socket/basicsocket/do_not_reverse_lookup_spec.rb b/spec/ruby/library/socket/basicsocket/do_not_reverse_lookup_spec.rb
index a8800a8493..36338bfd59 100644
--- a/spec/ruby/library/socket/basicsocket/do_not_reverse_lookup_spec.rb
+++ b/spec/ruby/library/socket/basicsocket/do_not_reverse_lookup_spec.rb
@@ -16,7 +16,7 @@ describe "BasicSocket.do_not_reverse_lookup" do
end
it "defaults to true" do
- BasicSocket.do_not_reverse_lookup.should be_true
+ BasicSocket.do_not_reverse_lookup.should == true
end
it "causes 'peeraddr' to avoid name lookups" do
diff --git a/spec/ruby/library/socket/basicsocket/for_fd_spec.rb b/spec/ruby/library/socket/basicsocket/for_fd_spec.rb
index 9c9e6a8b55..8d5b71cfa9 100644
--- a/spec/ruby/library/socket/basicsocket/for_fd_spec.rb
+++ b/spec/ruby/library/socket/basicsocket/for_fd_spec.rb
@@ -15,7 +15,7 @@ describe "BasicSocket.for_fd" do
it "return a Socket instance wrapped around the descriptor" do
@s2 = TCPServer.for_fd(@server.fileno)
@s2.autoclose = false
- @s2.should be_kind_of(TCPServer)
+ @s2.should.is_a?(TCPServer)
@s2.fileno.should == @server.fileno
end
@@ -24,7 +24,7 @@ describe "BasicSocket.for_fd" do
socket2 = Socket.for_fd(@socket1.fileno)
socket2.autoclose = false
- socket2.should be_an_instance_of(Socket)
+ socket2.should.instance_of?(Socket)
socket2.fileno.should == @socket1.fileno
end
@@ -33,6 +33,6 @@ describe "BasicSocket.for_fd" do
socket2 = Socket.for_fd(@socket1.fileno)
socket2.autoclose = false
- socket2.binmode?.should be_true
+ socket2.binmode?.should == true
end
end
diff --git a/spec/ruby/library/socket/basicsocket/getpeereid_spec.rb b/spec/ruby/library/socket/basicsocket/getpeereid_spec.rb
index 6179211d96..b9851bae15 100644
--- a/spec/ruby/library/socket/basicsocket/getpeereid_spec.rb
+++ b/spec/ruby/library/socket/basicsocket/getpeereid_spec.rb
@@ -2,7 +2,7 @@ require_relative '../spec_helper'
require_relative '../fixtures/classes'
describe 'BasicSocket#getpeereid' do
- with_feature :unix_socket do
+ platform_is_not :windows do
describe 'using a UNIXSocket' do
before do
@path = SocketSpecs.socket_path
@@ -30,7 +30,7 @@ describe 'BasicSocket#getpeereid' do
it 'raises NoMethodError' do
@sock = TCPServer.new('127.0.0.1', 0)
- -> { @sock.getpeereid }.should raise_error(NoMethodError)
+ -> { @sock.getpeereid }.should.raise(NoMethodError)
end
end
end
diff --git a/spec/ruby/library/socket/basicsocket/getpeername_spec.rb b/spec/ruby/library/socket/basicsocket/getpeername_spec.rb
index 0b93f02eef..7e2f6f2e7b 100644
--- a/spec/ruby/library/socket/basicsocket/getpeername_spec.rb
+++ b/spec/ruby/library/socket/basicsocket/getpeername_spec.rb
@@ -20,6 +20,6 @@ describe "Socket::BasicSocket#getpeername" do
end
it 'raises Errno::ENOTCONN for a disconnected socket' do
- -> { @server.getpeername }.should raise_error(Errno::ENOTCONN)
+ -> { @server.getpeername }.should.raise(Errno::ENOTCONN)
end
end
diff --git a/spec/ruby/library/socket/basicsocket/getsockname_spec.rb b/spec/ruby/library/socket/basicsocket/getsockname_spec.rb
index b33db088b6..a54626647e 100644
--- a/spec/ruby/library/socket/basicsocket/getsockname_spec.rb
+++ b/spec/ruby/library/socket/basicsocket/getsockname_spec.rb
@@ -3,7 +3,7 @@ require_relative '../fixtures/classes'
describe "Socket::BasicSocket#getsockname" do
after :each do
- @socket.closed?.should be_false
+ @socket.closed?.should == false
@socket.close
end
@@ -16,7 +16,7 @@ describe "Socket::BasicSocket#getsockname" do
it "works on sockets listening in ipaddr_any" do
@socket = TCPServer.new(0)
sockaddr = Socket.unpack_sockaddr_in(@socket.getsockname)
- ["::", "0.0.0.0", "::ffff:0.0.0.0"].include?(sockaddr[1]).should be_true
+ ["::", "0.0.0.0", "::ffff:0.0.0.0"].include?(sockaddr[1]).should == true
sockaddr[0].should == @socket.addr[1]
end
diff --git a/spec/ruby/library/socket/basicsocket/getsockopt_spec.rb b/spec/ruby/library/socket/basicsocket/getsockopt_spec.rb
index ce65d6c92b..744297ad02 100644
--- a/spec/ruby/library/socket/basicsocket/getsockopt_spec.rb
+++ b/spec/ruby/library/socket/basicsocket/getsockopt_spec.rb
@@ -7,7 +7,7 @@ describe "BasicSocket#getsockopt" do
end
after :each do
- @sock.closed?.should be_false
+ @sock.closed?.should == false
@sock.close
end
@@ -41,13 +41,13 @@ describe "BasicSocket#getsockopt" do
end
it "raises a SystemCallError with an invalid socket option" do
- -> { @sock.getsockopt Socket::SOL_SOCKET, -1 }.should raise_error(Errno::ENOPROTOOPT)
+ -> { @sock.getsockopt Socket::SOL_SOCKET, -1 }.should.raise(Errno::ENOPROTOOPT)
end
it 'returns a Socket::Option using a constant' do
opt = @sock.getsockopt(Socket::SOL_SOCKET, Socket::SO_TYPE)
- opt.should be_an_instance_of(Socket::Option)
+ opt.should.instance_of?(Socket::Option)
end
it 'returns a Socket::Option for a boolean option' do
@@ -59,7 +59,7 @@ describe "BasicSocket#getsockopt" do
it 'returns a Socket::Option for a numeric option' do
opt = @sock.getsockopt(Socket::IPPROTO_IP, Socket::IP_TTL)
- opt.int.should be_kind_of(Integer)
+ opt.int.should.is_a?(Integer)
end
it 'returns a Socket::Option for a struct option' do
@@ -69,7 +69,7 @@ describe "BasicSocket#getsockopt" do
end
it 'raises Errno::ENOPROTOOPT when requesting an invalid option' do
- -> { @sock.getsockopt(Socket::SOL_SOCKET, -1) }.should raise_error(Errno::ENOPROTOOPT)
+ -> { @sock.getsockopt(Socket::SOL_SOCKET, -1) }.should.raise(Errno::ENOPROTOOPT)
end
describe 'using Symbols as arguments' do
@@ -171,7 +171,7 @@ describe "BasicSocket#getsockopt" do
opt = @sock.getsockopt(Socket::IPPROTO_IP, Socket::IP_TTL).to_s
array = opt.unpack('i')
- array[0].should be_kind_of(Integer)
+ array[0].should.is_a?(Integer)
array[0].should > 0
end
diff --git a/spec/ruby/library/socket/basicsocket/recv_nonblock_spec.rb b/spec/ruby/library/socket/basicsocket/recv_nonblock_spec.rb
index f2a6682f12..8aca7d0332 100644
--- a/spec/ruby/library/socket/basicsocket/recv_nonblock_spec.rb
+++ b/spec/ruby/library/socket/basicsocket/recv_nonblock_spec.rb
@@ -16,7 +16,7 @@ describe "Socket::BasicSocket#recv_nonblock" do
platform_is_not :windows do
describe 'using an unbound socket' do
it 'raises an exception extending IO::WaitReadable' do
- -> { @s1.recv_nonblock(1) }.should raise_error(IO::WaitReadable)
+ -> { @s1.recv_nonblock(1) }.should.raise(IO::WaitReadable)
end
end
end
@@ -25,12 +25,12 @@ describe "Socket::BasicSocket#recv_nonblock" do
@s1.bind(Socket.pack_sockaddr_in(0, ip_address))
-> {
@s1.recv_nonblock(5)
- }.should raise_error(IO::WaitReadable) { |e|
+ }.should.raise(IO::WaitReadable) { |e|
platform_is_not :windows do
- e.should be_kind_of(Errno::EAGAIN)
+ e.should.is_a?(Errno::EAGAIN)
end
platform_is :windows do
- e.should be_kind_of(Errno::EWOULDBLOCK)
+ e.should.is_a?(Errno::EWOULDBLOCK)
end
}
end
@@ -74,7 +74,7 @@ describe "Socket::BasicSocket#recv_nonblock" do
@s1.recv_nonblock(1).should == "a"
-> {
@s1.recv_nonblock(5)
- }.should raise_error(IO::WaitReadable)
+ }.should.raise(IO::WaitReadable)
end
end
@@ -89,10 +89,10 @@ describe "Socket::BasicSocket#recv_nonblock" do
end
it "raises Errno::ENOTCONN" do
- -> { @server.recv_nonblock(1) }.should raise_error { |e|
+ -> { @server.recv_nonblock(1) }.should.raise { |e|
[Errno::ENOTCONN, Errno::EINVAL].should.include?(e.class)
}
- -> { @server.recv_nonblock(1, exception: false) }.should raise_error { |e|
+ -> { @server.recv_nonblock(1, exception: false) }.should.raise { |e|
[Errno::ENOTCONN, Errno::EINVAL].should.include?(e.class)
}
end
@@ -112,60 +112,30 @@ describe "Socket::BasicSocket#recv_nonblock" do
@server.close unless @server.closed?
end
- ruby_version_is ""..."3.3" do
- it "returns an empty String on a closed stream socket" do
- ready = false
-
- t = Thread.new do
- client = @server.accept
-
- Thread.pass while !ready
- begin
- client.recv_nonblock(10)
- rescue IO::EAGAINWaitReadable
- retry
- end
- ensure
- client.close if client
- end
-
- Thread.pass while t.status and t.status != "sleep"
- t.status.should_not be_nil
+ it "returns nil on a closed stream socket" do
+ ready = false
- socket = TCPSocket.new('127.0.0.1', @port)
- socket.close
- ready = true
+ t = Thread.new do
+ client = @server.accept
- t.value.should == ""
- end
- end
-
- ruby_version_is "3.3" do
- it "returns nil on a closed stream socket" do
- ready = false
-
- t = Thread.new do
- client = @server.accept
-
- Thread.pass while !ready
- begin
- client.recv_nonblock(10)
- rescue IO::EAGAINWaitReadable
- retry
- end
- ensure
- client.close if client
+ Thread.pass while !ready
+ begin
+ client.recv_nonblock(10)
+ rescue IO::EAGAINWaitReadable
+ retry
end
+ ensure
+ client.close if client
+ end
- Thread.pass while t.status and t.status != "sleep"
- t.status.should_not be_nil
+ Thread.pass while t.status and t.status != "sleep"
+ t.status.should_not == nil
- socket = TCPSocket.new('127.0.0.1', @port)
- socket.close
- ready = true
+ socket = TCPSocket.new('127.0.0.1', @port)
+ socket.close
+ ready = true
- t.value.should be_nil
- end
+ t.value.should == nil
end
end
end
diff --git a/spec/ruby/library/socket/basicsocket/recv_spec.rb b/spec/ruby/library/socket/basicsocket/recv_spec.rb
index a51920f52a..5c393218bc 100644
--- a/spec/ruby/library/socket/basicsocket/recv_spec.rb
+++ b/spec/ruby/library/socket/basicsocket/recv_spec.rb
@@ -22,7 +22,7 @@ describe "BasicSocket#recv" do
client.close
end
Thread.pass while t.status and t.status != "sleep"
- t.status.should_not be_nil
+ t.status.should_not == nil
socket = TCPSocket.new('127.0.0.1', @port)
socket.send('hello', 0)
@@ -44,7 +44,7 @@ describe "BasicSocket#recv" do
client.close
end
Thread.pass while t.status and t.status != "sleep"
- t.status.should_not be_nil
+ t.status.should_not == nil
socket = TCPSocket.new('127.0.0.1', @port)
socket.send('helloU', Socket::MSG_OOB)
@@ -64,7 +64,7 @@ describe "BasicSocket#recv" do
client.close
end
Thread.pass while t.status and t.status != "sleep"
- t.status.should_not be_nil
+ t.status.should_not == nil
socket = TCPSocket.new('127.0.0.1', @port)
socket.write("firstline\377secondline\377")
@@ -184,42 +184,21 @@ describe "BasicSocket#recv" do
@server.close unless @server.closed?
end
- ruby_version_is ""..."3.3" do
- it "returns an empty String on a closed stream socket" do
- t = Thread.new do
- client = @server.accept
- client.recv(10)
- ensure
- client.close if client
- 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 == ""
+ it "returns nil on a closed stream socket" do
+ t = Thread.new do
+ client = @server.accept
+ client.recv(10)
+ ensure
+ client.close if client
end
- end
-
- ruby_version_is "3.3" do
- it "returns nil on a closed stream socket" do
- t = Thread.new do
- client = @server.accept
- client.recv(10)
- ensure
- client.close if client
- end
- Thread.pass while t.status and t.status != "sleep"
- t.status.should_not be_nil
+ Thread.pass while t.status and t.status != "sleep"
+ t.status.should_not == nil
- socket = TCPSocket.new('127.0.0.1', @port)
- socket.close
+ socket = TCPSocket.new('127.0.0.1', @port)
+ socket.close
- t.value.should be_nil
- end
+ t.value.should == nil
end
end
diff --git a/spec/ruby/library/socket/basicsocket/recvmsg_nonblock_spec.rb b/spec/ruby/library/socket/basicsocket/recvmsg_nonblock_spec.rb
index b5fdd7c93b..9d77f5df6b 100644
--- a/spec/ruby/library/socket/basicsocket/recvmsg_nonblock_spec.rb
+++ b/spec/ruby/library/socket/basicsocket/recvmsg_nonblock_spec.rb
@@ -17,7 +17,7 @@ describe 'BasicSocket#recvmsg_nonblock' do
platform_is_not :windows do
describe 'using an unbound socket' do
it 'raises an exception extending IO::WaitReadable' do
- -> { @server.recvmsg_nonblock }.should raise_error(IO::WaitReadable)
+ -> { @server.recvmsg_nonblock }.should.raise(IO::WaitReadable)
end
end
end
@@ -29,7 +29,7 @@ describe 'BasicSocket#recvmsg_nonblock' do
describe 'without any data available' do
it 'raises an exception extending IO::WaitReadable' do
- -> { @server.recvmsg_nonblock }.should raise_error(IO::WaitReadable)
+ -> { @server.recvmsg_nonblock }.should.raise(IO::WaitReadable)
end
it 'returns :wait_readable with exception: false' do
@@ -47,7 +47,7 @@ describe 'BasicSocket#recvmsg_nonblock' do
end
it 'returns an Array containing the data, an Addrinfo and the flags' do
- @server.recvmsg_nonblock.should be_an_instance_of(Array)
+ @server.recvmsg_nonblock.should.instance_of?(Array)
end
describe 'without a maximum message length' do
@@ -74,12 +74,12 @@ describe 'BasicSocket#recvmsg_nonblock' do
end
it 'stores an Addrinfo at index 1' do
- @array[1].should be_an_instance_of(Addrinfo)
+ @array[1].should.instance_of?(Addrinfo)
end
platform_is_not :windows do
it 'stores the flags at index 2' do
- @array[2].should be_kind_of(Integer)
+ @array[2].should.is_a?(Integer)
end
end
@@ -124,8 +124,8 @@ describe 'BasicSocket#recvmsg_nonblock' do
end
it "raises Errno::ENOTCONN" do
- -> { @server.recvmsg_nonblock }.should raise_error(Errno::ENOTCONN)
- -> { @server.recvmsg_nonblock(exception: false) }.should raise_error(Errno::ENOTCONN)
+ -> { @server.recvmsg_nonblock }.should.raise(Errno::ENOTCONN)
+ -> { @server.recvmsg_nonblock(exception: false) }.should.raise(Errno::ENOTCONN)
end
end
@@ -154,7 +154,7 @@ describe 'BasicSocket#recvmsg_nonblock' do
ensure
socket.close
end
- }.should raise_error(IO::WaitReadable)
+ }.should.raise(IO::WaitReadable)
end
end
@@ -171,7 +171,7 @@ describe 'BasicSocket#recvmsg_nonblock' do
end
it 'returns an Array containing the data, an Addrinfo and the flags' do
- @socket.recvmsg_nonblock.should be_an_instance_of(Array)
+ @socket.recvmsg_nonblock.should.instance_of?(Array)
end
describe 'the returned Array' do
@@ -184,11 +184,11 @@ describe 'BasicSocket#recvmsg_nonblock' do
end
it 'stores an Addrinfo at index 1' do
- @array[1].should be_an_instance_of(Addrinfo)
+ @array[1].should.instance_of?(Addrinfo)
end
it 'stores the flags at index 2' do
- @array[2].should be_kind_of(Integer)
+ @array[2].should.is_a?(Integer)
end
describe 'the returned Addrinfo' do
@@ -197,7 +197,7 @@ describe 'BasicSocket#recvmsg_nonblock' do
end
it 'raises when receiving the ip_address message' do
- -> { @addr.ip_address }.should raise_error(SocketError)
+ -> { @addr.ip_address }.should.raise(SocketError)
end
it 'uses the correct address family' do
@@ -213,7 +213,7 @@ describe 'BasicSocket#recvmsg_nonblock' do
end
it 'raises when receiving the ip_port message' do
- -> { @addr.ip_port }.should raise_error(SocketError)
+ -> { @addr.ip_port }.should.raise(SocketError)
end
end
end
@@ -235,64 +235,31 @@ describe 'BasicSocket#recvmsg_nonblock' do
@server.close unless @server.closed?
end
- ruby_version_is ""..."3.3" do
- platform_is_not :windows do # #recvmsg_nonblock() raises 'Errno::EINVAL: Invalid argument - recvmsg(2)'
- it "returns an empty String as received data on a closed stream socket" do
- ready = false
+ platform_is_not :windows do
+ it "returns nil on a closed stream socket" do
+ ready = false
- t = Thread.new do
- client = @server.accept
+ t = Thread.new do
+ client = @server.accept
- Thread.pass while !ready
- begin
- client.recvmsg_nonblock(10)
- rescue IO::EAGAINWaitReadable
- retry
- end
- ensure
- client.close if client
+ Thread.pass while !ready
+ begin
+ client.recvmsg_nonblock(10)
+ rescue IO::EAGAINWaitReadable
+ retry
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
- ready = true
-
- t.value.should.is_a? Array
- t.value[0].should == ""
+ ensure
+ client.close if client
end
- end
- end
- ruby_version_is "3.3" do
- platform_is_not :windows do
- it "returns nil on a closed stream socket" do
- ready = false
+ Thread.pass while t.status and t.status != "sleep"
+ t.status.should_not == nil
- t = Thread.new do
- client = @server.accept
+ socket = TCPSocket.new('127.0.0.1', @port)
+ socket.close
+ ready = true
- Thread.pass while !ready
- begin
- client.recvmsg_nonblock(10)
- rescue IO::EAGAINWaitReadable
- retry
- end
- ensure
- client.close if client
- 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
- ready = true
-
- t.value.should be_nil
- end
+ t.value.should == nil
end
end
end
diff --git a/spec/ruby/library/socket/basicsocket/recvmsg_spec.rb b/spec/ruby/library/socket/basicsocket/recvmsg_spec.rb
index 04ba1d74c7..eabfb9dd18 100644
--- a/spec/ruby/library/socket/basicsocket/recvmsg_spec.rb
+++ b/spec/ruby/library/socket/basicsocket/recvmsg_spec.rb
@@ -41,7 +41,7 @@ describe 'BasicSocket#recvmsg' do
end
it 'returns an Array containing the data, an Addrinfo and the flags' do
- @server.recvmsg.should be_an_instance_of(Array)
+ @server.recvmsg.should.instance_of?(Array)
end
describe 'without a maximum message length' do
@@ -66,12 +66,12 @@ describe 'BasicSocket#recvmsg' do
end
it 'stores an Addrinfo at index 1' do
- @array[1].should be_an_instance_of(Addrinfo)
+ @array[1].should.instance_of?(Addrinfo)
end
platform_is_not :windows do
it 'stores the flags at index 2' do
- @array[2].should be_kind_of(Integer)
+ @array[2].should.is_a?(Integer)
end
end
@@ -144,7 +144,7 @@ describe 'BasicSocket#recvmsg' do
end
it 'returns an Array containing the data, an Addrinfo and the flags' do
- @socket.recvmsg.should be_an_instance_of(Array)
+ @socket.recvmsg.should.instance_of?(Array)
end
describe 'the returned Array' do
@@ -157,11 +157,11 @@ describe 'BasicSocket#recvmsg' do
end
it 'stores an Addrinfo at index 1' do
- @array[1].should be_an_instance_of(Addrinfo)
+ @array[1].should.instance_of?(Addrinfo)
end
it 'stores the flags at index 2' do
- @array[2].should be_kind_of(Integer)
+ @array[2].should.is_a?(Integer)
end
describe 'the returned Addrinfo' do
@@ -170,7 +170,7 @@ describe 'BasicSocket#recvmsg' do
end
it 'raises when receiving the ip_address message' do
- -> { @addr.ip_address }.should raise_error(SocketError)
+ -> { @addr.ip_address }.should.raise(SocketError)
end
it 'uses the correct address family' do
@@ -186,7 +186,7 @@ describe 'BasicSocket#recvmsg' do
end
it 'raises when receiving the ip_port message' do
- -> { @addr.ip_port }.should raise_error(SocketError)
+ -> { @addr.ip_port }.should.raise(SocketError)
end
end
end
@@ -208,46 +208,22 @@ describe 'BasicSocket#recvmsg' do
@server.close unless @server.closed?
end
- ruby_version_is ""..."3.3" do
- platform_is_not :windows do
- it "returns an empty String as received data on a closed stream socket" do
- t = Thread.new do
- client = @server.accept
- client.recvmsg(10)
- ensure
- client.close if client
- 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.is_a? Array
- t.value[0].should == ""
+ platform_is_not :windows do
+ it "returns nil on a closed stream socket" do
+ t = Thread.new do
+ client = @server.accept
+ client.recvmsg(10)
+ ensure
+ client.close if client
end
- end
- end
-
- ruby_version_is "3.3" do
- platform_is_not :windows do
- it "returns nil on a closed stream socket" do
- t = Thread.new do
- client = @server.accept
- client.recvmsg(10)
- ensure
- client.close if client
- end
- Thread.pass while t.status and t.status != "sleep"
- t.status.should_not be_nil
+ Thread.pass while t.status and t.status != "sleep"
+ t.status.should_not == nil
- socket = TCPSocket.new('127.0.0.1', @port)
- socket.close
+ socket = TCPSocket.new('127.0.0.1', @port)
+ socket.close
- t.value.should be_nil
- end
+ t.value.should == nil
end
end
end
diff --git a/spec/ruby/library/socket/basicsocket/send_spec.rb b/spec/ruby/library/socket/basicsocket/send_spec.rb
index 25ba3f5655..a2c2ee8de9 100644
--- a/spec/ruby/library/socket/basicsocket/send_spec.rb
+++ b/spec/ruby/library/socket/basicsocket/send_spec.rb
@@ -9,8 +9,8 @@ describe "BasicSocket#send" do
end
after :each do
- @server.closed?.should be_false
- @socket.closed?.should be_false
+ @server.closed?.should == false
+ @socket.closed?.should == false
@server.close
@socket.close
@@ -28,7 +28,7 @@ describe "BasicSocket#send" do
client.close
end
Thread.pass while t.status and t.status != "sleep"
- t.status.should_not be_nil
+ t.status.should_not == nil
@socket.send('hello', 0).should == 5
@socket.shutdown(1) # indicate, that we are done sending
@@ -50,7 +50,7 @@ describe "BasicSocket#send" do
client.close
end
Thread.pass while t.status and t.status != "sleep"
- t.status.should_not be_nil
+ t.status.should_not == nil
@socket.send('helloU', Socket::MSG_PEEK | Socket::MSG_OOB).should == 6
@socket.shutdown # indicate, that we are done sending
@@ -73,7 +73,7 @@ describe "BasicSocket#send" do
client.close
end
Thread.pass while t.status and t.status != "sleep"
- t.status.should_not be_nil
+ t.status.should_not == nil
sockaddr = Socket.pack_sockaddr_in(@port, "127.0.0.1")
@socket.send('hello', 0, sockaddr).should == 5
@@ -109,7 +109,7 @@ describe 'BasicSocket#send' do
describe 'without a destination address' do
it "raises #{SocketSpecs.dest_addr_req_error}" do
- -> { @client.send('hello', 0) }.should raise_error(SocketSpecs.dest_addr_req_error)
+ -> { @client.send('hello', 0) }.should.raise(SocketSpecs.dest_addr_req_error)
end
end
@@ -121,7 +121,7 @@ describe 'BasicSocket#send' do
it 'does not persist the connection after writing to the socket' do
@client.send('hello', 0, @server.getsockname)
- -> { @client.send('hello', 0) }.should raise_error(SocketSpecs.dest_addr_req_error)
+ -> { @client.send('hello', 0) }.should.raise(SocketSpecs.dest_addr_req_error)
end
end
diff --git a/spec/ruby/library/socket/basicsocket/sendmsg_nonblock_spec.rb b/spec/ruby/library/socket/basicsocket/sendmsg_nonblock_spec.rb
index 7acfc659bd..4cd6e8bdca 100644
--- a/spec/ruby/library/socket/basicsocket/sendmsg_nonblock_spec.rb
+++ b/spec/ruby/library/socket/basicsocket/sendmsg_nonblock_spec.rb
@@ -20,10 +20,10 @@ describe 'BasicSocket#sendmsg_nonblock' do
it "raises #{SocketSpecs.dest_addr_req_error}" do
-> {
@client.sendmsg_nonblock('hello')
- }.should raise_error(SocketSpecs.dest_addr_req_error)
+ }.should.raise(SocketSpecs.dest_addr_req_error)
-> {
@client.sendmsg_nonblock('hello', exception: false)
- }.should raise_error(SocketSpecs.dest_addr_req_error)
+ }.should.raise(SocketSpecs.dest_addr_req_error)
end
end
@@ -101,7 +101,7 @@ describe 'BasicSocket#sendmsg_nonblock' do
it 'raises IO::WaitWritable when the underlying buffer is full' do
-> {
10.times { @client.sendmsg_nonblock('hello' * 1_000_000) }
- }.should raise_error(IO::WaitWritable)
+ }.should.raise(IO::WaitWritable)
end
it 'returns :wait_writable when the underlying buffer is full with exception: false' do
diff --git a/spec/ruby/library/socket/basicsocket/sendmsg_spec.rb b/spec/ruby/library/socket/basicsocket/sendmsg_spec.rb
index 7ff336c0b7..dc999b32df 100644
--- a/spec/ruby/library/socket/basicsocket/sendmsg_spec.rb
+++ b/spec/ruby/library/socket/basicsocket/sendmsg_spec.rb
@@ -19,7 +19,7 @@ describe 'BasicSocket#sendmsg' do
platform_is_not :windows do
describe 'without a destination address' do
it "raises #{SocketSpecs.dest_addr_req_error}" do
- -> { @client.sendmsg('hello') }.should raise_error(SocketSpecs.dest_addr_req_error)
+ -> { @client.sendmsg('hello') }.should.raise(SocketSpecs.dest_addr_req_error)
end
end
end
diff --git a/spec/ruby/library/socket/basicsocket/setsockopt_spec.rb b/spec/ruby/library/socket/basicsocket/setsockopt_spec.rb
index 1e8d84e1c9..e306581aa3 100644
--- a/spec/ruby/library/socket/basicsocket/setsockopt_spec.rb
+++ b/spec/ruby/library/socket/basicsocket/setsockopt_spec.rb
@@ -40,7 +40,7 @@ describe "BasicSocket#setsockopt" do
it "raises EINVAL if passed wrong linger value" do
-> do
@sock.setsockopt(Socket::SOL_SOCKET, Socket::SO_LINGER, 0)
- end.should raise_error(Errno::EINVAL)
+ end.should.raise(Errno::EINVAL)
end
end
@@ -72,7 +72,7 @@ describe "BasicSocket#setsockopt" do
platform_is_not :windows do
-> {
@sock.setsockopt(Socket::SOL_SOCKET, Socket::SO_OOBINLINE, "")
- }.should raise_error(SystemCallError)
+ }.should.raise(SystemCallError)
end
@sock.setsockopt(Socket::SOL_SOCKET, Socket::SO_OOBINLINE, "blah").should == 0
@@ -82,7 +82,7 @@ describe "BasicSocket#setsockopt" do
platform_is_not :windows do
-> {
@sock.setsockopt(Socket::SOL_SOCKET, Socket::SO_OOBINLINE, "0")
- }.should raise_error(SystemCallError)
+ }.should.raise(SystemCallError)
end
@sock.setsockopt(Socket::SOL_SOCKET, Socket::SO_OOBINLINE, "\x00\x00\x00\x00").should == 0
@@ -92,13 +92,13 @@ describe "BasicSocket#setsockopt" do
platform_is_not :windows do
-> {
@sock.setsockopt(Socket::SOL_SOCKET, Socket::SO_OOBINLINE, "1")
- }.should raise_error(SystemCallError)
+ }.should.raise(SystemCallError)
end
platform_is_not :windows do
-> {
@sock.setsockopt(Socket::SOL_SOCKET, Socket::SO_OOBINLINE, "\x00\x00\x00")
- }.should raise_error(SystemCallError)
+ }.should.raise(SystemCallError)
end
@sock.setsockopt(Socket::SOL_SOCKET, Socket::SO_OOBINLINE, [1].pack('i')).should == 0
@@ -127,7 +127,7 @@ describe "BasicSocket#setsockopt" do
-> {
@sock.setsockopt(Socket::SOL_SOCKET, Socket::SO_SNDBUF, nil).should == 0
- }.should raise_error(TypeError)
+ }.should.raise(TypeError)
@sock.setsockopt(Socket::SOL_SOCKET, Socket::SO_SNDBUF, 1).should == 0
n = @sock.getsockopt(Socket::SOL_SOCKET, Socket::SO_SNDBUF).to_s
@@ -139,23 +139,23 @@ describe "BasicSocket#setsockopt" do
-> {
@sock.setsockopt(Socket::SOL_SOCKET, Socket::SO_SNDBUF, "")
- }.should raise_error(SystemCallError)
+ }.should.raise(SystemCallError)
-> {
@sock.setsockopt(Socket::SOL_SOCKET, Socket::SO_SNDBUF, "bla")
- }.should raise_error(SystemCallError)
+ }.should.raise(SystemCallError)
-> {
@sock.setsockopt(Socket::SOL_SOCKET, Socket::SO_SNDBUF, "0")
- }.should raise_error(SystemCallError)
+ }.should.raise(SystemCallError)
-> {
@sock.setsockopt(Socket::SOL_SOCKET, Socket::SO_SNDBUF, "1")
- }.should raise_error(SystemCallError)
+ }.should.raise(SystemCallError)
-> {
@sock.setsockopt(Socket::SOL_SOCKET, Socket::SO_SNDBUF, "\x00\x00\x00")
- }.should raise_error(SystemCallError)
+ }.should.raise(SystemCallError)
@sock.setsockopt(Socket::SOL_SOCKET, Socket::SO_SNDBUF, "\x00\x00\x01\x00").should == 0
n = @sock.getsockopt(Socket::SOL_SOCKET, Socket::SO_SNDBUF).to_s
@@ -207,7 +207,7 @@ describe "BasicSocket#setsockopt" do
onoff, seconds = @sock.getsockopt(Socket::SOL_SOCKET, Socket::SO_LINGER).linger
seconds.should == 10
# Both results can be produced depending on the OS and value of Socket::SO_LINGER
- [true, Socket::SO_LINGER].should include(onoff)
+ [true, Socket::SO_LINGER].should.include?(onoff)
end
end
end
@@ -224,7 +224,7 @@ describe 'BasicSocket#setsockopt' do
describe 'using separate arguments with Symbols' do
it 'raises TypeError when the first argument is nil' do
- -> { @socket.setsockopt(nil, :REUSEADDR, true) }.should raise_error(TypeError)
+ -> { @socket.setsockopt(nil, :REUSEADDR, true) }.should.raise(TypeError)
end
it 'sets a boolean option' do
@@ -251,7 +251,7 @@ describe 'BasicSocket#setsockopt' do
platform_is_not :windows do
it 'raises Errno::EINVAL when setting an invalid option value' do
- -> { @socket.setsockopt(:SOCKET, :OOBINLINE, 'bla') }.should raise_error(Errno::EINVAL)
+ -> { @socket.setsockopt(:SOCKET, :OOBINLINE, 'bla') }.should.raise(Errno::EINVAL)
end
end
end
@@ -305,32 +305,30 @@ describe 'BasicSocket#setsockopt' do
it 'raises ArgumentError when passing 2 arguments' do
option = Socket::Option.bool(:INET, :SOCKET, :REUSEADDR, true)
- -> { @socket.setsockopt(option, :REUSEADDR) }.should raise_error(ArgumentError)
+ -> { @socket.setsockopt(option, :REUSEADDR) }.should.raise(ArgumentError)
end
it 'raises TypeError when passing 3 arguments' do
option = Socket::Option.bool(:INET, :SOCKET, :REUSEADDR, true)
- -> { @socket.setsockopt(option, :REUSEADDR, true) }.should raise_error(TypeError)
+ -> { @socket.setsockopt(option, :REUSEADDR, true) }.should.raise(TypeError)
end
end
end
- with_feature :unix_socket do
- describe 'using a UNIX socket' do
- before do
- @path = SocketSpecs.socket_path
- @server = UNIXServer.new(@path)
- end
+ describe 'using a UNIX socket' do
+ before do
+ @path = SocketSpecs.socket_path
+ @server = UNIXServer.new(@path)
+ end
- after do
- @server.close
- rm_r @path
- end
+ after do
+ @server.close
+ rm_r @path
+ end
- it 'sets a boolean option' do
- @server.setsockopt(:SOCKET, :REUSEADDR, true)
- @server.getsockopt(:SOCKET, :REUSEADDR).bool.should == true
- end
+ it 'sets a boolean option' do
+ @server.setsockopt(:SOCKET, :REUSEADDR, true)
+ @server.getsockopt(:SOCKET, :REUSEADDR).bool.should == true
end
end
end
diff --git a/spec/ruby/library/socket/basicsocket/shutdown_spec.rb b/spec/ruby/library/socket/basicsocket/shutdown_spec.rb
index c78b32de38..c96c62abe1 100644
--- a/spec/ruby/library/socket/basicsocket/shutdown_spec.rb
+++ b/spec/ruby/library/socket/basicsocket/shutdown_spec.rb
@@ -23,25 +23,25 @@ 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).to_s.should.empty?
end
it 'shuts down a socket for writing' do
@client.shutdown(Socket::SHUT_WR)
- -> { @client.write('hello') }.should raise_error(Errno::EPIPE)
+ -> { @client.write('hello') }.should.raise(Errno::EPIPE)
end
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).to_s.should.empty?
- -> { @client.write('hello') }.should raise_error(Errno::EPIPE)
+ -> { @client.write('hello') }.should.raise(Errno::EPIPE)
end
it 'raises ArgumentError when using an invalid option' do
- -> { @server.shutdown(666) }.should raise_error(ArgumentError)
+ -> { @server.shutdown(666) }.should.raise(ArgumentError)
end
end
@@ -49,37 +49,37 @@ 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).to_s.should.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).to_s.should.empty?
end
it 'shuts down a socket for writing using :WR' do
@client.shutdown(:WR)
- -> { @client.write('hello') }.should raise_error(Errno::EPIPE)
+ -> { @client.write('hello') }.should.raise(Errno::EPIPE)
end
it 'shuts down a socket for writing using :SHUT_WR' do
@client.shutdown(:SHUT_WR)
- -> { @client.write('hello') }.should raise_error(Errno::EPIPE)
+ -> { @client.write('hello') }.should.raise(Errno::EPIPE)
end
it 'shuts down a socket for reading and writing' do
@client.shutdown(:RDWR)
- @client.recv(1).to_s.should be_empty
+ @client.recv(1).to_s.should.empty?
- -> { @client.write('hello') }.should raise_error(Errno::EPIPE)
+ -> { @client.write('hello') }.should.raise(Errno::EPIPE)
end
it 'raises ArgumentError when using an invalid option' do
- -> { @server.shutdown(:Nope) }.should raise_error(SocketError)
+ -> { @server.shutdown(:Nope) }.should.raise(SocketError)
end
end
@@ -87,29 +87,29 @@ 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).to_s.should.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).to_s.should.empty?
end
it 'shuts down a socket for writing using "WR"' do
@client.shutdown('WR')
- -> { @client.write('hello') }.should raise_error(Errno::EPIPE)
+ -> { @client.write('hello') }.should.raise(Errno::EPIPE)
end
it 'shuts down a socket for writing using "SHUT_WR"' do
@client.shutdown('SHUT_WR')
- -> { @client.write('hello') }.should raise_error(Errno::EPIPE)
+ -> { @client.write('hello') }.should.raise(Errno::EPIPE)
end
it 'raises ArgumentError when using an invalid option' do
- -> { @server.shutdown('Nope') }.should raise_error(SocketError)
+ -> { @server.shutdown('Nope') }.should.raise(SocketError)
end
end
@@ -123,7 +123,7 @@ platform_is_not :windows do # hangs
@client.shutdown(@dummy)
- @client.recv(1).to_s.should be_empty
+ @client.recv(1).to_s.should.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).to_s.should.empty?
end
it 'shuts down a socket for reading and writing' do
@@ -139,15 +139,15 @@ platform_is_not :windows do # hangs
@client.shutdown(@dummy)
- @client.recv(1).to_s.should be_empty
+ @client.recv(1).to_s.should.empty?
- -> { @client.write('hello') }.should raise_error(Errno::EPIPE)
+ -> { @client.write('hello') }.should.raise(Errno::EPIPE)
end
end
describe 'using an object that does not respond to #to_str' do
it 'raises TypeError' do
- -> { @server.shutdown(mock(:dummy)) }.should raise_error(TypeError)
+ -> { @server.shutdown(mock(:dummy)) }.should.raise(TypeError)
end
end
end
diff --git a/spec/ruby/library/socket/constants/constants_spec.rb b/spec/ruby/library/socket/constants/constants_spec.rb
index b9a9d42725..a936473bb6 100644
--- a/spec/ruby/library/socket/constants/constants_spec.rb
+++ b/spec/ruby/library/socket/constants/constants_spec.rb
@@ -5,47 +5,47 @@ describe "Socket::Constants" do
it "defines socket types" do
consts = ["SOCK_DGRAM", "SOCK_RAW", "SOCK_RDM", "SOCK_SEQPACKET", "SOCK_STREAM"]
consts.each do |c|
- Socket::Constants.should have_constant(c)
+ Socket::Constants.should.const_defined?(c, false)
end
end
it "defines protocol families" do
consts = ["PF_INET6", "PF_INET", "PF_UNIX", "PF_UNSPEC"]
consts.each do |c|
- Socket::Constants.should have_constant(c)
+ Socket::Constants.should.const_defined?(c, false)
end
end
platform_is_not :aix do
it "defines PF_IPX protocol" do
- Socket::Constants.should have_constant("PF_IPX")
+ Socket::Constants.should.const_defined?("PF_IPX", false)
end
end
it "defines address families" do
consts = ["AF_INET6", "AF_INET", "AF_UNIX", "AF_UNSPEC"]
consts.each do |c|
- Socket::Constants.should have_constant(c)
+ Socket::Constants.should.const_defined?(c, false)
end
end
platform_is_not :aix do
it "defines AF_IPX address" do
- Socket::Constants.should have_constant("AF_IPX")
+ Socket::Constants.should.const_defined?("AF_IPX", false)
end
end
it "defines send/receive options" do
consts = ["MSG_DONTROUTE", "MSG_OOB", "MSG_PEEK"]
consts.each do |c|
- Socket::Constants.should have_constant(c)
+ Socket::Constants.should.const_defined?(c, false)
end
end
it "defines socket level options" do
consts = ["SOL_SOCKET"]
consts.each do |c|
- Socket::Constants.should have_constant(c)
+ Socket::Constants.should.const_defined?(c, false)
end
end
@@ -53,7 +53,7 @@ describe "Socket::Constants" do
consts = ["SO_BROADCAST", "SO_DEBUG", "SO_DONTROUTE", "SO_ERROR", "SO_KEEPALIVE", "SO_LINGER",
"SO_OOBINLINE", "SO_RCVBUF", "SO_REUSEADDR", "SO_SNDBUF", "SO_TYPE"]
consts.each do |c|
- Socket::Constants.should have_constant(c)
+ Socket::Constants.should.const_defined?(c, false)
end
end
@@ -64,7 +64,7 @@ describe "Socket::Constants" do
consts += ["IP_DEFAULT_MULTICAST_LOOP", "IP_DEFAULT_MULTICAST_TTL"]
end
consts.each do |c|
- Socket::Constants.should have_constant(c)
+ Socket::Constants.should.const_defined?(c, false)
end
end
@@ -72,7 +72,7 @@ describe "Socket::Constants" do
it "defines multicast options" do
consts = ["IP_MAX_MEMBERSHIPS"]
consts.each do |c|
- Socket::Constants.should have_constant(c)
+ Socket::Constants.should.const_defined?(c, false)
end
end
end
@@ -83,13 +83,13 @@ describe "Socket::Constants" do
consts << "TCP_MAXSEG"
end
consts.each do |c|
- Socket::Constants.should have_constant(c)
+ Socket::Constants.should.const_defined?(c, false)
end
end
platform_is_not :windows do
it 'defines SCM options' do
- Socket::Constants.should have_constant('SCM_RIGHTS')
+ Socket::Constants.should.const_defined?('SCM_RIGHTS', false)
end
it 'defines error options' do
@@ -101,7 +101,7 @@ describe "Socket::Constants" do
end
consts.each do |c|
- Socket::Constants.should have_constant(c)
+ Socket::Constants.should.const_defined?(c, false)
end
end
end
diff --git a/spec/ruby/library/socket/ipsocket/addr_spec.rb b/spec/ruby/library/socket/ipsocket/addr_spec.rb
index 199eb85ab7..eb16a8efdf 100644
--- a/spec/ruby/library/socket/ipsocket/addr_spec.rb
+++ b/spec/ruby/library/socket/ipsocket/addr_spec.rb
@@ -17,7 +17,7 @@ describe "Socket::IPSocket#addr" do
BasicSocket.do_not_reverse_lookup = false
addrinfo = @socket.addr
addrinfo[0].should == "AF_INET"
- addrinfo[1].should be_kind_of(Integer)
+ addrinfo[1].should.is_a?(Integer)
addrinfo[2].should == SocketSpecs.hostname
addrinfo[3].should == "127.0.0.1"
end
@@ -27,7 +27,7 @@ describe "Socket::IPSocket#addr" do
BasicSocket.do_not_reverse_lookup = true
addrinfo = @socket.addr
addrinfo[0].should == "AF_INET"
- addrinfo[1].should be_kind_of(Integer)
+ addrinfo[1].should.is_a?(Integer)
addrinfo[2].should == "127.0.0.1"
addrinfo[3].should == "127.0.0.1"
end
@@ -35,7 +35,7 @@ describe "Socket::IPSocket#addr" do
it "returns an address in the array if passed false" do
addrinfo = @socket.addr(false)
addrinfo[0].should == "AF_INET"
- addrinfo[1].should be_kind_of(Integer)
+ addrinfo[1].should.is_a?(Integer)
addrinfo[2].should == "127.0.0.1"
addrinfo[3].should == "127.0.0.1"
end
@@ -81,7 +81,7 @@ describe 'Socket::IPSocket#addr' do
describe 'using :cats as the argument' do
it 'raises ArgumentError' do
- -> { @server.addr(:cats) }.should raise_error(ArgumentError)
+ -> { @server.addr(:cats) }.should.raise(ArgumentError)
end
end
end
diff --git a/spec/ruby/library/socket/ipsocket/getaddress_spec.rb b/spec/ruby/library/socket/ipsocket/getaddress_spec.rb
index 329f8267d3..d302cd6a8a 100644
--- a/spec/ruby/library/socket/ipsocket/getaddress_spec.rb
+++ b/spec/ruby/library/socket/ipsocket/getaddress_spec.rb
@@ -23,6 +23,6 @@ describe "Socket::IPSocket#getaddress" do
it "raises an error on unknown hostnames" do
-> {
IPSocket.getaddress("rubyspecdoesntexist.ruby-lang.org")
- }.should raise_error(SocketError)
+ }.should.raise(SocketError)
end
end
diff --git a/spec/ruby/library/socket/ipsocket/inspect_spec.rb b/spec/ruby/library/socket/ipsocket/inspect_spec.rb
new file mode 100644
index 0000000000..85780a16f6
--- /dev/null
+++ b/spec/ruby/library/socket/ipsocket/inspect_spec.rb
@@ -0,0 +1,24 @@
+require_relative '../spec_helper'
+
+describe 'IPSocket#inspect' do
+ it "returns a String with the fd, family, address and port for TCPSocket" do
+ @server = TCPServer.new("127.0.0.1", 0)
+ @socket = TCPSocket.new("127.0.0.1", @server.addr[1])
+ port = @socket.addr[1]
+
+ @socket.inspect.should == "#<TCPSocket:fd #{@socket.fileno}, AF_INET, 127.0.0.1, #{port}>"
+ ensure
+ @socket&.close
+ @server&.close
+ end
+
+ it 'returns a String with the fd, family, address and port for UDPSocket' do
+ @socket = UDPSocket.new
+ @socket.bind('127.0.0.1', 0)
+ port = @socket.addr[1]
+
+ @socket.inspect.should == "#<UDPSocket:fd #{@socket.fileno}, AF_INET, 127.0.0.1, #{port}>"
+ ensure
+ @socket&.close
+ end
+end
diff --git a/spec/ruby/library/socket/ipsocket/peeraddr_spec.rb b/spec/ruby/library/socket/ipsocket/peeraddr_spec.rb
index 702650940b..b79222000a 100644
--- a/spec/ruby/library/socket/ipsocket/peeraddr_spec.rb
+++ b/spec/ruby/library/socket/ipsocket/peeraddr_spec.rb
@@ -18,7 +18,7 @@ describe "Socket::IPSocket#peeraddr" do
it "raises error if socket is not connected" do
-> {
@server.peeraddr
- }.should raise_error(Errno::ENOTCONN)
+ }.should.raise(Errno::ENOTCONN)
end
it "returns an array of information on the peer" do
@@ -92,7 +92,7 @@ describe 'Socket::IPSocket#peeraddr' do
describe 'using :cats as the argument' do
it 'raises ArgumentError' do
- -> { @client.peeraddr(:cats) }.should raise_error(ArgumentError)
+ -> { @client.peeraddr(:cats) }.should.raise(ArgumentError)
end
end
end
diff --git a/spec/ruby/library/socket/ipsocket/recvfrom_spec.rb b/spec/ruby/library/socket/ipsocket/recvfrom_spec.rb
index b58903df23..7af0078be1 100644
--- a/spec/ruby/library/socket/ipsocket/recvfrom_spec.rb
+++ b/spec/ruby/library/socket/ipsocket/recvfrom_spec.rb
@@ -83,43 +83,21 @@ describe "Socket::IPSocket#recvfrom" do
@client.close unless @client.closed?
end
- ruby_version_is ""..."3.3" do
- it "returns an empty String as received data on a closed stream socket" do
- t = Thread.new do
- client = @server.accept
- message = client.recvfrom(10)
- message
- ensure
- client.close if client
- end
-
- Thread.pass while t.status and t.status != "sleep"
- t.status.should_not be_nil
-
- @client.close
-
- t.value.should.is_a? Array
- t.value[0].should == ""
+ it "returns nil on a closed stream socket" do
+ t = Thread.new do
+ client = @server.accept
+ message = client.recvfrom(10)
+ message
+ ensure
+ client.close if client
end
- end
-
- ruby_version_is "3.3" do
- it "returns nil on a closed stream socket" do
- t = Thread.new do
- client = @server.accept
- message = client.recvfrom(10)
- message
- ensure
- client.close if client
- end
- Thread.pass while t.status and t.status != "sleep"
- t.status.should_not be_nil
+ Thread.pass while t.status and t.status != "sleep"
+ t.status.should_not == nil
- @client.close
+ @client.close
- t.value.should be_nil
- end
+ t.value.should == nil
end
end
diff --git a/spec/ruby/library/socket/option/bool_spec.rb b/spec/ruby/library/socket/option/bool_spec.rb
index 144a78043d..9992e842b3 100644
--- a/spec/ruby/library/socket/option/bool_spec.rb
+++ b/spec/ruby/library/socket/option/bool_spec.rb
@@ -4,7 +4,7 @@ require_relative '../fixtures/classes'
describe "Socket::Option.bool" do
it "creates a new Socket::Option" do
so = Socket::Option.bool(:INET, :SOCKET, :KEEPALIVE, true)
- so.should be_an_instance_of(Socket::Option)
+ so.should.instance_of?(Socket::Option)
so.family.should == Socket::AF_INET
so.level.should == Socket::SOL_SOCKET
so.optname.should == Socket::SO_KEEPALIVE
@@ -21,7 +21,7 @@ describe "Socket::Option#bool" do
platform_is_not :windows do
it 'raises TypeError when called on a non boolean option' do
opt = Socket::Option.linger(1, 4)
- -> { opt.bool }.should raise_error(TypeError)
+ -> { opt.bool }.should.raise(TypeError)
end
end
end
diff --git a/spec/ruby/library/socket/option/initialize_spec.rb b/spec/ruby/library/socket/option/initialize_spec.rb
index 8071ad7ef0..5af274f332 100644
--- a/spec/ruby/library/socket/option/initialize_spec.rb
+++ b/spec/ruby/library/socket/option/initialize_spec.rb
@@ -10,7 +10,7 @@ describe 'Socket::Option#initialize' do
opt = Socket::Option
.new(Socket::AF_INET, Socket::SOL_SOCKET, Socket::SO_KEEPALIVE, @bool)
- opt.should be_an_instance_of(Socket::Option)
+ opt.should.instance_of?(Socket::Option)
opt.family.should == Socket::AF_INET
opt.level.should == Socket::SOL_SOCKET
@@ -23,7 +23,7 @@ describe 'Socket::Option#initialize' do
it 'returns a Socket::Option' do
opt = Socket::Option.new(:INET, :SOCKET, :KEEPALIVE, @bool)
- opt.should be_an_instance_of(Socket::Option)
+ opt.should.instance_of?(Socket::Option)
opt.family.should == Socket::AF_INET
opt.level.should == Socket::SOL_SOCKET
@@ -34,19 +34,19 @@ describe 'Socket::Option#initialize' do
it 'raises when using an invalid address family' do
-> {
Socket::Option.new(:INET2, :SOCKET, :KEEPALIVE, @bool)
- }.should raise_error(SocketError)
+ }.should.raise(SocketError)
end
it 'raises when using an invalid level' do
-> {
Socket::Option.new(:INET, :CATS, :KEEPALIVE, @bool)
- }.should raise_error(SocketError)
+ }.should.raise(SocketError)
end
it 'raises when using an invalid option name' do
-> {
Socket::Option.new(:INET, :SOCKET, :CATS, @bool)
- }.should raise_error(SocketError)
+ }.should.raise(SocketError)
end
end
@@ -54,7 +54,7 @@ describe 'Socket::Option#initialize' do
it 'returns a Socket::Option' do
opt = Socket::Option.new('INET', 'SOCKET', 'KEEPALIVE', @bool)
- opt.should be_an_instance_of(Socket::Option)
+ opt.should.instance_of?(Socket::Option)
opt.family.should == Socket::AF_INET
opt.level.should == Socket::SOL_SOCKET
@@ -65,19 +65,19 @@ describe 'Socket::Option#initialize' do
it 'raises when using an invalid address family' do
-> {
Socket::Option.new('INET2', 'SOCKET', 'KEEPALIVE', @bool)
- }.should raise_error(SocketError)
+ }.should.raise(SocketError)
end
it 'raises when using an invalid level' do
-> {
Socket::Option.new('INET', 'CATS', 'KEEPALIVE', @bool)
- }.should raise_error(SocketError)
+ }.should.raise(SocketError)
end
it 'raises when using an invalid option name' do
-> {
Socket::Option.new('INET', 'SOCKET', 'CATS', @bool)
- }.should raise_error(SocketError)
+ }.should.raise(SocketError)
end
end
end
diff --git a/spec/ruby/library/socket/option/int_spec.rb b/spec/ruby/library/socket/option/int_spec.rb
index 8c69ef6cbd..0cd341f88a 100644
--- a/spec/ruby/library/socket/option/int_spec.rb
+++ b/spec/ruby/library/socket/option/int_spec.rb
@@ -4,7 +4,7 @@ require_relative '../fixtures/classes'
describe "Socket::Option.int" do
it "creates a new Socket::Option" do
so = Socket::Option.int(:INET, :SOCKET, :KEEPALIVE, 5)
- so.should be_an_instance_of(Socket::Option)
+ so.should.instance_of?(Socket::Option)
so.family.should == Socket::Constants::AF_INET
so.level.should == Socket::Constants::SOL_SOCKET
so.optname.should == Socket::Constants::SO_KEEPALIVE
@@ -14,7 +14,7 @@ describe "Socket::Option.int" do
it 'returns a Socket::Option' do
opt = Socket::Option.int(:INET, :IP, :TTL, 4)
- opt.should be_an_instance_of(Socket::Option)
+ opt.should.instance_of?(Socket::Option)
opt.family.should == Socket::AF_INET
opt.level.should == Socket::IPPROTO_IP
@@ -37,7 +37,7 @@ describe "Socket::Option#int" do
platform_is_not :windows do
it 'raises TypeError when called on a non integer option' do
opt = Socket::Option.linger(1, 4)
- -> { opt.int }.should raise_error(TypeError)
+ -> { opt.int }.should.raise(TypeError)
end
end
end
diff --git a/spec/ruby/library/socket/option/linger_spec.rb b/spec/ruby/library/socket/option/linger_spec.rb
index ee987db85b..87c5e0982e 100644
--- a/spec/ruby/library/socket/option/linger_spec.rb
+++ b/spec/ruby/library/socket/option/linger_spec.rb
@@ -9,7 +9,7 @@ end
describe "Socket::Option.linger" do
it "creates a new Socket::Option for SO_LINGER" do
so = Socket::Option.linger(1, 10)
- so.should be_an_instance_of(Socket::Option)
+ so.should.instance_of?(Socket::Option)
so.family.should == Socket::Constants::AF_UNSPEC
so.level.should == Socket::Constants::SOL_SOCKET
@@ -31,46 +31,46 @@ describe "Socket::Option#linger" do
it "returns linger option" do
so = Socket::Option.linger(0, 5)
ary = so.linger
- ary[0].should be_false
+ ary[0].should == false
ary[1].should == 5
so = Socket::Option.linger(false, 4)
ary = so.linger
- ary[0].should be_false
+ ary[0].should == false
ary[1].should == 4
so = Socket::Option.linger(1, 10)
ary = so.linger
- ary[0].should be_true
+ ary[0].should == true
ary[1].should == 10
so = Socket::Option.linger(true, 9)
ary = so.linger
- ary[0].should be_true
+ ary[0].should == true
ary[1].should == 9
end
it "raises TypeError if not a SO_LINGER" do
so = Socket::Option.int(:AF_UNSPEC, :SOL_SOCKET, :KEEPALIVE, 1)
- -> { so.linger }.should raise_error(TypeError)
+ -> { so.linger }.should.raise(TypeError)
end
it 'raises TypeError when called on a non SOL_SOCKET/SO_LINGER option' do
opt = Socket::Option.int(:INET, :IP, :TTL, 4)
- -> { opt.linger }.should raise_error(TypeError)
+ -> { opt.linger }.should.raise(TypeError)
end
platform_is_not :windows do
it "raises TypeError if option has not good size" do
so = Socket::Option.int(:AF_UNSPEC, :SOL_SOCKET, :LINGER, 1)
- -> { so.linger }.should raise_error(TypeError)
+ -> { so.linger }.should.raise(TypeError)
end
end
it 'raises TypeError when called on a non linger option' do
opt = Socket::Option.new(:INET, :SOCKET, :LINGER, '')
- -> { opt.linger }.should raise_error(TypeError)
+ -> { opt.linger }.should.raise(TypeError)
end
end
diff --git a/spec/ruby/library/socket/option/new_spec.rb b/spec/ruby/library/socket/option/new_spec.rb
index a9e6f09097..3721d63ee5 100644
--- a/spec/ruby/library/socket/option/new_spec.rb
+++ b/spec/ruby/library/socket/option/new_spec.rb
@@ -22,14 +22,14 @@ describe "Socket::Option.new" do
end
it "should raise error on unknown family" do
- -> { Socket::Option.new(:INET4, :SOCKET, :KEEPALIVE, [0].pack('i')) }.should raise_error(SocketError)
+ -> { Socket::Option.new(:INET4, :SOCKET, :KEEPALIVE, [0].pack('i')) }.should.raise(SocketError)
end
it "should raise error on unknown level" do
- -> { Socket::Option.new(:INET, :ROCKET, :KEEPALIVE, [0].pack('i')) }.should raise_error(SocketError)
+ -> { Socket::Option.new(:INET, :ROCKET, :KEEPALIVE, [0].pack('i')) }.should.raise(SocketError)
end
it "should raise error on unknown option name" do
- -> { Socket::Option.new(:INET, :SOCKET, :ALIVE, [0].pack('i')) }.should raise_error(SocketError)
+ -> { Socket::Option.new(:INET, :SOCKET, :ALIVE, [0].pack('i')) }.should.raise(SocketError)
end
end
diff --git a/spec/ruby/library/socket/shared/address.rb b/spec/ruby/library/socket/shared/address.rb
index f3be9cfb99..c64602df2f 100644
--- a/spec/ruby/library/socket/shared/address.rb
+++ b/spec/ruby/library/socket/shared/address.rb
@@ -46,7 +46,7 @@ describe :socket_local_remote_address, shared: true do
end
it 'returns an Addrinfo' do
- @addr.should be_an_instance_of(Addrinfo)
+ @addr.should.instance_of?(Addrinfo)
end
it 'uses 0 as the protocol' do
@@ -110,7 +110,7 @@ describe :socket_local_remote_address, shared: true do
end
it 'returns an Addrinfo' do
- @addr.should be_an_instance_of(Addrinfo)
+ @addr.should.instance_of?(Addrinfo)
end
it 'uses 0 as the protocol' do
@@ -129,41 +129,51 @@ describe :socket_local_remote_address, shared: true do
end
end
- with_feature :unix_socket do
- describe 'using UNIXSocket' do
- before :each do
- @path = SocketSpecs.socket_path
- @s = UNIXServer.new(@path)
- @a = UNIXSocket.new(@path)
- @b = @s.accept
- @addr = @object.call(@a)
- end
+ describe 'using UNIXSocket' do
+ before :each do
+ @path = SocketSpecs.socket_path
+ @s = UNIXServer.new(@path)
+ @a = UNIXSocket.new(@path)
+ @b = @s.accept
+ @addr = @object.call(@a)
+ end
- after :each do
- [@b, @a, @s].each(&:close)
- rm_r(@path)
- end
+ after :each do
+ [@b, @a, @s].each(&:close)
+ rm_r(@path)
+ end
- it 'uses AF_UNIX as the address family' do
- @addr.afamily.should == Socket::AF_UNIX
- end
+ it 'uses AF_UNIX as the address family' do
+ @addr.afamily.should == Socket::AF_UNIX
+ end
- it 'uses PF_UNIX as the protocol family' do
- @addr.pfamily.should == Socket::PF_UNIX
- end
+ it 'uses PF_UNIX as the protocol family' do
+ @addr.pfamily.should == Socket::PF_UNIX
+ end
- it 'uses SOCK_STREAM as the socket type' do
- @addr.socktype.should == Socket::SOCK_STREAM
+ it 'uses SOCK_STREAM as the socket type' do
+ @addr.socktype.should == Socket::SOCK_STREAM
+ end
+
+ it 'uses the correct socket path' do
+ if @method == :local_address
+ @addr.unix_path.should == ""
+ else
+ @addr.unix_path.should == @path
end
+ end
- it 'uses the correct socket path' do
+ platform_is_not :windows do
+ it 'equals address of peer socket' do
if @method == :local_address
- @addr.unix_path.should == ""
+ @addr.to_s.should == @b.remote_address.to_s
else
- @addr.unix_path.should == @path
+ @addr.to_s.should == @b.local_address.to_s
end
end
+ end
+ guard -> { platform_is :windows and ruby_bug "#21702", ""..."4.2" } do
it 'equals address of peer socket' do
if @method == :local_address
@addr.to_s.should == @b.remote_address.to_s
@@ -171,23 +181,23 @@ describe :socket_local_remote_address, shared: true do
@addr.to_s.should == @b.local_address.to_s
end
end
+ end
- it 'returns an Addrinfo' do
- @addr.should be_an_instance_of(Addrinfo)
- end
+ it 'returns an Addrinfo' do
+ @addr.should.instance_of?(Addrinfo)
+ end
- it 'uses 0 as the protocol' do
- @addr.protocol.should == 0
- end
+ it 'uses 0 as the protocol' do
+ @addr.protocol.should == 0
+ end
- it 'can be used to connect to the server' do
- skip if @method == :local_address
- b = @addr.connect
- begin
- b.remote_address.to_s.should == @addr.to_s
- ensure
- b.close
- end
+ it 'can be used to connect to the server' do
+ skip if @method == :local_address
+ b = @addr.connect
+ begin
+ b.remote_address.to_s.should == @addr.to_s
+ ensure
+ b.close
end
end
end
@@ -230,7 +240,7 @@ describe :socket_local_remote_address, shared: true do
end
it 'returns an Addrinfo' do
- @addr.should be_an_instance_of(Addrinfo)
+ @addr.should.instance_of?(Addrinfo)
end
it 'uses 0 as the protocol' do
diff --git a/spec/ruby/library/socket/shared/pack_sockaddr.rb b/spec/ruby/library/socket/shared/pack_sockaddr.rb
deleted file mode 100644
index f309aa02c7..0000000000
--- a/spec/ruby/library/socket/shared/pack_sockaddr.rb
+++ /dev/null
@@ -1,94 +0,0 @@
-# coding: utf-8
-describe :socket_pack_sockaddr_in, shared: true do
- it "packs and unpacks" do
- sockaddr_in = Socket.public_send(@method, 0, nil)
- port, addr = Socket.unpack_sockaddr_in(sockaddr_in)
- ["127.0.0.1", "::1"].include?(addr).should == true
- port.should == 0
-
- sockaddr_in = Socket.public_send(@method, 0, '')
- Socket.unpack_sockaddr_in(sockaddr_in).should == [0, '0.0.0.0']
-
- sockaddr_in = Socket.public_send(@method, 80, '127.0.0.1')
- Socket.unpack_sockaddr_in(sockaddr_in).should == [80, '127.0.0.1']
-
- sockaddr_in = Socket.public_send(@method, '80', '127.0.0.1')
- Socket.unpack_sockaddr_in(sockaddr_in).should == [80, '127.0.0.1']
-
- 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
-
- it 'resolves the service name to a port' do
- sockaddr_in = Socket.public_send(@method, 'http', '127.0.0.1')
- Socket.unpack_sockaddr_in(sockaddr_in).should == [80, '127.0.0.1']
- end
-
- describe 'using an IPv4 address' do
- it 'returns a String of 16 bytes' do
- str = Socket.public_send(@method, 80, '127.0.0.1')
-
- str.should be_an_instance_of(String)
- str.bytesize.should == 16
- end
- end
-
- describe 'using an IPv6 address' do
- it 'returns a String of 28 bytes' do
- str = Socket.public_send(@method, 80, '::1')
-
- str.should be_an_instance_of(String)
- str.bytesize.should == 28
- end
- end
-end
-
-describe :socket_pack_sockaddr_un, shared: true do
- with_feature :unix_socket do
- it 'should be idempotent' do
- bytes = Socket.public_send(@method, '/tmp/foo').bytes
- bytes[2..9].should == [47, 116, 109, 112, 47, 102, 111, 111]
- bytes[10..-1].all?(&:zero?).should == true
- end
-
- it "packs and unpacks" do
- sockaddr_un = Socket.public_send(@method, '/tmp/s')
- Socket.unpack_sockaddr_un(sockaddr_un).should == '/tmp/s'
- end
-
- it "handles correctly paths with multibyte chars" do
- sockaddr_un = Socket.public_send(@method, '/home/ваÑÑ/sock')
- path = Socket.unpack_sockaddr_un(sockaddr_un).encode('UTF-8', 'UTF-8')
- path.should == '/home/ваÑÑ/sock'
- end
- end
-
- platform_is :linux do
- it 'returns a String of 110 bytes' do
- str = Socket.public_send(@method, '/tmp/test.sock')
-
- str.should be_an_instance_of(String)
- str.bytesize.should == 110
- end
- end
-
- platform_is :bsd do
- it 'returns a String of 106 bytes' do
- str = Socket.public_send(@method, '/tmp/test.sock')
-
- str.should be_an_instance_of(String)
- str.bytesize.should == 106
- end
- end
-
- platform_is_not :windows, :aix do
- it "raises ArgumentError for paths that are too long" do
- # AIX doesn't raise error
- long_path = 'a' * 110
- -> { Socket.public_send(@method, long_path) }.should raise_error(ArgumentError)
- end
- end
-end
diff --git a/spec/ruby/library/socket/shared/socketpair.rb b/spec/ruby/library/socket/shared/socketpair.rb
deleted file mode 100644
index 25146cfff6..0000000000
--- a/spec/ruby/library/socket/shared/socketpair.rb
+++ /dev/null
@@ -1,138 +0,0 @@
-describe :socket_socketpair, shared: true do
- platform_is_not :windows do
- it "ensures the returned sockets are connected" do
- s1, s2 = Socket.public_send(@method, Socket::AF_UNIX, 1, 0)
- s1.puts("test")
- s2.gets.should == "test\n"
- s1.close
- s2.close
- end
-
- it "responses with array of two sockets" do
- begin
- s1, s2 = Socket.public_send(@method, :UNIX, :STREAM)
-
- s1.should be_an_instance_of(Socket)
- s2.should be_an_instance_of(Socket)
- ensure
- s1.close
- s2.close
- end
- end
-
- describe 'using an Integer as the 1st and 2nd argument' do
- it 'returns two Socket objects' do
- s1, s2 = Socket.public_send(@method, Socket::AF_UNIX, Socket::SOCK_STREAM)
-
- s1.should be_an_instance_of(Socket)
- s2.should be_an_instance_of(Socket)
- s1.close
- s2.close
- end
- end
-
- describe 'using a Symbol as the 1st and 2nd argument' do
- it 'returns two Socket objects' do
- s1, s2 = Socket.public_send(@method, :UNIX, :STREAM)
-
- s1.should be_an_instance_of(Socket)
- s2.should be_an_instance_of(Socket)
- s1.close
- s2.close
- end
-
- it 'raises SocketError for an unknown address family' do
- -> { Socket.public_send(@method, :CATS, :STREAM) }.should raise_error(SocketError)
- end
-
- it 'raises SocketError for an unknown socket type' do
- -> { Socket.public_send(@method, :UNIX, :CATS) }.should raise_error(SocketError)
- end
- end
-
- describe 'using a String as the 1st and 2nd argument' do
- it 'returns two Socket objects' do
- s1, s2 = Socket.public_send(@method, 'UNIX', 'STREAM')
-
- s1.should be_an_instance_of(Socket)
- s2.should be_an_instance_of(Socket)
- s1.close
- s2.close
- end
-
- it 'raises SocketError for an unknown address family' do
- -> { Socket.public_send(@method, 'CATS', 'STREAM') }.should raise_error(SocketError)
- end
-
- it 'raises SocketError for an unknown socket type' do
- -> { Socket.public_send(@method, 'UNIX', 'CATS') }.should raise_error(SocketError)
- end
- end
-
- describe 'using an object that responds to #to_str as the 1st and 2nd argument' do
- it 'returns two Socket objects' do
- family = mock(:family)
- type = mock(:type)
-
- family.stub!(:to_str).and_return('UNIX')
- type.stub!(:to_str).and_return('STREAM')
-
- s1, s2 = Socket.public_send(@method, family, type)
-
- s1.should be_an_instance_of(Socket)
- s2.should be_an_instance_of(Socket)
- s1.close
- s2.close
- end
-
- it 'raises TypeError when #to_str does not return a String' do
- family = mock(:family)
- type = mock(:type)
-
- family.stub!(:to_str).and_return(Socket::AF_UNIX)
- type.stub!(:to_str).and_return(Socket::SOCK_STREAM)
-
- -> { Socket.public_send(@method, family, type) }.should raise_error(TypeError)
- end
-
- it 'raises SocketError for an unknown address family' do
- family = mock(:family)
- type = mock(:type)
-
- family.stub!(:to_str).and_return('CATS')
- type.stub!(:to_str).and_return('STREAM')
-
- -> { Socket.public_send(@method, family, type) }.should raise_error(SocketError)
- end
-
- it 'raises SocketError for an unknown socket type' do
- family = mock(:family)
- type = mock(:type)
-
- family.stub!(:to_str).and_return('UNIX')
- type.stub!(:to_str).and_return('CATS')
-
- -> { Socket.public_send(@method, family, type) }.should raise_error(SocketError)
- end
- end
-
- it 'accepts a custom protocol as an Integer as the 3rd argument' do
- s1, s2 = Socket.public_send(@method, :UNIX, :STREAM, Socket::IPPROTO_IP)
- s1.should be_an_instance_of(Socket)
- s2.should be_an_instance_of(Socket)
- s1.close
- s2.close
- end
-
- it 'connects the returned Socket objects' do
- s1, s2 = Socket.public_send(@method, :UNIX, :STREAM)
- begin
- s1.write('hello')
- s2.recv(5).should == 'hello'
- ensure
- s1.close
- s2.close
- end
- end
- end
-end
diff --git a/spec/ruby/library/socket/socket/accept_loop_spec.rb b/spec/ruby/library/socket/socket/accept_loop_spec.rb
index 78e8c3fa4a..6c65b192ed 100644
--- a/spec/ruby/library/socket/socket/accept_loop_spec.rb
+++ b/spec/ruby/library/socket/socket/accept_loop_spec.rb
@@ -41,8 +41,8 @@ describe 'Socket.accept_loop' do
end
begin
- conn.should be_an_instance_of(Socket)
- addr.should be_an_instance_of(Addrinfo)
+ conn.should.instance_of?(Socket)
+ addr.should.instance_of?(Addrinfo)
ensure
conn.close
end
@@ -73,8 +73,8 @@ describe 'Socket.accept_loop' do
end
begin
- conn.should be_an_instance_of(Socket)
- addr.should be_an_instance_of(Addrinfo)
+ conn.should.instance_of?(Socket)
+ addr.should.instance_of?(Addrinfo)
ensure
conn.close
end
diff --git a/spec/ruby/library/socket/socket/accept_nonblock_spec.rb b/spec/ruby/library/socket/socket/accept_nonblock_spec.rb
index 011622988c..09cdbaa7b4 100644
--- a/spec/ruby/library/socket/socket/accept_nonblock_spec.rb
+++ b/spec/ruby/library/socket/socket/accept_nonblock_spec.rb
@@ -17,12 +17,12 @@ describe "Socket#accept_nonblock" do
it "raises IO::WaitReadable if the connection is not accepted yet" do
-> {
@socket.accept_nonblock
- }.should raise_error(IO::WaitReadable) { |e|
+ }.should.raise(IO::WaitReadable) { |e|
platform_is_not :windows do
- e.should be_kind_of(Errno::EAGAIN)
+ e.should.is_a?(Errno::EAGAIN)
end
platform_is :windows do
- e.should be_kind_of(Errno::EWOULDBLOCK)
+ e.should.is_a?(Errno::EWOULDBLOCK)
end
}
end
@@ -45,8 +45,8 @@ describe 'Socket#accept_nonblock' do
describe 'using an unbound socket' do
it 'raises Errno::EINVAL' do
- -> { @server.accept_nonblock }.should raise_error(Errno::EINVAL)
- -> { @server.accept_nonblock(exception: false) }.should raise_error(Errno::EINVAL)
+ -> { @server.accept_nonblock }.should.raise(Errno::EINVAL)
+ -> { @server.accept_nonblock(exception: false) }.should.raise(Errno::EINVAL)
end
end
@@ -56,8 +56,8 @@ describe 'Socket#accept_nonblock' do
end
it 'raises Errno::EINVAL' do
- -> { @server.accept_nonblock }.should raise_error(Errno::EINVAL)
- -> { @server.accept_nonblock(exception: false) }.should raise_error(Errno::EINVAL)
+ -> { @server.accept_nonblock }.should.raise(Errno::EINVAL)
+ -> { @server.accept_nonblock(exception: false) }.should.raise(Errno::EINVAL)
end
end
@@ -65,8 +65,8 @@ describe 'Socket#accept_nonblock' do
it 'raises IOError' do
@server.close
- -> { @server.accept_nonblock }.should raise_error(IOError)
- -> { @server.accept_nonblock(exception: false) }.should raise_error(IOError)
+ -> { @server.accept_nonblock }.should.raise(IOError)
+ -> { @server.accept_nonblock(exception: false) }.should.raise(IOError)
end
end
@@ -78,7 +78,7 @@ describe 'Socket#accept_nonblock' do
describe 'without a connected client' do
it 'raises IO::WaitReadable' do
- -> { @server.accept_nonblock }.should raise_error(IO::WaitReadable)
+ -> { @server.accept_nonblock }.should.raise(IO::WaitReadable)
end
end
@@ -100,8 +100,8 @@ describe 'Socket#accept_nonblock' do
IO.select([@server])
@socket, addrinfo = @server.accept_nonblock
- @socket.should be_an_instance_of(Socket)
- addrinfo.should be_an_instance_of(Addrinfo)
+ @socket.should.instance_of?(Socket)
+ addrinfo.should.instance_of?(Addrinfo)
end
describe 'the returned Addrinfo' do
diff --git a/spec/ruby/library/socket/socket/accept_spec.rb b/spec/ruby/library/socket/socket/accept_spec.rb
index 417f996c55..fca727ab08 100644
--- a/spec/ruby/library/socket/socket/accept_spec.rb
+++ b/spec/ruby/library/socket/socket/accept_spec.rb
@@ -15,7 +15,7 @@ describe 'Socket#accept' do
platform_is :linux do # hangs on other platforms
describe 'using an unbound socket' do
it 'raises Errno::EINVAL' do
- -> { @server.accept }.should raise_error(Errno::EINVAL)
+ -> { @server.accept }.should.raise(Errno::EINVAL)
end
end
@@ -25,7 +25,7 @@ describe 'Socket#accept' do
end
it 'raises Errno::EINVAL' do
- -> { @server.accept }.should raise_error(Errno::EINVAL)
+ -> { @server.accept }.should.raise(Errno::EINVAL)
end
end
end
@@ -34,7 +34,7 @@ describe 'Socket#accept' do
it 'raises IOError' do
@server.close
- -> { @server.accept }.should raise_error(IOError)
+ -> { @server.accept }.should.raise(IOError)
end
end
@@ -58,7 +58,7 @@ describe 'Socket#accept' do
value = thread.value
begin
- value.should be_an_instance_of(Array)
+ value.should.instance_of?(Array)
ensure
client.close
value[0].close
@@ -82,8 +82,8 @@ describe 'Socket#accept' do
it 'returns an Array containing a Socket and an Addrinfo' do
@socket, addrinfo = @server.accept
- @socket.should be_an_instance_of(Socket)
- addrinfo.should be_an_instance_of(Addrinfo)
+ @socket.should.instance_of?(Socket)
+ addrinfo.should.instance_of?(Addrinfo)
end
describe 'the returned Addrinfo' do
diff --git a/spec/ruby/library/socket/socket/bind_spec.rb b/spec/ruby/library/socket/socket/bind_spec.rb
index e76336eafa..164df92205 100644
--- a/spec/ruby/library/socket/socket/bind_spec.rb
+++ b/spec/ruby/library/socket/socket/bind_spec.rb
@@ -8,12 +8,12 @@ describe "Socket#bind on SOCK_DGRAM socket" do
end
after :each do
- @sock.closed?.should be_false
+ @sock.closed?.should == false
@sock.close
end
it "binds to a port" do
- -> { @sock.bind(@sockaddr) }.should_not raise_error
+ -> { @sock.bind(@sockaddr) }.should_not.raise
end
it "returns 0 if successful" do
@@ -23,12 +23,12 @@ describe "Socket#bind on SOCK_DGRAM socket" do
it "raises Errno::EINVAL when already bound" do
@sock.bind(@sockaddr)
- -> { @sock.bind(@sockaddr) }.should raise_error(Errno::EINVAL)
+ -> { @sock.bind(@sockaddr) }.should.raise(Errno::EINVAL)
end
it "raises Errno::EADDRNOTAVAIL when the specified sockaddr is not available from the local machine" do
sockaddr1 = Socket.pack_sockaddr_in(0, "4.3.2.1")
- -> { @sock.bind(sockaddr1) }.should raise_error(Errno::EADDRNOTAVAIL)
+ -> { @sock.bind(sockaddr1) }.should.raise(Errno::EADDRNOTAVAIL)
end
platform_is_not :windows, :cygwin do
@@ -36,7 +36,7 @@ describe "Socket#bind on SOCK_DGRAM socket" do
break if File.read('/proc/sys/net/ipv4/ip_unprivileged_port_start').to_i <= 1 rescue nil
it "raises Errno::EACCES when the current user does not have permission to bind" do
sockaddr1 = Socket.pack_sockaddr_in(1, "127.0.0.1")
- -> { @sock.bind(sockaddr1) }.should raise_error(Errno::EACCES)
+ -> { @sock.bind(sockaddr1) }.should.raise(Errno::EACCES)
end
end
end
@@ -50,12 +50,12 @@ describe "Socket#bind on SOCK_STREAM socket" do
end
after :each do
- @sock.closed?.should be_false
+ @sock.closed?.should == false
@sock.close
end
it "binds to a port" do
- -> { @sock.bind(@sockaddr) }.should_not raise_error
+ -> { @sock.bind(@sockaddr) }.should_not.raise
end
it "returns 0 if successful" do
@@ -65,12 +65,12 @@ describe "Socket#bind on SOCK_STREAM socket" do
it "raises Errno::EINVAL when already bound" do
@sock.bind(@sockaddr)
- -> { @sock.bind(@sockaddr) }.should raise_error(Errno::EINVAL)
+ -> { @sock.bind(@sockaddr) }.should.raise(Errno::EINVAL)
end
it "raises Errno::EADDRNOTAVAIL when the specified sockaddr is not available from the local machine" do
sockaddr1 = Socket.pack_sockaddr_in(0, "4.3.2.1")
- -> { @sock.bind(sockaddr1) }.should raise_error(Errno::EADDRNOTAVAIL)
+ -> { @sock.bind(sockaddr1) }.should.raise(Errno::EADDRNOTAVAIL)
end
platform_is_not :windows, :cygwin do
@@ -78,7 +78,7 @@ describe "Socket#bind on SOCK_STREAM socket" do
break if File.read('/proc/sys/net/ipv4/ip_unprivileged_port_start').to_i <= 1 rescue nil
it "raises Errno::EACCES when the current user does not have permission to bind" do
sockaddr1 = Socket.pack_sockaddr_in(1, "127.0.0.1")
- -> { @sock.bind(sockaddr1) }.should raise_error(Errno::EACCES)
+ -> { @sock.bind(sockaddr1) }.should.raise(Errno::EACCES)
end
end
end
@@ -103,14 +103,14 @@ describe 'Socket#bind' do
it 'raises Errno::EINVAL when binding to an already bound port' do
@socket.bind(@sockaddr)
- -> { @socket.bind(@sockaddr) }.should raise_error(Errno::EINVAL)
+ -> { @socket.bind(@sockaddr) }.should.raise(Errno::EINVAL)
end
it 'raises Errno::EADDRNOTAVAIL when the specified sockaddr is not available' do
ip = family == Socket::AF_INET ? '4.3.2.1' : '::2'
sockaddr1 = Socket.sockaddr_in(0, ip)
- -> { @socket.bind(sockaddr1) }.should raise_error(Errno::EADDRNOTAVAIL)
+ -> { @socket.bind(sockaddr1) }.should.raise(Errno::EADDRNOTAVAIL)
end
platform_is_not :windows do
@@ -120,7 +120,7 @@ describe 'Socket#bind' do
it 'raises Errno::EACCES when the user is not allowed to bind to the port' do
sockaddr1 = Socket.pack_sockaddr_in(1, ip_address)
- -> { @socket.bind(sockaddr1) }.should raise_error(Errno::EACCES)
+ -> { @socket.bind(sockaddr1) }.should.raise(Errno::EACCES)
end
end
end
@@ -138,7 +138,7 @@ describe 'Socket#bind' do
it 'binds to an Addrinfo' do
@socket.bind(@addr).should == 0
- @socket.local_address.should be_an_instance_of(Addrinfo)
+ @socket.local_address.should.instance_of?(Addrinfo)
end
it 'uses a new Addrinfo for the local address' do
diff --git a/spec/ruby/library/socket/socket/connect_nonblock_spec.rb b/spec/ruby/library/socket/socket/connect_nonblock_spec.rb
index 359b8719fb..dac24e3e5b 100644
--- a/spec/ruby/library/socket/socket/connect_nonblock_spec.rb
+++ b/spec/ruby/library/socket/socket/connect_nonblock_spec.rb
@@ -53,13 +53,13 @@ describe "Socket#connect_nonblock" do
it "raises Errno::EINPROGRESS when the connect would block" do
-> do
@socket.connect_nonblock(@addr)
- end.should raise_error(Errno::EINPROGRESS)
+ end.should.raise(Errno::EINPROGRESS)
end
it "raises Errno::EINPROGRESS with IO::WaitWritable mixed in when the connect would block" do
-> do
@socket.connect_nonblock(@addr)
- end.should raise_error(IO::WaitWritable)
+ end.should.raise(IO::WaitWritable)
end
it "returns :wait_writable in exceptionless mode when the connect would block" do
@@ -93,7 +93,7 @@ describe 'Socket#connect_nonblock' do
end
it 'raises TypeError when passed an Integer' do
- -> { @client.connect_nonblock(666) }.should raise_error(TypeError)
+ -> { @client.connect_nonblock(666) }.should.raise(TypeError)
end
end
@@ -122,7 +122,7 @@ describe 'Socket#connect_nonblock' do
# as it's too implementation-dependent and checking for connect()
# errors is futile anyways because of TOCTOU
@client.connect_nonblock(@server.connect_address)
- }.should raise_error(Errno::EISCONN)
+ }.should.raise(Errno::EISCONN)
end
it 'returns 0 when already connected in exceptionless mode' do
@@ -139,7 +139,7 @@ describe 'Socket#connect_nonblock' do
-> {
@client.connect_nonblock(@server.connect_address)
- }.should raise_error(IO::EINPROGRESSWaitWritable)
+ }.should.raise(IO::EINPROGRESSWaitWritable)
end
end
end
diff --git a/spec/ruby/library/socket/socket/connect_spec.rb b/spec/ruby/library/socket/socket/connect_spec.rb
index 130379ce2b..c928b66c53 100644
--- a/spec/ruby/library/socket/socket/connect_spec.rb
+++ b/spec/ruby/library/socket/socket/connect_spec.rb
@@ -40,7 +40,7 @@ describe 'Socket#connect' do
# as it's too implementation-dependent and checking for connect()
# errors is futile anyways because of TOCTOU
@client.connect(@server.getsockname)
- }.should raise_error(Errno::EISCONN)
+ }.should.raise(Errno::EISCONN)
end
platform_is_not :darwin do
@@ -70,7 +70,7 @@ describe 'Socket#connect' do
rescue Errno::ENETUNREACH
skip "Off line"
end
- }.should raise_error(IO::TimeoutError)
+ }.should.raise(IO::TimeoutError)
ensure
client.close
end
diff --git a/spec/ruby/library/socket/socket/getaddrinfo_spec.rb b/spec/ruby/library/socket/socket/getaddrinfo_spec.rb
index 9f049597d0..7e5bdc9b25 100644
--- a/spec/ruby/library/socket/socket/getaddrinfo_spec.rb
+++ b/spec/ruby/library/socket/socket/getaddrinfo_spec.rb
@@ -43,7 +43,7 @@ describe "Socket.getaddrinfo" do
addrinfo.each do |a|
case a.last
when Socket::IPPROTO_UDP, Socket::IPPROTO_TCP
- expected.should include(a)
+ expected.should.include?(a)
else
# don't check this. It's some weird protocol we don't know about
# so we can't spec it.
@@ -90,7 +90,7 @@ describe "Socket.getaddrinfo" do
["AF_INET6", 9, "::", "::", Socket::AF_INET6, Socket::SOCK_STREAM, Socket::IPPROTO_TCP],
["AF_INET6", 9, "0:0:0:0:0:0:0:0", "0:0:0:0:0:0:0:0", Socket::AF_INET6, Socket::SOCK_STREAM, Socket::IPPROTO_TCP]
]
- res.each { |a| expected.should include(a) }
+ res.each { |a| expected.should.include?(a) }
end
it "accepts empty addresses for IPv6 non-passive sockets" do
@@ -104,7 +104,15 @@ describe "Socket.getaddrinfo" do
["AF_INET6", 9, "::1", "::1", Socket::AF_INET6, Socket::SOCK_STREAM, Socket::IPPROTO_TCP],
["AF_INET6", 9, "0:0:0:0:0:0:0:1", "0:0:0:0:0:0:0:1", Socket::AF_INET6, Socket::SOCK_STREAM, Socket::IPPROTO_TCP]
]
- res.each { |a| expected.should include(a) }
+ res.each { |a| expected.should.include?(a) }
+ end
+
+ it "raises ResolutionError when fails to resolve address" do
+ -> {
+ Socket.getaddrinfo("www.kame.net", 80, "AF_UNIX")
+ }.should.raise(Socket::ResolutionError) { |e|
+ [Socket::EAI_FAMILY, Socket::EAI_FAIL].should.include?(e.error_code)
+ }
end
end
end
@@ -112,7 +120,7 @@ end
describe 'Socket.getaddrinfo' do
describe 'without global reverse lookups' do
it 'returns an Array' do
- Socket.getaddrinfo(nil, 'ftp').should be_an_instance_of(Array)
+ Socket.getaddrinfo(nil, 'ftp').should.instance_of?(Array)
end
it 'accepts an Integer as the address family' do
@@ -123,8 +131,8 @@ describe 'Socket.getaddrinfo' do
array[2].should == '127.0.0.1'
array[3].should == '127.0.0.1'
array[4].should == Socket::AF_INET
- array[5].should be_kind_of(Integer)
- array[6].should be_kind_of(Integer)
+ array[5].should.is_a?(Integer)
+ array[6].should.is_a?(Integer)
end
it 'accepts an Integer as the address family using IPv6' do
@@ -135,8 +143,8 @@ describe 'Socket.getaddrinfo' do
array[2].should == '::1'
array[3].should == '::1'
array[4].should == Socket::AF_INET6
- array[5].should be_kind_of(Integer)
- array[6].should be_kind_of(Integer)
+ array[5].should.is_a?(Integer)
+ array[6].should.is_a?(Integer)
end
it 'accepts a Symbol as the address family' do
@@ -147,8 +155,8 @@ describe 'Socket.getaddrinfo' do
array[2].should == '127.0.0.1'
array[3].should == '127.0.0.1'
array[4].should == Socket::AF_INET
- array[5].should be_kind_of(Integer)
- array[6].should be_kind_of(Integer)
+ array[5].should.is_a?(Integer)
+ array[6].should.is_a?(Integer)
end
it 'accepts a Symbol as the address family using IPv6' do
@@ -159,8 +167,8 @@ describe 'Socket.getaddrinfo' do
array[2].should == '::1'
array[3].should == '::1'
array[4].should == Socket::AF_INET6
- array[5].should be_kind_of(Integer)
- array[6].should be_kind_of(Integer)
+ array[5].should.is_a?(Integer)
+ array[6].should.is_a?(Integer)
end
it 'accepts a String as the address family' do
@@ -171,8 +179,8 @@ describe 'Socket.getaddrinfo' do
array[2].should == '127.0.0.1'
array[3].should == '127.0.0.1'
array[4].should == Socket::AF_INET
- array[5].should be_kind_of(Integer)
- array[6].should be_kind_of(Integer)
+ array[5].should.is_a?(Integer)
+ array[6].should.is_a?(Integer)
end
it 'accepts a String as the address family using IPv6' do
@@ -183,8 +191,8 @@ describe 'Socket.getaddrinfo' do
array[2].should == '::1'
array[3].should == '::1'
array[4].should == Socket::AF_INET6
- array[5].should be_kind_of(Integer)
- array[6].should be_kind_of(Integer)
+ array[5].should.is_a?(Integer)
+ array[6].should.is_a?(Integer)
end
it 'accepts an object responding to #to_str as the host' do
@@ -199,8 +207,8 @@ describe 'Socket.getaddrinfo' do
array[2].should == '127.0.0.1'
array[3].should == '127.0.0.1'
array[4].should == Socket::AF_INET
- array[5].should be_kind_of(Integer)
- array[6].should be_kind_of(Integer)
+ array[5].should.is_a?(Integer)
+ array[6].should.is_a?(Integer)
end
it 'accepts an object responding to #to_str as the address family' do
@@ -215,8 +223,8 @@ describe 'Socket.getaddrinfo' do
array[2].should == '127.0.0.1'
array[3].should == '127.0.0.1'
array[4].should == Socket::AF_INET
- array[5].should be_kind_of(Integer)
- array[6].should be_kind_of(Integer)
+ array[5].should.is_a?(Integer)
+ array[6].should.is_a?(Integer)
end
it 'accepts an Integer as the socket type' do
@@ -229,7 +237,7 @@ describe 'Socket.getaddrinfo' do
Socket::AF_INET,
Socket::SOCK_STREAM,
]
- [0, Socket::IPPROTO_TCP].should include(proto)
+ [0, Socket::IPPROTO_TCP].should.include?(proto)
end
it 'accepts a Symbol as the socket type' do
@@ -242,7 +250,7 @@ describe 'Socket.getaddrinfo' do
Socket::AF_INET,
Socket::SOCK_STREAM,
]
- [0, Socket::IPPROTO_TCP].should include(proto)
+ [0, Socket::IPPROTO_TCP].should.include?(proto)
end
it 'accepts a String as the socket type' do
@@ -255,7 +263,7 @@ describe 'Socket.getaddrinfo' do
Socket::AF_INET,
Socket::SOCK_STREAM,
]
- [0, Socket::IPPROTO_TCP].should include(proto)
+ [0, Socket::IPPROTO_TCP].should.include?(proto)
end
it 'accepts an object responding to #to_str as the socket type' do
@@ -272,7 +280,7 @@ describe 'Socket.getaddrinfo' do
Socket::AF_INET,
Socket::SOCK_STREAM,
]
- [0, Socket::IPPROTO_TCP].should include(proto)
+ [0, Socket::IPPROTO_TCP].should.include?(proto)
end
platform_is_not :windows do
@@ -286,7 +294,7 @@ describe 'Socket.getaddrinfo' do
Socket::AF_INET,
Socket::SOCK_DGRAM,
]
- [0, Socket::IPPROTO_UDP].should include(proto)
+ [0, Socket::IPPROTO_UDP].should.include?(proto)
end
end
@@ -301,7 +309,7 @@ describe 'Socket.getaddrinfo' do
Socket::AF_INET,
Socket::SOCK_STREAM,
]
- [0, Socket::IPPROTO_TCP].should include(proto)
+ [0, Socket::IPPROTO_TCP].should.include?(proto)
end
it 'performs a reverse lookup when the reverse_lookup argument is true' do
@@ -311,7 +319,7 @@ describe 'Socket.getaddrinfo' do
addr[0].should == 'AF_INET'
addr[1].should == 21
- addr[2].should be_an_instance_of(String)
+ addr[2].should.instance_of?(String)
addr[2].should_not == addr[3]
addr[3].should == '127.0.0.1'
@@ -324,7 +332,7 @@ describe 'Socket.getaddrinfo' do
addr[0].should == 'AF_INET'
addr[1].should == 21
- addr[2].should be_an_instance_of(String)
+ addr[2].should.instance_of?(String)
addr[2].should_not == addr[3]
addr[3].should == '127.0.0.1'
@@ -341,7 +349,7 @@ describe 'Socket.getaddrinfo' do
Socket::AF_INET,
Socket::SOCK_STREAM,
]
- [0, Socket::IPPROTO_TCP].should include(proto)
+ [0, Socket::IPPROTO_TCP].should.include?(proto)
end
end
@@ -364,7 +372,7 @@ describe 'Socket.getaddrinfo' do
# We don't have control over this value and there's no way to test this
# without relying on Socket.getaddrinfo()'s own behaviour (meaning this
# test would faily any way of the method was not implemented correctly).
- addr[2].should be_an_instance_of(String)
+ addr[2].should.instance_of?(String)
addr[2].should_not == addr[3]
addr[3].should == '127.0.0.1'
diff --git a/spec/ruby/library/socket/socket/gethostbyaddr_spec.rb b/spec/ruby/library/socket/socket/gethostbyaddr_spec.rb
index 5d936046f5..bf6d63dbe9 100644
--- a/spec/ruby/library/socket/socket/gethostbyaddr_spec.rb
+++ b/spec/ruby/library/socket/socket/gethostbyaddr_spec.rb
@@ -10,7 +10,7 @@ describe 'Socket.gethostbyaddr' do
describe 'without an explicit address family' do
it 'returns an Array' do
- suppress_warning { Socket.gethostbyaddr(@addr) }.should be_an_instance_of(Array)
+ suppress_warning { Socket.gethostbyaddr(@addr) }.should.instance_of?(Array)
end
describe 'the returned Array' do
@@ -23,10 +23,10 @@ describe 'Socket.gethostbyaddr' do
end
it 'includes the aliases as the 2nd value' do
- @array[1].should be_an_instance_of(Array)
+ @array[1].should.instance_of?(Array)
@array[1].each do |val|
- val.should be_an_instance_of(String)
+ val.should.instance_of?(String)
end
end
@@ -38,7 +38,7 @@ describe 'Socket.gethostbyaddr' do
@array[3].should == @addr
@array[4..-1].each do |val|
- val.should be_an_instance_of(String)
+ val.should.instance_of?(String)
end
end
end
@@ -46,15 +46,15 @@ describe 'Socket.gethostbyaddr' do
describe 'with an explicit address family' do
it 'returns an Array when using an Integer as the address family' do
- suppress_warning { Socket.gethostbyaddr(@addr, Socket::AF_INET) }.should be_an_instance_of(Array)
+ suppress_warning { Socket.gethostbyaddr(@addr, Socket::AF_INET) }.should.instance_of?(Array)
end
it 'returns an Array when using a Symbol as the address family' do
- suppress_warning { Socket.gethostbyaddr(@addr, :INET) }.should be_an_instance_of(Array)
+ suppress_warning { Socket.gethostbyaddr(@addr, :INET) }.should.instance_of?(Array)
end
it 'raises SocketError when the address is not supported by the family' do
- -> { suppress_warning { Socket.gethostbyaddr(@addr, :INET6) } }.should raise_error(SocketError)
+ -> { suppress_warning { Socket.gethostbyaddr(@addr, :INET6) } }.should.raise(SocketError)
end
end
end
@@ -67,7 +67,7 @@ describe 'Socket.gethostbyaddr' do
describe 'without an explicit address family' do
it 'returns an Array' do
- suppress_warning { Socket.gethostbyaddr(@addr) }.should be_an_instance_of(Array)
+ suppress_warning { Socket.gethostbyaddr(@addr) }.should.instance_of?(Array)
end
describe 'the returned Array' do
@@ -80,10 +80,10 @@ describe 'Socket.gethostbyaddr' do
end
it 'includes the aliases as the 2nd value' do
- @array[1].should be_an_instance_of(Array)
+ @array[1].should.instance_of?(Array)
@array[1].each do |val|
- val.should be_an_instance_of(String)
+ val.should.instance_of?(String)
end
end
@@ -92,10 +92,10 @@ describe 'Socket.gethostbyaddr' do
end
it 'includes all address strings as the remaining values' do
- @array[3].should be_an_instance_of(String)
+ @array[3].should.instance_of?(String)
@array[4..-1].each do |val|
- val.should be_an_instance_of(String)
+ val.should.instance_of?(String)
end
end
end
@@ -103,16 +103,16 @@ describe 'Socket.gethostbyaddr' do
describe 'with an explicit address family' do
it 'returns an Array when using an Integer as the address family' do
- suppress_warning { Socket.gethostbyaddr(@addr, Socket::AF_INET6) }.should be_an_instance_of(Array)
+ suppress_warning { Socket.gethostbyaddr(@addr, Socket::AF_INET6) }.should.instance_of?(Array)
end
it 'returns an Array when using a Symbol as the address family' do
- suppress_warning { Socket.gethostbyaddr(@addr, :INET6) }.should be_an_instance_of(Array)
+ suppress_warning { Socket.gethostbyaddr(@addr, :INET6) }.should.instance_of?(Array)
end
platform_is_not :windows, :wsl do
it 'raises SocketError when the address is not supported by the family' do
- -> { suppress_warning { Socket.gethostbyaddr(@addr, :INET) } }.should raise_error(SocketError)
+ -> { suppress_warning { Socket.gethostbyaddr(@addr, :INET) } }.should.raise(SocketError)
end
end
end
diff --git a/spec/ruby/library/socket/socket/gethostbyname_spec.rb b/spec/ruby/library/socket/socket/gethostbyname_spec.rb
index 618ef85387..326fe26094 100644
--- a/spec/ruby/library/socket/socket/gethostbyname_spec.rb
+++ b/spec/ruby/library/socket/socket/gethostbyname_spec.rb
@@ -16,7 +16,7 @@ end
describe 'Socket.gethostbyname' do
it 'returns an Array' do
- suppress_warning { Socket.gethostbyname('127.0.0.1') }.should be_an_instance_of(Array)
+ suppress_warning { Socket.gethostbyname('127.0.0.1') }.should.instance_of?(Array)
end
describe 'the returned Array' do
@@ -29,10 +29,10 @@ describe 'Socket.gethostbyname' do
end
it 'includes the aliases as the 2nd value' do
- @array[1].should be_an_instance_of(Array)
+ @array[1].should.instance_of?(Array)
@array[1].each do |val|
- val.should be_an_instance_of(String)
+ val.should.instance_of?(String)
end
end
@@ -43,10 +43,10 @@ describe 'Socket.gethostbyname' do
end
it 'includes the address strings as the remaining values' do
- @array[3].should be_an_instance_of(String)
+ @array[3].should.instance_of?(String)
@array[4..-1].each do |val|
- val.should be_an_instance_of(String)
+ val.should.instance_of?(String)
end
end
end
diff --git a/spec/ruby/library/socket/socket/getifaddrs_spec.rb b/spec/ruby/library/socket/socket/getifaddrs_spec.rb
index 839854ea27..1b326605c8 100644
--- a/spec/ruby/library/socket/socket/getifaddrs_spec.rb
+++ b/spec/ruby/library/socket/socket/getifaddrs_spec.rb
@@ -7,17 +7,17 @@ describe 'Socket.getifaddrs' do
end
it 'returns an Array' do
- @ifaddrs.should be_an_instance_of(Array)
+ @ifaddrs.should.instance_of?(Array)
end
describe 'the returned Array' do
it 'should not be empty' do
- @ifaddrs.should_not be_empty
+ @ifaddrs.should_not.empty?
end
it 'contains instances of Socket::Ifaddr' do
@ifaddrs.each do |ifaddr|
- ifaddr.should be_an_instance_of(Socket::Ifaddr)
+ ifaddr.should.instance_of?(Socket::Ifaddr)
end
end
end
@@ -25,19 +25,19 @@ describe 'Socket.getifaddrs' do
describe 'each returned Socket::Ifaddr' do
it 'has an interface index' do
@ifaddrs.each do |ifaddr|
- ifaddr.ifindex.should be_kind_of(Integer)
+ ifaddr.ifindex.should.is_a?(Integer)
end
end
it 'has an interface name' do
@ifaddrs.each do |ifaddr|
- ifaddr.name.should be_an_instance_of(String)
+ ifaddr.name.should.instance_of?(String)
end
end
it 'has a set of flags' do
@ifaddrs.each do |ifaddr|
- ifaddr.flags.should be_kind_of(Integer)
+ ifaddr.flags.should.is_a?(Integer)
end
end
end
@@ -49,17 +49,17 @@ describe 'Socket.getifaddrs' do
it 'is an Addrinfo' do
@addrs.all? do |addr|
- addr.should be_an_instance_of(Addrinfo)
+ addr.should.instance_of?(Addrinfo)
true
- end.should be_true
+ end.should == true
end
it 'has an address family' do
@addrs.all? do |addr|
- addr.afamily.should be_kind_of(Integer)
+ addr.afamily.should.is_a?(Integer)
addr.afamily.should_not == Socket::AF_UNSPEC
true
- end.should be_true
+ end.should == true
end
end
@@ -71,17 +71,17 @@ describe 'Socket.getifaddrs' do
it 'is an Addrinfo' do
@addrs.all? do |addr|
- addr.should be_an_instance_of(Addrinfo)
+ addr.should.instance_of?(Addrinfo)
true
- end.should be_true
+ end.should == true
end
it 'has an address family' do
@addrs.all? do |addr|
- addr.afamily.should be_kind_of(Integer)
+ addr.afamily.should.is_a?(Integer)
addr.afamily.should_not == Socket::AF_UNSPEC
true
- end.should be_true
+ end.should == true
end
end
@@ -92,24 +92,24 @@ describe 'Socket.getifaddrs' do
it 'is an Addrinfo' do
@addrs.all? do |addr|
- addr.should be_an_instance_of(Addrinfo)
+ addr.should.instance_of?(Addrinfo)
true
- end.should be_true
+ end.should == true
end
it 'has an address family' do
@addrs.all? do |addr|
- addr.afamily.should be_kind_of(Integer)
+ addr.afamily.should.is_a?(Integer)
addr.afamily.should_not == Socket::AF_UNSPEC
true
- end.should be_true
+ end.should == true
end
it 'has an IP address' do
@addrs.all? do |addr|
- addr.ip_address.should be_an_instance_of(String)
+ addr.ip_address.should.instance_of?(String)
true
- end.should be_true
+ end.should == true
end
end
end
diff --git a/spec/ruby/library/socket/socket/getnameinfo_spec.rb b/spec/ruby/library/socket/socket/getnameinfo_spec.rb
index 4f13bf484d..d0b77004de 100644
--- a/spec/ruby/library/socket/socket/getnameinfo_spec.rb
+++ b/spec/ruby/library/socket/socket/getnameinfo_spec.rb
@@ -60,6 +60,14 @@ describe "Socket.getnameinfo" do
name_info = Socket.getnameinfo ["AF_INET", 9, 'foo', '127.0.0.1']
name_info[1].should == 'discard'
end
+
+ it "raises ResolutionError when fails to resolve address" do
+ -> {
+ Socket.getnameinfo(["AF_UNIX", 80, "0.0.0.0"])
+ }.should.raise(Socket::ResolutionError) { |e|
+ [Socket::EAI_FAMILY, Socket::EAI_FAIL].should.include?(e.error_code)
+ }
+ end
end
describe 'Socket.getnameinfo' do
@@ -69,7 +77,7 @@ describe 'Socket.getnameinfo' do
end
it 'raises SocketError or TypeError when using an invalid String' do
- -> { Socket.getnameinfo('cats') }.should raise_error(Exception) { |e|
+ -> { Socket.getnameinfo('cats') }.should.raise(Exception) { |e|
(e.is_a?(SocketError) || e.is_a?(TypeError)).should == true
}
end
@@ -102,7 +110,7 @@ describe 'Socket.getnameinfo' do
end
it 'raises ArgumentError when using an invalid Array' do
- -> { Socket.getnameinfo([family_name]) }.should raise_error(ArgumentError)
+ -> { Socket.getnameinfo([family_name]) }.should.raise(ArgumentError)
end
platform_is_not :windows do
@@ -122,7 +130,7 @@ describe 'Socket.getnameinfo' do
describe 'without custom flags' do
it 'returns an Array containing the hostname and service name' do
array = Socket.getnameinfo(@addr)
- array.should be_an_instance_of(Array)
+ array.should.instance_of?(Array)
array[0].should == @hostname
array[1].should == 'ftp'
end
@@ -131,7 +139,7 @@ describe 'Socket.getnameinfo' do
addr = [family_name, 21, ip_address, nil]
array = Socket.getnameinfo(addr)
- array.should be_an_instance_of(Array)
+ array.should.instance_of?(Array)
array[0].should == @hostname
array[1].should == 'ftp'
end
diff --git a/spec/ruby/library/socket/socket/getservbyname_spec.rb b/spec/ruby/library/socket/socket/getservbyname_spec.rb
index d361e619f2..4a88444fff 100644
--- a/spec/ruby/library/socket/socket/getservbyname_spec.rb
+++ b/spec/ruby/library/socket/socket/getservbyname_spec.rb
@@ -27,6 +27,6 @@ describe "Socket#getservbyname" do
end
it "raises a SocketError when the service or port is invalid" do
- -> { Socket.getservbyname('invalid') }.should raise_error(SocketError)
+ -> { Socket.getservbyname('invalid') }.should.raise(SocketError)
end
end
diff --git a/spec/ruby/library/socket/socket/getservbyport_spec.rb b/spec/ruby/library/socket/socket/getservbyport_spec.rb
index 563c592b54..7e4b75fa52 100644
--- a/spec/ruby/library/socket/socket/getservbyport_spec.rb
+++ b/spec/ruby/library/socket/socket/getservbyport_spec.rb
@@ -18,6 +18,6 @@ describe 'Socket.getservbyport' do
end
it 'raises SocketError for an unknown port number' do
- -> { Socket.getservbyport(0) }.should raise_error(SocketError)
+ -> { Socket.getservbyport(0) }.should.raise(SocketError)
end
end
diff --git a/spec/ruby/library/socket/socket/initialize_spec.rb b/spec/ruby/library/socket/socket/initialize_spec.rb
index f8337bcaa5..a8fb1c61fa 100644
--- a/spec/ruby/library/socket/socket/initialize_spec.rb
+++ b/spec/ruby/library/socket/socket/initialize_spec.rb
@@ -13,7 +13,7 @@ describe 'Socket#initialize' do
it 'returns a Socket' do
@socket = Socket.new(Socket::AF_INET, Socket::SOCK_STREAM)
- @socket.should be_an_instance_of(Socket)
+ @socket.should.instance_of?(Socket)
end
end
@@ -21,7 +21,7 @@ describe 'Socket#initialize' do
it 'returns a Socket' do
@socket = Socket.new(:INET, :STREAM)
- @socket.should be_an_instance_of(Socket)
+ @socket.should.instance_of?(Socket)
end
end
@@ -29,7 +29,7 @@ describe 'Socket#initialize' do
it 'returns a Socket' do
@socket = Socket.new('INET', 'STREAM')
- @socket.should be_an_instance_of(Socket)
+ @socket.should.instance_of?(Socket)
end
end
@@ -43,7 +43,7 @@ describe 'Socket#initialize' do
@socket = Socket.new(family, type)
- @socket.should be_an_instance_of(Socket)
+ @socket.should.instance_of?(Socket)
end
it 'raises TypeError when the #to_str method does not return a String' do
@@ -53,7 +53,7 @@ describe 'Socket#initialize' do
family.stub!(:to_str).and_return(Socket::AF_INET)
type.stub!(:to_str).and_return(Socket::SOCK_STREAM)
- -> { Socket.new(family, type) }.should raise_error(TypeError)
+ -> { Socket.new(family, type) }.should.raise(TypeError)
end
end
@@ -61,11 +61,11 @@ describe 'Socket#initialize' do
it 'returns a Socket when using an Integer' do
@socket = Socket.new(:INET, :STREAM, Socket::IPPROTO_TCP)
- @socket.should be_an_instance_of(Socket)
+ @socket.should.instance_of?(Socket)
end
it 'raises TypeError when using a Symbol' do
- -> { Socket.new(:INET, :STREAM, :TCP) }.should raise_error(TypeError)
+ -> { Socket.new(:INET, :STREAM, :TCP) }.should.raise(TypeError)
end
end
@@ -82,6 +82,6 @@ describe 'Socket#initialize' do
it "sets the socket to binary mode" do
@socket = Socket.new(:INET, :STREAM)
- @socket.binmode?.should be_true
+ @socket.binmode?.should == true
end
end
diff --git a/spec/ruby/library/socket/socket/ip_address_list_spec.rb b/spec/ruby/library/socket/socket/ip_address_list_spec.rb
index f97c2d7f85..2c4e008af1 100644
--- a/spec/ruby/library/socket/socket/ip_address_list_spec.rb
+++ b/spec/ruby/library/socket/socket/ip_address_list_spec.rb
@@ -2,7 +2,7 @@ require_relative '../spec_helper'
describe 'Socket.ip_address_list' do
it 'returns an Array' do
- Socket.ip_address_list.should be_an_instance_of(Array)
+ Socket.ip_address_list.should.instance_of?(Array)
end
describe 'the returned Array' do
@@ -11,12 +11,12 @@ describe 'Socket.ip_address_list' do
end
it 'is not empty' do
- @array.should_not be_empty
+ @array.should_not.empty?
end
it 'contains Addrinfo objects' do
@array.each do |klass|
- klass.should be_an_instance_of(Addrinfo)
+ klass.should.instance_of?(Addrinfo)
end
end
end
@@ -28,8 +28,8 @@ describe 'Socket.ip_address_list' do
it 'has a non-empty IP address' do
@array.each do |addr|
- addr.ip_address.should be_an_instance_of(String)
- addr.ip_address.should_not be_empty
+ addr.ip_address.should.instance_of?(String)
+ addr.ip_address.should_not.empty?
end
end
diff --git a/spec/ruby/library/socket/socket/listen_spec.rb b/spec/ruby/library/socket/socket/listen_spec.rb
index 4d2aedab19..7986a0225c 100644
--- a/spec/ruby/library/socket/socket/listen_spec.rb
+++ b/spec/ruby/library/socket/socket/listen_spec.rb
@@ -7,7 +7,7 @@ describe "Socket#listen" do
end
after :each do
- @socket.closed?.should be_false
+ @socket.closed?.should == false
@socket.close
end
@@ -35,7 +35,7 @@ describe 'Socket#listen' do
end
it 'raises Errno::EOPNOTSUPP or Errno::EACCES' do
- -> { @server.listen(1) }.should raise_error { |e|
+ -> { @server.listen(1) }.should.raise { |e|
[Errno::EOPNOTSUPP, Errno::EACCES].should.include?(e.class)
}
end
@@ -59,7 +59,7 @@ describe 'Socket#listen' do
end
it "raises when the given argument can't be coerced to an Integer" do
- -> { @server.listen('cats') }.should raise_error(TypeError)
+ -> { @server.listen('cats') }.should.raise(TypeError)
end
end
end
diff --git a/spec/ruby/library/socket/socket/local_address_spec.rb b/spec/ruby/library/socket/socket/local_address_spec.rb
index 3687f93a0c..86b053fc3e 100644
--- a/spec/ruby/library/socket/socket/local_address_spec.rb
+++ b/spec/ruby/library/socket/socket/local_address_spec.rb
@@ -10,7 +10,7 @@ describe 'Socket#local_address' do
end
it 'returns an Addrinfo' do
- @sock.local_address.should be_an_instance_of(Addrinfo)
+ @sock.local_address.should.instance_of?(Addrinfo)
end
describe 'the returned Addrinfo' do
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..17a737cacd 100644
--- a/spec/ruby/library/socket/socket/pack_sockaddr_in_spec.rb
+++ b/spec/ruby/library/socket/socket/pack_sockaddr_in_spec.rb
@@ -1,7 +1,7 @@
require_relative '../spec_helper'
-require_relative '../fixtures/classes'
-require_relative '../shared/pack_sockaddr'
describe "Socket.pack_sockaddr_in" do
- it_behaves_like :socket_pack_sockaddr_in, :pack_sockaddr_in
+ it "is an alias of Socket.sockaddr_in" do
+ Socket.method(:pack_sockaddr_in).should == Socket.method(:sockaddr_in)
+ end
end
diff --git a/spec/ruby/library/socket/socket/pack_sockaddr_un_spec.rb b/spec/ruby/library/socket/socket/pack_sockaddr_un_spec.rb
index 1ee0bc6157..34d4fc1f51 100644
--- a/spec/ruby/library/socket/socket/pack_sockaddr_un_spec.rb
+++ b/spec/ruby/library/socket/socket/pack_sockaddr_un_spec.rb
@@ -1,7 +1,7 @@
require_relative '../spec_helper'
-require_relative '../fixtures/classes'
-require_relative '../shared/pack_sockaddr'
-describe "Socket#pack_sockaddr_un" do
- it_behaves_like :socket_pack_sockaddr_un, :pack_sockaddr_un
+describe "Socket.pack_sockaddr_un" do
+ it "is an alias of Socket.sockaddr_un" do
+ Socket.method(:pack_sockaddr_un).should == Socket.method(:sockaddr_un)
+ end
end
diff --git a/spec/ruby/library/socket/socket/pair_spec.rb b/spec/ruby/library/socket/socket/pair_spec.rb
index 8dd470a95e..91317a8d07 100644
--- a/spec/ruby/library/socket/socket/pair_spec.rb
+++ b/spec/ruby/library/socket/socket/pair_spec.rb
@@ -1,7 +1,141 @@
require_relative '../spec_helper'
require_relative '../fixtures/classes'
-require_relative '../shared/socketpair'
describe "Socket.pair" do
- it_behaves_like :socket_socketpair, :pair
+ platform_is_not :windows do
+ it "ensures the returned sockets are connected" do
+ s1, s2 = Socket.pair(Socket::AF_UNIX, 1, 0)
+ s1.puts("test")
+ s2.gets.should == "test\n"
+ s1.close
+ s2.close
+ end
+
+ it "returns an array of two sockets" do
+ begin
+ s1, s2 = Socket.pair(:UNIX, :STREAM)
+
+ s1.should.instance_of?(Socket)
+ s2.should.instance_of?(Socket)
+ ensure
+ s1.close
+ s2.close
+ end
+ end
+
+ describe 'using an Integer as the 1st and 2nd argument' do
+ it 'returns two Socket objects' do
+ s1, s2 = Socket.pair(Socket::AF_UNIX, Socket::SOCK_STREAM)
+
+ s1.should.instance_of?(Socket)
+ s2.should.instance_of?(Socket)
+ s1.close
+ s2.close
+ end
+ end
+
+ describe 'using a Symbol as the 1st and 2nd argument' do
+ it 'returns two Socket objects' do
+ s1, s2 = Socket.pair(:UNIX, :STREAM)
+
+ s1.should.instance_of?(Socket)
+ s2.should.instance_of?(Socket)
+ s1.close
+ s2.close
+ end
+
+ it 'raises SocketError for an unknown address family' do
+ -> { Socket.pair(:CATS, :STREAM) }.should.raise(SocketError)
+ end
+
+ it 'raises SocketError for an unknown socket type' do
+ -> { Socket.pair(:UNIX, :CATS) }.should.raise(SocketError)
+ end
+ end
+
+ describe 'using a String as the 1st and 2nd argument' do
+ it 'returns two Socket objects' do
+ s1, s2 = Socket.pair('UNIX', 'STREAM')
+
+ s1.should.instance_of?(Socket)
+ s2.should.instance_of?(Socket)
+ s1.close
+ s2.close
+ end
+
+ it 'raises SocketError for an unknown address family' do
+ -> { Socket.pair('CATS', 'STREAM') }.should.raise(SocketError)
+ end
+
+ it 'raises SocketError for an unknown socket type' do
+ -> { Socket.pair('UNIX', 'CATS') }.should.raise(SocketError)
+ end
+ end
+
+ describe 'using an object that responds to #to_str as the 1st and 2nd argument' do
+ it 'returns two Socket objects' do
+ family = mock(:family)
+ type = mock(:type)
+
+ family.stub!(:to_str).and_return('UNIX')
+ type.stub!(:to_str).and_return('STREAM')
+
+ s1, s2 = Socket.pair(family, type)
+
+ s1.should.instance_of?(Socket)
+ s2.should.instance_of?(Socket)
+ s1.close
+ s2.close
+ end
+
+ it 'raises TypeError when #to_str does not return a String' do
+ family = mock(:family)
+ type = mock(:type)
+
+ family.stub!(:to_str).and_return(Socket::AF_UNIX)
+ type.stub!(:to_str).and_return(Socket::SOCK_STREAM)
+
+ -> { Socket.pair(family, type) }.should.raise(TypeError)
+ end
+
+ it 'raises SocketError for an unknown address family' do
+ family = mock(:family)
+ type = mock(:type)
+
+ family.stub!(:to_str).and_return('CATS')
+ type.stub!(:to_str).and_return('STREAM')
+
+ -> { Socket.pair(family, type) }.should.raise(SocketError)
+ end
+
+ it 'raises SocketError for an unknown socket type' do
+ family = mock(:family)
+ type = mock(:type)
+
+ family.stub!(:to_str).and_return('UNIX')
+ type.stub!(:to_str).and_return('CATS')
+
+ -> { Socket.pair(family, type) }.should.raise(SocketError)
+ end
+ end
+
+ it 'accepts a custom protocol as an Integer as the 3rd argument' do
+ s1, s2 = Socket.pair(:UNIX, :STREAM, Socket::IPPROTO_IP)
+ s1.should.instance_of?(Socket)
+ s2.should.instance_of?(Socket)
+ s1.close
+ s2.close
+ end
+
+ it 'connects the returned Socket objects' do
+ s1, s2 = Socket.pair(:UNIX, :STREAM)
+ begin
+ s1.write('hello')
+ s2.recv(5).should == 'hello'
+ ensure
+ s1.close
+ s2.close
+ end
+ end
+ end
end
diff --git a/spec/ruby/library/socket/socket/recvfrom_nonblock_spec.rb b/spec/ruby/library/socket/socket/recvfrom_nonblock_spec.rb
index 01b42bcc52..ab29435a1d 100644
--- a/spec/ruby/library/socket/socket/recvfrom_nonblock_spec.rb
+++ b/spec/ruby/library/socket/socket/recvfrom_nonblock_spec.rb
@@ -16,7 +16,7 @@ describe 'Socket#recvfrom_nonblock' do
platform_is_not :windows do
describe 'using an unbound socket' do
it 'raises IO::WaitReadable' do
- -> { @server.recvfrom_nonblock(1) }.should raise_error(IO::WaitReadable)
+ -> { @server.recvfrom_nonblock(1) }.should.raise(IO::WaitReadable)
end
end
end
@@ -29,7 +29,7 @@ describe 'Socket#recvfrom_nonblock' do
describe 'without any data available' do
it 'raises IO::WaitReadable' do
- -> { @server.recvfrom_nonblock(1) }.should raise_error(IO::WaitReadable)
+ -> { @server.recvfrom_nonblock(1) }.should.raise(IO::WaitReadable)
end
it 'returns :wait_readable with exception: false' do
@@ -47,7 +47,7 @@ describe 'Socket#recvfrom_nonblock' do
IO.select([@server])
ret = @server.recvfrom_nonblock(1)
- ret.should be_an_instance_of(Array)
+ ret.should.instance_of?(Array)
ret.length.should == 2
end
end
@@ -98,7 +98,7 @@ describe 'Socket#recvfrom_nonblock' do
end
it 'contains an Addrinfo at index 1' do
- @array[1].should be_an_instance_of(Addrinfo)
+ @array[1].should.instance_of?(Addrinfo)
end
end
@@ -158,61 +158,30 @@ describe 'Socket#recvfrom_nonblock' do
@client.close unless @client.closed?
end
- ruby_version_is ""..."3.3" do
- it "returns an empty String as received data on a closed stream socket" do
- ready = false
+ it "returns nil on a closed stream socket" do
+ ready = false
- t = Thread.new do
- client, _ = @server.accept
+ t = Thread.new do
+ client, _ = @server.accept
- Thread.pass while !ready
- begin
- client.recvfrom_nonblock(10)
- rescue IO::EAGAINWaitReadable
- retry
- end
- ensure
- client.close if client
+ Thread.pass while !ready
+ begin
+ client.recvfrom_nonblock(10)
+ rescue IO::EAGAINWaitReadable
+ retry
end
-
- Thread.pass while t.status and t.status != "sleep"
- t.status.should_not be_nil
-
- @client.connect(@server_addr)
- @client.close
- ready = true
-
- t.value.should.is_a? Array
- t.value[0].should == ""
+ ensure
+ client.close if client
end
- end
- ruby_version_is "3.3" do
- it "returns nil on a closed stream socket" do
- ready = false
+ Thread.pass while t.status and t.status != "sleep"
+ t.status.should_not == nil
- t = Thread.new do
- client, _ = @server.accept
+ @client.connect(@server_addr)
+ @client.close
+ ready = true
- Thread.pass while !ready
- begin
- client.recvfrom_nonblock(10)
- rescue IO::EAGAINWaitReadable
- retry
- end
- ensure
- client.close if client
- end
-
- Thread.pass while t.status and t.status != "sleep"
- t.status.should_not be_nil
-
- @client.connect(@server_addr)
- @client.close
- ready = true
-
- t.value.should be_nil
- end
+ t.value.should == nil
end
end
end
diff --git a/spec/ruby/library/socket/socket/recvfrom_spec.rb b/spec/ruby/library/socket/socket/recvfrom_spec.rb
index 6ba39ffcaf..0f319fc47c 100644
--- a/spec/ruby/library/socket/socket/recvfrom_spec.rb
+++ b/spec/ruby/library/socket/socket/recvfrom_spec.rb
@@ -39,7 +39,7 @@ describe 'Socket#recvfrom' do
it 'returns an Array containing the data and an Addrinfo' do
ret = @server.recvfrom(1)
- ret.should be_an_instance_of(Array)
+ ret.should.instance_of?(Array)
ret.length.should == 2
end
@@ -53,7 +53,7 @@ describe 'Socket#recvfrom' do
end
it 'contains an Addrinfo at index 1' do
- @array[1].should be_an_instance_of(Addrinfo)
+ @array[1].should.instance_of?(Addrinfo)
end
end
@@ -111,43 +111,21 @@ describe 'Socket#recvfrom' do
@client.close unless @client.closed?
end
- ruby_version_is ""..."3.3" do
- it "returns an empty String as received data on a closed stream socket" do
- t = Thread.new do
- client, _ = @server.accept
- client.recvfrom(10)
- ensure
- client.close if client
- end
-
- Thread.pass while t.status and t.status != "sleep"
- t.status.should_not be_nil
-
- @client.connect(@server_addr)
- @client.close
-
- t.value.should.is_a? Array
- t.value[0].should == ""
+ it "returns nil on a closed stream socket" do
+ t = Thread.new do
+ client, _ = @server.accept
+ client.recvfrom(10)
+ ensure
+ client.close if client
end
- end
-
- ruby_version_is "3.3" do
- it "returns nil on a closed stream socket" do
- t = Thread.new do
- client, _ = @server.accept
- client.recvfrom(10)
- ensure
- client.close if client
- end
- Thread.pass while t.status and t.status != "sleep"
- t.status.should_not be_nil
+ Thread.pass while t.status and t.status != "sleep"
+ t.status.should_not == nil
- @client.connect(@server_addr)
- @client.close
+ @client.connect(@server_addr)
+ @client.close
- t.value.should be_nil
- end
+ t.value.should == nil
end
end
diff --git a/spec/ruby/library/socket/socket/remote_address_spec.rb b/spec/ruby/library/socket/socket/remote_address_spec.rb
index 24d60d7f58..f72ec50ed7 100644
--- a/spec/ruby/library/socket/socket/remote_address_spec.rb
+++ b/spec/ruby/library/socket/socket/remote_address_spec.rb
@@ -22,7 +22,7 @@ describe 'Socket#remote_address' do
end
it 'returns an Addrinfo' do
- @client.remote_address.should be_an_instance_of(Addrinfo)
+ @client.remote_address.should.instance_of?(Addrinfo)
end
describe 'the returned Addrinfo' do
diff --git a/spec/ruby/library/socket/socket/sockaddr_in_spec.rb b/spec/ruby/library/socket/socket/sockaddr_in_spec.rb
index 8ee956ac26..9d3367cd69 100644
--- a/spec/ruby/library/socket/socket/sockaddr_in_spec.rb
+++ b/spec/ruby/library/socket/socket/sockaddr_in_spec.rb
@@ -1,7 +1,49 @@
require_relative '../spec_helper'
require_relative '../fixtures/classes'
-require_relative '../shared/pack_sockaddr'
-describe "Socket#sockaddr_in" do
- it_behaves_like :socket_pack_sockaddr_in, :sockaddr_in
+describe "Socket.sockaddr_in" do
+ it "packs and unpacks" do
+ sockaddr_in = Socket.sockaddr_in(0, nil)
+ port, addr = Socket.unpack_sockaddr_in(sockaddr_in)
+ ["127.0.0.1", "::1"].include?(addr).should == true
+ port.should == 0
+
+ sockaddr_in = Socket.sockaddr_in(0, '')
+ Socket.unpack_sockaddr_in(sockaddr_in).should == [0, '0.0.0.0']
+
+ sockaddr_in = Socket.sockaddr_in(80, '127.0.0.1')
+ Socket.unpack_sockaddr_in(sockaddr_in).should == [80, '127.0.0.1']
+
+ sockaddr_in = Socket.sockaddr_in('80', '127.0.0.1')
+ Socket.unpack_sockaddr_in(sockaddr_in).should == [80, '127.0.0.1']
+
+ sockaddr_in = Socket.sockaddr_in(nil, '127.0.0.1')
+ Socket.unpack_sockaddr_in(sockaddr_in).should == [0, '127.0.0.1']
+
+ sockaddr_in = Socket.sockaddr_in(80, Socket::INADDR_ANY)
+ Socket.unpack_sockaddr_in(sockaddr_in).should == [80, '0.0.0.0']
+ end
+
+ it 'resolves the service name to a port' do
+ sockaddr_in = Socket.sockaddr_in('http', '127.0.0.1')
+ Socket.unpack_sockaddr_in(sockaddr_in).should == [80, '127.0.0.1']
+ end
+
+ describe 'using an IPv4 address' do
+ it 'returns a String of 16 bytes' do
+ str = Socket.sockaddr_in(80, '127.0.0.1')
+
+ str.should.instance_of?(String)
+ str.bytesize.should == 16
+ end
+ end
+
+ describe 'using an IPv6 address' do
+ it 'returns a String of 28 bytes' do
+ str = Socket.sockaddr_in(80, '::1')
+
+ str.should.instance_of?(String)
+ str.bytesize.should == 28
+ end
+ end
end
diff --git a/spec/ruby/library/socket/socket/sockaddr_un_spec.rb b/spec/ruby/library/socket/socket/sockaddr_un_spec.rb
index 8922ff4d6d..548dc526ff 100644
--- a/spec/ruby/library/socket/socket/sockaddr_un_spec.rb
+++ b/spec/ruby/library/socket/socket/sockaddr_un_spec.rb
@@ -1,7 +1,47 @@
require_relative '../spec_helper'
require_relative '../fixtures/classes'
-require_relative '../shared/pack_sockaddr'
-describe "Socket#sockaddr_un" do
- it_behaves_like :socket_pack_sockaddr_un, :sockaddr_un
+describe "Socket.sockaddr_un" do
+ it 'should be idempotent' do
+ bytes = Socket.sockaddr_un('/tmp/foo').bytes
+ bytes[2..9].should == [47, 116, 109, 112, 47, 102, 111, 111]
+ bytes[10..-1].all?(&:zero?).should == true
+ end
+
+ it "packs and unpacks" do
+ sockaddr_un = Socket.sockaddr_un('/tmp/s')
+ Socket.unpack_sockaddr_un(sockaddr_un).should == '/tmp/s'
+ end
+
+ it "handles correctly paths with multibyte chars" do
+ sockaddr_un = Socket.sockaddr_un('/home/ваÑÑ/sock')
+ path = Socket.unpack_sockaddr_un(sockaddr_un).encode('UTF-8', 'UTF-8')
+ path.should == '/home/ваÑÑ/sock'
+ end
+
+ platform_is :linux do
+ it 'returns a String of 110 bytes' do
+ str = Socket.sockaddr_un('/tmp/test.sock')
+
+ str.should.instance_of?(String)
+ str.bytesize.should == 110
+ end
+ end
+
+ platform_is :bsd do
+ it 'returns a String of 106 bytes' do
+ str = Socket.sockaddr_un('/tmp/test.sock')
+
+ str.should.instance_of?(String)
+ str.bytesize.should == 106
+ end
+ end
+
+ platform_is_not :aix do
+ it "raises ArgumentError for paths that are too long" do
+ # AIX doesn't raise error
+ long_path = 'a' * 110
+ -> { Socket.sockaddr_un(long_path) }.should.raise(ArgumentError)
+ end
+ end
end
diff --git a/spec/ruby/library/socket/socket/socketpair_spec.rb b/spec/ruby/library/socket/socket/socketpair_spec.rb
index 551c376d49..191fb358cf 100644
--- a/spec/ruby/library/socket/socket/socketpair_spec.rb
+++ b/spec/ruby/library/socket/socket/socketpair_spec.rb
@@ -1,7 +1,7 @@
require_relative '../spec_helper'
-require_relative '../fixtures/classes'
-require_relative '../shared/socketpair'
describe "Socket.socketpair" do
- it_behaves_like :socket_socketpair, :socketpair
+ it "is an alias of Socket.pair" do
+ Socket.method(:socketpair).should == Socket.method(:pair)
+ end
end
diff --git a/spec/ruby/library/socket/socket/sysaccept_spec.rb b/spec/ruby/library/socket/socket/sysaccept_spec.rb
index 92ac21124e..3e7078f745 100644
--- a/spec/ruby/library/socket/socket/sysaccept_spec.rb
+++ b/spec/ruby/library/socket/socket/sysaccept_spec.rb
@@ -15,7 +15,7 @@ describe 'Socket#sysaccept' do
platform_is :linux do # hangs on other platforms
describe 'using an unbound socket' do
it 'raises Errno::EINVAL' do
- -> { @server.sysaccept }.should raise_error(Errno::EINVAL)
+ -> { @server.sysaccept }.should.raise(Errno::EINVAL)
end
end
@@ -25,7 +25,7 @@ describe 'Socket#sysaccept' do
end
it 'raises Errno::EINVAL' do
- -> { @server.sysaccept }.should raise_error(Errno::EINVAL)
+ -> { @server.sysaccept }.should.raise(Errno::EINVAL)
end
end
end
@@ -59,7 +59,7 @@ describe 'Socket#sysaccept' do
@client.connect(@server_addr)
- thread.value.should be_an_instance_of(Array)
+ thread.value.should.instance_of?(Array)
end
end
@@ -76,8 +76,8 @@ describe 'Socket#sysaccept' do
it 'returns an Array containing an Integer and an Addrinfo' do
@fd, addrinfo = @server.sysaccept
- @fd.should be_kind_of(Integer)
- addrinfo.should be_an_instance_of(Addrinfo)
+ @fd.should.is_a?(Integer)
+ addrinfo.should.instance_of?(Addrinfo)
end
it 'returns a new file descriptor' do
diff --git a/spec/ruby/library/socket/socket/tcp_server_loop_spec.rb b/spec/ruby/library/socket/socket/tcp_server_loop_spec.rb
index a46c6df5c6..4e39d01d72 100644
--- a/spec/ruby/library/socket/socket/tcp_server_loop_spec.rb
+++ b/spec/ruby/library/socket/socket/tcp_server_loop_spec.rb
@@ -47,8 +47,8 @@ describe 'Socket.tcp_server_loop' do
# complete.
thread.join
- @sock.should be_an_instance_of(Socket)
- addr.should be_an_instance_of(Addrinfo)
+ @sock.should.instance_of?(Socket)
+ addr.should.instance_of?(Addrinfo)
end
end
end
diff --git a/spec/ruby/library/socket/socket/tcp_server_sockets_spec.rb b/spec/ruby/library/socket/socket/tcp_server_sockets_spec.rb
index bd496d3015..b6cdb3c583 100644
--- a/spec/ruby/library/socket/socket/tcp_server_sockets_spec.rb
+++ b/spec/ruby/library/socket/socket/tcp_server_sockets_spec.rb
@@ -13,16 +13,16 @@ describe 'Socket.tcp_server_sockets' do
it 'returns an Array of Socket objects' do
@sockets = Socket.tcp_server_sockets(0)
- @sockets.should be_an_instance_of(Array)
- @sockets[0].should be_an_instance_of(Socket)
+ @sockets.should.instance_of?(Array)
+ @sockets[0].should.instance_of?(Socket)
end
end
describe 'with a block' do
it 'yields the sockets to the supplied block' do
Socket.tcp_server_sockets(0) do |sockets|
- sockets.should be_an_instance_of(Array)
- sockets[0].should be_an_instance_of(Socket)
+ sockets.should.instance_of?(Array)
+ sockets[0].should.instance_of?(Socket)
end
end
diff --git a/spec/ruby/library/socket/socket/tcp_spec.rb b/spec/ruby/library/socket/socket/tcp_spec.rb
index faf020b1ea..cc3c9381c7 100644
--- a/spec/ruby/library/socket/socket/tcp_spec.rb
+++ b/spec/ruby/library/socket/socket/tcp_spec.rb
@@ -22,12 +22,12 @@ describe 'Socket.tcp' do
it 'returns a Socket when no block is given' do
@client = Socket.tcp(@host, @port)
- @client.should be_an_instance_of(Socket)
+ @client.should.instance_of?(Socket)
end
it 'yields the Socket when a block is given' do
Socket.tcp(@host, @port) do |socket|
- socket.should be_an_instance_of(Socket)
+ socket.should.instance_of?(Socket)
end
end
@@ -51,20 +51,38 @@ describe 'Socket.tcp' do
it 'raises ArgumentError when 6 arguments are provided' do
-> {
Socket.tcp(@host, @port, @host, 0, {:connect_timeout => 1}, 10)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
it 'connects to the server' do
@client = Socket.tcp(@host, @port)
-
@client.write('hello')
-
connection, _ = @server.accept
-
begin
connection.recv(5).should == 'hello'
ensure
connection.close
end
end
+
+ ruby_version_is "4.0" do
+ it 'connects to the server when passed open_timeout argument' do
+ @client = Socket.tcp(@host, @port, open_timeout: 60)
+ @client.write('open_timeout')
+ connection, _ = @server.accept
+ begin
+ connection.recv(12).should == 'open_timeout'
+ ensure
+ connection.close
+ end
+ end
+
+ it 'raises Errno::ETIMEDOUT with :open_timeout when no server is listening on the given address' do
+ -> {
+ Socket.tcp("192.0.2.1", 80, open_timeout: 0)
+ }.should.raise(Errno::ETIMEDOUT)
+ rescue Errno::ENETUNREACH
+ skip "all network interfaces down"
+ end
+ end
end
diff --git a/spec/ruby/library/socket/socket/udp_server_loop_on_spec.rb b/spec/ruby/library/socket/socket/udp_server_loop_on_spec.rb
index cb8c5c5587..9197509f1f 100644
--- a/spec/ruby/library/socket/socket/udp_server_loop_on_spec.rb
+++ b/spec/ruby/library/socket/socket/udp_server_loop_on_spec.rb
@@ -41,7 +41,7 @@ describe 'Socket.udp_server_loop_on' do
end
msg.should == 'hello'
- src.should be_an_instance_of(Socket::UDPSource)
+ src.should.instance_of?(Socket::UDPSource)
end
end
end
diff --git a/spec/ruby/library/socket/socket/udp_server_loop_spec.rb b/spec/ruby/library/socket/socket/udp_server_loop_spec.rb
index cd22ea56cf..d44d522c20 100644
--- a/spec/ruby/library/socket/socket/udp_server_loop_spec.rb
+++ b/spec/ruby/library/socket/socket/udp_server_loop_spec.rb
@@ -53,7 +53,7 @@ describe 'Socket.udp_server_loop' do
thread.join
msg.should == 'hello'
- src.should be_an_instance_of(Socket::UDPSource)
+ src.should.instance_of?(Socket::UDPSource)
end
end
end
diff --git a/spec/ruby/library/socket/socket/udp_server_recv_spec.rb b/spec/ruby/library/socket/socket/udp_server_recv_spec.rb
index 47ed74bc03..34e2280558 100644
--- a/spec/ruby/library/socket/socket/udp_server_recv_spec.rb
+++ b/spec/ruby/library/socket/socket/udp_server_recv_spec.rb
@@ -30,6 +30,6 @@ describe 'Socket.udp_server_recv' do
end
msg.should == 'hello'
- src.should be_an_instance_of(Socket::UDPSource)
+ src.should.instance_of?(Socket::UDPSource)
end
end
diff --git a/spec/ruby/library/socket/socket/udp_server_sockets_spec.rb b/spec/ruby/library/socket/socket/udp_server_sockets_spec.rb
index f8be672612..cb357977d6 100644
--- a/spec/ruby/library/socket/socket/udp_server_sockets_spec.rb
+++ b/spec/ruby/library/socket/socket/udp_server_sockets_spec.rb
@@ -13,16 +13,16 @@ describe 'Socket.udp_server_sockets' do
it 'returns an Array of Socket objects' do
@sockets = Socket.udp_server_sockets(0)
- @sockets.should be_an_instance_of(Array)
- @sockets[0].should be_an_instance_of(Socket)
+ @sockets.should.instance_of?(Array)
+ @sockets[0].should.instance_of?(Socket)
end
end
describe 'with a block' do
it 'yields the sockets to the supplied block' do
Socket.udp_server_sockets(0) do |sockets|
- sockets.should be_an_instance_of(Array)
- sockets[0].should be_an_instance_of(Socket)
+ sockets.should.instance_of?(Array)
+ sockets[0].should.instance_of?(Socket)
end
end
diff --git a/spec/ruby/library/socket/socket/unix_server_loop_spec.rb b/spec/ruby/library/socket/socket/unix_server_loop_spec.rb
index 0f34d4a50b..9d35a995bc 100644
--- a/spec/ruby/library/socket/socket/unix_server_loop_spec.rb
+++ b/spec/ruby/library/socket/socket/unix_server_loop_spec.rb
@@ -1,58 +1,56 @@
require_relative '../spec_helper'
require_relative '../fixtures/classes'
-with_feature :unix_socket do
- describe 'Socket.unix_server_loop' do
- before do
- @path = SocketSpecs.socket_path
- end
+describe 'Socket.unix_server_loop' do
+ before do
+ @path = SocketSpecs.socket_path
+ end
- after do
- rm_r(@path) if File.file?(@path)
- end
+ after do
+ rm_r(@path) if File.file?(@path)
+ end
- describe 'when no connections are available' do
- it 'blocks the caller' do
- -> { Socket.unix_server_loop(@path) }.should block_caller
- end
+ describe 'when no connections are available' do
+ it 'blocks the caller' do
+ -> { Socket.unix_server_loop(@path) }.should block_caller
end
+ end
- describe 'when a connection is available' do
- before do
- @client = nil
- end
+ describe 'when a connection is available' do
+ before do
+ @client = nil
+ end
- after do
- @sock.close if @sock
- @client.close if @client
- end
+ after do
+ @sock.close if @sock
+ @client.close if @client
+ end
- it 'yields a Socket and an Addrinfo' do
- @sock, addr = nil
+ it 'yields a Socket and an Addrinfo' do
+ @sock, addr = nil
- thread = Thread.new do
- Socket.unix_server_loop(@path) do |socket, addrinfo|
- @sock = socket
- addr = addrinfo
+ thread = Thread.new do
+ Socket.unix_server_loop(@path) do |socket, addrinfo|
+ @sock = socket
+ addr = addrinfo
- break
- end
+ break
end
+ end
- SocketSpecs.loop_with_timeout do
- begin
- @client = Socket.unix(@path)
- rescue SystemCallError
- sleep 0.01
- :retry
- end
+ SocketSpecs.loop_with_timeout do
+ begin
+ @client = Socket.unix(@path)
+ rescue SystemCallError
+ sleep 0.01
+ :retry
end
+ end
- thread.join
+ thread.join
- @sock.should be_an_instance_of(Socket)
- addr.should be_an_instance_of(Addrinfo)
- end
+ @sock.should.instance_of?(Socket)
+ addr.should.instance_of?(Addrinfo)
end
end
end
diff --git a/spec/ruby/library/socket/socket/unix_server_socket_spec.rb b/spec/ruby/library/socket/socket/unix_server_socket_spec.rb
index fc357740fa..da9671bf8c 100644
--- a/spec/ruby/library/socket/socket/unix_server_socket_spec.rb
+++ b/spec/ruby/library/socket/socket/unix_server_socket_spec.rb
@@ -1,48 +1,46 @@
require_relative '../spec_helper'
require_relative '../fixtures/classes'
-with_feature :unix_socket do
- describe 'Socket.unix_server_socket' do
+describe 'Socket.unix_server_socket' do
+ before do
+ @path = SocketSpecs.socket_path
+ end
+
+ after do
+ rm_r(@path)
+ end
+
+ describe 'when no block is given' do
before do
- @path = SocketSpecs.socket_path
+ @socket = nil
end
after do
- rm_r(@path)
+ @socket.close
end
- describe 'when no block is given' do
- before do
- @socket = nil
- end
-
- after do
- @socket.close
- end
+ it 'returns a Socket' do
+ @socket = Socket.unix_server_socket(@path)
- it 'returns a Socket' do
- @socket = Socket.unix_server_socket(@path)
-
- @socket.should be_an_instance_of(Socket)
- end
+ @socket.should.instance_of?(Socket)
end
+ end
- describe 'when a block is given' do
- it 'yields a Socket' do
- Socket.unix_server_socket(@path) do |sock|
- sock.should be_an_instance_of(Socket)
- end
+ describe 'when a block is given' do
+ it 'yields a Socket' do
+ Socket.unix_server_socket(@path) do |sock|
+ sock.should.instance_of?(Socket)
end
+ end
- it 'closes the Socket when the block returns' do
- socket = nil
-
- Socket.unix_server_socket(@path) do |sock|
- socket = sock
- end
+ it 'closes the Socket when the block returns' do
+ socket = nil
- socket.should be_an_instance_of(Socket)
+ Socket.unix_server_socket(@path) do |sock|
+ socket = sock
end
+
+ socket.should.instance_of?(Socket)
end
end
end
diff --git a/spec/ruby/library/socket/socket/unix_spec.rb b/spec/ruby/library/socket/socket/unix_spec.rb
index 4bff59bd4b..87f4938871 100644
--- a/spec/ruby/library/socket/socket/unix_spec.rb
+++ b/spec/ruby/library/socket/socket/unix_spec.rb
@@ -1,45 +1,43 @@
require_relative '../spec_helper'
require_relative '../fixtures/classes'
-with_feature :unix_socket do
- describe 'Socket.unix' do
- before do
- @path = SocketSpecs.socket_path
- @server = UNIXServer.new(@path)
- @socket = nil
- end
+describe 'Socket.unix' do
+ before do
+ @path = SocketSpecs.socket_path
+ @server = UNIXServer.new(@path)
+ @socket = nil
+ end
- after do
- @server.close
- @socket.close if @socket
+ after do
+ @server.close
+ @socket.close if @socket
- rm_r(@path)
- end
+ rm_r(@path)
+ end
- describe 'when no block is given' do
- it 'returns a Socket' do
- @socket = Socket.unix(@path)
+ describe 'when no block is given' do
+ it 'returns a Socket' do
+ @socket = Socket.unix(@path)
- @socket.should be_an_instance_of(Socket)
- end
+ @socket.should.instance_of?(Socket)
end
+ end
- describe 'when a block is given' do
- it 'yields a Socket' do
- Socket.unix(@path) do |sock|
- sock.should be_an_instance_of(Socket)
- end
+ describe 'when a block is given' do
+ it 'yields a Socket' do
+ Socket.unix(@path) do |sock|
+ sock.should.instance_of?(Socket)
end
+ end
- it 'closes the Socket when the block returns' do
- socket = nil
-
- Socket.unix(@path) do |sock|
- socket = sock
- end
+ it 'closes the Socket when the block returns' do
+ socket = nil
- socket.should.closed?
+ Socket.unix(@path) do |sock|
+ socket = sock
end
+
+ socket.should.closed?
end
end
end
diff --git a/spec/ruby/library/socket/socket/unpack_sockaddr_in_spec.rb b/spec/ruby/library/socket/socket/unpack_sockaddr_in_spec.rb
index 79ec68cd18..35d46b0fd0 100644
--- a/spec/ruby/library/socket/socket/unpack_sockaddr_in_spec.rb
+++ b/spec/ruby/library/socket/socket/unpack_sockaddr_in_spec.rb
@@ -32,15 +32,13 @@ describe "Socket.unpack_sockaddr_in" do
end
end
- with_feature :unix_socket do
- it "raises an ArgumentError when the sin_family is not AF_INET" do
- sockaddr = Socket.sockaddr_un '/tmp/x'
- -> { Socket.unpack_sockaddr_in sockaddr }.should raise_error(ArgumentError)
- end
+ it "raises an ArgumentError when the sin_family is not AF_INET" do
+ sockaddr = Socket.sockaddr_un '/tmp/x'
+ -> { Socket.unpack_sockaddr_in sockaddr }.should.raise(ArgumentError)
+ end
- it "raises an ArgumentError when passed addrinfo is not AF_INET/AF_INET6" do
- addrinfo = Addrinfo.unix('/tmp/sock')
- -> { Socket.unpack_sockaddr_in(addrinfo) }.should raise_error(ArgumentError)
- end
+ it "raises an ArgumentError when passed addrinfo is not AF_INET/AF_INET6" do
+ addrinfo = Addrinfo.unix('/tmp/sock')
+ -> { Socket.unpack_sockaddr_in(addrinfo) }.should.raise(ArgumentError)
end
end
diff --git a/spec/ruby/library/socket/socket/unpack_sockaddr_un_spec.rb b/spec/ruby/library/socket/socket/unpack_sockaddr_un_spec.rb
index 12f970f89b..85a941cfc2 100644
--- a/spec/ruby/library/socket/socket/unpack_sockaddr_un_spec.rb
+++ b/spec/ruby/library/socket/socket/unpack_sockaddr_un_spec.rb
@@ -1,26 +1,24 @@
require_relative '../spec_helper'
require_relative '../fixtures/classes'
-with_feature :unix_socket do
- describe 'Socket.unpack_sockaddr_un' do
- it 'decodes sockaddr to unix path' do
- sockaddr = Socket.sockaddr_un('/tmp/sock')
- Socket.unpack_sockaddr_un(sockaddr).should == '/tmp/sock'
- end
+describe 'Socket.unpack_sockaddr_un' do
+ it 'decodes sockaddr to unix path' do
+ sockaddr = Socket.sockaddr_un('/tmp/sock')
+ Socket.unpack_sockaddr_un(sockaddr).should == '/tmp/sock'
+ end
- it 'returns unix path from a passed Addrinfo' do
- addrinfo = Addrinfo.unix('/tmp/sock')
- Socket.unpack_sockaddr_un(addrinfo).should == '/tmp/sock'
- end
+ it 'returns unix path from a passed Addrinfo' do
+ addrinfo = Addrinfo.unix('/tmp/sock')
+ Socket.unpack_sockaddr_un(addrinfo).should == '/tmp/sock'
+ end
- it 'raises an ArgumentError when the sa_family is not AF_UNIX' do
- sockaddr = Socket.sockaddr_in(0, '127.0.0.1')
- -> { Socket.unpack_sockaddr_un(sockaddr) }.should raise_error(ArgumentError)
- end
+ it 'raises an ArgumentError when the sa_family is not AF_UNIX' do
+ sockaddr = Socket.sockaddr_in(0, '127.0.0.1')
+ -> { Socket.unpack_sockaddr_un(sockaddr) }.should.raise(ArgumentError)
+ end
- it 'raises an ArgumentError when passed addrinfo is not AF_UNIX' do
- addrinfo = Addrinfo.tcp('127.0.0.1', 0)
- -> { Socket.unpack_sockaddr_un(addrinfo) }.should raise_error(ArgumentError)
- end
+ it 'raises an ArgumentError when passed addrinfo is not AF_UNIX' do
+ addrinfo = Addrinfo.tcp('127.0.0.1', 0)
+ -> { Socket.unpack_sockaddr_un(addrinfo) }.should.raise(ArgumentError)
end
end
diff --git a/spec/ruby/library/socket/spec_helper.rb b/spec/ruby/library/socket/spec_helper.rb
index 1121542dd5..86f3a61086 100644
--- a/spec/ruby/library/socket/spec_helper.rb
+++ b/spec/ruby/library/socket/spec_helper.rb
@@ -1,13 +1,14 @@
require_relative '../../spec_helper'
require 'socket'
-MSpec.enable_feature :sock_packet if Socket.const_defined?(:SOCK_PACKET)
-MSpec.enable_feature :unix_socket unless PlatformGuard.windows?
-MSpec.enable_feature :udp_cork if Socket.const_defined?(:UDP_CORK)
-MSpec.enable_feature :tcp_cork if Socket.const_defined?(:TCP_CORK)
-MSpec.enable_feature :pktinfo if Socket.const_defined?(:IP_PKTINFO)
-MSpec.enable_feature :ipv6_pktinfo if Socket.const_defined?(:IPV6_PKTINFO)
-MSpec.enable_feature :ip_mtu if Socket.const_defined?(:IP_MTU)
-MSpec.enable_feature :ipv6_nexthop if Socket.const_defined?(:IPV6_NEXTHOP)
-MSpec.enable_feature :tcp_info if Socket.const_defined?(:TCP_INFO)
-MSpec.enable_feature :ancillary_data if Socket.const_defined?(:AncillaryData)
+# We force enable all features on Linux because anyway Linux implements all these features,
+# and we want a constant number of spec examples across Ruby implementations, even if they don't define these constants.
+MSpec.enable_feature :sock_packet if platform_is(:linux) || Socket.const_defined?(:SOCK_PACKET)
+MSpec.enable_feature :udp_cork if platform_is(:linux) || Socket.const_defined?(:UDP_CORK)
+MSpec.enable_feature :tcp_cork if platform_is(:linux) || Socket.const_defined?(:TCP_CORK)
+MSpec.enable_feature :pktinfo if platform_is(:linux) || Socket.const_defined?(:IP_PKTINFO)
+MSpec.enable_feature :ipv6_pktinfo if platform_is(:linux) || Socket.const_defined?(:IPV6_PKTINFO)
+MSpec.enable_feature :ip_mtu if platform_is(:linux) || Socket.const_defined?(:IP_MTU)
+MSpec.enable_feature :ipv6_nexthop if platform_is(:linux) || Socket.const_defined?(:IPV6_NEXTHOP)
+MSpec.enable_feature :tcp_info if platform_is(:linux) || Socket.const_defined?(:TCP_INFO)
+MSpec.enable_feature :ancillary_data if platform_is(:linux) || Socket.const_defined?(:AncillaryData)
diff --git a/spec/ruby/library/socket/tcpserver/accept_nonblock_spec.rb b/spec/ruby/library/socket/tcpserver/accept_nonblock_spec.rb
index 91f6a327f0..ac08fe37c6 100644
--- a/spec/ruby/library/socket/tcpserver/accept_nonblock_spec.rb
+++ b/spec/ruby/library/socket/tcpserver/accept_nonblock_spec.rb
@@ -15,7 +15,7 @@ describe "Socket::TCPServer.accept_nonblock" do
@server.listen(5)
-> {
@server.accept_nonblock
- }.should raise_error(IO::WaitReadable)
+ }.should.raise(IO::WaitReadable)
c = TCPSocket.new("127.0.0.1", @port)
IO.select([@server])
@@ -25,7 +25,7 @@ describe "Socket::TCPServer.accept_nonblock" do
port.should == @port
address.should == "127.0.0.1"
- s.should be_kind_of(TCPSocket)
+ s.should.is_a?(TCPSocket)
c.close
s.close
@@ -33,12 +33,12 @@ describe "Socket::TCPServer.accept_nonblock" do
it "raises an IOError if the socket is closed" do
@server.close
- -> { @server.accept }.should raise_error(IOError)
+ -> { @server.accept }.should.raise(IOError)
end
describe 'without a connected client' do
it 'raises error' do
- -> { @server.accept_nonblock }.should raise_error(IO::WaitReadable)
+ -> { @server.accept_nonblock }.should.raise(IO::WaitReadable)
end
it 'returns :wait_readable in exceptionless mode' do
@@ -59,7 +59,7 @@ describe 'TCPServer#accept_nonblock' do
describe 'without a connected client' do
it 'raises IO::WaitReadable' do
- -> { @server.accept_nonblock }.should raise_error(IO::WaitReadable)
+ -> { @server.accept_nonblock }.should.raise(IO::WaitReadable)
end
end
@@ -77,7 +77,7 @@ describe 'TCPServer#accept_nonblock' do
it 'returns a TCPSocket' do
IO.select([@server])
@socket = @server.accept_nonblock
- @socket.should be_an_instance_of(TCPSocket)
+ @socket.should.instance_of?(TCPSocket)
end
end
end
diff --git a/spec/ruby/library/socket/tcpserver/accept_spec.rb b/spec/ruby/library/socket/tcpserver/accept_spec.rb
index d8892cd5f0..f2aa0bf8e1 100644
--- a/spec/ruby/library/socket/tcpserver/accept_spec.rb
+++ b/spec/ruby/library/socket/tcpserver/accept_spec.rb
@@ -15,7 +15,7 @@ describe "TCPServer#accept" do
data = nil
t = Thread.new do
client = @server.accept
- client.should be_kind_of(TCPSocket)
+ client.should.is_a?(TCPSocket)
data = client.read(5)
client << "goodbye"
client.close
@@ -50,7 +50,7 @@ describe "TCPServer#accept" do
t = Thread.new {
-> {
@server.accept
- }.should raise_error(Exception, "interrupted")
+ }.should.raise(Exception, "interrupted")
}
Thread.pass while t.status and t.status != "sleep"
@@ -80,7 +80,7 @@ describe "TCPServer#accept" do
it "raises an IOError if the socket is closed" do
@server.close
- -> { @server.accept }.should raise_error(IOError)
+ -> { @server.accept }.should.raise(IOError)
end
end
@@ -112,7 +112,7 @@ describe 'TCPServer#accept' do
it 'returns a TCPSocket' do
@socket = @server.accept
- @socket.should be_an_instance_of(TCPSocket)
+ @socket.should.instance_of?(TCPSocket)
end
platform_is_not :windows do
diff --git a/spec/ruby/library/socket/tcpserver/gets_spec.rb b/spec/ruby/library/socket/tcpserver/gets_spec.rb
index 417976d737..72a72fa2dc 100644
--- a/spec/ruby/library/socket/tcpserver/gets_spec.rb
+++ b/spec/ruby/library/socket/tcpserver/gets_spec.rb
@@ -11,6 +11,6 @@ describe "TCPServer#gets" do
end
it "raises Errno::ENOTCONN on gets" do
- -> { @server.gets }.should raise_error(Errno::ENOTCONN)
+ -> { @server.gets }.should.raise(Errno::ENOTCONN)
end
end
diff --git a/spec/ruby/library/socket/tcpserver/initialize_spec.rb b/spec/ruby/library/socket/tcpserver/initialize_spec.rb
index 4ddd1f465f..517b014edc 100644
--- a/spec/ruby/library/socket/tcpserver/initialize_spec.rb
+++ b/spec/ruby/library/socket/tcpserver/initialize_spec.rb
@@ -12,7 +12,7 @@ describe 'TCPServer#initialize' do
end
it 'sets the port to the given argument' do
- @server.local_address.ip_port.should be_kind_of(Integer)
+ @server.local_address.ip_port.should.is_a?(Integer)
@server.local_address.ip_port.should > 0
end
@@ -24,7 +24,7 @@ describe 'TCPServer#initialize' do
end
it "sets the socket to binmode" do
- @server.binmode?.should be_true
+ @server.binmode?.should == true
end
end
@@ -38,7 +38,7 @@ describe 'TCPServer#initialize' do
end
it 'sets the port to the given argument' do
- @server.local_address.ip_port.should be_kind_of(Integer)
+ @server.local_address.ip_port.should.is_a?(Integer)
@server.local_address.ip_port.should > 0
end
@@ -52,7 +52,7 @@ describe 'TCPServer#initialize' do
describe 'with a single String argument containing a non numeric value' do
it 'raises SocketError' do
- -> { TCPServer.new('cats') }.should raise_error(SocketError)
+ -> { TCPServer.new('cats') }.should.raise(SocketError)
end
end
@@ -67,7 +67,7 @@ describe 'TCPServer#initialize' do
end
it 'sets the port to the given port argument' do
- @server.local_address.ip_port.should be_kind_of(Integer)
+ @server.local_address.ip_port.should.is_a?(Integer)
@server.local_address.ip_port.should > 0
end
@@ -90,7 +90,7 @@ describe 'TCPServer#initialize' do
end
it 'sets the port to the given port argument' do
- @server.local_address.ip_port.should be_kind_of(Integer)
+ @server.local_address.ip_port.should.is_a?(Integer)
@server.local_address.ip_port.should > 0
end
diff --git a/spec/ruby/library/socket/tcpserver/listen_spec.rb b/spec/ruby/library/socket/tcpserver/listen_spec.rb
index c877fdced6..5b046ef6f7 100644
--- a/spec/ruby/library/socket/tcpserver/listen_spec.rb
+++ b/spec/ruby/library/socket/tcpserver/listen_spec.rb
@@ -16,7 +16,7 @@ describe 'TCPServer#listen' do
end
it "raises when the given argument can't be coerced to an Integer" do
- -> { @server.listen('cats') }.should raise_error(TypeError)
+ -> { @server.listen('cats') }.should.raise(TypeError)
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..70b8d4352e 100644
--- a/spec/ruby/library/socket/tcpserver/new_spec.rb
+++ b/spec/ruby/library/socket/tcpserver/new_spec.rb
@@ -10,7 +10,7 @@ describe "TCPServer.new" do
@server = TCPServer.new('127.0.0.1', 0)
addr = @server.addr
addr[0].should == 'AF_INET'
- addr[1].should be_kind_of(Integer)
+ addr[1].should.is_a?(Integer)
# on some platforms (Mac), MRI
# returns comma at the end.
addr[2].should =~ /^#{SocketSpecs.hostname}\b/
@@ -20,7 +20,7 @@ describe "TCPServer.new" do
it "binds to localhost and a port with either IPv4 or IPv6" do
@server = TCPServer.new(SocketSpecs.hostname, 0)
addr = @server.addr
- addr[1].should be_kind_of(Integer)
+ addr[1].should.is_a?(Integer)
if addr[0] == 'AF_INET'
addr[2].should =~ /^#{SocketSpecs.hostname}\b/
addr[3].should == '127.0.0.1'
@@ -34,7 +34,7 @@ describe "TCPServer.new" do
@server = TCPServer.new('', 0)
addr = @server.addr
addr[0].should == 'AF_INET'
- addr[1].should be_kind_of(Integer)
+ addr[1].should.is_a?(Integer)
addr[2].should == '0.0.0.0'
addr[3].should == '0.0.0.0'
end
@@ -43,7 +43,7 @@ describe "TCPServer.new" do
@server = TCPServer.new('', '0')
addr = @server.addr
addr[0].should == 'AF_INET'
- addr[1].should be_kind_of(Integer)
+ addr[1].should.is_a?(Integer)
addr[2].should == '0.0.0.0'
addr[3].should == '0.0.0.0'
end
@@ -52,7 +52,7 @@ describe "TCPServer.new" do
@server = TCPServer.new('', nil)
addr = @server.addr
addr[0].should == 'AF_INET'
- addr[1].should be_kind_of(Integer)
+ addr[1].should.is_a?(Integer)
addr[2].should == '0.0.0.0'
addr[3].should == '0.0.0.0'
end
@@ -61,20 +61,20 @@ describe "TCPServer.new" do
@server = TCPServer.new('', '')
addr = @server.addr
addr[0].should == 'AF_INET'
- addr[1].should be_kind_of(Integer)
+ addr[1].should.is_a?(Integer)
addr[2].should == '0.0.0.0'
addr[3].should == '0.0.0.0'
end
it "coerces port to string, then determines port from that number or service name" do
- -> { TCPServer.new(SocketSpecs.hostname, Object.new) }.should raise_error(TypeError)
+ -> { TCPServer.new(SocketSpecs.hostname, Object.new) }.should.raise(TypeError)
port = Object.new
port.should_receive(:to_str).and_return("0")
@server = TCPServer.new(SocketSpecs.hostname, port)
addr = @server.addr
- addr[1].should be_kind_of(Integer)
+ addr[1].should.is_a?(Integer)
# TODO: This should also accept strings like 'https', but I don't know how to
# pick such a service port that will be able to reliably bind...
@@ -83,18 +83,18 @@ describe "TCPServer.new" do
it "has a single argument form and treats it as a port number" do
@server = TCPServer.new(0)
addr = @server.addr
- addr[1].should be_kind_of(Integer)
+ addr[1].should.is_a?(Integer)
end
it "coerces port to a string when it is the only argument" do
- -> { TCPServer.new(Object.new) }.should raise_error(TypeError)
+ -> { TCPServer.new(Object.new) }.should.raise(TypeError)
port = Object.new
port.should_receive(:to_str).and_return("0")
@server = TCPServer.new(port)
addr = @server.addr
- addr[1].should be_kind_of(Integer)
+ addr[1].should.is_a?(Integer)
end
it "does not use the given block and warns to use TCPServer::open" do
@@ -104,7 +104,7 @@ describe "TCPServer.new" do
end
it "raises Errno::EADDRNOTAVAIL when the address is unknown" do
- -> { TCPServer.new("1.2.3.4", 0) }.should raise_error(Errno::EADDRNOTAVAIL)
+ -> { TCPServer.new("1.2.3.4", 0) }.should.raise(Errno::EADDRNOTAVAIL)
end
# There is no way to make this fail-proof on all machines, because
@@ -114,7 +114,7 @@ describe "TCPServer.new" do
it "raises a SocketError when the host is unknown" do
-> {
TCPServer.new("--notavalidname", 0)
- }.should raise_error(SocketError)
+ }.should.raise(SocketError)
end
end
@@ -122,7 +122,7 @@ describe "TCPServer.new" do
@server = TCPServer.new('127.0.0.1', 0)
-> {
@server = TCPServer.new('127.0.0.1', @server.addr[1])
- }.should raise_error(Errno::EADDRINUSE)
+ }.should.raise(Errno::EADDRINUSE)
end
platform_is_not :windows, :aix do
diff --git a/spec/ruby/library/socket/tcpserver/sysaccept_spec.rb b/spec/ruby/library/socket/tcpserver/sysaccept_spec.rb
index bd7d33faf4..ed23bced23 100644
--- a/spec/ruby/library/socket/tcpserver/sysaccept_spec.rb
+++ b/spec/ruby/library/socket/tcpserver/sysaccept_spec.rb
@@ -21,7 +21,7 @@ describe "TCPServer#sysaccept" do
fd = @server.sysaccept
- fd.should be_kind_of(Integer)
+ fd.should.is_a?(Integer)
ensure
sock.close if sock && !sock.closed?
IO.for_fd(fd).close if fd
@@ -58,7 +58,7 @@ describe 'TCPServer#sysaccept' do
it 'returns a new file descriptor as an Integer' do
@fd = @server.sysaccept
- @fd.should be_kind_of(Integer)
+ @fd.should.is_a?(Integer)
@fd.should_not == @client.fileno
end
end
diff --git a/spec/ruby/library/socket/tcpsocket/gethostbyname_spec.rb b/spec/ruby/library/socket/tcpsocket/gethostbyname_spec.rb
index 5a2c704f35..c6fe007827 100644
--- a/spec/ruby/library/socket/tcpsocket/gethostbyname_spec.rb
+++ b/spec/ruby/library/socket/tcpsocket/gethostbyname_spec.rb
@@ -10,7 +10,7 @@ describe "TCPSocket.gethostbyname" do
end
it "returns an array elements of information on the hostname" do
- @host_info.should be_kind_of(Array)
+ @host_info.should.is_a?(Array)
end
platform_is_not :windows do
@@ -20,12 +20,12 @@ describe "TCPSocket.gethostbyname" do
it "returns the address type as the third value" do
address_type = @host_info[2]
- [Socket::AF_INET, Socket::AF_INET6].include?(address_type).should be_true
+ [Socket::AF_INET, Socket::AF_INET6].include?(address_type).should == true
end
it "returns the IP address as the fourth value" do
ip = @host_info[3]
- ["127.0.0.1", "::1"].include?(ip).should be_true
+ ["127.0.0.1", "::1"].include?(ip).should == true
end
end
@@ -48,14 +48,14 @@ describe "TCPSocket.gethostbyname" do
end
it "returns any aliases to the address as second value" do
- @host_info[1].should be_kind_of(Array)
+ @host_info[1].should.is_a?(Array)
end
end
describe 'TCPSocket.gethostbyname' do
it 'returns an Array' do
suppress_warning do
- TCPSocket.gethostbyname('127.0.0.1').should be_an_instance_of(Array)
+ TCPSocket.gethostbyname('127.0.0.1').should.instance_of?(Array)
end
end
@@ -72,11 +72,11 @@ describe 'TCPSocket.gethostbyname' do
end
it 'includes an array of alternative hostnames as the 2nd value' do
- @array[1].should be_an_instance_of(Array)
+ @array[1].should.instance_of?(Array)
end
it 'includes the address family as the 3rd value' do
- @array[2].should be_kind_of(Integer)
+ @array[2].should.is_a?(Integer)
end
it 'includes the IP addresses as all the remaining values' do
diff --git a/spec/ruby/library/socket/tcpsocket/initialize_spec.rb b/spec/ruby/library/socket/tcpsocket/initialize_spec.rb
index d7feb9751b..a33d0b16ba 100644
--- a/spec/ruby/library/socket/tcpsocket/initialize_spec.rb
+++ b/spec/ruby/library/socket/tcpsocket/initialize_spec.rb
@@ -31,7 +31,7 @@ describe 'TCPSocket#initialize' do
SocketSpecs.each_ip_protocol do |family, ip_address|
describe 'when no server is listening on the given address' do
it 'raises Errno::ECONNREFUSED' do
- -> { TCPSocket.new(ip_address, 666) }.should raise_error(Errno::ECONNREFUSED)
+ -> { TCPSocket.new(ip_address, 666) }.should.raise(Errno::ECONNREFUSED)
end
end
@@ -48,21 +48,21 @@ describe 'TCPSocket#initialize' do
it 'returns a TCPSocket when using an Integer as the port' do
@client = TCPSocket.new(ip_address, @port)
- @client.should be_an_instance_of(TCPSocket)
+ @client.should.instance_of?(TCPSocket)
end
it 'returns a TCPSocket when using a String as the port' do
@client = TCPSocket.new(ip_address, @port.to_s)
- @client.should be_an_instance_of(TCPSocket)
+ @client.should.instance_of?(TCPSocket)
end
it 'raises SocketError when the port number is a non numeric String' do
- -> { TCPSocket.new(ip_address, 'cats') }.should raise_error(SocketError)
+ -> { TCPSocket.new(ip_address, 'cats') }.should.raise(SocketError)
end
it 'set the socket to binmode' do
@client = TCPSocket.new(ip_address, @port)
- @client.binmode?.should be_true
+ @client.binmode?.should == true
end
it 'connects to the right address' do
diff --git a/spec/ruby/library/socket/tcpsocket/local_address_spec.rb b/spec/ruby/library/socket/tcpsocket/local_address_spec.rb
index ce66d5ff8f..5dcf741f29 100644
--- a/spec/ruby/library/socket/tcpsocket/local_address_spec.rb
+++ b/spec/ruby/library/socket/tcpsocket/local_address_spec.rb
@@ -23,7 +23,7 @@ describe 'TCPSocket#local_address' do
end
it 'returns an Addrinfo' do
- @sock.local_address.should be_an_instance_of(Addrinfo)
+ @sock.local_address.should.instance_of?(Addrinfo)
end
describe 'the returned Addrinfo' do
diff --git a/spec/ruby/library/socket/tcpsocket/remote_address_spec.rb b/spec/ruby/library/socket/tcpsocket/remote_address_spec.rb
index eb9dabc075..085d57b3f9 100644
--- a/spec/ruby/library/socket/tcpsocket/remote_address_spec.rb
+++ b/spec/ruby/library/socket/tcpsocket/remote_address_spec.rb
@@ -23,7 +23,7 @@ describe 'TCPSocket#remote_address' do
end
it 'returns an Addrinfo' do
- @sock.remote_address.should be_an_instance_of(Addrinfo)
+ @sock.remote_address.should.instance_of?(Addrinfo)
end
describe 'the returned Addrinfo' do
diff --git a/spec/ruby/library/socket/tcpsocket/shared/new.rb b/spec/ruby/library/socket/tcpsocket/shared/new.rb
index 5280eb7900..9c15dced4f 100644
--- a/spec/ruby/library/socket/tcpsocket/shared/new.rb
+++ b/spec/ruby/library/socket/tcpsocket/shared/new.rb
@@ -3,24 +3,33 @@ require_relative '../../fixtures/classes'
describe :tcpsocket_new, shared: true do
it "requires a hostname and a port as arguments" do
- -> { TCPSocket.send(@method) }.should raise_error(ArgumentError)
+ -> { TCPSocket.send(@method) }.should.raise(ArgumentError)
end
it "refuses the connection when there is no server to connect to" do
-> do
TCPSocket.send(@method, SocketSpecs.hostname, SocketSpecs.reserved_unused_port)
- end.should raise_error(SystemCallError) {|e|
- [Errno::ECONNREFUSED, Errno::EADDRNOTAVAIL].should include(e.class)
+ end.should.raise(SystemCallError) {|e|
+ [Errno::ECONNREFUSED, Errno::EADDRNOTAVAIL].should.include?(e.class)
}
end
it 'raises IO::TimeoutError 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(IO::TimeoutError)
+ }.should.raise(IO::TimeoutError)
rescue Errno::ENETUNREACH
- # In the case all network interfaces down.
- # raise_error cannot deal with multiple expected exceptions
+ skip "all network interfaces down"
+ end
+
+ ruby_version_is "4.0" do
+ it 'raises IO::TimeoutError with :open_timeout when no server is listening on the given address' do
+ -> {
+ TCPSocket.send(@method, "192.0.2.1", 80, open_timeout: 0)
+ }.should.raise(IO::TimeoutError)
+ rescue Errno::ENETUNREACH
+ skip "all network interfaces down"
+ end
end
describe "with a running server" do
@@ -39,34 +48,43 @@ describe :tcpsocket_new, shared: true do
it "silently ignores 'nil' as the third parameter" do
@socket = TCPSocket.send(@method, @hostname, @server.port, nil)
- @socket.should be_an_instance_of(TCPSocket)
+ @socket.should.instance_of?(TCPSocket)
end
it "connects to a listening server with host and port" do
@socket = TCPSocket.send(@method, @hostname, @server.port)
- @socket.should be_an_instance_of(TCPSocket)
+ @socket.should.instance_of?(TCPSocket)
end
it "connects to a server when passed local_host argument" do
@socket = TCPSocket.send(@method, @hostname, @server.port, @hostname)
- @socket.should be_an_instance_of(TCPSocket)
+ @socket.should.instance_of?(TCPSocket)
end
it "connects to a server when passed local_host and local_port arguments" do
- server = TCPServer.new(SocketSpecs.hostname, 0)
+ retries = 0
+ max_retries = 3
+
begin
- available_port = server.addr[1]
- ensure
- server.close
+ retries += 1
+ server = TCPServer.new(SocketSpecs.hostname, 0)
+ begin
+ available_port = server.addr[1]
+ ensure
+ server.close
+ end
+ @socket = TCPSocket.send(@method, @hostname, @server.port,
+ @hostname, available_port)
+ rescue Errno::EADDRINUSE
+ raise if retries >= max_retries
+ retry
end
- @socket = TCPSocket.send(@method, @hostname, @server.port,
- @hostname, available_port)
- @socket.should be_an_instance_of(TCPSocket)
+ @socket.should.instance_of?(TCPSocket)
end
it "has an address once it has connected to a listening server" do
@socket = TCPSocket.send(@method, @hostname, @server.port)
- @socket.should be_an_instance_of(TCPSocket)
+ @socket.should.instance_of?(TCPSocket)
# TODO: Figure out how to abstract this. You can get AF_INET
# from 'Socket.getaddrinfo(hostname, nil)[0][3]' but socket.addr
@@ -81,13 +99,20 @@ describe :tcpsocket_new, shared: true do
@socket.addr[3].should == SocketSpecs.addr(:ipv6)
end
- @socket.addr[1].should be_kind_of(Integer)
+ @socket.addr[1].should.is_a?(Integer)
@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)
+ @socket.should.instance_of?(TCPSocket)
+ end
+
+ ruby_version_is "4.0" do
+ it "connects to a server when passed open_timeout argument" do
+ @socket = TCPSocket.send(@method, @hostname, @server.port, open_timeout: 1)
+ @socket.should.instance_of?(TCPSocket)
+ end
end
end
end
diff --git a/spec/ruby/library/socket/udpsocket/bind_spec.rb b/spec/ruby/library/socket/udpsocket/bind_spec.rb
index 08b386e941..974e701e71 100644
--- a/spec/ruby/library/socket/udpsocket/bind_spec.rb
+++ b/spec/ruby/library/socket/udpsocket/bind_spec.rb
@@ -12,7 +12,7 @@ describe "UDPSocket#bind" do
it "binds the socket to a port" do
@socket.bind(SocketSpecs.hostname, 0)
- @socket.addr[1].should be_kind_of(Integer)
+ @socket.addr[1].should.is_a?(Integer)
end
it "raises Errno::EINVAL when already bound" do
@@ -20,7 +20,7 @@ describe "UDPSocket#bind" do
-> {
@socket.bind(SocketSpecs.hostname, @socket.addr[1])
- }.should raise_error(Errno::EINVAL)
+ }.should.raise(Errno::EINVAL)
end
it "receives a hostname and a port" do
diff --git a/spec/ruby/library/socket/udpsocket/initialize_spec.rb b/spec/ruby/library/socket/udpsocket/initialize_spec.rb
index ecf0043c10..c040187400 100644
--- a/spec/ruby/library/socket/udpsocket/initialize_spec.rb
+++ b/spec/ruby/library/socket/udpsocket/initialize_spec.rb
@@ -7,27 +7,27 @@ describe 'UDPSocket#initialize' do
it 'initializes a new UDPSocket' do
@socket = UDPSocket.new
- @socket.should be_an_instance_of(UDPSocket)
+ @socket.should.instance_of?(UDPSocket)
end
it 'initializes a new UDPSocket using an Integer' do
@socket = UDPSocket.new(Socket::AF_INET)
- @socket.should be_an_instance_of(UDPSocket)
+ @socket.should.instance_of?(UDPSocket)
end
it 'initializes a new UDPSocket using a Symbol' do
@socket = UDPSocket.new(:INET)
- @socket.should be_an_instance_of(UDPSocket)
+ @socket.should.instance_of?(UDPSocket)
end
it 'initializes a new UDPSocket using a String' do
@socket = UDPSocket.new('INET')
- @socket.should be_an_instance_of(UDPSocket)
+ @socket.should.instance_of?(UDPSocket)
end
it 'sets the socket to binmode' do
@socket = UDPSocket.new(:INET)
- @socket.binmode?.should be_true
+ @socket.binmode?.should == true
end
platform_is_not :windows do
@@ -46,8 +46,8 @@ describe 'UDPSocket#initialize' do
it 'raises Errno::EAFNOSUPPORT or Errno::EPROTONOSUPPORT when given an invalid address family' do
-> {
UDPSocket.new(666)
- }.should raise_error(SystemCallError) { |e|
- [Errno::EAFNOSUPPORT, Errno::EPROTONOSUPPORT].should include(e.class)
+ }.should.raise(SystemCallError) { |e|
+ [Errno::EAFNOSUPPORT, Errno::EPROTONOSUPPORT].should.include?(e.class)
}
end
end
diff --git a/spec/ruby/library/socket/udpsocket/inspect_spec.rb b/spec/ruby/library/socket/udpsocket/inspect_spec.rb
deleted file mode 100644
index e212120b14..0000000000
--- a/spec/ruby/library/socket/udpsocket/inspect_spec.rb
+++ /dev/null
@@ -1,17 +0,0 @@
-require_relative '../spec_helper'
-
-describe 'UDPSocket#inspect' do
- before do
- @socket = UDPSocket.new
- @socket.bind('127.0.0.1', 0)
- end
-
- after do
- @socket.close
- end
-
- it 'returns a String with the fd, family, address and port' do
- port = @socket.addr[1]
- @socket.inspect.should == "#<UDPSocket:fd #{@socket.fileno}, AF_INET, 127.0.0.1, #{port}>"
- end
-end
diff --git a/spec/ruby/library/socket/udpsocket/local_address_spec.rb b/spec/ruby/library/socket/udpsocket/local_address_spec.rb
index 92e4cc10c7..868d2f537e 100644
--- a/spec/ruby/library/socket/udpsocket/local_address_spec.rb
+++ b/spec/ruby/library/socket/udpsocket/local_address_spec.rb
@@ -28,7 +28,7 @@ describe 'UDPSocket#local_address' do
end
it 'returns an Addrinfo' do
- @sock.local_address.should be_an_instance_of(Addrinfo)
+ @sock.local_address.should.instance_of?(Addrinfo)
end
describe 'the returned Addrinfo' do
diff --git a/spec/ruby/library/socket/udpsocket/new_spec.rb b/spec/ruby/library/socket/udpsocket/new_spec.rb
index 79bfcb624d..aff111927c 100644
--- a/spec/ruby/library/socket/udpsocket/new_spec.rb
+++ b/spec/ruby/library/socket/udpsocket/new_spec.rb
@@ -8,22 +8,22 @@ describe 'UDPSocket.new' do
it 'without arguments' do
@socket = UDPSocket.new
- @socket.should be_an_instance_of(UDPSocket)
+ @socket.should.instance_of?(UDPSocket)
end
it 'using Integer argument' do
@socket = UDPSocket.new(Socket::AF_INET)
- @socket.should be_an_instance_of(UDPSocket)
+ @socket.should.instance_of?(UDPSocket)
end
it 'using Symbol argument' do
@socket = UDPSocket.new(:INET)
- @socket.should be_an_instance_of(UDPSocket)
+ @socket.should.instance_of?(UDPSocket)
end
it 'using String argument' do
@socket = UDPSocket.new('INET')
- @socket.should be_an_instance_of(UDPSocket)
+ @socket.should.instance_of?(UDPSocket)
end
it "does not use the given block and warns to use UDPSocket::open" do
@@ -33,8 +33,8 @@ describe 'UDPSocket.new' do
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)
+ -> { UDPSocket.new(-1) }.should.raise(SystemCallError) { |e|
+ [Errno::EAFNOSUPPORT, Errno::EPROTONOSUPPORT].should.include?(e.class)
}
end
end
diff --git a/spec/ruby/library/socket/udpsocket/open_spec.rb b/spec/ruby/library/socket/udpsocket/open_spec.rb
index e4dbb2ee2a..7c77855372 100644
--- a/spec/ruby/library/socket/udpsocket/open_spec.rb
+++ b/spec/ruby/library/socket/udpsocket/open_spec.rb
@@ -8,6 +8,6 @@ describe "UDPSocket.open" do
it "allows calls to open without arguments" do
@socket = UDPSocket.open
- @socket.should be_kind_of(UDPSocket)
+ @socket.should.is_a?(UDPSocket)
end
end
diff --git a/spec/ruby/library/socket/udpsocket/recvfrom_nonblock_spec.rb b/spec/ruby/library/socket/udpsocket/recvfrom_nonblock_spec.rb
index b804099589..460cf2c9a2 100644
--- a/spec/ruby/library/socket/udpsocket/recvfrom_nonblock_spec.rb
+++ b/spec/ruby/library/socket/udpsocket/recvfrom_nonblock_spec.rb
@@ -16,7 +16,7 @@ describe 'UDPSocket#recvfrom_nonblock' do
platform_is_not :windows do
describe 'using an unbound socket' do
it 'raises IO::WaitReadable' do
- -> { @server.recvfrom_nonblock(1) }.should raise_error(IO::WaitReadable)
+ -> { @server.recvfrom_nonblock(1) }.should.raise(IO::WaitReadable)
end
end
end
@@ -32,7 +32,7 @@ describe 'UDPSocket#recvfrom_nonblock' do
describe 'without any data available' do
it 'raises IO::WaitReadable' do
- -> { @server.recvfrom_nonblock(1) }.should raise_error(IO::WaitReadable)
+ -> { @server.recvfrom_nonblock(1) }.should.raise(IO::WaitReadable)
end
it 'returns :wait_readable with exception: false' do
@@ -48,7 +48,7 @@ describe 'UDPSocket#recvfrom_nonblock' do
it 'returns an Array containing the data and an Array' do
IO.select([@server])
- @server.recvfrom_nonblock(1).should be_an_instance_of(Array)
+ @server.recvfrom_nonblock(1).should.instance_of?(Array)
end
it 'writes the data to the buffer when one is present' do
@@ -78,7 +78,7 @@ describe 'UDPSocket#recvfrom_nonblock' do
end
it 'contains an Array at index 1' do
- @array[1].should be_an_instance_of(Array)
+ @array[1].should.instance_of?(Array)
end
end
diff --git a/spec/ruby/library/socket/udpsocket/remote_address_spec.rb b/spec/ruby/library/socket/udpsocket/remote_address_spec.rb
index 94889ce560..d1310200fc 100644
--- a/spec/ruby/library/socket/udpsocket/remote_address_spec.rb
+++ b/spec/ruby/library/socket/udpsocket/remote_address_spec.rb
@@ -28,7 +28,7 @@ describe 'UDPSocket#remote_address' do
end
it 'returns an Addrinfo' do
- @sock.remote_address.should be_an_instance_of(Addrinfo)
+ @sock.remote_address.should.instance_of?(Addrinfo)
end
describe 'the returned Addrinfo' do
diff --git a/spec/ruby/library/socket/udpsocket/send_spec.rb b/spec/ruby/library/socket/udpsocket/send_spec.rb
index 6dd5f67bea..63f5b0dcc6 100644
--- a/spec/ruby/library/socket/udpsocket/send_spec.rb
+++ b/spec/ruby/library/socket/udpsocket/send_spec.rb
@@ -34,7 +34,7 @@ describe "UDPSocket#send" do
@msg[0].should == "ad hoc"
@msg[1][0].should == "AF_INET"
- @msg[1][1].should be_kind_of(Integer)
+ @msg[1][1].should.is_a?(Integer)
@msg[1][3].should == "127.0.0.1"
end
@@ -46,7 +46,7 @@ describe "UDPSocket#send" do
@msg[0].should == "ad hoc"
@msg[1][0].should == "AF_INET"
- @msg[1][1].should be_kind_of(Integer)
+ @msg[1][1].should.is_a?(Integer)
@msg[1][3].should == "127.0.0.1"
end
@@ -59,7 +59,7 @@ describe "UDPSocket#send" do
@msg[0].should == "connection-based"
@msg[1][0].should == "AF_INET"
- @msg[1][1].should be_kind_of(Integer)
+ @msg[1][1].should.is_a?(Integer)
@msg[1][3].should == "127.0.0.1"
end
@@ -68,7 +68,7 @@ describe "UDPSocket#send" do
begin
-> do
@socket.send('1' * 100_000, 0, SocketSpecs.hostname, @port.to_s)
- end.should raise_error(Errno::EMSGSIZE)
+ end.should.raise(Errno::EMSGSIZE)
ensure
@socket.send("ad hoc", 0, SocketSpecs.hostname, @port)
@socket.close
@@ -96,7 +96,7 @@ describe 'UDPSocket#send' do
describe 'using a disconnected socket' do
describe 'without a destination address' do
it "raises #{SocketSpecs.dest_addr_req_error}" do
- -> { @client.send('hello', 0) }.should raise_error(SocketSpecs.dest_addr_req_error)
+ -> { @client.send('hello', 0) }.should.raise(SocketSpecs.dest_addr_req_error)
end
end
@@ -108,7 +108,7 @@ describe 'UDPSocket#send' do
it 'does not persist the connection after sending data' do
@client.send('hello', 0, @addr.ip_address, @addr.ip_port)
- -> { @client.send('hello', 0) }.should raise_error(SocketSpecs.dest_addr_req_error)
+ -> { @client.send('hello', 0) }.should.raise(SocketSpecs.dest_addr_req_error)
end
end
diff --git a/spec/ruby/library/socket/udpsocket/write_spec.rb b/spec/ruby/library/socket/udpsocket/write_spec.rb
index c971f29b62..d41ee078d8 100644
--- a/spec/ruby/library/socket/udpsocket/write_spec.rb
+++ b/spec/ruby/library/socket/udpsocket/write_spec.rb
@@ -12,7 +12,7 @@ describe "UDPSocket#write" do
-> do
s2.write('1' * 100_000)
- end.should raise_error(Errno::EMSGSIZE)
+ end.should.raise(Errno::EMSGSIZE)
ensure
s1.close if s1 && !s1.closed?
s2.close if s2 && !s2.closed?
diff --git a/spec/ruby/library/socket/unixserver/accept_nonblock_spec.rb b/spec/ruby/library/socket/unixserver/accept_nonblock_spec.rb
index dba3de7359..531d851658 100644
--- a/spec/ruby/library/socket/unixserver/accept_nonblock_spec.rb
+++ b/spec/ruby/library/socket/unixserver/accept_nonblock_spec.rb
@@ -1,87 +1,85 @@
require_relative '../spec_helper'
require_relative '../fixtures/classes'
-with_feature :unix_socket do
- describe "UNIXServer#accept_nonblock" do
- before :each do
- @path = SocketSpecs.socket_path
- @server = UNIXServer.open(@path)
- @client = UNIXSocket.open(@path)
+describe "UNIXServer#accept_nonblock" do
+ before :each do
+ @path = SocketSpecs.socket_path
+ @server = UNIXServer.open(@path)
+ @client = UNIXSocket.open(@path)
- @socket = @server.accept_nonblock
- @client.send("foobar", 0)
- end
+ @socket = @server.accept_nonblock
+ @client.send("foobar", 0)
+ end
- after :each do
- @socket.close
- @client.close
- @server.close
- SocketSpecs.rm_socket @path
- end
+ after :each do
+ @socket.close
+ @client.close
+ @server.close
+ SocketSpecs.rm_socket @path
+ end
- it "accepts a connection in a non-blocking way" do
- data = @socket.recvfrom(6).first
- data.should == "foobar"
- end
+ it "accepts a connection in a non-blocking way" do
+ data = @socket.recvfrom(6).first
+ data.should == "foobar"
+ end
- it "returns a UNIXSocket" do
- @socket.should be_kind_of(UNIXSocket)
- end
+ it "returns a UNIXSocket" do
+ @socket.should.is_a?(UNIXSocket)
+ end
+
+ it 'returns :wait_readable in exceptionless mode' do
+ @server.accept_nonblock(exception: false).should == :wait_readable
+ end
+end
- it 'returns :wait_readable in exceptionless mode' do
- @server.accept_nonblock(exception: false).should == :wait_readable
+describe 'UNIXServer#accept_nonblock' do
+ before do
+ @path = SocketSpecs.socket_path
+ @server = UNIXServer.new(@path)
+ end
+
+ after do
+ @server.close
+ rm_r(@path)
+ end
+
+ describe 'without a client' do
+ it 'raises IO::WaitReadable' do
+ -> { @server.accept_nonblock }.should.raise(IO::WaitReadable)
end
end
- describe 'UNIXServer#accept_nonblock' do
+ describe 'with a client' do
before do
- @path = SocketSpecs.socket_path
- @server = UNIXServer.new(@path)
+ @client = UNIXSocket.new(@path)
end
after do
- @server.close
- rm_r(@path)
+ @client.close
+ @socket.close if @socket
end
- describe 'without a client' do
- it 'raises IO::WaitReadable' do
- -> { @server.accept_nonblock }.should raise_error(IO::WaitReadable)
+ describe 'without any data' do
+ it 'returns a UNIXSocket' do
+ @socket = @server.accept_nonblock
+ @socket.should.instance_of?(UNIXSocket)
end
end
- describe 'with a client' do
+ describe 'with data available' do
before do
- @client = UNIXSocket.new(@path)
- end
-
- after do
- @client.close
- @socket.close if @socket
+ @client.write('hello')
end
- describe 'without any data' do
- it 'returns a UNIXSocket' do
- @socket = @server.accept_nonblock
- @socket.should be_an_instance_of(UNIXSocket)
- end
+ it 'returns a UNIXSocket' do
+ @socket = @server.accept_nonblock
+ @socket.should.instance_of?(UNIXSocket)
end
- describe 'with data available' do
- before do
- @client.write('hello')
- end
-
- it 'returns a UNIXSocket' do
+ describe 'the returned UNIXSocket' do
+ it 'can read the data written' do
@socket = @server.accept_nonblock
- @socket.should be_an_instance_of(UNIXSocket)
- end
-
- describe 'the returned UNIXSocket' do
- it 'can read the data written' do
- @socket = @server.accept_nonblock
- @socket.recv(5).should == 'hello'
- end
+ @socket.recv(5).should == 'hello'
end
end
end
diff --git a/spec/ruby/library/socket/unixserver/accept_spec.rb b/spec/ruby/library/socket/unixserver/accept_spec.rb
index 1305bc6220..8f3ea50966 100644
--- a/spec/ruby/library/socket/unixserver/accept_spec.rb
+++ b/spec/ruby/library/socket/unixserver/accept_spec.rb
@@ -1,126 +1,124 @@
require_relative '../spec_helper'
require_relative '../fixtures/classes'
-with_feature :unix_socket do
- describe "UNIXServer#accept" do
- before :each do
- @path = SocketSpecs.socket_path
- @server = UNIXServer.open(@path)
- end
+describe "UNIXServer#accept" do
+ before :each do
+ @path = SocketSpecs.socket_path
+ @server = UNIXServer.open(@path)
+ end
- after :each do
- @server.close if @server
- SocketSpecs.rm_socket @path
- end
+ after :each do
+ @server.close if @server
+ SocketSpecs.rm_socket @path
+ end
- it "accepts what is written by the client" do
- client = UNIXSocket.open(@path)
+ it "accepts what is written by the client" do
+ client = UNIXSocket.open(@path)
- client.send('hello', 0)
+ client.send('hello', 0)
- sock = @server.accept
- begin
- data, info = sock.recvfrom(5)
+ sock = @server.accept
+ begin
+ data, info = sock.recvfrom(5)
- data.should == 'hello'
- info.should_not be_empty
- ensure
- sock.close
- client.close
- end
+ data.should == 'hello'
+ info.should_not.empty?
+ ensure
+ sock.close
+ client.close
end
+ end
- it "can be interrupted by Thread#kill" do
- t = Thread.new {
- @server.accept
- }
- Thread.pass while t.status and t.status != "sleep"
-
- # kill thread, ensure it dies in a reasonable amount of time
- t.kill
- a = 0
- while t.alive? and a < 5000
- sleep 0.001
- a += 1
- end
- a.should < 5000
+ it "can be interrupted by Thread#kill" do
+ t = Thread.new {
+ @server.accept
+ }
+ Thread.pass while t.status and t.status != "sleep"
+
+ # kill thread, ensure it dies in a reasonable amount of time
+ t.kill
+ a = 0
+ while t.alive? and a < 5000
+ sleep 0.001
+ a += 1
end
+ a.should < 5000
+ end
- it "can be interrupted by Thread#raise" do
- t = Thread.new {
- -> {
- @server.accept
- }.should raise_error(Exception, "interrupted")
- }
+ it "can be interrupted by Thread#raise" do
+ t = Thread.new {
+ -> {
+ @server.accept
+ }.should.raise(Exception, "interrupted")
+ }
- Thread.pass while t.status and t.status != "sleep"
- t.raise Exception, "interrupted"
- t.join
- end
+ Thread.pass while t.status and t.status != "sleep"
+ t.raise Exception, "interrupted"
+ t.join
end
end
-with_feature :unix_socket do
- describe 'UNIXServer#accept' do
+describe 'UNIXServer#accept' do
+ before do
+ @path = SocketSpecs.socket_path
+ @server = UNIXServer.new(@path)
+ end
+
+ after do
+ @server.close
+ rm_r(@path)
+ end
+
+ describe 'without a client' do
+ it 'blocks the calling thread' do
+ -> { @server.accept }.should block_caller
+ end
+ end
+
+ describe 'with a client' do
before do
- @path = SocketSpecs.socket_path
- @server = UNIXServer.new(@path)
+ @client = UNIXSocket.new(@path)
end
after do
- @server.close
- rm_r(@path)
+ @client.close
+ @socket.close if @socket
end
- describe 'without a client' do
- it 'blocks the calling thread' do
- -> { @server.accept }.should block_caller
+ describe 'without any data' do
+ it 'returns a UNIXSocket' do
+ @socket = @server.accept
+ @socket.should.instance_of?(UNIXSocket)
end
end
- describe 'with a client' do
+ describe 'with data available' do
before do
- @client = UNIXSocket.new(@path)
- end
-
- after do
- @client.close
- @socket.close if @socket
+ @client.write('hello')
end
- describe 'without any data' do
- it 'returns a UNIXSocket' do
- @socket = @server.accept
- @socket.should be_an_instance_of(UNIXSocket)
- end
+ it 'returns a UNIXSocket' do
+ @socket = @server.accept
+ @socket.should.instance_of?(UNIXSocket)
end
- describe 'with data available' do
- before do
- @client.write('hello')
- end
-
- it 'returns a UNIXSocket' do
+ describe 'the returned UNIXSocket' do
+ it 'can read the data written' do
@socket = @server.accept
- @socket.should be_an_instance_of(UNIXSocket)
+ @socket.recv(5).should == 'hello'
end
- describe 'the returned UNIXSocket' do
- it 'can read the data written' do
- @socket = @server.accept
- @socket.recv(5).should == 'hello'
- end
-
+ platform_is_not :windows do
it "is set to nonblocking" do
require 'io/nonblock'
@socket = @server.accept
@socket.should.nonblock?
end
+ end
- it "is set to close on exec" do
- @socket = @server.accept
- @socket.should.close_on_exec?
- end
+ it "is set to close on exec" do
+ @socket = @server.accept
+ @socket.should.close_on_exec?
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..be1c2df4d7 100644
--- a/spec/ruby/library/socket/unixserver/for_fd_spec.rb
+++ b/spec/ruby/library/socket/unixserver/for_fd_spec.rb
@@ -1,23 +1,21 @@
require_relative '../spec_helper'
require_relative '../fixtures/classes'
-with_feature :unix_socket do
- describe "UNIXServer.for_fd" do
- before :each do
- @unix_path = SocketSpecs.socket_path
- @unix = UNIXServer.new(@unix_path)
- end
+describe "UNIXServer.for_fd" do
+ before :each do
+ @unix_path = SocketSpecs.socket_path
+ @unix = UNIXServer.new(@unix_path)
+ end
- after :each do
- @unix.close if @unix
- SocketSpecs.rm_socket @unix_path
- end
+ after :each do
+ @unix.close if @unix
+ SocketSpecs.rm_socket @unix_path
+ end
- it "can calculate the path" do
- b = UNIXServer.for_fd(@unix.fileno)
- b.autoclose = false
+ it "can calculate the path" do
+ b = UNIXServer.for_fd(@unix.fileno)
+ b.autoclose = false
- b.path.should == @unix_path
- end
+ b.path.should == @unix_path
end
end
diff --git a/spec/ruby/library/socket/unixserver/initialize_spec.rb b/spec/ruby/library/socket/unixserver/initialize_spec.rb
index 0cc49ef1eb..ca1dd301f0 100644
--- a/spec/ruby/library/socket/unixserver/initialize_spec.rb
+++ b/spec/ruby/library/socket/unixserver/initialize_spec.rb
@@ -1,28 +1,26 @@
require_relative '../spec_helper'
require_relative '../fixtures/classes'
-with_feature :unix_socket do
- describe 'UNIXServer#initialize' do
- before do
- @path = SocketSpecs.socket_path
- @server = UNIXServer.new(@path)
- end
+describe 'UNIXServer#initialize' do
+ before do
+ @path = SocketSpecs.socket_path
+ @server = UNIXServer.new(@path)
+ end
- after do
- @server.close if @server
- rm_r @path
- end
+ after do
+ @server.close if @server
+ rm_r @path
+ end
- it 'returns a new UNIXServer' do
- @server.should be_an_instance_of(UNIXServer)
- end
+ it 'returns a new UNIXServer' do
+ @server.should.instance_of?(UNIXServer)
+ end
- it 'sets the socket to binmode' do
- @server.binmode?.should be_true
- end
+ it 'sets the socket to binmode' do
+ @server.binmode?.should == true
+ end
- it 'raises Errno::EADDRINUSE when the socket is already in use' do
- -> { UNIXServer.new(@path) }.should raise_error(Errno::EADDRINUSE)
- end
+ it 'raises Errno::EADDRINUSE when the socket is already in use' do
+ -> { UNIXServer.new(@path) }.should.raise(Errno::EADDRINUSE)
end
end
diff --git a/spec/ruby/library/socket/unixserver/listen_spec.rb b/spec/ruby/library/socket/unixserver/listen_spec.rb
index b90b3bbb09..7938d648c4 100644
--- a/spec/ruby/library/socket/unixserver/listen_spec.rb
+++ b/spec/ruby/library/socket/unixserver/listen_spec.rb
@@ -1,21 +1,19 @@
require_relative '../spec_helper'
require_relative '../fixtures/classes'
-with_feature :unix_socket do
- describe 'UNIXServer#listen' do
- before do
- @path = SocketSpecs.socket_path
- @server = UNIXServer.new(@path)
- end
+describe 'UNIXServer#listen' do
+ before do
+ @path = SocketSpecs.socket_path
+ @server = UNIXServer.new(@path)
+ end
- after do
- @server.close
+ after do
+ @server.close
- rm_r(@path)
- end
+ rm_r(@path)
+ end
- it 'returns 0' do
- @server.listen(1).should == 0
- end
+ it 'returns 0' do
+ @server.listen(1).should == 0
end
end
diff --git a/spec/ruby/library/socket/unixserver/new_spec.rb b/spec/ruby/library/socket/unixserver/new_spec.rb
index a160e3ce5c..7d0c7bf76e 100644
--- a/spec/ruby/library/socket/unixserver/new_spec.rb
+++ b/spec/ruby/library/socket/unixserver/new_spec.rb
@@ -1,14 +1,12 @@
require_relative '../spec_helper'
require_relative 'shared/new'
-with_feature :unix_socket do
- describe "UNIXServer.new" do
- it_behaves_like :unixserver_new, :new
+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
+ 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
diff --git a/spec/ruby/library/socket/unixserver/open_spec.rb b/spec/ruby/library/socket/unixserver/open_spec.rb
index 16453dd3bd..c49df802d0 100644
--- a/spec/ruby/library/socket/unixserver/open_spec.rb
+++ b/spec/ruby/library/socket/unixserver/open_spec.rb
@@ -2,25 +2,23 @@ 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
- before :each do
- @path = SocketSpecs.socket_path
- end
+ 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 "yields the new UNIXServer object to the block, if given" do
- UNIXServer.open(@path) do |unix|
- unix.path.should == @path
- unix.addr.should == ["AF_UNIX", @path]
- end
+ it "yields the new UNIXServer object to the block, if given" do
+ UNIXServer.open(@path) do |unix|
+ unix.path.should == @path
+ unix.addr.should == ["AF_UNIX", @path]
end
end
end
diff --git a/spec/ruby/library/socket/unixserver/sysaccept_spec.rb b/spec/ruby/library/socket/unixserver/sysaccept_spec.rb
index e59731878a..5970c01114 100644
--- a/spec/ruby/library/socket/unixserver/sysaccept_spec.rb
+++ b/spec/ruby/library/socket/unixserver/sysaccept_spec.rb
@@ -1,51 +1,49 @@
require_relative '../spec_helper'
require_relative '../fixtures/classes'
-with_feature :unix_socket do
- describe 'UNIXServer#sysaccept' do
+describe 'UNIXServer#sysaccept' do
+ before do
+ @path = SocketSpecs.socket_path
+ @server = UNIXServer.new(@path)
+ end
+
+ after do
+ @server.close
+
+ rm_r(@path)
+ end
+
+ describe 'without a client' do
+ it 'blocks the calling thread' do
+ -> { @server.sysaccept }.should block_caller
+ end
+ end
+
+ describe 'with a client' do
before do
- @path = SocketSpecs.socket_path
- @server = UNIXServer.new(@path)
+ @client = UNIXSocket.new(@path)
end
after do
- @server.close
-
- rm_r(@path)
+ Socket.for_fd(@fd).close if @fd
+ @client.close
end
- describe 'without a client' do
- it 'blocks the calling thread' do
- -> { @server.sysaccept }.should block_caller
+ describe 'without any data' do
+ it 'returns an Integer' do
+ @fd = @server.sysaccept
+ @fd.should.is_a?(Integer)
end
end
- describe 'with a client' do
+ describe 'with data available' do
before do
- @client = UNIXSocket.new(@path)
- end
-
- after do
- Socket.for_fd(@fd).close if @fd
- @client.close
+ @client.write('hello')
end
- describe 'without any data' do
- it 'returns an Integer' do
- @fd = @server.sysaccept
- @fd.should be_kind_of(Integer)
- end
- end
-
- describe 'with data available' do
- before do
- @client.write('hello')
- end
-
- it 'returns an Integer' do
- @fd = @server.sysaccept
- @fd.should be_kind_of(Integer)
- end
+ it 'returns an Integer' do
+ @fd = @server.sysaccept
+ @fd.should.is_a?(Integer)
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..b3ae2af5d8 100644
--- a/spec/ruby/library/socket/unixsocket/addr_spec.rb
+++ b/spec/ruby/library/socket/unixsocket/addr_spec.rb
@@ -1,35 +1,33 @@
require_relative '../spec_helper'
require_relative '../fixtures/classes'
-with_feature :unix_socket do
- describe "UNIXSocket#addr" do
- before :each do
- @path = SocketSpecs.socket_path
- @server = UNIXServer.open(@path)
- @client = UNIXSocket.open(@path)
- end
+describe "UNIXSocket#addr" do
+ before :each do
+ @path = SocketSpecs.socket_path
+ @server = UNIXServer.open(@path)
+ @client = UNIXSocket.open(@path)
+ end
- after :each do
- @client.close
- @server.close
- SocketSpecs.rm_socket @path
- end
+ after :each do
+ @client.close
+ @server.close
+ SocketSpecs.rm_socket @path
+ end
- it "returns an array" do
- @client.addr.should be_kind_of(Array)
- end
+ it "returns an array" do
+ @client.addr.should.is_a?(Array)
+ end
- it "returns the address family of this socket in an array" do
- @client.addr[0].should == "AF_UNIX"
- @server.addr[0].should == "AF_UNIX"
- end
+ it "returns the address family of this socket in an array" do
+ @client.addr[0].should == "AF_UNIX"
+ @server.addr[0].should == "AF_UNIX"
+ end
- it "returns the path of the socket in an array if it's a server" do
- @server.addr[1].should == @path
- end
+ it "returns the path of the socket in an array if it's a server" do
+ @server.addr[1].should == @path
+ end
- it "returns an empty string for path if it's a client" do
- @client.addr[1].should == ""
- end
+ it "returns an empty string for path if it's a client" do
+ @client.addr[1].should == ""
end
end
diff --git a/spec/ruby/library/socket/unixsocket/initialize_spec.rb b/spec/ruby/library/socket/unixsocket/initialize_spec.rb
index bf7896ab0e..ac30b93de0 100644
--- a/spec/ruby/library/socket/unixsocket/initialize_spec.rb
+++ b/spec/ruby/library/socket/unixsocket/initialize_spec.rb
@@ -1,48 +1,56 @@
require_relative '../spec_helper'
require_relative '../fixtures/classes'
-with_feature :unix_socket do
- describe 'UNIXSocket#initialize' do
- describe 'using a non existing path' do
+describe 'UNIXSocket#initialize' do
+ describe 'using a non existing path' do
+ platform_is_not :windows do
it 'raises Errno::ENOENT' do
- -> { UNIXSocket.new(SocketSpecs.socket_path) }.should raise_error(Errno::ENOENT)
+ -> { UNIXSocket.new(SocketSpecs.socket_path) }.should.raise(Errno::ENOENT)
end
end
- describe 'using an existing socket path' do
- before do
- @path = SocketSpecs.socket_path
- @server = UNIXServer.new(@path)
- @socket = UNIXSocket.new(@path)
+ platform_is :windows do
+ # Why, Windows, why?
+ it 'raises Errno::ECONNREFUSED' do
+ -> { UNIXSocket.new(SocketSpecs.socket_path) }.should.raise(Errno::ECONNREFUSED)
end
+ end
+ end
- after do
- @socket.close
- @server.close
- rm_r(@path)
- end
+ describe 'using an existing socket path' do
+ before do
+ @path = SocketSpecs.socket_path
+ @server = UNIXServer.new(@path)
+ @socket = UNIXSocket.new(@path)
+ end
- it 'returns a new UNIXSocket' do
- @socket.should be_an_instance_of(UNIXSocket)
- end
+ after do
+ @socket.close
+ @server.close
+ rm_r(@path)
+ end
- it 'sets the socket path to an empty String' do
- @socket.path.should == ''
- end
+ it 'returns a new UNIXSocket' do
+ @socket.should.instance_of?(UNIXSocket)
+ end
- it 'sets the socket to binmode' do
- @socket.binmode?.should be_true
- end
+ it 'sets the socket path to an empty String' do
+ @socket.path.should == ''
+ end
+
+ it 'sets the socket to binmode' do
+ @socket.binmode?.should == true
+ end
+ platform_is_not :windows do
it 'sets the socket to nonblock' do
require 'io/nonblock'
@socket.should.nonblock?
end
+ end
- it 'sets the socket to close on exec' do
- @socket.should.close_on_exec?
- end
-
+ it 'sets the socket to close on exec' do
+ @socket.should.close_on_exec?
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..77bb521069 100644
--- a/spec/ruby/library/socket/unixsocket/inspect_spec.rb
+++ b/spec/ruby/library/socket/unixsocket/inspect_spec.rb
@@ -1,17 +1,15 @@
require_relative '../spec_helper'
require_relative '../fixtures/classes'
-with_feature :unix_socket do
- describe "UNIXSocket#inspect" do
- it "returns sockets fd for unnamed sockets" do
- begin
- s1, s2 = UNIXSocket.socketpair
- s1.inspect.should == "#<UNIXSocket:fd #{s1.fileno}>"
- s2.inspect.should == "#<UNIXSocket:fd #{s2.fileno}>"
- ensure
- s1.close
- s2.close
- end
+describe "UNIXSocket#inspect" do
+ it "returns sockets fd for unnamed sockets" do
+ begin
+ s1, s2 = UNIXSocket.socketpair
+ s1.inspect.should == "#<UNIXSocket:fd #{s1.fileno}>"
+ s2.inspect.should == "#<UNIXSocket:fd #{s2.fileno}>"
+ ensure
+ s1.close
+ s2.close
end
end
end
diff --git a/spec/ruby/library/socket/unixsocket/local_address_spec.rb b/spec/ruby/library/socket/unixsocket/local_address_spec.rb
index 734253e7f5..fc504698c3 100644
--- a/spec/ruby/library/socket/unixsocket/local_address_spec.rb
+++ b/spec/ruby/library/socket/unixsocket/local_address_spec.rb
@@ -1,94 +1,92 @@
require_relative '../spec_helper'
require_relative '../fixtures/classes'
-with_feature :unix_socket do
- describe 'UNIXSocket#local_address' do
- before do
- @path = SocketSpecs.socket_path
- @server = UNIXServer.new(@path)
- @client = UNIXSocket.new(@path)
- end
+describe 'UNIXSocket#local_address' do
+ before do
+ @path = SocketSpecs.socket_path
+ @server = UNIXServer.new(@path)
+ @client = UNIXSocket.new(@path)
+ end
- after do
- @client.close
- @server.close
+ after do
+ @client.close
+ @server.close
- rm_r(@path)
- end
-
- it 'returns an Addrinfo' do
- @client.local_address.should be_an_instance_of(Addrinfo)
- end
+ rm_r(@path)
+ end
- describe 'the returned Addrinfo' do
- platform_is_not :aix do
- it 'uses AF_UNIX as the address family' do
- @client.local_address.afamily.should == Socket::AF_UNIX
- end
+ it 'returns an Addrinfo' do
+ @client.local_address.should.instance_of?(Addrinfo)
+ end
- it 'uses PF_UNIX as the protocol family' do
- @client.local_address.pfamily.should == Socket::PF_UNIX
- end
+ describe 'the returned Addrinfo' do
+ platform_is_not :aix do
+ it 'uses AF_UNIX as the address family' do
+ @client.local_address.afamily.should == Socket::AF_UNIX
end
- it 'uses SOCK_STREAM as the socket type' do
- @client.local_address.socktype.should == Socket::SOCK_STREAM
+ it 'uses PF_UNIX as the protocol family' do
+ @client.local_address.pfamily.should == Socket::PF_UNIX
end
+ end
- platform_is_not :aix do
- it 'uses an empty socket path' do
- @client.local_address.unix_path.should == ''
- end
- end
+ it 'uses SOCK_STREAM as the socket type' do
+ @client.local_address.socktype.should == Socket::SOCK_STREAM
+ end
- it 'uses 0 as the protocol' do
- @client.local_address.protocol.should == 0
+ platform_is_not :aix do
+ it 'uses an empty socket path' do
+ @client.local_address.unix_path.should == ''
end
end
- end
- describe 'UNIXSocket#local_address with a UNIX socket pair' do
- before :each do
- @sock, @sock2 = Socket.pair(Socket::AF_UNIX, Socket::SOCK_STREAM)
+ it 'uses 0 as the protocol' do
+ @client.local_address.protocol.should == 0
end
+ end
+end
- after :each do
- @sock.close
- @sock2.close
- end
+describe 'UNIXSocket#local_address with a UNIX socket pair' do
+ before :each do
+ @sock, @sock2 = Socket.pair(Socket::AF_UNIX, Socket::SOCK_STREAM)
+ end
- it 'returns an Addrinfo' do
- @sock.local_address.should be_an_instance_of(Addrinfo)
- end
+ after :each do
+ @sock.close
+ @sock2.close
+ end
- describe 'the returned Addrinfo' do
- it 'uses AF_UNIX as the address family' do
- @sock.local_address.afamily.should == Socket::AF_UNIX
- end
+ it 'returns an Addrinfo' do
+ @sock.local_address.should.instance_of?(Addrinfo)
+ end
- it 'uses PF_UNIX as the protocol family' do
- @sock.local_address.pfamily.should == Socket::PF_UNIX
- end
+ describe 'the returned Addrinfo' do
+ it 'uses AF_UNIX as the address family' do
+ @sock.local_address.afamily.should == Socket::AF_UNIX
+ end
- it 'uses SOCK_STREAM as the socket type' do
- @sock.local_address.socktype.should == Socket::SOCK_STREAM
- end
+ it 'uses PF_UNIX as the protocol family' do
+ @sock.local_address.pfamily.should == Socket::PF_UNIX
+ end
- it 'raises SocketError for #ip_address' do
- -> {
- @sock.local_address.ip_address
- }.should raise_error(SocketError, "need IPv4 or IPv6 address")
- end
+ it 'uses SOCK_STREAM as the socket type' do
+ @sock.local_address.socktype.should == Socket::SOCK_STREAM
+ end
- it 'raises SocketError for #ip_port' do
- -> {
- @sock.local_address.ip_port
- }.should raise_error(SocketError, "need IPv4 or IPv6 address")
- end
+ it 'raises SocketError for #ip_address' do
+ -> {
+ @sock.local_address.ip_address
+ }.should.raise(SocketError, "need IPv4 or IPv6 address")
+ end
- it 'uses 0 as the protocol' do
- @sock.local_address.protocol.should == 0
- end
+ it 'raises SocketError for #ip_port' do
+ -> {
+ @sock.local_address.ip_port
+ }.should.raise(SocketError, "need IPv4 or IPv6 address")
+ end
+
+ it 'uses 0 as the protocol' do
+ @sock.local_address.protocol.should == 0
end
end
end
diff --git a/spec/ruby/library/socket/unixsocket/new_spec.rb b/spec/ruby/library/socket/unixsocket/new_spec.rb
index 6d8ea6dcfe..fea2c1e2b7 100644
--- a/spec/ruby/library/socket/unixsocket/new_spec.rb
+++ b/spec/ruby/library/socket/unixsocket/new_spec.rb
@@ -1,14 +1,12 @@
require_relative '../spec_helper'
require_relative 'shared/new'
-with_feature :unix_socket do
- describe "UNIXSocket.new" do
- it_behaves_like :unixsocket_new, :new
+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
+ 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
diff --git a/spec/ruby/library/socket/unixsocket/open_spec.rb b/spec/ruby/library/socket/unixsocket/open_spec.rb
index 61def30abb..b5e8c6c23a 100644
--- a/spec/ruby/library/socket/unixsocket/open_spec.rb
+++ b/spec/ruby/library/socket/unixsocket/open_spec.rb
@@ -2,27 +2,25 @@ 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
- before :each do
- @path = SocketSpecs.socket_path
- @server = UNIXServer.open(@path)
- end
+describe "UNIXSocket.open" do
+ before :each do
+ @path = SocketSpecs.socket_path
+ @server = UNIXServer.open(@path)
+ end
- after :each do
- @server.close
- SocketSpecs.rm_socket @path
- end
+ after :each do
+ @server.close
+ SocketSpecs.rm_socket @path
+ end
- it "opens a unix socket on the specified file and yields it to the block" do
- UNIXSocket.open(@path) do |client|
- client.addr[0].should == "AF_UNIX"
- client.should_not.closed?
- end
+ it "opens a unix socket on the specified file and yields it to the block" do
+ UNIXSocket.open(@path) do |client|
+ client.addr[0].should == "AF_UNIX"
+ client.should_not.closed?
end
end
end
diff --git a/spec/ruby/library/socket/unixsocket/pair_spec.rb b/spec/ruby/library/socket/unixsocket/pair_spec.rb
index b0a3b2af99..9f04f568fa 100644
--- a/spec/ruby/library/socket/unixsocket/pair_spec.rb
+++ b/spec/ruby/library/socket/unixsocket/pair_spec.rb
@@ -1,20 +1,59 @@
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
+ it_should_behave_like :partially_closable_sockets
- before :each do
- @s1, @s2 = UNIXSocket.pair
+ before :each do
+ @s1, @s2 = UNIXSocket.pair
+ end
+
+ after :each do
+ @s1.close
+ @s2.close
+ end
+
+ it "returns two UNIXSockets" do
+ @s1.should.instance_of?(UNIXSocket)
+ @s2.should.instance_of?(UNIXSocket)
+ end
+
+ it "returns a pair of connected sockets" do
+ @s1.puts "foo"
+ @s2.gets.should == "foo\n"
+ end
+
+ platform_is_not :windows do
+ 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
+
+ platform_is :windows do
+ it "emulates unnamed sockets with a temporary file with a path" do
+ @s1.addr.should == ["AF_UNIX", @s1.path]
+ @s2.peeraddr.should == ["AF_UNIX", @s1.path]
+ end
+
+ it "sets the peer address of first socket to an empty string" do
+ @s1.peeraddr.should == ["AF_UNIX", ""]
end
- after :each do
- @s1.close
- @s2.close
+ it "sets the address and path of second socket to an empty string" do
+ @s2.addr.should == ["AF_UNIX", ""]
+ @s2.path.should == ""
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..108a6c3063 100644
--- a/spec/ruby/library/socket/unixsocket/partially_closable_spec.rb
+++ b/spec/ruby/library/socket/unixsocket/partially_closable_spec.rb
@@ -2,22 +2,20 @@ require_relative '../spec_helper'
require_relative '../fixtures/classes'
require_relative '../shared/partially_closable_sockets'
-with_feature :unix_socket do
- describe "UNIXSocket partial closability" do
- before :each do
- @path = SocketSpecs.socket_path
- @server = UNIXServer.open(@path)
- @s1 = UNIXSocket.new(@path)
- @s2 = @server.accept
- end
-
- after :each do
- @server.close
- @s1.close
- @s2.close
- SocketSpecs.rm_socket @path
- end
+describe "UNIXSocket partial closability" do
+ before :each do
+ @path = SocketSpecs.socket_path
+ @server = UNIXServer.open(@path)
+ @s1 = UNIXSocket.new(@path)
+ @s2 = @server.accept
+ end
- it_should_behave_like :partially_closable_sockets
+ after :each do
+ @server.close
+ @s1.close
+ @s2.close
+ SocketSpecs.rm_socket @path
end
+
+ it_should_behave_like :partially_closable_sockets
end
diff --git a/spec/ruby/library/socket/unixsocket/path_spec.rb b/spec/ruby/library/socket/unixsocket/path_spec.rb
index a608378e4f..ffe7e4bea2 100644
--- a/spec/ruby/library/socket/unixsocket/path_spec.rb
+++ b/spec/ruby/library/socket/unixsocket/path_spec.rb
@@ -1,26 +1,24 @@
require_relative '../spec_helper'
require_relative '../fixtures/classes'
-with_feature :unix_socket do
- describe "UNIXSocket#path" do
- before :each do
- @path = SocketSpecs.socket_path
- @server = UNIXServer.open(@path)
- @client = UNIXSocket.open(@path)
- end
+describe "UNIXSocket#path" do
+ before :each do
+ @path = SocketSpecs.socket_path
+ @server = UNIXServer.open(@path)
+ @client = UNIXSocket.open(@path)
+ end
- after :each do
- @client.close
- @server.close
- SocketSpecs.rm_socket @path
- end
+ after :each do
+ @client.close
+ @server.close
+ SocketSpecs.rm_socket @path
+ end
- it "returns the path of the socket if it's a server" do
- @server.path.should == @path
- end
+ it "returns the path of the socket if it's a server" do
+ @server.path.should == @path
+ end
- it "returns an empty string for path if it's a client" do
- @client.path.should == ""
- end
+ it "returns an empty string for path if it's a client" do
+ @client.path.should == ""
end
end
diff --git a/spec/ruby/library/socket/unixsocket/peeraddr_spec.rb b/spec/ruby/library/socket/unixsocket/peeraddr_spec.rb
index 72bc96b1fe..b586b1fcbb 100644
--- a/spec/ruby/library/socket/unixsocket/peeraddr_spec.rb
+++ b/spec/ruby/library/socket/unixsocket/peeraddr_spec.rb
@@ -1,28 +1,26 @@
require_relative '../spec_helper'
require_relative '../fixtures/classes'
-with_feature :unix_socket do
- describe "UNIXSocket#peeraddr" do
- before :each do
- @path = SocketSpecs.socket_path
- @server = UNIXServer.open(@path)
- @client = UNIXSocket.open(@path)
- end
+describe "UNIXSocket#peeraddr" do
+ before :each do
+ @path = SocketSpecs.socket_path
+ @server = UNIXServer.open(@path)
+ @client = UNIXSocket.open(@path)
+ end
- after :each do
- @client.close
- @server.close
- SocketSpecs.rm_socket @path
- end
+ after :each do
+ @client.close
+ @server.close
+ SocketSpecs.rm_socket @path
+ end
- it "returns the address family and path of the server end of the connection" do
- @client.peeraddr.should == ["AF_UNIX", @path]
- end
+ it "returns the address family and path of the server end of the connection" do
+ @client.peeraddr.should == ["AF_UNIX", @path]
+ end
- it "raises an error in server sockets" do
- -> {
- @server.peeraddr
- }.should raise_error(Errno::ENOTCONN)
- end
+ it "raises an error in server sockets" do
+ -> {
+ @server.peeraddr
+ }.should.raise(Errno::ENOTCONN)
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..ac9d892375 100644
--- a/spec/ruby/library/socket/unixsocket/recv_io_spec.rb
+++ b/spec/ruby/library/socket/unixsocket/recv_io_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 "UNIXSocket#recv_io" do
before :each do
@path = SocketSpecs.socket_path
@@ -37,7 +37,7 @@ with_feature :unix_socket do
@socket = @server.accept
@io = @socket.recv_io(File)
- @io.should be_an_instance_of(File)
+ @io.should.instance_of?(File)
end
end
@@ -59,7 +59,7 @@ with_feature :unix_socket do
@client.send_io(@file)
@io = @server.recv_io
- @io.should be_an_instance_of(IO)
+ @io.should.instance_of?(IO)
end
end
@@ -68,7 +68,7 @@ with_feature :unix_socket do
@client.send_io(@file)
@io = @server.recv_io(File)
- @io.should be_an_instance_of(File)
+ @io.should.instance_of?(File)
end
end
@@ -77,7 +77,7 @@ with_feature :unix_socket do
@client.send_io(@file)
@io = @server.recv_io(File, File::WRONLY)
- @io.should be_an_instance_of(File)
+ @io.should.instance_of?(File)
end
end
end
diff --git a/spec/ruby/library/socket/unixsocket/recvfrom_spec.rb b/spec/ruby/library/socket/unixsocket/recvfrom_spec.rb
index d849fdc302..9ae3777961 100644
--- a/spec/ruby/library/socket/unixsocket/recvfrom_spec.rb
+++ b/spec/ruby/library/socket/unixsocket/recvfrom_spec.rb
@@ -1,59 +1,105 @@
require_relative '../spec_helper'
require_relative '../fixtures/classes'
-with_feature :unix_socket do
- describe "UNIXSocket#recvfrom" do
- before :each do
- @path = SocketSpecs.socket_path
- @server = UNIXServer.open(@path)
- @client = UNIXSocket.open(@path)
+describe "UNIXSocket#recvfrom" do
+ before :each do
+ @path = SocketSpecs.socket_path
+ @server = UNIXServer.open(@path)
+ @client = UNIXSocket.open(@path)
+ end
+
+ after :each do
+ @client.close
+ @server.close
+ SocketSpecs.rm_socket @path
+ end
+
+ it "receives len bytes from sock, returning an array containing sent data as first element" do
+ @client.send("foobar", 0)
+ sock = @server.accept
+ sock.recvfrom(6).first.should == "foobar"
+ sock.close
+ end
+
+ context "when called on a server's socket" do
+ platform_is_not :windows do
+ it "returns an array containing basic information on the client as second element" do
+ @client.send("foobar", 0)
+ sock = @server.accept
+ data = sock.recvfrom(6)
+ data.last.should == ["AF_UNIX", ""]
+ sock.close
+ end
end
- after :each do
- @client.close
- @server.close
- SocketSpecs.rm_socket @path
+ guard -> { platform_is :windows and ruby_bug "#21702", ""..."4.2" } do
+ it "returns an array containing basic information on the client as second element" do
+ @client.send("foobar", 0)
+ sock = @server.accept
+ data = sock.recvfrom(6)
+ data.last.should == ["AF_UNIX", ""]
+ sock.close
+ end
end
+ end
- it "receives len bytes from sock" do
- @client.send("foobar", 0)
- sock = @server.accept
- sock.recvfrom(6).first.should == "foobar"
- sock.close
+ context "when called on a client's socket" do
+ platform_is :linux do
+ it "returns an array containing server's address as second element" do
+ @client.send("", 0)
+ sock = @server.accept
+ sock.send("barfoo", 0)
+ @client.recvfrom(6).last.should == ["AF_UNIX", @server.local_address.unix_path]
+ sock.close
+ end
end
- it "returns an array with data and information on the sender" do
- @client.send("foobar", 0)
- sock = @server.accept
- data = sock.recvfrom(6)
- data.first.should == "foobar"
- data.last.should == ["AF_UNIX", ""]
- sock.close
+ guard -> { platform_is :windows and ruby_bug "#21702", ""..."4.2" } do
+ it "returns an array containing server's address as second element" do
+ @client.send("", 0)
+ sock = @server.accept
+ sock.send("barfoo", 0)
+ # This may not be correct, depends on what underlying recvfrom actually returns.
+ @client.recvfrom(6).last.should == ["AF_UNIX", @server.local_address.unix_path]
+ sock.close
+ end
end
- it "allows an output buffer as third argument" do
- buffer = +''
+ platform_is :darwin do
+ it "returns an array containing basic information on the server as second element" do
+ @client.send("", 0)
+ sock = @server.accept
+ sock.send("barfoo", 0)
+ @client.recvfrom(6).last.should == ["AF_UNIX", ""]
+ sock.close
+ end
+ end
+ end
- @client.send("foobar", 0)
- sock = @server.accept
- message, = sock.recvfrom(6, 0, buffer)
- sock.close
+ it "allows an output buffer as third argument" do
+ buffer = +''
- message.should.equal?(buffer)
- buffer.should == "foobar"
- end
+ @client.send("foobar", 0)
+ sock = @server.accept
+ message, = sock.recvfrom(6, 0, buffer)
+ sock.close
- it "preserves the encoding of the given buffer" do
- buffer = ''.encode(Encoding::ISO_8859_1)
+ message.should.equal?(buffer)
+ buffer.should == "foobar"
+ end
- @client.send("foobar", 0)
- sock = @server.accept
- sock.recvfrom(6, 0, buffer)
- sock.close
+ it "preserves the encoding of the given buffer" do
+ buffer = ''.encode(Encoding::ISO_8859_1)
- buffer.encoding.should == Encoding::ISO_8859_1
- end
+ @client.send("foobar", 0)
+ sock = @server.accept
+ sock.recvfrom(6, 0, buffer)
+ sock.close
+ buffer.encoding.should == Encoding::ISO_8859_1
+ end
+
+ platform_is_not :windows do
it "uses different message options" do
@client.send("foobar", Socket::MSG_PEEK)
sock = @server.accept
@@ -65,24 +111,34 @@ with_feature :unix_socket do
sock.close
end
end
+end
- describe 'UNIXSocket#recvfrom' do
- describe 'using a socket pair' do
- before do
- @client, @server = UNIXSocket.socketpair
- @client.write('hello')
- end
+describe 'UNIXSocket#recvfrom' do
+ describe 'using a socket pair' do
+ before do
+ @client, @server = UNIXSocket.socketpair
+ @client.write('hello')
+ end
- after do
- @client.close
- @server.close
+ after do
+ @client.close
+ @server.close
+ end
+
+ platform_is_not :windows do
+ it 'returns an Array containing the data and address information' do
+ @server.recvfrom(5).should == ['hello', ['AF_UNIX', '']]
end
+ end
+ guard -> { platform_is :windows and ruby_bug "#21702", ""..."4.2" } do
it 'returns an Array containing the data and address information' do
@server.recvfrom(5).should == ['hello', ['AF_UNIX', '']]
end
end
+ end
+ platform_is_not :windows do
# These specs are taken from the rdoc examples on UNIXSocket#recvfrom.
describe 'using a UNIX socket constructed using UNIXSocket.for_fd' do
before do
diff --git a/spec/ruby/library/socket/unixsocket/remote_address_spec.rb b/spec/ruby/library/socket/unixsocket/remote_address_spec.rb
index 0b416254d0..d2303a6587 100644
--- a/spec/ruby/library/socket/unixsocket/remote_address_spec.rb
+++ b/spec/ruby/library/socket/unixsocket/remote_address_spec.rb
@@ -1,45 +1,43 @@
require_relative '../spec_helper'
require_relative '../fixtures/classes'
-with_feature :unix_socket do
- describe 'UNIXSocket#remote_address' do
- before do
- @path = SocketSpecs.socket_path
- @server = UNIXServer.new(@path)
- @client = UNIXSocket.new(@path)
- end
+describe 'UNIXSocket#remote_address' do
+ before do
+ @path = SocketSpecs.socket_path
+ @server = UNIXServer.new(@path)
+ @client = UNIXSocket.new(@path)
+ end
- after do
- @client.close
- @server.close
+ after do
+ @client.close
+ @server.close
- rm_r(@path)
- end
+ rm_r(@path)
+ end
- it 'returns an Addrinfo' do
- @client.remote_address.should be_an_instance_of(Addrinfo)
- end
+ it 'returns an Addrinfo' do
+ @client.remote_address.should.instance_of?(Addrinfo)
+ end
- describe 'the returned Addrinfo' do
- it 'uses AF_UNIX as the address family' do
- @client.remote_address.afamily.should == Socket::AF_UNIX
- end
+ describe 'the returned Addrinfo' do
+ it 'uses AF_UNIX as the address family' do
+ @client.remote_address.afamily.should == Socket::AF_UNIX
+ end
- it 'uses PF_UNIX as the protocol family' do
- @client.remote_address.pfamily.should == Socket::PF_UNIX
- end
+ it 'uses PF_UNIX as the protocol family' do
+ @client.remote_address.pfamily.should == Socket::PF_UNIX
+ end
- it 'uses SOCK_STREAM as the socket type' do
- @client.remote_address.socktype.should == Socket::SOCK_STREAM
- end
+ it 'uses SOCK_STREAM as the socket type' do
+ @client.remote_address.socktype.should == Socket::SOCK_STREAM
+ end
- it 'uses the correct socket path' do
- @client.remote_address.unix_path.should == @path
- end
+ it 'uses the correct socket path' do
+ @client.remote_address.unix_path.should == @path
+ end
- it 'uses 0 as the protocol' do
- @client.remote_address.protocol.should == 0
- end
+ it 'uses 0 as the protocol' do
+ @client.remote_address.protocol.should == 0
end
end
end
diff --git a/spec/ruby/library/socket/unixsocket/send_io_spec.rb b/spec/ruby/library/socket/unixsocket/send_io_spec.rb
index 80f3550c6d..0063fc7d3f 100644
--- a/spec/ruby/library/socket/unixsocket/send_io_spec.rb
+++ b/spec/ruby/library/socket/unixsocket/send_io_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 "UNIXSocket#send_io" do
before :each do
@path = SocketSpecs.socket_path
@@ -49,7 +49,7 @@ with_feature :unix_socket do
@client.send_io(@file)
@io = @server.recv_io
- @io.should be_an_instance_of(IO)
+ @io.should.instance_of?(IO)
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..a8bfb412e5 100644
--- a/spec/ruby/library/socket/unixsocket/socketpair_spec.rb
+++ b/spec/ruby/library/socket/unixsocket/socketpair_spec.rb
@@ -1,20 +1,7 @@
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
- @s1, @s2 = UNIXSocket.socketpair
- end
-
- after :each do
- @s1.close
- @s2.close
- end
+describe "UNIXSocket.socketpair" do
+ it "is an alias of UNIXSocket.pair" do
+ UNIXSocket.method(:socketpair).should == UNIXSocket.method(:pair)
end
end
diff --git a/spec/ruby/library/stringio/append_spec.rb b/spec/ruby/library/stringio/append_spec.rb
index cb50d73d1b..c21ba00508 100644
--- a/spec/ruby/library/stringio/append_spec.rb
+++ b/spec/ruby/library/stringio/append_spec.rb
@@ -7,7 +7,7 @@ describe "StringIO#<< when passed [Object]" do
end
it "returns self" do
- (@io << "just testing").should equal(@io)
+ (@io << "just testing").should.equal?(@io)
end
it "writes the passed argument onto self" do
@@ -31,7 +31,7 @@ describe "StringIO#<< when passed [Object]" do
it "updates self's position" do
@io << "test"
- @io.pos.should eql(4)
+ @io.pos.should.eql?(4)
end
it "tries to convert the passed argument to a String using #to_s" do
@@ -45,11 +45,11 @@ end
describe "StringIO#<< when self is not writable" do
it "raises an IOError" do
io = StringIO.new(+"test", "r")
- -> { io << "test" }.should raise_error(IOError)
+ -> { io << "test" }.should.raise(IOError)
io = StringIO.new(+"test")
io.close_write
- -> { io << "test" }.should raise_error(IOError)
+ -> { io << "test" }.should.raise(IOError)
end
end
@@ -69,6 +69,6 @@ describe "StringIO#<< when in append mode" do
it "correctly updates self's position" do
@io << ", testing"
- @io.pos.should eql(16)
+ @io.pos.should.eql?(16)
end
end
diff --git a/spec/ruby/library/stringio/binmode_spec.rb b/spec/ruby/library/stringio/binmode_spec.rb
index 9e92c63814..bc7ccda0a2 100644
--- a/spec/ruby/library/stringio/binmode_spec.rb
+++ b/spec/ruby/library/stringio/binmode_spec.rb
@@ -4,7 +4,7 @@ require_relative 'fixtures/classes'
describe "StringIO#binmode" do
it "returns self" do
io = StringIO.new(+"example")
- io.binmode.should equal(io)
+ io.binmode.should.equal?(io)
end
it "changes external encoding to BINARY" do
diff --git a/spec/ruby/library/stringio/close_read_spec.rb b/spec/ruby/library/stringio/close_read_spec.rb
index 0f08e1ff2e..dd46a927be 100644
--- a/spec/ruby/library/stringio/close_read_spec.rb
+++ b/spec/ruby/library/stringio/close_read_spec.rb
@@ -7,12 +7,12 @@ describe "StringIO#close_read" do
end
it "returns nil" do
- @io.close_read.should be_nil
+ @io.close_read.should == nil
end
it "prevents further reading" do
@io.close_read
- -> { @io.read(1) }.should raise_error(IOError)
+ -> { @io.read(1) }.should.raise(IOError)
end
it "allows further writing" do
@@ -22,7 +22,7 @@ describe "StringIO#close_read" do
it "raises an IOError when in write-only mode" do
io = StringIO.new(+"example", "w")
- -> { io.close_read }.should raise_error(IOError)
+ -> { io.close_read }.should.raise(IOError)
io = StringIO.new("example")
io.close_read
diff --git a/spec/ruby/library/stringio/close_spec.rb b/spec/ruby/library/stringio/close_spec.rb
index 520a8de782..6febd14a26 100644
--- a/spec/ruby/library/stringio/close_spec.rb
+++ b/spec/ruby/library/stringio/close_spec.rb
@@ -7,17 +7,17 @@ describe "StringIO#close" do
end
it "returns nil" do
- @io.close.should be_nil
+ @io.close.should == nil
end
it "prevents further reading and/or writing" do
@io.close
- -> { @io.read(1) }.should raise_error(IOError)
- -> { @io.write('x') }.should raise_error(IOError)
+ -> { @io.read(1) }.should.raise(IOError)
+ -> { @io.write('x') }.should.raise(IOError)
end
it "does not raise anything when self was already closed" do
@io.close
- -> { @io.close }.should_not raise_error(IOError)
+ -> { @io.close }.should_not.raise(IOError)
end
end
diff --git a/spec/ruby/library/stringio/close_write_spec.rb b/spec/ruby/library/stringio/close_write_spec.rb
index c86c3f9826..b74b996166 100644
--- a/spec/ruby/library/stringio/close_write_spec.rb
+++ b/spec/ruby/library/stringio/close_write_spec.rb
@@ -7,12 +7,12 @@ describe "StringIO#close_write" do
end
it "returns nil" do
- @io.close_write.should be_nil
+ @io.close_write.should == nil
end
it "prevents further writing" do
@io.close_write
- -> { @io.write('x') }.should raise_error(IOError)
+ -> { @io.write('x') }.should.raise(IOError)
end
it "allows further reading" do
@@ -22,7 +22,7 @@ describe "StringIO#close_write" do
it "raises an IOError when in read-only mode" do
io = StringIO.new(+"example", "r")
- -> { io.close_write }.should raise_error(IOError)
+ -> { io.close_write }.should.raise(IOError)
io = StringIO.new(+"example")
io.close_write
diff --git a/spec/ruby/library/stringio/closed_read_spec.rb b/spec/ruby/library/stringio/closed_read_spec.rb
index b4dcadc3a4..2e3813b1bc 100644
--- a/spec/ruby/library/stringio/closed_read_spec.rb
+++ b/spec/ruby/library/stringio/closed_read_spec.rb
@@ -5,8 +5,8 @@ describe "StringIO#closed_read?" do
it "returns true if self is not readable" do
io = StringIO.new(+"example", "r+")
io.close_write
- io.closed_read?.should be_false
+ io.closed_read?.should == false
io.close_read
- io.closed_read?.should be_true
+ io.closed_read?.should == true
end
end
diff --git a/spec/ruby/library/stringio/closed_spec.rb b/spec/ruby/library/stringio/closed_spec.rb
index bf7ba63184..647fe445da 100644
--- a/spec/ruby/library/stringio/closed_spec.rb
+++ b/spec/ruby/library/stringio/closed_spec.rb
@@ -5,12 +5,12 @@ describe "StringIO#closed?" do
it "returns true if self is completely closed" do
io = StringIO.new(+"example", "r+")
io.close_read
- io.closed?.should be_false
+ io.closed?.should == false
io.close_write
- io.closed?.should be_true
+ io.closed?.should == true
io = StringIO.new(+"example", "r+")
io.close
- io.closed?.should be_true
+ io.closed?.should == true
end
end
diff --git a/spec/ruby/library/stringio/closed_write_spec.rb b/spec/ruby/library/stringio/closed_write_spec.rb
index 2bd3e6fa8b..339691cd82 100644
--- a/spec/ruby/library/stringio/closed_write_spec.rb
+++ b/spec/ruby/library/stringio/closed_write_spec.rb
@@ -5,8 +5,8 @@ describe "StringIO#closed_write?" do
it "returns true if self is not writable" do
io = StringIO.new(+"example", "r+")
io.close_read
- io.closed_write?.should be_false
+ io.closed_write?.should == false
io.close_write
- io.closed_write?.should be_true
+ io.closed_write?.should == true
end
end
diff --git a/spec/ruby/library/stringio/each_byte_spec.rb b/spec/ruby/library/stringio/each_byte_spec.rb
index 6f82a32441..1be0081c1e 100644
--- a/spec/ruby/library/stringio/each_byte_spec.rb
+++ b/spec/ruby/library/stringio/each_byte_spec.rb
@@ -1,11 +1,51 @@
require_relative '../../spec_helper'
require 'stringio'
-require_relative 'shared/each_byte'
describe "StringIO#each_byte" do
- it_behaves_like :stringio_each_byte, :each_byte
+ before :each do
+ @io = StringIO.new("xyz")
+ end
+
+ it "yields each character code in turn" do
+ seen = []
+ @io.each_byte { |b| seen << b }
+ seen.should == [120, 121, 122]
+ end
+
+ it "updates the position before each yield" do
+ seen = []
+ @io.each_byte { |b| seen << @io.pos }
+ seen.should == [1, 2, 3]
+ end
+
+ it "does not yield if the current position is out of bounds" do
+ @io.pos = 1000
+ seen = nil
+ @io.each_byte { |b| seen = b }
+ seen.should == nil
+ end
+
+ it "returns self" do
+ @io.each_byte {}.should.equal?(@io)
+ end
+
+ it "returns an Enumerator when passed no block" do
+ enum = @io.each_byte
+ enum.instance_of?(Enumerator).should == true
+
+ seen = []
+ enum.each { |b| seen << b }
+ seen.should == [120, 121, 122]
+ end
end
describe "StringIO#each_byte when self is not readable" do
- it_behaves_like :stringio_each_byte_not_readable, :each_byte
+ it "raises an IOError" do
+ io = StringIO.new(+"xyz", "w")
+ -> { io.each_byte { |b| b } }.should.raise(IOError)
+
+ io = StringIO.new("xyz")
+ io.close_read
+ -> { io.each_byte { |b| b } }.should.raise(IOError)
+ end
end
diff --git a/spec/ruby/library/stringio/each_char_spec.rb b/spec/ruby/library/stringio/each_char_spec.rb
index 14b2f09a17..1db80c7d07 100644
--- a/spec/ruby/library/stringio/each_char_spec.rb
+++ b/spec/ruby/library/stringio/each_char_spec.rb
@@ -1,11 +1,38 @@
require_relative '../../spec_helper'
require 'stringio'
-require_relative 'shared/each_char'
describe "StringIO#each_char" do
- it_behaves_like :stringio_each_char, :each_char
+ before :each do
+ @io = StringIO.new("xyz äöü")
+ end
+
+ it "yields each character code in turn" do
+ seen = []
+ @io.each_char { |c| seen << c }
+ seen.should == ["x", "y", "z", " ", "ä", "ö", "ü"]
+ end
+
+ it "returns self" do
+ @io.each_char {}.should.equal?(@io)
+ end
+
+ it "returns an Enumerator when passed no block" do
+ enum = @io.each_char
+ enum.instance_of?(Enumerator).should == true
+
+ seen = []
+ enum.each { |c| seen << c }
+ seen.should == ["x", "y", "z", " ", "ä", "ö", "ü"]
+ end
end
describe "StringIO#each_char when self is not readable" do
- it_behaves_like :stringio_each_char_not_readable, :each_char
+ it "raises an IOError" do
+ io = StringIO.new(+"xyz", "w")
+ -> { io.each_char { |b| b } }.should.raise(IOError)
+
+ io = StringIO.new("xyz")
+ io.close_read
+ -> { io.each_char { |b| b } }.should.raise(IOError)
+ end
end
diff --git a/spec/ruby/library/stringio/each_codepoint_spec.rb b/spec/ruby/library/stringio/each_codepoint_spec.rb
index f18de22aad..d4f461db90 100644
--- a/spec/ruby/library/stringio/each_codepoint_spec.rb
+++ b/spec/ruby/library/stringio/each_codepoint_spec.rb
@@ -1,9 +1,47 @@
-# -*- encoding: utf-8 -*-
require_relative '../../spec_helper'
-require_relative 'fixtures/classes'
-require_relative 'shared/codepoints'
+require 'stringio'
# See redmine #1667
describe "StringIO#each_codepoint" do
- it_behaves_like :stringio_codepoints, :each_codepoint
+ before :each do
+ @io = StringIO.new("∂φ/∂x = gaîté")
+ @enum = @io.each_codepoint
+ end
+
+ it "returns an Enumerator" do
+ @enum.should.instance_of?(Enumerator)
+ end
+
+ it "yields each codepoint code in turn" do
+ @enum.to_a.should == [8706, 966, 47, 8706, 120, 32, 61, 32, 103, 97, 238, 116, 233]
+ end
+
+ it "yields each codepoint starting from the current position" do
+ @io.pos = 15
+ @enum.to_a.should == [238, 116, 233]
+ end
+
+ it "raises an error if reading invalid sequence" do
+ @io.pos = 1 # inside of a multibyte sequence
+ -> { @enum.first }.should.raise(ArgumentError)
+ end
+
+ it "raises an IOError if not readable" do
+ @io.close_read
+ -> { @enum.to_a }.should.raise(IOError)
+
+ io = StringIO.new(+"xyz", "w")
+ -> { io.each_codepoint.to_a }.should.raise(IOError)
+ end
+
+
+ it "calls the given block" do
+ r = []
+ @io.each_codepoint{|c| r << c }
+ r.should == [8706, 966, 47, 8706, 120, 32, 61, 32, 103, 97, 238, 116, 233]
+ end
+
+ it "returns self" do
+ @io.each_codepoint {|l| l }.should.equal?(@io)
+ end
end
diff --git a/spec/ruby/library/stringio/each_line_spec.rb b/spec/ruby/library/stringio/each_line_spec.rb
index 4ac0db7c45..4abecbf026 100644
--- a/spec/ruby/library/stringio/each_line_spec.rb
+++ b/spec/ruby/library/stringio/each_line_spec.rb
@@ -1,27 +1,212 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
-require_relative 'shared/each'
describe "StringIO#each_line when passed a separator" do
- it_behaves_like :stringio_each_separator, :each_line
+ before :each do
+ @io = StringIO.new("a b c d e\n1 2 3 4 5")
+ end
+
+ it "uses the passed argument as the line separator" do
+ seen = []
+ @io.each_line(" ") {|s| seen << s}
+ seen.should == ["a ", "b ", "c ", "d ", "e\n1 ", "2 ", "3 ", "4 ", "5"]
+ end
+
+ it "does not change $_" do
+ $_ = "test"
+ @io.each_line(" ") { |s| s}
+ $_.should == "test"
+ end
+
+ it "returns self" do
+ @io.each_line {|l| l }.should.equal?(@io)
+ end
+
+ it "tries to convert the passed separator to a String using #to_str" do
+ obj = mock("to_str")
+ obj.stub!(:to_str).and_return(" ")
+
+ seen = []
+ @io.each_line(obj) { |l| seen << l }
+ seen.should == ["a ", "b ", "c ", "d ", "e\n1 ", "2 ", "3 ", "4 ", "5"]
+ end
+
+ it "yields self's content starting from the current position when the passed separator is nil" do
+ seen = []
+ io = StringIO.new("1 2 1 2 1 2")
+ io.pos = 2
+ io.each_line(nil) {|s| seen << s}
+ seen.should == ["2 1 2 1 2"]
+ end
+
+ 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")
+ io.each_line("") {|s| seen << s}
+ seen.should == ["para1\n\n", "para2\n\n\n", "para3"]
+ end
end
describe "StringIO#each_line when passed no arguments" do
- it_behaves_like :stringio_each_no_arguments, :each_line
+ before :each do
+ @io = StringIO.new("a b c d e\n1 2 3 4 5")
+ end
+
+ it "yields each line to the passed block" do
+ seen = []
+ @io.each_line {|s| seen << s }
+ seen.should == ["a b c d e\n", "1 2 3 4 5"]
+ end
+
+ it "yields each line starting from the current position" do
+ seen = []
+ @io.pos = 4
+ @io.each_line {|s| seen << s }
+ seen.should == ["c d e\n", "1 2 3 4 5"]
+ end
+
+ it "does not change $_" do
+ $_ = "test"
+ @io.each_line { |s| s}
+ $_.should == "test"
+ end
+
+ it "uses $/ as the default line separator" do
+ seen = []
+ begin
+ old_rs = $/
+ suppress_warning {$/ = " "}
+ @io.each_line {|s| seen << s }
+ seen.should.eql?(["a ", "b ", "c ", "d ", "e\n1 ", "2 ", "3 ", "4 ", "5"])
+ ensure
+ suppress_warning {$/ = old_rs}
+ end
+ end
+
+ it "returns self" do
+ @io.each_line {|l| l }.should.equal?(@io)
+ end
+
+ it "returns an Enumerator when passed no block" do
+ enum = @io.each_line
+ enum.instance_of?(Enumerator).should == true
+
+ seen = []
+ enum.each { |b| seen << b }
+ seen.should == ["a b c d e\n", "1 2 3 4 5"]
+ end
end
describe "StringIO#each_line when self is not readable" do
- it_behaves_like :stringio_each_not_readable, :each_line
+ it "raises an IOError" do
+ io = StringIO.new(+"a b c d e", "w")
+ -> { io.each_line { |b| b } }.should.raise(IOError)
+
+ io = StringIO.new("a b c d e")
+ io.close_read
+ -> { io.each_line { |b| b } }.should.raise(IOError)
+ end
+end
+
+describe "StringIO#each_line when passed chomp" do
+ it "yields each line with removed newline characters to the passed block" do
+ seen = []
+ io = StringIO.new("a b \rc d e\n1 2 3 4 5\r\nthe end")
+ io.each_line(chomp: true) {|s| seen << s }
+ seen.should == ["a b \rc d e", "1 2 3 4 5", "the end"]
+ end
+
+ it "returns each line with removed newline characters when called without block" do
+ seen = []
+ io = StringIO.new("a b \rc d e\n1 2 3 4 5\r\nthe end")
+ enum = io.each_line(chomp: true)
+ enum.each {|s| seen << s }
+ seen.should == ["a b \rc d e", "1 2 3 4 5", "the end"]
+ end
end
describe "StringIO#each_line when passed chomp" do
- it_behaves_like :stringio_each_chomp, :each_line
+ it "yields each line with removed separator to the passed block" do
+ seen = []
+ io = StringIO.new("a b \nc d e|1 2 3 4 5\n|the end")
+ io.each_line("|", chomp: true) {|s| seen << s }
+ seen.should == ["a b \nc d e", "1 2 3 4 5\n", "the end"]
+ end
+
+ it "returns each line with removed separator when called without block" do
+ seen = []
+ io = StringIO.new("a b \nc d e|1 2 3 4 5\n|the end")
+ enum = io.each_line("|", chomp: true)
+ enum.each {|s| seen << s }
+ seen.should == ["a b \nc d e", "1 2 3 4 5\n", "the end"]
+ end
end
describe "StringIO#each_line when passed limit" do
- it_behaves_like :stringio_each_limit, :each_line
+ before :each do
+ @io = StringIO.new("a b c d e\n1 2 3 4 5")
+ end
+
+ it "returns the data read until the limit is met" do
+ seen = []
+ @io.each_line(4) { |s| seen << s }
+ seen.should == ["a b ", "c d ", "e\n", "1 2 ", "3 4 ", "5"]
+ end
end
describe "StringIO#each when passed separator and limit" do
- it_behaves_like :stringio_each_separator_and_limit, :each_line
+ before :each do
+ @io = StringIO.new("this>is>an>example")
+ end
+
+ it "returns the data read until the limit is consumed or the separator is met" do
+ @io.each_line('>', 8) { |s| break s }.should == "this>"
+ @io.each_line('>', 2) { |s| break s }.should == "is"
+ @io.each_line('>', 10) { |s| break s }.should == ">"
+ @io.each_line('>', 6) { |s| break s }.should == "an>"
+ @io.each_line('>', 5) { |s| break s }.should == "examp"
+ end
+
+ it "truncates the multi-character separator at the end to meet the limit" do
+ @io.each_line("is>an", 7) { |s| break s }.should == "this>is"
+ end
+
+ it "does not change $_" do
+ $_ = "test"
+ @io.each_line('>', 8) { |s| s }
+ $_.should == "test"
+ end
+
+ it "updates self's lineno by one" do
+ @io.each_line('>', 3) { |s| break s }
+ @io.lineno.should.eql?(1)
+
+ @io.each_line('>', 3) { |s| break s }
+ @io.lineno.should.eql?(2)
+
+ @io.each_line('>', 3) { |s| break s }
+ @io.lineno.should.eql?(3)
+ end
+
+ it "tries to convert the passed separator to a String using #to_str" do # TODO
+ obj = mock('to_str')
+ obj.should_receive(:to_str).and_return('>')
+
+ seen = []
+ @io.each_line(obj, 5) { |s| seen << s }
+ seen.should == ["this>", "is>", "an>", "examp", "le"]
+ end
+
+ it "does not raise TypeError if passed separator is nil" do
+ @io.each_line(nil, 5) { |s| break s }.should == "this>"
+ end
+
+ it "tries to convert the passed limit to an Integer using #to_int" do # TODO
+ obj = mock('to_int')
+ obj.should_receive(:to_int).and_return(5)
+
+ seen = []
+ @io.each_line('>', obj) { |s| seen << s }
+ seen.should == ["this>", "is>", "an>", "examp", "le"]
+ end
end
diff --git a/spec/ruby/library/stringio/each_spec.rb b/spec/ruby/library/stringio/each_spec.rb
index 7eb322f3ff..f3785bc18f 100644
--- a/spec/ruby/library/stringio/each_spec.rb
+++ b/spec/ruby/library/stringio/each_spec.rb
@@ -1,31 +1,8 @@
require_relative '../../spec_helper'
-require_relative 'fixtures/classes'
-require_relative 'shared/each'
+require 'stringio'
-describe "StringIO#each when passed a separator" do
- it_behaves_like :stringio_each_separator, :each
-end
-
-describe "StringIO#each when passed no arguments" do
- it_behaves_like :stringio_each_no_arguments, :each
-end
-
-describe "StringIO#each when self is not readable" do
- it_behaves_like :stringio_each_not_readable, :each
-end
-
-describe "StringIO#each when passed chomp" do
- it_behaves_like :stringio_each_chomp, :each
-end
-
-describe "StringIO#each when passed chomp" do
- it_behaves_like :stringio_each_separator_and_chomp, :each
-end
-
-describe "StringIO#each when passed limit" do
- it_behaves_like :stringio_each_limit, :each
-end
-
-describe "StringIO#each when passed separator and limit" do
- it_behaves_like :stringio_each_separator_and_limit, :each
+describe "StringIO#each" do
+ it "is an alias of StringIO#each_line" do
+ StringIO.instance_method(:each).should == StringIO.instance_method(:each_line)
+ end
end
diff --git a/spec/ruby/library/stringio/eof_spec.rb b/spec/ruby/library/stringio/eof_spec.rb
index af0170977c..acc49305f5 100644
--- a/spec/ruby/library/stringio/eof_spec.rb
+++ b/spec/ruby/library/stringio/eof_spec.rb
@@ -1,11 +1,33 @@
require_relative '../../spec_helper'
-require_relative 'fixtures/classes'
-require_relative 'shared/eof'
+require 'stringio'
describe "StringIO#eof?" do
- it_behaves_like :stringio_eof, :eof?
+ before :each do
+ @io = StringIO.new("eof")
+ end
+
+ it "returns true when self's position is greater than or equal to self's size" do
+ @io.pos = 3
+ @io.eof?.should == true
+
+ @io.pos = 6
+ @io.eof?.should == true
+ end
+
+ it "returns false when self's position is less than self's size" do
+ @io.pos = 0
+ @io.eof?.should == false
+
+ @io.pos = 1
+ @io.eof?.should == false
+
+ @io.pos = 2
+ @io.eof?.should == false
+ end
end
describe "StringIO#eof" do
- it_behaves_like :stringio_eof, :eof
+ it "is an alias of StringIO#eof?" do
+ StringIO.instance_method(:eof).should == StringIO.instance_method(:eof?)
+ end
end
diff --git a/spec/ruby/library/stringio/fcntl_spec.rb b/spec/ruby/library/stringio/fcntl_spec.rb
index a78004d868..6108130db7 100644
--- a/spec/ruby/library/stringio/fcntl_spec.rb
+++ b/spec/ruby/library/stringio/fcntl_spec.rb
@@ -3,6 +3,6 @@ require_relative 'fixtures/classes'
describe "StringIO#fcntl" do
it "raises a NotImplementedError" do
- -> { StringIO.new("boom").fcntl }.should raise_error(NotImplementedError)
+ -> { StringIO.new("boom").fcntl }.should.raise(NotImplementedError)
end
end
diff --git a/spec/ruby/library/stringio/fileno_spec.rb b/spec/ruby/library/stringio/fileno_spec.rb
index 5a9f440a0f..f5d1e83776 100644
--- a/spec/ruby/library/stringio/fileno_spec.rb
+++ b/spec/ruby/library/stringio/fileno_spec.rb
@@ -3,6 +3,6 @@ require 'stringio'
describe "StringIO#fileno" do
it "returns nil" do
- StringIO.new("nuffin").fileno.should be_nil
+ StringIO.new("nuffin").fileno.should == nil
end
end
diff --git a/spec/ruby/library/stringio/flush_spec.rb b/spec/ruby/library/stringio/flush_spec.rb
index 4dc58b1d48..48be44773c 100644
--- a/spec/ruby/library/stringio/flush_spec.rb
+++ b/spec/ruby/library/stringio/flush_spec.rb
@@ -4,6 +4,6 @@ require_relative 'fixtures/classes'
describe "StringIO#flush" do
it "returns self" do
io = StringIO.new(+"flush")
- io.flush.should equal(io)
+ 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..30fae15c8e 100644
--- a/spec/ruby/library/stringio/fsync_spec.rb
+++ b/spec/ruby/library/stringio/fsync_spec.rb
@@ -4,6 +4,6 @@ require_relative 'fixtures/classes'
describe "StringIO#fsync" do
it "returns zero" do
io = StringIO.new(+"fsync")
- io.fsync.should eql(0)
+ 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 ac876f0b4f..5dc572fba5 100644
--- a/spec/ruby/library/stringio/gets_spec.rb
+++ b/spec/ruby/library/stringio/gets_spec.rb
@@ -10,8 +10,8 @@ describe "StringIO#gets" do
@io = StringIO.new("this>is>an>example")
@io.pos = 36
- @io.gets(">").should be_nil
- @io.gets(">").should be_nil
+ @io.gets(">").should == nil
+ @io.gets(">").should == nil
end
end
@@ -22,8 +22,8 @@ describe "StringIO#gets" do
@io = StringIO.new("this>is>an>example")
@io.pos = 36
- @io.gets(3).should be_nil
- @io.gets(3).should be_nil
+ @io.gets(3).should == nil
+ @io.gets(3).should == nil
end
end
@@ -34,8 +34,8 @@ describe "StringIO#gets" do
@io = StringIO.new("this>is>an>example")
@io.pos = 36
- @io.gets(">", 3).should be_nil
- @io.gets(">", 3).should be_nil
+ @io.gets(">", 3).should == nil
+ @io.gets(">", 3).should == nil
end
end
@@ -46,8 +46,8 @@ describe "StringIO#gets" do
@io = StringIO.new("this>is>an>example")
@io.pos = 36
- @io.gets.should be_nil
- @io.gets.should be_nil
+ @io.gets.should == nil
+ @io.gets.should == nil
end
end
diff --git a/spec/ruby/library/stringio/initialize_spec.rb b/spec/ruby/library/stringio/initialize_spec.rb
index 6f4d2e456c..413e0aacc0 100644
--- a/spec/ruby/library/stringio/initialize_spec.rb
+++ b/spec/ruby/library/stringio/initialize_spec.rb
@@ -8,111 +8,111 @@ describe "StringIO#initialize when passed [Object, mode]" do
it "uses the passed Object as the StringIO backend" do
@io.send(:initialize, str = "example", "r")
- @io.string.should equal(str)
+ @io.string.should.equal?(str)
end
it "sets the mode based on the passed mode" do
io = StringIO.allocate
io.send(:initialize, +"example", "r")
- io.closed_read?.should be_false
- io.closed_write?.should be_true
+ io.closed_read?.should == false
+ io.closed_write?.should == true
io = StringIO.allocate
io.send(:initialize, +"example", "rb")
- io.closed_read?.should be_false
- io.closed_write?.should be_true
+ io.closed_read?.should == false
+ io.closed_write?.should == true
io = StringIO.allocate
io.send(:initialize, +"example", "r+")
- io.closed_read?.should be_false
- io.closed_write?.should be_false
+ io.closed_read?.should == false
+ io.closed_write?.should == false
io = StringIO.allocate
io.send(:initialize, +"example", "rb+")
- io.closed_read?.should be_false
- io.closed_write?.should be_false
+ io.closed_read?.should == false
+ io.closed_write?.should == false
io = StringIO.allocate
io.send(:initialize, +"example", "w")
- io.closed_read?.should be_true
- io.closed_write?.should be_false
+ io.closed_read?.should == true
+ io.closed_write?.should == false
io = StringIO.allocate
io.send(:initialize, +"example", "wb")
- io.closed_read?.should be_true
- io.closed_write?.should be_false
+ io.closed_read?.should == true
+ io.closed_write?.should == false
io = StringIO.allocate
io.send(:initialize, +"example", "w+")
- io.closed_read?.should be_false
- io.closed_write?.should be_false
+ io.closed_read?.should == false
+ io.closed_write?.should == false
io = StringIO.allocate
io.send(:initialize, +"example", "wb+")
- io.closed_read?.should be_false
- io.closed_write?.should be_false
+ io.closed_read?.should == false
+ io.closed_write?.should == false
io = StringIO.allocate
io.send(:initialize, +"example", "a")
- io.closed_read?.should be_true
- io.closed_write?.should be_false
+ io.closed_read?.should == true
+ io.closed_write?.should == false
io = StringIO.allocate
io.send(:initialize, +"example", "ab")
- io.closed_read?.should be_true
- io.closed_write?.should be_false
+ io.closed_read?.should == true
+ io.closed_write?.should == false
io = StringIO.allocate
io.send(:initialize, +"example", "a+")
- io.closed_read?.should be_false
- io.closed_write?.should be_false
+ io.closed_read?.should == false
+ io.closed_write?.should == false
io = StringIO.allocate
io.send(:initialize, +"example", "ab+")
- io.closed_read?.should be_false
- io.closed_write?.should be_false
+ io.closed_read?.should == false
+ io.closed_write?.should == false
end
it "allows passing the mode as an Integer" do
io = StringIO.allocate
io.send(:initialize, +"example", IO::RDONLY)
- io.closed_read?.should be_false
- io.closed_write?.should be_true
+ io.closed_read?.should == false
+ io.closed_write?.should == true
io = StringIO.allocate
io.send(:initialize, +"example", IO::RDWR)
- io.closed_read?.should be_false
- io.closed_write?.should be_false
+ io.closed_read?.should == false
+ io.closed_write?.should == false
io = StringIO.allocate
io.send(:initialize, +"example", IO::WRONLY)
- io.closed_read?.should be_true
- io.closed_write?.should be_false
+ io.closed_read?.should == true
+ io.closed_write?.should == false
io = StringIO.allocate
io.send(:initialize, +"example", IO::WRONLY | IO::TRUNC)
- io.closed_read?.should be_true
- io.closed_write?.should be_false
+ io.closed_read?.should == true
+ io.closed_write?.should == false
io = StringIO.allocate
io.send(:initialize, +"example", IO::RDWR | IO::TRUNC)
- io.closed_read?.should be_false
- io.closed_write?.should be_false
+ io.closed_read?.should == false
+ io.closed_write?.should == false
io = StringIO.allocate
io.send(:initialize, +"example", IO::WRONLY | IO::APPEND)
- io.closed_read?.should be_true
- io.closed_write?.should be_false
+ io.closed_read?.should == true
+ io.closed_write?.should == false
io = StringIO.allocate
io.send(:initialize, +"example", IO::RDWR | IO::APPEND)
- io.closed_read?.should be_false
- io.closed_write?.should be_false
+ io.closed_read?.should == false
+ io.closed_write?.should == false
end
it "raises a FrozenError when passed a frozen String in truncate mode as StringIO backend" do
io = StringIO.allocate
- -> { io.send(:initialize, "example".freeze, IO::TRUNC) }.should raise_error(FrozenError)
+ -> { io.send(:initialize, "example".freeze, IO::TRUNC) }.should.raise(FrozenError)
end
it "tries to convert the passed mode to a String using #to_str" do
@@ -120,15 +120,15 @@ describe "StringIO#initialize when passed [Object, mode]" do
obj.should_receive(:to_str).and_return("r")
@io.send(:initialize, +"example", obj)
- @io.closed_read?.should be_false
- @io.closed_write?.should be_true
+ @io.closed_read?.should == false
+ @io.closed_write?.should == true
end
it "raises an Errno::EACCES error when passed a frozen string with a write-mode" do
(str = "example").freeze
- -> { @io.send(:initialize, str, "r+") }.should raise_error(Errno::EACCES)
- -> { @io.send(:initialize, str, "w") }.should raise_error(Errno::EACCES)
- -> { @io.send(:initialize, str, "a") }.should raise_error(Errno::EACCES)
+ -> { @io.send(:initialize, str, "r+") }.should.raise(Errno::EACCES)
+ -> { @io.send(:initialize, str, "w") }.should.raise(Errno::EACCES)
+ -> { @io.send(:initialize, str, "a") }.should.raise(Errno::EACCES)
end
it "truncates all the content if passed w mode" do
@@ -159,19 +159,19 @@ describe "StringIO#initialize when passed [Object]" do
it "uses the passed Object as the StringIO backend" do
@io.send(:initialize, str = "example")
- @io.string.should equal(str)
+ @io.string.should.equal?(str)
end
it "sets the mode to read-write if the string is mutable" do
@io.send(:initialize, +"example")
- @io.closed_read?.should be_false
- @io.closed_write?.should be_false
+ @io.closed_read?.should == false
+ @io.closed_write?.should == 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
+ @io.closed_read?.should == false
+ @io.closed_write?.should == true
end
it "tries to convert the passed Object to a String using #to_str" do
@@ -184,8 +184,8 @@ describe "StringIO#initialize when passed [Object]" do
it "automatically sets the mode to read-only when passed a frozen string" do
(str = "example").freeze
@io.send(:initialize, str)
- @io.closed_read?.should be_false
- @io.closed_write?.should be_true
+ @io.closed_read?.should == false
+ @io.closed_write?.should == true
end
end
@@ -193,8 +193,8 @@ end
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.closed_read?.should be_false
- io.closed_write?.should be_true
+ io.closed_read?.should == false
+ io.closed_write?.should == true
end
it "accepts a mode argument set to nil with a valid :mode option" do
@@ -223,54 +223,54 @@ describe "StringIO#initialize when passed keyword arguments and error happens" d
it "raises an error if passed encodings two ways" do
-> {
@io = StringIO.new(+'', 'w:ISO-8859-1', encoding: 'ISO-8859-1')
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
-> {
@io = StringIO.new(+'', 'w:ISO-8859-1', external_encoding: 'ISO-8859-1')
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
-> {
@io = StringIO.new(+'', 'w:ISO-8859-1:UTF-8', internal_encoding: 'ISO-8859-1')
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
it "raises an error if passed matching binary/text mode two ways" do
-> {
@io = StringIO.new(+'', "wb", binmode: true)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
-> {
@io = StringIO.new(+'', "wt", textmode: true)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
-> {
@io = StringIO.new(+'', "wb", textmode: false)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
-> {
@io = StringIO.new(+'', "wt", binmode: false)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
it "raises an error if passed conflicting binary/text mode two ways" do
-> {
@io = StringIO.new(+'', "wb", binmode: false)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
-> {
@io = StringIO.new(+'', "wt", textmode: false)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
-> {
@io = StringIO.new(+'', "wb", textmode: true)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
-> {
@io = StringIO.new(+'', "wt", binmode: true)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
it "raises an error when trying to set both binmode and textmode" do
-> {
@io = StringIO.new(+'', "w", textmode: true, binmode: true)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
-> {
@io = StringIO.new(+'', File::Constants::WRONLY, textmode: true, binmode: true)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
end
@@ -280,13 +280,13 @@ describe "StringIO#initialize when passed no arguments" do
end
it "is private" do
- StringIO.should have_private_instance_method(:initialize)
+ StringIO.private_instance_methods(false).should.include?(:initialize)
end
it "sets the mode to read-write" do
@io.send(:initialize)
- @io.closed_read?.should be_false
- @io.closed_write?.should be_false
+ @io.closed_read?.should == false
+ @io.closed_write?.should == false
end
it "uses an empty String as the StringIO backend" do
diff --git a/spec/ruby/library/stringio/inspect_spec.rb b/spec/ruby/library/stringio/inspect_spec.rb
index 7c02f8d360..962d858e48 100644
--- a/spec/ruby/library/stringio/inspect_spec.rb
+++ b/spec/ruby/library/stringio/inspect_spec.rb
@@ -9,7 +9,7 @@ describe "StringIO#inspect" do
it "does not include the contents" do
io = StringIO.new("contents")
- io.inspect.should_not include("contents")
+ io.inspect.should_not.include?("contents")
end
it "uses the regular Object#inspect without any instance variable" do
diff --git a/spec/ruby/library/stringio/isatty_spec.rb b/spec/ruby/library/stringio/isatty_spec.rb
index 1ef33978b5..07743acc12 100644
--- a/spec/ruby/library/stringio/isatty_spec.rb
+++ b/spec/ruby/library/stringio/isatty_spec.rb
@@ -1,7 +1,8 @@
require_relative '../../spec_helper'
-require_relative 'fixtures/classes'
-require_relative 'shared/isatty'
+require 'stringio'
describe "StringIO#isatty" do
- it_behaves_like :stringio_isatty, :isatty
+ it "is an alias of StringIO#tty?" do
+ StringIO.instance_method(:isatty).should == StringIO.instance_method(:tty?)
+ end
end
diff --git a/spec/ruby/library/stringio/length_spec.rb b/spec/ruby/library/stringio/length_spec.rb
index d3070f50a7..a83be6256a 100644
--- a/spec/ruby/library/stringio/length_spec.rb
+++ b/spec/ruby/library/stringio/length_spec.rb
@@ -1,7 +1,8 @@
require_relative '../../spec_helper'
-require_relative 'fixtures/classes'
-require_relative 'shared/length'
+require 'stringio'
describe "StringIO#length" do
- it_behaves_like :stringio_length, :length
+ it "returns the length of the wrapped string" do
+ StringIO.new("example").length.should == 7
+ end
end
diff --git a/spec/ruby/library/stringio/lineno_spec.rb b/spec/ruby/library/stringio/lineno_spec.rb
index c620a1a686..a96dc05927 100644
--- a/spec/ruby/library/stringio/lineno_spec.rb
+++ b/spec/ruby/library/stringio/lineno_spec.rb
@@ -10,7 +10,7 @@ describe "StringIO#lineno" do
@io.gets
@io.gets
@io.gets
- @io.lineno.should eql(3)
+ @io.lineno.should.eql?(3)
end
end
@@ -21,10 +21,10 @@ describe "StringIO#lineno=" do
it "sets the current line number, but has no impact on the position" do
@io.lineno = 3
- @io.pos.should eql(0)
+ @io.pos.should.eql?(0)
@io.gets.should == "this\n"
- @io.lineno.should eql(4)
- @io.pos.should eql(5)
+ @io.lineno.should.eql?(4)
+ @io.pos.should.eql?(5)
end
end
diff --git a/spec/ruby/library/stringio/open_spec.rb b/spec/ruby/library/stringio/open_spec.rb
index b7c90661f9..23c7b34e09 100644
--- a/spec/ruby/library/stringio/open_spec.rb
+++ b/spec/ruby/library/stringio/open_spec.rb
@@ -4,24 +4,24 @@ require 'stringio'
describe "StringIO.open when passed [Object, mode]" do
it "uses the passed Object as the StringIO backend" do
io = StringIO.open(str = "example", "r")
- io.string.should equal(str)
+ io.string.should.equal?(str)
end
it "returns the blocks return value when yielding" do
ret = StringIO.open(+"example", "r") { :test }
- ret.should equal(:test)
+ ret.should.equal?(:test)
end
it "yields self to the passed block" do
io = nil
StringIO.open(+"example", "r") { |strio| io = strio }
- io.should be_kind_of(StringIO)
+ io.should.is_a?(StringIO)
end
it "closes self after yielding" do
io = nil
StringIO.open(+"example", "r") { |strio| io = strio }
- io.closed?.should be_true
+ io.closed?.should == true
end
it "even closes self when an exception is raised while yielding" do
@@ -33,13 +33,13 @@ describe "StringIO.open when passed [Object, mode]" do
end
rescue
end
- io.closed?.should be_true
+ io.closed?.should == true
end
it "sets self's string to nil after yielding" do
io = nil
StringIO.open(+"example", "r") { |strio| io = strio }
- io.string.should be_nil
+ io.string.should == nil
end
it "even sets self's string to nil when an exception is raised while yielding" do
@@ -51,91 +51,91 @@ describe "StringIO.open when passed [Object, mode]" do
end
rescue
end
- io.string.should be_nil
+ io.string.should == nil
end
it "sets the mode based on the passed mode" do
io = StringIO.open(+"example", "r")
- io.closed_read?.should be_false
- io.closed_write?.should be_true
+ io.closed_read?.should == false
+ io.closed_write?.should == true
io = StringIO.open(+"example", "rb")
- io.closed_read?.should be_false
- io.closed_write?.should be_true
+ io.closed_read?.should == false
+ io.closed_write?.should == true
io = StringIO.open(+"example", "r+")
- io.closed_read?.should be_false
- io.closed_write?.should be_false
+ io.closed_read?.should == false
+ io.closed_write?.should == false
io = StringIO.open(+"example", "rb+")
- io.closed_read?.should be_false
- io.closed_write?.should be_false
+ io.closed_read?.should == false
+ io.closed_write?.should == false
io = StringIO.open(+"example", "w")
- io.closed_read?.should be_true
- io.closed_write?.should be_false
+ io.closed_read?.should == true
+ io.closed_write?.should == false
io = StringIO.open(+"example", "wb")
- io.closed_read?.should be_true
- io.closed_write?.should be_false
+ io.closed_read?.should == true
+ io.closed_write?.should == false
io = StringIO.open(+"example", "w+")
- io.closed_read?.should be_false
- io.closed_write?.should be_false
+ io.closed_read?.should == false
+ io.closed_write?.should == false
io = StringIO.open(+"example", "wb+")
- io.closed_read?.should be_false
- io.closed_write?.should be_false
+ io.closed_read?.should == false
+ io.closed_write?.should == false
io = StringIO.open(+"example", "a")
- io.closed_read?.should be_true
- io.closed_write?.should be_false
+ io.closed_read?.should == true
+ io.closed_write?.should == false
io = StringIO.open(+"example", "ab")
- io.closed_read?.should be_true
- io.closed_write?.should be_false
+ io.closed_read?.should == true
+ io.closed_write?.should == false
io = StringIO.open(+"example", "a+")
- io.closed_read?.should be_false
- io.closed_write?.should be_false
+ io.closed_read?.should == false
+ io.closed_write?.should == false
io = StringIO.open(+"example", "ab+")
- io.closed_read?.should be_false
- io.closed_write?.should be_false
+ io.closed_read?.should == false
+ io.closed_write?.should == false
end
it "allows passing the mode as an Integer" do
io = StringIO.open(+"example", IO::RDONLY)
- io.closed_read?.should be_false
- io.closed_write?.should be_true
+ io.closed_read?.should == false
+ io.closed_write?.should == true
io = StringIO.open(+"example", IO::RDWR)
- io.closed_read?.should be_false
- io.closed_write?.should be_false
+ io.closed_read?.should == false
+ io.closed_write?.should == false
io = StringIO.open(+"example", IO::WRONLY)
- io.closed_read?.should be_true
- io.closed_write?.should be_false
+ io.closed_read?.should == true
+ io.closed_write?.should == false
io = StringIO.open(+"example", IO::WRONLY | IO::TRUNC)
- io.closed_read?.should be_true
- io.closed_write?.should be_false
+ io.closed_read?.should == true
+ io.closed_write?.should == false
io = StringIO.open(+"example", IO::RDWR | IO::TRUNC)
- io.closed_read?.should be_false
- io.closed_write?.should be_false
+ io.closed_read?.should == false
+ io.closed_write?.should == false
io = StringIO.open(+"example", IO::WRONLY | IO::APPEND)
- io.closed_read?.should be_true
- io.closed_write?.should be_false
+ io.closed_read?.should == true
+ io.closed_write?.should == false
io = StringIO.open(+"example", IO::RDWR | IO::APPEND)
- io.closed_read?.should be_false
- io.closed_write?.should be_false
+ io.closed_read?.should == false
+ io.closed_write?.should == false
end
it "raises a FrozenError when passed a frozen String in truncate mode as StringIO backend" do
- -> { StringIO.open("example".freeze, IO::TRUNC) }.should raise_error(FrozenError)
+ -> { StringIO.open("example".freeze, IO::TRUNC) }.should.raise(FrozenError)
end
it "tries to convert the passed mode to a String using #to_str" do
@@ -143,34 +143,34 @@ describe "StringIO.open when passed [Object, mode]" do
obj.should_receive(:to_str).and_return("r")
io = StringIO.open(+"example", obj)
- io.closed_read?.should be_false
- io.closed_write?.should be_true
+ io.closed_read?.should == false
+ io.closed_write?.should == true
end
it "raises an Errno::EACCES error when passed a frozen string with a write-mode" do
(str = "example").freeze
- -> { StringIO.open(str, "r+") }.should raise_error(Errno::EACCES)
- -> { StringIO.open(str, "w") }.should raise_error(Errno::EACCES)
- -> { StringIO.open(str, "a") }.should raise_error(Errno::EACCES)
+ -> { StringIO.open(str, "r+") }.should.raise(Errno::EACCES)
+ -> { StringIO.open(str, "w") }.should.raise(Errno::EACCES)
+ -> { StringIO.open(str, "a") }.should.raise(Errno::EACCES)
end
end
describe "StringIO.open when passed [Object]" do
it "uses the passed Object as the StringIO backend" do
io = StringIO.open(str = "example")
- io.string.should equal(str)
+ io.string.should.equal?(str)
end
it "yields self to the passed block" do
io = nil
ret = StringIO.open(+"example") { |strio| io = strio }
- io.should equal(ret)
+ io.should.equal?(ret)
end
it "sets the mode to read-write (r+)" do
io = StringIO.open(+"example")
- io.closed_read?.should be_false
- io.closed_write?.should be_false
+ io.closed_read?.should == false
+ io.closed_write?.should == false
io = StringIO.new(+"example")
io.printf("%d", 123)
@@ -187,8 +187,8 @@ describe "StringIO.open when passed [Object]" do
it "automatically sets the mode to read-only when passed a frozen string" do
(str = "example").freeze
io = StringIO.open(str)
- io.closed_read?.should be_false
- io.closed_write?.should be_true
+ io.closed_read?.should == false
+ io.closed_write?.should == true
end
end
@@ -196,13 +196,13 @@ describe "StringIO.open when passed no arguments" do
it "yields self to the passed block" do
io = nil
ret = StringIO.open { |strio| io = strio }
- io.should equal(ret)
+ io.should.equal?(ret)
end
it "sets the mode to read-write (r+)" do
io = StringIO.open
- io.closed_read?.should be_false
- io.closed_write?.should be_false
+ io.closed_read?.should == false
+ io.closed_write?.should == false
io = StringIO.new(+"example")
io.printf("%d", 123)
diff --git a/spec/ruby/library/stringio/path_spec.rb b/spec/ruby/library/stringio/path_spec.rb
index 1184ca523f..dcb77b1df8 100644
--- a/spec/ruby/library/stringio/path_spec.rb
+++ b/spec/ruby/library/stringio/path_spec.rb
@@ -3,6 +3,6 @@ require_relative 'fixtures/classes'
describe "StringIO#path" do
it "is not defined" do
- -> { StringIO.new("path").path }.should raise_error(NoMethodError)
+ -> { StringIO.new("path").path }.should.raise(NoMethodError)
end
end
diff --git a/spec/ruby/library/stringio/pid_spec.rb b/spec/ruby/library/stringio/pid_spec.rb
index 08f2d7ab1a..7a729fbe41 100644
--- a/spec/ruby/library/stringio/pid_spec.rb
+++ b/spec/ruby/library/stringio/pid_spec.rb
@@ -3,6 +3,6 @@ require_relative 'fixtures/classes'
describe "StringIO#pid" do
it "returns nil" do
- StringIO.new("pid").pid.should be_nil
+ StringIO.new("pid").pid.should == nil
end
end
diff --git a/spec/ruby/library/stringio/pos_spec.rb b/spec/ruby/library/stringio/pos_spec.rb
index 81be5f01a5..16f068b049 100644
--- a/spec/ruby/library/stringio/pos_spec.rb
+++ b/spec/ruby/library/stringio/pos_spec.rb
@@ -1,9 +1,17 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
-require_relative 'shared/tell'
describe "StringIO#pos" do
- it_behaves_like :stringio_tell, :pos
+ before :each do
+ @io = StringIOSpecs.build
+ end
+
+ it "returns the current byte offset" do
+ @io.getc
+ @io.pos.should == 1
+ @io.read(7)
+ @io.pos.should == 8
+ end
end
describe "StringIO#pos=" do
@@ -17,7 +25,7 @@ describe "StringIO#pos=" do
end
it "raises an EINVAL if given a negative argument" do
- -> { @io.pos = -10 }.should raise_error(Errno::EINVAL)
+ -> { @io.pos = -10 }.should.raise(Errno::EINVAL)
end
it "updates the current byte offset after reaching EOF" do
diff --git a/spec/ruby/library/stringio/print_spec.rb b/spec/ruby/library/stringio/print_spec.rb